From c8265f81cf591587f6056a9f9def6150008d9b6e Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot Date: Thu, 6 Jul 2023 12:42:24 -0700 Subject: [PATCH 0001/1547] Marks Linux firebase_oriol33_abstract_method_smoke_test to be unflaky (#128398) The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux%20firebase_oriol33_abstract_method_smoke_test%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index cd162a085c68d..0a51da5a3a969 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -414,7 +414,6 @@ targets: - .ci.yaml - name: Linux firebase_oriol33_abstract_method_smoke_test - bringup: true recipe: firebaselab/firebaselab timeout: 60 properties: From 94f0459d8bbc4fc2d61175f5786008859f0d3634 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 6 Jul 2023 17:24:20 -0400 Subject: [PATCH 0002/1547] Manual roll Flutter Engine from bd2e42b203e1 to 06c936205d96 (27 revisions) (#130097) Manual roll Flutter Engine from bd2e42b203e1 to 06c936205d96 (27 revisions) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/bd2e42b203e1...06c936205d96 2023-07-06 dnfield@google.com Handle nested display list clips in Impeller dispatcher (flutter/engine#43442) 2023-07-06 louiseh0313@gmail.com Add Look Up to iOS selection controls (flutter/engine#43308) 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from 6aaef9cbc3af to 10a43e57e0a6 (1 revision) (flutter/engine#43444) 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from 620de5ac9f6b to 6aaef9cbc3af (1 revision) (flutter/engine#43441) 2023-07-06 ychris@google.com Revert "[iOS][Keyboard] Wait vsync on UI thread and update viewport inset to avoid jitter." (flutter/engine#43422) 2023-07-06 skia-flutter-autoroll@skia.org Roll ICU from a2961dc659b4 to e8c3bc9ea97d (7 revisions) (flutter/engine#43440) 2023-07-06 zanderso@users.noreply.github.com Further shard clang-tidy runs (flutter/engine#43428) 2023-07-06 dnfield@google.com Release log capture at end of test (flutter/engine#43429) 2023-07-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from uGhka7LBG80dM_I3a... to 3D0ft09qP4-Hp_3mQ... (flutter/engine#43439) 2023-07-06 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from amH2MWTworhTLdMWy... to MEXi9Xyj7u24PSx_J... (flutter/engine#43438) 2023-07-06 109111084+yaakovschectman@users.noreply.github.com Use Windows Display Language (flutter/engine#43341) 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from b2ba6e1d8c0e to 620de5ac9f6b (2 revisions) (flutter/engine#43437) 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from 50e866b51a64 to b2ba6e1d8c0e (2 revisions) (flutter/engine#43436) 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from 8ed969b60e98 to 50e866b51a64 (1 revision) (flutter/engine#43435) 2023-07-06 737941+loic-sharma@users.noreply.github.com Fix typo in painting.dart (flutter/engine#43378) 2023-07-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from C3Q7MJBYkiin8zw-f... to uGhka7LBG80dM_I3a... (flutter/engine#43433) 2023-07-06 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from iwgWLB4KaXslnaGwK... to amH2MWTworhTLdMWy... (flutter/engine#43432) 2023-07-05 skia-flutter-autoroll@skia.org Roll Skia from a39421eb8d7b to 8ed969b60e98 (6 revisions) (flutter/engine#43431) 2023-07-05 jonahwilliams@google.com [Impeller] Allocate fewer textures in dedicated memory and adjust buffer flags. (flutter/engine#43313) 2023-07-05 skia-flutter-autoroll@skia.org Roll Skia from d6e941012b87 to a39421eb8d7b (4 revisions) (flutter/engine#43427) 2023-07-05 skia-flutter-autoroll@skia.org Roll Skia from e0b9e047332d to d6e941012b87 (2 revisions) (flutter/engine#43424) 2023-07-05 ychris@google.com [iOS] Avoid crash when backdrop filter is null for PlatformViews (flutter/engine#43150) 2023-07-05 skia-flutter-autoroll@skia.org Roll Skia from 401c397f7235 to e0b9e047332d (1 revision) (flutter/engine#43420) 2023-07-05 737941+loic-sharma@users.noreply.github.com [Windows] Fix `FlutterWindow::GetNativeViewAccessible` crash (flutter/engine#43368) 2023-07-05 linxunfeng@yeah.net [iOS] Fix FlutterViewController retain cycle (flutter/engine#43379) 2023-07-05 skia-flutter-autoroll@skia.org Roll Skia from 23052eb28808 to 401c397f7235 (1 revision) (flutter/engine#43419) 2023-07-05 skia-flutter-autoroll@skia.org Roll Skia from d58324bf653d to 23052eb28808 (3 revisions) (flutter/engine#43418) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from iwgWLB4KaXsl to MEXi9Xyj7u24 fuchsia/sdk/core/mac-amd64 from C3Q7MJBYkiin to 3D0ft09qP4-H If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: ... --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7d0d48483dd33..4c0da53b7d44b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bd2e42b203e14507055704d06c9ac0c6f50c2f01 +06c936205d96810f7c236f5b7b1713b03f5fcb19 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 11f77a582348c..590a714b578e5 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -iwgWLB4KaXslnaGwKuAD5S9wamgkF0Mj9a411131XdkC +MEXi9Xyj7u24PSx_Jvgw9TuwyOPq0iNP_ntkEuuNNSYC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 40252d6d5a90b..94c7734c21ec3 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -C3Q7MJBYkiin8zw-fLJ9QmM-8anKHqabR7B2KFuBYUgC +3D0ft09qP4-Hp_3mQoSznlSZ6q9XPGl7Yt9lrqlk-0cC From 1fb3687bf8bc2b42317cf071ea9ff269db649b75 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 6 Jul 2023 18:39:09 -0400 Subject: [PATCH 0003/1547] Roll Flutter Engine from 06c936205d96 to 42df55a9e63e (3 revisions) (#130100) https://github.com/flutter/engine/compare/06c936205d96...42df55a9e63e 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from 10a43e57e0a6 to 072dfcc435de (2 revisions) (flutter/engine#43445) 2023-07-06 dkwingsmt@users.noreply.github.com Remove dead code for recreating a11y node delegates (flutter/engine#43359) 2023-07-06 737941+loic-sharma@users.noreply.github.com [macOS] Fix assertion typo (flutter/engine#43179) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4c0da53b7d44b..7615785b2fabc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -06c936205d96810f7c236f5b7b1713b03f5fcb19 +42df55a9e63ed3a8f0c70239c046e9242aad2660 From bf72b63536ca898cdc015565d8eee5bc3c43aa50 Mon Sep 17 00:00:00 2001 From: fzyzcjy <5236035+fzyzcjy@users.noreply.github.com> Date: Fri, 7 Jul 2023 07:30:01 +0800 Subject: [PATCH 0004/1547] Super tiny code optimization: No need to redundantly check whether value has changed (#130050) Removed two unnecessary `if` conditions. --- packages/flutter/lib/src/widgets/text_selection.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 34e3279551925..a447e6e0cb97c 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -3312,7 +3312,7 @@ class ClipboardStatusNotifier extends ValueNotifier with Widget )); // In the case of an error from the Clipboard API, set the value to // unknown so that it will try to update again later. - if (_disposed || value == ClipboardStatus.unknown) { + if (_disposed) { return; } value = ClipboardStatus.unknown; @@ -3322,7 +3322,7 @@ class ClipboardStatusNotifier extends ValueNotifier with Widget ? ClipboardStatus.pasteable : ClipboardStatus.notPasteable; - if (_disposed || nextStatus == value) { + if (_disposed) { return; } value = nextStatus; From 6baa72be68dc1af16f690f71cab9a7b578f58460 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 6 Jul 2023 19:54:37 -0400 Subject: [PATCH 0005/1547] Roll Flutter Engine from 42df55a9e63e to 48bf7ac59254 (1 revision) (#130106) https://github.com/flutter/engine/compare/42df55a9e63e...48bf7ac59254 2023-07-06 john@johnmccutchan.com Eagerly remove the PlatformView from the view hierarchy on Android (flutter/engine#43423) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7615785b2fabc..a34b22b402104 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -42df55a9e63ed3a8f0c70239c046e9242aad2660 +48bf7ac592547babc572fc0f0f5b8f019b75fa53 From f5d3cb6d4f7e19484964c6cadd2637706752db22 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 6 Jul 2023 20:39:00 -0400 Subject: [PATCH 0006/1547] Roll Flutter Engine from 48bf7ac59254 to 491f317978f4 (2 revisions) (#130107) https://github.com/flutter/engine/compare/48bf7ac59254...491f317978f4 2023-07-06 chinmaygarde@google.com Account for updated Impeller label. (flutter/engine#43450) 2023-07-06 bdero@google.com [Impeller] Fix DrawPicture. (flutter/engine#43446) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a34b22b402104..bd3b7067ccdf3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -48bf7ac592547babc572fc0f0f5b8f019b75fa53 +491f317978f4258332d3b8946395a5888d510274 From 03af0e535f00b6cfa040bf9f6f6fc7fbdd8bd9ae Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 6 Jul 2023 22:25:11 -0400 Subject: [PATCH 0007/1547] Roll Flutter Engine from 491f317978f4 to 1fa222fae283 (1 revision) (#130110) https://github.com/flutter/engine/compare/491f317978f4...1fa222fae283 2023-07-06 skia-flutter-autoroll@skia.org Roll Skia from 072dfcc435de to 11a2eefe4c61 (5 revisions) (flutter/engine#43451) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bd3b7067ccdf3..d4888837289bd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -491f317978f4258332d3b8946395a5888d510274 +1fa222fae28354a3e9e1d0b73190b0a4b2564731 From 9c006666d16bf9c9f8f6f961fe8c041266f72c96 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 6 Jul 2023 23:55:43 -0400 Subject: [PATCH 0008/1547] Roll Flutter Engine from 1fa222fae283 to 650ff096488a (3 revisions) (#130114) https://github.com/flutter/engine/compare/1fa222fae283...650ff096488a 2023-07-07 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from MEXi9Xyj7u24PSx_J... to Cfxhimvf7nMO99ky_... (flutter/engine#43454) 2023-07-07 zanderso@users.noreply.github.com Reduce redundant Linux clang-tidy work and run on more cores (flutter/engine#43448) 2023-07-07 jason-simmons@users.noreply.github.com [Impeller] Set up the clear color for non-MSAA render targets. (flutter/engine#43452) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from MEXi9Xyj7u24 to Cfxhimvf7nMO If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d4888837289bd..a00f0d138cf2a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1fa222fae28354a3e9e1d0b73190b0a4b2564731 +650ff096488a13ee360f5e877e276b678cb3d71f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 590a714b578e5..02c4cc23a4acc 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -MEXi9Xyj7u24PSx_Jvgw9TuwyOPq0iNP_ntkEuuNNSYC +Cfxhimvf7nMO99ky_58fDRvaiZ6Q6175h0Uet70Um30C From ce9a604a3bad2c56067d8fac2a5251d17c312fbf Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 01:18:04 -0400 Subject: [PATCH 0009/1547] Roll Flutter Engine from 650ff096488a to 8aa2e6516af1 (1 revision) (#130116) https://github.com/flutter/engine/compare/650ff096488a...8aa2e6516af1 2023-07-07 dnfield@google.com [Impeller] Duplicate include removal from lazy_glyph_atlas.cc. (flutter/engine#43453) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a00f0d138cf2a..445788c87e6f7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -650ff096488a13ee360f5e877e276b678cb3d71f +8aa2e6516af16a7c76e9e47e48e4f6aa0d2ea667 From d5b8db303f6d333a5b6367ac12050f254a9543c9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 11:53:56 -0400 Subject: [PATCH 0010/1547] Roll Packages from 771ec9b42a38 to 9bcf4bfa493f (12 revisions) (#130143) https://github.com/flutter/packages/compare/771ec9b42a38...9bcf4bfa493f 2023-07-07 stuartmorgan@google.com [ci] Add LUCI web platform tests (flutter/packages#4391) 2023-07-07 stuartmorgan@google.com [webview_flutter] Enable unawaited_futures lint (flutter/packages#4271) 2023-07-07 stuartmorgan@google.com [ci] Add partial LUCI version of repo_checks (flutter/packages#4389) 2023-07-06 49699333+dependabot[bot]@users.noreply.github.com Bump ossf/scorecard-action from 2.1.3 to 2.2.0 (flutter/packages#4302) 2023-07-06 10687576+bparrishMines@users.noreply.github.com [webview_flutter_android][webview_flutter_wkwebview] Fixes unawaited_futures violations (flutter/packages#4354) 2023-07-06 stuartmorgan@google.com [local_auth] Update Windows Pigeon version (flutter/packages#4388) 2023-07-06 77553258+victorsanni@users.noreply.github.com [url_launcher] Remove nested third_party safari checker (flutter/packages#4330) 2023-07-06 stuartmorgan@google.com [ci] Add partial LUCI Android platform tests (flutter/packages#4381) 2023-07-06 stuartmorgan@google.com [ci] Switch `master` Linux custom package tests to LUCI (flutter/packages#4386) 2023-07-06 47866232+chunhtai@users.noreply.github.com [go_router] Exposes package-level privates (flutter/packages#4380) 2023-07-06 stuartmorgan@google.com [file_selector] Update to 1.0 (flutter/packages#4362) 2023-07-06 engine-flutter-autoroll@skia.org Roll Flutter from 35085c394dda to bc49cd1bcab5 (14 revisions) (flutter/packages#4387) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 3999e9c238279..c16fcbc09de6e 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -771ec9b42a382b2282d2a18f99e96b6276d7063c +9bcf4bfa493f630c5505db8fc9d79e19a7c29a5a From d55a7d89e05ede19676ef8065e4c72123107b6dd Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Fri, 7 Jul 2023 09:39:08 -0700 Subject: [PATCH 0011/1547] Revert "fix a bug when android uses CupertinoPageTransitionsBuilder..." (#130144) Reverts flutter/flutter#114303 The breaking API change in flutter/flutter#114303 broke internal tests/apps (Google internal link b/290154304) as well as external dependents: https://github.com/flutter/flutter/issues/130062. Fixes https://github.com/flutter/flutter/issues/130062 --- packages/flutter/lib/src/material/page.dart | 18 +-- .../src/material/page_transitions_theme.dart | 9 +- .../material/page_transitions_theme_test.dart | 136 ------------------ 3 files changed, 9 insertions(+), 154 deletions(-) diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index 4ab01b2d591ce..73d677ff4cd78 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -80,8 +80,6 @@ class MaterialPageRoute extends PageRoute with MaterialRouteTransitionMixi /// * [CupertinoPageTransitionsBuilder], which is the default page transition /// for iOS and macOS. mixin MaterialRouteTransitionMixin on PageRoute { - TargetPlatform? _effectiveTargetPlatform; - /// Builds the primary contents of the route. @protected Widget buildContent(BuildContext context); @@ -118,20 +116,8 @@ mixin MaterialRouteTransitionMixin on PageRoute { @override Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { - return ValueListenableBuilder( - valueListenable: navigator!.userGestureInProgressNotifier, - builder: (BuildContext context, bool useGestureInProgress, Widget? _) { - final ThemeData themeData = Theme.of(context); - - if (useGestureInProgress) { - // The platform should be kept unchanged during an user gesture. - _effectiveTargetPlatform ??= themeData.platform; - } else { - _effectiveTargetPlatform = themeData.platform; - } - return themeData.pageTransitionsTheme.buildTransitions(this, context, animation, secondaryAnimation, child, _effectiveTargetPlatform!); - }, - ); + final PageTransitionsTheme theme = Theme.of(context).pageTransitionsTheme; + return theme.buildTransitions(this, context, animation, secondaryAnimation, child); } } diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart index 6cf76570dfbd7..7c960a8362f79 100644 --- a/packages/flutter/lib/src/material/page_transitions_theme.dart +++ b/packages/flutter/lib/src/material/page_transitions_theme.dart @@ -741,7 +741,7 @@ class PageTransitionsTheme with Diagnosticable { Map get builders => _builders; final Map _builders; - /// Delegates to the builder for the current [platform]. + /// Delegates to the builder for the current [ThemeData.platform]. /// If a builder for the current platform is not found, then the /// [ZoomPageTransitionsBuilder] is used. /// @@ -752,8 +752,13 @@ class PageTransitionsTheme with Diagnosticable { Animation animation, Animation secondaryAnimation, Widget child, - TargetPlatform platform, ) { + TargetPlatform platform = Theme.of(context).platform; + + if (CupertinoRouteTransitionMixin.isPopGestureInProgress(route)) { + platform = TargetPlatform.iOS; + } + final PageTransitionsBuilder matchingBuilder = builders[platform] ?? const ZoomPageTransitionsBuilder(); return matchingBuilder.buildTransitions(route, context, animation, secondaryAnimation, child); diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart index e1f933da48202..323d4ed0c03d2 100644 --- a/packages/flutter/test/material/page_transitions_theme_test.dart +++ b/packages/flutter/test/material/page_transitions_theme_test.dart @@ -350,140 +350,4 @@ void main() { await tester.pumpAndSettle(); expect(builtCount, 1); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - - testWidgets('android can use CupertinoPageTransitionsBuilder', (WidgetTester tester) async { - int builtCount = 0; - - final Map routes = { - '/': (BuildContext context) => Material( - child: TextButton( - child: const Text('push'), - onPressed: () { Navigator.of(context).pushNamed('/b'); }, - ), - ), - '/b': (BuildContext context) => StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - builtCount++; - return TextButton( - child: const Text('pop'), - onPressed: () { Navigator.pop(context); }, - ); - }, - ), - }; - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - pageTransitionsTheme: const PageTransitionsTheme( - builders: { - TargetPlatform.android: CupertinoPageTransitionsBuilder(), - // iOS uses different PageTransitionsBuilder - TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(), - }, - ), - ), - routes: routes, - ), - ); - - // No matter push or pop was called, the child widget should built only once. - await tester.tap(find.text('push')); - await tester.pumpAndSettle(); - expect(builtCount, 1); - - final Size size = tester.getSize(find.byType(MaterialApp)); - await tester.flingFrom(Offset(0, size.height / 2), Offset(size.width * 2 / 3, 0), 500); - - await tester.pumpAndSettle(); - expect(find.text('push'), findsOneWidget); - expect(builtCount, 1); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - - testWidgets('back gesture while TargetPlatform changes', (WidgetTester tester) async { - final Map routes = { - '/': (BuildContext context) => Material( - child: TextButton( - child: const Text('PUSH'), - onPressed: () { Navigator.of(context).pushNamed('/b'); }, - ), - ), - '/b': (BuildContext context) => const Text('HELLO'), - }; - const PageTransitionsTheme pageTransitionsTheme = PageTransitionsTheme( - builders: { - TargetPlatform.android: CupertinoPageTransitionsBuilder(), - // iOS uses different PageTransitionsBuilder - TargetPlatform.iOS: FadeUpwardsPageTransitionsBuilder(), - }, - ); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - platform: TargetPlatform.android, - pageTransitionsTheme: pageTransitionsTheme, - ), - routes: routes, - ), - ); - await tester.tap(find.text('PUSH')); - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2); - expect(find.text('PUSH'), findsNothing); - expect(find.text('HELLO'), findsOneWidget); - - final Offset helloPosition1 = tester.getCenter(find.text('HELLO')); - final TestGesture gesture = await tester.startGesture(const Offset(2.5, 300.0)); - await tester.pump(const Duration(milliseconds: 20)); - await gesture.moveBy(const Offset(100.0, 0.0)); - expect(find.text('PUSH'), findsNothing); - expect(find.text('HELLO'), findsOneWidget); - await tester.pump(const Duration(milliseconds: 20)); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsOneWidget); - final Offset helloPosition2 = tester.getCenter(find.text('HELLO')); - expect(helloPosition1.dx, lessThan(helloPosition2.dx)); - expect(helloPosition1.dy, helloPosition2.dy); - expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.android); - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - platform: TargetPlatform.iOS, - pageTransitionsTheme: pageTransitionsTheme, - ), - routes: routes, - ), - ); - // Now, let the theme animation run through. - // This takes three frames (including the first one above): - // 1. Start the Theme animation. It's at t=0 so everything else is identical. - // 2. Start any animations that are informed by the Theme, for example, the - // DefaultTextStyle, on the first frame that the theme is not at t=0. In - // this case, it's at t=1.0 of the theme animation, so this is also the - // frame in which the theme animation ends. - // 3. End all the other animations. - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2); - expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.iOS); - final Offset helloPosition3 = tester.getCenter(find.text('HELLO')); - expect(helloPosition3, helloPosition2); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsOneWidget); - await gesture.moveBy(const Offset(100.0, 0.0)); - await tester.pump(const Duration(milliseconds: 20)); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsOneWidget); - final Offset helloPosition4 = tester.getCenter(find.text('HELLO')); - expect(helloPosition3.dx, lessThan(helloPosition4.dx)); - expect(helloPosition3.dy, helloPosition4.dy); - await gesture.moveBy(const Offset(500.0, 0.0)); - await gesture.up(); - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 3); - expect(find.text('PUSH'), findsOneWidget); - expect(find.text('HELLO'), findsNothing); - - await tester.tap(find.text('PUSH')); - expect(await tester.pumpAndSettle(const Duration(minutes: 1)), 2); - expect(find.text('PUSH'), findsNothing); - expect(find.text('HELLO'), findsOneWidget); - }); } From 6683468f0b6516fed218a623a2ce94f4ca0cf342 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:49:00 -0500 Subject: [PATCH 0012/1547] Add debugging for iOS startup test flakes (#130099) Adding debugging for https://github.com/flutter/flutter/issues/129836. Takes a screenshot when startup test takes too long (10 minutes). Also, removes some old debugging and add new debugging message. --- dev/devicelab/lib/tasks/perf_tests.dart | 47 +++++++++++++------ .../flutter_tools/lib/src/ios/ios_deploy.dart | 17 +++++-- .../general.shard/ios/ios_deploy_test.dart | 27 +++++++++++ 3 files changed, 71 insertions(+), 20 deletions(-) diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index b35bb41a1342d..20c8389cf2309 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -771,6 +771,15 @@ class StartupTest { const int maxFailures = 3; int currentFailures = 0; for (int i = 0; i < iterations; i += 1) { + // Startup should not take more than a few minutes. After 10 minutes, + // take a screenshot to help debug. + final Timer timer = Timer(const Duration(minutes: 10), () async { + print('Startup not completed within 10 minutes. Taking a screenshot...'); + await _flutterScreenshot( + device.deviceId, + 'screenshot_startup_${DateTime.now().toLocal().toIso8601String()}.png', + ); + }); final int result = await flutter('run', options: [ '--no-android-gradle-daemon', '--no-publish-port', @@ -782,7 +791,8 @@ class StartupTest { device.deviceId, if (applicationBinaryPath != null) '--use-application-binary=$applicationBinaryPath', - ], canFail: true); + ], canFail: true); + timer.cancel(); if (result == 0) { final Map data = json.decode( file('${_testOutputDirectory(testDirectory)}/start_up_info.json').readAsStringSync(), @@ -790,20 +800,10 @@ class StartupTest { results.add(data); } else { currentFailures += 1; - if (hostAgent.dumpDirectory != null) { - await flutter( - 'screenshot', - options: [ - '-d', - device.deviceId, - '--out', - hostAgent.dumpDirectory! - .childFile('screenshot_startup_failure_$currentFailures.png') - .path, - ], - canFail: true, - ); - } + await _flutterScreenshot( + device.deviceId, + 'screenshot_startup_failure_$currentFailures.png', + ); i -= 1; if (currentFailures == maxFailures) { return TaskResult.failure('Application failed to start $maxFailures times'); @@ -829,6 +829,23 @@ class StartupTest { ]); }); } + + Future _flutterScreenshot(String deviceId, String screenshotName) async { + if (hostAgent.dumpDirectory != null) { + await flutter( + 'screenshot', + options: [ + '-d', + deviceId, + '--out', + hostAgent.dumpDirectory! + .childFile(screenshotName) + .path, + ], + canFail: true, + ); + } + } } /// A one-off test to verify that devtools starts in profile mode. diff --git a/packages/flutter_tools/lib/src/ios/ios_deploy.dart b/packages/flutter_tools/lib/src/ios/ios_deploy.dart index 2d1f7d6ffbe53..846b9b4c79ef5 100644 --- a/packages/flutter_tools/lib/src/ios/ios_deploy.dart +++ b/packages/flutter_tools/lib/src/ios/ios_deploy.dart @@ -338,6 +338,8 @@ class IOSDeployDebugger { RegExp lldbRun = RegExp(r'\(lldb\)\s*run'); final Completer debuggerCompleter = Completer(); + + bool receivedLogs = false; try { _iosDeployProcess = await _processUtils.start( _launchCommand, @@ -386,8 +388,6 @@ class IOSDeployDebugger { if (lldbRun.hasMatch(line)) { _logger.printTrace(line); _debuggerState = _IOSDeployDebuggerState.launching; - // TODO(vashworth): Remove all debugger state comments when https://github.com/flutter/flutter/issues/126412 is resolved. - _logger.printTrace('Debugger state set to launching.'); return; } // Next line after "run" must be "success", or the attach failed. @@ -396,7 +396,6 @@ class IOSDeployDebugger { _logger.printTrace(line); final bool attachSuccess = line == 'success'; _debuggerState = attachSuccess ? _IOSDeployDebuggerState.attached : _IOSDeployDebuggerState.detached; - _logger.printTrace('Debugger state set to ${attachSuccess ? 'attached' : 'detached'}.'); if (!debuggerCompleter.isCompleted) { debuggerCompleter.complete(attachSuccess); } @@ -425,7 +424,6 @@ class IOSDeployDebugger { // Even though we're not "detached", just stopped, mark as detached so the backtrace // is only show in verbose. _debuggerState = _IOSDeployDebuggerState.detached; - _logger.printTrace('Debugger state set to detached.'); // If we paused the app and are waiting to resume it, complete the completer final Completer? processResumeCompleter = _processResumeCompleter; @@ -465,7 +463,6 @@ class IOSDeployDebugger { _logger.printTrace(line); // we marked this detached when we received [_backTraceAll] _debuggerState = _IOSDeployDebuggerState.attached; - _logger.printTrace('Debugger state set to attached.'); return; } @@ -480,6 +477,16 @@ class IOSDeployDebugger { // This will still cause "legit" logged newlines to be doubled... } else if (!_debuggerOutput.isClosed) { _debuggerOutput.add(line); + + // Sometimes the `ios-deploy` process does not return logs from the + // application after attaching, such as the Dart VM url. In CI, + // `idevicesyslog` is used as a fallback to get logs. Print a + // message to indicate whether logs were received from `ios-deploy` + // to help with debugging. + if (!receivedLogs) { + _logger.printTrace('Received logs from ios-deploy.'); + receivedLogs = true; + } } lastLineFromDebugger = line; }); diff --git a/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart index 72e453823fcb7..e5bce99b638a2 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart @@ -341,6 +341,33 @@ void main () { await iosDeployDebugger.launchAndAttach(); expect(logger.errorText, contains('Try launching from within Xcode')); }); + + testWithoutContext('debugger attached and received logs', () async { + final StreamController> stdin = StreamController>(); + final FakeProcessManager processManager = FakeProcessManager.list([ + FakeCommand( + command: const ['ios-deploy'], + stdout: '(lldb) run\r\nsuccess\r\nLog on attach1\r\n\r\nLog on attach2\r\n', + stdin: IOSink(stdin.sink), + ), + ]); + final IOSDeployDebugger iosDeployDebugger = IOSDeployDebugger.test( + processManager: processManager, + logger: logger, + ); + final List receivedLogLines = []; + final Stream logLines = iosDeployDebugger.logLines + ..listen(receivedLogLines.add); + + expect(iosDeployDebugger.logLines, emitsInOrder([ + 'Log on attach1', + 'Log on attach2', + ])); + expect(await iosDeployDebugger.launchAndAttach(), isTrue); + await logLines.drain(); + + expect(LineSplitter.split(logger.traceText), containsOnce('Received logs from ios-deploy.')); + }); }); testWithoutContext('detach', () async { From 9373289249c2354e80af02679d96fc3c87dfdccf Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 12:55:54 -0400 Subject: [PATCH 0013/1547] Roll Flutter Engine from 8aa2e6516af1 to 5ae09b8b4fa3 (7 revisions) (#130150) https://github.com/flutter/engine/compare/8aa2e6516af1...5ae09b8b4fa3 2023-07-07 aam@google.com Revert "Manual roll Dart SDK from 2d98d9e27dae to 0b07debd5862 (21 revisions) (#43457)" (flutter/engine#43466) 2023-07-07 skia-flutter-autoroll@skia.org Roll Skia from 7a3a89fadc25 to 5eba922297bb (1 revision) (flutter/engine#43464) 2023-07-07 skia-flutter-autoroll@skia.org Roll Skia from adf5b9c27c33 to 7a3a89fadc25 (1 revision) (flutter/engine#43462) 2023-07-07 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 3D0ft09qP4-Hp_3mQ... to MPy31yjgPV-d_YJq0... (flutter/engine#43460) 2023-07-07 skia-flutter-autoroll@skia.org Roll Skia from 57dc2a31bf26 to adf5b9c27c33 (2 revisions) (flutter/engine#43459) 2023-07-07 skia-flutter-autoroll@skia.org Roll Skia from 11a2eefe4c61 to 57dc2a31bf26 (1 revision) (flutter/engine#43456) 2023-07-07 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 2d98d9e27dae to 0b07debd5862 (21 revisions) (flutter/engine#43457) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 3D0ft09qP4-H to MPy31yjgPV-d If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 445788c87e6f7..005097ae5c9ac 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8aa2e6516af16a7c76e9e47e48e4f6aa0d2ea667 +5ae09b8b4fa381e8723ed5382a26eafd0d97236f diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 94c7734c21ec3..747bb027b1e25 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -3D0ft09qP4-Hp_3mQoSznlSZ6q9XPGl7Yt9lrqlk-0cC +MPy31yjgPV-d_YJq0flrP6oOibi_1do-LGtXh4cHOqEC From 61ebf755d766cb113537981b68d7e6d0efa950a2 Mon Sep 17 00:00:00 2001 From: fzyzcjy <5236035+fzyzcjy@users.noreply.github.com> Date: Sat, 8 Jul 2023 01:11:49 +0800 Subject: [PATCH 0014/1547] Tiny one space formatting fix (#130053) You know, I like to see beautiful code, so really hope we have auto formatter, such that all these (at least such formatting error) can be done automatically! --- packages/flutter/lib/src/material/date.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/date.dart b/packages/flutter/lib/src/material/date.dart index 8d59527e48daa..b6e00827b7272 100644 --- a/packages/flutter/lib/src/material/date.dart +++ b/packages/flutter/lib/src/material/date.dart @@ -67,7 +67,7 @@ abstract final class DateUtils { /// /// `date` would be January 15, 2019. /// `futureDate` would be April 1, 2019 since it adds 3 months. - static DateTime addMonthsToMonthDate(DateTime monthDate, int monthsToAdd) { + static DateTime addMonthsToMonthDate(DateTime monthDate, int monthsToAdd) { return DateTime(monthDate.year, monthDate.month + monthsToAdd); } From 8ab46bbce4d2c70559dafe1aeb55cea7fcd9a9f4 Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Fri, 7 Jul 2023 10:25:35 -0700 Subject: [PATCH 0015/1547] (Raw)Autocomplete: Add optional [optionsViewOpenDirection] param (#129802) Allows positioning Autocomplete options above the field (previously hardcoded to under the field). --- .../lib/src/material/autocomplete.dart | 5 + .../flutter/lib/src/widgets/autocomplete.dart | 54 ++++++- .../test/material/autocomplete_test.dart | 49 +++++++ .../test/widgets/autocomplete_test.dart | 138 ++++++++++++++++++ 4 files changed, 240 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/material/autocomplete.dart b/packages/flutter/lib/src/material/autocomplete.dart index 9f00633c9cc1e..c078018a6a0d5 100644 --- a/packages/flutter/lib/src/material/autocomplete.dart +++ b/packages/flutter/lib/src/material/autocomplete.dart @@ -66,6 +66,7 @@ class Autocomplete extends StatelessWidget { this.onSelected, this.optionsMaxHeight = 200.0, this.optionsViewBuilder, + this.optionsViewOpenDirection = OptionsViewOpenDirection.down, this.initialValue, }); @@ -90,6 +91,9 @@ class Autocomplete extends StatelessWidget { /// default. final AutocompleteOptionsViewBuilder? optionsViewBuilder; + /// {@macro flutter.widgets.RawAutocomplete.optionsViewOpenDirection} + final OptionsViewOpenDirection optionsViewOpenDirection; + /// The maximum height used for the default Material options list widget. /// /// When [optionsViewBuilder] is `null`, this property sets the maximum height @@ -116,6 +120,7 @@ class Autocomplete extends StatelessWidget { fieldViewBuilder: fieldViewBuilder, initialValue: initialValue, optionsBuilder: optionsBuilder, + optionsViewOpenDirection: optionsViewOpenDirection, optionsViewBuilder: optionsViewBuilder ?? (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { return _AutocompleteOptions( displayStringForOption: displayStringForOption, diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index 967c1160a2f82..c5171ae50eba1 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -77,6 +77,29 @@ typedef AutocompleteFieldViewBuilder = Widget Function( /// * [RawAutocomplete.displayStringForOption], which is of this type. typedef AutocompleteOptionToString = String Function(T option); +/// A direction in which to open the options-view overlay. +/// +/// See also: +/// +/// * [RawAutocomplete.optionsViewOpenDirection], which is of this type. +/// * [RawAutocomplete.optionsViewBuilder] to specify how to build the +/// selectable-options widget. +/// * [RawAutocomplete.fieldViewBuilder] to optionally specify how to build the +/// corresponding field widget. +enum OptionsViewOpenDirection { + /// Open upward. + /// + /// The bottom edge of the options view will align with the top edge + /// of the text field built by [RawAutocomplete.fieldViewBuilder]. + up, + + /// Open downward. + /// + /// The top edge of the options view will align with the bottom edge + /// of the text field built by [RawAutocomplete.fieldViewBuilder]. + down, +} + // TODO(justinmc): Mention AutocompleteCupertino when it is implemented. /// {@template flutter.widgets.RawAutocomplete.RawAutocomplete} /// A widget for helping the user make a selection by entering some text and @@ -128,6 +151,7 @@ class RawAutocomplete extends StatefulWidget { super.key, required this.optionsViewBuilder, required this.optionsBuilder, + this.optionsViewOpenDirection = OptionsViewOpenDirection.down, this.displayStringForOption = defaultStringForOption, this.fieldViewBuilder, this.focusNode, @@ -151,6 +175,9 @@ class RawAutocomplete extends StatefulWidget { /// Pass the provided [TextEditingController] to the field built here so that /// RawAutocomplete can listen for changes. /// {@endtemplate} + /// + /// If this parameter is null, then a [SizedBox.shrink] is built instead. + /// For how that pattern can be useful, see [textEditingController]. final AutocompleteFieldViewBuilder? fieldViewBuilder; /// The [FocusNode] that is used for the text field. @@ -161,9 +188,9 @@ class RawAutocomplete extends StatefulWidget { /// field built by [fieldViewBuilder]. For example, it may be desirable to /// place the text field in the AppBar and the options below in the main body. /// - /// When following this pattern, [fieldViewBuilder] can return - /// `SizedBox.shrink()` so that nothing is drawn where the text field would - /// normally be. A separate text field can be created elsewhere, and a + /// When following this pattern, [fieldViewBuilder] can be omitted, + /// so that a text field is not drawn where it would normally be. + /// A separate text field can be created elsewhere, and a /// FocusNode and TextEditingController can be passed both to that text field /// and to RawAutocomplete. /// @@ -182,9 +209,10 @@ class RawAutocomplete extends StatefulWidget { /// {@template flutter.widgets.RawAutocomplete.optionsViewBuilder} /// Builds the selectable options widgets from a list of options objects. /// - /// The options are displayed floating below the field using a + /// The options are displayed floating below or above the field using a /// [CompositedTransformFollower] inside of an [Overlay], not at the same - /// place in the widget tree as [RawAutocomplete]. + /// place in the widget tree as [RawAutocomplete]. To control whether it opens + /// upward or downward, use [optionsViewOpenDirection]. /// /// In order to track which item is highlighted by keyboard navigation, the /// resulting options will be wrapped in an inherited @@ -197,6 +225,13 @@ class RawAutocomplete extends StatefulWidget { /// {@endtemplate} final AutocompleteOptionsViewBuilder optionsViewBuilder; + /// {@template flutter.widgets.RawAutocomplete.optionsViewOpenDirection} + /// The direction in which to open the options-view overlay. + /// + /// Defaults to [OptionsViewOpenDirection.down]. + /// {@endtemplate} + final OptionsViewOpenDirection optionsViewOpenDirection; + /// {@template flutter.widgets.RawAutocomplete.displayStringForOption} /// Returns the string to display in the field when the option is selected. /// @@ -421,7 +456,14 @@ class _RawAutocompleteState extends State> return CompositedTransformFollower( link: _optionsLayerLink, showWhenUnlinked: false, - targetAnchor: Alignment.bottomLeft, + targetAnchor: switch (widget.optionsViewOpenDirection) { + OptionsViewOpenDirection.up => Alignment.topLeft, + OptionsViewOpenDirection.down => Alignment.bottomLeft, + }, + followerAnchor: switch (widget.optionsViewOpenDirection) { + OptionsViewOpenDirection.up => Alignment.bottomLeft, + OptionsViewOpenDirection.down => Alignment.topLeft, + }, child: TextFieldTapRegion( child: AutocompleteHighlightedOption( highlightIndexNotifier: _highlightedOptionIndex, diff --git a/packages/flutter/test/material/autocomplete_test.dart b/packages/flutter/test/material/autocomplete_test.dart index ad33efd68c667..45f028bc02237 100644 --- a/packages/flutter/test/material/autocomplete_test.dart +++ b/packages/flutter/test/material/autocomplete_test.dart @@ -507,4 +507,53 @@ void main() { checkOptionHighlight(tester, 'lemur', null); checkOptionHighlight(tester, 'northern white rhinoceros', null); }); + + group('optionsViewOpenDirection', () { + testWidgets('default (down)', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Autocomplete( + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + ), + ), + ), + ); + final OptionsViewOpenDirection actual = tester.widget>(find.byType(RawAutocomplete)) + .optionsViewOpenDirection; + expect(actual, equals(OptionsViewOpenDirection.down)); + }); + + testWidgets('down', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Autocomplete( + optionsViewOpenDirection: OptionsViewOpenDirection.down, // ignore: avoid_redundant_argument_values + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + ), + ), + ), + ); + final OptionsViewOpenDirection actual = tester.widget>(find.byType(RawAutocomplete)) + .optionsViewOpenDirection; + expect(actual, equals(OptionsViewOpenDirection.down)); + }); + + testWidgets('up', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Autocomplete( + optionsViewOpenDirection: OptionsViewOpenDirection.up, + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + ), + ), + ), + ); + final OptionsViewOpenDirection actual = tester.widget>(find.byType(RawAutocomplete)) + .optionsViewOpenDirection; + expect(actual, equals(OptionsViewOpenDirection.up)); + }); + }); } diff --git a/packages/flutter/test/widgets/autocomplete_test.dart b/packages/flutter/test/widgets/autocomplete_test.dart index a35d324e5d4ef..cbedb27c76977 100644 --- a/packages/flutter/test/widgets/autocomplete_test.dart +++ b/packages/flutter/test/widgets/autocomplete_test.dart @@ -421,6 +421,144 @@ void main() { expect(textEditingController.text, lastOptions.elementAt(0)); }); + group('optionsViewOpenDirection', () { + testWidgets('unset (default behavior): open downward', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: RawAutocomplete( + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + fieldViewBuilder: (BuildContext context, TextEditingController controller, FocusNode focusNode, VoidCallback onFieldSubmitted) { + return TextField(controller: controller, focusNode: focusNode); + }, + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + return const Text('a'); + }, + ), + ), + ), + ), + ); + await tester.showKeyboard(find.byType(TextField)); + expect(tester.getBottomLeft(find.byType(TextField)), + offsetMoreOrLessEquals(tester.getTopLeft(find.text('a')))); + }); + + testWidgets('down: open downward', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: RawAutocomplete( + optionsViewOpenDirection: OptionsViewOpenDirection.down, // ignore: avoid_redundant_argument_values + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + fieldViewBuilder: (BuildContext context, TextEditingController controller, FocusNode focusNode, VoidCallback onFieldSubmitted) { + return TextField(controller: controller, focusNode: focusNode); + }, + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + return const Text('a'); + }, + ), + ), + ), + ), + ); + await tester.showKeyboard(find.byType(TextField)); + expect(tester.getBottomLeft(find.byType(TextField)), + offsetMoreOrLessEquals(tester.getTopLeft(find.text('a')))); + }); + + testWidgets('up: open upward', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: RawAutocomplete( + optionsViewOpenDirection: OptionsViewOpenDirection.up, + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + fieldViewBuilder: (BuildContext context, TextEditingController controller, FocusNode focusNode, VoidCallback onFieldSubmitted) { + return TextField(controller: controller, focusNode: focusNode); + }, + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + return const Text('a'); + }, + ), + ), + ), + ), + ); + await tester.showKeyboard(find.byType(TextField)); + expect(tester.getTopLeft(find.byType(TextField)), + offsetMoreOrLessEquals(tester.getBottomLeft(find.text('a')))); + }); + + group('fieldViewBuilder not passed', () { + testWidgets('down', (WidgetTester tester) async { + final GlobalKey autocompleteKey = GlobalKey(); + final TextEditingController controller = TextEditingController(); + final FocusNode focusNode = FocusNode(); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextField(controller: controller, focusNode: focusNode), + RawAutocomplete( + key: autocompleteKey, + textEditingController: controller, + focusNode: focusNode, + optionsViewOpenDirection: OptionsViewOpenDirection.down, // ignore: avoid_redundant_argument_values + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + return const Text('a'); + }, + ), + ], + ), + ), + ), + ); + await tester.showKeyboard(find.byType(TextField)); + expect(tester.getBottomLeft(find.byKey(autocompleteKey)), + offsetMoreOrLessEquals(tester.getTopLeft(find.text('a')))); + }); + + testWidgets('up', (WidgetTester tester) async { + final GlobalKey autocompleteKey = GlobalKey(); + final TextEditingController controller = TextEditingController(); + final FocusNode focusNode = FocusNode(); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Column( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RawAutocomplete( + key: autocompleteKey, + textEditingController: controller, + focusNode: focusNode, + optionsViewOpenDirection: OptionsViewOpenDirection.up, + optionsBuilder: (TextEditingValue textEditingValue) => ['a'], + optionsViewBuilder: (BuildContext context, AutocompleteOnSelected onSelected, Iterable options) { + return const Text('a'); + }, + ), + TextField(controller: controller, focusNode: focusNode), + ], + ), + ), + ), + ); + await tester.showKeyboard(find.byType(TextField)); + expect(tester.getTopLeft(find.byKey(autocompleteKey)), + offsetMoreOrLessEquals(tester.getBottomLeft(find.text('a')))); + }); + }); + }); + testWidgets('options follow field when it moves', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); From f2e281fb31efc40a878e8e65cc6543341ffd97bc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 13:30:27 -0400 Subject: [PATCH 0016/1547] Roll Packages from 9bcf4bfa493f to b61eea12dbf9 (1 revision) (#130154) https://github.com/flutter/packages/compare/9bcf4bfa493f...b61eea12dbf9 2023-07-07 aam@google.com Roll pigeon dependency to unblock flutter framework deps roll (flutter/packages#4383) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index c16fcbc09de6e..7b80e436d6ad1 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -9bcf4bfa493f630c5505db8fc9d79e19a7c29a5a +b61eea12dbf94650fac7aaaed1e880b6cde69442 From 3f2d798bd6c21f3118927aa801f2aae833062d59 Mon Sep 17 00:00:00 2001 From: Caique Ribeiro de Oliveira Date: Fri, 7 Jul 2023 15:09:57 -0300 Subject: [PATCH 0017/1547] Fix XCode download link (#129795) image I was installing Flutter and noticed that the download link for Xcode is incorrect. They might have changed it, but the current link doesn't exist. --- packages/flutter_tools/lib/src/base/user_messages.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 8441db2a7df04..1c13db18f95e6 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -183,10 +183,10 @@ class UserMessages { ' sudo xcodebuild -runFirstLaunch'; String get xcodeMissing => 'Xcode not installed; this is necessary for iOS and macOS development.\n' - 'Download at https://developer.apple.com/xcode/download/.'; + 'Download at https://developer.apple.com/xcode/.'; String get xcodeIncomplete => 'Xcode installation is incomplete; a full installation is necessary for iOS and macOS development.\n' - 'Download at: https://developer.apple.com/xcode/download/\n' + 'Download at: https://developer.apple.com/xcode/\n' 'Or install Xcode via the App Store.\n' 'Once installed, run:\n' ' sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer\n' From ce508286693e63454e4d43f8aac4fbcad36d10d7 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 7 Jul 2023 12:33:08 -0700 Subject: [PATCH 0018/1547] Test that inspector does not hold objects. (#130102) --- .../test/widgets/widget_inspector_test.dart | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 743b4da59ea8f..9f18ec163069a 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -10,6 +10,7 @@ library; import 'dart:convert'; +import 'dart:developer'; import 'dart:math'; import 'dart:ui' as ui; @@ -240,6 +241,29 @@ extension TextFromString on String { } } +/// Forces garbage collection by aggressive memory allocation. +/// +/// Copied from internal code of +/// https://github.com/dart-lang/leak_tracker +Future _forceGC() async { + const int gcCycles = 3; // 1 should be enough, but we do 3 to make sure test is not flaky. + final int barrier = reachabilityBarrier; + + final List> storage = >[]; + + void allocateMemory() { + storage.add(Iterable.generate(10000, (_) => DateTime.now()).toList()); + if (storage.length > 100) { + storage.removeAt(0); + } + } + + while (reachabilityBarrier < barrier + gcCycles) { + await Future.delayed(Duration.zero); + allocateMemory(); + } +} + final List _weakValueTests = [1, 1.0, 'hello', true, false, Object(), [3, 4], DateTime(2023)]; void main() { @@ -299,6 +323,19 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(WidgetInspectorService.objectToDiagnosticsNode(Alignment.bottomCenter), isNull); }); + test('WidgetInspector does not hold objects from GC', () async { + List? someObject = [DateTime.now(), DateTime.now()]; + final String? id = service.toId(someObject, 'group_name'); + + expect(id, isNotNull); + + final WeakReference ref = WeakReference(someObject); + someObject = null; + await _forceGC(); + + expect(ref.target, null); + }); + testWidgets('WidgetInspector smoke test', (WidgetTester tester) async { // This is a smoke test to verify that adding the inspector doesn't crash. await tester.pumpWidget( @@ -3775,7 +3812,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { _CreationLocation location = knownLocations[id]!; expect(location.file, equals(file)); // ClockText widget. - expect(location.line, equals(55)); + expect(location.line, equals(56)); expect(location.column, equals(9)); expect(location.name, equals('ClockText')); expect(count, equals(1)); @@ -3785,7 +3822,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { location = knownLocations[id]!; expect(location.file, equals(file)); // Text widget in _ClockTextState build method. - expect(location.line, equals(93)); + expect(location.line, equals(94)); expect(location.column, equals(12)); expect(location.name, equals('Text')); expect(count, equals(1)); @@ -3812,7 +3849,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { location = knownLocations[id]!; expect(location.file, equals(file)); // ClockText widget. - expect(location.line, equals(55)); + expect(location.line, equals(56)); expect(location.column, equals(9)); expect(location.name, equals('ClockText')); expect(count, equals(3)); // 3 clock widget instances rebuilt. @@ -3822,7 +3859,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { location = knownLocations[id]!; expect(location.file, equals(file)); // Text widget in _ClockTextState build method. - expect(location.line, equals(93)); + expect(location.line, equals(94)); expect(location.column, equals(12)); expect(location.name, equals('Text')); expect(count, equals(3)); // 3 clock widget instances rebuilt. From acb0855432333f367f4c900fdd9c04e19631abdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20S=20Guerrero?= Date: Fri, 7 Jul 2023 14:04:00 -0600 Subject: [PATCH 0019/1547] Revert "[a11y] CupertinoSwitch On/Off labels" (#130166) Reverts flutter/flutter#127776 Currently breaking google testing --- .../flutter/lib/src/cupertino/switch.dart | 106 ---------- .../flutter/lib/src/widgets/media_query.dart | 41 ---- .../flutter/test/cupertino/switch_test.dart | 181 ------------------ .../test/widgets/media_query_test.dart | 55 ------ 4 files changed, 383 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 75518bcdec84f..2057e115a214f 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -75,8 +75,6 @@ class CupertinoSwitch extends StatefulWidget { this.thumbColor, this.applyTheme, this.focusColor, - this.onLabelColor, - this.offLabelColor, this.focusNode, this.onFocusChange, this.autofocus = false, @@ -135,17 +133,6 @@ class CupertinoSwitch extends StatefulWidget { /// Defaults to a slightly transparent [activeColor]. final Color? focusColor; - /// The color to use for the accessibility label when the switch is on. - /// - /// Defaults to [CupertinoColors.white] when null. - final Color? onLabelColor; - - /// The color to use for the accessibility label when the switch is off. - /// - /// Defaults to [Color.fromARGB(255, 179, 179, 179)] - /// (or [Color.fromARGB(255, 255, 255, 255)] in high contrast) when null. - final Color? offLabelColor; - /// {@macro flutter.widgets.Focus.focusNode} final FocusNode? focusNode; @@ -370,19 +357,6 @@ class _CupertinoSwitchState extends State with TickerProviderSt ?? CupertinoColors.systemGreen, context, ); - final (Color onLabelColor, Color offLabelColor)? onOffLabelColors = - MediaQuery.onOffSwitchLabelsOf(context) - ? ( - CupertinoDynamicColor.resolve( - widget.onLabelColor ?? CupertinoColors.white, - context, - ), - CupertinoDynamicColor.resolve( - widget.offLabelColor ?? _kOffLabelColor, - context, - ), - ) - : null; if (needsPositionAnimation) { _resumePositionAnimation(); } @@ -415,7 +389,6 @@ class _CupertinoSwitchState extends State with TickerProviderSt textDirection: Directionality.of(context), isFocused: isFocused, state: this, - onOffLabelColors: onOffLabelColors, ), ), ), @@ -444,7 +417,6 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { required this.textDirection, required this.isFocused, required this.state, - required this.onOffLabelColors, }); final bool value; @@ -456,7 +428,6 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { final _CupertinoSwitchState state; final TextDirection textDirection; final bool isFocused; - final (Color onLabelColor, Color offLabelColor)? onOffLabelColors; @override _RenderCupertinoSwitch createRenderObject(BuildContext context) { @@ -470,7 +441,6 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { textDirection: textDirection, isFocused: isFocused, state: state, - onOffLabelColors: onOffLabelColors, ); } @@ -497,24 +467,6 @@ const double _kTrackInnerEnd = _kTrackWidth - _kTrackInnerStart; const double _kTrackInnerLength = _kTrackInnerEnd - _kTrackInnerStart; const double _kSwitchWidth = 59.0; const double _kSwitchHeight = 39.0; -// Label sizes and padding taken from xcode inspector. -// See https://github.com/flutter/flutter/issues/4830#issuecomment-528495360 -const double _kOnLabelWidth = 1.0; -const double _kOnLabelHeight = 10.0; -const double _kOnLabelPaddingHorizontal = 11.0; -const double _kOffLabelWidth = 1.0; -const double _kOffLabelPaddingHorizontal = 12.0; -const double _kOffLabelRadius = 5.0; -const CupertinoDynamicColor _kOffLabelColor = CupertinoDynamicColor.withBrightnessAndContrast( - debugLabel: 'offSwitchLabel', - // Source: https://github.com/flutter/flutter/pull/39993#discussion_r321946033 - color: Color.fromARGB(255, 179, 179, 179), - // Source: https://github.com/flutter/flutter/pull/39993#issuecomment-535196665 - darkColor: Color.fromARGB(255, 179, 179, 179), - // Source: https://github.com/flutter/flutter/pull/127776#discussion_r1244208264 - highContrastColor: Color.fromARGB(255, 255, 255, 255), - darkHighContrastColor: Color.fromARGB(255, 255, 255, 255), -); // Opacity of a disabled switch, as eye-balled from iOS Simulator on Mac. const double _kCupertinoSwitchDisabledOpacity = 0.5; @@ -532,7 +484,6 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { required TextDirection textDirection, required bool isFocused, required _CupertinoSwitchState state, - required (Color onLabelColor, Color offLabelColor)? onOffLabelColors, }) : _value = value, _activeColor = activeColor, _trackColor = trackColor, @@ -542,7 +493,6 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { _textDirection = textDirection, _isFocused = isFocused, _state = state, - _onOffLabelColors = onOffLabelColors, super(additionalConstraints: const BoxConstraints.tightFor(width: _kSwitchWidth, height: _kSwitchHeight)) { state.position.addListener(markNeedsPaint); state._reaction.addListener(markNeedsPaint); @@ -634,16 +584,6 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { markNeedsPaint(); } - (Color onLabelColor, Color offLabelColor)? get onOffLabelColors => _onOffLabelColors; - (Color onLabelColor, Color offLabelColor)? _onOffLabelColors; - set onOffLabelColors((Color onLabelColor, Color offLabelColor)? value) { - if (value == _onOffLabelColors) { - return; - } - _onOffLabelColors = value; - markNeedsPaint(); - } - bool get isInteractive => onChanged != null; @override @@ -709,52 +649,6 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { canvas.drawRRect(borderTrackRRect, borderPaint); } - if (_onOffLabelColors != null) { - final (Color onLabelColor, Color offLabelColor) = onOffLabelColors!; - - final double leftLabelOpacity = visualPosition * (1.0 - currentReactionValue); - final double rightLabelOpacity = (1.0 - visualPosition) * (1.0 - currentReactionValue); - final (double onLabelOpacity, double offLabelOpacity) = - switch (textDirection) { - TextDirection.ltr => (leftLabelOpacity, rightLabelOpacity), - TextDirection.rtl => (rightLabelOpacity, leftLabelOpacity), - }; - - final (Offset onLabelOffset, Offset offLabelOffset) = - switch (textDirection) { - TextDirection.ltr => ( - trackRect.centerLeft.translate(_kOnLabelPaddingHorizontal, 0), - trackRect.centerRight.translate(-_kOffLabelPaddingHorizontal, 0), - ), - TextDirection.rtl => ( - trackRect.centerRight.translate(-_kOnLabelPaddingHorizontal, 0), - trackRect.centerLeft.translate(_kOffLabelPaddingHorizontal, 0), - ), - }; - - // Draws '|' label - final Rect onLabelRect = Rect.fromCenter( - center: onLabelOffset, - width: _kOnLabelWidth, - height: _kOnLabelHeight, - ); - final Paint onLabelPaint = Paint() - ..color = onLabelColor.withOpacity(onLabelOpacity) - ..style = PaintingStyle.fill; - canvas.drawRect(onLabelRect, onLabelPaint); - - // Draws 'O' label - final Paint offLabelPaint = Paint() - ..color = offLabelColor.withOpacity(offLabelOpacity) - ..style = PaintingStyle.stroke - ..strokeWidth = _kOffLabelWidth; - canvas.drawCircle( - offLabelOffset, - _kOffLabelRadius, - offLabelPaint, - ); - } - final double currentThumbExtension = CupertinoThumbPainter.extension * currentReactionValue; final double thumbLeft = lerpDouble( trackRect.left + _kTrackInnerStart - CupertinoThumbPainter.radius, diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 0714708e14ade..8cd8ee3c2a379 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -60,8 +60,6 @@ enum _MediaQueryAspect { invertColors, /// Specifies the aspect corresponding to [MediaQueryData.highContrast]. highContrast, - /// Specifies the aspect corresponding to [MediaQueryData.onOffSwitchLabels]. - onOffSwitchLabels, /// Specifies the aspect corresponding to [MediaQueryData.disableAnimations]. disableAnimations, /// Specifies the aspect corresponding to [MediaQueryData.boldText]. @@ -155,7 +153,6 @@ class MediaQueryData { this.accessibleNavigation = false, this.invertColors = false, this.highContrast = false, - this.onOffSwitchLabels = false, this.disableAnimations = false, this.boldText = false, this.navigationMode = NavigationMode.traditional, @@ -223,7 +220,6 @@ class MediaQueryData { disableAnimations = platformData?.disableAnimations ?? view.platformDispatcher.accessibilityFeatures.disableAnimations, boldText = platformData?.boldText ?? view.platformDispatcher.accessibilityFeatures.boldText, highContrast = platformData?.highContrast ?? view.platformDispatcher.accessibilityFeatures.highContrast, - onOffSwitchLabels = platformData?.onOffSwitchLabels ?? view.platformDispatcher.accessibilityFeatures.onOffSwitchLabels, alwaysUse24HourFormat = platformData?.alwaysUse24HourFormat ?? view.platformDispatcher.alwaysUse24HourFormat, navigationMode = platformData?.navigationMode ?? NavigationMode.traditional, gestureSettings = DeviceGestureSettings.fromView(view), @@ -420,15 +416,6 @@ class MediaQueryData { /// or above. final bool highContrast; - /// Whether the user requested to show on/off labels inside switches on iOS, - /// via Settings -> Accessibility -> Display & Text Size -> On/Off Labels. - /// - /// See also: - /// - /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting - /// originates. - final bool onOffSwitchLabels; - /// Whether the platform is requesting that animations be disabled or reduced /// as much as possible. /// @@ -501,7 +488,6 @@ class MediaQueryData { EdgeInsets? systemGestureInsets, bool? alwaysUse24HourFormat, bool? highContrast, - bool? onOffSwitchLabels, bool? disableAnimations, bool? invertColors, bool? accessibleNavigation, @@ -522,7 +508,6 @@ class MediaQueryData { alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat, invertColors: invertColors ?? this.invertColors, highContrast: highContrast ?? this.highContrast, - onOffSwitchLabels: onOffSwitchLabels ?? this.onOffSwitchLabels, disableAnimations: disableAnimations ?? this.disableAnimations, accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation, boldText: boldText ?? this.boldText, @@ -714,7 +699,6 @@ class MediaQueryData { && other.systemGestureInsets == systemGestureInsets && other.alwaysUse24HourFormat == alwaysUse24HourFormat && other.highContrast == highContrast - && other.onOffSwitchLabels == onOffSwitchLabels && other.disableAnimations == disableAnimations && other.invertColors == invertColors && other.accessibleNavigation == accessibleNavigation @@ -735,7 +719,6 @@ class MediaQueryData { viewInsets, alwaysUse24HourFormat, highContrast, - onOffSwitchLabels, disableAnimations, invertColors, accessibleNavigation, @@ -759,7 +742,6 @@ class MediaQueryData { 'alwaysUse24HourFormat: $alwaysUse24HourFormat', 'accessibleNavigation: $accessibleNavigation', 'highContrast: $highContrast', - 'onOffSwitchLabels: $onOffSwitchLabels', 'disableAnimations: $disableAnimations', 'invertColors: $invertColors', 'boldText: $boldText', @@ -1273,25 +1255,6 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// the [MediaQueryData.highContrast] property of the ancestor [MediaQuery] changes. static bool? maybeHighContrastOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.highContrast)?.highContrast; - /// Returns onOffSwitchLabels for the nearest MediaQuery ancestor or false, if no - /// such ancestor exists. - /// - /// See also: - /// - /// * [MediaQueryData.onOffSwitchLabels], which indicates the platform's - /// desire to show on/off labels inside switches. - /// - /// Use of this method will cause the given [context] to rebuild any time that - /// the [MediaQueryData.onOffSwitchLabels] property of the ancestor [MediaQuery] changes. - static bool onOffSwitchLabelsOf(BuildContext context) => maybeOnOffSwitchLabelsOf(context) ?? false; - - /// Returns onOffSwitchLabels for the nearest MediaQuery ancestor or - /// null, if no such ancestor exists. - /// - /// Use of this method will cause the given [context] to rebuild any time that - /// the [MediaQueryData.onOffSwitchLabels] property of the ancestor [MediaQuery] changes. - static bool? maybeOnOffSwitchLabelsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.onOffSwitchLabels)?.onOffSwitchLabels; - /// Returns disableAnimations for the nearest MediaQuery ancestor or /// [Brightness.light], if no such ancestor exists. /// @@ -1443,10 +1406,6 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { if (data.highContrast != oldWidget.data.highContrast) { return true; } - case _MediaQueryAspect.onOffSwitchLabels: - if (data.onOffSwitchLabels != oldWidget.data.onOffSwitchLabels) { - return true; - } case _MediaQueryAspect.disableAnimations: if (data.disableAnimations != oldWidget.data.disableAnimations) { return true; diff --git a/packages/flutter/test/cupertino/switch_test.dart b/packages/flutter/test/cupertino/switch_test.dart index af9a1336de652..f91fd0af87aa7 100644 --- a/packages/flutter/test/cupertino/switch_test.dart +++ b/packages/flutter/test/cupertino/switch_test.dart @@ -753,187 +753,6 @@ void main() { ); }); - PaintPattern onLabelPaintPattern({ - required int alpha, - bool isRtl = false, - }) => - paints - ..rect( - rect: Rect.fromLTWH(isRtl ? 43.5 : 14.5, 14.5, 1.0, 10.0), - color: const Color(0xffffffff).withAlpha(alpha), - style: PaintingStyle.fill, - ); - - PaintPattern offLabelPaintPattern({ - required int alpha, - bool highContrast = false, - bool isRtl = false, - }) => - paints - ..circle( - x: isRtl ? 16.0 : 43.0, - y: 19.5, - radius: 5.0, - color: - (highContrast ? const Color(0xffffffff) : const Color(0xffb3b3b3)) - .withAlpha(alpha), - strokeWidth: 1.0, - style: PaintingStyle.stroke, - ); - - testWidgets('Switch renders switch labels correctly before, during, and after being tapped', (WidgetTester tester) async { - final Key switchKey = UniqueKey(); - bool value = false; - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(onOffSwitchLabels: true), - child: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Center( - child: RepaintBoundary( - child: CupertinoSwitch( - key: switchKey, - value: value, - dragStartBehavior: DragStartBehavior.down, - onChanged: (bool newValue) { - setState(() { - value = newValue; - }); - }, - ), - ), - ); - }, - ), - ), - ), - ); - - final RenderObject switchRenderObject = - tester.element(find.byType(CupertinoSwitch)).renderObject!; - - expect(switchRenderObject, offLabelPaintPattern(alpha: 255)); - expect(switchRenderObject, onLabelPaintPattern(alpha: 0)); - - await tester.tap(find.byKey(switchKey)); - expect(value, isTrue); - - // Kick off animation, then advance to intermediate frame. - await tester.pump(); - await tester.pump(const Duration(milliseconds: 60)); - expect(switchRenderObject, onLabelPaintPattern(alpha: 131)); - expect(switchRenderObject, offLabelPaintPattern(alpha: 124)); - - await tester.pumpAndSettle(); - expect(switchRenderObject, onLabelPaintPattern(alpha: 255)); - expect(switchRenderObject, offLabelPaintPattern(alpha: 0)); - }); - - testWidgets('Switch renders switch labels correctly before, during, and after being tapped in high contrast', (WidgetTester tester) async { - final Key switchKey = UniqueKey(); - bool value = false; - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData( - onOffSwitchLabels: true, - highContrast: true, - ), - child: Directionality( - textDirection: TextDirection.ltr, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Center( - child: RepaintBoundary( - child: CupertinoSwitch( - key: switchKey, - value: value, - dragStartBehavior: DragStartBehavior.down, - onChanged: (bool newValue) { - setState(() { - value = newValue; - }); - }, - ), - ), - ); - }, - ), - ), - ), - ); - - final RenderObject switchRenderObject = - tester.element(find.byType(CupertinoSwitch)).renderObject!; - - expect(switchRenderObject, offLabelPaintPattern(highContrast: true, alpha: 255)); - expect(switchRenderObject, onLabelPaintPattern(alpha: 0)); - - await tester.tap(find.byKey(switchKey)); - expect(value, isTrue); - - // Kick off animation, then advance to intermediate frame. - await tester.pump(); - await tester.pump(const Duration(milliseconds: 60)); - expect(switchRenderObject, onLabelPaintPattern(alpha: 131)); - expect(switchRenderObject, offLabelPaintPattern(highContrast: true, alpha: 124)); - - await tester.pumpAndSettle(); - expect(switchRenderObject, onLabelPaintPattern(alpha: 255)); - expect(switchRenderObject, offLabelPaintPattern(highContrast: true, alpha: 0)); - }); - - testWidgets('Switch renders switch labels correctly before, during, and after being tapped with direction rtl', (WidgetTester tester) async { - final Key switchKey = UniqueKey(); - bool value = false; - await tester.pumpWidget( - MediaQuery( - data: const MediaQueryData(onOffSwitchLabels: true), - child: Directionality( - textDirection: TextDirection.rtl, - child: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Center( - child: RepaintBoundary( - child: CupertinoSwitch( - key: switchKey, - value: value, - dragStartBehavior: DragStartBehavior.down, - onChanged: (bool newValue) { - setState(() { - value = newValue; - }); - }, - ), - ), - ); - }, - ), - ), - ), - ); - - final RenderObject switchRenderObject = - tester.element(find.byType(CupertinoSwitch)).renderObject!; - - expect(switchRenderObject, offLabelPaintPattern(isRtl: true, alpha: 255)); - expect(switchRenderObject, onLabelPaintPattern(isRtl: true, alpha: 0)); - - await tester.tap(find.byKey(switchKey)); - expect(value, isTrue); - - // Kick off animation, then advance to intermediate frame. - await tester.pump(); - await tester.pump(const Duration(milliseconds: 60)); - expect(switchRenderObject, onLabelPaintPattern(isRtl: true, alpha: 131)); - expect(switchRenderObject, offLabelPaintPattern(isRtl: true, alpha: 124)); - - await tester.pumpAndSettle(); - expect(switchRenderObject, onLabelPaintPattern(isRtl: true, alpha: 255)); - expect(switchRenderObject, offLabelPaintPattern(isRtl: true, alpha: 0)); - }); - testWidgets('Switch renders correctly in dark mode', (WidgetTester tester) async { final Key switchKey = UniqueKey(); bool value = false; diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 135f284ac9690..9516e35e2fdc3 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -154,7 +154,6 @@ void main() { expect(data.disableAnimations, false); expect(data.boldText, false); expect(data.highContrast, false); - expect(data.onOffSwitchLabels, false); expect(data.platformBrightness, Brightness.light); expect(data.gestureSettings.touchSlop, null); expect(data.displayFeatures, isEmpty); @@ -169,7 +168,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, alwaysUse24HourFormat: true, navigationMode: NavigationMode.directional, ); @@ -190,7 +188,6 @@ void main() { expect(data.disableAnimations, platformData.disableAnimations); expect(data.boldText, platformData.boldText); expect(data.highContrast, platformData.highContrast); - expect(data.onOffSwitchLabels, platformData.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -220,7 +217,6 @@ void main() { expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); - expect(data.onOffSwitchLabels, tester.platformDispatcher.accessibilityFeatures.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -236,7 +232,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, alwaysUse24HourFormat: true, navigationMode: NavigationMode.directional, ); @@ -269,7 +264,6 @@ void main() { expect(data.disableAnimations, platformData.disableAnimations); expect(data.boldText, platformData.boldText); expect(data.highContrast, platformData.highContrast); - expect(data.onOffSwitchLabels, platformData.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -317,7 +311,6 @@ void main() { expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); - expect(data.onOffSwitchLabels, tester.platformDispatcher.accessibilityFeatures.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -496,7 +489,6 @@ void main() { expect(copied.disableAnimations, data.disableAnimations); expect(copied.boldText, data.boldText); expect(copied.highContrast, data.highContrast); - expect(copied.onOffSwitchLabels, data.onOffSwitchLabels); expect(copied.platformBrightness, data.platformBrightness); expect(copied.gestureSettings, data.gestureSettings); expect(copied.displayFeatures, data.displayFeatures); @@ -536,7 +528,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, platformBrightness: Brightness.dark, navigationMode: NavigationMode.directional, gestureSettings: gestureSettings, @@ -555,7 +546,6 @@ void main() { expect(copied.disableAnimations, true); expect(copied.boldText, true); expect(copied.highContrast, true); - expect(copied.onOffSwitchLabels, true); expect(copied.platformBrightness, Brightness.dark); expect(copied.navigationMode, NavigationMode.directional); expect(copied.gestureSettings, gestureSettings); @@ -593,7 +583,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -629,7 +618,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -665,7 +653,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -698,7 +685,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -734,7 +720,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -770,7 +755,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -806,7 +790,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -839,7 +822,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -875,7 +857,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -911,7 +892,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -947,7 +927,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -980,7 +959,6 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); - expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -1066,33 +1044,6 @@ void main() { expect(insideHighContrast, true); }); - testWidgets('MediaQuery.onOffSwitchLabelsOf', (WidgetTester tester) async { - late bool outsideOnOffSwitchLabels; - late bool insideOnOffSwitchLabels; - - await tester.pumpWidget( - Builder( - builder: (BuildContext context) { - outsideOnOffSwitchLabels = MediaQuery.onOffSwitchLabelsOf(context); - return MediaQuery( - data: const MediaQueryData( - onOffSwitchLabels: true, - ), - child: Builder( - builder: (BuildContext context) { - insideOnOffSwitchLabels = MediaQuery.onOffSwitchLabelsOf(context); - return Container(); - }, - ), - ); - }, - ), - ); - - expect(outsideOnOffSwitchLabels, false); - expect(insideOnOffSwitchLabels, true); - }); - testWidgets('MediaQuery.boldTextOf', (WidgetTester tester) async { late bool outsideBoldTextOverride; late bool insideBoldTextOverride; @@ -1220,7 +1171,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, displayFeatures: displayFeatures, ), child: Builder( @@ -1251,7 +1201,6 @@ void main() { expect(subScreenMediaQuery.disableAnimations, true); expect(subScreenMediaQuery.boldText, true); expect(subScreenMediaQuery.highContrast, true); - expect(subScreenMediaQuery.onOffSwitchLabels, true); expect(subScreenMediaQuery.displayFeatures, isEmpty); }); @@ -1295,7 +1244,6 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, - onOffSwitchLabels: true, displayFeatures: displayFeatures, ), child: Builder( @@ -1335,7 +1283,6 @@ void main() { expect(subScreenMediaQuery.disableAnimations, true); expect(subScreenMediaQuery.boldText, true); expect(subScreenMediaQuery.highContrast, true); - expect(subScreenMediaQuery.onOffSwitchLabels, true); expect(subScreenMediaQuery.displayFeatures, [cutoutDisplayFeature]); }); @@ -1506,8 +1453,6 @@ void main() { const _MediaQueryAspectCase(MediaQuery.maybeInvertColorsOf, MediaQueryData(invertColors: true)), const _MediaQueryAspectCase(MediaQuery.highContrastOf, MediaQueryData(highContrast: true)), const _MediaQueryAspectCase(MediaQuery.maybeHighContrastOf, MediaQueryData(highContrast: true)), - const _MediaQueryAspectCase(MediaQuery.onOffSwitchLabelsOf, MediaQueryData(onOffSwitchLabels: true)), - const _MediaQueryAspectCase(MediaQuery.maybeOnOffSwitchLabelsOf, MediaQueryData(onOffSwitchLabels: true)), const _MediaQueryAspectCase(MediaQuery.disableAnimationsOf, MediaQueryData(disableAnimations: true)), const _MediaQueryAspectCase(MediaQuery.maybeDisableAnimationsOf, MediaQueryData(disableAnimations: true)), const _MediaQueryAspectCase(MediaQuery.boldTextOf, MediaQueryData(boldText: true)), From 3b8f6c4020a70a03267ab0ab9e25e83b26341082 Mon Sep 17 00:00:00 2001 From: Alexander Aprelev Date: Fri, 7 Jul 2023 13:55:35 -0700 Subject: [PATCH 0020/1547] Upgrade framework pub dependencies, roll engine with rolled dart sdk (#130163) Manual roll is needed because incoming dart sdk requires updated version vm_snapshot_analysis (>=0.7.4). https://github.com/flutter/engine/compare/5ae09b8b4fa381e8723ed5382a26eafd0d97236f...7c83ea3e854202aea22405a947ac1b8f18c5a72c ``` 7c83ea3e85 Reland "Manual roll Dart SDK from 2d98d9e27dae to 0b07debd5862 (21 revisions) (#43457)" (#43472) 9ef3e8d533 Roll Skia from 5eba922297bb to 93c92f97f5ab (2 revisions) (#43471) ``` Remove implementation of SuitePlatform from the test as well. Remove use of fake cwd from SuitePlatform as it can't be properly faked. --- bin/internal/engine.version | 2 +- dev/automated_tests/pubspec.yaml | 19 ++++---- dev/benchmarks/complex_layout/pubspec.yaml | 19 ++++---- dev/benchmarks/macrobenchmarks/pubspec.yaml | 19 ++++---- dev/benchmarks/microbenchmarks/pubspec.yaml | 19 ++++---- .../multiple_flutters/module/pubspec.yaml | 4 +- .../platform_channels_benchmarks/pubspec.yaml | 19 ++++---- .../platform_views_layout/pubspec.yaml | 19 ++++---- .../pubspec.yaml | 19 ++++---- dev/benchmarks/test_apps/stocks/pubspec.yaml | 19 ++++---- dev/bots/pubspec.yaml | 21 ++++----- dev/conductor/core/pubspec.yaml | 19 ++++---- dev/customer_testing/pubspec.yaml | 19 ++++---- dev/devicelab/pubspec.yaml | 21 ++++----- dev/forbidden_from_release_tests/pubspec.yaml | 4 +- .../pubspec.yaml | 8 ++-- .../android_semantics_testing/pubspec.yaml | 19 ++++---- .../android_views/pubspec.yaml | 21 ++++----- dev/integration_tests/channels/pubspec.yaml | 10 ++--- .../deferred_components_test/pubspec.yaml | 19 ++++---- .../external_ui/pubspec.yaml | 19 ++++---- dev/integration_tests/flavors/pubspec.yaml | 19 ++++---- .../flutter_gallery/pubspec.yaml | 23 +++++----- .../gradle_deprecated_settings/pubspec.yaml | 10 ++--- .../hybrid_android_views/pubspec.yaml | 21 ++++----- .../flutterapp/pubspec.yaml | 8 ++-- .../ios_app_with_extensions/pubspec.yaml | 8 ++-- .../ios_platform_view_tests/pubspec.yaml | 19 ++++---- .../non_nullable/pubspec.yaml | 8 ++-- .../platform_interaction/pubspec.yaml | 19 ++++---- .../release_smoke_test/pubspec.yaml | 10 ++--- .../spell_check/pubspec.yaml | 10 ++--- dev/integration_tests/ui/pubspec.yaml | 19 ++++---- .../web_e2e_tests/pubspec.yaml | 19 ++++---- .../wide_gamut_test/pubspec.yaml | 10 ++--- .../windows_startup_test/pubspec.yaml | 19 ++++---- dev/manual_tests/pubspec.yaml | 8 ++-- dev/tools/gen_defaults/pubspec.yaml | 19 ++++---- dev/tools/gen_keycodes/pubspec.yaml | 19 ++++---- dev/tools/pubspec.yaml | 19 ++++---- dev/tools/vitool/pubspec.yaml | 8 ++-- dev/tracing_tests/pubspec.yaml | 10 ++--- examples/api/pubspec.yaml | 19 ++++---- examples/hello_world/pubspec.yaml | 19 ++++---- examples/image_list/pubspec.yaml | 8 ++-- examples/layers/pubspec.yaml | 8 ++-- examples/platform_channel/pubspec.yaml | 19 ++++---- examples/platform_channel_swift/pubspec.yaml | 19 ++++---- examples/splash/pubspec.yaml | 8 ++-- examples/texture/pubspec.yaml | 19 ++++---- packages/flutter/pubspec.yaml | 19 ++++---- .../flutter/test_private/test/pubspec.yaml | 8 ++-- packages/flutter_driver/pubspec.yaml | 19 ++++---- packages/flutter_goldens/pubspec.yaml | 8 ++-- packages/flutter_localizations/pubspec.yaml | 8 ++-- packages/flutter_test/pubspec.yaml | 8 ++-- packages/flutter_tools/pubspec.yaml | 33 +++++++------- .../dap/flutter_adapter_test.dart | 44 +++++++++---------- .../dap/flutter_test_adapter_test.dart | 8 ++-- .../general.shard/flutter_platform_test.dart | 16 ++++--- packages/flutter_web_plugins/pubspec.yaml | 8 ++-- .../pubspec.yaml | 19 ++++---- .../integration_test/example/pubspec.yaml | 19 ++++---- packages/integration_test/pubspec.yaml | 10 ++--- 64 files changed, 514 insertions(+), 475 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 005097ae5c9ac..e65633fea2d35 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5ae09b8b4fa381e8723ed5382a26eafd0d97236f +7c83ea3e854202aea22405a947ac1b8f18c5a72c diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index e930a775edacd..78466d3d6304c 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -13,10 +13,10 @@ dependencies: integration_test: sdk: flutter platform: 3.1.0 - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,6 +26,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,15 +53,15 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +73,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 8050 +# PUBSPEC CHECKSUM: 62e1 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index fe6ed3df54dc5..4331605f94924 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -26,31 +26,32 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 integration_test: sdk: flutter - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -70,7 +71,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,4 +84,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 1c29 +# PUBSPEC CHECKSUM: e1ba diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 7617d7829eb31..b4c6c650f2fc4 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -32,27 +32,28 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 + test: 1.24.4 integration_test: sdk: flutter - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,7 +72,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -210,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 1c29 +# PUBSPEC CHECKSUM: e1ba diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index c54fbc3f85e6f..aaf8d8f1f1fb5 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -12,11 +12,11 @@ dependencies: sdk: flutter stocks: path: ../test_apps/stocks - test: 1.24.3 + test: 1.24.4 flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,6 +26,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,15 +54,15 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -137,4 +138,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 06a0 +# PUBSPEC CHECKSUM: 5532 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index fe87a6f038a95..2e02625c749d2 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -50,4 +50,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 4eb9 +# PUBSPEC CHECKSUM: 7bba diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index ebb1feccb255e..9a1e0a2fe7f1e 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../microbenchmarks cupertino_icons: 1.0.5 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,6 +27,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_gallery_assets: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,16 +54,16 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 918b +# PUBSPEC CHECKSUM: 051d diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 396fbd7838694..6fc9f64dd3bef 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -26,29 +26,30 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,7 +69,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 1c29 +# PUBSPEC CHECKSUM: e1ba diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index df764b6158940..f0cf52b706b8c 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -26,29 +26,30 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,7 +69,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 1c29 +# PUBSPEC CHECKSUM: e1ba diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 5d08473095290..c54dd5fc92ad5 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -32,15 +32,16 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,12 +62,12 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +77,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d14b +# PUBSPEC CHECKSUM: 67dc diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index d1787a231ad73..2b4fbe7747fb1 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -15,11 +15,11 @@ dependencies: path: 1.8.3 platform: 3.1.0 process: 4.2.4 - test: 1.24.3 + test: 1.24.4 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,6 +28,7 @@ dependencies: collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" equatable: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,7 +43,7 @@ dependencies: json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - metrics_center: 1.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + metrics_center: 1.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,13 +57,13 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -70,6 +71,6 @@ dependencies: yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test_api: 0.6.0 + test_api: 0.6.1 -# PUBSPEC CHECKSUM: f223 +# PUBSPEC CHECKSUM: c2dc diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index e650875668300..831df5d3c23b2 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -30,14 +30,15 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 - test_api: 0.6.0 + test: 1.24.4 + test_api: 0.6.1 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,13 +57,13 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 282c +# PUBSPEC CHECKSUM: eebd diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 9f5cb6daa43af..2c451222cf110 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -18,14 +18,15 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -44,15 +45,15 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: df79 +# PUBSPEC CHECKSUM: 940b diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index a74f303ceb275..5eb968e04e64a 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -12,15 +12,15 @@ dependencies: http: 0.13.6 logging: 1.2.0 meta: 1.9.1 - metrics_center: 1.0.9 + metrics_center: 1.0.10 path: 1.8.3 platform: 3.1.0 process: 4.2.4 pubspec_parse: 1.2.3 shelf: 1.4.1 shelf_static: 1.1.2 - stack_trace: 1.11.0 - vm_service: 11.7.1 + stack_trace: 1.11.1 + vm_service: 11.7.2 web: 0.1.4-beta webkit_inspection_protocol: 1.2.0 @@ -40,19 +40,20 @@ dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,9 +66,9 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a090 +# PUBSPEC CHECKSUM: 1d4a diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index 48beef50b20e7..38a767f90b6d1 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -10,10 +10,10 @@ dependencies: package_config: 2.1.0 path: 1.8.3 process: 4.2.4 - vm_snapshot_analysis: 0.7.2 + vm_snapshot_analysis: 0.7.6 collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5a67 +# PUBSPEC CHECKSUM: 5e6b diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index 5b52b760c400d..01c60250358f0 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -52,11 +52,11 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -96,4 +96,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: d514 +# PUBSPEC CHECKSUM: 9e17 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index f50c94031bd94..eb7899b5447fe 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: flutter_test: sdk: flutter pub_semver: 2.1.4 - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,6 +24,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,15 +49,15 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3549 +# PUBSPEC CHECKSUM: 79da diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 3d17c7d390563..db69bfbdfbc40 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -39,31 +39,32 @@ dependencies: plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,7 +84,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +94,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6876 +# PUBSPEC CHECKSUM: ae09 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index dbaf46734172a..0a8e882e3c6a4 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -31,16 +31,16 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3234 +# PUBSPEC CHECKSUM: 4738 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index fa45b4baee41e..0aa2933ab3b4e 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -21,29 +21,30 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,7 +64,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -80,4 +81,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index 63f9692033a55..d0e1921531a32 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,6 +21,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,16 +46,16 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3dd1 +# PUBSPEC CHECKSUM: c363 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 7e6e37466ed81..4a1bf4d3bb8f9 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,6 +23,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,16 +48,16 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 7be18d52b30eb..2ec7a701cc6a3 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -44,8 +44,8 @@ dependencies: url_launcher_linux: 3.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_macos: 3.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_platform_interface: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_web: 2.0.17 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_windows: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_web: 2.0.18 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_windows: 3.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_platform_interface: 5.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_web: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,18 +58,19 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter - test: 1.24.3 + test: 1.24.4 integration_test: sdk: flutter - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,13 +94,13 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -276,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: bd6f +# PUBSPEC CHECKSUM: 4c03 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 70db19b854d14..0cff6ce665b12 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.1+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,16 +27,16 @@ dependencies: plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" quiver: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_transform: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: f3fe +# PUBSPEC CHECKSUM: bf03 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 460a189ce623d..e80ef4b34860c 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -37,31 +37,32 @@ dependencies: plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,7 +82,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6876 +# PUBSPEC CHECKSUM: ae09 diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index ab6b4f34a0f8f..d7c0aa5f4aa14 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -45,11 +45,11 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: # The following line ensures that the Material Icons font is @@ -99,4 +99,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: f5e9 +# PUBSPEC CHECKSUM: beec diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index 2631ecbf165af..08cab7f06ea3d 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -47,11 +47,11 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -91,4 +91,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: e86f +# PUBSPEC CHECKSUM: b172 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 3d03abe456cd1..0ce093a668287 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -21,29 +21,30 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,7 +64,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +78,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index b1d61f8cec408..16142b2ae9673 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -30,13 +30,13 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: f5e9 +# PUBSPEC CHECKSUM: beec diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 44875f9bbdad5..49b4710fce6ba 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,6 +21,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,16 +46,16 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3dd1 +# PUBSPEC CHECKSUM: c363 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 7426fb46cd40e..2bc9222f084fe 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -27,11 +27,11 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b2fa +# PUBSPEC CHECKSUM: 07fe diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index 91be571793695..cf9b04a3e2f54 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -61,12 +61,12 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 85a2 +# PUBSPEC CHECKSUM: d9a6 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 4613a4e7090c8..8410214f74443 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,6 +23,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,15 +48,15 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,7 +67,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test_api: 0.6.0 + test_api: 0.6.1 clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +77,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 37e371439dec2..e736b7f7844fc 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -34,14 +34,14 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,14 +49,15 @@ dev_dependencies: flutter_goldens: sdk: flutter http: 0.13.6 - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,11 +78,11 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ab73 +# PUBSPEC CHECKSUM: 2405 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index e7eeb65b71a05..aa93540b22089 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -31,14 +31,14 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b2fa +# PUBSPEC CHECKSUM: 07fe diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index e786d59a3176c..2c10a2862126d 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,6 +21,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,16 +46,16 @@ dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,4 +63,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3dd1 +# PUBSPEC CHECKSUM: c363 diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index ce15e76cabb4e..c69dd938a9468 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -25,13 +25,13 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b642 +# PUBSPEC CHECKSUM: 7f45 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index c4665a8c1d9ed..3222e85e1d4b6 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -10,16 +10,17 @@ dependencies: dev_dependencies: path: 1.8.3 - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,17 +43,17 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: df79 +# PUBSPEC CHECKSUM: 940b diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index df0953cc1d728..53abe32375184 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -20,15 +20,16 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 - test_api: 0.6.0 + test: 1.24.4 + test_api: 0.6.1 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,13 +49,13 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5270 +# PUBSPEC CHECKSUM: 7602 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 13c5c0edbb227..30039144ebdde 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -26,14 +26,15 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 - test_api: 0.6.0 + test: 1.24.4 + test_api: 0.6.1 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,13 +53,13 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: cc8a +# PUBSPEC CHECKSUM: 0d1c diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 59a59762161e3..26c882044daa7 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -31,10 +31,10 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f2ea +# PUBSPEC CHECKSUM: f7ed diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 203fb17208fe5..3ac5761dbaaab 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: flutter: sdk: flutter - vm_service: 11.7.1 + vm_service: 11.7.2 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,10 +28,10 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b2fa +# PUBSPEC CHECKSUM: 07fe diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index eed8da11cee1a..73110a6c09e8e 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -31,10 +31,10 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,6 +42,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,15 +68,15 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +86,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0b3d +# PUBSPEC CHECKSUM: 62ce diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 637943e4bf191..b5ad48b7986c7 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -19,10 +19,10 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,6 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,19 +54,19 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index ab1be6fd8ec80..b082083a7a6da 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -37,11 +37,11 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -54,4 +54,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: f5e9 +# PUBSPEC CHECKSUM: beec diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index 1e09ede979b4b..4a83ace90ddba 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -25,15 +25,15 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: assets: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: b642 +# PUBSPEC CHECKSUM: 7f45 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 415db71426f59..a6026f54880f9 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -19,10 +19,10 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,6 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,15 +54,15 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 728d5ecaa7286..7b2164bfc3bca 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -19,10 +19,10 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,6 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,15 +54,15 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 968e +# PUBSPEC CHECKSUM: be20 diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 478640f70f7b5..864fe341bf3e1 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -25,10 +25,10 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b642 +# PUBSPEC CHECKSUM: 7f45 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 20cbb697abf18..891bf363a1957 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -17,10 +17,10 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,6 +28,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,17 +52,17 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3549 +# PUBSPEC CHECKSUM: 79da diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index eb0f026887878..68b47a6cf26dc 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -25,8 +25,8 @@ dev_dependencies: leak_tracker: 7.0.4 leak_tracker_testing: 1.0.0 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,6 +34,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,18 +60,18 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 155f +# PUBSPEC CHECKSUM: 32f0 diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index c2e5ee2e909fa..dbdcd862d75ec 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -23,11 +23,11 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -39,4 +39,4 @@ dev_dependencies: platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6c3d +# PUBSPEC CHECKSUM: 3540 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index d817a82060eb7..15e98d5d0a69a 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: sdk: flutter path: 1.8.3 meta: 1.9.1 - vm_service: 11.7.1 + vm_service: 11.7.2 webdriver: 3.0.2 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,25 +28,26 @@ dependencies: platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: fake_async: 1.3.1 - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,11 +66,11 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a395 +# PUBSPEC CHECKSUM: 6927 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index 07e7fd2d56a37..ad47b7a980b2b 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -27,13 +27,13 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6a9e +# PUBSPEC CHECKSUM: 99a1 diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index df2d0b4195bb2..f5ebaae2f8859 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -28,10 +28,10 @@ dev_dependencies: fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 837c +# PUBSPEC CHECKSUM: 4c7f diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index fe95841298336..fc8a02ede2d34 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. - test_api: 0.6.0 + test_api: 0.6.1 matcher: 0.12.16 # Used by golden file comparator @@ -25,7 +25,7 @@ dependencies: # We import stack_trace because the test packages uses it and we # need to be able to unmangle the stack traces that it passed to # stack_trace. See https://github.com/dart-lang/test/issues/590 - stack_trace: 1.11.0 + stack_trace: 1.11.1 # Used by globalToLocal et al. vector_math: 2.1.4 @@ -37,7 +37,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ dependencies: dev_dependencies: file: 6.1.4 -# PUBSPEC CHECKSUM: 7736 +# PUBSPEC CHECKSUM: 4039 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 0ed5c487cb648..39b142c5f17e2 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -10,8 +10,8 @@ dependencies: archive: 3.3.2 args: 2.4.2 browser_launcher: 1.1.1 - dds: 2.9.0 - dwds: 19.0.1 + dds: 2.9.2 + dwds: 19.0.2 completion: 1.0.1 coverage: 1.6.3 crypto: 3.0.3 @@ -26,7 +26,7 @@ dependencies: package_config: 2.1.0 process: 4.2.4 fake_async: 1.3.1 - stack_trace: 1.11.0 + stack_trace: 1.11.1 usage: 4.1.1 webdriver: 3.0.2 webkit_inspection_protocol: 1.2.0 @@ -34,10 +34,10 @@ dependencies: yaml: 3.1.2 native_stack_traces: 0.5.6 shelf: 1.4.1 - vm_snapshot_analysis: 0.7.2 + vm_snapshot_analysis: 0.7.6 uuid: 3.0.7 web_socket_channel: 2.4.0 - stream_channel: 2.1.1 + stream_channel: 2.1.2 shelf_web_socket: 1.0.4 shelf_static: 1.1.2 pub_semver: 2.1.4 @@ -48,28 +48,29 @@ dependencies: http_multi_server: 3.2.1 convert: 3.1.1 async: 2.11.0 - unified_analytics: 2.0.0 + unified_analytics: 3.0.0 # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. - test_api: 0.6.0 - test_core: 0.5.3 + test_api: 0.6.1 + test_core: 0.5.4 - vm_service: 11.7.1 + vm_service: 11.7.2 standard_message_codec: 0.0.1+3 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_value: 8.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dap: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dds_service_extensions: 1.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - devtools_shared: 2.24.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dds_service_extensions: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + devtools_shared: 2.25.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -100,10 +101,10 @@ dev_dependencies: checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: d197 +# PUBSPEC CHECKSUM: 5e34 diff --git a/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart b/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart index d5b958ae23958..4dd3e0bb22818 100644 --- a/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/general.shard/dap/flutter_adapter_test.dart @@ -44,7 +44,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -63,7 +63,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', env: { 'MY_TEST_ENV': 'MY_TEST_VALUE', @@ -85,7 +85,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -112,7 +112,7 @@ void main() { ); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -146,7 +146,7 @@ void main() { ); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -170,7 +170,7 @@ void main() { ); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -195,7 +195,7 @@ void main() { final Completer launchCompleter = Completer(); final FlutterLaunchRequestArguments launchArgs = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); final Completer restartCompleter = Completer(); @@ -221,7 +221,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -261,7 +261,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', ); await adapter.configurationDoneRequest(MockRequest(), null, () {}); @@ -280,7 +280,7 @@ void main() { final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', program: 'program/main.dart', ); @@ -308,7 +308,7 @@ void main() { final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', program: 'program/main.dart', vmServiceUri: 'ws://1.2.3.4/ws' ); @@ -340,7 +340,7 @@ void main() { final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', program: 'program/main.dart', vmServiceInfoFile: serviceInfoFile.path, ); @@ -374,7 +374,7 @@ void main() { final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', program: 'program/main.dart', vmServiceInfoFile: serviceInfoFile.path, ); @@ -408,7 +408,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', ); await adapter.configurationDoneRequest(MockRequest(), null, () {}); @@ -430,7 +430,7 @@ void main() { ); final FlutterAttachRequestArguments args = FlutterAttachRequestArguments( - cwd: '/project', + cwd: '.', ); await adapter.configurationDoneRequest(MockRequest(), null, () {}); @@ -518,7 +518,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', ); @@ -537,7 +537,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', noDebug: true, ); @@ -557,7 +557,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', toolArgs: ['--profile'], ); @@ -577,7 +577,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', toolArgs: ['--release'], ); @@ -598,7 +598,7 @@ void main() { final Completer responseCompleter = Completer(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', toolArgs: ['tool_arg'], noDebug: true, @@ -659,7 +659,7 @@ void main() { platform: platform, ); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', customTool: '/custom/flutter', noDebug: true, @@ -681,7 +681,7 @@ void main() { platform: platform, ); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', customTool: '/custom/flutter', customToolReplacesArgs: 9999, // replaces all built-in args diff --git a/packages/flutter_tools/test/general.shard/dap/flutter_test_adapter_test.dart b/packages/flutter_tools/test/general.shard/dap/flutter_test_adapter_test.dart index a2717ea7382ee..26710f2d98144 100644 --- a/packages/flutter_tools/test/general.shard/dap/flutter_test_adapter_test.dart +++ b/packages/flutter_tools/test/general.shard/dap/flutter_test_adapter_test.dart @@ -37,7 +37,7 @@ void main() { final Completer responseCompleter = Completer(); final MockRequest request = MockRequest(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', toolArgs: ['tool_arg'], noDebug: true, @@ -59,7 +59,7 @@ void main() { final Completer responseCompleter = Completer(); final MockRequest request = MockRequest(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', env: { 'MY_TEST_ENV': 'MY_TEST_VALUE', @@ -82,7 +82,7 @@ void main() { final Completer responseCompleter = Completer(); final MockRequest request = MockRequest(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', customTool: '/custom/flutter', noDebug: true, @@ -105,7 +105,7 @@ void main() { final Completer responseCompleter = Completer(); final MockRequest request = MockRequest(); final FlutterLaunchRequestArguments args = FlutterLaunchRequestArguments( - cwd: '/project', + cwd: '.', program: 'foo.dart', customTool: '/custom/flutter', customToolReplacesArgs: 9999, // replaces all built-in args diff --git a/packages/flutter_tools/test/general.shard/flutter_platform_test.dart b/packages/flutter_tools/test/general.shard/flutter_platform_test.dart index 89510dcd47692..6f4b5f65e6be4 100644 --- a/packages/flutter_tools/test/general.shard/flutter_platform_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_platform_test.dart @@ -8,7 +8,6 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/test/flutter_platform.dart'; -import 'package:test/fake.dart'; import 'package:test_core/backend.dart'; // ignore: deprecated_member_use import '../src/common.dart'; @@ -25,6 +24,11 @@ void main() { }); group('FlutterPlatform', () { + late SuitePlatform fakeSuitePlatform; + setUp(() { + fakeSuitePlatform = SuitePlatform(Runtime.vm); + }); + testUsingContext('ensureConfiguration throws an error if an ' 'explicitVmServicePort is specified and more than one test file', () async { final FlutterPlatform flutterPlatform = FlutterPlatform( @@ -35,9 +39,9 @@ void main() { ), enableVmService: false, ); - flutterPlatform.loadChannel('test1.dart', FakeSuitePlatform()); + flutterPlatform.loadChannel('test1.dart', fakeSuitePlatform); - expect(() => flutterPlatform.loadChannel('test2.dart', FakeSuitePlatform()), throwsToolExit()); + expect(() => flutterPlatform.loadChannel('test2.dart', fakeSuitePlatform), throwsToolExit()); }, overrides: { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), @@ -51,9 +55,9 @@ void main() { precompiledDillPath: 'example.dill', enableVmService: false, ); - flutterPlatform.loadChannel('test1.dart', FakeSuitePlatform()); + flutterPlatform.loadChannel('test1.dart', fakeSuitePlatform); - expect(() => flutterPlatform.loadChannel('test2.dart', FakeSuitePlatform()), throwsToolExit()); + expect(() => flutterPlatform.loadChannel('test2.dart', fakeSuitePlatform), throwsToolExit()); }, overrides: { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), @@ -119,5 +123,3 @@ void main() { }); }); } - -class FakeSuitePlatform extends Fake implements SuitePlatform { } diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index 15883816ca0f3..d5efee980c04d 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -27,10 +27,10 @@ dev_dependencies: matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b642 +# PUBSPEC CHECKSUM: 7f45 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 35ca0afb66185..b02d25646833f 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -8,7 +8,7 @@ environment: dependencies: process: 4.2.4 - vm_service: 11.7.1 + vm_service: 11.7.2 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -16,10 +16,10 @@ dependencies: platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.3 + test: 1.24.4 - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,6 +27,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,12 +48,12 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +64,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: f780 +# PUBSPEC CHECKSUM: 4a12 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 8512ef6481637..754a3cd42c69d 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -28,14 +28,14 @@ dev_dependencies: sdk: flutter integration_test_macos: path: ../integration_test_macos - test: 1.24.3 + test: 1.24.4 pedantic: 1.11.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 61.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 5.13.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,6 +43,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,15 +67,15 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e4fc +# PUBSPEC CHECKSUM: 108e diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index b50eb44ce5b62..9206b04d52b4c 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: flutter_test: sdk: flutter path: 1.8.3 - vm_service: 11.7.1 + vm_service: 11.7.2 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,12 +26,12 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stack_trace: 1.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - stream_channel: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_api: 0.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 3234 +# PUBSPEC CHECKSUM: 4738 From b80bbd55000a45b5c68c02ef07e68f6bebc72723 Mon Sep 17 00:00:00 2001 From: hangyu Date: Fri, 7 Jul 2023 15:19:09 -0700 Subject: [PATCH 0021/1547] Add a threshold when comparing screen order for selectables. (#130043) Add a threshold when comparing screen order for selectables. So when the vertical position diff is within the threshold, will compare the horizontal position. This fixes https://github.com/flutter/flutter/issues/111021 and https://github.com/flutter/flutter/issues/127942 --- .../lib/src/widgets/selectable_region.dart | 11 +++-- .../test/widgets/selectable_region_test.dart | 45 +++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 1786b00ff7af6..568cb645073eb 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -39,6 +39,11 @@ const Set _kLongPressSelectionDevices = { PointerDeviceKind.invertedStylus, }; +// In practice some selectables like widgetspan shift several pixels. So when +// the vertical position diff is within the threshold, compare the horizontal +// position to make the compareScreenOrder function more robust. +const double _kSelectableVerticalComparingThreshold = 3.0; + /// A widget that introduces an area for user selections. /// /// Flutter widgets are not selectable by default. Wrapping a widget subtree @@ -1703,11 +1708,11 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai /// Returns positive if a is lower, negative if a is higher, 0 if their /// order can't be determine solely by their vertical position. static int _compareVertically(Rect a, Rect b) { - if ((a.top - b.top < precisionErrorTolerance && a.bottom - b.bottom > - precisionErrorTolerance) || - (b.top - a.top < precisionErrorTolerance && b.bottom - a.bottom > - precisionErrorTolerance)) { + if ((a.top - b.top < _kSelectableVerticalComparingThreshold && a.bottom - b.bottom > - _kSelectableVerticalComparingThreshold) || + (b.top - a.top < _kSelectableVerticalComparingThreshold && b.bottom - a.bottom > - _kSelectableVerticalComparingThreshold)) { return 0; } - if ((a.top - b.top).abs() > precisionErrorTolerance) { + if ((a.top - b.top).abs() > _kSelectableVerticalComparingThreshold) { return a.top > b.top ? 1 : -1; } return a.bottom > b.bottom ? 1 : -1; diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index e2903ab77837e..7d9fbd174c9fc 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -2469,6 +2469,51 @@ void main() { skip: !kIsWeb, // [intended] ); }); + + testWidgets('Multiple selectables on a single line should be in screen order', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/127942. + final UniqueKey outerText = UniqueKey(); + const TextStyle textStyle = TextStyle(fontSize: 10); + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: Scaffold( + body: Center( + child: Text.rich( + const TextSpan( + children: [ + TextSpan(text: 'Hello my name is ', style: textStyle), + WidgetSpan( + child: Text('Dash', style: textStyle), + alignment: PlaceholderAlignment.middle, + ), + TextSpan(text: '.', style: textStyle), + ], + ), + key: outerText, + ), + ), + ), + ), + ), + ); + final RenderParagraph paragraph1 = tester.renderObject(find.descendant(of: find.byKey(outerText), matching: find.byType(RichText)).first); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 0), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + + // Select all. + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.keyA, control: true)); + + // keyboard copy. + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.keyC, control: true)); + + final Map clipboardData = mockClipboard.clipboardData as Map; + expect(clipboardData['text'], 'Hello my name is Dash.'); + }); } class SelectionSpy extends LeafRenderObjectWidget { From 2b6492426e5c9a17f3597f40323ce902d4540396 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 18:41:26 -0400 Subject: [PATCH 0022/1547] Roll Flutter Engine from 7c83ea3e8542 to b39e6fe4b3bf (1 revision) (#130176) https://github.com/flutter/engine/compare/7c83ea3e8542...b39e6fe4b3bf 2023-07-07 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Cfxhimvf7nMO99ky_... to vee6hAD_43mq_4FS7... (flutter/engine#43475) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from Cfxhimvf7nMO to vee6hAD_43mq If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e65633fea2d35..f3cf23b6de2de 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7c83ea3e854202aea22405a947ac1b8f18c5a72c +b39e6fe4b3bf98fdf20862c68177c2ed8a2785ec diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 02c4cc23a4acc..d93b0e2230160 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -Cfxhimvf7nMO99ky_58fDRvaiZ6Q6175h0Uet70Um30C +vee6hAD_43mq_4FS7wnS04qeXSr3bMCDCkVid8PHIl8C From 6502f46b8a30ce7654693d494435a2783c7ba236 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 19:33:20 -0400 Subject: [PATCH 0023/1547] Roll Flutter Engine from b39e6fe4b3bf to 893ab3bf7bb9 (1 revision) (#130180) https://github.com/flutter/engine/compare/b39e6fe4b3bf...893ab3bf7bb9 2023-07-07 skia-flutter-autoroll@skia.org Roll Dart SDK from 0b07debd5862 to 4998bf65f91c (2 revisions) (flutter/engine#43480) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f3cf23b6de2de..2ac646964b2a7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b39e6fe4b3bf98fdf20862c68177c2ed8a2785ec +893ab3bf7bb9cf104846ec50b79baf4864089253 From 99841eb7fecec0770afc975ff1b75ef819bc33d0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 20:26:32 -0400 Subject: [PATCH 0024/1547] Roll Flutter Engine from 893ab3bf7bb9 to 40a8732a5de0 (1 revision) (#130186) https://github.com/flutter/engine/compare/893ab3bf7bb9...40a8732a5de0 2023-07-07 skia-flutter-autoroll@skia.org Roll Skia from 93c92f97f5ab to 2885452c3fb1 (2 revisions) (flutter/engine#43478) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2ac646964b2a7..59283d825bfff 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -893ab3bf7bb9cf104846ec50b79baf4864089253 +40a8732a5de0e63f2903bf0e565383f9671ce93c From e3b5ae56cd52eb4ede4756f5215849c5d79d79d7 Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:30:17 -0700 Subject: [PATCH 0025/1547] Remove unneeded configuration file (#130183) Remove autosubmit config files that are no longer being used. This was from a previous design and not longer used. *List which issues are fixed by this PR. You must list at least one issue.* Part of https://github.com/flutter/flutter/issues/130182 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .github/autosubmit.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .github/autosubmit.yml diff --git a/.github/autosubmit.yml b/.github/autosubmit.yml deleted file mode 100644 index 74f629659d43c..0000000000000 --- a/.github/autosubmit.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright 2023 The Flutter Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# This file will be added to flutter's internal repository. -# https://github.com/flutter/flutter/wiki/Autosubmit-bot -config_path: 'autosubmit/flutter/autosubmit_master.yml' From 0cb6a03d9257df981f8cb3a07e744ae521b09e95 Mon Sep 17 00:00:00 2001 From: Chuan-Yen Chiang Date: Sat, 8 Jul 2023 02:35:53 +0200 Subject: [PATCH 0026/1547] fix: duplicated Intellij IDE message when running flutter doctor (#129030) This PR fixes the duplicated message from `flutter doctor` when install `Intellij IDE` from `JetBrains Toolbox`. The solution is based on the #98276. Add a function to skip the creation of the validator for `Mac` when the key word `JetBrainsToolboxApp` is in the `info.plist`. Before: Screenshot 2023-06-16 at 21 04 43 After: Screenshot 2023-06-16 at 21 13 15 fix #98276 --- .../lib/src/intellij/intellij_validator.dart | 12 ++++++ .../intellij/intellij_validator_test.dart | 42 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart index 7f09515dec91d..691d8e5ebe272 100644 --- a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart +++ b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart @@ -376,6 +376,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator { 'IntelliJ IDEA.app': _ultimateEditionId, 'IntelliJ IDEA Ultimate.app': _ultimateEditionId, 'IntelliJ IDEA CE.app': _communityEditionId, + 'IntelliJ IDEA Community Edition.app': _communityEditionId, }; static Iterable installed({ @@ -482,6 +483,17 @@ class IntelliJValidatorOnMac extends IntelliJValidator { ]), )); } + + // Remove JetBrains Toolbox link apps. These tiny apps just + // link to the full app, will get detected elsewhere in our search. + validators.removeWhere((DoctorValidator validator) { + final String identifierKey = plistParser.getValueFromFile( + (validator as IntelliJValidatorOnMac).plistFile, + PlistParser.kCFBundleIdentifierKey, + ) as String; + return identifierKey.contains('com.jetbrains.toolbox.linkapp'); + }); + return validators; } diff --git a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart index eab4b0b9f8927..bd7f810a58c9a 100644 --- a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart @@ -305,6 +305,7 @@ void main() { processManager: processManager, plistParser: FakePlistParser({ PlistParser.kCFBundleShortVersionStringKey: '2020.10', + PlistParser.kCFBundleIdentifierKey: 'com.jetbrains.intellij', }), ).whereType(); expect(validators.length, 2); @@ -371,6 +372,47 @@ void main() { expect(validator.pluginsPath, '/path/to/JetBrainsToolboxApp.plugins'); }); + + testWithoutContext('Remove JetBrains Toolbox', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final List installPaths = [ + fileSystem.path.join('/', 'foo', 'bar', 'Applications', + 'JetBrains Toolbox', 'IntelliJ IDEA Ultimate.app'), + fileSystem.path.join('/', 'foo', 'bar', 'Applications', + 'JetBrains Toolbox', 'IntelliJ IDEA Community Edition.app') + ]; + + for (final String installPath in installPaths) { + fileSystem.directory(installPath).createSync(recursive: true); + } + + final FakeProcessManager processManager = + FakeProcessManager.list([ + const FakeCommand(command: [ + 'mdfind', + 'kMDItemCFBundleIdentifier="com.jetbrains.intellij.ce"', + ], stdout: 'skip'), + const FakeCommand(command: [ + 'mdfind', + 'kMDItemCFBundleIdentifier="com.jetbrains.intellij*"', + ], stdout: 'skip') + ]); + + final Iterable installed = + IntelliJValidatorOnMac.installed( + fileSystem: fileSystem, + fileSystemUtils: + FileSystemUtils(fileSystem: fileSystem, platform: macPlatform), + userMessages: UserMessages(), + plistParser: FakePlistParser({ + 'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp', + 'CFBundleIdentifier': 'com.jetbrains.toolbox.linkapp', + }), + processManager: processManager, + ); + + expect(installed.length, 0); + }); } class IntelliJValidatorTestTarget extends IntelliJValidator { From 6a619bb3a58ffea72e7e0100c6e085c8b186ed7b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 21:14:55 -0400 Subject: [PATCH 0027/1547] Roll Flutter Engine from 40a8732a5de0 to 13d9d84e8aba (2 revisions) (#130189) https://github.com/flutter/engine/compare/40a8732a5de0...13d9d84e8aba 2023-07-07 dworsham@google.com [fuchsia] Fix tests; remove fuchsia dart SDK deps (flutter/engine#43461) 2023-07-07 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from MPy31yjgPV-d_YJq0... to 8YPOimmJgaAd5SlAT... (flutter/engine#43481) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from MPy31yjgPV-d to 8YPOimmJgaAd If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 59283d825bfff..9352217880a78 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -40a8732a5de0e63f2903bf0e565383f9671ce93c +13d9d84e8abaa2e195df3d7e203b82fa4c87533c diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 747bb027b1e25..4374d6ec4b70d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -MPy31yjgPV-d_YJq0flrP6oOibi_1do-LGtXh4cHOqEC +8YPOimmJgaAd5SlATKVqEd9jzEYsW-VZqoQywvFAG08C From 7495415363d836cba2f6720379b23e0a7e4db643 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 7 Jul 2023 22:03:22 -0400 Subject: [PATCH 0028/1547] Roll Flutter Engine from 13d9d84e8aba to 4ca619166c4a (2 revisions) (#130191) https://github.com/flutter/engine/compare/13d9d84e8aba...4ca619166c4a 2023-07-08 32242716+ricardoamador@users.noreply.github.com Remove unused autosubmit configuration file (flutter/engine#43483) 2023-07-07 skia-flutter-autoroll@skia.org Roll Skia from 2885452c3fb1 to 6d733caa0d3f (1 revision) (flutter/engine#43482) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9352217880a78..91236fe6cb30d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -13d9d84e8abaa2e195df3d7e203b82fa4c87533c +4ca619166c4a086ffd7f9449e342afff92165476 From 50d26f7a20859870eac39298b2b658a1e9f16aa3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 8 Jul 2023 04:06:38 -0400 Subject: [PATCH 0029/1547] Roll Flutter Engine from 4ca619166c4a to 9006633571bb (2 revisions) (#130195) https://github.com/flutter/engine/compare/4ca619166c4a...9006633571bb 2023-07-08 dkwingsmt@users.noreply.github.com Make updating window metrics multi-view (flutter/engine#43366) 2023-07-08 dkwingsmt@users.noreply.github.com Rename default views to implicit views (flutter/engine#43364) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 91236fe6cb30d..2b9866f225631 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4ca619166c4a086ffd7f9449e342afff92165476 +9006633571bbe0613398db94b0e98cc44d4d94cd From 7556274b121a55ce0b911b08b97cee2e5c77ee8b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 8 Jul 2023 05:14:41 -0400 Subject: [PATCH 0030/1547] Roll Flutter Engine from 9006633571bb to d5a35b4650b1 (1 revision) (#130197) https://github.com/flutter/engine/compare/9006633571bb...d5a35b4650b1 2023-07-08 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from vee6hAD_43mq_4FS7... to Q4Oq8NRW2yeBrgy4b... (flutter/engine#43486) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from vee6hAD_43mq to Q4Oq8NRW2yeB If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2b9866f225631..5e1312d28a9c0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9006633571bbe0613398db94b0e98cc44d4d94cd +d5a35b4650b1c3188e1eacf261d5547f99d38ab4 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index d93b0e2230160..9cb7641675975 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -vee6hAD_43mq_4FS7wnS04qeXSr3bMCDCkVid8PHIl8C +Q4Oq8NRW2yeBrgy4bUuNCaaMHWiTW0fF0oMdq58NFpQC From 24082b9f9236dd634a9ea5744aacc80e068d792e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 8 Jul 2023 10:40:39 -0400 Subject: [PATCH 0031/1547] Roll Flutter Engine from d5a35b4650b1 to 69eb8275ce47 (1 revision) (#130199) https://github.com/flutter/engine/compare/d5a35b4650b1...69eb8275ce47 2023-07-08 skia-flutter-autoroll@skia.org Roll Skia from 6d733caa0d3f to 05ce4af04609 (1 revision) (flutter/engine#43489) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5e1312d28a9c0..6bdb4bd88947f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d5a35b4650b1c3188e1eacf261d5547f99d38ab4 +69eb8275ce47fea54de17ed58c169e18b4d372da From 65ff3cb9b45c781a7534da023013e6f7b0d5befd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 8 Jul 2023 12:06:41 -0400 Subject: [PATCH 0032/1547] Roll Flutter Engine from 69eb8275ce47 to 189f823e7b41 (1 revision) (#130201) https://github.com/flutter/engine/compare/69eb8275ce47...189f823e7b41 2023-07-08 jason-simmons@users.noreply.github.com [Impeller] Check for a null command buffer in InlinePassContext::EndPass (flutter/engine#43485) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6bdb4bd88947f..39e39c5e753f6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -69eb8275ce47fea54de17ed58c169e18b4d372da +189f823e7b4103b6b438a57b4601455b3073b75a From 378e664833eb7037bd56ee8273a432523e6fd610 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 8 Jul 2023 15:31:18 -0400 Subject: [PATCH 0033/1547] Roll Flutter Engine from 189f823e7b41 to 0e06562c94c3 (1 revision) (#130208) https://github.com/flutter/engine/compare/189f823e7b41...0e06562c94c3 2023-07-08 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 8YPOimmJgaAd5SlAT... to TSpkNWkgR0F7xl8q5... (flutter/engine#43490) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 8YPOimmJgaAd to TSpkNWkgR0F7 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 39e39c5e753f6..fe535200bcd00 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -189f823e7b4103b6b438a57b4601455b3073b75a +0e06562c94c366aaac4bc3185a4fd52fe02cd3f6 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 4374d6ec4b70d..a06884c0b749a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -8YPOimmJgaAd5SlATKVqEd9jzEYsW-VZqoQywvFAG08C +TSpkNWkgR0F7xl8q5AQPp_xqgKkr-PX3xOqrH9OmquYC From b6f0bfac309b5a959a8773cc892b11de5be871a0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 8 Jul 2023 22:39:03 -0400 Subject: [PATCH 0034/1547] Roll Flutter Engine from 0e06562c94c3 to 958591a1c0e8 (1 revision) (#130217) https://github.com/flutter/engine/compare/0e06562c94c3...958591a1c0e8 2023-07-08 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Q4Oq8NRW2yeBrgy4b... to 8X61T1htYuHQtWtFv... (flutter/engine#43492) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from Q4Oq8NRW2yeB to 8X61T1htYuHQ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fe535200bcd00..34c362d27133d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0e06562c94c366aaac4bc3185a4fd52fe02cd3f6 +958591a1c0e8df9ad3377acec8d06668c8f7d280 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 9cb7641675975..b4dcc8604bb59 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -Q4Oq8NRW2yeBrgy4bUuNCaaMHWiTW0fF0oMdq58NFpQC +8X61T1htYuHQtWtFvxYbyx4PJau6HszSWtm3AUe76OgC From a35e42a8ca3871833d612f116e02855cfc39414c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 9 Jul 2023 00:29:20 -0400 Subject: [PATCH 0035/1547] Roll Flutter Engine from 958591a1c0e8 to 594701beda2c (1 revision) (#130218) https://github.com/flutter/engine/compare/958591a1c0e8...594701beda2c 2023-07-09 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from TSpkNWkgR0F7xl8q5... to UKVzvetd5M4SA_ufb... (flutter/engine#43494) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from TSpkNWkgR0F7 to UKVzvetd5M4S If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 34c362d27133d..0ede05d669d5d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -958591a1c0e8df9ad3377acec8d06668c8f7d280 +594701beda2ce8810a3ccda572f5f6facdddfad6 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index a06884c0b749a..ffcfe3f9c55ff 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -TSpkNWkgR0F7xl8q5AQPp_xqgKkr-PX3xOqrH9OmquYC +UKVzvetd5M4SA_ufbTTnS8b82IEQsj1ODaPYstw99JQC From bc5ba6bf3d299646f0637a43b849bf1c8f9c2e94 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 9 Jul 2023 07:57:25 -0400 Subject: [PATCH 0036/1547] Roll Flutter Engine from 594701beda2c to 9ae623328d28 (1 revision) (#130223) https://github.com/flutter/engine/compare/594701beda2c...9ae623328d28 2023-07-09 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 8X61T1htYuHQtWtFv... to E9CEA-wZJ9VgSP80c... (flutter/engine#43495) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 8X61T1htYuHQ to E9CEA-wZJ9Vg If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0ede05d669d5d..77eb331d7fdd2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -594701beda2ce8810a3ccda572f5f6facdddfad6 +9ae623328d286db428ae1c03e7f2ed82723fb7ab diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index b4dcc8604bb59..5b43fe369b734 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -8X61T1htYuHQtWtFvxYbyx4PJau6HszSWtm3AUe76OgC +E9CEA-wZJ9VgSP80cBycAETHFtR7VaKmfdHb3pn_nZIC From 3ec96a8a4a5dbc8b35fe15080f2290be039bad7d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 9 Jul 2023 08:57:27 -0400 Subject: [PATCH 0037/1547] Roll Flutter Engine from 9ae623328d28 to 111051e4f517 (1 revision) (#130225) https://github.com/flutter/engine/compare/9ae623328d28...111051e4f517 2023-07-09 skia-flutter-autoroll@skia.org Roll Skia from 05ce4af04609 to ab7f95f52ea6 (1 revision) (flutter/engine#43496) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 77eb331d7fdd2..438577639a8df 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9ae623328d286db428ae1c03e7f2ed82723fb7ab +111051e4f517eb848cf0cae641513b5877a6c20e From 899ebe355c9f5376758907b0f839d54d9b231f51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 9 Jul 2023 16:34:12 -0400 Subject: [PATCH 0038/1547] Roll Flutter Engine from 111051e4f517 to 382a0be57584 (1 revision) (#130232) https://github.com/flutter/engine/compare/111051e4f517...382a0be57584 2023-07-09 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from UKVzvetd5M4SA_ufb... to aQqgcKf1EwSoRWDet... (flutter/engine#43497) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from UKVzvetd5M4S to aQqgcKf1EwSo If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 438577639a8df..f3db3d21b3201 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -111051e4f517eb848cf0cae641513b5877a6c20e +382a0be5758486dfa83a6a992c9b4378b7d10ee7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ffcfe3f9c55ff..27630ecf4aceb 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -UKVzvetd5M4SA_ufbTTnS8b82IEQsj1ODaPYstw99JQC +aQqgcKf1EwSoRWDetU04qEIGmkIe5HpWz2fEGrF3_5MC From 5345221701727284bc961e3fb12ccfd3fc616dc7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 9 Jul 2023 21:01:34 -0400 Subject: [PATCH 0039/1547] Roll Flutter Engine from 382a0be57584 to 09c6ce42436b (1 revision) (#130233) https://github.com/flutter/engine/compare/382a0be57584...09c6ce42436b 2023-07-09 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from E9CEA-wZJ9VgSP80c... to eRSQn0XKuI7byK2i_... (flutter/engine#43498) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from E9CEA-wZJ9Vg to eRSQn0XKuI7b If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f3db3d21b3201..41dbe0c8712a1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -382a0be5758486dfa83a6a992c9b4378b7d10ee7 +09c6ce42436bf59196d06f6f0502f7f25648ea7f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 5b43fe369b734..9bece73eeb17c 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -E9CEA-wZJ9VgSP80cBycAETHFtR7VaKmfdHb3pn_nZIC +eRSQn0XKuI7byK2i_9p_Z4HzdJLKyHdrlMkMr95GfTkC From c565cff986638d2416de76fe5cf1b2ea3aa3eeaf Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 02:11:19 -0400 Subject: [PATCH 0040/1547] Roll Flutter Engine from 09c6ce42436b to ed3c5534ac6c (1 revision) (#130238) https://github.com/flutter/engine/compare/09c6ce42436b...ed3c5534ac6c 2023-07-10 dan@mindstab.net [linux] Allow overriding aot_library_path (flutter/engine#42555) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 41dbe0c8712a1..777996dfd8df3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09c6ce42436bf59196d06f6f0502f7f25648ea7f +ed3c5534ac6c84936fb5053691b6f5ad803969b0 From 1f2998e2045d06e0678bfc357d2779658b19f2de Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 04:17:17 -0400 Subject: [PATCH 0041/1547] Roll Flutter Engine from ed3c5534ac6c to e193c7c61bdb (1 revision) (#130240) https://github.com/flutter/engine/compare/ed3c5534ac6c...e193c7c61bdb 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from ab7f95f52ea6 to a72649f13420 (3 revisions) (flutter/engine#43504) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 777996dfd8df3..10eafb220c57c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ed3c5534ac6c84936fb5053691b6f5ad803969b0 +e193c7c61bdb3105813484e9a14a29ddc886f0bd From 9e76d54eb1dfd0f765a36e742d0b89a152e6c3b1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 05:45:08 -0400 Subject: [PATCH 0042/1547] Roll Flutter Engine from e193c7c61bdb to 074135bbcc61 (1 revision) (#130246) https://github.com/flutter/engine/compare/e193c7c61bdb...074135bbcc61 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from a72649f13420 to 0a1e7aeb29b5 (1 revision) (flutter/engine#43505) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 10eafb220c57c..e564242fc9e78 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e193c7c61bdb3105813484e9a14a29ddc886f0bd +074135bbcc6166bd395f3618b06af8b6000613fc From 2fd4f8bf15368a601a22ec08201869fb7288d03e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 07:19:26 -0400 Subject: [PATCH 0043/1547] Roll Flutter Engine from 074135bbcc61 to 49c6dcdac5ad (1 revision) (#130252) https://github.com/flutter/engine/compare/074135bbcc61...49c6dcdac5ad 2023-07-10 robert.ancell@canonical.com Fix leak when switching channels (flutter/engine#41827) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e564242fc9e78..a0853c938a9e7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -074135bbcc6166bd395f3618b06af8b6000613fc +49c6dcdac5ad51d78747d7c89b34a0405c241536 From 4ca4464b11d0862c77491fa868afae7f6b7ecbda Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 07:59:27 -0400 Subject: [PATCH 0044/1547] Roll Flutter Engine from 49c6dcdac5ad to 27f121896356 (2 revisions) (#130255) https://github.com/flutter/engine/compare/49c6dcdac5ad...27f121896356 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 0a1e7aeb29b5 to cf3f3d048122 (1 revision) (flutter/engine#43509) 2023-07-10 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from aQqgcKf1EwSoRWDet... to raXixVs2pKxD9ZasB... (flutter/engine#43508) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from aQqgcKf1EwSo to raXixVs2pKxD If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a0853c938a9e7..325017d6fa07f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -49c6dcdac5ad51d78747d7c89b34a0405c241536 +27f121896356757146233606a584a1a21315e2c7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 27630ecf4aceb..c489181d677d3 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -aQqgcKf1EwSoRWDetU04qEIGmkIe5HpWz2fEGrF3_5MC +raXixVs2pKxD9ZasBuNMwbtodIy1Ca6edQ5fxI2ehWUC From bde20211b3865a276668af4419cc7836e06f38b0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 10:55:30 -0400 Subject: [PATCH 0045/1547] Roll Flutter Engine from 27f121896356 to 168b68c304a5 (2 revisions) (#130265) https://github.com/flutter/engine/compare/27f121896356...168b68c304a5 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from cf3f3d048122 to 17686918fa1f (1 revision) (flutter/engine#43511) 2023-07-10 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from eRSQn0XKuI7byK2i_... to 4fmJ_PQoaE2L9vdx0... (flutter/engine#43510) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from eRSQn0XKuI7b to 4fmJ_PQoaE2L If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 325017d6fa07f..4a14b2437ca2f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -27f121896356757146233606a584a1a21315e2c7 +168b68c304a53eff12ee0d44225696b12d5ea313 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 9bece73eeb17c..bf717c19b63fb 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -eRSQn0XKuI7byK2i_9p_Z4HzdJLKyHdrlMkMr95GfTkC +4fmJ_PQoaE2L9vdx0eX2Tm7JhhRIeEDiROwucvp-MSMC From b828846fb9b7d827dabb6ba8e6cfada607617176 Mon Sep 17 00:00:00 2001 From: Rydmike Date: Mon, 10 Jul 2023 18:43:00 +0300 Subject: [PATCH 0046/1547] Fix default icon color constants reversed brightness documentation (#130231) Fixes the reversed default icon color constants brightness documentation for `kDefaultIconLightColor` and `kDefaultIconDarkColor`. FIX: https://github.com/flutter/flutter/issues/130230 --- packages/flutter/lib/src/material/constants.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/constants.dart b/packages/flutter/lib/src/material/constants.dart index 4696cce72d6a5..87064a5a560da 100644 --- a/packages/flutter/lib/src/material/constants.dart +++ b/packages/flutter/lib/src/material/constants.dart @@ -51,11 +51,11 @@ const EdgeInsets kTabLabelPadding = EdgeInsets.symmetric(horizontal: 16.0); const EdgeInsets kMaterialListPadding = EdgeInsets.symmetric(vertical: 8.0); /// The default color for [ThemeData.iconTheme] when [ThemeData.brightness] is -/// [Brightness.light]. This color is used in [IconButton] to detect whether +/// [Brightness.dark]. This color is used in [IconButton] to detect whether /// [IconTheme.of(context).color] is the same as the default color of [ThemeData.iconTheme]. const Color kDefaultIconLightColor = Colors.white; /// The default color for [ThemeData.iconTheme] when [ThemeData.brightness] is -/// [Brightness.dark]. This color is used in [IconButton] to detect whether +/// [Brightness.light]. This color is used in [IconButton] to detect whether /// [IconTheme.of(context).color] is the same as the default color of [ThemeData.iconTheme]. const Color kDefaultIconDarkColor = Colors.black87; From 2eaec8f5ac5368d9aacd50c4b2f61f15096fe0de Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 11:43:01 -0400 Subject: [PATCH 0047/1547] Roll Packages from b61eea12dbf9 to 4469c5e95dd8 (15 revisions) (#130266) https://github.com/flutter/packages/compare/b61eea12dbf9...4469c5e95dd8 2023-07-08 engine-flutter-autoroll@skia.org Roll Flutter from d55a7d89e05e to 65ff3cb9b45c (21 revisions) (flutter/packages#4413) 2023-07-08 stuartmorgan@google.com [tool] Update Dart SDK version (flutter/packages#4402) 2023-07-08 stuartmorgan@google.com [url_lancher] Don't use `canLaunchUrl` in Link (flutter/packages#4400) 2023-07-08 32242716+ricardoamador@users.noreply.github.com Remove unused autosubmit configuration file (flutter/packages#4410) 2023-07-07 49699333+dependabot[bot]@users.noreply.github.com [file_selector]: Bump androidx.annotation:annotation from 1.5.0 to 1.6.0 in /packages/file_selector/file_selector_android/android (flutter/packages#4312) 2023-07-07 engine-flutter-autoroll@skia.org Roll Flutter from bc49cd1bcab5 to d55a7d89e05e (17 revisions) (flutter/packages#4403) 2023-07-07 tarrinneal@gmail.com [shared_preferences] Variable binding in a condition requires an initializer fix (flutter/packages#4407) 2023-07-07 jhy03261997@gmail.com [go_router] implemented helpers for StatefulShellRoute (flutter/packages#4228) 2023-07-07 34871572+gmackall@users.noreply.github.com [in_app_purchase_android] Bump com.android.billingclient:billing from 5.2.0 to 6.0.0. (flutter/packages#4390) 2023-07-07 stuartmorgan@google.com [tool] Use 'flutter pub get' for Flutter packages (flutter/packages#4397) 2023-07-07 stuartmorgan@google.com [ci] Enable LUCI stable custom Linux tests (flutter/packages#4404) 2023-07-07 stuartmorgan@google.com [tool] Fix --current-package for app-facing packages (flutter/packages#4399) 2023-07-07 stuartmorgan@google.com [ci] Switch some tests to LUCI (flutter/packages#4395) 2023-07-07 tarrinneal@gmail.com [flutter_markdown] Pass parent TextStyle down to MarkdownElementBuilder.visitElementAfter (flutter/packages#4393) 2023-07-07 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.3.3 to 2.20.3 (flutter/packages#4394) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 7b80e436d6ad1..d3e606b04c5c5 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -b61eea12dbf94650fac7aaaed1e880b6cde69442 +4469c5e95dd891f7036ecd4cc240cca3c75fdbfe From 99a47c8460f585d7f3070128dd24e46e271e5aa6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 13:27:14 -0400 Subject: [PATCH 0048/1547] Roll Flutter Engine from 168b68c304a5 to 7b826a78e73c (1 revision) (#130273) https://github.com/flutter/engine/compare/168b68c304a5...7b826a78e73c 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 17686918fa1f to 1c9e2588b577 (3 revisions) (flutter/engine#43513) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4a14b2437ca2f..6abdf3792669e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -168b68c304a53eff12ee0d44225696b12d5ea313 +7b826a78e73ccc2338df3403e255896bfc1ef54a From 6c2023162fbfd3f24ae157b29329646488f84cd6 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:47:51 -0500 Subject: [PATCH 0049/1547] Change resultBundlePath representation from File to Directory (#130156) `resultBundlePath` is meant to be a directory. In the `xcodebuild --help`, it describes it as a directory: ``` -resultBundlePath PATH specifies the directory where a result bundle describing what occurred will be placed ``` This PR changes our usage of it from a file to a directory so that it gets deleted correctly between reruns. Fixes https://github.com/flutter/flutter/issues/129954. --- packages/flutter_tools/lib/src/ios/mac.dart | 12 +++--- .../hermetic/build_ios_test.dart | 40 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index cbd1f89c38aec..86a4a0546ad46 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -357,10 +357,10 @@ Future buildXcodeProject({ buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}'); } - final File resultBundleFile = tempDir.childFile(_kResultBundlePath); + final Directory resultBundleDirectory = tempDir.childDirectory(_kResultBundlePath); buildCommands.addAll([ '-resultBundlePath', - resultBundleFile.absolute.path, + resultBundleDirectory.absolute.path, '-resultBundleVersion', _kResultBundleVersion, ]); @@ -382,7 +382,7 @@ Future buildXcodeProject({ final Stopwatch sw = Stopwatch()..start(); initialBuildStatus = globals.logger.startProgress('Running Xcode build...'); - buildResult = await _runBuildWithRetries(buildCommands, app, resultBundleFile); + buildResult = await _runBuildWithRetries(buildCommands, app, resultBundleDirectory); // Notifies listener that no more output is coming. scriptOutputPipeFile?.writeAsStringSync('all done'); @@ -512,14 +512,14 @@ Future removeFinderExtendedAttributes(FileSystemEntity projectDirectory, P } } -Future _runBuildWithRetries(List buildCommands, BuildableIOSApp app, File resultBundleFile) async { +Future _runBuildWithRetries(List buildCommands, BuildableIOSApp app, Directory resultBundleDirectory) async { int buildRetryDelaySeconds = 1; int remainingTries = 8; RunResult? buildResult; while (remainingTries > 0) { - if (resultBundleFile.existsSync()) { - resultBundleFile.deleteSync(recursive: true); + if (resultBundleDirectory.existsSync()) { + resultBundleDirectory.deleteSync(recursive: true); } remainingTries--; buildRetryDelaySeconds *= 2; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index aaf95811246c6..c1f2dc3b47e77 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -117,7 +117,7 @@ void main() { 'xcresulttool', 'get', '--path', - _xcBundleFilePath, + _xcBundleDirectoryPath, '--format', 'json', ], @@ -173,7 +173,7 @@ void main() { '-destination', 'generic/platform=iOS', ], - '-resultBundlePath', _xcBundleFilePath, + '-resultBundlePath', _xcBundleDirectoryPath, '-resultBundleVersion', '3', 'FLUTTER_SUPPRESS_ANALYTICS=true', 'COMPILER_INDEX_STORE_ENABLE=NO', @@ -461,7 +461,7 @@ void main() { ProcessManager: () => FakeProcessManager.list([ xattrCommand, setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }), setUpXCResultCommand(), setUpRsyncCommand(), @@ -495,7 +495,7 @@ void main() { ProcessManager: () => FakeProcessManager.list([ xattrCommand, setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }, stdout: 'Lots of spew from Xcode', ), setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), @@ -530,7 +530,7 @@ void main() { ProcessManager: () => FakeProcessManager.list([ xattrCommand, setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }), setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded), setUpRsyncCommand(), @@ -594,7 +594,7 @@ void main() { ProcessManager: () => FakeProcessManager.list([ xattrCommand, setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }), setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue), setUpRsyncCommand(), @@ -628,7 +628,7 @@ void main() { setUpFakeXcodeBuildHandler( exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue), @@ -661,17 +661,17 @@ void main() { exitCode: 1, stdout: '$kConcurrentRunFailureMessage1 $kConcurrentRunFailureMessage2', onRun: () { - fileSystem.systemTempDirectory.childFile(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).childFile('result.xcresult').createSync(recursive: true); } ), // The second xcodebuild is triggered due to above concurrent run failure message. setUpFakeXcodeBuildHandler( onRun: () { // If the file is not cleaned, throw an error, test failure. - if (fileSystem.systemTempDirectory.childFile(_xcBundleFilePath).existsSync()) { + if (fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).existsSync()) { throwToolExit('xcresult bundle file existed.', exitCode: 2); } - fileSystem.systemTempDirectory.childFile(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).childFile('result.xcresult').createSync(recursive: true); } ), setUpXCResultCommand(stdout: kSampleResultJsonNoIssues), @@ -709,7 +709,7 @@ void main() { Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor ''', onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap), @@ -743,7 +743,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig setUpFakeXcodeBuildHandler( exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap), @@ -780,7 +780,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig Runner requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor ''', onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonNoIssues), @@ -815,7 +815,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig setUpFakeXcodeBuildHandler( exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonInvalidIssuesMap), @@ -850,7 +850,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig setUpFakeXcodeBuildHandler( exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonWithNoProvisioningProfileIssue), @@ -885,7 +885,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig setUpFakeXcodeBuildHandler( exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); } ), setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue), @@ -922,7 +922,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig simulator: true, exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }, ), setUpXCResultCommand(), @@ -958,7 +958,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig simulator: true, exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }, ), setUpXCResultCommand(stdout: kSampleResultJsonWithIssues), @@ -996,7 +996,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig simulator: true, exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); }, ), setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded), @@ -1040,7 +1040,7 @@ Runner requires a provisioning profile. Select a provisioning profile in the Sig }); } -const String _xcBundleFilePath = '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle'; +const String _xcBundleDirectoryPath = '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle'; class FakeAndroidSdk extends Fake implements AndroidSdk { @override From f731af637128c8cc45c0c4568323d1253b6dc4a0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 14:38:25 -0400 Subject: [PATCH 0050/1547] Roll Flutter Engine from 7b826a78e73c to 1de141c6a6e7 (2 revisions) (#130275) https://github.com/flutter/engine/compare/7b826a78e73c...1de141c6a6e7 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 1c9e2588b577 to 320f01ac1de7 (6 revisions) (flutter/engine#43514) 2023-07-10 2539699336@qq.com [iOS][Keyboard] Reland wait vsync on UI thread and update viewport inset to avoid jitter (flutter/engine#43463) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6abdf3792669e..c741a9c62810d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7b826a78e73ccc2338df3403e255896bfc1ef54a +1de141c6a6e744b30a1de179370aa0805e4e7b94 From dabd7b3bb58b43041e9db32c7090a01165e6d541 Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Mon, 10 Jul 2023 12:12:23 -0700 Subject: [PATCH 0051/1547] Throw error on unexpected positional arguments (#130274) This PR fixes ignoring when random positional arguments added to the `flutter gen-l10n`. So we are no longer able to call `flutter gen-l10n hello world` or `flutter gen-l10n --format false`. Fixes https://github.com/flutter/flutter/issues/118203 --- .../lib/src/commands/generate_localizations.dart | 5 +++++ .../hermetic/generate_localizations_test.dart | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/generate_localizations.dart b/packages/flutter_tools/lib/src/commands/generate_localizations.dart index a7931f0618f5f..452dc19a0bbeb 100644 --- a/packages/flutter_tools/lib/src/commands/generate_localizations.dart +++ b/packages/flutter_tools/lib/src/commands/generate_localizations.dart @@ -5,6 +5,7 @@ import 'package:process/process.dart'; import '../artifacts.dart'; +import '../base/common.dart'; import '../base/file_system.dart'; import '../base/logger.dart'; import '../localizations/gen_l10n.dart'; @@ -217,6 +218,10 @@ class GenerateLocalizationsCommand extends FlutterCommand { @override Future runCommand() async { + // Validate the rest of the args. + if (argResults!.rest.isNotEmpty) { + throwToolExit('Unexpected positional argument "${argResults!.rest.first}".'); + } // Keep in mind that this is also defined in the following locations: // 1. flutter_tools/lib/src/build_system/targets/localizations.dart // 2. flutter_tools/test/general.shard/build_system/targets/localizations_test.dart diff --git a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart index 552dd37470a8b..28c5d2767b48f 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart @@ -480,4 +480,17 @@ format: true FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), }); + + testUsingContext('throws error when unexpected positional argument is provided', () { + final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + ); + expect( + () async => createTestCommandRunner(command).run(['gen-l10n', '--synthetic-package', 'false']), + throwsToolExit(message: 'Unexpected positional argument "false".') + ); + }); } From 613bc890067988dc2112ab6bcf6410babd1d92be Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 15:24:26 -0400 Subject: [PATCH 0052/1547] Roll Flutter Engine from 1de141c6a6e7 to 3beba397ca4d (1 revision) (#130276) https://github.com/flutter/engine/compare/1de141c6a6e7...3beba397ca4d 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 320f01ac1de7 to 7e45a9fbca5f (3 revisions) (flutter/engine#43515) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c741a9c62810d..fbb281659ef51 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1de141c6a6e744b30a1de179370aa0805e4e7b94 +3beba397ca4dfae116873dda2611c27c7b587551 From b89bfd8e375cf08494cc7b30d97b0747df9f63d4 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Mon, 10 Jul 2023 12:32:56 -0700 Subject: [PATCH 0053/1547] re-enable "Linux packages_autoroller" (#130088) Fixes https://github.com/flutter/flutter/issues/129744 This change: 1. re-enables the Linux packages_autoroller 2. ensures we redact the token from appearing in any logs (in local testing I realized some failure logs might still expose the token) What actually fixed authentication however was creating and uploading a new GitHub personal access token, not this change. It's currently failing post-submit because being marked `bringup` it is running in the try pool, which does not have permissions to access the cloud KMS. However, I ran a LED build in the prod pool that succeeded: https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/fujino_google.com/3a8f128c352fca53a9a29f1e7eab6c3ed24f3bb2a5feb196ea1a69127540e8a6/+/build.proto?server=chromium-swarm.appspot.com --- .ci.yaml | 2 -- .../core/bin/packages_autoroller.dart | 5 +-- dev/conductor/core/lib/src/stdio.dart | 25 +++++++++++++++ dev/conductor/core/test/common.dart | 1 + dev/conductor/core/test/next_test.dart | 30 ++---------------- .../core/test/packages_autoroller_test.dart | 31 +++++++++++++++++++ 6 files changed, 63 insertions(+), 31 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 0a51da5a3a969..78b22e1e4d3f7 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -243,8 +243,6 @@ targets: - name: Linux packages_autoroller presubmit: false - # TODO(fujino): https://github.com/flutter/flutter/issues/129744 - bringup: true recipe: pub_autoroller/pub_autoroller timeout: 30 enabled_branches: diff --git a/dev/conductor/core/bin/packages_autoroller.dart b/dev/conductor/core/bin/packages_autoroller.dart index 6cb35b2cf8712..a890927f0a6f6 100644 --- a/dev/conductor/core/bin/packages_autoroller.dart +++ b/dev/conductor/core/bin/packages_autoroller.dart @@ -80,7 +80,7 @@ ${parser.usage} } final FrameworkRepository framework = FrameworkRepository( - _localCheckouts, + _localCheckouts(token), mirrorRemote: Remote.mirror(mirrorUrl), upstreamRemote: Remote.upstream(upstreamUrl), ); @@ -106,7 +106,7 @@ String _parseOrgName(String remoteUrl) { return match.group(1)!; } -Checkouts get _localCheckouts { +Checkouts _localCheckouts(String token) { const FileSystem fileSystem = LocalFileSystem(); const ProcessManager processManager = LocalProcessManager(); const Platform platform = LocalPlatform(); @@ -114,6 +114,7 @@ Checkouts get _localCheckouts { stdout: io.stdout, stderr: io.stderr, stdin: io.stdin, + filter: (String message) => message.replaceAll(token, '[GitHub TOKEN]'), ); return Checkouts( fileSystem: fileSystem, diff --git a/dev/conductor/core/lib/src/stdio.dart b/dev/conductor/core/lib/src/stdio.dart index 8777b91f40587..df8f81d056459 100644 --- a/dev/conductor/core/lib/src/stdio.dart +++ b/dev/conductor/core/lib/src/stdio.dart @@ -70,6 +70,7 @@ class VerboseStdio extends Stdio { required this.stdout, required this.stderr, required this.stdin, + this.filter, }); factory VerboseStdio.local() => VerboseStdio( @@ -82,26 +83,50 @@ class VerboseStdio extends Stdio { final io.Stdout stderr; final io.Stdin stdin; + /// If provided, all messages will be passed through this function before being logged. + final String Function(String)? filter; + @override void printError(String message) { + if (filter != null) { + message = filter!(message); + } super.printError(message); stderr.writeln(message); } + @override + void printWarning(String message) { + if (filter != null) { + message = filter!(message); + } + super.printWarning(message); + stderr.writeln(message); + } + @override void printStatus(String message) { + if (filter != null) { + message = filter!(message); + } super.printStatus(message); stdout.writeln(message); } @override void printTrace(String message) { + if (filter != null) { + message = filter!(message); + } super.printTrace(message); stdout.writeln(message); } @override void write(String message) { + if (filter != null) { + message = filter!(message); + } super.write(message); stdout.write(message); } diff --git a/dev/conductor/core/test/common.dart b/dev/conductor/core/test/common.dart index 9cf66ffdfe365..f1a2f3999924f 100644 --- a/dev/conductor/core/test/common.dart +++ b/dev/conductor/core/test/common.dart @@ -6,6 +6,7 @@ import 'package:args/args.dart'; import 'package:conductor_core/src/stdio.dart'; import 'package:test/test.dart'; +export 'package:test/fake.dart'; export 'package:test/test.dart' hide isInstanceOf; export '../../../../packages/flutter_tools/test/src/fake_process_manager.dart'; diff --git a/dev/conductor/core/test/next_test.dart b/dev/conductor/core/test/next_test.dart index f124aa2417895..dee3a2e567b41 100644 --- a/dev/conductor/core/test/next_test.dart +++ b/dev/conductor/core/test/next_test.dart @@ -1227,34 +1227,10 @@ void main() { } /// A [Stdio] that will throw an exception if any of its methods are called. -class _UnimplementedStdio implements Stdio { - const _UnimplementedStdio(); +class _UnimplementedStdio extends Fake implements Stdio { + _UnimplementedStdio(); - static const _UnimplementedStdio _instance = _UnimplementedStdio(); - static _UnimplementedStdio get instance => _instance; - - Never _throw() => throw Exception('Unimplemented!'); - - @override - List get logs => _throw(); - - @override - void printError(String message) => _throw(); - - @override - void printWarning(String message) => _throw(); - - @override - void printStatus(String message) => _throw(); - - @override - void printTrace(String message) => _throw(); - - @override - void write(String message) => _throw(); - - @override - String readLineSync() => _throw(); + static final _UnimplementedStdio instance = _UnimplementedStdio(); } class _TestRepository extends Repository { diff --git a/dev/conductor/core/test/packages_autoroller_test.dart b/dev/conductor/core/test/packages_autoroller_test.dart index 50e21a1aee56f..9ce7a282a6c33 100644 --- a/dev/conductor/core/test/packages_autoroller_test.dart +++ b/dev/conductor/core/test/packages_autoroller_test.dart @@ -512,4 +512,35 @@ void main() { expect(processManager, hasNoRemainingExpectations); }); }); + + test('VerboseStdio logger can filter out confidential pattern', () async { + const String token = 'secret'; + const String replacement = 'replacement'; + final VerboseStdio stdio = VerboseStdio( + stdin: _NoOpStdin(), + stderr: _NoOpStdout(), + stdout: _NoOpStdout(), + filter: (String msg) => msg.replaceAll(token, replacement), + ); + stdio.printStatus('Hello'); + expect(stdio.logs.last, '[status] Hello'); + + stdio.printStatus('Using $token'); + expect(stdio.logs.last, '[status] Using $replacement'); + + stdio.printWarning('Using $token'); + expect(stdio.logs.last, '[warning] Using $replacement'); + + stdio.printError('Using $token'); + expect(stdio.logs.last, '[error] Using $replacement'); + + stdio.printTrace('Using $token'); + expect(stdio.logs.last, '[trace] Using $replacement'); + }); +} + +class _NoOpStdin extends Fake implements io.Stdin {} +class _NoOpStdout extends Fake implements io.Stdout { + @override + void writeln([Object? object]) {} } From cb91ba11a9ad697cbb93f2108040c38063a2ab7b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 16:08:08 -0400 Subject: [PATCH 0054/1547] Roll Flutter Engine from 3beba397ca4d to 71c5674a44a5 (1 revision) (#130278) https://github.com/flutter/engine/compare/3beba397ca4d...71c5674a44a5 2023-07-10 skia-flutter-autoroll@skia.org Roll Dart SDK from 4998bf65f91c to 3778952664e0 (6 revisions) (flutter/engine#43516) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fbb281659ef51..f05970eeb190b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3beba397ca4dfae116873dda2611c27c7b587551 +71c5674a44a5c1ff7e07a716d6573bae5eb2884f From 38e568e0582ae3514a38d372b592245635cab3f6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 17:10:58 -0400 Subject: [PATCH 0055/1547] Roll Flutter Engine from 71c5674a44a5 to b328b034f07b (1 revision) (#130282) https://github.com/flutter/engine/compare/71c5674a44a5...b328b034f07b 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 7e45a9fbca5f to 03e689a0fa32 (2 revisions) (flutter/engine#43517) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f05970eeb190b..5739d78bec7db 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -71c5674a44a5c1ff7e07a716d6573bae5eb2884f +b328b034f07b8f690142d1ce696a15c52cb42504 From f30e6f4571600ec6b1d878db8d9b684ecdc7215f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 19:10:01 -0400 Subject: [PATCH 0056/1547] Roll Flutter Engine from b328b034f07b to 7d054abf842c (3 revisions) (#130287) https://github.com/flutter/engine/compare/b328b034f07b...7d054abf842c 2023-07-10 bdero@google.com [Impeller] Add matrix backdrop filter golden. (flutter/engine#43484) 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 03e689a0fa32 to c06d7ef5c276 (1 revision) (flutter/engine#43520) 2023-07-10 robert.ancell@canonical.com Use better method of ensuring that *_get_type() functions are exported (flutter/engine#43395) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5739d78bec7db..14335d0c756c2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b328b034f07b8f690142d1ce696a15c52cb42504 +7d054abf842ce00234077e4b2f5584bba1f693ea From 6865bb4c9b58b998060ef0c6a08305bd771f7ef8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 23:23:12 +0000 Subject: [PATCH 0057/1547] Bump actions/labeler from 4.2.0 to 4.3.0 (#130291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/labeler](https://github.com/actions/labeler) from 4.2.0 to 4.3.0.
Release notes

Sourced from actions/labeler's releases.

v4.3.0

What's Changed

In scope of this release, the ability to specify pull request number(s) was added by @​credfeto in actions/labeler#349.

Support for reading from the configuration file presented on the runner was added by @​lrstanley in actions/labeler#394. It allows you to use a configuration file generated during workflow run or uploaded from a separate repository.

Please refer to the action documentation for more information.

This release also includes the following changes:

New Contributors

Full Changelog: https://github.com/actions/labeler/compare/v4...v4.3.0

Commits
  • ac9175f Bump @​octokit/plugin-retry from 5.0.4 to 5.0.5 (#610)
  • 7542ec7 Bump tough-cookie from 4.1.2 to 4.1.3 (#609)
  • be13bbd Early exit when no files are changed. (#456)
  • 994304c feat(config): support reading from local file if it exists (#394)
  • 327d35f Added ability to pass in an optional PR number as a parameter (#349)
  • 65f306b Fix a typo in the example about using the action outputs (#606)
  • b669025 Bump @​typescript-eslint/eslint-plugin from 5.60.1 to 5.61.0 (#604)
  • 52979ba Bump @​typescript-eslint/parser from 5.60.1 to 5.61.0 (#602)
  • 5bea145 Bump eslint from 8.43.0 to 8.44.0 (#601)
  • a212485 Add examples to match all repo files (#600)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/labeler&package-manager=github_actions&previous-version=4.2.0&new-version=4.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 336d04f809a15..e24e4552853e5 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -17,6 +17,6 @@ jobs: runs-on: ubuntu-latest steps: # Source available at https://github.com/actions/labeler/blob/main/README.md - - uses: actions/labeler@0967ca812e7fdc8f5f71402a1b486d5bd061fe20 + - uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 with: sync-labels: false From 829d1482ec0867c8f175d6af5e5d6ff27c6d07d3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 19:58:24 -0400 Subject: [PATCH 0058/1547] Roll Flutter Engine from 7d054abf842c to 2a0dd9d2f28e (4 revisions) (#130296) https://github.com/flutter/engine/compare/7d054abf842c...2a0dd9d2f28e 2023-07-10 chinmaygarde@google.com [Impeller] Fix Vulkan validation error when there is a blit directed at a swapchain image. (flutter/engine#43527) 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from 89313a8cadab to aad8fbb17d69 (3 revisions) (flutter/engine#43526) 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from c06d7ef5c276 to 89313a8cadab (2 revisions) (flutter/engine#43521) 2023-07-10 jonahwilliams@google.com [Impeller] Don't decompress into device buffer for Vulkan/GLES. (flutter/engine#43493) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 14335d0c756c2..3e8e22bf7d6bf 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7d054abf842ce00234077e4b2f5584bba1f693ea +2a0dd9d2f28ed1f382b316c66150a1fa14243e3d From 488ad3846ca04f90357a5c1a7f06f06fb5e09c6d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 20:42:13 -0400 Subject: [PATCH 0059/1547] Roll Flutter Engine from 2a0dd9d2f28e to daecd616f5a7 (3 revisions) (#130298) https://github.com/flutter/engine/compare/2a0dd9d2f28e...daecd616f5a7 2023-07-10 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from raXixVs2pKxD9ZasB... to bb8HXP6JZ60Unjk-W... (flutter/engine#43532) 2023-07-10 skia-flutter-autoroll@skia.org Roll Dart SDK from 3778952664e0 to f9d33db51927 (1 revision) (flutter/engine#43531) 2023-07-10 skia-flutter-autoroll@skia.org Roll Skia from aad8fbb17d69 to 2db628aa1181 (1 revision) (flutter/engine#43530) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from raXixVs2pKxD to bb8HXP6JZ60U If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3e8e22bf7d6bf..94c94cc5e6c17 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2a0dd9d2f28ed1f382b316c66150a1fa14243e3d +daecd616f5a7e4a0af283d988b683d3d88fa1ba0 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c489181d677d3..a07fc21eacb3a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -raXixVs2pKxD9ZasBuNMwbtodIy1Ca6edQ5fxI2ehWUC +bb8HXP6JZ60Unjk-WW7NnWpF4jfFZ-BUn9KZJQsyhHMC From 3163306d885ca3a3789131dd9be5a2827ea742dc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 23:09:08 -0400 Subject: [PATCH 0060/1547] Roll Flutter Engine from daecd616f5a7 to 95316fbc25a7 (4 revisions) (#130305) https://github.com/flutter/engine/compare/daecd616f5a7...95316fbc25a7 2023-07-11 jonahwilliams@google.com [Impeller] Unconditionally cache swapchain msaa texture. (flutter/engine#43529) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from c3d39bed2830 to 76daa2a33fa5 (1 revision) (flutter/engine#43539) 2023-07-11 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 4fmJ_PQoaE2L9vdx0... to cgcxIe8D4wb8hQWCV... (flutter/engine#43538) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 2db628aa1181 to c3d39bed2830 (1 revision) (flutter/engine#43537) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 4fmJ_PQoaE2L to cgcxIe8D4wb8 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 94c94cc5e6c17..5338da0340b62 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -daecd616f5a7e4a0af283d988b683d3d88fa1ba0 +95316fbc25a71027fdc428b7c68d7bb0d75308ec diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index bf717c19b63fb..90e8f19bf2574 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -4fmJ_PQoaE2L9vdx0eX2Tm7JhhRIeEDiROwucvp-MSMC +cgcxIe8D4wb8hQWCV34gOpkrhylRd-ZTpPHWu8KqG5EC From 8ee019d587f1bde21303c847fcee52063add02ec Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 11 Jul 2023 15:45:46 +1200 Subject: [PATCH 0061/1547] Add Linux implementation of the platform view example (#123731) --- examples/platform_view/lib/main.dart | 3 +- examples/platform_view/linux/CMakeLists.txt | 140 +++++++++++++++ .../linux/flutter/CMakeLists.txt | 88 +++++++++ examples/platform_view/linux/main.cc | 10 ++ .../platform_view/linux/my_application.cc | 167 ++++++++++++++++++ examples/platform_view/linux/my_application.h | 22 +++ 6 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 examples/platform_view/linux/CMakeLists.txt create mode 100644 examples/platform_view/linux/flutter/CMakeLists.txt create mode 100644 examples/platform_view/linux/main.cc create mode 100644 examples/platform_view/linux/my_application.cc create mode 100644 examples/platform_view/linux/my_application.h diff --git a/examples/platform_view/lib/main.dart b/examples/platform_view/lib/main.dart index 198dcdf2435e0..6e0e8904eaa6e 100644 --- a/examples/platform_view/lib/main.dart +++ b/examples/platform_view/lib/main.dart @@ -57,8 +57,9 @@ class _MyHomePageState extends State { return const Text('Continue in Windows view'); case TargetPlatform.macOS: return const Text('Continue in macOS view'); - case TargetPlatform.fuchsia: case TargetPlatform.linux: + return const Text('Continue in Linux view'); + case TargetPlatform.fuchsia: throw UnimplementedError('Platform not yet implemented'); } } diff --git a/examples/platform_view/linux/CMakeLists.txt b/examples/platform_view/linux/CMakeLists.txt new file mode 100644 index 0000000000000..67f289712447f --- /dev/null +++ b/examples/platform_view/linux/CMakeLists.txt @@ -0,0 +1,140 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 17) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "platform_view") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "io.flutter.examples.platform_view") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/examples/platform_view/linux/flutter/CMakeLists.txt b/examples/platform_view/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000000000..d5bd01648a96d --- /dev/null +++ b/examples/platform_view/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/examples/platform_view/linux/main.cc b/examples/platform_view/linux/main.cc new file mode 100644 index 0000000000000..281a29e16b599 --- /dev/null +++ b/examples/platform_view/linux/main.cc @@ -0,0 +1,10 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/examples/platform_view/linux/my_application.cc b/examples/platform_view/linux/my_application.cc new file mode 100644 index 0000000000000..403df877b0ac7 --- /dev/null +++ b/examples/platform_view/linux/my_application.cc @@ -0,0 +1,167 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include + +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + + // Channel to receive platform view requests from Flutter. + FlMethodChannel* platform_view_channel; + + // Main window. + GtkWindow* window; + + // Current counter. + int64_t counter; + + // Request in progress. + FlMethodCall* method_call; + + // Native window requested by Flutter. + GtkWindow* native_window; + + // Label to show count. + GtkLabel* counter_label; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +static void update_counter_label(MyApplication* self) { + g_autofree gchar* text = + g_strdup_printf("Button tapped %" G_GINT64_FORMAT " %s.", self->counter, + self->counter == 1 ? "time" : "times"); + gtk_label_set_text(self->counter_label, text); +} + +static void button_clicked_cb(MyApplication* self) { + self->counter++; + update_counter_label(self); +} + +static void native_window_delete_event_cb(MyApplication* self, + gint response_id) { + g_autoptr(FlValue) counter_value = fl_value_new_int(self->counter); + fl_method_call_respond_success(self->method_call, counter_value, nullptr); + g_clear_object(&self->method_call); +} + +// Handle request to switch the view. +static void handle_switch_view(MyApplication* self, FlMethodCall* method_call) { + FlValue* counter_value = fl_method_call_get_args(method_call); + if (fl_value_get_type(counter_value) != FL_VALUE_TYPE_INT) { + fl_method_call_respond_error(self->method_call, "Invalid args", + "Invalid switchView args", nullptr, nullptr); + return; + } + + self->counter = fl_value_get_int(counter_value); + self->method_call = FL_METHOD_CALL(g_object_ref(method_call)); + + // Show the same UI in a native window. + self->native_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + gtk_window_set_transient_for(self->native_window, self->window); + gtk_window_set_modal(self->native_window, TRUE); + gtk_window_set_destroy_with_parent(self->native_window, TRUE); + g_signal_connect_swapped(self->native_window, "delete-event", + G_CALLBACK(native_window_delete_event_cb), self); + + GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12); + gtk_widget_set_margin_start(box, 24); + gtk_widget_set_margin_end(box, 24); + gtk_widget_set_margin_top(box, 24); + gtk_widget_set_margin_bottom(box, 24); + gtk_widget_show(box); + gtk_container_add(GTK_CONTAINER(self->native_window), box); + + self->counter_label = GTK_LABEL(gtk_label_new("")); + gtk_widget_show(GTK_WIDGET(self->counter_label)); + gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(self->counter_label)); + + GtkWidget* button = gtk_button_new_with_label("+"); + gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(button)), + "circular"); + gtk_widget_set_halign(button, GTK_ALIGN_CENTER); + gtk_widget_show(button); + gtk_container_add(GTK_CONTAINER(box), button); + g_signal_connect_swapped(button, "clicked", G_CALLBACK(button_clicked_cb), + self); + + update_counter_label(self); + + gtk_window_present(self->native_window); +} + +// Handle platform view requests from Flutter. +static void platform_view_channel_method_cb(FlMethodChannel* channel, + FlMethodCall* method_call, + gpointer user_data) { + MyApplication* self = MY_APPLICATION(user_data); + + const char* name = fl_method_call_get_name(method_call); + if (g_str_equal(name, "switchView")) { + handle_switch_view(self, method_call); + } else { + fl_method_call_respond_not_implemented(method_call, nullptr); + } +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + + g_clear_object(&self->platform_view_channel); + + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + self->window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + gtk_window_set_default_size(self->window, 1280, 720); + gtk_widget_show(GTK_WIDGET(self->window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(self->window), GTK_WIDGET(view)); + + // Create channel to handle platform view requests from Flutter. + FlEngine* engine = fl_view_get_engine(view); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + self->platform_view_channel = fl_method_channel_new( + fl_engine_get_binary_messenger(engine), + "samples.flutter.io/platform_view", FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(self->platform_view_channel, + platform_view_channel_method_cb, + self, nullptr); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; + G_APPLICATION_CLASS(klass)->activate = my_application_activate; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, "flags", + G_APPLICATION_NON_UNIQUE, nullptr)); +} diff --git a/examples/platform_view/linux/my_application.h b/examples/platform_view/linux/my_application.h new file mode 100644 index 0000000000000..8c66ec485434d --- /dev/null +++ b/examples/platform_view/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ From ad74a4f76c2c1453f7f95b8fc5fd625cf99b6ffc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 10 Jul 2023 23:51:23 -0400 Subject: [PATCH 0062/1547] Roll Flutter Engine from 95316fbc25a7 to 312e4813a880 (2 revisions) (#130307) https://github.com/flutter/engine/compare/95316fbc25a7...312e4813a880 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 76daa2a33fa5 to bbe71d71e576 (1 revision) (flutter/engine#43541) 2023-07-11 flar@google.com Use full 4x4 matrix transforms in TransformLayer (flutter/engine#43536) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5338da0340b62..ff5c760ce1d93 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -95316fbc25a71027fdc428b7c68d7bb0d75308ec +312e4813a880653b1e2b0647a4194e6aca6cee88 From 901d44f230bcdff434c61ebea2416e1214165b63 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 00:55:01 -0400 Subject: [PATCH 0063/1547] Roll Flutter Engine from 312e4813a880 to 2c82dd7ec54b (1 revision) (#130309) https://github.com/flutter/engine/compare/312e4813a880...2c82dd7ec54b 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from bbe71d71e576 to d0991c6af2d6 (1 revision) (flutter/engine#43543) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ff5c760ce1d93..e0a5653768d6e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -312e4813a880653b1e2b0647a4194e6aca6cee88 +2c82dd7ec54becf3b78836ec179ffe62603637f7 From 2d951ac22c417fb13a0114ed589ff024b1b73e39 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 01:44:13 -0400 Subject: [PATCH 0064/1547] Roll Flutter Engine from 2c82dd7ec54b to 153d9e1d598a (2 revisions) (#130311) https://github.com/flutter/engine/compare/2c82dd7ec54b...153d9e1d598a 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from d0991c6af2d6 to 6a5c4b0c0fcb (1 revision) (flutter/engine#43544) 2023-07-11 chinmaygarde@google.com [Impeller] Refactor barriers and add documentation. (flutter/engine#43540) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e0a5653768d6e..8af9ed6a1a4e9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2c82dd7ec54becf3b78836ec179ffe62603637f7 +153d9e1d598af4e55c6b090f0164ec9ba15b4762 From 81d7297d916bca19a7969b3a9d529f4f89d9f199 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 02:28:10 -0400 Subject: [PATCH 0065/1547] Roll Flutter Engine from 153d9e1d598a to 767f2fb8ab03 (1 revision) (#130313) https://github.com/flutter/engine/compare/153d9e1d598a...767f2fb8ab03 2023-07-11 dnfield@google.com [Impeller] Improve resolution of text scaling. (flutter/engine#43533) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8af9ed6a1a4e9..e2d58cde04a00 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -153d9e1d598af4e55c6b090f0164ec9ba15b4762 +767f2fb8ab032152de8a03680d3632f53e686ab6 From d71bbfb490357eaf804c7e3abe0713b6bc94f221 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Mon, 10 Jul 2023 23:44:33 -0700 Subject: [PATCH 0066/1547] Implement preferPaintInterior correctly for _CompoundBorder (#129851) --- .../flutter/lib/src/painting/borders.dart | 2 +- .../flutter/test/painting/border_test.dart | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/painting/borders.dart b/packages/flutter/lib/src/painting/borders.dart index b96713cdfcff8..82282a6d8800c 100644 --- a/packages/flutter/lib/src/painting/borders.dart +++ b/packages/flutter/lib/src/painting/borders.dart @@ -840,7 +840,7 @@ class _CompoundBorder extends ShapeBorder { } @override - bool get preferPaintInterior => true; + bool get preferPaintInterior => borders.every((ShapeBorder border) => border.preferPaintInterior); @override void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) { diff --git a/packages/flutter/test/painting/border_test.dart b/packages/flutter/test/painting/border_test.dart index db0fdc4522b5b..f2f2aebe5e1b1 100644 --- a/packages/flutter/test/painting/border_test.dart +++ b/packages/flutter/test/painting/border_test.dart @@ -402,4 +402,71 @@ void main() { await tester.pumpWidget(buildWidget(border: allowedBorderDirectionalVariations, boxShape: BoxShape.circle)); expect(tester.takeException(), isNull); }); + + test('Compound borders with differing preferPaintInteriors', () { + expect(ShapeWithInterior().preferPaintInterior, isTrue); + expect(ShapeWithoutInterior().preferPaintInterior, isFalse); + expect((ShapeWithInterior() + ShapeWithInterior()).preferPaintInterior, isTrue); + expect((ShapeWithInterior() + ShapeWithoutInterior()).preferPaintInterior, isFalse); + expect((ShapeWithoutInterior() + ShapeWithInterior()).preferPaintInterior, isFalse); + expect((ShapeWithoutInterior() + ShapeWithoutInterior()).preferPaintInterior, isFalse); + }); +} + +class ShapeWithInterior extends ShapeBorder { + @override + bool get preferPaintInterior => true; + + @override + ShapeBorder scale(double t) { + return this; + } + + @override + EdgeInsetsGeometry get dimensions => EdgeInsets.zero; + + @override + Path getInnerPath(Rect rect, { TextDirection? textDirection }) { + return Path(); + } + + @override + Path getOuterPath(Rect rect, { TextDirection? textDirection }) { + return Path(); + } + + @override + void paintInterior(Canvas canvas, Rect rect, Paint paint, { TextDirection? textDirection }) { } + + @override + void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) { } +} + +class ShapeWithoutInterior extends ShapeBorder { + @override + bool get preferPaintInterior => false; + + @override + ShapeBorder scale(double t) { + return this; + } + + @override + EdgeInsetsGeometry get dimensions => EdgeInsets.zero; + + @override + Path getInnerPath(Rect rect, { TextDirection? textDirection }) { + return Path(); + } + + @override + Path getOuterPath(Rect rect, { TextDirection? textDirection }) { + return Path(); + } + + @override + void paintInterior(Canvas canvas, Rect rect, Paint paint, { TextDirection? textDirection }) { } + + @override + void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) { } } From 1b756bc5f9ec9d6ce51b4b20fd21556f981e5dc2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 03:21:17 -0400 Subject: [PATCH 0067/1547] Roll Flutter Engine from 767f2fb8ab03 to 12aa98177cf2 (1 revision) (#130315) https://github.com/flutter/engine/compare/767f2fb8ab03...12aa98177cf2 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 6a5c4b0c0fcb to 77267bf1e7b3 (1 revision) (flutter/engine#43545) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e2d58cde04a00..729de2fbcb74e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -767f2fb8ab032152de8a03680d3632f53e686ab6 +12aa98177cf2be210e51be9dbbaf0b964a54adf6 From 74491fc73e512fbb93b348499561b94fdb1bdf50 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 04:36:25 -0400 Subject: [PATCH 0068/1547] Roll Flutter Engine from 12aa98177cf2 to 2139c8a90822 (2 revisions) (#130316) https://github.com/flutter/engine/compare/12aa98177cf2...2139c8a90822 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 77267bf1e7b3 to eb1cdb6bd87f (2 revisions) (flutter/engine#43548) 2023-07-11 49699333+dependabot[bot]@users.noreply.github.com Bump actions/labeler from 4.2.0 to 4.3.0 (flutter/engine#43546) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 729de2fbcb74e..527feb1b90fde 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -12aa98177cf2be210e51be9dbbaf0b964a54adf6 +2139c8a90822d6dacc129a51fa02672c4e564157 From af2e28230f1639e071ad0138a8507691d85c37bf Mon Sep 17 00:00:00 2001 From: Darshan Rander Date: Tue, 11 Jul 2023 14:17:11 +0530 Subject: [PATCH 0069/1547] fix: `ExpansionTileTheme.shape` assignment in `ExpansionTile` (#127749) The ExpansionTile was not following `shape` from ExpansionTileTheme as it was assigning wrong parameter to the tween. fixes #129785 --- packages/flutter/lib/src/material/expansion_tile.dart | 2 +- packages/flutter/test/material/expansion_tile_theme_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/expansion_tile.dart b/packages/flutter/lib/src/material/expansion_tile.dart index 10ca52d5aab44..3dc8e99f8647b 100644 --- a/packages/flutter/lib/src/material/expansion_tile.dart +++ b/packages/flutter/lib/src/material/expansion_tile.dart @@ -683,7 +683,7 @@ class _ExpansionTileState extends State with SingleTickerProvider bottom: BorderSide(color: Colors.transparent), ) ..end = widget.shape - ?? expansionTileTheme.collapsedShape + ?? expansionTileTheme.shape ?? Border( top: BorderSide(color: theme.dividerColor), bottom: BorderSide(color: theme.dividerColor), diff --git a/packages/flutter/test/material/expansion_tile_theme_test.dart b/packages/flutter/test/material/expansion_tile_theme_test.dart index 323d3eb2540c3..cb29a397e5cd6 100644 --- a/packages/flutter/test/material/expansion_tile_theme_test.dart +++ b/packages/flutter/test/material/expansion_tile_theme_test.dart @@ -290,7 +290,7 @@ void main() { // Check the expanded text color when textColor is applied. expect(getTextColor(), textColor); // Check the expanded ShapeBorder when shape is applied. - expect(shapeDecoration.shape, collapsedShape); + expect(shapeDecoration.shape, shape); // Check the child position when expandedAlignment is applied. final Rect childRect = tester.getRect(find.text('Tile 1')); From 2bf8414a20108065eb1eebc8885b5b6c83ad9b18 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 11 Jul 2023 01:53:59 -0700 Subject: [PATCH 0070/1547] Update labeler for recent changes (#130168) 'team' is going away, and 'tech debt' got renamed. --- .github/labeler.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index b134dfdbc907f..9571981ef296c 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -79,21 +79,10 @@ framework: platform-ios: - packages/flutter_tools/lib/src/ios/**/* -team: - - '**/pubspec.yaml' - - '**/fix_data.yaml' - - '**/*.expect' - - '**/*test_fixes*' - - .github/**/* - - dev/**/* - - examples/**/* - - packages/flutter_goldens/**/* - - packages/flutter_goldens_client/**/* - 'customer: gallery': - examples/flutter_gallery/**/* -tech-debt: +'c: tech-debt': - '**/fix_data.yaml' - '**/*.expect' - '**/*test_fixes*' From eaf01a9a50d34222e934046ca72db4f79628f334 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 05:28:12 -0400 Subject: [PATCH 0071/1547] Roll Flutter Engine from 2139c8a90822 to bfda8f173fea (2 revisions) (#130321) https://github.com/flutter/engine/compare/2139c8a90822...bfda8f173fea 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from eb1cdb6bd87f to 5c8ed590d4f3 (1 revision) (flutter/engine#43549) 2023-07-11 skia-flutter-autoroll@skia.org Roll Dart SDK from f9d33db51927 to b3e9621a423e (2 revisions) (flutter/engine#43547) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 527feb1b90fde..d81bb5b832436 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2139c8a90822d6dacc129a51fa02672c4e564157 +bfda8f173fea20b3a148a7e4ca6cd14767f9e157 From 476e2d516677c90df211ed5e9a1a39e14329309f Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 11 Jul 2023 12:30:05 +0300 Subject: [PATCH 0072/1547] Add `Badge` widget to `NavigationBar` and `NavigationRail` examples (#129834) fixes [Showcase `Badge` widget in `NavigationBar` and `NavigationRail` examples ](https://github.com/flutter/flutter/issues/129832) | Preview | Preview | Preview | | --------------- | --------------- | --------------- | | | | | --- .../navigation_bar/navigation_bar.0.dart | 105 ++++++++++++++---- .../navigation_rail/navigation_rail.1.dart | 16 ++- .../navigation_bar/navigation_bar.0_test.dart | 34 ++++-- .../navigation_rail.1_test.dart | 20 ++++ 4 files changed, 142 insertions(+), 33 deletions(-) diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.0.dart b/examples/api/lib/material/navigation_bar/navigation_bar.0.dart index b5ff01d313111..5c38b8c1615ed 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.0.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.0.dart @@ -13,7 +13,10 @@ class NavigationBarApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp(home: NavigationExample()); + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const NavigationExample(), + ); } } @@ -29,6 +32,7 @@ class _NavigationExampleState extends State { @override Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); return Scaffold( bottomNavigationBar: NavigationBar( onDestinationSelected: (int index) { @@ -36,7 +40,7 @@ class _NavigationExampleState extends State { currentPageIndex = index; }); }, - indicatorColor: Colors.amber[800], + indicatorColor: Colors.amber, selectedIndex: currentPageIndex, destinations: const [ NavigationDestination( @@ -45,31 +49,94 @@ class _NavigationExampleState extends State { label: 'Home', ), NavigationDestination( - icon: Icon(Icons.business), - label: 'Business', + icon: Badge(child: Icon(Icons.notifications_sharp)), + label: 'Notifications', ), NavigationDestination( - selectedIcon: Icon(Icons.school), - icon: Icon(Icons.school_outlined), - label: 'School', + icon: Badge( + label: Text('2'), + child: Icon(Icons.messenger_sharp), + ), + label: 'Messages', ), ], ), body: [ - Container( - color: Colors.red, - alignment: Alignment.center, - child: const Text('Page 1'), + /// Home page + Card( + shadowColor: Colors.transparent, + margin: const EdgeInsets.all(8.0), + child: SizedBox.expand( + child: Center( + child: Text( + 'Home page', + style: theme.textTheme.titleLarge, + ), + ), + ), ), - Container( - color: Colors.green, - alignment: Alignment.center, - child: const Text('Page 2'), + /// Notifications page + const Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Card( + child: ListTile( + leading: Icon(Icons.notifications_sharp), + title: Text('Notification 1'), + subtitle: Text('This is a notification'), + ), + ), + Card( + child: ListTile( + leading: Icon(Icons.notifications_sharp), + title: Text('Notification 2'), + subtitle: Text('This is a notification'), + ), + ), + ], + ), ), - Container( - color: Colors.blue, - alignment: Alignment.center, - child: const Text('Page 3'), + /// Messages page + ListView.builder( + reverse: true, + itemCount: 2, + itemBuilder: (BuildContext context, int index) { + if (index == 0) { + return Align( + alignment: Alignment.centerRight, + child: Container( + margin: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(8.0), + ), + child: Text( + 'Hello', + style: theme.textTheme.bodyLarge! + .copyWith(color: theme.colorScheme.onPrimary), + ), + ), + ); + } + return Align( + alignment: Alignment.centerLeft, + child: Container( + margin: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(8.0), + ), + child: Text( + 'Hi!', + style: theme.textTheme.bodyLarge! + .copyWith(color: theme.colorScheme.onPrimary), + ), + ), + ); + }, ), ][currentPageIndex], ); diff --git a/examples/api/lib/material/navigation_rail/navigation_rail.1.dart b/examples/api/lib/material/navigation_rail/navigation_rail.1.dart index 812f3341b6941..f3e943736e3cd 100644 --- a/examples/api/lib/material/navigation_rail/navigation_rail.1.dart +++ b/examples/api/lib/material/navigation_rail/navigation_rail.1.dart @@ -14,7 +14,7 @@ class NavigationRailExampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true), + theme: ThemeData(useMaterial3: true), home: const NavRailExample(), ); } @@ -73,13 +73,19 @@ class _NavRailExampleState extends State { label: Text('First'), ), NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.book), + icon: Badge(child: Icon(Icons.bookmark_border)), + selectedIcon: Badge(child: Icon(Icons.book)), label: Text('Second'), ), NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), + icon: Badge( + label: Text('4'), + child: Icon(Icons.star_border), + ), + selectedIcon: Badge( + label: Text('4'), + child: Icon(Icons.star), + ), label: Text('Third'), ), ], diff --git a/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart b/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart index f18598a397cf0..d89d8db5a20b3 100644 --- a/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart +++ b/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart @@ -17,20 +17,36 @@ void main() { /// NavigationDestinations must be rendered expect(find.text('Home'), findsOneWidget); - expect(find.text('Business'), findsOneWidget); - expect(find.text('School'), findsOneWidget); + expect(find.text('Notifications'), findsOneWidget); + expect(find.text('Messages'), findsOneWidget); - /// initial index must be zero + /// Test notification badge. + final Badge notificationBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.notifications_sharp), + matching: find.byType(Badge), + )); + expect(notificationBadge.label, null); + + /// Test messages badge. + final Badge messagesBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.messenger_sharp), + matching: find.byType(Badge), + )); + expect(messagesBadge.label, isNotNull); + + /// Initial index must be zero expect(navigationBarWidget.selectedIndex, 0); + expect(find.text('Home page'), findsOneWidget); - /// switch to second tab - await tester.tap(find.text('Business')); + /// Switch to second tab + await tester.tap(find.text('Notifications')); await tester.pumpAndSettle(); - expect(find.text('Page 2'), findsOneWidget); + expect(find.text('This is a notification'), findsNWidgets(2)); - /// switch to third tab - await tester.tap(find.text('School')); + /// Switch to third tab + await tester.tap(find.text('Messages')); await tester.pumpAndSettle(); - expect(find.text('Page 3'), findsOneWidget); + expect(find.text('Hi!'), findsOneWidget); + expect(find.text('Hello'), findsOneWidget); }); } diff --git a/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart b/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart index 1c3eee14820e0..d3526d4adc430 100644 --- a/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart +++ b/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart @@ -94,4 +94,24 @@ void main() { expect(find.byType(FloatingActionButton), findsOneWidget); expect(find.byType(IconButton), findsOneWidget); }); + + testWidgets('Destinations have badge', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigationRailExampleApp(), + ); + + // Test badge wthout label. + final Badge notificationBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.bookmark_border), + matching: find.byType(Badge), + )); + expect(notificationBadge.label, null); + + // Test badge with label. + final Badge messagesBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.star_border), + matching: find.byType(Badge), + )); + expect(messagesBadge.label, isNotNull); + }); } From 2fb9a3ccdd95ab744b61762a8fce69c862740911 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 07:17:23 -0400 Subject: [PATCH 0073/1547] Roll Flutter Engine from bfda8f173fea to 417c50199e14 (2 revisions) (#130324) https://github.com/flutter/engine/compare/bfda8f173fea...417c50199e14 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 5c8ed590d4f3 to 57cf27703ab7 (1 revision) (flutter/engine#43551) 2023-07-11 flar@google.com remove include of SkPicture files from non-Fuchsia sources (flutter/engine#43542) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d81bb5b832436..b64ece0d2e737 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bfda8f173fea20b3a148a7e4ca6cd14767f9e157 +417c50199e14f5410b3dae2b0cefad7127502b16 From c7da629cbbb910300defa346452b9e094b534701 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 09:34:17 -0400 Subject: [PATCH 0074/1547] Roll Flutter Engine from 417c50199e14 to 5e9f0d61a42a (1 revision) (#130330) https://github.com/flutter/engine/compare/417c50199e14...5e9f0d61a42a 2023-07-11 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from bb8HXP6JZ60Unjk-W... to qVHNy9nU6cQKtR_IB... (flutter/engine#43552) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from bb8HXP6JZ60U to qVHNy9nU6cQK If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b64ece0d2e737..2923dfd8cf8f9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -417c50199e14f5410b3dae2b0cefad7127502b16 +5e9f0d61a42abd72eb7b06959412f907cf26c827 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index a07fc21eacb3a..e10a9cc4a4d73 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -bb8HXP6JZ60Unjk-WW7NnWpF4jfFZ-BUn9KZJQsyhHMC +qVHNy9nU6cQKtR_IB3S0nRZSp5_ln-MkeXGODrfDpTwC From de238b604880fe27cf9017602a37d51378a11c9a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 10:49:26 -0400 Subject: [PATCH 0075/1547] Roll Flutter Engine from 5e9f0d61a42a to d75c70870f86 (1 revision) (#130332) https://github.com/flutter/engine/compare/5e9f0d61a42a...d75c70870f86 2023-07-11 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from cgcxIe8D4wb8hQWCV... to EnRnFf_eyS6SGqpHi... (flutter/engine#43553) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from cgcxIe8D4wb8 to EnRnFf_eyS6S If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2923dfd8cf8f9..58bc5ec64b14d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5e9f0d61a42abd72eb7b06959412f907cf26c827 +d75c70870f868a74d702f582418dd57b8889ecbb diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 90e8f19bf2574..0a0eee1b44dc9 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -cgcxIe8D4wb8hQWCV34gOpkrhylRd-ZTpPHWu8KqG5EC +EnRnFf_eyS6SGqpHiiWpv5xGotfyBLzeeSi85KTGhnwC From 3273182a8e75ab6437e66e57ecbcd55a2e793757 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 11:58:51 -0400 Subject: [PATCH 0076/1547] Roll Flutter Engine from d75c70870f86 to 0011db79d41f (2 revisions) (#130337) https://github.com/flutter/engine/compare/d75c70870f86...0011db79d41f 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from aba52937c5a2 to a788eeaa7ab6 (1 revision) (flutter/engine#43555) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 57cf27703ab7 to aba52937c5a2 (1 revision) (flutter/engine#43554) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 58bc5ec64b14d..8d1a8050153c2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d75c70870f868a74d702f582418dd57b8889ecbb +0011db79d41fe1b0fc2845caf8fdd619f8183141 From 2009f32e53a8360e94fee1287eda44c86ede6be6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 12:48:19 -0400 Subject: [PATCH 0077/1547] Roll Packages from 4469c5e95dd8 to 188a8468f557 (6 revisions) (#130340) https://github.com/flutter/packages/compare/4469c5e95dd8...188a8468f557 2023-07-11 32538273+ValentinVignal@users.noreply.github.com [go_router] Fix some typos in the comments and asserts (flutter/packages#4412) 2023-07-11 tarrinneal@gmail.com [pigeon] `Object` type in class integration tests (flutter/packages#4384) 2023-07-11 49699333+dependabot[bot]@users.noreply.github.com [pigeon]: Bump org.jetbrains.kotlin:kotlin-gradle-plugin from 1.8.22 to 1.9.0 in /packages/pigeon/platform_tests/test_plugin/android (flutter/packages#4419) 2023-07-10 stuartmorgan@google.com [ci] Add initial LUCI legacy analysis (flutter/packages#4428) 2023-07-10 stuartmorgan@google.com [web_benchmarks] Migrate custom test to `custom_package_tests` (flutter/packages#4429) 2023-07-10 goddchen@gmail.com go_router: docs: fix typo in StatefulShellRoute.indexedStack(...) docs (flutter/packages#4341) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index d3e606b04c5c5..476fd631c27d3 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -4469c5e95dd891f7036ecd4cc240cca3c75fdbfe +188a8468f557d1f0dfdf3ab11491b8f36615577d From 12acff81c7e1a54c96c5d518cebbc0ac177cc447 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:08:07 -0700 Subject: [PATCH 0078/1547] `DropdownMenu` can be expanded to its parent size (#129753) Fixes #125199 This PR is to add a new property `expandedInsets` so that the `DropdownMenu` can be expandable and has some margins around.
Example: Setting `expandedInsets` to `EdgeInsets.zero` ```dart import 'package:flutter/material.dart'; void main() => runApp(const DropdownMenuExample()); class DropdownMenuExample extends StatefulWidget { const DropdownMenuExample({super.key}); @override State createState() => _DropdownMenuExampleState(); } class _DropdownMenuExampleState extends State { final TextEditingController colorController = TextEditingController(); ColorLabel? selectedColor; @override Widget build(BuildContext context) { final List> colorEntries = >[]; for (final ColorLabel color in ColorLabel.values) { colorEntries.add( DropdownMenuEntry(value: color, label: color.label, enabled: color.label != 'Grey'), ); } return MaterialApp( theme: ThemeData( useMaterial3: true, colorSchemeSeed: Colors.green, ), home: Scaffold( body: Center( child: Container( width: 500, height: 500, color: Colors.orange, child: DropdownMenu( expandedInsets: EdgeInsets.zero, inputDecorationTheme: const InputDecorationTheme( filled: true, fillColor: Colors.white, border: OutlineInputBorder(), ), controller: colorController, dropdownMenuEntries: colorEntries, onSelected: (ColorLabel? color) { setState(() { selectedColor = color; }); }, // expandedInsets: EdgeInsets.only(left: 35.0, right: 20.0, top: 80), ), ), ), ), ); } } enum ColorLabel { blue('Blue', Colors.blue), pink('Pink', Colors.pink), green('Green', Colors.green), yellow('Yellow', Colors.yellow), grey('Grey', Colors.grey); const ColorLabel(this.label, this.color); final String label; final Color color; } ``` Screenshot 2023-06-28 at 11 33 20 PM
--- .../lib/src/material/dropdown_menu.dart | 203 ++++++++++-------- .../test/material/dropdown_menu_test.dart | 64 ++++++ 2 files changed, 183 insertions(+), 84 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 0d7125d6be56b..4bf3cee5975f0 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -139,6 +139,7 @@ class DropdownMenu extends StatefulWidget { this.initialSelection, this.onSelected, this.requestFocusOnTap, + this.expandedInsets, required this.dropdownMenuEntries, }); @@ -277,6 +278,21 @@ class DropdownMenu extends StatefulWidget { /// contain space for padding. final List> dropdownMenuEntries; + /// Defines the menu text field's width to be equal to its parent's width + /// plus the horizontal width of the specified insets. + /// + /// If this property is null, the width of the text field will be determined + /// by the width of menu items or [DropdownMenu.width]. If this property is not null, + /// the text field's width will match the parent's width plus the specified insets. + /// If the value of this property is [EdgeInsets.zero], the width of the text field will be the same + /// as its parent's width. + /// + /// The [expandedInsets]' top and bottom are ignored, only its left and right + /// properties are used. + /// + /// Defaults to null. + final EdgeInsets? expandedInsets; + @override State> createState() => _DropdownMenuState(); } @@ -549,6 +565,108 @@ class _DropdownMenuState extends State> { final MouseCursor effectiveMouseCursor = canRequestFocus() ? SystemMouseCursors.text : SystemMouseCursors.click; + Widget menuAnchor = MenuAnchor( + style: effectiveMenuStyle, + controller: _controller, + menuChildren: menu, + crossAxisUnconstrained: false, + builder: (BuildContext context, MenuController controller, Widget? child) { + assert(_initialMenu != null); + final Widget trailingButton = Padding( + padding: const EdgeInsets.all(4.0), + child: IconButton( + isSelected: controller.isOpen, + icon: widget.trailingIcon ?? const Icon(Icons.arrow_drop_down), + selectedIcon: widget.selectedTrailingIcon ?? const Icon(Icons.arrow_drop_up), + onPressed: () { + handlePressed(controller); + }, + ), + ); + + final Widget leadingButton = Padding( + padding: const EdgeInsets.all(8.0), + child: widget.leadingIcon ?? const SizedBox() + ); + + final Widget textField = TextField( + key: _anchorKey, + mouseCursor: effectiveMouseCursor, + canRequestFocus: canRequestFocus(), + enableInteractiveSelection: canRequestFocus(), + textAlignVertical: TextAlignVertical.center, + style: effectiveTextStyle, + controller: _textEditingController, + onEditingComplete: () { + if (currentHighlight != null) { + final DropdownMenuEntry entry = filteredEntries[currentHighlight!]; + if (entry.enabled) { + _textEditingController.text = entry.label; + _textEditingController.selection = + TextSelection.collapsed(offset: _textEditingController.text.length); + widget.onSelected?.call(entry.value); + } + } else { + widget.onSelected?.call(null); + } + if (!widget.enableSearch) { + currentHighlight = null; + } + if (_textEditingController.text.isNotEmpty) { + controller.close(); + } + }, + onTap: () { + handlePressed(controller); + }, + onChanged: (String text) { + controller.open(); + setState(() { + filteredEntries = widget.dropdownMenuEntries; + _enableFilter = widget.enableFilter; + }); + }, + decoration: InputDecoration( + enabled: widget.enabled, + label: widget.label, + hintText: widget.hintText, + helperText: widget.helperText, + errorText: widget.errorText, + prefixIcon: widget.leadingIcon != null ? Container( + key: _leadingKey, + child: widget.leadingIcon + ) : null, + suffixIcon: trailingButton, + ).applyDefaults(effectiveInputDecorationTheme) + ); + + if (widget.expandedInsets != null) { + // If [expandedInsets] is not null, the width of the text field should depend + // on its parent width. So we don't need to use `_DropdownMenuBody` to + // calculate the children's width. + return textField; + } + + return _DropdownMenuBody( + width: widget.width, + children: [ + textField, + for (final Widget item in _initialMenu!) item, + trailingButton, + leadingButton, + ], + ); + }, + ); + + if (widget.expandedInsets != null) { + menuAnchor = Container( + alignment: AlignmentDirectional.topStart, + padding: widget.expandedInsets?.copyWith(top: 0.0, bottom: 0.0), + child: menuAnchor, + ); + } + return Shortcuts( shortcuts: _kMenuTraversalShortcuts, child: Actions( @@ -560,90 +678,7 @@ class _DropdownMenuState extends State> { onInvoke: handleDownKeyInvoke, ), }, - child: MenuAnchor( - style: effectiveMenuStyle, - controller: _controller, - menuChildren: menu, - crossAxisUnconstrained: false, - builder: (BuildContext context, MenuController controller, Widget? child) { - assert(_initialMenu != null); - final Widget trailingButton = Padding( - padding: const EdgeInsets.all(4.0), - child: IconButton( - isSelected: controller.isOpen, - icon: widget.trailingIcon ?? const Icon(Icons.arrow_drop_down), - selectedIcon: widget.selectedTrailingIcon ?? const Icon(Icons.arrow_drop_up), - onPressed: () { - handlePressed(controller); - }, - ), - ); - - final Widget leadingButton = Padding( - padding: const EdgeInsets.all(8.0), - child: widget.leadingIcon ?? const SizedBox() - ); - - return _DropdownMenuBody( - width: widget.width, - children: [ - TextField( - key: _anchorKey, - mouseCursor: effectiveMouseCursor, - canRequestFocus: canRequestFocus(), - enableInteractiveSelection: canRequestFocus(), - textAlignVertical: TextAlignVertical.center, - style: effectiveTextStyle, - controller: _textEditingController, - onEditingComplete: () { - if (currentHighlight != null) { - final DropdownMenuEntry entry = filteredEntries[currentHighlight!]; - if (entry.enabled) { - _textEditingController.text = entry.label; - _textEditingController.selection = - TextSelection.collapsed(offset: _textEditingController.text.length); - widget.onSelected?.call(entry.value); - } - } else { - widget.onSelected?.call(null); - } - if (!widget.enableSearch) { - currentHighlight = null; - } - if (_textEditingController.text.isNotEmpty) { - controller.close(); - } - }, - onTap: () { - handlePressed(controller); - }, - onChanged: (String text) { - controller.open(); - setState(() { - filteredEntries = widget.dropdownMenuEntries; - _enableFilter = widget.enableFilter; - }); - }, - decoration: InputDecoration( - enabled: widget.enabled, - label: widget.label, - hintText: widget.hintText, - helperText: widget.helperText, - errorText: widget.errorText, - prefixIcon: widget.leadingIcon != null ? Container( - key: _leadingKey, - child: widget.leadingIcon - ) : null, - suffixIcon: trailingButton, - ).applyDefaults(effectiveInputDecorationTheme) - ), - for (final Widget c in _initialMenu!) c, - trailingButton, - leadingButton, - ], - ); - }, - ), + child: menuAnchor, ), ); } diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 71f05e87ae638..6642efd227863 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -216,6 +216,70 @@ void main() { expect(box.size.width, customWidth); }); + testWidgets('The width of MenuAnchor respects MenuAnchor.expandedInsets', (WidgetTester tester) async { + const double parentWidth = 500.0; + final List> shortMenuItems = >[]; + for (final ShortMenu value in ShortMenu.values) { + final DropdownMenuEntry entry = DropdownMenuEntry(value: value, label: value.label); + shortMenuItems.add(entry); + } + Widget buildMenuAnchor({EdgeInsets? expandedInsets}) { + return MaterialApp( + home: Scaffold( + body: SizedBox( + width: parentWidth, + height: parentWidth, + child: DropdownMenu( + expandedInsets: expandedInsets, + dropdownMenuEntries: shortMenuItems, + ), + ), + ), + ); + } + + // By default, the width of the text field is determined by the menu children. + await tester.pumpWidget(buildMenuAnchor()); + RenderBox box = tester.firstRenderObject(find.byType(TextField)); + expect(box.size.width, 136.0); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + Size buttonSize = tester.getSize(find.widgetWithText(MenuItemButton, 'I0').hitTestable()); + expect(buttonSize.width, 136.0); + + // If expandedInsets is EdgeInsets.zero, the width should be the same as its parent. + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildMenuAnchor(expandedInsets: EdgeInsets.zero)); + box = tester.firstRenderObject(find.byType(TextField)); + expect(box.size.width, parentWidth); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + buttonSize = tester.getSize(find.widgetWithText(MenuItemButton, 'I0')); + expect(buttonSize.width, parentWidth); + + // If expandedInsets is not zero, the width of the text field should be adjusted + // based on the EdgeInsets.left and EdgeInsets.right. The top and bottom values + // will be ignored. + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildMenuAnchor(expandedInsets: const EdgeInsets.only(left: 35.0, top: 50.0, right: 20.0))); + box = tester.firstRenderObject(find.byType(TextField)); + expect(box.size.width, parentWidth - 35.0 - 20.0); + final Rect containerRect = tester.getRect(find.byType(SizedBox).first); + final Rect dropdownMenuRect = tester.getRect(find.byType(TextField)); + expect(dropdownMenuRect.top, containerRect.top); + + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + + buttonSize = tester.getSize(find.widgetWithText(MenuItemButton, 'I0')); + expect(buttonSize.width, parentWidth - 35.0 - 20.0); + }); + testWidgets('The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); From ec2e78e69a8570baf7355d920acbe5f8e75c44da Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Tue, 11 Jul 2023 10:43:18 -0700 Subject: [PATCH 0079/1547] Roll pub packages (#130289) This PR was generated by `flutter update-packages --force-upgrade`. --- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 2ec7a701cc6a3..39c869617dd3a 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: intl: 0.18.1 connectivity: 3.0.6 string_scanner: 1.2.0 - url_launcher: 6.1.11 + url_launcher: 6.1.12 # This is listed as direct so it can be manually pinned url_launcher_android: 6.0.17 cupertino_icons: 1.0.5 @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 4c03 +# PUBSPEC CHECKSUM: 9c04 From f30cd64a16366f7b83f730036e65bafb84816301 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 13:56:08 -0400 Subject: [PATCH 0080/1547] Roll Flutter Engine from 0011db79d41f to 75ada1bdf9fd (2 revisions) (#130345) https://github.com/flutter/engine/compare/0011db79d41f...75ada1bdf9fd 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 1f4ddedd7872 to 68bcc4470230 (4 revisions) (flutter/engine#43557) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from a788eeaa7ab6 to 1f4ddedd7872 (1 revision) (flutter/engine#43556) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8d1a8050153c2..85878a6b63677 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0011db79d41fe1b0fc2845caf8fdd619f8183141 +75ada1bdf9fdbc0ae8d31044bc57b031f64d85ad From e608a697c66a32d440bdb2e07b2b2c24dce7ef79 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 11 Jul 2023 11:19:19 -0700 Subject: [PATCH 0081/1547] Upgrade leak_tracker to 7.0.6. (#130346) --- packages/flutter/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 68b47a6cf26dc..391be87f260a1 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 7.0.4 + leak_tracker: 7.0.6 leak_tracker_testing: 1.0.0 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 32f0 +# PUBSPEC CHECKSUM: 46f2 From 5d4a1f1f5fe1d0d0191c691eb60b6814654d6929 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 14:45:22 -0400 Subject: [PATCH 0082/1547] Roll Flutter Engine from 75ada1bdf9fd to afee1db31e5e (1 revision) (#130349) https://github.com/flutter/engine/compare/75ada1bdf9fd...afee1db31e5e 2023-07-11 dworsham@google.com [fuchsia] Remove FIDL dart references (flutter/engine#43550) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 85878a6b63677..fc81bd1723fbe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -75ada1bdf9fdbc0ae8d31044bc57b031f64d85ad +afee1db31e5e4863e6af863539e585067816f4b6 From 0757165e5906d9861c1ce77ac8d2e1e96f2b2d5b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 15:33:24 -0400 Subject: [PATCH 0083/1547] Roll Flutter Engine from afee1db31e5e to 59f234645dd2 (2 revisions) (#130352) https://github.com/flutter/engine/compare/afee1db31e5e...59f234645dd2 2023-07-11 skia-flutter-autoroll@skia.org Roll Dart SDK from b3e9621a423e to 8b1c04086525 (2 revisions) (flutter/engine#43561) 2023-07-11 dnfield@google.com Delete unused display list/SkPicture code (flutter/engine#43560) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fc81bd1723fbe..f606f2ddadb9c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -afee1db31e5e4863e6af863539e585067816f4b6 +59f234645dd2b6b579d68fd5c2416d170dae2f19 From cc180e214e83406db6ca5d15b4d1cb3c4f0c5f6d Mon Sep 17 00:00:00 2001 From: Tsukuru Tanimichi Date: Wed, 12 Jul 2023 04:57:35 +0900 Subject: [PATCH 0084/1547] Links in `material` library docs are outdated (#129891) https://api.flutter.dev/flutter/material/material-library.html Links in `material` library docs are outdated --- packages/flutter/lib/material.dart | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart index 8ca80a7364088..213bd29d8a42e 100644 --- a/packages/flutter/lib/material.dart +++ b/packages/flutter/lib/material.dart @@ -10,14 +10,10 @@ /// /// See also: /// -/// * [flutter.dev/widgets/material](https://flutter.dev/widgets/material) +/// * [docs.flutter.dev/ui/widgets/material](https://docs.flutter.dev/ui/widgets/material) /// for a catalog of commonly-used Material component widgets. -/// * [material.io/design](https://material.io/design/) -/// for an introduction to Material Design. -/// * [material.io/components](https://material.io/components?platform=flutter) -/// for the Material 2 specification. -/// * [m3.material.io](https://m3.material.io) -/// for the Material 3 specification. +/// * [m3.material.io](https://m3.material.io/) for the Material 3 specification +/// * [m2.material.io](https://m2.material.io/) for the Material 2 specification library material; export 'src/material/about.dart'; From 018fa8c51eeab7f7c98f9cda981931cb5c69db94 Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Tue, 11 Jul 2023 13:04:17 -0700 Subject: [PATCH 0085/1547] Refactor refresh_indicator.1.dart to not use shrinkwrap (#129377) This PR changes the example app into a custom scrollview with three slivers. The middle sliver has a nested scrollview of height 300 and only this nested sliver can trigger the refresh indicator. Fixes https://github.com/flutter/flutter/issues/116237. --- .../refresh_indicator.1.dart | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/examples/api/lib/material/refresh_indicator/refresh_indicator.1.dart b/examples/api/lib/material/refresh_indicator/refresh_indicator.1.dart index aec46093c8e84..c389d404ab762 100644 --- a/examples/api/lib/material/refresh_indicator/refresh_indicator.1.dart +++ b/examples/api/lib/material/refresh_indicator/refresh_indicator.1.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; /// Flutter code sample for [RefreshIndicator]. @@ -13,8 +14,9 @@ class RefreshIndicatorExampleApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( - home: RefreshIndicatorExample(), + return MaterialApp( + scrollBehavior: const MaterialScrollBehavior().copyWith(dragDevices: PointerDeviceKind.values.toSet()), + home: const RefreshIndicatorExample(), ); } } @@ -40,17 +42,17 @@ class RefreshIndicatorExample extends StatelessWidget { // from the widget's children. // // By default this is set to `notification.depth == 0`, which ensures - // the only the scroll notifications from the first child are listened to. + // the only the scroll notifications from the first scroll view are listened to. // // Here setting `notification.depth == 1` triggers the refresh indicator // when overscrolling the nested scroll view. notificationPredicate: (ScrollNotification notification) { return notification.depth == 1; }, - child: SingleChildScrollView( - child: Column( - children: [ - Container( + child: CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: Container( height: 100, alignment: Alignment.center, color: Colors.pink[100], @@ -65,10 +67,12 @@ class RefreshIndicatorExample extends StatelessWidget { ], ), ), - Container( + ), + SliverToBoxAdapter( + child: Container( color: Colors.green[100], + height: 300, child: ListView.builder( - shrinkWrap: true, itemCount: 25, itemBuilder: (BuildContext context, int index) { return const ListTile( @@ -78,8 +82,17 @@ class RefreshIndicatorExample extends StatelessWidget { }, ), ), - ], - ), + ), + SliverList.builder( + itemCount: 20, + itemBuilder: (BuildContext context, int index) { + return const ListTile( + title: Text('Pull down here'), + subtitle: Text("Refresh indicator won't trigger"), + ); + } + ) + ], ), ), ); From e12167d98c44ad1977934399757a4351821f4f95 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 17:29:21 -0400 Subject: [PATCH 0086/1547] Roll Flutter Engine from 59f234645dd2 to e2df01610fb3 (3 revisions) (#130357) https://github.com/flutter/engine/compare/59f234645dd2...e2df01610fb3 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 68bcc4470230 to 47a37395ee40 (12 revisions) (flutter/engine#43568) 2023-07-11 dnfield@google.com Remove stray semicolons from embedded_views.cc (flutter/engine#43566) 2023-07-11 bdero@google.com [Impeller] Apply color filters on the CPU for solid colors & gradients. (flutter/engine#43519) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f606f2ddadb9c..d2220cd4ef201 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -59f234645dd2b6b579d68fd5c2416d170dae2f19 +e2df01610fb3ca080c7fd31a5bbfe1bd3c5c8227 From 233a1bb3165f1509741ed60e43b80fefc5b563a8 Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Tue, 11 Jul 2023 15:37:31 -0700 Subject: [PATCH 0087/1547] autocomplete: Remove mistaken paragraph in `onSelected` doc (#130190) Fixes #130187. Fixes #130187 by removing the mistaken paragraph; see there for details. --- packages/flutter/lib/src/widgets/autocomplete.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index c5171ae50eba1..c46d65d621234 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -244,10 +244,6 @@ class RawAutocomplete extends StatefulWidget { /// {@template flutter.widgets.RawAutocomplete.onSelected} /// Called when an option is selected by the user. - /// - /// Any [TextEditingController] listeners will not be called when the user - /// selects an option, even though the field will update with the selected - /// value, so use this to be informed of selection. /// {@endtemplate} final AutocompleteOnSelected? onSelected; From c94e6766fd4ed376293bf026ee241ae75fd358e1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 18:44:05 -0400 Subject: [PATCH 0088/1547] Roll Flutter Engine from e2df01610fb3 to 875d87e02276 (3 revisions) (#130359) https://github.com/flutter/engine/compare/e2df01610fb3...875d87e02276 2023-07-11 chinmaygarde@google.com [Impeller] Fix WRITE_AFTER_WRITE hazard in ColorWheel/Vulkan. (flutter/engine#43570) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 47a37395ee40 to d2051446ee6b (4 revisions) (flutter/engine#43569) 2023-07-11 gwen.mittertreiner@gmail.com [fuchsia][cml] Mark Tracing as Optional (flutter/engine#43567) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d2220cd4ef201..67fbce345c4b0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e2df01610fb3ca080c7fd31a5bbfe1bd3c5c8227 +875d87e02276c17d8224953bf72e1a93b07a5679 From 4e8014bf76c14759b35353565075ab55d263c268 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 11 Jul 2023 17:41:14 -0700 Subject: [PATCH 0089/1547] Enable not GCed leak tracking. (#130159) --- .../test/foundation/leak_tracking.dart | 10 +---- .../test/foundation/leak_tracking_test.dart | 39 ++++++++++++------- .../flutter/test/material/about_test.dart | 20 +++++++++- .../test/widgets/widget_inspector_test.dart | 29 ++------------ 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/packages/flutter/test/foundation/leak_tracking.dart b/packages/flutter/test/foundation/leak_tracking.dart index 26a3dbd7a0bac..37b169cda0450 100644 --- a/packages/flutter/test/foundation/leak_tracking.dart +++ b/packages/flutter/test/foundation/leak_tracking.dart @@ -54,13 +54,13 @@ void testWidgetsWithLeakTracking( bool semanticsEnabled = true, TestVariant variant = const DefaultTestVariant(), dynamic tags, - LeakTrackingTestConfig leakTrackingConfig = const LeakTrackingTestConfig(), + LeakTrackingTestConfig leakTrackingTestConfig = const LeakTrackingTestConfig(), }) { Future wrappedCallback(WidgetTester tester) async { await _withFlutterLeakTracking( () async => callback(tester), tester, - leakTrackingConfig, + leakTrackingTestConfig, ); } @@ -169,12 +169,6 @@ class LeakCleaner { /// Returns true if [leak] should be reported as failure. bool _shouldReportLeak(LeakType leakType, LeakReport leak, Map<(String, LeakType), int> countByClassAndType) { - // Tracking for non-GCed is temporarily disabled. - // TODO(polina-c): turn on tracking for non-GCed after investigating existing leaks. - if (leakType != LeakType.notDisposed) { - return false; - } - final String leakingClass = leak.type; final (String, LeakType) classAndType = (leakingClass, leakType); diff --git a/packages/flutter/test/foundation/leak_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test.dart index fc71814d260ff..e9a66480c0188 100644 --- a/packages/flutter/test/foundation/leak_tracking_test.dart +++ b/packages/flutter/test/foundation/leak_tracking_test.dart @@ -18,7 +18,7 @@ Leaks _leaksOfAllTypes() => Leaks(> { }); Future main() async { - test('Trivial $LeakCleaner returns only non-disposed leaks.', () { + test('Trivial $LeakCleaner returns all leaks.', () { final LeakCleaner leakCleaner = LeakCleaner(const LeakTrackingTestConfig()); final Leaks leaks = _leaksOfAllTypes(); final int leakTotal = leaks.total; @@ -26,7 +26,7 @@ Future main() async { final Leaks cleanedLeaks = leakCleaner.clean(leaks); expect(leaks.total, leakTotal); - expect(cleanedLeaks.total, 1); + expect(cleanedLeaks.total, 3); }); test('$LeakCleaner catches extra leaks', () { @@ -48,7 +48,7 @@ Future main() async { (WidgetTester tester) async { await tester.pumpWidget(_StatelessLeakingWidget()); }, - leakTrackingConfig: LeakTrackingTestConfig( + leakTrackingTestConfig: LeakTrackingTestConfig( notDisposedAllowList: {_leakTrackedClassName: null}, notGCedAllowList: {_leakTrackedClassName: null}, ), @@ -59,7 +59,7 @@ Future main() async { (WidgetTester tester) async { await tester.pumpWidget(_StatelessLeakingWidget()); }, - leakTrackingConfig: LeakTrackingTestConfig( + leakTrackingTestConfig: LeakTrackingTestConfig( notDisposedAllowList: {_leakTrackedClassName: 1}, notGCedAllowList: {_leakTrackedClassName: 1}, ), @@ -76,7 +76,7 @@ Future main() async { await tester.pumpWidget(_StatelessLeakingWidget()); await tester.pumpWidget(_StatelessLeakingWidget()); }, - leakTrackingConfig: LeakTrackingTestConfig( + leakTrackingTestConfig: LeakTrackingTestConfig( onLeaks: (Leaks theLeaks) { leaks = theLeaks; }, @@ -85,7 +85,7 @@ Future main() async { ), ); - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 2)); + tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 2, expectedNotGCed: 2, shouldContainDebugInfo: false)); }); group('respects notGCed allow lists', () { @@ -98,7 +98,7 @@ Future main() async { (WidgetTester tester) async { await tester.pumpWidget(_StatelessLeakingWidget()); }, - leakTrackingConfig: LeakTrackingTestConfig( + leakTrackingTestConfig: LeakTrackingTestConfig( onLeaks: (Leaks theLeaks) { leaks = theLeaks; }, @@ -107,7 +107,7 @@ Future main() async { ), ); - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1)); + tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, shouldContainDebugInfo: false)); }); group('catches that', () { @@ -120,7 +120,7 @@ Future main() async { (WidgetTester tester) async { await tester.pumpWidget(_StatelessLeakingWidget()); }, - leakTrackingConfig: LeakTrackingTestConfig( + leakTrackingTestConfig: LeakTrackingTestConfig( onLeaks: (Leaks theLeaks) { leaks = theLeaks; }, @@ -128,7 +128,7 @@ Future main() async { ), ); - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1)); + tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, expectedNotGCed: 1, shouldContainDebugInfo: false)); }); }, skip: isBrowser); // [intended] Leak detection is off for web. @@ -140,7 +140,12 @@ Future main() async { } /// Verifies [leaks] contains expected number of leaks for [_LeakTrackedClass]. -void _verifyLeaks(Leaks leaks, { int expectedNotDisposed = 0, int expectedNotGCed = 0 }) { +void _verifyLeaks( + Leaks leaks, { + int expectedNotDisposed = 0, + int expectedNotGCed = 0, + required bool shouldContainDebugInfo, +}) { const String linkToLeakTracker = 'https://github.com/dart-lang/leak_tracker'; expect( @@ -152,14 +157,20 @@ void _verifyLeaks(Leaks leaks, { int expectedNotDisposed = 0, int expectedNotGC ), ); - _verifyLeakList(leaks.notDisposed, expectedNotDisposed); - _verifyLeakList(leaks.notGCed, expectedNotGCed); + _verifyLeakList(leaks.notDisposed, expectedNotDisposed, shouldContainDebugInfo); + _verifyLeakList(leaks.notGCed, expectedNotGCed, shouldContainDebugInfo); } -void _verifyLeakList(List list, int expectedCount){ +void _verifyLeakList(List list, int expectedCount, bool shouldContainDebugInfo){ expect(list.length, expectedCount); for (final LeakReport leak in list) { + if (shouldContainDebugInfo) { + expect(leak.context, isNotEmpty); + } else { + expect(leak.context ?? {}, isEmpty); + } + expect(leak.trackedClass, contains(_LeakTrackedClass.library)); expect(leak.trackedClass, contains(_leakTrackedClassName)); } diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 29cfdf5a372b4..3c15de4ebb5de 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -201,7 +201,15 @@ void main() { await tester.tap(find.text('Another package')); await tester.pumpAndSettle(); expect(find.text('Another license'), findsOneWidget); - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130354 + notGCedAllowList: { + 'ValueNotifier<_OverlayEntryWidgetState?>':2, + 'ValueNotifier': 1, + }, + )); testWidgetsWithLeakTracking('LicensePage control test with all properties', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); @@ -278,7 +286,15 @@ void main() { await tester.tap(find.text('Another package')); await tester.pumpAndSettle(); expect(find.text('Another license'), findsOneWidget); - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130354 + notGCedAllowList: { + 'ValueNotifier<_OverlayEntryWidgetState?>':2, + 'ValueNotifier': 1, + }, + )); testWidgetsWithLeakTracking('_PackageLicensePage title style without AppBarTheme', (WidgetTester tester) async { LicenseRegistry.addLicense(() { diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 9f18ec163069a..a75293e832515 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -10,7 +10,6 @@ library; import 'dart:convert'; -import 'dart:developer'; import 'dart:math'; import 'dart:ui' as ui; @@ -20,6 +19,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker/leak_tracker.dart'; import 'widget_inspector_test_utils.dart'; @@ -241,29 +241,6 @@ extension TextFromString on String { } } -/// Forces garbage collection by aggressive memory allocation. -/// -/// Copied from internal code of -/// https://github.com/dart-lang/leak_tracker -Future _forceGC() async { - const int gcCycles = 3; // 1 should be enough, but we do 3 to make sure test is not flaky. - final int barrier = reachabilityBarrier; - - final List> storage = >[]; - - void allocateMemory() { - storage.add(Iterable.generate(10000, (_) => DateTime.now()).toList()); - if (storage.length > 100) { - storage.removeAt(0); - } - } - - while (reachabilityBarrier < barrier + gcCycles) { - await Future.delayed(Duration.zero); - allocateMemory(); - } -} - final List _weakValueTests = [1, 1.0, 'hello', true, false, Object(), [3, 4], DateTime(2023)]; void main() { @@ -331,7 +308,9 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { final WeakReference ref = WeakReference(someObject); someObject = null; - await _forceGC(); + + // 1 should be enough for [fullGcCycles], but it is 3 to make sure tests are not flaky. + await forceGC(fullGcCycles: 3); expect(ref.target, null); }); From c8906bbd49424b9b8a3425064848954262b5acf1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 20:55:18 -0400 Subject: [PATCH 0090/1547] Roll Flutter Engine from 875d87e02276 to d00590fde18c (5 revisions) (#130369) https://github.com/flutter/engine/compare/875d87e02276...d00590fde18c 2023-07-11 jason-simmons@users.noreply.github.com Release the mutex in the CanCreateConcurrentMessageLoop test before waking the latch (flutter/engine#43574) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from 2998197ce4ca to c769464a8b79 (2 revisions) (flutter/engine#43577) 2023-07-11 zanderso@users.noreply.github.com Run linux_unopt on a machine with more cores (flutter/engine#43473) 2023-07-11 skia-flutter-autoroll@skia.org Roll Skia from d2051446ee6b to 2998197ce4ca (1 revision) (flutter/engine#43572) 2023-07-11 skia-flutter-autoroll@skia.org Roll Dart SDK from 8b1c04086525 to 551915bf6ebe (1 revision) (flutter/engine#43571) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 67fbce345c4b0..505930c96b6dc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -875d87e02276c17d8224953bf72e1a93b07a5679 +d00590fde18c5286e23cdb630b59ec2a65d50ff4 From d77f918f8eaff6009d5b2e52f0f8529798db2de5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 11 Jul 2023 22:02:03 -0400 Subject: [PATCH 0091/1547] Roll Flutter Engine from d00590fde18c to e109a3c0c347 (1 revision) (#130371) https://github.com/flutter/engine/compare/d00590fde18c...e109a3c0c347 2023-07-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from qVHNy9nU6cQKtR_IB... to LV7zVdnjfEPukVG8L... (flutter/engine#43580) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from qVHNy9nU6cQK to LV7zVdnjfEPu If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 505930c96b6dc..080d774bf9488 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d00590fde18c5286e23cdb630b59ec2a65d50ff4 +e109a3c0c347aa9538b007f1cf04e5ceee30c1f0 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index e10a9cc4a4d73..70e5b1948594c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -qVHNy9nU6cQKtR_IB3S0nRZSp5_ln-MkeXGODrfDpTwC +LV7zVdnjfEPukVG8LxpHU5U44yd48wLv8LSCvKKgAFcC From 1d30e3e4fb0480d05f0c0312f208ab3e59ed5549 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 02:05:57 -0400 Subject: [PATCH 0092/1547] Roll Flutter Engine from e109a3c0c347 to 1b44d7ee1a60 (3 revisions) (#130380) https://github.com/flutter/engine/compare/e109a3c0c347...1b44d7ee1a60 2023-07-12 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from EnRnFf_eyS6SGqpHi... to zTuZjXzI3bqscWmeo... (flutter/engine#43583) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from c769464a8b79 to d0ecba6d753c (2 revisions) (flutter/engine#43582) 2023-07-12 skia-flutter-autoroll@skia.org Roll Dart SDK from 551915bf6ebe to 51d6128b190e (1 revision) (flutter/engine#43581) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from EnRnFf_eyS6S to zTuZjXzI3bqs If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 080d774bf9488..cd112fe27a024 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e109a3c0c347aa9538b007f1cf04e5ceee30c1f0 +1b44d7ee1a609cb9743940431704f5f1a50653e5 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 0a0eee1b44dc9..6b18f4b0615ba 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -EnRnFf_eyS6SGqpHiiWpv5xGotfyBLzeeSi85KTGhnwC +zTuZjXzI3bqscWmeoUECcqUfjZ-n7qt4XIGtOMS5TDgC From 10189d1a30511190378c87d6bca83c7410591e7b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 02:58:09 -0400 Subject: [PATCH 0093/1547] Roll Flutter Engine from 1b44d7ee1a60 to 7de68c62742d (4 revisions) (#130384) https://github.com/flutter/engine/compare/1b44d7ee1a60...7de68c62742d 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 7b0d85cff28a to 33cfa4fc2aeb (1 revision) (flutter/engine#43586) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from d0ecba6d753c to 7b0d85cff28a (1 revision) (flutter/engine#43585) 2023-07-12 chinmaygarde@google.com [Impeller] Remove un-actionable info log about validations. (flutter/engine#43575) 2023-07-12 chinmaygarde@google.com [Impeller] Create a resource manager that batch deallocates resources on a dedicated thread. (flutter/engine#43579) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cd112fe27a024..4e75524cc35c6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1b44d7ee1a609cb9743940431704f5f1a50653e5 +7de68c62742de8d98bf29f4af605685eb6e5b4ef From fd720fab03dd947d1948e1eab1a0b4b22aecaa15 Mon Sep 17 00:00:00 2001 From: huycozy <104349824+huycozy@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:47:05 +0700 Subject: [PATCH 0094/1547] Make new issue template for 1P package (#130065) Closes https://github.com/flutter/flutter/issues/117750. ### Demo
Preview screenshot ![screenshot](https://github.com/flutter/flutter/assets/104349824/40968935-b898-4303-b3ee-08abed94f6eb)
Demo issue template: [Report a bug in Flutter's first party package](https://github.com/huycozy/flutter/issues/new?assignees=&labels=&projects=&template=9_first_party_packages.yml) Demo a filed issue: https://github.com/huycozy/flutter/issues/2 --- .../ISSUE_TEMPLATE/9_first_party_packages.yml | 222 ++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/9_first_party_packages.yml diff --git a/.github/ISSUE_TEMPLATE/9_first_party_packages.yml b/.github/ISSUE_TEMPLATE/9_first_party_packages.yml new file mode 100644 index 0000000000000..0e8ef8ab04b92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/9_first_party_packages.yml @@ -0,0 +1,222 @@ +name: Report a bug in one of Flutter's first-party packages +description: | + You found a bug in one of Flutter's first-party packages. +body: + - type: markdown + attributes: + value: | + Thank you for using Flutter! + + If you are looking for support, please check out our documentation + or consider asking a question on Stack Overflow: + + - https://flutter.dev/ + - https://api.flutter.dev/ + - https://stackoverflow.com/questions/tagged/flutter?sort=frequent + - type: checkboxes + attributes: + label: Is there an existing issue for this? + options: + - label: I have searched the [existing package issues](https://github.com/flutter/flutter/issues?q=is%3Aopen+is%3Aissue+label%3Apackage) + required: true + - label: I have read the [guide to filing a bug](https://flutter.dev/docs/resources/bug-reports) + required: true + - type: dropdown + id: packages + attributes: + label: What package does this bug report belong to? + description: | + If the package you are reporting a bug for is not listed here, + it could be a third party package's issue. + In that case, you should report the issue to the package's developers. + options: + - animations + - camera + - cross_file + - css_colors + - dynamic_layouts + - espresso + - extension_google_sign_in_as_googleapis_auth + - file_selector + - flutter_adaptive_scaffold + - flutter_image + - flutter_lints + - flutter_markdown + - flutter_migrate + - flutter_plugin_android_lifecycle + - flutter_template_images + - go_router + - go_router_builder + - google_identity_services_web + - google_maps_flutter + - google_sign_in + - image_picker + - in_app_purchase + - ios_platform_images + - local_auth + - metrics_center + - multicast_dns + - palette_generator + - path_provider + - pigeon + - plugin_platform_interface + - pointer_interceptor + - quick_actions + - rfw + - shared_preferences + - standard_message_codec + - url_launcher + - video_player + - web_benchmarks + - webview_flutter + - xdg_directories + validations: + required: true + - type: dropdown + id: target_platforms + attributes: + label: What target platforms are you seeing this bug on? + description: Have you confirmed that package supports the platform you are reporting against? + multiple: true + options: + - Android + - iOS + - Web + - macOS + - Linux + - Windows + validations: + required: true + - type: dropdown + id: pub_upgrade + attributes: + label: Have you already upgraded your packages? + description: | + Please check if the issue still persists or not after running `flutter pub upgrade`. + options: + - "Yes" + - "No" + validations: + required: true + - type: textarea + attributes: + label: Dependency versions + description: | + `pubspec.lock` file content that includes the package and its dependencies. + + You can remove private dependencies from the file if they are sensitive. + + If the file is too large to be uploaded to GitHub or the content is too long, + you may use online tools like https://pastebin.com and share the url here. + + Note: Please do not upload screenshots of text. Instead, use code blocks + or the above mentioned ways to upload this. + value: | +
pubspec.lock + + ```lock + [Paste file content here] + ``` + +
+ - type: textarea + attributes: + label: Steps to reproduce + description: Please tell us exactly how to reproduce the problem you are running into. + placeholder: | + 1. ... + 2. ... + 3. ... + validations: + required: true + - type: textarea + attributes: + label: Expected results + description: Please tell us what is expected to happen. + validations: + required: true + - type: textarea + attributes: + label: Actual results + description: Please tell us what is actually happening. + validations: + required: true + - type: textarea + attributes: + label: Code sample + description: | + Please create a minimal reproducible sample that shows the problem + and attach it below between the lines with the backticks. + + To create it, use the `flutter create bug` command and update the `main.dart` file. + + Alternatively, you can create a public GitHub repository to share your sample. + + Without this we will unlikely be able to progress on the issue, and because of that + we regretfully will have to close it. + + You can also refer to the package's example project if it is simple enough + to reproduce the bug. + + Note: Please do not upload screenshots of text. Instead, use code blocks + or the above mentioned ways to upload your code sample. + value: | +
Code sample + + ```dart + [Paste your code here] + ``` + +
+ validations: + required: true + - type: textarea + attributes: + label: Screenshots or Videos + description: | + Upload any screenshots or videos of the bug if applicable. + value: | +
+ Screenshots / Video demonstration + + [Upload media here] + +
+ - type: textarea + attributes: + label: Logs + description: | + Include the full logs of the commands you are running between the lines + with the backticks below. If you are running any `flutter` commands, + please include the output of running them with `--verbose`; for example, + the output of running `flutter --verbose create foo`. + + If the logs are too large to be uploaded to GitHub, you may upload + them as a `txt` file or use online tools like https://pastebin.com to + share it. + + Note: Please do not upload screenshots of text. Instead, use code blocks + or the above mentioned ways to upload logs. + value: | +
Logs + + ```console + [Paste your logs here] + ``` + +
+ - type: textarea + attributes: + label: Flutter Doctor output + description: | + Please provide the full output of running `flutter doctor -v` + value: | +
Doctor output + + ```console + [Paste your output here] + ``` + +
+ validations: + required: true From 7decd77d0e41eb00b1299949358f5a2b2e11dcb1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 04:39:13 -0400 Subject: [PATCH 0095/1547] Roll Flutter Engine from 7de68c62742d to 3482e05776a7 (2 revisions) (#130390) https://github.com/flutter/engine/compare/7de68c62742d...3482e05776a7 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from af2a829258a0 to 0ac60b2cecfe (2 revisions) (flutter/engine#43592) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 33cfa4fc2aeb to af2a829258a0 (1 revision) (flutter/engine#43591) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4e75524cc35c6..736baee77c844 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7de68c62742de8d98bf29f4af605685eb6e5b4ef +3482e05776a7d8f6e62fa751e202661942980da4 From 485e79dea721d35ce6ef9f985442d2a3bd746095 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 05:31:36 -0400 Subject: [PATCH 0096/1547] Roll Flutter Engine from 3482e05776a7 to 29c5c41eeb19 (1 revision) (#130393) https://github.com/flutter/engine/compare/3482e05776a7...29c5c41eeb19 2023-07-12 skia-flutter-autoroll@skia.org Roll Dart SDK from 51d6128b190e to b95f6531c726 (2 revisions) (flutter/engine#43594) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 736baee77c844..497216b0c9911 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3482e05776a7d8f6e62fa751e202661942980da4 +29c5c41eeb190ac0dc44c9135ac04ec1f227815a From ac8e8027bd429d549e468bc71b3729639de40d40 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 06:16:25 -0400 Subject: [PATCH 0097/1547] Roll Flutter Engine from 29c5c41eeb19 to 73093fdd77c3 (2 revisions) (#130398) https://github.com/flutter/engine/compare/29c5c41eeb19...73093fdd77c3 2023-07-12 flar@google.com header file cleanup focusing on removing unnecessary SkPicture includes (flutter/engine#43589) 2023-07-12 bdero@google.com [Impeller] Document ColorSourceContents (flutter/engine#43590) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 497216b0c9911..cefa7cb5db6d0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -29c5c41eeb190ac0dc44c9135ac04ec1f227815a +73093fdd77c3f4816c535de4aa7ae8d5e45b6c05 From 1a14dda88c9bfbba5f7907d64dd5299b60a30284 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 06:58:05 -0400 Subject: [PATCH 0098/1547] Roll Flutter Engine from 73093fdd77c3 to 3dbe7dbeb5d4 (1 revision) (#130399) https://github.com/flutter/engine/compare/73093fdd77c3...3dbe7dbeb5d4 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 0ac60b2cecfe to 0fb595ccc6a7 (1 revision) (flutter/engine#43596) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cefa7cb5db6d0..6df6cae258f27 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -73093fdd77c3f4816c535de4aa7ae8d5e45b6c05 +3dbe7dbeb5d46bef5a151d21b14612a9eb520965 From 1d50000a10c2cf816b458938e6ce2855702a871e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 08:45:25 -0400 Subject: [PATCH 0099/1547] Roll Flutter Engine from 3dbe7dbeb5d4 to c7317a58466e (1 revision) (#130402) https://github.com/flutter/engine/compare/3dbe7dbeb5d4...c7317a58466e 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 0fb595ccc6a7 to 6a8be5964fbe (1 revision) (flutter/engine#43597) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6df6cae258f27..891de7ffdd794 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3dbe7dbeb5d46bef5a151d21b14612a9eb520965 +c7317a58466e938ea39907b3737c1f37a354832f From ba6009bccacbaa2b17d70fa211cebedf57ba7eae Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 10:18:07 -0400 Subject: [PATCH 0100/1547] Roll Flutter Engine from c7317a58466e to d68ea304eeda (1 revision) (#130410) https://github.com/flutter/engine/compare/c7317a58466e...d68ea304eeda 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 6a8be5964fbe to 9038aec6a23a (1 revision) (flutter/engine#43598) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 891de7ffdd794..8f6e9d995cfdc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c7317a58466e938ea39907b3737c1f37a354832f +d68ea304eeda0519981cd2850153e19d5f517c5d From 21fa18b3fedeb0ba51a5e4ac94f53f3bd0493fbc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 11:08:00 -0400 Subject: [PATCH 0101/1547] Roll Flutter Engine from d68ea304eeda to 5c887028810d (2 revisions) (#130413) https://github.com/flutter/engine/compare/d68ea304eeda...5c887028810d 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 9038aec6a23a to ac4c113c071d (1 revision) (flutter/engine#43600) 2023-07-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from LV7zVdnjfEPukVG8L... to 0fvk838jTDNQ_l43k... (flutter/engine#43599) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from LV7zVdnjfEPu to 0fvk838jTDNQ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8f6e9d995cfdc..51d4168538672 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d68ea304eeda0519981cd2850153e19d5f517c5d +5c887028810d55e3acdfc6582009e46363fbe699 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 70e5b1948594c..3ee92df67e9eb 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -LV7zVdnjfEPukVG8LxpHU5U44yd48wLv8LSCvKKgAFcC +0fvk838jTDNQ_l43kj5Vz-3ZA1JntonkaLZ8UJxQSaUC From 21e3bb89676c0eb1a86aba9aa3398f32fe02f2d3 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 12 Jul 2023 18:47:51 +0300 Subject: [PATCH 0102/1547] Update `RadioListTile` tests format for M2/M3 (#130391) Update tests format context: https://github.com/flutter/flutter/pull/129718#issuecomment-1615124857 --- packages/flutter/test/material/radio_list_tile_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/flutter/test/material/radio_list_tile_test.dart b/packages/flutter/test/material/radio_list_tile_test.dart index 9e0cba869a568..b5c555083c5b8 100644 --- a/packages/flutter/test/material/radio_list_tile_test.dart +++ b/packages/flutter/test/material/radio_list_tile_test.dart @@ -1012,7 +1012,7 @@ void main() { ); }); - testWidgets('RadioListTile respects hoverColor', (WidgetTester tester) async { + testWidgets('Material3 - RadioListTile respects hoverColor', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; final Color? hoverColor = Colors.orange[500]; @@ -1078,7 +1078,7 @@ void main() { ); }); - testWidgets('RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgets('Material3 - RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -1339,7 +1339,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgets('Material2 - RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -1443,7 +1443,7 @@ void main() { ); }); - testWidgets('RadioListTile respects hoverColor', (WidgetTester tester) async { + testWidgets('Material2 - RadioListTile respects hoverColor', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; final Color? hoverColor = Colors.orange[500]; From 544d30dbaddf17edbed6cbc52c8877482497e049 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 12:23:19 -0400 Subject: [PATCH 0103/1547] Roll Packages from 188a8468f557 to 250871431bed (14 revisions) (#130418) https://github.com/flutter/packages/compare/188a8468f557...250871431bed 2023-07-12 39314023+wer-mathurin@users.noreply.github.com ADD appBarBreakpoint (flutter/packages#4434) 2023-07-12 engine-flutter-autoroll@skia.org Roll Flutter from 65ff3cb9b45c to 3ec96a8a4a5d (5 revisions) (flutter/packages#4415) 2023-07-12 tarrinneal@gmail.com [image_picker] Roll dependancies to avoid error (flutter/packages#4431) 2023-07-12 49699333+dependabot[bot]@users.noreply.github.com [in_app_pur]: Bump com.android.billingclient:billing from 6.0.0 to 6.0.1 in /packages/in_app_purchase/in_app_purchase_android/android (flutter/packages#4422) 2023-07-12 ditman@gmail.com [file_selector] Avoids using path_provider in web example app. (flutter/packages#4445) 2023-07-12 ian@hixie.ch [rfw] Add some more documentation for RFW (flutter/packages#4349) 2023-07-12 stuartmorgan@google.com [ci] Enable LUCI legacy analysis (flutter/packages#4435) 2023-07-11 ian@hixie.ch [webview_flutter_wkwebview] NSError.toString (flutter/packages#4441) 2023-07-11 stuartmorgan@google.com [ci] Remove unused Chromium setup (flutter/packages#4437) 2023-07-11 ian@hixie.ch [flutter_plugin_tools] Reimplements the excerpt system inline in the tool, rather than relying on a separate package. (flutter/packages#4417) 2023-07-11 10687576+bparrishMines@users.noreply.github.com [ci] Remove webview_flutter implementation opt outs for custom analysis (flutter/packages#4438) 2023-07-11 stuartmorgan@google.com [palette_generator] Add web support to unit tests (flutter/packages#4440) 2023-07-11 stuartmorgan@google.com [tool] Conditionalize color on `stdout` (flutter/packages#4436) 2023-07-11 47866232+chunhtai@users.noreply.github.com [go_router_builder] Cleans up builder code. (flutter/packages#4356) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 476fd631c27d3..6dd2b6dcc8cb7 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -188a8468f557d1f0dfdf3ab11491b8f36615577d +250871431bedcfab9ca38b8a5170ab8761810f64 From 58acd6099eb470440ef8824f6ff87da6a107241a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 13:13:25 -0400 Subject: [PATCH 0104/1547] Roll Flutter Engine from 5c887028810d to 16e2ab7e986c (2 revisions) (#130421) https://github.com/flutter/engine/compare/5c887028810d...16e2ab7e986c 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from ac4c113c071d to ebc149cff431 (4 revisions) (flutter/engine#43603) 2023-07-12 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from zTuZjXzI3bqscWmeo... to 1STsUj0X5YgpiSNEb... (flutter/engine#43602) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from zTuZjXzI3bqs to 1STsUj0X5Ygp If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 51d4168538672..2fe5c0f372fc1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5c887028810d55e3acdfc6582009e46363fbe699 +16e2ab7e986c8c7ad2a704245df48ca96ea90948 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 6b18f4b0615ba..1fa79f23e439a 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -zTuZjXzI3bqscWmeoUECcqUfjZ-n7qt4XIGtOMS5TDgC +1STsUj0X5YgpiSNEbqRCus0XRGJ-uLoTCxmjIVMy_EoC From 42924e275bab76325563d87dea54233db14f6ba1 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 12 Jul 2023 20:25:20 +0300 Subject: [PATCH 0105/1547] Update `Divider`/`VerticalDivider` and theme tests for M2/M3 (#130415) Updated unit tests for `Divider`/ `VerticalDivider` and theme to have M2 and M3 versions. More info in https://github.com/flutter/flutter/pull/128725 --- .../flutter/test/material/divider_test.dart | 78 ++++++++++--------- .../test/material/divider_theme_test.dart | 20 ++--- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/packages/flutter/test/material/divider_test.dart b/packages/flutter/test/material/divider_test.dart index 7136767808305..127af32dbaff3 100644 --- a/packages/flutter/test/material/divider_test.dart +++ b/packages/flutter/test/material/divider_test.dart @@ -4,16 +4,29 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; + import '../rendering/mock_canvas.dart'; void main() { - testWidgets('Divider control test', (WidgetTester tester) async { + testWidgets('Material3 - Divider control test', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Center(child: Divider()), + ), + ); + final RenderBox box = tester.firstRenderObject(find.byType(Divider)); + expect(box.size.height, 16.0); + final Container container = tester.widget(find.byType(Container)); + final BoxDecoration decoration = container.decoration! as BoxDecoration; + expect(decoration.border!.bottom.width, 1.0); + }); + + testWidgets('Material2 - Divider control test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), - home: const Center( - child: Divider(), - ), + home: const Center(child: Divider()), ), ); final RenderBox box = tester.firstRenderObject(find.byType(Divider)); @@ -27,11 +40,7 @@ void main() { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, - child: Center( - child: Divider( - thickness: 5.0, - ), - ), + child: Center(child: Divider(thickness: 5.0)), ), ); final Container container = tester.widget(find.byType(Container)); @@ -47,11 +56,7 @@ void main() { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, - child: Center( - child: Divider( - indent: customIndent, - ), - ), + child: Center(child: Divider(indent: customIndent)), ), ); // The divider line is drawn with a DecoratedBox with a border @@ -63,11 +68,7 @@ void main() { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, - child: Center( - child: Divider( - endIndent: customIndent, - ), - ), + child: Center(child: Divider(endIndent: customIndent)), ), ); dividerRect = tester.getRect(find.byType(Divider)); @@ -92,13 +93,26 @@ void main() { expect(lineRect.right, dividerRect.right - customIndent); }); - testWidgets('Vertical Divider Test', (WidgetTester tester) async { + testWidgets('Material3 - Vertical Divider Test', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Center(child: VerticalDivider()), + ), + ); + final RenderBox box = tester.firstRenderObject(find.byType(VerticalDivider)); + expect(box.size.width, 16.0); + final Container container = tester.widget(find.byType(Container)); + final BoxDecoration decoration = container.decoration! as BoxDecoration; + final Border border = decoration.border! as Border; + expect(border.left.width, 1.0); + }); + + testWidgets('Material2 - Vertical Divider Test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), - home: const Center( - child: VerticalDivider(), - ), + home: const Center(child: VerticalDivider()), ), ); final RenderBox box = tester.firstRenderObject(find.byType(VerticalDivider)); @@ -113,11 +127,7 @@ void main() { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, - child: Center( - child: VerticalDivider( - thickness: 5.0, - ), - ), + child: Center(child: VerticalDivider(thickness: 5.0)), ), ); final Container container = tester.widget(find.byType(Container)); @@ -158,11 +168,7 @@ void main() { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, - child: Center( - child: VerticalDivider( - indent: customIndent, - ), - ), + child: Center(child: VerticalDivider(indent: customIndent)), ), ); // The divider line is drawn with a DecoratedBox with a border @@ -174,11 +180,7 @@ void main() { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, - child: Center( - child: VerticalDivider( - endIndent: customIndent, - ), - ), + child: Center(child: VerticalDivider(endIndent: customIndent)), ), ); dividerRect = tester.getRect(find.byType(VerticalDivider)); diff --git a/packages/flutter/test/material/divider_theme_test.dart b/packages/flutter/test/material/divider_theme_test.dart index 49afe07313a0d..6928a792d49a6 100644 --- a/packages/flutter/test/material/divider_theme_test.dart +++ b/packages/flutter/test/material/divider_theme_test.dart @@ -26,9 +26,9 @@ void main() { const DividerThemeData().debugFillProperties(builder); final List description = builder.properties - .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode node) => node.toString()) - .toList(); + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); expect(description, []); }); @@ -44,9 +44,9 @@ void main() { ).debugFillProperties(builder); final List description = builder.properties - .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) - .map((DiagnosticsNode node) => node.toString()) - .toList(); + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); expect(description, [ 'color: Color(0xffffffff)', @@ -57,7 +57,7 @@ void main() { ]); }); - group('Horizontal Divider', () { + group('Material3 - Horizontal Divider', () { testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( @@ -159,7 +159,7 @@ void main() { }); }); - group('Vertical Divider', () { + group('Material3 - Vertical Divider', () { testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( @@ -270,7 +270,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - group('Horizontal Divider', () { + group('Material2 - Horizontal Divider', () { testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -313,7 +313,7 @@ void main() { }); }); - group('Vertical Divider', () { + group('Material2 - Vertical Divider', () { testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), From d75735eea611ed46a508c9e6813efd109760dab2 Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Wed, 12 Jul 2023 12:50:53 -0700 Subject: [PATCH 0106/1547] Use platform specific line separator in gen-l10n (#130090) Currently files are not generated with `\r\n` in windows. This PR should fix the issue. Fixes https://github.com/flutter/flutter/issues/109761. --- .../lib/src/localizations/gen_l10n.dart | 28 ++++++++------ .../hermetic/generate_localizations_test.dart | 14 +++++-- .../generate_localizations_test.dart | 37 ++++++++++++++++++- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 17bc3641a2ebe..4288d5fdd163f 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -47,6 +47,9 @@ Future generateLocalizations({ precacheLanguageAndRegionTags(); + // Use \r\n if project's pubspec file contains \r\n. + final bool useCRLF = fileSystem.file('pubspec.yaml').readAsStringSync().contains('\r\n'); + LocalizationsGenerator generator; try { generator = LocalizationsGenerator( @@ -71,7 +74,7 @@ Future generateLocalizations({ suppressWarnings: options.suppressWarnings, ) ..loadResources() - ..writeOutputFiles(isFromYaml: true); + ..writeOutputFiles(isFromYaml: true, useCRLF: useCRLF); } on L10nException catch (e) { throwToolExit(e.message); } @@ -79,7 +82,6 @@ Future generateLocalizations({ final List outputFileList = generator.outputFileList; final File? untranslatedMessagesFile = generator.untranslatedMessagesFile; - // All other post processing. if (options.format) { final List formatFileList = outputFileList.toList(); if (untranslatedMessagesFile != null) { @@ -1310,7 +1312,7 @@ The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", " } } - List writeOutputFiles({ bool isFromYaml = false }) { + List writeOutputFiles({ bool isFromYaml = false, bool useCRLF = false }) { // First, generate the string contents of all necessary files. final String generatedLocalizationsFile = _generateCode(); @@ -1328,7 +1330,9 @@ The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", " syntheticPackageDirectory.createSync(recursive: true); final File flutterGenPubspec = syntheticPackageDirectory.childFile('pubspec.yaml'); if (!flutterGenPubspec.existsSync()) { - flutterGenPubspec.writeAsStringSync(emptyPubspecTemplate); + flutterGenPubspec.writeAsStringSync( + useCRLF ? emptyPubspecTemplate.replaceAll('\n', '\r\n') : emptyPubspecTemplate + ); } } @@ -1347,11 +1351,13 @@ The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", " // Generate the required files for localizations. _languageFileMap.forEach((File file, String contents) { - file.writeAsStringSync(contents); + file.writeAsStringSync(useCRLF ? contents.replaceAll('\n', '\r\n') : contents); _outputFileList.add(file.absolute.path); }); - baseOutputFile.writeAsStringSync(generatedLocalizationsFile); + baseOutputFile.writeAsStringSync( + useCRLF ? generatedLocalizationsFile.replaceAll('\n', '\r\n') : generatedLocalizationsFile + ); final File? messagesFile = untranslatedMessagesFile; if (messagesFile != null) { _generateUntranslatedMessagesFile(logger, messagesFile); @@ -1387,12 +1393,12 @@ The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", " if (!inputsAndOutputsListFileLocal.existsSync()) { inputsAndOutputsListFileLocal.createSync(recursive: true); } - + final String filesListContent = json.encode( { + 'inputs': _inputFileList, + 'outputs': _outputFileList, + }); inputsAndOutputsListFileLocal.writeAsStringSync( - json.encode( { - 'inputs': _inputFileList, - 'outputs': _outputFileList, - }), + useCRLF ? filesListContent.replaceAll('\n', '\r\n') : filesListContent, ); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart index 28c5d2767b48f..e2556a6e58c73 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart @@ -78,6 +78,11 @@ void main() { "description": "Sample description" } }'''); + fileSystem + .file('pubspec.yaml') + .writeAsStringSync(''' +flutter: + generate: true'''); final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, @@ -109,7 +114,11 @@ void main() { } }'''); fileSystem.file('header.txt').writeAsStringSync('a header file'); - + fileSystem + .file('pubspec.yaml') + .writeAsStringSync(''' +flutter: + generate: true'''); final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( fileSystem: fileSystem, logger: logger, @@ -442,7 +451,7 @@ format: true ProcessManager: () => FakeProcessManager.any(), }); - testUsingContext('throw when generate: false and uses synthetic package when run via commandline options', () async { + testUsingContext('throw when generate: false and uses synthetic package when run via commandline options', () async { final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) ..createSync(recursive: true); arbFile.writeAsStringSync(''' @@ -475,7 +484,6 @@ format: true () async => createTestCommandRunner(command).run(['gen-l10n', '--synthetic-package']), throwsToolExit(message: 'Attempted to generate localizations code without having the flutter: generate flag turned on.') ); - }, overrides: { FileSystem: () => fileSystem, ProcessManager: () => FakeProcessManager.any(), diff --git a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart index ba35df50a8805..67cc9667a27c1 100644 --- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart @@ -59,6 +59,13 @@ void _standardFlutterDirectoryL10nSetup(FileSystem fs) { .writeAsStringSync(singleMessageArbFileString); l10nDirectory.childFile(esArbFileName) .writeAsStringSync(singleEsMessageArbFileString); + fs.file('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(''' +flutter: + generate: true +'''); + } void main() { @@ -763,7 +770,7 @@ class FooEn extends Foo { _standardFlutterDirectoryL10nSetup(fs); // Missing flutter: generate: true should throw exception. - fs.file(fs.path.join(syntheticPackagePath, 'pubspec.yaml')) + fs.file('pubspec.yaml') ..createSync(recursive: true) ..writeAsStringSync(''' flutter: @@ -799,6 +806,34 @@ flutter: ); }); + testWithoutContext('uses the same line terminator as pubspec.yaml', () async { + _standardFlutterDirectoryL10nSetup(fs); + + fs.file('pubspec.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(''' +flutter:\r + generate: true\r +'''); + + final LocalizationOptions options = LocalizationOptions( + arbDir: fs.path.join('lib', 'l10n'), + outputClass: defaultClassNameString, + outputLocalizationFile: defaultOutputFileString, + ); + await generateLocalizations( + fileSystem: fs, + options: options, + logger: BufferLogger.test(), + projectDir: fs.currentDirectory, + dependenciesDir: fs.currentDirectory, + artifacts: artifacts, + processManager: processManager, + ); + final String content = getGeneratedFileContent(locale: 'en'); + expect(content, contains('\r\n')); + }); + testWithoutContext('blank lines generated nicely', () async { _standardFlutterDirectoryL10nSetup(fs); From 3d67ca43113a9139bbb556ec026741b44b7dcdb3 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Wed, 12 Jul 2023 13:08:05 -0700 Subject: [PATCH 0107/1547] Add missing links to examples that aren't linked anywhere (#130422) ## Description This adds links to examples that were not linked anywhere. ## Related Issues - Fixes #129956 ## Tests - Documentation only change --- .../action_buttons/action_icon_theme.0.dart | 8 +++++++- .../lib/material/search_anchor/search_anchor.3.dart | 5 ++--- .../lib/material/search_anchor/search_anchor.4.dart | 3 +-- .../api/lib/material/snack_bar/snack_bar.2.dart | 6 +++--- examples/api/lib/material/switch/switch.3.dart | 4 ++-- .../lib/painting/linear_border/linear_border.0.dart | 7 ++++--- .../lib/src/material/action_icons_theme.dart | 7 +++++++ packages/flutter/lib/src/material/scaffold.dart | 6 ++++++ .../flutter/lib/src/material/search_anchor.dart | 13 +++++++++++++ packages/flutter/lib/src/material/snack_bar.dart | 7 +++++++ packages/flutter/lib/src/material/switch.dart | 7 +++++++ packages/flutter/lib/src/material/text_field.dart | 7 +++++++ .../flutter/lib/src/painting/linear_border.dart | 6 ++++++ packages/flutter/lib/src/widgets/basic.dart | 6 ++++++ 14 files changed, 78 insertions(+), 14 deletions(-) diff --git a/examples/api/lib/material/action_buttons/action_icon_theme.0.dart b/examples/api/lib/material/action_buttons/action_icon_theme.0.dart index 653b6ee6a70c2..20671520545c7 100644 --- a/examples/api/lib/material/action_buttons/action_icon_theme.0.dart +++ b/examples/api/lib/material/action_buttons/action_icon_theme.0.dart @@ -73,7 +73,13 @@ class MyHomePage extends StatelessWidget { appBar: AppBar( title: Text(title), ), - drawer: const Drawer(), + drawer: Drawer( + child: Column( + children: [ + TextButton(child: const Text('Drawer Item'), onPressed: () {}), + ], + ), + ), body: const Center( child: NextPageButton(), ), diff --git a/examples/api/lib/material/search_anchor/search_anchor.3.dart b/examples/api/lib/material/search_anchor/search_anchor.3.dart index 80694e04d11d0..e0eae6b16021f 100644 --- a/examples/api/lib/material/search_anchor/search_anchor.3.dart +++ b/examples/api/lib/material/search_anchor/search_anchor.3.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; -/// Flutter code sample for [SearchAnchor] that shows how to fetch the suggestions -/// from a remote API. +/// Flutter code sample for [SearchAnchor]. const Duration fakeAPIDuration = Duration(seconds: 1); @@ -60,7 +59,7 @@ class _AsyncSearchAnchorState extends State<_AsyncSearchAnchor > { final List options = (await _FakeAPI.search(_searchingWithQuery!)).toList(); // If another search happened after this one, throw away these options. - // Use the previous options intead and wait for the newer request to + // Use the previous options instead and wait for the newer request to // finish. if (_searchingWithQuery != controller.text) { return _lastOptions; diff --git a/examples/api/lib/material/search_anchor/search_anchor.4.dart b/examples/api/lib/material/search_anchor/search_anchor.4.dart index 8417ce6113c55..d7e90ea12a066 100644 --- a/examples/api/lib/material/search_anchor/search_anchor.4.dart +++ b/examples/api/lib/material/search_anchor/search_anchor.4.dart @@ -6,8 +6,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; -/// Flutter code sample for [SearchAnchor] that demonstrates fetching the -/// suggestions asynchronously and debouncing the network calls. +/// Flutter code sample for [SearchAnchor]. const Duration fakeAPIDuration = Duration(seconds: 1); const Duration debounceDuration = Duration(milliseconds: 500); diff --git a/examples/api/lib/material/snack_bar/snack_bar.2.dart b/examples/api/lib/material/snack_bar/snack_bar.2.dart index 7a211be20723a..63fca4d7f9e22 100644 --- a/examples/api/lib/material/snack_bar/snack_bar.2.dart +++ b/examples/api/lib/material/snack_bar/snack_bar.2.dart @@ -4,12 +4,12 @@ import 'package:flutter/material.dart'; -/// Flutter code sample for [SnackBar] with Material 3 specifications. +/// Flutter code sample for [SnackBar]. void main() => runApp(const SnackBarExampleApp()); -// A Material 3 [SnackBar] demonstrating an optional icon, in either floating -// or fixed format. +/// A Material 3 [SnackBar] demonstrating an optional icon, in either floating +/// or fixed format. class SnackBarExampleApp extends StatelessWidget { const SnackBarExampleApp({super.key}); diff --git a/examples/api/lib/material/switch/switch.3.dart b/examples/api/lib/material/switch/switch.3.dart index 023c3387d0099..b1ba74d7dfb79 100644 --- a/examples/api/lib/material/switch/switch.3.dart +++ b/examples/api/lib/material/switch/switch.3.dart @@ -16,7 +16,7 @@ class SwitchApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.light(useMaterial3: true).copyWith( - // Use the ambient [CupetinoThemeData] to style all widgets which would + // Use the ambient CupertinoThemeData to style all widgets which would // otherwise use iOS defaults. cupertinoOverrideTheme: const CupertinoThemeData(applyThemeToAll: true), ), @@ -54,7 +54,7 @@ class _SwitchExampleState extends State { }, ), Switch.adaptive( - // Don't use the ambient [CupetinoThemeData] to style this switch. + // Don't use the ambient CupertinoThemeData to style this switch. applyCupertinoTheme: false, value: light, onChanged: (bool value) { diff --git a/examples/api/lib/painting/linear_border/linear_border.0.dart b/examples/api/lib/painting/linear_border/linear_border.0.dart index 991fa0fa02aa6..510a65236eb9f 100644 --- a/examples/api/lib/painting/linear_border/linear_border.0.dart +++ b/examples/api/lib/painting/linear_border/linear_border.0.dart @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Examples of LinearBorder and LinearBorderEdge. - import 'package:flutter/material.dart'; +/// Examples for [LinearBorder] and [LinearBorderEdge]. + void main() { runApp(const ExampleApp()); } @@ -18,7 +18,8 @@ class ExampleApp extends StatelessWidget { return MaterialApp( theme: ThemeData.light(useMaterial3: true), home: const Directionality( - textDirection: TextDirection.ltr, // Or try rtl. + // TRY THIS: Switch to TextDirection.rtl to see how the borders change. + textDirection: TextDirection.ltr, child: Home(), ), ); diff --git a/packages/flutter/lib/src/material/action_icons_theme.dart b/packages/flutter/lib/src/material/action_icons_theme.dart index 7dd698793dfb5..6c291e6b1ebd2 100644 --- a/packages/flutter/lib/src/material/action_icons_theme.dart +++ b/packages/flutter/lib/src/material/action_icons_theme.dart @@ -114,6 +114,13 @@ class ActionIconThemeData with Diagnosticable { /// An inherited widget that overrides the default icon of [BackButtonIcon], /// [CloseButtonIcon], [DrawerButtonIcon], and [EndDrawerButtonIcon] in this /// widget's subtree. +/// +/// {@tool dartpad} +/// This example shows how to define custom builders for drawer and back +/// buttons. +/// +/// ** See code in examples/api/lib/material/action_buttons/action_icon_theme.0.dart ** +/// {@end-tool} class ActionIconTheme extends InheritedTheme { /// Creates a theme that overrides the default icon of [BackButtonIcon], /// [CloseButtonIcon], [DrawerButtonIcon], and [EndDrawerButtonIcon] in this diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index fbcd472801923..110cbbbfb1c89 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -279,6 +279,12 @@ class ScaffoldMessengerState extends State with TickerProvide /// the SnackBar to be visible. /// /// {@tool dartpad} + /// Here is an example showing how to display a [SnackBar] with [showSnackBar] + /// + /// ** See code in examples/api/lib/material/scaffold/scaffold_messenger_state.show_snack_bar.0.dart ** + /// {@end-tool} + /// + /// {@tool dartpad} /// Here is an example showing that a floating [SnackBar] appears above [Scaffold.floatingActionButton]. /// /// ** See code in examples/api/lib/material/scaffold/scaffold_messenger_state.show_snack_bar.1.dart ** diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index e9b3037ffcfcb..fbb4682c8ee7e 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -87,6 +87,19 @@ typedef ViewBuilder = Widget Function(Iterable suggestions); /// ** See code in examples/api/lib/material/search_anchor/search_anchor.1.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example shows how to fetch the search suggestions from a remote API. +/// +/// ** See code in examples/api/lib/material/search_anchor/search_anchor.3.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This example demonstrates fetching the search suggestions asynchronously and +/// debouncing network calls. +/// +/// ** See code in examples/api/lib/material/search_anchor/search_anchor.4.dart ** +/// {@end-tool} +/// /// See also: /// /// * [SearchBar], a widget that defines a search bar. diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index 5bed2ab347ce5..5dea738bc0bfa 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -250,6 +250,13 @@ class _SnackBarActionState extends State { /// ** See code in examples/api/lib/material/snack_bar/snack_bar.1.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example demonstrates the various [SnackBar] widget components, +/// including an optional icon, in either floating or fixed format. +/// +/// ** See code in examples/api/lib/material/snack_bar/snack_bar.2.dart ** +/// {@end-tool} +/// /// See also: /// /// * [ScaffoldMessenger.of], to obtain the current [ScaffoldMessengerState], diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index 0cfc6ff81550e..e301c8578b8ce 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -69,6 +69,13 @@ enum _SwitchType { material, adaptive } /// ** See code in examples/api/lib/material/switch/switch.2.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example shows how to use the ambient [CupertinoThemeData] to style all +/// widgets which would otherwise use iOS defaults. +/// +/// ** See code in examples/api/lib/material/switch/switch.3.dart ** +/// {@end-tool} +/// /// See also: /// /// * [SwitchListTile], which combines this widget with a [ListTile] so that diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index f2d6716f5ec79..4a3a1e54186ce 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -178,6 +178,13 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete /// /// {@macro flutter.widgets.editableText.accessibility} /// +/// {@tool dartpad} +/// This sample shows how to style a text field to match a filled or outlined +/// Material Design 3 text field. +/// +/// ** See code in examples/api/lib/material/text_field/text_field.2.dart ** +/// {@end-tool} +/// /// See also: /// /// * [TextFormField], which integrates with the [Form] widget. diff --git a/packages/flutter/lib/src/painting/linear_border.dart b/packages/flutter/lib/src/painting/linear_border.dart index 76dc6709a59e5..eaa51eec1145e 100644 --- a/packages/flutter/lib/src/painting/linear_border.dart +++ b/packages/flutter/lib/src/painting/linear_border.dart @@ -132,6 +132,12 @@ class LinearBorderEdge { /// /// Convenience constructors are included for the common case where just one edge is specified: /// [LinearBorder.start], [LinearBorder.end], [LinearBorder.top], [LinearBorder.bottom]. +/// +/// {@tool dartpad} +/// This example shows how to draw different kinds of [LinearBorder]s. +/// +/// ** See code in examples/api/lib/painting/linear_border/linear_border.0.dart ** +/// {@end-tool} class LinearBorder extends OutlinedBorder { /// Creates a rectangular box border that's rendered as zero to four lines. const LinearBorder({ diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index cd6c205aa9ccf..655b3e875ea93 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -3036,6 +3036,12 @@ class LimitedBox extends SingleChildRenderObjectWidget { /// A widget that imposes different constraints on its child than it gets /// from its parent, possibly allowing the child to overflow the parent. /// +/// {@tool dartpad} +/// This example shows how an [OverflowBox] is used, and what its effect is. +/// +/// ** See code in examples/api/lib/widgets/basic/overflowbox.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [RenderConstrainedOverflowBox] for details about how [OverflowBox] is From a189d95ac209570e0b4f4973ca11aeb96c8e982d Mon Sep 17 00:00:00 2001 From: Gil Nobrega <82336674+gilnobrega@users.noreply.github.com> Date: Wed, 12 Jul 2023 21:50:18 +0100 Subject: [PATCH 0108/1547] Reland [a11y] CupertinoSwitch On/Off labels (#130173) This original PR (https://github.com/flutter/flutter/pull/127776) was reverted (https://github.com/flutter/flutter/pull/130166) due to a Google test failure. This reopens the PR as per the discussion in https://github.com/flutter/flutter/pull/130166#issuecomment-1626105218. Fixes issue #4830. --- .../flutter/lib/src/cupertino/switch.dart | 106 ++++++++++ .../flutter/lib/src/widgets/media_query.dart | 41 ++++ .../flutter/test/cupertino/switch_test.dart | 181 ++++++++++++++++++ .../test/widgets/media_query_test.dart | 55 ++++++ 4 files changed, 383 insertions(+) diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 2057e115a214f..75518bcdec84f 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -75,6 +75,8 @@ class CupertinoSwitch extends StatefulWidget { this.thumbColor, this.applyTheme, this.focusColor, + this.onLabelColor, + this.offLabelColor, this.focusNode, this.onFocusChange, this.autofocus = false, @@ -133,6 +135,17 @@ class CupertinoSwitch extends StatefulWidget { /// Defaults to a slightly transparent [activeColor]. final Color? focusColor; + /// The color to use for the accessibility label when the switch is on. + /// + /// Defaults to [CupertinoColors.white] when null. + final Color? onLabelColor; + + /// The color to use for the accessibility label when the switch is off. + /// + /// Defaults to [Color.fromARGB(255, 179, 179, 179)] + /// (or [Color.fromARGB(255, 255, 255, 255)] in high contrast) when null. + final Color? offLabelColor; + /// {@macro flutter.widgets.Focus.focusNode} final FocusNode? focusNode; @@ -357,6 +370,19 @@ class _CupertinoSwitchState extends State with TickerProviderSt ?? CupertinoColors.systemGreen, context, ); + final (Color onLabelColor, Color offLabelColor)? onOffLabelColors = + MediaQuery.onOffSwitchLabelsOf(context) + ? ( + CupertinoDynamicColor.resolve( + widget.onLabelColor ?? CupertinoColors.white, + context, + ), + CupertinoDynamicColor.resolve( + widget.offLabelColor ?? _kOffLabelColor, + context, + ), + ) + : null; if (needsPositionAnimation) { _resumePositionAnimation(); } @@ -389,6 +415,7 @@ class _CupertinoSwitchState extends State with TickerProviderSt textDirection: Directionality.of(context), isFocused: isFocused, state: this, + onOffLabelColors: onOffLabelColors, ), ), ), @@ -417,6 +444,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { required this.textDirection, required this.isFocused, required this.state, + required this.onOffLabelColors, }); final bool value; @@ -428,6 +456,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { final _CupertinoSwitchState state; final TextDirection textDirection; final bool isFocused; + final (Color onLabelColor, Color offLabelColor)? onOffLabelColors; @override _RenderCupertinoSwitch createRenderObject(BuildContext context) { @@ -441,6 +470,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { textDirection: textDirection, isFocused: isFocused, state: state, + onOffLabelColors: onOffLabelColors, ); } @@ -467,6 +497,24 @@ const double _kTrackInnerEnd = _kTrackWidth - _kTrackInnerStart; const double _kTrackInnerLength = _kTrackInnerEnd - _kTrackInnerStart; const double _kSwitchWidth = 59.0; const double _kSwitchHeight = 39.0; +// Label sizes and padding taken from xcode inspector. +// See https://github.com/flutter/flutter/issues/4830#issuecomment-528495360 +const double _kOnLabelWidth = 1.0; +const double _kOnLabelHeight = 10.0; +const double _kOnLabelPaddingHorizontal = 11.0; +const double _kOffLabelWidth = 1.0; +const double _kOffLabelPaddingHorizontal = 12.0; +const double _kOffLabelRadius = 5.0; +const CupertinoDynamicColor _kOffLabelColor = CupertinoDynamicColor.withBrightnessAndContrast( + debugLabel: 'offSwitchLabel', + // Source: https://github.com/flutter/flutter/pull/39993#discussion_r321946033 + color: Color.fromARGB(255, 179, 179, 179), + // Source: https://github.com/flutter/flutter/pull/39993#issuecomment-535196665 + darkColor: Color.fromARGB(255, 179, 179, 179), + // Source: https://github.com/flutter/flutter/pull/127776#discussion_r1244208264 + highContrastColor: Color.fromARGB(255, 255, 255, 255), + darkHighContrastColor: Color.fromARGB(255, 255, 255, 255), +); // Opacity of a disabled switch, as eye-balled from iOS Simulator on Mac. const double _kCupertinoSwitchDisabledOpacity = 0.5; @@ -484,6 +532,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { required TextDirection textDirection, required bool isFocused, required _CupertinoSwitchState state, + required (Color onLabelColor, Color offLabelColor)? onOffLabelColors, }) : _value = value, _activeColor = activeColor, _trackColor = trackColor, @@ -493,6 +542,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { _textDirection = textDirection, _isFocused = isFocused, _state = state, + _onOffLabelColors = onOffLabelColors, super(additionalConstraints: const BoxConstraints.tightFor(width: _kSwitchWidth, height: _kSwitchHeight)) { state.position.addListener(markNeedsPaint); state._reaction.addListener(markNeedsPaint); @@ -584,6 +634,16 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { markNeedsPaint(); } + (Color onLabelColor, Color offLabelColor)? get onOffLabelColors => _onOffLabelColors; + (Color onLabelColor, Color offLabelColor)? _onOffLabelColors; + set onOffLabelColors((Color onLabelColor, Color offLabelColor)? value) { + if (value == _onOffLabelColors) { + return; + } + _onOffLabelColors = value; + markNeedsPaint(); + } + bool get isInteractive => onChanged != null; @override @@ -649,6 +709,52 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { canvas.drawRRect(borderTrackRRect, borderPaint); } + if (_onOffLabelColors != null) { + final (Color onLabelColor, Color offLabelColor) = onOffLabelColors!; + + final double leftLabelOpacity = visualPosition * (1.0 - currentReactionValue); + final double rightLabelOpacity = (1.0 - visualPosition) * (1.0 - currentReactionValue); + final (double onLabelOpacity, double offLabelOpacity) = + switch (textDirection) { + TextDirection.ltr => (leftLabelOpacity, rightLabelOpacity), + TextDirection.rtl => (rightLabelOpacity, leftLabelOpacity), + }; + + final (Offset onLabelOffset, Offset offLabelOffset) = + switch (textDirection) { + TextDirection.ltr => ( + trackRect.centerLeft.translate(_kOnLabelPaddingHorizontal, 0), + trackRect.centerRight.translate(-_kOffLabelPaddingHorizontal, 0), + ), + TextDirection.rtl => ( + trackRect.centerRight.translate(-_kOnLabelPaddingHorizontal, 0), + trackRect.centerLeft.translate(_kOffLabelPaddingHorizontal, 0), + ), + }; + + // Draws '|' label + final Rect onLabelRect = Rect.fromCenter( + center: onLabelOffset, + width: _kOnLabelWidth, + height: _kOnLabelHeight, + ); + final Paint onLabelPaint = Paint() + ..color = onLabelColor.withOpacity(onLabelOpacity) + ..style = PaintingStyle.fill; + canvas.drawRect(onLabelRect, onLabelPaint); + + // Draws 'O' label + final Paint offLabelPaint = Paint() + ..color = offLabelColor.withOpacity(offLabelOpacity) + ..style = PaintingStyle.stroke + ..strokeWidth = _kOffLabelWidth; + canvas.drawCircle( + offLabelOffset, + _kOffLabelRadius, + offLabelPaint, + ); + } + final double currentThumbExtension = CupertinoThumbPainter.extension * currentReactionValue; final double thumbLeft = lerpDouble( trackRect.left + _kTrackInnerStart - CupertinoThumbPainter.radius, diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 8cd8ee3c2a379..0714708e14ade 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -60,6 +60,8 @@ enum _MediaQueryAspect { invertColors, /// Specifies the aspect corresponding to [MediaQueryData.highContrast]. highContrast, + /// Specifies the aspect corresponding to [MediaQueryData.onOffSwitchLabels]. + onOffSwitchLabels, /// Specifies the aspect corresponding to [MediaQueryData.disableAnimations]. disableAnimations, /// Specifies the aspect corresponding to [MediaQueryData.boldText]. @@ -153,6 +155,7 @@ class MediaQueryData { this.accessibleNavigation = false, this.invertColors = false, this.highContrast = false, + this.onOffSwitchLabels = false, this.disableAnimations = false, this.boldText = false, this.navigationMode = NavigationMode.traditional, @@ -220,6 +223,7 @@ class MediaQueryData { disableAnimations = platformData?.disableAnimations ?? view.platformDispatcher.accessibilityFeatures.disableAnimations, boldText = platformData?.boldText ?? view.platformDispatcher.accessibilityFeatures.boldText, highContrast = platformData?.highContrast ?? view.platformDispatcher.accessibilityFeatures.highContrast, + onOffSwitchLabels = platformData?.onOffSwitchLabels ?? view.platformDispatcher.accessibilityFeatures.onOffSwitchLabels, alwaysUse24HourFormat = platformData?.alwaysUse24HourFormat ?? view.platformDispatcher.alwaysUse24HourFormat, navigationMode = platformData?.navigationMode ?? NavigationMode.traditional, gestureSettings = DeviceGestureSettings.fromView(view), @@ -416,6 +420,15 @@ class MediaQueryData { /// or above. final bool highContrast; + /// Whether the user requested to show on/off labels inside switches on iOS, + /// via Settings -> Accessibility -> Display & Text Size -> On/Off Labels. + /// + /// See also: + /// + /// * [dart:ui.PlatformDispatcher.accessibilityFeatures], where the setting + /// originates. + final bool onOffSwitchLabels; + /// Whether the platform is requesting that animations be disabled or reduced /// as much as possible. /// @@ -488,6 +501,7 @@ class MediaQueryData { EdgeInsets? systemGestureInsets, bool? alwaysUse24HourFormat, bool? highContrast, + bool? onOffSwitchLabels, bool? disableAnimations, bool? invertColors, bool? accessibleNavigation, @@ -508,6 +522,7 @@ class MediaQueryData { alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat, invertColors: invertColors ?? this.invertColors, highContrast: highContrast ?? this.highContrast, + onOffSwitchLabels: onOffSwitchLabels ?? this.onOffSwitchLabels, disableAnimations: disableAnimations ?? this.disableAnimations, accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation, boldText: boldText ?? this.boldText, @@ -699,6 +714,7 @@ class MediaQueryData { && other.systemGestureInsets == systemGestureInsets && other.alwaysUse24HourFormat == alwaysUse24HourFormat && other.highContrast == highContrast + && other.onOffSwitchLabels == onOffSwitchLabels && other.disableAnimations == disableAnimations && other.invertColors == invertColors && other.accessibleNavigation == accessibleNavigation @@ -719,6 +735,7 @@ class MediaQueryData { viewInsets, alwaysUse24HourFormat, highContrast, + onOffSwitchLabels, disableAnimations, invertColors, accessibleNavigation, @@ -742,6 +759,7 @@ class MediaQueryData { 'alwaysUse24HourFormat: $alwaysUse24HourFormat', 'accessibleNavigation: $accessibleNavigation', 'highContrast: $highContrast', + 'onOffSwitchLabels: $onOffSwitchLabels', 'disableAnimations: $disableAnimations', 'invertColors: $invertColors', 'boldText: $boldText', @@ -1255,6 +1273,25 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// the [MediaQueryData.highContrast] property of the ancestor [MediaQuery] changes. static bool? maybeHighContrastOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.highContrast)?.highContrast; + /// Returns onOffSwitchLabels for the nearest MediaQuery ancestor or false, if no + /// such ancestor exists. + /// + /// See also: + /// + /// * [MediaQueryData.onOffSwitchLabels], which indicates the platform's + /// desire to show on/off labels inside switches. + /// + /// Use of this method will cause the given [context] to rebuild any time that + /// the [MediaQueryData.onOffSwitchLabels] property of the ancestor [MediaQuery] changes. + static bool onOffSwitchLabelsOf(BuildContext context) => maybeOnOffSwitchLabelsOf(context) ?? false; + + /// Returns onOffSwitchLabels for the nearest MediaQuery ancestor or + /// null, if no such ancestor exists. + /// + /// Use of this method will cause the given [context] to rebuild any time that + /// the [MediaQueryData.onOffSwitchLabels] property of the ancestor [MediaQuery] changes. + static bool? maybeOnOffSwitchLabelsOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.onOffSwitchLabels)?.onOffSwitchLabels; + /// Returns disableAnimations for the nearest MediaQuery ancestor or /// [Brightness.light], if no such ancestor exists. /// @@ -1406,6 +1443,10 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { if (data.highContrast != oldWidget.data.highContrast) { return true; } + case _MediaQueryAspect.onOffSwitchLabels: + if (data.onOffSwitchLabels != oldWidget.data.onOffSwitchLabels) { + return true; + } case _MediaQueryAspect.disableAnimations: if (data.disableAnimations != oldWidget.data.disableAnimations) { return true; diff --git a/packages/flutter/test/cupertino/switch_test.dart b/packages/flutter/test/cupertino/switch_test.dart index f91fd0af87aa7..af9a1336de652 100644 --- a/packages/flutter/test/cupertino/switch_test.dart +++ b/packages/flutter/test/cupertino/switch_test.dart @@ -753,6 +753,187 @@ void main() { ); }); + PaintPattern onLabelPaintPattern({ + required int alpha, + bool isRtl = false, + }) => + paints + ..rect( + rect: Rect.fromLTWH(isRtl ? 43.5 : 14.5, 14.5, 1.0, 10.0), + color: const Color(0xffffffff).withAlpha(alpha), + style: PaintingStyle.fill, + ); + + PaintPattern offLabelPaintPattern({ + required int alpha, + bool highContrast = false, + bool isRtl = false, + }) => + paints + ..circle( + x: isRtl ? 16.0 : 43.0, + y: 19.5, + radius: 5.0, + color: + (highContrast ? const Color(0xffffffff) : const Color(0xffb3b3b3)) + .withAlpha(alpha), + strokeWidth: 1.0, + style: PaintingStyle.stroke, + ); + + testWidgets('Switch renders switch labels correctly before, during, and after being tapped', (WidgetTester tester) async { + final Key switchKey = UniqueKey(); + bool value = false; + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(onOffSwitchLabels: true), + child: Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Center( + child: RepaintBoundary( + child: CupertinoSwitch( + key: switchKey, + value: value, + dragStartBehavior: DragStartBehavior.down, + onChanged: (bool newValue) { + setState(() { + value = newValue; + }); + }, + ), + ), + ); + }, + ), + ), + ), + ); + + final RenderObject switchRenderObject = + tester.element(find.byType(CupertinoSwitch)).renderObject!; + + expect(switchRenderObject, offLabelPaintPattern(alpha: 255)); + expect(switchRenderObject, onLabelPaintPattern(alpha: 0)); + + await tester.tap(find.byKey(switchKey)); + expect(value, isTrue); + + // Kick off animation, then advance to intermediate frame. + await tester.pump(); + await tester.pump(const Duration(milliseconds: 60)); + expect(switchRenderObject, onLabelPaintPattern(alpha: 131)); + expect(switchRenderObject, offLabelPaintPattern(alpha: 124)); + + await tester.pumpAndSettle(); + expect(switchRenderObject, onLabelPaintPattern(alpha: 255)); + expect(switchRenderObject, offLabelPaintPattern(alpha: 0)); + }); + + testWidgets('Switch renders switch labels correctly before, during, and after being tapped in high contrast', (WidgetTester tester) async { + final Key switchKey = UniqueKey(); + bool value = false; + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData( + onOffSwitchLabels: true, + highContrast: true, + ), + child: Directionality( + textDirection: TextDirection.ltr, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Center( + child: RepaintBoundary( + child: CupertinoSwitch( + key: switchKey, + value: value, + dragStartBehavior: DragStartBehavior.down, + onChanged: (bool newValue) { + setState(() { + value = newValue; + }); + }, + ), + ), + ); + }, + ), + ), + ), + ); + + final RenderObject switchRenderObject = + tester.element(find.byType(CupertinoSwitch)).renderObject!; + + expect(switchRenderObject, offLabelPaintPattern(highContrast: true, alpha: 255)); + expect(switchRenderObject, onLabelPaintPattern(alpha: 0)); + + await tester.tap(find.byKey(switchKey)); + expect(value, isTrue); + + // Kick off animation, then advance to intermediate frame. + await tester.pump(); + await tester.pump(const Duration(milliseconds: 60)); + expect(switchRenderObject, onLabelPaintPattern(alpha: 131)); + expect(switchRenderObject, offLabelPaintPattern(highContrast: true, alpha: 124)); + + await tester.pumpAndSettle(); + expect(switchRenderObject, onLabelPaintPattern(alpha: 255)); + expect(switchRenderObject, offLabelPaintPattern(highContrast: true, alpha: 0)); + }); + + testWidgets('Switch renders switch labels correctly before, during, and after being tapped with direction rtl', (WidgetTester tester) async { + final Key switchKey = UniqueKey(); + bool value = false; + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(onOffSwitchLabels: true), + child: Directionality( + textDirection: TextDirection.rtl, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Center( + child: RepaintBoundary( + child: CupertinoSwitch( + key: switchKey, + value: value, + dragStartBehavior: DragStartBehavior.down, + onChanged: (bool newValue) { + setState(() { + value = newValue; + }); + }, + ), + ), + ); + }, + ), + ), + ), + ); + + final RenderObject switchRenderObject = + tester.element(find.byType(CupertinoSwitch)).renderObject!; + + expect(switchRenderObject, offLabelPaintPattern(isRtl: true, alpha: 255)); + expect(switchRenderObject, onLabelPaintPattern(isRtl: true, alpha: 0)); + + await tester.tap(find.byKey(switchKey)); + expect(value, isTrue); + + // Kick off animation, then advance to intermediate frame. + await tester.pump(); + await tester.pump(const Duration(milliseconds: 60)); + expect(switchRenderObject, onLabelPaintPattern(isRtl: true, alpha: 131)); + expect(switchRenderObject, offLabelPaintPattern(isRtl: true, alpha: 124)); + + await tester.pumpAndSettle(); + expect(switchRenderObject, onLabelPaintPattern(isRtl: true, alpha: 255)); + expect(switchRenderObject, offLabelPaintPattern(isRtl: true, alpha: 0)); + }); + testWidgets('Switch renders correctly in dark mode', (WidgetTester tester) async { final Key switchKey = UniqueKey(); bool value = false; diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 9516e35e2fdc3..135f284ac9690 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -154,6 +154,7 @@ void main() { expect(data.disableAnimations, false); expect(data.boldText, false); expect(data.highContrast, false); + expect(data.onOffSwitchLabels, false); expect(data.platformBrightness, Brightness.light); expect(data.gestureSettings.touchSlop, null); expect(data.displayFeatures, isEmpty); @@ -168,6 +169,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, alwaysUse24HourFormat: true, navigationMode: NavigationMode.directional, ); @@ -188,6 +190,7 @@ void main() { expect(data.disableAnimations, platformData.disableAnimations); expect(data.boldText, platformData.boldText); expect(data.highContrast, platformData.highContrast); + expect(data.onOffSwitchLabels, platformData.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -217,6 +220,7 @@ void main() { expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); + expect(data.onOffSwitchLabels, tester.platformDispatcher.accessibilityFeatures.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -232,6 +236,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, alwaysUse24HourFormat: true, navigationMode: NavigationMode.directional, ); @@ -264,6 +269,7 @@ void main() { expect(data.disableAnimations, platformData.disableAnimations); expect(data.boldText, platformData.boldText); expect(data.highContrast, platformData.highContrast); + expect(data.onOffSwitchLabels, platformData.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, platformData.alwaysUse24HourFormat); expect(data.navigationMode, platformData.navigationMode); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -311,6 +317,7 @@ void main() { expect(data.disableAnimations, tester.platformDispatcher.accessibilityFeatures.disableAnimations); expect(data.boldText, tester.platformDispatcher.accessibilityFeatures.boldText); expect(data.highContrast, tester.platformDispatcher.accessibilityFeatures.highContrast); + expect(data.onOffSwitchLabels, tester.platformDispatcher.accessibilityFeatures.onOffSwitchLabels); expect(data.alwaysUse24HourFormat, tester.platformDispatcher.alwaysUse24HourFormat); expect(data.navigationMode, NavigationMode.traditional); expect(data.gestureSettings, DeviceGestureSettings.fromView(tester.view)); @@ -489,6 +496,7 @@ void main() { expect(copied.disableAnimations, data.disableAnimations); expect(copied.boldText, data.boldText); expect(copied.highContrast, data.highContrast); + expect(copied.onOffSwitchLabels, data.onOffSwitchLabels); expect(copied.platformBrightness, data.platformBrightness); expect(copied.gestureSettings, data.gestureSettings); expect(copied.displayFeatures, data.displayFeatures); @@ -528,6 +536,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, platformBrightness: Brightness.dark, navigationMode: NavigationMode.directional, gestureSettings: gestureSettings, @@ -546,6 +555,7 @@ void main() { expect(copied.disableAnimations, true); expect(copied.boldText, true); expect(copied.highContrast, true); + expect(copied.onOffSwitchLabels, true); expect(copied.platformBrightness, Brightness.dark); expect(copied.navigationMode, NavigationMode.directional); expect(copied.gestureSettings, gestureSettings); @@ -583,6 +593,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -618,6 +629,7 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); + expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -653,6 +665,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -685,6 +698,7 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); + expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -720,6 +734,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -755,6 +770,7 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); + expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -790,6 +806,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -822,6 +839,7 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); + expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -857,6 +875,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -892,6 +911,7 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); + expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -927,6 +947,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, navigationMode: NavigationMode.directional, displayFeatures: displayFeatures, ), @@ -959,6 +980,7 @@ void main() { expect(unpadded.disableAnimations, true); expect(unpadded.boldText, true); expect(unpadded.highContrast, true); + expect(unpadded.onOffSwitchLabels, true); expect(unpadded.navigationMode, NavigationMode.directional); expect(unpadded.displayFeatures, displayFeatures); }); @@ -1044,6 +1066,33 @@ void main() { expect(insideHighContrast, true); }); + testWidgets('MediaQuery.onOffSwitchLabelsOf', (WidgetTester tester) async { + late bool outsideOnOffSwitchLabels; + late bool insideOnOffSwitchLabels; + + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + outsideOnOffSwitchLabels = MediaQuery.onOffSwitchLabelsOf(context); + return MediaQuery( + data: const MediaQueryData( + onOffSwitchLabels: true, + ), + child: Builder( + builder: (BuildContext context) { + insideOnOffSwitchLabels = MediaQuery.onOffSwitchLabelsOf(context); + return Container(); + }, + ), + ); + }, + ), + ); + + expect(outsideOnOffSwitchLabels, false); + expect(insideOnOffSwitchLabels, true); + }); + testWidgets('MediaQuery.boldTextOf', (WidgetTester tester) async { late bool outsideBoldTextOverride; late bool insideBoldTextOverride; @@ -1171,6 +1220,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, displayFeatures: displayFeatures, ), child: Builder( @@ -1201,6 +1251,7 @@ void main() { expect(subScreenMediaQuery.disableAnimations, true); expect(subScreenMediaQuery.boldText, true); expect(subScreenMediaQuery.highContrast, true); + expect(subScreenMediaQuery.onOffSwitchLabels, true); expect(subScreenMediaQuery.displayFeatures, isEmpty); }); @@ -1244,6 +1295,7 @@ void main() { disableAnimations: true, boldText: true, highContrast: true, + onOffSwitchLabels: true, displayFeatures: displayFeatures, ), child: Builder( @@ -1283,6 +1335,7 @@ void main() { expect(subScreenMediaQuery.disableAnimations, true); expect(subScreenMediaQuery.boldText, true); expect(subScreenMediaQuery.highContrast, true); + expect(subScreenMediaQuery.onOffSwitchLabels, true); expect(subScreenMediaQuery.displayFeatures, [cutoutDisplayFeature]); }); @@ -1453,6 +1506,8 @@ void main() { const _MediaQueryAspectCase(MediaQuery.maybeInvertColorsOf, MediaQueryData(invertColors: true)), const _MediaQueryAspectCase(MediaQuery.highContrastOf, MediaQueryData(highContrast: true)), const _MediaQueryAspectCase(MediaQuery.maybeHighContrastOf, MediaQueryData(highContrast: true)), + const _MediaQueryAspectCase(MediaQuery.onOffSwitchLabelsOf, MediaQueryData(onOffSwitchLabels: true)), + const _MediaQueryAspectCase(MediaQuery.maybeOnOffSwitchLabelsOf, MediaQueryData(onOffSwitchLabels: true)), const _MediaQueryAspectCase(MediaQuery.disableAnimationsOf, MediaQueryData(disableAnimations: true)), const _MediaQueryAspectCase(MediaQuery.maybeDisableAnimationsOf, MediaQueryData(disableAnimations: true)), const _MediaQueryAspectCase(MediaQuery.boldTextOf, MediaQueryData(boldText: true)), From ab39bff282559a5189f91210b011b6406565fa51 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam <58529443+srujzs@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:54:15 -0700 Subject: [PATCH 0109/1547] Refactor JSNumber.toDart and Object.toJS (#129436) JSNumber.toDart will now be two functions: toDartDouble and toDartInt. There was code that did an Object.toJS. This has been changed to use Function.toJS as well to make it consistent with the code in flutter/packages: https://github.com/flutter/packages/blob/0ef393811d0c2653e68ac135733353fcad8fffa9/packages/web_benchmarks/lib/src/recorder.dart#L1223 This is to help land this CL: https://dart-review.googlesource.com/c/sdk/+/309082 https://dart-review.googlesource.com/c/sdk/+/309081 is the CL that added the new methods. ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. --- .../macrobenchmarks/lib/src/web/recorder.dart | 4 +--- packages/flutter/lib/src/services/dom.dart | 16 ++++++++-------- .../test/painting/_test_http_request.dart | 2 -- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart index ae583dc8ba80e..3e867ac23f0bb 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart @@ -1336,9 +1336,7 @@ void registerEngineBenchmarkValueListener(String name, EngineBenchmarkValueListe if (_engineBenchmarkListeners.isEmpty) { // The first listener is being registered. Register the global listener. web.window['_flutter_internal_on_benchmark'.toJS] = - // Upcast to [Object] to export. - // ignore: unnecessary_cast - (_dispatchEngineBenchmarkValue as Object).toJS; + _dispatchEngineBenchmarkValue.toJS; } _engineBenchmarkListeners[name] = listener; } diff --git a/packages/flutter/lib/src/services/dom.dart b/packages/flutter/lib/src/services/dom.dart index 00d3770949b3d..42235a84cf505 100644 --- a/packages/flutter/lib/src/services/dom.dart +++ b/packages/flutter/lib/src/services/dom.dart @@ -117,7 +117,7 @@ extension DomXMLHttpRequestExtension on DomXMLHttpRequest { external JSNumber? get _status; /// Gets the status. - int? get status => _status?.toDart.toInt(); + int? get status => _status?.toDartInt; @JS('responseType') external set _responseType(JSString value); @@ -184,13 +184,13 @@ extension DomProgressEventExtension on DomProgressEvent { external JSNumber? get _loaded; /// Amount of work done. - int? get loaded => _loaded?.toDart.toInt(); + int? get loaded => _loaded?.toDartInt; @JS('total') external JSNumber? get _total; /// Total amount of work. - int? get total => _total?.toDart.toInt(); + int? get total => _total?.toDartInt; } /// The underlying DOM document. @@ -291,19 +291,19 @@ extension DomMouseEventExtension on DomMouseEvent { external JSNumber get _offsetX; /// Returns the current x offset. - num get offsetX => _offsetX.toDart; + num get offsetX => _offsetX.toDartDouble; @JS('offsetY') external JSNumber get _offsetY; /// Returns the current y offset. - num get offsetY => _offsetY.toDart; + num get offsetY => _offsetY.toDartDouble; @JS('button') external JSNumber get _button; /// Returns the current button. - int get button => _button.toDart.toInt(); + int get button => _button.toDartInt; } /// A DOM selection. @@ -394,9 +394,9 @@ extension DomCSSStyleSheetExtension on DomCSSStyleSheet { /// Inserts a rule into this style sheet. int insertRule(String rule, [int? index]) { if (index == null) { - return _insertRule1(rule.toJS).toDart.toInt(); + return _insertRule1(rule.toJS).toDartInt; } else { - return _insertRule2(rule.toJS, index.toDouble().toJS).toDart.toInt(); + return _insertRule2(rule.toJS, index.toJS).toDartInt; } } } diff --git a/packages/flutter/test/painting/_test_http_request.dart b/packages/flutter/test/painting/_test_http_request.dart index 8324d9b5e2a86..ccfbf1d752af9 100644 --- a/packages/flutter/test/painting/_test_http_request.dart +++ b/packages/flutter/test/painting/_test_http_request.dart @@ -43,8 +43,6 @@ class TestHttpRequest { setRequestHeader: setRequestHeader.toJS, addEventListener: addEventListener.toJS, ); - // TODO(srujzs): This is needed for when we reify JS types. Right now, JSAny - // is a typedef for Object?, but when we reify, it'll be its own type. final JSAny mock = _mock as JSAny; createGetter(mock, 'headers', () => headers.jsify()); createGetter(mock, From dd0b6e35f363c04991f172b4219188740d5ae112 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:27:37 -0700 Subject: [PATCH 0110/1547] Update `Checkbox` tests for M2/M3 (#130351) Updated unit tests for `Checkbox` to have M2 and M3 versions. More info in #127064 --- .../flutter/test/material/checkbox_test.dart | 527 +++++++++++++++--- 1 file changed, 460 insertions(+), 67 deletions(-) diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart index 8a7a592f24e12..919ee8d267165 100644 --- a/packages/flutter/test/material/checkbox_test.dart +++ b/packages/flutter/test/material/checkbox_test.dart @@ -414,7 +414,8 @@ void main() { semanticsTester.dispose(); }); - testWidgets('Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { + testWidgets('Material2 - Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); Widget buildFrame(bool? checkboxValue) { return Theme( data: theme, @@ -446,8 +447,8 @@ void main() { await tester.pumpAndSettle(); expect(getCheckboxRenderer(), paints - ..path(color: theme.useMaterial3 ? theme.colorScheme.primary : theme.colorScheme.secondary) - ..path(color: theme.useMaterial3 ? theme.colorScheme.onPrimary : const Color(0xFFFFFFFF)) + ..path(color: theme.colorScheme.secondary) + ..path(color: const Color(0xFFFFFFFF)) ); // checkmark is rendered as a path await tester.pumpWidget(buildFrame(false)); @@ -464,8 +465,8 @@ void main() { await tester.pumpAndSettle(); expect(getCheckboxRenderer(), paints - ..path(color: theme.useMaterial3 ? theme.colorScheme.primary : theme.colorScheme.secondary) - ..path(color: theme.useMaterial3 ? theme.colorScheme.onPrimary : const Color(0xFFFFFFFF)) + ..path(color: theme.colorScheme.secondary) + ..path(color: const Color(0xFFFFFFFF)) ); // checkmark is rendered as a path await tester.pumpWidget(buildFrame(null)); @@ -473,10 +474,69 @@ void main() { expect(getCheckboxRenderer(), paints..line()); // null is rendered as a line (a "dash") }); - testWidgets('Checkbox color rendering', (WidgetTester tester) async { - final ThemeData theme = ThemeData(); + testWidgets('Material3 - Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + Widget buildFrame(bool? checkboxValue) { + return Theme( + data: theme, + child: Material( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Checkbox( + tristate: true, + value: checkboxValue, + onChanged: (bool? value) { }, + ); + }, + ), + ), + ); + } + + RenderBox getCheckboxRenderer() { + return tester.renderObject(find.byType(Checkbox)); + } + + await tester.pumpWidget(buildFrame(false)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..path(color: Colors.transparent)); // paint transparent border + expect(getCheckboxRenderer(), isNot(paints..line())); // null is rendered as a line (a "dash") + expect(getCheckboxRenderer(), paints..drrect()); // empty checkbox + + await tester.pumpWidget(buildFrame(true)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), + paints + ..path(color: theme.colorScheme.primary) + ..path(color: theme.colorScheme.onPrimary) + ); // checkmark is rendered as a path + + await tester.pumpWidget(buildFrame(false)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..path(color: Colors.transparent)); // paint transparent border + expect(getCheckboxRenderer(), isNot(paints..line())); // null is rendered as a line (a "dash") + expect(getCheckboxRenderer(), paints..drrect()); // empty checkbox + + await tester.pumpWidget(buildFrame(null)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..line()); // null is rendered as a line (a "dash") + + await tester.pumpWidget(buildFrame(true)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), + paints + ..path(color: theme.colorScheme.primary) + ..path(color: theme.colorScheme.onPrimary) + ); // checkmark is rendered as a path + + await tester.pumpWidget(buildFrame(null)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..line()); // null is rendered as a line (a "dash") + }); + + testWidgets('Material2 - Checkbox color rendering', (WidgetTester tester) async { + ThemeData theme = ThemeData(useMaterial3: false); const Color borderColor = Color(0xff2196f3); - const Color m3BorderColor = Color(0xFF6750A4); Color checkColor = const Color(0xffFFFFFF); Color activeColor; @@ -504,24 +564,20 @@ void main() { await tester.pumpWidget(buildFrame(checkColor: checkColor)); await tester.pumpAndSettle(); - expect(getCheckboxRenderer(), paints..path(color: theme.useMaterial3 ? m3BorderColor : borderColor)..path(color: checkColor)); // paints's color is 0xFFFFFFFF (default color) + expect(getCheckboxRenderer(), paints..path(color: borderColor)..path(color: checkColor)); // paints's color is 0xFFFFFFFF (default color) checkColor = const Color(0xFF000000); await tester.pumpWidget(buildFrame(checkColor: checkColor)); await tester.pumpAndSettle(); - expect(getCheckboxRenderer(), paints..path(color: theme.useMaterial3 ? m3BorderColor : borderColor)..path(color: checkColor)); // paints's color is 0xFF000000 (params) + expect(getCheckboxRenderer(), paints..path(color: borderColor)..path(color: checkColor)); // paints's color is 0xFF000000 (params) activeColor = const Color(0xFF00FF00); - ThemeData themeData = ThemeData(); - final bool material3 = themeData.useMaterial3; - final ColorScheme colorScheme = material3 - ? const ColorScheme.light().copyWith(primary: activeColor) - : const ColorScheme.light().copyWith(secondary: activeColor); - themeData = themeData.copyWith(colorScheme: colorScheme); + final ColorScheme colorScheme = const ColorScheme.light().copyWith(secondary: activeColor); + theme = theme.copyWith(colorScheme: colorScheme); await tester.pumpWidget(buildFrame( - themeData: themeData), + themeData: theme), ); await tester.pumpAndSettle(); expect(getCheckboxRenderer(), paints..path(color: activeColor)); // paints's color is 0xFF00FF00 (theme) @@ -530,11 +586,135 @@ void main() { await tester.pumpWidget(buildFrame(activeColor: activeColor)); await tester.pumpAndSettle(); - expect(getCheckboxRenderer(), paints..path(color: activeColor)); // paints's color is 0xFF000000 (params) + expect(getCheckboxRenderer(), paints..path(color: activeColor)); }); - testWidgets('Checkbox is focusable and has correct focus color', (WidgetTester tester) async { + testWidgets('Material3 - Checkbox color rendering', (WidgetTester tester) async { + ThemeData theme = ThemeData(useMaterial3: true); + const Color borderColor = Color(0xFF6750A4); + Color checkColor = const Color(0xffFFFFFF); + Color activeColor; + + Widget buildFrame({Color? activeColor, Color? checkColor, ThemeData? themeData}) { + return Material( + child: Theme( + data: themeData ?? theme, + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Checkbox( + value: true, + activeColor: activeColor, + checkColor: checkColor, + onChanged: (bool? value) { }, + ); + }, + ), + ), + ); + } + + RenderBox getCheckboxRenderer() { + return tester.renderObject(find.byType(Checkbox)); + } + + await tester.pumpWidget(buildFrame(checkColor: checkColor)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..path(color: borderColor)..path(color: checkColor)); // paints's color is 0xFFFFFFFF (default color) + + checkColor = const Color(0xFF000000); + + await tester.pumpWidget(buildFrame(checkColor: checkColor)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..path(color: borderColor)..path(color: checkColor)); // paints's color is 0xFF000000 (params) + + activeColor = const Color(0xFF00FF00); + + final ColorScheme colorScheme = const ColorScheme.light().copyWith(primary: activeColor); + theme = theme.copyWith(colorScheme: colorScheme); + await tester.pumpWidget(buildFrame(themeData: theme)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..path(color: activeColor)); // paints's color is 0xFF00FF00 (theme) + + activeColor = const Color(0xFF000000); + + await tester.pumpWidget(buildFrame(activeColor: activeColor)); + await tester.pumpAndSettle(); + expect(getCheckboxRenderer(), paints..path(color: activeColor)); + }); + + testWidgets('Material2 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + bool? value = true; + Widget buildApp({bool enabled = true}) { + return MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Material( + child: Center( + child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { + return Checkbox( + value: value, + onChanged: enabled ? (bool? newValue) { + setState(() { + value = newValue; + }); + } : null, + focusColor: Colors.orange[500], + autofocus: true, + focusNode: focusNode, + ); + }), + ), + ), + ); + } + await tester.pumpWidget(buildApp()); + + await tester.pumpAndSettle(); + expect(focusNode.hasPrimaryFocus, isTrue); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints + ..circle(color: Colors.orange[500]) + ..path(color: const Color(0xff2196f3)) + ..path(color: Colors.white) + ); + + // Check the false value. + value = false; + await tester.pumpWidget(buildApp()); + await tester.pumpAndSettle(); + expect(focusNode.hasPrimaryFocus, isTrue); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints + ..circle(color: Colors.orange[500]) + ..drrect( + color: const Color(0x8a000000), + outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)), + inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, Radius.zero), + ), + ); + + // Check what happens when disabled. + value = false; + await tester.pumpWidget(buildApp(enabled: false)); + await tester.pumpAndSettle(); + expect(focusNode.hasPrimaryFocus, isFalse); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints + ..drrect( + color: const Color(0x61000000), + outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(1.0)), + inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, Radius.zero), + ), + ); + }); + + testWidgets('Material3 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + final ThemeData theme = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp({bool enabled = true}) { @@ -562,19 +742,13 @@ void main() { await tester.pumpWidget(buildApp()); await tester.pumpAndSettle(); - final bool material3 = theme.useMaterial3; expect(focusNode.hasPrimaryFocus, isTrue); expect( Material.of(tester.element(find.byType(Checkbox))), - material3 - ? (paints - ..circle(color: Colors.orange[500]) - ..path(color: theme.colorScheme.primary) - ..path(color: theme.colorScheme.onPrimary)) - : (paints - ..circle(color: Colors.orange[500]) - ..path(color: const Color(0xff2196f3)) - ..path(color: Colors.white)) + paints + ..circle(color: Colors.orange[500]) + ..path(color: theme.colorScheme.primary) + ..path(color: theme.colorScheme.onPrimary) ); // Check the false value. @@ -587,8 +761,8 @@ void main() { paints ..circle(color: Colors.orange[500]) ..drrect( - color: material3 ? theme.colorScheme.onSurface : const Color(0x8a000000), - outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, material3 ? const Radius.circular(2.0) : const Radius.circular(1.0)), + color: theme.colorScheme.onSurface, + outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(2.0)), inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, Radius.zero), ), ); @@ -602,8 +776,8 @@ void main() { Material.of(tester.element(find.byType(Checkbox))), paints ..drrect( - color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000), - outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, material3 ? const Radius.circular(2.0) : const Radius.circular(1.0)), + color: theme.colorScheme.onSurface.withOpacity(0.38), + outer: RRect.fromLTRBR(15.0, 15.0, 33.0, 33.0, const Radius.circular(2.0)), inner: RRect.fromLTRBR(17.0, 17.0, 31.0, 31.0, Radius.zero), ), ); @@ -670,10 +844,67 @@ void main() { ); }); - testWidgets('Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgets('Material2 - Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + bool? value = true; + final ThemeData theme = ThemeData(useMaterial3: false); + Widget buildApp({bool enabled = true}) { + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: StatefulBuilder(builder: (BuildContext context, StateSetter setState) { + return Checkbox( + value: value, + onChanged: enabled ? (bool? newValue) { + setState(() { + value = newValue; + }); + } : null, + hoverColor: Colors.orange[500], + ); + }), + ), + ), + ); + } + await tester.pumpWidget(buildApp()); + await tester.pumpAndSettle(); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints + ..path(color: const Color(0xff2196f3)) + ..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ); + + // Start hovering + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.moveTo(tester.getCenter(find.byType(Checkbox))); + + await tester.pumpWidget(buildApp()); + await tester.pumpAndSettle(); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints + ..path(color: const Color(0xff2196f3)) + ..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ); + + // Check what happens when disabled. + await tester.pumpWidget(buildApp(enabled: false)); + await tester.pumpAndSettle(); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints + ..path(color: const Color(0x61000000)) + ..path(color: const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ); + }); + + testWidgets('Material3 - Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; - final bool material3 = theme.useMaterial3; + final ThemeData theme = ThemeData(useMaterial3: true); Widget buildApp({bool enabled = true}) { return MaterialApp( theme: theme, @@ -699,8 +930,8 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), paints - ..path(color: material3 ? const Color(0xff6750a4) : const Color(0xff2196f3)) - ..path(color: material3 ? theme.colorScheme.onPrimary : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ..path(color: const Color(0xff6750a4)) + ..path(color: theme.colorScheme.onPrimary, style: PaintingStyle.stroke, strokeWidth: 2.0), ); // Start hovering @@ -712,8 +943,8 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), paints - ..path(color: material3 ? const Color(0xff6750a4) : const Color(0xff2196f3)) - ..path(color: material3 ? theme.colorScheme.onPrimary : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ..path(color: const Color(0xff6750a4)) + ..path(color: theme.colorScheme.onPrimary, style: PaintingStyle.stroke, strokeWidth: 2.0), ); // Check what happens when disabled. @@ -722,8 +953,8 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), paints - ..path(color: material3 ? theme.colorScheme.onSurface.withOpacity(0.38) : const Color(0x61000000)) - ..path(color: material3 ? theme.colorScheme.surface : const Color(0xffffffff), style: PaintingStyle.stroke, strokeWidth: 2.0), + ..path(color: theme.colorScheme.onSurface.withOpacity(0.38)) + ..path(color: theme.colorScheme.surface, style: PaintingStyle.stroke, strokeWidth: 2.0), ); }); @@ -1108,12 +1339,12 @@ void main() { ); }); - testWidgets('Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { + testWidgets('Material2 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + final ThemeData theme = ThemeData(useMaterial3: false); final ColorScheme colors = theme.colorScheme; - final bool material3 = theme.useMaterial3; Widget buildCheckbox({bool active = false, bool focused = false}) { return MaterialApp( theme: theme, @@ -1134,11 +1365,8 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), - material3 - ? (paints..circle(color: colors.primary.withOpacity(0.12))) - : (paints - ..circle(color: theme.unselectedWidgetColor.withAlpha(kRadialReactionAlpha),) - ), + paints + ..circle(color: theme.unselectedWidgetColor.withAlpha(kRadialReactionAlpha)), reason: 'Default inactive pressed Checkbox should have overlay color from default fillColor', ); @@ -1148,11 +1376,73 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), - material3 - ? (paints..circle(color: colors.onSurface.withOpacity(0.12))) - : (paints - ..circle(color: colors.secondary.withAlpha(kRadialReactionAlpha),) + paints + ..circle(color: colors.secondary.withAlpha(kRadialReactionAlpha)), + reason: 'Default active pressed Checkbox should have overlay color from default fillColor', + ); + + await tester.pumpWidget(Container()); // reset test + await tester.pumpWidget(buildCheckbox(focused: true)); + await tester.pumpAndSettle(); + + expect(focusNode.hasPrimaryFocus, isTrue); + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints..circle(color: theme.focusColor), + reason: 'Focused Checkbox should use default focused overlay color', + ); + + await tester.pumpWidget(Container()); // reset test + await tester.pumpWidget(buildCheckbox()); + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints..circle(color: theme.hoverColor), + reason: 'Hovered Checkbox should use default hovered overlay color', + ); + }); + + testWidgets('Material3 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + + final ThemeData theme = ThemeData(useMaterial3: true); + final ColorScheme colors = theme.colorScheme; + Widget buildCheckbox({bool active = false, bool focused = false}) { + return MaterialApp( + theme: theme, + home: Scaffold( + body: Checkbox( + focusNode: focusNode, + autofocus: focused, + value: active, + onChanged: (_) { }, + ), ), + ); + } + + await tester.pumpWidget(buildCheckbox()); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints..circle(color: colors.primary.withOpacity(0.12)), + reason: 'Default inactive pressed Checkbox should have overlay color from default fillColor', + ); + + await tester.pumpWidget(buildCheckbox(active: true)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints..circle(color: colors.onSurface.withOpacity(0.12)), reason: 'Default active pressed Checkbox should have overlay color from default fillColor', ); @@ -1163,9 +1453,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isTrue); expect( Material.of(tester.element(find.byType(Checkbox))), - material3 - ? (paints..circle(color: colors.onSurface.withOpacity(0.12))) - : (paints..circle(color: theme.focusColor)), + paints..circle(color: colors.onSurface.withOpacity(0.12)), reason: 'Focused Checkbox should use default focused overlay color', ); @@ -1178,9 +1466,7 @@ void main() { expect( Material.of(tester.element(find.byType(Checkbox))), - material3 - ? (paints..circle(color: colors.onSurface.withOpacity(0.08))) - : (paints..circle(color: theme.hoverColor)), + paints..circle(color: colors.onSurface.withOpacity(0.08)), reason: 'Hovered Checkbox should use default hovered overlay color', ); }); @@ -1516,13 +1802,13 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: activeColor)); // checkbox fill }); - testWidgets('Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { + testWidgets('Material2 - Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { const Color borderColor = Color(0xfff44336); const BorderSide side = BorderSide( width: 4, color: borderColor, ); - final bool material3 = theme.useMaterial3; + final ThemeData theme = ThemeData(useMaterial3: false); Widget buildApp({ bool? value, bool enabled = true }) { return MaterialApp( @@ -1546,7 +1832,7 @@ void main() { paints ..drrect( color: borderColor, - outer: material3 ? RRect.fromLTRBR(15, 15, 33, 33, const Radius.circular(2)) : RRect.fromLTRBR(15, 15, 33, 33, const Radius.circular(1)), + outer: RRect.fromLTRBR(15, 15, 33, 33, const Radius.circular(1)), inner: RRect.fromLTRBR(19, 19, 29, 29, Radius.zero), ), ); @@ -1570,6 +1856,60 @@ void main() { expectBorder(); }); + testWidgets('Material3 - Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { + const Color borderColor = Color(0xfff44336); + const BorderSide side = BorderSide( + width: 4, + color: borderColor, + ); + final ThemeData theme = ThemeData(useMaterial3: true); + + Widget buildApp({ bool? value, bool enabled = true }) { + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: Checkbox( + value: value, + tristate: value == null, + onChanged: enabled ? (bool? newValue) { } : null, + side: MaterialStateBorderSide.resolveWith((Set states) => side), + ), + ), + ), + ); + } + + void expectBorder() { + expect( + tester.renderObject(find.byType(Checkbox)), + paints + ..drrect( + color: borderColor, + outer: RRect.fromLTRBR(15, 15, 33, 33, const Radius.circular(2)), + inner: RRect.fromLTRBR(19, 19, 29, 29, Radius.zero), + ), + ); + } + + await tester.pumpWidget(buildApp(value: false)); + await tester.pumpAndSettle(); + expectBorder(); + + + await tester.pumpWidget(buildApp(value: false, enabled: false)); + await tester.pumpAndSettle(); + expectBorder(); + + await tester.pumpWidget(buildApp(value: true)); + await tester.pumpAndSettle(); + expectBorder(); + + await tester.pumpWidget(buildApp()); + await tester.pumpAndSettle(); + expectBorder(); + }); + testWidgets('disabled checkbox shows tooltip', (WidgetTester tester) async { const String longPressTooltip = 'long press tooltip'; const String tapTooltip = 'tap tooltip'; @@ -1624,7 +1964,7 @@ void main() { expect(find.text(tapTooltip), findsOneWidget); }); - testWidgets('Checkbox has default error color when isError is set to true - M3', (WidgetTester tester) async { + testWidgets('Material3 - Checkbox has default error color when isError is set to true', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); final ThemeData themeData = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -1696,7 +2036,7 @@ void main() { await tester.pump(); }); - testWidgets('Checkbox MaterialStateBorderSide applies in error states - M3', (WidgetTester tester) async { + testWidgets('Material3 - Checkbox MaterialStateBorderSide applies in error states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); final ThemeData themeData = ThemeData(useMaterial3: true); const Color borderColor = Color(0xffffeb3b); @@ -1775,7 +2115,7 @@ void main() { await tester.pump(); }); - testWidgets('Checkbox has correct default shape - M3', (WidgetTester tester) async { + testWidgets('Material3 - Checkbox has correct default shape', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); Widget buildApp() { @@ -1841,7 +2181,8 @@ void main() { } }); - testWidgets('Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { + testWidgets('Material2 - Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); const Color activeBackgroundColor = Color(0xff123456); const Color inactiveBackgroundColor = Color(0xff654321); @@ -1870,14 +2211,66 @@ void main() { } // Checkbox is unselected, so the default BorderSide appears and fillColor is checkbox's background color. + await tester.pumpWidget(buildApp()); + await tester.pumpAndSettle(); + expect( + getCheckboxRenderer(), + paints + ..drrect( + color: theme.unselectedWidgetColor, + ), + ); + expect(getCheckboxRenderer(), paints..path(color: inactiveBackgroundColor)); + + await tester.pumpWidget(buildApp(enabled: false)); + await tester.pumpAndSettle(); + expect( + getCheckboxRenderer(), + paints + ..drrect( + color: theme.disabledColor, + ), + ); + expect(getCheckboxRenderer(), paints..path(color: inactiveBackgroundColor)); + }); + + testWidgets('Material3 - Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + const Color activeBackgroundColor = Color(0xff123456); + const Color inactiveBackgroundColor = Color(0xff654321); + + Widget buildApp({ bool enabled = true }) { + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: Checkbox( + fillColor: MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return activeBackgroundColor; + } + return inactiveBackgroundColor; + }), + value: false, + onChanged: enabled ? (bool? newValue) { } : null, + ), + ), + ), + ); + } + RenderBox getCheckboxRenderer() { + return tester.renderObject(find.byType(Checkbox)); + } + + // Checkbox is unselected, so the default BorderSide appears and fillColor is checkbox's background color. await tester.pumpWidget(buildApp()); await tester.pumpAndSettle(); expect( getCheckboxRenderer(), paints ..drrect( - color: theme.useMaterial3 ? theme.colorScheme.onSurfaceVariant : theme.unselectedWidgetColor, + color: theme.colorScheme.onSurfaceVariant, ), ); expect(getCheckboxRenderer(), paints..path(color: inactiveBackgroundColor)); @@ -1888,7 +2281,7 @@ void main() { getCheckboxRenderer(), paints ..drrect( - color: theme.useMaterial3 ? theme.colorScheme.onSurface.withOpacity(0.38) : theme.disabledColor, + color: theme.colorScheme.onSurface.withOpacity(0.38), ), ); expect(getCheckboxRenderer(), paints..path(color: inactiveBackgroundColor)); From 2da353a59ae756e286ae131a04e25e4ccf321f31 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 12 Jul 2023 17:35:57 -0700 Subject: [PATCH 0111/1547] Exclude `Tooltip`'s overlay child from SelectableRegion (#130181) Fixes https://github.com/flutter/flutter/issues/129969 by making tooltip text unselectable (for now). Also fixes some other issues uncovered when I was writing the tests. Currently `getTransformTo` only works on ancestors. I'll try to add a new method that computes the transform from 2 arbitrary render objects in the same render tree in a follow-up PR and make `Selectable` use that method instead. --- .../lib/src/material/selection_area.dart | 28 ++---- .../flutter/lib/src/material/tooltip.dart | 19 +++- packages/flutter/lib/src/widgets/overlay.dart | 1 + .../flutter/test/material/tooltip_test.dart | 91 +++++++++++++++++++ 4 files changed, 115 insertions(+), 24 deletions(-) diff --git a/packages/flutter/lib/src/material/selection_area.dart b/packages/flutter/lib/src/material/selection_area.dart index 625f3aa1afaab..2334f545cc3bf 100644 --- a/packages/flutter/lib/src/material/selection_area.dart +++ b/packages/flutter/lib/src/material/selection_area.dart @@ -103,13 +103,7 @@ class SelectionArea extends StatefulWidget { } class _SelectionAreaState extends State { - FocusNode get _effectiveFocusNode { - if (widget.focusNode != null) { - return widget.focusNode!; - } - _internalNode ??= FocusNode(); - return _internalNode!; - } + FocusNode get _effectiveFocusNode => widget.focusNode ?? (_internalNode ??= FocusNode()); FocusNode? _internalNode; @override @@ -121,20 +115,12 @@ class _SelectionAreaState extends State { @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); - TextSelectionControls? controls = widget.selectionControls; - switch (Theme.of(context).platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - controls ??= materialTextSelectionHandleControls; - case TargetPlatform.iOS: - controls ??= cupertinoTextSelectionHandleControls; - case TargetPlatform.linux: - case TargetPlatform.windows: - controls ??= desktopTextSelectionHandleControls; - case TargetPlatform.macOS: - controls ??= cupertinoDesktopTextSelectionHandleControls; - } - + final TextSelectionControls controls = widget.selectionControls ?? switch (Theme.of(context).platform) { + TargetPlatform.android || TargetPlatform.fuchsia => materialTextSelectionHandleControls, + TargetPlatform.linux || TargetPlatform.windows => desktopTextSelectionHandleControls, + TargetPlatform.iOS => cupertinoTextSelectionHandleControls, + TargetPlatform.macOS => cupertinoDesktopTextSelectionHandleControls, + }; return SelectableRegion( selectionControls: controls, focusNode: _effectiveFocusNode, diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart index 045d97d767c2f..2be81e1ba51cc 100644 --- a/packages/flutter/lib/src/material/tooltip.dart +++ b/packages/flutter/lib/src/material/tooltip.dart @@ -482,13 +482,16 @@ class TooltipState extends State with SingleTickerProviderStateMixin { void _scheduleDismissTooltip({ required Duration withDelay }) { assert(mounted); assert( - !(_timer?.isActive ?? false) || _controller.status != AnimationStatus.reverse, + !(_timer?.isActive ?? false) || _backingController?.status != AnimationStatus.reverse, 'timer must not be active when the tooltip is fading out', ); _timer?.cancel(); _timer = null; - switch (_controller.status) { + // Use _backingController instead of _controller to prevent the lazy getter + // from instaniating an AnimationController unnecessarily. + switch (_backingController?.status) { + case null: case AnimationStatus.reverse: case AnimationStatus.dismissed: break; @@ -740,7 +743,7 @@ class TooltipState extends State with SingleTickerProviderStateMixin { }; final TooltipThemeData tooltipTheme = _tooltipTheme; - return _TooltipOverlay( + final _TooltipOverlay overlayChild = _TooltipOverlay( richMessage: widget.richMessage ?? TextSpan(text: widget.message), height: widget.height ?? tooltipTheme.height ?? _getDefaultTooltipHeight(), padding: widget.padding ?? tooltipTheme.padding ?? _getDefaultPadding(), @@ -755,13 +758,23 @@ class TooltipState extends State with SingleTickerProviderStateMixin { verticalOffset: widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset, preferBelow: widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow, ); + + return SelectionContainer.maybeOf(context) == null + ? overlayChild + : SelectionContainer.disabled(child: overlayChild); } @override void dispose() { GestureBinding.instance.pointerRouter.removeGlobalRoute(_handleGlobalPointerEvent); Tooltip._openedTooltips.remove(this); + // _longPressRecognizer.dispose() and _tapRecognizer.dispose() may call + // their registered onCancel callbacks if there's a gesture in progress. + // Remove the onCancel callbacks to prevent the registered callbacks from + // triggering unnecessary side effects (such as animations). + _longPressRecognizer?.onLongPressCancel = null; _longPressRecognizer?.dispose(); + _tapRecognizer?.onTapCancel = null; _tapRecognizer?.dispose(); _timer?.cancel(); _backingController?.dispose(); diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index c3e71dfcafead..6b2427662a639 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -1569,6 +1569,7 @@ class _OverlayPortalState extends State { @override void dispose() { + assert(widget.controller._attachTarget == this); widget.controller._attachTarget = null; _locationCache?._debugMarkLocationInvalid(); _locationCache = null; diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 544f88324720f..84d637190d762 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -2278,6 +2278,97 @@ void main() { await tester.pump(const Duration(seconds: 1)); expect(element.dirty, isFalse); }); + + testWidgets('Tooltip does not initialize animation controller in dispose process', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Center( + child: Tooltip( + message: tooltipText, + waitDuration: Duration(seconds: 1), + triggerMode: TooltipTriggerMode.longPress, + child: SizedBox.square(dimension: 50), + ), + ), + ), + ); + + await tester.startGesture(tester.getCenter(find.byType(Tooltip))); + await tester.pumpWidget(const SizedBox()); + expect(tester.takeException(), isNull); + }); + + testWidgets('Tooltip does not crash when showing the tooltip but the OverlayPortal is unmounted, during dispose', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: SelectionArea( + child: Center( + child: Tooltip( + message: tooltipText, + waitDuration: Duration(seconds: 1), + triggerMode: TooltipTriggerMode.longPress, + child: SizedBox.square(dimension: 50), + ), + ), + ), + ), + ); + + final TooltipState tooltipState = tester.state(find.byType(Tooltip)); + await tester.startGesture(tester.getCenter(find.byType(Tooltip))); + tooltipState.ensureTooltipVisible(); + await tester.pumpWidget(const SizedBox()); + expect(tester.takeException(), isNull); + }); + + testWidgets('Tooltip is not selectable', (WidgetTester tester) async { + const String tooltipText = 'AAAAAAAAAAAAAAAAAAAAAAA'; + String? selectedText; + await tester.pumpWidget( + MaterialApp( + home: SelectionArea( + onSelectionChanged: (SelectedContent? content) { selectedText = content?.plainText; }, + child: const Center( + child: Column( + children: [ + Text('Select Me'), + Tooltip( + message: tooltipText, + waitDuration: Duration(seconds: 1), + triggerMode: TooltipTriggerMode.longPress, + child: SizedBox.square(dimension: 50), + ), + ], + ), + ), + ), + ), + ); + + final TooltipState tooltipState = tester.state(find.byType(Tooltip)); + + final Rect textRect = tester.getRect(find.text('Select Me')); + final TestGesture gesture = await tester.startGesture(Alignment.centerLeft.alongSize(textRect.size) + textRect.topLeft); + // Drag from centerLeft to centerRight to select the text. + await tester.pump(const Duration(seconds: 1)); + await gesture.moveTo(Alignment.centerRight.alongSize(textRect.size) + textRect.topLeft); + await tester.pump(); + + tooltipState.ensureTooltipVisible(); + await tester.pump(); + // Make sure the tooltip becomes visible. + expect(find.text(tooltipText), findsOneWidget); + assert(selectedText != null); + + final Rect tooltipTextRect = tester.getRect(find.text(tooltipText)); + // Now drag from centerLeft to centerRight to select the tooltip text. + await gesture.moveTo(Alignment.centerLeft.alongSize(tooltipTextRect.size) + tooltipTextRect.topLeft); + await tester.pump(); + await gesture.moveTo(Alignment.centerRight.alongSize(tooltipTextRect.size) + tooltipTextRect.topLeft); + await tester.pump(); + + expect(selectedText, isNot(contains('A'))); + }); } Future setWidgetForTooltipMode( From 47ba59c762919d66811b72acab9732d6aa2a93c9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 12 Jul 2023 20:46:57 -0400 Subject: [PATCH 0112/1547] Roll Flutter Engine from 16e2ab7e986c to 1b1ccdd1f527 (13 revisions) (#130458) https://github.com/flutter/engine/compare/16e2ab7e986c...1b1ccdd1f527 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 4e989b1564ee to bedc92598644 (1 revision) (flutter/engine#43617) 2023-07-12 flar@google.com move rtree and canvas_spy sources to Fuchsia sub-directory (flutter/engine#43615) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 68e3c0b3eea7 to 4e989b1564ee (6 revisions) (flutter/engine#43614) 2023-07-12 ian@hixie.ch Document (and assert) that channel names can't contains nulls (flutter/engine#43593) 2023-07-12 58529443+srujzs@users.noreply.github.com Reland "Refactor JSNumber.toDart and Object.toJS" (flutter/engine#43363) 2023-07-12 31859944+LongCatIsLooong@users.noreply.github.com Add a flag to `ParagraphBuilder` for rounding hack migration (flutter/engine#43118) 2023-07-12 john@johnmccutchan.com [Impeller] Fixes for asymmetric stencil descriptors (flutter/engine#43535) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from adeeb8d50f7c to 68e3c0b3eea7 (1 revision) (flutter/engine#43609) 2023-07-12 flar@google.com Add comment to use of 3x3 mapRect in TransformLayer (flutter/engine#43608) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from a251a36ea519 to adeeb8d50f7c (1 revision) (flutter/engine#43606) 2023-07-12 skia-flutter-autoroll@skia.org Roll Dart SDK from b95f6531c726 to 8f8f281ccdc6 (2 revisions) (flutter/engine#43607) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from ebc149cff431 to a251a36ea519 (2 revisions) (flutter/engine#43604) 2023-07-12 jonahwilliams@google.com [Impeller] Use new SkParagraph APIs for stroked text. (flutter/engine#41735) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2fe5c0f372fc1..05bb710821d11 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -16e2ab7e986c8c7ad2a704245df48ca96ea90948 +1b1ccdd1f527404a20656c8b1f8decd7061b0ba4 From c40173f114fa8b830531578586f4f4eedd2b2c1f Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 13 Jul 2023 08:02:39 -0700 Subject: [PATCH 0113/1547] Revert "Roll Flutter Engine from 16e2ab7e986c to 1b1ccdd1f527 (13 revisions)" (#130479) Reverts flutter/flutter#130458 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 05bb710821d11..2fe5c0f372fc1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1b1ccdd1f527404a20656c8b1f8decd7061b0ba4 +16e2ab7e986c8c7ad2a704245df48ca96ea90948 From 9f53df559f4195e3752896aa823dee9d83042056 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 13 Jul 2023 08:33:07 -0700 Subject: [PATCH 0114/1547] Correct a few import sortings (#130435) Move a few import directives to be in correct order. Fixes https://github.com/flutter/flutter/issues/130434 --- .../microbenchmarks/lib/gestures/gesture_detector_bench.dart | 2 +- dev/conductor/core/test/packages_autoroller_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/benchmarks/microbenchmarks/lib/gestures/gesture_detector_bench.dart b/dev/benchmarks/microbenchmarks/lib/gestures/gesture_detector_bench.dart index 717535f367da1..a5ca499555987 100644 --- a/dev/benchmarks/microbenchmarks/lib/gestures/gesture_detector_bench.dart +++ b/dev/benchmarks/microbenchmarks/lib/gestures/gesture_detector_bench.dart @@ -4,8 +4,8 @@ import 'package:flutter_test/flutter_test.dart'; -import './apps/button_matrix_app.dart' as button_matrix; import '../common.dart'; +import 'apps/button_matrix_app.dart' as button_matrix; const int _kNumWarmUpIters = 20; const int _kNumIters = 300; diff --git a/dev/conductor/core/test/packages_autoroller_test.dart b/dev/conductor/core/test/packages_autoroller_test.dart index 9ce7a282a6c33..3861759b9229b 100644 --- a/dev/conductor/core/test/packages_autoroller_test.dart +++ b/dev/conductor/core/test/packages_autoroller_test.dart @@ -11,8 +11,8 @@ import 'package:conductor_core/packages_autoroller.dart'; import 'package:file/memory.dart'; import 'package:platform/platform.dart'; -import './common.dart'; import '../bin/packages_autoroller.dart' show run; +import 'common.dart'; void main() { const String flutterRoot = '/flutter'; From fad8bbfbbe785f3f3be974012b01077f137e4e01 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 11:51:10 -0400 Subject: [PATCH 0115/1547] Roll Packages from 250871431bed to aa1eace00188 (6 revisions) (#130495) https://github.com/flutter/packages/compare/250871431bed...aa1eace00188 2023-07-13 ian@hixie.ch [rfw] Restore RFW to 100% coverage (flutter/packages#4355) 2023-07-12 65381000+raju8000@users.noreply.github.com [file_selector_web] Listens to file input cancel event. (flutter/packages#3683) 2023-07-12 sam.rawlins@gmail.com [cross_file] Correct sorting of import starting with dot-slash (flutter/packages#4449) 2023-07-12 ian@hixie.ch [metrics_center] Remove Equatable dependency (flutter/packages#4444) 2023-07-12 engine-flutter-autoroll@skia.org Roll Flutter from 3ec96a8a4a5d to 544d30dbaddf (66 revisions) (flutter/packages#4448) 2023-07-12 stuartmorgan@google.com [ci] Move snippet checks to LUCI (flutter/packages#4446) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 6dd2b6dcc8cb7..9e6a579ae5001 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -250871431bedcfab9ca38b8a5170ab8761810f64 +aa1eace001880d6e08f2b67ad3eed70241b5a1bc From 13283f86cb89b280047d8031a7fde110f09ac163 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 13 Jul 2023 08:55:36 -0700 Subject: [PATCH 0116/1547] Revert "Marks Linux firebase_oriol33_abstract_method_smoke_test to be unflaky" (#130497) Reverts flutter/flutter#128398 See e.g. https://ci.chromium.org/ui/p/flutter/builders/try/Linux%20firebase_oriol33_abstract_method_smoke_test/350/overview --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 78b22e1e4d3f7..385dbf30e4e31 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -412,6 +412,7 @@ targets: - .ci.yaml - name: Linux firebase_oriol33_abstract_method_smoke_test + bringup: true recipe: firebaselab/firebaselab timeout: 60 properties: From ee4208fd26abd5c91680b4aa185df0ae9e00ce61 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 12:21:24 -0400 Subject: [PATCH 0117/1547] Roll Flutter Engine from 16e2ab7e986c to b4080361f2f9 (28 revisions) (#130496) Roll Flutter Engine from 16e2ab7e986c to b4080361f2f9 (28 revisions) https://github.com/flutter/engine/compare/16e2ab7e986c...b4080361f2f9 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from e5ec341bc3ca to 56b68ce6196c (1 revision) (flutter/engine#43633) 2023-07-13 skia-flutter-autoroll@skia.org Roll Dart SDK from f499e91e8cb2 to ade4dae923f3 (1 revision) (flutter/engine#43632) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from 811b046c673b to e5ec341bc3ca (1 revision) (flutter/engine#43631) 2023-07-13 ian@hixie.ch Make GOMA state automatic by default (flutter/engine#43584) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from c8da0c657c4e to 811b046c673b (3 revisions) (flutter/engine#43630) 2023-07-13 chinmaygarde@google.com [Impeller] Remove unactionable error logs and use structure chains for instance creation. (flutter/engine#43629) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from 7f391ea9164e to c8da0c657c4e (1 revision) (flutter/engine#43628) 2023-07-13 chinmaygarde@google.com [Impeller] Add RAII wrappers for VMA objects. (flutter/engine#43626) 2023-07-13 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 1STsUj0X5YgpiSNEb... to xBJq6PsO5ebblODMe... (flutter/engine#43627) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from 6ed93436d57c to 7f391ea9164e (1 revision) (flutter/engine#43625) 2023-07-13 skia-flutter-autoroll@skia.org Roll Dart SDK from 8f8f281ccdc6 to f499e91e8cb2 (3 revisions) (flutter/engine#43623) 2023-07-13 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 0fvk838jTDNQ_l43k... to 3C7P0w8ySmtqpyi3S... (flutter/engine#43622) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from bedc92598644 to 6ed93436d57c (3 revisions) (flutter/engine#43621) 2023-07-13 jonahwilliams@google.com [Impeller] Add support to embedder for Impeller on GL (via Angle on Windows). (flutter/engine#43388) 2023-07-12 jonahwilliams@google.com [Impeller] Allocate buffers out of a pool on the raster thread. (flutter/engine#43564) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 4e989b1564ee to bedc92598644 (1 revision) (flutter/engine#43617) 2023-07-12 flar@google.com move rtree and canvas_spy sources to Fuchsia sub-directory (flutter/engine#43615) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from 68e3c0b3eea7 to 4e989b1564ee (6 revisions) (flutter/engine#43614) 2023-07-12 ian@hixie.ch Document (and assert) that channel names can't contains nulls (flutter/engine#43593) 2023-07-12 58529443+srujzs@users.noreply.github.com Reland "Refactor JSNumber.toDart and Object.toJS" (flutter/engine#43363) 2023-07-12 31859944+LongCatIsLooong@users.noreply.github.com Add a flag to `ParagraphBuilder` for rounding hack migration (flutter/engine#43118) 2023-07-12 john@johnmccutchan.com [Impeller] Fixes for asymmetric stencil descriptors (flutter/engine#43535) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from adeeb8d50f7c to 68e3c0b3eea7 (1 revision) (flutter/engine#43609) 2023-07-12 flar@google.com Add comment to use of 3x3 mapRect in TransformLayer (flutter/engine#43608) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from a251a36ea519 to adeeb8d50f7c (1 revision) (flutter/engine#43606) 2023-07-12 skia-flutter-autoroll@skia.org Roll Dart SDK from b95f6531c726 to 8f8f281ccdc6 (2 revisions) (flutter/engine#43607) 2023-07-12 skia-flutter-autoroll@skia.org Roll Skia from ebc149cff431 to a251a36ea519 (2 revisions) (flutter/engine#43604) 2023-07-12 jonahwilliams@google.com [Impeller] Use new SkParagraph APIs for stroked text. (flutter/engine#41735) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 1STsUj0X5Ygp to xBJq6PsO5ebb fuchsia/sdk/core/mac-amd64 from 0fvk838jTDNQ to 3C7P0w8ySmtq If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md ... --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2fe5c0f372fc1..15480cdffa675 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -16e2ab7e986c8c7ad2a704245df48ca96ea90948 +b4080361f2f9daba4626eac7a0c4616655e8a21e diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 1fa79f23e439a..195768f741a52 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -1STsUj0X5YgpiSNEbqRCus0XRGJ-uLoTCxmjIVMy_EoC +xBJq6PsO5ebblODMegtfmB5Q-Kaghtn_K0m3pR3dU60C diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 3ee92df67e9eb..f1ed94b7899ac 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -0fvk838jTDNQ_l43kj5Vz-3ZA1JntonkaLZ8UJxQSaUC +3C7P0w8ySmtqpyi3SZWDcHJ9zdLC09Fo45XjXGjJ1xQC From 60c1f3760945dd3b45a1f9f84c57c39a0cc0480c Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 13 Jul 2023 09:26:02 -0700 Subject: [PATCH 0118/1547] [flutter_tools] remove desktop device restrictions on Impeller. (#130430) All current desktop backends will support Impeller after https://github.com/flutter/engine/pull/43388 lands. --- .../flutter_tools/lib/src/desktop_device.dart | 16 +++----- .../lib/src/macos/macos_device.dart | 3 -- .../general.shard/desktop_device_test.dart | 40 +++++++++---------- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/packages/flutter_tools/lib/src/desktop_device.dart b/packages/flutter_tools/lib/src/desktop_device.dart index c8937258ddde4..83271771d758a 100644 --- a/packages/flutter_tools/lib/src/desktop_device.dart +++ b/packages/flutter_tools/lib/src/desktop_device.dart @@ -209,8 +209,6 @@ abstract class DesktopDevice extends Device { /// steps to be run. void onAttached(ApplicationPackage package, BuildInfo buildInfo, Process process) {} - bool get supportsImpeller => false; - /// Computes a set of environment variables used to pass debugging information /// to the engine without interfering with application level command line /// arguments. @@ -268,14 +266,12 @@ abstract class DesktopDevice extends Device { if (debuggingOptions.purgePersistentCache) { addFlag('purge-persistent-cache=true'); } - if (supportsImpeller) { - switch (debuggingOptions.enableImpeller) { - case ImpellerStatus.enabled: - addFlag('enable-impeller=true'); - case ImpellerStatus.disabled: - case ImpellerStatus.platformDefault: - addFlag('enable-impeller=false'); - } + switch (debuggingOptions.enableImpeller) { + case ImpellerStatus.enabled: + addFlag('enable-impeller=true'); + case ImpellerStatus.disabled: + case ImpellerStatus.platformDefault: + addFlag('enable-impeller=false'); } // Options only supported when there is a VM Service connection between the // tool and the device, usually in debug or profile mode. diff --git a/packages/flutter_tools/lib/src/macos/macos_device.dart b/packages/flutter_tools/lib/src/macos/macos_device.dart index 478c8ac27c125..43ada0af083c1 100644 --- a/packages/flutter_tools/lib/src/macos/macos_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_device.dart @@ -47,9 +47,6 @@ class MacOSDevice extends DesktopDevice { @override String get name => 'macOS'; - @override - bool get supportsImpeller => true; - @override Future get targetPlatform async => TargetPlatform.darwin; diff --git a/packages/flutter_tools/test/general.shard/desktop_device_test.dart b/packages/flutter_tools/test/general.shard/desktop_device_test.dart index 57631ac8fe70c..39890473e67ea 100644 --- a/packages/flutter_tools/test/general.shard/desktop_device_test.dart +++ b/packages/flutter_tools/test/general.shard/desktop_device_test.dart @@ -155,14 +155,15 @@ void main() { 'FLUTTER_ENGINE_SWITCH_10': 'dump-skp-on-shader-compilation=true', 'FLUTTER_ENGINE_SWITCH_11': 'cache-sksl=true', 'FLUTTER_ENGINE_SWITCH_12': 'purge-persistent-cache=true', - 'FLUTTER_ENGINE_SWITCH_13': 'enable-checked-mode=true', - 'FLUTTER_ENGINE_SWITCH_14': 'verify-entry-points=true', - 'FLUTTER_ENGINE_SWITCH_15': 'start-paused=true', - 'FLUTTER_ENGINE_SWITCH_16': 'disable-service-auth-codes=true', - 'FLUTTER_ENGINE_SWITCH_17': 'dart-flags=--null_assertions', - 'FLUTTER_ENGINE_SWITCH_18': 'use-test-fonts=true', - 'FLUTTER_ENGINE_SWITCH_19': 'verbose-logging=true', - 'FLUTTER_ENGINE_SWITCHES': '19', + 'FLUTTER_ENGINE_SWITCH_13': 'enable-impeller=false', + 'FLUTTER_ENGINE_SWITCH_14': 'enable-checked-mode=true', + 'FLUTTER_ENGINE_SWITCH_15': 'verify-entry-points=true', + 'FLUTTER_ENGINE_SWITCH_16': 'start-paused=true', + 'FLUTTER_ENGINE_SWITCH_17': 'disable-service-auth-codes=true', + 'FLUTTER_ENGINE_SWITCH_18': 'dart-flags=--null_assertions', + 'FLUTTER_ENGINE_SWITCH_19': 'use-test-fonts=true', + 'FLUTTER_ENGINE_SWITCH_20': 'verbose-logging=true', + 'FLUTTER_ENGINE_SWITCHES': '20', } ), ]); @@ -209,7 +210,8 @@ void main() { 'FLUTTER_ENGINE_SWITCH_2': 'trace-startup=true', 'FLUTTER_ENGINE_SWITCH_3': 'trace-allowlist=foo,bar', 'FLUTTER_ENGINE_SWITCH_4': 'cache-sksl=true', - 'FLUTTER_ENGINE_SWITCHES': '4', + 'FLUTTER_ENGINE_SWITCH_5': 'enable-impeller=false', + 'FLUTTER_ENGINE_SWITCHES': '5', } ), ]); @@ -301,7 +303,7 @@ void main() { ); }); - testWithoutContext('Desktop devices that support impeller pass through the enable-impeller flag', () async { + testWithoutContext('Desktop devices pass through the enable-impeller flag', () async { final FakeProcessManager processManager = FakeProcessManager.list([ const FakeCommand( command: ['debug'], @@ -317,7 +319,6 @@ void main() { ]); final FakeDesktopDevice device = setUpDesktopDevice( processManager: processManager, - supportsImpeller: true, ); final FakeApplicationPackage package = FakeApplicationPackage(); @@ -332,16 +333,17 @@ void main() { ); }); - testWithoutContext('Desktop devices that do not support impeller ignore the enable-impeller flag', () async { + testWithoutContext('Desktop devices pass through the --no-enable-impeller flag', () async { final FakeProcessManager processManager = FakeProcessManager.list([ const FakeCommand( command: ['debug'], exitCode: -1, environment: { 'FLUTTER_ENGINE_SWITCH_1': 'enable-dart-profiling=true', - 'FLUTTER_ENGINE_SWITCH_2': 'enable-checked-mode=true', - 'FLUTTER_ENGINE_SWITCH_3': 'verify-entry-points=true', - 'FLUTTER_ENGINE_SWITCHES': '3' + 'FLUTTER_ENGINE_SWITCH_2': 'enable-impeller=false', + 'FLUTTER_ENGINE_SWITCH_3': 'enable-checked-mode=true', + 'FLUTTER_ENGINE_SWITCH_4': 'verify-entry-points=true', + 'FLUTTER_ENGINE_SWITCHES': '4' } ), ]); @@ -355,7 +357,7 @@ void main() { prebuiltApplication: true, debuggingOptions: DebuggingOptions.enabled( BuildInfo.debug, - enableImpeller: ImpellerStatus.enabled, + enableImpeller: ImpellerStatus.disabled, dartEntrypointArgs: [], ), ); @@ -368,7 +370,6 @@ FakeDesktopDevice setUpDesktopDevice({ ProcessManager? processManager, OperatingSystemUtils? operatingSystemUtils, bool nullExecutablePathForDevice = false, - bool supportsImpeller = false, }) { return FakeDesktopDevice( fileSystem: fileSystem ?? MemoryFileSystem.test(), @@ -376,7 +377,6 @@ FakeDesktopDevice setUpDesktopDevice({ processManager: processManager ?? FakeProcessManager.any(), operatingSystemUtils: operatingSystemUtils ?? FakeOperatingSystemUtils(), nullExecutablePathForDevice: nullExecutablePathForDevice, - supportsImpeller: supportsImpeller, ); } @@ -388,7 +388,6 @@ class FakeDesktopDevice extends DesktopDevice { required FileSystem fileSystem, required OperatingSystemUtils operatingSystemUtils, this.nullExecutablePathForDevice = false, - this.supportsImpeller = false, }) : super( 'dummy', platformType: PlatformType.linux, @@ -407,9 +406,6 @@ class FakeDesktopDevice extends DesktopDevice { final bool nullExecutablePathForDevice; - @override - final bool supportsImpeller; - @override String get name => 'dummy'; From 604010e9e229222412054fe39377ee8669c22ab0 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:51:13 -0500 Subject: [PATCH 0119/1547] Print pretty error when xcodebuild fails due to missing simulator (#130286) Starting in Xcode 15, the simulator is no longer included in Xcode and must be downloaded and installed separately. If you try to run flutter and the simulator is missing, you'll get an error like ``` xcodebuild: error: Unable to find a destination matching the provided destination specifier: { id:B1234A5C-67B8-901D-B2CB-FE34F56BDE78 } Ineligible destinations for the "Runner" scheme: { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform } ``` Print a pretty error to make it easier for developers to know what to do. Part 2 of https://github.com/flutter/flutter/issues/129558. --- packages/flutter_tools/lib/src/ios/mac.dart | 50 +++- .../flutter_tools/lib/src/ios/xcresult.dart | 88 +++++++ .../hermetic/build_ios_test.dart | 31 +++ .../test/general.shard/ios/mac_test.dart | 38 +++ .../test/general.shard/ios/xcresult_test.dart | 13 + .../general.shard/ios/xcresult_test_data.dart | 249 ++++++++++++++++++ 6 files changed, 468 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 86a4a0546ad46..6a088c705cde3 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -41,6 +42,21 @@ import 'xcresult.dart'; const String kConcurrentRunFailureMessage1 = 'database is locked'; const String kConcurrentRunFailureMessage2 = 'there are two concurrent builds running'; +/// User message when missing platform required to use Xcode. +/// +/// Starting with Xcode 15, the simulator is no longer downloaded with Xcode +/// and must be downloaded and installed separately. +@visibleForTesting +String missingPlatformInstructions(String simulatorVersion) => ''' +════════════════════════════════════════════════════════════════════════════════ +$simulatorVersion is not installed. To download and install the platform, open +Xcode, select Xcode > Settings > Platforms, and click the GET button for the +required platform. + +For more information, please visit: + https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes +════════════════════════════════════════════════════════════════════════════════'''; + class IMobileDevice { IMobileDevice({ required Artifacts artifacts, @@ -700,6 +716,11 @@ _XCResultIssueHandlingResult _handleXCResultIssue({required XCResultIssue issue, return _XCResultIssueHandlingResult(requiresProvisioningProfile: true, hasProvisioningProfileIssue: true); } else if (message.toLowerCase().contains('provisioning profile')) { return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: true); + } else if (message.toLowerCase().contains('ineligible destinations')) { + final String? missingPlatform = _parseMissingPlatform(message); + if (missingPlatform != null) { + return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false, missingPlatform: missingPlatform); + } } return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false); } @@ -709,6 +730,7 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode bool requiresProvisioningProfile = false; bool hasProvisioningProfileIssue = false; bool issueDetected = false; + String? missingPlatform; if (xcResult != null && xcResult.parseSuccess) { for (final XCResultIssue issue in xcResult.issues) { @@ -719,6 +741,7 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode if (handlingResult.requiresProvisioningProfile) { requiresProvisioningProfile = true; } + missingPlatform = handlingResult.missingPlatform; issueDetected = true; } } else if (xcResult != null) { @@ -738,6 +761,8 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode logger.printError(' open ios/Runner.xcworkspace'); logger.printError(''); logger.printError("Also try selecting 'Product > Build' to fix the problem."); + } else if (missingPlatform != null) { + logger.printError(missingPlatformInstructions(missingPlatform), emphasis: true); } return issueDetected; @@ -773,18 +798,41 @@ void _parseIssueInStdout(XcodeBuildExecution xcodeBuildExecution, Logger logger, && (result.stdout?.contains('requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor') ?? false)) { logger.printError(noProvisioningProfileInstruction, emphasis: true); } + + if (stderr != null && stderr.contains('Ineligible destinations')) { + final String? version = _parseMissingPlatform(stderr); + if (version != null) { + logger.printError(missingPlatformInstructions(version), emphasis: true); + } + } +} + +String? _parseMissingPlatform(String message) { + final RegExp pattern = RegExp(r'error:(.*?) is not installed\. To use with Xcode, first download and install the platform'); + final RegExpMatch? match = pattern.firstMatch(message); + if (match != null) { + final String? version = match.group(1); + return version; + } + return null; } // The result of [_handleXCResultIssue]. class _XCResultIssueHandlingResult { - _XCResultIssueHandlingResult({required this.requiresProvisioningProfile, required this.hasProvisioningProfileIssue}); + _XCResultIssueHandlingResult({ + required this.requiresProvisioningProfile, + required this.hasProvisioningProfileIssue, + this.missingPlatform, + }); // An issue indicates that user didn't provide the provisioning profile. final bool requiresProvisioningProfile; // An issue indicates that there is a provisioning profile issue. final bool hasProvisioningProfileIssue; + + final String? missingPlatform; } const String _kResultBundlePath = 'temporary_xcresult_bundle'; diff --git a/packages/flutter_tools/lib/src/ios/xcresult.dart b/packages/flutter_tools/lib/src/ios/xcresult.dart index 5bb520e0a5046..1329d6b3bd754 100644 --- a/packages/flutter_tools/lib/src/ios/xcresult.dart +++ b/packages/flutter_tools/lib/src/ios/xcresult.dart @@ -104,6 +104,13 @@ class XCResult { issueDiscarder: issueDiscarders, )); } + + final Object? actionsMap = resultJson['actions']; + if (actionsMap is Map) { + final List actionIssues = _parseActionIssues(actionsMap, issueDiscarders: issueDiscarders); + issues.addAll(actionIssues); + } + return XCResult._(issues: issues); } @@ -383,3 +390,84 @@ List _parseIssuesFromIssueSummariesJson({ } return issues; } + +List _parseActionIssues( + Map actionsMap, { + required List issueDiscarders, +}) { + // Example of json: + // { + // "actions" : { + // "_values" : [ + // { + // "actionResult" : { + // "_type" : { + // "_name" : "ActionResult" + // }, + // "issues" : { + // "_type" : { + // "_name" : "ResultIssueSummaries" + // }, + // "testFailureSummaries" : { + // "_type" : { + // "_name" : "Array" + // }, + // "_values" : [ + // { + // "_type" : { + // "_name" : "TestFailureIssueSummary", + // "_supertype" : { + // "_name" : "IssueSummary" + // } + // }, + // "issueType" : { + // "_type" : { + // "_name" : "String" + // }, + // "_value" : "Uncategorized" + // }, + // "message" : { + // "_type" : { + // "_name" : "String" + // }, + // "_value" : "Unable to find a destination matching the provided destination specifier:\n\t\t{ id:1234D567-890C-1DA2-34E5-F6789A0123C4 }\n\n\tIneligible destinations for the \"Runner\" scheme:\n\t\t{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform }" + // } + // } + // ] + // } + // } + // } + // } + // ] + // } + // } + final List issues = []; + final Object? actionsValues = actionsMap['_values']; + if (actionsValues is! List) { + return issues; + } + + for (final Object? actionValue in actionsValues) { + if (actionValue is!Map) { + continue; + } + final Object? actionResult = actionValue['actionResult']; + if (actionResult is! Map) { + continue; + } + final Object? actionResultIssues = actionResult['issues']; + if (actionResultIssues is! Map) { + continue; + } + final Object? testFailureSummaries = actionResultIssues['testFailureSummaries']; + if (testFailureSummaries is Map) { + issues.addAll(_parseIssuesFromIssueSummariesJson( + type: XCResultIssueType.error, + issueSummariesJson: testFailureSummaries, + issueDiscarder: issueDiscarders, + )); + } + } + + return issues; + } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index c1f2dc3b47e77..509de40ad0c37 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -638,6 +638,37 @@ void main() { XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); + testUsingContext('Extra error message for missing simulator platform in xcresult bundle.', () async { + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + + createMinimalMockProjectFiles(); + + await expectLater( + createTestCommandRunner(command).run(const ['build', 'ios', '--no-pub']), + throwsToolExit(), + ); + + expect(testLogger.errorText, contains(missingPlatformInstructions('iOS 17.0'))); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.list([ + xattrCommand, + setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { + fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); + }), + setUpXCResultCommand(stdout: kSampleResultJsonWithActionIssues), + setUpRsyncCommand(), + ]), + Platform: () => macosPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + }); + testUsingContext('Delete xcresult bundle before each xcodebuild command.', () async { final BuildCommand command = BuildCommand( androidSdk: FakeAndroidSdk(), diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index e7fef592be5f1..303d261273ee7 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -245,6 +245,44 @@ Error launching application on iPhone.''', ); }); + testWithoutContext('fallback to stdout: Ineligible destinations', () async { + final Map buildSettingsWithDevTeam = { + 'PRODUCT_BUNDLE_IDENTIFIER': 'test.app', + 'DEVELOPMENT_TEAM': 'a team', + }; + final XcodeBuildResult buildResult = XcodeBuildResult( + success: false, + stderr: ''' +Launching lib/main.dart on iPhone in debug mode... +Signing iOS app for device deployment using developer identity: "iPhone Developer: test@flutter.io (1122334455)" +Running Xcode build... 1.3s +Failed to build iOS app +Error output from Xcode build: +↳ + xcodebuild: error: Unable to find a destination matching the provided destination specifier: + { id:1234D567-890C-1DA2-34E5-F6789A0123C4 } + + Ineligible destinations for the "Runner" scheme: + { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform } + +Could not build the precompiled application for the device. + +Error launching application on iPhone.''', + xcodeBuildExecution: XcodeBuildExecution( + buildCommands: ['xcrun', 'xcodebuild', 'blah'], + appDirectory: '/blah/blah', + environmentType: EnvironmentType.physical, + buildSettings: buildSettingsWithDevTeam, + ), + ); + + await diagnoseXcodeBuildFailure(buildResult, testUsage, logger); + expect( + logger.errorText, + contains(missingPlatformInstructions('iOS 17.0')), + ); + }); + testWithoutContext('No development team shows message', () async { final XcodeBuildResult buildResult = XcodeBuildResult( success: false, diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart index 72b78681c838f..19f6944b0895a 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart @@ -204,6 +204,19 @@ void main() { expect(result.parsingErrorMessage, isNull); }); + testWithoutContext( + 'correctly parse sample result json with action issues.', () async { + final XCResultGenerator generator = setupGenerator(resultJson: kSampleResultJsonWithActionIssues); + final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning); + final XCResult result = await generator.generate(issueDiscarders: [discarder]); + expect(result.issues.length, 1); + expect(result.issues.first.type, XCResultIssueType.error); + expect(result.issues.first.subType, 'Uncategorized'); + expect(result.issues.first.message, contains('Unable to find a destination matching the provided destination specifier')); + expect(result.parseSuccess, isTrue); + expect(result.parsingErrorMessage, isNull); + }); + testWithoutContext( 'error: `xcresulttool get` process fail should return an `XCResult` with stderr as `parsingErrorMessage`.', () async { diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart index 645afd1e876ee..5845262c21851 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart @@ -378,3 +378,252 @@ const String kSampleResultJsonWithProvisionIssue = r''' } } '''; + + +/// An example xcresult bundle json that contains action issues. +const String kSampleResultJsonWithActionIssues = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "ActionRecord" + }, + "actionResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + }, + "testFailureSummaries" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "TestFailureIssueSummary", + "_supertype" : { + "_name" : "IssueSummary" + } + }, + "issueType" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Uncategorized" + }, + "message" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Unable to find a destination matching the provided destination specifier:\n\t\t{ id:1234D567-890C-1DA2-34E5-F6789A0123C4 }\n\n\tIneligible destinations for the \"Runner\" scheme:\n\t\t{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform }" + } + } + ] + } + }, + "logRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~5X-qvql8_ppq0bj9taBMeZd4L2lXQagy1twsFRWwc06r42obpBZfP87uKnGO98mp5CUz1Ppr1knHiTMH9tOuwQ==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActivityLogSection" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "All Tests" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "failedToStart" + }, + "testsRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~Dmuz8-g6YRb8HPVbTUXJD21oy3r5jxIGi-njd2Lc43yR5JlJf7D78HtNn2BsrF5iw1uYMnsuJ9xFDV7ZAmwhGg==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActionTestPlanRunSummaries" + } + } + } + }, + "buildResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Build Succeeded" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "succeeded" + } + }, + "endedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2023-07-10T12:52:22.592-0500" + }, + "runDestination" : { + "_type" : { + "_name" : "ActionRunDestinationRecord" + }, + "localComputerRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + } + } + }, + "targetDeviceRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + } + } + }, + "targetSDKRecord" : { + "_type" : { + "_name" : "ActionSDKRecord" + } + } + }, + "schemeCommandName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Test" + }, + "schemeTaskName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "BuildAndAction" + }, + "startedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2023-07-10T12:52:22.592-0500" + }, + "title" : { + "_type" : { + "_name" : "String" + }, + "_value" : "RunnerTests.xctest" + } + } + ] + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metadataRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~pY0GqmiVE6Q3qlWdLJDp_PnrsUKsJ7KKM1zKGnvEZOWGdBeGNArjjU62kgF2UBFdQLdRmf5SGpImQfJB6e7vDQ==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActionsInvocationMetadata" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + } +} +'''; From ab86c79c3a1fd92ab36071b62702698058216479 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:19:56 -0500 Subject: [PATCH 0120/1547] Revert "Print pretty error when xcodebuild fails due to missing simulator" (#130504) Reverts flutter/flutter#130286 --- packages/flutter_tools/lib/src/ios/mac.dart | 50 +--- .../flutter_tools/lib/src/ios/xcresult.dart | 88 ------- .../hermetic/build_ios_test.dart | 31 --- .../test/general.shard/ios/mac_test.dart | 38 --- .../test/general.shard/ios/xcresult_test.dart | 13 - .../general.shard/ios/xcresult_test_data.dart | 249 ------------------ 6 files changed, 1 insertion(+), 468 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 6a088c705cde3..86a4a0546ad46 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -4,7 +4,6 @@ import 'dart:async'; -import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -42,21 +41,6 @@ import 'xcresult.dart'; const String kConcurrentRunFailureMessage1 = 'database is locked'; const String kConcurrentRunFailureMessage2 = 'there are two concurrent builds running'; -/// User message when missing platform required to use Xcode. -/// -/// Starting with Xcode 15, the simulator is no longer downloaded with Xcode -/// and must be downloaded and installed separately. -@visibleForTesting -String missingPlatformInstructions(String simulatorVersion) => ''' -════════════════════════════════════════════════════════════════════════════════ -$simulatorVersion is not installed. To download and install the platform, open -Xcode, select Xcode > Settings > Platforms, and click the GET button for the -required platform. - -For more information, please visit: - https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes -════════════════════════════════════════════════════════════════════════════════'''; - class IMobileDevice { IMobileDevice({ required Artifacts artifacts, @@ -716,11 +700,6 @@ _XCResultIssueHandlingResult _handleXCResultIssue({required XCResultIssue issue, return _XCResultIssueHandlingResult(requiresProvisioningProfile: true, hasProvisioningProfileIssue: true); } else if (message.toLowerCase().contains('provisioning profile')) { return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: true); - } else if (message.toLowerCase().contains('ineligible destinations')) { - final String? missingPlatform = _parseMissingPlatform(message); - if (missingPlatform != null) { - return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false, missingPlatform: missingPlatform); - } } return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false); } @@ -730,7 +709,6 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode bool requiresProvisioningProfile = false; bool hasProvisioningProfileIssue = false; bool issueDetected = false; - String? missingPlatform; if (xcResult != null && xcResult.parseSuccess) { for (final XCResultIssue issue in xcResult.issues) { @@ -741,7 +719,6 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode if (handlingResult.requiresProvisioningProfile) { requiresProvisioningProfile = true; } - missingPlatform = handlingResult.missingPlatform; issueDetected = true; } } else if (xcResult != null) { @@ -761,8 +738,6 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode logger.printError(' open ios/Runner.xcworkspace'); logger.printError(''); logger.printError("Also try selecting 'Product > Build' to fix the problem."); - } else if (missingPlatform != null) { - logger.printError(missingPlatformInstructions(missingPlatform), emphasis: true); } return issueDetected; @@ -798,41 +773,18 @@ void _parseIssueInStdout(XcodeBuildExecution xcodeBuildExecution, Logger logger, && (result.stdout?.contains('requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor') ?? false)) { logger.printError(noProvisioningProfileInstruction, emphasis: true); } - - if (stderr != null && stderr.contains('Ineligible destinations')) { - final String? version = _parseMissingPlatform(stderr); - if (version != null) { - logger.printError(missingPlatformInstructions(version), emphasis: true); - } - } -} - -String? _parseMissingPlatform(String message) { - final RegExp pattern = RegExp(r'error:(.*?) is not installed\. To use with Xcode, first download and install the platform'); - final RegExpMatch? match = pattern.firstMatch(message); - if (match != null) { - final String? version = match.group(1); - return version; - } - return null; } // The result of [_handleXCResultIssue]. class _XCResultIssueHandlingResult { - _XCResultIssueHandlingResult({ - required this.requiresProvisioningProfile, - required this.hasProvisioningProfileIssue, - this.missingPlatform, - }); + _XCResultIssueHandlingResult({required this.requiresProvisioningProfile, required this.hasProvisioningProfileIssue}); // An issue indicates that user didn't provide the provisioning profile. final bool requiresProvisioningProfile; // An issue indicates that there is a provisioning profile issue. final bool hasProvisioningProfileIssue; - - final String? missingPlatform; } const String _kResultBundlePath = 'temporary_xcresult_bundle'; diff --git a/packages/flutter_tools/lib/src/ios/xcresult.dart b/packages/flutter_tools/lib/src/ios/xcresult.dart index 1329d6b3bd754..5bb520e0a5046 100644 --- a/packages/flutter_tools/lib/src/ios/xcresult.dart +++ b/packages/flutter_tools/lib/src/ios/xcresult.dart @@ -104,13 +104,6 @@ class XCResult { issueDiscarder: issueDiscarders, )); } - - final Object? actionsMap = resultJson['actions']; - if (actionsMap is Map) { - final List actionIssues = _parseActionIssues(actionsMap, issueDiscarders: issueDiscarders); - issues.addAll(actionIssues); - } - return XCResult._(issues: issues); } @@ -390,84 +383,3 @@ List _parseIssuesFromIssueSummariesJson({ } return issues; } - -List _parseActionIssues( - Map actionsMap, { - required List issueDiscarders, -}) { - // Example of json: - // { - // "actions" : { - // "_values" : [ - // { - // "actionResult" : { - // "_type" : { - // "_name" : "ActionResult" - // }, - // "issues" : { - // "_type" : { - // "_name" : "ResultIssueSummaries" - // }, - // "testFailureSummaries" : { - // "_type" : { - // "_name" : "Array" - // }, - // "_values" : [ - // { - // "_type" : { - // "_name" : "TestFailureIssueSummary", - // "_supertype" : { - // "_name" : "IssueSummary" - // } - // }, - // "issueType" : { - // "_type" : { - // "_name" : "String" - // }, - // "_value" : "Uncategorized" - // }, - // "message" : { - // "_type" : { - // "_name" : "String" - // }, - // "_value" : "Unable to find a destination matching the provided destination specifier:\n\t\t{ id:1234D567-890C-1DA2-34E5-F6789A0123C4 }\n\n\tIneligible destinations for the \"Runner\" scheme:\n\t\t{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform }" - // } - // } - // ] - // } - // } - // } - // } - // ] - // } - // } - final List issues = []; - final Object? actionsValues = actionsMap['_values']; - if (actionsValues is! List) { - return issues; - } - - for (final Object? actionValue in actionsValues) { - if (actionValue is!Map) { - continue; - } - final Object? actionResult = actionValue['actionResult']; - if (actionResult is! Map) { - continue; - } - final Object? actionResultIssues = actionResult['issues']; - if (actionResultIssues is! Map) { - continue; - } - final Object? testFailureSummaries = actionResultIssues['testFailureSummaries']; - if (testFailureSummaries is Map) { - issues.addAll(_parseIssuesFromIssueSummariesJson( - type: XCResultIssueType.error, - issueSummariesJson: testFailureSummaries, - issueDiscarder: issueDiscarders, - )); - } - } - - return issues; - } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index 509de40ad0c37..c1f2dc3b47e77 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -638,37 +638,6 @@ void main() { XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); - testUsingContext('Extra error message for missing simulator platform in xcresult bundle.', () async { - final BuildCommand command = BuildCommand( - androidSdk: FakeAndroidSdk(), - buildSystem: TestBuildSystem.all(BuildResult(success: true)), - fileSystem: MemoryFileSystem.test(), - logger: BufferLogger.test(), - osUtils: FakeOperatingSystemUtils(), - ); - - createMinimalMockProjectFiles(); - - await expectLater( - createTestCommandRunner(command).run(const ['build', 'ios', '--no-pub']), - throwsToolExit(), - ); - - expect(testLogger.errorText, contains(missingPlatformInstructions('iOS 17.0'))); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => FakeProcessManager.list([ - xattrCommand, - setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { - fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync(); - }), - setUpXCResultCommand(stdout: kSampleResultJsonWithActionIssues), - setUpRsyncCommand(), - ]), - Platform: () => macosPlatform, - XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), - }); - testUsingContext('Delete xcresult bundle before each xcodebuild command.', () async { final BuildCommand command = BuildCommand( androidSdk: FakeAndroidSdk(), diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index 303d261273ee7..e7fef592be5f1 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -245,44 +245,6 @@ Error launching application on iPhone.''', ); }); - testWithoutContext('fallback to stdout: Ineligible destinations', () async { - final Map buildSettingsWithDevTeam = { - 'PRODUCT_BUNDLE_IDENTIFIER': 'test.app', - 'DEVELOPMENT_TEAM': 'a team', - }; - final XcodeBuildResult buildResult = XcodeBuildResult( - success: false, - stderr: ''' -Launching lib/main.dart on iPhone in debug mode... -Signing iOS app for device deployment using developer identity: "iPhone Developer: test@flutter.io (1122334455)" -Running Xcode build... 1.3s -Failed to build iOS app -Error output from Xcode build: -↳ - xcodebuild: error: Unable to find a destination matching the provided destination specifier: - { id:1234D567-890C-1DA2-34E5-F6789A0123C4 } - - Ineligible destinations for the "Runner" scheme: - { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform } - -Could not build the precompiled application for the device. - -Error launching application on iPhone.''', - xcodeBuildExecution: XcodeBuildExecution( - buildCommands: ['xcrun', 'xcodebuild', 'blah'], - appDirectory: '/blah/blah', - environmentType: EnvironmentType.physical, - buildSettings: buildSettingsWithDevTeam, - ), - ); - - await diagnoseXcodeBuildFailure(buildResult, testUsage, logger); - expect( - logger.errorText, - contains(missingPlatformInstructions('iOS 17.0')), - ); - }); - testWithoutContext('No development team shows message', () async { final XcodeBuildResult buildResult = XcodeBuildResult( success: false, diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart index 19f6944b0895a..72b78681c838f 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart @@ -204,19 +204,6 @@ void main() { expect(result.parsingErrorMessage, isNull); }); - testWithoutContext( - 'correctly parse sample result json with action issues.', () async { - final XCResultGenerator generator = setupGenerator(resultJson: kSampleResultJsonWithActionIssues); - final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning); - final XCResult result = await generator.generate(issueDiscarders: [discarder]); - expect(result.issues.length, 1); - expect(result.issues.first.type, XCResultIssueType.error); - expect(result.issues.first.subType, 'Uncategorized'); - expect(result.issues.first.message, contains('Unable to find a destination matching the provided destination specifier')); - expect(result.parseSuccess, isTrue); - expect(result.parsingErrorMessage, isNull); - }); - testWithoutContext( 'error: `xcresulttool get` process fail should return an `XCResult` with stderr as `parsingErrorMessage`.', () async { diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart index 5845262c21851..645afd1e876ee 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart @@ -378,252 +378,3 @@ const String kSampleResultJsonWithProvisionIssue = r''' } } '''; - - -/// An example xcresult bundle json that contains action issues. -const String kSampleResultJsonWithActionIssues = r''' -{ - "_type" : { - "_name" : "ActionsInvocationRecord" - }, - "actions" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "ActionRecord" - }, - "actionResult" : { - "_type" : { - "_name" : "ActionResult" - }, - "coverage" : { - "_type" : { - "_name" : "CodeCoverageInfo" - } - }, - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - }, - "testFailureSummaries" : { - "_type" : { - "_name" : "Array" - }, - "_values" : [ - { - "_type" : { - "_name" : "TestFailureIssueSummary", - "_supertype" : { - "_name" : "IssueSummary" - } - }, - "issueType" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Uncategorized" - }, - "message" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Unable to find a destination matching the provided destination specifier:\n\t\t{ id:1234D567-890C-1DA2-34E5-F6789A0123C4 }\n\n\tIneligible destinations for the \"Runner\" scheme:\n\t\t{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform }" - } - } - ] - } - }, - "logRef" : { - "_type" : { - "_name" : "Reference" - }, - "id" : { - "_type" : { - "_name" : "String" - }, - "_value" : "0~5X-qvql8_ppq0bj9taBMeZd4L2lXQagy1twsFRWwc06r42obpBZfP87uKnGO98mp5CUz1Ppr1knHiTMH9tOuwQ==" - }, - "targetType" : { - "_type" : { - "_name" : "TypeDefinition" - }, - "name" : { - "_type" : { - "_name" : "String" - }, - "_value" : "ActivityLogSection" - } - } - }, - "metrics" : { - "_type" : { - "_name" : "ResultMetrics" - } - }, - "resultName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "All Tests" - }, - "status" : { - "_type" : { - "_name" : "String" - }, - "_value" : "failedToStart" - }, - "testsRef" : { - "_type" : { - "_name" : "Reference" - }, - "id" : { - "_type" : { - "_name" : "String" - }, - "_value" : "0~Dmuz8-g6YRb8HPVbTUXJD21oy3r5jxIGi-njd2Lc43yR5JlJf7D78HtNn2BsrF5iw1uYMnsuJ9xFDV7ZAmwhGg==" - }, - "targetType" : { - "_type" : { - "_name" : "TypeDefinition" - }, - "name" : { - "_type" : { - "_name" : "String" - }, - "_value" : "ActionTestPlanRunSummaries" - } - } - } - }, - "buildResult" : { - "_type" : { - "_name" : "ActionResult" - }, - "coverage" : { - "_type" : { - "_name" : "CodeCoverageInfo" - } - }, - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - } - }, - "metrics" : { - "_type" : { - "_name" : "ResultMetrics" - } - }, - "resultName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Build Succeeded" - }, - "status" : { - "_type" : { - "_name" : "String" - }, - "_value" : "succeeded" - } - }, - "endedTime" : { - "_type" : { - "_name" : "Date" - }, - "_value" : "2023-07-10T12:52:22.592-0500" - }, - "runDestination" : { - "_type" : { - "_name" : "ActionRunDestinationRecord" - }, - "localComputerRecord" : { - "_type" : { - "_name" : "ActionDeviceRecord" - }, - "platformRecord" : { - "_type" : { - "_name" : "ActionPlatformRecord" - } - } - }, - "targetDeviceRecord" : { - "_type" : { - "_name" : "ActionDeviceRecord" - }, - "platformRecord" : { - "_type" : { - "_name" : "ActionPlatformRecord" - } - } - }, - "targetSDKRecord" : { - "_type" : { - "_name" : "ActionSDKRecord" - } - } - }, - "schemeCommandName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "Test" - }, - "schemeTaskName" : { - "_type" : { - "_name" : "String" - }, - "_value" : "BuildAndAction" - }, - "startedTime" : { - "_type" : { - "_name" : "Date" - }, - "_value" : "2023-07-10T12:52:22.592-0500" - }, - "title" : { - "_type" : { - "_name" : "String" - }, - "_value" : "RunnerTests.xctest" - } - } - ] - }, - "issues" : { - "_type" : { - "_name" : "ResultIssueSummaries" - } - }, - "metadataRef" : { - "_type" : { - "_name" : "Reference" - }, - "id" : { - "_type" : { - "_name" : "String" - }, - "_value" : "0~pY0GqmiVE6Q3qlWdLJDp_PnrsUKsJ7KKM1zKGnvEZOWGdBeGNArjjU62kgF2UBFdQLdRmf5SGpImQfJB6e7vDQ==" - }, - "targetType" : { - "_type" : { - "_name" : "TypeDefinition" - }, - "name" : { - "_type" : { - "_name" : "String" - }, - "_value" : "ActionsInvocationMetadata" - } - } - }, - "metrics" : { - "_type" : { - "_name" : "ResultMetrics" - } - } -} -'''; From 2e8af2c35eb6760fd33429ed26182c167126cee5 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 13 Jul 2023 10:41:16 -0700 Subject: [PATCH 0121/1547] Unifies text field focus management in desktops (#129652) related https://github.com/flutter/flutter/issues/128709 engine PR: https://github.com/flutter/engine/pull/43279 The web engine requires a way to unfocus textfield, It comes to nature to me that we should leverage didGain/didLose a11y focus action. I also unifies the action handler of all desktop platforms ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../flutter/lib/src/material/text_field.dart | 17 +++++++++++++++++ packages/flutter/test/material/search_test.dart | 16 ++++++++++++---- .../flutter/test/material/text_field_test.dart | 9 +++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 4a3a1e54186ce..9b71adbdc9c6c 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -1290,6 +1290,7 @@ class _TextFieldState extends State with RestorationMixin implements Color? autocorrectionTextRectColor; Radius? cursorRadius = widget.cursorRadius; VoidCallback? handleDidGainAccessibilityFocus; + VoidCallback? handleDidLoseAccessibilityFocus; switch (theme.platform) { case TargetPlatform.iOS: @@ -1320,6 +1321,9 @@ class _TextFieldState extends State with RestorationMixin implements _effectiveFocusNode.requestFocus(); } }; + handleDidLoseAccessibilityFocus = () { + _effectiveFocusNode.unfocus(); + }; case TargetPlatform.android: case TargetPlatform.fuchsia: @@ -1337,6 +1341,15 @@ class _TextFieldState extends State with RestorationMixin implements cursorOpacityAnimates ??= false; cursorColor = _hasError ? _errorColor : widget.cursorColor ?? selectionStyle.cursorColor ?? theme.colorScheme.primary; selectionColor = selectionStyle.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40); + handleDidGainAccessibilityFocus = () { + // Automatically activate the TextField when it receives accessibility focus. + if (!_effectiveFocusNode.hasFocus && _effectiveFocusNode.canRequestFocus) { + _effectiveFocusNode.requestFocus(); + } + }; + handleDidLoseAccessibilityFocus = () { + _effectiveFocusNode.unfocus(); + }; case TargetPlatform.windows: forcePressEnabled = false; @@ -1351,6 +1364,9 @@ class _TextFieldState extends State with RestorationMixin implements _effectiveFocusNode.requestFocus(); } }; + handleDidLoseAccessibilityFocus = () { + _effectiveFocusNode.unfocus(); + }; } Widget child = RepaintBoundary( @@ -1478,6 +1494,7 @@ class _TextFieldState extends State with RestorationMixin implements _requestKeyboard(); }, onDidGainAccessibilityFocus: handleDidGainAccessibilityFocus, + onDidLoseAccessibilityFocus: handleDidLoseAccessibilityFocus, child: child, ); }, diff --git a/packages/flutter/test/material/search_test.dart b/packages/flutter/test/material/search_test.dart index be9a1d6a2498e..e1623b664fe8a 100644 --- a/packages/flutter/test/material/search_test.dart +++ b/packages/flutter/test/material/search_test.dart @@ -605,6 +605,9 @@ void main() { const Widget flexibleSpace = Text('FlexibleSpace'); TestSemantics buildExpected({ required String routeName }) { + final bool isDesktop = debugDefaultTargetPlatformOverride == TargetPlatform.macOS || + debugDefaultTargetPlatformOverride == TargetPlatform.windows || + debugDefaultTargetPlatformOverride == TargetPlatform.linux; return TestSemantics.root( children: [ TestSemantics( @@ -651,9 +654,10 @@ void main() { debugDefaultTargetPlatformOverride != TargetPlatform.macOS) SemanticsFlag.namesRoute, ], actions: [ - if (debugDefaultTargetPlatformOverride == TargetPlatform.macOS || - debugDefaultTargetPlatformOverride == TargetPlatform.windows) + if (isDesktop) SemanticsAction.didGainAccessibilityFocus, + if (isDesktop) + SemanticsAction.didLoseAccessibilityFocus, SemanticsAction.tap, SemanticsAction.setSelection, SemanticsAction.setText, @@ -748,6 +752,9 @@ void main() { group('contributes semantics', () { TestSemantics buildExpected({ required String routeName }) { + final bool isDesktop = debugDefaultTargetPlatformOverride == TargetPlatform.macOS || + debugDefaultTargetPlatformOverride == TargetPlatform.windows || + debugDefaultTargetPlatformOverride == TargetPlatform.linux; return TestSemantics.root( children: [ TestSemantics( @@ -791,9 +798,10 @@ void main() { debugDefaultTargetPlatformOverride != TargetPlatform.macOS) SemanticsFlag.namesRoute, ], actions: [ - if (debugDefaultTargetPlatformOverride == TargetPlatform.macOS || - debugDefaultTargetPlatformOverride == TargetPlatform.windows) + if (isDesktop) SemanticsAction.didGainAccessibilityFocus, + if (isDesktop) + SemanticsAction.didLoseAccessibilityFocus, SemanticsAction.tap, SemanticsAction.setSelection, SemanticsAction.setText, diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index b7a226e989f1a..09fb36bce0f00 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -655,7 +655,7 @@ void main() { expect(editableText.cursorOpacityAnimates, false); }); - testWidgets('Activates the text field when receives semantics focus on Mac, Windows', (WidgetTester tester) async { + testWidgets('Activates the text field when receives semantics focus on desktops', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; final FocusNode focusNode = FocusNode(); @@ -686,6 +686,7 @@ void main() { actions: [ SemanticsAction.tap, SemanticsAction.didGainAccessibilityFocus, + SemanticsAction.didLoseAccessibilityFocus, ], textDirection: TextDirection.ltr, ), @@ -705,8 +706,12 @@ void main() { semanticsOwner.performAction(4, SemanticsAction.didGainAccessibilityFocus); await tester.pumpAndSettle(); expect(focusNode.hasFocus, isTrue); + + semanticsOwner.performAction(4, SemanticsAction.didLoseAccessibilityFocus); + await tester.pumpAndSettle(); + expect(focusNode.hasFocus, isFalse); semantics.dispose(); - }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows })); + }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux })); testWidgets('TextField passes onEditingComplete to EditableText', (WidgetTester tester) async { void onEditingComplete() { } From 7179ca96dd8b68307173323224d19bc42efcb0cb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 13:46:45 -0400 Subject: [PATCH 0122/1547] Roll Flutter Engine from b4080361f2f9 to 88b858151685 (3 revisions) (#130502) https://github.com/flutter/engine/compare/b4080361f2f9...88b858151685 2023-07-13 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 3C7P0w8ySmtqpyi3S... to rRUd41Mv9NI0n3Iyc... (flutter/engine#43635) 2023-07-13 skia-flutter-autoroll@skia.org Roll Dart SDK from ade4dae923f3 to 16ddfe8d08e0 (1 revision) (flutter/engine#43634) 2023-07-13 jason-simmons@users.noreply.github.com Apply the transform of an image filter layer to paint bounds in the CanvasKit backend (flutter/engine#43353) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 3C7P0w8ySmtq to rRUd41Mv9NI0 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 15480cdffa675..42be3dfa6a635 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b4080361f2f9daba4626eac7a0c4616655e8a21e +88b858151685ccae238200ab3c1785dd61242fb0 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index f1ed94b7899ac..79ea6aaa3d83a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -3C7P0w8ySmtqpyi3SZWDcHJ9zdLC09Fo45XjXGjJ1xQC +rRUd41Mv9NI0n3IycuJXEbDEmYYuE1P9aTHCcu_c0NkC From 8e806636405a220f81631d637a49516fbcfd122a Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 13 Jul 2023 10:50:24 -0700 Subject: [PATCH 0123/1547] Mark leak in text_form_field_test.dart. (#130468) --- packages/flutter/test/material/text_form_field_test.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index b46266268ce22..12996a6e399f1 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart'; @@ -103,7 +104,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('can use the desktop cut/copy/paste buttons on Windows and Linux', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use the desktop cut/copy/paste buttons on Windows and Linux', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); @@ -247,6 +248,9 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.windows }), skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130467 + leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: {'ValueNotifier<_OverlayEntryWidgetState?>': 16}), ); testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { From a3ca2677b6b3c6b210e6a4259d4ed6ceb2b6a919 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 14:31:09 -0400 Subject: [PATCH 0124/1547] Roll Flutter Engine from 88b858151685 to 081fbab5f277 (3 revisions) (#130508) https://github.com/flutter/engine/compare/88b858151685...081fbab5f277 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from c2d28b15c246 to 743ad92f5de2 (4 revisions) (flutter/engine#43640) 2023-07-13 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from xBJq6PsO5ebblODMe... to -csWUV7Dv3hETOoDw... (flutter/engine#43639) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from 56b68ce6196c to c2d28b15c246 (1 revision) (flutter/engine#43638) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from xBJq6PsO5ebb to -csWUV7Dv3hE If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 42be3dfa6a635..046215c8a9467 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -88b858151685ccae238200ab3c1785dd61242fb0 +081fbab5f277f5c79dfd7c774ac35ff0a4c182c6 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 195768f741a52..6ca48adbc0863 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -xBJq6PsO5ebblODMegtfmB5Q-Kaghtn_K0m3pR3dU60C +-csWUV7Dv3hETOoDwiBHVjB-2sa36bEnpFP8NDjE7ucC From 5870159ed765e8218ddd3742d8f55996348f2153 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 13 Jul 2023 11:40:50 -0700 Subject: [PATCH 0125/1547] Upgrade leak_tracker. (#130507) --- dev/bots/pubspec.yaml | 5 ++--- dev/devicelab/pubspec.yaml | 5 ++--- packages/flutter/pubspec.yaml | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 2b4fbe7747fb1..970d1e1a6ef82 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -29,7 +29,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - equatable: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,7 +42,7 @@ dependencies: json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - metrics_center: 1.0.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + metrics_center: 1.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +72,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: c2dc +# PUBSPEC CHECKSUM: d7d7 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 5eb968e04e64a..924bcfc78957d 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: http: 0.13.6 logging: 1.2.0 meta: 1.9.1 - metrics_center: 1.0.10 + metrics_center: 1.0.11 path: 1.8.3 platform: 3.1.0 process: 4.2.4 @@ -30,7 +30,6 @@ dependencies: collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - equatable: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +70,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1d4a +# PUBSPEC CHECKSUM: cd45 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 391be87f260a1..5cae5d9304cec 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 7.0.6 + leak_tracker: 7.0.8 leak_tracker_testing: 1.0.0 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 46f2 +# PUBSPEC CHECKSUM: 5af4 From 315ebafea37e67e08c630faa8c1bb56143c791c6 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:41:56 -0700 Subject: [PATCH 0126/1547] =?UTF-8?q?PlatformRouteInformationProvider=20do?= =?UTF-8?q?es=20not=20push=20new=20entry=20if=20query=20par=E2=80=A6=20(#1?= =?UTF-8?q?30457)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ameter is semanticsally the same The URI compare does not taking into account that query parameter may or may not be encoded, or the parameters' order can be different. However, they are all semantically the same. This pr makes PlatformRouteInformationProvider to take those into account when deciding whether it should push/replace the browser history entry. --- packages/flutter/lib/src/widgets/router.dart | 9 ++- .../flutter/test/widgets/router_test.dart | 70 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index 918d36b526b3a..63db13e365483 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:collection'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; @@ -1466,12 +1467,18 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid required RouteInformation initialRouteInformation, }) : _value = initialRouteInformation; + static bool _equals(Uri a, Uri b) { + return a.path == b.path + && a.fragment == b.fragment + && const DeepCollectionEquality.unordered().equals(a.queryParametersAll, b.queryParametersAll); + } + @override void routerReportsNewRouteInformation(RouteInformation routeInformation, {RouteInformationReportingType type = RouteInformationReportingType.none}) { final bool replace = type == RouteInformationReportingType.neglect || (type == RouteInformationReportingType.none && - _valueInEngine.uri == routeInformation.uri); + _equals(_valueInEngine.uri, routeInformation.uri)); SystemNavigator.selectMultiEntryHistory(); SystemNavigator.routeInformationUpdated( uri: routeInformation.uri, diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index f07d59245be12..cf46e0fc3d476 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -867,6 +867,76 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester ]); }); + testWidgets('PlatformRouteInformationProvider does not push new entry if query parameters are semantically the same', (WidgetTester tester) async { + final List log = []; + TestDefaultBinaryMessengerBinding + .instance.defaultBinaryMessenger + .setMockMethodCallHandler( + SystemChannels.navigation, + (MethodCall methodCall) async { + log.add(methodCall); + return null; + } + ); + final RouteInformation initial = RouteInformation( + uri: Uri.parse('initial?a=ws/abcd'), + ); + final RouteInformationProvider provider = PlatformRouteInformationProvider( + initialRouteInformation: initial + ); + // Make sure engine is updated with initial route + provider.routerReportsNewRouteInformation(initial); + log.clear(); + + provider.routerReportsNewRouteInformation( + RouteInformation( + uri: Uri( + path: 'initial', + queryParameters: {'a': 'ws/abcd'}, // This will be escaped. + ), + ), + ); + expect(provider.value.uri.toString(), 'initial?a=ws%2Fabcd'); + // should use `replace: true` + expect(log, [ + isMethodCall('selectMultiEntryHistory', arguments: null), + isMethodCall('routeInformationUpdated', arguments: { 'uri': 'initial?a=ws%2Fabcd', 'state': null, 'replace': true }), + ]); + log.clear(); + + provider.routerReportsNewRouteInformation( + RouteInformation(uri: Uri.parse('initial?a=1&b=2')), + ); + log.clear(); + + // Change query parameters order + provider.routerReportsNewRouteInformation( + RouteInformation(uri: Uri.parse('initial?b=2&a=1')), + ); + // should use `replace: true` + expect(log, [ + isMethodCall('selectMultiEntryHistory', arguments: null), + isMethodCall('routeInformationUpdated', arguments: { 'uri': 'initial?b=2&a=1', 'state': null, 'replace': true }), + ]); + log.clear(); + + provider.routerReportsNewRouteInformation( + RouteInformation(uri: Uri.parse('initial?a=1&a=2')), + ); + log.clear(); + + // Change query parameters order for same key + provider.routerReportsNewRouteInformation( + RouteInformation(uri: Uri.parse('initial?a=2&a=1')), + ); + // should use `replace: true` + expect(log, [ + isMethodCall('selectMultiEntryHistory', arguments: null), + isMethodCall('routeInformationUpdated', arguments: { 'uri': 'initial?a=2&a=1', 'state': null, 'replace': true }), + ]); + log.clear(); + }); + testWidgets('RootBackButtonDispatcher works', (WidgetTester tester) async { final BackButtonDispatcher outerDispatcher = RootBackButtonDispatcher(); final RouteInformationProvider provider = PlatformRouteInformationProvider( From 2892b5755877df068ff94fb9b36f0f99924bd907 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:36:10 -0500 Subject: [PATCH 0127/1547] Reland "Print pretty error when xcodebuild fails due to missing simulator #130286" (#130506) Reland https://github.com/flutter/flutter/pull/130286 with fix. It failed the first time because of a discrepancy between the master branch and my branch (see https://github.com/flutter/flutter/pull/130504#issue-1803449182 for more info). --- packages/flutter_tools/lib/src/ios/mac.dart | 50 +++- .../flutter_tools/lib/src/ios/xcresult.dart | 88 +++++++ .../hermetic/build_ios_test.dart | 31 +++ .../test/general.shard/ios/mac_test.dart | 38 +++ .../test/general.shard/ios/xcresult_test.dart | 13 + .../general.shard/ios/xcresult_test_data.dart | 249 ++++++++++++++++++ 6 files changed, 468 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 86a4a0546ad46..6a088c705cde3 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; @@ -41,6 +42,21 @@ import 'xcresult.dart'; const String kConcurrentRunFailureMessage1 = 'database is locked'; const String kConcurrentRunFailureMessage2 = 'there are two concurrent builds running'; +/// User message when missing platform required to use Xcode. +/// +/// Starting with Xcode 15, the simulator is no longer downloaded with Xcode +/// and must be downloaded and installed separately. +@visibleForTesting +String missingPlatformInstructions(String simulatorVersion) => ''' +════════════════════════════════════════════════════════════════════════════════ +$simulatorVersion is not installed. To download and install the platform, open +Xcode, select Xcode > Settings > Platforms, and click the GET button for the +required platform. + +For more information, please visit: + https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes +════════════════════════════════════════════════════════════════════════════════'''; + class IMobileDevice { IMobileDevice({ required Artifacts artifacts, @@ -700,6 +716,11 @@ _XCResultIssueHandlingResult _handleXCResultIssue({required XCResultIssue issue, return _XCResultIssueHandlingResult(requiresProvisioningProfile: true, hasProvisioningProfileIssue: true); } else if (message.toLowerCase().contains('provisioning profile')) { return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: true); + } else if (message.toLowerCase().contains('ineligible destinations')) { + final String? missingPlatform = _parseMissingPlatform(message); + if (missingPlatform != null) { + return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false, missingPlatform: missingPlatform); + } } return _XCResultIssueHandlingResult(requiresProvisioningProfile: false, hasProvisioningProfileIssue: false); } @@ -709,6 +730,7 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode bool requiresProvisioningProfile = false; bool hasProvisioningProfileIssue = false; bool issueDetected = false; + String? missingPlatform; if (xcResult != null && xcResult.parseSuccess) { for (final XCResultIssue issue in xcResult.issues) { @@ -719,6 +741,7 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode if (handlingResult.requiresProvisioningProfile) { requiresProvisioningProfile = true; } + missingPlatform = handlingResult.missingPlatform; issueDetected = true; } } else if (xcResult != null) { @@ -738,6 +761,8 @@ bool _handleIssues(XCResult? xcResult, Logger logger, XcodeBuildExecution? xcode logger.printError(' open ios/Runner.xcworkspace'); logger.printError(''); logger.printError("Also try selecting 'Product > Build' to fix the problem."); + } else if (missingPlatform != null) { + logger.printError(missingPlatformInstructions(missingPlatform), emphasis: true); } return issueDetected; @@ -773,18 +798,41 @@ void _parseIssueInStdout(XcodeBuildExecution xcodeBuildExecution, Logger logger, && (result.stdout?.contains('requires a provisioning profile. Select a provisioning profile in the Signing & Capabilities editor') ?? false)) { logger.printError(noProvisioningProfileInstruction, emphasis: true); } + + if (stderr != null && stderr.contains('Ineligible destinations')) { + final String? version = _parseMissingPlatform(stderr); + if (version != null) { + logger.printError(missingPlatformInstructions(version), emphasis: true); + } + } +} + +String? _parseMissingPlatform(String message) { + final RegExp pattern = RegExp(r'error:(.*?) is not installed\. To use with Xcode, first download and install the platform'); + final RegExpMatch? match = pattern.firstMatch(message); + if (match != null) { + final String? version = match.group(1); + return version; + } + return null; } // The result of [_handleXCResultIssue]. class _XCResultIssueHandlingResult { - _XCResultIssueHandlingResult({required this.requiresProvisioningProfile, required this.hasProvisioningProfileIssue}); + _XCResultIssueHandlingResult({ + required this.requiresProvisioningProfile, + required this.hasProvisioningProfileIssue, + this.missingPlatform, + }); // An issue indicates that user didn't provide the provisioning profile. final bool requiresProvisioningProfile; // An issue indicates that there is a provisioning profile issue. final bool hasProvisioningProfileIssue; + + final String? missingPlatform; } const String _kResultBundlePath = 'temporary_xcresult_bundle'; diff --git a/packages/flutter_tools/lib/src/ios/xcresult.dart b/packages/flutter_tools/lib/src/ios/xcresult.dart index 5bb520e0a5046..1329d6b3bd754 100644 --- a/packages/flutter_tools/lib/src/ios/xcresult.dart +++ b/packages/flutter_tools/lib/src/ios/xcresult.dart @@ -104,6 +104,13 @@ class XCResult { issueDiscarder: issueDiscarders, )); } + + final Object? actionsMap = resultJson['actions']; + if (actionsMap is Map) { + final List actionIssues = _parseActionIssues(actionsMap, issueDiscarders: issueDiscarders); + issues.addAll(actionIssues); + } + return XCResult._(issues: issues); } @@ -383,3 +390,84 @@ List _parseIssuesFromIssueSummariesJson({ } return issues; } + +List _parseActionIssues( + Map actionsMap, { + required List issueDiscarders, +}) { + // Example of json: + // { + // "actions" : { + // "_values" : [ + // { + // "actionResult" : { + // "_type" : { + // "_name" : "ActionResult" + // }, + // "issues" : { + // "_type" : { + // "_name" : "ResultIssueSummaries" + // }, + // "testFailureSummaries" : { + // "_type" : { + // "_name" : "Array" + // }, + // "_values" : [ + // { + // "_type" : { + // "_name" : "TestFailureIssueSummary", + // "_supertype" : { + // "_name" : "IssueSummary" + // } + // }, + // "issueType" : { + // "_type" : { + // "_name" : "String" + // }, + // "_value" : "Uncategorized" + // }, + // "message" : { + // "_type" : { + // "_name" : "String" + // }, + // "_value" : "Unable to find a destination matching the provided destination specifier:\n\t\t{ id:1234D567-890C-1DA2-34E5-F6789A0123C4 }\n\n\tIneligible destinations for the \"Runner\" scheme:\n\t\t{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform }" + // } + // } + // ] + // } + // } + // } + // } + // ] + // } + // } + final List issues = []; + final Object? actionsValues = actionsMap['_values']; + if (actionsValues is! List) { + return issues; + } + + for (final Object? actionValue in actionsValues) { + if (actionValue is!Map) { + continue; + } + final Object? actionResult = actionValue['actionResult']; + if (actionResult is! Map) { + continue; + } + final Object? actionResultIssues = actionResult['issues']; + if (actionResultIssues is! Map) { + continue; + } + final Object? testFailureSummaries = actionResultIssues['testFailureSummaries']; + if (testFailureSummaries is Map) { + issues.addAll(_parseIssuesFromIssueSummariesJson( + type: XCResultIssueType.error, + issueSummariesJson: testFailureSummaries, + issueDiscarder: issueDiscarders, + )); + } + } + + return issues; + } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index c1f2dc3b47e77..a36960457498b 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -638,6 +638,37 @@ void main() { XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); + testUsingContext('Extra error message for missing simulator platform in xcresult bundle.', () async { + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + + createMinimalMockProjectFiles(); + + await expectLater( + createTestCommandRunner(command).run(const ['build', 'ios', '--no-pub']), + throwsToolExit(), + ); + + expect(testLogger.errorText, contains(missingPlatformInstructions('iOS 17.0'))); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.list([ + xattrCommand, + setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () { + fileSystem.systemTempDirectory.childDirectory(_xcBundleDirectoryPath).createSync(); + }), + setUpXCResultCommand(stdout: kSampleResultJsonWithActionIssues), + setUpRsyncCommand(), + ]), + Platform: () => macosPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + }); + testUsingContext('Delete xcresult bundle before each xcodebuild command.', () async { final BuildCommand command = BuildCommand( androidSdk: FakeAndroidSdk(), diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index e7fef592be5f1..303d261273ee7 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -245,6 +245,44 @@ Error launching application on iPhone.''', ); }); + testWithoutContext('fallback to stdout: Ineligible destinations', () async { + final Map buildSettingsWithDevTeam = { + 'PRODUCT_BUNDLE_IDENTIFIER': 'test.app', + 'DEVELOPMENT_TEAM': 'a team', + }; + final XcodeBuildResult buildResult = XcodeBuildResult( + success: false, + stderr: ''' +Launching lib/main.dart on iPhone in debug mode... +Signing iOS app for device deployment using developer identity: "iPhone Developer: test@flutter.io (1122334455)" +Running Xcode build... 1.3s +Failed to build iOS app +Error output from Xcode build: +↳ + xcodebuild: error: Unable to find a destination matching the provided destination specifier: + { id:1234D567-890C-1DA2-34E5-F6789A0123C4 } + + Ineligible destinations for the "Runner" scheme: + { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform } + +Could not build the precompiled application for the device. + +Error launching application on iPhone.''', + xcodeBuildExecution: XcodeBuildExecution( + buildCommands: ['xcrun', 'xcodebuild', 'blah'], + appDirectory: '/blah/blah', + environmentType: EnvironmentType.physical, + buildSettings: buildSettingsWithDevTeam, + ), + ); + + await diagnoseXcodeBuildFailure(buildResult, testUsage, logger); + expect( + logger.errorText, + contains(missingPlatformInstructions('iOS 17.0')), + ); + }); + testWithoutContext('No development team shows message', () async { final XcodeBuildResult buildResult = XcodeBuildResult( success: false, diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart index 72b78681c838f..19f6944b0895a 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test.dart @@ -204,6 +204,19 @@ void main() { expect(result.parsingErrorMessage, isNull); }); + testWithoutContext( + 'correctly parse sample result json with action issues.', () async { + final XCResultGenerator generator = setupGenerator(resultJson: kSampleResultJsonWithActionIssues); + final XCResultIssueDiscarder discarder = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning); + final XCResult result = await generator.generate(issueDiscarders: [discarder]); + expect(result.issues.length, 1); + expect(result.issues.first.type, XCResultIssueType.error); + expect(result.issues.first.subType, 'Uncategorized'); + expect(result.issues.first.message, contains('Unable to find a destination matching the provided destination specifier')); + expect(result.parseSuccess, isTrue); + expect(result.parsingErrorMessage, isNull); + }); + testWithoutContext( 'error: `xcresulttool get` process fail should return an `XCResult` with stderr as `parsingErrorMessage`.', () async { diff --git a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart index 645afd1e876ee..5845262c21851 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcresult_test_data.dart @@ -378,3 +378,252 @@ const String kSampleResultJsonWithProvisionIssue = r''' } } '''; + + +/// An example xcresult bundle json that contains action issues. +const String kSampleResultJsonWithActionIssues = r''' +{ + "_type" : { + "_name" : "ActionsInvocationRecord" + }, + "actions" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "ActionRecord" + }, + "actionResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + }, + "testFailureSummaries" : { + "_type" : { + "_name" : "Array" + }, + "_values" : [ + { + "_type" : { + "_name" : "TestFailureIssueSummary", + "_supertype" : { + "_name" : "IssueSummary" + } + }, + "issueType" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Uncategorized" + }, + "message" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Unable to find a destination matching the provided destination specifier:\n\t\t{ id:1234D567-890C-1DA2-34E5-F6789A0123C4 }\n\n\tIneligible destinations for the \"Runner\" scheme:\n\t\t{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Any iOS Device, error:iOS 17.0 is not installed. To use with Xcode, first download and install the platform }" + } + } + ] + } + }, + "logRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~5X-qvql8_ppq0bj9taBMeZd4L2lXQagy1twsFRWwc06r42obpBZfP87uKnGO98mp5CUz1Ppr1knHiTMH9tOuwQ==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActivityLogSection" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "All Tests" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "failedToStart" + }, + "testsRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~Dmuz8-g6YRb8HPVbTUXJD21oy3r5jxIGi-njd2Lc43yR5JlJf7D78HtNn2BsrF5iw1uYMnsuJ9xFDV7ZAmwhGg==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActionTestPlanRunSummaries" + } + } + } + }, + "buildResult" : { + "_type" : { + "_name" : "ActionResult" + }, + "coverage" : { + "_type" : { + "_name" : "CodeCoverageInfo" + } + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + }, + "resultName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Build Succeeded" + }, + "status" : { + "_type" : { + "_name" : "String" + }, + "_value" : "succeeded" + } + }, + "endedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2023-07-10T12:52:22.592-0500" + }, + "runDestination" : { + "_type" : { + "_name" : "ActionRunDestinationRecord" + }, + "localComputerRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + } + } + }, + "targetDeviceRecord" : { + "_type" : { + "_name" : "ActionDeviceRecord" + }, + "platformRecord" : { + "_type" : { + "_name" : "ActionPlatformRecord" + } + } + }, + "targetSDKRecord" : { + "_type" : { + "_name" : "ActionSDKRecord" + } + } + }, + "schemeCommandName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "Test" + }, + "schemeTaskName" : { + "_type" : { + "_name" : "String" + }, + "_value" : "BuildAndAction" + }, + "startedTime" : { + "_type" : { + "_name" : "Date" + }, + "_value" : "2023-07-10T12:52:22.592-0500" + }, + "title" : { + "_type" : { + "_name" : "String" + }, + "_value" : "RunnerTests.xctest" + } + } + ] + }, + "issues" : { + "_type" : { + "_name" : "ResultIssueSummaries" + } + }, + "metadataRef" : { + "_type" : { + "_name" : "Reference" + }, + "id" : { + "_type" : { + "_name" : "String" + }, + "_value" : "0~pY0GqmiVE6Q3qlWdLJDp_PnrsUKsJ7KKM1zKGnvEZOWGdBeGNArjjU62kgF2UBFdQLdRmf5SGpImQfJB6e7vDQ==" + }, + "targetType" : { + "_type" : { + "_name" : "TypeDefinition" + }, + "name" : { + "_type" : { + "_name" : "String" + }, + "_value" : "ActionsInvocationMetadata" + } + } + }, + "metrics" : { + "_type" : { + "_name" : "ResultMetrics" + } + } +} +'''; From 360ca44ec11b2e6f221014bd45c44834da357630 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 15:58:06 -0400 Subject: [PATCH 0128/1547] Roll Flutter Engine from 081fbab5f277 to c31cfc517274 (5 revisions) (#130512) https://github.com/flutter/engine/compare/081fbab5f277...c31cfc517274 2023-07-13 jonahwilliams@google.com [Impeller] Switch back to using explicit flush for device buffers. (flutter/engine#43644) 2023-07-13 15619084+vashworth@users.noreply.github.com Add logs to debug VM Service Publication (flutter/engine#43616) 2023-07-13 31859944+LongCatIsLooong@users.noreply.github.com Revert "Add a flag to `ParagraphBuilder` for rounding hack migration" (flutter/engine#43642) 2023-07-13 47866232+chunhtai@users.noreply.github.com [web] TextField a11y focus should call didGain/didLose a11y focus action (flutter/engine#43279) 2023-07-13 john@johnmccutchan.com Improve Stencil Playground test (flutter/engine#43641) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 046215c8a9467..8d346ab33e0e7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -081fbab5f277f5c79dfd7c774ac35ff0a4c182c6 +c31cfc517274a6cc5f988761e861575d93546863 From 157660afc11d3b734310036a9354cf62861f8c50 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Thu, 13 Jul 2023 13:06:03 -0700 Subject: [PATCH 0129/1547] Change the default for`ThemeData.useMaterial3` to true (#129724) Changes the default for `ThemeData.useMaterial3` to true. See https://github.com/flutter/flutter/issues/127064 --- packages/flutter/lib/src/material/theme_data.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 57dfafcddbb42..b541ddbe47795 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -439,7 +439,7 @@ class ThemeData with Diagnosticable { pageTransitionsTheme ??= const PageTransitionsTheme(); scrollbarTheme ??= const ScrollbarThemeData(); visualDensity ??= VisualDensity.defaultDensityForPlatform(platform); - useMaterial3 ??= false; + useMaterial3 ??= true; final bool useInkSparkle = platform == TargetPlatform.android && !kIsWeb; splashFactory ??= useMaterial3 ? useInkSparkle ? InkSparkle.splashFactory : InkRipple.splashFactory From 87d5214da61c7537742c00f9f1799af4cd7e672e Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Thu, 13 Jul 2023 16:12:10 -0400 Subject: [PATCH 0130/1547] [web] Migrate web-only initialization APIs (#129856) - `ui_web.warmupEngine` - `ui_web.setPluginHandler` - `ui_web.debugEmulateFlutterTesterEnvironment` --- .../flutter/lib/src/foundation/_platform_web.dart | 6 ++---- packages/flutter_tools/lib/src/web/bootstrap.dart | 3 ++- .../lib/src/web/file_generators/main_dart.dart | 4 ++-- .../general.shard/build_system/targets/web_test.dart | 8 ++++---- .../test/general.shard/resident_web_runner_test.dart | 4 ++-- .../flutter_web_plugins/lib/src/plugin_registry.dart | 11 +++++------ .../test/plugin_event_channel_test.dart | 4 ++-- .../test/plugin_registry_test.dart | 4 ++-- 8 files changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/flutter/lib/src/foundation/_platform_web.dart b/packages/flutter/lib/src/foundation/_platform_web.dart index 788cbf4c7f26d..babeee421a23f 100644 --- a/packages/flutter/lib/src/foundation/_platform_web.dart +++ b/packages/flutter/lib/src/foundation/_platform_web.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui; +import 'dart:ui_web' as ui_web; import '../services/dom.dart'; @@ -23,9 +23,7 @@ platform.TargetPlatform get defaultTargetPlatform { final platform.TargetPlatform? _testPlatform = () { platform.TargetPlatform? result; assert(() { - // This member is only available in the web's dart:ui implementation. - // ignore: undefined_prefixed_name - if (ui.debugEmulateFlutterTesterEnvironment as bool) { + if (ui_web.debugEmulateFlutterTesterEnvironment) { result = platform.TargetPlatform.android; } return true; diff --git a/packages/flutter_tools/lib/src/web/bootstrap.dart b/packages/flutter_tools/lib/src/web/bootstrap.dart index 5f5f6d1f697cd..de08019febe0c 100644 --- a/packages/flutter_tools/lib/src/web/bootstrap.dart +++ b/packages/flutter_tools/lib/src/web/bootstrap.dart @@ -219,6 +219,7 @@ String generateTestEntrypoint({ // @dart = ${languageVersion.major}.${languageVersion.minor} import 'org-dartlang-app:///$relativeTestPath' as test; import 'dart:ui' as ui; + import 'dart:ui_web' as ui_web; import 'dart:html'; import 'dart:js'; ${testConfigPath != null ? "import '${Uri.file(testConfigPath)}' as test_config;" : ""} @@ -227,7 +228,7 @@ String generateTestEntrypoint({ import 'package:test_api/backend.dart'; Future main() async { - ui.debugEmulateFlutterTesterEnvironment = true; + ui_web.debugEmulateFlutterTesterEnvironment = true; await ui.webOnlyInitializePlatform(); webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('${Uri.file(absolutePath)}')); (ui.window as dynamic).debugOverrideDevicePixelRatio(3.0); diff --git a/packages/flutter_tools/lib/src/web/file_generators/main_dart.dart b/packages/flutter_tools/lib/src/web/file_generators/main_dart.dart index 9d87fe1a3e72a..040e4097ab796 100644 --- a/packages/flutter_tools/lib/src/web/file_generators/main_dart.dart +++ b/packages/flutter_tools/lib/src/web/file_generators/main_dart.dart @@ -19,7 +19,7 @@ String generateMainDartFile(String appEntrypoint, { '', '// ignore_for_file: type=lint', '', - "import 'dart:ui' as ui;", + "import 'dart:ui_web' as ui_web;", "import 'dart:async';", '', "import '$appEntrypoint' as entrypoint;", @@ -29,7 +29,7 @@ String generateMainDartFile(String appEntrypoint, { 'typedef _NullaryFunction = dynamic Function();', '', 'Future main() async {', - ' await ui.webOnlyWarmupEngine(', + ' await ui_web.bootstrapEngine(', ' runApp: () {', ' if (entrypoint.main is _UnaryFunction) {', ' return (entrypoint.main as _UnaryFunction)([]);', diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index d2b79401eaa96..8e47324eda371 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -118,7 +118,7 @@ void main() { expect(generated, contains("import 'package:foo/main.dart' as entrypoint;")); // Main - expect(generated, contains('ui.webOnlyWarmupEngine(')); + expect(generated, contains('ui_web.bootstrapEngine(')); expect(generated, contains('entrypoint.main as _')); }, overrides: { TemplateRenderer: () => const MustacheTemplateRenderer(), @@ -270,7 +270,7 @@ void main() { expect(generated, contains("import 'package:foo/main.dart' as entrypoint;")); // Main - expect(generated, contains('ui.webOnlyWarmupEngine(')); + expect(generated, contains('ui_web.bootstrapEngine(')); expect(generated, contains('entrypoint.main as _')); }, overrides: { Platform: () => windows, @@ -295,7 +295,7 @@ void main() { expect(generated, contains("import 'package:foo/main.dart' as entrypoint;")); // Main - expect(generated, contains('ui.webOnlyWarmupEngine(')); + expect(generated, contains('ui_web.bootstrapEngine(')); expect(generated, contains('entrypoint.main as _')); }, overrides: { TemplateRenderer: () => const MustacheTemplateRenderer(), @@ -351,7 +351,7 @@ void main() { expect(generated, contains("import 'package:foo/main.dart' as entrypoint;")); // Main - expect(generated, contains('ui.webOnlyWarmupEngine(')); + expect(generated, contains('ui_web.bootstrapEngine(')); expect(generated, contains('entrypoint.main as _')); }, overrides: { TemplateRenderer: () => const MustacheTemplateRenderer(), diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 9a307d567fce6..ff803f7bbc7f3 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -730,8 +730,8 @@ void main() { final String entrypointContents = fileSystem.file(webDevFS.mainUri).readAsStringSync(); expect(entrypointContents, contains('// Flutter web bootstrap script')); - expect(entrypointContents, contains("import 'dart:ui' as ui;")); - expect(entrypointContents, contains('await ui.webOnlyWarmupEngine(')); + expect(entrypointContents, contains("import 'dart:ui_web' as ui_web;")); + expect(entrypointContents, contains('await ui_web.bootstrapEngine(')); expect(logger.statusText, contains('Restarted application in')); expect(result.code, 0); diff --git a/packages/flutter_web_plugins/lib/src/plugin_registry.dart b/packages/flutter_web_plugins/lib/src/plugin_registry.dart index b4a11f61f3884..78108b9699c39 100644 --- a/packages/flutter_web_plugins/lib/src/plugin_registry.dart +++ b/packages/flutter_web_plugins/lib/src/plugin_registry.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:ui' as ui; +import 'dart:ui_web' as ui_web; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -57,13 +58,11 @@ class Registrar extends BinaryMessenger { /// previously-registered handler and replaces it with the handler /// from this object. /// - /// This method uses a function called `webOnlySetPluginHandler` in - /// the [dart:ui] library. That function is only available when + /// This method uses a function called `setPluginHandler` in + /// the [dart:ui_web] library. That function is only available when /// compiling for the web. void registerMessageHandler() { - // The `ui.webOnlySetPluginHandler` function below is only defined in the Web dart:ui. - // ignore: undefined_function, avoid_dynamic_calls - ui.webOnlySetPluginHandler(handleFrameworkMessage); + ui_web.setPluginHandler(handleFrameworkMessage); } /// Receives a platform message from the framework. @@ -101,7 +100,7 @@ class Registrar extends BinaryMessenger { /// the following: /// /// ```dart - /// ui.webOnlySetPluginHandler(webPluginRegistrar.handleFrameworkMessage); + /// ui_web.setPluginHandler(handleFrameworkMessage); /// ``` Future handleFrameworkMessage( String channel, diff --git a/packages/flutter_web_plugins/test/plugin_event_channel_test.dart b/packages/flutter_web_plugins/test/plugin_event_channel_test.dart index 280580f5a51ae..b43a841bf116c 100644 --- a/packages/flutter_web_plugins/test/plugin_event_channel_test.dart +++ b/packages/flutter_web_plugins/test/plugin_event_channel_test.dart @@ -6,7 +6,7 @@ library; import 'dart:async'; -import 'dart:ui' as ui; +import 'dart:ui_web' as ui_web; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,7 +14,7 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; void main() { // Disabling tester emulation because this test relies on real message channel communication. - ui.debugEmulateFlutterTesterEnvironment = false; // ignore: undefined_prefixed_name + ui_web.debugEmulateFlutterTesterEnvironment = false; group('Plugin Event Channel', () { setUp(() { diff --git a/packages/flutter_web_plugins/test/plugin_registry_test.dart b/packages/flutter_web_plugins/test/plugin_registry_test.dart index d33d88866a020..43d724527e94a 100644 --- a/packages/flutter_web_plugins/test/plugin_registry_test.dart +++ b/packages/flutter_web_plugins/test/plugin_registry_test.dart @@ -5,7 +5,7 @@ @TestOn('chrome') // Uses web-only Flutter SDK library; -import 'dart:ui' as ui; +import 'dart:ui_web' as ui_web; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -31,7 +31,7 @@ class TestPlugin { void main() { // Disabling tester emulation because this test relies on real message channel communication. - ui.debugEmulateFlutterTesterEnvironment = false; // ignore: undefined_prefixed_name + ui_web.debugEmulateFlutterTesterEnvironment = false; group('Plugin Registry', () { setUp(() { From 0e543889ec287bafeaf7a871c68a8062c205bc65 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 13 Jul 2023 14:35:30 -0700 Subject: [PATCH 0131/1547] mark android impeller tests as bringup (#130525) These should not close the tree as this backend is a WIP. --- .ci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 385dbf30e4e31..5a63470e4f57a 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2307,8 +2307,10 @@ targets: - name: Linux_android new_gallery_impeller__transition_perf recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: + ignore_flakiness: "true" tags: > ["devicelab", "android", "linux"] task_name: new_gallery_impeller__transition_perf @@ -2593,8 +2595,10 @@ targets: - name: Linux_android animated_blur_backdrop_filter_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: + ignore_flakiness: "true" tags: > ["devicelab", "android", "linux"] task_name: animated_blur_backdrop_filter_perf__timeline_summary From 3c2cd015cca63772d61f215ffda4cd4cb92dda7c Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 13 Jul 2023 14:54:28 -0700 Subject: [PATCH 0132/1547] Inspector should not hold callback from garbage collection. (#130436) --- .../lib/src/widgets/widget_inspector.dart | 47 +++++++++++++++++-- .../widgets/widget_inspector_test_utils.dart | 1 + 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 7a88e928e81de..d4a8c87cafbae 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -784,7 +784,6 @@ mixin WidgetInspectorService { bool _trackRebuildDirtyWidgets = false; bool _trackRepaintWidgets = false; - late RegisterServiceExtensionCallback _registerServiceExtensionCallback; /// Registers a service extension method with the given name (full /// name "ext.flutter.inspector.name"). /// @@ -797,8 +796,9 @@ mixin WidgetInspectorService { void registerServiceExtension({ required String name, required ServiceExtensionCallback callback, + required RegisterServiceExtensionCallback registerExtension, }) { - _registerServiceExtensionCallback( + registerExtension( name: 'inspector.$name', callback: callback, ); @@ -809,12 +809,14 @@ mixin WidgetInspectorService { void _registerSignalServiceExtension({ required String name, required FutureOr Function() callback, + required RegisterServiceExtensionCallback registerExtension, }) { registerServiceExtension( name: name, callback: (Map parameters) async { return {'result': await callback()}; }, + registerExtension: registerExtension, ); } @@ -827,12 +829,14 @@ mixin WidgetInspectorService { void _registerObjectGroupServiceExtension({ required String name, required FutureOr Function(String objectGroup) callback, + required RegisterServiceExtensionCallback registerExtension, }) { registerServiceExtension( name: name, callback: (Map parameters) async { return {'result': await callback(parameters['objectGroup']!)}; }, + registerExtension: registerExtension, ); } @@ -852,6 +856,7 @@ mixin WidgetInspectorService { required String name, required AsyncValueGetter getter, required AsyncValueSetter setter, + required RegisterServiceExtensionCallback registerExtension, }) { registerServiceExtension( name: name, @@ -863,6 +868,7 @@ mixin WidgetInspectorService { } return {'enabled': await getter() ? 'true' : 'false'}; }, + registerExtension: registerExtension, ); } @@ -893,6 +899,7 @@ mixin WidgetInspectorService { void _registerServiceExtensionWithArg({ required String name, required FutureOr Function(String? objectId, String objectGroup) callback, + required RegisterServiceExtensionCallback registerExtension, }) { registerServiceExtension( name: name, @@ -902,6 +909,7 @@ mixin WidgetInspectorService { 'result': await callback(parameters['arg'], parameters['objectGroup']!), }; }, + registerExtension: registerExtension, ); } @@ -911,6 +919,7 @@ mixin WidgetInspectorService { void _registerServiceExtensionVarArgs({ required String name, required FutureOr Function(List args) callback, + required RegisterServiceExtensionCallback registerExtension, }) { registerServiceExtension( name: name, @@ -931,6 +940,7 @@ mixin WidgetInspectorService { assert(index == parameters.length || (index == parameters.length - 1 && parameters.containsKey('isolateId'))); return {'result': await callback(args)}; }, + registerExtension: registerExtension, ); } @@ -1011,13 +1021,12 @@ mixin WidgetInspectorService { /// * /// * [BindingBase.initServiceExtensions], which explains when service /// extensions can be used. - void initServiceExtensions(RegisterServiceExtensionCallback registerServiceExtensionCallback) { + void initServiceExtensions(RegisterServiceExtensionCallback registerExtension) { final FlutterExceptionHandler defaultExceptionHandler = FlutterError.presentError; if (isStructuredErrorsEnabled()) { FlutterError.presentError = _reportStructuredError; } - _registerServiceExtensionCallback = registerServiceExtensionCallback; assert(!_debugServiceExtensionsRegistered); assert(() { _debugServiceExtensionsRegistered = true; @@ -1033,6 +1042,7 @@ mixin WidgetInspectorService { FlutterError.presentError = value ? _reportStructuredError : defaultExceptionHandler; return Future.value(); }, + registerExtension: registerExtension, ); _registerBoolServiceExtension( @@ -1045,6 +1055,7 @@ mixin WidgetInspectorService { WidgetsApp.debugShowWidgetInspectorOverride = value; return forceRebuild(); }, + registerExtension: registerExtension, ); if (isWidgetCreationTracked()) { @@ -1071,6 +1082,7 @@ mixin WidgetInspectorService { return; } }, + registerExtension: registerExtension, ); _registerBoolServiceExtension( @@ -1097,6 +1109,7 @@ mixin WidgetInspectorService { debugOnProfilePaint = null; } }, + registerExtension: registerExtension, ); } @@ -1106,6 +1119,7 @@ mixin WidgetInspectorService { disposeAllGroups(); return null; }, + registerExtension: registerExtension, ); _registerObjectGroupServiceExtension( name: WidgetInspectorServiceExtensions.disposeGroup.name, @@ -1113,10 +1127,12 @@ mixin WidgetInspectorService { disposeGroup(name); return null; }, + registerExtension: registerExtension, ); _registerSignalServiceExtension( name: WidgetInspectorServiceExtensions.isWidgetTreeReady.name, callback: isWidgetTreeReady, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.disposeId.name, @@ -1124,6 +1140,7 @@ mixin WidgetInspectorService { disposeId(objectId, objectGroup); return null; }, + registerExtension: registerExtension, ); _registerServiceExtensionVarArgs( name: WidgetInspectorServiceExtensions.setPubRootDirectories.name, @@ -1131,6 +1148,7 @@ mixin WidgetInspectorService { setPubRootDirectories(args); return null; }, + registerExtension: registerExtension, ); _registerServiceExtensionVarArgs( name: WidgetInspectorServiceExtensions.addPubRootDirectories.name, @@ -1138,6 +1156,7 @@ mixin WidgetInspectorService { addPubRootDirectories(args); return null; }, + registerExtension: registerExtension, ); _registerServiceExtensionVarArgs( name: WidgetInspectorServiceExtensions.removePubRootDirectories.name, @@ -1145,49 +1164,60 @@ mixin WidgetInspectorService { removePubRootDirectories(args); return null; }, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.getPubRootDirectories.name, callback: pubRootDirectories, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.setSelectionById.name, callback: setSelectionById, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getParentChain.name, callback: _getParentChain, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getProperties.name, callback: _getProperties, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getChildren.name, callback: _getChildren, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getChildrenSummaryTree.name, callback: _getChildrenSummaryTree, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getChildrenDetailsSubtree.name, callback: _getChildrenDetailsSubtree, + registerExtension: registerExtension, ); _registerObjectGroupServiceExtension( name: WidgetInspectorServiceExtensions.getRootWidget.name, callback: _getRootWidget, + registerExtension: registerExtension, ); _registerObjectGroupServiceExtension( name: WidgetInspectorServiceExtensions.getRootWidgetSummaryTree.name, callback: _getRootWidgetSummaryTree, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.getRootWidgetSummaryTreeWithPreviews.name, callback: _getRootWidgetSummaryTreeWithPreviews, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.getDetailsSubtree.name, @@ -1202,19 +1232,23 @@ mixin WidgetInspectorService { ), }; }, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getSelectedWidget.name, callback: _getSelectedWidget, + registerExtension: registerExtension, ); _registerServiceExtensionWithArg( name: WidgetInspectorServiceExtensions.getSelectedSummaryWidget.name, callback: _getSelectedSummaryWidget, + registerExtension: registerExtension, ); _registerSignalServiceExtension( name: WidgetInspectorServiceExtensions.isWidgetCreationTracked.name, callback: isWidgetCreationTracked, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.screenshot.name, @@ -1242,22 +1276,27 @@ mixin WidgetInspectorService { 'result': base64.encoder.convert(Uint8List.view(byteData!.buffer)), }; }, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.getLayoutExplorerNode.name, callback: _getLayoutExplorerNode, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.setFlexFit.name, callback: _setFlexFit, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.setFlexFactor.name, callback: _setFlexFactor, + registerExtension: registerExtension, ); registerServiceExtension( name: WidgetInspectorServiceExtensions.setFlexProperties.name, callback: _setFlexProperties, + registerExtension: registerExtension, ); } diff --git a/packages/flutter/test/widgets/widget_inspector_test_utils.dart b/packages/flutter/test/widgets/widget_inspector_test_utils.dart index f7b368663898f..c43e388b36364 100644 --- a/packages/flutter/test/widgets/widget_inspector_test_utils.dart +++ b/packages/flutter/test/widgets/widget_inspector_test_utils.dart @@ -47,6 +47,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { void registerServiceExtension({ required String name, required ServiceExtensionCallback callback, + required RegisterServiceExtensionCallback registerExtension, }) { assert(!extensions.containsKey(name)); extensions[name] = callback; From 99efd1b58511991b97cc2ec22cb4e1f5d843df18 Mon Sep 17 00:00:00 2001 From: Piotr FLEURY Date: Fri, 14 Jul 2023 00:00:55 +0200 Subject: [PATCH 0133/1547] Fix .env regex constants (#130072) Set `.env` regex list as constants. This pull request fixes the nit related in this comment: https://github.com/flutter/flutter/pull/128668#discussion_r1253377454 --- .../lib/src/runner/flutter_command.dart | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index b7e624b4e2589..204782e3d403a 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -34,6 +34,31 @@ import 'target_devices.dart'; export '../cache.dart' show DevelopmentArtifact; +abstract class DotEnvRegex { + // Dot env multi-line block value regex + static final RegExp multiLineBlock = RegExp(r'^\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*=\s*"""\s*(.*)$'); + + // Dot env full line value regex (eg FOO=bar) + // Entire line will be matched including key and value + static final RegExp keyValue = RegExp(r'^\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*=\s*(.*)?$'); + + // Dot env value wrapped in double quotes regex (eg FOO="bar") + // Value between double quotes will be matched (eg only bar in "bar") + static final RegExp doubleQuotedValue = RegExp(r'^"(.*)"\s*(\#\s*.*)?$'); + + // Dot env value wrapped in single quotes regex (eg FOO='bar') + // Value between single quotes will be matched (eg only bar in 'bar') + static final RegExp singleQuotedValue = RegExp(r"^'(.*)'\s*(\#\s*.*)?$"); + + // Dot env value wrapped in back quotes regex (eg FOO=`bar`) + // Value between back quotes will be matched (eg only bar in `bar`) + static final RegExp backQuotedValue = RegExp(r'^`(.*)`\s*(\#\s*.*)?$'); + + // Dot env value without quotes regex (eg FOO=bar) + // Value without quotes will be matched (eg full value after the equals sign) + static final RegExp unquotedValue = RegExp(r'^([^#\n\s]*)\s*(?:\s*#\s*(.*))?$'); +} + enum ExitStatus { success, warning, @@ -1390,45 +1415,39 @@ abstract class FlutterCommand extends Command { /// /// Returns a record of key and value as strings. MapEntry _parseProperty(String line) { - final RegExp blockRegExp = RegExp(r'^\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*=\s*"""\s*(.*)$'); - if (blockRegExp.hasMatch(line)) { + if (DotEnvRegex.multiLineBlock.hasMatch(line)) { throwToolExit('Multi-line value is not supported: $line'); } - final RegExp propertyRegExp = RegExp(r'^\s*([a-zA-Z_]+[a-zA-Z0-9_]*)\s*=\s*(.*)?$'); - final Match? match = propertyRegExp.firstMatch(line); - if (match == null) { + final Match? keyValueMatch = DotEnvRegex.keyValue.firstMatch(line); + if (keyValueMatch == null) { throwToolExit('Unable to parse file provided for ' '--${FlutterOptions.kDartDefineFromFileOption}.\n' 'Invalid property line: $line'); } - final String key = match.group(1)!; - final String value = match.group(2) ?? ''; + final String key = keyValueMatch.group(1)!; + final String value = keyValueMatch.group(2) ?? ''; // Remove wrapping quotes and trailing line comment. - final RegExp doubleQuoteValueRegExp = RegExp(r'^"(.*)"\s*(\#\s*.*)?$'); - final Match? doubleQuoteValue = doubleQuoteValueRegExp.firstMatch(value); - if (doubleQuoteValue != null) { - return MapEntry(key, doubleQuoteValue.group(1)!); + final Match? doubleQuotedValueMatch = DotEnvRegex.doubleQuotedValue.firstMatch(value); + if (doubleQuotedValueMatch != null) { + return MapEntry(key, doubleQuotedValueMatch.group(1)!); } - final RegExp quoteValueRegExp = RegExp(r"^'(.*)'\s*(\#\s*.*)?$"); - final Match? quoteValue = quoteValueRegExp.firstMatch(value); - if (quoteValue != null) { - return MapEntry(key, quoteValue.group(1)!); + final Match? singleQuotedValueMatch = DotEnvRegex.singleQuotedValue.firstMatch(value); + if (singleQuotedValueMatch != null) { + return MapEntry(key, singleQuotedValueMatch.group(1)!); } - final RegExp backQuoteValueRegExp = RegExp(r'^`(.*)`\s*(\#\s*.*)?$'); - final Match? backQuoteValue = backQuoteValueRegExp.firstMatch(value); - if (backQuoteValue != null) { - return MapEntry(key, backQuoteValue.group(1)!); + final Match? backQuotedValueMatch = DotEnvRegex.backQuotedValue.firstMatch(value); + if (backQuotedValueMatch != null) { + return MapEntry(key, backQuotedValueMatch.group(1)!); } - final RegExp noQuoteValueRegExp = RegExp(r'^([^#\n\s]*)\s*(?:\s*#\s*(.*))?$'); - final Match? noQuoteValue = noQuoteValueRegExp.firstMatch(value); - if (noQuoteValue != null) { - return MapEntry(key, noQuoteValue.group(1)!); + final Match? unquotedValueMatch = DotEnvRegex.unquotedValue.firstMatch(value); + if (unquotedValueMatch != null) { + return MapEntry(key, unquotedValueMatch.group(1)!); } return MapEntry(key, value); From f8c911656134563ac7b58ef5a81fa8ed3c5ad52c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 18:02:58 -0400 Subject: [PATCH 0134/1547] Roll Flutter Engine from c31cfc517274 to 1867efbf2936 (1 revision) (#130517) https://github.com/flutter/engine/compare/c31cfc517274...1867efbf2936 2023-07-13 skia-flutter-autoroll@skia.org Roll Dart SDK from 16ddfe8d08e0 to 9506d0c9f5ef (1 revision) (flutter/engine#43646) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8d346ab33e0e7..23dffd1f07776 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c31cfc517274a6cc5f988761e861575d93546863 +1867efbf2936c6bd6b9c25c9717378a38a92e037 From e1d025ae54a772c5ad12b1e2de01060688ba1d4d Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 13 Jul 2023 15:31:02 -0700 Subject: [PATCH 0135/1547] Move straggling Android Impeller test to staging. (#130529) --- .ci.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 5a63470e4f57a..101192113356a 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2217,8 +2217,10 @@ targets: - name: Linux_android list_text_layout_impeller_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: + ignore_flakiness: "true" tags: > ["devicelab", "android", "linux"] task_name: list_text_layout_impeller_perf__e2e_summary @@ -2321,6 +2323,7 @@ targets: presubmit: false timeout: 60 properties: + ignore_flakiness: "true" tags: > ["devicelab", "android", "linux", "samsung", "s10"] task_name: new_gallery_impeller__transition_perf @@ -2412,6 +2415,7 @@ targets: presubmit: false timeout: 60 properties: + ignore_flakiness: "true" tags: > ["devicelab", "android", "linux"] task_name: platform_views_scroll_perf_impeller__timeline_summary @@ -2422,6 +2426,7 @@ targets: presubmit: false timeout: 60 properties: + ignore_flakiness: "true" tags: > ["devicelab", "android", "linux", "samsung", "s10"] task_name: platform_views_scroll_perf_impeller__timeline_summary From 7fc49906b18981a542386e2ac66df0c54db7852e Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:41:57 -0700 Subject: [PATCH 0136/1547] Update `CardTheme`, `DrawerTheme`, `NavigationBar`, and `NavigationRailTheme` tests for M2/M3 (#130047) Updated unit tests for `CardTheme`, `DrawerTheme`, `NavigationBar`, and `NavigationRailTheme` to have M2 and M3 versions. More info in https://github.com/flutter/flutter/issues/127064 --- .../test/material/card_theme_test.dart | 29 +++++-- .../test/material/drawer_theme_test.dart | 82 +++++++++++++----- .../test/material/navigation_bar_test.dart | 84 +++++++++++++++++-- .../material/navigation_rail_theme_test.dart | 4 +- 4 files changed, 160 insertions(+), 39 deletions(-) diff --git a/packages/flutter/test/material/card_theme_test.dart b/packages/flutter/test/material/card_theme_test.dart index 992fbf937b222..2e22d13132a01 100644 --- a/packages/flutter/test/material/card_theme_test.dart +++ b/packages/flutter/test/material/card_theme_test.dart @@ -22,7 +22,7 @@ void main() { expect(identical(CardTheme.lerp(theme, theme, 0.5), theme), true); }); - testWidgets('Passing no CardTheme returns defaults', (WidgetTester tester) async { + testWidgets('Material3 - Passing no CardTheme returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, @@ -117,9 +117,8 @@ void main() { expect(material.color, cardTheme.color); }); - testWidgets('ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { - final ThemeData themeData = _themeData(); - final bool material3 = themeData.useMaterial3; + testWidgets('Material3 - ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { + final ThemeData themeData = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: themeData, @@ -129,10 +128,10 @@ void main() { )); final Material material = _getCardMaterial(tester); - expect(material.color, material3 ? themeData.colorScheme.surface: themeData.cardColor); + expect(material.color, themeData.colorScheme.surface); }); - testWidgets('CardTheme customizes shape', (WidgetTester tester) async { + testWidgets('Material3 - CardTheme customizes shape', (WidgetTester tester) async { const CardTheme cardTheme = CardTheme( color: Colors.white, shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(7))), @@ -166,7 +165,21 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Passing no CardTheme returns defaults - M2', (WidgetTester tester) async { + testWidgets('Material2 - ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { + final ThemeData themeData = ThemeData(useMaterial3: false); + + await tester.pumpWidget(MaterialApp( + theme: themeData, + home: const Scaffold( + body: Card(), + ), + )); + + final Material material = _getCardMaterial(tester); + expect(material.color, themeData.cardColor); + }); + + testWidgets('Material2 - Passing no CardTheme returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -188,7 +201,7 @@ void main() { )); }); - testWidgets('CardTheme customizes shape - M2', (WidgetTester tester) async { + testWidgets('Material2 - CardTheme customizes shape', (WidgetTester tester) async { const CardTheme cardTheme = CardTheme( color: Colors.white, shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(7))), diff --git a/packages/flutter/test/material/drawer_theme_test.dart b/packages/flutter/test/material/drawer_theme_test.dart index 1a25f288e7f64..c7a24d2d48337 100644 --- a/packages/flutter/test/material/drawer_theme_test.dart +++ b/packages/flutter/test/material/drawer_theme_test.dart @@ -58,10 +58,9 @@ void main() { ]); }); - testWidgets('Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { + testWidgets('Material2 - Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); - final ThemeData theme = ThemeData(); - final bool useMaterial3 = theme.useMaterial3; + final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( MaterialApp( theme: theme, @@ -74,24 +73,69 @@ void main() { scaffoldKey.currentState!.openDrawer(); await tester.pumpAndSettle(); - expect(_drawerMaterial(tester).color, useMaterial3 ? theme.colorScheme.surface : null); - expect(_drawerMaterial(tester).elevation, useMaterial3 ? 1.0 : 16.0); - expect(_drawerMaterial(tester).shadowColor, useMaterial3 ? Colors.transparent : ThemeData().shadowColor); - expect(_drawerMaterial(tester).surfaceTintColor, useMaterial3 ? theme.colorScheme.surfaceTint : null); + expect(_drawerMaterial(tester).color, null); + expect(_drawerMaterial(tester).elevation, 16.0); + expect(_drawerMaterial(tester).shadowColor, theme.shadowColor); + expect(_drawerMaterial(tester).surfaceTintColor, null); + expect(_drawerMaterial(tester).shape, null); + expect(_scrim(tester).color, Colors.black54); + expect(_drawerRenderBox(tester).size.width, 304.0); + }); + + testWidgets('Material3 - Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + final ThemeData theme = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + key: scaffoldKey, + drawer: const Drawer(), + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pumpAndSettle(); + + expect(_drawerMaterial(tester).color, theme.colorScheme.surface); + expect(_drawerMaterial(tester).elevation, 1.0); + expect(_drawerMaterial(tester).shadowColor, Colors.transparent); + expect(_drawerMaterial(tester).surfaceTintColor, theme.colorScheme.surfaceTint); expect( _drawerMaterial(tester).shape, - useMaterial3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(right: Radius.circular(16.0))) - : null, + const RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(right: Radius.circular(16.0))) ); expect(_scrim(tester).color, Colors.black54); expect(_drawerRenderBox(tester).size.width, 304.0); }); - testWidgets('Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { + testWidgets('Material2 - Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + final ThemeData theme = ThemeData(useMaterial3: false); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + key: scaffoldKey, + endDrawer: const Drawer(), + ), + ), + ); + scaffoldKey.currentState!.openEndDrawer(); + await tester.pumpAndSettle(); + + expect(_drawerMaterial(tester).color, null); + expect(_drawerMaterial(tester).elevation, 16.0); + expect(_drawerMaterial(tester).shadowColor, theme.shadowColor); + expect(_drawerMaterial(tester).surfaceTintColor, null); + expect(_drawerMaterial(tester).shape, null); + expect(_scrim(tester).color, Colors.black54); + expect(_drawerRenderBox(tester).size.width, 304.0); + }); + + testWidgets('Material3 - Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); - final ThemeData theme = ThemeData(); - final bool useMaterial3 = theme.useMaterial3; + final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( theme: theme, @@ -104,15 +148,13 @@ void main() { scaffoldKey.currentState!.openEndDrawer(); await tester.pumpAndSettle(); - expect(_drawerMaterial(tester).color, useMaterial3 ? theme.colorScheme.surface : null); - expect(_drawerMaterial(tester).elevation, useMaterial3 ? 1.0 : 16.0); - expect(_drawerMaterial(tester).shadowColor, useMaterial3 ? Colors.transparent : ThemeData().shadowColor); - expect(_drawerMaterial(tester).surfaceTintColor, useMaterial3 ? ThemeData().colorScheme.surfaceTint : null); + expect(_drawerMaterial(tester).color, theme.colorScheme.surface); + expect(_drawerMaterial(tester).elevation, 1.0); + expect(_drawerMaterial(tester).shadowColor, Colors.transparent); + expect(_drawerMaterial(tester).surfaceTintColor, theme.colorScheme.surfaceTint); expect( _drawerMaterial(tester).shape, - useMaterial3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(16.0))) - : null, + const RoundedRectangleBorder(borderRadius: BorderRadius.horizontal(left: Radius.circular(16.0))) ); expect(_scrim(tester).color, Colors.black54); expect(_drawerRenderBox(tester).size.width, 304.0); diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index 77e6ecc0d76df..cf942f175254f 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -246,7 +246,7 @@ void main() { ); }); - testWidgets('NavigationBar uses proper defaults when no parameters are given - M2', (WidgetTester tester) async { + testWidgets('Material2 - NavigationBar uses proper defaults when no parameters are given', (WidgetTester tester) async { // M2 settings that were hand coded. await tester.pumpWidget( _buildWidget( @@ -275,7 +275,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))); }); - testWidgets('NavigationBar uses proper defaults when no parameters are given - M3', (WidgetTester tester) async { + testWidgets('Material3 - NavigationBar uses proper defaults when no parameters are given', (WidgetTester tester) async { // M3 settings from the token database. final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -305,7 +305,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder()); }); - testWidgets('NavigationBar shows tooltips with text scaling ', (WidgetTester tester) async { + testWidgets('Material2 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { const String label = 'A'; Widget buildApp({ required double textScaleFactor }) { @@ -364,6 +364,72 @@ void main() { expect(tester.getSize(find.text(label).last), Size(defaultTooltipSize.width * 4, defaultTooltipSize.height * 4)); }); + testWidgets('Material3 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { + const String label = 'A'; + + Widget buildApp({ required double textScaleFactor }) { + return MediaQuery( + data: MediaQueryData(textScaleFactor: textScaleFactor), + child: Localizations( + locale: const Locale('en', 'US'), + delegates: const >[ + DefaultMaterialLocalizations.delegate, + DefaultWidgetsLocalizations.delegate, + ], + child: MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Navigator( + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + builder: (BuildContext context) { + return Scaffold( + bottomNavigationBar: NavigationBar( + destinations: const [ + NavigationDestination( + label: label, + icon: Icon(Icons.ac_unit), + tooltip: label, + ), + NavigationDestination( + label: 'B', + icon: Icon(Icons.battery_alert), + ), + ], + ), + ); + }, + ); + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildApp(textScaleFactor: 1.0)); + expect(find.text(label), findsOneWidget); + await tester.longPress(find.text(label)); + expect(find.text(label), findsNWidgets(2)); + + if (kIsWeb && !isCanvasKit) { + expect(tester.getSize(find.text(label).last), const Size(15.0, 21.0)); + } else { + expect(tester.getSize(find.text(label).last), const Size(15.0, 20.0)); + } + // The duration is needed to ensure the tooltip disappears. + await tester.pumpAndSettle(const Duration(seconds: 2)); + + await tester.pumpWidget(buildApp(textScaleFactor: 4.0)); + expect(find.text(label), findsOneWidget); + await tester.longPress(find.text(label)); + + if (kIsWeb && !isCanvasKit) { + expect(tester.getSize(find.text(label).last), const Size(57.0, 81.0)); + } else { + expect(tester.getSize(find.text(label).last), const Size(57.0, 80.0)); + } + }); + testWidgets('Custom tooltips in NavigationBarDestination', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( @@ -566,7 +632,7 @@ void main() { expect(newHeight, equals(initialHeight)); }); - testWidgets('Navigation indicator renders ripple', (WidgetTester tester) async { + testWidgets('Material3 - Navigation indicator renders ripple', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/116751. int selectedIndex = 0; @@ -767,7 +833,7 @@ void main() { ); }); - testWidgets('Navigation indicator ripple golden test', (WidgetTester tester) async { + testWidgets('Material3 - Navigation indicator ripple golden test', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117420. Widget buildWidget({ NavigationDestinationLabelBehavior? labelBehavior }) { @@ -875,7 +941,7 @@ void main() { expect(transform.getColumn(0)[0], 1.0); }); - testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgets('Material3 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); const ShapeBorder shape = RoundedRectangleBorder(); @@ -921,7 +987,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgets('Material2 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const Color color = Color(0xff0000ff); const ShapeBorder shape = RoundedRectangleBorder(); @@ -965,7 +1031,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, shape); }); - testWidgets('Navigation indicator renders ripple', (WidgetTester tester) async { + testWidgets('Material2 - Navigation indicator renders ripple', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/116751. int selectedIndex = 0; @@ -1166,7 +1232,7 @@ void main() { ); }); - testWidgets('Navigation indicator ripple golden test', (WidgetTester tester) async { + testWidgets('Material2 - Navigation indicator ripple golden test', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117420. Widget buildWidget({ NavigationDestinationLabelBehavior? labelBehavior }) { diff --git a/packages/flutter/test/material/navigation_rail_theme_test.dart b/packages/flutter/test/material/navigation_rail_theme_test.dart index bf77080fd61f9..7a56586ca2643 100644 --- a/packages/flutter/test/material/navigation_rail_theme_test.dart +++ b/packages/flutter/test/material/navigation_rail_theme_test.dart @@ -12,7 +12,7 @@ void main() { expect(const NavigationRailThemeData().hashCode, const NavigationRailThemeData().copyWith().hashCode); }); - testWidgets('Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { + testWidgets('Material3 - Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); // Material 3 defaults await tester.pumpWidget( @@ -47,7 +47,7 @@ void main() { expect(inkResponse.customBorder, const StadiumBorder()); }); - testWidgets('Default values are used when no NavigationRail or NavigationRailThemeData properties are specified (Material 2)', (WidgetTester tester) async { + testWidgets('Material2 - Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { // This test can be removed when `useMaterial3` is deprecated. await tester.pumpWidget( MaterialApp( From 03749051e89d39b4267b355820e644cac8cced1c Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 13 Jul 2023 15:53:51 -0700 Subject: [PATCH 0137/1547] Always escape when writing pubspec.yaml's 'description' field. (#130096) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/flutter/flutter/issues/80013. **Before**: ``` $ flutter create test1 --description "a: b" Creating project test1... Error detected in pubspec.yaml: Error on line 2, column 15: Mapping values are not allowed here. Did you miss a colon earlier? ╷ 2 │ description: a: b │ ^ ╵ Please correct the pubspec.yaml file at /Users/matan/Developer/scratch/test1/pubspec.yaml ``` **After**: ``` $ flutter create test1 --description "a: b" Creating project test1... Resolving dependencies in test1... Got dependencies in test1. Wrote 129 files. All done! You can find general documentation for Flutter at: https://docs.flutter.dev/ Detailed API documentation is available at: https://api.flutter.dev/ If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev In order to run your application, type: $ cd test1 $ flutter run Your application code is in test1/lib/main.dart. ``` --- It's worth noting that this _always_ escapes a non-empty project description, which means that descriptions that were not previously wrapped in `"`s' will be. I'm not sure how worth it is to do a _conditional_ escape (i.e. only escape if not escaping would cause a problem), but willing to change. Side-note: I had no idea where to list this test in the (very large) `create_test.dart`, so I did my best :) --- .../lib/src/commands/create_base.dart | 2 +- .../commands.shard/permeable/create_test.dart | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index 90c3fa00bbb82..36e84c40f4d1f 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -389,7 +389,7 @@ abstract class CreateBase extends FlutterCommand { 'macosIdentifier': appleIdentifier, 'linuxIdentifier': linuxIdentifier, 'windowsIdentifier': windowsIdentifier, - 'description': projectDescription, + 'description': projectDescription != null ? escapeYamlString(projectDescription) : null, 'dartSdk': '$flutterRoot/bin/cache/dart-sdk', 'androidMinApiLevel': android_common.minApiLevel, 'androidSdkVersion': kAndroidSdkMinVersion, diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 9069a35351744..1663f8cdaf2ea 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -3266,6 +3266,24 @@ void main() { ), }); + testUsingContext('should escape ":" in project description', () async { + await _createProject( + projectDir, + [ + '--no-pub', + '--description', + 'a: b', + ], + [ + 'pubspec.yaml', + ], + ); + + final String rawPubspec = await projectDir.childFile('pubspec.yaml').readAsString(); + final Pubspec pubspec = Pubspec.parse(rawPubspec); + expect(pubspec.description, 'a: b'); + }); + testUsingContext('create an FFI plugin with ios, then add macos', () async { Cache.flutterRoot = '../..'; From 7abdb866cc556fa4a2c72efc15bd4b5307376ac8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 18:53:54 -0400 Subject: [PATCH 0138/1547] Roll Flutter Engine from 1867efbf2936 to 0f0436b28430 (1 revision) (#130526) https://github.com/flutter/engine/compare/1867efbf2936...0f0436b28430 2023-07-13 jason-simmons@users.noreply.github.com Fix a Fuchsia formatter type mismatch flagged by the pending Clang roll (flutter/engine#43651) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 23dffd1f07776..ccff2fdc4eec1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1867efbf2936c6bd6b9c25c9717378a38a92e037 +0f0436b28430bd79e854f2294a60aa33417068fa From 26a17a4cbae9aa2111ade7cd0adb812e27a7167a Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 13 Jul 2023 16:24:21 -0700 Subject: [PATCH 0139/1547] Upgrade leak_tracker. (#130528) --- packages/flutter/pubspec.yaml | 6 +++--- packages/flutter/test/flutter_test_config.dart | 2 +- packages/flutter/test/foundation/leak_tracking.dart | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 5cae5d9304cec..903a71153caef 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,8 +22,8 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 7.0.8 - leak_tracker_testing: 1.0.0 + leak_tracker: 8.0.0 + leak_tracker_testing: 1.0.2 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5af4 +# PUBSPEC CHECKSUM: c3ef diff --git a/packages/flutter/test/flutter_test_config.dart b/packages/flutter/test/flutter_test_config.dart index 0be2e3a439b64..e8d488aff5fe2 100644 --- a/packages/flutter/test/flutter_test_config.dart +++ b/packages/flutter/test/flutter_test_config.dart @@ -23,7 +23,7 @@ Future testExecutable(FutureOr Function() testMain) { // receive the event. WidgetController.hitTestWarningShouldBeFatal = true; - LeakTrackingTestConfig.warnForNonSupportedPlatforms = false; + LeakTrackerGlobalSettings.warnForNonSupportedPlatforms = false; // Enable golden file testing using Skia Gold. return flutter_goldens.testExecutable(testMain); diff --git a/packages/flutter/test/foundation/leak_tracking.dart b/packages/flutter/test/foundation/leak_tracking.dart index 37b169cda0450..86cf3fa0bea89 100644 --- a/packages/flutter/test/foundation/leak_tracking.dart +++ b/packages/flutter/test/foundation/leak_tracking.dart @@ -99,7 +99,7 @@ Future _withFlutterLeakTracking( ) async { // Leak tracker does not work for web platform. if (kIsWeb) { - final bool shouldPrintWarning = !_webWarningPrinted && LeakTrackingTestConfig.warnForNonSupportedPlatforms; + final bool shouldPrintWarning = !_webWarningPrinted && LeakTrackerGlobalSettings.warnForNonSupportedPlatforms; if (shouldPrintWarning) { _webWarningPrinted = true; debugPrint('Leak tracking is not supported on web platform.\nTo turn off this message, set `LeakTrackingTestConfig.warnForNonSupportedPlatforms` to false.'); From bd18e78c9c08a1db1aefd8528886365f8ec0e8e3 Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Thu, 13 Jul 2023 16:46:49 -0700 Subject: [PATCH 0140/1547] Fix `timeOfDayFormat` for Danish (#130437) See title. According to [CLDR](https://icu4c-demos.unicode.org/icu-bin/locexp?_=da_DK&d_=en&_l=da), proper time of day format should be `HH.mm`. Fixes https://github.com/flutter/flutter/issues/130234. --- .../lib/src/l10n/generated_material_localizations.dart | 2 +- packages/flutter_localizations/lib/src/l10n/material_da.arb | 2 +- .../flutter_localizations/test/material/date_time_test.dart | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index d936427c1653a..7d008703cf374 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -6204,7 +6204,7 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { String get tabLabelRaw => r'Fane $tabIndex af $tabCount'; @override - TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.HH_colon_mm; + TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.HH_dot_mm; @override String get timePickerDialHelpText => 'Vælg tidspunkt'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_da.arb b/packages/flutter_localizations/lib/src/l10n/material_da.arb index 52c309eda3564..a2dc08864ff7e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_da.arb @@ -1,6 +1,6 @@ { "scriptCategory": "English-like", - "timeOfDayFormat": "HH:mm", + "timeOfDayFormat": "HH.mm", "openAppDrawerTooltip": "Åbn navigationsmenuen", "backButtonTooltip": "Tilbage", "closeButtonTooltip": "Luk", diff --git a/packages/flutter_localizations/test/material/date_time_test.dart b/packages/flutter_localizations/test/material/date_time_test.dart index 6fb4aece19af3..4cab48f84b1a0 100644 --- a/packages/flutter_localizations/test/material/date_time_test.dart +++ b/packages/flutter_localizations/test/material/date_time_test.dart @@ -110,6 +110,7 @@ void main() { testWidgets('formats ${TimeOfDayFormat.HH_dot_mm}', (WidgetTester tester) async { expect(await formatTimeOfDay(tester, const Locale('fi'), const TimeOfDay(hour: 20, minute: 32)), '20.32'); expect(await formatTimeOfDay(tester, const Locale('fi'), const TimeOfDay(hour: 9, minute: 32)), '09.32'); + expect(await formatTimeOfDay(tester, const Locale('da'), const TimeOfDay(hour: 9, minute: 32)), '09.32'); }); testWidgets('formats ${TimeOfDayFormat.frenchCanadian}', (WidgetTester tester) async { From a7a353ca2b9a02714ab8b592b86f5bd325f4b8b4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 20:24:53 -0400 Subject: [PATCH 0141/1547] Roll Flutter Engine from 0f0436b28430 to 8a42bfc80e3a (6 revisions) (#130538) https://github.com/flutter/engine/compare/0f0436b28430...8a42bfc80e3a 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from 52613fcc0780 to 9e4f5cc3aeb4 (1 revision) (flutter/engine#43659) 2023-07-13 jonahwilliams@google.com [Impeller] no-op fragment program on Android until it works. (flutter/engine#43657) 2023-07-13 31859944+LongCatIsLooong@users.noreply.github.com Reland #43118 "Add a flag to ParagraphBuilder for rounding hack migration" (flutter/engine#43647) 2023-07-13 ychris@google.com Unmerge threads if the current merger is the only one that's merged. (flutter/engine#43652) 2023-07-13 dnfield@google.com Revert https://github.com/flutter/engine/pull/43533 (flutter/engine#43654) 2023-07-13 skia-flutter-autoroll@skia.org Roll Skia from 743ad92f5de2 to 52613fcc0780 (9 revisions) (flutter/engine#43655) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ccff2fdc4eec1..270b24ec6f671 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0f0436b28430bd79e854f2294a60aa33417068fa +8a42bfc80e3ad61a2da11f084bddf4b436778ff4 From c01d2b7f66c1f1187460ffba66cce54ee0285420 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 21:26:14 -0400 Subject: [PATCH 0142/1547] Roll Flutter Engine from 8a42bfc80e3a to 601f0c173b8e (1 revision) (#130544) https://github.com/flutter/engine/compare/8a42bfc80e3a...601f0c173b8e 2023-07-13 jason-simmons@users.noreply.github.com Fix a clang-tidy warning about a potentially nil value in the editingState dictionary (flutter/engine#43660) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 270b24ec6f671..bc5278aeddc99 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8a42bfc80e3ad61a2da11f084bddf4b436778ff4 +601f0c173b8ea8ed6484b24a960d3b60b414fc66 From 46125d07db603d6b053270aab8c826721a16ef2f Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 13 Jul 2023 18:43:47 -0700 Subject: [PATCH 0143/1547] Mention saveLayer in the CustomPainter docs. (#130520) Fixes https://github.com/flutter/flutter/issues/11002 --- .../flutter/lib/src/rendering/custom_paint.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/flutter/lib/src/rendering/custom_paint.dart b/packages/flutter/lib/src/rendering/custom_paint.dart index e59d51ad99439..cb2142315ce1d 100644 --- a/packages/flutter/lib/src/rendering/custom_paint.dart +++ b/packages/flutter/lib/src/rendering/custom_paint.dart @@ -119,6 +119,23 @@ typedef SemanticsBuilderCallback = List Function(Size si /// ``` /// {@end-tool} /// +/// ## Composition and the sharing of canvases +/// +/// Widgets (or rather, render objects) are composited together using a minimum +/// number of [Canvas]es, for performance reasons. As a result, a +/// [CustomPainter]'s [Canvas] may be the same as that used by other widgets +/// (including other [CustomPaint] widgets). +/// +/// This is mostly unnoticeable, except when using unusual [BlendMode]s. For +/// example, trying to use [BlendMode.dstOut] to "punch a hole" through a +/// previously-drawn image may erase more than was intended, because previous +/// widgets will have been painted onto the same canvas. +/// +/// To avoid this issue, consider using [Canvas.saveLayer] and +/// [Canvas.restore] when using such blend modes. Creating new layers is +/// relatively expensive, however, and should be done sparingly to avoid +/// introducing jank. +/// /// See also: /// /// * [Canvas], the class that a custom painter uses to paint. From 90ed1dfab49002f90e8fd568c7d8f76b0713c3c2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 22:09:26 -0400 Subject: [PATCH 0144/1547] Roll Flutter Engine from 601f0c173b8e to 77d8ec0a096c (2 revisions) (#130549) https://github.com/flutter/engine/compare/601f0c173b8e...77d8ec0a096c 2023-07-14 ian@hixie.ch Add more points to [MediaQuery]. (flutter/engine#43649) 2023-07-14 ian@hixie.ch Remove unimplemented API call saveCompilationTrace (flutter/engine#43656) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bc5278aeddc99..223a3c53cd63e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -601f0c173b8ea8ed6484b24a960d3b60b414fc66 +77d8ec0a096c1649b967324f7eef81b67b45c2d1 From a6fb2e0aca64d843749bdeaf2003a5c756f96d87 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 13 Jul 2023 23:29:07 -0400 Subject: [PATCH 0145/1547] Roll Flutter Engine from 77d8ec0a096c to 2262a871c10a (1 revision) (#130551) https://github.com/flutter/engine/compare/77d8ec0a096c...2262a871c10a 2023-07-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 9506d0c9f5ef to 8f49edfb6989 (1 revision) (flutter/engine#43665) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 223a3c53cd63e..349f25ea95c78 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -77d8ec0a096c1649b967324f7eef81b67b45c2d1 +2262a871c10a85ae68faee11891dc494bb45aa85 From 4c0c8c30456aa1bd7ff911aef3f9df2ccc3e345b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 00:37:12 -0400 Subject: [PATCH 0146/1547] Roll Flutter Engine from 2262a871c10a to 8d14461f7bc3 (1 revision) (#130555) https://github.com/flutter/engine/compare/2262a871c10a...8d14461f7bc3 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 9e4f5cc3aeb4 to ffed127e8974 (1 revision) (flutter/engine#43666) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 349f25ea95c78..69c5b8c6beaa2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2262a871c10a85ae68faee11891dc494bb45aa85 +8d14461f7bc35a10873da2f71c894ade0111a308 From e90f980f4033567c8153f3c77c5b0fd2c911f62f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 01:23:05 -0400 Subject: [PATCH 0147/1547] Roll Flutter Engine from 8d14461f7bc3 to 0428c9d53e99 (1 revision) (#130556) https://github.com/flutter/engine/compare/8d14461f7bc3...0428c9d53e99 2023-07-14 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from rRUd41Mv9NI0n3Iyc... to J0oxaSt651gKgDreU... (flutter/engine#43667) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from rRUd41Mv9NI0 to J0oxaSt651gK If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 69c5b8c6beaa2..48cf3ffe23e4f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8d14461f7bc35a10873da2f71c894ade0111a308 +0428c9d53e992c8400eec020462566d6725bcf28 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 79ea6aaa3d83a..519e77eb3d4e5 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -rRUd41Mv9NI0n3IycuJXEbDEmYYuE1P9aTHCcu_c0NkC +J0oxaSt651gKgDreUUVzse6-xsrejysSrYuIslJ3BZ0C From c3cd01661cf8143cd15fd3b6c3236ae112fef286 Mon Sep 17 00:00:00 2001 From: lsaudon Date: Fri, 14 Jul 2023 08:58:00 +0200 Subject: [PATCH 0148/1547] Tap on button behind snack bar defined by margin (#127959) If the margin is used, set the `HitTestBehavior` to `deferToChild`. *List which issues are fixed by this PR. You must list at least one issue.* #78537 #114810 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../flutter/lib/src/material/snack_bar.dart | 12 ++ .../flutter/test/material/snack_bar_test.dart | 170 ++++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index 5dea738bc0bfa..ce3df05095567 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -283,6 +283,7 @@ class SnackBar extends StatefulWidget { this.padding, this.width, this.shape, + this.hitTestBehavior, this.behavior, this.action, this.actionOverflowThreshold, @@ -331,6 +332,8 @@ class SnackBar extends StatefulWidget { /// If this property is null, then [SnackBarThemeData.insetPadding] of /// [ThemeData.snackBarTheme] is used. If that is also null, then the default is /// `EdgeInsets.fromLTRB(15.0, 5.0, 15.0, 10.0)`. + /// + /// If this property is not null and [hitTestBehavior] is null, then [hitTestBehavior] default is [HitTestBehavior.deferToChild]. final EdgeInsetsGeometry? margin; /// The amount of padding to apply to the snack bar's content and optional @@ -384,6 +387,13 @@ class SnackBar extends StatefulWidget { /// circular corner radius of 4.0. final ShapeBorder? shape; + /// Defines how the snack bar area, including margin, will behave during hit testing. + /// + /// If this property is null and [margin] is not null, then [HitTestBehavior.deferToChild] is used by default. + /// + /// Please refer to [HitTestBehavior] for a detailed explanation of every behavior. + final HitTestBehavior? hitTestBehavior; + /// This defines the behavior and location of the snack bar. /// /// Defines where a [SnackBar] should appear within a [Scaffold] and how its @@ -489,6 +499,7 @@ class SnackBar extends StatefulWidget { padding: padding, width: width, shape: shape, + hitTestBehavior: hitTestBehavior, behavior: behavior, action: action, actionOverflowThreshold: actionOverflowThreshold, @@ -776,6 +787,7 @@ class _SnackBarState extends State { key: const Key('dismissible'), direction: widget.dismissDirection, resizeDuration: null, + behavior: widget.hitTestBehavior ?? (widget.margin != null ? HitTestBehavior.deferToChild : HitTestBehavior.opaque), onDismissed: (DismissDirection direction) { ScaffoldMessenger.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.swipe); }, diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index a31753412f845..0cd5479071306 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -7,6 +7,7 @@ @Tags(['reduced-test-set']) library; +import 'dart:async'; import 'dart:ui'; import 'package:flutter/material.dart'; @@ -2915,6 +2916,175 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes expect(material.clipBehavior, Clip.antiAlias); }); + + testWidgets('Tap on button behind snack bar defined by width', (WidgetTester tester) async { + tester.view.physicalSize = const Size.square(200); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + + const String buttonText = 'Show snackbar'; + const String snackbarContent = 'Snackbar'; + const String buttonText2 = 'Try press me'; + + final Completer completer = Completer(); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ElevatedButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + behavior: SnackBarBehavior.floating, + width: 100, + content: Text(snackbarContent), + ), + ); + }, + child: const Text(buttonText), + ), + ElevatedButton( + onPressed: () { + completer.complete(); + }, + child: const Text(buttonText2), + ), + ], + ); + }, + ), + ), + )); + + await tester.tap(find.text(buttonText)); + await tester.pumpAndSettle(); + + expect(find.text(snackbarContent), findsOneWidget); + await tester.tapAt(tester.getTopLeft(find.text(buttonText2))); + expect(find.text(snackbarContent), findsOneWidget); + + expect(completer.isCompleted, true); + }); + + + testWidgets('Tap on button behind snack bar defined by margin', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/78537. + tester.view.physicalSize = const Size.square(200); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + + const String buttonText = 'Show snackbar'; + const String snackbarContent = 'Snackbar'; + const String buttonText2 = 'Try press me'; + + final Completer completer = Completer(); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ElevatedButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + behavior: SnackBarBehavior.floating, + margin: EdgeInsets.only(left: 100), + content: Text(snackbarContent), + ), + ); + }, + child: const Text(buttonText), + ), + ElevatedButton( + onPressed: () { + completer.complete(); + }, + child: const Text(buttonText2), + ), + ], + ); + }, + ), + ), + )); + + await tester.tap(find.text(buttonText)); + await tester.pumpAndSettle(); + + expect(find.text(snackbarContent), findsOneWidget); + await tester.tapAt(tester.getTopLeft(find.text(buttonText2))); + expect(find.text(snackbarContent), findsOneWidget); + + expect(completer.isCompleted, true); + }); + + testWidgets("Can't tap on button behind snack bar defined by margin and HitTestBehavior.opaque", (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/78537. + tester.view.physicalSize = const Size.square(200); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + + const String buttonText = 'Show snackbar'; + const String snackbarContent = 'Snackbar'; + const String buttonText2 = 'Try press me'; + + final Completer completer = Completer(); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ElevatedButton( + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + hitTestBehavior: HitTestBehavior.opaque, + behavior: SnackBarBehavior.floating, + margin: EdgeInsets.only(left: 100), + content: Text(snackbarContent), + ), + ); + }, + child: const Text(buttonText), + ), + ElevatedButton( + onPressed: () { + completer.complete(); + }, + child: const Text(buttonText2), + ), + ], + ); + }, + ), + ), + )); + + await tester.tap(find.text(buttonText)); + await tester.pumpAndSettle(); + + expect(find.text(snackbarContent), findsOneWidget); + await tester.tapAt(tester.getTopLeft(find.text(buttonText2))); + expect(find.text(snackbarContent), findsOneWidget); + + expect(completer.isCompleted, false); + }); } /// Start test for "SnackBar dismiss test". From 4320abbd95445f6971ddcbf9da99d22f4e223a91 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 03:06:22 -0400 Subject: [PATCH 0149/1547] Roll Flutter Engine from 0428c9d53e99 to fcecec871aae (1 revision) (#130561) https://github.com/flutter/engine/compare/0428c9d53e99...fcecec871aae 2023-07-14 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -csWUV7Dv3hETOoDw... to LZPMbHnVPFdbXndcX... (flutter/engine#43669) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from -csWUV7Dv3hE to LZPMbHnVPFdb If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 48cf3ffe23e4f..05b7b3c5cfaea 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0428c9d53e992c8400eec020462566d6725bcf28 +fcecec871aae26167ee2c96383e0a50f9cf58872 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 6ca48adbc0863..eb21e465df060 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ --csWUV7Dv3hETOoDwiBHVjB-2sa36bEnpFP8NDjE7ucC +LZPMbHnVPFdbXndcXVTMyrYiv-0ooqPmxW2FSTAilQgC From feab85451697da601ab9bbb8119a3e966d37bfc6 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 14 Jul 2023 10:36:36 +0300 Subject: [PATCH 0150/1547] Update `DialogTheme` tests for M2/M3 (#130414) Updated unit tests for `DialogTheme` to have M2 and M3 versions. More info in https://github.com/flutter/flutter/pull/128725 --- .../test/material/dialog_theme_test.dart | 108 ++++++++++++++---- 1 file changed, 88 insertions(+), 20 deletions(-) diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index f215649d4826c..22c78e3a817e4 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -165,7 +165,31 @@ void main() { expect(bottomLeft.dy, 576.0); }); - testWidgets('Dialog alignment takes priority over theme', (WidgetTester tester) async { + testWidgets('Material3 - Dialog alignment takes priority over theme', (WidgetTester tester) async { + const AlertDialog dialog = AlertDialog( + title: Text('Title'), + actions: [ ], + alignment: Alignment.topRight, + ); + final ThemeData theme = ThemeData( + useMaterial3: true, + dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft), + ); + + await tester.pumpWidget( + _appWithDialog(tester, dialog, theme: theme), + ); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final Offset bottomLeft = tester.getBottomLeft( + find.descendant(of: find.byType(Dialog), matching: find.byType(Material)), + ); + expect(bottomLeft.dx, 480.0); + expect(bottomLeft.dy, 124.0); + }); + + testWidgets('Material2 - Dialog alignment takes priority over theme', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], @@ -186,7 +210,29 @@ void main() { expect(bottomLeft.dy, 104.0); }); - testWidgets('Custom dialog shape matches golden', (WidgetTester tester) async { + testWidgets('Material3 - Custom dialog shape matches golden', (WidgetTester tester) async { + const RoundedRectangleBorder customBorder = + RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); + const AlertDialog dialog = AlertDialog( + title: Text('Title'), + actions: [ ], + ); + final ThemeData theme = ThemeData( + useMaterial3: true, + dialogTheme: const DialogTheme(shape: customBorder), + ); + + await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + await expectLater( + find.byKey(_painterKey), + matchesGoldenFile('m3_dialog_theme.dialog_with_custom_border.png'), + ); + }); + + testWidgets('Material2 - Custom dialog shape matches golden', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -201,7 +247,7 @@ void main() { await expectLater( find.byKey(_painterKey), - matchesGoldenFile('dialog_theme.dialog_with_custom_border.png'), + matchesGoldenFile('m2_dialog_theme.dialog_with_custom_border.png'), ); }); @@ -246,9 +292,8 @@ void main() { expect(text.text.style!.color, dialogThemeColor); }); - testWidgets('Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { - const Color iconThemeColor = Colors.yellow; - final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); + testWidgets('Material3 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: [ ], @@ -260,11 +305,12 @@ void main() { // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); - expect(text.text.style!.color, iconThemeColor); + expect(text.text.style!.color, theme.colorScheme.secondary); }); - testWidgets('Custom Icon Color - Theme - lowest preference for M3', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); + testWidgets('Material2 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + const Color iconThemeColor = Colors.yellow; + final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: [ ], @@ -276,7 +322,7 @@ void main() { // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); - expect(text.text.style!.color, theme.colorScheme.secondary); + expect(text.text.style!.color, iconThemeColor); }); testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { @@ -313,13 +359,24 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Custom Title Text Style - Theme', (WidgetTester tester) async { + testWidgets('Material3 - Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog( - title: Text(titleText), - actions: [ ], - ); + const AlertDialog dialog = AlertDialog(title: Text(titleText)); + final ThemeData theme = ThemeData(useMaterial3: true, textTheme: const TextTheme(headlineSmall: titleTextStyle)); + + await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final RenderParagraph title = _getTextRenderObject(tester, titleText); + expect(title.text.style!.color, titleTextStyle.color); + }); + + testWidgets('Material2 - Custom Title Text Style - Theme', (WidgetTester tester) async { + const String titleText = 'Title'; + const TextStyle titleTextStyle = TextStyle(color: Colors.pink); + const AlertDialog dialog = AlertDialog(title: Text(titleText)); final ThemeData theme = ThemeData(useMaterial3: false, textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); @@ -412,13 +469,24 @@ void main() { expect(content.text.style, contentTextStyle); }); - testWidgets('Custom Content Text Style - Theme', (WidgetTester tester) async { + testWidgets('Material3 - Custom Content Text Style - Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog( - content: Text(contentText), - actions: [ ], - ); + const AlertDialog dialog = AlertDialog(content: Text(contentText),); + final ThemeData theme = ThemeData(useMaterial3: true, textTheme: const TextTheme(bodyMedium: contentTextStyle)); + + await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final RenderParagraph content = _getTextRenderObject(tester, contentText); + expect(content.text.style!.color, contentTextStyle.color); + }); + + testWidgets('Material2 - Custom Content Text Style - Theme', (WidgetTester tester) async { + const String contentText = 'Content'; + const TextStyle contentTextStyle = TextStyle(color: Colors.pink); + const AlertDialog dialog = AlertDialog(content: Text(contentText)); final ThemeData theme = ThemeData(useMaterial3: false, textTheme: const TextTheme(titleMedium: contentTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); From a65e739483e0ad1c9f4746322418a6655e30c1b5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 03:46:07 -0400 Subject: [PATCH 0151/1547] Roll Flutter Engine from fcecec871aae to 427ceaf089bd (3 revisions) (#130563) https://github.com/flutter/engine/compare/fcecec871aae...427ceaf089bd 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 2848267f631d to 8192de1efc1b (1 revision) (flutter/engine#43672) 2023-07-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 8f49edfb6989 to 8e4eac435b49 (1 revision) (flutter/engine#43671) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from ffed127e8974 to 2848267f631d (3 revisions) (flutter/engine#43670) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 05b7b3c5cfaea..98617ecda5b53 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fcecec871aae26167ee2c96383e0a50f9cf58872 +427ceaf089bd9f85bb140649e12cbf9a3634ff1b From b8fa9233862911f43766184c7910c8e3a2055a31 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 14 Jul 2023 07:15:45 -0700 Subject: [PATCH 0152/1547] Revert "Update `DialogTheme` tests for M2/M3" (#130578) Reverts flutter/flutter#130414 Skia gold failures https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20framework_tests_libraries/11972/overview --- .../test/material/dialog_theme_test.dart | 108 ++++-------------- 1 file changed, 20 insertions(+), 88 deletions(-) diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index 22c78e3a817e4..f215649d4826c 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -165,31 +165,7 @@ void main() { expect(bottomLeft.dy, 576.0); }); - testWidgets('Material3 - Dialog alignment takes priority over theme', (WidgetTester tester) async { - const AlertDialog dialog = AlertDialog( - title: Text('Title'), - actions: [ ], - alignment: Alignment.topRight, - ); - final ThemeData theme = ThemeData( - useMaterial3: true, - dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft), - ); - - await tester.pumpWidget( - _appWithDialog(tester, dialog, theme: theme), - ); - await tester.tap(find.text('X')); - await tester.pumpAndSettle(); - - final Offset bottomLeft = tester.getBottomLeft( - find.descendant(of: find.byType(Dialog), matching: find.byType(Material)), - ); - expect(bottomLeft.dx, 480.0); - expect(bottomLeft.dy, 124.0); - }); - - testWidgets('Material2 - Dialog alignment takes priority over theme', (WidgetTester tester) async { + testWidgets('Dialog alignment takes priority over theme', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], @@ -210,29 +186,7 @@ void main() { expect(bottomLeft.dy, 104.0); }); - testWidgets('Material3 - Custom dialog shape matches golden', (WidgetTester tester) async { - const RoundedRectangleBorder customBorder = - RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); - const AlertDialog dialog = AlertDialog( - title: Text('Title'), - actions: [ ], - ); - final ThemeData theme = ThemeData( - useMaterial3: true, - dialogTheme: const DialogTheme(shape: customBorder), - ); - - await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); - await tester.tap(find.text('X')); - await tester.pumpAndSettle(); - - await expectLater( - find.byKey(_painterKey), - matchesGoldenFile('m3_dialog_theme.dialog_with_custom_border.png'), - ); - }); - - testWidgets('Material2 - Custom dialog shape matches golden', (WidgetTester tester) async { + testWidgets('Custom dialog shape matches golden', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -247,7 +201,7 @@ void main() { await expectLater( find.byKey(_painterKey), - matchesGoldenFile('m2_dialog_theme.dialog_with_custom_border.png'), + matchesGoldenFile('dialog_theme.dialog_with_custom_border.png'), ); }); @@ -292,8 +246,9 @@ void main() { expect(text.text.style!.color, dialogThemeColor); }); - testWidgets('Material3 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); + testWidgets('Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + const Color iconThemeColor = Colors.yellow; + final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: [ ], @@ -305,12 +260,11 @@ void main() { // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); - expect(text.text.style!.color, theme.colorScheme.secondary); + expect(text.text.style!.color, iconThemeColor); }); - testWidgets('Material2 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { - const Color iconThemeColor = Colors.yellow; - final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); + testWidgets('Custom Icon Color - Theme - lowest preference for M3', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: [ ], @@ -322,7 +276,7 @@ void main() { // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); - expect(text.text.style!.color, iconThemeColor); + expect(text.text.style!.color, theme.colorScheme.secondary); }); testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { @@ -359,24 +313,13 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Material3 - Custom Title Text Style - Theme', (WidgetTester tester) async { - const String titleText = 'Title'; - const TextStyle titleTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog(title: Text(titleText)); - final ThemeData theme = ThemeData(useMaterial3: true, textTheme: const TextTheme(headlineSmall: titleTextStyle)); - - await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); - await tester.tap(find.text('X')); - await tester.pumpAndSettle(); - - final RenderParagraph title = _getTextRenderObject(tester, titleText); - expect(title.text.style!.color, titleTextStyle.color); - }); - - testWidgets('Material2 - Custom Title Text Style - Theme', (WidgetTester tester) async { + testWidgets('Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog(title: Text(titleText)); + const AlertDialog dialog = AlertDialog( + title: Text(titleText), + actions: [ ], + ); final ThemeData theme = ThemeData(useMaterial3: false, textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); @@ -469,24 +412,13 @@ void main() { expect(content.text.style, contentTextStyle); }); - testWidgets('Material3 - Custom Content Text Style - Theme', (WidgetTester tester) async { + testWidgets('Custom Content Text Style - Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog(content: Text(contentText),); - final ThemeData theme = ThemeData(useMaterial3: true, textTheme: const TextTheme(bodyMedium: contentTextStyle)); - - await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); - await tester.tap(find.text('X')); - await tester.pumpAndSettle(); - - final RenderParagraph content = _getTextRenderObject(tester, contentText); - expect(content.text.style!.color, contentTextStyle.color); - }); - - testWidgets('Material2 - Custom Content Text Style - Theme', (WidgetTester tester) async { - const String contentText = 'Content'; - const TextStyle contentTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog(content: Text(contentText)); + const AlertDialog dialog = AlertDialog( + content: Text(contentText), + actions: [ ], + ); final ThemeData theme = ThemeData(useMaterial3: false, textTheme: const TextTheme(titleMedium: contentTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); From ef312048e540ba600689cf946603fd79d4d9b104 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Fri, 14 Jul 2023 17:04:40 +0200 Subject: [PATCH 0153/1547] Fix finish translation for tab labels (#130333) ## Description This PR update the finnish translations for tab label. ## Related Issue fixes https://github.com/flutter/flutter/issues/110451 ## Tests Adds 2 tests. --- .../flutter_localizations/lib/src/l10n/cupertino_fi.arb | 2 +- .../lib/src/l10n/generated_cupertino_localizations.dart | 2 +- .../lib/src/l10n/generated_material_localizations.dart | 2 +- .../flutter_localizations/lib/src/l10n/material_fi.arb | 2 +- .../test/cupertino/translations_test.dart | 9 +++++++++ .../test/material/translations_test.dart | 9 +++++++++ 6 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb index dbae7c6bc2777..f69aaa54ce035 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb @@ -19,7 +19,7 @@ "copyButtonLabel": "Kopioi", "pasteButtonLabel": "Liitä", "selectAllButtonLabel": "Valitse kaikki", - "tabSemanticsLabel": "Välilehti $tabIndex/$tabCount", + "tabSemanticsLabel": "Välilehti $tabIndex kautta $tabCount", "modalBarrierDismissLabel": "Ohita", "searchTextFieldPlaceholderLabel": "Hae", "noSpellCheckReplacementsLabel": "No Replacements Found" diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index 90a899f0a3d57..bb53ac311049c 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -3983,7 +3983,7 @@ class CupertinoLocalizationFi extends GlobalCupertinoLocalizations { String get selectAllButtonLabel => 'Valitse kaikki'; @override - String get tabSemanticsLabelRaw => r'Välilehti $tabIndex/$tabCount'; + String get tabSemanticsLabelRaw => r'Välilehti $tabIndex kautta $tabCount'; @override String? get timerPickerHourLabelFew => null; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index 7d008703cf374..7d5d7e68a08e3 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -14206,7 +14206,7 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { String get signedInLabel => 'Kirjautunut sisään'; @override - String get tabLabelRaw => r'Välilehti $tabIndex/$tabCount'; + String get tabLabelRaw => r'Välilehti $tabIndex kautta $tabCount'; @override TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.HH_dot_mm; diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index 8db1a1af41adb..ce9d501370e9b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -17,7 +17,7 @@ "pageRowsInfoTitle": "$firstRow–$lastRow/$rowCount", "pageRowsInfoTitleApproximate": "$firstRow–$lastRow/~$rowCount", "rowsPerPageTitle": "Riviä/sivu:", - "tabLabel": "Välilehti $tabIndex/$tabCount", + "tabLabel": "Välilehti $tabIndex kautta $tabCount", "selectedRowCountTitleOne": "1 kohde valittu", "selectedRowCountTitleOther": "$selectedRowCount kohdetta valittu", "cancelButtonLabel": "Peru", diff --git a/packages/flutter_localizations/test/cupertino/translations_test.dart b/packages/flutter_localizations/test/cupertino/translations_test.dart index 78fcd0263a2d2..652c8c105b17b 100644 --- a/packages/flutter_localizations/test/cupertino/translations_test.dart +++ b/packages/flutter_localizations/test/cupertino/translations_test.dart @@ -194,4 +194,13 @@ void main() { expect(file.readAsStringSync(), encodedArbFile); } }); + + // Regression test for https://github.com/flutter/flutter/issues/110451. + testWidgets('Finnish translation for tab label', (WidgetTester tester) async { + const Locale locale = Locale('fi'); + expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue); + final CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale); + expect(localizations, isA()); + expect(localizations.tabSemanticsLabel(tabIndex: 1, tabCount: 2), 'Välilehti 1 kautta 2'); + }); } diff --git a/packages/flutter_localizations/test/material/translations_test.dart b/packages/flutter_localizations/test/material/translations_test.dart index c914362031298..cb0e38ad2406f 100644 --- a/packages/flutter_localizations/test/material/translations_test.dart +++ b/packages/flutter_localizations/test/material/translations_test.dart @@ -528,4 +528,13 @@ void main() { expect(file.readAsStringSync(), encodedArbFile); } }); + + // Regression test for https://github.com/flutter/flutter/issues/110451. + testWidgets('Finnish translation for tab label', (WidgetTester tester) async { + const Locale locale = Locale('fi'); + expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue); + final MaterialLocalizations localizations = await GlobalMaterialLocalizations.delegate.load(locale); + expect(localizations, isA()); + expect(localizations.tabLabel(tabIndex: 1, tabCount: 2), 'Välilehti 1 kautta 2'); + }); } From 5cbccc4d790a9135e5e06a3aceaa7ec356aa451c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 11:04:43 -0400 Subject: [PATCH 0154/1547] Roll Flutter Engine from 427ceaf089bd to 3a1b12a2fa09 (1 revision) (#130577) https://github.com/flutter/engine/compare/427ceaf089bd...3a1b12a2fa09 2023-07-14 kustermann@google.com Use utf8.encode() instead of longer const Utf8Encoder.convert() (flutter/engine#43675) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 98617ecda5b53..b668b2047b69d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -427ceaf089bd9f85bb140649e12cbf9a3634ff1b +3a1b12a2fa09c04e7053ff687970e3fd13829f1d From f5a5581fdbae6ac7a4e18436544dc6facad3c85d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 11:56:16 -0400 Subject: [PATCH 0155/1547] Roll Flutter Engine from 3a1b12a2fa09 to 6df061859ac7 (2 revisions) (#130583) https://github.com/flutter/engine/compare/3a1b12a2fa09...6df061859ac7 2023-07-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 8e4eac435b49 to 3701605e0abf (1 revision) (flutter/engine#43679) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 8192de1efc1b to 7990401d716a (1 revision) (flutter/engine#43678) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b668b2047b69d..9f86bfe2e36f5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3a1b12a2fa09c04e7053ff687970e3fd13829f1d +6df061859ac7b08a8dc664d04fbf0c5e3f5d38aa From b91aedb175798ce2da1ef0cf4f988ac54186b585 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Fri, 14 Jul 2023 09:13:57 -0700 Subject: [PATCH 0156/1547] Fix StateError during hot reload when no Dart isolates found (#130537) Fixes https://github.com/flutter/flutter/issues/116262 --- packages/flutter_tools/lib/src/run_hot.dart | 21 ++++--- .../test/general.shard/run_hot_test.dart | 62 +++++++++++++++++++ 2 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 packages/flutter_tools/test/general.shard/run_hot_test.dart diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 7d8c77ac02b26..57e4e0eac3ea9 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -91,7 +91,7 @@ class HotRunner extends ResidentRunner { this.multidexEnabled = false, super.devtoolsHandler, StopwatchFactory stopwatchFactory = const StopwatchFactory(), - ReloadSourcesHelper reloadSourcesHelper = _defaultReloadSourcesHelper, + ReloadSourcesHelper reloadSourcesHelper = defaultReloadSourcesHelper, ReassembleHelper reassembleHelper = _defaultReassembleHelper, }) : _stopwatchFactory = stopwatchFactory, _reloadSourcesHelper = reloadSourcesHelper, @@ -1174,7 +1174,8 @@ typedef ReloadSourcesHelper = Future Function( String? reason, ); -Future _defaultReloadSourcesHelper( +@visibleForTesting +Future defaultReloadSourcesHelper( HotRunner hotRunner, List flutterDevices, bool? pause, @@ -1186,7 +1187,7 @@ Future _defaultReloadSourcesHelper( ) async { final Stopwatch vmReloadTimer = Stopwatch()..start(); const String entryPath = 'main.dart.incremental.dill'; - final List> allReportsFutures = >[]; + final List> allReportsFutures = >[]; for (final FlutterDevice? device in flutterDevices) { final List> reportFutures = await _reloadDeviceSources( @@ -1194,10 +1195,13 @@ Future _defaultReloadSourcesHelper( entryPath, pause: pause, ); - allReportsFutures.add(Future.wait(reportFutures).then( + allReportsFutures.add(Future.wait(reportFutures).then( (List reports) async { // TODO(aam): Investigate why we are validating only first reload report, // which seems to be current behavior + if (reports.isEmpty) { + return null; + } final vm_service.ReloadReport firstReport = reports.first; // Don't print errors because they will be printed further down when // `validateReloadReport` is called again. @@ -1208,9 +1212,9 @@ Future _defaultReloadSourcesHelper( }, )); } - final List reports = await Future.wait(allReportsFutures); - final vm_service.ReloadReport reloadReport = reports.first.reports[0]; - if (!HotRunner.validateReloadReport(reloadReport)) { + final Iterable reports = (await Future.wait(allReportsFutures)).whereType(); + final vm_service.ReloadReport? reloadReport = reports.isEmpty ? null : reports.first.reports[0]; + if (reloadReport == null || !HotRunner.validateReloadReport(reloadReport)) { // Reload failed. HotEvent('reload-reject', targetPlatform: targetPlatform!, @@ -1223,6 +1227,9 @@ Future _defaultReloadSourcesHelper( // Reset devFS lastCompileTime to ensure the file will still be marked // as dirty on subsequent reloads. _resetDevFSCompileTime(flutterDevices); + if (reloadReport == null) { + return OperationResult(1, 'No Dart isolates found'); + } final ReloadReportContents contents = ReloadReportContents.fromReloadReport(reloadReport); return OperationResult(1, 'Reload rejected: ${contents.notices.join("\n")}'); } diff --git a/packages/flutter_tools/test/general.shard/run_hot_test.dart b/packages/flutter_tools/test/general.shard/run_hot_test.dart new file mode 100644 index 0000000000000..bcd367e76a711 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/run_hot_test.dart @@ -0,0 +1,62 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_tools/src/devfs.dart'; +import 'package:flutter_tools/src/resident_runner.dart'; +import 'package:flutter_tools/src/run_hot.dart'; +import 'package:flutter_tools/src/vmservice.dart'; +import 'package:test/fake.dart'; +import 'package:vm_service/vm_service.dart' as vm_service; + +import '../src/context.dart'; + +void main() { + testUsingContext('defaultReloadSourcesHelper() handles empty DeviceReloadReports)', () { + defaultReloadSourcesHelper( + _FakeHotRunner(), + [_FakeFlutterDevice()], + false, + const {}, + 'android', + 'flutter-sdk', + false, + 'test-reason', + ); + }); +} + +class _FakeHotRunner extends Fake implements HotRunner {} + +class _FakeDevFS extends Fake implements DevFS { + @override + final Uri? baseUri = Uri(); + + @override + void resetLastCompiled() {} +} + +class _FakeFlutterDevice extends Fake implements FlutterDevice { + @override + final DevFS? devFS = _FakeDevFS(); + + @override + final FlutterVmService? vmService = _FakeFlutterVmService(); +} + +class _FakeFlutterVmService extends Fake implements FlutterVmService { + @override + final vm_service.VmService service = _FakeVmService(); +} + +class _FakeVmService extends Fake implements vm_service.VmService { + @override + Future<_FakeVm> getVM() async => _FakeVm(); +} + +class _FakeVm extends Fake implements vm_service.VM { + final List _isolates = []; + + @override + List? get isolates => _isolates; +} From 79119dfc66c667cf67c0b567f92dc948f17eb362 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 12:42:08 -0400 Subject: [PATCH 0157/1547] Roll Flutter Engine from 6df061859ac7 to 805162c18b32 (1 revision) (#130589) https://github.com/flutter/engine/compare/6df061859ac7...805162c18b32 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 7990401d716a to b4b9c76206f3 (1 revision) (flutter/engine#43681) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9f86bfe2e36f5..5ebed78ec9ca5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6df061859ac7b08a8dc664d04fbf0c5e3f5d38aa +805162c18b32c8352c71d9e832a812fc40058020 From a903f1defb15d7f53d3208910f2468270eabc9b7 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 14 Jul 2023 11:51:50 -0500 Subject: [PATCH 0158/1547] Add verbose engine logs for iOS start up tests (#130511) Added to be able to view logs from https://github.com/flutter/engine/pull/43616. Added to debug https://github.com/flutter/flutter/issues/129836 --- dev/devicelab/lib/tasks/perf_tests.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 20c8389cf2309..0f018ad7accba 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -786,6 +786,9 @@ class StartupTest { '--verbose', '--profile', '--trace-startup', + // TODO(vashworth): Remove once done debugging https://github.com/flutter/flutter/issues/129836 + if (device is IosDevice) + '--verbose-system-logs', '--target=$target', '-d', device.deviceId, From 93919232762912479c2d63d32a548433e3a0d6ee Mon Sep 17 00:00:00 2001 From: gmackall <34871572+gmackall@users.noreply.github.com> Date: Fri, 14 Jul 2023 09:57:06 -0700 Subject: [PATCH 0159/1547] Add an android migrator to upgrade minSdkVersions 16,17,18 to flutter.minSdkVersion (#129729) This migrator will upgrade the minSdkVersion used in the [module-level build.gradle](https://developer.android.com/build#module-level) file to flutter.minSdkVersion. The PR also makes a small refactor to `AndroidProject` to add a getter for the module level build.gradle file, and uses that getter in places where we were getting that file (previously it was being gotten directly via `hostAppGradleRoot.childDirectory('app').childFile('build.gradle')`. Part of the work for deprecating support for the Jelly Bean android apis. --- .../flutter_tools/lib/src/android/gradle.dart | 5 +- .../lib/src/android/gradle_utils.dart | 13 +- .../migrations/min_sdk_version_migration.dart | 47 +++++ packages/flutter_tools/lib/src/project.dart | 56 ++++-- .../android_project_migration_test.dart | 190 +++++++++++++++++- 5 files changed, 282 insertions(+), 29 deletions(-) create mode 100644 packages/flutter_tools/lib/src/android/migrations/min_sdk_version_migration.dart diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 6d1e3e7345b12..d90431dd49486 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -35,6 +35,7 @@ import 'gradle_errors.dart'; import 'gradle_utils.dart'; import 'java.dart'; import 'migrations/android_studio_java_gradle_conflict_migration.dart'; +import 'migrations/min_sdk_version_migration.dart'; import 'migrations/top_level_gradle_build_file_migration.dart'; import 'multidex.dart'; @@ -330,8 +331,8 @@ class AndroidGradleBuilder implements AndroidBuilder { AndroidStudioJavaGradleConflictMigration(_logger, project: project.android, androidStudio: _androidStudio, - java: globals.java) - , + java: globals.java), + MinSdkVersionMigration(project.android, _logger), ]; final ProjectMigration migration = ProjectMigration(migrators); diff --git a/packages/flutter_tools/lib/src/android/gradle_utils.dart b/packages/flutter_tools/lib/src/android/gradle_utils.dart index 12d83a7ded7c2..90b80a385749b 100644 --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart @@ -57,23 +57,28 @@ const String maxKnownAgpVersion = '8.1'; // Parentheticals are use to group which helps with version extraction. // "...build:gradle:(...)" where group(1) should be the version string. final RegExp _androidGradlePluginRegExp = - RegExp(r'com\.android\.tools\.build:gradle:(\d+\.\d+\.\d+)'); + RegExp(r'com\.android\.tools\.build:gradle:(\d+\.\d+\.\d+)'); // Expected content format (with lines above and below). // Version can have 2 or 3 numbers. // 'distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip' // '^\s*' protects against commented out lines. final RegExp distributionUrlRegex = - RegExp(r'^\s*distributionUrl\s*=\s*.*\.zip', multiLine: true); + RegExp(r'^\s*distributionUrl\s*=\s*.*\.zip', multiLine: true); // Modified version of the gradle distribution url match designed to only match // gradle.org urls so that we can guarantee any modifications to the url // still points to a hosted zip. final RegExp gradleOrgVersionMatch = -RegExp( + RegExp( r'^\s*distributionUrl\s*=\s*https\\://services\.gradle\.org/distributions/gradle-((?:\d|\.)+)-(.*)\.zip', multiLine: true -); + ); + +// This matches uncommented minSdkVersion lines in the module-level build.gradle +// file which have minSdkVersion 16,17, or 18 (the Jelly Bean api levels). +final RegExp jellyBeanMinSdkVersionMatch = + RegExp(r'(?<=^\s*)minSdkVersion 1[678](?=\s*(?://|$))', multiLine: true); // From https://docs.gradle.org/current/userguide/command_line_interface.html#command_line_interface const String gradleVersionFlag = r'--version'; diff --git a/packages/flutter_tools/lib/src/android/migrations/min_sdk_version_migration.dart b/packages/flutter_tools/lib/src/android/migrations/min_sdk_version_migration.dart new file mode 100644 index 0000000000000..d7d4cd1fc029e --- /dev/null +++ b/packages/flutter_tools/lib/src/android/migrations/min_sdk_version_migration.dart @@ -0,0 +1,47 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; + +import '../../base/file_system.dart'; +import '../../base/project_migrator.dart'; +import '../../project.dart'; +import '../gradle_utils.dart'; + +/// Replacement value for https://developer.android.com/reference/tools/gradle-api/8.0/com/android/build/api/dsl/BaseFlavor#minSdkVersion(kotlin.Int) +/// that instead of using a value defaults to the version defined by the +/// flutter sdk as the minimum supported by flutter. +@visibleForTesting +const String replacementMinSdkText = 'minSdkVersion flutter.minSdkVersion'; + +@visibleForTesting +const String appGradleNotFoundWarning = 'Module level build.gradle file not found, skipping minSdkVersion migration.'; + +class MinSdkVersionMigration extends ProjectMigrator { + MinSdkVersionMigration( + AndroidProject project, + super.logger, + ) : _project = project; + + final AndroidProject _project; + + @override + void migrate() { + // Skip applying migration in modules as the FlutterExtension is not applied. + if (_project.isModule) { + return; + } + try { + processFileLines(_project.appGradleFile); + } on FileSystemException { + // Skip if we cannot find the app level build.gradle file. + logger.printTrace(appGradleNotFoundWarning); + } + } + + @override + String migrateFileContents(String fileContents) { + return fileContents.replaceAll(jellyBeanMinSdkVersionMatch, replacementMinSdkText); + } +} diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 38a63ff55df1b..1aee9c281b29a 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -509,30 +509,45 @@ class AndroidProject extends FlutterProjectPlatform { if (plugin.existsSync()) { return false; } - final File appGradle = hostAppGradleRoot.childFile( - fileSystem.path.join('app', 'build.gradle')); - if (!appGradle.existsSync()) { - return false; - } - for (final String line in appGradle.readAsLinesSync()) { - final bool fileBasedApply = line.contains(RegExp(r'apply from: .*/flutter.gradle')); - final bool declarativeApply = line.contains('dev.flutter.flutter-gradle-plugin'); - final bool managed = line.contains("def flutterPluginVersion = 'managed'"); - if (fileBasedApply || declarativeApply || managed) { - return true; + try { + for (final String line in appGradleFile.readAsLinesSync()) { + // This syntax corresponds to applying the Flutter Gradle Plugin with a + // script. + // See https://docs.gradle.org/current/userguide/plugins.html#sec:script_plugins. + final bool fileBasedApply = line.contains(RegExp(r'apply from: .*/flutter.gradle')); + + // This syntax corresponds to applying the Flutter Gradle Plugin using + // the declarative "plugins {}" block after including it in the + // pluginManagement block of the settings.gradle file. + // See https://docs.gradle.org/current/userguide/composite_builds.html#included_plugin_builds, + // as well as the settings.gradle and build.gradle templates. + final bool declarativeApply = line.contains('dev.flutter.flutter-gradle-plugin'); + + // This case allows for flutter run/build to work for modules. It does + // not guarantee the Flutter Gradle Plugin is applied. + final bool managed = line.contains("def flutterPluginVersion = 'managed'"); + if (fileBasedApply || declarativeApply || managed) { + return true; + } } + } on FileSystemException { + return false; } return false; } /// True, if the app project is using Kotlin. bool get isKotlin { - final File gradleFile = hostAppGradleRoot.childDirectory('app').childFile('build.gradle'); - final bool imperativeMatch = firstMatchInFile(gradleFile, _imperativeKotlinPluginPattern) != null; - final bool declarativeMatch = firstMatchInFile(gradleFile, _declarativeKotlinPluginPattern) != null; + final bool imperativeMatch = firstMatchInFile(appGradleFile, _imperativeKotlinPluginPattern) != null; + final bool declarativeMatch = firstMatchInFile(appGradleFile, _declarativeKotlinPluginPattern) != null; return imperativeMatch || declarativeMatch; } + /// Gets the module-level build.gradle file. + /// See https://developer.android.com/build#module-level. + File get appGradleFile => hostAppGradleRoot.childDirectory('app') + .childFile('build.gradle'); + File get appManifestFile { if (isUsingGradle) { return hostAppGradleRoot @@ -627,21 +642,18 @@ $javaGradleCompatUrl } String? get applicationId { - final File gradleFile = hostAppGradleRoot.childDirectory('app').childFile('build.gradle'); - return firstMatchInFile(gradleFile, _applicationIdPattern)?.group(1); + return firstMatchInFile(appGradleFile, _applicationIdPattern)?.group(1); } /// Get the namespace for newer Android projects, /// which replaces the `package` attribute in the Manifest.xml. String? get namespace { - final File gradleFile = hostAppGradleRoot.childDirectory('app').childFile('build.gradle'); - - if (!gradleFile.existsSync()) { + try { + // firstMatchInFile() reads per line but `_androidNamespacePattern` matches a multiline pattern. + return _androidNamespacePattern.firstMatch(appGradleFile.readAsStringSync())?.group(1); + } on FileSystemException { return null; } - - // firstMatchInFile() reads per line but `_androidNamespacePattern` matches a multiline pattern. - return _androidNamespacePattern.firstMatch(gradleFile.readAsStringSync())?.group(1); } String? get group { diff --git a/packages/flutter_tools/test/general.shard/android/android_project_migration_test.dart b/packages/flutter_tools/test/general.shard/android/android_project_migration_test.dart index 8722774497cce..5096ae0ec805b 100644 --- a/packages/flutter_tools/test/general.shard/android/android_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_project_migration_test.dart @@ -7,6 +7,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/android/gradle_utils.dart'; import 'package:flutter_tools/src/android/migrations/android_studio_java_gradle_conflict_migration.dart'; +import 'package:flutter_tools/src/android/migrations/min_sdk_version_migration.dart'; import 'package:flutter_tools/src/android/migrations/top_level_gradle_build_file_migration.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/version.dart'; @@ -41,6 +42,79 @@ zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists '''; +String sampleModuleGradleBuildFile(String minSdkVersionString) { + return r''' +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.asset_sample" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.asset_sample" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + ''' + minSdkVersionString + r''' + + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies {} +'''; +} + final Version androidStudioDolphin = Version(2021, 3, 1); const Version _javaVersion17 = Version.withText(17, 0, 2, 'openjdk 17.0.2'); @@ -257,14 +331,128 @@ tasks.register("clean", Delete) { expect(bufferLogger.traceText, contains(optOutFlagEnabled)); }); }); + + group('migrate min sdk versions less than 19 to flutter.minSdkVersion ' + 'when in a FlutterProject that is an app', () + { + late MemoryFileSystem memoryFileSystem; + late BufferLogger bufferLogger; + late FakeAndroidProject project; + late MinSdkVersionMigration migration; + + setUp(() { + memoryFileSystem = MemoryFileSystem.test(); + memoryFileSystem.currentDirectory.childDirectory('android').createSync(); + bufferLogger = BufferLogger.test(); + project = FakeAndroidProject( + root: memoryFileSystem.currentDirectory.childDirectory('android'), + ); + project.appGradleFile.parent.createSync(recursive: true); + migration = MinSdkVersionMigration( + project, + bufferLogger + ); + }); + + testWithoutContext('do nothing when files missing', () { + migration.migrate(); + expect(bufferLogger.traceText, contains(appGradleNotFoundWarning)); + }); + + testWithoutContext('replace when api 16', () { + const String minSdkVersion16 = 'minSdkVersion 16'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(minSdkVersion16)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(replacementMinSdkText)); + }); + + testWithoutContext('replace when api 17', () { + const String minSdkVersion17 = 'minSdkVersion 17'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(minSdkVersion17)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(replacementMinSdkText)); + }); + + testWithoutContext('replace when api 18', () { + const String minSdkVersion18 = 'minSdkVersion 18'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(minSdkVersion18)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(replacementMinSdkText)); + }); + + testWithoutContext('do nothing when >=api 19', () { + const String minSdkVersion19 = 'minSdkVersion 19'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(minSdkVersion19)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(minSdkVersion19)); + }); + + testWithoutContext('do nothing when already using ' + 'flutter.minSdkVersion', () { + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(replacementMinSdkText)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(replacementMinSdkText)); + }); + + testWithoutContext('avoid rewriting comments', () { + const String code = '// minSdkVersion 16 // old default\n' + ' minSdkVersion 23 // new version'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(code)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(code)); + }); + + testWithoutContext('do nothing when project is a module', () { + project = FakeAndroidProject( + root: memoryFileSystem.currentDirectory.childDirectory('android'), + module: true, + ); + migration = MinSdkVersionMigration( + project, + bufferLogger + ); + const String minSdkVersion16 = 'minSdkVersion 16'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(minSdkVersion16)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(minSdkVersion16)); + }); + + testWithoutContext('do nothing when minSdkVersion is set ' + 'to a constant', () { + const String minSdkVersionConstant = 'minSdkVersion kMinSdkversion'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(minSdkVersionConstant)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(minSdkVersionConstant)); + }); + + testWithoutContext('do nothing when minSdkVersion is set ' + 'using = syntax', () { + const String equalsSyntaxMinSdkVersion16 = 'minSdkVersion = 16'; + project.appGradleFile.writeAsStringSync(sampleModuleGradleBuildFile(equalsSyntaxMinSdkVersion16)); + migration.migrate(); + expect(project.appGradleFile.readAsStringSync(), sampleModuleGradleBuildFile(equalsSyntaxMinSdkVersion16)); + }); + }); }); } class FakeAndroidProject extends Fake implements AndroidProject { - FakeAndroidProject({required Directory root}) : hostAppGradleRoot = root; + FakeAndroidProject({required Directory root, this.module, this.plugin}) : hostAppGradleRoot = root; @override Directory hostAppGradleRoot; + + final bool? module; + final bool? plugin; + + @override + bool get isPlugin => plugin ?? false; + + @override + bool get isModule => module ?? false; + + @override + File get appGradleFile => hostAppGradleRoot.childDirectory('app').childFile('build.gradle'); } class FakeAndroidStudio extends Fake implements AndroidStudio { From d5e7f407e120b369027ea4c1b068d5ac79252cac Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 14 Jul 2023 10:14:04 -0700 Subject: [PATCH 0160/1547] Test cover some leak-free code. (#130543) --- .../test/material/expand_icon_test.dart | 20 ++--- .../floating_action_button_location_test.dart | 76 ++++++++--------- .../test/material/ink_sparkle_test.dart | 13 +-- .../flutter/test/material/material_test.dart | 81 ++++++++++--------- .../test/material/navigation_bar_test.dart | 43 +++++----- .../persistent_bottom_sheet_test.dart | 26 +++--- .../flutter/test/material/radio_test.dart | 53 ++++++------ .../test/material/refresh_indicator_test.dart | 58 ++++++------- .../test/material/segmented_button_test.dart | 13 +-- 9 files changed, 198 insertions(+), 185 deletions(-) diff --git a/packages/flutter/test/material/expand_icon_test.dart b/packages/flutter/test/material/expand_icon_test.dart index 4d795da9adb66..5908befe00f68 100644 --- a/packages/flutter/test/material/expand_icon_test.dart +++ b/packages/flutter/test/material/expand_icon_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + Widget wrap({ required Widget child, ThemeData? theme }) { return MaterialApp( theme: theme, @@ -15,7 +17,7 @@ Widget wrap({ required Widget child, ThemeData? theme }) { } void main() { - testWidgets('ExpandIcon test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon test', (WidgetTester tester) async { bool expanded = false; IconTheme iconTheme; @@ -73,7 +75,7 @@ void main() { expect(iconTheme.data.color, equals(Colors.white60)); }); - testWidgets('ExpandIcon disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon disabled', (WidgetTester tester) async { IconTheme iconTheme; // Light mode test await tester.pumpWidget(wrap( @@ -96,7 +98,7 @@ void main() { expect(iconTheme.data.color, equals(Colors.white38)); }); - testWidgets('ExpandIcon test isExpanded does not trigger callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon test isExpanded does not trigger callback', (WidgetTester tester) async { bool expanded = false; await tester.pumpWidget(wrap( @@ -119,7 +121,7 @@ void main() { expect(expanded, isFalse); }); - testWidgets('ExpandIcon is rotated initially if isExpanded is true on first build', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon is rotated initially if isExpanded is true on first build', (WidgetTester tester) async { bool expanded = true; await tester.pumpWidget(wrap( @@ -134,7 +136,7 @@ void main() { expect(rotation.turns.value, 0.5); }); - testWidgets('ExpandIcon default size is 24', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon default size is 24', (WidgetTester tester) async { final ExpandIcon expandIcon = ExpandIcon( onPressed: (bool isExpanded) {}, ); @@ -147,7 +149,7 @@ void main() { expect(icon.size, 24); }); - testWidgets('ExpandIcon has the correct given size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon has the correct given size', (WidgetTester tester) async { ExpandIcon expandIcon = ExpandIcon( size: 36, onPressed: (bool isExpanded) {}, @@ -173,7 +175,7 @@ void main() { expect(icon.size, 48); }); - testWidgets('ExpandIcon has correct semantic hints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon has correct semantic hints', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations(); await tester.pumpWidget(wrap( @@ -210,7 +212,7 @@ void main() { handle.dispose(); }); - testWidgets('ExpandIcon uses custom icon color and expanded icon color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon uses custom icon color and expanded icon color', (WidgetTester tester) async { bool expanded = false; IconTheme iconTheme; @@ -271,7 +273,7 @@ void main() { expect(iconTheme.data.color, equals(Colors.indigo)); }); - testWidgets('ExpandIcon uses custom disabled icon color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpandIcon uses custom disabled icon color', (WidgetTester tester) async { IconTheme iconTheme; await tester.pumpWidget(wrap( diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index faefd63c90cfa..5b937e0757503 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -8,9 +8,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { group('Basic floating action button locations', () { - testWidgets('still animates motion when the floating action button is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('still animates motion when the floating action button is null', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(fab: null)); expect(find.byType(FloatingActionButton), findsNothing); @@ -27,7 +29,7 @@ void main() { expect(tester.binding.transientCallbackCount, greaterThan(0)); }); - testWidgets('moves fab from center to end and back', (WidgetTester tester) async { + testWidgetsWithLeakTracking('moves fab from center to end and back', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.endFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(756.0, 356.0)); @@ -52,7 +54,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('moves to and from custom-defined positions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('moves to and from custom-defined positions', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: const _StartTopFloatingActionButtonLocation())); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(44.0, 56.0)); @@ -173,7 +175,7 @@ void main() { previousRotations = null; }); - testWidgets('moving the fab to centerFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('moving the fab to centerFloat', (WidgetTester tester) async { // Create a scaffold with the fab at endFloat await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.endFloat, listener: geometryListener)); setupListener(tester); @@ -183,7 +185,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting motion towards the StartTop location.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting motion towards the StartTop location.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -196,7 +198,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting entrance to remove the fab.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting entrance to remove the fab.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(fab: null, location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -215,7 +217,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting entrance of a new fab.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting entrance of a new fab.', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( fab: null, @@ -241,7 +243,7 @@ void main() { }); }); - testWidgets('Docked floating action button locations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Docked floating action button locations', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( location: FloatingActionButtonLocation.endDocked, @@ -276,7 +278,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(756.0, 500.0)); }); - testWidgets('Docked floating action button locations: no BAB, small BAB', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Docked floating action button locations: no BAB, small BAB', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( location: FloatingActionButtonLocation.endDocked, @@ -295,7 +297,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(756.0, 572.0)); }); - testWidgets('Contained floating action button locations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Contained floating action button locations', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( location: FloatingActionButtonLocation.endContained, @@ -310,7 +312,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(756.0, 550.0)); }); - testWidgets('Mini-start-top floating action button location', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mini-start-top floating action button location', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -331,7 +333,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)).dy, kToolbarHeight); }); - testWidgets('Start-top floating action button location LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Start-top floating action button location LTR', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -344,7 +346,7 @@ void main() { expect(tester.getRect(find.byType(FloatingActionButton)), rectMoreOrLessEquals(const Rect.fromLTWH(16.0, 28.0, 56.0, 56.0))); }); - testWidgets('End-top floating action button location RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('End-top floating action button location RTL', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -360,7 +362,7 @@ void main() { expect(tester.getRect(find.byType(FloatingActionButton)), rectMoreOrLessEquals(const Rect.fromLTWH(16.0, 28.0, 56.0, 56.0))); }); - testWidgets('Start-top floating action button location RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Start-top floating action button location RTL', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -376,7 +378,7 @@ void main() { expect(tester.getRect(find.byType(FloatingActionButton)), rectMoreOrLessEquals(const Rect.fromLTWH(800.0 - 56.0 - 16.0, 28.0, 56.0, 56.0))); }); - testWidgets('End-top floating action button location LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('End-top floating action button location LTR', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -390,19 +392,19 @@ void main() { }); group('New Floating Action Button Locations', () { - testWidgets('startTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('startTop', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.startTop)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _topOffsetY)); }); - testWidgets('centerTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('centerTop', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.centerTop)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _topOffsetY)); }); - testWidgets('endTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endTop', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endTop)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _topOffsetY)); @@ -438,25 +440,25 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _dockedOffsetY)); }); - testWidgets('endDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _dockedOffsetY)); }); - testWidgets('endContained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endContained', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endContained)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _containedOffsetY)); }); - testWidgets('miniStartTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartTop', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniStartTop)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniLeftOffsetX, _topOffsetY)); }); - testWidgets('miniEndTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniEndTop', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniEndTop)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniRightOffsetX, _topOffsetY)); @@ -494,7 +496,7 @@ void main() { // Test a few RTL cases. - testWidgets('endTop, RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endTop, RTL', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endTop, textDirection: TextDirection.rtl)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _topOffsetY)); @@ -508,25 +510,25 @@ void main() { }); group('Custom Floating Action Button Locations', () { - testWidgets('Almost end float', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Almost end float', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(_AlmostEndFloatFabLocation())); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX - 50, _floatOffsetY)); }); - testWidgets('Almost end float, RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Almost end float, RTL', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(_AlmostEndFloatFabLocation(), textDirection: TextDirection.rtl)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX + 50, _floatOffsetY)); }); - testWidgets('Quarter end top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Quarter end top', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(_QuarterEndTopFabLocation())); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX * 0.75 + _leftOffsetX * 0.25, _topOffsetY)); }); - testWidgets('Quarter end top, RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Quarter end top, RTL', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(_QuarterEndTopFabLocation(), textDirection: TextDirection.rtl)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX * 0.75 + _rightOffsetX * 0.25, _topOffsetY)); @@ -534,7 +536,7 @@ void main() { }); group('Moves involving new locations', () { - testWidgets('Moves between new locations and new locations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moves between new locations and new locations', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.centerTop)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _topOffsetY)); @@ -556,7 +558,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _dockedOffsetY)); }); - testWidgets('Moves between new locations and old locations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moves between new locations and old locations', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _dockedOffsetY)); @@ -586,7 +588,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _topOffsetY)); }); - testWidgets('Moves between new locations and old locations with custom animator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moves between new locations and old locations with custom animator', (WidgetTester tester) async { final FloatingActionButtonAnimator animator = _LinearMovementFabAnimator(); const Offset begin = Offset(_centerOffsetX, _topOffsetY); const Offset end = Offset(_rightOffsetX - 50, _floatOffsetY); @@ -628,7 +630,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('Animator can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animator can be updated', (WidgetTester tester) async { FloatingActionButtonAnimator fabAnimator = FloatingActionButtonAnimator.scaling; FloatingActionButtonLocation fabLocation = FloatingActionButtonLocation.startFloat; @@ -1511,7 +1513,7 @@ void main() { ); } - testWidgets('startTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('startTop', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(16.0, 50.0, 72.0, 106.0); // Positioned relative to AppBar const Rect appBarRect = Rect.fromLTRB(16.0, 28.0, 72.0, 84.0); @@ -1523,7 +1525,7 @@ void main() { ); }); - testWidgets('miniStartTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartTop', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(12.0, 50.0, 60.0, 98.0); // Positioned relative to AppBar const Rect appBarRect = Rect.fromLTRB(12.0, 32.0, 60.0, 80.0); @@ -1536,7 +1538,7 @@ void main() { ); }); - testWidgets('centerTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('centerTop', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(372.0, 50.0, 428.0, 106.0); // Positioned relative to AppBar const Rect appBarRect = Rect.fromLTRB(372.0, 28.0, 428.0, 84.0); @@ -1548,7 +1550,7 @@ void main() { ); }); - testWidgets('miniCenterTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniCenterTop', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(376.0, 50.0, 424.0, 98.0); // Positioned relative to AppBar const Rect appBarRect = Rect.fromLTRB(376.0, 32.0, 424.0, 80.0); @@ -1561,7 +1563,7 @@ void main() { ); }); - testWidgets('endTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endTop', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(728.0, 50.0, 784.0, 106.0); // Positioned relative to AppBar const Rect appBarRect = Rect.fromLTRB(728.0, 28.0, 784.0, 84.0); @@ -1573,7 +1575,7 @@ void main() { ); }); - testWidgets('miniEndTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniEndTop', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(740.0, 50.0, 788.0, 98.0); // Positioned relative to AppBar const Rect appBarRect = Rect.fromLTRB(740.0, 32.0, 788.0, 80.0); diff --git a/packages/flutter/test/material/ink_sparkle_test.dart b/packages/flutter/test/material/ink_sparkle_test.dart index 6fea3242e3d3d..b0a44de48949f 100644 --- a/packages/flutter/test/material/ink_sparkle_test.dart +++ b/packages/flutter/test/material/ink_sparkle_test.dart @@ -11,10 +11,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/src/foundation/constants.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgets('InkSparkle in a Button compiles and does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle in a Button compiles and does not crash', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Center( @@ -34,7 +35,7 @@ void main() { skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgets('InkSparkle default splashFactory paints with drawRect when bounded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle default splashFactory paints with drawRect when bounded', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Center( @@ -65,7 +66,7 @@ void main() { skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgets('InkSparkle default splashFactory paints with drawPaint when unbounded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle default splashFactory paints with drawPaint when unbounded', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Center( @@ -92,19 +93,19 @@ void main() { // Goldens // ///////////// - testWidgets('InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'top_left', 0.2); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgets('InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'center', 0.5); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgets('InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'bottom_right', 0.8); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index f08733a29e578..2832acb09e8cd 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/test_border.dart' show TestBorder; @@ -72,7 +73,7 @@ class ElevationColor { void main() { // Regression test for https://github.com/flutter/flutter/issues/81504 - testWidgets('MaterialApp.home nullable and update test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.home nullable and update test', (WidgetTester tester) async { // _WidgetsAppState._usesNavigator == true await tester.pumpWidget(const MaterialApp(home: SizedBox.shrink())); @@ -85,7 +86,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('default Material debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default Material debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const Material().debugFillProperties(builder); @@ -97,7 +98,7 @@ void main() { expect(description, ['type: canvas']); }); - testWidgets('Material implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const Material( color: Color(0xFFFFFFFF), @@ -123,7 +124,7 @@ void main() { ]); }); - testWidgets('LayoutChangedNotification test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutChangedNotification test', (WidgetTester tester) async { await tester.pumpWidget( const Material( child: NotifyMaterial(), @@ -131,7 +132,7 @@ void main() { ); }); - testWidgets('ListView scroll does not repaint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView scroll does not repaint', (WidgetTester tester) async { final List log = []; await tester.pumpWidget( @@ -190,7 +191,7 @@ void main() { expect(log, isEmpty); }); - testWidgets('Shadow color defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shadow color defaults', (WidgetTester tester) async { Widget buildWithShadow(Color? shadowColor) { return Center( child: SizedBox( @@ -242,7 +243,7 @@ void main() { expect(getModel(tester).shadowColor, Colors.transparent); }); - testWidgets('Shadows animate smoothly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shadows animate smoothly', (WidgetTester tester) async { // This code verifies that the PhysicalModel's elevation animates over // a kThemeChangeDuration time interval. @@ -267,7 +268,7 @@ void main() { expect(modelE.elevation, equals(9.0)); }); - testWidgets('Shadow colors animate smoothly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shadow colors animate smoothly', (WidgetTester tester) async { // This code verifies that the PhysicalModel's shadowColor animates over // a kThemeChangeDuration time interval. @@ -292,7 +293,7 @@ void main() { expect(modelE.shadowColor, equals(const Color(0xFFFF0000))); }); - testWidgets('Transparent material widget does not absorb hit test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Transparent material widget does not absorb hit test', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/58665. bool pressed = false; await tester.pumpWidget( @@ -323,7 +324,7 @@ void main() { }); group('Surface Tint Overlay', () { - testWidgets('applyElevationOverlayColor does not effect anything with useMaterial3 set to true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applyElevationOverlayColor does not effect anything with useMaterial3 set to true', (WidgetTester tester) async { const Color surfaceColor = Color(0xFF121212); await tester.pumpWidget(Theme( data: ThemeData( @@ -337,7 +338,7 @@ void main() { expect(model.color, equals(surfaceColor)); }); - testWidgets('surfaceTintColor is used to as an overlay to indicate elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('surfaceTintColor is used to as an overlay to indicate elevation', (WidgetTester tester) async { const Color baseColor = Color(0xFF121212); const Color surfaceTintColor = Color(0xff44CCFF); @@ -400,7 +401,7 @@ void main() { group('Elevation Overlay M2', () { // These tests only apply to the Material 2 overlay mechanism. This group // can be removed after migration to Material 3 is complete. - testWidgets('applyElevationOverlayColor set to false does not change surface color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applyElevationOverlayColor set to false does not change surface color', (WidgetTester tester) async { const Color surfaceColor = Color(0xFF121212); await tester.pumpWidget(Theme( data: ThemeData( @@ -414,7 +415,7 @@ void main() { expect(model.color, equals(surfaceColor)); }); - testWidgets('applyElevationOverlayColor set to true applies a semi-transparent onSurface color to the surface color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applyElevationOverlayColor set to true applies a semi-transparent onSurface color to the surface color', (WidgetTester tester) async { const Color surfaceColor = Color(0xFF121212); const Color onSurfaceColor = Colors.greenAccent; @@ -456,7 +457,7 @@ void main() { } }); - testWidgets('overlay will not apply to materials using a non-surface color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overlay will not apply to materials using a non-surface color', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData( @@ -475,7 +476,7 @@ void main() { expect(model.color, equals(Colors.cyan)); }); - testWidgets('overlay will not apply to materials using a light theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overlay will not apply to materials using a light theme', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData( @@ -494,7 +495,7 @@ void main() { expect(model.color, equals(Colors.cyan)); }); - testWidgets('overlay will apply to materials with a non-opaque surface color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overlay will apply to materials with a non-opaque surface color', (WidgetTester tester) async { const Color surfaceColor = Color(0xFF121212); const Color surfaceColorWithOverlay = Color(0xC6353535); @@ -517,7 +518,7 @@ void main() { expect(model.color, isNot(equals(surfaceColor))); }); - testWidgets('Expected overlay color can be computed using colorWithOverlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Expected overlay color can be computed using colorWithOverlay', (WidgetTester tester) async { const Color surfaceColor = Color(0xFF123456); const Color onSurfaceColor = Color(0xFF654321); const double elevation = 8.0; @@ -550,7 +551,7 @@ void main() { }); // Elevation Overlay M2 group group('Transparency clipping', () { - testWidgets('No clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No clip by default', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -564,7 +565,7 @@ void main() { expect(renderClip.clipBehavior, equals(Clip.none)); }); - testWidgets('clips to bounding rect by default given Clip.antiAlias', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clips to bounding rect by default given Clip.antiAlias', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -578,7 +579,7 @@ void main() { expect(find.byKey(materialKey), clipsWithBoundingRect); }); - testWidgets('clips to rounded rect when borderRadius provided given Clip.antiAlias', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clips to rounded rect when borderRadius provided given Clip.antiAlias', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -598,7 +599,7 @@ void main() { ); }); - testWidgets('clips to shape when provided given Clip.antiAlias', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clips to shape when provided given Clip.antiAlias', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -618,7 +619,7 @@ void main() { ); }); - testWidgets('supports directional clips', (WidgetTester tester) async { + testWidgetsWithLeakTracking('supports directional clips', (WidgetTester tester) async { final List logs = []; final ShapeBorder shape = TestBorder((String message) { logs.add(message); }); Widget buildMaterial() { @@ -683,7 +684,7 @@ void main() { }); group('PhysicalModels', () { - testWidgets('canvas', (WidgetTester tester) async { + testWidgetsWithLeakTracking('canvas', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -699,7 +700,7 @@ void main() { )); }); - testWidgets('canvas with borderRadius and elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('canvas with borderRadius and elevation', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -717,7 +718,7 @@ void main() { )); }); - testWidgets('canvas with shape and elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('canvas with shape and elevation', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -734,7 +735,7 @@ void main() { )); }); - testWidgets('card', (WidgetTester tester) async { + testWidgetsWithLeakTracking('card', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -751,7 +752,7 @@ void main() { )); }); - testWidgets('card with borderRadius and elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('card with borderRadius and elevation', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -770,7 +771,7 @@ void main() { )); }); - testWidgets('card with shape and elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('card with shape and elevation', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -788,7 +789,7 @@ void main() { )); }); - testWidgets('circle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('circle', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -805,7 +806,7 @@ void main() { )); }); - testWidgets('button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('button', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -823,7 +824,7 @@ void main() { )); }); - testWidgets('button with elevation and borderRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('button with elevation and borderRadius', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -843,7 +844,7 @@ void main() { )); }); - testWidgets('button with elevation and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('button with elevation and shape', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -864,7 +865,7 @@ void main() { }); group('Border painting', () { - testWidgets('border is painted on physical layers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is painted on physical layers', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -885,7 +886,7 @@ void main() { expect(box, paints..circle()); }); - testWidgets('border is painted for transparent material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is painted for transparent material', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -905,7 +906,7 @@ void main() { expect(box, paints..circle()); }); - testWidgets('border is not painted for when border side is none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is not painted for when border side is none', (WidgetTester tester) async { final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget( Material( @@ -920,7 +921,7 @@ void main() { expect(box, isNot(paints..circle())); }); - testWidgets('border is painted above child by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is painted above child by default', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -959,7 +960,7 @@ void main() { ); }); - testWidgets('border is painted below child when specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is painted below child when specified', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -1039,7 +1040,7 @@ void main() { }); group('LookupBoundary', () { - testWidgets('hides Material from Material.maybeOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hides Material from Material.maybeOf', (WidgetTester tester) async { MaterialInkController? material; await tester.pumpWidget( @@ -1058,7 +1059,7 @@ void main() { expect(material, isNull); }); - testWidgets('hides Material from Material.of', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hides Material from Material.of', (WidgetTester tester) async { await tester.pumpWidget( Material( child: LookupBoundary( @@ -1090,7 +1091,7 @@ void main() { ); }); - testWidgets('hides Material from debugCheckHasMaterial', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hides Material from debugCheckHasMaterial', (WidgetTester tester) async { await tester.pumpWidget( Material( child: LookupBoundary( diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index cf942f175254f..f54f45e973bbd 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -14,10 +14,11 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgets('Navigation bar updates destinations when tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation bar updates destinations when tapped', (WidgetTester tester) async { int mutatedIndex = -1; final Widget widget = _buildWidget( NavigationBar( @@ -49,7 +50,7 @@ void main() { expect(mutatedIndex, 0); }); - testWidgets('NavigationBar can update background color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationBar can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; await tester.pumpWidget( @@ -74,7 +75,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgets('NavigationBar can update elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationBar can update elevation', (WidgetTester tester) async { const double elevation = 42.0; await tester.pumpWidget( @@ -99,7 +100,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(elevation)); }); - testWidgets('NavigationBar adds bottom padding to height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationBar adds bottom padding to height', (WidgetTester tester) async { const double bottomPadding = 40.0; await tester.pumpWidget( @@ -148,7 +149,7 @@ void main() { expect(tester.getSize(find.byType(NavigationBar)).height, expectedHeight); }); - testWidgets('NavigationBar respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationBar respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async { const double safeAreaPadding = 40.0; Widget navigationBar() { return NavigationBar( @@ -246,7 +247,7 @@ void main() { ); }); - testWidgets('Material2 - NavigationBar uses proper defaults when no parameters are given', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - NavigationBar uses proper defaults when no parameters are given', (WidgetTester tester) async { // M2 settings that were hand coded. await tester.pumpWidget( _buildWidget( @@ -275,7 +276,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))); }); - testWidgets('Material3 - NavigationBar uses proper defaults when no parameters are given', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - NavigationBar uses proper defaults when no parameters are given', (WidgetTester tester) async { // M3 settings from the token database. final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -305,7 +306,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder()); }); - testWidgets('Material2 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { const String label = 'A'; Widget buildApp({ required double textScaleFactor }) { @@ -364,7 +365,7 @@ void main() { expect(tester.getSize(find.text(label).last), Size(defaultTooltipSize.width * 4, defaultTooltipSize.height * 4)); }); - testWidgets('Material3 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - NavigationBar shows tooltips with text scaling', (WidgetTester tester) async { const String label = 'A'; Widget buildApp({ required double textScaleFactor }) { @@ -430,7 +431,7 @@ void main() { } }); - testWidgets('Custom tooltips in NavigationBarDestination', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom tooltips in NavigationBarDestination', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -470,7 +471,7 @@ void main() { }); - testWidgets('Navigation bar semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation bar semantics', (WidgetTester tester) async { Widget widget({int selectedIndex = 0}) { return _buildWidget( NavigationBar( @@ -534,7 +535,7 @@ void main() { ); }); - testWidgets('Navigation bar semantics with some labels hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation bar semantics with some labels hidden', (WidgetTester tester) async { Widget widget({int selectedIndex = 0}) { return _buildWidget( NavigationBar( @@ -599,7 +600,7 @@ void main() { ); }); - testWidgets('Navigation bar does not grow with text scale factor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation bar does not grow with text scale factor', (WidgetTester tester) async { const int animationMilliseconds = 800; Widget widget({double textScaleFactor = 1}) { @@ -632,7 +633,7 @@ void main() { expect(newHeight, equals(initialHeight)); }); - testWidgets('Material3 - Navigation indicator renders ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Navigation indicator renders ripple', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/116751. int selectedIndex = 0; @@ -833,7 +834,7 @@ void main() { ); }); - testWidgets('Material3 - Navigation indicator ripple golden test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Navigation indicator ripple golden test', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117420. Widget buildWidget({ NavigationDestinationLabelBehavior? labelBehavior }) { @@ -890,7 +891,7 @@ void main() { await expectLater(find.byType(NavigationBar), matchesGoldenFile('indicator_onlyShowSelected_unselected_m3.png')); }); - testWidgets('Navigation indicator scale transform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation indicator scale transform', (WidgetTester tester) async { int selectedIndex = 0; Widget buildNavigationBar() { @@ -941,7 +942,7 @@ void main() { expect(transform.getColumn(0)[0], 1.0); }); - testWidgets('Material3 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); const ShapeBorder shape = RoundedRectangleBorder(); @@ -987,7 +988,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Material2 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const Color color = Color(0xff0000ff); const ShapeBorder shape = RoundedRectangleBorder(); @@ -1031,7 +1032,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, shape); }); - testWidgets('Material2 - Navigation indicator renders ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Navigation indicator renders ripple', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/116751. int selectedIndex = 0; @@ -1232,7 +1233,7 @@ void main() { ); }); - testWidgets('Material2 - Navigation indicator ripple golden test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Navigation indicator ripple golden test', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117420. Widget buildWidget({ NavigationDestinationLabelBehavior? labelBehavior }) { @@ -1289,7 +1290,7 @@ void main() { await expectLater(find.byType(NavigationBar), matchesGoldenFile('indicator_onlyShowSelected_unselected_m2.png')); }); - testWidgets('Destination icon does not rebuild when tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination icon does not rebuild when tapped', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/122811. Widget buildNavigationBar() { diff --git a/packages/flutter/test/material/persistent_bottom_sheet_test.dart b/packages/flutter/test/material/persistent_bottom_sheet_test.dart index 8c51e01ef030a..eb7c6eec93f7d 100644 --- a/packages/flutter/test/material/persistent_bottom_sheet_test.dart +++ b/packages/flutter/test/material/persistent_bottom_sheet_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { // Pumps and ensures that the BottomSheet animates non-linearly. Future checkNonLinearAnimation(WidgetTester tester) async { @@ -95,7 +97,7 @@ void main() { await tester.pumpWidget(buildFrame(const Text('I love Flutter!'))); }); - testWidgets('Verify that a BottomSheet can be rebuilt with ScaffoldFeatureController.setState()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a BottomSheet can be rebuilt with ScaffoldFeatureController.setState()', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); int buildCount = 0; @@ -122,7 +124,7 @@ void main() { expect(buildCount, equals(2)); }); - testWidgets('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: const Center(child: Text('body')), @@ -153,7 +155,7 @@ void main() { expect(find.text('Two'), findsOneWidget); }); - testWidgets('Verify that a scrollable BottomSheet can be dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a scrollable BottomSheet can be dismissed', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -185,7 +187,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -223,7 +225,7 @@ void main() { expect(find.text('Two'), findsOneWidget); }); - testWidgets('Verify that a BottomSheet animates non-linearly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a BottomSheet animates non-linearly', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -297,7 +299,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -408,7 +410,7 @@ void main() { expect(find.text('Item 22'), findsNothing); }); - testWidgets('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -462,7 +464,7 @@ void main() { expect(find.byType(FloatingActionButton).hitTestable(), findsNothing); }); - testWidgets('showBottomSheet()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showBottomSheet()', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -486,7 +488,7 @@ void main() { expect(buildCount, equals(1)); }); - testWidgets('Scaffold removes top MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold removes top MediaQuery padding', (WidgetTester tester) async { late BuildContext scaffoldContext; late BuildContext bottomSheetContext; @@ -588,7 +590,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/71435 - testWidgets( + testWidgetsWithLeakTracking( 'Scaffold.bottomSheet should be updated without creating a new RO' ' when the new widget has the same key and type.', (WidgetTester tester) async { @@ -612,7 +614,7 @@ void main() { }, ); - testWidgets('Verify that visual properties are passed through', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that visual properties are passed through', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const Color color = Colors.pink; const double elevation = 9.0; @@ -647,7 +649,7 @@ void main() { expect(bottomSheet.clipBehavior, clipBehavior); }); - testWidgets('PersistentBottomSheetController.close dismisses the bottom sheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PersistentBottomSheetController.close dismisses the bottom sheet', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index 9f4610c12f9b3..04ab76fa01b3f 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -17,13 +17,14 @@ import 'package:flutter/services.dart'; import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { final ThemeData theme = ThemeData(); - testWidgets('Radio control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio control test', (WidgetTester tester) async { final Key key = UniqueKey(); final List log = []; @@ -84,7 +85,7 @@ void main() { expect(log, isEmpty); }); - testWidgets('Radio can be toggled when toggleable is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio can be toggled when toggleable is set', (WidgetTester tester) async { final Key key = UniqueKey(); final List log = []; @@ -148,7 +149,7 @@ void main() { expect(log, equals([1])); }); - testWidgets('Radio size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { final Key key1 = UniqueKey(); await tester.pumpWidget( Theme( @@ -194,7 +195,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(40.0, 40.0)); }); - testWidgets('Radio selected semantics - platform adaptive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio selected semantics - platform adaptive', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Theme( @@ -229,7 +230,7 @@ void main() { semantics.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('Radio semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Theme( @@ -360,7 +361,7 @@ void main() { semantics.dispose(); }); - testWidgets('has semantic events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantic events', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Key key = UniqueKey(); dynamic semanticEvent; @@ -398,7 +399,7 @@ void main() { tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('Material2 - Radio ink ripple is displayed correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio ink ripple is displayed correctly', (WidgetTester tester) async { final Key painterKey = UniqueKey(); const Key radioKey = Key('radio'); @@ -432,7 +433,7 @@ void main() { ); }); - testWidgets('Material3 - Radio ink ripple is displayed correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio ink ripple is displayed correctly', (WidgetTester tester) async { final Key painterKey = UniqueKey(); const Key radioKey = Key('radio'); @@ -466,7 +467,7 @@ void main() { ); }); - testWidgets('Radio with splash radius set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio with splash radius set', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; Widget buildApp() { @@ -503,7 +504,7 @@ void main() { ); }); - testWidgets('Material2 - Radio is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; @@ -586,7 +587,7 @@ void main() { ); }); - testWidgets('Material3 - Radio is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; @@ -664,7 +665,7 @@ void main() { ); }); - testWidgets('Material2 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; const Key radioKey = Key('radio'); @@ -747,7 +748,7 @@ void main() { ); }); - testWidgets('Material3 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; const Key radioKey = Key('radio'); @@ -831,7 +832,7 @@ void main() { ); }); - testWidgets('Radio can be controlled by keyboard shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio can be controlled by keyboard shortcuts', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 1; const Key radioKey0 = Key('radio0'); @@ -910,7 +911,7 @@ void main() { expect(groupValue, equals(2)); }); - testWidgets('Radio responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( @@ -949,7 +950,7 @@ void main() { expect(box.size, equals(const Size(60, 36))); }); - testWidgets('Radio changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio changes mouse cursor when hovered', (WidgetTester tester) async { const Key key = ValueKey(1); // Test Radio() constructor await tester.pumpWidget( @@ -1032,7 +1033,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('Radio button fill color resolves in enabled/disabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio button fill color resolves in enabled/disabled states', (WidgetTester tester) async { const Color activeEnabledFillColor = Color(0xFF000001); const Color activeDisabledFillColor = Color(0xFF000002); const Color inactiveEnabledFillColor = Color(0xFF000003); @@ -1143,7 +1144,7 @@ void main() { ); }); - testWidgets('Material2 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredFillColor = Color(0xFF000001); @@ -1226,7 +1227,7 @@ void main() { ); }); - testWidgets('Material3 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredFillColor = Color(0xFF000001); @@ -1449,7 +1450,7 @@ void main() { ); }); - testWidgets('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { final Key key = UniqueKey(); Widget buildRadio(bool show) { @@ -1475,7 +1476,7 @@ void main() { await gesture.up(); }); - testWidgets('disabled radio shows tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled radio shows tooltip', (WidgetTester tester) async { const String longPressTooltip = 'long press tooltip'; const String tapTooltip = 'tap tooltip'; await tester.pumpWidget( @@ -1531,7 +1532,7 @@ void main() { expect(find.text(tapTooltip), findsOneWidget); }); - testWidgets('Material2 - Radio button default colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio button default colors', (WidgetTester tester) async { Widget buildRadio({bool enabled = true, bool selected = true}) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1577,7 +1578,7 @@ void main() { ); }); - testWidgets('Material3 - Radio button default colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio button default colors', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); Widget buildRadio({bool enabled = true, bool selected = true}) { return MaterialApp( @@ -1798,7 +1799,7 @@ void main() { ); }); - testWidgets('Radio.adaptive shows the correct platform widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio.adaptive shows the correct platform widget', (WidgetTester tester) async { Widget buildApp(TargetPlatform platform) { return MaterialApp( theme: ThemeData(platform: platform), @@ -1829,7 +1830,7 @@ void main() { } }); - testWidgets('Material2 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: false); @@ -1894,7 +1895,7 @@ void main() { ); }); - testWidgets('Material3 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: true); diff --git a/packages/flutter/test/material/refresh_indicator_test.dart b/packages/flutter/test/material/refresh_indicator_test.dart index 9a2248204d94f..4378ff8cd8e0f 100644 --- a/packages/flutter/test/material/refresh_indicator_test.dart +++ b/packages/flutter/test/material/refresh_indicator_test.dart @@ -9,6 +9,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + bool refreshCalled = false; Future refresh() { @@ -22,7 +24,7 @@ Future holdRefresh() { } void main() { - testWidgets('RefreshIndicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator', (WidgetTester tester) async { refreshCalled = false; final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( @@ -56,7 +58,7 @@ void main() { handle.dispose(); }); - testWidgets('Refresh Indicator - nested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Refresh Indicator - nested', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -97,7 +99,7 @@ void main() { expect(refreshCalled, true); }); - testWidgets('RefreshIndicator - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - reverse', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -125,7 +127,7 @@ void main() { expect(refreshCalled, true); }); - testWidgets('RefreshIndicator - top - position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - top - position', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -151,7 +153,7 @@ void main() { expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0)); }); - testWidgets('RefreshIndicator - reverse - position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - reverse - position', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -178,7 +180,7 @@ void main() { expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0)); }); - testWidgets('RefreshIndicator - no movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - no movement', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -206,7 +208,7 @@ void main() { expect(refreshCalled, false); }); - testWidgets('RefreshIndicator - not enough', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - not enough', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -233,7 +235,7 @@ void main() { expect(refreshCalled, false); }); - testWidgets('RefreshIndicator - just enough', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - just enough', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -260,7 +262,7 @@ void main() { expect(refreshCalled, true); }); - testWidgets('RefreshIndicator - show - slow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - show - slow', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -303,7 +305,7 @@ void main() { expect(refreshCalled, false); }); - testWidgets('RefreshIndicator - show - fast', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - show - fast', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -347,7 +349,7 @@ void main() { expect(completed, true); }); - testWidgets('RefreshIndicator - show - fast - twice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - show - fast - twice', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -385,7 +387,7 @@ void main() { expect(completed2, true); }); - testWidgets('Refresh starts while scroll view moves back to 0.0 after overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Refresh starts while scroll view moves back to 0.0 after overscroll', (WidgetTester tester) async { refreshCalled = false; double lastScrollOffset; final ScrollController controller = ScrollController(); @@ -424,7 +426,7 @@ void main() { expect(refreshCalled, isTrue); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('RefreshIndicator does not force child to relayout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator does not force child to relayout', (WidgetTester tester) async { int layoutCount = 0; Widget layoutCallback(BuildContext context, BoxConstraints constraints) { @@ -459,7 +461,7 @@ void main() { expect(layoutCount, 1); }); - testWidgets('RefreshIndicator responds to strokeWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator responds to strokeWidth', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: RefreshIndicator( @@ -507,7 +509,7 @@ void main() { ); }); - testWidgets('RefreshIndicator responds to edgeOffset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator responds to edgeOffset', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: RefreshIndicator( @@ -555,7 +557,7 @@ void main() { ); }); - testWidgets('RefreshIndicator appears at edgeOffset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator appears at edgeOffset', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: RefreshIndicator( edgeOffset: kToolbarHeight, @@ -584,7 +586,7 @@ void main() { ); }); - testWidgets('Top RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Top RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { refreshCalled = false; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -619,7 +621,7 @@ void main() { expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0)); }); - testWidgets('Reverse RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reverse RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { refreshCalled = false; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -656,7 +658,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/71936 - testWidgets('RefreshIndicator(anywhere mode) should not be shown when overscroll occurs due to inertia', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator(anywhere mode) should not be shown when overscroll occurs due to inertia', (WidgetTester tester) async { refreshCalled = false; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -692,7 +694,7 @@ void main() { expect(find.byType(RefreshProgressIndicator), findsNothing); }); - testWidgets('Top RefreshIndicator(onEdge mode) should not be shown when dragging from non-zero scroll position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Top RefreshIndicator(onEdge mode) should not be shown when dragging from non-zero scroll position', (WidgetTester tester) async { refreshCalled = false; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -726,7 +728,7 @@ void main() { expect(find.byType(RefreshProgressIndicator), findsNothing); }); - testWidgets('Reverse RefreshIndicator(onEdge mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reverse RefreshIndicator(onEdge mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { refreshCalled = false; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -761,7 +763,7 @@ void main() { expect(find.byType(RefreshProgressIndicator), findsNothing); }); - testWidgets('ScrollController.jumpTo should not trigger the refresh indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollController.jumpTo should not trigger the refresh indicator', (WidgetTester tester) async { refreshCalled = false; final ScrollController scrollController = ScrollController(initialScrollOffset: 500.0); await tester.pumpWidget( @@ -793,7 +795,7 @@ void main() { expect(refreshCalled, false); }); - testWidgets('RefreshIndicator.adaptive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator.adaptive', (WidgetTester tester) async { Widget buildFrame(TargetPlatform platform) { return MaterialApp( theme: ThemeData(platform: platform), @@ -835,7 +837,7 @@ void main() { } }); - testWidgets('RefreshIndicator color defaults to ColorScheme.primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator color defaults to ColorScheme.primary', (WidgetTester tester) async { const Color primaryColor = Color(0xff4caf50); final ThemeData theme = ThemeData.from(colorScheme: const ColorScheme.light().copyWith(primary: primaryColor)); await tester.pumpWidget( @@ -871,7 +873,7 @@ void main() { expect(tester.widget(find.byType(RefreshProgressIndicator)).valueColor!.value, primaryColor); }); - testWidgets('RefreshIndicator.color can be updated at runtime', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator.color can be updated at runtime', (WidgetTester tester) async { refreshCalled = false; Color refreshIndicatorColor = Colors.green; const Color red = Colors.red; @@ -918,7 +920,7 @@ void main() { expect(tester.widget(find.byType(RefreshProgressIndicator)).valueColor!.value, red.withOpacity(1.0)); }); - testWidgets('RefreshIndicator - reverse - BouncingScrollPhysics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator - reverse - BouncingScrollPhysics', (WidgetTester tester) async { refreshCalled = false; await tester.pumpWidget( MaterialApp( @@ -952,7 +954,7 @@ void main() { expect(refreshCalled, true); }); - testWidgets('RefreshIndicator disallows indicator - glow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator disallows indicator - glow', (WidgetTester tester) async { refreshCalled = false; bool glowAccepted = true; ScrollNotification? lastNotification; @@ -1004,7 +1006,7 @@ void main() { expect(glowAccepted, false); }); - testWidgets('RefreshIndicator disallows indicator - stretch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshIndicator disallows indicator - stretch', (WidgetTester tester) async { refreshCalled = false; bool stretchAccepted = true; ScrollNotification? lastNotification; diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index cb785b3217e85..a4641423e25e2 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; @@ -22,7 +23,7 @@ Widget boilerplate({required Widget child}) { void main() { - testWidgets('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -330,7 +331,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgets('SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -409,7 +410,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgets('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -486,7 +487,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes semantics.dispose(); }); - testWidgets('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -534,7 +535,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('SegmentedButton has no tooltips by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton has no tooltips by default', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -558,7 +559,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byType(Tooltip), findsNothing); }); - testWidgets('SegmentedButton has correct tooltips', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton has correct tooltips', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( From 934d20864d075768e1456c1c0769eebd9cffd641 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 14:10:10 -0400 Subject: [PATCH 0161/1547] Roll Flutter Engine from 805162c18b32 to c8dbd8a45f79 (2 revisions) (#130596) https://github.com/flutter/engine/compare/805162c18b32...c8dbd8a45f79 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from b4b9c76206f3 to de6099518f90 (4 revisions) (flutter/engine#43687) 2023-07-14 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from J0oxaSt651gKgDreU... to Z-1lzZAOYHvVrdjQ8... (flutter/engine#43685) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from J0oxaSt651gK to Z-1lzZAOYHvV If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5ebed78ec9ca5..ff94b98935699 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -805162c18b32c8352c71d9e832a812fc40058020 +c8dbd8a45f7957541c73251bb494720e15f1af61 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 519e77eb3d4e5..0b217311b7953 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -J0oxaSt651gKgDreUUVzse6-xsrejysSrYuIslJ3BZ0C +Z-1lzZAOYHvVrdjQ8BvAyXjjPHDVMAdLAAxqb4caxGQC From 56b5cc908304831cb7d1230e009d3a241991a5b6 Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Fri, 14 Jul 2023 11:24:25 -0700 Subject: [PATCH 0162/1547] Roll pub packages (#130348) This PR was generated by `flutter update-packages --force-upgrade`. From 847d1f0460ead45085c2170aacb77a79f1a76309 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 14:57:51 -0400 Subject: [PATCH 0163/1547] Roll Flutter Engine from c8dbd8a45f79 to 63e9cbe7baa3 (3 revisions) (#130601) https://github.com/flutter/engine/compare/c8dbd8a45f79...63e9cbe7baa3 2023-07-14 kjlubick@users.noreply.github.com Add missing Skia #includes (flutter/engine#43680) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from de6099518f90 to c14fda1cb615 (1 revision) (flutter/engine#43689) 2023-07-14 flar@google.com Fix DisplayListMatrixClipTracker handling of diff clips (flutter/engine#43664) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ff94b98935699..ee89ad4a0604a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c8dbd8a45f7957541c73251bb494720e15f1af61 +63e9cbe7baa3f81c54b39258dc269aa9bba3b57f From 1c1c273bca325be127ddd42849b05c42132fd16e Mon Sep 17 00:00:00 2001 From: Pavel Mazhnik Date: Fri, 14 Jul 2023 22:10:55 +0300 Subject: [PATCH 0164/1547] [web] remove unnecessary awaits from flutter.js (#130204) Fixed types for `_getNewServiceWorker` and `_waitForServiceWorkerActivation` functions. These functions currently expect a Promise as an argument, but we're actually passing in an already resolved value: ```js .then(this._getNewServiceWorker) .then(this._waitForServiceWorkerActivation); ``` --- .../lib/src/web/file_generators/js/flutter.js | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js b/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js index d3efa7fd80d9d..c60bf3555e5a4 100644 --- a/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js +++ b/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js @@ -156,53 +156,46 @@ _flutter.loader = null; } /** - * Returns the latest service worker for the given `serviceWorkerRegistrationPromise`. + * Returns the latest service worker for the given `serviceWorkerRegistration`. * * This might return the current service worker, if there's no new service worker * awaiting to be installed/updated. * - * @param {Promise} serviceWorkerRegistrationPromise + * @param {ServiceWorkerRegistration} serviceWorkerRegistration * @returns {Promise} */ - async _getNewServiceWorker(serviceWorkerRegistrationPromise) { - const reg = await serviceWorkerRegistrationPromise; - - if (!reg.active && (reg.installing || reg.waiting)) { + async _getNewServiceWorker(serviceWorkerRegistration) { + if (!serviceWorkerRegistration.active && (serviceWorkerRegistration.installing || serviceWorkerRegistration.waiting)) { // No active web worker and we have installed or are installing // one for the first time. Simply wait for it to activate. console.debug("Installing/Activating first service worker."); - return reg.installing || reg.waiting; - } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) { + return serviceWorkerRegistration.installing || serviceWorkerRegistration.waiting; + } else if (!serviceWorkerRegistration.active.scriptURL.endsWith(serviceWorkerVersion)) { // When the app updates the serviceWorkerVersion changes, so we // need to ask the service worker to update. - return reg.update().then((newReg) => { - console.debug("Updating service worker."); - return newReg.installing || newReg.waiting || newReg.active; - }); + const newRegistration = await serviceWorkerRegistration.update(); + console.debug("Updating service worker."); + return newRegistration.installing || newRegistration.waiting || newRegistration.active; } else { console.debug("Loading from existing service worker."); - return reg.active; + return serviceWorkerRegistration.active; } } /** - * Returns a Promise that resolves when the `latestServiceWorker` changes its + * Returns a Promise that resolves when the `serviceWorker` changes its * state to "activated". * - * @param {Promise} latestServiceWorkerPromise + * @param {ServiceWorker} serviceWorker * @returns {Promise} */ - async _waitForServiceWorkerActivation(latestServiceWorkerPromise) { - const serviceWorker = await latestServiceWorkerPromise; - + async _waitForServiceWorkerActivation(serviceWorker) { if (!serviceWorker || serviceWorker.state == "activated") { if (!serviceWorker) { - return Promise.reject( - new Error("Cannot activate a null service worker!") - ); + throw new Error("Cannot activate a null service worker!"); } else { console.debug("Service worker already active."); - return Promise.resolve(); + return; } } return new Promise((resolve, _) => { From 41d137f391f06c6593173ea21fa9261adadfb691 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 15:28:10 -0400 Subject: [PATCH 0165/1547] Roll Packages from aa1eace00188 to 369ee7e1a1cb (10 revisions) (#130605) https://github.com/flutter/packages/compare/aa1eace00188...369ee7e1a1cb 2023-07-14 reidbaker@google.com [Tool] New tool to download android dependencies (flutter/packages#4408) 2023-07-14 zaldypagaduanjr@gmail.com [video_player] added iOS exception on incorrect asset path (flutter/packages#4318) 2023-07-14 joonas.kerttula@codemate.com [google_maps_flutter_platform_interface] Add support for cloud-based map styling (flutter/packages#4141) 2023-07-14 10687576+bparrishMines@users.noreply.github.com [webview_flutter] Adds support for receiving a url with WebResourceError (flutter/packages#3884) 2023-07-14 stuartmorgan@google.com [xdg_directories] Remove `process` dependency (flutter/packages#4460) 2023-07-13 stuartmorgan@google.com [various] Update Pigeon in Swift plugins (flutter/packages#4461) 2023-07-13 engine-flutter-autoroll@skia.org Roll Flutter from 544d30dbaddf to c40173f114fa (10 revisions) (flutter/packages#4457) 2023-07-13 engine-flutter-autoroll@skia.org Roll Flutter (stable) from 796c8ef79279 to f468f3366c26 (2 revisions) (flutter/packages#4456) 2023-07-13 bisor0627@gmail.com Fix Router Config Issues #4300 (go_router_builder/example) (flutter/packages#4369) 2023-07-13 10687576+bparrishMines@users.noreply.github.com [webview_flutter_platform_interface] Adds url to `WebResourceError` (flutter/packages#4439) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 9e6a579ae5001..c63b85b36b347 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -aa1eace001880d6e08f2b67ad3eed70241b5a1bc +369ee7e1a1cba9cd49421dd12bd1fd6fa69d6b68 From d5c724eb07a6d954ff59955f569c550047de8938 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Fri, 14 Jul 2023 13:36:02 -0700 Subject: [PATCH 0166/1547] Remove unused imports (#130603) --- packages/flutter/lib/src/rendering/object.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 3e42a22ca2127..b12378a9ff4f8 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:ui' as ui show PictureRecorder; -import 'dart:ui'; import 'package:flutter/animation.dart'; import 'package:flutter/foundation.dart'; @@ -14,7 +13,6 @@ import 'package:flutter/semantics.dart'; import 'debug.dart'; import 'layer.dart'; -import 'proxy_box.dart'; export 'package:flutter/foundation.dart' show DiagnosticPropertiesBuilder, From f2574ba1deb12523d25b1e860bd9a4d7d2d30bdd Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 14 Jul 2023 14:12:24 -0700 Subject: [PATCH 0167/1547] Use the new rounding hack migration flag in TextPainter (#130548) --- .../lib/src/painting/text_painter.dart | 7 +- .../cupertino/nav_bar_transition_test.dart | 144 +++++++++--------- .../flutter/test/material/badge_test.dart | 8 +- .../test/material/date_range_picker_test.dart | 2 +- .../material/flexible_space_bar_test.dart | 6 +- .../test/material/input_decorator_test.dart | 4 +- .../test/material/navigation_rail_test.dart | 6 +- .../test/material/outlined_button_test.dart | 6 +- .../test/material/tab_bar_theme_test.dart | 6 +- packages/flutter/test/material/tabs_test.dart | 4 +- .../test/material/text_button_test.dart | 14 +- .../test/material/time_picker_test.dart | 4 +- .../test/painting/text_painter_test.dart | 2 +- 13 files changed, 112 insertions(+), 101 deletions(-) diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 08ed58c612960..bcad34b23dfd5 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -278,13 +278,10 @@ class _TextLayout { // object when it's no logner needed. ui.Paragraph _paragraph; - /// Whether to enable the rounding in _applyFloatingPointHack and SkParagraph. - static const bool _shouldApplyFloatingPointHack = !bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK'); - // TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/31707 // remove this hack as well as the flooring in `layout`. @pragma('vm:prefer-inline') - static double _applyFloatingPointHack(double layoutValue) => _shouldApplyFloatingPointHack ? layoutValue.ceilToDouble() : layoutValue; + static double _applyFloatingPointHack(double layoutValue) => ui.ParagraphBuilder.shouldDisableRoundingHack ? layoutValue : layoutValue.ceilToDouble(); /// Whether this layout has been invalidated and disposed. /// @@ -362,7 +359,7 @@ class _TextPainterLayoutCacheWithOffset { static double _contentWidthFor(double minWidth, double maxWidth, TextWidthBasis widthBasis, _TextLayout layout) { // TODO(LongCatIsLooong): remove the rounding when _applyFloatingPointHack // is removed. - if (_TextLayout._shouldApplyFloatingPointHack) { + if (!ui.ParagraphBuilder.shouldDisableRoundingHack) { minWidth = minWidth.floorToDouble(); maxWidth = maxWidth.floorToDouble(); } diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index cdefa99dc59b5..abfbf7bc31f1b 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -145,15 +145,15 @@ void main() { // place. expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, 13.5, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, 13.5, ), ); @@ -172,15 +172,15 @@ void main() { // Same as LTR but more to the right now. expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, 13.5, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, 13.5, ), ); @@ -371,8 +371,8 @@ void main() { expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, 13.5, ), ); @@ -384,8 +384,8 @@ void main() { expect(topBackLabel.text.style!.color, const Color(0xff000306)); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 342.547737105096302912 : 342.33420100808144, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, 13.5, ), ); @@ -422,8 +422,8 @@ void main() { expect(bottomMiddle.text.style!.color, const Color(0xff000306)); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, 13.5, ), ); @@ -435,8 +435,8 @@ void main() { expect(topBackLabel.text.style!.color, const Color(0xff000306)); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 357.912261979376353338 : 357.66579899191856, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, 13.5, ), ); @@ -736,15 +736,15 @@ void main() { ); // Come in from the right and fade in. checkOpacity(tester, backChevron, 0.0); - expect(tester.getTopLeft(backChevron), const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 87.2460581221158690823 : 88.04496401548386, + expect(tester.getTopLeft(backChevron), Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 87.2460581221158690823 : 88.04496401548386, 7.0, )); await tester.pump(const Duration(milliseconds: 200)); checkOpacity(tester, backChevron, 0.09497911669313908); - expect(tester.getTopLeft(backChevron), const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 30.8718595298545324113 : 31.055883467197418, + expect(tester.getTopLeft(backChevron), Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 30.8718595298545324113 : 31.055883467197418, 7.0, )); }); @@ -784,8 +784,8 @@ void main() { checkOpacity(tester, backChevron, 0.0); expect( tester.getTopRight(backChevron), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 687.163941725296126606 : 685.9550359845161, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 687.163941725296126606 : 685.9550359845161, 7.0, ), ); @@ -794,8 +794,8 @@ void main() { checkOpacity(tester, backChevron, 0.09497911669313908); expect( tester.getTopRight(backChevron), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 743.538140317557690651 : 742.9441165328026, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 743.538140317557690651 : 742.9441165328026, 7.0, ), ); @@ -899,8 +899,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('custom')), 0.9280824661254883); expect( tester.getTopLeft(flying(tester, find.text('custom'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 684.459999084472656250 : 684.0, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 684.459999084472656250 : 684.0, 13.5, ), ); @@ -909,8 +909,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('custom')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('custom'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 684.459999084472656250 : 684.0, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 684.459999084472656250 : 684.0, 13.5, ), ); @@ -941,8 +941,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 1')), 0.7952219992876053); expect( tester.getTopLeft(flying(tester, find.text('Page 1'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 41.3003370761871337891 : 41.71033692359924, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 41.3003370761871337891 : 41.71033692359924, 13.5, ), ); @@ -951,8 +951,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 1')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('Page 1'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? -258.642192125320434570 : -258.2321922779083, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? -258.642192125320434570 : -258.2321922779083, 13.5, ), ); @@ -984,8 +984,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 1')), 0.7952219992876053); expect( tester.getTopRight(flying(tester, find.text('Page 1'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 758.699662923812866211 : 758.2896630764008, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 758.699662923812866211 : 758.2896630764008, 13.5, ), ); @@ -995,8 +995,8 @@ void main() { expect( tester.getTopRight(flying(tester, find.text('Page 1'))), // >1000. It's now off the screen. - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 1058.64219212532043457 : 1058.2321922779083, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 1058.64219212532043457 : 1058.2321922779083, 13.5, ), ); @@ -1021,15 +1021,15 @@ void main() { expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, 52.73951627314091, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, 52.73951627314091, ), ); @@ -1040,15 +1040,15 @@ void main() { expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, 22.49655644595623, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, 22.49655644595623, ), ); @@ -1072,15 +1072,15 @@ void main() { checkOpacity(tester, flying(tester, find.text('Back')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('A title too long to fit'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, 52.73951627314091, ), ); expect( tester.getTopLeft(flying(tester, find.text('Back'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 16.9155227761479522997 : 16.926069676876068, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, 52.73951627314091, ), ); @@ -1090,15 +1090,15 @@ void main() { checkOpacity(tester, flying(tester, find.text('Back')), 0.4604858811944723); expect( tester.getTopLeft(flying(tester, find.text('A title too long to fit'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, 22.49655644595623, ), ); expect( tester.getTopLeft(flying(tester, find.text('Back'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 43.6029094262710827934 : 43.92089730501175, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, 22.49655644595623, ), ); @@ -1156,8 +1156,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 739.940336465835571289 : 739.7103369235992, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 739.940336465835571289 : 739.7103369235992, 13.5, ), ); @@ -1167,8 +1167,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.29867843724787235); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 504.880443334579467773 : 504.65044379234314, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 504.880443334579467773 : 504.65044379234314, 13.5, ), ); @@ -1212,8 +1212,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.0); expect( tester.getTopRight(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 60.0596635341644287109 : 60.28966307640076, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 60.0596635341644287109 : 60.28966307640076, 13.5, ), ); @@ -1223,8 +1223,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.29867843724787235); expect( tester.getTopRight(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 295.119556665420532227 : 295.34955620765686, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 295.119556665420532227 : 295.34955620765686, 13.5, ), ); @@ -1350,8 +1350,8 @@ void main() { // Page 2, which is the middle of the top route, start to fly back to the right. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 353.810205429792404175 : 353.5802058875561, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 353.810205429792404175 : 353.5802058875561, 13.5, ), ); @@ -1368,16 +1368,16 @@ void main() { // Transition continues. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 655.435583114624023438 : 655.2055835723877, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 655.435583114624023438 : 655.2055835723877, 13.5, ), ); await tester.pump(const Duration(milliseconds: 50)); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 749.863556146621704102 : 749.6335566043854, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 749.863556146621704102 : 749.6335566043854, 13.5, ), ); @@ -1421,8 +1421,8 @@ void main() { // Page 2, which is the middle of the top route, start to fly back to the right. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 353.810205429792404175 : 353.5802058875561, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 353.810205429792404175 : 353.5802058875561, 13.5, ), ); @@ -1433,16 +1433,16 @@ void main() { // Transition continues from the point we let off. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 353.810205429792404175 : 353.5802058875561, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 353.810205429792404175 : 353.5802058875561, 13.5, ), ); await tester.pump(const Duration(milliseconds: 50)); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - const Offset( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 350.231143206357955933 : 350.0011436641216, + Offset( + ParagraphBuilder.shouldDisableRoundingHack ? 350.231143206357955933 : 350.0011436641216, 13.5, ), ); diff --git a/packages/flutter/test/material/badge_test.dart b/packages/flutter/test/material/badge_test.dart index 4b97861418da9..05691229a59bf 100644 --- a/packages/flutter/test/material/badge_test.dart +++ b/packages/flutter/test/material/badge_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -50,7 +52,7 @@ void main() { expect(tester.getTopLeft(find.text('0')), const Offset(16, -4)); final RenderBox box = tester.renderObject(find.byType(Badge)); - final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack ? RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8)) : RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)); expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); @@ -92,7 +94,7 @@ void main() { expect(tester.getTopLeft(find.text('0')), const Offset(0, -4)); final RenderBox box = tester.renderObject(find.byType(Badge)); - final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack ? RRect.fromLTRBR(-4, -4, 15.5, 12, const Radius.circular(8)) : RRect.fromLTRBR(-4, -4, 16, 12, const Radius.circular(8)); expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); @@ -149,7 +151,7 @@ void main() { // T = alignment.top // R = L + '0'.width + padding.width // B = T + largeSize, R = largeSize/2 - final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack ? RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8)) : RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)); expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index 6feafa939d78b..82b9d3fc6c486 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -134,7 +134,7 @@ void main() { ); expect( saveButtonBottomLeft.dx, - const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? moreOrLessEquals(711.6, epsilon: 1e-5) : (800 - 89.0), + ParagraphBuilder.shouldDisableRoundingHack ? moreOrLessEquals(711.6, epsilon: 1e-5) : (800 - 89.0), ); expect(saveButtonBottomLeft.dy, helpTextTopLeft.dy); expect(entryButtonBottomLeft.dx, saveButtonBottomLeft.dx - 48.0); diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index 7477480f9f969..a643d4a0c3137 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -7,6 +7,8 @@ @Tags(['reduced-test-set']) library; +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -470,7 +472,7 @@ void main() { ), ); - final double textWidth = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final double textWidth = ui.ParagraphBuilder.shouldDisableRoundingHack ? width : (width / 1.5).floorToDouble() * 1.5; // The title is scaled and transformed to be 1.5 times bigger, when the @@ -541,7 +543,7 @@ void main() { // bottom edge. const double bottomMargin = titleFontSize * (expandedTitleScale - 1); - final double textWidth = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final double textWidth = ui.ParagraphBuilder.shouldDisableRoundingHack ? collapsedWidth : (collapsedWidth / 3).floorToDouble() * 3; // The title is scaled and transformed to be 3 times bigger, when the diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 775505396767e..d7b864179797a 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -5928,10 +5928,10 @@ void main() { } final Rect clipRect = arguments[0] as Rect; // _kFinalLabelScale = 0.75 - const double width = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final double width = ParagraphBuilder.shouldDisableRoundingHack ? 100 / 0.75 : 133.0; - expect(clipRect, rectMoreOrLessEquals(const Rect.fromLTWH(0, 0, width, 16.0), epsilon: 1e-5)); + expect(clipRect, rectMoreOrLessEquals(Rect.fromLTWH(0, 0, width, 16.0), epsilon: 1e-5)); return true; }), ); diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index fb0086b9d2446..eeeb5c411a8fe 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -583,7 +585,7 @@ void main() { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. - const double destinationWidth = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 125.5 : 126.0; + final double destinationWidth = ui.ParagraphBuilder.shouldDisableRoundingHack ? 125.5 : 126.0; // Height of a destination indicator with icon. const double destinationHeight = 32.0; // Space between the indicator and label. @@ -858,7 +860,7 @@ void main() { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. - const double destinationWidth = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 125.5 : 126.0; + final double destinationWidth = ui.ParagraphBuilder.shouldDisableRoundingHack ? 125.5 : 126.0; // Height of a destination indicator with icon. const double destinationHeight = 32.0; // Space between the indicator and label. diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index eb25c9401993e..704c7a7a3a1e1 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -1066,8 +1068,8 @@ void main() { ); expect(tester.getSize(find.byType(OutlinedButton)), equals(const Size(88.0, 48.0))); - expect(tester.getSize(find.byType(Text)), const Size( - bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 52.5 : 53.0, + expect(tester.getSize(find.byType(Text)), Size( + ui.ParagraphBuilder.shouldDisableRoundingHack ? 52.5 : 53.0, 18.0, )); diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 4b8c5a924399e..3b686c185ddc4 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -7,6 +7,8 @@ @Tags(['reduced-test-set']) library; +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -607,8 +609,8 @@ void main() { ..line( color: theme.colorScheme.primary, strokeWidth: indicatorWeight, - p1: const Offset(bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 65.75 : 65.5, indicatorY), - p2: const Offset(bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? 134.25 : 134.5, indicatorY), + p1: Offset(ui.ParagraphBuilder.shouldDisableRoundingHack ? 65.75 : 65.5, indicatorY), + p2: Offset(ui.ParagraphBuilder.shouldDisableRoundingHack ? 134.25 : 134.5, indicatorY), ), ); }); diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index c2194170fe01f..62e4f172fd09f 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -489,7 +491,7 @@ void main() { const double indicatorWeight = 3.0; - final RRect rrect = const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') + final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack ? RRect.fromLTRBAndCorners( 64.75, tabBarBox.size.height - indicatorWeight, diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 6e458587fbb2d..a86fed59648d9 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui' as ui show ParagraphBuilder; + import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -618,12 +620,12 @@ void main() { ), ); - const Size textButtonSize = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') - ? Size(68.5, 48.0) - : Size(69.0, 48.0); - const Size textSize = bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') - ? Size(52.5, 18.0) - : Size(53.0, 18.0); + final Size textButtonSize = ui.ParagraphBuilder.shouldDisableRoundingHack + ? const Size(68.5, 48.0) + : const Size(69.0, 48.0); + final Size textSize = ui.ParagraphBuilder.shouldDisableRoundingHack + ? const Size(52.5, 18.0) + : const Size(53.0, 18.0); expect(tester.getSize(find.byType(TextButton)), textButtonSize); expect(tester.getSize(find.byType(Text)), textSize); diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 1c1360c9cf71d..b17d2e46d1303 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -746,7 +746,7 @@ void main() { case MaterialType.material2: expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155))); expect(tester.getBottomRight(find.text(selectTimeString)), equals( - const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? const Offset(280.5, 165) : const Offset(281, 165), + ParagraphBuilder.shouldDisableRoundingHack ? const Offset(280.5, 165) : const Offset(281, 165), )); expect(tester.getBottomRight(find.text(okString)).dx, 644); expect(tester.getBottomLeft(find.text(okString)).dx, 616); @@ -768,7 +768,7 @@ void main() { switch (materialType) { case MaterialType.material2: expect(tester.getTopLeft(find.text(selectTimeString)), equals( - const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK') ? const Offset(519.5, 155) : const Offset(519, 155), + ParagraphBuilder.shouldDisableRoundingHack ? const Offset(519.5, 155) : const Offset(519, 155), )); expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165))); expect(tester.getBottomLeft(find.text(okString)).dx, 156); diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index 57b6d63023597..f0b76fc0b9918 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -1509,7 +1509,7 @@ void main() { }); test('TextPainter line breaking does not round to integers', () { - if (! const bool.hasEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')) { + if (!ui.ParagraphBuilder.shouldDisableRoundingHack) { return; } const double fontSize = 1.25; From 6d8dc1983088dc9d3da13b1d1979c2e818d974b9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 17:17:13 -0400 Subject: [PATCH 0168/1547] Roll Flutter Engine from 63e9cbe7baa3 to 2fabf4e5c9ed (3 revisions) (#130615) https://github.com/flutter/engine/compare/63e9cbe7baa3...2fabf4e5c9ed 2023-07-14 jonahwilliams@google.com [Impeller] remove requests for dedicated allocations. (flutter/engine#43686) 2023-07-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 3701605e0abf to d1fcadf22aad (1 revision) (flutter/engine#43692) 2023-07-14 jason-simmons@users.noreply.github.com More fixes for the new clang-tidy roll on iOS targets (flutter/engine#43688) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ee89ad4a0604a..6e0822bbbead5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -63e9cbe7baa3f81c54b39258dc269aa9bba3b57f +2fabf4e5c9eda65ec053ed95a4d92daf291d3f2f From 3132b3a71b92b9a53c0aa52ac4816c82264f0fa4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 18:10:51 -0400 Subject: [PATCH 0169/1547] Roll Flutter Engine from 2fabf4e5c9ed to 21b8e6831be9 (2 revisions) (#130620) https://github.com/flutter/engine/compare/2fabf4e5c9ed...21b8e6831be9 2023-07-14 kjlubick@users.noreply.github.com Remove calls to SkCanvas::flush() (flutter/engine#43684) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from c14fda1cb615 to 315c7f08c731 (3 revisions) (flutter/engine#43700) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6e0822bbbead5..ad48b9573e8c0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2fabf4e5c9eda65ec053ed95a4d92daf291d3f2f +21b8e6831be9de82ce00e3cb7ac7b9cc327ae761 From 5654bfe89a4e090656111b9d83f61a0dad2963d7 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Fri, 14 Jul 2023 15:47:12 -0700 Subject: [PATCH 0170/1547] Remove duplicated dart:ui imports (#130606) Small clean up. A file probably doesn't need multiple way to refer to dart:ui concepts. --- packages/flutter/lib/src/material/animated_icons.dart | 3 +-- .../lib/src/material/animated_icons/animated_icons.dart | 4 ++-- packages/flutter/lib/src/painting/image_provider.dart | 6 ++---- packages/flutter/lib/src/semantics/semantics.dart | 9 ++++----- .../test/animated_icons_private_test.dart.tmpl | 3 +-- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/flutter/lib/src/material/animated_icons.dart b/packages/flutter/lib/src/material/animated_icons.dart index 659c66ba2c6ff..12ae800e750b2 100644 --- a/packages/flutter/lib/src/material/animated_icons.dart +++ b/packages/flutter/lib/src/material/animated_icons.dart @@ -6,8 +6,7 @@ library material_animated_icons; import 'dart:math' as math show pi; -import 'dart:ui' as ui show Canvas, Paint, Path; -import 'dart:ui' show lerpDouble; +import 'dart:ui' as ui show Canvas, Paint, Path, lerpDouble; import 'package:flutter/foundation.dart' show clampDouble; import 'package:flutter/widgets.dart'; diff --git a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart index bc8ea27ac4790..addcf65d47846 100644 --- a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart +++ b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart @@ -196,7 +196,7 @@ class _PathFrames { final List opacities; void paint(ui.Canvas canvas, Color color, _UiPathFactory uiPathFactory, double progress) { - final double opacity = _interpolate(opacities, progress, lerpDouble)!; + final double opacity = _interpolate(opacities, progress, ui.lerpDouble)!; final ui.Paint paint = ui.Paint() ..style = PaintingStyle.fill ..color = color.withOpacity(color.opacity * opacity); @@ -293,7 +293,7 @@ T _interpolate(List values, double progress, _Interpolator interpolator if (values.length == 1) { return values[0]; } - final double targetIdx = lerpDouble(0, values.length -1, progress)!; + final double targetIdx = ui.lerpDouble(0, values.length -1, progress)!; final int lowIdx = targetIdx.floor(); final int highIdx = targetIdx.ceil(); final double t = targetIdx - lowIdx; diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index ebc583fb71eba..cc929d8701aa1 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -6,8 +6,6 @@ import 'dart:async'; import 'dart:io'; import 'dart:math' as math; import 'dart:ui' as ui; -import 'dart:ui' show Locale, Size, TextDirection; - import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; @@ -54,7 +52,7 @@ class ImageConfiguration { ImageConfiguration copyWith({ AssetBundle? bundle, double? devicePixelRatio, - Locale? locale, + ui.Locale? locale, TextDirection? textDirection, Size? size, TargetPlatform? platform, @@ -77,7 +75,7 @@ class ImageConfiguration { final double? devicePixelRatio; /// The language and region for which to select the image. - final Locale? locale; + final ui.Locale? locale; /// The reading direction of the language for which to select the image. final TextDirection? textDirection; diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index cf39779d17061..227ad64680d4c 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -3,8 +3,7 @@ // found in the LICENSE file. import 'dart:math' as math; -import 'dart:ui' as ui; -import 'dart:ui' show Offset, Rect, SemanticsAction, SemanticsFlag, StringAttribute, TextDirection; +import 'dart:ui' show Offset, Rect, SemanticsAction, SemanticsFlag, SemanticsUpdate, SemanticsUpdateBuilder, StringAttribute, TextDirection; import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; @@ -52,7 +51,7 @@ typedef SemanticsActionHandler = void Function(Object? args); /// Signature for a function that receives a semantics update and returns no result. /// /// Used by [SemanticsOwner.onSemanticsUpdate]. -typedef SemanticsUpdateCallback = void Function(ui.SemanticsUpdate update); +typedef SemanticsUpdateCallback = void Function(SemanticsUpdate update); /// Signature for the [SemanticsConfiguration.childConfigurationsDelegate]. /// @@ -2668,7 +2667,7 @@ class SemanticsNode with DiagnosticableTreeMixin { static final Int32List _kEmptyCustomSemanticsActionsList = Int32List(0); static final Float64List _kIdentityTransform = _initIdentityTransform(); - void _addToUpdate(ui.SemanticsUpdateBuilder builder, Set customSemanticsActionIdsUpdate) { + void _addToUpdate(SemanticsUpdateBuilder builder, Set customSemanticsActionIdsUpdate) { assert(_dirty); final SemanticsData data = getSemanticsData(); final Int32List childrenInTraversalOrder; @@ -3288,7 +3287,7 @@ class SemanticsOwner extends ChangeNotifier { } } visitedNodes.sort((SemanticsNode a, SemanticsNode b) => a.depth - b.depth); - final ui.SemanticsUpdateBuilder builder = SemanticsBinding.instance.createSemanticsUpdateBuilder(); + final SemanticsUpdateBuilder builder = SemanticsBinding.instance.createSemanticsUpdateBuilder(); for (final SemanticsNode node in visitedNodes) { assert(node.parent?._dirty != true); // could be null (no parent) or false (not dirty) // The _serialize() method marks the node as not dirty, and diff --git a/packages/flutter/test_private/test/animated_icons_private_test.dart.tmpl b/packages/flutter/test_private/test/animated_icons_private_test.dart.tmpl index af1d2c43368a6..5e0205daafdf0 100644 --- a/packages/flutter/test_private/test/animated_icons_private_test.dart.tmpl +++ b/packages/flutter/test_private/test/animated_icons_private_test.dart.tmpl @@ -12,8 +12,7 @@ library material_animated_icons; import 'dart:math' as math show pi; -import 'dart:ui' show Offset, lerpDouble; -import 'dart:ui' as ui show Canvas, Paint, Path; +import 'dart:ui' as ui show Canvas, Paint, Path, lerpDouble; import 'package:flutter/foundation.dart' show clampDouble; import 'package:flutter/widgets.dart'; From 86726cde7b07965539cbc0bac319cffa17315c2a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 18:54:59 -0400 Subject: [PATCH 0171/1547] Roll Flutter Engine from 21b8e6831be9 to 403866d16137 (2 revisions) (#130626) https://github.com/flutter/engine/compare/21b8e6831be9...403866d16137 2023-07-14 jonahwilliams@google.com [Impeller] defer construction of VkCommandBuffer until encoding begins. (flutter/engine#43605) 2023-07-14 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from LZPMbHnVPFdbXndcX... to DEENqWMCYI1SMYsYH... (flutter/engine#43702) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from LZPMbHnVPFdb to DEENqWMCYI1S If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ad48b9573e8c0..2758653c3dfc6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -21b8e6831be9de82ce00e3cb7ac7b9cc327ae761 +403866d16137bacd1ad69b7665df0c72f109521e diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index eb21e465df060..a78c73eefbda2 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -LZPMbHnVPFdbXndcXVTMyrYiv-0ooqPmxW2FSTAilQgC +DEENqWMCYI1SMYsYHT19t95MMYnCDspQKVWozpxeehQC From 7064b4e935b7fbecc50f1b77b4b4365c6213900a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Jul 2023 23:00:50 +0000 Subject: [PATCH 0172/1547] Bump github/codeql-action from 2.2.9 to 2.20.4 (#130618) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.2.9 to 2.20.4.
Release notes

Sourced from github/codeql-action's releases.

CodeQL Bundle

Bundles CodeQL CLI v2.14.0

Includes the following CodeQL language packs from github/codeql@codeql-cli/v2.14.0:

CodeQL Bundle

Bundles CodeQL CLI v2.13.5

Includes the following CodeQL language packs from github/codeql@codeql-cli/v2.13.5:

CodeQL Bundle

Bundles CodeQL CLI v2.13.4

Includes the following CodeQL language packs from github/codeql@codeql-cli/v2.13.4:

... (truncated)

Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

[UNRELEASED]

No user facing changes.

See the releases page for the relevant changes to the CodeQL CLI and language packs.

2.20.4 - 14 Jul 2023

  • This is the last release of the Action that supports CodeQL CLI versions 2.8.5 to 2.9.3. These versions of the CodeQL CLI were deprecated on June 20, 2023 alongside GitHub Enterprise Server 3.5 and will not be supported by the next release of the CodeQL Action (2.21.0).
    • If you are using one of these versions, please update to CodeQL CLI version 2.9.4 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
    • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.8.5 and 2.9.3, you can replace 'github/codeql-action/@​v2' by 'github/codeql-action/@​v2.20.4' in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
  • We are rolling out a feature in July 2023 that will slightly reduce the default amount of RAM used for query execution, in proportion to the runner's total memory. This will help to avoid out-of-memory failures on larger runners. #1760
  • Update default CodeQL bundle version to 2.14.0. #1762

2.20.3 - 06 Jul 2023

  • Update default CodeQL bundle version to 2.13.5. #1743

2.20.2 - 03 Jul 2023

No user facing changes.

2.20.1 - 21 Jun 2023

  • Update default CodeQL bundle version to 2.13.4. #1721
  • Experimental: add a new resolve-environment action which attempts to infer a configuration for the build environment that is required to build a given project. Do not use this in production as it is part of an internal experiment and subject to change at any time.

2.20.0 - 13 Jun 2023

  • Bump the version of the Action to 2.20.0. This ensures that users who received a Dependabot upgrade to cdcdbb5, which was mistakenly marked as Action version 2.13.4, continue to receive updates to the CodeQL Action. Full details in #1729

2.3.6 - 01 Jun 2023

  • Update default CodeQL bundle version to 2.13.3. #1698

2.3.5 - 25 May 2023

  • Allow invalid URIs to be used as values to artifactLocation.uri properties. This reverses a change from #1668 that inadvertently led to stricter validation of some URI values. #1705
  • Gracefully handle invalid URIs when fingerprinting. #1694

2.3.4 - 24 May 2023

  • Updated the SARIF 2.1.0 JSON schema file to the latest from oasis-tcs/sarif-spec. #1668
  • We are rolling out a feature in May 2023 that will disable Python dependency installation for new users of the CodeQL Action. This improves the speed of analysis while having only a very minor impact on results. #1676
  • We are improving the way that CodeQL bundles are tagged to make it possible to easily identify bundles by their CodeQL semantic version. #1682
    • As of CodeQL CLI 2.13.4, CodeQL bundles will be tagged using semantic versions, for example codeql-bundle-v2.13.4, instead of timestamps, like codeql-bundle-20230615.
    • This change does not affect the majority of workflows, and we will not be changing tags for existing bundle releases.
    • Some workflows with custom logic that depends on the specific format of the CodeQL bundle tag may need to be updated. For example, if your workflow matches CodeQL bundle tag names against a codeql-bundle-yyyymmdd pattern, you should update it to also recognize codeql-bundle-vx.y.z tags.

... (truncated)

Commits
  • 489225d Merge pull request #1777 from github/update-v2.20.4-a148c5807
  • 1b6383d Update changelog for v2.20.4
  • a148c58 Merge pull request #1776 from github/aeisenberg/changelog-releases
  • 50527c5 Add link to releases page in changelog
  • 814b2ed Merge pull request #1762 from github/update-bundle/codeql-bundle-v2.14.0
  • d2baed4 Merge branch 'main' into update-bundle/codeql-bundle-v2.14.0
  • c552617 Merge pull request #1774 from github/dependabot/npm_and_yarn/npm-a34e423e98
  • c1f4958 Fix dependency incompatibilities
  • 40a500c Update checked-in dependencies
  • 4fad06f Bump the npm group with 21 updates
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.2.9&new-version=2.20.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 31e4e434b4244..abdcaa9ce7f12 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@04df1262e6247151b5ac09cd2c303ac36ad3f62b + uses: github/codeql-action/upload-sarif@489225d82a57396c6f426a40e66d461b16b3461d with: sarif_file: results.sarif From fa5869a4624a3b4c504c871a55626def6fc28693 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 14 Jul 2023 16:01:50 -0700 Subject: [PATCH 0173/1547] Clarify docs on WidgetsBindingObserver (#130621) Fixes https://github.com/flutter/flutter/issues/56102 --- packages/flutter/lib/src/widgets/binding.dart | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index e085542bc077d..8750f0ef24072 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -26,25 +26,33 @@ export 'dart:ui' show AppLifecycleState, Locale; /// Interface for classes that register with the Widgets layer binding. /// -/// When used as a mixin, provides no-op method implementations. +/// This can be used by any class, not just widgets. It provides an interface +/// which is used by [WidgetsBinding.addObserver] and +/// [WidgetsBinding.removeObserver] to notify objects of changes in the +/// environment, such as changes to the device metrics or accessibility +/// settings. It is used to implement features such as [MediaQuery]. /// -/// See [WidgetsBinding.addObserver] and [WidgetsBinding.removeObserver]. +/// This class can be extended directly, or mixed in, to get default behaviors +/// for all of the handlers. Alternatively it can can be used with the +/// `implements` keyword, in which case all the handlers must be implemented +/// (and the analyzer will list those that have been omitted). /// -/// This class can be extended directly, to get default behaviors for all of the -/// handlers, or can used with the `implements` keyword, in which case all the -/// handlers must be implemented (and the analyzer will list those that have -/// been omitted). +/// To start receiving notifications, call `WidgetsBinding.instance.addObserver` +/// with a reference to the object implementing the [WidgetsBindingObserver] +/// interface. To avoid memory leaks, call +/// `WidgetsBinding.instance.removeObserver` to unregister the object when it +/// reaches the end of its lifecycle. /// /// {@tool dartpad} /// This sample shows how to implement parts of the [State] and /// [WidgetsBindingObserver] protocols necessary to react to application /// lifecycle messages. See [didChangeAppLifecycleState]. /// +/// To respond to other notifications, replace the [didChangeAppLifecycleState] +/// method in this example with other methods from this class. +/// /// ** See code in examples/api/lib/widgets/binding/widget_binding_observer.0.dart ** /// {@end-tool} -/// -/// To respond to other notifications, replace the [didChangeAppLifecycleState] -/// method above with other methods from this class. abstract mixin class WidgetsBindingObserver { /// Called when the system tells the app to pop the current route. /// For example, on Android, this is called when the user presses From a47c0803cfeb353d306600841b3a901efa35b3a4 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 14 Jul 2023 16:37:10 -0700 Subject: [PATCH 0174/1547] Consistency in dependOnInheritedWidgetOfExactType guidance (#130632) Fixes https://github.com/flutter/flutter/issues/47067 --- packages/flutter/lib/src/widgets/framework.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index c6d8f056fd430..2331ea9d31d09 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -993,7 +993,7 @@ abstract class State with Diagnosticable { /// /// {@endtemplate} /// - /// You cannot use [BuildContext.dependOnInheritedWidgetOfExactType] from this + /// You should not use [BuildContext.dependOnInheritedWidgetOfExactType] from this /// method. However, [didChangeDependencies] will be called immediately /// following this method, and [BuildContext.dependOnInheritedWidgetOfExactType] can /// be used there. @@ -2240,7 +2240,8 @@ abstract class BuildContext { /// again if the inherited value were to change. To ensure that the widget /// correctly updates itself when the inherited value changes, only call this /// (directly or indirectly) from build methods, layout and paint callbacks, - /// or from [State.didChangeDependencies]. + /// or from [State.didChangeDependencies] (which is called immediately after + /// [State.initState]). /// /// This method should not be called from [State.dispose] because the element /// tree is no longer stable at that time. To refer to an ancestor from that From 4d7bffe7f5607d0d84cfc0c67c1aaadc3f7b9a95 Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:52:49 -0700 Subject: [PATCH 0175/1547] Remove use_emulator flag (#130634) MInor cleanup to remove the use_emulator flag as adding the virtual device is enough to signal use of an emulator. Land after https://flutter-review.googlesource.com/c/recipes/+/47341 *List which issues are fixed by this PR. You must list at least one issue.* Fixes https://github.com/flutter/flutter/issues/130522 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 101192113356a..fc1cb7bf1048f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1588,7 +1588,6 @@ targets: [ {"dependency": "android_virtual_device", "version": "33"} ] - use_emulator: "true" - name: Linux_android android_obfuscate_test recipe: devicelab/devicelab_drone From 366615973a6519f56686f5cf07bdd71ea7a42729 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 20:19:31 -0400 Subject: [PATCH 0176/1547] Roll Flutter Engine from 403866d16137 to bf6d4bfe27cc (5 revisions) (#130643) https://github.com/flutter/engine/compare/403866d16137...bf6d4bfe27cc 2023-07-14 dnfield@google.com [Impeller] Fix text scaling issues again, this time with perspective when a save layer is involved (flutter/engine#43695) 2023-07-14 flar@google.com Reland "add non-rendering operation culling to DisplayListBuilder" (#41463) (flutter/engine#43698) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 5f6578398870 to 271b2b6d5aaa (2 revisions) (flutter/engine#43706) 2023-07-14 jonahwilliams@google.com [Impeller] Ensure that missing color attachment 0u does not cause crash in embedder API (flutter/engine#43705) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 315c7f08c731 to 5f6578398870 (4 revisions) (flutter/engine#43704) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2758653c3dfc6..115bd941caeec 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -403866d16137bacd1ad69b7665df0c72f109521e +bf6d4bfe27cca6e6189382d17e5d371162492a27 From 127b7c8b0573f8feab1e15db65ab76f0368a2aeb Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 14 Jul 2023 19:04:05 -0700 Subject: [PATCH 0177/1547] Upgrade leak_tacker and other packages. (#130585) --- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 8 +++----- dev/integration_tests/android_views/pubspec.yaml | 7 +++---- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- dev/integration_tests/hybrid_android_views/pubspec.yaml | 7 +++---- packages/flutter/pubspec.yaml | 4 ++-- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 2e02625c749d2..995328458fdbc 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -18,7 +18,6 @@ dependencies: collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" ffi: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http: 0.13.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,13 +25,12 @@ dependencies: path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_android: 2.0.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -40,7 +38,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -50,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 7bba +# PUBSPEC CHECKSUM: e075 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index db69bfbdfbc40..92b24ab097ad6 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -31,13 +31,12 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -50,7 +49,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -94,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ae09 +# PUBSPEC CHECKSUM: d1b7 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 39c869617dd3a..cc8ca6da0a32c 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_ios: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_linux: 3.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_macos: 3.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_macos: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_platform_interface: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_web: 2.0.18 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_windows: 3.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 9c04 +# PUBSPEC CHECKSUM: 2205 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index e80ef4b34860c..eafd3366ce822 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -29,13 +29,12 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_android: 2.0.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,7 +47,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -92,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ae09 +# PUBSPEC CHECKSUM: d1b7 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 903a71153caef..bb188d46228e7 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 8.0.0 + leak_tracker: 8.0.1 leak_tracker_testing: 1.0.2 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c3ef +# PUBSPEC CHECKSUM: cdf0 From 5e5b0263c3394e78a548dac6137580d3698b83bc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 14 Jul 2023 22:07:25 -0400 Subject: [PATCH 0178/1547] Roll Flutter Engine from bf6d4bfe27cc to 85af5cedf0a7 (1 revision) (#130646) https://github.com/flutter/engine/compare/bf6d4bfe27cc...85af5cedf0a7 2023-07-14 yjbanov@google.com [web] always add secondary role managers (flutter/engine#43663) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 115bd941caeec..b7267e79908c2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bf6d4bfe27cca6e6189382d17e5d371162492a27 +85af5cedf0a7bbb3702c742da61d8ddb56b67e1a From f842ed916514879fe6898b2a5a4053c63c3308fe Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Sat, 15 Jul 2023 09:18:23 -0700 Subject: [PATCH 0179/1547] Reverts "Roll Flutter Engine from bf6d4bfe27cc to 85af5cedf0a7 (1 revision) (#130646)" (#130660) Reverting engine rolls for test failure in https://ci.chromium.org/ui/p/flutter/builders/prod/Linux_android%20hybrid_android_views_integration_test/8517/overview --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b7267e79908c2..2758653c3dfc6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -85af5cedf0a7bbb3702c742da61d8ddb56b67e1a +403866d16137bacd1ad69b7665df0c72f109521e From 4f437d4765de0c9d5f8948ceab28722d92c8f283 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 15 Jul 2023 18:27:42 -0400 Subject: [PATCH 0180/1547] Manual roll Flutter Engine from 403866d16137 to 683087731feb (16 revisions) (#130666) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/403866d16137...683087731feb 2023-07-15 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from DEENqWMCYI1SMYsYH... to rmzZN2ZAgpbjAFi5_... (flutter/engine#43722) 2023-07-15 zanderso@users.noreply.github.com Revert "Reland "add non-rendering operation culling to DisplayListBuilder" (#41463)" (flutter/engine#43721) 2023-07-15 skia-flutter-autoroll@skia.org Roll Clang from 6d667d4b261e to ebd0b8a0472b (flutter/engine#43673) 2023-07-15 skia-flutter-autoroll@skia.org Roll Dart SDK from 671bbdf6c542 to 0bd185c282d2 (1 revision) (flutter/engine#43719) 2023-07-15 26625149+0xZOne@users.noreply.github.com Optimizing performance by avoiding multiple GC operations caused by multiple surface destruction notifications (flutter/engine#43587) 2023-07-15 skia-flutter-autoroll@skia.org Roll Skia from 975eb1250431 to 6fb535aede4e (1 revision) (flutter/engine#43716) 2023-07-15 skia-flutter-autoroll@skia.org Roll Dart SDK from d1fcadf22aad to 671bbdf6c542 (2 revisions) (flutter/engine#43715) 2023-07-15 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Z-1lzZAOYHvVrdjQ8... to oeYLDNShuD-FTgGwU... (flutter/engine#43714) 2023-07-15 skia-flutter-autoroll@skia.org Roll Skia from 271b2b6d5aaa to 975eb1250431 (2 revisions) (flutter/engine#43712) 2023-07-15 goderbauer@google.com Move ViewConfiguration ownership to FlutterView (flutter/engine#43701) 2023-07-14 yjbanov@google.com [web] always add secondary role managers (flutter/engine#43663) 2023-07-14 dnfield@google.com [Impeller] Fix text scaling issues again, this time with perspective when a save layer is involved (flutter/engine#43695) 2023-07-14 flar@google.com Reland "add non-rendering operation culling to DisplayListBuilder" (#41463) (flutter/engine#43698) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 5f6578398870 to 271b2b6d5aaa (2 revisions) (flutter/engine#43706) 2023-07-14 jonahwilliams@google.com [Impeller] Ensure that missing color attachment 0u does not cause crash in embedder API (flutter/engine#43705) 2023-07-14 skia-flutter-autoroll@skia.org Roll Skia from 315c7f08c731 to 5f6578398870 (4 revisions) (flutter/engine#43704) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from DEENqWMCYI1S to rmzZN2ZAgpbj fuchsia/sdk/core/mac-amd64 from Z-1lzZAOYHvV to oeYLDNShuD-F If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2758653c3dfc6..01a99c5f7aac4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -403866d16137bacd1ad69b7665df0c72f109521e +683087731feb6a8c236b8c5224c2b7a2167e1dff diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index a78c73eefbda2..b8ce2840a7bbc 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -DEENqWMCYI1SMYsYHT19t95MMYnCDspQKVWozpxeehQC +rmzZN2ZAgpbjAFi5_CFO_m00MGyay1RhXb6hWI3qKQcC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 0b217311b7953..5dfca8b04282b 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Z-1lzZAOYHvVrdjQ8BvAyXjjPHDVMAdLAAxqb4caxGQC +oeYLDNShuD-FTgGwUslapBKTerxUBlDZtVqgt6L8pIYC From a1db2fe3bf33c74199e8a136b6c03e8fe081ab37 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Sun, 16 Jul 2023 16:39:20 -0700 Subject: [PATCH 0181/1547] Update list of CoC contacts. (#130630) --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b24b7393fe543..86f1ec710e107 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -15,7 +15,7 @@ Specifically: Should you experience anything that makes you feel unwelcome in Flutter's community, please contact [conduct@flutter.dev](mailto:conduct@flutter.dev) or, if you prefer, directly contact someone on the project, for instance -[Hixie](mailto:ian@hixie.ch) or [Tim](mailto:timsneath@google.com). +[Hixie](mailto:ian@hixie.ch). The Flutter project will not tolerate harassment in Flutter's community, even outside of Flutter's public communication channels. From 5a866a031f6d7b81c1f9abafa6efdd0c3ad36f8f Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Sun, 16 Jul 2023 17:36:30 -0700 Subject: [PATCH 0182/1547] Clarify the whole "CustomPainters default to Size.zero" thing. (#130624) Fixes https://github.com/flutter/flutter/issues/52707 --- packages/flutter/lib/src/widgets/basic.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 655b3e875ea93..100f68d584af6 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -600,11 +600,13 @@ class BackdropFilter extends SingleChildRenderObjectWidget { /// `setState` or `markNeedsLayout` during the callback (the layout for this /// frame has already happened). /// -/// Custom painters normally size themselves to their child. If they do not have -/// a child, they attempt to size themselves to the [size], which defaults to -/// [Size.zero]. [size] must not be null. +/// Custom painters normally size themselves to their [child]. If they do not +/// have a child, they attempt to size themselves to the specified [size], which +/// defaults to [Size.zero]. The parent [may enforce constraints on this +/// size](https://docs.flutter.dev/ui/layout/constraints). /// -/// [isComplex] and [willChange] are hints to the compositor's raster cache. +/// The [isComplex] and [willChange] properties are hints to the compositor's +/// raster cache. /// /// {@tool snippet} /// From f4da09626ef0985b30e37cdaeef2da6c2022b006 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Mon, 17 Jul 2023 01:07:10 -0700 Subject: [PATCH 0183/1547] Update `DropdownMenu`, `SnackBarTheme` and `Stepper` tests for M2/M3 (#130464) Updated unit tests for `DropdownMenu`, `SnackBarTheme` and `Stepper` to have M2 and M3 versions. More info in #127064 --- .../test/material/dropdown_menu_test.dart | 117 +++++++++- .../test/material/snack_bar_theme_test.dart | 45 +++- .../flutter/test/material/stepper_test.dart | 214 +++++++++++++++--- 3 files changed, 331 insertions(+), 45 deletions(-) diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 6642efd227863..d61d1764a8227 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -5,6 +5,7 @@ import 'dart:ui'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -109,11 +110,10 @@ void main() { expect(updatedMenuMaterial, findsNothing); }); - testWidgets('The width of the text field should always be the same as the menu view', + testWidgets('Material2 - The width of the text field should always be the same as the menu view', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: false); - final bool useMaterial3 = themeData.useMaterial3; await tester.pumpWidget( MaterialApp( theme: themeData, @@ -129,7 +129,7 @@ void main() { final Finder textField = find.byType(TextField); final Size anchorSize = tester.getSize(textField); - expect(anchorSize, useMaterial3 ? const Size(195.0, 60.0) : const Size(180.0, 56.0)); + expect(anchorSize, const Size(180.0, 56.0)); await tester.tap(find.byType(DropdownMenu)); await tester.pumpAndSettle(); @@ -139,7 +139,7 @@ void main() { matching: find.byType(Material), ); final Size menuSize = tester.getSize(menuMaterial); - expect(menuSize, useMaterial3 ? const Size(195.0, 304.0) : const Size(180.0, 304.0)); + expect(menuSize, const Size(180.0, 304.0)); // The text field should have same width as the menu // when the width property is not null. @@ -147,7 +147,64 @@ void main() { final Finder anchor = find.byType(TextField); final Size size = tester.getSize(anchor); - expect(size, useMaterial3 ? const Size(200.0, 60.0) : const Size(200.0, 56.0)); + expect(size, const Size(200.0, 56.0)); + + await tester.tap(anchor); + await tester.pumpAndSettle(); + + final Finder updatedMenu = find.ancestor( + of: find.byType(SingleChildScrollView), + matching: find.byType(Material), + ); + final Size updatedMenuSize = tester.getSize(updatedMenu); + expect(updatedMenuSize, const Size(200.0, 304.0)); + }); + + testWidgets('Material3 - The width of the text field should always be the same as the menu view', + (WidgetTester tester) async { + final ThemeData themeData = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + body: SafeArea( + child: DropdownMenu( + dropdownMenuEntries: menuChildren, + ), + ), + ), + ) + ); + + final Finder textField = find.byType(TextField); + final Size anchorSize = tester.getSize(textField); + if (kIsWeb && !isCanvasKit) { + expect(anchorSize, const Size(195.0, 61.0)); + } else { + expect(anchorSize, const Size(195.0, 60.0)); + } + + await tester.tap(find.byType(DropdownMenu)); + await tester.pumpAndSettle(); + + final Finder menuMaterial = find.ancestor( + of: find.byType(SingleChildScrollView), + matching: find.byType(Material), + ); + final Size menuSize = tester.getSize(menuMaterial); + expect(menuSize, const Size(195.0, 304.0)); + + // The text field should have same width as the menu + // when the width property is not null. + await tester.pumpWidget(buildTest(themeData, menuChildren, width: 200.0)); + + final Finder anchor = find.byType(TextField); + final Size size = tester.getSize(anchor); + if (kIsWeb && !isCanvasKit) { + expect(size, const Size(200.0, 61.0)); + } else { + expect(size, const Size(200.0, 60.0)); + } await tester.tap(anchor); await tester.pumpAndSettle(); @@ -280,10 +337,9 @@ void main() { expect(buttonSize.width, parentWidth - 35.0 - 20.0); }); - testWidgets('The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list', + testWidgets('Material2 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list', (WidgetTester tester) async { - final ThemeData themeData = ThemeData(); - final bool material3 = themeData.useMaterial3; + final ThemeData themeData = ThemeData(useMaterial3: false); await tester.pumpWidget(buildTest(themeData, menuChildren)); await tester.tap(find.byType(DropdownMenu)); @@ -303,7 +359,7 @@ void main() { matching: find.byType(Padding), ).first; final Size menuViewSize = tester.getSize(menuView); - expect(menuViewSize, material3 ? const Size(195.0, 304.0) : const Size(180.0, 304.0)); // 304 = 288 + vertical padding(2 * 8) + expect(menuViewSize, const Size(180.0, 304.0)); // 304 = 288 + vertical padding(2 * 8) // Constrains the menu height. await tester.pumpWidget(Container()); @@ -319,9 +375,50 @@ void main() { ).first; final Size updatedMenuSize = tester.getSize(updatedMenu); - expect(updatedMenuSize, material3 ? const Size(195.0, 100.0) : const Size(180.0, 100.0)); + expect(updatedMenuSize, const Size(180.0, 100.0)); }); + testWidgets('Material3 - The menuHeight property can be used to show a shorter scrollable menu list instead of the complete list', + (WidgetTester tester) async { + final ThemeData themeData = ThemeData(useMaterial3: true); + await tester.pumpWidget(buildTest(themeData, menuChildren)); + + await tester.tap(find.byType(DropdownMenu)); + await tester.pumpAndSettle(); + + final Element firstItem = tester.element(find.widgetWithText(MenuItemButton, 'Item 0').last); + final RenderBox firstBox = firstItem.renderObject! as RenderBox; + final Offset topLeft = firstBox.localToGlobal(firstBox.size.topLeft(Offset.zero)); + final Element lastItem = tester.element(find.widgetWithText(MenuItemButton, 'Item 5').last); + final RenderBox lastBox = lastItem.renderObject! as RenderBox; + final Offset bottomRight = lastBox.localToGlobal(lastBox.size.bottomRight(Offset.zero)); + // height = height of MenuItemButton * 6 = 48 * 6 + expect(bottomRight.dy - topLeft.dy, 288.0); + + final Finder menuView = find.ancestor( + of: find.byType(SingleChildScrollView), + matching: find.byType(Padding), + ).first; + final Size menuViewSize = tester.getSize(menuView); + expect(menuViewSize, const Size(195.0, 304.0)); // 304 = 288 + vertical padding(2 * 8) + + // Constrains the menu height. + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildTest(themeData, menuChildren, menuHeight: 100)); + await tester.pumpAndSettle(); + + await tester.tap(find.byType(DropdownMenu)); + await tester.pumpAndSettle(); + + final Finder updatedMenu = find.ancestor( + of: find.byType(SingleChildScrollView), + matching: find.byType(Padding), + ).first; + + final Size updatedMenuSize = tester.getSize(updatedMenu); + expect(updatedMenuSize, const Size(195.0, 100.0)); +}); + testWidgets('The text in the menu button should be aligned with the text of ' 'the text field - LTR', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); diff --git a/packages/flutter/test/material/snack_bar_theme_test.dart b/packages/flutter/test/material/snack_bar_theme_test.dart index be25edd2d5a95..c84df3b78cf22 100644 --- a/packages/flutter/test/material/snack_bar_theme_test.dart +++ b/packages/flutter/test/material/snack_bar_theme_test.dart @@ -96,10 +96,43 @@ void main() { ]); }); - testWidgets('Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { + testWidgets('Material2 - Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { const String text = 'I am a snack bar.'; - final ThemeData theme = ThemeData(); - final bool material3 = theme.useMaterial3; + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text(text), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + )); + }, + child: const Text('X'), + ); + }, + ), + ), + )); + + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final Material material = _getSnackBarMaterial(tester); + final RenderParagraph content = _getSnackBarTextRenderObject(tester, text); + + expect(content.text.style, Typography.material2018().white.titleMedium); + expect(material.color, const Color(0xFF333333)); + expect(material.elevation, 6.0); + expect(material.shape, null); + }); + + testWidgets('Material3 - Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { + const String text = 'I am a snack bar.'; + final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, home: Scaffold( @@ -126,10 +159,8 @@ void main() { final Material material = _getSnackBarMaterial(tester); final RenderParagraph content = _getSnackBarTextRenderObject(tester, text); - expect(content.text.style, material3 - ? Typography.material2021().englishLike.bodyMedium?.merge(Typography.material2021().black.bodyMedium).copyWith(color: theme.colorScheme.onInverseSurface, decorationColor: theme.colorScheme.onSurface) - : Typography.material2018().white.titleMedium); - expect(material.color, material3 ? theme.colorScheme.inverseSurface : const Color(0xFF333333)); + expect(content.text.style, Typography.material2021().englishLike.bodyMedium?.merge(Typography.material2021().black.bodyMedium).copyWith(color: theme.colorScheme.onInverseSurface, decorationColor: theme.colorScheme.onSurface)); + expect(material.color, theme.colorScheme.inverseSurface); expect(material.elevation, 6.0); expect(material.shape, null); }); diff --git a/packages/flutter/test/material/stepper_test.dart b/packages/flutter/test/material/stepper_test.dart index d85070b607b4f..e89a8efec1c18 100644 --- a/packages/flutter/test/material/stepper_test.dart +++ b/packages/flutter/test/material/stepper_test.dart @@ -214,15 +214,57 @@ void main() { expect(find.text('B'), findsOneWidget); }); - testWidgets('Stepper button test', (WidgetTester tester) async { + testWidgets('Material2 - Stepper button test', (WidgetTester tester) async { bool continuePressed = false; bool cancelPressed = false; - final ThemeData theme = ThemeData(); - final bool material3 = theme.useMaterial3; await tester.pumpWidget( MaterialApp( - theme: theme, + theme: ThemeData(useMaterial3: false), + home: Material( + child: Stepper( + type: StepperType.horizontal, + onStepContinue: () { + continuePressed = true; + }, + onStepCancel: () { + cancelPressed = true; + }, + steps: const [ + Step( + title: Text('Step 1'), + content: SizedBox( + width: 100.0, + height: 100.0, + ), + ), + Step( + title: Text('Step 2'), + content: SizedBox( + width: 200.0, + height: 200.0, + ), + ), + ], + ), + ), + ), + ); + + await tester.tap(find.text('CONTINUE')); + await tester.tap(find.text('CANCEL')); + + expect(continuePressed, isTrue); + expect(cancelPressed, isTrue); + }); + + testWidgets('Material3 - Stepper button test', (WidgetTester tester) async { + bool continuePressed = false; + bool cancelPressed = false; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), home: Material( child: Stepper( type: StepperType.horizontal, @@ -253,8 +295,8 @@ void main() { ), ); - await tester.tap(find.text(material3 ? 'Continue' : 'CONTINUE')); - await tester.tap(find.text(material3 ? 'Cancel' : 'CANCEL')); + await tester.tap(find.text('Continue')); + await tester.tap(find.text('Cancel')); expect(continuePressed, isTrue); expect(cancelPressed, isTrue); @@ -833,7 +875,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(tester.takeException(), isNull); }); - testWidgets('Stepper enabled button styles', (WidgetTester tester) async { + testWidgets('Material2 - Stepper enabled button styles', (WidgetTester tester) async { Widget buildFrame(ThemeData theme) { return MaterialApp( theme: theme, @@ -861,15 +903,14 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async const OutlinedBorder buttonShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2))); - final ThemeData themeLight = ThemeData.light(); - final bool material3Light = themeLight.useMaterial3; + final ThemeData themeLight = ThemeData(useMaterial3: false); await tester.pumpWidget(buildFrame(themeLight)); - final String continueStr = material3Light ? 'Continue' : 'CONTINUE'; - final String cancelStr = material3Light ? 'Cancel' : 'CANCEL'; - final Rect continueButtonRect = material3Light ? const Rect.fromLTRB(24.0, 212.0, 169.0, 260.0) : const Rect.fromLTRB(24.0, 212.0, 168.0, 260.0); - final Rect cancelButtonRect = material3Light ? const Rect.fromLTRB(177.0, 212.0, 294.0, 260.0) : const Rect.fromLTRB(176.0, 212.0, 292.0, 260.0); - expect(buttonMaterial(continueStr).color!.value, material3Light ? themeLight.colorScheme.primary.value : 0xff2196f3); + const String continueStr = 'CONTINUE'; + const String cancelStr = 'CANCEL'; + const Rect continueButtonRect = Rect.fromLTRB(24.0, 212.0, 168.0, 260.0); + const Rect cancelButtonRect = Rect.fromLTRB(176.0, 212.0, 292.0, 260.0); + expect(buttonMaterial(continueStr).color!.value, 0xff2196f3); expect(buttonMaterial(continueStr).textStyle!.color!.value, 0xffffffff); expect(buttonMaterial(continueStr).shape, buttonShape); expect(tester.getRect(find.widgetWithText(TextButton, continueStr)), continueButtonRect); @@ -879,13 +920,12 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(buttonMaterial(cancelStr).shape, buttonShape); expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); - final ThemeData themeDark = ThemeData.dark(); - final bool material3Dark = themeDark.useMaterial3; + final ThemeData themeDark = ThemeData.dark(useMaterial3: false); await tester.pumpWidget(buildFrame(themeDark)); await tester.pumpAndSettle(); // Complete the theme animation. expect(buttonMaterial(continueStr).color!.value, 0); - expect(buttonMaterial(continueStr).textStyle!.color!.value, material3Dark ? themeDark.colorScheme.onSurface.value : 0xffffffff); + expect(buttonMaterial(continueStr).textStyle!.color!.value, 0xffffffff); expect(buttonMaterial(continueStr).shape, buttonShape); expect(tester.getRect(find.widgetWithText(TextButton, continueStr)), continueButtonRect); @@ -895,13 +935,15 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); }); - testWidgets('Stepper disabled button styles', (WidgetTester tester) async { + testWidgets('Material3 - Stepper enabled button styles', (WidgetTester tester) async { Widget buildFrame(ThemeData theme) { return MaterialApp( theme: theme, home: Material( child: Stepper( type: StepperType.horizontal, + onStepCancel: () { }, + onStepContinue: () { }, steps: const [ Step( title: Text('step1'), @@ -919,28 +961,144 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async ); } - final ThemeData themeLight = ThemeData.light(); - final bool material3Light = themeLight.useMaterial3; + const OutlinedBorder buttonShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2))); + + final ThemeData themeLight = ThemeData(useMaterial3: true); await tester.pumpWidget(buildFrame(themeLight)); - final String continueStr = material3Light ? 'Continue' : 'CONTINUE'; - final String cancelStr = material3Light ? 'Cancel' : 'CANCEL'; + const String continueStr = 'Continue'; + const String cancelStr = 'Cancel'; + const Rect continueButtonRect = Rect.fromLTRB(24.0, 212.0, 169.0, 260.0); + const Rect cancelButtonRect = Rect.fromLTRB(177.0, 212.0, 294.0, 260.0); + expect(buttonMaterial(continueStr).color!.value, themeLight.colorScheme.primary.value); + expect(buttonMaterial(continueStr).textStyle!.color!.value, 0xffffffff); + expect(buttonMaterial(continueStr).shape, buttonShape); + expect(tester.getRect(find.widgetWithText(TextButton, continueStr)), continueButtonRect); + + expect(buttonMaterial(cancelStr).color!.value, 0); + expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0x8a000000); + expect(buttonMaterial(cancelStr).shape, buttonShape); + expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); + + final ThemeData themeDark = ThemeData.dark(useMaterial3: true); + await tester.pumpWidget(buildFrame(themeDark)); + await tester.pumpAndSettle(); // Complete the theme animation. + expect(buttonMaterial(continueStr).color!.value, 0); - expect(buttonMaterial(continueStr).textStyle!.color!.value, material3Light ? themeLight.colorScheme.onSurface.withOpacity(0.38).value : 0x61000000); + expect(buttonMaterial(continueStr).textStyle!.color!.value, themeDark.colorScheme.onSurface.value); + expect(buttonMaterial(continueStr).shape, buttonShape); + expect(tester.getRect(find.widgetWithText(TextButton, continueStr)), continueButtonRect); expect(buttonMaterial(cancelStr).color!.value, 0); - expect(buttonMaterial(cancelStr).textStyle!.color!.value, material3Light ? themeLight.colorScheme.onSurface.withOpacity(0.38).value : 0x61000000); + expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0xb3ffffff); + expect(buttonMaterial(cancelStr).shape, buttonShape); + expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); + }); - final ThemeData themeDark = ThemeData.dark(); - final bool material3Dark = themeDark.useMaterial3; + testWidgets('Material2 - Stepper disabled button styles', (WidgetTester tester) async { + Widget buildFrame(ThemeData theme) { + return MaterialApp( + theme: theme, + home: Material( + child: Stepper( + type: StepperType.horizontal, + steps: const [ + Step( + title: Text('step1'), + content: SizedBox(width: 100, height: 100), + ), + ], + ), + ), + ); + } + + Material buttonMaterial(String label) { + return tester.widget( + find.descendant(of: find.widgetWithText(TextButton, label), matching: find.byType(Material)), + ); + } + + final ThemeData themeLight = ThemeData(useMaterial3: false); + await tester.pumpWidget(buildFrame(themeLight)); + + const String continueStr = 'CONTINUE'; + const String cancelStr = 'CANCEL'; + expect(buttonMaterial(continueStr).color!.value, 0); + expect(buttonMaterial(continueStr).textStyle!.color!.value, 0x61000000); + + expect(buttonMaterial(cancelStr).color!.value, 0); + expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0x61000000); + + final ThemeData themeDark = ThemeData.dark(useMaterial3: false); await tester.pumpWidget(buildFrame(themeDark)); await tester.pumpAndSettle(); // Complete the theme animation. expect(buttonMaterial(continueStr).color!.value, 0); - expect(buttonMaterial(continueStr).textStyle!.color!.value, material3Dark ? themeDark.colorScheme.onSurface.withOpacity(0.38).value : 0x61ffffff); + expect(buttonMaterial(continueStr).textStyle!.color!.value, 0x61ffffff); expect(buttonMaterial(cancelStr).color!.value, 0); - expect(buttonMaterial(cancelStr).textStyle!.color!.value, material3Dark ? themeDark.colorScheme.onSurface.withOpacity(0.38).value : 0x61ffffff); + expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0x61ffffff); + }); + + testWidgets('Material3 - Stepper disabled button styles', (WidgetTester tester) async { + Widget buildFrame(ThemeData theme) { + return MaterialApp( + theme: theme, + home: Material( + child: Stepper( + type: StepperType.horizontal, + steps: const [ + Step( + title: Text('step1'), + content: SizedBox(width: 100, height: 100), + ), + ], + ), + ), + ); + } + + Material buttonMaterial(String label) { + return tester.widget( + find.descendant(of: find.widgetWithText(TextButton, label), matching: find.byType(Material)), + ); + } + + final ThemeData themeLight = ThemeData(useMaterial3: true); + final ColorScheme colorsLight = themeLight.colorScheme; + await tester.pumpWidget(buildFrame(themeLight)); + + const String continueStr = 'Continue'; + const String cancelStr = 'Cancel'; + expect(buttonMaterial(continueStr).color!.value, 0); + expect( + buttonMaterial(continueStr).textStyle!.color!.value, + colorsLight.onSurface.withOpacity(0.38).value, + ); + + expect(buttonMaterial(cancelStr).color!.value, 0); + expect( + buttonMaterial(cancelStr).textStyle!.color!.value, + colorsLight.onSurface.withOpacity(0.38).value, + ); + + final ThemeData themeDark = ThemeData.dark(useMaterial3: true); + final ColorScheme colorsDark = themeDark.colorScheme; + await tester.pumpWidget(buildFrame(themeDark)); + await tester.pumpAndSettle(); // Complete the theme animation. + + expect(buttonMaterial(continueStr).color!.value, 0); + expect( + buttonMaterial(continueStr).textStyle!.color!.value, + colorsDark.onSurface.withOpacity(0.38).value, + ); + + expect(buttonMaterial(cancelStr).color!.value, 0); + expect( + buttonMaterial(cancelStr).textStyle!.color!.value, + colorsDark.onSurface.withOpacity(0.38).value, + ); }); testWidgets('Vertical and Horizontal Stepper physics test', (WidgetTester tester) async { From a6187d9a926935ec926055bf8dbf766b1655b3d2 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 17 Jul 2023 11:08:51 +0300 Subject: [PATCH 0184/1547] Fix `DatePicker` uses incorrect overlay color from `DatePickerTheme` and add missing tests (#130584) fixes [YearPickerState in calendar_date_picker is using dayOverlayColor instead of yearOverlayColor](https://github.com/flutter/flutter/issues/130051) ### Description - Fix year selection uses incorrect overlay color from `DatePickerTheme` - Update defaults tests to check for overlay color for different modes - Add tests to check overlay color is resolved. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( datePickerTheme: const DatePickerThemeData( yearOverlayColor: MaterialStatePropertyAll(Colors.green), dayOverlayColor: MaterialStatePropertyAll(Colors.amber), ), useMaterial3: true, ), home: Directionality( textDirection: TextDirection.ltr, child: Material( child: Center( child: DatePickerDialog( initialDate: DateTime(2023, DateTime.january, 25), firstDate: DateTime(2022), lastDate: DateTime(2024, DateTime.december, 31), currentDate: DateTime(2023, DateTime.january, 24), ), ), ), ), ); } } ```
```dart yearOverlayColor: MaterialStatePropertyAll(Colors.green), dayOverlayColor: MaterialStatePropertyAll(Colors.red), ``` ### Before ![Screenshot 2023-07-14 at 18 39 51](https://github.com/flutter/flutter/assets/48603081/52ec5096-bad6-4753-9e9a-15b6d5ce767e) ### After ![Screenshot 2023-07-14 at 18 38 32](https://github.com/flutter/flutter/assets/48603081/a51aeca8-a5c2-42b4-8c05-b55f9955e860) --- .../src/material/calendar_date_picker.dart | 2 +- .../test/material/date_picker_theme_test.dart | 282 ++++++++++++++++++ 2 files changed, 283 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 641ad3ba5e124..3bdddf3a57677 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -1191,7 +1191,7 @@ class _YearPickerState extends State { final Color? background = resolve((DatePickerThemeData? theme) => isCurrentYear ? theme?.todayBackgroundColor : theme?.yearBackgroundColor, states); final MaterialStateProperty overlayColor = MaterialStateProperty.resolveWith((Set states) => - effectiveValue((DatePickerThemeData? theme) => theme?.dayOverlayColor?.resolve(states)), + effectiveValue((DatePickerThemeData? theme) => theme?.yearOverlayColor?.resolve(states)), ); BoxBorder? border; diff --git a/packages/flutter/test/material/date_picker_theme_test.dart b/packages/flutter/test/material/date_picker_theme_test.dart index 191c6faa3aa37..681591cf8aa6c 100644 --- a/packages/flutter/test/material/date_picker_theme_test.dart +++ b/packages/flutter/test/material/date_picker_theme_test.dart @@ -3,9 +3,13 @@ // found in the LICENSE file. import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../rendering/mock_canvas.dart'; + void main() { const DatePickerThemeData datePickerTheme = DatePickerThemeData( backgroundColor: Color(0xfffffff0), @@ -389,6 +393,16 @@ void main() { expect(day24Decoration.border?.top.width, datePickerTheme.todayBorder?.width); expect(day24Decoration.border?.bottom.width, datePickerTheme.todayBorder?.width); + // Test the day overlay color. + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.text('25'))); + await tester.pumpAndSettle(); + expect(inkFeatures, paints..circle(color: datePickerTheme.dayOverlayColor?.resolve({}))); + // Show the year selector. await tester.tap(find.text('January 2023')); @@ -409,6 +423,11 @@ void main() { expect(year2023Decoration.border?.bottom.width, datePickerTheme.todayBorder?.width); expect(year2023Decoration.border?.top.color, datePickerTheme.todayForegroundColor?.resolve({})); expect(year2023Decoration.border?.bottom.color, datePickerTheme.todayForegroundColor?.resolve({})); + + // Test the year overlay color. + await gesture.moveTo(tester.getCenter(find.text('2024'))); + await tester.pumpAndSettle(); + expect(inkFeatures, paints..rect(color: datePickerTheme.yearOverlayColor?.resolve({}))); }); testWidgets('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async { @@ -496,6 +515,21 @@ void main() { final Text selectedDate = tester.widget(find.text('Jan 17')); expect(selectedDate.style?.color, datePickerTheme.rangePickerHeaderForegroundColor); expect(selectedDate.style?.fontSize, datePickerTheme.rangePickerHeaderHeadlineStyle?.fontSize); + + // Test the day overlay color. + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.text('16'))); + await tester.pumpAndSettle(); + expect(inkFeatures, paints..circle(color: datePickerTheme.dayOverlayColor?.resolve({}))); + + // Test the range selection overlay color. + await gesture.moveTo(tester.getCenter(find.text('18'))); + await tester.pumpAndSettle(); + expect(inkFeatures, paints..circle(color: datePickerTheme.rangeSelectionOverlayColor?.resolve({}))); }); testWidgets('Dividers use DatePickerThemeData.dividerColor', (WidgetTester tester) async { @@ -594,4 +628,252 @@ void main() { expect(inputDecoration.fillColor, const Color(0xFF00FF00)); expect(inputDecoration.border , const OutlineInputBorder()); }); + + testWidgets('DatePickerDialog resolves DatePickerTheme.dayOverlayColor states', (WidgetTester tester) async { + final MaterialStateProperty dayOverlayColor = MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered)) { + return const Color(0xff00ff00); + } + if (states.contains(MaterialState.focused)) { + return const Color(0xffff00ff); + } + if (states.contains(MaterialState.pressed)) { + return const Color(0xffffff00); + } + return Colors.transparent; + }); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + datePickerTheme: DatePickerThemeData( + dayOverlayColor: dayOverlayColor, + ), + useMaterial3: true, + ), + home: Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: Focus( + child: DatePickerDialog( + initialDate: DateTime(2023, DateTime.january, 25), + firstDate: DateTime(2022), + lastDate: DateTime(2024, DateTime.december, 31), + currentDate: DateTime(2023, DateTime.january, 24), + ), + ), + ), + ), + ), + ), + ); + + // Test the hover overlay color. + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.text('20'))); + await tester.pumpAndSettle(); + expect( + inkFeatures, + paints + ..circle(color: dayOverlayColor.resolve({MaterialState.hovered})), + ); + + // Test the pressed overlay color. + await gesture.down(tester.getCenter(find.text('20'))); + await tester.pumpAndSettle(); + if (kIsWeb) { + // An extra circle is painted on the web for the hovered state. + expect( + inkFeatures, + paints + ..circle(color: dayOverlayColor.resolve({MaterialState.hovered})) + ..circle(color: dayOverlayColor.resolve({MaterialState.hovered})) + ..circle(color: dayOverlayColor.resolve({MaterialState.pressed})), + ); + } else { + expect( + inkFeatures, + paints + ..circle(color: dayOverlayColor.resolve({MaterialState.hovered})) + ..circle(color: dayOverlayColor.resolve({MaterialState.pressed})), + ); + } + + await gesture.removePointer(); + await tester.pumpAndSettle(); + + // Focus day selection. + for (int i = 0; i < 5; i++) { + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pumpAndSettle(); + } + + // Test the focused overlay color. + expect( + inkFeatures, + paints + ..circle(color: dayOverlayColor.resolve({MaterialState.focused})), + ); + }); + + testWidgets('DatePickerDialog resolves DatePickerTheme.yearOverlayColor states', (WidgetTester tester) async { + final MaterialStateProperty yearOverlayColor = MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered)) { + return const Color(0xff00ff00); + } + if (states.contains(MaterialState.focused)) { + return const Color(0xffff00ff); + } + if (states.contains(MaterialState.pressed)) { + return const Color(0xffffff00); + } + return Colors.transparent; + }); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + datePickerTheme: DatePickerThemeData( + yearOverlayColor: yearOverlayColor, + ), + useMaterial3: true, + ), + home: Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: Focus( + child: DatePickerDialog( + initialDate: DateTime(2023, DateTime.january, 25), + firstDate: DateTime(2022), + lastDate: DateTime(2024, DateTime.december, 31), + currentDate: DateTime(2023, DateTime.january, 24), + initialCalendarMode: DatePickerMode.year, + ), + ), + ), + ), + ), + ), + ); + + // Test the hover overlay color. + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.text('2022'))); + await tester.pumpAndSettle(); + expect( + inkFeatures, + paints + ..rect(color: yearOverlayColor.resolve({MaterialState.hovered})), + ); + + // Test the pressed overlay color. + await gesture.down(tester.getCenter(find.text('2022'))); + await tester.pumpAndSettle(); + expect( + inkFeatures, + paints + ..rect(color: yearOverlayColor.resolve({MaterialState.hovered})) + ..rect(color: yearOverlayColor.resolve({MaterialState.pressed})), + ); + + await gesture.removePointer(); + await tester.pumpAndSettle(); + + // Focus year selection. + for (int i = 0; i < 3; i++) { + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pumpAndSettle(); + } + + // Test the focused overlay color. + expect( + inkFeatures, + paints + ..rect(color: yearOverlayColor.resolve({MaterialState.focused})), + ); + }); + + testWidgets('DateRangePickerDialog resolves DatePickerTheme.rangeSelectionOverlayColor states', (WidgetTester tester) async { + final MaterialStateProperty rangeSelectionOverlayColor = MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered)) { + return const Color(0xff00ff00); + } + if (states.contains(MaterialState.pressed)) { + return const Color(0xffffff00); + } + return Colors.transparent; + }); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + datePickerTheme: DatePickerThemeData( + rangeSelectionOverlayColor: rangeSelectionOverlayColor, + ), + useMaterial3: true, + ), + home: Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: DateRangePickerDialog( + firstDate: DateTime(2023), + lastDate: DateTime(2023, DateTime.january, 31), + initialDateRange: DateTimeRange( + start: DateTime(2023, DateTime.january, 17), + end: DateTime(2023, DateTime.january, 20), + ), + currentDate: DateTime(2023, DateTime.january, 23), + ), + ), + ), + ), + ), + ); + + // Test the hover overlay color. + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + final TestGesture gesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.text('18'))); + await tester.pumpAndSettle(); + expect( + inkFeatures, + paints + ..circle(color: rangeSelectionOverlayColor.resolve({MaterialState.hovered})), + ); + + // Test the pressed overlay color. + await gesture.down(tester.getCenter(find.text('18'))); + await tester.pumpAndSettle(); + if (kIsWeb) { + // An extra circle is painted on the web for the hovered state. + expect( + inkFeatures, + paints + ..circle(color: rangeSelectionOverlayColor.resolve({MaterialState.hovered})) + ..circle(color: rangeSelectionOverlayColor.resolve({MaterialState.hovered})) + ..circle(color: rangeSelectionOverlayColor.resolve({MaterialState.pressed})), + ); + } else { + expect( + inkFeatures, + paints + ..circle(color: rangeSelectionOverlayColor.resolve({MaterialState.hovered})) + ..circle(color: rangeSelectionOverlayColor.resolve({MaterialState.pressed})), + ); + } + }); } From 3a1190a5a85c3e6a0cf3a9c30f34548fdd48ac1e Mon Sep 17 00:00:00 2001 From: Pavel Mazhnik Date: Mon, 17 Jul 2023 11:42:13 +0300 Subject: [PATCH 0185/1547] [flutter_tools] Support coverage collection for dependencies (#129513) PR provides a new option to the `test` command to include coverage info of specified packages. It helps collecting coverage info in test setups where test code lives in separate packages or for multi-package projects. At present, only current package is included to the final report. Usage: Consider an app with two packages: `app`, `common`. Some of the tests in `app` use (indirectly) code that is located in `common`. When running with `--coverage` flag, that code is not included in the coverage report by default. To include `common` package in report, we can run: ```sh flutter test --coverage --coverage-package app --coverage-package common ``` Note that `--coverage-package` accepts regular expression. Fixes https://github.com/flutter/flutter/issues/79661 Fixes https://github.com/flutter/flutter/issues/101486 Fixes https://github.com/flutter/flutter/issues/93619 --- .../flutter_tools/lib/src/commands/test.dart | 40 ++++- .../lib/src/test/coverage_collector.dart | 9 +- .../commands.shard/hermetic/test_test.dart | 164 +++++++++++++++++- .../coverage_collector_test.dart | 49 ++++++ 4 files changed, 257 insertions(+), 5 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index 8bd076edcd5d1..16864daee6bef 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:meta/meta.dart'; +import 'package:package_config/package_config_types.dart'; import '../asset.dart'; import '../base/common.dart'; @@ -131,6 +132,13 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { defaultsTo: 'coverage/lcov.info', help: 'Where to store coverage information (if coverage is enabled).', ) + ..addMultiOption('coverage-package', + help: 'A regular expression matching packages names ' + 'to include in the coverage report (if coverage is enabled). ' + 'If unset, matches the current package name.', + valueHelp: 'package-name-regexp', + splitCommas: false, + ) ..addFlag('machine', hide: !verboseHelp, negatable: false, @@ -395,10 +403,14 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { CoverageCollector? collector; if (boolArg('coverage') || boolArg('merge-coverage') || boolArg('branch-coverage')) { - final String projectName = flutterProject.manifest.appName; + final Set packagesToInclude = _getCoveragePackages( + stringsArg('coverage-package'), + flutterProject, + buildInfo.packageConfig, + ); collector = CoverageCollector( verbose: !machine, - libraryNames: {projectName}, + libraryNames: packagesToInclude, packagesPath: buildInfo.packagesPath, resolver: await CoverageCollector.getResolver(buildInfo.packagesPath), testTimeRecorder: testTimeRecorder, @@ -508,6 +520,30 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { return FlutterCommandResult.success(); } + Set _getCoveragePackages( + List packagesRegExps, + FlutterProject flutterProject, + PackageConfig packageConfig, + ) { + final String projectName = flutterProject.manifest.appName; + final Set packagesToInclude = { + if (packagesRegExps.isEmpty) projectName, + }; + try { + for (final String regExpStr in packagesRegExps) { + final RegExp regExp = RegExp(regExpStr); + packagesToInclude.addAll( + packageConfig.packages + .map((Package e) => e.name) + .where((String e) => regExp.hasMatch(e)), + ); + } + } on FormatException catch (e) { + throwToolExit('Regular expression syntax is invalid. $e'); + } + return packagesToInclude; + } + /// Parses a test file/directory target passed as an argument and returns it /// as an absolute file:/// [URI] with optional querystring for name/line/col. Uri _parseTestArgument(String arg) { diff --git a/packages/flutter_tools/lib/src/test/coverage_collector.dart b/packages/flutter_tools/lib/src/test/coverage_collector.dart index 1881fb6473fb0..48a5da2596df5 100644 --- a/packages/flutter_tools/lib/src/test/coverage_collector.dart +++ b/packages/flutter_tools/lib/src/test/coverage_collector.dart @@ -187,8 +187,13 @@ class CoverageCollector extends TestWatcher { if (formatter == null) { final coverage.Resolver usedResolver = resolver ?? this.resolver ?? await CoverageCollector.getResolver(packagesPath); final String packagePath = globals.fs.currentDirectory.path; - final List reportOn = coverageDirectory == null - ? [globals.fs.path.join(packagePath, 'lib')] + // find paths for libraryNames so we can include them to report + final List? libraryPaths = libraryNames + ?.map((String e) => usedResolver.resolve('package:$e')) + .whereType() + .toList(); + final List? reportOn = coverageDirectory == null + ? libraryPaths : [coverageDirectory.path]; formatter = (Map hitmap) => hitmap .formatLcov(usedResolver, reportOn: reportOn, basePath: packagePath); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart index 2c8d81e6e47aa..c0da0c933adee 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -16,14 +16,19 @@ import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; +import 'package:flutter_tools/src/test/coverage_collector.dart'; import 'package:flutter_tools/src/test/runner.dart'; +import 'package:flutter_tools/src/test/test_device.dart'; import 'package:flutter_tools/src/test/test_time_recorder.dart'; import 'package:flutter_tools/src/test/test_wrapper.dart'; import 'package:flutter_tools/src/test/watcher.dart'; +import 'package:stream_channel/stream_channel.dart'; +import 'package:vm_service/vm_service.dart'; import '../../src/common.dart'; import '../../src/context.dart'; import '../../src/fake_devices.dart'; +import '../../src/fake_vm_services.dart'; import '../../src/logging_logger.dart'; import '../../src/test_flutter_command_runner.dart'; @@ -249,6 +254,137 @@ dev_dependencies: Cache: () => Cache.test(processManager: FakeProcessManager.any()), }); + testUsingContext('Coverage provides current library name to Coverage Collector by default', () async { + const String currentPackageName = ''; + final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( + requests: [ + FakeVmServiceRequest( + method: 'getVM', + jsonResponse: (VM.parse({})! + ..isolates = [ + IsolateRef.parse({ + 'id': '1', + })!, + ] + ).toJson(), + ), + FakeVmServiceRequest( + method: 'getVersion', + jsonResponse: Version(major: 3, minor: 57).toJson(), + ), + FakeVmServiceRequest( + method: 'getSourceReport', + args: { + 'isolateId': '1', + 'reports': ['Coverage'], + 'forceCompile': true, + 'reportLines': true, + 'libraryFilters': ['package:$currentPackageName/'], + }, + jsonResponse: SourceReport( + ranges: [], + ).toJson(), + ), + ], + ); + final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0, null, fakeVmServiceHost); + + final TestCommand testCommand = TestCommand(testRunner: testRunner); + final CommandRunner commandRunner = + createTestCommandRunner(testCommand); + await commandRunner.run(const [ + 'test', + '--no-pub', + '--coverage', + '--', + 'test/some_test.dart', + ]); + expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect( + (testRunner.lastTestWatcher! as CoverageCollector).libraryNames, + {currentPackageName}, + ); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + Cache: () => Cache.test(processManager: FakeProcessManager.any()), + }); + + testUsingContext('Coverage provides library names matching regexps to Coverage Collector', () async { + final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( + requests: [ + FakeVmServiceRequest( + method: 'getVM', + jsonResponse: (VM.parse({})! + ..isolates = [ + IsolateRef.parse({ + 'id': '1', + })!, + ] + ).toJson(), + ), + FakeVmServiceRequest( + method: 'getVersion', + jsonResponse: Version(major: 3, minor: 57).toJson(), + ), + FakeVmServiceRequest( + method: 'getSourceReport', + args: { + 'isolateId': '1', + 'reports': ['Coverage'], + 'forceCompile': true, + 'reportLines': true, + 'libraryFilters': ['package:test_api/'], + }, + jsonResponse: SourceReport( + ranges: [], + ).toJson(), + ), + ], + ); + final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0, null, fakeVmServiceHost); + + final TestCommand testCommand = TestCommand(testRunner: testRunner); + final CommandRunner commandRunner = + createTestCommandRunner(testCommand); + await commandRunner.run(const [ + 'test', + '--no-pub', + '--coverage', + '--coverage-package=^test', + '--', + 'test/some_test.dart', + ]); + expect(fakeVmServiceHost.hasRemainingExpectations, false); + expect( + (testRunner.lastTestWatcher! as CoverageCollector).libraryNames, + {'test_api'}, + ); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + Cache: () => Cache.test(processManager: FakeProcessManager.any()), + }); + + testUsingContext('Coverage provides error message if regular expression syntax is invalid', () async { + final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0); + + final TestCommand testCommand = TestCommand(testRunner: testRunner); + final CommandRunner commandRunner = createTestCommandRunner(testCommand); + + expect(() => commandRunner.run(const [ + 'test', + '--no-pub', + '--coverage', + r'--coverage-package="$+"', + '--', + 'test/some_test.dart', + ]), throwsToolExit(message: RegExp(r'Regular expression syntax is invalid. FormatException: Nothing to repeat[ \t]*"\$\+"'))); + }, overrides: { + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + }); + testUsingContext('Pipes start-paused to package:test', () async { final FakePackageTest fakePackageTest = FakePackageTest(); @@ -864,7 +1000,7 @@ dev_dependencies: } class FakeFlutterTestRunner implements FlutterTestRunner { - FakeFlutterTestRunner(this.exitCode, [this.leastRunTime]); + FakeFlutterTestRunner(this.exitCode, [this.leastRunTime, this.fakeVmServiceHost]); int exitCode; Duration? leastRunTime; @@ -873,6 +1009,8 @@ class FakeFlutterTestRunner implements FlutterTestRunner { String? lastFileReporterValue; String? lastReporterOption; int? lastConcurrency; + TestWatcher? lastTestWatcher; + FakeVmServiceHost? fakeVmServiceHost; @override Future runTests( @@ -912,15 +1050,39 @@ class FakeFlutterTestRunner implements FlutterTestRunner { lastFileReporterValue = fileReporter; lastReporterOption = reporter; lastConcurrency = concurrency; + lastTestWatcher = watcher; if (leastRunTime != null) { await Future.delayed(leastRunTime!); } + if (watcher is CoverageCollector) { + await watcher.collectCoverage( + TestTestDevice(), + serviceOverride: fakeVmServiceHost?.vmService, + ); + } + return exitCode; } } +class TestTestDevice extends TestDevice { + @override + Future get finished => Future.delayed(const Duration(seconds: 1)); + + @override + Future kill() => Future.value(); + + @override + Future get vmServiceUri => Future.value(Uri()); + + @override + Future> start(String entrypointPath) { + throw UnimplementedError(); + } +} + class FakePackageTest implements TestWrapper { List? lastArgs; diff --git a/packages/flutter_tools/test/general.shard/coverage_collector_test.dart b/packages/flutter_tools/test/general.shard/coverage_collector_test.dart index be5792e5b85f1..9ecce507434e3 100644 --- a/packages/flutter_tools/test/general.shard/coverage_collector_test.dart +++ b/packages/flutter_tools/test/general.shard/coverage_collector_test.dart @@ -6,6 +6,8 @@ import 'dart:convert' show jsonEncode; import 'dart:io' show Directory, File; import 'package:coverage/src/hitmap.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/base/file_system.dart' show FileSystem; import 'package:flutter_tools/src/test/coverage_collector.dart'; import 'package:flutter_tools/src/test/test_device.dart' show TestDevice; import 'package:flutter_tools/src/test/test_time_recorder.dart'; @@ -13,6 +15,7 @@ import 'package:stream_channel/stream_channel.dart' show StreamChannel; import 'package:vm_service/vm_service.dart'; import '../src/common.dart'; +import '../src/context.dart'; import '../src/fake_vm_services.dart'; import '../src/logging_logger.dart'; @@ -515,6 +518,52 @@ void main() { } }); + testUsingContext('Coverage collector respects libraryNames in finalized report', () async { + Directory? tempDir; + try { + tempDir = Directory.systemTemp.createTempSync('flutter_coverage_collector_test.'); + final File packagesFile = writeFooBarPackagesJson(tempDir); + File('${tempDir.path}/foo/foo.dart').createSync(recursive: true); + File('${tempDir.path}/bar/bar.dart').createSync(recursive: true); + + final String packagesPath = packagesFile.path; + CoverageCollector collector = CoverageCollector( + libraryNames: {'foo', 'bar'}, + verbose: false, + packagesPath: packagesPath, + resolver: await CoverageCollector.getResolver(packagesPath) + ); + await collector.collectCoverage( + TestTestDevice(), + serviceOverride: createFakeVmServiceHostWithFooAndBar(libraryFilters: ['package:foo/', 'package:bar/']).vmService, + ); + + String? report = await collector.finalizeCoverage(); + expect(report, contains('foo.dart')); + expect(report, contains('bar.dart')); + + collector = CoverageCollector( + libraryNames: {'foo'}, + verbose: false, + packagesPath: packagesPath, + resolver: await CoverageCollector.getResolver(packagesPath) + ); + await collector.collectCoverage( + TestTestDevice(), + serviceOverride: createFakeVmServiceHostWithFooAndBar(libraryFilters: ['package:foo/']).vmService, + ); + + report = await collector.finalizeCoverage(); + expect(report, contains('foo.dart')); + expect(report, isNot(contains('bar.dart'))); + } finally { + tempDir?.deleteSync(recursive: true); + } + }, overrides: { + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + }); + testWithoutContext('Coverage collector records test timings when provided TestTimeRecorder', () async { Directory? tempDir; try { From 8b2d4e705c0cc6419530e7a9125ecc235cc346cc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 11:15:05 -0400 Subject: [PATCH 0186/1547] Roll Flutter Engine from 683087731feb to e4cae43c9c7a (9 revisions) (#130716) https://github.com/flutter/engine/compare/683087731feb...e4cae43c9c7a 2023-07-16 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 4pmlR2uz3SrLRNNSG... to VYjne_BEm9inQ5fnq... (flutter/engine#43732) 2023-07-16 skia-flutter-autoroll@skia.org Roll Dart SDK from d34f04f4a152 to 827259dfffb9 (1 revision) (flutter/engine#43731) 2023-07-16 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from rmzZN2ZAgpbjAFi5_... to Buo0mx6dVLK5kvgQ3... (flutter/engine#43730) 2023-07-16 chinmaygarde@google.com [Impeller] Fix pipeline stats traced to the timeline. (flutter/engine#43729) 2023-07-15 jonahwilliams@google.com [Impeller] fix some OpenGL Linux desktop issues. (flutter/engine#43727) 2023-07-15 skia-flutter-autoroll@skia.org Roll Skia from 0768501cd267 to ee4369879cc0 (1 revision) (flutter/engine#43728) 2023-07-15 skia-flutter-autoroll@skia.org Roll Skia from 6fb535aede4e to 0768501cd267 (3 revisions) (flutter/engine#43726) 2023-07-15 skia-flutter-autoroll@skia.org Roll Dart SDK from 0bd185c282d2 to d34f04f4a152 (1 revision) (flutter/engine#43724) 2023-07-15 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from oeYLDNShuD-FTgGwU... to 4pmlR2uz3SrLRNNSG... (flutter/engine#43723) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from rmzZN2ZAgpbj to Buo0mx6dVLK5 fuchsia/sdk/core/mac-amd64 from oeYLDNShuD-F to VYjne_BEm9in If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 01a99c5f7aac4..ff16c3f7b21f2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -683087731feb6a8c236b8c5224c2b7a2167e1dff +e4cae43c9c7a61084fe0a5d47c0253413f8da771 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index b8ce2840a7bbc..4bff2ef00e0ca 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -rmzZN2ZAgpbjAFi5_CFO_m00MGyay1RhXb6hWI3qKQcC +Buo0mx6dVLK5kvgQ3U5YTxISQGTsnaPC4axo699B5oEC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 5dfca8b04282b..b68be3cc7ab95 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -oeYLDNShuD-FTgGwUslapBKTerxUBlDZtVqgt6L8pIYC +VYjne_BEm9inQ5fnqh_RhYSoT2s9UYazyEBvyVCzB2QC From 526522d9e5c7c7935de1fbc99fcbb771b18a4390 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 17 Jul 2023 18:16:58 +0300 Subject: [PATCH 0187/1547] [Reland] - Update `DialogTheme` tests for M2/M3 (#130711) This relands https://github.com/flutter/flutter/pull/130414 (which was reverted in https://github.com/flutter/flutter/pull/130578) --- .../test/material/dialog_theme_test.dart | 108 ++++++++++++++---- 1 file changed, 88 insertions(+), 20 deletions(-) diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index f215649d4826c..22c78e3a817e4 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -165,7 +165,31 @@ void main() { expect(bottomLeft.dy, 576.0); }); - testWidgets('Dialog alignment takes priority over theme', (WidgetTester tester) async { + testWidgets('Material3 - Dialog alignment takes priority over theme', (WidgetTester tester) async { + const AlertDialog dialog = AlertDialog( + title: Text('Title'), + actions: [ ], + alignment: Alignment.topRight, + ); + final ThemeData theme = ThemeData( + useMaterial3: true, + dialogTheme: const DialogTheme(alignment: Alignment.bottomLeft), + ); + + await tester.pumpWidget( + _appWithDialog(tester, dialog, theme: theme), + ); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final Offset bottomLeft = tester.getBottomLeft( + find.descendant(of: find.byType(Dialog), matching: find.byType(Material)), + ); + expect(bottomLeft.dx, 480.0); + expect(bottomLeft.dy, 124.0); + }); + + testWidgets('Material2 - Dialog alignment takes priority over theme', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], @@ -186,7 +210,29 @@ void main() { expect(bottomLeft.dy, 104.0); }); - testWidgets('Custom dialog shape matches golden', (WidgetTester tester) async { + testWidgets('Material3 - Custom dialog shape matches golden', (WidgetTester tester) async { + const RoundedRectangleBorder customBorder = + RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); + const AlertDialog dialog = AlertDialog( + title: Text('Title'), + actions: [ ], + ); + final ThemeData theme = ThemeData( + useMaterial3: true, + dialogTheme: const DialogTheme(shape: customBorder), + ); + + await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + await expectLater( + find.byKey(_painterKey), + matchesGoldenFile('m3_dialog_theme.dialog_with_custom_border.png'), + ); + }); + + testWidgets('Material2 - Custom dialog shape matches golden', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -201,7 +247,7 @@ void main() { await expectLater( find.byKey(_painterKey), - matchesGoldenFile('dialog_theme.dialog_with_custom_border.png'), + matchesGoldenFile('m2_dialog_theme.dialog_with_custom_border.png'), ); }); @@ -246,9 +292,8 @@ void main() { expect(text.text.style!.color, dialogThemeColor); }); - testWidgets('Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { - const Color iconThemeColor = Colors.yellow; - final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); + testWidgets('Material3 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: [ ], @@ -260,11 +305,12 @@ void main() { // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); - expect(text.text.style!.color, iconThemeColor); + expect(text.text.style!.color, theme.colorScheme.secondary); }); - testWidgets('Custom Icon Color - Theme - lowest preference for M3', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); + testWidgets('Material2 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + const Color iconThemeColor = Colors.yellow; + final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), actions: [ ], @@ -276,7 +322,7 @@ void main() { // first is Text('X') final RichText text = tester.widget(find.byType(RichText).last); - expect(text.text.style!.color, theme.colorScheme.secondary); + expect(text.text.style!.color, iconThemeColor); }); testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { @@ -313,13 +359,24 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Custom Title Text Style - Theme', (WidgetTester tester) async { + testWidgets('Material3 - Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog( - title: Text(titleText), - actions: [ ], - ); + const AlertDialog dialog = AlertDialog(title: Text(titleText)); + final ThemeData theme = ThemeData(useMaterial3: true, textTheme: const TextTheme(headlineSmall: titleTextStyle)); + + await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final RenderParagraph title = _getTextRenderObject(tester, titleText); + expect(title.text.style!.color, titleTextStyle.color); + }); + + testWidgets('Material2 - Custom Title Text Style - Theme', (WidgetTester tester) async { + const String titleText = 'Title'; + const TextStyle titleTextStyle = TextStyle(color: Colors.pink); + const AlertDialog dialog = AlertDialog(title: Text(titleText)); final ThemeData theme = ThemeData(useMaterial3: false, textTheme: const TextTheme(titleLarge: titleTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); @@ -412,13 +469,24 @@ void main() { expect(content.text.style, contentTextStyle); }); - testWidgets('Custom Content Text Style - Theme', (WidgetTester tester) async { + testWidgets('Material3 - Custom Content Text Style - Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); - const AlertDialog dialog = AlertDialog( - content: Text(contentText), - actions: [ ], - ); + const AlertDialog dialog = AlertDialog(content: Text(contentText),); + final ThemeData theme = ThemeData(useMaterial3: true, textTheme: const TextTheme(bodyMedium: contentTextStyle)); + + await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + final RenderParagraph content = _getTextRenderObject(tester, contentText); + expect(content.text.style!.color, contentTextStyle.color); + }); + + testWidgets('Material2 - Custom Content Text Style - Theme', (WidgetTester tester) async { + const String contentText = 'Content'; + const TextStyle contentTextStyle = TextStyle(color: Colors.pink); + const AlertDialog dialog = AlertDialog(content: Text(contentText)); final ThemeData theme = ThemeData(useMaterial3: false, textTheme: const TextTheme(titleMedium: contentTextStyle)); await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme)); From 6cbc11d63fadb2da6ffa5094b8b09bc498092f8e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 11:53:00 -0400 Subject: [PATCH 0188/1547] Roll Packages from 369ee7e1a1cb to 6889cca8ba78 (5 revisions) (#130721) https://github.com/flutter/packages/compare/369ee7e1a1cb...6889cca8ba78 2023-07-17 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.20.3 to 2.20.4 (flutter/packages#4490) 2023-07-15 stuartmorgan@google.com [ci] Switch Android unit tests to LUCI (flutter/packages#4406) 2023-07-15 stuartmorgan@google.com [ci] Introduce LUCI versions of Linux desktop platform tests (flutter/packages#4223) 2023-07-14 43054281+camsim99@users.noreply.github.com [camerax] Marks all wrapped classes as immutable (flutter/packages#4451) 2023-07-14 47866232+chunhtai@users.noreply.github.com [go_router] Bumps example go_router version and migrate example code (flutter/packages#4469) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index c63b85b36b347..ba82134ddac0b 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -369ee7e1a1cba9cd49421dd12bd1fd6fa69d6b68 +6889cca8ba78c5f2ebffd5f52ba92c54a319cc14 From 7a42ed7ef6ed7404251f0215bda277312d2cd690 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 17 Jul 2023 08:57:08 -0700 Subject: [PATCH 0189/1547] Update to valid build tools variant and update lockfiles (#125825) https://github.com/flutter/flutter/issues/125331 --- .ci.yaml | 2 +- .../android/build.gradle | 2 +- .../android/buildscript-gradle.lockfile | 97 +++++++++---------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 4 files changed, 51 insertions(+), 52 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index fc1cb7bf1048f..b04580a0f8620 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -430,7 +430,7 @@ targets: [] - name: Linux firebase_abstract_method_smoke_test - bringup: true # Flaky https://github.com/flutter/flutter/issues/124691 + bringup: false recipe: firebaselab/firebaselab timeout: 60 properties: diff --git a/dev/integration_tests/abstract_method_smoke_test/android/build.gradle b/dev/integration_tests/abstract_method_smoke_test/android/build.gradle index a2a8866952986..20b59171a855c 100644 --- a/dev/integration_tests/abstract_method_smoke_test/android/build.gradle +++ b/dev/integration_tests/abstract_method_smoke_test/android/build.gradle @@ -14,7 +14,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/dev/integration_tests/abstract_method_smoke_test/android/buildscript-gradle.lockfile b/dev/integration_tests/abstract_method_smoke_test/android/buildscript-gradle.lockfile index eb605802d98f5..135d58bac49a3 100644 --- a/dev/integration_tests/abstract_method_smoke_test/android/buildscript-gradle.lockfile +++ b/dev/integration_tests/abstract_method_smoke_test/android/buildscript-gradle.lockfile @@ -1,45 +1,46 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -androidx.databinding:databinding-common:7.3.0=classpath -androidx.databinding:databinding-compiler-common:7.3.0=classpath -com.android.databinding:baseLibrary:7.3.0=classpath -com.android.tools.analytics-library:crash:30.3.0=classpath -com.android.tools.analytics-library:protos:30.3.0=classpath -com.android.tools.analytics-library:shared:30.3.0=classpath -com.android.tools.analytics-library:tracker:30.3.0=classpath +androidx.databinding:databinding-common:7.4.2=classpath +androidx.databinding:databinding-compiler-common:7.4.2=classpath +com.android.databinding:baseLibrary:7.4.2=classpath +com.android.tools.analytics-library:crash:30.4.2=classpath +com.android.tools.analytics-library:protos:30.4.2=classpath +com.android.tools.analytics-library:shared:30.4.2=classpath +com.android.tools.analytics-library:tracker:30.4.2=classpath com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10=classpath com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10=classpath -com.android.tools.build:aapt2-proto:7.3.0-8691043=classpath -com.android.tools.build:aaptcompiler:7.3.0=classpath -com.android.tools.build:apksig:7.3.0=classpath -com.android.tools.build:apkzlib:7.3.0=classpath -com.android.tools.build:builder-model:7.3.0=classpath -com.android.tools.build:builder-test-api:7.3.0=classpath -com.android.tools.build:builder:7.3.0=classpath -com.android.tools.build:bundletool:1.9.0=classpath -com.android.tools.build:gradle-api:7.3.0=classpath -com.android.tools.build:gradle:7.3.0=classpath -com.android.tools.build:manifest-merger:30.3.0=classpath +com.android.tools.build:aapt2-proto:7.4.2-8841542=classpath +com.android.tools.build:aaptcompiler:7.4.2=classpath +com.android.tools.build:apksig:7.4.2=classpath +com.android.tools.build:apkzlib:7.4.2=classpath +com.android.tools.build:builder-model:7.4.2=classpath +com.android.tools.build:builder-test-api:7.4.2=classpath +com.android.tools.build:builder:7.4.2=classpath +com.android.tools.build:bundletool:1.11.4=classpath +com.android.tools.build:gradle-api:7.4.2=classpath +com.android.tools.build:gradle-settings-api:7.4.2=classpath +com.android.tools.build:gradle:7.4.2=classpath +com.android.tools.build:manifest-merger:30.4.2=classpath com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api=classpath -com.android.tools.ddms:ddmlib:30.3.0=classpath -com.android.tools.layoutlib:layoutlib-api:30.3.0=classpath -com.android.tools.lint:lint-model:30.3.0=classpath -com.android.tools.lint:lint-typedef-remover:30.3.0=classpath -com.android.tools.utp:android-device-provider-ddmlib-proto:30.3.0=classpath -com.android.tools.utp:android-device-provider-gradle-proto:30.3.0=classpath -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:30.3.0=classpath -com.android.tools.utp:android-test-plugin-host-coverage-proto:30.3.0=classpath -com.android.tools.utp:android-test-plugin-host-retention-proto:30.3.0=classpath -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:30.3.0=classpath -com.android.tools:annotations:30.3.0=classpath -com.android.tools:common:30.3.0=classpath -com.android.tools:dvlib:30.3.0=classpath -com.android.tools:repository:30.3.0=classpath -com.android.tools:sdk-common:30.3.0=classpath -com.android.tools:sdklib:30.3.0=classpath -com.android:signflinger:7.3.0=classpath -com.android:zipflinger:7.3.0=classpath +com.android.tools.ddms:ddmlib:30.4.2=classpath +com.android.tools.layoutlib:layoutlib-api:30.4.2=classpath +com.android.tools.lint:lint-model:30.4.2=classpath +com.android.tools.lint:lint-typedef-remover:30.4.2=classpath +com.android.tools.utp:android-device-provider-ddmlib-proto:30.4.2=classpath +com.android.tools.utp:android-device-provider-gradle-proto:30.4.2=classpath +com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:30.4.2=classpath +com.android.tools.utp:android-test-plugin-host-coverage-proto:30.4.2=classpath +com.android.tools.utp:android-test-plugin-host-retention-proto:30.4.2=classpath +com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:30.4.2=classpath +com.android.tools:annotations:30.4.2=classpath +com.android.tools:common:30.4.2=classpath +com.android.tools:dvlib:30.4.2=classpath +com.android.tools:repository:30.4.2=classpath +com.android.tools:sdk-common:30.4.2=classpath +com.android.tools:sdklib:30.4.2=classpath +com.android:signflinger:7.4.2=classpath +com.android:zipflinger:7.4.2=classpath com.github.gundy:semver4j:0.16.4=classpath com.google.android:annotations:4.1.1.4=classpath com.google.api.grpc:proto-google-common-protos:2.0.1=classpath @@ -57,8 +58,7 @@ com.google.j2objc:j2objc-annotations:1.3=classpath com.google.jimfs:jimfs:1.1=classpath com.google.protobuf:protobuf-java-util:3.17.2=classpath com.google.protobuf:protobuf-java:3.17.2=classpath -com.google.testing.platform:core-proto:0.0.8-alpha07=classpath -com.googlecode.json-simple:json-simple:1.1=classpath +com.google.testing.platform:core-proto:0.0.8-alpha08=classpath com.googlecode.juniversalchardet:juniversalchardet:1.0.3=classpath com.squareup:javapoet:1.10.0=classpath com.squareup:javawriter:2.5.0=classpath @@ -87,7 +87,6 @@ io.netty:netty-handler:4.1.52.Final=classpath io.netty:netty-resolver:4.1.52.Final=classpath io.netty:netty-transport:4.1.52.Final=classpath io.perfmark:perfmark-api:0.23.0=classpath -it.unimi.dsi:fastutil:8.4.0=classpath jakarta.activation:jakarta.activation-api:1.2.1=classpath jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=classpath javax.annotation:javax.annotation-api:1.3.2=classpath @@ -123,15 +122,15 @@ org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10=classpath org.jetbrains.kotlin:kotlin-klib-commonizer-api:1.7.10=classpath org.jetbrains.kotlin:kotlin-native-utils:1.7.10=classpath org.jetbrains.kotlin:kotlin-project-model:1.7.10=classpath -org.jetbrains.kotlin:kotlin-reflect:1.5.31=classpath +org.jetbrains.kotlin:kotlin-reflect:1.7.10=classpath org.jetbrains.kotlin:kotlin-scripting-common:1.7.10=classpath org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.7.10=classpath org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.7.10=classpath org.jetbrains.kotlin:kotlin-scripting-jvm:1.7.10=classpath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=classpath +org.jetbrains.kotlin:kotlin-stdlib-common:1.7.10=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.10=classpath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10=classpath +org.jetbrains.kotlin:kotlin-stdlib:1.7.10=classpath org.jetbrains.kotlin:kotlin-tooling-core:1.7.10=classpath org.jetbrains.kotlin:kotlin-tooling-metadata:1.7.10=classpath org.jetbrains.kotlin:kotlin-util-io:1.7.10=classpath @@ -140,11 +139,11 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.0=classpath org.jetbrains:annotations:13.0=classpath org.json:json:20180813=classpath org.jvnet.staxex:stax-ex:1.8.1=classpath -org.ow2.asm:asm-analysis:9.1=classpath -org.ow2.asm:asm-commons:9.1=classpath -org.ow2.asm:asm-tree:9.1=classpath -org.ow2.asm:asm-util:9.1=classpath -org.ow2.asm:asm:9.1=classpath +org.ow2.asm:asm-analysis:9.2=classpath +org.ow2.asm:asm-commons:9.2=classpath +org.ow2.asm:asm-tree:9.2=classpath +org.ow2.asm:asm-util:9.2=classpath +org.ow2.asm:asm:9.2=classpath org.slf4j:slf4j-api:1.7.30=classpath org.tensorflow:tensorflow-lite-metadata:0.1.0-rc2=classpath xerces:xercesImpl:2.12.0=classpath diff --git a/dev/integration_tests/abstract_method_smoke_test/android/gradle/wrapper/gradle-wrapper.properties b/dev/integration_tests/abstract_method_smoke_test/android/gradle/wrapper/gradle-wrapper.properties index cb24abda10ae7..3c472b99c6f35 100644 --- a/dev/integration_tests/abstract_method_smoke_test/android/gradle/wrapper/gradle-wrapper.properties +++ b/dev/integration_tests/abstract_method_smoke_test/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip From 6f09064e785b2bb600a390fe6d8be4ac6775b82b Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 17 Jul 2023 09:14:08 -0700 Subject: [PATCH 0190/1547] Stand-alone widget tree with multiple render trees to enable multi-view rendering (#125003) This change enables Flutter to generate multiple Scenes to be rendered into separate FlutterViews from a single widget tree. Each Scene is described by a separate render tree, which are all associated with the single widget tree. This PR implements the framework-side mechanisms to describe the content to be rendered into multiple views. Separate engine-side changes are necessary to provide these views to the framework and to draw the framework-generated Scene into them. ## Summary of changes The details of this change are described in [flutter.dev/go/multiple-views](https://flutter.dev/go/multiple-views). Below is a high-level summary organized by layers. ### Rendering layer changes * The `RendererBinding` no longer owns a single `renderView`. In fact, it doesn't OWN any `RenderView`s at all anymore. Instead, it offers an API (`addRenderView`/`removeRenderView`) to add and remove `RenderView`s that then will be MANAGED by the binding. The `RenderView` itself is now owned by a higher-level abstraction (e.g. the `RawView` Element of the widgets layer, see below), who is also in charge of adding it to the binding. When added, the binding will interact with the `RenderView` to produce a frame (e.g. by calling `compositeFrame` on it) and to perform hit tests for incoming pointer events. Multiple `RenderView`s can be added to the binding (typically one per `FlutterView`) to produce multiple Scenes. * Instead of owning a single `pipelineOwner`, the `RendererBinding` now owns the root of the `PipelineOwner` tree (exposed as `rootPipelineOwner` on the binding). Each `PipelineOwner` in that tree (except for the root) typically manages its own render tree typically rooted in one of the `RenderView`s mentioned in the previous bullet. During frame production, the binding will instruct each `PipelineOwner` of that tree to flush layout, paint, semantics etc. A higher-level abstraction (e.g. the widgets layer, see below) is in charge of adding `PipelineOwner`s to this tree. * Backwards compatibility: The old `renderView` and `pipelineOwner` properties of the `RendererBinding` are retained, but marked as deprecated. Care has been taken to keep their original behavior for the deprecation period, i.e. if you just call `runApp`, the render tree bootstrapped by this call is rooted in the deprecated `RendererBinding.renderView` and managed by the deprecated `RendererBinding.pipelineOwner`. ### Widgets layer changes * The `WidgetsBinding` no longer attaches the widget tree to an existing render tree. Instead, it bootstraps a stand-alone widget tree that is not backed by a render tree. For this, `RenderObjectToWidgetAdapter` has been replaced by `RootWidget`. * Multiple render trees can be bootstrapped and attached to the widget tree with the help of the `View` widget, which internally is backed by a `RawView` widget. Configured with a `FlutterView` to render into, the `RawView` creates a new `PipelineOwner` and a new `RenderView` for the new render tree. It adds the new `RenderView` to the `RendererBinding` and its `PipelineOwner` to the pipeline owner tree. * The `View` widget can only appear in certain well-defined locations in the widget tree since it bootstraps a new render tree and does not insert a `RenderObject` into an ancestor. However, almost all Elements expect that their children insert `RenderObject`s, otherwise they will not function properly. To produce a good error message when the `View` widget is used in an illegal location, the `debugMustInsertRenderObjectIntoSlot` method has been added to Element, where a child can ask whether a given slot must insert a RenderObject into its ancestor or not. In practice, the `View` widget can be used as a child of the `RootWidget`, inside the `view` slot of the `ViewAnchor` (see below) and inside a `ViewCollection` (see below). In those locations, the `View` widget may be wrapped in other non-RenderObjectWidgets (e.g. InheritedWidgets). * The new `ViewAnchor` can be used to create a side-view inside a parent `View`. The `child` of the `ViewAnchor` widget renders into the parent `View` as usual, but the `view` slot can take on another `View` widget, which has access to all inherited widgets above the `ViewAnchor`. Metaphorically speaking, the view is anchored to the location of the `ViewAnchor` in the widget tree. * The new `ViewCollection` widget allows for multiple sibling views as it takes a list of `View`s as children. It can be used in all the places that accept a `View` widget. ## Google3 As of July 5, 2023 this change passed a TAP global presubmit (TGP) in google3: tap/OCL:544707016:BASE:545809771:1688597935864:e43dd651 ## Note to reviewers This change is big (sorry). I suggest focusing the initial review on the changes inside of `packages/flutter` first. The majority of the changes describe above are implemented in (listed in suggested review order): * `rendering/binding.dart` * `widgets/binding.dart` * `widgets/view.dart` * `widgets/framework.dart` All other changes included in the PR are basically the fallout of what's implemented in those files. Also note that a lot of the lines added in this PR are documentation and tests. I am also very happy to walk reviewers through the code in person or via video call, if that is helpful. I appreciate any feedback. ## Feedback to address before submitting ("TODO") --- .../lib/stocks/layout_bench.dart | 2 +- dev/bots/test.dart | 2 +- .../flutter_gallery/test/smoke_test.dart | 4 +- .../rendering/custom_coordinate_systems.dart | 3 +- examples/layers/rendering/flex_layout.dart | 3 +- examples/layers/rendering/hello_world.dart | 6 +- .../layers/rendering/spinning_square.dart | 4 +- examples/layers/rendering/src/binding.dart | 69 + examples/layers/rendering/touch_input.dart | 4 +- examples/layers/widgets/spinning_mixed.dart | 18 +- .../flutter/lib/src/rendering/binding.dart | 463 +++++-- .../flutter/lib/src/rendering/object.dart | 59 +- packages/flutter/lib/src/rendering/view.dart | 39 +- packages/flutter/lib/src/widgets/adapter.dart | 177 +++ packages/flutter/lib/src/widgets/binding.dart | 175 +-- .../flutter/lib/src/widgets/framework.dart | 202 ++- .../lib/src/widgets/semantics_debugger.dart | 36 +- packages/flutter/lib/src/widgets/view.dart | 664 +++++++++- .../lib/src/widgets/widget_inspector.dart | 3 +- packages/flutter/lib/widgets.dart | 1 + .../foundation/service_extensions_test.dart | 38 +- .../binding_pipeline_manifold_test.dart | 16 +- .../flutter/test/rendering/binding_test.dart | 31 +- .../rendering/mouse_tracker_test_utils.dart | 15 +- .../rendering/multi_view_binding_test.dart | 208 +++ .../rendering/pipeline_owner_tree_test.dart | 63 +- .../test/rendering/platform_view_test.dart | 8 +- .../test/rendering/rendering_tester.dart | 51 +- .../flutter/test/rendering/view_test.dart | 10 + .../test/scheduler/benchmarks_test.dart | 2 +- .../flutter/test/widgets/container_test.dart | 91 +- .../custom_multi_child_layout_test.dart | 5 +- packages/flutter/test/widgets/debug_test.dart | 5 +- .../test/widgets/focus_manager_test.dart | 5 +- .../flutter/test/widgets/init_state_test.dart | 2 +- .../flutter/test/widgets/keep_alive_test.dart | 4 +- .../test/widgets/media_query_test.dart | 36 +- .../test/widgets/multi_view_binding_test.dart | 39 + .../widgets/multi_view_tree_updates_test.dart | 221 ++++ .../slotted_render_object_widget_test.dart | 15 +- .../test/widgets/stateful_component_test.dart | 3 +- .../flutter/test/widgets/tree_shape_test.dart | 1161 +++++++++++++++++ packages/flutter/test/widgets/view_test.dart | 435 +++++- .../test/widgets/widget_inspector_test.dart | 3 +- .../widgets/memory_allocations_test.dart | 2 +- .../lib/src/common/handler_factory.dart | 13 +- .../flutter_test/lib/src/_matchers_web.dart | 4 +- .../flutter_test/lib/src/accessibility.dart | 37 +- packages/flutter_test/lib/src/binding.dart | 135 +- packages/flutter_test/lib/src/controller.dart | 95 +- packages/flutter_test/lib/src/finders.dart | 4 +- .../flutter_test/lib/src/widget_tester.dart | 44 +- .../test/multi_view_accessibility_test.dart | 135 ++ .../test/multi_view_controller_test.dart | 232 ++++ .../flutter_test_config.dart | 6 +- .../test/widget_tester_live_device_test.dart | 4 +- .../lib/integration_test.dart | 17 +- 57 files changed, 4595 insertions(+), 534 deletions(-) create mode 100644 examples/layers/rendering/src/binding.dart create mode 100644 packages/flutter/lib/src/widgets/adapter.dart create mode 100644 packages/flutter/test/rendering/multi_view_binding_test.dart create mode 100644 packages/flutter/test/widgets/multi_view_binding_test.dart create mode 100644 packages/flutter/test/widgets/multi_view_tree_updates_test.dart create mode 100644 packages/flutter/test/widgets/tree_shape_test.dart create mode 100644 packages/flutter_test/test/multi_view_accessibility_test.dart create mode 100644 packages/flutter_test/test/multi_view_controller_test.dart diff --git a/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart b/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart index e42211d594cd7..9d72b87aa3a87 100644 --- a/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart +++ b/dev/benchmarks/microbenchmarks/lib/stocks/layout_bench.dart @@ -39,7 +39,7 @@ Future main() async { size: const Size(355.0, 635.0), view: tester.view, ); - final RenderView renderView = WidgetsBinding.instance.renderView; + final RenderView renderView = WidgetsBinding.instance.renderViews.single; binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmark; watch.start(); diff --git a/dev/bots/test.dart b/dev/bots/test.dart index c994041f7839e..d4aa4e7d232ca 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1361,7 +1361,7 @@ Future _runWebTreeshakeTest() async { final String javaScript = mainDartJs.readAsStringSync(); // Check that we're not looking at minified JS. Otherwise this test would result in false positive. - expect(javaScript.contains('RenderObjectToWidgetElement'), true); + expect(javaScript.contains('RootElement'), true); const String word = 'debugFillProperties'; int count = 0; diff --git a/dev/integration_tests/flutter_gallery/test/smoke_test.dart b/dev/integration_tests/flutter_gallery/test/smoke_test.dart index 98f473880dd5f..cd49804f804b9 100644 --- a/dev/integration_tests/flutter_gallery/test/smoke_test.dart +++ b/dev/integration_tests/flutter_gallery/test/smoke_test.dart @@ -79,8 +79,8 @@ Future smokeDemo(WidgetTester tester, GalleryDemo demo) async { // Verify that the dumps are pretty. final String routeName = demo.routeName; verifyToStringOutput('debugDumpApp', routeName, WidgetsBinding.instance.rootElement!.toStringDeep()); - verifyToStringOutput('debugDumpRenderTree', routeName, RendererBinding.instance.renderView.toStringDeep()); - verifyToStringOutput('debugDumpLayerTree', routeName, RendererBinding.instance.renderView.debugLayer?.toStringDeep() ?? ''); + verifyToStringOutput('debugDumpRenderTree', routeName, RendererBinding.instance.renderViews.single.toStringDeep()); + verifyToStringOutput('debugDumpLayerTree', routeName, RendererBinding.instance.renderViews.single.debugLayer?.toStringDeep() ?? ''); verifyToStringOutput('debugDumpFocusTree', routeName, WidgetsBinding.instance.focusManager.toStringDeep()); // Scroll the demo around a bit more. diff --git a/examples/layers/rendering/custom_coordinate_systems.dart b/examples/layers/rendering/custom_coordinate_systems.dart index 28aa4137892fa..d7fd16186e5d0 100644 --- a/examples/layers/rendering/custom_coordinate_systems.dart +++ b/examples/layers/rendering/custom_coordinate_systems.dart @@ -6,6 +6,7 @@ // system. Most of the guts of this examples are in src/sector_layout.dart. import 'package:flutter/rendering.dart'; +import 'src/binding.dart'; import 'src/sector_layout.dart'; RenderBox buildSectorExample() { @@ -21,5 +22,5 @@ RenderBox buildSectorExample() { } void main() { - RenderingFlutterBinding(root: buildSectorExample()).scheduleFrame(); + ViewRenderingFlutterBinding(root: buildSectorExample()).scheduleFrame(); } diff --git a/examples/layers/rendering/flex_layout.dart b/examples/layers/rendering/flex_layout.dart index 43c29509fc957..845a232fa1819 100644 --- a/examples/layers/rendering/flex_layout.dart +++ b/examples/layers/rendering/flex_layout.dart @@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart'; +import 'src/binding.dart'; import 'src/solid_color_box.dart'; void main() { @@ -86,5 +87,5 @@ void main() { child: RenderPadding(child: table, padding: const EdgeInsets.symmetric(vertical: 50.0)), ); - RenderingFlutterBinding(root: root).scheduleFrame(); + ViewRenderingFlutterBinding(root: root).scheduleFrame(); } diff --git a/examples/layers/rendering/hello_world.dart b/examples/layers/rendering/hello_world.dart index 03b4801e28252..cb49f94d373b2 100644 --- a/examples/layers/rendering/hello_world.dart +++ b/examples/layers/rendering/hello_world.dart @@ -7,9 +7,11 @@ import 'package:flutter/rendering.dart'; +import 'src/binding.dart'; + void main() { - // We use RenderingFlutterBinding to attach the render tree to the window. - RenderingFlutterBinding( + // We use ViewRenderingFlutterBinding to attach the render tree to the window. + ViewRenderingFlutterBinding( // The root of our render tree is a RenderPositionedBox, which centers its // child both vertically and horizontally. root: RenderPositionedBox( diff --git a/examples/layers/rendering/spinning_square.dart b/examples/layers/rendering/spinning_square.dart index 68b1359139304..cb833069fdecc 100644 --- a/examples/layers/rendering/spinning_square.dart +++ b/examples/layers/rendering/spinning_square.dart @@ -11,6 +11,8 @@ import 'package:flutter/animation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; +import 'src/binding.dart'; + class NonStopVSync implements TickerProvider { const NonStopVSync(); @override @@ -42,7 +44,7 @@ void main() { child: spin, ); // and attach it to the window. - RenderingFlutterBinding(root: root); + ViewRenderingFlutterBinding(root: root); // To make the square spin, we use an animation that repeats every 1800 // milliseconds. diff --git a/examples/layers/rendering/src/binding.dart b/examples/layers/rendering/src/binding.dart new file mode 100644 index 0000000000000..ae8cedcc90dde --- /dev/null +++ b/examples/layers/rendering/src/binding.dart @@ -0,0 +1,69 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/rendering.dart'; + +/// An extension of [RenderingFlutterBinding] that owns and manages a +/// [renderView]. +/// +/// Unlike [RenderingFlutterBinding], this binding also creates and owns a +/// [renderView] to simplify bootstrapping for apps that have a dedicated main +/// view. +class ViewRenderingFlutterBinding extends RenderingFlutterBinding { + /// Creates a binding for the rendering layer. + /// + /// The `root` render box is attached directly to the [renderView] and is + /// given constraints that require it to fill the window. The [renderView] + /// itself is attached to the [rootPipelineOwner]. + /// + /// This binding does not automatically schedule any frames. Callers are + /// responsible for deciding when to first call [scheduleFrame]. + ViewRenderingFlutterBinding({ RenderBox? root }) : _root = root; + + @override + void initInstances() { + super.initInstances(); + // TODO(goderbauer): Create window if embedder doesn't provide an implicit view. + assert(PlatformDispatcher.instance.implicitView != null); + _renderView = initRenderView(PlatformDispatcher.instance.implicitView!); + _renderView.child = _root; + _root = null; + } + + RenderBox? _root; + + @override + RenderView get renderView => _renderView; + late RenderView _renderView; + + /// Creates a [RenderView] object to be the root of the + /// [RenderObject] rendering tree, and initializes it so that it + /// will be rendered when the next frame is requested. + /// + /// Called automatically when the binding is created. + RenderView initRenderView(FlutterView view) { + final RenderView renderView = RenderView(view: view); + rootPipelineOwner.rootNode = renderView; + addRenderView(renderView); + renderView.prepareInitialFrame(); + return renderView; + } + + @override + PipelineOwner createRootPipelineOwner() { + return PipelineOwner( + onSemanticsOwnerCreated: () { + renderView.scheduleInitialSemantics(); + }, + onSemanticsUpdate: (SemanticsUpdate update) { + renderView.updateSemantics(update); + }, + onSemanticsOwnerDisposed: () { + renderView.clearSemantics(); + }, + ); + } +} diff --git a/examples/layers/rendering/touch_input.dart b/examples/layers/rendering/touch_input.dart index 3747eb43dfc14..37a944528447d 100644 --- a/examples/layers/rendering/touch_input.dart +++ b/examples/layers/rendering/touch_input.dart @@ -8,6 +8,8 @@ import 'package:flutter/material.dart'; // Imported just for its color palette. import 'package:flutter/rendering.dart'; +import 'src/binding.dart'; + // Material design colors. :p List _kColors = [ Colors.teal, @@ -133,5 +135,5 @@ void main() { ..left = 20.0; // Finally, we attach the render tree we've built to the screen. - RenderingFlutterBinding(root: stack).scheduleFrame(); + ViewRenderingFlutterBinding(root: stack).scheduleFrame(); } diff --git a/examples/layers/widgets/spinning_mixed.dart b/examples/layers/widgets/spinning_mixed.dart index cdde8f7b6e3dd..6d3223c7b0065 100644 --- a/examples/layers/widgets/spinning_mixed.dart +++ b/examples/layers/widgets/spinning_mixed.dart @@ -52,10 +52,10 @@ void attachWidgetTreeToRenderTree(RenderProxyBox container) { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ ElevatedButton( - child: Row( + child: const Row( children: [ - Image.network('https://flutter.dev/images/favicon.png'), - const Text('PRESS ME'), + FlutterLogo(), + Text('PRESS ME'), ], ), onPressed: () { @@ -102,6 +102,16 @@ void main() { transformBox = RenderTransform(child: flexRoot, transform: Matrix4.identity(), alignment: Alignment.center); final RenderPadding root = RenderPadding(padding: const EdgeInsets.all(80.0), child: transformBox); - binding.renderView.child = root; + // TODO(goderbauer): Create a window if embedder doesn't provide an implicit view to draw into. + assert(binding.platformDispatcher.implicitView != null); + final RenderView view = RenderView( + view: binding.platformDispatcher.implicitView!, + child: root, + ); + final PipelineOwner pipelineOwner = PipelineOwner()..rootNode = view; + binding.rootPipelineOwner.adoptChild(pipelineOwner); + binding.addRenderView(view); + view.prepareInitialFrame(); + binding.addPersistentFrameCallback(rotate); } diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index a90e062c42114..8b14588b78db1 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -10,7 +10,6 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter/services.dart'; -import 'box.dart'; import 'debug.dart'; import 'mouse_tracker.dart'; import 'object.dart'; @@ -22,28 +21,34 @@ export 'package:flutter/gestures.dart' show HitTestResult; // Examples can assume: // late BuildContext context; -/// The glue between the render tree and the Flutter engine. +/// The glue between the render trees and the Flutter engine. +/// +/// The [RendererBinding] manages multiple independent render trees. Each render +/// tree is rooted in a [RenderView] that must be added to the binding via +/// [addRenderView] to be considered during frame production, hit testing, etc. +/// Furthermore, the render tree must be managed by a [PipelineOwner] that is +/// part of the pipeline owner tree rooted at [rootPipelineOwner]. +/// +/// Adding [PipelineOwner]s and [RenderView]s to this binding in the way +/// described above is left as a responsibility for a higher level abstraction. +/// The widgets library, for example, introduces the [View] widget, which +/// registers its [RenderView] and [PipelineOwner] with this binding. mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable { @override void initInstances() { super.initInstances(); _instance = this; - _pipelineOwner = PipelineOwner( - onSemanticsOwnerCreated: _handleSemanticsOwnerCreated, - onSemanticsUpdate: _handleSemanticsUpdate, - onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed, - ); + _rootPipelineOwner = createRootPipelineOwner(); platformDispatcher ..onMetricsChanged = handleMetricsChanged ..onTextScaleFactorChanged = handleTextScaleFactorChanged ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged; - initRenderView(); addPersistentFrameCallback(_handlePersistentFrameCallback); initMouseTracker(); if (kIsWeb) { addPostFrameCallback(_handleWebFirstFrame); } - _pipelineOwner.attach(_manifold); + rootPipelineOwner.attach(_manifold); } /// The current [RendererBinding], if one has been created. @@ -108,9 +113,8 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture registerServiceExtension( name: RenderingServiceExtensions.debugDumpLayerTree.name, callback: (Map parameters) async { - final String data = RendererBinding.instance.renderView.debugLayer?.toStringDeep() ?? 'Layer tree unavailable.'; return { - 'data': data, + 'data': _debugCollectLayerTrees(), }; }, ); @@ -155,9 +159,8 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture registerServiceExtension( name: RenderingServiceExtensions.debugDumpRenderTree.name, callback: (Map parameters) async { - final String data = RendererBinding.instance.renderView.toStringDeep(); return { - 'data': data, + 'data': _debugCollectRenderTrees(), }; }, ); @@ -165,7 +168,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture name: RenderingServiceExtensions.debugDumpSemanticsTreeInTraversalOrder.name, callback: (Map parameters) async { return { - 'data': _generateSemanticsTree(DebugSemanticsDumpOrder.traversalOrder), + 'data': _debugCollectSemanticsTrees(DebugSemanticsDumpOrder.traversalOrder), }; }, ); @@ -173,7 +176,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture name: RenderingServiceExtensions.debugDumpSemanticsTreeInInverseHitTestOrder.name, callback: (Map parameters) async { return { - 'data': _generateSemanticsTree(DebugSemanticsDumpOrder.inverseHitTest), + 'data': _debugCollectSemanticsTrees(DebugSemanticsDumpOrder.inverseHitTest), }; }, ); @@ -200,38 +203,156 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture late final PipelineManifold _manifold = _BindingPipelineManifold(this); - /// Creates a [RenderView] object to be the root of the - /// [RenderObject] rendering tree, and initializes it so that it - /// will be rendered when the next frame is requested. - /// - /// Called automatically when the binding is created. - void initRenderView() { - assert(!_debugIsRenderViewInitialized); - assert(() { - _debugIsRenderViewInitialized = true; - return true; - }()); - renderView = RenderView(configuration: createViewConfiguration(), view: platformDispatcher.implicitView!); - renderView.prepareInitialFrame(); - } - bool _debugIsRenderViewInitialized = false; - /// The object that manages state about currently connected mice, for hover /// notification. MouseTracker get mouseTracker => _mouseTracker!; MouseTracker? _mouseTracker; - /// The render tree's owner, which maintains dirty state for layout, - /// composite, paint, and accessibility semantics. - PipelineOwner get pipelineOwner => _pipelineOwner; - late PipelineOwner _pipelineOwner; + /// Deprecated. Will be removed in a future version of Flutter. + /// + /// This is typically the owner of the render tree bootstrapped by [runApp] + /// and rooted in [renderView]. It maintains dirty state for layout, + /// composite, paint, and accessibility semantics for that tree. + /// + /// However, by default, the [pipelineOwner] does not participate in frame + /// production because it is not automatically attached to the + /// [rootPipelineOwner] or any of its descendants. It is also not + /// automatically associated with the [renderView]. This is left as a + /// responsibility for a higher level abstraction. The [WidgetsBinding], for + /// example, wires this up in [WidgetsBinding.wrapWithDefaultView], which is + /// called indirectly from [runApp]. + /// + /// Apps, that don't use the [WidgetsBinding] or don't call [runApp] (or + /// [WidgetsBinding.wrapWithDefaultView]) must manually add this pipeline owner + /// to the pipeline owner tree rooted at [rootPipelineOwner] and assign a + /// [RenderView] to it if the they want to use this deprecated property. + /// + /// Instead of accessing this deprecated property, consider interacting with + /// the root of the [PipelineOwner] tree (exposed in [rootPipelineOwner]) or + /// instead of accessing the [SemanticsOwner] of any [PipelineOwner] consider + /// interacting with the [SemanticsBinding] (exposed via + /// [SemanticsBinding.instance]) directly. + @Deprecated( + 'Interact with the pipelineOwner tree rooted at RendererBinding.rootPipelineOwner instead. ' + 'Or instead of accessing the SemanticsOwner of any PipelineOwner interact with the SemanticsBinding directly. ' + 'This feature was deprecated after v3.10.0-12.0.pre.' + ) + late final PipelineOwner pipelineOwner = PipelineOwner( + onSemanticsOwnerCreated: () { + (pipelineOwner.rootNode as RenderView?)?.scheduleInitialSemantics(); + }, + onSemanticsUpdate: (ui.SemanticsUpdate update) { + (pipelineOwner.rootNode as RenderView?)?.updateSemantics(update); + }, + onSemanticsOwnerDisposed: () { + (pipelineOwner.rootNode as RenderView?)?.clearSemantics(); + } + ); + + /// Deprecated. Will be removed in a future version of Flutter. + /// + /// This is typically the root of the render tree bootstrapped by [runApp]. + /// + /// However, by default this render view is not associated with any + /// [PipelineOwner] and therefore isn't considered during frame production. + /// It is also not registered with this binding via [addRenderView]. + /// Wiring this up is left as a responsibility for a higher level. The + /// [WidgetsBinding], for example, sets this up in + /// [WidgetsBinding.wrapWithDefaultView], which is called indirectly from + /// [runApp]. + /// + /// Apps that don't use the [WidgetsBinding] or don't call [runApp] (or + /// [WidgetsBinding.wrapWithDefaultView]) must manually assign a + /// [PipelineOwner] to this [RenderView], make sure the pipeline owner is part + /// of the pipeline owner tree rooted at [rootPipelineOwner], and call + /// [addRenderView] if they want to use this deprecated property. + /// + /// Instead of interacting with this deprecated property, consider using + /// [renderViews] instead, which contains all [RenderView]s managed by the + /// binding. + @Deprecated( + 'Consider using RendererBinding.renderViews instead as the binding may manage multiple RenderViews. ' + 'This feature was deprecated after v3.10.0-12.0.pre.' + ) + // TODO(goderbauer): When this deprecated property is removed also delete the _ReusableRenderView class. + late final RenderView renderView = _ReusableRenderView( + view: platformDispatcher.implicitView!, + ); + + /// Creates the [PipelineOwner] that serves as the root of the pipeline owner + /// tree ([rootPipelineOwner]). + /// + /// {@template flutter.rendering.createRootPipelineOwner} + /// By default, the root pipeline owner is not setup to manage a render tree + /// and its [PipelineOwner.rootNode] must not be assigned. If necessary, + /// [createRootPipelineOwner] may be overridden to create a root pipeline + /// owner configured to manage its own render tree. + /// + /// In typical use, child pipeline owners are added to the root pipeline owner + /// (via [PipelineOwner.adoptChild]). Those children typically do each manage + /// their own [RenderView] and produce distinct render trees which render + /// their content into the [FlutterView] associated with that [RenderView]. + /// {@endtemplate} + PipelineOwner createRootPipelineOwner() { + return _DefaultRootPipelineOwner(); + } + + /// The [PipelineOwner] that is the root of the PipelineOwner tree. + /// + /// {@macro flutter.rendering.createRootPipelineOwner} + PipelineOwner get rootPipelineOwner => _rootPipelineOwner; + late PipelineOwner _rootPipelineOwner; + + /// The [RenderView]s managed by this binding. + /// + /// A [RenderView] is added by [addRenderView] and removed by [removeRenderView]. + Iterable get renderViews => _viewIdToRenderView.values; + final Map _viewIdToRenderView = {}; + + /// Adds a [RenderView] to this binding. + /// + /// The binding will interact with the [RenderView] in the following ways: + /// + /// * setting and updating [RenderView.configuration], + /// * calling [RenderView.compositeFrame] when it is time to produce a new + /// frame, and + /// * forwarding relevant pointer events to the [RenderView] for hit testing. + /// + /// To remove a [RenderView] from the binding, call [removeRenderView]. + void addRenderView(RenderView view) { + final Object viewId = view.flutterView.viewId; + assert(!_viewIdToRenderView.containsValue(view)); + assert(!_viewIdToRenderView.containsKey(viewId)); + _viewIdToRenderView[viewId] = view; + view.configuration = createViewConfigurationFor(view); + } - /// The render tree that's attached to the output surface. - RenderView get renderView => _pipelineOwner.rootNode! as RenderView; - /// Sets the given [RenderView] object (which must not be null), and its tree, to - /// be the new render tree to display. The previous tree, if any, is detached. - set renderView(RenderView value) { - _pipelineOwner.rootNode = value; + /// Removes a [RenderView] previously added with [addRenderView] from the + /// binding. + void removeRenderView(RenderView view) { + final Object viewId = view.flutterView.viewId; + assert(_viewIdToRenderView[viewId] == view); + _viewIdToRenderView.remove(viewId); + } + + /// Returns a [ViewConfiguration] configured for the provided [RenderView] + /// based on the current environment. + /// + /// This is called during [addRenderView] and also in response to changes to + /// the system metrics to update all [renderViews] added to the binding. + /// + /// Bindings can override this method to change what size or device pixel + /// ratio the [RenderView] will use. For example, the testing framework uses + /// this to force the display into 800x600 when a test is run on the device + /// using `flutter run`. + @protected + ViewConfiguration createViewConfigurationFor(RenderView renderView) { + final FlutterView view = renderView.flutterView; + final double devicePixelRatio = view.devicePixelRatio; + return ViewConfiguration( + size: view.physicalSize / devicePixelRatio, + devicePixelRatio: devicePixelRatio, + ); } /// Called when the system metrics change. @@ -240,8 +361,12 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture @protected @visibleForTesting void handleMetricsChanged() { - renderView.configuration = createViewConfiguration(); - if (renderView.child != null) { + bool forceFrame = false; + for (final RenderView view in renderViews) { + forceFrame = forceFrame || view.child != null; + view.configuration = createViewConfigurationFor(view); + } + if (forceFrame) { scheduleForcedFrame(); } } @@ -288,25 +413,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture @protected void handlePlatformBrightnessChanged() { } - /// Returns a [ViewConfiguration] configured for the [RenderView] based on the - /// current environment. - /// - /// This is called during construction and also in response to changes to the - /// system metrics. - /// - /// Bindings can override this method to change what size or device pixel - /// ratio the [RenderView] will use. For example, the testing framework uses - /// this to force the display into 800x600 when a test is run on the device - /// using `flutter run`. - ViewConfiguration createViewConfiguration() { - final FlutterView view = platformDispatcher.implicitView!; - final double devicePixelRatio = view.devicePixelRatio; - return ViewConfiguration( - size: view.physicalSize / devicePixelRatio, - devicePixelRatio: devicePixelRatio, - ); - } - /// Creates a [MouseTracker] which manages state about currently connected /// mice, for hover notification. /// @@ -335,19 +441,10 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture @override void performSemanticsAction(SemanticsActionEvent action) { - _pipelineOwner.semanticsOwner?.performAction(action.nodeId, action.type, action.arguments); - } - - void _handleSemanticsOwnerCreated() { - renderView.scheduleInitialSemantics(); - } - - void _handleSemanticsUpdate(ui.SemanticsUpdate update) { - renderView.updateSemantics(update); - } - - void _handleSemanticsOwnerDisposed() { - renderView.clearSemantics(); + // Due to the asynchronicity in some screen readers (they may not have + // processed the latest semantics update yet) this code is more forgiving + // and actions for views/nodes that no longer exist are gracefully ignored. + _viewIdToRenderView[action.viewId]?.owner?.semanticsOwner?.performAction(action.nodeId, action.type, action.arguments); } void _handleWebFirstFrame(Duration _) { @@ -491,12 +588,14 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture // When editing the above, also update widgets/binding.dart's copy. @protected void drawFrame() { - pipelineOwner.flushLayout(); - pipelineOwner.flushCompositingBits(); - pipelineOwner.flushPaint(); + rootPipelineOwner.flushLayout(); + rootPipelineOwner.flushCompositingBits(); + rootPipelineOwner.flushPaint(); if (sendFramesToEngine) { - renderView.compositeFrame(); // this sends the bits to the GPU - pipelineOwner.flushSemantics(); // this also sends the semantics to the OS. + for (final RenderView renderView in renderViews) { + renderView.compositeFrame(); // this sends the bits to the GPU + } + rootPipelineOwner.flushSemantics(); // this sends the semantics to the OS. _firstFrameSent = true; } } @@ -509,7 +608,9 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture FlutterTimeline.startSync('Preparing Hot Reload (layout)'); } try { - renderView.reassemble(); + for (final RenderView renderView in renderViews) { + renderView.reassemble(); + } } finally { if (!kReleaseMode) { FlutterTimeline.finishSync(); @@ -520,18 +621,9 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture await endOfFrame; } - late final int _implicitViewId = platformDispatcher.implicitView!.viewId; - @override void hitTestInView(HitTestResult result, Offset position, int viewId) { - // Currently Flutter only supports one view, the implicit view `renderView`. - // TODO(dkwingsmt): After Flutter supports multi-view, look up the correct - // render view for the ID. - // https://github.com/flutter/flutter/issues/121573 - assert(viewId == _implicitViewId, - 'Unexpected view ID $viewId (expecting implicit view ID $_implicitViewId)'); - assert(viewId == renderView.flutterView.viewId); - renderView.hitTest(result, position: position); + _viewIdToRenderView[viewId]?.hitTest(result, position: position); super.hitTestInView(result, position, viewId); } @@ -541,40 +633,93 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture child.markNeedsPaint(); child.visitChildren(visitor); }; - instance.renderView.visitChildren(visitor); + for (final RenderView renderView in renderViews) { + renderView.visitChildren(visitor); + } return endOfFrame; } } -/// Prints a textual representation of the entire render tree. +String _debugCollectRenderTrees() { + if (RendererBinding.instance.renderViews.isEmpty) { + return 'No render tree root was added to the binding.'; + } + return [ + for (final RenderView renderView in RendererBinding.instance.renderViews) + renderView.toStringDeep(), + ].join('\n\n'); +} + +/// Prints a textual representation of the render trees. +/// +/// {@template flutter.rendering.debugDumpRenderTree} +/// It prints the trees associated with every [RenderView] in +/// [RendererBinding.renderView], separated by two blank lines. +/// {@endtemplate} void debugDumpRenderTree() { - debugPrint(RendererBinding.instance.renderView.toStringDeep()); + debugPrint(_debugCollectRenderTrees()); +} + +String _debugCollectLayerTrees() { + if (RendererBinding.instance.renderViews.isEmpty) { + return 'No render tree root was added to the binding.'; + } + return [ + for (final RenderView renderView in RendererBinding.instance.renderViews) + renderView.debugLayer?.toStringDeep() ?? 'Layer tree unavailable for $renderView.', + ].join('\n\n'); } -/// Prints a textual representation of the entire layer tree. +/// Prints a textual representation of the layer trees. +/// +/// {@macro flutter.rendering.debugDumpRenderTree} void debugDumpLayerTree() { - debugPrint(RendererBinding.instance.renderView.debugLayer?.toStringDeep()); + debugPrint(_debugCollectLayerTrees()); } -/// Prints a textual representation of the entire semantics tree. -/// This will only work if there is a semantics client attached. -/// Otherwise, a notice that no semantics are available will be printed. +String _debugCollectSemanticsTrees(DebugSemanticsDumpOrder childOrder) { + if (RendererBinding.instance.renderViews.isEmpty) { + return 'No render tree root was added to the binding.'; + } + const String explanation = 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' + 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n' + 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.'; + final List trees = []; + bool printedExplanation = false; + for (final RenderView renderView in RendererBinding.instance.renderViews) { + final String? tree = renderView.debugSemantics?.toStringDeep(childOrder: childOrder); + if (tree != null) { + trees.add(tree); + } else { + String message = 'Semantics not generated for $renderView.'; + if (!printedExplanation) { + printedExplanation = true; + message = '$message\n$explanation'; + } + trees.add(message); + } + } + return trees.join('\n\n'); +} + +/// Prints a textual representation of the semantics trees. +/// +/// {@macro flutter.rendering.debugDumpRenderTree} +/// +/// Semantics trees are only constructed when semantics are enabled (see +/// [SemanticsBinding.semanticsEnabled]). If a semantics tree is not available, +/// a notice about the missing semantics tree is printed instead. /// /// The order in which the children of a [SemanticsNode] will be printed is /// controlled by the [childOrder] parameter. void debugDumpSemanticsTree([DebugSemanticsDumpOrder childOrder = DebugSemanticsDumpOrder.traversalOrder]) { - debugPrint(_generateSemanticsTree(childOrder)); + debugPrint(_debugCollectSemanticsTrees(childOrder)); } -String _generateSemanticsTree(DebugSemanticsDumpOrder childOrder) { - final String? tree = RendererBinding.instance.renderView.debugSemantics?.toStringDeep(childOrder: childOrder); - if (tree != null) { - return tree; - } - return 'Semantics not generated.\n' - 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' - 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n' - 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.'; +/// Prints a textual representation of the [PipelineOwner] tree rooted at +/// [RendererBinding.rootPipelineOwner]. +void debugDumpPipelineOwnerTree() { + debugPrint(RendererBinding.instance.rootPipelineOwner.toStringDeep()); } /// A concrete binding for applications that use the Rendering framework @@ -595,18 +740,17 @@ String _generateSemanticsTree(DebugSemanticsDumpOrder childOrder) { /// rendering layer directly. If you are writing to a higher-level /// library, such as the Flutter Widgets library, then you would use /// that layer's binding (see [WidgetsFlutterBinding]). +/// +/// The [RenderingFlutterBinding] can manage multiple render trees. Each render +/// tree is rooted in a [RenderView] that must be added to the binding via +/// [addRenderView] to be consider during frame production, hit testing, etc. +/// Furthermore, the render tree must be managed by a [PipelineOwner] that is +/// part of the pipeline owner tree rooted at [rootPipelineOwner]. +/// +/// Adding [PipelineOwner]s and [RenderView]s to this binding in the way +/// described above is left as a responsibility for a higher level abstraction. +/// The binding does not own any [RenderView]s directly. class RenderingFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, SemanticsBinding, PaintingBinding, RendererBinding { - /// Creates a binding for the rendering layer. - /// - /// The `root` render box is attached directly to the [renderView] and is - /// given constraints that require it to fill the window. - /// - /// This binding does not automatically schedule any frames. Callers are - /// responsible for deciding when to first call [scheduleFrame]. - RenderingFlutterBinding({ RenderBox? root }) { - renderView.child = root; - } - /// Returns an instance of the binding that implements /// [RendererBinding]. If no binding has yet been initialized, the /// [RenderingFlutterBinding] class is used to create and initialize @@ -645,3 +789,82 @@ class _BindingPipelineManifold extends ChangeNotifier implements PipelineManifol super.dispose(); } } + +// A [PipelineOwner] that cannot have a root node. +class _DefaultRootPipelineOwner extends PipelineOwner { + _DefaultRootPipelineOwner() : super(onSemanticsUpdate: _onSemanticsUpdate); + + @override + set rootNode(RenderObject? _) { + assert(() { + throw FlutterError.fromParts([ + ErrorSummary( + 'Cannot set a rootNode on the default root pipeline owner.', + ), + ErrorDescription( + 'By default, the RendererBinding.rootPipelineOwner is not configured ' + 'to manage a root node because this pipeline owner does not define a ' + 'proper onSemanticsUpdate callback to handle semantics for that node.', + ), + ErrorHint( + 'Typically, the root pipeline owner does not manage a root node. ' + 'Instead, properly configured child pipeline owners (which do manage ' + 'root nodes) are added to it. Alternatively, if you do want to set a ' + 'root node for the root pipeline owner, override ' + 'RendererBinding.createRootPipelineOwner to create a ' + 'pipeline owner that is configured to properly handle semantics for ' + 'the provided root node.' + ), + ]); + }()); + } + + static void _onSemanticsUpdate(ui.SemanticsUpdate _) { + // Neve called because we don't have a root node. + assert(false); + } +} + +// Prior to multi view support, the [RendererBinding] would own a long-lived +// [RenderView], that was never disposed (see [RendererBinding.renderView]). +// With multi view support, the [RendererBinding] no longer owns a [RenderView] +// and instead higher level abstractions (like the [View] widget) can add/remove +// multiple [RenderView]s to the binding as needed. When the [View] widget is no +// longer needed, it expects to dispose its [RenderView]. +// +// This special version of a [RenderView] now exists as a bridge between those +// worlds to continue supporting the [RendererBinding.renderView] property +// through its deprecation period. Per the property's contract, it is supposed +// to be long-lived, but it is also managed by a [View] widget (introduced by +// [WidgetsBinding.wrapWithDefaultView]), that expects to dispose its render +// object at the end of the widget's life time. This special version now +// implements logic to reset the [RenderView] when it is "disposed" so it can be +// reused by another [View] widget. +// +// Once the deprecated [RendererBinding.renderView] property is removed, this +// class is no longer necessary. +class _ReusableRenderView extends RenderView { + _ReusableRenderView({required super.view}); + + bool _initialFramePrepared = false; + + @override + void prepareInitialFrame() { + if (_initialFramePrepared) { + return; + } + super.prepareInitialFrame(); + _initialFramePrepared = true; + } + + @override + void scheduleInitialSemantics() { + clearSemantics(); + super.scheduleInitialSemantics(); + } + + @override + void dispose() { // ignore: must_call_super + child = null; + } +} diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index b12378a9ff4f8..9a54bea5cbf82 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -870,7 +870,7 @@ class _LocalSemanticsHandle implements SemanticsHandle { /// without tying it to a specific binding implementation. All [PipelineOwner]s /// in a given tree must be attached to the same [PipelineManifold]. This /// happens automatically during [adoptChild]. -class PipelineOwner { +class PipelineOwner with DiagnosticableTreeMixin { /// Creates a pipeline owner. /// /// Typically created by the binding (e.g., [RendererBinding]), but can be @@ -984,7 +984,7 @@ class PipelineOwner { return true; }()); FlutterTimeline.startSync( - 'LAYOUT', + 'LAYOUT$_debugRootSuffixForTimelineEventNames', arguments: debugTimelineArguments, ); } @@ -1071,7 +1071,7 @@ class PipelineOwner { /// [flushPaint]. void flushCompositingBits() { if (!kReleaseMode) { - FlutterTimeline.startSync('UPDATING COMPOSITING BITS'); + FlutterTimeline.startSync('UPDATING COMPOSITING BITS$_debugRootSuffixForTimelineEventNames'); } _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth); for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) { @@ -1120,7 +1120,7 @@ class PipelineOwner { return true; }()); FlutterTimeline.startSync( - 'PAINT', + 'PAINT$_debugRootSuffixForTimelineEventNames', arguments: debugTimelineArguments, ); } @@ -1247,7 +1247,7 @@ class PipelineOwner { return; } if (!kReleaseMode) { - FlutterTimeline.startSync('SEMANTICS'); + FlutterTimeline.startSync('SEMANTICS$_debugRootSuffixForTimelineEventNames'); } assert(_semanticsOwner != null); assert(() { @@ -1279,6 +1279,20 @@ class PipelineOwner { } } + @override + List debugDescribeChildren() { + return [ + for (final PipelineOwner child in _children) + child.toDiagnosticsNode(), + ]; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('rootNode', rootNode, defaultValue: null)); + } + // TREE MANAGEMENT final Set _children = {}; @@ -1290,6 +1304,8 @@ class PipelineOwner { return true; } + String get _debugRootSuffixForTimelineEventNames => _debugParent == null ? ' (root)' : ''; + /// Mark this [PipelineOwner] as attached to the given [PipelineManifold]. /// /// Typically, this is only called directly on the root [PipelineOwner]. @@ -1315,7 +1331,9 @@ class PipelineOwner { assert(_manifold != null); _manifold!.removeListener(_updateSemanticsOwner); _manifold = null; - _updateSemanticsOwner(); + // Not updating the semantics owner here to not disrupt any of its clients + // in case we get re-attached. If necessary, semantics owner will be updated + // in "attach", or disposed in "dispose", if not reattached. for (final PipelineOwner child in _children) { child.detach(); @@ -1351,7 +1369,9 @@ class PipelineOwner { assert(!_children.contains(child)); assert(_debugAllowChildListModifications, 'Cannot modify child list after layout.'); _children.add(child); - assert(_debugSetParent(child, this)); + if (!kReleaseMode) { + _debugSetParent(child, this); + } if (_manifold != null) { child.attach(_manifold!); } @@ -1369,7 +1389,9 @@ class PipelineOwner { assert(_children.contains(child)); assert(_debugAllowChildListModifications, 'Cannot modify child list after layout.'); _children.remove(child); - assert(_debugSetParent(child, null)); + if (!kReleaseMode) { + _debugSetParent(child, null); + } if (_manifold != null) { child.detach(); } @@ -1384,6 +1406,26 @@ class PipelineOwner { void visitChildren(PipelineOwnerVisitor visitor) { _children.forEach(visitor); } + + /// Release any resources held by this pipeline owner. + /// + /// Prior to calling this method the pipeline owner must be removed from the + /// pipeline owner tree, i.e. it must have neither a parent nor any children + /// (see [dropChild]). It also must be [detach]ed from any [PipelineManifold]. + /// + /// The object is no longer usable after calling dispose. + void dispose() { + assert(_children.isEmpty); + assert(rootNode == null); + assert(_manifold == null); + assert(_debugParent == null); + _semanticsOwner?.dispose(); + _semanticsOwner = null; + _nodesNeedingLayout.clear(); + _nodesNeedingCompositingBitsUpdate.clear(); + _nodesNeedingPaint.clear(); + _nodesNeedingSemantics.clear(); + } } /// Signature for the callback to [PipelineOwner.visitChildren]. @@ -3919,7 +3961,6 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge /// This mixin is typically used to implement render objects created /// in a [SingleChildRenderObjectWidget]. mixin RenderObjectWithChildMixin on RenderObject { - /// Checks whether the given render object has the correct [runtimeType] to be /// a child of this render object. /// diff --git a/packages/flutter/lib/src/rendering/view.dart b/packages/flutter/lib/src/rendering/view.dart index 906d237c1da50..03db7f1d608ca 100644 --- a/packages/flutter/lib/src/rendering/view.dart +++ b/packages/flutter/lib/src/rendering/view.dart @@ -67,10 +67,14 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin /// /// Typically created by the binding (e.g., [RendererBinding]). /// - /// The [configuration] must not be null. + /// Providing a [configuration] is optional, but a configuration must be set + /// before calling [prepareInitialFrame]. This decouples creating the + /// [RenderView] object from configuring it. Typically, the object is created + /// by the [View] widget and configured by the [RendererBinding] when the + /// [RenderView] is registered with it by the [View] widget. RenderView({ RenderBox? child, - required ViewConfiguration configuration, + ViewConfiguration? configuration, required ui.FlutterView view, }) : _configuration = configuration, _view = view { @@ -82,26 +86,39 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin Size _size = Size.zero; /// The constraints used for the root layout. - ViewConfiguration get configuration => _configuration; - ViewConfiguration _configuration; - - /// The configuration is initially set by the [configuration] argument - /// passed to the constructor. /// - /// Always call [prepareInitialFrame] before changing the configuration. + /// Typically, this configuration is set by the [RendererBinding], when the + /// [RenderView] is registered with it. It will also update the configuration + /// if necessary. Therefore, if used in conjunction with the [RendererBinding] + /// this property must not be set manually as the [RendererBinding] will just + /// override it. + /// + /// For tests that want to change the size of the view, set + /// [TestFlutterView.physicalSize] on the appropriate [TestFlutterView] + /// (typically [WidgetTester.view]) instead of setting a configuration + /// directly on the [RenderView]. + ViewConfiguration get configuration => _configuration!; + ViewConfiguration? _configuration; set configuration(ViewConfiguration value) { - if (configuration == value) { + if (_configuration == value) { return; } - final ViewConfiguration oldConfiguration = _configuration; + final ViewConfiguration? oldConfiguration = _configuration; _configuration = value; - if (oldConfiguration.toMatrix() != _configuration.toMatrix()) { + if (_rootTransform == null) { + // [prepareInitialFrame] has not been called yet, nothing to do for now. + return; + } + if (oldConfiguration?.toMatrix() != configuration.toMatrix()) { replaceRootLayer(_updateMatricesAndCreateNewRootLayer()); } assert(_rootTransform != null); markNeedsLayout(); } + /// Whether a [configuration] has been set. + bool get hasConfiguration => _configuration != null; + /// The [FlutterView] into which this [RenderView] will render. ui.FlutterView get flutterView => _view; final ui.FlutterView _view; diff --git a/packages/flutter/lib/src/widgets/adapter.dart b/packages/flutter/lib/src/widgets/adapter.dart new file mode 100644 index 0000000000000..1948312f7de41 --- /dev/null +++ b/packages/flutter/lib/src/widgets/adapter.dart @@ -0,0 +1,177 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; + +import 'framework.dart'; + +/// A bridge from a [RenderObject] to an [Element] tree. +/// +/// The given container is the [RenderObject] that the [Element] tree should be +/// inserted into. It must be a [RenderObject] that implements the +/// [RenderObjectWithChildMixin] protocol. The type argument `T` is the kind of +/// [RenderObject] that the container expects as its child. +/// +/// The [RenderObjectToWidgetAdapter] is an alternative to [RootWidget] for +/// bootstrapping an element tree. Unlike [RootWidget] it requires the +/// existence of a render tree (the [container]) to attach the element tree to. +class RenderObjectToWidgetAdapter extends RenderObjectWidget { + /// Creates a bridge from a [RenderObject] to an [Element] tree. + RenderObjectToWidgetAdapter({ + this.child, + required this.container, + this.debugShortDescription, + }) : super(key: GlobalObjectKey(container)); + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget? child; + + /// The [RenderObject] that is the parent of the [Element] created by this widget. + final RenderObjectWithChildMixin container; + + /// A short description of this widget used by debugging aids. + final String? debugShortDescription; + + @override + RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this); + + @override + RenderObjectWithChildMixin createRenderObject(BuildContext context) => container; + + @override + void updateRenderObject(BuildContext context, RenderObject renderObject) { } + + /// Inflate this widget and actually set the resulting [RenderObject] as the + /// child of [container]. + /// + /// If `element` is null, this function will create a new element. Otherwise, + /// the given element will have an update scheduled to switch to this widget. + RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? element ]) { + if (element == null) { + owner.lockState(() { + element = createElement(); + assert(element != null); + element!.assignOwner(owner); + }); + owner.buildScope(element!, () { + element!.mount(null, null); + }); + } else { + element._newWidget = this; + element.markNeedsBuild(); + } + return element!; + } + + @override + String toStringShort() => debugShortDescription ?? super.toStringShort(); +} + +/// The root of an element tree that is hosted by a [RenderObject]. +/// +/// This element class is the instantiation of a [RenderObjectToWidgetAdapter] +/// widget. It can be used only as the root of an [Element] tree (it cannot be +/// mounted into another [Element]; it's parent must be null). +/// +/// In typical usage, it will be instantiated for a [RenderObjectToWidgetAdapter] +/// whose container is the [RenderView]. +class RenderObjectToWidgetElement extends RenderTreeRootElement with RootElementMixin { + /// Creates an element that is hosted by a [RenderObject]. + /// + /// The [RenderObject] created by this element is not automatically set as a + /// child of the hosting [RenderObject]. To actually attach this element to + /// the render tree, call [RenderObjectToWidgetAdapter.attachToRenderTree]. + RenderObjectToWidgetElement(RenderObjectToWidgetAdapter super.widget); + + Element? _child; + + static const Object _rootChildSlot = Object(); + + @override + void visitChildren(ElementVisitor visitor) { + if (_child != null) { + visitor(_child!); + } + } + + @override + void forgetChild(Element child) { + assert(child == _child); + _child = null; + super.forgetChild(child); + } + + @override + void mount(Element? parent, Object? newSlot) { + assert(parent == null); + super.mount(parent, newSlot); + _rebuild(); + assert(_child != null); + } + + @override + void update(RenderObjectToWidgetAdapter newWidget) { + super.update(newWidget); + assert(widget == newWidget); + _rebuild(); + } + + // When we are assigned a new widget, we store it here + // until we are ready to update to it. + Widget? _newWidget; + + @override + void performRebuild() { + if (_newWidget != null) { + // _newWidget can be null if, for instance, we were rebuilt + // due to a reassemble. + final Widget newWidget = _newWidget!; + _newWidget = null; + update(newWidget as RenderObjectToWidgetAdapter); + } + super.performRebuild(); + assert(_newWidget == null); + } + + @pragma('vm:notify-debugger-on-exception') + void _rebuild() { + try { + _child = updateChild(_child, (widget as RenderObjectToWidgetAdapter).child, _rootChildSlot); + } catch (exception, stack) { + final FlutterErrorDetails details = FlutterErrorDetails( + exception: exception, + stack: stack, + library: 'widgets library', + context: ErrorDescription('attaching to the render tree'), + ); + FlutterError.reportError(details); + final Widget error = ErrorWidget.builder(details); + _child = updateChild(null, error, _rootChildSlot); + } + } + + @override + RenderObjectWithChildMixin get renderObject => super.renderObject as RenderObjectWithChildMixin; + + @override + void insertRenderObjectChild(RenderObject child, Object? slot) { + assert(slot == _rootChildSlot); + assert(renderObject.debugValidateChild(child)); + renderObject.child = child as T; + } + + @override + void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) { + assert(false); + } + + @override + void removeRenderObjectChild(RenderObject child, Object? slot) { + assert(renderObject.child == child); + renderObject.child = null; + } +} diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 8750f0ef24072..f4778adfb3008 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -280,6 +280,48 @@ abstract mixin class WidgetsBindingObserver { } /// The glue between the widgets layer and the Flutter engine. +/// +/// The [WidgetsBinding] manages a single [Element] tree rooted at [rootElement]. +/// Calling [runApp] (which indirectly calls [attachRootWidget]) bootstraps that +/// element tree. +/// +/// ## Relationship to render trees +/// +/// Multiple render trees may be associated with the element tree. Those are +/// managed by the underlying [RendererBinding]. +/// +/// The element tree is segmented into two types of zones: rendering zones and +/// non-rendering zones. +/// +/// A rendering zone is a part of the element tree that is backed by a render +/// tree and it describes the pixels that are drawn on screen. For elements in +/// this zone, [Element.renderObject] never returns null because the elements +/// are all associated with [RenderObject]s. Almost all widgets can be placed in +/// a rendering zone; notable exceptions are the [View] widget, [ViewCollection] +/// widget, and [RootWidget]. +/// +/// A non-rendering zone is a part of the element tree that is not backed by a +/// render tree. For elements in this zone, [Element.renderObject] returns null +/// because the elements are not associated with any [RenderObject]s. Only +/// widgets that do not produce a [RenderObject] can be used in this zone +/// because there is no render tree to attach the render object to. In other +/// words, [RenderObjectWidget]s cannot be used in this zone. Typically, one +/// would find [InheritedWidget]s, [View]s, and [ViewCollection]s in this zone +/// to inject data across rendering zones into the tree and to organize the +/// rendering zones (and by extension their associated render trees) into a +/// unified element tree. +/// +/// The root of the element tree at [rootElement] starts a non-rendering zone. +/// Within a non-rendering zone, the [View] widget is used to start a rendering +/// zone by bootstrapping a render tree. Within a rendering zone, the +/// [ViewAnchor] can be used to start a new non-rendering zone. +/// +// TODO(goderbauer): Include an example graph showcasing the different zones. +/// +/// To figure out if an element is in a rendering zone it may walk up the tree +/// calling [Element.debugExpectsRenderObjectForSlot] on its ancestors. If it +/// reaches an element that returns false, it is in a non-rendering zone. If it +/// reaches a [RenderObjectElement] ancestor it is in a rendering zone. mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding { @override void initInstances() { @@ -975,6 +1017,8 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB Widget wrapWithDefaultView(Widget rootWidget) { return View( view: platformDispatcher.implicitView!, + deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner: pipelineOwner, + deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView: renderView, child: rootWidget, ); } @@ -1000,13 +1044,25 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a /// widget and attaches it to the render tree. void attachRootWidget(Widget rootWidget) { - final bool isBootstrapFrame = rootElement == null; - _readyToProduceFrames = true; - _rootElement = RenderObjectToWidgetAdapter( - container: renderView, + attachToBuildOwner(RootWidget( debugShortDescription: '[root]', child: rootWidget, - ).attachToRenderTree(buildOwner!, rootElement as RenderObjectToWidgetElement?); + )); + } + + /// Called by [attachRootWidget] to attach the provided [RootWidget] to the + /// [buildOwner]. + /// + /// This creates the [rootElement], if necessary, or re-uses an existing one. + /// + /// This method is rarely called directly, but it can be useful in tests to + /// restore the element tree to a previous version by providing the + /// [RootWidget] of that version (see [WidgetTester.restartAndRestore] for an + /// exemplary use case). + void attachToBuildOwner(RootWidget widget) { + final bool isBootstrapFrame = rootElement == null; + _readyToProduceFrames = true; + _rootElement = widget.attach(buildOwner!, rootElement as RootElement?); if (isBootstrapFrame) { SchedulerBinding.instance.ensureVisualUpdate(); } @@ -1121,52 +1177,40 @@ void debugDumpApp() { debugPrint(_debugDumpAppString()); } -/// A bridge from a [RenderObject] to an [Element] tree. +/// A widget for the root of the widget tree. /// -/// The given container is the [RenderObject] that the [Element] tree should be -/// inserted into. It must be a [RenderObject] that implements the -/// [RenderObjectWithChildMixin] protocol. The type argument `T` is the kind of -/// [RenderObject] that the container expects as its child. +/// Exposes an [attach] method to attach the widget tree to a [BuildOwner]. That +/// method also bootstraps the element tree. /// -/// Used by [runApp] to bootstrap applications. -class RenderObjectToWidgetAdapter extends RenderObjectWidget { - /// Creates a bridge from a [RenderObject] to an [Element] tree. - /// - /// Used by [WidgetsBinding] to attach the root widget to the [RenderView]. - RenderObjectToWidgetAdapter({ +/// Used by [WidgetsBinding.attachRootWidget] (which is indirectly called by +/// [runApp]) to bootstrap applications. +class RootWidget extends Widget { + /// Creates a [RootWidget]. + const RootWidget({ + super.key, this.child, - required this.container, this.debugShortDescription, - }) : super(key: GlobalObjectKey(container)); + }); /// The widget below this widget in the tree. /// /// {@macro flutter.widgets.ProxyWidget.child} final Widget? child; - /// The [RenderObject] that is the parent of the [Element] created by this widget. - final RenderObjectWithChildMixin container; - /// A short description of this widget used by debugging aids. final String? debugShortDescription; @override - RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this); - - @override - RenderObjectWithChildMixin createRenderObject(BuildContext context) => container; - - @override - void updateRenderObject(BuildContext context, RenderObject renderObject) { } + RootElement createElement() => RootElement(this); - /// Inflate this widget and actually set the resulting [RenderObject] as the - /// child of [container]. + /// Inflate this widget and attaches it to the provided [BuildOwner]. /// /// If `element` is null, this function will create a new element. Otherwise, /// the given element will have an update scheduled to switch to this widget. /// - /// Used by [runApp] to bootstrap applications. - RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? element ]) { + /// Used by [WidgetsBinding.attachToBuildOwner] (which is indirectly called by + /// [runApp]) to bootstrap applications. + RootElement attach(BuildOwner owner, [ RootElement? element ]) { if (element == null) { owner.lockState(() { element = createElement(); @@ -1174,7 +1218,7 @@ class RenderObjectToWidgetAdapter extends RenderObjectWi element!.assignOwner(owner); }); owner.buildScope(element!, () { - element!.mount(null, null); + element!.mount(/* parent */ null, /* slot */ null); }); } else { element._newWidget = this; @@ -1187,28 +1231,22 @@ class RenderObjectToWidgetAdapter extends RenderObjectWi String toStringShort() => debugShortDescription ?? super.toStringShort(); } -/// The root of the element tree that is hosted by a [RenderObject]. +/// The root of the element tree. /// -/// This element class is the instantiation of a [RenderObjectToWidgetAdapter] -/// widget. It can be used only as the root of an [Element] tree (it cannot be -/// mounted into another [Element]; it's parent must be null). +/// This element class is the instantiation of a [RootWidget]. It can be used +/// only as the root of an [Element] tree (it cannot be mounted into another +/// [Element]; its parent must be null). /// -/// In typical usage, it will be instantiated for a [RenderObjectToWidgetAdapter] -/// whose container is the [RenderView] that connects to the Flutter engine. In -/// this usage, it is normally instantiated by the bootstrapping logic in the -/// [WidgetsFlutterBinding] singleton created by [runApp]. -class RenderObjectToWidgetElement extends RenderObjectElement with RootElementMixin { - /// Creates an element that is hosted by a [RenderObject]. - /// - /// The [RenderObject] created by this element is not automatically set as a - /// child of the hosting [RenderObject]. To actually attach this element to - /// the render tree, call [RenderObjectToWidgetAdapter.attachToRenderTree]. - RenderObjectToWidgetElement(RenderObjectToWidgetAdapter super.widget); +/// In typical usage, it will be instantiated for a [RootWidget] by calling +/// [RootWidget.attach]. In this usage, it is normally instantiated by the +/// bootstrapping logic in the [WidgetsFlutterBinding] singleton created by +/// [runApp]. +class RootElement extends Element with RootElementMixin { + /// Creates a [RootElement] for the provided [RootWidget]. + RootElement(RootWidget super.widget); Element? _child; - static const Object _rootChildSlot = Object(); - @override void visitChildren(ElementVisitor visitor) { if (_child != null) { @@ -1225,14 +1263,15 @@ class RenderObjectToWidgetElement extends RenderObjectEl @override void mount(Element? parent, Object? newSlot) { - assert(parent == null); + assert(parent == null); // We are the root! super.mount(parent, newSlot); _rebuild(); assert(_child != null); + super.performRebuild(); // clears the "dirty" flag } @override - void update(RenderObjectToWidgetAdapter newWidget) { + void update(RootWidget newWidget) { super.update(newWidget); assert(widget == newWidget); _rebuild(); @@ -1240,25 +1279,24 @@ class RenderObjectToWidgetElement extends RenderObjectEl // When we are assigned a new widget, we store it here // until we are ready to update to it. - Widget? _newWidget; + RootWidget? _newWidget; @override void performRebuild() { if (_newWidget != null) { // _newWidget can be null if, for instance, we were rebuilt // due to a reassemble. - final Widget newWidget = _newWidget!; + final RootWidget newWidget = _newWidget!; _newWidget = null; - update(newWidget as RenderObjectToWidgetAdapter); + update(newWidget); } super.performRebuild(); assert(_newWidget == null); } - @pragma('vm:notify-debugger-on-exception') void _rebuild() { try { - _child = updateChild(_child, (widget as RenderObjectToWidgetAdapter).child, _rootChildSlot); + _child = updateChild(_child, (widget as RootWidget).child, /* slot */ null); } catch (exception, stack) { final FlutterErrorDetails details = FlutterErrorDetails( exception: exception, @@ -1267,31 +1305,18 @@ class RenderObjectToWidgetElement extends RenderObjectEl context: ErrorDescription('attaching to the render tree'), ); FlutterError.reportError(details); - final Widget error = ErrorWidget.builder(details); - _child = updateChild(null, error, _rootChildSlot); + // No error widget possible here since it wouldn't have a view to render into. + _child = null; } - } - - @override - RenderObjectWithChildMixin get renderObject => super.renderObject as RenderObjectWithChildMixin; - @override - void insertRenderObjectChild(RenderObject child, Object? slot) { - assert(slot == _rootChildSlot); - assert(renderObject.debugValidateChild(child)); - renderObject.child = child as T; } @override - void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) { - assert(false); - } + bool get debugDoingBuild => false; // This element doesn't have a build phase. @override - void removeRenderObjectChild(RenderObject child, Object? slot) { - assert(renderObject.child == child); - renderObject.child = null; - } + // There is no ancestor RenderObjectElement that the render object could be attached to. + bool debugExpectsRenderObjectForSlot(Object? slot) => false; } /// A concrete binding for applications based on the Widgets framework. diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 2331ea9d31d09..da4132c16a5d7 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -3452,6 +3452,11 @@ abstract class Element extends DiagnosticableTree implements BuildContext { /// If this object is a [RenderObjectElement], the render object is the one at /// this location in the tree. Otherwise, this getter will walk down the tree /// until it finds a [RenderObjectElement]. + /// + /// Some locations in the tree are not backed by a render object. In those + /// cases, this getter returns null. This can happen, if the element is + /// located outside of a [View] since only the element subtree rooted in a + /// view has a render tree associated with it. RenderObject? get renderObject { Element? current = this; while (current != null) { @@ -3460,17 +3465,33 @@ abstract class Element extends DiagnosticableTree implements BuildContext { } else if (current is RenderObjectElement) { return current.renderObject; } else { - Element? next; - current.visitChildren((Element child) { - assert(next == null); // This verifies that there's only one child. - next = child; - }); - current = next; + current = current.renderObjectAttachingChild; } } return null; } + /// Returns the child of this [Element] that will insert a [RenderObject] into + /// an ancestor of this Element to construct the render tree. + /// + /// Returns null if this Element doesn't have any children who need to attach + /// a [RenderObject] to an ancestor of this [Element]. A [RenderObjectElement] + /// will therefore return null because its children insert their + /// [RenderObject]s into the [RenderObjectElement] itself and not into an + /// ancestor of the [RenderObjectElement]. + /// + /// Furthermore, this may return null for [Element]s that hoist their own + /// independent render tree and do not extend the ancestor render tree. + @protected + Element? get renderObjectAttachingChild { + Element? next; + visitChildren((Element child) { + assert(next == null); // This verifies that there's only one child. + next = child; + }); + return next; + } + @override List describeMissingAncestor({ required Type expectedAncestorType }) { final List information = []; @@ -4021,15 +4042,20 @@ abstract class Element extends DiagnosticableTree implements BuildContext { assert(_lifecycleState == _ElementLifecycle.active); assert(child._parent == this); void visit(Element element) { - element._updateSlot(newSlot); - if (element is! RenderObjectElement) { - element.visitChildren(visit); + element.updateSlot(newSlot); + final Element? descendant = element.renderObjectAttachingChild; + if (descendant != null) { + visit(descendant); } } visit(child); } - void _updateSlot(Object? newSlot) { + /// Called by [updateSlotForChild] when the framework needs to change the slot + /// that this [Element] occupies in its ancestor. + @protected + @mustCallSuper + void updateSlot(Object? newSlot) { assert(_lifecycleState == _ElementLifecycle.active); assert(_parent != null); assert(_parent!._lifecycleState == _ElementLifecycle.active); @@ -4070,7 +4096,7 @@ abstract class Element extends DiagnosticableTree implements BuildContext { /// /// The `newSlot` argument specifies the new value for this element's [slot]. void attachRenderObject(Object? newSlot) { - assert(_slot == null); + assert(slot == null); visitChildren((Element child) { child.attachRenderObject(newSlot); }); @@ -4143,7 +4169,6 @@ abstract class Element extends DiagnosticableTree implements BuildContext { @protected @pragma('vm:prefer-inline') Element inflateWidget(Widget newWidget, Object? newSlot) { - final bool isTimelineTracked = !kReleaseMode && _isProfileBuildsEnabledFor(newWidget); if (isTimelineTracked) { Map? debugTimelineArguments; @@ -4169,7 +4194,17 @@ abstract class Element extends DiagnosticableTree implements BuildContext { _debugCheckForCycles(newChild); return true; }()); - newChild._activateWithParent(this, newSlot); + try { + newChild._activateWithParent(this, newSlot); + } catch (_) { + // Attempt to do some clean-up if activation fails to leave tree in a reasonable state. + try { + deactivateChild(newChild); + } catch (_) { + // Clean-up failed. Only surface original exception. + } + rethrow; + } final Element? updatedChild = updateChild(newChild, newWidget, newSlot); assert(newChild == updatedChild); return updatedChild!; @@ -4404,6 +4439,33 @@ abstract class Element extends DiagnosticableTree implements BuildContext { _lifecycleState = _ElementLifecycle.defunct; } + /// Whether the child in the provided `slot` (or one of its descendants) must + /// insert a [RenderObject] into its ancestor [RenderObjectElement] by calling + /// [RenderObjectElement.insertRenderObjectChild] on it. + /// + /// This method is used to define non-rendering zones in the element tree (see + /// [WidgetsBinding] for an explanation of rendering and non-rendering zones): + /// + /// Most branches of the [Element] tree are expected to eventually insert a + /// [RenderObject] into their [RenderObjectElement] ancestor to construct the + /// render tree. However, there is a notable exception: an [Element] may + /// expect that the occupant of a certain child slot creates a new independent + /// render tree and therefore is not allowed to insert a render object into + /// the existing render tree. Those elements must return false from this + /// method for the slot in question to signal to the child in that slot that + /// it must not call [RenderObjectElement.insertRenderObjectChild] on its + /// ancestor. + /// + /// As an example, the element backing the [ViewAnchor] returns false from + /// this method for the [ViewAnchor.view] slot to enforce that it is occupied + /// by e.g. a [View] widget, which will ultimately bootstrap a separate + /// render tree for that view. Another example is the [ViewCollection] widget, + /// which returns false for all its slots for the same reason. + /// + /// Overriding this method is not common, as elements behaving in the way + /// described above are rare. + bool debugExpectsRenderObjectForSlot(Object? slot) => true; + @override RenderObject? findRenderObject() { assert(() { @@ -5266,6 +5328,9 @@ abstract class ComponentElement extends Element { @override bool get debugDoingBuild => _debugDoingBuild; + @override + Element? get renderObjectAttachingChild => _child; + @override void mount(Element? parent, Object? newSlot) { super.mount(parent, newSlot); @@ -6073,6 +6138,9 @@ abstract class RenderObjectElement extends Element { } RenderObject? _renderObject; + @override + Element? get renderObjectAttachingChild => null; + bool _debugDoingBuild = false; @override bool get debugDoingBuild => _debugDoingBuild; @@ -6082,8 +6150,25 @@ abstract class RenderObjectElement extends Element { RenderObjectElement? _findAncestorRenderObjectElement() { Element? ancestor = _parent; while (ancestor != null && ancestor is! RenderObjectElement) { - ancestor = ancestor._parent; + // In debug mode we check whether the ancestor accepts RenderObjects to + // produce a better error message in attachRenderObject. In release mode, + // we assume only correct trees are built (i.e. + // debugExpectsRenderObjectForSlot always returns true) and don't check + // explicitly. + assert(() { + if (!ancestor!.debugExpectsRenderObjectForSlot(slot)) { + ancestor = null; + } + return true; + }()); + ancestor = ancestor?._parent; } + assert(() { + if (ancestor?.debugExpectsRenderObjectForSlot(slot) == false) { + ancestor = null; + } + return true; + }()); return ancestor as RenderObjectElement?; } @@ -6151,7 +6236,7 @@ abstract class RenderObjectElement extends Element { _debugUpdateRenderObjectOwner(); return true; }()); - assert(_slot == newSlot); + assert(slot == newSlot); attachRenderObject(newSlot); super.performRebuild(); // clears the "dirty" flag } @@ -6252,12 +6337,13 @@ abstract class RenderObjectElement extends Element { } @override - void _updateSlot(Object? newSlot) { + void updateSlot(Object? newSlot) { final Object? oldSlot = slot; assert(oldSlot != newSlot); - super._updateSlot(newSlot); + super.updateSlot(newSlot); assert(slot == newSlot); - _ancestorRenderObjectElement!.moveRenderObjectChild(renderObject, oldSlot, slot); + assert(_ancestorRenderObjectElement == _findAncestorRenderObjectElement()); + _ancestorRenderObjectElement?.moveRenderObjectChild(renderObject, oldSlot, slot); } @override @@ -6265,6 +6351,25 @@ abstract class RenderObjectElement extends Element { assert(_ancestorRenderObjectElement == null); _slot = newSlot; _ancestorRenderObjectElement = _findAncestorRenderObjectElement(); + assert(() { + if (_ancestorRenderObjectElement == null) { + FlutterError.reportError(FlutterErrorDetails(exception: FlutterError.fromParts( + [ + ErrorSummary( + 'The render object for ${toStringShort()} cannot find ancestor render object to attach to.', + ), + ErrorDescription( + 'The ownership chain for the RenderObject in question was:\n ${debugGetCreatorChain(10)}', + ), + ErrorHint( + 'Try wrapping your widget in a View widget or any other widget that is backed by ' + 'a $RenderTreeRootElement to serve as the root of the render tree.', + ), + ] + ))); + } + return true; + }()); _ancestorRenderObjectElement?.insertRenderObjectChild(renderObject, newSlot); final ParentDataElement? parentDataElement = _findAncestorParentDataElement(); if (parentDataElement != null) { @@ -6597,6 +6702,67 @@ class MultiChildRenderObjectElement extends RenderObjectElement { } } +/// A [RenderObjectElement] used to manage the root of a render tree. +/// +/// Unlike any other render object element this element does not attempt to +/// attach its [renderObject] to the closest ancestor [RenderObjectElement]. +/// Instead, subclasses must override [attachRenderObject] and +/// [detachRenderObject] to attach/detach the [renderObject] to whatever +/// instance manages the render tree (e.g. by assigning it to +/// [PipelineOwner.rootNode]). +abstract class RenderTreeRootElement extends RenderObjectElement { + /// Creates an element that uses the given widget as its configuration. + RenderTreeRootElement(super.widget); + + @override + @mustCallSuper + void attachRenderObject(Object? newSlot) { + _slot = newSlot; + assert(_debugCheckMustNotAttachRenderObjectToAncestor()); + } + + @override + @mustCallSuper + void detachRenderObject() { + _slot = null; + } + + @override + void updateSlot(Object? newSlot) { + super.updateSlot(newSlot); + assert(_debugCheckMustNotAttachRenderObjectToAncestor()); + } + + bool _debugCheckMustNotAttachRenderObjectToAncestor() { + if (!kDebugMode) { + return true; + } + if (_findAncestorRenderObjectElement() != null) { + throw FlutterError.fromParts( + [ + ErrorSummary( + 'The RenderObject for ${toStringShort()} cannot maintain an independent render tree at its current location.', + ), + ErrorDescription( + 'The ownership chain for the RenderObject in question was:\n ${debugGetCreatorChain(10)}', + ), + ErrorDescription( + 'This RenderObject is the root of an independent render tree and it cannot ' + 'attach itself to an ancestor in an existing tree. The ancestor RenderObject, ' + 'however, expects that a child will be attached.', + ), + ErrorHint( + 'Try moving the subtree that contains the ${toStringShort()} widget into the ' + 'view property of a ViewAnchor widget or to the root of the widget tree, where ' + 'it is not expected to attach its RenderObject to a parent.', + ), + ], + ); + } + return true; + } +} + /// A wrapper class for the [Element] that is the creator of a [RenderObject]. /// /// Setting a [DebugCreator] as [RenderObject.debugCreator] will lead to better diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart index c51ecf9a1ac4a..24a12d06e7fe3 100644 --- a/packages/flutter/lib/src/widgets/semantics_debugger.dart +++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart @@ -47,25 +47,31 @@ class SemanticsDebugger extends StatefulWidget { } class _SemanticsDebuggerState extends State with WidgetsBindingObserver { - late _SemanticsClient _client; + _SemanticsClient? _client; + PipelineOwner? _pipelineOwner; @override void initState() { super.initState(); - // TODO(abarth): We shouldn't reach out to the WidgetsBinding.instance - // static here because we might not be in a tree that's attached to that - // binding. Instead, we should find a way to get to the PipelineOwner from - // the BuildContext. - _client = _SemanticsClient(WidgetsBinding.instance.pipelineOwner) - ..addListener(_update); WidgetsBinding.instance.addObserver(this); } + @override + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final PipelineOwner newOwner = View.pipelineOwnerOf(context); + if (newOwner != _pipelineOwner) { + _client?.dispose(); + _client = _SemanticsClient(newOwner) + ..addListener(_update); + _pipelineOwner = newOwner; + } + } + @override void dispose() { - _client - ..removeListener(_update) - ..dispose(); + _client?.dispose(); WidgetsBinding.instance.removeObserver(this); super.dispose(); } @@ -145,19 +151,15 @@ class _SemanticsDebuggerState extends State with WidgetsBindi } void _performAction(Offset position, SemanticsAction action) { - _pipelineOwner.semanticsOwner?.performActionAt(position, action); + _pipelineOwner?.semanticsOwner?.performActionAt(position, action); } - // TODO(abarth): This shouldn't be a static. We should get the pipeline owner - // from [context] somehow. - PipelineOwner get _pipelineOwner => WidgetsBinding.instance.pipelineOwner; - @override Widget build(BuildContext context) { return CustomPaint( foregroundPainter: _SemanticsDebuggerPainter( - _pipelineOwner, - _client.generation, + _pipelineOwner!, + _client!.generation, _lastPointerDownLocation, // in physical pixels View.of(context).devicePixelRatio, widget.labelStyle, diff --git a/packages/flutter/lib/src/widgets/view.dart b/packages/flutter/lib/src/widgets/view.dart index 14f87c6d10df0..b25558b6c5464 100644 --- a/packages/flutter/lib/src/widgets/view.dart +++ b/packages/flutter/lib/src/widgets/view.dart @@ -2,48 +2,89 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show FlutterView; +import 'dart:collection'; +import 'dart:ui' show FlutterView, SemanticsUpdate; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; import 'framework.dart'; import 'lookup_boundary.dart'; import 'media_query.dart'; -/// Injects a [FlutterView] into the tree and makes it available to descendants -/// within the same [LookupBoundary] via [View.of] and [View.maybeOf]. +/// Bootstraps a render tree that is rendered into the provided [FlutterView]. +/// +/// The content rendered into that view is determined by the provided [child]. +/// Descendants within the same [LookupBoundary] can look up the view they are +/// rendered into via [View.of] and [View.maybeOf]. /// /// The provided [child] is wrapped in a [MediaQuery] constructed from the given /// [view]. /// -/// In a future version of Flutter, the functionality of this widget will be -/// extended to actually bootstrap the render tree that is going to be rendered -/// into the provided [view]. This will enable rendering content into multiple -/// [FlutterView]s from a single widget tree. -/// /// Each [FlutterView] can be associated with at most one [View] widget in the /// widget tree. Two or more [View] widgets configured with the same /// [FlutterView] must never exist within the same widget tree at the same time. -/// Internally, this limitation is enforced by a [GlobalObjectKey] that derives -/// its identity from the [view] provided to this widget. +/// This limitation is enforced by a [GlobalObjectKey] that derives its identity +/// from the [view] provided to this widget. +/// +/// Since the [View] widget bootstraps its own independent render tree, neither +/// it nor any of its descendants will insert a [RenderObject] into an existing +/// render tree. Therefore, the [View] widget can only be used in those parts of +/// the widget tree where it is not required to participate in the construction +/// of the surrounding render tree. In other words, the widget may only be used +/// in a non-rendering zone of the widget tree (see [WidgetsBinding] for a +/// definition of rendering and non-rendering zones). +/// +/// In practical terms, the widget is typically used at the root of the widget +/// tree outside of any other [View] widget, as a child of a [ViewCollection] +/// widget, or in the [ViewAnchor.view] slot of a [ViewAnchor] widget. It is not +/// required to be a direct child, though, since other non-[RenderObjectWidget]s +/// (e.g. [InheritedWidget]s, [Builder]s, or [StatefulWidget]s/[StatelessWidget] +/// that only produce non-[RenderObjectWidget]s) are allowed to be present +/// between those widgets and the [View] widget. +/// +/// See also: +/// +/// * [Element.debugExpectsRenderObjectForSlot], which defines whether a [View] +/// widget is allowed in a given child slot. class View extends StatelessWidget { - /// Injects the provided [view] into the widget tree. - View({required this.view, required this.child}) : super(key: GlobalObjectKey(view)); + /// Create a [View] widget to bootstrap a render tree that is rendered into + /// the provided [FlutterView]. + /// + /// The content rendered into that [view] is determined by the given [child] + /// widget. + View({ + super.key, + required this.view, + @Deprecated( + 'Do not use. ' + 'This parameter only exists to implement the deprecated RendererBinding.pipelineOwner property until it is removed. ' + 'This feature was deprecated after v3.10.0-12.0.pre.' + ) + PipelineOwner? deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner, + @Deprecated( + 'Do not use. ' + 'This parameter only exists to implement the deprecated RendererBinding.renderView property until it is removed. ' + 'This feature was deprecated after v3.10.0-12.0.pre.' + ) + RenderView? deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView, + required this.child, + }) : _deprecatedPipelineOwner = deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner, + _deprecatedRenderView = deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView, + assert((deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner == null) == (deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView == null)), + assert(deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView == null || deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView.flutterView == view); - /// The [FlutterView] to be injected into the tree. + /// The [FlutterView] into which [child] is drawn. final FlutterView view; + /// The widget below this widget in the tree, which will be drawn into the + /// [view]. + /// /// {@macro flutter.widgets.ProxyWidget.child} final Widget child; - @override - Widget build(BuildContext context) { - return _ViewScope( - view: view, - child: MediaQuery.fromView( - view: view, - child: child, - ), - ); - } + final PipelineOwner? _deprecatedPipelineOwner; + final RenderView? _deprecatedRenderView; /// Returns the [FlutterView] that the provided `context` will render into. /// @@ -106,13 +147,588 @@ class View extends StatelessWidget { }()); return result!; } + + /// Returns the [PipelineOwner] parent to which a child [View] should attach + /// its [PipelineOwner] to. + /// + /// If `context` has a [View] ancestor, it returns the [PipelineOwner] + /// responsible for managing the render tree of that view. If there is no + /// [View] ancestor, [RendererBinding.rootPipelineOwner] is returned instead. + static PipelineOwner pipelineOwnerOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType<_PipelineOwnerScope>()?.pipelineOwner + ?? RendererBinding.instance.rootPipelineOwner; + } + + @override + Widget build(BuildContext context) { + return _RawView( + view: view, + deprecatedPipelineOwner: _deprecatedPipelineOwner, + deprecatedRenderView: _deprecatedRenderView, + builder: (BuildContext context, PipelineOwner owner) { + return _ViewScope( + view: view, + child: _PipelineOwnerScope( + pipelineOwner: owner, + child: MediaQuery.fromView( + view: view, + child: child, + ), + ), + ); + } + ); + } +} + +/// A builder for the content [Widget] of a [_RawView]. +/// +/// The widget returned by the builder defines the content that is drawn into +/// the [FlutterView] configured on the [_RawView]. +/// +/// The builder is given the [PipelineOwner] that the [_RawView] uses to manage +/// its render tree. Typical builder implementations make that pipeline owner +/// available as an attachment point for potential child views. +/// +/// Used by [_RawView.builder]. +typedef _RawViewContentBuilder = Widget Function(BuildContext context, PipelineOwner owner); + +/// The workhorse behind the [View] widget that actually bootstraps a render +/// tree. +/// +/// It instantiates the [RenderView] as the root of that render tree and adds it +/// to the [RendererBinding] via [RendererBinding.addRenderView]. It also owns +/// the [PipelineOwner] that manages this render tree and adds it as a child to +/// the surrounding parent [PipelineOwner] obtained with [View.pipelineOwnerOf]. +/// This ensures that the render tree bootstrapped by this widget participates +/// properly in frame production and hit testing. +class _RawView extends RenderObjectWidget { + /// Create a [RawView] widget to bootstrap a render tree that is rendered into + /// the provided [FlutterView]. + /// + /// The content rendered into that [view] is determined by the [Widget] + /// returned by [builder]. + _RawView({ + required this.view, + required PipelineOwner? deprecatedPipelineOwner, + required RenderView? deprecatedRenderView, + required this.builder, + }) : _deprecatedPipelineOwner = deprecatedPipelineOwner, + _deprecatedRenderView = deprecatedRenderView, + assert(deprecatedRenderView == null || deprecatedRenderView.flutterView == view), + // TODO(goderbauer): Replace this with GlobalObjectKey(view) when the deprecated properties are removed. + super(key: _DeprecatedRawViewKey(view, deprecatedPipelineOwner, deprecatedRenderView)); + + /// The [FlutterView] into which the [Widget] returned by [builder] is drawn. + final FlutterView view; + + /// Determines the content [Widget] that is drawn into the [view]. + /// + /// The [builder] is given the [PipelineOwner] responsible for the render tree + /// bootstrapped by this widget and typically makes it available as an + /// attachment point for potential child views. + final _RawViewContentBuilder builder; + + final PipelineOwner? _deprecatedPipelineOwner; + final RenderView? _deprecatedRenderView; + + @override + RenderObjectElement createElement() => _RawViewElement(this); + + @override + RenderObject createRenderObject(BuildContext context) { + return _deprecatedRenderView ?? RenderView( + view: view, + ); + } + + // No need to implement updateRenderObject: RawView uses the view as a + // GlobalKey, so we never need to update the RenderObject with a new view. +} + +class _RawViewElement extends RenderTreeRootElement { + _RawViewElement(super.widget); + + late final PipelineOwner _pipelineOwner = PipelineOwner( + onSemanticsOwnerCreated: _handleSemanticsOwnerCreated, + onSemanticsUpdate: _handleSemanticsUpdate, + onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed, + ); + + PipelineOwner get _effectivePipelineOwner => (widget as _RawView)._deprecatedPipelineOwner ?? _pipelineOwner; + + void _handleSemanticsOwnerCreated() { + (_effectivePipelineOwner.rootNode as RenderView?)?.scheduleInitialSemantics(); + } + + void _handleSemanticsOwnerDisposed() { + (_effectivePipelineOwner.rootNode as RenderView?)?.clearSemantics(); + } + + void _handleSemanticsUpdate(SemanticsUpdate update) { + (widget as _RawView).view.updateSemantics(update); + } + + @override + RenderView get renderObject => super.renderObject as RenderView; + + Element? _child; + + void _updateChild() { + try { + final Widget child = (widget as _RawView).builder(this, _effectivePipelineOwner); + _child = updateChild(_child, child, null); + } catch (e, stack) { + final FlutterErrorDetails details = FlutterErrorDetails( + exception: e, + stack: stack, + library: 'widgets library', + context: ErrorDescription('building $this'), + informationCollector: !kDebugMode ? null : () => [ + DiagnosticsDebugCreator(DebugCreator(this)), + ], + ); + FlutterError.reportError(details); + final Widget error = ErrorWidget.builder(details); + _child = updateChild(null, error, slot); + } + } + + @override + void mount(Element? parent, Object? newSlot) { + super.mount(parent, newSlot); + assert(_effectivePipelineOwner.rootNode == null); + _effectivePipelineOwner.rootNode = renderObject; + _attachView(); + _updateChild(); + renderObject.prepareInitialFrame(); + if (_effectivePipelineOwner.semanticsOwner != null) { + renderObject.scheduleInitialSemantics(); + } + } + + PipelineOwner? _parentPipelineOwner; // Is null if view is currently not attached. + + void _attachView([PipelineOwner? parentPipelineOwner]) { + assert(_parentPipelineOwner == null); + parentPipelineOwner ??= View.pipelineOwnerOf(this); + parentPipelineOwner.adoptChild(_effectivePipelineOwner); + RendererBinding.instance.addRenderView(renderObject); + _parentPipelineOwner = parentPipelineOwner; + } + + void _detachView() { + final PipelineOwner? parentPipelineOwner = _parentPipelineOwner; + if (parentPipelineOwner != null) { + RendererBinding.instance.removeRenderView(renderObject); + parentPipelineOwner.dropChild(_effectivePipelineOwner); + _parentPipelineOwner = null; + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + if (_parentPipelineOwner == null) { + return; + } + final PipelineOwner newParentPipelineOwner = View.pipelineOwnerOf(this); + if (newParentPipelineOwner != _parentPipelineOwner) { + _detachView(); + _attachView(newParentPipelineOwner); + } + } + + @override + void performRebuild() { + super.performRebuild(); + _updateChild(); + } + + @override + void activate() { + super.activate(); + assert(_effectivePipelineOwner.rootNode == null); + _effectivePipelineOwner.rootNode = renderObject; + _attachView(); + } + + @override + void deactivate() { + _detachView(); + assert(_effectivePipelineOwner.rootNode == renderObject); + _effectivePipelineOwner.rootNode = null; // To satisfy the assert in the super class. + super.deactivate(); + } + + @override + void update(_RawView newWidget) { + super.update(newWidget); + _updateChild(); + } + + @override + void visitChildren(ElementVisitor visitor) { + if (_child != null) { + visitor(_child!); + } + } + + @override + void forgetChild(Element child) { + assert(child == _child); + _child = null; + super.forgetChild(child); + } + + @override + void insertRenderObjectChild(RenderBox child, Object? slot) { + assert(slot == null); + assert(renderObject.debugValidateChild(child)); + renderObject.child = child; + } + + @override + void moveRenderObjectChild(RenderObject child, Object? oldSlot, Object? newSlot) { + assert(false); + } + + @override + void removeRenderObjectChild(RenderObject child, Object? slot) { + assert(slot == null); + assert(renderObject.child == child); + renderObject.child = null; + } + + @override + void unmount() { + if (_effectivePipelineOwner != (widget as _RawView)._deprecatedPipelineOwner) { + _effectivePipelineOwner.dispose(); + } + super.unmount(); + } } class _ViewScope extends InheritedWidget { const _ViewScope({required this.view, required super.child}); - final FlutterView view; + final FlutterView? view; @override bool updateShouldNotify(_ViewScope oldWidget) => view != oldWidget.view; } + +class _PipelineOwnerScope extends InheritedWidget { + const _PipelineOwnerScope({ + required this.pipelineOwner, + required super.child, + }); + + final PipelineOwner pipelineOwner; + + @override + bool updateShouldNotify(_PipelineOwnerScope oldWidget) => pipelineOwner != oldWidget.pipelineOwner; +} + +class _MultiChildComponentWidget extends Widget { + const _MultiChildComponentWidget({ + super.key, + List views = const [], + Widget? child, + }) : _views = views, _child = child; + + // It is up to the subclasses to make the relevant properties public. + final List _views; + final Widget? _child; + + @override + Element createElement() => _MultiChildComponentElement(this); +} + +/// A collection of sibling [View]s. +/// +/// This widget can only be used in places were a [View] widget is allowed, i.e. +/// in a non-rendering zone of the widget tree. In practical terms, it can be +/// used at the root of the widget tree outside of any [View] widget, as a child +/// to a another [ViewCollection], or in the [ViewAnchor.view] slot of a +/// [ViewAnchor] widget. It is not required to be a direct child of those +/// widgets; other non-[RenderObjectWidget]s may appear in between the two (such +/// as an [InheritedWidget]). +/// +/// Similarly, the [views] children of this widget must be [View]s, but they +/// may be wrapped in additional non-[RenderObjectWidget]s (e.g. +/// [InheritedWidget]s). +/// +/// See also: +/// +/// * [WidgetsBinding] for an explanation of rendering and non-rendering zones. +class ViewCollection extends _MultiChildComponentWidget { + /// Creates a [ViewCollection] widget. + /// + /// The provided list of [views] must contain at least one widget. + const ViewCollection({super.key, required super.views}) : assert(views.length > 0); + + /// The [View] descendants of this widget. + /// + /// The [View]s may be wrapped in other non-[RenderObjectWidget]s (e.g. + /// [InheritedWidget]s). However, no [RenderObjectWidget] is allowed to appear + /// between the [ViewCollection] and the next [View] widget. + List get views => _views; +} + +/// Decorates a [child] widget with a side [View]. +/// +/// This widget must have a [View] ancestor, into which the [child] widget +/// is rendered. +/// +/// Typically, a [View] or [ViewCollection] widget is used in the [view] slot to +/// define the content of the side view(s). Those widgets may be wrapped in +/// other non-[RenderObjectWidget]s (e.g. [InheritedWidget]s). However, no +/// [RenderObjectWidget] is allowed to appear between the [ViewAnchor] and the +/// next [View] widget in the [view] slot. The widgets in the [view] slot have +/// access to all [InheritedWidget]s above the [ViewAnchor] in the tree. +/// +/// In technical terms, the [ViewAnchor] can only be used in a rendering zone of +/// the widget tree and the [view] slot marks the start of a new non-rendering +/// zone (see [WidgetsBinding] for a definition of these zones). Typically, +/// it is occupied by a [View] widget, which will start a new rendering zone. +/// +/// {@template flutter.widgets.ViewAnchor} +/// An example use case for this widget is a tooltip for a button. The tooltip +/// should be able to extend beyond the bounds of the main view. For this, the +/// tooltip can be implemented as a separate [View], which is anchored to the +/// button in the main view by wrapping that button with a [ViewAnchor]. In this +/// example, the [view] slot is configured with the tooltip [View] and the +/// [child] is the button widget rendered into the surrounding view. +/// {@endtemplate} +class ViewAnchor extends StatelessWidget { + /// Creates a [ViewAnchor] widget. + const ViewAnchor({ + super.key, + this.view, + required this.child, + }); + + /// The widget that defines the view anchored to this widget. + /// + /// Typically, a [View] or [ViewCollection] widget is used, which may be + /// wrapped in other non-[RenderObjectWidget]s (e.g. [InheritedWidget]s). + /// + /// {@macro flutter.widgets.ViewAnchor} + final Widget? view; + + /// The widget below this widget in the tree. + /// + /// It is rendered into the surrounding view, not in the view defined by + /// [view]. + /// + /// {@macro flutter.widgets.ViewAnchor} + final Widget child; + + @override + Widget build(BuildContext context) { + return _MultiChildComponentWidget( + views: [ + if (view != null) + _ViewScope( + view: null, + child: view!, + ), + ], + child: child, + ); + } +} + +class _MultiChildComponentElement extends Element { + _MultiChildComponentElement(super.widget); + + List _viewElements = []; + final Set _forgottenViewElements = HashSet(); + Element? _childElement; + + bool _debugAssertChildren() { + final _MultiChildComponentWidget typedWidget = widget as _MultiChildComponentWidget; + // Each view widget must have a corresponding element. + assert(_viewElements.length == typedWidget._views.length); + // Iff there is a child widget, it must have a corresponding element. + assert((_childElement == null) == (typedWidget._child == null)); + // The child element is not also a view element. + assert(!_viewElements.contains(_childElement)); + return true; + } + + @override + void attachRenderObject(Object? newSlot) { + super.attachRenderObject(newSlot); + assert(_debugCheckMustAttachRenderObject(newSlot)); + } + + @override + void mount(Element? parent, Object? newSlot) { + super.mount(parent, newSlot); + assert(_debugCheckMustAttachRenderObject(newSlot)); + assert(_viewElements.isEmpty); + assert(_childElement == null); + rebuild(); + assert(_debugAssertChildren()); + } + + @override + void updateSlot(Object? newSlot) { + super.updateSlot(newSlot); + assert(_debugCheckMustAttachRenderObject(newSlot)); + } + + bool _debugCheckMustAttachRenderObject(Object? slot) { + // Check only applies in the ViewCollection configuration. + if (!kDebugMode || (widget as _MultiChildComponentWidget)._child != null) { + return true; + } + bool hasAncestorRenderObjectElement = false; + bool ancestorWantsRenderObject = true; + visitAncestorElements((Element ancestor) { + if (!ancestor.debugExpectsRenderObjectForSlot(slot)) { + ancestorWantsRenderObject = false; + return false; + } + if (ancestor is RenderObjectElement) { + hasAncestorRenderObjectElement = true; + return false; + } + return true; + }); + if (hasAncestorRenderObjectElement && ancestorWantsRenderObject) { + FlutterError.reportError( + FlutterErrorDetails(exception: FlutterError.fromParts( + [ + ErrorSummary( + 'The Element for ${toStringShort()} cannot be inserted into slot "$slot" of its ancestor. ', + ), + ErrorDescription( + 'The ownership chain for the Element in question was:\n ${debugGetCreatorChain(10)}', + ), + ErrorDescription( + 'This Element allows the creation of multiple independent render trees, which cannot ' + 'be attached to an ancestor in an existing render tree. However, an ancestor RenderObject ' + 'is expecting that a child will be attached.' + ), + ErrorHint( + 'Try moving the subtree that contains the ${toStringShort()} widget into the ' + 'view property of a ViewAnchor widget or to the root of the widget tree, where ' + 'it is not expected to attach its RenderObject to its ancestor.', + ), + ], + )), + ); + } + return true; + } + + @override + void update(_MultiChildComponentWidget newWidget) { + // Cannot switch from ViewAnchor config to ViewCollection config. + assert((newWidget._child == null) == ((widget as _MultiChildComponentWidget)._child == null)); + super.update(newWidget); + rebuild(force: true); + assert(_debugAssertChildren()); + } + + static const Object _viewSlot = Object(); + + @override + bool debugExpectsRenderObjectForSlot(Object? slot) => slot != _viewSlot; + + @override + void performRebuild() { + final _MultiChildComponentWidget typedWidget = widget as _MultiChildComponentWidget; + + _childElement = updateChild(_childElement, typedWidget._child, slot); + + final List views = typedWidget._views; + _viewElements = updateChildren( + _viewElements, + views, + forgottenChildren: _forgottenViewElements, + slots: List.generate(views.length, (_) => _viewSlot), + ); + _forgottenViewElements.clear(); + + super.performRebuild(); // clears the dirty flag + assert(_debugAssertChildren()); + } + + @override + void forgetChild(Element child) { + if (child == _childElement) { + _childElement = null; + } else { + assert(_viewElements.contains(child)); + assert(!_forgottenViewElements.contains(child)); + _forgottenViewElements.add(child); + } + super.forgetChild(child); + } + + @override + void visitChildren(ElementVisitor visitor) { + if (_childElement != null) { + visitor(_childElement!); + } + for (final Element child in _viewElements) { + if (!_forgottenViewElements.contains(child)) { + visitor(child); + } + } + } + + @override + bool get debugDoingBuild => false; // This element does not have a concept of "building". + + @override + Element? get renderObjectAttachingChild => _childElement; + + @override + List debugDescribeChildren() { + final List children = []; + if (_childElement != null) { + children.add(_childElement!.toDiagnosticsNode()); + } + for (int i = 0; i < _viewElements.length; i++) { + children.add(_viewElements[i].toDiagnosticsNode( + name: 'view ${i + 1}', + style: DiagnosticsTreeStyle.offstage, + )); + } + return children; + } +} + +// A special [GlobalKey] to support passing the deprecated +// [RendererBinding.renderView] and [RendererBinding.pipelineOwner] to the +// [_RawView]. Will be removed when those deprecated properties are removed. +@optionalTypeArgs +class _DeprecatedRawViewKey> extends GlobalKey { + const _DeprecatedRawViewKey(this.view, this.owner, this.renderView) : super.constructor(); + + final FlutterView view; + final PipelineOwner? owner; + final RenderView? renderView; + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is _DeprecatedRawViewKey + && identical(other.view, view) + && identical(other.owner, owner) + && identical(other.renderView, renderView); + } + + @override + int get hashCode => Object.hash(view, owner, renderView); + + @override + String toString() => '[_DeprecatedRawViewKey ${describeIdentity(view)}]'; +} diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index d4a8c87cafbae..d3ffc09525ea0 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -1103,8 +1103,7 @@ mixin WidgetInspectorService { renderObject.markNeedsPaint(); renderObject.visitChildren(markTreeNeedsPaint); } - final RenderObject root = RendererBinding.instance.renderView; - markTreeNeedsPaint(root); + RendererBinding.instance.renderViews.forEach(markTreeNeedsPaint); } else { debugOnProfilePaint = null; } diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index fd2cf457c4110..092cd82e55154 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -18,6 +18,7 @@ export 'package:vector_math/vector_math_64.dart' show Matrix4; export 'foundation.dart' show UniqueKey; export 'rendering.dart' show TextSelectionHandleType; export 'src/widgets/actions.dart'; +export 'src/widgets/adapter.dart'; export 'src/widgets/animated_cross_fade.dart'; export 'src/widgets/animated_scroll_view.dart'; export 'src/widgets/animated_size.dart'; diff --git a/packages/flutter/test/foundation/service_extensions_test.dart b/packages/flutter/test/foundation/service_extensions_test.dart index 2e524b70d15e1..b97a70a74a6a5 100644 --- a/packages/flutter/test/foundation/service_extensions_test.dart +++ b/packages/flutter/test/foundation/service_extensions_test.dart @@ -117,9 +117,17 @@ Future> hasReassemble(Future> pendingR void main() { final List console = []; + late PipelineOwner owner; setUpAll(() async { - binding = TestServiceExtensionsBinding()..scheduleFrame(); + binding = TestServiceExtensionsBinding(); + final RenderView view = RenderView(view: binding.platformDispatcher.views.single); + owner = PipelineOwner(onSemanticsUpdate: (ui.SemanticsUpdate _) { }) + ..rootNode = view; + binding.rootPipelineOwner.adoptChild(owner); + binding.addRenderView(view); + view.prepareInitialFrame(); + binding.scheduleFrame(); expect(binding.frameScheduled, isTrue); // We need to test this service extension here because the result is true @@ -176,6 +184,10 @@ void main() { expect(console, isEmpty); debugPrint = debugPrintThrottled; + binding.rootPipelineOwner.dropChild(owner); + owner + ..rootNode = null + ..dispose(); }); // The following list is alphabetical, one test per extension. @@ -268,11 +280,13 @@ void main() { await binding.doFrame(); final Map result = await binding.testExtension(RenderingServiceExtensions.debugDumpSemanticsTreeInTraversalOrder.name, {}); - expect(result, { - 'data': 'Semantics not generated.\n' - 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' - 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n' - 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.' + expect(result, { + 'data': matches( + r'Semantics not generated for RenderView#[0-9a-f]{5}\.\n' + r'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' + r'Usually, platforms only ask for semantics when assistive technologies \(like screen readers\) are running.\n' + r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.' + ) }); }); @@ -280,11 +294,13 @@ void main() { await binding.doFrame(); final Map result = await binding.testExtension(RenderingServiceExtensions.debugDumpSemanticsTreeInInverseHitTestOrder.name, {}); - expect(result, { - 'data': 'Semantics not generated.\n' - 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' - 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n' - 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.' + expect(result, { + 'data': matches( + r'Semantics not generated for RenderView#[0-9a-f]{5}\.\n' + r'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' + r'Usually, platforms only ask for semantics when assistive technologies \(like screen readers\) are running.\n' + r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.' + ) }); }); diff --git a/packages/flutter/test/rendering/binding_pipeline_manifold_test.dart b/packages/flutter/test/rendering/binding_pipeline_manifold_test.dart index 5374454db90be..81d79a5a82e34 100644 --- a/packages/flutter/test/rendering/binding_pipeline_manifold_test.dart +++ b/packages/flutter/test/rendering/binding_pipeline_manifold_test.dart @@ -13,20 +13,20 @@ void main() { tearDown(() { final List children = []; - RendererBinding.instance.pipelineOwner.visitChildren((PipelineOwner child) { + RendererBinding.instance.rootPipelineOwner.visitChildren((PipelineOwner child) { children.add(child); }); - children.forEach(RendererBinding.instance.pipelineOwner.dropChild); + children.forEach(RendererBinding.instance.rootPipelineOwner.dropChild); }); test("BindingPipelineManifold notifies binding if render object managed by binding's PipelineOwner tree needs visual update", () { final PipelineOwner child = PipelineOwner(); - RendererBinding.instance.pipelineOwner.adoptChild(child); + RendererBinding.instance.rootPipelineOwner.adoptChild(child); final RenderObject renderObject = TestRenderObject(); child.rootNode = renderObject; renderObject.scheduleInitialLayout(); - RendererBinding.instance.pipelineOwner.flushLayout(); + RendererBinding.instance.rootPipelineOwner.flushLayout(); MyTestRenderingFlutterBinding.instance.ensureVisualUpdateCount = 0; renderObject.markNeedsLayout(); @@ -37,20 +37,20 @@ void main() { final PipelineOwner child = PipelineOwner( onSemanticsUpdate: (_) { }, ); - RendererBinding.instance.pipelineOwner.adoptChild(child); + RendererBinding.instance.rootPipelineOwner.adoptChild(child); expect(child.semanticsOwner, isNull); - expect(RendererBinding.instance.pipelineOwner.semanticsOwner, isNull); + expect(RendererBinding.instance.rootPipelineOwner.semanticsOwner, isNull); final SemanticsHandle handle = SemanticsBinding.instance.ensureSemantics(); expect(child.semanticsOwner, isNotNull); - expect(RendererBinding.instance.pipelineOwner.semanticsOwner, isNotNull); + expect(RendererBinding.instance.rootPipelineOwner.semanticsOwner, isNotNull); handle.dispose(); expect(child.semanticsOwner, isNull); - expect(RendererBinding.instance.pipelineOwner.semanticsOwner, isNull); + expect(RendererBinding.instance.rootPipelineOwner.semanticsOwner, isNull); }); } diff --git a/packages/flutter/test/rendering/binding_test.dart b/packages/flutter/test/rendering/binding_test.dart index 80495aa264c02..67cc00b998dac 100644 --- a/packages/flutter/test/rendering/binding_test.dart +++ b/packages/flutter/test/rendering/binding_test.dart @@ -10,29 +10,48 @@ import 'package:flutter_test/flutter_test.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); - test('handleMetricsChanged does not scheduleForcedFrame unless there is a child to the renderView', () async { + test('handleMetricsChanged does not scheduleForcedFrame unless there a registered renderView with a child', () async { expect(SchedulerBinding.instance.hasScheduledFrame, false); RendererBinding.instance.handleMetricsChanged(); expect(SchedulerBinding.instance.hasScheduledFrame, false); + RendererBinding.instance.addRenderView(RendererBinding.instance.renderView); + RendererBinding.instance.handleMetricsChanged(); + expect(SchedulerBinding.instance.hasScheduledFrame, false); + RendererBinding.instance.renderView.child = RenderLimitedBox(); RendererBinding.instance.handleMetricsChanged(); expect(SchedulerBinding.instance.hasScheduledFrame, true); + + RendererBinding.instance.removeRenderView(RendererBinding.instance.renderView); }); test('debugDumpSemantics prints explanation when semantics are unavailable', () { + RendererBinding.instance.addRenderView(RendererBinding.instance.renderView); final List log = []; debugPrint = (String? message, {int? wrapWidth}) { log.add(message); }; debugDumpSemanticsTree(); expect(log, hasLength(1)); + expect(log.single, startsWith('Semantics not generated')); + expect(log.single, endsWith( + 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' + 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n' + 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.' + )); + RendererBinding.instance.removeRenderView(RendererBinding.instance.renderView); + }); + + test('root pipeline owner cannot manage root node', () { + final RenderObject rootNode = RenderProxyBox(); expect( - log.single, - 'Semantics not generated.\n' - 'For performance reasons, the framework only generates semantics when asked to do so by the platform.\n' - 'Usually, platforms only ask for semantics when assistive technologies (like screen readers) are running.\n' - 'To generate semantics, try turning on an assistive technology (like VoiceOver or TalkBack) on your device.' + () => RendererBinding.instance.rootPipelineOwner.rootNode = rootNode, + throwsA(isFlutterError.having( + (FlutterError e) => e.message, + 'message', + contains('Cannot set a rootNode on the default root pipeline owner.'), + )), ); }); } diff --git a/packages/flutter/test/rendering/mouse_tracker_test_utils.dart b/packages/flutter/test/rendering/mouse_tracker_test_utils.dart index 1f9c5bfe052dc..eb81870be9c7c 100644 --- a/packages/flutter/test/rendering/mouse_tracker_test_utils.dart +++ b/packages/flutter/test/rendering/mouse_tracker_test_utils.dart @@ -32,8 +32,21 @@ class TestMouseTrackerFlutterBinding extends BindingBase postFrameCallbacks = []; } + late final RenderView _renderView = RenderView( + view: platformDispatcher.implicitView!, + ); + + late final PipelineOwner _pipelineOwner = PipelineOwner( + onSemanticsUpdate: (ui.SemanticsUpdate _) { assert(false); }, + ); + void setHitTest(BoxHitTest hitTest) { - renderView.child = _TestHitTester(hitTest); + if (_pipelineOwner.rootNode == null) { + _pipelineOwner.rootNode = _renderView; + rootPipelineOwner.adoptChild(_pipelineOwner); + addRenderView(_renderView); + } + _renderView.child = _TestHitTester(hitTest); } SchedulerPhase? _overridePhase; diff --git a/packages/flutter/test/rendering/multi_view_binding_test.dart b/packages/flutter/test/rendering/multi_view_binding_test.dart new file mode 100644 index 0000000000000..9a57757975895 --- /dev/null +++ b/packages/flutter/test/rendering/multi_view_binding_test.dart @@ -0,0 +1,208 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + final RendererBinding binding = RenderingFlutterBinding.ensureInitialized(); + + test('Adding/removing renderviews updates renderViews getter', () { + final FlutterView flutterView = FakeFlutterView(); + final RenderView view = RenderView(view: flutterView); + + expect(binding.renderViews, isEmpty); + binding.addRenderView(view); + expect(binding.renderViews, contains(view)); + expect(view.configuration.devicePixelRatio, flutterView.devicePixelRatio); + expect(view.configuration.size, flutterView.physicalSize / flutterView.devicePixelRatio); + + binding.removeRenderView(view); + expect(binding.renderViews, isEmpty); + }); + + test('illegal add/remove renderviews', () { + final FlutterView flutterView = FakeFlutterView(); + final RenderView view1 = RenderView(view: flutterView); + final RenderView view2 = RenderView(view: flutterView); + final RenderView view3 = RenderView(view: FakeFlutterView(viewId: 200)); + + expect(binding.renderViews, isEmpty); + binding.addRenderView(view1); + expect(binding.renderViews, contains(view1)); + + expect(() => binding.addRenderView(view1), throwsAssertionError); + expect(() => binding.addRenderView(view2), throwsAssertionError); + expect(() => binding.removeRenderView(view2), throwsAssertionError); + expect(() => binding.removeRenderView(view3), throwsAssertionError); + + expect(binding.renderViews, contains(view1)); + binding.removeRenderView(view1); + expect(binding.renderViews, isEmpty); + expect(() => binding.removeRenderView(view1), throwsAssertionError); + expect(() => binding.removeRenderView(view2), throwsAssertionError); + }); + + test('changing metrics updates configuration', () { + final FakeFlutterView flutterView = FakeFlutterView(); + final RenderView view = RenderView(view: flutterView); + binding.addRenderView(view); + expect(view.configuration.devicePixelRatio, 2.5); + expect(view.configuration.size, const Size(160.0, 240.0)); + + flutterView.devicePixelRatio = 3.0; + flutterView.physicalSize = const Size(300, 300); + binding.handleMetricsChanged(); + expect(view.configuration.devicePixelRatio, 3.0); + expect(view.configuration.size, const Size(100.0, 100.0)); + + binding.removeRenderView(view); + }); + + test('semantics actions are performed on the right view', () { + final FakeFlutterView flutterView1 = FakeFlutterView(viewId: 1); + final FakeFlutterView flutterView2 = FakeFlutterView(viewId: 2); + final RenderView renderView1 = RenderView(view: flutterView1); + final RenderView renderView2 = RenderView(view: flutterView2); + final PipelineOwnerSpy owner1 = PipelineOwnerSpy() + ..rootNode = renderView1; + final PipelineOwnerSpy owner2 = PipelineOwnerSpy() + ..rootNode = renderView2; + + binding.addRenderView(renderView1); + binding.addRenderView(renderView2); + + binding.performSemanticsAction( + const SemanticsActionEvent(type: SemanticsAction.copy, viewId: 1, nodeId: 11), + ); + expect(owner1.semanticsOwner.performedActions.single, (11, SemanticsAction.copy, null)); + expect(owner2.semanticsOwner.performedActions, isEmpty); + owner1.semanticsOwner.performedActions.clear(); + + binding.performSemanticsAction( + const SemanticsActionEvent(type: SemanticsAction.tap, viewId: 2, nodeId: 22), + ); + expect(owner1.semanticsOwner.performedActions, isEmpty); + expect(owner2.semanticsOwner.performedActions.single, (22, SemanticsAction.tap, null)); + owner2.semanticsOwner.performedActions.clear(); + + binding.performSemanticsAction( + const SemanticsActionEvent(type: SemanticsAction.tap, viewId: 3, nodeId: 22), + ); + expect(owner1.semanticsOwner.performedActions, isEmpty); + expect(owner2.semanticsOwner.performedActions, isEmpty); + + binding.removeRenderView(renderView1); + binding.removeRenderView(renderView2); + }); + + test('all registered renderviews are asked to composite frame', () { + final FakeFlutterView flutterView1 = FakeFlutterView(viewId: 1); + final FakeFlutterView flutterView2 = FakeFlutterView(viewId: 2); + final RenderView renderView1 = RenderView(view: flutterView1); + final RenderView renderView2 = RenderView(view: flutterView2); + final PipelineOwner owner1 = PipelineOwner()..rootNode = renderView1; + final PipelineOwner owner2 = PipelineOwner()..rootNode = renderView2; + binding.rootPipelineOwner.adoptChild(owner1); + binding.rootPipelineOwner.adoptChild(owner2); + binding.addRenderView(renderView1); + binding.addRenderView(renderView2); + renderView1.prepareInitialFrame(); + renderView2.prepareInitialFrame(); + + expect(flutterView1.renderedScenes, isEmpty); + expect(flutterView2.renderedScenes, isEmpty); + + binding.handleBeginFrame(Duration.zero); + binding.handleDrawFrame(); + + expect(flutterView1.renderedScenes, hasLength(1)); + expect(flutterView2.renderedScenes, hasLength(1)); + + binding.removeRenderView(renderView1); + + binding.handleBeginFrame(Duration.zero); + binding.handleDrawFrame(); + + expect(flutterView1.renderedScenes, hasLength(1)); + expect(flutterView2.renderedScenes, hasLength(2)); + + binding.removeRenderView(renderView2); + + binding.handleBeginFrame(Duration.zero); + binding.handleDrawFrame(); + + expect(flutterView1.renderedScenes, hasLength(1)); + expect(flutterView2.renderedScenes, hasLength(2)); + }); + + test('hit-testing reaches the right view', () { + final FakeFlutterView flutterView1 = FakeFlutterView(viewId: 1); + final FakeFlutterView flutterView2 = FakeFlutterView(viewId: 2); + final RenderView renderView1 = RenderView(view: flutterView1); + final RenderView renderView2 = RenderView(view: flutterView2); + binding.addRenderView(renderView1); + binding.addRenderView(renderView2); + + HitTestResult result = HitTestResult(); + binding.hitTestInView(result, Offset.zero, 1); + expect(result.path, hasLength(2)); + expect(result.path.first.target, renderView1); + expect(result.path.last.target, binding); + + result = HitTestResult(); + binding.hitTestInView(result, Offset.zero, 2); + expect(result.path, hasLength(2)); + expect(result.path.first.target, renderView2); + expect(result.path.last.target, binding); + + result = HitTestResult(); + binding.hitTestInView(result, Offset.zero, 3); + expect(result.path.single.target, binding); + + binding.removeRenderView(renderView1); + binding.removeRenderView(renderView2); + }); +} + +class FakeFlutterView extends Fake implements FlutterView { + FakeFlutterView({ + this.viewId = 100, + this.devicePixelRatio = 2.5, + this.physicalSize = const Size(400,600), + this.padding = FakeViewPadding.zero, + }); + + @override + final int viewId; + @override + double devicePixelRatio; + @override + Size physicalSize; + @override + ViewPadding padding; + + List renderedScenes = []; + + @override + void render(Scene scene) { + renderedScenes.add(scene); + } +} + +class PipelineOwnerSpy extends PipelineOwner { + @override + final SemanticsOwnerSpy semanticsOwner = SemanticsOwnerSpy(); +} + +class SemanticsOwnerSpy extends Fake implements SemanticsOwner { + final List<(int, SemanticsAction, Object?)> performedActions = <(int, SemanticsAction, Object?)>[]; + + @override + void performAction(int id, SemanticsAction action, [ Object? args ]) { + performedActions.add((id, action, args)); + } +} diff --git a/packages/flutter/test/rendering/pipeline_owner_tree_test.dart b/packages/flutter/test/rendering/pipeline_owner_tree_test.dart index 5c2368dee5a7a..2f997ea7c670e 100644 --- a/packages/flutter/test/rendering/pipeline_owner_tree_test.dart +++ b/packages/flutter/test/rendering/pipeline_owner_tree_test.dart @@ -678,20 +678,43 @@ void main() { expect(root.semanticsOwner, isNotNull); expect(child.semanticsOwner, isNotNull); - expect(childOfChild.semanticsOwner, isNull); + expect(childOfChild.semanticsOwner, isNotNull); // Retained in case we get re-attached. final SemanticsHandle childSemantics = child.ensureSemantics(); root.dropChild(child); expect(root.semanticsOwner, isNotNull); expect(child.semanticsOwner, isNotNull); - expect(childOfChild.semanticsOwner, isNull); + expect(childOfChild.semanticsOwner, isNotNull); // Retained in case we get re-attached. childSemantics.dispose(); expect(root.semanticsOwner, isNotNull); expect(child.semanticsOwner, isNull); - expect(childOfChild.semanticsOwner, isNull); + expect(childOfChild.semanticsOwner, isNotNull); + + manifold.semanticsEnabled = false; + + expect(root.semanticsOwner, isNull); + expect(childOfChild.semanticsOwner, isNotNull); + + root.adoptChild(childOfChild); + expect(root.semanticsOwner, isNull); + expect(childOfChild.semanticsOwner, isNull); // Disposed on re-attachment. + + manifold.semanticsEnabled = true; + expect(root.semanticsOwner, isNotNull); + expect(childOfChild.semanticsOwner, isNotNull); + + root.dropChild(childOfChild); + + expect(root.semanticsOwner, isNotNull); + expect(childOfChild.semanticsOwner, isNotNull); + + childOfChild.dispose(); + + expect(root.semanticsOwner, isNotNull); + expect(childOfChild.semanticsOwner, isNull); // Disposed on dispose. }); test('can adopt/drop children during own layout', () { @@ -789,6 +812,38 @@ void main() { }); expect(children.single, childOfChild3); }); + + test('printing pipeline owner tree smoke test', () { + final PipelineOwner root = PipelineOwner(); + final PipelineOwner child1 = PipelineOwner() + ..rootNode = FakeRenderView(); + final PipelineOwner childOfChild1 = PipelineOwner() + ..rootNode = FakeRenderView(); + final PipelineOwner child2 = PipelineOwner() + ..rootNode = FakeRenderView(); + final PipelineOwner childOfChild2 = PipelineOwner() + ..rootNode = FakeRenderView(); + + root.adoptChild(child1); + child1.adoptChild(childOfChild1); + root.adoptChild(child2); + child2.adoptChild(childOfChild2); + + expect(root.toStringDeep(), equalsIgnoringHashCodes( + 'PipelineOwner#00000\n' + ' ├─PipelineOwner#00000\n' + ' │ │ rootNode: FakeRenderView#00000 NEEDS-LAYOUT NEEDS-PAINT\n' + ' │ │\n' + ' │ └─PipelineOwner#00000\n' + ' │ rootNode: FakeRenderView#00000 NEEDS-LAYOUT NEEDS-PAINT\n' + ' │\n' + ' └─PipelineOwner#00000\n' + ' │ rootNode: FakeRenderView#00000 NEEDS-LAYOUT NEEDS-PAINT\n' + ' │\n' + ' └─PipelineOwner#00000\n' + ' rootNode: FakeRenderView#00000 NEEDS-LAYOUT NEEDS-PAINT\n' + )); + }); } class TestPipelineManifold extends ChangeNotifier implements PipelineManifold { @@ -860,3 +915,5 @@ List _treeWalk(PipelineOwner root) { root.visitChildren(visitor); return results; } + +class FakeRenderView extends RenderBox { } diff --git a/packages/flutter/test/rendering/platform_view_test.dart b/packages/flutter/test/rendering/platform_view_test.dart index baee5bc54586d..c6ab6cc9b54f0 100644 --- a/packages/flutter/test/rendering/platform_view_test.dart +++ b/packages/flutter/test/rendering/platform_view_test.dart @@ -47,10 +47,10 @@ void main() { child: platformViewRenderBox, ); int semanticsUpdateCount = 0; - final SemanticsHandle semanticsHandle = TestRenderingFlutterBinding.instance.pipelineOwner.ensureSemantics( - listener: () { - ++semanticsUpdateCount; - }, + final SemanticsHandle semanticsHandle = TestRenderingFlutterBinding.instance.rootPipelineOwner.ensureSemantics( + listener: () { + ++semanticsUpdateCount; + }, ); layout(tree, phase: EnginePhase.flushSemantics); // Initial semantics update diff --git a/packages/flutter/test/rendering/rendering_tester.dart b/packages/flutter/test/rendering/rendering_tester.dart index 7e8d0e6c1dde7..6ebfc38f4de22 100644 --- a/packages/flutter/test/rendering/rendering_tester.dart +++ b/packages/flutter/test/rendering/rendering_tester.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:ui' show SemanticsUpdate; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -43,6 +44,44 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser void initInstances() { super.initInstances(); _instance = this; + // TODO(goderbauer): Create (fake) window if embedder doesn't provide an implicit view. + assert(platformDispatcher.implicitView != null); + _renderView = initRenderView(platformDispatcher.implicitView!); + } + + @override + RenderView get renderView => _renderView; + late RenderView _renderView; + + @override + PipelineOwner get pipelineOwner => rootPipelineOwner; + + /// Creates a [RenderView] object to be the root of the + /// [RenderObject] rendering tree, and initializes it so that it + /// will be rendered when the next frame is requested. + /// + /// Called automatically when the binding is created. + RenderView initRenderView(FlutterView view) { + final RenderView renderView = RenderView(view: view); + rootPipelineOwner.rootNode = renderView; + addRenderView(renderView); + renderView.prepareInitialFrame(); + return renderView; + } + + @override + PipelineOwner createRootPipelineOwner() { + return PipelineOwner( + onSemanticsOwnerCreated: () { + renderView.scheduleInitialSemantics(); + }, + onSemanticsUpdate: (SemanticsUpdate update) { + renderView.updateSemantics(update); + }, + onSemanticsOwnerDisposed: () { + renderView.clearSemantics(); + }, + ); } /// Creates and initializes the binding. This function is @@ -139,23 +178,25 @@ class TestRenderingFlutterBinding extends BindingBase with SchedulerBinding, Ser final FlutterExceptionHandler? oldErrorHandler = FlutterError.onError; FlutterError.onError = _errors.add; try { - pipelineOwner.flushLayout(); + rootPipelineOwner.flushLayout(); if (phase == EnginePhase.layout) { return; } - pipelineOwner.flushCompositingBits(); + rootPipelineOwner.flushCompositingBits(); if (phase == EnginePhase.compositingBits) { return; } - pipelineOwner.flushPaint(); + rootPipelineOwner.flushPaint(); if (phase == EnginePhase.paint) { return; } - renderView.compositeFrame(); + for (final RenderView renderView in renderViews) { + renderView.compositeFrame(); + } if (phase == EnginePhase.composite) { return; } - pipelineOwner.flushSemantics(); + rootPipelineOwner.flushSemantics(); if (phase == EnginePhase.flushSemantics) { return; } diff --git a/packages/flutter/test/rendering/view_test.dart b/packages/flutter/test/rendering/view_test.dart index a3367a691fbef..6344c7a53b3b2 100644 --- a/packages/flutter/test/rendering/view_test.dart +++ b/packages/flutter/test/rendering/view_test.dart @@ -122,6 +122,16 @@ void main() { isNot(paintsGreenRect), ); }); + + test('Config can be set and changed after instantiation without calling prepareInitialFrame first', () { + final RenderView view = RenderView( + view: RendererBinding.instance.platformDispatcher.views.single, + ); + view.configuration = const ViewConfiguration(size: Size(100, 200), devicePixelRatio: 3.0); + view.configuration = const ViewConfiguration(size: Size(200, 300), devicePixelRatio: 2.0); + PipelineOwner().rootNode = view; + view.prepareInitialFrame(); + }); } const Color orange = Color(0xFFFF9000); diff --git a/packages/flutter/test/scheduler/benchmarks_test.dart b/packages/flutter/test/scheduler/benchmarks_test.dart index 9578ba74c4938..ec9c03b54a2f8 100644 --- a/packages/flutter/test/scheduler/benchmarks_test.dart +++ b/packages/flutter/test/scheduler/benchmarks_test.dart @@ -42,7 +42,7 @@ void main() { await benchmarkWidgets( (WidgetTester tester) async { const Key root = Key('root'); - binding.attachRootWidget(Container(key: root)); + binding.attachRootWidget(binding.wrapWithDefaultView(Container(key: root))); await tester.pump(); expect(binding.framesBegun, greaterThan(0)); diff --git a/packages/flutter/test/widgets/container_test.dart b/packages/flutter/test/widgets/container_test.dart index 7c327bc975466..37f08221419fe 100644 --- a/packages/flutter/test/widgets/container_test.dart +++ b/packages/flutter/test/widgets/container_test.dart @@ -156,8 +156,9 @@ void main() { equalsIgnoringHashCodes( 'RenderPadding#00000 relayoutBoundary=up1\n' ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ size: Size(63.0, 88.0)\n' @@ -165,8 +166,9 @@ void main() { ' │\n' ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope ←\n' + ' │ _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' ' │ size: Size(53.0, 78.0)\n' @@ -174,8 +176,9 @@ void main() { ' │\n' ' └─child: RenderDecoratedBox#00000\n' ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' - ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ Align ← MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope\n' + ' │ ← _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ size: Size(53.0, 78.0)\n' @@ -188,8 +191,9 @@ void main() { ' └─child: _RenderColoredBox#00000\n' ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' - ' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' + ' │ _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ ⋯\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ size: Size(53.0, 78.0)\n' @@ -198,8 +202,8 @@ void main() { ' └─child: RenderPadding#00000\n' ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' - ' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' + ' │ ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← ⋯\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ size: Size(53.0, 78.0)\n' @@ -208,8 +212,7 @@ void main() { ' └─child: RenderPositionedBox#00000\n' ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← ⋯\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ← ⋯\n' ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' ' │ size: Size(39.0, 64.0)\n' @@ -220,7 +223,7 @@ void main() { ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← ⋯\n' ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' ' │ size: Size(25.0, 33.0)\n' @@ -255,8 +258,9 @@ void main() { equalsIgnoringHashCodes( 'RenderPadding#00000 relayoutBoundary=up1\n' ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ layer: null\n' @@ -267,8 +271,9 @@ void main() { ' │\n' ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope ←\n' + ' │ _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' ' │ layer: null\n' @@ -278,8 +283,9 @@ void main() { ' │\n' ' └─child: RenderDecoratedBox#00000\n' ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' - ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ Align ← MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope\n' + ' │ ← _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ layer: null\n' @@ -300,8 +306,9 @@ void main() { ' └─child: _RenderColoredBox#00000\n' ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' - ' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' + ' │ _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ ⋯\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ layer: null\n' @@ -312,8 +319,8 @@ void main() { ' └─child: RenderPadding#00000\n' ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' - ' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' + ' │ ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← ⋯\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ layer: null\n' @@ -325,8 +332,7 @@ void main() { ' └─child: RenderPositionedBox#00000\n' ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← ⋯\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ← ⋯\n' ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' ' │ layer: null\n' @@ -340,7 +346,7 @@ void main() { ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up1\n' ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← ⋯\n' ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' ' │ layer: null\n' @@ -367,7 +373,7 @@ void main() { ' shape: rectangle\n' ' configuration: ImageConfiguration(bundle:\n' ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' android)\n', + ' android)\n' ), ); }); @@ -386,8 +392,9 @@ void main() { 'RenderPadding#00000 relayoutBoundary=up1\n' ' │ needsCompositing: false\n' ' │ creator: Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ layer: null\n' @@ -401,8 +408,9 @@ void main() { ' └─child: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' │ needsCompositing: false\n' ' │ creator: ConstrainedBox ← Padding ← Container ← Align ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope ←\n' + ' │ _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: offset=Offset(5.0, 5.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=790.0, 0.0<=h<=590.0)\n' ' │ layer: null\n' @@ -415,8 +423,9 @@ void main() { ' └─child: RenderDecoratedBox#00000\n' ' │ needsCompositing: false\n' ' │ creator: DecoratedBox ← ConstrainedBox ← Padding ← Container ←\n' - ' │ Align ← MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ Align ← MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope\n' + ' │ ← _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ layer: null\n' @@ -440,8 +449,9 @@ void main() { ' │ needsCompositing: false\n' ' │ creator: ColoredBox ← DecoratedBox ← ConstrainedBox ← Padding ←\n' ' │ Container ← Align ← MediaQuery ← _MediaQueryFromView ←\n' - ' │ _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' + ' │ _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ ⋯\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ layer: null\n' @@ -455,8 +465,8 @@ void main() { ' │ needsCompositing: false\n' ' │ creator: Padding ← ColoredBox ← DecoratedBox ← ConstrainedBox ←\n' ' │ Padding ← Container ← Align ← MediaQuery ← _MediaQueryFromView\n' - ' │ ← _ViewScope ← View-[GlobalObjectKey TestFlutterView#00000] ←\n' - ' │ [root]\n' + ' │ ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← ⋯\n' ' │ parentData: (can use size)\n' ' │ constraints: BoxConstraints(w=53.0, h=78.0)\n' ' │ layer: null\n' @@ -471,8 +481,7 @@ void main() { ' │ needsCompositing: false\n' ' │ creator: Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← ⋯\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ← ⋯\n' ' │ parentData: offset=Offset(7.0, 7.0) (can use size)\n' ' │ constraints: BoxConstraints(w=39.0, h=64.0)\n' ' │ layer: null\n' @@ -489,7 +498,7 @@ void main() { ' │ needsCompositing: false\n' ' │ creator: SizedBox ← Align ← Padding ← ColoredBox ← DecoratedBox ←\n' ' │ ConstrainedBox ← Padding ← Container ← Align ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← ⋯\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← ⋯\n' ' │ parentData: offset=Offset(14.0, 31.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=39.0, 0.0<=h<=64.0)\n' ' │ layer: null\n' @@ -521,7 +530,7 @@ void main() { ' shape: rectangle\n' ' configuration: ImageConfiguration(bundle:\n' ' PlatformAssetBundle#00000(), devicePixelRatio: 3.0, platform:\n' - ' android)\n', + ' android)\n' ), ); }); diff --git a/packages/flutter/test/widgets/custom_multi_child_layout_test.dart b/packages/flutter/test/widgets/custom_multi_child_layout_test.dart index 0a6db8b1c85b6..a12887496a040 100644 --- a/packages/flutter/test/widgets/custom_multi_child_layout_test.dart +++ b/packages/flutter/test/widgets/custom_multi_child_layout_test.dart @@ -373,8 +373,9 @@ void main() { ' The following child has no ID: RenderConstrainedBox#00000 NEEDS-LAYOUT NEEDS-PAINT:\n' ' creator: ConstrainedBox ← Container ← LayoutWithMissingId ←\n' ' CustomMultiChildLayout ← Center ← MediaQuery ←\n' - ' _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' TestFlutterView#00000] ← [root]\n' + ' _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ←\n' + ' _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' [root]\n' ' parentData: offset=Offset(0.0, 0.0); id=null\n' ' constraints: MISSING\n' ' size: MISSING\n' diff --git a/packages/flutter/test/widgets/debug_test.dart b/packages/flutter/test/widgets/debug_test.dart index a98f70fe4ff59..8ae59d0aa05a7 100644 --- a/packages/flutter/test/widgets/debug_test.dart +++ b/packages/flutter/test/widgets/debug_test.dart @@ -144,7 +144,10 @@ void main() { ), ); } - return Container(); + return View( + view: tester.view, + child: const SizedBox(), + ); }, ), ); diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 1589bac4e9d2c..0a49b56f4ece9 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -1227,8 +1227,9 @@ void main() { 'FocusManager#00000\n' ' │ primaryFocus: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n' ' │ primaryFocusCreator: Container-[GlobalKey#00000] ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ [root]\n' ' │\n' ' └─rootScope: FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n' ' │ IN FOCUS PATH\n' diff --git a/packages/flutter/test/widgets/init_state_test.dart b/packages/flutter/test/widgets/init_state_test.dart index e70267e55e6d5..d6b74a256d30b 100644 --- a/packages/flutter/test/widgets/init_state_test.dart +++ b/packages/flutter/test/widgets/init_state_test.dart @@ -30,7 +30,7 @@ class TestWidgetState extends State { void main() { testWidgets('initState() is called when we are in the tree', (WidgetTester tester) async { await tester.pumpWidget(const Parent(child: TestWidget())); - expect(ancestors, containsAllInOrder(['Parent', 'View', 'RenderObjectToWidgetAdapter'])); + expect(ancestors, containsAllInOrder(['Parent', 'View', 'RootWidget'])); }); } diff --git a/packages/flutter/test/widgets/keep_alive_test.dart b/packages/flutter/test/widgets/keep_alive_test.dart index a92e9b24ca934..b25a14d45d677 100644 --- a/packages/flutter/test/widgets/keep_alive_test.dart +++ b/packages/flutter/test/widgets/keep_alive_test.dart @@ -205,7 +205,7 @@ void main() { ); // The important lines below are the ones marked with "<----" expect(tester.binding.renderView.toStringDeep(minLevel: DiagnosticLevel.info), equalsIgnoringHashCodes( - 'RenderView#00000\n' + '_ReusableRenderView#00000\n' ' │ debug mode enabled - ${Platform.operatingSystem}\n' ' │ view size: Size(2400.0, 1800.0) (in physical pixels)\n' ' │ device pixel ratio: 3.0 (physical pixels per logical pixel)\n' @@ -379,7 +379,7 @@ void main() { await tester.drag(find.byType(ListView), const Offset(0.0, -1000.0)); await tester.pump(); expect(tester.binding.renderView.toStringDeep(minLevel: DiagnosticLevel.info), equalsIgnoringHashCodes( - 'RenderView#00000\n' + '_ReusableRenderView#00000\n' ' │ debug mode enabled - ${Platform.operatingSystem}\n' ' │ view size: Size(2400.0, 1800.0) (in physical pixels)\n' ' │ device pixel ratio: 3.0 (physical pixels per logical pixel)\n' diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 135f284ac9690..2a24e45ca0726 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -44,26 +44,25 @@ class _MediaQueryAspectVariant extends TestVariant<_MediaQueryAspectCase> { void main() { testWidgets('MediaQuery does not have a default', (WidgetTester tester) async { - bool tested = false; + late final FlutterError error; // Cannot use tester.pumpWidget here because it wraps the widget in a View, // which introduces a MediaQuery ancestor. await pumpWidgetWithoutViewWrapper( tester: tester, widget: Builder( builder: (BuildContext context) { - tested = true; - MediaQuery.of(context); // should throw - return Container(); + try { + MediaQuery.of(context); + } on FlutterError catch (e) { + error = e; + } + return View( + view: tester.view, + child: const SizedBox(), + ); }, ), ); - expect(tested, isTrue); - final dynamic exception = tester.takeException(); - expect(exception, isNotNull); - expect(exception ,isFlutterError); - final FlutterError error = exception as FlutterError; - expect(error.diagnostics.length, 5); - expect(error.diagnostics.last, isA()); expect( error.toStringDeep(), startsWith( @@ -119,7 +118,10 @@ void main() { final MediaQueryData? data = MediaQuery.maybeOf(context); expect(data, isNull); tested = true; - return Container(); + return View( + view: tester.view, + child: const SizedBox(), + ); }, ), ); @@ -295,7 +297,10 @@ void main() { child: Builder( builder: (BuildContext context) { data = MediaQuery.of(context); - return const Placeholder(); + return View( + view: tester.view, + child: const SizedBox(), + ); }, ) ); @@ -348,7 +353,10 @@ void main() { builder: (BuildContext context) { rebuildCount++; data = MediaQuery.of(context); - return const Placeholder(); + return View( + view: tester.view, + child: const SizedBox(), + ); }, ), ); diff --git a/packages/flutter/test/widgets/multi_view_binding_test.dart b/packages/flutter/test/widgets/multi_view_binding_test.dart new file mode 100644 index 0000000000000..6c7c1d09de368 --- /dev/null +++ b/packages/flutter/test/widgets/multi_view_binding_test.dart @@ -0,0 +1,39 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('runApp uses deprecated pipelineOwner and renderView', (WidgetTester tester) async { + runApp(const SizedBox()); + final RenderObject renderObject = tester.renderObject(find.byType(SizedBox)); + + RenderObject parent = renderObject; + while (parent.parent != null) { + parent = parent.parent!; + } + expect(parent, isA()); + expect(parent, equals(tester.binding.renderView)); + + expect(renderObject.owner, equals(tester.binding.pipelineOwner)); + }); + + testWidgets('can manually attach RootWidget to build owner', (WidgetTester tester) async { + expect(find.byType(ColoredBox), findsNothing); + + final RootWidget rootWidget = RootWidget( + child: View( + view: tester.view, + child: const ColoredBox(color: Colors.orange), + ), + ); + tester.binding.attachToBuildOwner(rootWidget); + await tester.pump(); + expect(find.byType(ColoredBox), findsOneWidget); + expect(tester.binding.rootElement!.widget, equals(rootWidget)); + expect(tester.element(find.byType(ColoredBox)).owner, equals(tester.binding.buildOwner)); + }); +} diff --git a/packages/flutter/test/widgets/multi_view_tree_updates_test.dart b/packages/flutter/test/widgets/multi_view_tree_updates_test.dart new file mode 100644 index 0000000000000..7bc41fe9c519c --- /dev/null +++ b/packages/flutter/test/widgets/multi_view_tree_updates_test.dart @@ -0,0 +1,221 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Widgets in view update as expected', (WidgetTester tester) async { + final Widget widget = View( + view: tester.view, + child: const TestWidget(), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: widget, + ); + + expect(find.text('Hello'), findsOneWidget); + expect(tester.renderObject(find.byType(Text)).text.toPlainText(), 'Hello'); + + tester.state(find.byType(TestWidget)).text = 'World'; + await tester.pump(); + expect(find.text('Hello'), findsNothing); + expect(find.text('World'), findsOneWidget); + expect(tester.renderObject(find.byType(Text)).text.toPlainText(), 'World'); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [widget], + ), + ); + expect(find.text('Hello'), findsNothing); + expect(find.text('World'), findsOneWidget); + expect(tester.renderObject(find.byType(Text)).text.toPlainText(), 'World'); + + tester.state(find.byType(TestWidget)).text = 'FooBar'; + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: widget, + ); + expect(find.text('World'), findsNothing); + expect(find.text('FooBar'), findsOneWidget); + expect(tester.renderObject(find.byType(Text)).text.toPlainText(), 'FooBar'); + }); + + testWidgets('Views in ViewCollection update as expected', (WidgetTester tester) async { + Iterable renderParagraphTexts() { + return tester.renderObjectList(find.byType(Text)).map((RenderParagraph r) => r.text.toPlainText()); + } + + final Key key1 = UniqueKey(); + final Key key2 = UniqueKey(); + final Widget view1 = View( + view: tester.view, + child: TestWidget(key: key1), + ); + final Widget view2 = View( + view: FakeView(tester.view), + child: TestWidget(key: key2), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [view1, view2], + ), + ); + + expect(find.text('Hello'), findsNWidgets(2)); + expect(renderParagraphTexts(), ['Hello', 'Hello']); + + tester.state(find.byKey(key1)).text = 'Guten'; + tester.state(find.byKey(key2)).text = 'Tag'; + await tester.pump(); + expect(find.text('Hello'), findsNothing); + expect(find.text('Guten'), findsOneWidget); + expect(find.text('Tag'), findsOneWidget); + expect(renderParagraphTexts(), ['Guten', 'Tag']); + + tester.state(find.byKey(key2)).text = 'Abend'; + await tester.pump(); + expect(find.text('Tag'), findsNothing); + expect(find.text('Guten'), findsOneWidget); + expect(find.text('Abend'), findsOneWidget); + expect(renderParagraphTexts(), ['Guten', 'Abend']); + + tester.state(find.byKey(key2)).text = 'Morgen'; + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [view1, ViewCollection(views: [view2])], + ), + ); + expect(find.text('Abend'), findsNothing); + expect(find.text('Guten'), findsOneWidget); + expect(find.text('Morgen'), findsOneWidget); + expect(renderParagraphTexts(), ['Guten', 'Morgen']); + }); + + testWidgets('Views in ViewAnchor update as expected', (WidgetTester tester) async { + Iterable renderParagraphTexts() { + return tester.renderObjectList(find.byType(Text)).map((RenderParagraph r) => r.text.toPlainText()); + } + + final Key insideAnchoredViewKey = UniqueKey(); + final Key outsideAnchoredViewKey = UniqueKey(); + final Widget view = View( + view: FakeView(tester.view), + child: TestWidget(key: insideAnchoredViewKey), + ); + + await tester.pumpWidget( + ViewAnchor( + view: view, + child: TestWidget(key: outsideAnchoredViewKey), + ), + ); + + expect(find.text('Hello'), findsNWidgets(2)); + expect(renderParagraphTexts(), ['Hello', 'Hello']); + + tester.state(find.byKey(outsideAnchoredViewKey)).text = 'Guten'; + tester.state(find.byKey(insideAnchoredViewKey)).text = 'Tag'; + await tester.pump(); + expect(find.text('Hello'), findsNothing); + expect(find.text('Guten'), findsOneWidget); + expect(find.text('Tag'), findsOneWidget); + expect(renderParagraphTexts(), ['Guten', 'Tag']); + + tester.state(find.byKey(insideAnchoredViewKey)).text = 'Abend'; + await tester.pump(); + expect(find.text('Tag'), findsNothing); + expect(find.text('Guten'), findsOneWidget); + expect(find.text('Abend'), findsOneWidget); + expect(renderParagraphTexts(), ['Guten', 'Abend']); + + tester.state(find.byKey(outsideAnchoredViewKey)).text = 'Schönen'; + await tester.pump(); + expect(find.text('Guten'), findsNothing); + expect(find.text('Schönen'), findsOneWidget); + expect(find.text('Abend'), findsOneWidget); + expect(renderParagraphTexts(), ['Schönen', 'Abend']); + + tester.state(find.byKey(insideAnchoredViewKey)).text = 'Tag'; + await tester.pumpWidget( + ViewAnchor( + view: ViewCollection(views: [view]), + child: TestWidget(key: outsideAnchoredViewKey), + ), + ); + await tester.pump(); + expect(find.text('Abend'), findsNothing); + expect(find.text('Schönen'), findsOneWidget); + expect(find.text('Tag'), findsOneWidget); + expect(renderParagraphTexts(), ['Schönen', 'Tag']); + + tester.state(find.byKey(insideAnchoredViewKey)).text = 'Morgen'; + await tester.pumpWidget( + SizedBox( + child: ViewAnchor( + view: ViewCollection(views: [view]), + child: TestWidget(key: outsideAnchoredViewKey), + ), + ), + ); + await tester.pump(); + expect(find.text('Schönen'), findsNothing); // The `outsideAnchoredViewKey` is not a global key, its state is lost in the move above. + expect(find.text('Tag'), findsNothing); + expect(find.text('Hello'), findsOneWidget); + expect(find.text('Morgen'), findsOneWidget); + expect(renderParagraphTexts(), ['Hello', 'Morgen']); + }); +} + +class TestWidget extends StatefulWidget { + const TestWidget({super.key}); + + @override + State createState() => TestWidgetState(); +} + +class TestWidgetState extends State { + String get text => _text; + String _text = 'Hello'; + set text(String value) { + if (_text == value) { + return; + } + setState(() { + _text = value; + }); + } + + @override + Widget build(BuildContext context) { + return Text(text, textDirection: TextDirection.ltr); + } +} + +Future pumpWidgetWithoutViewWrapper({required WidgetTester tester, required Widget widget}) { + tester.binding.attachRootWidget(widget); + tester.binding.scheduleFrame(); + return tester.binding.pump(); +} + +class FakeView extends TestFlutterView{ + FakeView(FlutterView view, { this.viewId = 100 }) : super( + view: view, + platformDispatcher: view.platformDispatcher as TestPlatformDispatcher, + display: view.display as TestDisplay, + ); + + @override + final int viewId; +} diff --git a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart index 7d61f844a8182..1ec23fa8081f6 100644 --- a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart +++ b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart @@ -222,16 +222,18 @@ void main() { equalsIgnoringHashCodes( '_RenderDiagonal#00000 relayoutBoundary=up1\n' ' │ creator: _Diagonal ← Align ← Directionality ← MediaQuery ←\n' - ' │ _MediaQueryFromView ← _ViewScope ← View-[GlobalObjectKey\n' - ' │ TestFlutterView#00000] ← [root]\n' + ' │ _MediaQueryFromView ← _PipelineOwnerScope ← _ViewScope ←\n' + ' │ _RawView-[_DeprecatedRawViewKey TestFlutterView#00000] ← View ←\n' + ' │ [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(0.0<=w<=800.0, 0.0<=h<=600.0)\n' ' │ size: Size(190.0, 220.0)\n' ' │\n' ' ├─topLeft: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' │ creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n' - ' │ MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' │ View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' │ MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope ←\n' + ' │ _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' │ TestFlutterView#00000] ← View ← [root]\n' ' │ parentData: offset=Offset(0.0, 0.0) (can use size)\n' ' │ constraints: BoxConstraints(unconstrained)\n' ' │ size: Size(80.0, 100.0)\n' @@ -239,8 +241,9 @@ void main() { ' │\n' ' └─bottomRight: RenderConstrainedBox#00000 relayoutBoundary=up2\n' ' creator: SizedBox ← _Diagonal ← Align ← Directionality ←\n' - ' MediaQuery ← _MediaQueryFromView ← _ViewScope ←\n' - ' View-[GlobalObjectKey TestFlutterView#00000] ← [root]\n' + ' MediaQuery ← _MediaQueryFromView ← _PipelineOwnerScope ←\n' + ' _ViewScope ← _RawView-[_DeprecatedRawViewKey\n' + ' TestFlutterView#00000] ← View ← [root]\n' ' parentData: offset=Offset(80.0, 100.0) (can use size)\n' ' constraints: BoxConstraints(unconstrained)\n' ' size: Size(110.0, 120.0)\n' diff --git a/packages/flutter/test/widgets/stateful_component_test.dart b/packages/flutter/test/widgets/stateful_component_test.dart index 3cebbe5829b26..078e30f0cd6fd 100644 --- a/packages/flutter/test/widgets/stateful_component_test.dart +++ b/packages/flutter/test/widgets/stateful_component_test.dart @@ -10,10 +10,9 @@ import 'test_widgets.dart'; void main() { testWidgets('Stateful widget smoke test', (WidgetTester tester) async { - void checkTree(BoxDecoration expectedDecoration) { final SingleChildRenderObjectElement element = tester.element( - find.byElementPredicate((Element element) => element is SingleChildRenderObjectElement), + find.byElementPredicate((Element element) => element is SingleChildRenderObjectElement && element.renderObject is! RenderView), ); expect(element, isNotNull); expect(element.renderObject, isA()); diff --git a/packages/flutter/test/widgets/tree_shape_test.dart b/packages/flutter/test/widgets/tree_shape_test.dart new file mode 100644 index 0000000000000..306bacfb18cb0 --- /dev/null +++ b/packages/flutter/test/widgets/tree_shape_test.dart @@ -0,0 +1,1161 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Providing a RenderObjectWidget directly to the RootWidget fails', (WidgetTester tester) async { + // No render tree exists to attach the RenderObjectWidget to. + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: const ColoredBox(color: Colors.red), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + startsWith('The render object for ColoredBox cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('Moving a RenderObjectWidget to the RootWidget via GlobalKey fails', (WidgetTester tester) async { + final Widget globalKeyedWidget = ColoredBox( + key: GlobalKey(), + color: Colors.red, + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + child: globalKeyedWidget, + ), + ); + expect(tester.takeException(), isNull); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: globalKeyedWidget, + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + contains('cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('A View cannot be a child of a render object widget', (WidgetTester tester) async { + await tester.pumpWidget(Center( + child: View( + view: FakeView(tester.view), + child: Container(), + ), + )); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + contains('cannot maintain an independent render tree at its current location.'), + )); + }); + + testWidgets('The child of a ViewAnchor cannot be a View', (WidgetTester tester) async { + await tester.pumpWidget( + ViewAnchor( + child: View( + view: FakeView(tester.view), + child: Container(), + ), + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + contains('cannot maintain an independent render tree at its current location.'), + )); + }); + + testWidgets('A View can not be moved via GlobalKey to be a child of a RenderObject', (WidgetTester tester) async { + final Widget globalKeyedView = View( + key: GlobalKey(), + view: FakeView(tester.view), + child: const ColoredBox(color: Colors.red), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: globalKeyedView, + ); + expect(tester.takeException(), isNull); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + child: globalKeyedView, + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + contains('cannot maintain an independent render tree at its current location.'), + )); + }); + + testWidgets('The view property of a ViewAnchor cannot be a render object widget', (WidgetTester tester) async { + await tester.pumpWidget( + ViewAnchor( + view: const ColoredBox(color: Colors.red), + child: Container(), + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + startsWith('The render object for ColoredBox cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('A RenderObject cannot be moved into the view property of a ViewAnchor via GlobalKey', (WidgetTester tester) async { + final Widget globalKeyedWidget = ColoredBox( + key: GlobalKey(), + color: Colors.red, + ); + + await tester.pumpWidget( + ViewAnchor( + child: globalKeyedWidget, + ), + ); + expect(tester.takeException(), isNull); + + await tester.pumpWidget( + ViewAnchor( + view: globalKeyedWidget, + child: const SizedBox(), + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + contains('cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('ViewAnchor cannot be used at the top of the widget tree (outside of View)', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: const ViewAnchor( + child: SizedBox(), + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + startsWith('The render object for SizedBox cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('ViewAnchor cannot be moved to the top of the widget tree (outside of View) via GlobalKey', (WidgetTester tester) async { + final Widget globalKeyedViewAnchor = ViewAnchor( + key: GlobalKey(), + child: const SizedBox(), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + child: globalKeyedViewAnchor, + ), + ); + expect(tester.takeException(), isNull); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: globalKeyedViewAnchor, + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + contains('cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('View can be used at the top of the widget tree', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + child: Container(), + ), + ); + + expect(tester.takeException(), isNull); + }); + + testWidgets('View can be moved to the top of the widget tree view GlobalKey', (WidgetTester tester) async { + final Widget globalKeyView = View( + view: FakeView(tester.view), + child: const ColoredBox(color: Colors.red), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + child: ViewAnchor( + view: globalKeyView, // This one has trouble when deactivating + child: const SizedBox(), + ), + ), + ); + expect(tester.takeException(), isNull); + expect(find.byType(SizedBox), findsOneWidget); + expect(find.byType(ColoredBox), findsOneWidget); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: globalKeyView, + ); + expect(tester.takeException(), isNull); + expect(find.byType(SizedBox), findsNothing); + expect(find.byType(ColoredBox), findsOneWidget); + }); + + testWidgets('ViewCollection can be used at the top of the widget tree', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: tester.view, + child: Container(), + ), + ], + ), + ); + + expect(tester.takeException(), isNull); + }); + + testWidgets('ViewCollection cannot be used inside a View', (WidgetTester tester) async { + await tester.pumpWidget( + ViewCollection( + views: [ + View( + view: FakeView(tester.view), + child: Container(), + ), + ], + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + startsWith('The Element for ViewCollection cannot be inserted into slot "null" of its ancestor.'), + )); + }); + + testWidgets('ViewCollection can be used as ViewAnchor.view', (WidgetTester tester) async { + await tester.pumpWidget( + ViewAnchor( + view: ViewCollection( + views: [ + View( + view: FakeView(tester.view), + child: Container(), + ) + ], + ), + child: Container(), + ), + ); + + expect(tester.takeException(), isNull); + }); + + testWidgets('ViewCollection cannot have render object widgets as children', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: const [ + ColoredBox(color: Colors.red), + ], + ), + ); + + expect(tester.takeException(), isFlutterError.having( + (FlutterError error) => error.message, + 'message', + startsWith('The render object for ColoredBox cannot find ancestor render object to attach to.'), + )); + }); + + testWidgets('Views can be moved in and out of ViewCollections via GlobalKey', (WidgetTester tester) async { + final Widget greenView = View( + key: GlobalKey(debugLabel: 'green'), + view: tester.view, + child: const ColoredBox(color: Colors.green), + ); + final Widget redView = View( + key: GlobalKey(debugLabel: 'red'), + view: FakeView(tester.view), + child: const ColoredBox(color: Colors.red), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + greenView, + ViewCollection( + views: [ + redView, + ], + ), + ] + ), + ); + expect(tester.takeException(), isNull); + expect(find.byType(ColoredBox), findsNWidgets(2)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + redView, + ViewCollection( + views: [ + greenView, + ], + ), + ] + ), + ); + expect(tester.takeException(), isNull); + expect(find.byType(ColoredBox), findsNWidgets(2)); + }); + + testWidgets('Can move stuff between views via global key: viewA -> viewB', (WidgetTester tester) async { + final FlutterView greenView = tester.view; + final FlutterView redView = FakeView(tester.view); + final Widget globalKeyChild = SizedBox( + key: GlobalKey(), + ); + + Map collectLeafRenderObjects() { + final Map result = {}; + for (final RenderView renderView in RendererBinding.instance.renderViews) { + void visit(RenderObject object) { + result[renderView.flutterView.viewId] = object; + object.visitChildren(visit); + } + visit(renderView); + } + return result; + } + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: greenView, + child: ColoredBox( + color: Colors.green, + child: globalKeyChild, + ), + ), + View( + view: redView, + child: const ColoredBox( + color: Colors.red, + ), + ), + ], + ), + ); + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + final RenderObject boxWithGlobalKey = tester.renderObject(find.byKey(globalKeyChild.key!)); + + Map leafRenderObject = collectLeafRenderObjects(); + expect(leafRenderObject[greenView.viewId], isA()); + expect(leafRenderObject[redView.viewId], isNot(isA())); + + // Move the child. + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: greenView, + child: const ColoredBox( + color: Colors.green, + ), + ), + View( + view: redView, + child: ColoredBox( + color: Colors.red, + child: globalKeyChild, + ), + ), + ], + ), + ); + + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + tester.renderObject(find.byKey(globalKeyChild.key!)), + equals(boxWithGlobalKey), + ); + + leafRenderObject = collectLeafRenderObjects(); + expect(leafRenderObject[greenView.viewId], isNot(isA())); + expect(leafRenderObject[redView.viewId], isA()); + }); + + testWidgets('Can move stuff between views via global key: viewB -> viewA', (WidgetTester tester) async { + final FlutterView greenView = tester.view; + final FlutterView redView = FakeView(tester.view); + final Widget globalKeyChild = SizedBox( + key: GlobalKey(), + ); + + Map collectLeafRenderObjects() { + final Map result = {}; + for (final RenderView renderView in RendererBinding.instance.renderViews) { + void visit(RenderObject object) { + result[renderView.flutterView.viewId] = object; + object.visitChildren(visit); + } + visit(renderView); + } + return result; + } + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: greenView, + child: const ColoredBox( + color: Colors.green, + ), + ), + View( + view: redView, + child: ColoredBox( + color: Colors.red, + child: globalKeyChild, + ), + ), + ], + ), + ); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + final RenderObject boxWithGlobalKey = tester.renderObject(find.byKey(globalKeyChild.key!)); + + Map leafRenderObject = collectLeafRenderObjects(); + expect(leafRenderObject[redView.viewId], isA()); + expect(leafRenderObject[greenView.viewId], isNot(isA())); + + // Move the child. + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: greenView, + child: ColoredBox( + color: Colors.green, + child: globalKeyChild, + ), + ), + View( + view: redView, + child: const ColoredBox( + color: Colors.red, + ), + ), + ], + ), + ); + + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + tester.renderObject(find.byKey(globalKeyChild.key!)), + equals(boxWithGlobalKey), + ); + + leafRenderObject = collectLeafRenderObjects(); + expect(leafRenderObject[redView.viewId], isNot(isA())); + expect(leafRenderObject[greenView.viewId], isA()); + }); + + testWidgets('Can move stuff out of a view that is going away, viewA -> ViewB', (WidgetTester tester) async { + final FlutterView greenView = tester.view; + final Key greenKey = UniqueKey(); + final FlutterView redView = FakeView(tester.view); + final Key redKey = UniqueKey(); + final Widget globalKeyChild = SizedBox( + key: GlobalKey(), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + key: greenKey, + view: greenView, + child: const ColoredBox( + color: Colors.green, + ), + ), + View( + key: redKey, + view: redView, + child: ColoredBox( + color: Colors.red, + child: globalKeyChild, + ), + ), + ], + ), + ); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + final RenderObject boxWithGlobalKey = tester.renderObject(find.byKey(globalKeyChild.key!)); + + // Move the child and remove its view. + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + key: greenKey, + view: greenView, + child: ColoredBox( + color: Colors.green, + child: globalKeyChild, + ), + ), + ], + ), + ); + + expect( + findsColoredBox(Colors.red), + findsNothing, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + tester.renderObject(find.byKey(globalKeyChild.key!)), + equals(boxWithGlobalKey), + ); + }); + + testWidgets('Can move stuff out of a view that is going away, viewB -> ViewA', (WidgetTester tester) async { + final FlutterView greenView = tester.view; + final Key greenKey = UniqueKey(); + final FlutterView redView = FakeView(tester.view); + final Key redKey = UniqueKey(); + final Widget globalKeyChild = SizedBox( + key: GlobalKey(), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + key: greenKey, + view: greenView, + child: ColoredBox( + color: Colors.green, + child: globalKeyChild, + ), + ), + View( + key: redKey, + view: redView, + child: const ColoredBox( + color: Colors.red, + ), + ), + ], + ), + ); + expect( + find.descendant( + of: findsColoredBox(Colors.green), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + final RenderObject boxWithGlobalKey = tester.renderObject(find.byKey(globalKeyChild.key!)); + + // Move the child and remove its view. + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + key: redKey, + view: redView, + child: ColoredBox( + color: Colors.red, + child: globalKeyChild, + ), + ), + ], + ), + ); + + expect( + findsColoredBox(Colors.green), + findsNothing, + ); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect( + tester.renderObject(find.byKey(globalKeyChild.key!)), + equals(boxWithGlobalKey), + ); + }); + + testWidgets('Can move stuff out of a view that is moving itself, stuff ends up before view', (WidgetTester tester) async { + final Key key1 = UniqueKey(); + final Key key2 = UniqueKey(); + final Key key3 = UniqueKey(); + final Key key4 = UniqueKey(); + + final GlobalKey viewKey = GlobalKey(); + final GlobalKey childKey = GlobalKey(); + + await tester.pumpWidget(Column( + children: [ + SizedBox(key: key1), + ViewAnchor( + key: key2, + view: View( + key: viewKey, + view: FakeView(tester.view), + child: SizedBox( + child: ColoredBox( + key: childKey, + color: Colors.green, + ), + ), + ), + child: const SizedBox(), + ), + ViewAnchor( + key: key3, + child: const SizedBox(), + ), + SizedBox(key: key4), + ], + )); + + await tester.pumpWidget(Column( + children: [ + SizedBox( + key: key1, + child: ColoredBox( + key: childKey, + color: Colors.green, + ), + ), + ViewAnchor( + key: key2, + child: const SizedBox(), + ), + ViewAnchor( + key: key3, + view: View( + key: viewKey, + view: FakeView(tester.view), + child: const SizedBox(), + ), + child: const SizedBox(), + ), + SizedBox(key: key4), + ], + )); + + await tester.pumpWidget(Column( + children: [ + SizedBox(key: key1), + ViewAnchor( + key: key2, + view: View( + key: viewKey, + view: FakeView(tester.view), + child: SizedBox( + child: ColoredBox( + key: childKey, + color: Colors.green, + ), + ), + ), + child: const SizedBox(), + ), + ViewAnchor( + key: key3, + child: const SizedBox(), + ), + SizedBox(key: key4), + ], + )); + }); + + testWidgets('Can move stuff out of a view that is moving itself, stuff ends up after view', (WidgetTester tester) async { + final Key key1 = UniqueKey(); + final Key key2 = UniqueKey(); + final Key key3 = UniqueKey(); + final Key key4 = UniqueKey(); + + final GlobalKey viewKey = GlobalKey(); + final GlobalKey childKey = GlobalKey(); + + await tester.pumpWidget(Column( + children: [ + SizedBox(key: key1), + ViewAnchor( + key: key2, + view: View( + key: viewKey, + view: FakeView(tester.view), + child: SizedBox( + child: ColoredBox( + key: childKey, + color: Colors.green, + ), + ), + ), + child: const SizedBox(), + ), + ViewAnchor( + key: key3, + child: const SizedBox(), + ), + SizedBox(key: key4), + ], + )); + + await tester.pumpWidget(Column( + children: [ + SizedBox( + key: key1, + ), + ViewAnchor( + key: key2, + child: const SizedBox(), + ), + ViewAnchor( + key: key3, + view: View( + key: viewKey, + view: FakeView(tester.view), + child: const SizedBox(), + ), + child: const SizedBox(), + ), + SizedBox( + key: key4, + child: ColoredBox( + key: childKey, + color: Colors.green, + ), + ), + ], + )); + + await tester.pumpWidget(Column( + children: [ + SizedBox(key: key1), + ViewAnchor( + key: key2, + view: View( + key: viewKey, + view: FakeView(tester.view), + child: SizedBox( + child: ColoredBox( + key: childKey, + color: Colors.green, + ), + ), + ), + child: const SizedBox(), + ), + ViewAnchor( + key: key3, + child: const SizedBox(), + ), + SizedBox(key: key4), + ], + )); + }); + + testWidgets('Can globalkey move down the tree from a view that is going away', (WidgetTester tester) async { + final FlutterView anchorView = FakeView(tester.view); + final Widget globalKeyChild = SizedBox( + key: GlobalKey(), + ); + + await tester.pumpWidget( + ColoredBox( + color: Colors.green, + child: ViewAnchor( + view: View( + view: anchorView, + child: ColoredBox( + color: Colors.yellow, + child: globalKeyChild, + ), + ), + child: const ColoredBox(color: Colors.red), + ), + ), + ); + + expect(findsColoredBox(Colors.green), findsOneWidget); + expect(findsColoredBox(Colors.yellow), findsOneWidget); + expect( + find.descendant( + of: findsColoredBox(Colors.yellow), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect(findsColoredBox(Colors.red), findsOneWidget); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + expect(find.byType(SizedBox), findsOneWidget); + final RenderObject boxWithGlobalKey = tester.renderObject(find.byKey(globalKeyChild.key!)); + + await tester.pumpWidget( + ColoredBox( + color: Colors.green, + child: ViewAnchor( + child: ColoredBox( + color: Colors.red, + child: globalKeyChild, + ), + ), + ), + ); + expect(findsColoredBox(Colors.green), findsOneWidget); + expect(findsColoredBox(Colors.yellow), findsNothing); + expect( + find.descendant( + of: findsColoredBox(Colors.yellow), + matching: find.byType(SizedBox), + ), + findsNothing, + ); + expect(findsColoredBox(Colors.red), findsOneWidget); + expect( + find.descendant( + of: findsColoredBox(Colors.red), + matching: find.byType(SizedBox), + ), + findsOneWidget, + ); + expect(find.byType(SizedBox), findsOneWidget); + expect( + tester.renderObject(find.byKey(globalKeyChild.key!)), + boxWithGlobalKey, + ); + }); + + testWidgets('RenderObjects are disposed when a view goes away from a ViewAnchor', (WidgetTester tester) async { + final FlutterView anchorView = FakeView(tester.view); + + await tester.pumpWidget( + ColoredBox( + color: Colors.green, + child: ViewAnchor( + view: View( + view: anchorView, + child: const ColoredBox(color: Colors.yellow), + ), + child: const ColoredBox(color: Colors.red), + ), + ), + ); + + final RenderObject box = tester.renderObject(findsColoredBox(Colors.yellow)); + + await tester.pumpWidget( + const ColoredBox( + color: Colors.green, + child: ViewAnchor( + child: ColoredBox(color: Colors.red), + ), + ), + ); + + expect(box.debugDisposed, isTrue); + }); + + testWidgets('RenderObjects are disposed when a view goes away from a ViewCollection', (WidgetTester tester) async { + final FlutterView redView = tester.view; + final FlutterView greenView = FakeView(tester.view); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: redView, + child: const ColoredBox(color: Colors.red), + ), + View( + view: greenView, + child: const ColoredBox(color: Colors.green), + ), + ], + ), + ); + + expect(findsColoredBox(Colors.green), findsOneWidget); + expect(findsColoredBox(Colors.red), findsOneWidget); + final RenderObject box = tester.renderObject(findsColoredBox(Colors.green)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: redView, + child: const ColoredBox(color: Colors.red), + ), + ], + ), + ); + + expect(findsColoredBox(Colors.green), findsNothing); + expect(findsColoredBox(Colors.red), findsOneWidget); + expect(box.debugDisposed, isTrue); + }); + + testWidgets('View can be wrapped and unwrapped', (WidgetTester tester) async { + final Widget view = View( + view: tester.view, + child: const SizedBox(), + ); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: view, + ); + + final RenderObject renderView = tester.renderObject(find.byType(View)); + final RenderObject renderSizedBox = tester.renderObject(find.byType(SizedBox)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [view], + ), + ); + + expect(tester.renderObject(find.byType(View)), same(renderView)); + expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: view, + ); + + expect(tester.renderObject(find.byType(View)), same(renderView)); + expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); + }); + + testWidgets('ViewAnchor with View can be wrapped and unwrapped', (WidgetTester tester) async { + final Widget viewAnchor = ViewAnchor( + view: View( + view: FakeView(tester.view), + child: const SizedBox(), + ), + child: const ColoredBox(color: Colors.green), + ); + + await tester.pumpWidget(viewAnchor); + + final List renderViews = tester.renderObjectList(find.byType(View)).toList(); + final RenderObject renderSizedBox = tester.renderObject(find.byType(SizedBox)); + + await tester.pumpWidget(ColoredBox(color: Colors.yellow, child: viewAnchor)); + + expect(tester.renderObjectList(find.byType(View)), renderViews); + expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); + + await tester.pumpWidget(viewAnchor); + + expect(tester.renderObjectList(find.byType(View)), renderViews); + expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); + }); + + testWidgets('Moving a View keeps its semantics tree stable', (WidgetTester tester) async { + final Widget view = View( + // No explicit key, we rely on the implicit key of the underlying RawView. + view: tester.view, + child: Semantics( + textDirection: TextDirection.ltr, + label: 'Hello', + child: const SizedBox(), + ) + ); + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: view, + ); + + final RenderObject renderSemantics = tester.renderObject(find.bySemanticsLabel('Hello')); + final SemanticsNode semantics = tester.getSemantics(find.bySemanticsLabel('Hello')); + expect(semantics.id, 1); + expect(renderSemantics.debugSemantics, same(semantics)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + view, + ], + ), + ); + + final RenderObject renderSemanticsAfterMove = tester.renderObject(find.bySemanticsLabel('Hello')); + final SemanticsNode semanticsAfterMove = tester.getSemantics(find.bySemanticsLabel('Hello')); + expect(renderSemanticsAfterMove, same(renderSemantics)); + expect(semanticsAfterMove.id, 1); + expect(semanticsAfterMove, same(semantics)); + }); +} + +Finder findsColoredBox(Color color) { + return find.byWidgetPredicate((Widget widget) => widget is ColoredBox && widget.color == color); +} + +Future pumpWidgetWithoutViewWrapper({required WidgetTester tester, required Widget widget}) { + tester.binding.attachRootWidget(widget); + tester.binding.scheduleFrame(); + return tester.binding.pump(); +} + +class FakeView extends TestFlutterView{ + FakeView(FlutterView view, { this.viewId = 100 }) : super( + view: view, + platformDispatcher: view.platformDispatcher as TestPlatformDispatcher, + display: view.display as TestDisplay, + ); + + @override + final int viewId; +} diff --git a/packages/flutter/test/widgets/view_test.dart b/packages/flutter/test/widgets/view_test.dart index 6da63c137dced..b0a87c09ffb8e 100644 --- a/packages/flutter/test/widgets/view_test.dart +++ b/packages/flutter/test/widgets/view_test.dart @@ -4,7 +4,8 @@ import 'dart:ui'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -67,4 +68,436 @@ void main() { )), ); }); + + testWidgets('child of view finds view, parentPipelineOwner, mediaQuery', (WidgetTester tester) async { + FlutterView? outsideView; + FlutterView? insideView; + PipelineOwner? outsideParent; + PipelineOwner? insideParent; + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: Builder( + builder: (BuildContext context) { + outsideView = View.maybeOf(context); + outsideParent = View.pipelineOwnerOf(context); + return View( + view: tester.view, + child: Builder( + builder: (BuildContext context) { + insideView = View.maybeOf(context); + insideParent = View.pipelineOwnerOf(context); + return const SizedBox(); + }, + ), + ); + }, + ), + ); + expect(outsideView, isNull); + expect(insideView, equals(tester.view)); + + expect(outsideParent, isNotNull); + expect(insideParent, isNotNull); + expect(outsideParent, isNot(equals(insideParent))); + + expect(outsideParent, tester.binding.rootPipelineOwner); + expect(insideParent, equals(tester.renderObject(find.byType(SizedBox)).owner)); + + final List pipelineOwners = []; + tester.binding.rootPipelineOwner.visitChildren((PipelineOwner child) { + pipelineOwners.add(child); + }); + expect(pipelineOwners.single, equals(insideParent)); + }); + + testWidgets('cannot have multiple views with same FlutterView', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: tester.view, + child: const SizedBox(), + ), + View( + view: tester.view, + child: const SizedBox(), + ), + ], + ), + ); + + expect( + tester.takeException(), + isFlutterError.having( + (FlutterError e) => e.message, + 'message', + contains('Multiple widgets used the same GlobalKey'), + ), + ); + }); + + testWidgets('ViewCollection must have one view', (WidgetTester tester) async { + expect(() => ViewCollection(views: const []), throwsAssertionError); + }); + + testWidgets('ViewAnchor.child does not see surrounding view', (WidgetTester tester) async { + FlutterView? inside; + FlutterView? outside; + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + outside = View.maybeOf(context); + return ViewAnchor( + view: Builder( + builder: (BuildContext context) { + inside = View.maybeOf(context); + return View(view: FakeView(tester.view), child: const SizedBox()); + }, + ), + child: const SizedBox(), + ); + }, + ), + ); + expect(inside, isNull); + expect(outside, isNotNull); + }); + + testWidgets('ViewAnchor layout order', (WidgetTester tester) async { + Finder findSpyWidget(int label) { + return find.byWidgetPredicate((Widget w) => w is SpyRenderWidget && w.label == label); + } + + final List log = []; + await tester.pumpWidget( + SpyRenderWidget( + label: 1, + log: log, + child: ViewAnchor( + view: View( + view: FakeView(tester.view), + child: SpyRenderWidget(label: 2, log: log), + ), + child: SpyRenderWidget(label: 3, log: log), + ), + ), + ); + log.clear(); + tester.renderObject(findSpyWidget(3)).markNeedsLayout(); + tester.renderObject(findSpyWidget(2)).markNeedsLayout(); + tester.renderObject(findSpyWidget(1)).markNeedsLayout(); + await tester.pump(); + expect(log, ['layout 1', 'layout 3', 'layout 2']); + }); + + testWidgets('visitChildren of ViewAnchor visits both children', (WidgetTester tester) async { + await tester.pumpWidget( + ViewAnchor( + view: View( + view: FakeView(tester.view), + child: const ColoredBox(color: Colors.green), + ), + child: const SizedBox(), + ), + ); + final Element viewAnchorElement = tester.element(find.byElementPredicate((Element e) => e.runtimeType.toString() == '_MultiChildComponentElement')); + final List children = []; + viewAnchorElement.visitChildren((Element element) { + children.add(element); + }); + expect(children, hasLength(2)); + + await tester.pumpWidget( + const ViewAnchor( + child: SizedBox(), + ), + ); + children.clear(); + viewAnchorElement.visitChildren((Element element) { + children.add(element); + }); + expect(children, hasLength(1)); + }); + + testWidgets('visitChildren of ViewCollection visits all children', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: tester.view, + child: const SizedBox(), + ), + View( + view: FakeView(tester.view), + child: const SizedBox(), + ), + View( + view: FakeView(tester.view, viewId: 423), + child: const SizedBox(), + ), + ], + ), + ); + final Element viewAnchorElement = tester.element(find.byElementPredicate((Element e) => e.runtimeType.toString() == '_MultiChildComponentElement')); + final List children = []; + viewAnchorElement.visitChildren((Element element) { + children.add(element); + }); + expect(children, hasLength(3)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: ViewCollection( + views: [ + View( + view: tester.view, + child: const SizedBox(), + ), + ], + ), + ); + children.clear(); + viewAnchorElement.visitChildren((Element element) { + children.add(element); + }); + expect(children, hasLength(1)); + }); + + group('renderObject getter', () { + testWidgets('ancestors of view see RenderView as renderObject', (WidgetTester tester) async { + late BuildContext builderContext; + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: Builder( + builder: (BuildContext context) { + builderContext = context; + return View( + view: tester.view, + child: const SizedBox(), + ); + }, + ), + ); + + final RenderObject? renderObject = builderContext.findRenderObject(); + expect(renderObject, isNotNull); + expect(renderObject, isA()); + expect(renderObject, tester.renderObject(find.byType(View))); + expect(tester.element(find.byType(Builder)).renderObject, renderObject); + }); + + testWidgets('ancestors of ViewCollection get null for renderObject', (WidgetTester tester) async { + late BuildContext builderContext; + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: Builder( + builder: (BuildContext context) { + builderContext = context; + return ViewCollection( + views: [ + View( + view: tester.view, + child: const SizedBox(), + ), + View( + view: FakeView(tester.view), + child: const SizedBox(), + ), + ], + ); + }, + ), + ); + + final RenderObject? renderObject = builderContext.findRenderObject(); + expect(renderObject, isNull); + expect(tester.element(find.byType(Builder)).renderObject, isNull); + }); + + testWidgets('ancestors of a ViewAnchor see the right RenderObject', (WidgetTester tester) async { + late BuildContext builderContext; + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + builderContext = context; + return ViewAnchor( + view: View( + view: FakeView(tester.view), + child: const ColoredBox(color: Colors.green), + ), + child: const SizedBox(), + ); + }, + ), + ); + + final RenderObject? renderObject = builderContext.findRenderObject(); + expect(renderObject, isNotNull); + expect(renderObject, isA()); + expect(renderObject, tester.renderObject(find.byType(SizedBox))); + expect(tester.element(find.byType(Builder)).renderObject, renderObject); + }); + }); + + testWidgets('correctly switches between view configurations', (WidgetTester tester) async { + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner: tester.binding.pipelineOwner, + deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView: tester.binding.renderView, + child: const SizedBox(), + ), + ); + RenderObject renderView = tester.renderObject(find.byType(View)); + expect(renderView, same(tester.binding.renderView)); + expect(renderView.owner, same(tester.binding.pipelineOwner)); + expect(tester.renderObject(find.byType(SizedBox)).owner, same(tester.binding.pipelineOwner)); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + child: const SizedBox(), + ), + ); + renderView = tester.renderObject(find.byType(View)); + expect(renderView, isNot(same(tester.binding.renderView))); + expect(renderView.owner, isNot(same(tester.binding.pipelineOwner))); + expect(tester.renderObject(find.byType(SizedBox)).owner, isNot(same(tester.binding.pipelineOwner))); + + await pumpWidgetWithoutViewWrapper( + tester: tester, + widget: View( + view: tester.view, + deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner: tester.binding.pipelineOwner, + deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView: tester.binding.renderView, + child: const SizedBox(), + ), + ); + renderView = tester.renderObject(find.byType(View)); + expect(renderView, same(tester.binding.renderView)); + expect(renderView.owner, same(tester.binding.pipelineOwner)); + expect(tester.renderObject(find.byType(SizedBox)).owner, same(tester.binding.pipelineOwner)); + + expect(() => View( + view: tester.view, + deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner: tester.binding.pipelineOwner, + child: const SizedBox(), + ), throwsAssertionError); + expect(() => View( + view: tester.view, + deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView: tester.binding.renderView, + child: const SizedBox(), + ), throwsAssertionError); + expect(() => View( + view: FakeView(tester.view), + deprecatedDoNotUseWillBeRemovedWithoutNoticeRenderView: tester.binding.renderView, + deprecatedDoNotUseWillBeRemovedWithoutNoticePipelineOwner: tester.binding.pipelineOwner, + child: const SizedBox(), + ), throwsAssertionError); + }); + + testWidgets('attaches itself correctly', (WidgetTester tester) async { + final Key viewKey = UniqueKey(); + late final PipelineOwner parentPipelineOwner; + await tester.pumpWidget( + ViewAnchor( + view: Builder( + builder: (BuildContext context) { + parentPipelineOwner = View.pipelineOwnerOf(context); + return View( + key: viewKey, + view: FakeView(tester.view), + child: const SizedBox(), + ); + }, + ), + child: const ColoredBox(color: Colors.green), + ), + ); + + expect(parentPipelineOwner, isNot(RendererBinding.instance.rootPipelineOwner)); + + final RenderView rawView = tester.renderObject(find.byKey(viewKey)); + expect(RendererBinding.instance.renderViews, contains(rawView)); + + final List children = []; + parentPipelineOwner.visitChildren((PipelineOwner child) { + children.add(child); + }); + final PipelineOwner rawViewOwner = rawView.owner!; + expect(children, contains(rawViewOwner)); + + // Remove that View from the tree. + await tester.pumpWidget( + const ViewAnchor( + child: ColoredBox(color: Colors.green), + ), + ); + + expect(rawView.owner, isNull); + expect(RendererBinding.instance.renderViews, isNot(contains(rawView))); + children.clear(); + parentPipelineOwner.visitChildren((PipelineOwner child) { + children.add(child); + }); + expect(children, isNot(contains(rawViewOwner))); + }); +} + +Future pumpWidgetWithoutViewWrapper({required WidgetTester tester, required Widget widget}) { + tester.binding.attachRootWidget(widget); + tester.binding.scheduleFrame(); + return tester.binding.pump(); +} + +class FakeView extends TestFlutterView{ + FakeView(FlutterView view, { this.viewId = 100 }) : super( + view: view, + platformDispatcher: view.platformDispatcher as TestPlatformDispatcher, + display: view.display as TestDisplay, + ); + + @override + final int viewId; +} + +class SpyRenderWidget extends SizedBox { + const SpyRenderWidget({super.key, required this.label, required this.log, super.child}); + + final int label; + final List log; + + @override + RenderSpy createRenderObject(BuildContext context) { + return RenderSpy( + additionalConstraints: const BoxConstraints(), + label: label, + log: log, + ); + } + + @override + void updateRenderObject(BuildContext context, RenderSpy renderObject) { + renderObject + ..label = label + ..log = log; + } +} + +class RenderSpy extends RenderConstrainedBox { + RenderSpy({required super.additionalConstraints, required this.label, required this.log}); + + int label; + List log; + + @override + void performLayout() { + log.add('layout $label'); + super.performLayout(); + } } diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index a75293e832515..9e00c5352bab3 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -4509,7 +4509,6 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(result['parentData'], isNull); }); - testWidgets('ext.flutter.inspector.getLayoutExplorerNode for RenderView',(WidgetTester tester) async { await pumpWidgetForLayoutExplorer(tester); @@ -4530,7 +4529,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { final Map? renderObject = result['renderObject'] as Map?; expect(renderObject, isNotNull); - expect(renderObject!['description'], startsWith('RenderView')); + expect(renderObject!['description'], contains('RenderView')); expect(result['parentRenderElement'], isNull); expect(result['constraints'], isNull); diff --git a/packages/flutter/test_release/widgets/memory_allocations_test.dart b/packages/flutter/test_release/widgets/memory_allocations_test.dart index 166725ab6b1a6..4057379308d3f 100644 --- a/packages/flutter/test_release/widgets/memory_allocations_test.dart +++ b/packages/flutter/test_release/widgets/memory_allocations_test.dart @@ -55,7 +55,7 @@ class _TestRenderObject extends RenderObject { Rect get semanticBounds => throw UnimplementedError(); } -class _TestElement extends RenderObjectElement with RootElementMixin { +class _TestElement extends RenderTreeRootElement with RootElementMixin { _TestElement(): super(_TestLeafRenderObjectWidget()); void makeInactive() { diff --git a/packages/flutter_driver/lib/src/common/handler_factory.dart b/packages/flutter_driver/lib/src/common/handler_factory.dart index 05e70aee8d2fe..9960e8396dba4 100644 --- a/packages/flutter_driver/lib/src/common/handler_factory.dart +++ b/packages/flutter_driver/lib/src/common/handler_factory.dart @@ -187,11 +187,20 @@ mixin CommandHandlerFactory { Future _getHealth(Command command) async => const Health(HealthStatus.ok); Future _getLayerTree(Command command) async { - return LayerTree(RendererBinding.instance.renderView.debugLayer?.toStringDeep()); + final String trees = [ + for (final RenderView renderView in RendererBinding.instance.renderViews) + if (renderView.debugLayer != null) + renderView.debugLayer!.toStringDeep(), + ].join('\n\n'); + return LayerTree(trees.isNotEmpty ? trees : null); } Future _getRenderTree(Command command) async { - return RenderTree(RendererBinding.instance.renderView.toStringDeep()); + final String trees = [ + for (final RenderView renderView in RendererBinding.instance.renderViews) + renderView.toStringDeep(), + ].join('\n\n'); + return RenderTree(trees.isNotEmpty ? trees : null); } Future _enterText(Command command) async { diff --git a/packages/flutter_test/lib/src/_matchers_web.dart b/packages/flutter_test/lib/src/_matchers_web.dart index 749b57164eda3..7f54720eb236c 100644 --- a/packages/flutter_test/lib/src/_matchers_web.dart +++ b/packages/flutter_test/lib/src/_matchers_web.dart @@ -58,8 +58,8 @@ class MatchesGoldenFile extends AsyncMatcher { final RenderObject renderObject = _findRepaintBoundary(element); final Size size = renderObject.paintBounds.size; final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance; - final Element e = binding.rootElement!; final ui.FlutterView view = binding.platformDispatcher.implicitView!; + final RenderView renderView = binding.renderViews.firstWhere((RenderView r) => r.flutterView == view); // Unlike `flutter_tester`, we don't have the ability to render an element // to an image directly. Instead, we will use `window.render()` to render @@ -78,7 +78,7 @@ class MatchesGoldenFile extends AsyncMatcher { return ex.message; } }); - _renderElement(view, _findRepaintBoundary(e)); + _renderElement(view, renderView); return result; } diff --git a/packages/flutter_test/lib/src/accessibility.dart b/packages/flutter_test/lib/src/accessibility.dart index a696837d3a623..7faeb4a386259 100644 --- a/packages/flutter_test/lib/src/accessibility.dart +++ b/packages/flutter_test/lib/src/accessibility.dart @@ -131,11 +131,10 @@ class MinimumTapTargetGuideline extends AccessibilityGuideline { @override FutureOr evaluate(WidgetTester tester) { Evaluation result = const Evaluation.pass(); - for (final FlutterView view in tester.platformDispatcher.views) { + for (final RenderView view in tester.binding.renderViews) { result += _traverse( - view, - // TODO(pdblasi-google): Get the specific semantics root for this view when available - tester.binding.pipelineOwner.semanticsOwner!.rootSemanticsNode!, + view.flutterView, + view.owner!.semanticsOwner!.rootSemanticsNode!, ); } @@ -239,10 +238,8 @@ class LabeledTapTargetGuideline extends AccessibilityGuideline { FutureOr evaluate(WidgetTester tester) { Evaluation result = const Evaluation.pass(); - // TODO(pdblasi-google): Use view to retrieve the appropriate root semantics node when available. - // ignore: unused_local_variable - for (final FlutterView view in tester.platformDispatcher.views) { - result += _traverse(tester.binding.pipelineOwner.semanticsOwner!.rootSemanticsNode!); + for (final RenderView view in tester.binding.renderViews) { + result += _traverse(view.owner!.semanticsOwner!.rootSemanticsNode!); } return result; @@ -318,9 +315,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { @override Future evaluate(WidgetTester tester) async { Evaluation result = const Evaluation.pass(); - for (final FlutterView view in tester.platformDispatcher.views) { - // TODO(pdblasi): This renderView will need to be retrieved from view when available. - final RenderView renderView = tester.binding.renderView; + for (final RenderView renderView in tester.binding.renderViews) { final OffsetLayer layer = renderView.debugLayer! as OffsetLayer; final SemanticsNode root = renderView.owner!.semanticsOwner!.rootSemanticsNode!; @@ -329,13 +324,13 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { () async { // Needs to be the same pixel ratio otherwise our dimensions won't match // the last transform layer. - final double ratio = 1 / view.devicePixelRatio; + final double ratio = 1 / renderView.flutterView.devicePixelRatio; image = await layer.toImage(renderView.paintBounds, pixelRatio: ratio); return image.toByteData(); }, ); - result += await _evaluateNode(root, tester, image, byteData!, view); + result += await _evaluateNode(root, tester, image, byteData!, renderView); } return result; @@ -346,7 +341,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { WidgetTester tester, ui.Image image, ByteData byteData, - FlutterView view, + RenderView renderView, ) async { Evaluation result = const Evaluation.pass(); @@ -368,7 +363,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { return true; }); for (final SemanticsNode child in children) { - result += await _evaluateNode(child, tester, image, byteData, view); + result += await _evaluateNode(child, tester, image, byteData, renderView); } if (shouldSkipNode(data)) { return result; @@ -376,7 +371,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { final String text = data.label.isEmpty ? data.value : data.label; final Iterable elements = find.text(text).hitTestable().evaluate(); for (final Element element in elements) { - result += await _evaluateElement(node, element, tester, image, byteData, view); + result += await _evaluateElement(node, element, tester, image, byteData, renderView); } return result; } @@ -387,7 +382,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { WidgetTester tester, ui.Image image, ByteData byteData, - FlutterView view, + RenderView renderView, ) async { // Look up inherited text properties to determine text size and weight. late bool isBold; @@ -408,7 +403,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { // not included in renderBox.getTransformTo(null). Manually multiply the // root transform to the global transform. final Matrix4 rootTransform = Matrix4.identity(); - tester.binding.renderView.applyPaintTransform(tester.binding.renderView.child!, rootTransform); + renderView.applyPaintTransform(renderView.child!, rootTransform); rootTransform.multiply(globalTransform); screenBounds = MatrixUtils.transformRect(rootTransform, renderBox.paintBounds); Rect nodeBounds = node.rect; @@ -443,7 +438,7 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { throw StateError('Unexpected widget type: ${widget.runtimeType}'); } - if (isNodeOffScreen(paintBoundsWithOffset, view)) { + if (isNodeOffScreen(paintBoundsWithOffset, renderView.flutterView)) { return const Evaluation.pass(); } @@ -562,9 +557,7 @@ class CustomMinimumContrastGuideline extends AccessibilityGuideline { Evaluation result = const Evaluation.pass(); for (final Element element in elements) { final FlutterView view = tester.viewOf(find.byElementPredicate((Element e) => e == element)); - - // TODO(pdblasi): Obtain this renderView from view when possible. - final RenderView renderView = tester.binding.renderView; + final RenderView renderView = tester.binding.renderViews.firstWhere((RenderView r) => r.flutterView == view); final OffsetLayer layer = renderView.debugLayer! as OffsetLayer; late final ui.Image image; diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index 23caf1f33b3d3..c3c289b016ed1 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -495,8 +495,8 @@ abstract class TestWidgetsFlutterBinding extends BindingBase Size? _surfaceSize; - /// Artificially changes the surface size to `size` on the Widget binding, - /// then flushes microtasks. + /// Artificially changes the logical size of [WidgetTester.view] to the + /// specified size, then flushes microtasks. /// /// Set to null to use the default surface size. /// @@ -508,7 +508,10 @@ abstract class TestWidgetsFlutterBinding extends BindingBase /// addTearDown(() => binding.setSurfaceSize(null)); /// ``` /// - /// See also [TestFlutterView.physicalSize], which has a similar effect. + /// This method only affects the size of the [WidgetTester.view]. It does not + /// affect the size of any other views. Instead of this method, consider + /// setting [TestFlutterView.physicalSize], which works for any view, + /// including [WidgetTester.view]. // TODO(pdblasi-google): Deprecate this. https://github.com/flutter/flutter/issues/123881 Future setSurfaceSize(Size? size) { return TestAsyncUtils.guard(() async { @@ -522,14 +525,37 @@ abstract class TestWidgetsFlutterBinding extends BindingBase } @override - ViewConfiguration createViewConfiguration() { - final FlutterView view = platformDispatcher.implicitView!; - final double devicePixelRatio = view.devicePixelRatio; - final Size size = _surfaceSize ?? view.physicalSize / devicePixelRatio; - return ViewConfiguration( - size: size, - devicePixelRatio: devicePixelRatio, - ); + void addRenderView(RenderView view) { + _insideAddRenderView = true; + try { + super.addRenderView(view); + } finally { + _insideAddRenderView = false; + } + } + + bool _insideAddRenderView = false; + + @override + ViewConfiguration createViewConfigurationFor(RenderView renderView) { + if (_insideAddRenderView + && renderView.hasConfiguration + && renderView.configuration is TestViewConfiguration + && renderView == this.renderView) { // ignore: deprecated_member_use + // If a test has reached out to the now deprecated renderView property to set a custom TestViewConfiguration + // we are not replacing it. This is to maintain backwards compatibility with how things worked prior to the + // deprecation of that property. + // TODO(goderbauer): Remove this "if" when the deprecated renderView property is removed. + return renderView.configuration; + } + final FlutterView view = renderView.flutterView; + if (_surfaceSize != null && view == platformDispatcher.implicitView) { + return ViewConfiguration( + size: _surfaceSize!, + devicePixelRatio: view.devicePixelRatio, + ); + } + return super.createViewConfigurationFor(renderView); } /// Acts as if the application went idle. @@ -1377,16 +1403,18 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { debugBuildingDirtyElements = true; buildOwner!.buildScope(rootElement!); if (_phase != EnginePhase.build) { - pipelineOwner.flushLayout(); + rootPipelineOwner.flushLayout(); if (_phase != EnginePhase.layout) { - pipelineOwner.flushCompositingBits(); + rootPipelineOwner.flushCompositingBits(); if (_phase != EnginePhase.compositingBits) { - pipelineOwner.flushPaint(); + rootPipelineOwner.flushPaint(); if (_phase != EnginePhase.paint && sendFramesToEngine) { _firstFrameSent = true; - renderView.compositeFrame(); // this sends the bits to the GPU + for (final RenderView renderView in renderViews) { + renderView.compositeFrame(); // this sends the bits to the GPU + } if (_phase != EnginePhase.composite) { - pipelineOwner.flushSemantics(); + rootPipelineOwner.flushSemantics(); // this sends the semantics to the OS. assert(_phase == EnginePhase.flushSemantics || _phase == EnginePhase.sendSemanticsUpdate); } @@ -1759,9 +1787,14 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { } } - void _markViewNeedsPaint() { + void _markViewsNeedPaint([int? viewId]) { _viewNeedsPaint = true; - renderView.markNeedsPaint(); + final Iterable toMark = viewId == null + ? renderViews + : renderViews.where((RenderView renderView) => renderView.flutterView.viewId == viewId); + for (final RenderView renderView in toMark) { + renderView.markNeedsPaint(); + } } TextPainter? _label; @@ -1779,15 +1812,16 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { _label ??= TextPainter(textAlign: TextAlign.left, textDirection: TextDirection.ltr); _label!.text = TextSpan(text: value, style: _labelStyle); _label!.layout(); - _markViewNeedsPaint(); + _markViewsNeedPaint(); } - final Map _pointerIdToPointerRecord = {}; + final Expando> _renderViewToPointerIdToPointerRecord = Expando>(); void _handleRenderViewPaint(PaintingContext context, Offset offset, RenderView renderView) { assert(offset == Offset.zero); - if (_pointerIdToPointerRecord.isNotEmpty) { + final Map? pointerIdToRecord = _renderViewToPointerIdToPointerRecord[renderView]; + if (pointerIdToRecord != null && pointerIdToRecord.isNotEmpty) { final double radius = renderView.configuration.size.shortestSide * 0.05; final Path path = Path() ..addOval(Rect.fromCircle(center: Offset.zero, radius: radius)) @@ -1800,7 +1834,7 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { ..strokeWidth = radius / 10.0 ..style = PaintingStyle.stroke; bool dirty = false; - for (final _LiveTestPointerRecord record in _pointerIdToPointerRecord.values) { + for (final _LiveTestPointerRecord record in pointerIdToRecord.values) { paint.color = record.color.withOpacity(record.decay < 0 ? (record.decay / (_kPointerDecay - 1)) : 1.0); canvas.drawPath(path.shift(record.position), paint); if (record.decay < 0) { @@ -1808,14 +1842,14 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { } record.decay += 1; } - _pointerIdToPointerRecord + pointerIdToRecord .keys - .where((int pointer) => _pointerIdToPointerRecord[pointer]!.decay == 0) + .where((int pointer) => pointerIdToRecord[pointer]!.decay == 0) .toList() - .forEach(_pointerIdToPointerRecord.remove); + .forEach(pointerIdToRecord.remove); if (dirty) { scheduleMicrotask(() { - _markViewNeedsPaint(); + _markViewsNeedPaint(renderView.flutterView.viewId); }); } } @@ -1846,19 +1880,29 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { void handlePointerEvent(PointerEvent event) { switch (pointerEventSource) { case TestBindingEventSource.test: - final _LiveTestPointerRecord? record = _pointerIdToPointerRecord[event.pointer]; - if (record != null) { - record.position = event.position; - if (!event.down) { - record.decay = _kPointerDecay; + RenderView? target; + for (final RenderView renderView in renderViews) { + if (renderView.flutterView.viewId == event.viewId) { + target = renderView; + break; + } + } + if (target != null) { + final _LiveTestPointerRecord? record = _renderViewToPointerIdToPointerRecord[target]?[event.pointer]; + if (record != null) { + record.position = event.position; + if (!event.down) { + record.decay = _kPointerDecay; + } + _markViewsNeedPaint(event.viewId); + } else if (event.down) { + _renderViewToPointerIdToPointerRecord[target] ??= {}; + _renderViewToPointerIdToPointerRecord[target]![event.pointer] = _LiveTestPointerRecord( + event.pointer, + event.position, + ); + _markViewsNeedPaint(event.viewId); } - _markViewNeedsPaint(); - } else if (event.down) { - _pointerIdToPointerRecord[event.pointer] = _LiveTestPointerRecord( - event.pointer, - event.position, - ); - _markViewNeedsPaint(); } super.handlePointerEvent(event); case TestBindingEventSource.device: @@ -1870,6 +1914,7 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { // The pointer events received with this source has a global position // (see [handlePointerEventForSource]). Transform it to the local // coordinate space used by the testing widgets. + final RenderView renderView = renderViews.firstWhere((RenderView r) => r.flutterView.viewId == event.viewId); final PointerEvent localEvent = event.copyWith(position: globalToLocal(event.position, renderView)); withPointerEventSource(TestBindingEventSource.device, () => super.handlePointerEvent(localEvent) @@ -1987,10 +2032,18 @@ class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { } @override - ViewConfiguration createViewConfiguration() { + ViewConfiguration createViewConfigurationFor(RenderView renderView) { + final FlutterView view = renderView.flutterView; + if (view == platformDispatcher.implicitView) { + return TestViewConfiguration.fromView( + size: _surfaceSize ?? _kDefaultTestViewportSize, + view: view, + ); + } + final double devicePixelRatio = view.devicePixelRatio; return TestViewConfiguration.fromView( - size: _surfaceSize ?? _kDefaultTestViewportSize, - view: platformDispatcher.implicitView!, + size: view.physicalSize / devicePixelRatio, + view: view, ); } diff --git a/packages/flutter_test/lib/src/controller.dart b/packages/flutter_test/lib/src/controller.dart index 4033ba0ad872c..9443e36ec97a7 100644 --- a/packages/flutter_test/lib/src/controller.dart +++ b/packages/flutter_test/lib/src/controller.dart @@ -36,7 +36,7 @@ class SemanticsController { /// Creates a [SemanticsController] that uses the given binding. Will be /// automatically created as part of instantiating a [WidgetController], but /// a custom implementation can be passed via the [WidgetController] constructor. - SemanticsController._(WidgetsBinding binding) : _binding = binding; + SemanticsController._(this._controller); static final int _scrollingActions = SemanticsAction.scrollUp.index | @@ -55,7 +55,7 @@ class SemanticsController { SemanticsFlag.isSlider.index | SemanticsFlag.isInMutuallyExclusiveGroup.index; - final WidgetsBinding _binding; + final WidgetController _controller; /// Attempts to find the [SemanticsNode] of first result from `finder`. /// @@ -73,7 +73,7 @@ class SemanticsController { /// if no semantics are found or are not enabled. SemanticsNode find(Finder finder) { TestAsyncUtils.guardSync(); - if (!_binding.semanticsEnabled) { + if (!_controller.binding.semanticsEnabled) { throw StateError('Semantics are not enabled.'); } final Iterable candidates = finder.evaluate(); @@ -109,6 +109,13 @@ class SemanticsController { /// tree. If `end` finds zero elements or more than one element, a /// [StateError] will be thrown. /// + /// If provided, the nodes for `end` and `start` must be part of the same + /// semantics tree, i.e. they must be part of the same view. + /// + /// If neither `start` or `end` is provided, `view` can be provided to specify + /// the semantics tree to traverse. If `view` is left unspecified, + /// [WidgetTester.view] is traversed by default. + /// /// Since the order is simulated, edge cases that differ between platforms /// (such as how the last visible item in a scrollable list is handled) may be /// inconsistent with platform behavior, but are expected to be sufficient for @@ -139,10 +146,47 @@ class SemanticsController { /// parts of the traversal. /// * [orderedEquals], which can be given an [Iterable] to exactly /// match the order of the traversal. - Iterable simulatedAccessibilityTraversal({Finder? start, Finder? end}) { + Iterable simulatedAccessibilityTraversal({Finder? start, Finder? end, FlutterView? view}) { TestAsyncUtils.guardSync(); + FlutterView? startView; + FlutterView? endView; + if (start != null) { + startView = _controller.viewOf(start); + if (view != null && startView != view) { + throw StateError( + 'The start node is not part of the provided view.\n' + 'Finder: ${start.description}\n' + 'View of start node: $startView\n' + 'Specified view: $view' + ); + } + } + if (end != null) { + endView = _controller.viewOf(end); + if (view != null && endView != view) { + throw StateError( + 'The end node is not part of the provided view.\n' + 'Finder: ${end.description}\n' + 'View of end node: $endView\n' + 'Specified view: $view' + ); + } + } + if (endView != null && startView != null && endView != startView) { + throw StateError( + 'The start and end node are in different views.\n' + 'Start finder: ${start!.description}\n' + 'End finder: ${end!.description}\n' + 'View of start node: $startView\n' + 'View of end node: $endView' + ); + } + + final FlutterView actualView = view ?? startView ?? endView ?? _controller.view; + final RenderView renderView = _controller.binding.renderViews.firstWhere((RenderView r) => r.flutterView == actualView); + final List traversal = []; - _traverse(_binding.pipelineOwner.semanticsOwner!.rootSemanticsNode!, traversal); + _traverse(renderView.owner!.semanticsOwner!.rootSemanticsNode!, traversal); int startIndex = 0; int endIndex = traversal.length - 1; @@ -229,8 +273,7 @@ class SemanticsController { /// Concrete subclasses must implement the [pump] method. abstract class WidgetController { /// Creates a widget controller that uses the given binding. - WidgetController(this.binding) - : _semantics = SemanticsController._(binding); + WidgetController(this.binding); /// A reference to the current instance of the binding. final WidgetsBinding binding; @@ -280,7 +323,7 @@ abstract class WidgetController { return _semantics; } - final SemanticsController _semantics; + late final SemanticsController _semantics = SemanticsController._(this); // FINDER API @@ -297,14 +340,16 @@ abstract class WidgetController { /// * [view] which returns the [TestFlutterView] used when only a single /// view is being used. TestFlutterView viewOf(Finder finder) { - final View view = firstWidget( + return _viewOf(finder) as TestFlutterView; + } + + FlutterView _viewOf(Finder finder) { + return firstWidget( find.ancestor( of: finder, matching: find.byType(View), - ) - ); - - return view.view as TestFlutterView; + ), + ).view; } /// Checks if `finder` exists in the tree. @@ -516,7 +561,12 @@ abstract class WidgetController { } /// Returns a list of all the [Layer] objects in the rendering. - List get layers => _walkLayers(binding.renderView.debugLayer!).toList(); + List get layers { + return [ + for (final RenderView renderView in binding.renderViews) + ..._walkLayers(renderView.debugLayer!) + ]; + } Iterable _walkLayers(Layer layer) sync* { TestAsyncUtils.guardSync(); yield layer; @@ -1190,10 +1240,10 @@ abstract class WidgetController { } /// Forwards the given location to the binding's hitTest logic. - HitTestResult hitTestOnBinding(Offset location) { + HitTestResult hitTestOnBinding(Offset location, { int? viewId }) { + viewId ??= view.viewId; final HitTestResult result = HitTestResult(); - // TODO(goderbauer): Support multiple views in flutter_test pointer event handling, https://github.com/flutter/flutter/issues/128281 - binding.hitTest(result, location); // ignore: deprecated_member_use + binding.hitTestInView(result, location, viewId); return result; } @@ -1313,9 +1363,9 @@ abstract class WidgetController { final RenderBox box = element.renderObject! as RenderBox; final Offset location = box.localToGlobal(sizeToPoint(box.size)); if (warnIfMissed) { + final FlutterView view = _viewOf(finder); final HitTestResult result = HitTestResult(); - // TODO(goderbauer): Support multiple views in flutter_test pointer event handling, https://github.com/flutter/flutter/issues/128281 - binding.hitTest(result, location); // ignore: deprecated_member_use + binding.hitTestInView(result, location, view.viewId); bool found = false; for (final HitTestEntry entry in result.path) { if (entry.target == box) { @@ -1324,15 +1374,16 @@ abstract class WidgetController { } } if (!found) { + final RenderView renderView = binding.renderViews.firstWhere((RenderView r) => r.flutterView == view); bool outOfBounds = false; - outOfBounds = !(Offset.zero & binding.renderView.size).contains(location); + outOfBounds = !(Offset.zero & renderView.size).contains(location); if (hitTestWarningShouldBeFatal) { throw FlutterError.fromParts([ ErrorSummary('Finder specifies a widget that would not receive pointer events.'), ErrorDescription('A call to $callee() with finder "$finder" derived an Offset ($location) that would not hit test on the specified widget.'), ErrorHint('Maybe the widget is actually off-screen, or another widget is obscuring it, or the widget cannot receive pointer events.'), if (outOfBounds) - ErrorHint('Indeed, $location is outside the bounds of the root of the render tree, ${binding.renderView.size}.'), + ErrorHint('Indeed, $location is outside the bounds of the root of the render tree, ${renderView.size}.'), box.toDiagnosticsNode(name: 'The finder corresponds to this RenderBox', style: DiagnosticsTreeStyle.singleLine), ErrorDescription('The hit test result at that offset is: $result'), ErrorDescription('If you expected this target not to be able to receive pointer events, pass "warnIfMissed: false" to "$callee()".'), @@ -1343,7 +1394,7 @@ abstract class WidgetController { '\n' 'Warning: A call to $callee() with finder "$finder" derived an Offset ($location) that would not hit test on the specified widget.\n' 'Maybe the widget is actually off-screen, or another widget is obscuring it, or the widget cannot receive pointer events.\n' - '${outOfBounds ? "Indeed, $location is outside the bounds of the root of the render tree, ${binding.renderView.size}.\n" : ""}' + '${outOfBounds ? "Indeed, $location is outside the bounds of the root of the render tree, ${renderView.size}.\n" : ""}' 'The finder corresponds to this RenderBox: $box\n' 'The hit test result at that offset is: $result\n' '${StackTrace.current}' diff --git a/packages/flutter_test/lib/src/finders.dart b/packages/flutter_test/lib/src/finders.dart index 1e881489cb504..e1afcc8fa8cc0 100644 --- a/packages/flutter_test/lib/src/finders.dart +++ b/packages/flutter_test/lib/src/finders.dart @@ -639,11 +639,11 @@ class _HitTestableFinder extends ChainedFinder { @override Iterable filter(Iterable parentCandidates) sync* { for (final Element candidate in parentCandidates) { + final int viewId = candidate.findAncestorWidgetOfExactType()!.view.viewId; final RenderBox box = candidate.renderObject! as RenderBox; final Offset absoluteOffset = box.localToGlobal(alignment.alongSize(box.size)); final HitTestResult hitResult = HitTestResult(); - // TODO(goderbauer): Support multiple views in flutter_test pointer event handling, https://github.com/flutter/flutter/issues/128281 - WidgetsBinding.instance.hitTest(hitResult, absoluteOffset); // ignore: deprecated_member_use + WidgetsBinding.instance.hitTestInView(hitResult, absoluteOffset, viewId); for (final HitTestEntry entry in hitResult.path) { if (entry.target == candidate.renderObject) { yield candidate; diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart index 8cd6d50cb0234..f63f79d0a4491 100644 --- a/packages/flutter_test/lib/src/widget_tester.dart +++ b/packages/flutter_test/lib/src/widget_tester.dart @@ -569,24 +569,12 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker EnginePhase phase = EnginePhase.sendSemanticsUpdate, ]) { return TestAsyncUtils.guard(() { - return _pumpWidget( - binding.wrapWithDefaultView(widget), - duration, - phase, - ); + binding.attachRootWidget(binding.wrapWithDefaultView(widget)); + binding.scheduleFrame(); + return binding.pump(duration, phase); }); } - Future _pumpWidget( - Widget widget, [ - Duration? duration, - EnginePhase phase = EnginePhase.sendSemanticsUpdate, - ]) { - binding.attachRootWidget(widget); - binding.scheduleFrame(); - return binding.pump(duration, phase); - } - @override Future> handlePointerEventRecord(Iterable records) { assert(records.isNotEmpty); @@ -745,12 +733,14 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker 'your widget tree in a RootRestorationScope?', ); return TestAsyncUtils.guard(() async { - final Widget widget = ((binding.rootElement! as RenderObjectToWidgetElement).widget as RenderObjectToWidgetAdapter).child!; + final RootWidget widget = binding.rootElement!.widget as RootWidget; final TestRestorationData restorationData = binding.restorationManager.restorationData; runApp(Container(key: UniqueKey())); await pump(); binding.restorationManager.restoreFrom(restorationData); - return _pumpWidget(widget); + binding.attachToBuildOwner(widget); + binding.scheduleFrame(); + return binding.pump(); }); } @@ -837,9 +827,11 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker bool get hasRunningAnimations => binding.transientCallbackCount > 0; @override - HitTestResult hitTestOnBinding(Offset location) { - location = binding.localToGlobal(location, binding.renderView); - return super.hitTestOnBinding(location); + HitTestResult hitTestOnBinding(Offset location, {int? viewId}) { + viewId ??= view.viewId; + final RenderView renderView = binding.renderViews.firstWhere((RenderView r) => r.flutterView.viewId == viewId); + location = binding.localToGlobal(location, renderView); + return super.hitTestOnBinding(location, viewId: viewId); } @override @@ -861,10 +853,12 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker .map((HitTestEntry candidate) => candidate.target) .whereType() .first; - final Element? innerTargetElement = _lastWhereOrNull( - collectAllElementsFrom(binding.rootElement!, skipOffstage: true), - (Element element) => element.renderObject == innerTarget, - ); + final Element? innerTargetElement = binding.renderViews.contains(innerTarget) + ? null + : _lastWhereOrNull( + collectAllElementsFrom(binding.rootElement!, skipOffstage: true), + (Element element) => element.renderObject == innerTarget, + ); if (innerTargetElement == null) { printToConsole('No widgets found at ${event.position}.'); return; @@ -1060,6 +1054,8 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker int? _lastRecordedSemanticsHandles; + // TODO(goderbauer): Only use binding.debugOutstandingSemanticsHandles when deprecated binding.pipelineOwner is removed. + // ignore: deprecated_member_use int get _currentSemanticsHandles => binding.debugOutstandingSemanticsHandles + binding.pipelineOwner.debugOutstandingSemanticsHandles; void _recordNumberOfSemanticsHandles() { diff --git a/packages/flutter_test/test/multi_view_accessibility_test.dart b/packages/flutter_test/test/multi_view_accessibility_test.dart new file mode 100644 index 0000000000000..c070ad63107ba --- /dev/null +++ b/packages/flutter_test/test/multi_view_accessibility_test.dart @@ -0,0 +1,135 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Detects tap targets in all views', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await pumpViews( + tester: tester, + viewContents: [ + SizedBox( + width: 47.0, + height: 47.0, + child: GestureDetector(onTap: () {}), + ), + SizedBox( + width: 46.0, + height: 46.0, + child: GestureDetector(onTap: () {}), + ), + ], + ); + final Evaluation result = await androidTapTargetGuideline.evaluate(tester); + expect(result.passed, false); + expect( + result.reason, + contains('expected tap target size of at least Size(48.0, 48.0), but found Size(47.0, 47.0)'), + ); + expect( + result.reason, + contains('expected tap target size of at least Size(48.0, 48.0), but found Size(46.0, 46.0)'), + ); + handle.dispose(); + }); + + testWidgets('Detects labeled tap targets in all views', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await pumpViews( + tester: tester, + viewContents: [ + SizedBox( + width: 47.0, + height: 47.0, + child: GestureDetector(onTap: () {}), + ), + SizedBox( + width: 46.0, + height: 46.0, + child: GestureDetector(onTap: () {}), + ), + ], + ); + final Evaluation result = await labeledTapTargetGuideline.evaluate(tester); + expect(result.passed, false); + final List lines = const LineSplitter().convert(result.reason!); + expect(lines, hasLength(2)); + expect(lines.first, startsWith('SemanticsNode#1(Rect.fromLTRB(0.0, 0.0, 47.0, 47.0)')); + expect(lines.first, endsWith('expected tappable node to have semantic label, but none was found.')); + expect(lines.last, startsWith('SemanticsNode#2(Rect.fromLTRB(0.0, 0.0, 46.0, 46.0)')); + expect(lines.last, endsWith('expected tappable node to have semantic label, but none was found.')); + handle.dispose(); + }); + + testWidgets('Detects contrast problems in all views', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + await pumpViews( + tester: tester, + viewContents: [ + Container( + width: 200.0, + height: 200.0, + color: Colors.yellow, + child: const Text( + 'this is a test', + style: TextStyle(fontSize: 14.0, color: Colors.yellowAccent), + ), + ), + Container( + width: 200.0, + height: 200.0, + color: Colors.yellow, + child: const Text( + 'this is a test', + style: TextStyle(fontSize: 25.0, color: Colors.yellowAccent), + ), + ), + ], + ); + final Evaluation result = await textContrastGuideline.evaluate(tester); + expect(result.passed, false); + expect(result.reason, contains('Expected contrast ratio of at least 4.5 but found 0.88 for a font size of 14.0.')); + expect(result.reason, contains('Expected contrast ratio of at least 3.0 but found 0.88 for a font size of 25.0.')); + handle.dispose(); + }); +} + +Future pumpViews({required WidgetTester tester, required List viewContents}) { + final List views = [ + for (int i = 0; i < viewContents.length; i++) + View( + view: FakeView(tester.view, viewId: i + 100), + child: Center( + child: viewContents[i], + ), + ), + ]; + + tester.binding.attachRootWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ViewCollection( + views: views, + ), + ), + ); + tester.binding.scheduleFrame(); + return tester.binding.pump(); +} + +class FakeView extends TestFlutterView{ + FakeView(FlutterView view, { this.viewId = 100 }) : super( + view: view, + platformDispatcher: view.platformDispatcher as TestPlatformDispatcher, + display: view.display as TestDisplay, + ); + + @override + final int viewId; +} diff --git a/packages/flutter_test/test/multi_view_controller_test.dart b/packages/flutter_test/test/multi_view_controller_test.dart new file mode 100644 index 0000000000000..6d74d924c15fc --- /dev/null +++ b/packages/flutter_test/test/multi_view_controller_test.dart @@ -0,0 +1,232 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('simulatedAccessibilityTraversal - start and end in same view', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + tester.semantics.simulatedAccessibilityTraversal( + start: find.text('View2Child1'), + end: find.text('View2Child3'), + ).map((SemanticsNode node) => node.label), + [ + 'View2Child1', + 'View2Child2', + 'View2Child3', + ], + ); + }); + + testWidgets('simulatedAccessibilityTraversal - start not specified', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + tester.semantics.simulatedAccessibilityTraversal( + end: find.text('View2Child3'), + ).map((SemanticsNode node) => node.label), + [ + 'View2Child0', + 'View2Child1', + 'View2Child2', + 'View2Child3', + ], + ); + }); + + testWidgets('simulatedAccessibilityTraversal - end not specified', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + tester.semantics.simulatedAccessibilityTraversal( + start: find.text('View2Child1'), + ).map((SemanticsNode node) => node.label), + [ + 'View2Child1', + 'View2Child2', + 'View2Child3', + 'View2Child4', + ], + ); + }); + + testWidgets('simulatedAccessibilityTraversal - nothing specified', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + tester.semantics.simulatedAccessibilityTraversal().map((SemanticsNode node) => node.label), + [ + 'View1Child0', + 'View1Child1', + 'View1Child2', + 'View1Child3', + 'View1Child4', + ], + ); + // Should be traversing over tester.view. + expect(tester.viewOf(find.text('View1Child0')), tester.view); + }); + + testWidgets('simulatedAccessibilityTraversal - only view specified', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + tester.semantics.simulatedAccessibilityTraversal( + view: tester.viewOf(find.text('View2Child1')), + ).map((SemanticsNode node) => node.label), + [ + 'View2Child0', + 'View2Child1', + 'View2Child2', + 'View2Child3', + 'View2Child4', + ], + ); + }); + + testWidgets('simulatedAccessibilityTraversal - everything specified', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + tester.semantics.simulatedAccessibilityTraversal( + start: find.text('View2Child1'), + end: find.text('View2Child3'), + view: tester.viewOf(find.text('View2Child1')), + ).map((SemanticsNode node) => node.label), + [ + 'View2Child1', + 'View2Child2', + 'View2Child3', + ], + ); + }); + + testWidgets('simulatedAccessibilityTraversal - start and end not in same view', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + () => tester.semantics.simulatedAccessibilityTraversal( + start: find.text('View2Child1'), + end: find.text('View1Child3'), + ), + throwsA(isStateError.having( + (StateError e) => e.message, + 'message', + contains('The start and end node are in different views.'), + )), + ); + }); + + testWidgets('simulatedAccessibilityTraversal - start is not in view', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + () => tester.semantics.simulatedAccessibilityTraversal( + start: find.text('View2Child1'), + end: find.text('View1Child3'), + view: tester.viewOf(find.text('View1Child3')), + ), + throwsA(isStateError.having( + (StateError e) => e.message, + 'message', + contains('The start node is not part of the provided view.'), + )), + ); + }); + + testWidgets('simulatedAccessibilityTraversal - end is not in view', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect( + () => tester.semantics.simulatedAccessibilityTraversal( + start: find.text('View2Child1'), + end: find.text('View1Child3'), + view: tester.viewOf(find.text('View2Child1')), + ), + throwsA(isStateError.having( + (StateError e) => e.message, + 'message', + contains('The end node is not part of the provided view.'), + )), + ); + }); + + testWidgets('viewOf', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect(tester.viewOf(find.text('View0Child0')).viewId, 100); + expect(tester.viewOf(find.text('View1Child1')).viewId, tester.view.viewId); + expect(tester.viewOf(find.text('View2Child2')).viewId, 102); + }); + + testWidgets('layers includes layers from all views', (WidgetTester tester) async { + await pumpViews(tester: tester); + const int numberOfViews = 3; + expect(tester.binding.renderViews.length, numberOfViews); // One RenderView for each FlutterView. + + final List layers = tester.layers; + // Each RenderView contributes a TransformLayer and a PictureLayer. + expect(layers, hasLength(numberOfViews * 2)); + expect(layers.whereType(), hasLength(numberOfViews)); + expect(layers.whereType(), hasLength(numberOfViews)); + expect( + layers.whereType().map((TransformLayer l ) => l.owner), + containsAll(tester.binding.renderViews), + ); + }); + + testWidgets('hitTestOnBinding', (WidgetTester tester) async { + await pumpViews(tester: tester); + // Not specifying a viewId hit tests on tester.view: + HitTestResult result = tester.hitTestOnBinding(Offset.zero); + expect(result.path.map((HitTestEntry h) => h.target).whereType().single.flutterView, tester.view); + // Specifying a viewId is respected: + result = tester.hitTestOnBinding(Offset.zero, viewId: 100); + expect(result.path.map((HitTestEntry h) => h.target).whereType().single.flutterView.viewId, 100); + result = tester.hitTestOnBinding(Offset.zero, viewId: 102); + expect(result.path.map((HitTestEntry h) => h.target).whereType().single.flutterView.viewId, 102); + }); + + testWidgets('hitTestable works in different Views', (WidgetTester tester) async { + await pumpViews(tester: tester); + expect((find.text('View0Child0').hitTestable().evaluate().single.widget as Text).data, 'View0Child0'); + expect((find.text('View1Child1').hitTestable().evaluate().single.widget as Text).data, 'View1Child1'); + expect((find.text('View2Child2').hitTestable().evaluate().single.widget as Text).data, 'View2Child2'); + }); +} + +Future pumpViews({required WidgetTester tester}) { + final List views = [ + for (int i = 0; i < 3; i++) + View( + view: i == 1 ? tester.view : FakeView(tester.view, viewId: i + 100), + child: Center( + child: Column( + children: [ + for (int c = 0; c < 5; c++) + Semantics(container: true, child: Text('View${i}Child$c')), + ], + ), + ), + ), + ]; + + tester.binding.attachRootWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ViewCollection( + views: views, + ), + ), + ); + tester.binding.scheduleFrame(); + return tester.binding.pump(); +} + +class FakeView extends TestFlutterView{ + FakeView(FlutterView view, { this.viewId = 100 }) : super( + view: view, + platformDispatcher: view.platformDispatcher as TestPlatformDispatcher, + display: view.display as TestDisplay, + ); + + @override + final int viewId; +} diff --git a/packages/flutter_test/test/semantics_checker/flutter_test_config.dart b/packages/flutter_test/test/semantics_checker/flutter_test_config.dart index 88b2aee380d1a..f4a4af6b75ef0 100644 --- a/packages/flutter_test/test/semantics_checker/flutter_test_config.dart +++ b/packages/flutter_test/test/semantics_checker/flutter_test_config.dart @@ -22,9 +22,9 @@ Future testExecutable(FutureOr Function() testMain) async { void pipelineOwnerTestRun() { testWidgets('open SemanticsHandle from PipelineOwner fails test', (WidgetTester tester) async { - final int outstandingHandles = tester.binding.pipelineOwner.debugOutstandingSemanticsHandles; - tester.binding.pipelineOwner.ensureSemantics(); - expect(tester.binding.pipelineOwner.debugOutstandingSemanticsHandles, outstandingHandles + 1); + final int outstandingHandles = tester.binding.debugOutstandingSemanticsHandles; + tester.binding.ensureSemantics(); + expect(tester.binding.debugOutstandingSemanticsHandles, outstandingHandles + 1); // SemanticsHandle is not disposed on purpose to verify in tearDown that // the test failed due to an active SemanticsHandle. }); diff --git a/packages/flutter_test/test/widget_tester_live_device_test.dart b/packages/flutter_test/test/widget_tester_live_device_test.dart index 4f9871011ecc6..c6468a2f47fa6 100644 --- a/packages/flutter_test/test/widget_tester_live_device_test.dart +++ b/packages/flutter_test/test/widget_tester_live_device_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; // Only check the initial lines of the message, since the message walks the @@ -82,7 +83,7 @@ No widgets found at Offset(1.0, 1.0). ), ); - final Size originalSize = tester.binding.createViewConfiguration().size; + final Size originalSize = tester.binding.createViewConfigurationFor(tester.binding.renderView).size; // ignore: deprecated_member_use await tester.binding.setSurfaceSize(const Size(2000, 1800)); try { await tester.pump(); @@ -126,6 +127,7 @@ class _MockLiveTestWidgetsFlutterBinding extends LiveTestWidgetsFlutterBinding { // real devices touches sends event in the global coordinate system. // See the documentation of [handlePointerEventForSource] for details. if (source == TestBindingEventSource.test) { + final RenderView renderView = renderViews.firstWhere((RenderView r) => r.flutterView.viewId == event.viewId); final PointerEvent globalEvent = event.copyWith(position: localToGlobal(event.position, renderView)); return super.handlePointerEventForSource(globalEvent); } diff --git a/packages/integration_test/lib/integration_test.dart b/packages/integration_test/lib/integration_test.dart index d46276d1bd6f1..14542e6637e09 100644 --- a/packages/integration_test/lib/integration_test.dart +++ b/packages/integration_test/lib/integration_test.dart @@ -100,10 +100,6 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab // under debug mode. static bool _firstRun = false; - /// Artificially changes the surface size to `size` on the Widget binding, - /// then flushes microtasks. - /// - /// Set to null to use the default surface size. @override Future setSurfaceSize(Size? size) { return TestAsyncUtils.guard(() async { @@ -117,12 +113,11 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab } @override - ViewConfiguration createViewConfiguration() { - final FlutterView view = platformDispatcher.implicitView!; - final double devicePixelRatio = view.devicePixelRatio; - final Size size = _surfaceSize ?? view.physicalSize / devicePixelRatio; + ViewConfiguration createViewConfigurationFor(RenderView renderView) { + final FlutterView view = renderView.flutterView; + final Size? surfaceSize = view == platformDispatcher.implicitView ? _surfaceSize : null; return TestViewConfiguration.fromView( - size: size, + size: surfaceSize ?? view.physicalSize / view.devicePixelRatio, view: view, ); } @@ -442,11 +437,11 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab Timeout defaultTestTimeout = Timeout.none; @override - void attachRootWidget(Widget rootWidget) { + Widget wrapWithDefaultView(Widget rootWidget) { // This is a workaround where screenshots of root widgets have incorrect // bounds. // TODO(jiahaog): Remove when https://github.com/flutter/flutter/issues/66006 is fixed. - super.attachRootWidget(RepaintBoundary(child: rootWidget)); + return super.wrapWithDefaultView(RepaintBoundary(child: rootWidget)); } @override From 083d18e83f8f0347a4b22118ad3f66aa0dd7ea0e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 12:21:15 -0400 Subject: [PATCH 0191/1547] Roll Flutter Engine from e4cae43c9c7a to b5282b089513 (1 revision) (#130723) https://github.com/flutter/engine/compare/e4cae43c9c7a...b5282b089513 2023-07-16 skia-flutter-autoroll@skia.org Roll Skia from ee4369879cc0 to 288c98d7ef0b (1 revision) (flutter/engine#43733) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ff16c3f7b21f2..802d49d69022e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e4cae43c9c7a61084fe0a5d47c0253413f8da771 +b5282b08951344e5f4b6eaf1c8e5ee153bb9ee9e From 1bfe228947485c7f6b1ac3908fcaa60480720822 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 13:34:15 -0400 Subject: [PATCH 0192/1547] Roll Flutter Engine from b5282b089513 to 09fe990ebfcf (1 revision) (#130729) https://github.com/flutter/engine/compare/b5282b089513...09fe990ebfcf 2023-07-17 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Buo0mx6dVLK5kvgQ3... to WZt3P7Fm3_GUvAaDv... (flutter/engine#43734) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from Buo0mx6dVLK5 to WZt3P7Fm3_GU If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 802d49d69022e..de0fa3345e47f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b5282b08951344e5f4b6eaf1c8e5ee153bb9ee9e +09fe990ebfcfde02bc860327fef3ea7d849fbd73 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 4bff2ef00e0ca..48950f33b2e18 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -Buo0mx6dVLK5kvgQ3U5YTxISQGTsnaPC4axo699B5oEC +WZt3P7Fm3_GUvAaDvmnYWul_8lnAYZ6MB5ZCdcp5VhsC From 7937b1d51f7b2bc835845f0c2fdbea15013251ec Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Mon, 17 Jul 2023 10:34:35 -0700 Subject: [PATCH 0193/1547] Skip the iteration in Layer._fireCompositionCallbacks if the callbacks map is empty (#130438) This was showing up as a hot spot in some benchmarks and profiles. This function is called frequently during frame builds and often has an empty map. There may be significant overhead from obtaining the values iterator and cloning it into a list. See https://github.com/flutter/flutter/issues/130339 --- packages/flutter/lib/src/rendering/layer.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index 779574f3f872c..51b5e86a2e45f 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -172,6 +172,9 @@ abstract class Layer with DiagnosticableTreeMixin { } void _fireCompositionCallbacks({required bool includeChildren}) { + if (_callbacks.isEmpty) { + return; + } for (final VoidCallback callback in List.of(_callbacks.values)) { callback(); } From e06650bdbeb4b0ca8273bc2651a48e9549c08954 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 17 Jul 2023 10:40:07 -0700 Subject: [PATCH 0194/1547] Guard access to dart:developer with !kReleaseMode (#130627) --- .../flutter/lib/src/foundation/binding.dart | 12 ++++-- .../flutter/lib/src/painting/image_cache.dart | 37 +++++++++---------- .../lib/src/painting/shader_warm_up.dart | 10 +++-- .../flutter/lib/src/scheduler/binding.dart | 10 +++-- .../lib/src/services/platform_channel.dart | 10 +++-- 5 files changed, 47 insertions(+), 32 deletions(-) diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index bc451ac718c54..de0bac79bc6ab 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -158,9 +158,8 @@ abstract class BindingBase { initServiceExtensions(); assert(_debugServiceExtensionsRegistered); - developer.postEvent('Flutter.FrameworkInitialization', {}); - if (!kReleaseMode) { + developer.postEvent('Flutter.FrameworkInitialization', {}); FlutterTimeline.finishSync(); } } @@ -657,14 +656,19 @@ abstract class BindingBase { /// [locked]. @protected Future lockEvents(Future Function() callback) { - final developer.TimelineTask timelineTask = developer.TimelineTask()..start('Lock events'); + developer.TimelineTask? debugTimelineTask; + if (!kReleaseMode) { + debugTimelineTask = developer.TimelineTask()..start('Lock events'); + } _lockCount += 1; final Future future = callback(); future.whenComplete(() { _lockCount -= 1; if (!locked) { - timelineTask.finish(); + if (!kReleaseMode) { + debugTimelineTask!.finish(); + } try { unlocked(); } catch (error, stack) { diff --git a/packages/flutter/lib/src/painting/image_cache.dart b/packages/flutter/lib/src/painting/image_cache.dart index d14bab2ccd40b..7a7c17b46ccac 100644 --- a/packages/flutter/lib/src/painting/image_cache.dart +++ b/packages/flutter/lib/src/painting/image_cache.dart @@ -103,9 +103,9 @@ class ImageCache { if (value == maximumSize) { return; } - TimelineTask? timelineTask; + TimelineTask? debugTimelineTask; if (!kReleaseMode) { - timelineTask = TimelineTask()..start( + debugTimelineTask = TimelineTask()..start( 'ImageCache.setMaximumSize', arguments: {'value': value}, ); @@ -114,10 +114,10 @@ class ImageCache { if (maximumSize == 0) { clear(); } else { - _checkCacheSize(timelineTask); + _checkCacheSize(debugTimelineTask); } if (!kReleaseMode) { - timelineTask!.finish(); + debugTimelineTask!.finish(); } } @@ -142,9 +142,9 @@ class ImageCache { if (value == _maximumSizeBytes) { return; } - TimelineTask? timelineTask; + TimelineTask? debugTimelineTask; if (!kReleaseMode) { - timelineTask = TimelineTask()..start( + debugTimelineTask = TimelineTask()..start( 'ImageCache.setMaximumSizeBytes', arguments: {'value': value}, ); @@ -153,10 +153,10 @@ class ImageCache { if (_maximumSizeBytes == 0) { clear(); } else { - _checkCacheSize(timelineTask); + _checkCacheSize(debugTimelineTask); } if (!kReleaseMode) { - timelineTask!.finish(); + debugTimelineTask!.finish(); } } @@ -283,7 +283,6 @@ class ImageCache { /// Resizes the cache as appropriate to maintain the constraints of /// [maximumSize] and [maximumSizeBytes]. void _touch(Object key, _CachedImage image, TimelineTask? timelineTask) { - assert(timelineTask != null); if (image.sizeBytes != null && image.sizeBytes! <= maximumSizeBytes && maximumSize > 0) { _currentSizeBytes += image.sizeBytes!; _cache[key] = image; @@ -324,9 +323,9 @@ class ImageCache { /// Images that are larger than [maximumSizeBytes] are not cached, and do not /// cause other images in the cache to be evicted. ImageStreamCompleter? putIfAbsent(Object key, ImageStreamCompleter Function() loader, { ImageErrorListener? onError }) { - TimelineTask? timelineTask; + TimelineTask? debugTimelineTask; if (!kReleaseMode) { - timelineTask = TimelineTask()..start( + debugTimelineTask = TimelineTask()..start( 'ImageCache.putIfAbsent', arguments: { 'key': key.toString(), @@ -337,7 +336,7 @@ class ImageCache { // Nothing needs to be done because the image hasn't loaded yet. if (result != null) { if (!kReleaseMode) { - timelineTask!.finish(arguments: {'result': 'pending'}); + debugTimelineTask!.finish(arguments: {'result': 'pending'}); } return result; } @@ -348,7 +347,7 @@ class ImageCache { final _CachedImage? image = _cache.remove(key); if (image != null) { if (!kReleaseMode) { - timelineTask!.finish(arguments: {'result': 'keepAlive'}); + debugTimelineTask!.finish(arguments: {'result': 'keepAlive'}); } // The image might have been keptAlive but had no listeners (so not live). // Make sure the cache starts tracking it as live again. @@ -369,10 +368,10 @@ class ImageCache { liveImage.completer, sizeBytes: liveImage.sizeBytes, ), - timelineTask, + debugTimelineTask, ); if (!kReleaseMode) { - timelineTask!.finish(arguments: {'result': 'keepAlive'}); + debugTimelineTask!.finish(arguments: {'result': 'keepAlive'}); } return liveImage.completer; } @@ -382,7 +381,7 @@ class ImageCache { _trackLiveImage(key, result, null); } catch (error, stackTrace) { if (!kReleaseMode) { - timelineTask!.finish(arguments: { + debugTimelineTask!.finish(arguments: { 'result': 'error', 'error': error.toString(), 'stackTrace': stackTrace.toString(), @@ -397,7 +396,7 @@ class ImageCache { } if (!kReleaseMode) { - timelineTask!.start('listener'); + debugTimelineTask!.start('listener'); } // A multi-frame provider may call the listener more than once. We need do make // sure that some cleanup works won't run multiple times, such as finishing the @@ -424,7 +423,7 @@ class ImageCache { // Only touch if the cache was enabled when resolve was initially called. if (trackPendingImage) { - _touch(key, image, timelineTask); + _touch(key, image, debugTimelineTask); } else { image.dispose(); } @@ -434,7 +433,7 @@ class ImageCache { pendingImage.removeListener(); } if (!kReleaseMode && !listenedOnce) { - timelineTask! + debugTimelineTask! ..finish(arguments: { 'syncCall': syncCall, 'sizeInBytes': sizeBytes, diff --git a/packages/flutter/lib/src/painting/shader_warm_up.dart b/packages/flutter/lib/src/painting/shader_warm_up.dart index 29bc0ecbc1cc9..48a5bf0edfdfc 100644 --- a/packages/flutter/lib/src/painting/shader_warm_up.dart +++ b/packages/flutter/lib/src/painting/shader_warm_up.dart @@ -88,14 +88,18 @@ abstract class ShaderWarmUp { final ui.Picture picture = recorder.endRecording(); assert(debugCaptureShaderWarmUpPicture(picture)); if (!kIsWeb || isCanvasKit) { // Picture.toImage is not yet implemented on the web. - final TimelineTask shaderWarmUpTask = TimelineTask(); - shaderWarmUpTask.start('Warm-up shader'); + TimelineTask? debugShaderWarmUpTask; + if (!kReleaseMode) { + debugShaderWarmUpTask = TimelineTask()..start('Warm-up shader'); + } try { final ui.Image image = await picture.toImage(size.width.ceil(), size.height.ceil()); assert(debugCaptureShaderWarmUpImage(image)); image.dispose(); } finally { - shaderWarmUpTask.finish(); + if (!kReleaseMode) { + debugShaderWarmUpTask!.finish(); + } } } picture.dispose(); diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index dc690ab518825..0ff4b85c7f790 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -14,7 +14,6 @@ import 'debug.dart'; import 'priority.dart'; import 'service_extensions.dart'; -export 'dart:developer' show Flow; export 'dart:ui' show AppLifecycleState, FrameTiming, TimingsCallback; export 'priority.dart' show Priority; @@ -940,7 +939,10 @@ mixin SchedulerBinding on BindingBase { } _warmUpFrame = true; - final TimelineTask timelineTask = TimelineTask()..start('Warm-up frame'); + TimelineTask? debugTimelineTask; + if (!kReleaseMode) { + debugTimelineTask = TimelineTask()..start('Warm-up frame'); + } final bool hadScheduledFrame = _hasScheduledFrame; // We use timers here to ensure that microtasks flush in between. Timer.run(() { @@ -969,7 +971,9 @@ mixin SchedulerBinding on BindingBase { // scheduled frame has finished. lockEvents(() async { await endOfFrame; - timelineTask.finish(); + if (!kReleaseMode) { + debugTimelineTask!.finish(); + } }); } diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index b794253dd1834..259583f2e0bb4 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart @@ -39,14 +39,18 @@ class _ProfiledBinaryMessenger implements BinaryMessenger { } Future? sendWithPostfix(String channel, String postfix, ByteData? message) async { - final TimelineTask task = TimelineTask(); _debugRecordUpStream(channelTypeName, '$channel$postfix', codecTypeName, message); - task.start('Platform Channel send $channel$postfix'); + TimelineTask? debugTimelineTask; + if (!kReleaseMode) { + debugTimelineTask = TimelineTask()..start('Platform Channel send $channel$postfix'); + } final ByteData? result; try { result = await proxy.send(channel, message); } finally { - task.finish(); + if (!kReleaseMode) { + debugTimelineTask!.finish(); + } } _debugRecordDownStream(channelTypeName, '$channel$postfix', codecTypeName, result); return result; From d64cc47920ba2a1f1b3b172aabbd71bb3ffcc368 Mon Sep 17 00:00:00 2001 From: Lau Ching Jun Date: Mon, 17 Jul 2023 10:40:12 -0700 Subject: [PATCH 0195/1547] Make ProxiedDevices a subclass of PollingDeviceDiscovery. (#130640) The daemon ignores all device discovery that is not a PollingDeviceDiscovery. Make ProxiedDevices a PollingDeviceDiscovery so that it can be used in flutter daemon. Note that there is a TODO item added in the test, which I intend to attempt fixing in a subsequent PR. --- .../lib/src/proxied_devices/devices.dart | 8 +++- .../proxied_devices/proxied_devices_test.dart | 39 ++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/packages/flutter_tools/lib/src/proxied_devices/devices.dart b/packages/flutter_tools/lib/src/proxied_devices/devices.dart index 332b30b0e50f2..93df50e03ff43 100644 --- a/packages/flutter_tools/lib/src/proxied_devices/devices.dart +++ b/packages/flutter_tools/lib/src/proxied_devices/devices.dart @@ -36,14 +36,15 @@ T _cast(Object? object) { /// /// If [deltaFileTransfer] is true, the proxy will use an rsync-like algorithm that /// only transfers the changed part of the application package for deployment. -class ProxiedDevices extends DeviceDiscovery { +class ProxiedDevices extends PollingDeviceDiscovery { ProxiedDevices(this.connection, { bool deltaFileTransfer = true, bool enableDdsProxy = false, required Logger logger, }) : _deltaFileTransfer = deltaFileTransfer, _enableDdsProxy = enableDdsProxy, - _logger = logger; + _logger = logger, + super('Proxied devices'); /// [DaemonConnection] used to communicate with the daemon. final DaemonConnection connection; @@ -88,6 +89,9 @@ class ProxiedDevices extends DeviceDiscovery { return filter.filterDevices(devices); } + @override + Future> pollingGetDevices({Duration? timeout}) => discoverDevices(timeout: timeout); + @override List get wellKnownIds => const []; diff --git a/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart b/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart index 8522d41e77c29..9f601fbbac03a 100644 --- a/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart +++ b/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart @@ -8,6 +8,7 @@ import 'dart:typed_data'; import 'package:flutter_tools/src/base/dds.dart'; import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/utils.dart'; import 'package:flutter_tools/src/daemon.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/proxied_devices/devices.dart'; @@ -363,7 +364,43 @@ void main() { expect(fakeFilter.devices![0].id, fakeDevice['id']); expect(fakeFilter.devices![1].id, fakeDevice2['id']); }); - }); + + testWithoutContext('publishes the devices on deviceNotifier after startPolling', () async { + bufferLogger = BufferLogger.test(); + final ProxiedDevices proxiedDevices = ProxiedDevices( + clientDaemonConnection, + logger: bufferLogger, + ); + + proxiedDevices.startPolling(); + + final ItemListNotifier? deviceNotifier = proxiedDevices.deviceNotifier; + expect(deviceNotifier, isNotNull); + + final List devicesAdded = []; + deviceNotifier!.onAdded.listen((Device device) { + devicesAdded.add(device); + }); + + final DaemonMessage message = await serverDaemonConnection.incomingCommands.first; + expect(message.data['id'], isNotNull); + expect(message.data['method'], 'device.discoverDevices'); + + serverDaemonConnection.sendResponse(message.data['id']!, >[ + fakeDevice, + fakeDevice2, + ]); + + await pumpEventQueue(); + + expect(devicesAdded.length, 2); + expect(devicesAdded[0].id, fakeDevice['id']); + expect(devicesAdded[1].id, fakeDevice2['id']); + }); + // Explicit timeout is needed because the default timeout is 2s, but `startPolling` waits for + // 4s before making its first poll. + // TODO(chingjun): Remove the timeout. + }, timeout: const Timeout(Duration(seconds: 6))); group('ProxiedDartDevelopmentService', () { testWithoutContext('forwards start and shutdown to remote', () async { From bf4d6597266f3d1ce76c6e24314dbdfdc427c62e Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:46:00 -0700 Subject: [PATCH 0196/1547] Allow `OverlayPortal` to be added/removed from the tree in a layout callback (#130670) Fixes https://github.com/flutter/flutter/issues/130668 --- packages/flutter/lib/src/widgets/overlay.dart | 12 +--- .../test/widgets/overlay_portal_test.dart | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index 6b2427662a639..04c71fab73f0e 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -936,14 +936,6 @@ class _RenderTheater extends RenderBox with ContainerRenderObjectMixin visitChildren(redepthChild); - void _adoptDeferredLayoutBoxChild(_RenderDeferredLayoutBox child) { - adoptChild(child); - } - - void _dropDeferredLayoutBoxChild(_RenderDeferredLayoutBox child) { - dropChild(child); - } - Alignment? _alignmentCache; Alignment get _resolvedAlignment => _alignmentCache ??= AlignmentDirectional.topStart.resolve(textDirection); @@ -1704,13 +1696,13 @@ final class _OverlayEntryLocation extends LinkedListEntry<_OverlayEntryLocation> // This call is allowed even when this location is invalidated. // See _OverlayPortalElement.activate. assert(_overlayChildRenderBox == null, '$_overlayChildRenderBox'); - _theater._adoptDeferredLayoutBoxChild(child); + _theater._addDeferredChild(child); _overlayChildRenderBox = child; } void _deactivate(_RenderDeferredLayoutBox child) { // This call is allowed even when this location is invalidated. - _theater._dropDeferredLayoutBoxChild(child); + _theater._removeDeferredChild(child); _overlayChildRenderBox = null; } diff --git a/packages/flutter/test/widgets/overlay_portal_test.dart b/packages/flutter/test/widgets/overlay_portal_test.dart index 1d90ecf1b7f77..702a5db64058d 100644 --- a/packages/flutter/test/widgets/overlay_portal_test.dart +++ b/packages/flutter/test/widgets/overlay_portal_test.dart @@ -655,6 +655,63 @@ void main() { verifyTreeIsClean(); }); + testWidgets('Adding/Removing OverlayPortal in LayoutBuilder during layout', (WidgetTester tester) async { + final GlobalKey widgetKey = GlobalKey(debugLabel: 'widget'); + final GlobalKey overlayKey = GlobalKey(debugLabel: 'overlay'); + controller1.hide(); + late StateSetter setState; + Size size = Size.zero; + + final Widget overlayPortal = OverlayPortal( + key: widgetKey, + controller: controller1, + overlayChildBuilder: (BuildContext context) => const Placeholder(), + child: const Placeholder(), + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + key: overlayKey, + initialEntries: [ + OverlayEntry( + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + setState = stateSetter; + return Center( + child: SizedBox.fromSize( + size: size, + child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { + // This layout callback adds/removes an OverlayPortal during layout. + return constraints.maxHeight > 0 ? overlayPortal : const SizedBox(); + }), + ), + ); + } + ); + } + ), + ], + ), + ), + ); + controller1.show(); + await tester.pump(); + expect(tester.takeException(), isNull); + + // Adds the OverlayPortal from within a LayoutBuilder, in a layout callback. + setState(() { size = const Size(300, 300); }); + await tester.pump(); + expect(tester.takeException(), isNull); + + // Removes the OverlayPortal from within a LayoutBuilder, in a layout callback. + setState(() { size = Size.zero; }); + await tester.pump(); + expect(tester.takeException(), isNull); + }); + testWidgets('Change overlay constraints', (WidgetTester tester) async { final GlobalKey widgetKey = GlobalKey(debugLabel: 'widget outer'); final GlobalKey overlayKey = GlobalKey(debugLabel: 'overlay'); From 0d1cc33b65aea95ee9ce320de5b96224d92fd770 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:46:03 -0700 Subject: [PATCH 0197/1547] `_RenderScaledInlineWidget` constrains child size (#130648) Fixes https://github.com/flutter/flutter/issues/130588 --- .../flutter/lib/src/widgets/widget_span.dart | 2 +- packages/flutter/test/widgets/text_test.dart | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/widget_span.dart b/packages/flutter/lib/src/widgets/widget_span.dart index b0e5ad99b3be3..776d4087ceff2 100644 --- a/packages/flutter/lib/src/widgets/widget_span.dart +++ b/packages/flutter/lib/src/widgets/widget_span.dart @@ -375,7 +375,7 @@ class _RenderScaledInlineWidget extends RenderBox with RenderObjectWithChildMixi // Only constrain the width to the maximum width of the paragraph. // Leave height unconstrained, which will overflow if expanded past. child.layout(BoxConstraints(maxWidth: constraints.maxWidth / scale), parentUsesSize: true); - size = child.size * scale; + size = constraints.constrain(child.size * scale); } @override diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index ea3202509c8cf..0289a64d20b0c 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -266,6 +266,23 @@ void main() { expect(renderText.size.height, singleLineHeight * textScaleFactor * 3); }); + testWidgets("Inline widgets' scaled sizes are constrained", (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/130588 + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + width: 100.3, + child: Text.rich(WidgetSpan(child: Row()), textScaleFactor: 0.3), + ), + ), + ), + ); + + expect(tester.takeException(), isNull); + }); + testWidgets('semanticsLabel can override text label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( From b2e22d3558e8334d4427ed9b78d21a347375fad2 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Mon, 17 Jul 2023 10:56:07 -0700 Subject: [PATCH 0198/1547] Replaces `textScaleFactor` with `TextScaler` (#128522) Deprecate `textScaleFactor` in favor of `textScaler`, in preparation for Android 14 [Non-linear font scaling to 200%](https://developer.android.com/about/versions/14/features#non-linear-font-scaling). The `TextScaler` class can be moved to `dart:ui` in the future, if we decide to use the Android platform API or AndroidX to get the scaling curve instead of hard coding the curve in the framework. I haven't put the Flutter version in the deprecation message so the analyzer checks are failing. Will do so after I finish the migration guide. **Why `TextScaler.textScaleFactor`** The author of a `TextScaler` subclass should provide a fallback `textScaleFactor`. By making `TextScaler` also contain the `textScaleFactor` information it also makes it easier to migrate: if a widget overrides `MediaQueryData.textScaler` in the tree, for unmigrated widgets in the subtree it would also have to override `MediaQueryData.textScaleFactor`, and that makes it difficult to remove `MediaQueryData.textScaleFactor` in the future. ## A full list of affected APIs in this PR Deprecated: The method/getter/setter/argument is annotated with a `@Deprecated()` annotation in this PR, and the caller should replace it with `textScaler` instead. Unless otherwise specified there will be a Flutter fix available to help with migration but it's still recommended to migrate case-by-case. **Replaced**: The method this `textScaleFactor` argument belongs to is rarely called directly by user code and is not overridden by any of the registered custom tests, so the argument is directly replaced by `TextScaler`. **To Be Deprecated**: The method/getter/setter/argument can't be deprecated in this PR because a registered customer test depends on it and a Flutter fix isn't available (or the test was run without applying flutter fixes first). This method/getter/setter/argument will be deprecated in a followup PR once the registered test is migrated. ### `Painting` Library | Affected API | State of `textScaleFactor` | Comment | | --- | --- | --- | | `InlineSpan.build({ double textScaleFactor = 1.0 })` argument | **Replaced** | | | `TextStyle.getParagraphStyle({ double TextScaleFactor = 1.0 })` argument | **Replaced** | | | `TextStyle.getTextStyle({ double TextScaleFactor = 1.0 })` argument| Deprecated | Can't replace: https://github.com/superlistapp/super_editor/blob/c47fd38dca4b7f43611690913b551a1773c563d7/super_editor/lib/src/infrastructure/super_textfield/desktop/desktop_textfield.dart#L1903-L1905| | `TextPainter({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | | | `TextPainter.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet | | `TextPainter.computeWidth({ double TextScaleFactor = 1.0 })` argument | Deprecated | | | `TextPainter.computeMaxIntrinsicWidth({ double TextScaleFactor = 1.0 })` argument | Deprecated | | ### `Rendering` Library | Affected API | State of `textScaleFactor` | Comment | | --- | --- | --- | | `RenderEditable({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | | | `RenderEditable.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet | | `RenderParagraph({ double TextScaleFactor = 1.0 })` constructor argument | Deprecated | | | `RenderParagraph.textScaleFactor` getter and setter | Deprecated | No Flutter Fix, not expressible yet | ### `Widgets` Library | Affected API | State of `textScaleFactor` | Comment | | --- | --- | --- | | `MediaQueryData({ double TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/test/text_scale_factor_test.dart#LL39C21-L39C35 | | `MediaQueryData.textScaleFactor` getter | Deprecated | | | `MediaQueryData.copyWith({ double? TextScaleFactor })` argument | Deprecated | | | `MediaQuery.maybeTextScaleFactorOf(BuildContext context)` static method | Deprecated | No Flutter Fix, not expressible yet | | `MediaQuery.textScaleFactorOf(BuildContext context)` static method | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/lib/src/_functions_io.dart#L68-L70, No Flutter Fix, not expressible yet | | `RichText({ double TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/lib/src/builder.dart#L829-L843 | | `RichText.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away| | `Text({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/914d120da12fba458c020210727831c31bd71041/packages/rfw/lib/src/flutter/core_widgets.dart#L647 , No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 | | `Text.rich({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | The default constructor has an argument that can't be deprecated right away. No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 | | `Text.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away | | `EditableText({ double? TextScaleFactor = 1.0 })` constructor argument | Deprecated | No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 | | `EditableText.textScaleFactor` getter | Deprecated | | ### `Material` Library | Affected API | State of `textScaleFactor` | Comment | | --- | --- | --- | | `SelectableText({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | https://github.com/flutter/packages/blob/cd7b93532e5cb605a42735e20f1de70fc00adae7/packages/flutter_markdown/lib/src/builder.dart#L829-L843, No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 | | `SelectableText.rich({ double? TextScaleFactor = 1.0 })` constructor argument | **To Be Deprecated** | The default constructor has an argument that can't be deprecated right away. No Flutter Fix because of https://github.com/dart-lang/sdk/issues/52664 | | `SelectableText.textScaleFactor` getter | **To Be Deprecated** | A constructor argument can't be deprecated right away | A lot of material widgets (`Slider`, `RangeSlider`, `TimePicker`, and different types of buttons) also change their layout based on `textScaleFactor`. These need to be handled in a case-by-case fashion and will be migrated in follow-up PRs. --- .../bench_pageview_scroll_linethrough.dart | 2 +- .../shrine/supplemental/product_card.dart | 3 +- .../flutter_gallery/lib/gallery/app.dart | 8 +- .../flutter_gallery/lib/gallery/home.dart | 3 +- .../flutter_gallery/lib/gallery/options.dart | 3 +- dev/manual_tests/lib/density.dart | 17 +- .../lib/action_chip_template.dart | 2 +- dev/tools/gen_defaults/lib/chip_template.dart | 2 +- .../lib/filter_chip_template.dart | 2 +- .../gen_defaults/lib/input_chip_template.dart | 2 +- .../material/app_bar/sliver_app_bar.1.dart | 2 +- .../material/app_bar/sliver_app_bar.4.dart | 2 +- .../time_picker/show_time_picker.0.dart | 3 +- .../flutter/lib/fix_data/fix_painting.yaml | 88 ++++++ .../flutter/lib/fix_data/fix_rendering.yaml | 44 +++ .../fix_data/fix_widgets/fix_media_query.yaml | 65 ++++ .../fix_data/fix_widgets/fix_rich_text.yaml | 43 +++ packages/flutter/lib/painting.dart | 1 + .../lib/src/cupertino/bottom_tab_bar.dart | 11 +- .../lib/src/cupertino/date_picker.dart | 16 +- .../flutter/lib/src/cupertino/dialog.dart | 18 +- .../flutter/lib/src/cupertino/nav_bar.dart | 28 +- .../lib/src/cupertino/page_scaffold.dart | 13 +- .../lib/src/cupertino/search_field.dart | 3 +- .../lib/src/cupertino/tab_scaffold.dart | 13 +- .../flutter/lib/src/material/action_chip.dart | 2 +- .../flutter/lib/src/material/app_bar.dart | 39 +-- .../src/material/bottom_navigation_bar.dart | 7 +- .../lib/src/material/button_style_button.dart | 15 +- packages/flutter/lib/src/material/chip.dart | 4 +- .../flutter/lib/src/material/choice_chip.dart | 2 +- .../lib/src/material/circle_avatar.dart | 7 +- .../flutter/lib/src/material/date_picker.dart | 24 +- packages/flutter/lib/src/material/dialog.dart | 4 +- .../flutter/lib/src/material/dropdown.dart | 3 +- .../lib/src/material/elevated_button.dart | 8 +- .../lib/src/material/filled_button.dart | 10 +- .../flutter/lib/src/material/filter_chip.dart | 2 +- .../flutter/lib/src/material/input_chip.dart | 2 +- .../lib/src/material/input_decorator.dart | 2 +- .../lib/src/material/navigation_bar.dart | 64 +--- .../lib/src/material/outlined_button.dart | 6 +- .../lib/src/material/selectable_text.dart | 35 ++- packages/flutter/lib/src/material/slider.dart | 4 +- .../flutter/lib/src/material/text_button.dart | 8 +- .../flutter/lib/src/material/time_picker.dart | 16 +- .../flutter/lib/src/painting/inline_span.dart | 8 +- .../lib/src/painting/text_painter.dart | 81 ++++- .../flutter/lib/src/painting/text_scaler.dart | 151 ++++++++++ .../flutter/lib/src/painting/text_span.dart | 7 +- .../flutter/lib/src/painting/text_style.dart | 41 ++- .../flutter/lib/src/rendering/editable.dart | 37 ++- .../flutter/lib/src/rendering/paragraph.dart | 45 ++- packages/flutter/lib/src/widgets/basic.dart | 41 ++- .../lib/src/widgets/editable_text.dart | 63 +++- .../flutter/lib/src/widgets/media_query.dart | 207 ++++++++++++- packages/flutter/lib/src/widgets/text.dart | 44 ++- .../flutter/lib/src/widgets/widget_span.dart | 39 ++- .../cupertino/material/tab_scaffold_test.dart | 4 +- .../flutter/test/cupertino/nav_bar_test.dart | 4 +- .../flutter/test/cupertino/scaffold_test.dart | 2 +- .../test/cupertino/tab_scaffold_test.dart | 4 +- .../flutter/test/material/app_bar_test.dart | 30 ++ packages/flutter/test/material/app_test.dart | 7 +- .../flutter/test/material/theme_test.dart | 3 +- .../test/painting/text_painter_test.dart | 8 +- .../test/painting/text_scaler_test.dart | 37 +++ .../test/painting/text_style_test.dart | 4 +- .../test/painting/widget_span_test.dart | 28 -- .../flutter/test/rendering/editable_test.dart | 7 +- .../test/rendering/paragraph_test.dart | 4 +- .../test/widgets/media_query_test.dart | 132 +++++---- .../flutter/test/widgets/rich_text_test.dart | 4 +- .../test/widgets/selectable_text_test.dart | 4 +- ...xt_scaler_backward_compatibility_test.dart | 278 ++++++++++++++++++ packages/flutter/test/widgets/text_test.dart | 12 +- .../test/widgets/widget_span_test.dart | 77 +++++ .../flutter/test_fixes/painting/painting.dart | 11 + .../test_fixes/painting/painting.dart.expect | 11 + .../test_fixes/rendering/rendering.dart | 6 + .../rendering/rendering.dart.expect | 6 + .../test_fixes/widgets/media_query.dart | 13 + .../widgets/media_query.dart.expect | 13 + .../flutter/test_fixes/widgets/rich_text.dart | 11 + .../test_fixes/widgets/rich_text.dart.expect | 11 + 85 files changed, 1696 insertions(+), 457 deletions(-) create mode 100644 packages/flutter/lib/fix_data/fix_widgets/fix_media_query.yaml create mode 100644 packages/flutter/lib/fix_data/fix_widgets/fix_rich_text.yaml create mode 100644 packages/flutter/lib/src/painting/text_scaler.dart create mode 100644 packages/flutter/test/painting/text_scaler_test.dart delete mode 100644 packages/flutter/test/painting/widget_span_test.dart create mode 100644 packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart create mode 100644 packages/flutter/test/widgets/widget_span_test.dart create mode 100644 packages/flutter/test_fixes/widgets/media_query.dart create mode 100644 packages/flutter/test_fixes/widgets/media_query.dart.expect create mode 100644 packages/flutter/test_fixes/widgets/rich_text.dart create mode 100644 packages/flutter/test_fixes/widgets/rich_text.dart.expect diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart index c605072714d85..f5ee8dd906eb8 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart @@ -95,7 +95,7 @@ class _CustomPainter extends CustomPainter { yPosition = viewPadding; _textPainter.textDirection = TextDirection.ltr; _textPainter.textWidthBasis = TextWidthBasis.longestLine; - _textPainter.textScaleFactor = 1; + _textPainter.textScaler = TextScaler.noScaling; const TextStyle textStyle = TextStyle(color: Colors.black87, fontSize: 13, fontFamily: 'Roboto'); diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart index b5d4083d9cbda..5a32001fed47a 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/supplemental/product_card.dart @@ -52,7 +52,8 @@ class ProductCard extends StatelessWidget { child: imageWidget, ), SizedBox( - height: kTextBoxHeight * MediaQuery.of(context).textScaleFactor, + // ignore: deprecated_member_use, https://github.com/flutter/flutter/issues/128825 + height: kTextBoxHeight * MediaQuery.textScalerOf(context).textScaleFactor, width: 121.0, child: Column( mainAxisAlignment: MainAxisAlignment.end, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/app.dart b/dev/integration_tests/flutter_gallery/lib/gallery/app.dart index 788c48d7a170d..e2d8f0fb34a78 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/app.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/app.dart @@ -104,10 +104,10 @@ class _GalleryAppState extends State { Widget _applyTextScaleFactor(Widget child) { return Builder( builder: (BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: _options!.textScaleFactor!.scale, - ), + final double? textScaleFactor = _options!.textScaleFactor!.scale; + return MediaQuery.withClampedTextScaling( + minScaleFactor: textScaleFactor ?? 0.0, + maxScaleFactor: textScaleFactor ?? double.infinity, child: child, ); }, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart index ebbce5404ecba..c661ce64486cd 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart @@ -178,7 +178,8 @@ class _DemoItem extends StatelessWidget { Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final bool isDark = theme.brightness == Brightness.dark; - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); + // ignore: deprecated_member_use, https://github.com/flutter/flutter/issues/128825 + final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; return RawMaterialButton( splashColor: theme.primaryColor.withOpacity(0.12), highlightColor: Colors.transparent, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/options.dart b/dev/integration_tests/flutter_gallery/lib/gallery/options.dart index c1c4b8314e5fe..53b542ff4eb85 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/options.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/options.dart @@ -100,7 +100,8 @@ class _OptionsItem extends StatelessWidget { @override Widget build(BuildContext context) { - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); + // ignore: deprecated_member_use, https://github.com/flutter/flutter/issues/128825 + final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; return MergeSemantics( child: Container( diff --git a/dev/manual_tests/lib/density.dart b/dev/manual_tests/lib/density.dart index 02e252e4da4be..783b7d0108adb 100644 --- a/dev/manual_tests/lib/density.dart +++ b/dev/manual_tests/lib/density.dart @@ -621,14 +621,17 @@ class _MyHomePageState extends State { data: Theme.of(context).copyWith(visualDensity: _model.density), child: Directionality( textDirection: _model.rtl ? TextDirection.rtl : TextDirection.ltr, - child: MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: _model.size), - child: SizedBox.expand( - child: ListView( - children: tiles, + child: Builder(builder: (BuildContext context) { + final MediaQueryData mediaQueryData = MediaQuery.of(context); + return MediaQuery( + data: mediaQueryData.copyWith(textScaler: TextScaler.linear(_model.size)), + child: SizedBox.expand( + child: ListView( + children: tiles, + ), ), - ), - ), + ); + }), ), ), ), diff --git a/dev/tools/gen_defaults/lib/action_chip_template.dart b/dev/tools/gen_defaults/lib/action_chip_template.dart index 54027c13d75d2..ade6164e6334b 100644 --- a/dev/tools/gen_defaults/lib/action_chip_template.dart +++ b/dev/tools/gen_defaults/lib/action_chip_template.dart @@ -91,7 +91,7 @@ class _${blockName}DefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } '''; diff --git a/dev/tools/gen_defaults/lib/chip_template.dart b/dev/tools/gen_defaults/lib/chip_template.dart index 8d9c05b7ccb73..4d9383399d16d 100644 --- a/dev/tools/gen_defaults/lib/chip_template.dart +++ b/dev/tools/gen_defaults/lib/chip_template.dart @@ -70,7 +70,7 @@ class _${blockName}DefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } '''; diff --git a/dev/tools/gen_defaults/lib/filter_chip_template.dart b/dev/tools/gen_defaults/lib/filter_chip_template.dart index 6609613cde24e..d13cba9cff9e3 100644 --- a/dev/tools/gen_defaults/lib/filter_chip_template.dart +++ b/dev/tools/gen_defaults/lib/filter_chip_template.dart @@ -108,7 +108,7 @@ class _${blockName}DefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } '''; diff --git a/dev/tools/gen_defaults/lib/input_chip_template.dart b/dev/tools/gen_defaults/lib/input_chip_template.dart index 245a171b9073d..529113cbbfa42 100644 --- a/dev/tools/gen_defaults/lib/input_chip_template.dart +++ b/dev/tools/gen_defaults/lib/input_chip_template.dart @@ -85,7 +85,7 @@ class _${blockName}DefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } '''; diff --git a/examples/api/lib/material/app_bar/sliver_app_bar.1.dart b/examples/api/lib/material/app_bar/sliver_app_bar.1.dart index 9d7ad116fc497..46b41d8180816 100644 --- a/examples/api/lib/material/app_bar/sliver_app_bar.1.dart +++ b/examples/api/lib/material/app_bar/sliver_app_bar.1.dart @@ -63,7 +63,7 @@ class _SliverAppBarExampleState extends State { color: index.isOdd ? Colors.white : Colors.black12, height: 100.0, child: Center( - child: Text('$index', textScaleFactor: 5), + child: Text('$index', textScaler: const TextScaler.linear(5)), ), ); }, diff --git a/examples/api/lib/material/app_bar/sliver_app_bar.4.dart b/examples/api/lib/material/app_bar/sliver_app_bar.4.dart index 769c970fa1bd1..77d2773988bb5 100644 --- a/examples/api/lib/material/app_bar/sliver_app_bar.4.dart +++ b/examples/api/lib/material/app_bar/sliver_app_bar.4.dart @@ -51,7 +51,7 @@ class _StretchableSliverAppBarState extends State { color: index.isOdd ? Colors.white : Colors.black12, height: 100.0, child: Center( - child: Text('$index', textScaleFactor: 5), + child: Text('$index', textScaler: const TextScaler.linear(5.0)), ), ); }, diff --git a/examples/api/lib/material/time_picker/show_time_picker.0.dart b/examples/api/lib/material/time_picker/show_time_picker.0.dart index 6e7b9cfee9cfc..d7d05702d6c49 100644 --- a/examples/api/lib/material/time_picker/show_time_picker.0.dart +++ b/examples/api/lib/material/time_picker/show_time_picker.0.dart @@ -129,7 +129,8 @@ class _TimePickerOptionsState extends State { gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 350, mainAxisSpacing: 4, - mainAxisExtent: 200 * MediaQuery.textScaleFactorOf(context), + // ignore: deprecated_member_use, https://github.com/flutter/flutter/issues/128825 + mainAxisExtent: 200 * MediaQuery.textScalerOf(context).textScaleFactor, crossAxisSpacing: 4, ), children: [ diff --git a/packages/flutter/lib/fix_data/fix_painting.yaml b/packages/flutter/lib/fix_data/fix_painting.yaml index 0b88041a101c9..b83d86f28ce9c 100644 --- a/packages/flutter/lib/fix_data/fix_painting.yaml +++ b/packages/flutter/lib/fix_data/fix_painting.yaml @@ -18,6 +18,94 @@ # * Fixes in this file are from the Painting library. * version: 1 transforms: + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'painting.dart' ] + method: 'computeMaxIntrinsicWidth' + inClass: 'TextPainter' + changes: + - kind: 'addParameter' + index: 4 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'painting.dart' ] + method: 'computeWidth' + inClass: 'TextPainter' + changes: + - kind: 'addParameter' + index: 4 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'painting.dart' ] + constructor: '' + inClass: 'TextPainter' + changes: + - kind: 'addParameter' + index: 0 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'painting.dart' ] + method: 'getTextStyle' + inClass: 'TextStyle' + changes: + - kind: 'addParameter' + index: 0 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + # Changes made in https://github.com/flutter/flutter/pull/121152 - title: "Rename to 'fromViewPadding'" date: 2022-02-21 diff --git a/packages/flutter/lib/fix_data/fix_rendering.yaml b/packages/flutter/lib/fix_data/fix_rendering.yaml index efc56a8bc4275..75ae29fc5615d 100644 --- a/packages/flutter/lib/fix_data/fix_rendering.yaml +++ b/packages/flutter/lib/fix_data/fix_rendering.yaml @@ -18,6 +18,50 @@ # * Fixes in this file are from the Rendering library. * version: 1 transforms: + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'rendering.dart' ] + constructor: '' + inClass: 'RenderParagraph' + changes: + - kind: 'addParameter' + index: 5 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'rendering.dart' ] + constructor: '' + inClass: 'RenderEditable' + changes: + - kind: 'addParameter' + index: 15 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + # Changes made in https://github.com/flutter/flutter/pull/66305 - title: "Migrate to 'clipBehavior'" date: 2020-09-22 diff --git a/packages/flutter/lib/fix_data/fix_widgets/fix_media_query.yaml b/packages/flutter/lib/fix_data/fix_widgets/fix_media_query.yaml new file mode 100644 index 0000000000000..c7092e9311b45 --- /dev/null +++ b/packages/flutter/lib/fix_data/fix_widgets/fix_media_query.yaml @@ -0,0 +1,65 @@ +# Copyright 2014 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# For details regarding the *Flutter Fix* feature, see +# https://flutter.dev/docs/development/tools/flutter-fix + +# Please add new fixes to the top of the file, separated by one blank line +# from other fixes. In a comment, include a link to the PR where the change +# requiring the fix was made. + +# Every fix must be tested. See the flutter/packages/flutter/test_fixes/README.md +# file for instructions on testing these data driven fixes. + +# For documentation about this file format, see +# https://dart.dev/go/data-driven-fixes. + +# * Fixes in this file are for MediaQuery and MediaQueryData from the widgets library. * +version: 1 +transforms: + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'widgets.dart', 'material.dart', 'cupertino.dart' ] + method: 'copyWith' + inClass: 'MediaQueryData' + changes: + - kind: 'addParameter' + index: 3 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'widgets.dart', 'material.dart', 'cupertino.dart' ] + constructor: '' + inClass: 'MediaQueryData' + changes: + - kind: 'addParameter' + index: 3 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + +# Before adding a new fix: read instructions at the top of this file. diff --git a/packages/flutter/lib/fix_data/fix_widgets/fix_rich_text.yaml b/packages/flutter/lib/fix_data/fix_widgets/fix_rich_text.yaml new file mode 100644 index 0000000000000..1f3f5cc014837 --- /dev/null +++ b/packages/flutter/lib/fix_data/fix_widgets/fix_rich_text.yaml @@ -0,0 +1,43 @@ +# Copyright 2014 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# For details regarding the *Flutter Fix* feature, see +# https://flutter.dev/docs/development/tools/flutter-fix + +# Please add new fixes to the top of the file, separated by one blank line +# from other fixes. In a comment, include a link to the PR where the change +# requiring the fix was made. + +# Every fix must be tested. See the flutter/packages/flutter/test_fixes/README.md +# file for instructions on testing these data driven fixes. + +# For documentation about this file format, see +# https://dart.dev/go/data-driven-fixes. + +# * Fixes in this file are for RichText from the widgets library. * +version: 1 +transforms: + # Change made in https://github.com/flutter/flutter/pull/128522 + - title: "Migrate to 'textScaler'" + date: 2023-06-09 + element: + uris: [ 'widgets.dart', 'material.dart', 'cupertino.dart' ] + constructor: '' + inClass: 'RichText' + changes: + - kind: 'addParameter' + index: 7 + name: 'textScaler' + style: optional_named + argumentValue: + expression: 'TextScaler.linear({% textScaleFactor %})' + requiredIf: "textScaleFactor != ''" + - kind: 'removeParameter' + name: 'textScaleFactor' + variables: + textScaleFactor: + kind: 'fragment' + value: 'arguments[textScaleFactor]' + +# Before adding a new fix: read instructions at the top of this file. diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart index 8a78b6bf4a186..2fa89c23cf8bc 100644 --- a/packages/flutter/lib/painting.dart +++ b/packages/flutter/lib/painting.dart @@ -60,5 +60,6 @@ export 'src/painting/stadium_border.dart'; export 'src/painting/star_border.dart'; export 'src/painting/strut_style.dart'; export 'src/painting/text_painter.dart'; +export 'src/painting/text_scaler.dart'; export 'src/painting/text_span.dart'; export 'src/painting/text_style.dart'; diff --git a/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart b/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart index 4bdbe86a99b22..6d920abff92bb 100644 --- a/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart +++ b/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart @@ -37,13 +37,10 @@ const Color _kDefaultTabBarInactiveColor = CupertinoColors.inactiveGray; /// If the given [backgroundColor]'s opacity is not 1.0 (which is the case by /// default), it will produce a blurring effect to the content behind it. /// -/// When used as [CupertinoTabScaffold.tabBar], by default [CupertinoTabBar] has -/// its text scale factor set to 1.0 and does not respond to text scale factor -/// changes from the operating system, to match the native iOS behavior. To override -/// this behavior, wrap each of the `navigationBar`'s components inside a [MediaQuery] -/// with the desired [MediaQueryData.textScaleFactor] value. The text scale factor -/// value from the operating system can be retrieved in many ways, such as querying -/// [MediaQuery.textScaleFactorOf] against [CupertinoApp]'s [BuildContext]. +/// When used as [CupertinoTabScaffold.tabBar], by default [CupertinoTabBar] +/// disables text scaling to match the native iOS behavior. To override +/// this behavior, wrap each of the `navigationBar`'s components inside a +/// [MediaQuery] with the desired [TextScaler]. /// /// {@tool dartpad} /// This example shows a [CupertinoTabBar] placed in a [CupertinoTabScaffold]. diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 1b43e697bc540..693b4069a3ee1 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -1097,8 +1097,7 @@ class _CupertinoDatePickerDateTimeState extends State { final double maxPickerWidth = totalColumnWidths > _kPickerWidth ? totalColumnWidths : _kPickerWidth; - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + return MediaQuery.withNoTextScaling( child: DefaultTextStyle.merge( style: _kDefaultPickerTextStyle, child: CustomMultiChildLayout( @@ -1487,8 +1486,7 @@ class _CupertinoDatePickerDateState extends State { final double maxPickerWidth = totalColumnWidths > _kPickerWidth ? totalColumnWidths : _kPickerWidth; - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + return MediaQuery.withNoTextScaling( child: DefaultTextStyle.merge( style: _kDefaultPickerTextStyle, child: CustomMultiChildLayout( @@ -1802,8 +1800,7 @@ class _CupertinoDatePickerMonthYearState extends State { final double maxPickerWidth = totalColumnWidths > _kPickerWidth ? totalColumnWidths : _kPickerWidth; - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + return MediaQuery.withNoTextScaling( child: DefaultTextStyle.merge( style: _kDefaultPickerTextStyle, child: CustomMultiChildLayout( @@ -2502,10 +2499,9 @@ class _CupertinoTimerPickerState extends State { ]; } final CupertinoThemeData themeData = CupertinoTheme.of(context); - return MediaQuery( - // The native iOS picker's text scaling is fixed, so we will also fix it - // as well in our picker. - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + // The native iOS picker's text scaling is fixed, so we will also fix it + // as well in our picker. + return MediaQuery.withNoTextScaling( child: CupertinoTheme( data: themeData.copyWith( textTheme: themeData.textTheme.copyWith( diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 0cb4cf8adc105..ef8c10936043b 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -149,7 +149,7 @@ const double _kMaxRegularTextScaleFactor = 1.4; // Accessibility mode on iOS is determined by the text scale factor that the // user has selected. bool _isInAccessibilityMode(BuildContext context) { - final double? factor = MediaQuery.maybeTextScaleFactorOf(context); + final double? factor = MediaQuery.maybeTextScalerOf(context)?.textScaleFactor; return factor != null && factor > _kMaxRegularTextScaleFactor; } @@ -257,7 +257,7 @@ class CupertinoAlertDialog extends StatelessWidget { final Curve insetAnimationCurve; Widget _buildContent(BuildContext context) { - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); + final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; final List children = [ if (title != null || content != null) @@ -317,14 +317,11 @@ class CupertinoAlertDialog extends StatelessWidget { Widget build(BuildContext context) { final CupertinoLocalizations localizations = CupertinoLocalizations.of(context); final bool isInAccessibilityMode = _isInAccessibilityMode(context); - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); return CupertinoUserInterfaceLevel( data: CupertinoUserInterfaceLevelData.elevated, - child: MediaQuery( - data: MediaQuery.of(context).copyWith( - // iOS does not shrink dialog content below a 1.0 scale factor - textScaleFactor: math.max(textScaleFactor, 1.0), - ), + child: MediaQuery.withClampedTextScaling( + // iOS does not shrink dialog content below a 1.0 scale factor + minScaleFactor: 1.0, child: ScrollConfiguration( // A CupertinoScrollbar is built-in below. behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), @@ -1633,7 +1630,7 @@ class CupertinoDialogAction extends StatelessWidget { bool get enabled => onPressed != null; double _calculatePadding(BuildContext context) { - return 8.0 * MediaQuery.textScaleFactorOf(context); + return 8.0 * MediaQuery.textScalerOf(context).textScaleFactor; } // Dialog action content shrinks to fit, up to a certain point, and if it still @@ -1649,12 +1646,11 @@ class CupertinoDialogAction extends StatelessWidget { final double dialogWidth = isInAccessibilityMode ? _kAccessibilityCupertinoDialogWidth : _kCupertinoDialogWidth; - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); // The fontSizeRatio is the ratio of the current text size (including any // iOS scale factor) vs the minimum text size that we allow in action // buttons. This ratio information is used to automatically scale down action // button text to fit the available space. - final double fontSizeRatio = (textScaleFactor * textStyle.fontSize!) / _kDialogMinButtonFontSize; + final double fontSizeRatio = MediaQuery.textScalerOf(context).scale(textStyle.fontSize!) / _kDialogMinButtonFontSize; final double padding = _calculatePadding(context); return IntrinsicHeight( diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index f33ea8d95c99f..9c2d472f15f39 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -229,12 +229,9 @@ bool _isTransitionable(BuildContext context) { /// behavior for multiple navigation bars per route. /// /// When used in a [CupertinoPageScaffold], [CupertinoPageScaffold.navigationBar] -/// has its text scale factor set to 1.0 and does not respond to text scale factor -/// changes from the operating system, to match the native iOS behavior. To override -/// this behavior, wrap each of the `navigationBar`'s components inside a [MediaQuery] -/// with the desired [MediaQueryData.textScaleFactor] value. The text scale factor -/// value from the operating system can be retrieved in many ways, such as querying -/// [MediaQuery.textScaleFactorOf] against [CupertinoApp]'s [BuildContext]. +/// disables text scaling to match the native iOS behavior. To override +/// this behavior, wrap each of the `navigationBar`'s components inside a +/// [MediaQuery] with the desired [TextScaler]. /// /// {@tool dartpad} /// This example shows a [CupertinoNavigationBar] placed in a [CupertinoPageScaffold]. @@ -555,13 +552,10 @@ class _CupertinoNavigationBarState extends State { /// Use [transitionBetweenRoutes] or [heroTag] to customize the transition /// behavior for multiple navigation bars per route. /// -/// [CupertinoSliverNavigationBar] has its text scale factor set to 1.0 by default -/// and does not respond to text scale factor changes from the operating system, -/// to match the native iOS behavior. To override this behavior, wrap each of the +/// [CupertinoSliverNavigationBar] by default disables text scaling to match the +/// native iOS behavior. To override this behavior, wrap each of the /// [CupertinoSliverNavigationBar]'s components inside a [MediaQuery] with the -/// desired [MediaQueryData.textScaleFactor] value. The text scale factor value -/// from the operating system can be retrieved in many ways, such as querying -/// [MediaQuery.textScaleFactorOf] against [CupertinoApp]'s [BuildContext]. +/// desired [TextScaler]. /// /// The [stretch] parameter determines whether the nav bar should stretch to /// fill the over-scroll area. The nav bar can still expand and contract as the @@ -741,8 +735,7 @@ class _CupertinoSliverNavigationBarState extends State { top: 0.0, left: 0.0, right: 0.0, - child: MediaQuery( - data: existingMediaQuery.copyWith(textScaleFactor: 1), + child: MediaQuery.withNoTextScaling( child: widget.navigationBar!, ), ), diff --git a/packages/flutter/lib/src/cupertino/search_field.dart b/packages/flutter/lib/src/cupertino/search_field.dart index ac868801bc08f..0748feb13fff3 100644 --- a/packages/flutter/lib/src/cupertino/search_field.dart +++ b/packages/flutter/lib/src/cupertino/search_field.dart @@ -400,8 +400,7 @@ class _CupertinoSearchTextFieldState extends State // The icon size will be scaled by a factor of the accessibility text scale, // to follow the behavior of `UISearchTextField`. - final double scaledIconSize = - MediaQuery.textScaleFactorOf(context) * widget.itemSize; + final double scaledIconSize = MediaQuery.textScalerOf(context).textScaleFactor * widget.itemSize; // If decoration was not provided, create a decoration with the provided // background color and border radius. diff --git a/packages/flutter/lib/src/cupertino/tab_scaffold.dart b/packages/flutter/lib/src/cupertino/tab_scaffold.dart index 056cf18ef967a..8bd129a7eb7ac 100644 --- a/packages/flutter/lib/src/cupertino/tab_scaffold.dart +++ b/packages/flutter/lib/src/cupertino/tab_scaffold.dart @@ -158,13 +158,9 @@ class CupertinoTabScaffold extends StatefulWidget { /// If translucent, the main content may slide behind it. /// Otherwise, the main content's bottom margin will be offset by its height. /// - /// By default [tabBar] has its text scale factor set to 1.0 and does not - /// respond to text scale factor changes from the operating system, to match - /// the native iOS behavior. To override this behavior, wrap each of the [tabBar]'s - /// items inside a [MediaQuery] with the desired [MediaQueryData.textScaleFactor] - /// value. The text scale factor value from the operating system can be retrieved - /// int many ways, such as querying [MediaQuery.textScaleFactorOf] against - /// [CupertinoApp]'s [BuildContext]. + /// By default [tabBar] disables text scaling to match the native iOS behavior. + /// To override this behavior, wrap each of the [tabBar]'s items inside a + /// [MediaQuery] with the desired [TextScaler]. /// /// Must not be null. final CupertinoTabBar tabBar; @@ -361,8 +357,7 @@ class _CupertinoTabScaffoldState extends State with Restor children: [ // The main content being at the bottom is added to the stack first. content, - MediaQuery( - data: existingMediaQuery.copyWith(textScaleFactor: 1), + MediaQuery.withNoTextScaling( child: Align( alignment: Alignment.bottomCenter, // Override the tab bar's currentIndex to the current tab and hook in diff --git a/packages/flutter/lib/src/material/action_chip.dart b/packages/flutter/lib/src/material/action_chip.dart index 725570fd56dfb..142fc4058b6fb 100644 --- a/packages/flutter/lib/src/material/action_chip.dart +++ b/packages/flutter/lib/src/material/action_chip.dart @@ -311,7 +311,7 @@ class _ActionChipDefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index d0aabc3ca0d19..c94bfa5e3c1a4 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -951,22 +951,13 @@ class _AppBarState extends State { Widget? title = widget.title; if (title != null) { - bool? namesRoute; - switch (theme.platform) { - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - namesRoute = true; - case TargetPlatform.iOS: - case TargetPlatform.macOS: - break; - } - title = _AppBarTitleBox(child: title); if (!widget.excludeHeaderSemantics) { title = Semantics( - namesRoute: namesRoute, + namesRoute: switch (theme.platform) { + TargetPlatform.android || TargetPlatform.fuchsia || TargetPlatform.linux || TargetPlatform.windows => true, + TargetPlatform.iOS || TargetPlatform.macOS => null, + }, header: true, child: title, ); @@ -982,16 +973,9 @@ class _AppBarState extends State { // Set maximum text scale factor to [_kMaxTitleTextScaleFactor] for the // title to keep the visual hierarchy the same even with larger font // sizes. To opt out, wrap the [title] widget in a [MediaQuery] widget - // with [MediaQueryData.textScaleFactor] set to - // `MediaQuery.textScaleFactorOf(context)`. - final MediaQueryData mediaQueryData = MediaQuery.of(context); - title = MediaQuery( - data: mediaQueryData.copyWith( - textScaleFactor: math.min( - mediaQueryData.textScaleFactor, - _kMaxTitleTextScaleFactor, - ), - ), + // with a different `TextScaler`. + title = MediaQuery.withClampedTextScaling( + maxScaleFactor: _kMaxTitleTextScaleFactor, child: title, ); } @@ -2098,7 +2082,6 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget { Widget build(BuildContext context) { late final AppBarTheme appBarTheme = AppBarTheme.of(context); late final AppBarTheme defaults = Theme.of(context).useMaterial3 ? _AppBarDefaultsM3(context) : _AppBarDefaultsM2(context); - final double textScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), _kMaxTitleTextScaleFactor); // TODO(tahatesser): Add link to Material spec when available, https://github.com/flutter/flutter/issues/58769. final FlexibleSpaceBarSettings settings = context.dependOnInheritedWidgetOfExactType()!; final _ScrollUnderFlexibleConfig config = configBuilder(context); assert( @@ -2125,10 +2108,10 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget { // Set maximum text scale factor to [_kMaxTitleTextScaleFactor] for the // title to keep the visual hierarchy the same even with larger font // sizes. To opt out, wrap the [title] widget in a [MediaQuery] widget - // with [MediaQueryData.textScaleFactor] set to - // `MediaQuery.textScaleFactorOf(context)`. - return MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), + // with a different TextScaler. + // TODO(tahatesser): Add link to Material spec when available, https://github.com/flutter/flutter/issues/58769. + return MediaQuery.withClampedTextScaling( + maxScaleFactor: _kMaxTitleTextScaleFactor, // This column will assume the full height of the parent Stack. child: Column( children: [ diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar.dart b/packages/flutter/lib/src/material/bottom_navigation_bar.dart index f85a58e8e9c32..15e63f6a59242 100644 --- a/packages/flutter/lib/src/material/bottom_navigation_bar.dart +++ b/packages/flutter/lib/src/material/bottom_navigation_bar.dart @@ -784,11 +784,8 @@ class _Label extends StatelessWidget { if (item.label != null) { // Do not grow text in bottom navigation bar when we can show a tooltip // instead. - final MediaQueryData mediaQueryData = MediaQuery.of(context); - text = MediaQuery( - data: mediaQueryData.copyWith( - textScaleFactor: math.min(1.0, mediaQueryData.textScaleFactor), - ), + text = MediaQuery.withClampedTextScaling( + maxScaleFactor: 1.0, child: text, ); } diff --git a/packages/flutter/lib/src/material/button_style_button.dart b/packages/flutter/lib/src/material/button_style_button.dart index 9155e49ef69a4..c1f75e87c8e06 100644 --- a/packages/flutter/lib/src/material/button_style_button.dart +++ b/packages/flutter/lib/src/material/button_style_button.dart @@ -184,15 +184,12 @@ abstract class ButtonStyleButton extends StatefulWidget { EdgeInsetsGeometry geometry3x, double textScaleFactor, ) { - - if (textScaleFactor <= 1) { - return geometry1x; - } else if (textScaleFactor >= 3) { - return geometry3x; - } else if (textScaleFactor <= 2) { - return EdgeInsetsGeometry.lerp(geometry1x, geometry2x, textScaleFactor - 1)!; - } - return EdgeInsetsGeometry.lerp(geometry2x, geometry3x, textScaleFactor - 2)!; + return switch (textScaleFactor) { + <= 1 => geometry1x, + < 2 => EdgeInsetsGeometry.lerp(geometry1x, geometry2x, textScaleFactor - 1)!, + < 3 => EdgeInsetsGeometry.lerp(geometry2x, geometry3x, textScaleFactor - 2)!, + _ => geometry3x, + }; } } diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index eb457147e068d..562a1878f31fb 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -1169,7 +1169,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid final EdgeInsetsGeometry defaultLabelPadding = EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; final ThemeData theme = Theme.of(context); @@ -2283,7 +2283,7 @@ class _ChipDefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } diff --git a/packages/flutter/lib/src/material/choice_chip.dart b/packages/flutter/lib/src/material/choice_chip.dart index 7b05db36229a9..8eba9b0b7dd4f 100644 --- a/packages/flutter/lib/src/material/choice_chip.dart +++ b/packages/flutter/lib/src/material/choice_chip.dart @@ -338,7 +338,7 @@ class _ChoiceChipDefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } diff --git a/packages/flutter/lib/src/material/circle_avatar.dart b/packages/flutter/lib/src/material/circle_avatar.dart index 6d537775ab3cc..3f7c9584ff0cb 100644 --- a/packages/flutter/lib/src/material/circle_avatar.dart +++ b/packages/flutter/lib/src/material/circle_avatar.dart @@ -252,10 +252,9 @@ class CircleAvatar extends StatelessWidget { child: child == null ? null : Center( - child: MediaQuery( - // Need to ignore the ambient textScaleFactor here so that the - // text doesn't escape the avatar when the textScaleFactor is large. - data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), + // Need to disable text scaling here so that the text doesn't + // escape the avatar when the textScaleFactor is large. + child: MediaQuery.withNoTextScaling( child: IconTheme( data: theme.iconTheme.copyWith(color: textStyle.color), child: DefaultTextStyle( diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index afb72d4b84ba7..2fb95113d0dad 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -46,6 +46,7 @@ const Size _inputRangeLandscapeDialogSize = Size(496, 164.0); const Duration _dialogSizeAnimationDuration = Duration(milliseconds: 200); const double _inputFormPortraitHeight = 98.0; const double _inputFormLandscapeHeight = 108.0; +const double _kMaxTextScaleFactor = 1.3; /// Shows a dialog containing a Material Design date picker. /// @@ -436,9 +437,7 @@ class _DatePickerDialogState extends State with RestorationMix } void _handleOnDatePickerModeChange() { - if (widget.onDatePickerModeChange != null) { - widget.onDatePickerModeChange!(_entryMode.value); - } + widget.onDatePickerModeChange?.call(_entryMode.value); } void _handleEntryModeToggle() { @@ -454,7 +453,7 @@ class _DatePickerDialogState extends State with RestorationMix _handleOnDatePickerModeChange(); case DatePickerEntryMode.calendarOnly: case DatePickerEntryMode.inputOnly: - assert(false, 'Can not change entry mode from _entryMode'); + assert(false, 'Can not change entry mode from ${_entryMode.value}'); } }); } @@ -642,7 +641,7 @@ class _DatePickerDialogState extends State with RestorationMix // Constrain the textScaleFactor to the largest supported value to prevent // layout issues. - final double textScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), 1.3); + final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: _kMaxTextScaleFactor).textScaleFactor; final Size dialogSize = _dialogSize(context) * textScaleFactor; final DialogTheme dialogTheme = theme.dialogTheme; return Dialog( @@ -662,10 +661,10 @@ class _DatePickerDialogState extends State with RestorationMix height: dialogSize.height, duration: _dialogSizeAnimationDuration, curve: Curves.easeIn, - child: MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: textScaleFactor, - ), + child: MediaQuery.withClampedTextScaling( + // Constrain the textScaleFactor to the largest supported value to prevent + // layout issues. + maxScaleFactor: _kMaxTextScaleFactor, child: Builder(builder: (BuildContext context) { switch (orientation) { case Orientation.portrait: @@ -1391,7 +1390,6 @@ class _DateRangePickerDialogState extends State with Rest final ThemeData theme = Theme.of(context); final bool useMaterial3 = theme.useMaterial3; final Orientation orientation = MediaQuery.orientationOf(context); - final double textScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), 1.3); final MaterialLocalizations localizations = MaterialLocalizations.of(context); final DatePickerThemeData datePickerTheme = DatePickerTheme.of(context); final DatePickerThemeData defaults = DatePickerTheme.defaults(context); @@ -1535,10 +1533,8 @@ class _DateRangePickerDialogState extends State with Rest height: size.height, duration: _dialogSizeAnimationDuration, curve: Curves.easeIn, - child: MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: textScaleFactor, - ), + child: MediaQuery.withClampedTextScaling( + maxScaleFactor: _kMaxTextScaleFactor, child: Builder(builder: (BuildContext context) { return contents; }), diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 181aff65f5ca0..57300b56011a4 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -719,7 +719,7 @@ class AlertDialog extends StatelessWidget { // The paddingScaleFactor is used to adjust the padding of Dialog's // children. - final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.textScaleFactorOf(context)); + final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.textScalerOf(context).textScaleFactor); final TextDirection? textDirection = Directionality.maybeOf(context); Widget? iconWidget; @@ -1216,7 +1216,7 @@ class SimpleDialog extends StatelessWidget { // The paddingScaleFactor is used to adjust the padding of Dialog // children. - final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.textScaleFactorOf(context)); + final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.textScalerOf(context).textScaleFactor); final TextDirection? textDirection = Directionality.maybeOf(context); Widget? titleWidget; diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index a115b0982b134..17bc7ec6d11bd 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -1355,9 +1355,8 @@ class _DropdownButtonState extends State> with WidgetsBindi // Similarly, we don't reduce the height of the button so much that its icon // would be clipped. double get _denseButtonHeight { - final double textScaleFactor = MediaQuery.textScaleFactorOf(context); final double fontSize = _textStyle!.fontSize ?? Theme.of(context).textTheme.titleMedium!.fontSize!; - final double scaledFontSize = textScaleFactor * fontSize; + final double scaledFontSize = MediaQuery.textScalerOf(context).scale(fontSize); return math.max(scaledFontSize, math.max(widget.iconSize, _kDenseButtonHeight)); } diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index 92d57fb5d072b..5f8b4fe64088f 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -398,7 +398,7 @@ EdgeInsetsGeometry _scaledPadding(BuildContext context) { EdgeInsets.symmetric(horizontal: padding1x), EdgeInsets.symmetric(horizontal: padding1x / 2), EdgeInsets.symmetric(horizontal: padding1x / 2 / 2), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); } @@ -506,12 +506,12 @@ class _ElevatedButtonWithIcon extends ElevatedButton { const EdgeInsetsDirectional.fromSTEB(16, 0, 24, 0), const EdgeInsetsDirectional.fromSTEB(8, 0, 12, 0), const EdgeInsetsDirectional.fromSTEB(4, 0, 6, 0), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ) : ButtonStyleButton.scaledPadding( const EdgeInsetsDirectional.fromSTEB(12, 0, 16, 0), const EdgeInsets.symmetric(horizontal: 8), const EdgeInsetsDirectional.fromSTEB(8, 0, 4, 0), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); return super.defaultStyleOf(context).copyWith( padding: MaterialStatePropertyAll(scaledPadding), @@ -527,7 +527,7 @@ class _ElevatedButtonWithIconChild extends StatelessWidget { @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScaleFactorOf(context); + final double scale = MediaQuery.textScalerOf(context).textScaleFactor; final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; return Row( mainAxisSize: MainAxisSize.min, diff --git a/packages/flutter/lib/src/material/filled_button.dart b/packages/flutter/lib/src/material/filled_button.dart index d0933f891bb5a..b348e41c113ae 100644 --- a/packages/flutter/lib/src/material/filled_button.dart +++ b/packages/flutter/lib/src/material/filled_button.dart @@ -285,7 +285,7 @@ class FilledButton extends ButtonStyleButton { /// each state, and "others" means all other states. /// /// The `textScaleFactor` is the value of - /// `MediaQuery.textScaleFactorOf(context)` and the names of the + /// `MediaQuery.textScalerOf(context).textScaleFactor` and the names of the /// EdgeInsets constructors and `EdgeInsetsGeometry.lerp` have been /// abbreviated for readability. /// @@ -411,7 +411,7 @@ EdgeInsetsGeometry _scaledPadding(BuildContext context) { EdgeInsets.symmetric(horizontal: padding1x), EdgeInsets.symmetric(horizontal: padding1x / 2), EdgeInsets.symmetric(horizontal: padding1x / 2 / 2), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); } @@ -514,12 +514,12 @@ class _FilledButtonWithIcon extends FilledButton { const EdgeInsetsDirectional.fromSTEB(16, 0, 24, 0), const EdgeInsetsDirectional.fromSTEB(8, 0, 12, 0), const EdgeInsetsDirectional.fromSTEB(4, 0, 6, 0), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ) : ButtonStyleButton.scaledPadding( const EdgeInsetsDirectional.fromSTEB(12, 0, 16, 0), const EdgeInsets.symmetric(horizontal: 8), const EdgeInsetsDirectional.fromSTEB(8, 0, 4, 0), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); return super.defaultStyleOf(context).copyWith( padding: MaterialStatePropertyAll(scaledPadding), @@ -535,7 +535,7 @@ class _FilledButtonWithIconChild extends StatelessWidget { @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScaleFactorOf(context); + final double scale = MediaQuery.textScalerOf(context).textScaleFactor; // Adjust the gap based on the text scale factor. Start at 8, and lerp // to 4 based on how large the text is. final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; diff --git a/packages/flutter/lib/src/material/filter_chip.dart b/packages/flutter/lib/src/material/filter_chip.dart index 887bb05c87c1c..c56a1832b3dfd 100644 --- a/packages/flutter/lib/src/material/filter_chip.dart +++ b/packages/flutter/lib/src/material/filter_chip.dart @@ -338,7 +338,7 @@ class _FilterChipDefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } diff --git a/packages/flutter/lib/src/material/input_chip.dart b/packages/flutter/lib/src/material/input_chip.dart index 756d557ee1bf0..56ef93fe6c94d 100644 --- a/packages/flutter/lib/src/material/input_chip.dart +++ b/packages/flutter/lib/src/material/input_chip.dart @@ -321,7 +321,7 @@ class _InputChipDefaultsM3 extends ChipThemeData { EdgeInsetsGeometry? get labelPadding => EdgeInsets.lerp( const EdgeInsets.symmetric(horizontal: 8.0), const EdgeInsets.symmetric(horizontal: 4.0), - clampDouble(MediaQuery.textScaleFactorOf(context) - 1.0, 0.0, 1.0), + clampDouble(MediaQuery.textScalerOf(context).textScaleFactor - 1.0, 0.0, 1.0), )!; } diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index d957c7aaf2948..0a9374c0bd731 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -2406,7 +2406,7 @@ class _InputDecoratorState extends State with TickerProviderStat contentPadding = decorationContentPadding ?? EdgeInsets.zero; } else if (!border.isOutline) { // 4.0: the vertical gap between the inline elements and the floating label. - floatingLabelHeight = (4.0 + 0.75 * labelStyle.fontSize!) * MediaQuery.textScaleFactorOf(context); + floatingLabelHeight = (4.0 + 0.75 * labelStyle.fontSize!) * MediaQuery.textScalerOf(context).textScaleFactor; if (decoration.filled ?? false) { contentPadding = decorationContentPadding ?? (decorationIsDense ? const EdgeInsets.fromLTRB(12.0, 8.0, 12.0, 8.0) diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index fff6c2b435ebf..c6c99e40d8348 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart' show clampDouble; import 'package:flutter/widgets.dart'; import 'color_scheme.dart'; @@ -33,7 +32,7 @@ const double _kIndicatorWidth = 64; /// /// This widget does not adjust its size with the [ThemeData.visualDensity]. /// -/// The [MediaQueryData.textScaleFactor] does not adjust the size of this widget but +/// The [MediaQueryData.textScaler] does not adjust the size of this widget but /// rather the size of the [Tooltip]s displayed on long presses of the /// destinations. /// @@ -183,7 +182,7 @@ class NavigationBar extends StatelessWidget { /// automatically. /// /// The height does not adjust with [ThemeData.visualDensity] or - /// [MediaQueryData.textScaleFactor] as this component loses usability at + /// [MediaQueryData.textScaler] as this component loses usability at /// larger and smaller sizes due to the truncating of labels or smaller tap /// targets. /// @@ -383,18 +382,14 @@ class NavigationDestination extends StatelessWidget { ?? defaults.labelTextStyle!.resolve(selectedState); final TextStyle? effectiveUnselectedLabelTextStyle = navigationBarTheme.labelTextStyle?.resolve(unselectedState) ?? defaults.labelTextStyle!.resolve(unselectedState); + final TextStyle? textStyle = _isForwardOrCompleted(animation) ? effectiveSelectedLabelTextStyle : effectiveUnselectedLabelTextStyle; return Padding( padding: const EdgeInsets.only(top: 4), - child: _ClampTextScaleFactor( + child: MediaQuery.withClampedTextScaling( // Don't scale labels of destinations, instead, tooltip text will // upscale. - upperLimit: 1, - child: Text( - label, - style: _isForwardOrCompleted(animation) - ? effectiveSelectedLabelTextStyle - : effectiveUnselectedLabelTextStyle, - ), + maxScaleFactor: 1.0, + child: Text(label, style: textStyle), ), ); }, @@ -1018,53 +1013,6 @@ class _NavigationDestinationLayoutDelegate extends MultiChildLayoutDelegate { } } -/// Utility Widgets - -// Clamps [MediaQueryData.textScaleFactor] so that if it is greater than -// [upperLimit] or less than [lowerLimit], [upperLimit] or [lowerLimit] will be -// used instead for the [child] widget. -// -// Example: -// -// ```dart -// _ClampTextScaleFactor( -// upperLimit: 2.0, -// child: const Text('Foo'), // If textScaleFactor is 3.0, this will only scale 2x. -// ) -// ``` -class _ClampTextScaleFactor extends StatelessWidget { - /// Clamps the text scale factor of descendants by modifying the [MediaQuery] - /// surrounding [child]. - const _ClampTextScaleFactor({ - this.upperLimit = double.infinity, - required this.child, - }); - - /// The maximum amount that the text scale factor should be for the [child] - /// widget. - /// - /// If this is `1.5`, the textScaleFactor for child widgets will never be - /// greater than `1.5`. - final double upperLimit; - - /// The [Widget] that should have its (and its descendants) text scale factor - /// clamped. - final Widget child; - - @override - Widget build(BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaleFactor: clampDouble(MediaQuery.textScaleFactorOf(context), - 0.0, - upperLimit, - ), - ), - child: child, - ); - } -} - /// Widget that listens to an animation, and rebuilds when the animation changes /// [AnimationStatus]. /// diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index 8ee11e3b3e72d..60ff7cbe4d933 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -354,7 +354,7 @@ EdgeInsetsGeometry _scaledPadding(BuildContext context) { EdgeInsets.symmetric(horizontal: padding1x), EdgeInsets.symmetric(horizontal: padding1x / 2), EdgeInsets.symmetric(horizontal: padding1x / 2 / 2), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); } @@ -439,7 +439,7 @@ class _OutlinedButtonWithIcon extends OutlinedButton { const EdgeInsetsDirectional.fromSTEB(16, 0, 24, 0), const EdgeInsetsDirectional.fromSTEB(8, 0, 12, 0), const EdgeInsetsDirectional.fromSTEB(4, 0, 6, 0), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); return super.defaultStyleOf(context).copyWith( padding: MaterialStatePropertyAll(scaledPadding), @@ -458,7 +458,7 @@ class _OutlinedButtonWithIconChild extends StatelessWidget { @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScaleFactorOf(context); + final double scale = MediaQuery.textScalerOf(context).textScaleFactor; final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; return Row( mainAxisSize: MainAxisSize.min, diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index 433de56181c54..8616a4f8ba42d 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -185,7 +185,13 @@ class SelectableText extends StatefulWidget { this.strutStyle, this.textAlign, this.textDirection, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) this.textScaleFactor, + this.textScaler, this.showCursor = false, this.autofocus = false, @Deprecated( @@ -218,6 +224,10 @@ class SelectableText extends StatefulWidget { (maxLines == null) || (minLines == null) || (maxLines >= minLines), "minLines can't be greater than maxLines", ), + assert( + textScaler == null || textScaleFactor == null, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ), textSpan = null; /// Creates a selectable text widget with a [TextSpan]. @@ -234,7 +244,13 @@ class SelectableText extends StatefulWidget { this.strutStyle, this.textAlign, this.textDirection, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) this.textScaleFactor, + this.textScaler, this.showCursor = false, this.autofocus = false, @Deprecated( @@ -267,6 +283,10 @@ class SelectableText extends StatefulWidget { (maxLines == null) || (minLines == null) || (maxLines >= minLines), "minLines can't be greater than maxLines", ), + assert( + textScaler == null || textScaleFactor == null, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ), data = null; /// The text to display. @@ -322,8 +342,16 @@ class SelectableText extends StatefulWidget { final TextDirection? textDirection; /// {@macro flutter.widgets.editableText.textScaleFactor} + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) final double? textScaleFactor; + /// {@macro flutter.painting.textPainter.textScaler} + final TextScaler? textScaler; + /// {@macro flutter.widgets.editableText.autofocus} final bool autofocus; @@ -457,6 +485,7 @@ class SelectableText extends StatefulWidget { properties.add(EnumProperty('textAlign', textAlign, defaultValue: null)); properties.add(EnumProperty('textDirection', textDirection, defaultValue: null)); properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null)); + properties.add(DiagnosticsProperty('textScaler', textScaler, defaultValue: null)); properties.add(DoubleProperty('cursorWidth', cursorWidth, defaultValue: 2.0)); properties.add(DoubleProperty('cursorHeight', cursorHeight, defaultValue: null)); properties.add(DiagnosticsProperty('cursorRadius', cursorRadius, defaultValue: null)); @@ -671,6 +700,10 @@ class _SelectableTextState extends State implements TextSelectio if (effectiveTextStyle == null || effectiveTextStyle.inherit) { effectiveTextStyle = defaultTextStyle.style.merge(widget.style ?? _controller._textSpan.style); } + final TextScaler? effectiveScaler = widget.textScaler ?? switch (widget.textScaleFactor) { + null => null, + final double textScaleFactor => TextScaler.linear(textScaleFactor), + }; final Widget child = RepaintBoundary( child: EditableText( key: editableTextKey, @@ -686,7 +719,7 @@ class _SelectableTextState extends State implements TextSelectio strutStyle: widget.strutStyle ?? const StrutStyle(), textAlign: widget.textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start, textDirection: widget.textDirection, - textScaleFactor: widget.textScaleFactor, + textScaler: effectiveScaler, autofocus: widget.autofocus, forceLine: false, minLines: widget.minLines, diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 6680aaa144b17..61acbf04eee65 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -889,8 +889,8 @@ class _SliderState extends State with TickerProviderStateMixin { // This needs to be updated when accessibility // guidelines are available on the material specs page // https://m3.material.io/components/sliders/accessibility. - ? math.min(MediaQuery.textScaleFactorOf(context), 1.3) - : MediaQuery.textScaleFactorOf(context); + ? MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 1.3).textScaleFactor + : MediaQuery.textScalerOf(context).textScaleFactor; return Semantics( container: true, diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index 8e5c2db54885a..223c7f3b03ecc 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -248,7 +248,7 @@ class TextButton extends ButtonStyleButton { /// each state and "others" means all other states. /// /// The `textScaleFactor` is the value of - /// `MediaQuery.textScaleFactorOf(context)` and the names of the + /// `MediaQuery.textScalerOf(context).textScaleFactor` and the names of the /// EdgeInsets constructors and `EdgeInsetsGeometry.lerp` have been /// abbreviated for readability. /// @@ -385,7 +385,7 @@ EdgeInsetsGeometry _scaledPadding(BuildContext context) { useMaterial3 ? const EdgeInsets.symmetric(horizontal: 12, vertical: 8) : const EdgeInsets.all(8), const EdgeInsets.symmetric(horizontal: 8), const EdgeInsets.symmetric(horizontal: 4), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); } @@ -500,7 +500,7 @@ class _TextButtonWithIcon extends TextButton { useMaterial3 ? const EdgeInsetsDirectional.fromSTEB(12, 8, 16, 8) : const EdgeInsets.all(8), const EdgeInsets.symmetric(horizontal: 4), const EdgeInsets.symmetric(horizontal: 4), - MediaQuery.textScaleFactorOf(context), + MediaQuery.textScalerOf(context).textScaleFactor, ); return super.defaultStyleOf(context).copyWith( padding: MaterialStatePropertyAll(scaledPadding), @@ -519,7 +519,7 @@ class _TextButtonWithIconChild extends StatelessWidget { @override Widget build(BuildContext context) { - final double scale = MediaQuery.textScaleFactorOf(context); + final double scale = MediaQuery.textScalerOf(context).textScaleFactor; final double gap = scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!; return Row( mainAxisSize: MainAxisSize.min, diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 479438aa15f27..1d2e9dc2a9ca6 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -348,7 +348,7 @@ class _HourMinuteControl extends StatelessWidget { child: Text( text, style: effectiveStyle, - textScaleFactor: 1, + textScaler: TextScaler.noScaling, ), ), ), @@ -479,7 +479,7 @@ class _StringFragment extends StatelessWidget { child: Text( _stringFragmentValue(timeOfDayFormat), style: effectiveStyle, - textScaleFactor: 1, + textScaler: TextScaler.noScaling, textAlign: TextAlign.center, ), ), @@ -696,7 +696,7 @@ class _AmPmButton extends StatelessWidget { final Color resolvedBackgroundColor = MaterialStateProperty.resolveAs(timePickerTheme.dayPeriodColor ?? defaultTheme.dayPeriodColor, states); final Color resolvedTextColor = MaterialStateProperty.resolveAs(timePickerTheme.dayPeriodTextColor ?? defaultTheme.dayPeriodTextColor, states); final TextStyle? resolvedTextStyle = MaterialStateProperty.resolveAs(timePickerTheme.dayPeriodTextStyle ?? defaultTheme.dayPeriodTextStyle, states)?.copyWith(color: resolvedTextColor); - final double buttonTextScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), 2); + final TextScaler buttonTextScaler = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 2.0); return Material( color: resolvedBackgroundColor, @@ -710,7 +710,7 @@ class _AmPmButton extends StatelessWidget { child: Text( label, style: resolvedTextStyle, - textScaleFactor: buttonTextScaleFactor, + textScaler: buttonTextScaler, ), ), ), @@ -1394,14 +1394,13 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { required String label, required VoidCallback onTap, }) { - final double labelScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), 2); return _TappableLabel( value: value, inner: inner, painter: TextPainter( text: TextSpan(style: textStyle, text: label), textDirection: TextDirection.ltr, - textScaleFactor: labelScaleFactor, + textScaler: MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 2.0), )..layout(), onTap: onTap, ); @@ -2063,8 +2062,7 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> with Restora return SizedBox.fromSize( size: alwaysUse24HourFormat ? defaultTheme.hourMinuteInputSize24Hour : defaultTheme.hourMinuteInputSize, - child: MediaQuery( - data: MediaQuery.of(context).copyWith(textScaleFactor: 1), + child: MediaQuery.withNoTextScaling( child: UnmanagedRestorationScope( bucket: bucket, child: Semantics( @@ -2311,7 +2309,7 @@ class _TimePickerDialogState extends State with RestorationMix // Constrain the textScaleFactor to prevent layout issues. Since only some // parts of the time picker scale up with textScaleFactor, we cap the factor // to 1.1 as that provides enough space to reasonably fit all the content. - final double textScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), 1.1); + final double textScaleFactor = MediaQuery.textScalerOf(context).clamp(maxScaleFactor: 1.1).textScaleFactor; final Size timePickerSize; switch (_entryMode.value) { diff --git a/packages/flutter/lib/src/painting/inline_span.dart b/packages/flutter/lib/src/painting/inline_span.dart index 9037b99c09a04..175ee7d8963cc 100644 --- a/packages/flutter/lib/src/painting/inline_span.dart +++ b/packages/flutter/lib/src/painting/inline_span.dart @@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart'; import 'basic_types.dart'; import 'text_painter.dart'; +import 'text_scaler.dart'; import 'text_span.dart'; import 'text_style.dart'; @@ -209,7 +210,7 @@ abstract class InlineSpan extends DiagnosticableTree { /// Apply the properties of this object to the given [ParagraphBuilder], from /// which a [Paragraph] can be obtained. /// - /// The `textScaleFactor` parameter specifies a scale that the text and + /// The `textScaler` parameter specifies a [TextScaler] that the text and /// placeholders will be scaled by. The scaling is performed before layout, /// so the text will be laid out with the scaled glyphs and placeholders. /// @@ -218,7 +219,10 @@ abstract class InlineSpan extends DiagnosticableTree { /// in the same order as defined in the [InlineSpan] tree. /// /// [Paragraph] objects can be drawn on [Canvas] objects. - void build(ui.ParagraphBuilder builder, { double textScaleFactor = 1.0, List? dimensions }); + void build(ui.ParagraphBuilder builder, { + TextScaler textScaler = TextScaler.noScaling, + List? dimensions, + }); /// Walks this [InlineSpan] and any descendants in pre-order and calls `visitor` /// for each span that has content. diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index bcad34b23dfd5..07a26d79e3bae 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -22,6 +22,7 @@ import 'basic_types.dart'; import 'inline_span.dart'; import 'placeholder_span.dart'; import 'strut_style.dart'; +import 'text_scaler.dart'; import 'text_span.dart'; export 'package:flutter/services.dart' show TextRange, TextSelection; @@ -487,7 +488,13 @@ class TextPainter { InlineSpan? text, TextAlign textAlign = TextAlign.start, TextDirection? textDirection, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, int? maxLines, String? ellipsis, Locale? locale, @@ -496,10 +503,11 @@ class TextPainter { ui.TextHeightBehavior? textHeightBehavior, }) : assert(text == null || text.debugAssertIsValid()), assert(maxLines == null || maxLines > 0), + assert(textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), 'Use textScaler instead.'), _text = text, _textAlign = textAlign, _textDirection = textDirection, - _textScaleFactor = textScaleFactor, + _textScaler = textScaler == TextScaler.noScaling ? TextScaler.linear(textScaleFactor) : textScaler, _maxLines = maxLines, _ellipsis = ellipsis, _locale = locale, @@ -519,7 +527,13 @@ class TextPainter { required InlineSpan text, required TextDirection textDirection, TextAlign textAlign = TextAlign.start, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, int? maxLines, String? ellipsis, Locale? locale, @@ -529,11 +543,15 @@ class TextPainter { double minWidth = 0.0, double maxWidth = double.infinity, }) { + assert( + textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), + 'Use textScaler instead.', + ); final TextPainter painter = TextPainter( text: text, textAlign: textAlign, textDirection: textDirection, - textScaleFactor: textScaleFactor, + textScaler: textScaler == TextScaler.noScaling ? TextScaler.linear(textScaleFactor) : textScaler, maxLines: maxLines, ellipsis: ellipsis, locale: locale, @@ -561,7 +579,13 @@ class TextPainter { required InlineSpan text, required TextDirection textDirection, TextAlign textAlign = TextAlign.start, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, int? maxLines, String? ellipsis, Locale? locale, @@ -571,11 +595,15 @@ class TextPainter { double minWidth = 0.0, double maxWidth = double.infinity, }) { + assert( + textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), + 'Use textScaler instead.', + ); final TextPainter painter = TextPainter( text: text, textAlign: textAlign, textDirection: textDirection, - textScaleFactor: textScaleFactor, + textScaler: textScaler == TextScaler.noScaling ? TextScaler.linear(textScaleFactor) : textScaler, maxLines: maxLines, ellipsis: ellipsis, locale: locale, @@ -728,19 +756,48 @@ class TextPainter { _layoutTemplate = null; // Shouldn't really matter, but for strict correctness... } + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [textScaler] instead. + /// /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than /// the specified font size. /// /// After this is set, you must call [layout] before the next call to [paint]. - double get textScaleFactor => _textScaleFactor; - double _textScaleFactor; + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double get textScaleFactor => textScaler.textScaleFactor; + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) set textScaleFactor(double value) { - if (_textScaleFactor == value) { + textScaler = TextScaler.linear(value); + } + + /// {@template flutter.painting.textPainter.textScaler} + /// The font scaling strategy to use when laying out and rendering the text. + /// + /// The value usually comes from [MediaQuery.textScalerOf], which typically + /// reflects the user-specified text scaling value in the platform's + /// accessibility settings. The [TextStyle.fontSize] of the text will be + /// adjusted by the [TextScaler] before the text is laid out and rendered. + /// {@endtemplate} + /// + /// The [layout] method must be called after [textScaler] changes as it + /// affects the text layout. + TextScaler get textScaler => _textScaler; + TextScaler _textScaler; + set textScaler(TextScaler value) { + if (value == _textScaler) { return; } - _textScaleFactor = value; + _textScaler = value; markNeedsLayout(); _layoutTemplate?.dispose(); _layoutTemplate = null; @@ -905,7 +962,7 @@ class TextPainter { return _text!.style?.getParagraphStyle( textAlign: textAlign, textDirection: textDirection ?? defaultTextDirection, - textScaleFactor: textScaleFactor, + textScaler: textScaler, maxLines: _maxLines, textHeightBehavior: _textHeightBehavior, ellipsis: _ellipsis, @@ -916,8 +973,8 @@ class TextPainter { textDirection: textDirection ?? defaultTextDirection, // Use the default font size to multiply by as RichText does not // perform inheriting [TextStyle]s and would otherwise - // fail to apply textScaleFactor. - fontSize: _kDefaultFontSize * textScaleFactor, + // fail to apply textScaler. + fontSize: textScaler.scale(_kDefaultFontSize), maxLines: maxLines, textHeightBehavior: _textHeightBehavior, ellipsis: ellipsis, @@ -930,7 +987,7 @@ class TextPainter { final ui.ParagraphBuilder builder = ui.ParagraphBuilder( _createParagraphStyle(TextDirection.rtl), ); // direction doesn't matter, text is just a space - final ui.TextStyle? textStyle = text?.style?.getTextStyle(textScaleFactor: textScaleFactor); + final ui.TextStyle? textStyle = text?.style?.getTextStyle(textScaler: textScaler); if (textStyle != null) { builder.pushStyle(textStyle); } @@ -1025,7 +1082,7 @@ class TextPainter { // assign it to _paragraph. ui.Paragraph _createParagraph(InlineSpan text) { final ui.ParagraphBuilder builder = ui.ParagraphBuilder(_createParagraphStyle()); - text.build(builder, textScaleFactor: textScaleFactor, dimensions: _placeholderDimensions); + text.build(builder, textScaler: textScaler, dimensions: _placeholderDimensions); assert(() { _debugMarkNeedsLayoutCallStack = null; return true; diff --git a/packages/flutter/lib/src/painting/text_scaler.dart b/packages/flutter/lib/src/painting/text_scaler.dart new file mode 100644 index 0000000000000..554cfb892fa5a --- /dev/null +++ b/packages/flutter/lib/src/painting/text_scaler.dart @@ -0,0 +1,151 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' show max, min; + +import 'package:flutter/foundation.dart'; + +/// A class that describes how textual contents should be scaled for better +/// readability. +/// +/// The [scale] function computes the scaled font size given the original +/// unscaled font size specified by app developers. +/// +/// The [==] operator defines the equality of 2 [TextScaler]s, which the +/// framework uses to determine whether text widgets should rebuild when their +/// [TextScaler] changes. Consider overridding the [==] operator if applicable +/// to avoid unnecessary rebuilds. +@immutable +abstract class TextScaler { + /// Creates a TextScaler. + const TextScaler(); + + /// Creates a proportional [TextScaler] that scales the incoming font size by + /// multiplying it with the given `textScaleFactor`. + const factory TextScaler.linear(double textScaleFactor) = _LinearTextScaler; + + /// A [TextScaler] that doesn't scale the input font size. + /// + /// This is equivalent to `TextScaler.linear(1.0)`, the [TextScaler.scale] + /// implementation always returns the input font size as-is. + static const TextScaler noScaling = _LinearTextScaler(1.0); + + /// Computes the scaled font size (in logical pixels) with the given unscaled + /// `fontSize` (in logical pixels). + /// + /// The input `fontSize` must be finite and non-negative. + /// + /// When given the same `fontSize` input, this method returns the same value. + /// The output of a larger input `fontSize` is typically larger than that of a + /// smaller input, but on unusual occasions they may produce the same output. + /// For example, some platforms use single-precision floats to represent font + /// sizes, as a result of truncation two different unscaled font sizes can be + /// scaled to the same value. + double scale(double fontSize); + + /// The estimated number of font pixels for each logical pixel. This property + /// exists only for backward compatibility purposes, and will be removed in + /// a future version of Flutter. + /// + /// The value of this property is only an estimate, so it may not reflect the + /// exact text scaling strategy this [TextScaler] represents, especially when + /// this [TextScaler] is not linear. Consider using [TextScaler.scale] instead. + @Deprecated( + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double get textScaleFactor; + + /// Returns a new [TextScaler] that restricts the scaled font size to within + /// the range `[minScaleFactor * fontSize, maxScaleFactor * fontSize]`. + TextScaler clamp({ double minScaleFactor = 0, double maxScaleFactor = double.infinity }) { + assert(maxScaleFactor >= minScaleFactor); + assert(!maxScaleFactor.isNaN); + assert(minScaleFactor.isFinite); + assert(minScaleFactor >= 0); + + return minScaleFactor == maxScaleFactor + ? TextScaler.linear(minScaleFactor) + : _ClampedTextScaler(this, minScaleFactor, maxScaleFactor); + } +} + +final class _LinearTextScaler implements TextScaler { + const _LinearTextScaler(this.textScaleFactor) : assert(textScaleFactor >= 0); + + @override + final double textScaleFactor; + + @override + double scale(double fontSize) { + assert(fontSize >= 0); + assert(fontSize.isFinite); + return fontSize * textScaleFactor; + } + + @override + TextScaler clamp({ double minScaleFactor = 0, double maxScaleFactor = double.infinity }) { + assert(maxScaleFactor >= minScaleFactor); + assert(!maxScaleFactor.isNaN); + assert(minScaleFactor.isFinite); + assert(minScaleFactor >= 0); + + final double newScaleFactor = clampDouble(textScaleFactor, minScaleFactor, maxScaleFactor); + return newScaleFactor == textScaleFactor ? this : _LinearTextScaler(newScaleFactor); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is _LinearTextScaler && other.textScaleFactor == textScaleFactor; + } + + @override + int get hashCode => textScaleFactor.hashCode; + + @override + String toString() => textScaleFactor == 1.0 ? 'no scaling' : 'linear (${textScaleFactor}x)'; +} + +final class _ClampedTextScaler implements TextScaler { + const _ClampedTextScaler(this.scaler, this.minScale, this.maxScale) : assert(maxScale > minScale); + final TextScaler scaler; + final double minScale; + final double maxScale; + + @override + double get textScaleFactor => clampDouble(scaler.textScaleFactor, minScale, maxScale); + + @override + double scale(double fontSize) { + assert(fontSize >= 0); + assert(fontSize.isFinite); + return minScale == maxScale + ? minScale * fontSize + : clampDouble(scaler.scale(fontSize), minScale * fontSize, maxScale * fontSize); + } + + @override + TextScaler clamp({ double minScaleFactor = 0, double maxScaleFactor = double.infinity }) { + return minScaleFactor == maxScaleFactor + ? _LinearTextScaler(minScaleFactor) + : _ClampedTextScaler(scaler, max(minScaleFactor, minScale), min(maxScaleFactor, maxScale)); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + return other is _ClampedTextScaler + && minScale == other.minScale + && maxScale == other.maxScale + && (minScale == maxScale || scaler == other.scaler); + } + + @override + int get hashCode => minScale == maxScale ? minScale.hashCode : Object.hash(scaler, minScale, maxScale); +} diff --git a/packages/flutter/lib/src/painting/text_span.dart b/packages/flutter/lib/src/painting/text_span.dart index 34168be205e91..c3f37310332bc 100644 --- a/packages/flutter/lib/src/painting/text_span.dart +++ b/packages/flutter/lib/src/painting/text_span.dart @@ -11,6 +11,7 @@ import 'package:flutter/services.dart'; import 'basic_types.dart'; import 'inline_span.dart'; import 'text_painter.dart'; +import 'text_scaler.dart'; // Examples can assume: // late TextSpan myTextSpan; @@ -267,13 +268,13 @@ class TextSpan extends InlineSpan implements HitTestTarget, MouseTrackerAnnotati @override void build( ui.ParagraphBuilder builder, { - double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, List? dimensions, }) { assert(debugAssertIsValid()); final bool hasStyle = style != null; if (hasStyle) { - builder.pushStyle(style!.getTextStyle(textScaleFactor: textScaleFactor)); + builder.pushStyle(style!.getTextStyle(textScaler: textScaler)); } if (text != null) { try { @@ -294,7 +295,7 @@ class TextSpan extends InlineSpan implements HitTestTarget, MouseTrackerAnnotati for (final InlineSpan child in children) { child.build( builder, - textScaleFactor: textScaleFactor, + textScaler: textScaler, dimensions: dimensions, ); } diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart index b00e0191d0184..d88e5a0262381 100644 --- a/packages/flutter/lib/src/painting/text_style.dart +++ b/packages/flutter/lib/src/painting/text_style.dart @@ -19,6 +19,7 @@ import 'basic_types.dart'; import 'colors.dart'; import 'strut_style.dart'; import 'text_painter.dart'; +import 'text_scaler.dart'; const String _kDefaultDebugLabel = 'unknown'; @@ -1271,7 +1272,24 @@ class TextStyle with Diagnosticable { } /// The style information for text runs, encoded for use by `dart:ui`. - ui.TextStyle getTextStyle({ double textScaleFactor = 1.0 }) { + ui.TextStyle getTextStyle({ + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, + }) { + assert( + identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ); + final double? fontSize = switch (this.fontSize) { + null => null, + final double size when textScaler == TextScaler.noScaling => size * textScaleFactor, + final double size => textScaler.scale(size), + }; return ui.TextStyle( color: color, decoration: decoration, @@ -1284,16 +1302,17 @@ class TextStyle with Diagnosticable { leadingDistribution: leadingDistribution, fontFamily: fontFamily, fontFamilyFallback: fontFamilyFallback, - fontSize: fontSize == null ? null : fontSize! * textScaleFactor, + fontSize: fontSize, letterSpacing: letterSpacing, wordSpacing: wordSpacing, height: height, locale: locale, foreground: foreground, - background: background ?? (backgroundColor != null - ? (Paint()..color = backgroundColor!) - : null - ), + background: switch ((background, backgroundColor)) { + (final Paint paint, _) => paint, + (_, final Color color) => Paint()..color = color, + _ => null, + }, shadows: shadows, fontFeatures: fontFeatures, fontVariations: fontVariations, @@ -1311,7 +1330,7 @@ class TextStyle with Diagnosticable { ui.ParagraphStyle getParagraphStyle({ TextAlign? textAlign, TextDirection? textDirection, - double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, String? ellipsis, int? maxLines, ui.TextHeightBehavior? textHeightBehavior, @@ -1327,6 +1346,7 @@ class TextStyle with Diagnosticable { final ui.TextLeadingDistribution? leadingDistribution = this.leadingDistribution; final ui.TextHeightBehavior? effectiveTextHeightBehavior = textHeightBehavior ?? (leadingDistribution == null ? null : ui.TextHeightBehavior(leadingDistribution: leadingDistribution)); + return ui.ParagraphStyle( textAlign: textAlign, textDirection: textDirection, @@ -1335,13 +1355,16 @@ class TextStyle with Diagnosticable { fontWeight: fontWeight ?? this.fontWeight, fontStyle: fontStyle ?? this.fontStyle, fontFamily: fontFamily ?? this.fontFamily, - fontSize: (fontSize ?? this.fontSize ?? _kDefaultFontSize) * textScaleFactor, + fontSize: textScaler.scale(fontSize ?? this.fontSize ?? _kDefaultFontSize), height: height ?? this.height, textHeightBehavior: effectiveTextHeightBehavior, strutStyle: strutStyle == null ? null : ui.StrutStyle( fontFamily: strutStyle.fontFamily, fontFamilyFallback: strutStyle.fontFamilyFallback, - fontSize: strutStyle.fontSize == null ? null : strutStyle.fontSize! * textScaleFactor, + fontSize: switch (strutStyle.fontSize) { + null => null, + final double unscaled => textScaler.scale(unscaled), + }, height: strutStyle.height, leading: strutStyle.leading, fontWeight: strutStyle.fontWeight, diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index a357bde585572..d03d5f6b2d428 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -288,7 +288,13 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, bool expands = false, StrutStyle? strutStyle, Color? selectionColor, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, TextSelection? selection, required ViewportOffset offset, this.ignorePointer = false, @@ -326,6 +332,10 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, !expands || (maxLines == null && minLines == null), 'minLines and maxLines must be null when expands is true.', ), + assert( + identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ), assert(obscuringCharacter.characters.length == 1), assert(cursorWidth >= 0.0), assert(cursorHeight == null || cursorHeight >= 0.0), @@ -333,7 +343,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, text: text, textAlign: textAlign, textDirection: textDirection, - textScaleFactor: textScaleFactor, + textScaler: textScaler == TextScaler.noScaling ? TextScaler.linear(textScaleFactor) : textScaler, locale: locale, maxLines: maxLines == 1 ? 1 : null, strutStyle: strutStyle, @@ -985,16 +995,35 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, _selectionPainter.highlightColor = value; } + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [textScaler] instead. + /// /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than /// the specified font size. + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) double get textScaleFactor => _textPainter.textScaleFactor; + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) set textScaleFactor(double value) { - if (_textPainter.textScaleFactor == value) { + textScaler = TextScaler.linear(value); + } + + /// {@macro flutter.painting.textPainter.textScaler} + TextScaler get textScaler => _textPainter.textScaler; + set textScaler(TextScaler value) { + if (_textPainter.textScaler == value) { return; } - _textPainter.textScaleFactor = value; + _textPainter.textScaler = value; markNeedsTextLayout(); } @@ -2528,7 +2557,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, properties.add(IntProperty('minLines', minLines)); properties.add(DiagnosticsProperty('expands', expands, defaultValue: false)); properties.add(ColorProperty('selectionColor', selectionColor)); - properties.add(DoubleProperty('textScaleFactor', textScaleFactor)); + properties.add(DiagnosticsProperty('textScaler', textScaler, defaultValue: TextScaler.noScaling)); properties.add(DiagnosticsProperty('locale', locale, defaultValue: null)); properties.add(DiagnosticsProperty('selection', selection)); properties.add(DiagnosticsProperty('offset', offset)); diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 066f6137e715a..4fd946a88d991 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -253,7 +253,7 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin 0), + assert( + identical(textScaler, TextScaler.noScaling) || textScaleFactor == 1.0, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ), _softWrap = softWrap, _overflow = overflow, _selectionColor = selectionColor, @@ -280,7 +290,7 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin _textPainter.textScaleFactor; + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) set textScaleFactor(double value) { - if (_textPainter.textScaleFactor == value) { + textScaler = TextScaler.linear(value); + } + + /// {@macro flutter.painting.textPainter.textScaler} + TextScaler get textScaler => _textPainter.textScaler; + set textScaler(TextScaler value) { + if (_textPainter.textScaler == value) { return; } - _textPainter.textScaleFactor = value; + _textPainter.textScaler = value; _overflowShader = null; markNeedsLayout(); } @@ -791,7 +820,7 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin('overflow', overflow)); properties.add( - DoubleProperty( - 'textScaleFactor', - textScaleFactor, - defaultValue: 1.0, - ), + DiagnosticsProperty('textScaler', textScaler, defaultValue: TextScaler.noScaling), ); properties.add( DiagnosticsProperty( diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 100f68d584af6..3dc2786736bce 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -5715,7 +5715,7 @@ class Flow extends MultiChildRenderObjectWidget { class RichText extends MultiChildRenderObjectWidget { /// Creates a paragraph of rich text. /// - /// The [text], [textAlign], [softWrap], [overflow], and [textScaleFactor] + /// The [text], [textAlign], [softWrap], [overflow], and [textScaler] /// arguments must not be null. /// /// The [maxLines] property may be null (and indeed defaults to null), but if @@ -5730,7 +5730,13 @@ class RichText extends MultiChildRenderObjectWidget { this.textDirection, this.softWrap = true, this.overflow = TextOverflow.clip, - this.textScaleFactor = 1.0, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, this.maxLines, this.locale, this.strutStyle, @@ -5740,7 +5746,17 @@ class RichText extends MultiChildRenderObjectWidget { this.selectionColor, }) : assert(maxLines == null || maxLines > 0), assert(selectionRegistrar == null || selectionColor != null), - super(children: WidgetSpan.extractFromInlineSpan(text, textScaleFactor)); + assert(textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), 'Use textScaler instead.'), + textScaler = _effectiveTextScalerFrom(textScaler, textScaleFactor), + super(children: WidgetSpan.extractFromInlineSpan(text, _effectiveTextScalerFrom(textScaler, textScaleFactor))); + + static TextScaler _effectiveTextScalerFrom(TextScaler textScaler, double textScaleFactor) { + return switch ((textScaler, textScaleFactor)) { + (final TextScaler scaler, 1.0) => scaler, + (TextScaler.noScaling, final double textScaleFactor) => TextScaler.linear(textScaleFactor), + (final TextScaler scaler, _) => scaler, + }; + } /// The text to display in this widget. final InlineSpan text; @@ -5772,11 +5788,22 @@ class RichText extends MultiChildRenderObjectWidget { /// How visual overflow should be handled. final TextOverflow overflow; + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [textScaler] instead. + /// /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than /// the specified font size. - final double textScaleFactor; + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double get textScaleFactor => textScaler.textScaleFactor; + + /// {@macro flutter.painting.textPainter.textScaler} + final TextScaler textScaler; /// An optional maximum number of lines for the text to span, wrapping if necessary. /// If the text exceeds the given number of lines, it will be truncated according @@ -5826,7 +5853,7 @@ class RichText extends MultiChildRenderObjectWidget { textDirection: textDirection ?? Directionality.of(context), softWrap: softWrap, overflow: overflow, - textScaleFactor: textScaleFactor, + textScaler: textScaler, maxLines: maxLines, strutStyle: strutStyle, textWidthBasis: textWidthBasis, @@ -5846,7 +5873,7 @@ class RichText extends MultiChildRenderObjectWidget { ..textDirection = textDirection ?? Directionality.of(context) ..softWrap = softWrap ..overflow = overflow - ..textScaleFactor = textScaleFactor + ..textScaler = textScaler ..maxLines = maxLines ..strutStyle = strutStyle ..textWidthBasis = textWidthBasis @@ -5863,7 +5890,7 @@ class RichText extends MultiChildRenderObjectWidget { properties.add(EnumProperty('textDirection', textDirection, defaultValue: null)); properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true)); properties.add(EnumProperty('overflow', overflow, defaultValue: TextOverflow.clip)); - properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: 1.0)); + properties.add(DiagnosticsProperty('textScaler', textScaler, defaultValue: TextScaler.noScaling)); properties.add(IntProperty('maxLines', maxLines, ifNull: 'unlimited')); properties.add(EnumProperty('textWidthBasis', textWidthBasis, defaultValue: TextWidthBasis.parent)); properties.add(StringProperty('text', text.toPlainText())); diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 859dfa89bd24f..d23229d536d24 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -752,7 +752,13 @@ class EditableText extends StatefulWidget { this.textAlign = TextAlign.start, this.textDirection, this.locale, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) this.textScaleFactor, + this.textScaler, this.maxLines = 1, this.minLines, this.expands = false, @@ -1054,6 +1060,9 @@ class EditableText extends StatefulWidget { final Locale? locale; /// {@template flutter.widgets.editableText.textScaleFactor} + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [textScaler] instead. + /// /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than @@ -1062,8 +1071,16 @@ class EditableText extends StatefulWidget { /// Defaults to the [MediaQueryData.textScaleFactor] obtained from the ambient /// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope. /// {@endtemplate} + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) final double? textScaleFactor; + /// {@macro flutter.painting.textPainter.textScaler} + final TextScaler? textScaler; + /// The color to use when painting the cursor. /// /// Cannot be null. @@ -2039,7 +2056,7 @@ class EditableText extends StatefulWidget { properties.add(EnumProperty('textAlign', textAlign, defaultValue: null)); properties.add(EnumProperty('textDirection', textDirection, defaultValue: null)); properties.add(DiagnosticsProperty('locale', locale, defaultValue: null)); - properties.add(DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null)); + properties.add(DiagnosticsProperty('textScaler', textScaler, defaultValue: null)); properties.add(IntProperty('maxLines', maxLines, defaultValue: 1)); properties.add(IntProperty('minLines', minLines, defaultValue: null)); properties.add(DiagnosticsProperty('expands', expands, defaultValue: false)); @@ -3890,11 +3907,17 @@ class EditableTextState extends State with AutomaticKeepAliveClien } final InlineSpan inlineSpan = renderEditable.text!; + final TextScaler effectiveTextScaler = switch ((widget.textScaler, widget.textScaleFactor)) { + (final TextScaler textScaler, _) => textScaler, + (null, final double textScaleFactor) => TextScaler.linear(textScaleFactor), + (null, null) => MediaQuery.textScalerOf(context), + }; + final _ScribbleCacheKey newCacheKey = _ScribbleCacheKey( inlineSpan: inlineSpan, textAlign: widget.textAlign, textDirection: _textDirection, - textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context), + textScaler: effectiveTextScaler, textHeightBehavior: widget.textHeightBehavior ?? DefaultTextHeightBehavior.maybeOf(context), locale: widget.locale, structStyle: widget.strutStyle, @@ -4588,6 +4611,12 @@ class EditableTextState extends State with AutomaticKeepAliveClien super.build(context); // See AutomaticKeepAliveClientMixin. final TextSelectionControls? controls = widget.selectionControls; + final TextScaler effectiveTextScaler = switch ((widget.textScaler, widget.textScaleFactor)) { + (final TextScaler textScaler, _) => textScaler, + (null, final double textScaleFactor) => TextScaler.linear(textScaleFactor), + (null, null) => MediaQuery.textScalerOf(context), + }; + return _CompositionCallback( compositeCallback: _compositeCallback, enabled: _hasInputConnection, @@ -4688,7 +4717,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien selectionColor: _selectionOverlay?.spellCheckToolbarIsVisible ?? false ? _spellCheckConfiguration.misspelledSelectionColor ?? widget.selectionColor : widget.selectionColor, - textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context), + textScaler: effectiveTextScaler, textAlign: widget.textAlign, textDirection: _textDirection, locale: widget.locale, @@ -4814,7 +4843,7 @@ class _Editable extends MultiChildRenderObjectWidget { required this.expands, this.strutStyle, this.selectionColor, - required this.textScaleFactor, + required this.textScaler, required this.textAlign, required this.textDirection, this.locale, @@ -4835,7 +4864,7 @@ class _Editable extends MultiChildRenderObjectWidget { this.promptRectRange, this.promptRectColor, required this.clipBehavior, - }) : super(children: WidgetSpan.extractFromInlineSpan(inlineSpan, textScaleFactor)); + }) : super(children: WidgetSpan.extractFromInlineSpan(inlineSpan, textScaler)); final InlineSpan inlineSpan; final TextEditingValue value; @@ -4852,7 +4881,7 @@ class _Editable extends MultiChildRenderObjectWidget { final bool expands; final StrutStyle? strutStyle; final Color? selectionColor; - final double textScaleFactor; + final TextScaler textScaler; final TextAlign textAlign; final TextDirection textDirection; final Locale? locale; @@ -4893,7 +4922,7 @@ class _Editable extends MultiChildRenderObjectWidget { expands: expands, strutStyle: strutStyle, selectionColor: selectionColor, - textScaleFactor: textScaleFactor, + textScaler: textScaler, textAlign: textAlign, textDirection: textDirection, locale: locale ?? Localizations.maybeLocaleOf(context), @@ -4937,7 +4966,7 @@ class _Editable extends MultiChildRenderObjectWidget { ..expands = expands ..strutStyle = strutStyle ..selectionColor = selectionColor - ..textScaleFactor = textScaleFactor + ..textScaler = textScaler ..textAlign = textAlign ..textDirection = textDirection ..locale = locale ?? Localizations.maybeLocaleOf(context) @@ -4970,7 +4999,7 @@ class _ScribbleCacheKey { required this.inlineSpan, required this.textAlign, required this.textDirection, - required this.textScaleFactor, + required this.textScaler, required this.textHeightBehavior, required this.locale, required this.structStyle, @@ -4980,7 +5009,7 @@ class _ScribbleCacheKey { final TextAlign textAlign; final TextDirection textDirection; - final double textScaleFactor; + final TextScaler textScaler; final TextHeightBehavior? textHeightBehavior; final Locale? locale; final StrutStyle structStyle; @@ -4994,7 +5023,7 @@ class _ScribbleCacheKey { } final bool needsLayout = textAlign != other.textAlign || textDirection != other.textDirection - || textScaleFactor != other.textScaleFactor + || textScaler != other.textScaler || (textHeightBehavior ?? const TextHeightBehavior()) != (other.textHeightBehavior ?? const TextHeightBehavior()) || locale != other.locale || structStyle != other.structStyle @@ -5111,17 +5140,19 @@ class _ScribblePlaceholder extends WidgetSpan { final Size size; @override - void build(ui.ParagraphBuilder builder, { double textScaleFactor = 1.0, List? dimensions }) { + void build(ui.ParagraphBuilder builder, { + TextScaler textScaler = TextScaler.noScaling, + List? dimensions, + }) { assert(debugAssertIsValid()); final bool hasStyle = style != null; if (hasStyle) { - builder.pushStyle(style!.getTextStyle(textScaleFactor: textScaleFactor)); + builder.pushStyle(style!.getTextStyle(textScaler: textScaler)); } builder.addPlaceholder( - size.width, - size.height, + size.width * textScaler.textScaleFactor, + size.height * textScaler.textScaleFactor, alignment, - scale: textScaleFactor, ); if (hasStyle) { builder.pop(); diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 0714708e14ade..1c80b4d2e2b74 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -30,8 +30,8 @@ enum Orientation { /// /// [MediaQuery] contains a large number of related properties. Widgets frequently /// depend on only a few of these attributes. For example, a widget that needs to -/// rebuild when the [MediaQueryData.textScaleFactor] changes does not need to -/// be notified when the [MediaQueryData.size] changes. Specifying an aspect avoids +/// rebuild when the [MediaQueryData.textScaler] changes does not need to be +/// notified when the [MediaQueryData.size] changes. Specifying an aspect avoids /// unnecessary rebuilds. enum _MediaQueryAspect { /// Specifies the aspect corresponding to [MediaQueryData.size]. @@ -42,6 +42,8 @@ enum _MediaQueryAspect { devicePixelRatio, /// Specifies the aspect corresponding to [MediaQueryData.textScaleFactor]. textScaleFactor, + /// Specifies the aspect corresponding to [MediaQueryData.textScaler]. + textScaler, /// Specifies the aspect corresponding to [MediaQueryData.platformBrightness]. platformBrightness, /// Specifies the aspect corresponding to [MediaQueryData.padding]. @@ -140,12 +142,20 @@ enum _MediaQueryAspect { class MediaQueryData { /// Creates data for a media query with explicit values. /// - /// Consider using [MediaQueryData.fromView] to create data based on a - /// [dart:ui.FlutterView]. + /// In a typical application, calling this constructor directly is rarely + /// needed. Consider using [MediaQueryData.fromView] to create data based on a + /// [dart:ui.FlutterView], or [MediaQueryData.copyWith] to create a new copy + /// of [MediaQueryData] with updated properties from a base [MediaQueryData]. const MediaQueryData({ this.size = Size.zero, this.devicePixelRatio = 1.0, - this.textScaleFactor = 1.0, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double textScaleFactor = 1.0, + TextScaler textScaler = _kUnspecifiedTextScaler, this.platformBrightness = Brightness.light, this.padding = EdgeInsets.zero, this.viewInsets = EdgeInsets.zero, @@ -161,7 +171,12 @@ class MediaQueryData { this.navigationMode = NavigationMode.traditional, this.gestureSettings = const DeviceGestureSettings(touchSlop: kTouchSlop), this.displayFeatures = const [], - }); + }) : _textScaleFactor = textScaleFactor, + _textScaler = textScaler, + assert( + identical(textScaler, _kUnspecifiedTextScaler) || textScaleFactor == 1.0, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ); /// Deprecated. Use [MediaQueryData.fromView] instead. /// @@ -212,7 +227,8 @@ class MediaQueryData { MediaQueryData.fromView(ui.FlutterView view, {MediaQueryData? platformData}) : size = view.physicalSize / view.devicePixelRatio, devicePixelRatio = view.devicePixelRatio, - textScaleFactor = platformData?.textScaleFactor ?? view.platformDispatcher.textScaleFactor, + _textScaleFactor = 1.0, // _textScaler is the source of truth. + _textScaler = _textScalerFromView(view, platformData), platformBrightness = platformData?.platformBrightness ?? view.platformDispatcher.platformBrightness, padding = EdgeInsets.fromViewPadding(view.padding, view.devicePixelRatio), viewPadding = EdgeInsets.fromViewPadding(view.viewPadding, view.devicePixelRatio), @@ -229,6 +245,11 @@ class MediaQueryData { gestureSettings = DeviceGestureSettings.fromView(view), displayFeatures = view.displayFeatures; + static TextScaler _textScalerFromView(ui.FlutterView view, MediaQueryData? platformData) { + final double scaleFactor = platformData?.textScaleFactor ?? view.platformDispatcher.textScaleFactor; + return scaleFactor == 1.0 ? TextScaler.noScaling : TextScaler.linear(scaleFactor); + } + /// The size of the media in logical pixels (e.g, the size of the screen). /// /// Logical pixels are roughly the same visual size across devices. Physical @@ -261,6 +282,9 @@ class MediaQueryData { /// the Nexus 6 has a device pixel ratio of 3.5. final double devicePixelRatio; + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [textScaler] instead. + /// /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than @@ -270,7 +294,44 @@ class MediaQueryData { /// /// * [MediaQuery.textScaleFactorOf], a method to find and depend on the /// textScaleFactor defined for a [BuildContext]. - final double textScaleFactor; + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) + double get textScaleFactor => textScaler.textScaleFactor; + // TODO(LongCatIsLooong): remove this after textScaleFactor is removed. To + // maintain backward compatibility and also keep the const constructor this + // has to be kept as a private field. + // https://github.com/flutter/flutter/issues/128825 + final double _textScaleFactor; + + /// The font scaling strategy to use for laying out textual contents. + /// + /// If this [MediaQueryData] is created by the [MediaQueryData.fromView] + /// constructor, this property reflects the platform's preferred text scaling + /// strategy, and may change as the user changes the scaling factor in the + /// operating system's accessibility settings. + /// + /// See also: + /// + /// * [MediaQuery.textScalerOf], a method to find and depend on the + /// [textScaler] defined for a [BuildContext]. + /// * [TextPainter], a class that lays out and paints text. + TextScaler get textScaler { + // The constructor was called with an explicitly specified textScaler value, + // we assume the caller is migrated and ignore _textScaleFactor. + if (!identical(_kUnspecifiedTextScaler, _textScaler)) { + return _textScaler; + } + return _textScaleFactor == 1.0 + // textScaleFactor and textScaler from the constructor are consistent. + ? TextScaler.noScaling + // The constructor was called with an explicitly specified textScaleFactor, + // we assume the caller is unmigrated and ignore _textScaler. + : TextScaler.linear(_textScaleFactor); + } + final TextScaler _textScaler; /// The current brightness mode of the host platform. /// @@ -490,10 +551,19 @@ class MediaQueryData { /// Creates a copy of this media query data but with the given fields replaced /// with the new values. + /// + /// The `textScaler` parameter and `textScaleFactor` parameter must not be + /// both specified. MediaQueryData copyWith({ Size? size, double? devicePixelRatio, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) double? textScaleFactor, + TextScaler? textScaler, Brightness? platformBrightness, EdgeInsets? padding, EdgeInsets? viewPadding, @@ -510,10 +580,14 @@ class MediaQueryData { DeviceGestureSettings? gestureSettings, List? displayFeatures, }) { + assert(textScaleFactor == null || textScaler == null); + if (textScaleFactor != null) { + textScaler ??= TextScaler.linear(textScaleFactor); + } return MediaQueryData( size: size ?? this.size, devicePixelRatio: devicePixelRatio ?? this.devicePixelRatio, - textScaleFactor: textScaleFactor ?? this.textScaleFactor, + textScaler: textScaler ?? this.textScaler, platformBrightness: platformBrightness ?? this.platformBrightness, padding: padding ?? this.padding, viewPadding: viewPadding ?? this.viewPadding, @@ -750,7 +824,7 @@ class MediaQueryData { final List properties = [ 'size: $size', 'devicePixelRatio: ${devicePixelRatio.toStringAsFixed(1)}', - 'textScaleFactor: ${textScaleFactor.toStringAsFixed(1)}', + 'textScaler: $textScaler', 'platformBrightness: $platformBrightness', 'padding: $padding', 'viewPadding: $viewPadding', @@ -1002,6 +1076,64 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { ); } + /// Wraps the `child` in a [MediaQuery] with its [MediaQueryData.textScaler] + /// set to [TextScaler.noScaling]. + /// + /// The returned widget must be inserted in a widget tree below an existing + /// [MediaQuery] widget. + /// + /// This can be used to prevent, for example, icon fonts from scaling as the + /// user adjusts the platform's text scaling value. + static Widget withNoTextScaling({ + Key? key, + required Widget child, + }) { + return Builder( + key: key, + builder: (BuildContext context) { + assert(debugCheckHasMediaQuery(context)); + return MediaQuery( + data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling), + child: child, + ); + }, + ); + } + + /// Wraps the `child` in a [MediaQuery] and applies [TextScaler.clamp] on the + /// current [MediaQueryData.textScaler]. + /// + /// The returned widget must be inserted in a widget tree below an existing + /// [MediaQuery] widget. + /// + /// This is a convenience function to restrict the range of the scaled text + /// size to `[minScaleFactor * fontSize, maxScaleFactor * fontSize]` (to + /// prevent excessive text scaling that would break the UI, for example). When + /// `minScaleFactor` equals `maxScaleFactor`, the scaler becomes + /// `TextScaler.linear(minScaleFactor)`. + static Widget withClampedTextScaling({ + Key? key, + double minScaleFactor = 0.0, + double maxScaleFactor = double.infinity, + required Widget child, + }) { + assert(maxScaleFactor >= minScaleFactor); + assert(!maxScaleFactor.isNaN); + assert(minScaleFactor.isFinite); + assert(minScaleFactor >= 0); + + return Builder(builder: (BuildContext context) { + assert(debugCheckHasMediaQuery(context)); + final MediaQueryData data = MediaQuery.of(context); + return MediaQuery( + data: data.copyWith( + textScaler: data.textScaler.clamp(minScaleFactor: minScaleFactor, maxScaleFactor: maxScaleFactor), + ), + child: child, + ); + }); + } + /// Contains information about the current media. /// /// For example, the [MediaQueryData.size] property contains the width and @@ -1126,20 +1258,53 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// the [MediaQueryData.devicePixelRatio] property of the ancestor [MediaQuery] changes. static double? maybeDevicePixelRatioOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.devicePixelRatio)?.devicePixelRatio; + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [maybeTextScalerOf] instead. + /// /// Returns textScaleFactor for the nearest MediaQuery ancestor or /// 1.0, if no such ancestor exists. /// /// Use of this method will cause the given [context] to rebuild any time that /// the [MediaQueryData.textScaleFactor] property of the ancestor [MediaQuery] changes. + @Deprecated( + 'Use textScalerOf instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) static double textScaleFactorOf(BuildContext context) => maybeTextScaleFactorOf(context) ?? 1.0; + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [maybeTextScalerOf] instead. + /// /// Returns textScaleFactor for the nearest MediaQuery ancestor or /// null, if no such ancestor exists. /// /// Use of this method will cause the given [context] to rebuild any time that - /// the [MediaQueryData.textScaleFactor] property of the ancestor [MediaQuery] changes. + /// the [MediaQueryData.textScaleFactor] property of the ancestor [MediaQuery] + /// changes. + @Deprecated( + 'Use maybeTextScalerOf instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) static double? maybeTextScaleFactorOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.textScaleFactor)?.textScaleFactor; + /// Returns the [TextScaler] for the nearest [MediaQuery] ancestor or null if + /// no such ancestor exists. + /// + /// Use of this method will cause the given [context] to rebuild any time that + /// the [MediaQueryData.textScaler] property of the ancestor [MediaQuery] + /// changes. + static TextScaler textScalerOf(BuildContext context) => maybeTextScalerOf(context) ?? TextScaler.noScaling; + + /// Returns the [TextScaler] for the nearest [MediaQuery] ancestor or + /// [TextScaler.noScaling] if no such ancestor exists. + /// + /// Use of this method will cause the given [context] to rebuild any time that + /// the [MediaQueryData.textScaler] property of the ancestor [MediaQuery] + /// changes. + static TextScaler? maybeTextScalerOf(BuildContext context) => _maybeOf(context, _MediaQueryAspect.textScaler)?.textScaler; + /// Returns platformBrightness for the nearest MediaQuery ancestor or /// [Brightness.light], if no such ancestor exists. /// @@ -1407,6 +1572,10 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { if (data.textScaleFactor != oldWidget.data.textScaleFactor) { return true; } + case _MediaQueryAspect.textScaler: + if (data.textScaler != oldWidget.data.textScaler) { + return true; + } case _MediaQueryAspect.platformBrightness: if (data.platformBrightness != oldWidget.data.platformBrightness) { return true; @@ -1620,3 +1789,19 @@ class _MediaQueryFromViewState extends State<_MediaQueryFromView> with WidgetsBi ); } } + +const TextScaler _kUnspecifiedTextScaler = _UnspecifiedTextScaler(); +// TODO(LongCatIsLooong): Remove once `MediaQueryData.textScaleFactor` is +// removed: https://github.com/flutter/flutter/issues/128825. +class _UnspecifiedTextScaler implements TextScaler { + const _UnspecifiedTextScaler(); + + @override + TextScaler clamp({double minScaleFactor = 0, double maxScaleFactor = double.infinity}) => throw UnimplementedError(); + + @override + double scale(double fontSize) => throw UnimplementedError(); + + @override + double get textScaleFactor => throw UnimplementedError(); +} diff --git a/packages/flutter/lib/src/widgets/text.dart b/packages/flutter/lib/src/widgets/text.dart index 45111223b0639..b1870e1a94b1f 100644 --- a/packages/flutter/lib/src/widgets/text.dart +++ b/packages/flutter/lib/src/widgets/text.dart @@ -435,13 +435,23 @@ class Text extends StatelessWidget { this.locale, this.softWrap, this.overflow, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) this.textScaleFactor, + this.textScaler, this.maxLines, this.semanticsLabel, this.textWidthBasis, this.textHeightBehavior, this.selectionColor, - }) : textSpan = null; + }) : textSpan = null, + assert( + textScaler == null || textScaleFactor == null, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ); /// Creates a text widget with a [InlineSpan]. /// @@ -463,13 +473,23 @@ class Text extends StatelessWidget { this.locale, this.softWrap, this.overflow, + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) this.textScaleFactor, + this.textScaler, this.maxLines, this.semanticsLabel, this.textWidthBasis, this.textHeightBehavior, this.selectionColor, - }) : data = null; + }) : data = null, + assert( + textScaler == null || textScaleFactor == null, + 'textScaleFactor is deprecated and cannot be specified when textScaler is specified.', + ); /// The text to display. /// @@ -529,6 +549,9 @@ class Text extends StatelessWidget { /// from the nearest [DefaultTextStyle] ancestor will be used. final TextOverflow? overflow; + /// Deprecated. Will be removed in a future version of Flutter. Use + /// [textScaler] instead. + /// /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than @@ -537,8 +560,16 @@ class Text extends StatelessWidget { /// The value given to the constructor as textScaleFactor. If null, will /// use the [MediaQueryData.textScaleFactor] obtained from the ambient /// [MediaQuery], or 1.0 if there is no [MediaQuery] in scope. + @Deprecated( + 'Use textScaler instead. ' + 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. ' + 'This feature was deprecated after v3.12.0-2.0.pre.', + ) final double? textScaleFactor; + /// {@macro flutter.painting.textPainter.textScaler} + final TextScaler? textScaler; + /// An optional maximum number of lines for the text to span, wrapping if necessary. /// If the text exceeds the given number of lines, it will be truncated according /// to [overflow]. @@ -595,13 +626,20 @@ class Text extends StatelessWidget { effectiveTextStyle = effectiveTextStyle!.merge(const TextStyle(fontWeight: FontWeight.bold)); } final SelectionRegistrar? registrar = SelectionContainer.maybeOf(context); + final TextScaler textScaler = switch ((this.textScaler, textScaleFactor)) { + (final TextScaler textScaler, _) => textScaler, + // For unmigrated apps, fall back to textScaleFactor. + (null, final double textScaleFactor) => TextScaler.linear(textScaleFactor), + (null, null) => MediaQuery.textScalerOf(context), + }; + Widget result = RichText( textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start, textDirection: textDirection, // RichText uses Directionality.of to obtain a default if this is null. locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null softWrap: softWrap ?? defaultTextStyle.softWrap, overflow: overflow ?? effectiveTextStyle?.overflow ?? defaultTextStyle.overflow, - textScaleFactor: textScaleFactor ?? MediaQuery.textScaleFactorOf(context), + textScaler: textScaler, maxLines: maxLines ?? defaultTextStyle.maxLines, strutStyle: strutStyle, textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis, diff --git a/packages/flutter/lib/src/widgets/widget_span.dart b/packages/flutter/lib/src/widgets/widget_span.dart index 776d4087ceff2..34afb66f3a935 100644 --- a/packages/flutter/lib/src/widgets/widget_span.dart +++ b/packages/flutter/lib/src/widgets/widget_span.dart @@ -10,6 +10,8 @@ import 'package:flutter/rendering.dart'; import 'basic.dart'; import 'framework.dart'; +const double _kEngineDefaultFontSize = 14.0; + // Examples can assume: // late WidgetSpan myWidgetSpan; @@ -90,17 +92,28 @@ class WidgetSpan extends PlaceholderSpan { /// Helper function for extracting [WidgetSpan]s in preorder, from the given /// [InlineSpan] as a list of widgets. /// - /// The `textScaleFactor` is the the number of font pixels for each logical - /// pixel. + /// The `textScaler` is the scaling strategy for scaling the content. /// /// This function is used by [EditableText] and [RichText] so calling it /// directly is rarely necessary. - static List extractFromInlineSpan(InlineSpan span, double textScaleFactor) { + static List extractFromInlineSpan(InlineSpan span, TextScaler textScaler) { final List widgets = []; + // _kEngineDefaultFontSize is the default font size to use when none of the + // ancestor spans specifies one. + final List fontSizeStack = [_kEngineDefaultFontSize]; int index = 0; // This assumes an InlineSpan tree's logical order is equivalent to preorder. - span.visitChildren((InlineSpan span) { + bool visitSubtree(InlineSpan span) { + final double? fontSizeToPush = switch (span.style?.fontSize) { + final double size when size != fontSizeStack.last => size, + _ => null, + }; + if (fontSizeToPush != null) { + fontSizeStack.add(fontSizeToPush); + } if (span is WidgetSpan) { + final double fontSize = fontSizeStack.last; + final double textScaleFactor = fontSize == 0 ? 0 : textScaler.scale(fontSize) / fontSize; widgets.add( _WidgetSpanParentData( span: span, @@ -115,8 +128,15 @@ class WidgetSpan extends PlaceholderSpan { span is WidgetSpan || span is! PlaceholderSpan, '$span is a PlaceholderSpan but not a WidgetSpan subclass. This is currently not supported.', ); + span.visitDirectChildren(visitSubtree); + if (fontSizeToPush != null) { + final double poppedFontSize = fontSizeStack.removeLast(); + assert(fontSizeStack.isNotEmpty); + assert(poppedFontSize == fontSizeToPush); + } return true; - }); + } + visitSubtree(span); return widgets; } @@ -130,14 +150,17 @@ class WidgetSpan extends PlaceholderSpan { /// in-order mapping of widget to laid-out dimensions. If no such dimension /// is provided, the widget will be skipped. /// - /// The `textScaleFactor` will be applied to the laid-out size of the widget. + /// The `textScaler` will be applied to the laid-out size of the widget. @override - void build(ui.ParagraphBuilder builder, { double textScaleFactor = 1.0, List? dimensions }) { + void build(ui.ParagraphBuilder builder, { + TextScaler textScaler = TextScaler.noScaling, + List? dimensions, + }) { assert(debugAssertIsValid()); assert(dimensions != null); final bool hasStyle = style != null; if (hasStyle) { - builder.pushStyle(style!.getTextStyle(textScaleFactor: textScaleFactor)); + builder.pushStyle(style!.getTextStyle(textScaler: textScaler)); } assert(builder.placeholderCount < dimensions!.length); final PlaceholderDimensions currentDimensions = dimensions![builder.placeholderCount]; diff --git a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart index ed211846d60e2..1014b4137e80b 100644 --- a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart @@ -311,10 +311,10 @@ void main() { ); expect(barItems.length, greaterThan(0)); - expect(barItems.any((RichText t) => t.textScaleFactor != 1), isFalse); + expect(barItems, isNot(contains(predicate((RichText t) => t.textScaler != TextScaler.noScaling)))); expect(contents.length, greaterThan(0)); - expect(contents.any((RichText t) => t.textScaleFactor != 99), isFalse); + expect(contents, isNot(contains(predicate((RichText t) => t.textScaler != const TextScaler.linear(99.0))))); }); } diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index 9b7532afd0619..4f86b395d8f23 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -1230,10 +1230,10 @@ void main() { ); expect(barItems.length, greaterThan(0)); - expect(barItems.any((RichText t) => t.textScaleFactor != 1), isFalse); + expect(barItems, isNot(contains(predicate((RichText t) => t.textScaler != TextScaler.noScaling)))); expect(contents.length, greaterThan(0)); - expect(contents.any((RichText t) => t.textScaleFactor != 99), isFalse); + expect(contents, isNot(contains(predicate((RichText t) => t.textScaler != const TextScaler.linear(99.0))))); // Also works with implicitly added widgets. tester.state(find.byType(Navigator)).push(CupertinoPageRoute( diff --git a/packages/flutter/test/cupertino/scaffold_test.dart b/packages/flutter/test/cupertino/scaffold_test.dart index 41b40c07b1fd9..833c484f26cd9 100644 --- a/packages/flutter/test/cupertino/scaffold_test.dart +++ b/packages/flutter/test/cupertino/scaffold_test.dart @@ -554,6 +554,6 @@ void main() { expect(richTextList.length, greaterThan(0)); expect(richTextList.any((RichText text) => text.textScaleFactor != 1), isFalse); - expect(tester.widget(find.descendant(of: find.text('content'), matching: find.byType(RichText))).textScaleFactor, 99); + expect(tester.widget(find.descendant(of: find.text('content'), matching: find.byType(RichText))).textScaler, const TextScaler.linear(99.0)); }); } diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index 9e76489704ff4..a8a43b510277d 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -1106,10 +1106,10 @@ void main() { ); expect(barItems.length, greaterThan(0)); - expect(barItems.any((RichText t) => t.textScaleFactor != 1), isFalse); + expect(barItems, isNot(contains(predicate((RichText t) => t.textScaler != TextScaler.noScaling)))); expect(contents.length, greaterThan(0)); - expect(contents.any((RichText t) => t.textScaleFactor != 99), isFalse); + expect(contents, isNot(contains(predicate((RichText t) => t.textScaler != const TextScaler.linear(99.0))))); }); testWidgets('state restoration', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index b9234fbe602dd..ecdfd3d8021d9 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -1685,6 +1685,36 @@ void main() { expect(appBarHeight(tester), kToolbarHeight + 100.0); }); + testWidgets('AppBar.title sees the correct padding from MediaQuery', (WidgetTester tester) async { + bool titleBuilt = false; + await tester.pumpWidget( + Localizations( + locale: const Locale('en', 'US'), + delegates: const >[ + DefaultMaterialLocalizations.delegate, + DefaultWidgetsLocalizations.delegate, + ], + child: Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(padding: EdgeInsets.fromLTRB(12, 34, 56, 78)), + child: Scaffold( + appBar: AppBar( + title: Builder(builder: (BuildContext context) { + titleBuilt = true; + final EdgeInsets padding = MediaQuery.paddingOf(context); + expect(padding, EdgeInsets.zero); + return const Text('heh'); + }), + ), + ), + ), + ), + ), + ); + expect(titleBuilt, isTrue); + }); + testWidgets('AppBar updates when you add a drawer', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 734aa878be7a8..d4dad0cb59df0 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -465,15 +465,14 @@ void main() { }); testWidgets('Can get text scale from media query', (WidgetTester tester) async { - double? textScaleFactor; + TextScaler? textScaler; await tester.pumpWidget(MaterialApp( home: Builder(builder:(BuildContext context) { - textScaleFactor = MediaQuery.textScaleFactorOf(context); + textScaler = MediaQuery.textScalerOf(context); return Container(); }), )); - expect(textScaleFactor, isNotNull); - expect(textScaleFactor, equals(1.0)); + expect(textScaler, TextScaler.noScaling); }); testWidgets('MaterialApp.navigatorKey', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index 3a907941c33aa..1cbcbca3002bf 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -1140,6 +1140,7 @@ class _TextStyleProxy implements TextStyle { TextAlign? textAlign, TextDirection? textDirection, double textScaleFactor = 1.0, + TextScaler textScaler = TextScaler.noScaling, String? ellipsis, int? maxLines, ui.TextHeightBehavior? textHeightBehavior, @@ -1155,7 +1156,7 @@ class _TextStyleProxy implements TextStyle { } @override - ui.TextStyle getTextStyle({ double textScaleFactor = 1.0 }) { + ui.TextStyle getTextStyle({ double textScaleFactor = 1.0, TextScaler textScaler = TextScaler.noScaling }) { throw UnimplementedError(); } diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index f0b76fc0b9918..55c7ec50e09e2 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -400,27 +400,27 @@ void main() { painter.dispose(); }); - test('TextPainter textScaleFactor test', () { + test('TextPainter textScaler test', () { final TextPainter painter = TextPainter( text: const TextSpan( text: 'X', style: TextStyle(inherit: false, fontSize: 10.0), ), textDirection: TextDirection.ltr, - textScaleFactor: 2.0, + textScaler: const TextScaler.linear(2.0), ); painter.layout(); expect(painter.size, const Size(20.0, 20.0)); painter.dispose(); }); - test('TextPainter textScaleFactor null style test', () { + test('TextPainter textScaler null style test', () { final TextPainter painter = TextPainter( text: const TextSpan( text: 'X', ), textDirection: TextDirection.ltr, - textScaleFactor: 2.0, + textScaler: const TextScaler.linear(2.0), ); painter.layout(); expect(painter.size, const Size(28.0, 28.0)); diff --git a/packages/flutter/test/painting/text_scaler_test.dart b/packages/flutter/test/painting/text_scaler_test.dart new file mode 100644 index 0000000000000..6083f15ce2aef --- /dev/null +++ b/packages/flutter/test/painting/text_scaler_test.dart @@ -0,0 +1,37 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/painting.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('Linear TextScaler', () { + test('equality', () { + const TextScaler a = TextScaler.linear(3.0); + final TextScaler b = TextScaler.noScaling.clamp(minScaleFactor: 3.0); + // Creates a non-const TextScaler instance. + final TextScaler c = TextScaler.linear(3.0); // ignore: prefer_const_constructors + final TextScaler d = TextScaler.noScaling + .clamp(minScaleFactor: 1, maxScaleFactor: 5) + .clamp(minScaleFactor: 3, maxScaleFactor: 6); + + final List list = [a, b, c, d]; + for (final TextScaler lhs in list) { + expect(list, everyElement(lhs)); + } + }); + + test('clamping', () { + expect(TextScaler.noScaling.clamp(minScaleFactor: 3.0), const TextScaler.linear(3.0)); + expect(const TextScaler.linear(5.0).clamp(maxScaleFactor: 3.0), const TextScaler.linear(3.0)); + expect(const TextScaler.linear(5.0).clamp(maxScaleFactor: 3.0), const TextScaler.linear(3.0)); + expect(const TextScaler.linear(5.0).clamp(minScaleFactor: 3.0, maxScaleFactor: 3.0), const TextScaler.linear(3.0)); + // Asserts when min > max. + expect( + () => TextScaler.noScaling.clamp(minScaleFactor: 5.0, maxScaleFactor: 4.0), + throwsA(isA().having((AssertionError error) => error.toString(), 'message', contains('maxScaleFactor >= minScaleFactor'))), + ); + }); + }); +} diff --git a/packages/flutter/test/painting/text_style_test.dart b/packages/flutter/test/painting/text_style_test.dart index d2bd4c4b1ef65..1658eb59137e2 100644 --- a/packages/flutter/test/painting/text_style_test.dart +++ b/packages/flutter/test/painting/text_style_test.dart @@ -503,9 +503,9 @@ void main() { expect(TextStyle.lerp(redPaintTextStyle, bluePaintTextStyle, .75)!.background!.color, blue); }); - test('TextStyle strut textScaleFactor', () { + test('TextStyle strut textScaler', () { const TextStyle style0 = TextStyle(fontSize: 10); - final ui.ParagraphStyle paragraphStyle0 = style0.getParagraphStyle(textScaleFactor: 2.5); + final ui.ParagraphStyle paragraphStyle0 = style0.getParagraphStyle(textScaler: const TextScaler.linear(2.5)); const TextStyle style1 = TextStyle(fontSize: 25); final ui.ParagraphStyle paragraphStyle1 = style1.getParagraphStyle(); diff --git a/packages/flutter/test/painting/widget_span_test.dart b/packages/flutter/test/painting/widget_span_test.dart deleted file mode 100644 index 632920754e4cd..0000000000000 --- a/packages/flutter/test/painting/widget_span_test.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - test('WidgetSpan codeUnitAt', () { - const InlineSpan span = WidgetSpan(child: SizedBox()); - expect(span.codeUnitAt(-1), isNull); - expect(span.codeUnitAt(0), PlaceholderSpan.placeholderCodeUnit); - expect(span.codeUnitAt(1), isNull); - expect(span.codeUnitAt(2), isNull); - - const InlineSpan nestedSpan = TextSpan( - text: 'AAA', - children: [span, span], - ); - expect(nestedSpan.codeUnitAt(-1), isNull); - expect(nestedSpan.codeUnitAt(0), 65); - expect(nestedSpan.codeUnitAt(1), 65); - expect(nestedSpan.codeUnitAt(2), 65); - expect(nestedSpan.codeUnitAt(3), PlaceholderSpan.placeholderCodeUnit); - expect(nestedSpan.codeUnitAt(4), PlaceholderSpan.placeholderCodeUnit); - expect(nestedSpan.codeUnitAt(5), isNull); - }); -} diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index 0a31aa54e15ab..118f1adbf694b 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -230,7 +230,6 @@ void main() { ' │ maxLines: 1\n' ' │ minLines: null\n' ' │ selectionColor: null\n' - ' │ textScaleFactor: 1.0\n' ' │ locale: ja_JP\n' ' │ selection: null\n' ' │ offset: _FixedViewportOffset#00000(offset: 0.0)\n' @@ -331,7 +330,7 @@ void main() { ), )); - editable.textScaleFactor = 2; + editable.textScaler = const TextScaler.linear(2.0); pumpFrame(phase: EnginePhase.compositingBits); // Now the caret height is much bigger due to the bigger font scale. @@ -454,7 +453,7 @@ void main() { ), )); - editable.textScaleFactor = 2; + editable.textScaler = const TextScaler.linear(2.0); pumpFrame(phase: EnginePhase.compositingBits); // Now the caret height is much bigger due to the bigger font scale. @@ -1631,7 +1630,7 @@ void main() { selection: const TextSelection.collapsed(offset: 3), maxLines: 2, minLines: 2, - textScaleFactor: 2.0, + textScaler: const TextScaler.linear(2.0), children: renderBoxes, ); _applyParentData(renderBoxes, editable.text!); diff --git a/packages/flutter/test/rendering/paragraph_test.dart b/packages/flutter/test/rendering/paragraph_test.dart index 8ae7c59ec126e..f7d8eba8c2e4b 100644 --- a/packages/flutter/test/rendering/paragraph_test.dart +++ b/packages/flutter/test/rendering/paragraph_test.dart @@ -406,7 +406,7 @@ void main() { expect(paragraph.debugNeedsPaint, isFalse); }); - test('nested TextSpans in paragraph handle textScaleFactor correctly.', () { + test('nested TextSpans in paragraph handle linear textScaler correctly.', () { const TextSpan testSpan = TextSpan( text: 'a', style: TextStyle( @@ -430,7 +430,7 @@ void main() { final RenderParagraph paragraph = RenderParagraph( testSpan, textDirection: TextDirection.ltr, - textScaleFactor: 1.3, + textScaler: const TextScaler.linear(1.3), ); paragraph.layout(const BoxConstraints()); expect(paragraph.size.width, 78.0); diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 2a24e45ca0726..38793a39489ff 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -181,7 +181,7 @@ void main() { expect(data.hashCode, data.copyWith().hashCode); expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.devicePixelRatio, tester.view.devicePixelRatio); - expect(data.textScaleFactor, platformData.textScaleFactor); + expect(data.textScaler, TextScaler.linear(platformData.textScaleFactor)); expect(data.platformBrightness, platformData.platformBrightness); expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); @@ -211,7 +211,7 @@ void main() { expect(data.hashCode, data.copyWith().hashCode); expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.devicePixelRatio, tester.view.devicePixelRatio); - expect(data.textScaleFactor, tester.platformDispatcher.textScaleFactor); + expect(data.textScaler, TextScaler.linear(tester.platformDispatcher.textScaleFactor)); expect(data.platformBrightness, tester.platformDispatcher.platformBrightness); expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); @@ -260,7 +260,7 @@ void main() { expect(data, isNot(platformData)); expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.devicePixelRatio, tester.view.devicePixelRatio); - expect(data.textScaleFactor, platformData.textScaleFactor); + expect(data.textScaler, TextScaler.linear(platformData.textScaleFactor)); expect(data.platformBrightness, platformData.platformBrightness); expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); @@ -311,7 +311,7 @@ void main() { expect(outerData, isNull); expect(data.size, tester.view.physicalSize / tester.view.devicePixelRatio); expect(data.devicePixelRatio, tester.view.devicePixelRatio); - expect(data.textScaleFactor, tester.platformDispatcher.textScaleFactor); + expect(data.textScaler, TextScaler.linear(tester.platformDispatcher.textScaleFactor)); expect(data.platformBrightness, tester.platformDispatcher.platformBrightness); expect(data.padding, EdgeInsets.fromViewPadding(tester.view.padding, tester.view.devicePixelRatio)); expect(data.viewPadding, EdgeInsets.fromViewPadding(tester.view.viewPadding, tester.view.devicePixelRatio)); @@ -367,10 +367,10 @@ void main() { expect(outerData, isNull); expect(rebuildCount, 1); - expect(data.textScaleFactor, 123); + expect(data.textScaler, const TextScaler.linear(123)); tester.platformDispatcher.textScaleFactorTestValue = 456; await tester.pump(); - expect(data.textScaleFactor, 456); + expect(data.textScaler, const TextScaler.linear(456)); expect(rebuildCount, 2); expect(data.platformBrightness, Brightness.dark); @@ -407,7 +407,7 @@ void main() { await tester.pumpWidget( MediaQuery( data: const MediaQueryData( - textScaleFactor: 44, + textScaler: TextScaler.linear(44), platformBrightness: Brightness.dark, accessibleNavigation: true, ), @@ -426,10 +426,10 @@ void main() { expect(rebuildCount, 1); - expect(data.textScaleFactor, 44); + expect(data.textScaler, const TextScaler.linear(44)); tester.platformDispatcher.textScaleFactorTestValue = 456; await tester.pump(); - expect(data.textScaleFactor, 44); + expect(data.textScaler, const TextScaler.linear(44)); expect(rebuildCount, 1); expect(data.platformBrightness, Brightness.dark); @@ -454,14 +454,14 @@ void main() { testWidgets('MediaQuery.fromView updates when parent data changes', (WidgetTester tester) async { late MediaQueryData data; int rebuildCount = 0; - double textScaleFactor = 55; + TextScaler textScaler = const TextScaler.linear(55); late StateSetter stateSetter; await tester.pumpWidget( StatefulBuilder( builder: (BuildContext context, StateSetter setState) { stateSetter = setState; return MediaQuery( - data: MediaQueryData(textScaleFactor: textScaleFactor), + data: MediaQueryData(textScaler: textScaler), child: MediaQuery.fromView( view: tester.view, child: Builder( @@ -478,13 +478,13 @@ void main() { ); expect(rebuildCount, 1); - expect(data.textScaleFactor, 55); + expect(data.textScaler, const TextScaler.linear(55)); stateSetter(() { - textScaleFactor = 66; + textScaler = const TextScaler.linear(66); }); await tester.pump(); - expect(data.textScaleFactor, 66); + expect(data.textScaler, const TextScaler.linear(66)); expect(rebuildCount, 2); }); @@ -493,7 +493,7 @@ void main() { final MediaQueryData copied = data.copyWith(); expect(copied.size, data.size); expect(copied.devicePixelRatio, data.devicePixelRatio); - expect(copied.textScaleFactor, data.textScaleFactor); + expect(copied.textScaler, data.textScaler); expect(copied.padding, data.padding); expect(copied.viewPadding, data.viewPadding); expect(copied.viewInsets, data.viewInsets); @@ -515,7 +515,7 @@ void main() { // values are copied over exactly const Size customSize = Size(3.14, 2.72); const double customDevicePixelRatio = 1.41; - const double customTextScaleFactor = 1.62; + const TextScaler customTextScaler = TextScaler.linear(1.23); const EdgeInsets customPadding = EdgeInsets.all(9.10938); const EdgeInsets customViewPadding = EdgeInsets.all(11.24031); const EdgeInsets customViewInsets = EdgeInsets.all(1.67262); @@ -533,7 +533,7 @@ void main() { final MediaQueryData copied = data.copyWith( size: customSize, devicePixelRatio: customDevicePixelRatio, - textScaleFactor: customTextScaleFactor, + textScaler: customTextScaler, padding: customPadding, viewPadding: customViewPadding, viewInsets: customViewInsets, @@ -552,7 +552,7 @@ void main() { ); expect(copied.size, customSize); expect(copied.devicePixelRatio, customDevicePixelRatio); - expect(copied.textScaleFactor, customTextScaleFactor); + expect(copied.textScaler, customTextScaler); expect(copied.padding, customPadding); expect(copied.viewPadding, customViewPadding); expect(copied.viewInsets, customViewInsets); @@ -573,7 +573,7 @@ void main() { testWidgets('MediaQuery.removePadding removes specified padding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); @@ -591,7 +591,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -627,7 +627,7 @@ void main() { expect(unpadded.size, size); expect(unpadded.devicePixelRatio, devicePixelRatio); - expect(unpadded.textScaleFactor, textScaleFactor); + expect(unpadded.textScaler, textScaler); expect(unpadded.padding, EdgeInsets.zero); expect(unpadded.viewPadding, viewInsets); expect(unpadded.viewInsets, viewInsets); @@ -645,7 +645,7 @@ void main() { testWidgets('MediaQuery.removePadding only removes specified padding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); @@ -663,7 +663,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -696,7 +696,7 @@ void main() { expect(unpadded.size, size); expect(unpadded.devicePixelRatio, devicePixelRatio); - expect(unpadded.textScaleFactor, textScaleFactor); + expect(unpadded.textScaler, textScaler); expect(unpadded.padding, padding.copyWith(top: 0)); expect(unpadded.viewPadding, viewPadding.copyWith(top: viewInsets.top)); expect(unpadded.viewInsets, viewInsets); @@ -714,7 +714,7 @@ void main() { testWidgets('MediaQuery.removeViewInsets removes specified viewInsets', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); @@ -732,7 +732,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -768,7 +768,7 @@ void main() { expect(unpadded.size, size); expect(unpadded.devicePixelRatio, devicePixelRatio); - expect(unpadded.textScaleFactor, textScaleFactor); + expect(unpadded.textScaler, textScaler); expect(unpadded.padding, padding); expect(unpadded.viewPadding, padding); expect(unpadded.viewInsets, EdgeInsets.zero); @@ -786,7 +786,7 @@ void main() { testWidgets('MediaQuery.removeViewInsets removes only specified viewInsets', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); @@ -804,7 +804,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -837,7 +837,7 @@ void main() { expect(unpadded.size, size); expect(unpadded.devicePixelRatio, devicePixelRatio); - expect(unpadded.textScaleFactor, textScaleFactor); + expect(unpadded.textScaler, textScaler); expect(unpadded.padding, padding); expect(unpadded.viewPadding, viewPadding.copyWith(bottom: 8)); expect(unpadded.viewInsets, viewInsets.copyWith(bottom: 0)); @@ -855,7 +855,7 @@ void main() { testWidgets('MediaQuery.removeViewPadding removes specified viewPadding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); @@ -873,7 +873,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -909,7 +909,7 @@ void main() { expect(unpadded.size, size); expect(unpadded.devicePixelRatio, devicePixelRatio); - expect(unpadded.textScaleFactor, textScaleFactor); + expect(unpadded.textScaler, textScaler); expect(unpadded.padding, EdgeInsets.zero); expect(unpadded.viewPadding, EdgeInsets.zero); expect(unpadded.viewInsets, viewInsets); @@ -927,7 +927,7 @@ void main() { testWidgets('MediaQuery.removeViewPadding removes only specified viewPadding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); @@ -945,7 +945,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -978,7 +978,7 @@ void main() { expect(unpadded.size, size); expect(unpadded.devicePixelRatio, devicePixelRatio); - expect(unpadded.textScaleFactor, textScaleFactor); + expect(unpadded.textScaler, textScaler); expect(unpadded.padding, padding.copyWith(left: 0)); expect(unpadded.viewPadding, viewPadding.copyWith(left: 0)); expect(unpadded.viewInsets, viewInsets); @@ -993,21 +993,21 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.textScaleFactorOf', (WidgetTester tester) async { - late double outsideTextScaleFactor; - late double insideTextScaleFactor; + testWidgets('MediaQuery.textScalerOf', (WidgetTester tester) async { + late TextScaler outsideTextScaler; + late TextScaler insideTextScaler; await tester.pumpWidget( Builder( builder: (BuildContext context) { - outsideTextScaleFactor = MediaQuery.textScaleFactorOf(context); + outsideTextScaler = MediaQuery.textScalerOf(context); return MediaQuery( data: const MediaQueryData( - textScaleFactor: 4.0, + textScaler: TextScaler.linear(4.0), ), child: Builder( builder: (BuildContext context) { - insideTextScaleFactor = MediaQuery.textScaleFactorOf(context); + insideTextScaler = MediaQuery.textScalerOf(context); return Container(); }, ), @@ -1016,8 +1016,8 @@ void main() { ), ); - expect(outsideTextScaleFactor, 1.0); - expect(insideTextScaleFactor, 4.0); + expect(outsideTextScaler, TextScaler.noScaling); + expect(insideTextScaler, const TextScaler.linear(4.0)); }); testWidgets('MediaQuery.platformBrightnessOf', (WidgetTester tester) async { @@ -1192,7 +1192,7 @@ void main() { testWidgets('MediaQuery.removeDisplayFeatures removes specified display features and padding', (WidgetTester tester) async { const Size size = Size(82.0, 40.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 10.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); @@ -1218,7 +1218,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -1249,7 +1249,7 @@ void main() { expect(subScreenMediaQuery.size, size); expect(subScreenMediaQuery.devicePixelRatio, devicePixelRatio); - expect(subScreenMediaQuery.textScaleFactor, textScaleFactor); + expect(subScreenMediaQuery.textScaler, textScaler); expect(subScreenMediaQuery.padding, EdgeInsets.zero); expect(subScreenMediaQuery.viewPadding, EdgeInsets.zero); expect(subScreenMediaQuery.viewInsets, EdgeInsets.zero); @@ -1266,7 +1266,7 @@ void main() { testWidgets('MediaQuery.removePadding only removes specified display features and padding', (WidgetTester tester) async { const Size size = Size(82.0, 40.0); const double devicePixelRatio = 2.0; - const double textScaleFactor = 1.2; + const TextScaler textScaler = TextScaler.linear(1.2); const EdgeInsets padding = EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0); const EdgeInsets viewPadding = EdgeInsets.only(top: 6.0, right: 8.0, left: 46.0, bottom: 12.0); const EdgeInsets viewInsets = EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0); @@ -1293,7 +1293,7 @@ void main() { data: const MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, - textScaleFactor: textScaleFactor, + textScaler: textScaler, padding: padding, viewPadding: viewPadding, viewInsets: viewInsets, @@ -1324,7 +1324,7 @@ void main() { expect(subScreenMediaQuery.size, size); expect(subScreenMediaQuery.devicePixelRatio, devicePixelRatio); - expect(subScreenMediaQuery.textScaleFactor, textScaleFactor); + expect(subScreenMediaQuery.textScaler, textScaler); expect( subScreenMediaQuery.padding, const EdgeInsets.only(top: 1.0, right: 2.0, bottom: 4.0), @@ -1357,11 +1357,11 @@ void main() { testWidgets('MediaQuery can be partially depended-on', (WidgetTester tester) async { MediaQueryData data = const MediaQueryData( size: Size(800, 600), - textScaleFactor: 1.1 + textScaler: TextScaler.linear(1.1), ); int sizeBuildCount = 0; - int textScaleFactorBuildCount = 0; + int textScalerBuildCount = 0; final Widget showSize = Builder( builder: (BuildContext context) { @@ -1370,10 +1370,10 @@ void main() { } ); - final Widget showTextScaleFactor = Builder( + final Widget showTextScaler = Builder( builder: (BuildContext context) { - textScaleFactorBuildCount++; - return Text('textScaleFactor: ${MediaQuery.textScaleFactorOf(context).toStringAsFixed(1)}'); + textScalerBuildCount++; + return Text('textScaler: ${MediaQuery.textScalerOf(context)}'); } ); @@ -1385,7 +1385,7 @@ void main() { child: Column( children: [ showSize, - showTextScaleFactor, + showTextScaler, ElevatedButton( onPressed: () { setState(() { @@ -1397,10 +1397,10 @@ void main() { ElevatedButton( onPressed: () { setState(() { - data = data.copyWith(textScaleFactor: data.textScaleFactor + 0.1); + data = data.copyWith(textScaler: TextScaler.noScaling); }); }, - child: const Text('Increase textScaleFactor by 0.1') + child: const Text('Disable text scaling') ) ] ) @@ -1411,23 +1411,23 @@ void main() { await tester.pumpWidget(MaterialApp(home: page)); expect(find.text('size: Size(800.0, 600.0)'), findsOneWidget); - expect(find.text('textScaleFactor: 1.1'), findsOneWidget); + expect(find.text('textScaler: linear (1.1x)'), findsOneWidget); expect(sizeBuildCount, 1); - expect(textScaleFactorBuildCount, 1); + expect(textScalerBuildCount, 1); await tester.tap(find.text('Increase width by 100')); await tester.pumpAndSettle(); expect(find.text('size: Size(900.0, 600.0)'), findsOneWidget); - expect(find.text('textScaleFactor: 1.1'), findsOneWidget); + expect(find.text('textScaler: linear (1.1x)'), findsOneWidget); expect(sizeBuildCount, 2); - expect(textScaleFactorBuildCount, 1); + expect(textScalerBuildCount, 1); - await tester.tap(find.text('Increase textScaleFactor by 0.1')); + await tester.tap(find.text('Disable text scaling')); await tester.pumpAndSettle(); expect(find.text('size: Size(900.0, 600.0)'), findsOneWidget); - expect(find.text('textScaleFactor: 1.2'), findsOneWidget); + expect(find.text('textScaler: no scaling'), findsOneWidget); expect(sizeBuildCount, 2); - expect(textScaleFactorBuildCount, 2); + expect(textScalerBuildCount, 2); }); testWidgets('MediaQuery partial dependencies', (WidgetTester tester) async { @@ -1496,6 +1496,8 @@ void main() { const _MediaQueryAspectCase(MediaQuery.maybeDevicePixelRatioOf, MediaQueryData(devicePixelRatio: 1.1)), const _MediaQueryAspectCase(MediaQuery.textScaleFactorOf, MediaQueryData(textScaleFactor: 1.1)), const _MediaQueryAspectCase(MediaQuery.maybeTextScaleFactorOf, MediaQueryData(textScaleFactor: 1.1)), + const _MediaQueryAspectCase(MediaQuery.textScalerOf, MediaQueryData(textScaler: TextScaler.linear(1.1))), + const _MediaQueryAspectCase(MediaQuery.maybeTextScalerOf, MediaQueryData(textScaler: TextScaler.linear(1.1))), const _MediaQueryAspectCase(MediaQuery.platformBrightnessOf, MediaQueryData(platformBrightness: Brightness.dark)), const _MediaQueryAspectCase(MediaQuery.maybePlatformBrightnessOf, MediaQueryData(platformBrightness: Brightness.dark)), const _MediaQueryAspectCase(MediaQuery.paddingOf, MediaQueryData(padding: EdgeInsets.all(1))), diff --git a/packages/flutter/test/widgets/rich_text_test.dart b/packages/flutter/test/widgets/rich_text_test.dart index e8c83eea5b6b9..474854c22e960 100644 --- a/packages/flutter/test/widgets/rich_text_test.dart +++ b/packages/flutter/test/widgets/rich_text_test.dart @@ -193,12 +193,12 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect(description, unorderedMatches([ + expect(description, unorderedMatches([ contains('textAlign: center'), contains('textDirection: rtl'), contains('softWrap: no wrapping except at line break characters'), contains('overflow: ellipsis'), - contains('textScaleFactor: 1.3'), + contains('textScaler: linear (1.3x)'), contains('maxLines: 1'), contains('textWidthBasis: longestLine'), contains('text: "rich text"'), diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 34099ff2e0510..033d5c2f451a8 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -4094,7 +4094,7 @@ void main() { style: TextStyle(color: Color(0xff00ff00)), textAlign: TextAlign.end, textDirection: TextDirection.ltr, - textScaleFactor: 1.0, + textScaler: TextScaler.noScaling, autofocus: true, showCursor: true, minLines: 2, @@ -4122,7 +4122,7 @@ void main() { 'maxLines: 10', 'textAlign: end', 'textDirection: ltr', - 'textScaleFactor: 1.0', + 'textScaler: no scaling', 'cursorWidth: 1.0', 'cursorHeight: 1.0', 'cursorRadius: Radius.circular(0.0)', diff --git a/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart b/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart new file mode 100644 index 0000000000000..c38c3f617fd38 --- /dev/null +++ b/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart @@ -0,0 +1,278 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// TODO(LongCatIsLooong): Remove this file once textScaleFactor is removed. +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('TextStyle', () { + test('getTextSyle is backward compatible', () { + expect( + const TextStyle(fontSize: 14).getTextStyle(textScaleFactor: 2.0).toString(), + contains('fontSize: 28'), + ); + }, skip: kIsWeb); // [intended] CkTextStyle doesn't have a custom toString implementation. + }); + group('TextPainter', () { + test('textScaleFactor translates to textScaler', () { + final TextPainter textPainter = TextPainter( + text: const TextSpan(text: 'text'), + textDirection: TextDirection.ltr, + textScaleFactor: 42, + ); + + expect(textPainter.textScaler, const TextScaler.linear(42.0)); + + // Linear TextScaler translates to textScaleFactor. + textPainter.textScaler = const TextScaler.linear(12.0); + expect(textPainter.textScaleFactor, 12.0); + + textPainter.textScaleFactor = 10; + expect(textPainter.textScaler, const TextScaler.linear(10)); + }); + }); + + group('MediaQuery', () { + test('specifying both textScaler and textScalingFactor asserts', () { + expect( + () => MediaQueryData(textScaleFactor: 2, textScaler: const TextScaler.linear(2.0)), + throwsAssertionError, + ); + }); + + test('copyWith is backward compatible', () { + const MediaQueryData data = MediaQueryData(textScaler: TextScaler.linear(2.0)); + + final MediaQueryData data1 = data.copyWith(textScaleFactor: 42); + expect(data1.textScaler, const TextScaler.linear(42)); + expect(data1.textScaleFactor, 42); + + final MediaQueryData data2 = data.copyWith(textScaler: TextScaler.noScaling); + expect(data2.textScaler, TextScaler.noScaling); + expect(data2.textScaleFactor, 1.0); + }); + + test('copyWith specifying both textScaler and textScalingFactor asserts', () { + const MediaQueryData data = MediaQueryData(); + expect( + () => data.copyWith(textScaleFactor: 2, textScaler: const TextScaler.linear(2.0)), + throwsAssertionError, + ); + }); + + testWidgets('MediaQuery.textScaleFactorOf overriding compatibility', (WidgetTester tester) async { + late final double outsideTextScaleFactor; + late final TextScaler outsideTextScaler; + late final double insideTextScaleFactor; + late final TextScaler insideTextScaler; + + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + outsideTextScaleFactor = MediaQuery.textScaleFactorOf(context); + outsideTextScaler = MediaQuery.textScalerOf(context); + return MediaQuery( + data: const MediaQueryData( + textScaleFactor: 4.0, + ), + child: Builder( + builder: (BuildContext context) { + insideTextScaleFactor = MediaQuery.textScaleFactorOf(context); + insideTextScaler = MediaQuery.textScalerOf(context); + return Container(); + }, + ), + ); + }, + ), + ); + + // Overriding textScaleFactor should work for unmigrated widgets that are + // still using MediaQuery.textScaleFactorOf. Also if a unmigrated widget + // overrides MediaQuery.textScaleFactor, migrated widgets in the subtree + // should get the correct TextScaler. + expect(outsideTextScaleFactor, 1.0); + expect(outsideTextScaler.textScaleFactor, 1.0); + expect(outsideTextScaler, TextScaler.noScaling); + expect(insideTextScaleFactor, 4.0); + expect(insideTextScaler.textScaleFactor, 4.0); + expect(insideTextScaler, const TextScaler.linear(4.0)); + }); + + testWidgets('textScaleFactor overriding backward compatibility', (WidgetTester tester) async { + late final double outsideTextScaleFactor; + late final TextScaler outsideTextScaler; + late final double insideTextScaleFactor; + late final TextScaler insideTextScaler; + + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + outsideTextScaleFactor = MediaQuery.textScaleFactorOf(context); + outsideTextScaler = MediaQuery.textScalerOf(context); + return MediaQuery( + data: const MediaQueryData(textScaler: TextScaler.linear(4.0)), + child: Builder( + builder: (BuildContext context) { + insideTextScaleFactor = MediaQuery.textScaleFactorOf(context); + insideTextScaler = MediaQuery.textScalerOf(context); + return Container(); + }, + ), + ); + }, + ), + ); + + expect(outsideTextScaleFactor, 1.0); + expect(outsideTextScaler.textScaleFactor, 1.0); + expect(outsideTextScaler, TextScaler.noScaling); + expect(insideTextScaleFactor, 4.0); + expect(insideTextScaler.textScaleFactor, 4.0); + expect(insideTextScaler, const TextScaler.linear(4.0)); + }); + }); + + group('RenderObjects backward compatibility', () { + test('RenderEditable', () { + final RenderEditable renderObject = RenderEditable( + backgroundCursorColor: const Color.fromARGB(0xFF, 0xFF, 0x00, 0x00), + textDirection: TextDirection.ltr, + cursorColor: const Color.fromARGB(0xFF, 0xFF, 0x00, 0x00), + offset: ViewportOffset.zero(), + textSelectionDelegate: _FakeEditableTextState(), + text: const TextSpan( + text: 'test', + style: TextStyle(height: 1.0, fontSize: 10.0), + ), + startHandleLayerLink: LayerLink(), + endHandleLayerLink: LayerLink(), + selection: const TextSelection.collapsed(offset: 0), + ); + expect(renderObject.textScaleFactor, 1.0); + + renderObject.textScaleFactor = 3.0; + expect(renderObject.textScaleFactor, 3.0); + expect(renderObject.textScaler, const TextScaler.linear(3.0)); + + renderObject.textScaler = const TextScaler.linear(4.0); + expect(renderObject.textScaleFactor, 4.0); + }); + + test('RenderParagraph', () { + final RenderParagraph renderObject = RenderParagraph( + const TextSpan( + text: 'test', + style: TextStyle(height: 1.0, fontSize: 10.0), + ), + textDirection: TextDirection.ltr, + ); + expect(renderObject.textScaleFactor, 1.0); + + renderObject.textScaleFactor = 3.0; + expect(renderObject.textScaleFactor, 3.0); + expect(renderObject.textScaler, const TextScaler.linear(3.0)); + + renderObject.textScaler = const TextScaler.linear(4.0); + expect(renderObject.textScaleFactor, 4.0); + }); + }); + + group('Widgets backward compatibility', () { + testWidgets('RichText', (WidgetTester tester) async { + await tester.pumpWidget( + RichText( + textDirection: TextDirection.ltr, + text: const TextSpan(), + textScaleFactor: 2.0, + ), + ); + + expect( + tester.renderObject(find.byType(RichText)).textScaler, + const TextScaler.linear(2.0), + ); + expect(tester.renderObject(find.byType(RichText)).textScaleFactor, 2.0); + }); + + testWidgets('Text', (WidgetTester tester) async { + await tester.pumpWidget( + const Text( + 'text', + textDirection: TextDirection.ltr, + textScaleFactor: 2.0, + ), + ); + + expect( + tester.renderObject(find.text('text')).textScaler, + const TextScaler.linear(2.0), + ); + }); + + testWidgets('EditableText', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(); + final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Node'); + const TextStyle textStyle = TextStyle(); + const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00); + await tester.pumpWidget( + MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.rtl, + child: EditableText( + backgroundCursorColor: cursorColor, + controller: controller, + focusNode: focusNode, + style: textStyle, + cursorColor: cursorColor, + textScaleFactor: 2.0, + ), + ), + ), + ); + + final RenderEditable renderEditable = tester.allRenderObjects.whereType().first; + expect( + renderEditable.textScaler, + const TextScaler.linear(2.0), + ); + }); + }); +} + +class _FakeEditableTextState with TextSelectionDelegate { + @override + TextEditingValue textEditingValue = TextEditingValue.empty; + + TextSelection? selection; + + @override + void hideToolbar([bool hideHandles = true]) { } + + @override + void userUpdateTextEditingValue(TextEditingValue value, SelectionChangedCause cause) { + selection = value.selection; + } + + @override + void bringIntoView(TextPosition position) { } + + @override + void cutSelection(SelectionChangedCause cause) { } + + @override + Future pasteText(SelectionChangedCause cause) { + return Future.value(); + } + + @override + void selectAll(SelectionChangedCause cause) { } + + @override + void copySelection(SelectionChangedCause cause) { } +} diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index 0289a64d20b0c..c535fbd9c52de 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -24,7 +24,7 @@ void main() { RichText text = tester.firstWidget(find.byType(RichText)); expect(text, isNotNull); - expect(text.textScaleFactor, 1.3); + expect(text.textScaler, const TextScaler.linear(1.3)); await tester.pumpWidget(const Center( child: Text('Hello', textDirection: TextDirection.ltr), @@ -32,7 +32,7 @@ void main() { text = tester.firstWidget(find.byType(RichText)); expect(text, isNotNull); - expect(text.textScaleFactor, 1.0); + expect(text.textScaler, TextScaler.noScaling); }); testWidgets('Text respects textScaleFactor with default font size', (WidgetTester tester) async { @@ -42,7 +42,7 @@ void main() { RichText text = tester.firstWidget(find.byType(RichText)); expect(text, isNotNull); - expect(text.textScaleFactor, 1.0); + expect(text.textScaler, TextScaler.noScaling); final Size baseSize = tester.getSize(find.byType(RichText)); expect(baseSize.width, equals(70.0)); expect(baseSize.height, equals(14.0)); @@ -57,7 +57,7 @@ void main() { text = tester.firstWidget(find.byType(RichText)); expect(text, isNotNull); - expect(text.textScaleFactor, 1.5); + expect(text.textScaler, const TextScaler.linear(1.5)); final Size largeSize = tester.getSize(find.byType(RichText)); expect(largeSize.width, 105.0); expect(largeSize.height, equals(21.0)); @@ -74,7 +74,7 @@ void main() { RichText text = tester.firstWidget(find.byType(RichText)); expect(text, isNotNull); - expect(text.textScaleFactor, 1.0); + expect(text.textScaler, TextScaler.noScaling); final Size baseSize = tester.getSize(find.byType(RichText)); expect(baseSize.width, equals(100.0)); expect(baseSize.height, equals(20.0)); @@ -90,7 +90,7 @@ void main() { text = tester.firstWidget(find.byType(RichText)); expect(text, isNotNull); - expect(text.textScaleFactor, 1.3); + expect(text.textScaler, const TextScaler.linear(1.3)); final Size largeSize = tester.getSize(find.byType(RichText)); expect(largeSize.width, 130.0); expect(largeSize.height, equals(26.0)); diff --git a/packages/flutter/test/widgets/widget_span_test.dart b/packages/flutter/test/widgets/widget_span_test.dart new file mode 100644 index 0000000000000..d903ab567e972 --- /dev/null +++ b/packages/flutter/test/widgets/widget_span_test.dart @@ -0,0 +1,77 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('WidgetSpan codeUnitAt', () { + const InlineSpan span = WidgetSpan(child: SizedBox()); + expect(span.codeUnitAt(-1), isNull); + expect(span.codeUnitAt(0), PlaceholderSpan.placeholderCodeUnit); + expect(span.codeUnitAt(1), isNull); + expect(span.codeUnitAt(2), isNull); + + const InlineSpan nestedSpan = TextSpan( + text: 'AAA', + children: [span, span], + ); + expect(nestedSpan.codeUnitAt(-1), isNull); + expect(nestedSpan.codeUnitAt(0), 65); + expect(nestedSpan.codeUnitAt(1), 65); + expect(nestedSpan.codeUnitAt(2), 65); + expect(nestedSpan.codeUnitAt(3), PlaceholderSpan.placeholderCodeUnit); + expect(nestedSpan.codeUnitAt(4), PlaceholderSpan.placeholderCodeUnit); + expect(nestedSpan.codeUnitAt(5), isNull); + }); + + test('WidgetSpan.extractFromInlineSpan applies the correct scaling factor', () { + const WidgetSpan a = WidgetSpan(child: SizedBox(), style: TextStyle(fontSize: 0)); + const WidgetSpan b = WidgetSpan(child: SizedBox(), style: TextStyle(fontSize: 10)); + const WidgetSpan c = WidgetSpan(child: SizedBox()); + const WidgetSpan d = WidgetSpan(child: SizedBox(), style: TextStyle(letterSpacing: 999)); + + const TextSpan span = TextSpan( + children: [ + a, // fontSize = 0. + TextSpan( + children: [ + b, // fontSize = 10. + c, // fontSize = 20. + ], + style: TextStyle(fontSize: 20), + ), + d, // fontSize = 14. + ] + ); + + double effectiveTextScaleFactorFromWidget(Widget widget) { + final Semantics child = (widget as ProxyWidget).child as Semantics; + final dynamic grandChild = child.child; + final double textScaleFactor = grandChild.textScaleFactor as double; // ignore: avoid_dynamic_calls + return textScaleFactor; + } + + final List textScaleFactors = WidgetSpan.extractFromInlineSpan(span, const _QuadraticScaler()) + .map(effectiveTextScaleFactorFromWidget).toList(); + + expect(textScaleFactors, [ + 0, // a + 10, // b + 20, // c + 14, // d + ]); + }); +} + + +class _QuadraticScaler extends TextScaler { + const _QuadraticScaler(); + + @override + double scale(double fontSize) => fontSize * fontSize; + + @override + double get textScaleFactor => throw UnimplementedError(); +} diff --git a/packages/flutter/test_fixes/painting/painting.dart b/packages/flutter/test_fixes/painting/painting.dart index 625a0e701d179..2f2669f3557bf 100644 --- a/packages/flutter/test_fixes/painting/painting.dart +++ b/packages/flutter/test_fixes/painting/painting.dart @@ -7,4 +7,15 @@ import 'package:flutter/painting.dart'; void main() { // Change made in https://github.com/flutter/flutter/pull/121152 final EdgeInsets insets = EdgeInsets.fromWindowPadding(ViewPadding.zero, 3.0); + + // Change made in https://github.com/flutter/flutter/pull/128522 + const TextStyle textStyle = TextStyle() + ..getTextStyle(textScaleFactor: math.min(_kTextScaleFactor, 1.0)) + ..getTextStyle(); + + TextPainter(text: inlineSpan); + TextPainter(textScaleFactor: someValue); + + TextPainter.computeWidth(textScaleFactor: textScaleFactor); + TextPainter.computeMaxIntrinsicWidth(textScaleFactor: textScaleFactor); } diff --git a/packages/flutter/test_fixes/painting/painting.dart.expect b/packages/flutter/test_fixes/painting/painting.dart.expect index 245193c8538d2..249f3dac39330 100644 --- a/packages/flutter/test_fixes/painting/painting.dart.expect +++ b/packages/flutter/test_fixes/painting/painting.dart.expect @@ -7,4 +7,15 @@ import 'package:flutter/painting.dart'; void main() { // Change made in https://github.com/flutter/flutter/pull/121152 final EdgeInsets insets = EdgeInsets.fromViewPadding(ViewPadding.zero, 3.0); + + // Change made in https://github.com/flutter/flutter/pull/128522 + const TextStyle textStyle = TextStyle() + ..getTextStyle(textScaler: TextScaler.linear(math.min(_kTextScaleFactor, 1.0))) + ..getTextStyle(); + + TextPainter(text: inlineSpan); + TextPainter(textScaler: TextScaler.linear(someValue)); + + TextPainter.computeWidth(textScaler: TextScaler.linear(textScaleFactor)); + TextPainter.computeMaxIntrinsicWidth(textScaler: TextScaler.linear(textScaleFactor)); } diff --git a/packages/flutter/test_fixes/rendering/rendering.dart b/packages/flutter/test_fixes/rendering/rendering.dart index f8bfd0d1a5296..705085486fa68 100644 --- a/packages/flutter/test_fixes/rendering/rendering.dart +++ b/packages/flutter/test_fixes/rendering/rendering.dart @@ -18,4 +18,10 @@ void main() { renderListWheelViewport = RenderListWheelViewport(clipToSize: false); renderListWheelViewport = RenderListWheelViewport(error: ''); renderListWheelViewport.clipToSize; + + // Change made in https://github.com/flutter/flutter/pull/128522 + RenderParagraph(textScaleFactor: math.min(123, 456)); + RenderParagraph(); + RenderEditable(textScaleFactor: math.min(123, 456)); + RenderEditable(); } diff --git a/packages/flutter/test_fixes/rendering/rendering.dart.expect b/packages/flutter/test_fixes/rendering/rendering.dart.expect index 850b37fdf39e5..e660069f3fa5d 100644 --- a/packages/flutter/test_fixes/rendering/rendering.dart.expect +++ b/packages/flutter/test_fixes/rendering/rendering.dart.expect @@ -18,4 +18,10 @@ void main() { renderListWheelViewport = RenderListWheelViewport(clipBehavior: Clip.none); renderListWheelViewport = RenderListWheelViewport(error: ''); renderListWheelViewport.clipBehavior; + + // Change made in https://github.com/flutter/flutter/pull/128522 + RenderParagraph(textScaler: TextScaler.linear(math.min(123, 456))); + RenderParagraph(); + RenderEditable(textScaler: TextScaler.linear(math.min(123, 456))); + RenderEditable(); } diff --git a/packages/flutter/test_fixes/widgets/media_query.dart b/packages/flutter/test_fixes/widgets/media_query.dart new file mode 100644 index 0000000000000..35c8450a28251 --- /dev/null +++ b/packages/flutter/test_fixes/widgets/media_query.dart @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; + +void main() { + // Change made in https://github.com/flutter/flutter/pull/128522 + MediaQueryData(); + MediaQueryData(textScaleFactor: 2.0) + ..copyWith(textScaleFactor: 2.0) + ..copyWith(); +} diff --git a/packages/flutter/test_fixes/widgets/media_query.dart.expect b/packages/flutter/test_fixes/widgets/media_query.dart.expect new file mode 100644 index 0000000000000..6e88c7793caf4 --- /dev/null +++ b/packages/flutter/test_fixes/widgets/media_query.dart.expect @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; + +void main() { + // Change made in https://github.com/flutter/flutter/pull/128522 + MediaQueryData(); + MediaQueryData(textScaler: TextScaler.linear(2.0)) + ..copyWith(textScaler: TextScaler.linear(2.0)) + ..copyWith(); +} diff --git a/packages/flutter/test_fixes/widgets/rich_text.dart b/packages/flutter/test_fixes/widgets/rich_text.dart new file mode 100644 index 0000000000000..8e61177e1c406 --- /dev/null +++ b/packages/flutter/test_fixes/widgets/rich_text.dart @@ -0,0 +1,11 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; + +void main() { + // Change made in https://github.com/flutter/flutter/pull/128522 + RichText(); + RichText(textScaleFactor: 2.0); +} diff --git a/packages/flutter/test_fixes/widgets/rich_text.dart.expect b/packages/flutter/test_fixes/widgets/rich_text.dart.expect new file mode 100644 index 0000000000000..c517fb4a0f25e --- /dev/null +++ b/packages/flutter/test_fixes/widgets/rich_text.dart.expect @@ -0,0 +1,11 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; + +void main() { + // Change made in https://github.com/flutter/flutter/pull/128522 + RichText(); + RichText(textScaler: TextScaler.linear(2.0)); +} From 1937ae65391e1b397ccac119597998deeff05404 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Mon, 17 Jul 2023 11:20:27 -0700 Subject: [PATCH 0199/1547] Make AbstractNode-derived docs more specific on RenderObject et al. (#130689) These methods and/or their docs were recently copied (in #128467 and #128973) from their classes' former shared base class AbstractNode. Their wording was fittingly abstract there, but that abstraction is a bit puzzling for a reader finding them on these more concrete classes and not aware of the AbstractNode history. So make them more concrete, in similar terms to the other methods around them. Also copy some useful points between corresponding methods on different classes (like that the parent of the root is null), and try to clean up the prose on [RenderObject.depth]. We focus on the more outward-facing parts of the API, letting methods like `redepthChildren` continue to talk generically about "nodes". --- packages/flutter/lib/src/rendering/layer.dart | 18 ++++---- .../flutter/lib/src/rendering/object.dart | 42 ++++++++++--------- .../flutter/lib/src/semantics/semantics.dart | 16 ++++--- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index 51b5e86a2e45f..1cff262dde684 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -498,20 +498,22 @@ abstract class Layer with DiagnosticableTreeMixin { _needsAddToScene = _needsAddToScene || alwaysNeedsAddToScene; } - /// The owner for this node (null if unattached). + /// The owner for this layer (null if unattached). /// - /// The entire subtree that this node belongs to will have the same owner. + /// The entire layer tree that this layer belongs to will have the same owner. + /// + /// Typically the owner is a [RenderView]. Object? get owner => _owner; Object? _owner; - /// Whether this node is in a tree whose root is attached to something. + /// Whether the layer tree containing this layer is attached to an owner. /// /// This becomes true during the call to [attach]. /// /// This becomes false during the call to [detach]. bool get attached => _owner != null; - /// Mark this node as attached to the given owner. + /// Mark this layer as attached to the given owner. /// /// Typically called only from the [parent]'s [attach] method, and by the /// [owner] to mark the root of a tree as attached. @@ -528,7 +530,7 @@ abstract class Layer with DiagnosticableTreeMixin { _owner = owner; } - /// Mark this node as detached. + /// Mark this layer as detached from its owner. /// /// Typically called only from the [parent]'s [detach], and by the [owner] to /// mark the root of a tree as detached. @@ -545,10 +547,12 @@ abstract class Layer with DiagnosticableTreeMixin { assert(parent == null || attached == parent!.attached); } - /// The depth of this node in the tree. + /// The depth of this layer in the layer tree. /// /// The depth of nodes in a tree monotonically increases as you traverse down - /// the tree. + /// the tree. There's no guarantee regarding depth between siblings. + /// + /// The depth is used to ensure that nodes are processed in depth order. int get depth => _depth; int _depth = 0; diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 9a54bea5cbf82..730bf50506442 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -1727,21 +1727,22 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge } } - /// The depth of this node in the tree. + /// The depth of this render object in the render tree. /// /// The depth of nodes in a tree monotonically increases as you traverse down - /// the tree. - /// - /// Nodes always have a [depth] greater than their ancestors'. There's no - /// guarantee regarding depth between siblings. The depth of a node is used to - /// ensure that nodes are processed in depth order. The [depth] of a child can - /// be more than one greater than the [depth] of the parent, because the [depth] - /// values are never decreased: all that matters is that it's greater than the - /// parent. Consider a tree with a root node A, a child B, and a grandchild C. - /// Initially, A will have [depth] 0, B [depth] 1, and C [depth] 2. If C is - /// moved to be a child of A, sibling of B, then the numbers won't change. C's - /// [depth] will still be 2. The [depth] is automatically maintained by the - /// [adoptChild] and [dropChild] methods. + /// the tree: a node always has a [depth] greater than its ancestors. + /// There's no guarantee regarding depth between siblings. + /// + /// The [depth] of a child can be more than one greater than the [depth] of + /// the parent, because the [depth] values are never decreased: all that + /// matters is that it's greater than the parent. Consider a tree with a root + /// node A, a child B, and a grandchild C. Initially, A will have [depth] 0, + /// B [depth] 1, and C [depth] 2. If C is moved to be a child of A, + /// sibling of B, then the numbers won't change. C's [depth] will still be 2. + /// + /// The depth of a node is used to ensure that nodes are processed in + /// depth order. The [depth] is automatically maintained by the [adoptChild] + /// and [dropChild] methods. int get depth => _depth; int _depth = 0; @@ -1765,7 +1766,9 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge @protected void redepthChildren() { } - /// The parent of this node in the tree. + /// The parent of this render object in the render tree. + /// + /// The [parent] of the root node in the render tree is null. RenderObject? get parent => _parent; RenderObject? _parent; @@ -2052,20 +2055,21 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge return layoutParent; } - /// The owner for this node (null if unattached). + /// The owner for this render object (null if unattached). /// - /// The entire subtree that this node belongs to will have the same owner. + /// The entire render tree that this render object belongs to + /// will have the same owner. PipelineOwner? get owner => _owner; PipelineOwner? _owner; - /// Whether this node is in a tree whose root is attached to something. + /// Whether the render tree this render object belongs to is attached to a [PipelineOwner]. /// /// This becomes true during the call to [attach]. /// /// This becomes false during the call to [detach]. bool get attached => _owner != null; - /// Mark this node as attached to the given owner. + /// Mark this render object as attached to the given owner. /// /// Typically called only from the [parent]'s [attach] method, and by the /// [owner] to mark the root of a tree as attached. @@ -2107,7 +2111,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge } } - /// Mark this node as detached. + /// Mark this render object as detached from its [PipelineOwner]. /// /// Typically called only from the [parent]'s [detach], and by the [owner] to /// mark the root of a tree as detached. diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index 227ad64680d4c..53d03c274bcb6 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -1999,25 +1999,29 @@ class SemanticsNode with DiagnosticableTreeMixin { /// The owner for this node (null if unattached). /// - /// The entire subtree that this node belongs to will have the same owner. + /// The entire semantics tree that this node belongs to will have the same owner. SemanticsOwner? get owner => _owner; SemanticsOwner? _owner; - /// Whether this node is in a tree whose root is attached to something. + /// Whether the semantics tree this node belongs to is attached to a [SemanticsOwner]. /// /// This becomes true during the call to [attach]. /// /// This becomes false during the call to [detach]. bool get attached => _owner != null; - /// The parent of this node in the tree. + /// The parent of this node in the semantics tree. + /// + /// The [parent] of the root node in the semantics tree is null. SemanticsNode? get parent => _parent; SemanticsNode? _parent; - /// The depth of this node in the tree. + /// The depth of this node in the semantics tree. /// /// The depth of nodes in a tree monotonically increases as you traverse down - /// the tree. + /// the tree. There's no guarantee regarding depth between siblings. + /// + /// The depth is used to ensure that nodes are processed in depth order. int get depth => _depth; int _depth = 0; @@ -2082,7 +2086,7 @@ class SemanticsNode with DiagnosticableTreeMixin { } } - /// Mark this node as detached. + /// Mark this node as detached from its owner. @visibleForTesting void detach() { assert(_owner != null); From 0df4496cdb50c4b7d6c42d461c46b3f4c2029d95 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Mon, 17 Jul 2023 11:24:49 -0700 Subject: [PATCH 0200/1547] Add missing example links (#130521) ## Description This adds some more missing example links. I also wrote another PR for adding a check to make sure that examples are all linked from a source file and have tests: https://github.com/flutter/flutter/pull/130523 ## Related Issues - https://github.com/flutter/flutter/issues/129956 ## Tests - Documentation and refactoring only. --- .../api/lib/material/drawer/drawer.0.dart | 90 +++++++++++++++++++ .../navigation_drawer.0.dart | 26 +++--- .../navigation_drawer.1.dart | 60 ------------- .../scaffold_state.show_snack_bar.0.dart | 43 --------- .../test/material/drawer/drawer.0_test.dart | 43 +++++++++ .../navigation_drawer.0_test.dart | 41 +++++++++ 6 files changed, 189 insertions(+), 114 deletions(-) create mode 100644 examples/api/lib/material/drawer/drawer.0.dart delete mode 100644 examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart delete mode 100644 examples/api/lib/material/scaffold/scaffold_state.show_snack_bar.0.dart create mode 100644 examples/api/test/material/drawer/drawer.0_test.dart create mode 100644 examples/api/test/material/navigation_drawer/navigation_drawer.0_test.dart diff --git a/examples/api/lib/material/drawer/drawer.0.dart b/examples/api/lib/material/drawer/drawer.0.dart new file mode 100644 index 0000000000000..46c96ac435bb7 --- /dev/null +++ b/examples/api/lib/material/drawer/drawer.0.dart @@ -0,0 +1,90 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [Drawer]. + +void main() => runApp(const DrawerApp()); + +class DrawerApp extends StatelessWidget { + const DrawerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const DrawerExample(), + ); + } +} + +class DrawerExample extends StatefulWidget { + const DrawerExample({super.key}); + + @override + State createState() => _DrawerExampleState(); +} + +class _DrawerExampleState extends State { + String selectedPage = ''; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Drawer Example'), + ), + drawer: Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + const DrawerHeader( + decoration: BoxDecoration( + color: Colors.blue, + ), + child: Text( + 'Drawer Header', + style: TextStyle( + color: Colors.white, + fontSize: 24, + ), + ), + ), + ListTile( + leading: const Icon(Icons.message), + title: const Text('Messages'), + onTap: () { + setState(() { + selectedPage = 'Messages'; + }); + }, + ), + ListTile( + leading: const Icon(Icons.account_circle), + title: const Text('Profile'), + onTap: () { + setState(() { + selectedPage = 'Profile'; + }); + }, + ), + ListTile( + leading: const Icon(Icons.settings), + title: const Text('Settings'), + onTap: () { + setState(() { + selectedPage = 'Settings'; + }); + }, + ), + ], + ), + ), + body: Center( + child: Text('Page: $selectedPage'), + ), + ); + } +} diff --git a/examples/api/lib/material/navigation_drawer/navigation_drawer.0.dart b/examples/api/lib/material/navigation_drawer/navigation_drawer.0.dart index 446cd1308c3ff..1854b6f850696 100644 --- a/examples/api/lib/material/navigation_drawer/navigation_drawer.0.dart +++ b/examples/api/lib/material/navigation_drawer/navigation_drawer.0.dart @@ -11,6 +11,8 @@ import 'package:flutter/material.dart'; /// Flutter code sample for [NavigationDrawer]. +void main() => runApp(const NavigationDrawerApp()); + class ExampleDestination { const ExampleDestination(this.label, this.icon, this.selectedIcon); @@ -20,20 +22,22 @@ class ExampleDestination { } const List destinations = [ - ExampleDestination('page 0', Icon(Icons.widgets_outlined), Icon(Icons.widgets)), - ExampleDestination('page 1', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)), - ExampleDestination('page 2', Icon(Icons.text_snippet_outlined), Icon(Icons.text_snippet)), - ExampleDestination('page 3', Icon(Icons.invert_colors_on_outlined), Icon(Icons.opacity)), + ExampleDestination('Messages', Icon(Icons.widgets_outlined), Icon(Icons.widgets)), + ExampleDestination('Profile', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)), + ExampleDestination('Settings', Icon(Icons.settings_outlined), Icon(Icons.settings)), ]; -void main() { - runApp( - MaterialApp( +class NavigationDrawerApp extends StatelessWidget { + const NavigationDrawerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(useMaterial3: true), home: const NavigationDrawerExample(), - ), - ); + ); + } } class NavigationDrawerExample extends StatefulWidget { @@ -65,7 +69,7 @@ class _NavigationDrawerExampleState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Text('Page Index = $screenIndex'), + Text('Page Index = $screenIndex'), ], ), ), @@ -125,7 +129,7 @@ class _NavigationDrawerExampleState extends State { child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - Text('Page Index = $screenIndex'), + Text('Page Index = $screenIndex'), ElevatedButton( onPressed: openDrawer, child: const Text('Open Drawer'), diff --git a/examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart b/examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart deleted file mode 100644 index 344f410481773..0000000000000 --- a/examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -/// Flutter code sample for [NavigationDrawer]. - -void main() => runApp(const MyApp()); - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - debugShowCheckedModeBanner: false, - theme: ThemeData( - useMaterial3: true, - ), - home: const MyHomePage(), - ); - } -} - -class MyHomePage extends StatelessWidget { - const MyHomePage({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Drawer Demo'), - ), - drawer: NavigationDrawer( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(28, 16, 16, 10), - child: Text( - 'Drawer Header', - style: Theme.of(context).textTheme.titleSmall, - ), - ), - const NavigationDrawerDestination( - icon: Icon(Icons.message), - label: Text('Messages'), - ), - const NavigationDrawerDestination( - icon: Icon(Icons.account_circle), - label: Text('Profile'), - ), - const NavigationDrawerDestination( - icon: Icon(Icons.settings), - label: Text('Settings'), - ), - ]) - ); - } -} diff --git a/examples/api/lib/material/scaffold/scaffold_state.show_snack_bar.0.dart b/examples/api/lib/material/scaffold/scaffold_state.show_snack_bar.0.dart deleted file mode 100644 index 0f077982b9aba..0000000000000 --- a/examples/api/lib/material/scaffold/scaffold_state.show_snack_bar.0.dart +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -/// Flutter code sample for [ScaffoldState.showSnackBar]. - -void main() => runApp(const ShowSnackBarExampleApp()); - -class ShowSnackBarExampleApp extends StatelessWidget { - const ShowSnackBarExampleApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar(title: const Text('ScaffoldState Sample')), - body: const Center( - child: ShowSnackBarExample(), - ), - ), - ); - } -} - -class ShowSnackBarExample extends StatelessWidget { - const ShowSnackBarExample({super.key}); - - @override - Widget build(BuildContext context) { - return OutlinedButton( - onPressed: () { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('A SnackBar has been shown.'), - ), - ); - }, - child: const Text('Show SnackBar'), - ); - } -} diff --git a/examples/api/test/material/drawer/drawer.0_test.dart b/examples/api/test/material/drawer/drawer.0_test.dart new file mode 100644 index 0000000000000..6b942022173e1 --- /dev/null +++ b/examples/api/test/material/drawer/drawer.0_test.dart @@ -0,0 +1,43 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/drawer/drawer.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Navigation bar updates destination on tap', + (WidgetTester tester) async { + await tester.pumpWidget( + const example.DrawerApp(), + ); + + await tester.tap(find.byIcon(Icons.menu)); + await tester.pumpAndSettle(); + + /// NavigationDestinations must be rendered + expect(find.text('Messages'), findsOneWidget); + expect(find.text('Profile'), findsOneWidget); + expect(find.text('Settings'), findsOneWidget); + + /// Initial index must be zero + expect(find.text('Page: '), findsOneWidget); + + /// Switch to second tab + await tester.tap(find.ancestor(of: find.text('Messages'), matching: find.byType(InkWell))); + await tester.pumpAndSettle(); + expect(find.text('Page: Messages'), findsOneWidget); + + /// Switch to third tab + await tester.tap(find.ancestor(of: find.text('Profile'), matching: find.byType(InkWell))); + await tester.pumpAndSettle(); + expect(find.text('Page: Profile'), findsOneWidget); + + /// Switch to fourth tab + await tester.tap(find.ancestor(of: find.text('Settings'), matching: find.byType(InkWell))); + await tester.pumpAndSettle(); + expect(find.text('Page: Settings'), findsOneWidget); + }); +} diff --git a/examples/api/test/material/navigation_drawer/navigation_drawer.0_test.dart b/examples/api/test/material/navigation_drawer/navigation_drawer.0_test.dart new file mode 100644 index 0000000000000..a7e9916d827fc --- /dev/null +++ b/examples/api/test/material/navigation_drawer/navigation_drawer.0_test.dart @@ -0,0 +1,41 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/navigation_drawer/navigation_drawer.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Navigation bar updates destination on tap', + (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigationDrawerApp(), + ); + + await tester.tap(find.text('Open Drawer')); + await tester.pumpAndSettle(); + + final NavigationDrawer navigationDrawerWidget = tester.firstWidget(find.byType(NavigationDrawer)); + + /// NavigationDestinations must be rendered + expect(find.text('Messages'), findsNWidgets(2)); + expect(find.text('Profile'), findsNWidgets(2)); + expect(find.text('Settings'), findsNWidgets(2)); + + /// Initial index must be zero + expect(navigationDrawerWidget.selectedIndex, 0); + expect(find.text('Page Index = 0'), findsOneWidget); + + /// Switch to second tab + await tester.tap(find.ancestor(of: find.text('Profile'), matching: find.byType(InkWell))); + await tester.pumpAndSettle(); + expect(find.text('Page Index = 1'), findsOneWidget); + + /// Switch to fourth tab + await tester.tap(find.ancestor(of: find.text('Settings'), matching: find.byType(InkWell))); + await tester.pumpAndSettle(); + expect(find.text('Page Index = 2'), findsOneWidget); + }); +} From 220b0c4d9f56191a016dc61130aecf6004f73987 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 15:48:18 -0400 Subject: [PATCH 0201/1547] Roll Flutter Engine from 09fe990ebfcf to aa3239cf3c01 (5 revisions) (#130735) https://github.com/flutter/engine/compare/09fe990ebfcf...aa3239cf3c01 2023-07-17 10456171+caroqliu@users.noreply.github.com [fuchsia] flutter-embedder-test and touch-input-test use Flatland Test UI Stack (flutter/engine#43562) 2023-07-17 skia-flutter-autoroll@skia.org Roll Skia from 4ec9f2497be1 to dc93f341ec38 (10 revisions) (flutter/engine#43739) 2023-07-17 skia-flutter-autoroll@skia.org Roll Skia from 288c98d7ef0b to 4ec9f2497be1 (1 revision) (flutter/engine#43738) 2023-07-17 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from VYjne_BEm9inQ5fnq... to jtvD_HgQVBqadF3jX... (flutter/engine#43736) 2023-07-17 skia-flutter-autoroll@skia.org Roll Dart SDK from 827259dfffb9 to c1bfb2689f6f (1 revision) (flutter/engine#43735) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from VYjne_BEm9in to jtvD_HgQVBqa If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index de0fa3345e47f..4d9f4a89e5bd8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09fe990ebfcfde02bc860327fef3ea7d849fbd73 +aa3239cf3c01e8ba310f9d40ae42463156debde3 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index b68be3cc7ab95..7396b9ea71f4d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -VYjne_BEm9inQ5fnqh_RhYSoT2s9UYazyEBvyVCzB2QC +jtvD_HgQVBqadF3jXnPpEmHqe25HQIpLG8fS4CBsD_MC From e337343ab793d44cf260b8a397849aa87d8fb93c Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 17 Jul 2023 12:48:58 -0700 Subject: [PATCH 0202/1547] Mark some leaks. (#130470) --- .../test/foundation/leak_tracking.dart | 12 +++++++ .../test/foundation/leak_tracking_test.dart | 34 ++++++++++++++++--- .../test/material/date_range_picker_test.dart | 10 ++++-- .../material/text_selection_theme_test.dart | 16 +++++++-- 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/packages/flutter/test/foundation/leak_tracking.dart b/packages/flutter/test/foundation/leak_tracking.dart index 86cf3fa0bea89..1ed364c9fa469 100644 --- a/packages/flutter/test/foundation/leak_tracking.dart +++ b/packages/flutter/test/foundation/leak_tracking.dart @@ -169,6 +169,18 @@ class LeakCleaner { /// Returns true if [leak] should be reported as failure. bool _shouldReportLeak(LeakType leakType, LeakReport leak, Map<(String, LeakType), int> countByClassAndType) { + switch (leakType) { + case LeakType.notDisposed: + if (config.allowAllNotDisposed) { + return false; + } + case LeakType.notGCed: + case LeakType.gcedLate: + if (config.allowAllNotGCed) { + return false; + } + } + final String leakingClass = leak.type; final (String, LeakType) classAndType = (leakingClass, leakType); diff --git a/packages/flutter/test/foundation/leak_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test.dart index e9a66480c0188..bd02bd2c781dd 100644 --- a/packages/flutter/test/foundation/leak_tracking_test.dart +++ b/packages/flutter/test/foundation/leak_tracking_test.dart @@ -54,6 +54,28 @@ Future main() async { ), ); + testWidgetsWithLeakTracking( + 'respects allowAllNotDisposed', + (WidgetTester tester) async { + // ignore: avoid_redundant_argument_values, for readability. + await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: true, notGCed: false)); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + ), + ); + + testWidgetsWithLeakTracking( + 'respects allowAllNotGCed', + (WidgetTester tester) async { + // ignore: avoid_redundant_argument_values, for readability. + await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: false, notGCed: true)); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotGCed: true, + ), + ); + testWidgetsWithLeakTracking( 'respects count in allow lists', (WidgetTester tester) async { @@ -180,10 +202,14 @@ void _verifyLeakList(List list, int expectedCount, bool shouldContai final List<_LeakTrackedClass> _notGcedStorage = <_LeakTrackedClass>[]; class _StatelessLeakingWidget extends StatelessWidget { - _StatelessLeakingWidget() { - // ignore: unused_local_variable, the variable is used to create non disposed leak - final _LeakTrackedClass notDisposed = _LeakTrackedClass(); - _notGcedStorage.add(_LeakTrackedClass()..dispose()); + _StatelessLeakingWidget({bool notDisposed = true, bool notGCed = true}) { + if (notDisposed) { + // ignore: unused_local_variable, the variable is used to create non disposed leak + final _LeakTrackedClass notDisposed = _LeakTrackedClass(); + } + if (notGCed) { + _notGcedStorage.add(_LeakTrackedClass()..dispose()); + } } @override diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index 82b9d3fc6c486..baf135666ab9d 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import 'feedback_tester.dart'; void main() { @@ -250,12 +251,17 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('landscape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('landscape', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizeLandscape); expect(tester.widget(find.text('Jan 15 – Jan 25, 2016')).style?.fontSize, 24); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); - }); + }, + // TODO(polina-c): remove after resolving + // https://github.com/flutter/flutter/issues/130354 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotGCed: true, + )); }); testWidgets('Save and help text is used', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index bc80531b162b7..42a11c12df071 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -59,7 +60,7 @@ void main() { ]); }); - testWidgets('Empty textSelectionTheme will use defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty textSelectionTheme will use defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(); final bool material3 = theme.useMaterial3; final Color defaultCursorColor = material3 ? theme.colorScheme.primary : const Color(0xff2196f3); @@ -106,7 +107,18 @@ void main() { await tester.pumpAndSettle(); final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); - }); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130469 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'ValueNotifier': 1, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, + 'ValueNotifier': 1, + }, + // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. + allowAllNotGCed: true, + )); testWidgets('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { const TextSelectionThemeData textSelectionTheme = TextSelectionThemeData( From 085d6c97001c70e322ca19bbe7c24a4a8efab4a0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 16:34:53 -0400 Subject: [PATCH 0203/1547] Roll Flutter Engine from aa3239cf3c01 to ddbe23b374d8 (3 revisions) (#130741) https://github.com/flutter/engine/compare/aa3239cf3c01...ddbe23b374d8 2023-07-17 skia-flutter-autoroll@skia.org Roll Skia from b25cd035db06 to f0e1963324eb (2 revisions) (flutter/engine#43741) 2023-07-17 skia-flutter-autoroll@skia.org Roll Skia from dc93f341ec38 to b25cd035db06 (2 revisions) (flutter/engine#43740) 2023-07-17 bdero@google.com [Impeller] Correct coverage hint usage in PipelineBlend (flutter/engine#43708) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4d9f4a89e5bd8..22d2d359a7d68 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -aa3239cf3c01e8ba310f9d40ae42463156debde3 +ddbe23b374d8250a353030c42242963227ec8fe2 From e8231cea4cae0acd8a6204f925d12c7a60380d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:06:15 -0700 Subject: [PATCH 0204/1547] Move examples to `ListenableBuilder` (#130671) Updates examples to use the new `ListenableBuilder` if there's no animation. This is slightly more idiomatic. --- .../lib/services/keyboard_key/logical_keyboard_key.0.dart | 4 ++-- .../services/keyboard_key/physical_keyboard_key.0.dart | 4 ++-- examples/api/lib/widgets/actions/actions.0.dart | 8 ++++---- examples/api/lib/widgets/shortcuts/shortcuts.1.dart | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart b/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart index 3be60f244dee3..77b09d3038e1d 100644 --- a/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart +++ b/examples/api/lib/services/keyboard_key/logical_keyboard_key.0.dart @@ -74,8 +74,8 @@ class _MyKeyExampleState extends State { child: Focus( focusNode: _focusNode, onKey: _handleKeyEvent, - child: AnimatedBuilder( - animation: _focusNode, + child: ListenableBuilder( + listenable: _focusNode, builder: (BuildContext context, Widget? child) { if (!_focusNode.hasFocus) { return GestureDetector( diff --git a/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart b/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart index c5eaf1cd25165..6b569409bbbad 100644 --- a/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart +++ b/examples/api/lib/services/keyboard_key/physical_keyboard_key.0.dart @@ -74,8 +74,8 @@ class _MyPhysicalKeyExampleState extends State { child: Focus( focusNode: _focusNode, onKey: _handleKeyEvent, - child: AnimatedBuilder( - animation: _focusNode, + child: ListenableBuilder( + listenable: _focusNode, builder: (BuildContext context, Widget? child) { if (!_focusNode.hasFocus) { return GestureDetector( diff --git a/examples/api/lib/widgets/actions/actions.0.dart b/examples/api/lib/widgets/actions/actions.0.dart index e8f3366e22671..9752b07cfa6b3 100644 --- a/examples/api/lib/widgets/actions/actions.0.dart +++ b/examples/api/lib/widgets/actions/actions.0.dart @@ -91,8 +91,8 @@ class _SaveButtonState extends State { @override Widget build(BuildContext context) { - return AnimatedBuilder( - animation: widget.valueNotifier, + return ListenableBuilder( + listenable: widget.valueNotifier, builder: (BuildContext context, Widget? child) { return TextButton.icon( icon: const Icon(Icons.save), @@ -146,8 +146,8 @@ class _ActionsExampleState extends State { Actions.invoke(context, ModifyIntent(++count)); }, ), - AnimatedBuilder( - animation: model.data, + ListenableBuilder( + listenable: model.data, builder: (BuildContext context, Widget? child) { return Padding( padding: const EdgeInsets.all(8.0), diff --git a/examples/api/lib/widgets/shortcuts/shortcuts.1.dart b/examples/api/lib/widgets/shortcuts/shortcuts.1.dart index 6f1281d0fc592..8d59f00601fcd 100644 --- a/examples/api/lib/widgets/shortcuts/shortcuts.1.dart +++ b/examples/api/lib/widgets/shortcuts/shortcuts.1.dart @@ -100,8 +100,8 @@ class _ShortcutsExampleState extends State { children: [ const Text('Add to the counter by pressing the up arrow key'), const Text('Subtract from the counter by pressing the down arrow key'), - AnimatedBuilder( - animation: model, + ListenableBuilder( + listenable: model, builder: (BuildContext context, Widget? child) { return Text('count: ${model.count}'); }, From ede545cd8bb1cb642886148d0adbf47da986460f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 17:25:11 -0400 Subject: [PATCH 0205/1547] Roll Flutter Engine from ddbe23b374d8 to 15c15fd75743 (2 revisions) (#130746) https://github.com/flutter/engine/compare/ddbe23b374d8...15c15fd75743 2023-07-17 skia-flutter-autoroll@skia.org Roll Dart SDK from c1bfb2689f6f to 78c9ac730629 (1 revision) (flutter/engine#43745) 2023-07-17 skia-flutter-autoroll@skia.org Roll Skia from f0e1963324eb to f29d58569c67 (4 revisions) (flutter/engine#43744) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 22d2d359a7d68..c3dc0f3bb0cae 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ddbe23b374d8250a353030c42242963227ec8fe2 +15c15fd75743e908cab41fd74461fd9815802967 From 2dbf594fde915f531bfad55597796cb36cf06e4f Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 17 Jul 2023 15:05:37 -0700 Subject: [PATCH 0206/1547] Resolve TODOs in channels integration test (#130745) They were helpful in diagnosing the flake in https://github.com/flutter/flutter/issues/116663, but now that that's resolved they have outlived their usefulness. Let's remove 'em! --- .../channels/integration_test/main_test.dart | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dev/integration_tests/channels/integration_test/main_test.dart b/dev/integration_tests/channels/integration_test/main_test.dart index 2ec03ce92ee18..438ad8aa235ca 100644 --- a/dev/integration_tests/channels/integration_test/main_test.dart +++ b/dev/integration_tests/channels/integration_test/main_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:channels/main.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,9 +13,6 @@ String getStatus(WidgetTester tester) => tester.widget(statusField).data!; void main() { testWidgets('step through', (WidgetTester tester) async { - // TODO(goderbauer): Remove this once https://github.com/flutter/flutter/issues/116663 is diagnosed. - debugPrintHitTestResults = true; - await tester.pumpWidget(const TestApp()); await tester.pumpAndSettle(); @@ -37,9 +33,6 @@ void main() { } } - // TODO(goderbauer): Remove this once https://github.com/flutter/flutter/issues/116663 is diagnosed. - debugPrintHitTestResults = false; - final String status = getStatus(tester); if (status != 'complete') { fail('Failed at step $step with status $status'); From 1b07c3d798caabd1b38aef203420809cfad3e92d Mon Sep 17 00:00:00 2001 From: hellohuanlin <41930132+hellohuanlin@users.noreply.github.com> Date: Mon, 17 Jul 2023 15:21:07 -0700 Subject: [PATCH 0207/1547] [tools/ios_build_ipa] fallback to CFBundleName if CFBundleDisplayName is absent (#130752) The display name will fallback to CFBundleName if CFBundleDisplayName is absent. *List which issues are fixed by this PR. You must list at least one issue.* Fixes https://github.com/flutter/flutter/issues/120553 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/commands/build_ios.dart | 3 +- .../lib/src/ios/plist_parser.dart | 1 + .../hermetic/build_ipa_test.dart | 58 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 27a483aa08cab..211bf2f16c7c8 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -378,7 +378,8 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { xcodeProjectSettingsMap['Version Number'] = globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleShortVersionStringKey); xcodeProjectSettingsMap['Build Number'] = globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleVersionKey); - xcodeProjectSettingsMap['Display Name'] = globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleDisplayNameKey); + xcodeProjectSettingsMap['Display Name'] = globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleDisplayNameKey) + ?? globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleNameKey); xcodeProjectSettingsMap['Deployment Target'] = globals.plistParser.getValueFromFile(plistPath, PlistParser.kMinimumOSVersionKey); xcodeProjectSettingsMap['Bundle Identifier'] = globals.plistParser.getValueFromFile(plistPath, PlistParser.kCFBundleIdentifierKey); diff --git a/packages/flutter_tools/lib/src/ios/plist_parser.dart b/packages/flutter_tools/lib/src/ios/plist_parser.dart index f6e1a9fe7ccc5..de40cedff8ede 100644 --- a/packages/flutter_tools/lib/src/ios/plist_parser.dart +++ b/packages/flutter_tools/lib/src/ios/plist_parser.dart @@ -30,6 +30,7 @@ class PlistParser { static const String kCFBundleExecutableKey = 'CFBundleExecutable'; static const String kCFBundleVersionKey = 'CFBundleVersion'; static const String kCFBundleDisplayNameKey = 'CFBundleDisplayName'; + static const String kCFBundleNameKey = 'CFBundleName'; static const String kMinimumOSVersionKey = 'MinimumOSVersion'; static const String kNSPrincipalClassKey = 'NSPrincipalClass'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index 622be93c1fdee..11f65819e1c06 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -954,6 +954,8 @@ void main() { plistUtils.fileContents[plistPath] = { 'CFBundleIdentifier': 'io.flutter.someProject', 'CFBundleDisplayName': 'Awesome Gallery', + // Will not use CFBundleName since CFBundleDisplayName is present. + 'CFBundleName': 'Awesome Gallery 2', 'MinimumOSVersion': '11.0', 'CFBundleVersion': '666', 'CFBundleShortVersionString': '12.34.56', @@ -992,6 +994,62 @@ void main() { PlistParser: () => plistUtils, }); + testUsingContext( + 'Validate basic Xcode settings with CFBundleDisplayName fallback to CFBundleName', () async { + const String plistPath = 'build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app/Info.plist'; + fakeProcessManager.addCommands([ + xattrCommand, + setUpFakeXcodeBuildHandler(onRun: () { + fileSystem.file(plistPath).createSync(recursive: true); + }), + exportArchiveCommand(exportOptionsPlist: _exportOptionsPlist), + ]); + + createMinimalMockProjectFiles(); + + plistUtils.fileContents[plistPath] = { + 'CFBundleIdentifier': 'io.flutter.someProject', + // Will use CFBundleName since CFBundleDisplayName is absent. + 'CFBundleName': 'Awesome Gallery', + 'MinimumOSVersion': '11.0', + 'CFBundleVersion': '666', + 'CFBundleShortVersionString': '12.34.56', + }; + + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + await createTestCommandRunner(command).run( + ['build', 'ipa', '--no-pub']); + + expect( + testLogger.statusText, + contains( + '[✓] App Settings Validation\n' + ' • Version Number: 12.34.56\n' + ' • Build Number: 666\n' + ' • Display Name: Awesome Gallery\n' + ' • Deployment Target: 11.0\n' + ' • Bundle Identifier: io.flutter.someProject\n' + ) + ); + expect( + testLogger.statusText, + contains('To update the settings, please refer to https://docs.flutter.dev/deployment/ios') + ); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => fakeProcessManager, + Platform: () => macosPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + PlistParser: () => plistUtils, + }); + + testUsingContext( 'Validate basic Xcode settings with default bundle identifier prefix', () async { const String plistPath = 'build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app/Info.plist'; From d0bb56f0244731b389f33f8d95f7f75697463bee Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 19:02:23 -0400 Subject: [PATCH 0208/1547] Roll Flutter Engine from 15c15fd75743 to 09689d37e1d6 (3 revisions) (#130758) https://github.com/flutter/engine/compare/15c15fd75743...09689d37e1d6 2023-07-17 737941+loic-sharma@users.noreply.github.com [Windows] Remove accessibility bridge helpers from the engine (flutter/engine#43710) 2023-07-17 jason-simmons@users.noreply.github.com Move Dart licenses into a separate golden file (flutter/engine#43289) 2023-07-17 skia-flutter-autoroll@skia.org Roll Skia from f29d58569c67 to f2a4222bb72e (1 revision) (flutter/engine#43746) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c3dc0f3bb0cae..a51371f94df41 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -15c15fd75743e908cab41fd74461fd9815802967 +09689d37e1d6cca748b17d9682127b08825a3297 From fe7d01ffab1cac2b97aa07e66b0c31a2bf851efa Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Mon, 17 Jul 2023 16:35:20 -0700 Subject: [PATCH 0209/1547] Prevent `InputDecorator` from supplying its descendants with non-normalized constraints (#130460) Fixes https://github.com/flutter/flutter/issues/129611 --- .../lib/src/material/input_decorator.dart | 4 +- .../test/material/input_decorator_test.dart | 56 ++++++++++++++----- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 0a9374c0bd731..ecfd98ab8568d 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -964,7 +964,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin boxToBaseline[prefixIcon] = _layoutLineBox(prefixIcon, containerConstraints); boxToBaseline[suffixIcon] = _layoutLineBox(suffixIcon, containerConstraints); final BoxConstraints contentConstraints = containerConstraints.copyWith( - maxWidth: containerConstraints.maxWidth - contentPadding.horizontal, + maxWidth: math.max(0.0, containerConstraints.maxWidth - contentPadding.horizontal), ); boxToBaseline[prefix] = _layoutLineBox(prefix, contentConstraints); boxToBaseline[suffix] = _layoutLineBox(suffix, contentConstraints); @@ -1093,7 +1093,7 @@ class _RenderDecoration extends RenderBox with SlottedContainerRenderObjectMixin final double minContainerHeight = decoration.isDense! || decoration.isCollapsed || expands ? 0.0 : kMinInteractiveDimension; - final double maxContainerHeight = boxConstraints.maxHeight - bottomHeight; + final double maxContainerHeight = math.max(0.0, boxConstraints.maxHeight - bottomHeight); final double containerHeight = expands ? maxContainerHeight : math.min(math.max(contentHeight, minContainerHeight), maxContainerHeight); diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index d7b864179797a..088cd67a5d1c7 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -158,7 +158,11 @@ TextStyle? getIconStyle(WidgetTester tester, IconData icon) { } void main() { - for (final bool useMaterial3 in [true, false]){ + runAllTests(useMaterial3: true); + runAllTests(useMaterial3: false); +} + +void runAllTests({ required bool useMaterial3 }) { testWidgets('InputDecorator input/label text layout', (WidgetTester tester) async { // The label appears above the input text await tester.pumpWidget( @@ -1796,7 +1800,7 @@ void main() { ), ); await tester.pumpWidget( - MaterialApp( + MaterialApp( theme: theme, home: Material( child: TextField( @@ -2011,9 +2015,9 @@ void main() { // Overall height for this InputDecorator is 48dps because the prefix icon's minimum size // is 48x48 and the rest of the elements only require 40dps: - // 12 - top padding - // 16 - input text (font size 16dps) - // 12 - bottom padding + // 12 - top padding + // 16 - input text (font size 16dps) + // 12 - bottom padding expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0)); expect(tester.getSize(find.text('text')).height, 16.0); @@ -2085,10 +2089,10 @@ void main() { ); // Overall height for this InputDecorator is 48dps because the prefix icon's minimum size - // is 48x48 and the rest of the elements only require 40dps: - // 12 - top padding - // 16 - input text (font size 16dps) - // 12 - bottom padding + // is 48x48 and the rest of the elements only require 40dps: + // 12 - top padding + // 16 - input text (font size 16dps) + // 12 - bottom padding expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 48.0)); expect(tester.getSize(find.byKey(prefixKey)).height, 16.0); @@ -2303,9 +2307,9 @@ void main() { // Overall height for this InputDecorator is 100dps because the prefix icon's size // is 100x100 and the rest of the elements only require 40dps: - // 12 - top padding - // 16 - input text (font size 16dps) - // 12 - bottom padding + // 12 - top padding + // 16 - input text (font size 16dps) + // 12 - bottom padding expect(tester.getSize(find.byType(InputDecorator)), const Size(800.0, 100.0)); expect(tester.getSize(find.byKey(prefixKey)).height, 100.0); @@ -5487,7 +5491,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317 - testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular border', (WidgetTester tester) async { +testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular border', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/78855 const String labelText = 'Flutter'; @@ -6546,5 +6550,29 @@ void main() { // The prefix is inside the decorator. expect(decoratorRight, lessThanOrEqualTo(prefixRight)); }); -} + + testWidgets('InputDecorator with counter does not crash when given a 0 size', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/129611 + const InputDecoration decoration = InputDecoration( + contentPadding: EdgeInsetsDirectional.all(99), + prefixIcon: Focus(child: Icon(Icons.search)), + counter: Text('COUNTER'), + ); + + await tester.pumpWidget( + Center( + child: SizedBox.square( + dimension: 0.0, + child: buildInputDecorator( + useMaterial3: useMaterial3, + decoration: decoration, + ), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(InputDecorator), findsOneWidget); + expect(tester.renderObject(find.text('COUNTER')).size, Size.zero); + }); } From 236a131cff5373a628ab52629bd8e357d3ce4931 Mon Sep 17 00:00:00 2001 From: Andrew Kolos Date: Mon, 17 Jul 2023 16:51:14 -0700 Subject: [PATCH 0210/1547] update link to good first issues (#130759) Today (Jul 17, 2023), I renamed the `good first contribution` label to `good first issue`. This is because 1) `good first issue` is more commonly used for this intent across GitHub and and thus may be (ever so slightly) more recognizable to potential new contributors, and, more importantly, 2) GitHub recognizes the label `good first issue` when surfacing good first issues in specific places in GitHub[^1]. This PR updates Contributing.md to match the new name. `grep` did not find any other references to `good first contribution` to update in this repo. [^1]: [Source (GitHub docs)](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/encouraging-helpful-contributions-to-your-project-with-labels). Example: https://github.com/flutter/flutter/contribute. If my vague memory serves me correctly, this can also appear in certain emails or the "discovery queue"-type experience that GitHub provides. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d73e488ea62e..46e2c045acee5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,7 +91,7 @@ for how to set up your development environment, or ask in #hackers-test on Disco Developing for Flutter ---------------------- -If you would prefer to write code, you may wish to start with our list of [good first contributions](https://github.com/flutter/flutter/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+contribution%22). +If you would prefer to write code, you may wish to start with our list of [good first issues](https://github.com/flutter/flutter/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). To develop for Flutter, you will eventually need to become familiar with our processes and conventions. This section lists the documents From c1f6b32c81b00576168e727ac2d0d52290148295 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 17 Jul 2023 17:56:25 -0700 Subject: [PATCH 0211/1547] Stabilize hybrid_android_views_integration_test rendering tree (#130751) Fixes: https://github.com/flutter/flutter/issues/130738 A widget was added to explicitly and intentionally overlap the PlatformView so that the rendering tree of Views would always have an underlay and an overlay to match the test expectations. --- .../lib/nested_view_event_page.dart | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart b/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart index bdcb3dd90668d..b58580c40727c 100644 --- a/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart +++ b/dev/integration_tests/hybrid_android_views/lib/nested_view_event_page.dart @@ -51,13 +51,30 @@ class NestedViewEventBodyState extends State { children: [ SizedBox( height: 300, - child: showPlatformView ? - AndroidPlatformView( - key: const ValueKey('PlatformView'), - viewType: 'simple_view', - onPlatformViewCreated: onPlatformViewCreated, - useHybridComposition: useHybridComposition, - ) : null, + child: Stack( + alignment: Alignment.topCenter, + children: [ + if (showPlatformView) + AndroidPlatformView( + key: const ValueKey('PlatformView'), + viewType: 'simple_view', + onPlatformViewCreated: onPlatformViewCreated, + useHybridComposition: useHybridComposition, + ), + // The overlapping widget stabilizes the view tree by ensuring + // that there is widget content on top of the platform view. + // Without this widget, we rely on the UI elements down below + // to "incidentally" draw on top of the PlatformView which + // is not a reliable behavior as we eliminate non-visible + // rendering operations throughout the framework and engine. + const Positioned( + top: 50, + child: Text('overlapping widget', + style: TextStyle(color: Colors.yellow), + ), + ), + ], + ), ), if (_lastTestStatus != _LastTestStatus.pending) _statusWidget(), if (viewChannel != null) ... [ From 11f7c45a6dc0f94caa9b3b0c10627232fb059a8d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 20:59:24 -0400 Subject: [PATCH 0212/1547] Roll Flutter Engine from 09689d37e1d6 to 3cceb705007e (2 revisions) (#130763) https://github.com/flutter/engine/compare/09689d37e1d6...3cceb705007e 2023-07-17 brianosman@google.com Fix drawVertices documentation (flutter/engine#43747) 2023-07-17 zanderso@users.noreply.github.com Revert "Roll Clang from 6d667d4b261e to ebd0b8a0472b" (flutter/engine#43749) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a51371f94df41..a6f17c04a7384 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09689d37e1d6cca748b17d9682127b08825a3297 +3cceb705007ed5ee63ab5679a4eb853248500d38 From 8a8f023466908961f153a654c537b9b0ff72b7e5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 22:46:27 -0400 Subject: [PATCH 0213/1547] Roll Flutter Engine from 3cceb705007e to f2958f9229a4 (1 revision) (#130767) https://github.com/flutter/engine/compare/3cceb705007e...f2958f9229a4 2023-07-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 78c9ac730629 to 32bc5d654e92 (1 revision) (flutter/engine#43751) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a6f17c04a7384..319f7b36adacf 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3cceb705007ed5ee63ab5679a4eb853248500d38 +f2958f9229a44bc6dec324efd7bb31d001d18142 From e276629ffb0ac66477eb383f6552d3eb4c228895 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 17 Jul 2023 23:29:46 -0400 Subject: [PATCH 0214/1547] Roll Flutter Engine from f2958f9229a4 to 77ec92371846 (1 revision) (#130769) https://github.com/flutter/engine/compare/f2958f9229a4...77ec92371846 2023-07-18 zanderso@users.noreply.github.com Add a GN flag to set the Dart VM's optimization level (flutter/engine#43743) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 319f7b36adacf..42a4cd7604584 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f2958f9229a44bc6dec324efd7bb31d001d18142 +77ec9237184635f26b9a2f9ac0408866b735b9b4 From e12d31ad75fcb11c5fa3e2c5a6f3e4e739f1cfe5 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Mon, 17 Jul 2023 20:36:18 -0700 Subject: [PATCH 0215/1547] Document stack's clipping behaviour better (#130749) Fixes https://github.com/flutter/flutter/issues/40216 --- packages/flutter/lib/src/rendering/stack.dart | 11 ++++++++++- packages/flutter/lib/src/widgets/basic.dart | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart index bb2e3c9a708a5..fb8aa3f97ee09 100644 --- a/packages/flutter/lib/src/rendering/stack.dart +++ b/packages/flutter/lib/src/rendering/stack.dart @@ -435,7 +435,16 @@ class RenderStack extends RenderBox /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Stacks only clip children whose geometry overflow the stack. A child that + /// paints outside its bounds (e.g. a box with a shadow) will not be clipped, + /// regardless of the value of this property. Similarly, a child that itself + /// has a descendant that overflows the stack will not be clipped, as only the + /// geometry of the stack's direct children are considered. + /// + /// To clip children whose geometry does not overflow the stack, consider + /// using a [RenderClipRect] render object. + /// + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 3dc2786736bce..dafcd1209262f 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -3914,6 +3914,15 @@ class Stack extends MultiChildRenderObjectWidget { /// {@macro flutter.material.Material.clipBehavior} /// + /// Stacks only clip children whose geometry overflow the stack. A child that + /// paints outside its bounds (e.g. a box with a shadow) will not be clipped, + /// regardless of the value of this property. Similarly, a child that itself + /// has a descendant that overflows the stack will not be clipped, as only the + /// geometry of the stack's direct children are considered. + /// + /// To clip children whose geometry does not overflow the stack, consider + /// using a [ClipRect] widget. + /// /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; From e14dcf06c6c9a83742bd48baeef2b98f8a977f7a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 01:23:32 -0400 Subject: [PATCH 0216/1547] Roll Flutter Engine from 77ec92371846 to 9d018f00d687 (1 revision) (#130772) https://github.com/flutter/engine/compare/77ec92371846...9d018f00d687 2023-07-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 32bc5d654e92 to 979375f92109 (1 revision) (flutter/engine#43753) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 42a4cd7604584..a17f2dcbc64df 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -77ec9237184635f26b9a2f9ac0408866b735b9b4 +9d018f00d6878d6c0778f9e8c86137ba4131dc4f From ace12f92def5922069cef15d82590027dc87f2e7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 02:14:23 -0400 Subject: [PATCH 0217/1547] Roll Flutter Engine from 9d018f00d687 to 116eedf769be (2 revisions) (#130774) https://github.com/flutter/engine/compare/9d018f00d687...116eedf769be 2023-07-18 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from jtvD_HgQVBqadF3jX... to _CIP-1iUTmGCbCDZ5... (flutter/engine#43755) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from f2a4222bb72e to 071d5897eb8a (1 revision) (flutter/engine#43754) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from jtvD_HgQVBqa to _CIP-1iUTmGC If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a17f2dcbc64df..865fc5e46bb47 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9d018f00d6878d6c0778f9e8c86137ba4131dc4f +116eedf769be09b78461905854b999680aa560fc diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7396b9ea71f4d..b74c44390fff2 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -jtvD_HgQVBqadF3jXnPpEmHqe25HQIpLG8fS4CBsD_MC +_CIP-1iUTmGCbCDZ50br0bLzTWEMTtTBH55gpi2EcQgC From 39c475c37943e85f617df67723ffbef02d113897 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 03:01:24 -0400 Subject: [PATCH 0218/1547] Roll Flutter Engine from 116eedf769be to c6e23288db8d (3 revisions) (#130778) https://github.com/flutter/engine/compare/116eedf769be...c6e23288db8d 2023-07-18 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from WZt3P7Fm3_GUvAaDv... to ixKM7wyMrqmPDaQ11... (flutter/engine#43756) 2023-07-18 jiahaog@users.noreply.github.com Minor fixes for C++20 compatibility (flutter/engine#43674) 2023-07-18 jiahaog@users.noreply.github.com Revert "Log dlopen errors in opt builds (#41477)" (flutter/engine#43677) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from WZt3P7Fm3_GU to ixKM7wyMrqmP If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 865fc5e46bb47..497c8225be060 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -116eedf769be09b78461905854b999680aa560fc +c6e23288db8d72cf3b84d1f6d0a5624660bf857f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 48950f33b2e18..78a061425fe44 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -WZt3P7Fm3_GUvAaDvmnYWul_8lnAYZ6MB5ZCdcp5VhsC +ixKM7wyMrqmPDaQ1116iI_iWW_tr97Vb1gGiPG1BmLAC From b552a0b3e6ed7e058a6994981f2aaf64a8aa4d82 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 04:05:23 -0400 Subject: [PATCH 0219/1547] Roll Flutter Engine from c6e23288db8d to 777fe158f4e7 (2 revisions) (#130779) https://github.com/flutter/engine/compare/c6e23288db8d...777fe158f4e7 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 48a44e2cda18 to 31be5646930b (3 revisions) (flutter/engine#43758) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 071d5897eb8a to 48a44e2cda18 (1 revision) (flutter/engine#43757) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 497c8225be060..85822715a83ce 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c6e23288db8d72cf3b84d1f6d0a5624660bf857f +777fe158f4e7a682bf8f78f7250c322b950e97ff From fa6754d362beda7e056f87a7b7c92405a631eb21 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 18 Jul 2023 11:26:09 +0300 Subject: [PATCH 0220/1547] Fix `iconTheme` in `AppBar` doesn't apply custom `Colors.white` in the dark mode for M3 (#130574) fixes [[Material3] AppBar does not respect `foregroundColor` or `iconTheme` for leading and actions in some cases](https://github.com/flutter/flutter/issues/130485) ### Description - Fix `Colors.white` not applied in dark mode - Add regression tests - make `iconStyle` private for consistency ### Before ![Screenshot 2023-07-14 at 18 40 58](https://github.com/flutter/flutter/assets/48603081/a6caffd6-d9a1-407a-aea7-c30047bfe7c7) ### After ![Screenshot 2023-07-14 at 18 41 04](https://github.com/flutter/flutter/assets/48603081/f864da7a-2ff8-46a4-8927-591e50050502) --- .../flutter/lib/src/material/constants.dart | 8 +- .../flutter/lib/src/material/icon_button.dart | 4 +- .../flutter/lib/src/material/theme_data.dart | 2 +- .../flutter/test/material/app_bar_test.dart | 176 ++++++++++++++---- .../test/material/app_bar_theme_test.dart | 28 +++ 5 files changed, 179 insertions(+), 39 deletions(-) diff --git a/packages/flutter/lib/src/material/constants.dart b/packages/flutter/lib/src/material/constants.dart index 87064a5a560da..ce5fb3256bbee 100644 --- a/packages/flutter/lib/src/material/constants.dart +++ b/packages/flutter/lib/src/material/constants.dart @@ -4,8 +4,6 @@ import 'package:flutter/painting.dart'; -import 'colors.dart'; - /// The minimum dimension of any interactive region according to Material /// guidelines. /// @@ -53,9 +51,11 @@ const EdgeInsets kMaterialListPadding = EdgeInsets.symmetric(vertical: 8.0); /// The default color for [ThemeData.iconTheme] when [ThemeData.brightness] is /// [Brightness.dark]. This color is used in [IconButton] to detect whether /// [IconTheme.of(context).color] is the same as the default color of [ThemeData.iconTheme]. -const Color kDefaultIconLightColor = Colors.white; +// ignore: prefer_const_constructors +final Color kDefaultIconLightColor = Color(0xFFFFFFFF); /// The default color for [ThemeData.iconTheme] when [ThemeData.brightness] is /// [Brightness.light]. This color is used in [IconButton] to detect whether /// [IconTheme.of(context).color] is the same as the default color of [ThemeData.iconTheme]. -const Color kDefaultIconDarkColor = Colors.black87; +// ignore: prefer_const_constructors +final Color kDefaultIconDarkColor = Color(0xDD000000); diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index 8fea4c9461be5..ade4e84e6677a 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -963,9 +963,9 @@ class _IconButtonM3 extends ButtonStyleButton { bool isIconThemeDefault(Color? color) { if (isDark) { - return color == kDefaultIconLightColor; + return identical(color, kDefaultIconLightColor); } - return color == kDefaultIconDarkColor; + return identical(color, kDefaultIconDarkColor); } final bool isDefaultColor = isIconThemeDefault(iconTheme.color); final bool isDefaultSize = iconTheme.size == const IconThemeData.fallback().size; diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index b541ddbe47795..c67e4b99aeba4 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -543,7 +543,7 @@ class ThemeData with Diagnosticable { } textTheme = defaultTextTheme.merge(textTheme); primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme); - iconTheme ??= isDark ? const IconThemeData(color: kDefaultIconLightColor) : const IconThemeData(color: kDefaultIconDarkColor); + iconTheme ??= isDark ? IconThemeData(color: kDefaultIconLightColor) : IconThemeData(color: kDefaultIconDarkColor); primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black); // COMPONENT THEMES diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index ecdfd3d8021d9..79e60bce01a14 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -55,7 +55,7 @@ ScrollController primaryScrollController(WidgetTester tester) { return PrimaryScrollController.of(tester.element(find.byType(CustomScrollView))); } -TextStyle? iconStyle(WidgetTester tester, IconData icon) { +TextStyle? _iconStyle(WidgetTester tester, IconData icon) { final RichText iconRichText = tester.widget( find.descendant(of: find.byIcon(icon).first, matching: find.byType(RichText)), ); @@ -575,7 +575,7 @@ void main() { ), ); - Color? iconColor() => iconStyle(tester, Icons.menu)?.color; + Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; final Color iconColorM2 = themeData.colorScheme.onPrimary; final Color iconColorM3 = themeData.colorScheme.onSurfaceVariant; expect(iconColor(), useMaterial3 ? iconColorM3 : iconColorM2); @@ -616,7 +616,7 @@ void main() { ), ); - Color? iconColor() => iconStyle(tester, Icons.menu)?.color; + Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; expect(iconColor(), color); }); @@ -655,7 +655,7 @@ void main() { ), ); - Color? iconColor() => iconStyle(tester, Icons.menu)?.color; + Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; final Color iconColorM2 = themeData.colorScheme.onPrimary; final Color iconColorM3 = themeData.colorScheme.onSurfaceVariant; expect(iconColor(), useMaterial3 ? iconColorM3 : iconColorM2); @@ -696,7 +696,7 @@ void main() { ), ); - Color? iconColor() => iconStyle(tester, Icons.menu)?.color; + Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; expect(iconColor(), color); }); @@ -3123,8 +3123,8 @@ void main() { expect(actionIconTheme.color, foregroundColor); // Test icon color - Color? leadingIconColor() => iconStyle(tester, Icons.add_circle)?.color; - Color? actionIconColor() => iconStyle(tester, Icons.ac_unit)?.color; + Color? leadingIconColor() => _iconStyle(tester, Icons.add_circle)?.color; + Color? actionIconColor() => _iconStyle(tester, Icons.ac_unit)?.color; expect(leadingIconColor(), foregroundColor); expect(actionIconColor(), foregroundColor); @@ -3156,8 +3156,8 @@ void main() { Color textColor() { return tester.renderObject(find.text('title')).text.style!.color!; } - Color? leadingIconColor() => iconStyle(tester, Icons.add_circle)?.color; - Color? actionIconColor() => iconStyle(tester, Icons.ac_unit)?.color; + Color? leadingIconColor() => _iconStyle(tester, Icons.add_circle)?.color; + Color? actionIconColor() => _iconStyle(tester, Icons.ac_unit)?.color; // M2 default color are onPrimary, and M3 has onSurface for leading and title, // onSurfaceVariant for actions. @@ -3191,9 +3191,9 @@ void main() { ), ); - Color? leadingIconColor() => iconStyle(tester, Icons.add_circle)?.color; - Color? actionIconColor() => iconStyle(tester, Icons.ac_unit)?.color; - Color? actionIconButtonColor() => iconStyle(tester, Icons.add)?.color; + Color? leadingIconColor() => _iconStyle(tester, Icons.add_circle)?.color; + Color? actionIconColor() => _iconStyle(tester, Icons.ac_unit)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; expect(leadingIconColor(), iconColor); expect(actionIconColor(), iconColor); @@ -3227,9 +3227,9 @@ void main() { ), ); - Color? leadingIconColor() => iconStyle(tester, Icons.add_circle)?.color; - Color? actionIconColor() => iconStyle(tester, Icons.ac_unit)?.color; - Color? actionIconButtonColor() => iconStyle(tester, Icons.add)?.color; + Color? leadingIconColor() => _iconStyle(tester, Icons.add_circle)?.color; + Color? actionIconColor() => _iconStyle(tester, Icons.ac_unit)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; expect(leadingIconColor(), themeData.colorScheme.onSurface); expect(actionIconColor(), actionsIconColor); @@ -3265,9 +3265,9 @@ void main() { ), ); - Color? leadingIconColor() => iconStyle(tester, Icons.add_circle)?.color; - Color? actionIconColor() => iconStyle(tester, Icons.ac_unit)?.color; - Color? actionIconButtonColor() => iconStyle(tester, Icons.add)?.color; + Color? leadingIconColor() => _iconStyle(tester, Icons.add_circle)?.color; + Color? actionIconColor() => _iconStyle(tester, Icons.ac_unit)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; expect(leadingIconColor(), overallIconColor); expect(actionIconColor(), actionsIconColor); @@ -3302,10 +3302,10 @@ void main() { ), ); - Color? leadingIconButtonColor() => iconStyle(tester, Icons.menu)?.color; - double? leadingIconButtonSize() => iconStyle(tester, Icons.menu)?.fontSize; - Color? actionIconButtonColor() => iconStyle(tester, Icons.add)?.color; - double? actionIconButtonSize() => iconStyle(tester, Icons.menu)?.fontSize; + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + double? leadingIconButtonSize() => _iconStyle(tester, Icons.menu)?.fontSize; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + double? actionIconButtonSize() => _iconStyle(tester, Icons.menu)?.fontSize; expect(leadingIconButtonColor(), Colors.yellow); expect(leadingIconButtonSize(), 30.0); @@ -3338,8 +3338,8 @@ void main() { ), ); - Color? leadingIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; - double? leadingIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.arrow_back)?.color; + double? leadingIconButtonSize() => _iconStyle(tester, Icons.arrow_back)?.fontSize; expect(leadingIconButtonColor(), Colors.yellow); expect(leadingIconButtonSize(), 30.0); @@ -3374,10 +3374,10 @@ void main() { ), ); - Color? leadingIconButtonColor() => iconStyle(tester, Icons.menu)?.color; - double? leadingIconButtonSize() => iconStyle(tester, Icons.menu)?.fontSize; - Color? actionIconButtonColor() => iconStyle(tester, Icons.add)?.color; - double? actionIconButtonSize() => iconStyle(tester, Icons.add)?.fontSize; + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + double? leadingIconButtonSize() => _iconStyle(tester, Icons.menu)?.fontSize; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + double? actionIconButtonSize() => _iconStyle(tester, Icons.add)?.fontSize; // The leading icon button uses the style in the IconButtonTheme because only actionsIconTheme is provided. expect(leadingIconButtonColor(), Colors.red); @@ -3413,8 +3413,8 @@ void main() { ), ); - Color? actionIconButtonColor() => iconStyle(tester, Icons.arrow_back)?.color; - double? actionIconButtonSize() => iconStyle(tester, Icons.arrow_back)?.fontSize; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.arrow_back)?.color; + double? actionIconButtonSize() => _iconStyle(tester, Icons.arrow_back)?.fontSize; expect(actionIconButtonColor(), Colors.yellow); expect(actionIconButtonSize(), 30.0); @@ -3446,12 +3446,124 @@ void main() { ), ); - Color? leadingIconButtonColor() => iconStyle(tester, Icons.menu)?.color; - Color? actionIconButtonColor() => iconStyle(tester, Icons.add)?.color; + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; expect(leadingIconButtonColor(), Colors.purple); expect(actionIconButtonColor(), Colors.purple); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/130485. + testWidgets('Material3 - AppBar.iconTheme is correctly applied in dark mode', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + colorScheme: const ColorScheme.dark().copyWith(onSurfaceVariant: Colors.red), + useMaterial3: true, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + iconTheme: const IconThemeData(color: Colors.white), + leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), + actions: [ + IconButton(icon: const Icon(Icons.add), onPressed: () {}), + ], + ), + ), + ), + ); + + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + + expect(leadingIconButtonColor(), Colors.white); + expect(actionIconButtonColor(), Colors.white); + }); + + // This is a regression test for https://github.com/flutter/flutter/issues/130485. + testWidgets('Material3 - AppBar.foregroundColor is correctly applied in dark mode', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + colorScheme: const ColorScheme.dark().copyWith(onSurfaceVariant: Colors.red), + useMaterial3: true, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + foregroundColor: Colors.white, + leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), + actions: [ + IconButton(icon: const Icon(Icons.add), onPressed: () {}), + ], + ), + ), + ), + ); + + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + + expect(leadingIconButtonColor(), Colors.white); + expect(actionIconButtonColor(), Colors.white); + }); + + // This is a regression test for https://github.com/flutter/flutter/issues/130485. + testWidgets('Material3 - AppBar.iconTheme is correctly applied in light mode', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + colorScheme: const ColorScheme.light().copyWith(onSurfaceVariant: Colors.red), + useMaterial3: true, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + iconTheme: const IconThemeData(color: Colors.black87), + leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), + actions: [ + IconButton(icon: const Icon(Icons.add), onPressed: () {}), + ], + ), + ), + ), + ); + + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + + expect(leadingIconButtonColor(), Colors.black87); + expect(actionIconButtonColor(), Colors.black87); + }); + + // This is a regression test for https://github.com/flutter/flutter/issues/130485. + testWidgets('Material3 - AppBar.foregroundColor is correctly applied in light mode', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + colorScheme: const ColorScheme.light().copyWith(onSurfaceVariant: Colors.red), + useMaterial3: true, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + foregroundColor: Colors.black87, + leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), + actions: [ + IconButton(icon: const Icon(Icons.add), onPressed: () {}), + ], + ), + ), + ), + ); + + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + + expect(leadingIconButtonColor(), Colors.black87); + expect(actionIconButtonColor(), Colors.black87); + }); }); group('MaterialStateColor scrolledUnder', () { diff --git a/packages/flutter/test/material/app_bar_theme_test.dart b/packages/flutter/test/material/app_bar_theme_test.dart index e520391d1a3cb..fca54545930b6 100644 --- a/packages/flutter/test/material/app_bar_theme_test.dart +++ b/packages/flutter/test/material/app_bar_theme_test.dart @@ -1055,6 +1055,34 @@ void main() { // one is used. This results in a difference for doubles in debugFillProperties between // the web and the rest of Flutter's target platforms. }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/87364 + + // This is a regression test for https://github.com/flutter/flutter/issues/130485. + testWidgets('Material3 - AppBarTheme.iconTheme correctly applies custom white color in dark mode', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + useMaterial3: true, + brightness: Brightness.dark, + appBarTheme: const AppBarTheme(iconTheme: IconThemeData(color: Colors.white)), + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), + actions: [ + IconButton(icon: const Icon(Icons.add), onPressed: () {}), + ], + ), + ), + ), + ); + + Color? leadingIconButtonColor() => _iconStyle(tester, Icons.menu)?.color; + Color? actionIconButtonColor() => _iconStyle(tester, Icons.add)?.color; + + expect(leadingIconButtonColor(), Colors.white); + expect(actionIconButtonColor(), Colors.white); + }); } AppBarTheme _appBarTheme() { From 3718aef47d0a186df97f1701142801323be07b67 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 05:15:19 -0400 Subject: [PATCH 0221/1547] Roll Flutter Engine from 777fe158f4e7 to b46a8baf8ed9 (1 revision) (#130782) https://github.com/flutter/engine/compare/777fe158f4e7...b46a8baf8ed9 2023-07-18 49699333+dependabot[bot]@users.noreply.github.com Bump actions/setup-python from 4.6.1 to 4.7.0 (flutter/engine#43760) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 85822715a83ce..166ff69bf6b0f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -777fe158f4e7a682bf8f78f7250c322b950e97ff +b46a8baf8ed9283b9e8d15bb1e1b713ade53aafc From 5952edb84b3609ffa0cf4f5477f4d1947f1f1c5c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 06:07:25 -0400 Subject: [PATCH 0222/1547] Roll Flutter Engine from b46a8baf8ed9 to 88be39be7b07 (1 revision) (#130784) https://github.com/flutter/engine/compare/b46a8baf8ed9...88be39be7b07 2023-07-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 979375f92109 to b83a63e0181a (1 revision) (flutter/engine#43762) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 166ff69bf6b0f..da7022316525b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b46a8baf8ed9283b9e8d15bb1e1b713ade53aafc +88be39be7b0734cf3eb5f9aaf36373b552344f6d From beb245c74942eb82cacedee039f2bd829ddbf422 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 07:25:32 -0400 Subject: [PATCH 0223/1547] Roll Flutter Engine from 88be39be7b07 to aaec42812a1f (1 revision) (#130787) https://github.com/flutter/engine/compare/88be39be7b07...aaec42812a1f 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 31be5646930b to a4df72ba04bb (1 revision) (flutter/engine#43763) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index da7022316525b..5e24b64d3467f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -88be39be7b0734cf3eb5f9aaf36373b552344f6d +aaec42812a1f2a7214a10c41af49ee31a538088d From 203ef6f7a32f494838a63f2c935ead994c0fcb6f Mon Sep 17 00:00:00 2001 From: yaakovschectman <109111084+yaakovschectman@users.noreply.github.com> Date: Tue, 18 Jul 2023 10:06:52 -0400 Subject: [PATCH 0224/1547] Extract common functionality of iOS platformviews into superclasses (#128716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move most functionality of `UiKitView` and its supporting classes into superclasses named `DarwinPlatformView`, etc., and create trivial or near-trivial subclasses with the same names as the old classes. I am currently awaiting approval for a macOS workstation that would allow me to run the iOS/macOS tests and make sure all existing functionality is preserved by this refactor. I can ensure that tests will pass, but doing so may need to wait for a while. Addresses [Add AppKitView](https://github.com/flutter/flutter/issues/128519) ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> Co-authored-by: Michael Goderbauer Co-authored-by: Chris Bracken --- .../lib/src/rendering/platform_view.dart | 132 ++++++++++------- .../lib/src/services/platform_views.dart | 22 ++- .../lib/src/widgets/platform_view.dart | 139 ++++++++++++------ 3 files changed, 188 insertions(+), 105 deletions(-) diff --git a/packages/flutter/lib/src/rendering/platform_view.dart b/packages/flutter/lib/src/rendering/platform_view.dart index ca605597669b2..6a0c19953cdf4 100644 --- a/packages/flutter/lib/src/rendering/platform_view.dart +++ b/packages/flutter/lib/src/rendering/platform_view.dart @@ -269,41 +269,23 @@ class RenderAndroidView extends PlatformViewRenderBox { } } -/// A render object for an iOS UIKit UIView. -/// -/// [RenderUiKitView] is responsible for sizing and displaying an iOS -/// [UIView](https://developer.apple.com/documentation/uikit/uiview). -/// -/// UIViews are added as sub views of the FlutterView and are composited by Quartz. -/// -/// {@macro flutter.rendering.RenderAndroidView.layout} -/// -/// {@macro flutter.rendering.RenderAndroidView.gestures} +/// Common render-layer functionality for iOS and macOS platform views. /// -/// See also: -/// -/// * [UiKitView] which is a widget that is used to show a UIView. -/// * [PlatformViewsService] which is a service for controlling platform views. -class RenderUiKitView extends RenderBox { - /// Creates a render object for an iOS UIView. - /// - /// The `viewId`, `hitTestBehavior`, and `gestureRecognizers` parameters must not be null. - RenderUiKitView({ - required UiKitViewController viewController, +/// Provides the basic rendering logic for iOS and macOS platformviews. +/// Subclasses shall override handleEvent in order to execute custom event logic. +/// T represents the class of the view controller for the corresponding widget. +abstract class RenderDarwinPlatformView extends RenderBox { + /// Creates a render object for a platform view. + RenderDarwinPlatformView({ + required T viewController, required this.hitTestBehavior, - required Set> gestureRecognizers, - }) : _viewController = viewController { - updateGestureRecognizers(gestureRecognizers); - } + }) : _viewController = viewController; - /// The unique identifier of the UIView controlled by this controller. - /// - /// Typically generated by [PlatformViewsRegistry.getNextPlatformViewId], the UIView - /// must have been created by calling [PlatformViewsService.initUiKitView]. - UiKitViewController get viewController => _viewController; - UiKitViewController _viewController; - set viewController(UiKitViewController value) { + /// The unique identifier of the platform view controlled by this controller. + T get viewController => _viewController; + T _viewController; + set viewController(T value) { if (_viewController == value) { return; } @@ -320,20 +302,6 @@ class RenderUiKitView extends RenderBox { // any newly arriving events there's nothing we need to invalidate. PlatformViewHitTestBehavior hitTestBehavior; - /// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers} - void updateGestureRecognizers(Set> gestureRecognizers) { - assert( - _factoriesTypeSet(gestureRecognizers).length == gestureRecognizers.length, - 'There were multiple gesture recognizer factories for the same type, there must only be a single ' - 'gesture recognizer factory for each gesture recognizer type.', - ); - if (_factoryTypesSetEquals(gestureRecognizers, _gestureRecognizer?.gestureRecognizerFactories)) { - return; - } - _gestureRecognizer?.dispose(); - _gestureRecognizer = _UiKitViewGestureRecognizer(viewController, gestureRecognizers); - } - @override bool get sizedByParent => true; @@ -343,8 +311,6 @@ class RenderUiKitView extends RenderBox { @override bool get isRepaintBoundary => true; - _UiKitViewGestureRecognizer? _gestureRecognizer; - PointerEvent? _lastPointerDownEvent; @override @@ -372,15 +338,6 @@ class RenderUiKitView extends RenderBox { @override bool hitTestSelf(Offset position) => hitTestBehavior != PlatformViewHitTestBehavior.transparent; - @override - void handleEvent(PointerEvent event, HitTestEntry entry) { - if (event is! PointerDownEvent) { - return; - } - _gestureRecognizer!.addPointer(event); - _lastPointerDownEvent = event.original ?? event; - } - // This is registered as a global PointerRoute while the render object is attached. void _handleGlobalPointerEvent(PointerEvent event) { if (event is! PointerDownEvent) { @@ -415,6 +372,69 @@ class RenderUiKitView extends RenderBox { @override void detach() { GestureBinding.instance.pointerRouter.removeGlobalRoute(_handleGlobalPointerEvent); + super.detach(); + } +} + +/// A render object for an iOS UIKit UIView. +/// +/// [RenderUiKitView] is responsible for sizing and displaying an iOS +/// [UIView](https://developer.apple.com/documentation/uikit/uiview). +/// +/// UIViews are added as subviews of the FlutterView and are composited by Quartz. +/// +/// The viewController is typically generated by [PlatformViewsRegistry.getNextPlatformViewId], the UIView +/// must have been created by calling [PlatformViewsService.initUiKitView]. +/// +/// {@macro flutter.rendering.RenderAndroidView.layout} +/// +/// {@macro flutter.rendering.RenderAndroidView.gestures} +/// +/// See also: +/// +/// * [UiKitView], which is a widget that is used to show a UIView. +/// * [PlatformViewsService], which is a service for controlling platform views. +class RenderUiKitView extends RenderDarwinPlatformView { + /// Creates a render object for an iOS UIView. + /// + /// The `viewId`, `hitTestBehavior`, and `gestureRecognizers` parameters must not be null. + RenderUiKitView({ + required super.viewController, + required super.hitTestBehavior, + required Set> gestureRecognizers + }) { + updateGestureRecognizers(gestureRecognizers); + } + + // TODO(schectman): Add gesture functionality to macOS platform view when implemented. + // https://github.com/flutter/flutter/issues/128519 + /// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers} + void updateGestureRecognizers(Set> gestureRecognizers) { + assert( + _factoriesTypeSet(gestureRecognizers).length == gestureRecognizers.length, + 'There were multiple gesture recognizer factories for the same type, there must only be a single ' + 'gesture recognizer factory for each gesture recognizer type.', + ); + if (_factoryTypesSetEquals(gestureRecognizers, _gestureRecognizer?.gestureRecognizerFactories)) { + return; + } + _gestureRecognizer?.dispose(); + _gestureRecognizer = _UiKitViewGestureRecognizer(viewController, gestureRecognizers); + } + + @override + void handleEvent(PointerEvent event, HitTestEntry entry) { + if (event is! PointerDownEvent) { + return; + } + _gestureRecognizer!.addPointer(event); + _lastPointerDownEvent = event.original ?? event; + } + + _UiKitViewGestureRecognizer? _gestureRecognizer; + + @override + void detach() { _gestureRecognizer!.reset(); super.detach(); } diff --git a/packages/flutter/lib/src/services/platform_views.dart b/packages/flutter/lib/src/services/platform_views.dart index a024d6a7642eb..d5e84543758d2 100644 --- a/packages/flutter/lib/src/services/platform_views.dart +++ b/packages/flutter/lib/src/services/platform_views.dart @@ -1313,11 +1313,13 @@ class _HybridAndroidViewControllerInternals extends _AndroidViewControllerIntern } } -/// Controls an iOS UIView. +/// Base class for iOS and macOS view controllers. /// -/// Typically created with [PlatformViewsService.initUiKitView]. -class UiKitViewController { - UiKitViewController._( +/// View controllers are used to create and interact with the UIView or NSView +/// underlying a platform view. +abstract class DarwinPlatformViewController { + /// Public default for subclasses to override. + DarwinPlatformViewController( this.id, TextDirection layoutDirection, ) : _layoutDirection = layoutDirection; @@ -1382,6 +1384,18 @@ class UiKitViewController { } } +/// Controller for an iOS platform view. +/// +/// View controllers create and interact with the underlying UIView. +/// +/// Typically created with [PlatformViewsService.initUiKitView]. +class UiKitViewController extends DarwinPlatformViewController { + UiKitViewController._( + super.id, + super.layoutDirection, + ); +} + /// An interface for controlling a single platform view. /// /// Used by [PlatformViewSurface] to interface with the platform view it embeds. diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index 722a22b983a08..a780994ff68dd 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -195,30 +195,15 @@ class AndroidView extends StatefulWidget { State createState() => _AndroidViewState(); } -// TODO(amirh): describe the embedding mechanism. -// TODO(ychris): remove the documentation for conic path not supported once https://github.com/flutter/flutter/issues/35062 is resolved. -/// Embeds an iOS view in the Widget hierarchy. -/// -/// Embedding iOS views is an expensive operation and should be avoided when a Flutter -/// equivalent is possible. -/// -/// {@macro flutter.widgets.AndroidView.layout} -/// -/// {@macro flutter.widgets.AndroidView.gestures} -/// -/// {@macro flutter.widgets.AndroidView.lifetime} -/// -/// Construction of UIViews is done asynchronously, before the UIView is ready this widget paints -/// nothing while maintaining the same layout constraints. +/// Common superclass for iOS and macOS platform views. /// -/// Clipping operations on a UiKitView can result slow performance. -/// If a conic path clipping is applied to a UIKitView, -/// a quad path is used to approximate the clip due to limitation of Quartz. -class UiKitView extends StatefulWidget { - /// Creates a widget that embeds an iOS view. +/// Platform views are used to embed native views in the widget hierarchy, with +/// support for transforms, clips, and opacity similar to any other Flutter widget. +abstract class _DarwinView extends StatefulWidget { + /// Creates a widget that embeds a platform view. /// /// {@macro flutter.widgets.AndroidView.constructorArgs} - const UiKitView({ + const _DarwinView({ super.key, required this.viewType, this.onPlatformViewCreated, @@ -299,6 +284,41 @@ class UiKitView extends StatefulWidget { // TODO(amirh): get a list of GestureRecognizers here. // https://github.com/flutter/flutter/issues/20953 final Set>? gestureRecognizers; +} + +// TODO(amirh): describe the embedding mechanism. +// TODO(ychris): remove the documentation for conic path not supported once https://github.com/flutter/flutter/issues/35062 is resolved. +/// Embeds an iOS view in the Widget hierarchy. +/// +/// Embedding iOS views is an expensive operation and should be avoided when a Flutter +/// equivalent is possible. +/// +/// {@macro flutter.widgets.AndroidView.layout} +/// +/// {@macro flutter.widgets.AndroidView.gestures} +/// +/// {@macro flutter.widgets.AndroidView.lifetime} +/// +/// Construction of UIViews is done asynchronously, before the UIView is ready this widget paints +/// nothing while maintaining the same layout constraints. +/// +/// Clipping operations on a UiKitView can result slow performance. +/// If a conic path clipping is applied to a UIKitView, +/// a quad path is used to approximate the clip due to limitation of Quartz. +class UiKitView extends _DarwinView { + /// Creates a widget that embeds an iOS view. + /// + /// {@macro flutter.widgets.AndroidView.constructorArgs} + const UiKitView({ + super.key, + required super.viewType, + super.onPlatformViewCreated, + super.hitTestBehavior = PlatformViewHitTestBehavior.opaque, + super.layoutDirection, + super.creationParams, + super.creationParamsCodec, + super.gestureRecognizers, + }) : assert(creationParams == null || creationParamsCodec != null); @override State createState() => _UiKitViewState(); @@ -573,8 +593,8 @@ class _AndroidViewState extends State { } } -class _UiKitViewState extends State { - UiKitViewController? _controller; +abstract class _DarwinViewState, ViewT extends _DarwinPlatformView> extends State { + ControllerT? _controller; TextDirection? _layoutDirection; bool _initialized = false; @@ -586,21 +606,19 @@ class _UiKitViewState extends State { @override Widget build(BuildContext context) { - final UiKitViewController? controller = _controller; + final ControllerT? controller = _controller; if (controller == null) { return const SizedBox.expand(); } return Focus( focusNode: focusNode, onFocusChange: (bool isFocused) => _onFocusChange(isFocused, controller), - child: _UiKitPlatformView( - controller: _controller!, - hitTestBehavior: widget.hitTestBehavior, - gestureRecognizers: widget.gestureRecognizers ?? _emptyRecognizersSet, - ), + child: childPlatformView() ); } + ViewT childPlatformView(); + void _initializeOnce() { if (_initialized) { return; @@ -625,7 +643,7 @@ class _UiKitViewState extends State { } @override - void didUpdateWidget(UiKitView oldWidget) { + void didUpdateWidget(PlatformViewT oldWidget) { super.didUpdateWidget(oldWidget); final TextDirection newLayoutDirection = _findLayoutDirection(); @@ -659,15 +677,8 @@ class _UiKitViewState extends State { Future _createNewUiKitView() async { final int id = platformViewsRegistry.getNextPlatformViewId(); - final UiKitViewController controller = await PlatformViewsService.initUiKitView( - id: id, - viewType: widget.viewType, - layoutDirection: _layoutDirection!, - creationParams: widget.creationParams, - creationParamsCodec: widget.creationParamsCodec, - onFocus: () { - focusNode?.requestFocus(); - } + final ControllerT controller = await createNewViewController( + id ); if (!mounted) { controller.dispose(); @@ -680,7 +691,9 @@ class _UiKitViewState extends State { }); } - void _onFocusChange(bool isFocused, UiKitViewController controller) { + Future createNewViewController(int id); + + void _onFocusChange(bool isFocused, ControllerT controller) { if (!isFocused) { // Unlike Android, we do not need to send "clearFocus" channel message // to the engine, because focusing on another view will automatically @@ -694,6 +707,31 @@ class _UiKitViewState extends State { } } +class _UiKitViewState extends _DarwinViewState { + @override + Future createNewViewController(int id) async { + return PlatformViewsService.initUiKitView( + id: id, + viewType: widget.viewType, + layoutDirection: _layoutDirection!, + creationParams: widget.creationParams, + creationParamsCodec: widget.creationParamsCodec, + onFocus: () { + focusNode?.requestFocus(); + } + ); + } + + @override + _UiKitPlatformView childPlatformView() { + return _UiKitPlatformView( + controller: _controller!, + hitTestBehavior: widget.hitTestBehavior, + gestureRecognizers: widget.gestureRecognizers ?? _DarwinViewState._emptyRecognizersSet, + ); + } +} + class _AndroidPlatformView extends LeafRenderObjectWidget { const _AndroidPlatformView({ required this.controller, @@ -725,17 +763,29 @@ class _AndroidPlatformView extends LeafRenderObjectWidget { } } -class _UiKitPlatformView extends LeafRenderObjectWidget { - const _UiKitPlatformView({ +abstract class _DarwinPlatformView> extends LeafRenderObjectWidget { + const _DarwinPlatformView({ required this.controller, required this.hitTestBehavior, required this.gestureRecognizers, }); - final UiKitViewController controller; + final TController controller; final PlatformViewHitTestBehavior hitTestBehavior; final Set> gestureRecognizers; + @override + @mustCallSuper + void updateRenderObject(BuildContext context, TRender renderObject) { + renderObject + ..viewController = controller + ..hitTestBehavior = hitTestBehavior; + } +} + +class _UiKitPlatformView extends _DarwinPlatformView { + const _UiKitPlatformView({required super.controller, required super.hitTestBehavior, required super.gestureRecognizers}); + @override RenderObject createRenderObject(BuildContext context) { return RenderUiKitView( @@ -747,8 +797,7 @@ class _UiKitPlatformView extends LeafRenderObjectWidget { @override void updateRenderObject(BuildContext context, RenderUiKitView renderObject) { - renderObject.viewController = controller; - renderObject.hitTestBehavior = hitTestBehavior; + super.updateRenderObject(context, renderObject); renderObject.updateGestureRecognizers(gestureRecognizers); } } From 3b0b8348fd3e3f18284a3807badc7d4e571b22b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 11:22:24 -0400 Subject: [PATCH 0225/1547] Roll Flutter Engine from aaec42812a1f to c27658cc5ade (2 revisions) (#130799) https://github.com/flutter/engine/compare/aaec42812a1f...c27658cc5ade 2023-07-18 skia-flutter-autoroll@skia.org Roll Dart SDK from b83a63e0181a to ec95774043ec (1 revision) (flutter/engine#43767) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from a4df72ba04bb to 8d3e00a1f25f (1 revision) (flutter/engine#43766) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5e24b64d3467f..0ecf44f5eec23 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -aaec42812a1f2a7214a10c41af49ee31a538088d +c27658cc5adee7a69f61d6a15d0465c9a82a4c2b From 8b768de18f292bbd534d30ac7b820ae567c9ff48 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 18 Jul 2023 08:26:09 -0700 Subject: [PATCH 0226/1547] Add lint check to make sure samples are linked and have tests (#130523) ## Description This adds a checker that will check all of the API docs examples to make sure that they are linked from at least one source file in the packages. It also checks to make sure that all of the examples have an associated test. Since there are a large number that don't have tests at the moment, there is also a large exception list that can be burned down (burn down list is in https://github.com/flutter/flutter/issues/130459). Because there are missing links currently, this PR will only pass after https://github.com/flutter/flutter/pull/130521 is merged. ## Related Issues - https://github.com/flutter/flutter/issues/129956 - https://github.com/flutter/flutter/issues/130459 ## Tests - Added test for the checker. --- dev/bots/analyze.dart | 7 + dev/bots/analyze_snippet_code.dart | 4 +- dev/bots/check_code_samples.dart | 481 ++++++++++++++++++ dev/bots/pubspec.yaml | 2 +- dev/bots/test/check_code_samples_test.dart | 190 +++++++ .../flutter/lib/src/material/checkbox.dart | 6 + packages/flutter/lib/src/material/drawer.dart | 41 +- 7 files changed, 689 insertions(+), 42 deletions(-) create mode 100644 dev/bots/check_code_samples.dart create mode 100644 dev/bots/test/check_code_samples_test.dart diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index 19056c54f36b1..9e87d94f0e117 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart @@ -187,6 +187,13 @@ Future run(List arguments) async { workingDirectory: flutterRoot, ); + // Make sure that all of the existing samples are linked from at least one API doc comment. + printProgress('Code sample link validation...'); + await runCommand(dart, + ['--enable-asserts', path.join(flutterRoot, 'dev', 'bots', 'check_code_samples.dart')], + workingDirectory: flutterRoot, + ); + // Try analysis against a big version of the gallery; generate into a temporary directory. printProgress('Dart analysis (mega gallery)...'); final Directory outDir = Directory.systemTemp.createTempSync('flutter_mega_gallery.'); diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index 119311239e780..5669f0cb404bd 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -5,7 +5,7 @@ // To run this, from the root of the Flutter repository: // bin/cache/dart-sdk/bin/dart --enable-asserts dev/bots/analyze_snippet_code.dart -// In general, please prefer using full inline examples in API docs. +// In general, please prefer using full linked examples in API docs. // // For documentation on creating sample code, see ../../examples/api/README.md // See also our style guide's discussion on documentation and sample code: @@ -13,7 +13,7 @@ // // This tool is used to analyze smaller snippets of code in the API docs. // Such snippets are wrapped in ```dart ... ``` blocks, which may themselves -// be wrapped in {@tool snippet} ... {@endtool} blocks to set them apart +// be wrapped in {@tool snippet} ... {@end-tool} blocks to set them apart // in the rendered output. // // Such snippets: diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart new file mode 100644 index 0000000000000..0ffd56e510797 --- /dev/null +++ b/dev/bots/check_code_samples.dart @@ -0,0 +1,481 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// To run this, from the root of the Flutter repository: +// bin/cache/dart-sdk/bin/dart --enable-asserts dev/bots/check_code_sample_links.dart + +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:path/path.dart' as path; + +import 'utils.dart'; + +final String _scriptLocation = path.fromUri(Platform.script); +final String _flutterRoot = path.dirname(path.dirname(path.dirname(_scriptLocation))); +final String _exampleDirectoryPath = path.join(_flutterRoot, 'examples', 'api'); +final String _packageDirectoryPath = path.join(_flutterRoot, 'packages'); +final String _dartUIDirectoryPath = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib'); + +final List _knownUnlinkedExamples = [ + // These are template files that aren't expected to be linked. + 'examples/api/lib/sample_templates/cupertino.0.dart', + 'examples/api/lib/sample_templates/widgets.0.dart', + 'examples/api/lib/sample_templates/material.0.dart', +]; + +void main(List args) { + final ArgParser argParser = ArgParser(); + argParser.addFlag( + 'help', + negatable: false, + help: 'Print help for this command.', + ); + argParser.addOption( + 'examples', + valueHelp: 'path', + defaultsTo: _exampleDirectoryPath, + help: 'A location where the API doc examples are found.', + ); + argParser.addOption( + 'packages', + valueHelp: 'path', + defaultsTo: _packageDirectoryPath, + help: 'A location where the source code that should link the API doc examples is found.', + ); + argParser.addOption( + 'dart-ui', + valueHelp: 'path', + defaultsTo: _dartUIDirectoryPath, + help: 'A location where the source code that should link the API doc examples is found.', + ); + argParser.addOption( + 'flutter-root', + valueHelp: 'path', + defaultsTo: _flutterRoot, + help: 'The path to the root of the Flutter repo.', + ); + final ArgResults parsedArgs; + + void usage() { + print('dart --enable-asserts ${path.basename(_scriptLocation)} [options]'); + print(argParser.usage); + } + + try { + parsedArgs = argParser.parse(args); + } on FormatException catch (e) { + print(e.message); + usage(); + exit(1); + } + + if (parsedArgs['help'] as bool) { + usage(); + exit(0); + } + + const FileSystem filesystem = LocalFileSystem(); + final Directory examples = filesystem.directory(parsedArgs['examples']! as String); + final Directory packages = filesystem.directory(parsedArgs['packages']! as String); + final Directory dartUIPath = filesystem.directory(parsedArgs['dart-ui']! as String); + final Directory flutterRoot = filesystem.directory(parsedArgs['flutter-root']! as String); + + final SampleChecker checker = SampleChecker( + examples: examples, + packages: packages, + dartUIPath: dartUIPath, + flutterRoot: flutterRoot, + ); + + if (!checker.checkCodeSamples()) { + reportErrorsAndExit('Some errors were found in the API docs code samples.'); + } + reportSuccessAndExit('All examples are linked and have tests.'); +} + +class SampleChecker { + SampleChecker({ + required this.examples, + required this.packages, + required this.dartUIPath, + required this.flutterRoot, + this.filesystem = const LocalFileSystem(), + }); + + final Directory examples; + final Directory packages; + final Directory dartUIPath; + final Directory flutterRoot; + final FileSystem filesystem; + + bool checkCodeSamples() { + filesystem.currentDirectory = flutterRoot; + + // Get a list of all the filenames in the source directory that end in "[0-9]+.dart". + final List exampleFilenames = getExampleFilenames(examples); + + // Get a list of all the example link paths that appear in the source files. + final Set exampleLinks = getExampleLinks(packages); + + // Also add in any that might be found in the dart:ui directory. + exampleLinks.addAll(getExampleLinks(dartUIPath)); + + // Get a list of the filenames that were not found in the source files. + final List missingFilenames = checkForMissingLinks(exampleFilenames, exampleLinks); + + // Get a list of any tests that are missing, as well as any that used to be + // missing, but have been implemented. + final (List missingTests, List noLongerMissing) = checkForMissingTests(exampleFilenames); + + // Remove any that we know are exceptions (examples that aren't expected to be + // linked into any source files). These are typically template files used to + // generate new examples. + missingFilenames.removeWhere((String file) => _knownUnlinkedExamples.contains(file)); + + if (missingFilenames.isEmpty && missingTests.isEmpty && noLongerMissing.isEmpty) { + return true; + } + + if (noLongerMissing.isNotEmpty) { + final StringBuffer buffer = StringBuffer('The following tests have been implemented! Huzzah!:\n'); + for (final File name in noLongerMissing) { + buffer.writeln(' ${getRelativePath(name)}'); + } + buffer.writeln('However, they now need to be removed from the _knownMissingTests'); + buffer.write('list in the script $_scriptLocation.'); + foundError(buffer.toString().split('\n')); + } + + if (missingTests.isNotEmpty) { + final StringBuffer buffer = StringBuffer('The following example test files are missing:\n'); + for (final File name in missingTests) { + buffer.writeln(' ${getRelativePath(name)}'); + } + foundError(buffer.toString().trimRight().split('\n')); + } + + if (missingFilenames.isNotEmpty) { + final StringBuffer buffer = + StringBuffer('The following examples are not linked from any source file API doc comments:\n'); + for (final String name in missingFilenames) { + buffer.writeln(' $name'); + } + buffer.write('Either link them to a source file API doc comment, or remove them.'); + foundError(buffer.toString().split('\n')); + } + return false; + } + + String getRelativePath(File file, [Directory? root]) { + root ??= flutterRoot; + return path.relative(file.absolute.path, from: root.absolute.path); + } + + List getFiles(Directory directory, [Pattern? filenamePattern]) { + final List filenames = directory + .listSync(recursive: true) + .map((FileSystemEntity entity) { + if (entity is File) { + return entity; + } else { + return null; + } + }) + .where((File? filename) => + filename != null && (filenamePattern == null || filename.absolute.path.contains(filenamePattern))) + .map((File? s) => s!) + .toList(); + return filenames; + } + + List getExampleFilenames(Directory directory) { + return getFiles( + directory.childDirectory('lib'), + RegExp(r'\d+\.dart$'), + ); + } + + Set getExampleLinks(Directory searchDirectory) { + final List files = getFiles(searchDirectory, RegExp(r'\.dart$')); + final Set searchStrings = {}; + final RegExp exampleRe = RegExp(r'\*\* See code in (?.*) \*\*'); + for (final File file in files) { + final String contents = file.readAsStringSync(); + searchStrings.addAll( + contents.split('\n').where((String s) => s.contains(exampleRe)).map( + (String e) { + return exampleRe.firstMatch(e)!.namedGroup('path')!; + }, + ), + ); + } + return searchStrings; + } + + List checkForMissingLinks(List exampleFilenames, Set searchStrings) { + final List missingFilenames = []; + for (final File example in exampleFilenames) { + final String relativePath = getRelativePath(example); + if (!searchStrings.contains(relativePath)) { + missingFilenames.add(relativePath); + } + } + return missingFilenames; + } + + String getTestNameForExample(File example, Directory examples) { + final String testPath = path.dirname( + path.join( + examples.absolute.path, + 'test', + getRelativePath(example, examples.childDirectory('lib')), + ), + ); + return '${path.join(testPath, path.basenameWithoutExtension(example.path))}_test.dart'; + } + + (List, List) checkForMissingTests(List exampleFilenames) { + final List missingTests = []; + final List noLongerMissingTests = []; + for (final File example in exampleFilenames) { + final File testFile = filesystem.file(getTestNameForExample(example, examples)); + final String name = path.relative(testFile.absolute.path, from: flutterRoot.absolute.path); + if (!testFile.existsSync()) { + missingTests.add(testFile); + } else if (_knownMissingTests.contains(name.replaceAll(r'\', '/'))) { + noLongerMissingTests.add(testFile); + } + } + // Skip any that we know are missing. + missingTests.removeWhere( + (File test) { + final String name = path.relative(test.absolute.path, from: flutterRoot.absolute.path).replaceAll(r'\', '/'); + return _knownMissingTests.contains(name); + }, + ); + return (missingTests, noLongerMissingTests); + } +} + +// These tests are known to be missing. They should all eventually be +// implemented, but until they are we allow them, so that we can catch any new +// examples that are added without tests. +// +// TODO(gspencergoog): implement the missing tests. +// See https://github.com/flutter/flutter/issues/130459 +final Set _knownMissingTests = { + 'examples/api/test/cupertino/text_field/cupertino_text_field.0_test.dart', + 'examples/api/test/material/bottom_app_bar/bottom_app_bar.2_test.dart', + 'examples/api/test/material/bottom_app_bar/bottom_app_bar.1_test.dart', + 'examples/api/test/material/theme/theme_extension.1_test.dart', + 'examples/api/test/material/elevated_button/elevated_button.0_test.dart', + 'examples/api/test/material/material_state/material_state_border_side.0_test.dart', + 'examples/api/test/material/material_state/material_state_mouse_cursor.0_test.dart', + 'examples/api/test/material/material_state/material_state_outlined_border.0_test.dart', + 'examples/api/test/material/material_state/material_state_property.0_test.dart', + 'examples/api/test/material/selectable_region/selectable_region.0_test.dart', + 'examples/api/test/material/text_field/text_field.2_test.dart', + 'examples/api/test/material/text_field/text_field.1_test.dart', + 'examples/api/test/material/button_style/button_style.0_test.dart', + 'examples/api/test/material/range_slider/range_slider.0_test.dart', + 'examples/api/test/material/card/card.2_test.dart', + 'examples/api/test/material/card/card.0_test.dart', + 'examples/api/test/material/selection_container/selection_container_disabled.0_test.dart', + 'examples/api/test/material/selection_container/selection_container.0_test.dart', + 'examples/api/test/material/color_scheme/dynamic_content_color.0_test.dart', + 'examples/api/test/material/platform_menu_bar/platform_menu_bar.0_test.dart', + 'examples/api/test/material/menu_anchor/menu_anchor.2_test.dart', + 'examples/api/test/material/stepper/stepper.controls_builder.0_test.dart', + 'examples/api/test/material/stepper/stepper.0_test.dart', + 'examples/api/test/material/flexible_space_bar/flexible_space_bar.0_test.dart', + 'examples/api/test/material/data_table/data_table.1_test.dart', + 'examples/api/test/material/data_table/data_table.0_test.dart', + 'examples/api/test/material/floating_action_button_location/standard_fab_location.0_test.dart', + 'examples/api/test/material/chip/deletable_chip_attributes.on_deleted.0_test.dart', + 'examples/api/test/material/snack_bar/snack_bar.0_test.dart', + 'examples/api/test/material/snack_bar/snack_bar.2_test.dart', + 'examples/api/test/material/snack_bar/snack_bar.1_test.dart', + 'examples/api/test/material/bottom_navigation_bar/bottom_navigation_bar.0_test.dart', + 'examples/api/test/material/bottom_navigation_bar/bottom_navigation_bar.1_test.dart', + 'examples/api/test/material/outlined_button/outlined_button.0_test.dart', + 'examples/api/test/material/icon_button/icon_button.2_test.dart', + 'examples/api/test/material/icon_button/icon_button.3_test.dart', + 'examples/api/test/material/icon_button/icon_button.0_test.dart', + 'examples/api/test/material/icon_button/icon_button.1_test.dart', + 'examples/api/test/material/expansion_panel/expansion_panel_list.0_test.dart', + 'examples/api/test/material/expansion_panel/expansion_panel_list.expansion_panel_list_radio.0_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.1_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.prefix_icon_constraints.0_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.material_state.0_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.2_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.0_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.label.0_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.suffix_icon_constraints.0_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.3_test.dart', + 'examples/api/test/material/input_decorator/input_decoration.material_state.1_test.dart', + 'examples/api/test/material/filled_button/filled_button.0_test.dart', + 'examples/api/test/material/text_form_field/text_form_field.1_test.dart', + 'examples/api/test/material/scrollbar/scrollbar.1_test.dart', + 'examples/api/test/material/scrollbar/scrollbar.0_test.dart', + 'examples/api/test/material/dropdown_menu/dropdown_menu.1_test.dart', + 'examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart', + 'examples/api/test/material/radio/radio.toggleable.0_test.dart', + 'examples/api/test/material/radio/radio.0_test.dart', + 'examples/api/test/material/search_anchor/search_anchor.0_test.dart', + 'examples/api/test/material/search_anchor/search_anchor.1_test.dart', + 'examples/api/test/material/search_anchor/search_anchor.2_test.dart', + 'examples/api/test/material/about/about_list_tile.0_test.dart', + 'examples/api/test/material/tab_controller/tab_controller.1_test.dart', + 'examples/api/test/material/selection_area/selection_area.0_test.dart', + 'examples/api/test/material/scaffold/scaffold.end_drawer.0_test.dart', + 'examples/api/test/material/scaffold/scaffold.drawer.0_test.dart', + 'examples/api/test/material/scaffold/scaffold.1_test.dart', + 'examples/api/test/material/scaffold/scaffold.of.0_test.dart', + 'examples/api/test/material/scaffold/scaffold_messenger.of.0_test.dart', + 'examples/api/test/material/scaffold/scaffold_messenger.0_test.dart', + 'examples/api/test/material/scaffold/scaffold.0_test.dart', + 'examples/api/test/material/scaffold/scaffold_state.show_bottom_sheet.0_test.dart', + 'examples/api/test/material/scaffold/scaffold.2_test.dart', + 'examples/api/test/material/scaffold/scaffold_messenger_state.show_material_banner.0_test.dart', + 'examples/api/test/material/scaffold/scaffold.of.1_test.dart', + 'examples/api/test/material/scaffold/scaffold_messenger.of.1_test.dart', + 'examples/api/test/material/scaffold/scaffold_messenger_state.show_snack_bar.0_test.dart', + 'examples/api/test/material/segmented_button/segmented_button.0_test.dart', + 'examples/api/test/material/app_bar/app_bar.2_test.dart', + 'examples/api/test/material/app_bar/sliver_app_bar.1_test.dart', + 'examples/api/test/material/app_bar/sliver_app_bar.2_test.dart', + 'examples/api/test/material/app_bar/sliver_app_bar.3_test.dart', + 'examples/api/test/material/app_bar/app_bar.1_test.dart', + 'examples/api/test/material/app_bar/sliver_app_bar.4_test.dart', + 'examples/api/test/material/app_bar/app_bar.3_test.dart', + 'examples/api/test/material/app_bar/app_bar.0_test.dart', + 'examples/api/test/material/ink_well/ink_well.0_test.dart', + 'examples/api/test/material/banner/material_banner.1_test.dart', + 'examples/api/test/material/banner/material_banner.0_test.dart', + 'examples/api/test/material/checkbox/checkbox.1_test.dart', + 'examples/api/test/material/checkbox/checkbox.0_test.dart', + 'examples/api/test/material/navigation_rail/navigation_rail.extended_animation.0_test.dart', + 'examples/api/test/material/text_button/text_button.0_test.dart', + 'examples/api/test/rendering/growth_direction/growth_direction.0_test.dart', + 'examples/api/test/rendering/sliver_grid/sliver_grid_delegate_with_fixed_cross_axis_count.0_test.dart', + 'examples/api/test/rendering/sliver_grid/sliver_grid_delegate_with_fixed_cross_axis_count.1_test.dart', + 'examples/api/test/rendering/scroll_direction/scroll_direction.0_test.dart', + 'examples/api/test/painting/axis_direction/axis_direction.0_test.dart', + 'examples/api/test/painting/linear_border/linear_border.0_test.dart', + 'examples/api/test/painting/gradient/linear_gradient.0_test.dart', + 'examples/api/test/painting/star_border/star_border.0_test.dart', + 'examples/api/test/painting/borders/border_side.stroke_align.0_test.dart', + 'examples/api/test/widgets/autocomplete/raw_autocomplete.focus_node.0_test.dart', + 'examples/api/test/widgets/autocomplete/raw_autocomplete.2_test.dart', + 'examples/api/test/widgets/autocomplete/raw_autocomplete.1_test.dart', + 'examples/api/test/widgets/autocomplete/raw_autocomplete.0_test.dart', + 'examples/api/test/widgets/navigator/navigator.restorable_push_and_remove_until.0_test.dart', + 'examples/api/test/widgets/navigator/navigator.0_test.dart', + 'examples/api/test/widgets/navigator/navigator.restorable_push.0_test.dart', + 'examples/api/test/widgets/navigator/navigator_state.restorable_push_replacement.0_test.dart', + 'examples/api/test/widgets/navigator/navigator_state.restorable_push_and_remove_until.0_test.dart', + 'examples/api/test/widgets/navigator/navigator.restorable_push_replacement.0_test.dart', + 'examples/api/test/widgets/navigator/restorable_route_future.0_test.dart', + 'examples/api/test/widgets/navigator/navigator_state.restorable_push.0_test.dart', + 'examples/api/test/widgets/focus_manager/focus_node.unfocus.0_test.dart', + 'examples/api/test/widgets/focus_manager/focus_node.0_test.dart', + 'examples/api/test/widgets/framework/build_owner.0_test.dart', + 'examples/api/test/widgets/framework/error_widget.0_test.dart', + 'examples/api/test/widgets/inherited_theme/inherited_theme.0_test.dart', + 'examples/api/test/widgets/sliver/decorated_sliver.0_test.dart', + 'examples/api/test/widgets/autofill/autofill_group.0_test.dart', + 'examples/api/test/widgets/drag_target/draggable.0_test.dart', + 'examples/api/test/widgets/shared_app_data/shared_app_data.1_test.dart', + 'examples/api/test/widgets/shared_app_data/shared_app_data.0_test.dart', + 'examples/api/test/widgets/form/form.0_test.dart', + 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view_state.0_test.dart', + 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view.2_test.dart', + 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view.1_test.dart', + 'examples/api/test/widgets/nested_scroll_view/nested_scroll_view.0_test.dart', + 'examples/api/test/widgets/page_view/page_view.0_test.dart', + 'examples/api/test/widgets/scroll_position/scroll_metrics_notification.0_test.dart', + 'examples/api/test/widgets/media_query/media_query_data.system_gesture_insets.0_test.dart', + 'examples/api/test/widgets/async/stream_builder.0_test.dart', + 'examples/api/test/widgets/async/future_builder.0_test.dart', + 'examples/api/test/widgets/restoration_properties/restorable_value.0_test.dart', + 'examples/api/test/widgets/animated_size/animated_size.0_test.dart', + 'examples/api/test/widgets/table/table.0_test.dart', + 'examples/api/test/widgets/animated_switcher/animated_switcher.0_test.dart', + 'examples/api/test/widgets/transitions/relative_positioned_transition.0_test.dart', + 'examples/api/test/widgets/transitions/positioned_transition.0_test.dart', + 'examples/api/test/widgets/transitions/listenable_builder.3_test.dart', + 'examples/api/test/widgets/transitions/sliver_fade_transition.0_test.dart', + 'examples/api/test/widgets/transitions/align_transition.0_test.dart', + 'examples/api/test/widgets/transitions/fade_transition.0_test.dart', + 'examples/api/test/widgets/transitions/animated_builder.0_test.dart', + 'examples/api/test/widgets/transitions/rotation_transition.0_test.dart', + 'examples/api/test/widgets/transitions/animated_widget.0_test.dart', + 'examples/api/test/widgets/transitions/slide_transition.0_test.dart', + 'examples/api/test/widgets/transitions/listenable_builder.2_test.dart', + 'examples/api/test/widgets/transitions/scale_transition.0_test.dart', + 'examples/api/test/widgets/transitions/default_text_style_transition.0_test.dart', + 'examples/api/test/widgets/transitions/decorated_box_transition.0_test.dart', + 'examples/api/test/widgets/transitions/size_transition.0_test.dart', + 'examples/api/test/widgets/animated_list/animated_list.0_test.dart', + 'examples/api/test/widgets/focus_traversal/focus_traversal_group.0_test.dart', + 'examples/api/test/widgets/focus_traversal/ordered_traversal_policy.0_test.dart', + 'examples/api/test/widgets/image/image.error_builder.0_test.dart', + 'examples/api/test/widgets/image/image.frame_builder.0_test.dart', + 'examples/api/test/widgets/image/image.loading_builder.0_test.dart', + 'examples/api/test/widgets/shortcuts/logical_key_set.0_test.dart', + 'examples/api/test/widgets/shortcuts/shortcuts.0_test.dart', + 'examples/api/test/widgets/shortcuts/single_activator.single_activator.0_test.dart', + 'examples/api/test/widgets/shortcuts/shortcuts.1_test.dart', + 'examples/api/test/widgets/shortcuts/character_activator.0_test.dart', + 'examples/api/test/widgets/shortcuts/callback_shortcuts.0_test.dart', + 'examples/api/test/widgets/page_storage/page_storage.0_test.dart', + 'examples/api/test/widgets/scrollbar/raw_scrollbar.1_test.dart', + 'examples/api/test/widgets/scrollbar/raw_scrollbar.2_test.dart', + 'examples/api/test/widgets/scrollbar/raw_scrollbar.desktop.0_test.dart', + 'examples/api/test/widgets/scrollbar/raw_scrollbar.shape.0_test.dart', + 'examples/api/test/widgets/scrollbar/raw_scrollbar.0_test.dart', + 'examples/api/test/widgets/sliver_fill/sliver_fill_remaining.2_test.dart', + 'examples/api/test/widgets/sliver_fill/sliver_fill_remaining.1_test.dart', + 'examples/api/test/widgets/sliver_fill/sliver_fill_remaining.3_test.dart', + 'examples/api/test/widgets/sliver_fill/sliver_fill_remaining.0_test.dart', + 'examples/api/test/widgets/interactive_viewer/interactive_viewer.constrained.0_test.dart', + 'examples/api/test/widgets/interactive_viewer/interactive_viewer.transformation_controller.0_test.dart', + 'examples/api/test/widgets/interactive_viewer/interactive_viewer.0_test.dart', + 'examples/api/test/widgets/notification_listener/notification.0_test.dart', + 'examples/api/test/widgets/gesture_detector/gesture_detector.1_test.dart', + 'examples/api/test/widgets/gesture_detector/gesture_detector.0_test.dart', + 'examples/api/test/widgets/editable_text/text_editing_controller.0_test.dart', + 'examples/api/test/widgets/editable_text/editable_text.on_changed.0_test.dart', + 'examples/api/test/widgets/undo_history/undo_history_controller.0_test.dart', + 'examples/api/test/widgets/overscroll_indicator/glowing_overscroll_indicator.1_test.dart', + 'examples/api/test/widgets/overscroll_indicator/glowing_overscroll_indicator.0_test.dart', + 'examples/api/test/widgets/tween_animation_builder/tween_animation_builder.0_test.dart', + 'examples/api/test/widgets/single_child_scroll_view/single_child_scroll_view.1_test.dart', + 'examples/api/test/widgets/single_child_scroll_view/single_child_scroll_view.0_test.dart', + 'examples/api/test/widgets/overflow_bar/overflow_bar.0_test.dart', + 'examples/api/test/widgets/restoration/restoration_mixin.0_test.dart', + 'examples/api/test/widgets/actions/actions.0_test.dart', + 'examples/api/test/widgets/actions/action_listener.0_test.dart', + 'examples/api/test/widgets/actions/focusable_action_detector.0_test.dart', + 'examples/api/test/widgets/color_filter/color_filtered.0_test.dart', + 'examples/api/test/widgets/focus_scope/focus.2_test.dart', + 'examples/api/test/widgets/focus_scope/focus.0_test.dart', + 'examples/api/test/widgets/focus_scope/focus.1_test.dart', + 'examples/api/test/widgets/focus_scope/focus_scope.0_test.dart', + 'examples/api/test/widgets/implicit_animations/animated_fractionally_sized_box.0_test.dart', + 'examples/api/test/widgets/implicit_animations/animated_align.0_test.dart', + 'examples/api/test/widgets/implicit_animations/animated_positioned.0_test.dart', + 'examples/api/test/widgets/implicit_animations/animated_padding.0_test.dart', + 'examples/api/test/widgets/implicit_animations/sliver_animated_opacity.0_test.dart', + 'examples/api/test/widgets/implicit_animations/animated_container.0_test.dart', + 'examples/api/test/widgets/dismissible/dismissible.0_test.dart', + 'examples/api/test/widgets/scroll_view/custom_scroll_view.1_test.dart', + 'examples/api/test/widgets/preferred_size/preferred_size.0_test.dart', + 'examples/api/test/widgets/inherited_notifier/inherited_notifier.0_test.dart', + 'examples/api/test/animation/curves/curve2_d.0_test.dart', + 'examples/api/test/gestures/pointer_signal_resolver/pointer_signal_resolver.0_test.dart', +}; diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 970d1e1a6ef82..c992ede277c44 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -8,6 +8,7 @@ dependencies: args: 2.4.2 crypto: 3.0.3 intl: 0.18.1 + file: 6.1.4 flutter_devicelab: path: ../devicelab http_parser: 4.0.2 @@ -29,7 +30,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" diff --git a/dev/bots/test/check_code_samples_test.dart b/dev/bots/test/check_code_samples_test.dart new file mode 100644 index 0000000000000..2fcae906f37fa --- /dev/null +++ b/dev/bots/test/check_code_samples_test.dart @@ -0,0 +1,190 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:path/path.dart' as path; + +import '../check_code_samples.dart'; +import '../utils.dart'; +import 'common.dart'; + +void main() { + late SampleChecker checker; + late FileSystem fs; + late Directory examples; + late Directory packages; + late Directory dartUIPath; + late Directory flutterRoot; + + String getRelativePath(File file, [Directory? from]) { + from ??= flutterRoot; + return path.relative(file.absolute.path, from: flutterRoot.absolute.path); + } + + void writeLink({required File source, required File example}) { + source + ..createSync(recursive: true) + ..writeAsStringSync(''' +/// Class documentation +/// +/// {@tool dartpad} +/// Example description +/// +/// ** See code in ${getRelativePath(example)} ** +/// {@end-tool} +'''); + } + + void buildTestFiles({bool missingLinks = false, bool missingTests = false}) { + final Directory examplesLib = examples.childDirectory('lib').childDirectory('layer')..createSync(recursive: true); + final File fooExample = examplesLib.childFile('foo_example.0.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// Example for foo'); + final File barExample = examplesLib.childFile('bar_example.0.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// Example for bar'); + final File curvesExample = + examples.childDirectory('lib').childDirectory('animation').childDirectory('curves').childFile('curve2_d.0.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// Missing a test, but OK'); + if (missingLinks) { + examplesLib.childFile('missing_example.0.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// Example that is not linked'); + } + final Directory examplesTests = examples.childDirectory('test').childDirectory('layer') + ..createSync(recursive: true); + examplesTests.childFile('foo_example.0_test.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// test for foo example'); + if (!missingTests) { + examplesTests.childFile('bar_example.0_test.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// test for bar example'); + } + if (missingLinks) { + examplesTests.childFile('missing_example.0_test.dart') + ..createSync(recursive: true) + ..writeAsStringSync('// test for foo example'); + } + final Directory flutterPackage = packages.childDirectory('flutter').childDirectory('lib').childDirectory('src') + ..createSync(recursive: true); + writeLink(source: flutterPackage.childDirectory('layer').childFile('foo.dart'), example: fooExample); + writeLink(source: flutterPackage.childDirectory('layer').childFile('bar.dart'), example: barExample); + writeLink(source: flutterPackage.childDirectory('animation').childFile('curves.dart'), example: curvesExample); + } + + setUp(() { + fs = MemoryFileSystem(style: Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix); + // Get the root prefix of the current directory so that on Windows we get a + // correct root prefix. + flutterRoot = fs.directory(path.join(path.rootPrefix(fs.currentDirectory.absolute.path), 'flutter sdk'))..createSync(recursive: true); + fs.currentDirectory = flutterRoot; + examples = flutterRoot.childDirectory('examples').childDirectory('api')..createSync(recursive: true); + packages = flutterRoot.childDirectory('packages')..createSync(recursive: true); + dartUIPath = flutterRoot + .childDirectory('bin') + .childDirectory('cache') + .childDirectory('pkg') + .childDirectory('sky_engine') + .childDirectory('lib') + ..createSync(recursive: true); + checker = SampleChecker( + examples: examples, + packages: packages, + dartUIPath: dartUIPath, + flutterRoot: flutterRoot, + filesystem: fs, + ); + }); + + test('check_code_samples.dart - checkCodeSamples catches missing links', () async { + buildTestFiles(missingLinks: true); + bool? success; + final String result = await capture( + () async { + success = checker.checkCodeSamples(); + }, + shouldHaveErrors: true, + ); + final String lines = [ + '╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════', + '║ The following examples are not linked from any source file API doc comments:', + '║ examples/api/lib/layer/missing_example.0.dart', + '║ Either link them to a source file API doc comment, or remove them.', + '╚═══════════════════════════════════════════════════════════════════════════════', + ].map((String line) { + return line.replaceAll('/', Platform.isWindows ? r'\' : '/'); + }).join('\n'); + expect(result, equals('$lines\n')); + expect(success, equals(false)); + }); + + test('check_code_samples.dart - checkCodeSamples catches missing tests', () async { + buildTestFiles(missingTests: true); + bool? success; + final String result = await capture( + () async { + success = checker.checkCodeSamples(); + }, + shouldHaveErrors: true, + ); + final String lines = [ + '╔═╡ERROR╞═══════════════════════════════════════════════════════════════════════', + '║ The following example test files are missing:', + '║ examples/api/test/layer/bar_example.0_test.dart', + '╚═══════════════════════════════════════════════════════════════════════════════', + ].map((String line) { + return line.replaceAll('/', Platform.isWindows ? r'\' : '/'); + }).join('\n'); + expect(result, equals('$lines\n')); + expect(success, equals(false)); + }); + + test('check_code_samples.dart - checkCodeSamples succeeds', () async { + buildTestFiles(); + bool? success; + final String result = await capture( + () async { + success = checker.checkCodeSamples(); + }, + ); + expect(result, isEmpty); + expect(success, equals(true)); + }); +} + +typedef AsyncVoidCallback = Future Function(); + +Future capture(AsyncVoidCallback callback, {bool shouldHaveErrors = false}) async { + final StringBuffer buffer = StringBuffer(); + final PrintCallback oldPrint = print; + try { + print = (Object? line) { + buffer.writeln(line); + }; + await callback(); + expect( + hasError, + shouldHaveErrors, + reason: buffer.isEmpty + ? '(No output to report.)' + : hasError + ? 'Unexpected errors:\n$buffer' + : 'Unexpected success:\n$buffer', + ); + } finally { + print = oldPrint; + resetErrorStatus(); + } + if (stdout.supportsAnsiEscapes) { + // Remove ANSI escapes when this test is running on a terminal. + return buffer.toString().replaceAll(RegExp(r'(\x9B|\x1B\[)[0-?]{1,3}[ -/]*[@-~]'), ''); + } else { + return buffer.toString(); + } +} diff --git a/packages/flutter/lib/src/material/checkbox.dart b/packages/flutter/lib/src/material/checkbox.dart index bfead13fe1d83..518351ae9cd1f 100644 --- a/packages/flutter/lib/src/material/checkbox.dart +++ b/packages/flutter/lib/src/material/checkbox.dart @@ -44,6 +44,12 @@ enum _CheckboxType { material, adaptive } /// ** See code in examples/api/lib/material/checkbox/checkbox.0.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This example shows what the checkbox error state looks like. +/// +/// ** See code in examples/api/lib/material/checkbox/checkbox.1.dart ** +/// {@end-tool} +/// /// See also: /// /// * [CheckboxListTile], which combines this widget with a [ListTile] so that diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index ecaecb2c0d482..c2b78ce0973f9 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -90,50 +90,13 @@ const Duration _kBaseSettleDuration = Duration(milliseconds: 246); /// The [Drawer] displays the four items using a [ListView], which allows the /// user to scroll through the items if need be. /// -/// ```dart -/// Scaffold( -/// appBar: AppBar( -/// title: const Text('Drawer Demo'), -/// ), -/// drawer: Drawer( -/// child: ListView( -/// padding: EdgeInsets.zero, -/// children: const [ -/// DrawerHeader( -/// decoration: BoxDecoration( -/// color: Colors.blue, -/// ), -/// child: Text( -/// 'Drawer Header', -/// style: TextStyle( -/// color: Colors.white, -/// fontSize: 24, -/// ), -/// ), -/// ), -/// ListTile( -/// leading: Icon(Icons.message), -/// title: Text('Messages'), -/// ), -/// ListTile( -/// leading: Icon(Icons.account_circle), -/// title: Text('Profile'), -/// ), -/// ListTile( -/// leading: Icon(Icons.settings), -/// title: Text('Settings'), -/// ), -/// ], -/// ), -/// ), -/// ) -/// ``` +/// ** See code in examples/api/lib/material/drawer/drawer.0.dart ** /// {@end-tool} /// /// {@tool snippet} /// This example shows how to migrate the above [Drawer] to a [NavigationDrawer]. /// -/// See code in examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart ** +/// ** See code in examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart ** /// {@end-tool} /// /// An open drawer may be closed with a swipe to close gesture, pressing the From 86385dce684e7c340ce457a382832ccb5cffde9a Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Tue, 18 Jul 2023 18:13:48 +0200 Subject: [PATCH 0227/1547] Update app tests for M3 (#130792) This PR updates unit tests from `app_test.dart` for M3 migration. More info in https://github.com/flutter/flutter/issues/127064 The diff is somewhat misleading because third test in the original code is now the fourth in the updated one, but because they were very similar git diff does not reflect this swap. And also, first test is M2 only and last one M3 only. --- packages/flutter/test/material/app_test.dart | 140 +++++++++---------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index d4dad0cb59df0..108970ae20061 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -979,7 +979,7 @@ void main() { expect(themeAfterBrightnessChange!.brightness, Brightness.dark); }); - testWidgets('MaterialApp provides default overscroll color', (WidgetTester tester) async { + testWidgets('Material2 - MaterialApp provides default overscroll color', (WidgetTester tester) async { Future slowDrag(WidgetTester tester, Offset start, Offset offset) async { final TestGesture gesture = await tester.startGesture(start); for (int index = 0; index < 10; index += 1) { @@ -1262,7 +1262,7 @@ void main() { expect(scrollBehavior.getScrollPhysics(capturedContext).runtimeType, NeverScrollableScrollPhysics); }); - testWidgets('ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { + testWidgets('Material2 - ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), scrollBehavior: const MaterialScrollBehavior(), @@ -1281,9 +1281,10 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsOneWidget); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async { + testWidgets('Material3 - ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( - scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), + theme: ThemeData(useMaterial3: true), + scrollBehavior: const MaterialScrollBehavior(), home: ListView( children: const [ SizedBox( @@ -1299,9 +1300,9 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('ScrollBehavior stretch android overscroll indicator via useMaterial3 flag', (WidgetTester tester) async { + testWidgets('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( - theme: ThemeData(useMaterial3: true), + scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), home: ListView( children: const [ SizedBox( @@ -1356,81 +1357,80 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets( - 'ListView clip behavior updates overscroll indicator clip behavior', (WidgetTester tester) async { - Widget buildFrame(Clip clipBehavior) { - return MaterialApp( - theme: ThemeData(useMaterial3: true), - home: Column( - children: [ - SizedBox( - height: 300, - child: ListView.builder( - itemCount: 20, - clipBehavior: clipBehavior, - itemBuilder: (BuildContext context, int index){ - return Padding( - padding: const EdgeInsets.all(10.0), - child: Text('Index $index'), - ); - }, - ), + testWidgets('Material3 - ListView clip behavior updates overscroll indicator clip behavior', (WidgetTester tester) async { + Widget buildFrame(Clip clipBehavior) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Column( + children: [ + SizedBox( + height: 300, + child: ListView.builder( + itemCount: 20, + clipBehavior: clipBehavior, + itemBuilder: (BuildContext context, int index){ + return Padding( + padding: const EdgeInsets.all(10.0), + child: Text('Index $index'), + ); + }, ), - Opacity( - opacity: 0.5, - child: Container( - color: const Color(0xD0FF0000), - height: 100, - ), + ), + Opacity( + opacity: 0.5, + child: Container( + color: const Color(0xD0FF0000), + height: 100, ), - ], - ), - ); - } + ), + ], + ), + ); + } - // Test default clip behavior. - await tester.pumpWidget(buildFrame(Clip.hardEdge)); + // Test default clip behavior. + await tester.pumpWidget(buildFrame(Clip.hardEdge)); - expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); - expect(find.byType(GlowingOverscrollIndicator), findsNothing); - expect(find.text('Index 1'), findsOneWidget); + expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); + expect(find.byType(GlowingOverscrollIndicator), findsNothing); + expect(find.text('Index 1'), findsOneWidget); - RenderClipRect renderClip = tester.allRenderObjects.whereType().first; - // Currently not clipping - expect(renderClip.clipBehavior, equals(Clip.none)); + RenderClipRect renderClip = tester.allRenderObjects.whereType().first; + // Currently not clipping + expect(renderClip.clipBehavior, equals(Clip.none)); - TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('Index 1'))); - // Overscroll the start. - await gesture.moveBy(const Offset(0.0, 200.0)); - await tester.pumpAndSettle(); - expect(find.text('Index 1'), findsOneWidget); - expect(tester.getCenter(find.text('Index 1')).dy, greaterThan(0)); - renderClip = tester.allRenderObjects.whereType().first; - // Now clipping - expect(renderClip.clipBehavior, equals(Clip.hardEdge)); + TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('Index 1'))); + // Overscroll the start. + await gesture.moveBy(const Offset(0.0, 200.0)); + await tester.pumpAndSettle(); + expect(find.text('Index 1'), findsOneWidget); + expect(tester.getCenter(find.text('Index 1')).dy, greaterThan(0)); + renderClip = tester.allRenderObjects.whereType().first; + // Now clipping + expect(renderClip.clipBehavior, equals(Clip.hardEdge)); - await gesture.up(); - await tester.pumpAndSettle(); + await gesture.up(); + await tester.pumpAndSettle(); - // Test custom clip behavior. - await tester.pumpWidget(buildFrame(Clip.none)); + // Test custom clip behavior. + await tester.pumpWidget(buildFrame(Clip.none)); - renderClip = tester.allRenderObjects.whereType().first; - // Currently not clipping - expect(renderClip.clipBehavior, equals(Clip.none)); + renderClip = tester.allRenderObjects.whereType().first; + // Currently not clipping + expect(renderClip.clipBehavior, equals(Clip.none)); - gesture = await tester.startGesture(tester.getCenter(find.text('Index 1'))); - // Overscroll the start. - await gesture.moveBy(const Offset(0.0, 200.0)); - await tester.pumpAndSettle(); - expect(find.text('Index 1'), findsOneWidget); - expect(tester.getCenter(find.text('Index 1')).dy, greaterThan(0)); - renderClip = tester.allRenderObjects.whereType().first; - // Now clipping - expect(renderClip.clipBehavior, equals(Clip.none)); + gesture = await tester.startGesture(tester.getCenter(find.text('Index 1'))); + // Overscroll the start. + await gesture.moveBy(const Offset(0.0, 200.0)); + await tester.pumpAndSettle(); + expect(find.text('Index 1'), findsOneWidget); + expect(tester.getCenter(find.text('Index 1')).dy, greaterThan(0)); + renderClip = tester.allRenderObjects.whereType().first; + // Now clipping + expect(renderClip.clipBehavior, equals(Clip.none)); - await gesture.up(); - await tester.pumpAndSettle(); + await gesture.up(); + await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); testWidgets('When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available', (WidgetTester tester) async { From b460d49199e56459cc8a27688a71075bbb3cfbbc Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 18 Jul 2023 19:24:11 +0300 Subject: [PATCH 0228/1547] Update `AppBar` and `AppBarTheme` tests for M2/M3 (#130790) Updated unit tests for `AppBar` and `AppBarTheme` to have M2 and M3 versions. More info in https://github.com/flutter/flutter/issues/127064 --- .../flutter/test/material/app_bar_test.dart | 453 +++++++++++++++--- .../test/material/app_bar_theme_test.dart | 383 ++++++++------- 2 files changed, 599 insertions(+), 237 deletions(-) diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 79e60bce01a14..eb51024e1de1d 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -559,10 +559,31 @@ void main() { ); }); - testWidgets('AppBar drawer icon has default color', (WidgetTester tester) async { - final ThemeData themeData = ThemeData.from(colorScheme: const ColorScheme.light()); - final bool useMaterial3 = themeData.useMaterial3; + testWidgets('Material2 - AppBar drawer icon has default color', (WidgetTester tester) async { + final ThemeData themeData = ThemeData.from( + colorScheme: const ColorScheme.light(), + useMaterial3: false, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + title: const Text('Howdy!'), + ), + drawer: const Drawer(), + ), + ), + ); + + expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onPrimary); + }); + testWidgets('Material3 - AppBar drawer icon has default color', (WidgetTester tester) async { + final ThemeData themeData = ThemeData.from( + colorScheme: const ColorScheme.light(), + useMaterial3: true, + ); await tester.pumpWidget( MaterialApp( theme: themeData, @@ -575,10 +596,7 @@ void main() { ), ); - Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; - final Color iconColorM2 = themeData.colorScheme.onPrimary; - final Color iconColorM3 = themeData.colorScheme.onSurfaceVariant; - expect(iconColor(), useMaterial3 ? iconColorM3 : iconColorM2); + expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onSurfaceVariant); }); testWidgets('AppBar drawer icon is sized by iconTheme', (WidgetTester tester) async { @@ -616,9 +634,7 @@ void main() { ), ); - Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; - - expect(iconColor(), color); + expect(_iconStyle(tester, Icons.menu)?.color, color); }); testWidgets('AppBar endDrawer icon has default size', (WidgetTester tester) async { @@ -632,6 +648,7 @@ void main() { ), ), ); + final double iconSize = const IconThemeData.fallback().size!; expect( tester.getSize(find.byIcon(Icons.menu)), @@ -639,10 +656,31 @@ void main() { ); }); - testWidgets('AppBar endDrawer icon has default color', (WidgetTester tester) async { - final ThemeData themeData = ThemeData.from(colorScheme: const ColorScheme.light()); - final bool useMaterial3 = themeData.useMaterial3; + testWidgets('Material2 - AppBar endDrawer icon has default color', (WidgetTester tester) async { + final ThemeData themeData = ThemeData.from( + colorScheme: const ColorScheme.light(), + useMaterial3: false, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + title: const Text('Howdy!'), + ), + endDrawer: const Drawer(), + ), + ), + ); + expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onPrimary); + }); + + testWidgets('Material3 - AppBar endDrawer icon has default color', (WidgetTester tester) async { + final ThemeData themeData = ThemeData.from( + colorScheme: const ColorScheme.light(), + useMaterial3: true, + ); await tester.pumpWidget( MaterialApp( theme: themeData, @@ -655,10 +693,7 @@ void main() { ), ); - Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; - final Color iconColorM2 = themeData.colorScheme.onPrimary; - final Color iconColorM3 = themeData.colorScheme.onSurfaceVariant; - expect(iconColor(), useMaterial3 ? iconColorM3 : iconColorM2); + expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onSurfaceVariant); }); testWidgets('AppBar endDrawer icon is sized by iconTheme', (WidgetTester tester) async { @@ -696,14 +731,72 @@ void main() { ), ); - Color? iconColor() => _iconStyle(tester, Icons.menu)?.color; + expect(_iconStyle(tester, Icons.menu)?.color, color); + }); + + testWidgets('Material2 - leading widget extends to edge and is square', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + platform: TargetPlatform.android, + useMaterial3: false, + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: IconButton(icon: const Icon(Icons.menu), onPressed: () {}), + title: const Text('X'), + ), + drawer: const Column(), // Doesn't really matter. Triggers a hamburger regardless. + ), + ), + ); + + // Default IconButton has a size of (56x56). + final Finder hamburger = find.byType(IconButton); + expect(tester.getTopLeft(hamburger), Offset.zero); + expect(tester.getSize(hamburger), const Size(56.0, 56.0)); - expect(iconColor(), color); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: Container(), + title: const Text('X'), + ), + ), + ), + ); + + // Default leading widget has a size of (56x56). + final Finder leadingBox = find.byType(Container); + expect(tester.getTopLeft(leadingBox), Offset.zero); + expect(tester.getSize(leadingBox), const Size(56.0, 56.0)); + + // The custom leading widget should still be 56x56 even if its size is smaller. + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Scaffold( + appBar: AppBar( + leading: const SizedBox(height: 36, width: 36,), + title: const Text('X'), + ), // Doesn't really matter. Triggers a hamburger regardless. + ), + ), + ); + + final Finder leading = find.byType(SizedBox); + expect(tester.getTopLeft(leading), Offset.zero); + expect(tester.getSize(leading), const Size(56.0, 56.0)); }); - testWidgets('leading widget extends to edge and is square', (WidgetTester tester) async { - final ThemeData themeData = ThemeData(platform: TargetPlatform.android); - final bool material3 = themeData.useMaterial3; + testWidgets('Material3 - leading widget extends to edge and is square', (WidgetTester tester) async { + final ThemeData themeData = ThemeData( + platform: TargetPlatform.android, + useMaterial3: true, + ); await tester.pumpWidget( MaterialApp( theme: themeData, @@ -717,10 +810,10 @@ void main() { ), ); - // Default IconButton has a size of (48x48) in M3, (56x56) in M2 + // Default IconButton has a size of (48x48). final Finder hamburger = find.byType(IconButton); - expect(tester.getTopLeft(hamburger), material3 ? const Offset(4.0, 4.0) : Offset.zero); - expect(tester.getSize(hamburger), material3 ? const Size(48.0, 48.0) : const Size(56.0, 56.0)); + expect(tester.getTopLeft(hamburger), const Offset(4.0, 4.0)); + expect(tester.getSize(hamburger), const Size(48.0, 48.0)); await tester.pumpWidget( MaterialApp( @@ -734,7 +827,7 @@ void main() { ), ); - // Default leading widget has a size of (56x56) for both M2 and M3 + // Default leading widget has a size of (56x56). final Finder leadingBox = find.byType(Container); expect(tester.getTopLeft(leadingBox), Offset.zero); expect(tester.getSize(leadingBox), const Size(56.0, 56.0)); @@ -757,9 +850,11 @@ void main() { expect(tester.getSize(leading), const Size(56.0, 56.0)); }); - testWidgets('test action is 4dp from edge and 48dp min', (WidgetTester tester) async { - final ThemeData theme = ThemeData(platform: TargetPlatform.android); - final bool material3 = theme.useMaterial3; + testWidgets('Material2 - Action is 4dp from edge and 48dp min', (WidgetTester tester) async { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, + useMaterial3: false, + ); await tester.pumpWidget( MaterialApp( theme: theme, @@ -792,7 +887,47 @@ void main() { final Finder shareButton = find.widgetWithIcon(IconButton, Icons.share); // The 20dp icon is expanded to fill the IconButton's touch target to 48dp. - expect(tester.getSize(shareButton), material3 ? const Size(48.0, 48.0) : const Size(48.0, 56.0)); + expect(tester.getSize(shareButton), const Size(48.0, 56.0)); + }); + + testWidgets('Material3 - Action is 4dp from edge and 48dp min', (WidgetTester tester) async { + final ThemeData theme = ThemeData( + platform: TargetPlatform.android, + useMaterial3: true, + ); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + appBar: AppBar( + title: const Text('X'), + actions: const [ + IconButton( + icon: Icon(Icons.share), + onPressed: null, + tooltip: 'Share', + iconSize: 20.0, + ), + IconButton( + icon: Icon(Icons.add), + onPressed: null, + tooltip: 'Add', + iconSize: 60.0, + ), + ], + ), + ), + ), + ); + + final Finder addButton = find.widgetWithIcon(IconButton, Icons.add); + expect(tester.getTopRight(addButton), const Offset(800.0, 0.0)); + // It's still the size it was plus the 2 * 8dp padding from IconButton. + expect(tester.getSize(addButton), const Size(60.0 + 2 * 8.0, 56.0)); + + final Finder shareButton = find.widgetWithIcon(IconButton, Icons.share); + // The 20dp icon is expanded to fill the IconButton's touch target to 48dp. + expect(tester.getSize(shareButton), const Size(48.0, 48.0)); }); testWidgets('SliverAppBar default configuration', (WidgetTester tester) async { @@ -828,7 +963,6 @@ void main() { }); testWidgets('SliverAppBar expandedHeight, pinned', (WidgetTester tester) async { - await tester.pumpWidget(buildSliverAppBarApp( pinned: true, expandedHeight: 128.0, @@ -860,7 +994,6 @@ void main() { }); testWidgets('SliverAppBar expandedHeight, pinned and floating', (WidgetTester tester) async { - await tester.pumpWidget(buildSliverAppBarApp( floating: true, pinned: true, @@ -1096,7 +1229,7 @@ void main() { expect(tabBarHeight(tester), initialTabBarHeight); }); - testWidgets('SliverAppBar.medium defaults', (WidgetTester tester) async { + testWidgets('Material3 - SliverAppBar.medium defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 112; @@ -1183,7 +1316,7 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('SliverAppBar.large defaults', (WidgetTester tester) async { + testWidgets('Material3 - SliverAppBar.large defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 152; @@ -1276,11 +1409,34 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('AppBar uses the specified elevation or defaults to 4.0', (WidgetTester tester) async { - final bool useMaterial3 = ThemeData().useMaterial3; + testWidgets('Material2 - AppBar uses the specified elevation or defaults to 4.0', (WidgetTester tester) async { + Widget buildAppBar([double? elevation]) { + return MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + appBar: AppBar(title: const Text('Title'), elevation: elevation), + ), + ); + } + + Material getMaterial() => tester.widget(find.descendant( + of: find.byType(AppBar), + matching: find.byType(Material), + )); + + // Default elevation should be used for the material. + await tester.pumpWidget(buildAppBar()); + expect(getMaterial().elevation, 4); + // AppBar should use the specified elevation. + await tester.pumpWidget(buildAppBar(8.0)); + expect(getMaterial().elevation, 8.0); + }); + + testWidgets('Material3 - AppBar uses the specified elevation or defaults to 0', (WidgetTester tester) async { Widget buildAppBar([double? elevation]) { return MaterialApp( + theme: ThemeData(useMaterial3: true), home: Scaffold( appBar: AppBar(title: const Text('Title'), elevation: elevation), ), @@ -1294,7 +1450,7 @@ void main() { // Default elevation should be used for the material. await tester.pumpWidget(buildAppBar()); - expect(getMaterial().elevation, useMaterial3 ? 0 : 4); + expect(getMaterial().elevation, 0); // AppBar should use the specified elevation. await tester.pumpWidget(buildAppBar(8.0)); @@ -1334,7 +1490,7 @@ void main() { expect(getMaterial().elevation, 10); }); - testWidgets('scrolledUnderElevation with nested scroll view', (WidgetTester tester) async { + testWidgets('Material3 - scrolledUnderElevation with nested scroll view', (WidgetTester tester) async { Widget buildAppBar({double? scrolledUnderElevation}) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1840,7 +1996,7 @@ void main() { ); }); - testWidgets('AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { + testWidgets('Material2 - AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/58665 final Key key = UniqueKey(); await tester.pumpWidget( @@ -1887,6 +2043,53 @@ void main() { expect(painter, paints..save()..translate()..save()..translate()..circle(x: 24.0, y: 28.0)); }); + testWidgets('Material3 - AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/58665 + final Key key = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + // Test was designed against InkSplash so need to make sure that is used. + theme: ThemeData( + useMaterial3: true, + splashFactory: InkSplash.splashFactory + ), + home: Center( + child: AppBar( + title: const Text('Abc'), + actions: [ + IconButton( + key: key, + icon: const Icon(Icons.add_circle), + tooltip: 'First button', + onPressed: () {}, + ), + ], + flexibleSpace: DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: const Alignment(-0.04, 1.0), + colors: [Colors.blue.shade500, Colors.blue.shade800], + ), + ), + ), + ), + ), + ), + ); + final RenderObject painter = tester.renderObject( + find.descendant( + of: find.descendant( + of: find.byType(AppBar), + matching: find.byType(Stack), + ), + matching: find.byType(Material).last, + ), + ); + await tester.tap(find.byKey(key)); + expect(painter, paints..save()..translate()..save()..translate()..circle(x: 20.0, y: 20.0)); + }); + testWidgets('AppBar handles loose children 0', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -2011,7 +2214,6 @@ void main() { testWidgets('AppBar positioning of leading and trailing widgets with top padding', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100)); - final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key trailingKey = UniqueKey(); @@ -2055,7 +2257,6 @@ void main() { testWidgets('SliverAppBar positioning of leading and trailing widgets with top padding', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100.0)); - final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key trailingKey = UniqueKey(); @@ -2093,7 +2294,6 @@ void main() { testWidgets('SliverAppBar positioning of leading and trailing widgets with bottom padding', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100.0, bottom: 50.0)); - final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key trailingKey = UniqueKey(); @@ -2503,7 +2703,7 @@ void main() { semantics.dispose(); }); - testWidgets('AppBar draws a light system bar for a dark background', (WidgetTester tester) async { + testWidgets('Material2 - AppBar draws a light system bar for a dark background', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(useMaterial3: false); await tester.pumpWidget(MaterialApp( theme: darkTheme, @@ -2521,7 +2721,26 @@ void main() { )); }); - testWidgets('AppBar draws a dark system bar for a light background', (WidgetTester tester) async { + testWidgets('Material3 - AppBar draws a light system bar for a dark background', (WidgetTester tester) async { + final ThemeData darkTheme = ThemeData.dark(useMaterial3: true); + await tester.pumpWidget(MaterialApp( + theme: darkTheme, + home: Scaffold( + appBar: AppBar( + title: const Text('test'), + ), + ), + )); + + expect(darkTheme.colorScheme.brightness, Brightness.dark); + expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarBrightness: Brightness.dark, + statusBarIconBrightness: Brightness.light, + )); + }); + + testWidgets('Material2 - AppBar draws a dark system bar for a light background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData(primarySwatch: Colors.lightBlue, useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -2541,7 +2760,28 @@ void main() { )); }); - testWidgets('Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { + testWidgets('Material3 - AppBar draws a dark system bar for a light background', (WidgetTester tester) async { + final ThemeData lightTheme = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: lightTheme, + home: Scaffold( + appBar: AppBar( + title: const Text('test'), + ), + ), + ), + ); + + expect(lightTheme.colorScheme.brightness, Brightness.light); + expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarBrightness: Brightness.light, + statusBarIconBrightness: Brightness.dark, + )); + }); + + testWidgets('Material2 - Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { Widget buildAppBar(ThemeData theme) { return MaterialApp( theme: theme, @@ -2592,27 +2832,94 @@ void main() { } }); - testWidgets('Default status bar color', (WidgetTester tester) async { - Future pumpBoilerplate({required bool useMaterial3}) async { - await tester.pumpWidget( - MaterialApp( - key: GlobalKey(), - theme: ThemeData.light().copyWith( - useMaterial3: useMaterial3, - appBarTheme: const AppBarTheme(), - ), - home: Scaffold( - appBar: AppBar( - title: const Text('title'), - ), - ), + testWidgets('Material3 - Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { + Widget buildAppBar(ThemeData theme) { + return MaterialApp( + theme: theme, + home: Scaffold( + appBar: AppBar(title: const Text('Title')), ), ); } - await pumpBoilerplate(useMaterial3: false); + // Using a light theme. + { + await tester.pumpWidget(buildAppBar(ThemeData(useMaterial3: true))); + final Material appBarMaterial = tester.widget( + find.descendant( + of: find.byType(AppBar), + matching: find.byType(Material), + ), + ); + final Brightness appBarBrightness = ThemeData.estimateBrightnessForColor(appBarMaterial.color!); + final Brightness onAppBarBrightness = appBarBrightness == Brightness.light + ? Brightness.dark + : Brightness.light; + + expect(SystemChrome.latestStyle, SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarBrightness: appBarBrightness, + statusBarIconBrightness: onAppBarBrightness, + )); + } + + // Using a dark theme. + { + await tester.pumpWidget(buildAppBar(ThemeData.dark(useMaterial3: true))); + final Material appBarMaterial = tester.widget( + find.descendant( + of: find.byType(AppBar), + matching: find.byType(Material), + ), + ); + final Brightness appBarBrightness = ThemeData.estimateBrightnessForColor(appBarMaterial.color!); + final Brightness onAppBarBrightness = appBarBrightness == Brightness.light + ? Brightness.dark + : Brightness.light; + + expect(SystemChrome.latestStyle, SystemUiOverlayStyle( + statusBarColor: Colors.transparent, + statusBarBrightness: appBarBrightness, + statusBarIconBrightness: onAppBarBrightness, + )); + } + }); + + testWidgets('Material2 - Default status bar color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + key: GlobalKey(), + theme: ThemeData.light().copyWith( + useMaterial3: false, + appBarTheme: const AppBarTheme(), + ), + home: Scaffold( + appBar: AppBar( + title: const Text('title'), + ), + ), + ), + ); + expect(SystemChrome.latestStyle!.statusBarColor, null); - await pumpBoilerplate(useMaterial3: true); + }); + + testWidgets('Material3 - Default status bar color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + key: GlobalKey(), + theme: ThemeData.light().copyWith( + useMaterial3: true, + appBarTheme: const AppBarTheme(), + ), + home: Scaffold( + appBar: AppBar( + title: const Text('title'), + ), + ), + ), + ); + expect(SystemChrome.latestStyle!.statusBarColor, Colors.transparent); }); @@ -3167,8 +3474,8 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/107305 - group('Icons are colored correctly by IconTheme and ActionIconTheme in M3', () { - testWidgets('Icons and IconButtons are colored by IconTheme in M3', (WidgetTester tester) async { + group('Material3 - Icons are colored correctly by IconTheme and ActionIconTheme', () { + testWidgets('Material3 - Icons and IconButtons are colored by IconTheme', (WidgetTester tester) async { const Color iconColor = Color(0xff00ff00); final Key leadingIconKey = UniqueKey(); final Key actionIconKey = UniqueKey(); @@ -3200,7 +3507,7 @@ void main() { expect(actionIconButtonColor(), iconColor); }); - testWidgets('Action icons and IconButtons are colored by ActionIconTheme - M3', (WidgetTester tester) async { + testWidgets('Material3 - Action icons and IconButtons are colored by ActionIconTheme', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: true, @@ -3236,7 +3543,7 @@ void main() { expect(actionIconButtonColor(), actionsIconColor); }); - testWidgets('The actionIconTheme property overrides iconTheme - M3', (WidgetTester tester) async { + testWidgets('Material3 - The actionIconTheme property overrides iconTheme', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: true, @@ -3274,7 +3581,7 @@ void main() { expect(actionIconButtonColor(), actionsIconColor); }); - testWidgets('AppBar.iconTheme should override any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBar.iconTheme should override any IconButtonTheme present in the theme', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3313,7 +3620,7 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3346,7 +3653,7 @@ void main() { }); - testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBar.actionsIconTheme should override any IconButtonTheme present in the theme', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3386,7 +3693,7 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3420,7 +3727,7 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme - M3', (WidgetTester tester) async { + testWidgets('Material3 - The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -5104,7 +5411,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('SliverAppBar.medium defaults', (WidgetTester tester) async { + testWidgets('Material2 - SliverAppBar.medium defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 112; @@ -5188,13 +5495,13 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('SliverAppBar.large defaults', (WidgetTester tester) async { + testWidgets('Material2 - SliverAppBar.large defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 152; await tester.pumpWidget(MaterialApp( - theme: ThemeData(useMaterial3: false), + theme: theme, home: Scaffold( body: CustomScrollView( primary: true, diff --git a/packages/flutter/test/material/app_bar_theme_test.dart b/packages/flutter/test/material/app_bar_theme_test.dart index fca54545930b6..3f1c076fb3bf5 100644 --- a/packages/flutter/test/material/app_bar_theme_test.dart +++ b/packages/flutter/test/material/app_bar_theme_test.dart @@ -42,9 +42,8 @@ void main() { expect(identical(AppBarTheme.lerp(data, data, 0.5), data), true); }); - testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async { - final ThemeData theme = ThemeData(); - final bool material3 = theme.useMaterial3; + testWidgets('Material2 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( MaterialApp( theme: theme, @@ -64,35 +63,58 @@ void main() { final RichText actionIconText = _getAppBarIconRichText(tester); final DefaultTextStyle text = _getAppBarText(tester); - if (theme.useMaterial3) { - expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); - expect(widget.color, theme.colorScheme.surface); - expect(widget.elevation, 0); - expect(widget.shadowColor, material3 ? Colors.transparent : null); - expect(widget.surfaceTintColor, theme.colorScheme.surfaceTint); - expect(widget.shape, null); - expect(iconTheme.data, IconThemeData(color: theme.colorScheme.onSurface, size: 24)); - expect(actionsIconTheme.data, IconThemeData(color: theme.colorScheme.onSurfaceVariant, size: 24)); - expect(actionIconText.text.style!.color, material3 ? theme.colorScheme.onSurfaceVariant : Colors.black); - expect(text.style, material3 - ? Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: theme.colorScheme.onSurface, decorationColor: theme.colorScheme.onSurface) - : Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: theme.colorScheme.onSurface)); - expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); - expect(tester.getSize(find.byType(AppBar)).width, 800); - } else { - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, Colors.blue); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(widget.surfaceTintColor, null); - expect(widget.shape, null); - expect(iconTheme.data, const IconThemeData(color: Colors.white)); - expect(actionsIconTheme.data, const IconThemeData(color: Colors.white)); - expect(actionIconText.text.style!.color, Colors.white); - expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().white.bodyMedium)); - expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); - expect(tester.getSize(find.byType(AppBar)).width, 800); - } + expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); + expect(widget.color, Colors.blue); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(widget.surfaceTintColor, null); + expect(widget.shape, null); + expect(iconTheme.data, const IconThemeData(color: Colors.white)); + expect(actionsIconTheme.data, const IconThemeData(color: Colors.white)); + expect(actionIconText.text.style!.color, Colors.white); + expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().white.bodyMedium)); + expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); + expect(tester.getSize(find.byType(AppBar)).width, 800); + }); + + testWidgets('Material3 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + appBar: AppBar( + actions: [ + IconButton(icon: const Icon(Icons.share), onPressed: () { }), + ], + ), + ), + ), + ); + + final Material widget = _getAppBarMaterial(tester); + final IconTheme iconTheme = _getAppBarIconTheme(tester); + final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + final RichText actionIconText = _getAppBarIconRichText(tester); + final DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); + expect(widget.color, theme.colorScheme.surface); + expect(widget.elevation, 0); + expect(widget.shadowColor, Colors.transparent); + expect(widget.surfaceTintColor, theme.colorScheme.surfaceTint); + expect(widget.shape, null); + expect(iconTheme.data, IconThemeData(color: theme.colorScheme.onSurface, size: 24)); + expect(actionsIconTheme.data, IconThemeData(color: theme.colorScheme.onSurfaceVariant, size: 24)); + expect(actionIconText.text.style!.color, theme.colorScheme.onSurfaceVariant); + expect( + text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .copyWith(color: theme.colorScheme.onSurface, decorationColor: theme.colorScheme.onSurface), + ); + expect(tester.getSize(find.byType(AppBar)).height, kToolbarHeight); + expect(tester.getSize(find.byType(AppBar)).width, 800); }); testWidgets('AppBar uses values from AppBarTheme', (WidgetTester tester) async { @@ -242,9 +264,9 @@ void main() { expect(text.style, appBarTheme.toolbarTextStyle); }); - testWidgets('ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { - final ThemeData lightTheme = ThemeData.from(colorScheme: const ColorScheme.light()); - final ThemeData darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark()); + testWidgets('Material2 - ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { + final ThemeData lightTheme = ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: false); + final ThemeData darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: false); Widget buildFrame(ThemeData appTheme) { return MaterialApp( theme: appTheme, @@ -262,121 +284,132 @@ void main() { ); } - if (lightTheme.useMaterial3) { - // M3 AppBar defaults for light themes: - // - elevation: 0 - // - shadow color: Colors.transparent - // - surface tint color: ColorScheme.surfaceTint - // - background color: ColorScheme.surface - // - foreground color: ColorScheme.onSurface - // - actions text: style bodyMedium, foreground color - // - status bar brightness: light (based on color scheme brightness) - { - await tester.pumpWidget(buildFrame(lightTheme)); - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); - expect(widget.color, lightTheme.colorScheme.surface); - expect(widget.elevation, 0); - expect(widget.shadowColor, Colors.transparent); - expect(widget.surfaceTintColor, lightTheme.colorScheme.surfaceTint); - expect(iconTheme.data.color, lightTheme.colorScheme.onSurface); - expect(actionsIconTheme.data.color, lightTheme.colorScheme.onSurface); - expect(actionIconText.text.style!.color, lightTheme.colorScheme.onSurface); - expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: lightTheme.colorScheme.onSurface)); - } - - // M3 AppBar defaults for dark themes: - // - elevation: 0 - // - shadow color: Colors.transparent - // - surface tint color: ColorScheme.surfaceTint - // - background color: ColorScheme.surface - // - foreground color: ColorScheme.onSurface - // - actions text: style bodyMedium, foreground color - // - status bar brightness: dark (based on background color) - { - await tester.pumpWidget(buildFrame(darkTheme)); - await tester.pumpAndSettle(); // Theme change animation - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.dark); - expect(widget.color, darkTheme.colorScheme.surface); - expect(widget.elevation, 0); - expect(widget.shadowColor, Colors.transparent); - expect(widget.surfaceTintColor, darkTheme.colorScheme.surfaceTint); - expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); - expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); - expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); - expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface, decorationColor: darkTheme.colorScheme.onSurface)); - } - } else { - // AppBar M2 defaults for light themes: - // - elevation: 4 - // - shadow color: black - // - surface tint color: null - // - background color: ColorScheme.primary - // - foreground color: ColorScheme.onPrimary - // - actions text: style bodyMedium, foreground color - // - status bar brightness: light (based on color scheme brightness) - { - await tester.pumpWidget(buildFrame(lightTheme)); - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, lightTheme.colorScheme.primary); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(widget.surfaceTintColor, null); - expect(iconTheme.data.color, lightTheme.colorScheme.onPrimary); - expect(actionsIconTheme.data.color, lightTheme.colorScheme.onPrimary); - expect(actionIconText.text.style!.color, lightTheme.colorScheme.onPrimary); - expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: lightTheme.colorScheme.onPrimary)); - } - - // AppBar M2 defaults for dark themes: - // - elevation: 4 - // - shadow color: black - // - surface tint color: null - // - background color: ColorScheme.surface - // - foreground color: ColorScheme.onSurface - // - actions text: style bodyMedium, foreground color - // - status bar brightness: dark (based on background color) - { - await tester.pumpWidget(buildFrame(darkTheme)); - await tester.pumpAndSettle(); // Theme change animation - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, darkTheme.colorScheme.surface); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(widget.surfaceTintColor, null); - expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); - expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); - expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); - expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface)); - } + // AppBar M2 defaults for light themes: + // - elevation: 4 + // - shadow color: black + // - surface tint color: null + // - background color: ColorScheme.primary + // - foreground color: ColorScheme.onPrimary + // - actions text: style bodyMedium, foreground color + // - status bar brightness: light (based on color scheme brightness) + await tester.pumpWidget(buildFrame(lightTheme)); + + Material widget = _getAppBarMaterial(tester); + IconTheme iconTheme = _getAppBarIconTheme(tester); + IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + RichText actionIconText = _getAppBarIconRichText(tester); + DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); + expect(widget.color, lightTheme.colorScheme.primary); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(widget.surfaceTintColor, null); + expect(iconTheme.data.color, lightTheme.colorScheme.onPrimary); + expect(actionsIconTheme.data.color, lightTheme.colorScheme.onPrimary); + expect(actionIconText.text.style!.color, lightTheme.colorScheme.onPrimary); + expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: lightTheme.colorScheme.onPrimary)); + + // AppBar M2 defaults for dark themes: + // - elevation: 4 + // - shadow color: black + // - surface tint color: null + // - background color: ColorScheme.surface + // - foreground color: ColorScheme.onSurface + // - actions text: style bodyMedium, foreground color + // - status bar brightness: dark (based on background color) + await tester.pumpWidget(buildFrame(darkTheme)); + await tester.pumpAndSettle(); // Theme change animation + + widget = _getAppBarMaterial(tester); + iconTheme = _getAppBarIconTheme(tester); + actionsIconTheme = _getAppBarActionsIconTheme(tester); + actionIconText = _getAppBarIconRichText(tester); + text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); + expect(widget.color, darkTheme.colorScheme.surface); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(widget.surfaceTintColor, null); + expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); + expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface)); + }); + + testWidgets('Material3 - ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { + final ThemeData lightTheme = ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true); + final ThemeData darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: true); + Widget buildFrame(ThemeData appTheme) { + return MaterialApp( + theme: appTheme, + home: Builder( + builder: (BuildContext context) { + return Scaffold( + appBar: AppBar( + actions: [ + IconButton(icon: const Icon(Icons.share), onPressed: () { }), + ], + ), + ); + }, + ), + ); } + + // M3 AppBar defaults for light themes: + // - elevation: 0 + // - shadow color: Colors.transparent + // - surface tint color: ColorScheme.surfaceTint + // - background color: ColorScheme.surface + // - foreground color: ColorScheme.onSurface + // - actions text: style bodyMedium, foreground color + // - status bar brightness: light (based on color scheme brightness) + await tester.pumpWidget(buildFrame(lightTheme)); + + Material widget = _getAppBarMaterial(tester); + IconTheme iconTheme = _getAppBarIconTheme(tester); + IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + RichText actionIconText = _getAppBarIconRichText(tester); + DefaultTextStyle text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.light); + expect(widget.color, lightTheme.colorScheme.surface); + expect(widget.elevation, 0); + expect(widget.shadowColor, Colors.transparent); + expect(widget.surfaceTintColor, lightTheme.colorScheme.surfaceTint); + expect(iconTheme.data.color, lightTheme.colorScheme.onSurface); + expect(actionsIconTheme.data.color, lightTheme.colorScheme.onSurface); + expect(actionIconText.text.style!.color, lightTheme.colorScheme.onSurface); + expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: lightTheme.colorScheme.onSurface)); + + // M3 AppBar defaults for dark themes: + // - elevation: 0 + // - shadow color: Colors.transparent + // - surface tint color: ColorScheme.surfaceTint + // - background color: ColorScheme.surface + // - foreground color: ColorScheme.onSurface + // - actions text: style bodyMedium, foreground color + // - status bar brightness: dark (based on background color) + await tester.pumpWidget(buildFrame(darkTheme)); + await tester.pumpAndSettle(); // Theme change animation + + widget = _getAppBarMaterial(tester); + iconTheme = _getAppBarIconTheme(tester); + actionsIconTheme = _getAppBarActionsIconTheme(tester); + actionIconText = _getAppBarIconRichText(tester); + text = _getAppBarText(tester); + + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.dark); + expect(widget.color, darkTheme.colorScheme.surface); + expect(widget.elevation, 0); + expect(widget.shadowColor, Colors.transparent); + expect(widget.surfaceTintColor, darkTheme.colorScheme.surfaceTint); + expect(iconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionsIconTheme.data.color, darkTheme.colorScheme.onSurface); + expect(actionIconText.text.style!.color, darkTheme.colorScheme.onSurface); + expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface, decorationColor: darkTheme.colorScheme.onSurface)); }); testWidgets('AppBar iconTheme with color=null defers to outer IconTheme', (WidgetTester tester) async { @@ -384,7 +417,7 @@ void main() { Widget buildFrame({ Color? appIconColor, Color? appBarIconColor }) { return MaterialApp( - theme: ThemeData.from(useMaterial3: false, colorScheme: const ColorScheme.light()), + theme: ThemeData.from(colorScheme: const ColorScheme.light()), home: IconTheme( data: IconThemeData(color: appIconColor), child: Builder( @@ -493,7 +526,7 @@ void main() { expect(appBar.surfaceTintColor, Colors.yellow); }); - testWidgets('AppBarTheme.iconTheme.color takes priority over IconButtonTheme.foregroundColor - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBarTheme.iconTheme.color takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { const IconThemeData overallIconTheme = IconThemeData(color: Colors.yellow); await tester.pumpWidget(MaterialApp( theme: ThemeData( @@ -519,7 +552,7 @@ void main() { expect(actionIconButtonColor, overallIconTheme.color); }); - testWidgets('AppBarTheme.iconTheme.size takes priority over IconButtonTheme.iconSize - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBarTheme.iconTheme.size takes priority over IconButtonTheme.iconSize', (WidgetTester tester) async { const IconThemeData overallIconTheme = IconThemeData(size: 30.0); await tester.pumpWidget(MaterialApp( theme: ThemeData( @@ -546,7 +579,7 @@ void main() { }); - testWidgets('AppBarTheme.actionsIconTheme.color takes priority over IconButtonTheme.foregroundColor - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBarTheme.actionsIconTheme.color takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { const IconThemeData actionsIconTheme = IconThemeData(color: Colors.yellow); final IconButtonThemeData iconButtonTheme = IconButtonThemeData( style: IconButton.styleFrom(foregroundColor: Colors.red), @@ -574,7 +607,7 @@ void main() { expect(actionIconButtonColor, actionsIconTheme.color); }); - testWidgets('AppBarTheme.actionsIconTheme.size takes priority over IconButtonTheme.iconSize - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBarTheme.actionsIconTheme.size takes priority over IconButtonTheme.iconSize', (WidgetTester tester) async { const IconThemeData actionsIconTheme = IconThemeData(size: 30.0); final IconButtonThemeData iconButtonTheme = IconButtonThemeData( style: IconButton.styleFrom(iconSize: 32.0), @@ -601,7 +634,7 @@ void main() { expect(actionIconButtonSize, actionsIconTheme.size); }); - testWidgets('AppBarTheme.foregroundColor takes priority over IconButtonTheme.foregroundColor - M3', (WidgetTester tester) async { + testWidgets('Material3 - AppBarTheme.foregroundColor takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { final IconButtonThemeData iconButtonTheme = IconButtonThemeData( style: IconButton.styleFrom(foregroundColor: Colors.red), ); @@ -1027,12 +1060,22 @@ void main() { testWidgets('AppBarTheme implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const AppBarTheme( - backgroundColor: Color(0xff000001), + backgroundColor: Color(0xff000000), + foregroundColor: Color(0xff000001), elevation: 8.0, + scrolledUnderElevation: 3, shadowColor: Color(0xff000002), surfaceTintColor: Color(0xff000003), + shape: StadiumBorder(), + iconTheme: IconThemeData(color: Color(0xff000004)), centerTitle: true, titleSpacing: 40.0, + toolbarHeight: 96, + toolbarTextStyle: TextStyle(color: Color(0xff000005)), + titleTextStyle: TextStyle(color: Color(0xff000006)), + systemOverlayStyle: SystemUiOverlayStyle( + systemNavigationBarColor: Color(0xff000007), + ), ).debugFillProperties(builder); final List description = builder.properties @@ -1040,14 +1083,26 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect(description, [ - 'backgroundColor: Color(0xff000001)', - 'elevation: 8.0', - 'shadowColor: Color(0xff000002)', - 'surfaceTintColor: Color(0xff000003)', - 'centerTitle: true', - 'titleSpacing: 40.0', - ]); + expect( + description, + equalsIgnoringHashCodes( + [ + 'backgroundColor: Color(0xff000000)', + 'foregroundColor: Color(0xff000001)', + 'elevation: 8.0', + 'scrolledUnderElevation: 3.0', + 'shadowColor: Color(0xff000002)', + 'surfaceTintColor: Color(0xff000003)', + 'shape: StadiumBorder(BorderSide(width: 0.0, style: none))', + 'iconTheme: IconThemeData#00000(color: Color(0xff000004))', + 'centerTitle: true', + 'titleSpacing: 40.0', + 'toolbarHeight: 96.0', + 'toolbarTextStyle: TextStyle(inherit: true, color: Color(0xff000005))', + 'titleTextStyle: TextStyle(inherit: true, color: Color(0xff000006))' + ], + ), + ); // On the web, Dart doubles and ints are backed by the same kind of object because // JavaScript does not support integers. So, the Dart double "4.0" is identical From 94179a8e3fd3b3c1da57735d00e88822c85081ad Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 12:42:10 -0400 Subject: [PATCH 0229/1547] Roll Packages from 6889cca8ba78 to 3e8b8130cda3 (9 revisions) (#130802) https://github.com/flutter/packages/compare/6889cca8ba78...3e8b8130cda3 2023-07-18 jkbturek@gmail.com [video_player] Fix iOS crash with multiple players (flutter/packages#4202) 2023-07-17 stuartmorgan@google.com [pigeon] Enable Android emulator tests in CI (flutter/packages#4484) 2023-07-17 defuncart@gmail.com [video_player] Add optional web options [Platform interface] (flutter/packages#4433) 2023-07-17 rexios@rexios.dev [google_maps_flutter_platform_interface] Platform interface changes for #3258 (flutter/packages#4478) 2023-07-17 yan.outside@gmail.com [video_player] fix: add missing isPlaybackLikelyToKeepUp check. (flutter/packages#3826) 2023-07-17 43054281+camsim99@users.noreply.github.com [camerax] Add flash configuration for image capture (flutter/packages#3800) 2023-07-17 stuartmorgan@google.com Remove `equatable` and `xml` allowances (flutter/packages#4489) 2023-07-17 stuartmorgan@google.com [ci] Switch Linux platform tests to LUCI (flutter/packages#4479) 2023-07-17 stuartmorgan@google.com [ci] Adjust bot configurations (flutter/packages#4485) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index ba82134ddac0b..3c83b71280590 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -6889cca8ba78c5f2ebffd5f52ba92c54a319cc14 +3e8b8130cda3b2564c8e9ee9f5825c0c34b8bc50 From fc2626a790ae20a1e985bf7004b13abfd3e0055f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 14:01:54 -0400 Subject: [PATCH 0230/1547] Roll Flutter Engine from c27658cc5ade to 831da7e9dc3b (2 revisions) (#130810) https://github.com/flutter/engine/compare/c27658cc5ade...831da7e9dc3b 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from b33cc7da1e23 to b7103fe086c1 (1 revision) (flutter/engine#43769) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 8d3e00a1f25f to b33cc7da1e23 (1 revision) (flutter/engine#43768) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0ecf44f5eec23..1e6bf665ed269 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c27658cc5adee7a69f61d6a15d0465c9a82a4c2b +831da7e9dc3b8be5ba70f0976efb4a4f168bb3dd From ab14a5c3563c0d7eede49ec6c1cd43f6f7ed0d49 Mon Sep 17 00:00:00 2001 From: Casey Hillers Date: Tue, 18 Jul 2023 11:19:23 -0700 Subject: [PATCH 0231/1547] [labeler] Mark sync-labels as empty (#130642) https://github.com/flutter/flutter/issues/128440 Recommendation from https://github.com/actions/labeler/issues/112#issuecomment-1136485391 --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index e24e4552853e5..43c62b2a44fc6 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -19,4 +19,4 @@ jobs: # Source available at https://github.com/actions/labeler/blob/main/README.md - uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 with: - sync-labels: false + sync-labels: '' From 433f93560aea91bea7cb8b4460110dbf7d29a2f8 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Tue, 18 Jul 2023 11:22:02 -0700 Subject: [PATCH 0232/1547] Updated `ThemeData.useMaterial3` API doc, default is `true` (#130764) Fixes https://github.com/flutter/flutter/issues/130761 --- .../flutter/lib/src/material/theme_data.dart | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index c67e4b99aeba4..f4c2f4209b5fc 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -1083,21 +1083,16 @@ class ThemeData with Diagnosticable { /// splash with sparkle effects. final InteractiveInkFeatureFactory splashFactory; - /// A temporary flag used to opt-in to Material 3 features. + /// A temporary flag that can be used to opt-out of Material 3 features. /// - /// If true, then widgets that have been migrated to Material 3 will - /// use new colors, typography and other features of Material 3. If false, - /// they will use the Material 2 look and feel. + /// This flag is _true_ by default. If false, then components will + /// continue to use the colors, typography and other features of + /// Material 2. /// - /// During the migration to Material 3, turning this on may yield - /// inconsistent look and feel in your app as some widgets are migrated - /// while others have yet to be. - /// - /// Defaults to false. When the Material 3 specification is complete - /// and all widgets are migrated on stable, we will change this flag to be - /// true by default. After that change has landed on stable, we will deprecate - /// this flag and remove all uses of it. At that point, the `material` library - /// will aim to only support Material 3. + /// In the long run this flag will be deprecated and eventually + /// only Material 3 will be supported. We recommend that applications + /// migrate to Material 3 as soon as that's practical. Until that migration + /// is complete, this flag can be set to false. /// /// ## Defaults /// @@ -1131,14 +1126,13 @@ class ThemeData with Diagnosticable { /// * Typography: [Typography] (see table above) /// /// ### Components - /// \* *new* means the new widgets/methods created since the last stable release. /// * Badges: [Badge] /// * Bottom app bar: [BottomAppBar] /// * Bottom sheets: [BottomSheet] /// * Buttons /// - Common buttons: [ElevatedButton], [FilledButton], [FilledButton.tonal], [OutlinedButton], [TextButton] /// - FAB: [FloatingActionButton], [FloatingActionButton.extended] - /// - Icon buttons: [IconButton], [IconButton.filled] (*new*), [IconButton.filledTonal] (*new*), [IconButton.outlined] (*new*) + /// - Icon buttons: [IconButton], [IconButton.filled] (*new*), [IconButton.filledTonal], [IconButton.outlined] /// - Segmented buttons: [SegmentedButton] (replacing [ToggleButtons]) /// * Cards: [Card] /// * Checkbox: [Checkbox], [CheckboxListTile] @@ -1156,11 +1150,11 @@ class ThemeData with Diagnosticable { /// * Navigation rail: [NavigationRail] /// * Progress indicators: [CircularProgressIndicator], [LinearProgressIndicator] /// * Radio button: [Radio], [RadioListTile] - /// * Search: [SearchBar] (*new*), [SearchAnchor] (*new*), + /// * Search: [SearchBar], [SearchAnchor], /// * Snack bar: [SnackBar] /// * Slider: [Slider], [RangeSlider] /// * Switch: [Switch], [SwitchListTile] - /// * Tabs: [TabBar], [TabBar.secondary] (*new*) + /// * Tabs: [TabBar], [TabBar.secondary] /// * TextFields: [TextField] together with its [InputDecoration] /// * Time pickers: [showTimePicker], [TimePickerDialog] /// * Top app bar: [AppBar], [SliverAppBar], [SliverAppBar.medium], [SliverAppBar.large] From b42879a94e2ca8524d16e4cd76fde27534816023 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Tue, 18 Jul 2023 11:38:12 -0700 Subject: [PATCH 0233/1547] [Android] Deletes deprecated splash screen meta-data element (#130744) Deletes deprecated splash screen meta-data element. This is no longer needed to present a splash screen in a Flutter application, but will be removed soon. See [go/flutter-splash-screen-migration](http://go/flutter-splash-screen-migration) for more information. Part of https://github.com/flutter/flutter/issues/105173. --- .../android/app/src/main/AndroidManifest.xml | 9 --------- .../test_data/deferred_components_project.dart | 9 --------- 2 files changed, 18 deletions(-) diff --git a/dev/integration_tests/deferred_components_test/android/app/src/main/AndroidManifest.xml b/dev/integration_tests/deferred_components_test/android/app/src/main/AndroidManifest.xml index 7ba934d1e32da..c43b90e80fc8f 100644 --- a/dev/integration_tests/deferred_components_test/android/app/src/main/AndroidManifest.xml +++ b/dev/integration_tests/deferred_components_test/android/app/src/main/AndroidManifest.xml @@ -28,15 +28,6 @@ found in the LICENSE file. --> android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> - - diff --git a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart index 35a7c1cbc26e4..fb59d2aa65406 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart @@ -508,15 +508,6 @@ class BasicDeferredComponentsConfig extends DeferredComponentsConfig { android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> - - From 8fa71cbbc5e4790b3f74a3ffa131e6a8c26d069f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 14:52:24 -0400 Subject: [PATCH 0234/1547] Roll Flutter Engine from 831da7e9dc3b to 45851af55bd6 (2 revisions) (#130814) https://github.com/flutter/engine/compare/831da7e9dc3b...45851af55bd6 2023-07-18 zanderso@users.noreply.github.com Reset Dart VM optimization level to 2 (flutter/engine#43770) 2023-07-18 jonahwilliams@google.com [Impeller] Avoid inserting additional save layers based on clip configuration. (flutter/engine#43759) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1e6bf665ed269..f2ca88dbcf274 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -831da7e9dc3b8be5ba70f0976efb4a4f168bb3dd +45851af55bd6066b7b912af0bdd5968830f7bd4b From 60425b3c5e396343f5a425209d11df644104475d Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:40:23 -0700 Subject: [PATCH 0235/1547] Roll pub packages (#130608) This PR was generated by `flutter update-packages --force-upgrade`. From bb798e2a845ae294bb033d23b5e6caf72abca1c4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 16:45:06 -0400 Subject: [PATCH 0236/1547] Roll Flutter Engine from 45851af55bd6 to 71bbecee3010 (7 revisions) (#130820) https://github.com/flutter/engine/compare/45851af55bd6...71bbecee3010 2023-07-18 mdebbar@google.com [web] sync => isSync , scuba => golden (flutter/engine#43699) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 219ca2581ab2 to 4e518e65fea0 (2 revisions) (flutter/engine#43777) 2023-07-18 skia-flutter-autoroll@skia.org Roll ANGLE from 113f847be69f to 52fe3116ead9 (146 revisions) (flutter/engine#43776) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from b7103fe086c1 to 219ca2581ab2 (1 revision) (flutter/engine#43774) 2023-07-18 chillers@google.com [ci.yaml] Skip windows arm on releases (flutter/engine#43771) 2023-07-18 gspencergoog@users.noreply.github.com Check FlutterAppDelegate selector support before calling (flutter/engine#43425) 2023-07-18 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from _CIP-1iUTmGCbCDZ5... to SCshjyIlymHWD9W4D... (flutter/engine#43773) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from _CIP-1iUTmGC to SCshjyIlymHW If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f2ca88dbcf274..db77b077abb66 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -45851af55bd6066b7b912af0bdd5968830f7bd4b +71bbecee301037eec63d898fcf9f6b136e4819e7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index b74c44390fff2..92ddc24221eb5 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -_CIP-1iUTmGCbCDZ50br0bLzTWEMTtTBH55gpi2EcQgC +SCshjyIlymHWD9W4DLT9CHMS3_5QMCQDb-m-DLzJi78C From c6b93b2db7fa20acf7af4be6cd3bfcead655dead Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Tue, 18 Jul 2023 13:59:48 -0700 Subject: [PATCH 0237/1547] Relax syntax for gen-l10n (#130736) To preserve backward compatibility with the old parser which would ignore syntax errors, this PR introduces a way to treat the special characters `{` and `}` in the following way: 1. If we encounter a `{` which searching for a string token and this `{` is not followed by a valid placeholder, then we treat the `{` as a string and continue lexing for strings. 2. If we encounter a `}` while not within some expression (i.e. placeholders, arguments, plurals, or selects), then we treat the `}` as a string and continue lexing for strings. This makes it so that ``` "helloWorld": "{ } { placeholder }", "@@helloWorld": { "placeholders": { "placeholder" {} } } ``` treats the `{ }` as a string while `{ placeholder } ` is treated as a placeholder. Fixes https://github.com/flutter/flutter/issues/122404. --- .../src/commands/generate_localizations.dart | 7 +++ .../lib/src/localizations/gen_l10n.dart | 15 +++++- .../lib/src/localizations/gen_l10n_types.dart | 9 +++- .../localizations/localizations_utils.dart | 15 +++++- .../lib/src/localizations/message_parser.dart | 37 ++++++++++++-- .../generate_localizations_test.dart | 18 +++++++ .../general.shard/message_parser_test.dart | 48 +++++++++++++++++++ 7 files changed, 143 insertions(+), 6 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/generate_localizations.dart b/packages/flutter_tools/lib/src/commands/generate_localizations.dart index 452dc19a0bbeb..f7dd479fbe48e 100644 --- a/packages/flutter_tools/lib/src/commands/generate_localizations.dart +++ b/packages/flutter_tools/lib/src/commands/generate_localizations.dart @@ -200,6 +200,13 @@ class GenerateLocalizationsCommand extends FlutterCommand { 'suppress-warnings', help: 'When specified, all warnings will be suppressed.\n' ); + argParser.addFlag( + 'relax-syntax', + help: 'When specified, the syntax will be relaxed so that the special character ' + '"{" is treated as a string if it is not followed by a valid placeholder ' + 'and "}" is treated as a string if it does not close any previous "{" ' + 'that is treated as a special character.', + ); } final FileSystem _fileSystem; diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 4288d5fdd163f..84d37b5e33d56 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -72,6 +72,7 @@ Future generateLocalizations({ useEscaping: options.useEscaping, logger: logger, suppressWarnings: options.suppressWarnings, + useRelaxedSyntax: options.relaxSyntax, ) ..loadResources() ..writeOutputFiles(isFromYaml: true, useCRLF: useCRLF); @@ -494,6 +495,7 @@ class LocalizationsGenerator { bool useEscaping = false, required Logger logger, bool suppressWarnings = false, + bool useRelaxedSyntax = false, }) { final Directory? projectDirectory = projectDirFromPath(fileSystem, projectPathString); final Directory inputDirectory = inputDirectoryFromPath(fileSystem, inputPathString, projectDirectory); @@ -517,6 +519,7 @@ class LocalizationsGenerator { useEscaping: useEscaping, logger: logger, suppressWarnings: suppressWarnings, + useRelaxedSyntax: useRelaxedSyntax, ); } @@ -541,6 +544,7 @@ class LocalizationsGenerator { required this.logger, this.useEscaping = false, this.suppressWarnings = false, + this.useRelaxedSyntax = false, }); final FileSystem _fs; @@ -617,6 +621,9 @@ class LocalizationsGenerator { /// from calling [_generateMethod]. bool hadErrors = false; + /// Whether to use relaxed syntax. + bool useRelaxedSyntax = false; + /// The list of all arb path strings in [inputDirectory]. List get arbPathStrings { return _allBundles.bundles.map((AppResourceBundle bundle) => bundle.file.path).toList(); @@ -908,7 +915,13 @@ class LocalizationsGenerator { } // The call to .toList() is absolutely necessary. Otherwise, it is an iterator and will call Message's constructor again. _allMessages = _templateBundle.resourceIds.map((String id) => Message( - _templateBundle, _allBundles, id, areResourceAttributesRequired, useEscaping: useEscaping, logger: logger, + _templateBundle, + _allBundles, + id, + areResourceAttributesRequired, + useEscaping: useEscaping, + logger: logger, + useRelaxedSyntax: useRelaxedSyntax, )).toList(); hadErrors = _allMessages.any((Message message) => message.hadErrors); if (inputsAndOutputsListFile != null) { diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart index a978e43794343..0ea3050e6152c 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart @@ -336,6 +336,7 @@ class Message { this.resourceId, bool isResourceAttributeRequired, { + this.useRelaxedSyntax = false, this.useEscaping = false, this.logger, } @@ -352,13 +353,18 @@ class Message { filenames[bundle.locale] = bundle.file.basename; final String? translation = bundle.translationFor(resourceId); messages[bundle.locale] = translation; + List? validPlaceholders; + if (useRelaxedSyntax) { + validPlaceholders = placeholders.entries.map((MapEntry e) => e.key).toList(); + } try { parsedMessages[bundle.locale] = translation == null ? null : Parser( resourceId, bundle.file.basename, translation, useEscaping: useEscaping, - logger: logger + placeholders: validPlaceholders, + logger: logger, ).parse(); } on L10nParserException catch (error) { logger?.printError(error.toString()); @@ -378,6 +384,7 @@ class Message { final Map parsedMessages; final Map placeholders; final bool useEscaping; + final bool useRelaxedSyntax; final Logger? logger; bool hadErrors = false; diff --git a/packages/flutter_tools/lib/src/localizations/localizations_utils.dart b/packages/flutter_tools/lib/src/localizations/localizations_utils.dart index 329f425a9bc23..84bfa86251629 100644 --- a/packages/flutter_tools/lib/src/localizations/localizations_utils.dart +++ b/packages/flutter_tools/lib/src/localizations/localizations_utils.dart @@ -354,6 +354,7 @@ class LocalizationOptions { bool? format, bool? useEscaping, bool? suppressWarnings, + bool? relaxSyntax, }) : templateArbFile = templateArbFile ?? 'app_en.arb', outputLocalizationFile = outputLocalizationFile ?? 'app_localizations.dart', outputClass = outputClass ?? 'AppLocalizations', @@ -363,7 +364,8 @@ class LocalizationOptions { nullableGetter = nullableGetter ?? true, format = format ?? false, useEscaping = useEscaping ?? false, - suppressWarnings = suppressWarnings ?? false; + suppressWarnings = suppressWarnings ?? false, + relaxSyntax = relaxSyntax ?? false; /// The `--arb-dir` argument. /// @@ -455,6 +457,16 @@ class LocalizationOptions { /// /// Whether or not to suppress warnings. final bool suppressWarnings; + + /// The `relax-syntax` argument. + /// + /// Whether or not to relax the syntax. When specified, the syntax will be + /// relaxed so that the special character "{" is treated as a string if it is + /// not followed by a valid placeholder and "}" is treated as a string if it + /// does not close any previous "{" that is treated as a special character. + /// This was added in for backward compatibility and is not recommended + /// as it may mask errors. + final bool relaxSyntax; } /// Parse the localizations configuration options from [file]. @@ -498,6 +510,7 @@ LocalizationOptions parseLocalizationsOptionsFromYAML({ format: _tryReadBool(yamlNode, 'format', logger), useEscaping: _tryReadBool(yamlNode, 'use-escaping', logger), suppressWarnings: _tryReadBool(yamlNode, 'suppress-warnings', logger), + relaxSyntax: _tryReadBool(yamlNode, 'relax-syntax', logger), ); } diff --git a/packages/flutter_tools/lib/src/localizations/message_parser.dart b/packages/flutter_tools/lib/src/localizations/message_parser.dart index 49a04fff4858d..6591d9da23660 100644 --- a/packages/flutter_tools/lib/src/localizations/message_parser.dart +++ b/packages/flutter_tools/lib/src/localizations/message_parser.dart @@ -198,7 +198,8 @@ class Parser { this.messageString, { this.useEscaping = false, - this.logger + this.logger, + this.placeholders, } ); @@ -207,6 +208,7 @@ class Parser { final String filename; final bool useEscaping; final Logger? logger; + final List? placeholders; static String indentForError(int position) { return '${List.filled(position, ' ').join()}^'; @@ -216,12 +218,16 @@ class Parser { // every instance of "{" and "}" toggles the isString boolean and every // instance of "'" toggles the isEscaped boolean (and treats a double // single quote "''" as a single quote "'"). When !isString and !isEscaped - // delimit tokens by whitespace and special characters. + // delimit tokens by whitespace and special characters. When placeholders + // is passed, relax the syntax so that "{" and "}" can be used as strings in + // certain cases. List lexIntoTokens() { + final bool useRelaxedLexer = placeholders != null; final List tokens = []; bool isString = true; // Index specifying where to match from int startIndex = 0; + int depth = 0; // At every iteration, we should be able to match a new token until we // reach the end of the string. If for some reason we don't match a @@ -267,9 +273,28 @@ class Parser { } match = brace.matchAsPrefix(messageString, startIndex); if (match != null) { + final String matchedBrace = match.group(0)!; + if (useRelaxedLexer) { + final Match? whitespaceMatch = whitespace.matchAsPrefix(messageString, match.end); + final int endOfWhitespace = whitespaceMatch?.group(0) == null ? match.end : whitespaceMatch!.end; + final Match? identifierMatch = alphanumeric.matchAsPrefix(messageString, endOfWhitespace); + // If we match a "}" and the depth is 0, treat it as a string. + // If we match a "{" and the next token is not a valid placeholder, treat it as a string. + if (matchedBrace == '}' && depth == 0) { + tokens.add(Node.string(startIndex, matchedBrace)); + startIndex = match.end; + continue; + } + if (matchedBrace == '{' && (identifierMatch == null || !placeholders!.contains(identifierMatch.group(0)))) { + tokens.add(Node.string(startIndex, matchedBrace)); + startIndex = match.end; + continue; + } + } tokens.add(Node.brace(startIndex, match.group(0)!)); isString = false; startIndex = match.end; + depth += 1; continue; } // Theoretically, we only reach this point because of unmatched single quotes because @@ -299,9 +324,15 @@ class Parser { if (match == null) { match = brace.matchAsPrefix(messageString, startIndex); if (match != null) { - tokens.add(Node.brace(startIndex, match.group(0)!)); + final String matchedBrace = match.group(0)!; + tokens.add(Node.brace(startIndex, matchedBrace)); isString = true; startIndex = match.end; + if (matchedBrace == '{') { + depth += 1; + } else { + depth -= 1; + } continue; } // This should only happen when there are special characters we are unable to match. diff --git a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart index 67cc9667a27c1..fa35cfd510b45 100644 --- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart @@ -95,6 +95,7 @@ void main() { bool useEscaping = false, bool areResourceAttributeRequired = false, bool suppressWarnings = false, + bool relaxSyntax = false, void Function(Directory)? setup, } ) { @@ -126,6 +127,7 @@ void main() { useEscaping: useEscaping, areResourceAttributesRequired: areResourceAttributeRequired, suppressWarnings: suppressWarnings, + useRelaxedSyntax: relaxSyntax, ) ..loadResources() ..writeOutputFiles(isFromYaml: isFromYaml); @@ -1475,6 +1477,22 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e expect(getGeneratedFileContent(locale: 'en'), contains('String helloWorld(Object name) {')); expect(getGeneratedFileContent(locale: 'es'), contains('String helloWorld(Object name) {')); }); + + testWithoutContext('braces are ignored as special characters if placeholder does not exist', () { + setupLocalizations({ + 'en': ''' +{ + "helloWorld": "Hello {name}", + "@@helloWorld": { + "placeholders": { + "names": {} + } + } +}''' + }, relaxSyntax: true); + final String content = getGeneratedFileContent(locale: 'en'); + expect(content, contains("String get helloWorld => 'Hello {name}'")); + }); }); group('DateTime tests', () { diff --git a/packages/flutter_tools/test/general.shard/message_parser_test.dart b/packages/flutter_tools/test/general.shard/message_parser_test.dart index efc9680adf249..3b716cd3c05ae 100644 --- a/packages/flutter_tools/test/general.shard/message_parser_test.dart +++ b/packages/flutter_tools/test/general.shard/message_parser_test.dart @@ -293,6 +293,54 @@ void main() { ))); }); + testWithoutContext('relaxed lexer', () { + final List tokens1 = Parser( + 'string', + 'app_en.arb', + '{ }', + placeholders: [], + ).lexIntoTokens(); + expect(tokens1, equals([ + Node(ST.string, 0, value: '{'), + Node(ST.string, 1, value: ' '), + Node(ST.string, 2, value: '}') + ])); + + final List tokens2 = Parser( + 'string', + 'app_en.arb', + '{ notAPlaceholder }', + placeholders: ['isAPlaceholder'], + ).lexIntoTokens(); + expect(tokens2, equals([ + Node(ST.string, 0, value: '{'), + Node(ST.string, 1, value: ' notAPlaceholder '), + Node(ST.string, 18, value: '}') + ])); + + final List tokens3 = Parser( + 'string', + 'app_en.arb', + '{ isAPlaceholder }', + placeholders: ['isAPlaceholder'], + ).lexIntoTokens(); + expect(tokens3, equals([ + Node(ST.openBrace, 0, value: '{'), + Node(ST.identifier, 2, value: 'isAPlaceholder'), + Node(ST.closeBrace, 17, value: '}') + ])); + }); + + testWithoutContext('relaxed lexer complex', () { + const String message = '{ notPlaceholder } {count,plural, =0{Hello} =1{Hello World} =2{Hello two worlds} few{Hello {count} worlds} many{Hello all {count} worlds} other{Hello other {count} worlds}}'; + final List tokens = Parser( + 'string', + 'app_en.arb', + message, + placeholders: ['count'], + ).lexIntoTokens(); + expect(tokens[0].type, equals(ST.string)); + }); testWithoutContext('parser basic', () { expect(Parser('helloWorld', 'app_en.arb', 'Hello {name}').parse(), equals( From edcaa335d11ebdf839beb3947ac939b4425cadbc Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:55:17 -0700 Subject: [PATCH 0238/1547] Roll pub packages (#130821) This PR was generated by `flutter update-packages --force-upgrade`. --- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/complex_layout/pubspec.yaml | 4 ++-- dev/benchmarks/macrobenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/microbenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_views_layout/pubspec.yaml | 4 ++-- .../platform_views_layout_hybrid_composition/pubspec.yaml | 4 ++-- dev/benchmarks/test_apps/stocks/pubspec.yaml | 4 ++-- dev/bots/pubspec.yaml | 4 ++-- dev/conductor/core/pubspec.yaml | 4 ++-- dev/customer_testing/pubspec.yaml | 4 ++-- dev/devicelab/pubspec.yaml | 4 ++-- dev/integration_tests/android_semantics_testing/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 4 ++-- dev/integration_tests/channels/pubspec.yaml | 4 ++-- dev/integration_tests/deferred_components_test/pubspec.yaml | 4 ++-- dev/integration_tests/external_ui/pubspec.yaml | 4 ++-- dev/integration_tests/flavors/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- dev/integration_tests/gradle_deprecated_settings/pubspec.yaml | 4 ++-- dev/integration_tests/hybrid_android_views/pubspec.yaml | 4 ++-- dev/integration_tests/ios_platform_view_tests/pubspec.yaml | 4 ++-- dev/integration_tests/platform_interaction/pubspec.yaml | 4 ++-- dev/integration_tests/release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- dev/integration_tests/windows_startup_test/pubspec.yaml | 4 ++-- dev/tools/gen_defaults/pubspec.yaml | 4 ++-- dev/tools/gen_keycodes/pubspec.yaml | 4 ++-- dev/tools/pubspec.yaml | 4 ++-- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 4 ++-- examples/hello_world/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 4 ++-- examples/platform_channel_swift/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 4 ++-- packages/flutter/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_tools/pubspec.yaml | 4 ++-- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 4 ++-- packages/integration_test/example/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 44 files changed, 88 insertions(+), 88 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 78466d3d6304c..56cba7ffe116f 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -61,7 +61,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 62e1 +# PUBSPEC CHECKSUM: a0e0 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 4331605f94924..540d800d05924 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: e1ba +# PUBSPEC CHECKSUM: 00b9 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index b4c6c650f2fc4..6ab3a87e4404e 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -211,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: e1ba +# PUBSPEC CHECKSUM: 00b9 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index aaf8d8f1f1fb5..d8b83e1034d0b 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -138,4 +138,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 5532 +# PUBSPEC CHECKSUM: 9331 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index 9a1e0a2fe7f1e..47ceda0564f0b 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 051d +# PUBSPEC CHECKSUM: 431c diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 6fc9f64dd3bef..0a769e35b444e 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: e1ba +# PUBSPEC CHECKSUM: 00b9 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index f0cf52b706b8c..c0de6537855f9 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: e1ba +# PUBSPEC CHECKSUM: 00b9 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index c54dd5fc92ad5..7ddb24b28193a 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -67,7 +67,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 67dc +# PUBSPEC CHECKSUM: 85db diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index c992ede277c44..ce8caef99192b 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: d7d7 +# PUBSPEC CHECKSUM: 16d6 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 831df5d3c23b2..33940c2c93d05 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -60,10 +60,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: eebd +# PUBSPEC CHECKSUM: 4bbc diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 2c451222cf110..a5bbf7d46aced 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -50,10 +50,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 940b +# PUBSPEC CHECKSUM: f00a diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 924bcfc78957d..26227aef98648 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: shelf: 1.4.1 shelf_static: 1.1.2 stack_trace: 1.11.1 - vm_service: 11.7.2 + vm_service: 11.8.0 web: 0.1.4-beta webkit_inspection_protocol: 1.2.0 @@ -70,4 +70,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: cd45 +# PUBSPEC CHECKSUM: 0c44 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index eb7899b5447fe..778543bed908d 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -57,7 +57,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 79da +# PUBSPEC CHECKSUM: b7d9 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 92b24ab097ad6..cd9b03e750718 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -45,7 +45,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d1b7 +# PUBSPEC CHECKSUM: abb6 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index 0a8e882e3c6a4..dbae723619e5b 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -37,10 +37,10 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4738 +# PUBSPEC CHECKSUM: 0c37 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 0aa2933ab3b4e..5b34a7ce41ddc 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index d0e1921531a32..f27bd9f7b0b20 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: c363 +# PUBSPEC CHECKSUM: e162 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 4a1bf4d3bb8f9..43d0b1b66bc8c 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -57,7 +57,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index cc8ca6da0a32c..ade76b8cbfcdf 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -100,7 +100,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 2205 +# PUBSPEC CHECKSUM: 4004 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 0cff6ce665b12..e2555a9ad85fb 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.1+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bf03 +# PUBSPEC CHECKSUM: 6604 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index eafd3366ce822..388af25d65588 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -43,7 +43,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d1b7 +# PUBSPEC CHECKSUM: abb6 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 0ce093a668287..66217c52f6e2a 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,4 +78,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 49b4710fce6ba..284708d57ebc7 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: c363 +# PUBSPEC CHECKSUM: e162 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 2bc9222f084fe..44016266a04cf 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -32,6 +32,6 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 07fe +# PUBSPEC CHECKSUM: ebfd diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index cf9b04a3e2f54..7f5fcdc2ff351 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -66,7 +66,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: d9a6 +# PUBSPEC CHECKSUM: bea5 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 8410214f74443..07aa059c3607f 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index e736b7f7844fc..2b811d248cfb3 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2405 +# PUBSPEC CHECKSUM: 4204 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index aa93540b22089..06e2922c978e1 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -36,9 +36,9 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 07fe +# PUBSPEC CHECKSUM: ebfd diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 2c10a2862126d..fd8de2469cac3 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +63,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c363 +# PUBSPEC CHECKSUM: e162 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 3222e85e1d4b6..8dd67d33b4e65 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -50,10 +50,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 940b +# PUBSPEC CHECKSUM: f00a diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 53abe32375184..e06fa8947e618 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -52,10 +52,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7602 +# PUBSPEC CHECKSUM: d201 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 30039144ebdde..3b8fccad2aba3 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -56,10 +56,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0d1c +# PUBSPEC CHECKSUM: 691b diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 3ac5761dbaaab..f9755ff87a314 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: flutter: sdk: flutter - vm_service: 11.7.2 + vm_service: 11.8.0 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 07fe +# PUBSPEC CHECKSUM: ebfd diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 73110a6c09e8e..38499d6262ddc 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -76,7 +76,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +86,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 62ce +# PUBSPEC CHECKSUM: 80cd diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index b5ad48b7986c7..264313489b832 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -62,11 +62,11 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index a6026f54880f9..0d4d725a3217e 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -62,7 +62,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 7b2164bfc3bca..1aecf2c579eb1 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -62,7 +62,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: be20 +# PUBSPEC CHECKSUM: dc1f diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 891bf363a1957..4d7b54f59d587 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -59,10 +59,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 79da +# PUBSPEC CHECKSUM: b7d9 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index bb188d46228e7..6bfb18f9684ee 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -68,10 +68,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: cdf0 +# PUBSPEC CHECKSUM: 0cef diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 15e98d5d0a69a..625779d3820b5 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: sdk: flutter path: 1.8.3 meta: 1.9.1 - vm_service: 11.7.2 + vm_service: 11.8.0 webdriver: 3.0.2 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6927 +# PUBSPEC CHECKSUM: 8726 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 39b142c5f17e2..a3e273d8b2222 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_api: 0.6.1 test_core: 0.5.4 - vm_service: 11.7.2 + vm_service: 11.8.0 standard_message_codec: 0.0.1+3 @@ -107,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 5e34 +# PUBSPEC CHECKSUM: 5033 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index b02d25646833f..f2bd16ab49b33 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -8,7 +8,7 @@ environment: dependencies: process: 4.2.4 - vm_service: 11.7.2 + vm_service: 11.8.0 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +64,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 4a12 +# PUBSPEC CHECKSUM: a611 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 754a3cd42c69d..7ace2b654a7dd 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -75,7 +75,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.7.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 108e +# PUBSPEC CHECKSUM: 2e8d diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 9206b04d52b4c..8ae84f8cc7399 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: flutter_test: sdk: flutter path: 1.8.3 - vm_service: 11.7.2 + vm_service: 11.8.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 4738 +# PUBSPEC CHECKSUM: 0c37 From e29f2b98af5d0e2aedc4b60afcbf85ba52997d6f Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Wed, 19 Jul 2023 00:10:17 +0200 Subject: [PATCH 0239/1547] Update SnackBar tests for M2/M3 (#130717) This PR updates unit tests for `SnackBar` to have M2 and M3 versions. More info in https://github.com/flutter/flutter/issues/127064 --- .../flutter/test/material/snack_bar_test.dart | 677 ++++++++++++++++-- 1 file changed, 625 insertions(+), 52 deletions(-) diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index 0cd5479071306..9436f743b4e30 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -10,6 +10,7 @@ library; import 'dart:async'; import 'dart:ui'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -302,7 +303,7 @@ void main() { expect(tapCount, equals(1)); }); - testWidgets('Light theme SnackBar has dark background', (WidgetTester tester) async { + testWidgets('Material2 - Light theme SnackBar has dark background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -344,6 +345,45 @@ void main() { expect(renderModel.color, equals(const Color(0xFF333333))); }); + testWidgets('Material3 - Light theme SnackBar has dark background', (WidgetTester tester) async { + final ThemeData lightTheme = ThemeData.light(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: lightTheme, + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction( + label: 'ACTION', + onPressed: () { }, + ), + ), + ); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + ); + + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); + + final Finder material = find.widgetWithText(Material, 'I am a snack bar.').first; + final RenderPhysicalModel renderModel = tester.renderObject(material); + + expect(renderModel.color, equals(lightTheme.colorScheme.inverseSurface)); + }); + testWidgets('Dark theme SnackBar has light background', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(); await tester.pumpWidget( @@ -383,7 +423,7 @@ void main() { expect(renderModel.color, equals(darkTheme.colorScheme.onSurface)); }); - testWidgets('Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { + testWidgets('Material2 - Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -422,6 +462,45 @@ void main() { expect(buttonTextStyle.color, equals(darkTheme.colorScheme.primary)); }); + testWidgets('Material3 - Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { + final ThemeData darkTheme = ThemeData.dark(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: darkTheme, + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction( + label: 'ACTION', + onPressed: () { }, + ), + ), + ); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + ); + + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); + + final TextStyle buttonTextStyle = tester.widget( + find.descendant(of: find.text('ACTION'), matching: find.byType(RichText)) + ).text.style!; + expect(buttonTextStyle.color, equals(darkTheme.colorScheme.inversePrimary)); + }); + testWidgets('SnackBar should inherit theme data from its ancestor.', (WidgetTester tester) async { final SliderThemeData sliderTheme = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, @@ -767,9 +846,7 @@ void main() { expect(snackBarBottomRight.dx, (800 + width) / 2); // Device width is 800. }); - testWidgets( - 'Snackbar width customization takes preference of widget over theme', - (WidgetTester tester) async { + testWidgets('Snackbar width customization takes preference of widget over theme', (WidgetTester tester) async { const double themeWidth = 200.0; const double widgetWidth = 400.0; await tester.pumpWidget( @@ -812,9 +889,10 @@ void main() { expect(snackBarBottomRight.dx, (800 + widgetWidth) / 2); // Device width is 800. }); - testWidgets('Snackbar labels can be colored as MaterialColor (Material 2)', (WidgetTester tester) async { + testWidgets('Material2 - Snackbar labels can be colored as MaterialColor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( + theme: ThemeData(useMaterial3: false), home: Scaffold( body: Builder( builder: (BuildContext context) { @@ -856,8 +934,7 @@ void main() { } }); - testWidgets('Snackbar labels can be colored as MaterialColor (Material 3)', - (WidgetTester tester) async { + testWidgets('Material3 - Snackbar labels can be colored as MaterialColor', (WidgetTester tester) async { const MaterialColor usedColor = Colors.teal; await tester.pumpWidget( @@ -960,7 +1037,7 @@ void main() { } }); - testWidgets('SnackBar button text alignment', (WidgetTester tester) async { + testWidgets('Material2 - SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: MediaQuery( @@ -1008,8 +1085,56 @@ void main() { expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 17.0 + 40.0); // margin + bottom padding }); + testWidgets('Material3 - SnackBar button text alignment', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: MediaQuery( + data: const MediaQueryData( + padding: EdgeInsets.only( + left: 10.0, + top: 20.0, + right: 30.0, + bottom: 40.0, + ), + ), + child: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () { }), + )); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + )); + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); // Animation last frame. + + final Offset textBottomLeft = tester.getBottomLeft(find.text('I am a snack bar.')); + final Offset textBottomRight = tester.getBottomRight(find.text('I am a snack bar.')); + final Offset actionTextBottomLeft = tester.getBottomLeft(find.text('ACTION')); + final Offset actionTextBottomRight = tester.getBottomRight(find.text('ACTION')); + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + final Offset snackBarBottomRight = tester.getBottomRight(find.byType(SnackBar)); + + expect(textBottomLeft.dx - snackBarBottomLeft.dx, 24.0 + 10.0); // margin + left padding + expect(snackBarBottomLeft.dy - textBottomLeft.dy, 14.0 + 40.0); // margin + bottom padding + expect(actionTextBottomLeft.dx - textBottomRight.dx, 24.0 + 12.0); // action padding + margin + expect(snackBarBottomRight.dx - actionTextBottomRight.dx, 24.0 + 12.0 + 30.0); // action (padding + margin) + right padding + expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 14.0 + 40.0); // margin + bottom padding + }); + testWidgets( - 'Custom padding between SnackBar and its contents when set to SnackBarBehavior.fixed', + 'Material2 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.fixed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1065,6 +1190,63 @@ void main() { }, ); + testWidgets( + 'Material3 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.fixed', + (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: MediaQuery( + data: const MediaQueryData( + padding: EdgeInsets.only( + left: 10.0, + top: 20.0, + right: 30.0, + bottom: 40.0, + ), + ), + child: Scaffold( + bottomNavigationBar: BottomNavigationBar( + items: const [ + BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Animutation'), + BottomNavigationBarItem(icon: Icon(Icons.block), label: 'Zombo.com'), + ], + ), + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + )); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + )); + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); // Animation last frame. + + final Offset textBottomLeft = tester.getBottomLeft(find.text('I am a snack bar.')); + final Offset textBottomRight = tester.getBottomRight(find.text('I am a snack bar.')); + final Offset actionTextBottomLeft = tester.getBottomLeft(find.text('ACTION')); + final Offset actionTextBottomRight = tester.getBottomRight(find.text('ACTION')); + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + final Offset snackBarBottomRight = tester.getBottomRight(find.byType(SnackBar)); + + expect(textBottomLeft.dx - snackBarBottomLeft.dx, 24.0 + 10.0); // margin + left padding + expect(snackBarBottomLeft.dy - textBottomLeft.dy, 14.0); // margin (with no bottom padding) + expect(actionTextBottomLeft.dx - textBottomRight.dx, 24.0 + 12.0); // action padding + margin + expect(snackBarBottomRight.dx - actionTextBottomRight.dx, 24.0 + 12.0 + 30.0); // action (padding + margin) + right padding + expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 14.0); // margin (with no bottom padding) + }, + ); + testWidgets('SnackBar should push FloatingActionButton above', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( @@ -1120,7 +1302,7 @@ void main() { expect(fabRect.bottomRight.dy, snackBarTopRight.dy - defaultFabPadding); }); - testWidgets('Floating SnackBar button text alignment', (WidgetTester tester) async { + testWidgets('Material2 - Floating SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -1171,12 +1353,123 @@ void main() { expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 27.0); // margin (with no bottom padding) }); + testWidgets('Material3 - Floating SnackBar button text alignment', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData( + useMaterial3: true, + snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating), + ), + home: MediaQuery( + data: const MediaQueryData( + padding: EdgeInsets.only( + left: 10.0, + top: 20.0, + right: 30.0, + bottom: 40.0, + ), + ), + child: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + )); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + )); + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); // Animation last frame. + + final Offset textBottomLeft = tester.getBottomLeft(find.text('I am a snack bar.')); + final Offset textBottomRight = tester.getBottomRight(find.text('I am a snack bar.')); + final Offset actionTextBottomLeft = tester.getBottomLeft(find.text('ACTION')); + final Offset actionTextBottomRight = tester.getBottomRight(find.text('ACTION')); + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + final Offset snackBarBottomRight = tester.getBottomRight(find.byType(SnackBar)); + + expect(textBottomLeft.dx - snackBarBottomLeft.dx, 31.0 + 10.0); // margin + left padding + expect(snackBarBottomLeft.dy - textBottomLeft.dy, 24.0); // margin (with no bottom padding) + expect(actionTextBottomLeft.dx - textBottomRight.dx, 16.0 + 8.0); // action padding + margin + expect(snackBarBottomRight.dx - actionTextBottomRight.dx, 31.0 + 30.0 + 8.0); // margin + right (padding + margin) + expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 24.0); // margin (with no bottom padding) + }); + + testWidgets( + 'Material2 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.floating', + (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData( + useMaterial3: false, + snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating), + ), + home: MediaQuery( + data: const MediaQueryData( + padding: EdgeInsets.only( + left: 10.0, + top: 20.0, + right: 30.0, + bottom: 40.0, + ), + ), + child: Scaffold( + bottomNavigationBar: BottomNavigationBar( + items: const [ + BottomNavigationBarItem(icon: Icon(Icons.favorite), label: 'Animutation'), + BottomNavigationBarItem(icon: Icon(Icons.block), label: 'Zombo.com'), + ], + ), + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + )); + }, + child: const Text('X'), + ); + }, + ), + ), + ), + )); + await tester.tap(find.text('X')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); // Animation last frame. + + final Offset textBottomLeft = tester.getBottomLeft(find.text('I am a snack bar.')); + final Offset textBottomRight = tester.getBottomRight(find.text('I am a snack bar.')); + final Offset actionTextBottomLeft = tester.getBottomLeft(find.text('ACTION')); + final Offset actionTextBottomRight = tester.getBottomRight(find.text('ACTION')); + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + final Offset snackBarBottomRight = tester.getBottomRight(find.byType(SnackBar)); + + expect(textBottomLeft.dx - snackBarBottomLeft.dx, 31.0 + 10.0); // margin + left padding + expect(snackBarBottomLeft.dy - textBottomLeft.dy, 27.0); // margin (with no bottom padding) + expect(actionTextBottomLeft.dx - textBottomRight.dx, 16.0 + 8.0); // action (margin + padding) + expect(snackBarBottomRight.dx - actionTextBottomRight.dx, 31.0 + 30.0 + 8.0); // margin + right (padding + margin) + expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 27.0); // margin (with no bottom padding) + }, + ); + testWidgets( - 'Custom padding between SnackBar and its contents when set to SnackBarBehavior.floating', + 'Material3 - Custom padding between SnackBar and its contents when set to SnackBarBehavior.floating', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( - useMaterial3: false, + useMaterial3: true, snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating), ), home: MediaQuery( @@ -1224,10 +1517,10 @@ void main() { final Offset snackBarBottomRight = tester.getBottomRight(find.byType(SnackBar)); expect(textBottomLeft.dx - snackBarBottomLeft.dx, 31.0 + 10.0); // margin + left padding - expect(snackBarBottomLeft.dy - textBottomLeft.dy, 27.0); // margin (with no bottom padding) + expect(snackBarBottomLeft.dy - textBottomLeft.dy, 24.0); // margin (with no bottom padding) expect(actionTextBottomLeft.dx - textBottomRight.dx, 16.0 + 8.0); // action (margin + padding) expect(snackBarBottomRight.dx - actionTextBottomRight.dx, 31.0 + 30.0 + 8.0); // margin + right (padding + margin) - expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 27.0); // margin (with no bottom padding) + expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 24.0); // margin (with no bottom padding) }, ); @@ -1858,16 +2151,12 @@ void main() { await tester.pumpAndSettle(); // Have the SnackBar fully animate out. } - void expectSnackBarNotVisibleError(WidgetTester tester) { - final AssertionError exception = tester.takeException() as AssertionError; - const String message = 'Floating SnackBar presented off screen.\n' - 'A SnackBar with behavior property set to SnackBarBehavior.floating is fully ' - 'or partially off screen because some or all the widgets provided to ' - 'Scaffold.floatingActionButton, Scaffold.persistentFooterButtons and ' - 'Scaffold.bottomNavigationBar take up too much vertical space.\n' - 'Consider constraining the size of these widgets to allow room for the SnackBar to be visible.'; - expect(exception.message, message); - } + const String offScreenMessage = 'Floating SnackBar presented off screen.\n' + 'A SnackBar with behavior property set to SnackBarBehavior.floating is fully ' + 'or partially off screen because some or all the widgets provided to ' + 'Scaffold.floatingActionButton, Scaffold.persistentFooterButtons and ' + 'Scaffold.bottomNavigationBar take up too much vertical space.\n' + 'Consider constraining the size of these widgets to allow room for the SnackBar to be visible.'; testWidgets('Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.floatingActionButton', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 @@ -1891,12 +2180,14 @@ void main() { // Run with the Snackbar fully off screen. await boilerplate(fabHeight: spaceAboveSnackBar + mediumFabHeight * 2); await openFloatingSnackBar(tester); - expectSnackBarNotVisibleError(tester); + AssertionError exception = tester.takeException() as AssertionError; + expect(exception.message, offScreenMessage); // Run with the Snackbar partially off screen. await boilerplate(fabHeight: spaceAboveSnackBar + mediumFabHeight + 10); await openFloatingSnackBar(tester); - expectSnackBarNotVisibleError(tester); + exception = tester.takeException() as AssertionError; + expect(exception.message, offScreenMessage); // Run with the Snackbar fully visible right on the top of the screen. await boilerplate(fabHeight: spaceAboveSnackBar + mediumFabHeight); @@ -1904,7 +2195,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { + testWidgets('Material2 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 await tester.pumpWidget( MaterialApp( @@ -1917,10 +2208,36 @@ void main() { await openFloatingSnackBar(tester); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - expectSnackBarNotVisibleError(tester); + + final AssertionError exception = tester.takeException() as AssertionError; + expect(exception.message, offScreenMessage); + }); + + testWidgets('Material3 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/84263 + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + persistentFooterButtons: [SizedBox(height: 1000)], + ), + ), + ); + + final FlutterExceptionHandler? handler = FlutterError.onError; + final List errorMessages = []; + FlutterError.onError = (FlutterErrorDetails details) { + errorMessages.add(details.exceptionAsString()); + }; + addTearDown(() => FlutterError.onError = handler); + + await openFloatingSnackBar(tester); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + expect(errorMessages.contains(offScreenMessage), isTrue); }); - testWidgets('Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { + testWidgets('Material2 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 await tester.pumpWidget( MaterialApp( @@ -1933,7 +2250,32 @@ void main() { await openFloatingSnackBar(tester); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - expectSnackBarNotVisibleError(tester); + final AssertionError exception = tester.takeException() as AssertionError; + expect(exception.message, offScreenMessage); + }); + + testWidgets('Material3 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/84263 + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomNavigationBar: SizedBox(height: 1000), + ), + ), + ); + + final FlutterExceptionHandler? handler = FlutterError.onError; + final List errorMessages = []; + FlutterError.onError = (FlutterErrorDetails details) { + errorMessages.add(details.exceptionAsString()); + }; + addTearDown(() => FlutterError.onError = handler); + + await openFloatingSnackBar(tester); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + expect(errorMessages.contains(offScreenMessage), isTrue); }); testWidgets( @@ -2155,7 +2497,7 @@ void main() { expect(find.text(snackBarText), findsOneWidget); }); - testWidgets('SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { + testWidgets('Material2 - SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2178,7 +2520,33 @@ void main() { )); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - await expectLater(find.byType(MaterialApp), matchesGoldenFile('snack_bar.goldenTest.workWithBottomSheet.png')); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.workWithBottomSheet.png')); + }); + + testWidgets('Material3 - SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomSheet: SizedBox( + width: 200, + height: 50, + child: ColoredBox( + color: Colors.pink, + ), + ), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state(find.byType(ScaffoldMessenger)); + scaffoldMessengerState.showSnackBar(SnackBar( + content: const Text('I love Flutter!'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + behavior: SnackBarBehavior.floating, + )); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.workWithBottomSheet.png')); }); testWidgets('ScaffoldMessenger does not duplicate a SnackBar when presenting a MaterialBanner.', (WidgetTester tester) async { @@ -2238,7 +2606,7 @@ void main() { expect(find.text(materialBannerText), findsOneWidget); }); - testWidgets('ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { + testWidgets('Material2 - ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -2265,12 +2633,48 @@ void main() { // overlapping the FAB. await expectLater( find.byType(MaterialApp), - matchesGoldenFile('snack_bar.scaffold.nested.png'), + matchesGoldenFile('m2_snack_bar.scaffold.nested.png'), ); final Offset snackBarTopRight = tester.getTopRight(find.byType(SnackBar)); expect(snackBarTopRight.dy, 465.0); }); + testWidgets('Material3 - ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: const Scaffold(), + floatingActionButton: FloatingActionButton(onPressed: () {}), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state( + find.byType(ScaffoldMessenger), + ); + scaffoldMessengerState.showSnackBar(SnackBar( + content: const Text('ScaffoldMessenger'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + behavior: SnackBarBehavior.floating, + )); + await tester.pumpAndSettle(); + + expect(find.byType(SnackBar), findsOneWidget); + // The FloatingActionButton helps us identify which Scaffold has the + // SnackBar here. Since the outer Scaffold contains a FAB, the SnackBar + // should be above it. If the inner Scaffold had the SnackBar, it would be + // overlapping the FAB. + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.scaffold.nested.png')); + final Offset snackBarTopRight = tester.getTopRight(find.byType(SnackBar)); + + // TODO(bleroux): https://github.com/flutter/flutter/issues/99933 + // A bug in the HTML renderer and/or Chrome 96+ causes a + // discrepancy in the paragraph height. + const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); + expect(snackBarTopRight.dy, hasIssue99933 ? 464.0 : 465.0); + }); + + testWidgets('ScaffoldMessengerState clearSnackBars works as expected', (WidgetTester tester) async { final List snackBars = ['Hello Snackbar', 'Hi Snackbar', 'Bye Snackbar']; int snackBarCounter = 0; @@ -2438,8 +2842,7 @@ void main() { }); } - - testWidgets('Snackbar by default clips BackdropFilter', (WidgetTester tester) async { + testWidgets('Material2 - Snackbar by default clips BackdropFilter', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/98205 await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -2469,7 +2872,40 @@ void main() { await tester.tap(find.text('I am a snack bar.')); await tester.pump(); // start animation await tester.pump(const Duration(milliseconds: 750)); - await expectLater(find.byType(MaterialApp), matchesGoldenFile('snack_bar.goldenTest.backdropFilter.png')); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.backdropFilter.png')); + }); + + testWidgets('Material3 - Snackbar by default clips BackdropFilter', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/98205 + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: const Scaffold(), + floatingActionButton: FloatingActionButton(onPressed: () {}), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state( + find.byType(ScaffoldMessenger), + ); + scaffoldMessengerState.showSnackBar(SnackBar( + backgroundColor: Colors.transparent, + content: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 20.0, + sigmaY: 20.0, + ), + child: const Text('I am a snack bar.'), + ), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + behavior: SnackBarBehavior.fixed, + )); + await tester.pumpAndSettle(); + await tester.tap(find.text('I am a snack bar.')); + await tester.pump(); // start animation + await tester.pump(const Duration(milliseconds: 750)); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.backdropFilter.png')); }); testWidgets('Floating snackbar can display optional icon', (WidgetTester tester) async { @@ -2504,7 +2940,7 @@ void main() { 'snack_bar.goldenTest.floatingWithActionWithIcon.png')); }); - testWidgets('Fixed width snackbar can display optional icon', (WidgetTester tester) async { + testWidgets('Material2 - Fixed width snackbar can display optional icon', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2528,10 +2964,37 @@ void main() { )); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - await expectLater(find.byType(MaterialApp), matchesGoldenFile('snack_bar.goldenTest.fixedWithActionWithIcon.png')); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.fixedWithActionWithIcon.png')); + }); + + testWidgets('Material3 - Fixed width snackbar can display optional icon', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomSheet: SizedBox( + width: 200, + height: 50, + child: ColoredBox( + color: Colors.pink, + ), + ), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state(find.byType(ScaffoldMessenger)); + scaffoldMessengerState.showSnackBar(SnackBar( + content: const Text('Go get a snack'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + showCloseIcon: true, + behavior: SnackBarBehavior.fixed, + )); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.fixedWithActionWithIcon.png')); }); - testWidgets('Fixed snackbar can display optional icon without action', (WidgetTester tester) async { + testWidgets('Material2 - Fixed snackbar can display optional icon without action', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2556,11 +3019,38 @@ void main() { ); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - await expectLater(find.byType(MaterialApp), matchesGoldenFile('snack_bar.goldenTest.fixedWithIcon.png')); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.fixedWithIcon.png')); }); - testWidgets( - 'Floating width snackbar can display optional icon without action', (WidgetTester tester) async { + testWidgets('Material3 - Fixed snackbar can display optional icon without action', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomSheet: SizedBox( + width: 200, + height: 50, + child: ColoredBox( + color: Colors.pink, + ), + ), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state(find.byType(ScaffoldMessenger)); + scaffoldMessengerState.showSnackBar( + const SnackBar( + content: Text('I wonder if there are snacks nearby?'), + duration: Duration(seconds: 2), + behavior: SnackBarBehavior.fixed, + showCloseIcon: true, + ), + ); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.fixedWithIcon.png')); + }); + + testWidgets('Material2 - Floating width snackbar can display optional icon without action', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2583,11 +3073,36 @@ void main() { )); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - await expectLater(find.byType(MaterialApp), - matchesGoldenFile('snack_bar.goldenTest.floatingWithIcon.png')); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.floatingWithIcon.png')); + }); + + testWidgets('Material3 - Floating width snackbar can display optional icon without action', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomSheet: SizedBox( + width: 200, + height: 50, + child: ColoredBox( + color: Colors.pink, + ), + ), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state(find.byType(ScaffoldMessenger)); + scaffoldMessengerState.showSnackBar(const SnackBar( + content: Text('Must go get a snack!'), + duration: Duration(seconds: 2), + showCloseIcon: true, + behavior: SnackBarBehavior.floating, + )); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.floatingWithIcon.png')); }); - testWidgets('Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { + testWidgets('Material2 - Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2611,11 +3126,37 @@ void main() { )); await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - await expectLater(find.byType(MaterialApp), - matchesGoldenFile('snack_bar.goldenTest.multiLineWithIcon.png')); + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.multiLineWithIcon.png')); + }); + + testWidgets('Material3 - Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomSheet: SizedBox( + width: 200, + height: 50, + child: ColoredBox( + color: Colors.pink, + ), + ), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state(find.byType(ScaffoldMessenger)); + scaffoldMessengerState.showSnackBar(const SnackBar( + content: Text( + 'This is a really long snackbar message. So long, it spans across more than one line!'), + duration: Duration(seconds: 2), + showCloseIcon: true, + behavior: SnackBarBehavior.floating, + )); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.multiLineWithIcon.png')); }); - testWidgets('Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { + testWidgets('Material2 - Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2639,8 +3180,40 @@ void main() { )); await tester.pumpAndSettle(); // Have the SnackBar fully animate in. - await expectLater(find.byType(MaterialApp), - matchesGoldenFile('snack_bar.goldenTest.multiLineWithIconWithZeroActionOverflowThreshold.png')); + await expectLater( + find.byType(MaterialApp), + matchesGoldenFile('m2_snack_bar.goldenTest.multiLineWithIconWithZeroActionOverflowThreshold.png'), + ); + }); + + testWidgets('Material3 - Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold( + bottomSheet: SizedBox( + width: 200, + height: 50, + child: ColoredBox( + color: Colors.pink, + ), + ), + ), + )); + + final ScaffoldMessengerState scaffoldMessengerState = tester.state(find.byType(ScaffoldMessenger)); + scaffoldMessengerState.showSnackBar(const SnackBar( + content: Text('This is a really long snackbar message. So long, it spans across more than one line!'), + duration: Duration(seconds: 2), + showCloseIcon: true, + behavior: SnackBarBehavior.floating, + actionOverflowThreshold: 1, + )); + await tester.pumpAndSettle(); // Have the SnackBar fully animate in. + + await expectLater( + find.byType(MaterialApp), + matchesGoldenFile('m3_snack_bar.goldenTest.multiLineWithIconWithZeroActionOverflowThreshold.png'), + ); }); testWidgets( From 0084347e7886955ec0c0eaacc4dca800e91d63fd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 18:31:05 -0400 Subject: [PATCH 0240/1547] Roll Flutter Engine from 71bbecee3010 to adf6142f6738 (2 revisions) (#130831) https://github.com/flutter/engine/compare/71bbecee3010...adf6142f6738 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 0adae44dd9cd to 9a0f6d82a6f5 (1 revision) (flutter/engine#43780) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 4e518e65fea0 to 0adae44dd9cd (6 revisions) (flutter/engine#43779) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index db77b077abb66..651e6185cfe35 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -71bbecee301037eec63d898fcf9f6b136e4819e7 +adf6142f6738fed19b7fd7163fec14ca312fc45e From 2d753a621ede0806ae8ee79b2ba20ef6d0fb08f7 Mon Sep 17 00:00:00 2001 From: fzyzcjy <5236035+fzyzcjy@users.noreply.github.com> Date: Wed, 19 Jul 2023 07:01:13 +0800 Subject: [PATCH 0241/1547] Fix super tiny space formatting (hope we have auto formatter in the future) (#127479) Just fix a space... I do hope we can have the auto formatter enabled in the future! --- packages/flutter/lib/src/material/text_field.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 9b71adbdc9c6c..aa8f715bf905b 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -805,7 +805,7 @@ class TextField extends StatefulWidget { decoration: TextDecoration.underline, decorationColor: Colors.red, decorationStyle: TextDecorationStyle.wavy, - ); + ); /// Default builder for [TextField]'s spell check suggestions toolbar. /// From d21109220b6fc944b3553dc40eb222dd3b55acd3 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 18 Jul 2023 16:02:56 -0700 Subject: [PATCH 0242/1547] Catch errors in loadStructuredData (#130748) Fixes https://github.com/flutter/flutter/issues/42390 --- .../src/foundation/synchronous_future.dart | 2 + .../lib/src/services/asset_bundle.dart | 118 +++++++++--------- .../test/services/asset_bundle_test.dart | 20 +++ 3 files changed, 78 insertions(+), 62 deletions(-) diff --git a/packages/flutter/lib/src/foundation/synchronous_future.dart b/packages/flutter/lib/src/foundation/synchronous_future.dart index ccdd1073dbdee..2b08456c69597 100644 --- a/packages/flutter/lib/src/foundation/synchronous_future.dart +++ b/packages/flutter/lib/src/foundation/synchronous_future.dart @@ -14,6 +14,8 @@ import 'dart:async'; /// rare occasions you want the ability to switch to an asynchronous model. **In /// general use of this class should be avoided as it is very difficult to debug /// such bimodal behavior.** +/// +/// A [SynchronousFuture] will never complete with an error. class SynchronousFuture implements Future { /// Creates a synchronous future. /// diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart index 5a752930ad69e..7ade7f8569852 100644 --- a/packages/flutter/lib/src/services/asset_bundle.dart +++ b/packages/flutter/lib/src/services/asset_bundle.dart @@ -105,18 +105,21 @@ abstract class AssetBundle { /// Retrieve a string from the asset bundle, parse it with the given function, /// and return that function's result. /// - /// Implementations may cache the result, so a particular key should only be - /// used with one parser for the lifetime of the asset bundle. - Future loadStructuredData(String key, Future Function(String value) parser); + /// The result is not cached by the default implementation; the parser is run + /// each time the resource is fetched. However, some subclasses may implement + /// caching (notably, subclasses of [CachingAssetBundle]). + Future loadStructuredData(String key, Future Function(String value) parser) async { + return parser(await loadString(key)); + } /// Retrieve [ByteData] from the asset bundle, parse it with the given function, /// and return that function's result. /// - /// Implementations may cache the result, so a particular key should only be - /// used with one parser for the lifetime of the asset bundle. + /// The result is not cached by the default implementation; the parser is run + /// each time the resource is fetched. However, some subclasses may implement + /// caching (notably, subclasses of [CachingAssetBundle]). Future loadStructuredBinaryData(String key, FutureOr Function(ByteData data) parser) async { - final ByteData data = await load(key); - return parser(data); + return parser(await load(key)); } /// If this is a caching asset bundle, and the given key describes a cached @@ -161,26 +164,6 @@ class NetworkAssetBundle extends AssetBundle { return bytes.buffer.asByteData(); } - /// Retrieve a string from the asset bundle, parse it with the given function, - /// and return the function's result. - /// - /// The result is not cached. The parser is run each time the resource is - /// fetched. - @override - Future loadStructuredData(String key, Future Function(String value) parser) async { - return parser(await loadString(key)); - } - - /// Retrieve [ByteData] from the asset bundle, parse it with the given function, - /// and return the function's result. - /// - /// The result is not cached. The parser is run each time the resource is - /// fetched. - @override - Future loadStructuredBinaryData(String key, FutureOr Function(ByteData data) parser) async { - return parser(await load(key)); - } - // TODO(ianh): Once the underlying network logic learns about caching, we // should implement evict(). @@ -217,30 +200,40 @@ abstract class CachingAssetBundle extends AssetBundle { /// unless you also fetch it with [loadString]). For any given `key`, the /// `parser` is only run the first time. /// - /// Once the value has been parsed, the future returned by this function for - /// subsequent calls will be a [SynchronousFuture], which resolves its - /// callback synchronously. + /// Once the value has been successfully parsed, the future returned by this + /// function for subsequent calls will be a [SynchronousFuture], which + /// resolves its callback synchronously. + /// + /// Failures are not cached, and are returned as [Future]s with errors. @override Future loadStructuredData(String key, Future Function(String value) parser) { if (_structuredDataCache.containsKey(key)) { return _structuredDataCache[key]! as Future; } - Completer? completer; - Future? result; + // loadString can return a SynchronousFuture in certain cases, like in the + // flutter_test framework. So, we need to support both async and sync flows. + Completer? completer; // For async flow. + Future? synchronousResult; // For sync flow. loadString(key, cache: false).then(parser).then((T value) { - result = SynchronousFuture(value); - _structuredDataCache[key] = result!; + synchronousResult = SynchronousFuture(value); + _structuredDataCache[key] = synchronousResult!; if (completer != null) { // We already returned from the loadStructuredData function, which means // we are in the asynchronous mode. Pass the value to the completer. The // completer's future is what we returned. completer.complete(value); } + }, onError: (Object error, StackTrace stack) { + assert(completer != null, 'unexpected synchronous failure'); + // Either loading or parsing failed. We must report the error back to the + // caller and anyone waiting on this call. We clear the cache for this + // key, however, because we want future attempts to try again. + _structuredDataCache.remove(key); + completer!.completeError(error, stack); }); - if (result != null) { - // The code above ran synchronously, and came up with an answer. - // Return the SynchronousFuture that we created above. - return result!; + if (synchronousResult != null) { + // The above code ran synchronously. We can synchronously return the result. + return synchronousResult!; } // The code above hasn't yet run its "then" handler yet. Let's prepare a // completer for it to use when it does run. @@ -255,40 +248,41 @@ abstract class CachingAssetBundle extends AssetBundle { /// The result of parsing the bytedata is cached (the bytedata itself is not). /// For any given `key`, the `parser` is only run the first time. /// - /// Once the value has been parsed, the future returned by this function for - /// subsequent calls will be a [SynchronousFuture], which resolves its - /// callback synchronously. + /// Once the value has been successfully parsed, the future returned by this + /// function for subsequent calls will be a [SynchronousFuture], which + /// resolves its callback synchronously. + /// + /// Failures are not cached, and are returned as [Future]s with errors. @override Future loadStructuredBinaryData(String key, FutureOr Function(ByteData data) parser) { if (_structuredBinaryDataCache.containsKey(key)) { return _structuredBinaryDataCache[key]! as Future; } - // load can return a SynchronousFuture in certain cases, like in the // flutter_test framework. So, we need to support both async and sync flows. Completer? completer; // For async flow. - SynchronousFuture? result; // For sync flow. - - load(key) - .then(parser) - .then((T value) { - result = SynchronousFuture(value); - _structuredBinaryDataCache[key] = result!; - if (completer != null) { - // The load and parse operation ran asynchronously. We already returned - // from the loadStructuredBinaryData function and therefore the caller - // was given the future of the completer. - completer.complete(value); - } - }, onError: (Object error, StackTrace stack) { - completer!.completeError(error, stack); - }); - - if (result != null) { + Future? synchronousResult; // For sync flow. + load(key).then(parser).then((T value) { + synchronousResult = SynchronousFuture(value); + _structuredBinaryDataCache[key] = synchronousResult!; + if (completer != null) { + // The load and parse operation ran asynchronously. We already returned + // from the loadStructuredBinaryData function and therefore the caller + // was given the future of the completer. + completer.complete(value); + } + }, onError: (Object error, StackTrace stack) { + assert(completer != null, 'unexpected synchronous failure'); + // Either loading or parsing failed. We must report the error back to the + // caller and anyone waiting on this call. We clear the cache for this + // key, however, because we want future attempts to try again. + _structuredBinaryDataCache.remove(key); + completer!.completeError(error, stack); + }); + if (synchronousResult != null) { // The above code ran synchronously. We can synchronously return the result. - return result!; + return synchronousResult!; } - // Since the above code is being run asynchronously and thus hasn't run its // `then` handler yet, we'll return a completer that will be completed // when the handler does run. diff --git a/packages/flutter/test/services/asset_bundle_test.dart b/packages/flutter/test/services/asset_bundle_test.dart index efa2f7d7cc006..5f7b7c738c8d6 100644 --- a/packages/flutter/test/services/asset_bundle_test.dart +++ b/packages/flutter/test/services/asset_bundle_test.dart @@ -135,6 +135,26 @@ void main() { expect(data, isA>()); expect(await data, 1); }); + + testWidgets('loadStructuredData handles exceptions correctly', (WidgetTester tester) async { + final TestAssetBundle bundle = TestAssetBundle(); + try { + await bundle.loadStructuredData('AssetManifest.json', (String value) => Future.error('what do they say?')); + fail('expected exception did not happen'); + } catch (e) { + expect(e.toString(), contains('what do they say?')); + } + }); + + testWidgets('loadStructuredBinaryData handles exceptions correctly', (WidgetTester tester) async { + final TestAssetBundle bundle = TestAssetBundle(); + try { + await bundle.loadStructuredBinaryData('AssetManifest.bin', (ByteData value) => Future.error('buy more crystals')); + fail('expected exception did not happen'); + } catch (e) { + expect(e.toString(), contains('buy more crystals')); + } + }); }); test('AssetImage.obtainKey succeeds with ImageConfiguration.empty', () async { From a4af12f477bc19ab56f312b722d6fa7259cc1038 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Wed, 19 Jul 2023 01:29:31 +0200 Subject: [PATCH 0243/1547] Update app_builder_test.dart for M3 (#130794) This PR updates unit tests from app_builder_test.dart for M3 migration. More info in https://github.com/flutter/flutter/issues/127064 In this particular case, I choose to make the tests Material-agnostic by removing the color theming which was not meaningful to what is tested here. --- packages/flutter/test/material/app_builder_test.dart | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/flutter/test/material/app_builder_test.dart b/packages/flutter/test/material/app_builder_test.dart index 851a88edcf82d..cc28307f40689 100644 --- a/packages/flutter/test/material/app_builder_test.dart +++ b/packages/flutter/test/material/app_builder_test.dart @@ -9,14 +9,9 @@ void main() { testWidgets("builder doesn't get called if app doesn't change", (WidgetTester tester) async { final List log = []; final Widget app = MaterialApp( - theme: ThemeData( - useMaterial3: false, - primarySwatch: Colors.green, - ), home: const Placeholder(), builder: (BuildContext context, Widget? child) { log.add('build'); - expect(Theme.of(context).primaryColor, Colors.green); expect(Directionality.of(context), TextDirection.ltr); expect(child, isA()); return const Placeholder(); @@ -42,14 +37,9 @@ void main() { final List log = []; await tester.pumpWidget( MaterialApp( - theme: ThemeData( - useMaterial3: false, - primarySwatch: Colors.yellow, - ), home: Builder( builder: (BuildContext context) { log.add('build'); - expect(Theme.of(context).primaryColor, Colors.yellow); expect(Directionality.of(context), TextDirection.rtl); return const Placeholder(); }, From 504c68ae818b0b8969757c25477026c71f3a9ebe Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 21:16:26 -0400 Subject: [PATCH 0244/1547] Roll Flutter Engine from adf6142f6738 to b3bfc744bb61 (7 revisions) (#130843) https://github.com/flutter/engine/compare/adf6142f6738...b3bfc744bb61 2023-07-18 zanderso@users.noreply.github.com Increase engine v2 orchestrator timeouts (flutter/engine#43788) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from dcc56df202cc to 280fb8391187 (1 revision) (flutter/engine#43793) 2023-07-18 zanderso@users.noreply.github.com Remove obsolete legacy engine builds from staging (flutter/engine#43790) 2023-07-18 skia-flutter-autoroll@skia.org Roll ANGLE from 52fe3116ead9 to 6eea5ff4db82 (1 revision) (flutter/engine#43789) 2023-07-18 bdero@google.com [Impeller] Fix GL_NUM_EXTENSIONS check for desktop GL (flutter/engine#43785) 2023-07-18 skia-flutter-autoroll@skia.org Roll Skia from 9a0f6d82a6f5 to dcc56df202cc (1 revision) (flutter/engine#43784) 2023-07-18 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ixKM7wyMrqmPDaQ11... to ZABO4Om1vToxhI394... (flutter/engine#43782) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ixKM7wyMrqmP to ZABO4Om1vTox If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 651e6185cfe35..de1bd91d525e2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -adf6142f6738fed19b7fd7163fec14ca312fc45e +b3bfc744bb61d5c7671b11d96abe60a43241d60e diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 78a061425fe44..466183a7f8631 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ixKM7wyMrqmPDaQ1116iI_iWW_tr97Vb1gGiPG1BmLAC +ZABO4Om1vToxhI394y3P1X0fu7gcLz2d65YNEeNTBZUC From 33d174d797efd85839730d9173eac3884f5768d5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 18 Jul 2023 22:36:21 -0400 Subject: [PATCH 0245/1547] Roll Flutter Engine from b3bfc744bb61 to 39d60be72ffb (1 revision) (#130847) https://github.com/flutter/engine/compare/b3bfc744bb61...39d60be72ffb 2023-07-19 skia-flutter-autoroll@skia.org Roll Dart SDK from ec95774043ec to c184cac2d22f (1 revision) (flutter/engine#43794) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index de1bd91d525e2..1f8c176cc6e4e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b3bfc744bb61d5c7671b11d96abe60a43241d60e +39d60be72ffbeffb7765fe764219b1e64ac98cef From a417a6993bd73a252e43408ed2bf44c4442ee807 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 02:36:01 -0400 Subject: [PATCH 0246/1547] Roll Flutter Engine from 39d60be72ffb to 29de67c7d009 (4 revisions) (#130855) https://github.com/flutter/engine/compare/39d60be72ffb...29de67c7d009 2023-07-19 skia-flutter-autoroll@skia.org Roll Dart SDK from c184cac2d22f to 9f5e86b4c108 (1 revision) (flutter/engine#43798) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from d1d2b623799e to caf0d191bd07 (1 revision) (flutter/engine#43797) 2023-07-19 skia-flutter-autoroll@skia.org Roll ANGLE from 6eea5ff4db82 to b32d661389a6 (1 revision) (flutter/engine#43796) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 280fb8391187 to d1d2b623799e (1 revision) (flutter/engine#43795) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1f8c176cc6e4e..7220ea2528e64 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -39d60be72ffbeffb7765fe764219b1e64ac98cef +29de67c7d009cf1733f6b7f2df996ec763d66723 From 3213588c03361df63a381b214075eb59a9d7ee65 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 03:20:21 -0400 Subject: [PATCH 0247/1547] Roll Flutter Engine from 29de67c7d009 to 0293a7cb7887 (1 revision) (#130858) https://github.com/flutter/engine/compare/29de67c7d009...0293a7cb7887 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from caf0d191bd07 to 9062ca6a691c (1 revision) (flutter/engine#43799) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7220ea2528e64..c1e2a82702145 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -29de67c7d009cf1733f6b7f2df996ec763d66723 +0293a7cb7887f97b2e6ce76eda0fcfeb27e5a6d9 From e4e9dde4edb7aa9f12ae92b389443f3b40d49743 Mon Sep 17 00:00:00 2001 From: Tomasz Gucio <72562119+tgucio@users.noreply.github.com> Date: Wed, 19 Jul 2023 11:48:01 +0200 Subject: [PATCH 0248/1547] Move TapAndDragGestureRecognizer code under gestures (#119508) --- packages/flutter/lib/gestures.dart | 1 + .../tap_and_drag.dart} | 87 +++++++------------ .../lib/src/widgets/text_selection.dart | 75 +++++++++++----- packages/flutter/lib/widgets.dart | 1 - .../tap_and_drag_test.dart} | 1 - .../test/widgets/text_selection_test.dart | 2 +- 6 files changed, 88 insertions(+), 79 deletions(-) rename packages/flutter/lib/src/{widgets/tap_and_drag_gestures.dart => gestures/tap_and_drag.dart} (94%) rename packages/flutter/test/{widgets/tap_and_drag_gestures_test.dart => gestures/tap_and_drag_test.dart} (99%) diff --git a/packages/flutter/lib/gestures.dart b/packages/flutter/lib/gestures.dart index be2f30debde65..8a126894494c6 100644 --- a/packages/flutter/lib/gestures.dart +++ b/packages/flutter/lib/gestures.dart @@ -30,5 +30,6 @@ export 'src/gestures/recognizer.dart'; export 'src/gestures/resampler.dart'; export 'src/gestures/scale.dart'; export 'src/gestures/tap.dart'; +export 'src/gestures/tap_and_drag.dart'; export 'src/gestures/team.dart'; export 'src/gestures/velocity_tracker.dart'; diff --git a/packages/flutter/lib/src/widgets/tap_and_drag_gestures.dart b/packages/flutter/lib/src/gestures/tap_and_drag.dart similarity index 94% rename from packages/flutter/lib/src/widgets/tap_and_drag_gestures.dart rename to packages/flutter/lib/src/gestures/tap_and_drag.dart index 51a8435b2f759..907173c5d79c2 100644 --- a/packages/flutter/lib/src/widgets/tap_and_drag_gestures.dart +++ b/packages/flutter/lib/src/gestures/tap_and_drag.dart @@ -5,11 +5,13 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/services.dart' show HardwareKeyboard, LogicalKeyboardKey; -import 'framework.dart'; -import 'gesture_detector.dart'; +import 'constants.dart'; +import 'events.dart'; +import 'monodrag.dart'; +import 'recognizer.dart'; +import 'scale.dart'; +import 'tap.dart'; // Examples can assume: // void setState(VoidCallback fn) { } @@ -75,14 +77,13 @@ typedef GestureTapDragDownCallback = void Function(TapDragDownDetails details); class TapDragDownDetails with Diagnosticable { /// Creates details for a [GestureTapDragDownCallback]. /// - /// The [globalPosition], [localPosition], [consecutiveTapCount], and - /// [keysPressedOnDown] arguments must be provided and must not be null. + /// The [globalPosition], [localPosition], and [consecutiveTapCount] + /// arguments must be provided and must not be null. TapDragDownDetails({ required this.globalPosition, required this.localPosition, this.kind, required this.consecutiveTapCount, - required this.keysPressedOnDown, }); /// The global position at which the pointer contacted the screen. @@ -98,9 +99,6 @@ class TapDragDownDetails with Diagnosticable { /// the number in the series this tap is. final int consecutiveTapCount; - /// The keys that were pressed when the most recent [PointerDownEvent] occurred. - final Set keysPressedOnDown; - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -108,7 +106,6 @@ class TapDragDownDetails with Diagnosticable { properties.add(DiagnosticsProperty('localPosition', localPosition)); properties.add(DiagnosticsProperty('kind', kind)); properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); - properties.add(DiagnosticsProperty>('keysPressedOnDown', keysPressedOnDown)); } } @@ -134,14 +131,13 @@ typedef GestureTapDragUpCallback = void Function(TapDragUpDetails details); class TapDragUpDetails with Diagnosticable { /// Creates details for a [GestureTapDragUpCallback]. /// - /// The [kind], [globalPosition], [localPosition], [consecutiveTapCount], and - /// [keysPressedOnDown] arguments must be provided and must not be null. + /// The [kind], [globalPosition], [localPosition], and [consecutiveTapCount] + /// arguments must be provided and must not be null. TapDragUpDetails({ required this.kind, required this.globalPosition, required this.localPosition, required this.consecutiveTapCount, - required this.keysPressedOnDown, }); /// The global position at which the pointer contacted the screen. @@ -157,9 +153,6 @@ class TapDragUpDetails with Diagnosticable { /// the number in the series this tap is. final int consecutiveTapCount; - /// The keys that were pressed when the most recent [PointerDownEvent] occurred. - final Set keysPressedOnDown; - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -167,7 +160,6 @@ class TapDragUpDetails with Diagnosticable { properties.add(DiagnosticsProperty('localPosition', localPosition)); properties.add(DiagnosticsProperty('kind', kind)); properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); - properties.add(DiagnosticsProperty>('keysPressedOnDown', keysPressedOnDown)); } } @@ -193,15 +185,14 @@ typedef GestureTapDragStartCallback = void Function(TapDragStartDetails details) class TapDragStartDetails with Diagnosticable { /// Creates details for a [GestureTapDragStartCallback]. /// - /// The [globalPosition], [localPosition], [consecutiveTapCount], and - /// [keysPressedOnDown] arguments must be provided and must not be null. + /// The [globalPosition], [localPosition], and [consecutiveTapCount] + /// arguments must be provided and must not be null. TapDragStartDetails({ this.sourceTimeStamp, required this.globalPosition, required this.localPosition, this.kind, required this.consecutiveTapCount, - required this.keysPressedOnDown, }); /// Recorded timestamp of the source pointer event that triggered the drag @@ -229,9 +220,6 @@ class TapDragStartDetails with Diagnosticable { /// the number in the series this tap is. final int consecutiveTapCount; - /// The keys that were pressed when the most recent [PointerDownEvent] occurred. - final Set keysPressedOnDown; - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -240,7 +228,6 @@ class TapDragStartDetails with Diagnosticable { properties.add(DiagnosticsProperty('localPosition', localPosition)); properties.add(DiagnosticsProperty('kind', kind)); properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); - properties.add(DiagnosticsProperty>('keysPressedOnDown', keysPressedOnDown)); } } @@ -272,8 +259,7 @@ class TapDragUpdateDetails with Diagnosticable { /// coordinates of [delta] and the other coordinate must be zero. /// /// The [globalPosition], [localPosition], [offsetFromOrigin], [localOffsetFromOrigin], - /// [consecutiveTapCount], and [keysPressedOnDown] arguments must be provided and must - /// not be null. + /// and [consecutiveTapCount] arguments must be provided and must not be null. TapDragUpdateDetails({ this.sourceTimeStamp, this.delta = Offset.zero, @@ -284,7 +270,6 @@ class TapDragUpdateDetails with Diagnosticable { required this.offsetFromOrigin, required this.localOffsetFromOrigin, required this.consecutiveTapCount, - required this.keysPressedOnDown, }) : assert( primaryDelta == null || (primaryDelta == delta.dx && delta.dy == 0.0) @@ -357,9 +342,6 @@ class TapDragUpdateDetails with Diagnosticable { /// the number in the series this tap is. final int consecutiveTapCount; - /// The keys that were pressed when the most recent [PointerDownEvent] occurred. - final Set keysPressedOnDown; - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -372,7 +354,6 @@ class TapDragUpdateDetails with Diagnosticable { properties.add(DiagnosticsProperty('offsetFromOrigin', offsetFromOrigin)); properties.add(DiagnosticsProperty('localOffsetFromOrigin', localOffsetFromOrigin)); properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); - properties.add(DiagnosticsProperty>('keysPressedOnDown', keysPressedOnDown)); } } @@ -400,13 +381,11 @@ class TapDragEndDetails with Diagnosticable { /// /// The [velocity] argument must not be null. /// - /// The [consecutiveTapCount], and [keysPressedOnDown] arguments must - /// be provided and must not be null. + /// The [consecutiveTapCount] argument must be provided and must not be null. TapDragEndDetails({ this.velocity = Velocity.zero, this.primaryVelocity, required this.consecutiveTapCount, - required this.keysPressedOnDown, }) : assert( primaryVelocity == null || primaryVelocity == velocity.pixelsPerSecond.dx @@ -434,16 +413,12 @@ class TapDragEndDetails with Diagnosticable { /// the number in the series this tap is. final int consecutiveTapCount; - /// The keys that were pressed when the most recent [PointerDownEvent] occurred. - final Set keysPressedOnDown; - @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('velocity', velocity)); properties.add(DiagnosticsProperty('primaryVelocity', primaryVelocity)); properties.add(DiagnosticsProperty('consecutiveTapCount', consecutiveTapCount)); - properties.add(DiagnosticsProperty>('keysPressedOnDown', keysPressedOnDown)); } } @@ -506,15 +481,6 @@ mixin _TapStatusTrackerMixin on OneSequenceGestureRecognizer { // this value will be set to `0`, and a new series will begin. int get consecutiveTapCount => _consecutiveTapCount; - // The set of [LogicalKeyboardKey]s pressed when the most recent [PointerDownEvent] - // was tracked in [addAllowedPointer]. - // - // This value defaults to an empty set. - // - // When the timer between two taps elapses, the recognizer loses the arena, the gesture is cancelled - // or the recognizer is disposed of then this value is reset. - Set get keysPressedOnDown => _keysPressedOnDown ?? {}; - // The upper limit for the [consecutiveTapCount]. When this limit is reached // all tap related state is reset and a new tap series is tracked. // @@ -525,7 +491,6 @@ mixin _TapStatusTrackerMixin on OneSequenceGestureRecognizer { PointerDownEvent? _down; PointerUpEvent? _up; int _consecutiveTapCount = 0; - Set? _keysPressedOnDown; OffsetPair? _originPosition; int? _previousButtons; @@ -534,6 +499,21 @@ mixin _TapStatusTrackerMixin on OneSequenceGestureRecognizer { Timer? _consecutiveTapTimer; Offset? _lastTapOffset; + /// {@template flutter.gestures.selectionrecognizers.BaseTapAndDragGestureRecognizer.onTapTrackStart} + /// Callback used to indicate that a tap tracking has started upon + /// a [PointerDownEvent]. + /// {@endtemplate} + VoidCallback? onTapTrackStart; + + /// {@template flutter.gestures.selectionrecognizers.BaseTapAndDragGestureRecognizer.onTapTrackReset} + /// Callback used to indicate that a tap tracking has been reset which + /// happens on the next [PointerDownEvent] after the timer between two taps + /// elapses, the recognizer loses the arena, the gesture is cancelled or + /// the recognizer is disposed of. + /// {@endtemplate} + + VoidCallback? onTapTrackReset; + // When tracking a tap, the [consecutiveTapCount] is incremented if the given tap // falls under the tolerance specifications and reset to 1 if not. @override @@ -595,10 +575,10 @@ mixin _TapStatusTrackerMixin on OneSequenceGestureRecognizer { void _trackTap(PointerDownEvent event) { _down = event; - _keysPressedOnDown = HardwareKeyboard.instance.logicalKeysPressed; _previousButtons = event.buttons; _lastTapOffset = event.position; _originPosition = OffsetPair(local: event.localPosition, global: event.position); + onTapTrackStart?.call(); } bool _hasSameButton(int buttons) { @@ -653,9 +633,9 @@ mixin _TapStatusTrackerMixin on OneSequenceGestureRecognizer { _originPosition = null; _lastTapOffset = null; _consecutiveTapCount = 0; - _keysPressedOnDown = null; _down = null; _up = null; + onTapTrackReset?.call(); } } @@ -1204,7 +1184,6 @@ sealed class BaseTapAndDragGestureRecognizer extends OneSequenceGestureRecognize localPosition: event.localPosition, kind: getKindForPointer(event.pointer), consecutiveTapCount: consecutiveTapCount, - keysPressedOnDown: keysPressedOnDown, ); if (onTapDown != null) { @@ -1224,7 +1203,6 @@ sealed class BaseTapAndDragGestureRecognizer extends OneSequenceGestureRecognize globalPosition: event.position, localPosition: event.localPosition, consecutiveTapCount: consecutiveTapCount, - keysPressedOnDown: keysPressedOnDown, ); if (onTapUp != null) { @@ -1245,7 +1223,6 @@ sealed class BaseTapAndDragGestureRecognizer extends OneSequenceGestureRecognize localPosition: _initialPosition.local, kind: getKindForPointer(event.pointer), consecutiveTapCount: consecutiveTapCount, - keysPressedOnDown: keysPressedOnDown, ); invokeCallback('onDragStart', () => onDragStart!(details)); @@ -1267,7 +1244,6 @@ sealed class BaseTapAndDragGestureRecognizer extends OneSequenceGestureRecognize offsetFromOrigin: globalPosition - _initialPosition.global, localOffsetFromOrigin: localPosition - _initialPosition.local, consecutiveTapCount: consecutiveTapCount, - keysPressedOnDown: keysPressedOnDown, ); if (dragUpdateThrottleFrequency != null) { @@ -1293,7 +1269,6 @@ sealed class BaseTapAndDragGestureRecognizer extends OneSequenceGestureRecognize TapDragEndDetails( primaryVelocity: 0.0, consecutiveTapCount: consecutiveTapCount, - keysPressedOnDown: keysPressedOnDown, ); if (onDragEnd != null) { diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index a447e6e0cb97c..8d45921727578 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -24,7 +24,6 @@ import 'gesture_detector.dart'; import 'magnifier.dart'; import 'overlay.dart'; import 'scrollable.dart'; -import 'tap_and_drag_gestures.dart'; import 'tap_region.dart'; import 'ticker_provider.dart'; import 'transitions.dart'; @@ -1993,11 +1992,6 @@ class TextSelectionGestureDetectorBuilder { && targetSelection.end >= textPosition.offset; } - /// Returns true if shift left or right is contained in the given set. - static bool _containsShift(Set keysPressed) { - return keysPressed.any({ LogicalKeyboardKey.shiftLeft, LogicalKeyboardKey.shiftRight }.contains); - } - // Expand the selection to the given global position. // // Either base or extent will be moved to the last tapped position, whichever @@ -2074,6 +2068,10 @@ class TextSelectionGestureDetectorBuilder { @protected RenderEditable get renderEditable => editableText.renderEditable; + /// Whether the Shift key was pressed when the most recent [PointerDownEvent] + /// was tracked by the [BaseTapAndDragGestureRecognizer]. + bool _isShiftPressed = false; + /// The viewport offset pixels of any [Scrollable] containing the /// [RenderEditable] at the last drag start. double _dragStartScrollOffset = 0.0; @@ -2113,6 +2111,30 @@ class TextSelectionGestureDetectorBuilder { // focused, the cursor moves to the long press position. bool _longPressStartedWithoutFocus = false; + /// Handler for [TextSelectionGestureDetector.onTapTrackStart]. + /// + /// See also: + /// + /// * [TextSelectionGestureDetector.onTapTrackStart], which triggers this + /// callback. + @protected + void onTapTrackStart() { + _isShiftPressed = HardwareKeyboard.instance.logicalKeysPressed + .intersection({LogicalKeyboardKey.shiftLeft, LogicalKeyboardKey.shiftRight}) + .isNotEmpty; + } + + /// Handler for [TextSelectionGestureDetector.onTapTrackReset]. + /// + /// See also: + /// + /// * [TextSelectionGestureDetector.onTapTrackReset], which triggers this + /// callback. + @protected + void onTapTrackReset() { + _isShiftPressed = false; + } + /// Handler for [TextSelectionGestureDetector.onTapDown]. /// /// By default, it forwards the tap to [RenderEditable.handleTapDown] and sets @@ -2145,11 +2167,9 @@ class TextSelectionGestureDetectorBuilder { || kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; - // Handle shift + click selection if needed. - final bool isShiftPressed = _containsShift(details.keysPressedOnDown); // It is impossible to extend the selection when the shift key is pressed, if the // renderEditable.selection is invalid. - final bool isShiftPressedValid = isShiftPressed && renderEditable.selection?.baseOffset != null; + final bool isShiftPressedValid = _isShiftPressed && renderEditable.selection?.baseOffset != null; switch (defaultTargetPlatform) { case TargetPlatform.android: case TargetPlatform.fuchsia: @@ -2246,11 +2266,9 @@ class TextSelectionGestureDetectorBuilder { @protected void onSingleTapUp(TapDragUpDetails details) { if (delegate.selectionEnabled) { - // Handle shift + click selection if needed. - final bool isShiftPressed = _containsShift(details.keysPressedOnDown); // It is impossible to extend the selection when the shift key is pressed, if the // renderEditable.selection is invalid. - final bool isShiftPressedValid = isShiftPressed && renderEditable.selection?.baseOffset != null; + final bool isShiftPressedValid = _isShiftPressed && renderEditable.selection?.baseOffset != null; switch (defaultTargetPlatform) { case TargetPlatform.linux: case TargetPlatform.macOS: @@ -2641,9 +2659,7 @@ class TextSelectionGestureDetectorBuilder { return; } - final bool isShiftPressed = _containsShift(details.keysPressedOnDown); - - if (isShiftPressed && renderEditable.selection != null && renderEditable.selection!.isValid) { + if (_isShiftPressed && renderEditable.selection != null && renderEditable.selection!.isValid) { switch (defaultTargetPlatform) { case TargetPlatform.iOS: case TargetPlatform.macOS: @@ -2730,9 +2746,7 @@ class TextSelectionGestureDetectorBuilder { return; } - final bool isShiftPressed = _containsShift(details.keysPressedOnDown); - - if (!isShiftPressed) { + if (!_isShiftPressed) { // Adjust the drag start offset for possible viewport offset changes. final Offset editableOffset = renderEditable.maxLines == 1 ? Offset(renderEditable.offset.pixels - _dragStartViewportOffset, 0.0) @@ -2931,14 +2945,13 @@ class TextSelectionGestureDetectorBuilder { /// callback. @protected void onDragSelectionEnd(TapDragEndDetails details) { - final bool isShiftPressed = _containsShift(details.keysPressedOnDown); _dragBeganOnPreviousSelection = null; if (_shouldShowSelectionToolbar && _TextSelectionGestureDetectorState._getEffectiveConsecutiveTapCount(details.consecutiveTapCount) == 2) { editableText.showToolbar(); } - if (isShiftPressed) { + if (_isShiftPressed) { _dragStartSelection = null; } @@ -2956,6 +2969,8 @@ class TextSelectionGestureDetectorBuilder { }) { return TextSelectionGestureDetector( key: key, + onTapTrackStart: onTapTrackStart, + onTapTrackReset: onTapTrackReset, onTapDown: onTapDown, onForcePressStart: delegate.forcePressEnabled ? onForcePressStart : null, onForcePressEnd: delegate.forcePressEnabled ? onForcePressEnd : null, @@ -2996,6 +3011,8 @@ class TextSelectionGestureDetector extends StatefulWidget { /// The [child] parameter must not be null. const TextSelectionGestureDetector({ super.key, + this.onTapTrackStart, + this.onTapTrackReset, this.onTapDown, this.onForcePressStart, this.onForcePressEnd, @@ -3015,6 +3032,12 @@ class TextSelectionGestureDetector extends StatefulWidget { required this.child, }); + /// {@macro flutter.gestures.selectionrecognizers.BaseTapAndDragGestureRecognizer.onTapTrackStart} + final VoidCallback? onTapTrackStart; + + /// {@macro flutter.gestures.selectionrecognizers.BaseTapAndDragGestureRecognizer.onTapTrackReset} + final VoidCallback? onTapTrackReset; + /// Called for every tap down including every tap down that's part of a /// double click or a long press, except touches that include enough movement /// to not qualify as taps (e.g. pans and flings). @@ -3125,6 +3148,14 @@ class _TextSelectionGestureDetectorState extends State Date: Wed, 19 Jul 2023 05:54:05 -0400 Subject: [PATCH 0249/1547] Roll Flutter Engine from 0293a7cb7887 to 09389b16d684 (5 revisions) (#130867) https://github.com/flutter/engine/compare/0293a7cb7887...09389b16d684 2023-07-19 skia-flutter-autoroll@skia.org Roll ANGLE from b32d661389a6 to 255dec886475 (1 revision) (flutter/engine#43804) 2023-07-19 jason-simmons@users.noreply.github.com Fix the rules for determining whether a blur image filter is valid (flutter/engine#43791) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 035b12a03918 to c03050eb2b65 (1 revision) (flutter/engine#43802) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 9062ca6a691c to 035b12a03918 (3 revisions) (flutter/engine#43801) 2023-07-19 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from SCshjyIlymHWD9W4D... to Iqf3gYJ8Vkq8k8l3O... (flutter/engine#43800) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from SCshjyIlymHW to Iqf3gYJ8Vkq8 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c1e2a82702145..95fa28ddd1dc6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0293a7cb7887f97b2e6ce76eda0fcfeb27e5a6d9 +09389b16d684badbc4365bb1c3ca8c389c98b112 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 92ddc24221eb5..cdea18ecdbff9 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -SCshjyIlymHWD9W4DLT9CHMS3_5QMCQDb-m-DLzJi78C +Iqf3gYJ8Vkq8k8l3OYAUUrwZJ8eEi2wVosGclDAPxtwC From d07e8aece184cac609aeda2b112420223c78d9b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 09:00:23 -0400 Subject: [PATCH 0250/1547] Roll Flutter Engine from 09389b16d684 to eb2285205f25 (3 revisions) (#130879) https://github.com/flutter/engine/compare/09389b16d684...eb2285205f25 2023-07-19 skia-flutter-autoroll@skia.org Roll ANGLE from 255dec886475 to 4dcaad2a894d (1 revision) (flutter/engine#43809) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from c03050eb2b65 to e9409b832799 (1 revision) (flutter/engine#43808) 2023-07-19 skia-flutter-autoroll@skia.org Roll Dart SDK from 9f5e86b4c108 to a013e7bf089e (1 revision) (flutter/engine#43805) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 95fa28ddd1dc6..2636a22fd011c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09389b16d684badbc4365bb1c3ca8c389c98b112 +eb2285205f255f1153a61696eacf8d9f068c404d From 305c36f3d2380b7bd69e1829b7f7d4dcdb157928 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 11:11:04 -0400 Subject: [PATCH 0251/1547] Roll Flutter Engine from eb2285205f25 to 076bd7b81d9c (2 revisions) (#130891) https://github.com/flutter/engine/compare/eb2285205f25...076bd7b81d9c 2023-07-19 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ZABO4Om1vToxhI394... to -SNz0augjLKFVsUWn... (flutter/engine#43810) 2023-07-19 kjlubick@users.noreply.github.com Update legacy call to SkImage::makeSubset (flutter/engine#43786) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ZABO4Om1vTox to -SNz0augjLKF If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2636a22fd011c..5005fbc4dc69c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -eb2285205f255f1153a61696eacf8d9f068c404d +076bd7b81d9c1aea5d9fda73a38cc8437d1aa09d diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 466183a7f8631..5f31d4afbfb3f 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ZABO4Om1vToxhI394y3P1X0fu7gcLz2d65YNEeNTBZUC +-SNz0augjLKFVsUWnMnuevifpykHjCqZd5_eL7gslrMC From 3b0b670d91cd7be06ccf369923ca34cd33d97a0e Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 19 Jul 2023 08:39:43 -0700 Subject: [PATCH 0252/1547] Mark Windows_android channels_integration_test_win flaky (#130893) For https://github.com/flutter/flutter/issues/130732 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index b04580a0f8620..3ebe720f1c12a 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4825,6 +4825,7 @@ targets: - name: Windows_android channels_integration_test_win recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/130732 presubmit: false timeout: 60 properties: From 566198890df6a65ccde65d832cfd0e6b5d76a16d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 11:43:16 -0400 Subject: [PATCH 0253/1547] Roll Packages from 3e8b8130cda3 to 209db219ad73 (8 revisions) (#130894) https://github.com/flutter/packages/compare/3e8b8130cda3...209db219ad73 2023-07-19 reidbaker@google.com [tooling] mark infra steps as infra steps in yaml files (flutter/packages#4473) 2023-07-19 engine-flutter-autoroll@skia.org Manual roll Flutter from f842ed916514 to 6f09064e785b (11 revisions) (flutter/packages#4518) 2023-07-19 stuartmorgan@google.com [ci] Enable new sharding (flutter/packages#4515) 2023-07-19 stuartmorgan@google.com [flutter_markdown] Change the way tests get screen size (flutter/packages#4514) 2023-07-18 stuartmorgan@google.com [ci] Roll Flutter to f842ed91 (flutter/packages#4513) 2023-07-18 stuartmorgan@google.com [image_picker] Update Android example (flutter/packages#4504) 2023-07-18 43054281+camsim99@users.noreply.github.com [camerax] Fixes relistening to `onStreamedFrameAvailable`'s stream behavior (flutter/packages#4511) 2023-07-18 43054281+camsim99@users.noreply.github.com [various] Deletes deprecated splash screen meta-data element (flutter/packages#4501) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 3c83b71280590..ea845d2cb41d0 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -3e8b8130cda3b2564c8e9ee9f5825c0c34b8bc50 +209db219ad736b5c299cde7a215ee71b1afb3f4e From ef43463c86bf52fbb5906a4526188b04570f73a0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 11:54:10 -0400 Subject: [PATCH 0254/1547] Roll Flutter Engine from 076bd7b81d9c to 9645d8e27b59 (1 revision) (#130895) https://github.com/flutter/engine/compare/076bd7b81d9c...9645d8e27b59 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from e9409b832799 to 1f175b7a2155 (1 revision) (flutter/engine#43811) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5005fbc4dc69c..782d3bc5b2a3b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -076bd7b81d9c1aea5d9fda73a38cc8437d1aa09d +9645d8e27b59f4552745ce0c67bb119abcebc9f0 From f00391196795624cb8966478ecbde9eeeb2b9450 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Wed, 19 Jul 2023 09:36:08 -0700 Subject: [PATCH 0255/1547] Fix contradictory advice in "detach" docs; cut redundancy in "attach" (#130688) Fixes #115525. On [AbstractNode.detach] and its two progeny [RenderNode.detach] and [Layer.detach], the docs said both to call the inherited method before detaching children, and to end by doing so. The former advice is what's enforced by an assertion in the base implementation, so cut out the other. The corresponding [attach] methods redundantly said twice to call the inherited method first, so cut the redundancy. Leave in place the version more recently added (in #76021), because that PR shows the old version must have been easy to overlook. --- packages/flutter/lib/src/foundation/node.dart | 17 ++++++----------- packages/flutter/lib/src/rendering/layer.dart | 17 ++++++----------- packages/flutter/lib/src/rendering/object.dart | 17 ++++++----------- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/packages/flutter/lib/src/foundation/node.dart b/packages/flutter/lib/src/foundation/node.dart index ca383fb1524c1..a32f30a4818c5 100644 --- a/packages/flutter/lib/src/foundation/node.dart +++ b/packages/flutter/lib/src/foundation/node.dart @@ -92,12 +92,9 @@ class AbstractNode { /// Typically called only from the [parent]'s [attach] method, and by the /// [owner] to mark the root of a tree as attached. /// - /// Subclasses with children should override this method to first call their - /// inherited [attach] method, and then [attach] all their children to the - /// same [owner]. - /// - /// Implementations of this method should start with a call to the inherited - /// method, as in `super.attach(owner)`. + /// Subclasses with children should override this method to + /// [attach] all their children to the same [owner] + /// after calling the inherited method, as in `super.attach(owner)`. @mustCallSuper void attach(covariant Object owner) { assert(_owner == null); @@ -109,11 +106,9 @@ class AbstractNode { /// Typically called only from the [parent]'s [detach], and by the [owner] to /// mark the root of a tree as detached. /// - /// Subclasses with children should override this method to first call their - /// inherited [detach] method, and then [detach] all their children. - /// - /// Implementations of this method should end with a call to the inherited - /// method, as in `super.detach()`. + /// Subclasses with children should override this method to + /// [detach] all their children after calling the inherited method, + /// as in `super.detach()`. @mustCallSuper void detach() { assert(_owner != null); diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index 1cff262dde684..d7777918636b9 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -518,12 +518,9 @@ abstract class Layer with DiagnosticableTreeMixin { /// Typically called only from the [parent]'s [attach] method, and by the /// [owner] to mark the root of a tree as attached. /// - /// Subclasses with children should override this method to first call their - /// inherited [attach] method, and then [attach] all their children to the - /// same [owner]. - /// - /// Implementations of this method should start with a call to the inherited - /// method, as in `super.attach(owner)`. + /// Subclasses with children should override this method to + /// [attach] all their children to the same [owner] + /// after calling the inherited method, as in `super.attach(owner)`. @mustCallSuper void attach(covariant Object owner) { assert(_owner == null); @@ -535,11 +532,9 @@ abstract class Layer with DiagnosticableTreeMixin { /// Typically called only from the [parent]'s [detach], and by the [owner] to /// mark the root of a tree as detached. /// - /// Subclasses with children should override this method to first call their - /// inherited [detach] method, and then [detach] all their children. - /// - /// Implementations of this method should end with a call to the inherited - /// method, as in `super.detach()`. + /// Subclasses with children should override this method to + /// [detach] all their children after calling the inherited method, + /// as in `super.detach()`. @mustCallSuper void detach() { assert(_owner != null); diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 730bf50506442..d988fc923e36d 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -2074,12 +2074,9 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge /// Typically called only from the [parent]'s [attach] method, and by the /// [owner] to mark the root of a tree as attached. /// - /// Subclasses with children should override this method to first call their - /// inherited [attach] method, and then [attach] all their children to the - /// same [owner]. - /// - /// Implementations of this method should start with a call to the inherited - /// method, as in `super.attach(owner)`. + /// Subclasses with children should override this method to + /// [attach] all their children to the same [owner] + /// after calling the inherited method, as in `super.attach(owner)`. @mustCallSuper void attach(PipelineOwner owner) { assert(!_debugDisposed); @@ -2116,11 +2113,9 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge /// Typically called only from the [parent]'s [detach], and by the [owner] to /// mark the root of a tree as detached. /// - /// Subclasses with children should override this method to first call their - /// inherited [detach] method, and then [detach] all their children. - /// - /// Implementations of this method should end with a call to the inherited - /// method, as in `super.detach()`. + /// Subclasses with children should override this method to + /// [detach] all their children after calling the inherited method, + /// as in `super.detach()`. @mustCallSuper void detach() { assert(_owner != null); From ffa59533203a63e50d40b928ecb4b7a2e44f7442 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 13:18:45 -0400 Subject: [PATCH 0256/1547] Roll Flutter Engine from 9645d8e27b59 to 4b274b5c2c3a (3 revisions) (#130903) https://github.com/flutter/engine/compare/9645d8e27b59...4b274b5c2c3a 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 16475d7aa315 to 4728980564b1 (1 revision) (flutter/engine#43815) 2023-07-19 jason-simmons@users.noreply.github.com Apply the offset to the child bounds of an ImageFilterLayer with no filter (flutter/engine#43783) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 1f175b7a2155 to 16475d7aa315 (1 revision) (flutter/engine#43812) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 782d3bc5b2a3b..4a826eee9e8c8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9645d8e27b59f4552745ce0c67bb119abcebc9f0 +4b274b5c2c3a3cd6e9e04041fea730952605ac57 From 8d3a5cf1a52fef558f66eba01dd92e60d6061332 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 14:38:56 -0400 Subject: [PATCH 0257/1547] Roll Flutter Engine from 4b274b5c2c3a to 2fab8ab5ff7f (2 revisions) (#130920) https://github.com/flutter/engine/compare/4b274b5c2c3a...2fab8ab5ff7f 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 4728980564b1 to a352521a3a7c (3 revisions) (flutter/engine#43816) 2023-07-19 bdero@google.com [Impeller] Disable color attachment on clip pipelines for Metal & Vulkan. (flutter/engine#43781) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4a826eee9e8c8..57ad1b50355f9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4b274b5c2c3a3cd6e9e04041fea730952605ac57 +2fab8ab5ff7ff60fc058cb90e5c279302083d540 From b54e83e4fc141c8a2b04cd2d0ede77f72d33979d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 16:01:25 -0400 Subject: [PATCH 0258/1547] Roll Flutter Engine from 2fab8ab5ff7f to 6ea54eee0592 (2 revisions) (#130929) https://github.com/flutter/engine/compare/2fab8ab5ff7f...6ea54eee0592 2023-07-19 skia-flutter-autoroll@skia.org Roll Dart SDK from a013e7bf089e to 936824d49aa7 (1 revision) (flutter/engine#43820) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from a352521a3a7c to 8d19d04472e1 (1 revision) (flutter/engine#43818) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 57ad1b50355f9..43f1d34c346fa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2fab8ab5ff7ff60fc058cb90e5c279302083d540 +6ea54eee0592c2033b9c058687f4ec3239c720b4 From 0830a362d51c6fc178f520aa58a9a4bf8e0d0e3c Mon Sep 17 00:00:00 2001 From: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> Date: Wed, 19 Jul 2023 22:07:59 +0200 Subject: [PATCH 0259/1547] Add support for M3 motion (#129942) ## Description This adds support for M3 easing and duration tokens. This PR includes these changes: * Generation of duration and easing constants, in `Durations` and `Easing`, respectively (`Curves` is already taken in the `animation` library) * Add 3 Dart fixes Once this is merged, I'll migrate packages/plugins/customers and then uncomment the deprecation notices for the 3 M2 curves, all of which have 1:1 replacements. ## Related Issues - Fixes https://github.com/flutter/flutter/issues/116525 ## Tests - Added Dart fix tests ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- dev/tools/gen_defaults/bin/gen_defaults.dart | 2 + .../gen_defaults/generated/used_tokens.csv | 25 ++ .../gen_defaults/lib/motion_template.dart | 90 +++++++ .../fix_data/fix_material/fix_material.yaml | 39 +++ packages/flutter/lib/material.dart | 1 + .../flutter/lib/src/animation/curves.dart | 3 +- packages/flutter/lib/src/material/curves.dart | 2 + packages/flutter/lib/src/material/motion.dart | 234 ++++++++++++++++++ .../flutter/test_fixes/material/material.dart | 6 + .../test_fixes/material/material.dart.expect | 6 + 10 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 dev/tools/gen_defaults/lib/motion_template.dart create mode 100644 packages/flutter/lib/src/material/motion.dart diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart index ee3acd11f9453..6dc16b7d044ac 100644 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ b/dev/tools/gen_defaults/bin/gen_defaults.dart @@ -37,6 +37,7 @@ import 'package:gen_defaults/input_chip_template.dart'; import 'package:gen_defaults/input_decorator_template.dart'; import 'package:gen_defaults/list_tile_template.dart'; import 'package:gen_defaults/menu_template.dart'; +import 'package:gen_defaults/motion_template.dart'; import 'package:gen_defaults/navigation_bar_template.dart'; import 'package:gen_defaults/navigation_drawer_template.dart'; import 'package:gen_defaults/navigation_rail_template.dart'; @@ -131,6 +132,7 @@ Future main(List args) async { ListTileTemplate('LisTile', '$materialLib/list_tile.dart', tokens).updateFile(); InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile(); MenuTemplate('Menu', '$materialLib/menu_anchor.dart', tokens).updateFile(); + MotionTemplate('Motion', '$materialLib/motion.dart', tokens, tokenLogger).updateFile(); NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile(); NavigationDrawerTemplate('NavigationDrawer', '$materialLib/navigation_drawer.dart', tokens).updateFile(); NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile(); diff --git a/dev/tools/gen_defaults/generated/used_tokens.csv b/dev/tools/gen_defaults/generated/used_tokens.csv index fd5cf2e88c0e7..28ec7c57f4746 100644 --- a/dev/tools/gen_defaults/generated/used_tokens.csv +++ b/dev/tools/gen_defaults/generated/used_tokens.csv @@ -856,6 +856,31 @@ md.sys.elevation.level2, md.sys.elevation.level3, md.sys.elevation.level4, md.sys.elevation.level5, +md.sys.motion.duration.extra-long1Ms, +md.sys.motion.duration.extra-long2Ms, +md.sys.motion.duration.extra-long3Ms, +md.sys.motion.duration.extra-long4Ms, +md.sys.motion.duration.long1Ms, +md.sys.motion.duration.long2Ms, +md.sys.motion.duration.long3Ms, +md.sys.motion.duration.long4Ms, +md.sys.motion.duration.medium1Ms, +md.sys.motion.duration.medium2Ms, +md.sys.motion.duration.medium3Ms, +md.sys.motion.duration.medium4Ms, +md.sys.motion.duration.short1Ms, +md.sys.motion.duration.short2Ms, +md.sys.motion.duration.short3Ms, +md.sys.motion.duration.short4Ms, +md.sys.motion.easing.emphasized.accelerate, +md.sys.motion.easing.emphasized.decelerate, +md.sys.motion.easing.legacy, +md.sys.motion.easing.legacy.accelerate, +md.sys.motion.easing.legacy.decelerate, +md.sys.motion.easing.linear, +md.sys.motion.easing.standard, +md.sys.motion.easing.standard.accelerate, +md.sys.motion.easing.standard.decelerate, md.sys.shape.corner.extra-large, md.sys.shape.corner.extra-large.top, md.sys.shape.corner.extra-small, diff --git a/dev/tools/gen_defaults/lib/motion_template.dart b/dev/tools/gen_defaults/lib/motion_template.dart new file mode 100644 index 0000000000000..0683244133c91 --- /dev/null +++ b/dev/tools/gen_defaults/lib/motion_template.dart @@ -0,0 +1,90 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'template.dart'; +import 'token_logger.dart'; + +class MotionTemplate extends TokenTemplate { + /// Since we generate the tokens dynamically, we need to store them and log + /// them manually, instead of using [getToken]. + MotionTemplate(String blockName, String fileName, this.tokens, this.tokensLogger) : super(blockName, fileName, tokens); + Map tokens; + TokenLogger tokensLogger; + + // List of duration tokens. + late List> durationTokens = tokens.entries.where( + (MapEntry entry) => entry.key.contains('.duration.') + ).toList() + ..sort( + (MapEntry a, MapEntry b) => (a.value as double).compareTo(b.value as double) + ); + + // List of easing curve tokens. + late List> easingCurveTokens = tokens.entries.where( + (MapEntry entry) => entry.key.contains('.easing.') + ).toList() + ..sort( + // Sort the legacy curves at the end of the list. + (MapEntry a, MapEntry b) => a.key.contains('legacy') ? 1 : a.key.compareTo(b.key) + ); + + String durationTokenString(String token, dynamic tokenValue) { + tokensLogger.log(token); + final String tokenName = token.split('.').last.replaceAll('-', '').replaceFirst('Ms', ''); + final int milliseconds = (tokenValue as double).toInt(); + return +''' + /// The $tokenName duration (${milliseconds}ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration $tokenName = Duration(milliseconds: $milliseconds); +'''; + } + + String easingCurveTokenString(String token, dynamic tokenValue) { + tokensLogger.log(token); + final String tokenName = token + .replaceFirst('md.sys.motion.easing.', '') + .replaceAllMapped(RegExp(r'[-\.](\w)'), (Match match) { + return match.group(1)!.toUpperCase(); + }); + return ''' + /// The $tokenName easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve $tokenName = $tokenValue; +'''; + } + + @override + String generate() => ''' +/// The set of durations in the Material specification. +/// +/// See also: +/// +/// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) +/// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) +abstract final class Durations { +${durationTokens.map((MapEntry entry) => durationTokenString(entry.key, entry.value)).join('\n')}} + + +// TODO(guidezpl): Improve with description and assets, b/289870605 + +/// The set of easing curves in the Material specification. +/// +/// See also: +/// +/// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) +/// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) +/// * [Curves], for a collection of non-Material animation easing curves. +abstract final class Easing { +${easingCurveTokens.map((MapEntry entry) => easingCurveTokenString(entry.key, entry.value)).join('\n')}} +'''; +} diff --git a/packages/flutter/lib/fix_data/fix_material/fix_material.yaml b/packages/flutter/lib/fix_data/fix_material/fix_material.yaml index 0359c8da87f0c..fb8467c0c858f 100644 --- a/packages/flutter/lib/fix_data/fix_material/fix_material.yaml +++ b/packages/flutter/lib/fix_data/fix_material/fix_material.yaml @@ -897,4 +897,43 @@ transforms: oldName: 'showTrackOnHover' newName: 'trackVisibility' + # Changes made in https://github.com/flutter/flutter/pull/129942 + - title: "Migrate to 'Easing.legacy'" + date: 2023-07-04 + element: + uris: [ 'material.dart' ] + variable: 'standardEasing' + changes: + - kind: 'replacedBy' + newElement: + uris: [ 'material.dart' ] + field: legacy + inClass: Easing + + # Changes made in https://github.com/flutter/flutter/pull/129942 + - title: "Migrate to 'Easing.legacyAccelerate'" + date: 2023-07-04 + element: + uris: [ 'material.dart' ] + variable: 'accelerateEasing' + changes: + - kind: 'replacedBy' + newElement: + uris: [ 'material.dart' ] + field: legacyAccelerate + inClass: Easing + + # Changes made in https://github.com/flutter/flutter/pull/129942 + - title: "Migrate to 'Easing.legacyDecelerate'" + date: 2023-07-04 + element: + uris: [ 'material.dart' ] + variable: 'decelerateEasing' + changes: + - kind: 'replacedBy' + newElement: + uris: [ 'material.dart' ] + field: legacyDecelerate + inClass: Easing + # Before adding a new fix: read instructions at the top of this file. diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart index 213bd29d8a42e..66153358ca668 100644 --- a/packages/flutter/lib/material.dart +++ b/packages/flutter/lib/material.dart @@ -122,6 +122,7 @@ export 'src/material/menu_button_theme.dart'; export 'src/material/menu_style.dart'; export 'src/material/menu_theme.dart'; export 'src/material/mergeable_material.dart'; +export 'src/material/motion.dart'; export 'src/material/navigation_bar.dart'; export 'src/material/navigation_bar_theme.dart'; export 'src/material/navigation_drawer.dart'; diff --git a/packages/flutter/lib/src/animation/curves.dart b/packages/flutter/lib/src/animation/curves.dart index fa75eadd965a7..d824c8221ace3 100644 --- a/packages/flutter/lib/src/animation/curves.dart +++ b/packages/flutter/lib/src/animation/curves.dart @@ -1354,6 +1354,7 @@ class ElasticInOutCurve extends Curve { /// /// * [Curve], the interface implemented by the constants available from the /// [Curves] class. +/// * [Easing], for the Material animation curves. abstract final class Curves { /// A linear animation curve. /// @@ -1741,7 +1742,7 @@ abstract final class Curves { /// /// See also: /// - /// * [standardEasing], the name for this curve in the Material specification. + /// * [Easing.legacy], the name for this curve in the Material specification. static const Cubic fastOutSlowIn = Cubic(0.4, 0.0, 0.2, 1.0); /// A cubic animation curve that starts quickly, slows down, and then ends diff --git a/packages/flutter/lib/src/material/curves.dart b/packages/flutter/lib/src/material/curves.dart index eb5762178f10d..c267e3771ee42 100644 --- a/packages/flutter/lib/src/material/curves.dart +++ b/packages/flutter/lib/src/material/curves.dart @@ -6,6 +6,8 @@ import 'package:flutter/animation.dart'; // The easing curves of the Material Library +// TODO(guidezpl): deprecate the three curves below once customers (packages/plugins) are migrated + /// The standard easing curve in the Material specification. /// /// Elements that begin and end at rest use standard easing. diff --git a/packages/flutter/lib/src/material/motion.dart b/packages/flutter/lib/src/material/motion.dart new file mode 100644 index 0000000000000..e93e8226254d2 --- /dev/null +++ b/packages/flutter/lib/src/material/motion.dart @@ -0,0 +1,234 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/animation.dart'; + +// BEGIN GENERATED TOKEN PROPERTIES - Motion + +// Do not edit by hand. The code between the "BEGIN GENERATED" and +// "END GENERATED" comments are generated from data in the Material +// Design token database by the script: +// dev/tools/gen_defaults/bin/gen_defaults.dart. + +/// The set of durations in the Material specification. +/// +/// See also: +/// +/// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) +/// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) +abstract final class Durations { + /// The short1 duration (50ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration short1 = Duration(milliseconds: 50); + + /// The short2 duration (100ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration short2 = Duration(milliseconds: 100); + + /// The short3 duration (150ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration short3 = Duration(milliseconds: 150); + + /// The short4 duration (200ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration short4 = Duration(milliseconds: 200); + + /// The medium1 duration (250ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration medium1 = Duration(milliseconds: 250); + + /// The medium2 duration (300ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration medium2 = Duration(milliseconds: 300); + + /// The medium3 duration (350ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration medium3 = Duration(milliseconds: 350); + + /// The medium4 duration (400ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration medium4 = Duration(milliseconds: 400); + + /// The long1 duration (450ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration long1 = Duration(milliseconds: 450); + + /// The long2 duration (500ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration long2 = Duration(milliseconds: 500); + + /// The long3 duration (550ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration long3 = Duration(milliseconds: 550); + + /// The long4 duration (600ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration long4 = Duration(milliseconds: 600); + + /// The extralong1 duration (700ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration extralong1 = Duration(milliseconds: 700); + + /// The extralong2 duration (800ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration extralong2 = Duration(milliseconds: 800); + + /// The extralong3 duration (900ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration extralong3 = Duration(milliseconds: 900); + + /// The extralong4 duration (1000ms) in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Duration tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#c009dec6-f29b-4503-b9f0-482af14a8bbd) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Duration extralong4 = Duration(milliseconds: 1000); +} + + +// TODO(guidezpl): Improve with description and assets, b/289870605 + +/// The set of easing curves in the Material specification. +/// +/// See also: +/// +/// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) +/// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) +/// * [Curves], for a collection of non-Material animation easing curves. +abstract final class Easing { + /// The emphasizedAccelerate easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve emphasizedAccelerate = Cubic(0.3, 0.0, 0.8, 0.15); + + /// The emphasizedDecelerate easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve emphasizedDecelerate = Cubic(0.05, 0.7, 0.1, 1.0); + + /// The linear easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve linear = Cubic(0.0, 0.0, 1.0, 1.0); + + /// The standard easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve standard = Cubic(0.2, 0.0, 0.0, 1.0); + + /// The standardAccelerate easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve standardAccelerate = Cubic(0.3, 0.0, 1.0, 1.0); + + /// The standardDecelerate easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve standardDecelerate = Cubic(0.0, 0.0, 0.0, 1.0); + + /// The legacyDecelerate easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve legacyDecelerate = Cubic(0.0, 0.0, 0.2, 1.0); + + /// The legacyAccelerate easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve legacyAccelerate = Cubic(0.4, 0.0, 1.0, 1.0); + + /// The legacy easing curve in the Material specification. + /// + /// See also: + /// + /// * [M3 guidelines: Easing tokens](https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#433b1153-2ea3-4fe2-9748-803a47bc97ee) + /// * [M3 guidelines: Applying easing and duration](https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration) + static const Curve legacy = Cubic(0.4, 0.0, 0.2, 1.0); +} + +// END GENERATED TOKEN PROPERTIES - Motion diff --git a/packages/flutter/test_fixes/material/material.dart b/packages/flutter/test_fixes/material/material.dart index c00c6f91c8db7..7fa4f903e5d93 100644 --- a/packages/flutter/test_fixes/material/material.dart +++ b/packages/flutter/test_fixes/material/material.dart @@ -317,4 +317,10 @@ void main() { clipBehavior: Clip.none, ); final Clip clip = details.clipBehavior; + + // Changes made in https://github.com/flutter/flutter/pull/129942 + // TODO(guidezpl): enable fix after https://github.com/dart-lang/sdk/issues/52902 + // const Curve curve = standardEasing; expect Easing.legacy + // const Curve curve = accelerateEasing; expect Easing.legacyAccelerate + // const Curve curve = decelerateEasing; expect Easing.legacyDecelerate } diff --git a/packages/flutter/test_fixes/material/material.dart.expect b/packages/flutter/test_fixes/material/material.dart.expect index 48c65bd6175e9..f6515961459f9 100644 --- a/packages/flutter/test_fixes/material/material.dart.expect +++ b/packages/flutter/test_fixes/material/material.dart.expect @@ -313,4 +313,10 @@ void main() { decorationClipBehavior: Clip.none, ); final Clip clip = details.decorationClipBehavior; + + // Changes made in https://github.com/flutter/flutter/pull/129942 + // TODO(guidezpl): enable fix after https://github.com/dart-lang/sdk/issues/52902 + // const Curve curve = standardEasing; expect Easing.legacy + // const Curve curve = accelerateEasing; expect Easing.legacyAccelerate + // const Curve curve = decelerateEasing; expect Easing.legacyDecelerate } From 6cabe73623a7a8c43b964b8ae3d4a6166ad77c45 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 17:27:33 -0400 Subject: [PATCH 0260/1547] Roll Flutter Engine from 6ea54eee0592 to 0af285219809 (4 revisions) (#130939) https://github.com/flutter/engine/compare/6ea54eee0592...0af285219809 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 650c980daa72 to 30d458aea0b9 (1 revision) (flutter/engine#43825) 2023-07-19 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Iqf3gYJ8Vkq8k8l3O... to 7kGBjmX-zBXcg1svE... (flutter/engine#43823) 2023-07-19 flar@google.com fix handling of clipped rendering inside a layer that applies a filter (flutter/engine#43787) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 8d19d04472e1 to 650c980daa72 (6 revisions) (flutter/engine#43821) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from Iqf3gYJ8Vkq8 to 7kGBjmX-zBXc If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 43f1d34c346fa..14d1a8a3fce06 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6ea54eee0592c2033b9c058687f4ec3239c720b4 +0af285219809931e72bc536dff1b1bcf8b7420a7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index cdea18ecdbff9..38e78c3da0950 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Iqf3gYJ8Vkq8k8l3OYAUUrwZJ8eEi2wVosGclDAPxtwC +7kGBjmX-zBXcg1svEd78lkHB3n85_cD7LYmNYYdeQlMC From 07cdf37ca3e380fefb2cf5aff75055981115511b Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 19 Jul 2023 15:47:43 -0700 Subject: [PATCH 0261/1547] Add implementation advice to debugTypicalAncestorWidgetClass (#130530) Fixes https://github.com/flutter/flutter/issues/56500 --- packages/flutter/lib/src/rendering/paragraph.dart | 2 +- packages/flutter/lib/src/widgets/framework.dart | 15 ++++++++++++++- packages/flutter/lib/src/widgets/widget_span.dart | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 4fd946a88d991..d53720c869bf9 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -71,7 +71,7 @@ class TextParentData extends ParentData with ContainerParentDataMixin } @override - String toString() =>'widget: $span, ${offset == null ? "not laid out" : "offset: $offset"}'; + String toString() => 'widget: $span, ${offset == null ? "not laid out" : "offset: $offset"}'; } /// A mixin that provides useful default behaviors for text [RenderBox]es diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index da4132c16a5d7..8628b57ba4a82 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1514,7 +1514,20 @@ abstract class ParentDataWidget extends ProxyWidget { /// that [applyParentData] will write to. /// /// This is only used in error messages to tell users what widget typically - /// wraps this ParentDataWidget. + /// wraps this [ParentDataWidget]. + /// + /// ## Implementations + /// + /// The returned type should be a subclass of `RenderObjectWidget`. + /// + /// ```dart + /// @override + /// Type get debugTypicalAncestorWidgetClass => FrogJar; + /// ``` + /// + /// If the "typical" parent is generic (`Foo`), consider specifying either + /// a typical type argument (e.g. `Foo` if `int` is typically how the + /// type is specialized), or specifying the upper bound (e.g. `Foo`). Type get debugTypicalAncestorWidgetClass; Iterable _debugDescribeIncorrectParentDataType({ diff --git a/packages/flutter/lib/src/widgets/widget_span.dart b/packages/flutter/lib/src/widgets/widget_span.dart index 34afb66f3a935..65427e7ed2d3b 100644 --- a/packages/flutter/lib/src/widgets/widget_span.dart +++ b/packages/flutter/lib/src/widgets/widget_span.dart @@ -290,7 +290,7 @@ class _WidgetSpanParentData extends ParentDataWidget { } @override - Type get debugTypicalAncestorWidgetClass => RenderInlineChildrenContainerDefaults; + Type get debugTypicalAncestorWidgetClass => RichText; } // A RenderObjectWidget that automatically applies text scaling on inline From 258382c5949ecc354c46591198a599953079865d Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Wed, 19 Jul 2023 15:48:40 -0700 Subject: [PATCH 0262/1547] Add menu dismiss localization (#128613) ## Description Modifies the semantic label for popup and context menus to be "Dismiss menu" instead of just "Dismiss". ## Related Issues - Fixes https://github.com/flutter/flutter/issues/118994 ## Tests - Updated tests --- .../lib/src/cupertino/context_menu.dart | 3 +- .../lib/src/cupertino/localizations.dart | 7 + .../src/material/material_localizations.dart | 7 + .../flutter/lib/src/material/popup_menu.dart | 2 +- .../test/material/localizations_test.dart | 1 + .../test/material/popup_menu_test.dart | 6 +- .../lib/src/l10n/cupertino_af.arb | 3 +- .../lib/src/l10n/cupertino_am.arb | 3 +- .../lib/src/l10n/cupertino_ar.arb | 3 +- .../lib/src/l10n/cupertino_as.arb | 3 +- .../lib/src/l10n/cupertino_az.arb | 3 +- .../lib/src/l10n/cupertino_be.arb | 3 +- .../lib/src/l10n/cupertino_bg.arb | 3 +- .../lib/src/l10n/cupertino_bn.arb | 3 +- .../lib/src/l10n/cupertino_bs.arb | 3 +- .../lib/src/l10n/cupertino_ca.arb | 3 +- .../lib/src/l10n/cupertino_cs.arb | 3 +- .../lib/src/l10n/cupertino_cy.arb | 3 +- .../lib/src/l10n/cupertino_da.arb | 3 +- .../lib/src/l10n/cupertino_de.arb | 3 +- .../lib/src/l10n/cupertino_el.arb | 3 +- .../lib/src/l10n/cupertino_en.arb | 5 + .../lib/src/l10n/cupertino_es.arb | 3 +- .../lib/src/l10n/cupertino_et.arb | 3 +- .../lib/src/l10n/cupertino_eu.arb | 3 +- .../lib/src/l10n/cupertino_fa.arb | 3 +- .../lib/src/l10n/cupertino_fi.arb | 3 +- .../lib/src/l10n/cupertino_fil.arb | 3 +- .../lib/src/l10n/cupertino_fr.arb | 3 +- .../lib/src/l10n/cupertino_gl.arb | 3 +- .../lib/src/l10n/cupertino_gsw.arb | 3 +- .../lib/src/l10n/cupertino_gu.arb | 3 +- .../lib/src/l10n/cupertino_he.arb | 3 +- .../lib/src/l10n/cupertino_hi.arb | 3 +- .../lib/src/l10n/cupertino_hr.arb | 3 +- .../lib/src/l10n/cupertino_hu.arb | 3 +- .../lib/src/l10n/cupertino_hy.arb | 3 +- .../lib/src/l10n/cupertino_id.arb | 3 +- .../lib/src/l10n/cupertino_is.arb | 3 +- .../lib/src/l10n/cupertino_it.arb | 3 +- .../lib/src/l10n/cupertino_ja.arb | 3 +- .../lib/src/l10n/cupertino_ka.arb | 3 +- .../lib/src/l10n/cupertino_kk.arb | 3 +- .../lib/src/l10n/cupertino_km.arb | 3 +- .../lib/src/l10n/cupertino_kn.arb | 3 +- .../lib/src/l10n/cupertino_ko.arb | 3 +- .../lib/src/l10n/cupertino_ky.arb | 3 +- .../lib/src/l10n/cupertino_lo.arb | 3 +- .../lib/src/l10n/cupertino_lt.arb | 3 +- .../lib/src/l10n/cupertino_lv.arb | 3 +- .../lib/src/l10n/cupertino_mk.arb | 3 +- .../lib/src/l10n/cupertino_ml.arb | 3 +- .../lib/src/l10n/cupertino_mn.arb | 3 +- .../lib/src/l10n/cupertino_mr.arb | 3 +- .../lib/src/l10n/cupertino_ms.arb | 3 +- .../lib/src/l10n/cupertino_my.arb | 3 +- .../lib/src/l10n/cupertino_nb.arb | 3 +- .../lib/src/l10n/cupertino_ne.arb | 3 +- .../lib/src/l10n/cupertino_nl.arb | 3 +- .../lib/src/l10n/cupertino_no.arb | 3 +- .../lib/src/l10n/cupertino_or.arb | 3 +- .../lib/src/l10n/cupertino_pa.arb | 3 +- .../lib/src/l10n/cupertino_pl.arb | 3 +- .../lib/src/l10n/cupertino_pt.arb | 3 +- .../lib/src/l10n/cupertino_ro.arb | 3 +- .../lib/src/l10n/cupertino_ru.arb | 3 +- .../lib/src/l10n/cupertino_si.arb | 3 +- .../lib/src/l10n/cupertino_sk.arb | 3 +- .../lib/src/l10n/cupertino_sl.arb | 3 +- .../lib/src/l10n/cupertino_sq.arb | 3 +- .../lib/src/l10n/cupertino_sr.arb | 3 +- .../lib/src/l10n/cupertino_sv.arb | 3 +- .../lib/src/l10n/cupertino_sw.arb | 3 +- .../lib/src/l10n/cupertino_ta.arb | 3 +- .../lib/src/l10n/cupertino_te.arb | 3 +- .../lib/src/l10n/cupertino_th.arb | 3 +- .../lib/src/l10n/cupertino_tl.arb | 3 +- .../lib/src/l10n/cupertino_tr.arb | 3 +- .../lib/src/l10n/cupertino_uk.arb | 3 +- .../lib/src/l10n/cupertino_ur.arb | 3 +- .../lib/src/l10n/cupertino_uz.arb | 3 +- .../lib/src/l10n/cupertino_vi.arb | 3 +- .../lib/src/l10n/cupertino_zh.arb | 3 +- .../lib/src/l10n/cupertino_zu.arb | 3 +- .../generated_cupertino_localizations.dart | 234 +++++++++++++++++ .../generated_material_localizations.dart | 237 ++++++++++++++++++ .../lib/src/l10n/material_af.arb | 3 +- .../lib/src/l10n/material_am.arb | 3 +- .../lib/src/l10n/material_ar.arb | 3 +- .../lib/src/l10n/material_as.arb | 3 +- .../lib/src/l10n/material_az.arb | 3 +- .../lib/src/l10n/material_be.arb | 3 +- .../lib/src/l10n/material_bg.arb | 3 +- .../lib/src/l10n/material_bn.arb | 3 +- .../lib/src/l10n/material_bs.arb | 3 +- .../lib/src/l10n/material_ca.arb | 3 +- .../lib/src/l10n/material_cs.arb | 3 +- .../lib/src/l10n/material_cy.arb | 3 +- .../lib/src/l10n/material_da.arb | 3 +- .../lib/src/l10n/material_de.arb | 3 +- .../lib/src/l10n/material_el.arb | 3 +- .../lib/src/l10n/material_en.arb | 5 + .../lib/src/l10n/material_es.arb | 3 +- .../lib/src/l10n/material_et.arb | 3 +- .../lib/src/l10n/material_eu.arb | 3 +- .../lib/src/l10n/material_fa.arb | 3 +- .../lib/src/l10n/material_fi.arb | 3 +- .../lib/src/l10n/material_fil.arb | 3 +- .../lib/src/l10n/material_fr.arb | 3 +- .../lib/src/l10n/material_gl.arb | 3 +- .../lib/src/l10n/material_gsw.arb | 3 +- .../lib/src/l10n/material_gu.arb | 3 +- .../lib/src/l10n/material_he.arb | 3 +- .../lib/src/l10n/material_hi.arb | 3 +- .../lib/src/l10n/material_hr.arb | 3 +- .../lib/src/l10n/material_hu.arb | 3 +- .../lib/src/l10n/material_hy.arb | 3 +- .../lib/src/l10n/material_id.arb | 3 +- .../lib/src/l10n/material_is.arb | 3 +- .../lib/src/l10n/material_it.arb | 3 +- .../lib/src/l10n/material_ja.arb | 3 +- .../lib/src/l10n/material_ka.arb | 3 +- .../lib/src/l10n/material_kk.arb | 3 +- .../lib/src/l10n/material_km.arb | 3 +- .../lib/src/l10n/material_kn.arb | 3 +- .../lib/src/l10n/material_ko.arb | 3 +- .../lib/src/l10n/material_ky.arb | 3 +- .../lib/src/l10n/material_lo.arb | 3 +- .../lib/src/l10n/material_lt.arb | 3 +- .../lib/src/l10n/material_lv.arb | 3 +- .../lib/src/l10n/material_mk.arb | 3 +- .../lib/src/l10n/material_ml.arb | 3 +- .../lib/src/l10n/material_mn.arb | 3 +- .../lib/src/l10n/material_mr.arb | 3 +- .../lib/src/l10n/material_ms.arb | 3 +- .../lib/src/l10n/material_my.arb | 3 +- .../lib/src/l10n/material_nb.arb | 3 +- .../lib/src/l10n/material_ne.arb | 3 +- .../lib/src/l10n/material_nl.arb | 3 +- .../lib/src/l10n/material_no.arb | 3 +- .../lib/src/l10n/material_or.arb | 3 +- .../lib/src/l10n/material_pa.arb | 3 +- .../lib/src/l10n/material_pl.arb | 3 +- .../lib/src/l10n/material_ps.arb | 3 +- .../lib/src/l10n/material_pt.arb | 3 +- .../lib/src/l10n/material_ro.arb | 3 +- .../lib/src/l10n/material_ru.arb | 3 +- .../lib/src/l10n/material_si.arb | 3 +- .../lib/src/l10n/material_sk.arb | 3 +- .../lib/src/l10n/material_sl.arb | 3 +- .../lib/src/l10n/material_sq.arb | 3 +- .../lib/src/l10n/material_sr.arb | 3 +- .../lib/src/l10n/material_sv.arb | 3 +- .../lib/src/l10n/material_sw.arb | 3 +- .../lib/src/l10n/material_ta.arb | 3 +- .../lib/src/l10n/material_te.arb | 3 +- .../lib/src/l10n/material_th.arb | 3 +- .../lib/src/l10n/material_tl.arb | 3 +- .../lib/src/l10n/material_tr.arb | 3 +- .../lib/src/l10n/material_uk.arb | 3 +- .../lib/src/l10n/material_ur.arb | 3 +- .../lib/src/l10n/material_uz.arb | 3 +- .../lib/src/l10n/material_vi.arb | 3 +- .../lib/src/l10n/material_zh.arb | 3 +- .../lib/src/l10n/material_zu.arb | 3 +- 165 files changed, 812 insertions(+), 160 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index f0d610c459b2b..1a98cf5bf4e43 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -12,6 +12,7 @@ import 'package:flutter/services.dart' show HapticFeedback; import 'package:flutter/widgets.dart'; import 'colors.dart'; +import 'localizations.dart'; // The scale of the child at the time that the CupertinoContextMenu opens. // This value was eyeballed from a physical device running iOS 13.1.2. @@ -535,7 +536,7 @@ class _CupertinoContextMenuState extends State with Ticker _route = _ContextMenuRoute( actions: widget.actions, - barrierLabel: 'Dismiss', + barrierLabel: CupertinoLocalizations.of(context).menuDismissLabel, filter: ui.ImageFilter.blur( sigmaX: 5.0, sigmaY: 5.0, diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index 477fda7567db0..c3456e82ae417 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -256,6 +256,10 @@ abstract class CupertinoLocalizations { /// user interaction with elements behind it. String get modalBarrierDismissLabel; + /// Label read out by accessibility tools (VoiceOver) for a context menu to + /// indicate that a tap outside dismisses the context menu. + String get menuDismissLabel; + /// The `CupertinoLocalizations` from the closest [Localizations] instance /// that encloses the given context. /// @@ -457,6 +461,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { @override String get modalBarrierDismissLabel => 'Dismiss'; + @override + String get menuDismissLabel => 'Dismiss menu'; + /// Creates an object that provides US English resource values for the /// cupertino library widgets. /// diff --git a/packages/flutter/lib/src/material/material_localizations.dart b/packages/flutter/lib/src/material/material_localizations.dart index 489c23a2ca143..87ef8826fb3a0 100644 --- a/packages/flutter/lib/src/material/material_localizations.dart +++ b/packages/flutter/lib/src/material/material_localizations.dart @@ -139,6 +139,10 @@ abstract class MaterialLocalizations { /// user interaction with elements behind it. String get modalBarrierDismissLabel; + /// Label read out by accessibility tools (TalkBack or VoiceOver) for a + /// context menu to indicate that a tap dismisses the context menu. + String get menuDismissLabel; + /// Label read out by accessibility tools (TalkBack or VoiceOver) when a /// drawer widget is opened. String get drawerLabel; @@ -1192,6 +1196,9 @@ class DefaultMaterialLocalizations implements MaterialLocalizations { @override String get modalBarrierDismissLabel => 'Dismiss'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override ScriptCategory get scriptCategory => ScriptCategory.englishLike; diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index c4846e8dd80b7..1d80305e74d62 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -976,7 +976,7 @@ Future showMenu({ shadowColor: shadowColor, surfaceTintColor: surfaceTintColor, semanticLabel: semanticLabel, - barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, + barrierLabel: MaterialLocalizations.of(context).menuDismissLabel, shape: shape, color: color, capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart index 67df019b002e9..9e303fef9fad3 100644 --- a/packages/flutter/test/material/localizations_test.dart +++ b/packages/flutter/test/material/localizations_test.dart @@ -38,6 +38,7 @@ void main() { expect(localizations.timePickerHourModeAnnouncement, isNotNull); expect(localizations.timePickerMinuteModeAnnouncement, isNotNull); expect(localizations.modalBarrierDismissLabel, isNotNull); + expect(localizations.menuDismissLabel, isNotNull); expect(localizations.drawerLabel, isNotNull); expect(localizations.menuBarMenuLabel, isNotNull); expect(localizations.popupMenuLabel, isNotNull); diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 13c24d0b8f028..ea3c47668eb15 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1196,7 +1196,7 @@ void main() { ), TestSemantics( actions: [SemanticsAction.tap, SemanticsAction.dismiss], - label: 'Dismiss', + label: 'Dismiss menu', textDirection: TextDirection.ltr, ), ], @@ -1284,7 +1284,7 @@ void main() { ), TestSemantics( actions: [SemanticsAction.tap, SemanticsAction.dismiss], - label: 'Dismiss', + label: 'Dismiss menu', textDirection: TextDirection.ltr, ), ], @@ -1407,7 +1407,7 @@ void main() { ), TestSemantics( actions: [SemanticsAction.tap, SemanticsAction.dismiss], - label: 'Dismiss', + label: 'Dismiss menu', textDirection: TextDirection.ltr, ), ], diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb index 1f96f95a55a0c..c3e82eaebc0a0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Oortjie $tabIndex van $tabCount", "modalBarrierDismissLabel": "Maak toe", "searchTextFieldPlaceholderLabel": "Soek", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb index d3de14de4340c..d3c01ffb78aa0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "ትር $tabIndex ከ$tabCount", "modalBarrierDismissLabel": "አሰናብት", "searchTextFieldPlaceholderLabel": "ፍለጋ", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb index 6f61d6b28544c..3e439036b05c1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb @@ -42,5 +42,6 @@ "tabSemanticsLabel": "علامة التبويب $tabIndex من $tabCount", "modalBarrierDismissLabel": "رفض", "searchTextFieldPlaceholderLabel": "بحث", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb index e40478d282f68..7c39f67115a0c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount টা টেবৰ $tabIndex নম্বৰটো", "modalBarrierDismissLabel": "অগ্ৰাহ্য কৰক", "searchTextFieldPlaceholderLabel": "সন্ধান কৰক", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb index 36b8ebb3f5aae..4b949456fb8bc 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex/$tabCount", "modalBarrierDismissLabel": "İmtina edin", "searchTextFieldPlaceholderLabel": "Axtarın", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb index 2ac08c1cf5289..2cad6127ace52 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Укладка $tabIndex з $tabCount", "modalBarrierDismissLabel": "Адхіліць", "searchTextFieldPlaceholderLabel": "Пошук", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb index 70dbfb2554b22..6841210327718 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Раздел $tabIndex от $tabCount", "modalBarrierDismissLabel": "Отхвърляне", "searchTextFieldPlaceholderLabel": "Търсене", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb index a69f8b2575a86..b29431eb359a4 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount-এর মধ্যে $tabIndex নম্বর ট্যাব", "modalBarrierDismissLabel": "খারিজ করুন", "searchTextFieldPlaceholderLabel": "সার্চ করুন", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb index 5a0039f51e95c..96b76cc3c60a1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb @@ -27,5 +27,6 @@ "tabSemanticsLabel": "Kartica $tabIndex od $tabCount", "modalBarrierDismissLabel": "Odbaci", "searchTextFieldPlaceholderLabel": "Pretraživanje", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb index 9f0fa56d2d6e1..81a0aa8e00478 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Pestanya $tabIndex de $tabCount", "modalBarrierDismissLabel": "Ignora", "searchTextFieldPlaceholderLabel": "Cerca", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb index bf8c3c0efdf5b..d243990e6e54f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Karta $tabIndex z $tabCount", "modalBarrierDismissLabel": "Zavřít", "searchTextFieldPlaceholderLabel": "Hledat", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb index 4ca5372dbe5ee..cfaae3d864671 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb @@ -42,5 +42,6 @@ "selectAllButtonLabel": "Dewis y Cyfan", "searchTextFieldPlaceholderLabel": "Chwilio", "modalBarrierDismissLabel": "Diystyru", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb index c98e5d763c170..295f08cac4ac0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Fane $tabIndex af $tabCount", "modalBarrierDismissLabel": "Afvis", "searchTextFieldPlaceholderLabel": "Søg", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb index df870f03a041b..72ce2888964b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex von $tabCount", "modalBarrierDismissLabel": "Schließen", "searchTextFieldPlaceholderLabel": "Suche", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb index 8020296f5b885..bdc52dad8b193 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Καρτέλα $tabIndex από $tabCount", "modalBarrierDismissLabel": "Παράβλεψη", "searchTextFieldPlaceholderLabel": "Αναζήτηση", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb index 2c003f7d5b415..716a4efd1a5b0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb @@ -178,5 +178,10 @@ "modalBarrierDismissLabel": "Dismiss", "@modalBarrierDismissLabel": { "description": "Label read out by accessibility tools (VoiceOver) for a modal barrier to indicate that a tap dismisses the barrier. A modal barrier can, for example, be found behind an alert or popup to block user interaction with elements behind it." + }, + + "menuDismissLabel": "Dismiss menu", + "@menuDismissLabel": { + "description": "Label read out by accessibility tools (TalkBack or VoiceOver) for the area around a menu to indicate that a tap dismisses the menu." } } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb index fbbcdf4e484c0..03d833ddebeb3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "modalBarrierDismissLabel": "Cerrar", "searchTextFieldPlaceholderLabel": "Buscar", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb index b584e67feae57..f8a35ae34ec5d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabIndex. vaheleht $tabCount-st", "modalBarrierDismissLabel": "Loobu", "searchTextFieldPlaceholderLabel": "Otsige", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb index d1882a4259d4e..ea93034f1093f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabIndex/$tabCount fitxa", "modalBarrierDismissLabel": "Baztertu", "searchTextFieldPlaceholderLabel": "Bilatu", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb index 63cd8734e083e..aee3c9bd86830 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "برگه $tabIndex از $tabCount", "modalBarrierDismissLabel": "نپذیرفتن", "searchTextFieldPlaceholderLabel": "جستجو", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb index f69aaa54ce035..ff85e706ce315 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Välilehti $tabIndex kautta $tabCount", "modalBarrierDismissLabel": "Ohita", "searchTextFieldPlaceholderLabel": "Hae", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb index 89396f80a54f4..3946ce990464d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex ng $tabCount", "modalBarrierDismissLabel": "I-dismiss", "searchTextFieldPlaceholderLabel": "Hanapin", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb index 069b9a19d3c66..f3b5ac58f196d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Onglet $tabIndex sur $tabCount", "modalBarrierDismissLabel": "Ignorer", "searchTextFieldPlaceholderLabel": "Rechercher", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb index 4acd2457606cb..9a454cdc5877c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Pestana $tabIndex de $tabCount", "modalBarrierDismissLabel": "Ignorar", "searchTextFieldPlaceholderLabel": "Fai unha busca", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb index df870f03a041b..72ce2888964b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex von $tabCount", "modalBarrierDismissLabel": "Schließen", "searchTextFieldPlaceholderLabel": "Suche", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb index c2b0e8e9a0f79..f29d316ec11b2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCountમાંથી $tabIndex ટૅબ", "modalBarrierDismissLabel": "છોડી દો", "searchTextFieldPlaceholderLabel": "શોધો", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb index 7671ac15dcf25..83cb32cdbbf5b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "כרטיסייה $tabIndex מתוך $tabCount", "modalBarrierDismissLabel": "סגירה", "searchTextFieldPlaceholderLabel": "חיפוש", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb index 4dafff61120c6..a412f37607a85 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount का टैब $tabIndex", "modalBarrierDismissLabel": "खारिज करें", "searchTextFieldPlaceholderLabel": "खोजें", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb index 3af6a49fa8ccc..b05fd416210ff 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb @@ -27,5 +27,6 @@ "tabSemanticsLabel": "Kartica $tabIndex od $tabCount", "modalBarrierDismissLabel": "Odbaci", "searchTextFieldPlaceholderLabel": "Pretraživanje", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb index 3f6c346e50d69..bfabfb5297c20 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount/$tabIndex. lap", "modalBarrierDismissLabel": "Elvetés", "searchTextFieldPlaceholderLabel": "Keresés", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb index d381cd1dbaf28..886965d3512a1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Ներդիր $tabIndex՝ $tabCount-ից", "modalBarrierDismissLabel": "Փակել", "searchTextFieldPlaceholderLabel": "Որոնում", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb index 59e1f52852c78..97cd510b712c2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex dari $tabCount", "modalBarrierDismissLabel": "Tutup", "searchTextFieldPlaceholderLabel": "Telusuri", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb index f9278ad1972a4..e2a270959f508 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Flipi $tabIndex af $tabCount", "modalBarrierDismissLabel": "Hunsa", "searchTextFieldPlaceholderLabel": "Leit", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb index 0e81c55e059e1..1effc1a6a4274 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Scheda $tabIndex di $tabCount", "modalBarrierDismissLabel": "Ignora", "searchTextFieldPlaceholderLabel": "Cerca", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb index 4920f0f4a3905..4e015ce3bc360 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "タブ: $tabIndex/$tabCount", "modalBarrierDismissLabel": "閉じる", "searchTextFieldPlaceholderLabel": "検索", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb index 3859335ba1e24..012e7e6ccda3b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "ჩანართი $tabIndex / $tabCount-დან", "modalBarrierDismissLabel": "დახურვა", "searchTextFieldPlaceholderLabel": "ძიება", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb index bc86ed2dd7ba0..9cfac67781959 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Қойынды: $tabIndex/$tabCount", "modalBarrierDismissLabel": "Жабу", "searchTextFieldPlaceholderLabel": "Іздеу", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb index aa8dede381325..75f748456a27b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "ផ្ទាំងទី $tabIndex នៃ $tabCount", "modalBarrierDismissLabel": "ច្រាន​ចោល", "searchTextFieldPlaceholderLabel": "ស្វែងរក", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb index 2c1ed6b2451df..42e61640714bf 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb @@ -22,5 +22,6 @@ "modalBarrierDismissLabel": "\u0cb5\u0c9c\u0cbe\u0c97\u0cca\u0cb3\u0cbf\u0cb8\u0cbf", "tabSemanticsLabel": "\u0024\u0074\u0061\u0062\u0043\u006f\u0075\u006e\u0074\u0020\u0cb0\u0cb2\u0ccd\u0cb2\u0cbf\u0ca8\u0020\u0024\u0074\u0061\u0062\u0049\u006e\u0064\u0065\u0078\u0020\u0c9f\u0ccd\u0caf\u0cbe\u0cac\u0ccd", "searchTextFieldPlaceholderLabel": "\u0cb9\u0cc1\u0ca1\u0cc1\u0c95\u0cbf", - "noSpellCheckReplacementsLabel": "\u004e\u006f\u0020\u0052\u0065\u0070\u006c\u0061\u0063\u0065\u006d\u0065\u006e\u0074\u0073\u0020\u0046\u006f\u0075\u006e\u0064" + "noSpellCheckReplacementsLabel": "\u004e\u006f\u0020\u0052\u0065\u0070\u006c\u0061\u0063\u0065\u006d\u0065\u006e\u0074\u0073\u0020\u0046\u006f\u0075\u006e\u0064", + "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb index 626331524b117..ace3363484991 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "탭 $tabCount개 중 $tabIndex번째", "modalBarrierDismissLabel": "닫기", "searchTextFieldPlaceholderLabel": "검색", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb index 7b04435d3ac86..504bf52c57365 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount ичинен $tabIndex-өтмөк", "modalBarrierDismissLabel": "Жабуу", "searchTextFieldPlaceholderLabel": "Издөө", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb index 811661befc724..f34735251cfe1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "ແຖບທີ $tabIndex ຈາກທັງໝົດ $tabCount", "modalBarrierDismissLabel": "ປິດໄວ້", "searchTextFieldPlaceholderLabel": "ຊອກຫາ", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb index 99bc7283ef72a..1516e209e86a1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "$tabIndex skirtukas iš $tabCount", "modalBarrierDismissLabel": "Atsisakyti", "searchTextFieldPlaceholderLabel": "Paieška", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb index d9f56156de423..59c683fea8e3a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb @@ -27,5 +27,6 @@ "tabSemanticsLabel": "$tabIndex. cilne no $tabCount", "modalBarrierDismissLabel": "Nerādīt", "searchTextFieldPlaceholderLabel": "Meklēšana", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb index 33a7378629c92..425255ea7cf7a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Картичка $tabIndex од $tabCount", "modalBarrierDismissLabel": "Отфрли", "searchTextFieldPlaceholderLabel": "Пребарувајте", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb index a261c9b2ebe75..446a4f4242db1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount ടാബിൽ $tabIndex-ാമത്തേത്", "modalBarrierDismissLabel": "നിരസിക്കുക", "searchTextFieldPlaceholderLabel": "തിരയുക", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb index a3baf66808a77..e06bc778a4db6 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount-н $tabIndex-р таб", "modalBarrierDismissLabel": "Үл хэрэгсэх", "searchTextFieldPlaceholderLabel": "Хайх", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb index d013b9e4e24a4..35128260ff35f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount पैकी $tabIndex टॅब", "modalBarrierDismissLabel": "डिसमिस करा", "searchTextFieldPlaceholderLabel": "शोधा", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb index 395f0fdb55285..691435092c478 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex daripada $tabCount", "modalBarrierDismissLabel": "Tolak", "searchTextFieldPlaceholderLabel": "Cari", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb index 1c5dac39cce2e..fb56c0d12adb0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "တဘ် $tabCount ခုအနက် $tabIndex ခု", "modalBarrierDismissLabel": "ပယ်ရန်", "searchTextFieldPlaceholderLabel": "ရှာရန်", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb index 9e22158f08cf2..a392f965e259b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb @@ -22,5 +22,6 @@ "selectAllButtonLabel": "Velg alle", "modalBarrierDismissLabel": "Avvis", "searchTextFieldPlaceholderLabel": "Søk", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb index 1859d479bbaa2..939e892bd3b08 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount मध्ये $tabIndex ट्याब", "modalBarrierDismissLabel": "खारेज गर्नुहोस्", "searchTextFieldPlaceholderLabel": "खोज्नुहोस्", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb index 5aff5981ed8ce..723afd6234b21 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tabblad $tabIndex van $tabCount", "modalBarrierDismissLabel": "Sluiten", "searchTextFieldPlaceholderLabel": "Zoeken", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb index 9e22158f08cf2..a392f965e259b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb @@ -22,5 +22,6 @@ "selectAllButtonLabel": "Velg alle", "modalBarrierDismissLabel": "Avvis", "searchTextFieldPlaceholderLabel": "Søk", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb index 347043ad8d89b..aea767ba97421 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCountର $tabIndex ଟାବ୍", "modalBarrierDismissLabel": "ଖାରଜ କରନ୍ତୁ", "searchTextFieldPlaceholderLabel": "ସନ୍ଧାନ କରନ୍ତୁ", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb index c742ff52fb92b..0abfd5d27a591 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount ਵਿੱਚੋਂ $tabIndex ਟੈਬ", "modalBarrierDismissLabel": "ਖਾਰਜ ਕਰੋ", "searchTextFieldPlaceholderLabel": "ਖੋਜੋ", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb index 19aa5b8299845..8a5d3470bf0a7 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Karta $tabIndex z $tabCount", "modalBarrierDismissLabel": "Zamknij", "searchTextFieldPlaceholderLabel": "Szukaj", - "noSpellCheckReplacementsLabel": "Nie znaleziono zastąpień" + "noSpellCheckReplacementsLabel": "Nie znaleziono zastąpień", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb index 23bf41fc61338..0129b43f45173 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Guia $tabIndex de $tabCount", "modalBarrierDismissLabel": "Dispensar", "searchTextFieldPlaceholderLabel": "Pesquisar", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb index 3086731d34fa3..2a2260d95940c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb @@ -27,5 +27,6 @@ "tabSemanticsLabel": "Fila $tabIndex din $tabCount", "modalBarrierDismissLabel": "Închideți", "searchTextFieldPlaceholderLabel": "Căutați", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb index 31db898a91566..9da4b9b91585b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Вкладка $tabIndex из $tabCount", "modalBarrierDismissLabel": "Закрыть", "searchTextFieldPlaceholderLabel": "Поиск", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb index be2d85f0ccd8d..14c8cb01588d1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "ටැබ $tabCount න් $tabIndex", "modalBarrierDismissLabel": "ඉවත ලන්න", "searchTextFieldPlaceholderLabel": "සෙවීම", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb index a65dc24aa8766..45f209c585760 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Karta $tabIndex z $tabCount", "modalBarrierDismissLabel": "Odmietnuť", "searchTextFieldPlaceholderLabel": "Hľadať", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb index 48ddd51c66be4..7b84c38117c41 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Zavihek $tabIndex od $tabCount", "modalBarrierDismissLabel": "Opusti", "searchTextFieldPlaceholderLabel": "Iskanje", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb index c5f6f60d9acd4..f7012fedd4ea6 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Skeda $tabIndex nga $tabCount", "modalBarrierDismissLabel": "Hiq", "searchTextFieldPlaceholderLabel": "Kërko", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb index 1883096dfce51..c8013a5cdc71e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb @@ -27,5 +27,6 @@ "tabSemanticsLabel": "$tabIndex. картица од $tabCount", "modalBarrierDismissLabel": "Одбаци", "searchTextFieldPlaceholderLabel": "Претражите", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb index 8b6aa26ee1720..cc2a1c68d6040 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Flik $tabIndex av $tabCount", "modalBarrierDismissLabel": "Stäng", "searchTextFieldPlaceholderLabel": "Sök", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb index 76e7eaee96863..8d297653ca6f2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Kichupo cha $tabIndex kati ya $tabCount", "modalBarrierDismissLabel": "Ondoa", "searchTextFieldPlaceholderLabel": "Tafuta", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb index a1d7a1d808af9..a680ab68d364e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "தாவல் $tabIndex / $tabCount", "modalBarrierDismissLabel": "நிராகரிக்கும்", "searchTextFieldPlaceholderLabel": "தேடுக", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb index 80ce7032be3d6..360d0ac66555e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCountలో $tabIndexవ ట్యాబ్", "modalBarrierDismissLabel": "విస్మరించు", "searchTextFieldPlaceholderLabel": "సెర్చ్ చేయి", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb index f69e1a3483332..e573711075409 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "แท็บที่ $tabIndex จาก $tabCount", "modalBarrierDismissLabel": "ปิด", "searchTextFieldPlaceholderLabel": "ค้นหา", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb index 89396f80a54f4..3946ce990464d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Tab $tabIndex ng $tabCount", "modalBarrierDismissLabel": "I-dismiss", "searchTextFieldPlaceholderLabel": "Hanapin", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb index 0bad769433078..24ef72c1f5c8a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Sekme $tabIndex/$tabCount", "modalBarrierDismissLabel": "Kapat", "searchTextFieldPlaceholderLabel": "Ara", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb index c10dfff0a25c1..3c5a80503539b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb @@ -32,5 +32,6 @@ "tabSemanticsLabel": "Вкладка $tabIndex з $tabCount", "modalBarrierDismissLabel": "Закрити", "searchTextFieldPlaceholderLabel": "Шукайте", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb index 99561dbfe7968..d0d0027e216d9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount میں سے $tabIndex ٹیب", "modalBarrierDismissLabel": "برخاست کریں", "searchTextFieldPlaceholderLabel": "تلاش کریں", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb index 438689b045a8f..d64d15b6dd150 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "$tabCount varaqdan $tabIndex", "modalBarrierDismissLabel": "Yopish", "searchTextFieldPlaceholderLabel": "Qidiruv", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb index 0f7714ae31c03..4682ba9d5d5b0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Thẻ $tabIndex/$tabCount", "modalBarrierDismissLabel": "Bỏ qua", "searchTextFieldPlaceholderLabel": "Tìm kiếm", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb index e90433429d058..9ee7ce9442d4d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "第 $tabIndex 个标签,共 $tabCount 个", "modalBarrierDismissLabel": "关闭", "searchTextFieldPlaceholderLabel": "搜索", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb index 57dbb148fdc01..f4caee097c3b0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb @@ -22,5 +22,6 @@ "tabSemanticsLabel": "Ithebhu $tabIndex kwangu-$tabCount", "modalBarrierDismissLabel": "Cashisa", "searchTextFieldPlaceholderLabel": "Sesha", - "noSpellCheckReplacementsLabel": "No Replacements Found" + "noSpellCheckReplacementsLabel": "No Replacements Found", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index bb53ac311049c..e7584c9398ce9 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -91,6 +91,9 @@ class CupertinoLocalizationAf extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Maak toe'; @@ -241,6 +244,9 @@ class CupertinoLocalizationAm extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'አሰናብት'; @@ -391,6 +397,9 @@ class CupertinoLocalizationAr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => r'$minute دقيقة​'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'رفض'; @@ -541,6 +550,9 @@ class CupertinoLocalizationAs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'অগ্ৰাহ্য কৰক'; @@ -691,6 +703,9 @@ class CupertinoLocalizationAz extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'İmtina edin'; @@ -841,6 +856,9 @@ class CupertinoLocalizationBe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Адхіліць'; @@ -991,6 +1009,9 @@ class CupertinoLocalizationBg extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Отхвърляне'; @@ -1141,6 +1162,9 @@ class CupertinoLocalizationBn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'খারিজ করুন'; @@ -1291,6 +1315,9 @@ class CupertinoLocalizationBs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -1441,6 +1468,9 @@ class CupertinoLocalizationCa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignora'; @@ -1591,6 +1621,9 @@ class CupertinoLocalizationCs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Zavřít'; @@ -1741,6 +1774,9 @@ class CupertinoLocalizationCy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => r'$minute munud'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Diystyru'; @@ -1891,6 +1927,9 @@ class CupertinoLocalizationDa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Afvis'; @@ -2041,6 +2080,9 @@ class CupertinoLocalizationDe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Schließen'; @@ -2212,6 +2254,9 @@ class CupertinoLocalizationEl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Παράβλεψη'; @@ -2362,6 +2407,9 @@ class CupertinoLocalizationEn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Dismiss'; @@ -2704,6 +2752,9 @@ class CupertinoLocalizationEs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Cerrar'; @@ -3514,6 +3565,9 @@ class CupertinoLocalizationEt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Loobu'; @@ -3664,6 +3718,9 @@ class CupertinoLocalizationEu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Baztertu'; @@ -3814,6 +3871,9 @@ class CupertinoLocalizationFa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'نپذیرفتن'; @@ -3964,6 +4024,9 @@ class CupertinoLocalizationFi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ohita'; @@ -4114,6 +4177,9 @@ class CupertinoLocalizationFil extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'I-dismiss'; @@ -4264,6 +4330,9 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignorer'; @@ -4456,6 +4525,9 @@ class CupertinoLocalizationGl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignorar'; @@ -4606,6 +4678,9 @@ class CupertinoLocalizationGsw extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Schließen'; @@ -4756,6 +4831,9 @@ class CupertinoLocalizationGu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'છોડી દો'; @@ -4906,6 +4984,9 @@ class CupertinoLocalizationHe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'סגירה'; @@ -5056,6 +5137,9 @@ class CupertinoLocalizationHi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'खारिज करें'; @@ -5206,6 +5290,9 @@ class CupertinoLocalizationHr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -5356,6 +5443,9 @@ class CupertinoLocalizationHu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Elvetés'; @@ -5506,6 +5596,9 @@ class CupertinoLocalizationHy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Փակել'; @@ -5656,6 +5749,9 @@ class CupertinoLocalizationId extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Tutup'; @@ -5806,6 +5902,9 @@ class CupertinoLocalizationIs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Hunsa'; @@ -5956,6 +6055,9 @@ class CupertinoLocalizationIt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignora'; @@ -6106,6 +6208,9 @@ class CupertinoLocalizationJa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '閉じる'; @@ -6256,6 +6361,9 @@ class CupertinoLocalizationKa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'დახურვა'; @@ -6406,6 +6514,9 @@ class CupertinoLocalizationKk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Жабу'; @@ -6556,6 +6667,9 @@ class CupertinoLocalizationKm extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ច្រាន​ចោល'; @@ -6706,6 +6820,9 @@ class CupertinoLocalizationKn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '\u{cb5}\u{c9c}\u{cbe}\u{c97}\u{cca}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; @@ -6856,6 +6973,9 @@ class CupertinoLocalizationKo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '닫기'; @@ -7006,6 +7126,9 @@ class CupertinoLocalizationKy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Жабуу'; @@ -7156,6 +7279,9 @@ class CupertinoLocalizationLo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ປິດໄວ້'; @@ -7306,6 +7432,9 @@ class CupertinoLocalizationLt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Atsisakyti'; @@ -7456,6 +7585,9 @@ class CupertinoLocalizationLv extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => r'$minute minūtes'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Nerādīt'; @@ -7606,6 +7738,9 @@ class CupertinoLocalizationMk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Отфрли'; @@ -7756,6 +7891,9 @@ class CupertinoLocalizationMl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'നിരസിക്കുക'; @@ -7906,6 +8044,9 @@ class CupertinoLocalizationMn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Үл хэрэгсэх'; @@ -8056,6 +8197,9 @@ class CupertinoLocalizationMr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'डिसमिस करा'; @@ -8206,6 +8350,9 @@ class CupertinoLocalizationMs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Tolak'; @@ -8356,6 +8503,9 @@ class CupertinoLocalizationMy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ပယ်ရန်'; @@ -8506,6 +8656,9 @@ class CupertinoLocalizationNb extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Avvis'; @@ -8656,6 +8809,9 @@ class CupertinoLocalizationNe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'खारेज गर्नुहोस्'; @@ -8806,6 +8962,9 @@ class CupertinoLocalizationNl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Sluiten'; @@ -8956,6 +9115,9 @@ class CupertinoLocalizationNo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Avvis'; @@ -9106,6 +9268,9 @@ class CupertinoLocalizationOr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ଖାରଜ କରନ୍ତୁ'; @@ -9256,6 +9421,9 @@ class CupertinoLocalizationPa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ਖਾਰਜ ਕਰੋ'; @@ -9406,6 +9574,9 @@ class CupertinoLocalizationPl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Zamknij'; @@ -9556,6 +9727,9 @@ class CupertinoLocalizationPt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Dispensar'; @@ -9742,6 +9916,9 @@ class CupertinoLocalizationRo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Închideți'; @@ -9892,6 +10069,9 @@ class CupertinoLocalizationRu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Закрыть'; @@ -10042,6 +10222,9 @@ class CupertinoLocalizationSi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ඉවත ලන්න'; @@ -10192,6 +10375,9 @@ class CupertinoLocalizationSk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Odmietnuť'; @@ -10342,6 +10528,9 @@ class CupertinoLocalizationSl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Opusti'; @@ -10492,6 +10681,9 @@ class CupertinoLocalizationSq extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Hiq'; @@ -10642,6 +10834,9 @@ class CupertinoLocalizationSr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Одбаци'; @@ -10906,6 +11101,9 @@ class CupertinoLocalizationSv extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Stäng'; @@ -11056,6 +11254,9 @@ class CupertinoLocalizationSw extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ondoa'; @@ -11206,6 +11407,9 @@ class CupertinoLocalizationTa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'நிராகரிக்கும்'; @@ -11356,6 +11560,9 @@ class CupertinoLocalizationTe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'విస్మరించు'; @@ -11506,6 +11713,9 @@ class CupertinoLocalizationTh extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ปิด'; @@ -11656,6 +11866,9 @@ class CupertinoLocalizationTl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'I-dismiss'; @@ -11806,6 +12019,9 @@ class CupertinoLocalizationTr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Kapat'; @@ -11956,6 +12172,9 @@ class CupertinoLocalizationUk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Закрити'; @@ -12106,6 +12325,9 @@ class CupertinoLocalizationUr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'برخاست کریں'; @@ -12256,6 +12478,9 @@ class CupertinoLocalizationUz extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Yopish'; @@ -12406,6 +12631,9 @@ class CupertinoLocalizationVi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Bỏ qua'; @@ -12556,6 +12784,9 @@ class CupertinoLocalizationZh extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '关闭'; @@ -12853,6 +13084,9 @@ class CupertinoLocalizationZu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Cashisa'; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index 7d5d7e68a08e3..efff5a5f81e5a 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -332,6 +332,9 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Kieslysbalkkieslys'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Maak toe'; @@ -810,6 +813,9 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'የምናሌ አሞሌ ምናሌ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'አሰናብት'; @@ -1288,6 +1294,9 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'قائمة شريط القوائم'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'رفض'; @@ -1766,6 +1775,9 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'মেনু বাৰ মেনু'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'অগ্ৰাহ্য কৰক'; @@ -2244,6 +2256,9 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menyu paneli menyusu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'İmtina edin'; @@ -2722,6 +2737,9 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Меню "Панэль меню"'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Адхіліць'; @@ -3200,6 +3218,9 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Меню на лентата с менюта'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Отхвърляне'; @@ -3678,6 +3699,9 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'মেনু বার মেনু'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'খারিজ করুন'; @@ -4156,6 +4180,9 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Meni trake menija'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -4634,6 +4661,9 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menú de la barra de menú'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignora'; @@ -5112,6 +5142,9 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Nabídka na liště s nabídkou'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Zavřít'; @@ -5590,6 +5623,9 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Dewislen bar dewislen'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Diystyru'; @@ -6068,6 +6104,9 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menuen for menulinjen'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Afvis'; @@ -6546,6 +6585,9 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menü in der Menüleiste'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Schließen'; @@ -7088,6 +7130,9 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Μενού γραμμής μενού'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Παράβλεψη'; @@ -7566,6 +7611,9 @@ class MaterialLocalizationEn extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu bar menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Dismiss'; @@ -8778,6 +8826,9 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menú de la barra de menú'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Cerrar'; @@ -12639,6 +12690,9 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menüüriba menüü'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Loobu'; @@ -13117,6 +13171,9 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu-barraren menua'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Baztertu'; @@ -13595,6 +13652,9 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'منوی نوار منو'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'نپذیرفتن'; @@ -14073,6 +14133,9 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Valikkopalkki'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ohita'; @@ -14551,6 +14614,9 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu sa menu bar'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'I-dismiss'; @@ -15029,6 +15095,9 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu de la barre de menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignorer'; @@ -15649,6 +15718,9 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menú da barra de menú'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignorar'; @@ -16127,6 +16199,9 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menü in der Menüleiste'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Schließen'; @@ -16605,6 +16680,9 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'મેનૂ બાર મેનૂ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'છોડી દો'; @@ -17083,6 +17161,9 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'תפריט בסרגל התפריטים'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'סגירה'; @@ -17561,6 +17642,9 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'मेन्यू बार का मेन्यू'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'खारिज करें'; @@ -18039,6 +18123,9 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Izbornik trake izbornika'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -18517,6 +18604,9 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menüsor menüje'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Elvetés'; @@ -18995,6 +19085,9 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Ընտրացանկի գոտու ընտրացանկ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Փակել'; @@ -19473,6 +19566,9 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu panel menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Tutup'; @@ -19951,6 +20047,9 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Valmyndarstika'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Hunsa'; @@ -20429,6 +20528,9 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu barra dei menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ignora'; @@ -20907,6 +21009,9 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'メニューバーのメニュー'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '閉じる'; @@ -21385,6 +21490,9 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'მენიუს ზოლის მენიუ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'დახურვა'; @@ -21863,6 +21971,9 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Мәзір жолағының мәзірі'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Жабу'; @@ -22341,6 +22452,9 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'ម៉ឺនុយរបារម៉ឺនុយ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ច្រាន​ចោល'; @@ -22819,6 +22933,9 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => '\u{cae}\u{cc6}\u{ca8}\u{cc1}\u{20}\u{cac}\u{cbe}\u{cb0}\u{ccd}\u{200c}\u{20}\u{cae}\u{cc6}\u{ca8}\u{cc1}'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '\u{cb5}\u{c9c}\u{cbe}\u{c97}\u{cca}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; @@ -23297,6 +23414,9 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => '메뉴 바 메뉴'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '닫기'; @@ -23775,6 +23895,9 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Меню тилкеси менюсу'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Жабуу'; @@ -24253,6 +24376,9 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'ເມນູແຖບເມນູ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ປິດໄວ້'; @@ -24731,6 +24857,9 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Meniu juostos meniu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Atsisakyti'; @@ -25209,6 +25338,9 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Izvēļņu joslas izvēlne'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Nerādīt'; @@ -25687,6 +25819,9 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Мени на лентата со мени'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Отфрли'; @@ -26165,6 +26300,9 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'മെനു ബാർ മെനു'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'നിരസിക്കുക'; @@ -26643,6 +26781,9 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Цэсний талбарын цэс'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Үл хэрэгсэх'; @@ -27121,6 +27262,9 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'मेनू बार मेनू'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'डिसमिस करा'; @@ -27599,6 +27743,9 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu bar menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Tolak'; @@ -28077,6 +28224,9 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'မီနူးဘား မီနူး'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ပယ်ရန်'; @@ -28555,6 +28705,9 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Meny med menylinje'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Avvis'; @@ -29033,6 +29186,9 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => '"मेनु बार" मेनु'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'खारेज गर्नुहोस्'; @@ -29511,6 +29667,9 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu van menubalk'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Sluiten'; @@ -29989,6 +30148,9 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Meny med menylinje'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Avvis'; @@ -30467,6 +30629,9 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'ମେନୁ ବାର ମେନୁ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ଖାରଜ କରନ୍ତୁ'; @@ -30945,6 +31110,9 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'ਮੀਨੂ ਬਾਰ ਮੀਨੂ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ਖਾਰਜ ਕਰੋ'; @@ -31423,6 +31591,9 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Pasek menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Zamknij'; @@ -31901,6 +32072,9 @@ class MaterialLocalizationPs extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu bar menu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'رد کړه'; @@ -32379,6 +32553,9 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu da barra de menus'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Dispensar'; @@ -33008,6 +33185,9 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Bară de meniu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Închideți'; @@ -33486,6 +33666,9 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Строка меню'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Закрыть'; @@ -33964,6 +34147,9 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'මෙනු තීරු මෙනුව'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ඉවත ලන්න'; @@ -34442,6 +34628,9 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Ponuka panela s ponukami'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Odmietnuť'; @@ -34920,6 +35109,9 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Meni menijske vrstice'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Opusti'; @@ -35398,6 +35590,9 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menyja e shiritit të menysë'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Hiq'; @@ -35876,6 +36071,9 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Мени трака менија'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Одбаци'; @@ -36668,6 +36866,9 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menyrad'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Stäng'; @@ -37146,6 +37347,9 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menyu ya upau wa menyu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Ondoa'; @@ -37624,6 +37828,9 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'மெனு பட்டியின் மெனு'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'நிராகரிக்கும்'; @@ -38102,6 +38309,9 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'మెనూ బార్ మెనూ'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'విస్మరించు'; @@ -38580,6 +38790,9 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'เมนูในแถบเมนู'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'ปิด'; @@ -39058,6 +39271,9 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menu sa menu bar'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'I-dismiss'; @@ -39536,6 +39752,9 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menü çubuğu menüsü'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Kapat'; @@ -40014,6 +40233,9 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Панель меню'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Закрити'; @@ -40492,6 +40714,9 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'مینیو بار کا مینیو'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'برخاست کریں'; @@ -40970,6 +41195,9 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Menyu paneli'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Yopish'; @@ -41448,6 +41676,9 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Trình đơn của thanh trình đơn'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Bỏ qua'; @@ -41926,6 +42157,9 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => '菜单栏的菜单'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => '关闭'; @@ -42897,6 +43131,9 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { @override String get menuBarMenuLabel => 'Imenyu yebha yemenyu'; + @override + String get menuDismissLabel => 'Dismiss menu'; + @override String get modalBarrierDismissLabel => 'Cashisa'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_af.arb b/packages/flutter_localizations/lib/src/l10n/material_af.arb index c593ac8c8228e..4ecc36d39d470 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_af.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_am.arb b/packages/flutter_localizations/lib/src/l10n/material_am.arb index 3538c87c0f2b5..695ebefec6a07 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_am.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ar.arb b/packages/flutter_localizations/lib/src/l10n/material_ar.arb index 73f9d2b1181a6..ecd809e069b4c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ar.arb @@ -151,5 +151,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_as.arb b/packages/flutter_localizations/lib/src/l10n/material_as.arb index f358a744115e2..39471cbf3d28f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_as.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_az.arb b/packages/flutter_localizations/lib/src/l10n/material_az.arb index ea0736f368180..6067f4e1da6cd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_az.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_be.arb b/packages/flutter_localizations/lib/src/l10n/material_be.arb index d58cb145704de..8f46fc18e887a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_be.arb @@ -146,5 +146,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bg.arb b/packages/flutter_localizations/lib/src/l10n/material_bg.arb index fb6074c48d6de..e5ad3fc8e3b53 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bg.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bn.arb b/packages/flutter_localizations/lib/src/l10n/material_bn.arb index 03587bc348245..8bbc98ddfe74a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bn.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bs.arb b/packages/flutter_localizations/lib/src/l10n/material_bs.arb index bbe68a1dafc4a..d4f65852b946c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bs.arb @@ -144,5 +144,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ca.arb b/packages/flutter_localizations/lib/src/l10n/material_ca.arb index aecdb082777ea..ca15e6cad3ca4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ca.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cs.arb b/packages/flutter_localizations/lib/src/l10n/material_cs.arb index 1e17c2e1c9a5b..77a8a955ca4be 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cs.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cy.arb b/packages/flutter_localizations/lib/src/l10n/material_cy.arb index 1cf88afa69ea4..d91a63187f4f2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cy.arb @@ -151,5 +151,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "scanTextButtonLabel": "Scan text" + "scanTextButtonLabel": "Scan text", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_da.arb b/packages/flutter_localizations/lib/src/l10n/material_da.arb index a2dc08864ff7e..cfab5e7b0e184 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_da.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_de.arb b/packages/flutter_localizations/lib/src/l10n/material_de.arb index 9a5fbefb09190..b70005ba37d4f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_de.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_el.arb b/packages/flutter_localizations/lib/src/l10n/material_el.arb index e9f3408a997ce..903ff89327cbf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_el.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb index dd9746dcd5956..511cc30c4ed1b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb @@ -242,6 +242,11 @@ "description": "Label read out by accessibility tools (TalkBack or VoiceOver) for a modal barrier to indicate that a tap dismisses the barrier. A modal barrier can for example be found behind a alert or popup to block user interaction with elements behind it." }, + "menuDismissLabel": "Dismiss menu", + "@menuDismissLabel": { + "description": "Label read out by accessibility tools (TalkBack or VoiceOver) for the area around a menu to indicate that a tap dismisses the menu." + }, + "dateSeparator": "/", "@dateSeparator": { "description": "The character string used to separate the parts of a compact date format. For example 'mm/dd/yyyy' has a separator of '/'." diff --git a/packages/flutter_localizations/lib/src/l10n/material_es.arb b/packages/flutter_localizations/lib/src/l10n/material_es.arb index 59eed0c4324de..f4d7fd2d4baae 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_et.arb b/packages/flutter_localizations/lib/src/l10n/material_et.arb index 97fb40a2a7ede..b7751aa65328a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_et.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_eu.arb b/packages/flutter_localizations/lib/src/l10n/material_eu.arb index 8e299211b2f8c..cafff7255f7fc 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_eu.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fa.arb b/packages/flutter_localizations/lib/src/l10n/material_fa.arb index 20c7fbcfd9937..d4dd6e5b06bab 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fa.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index ce9d501370e9b..649b1671d3359 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fil.arb b/packages/flutter_localizations/lib/src/l10n/material_fil.arb index fbf38a18b99a2..96c45b3285820 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fil.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr.arb b/packages/flutter_localizations/lib/src/l10n/material_fr.arb index accbb33f232e9..8d3795231c9d7 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fr.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gl.arb b/packages/flutter_localizations/lib/src/l10n/material_gl.arb index 2557795963089..4383f4ddbb440 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gl.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb index 1d803e7b2ff91..15d7095df0dd5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gu.arb b/packages/flutter_localizations/lib/src/l10n/material_gu.arb index 371690c084b97..cfcf9594584dd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gu.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_he.arb b/packages/flutter_localizations/lib/src/l10n/material_he.arb index c1f33f5bb61f2..63ad41324daca 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_he.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hi.arb b/packages/flutter_localizations/lib/src/l10n/material_hi.arb index 78fe9a1d30228..3104031e4b117 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hi.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hr.arb b/packages/flutter_localizations/lib/src/l10n/material_hr.arb index 7535eb9e70ed8..005ccce3578b2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hr.arb @@ -144,5 +144,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hu.arb b/packages/flutter_localizations/lib/src/l10n/material_hu.arb index 88c57ae8b3c57..798524a354918 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hu.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hy.arb b/packages/flutter_localizations/lib/src/l10n/material_hy.arb index 02d1ab87b93ad..030323d659e24 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hy.arb @@ -146,5 +146,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_id.arb b/packages/flutter_localizations/lib/src/l10n/material_id.arb index 131bface74bec..85b954c03d225 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_id.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_is.arb b/packages/flutter_localizations/lib/src/l10n/material_is.arb index 30078d757f967..595971efd8a40 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_is.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_it.arb b/packages/flutter_localizations/lib/src/l10n/material_it.arb index 1f35104a9d98d..605172effe21c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_it.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ja.arb b/packages/flutter_localizations/lib/src/l10n/material_ja.arb index 58e3c810ba73b..6fc3e26eebcbc 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ja.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ka.arb b/packages/flutter_localizations/lib/src/l10n/material_ka.arb index b221c94792889..febdb70b8fc4c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ka.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kk.arb b/packages/flutter_localizations/lib/src/l10n/material_kk.arb index a318f00a48881..055ea2b636fe3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kk.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_km.arb b/packages/flutter_localizations/lib/src/l10n/material_km.arb index 9c2a624991e25..a34049213d67b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_km.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kn.arb b/packages/flutter_localizations/lib/src/l10n/material_kn.arb index 624941d984c0d..cda53f81e57d4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kn.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "\u0043\u006f\u006c\u006c\u0061\u0070\u0073\u0065", "expansionTileCollapsedTapHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0020\u0066\u006f\u0072\u0020\u006d\u006f\u0072\u0065\u0020\u0064\u0065\u0074\u0061\u0069\u006c\u0073", "expandedHint": "\u0043\u006f\u006c\u006c\u0061\u0070\u0073\u0065\u0064", - "collapsedHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0065\u0064" + "collapsedHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0065\u0064", + "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ko.arb b/packages/flutter_localizations/lib/src/l10n/material_ko.arb index 4b2eeee024c9a..c022f36f9316a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ko.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ky.arb b/packages/flutter_localizations/lib/src/l10n/material_ky.arb index 568e08e294238..6b02039d9d1bd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ky.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lo.arb b/packages/flutter_localizations/lib/src/l10n/material_lo.arb index 2b02046d148c5..1007feaebe2eb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lo.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lt.arb b/packages/flutter_localizations/lib/src/l10n/material_lt.arb index 62d77cb56ac26..f0e1503adc1fe 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lt.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lv.arb b/packages/flutter_localizations/lib/src/l10n/material_lv.arb index 3c84e58cea342..f61b4dab93529 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lv.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mk.arb b/packages/flutter_localizations/lib/src/l10n/material_mk.arb index 99586cbc339ed..47e2ffc5b466f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mk.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ml.arb b/packages/flutter_localizations/lib/src/l10n/material_ml.arb index 28896359cc47d..1af3e2454f20f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ml.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mn.arb b/packages/flutter_localizations/lib/src/l10n/material_mn.arb index a960b7b141edb..7fe558525649a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mn.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mr.arb b/packages/flutter_localizations/lib/src/l10n/material_mr.arb index ccc1ab9019bd7..21ceeee708d77 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mr.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ms.arb b/packages/flutter_localizations/lib/src/l10n/material_ms.arb index 2efd94a47bbd9..c8ef18c21455b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ms.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_my.arb b/packages/flutter_localizations/lib/src/l10n/material_my.arb index 06cde1220d69b..969b66435df97 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_my.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nb.arb b/packages/flutter_localizations/lib/src/l10n/material_nb.arb index 0a4810524f235..27ab7e9e93212 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nb.arb @@ -139,5 +139,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ne.arb b/packages/flutter_localizations/lib/src/l10n/material_ne.arb index 7c53636103d85..3721981ee1b6d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ne.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nl.arb b/packages/flutter_localizations/lib/src/l10n/material_nl.arb index 16d0bceebf9e0..04e4774d90327 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nl.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_no.arb b/packages/flutter_localizations/lib/src/l10n/material_no.arb index a311a70b250c2..2cceaff489886 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_no.arb @@ -139,5 +139,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_or.arb b/packages/flutter_localizations/lib/src/l10n/material_or.arb index 299d57c067bcf..e0af6322b0ec0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_or.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pa.arb b/packages/flutter_localizations/lib/src/l10n/material_pa.arb index d48c4611a6da6..7ec370e66b538 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pa.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pl.arb b/packages/flutter_localizations/lib/src/l10n/material_pl.arb index 47695b170de7e..114ce4e7b2b6c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pl.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ps.arb b/packages/flutter_localizations/lib/src/l10n/material_ps.arb index 042b8055dbc7f..6f51f1fdb57e8 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ps.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ps.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb index c671af7dab373..a85ca3885a760 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb @@ -143,5 +143,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ro.arb b/packages/flutter_localizations/lib/src/l10n/material_ro.arb index fcd7130a5d472..6731bb241c094 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ro.arb @@ -145,5 +145,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ru.arb b/packages/flutter_localizations/lib/src/l10n/material_ru.arb index 9b81a9cc66bc8..e682daadbfa64 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ru.arb @@ -148,5 +148,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_si.arb b/packages/flutter_localizations/lib/src/l10n/material_si.arb index 4ac3ecfe99298..b71bf1d94f7a0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_si.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sk.arb b/packages/flutter_localizations/lib/src/l10n/material_sk.arb index a85cfaf3b0936..bcbea02c2288d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sk.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sl.arb b/packages/flutter_localizations/lib/src/l10n/material_sl.arb index 7fe2795860d4b..059e5033a9c59 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sl.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sq.arb b/packages/flutter_localizations/lib/src/l10n/material_sq.arb index 9db947b7c5025..c5c93fe2d931d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sq.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sr.arb b/packages/flutter_localizations/lib/src/l10n/material_sr.arb index 05865175bdb61..f370d680f954b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sr.arb @@ -144,5 +144,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sv.arb b/packages/flutter_localizations/lib/src/l10n/material_sv.arb index 5e4573804a750..5bfd5156aa57c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sv.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sw.arb b/packages/flutter_localizations/lib/src/l10n/material_sw.arb index b31a119b598b0..79eb4868c0db7 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sw.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ta.arb b/packages/flutter_localizations/lib/src/l10n/material_ta.arb index f6fd8c3b3b6cc..25e586e735ab0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ta.arb @@ -142,5 +142,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_te.arb b/packages/flutter_localizations/lib/src/l10n/material_te.arb index 4220e89b98015..aecf93193d730 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_te.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_th.arb b/packages/flutter_localizations/lib/src/l10n/material_th.arb index a0180b3b9b372..7fa35000392be 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_th.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tl.arb b/packages/flutter_localizations/lib/src/l10n/material_tl.arb index fbf38a18b99a2..96c45b3285820 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tl.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tr.arb b/packages/flutter_localizations/lib/src/l10n/material_tr.arb index b91d74d61651f..3e3a129722319 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tr.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uk.arb b/packages/flutter_localizations/lib/src/l10n/material_uk.arb index fe9dcddaaebf4..ef73b586a8ad2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uk.arb @@ -147,5 +147,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ur.arb b/packages/flutter_localizations/lib/src/l10n/material_ur.arb index c11abd3d38b6b..fa092aefce639 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ur.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uz.arb b/packages/flutter_localizations/lib/src/l10n/material_uz.arb index f773009cc91f2..cb62c2a556a6f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uz.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_vi.arb b/packages/flutter_localizations/lib/src/l10n/material_vi.arb index 8f57237cc0f32..a33f5cbb8aeae 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_vi.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh.arb b/packages/flutter_localizations/lib/src/l10n/material_zh.arb index 66a28a60bc1af..aa48e08adc600 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh.arb @@ -141,5 +141,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zu.arb b/packages/flutter_localizations/lib/src/l10n/material_zu.arb index aae990ba20d7a..ea76791c9fa89 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zu.arb @@ -140,5 +140,6 @@ "expansionTileExpandedTapHint": "Collapse", "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", - "collapsedHint": "Expanded" + "collapsedHint": "Expanded", + "menuDismissLabel": "Dismiss menu" } From 910e87eb739e5f8f018b730bea7d8d6ccd5cc5cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 22:51:25 +0000 Subject: [PATCH 0263/1547] Bump github/codeql-action from 2.20.4 to 2.21.0 (#130941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.20.4 to 2.21.0.
Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

[UNRELEASED]

No user facing changes.

2.21.0 - 19 Jul 2023

  • CodeQL Action now requires CodeQL CLI 2.9.4 or later. For more information, see the corresponding changelog entry for CodeQL Action version 2.20.4. #1724

2.20.4 - 14 Jul 2023

  • This is the last release of the Action that supports CodeQL CLI versions 2.8.5 to 2.9.3. These versions of the CodeQL CLI were deprecated on June 20, 2023 alongside GitHub Enterprise Server 3.5 and will not be supported by the next release of the CodeQL Action (2.21.0).
    • If you are using one of these versions, please update to CodeQL CLI version 2.9.4 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
    • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.8.5 and 2.9.3, you can replace 'github/codeql-action/@​v2' by 'github/codeql-action/@​v2.20.4' in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
  • We are rolling out a feature in July 2023 that will slightly reduce the default amount of RAM used for query execution, in proportion to the runner's total memory. This will help to avoid out-of-memory failures on larger runners. #1760
  • Update default CodeQL bundle version to 2.14.0. #1762

2.20.3 - 06 Jul 2023

  • Update default CodeQL bundle version to 2.13.5. #1743

2.20.2 - 03 Jul 2023

No user facing changes.

2.20.1 - 21 Jun 2023

  • Update default CodeQL bundle version to 2.13.4. #1721
  • Experimental: add a new resolve-environment action which attempts to infer a configuration for the build environment that is required to build a given project. Do not use this in production as it is part of an internal experiment and subject to change at any time.

2.20.0 - 13 Jun 2023

  • Bump the version of the Action to 2.20.0. This ensures that users who received a Dependabot upgrade to cdcdbb5, which was mistakenly marked as Action version 2.13.4, continue to receive updates to the CodeQL Action. Full details in #1729

2.3.6 - 01 Jun 2023

  • Update default CodeQL bundle version to 2.13.3. #1698

2.3.5 - 25 May 2023

  • Allow invalid URIs to be used as values to artifactLocation.uri properties. This reverses a change from #1668 that inadvertently led to stricter validation of some URI values. #1705
  • Gracefully handle invalid URIs when fingerprinting. #1694

2.3.4 - 24 May 2023

  • Updated the SARIF 2.1.0 JSON schema file to the latest from oasis-tcs/sarif-spec. #1668
  • We are rolling out a feature in May 2023 that will disable Python dependency installation for new users of the CodeQL Action. This improves the speed of analysis while having only a very minor impact on results. #1676

... (truncated)

Commits
  • 1813ca7 Merge pull request #1791 from github/update-v2.21.0-6ae46f7a9
  • 6843540 Update changelog for v2.21.0
  • 6ae46f7 Merge pull request #1790 from github/henrymercer/aborted-user-error
  • 0cae69e Report user errors in the abort stage appropriately
  • d2ed0a0 Merge pull request #1786 from github/dependabot/npm_and_yarn/npm-0a410f26d2
  • 651d091 Merge pull request #1788 from github/henrymercer/fix-feature-flag-usage
  • e0f0892 Add tests for new analysis summary feature flag
  • 27d3b2f Fix scaling reserved RAM feature flag naming
  • da4e0a0 Fix CodeQL version checks
  • e266801 Update checked-in dependencies
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.20.4&new-version=2.21.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index abdcaa9ce7f12..0e3a7abbf06f8 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@489225d82a57396c6f426a40e66d461b16b3461d + uses: github/codeql-action/upload-sarif@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 with: sarif_file: results.sarif From 10f464895d8941c541f0ad00843dbbdef965f4f1 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 19 Jul 2023 15:53:54 -0700 Subject: [PATCH 0264/1547] Add docs to Route.maintainState (#130638) Fixes https://github.com/flutter/flutter/issues/44836 --- packages/flutter/lib/src/widgets/routes.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index ad919c96dc697..441486e5ed676 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -1432,11 +1432,20 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute Date: Wed, 19 Jul 2023 18:53:57 -0400 Subject: [PATCH 0265/1547] Roll Flutter Engine from 0af285219809 to 938140a974b0 (1 revision) (#130943) https://github.com/flutter/engine/compare/0af285219809...938140a974b0 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 30d458aea0b9 to b1d6eab1f590 (2 revisions) (flutter/engine#43826) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 14d1a8a3fce06..a5b29812a4d83 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0af285219809931e72bc536dff1b1bcf8b7420a7 +938140a974b0156451700fdda0d7e7799dfc938f From 1c569e9c8dd6f6b707b761f52166aedcf091eb5c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 19:42:30 -0400 Subject: [PATCH 0266/1547] Roll Flutter Engine from 938140a974b0 to 7671e2f2a9fc (3 revisions) (#130948) https://github.com/flutter/engine/compare/938140a974b0...7671e2f2a9fc 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from b1d6eab1f590 to bf75ae2f6eec (2 revisions) (flutter/engine#43829) 2023-07-19 skia-flutter-autoroll@skia.org Roll ANGLE from 4dcaad2a894d to 4515b270772e (2 revisions) (flutter/engine#43830) 2023-07-19 737941+loic-sharma@users.noreply.github.com Add the 'affects: desktop' label to labeler.yml (flutter/engine#43827) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a5b29812a4d83..f73e25966af73 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -938140a974b0156451700fdda0d7e7799dfc938f +7671e2f2a9fc555e3ce7dd4f45eb1a8083561d89 From 28dfd836e2390e44e3803573720a1081d724b7b3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 20:29:23 -0400 Subject: [PATCH 0267/1547] Roll Flutter Engine from 7671e2f2a9fc to eff70f7287f9 (3 revisions) (#130953) https://github.com/flutter/engine/compare/7671e2f2a9fc...eff70f7287f9 2023-07-19 skia-flutter-autoroll@skia.org Roll Dart SDK from 936824d49aa7 to 677bbf64d4d7 (1 revision) (flutter/engine#43833) 2023-07-19 flar@google.com Reland "Add non-rendering operation culling to DisplayListBuilder" (#41463) (flutter/engine#43831) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from bf75ae2f6eec to 8413c82dea43 (1 revision) (flutter/engine#43832) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f73e25966af73..0dd79f07198e7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7671e2f2a9fc555e3ce7dd4f45eb1a8083561d89 +eff70f7287f9206c3042748955fdec3b37a3883d From 9c8ee4fab690d3abf03556eeb24a90d17f479eb7 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 19 Jul 2023 17:41:51 -0700 Subject: [PATCH 0268/1547] Document that you can't change initialRoute usefully (#130450) Fixes https://github.com/flutter/flutter/issues/12454 --- packages/flutter/lib/src/widgets/app.dart | 4 ++++ packages/flutter/lib/src/widgets/navigator.dart | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index c641566c384fe..af5d404c43033 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -725,6 +725,10 @@ class WidgetsApp extends StatefulWidget { /// [routes], [onGenerateRoute], or [onUnknownRoute]); if they are not, /// [initialRoute] must be null and [builder] must not be null. /// + /// Changing the [initialRoute] will have no effect, as it only controls the + /// _initial_ route. To change the route while the application is running, use + /// the [Navigator] or [Router] APIs. + /// /// See also: /// /// * [Navigator.initialRoute], which is used to implement this property. diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 353b0614fccb1..43156aa44e26e 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -1470,6 +1470,10 @@ class Navigator extends StatefulWidget { /// /// The value is interpreted according to [onGenerateInitialRoutes], which /// defaults to [defaultGenerateInitialRoutes]. + /// + /// Changing the [initialRoute] will have no effect, as it only controls the + /// _initial_ route. To change the route while the application is running, use + /// the static functions on this class, such as [push] or [replace]. final String? initialRoute; /// Called to generate a route for a given [RouteSettings]. From 4763be745d16635cb7ea16bd4e364bee1edf4d5f Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Wed, 19 Jul 2023 18:01:01 -0700 Subject: [PATCH 0269/1547] Can traverse if current focused node skips traversal (#130812) Currently if the focus is on a focusnode that `skipTraversal = true`, the tab won't be able to traverse focus out of the node. this pr fixes it --- .../lib/src/widgets/focus_traversal.dart | 47 +++++++++++----- .../test/material/icon_button_test.dart | 2 +- .../test/material/input_chip_test.dart | 2 +- .../material/raw_material_button_test.dart | 2 +- .../test/material/text_field_test.dart | 2 +- .../flutter/test/widgets/actions_test.dart | 2 + .../test/widgets/focus_traversal_test.dart | 55 +++++++++++++++++++ 7 files changed, 94 insertions(+), 18 deletions(-) diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 33a83b0b7a5b1..9cafbca24d6cf 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -352,7 +352,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { @protected Iterable sortDescendants(Iterable descendants, FocusNode currentNode); - Map _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode) { + Map _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { final FocusTraversalPolicy defaultPolicy = scopeGroupNode?.policy ?? ReadingOrderTraversalPolicy(); final Map groups = {}; for (final FocusNode node in scope.descendants) { @@ -374,7 +374,10 @@ abstract class FocusTraversalPolicy with Diagnosticable { } // Skip non-focusable and non-traversable nodes in the same way that // FocusScopeNode.traversalDescendants would. - if (node.canRequestFocus && !node.skipTraversal) { + // + // Current focused node needs to be in the group so that the caller can + // find the next traversable node from the current focused node. + if (node == currentNode || (node.canRequestFocus && !node.skipTraversal)) { groups[groupNode] ??= _FocusTraversalGroupInfo(groupNode, members: [], defaultPolicy: defaultPolicy); assert(!groups[groupNode]!.members.contains(node)); groups[groupNode]!.members.add(node); @@ -388,7 +391,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { List _sortAllDescendants(FocusScopeNode scope, FocusNode currentNode) { final _FocusTraversalGroupNode? scopeGroupNode = FocusTraversalGroup._getGroupNode(scope); // Build the sorting data structure, separating descendants into groups. - final Map groups = _findGroups(scope, scopeGroupNode); + final Map groups = _findGroups(scope, scopeGroupNode, currentNode); // Sort the member lists using the individual policy sorts. for (final FocusNode? key in groups.keys) { @@ -397,6 +400,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { groups[key]!.members.addAll(sortedMembers); } + // Traverse the group tree, adding the children of members in the order they // appear in the member lists. final List sortedDescendants = []; @@ -421,17 +425,29 @@ abstract class FocusTraversalPolicy with Diagnosticable { // They were left in above because they were needed to find their members // during sorting. sortedDescendants.removeWhere((FocusNode node) { - return !node.canRequestFocus || node.skipTraversal; + return node != currentNode && (!node.canRequestFocus || node.skipTraversal); }); // Sanity check to make sure that the algorithm above doesn't diverge from // the one in FocusScopeNode.traversalDescendants in terms of which nodes it // finds. - assert( - sortedDescendants.length <= scope.traversalDescendants.length && sortedDescendants.toSet().difference(scope.traversalDescendants.toSet()).isEmpty, - 'Sorted descendants contains different nodes than FocusScopeNode.traversalDescendants would. ' - 'These are the different nodes: ${sortedDescendants.toSet().difference(scope.traversalDescendants.toSet())}', - ); + assert((){ + final Set difference = sortedDescendants.toSet().difference(scope.traversalDescendants.toSet()); + if (currentNode.skipTraversal) { + assert( + difference.length == 1 && difference.contains(currentNode), + 'Sorted descendants contains different nodes than FocusScopeNode.traversalDescendants would. ' + 'These are the different nodes: ${difference.where((FocusNode node) => node != currentNode)}', + ); + return true; + } + assert( + difference.isEmpty, + 'Sorted descendants contains different nodes than FocusScopeNode.traversalDescendants would. ' + 'These are the different nodes: $difference', + ); + return true; + }()); return sortedDescendants; } @@ -453,7 +469,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { bool _moveFocus(FocusNode currentNode, {required bool forward}) { final FocusScopeNode nearestScope = currentNode.nearestScope!; invalidateScopeData(nearestScope); - final FocusNode? focusedChild = nearestScope.focusedChild; + FocusNode? focusedChild = nearestScope.focusedChild; if (focusedChild == null) { final FocusNode? firstFocus = forward ? findFirstFocus(currentNode) : findLastFocus(currentNode); if (firstFocus != null) { @@ -464,8 +480,11 @@ abstract class FocusTraversalPolicy with Diagnosticable { return true; } } - final List sortedNodes = _sortAllDescendants(nearestScope, currentNode); - if (sortedNodes.isEmpty) { + focusedChild ??= nearestScope; + final List sortedNodes = _sortAllDescendants(nearestScope, focusedChild); + + assert(sortedNodes.contains(focusedChild)); + if (sortedNodes.length < 2) { // If there are no nodes to traverse to, like when descendantsAreTraversable // is false or skipTraversal for all the nodes is true. return false; @@ -473,7 +492,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { if (forward && focusedChild == sortedNodes.last) { switch (nearestScope.traversalEdgeBehavior) { case TraversalEdgeBehavior.leaveFlutterView: - focusedChild!.unfocus(); + focusedChild.unfocus(); return false; case TraversalEdgeBehavior.closedLoop: requestFocusCallback(sortedNodes.first, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd); @@ -483,7 +502,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { if (!forward && focusedChild == sortedNodes.first) { switch (nearestScope.traversalEdgeBehavior) { case TraversalEdgeBehavior.leaveFlutterView: - focusedChild!.unfocus(); + focusedChild.unfocus(); return false; case TraversalEdgeBehavior.closedLoop: requestFocusCallback(sortedNodes.last, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart); diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 949a467b1be26..2bbe170f2a296 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -812,7 +812,7 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - expect(focusNode1.nextFocus(), isTrue); + expect(focusNode1.nextFocus(), isFalse); await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index 827ded808496e..7fec3ace8afdf 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -271,7 +271,7 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - expect(focusNode1.nextFocus(), isTrue); + expect(focusNode1.nextFocus(), isFalse); await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index da69556af2132..7935a4d3dc2e6 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -414,7 +414,7 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - expect(focusNode1.nextFocus(), isTrue); + expect(focusNode1.nextFocus(), isFalse); await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 09fb36bce0f00..9b3af744d3bca 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -6690,7 +6690,7 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - expect(focusNode1.nextFocus(), isTrue); + expect(focusNode1.nextFocus(), isFalse); await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index d428c994d04aa..b59f17f8eafc2 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -908,6 +908,7 @@ void main() { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( + focusNode: FocusNode(skipTraversal: true), child: Column( children: [ ElevatedButton( @@ -938,6 +939,7 @@ void main() { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( + focusNode: FocusNode(skipTraversal: true), descendantsAreTraversable: false, child: Column( children: [ diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index e03f77628bf9b..ff0b8c9729748 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -2090,6 +2090,61 @@ void main() { expect(Focus.of(upperLeftKey.currentContext!).hasPrimaryFocus, isTrue); }, skip: isBrowser, variant: KeySimulatorTransitModeVariant.all()); // https://github.com/flutter/flutter/issues/35347 + testWidgets('Focus traversal actions works when current focus skip traversal', (WidgetTester tester) async { + final GlobalKey key1 = GlobalKey(debugLabel: 'key1'); + final GlobalKey key2 = GlobalKey(debugLabel: 'key2'); + final GlobalKey key3 = GlobalKey(debugLabel: 'key3'); + + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFFFFFFFF), + onGenerateRoute: (RouteSettings settings) { + return TestRoute( + child: Directionality( + textDirection: TextDirection.ltr, + child: FocusScope( + debugLabel: 'scope', + child: Column( + children: [ + Row( + children: [ + Focus( + autofocus: true, + skipTraversal: true, + debugLabel: '1', + child: SizedBox(width: 100, height: 100, key: key1), + ), + Focus( + debugLabel: '2', + child: SizedBox(width: 100, height: 100, key: key2), + ), + Focus( + debugLabel: '3', + child: SizedBox(width: 100, height: 100, key: key3), + ), + ], + ), + ], + ), + ), + ), + ); + }, + ), + ); + + expect(Focus.of(key1.currentContext!).hasPrimaryFocus, isTrue); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + expect(Focus.of(key2.currentContext!).hasPrimaryFocus, isTrue); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + expect(Focus.of(key3.currentContext!).hasPrimaryFocus, isTrue); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + // Skips key 1 because it skips traversal. + expect(Focus.of(key2.currentContext!).hasPrimaryFocus, isTrue); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + expect(Focus.of(key3.currentContext!).hasPrimaryFocus, isTrue); + }, skip: isBrowser, variant: KeySimulatorTransitModeVariant.all()); // https://github.com/flutter/flutter/issues/35347 + testWidgets('Focus traversal inside a vertical scrollable scrolls to stay visible.', (WidgetTester tester) async { final List items = List.generate(11, (int index) => index).toList(); final List nodes = List.generate(11, (int index) => FocusNode(debugLabel: 'Item ${index + 1}')).toList(); From 3d7f5752336aaf098edc147ae33dbe55c040d64b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 21:15:39 -0400 Subject: [PATCH 0270/1547] Roll Flutter Engine from eff70f7287f9 to e2a36be2f084 (2 revisions) (#130956) https://github.com/flutter/engine/compare/eff70f7287f9...e2a36be2f084 2023-07-19 skia-flutter-autoroll@skia.org Roll ANGLE from 4515b270772e to 5e38a31bd76a (1 revision) (flutter/engine#43836) 2023-07-19 skia-flutter-autoroll@skia.org Roll Skia from 8413c82dea43 to b238c09fe959 (1 revision) (flutter/engine#43835) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0dd79f07198e7..5e462dec6fcbc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -eff70f7287f9206c3042748955fdec3b37a3883d +e2a36be2f0844839d764352c858fcc32ca6eb1fb From 17b732bb6ddd9631ed3f3e63afa0502fc7148080 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 19 Jul 2023 18:35:34 -0700 Subject: [PATCH 0271/1547] Further clarify Stack documentation on overflowing (#130776) Fixes #75731 --- packages/flutter/lib/src/widgets/basic.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index dafcd1209262f..a6c55db080e0a 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -3914,11 +3914,13 @@ class Stack extends MultiChildRenderObjectWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Stacks only clip children whose geometry overflow the stack. A child that - /// paints outside its bounds (e.g. a box with a shadow) will not be clipped, - /// regardless of the value of this property. Similarly, a child that itself - /// has a descendant that overflows the stack will not be clipped, as only the - /// geometry of the stack's direct children are considered. + /// Stacks only clip children whose _geometry_ overflows the stack. A child + /// that paints outside its bounds (e.g. a box with a shadow) will not be + /// clipped, regardless of the value of this property. Similarly, a child that + /// itself has a descendant that overflows the stack will not be clipped, as + /// only the geometry of the stack's direct children are considered. + /// [Transform] is an example of a widget that can cause its children to paint + /// outside its geometry. /// /// To clip children whose geometry does not overflow the stack, consider /// using a [ClipRect] widget. From 123413b05294a06a94eff717d1e68352de05023e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 22:37:23 -0400 Subject: [PATCH 0272/1547] Roll Flutter Engine from e2a36be2f084 to 56e88e8b0eef (1 revision) (#130959) https://github.com/flutter/engine/compare/e2a36be2f084...56e88e8b0eef 2023-07-20 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -SNz0augjLKFVsUWn... to ZwCUlo28olVzLlqTl... (flutter/engine#43839) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from -SNz0augjLKF to ZwCUlo28olVz If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5e462dec6fcbc..2f797d0849007 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e2a36be2f0844839d764352c858fcc32ca6eb1fb +56e88e8b0eefd3856368d9ae638a0f787277f592 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 5f31d4afbfb3f..d49a87cd98622 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ --SNz0augjLKFVsUWnMnuevifpykHjCqZd5_eL7gslrMC +ZwCUlo28olVzLlqTljGEaAvE9GgjVdpEkfLlEIWXcx0C From 3a1300e0c4cf01fc4de2f3cac606cd08034d1449 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 19 Jul 2023 20:28:57 -0700 Subject: [PATCH 0273/1547] Automatically create the layer when setting hints in PaintingContext (#130364) Fixes https://github.com/flutter/flutter/issues/92722 --- .../flutter/lib/src/rendering/object.dart | 20 ++++++++++-- .../test/rendering/painting_context_test.dart | 32 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 packages/flutter/test/rendering/painting_context_test.dart diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index d988fc923e36d..c6fc50a84e3f6 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -397,8 +397,16 @@ class PaintingContext extends ClipContext { /// If this hint is not set, the compositor will apply its own heuristics to /// decide whether the current layer is complex enough to benefit from /// caching. + /// + /// Calling this ensures a [Canvas] is available. Only draw calls on the + /// current canvas will be hinted; the hint is not propagated to new canvases + /// created after a new layer is added to the painting context (e.g. with + /// [addLayer] or [pushLayer]). void setIsComplexHint() { - _currentLayer?.isComplexHint = true; + if (_currentLayer == null) { + _startRecording(); + } + _currentLayer!.isComplexHint = true; } /// Hints that the painting in the current layer is likely to change next frame. @@ -407,8 +415,16 @@ class PaintingContext extends ClipContext { /// cache will not be used in the future. If this hint is not set, the /// compositor will apply its own heuristics to decide whether the current /// layer is likely to be reused in the future. + /// + /// Calling this ensures a [Canvas] is available. Only draw calls on the + /// current canvas will be hinted; the hint is not propagated to new canvases + /// created after a new layer is added to the painting context (e.g. with + /// [addLayer] or [pushLayer]). void setWillChangeHint() { - _currentLayer?.willChangeHint = true; + if (_currentLayer == null) { + _startRecording(); + } + _currentLayer!.willChangeHint = true; } /// Adds a composited leaf layer to the recording. diff --git a/packages/flutter/test/rendering/painting_context_test.dart b/packages/flutter/test/rendering/painting_context_test.dart new file mode 100644 index 0000000000000..0b97e7db3440f --- /dev/null +++ b/packages/flutter/test/rendering/painting_context_test.dart @@ -0,0 +1,32 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'rendering_tester.dart'; + +void main() { + TestRenderingFlutterBinding.ensureInitialized(); + + test('PaintingContext.setIsComplexHint', () { + final ContainerLayer layer = ContainerLayer(); + final PaintingContext context = PaintingContext(layer, Rect.zero); + expect(layer.hasChildren, isFalse); + context.setIsComplexHint(); + expect(layer.hasChildren, isTrue); + expect(layer.firstChild, isA()); + expect((layer.firstChild! as PictureLayer).isComplexHint, isTrue); + }); + + test('PaintingContext.setWillChangeHint', () { + final ContainerLayer layer = ContainerLayer(); + final PaintingContext context = PaintingContext(layer, Rect.zero); + expect(layer.hasChildren, isFalse); + context.setWillChangeHint(); + expect(layer.hasChildren, isTrue); + expect(layer.firstChild, isA()); + expect((layer.firstChild! as PictureLayer).willChangeHint, isTrue); + }); +} From 64edc55a7b0885c9c74be18e4c9d4a829f9f49c5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 19 Jul 2023 23:58:31 -0400 Subject: [PATCH 0274/1547] Roll Flutter Engine from 56e88e8b0eef to c902fec1e3ce (1 revision) (#130960) https://github.com/flutter/engine/compare/56e88e8b0eef...c902fec1e3ce 2023-07-20 skia-flutter-autoroll@skia.org Roll Dart SDK from 677bbf64d4d7 to 368a205aa1d4 (1 revision) (flutter/engine#43841) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2f797d0849007..eac6f324ab540 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -56e88e8b0eefd3856368d9ae638a0f787277f592 +c902fec1e3ce901f7bce568758f27f2f6298376c From a1b1386392267630b4dc813b1808af6247dc25f7 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 19 Jul 2023 21:35:11 -0700 Subject: [PATCH 0275/1547] More documentation for MediaQuery and friends (#130509) Fixes https://github.com/flutter/flutter/issues/11697 --- packages/flutter/lib/src/widgets/media_query.dart | 13 ++++++++++--- packages/flutter/lib/src/widgets/view.dart | 13 +++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 1c80b4d2e2b74..5e4272f497326 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -219,6 +219,10 @@ class MediaQueryData { /// this method again when it changes to keep the constructed [MediaQueryData] /// updated. /// + /// In general, [MediaQuery.of] is the appropriate way to obtain + /// [MediaQueryData] from a widget. This `fromView` constructor is primarily + /// for use in the implementation of the framework itself. + /// /// See also: /// /// * [MediaQuery.fromView], which constructs [MediaQueryData] from a provided @@ -262,9 +266,12 @@ class MediaQueryData { /// It is considered bad practice to cache and later use the size returned /// by `MediaQuery.of(context).size`. It will make the application non responsive /// and might lead to unexpected behaviors. - /// For instance, during startup, especially in release mode, the first returned - /// size might be (0,0). The size will be updated when the native platform - /// reports the actual resolution. + /// + /// For instance, during startup, especially in release mode, the first + /// returned size might be (0,0). The size will be updated when the native + /// platform reports the actual resolution. Using [MediaQuery.of] will ensure + /// that when the size changes, any widgets depending on the size are + /// automatically rebuilt. /// /// See the article on [Creating responsive and adaptive /// apps](https://docs.flutter.dev/development/ui/layout/adaptive-responsive) diff --git a/packages/flutter/lib/src/widgets/view.dart b/packages/flutter/lib/src/widgets/view.dart index b25558b6c5464..cfb6e02e1f378 100644 --- a/packages/flutter/lib/src/widgets/view.dart +++ b/packages/flutter/lib/src/widgets/view.dart @@ -21,6 +21,15 @@ import 'media_query.dart'; /// The provided [child] is wrapped in a [MediaQuery] constructed from the given /// [view]. /// +/// For most use cases, using [MediaQuery.of] is a more appropriate way of +/// obtaining the information that a [FlutterView] exposes. For example, using +/// [MediaQuery] will expose the _logical_ device size ([MediaQueryData.size]) +/// rather than the physical size ([FlutterView.physicalSize]). Similarly, while +/// [FlutterView.padding] conveys the information from the operating system, the +/// [MediaQueryData.padding] further adjusts this information to be aware of the +/// context of the widget; e.g. the [Scaffold] widget adjusts the values for its +/// various children. +/// /// Each [FlutterView] can be associated with at most one [View] widget in the /// widget tree. Two or more [View] widgets configured with the same /// [FlutterView] must never exist within the same widget tree at the same time. @@ -93,7 +102,7 @@ class View extends StatelessWidget { /// The method creates a dependency on the `context`, which will be informed /// when the identity of the [FlutterView] changes (i.e. the `context` is /// moved to render into a different [FlutterView] then before). The context - /// will not be informed when the properties on the [FlutterView] itself + /// will not be informed when the _properties_ on the [FlutterView] itself /// change their values. To access the property values of a [FlutterView] it /// is best practise to use [MediaQuery.maybeOf] instead, which will ensure /// that the `context` is informed when the view properties change. @@ -113,7 +122,7 @@ class View extends StatelessWidget { /// The method creates a dependency on the `context`, which will be informed /// when the identity of the [FlutterView] changes (i.e. the `context` is /// moved to render into a different [FlutterView] then before). The context - /// will not be informed when the properties on the [FlutterView] itself + /// will not be informed when the _properties_ on the [FlutterView] itself /// change their values. To access the property values of a [FlutterView] it /// is best practise to use [MediaQuery.of] instead, which will ensure that /// the `context` is informed when the view properties change. From 86c8abf88bd421842383af04499e1379098098e8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 00:51:38 -0400 Subject: [PATCH 0276/1547] Roll Flutter Engine from c902fec1e3ce to 204625490ca1 (1 revision) (#130962) https://github.com/flutter/engine/compare/c902fec1e3ce...204625490ca1 2023-07-20 john@johnmccutchan.com Add a PlatformViewRenderTarget abstraction (flutter/engine#43813) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index eac6f324ab540..aae68dbafa159 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c902fec1e3ce901f7bce568758f27f2f6298376c +204625490ca1b8a3a9fd939d9399a8b0242ca207 From d1d78bc91728dfdb06ad409a98427478acb64eb7 Mon Sep 17 00:00:00 2001 From: Lau Ching Jun Date: Wed, 19 Jul 2023 22:01:24 -0700 Subject: [PATCH 0277/1547] Make PollingDeviceDiscovery start the initial poll faster. (#130755) This will speed up the initial population of the device list. --- packages/flutter_tools/lib/src/device.dart | 7 ++++--- packages/flutter_tools/test/general.shard/device_test.dart | 1 - .../proxied_devices/proxied_devices_test.dart | 5 +---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index a919109367eab..83d13746d29f8 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -504,12 +504,13 @@ abstract class PollingDeviceDiscovery extends DeviceDiscovery { if (_timer == null) { deviceNotifier ??= ItemListNotifier(); // Make initial population the default, fast polling timeout. - _timer = _initTimer(null); + _timer = _initTimer(null, initialCall: true); } } - Timer _initTimer(Duration? pollingTimeout) { - return Timer(_pollingInterval, () async { + Timer _initTimer(Duration? pollingTimeout, {bool initialCall = false}) { + // Poll for devices immediately on the initial call for faster initial population. + return Timer(initialCall ? Duration.zero : _pollingInterval, () async { try { final List devices = await pollingGetDevices(timeout: pollingTimeout); deviceNotifier!.updateWithNewList(devices); diff --git a/packages/flutter_tools/test/general.shard/device_test.dart b/packages/flutter_tools/test/general.shard/device_test.dart index 2774536308214..fab87b8f71090 100644 --- a/packages/flutter_tools/test/general.shard/device_test.dart +++ b/packages/flutter_tools/test/general.shard/device_test.dart @@ -234,7 +234,6 @@ void main() { FakeAsync().run((FakeAsync time) { final FakePollingDeviceDiscovery pollingDeviceDiscovery = FakePollingDeviceDiscovery(); pollingDeviceDiscovery.startPolling(); - time.elapse(const Duration(milliseconds: 4001)); // First check should use the default polling timeout // to quickly populate the list. diff --git a/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart b/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart index 9f601fbbac03a..d6f982e35ae3d 100644 --- a/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart +++ b/packages/flutter_tools/test/general.shard/proxied_devices/proxied_devices_test.dart @@ -397,10 +397,7 @@ void main() { expect(devicesAdded[0].id, fakeDevice['id']); expect(devicesAdded[1].id, fakeDevice2['id']); }); - // Explicit timeout is needed because the default timeout is 2s, but `startPolling` waits for - // 4s before making its first poll. - // TODO(chingjun): Remove the timeout. - }, timeout: const Timeout(Duration(seconds: 6))); + }); group('ProxiedDartDevelopmentService', () { testWithoutContext('forwards start and shutdown to remote', () async { From 4cd9fd00c00f5952e1a4a88b11dcab728c870f28 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 03:35:00 -0400 Subject: [PATCH 0278/1547] Roll Flutter Engine from 204625490ca1 to b494143fb0bc (1 revision) (#130966) https://github.com/flutter/engine/compare/204625490ca1...b494143fb0bc 2023-07-20 skia-flutter-autoroll@skia.org Roll Dart SDK from 368a205aa1d4 to 603aacd8400f (1 revision) (flutter/engine#43843) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index aae68dbafa159..3150666156728 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -204625490ca1b8a3a9fd939d9399a8b0242ca207 +b494143fb0bc68864adafa02b42f26f23a04bd40 From ec508319f2ca685d4c64bceffd1db25cbe1cac32 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Thu, 20 Jul 2023 09:45:29 +0200 Subject: [PATCH 0279/1547] Update banner_theme_test.dart for M3 (#130884) This PR updates unit tests from banner_theme_test.dart for M3 migration. More info in https://github.com/flutter/flutter/issues/127064 Just added some `Material`prefixes. --- packages/flutter/test/material/banner_theme_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/flutter/test/material/banner_theme_test.dart b/packages/flutter/test/material/banner_theme_test.dart index 4fd5f3a05c319..ca4c9022d5940 100644 --- a/packages/flutter/test/material/banner_theme_test.dart +++ b/packages/flutter/test/material/banner_theme_test.dart @@ -66,7 +66,7 @@ void main() { ]); }); - testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { + testWidgets('Material3 - Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { const String contentText = 'Content'; final ThemeData theme = ThemeData(useMaterial3: true); late final ThemeData localizedTheme; @@ -115,7 +115,7 @@ void main() { expect(divider.color, theme.colorScheme.outlineVariant); }); - testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgets('Material3 - Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); final ThemeData theme = ThemeData(useMaterial3: true); @@ -453,7 +453,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { + testWidgets('Material2 - Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { const String contentText = 'Content'; await tester.pumpWidget(MaterialApp( @@ -499,7 +499,7 @@ void main() { expect(divider.color, null); }); - testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgets('Material2 - Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); From 0aba94f4619bf4fd739d5c1c541c0d928629398f Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Thu, 20 Jul 2023 09:54:23 +0200 Subject: [PATCH 0280/1547] Fix IconButton leaks its internal MaterialStatesController (#130720) ## Description This PR adds a call to dispose the internal `MaterialStatesController` instantiated by `_SelectableIconButtonState`. I found this memory leak while working on M2/M3 test update for `about_test.dart`. This memory leak only happens when using M3 because `IconButton` relies on `_SelectableIconButton` only when useMaterial3 is true: https://github.com/flutter/flutter/blob/3a1190a5a85c3e6a0cf3a9c30f34548fdd48ac1e/packages/flutter/lib/src/material/icon_button.dart#L671-L721 ## Related Issue Fixes https://github.com/flutter/flutter/issues/130708 ## Tests Adds 1 test. --- .../flutter/lib/src/material/icon_button.dart | 6 +++ .../test/material/icon_button_test.dart | 42 ++++++++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index ade4e84e6677a..88a9a36e24032 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -880,6 +880,12 @@ class _SelectableIconButtonState extends State<_SelectableIconButton> { ), ); } + + @override + void dispose() { + statesController.dispose(); + super.dispose(); + } } class _IconButtonM3 extends ButtonStyleButton { diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 2bbe170f2a296..bd8b6c3b5b0e7 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -2729,18 +2730,18 @@ void main() { final ColorScheme lightScheme = const ColorScheme.light().copyWith(onSurfaceVariant: const Color(0xffe91e60)); // Brightness.dark await tester.pumpWidget( - MaterialApp( - theme: ThemeData(colorScheme: lightScheme, useMaterial3: true,), - home: Scaffold( - body: IconTheme.merge( - data: const IconThemeData(size: 26), - child: IconButton( - icon: const Icon(Icons.account_box), - onPressed: () {}, - ), - ), - ) + MaterialApp( + theme: ThemeData(colorScheme: lightScheme, useMaterial3: true,), + home: Scaffold( + body: IconTheme.merge( + data: const IconThemeData(size: 26), + child: IconButton( + icon: const Icon(Icons.account_box), + onPressed: () {}, + ), + ), ) + ) ); Color? iconColor0() => _iconStyle(tester, Icons.account_box)?.color; @@ -2770,6 +2771,25 @@ void main() { expect(tester.takeException(), isNull); }); + + testWidgetsWithLeakTracking('Material3 - IconButton memory leak', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/130708. + Widget buildWidget(bool showIconButton) { + return showIconButton + ? MaterialApp( + theme: ThemeData(useMaterial3: true), + home: IconButton( + onPressed: () { }, + icon: const Icon(Icons.search), + ), + ) + : const SizedBox(); + } + await tester.pumpWidget(buildWidget(true)); + await tester.pumpWidget(buildWidget(false)); + + // No exception is thrown. + }); }); } From f92637d7c4374df5585bab4e032924eb54b0c217 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 20 Jul 2023 12:25:24 +0300 Subject: [PATCH 0281/1547] Fix chip delete button tap target spilling into the label. (#130896) fixes [Chip's delete button tap target is too big](https://github.com/flutter/flutter/issues/129986) ### Description This PR fixes the issue where the chip delete button is tappable within the label. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(useMaterial3: true), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sample'), ), body: Center( child: Chip( label: const Text('Really Long Label'), onDeleted: () {}, ), ), ); } } ```
### Before https://github.com/flutter/flutter/assets/48603081/14b369c5-c740-4dfc-a512-779bd3a1a46b ### After https://github.com/flutter/flutter/assets/48603081/08c6e232-0237-4ab2-9829-66ee8e5cead2 --- packages/flutter/lib/src/material/chip.dart | 12 +++-- packages/flutter/test/material/chip_test.dart | 51 +++++++++++++++++-- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 562a1878f31fb..adbe71273708b 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -1763,6 +1763,7 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } final bool hitIsOnDeleteIcon = deleteIcon != null && _hitIsOnDeleteIcon( padding: theme.padding, + labelPadding: theme.labelPadding, tapPosition: position, chipSize: size, deleteButtonSize: deleteIcon!.size, @@ -2186,6 +2187,7 @@ class _UnconstrainedInkSplashFactory extends InteractiveInkFeatureFactory { bool _hitIsOnDeleteIcon({ required EdgeInsetsGeometry padding, + required EdgeInsetsGeometry labelPadding, required Offset tapPosition, required Size chipSize, required Size deleteButtonSize, @@ -2197,10 +2199,10 @@ bool _hitIsOnDeleteIcon({ final Size deflatedSize = resolvedPadding.deflateSize(chipSize); final Offset adjustedPosition = tapPosition - Offset(resolvedPadding.left, resolvedPadding.top); // The delete button hit area should be at least the width of the delete - // button, but, if there's room, up to 24 pixels from the center of the delete - // icon (corresponding to part of a 48x48 square that Material would prefer - // for touch targets), but no more than approximately half of the overall size - // of the chip when the chip is small. + // button and right label padding, but, if there's room, up to 24 pixels + // from the center of the delete icon (corresponding to part of a 48x48 square + // that Material would prefer for touch targets), but no more than approximately + // half of the overall size of the chip when the chip is small. // // This isn't affected by materialTapTargetSize because it only applies to the // width of the tappable region within the chip, not outside of the chip, @@ -2211,7 +2213,7 @@ bool _hitIsOnDeleteIcon({ // chip will still hit the chip, not the delete button. final double accessibleDeleteButtonWidth = math.min( deflatedSize.width * 0.499, - math.max(deleteButtonSize.width, 24.0 + deleteButtonSize.width / 2.0), + math.min(labelPadding.resolve(textDirection).right + deleteButtonSize.width, 24.0 + deleteButtonSize.width / 2.0), ); switch (textDirection) { case TextDirection.ltr: diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index baa306a29404a..4f90081c708ff 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -639,7 +639,7 @@ void main() { }, ); - testWidgets('delete button tap target is the right proportion of the chip', (WidgetTester tester) async { + testWidgets('Delete button tap target is the right proportion of the chip', (WidgetTester tester) async { final UniqueKey deleteKey = UniqueKey(); bool calledDelete = false; await tester.pumpWidget( @@ -657,12 +657,15 @@ void main() { ), ), ); - await tester.tapAt(tester.getCenter(find.byKey(deleteKey)) - const Offset(24.0, 0.0)); + + // Test correct tap target size. + await tester.tapAt(tester.getCenter(find.byKey(deleteKey)) - const Offset(18.0, 0.0)); // Half the width of the delete button + right label padding. await tester.pump(); expect(calledDelete, isTrue); calledDelete = false; - await tester.tapAt(tester.getCenter(find.byKey(deleteKey)) - const Offset(25.0, 0.0)); + // Test incorrect tap target size. + await tester.tapAt(tester.getCenter(find.byKey(deleteKey)) - const Offset(19.0, 0.0)); await tester.pump(); expect(calledDelete, isFalse); calledDelete = false; @@ -3459,6 +3462,48 @@ void main() { expect(getMaterialBox(tester), paints..rrect(color: selectedColor)); }); + testWidgets('Delete button tap target area does not include label', (WidgetTester tester) async { + bool calledDelete = false; + await tester.pumpWidget( + wrapForChip( + child: Column( + children: [ + Chip( + label: const Text('Chip'), + onDeleted: () { + calledDelete = true; + }, + ), + ], + ), + ), + ); + + // Tap on the delete button. + await tester.tapAt(tester.getCenter(find.byType(Icon))); + await tester.pump(); + expect(calledDelete, isTrue); + calledDelete = false; + + final Offset labelCenter = tester.getCenter(find.text('Chip')); + + // Tap on the label. + await tester.tapAt(labelCenter); + await tester.pump(); + expect(calledDelete, isFalse); + + // Tap before end of the label. + final Size labelSize = tester.getSize(find.text('Chip')); + await tester.tapAt(Offset(labelCenter.dx + (labelSize.width / 2) - 1, labelCenter.dy)); + await tester.pump(); + expect(calledDelete, isFalse); + + // Tap after end of the label. + await tester.tapAt(Offset(labelCenter.dx + (labelSize.width / 2), labelCenter.dy)); + await tester.pump(); + expect(calledDelete, isTrue); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests From f212b1012de72d5a8e041f768e0a9026b919060d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 06:33:27 -0400 Subject: [PATCH 0282/1547] Roll Flutter Engine from b494143fb0bc to 2df3b9c4b2a4 (3 revisions) (#130973) https://github.com/flutter/engine/compare/b494143fb0bc...2df3b9c4b2a4 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from d09e9869f84c to 65a83c4de7f2 (2 revisions) (flutter/engine#43847) 2023-07-20 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 7kGBjmX-zBXcg1svE... to SmAtKPfGzPllC9gfO... (flutter/engine#43845) 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from b238c09fe959 to d09e9869f84c (1 revision) (flutter/engine#43842) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 7kGBjmX-zBXc to SmAtKPfGzPll If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3150666156728..c4d6952197d7b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b494143fb0bc68864adafa02b42f26f23a04bd40 +2df3b9c4b2a4e4a11bb94dad1ecbd38df6669301 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 38e78c3da0950..9ca77ea4f3c6e 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -7kGBjmX-zBXcg1svEd78lkHB3n85_cD7LYmNYYdeQlMC +SmAtKPfGzPllC9gfOpu2NtueRGB1spsiuLFWR8bhThoC From 98e9a73ce83e3d849ac376b22aa0ec7bc3d2359e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 10:34:23 -0400 Subject: [PATCH 0283/1547] Roll Flutter Engine from 2df3b9c4b2a4 to e40995da7869 (2 revisions) (#130985) https://github.com/flutter/engine/compare/2df3b9c4b2a4...e40995da7869 2023-07-20 skia-flutter-autoroll@skia.org Roll ANGLE from 5e38a31bd76a to a4c283be741f (1 revision) (flutter/engine#43849) 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from 65a83c4de7f2 to 401c85ab1e21 (1 revision) (flutter/engine#43848) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c4d6952197d7b..871b12060b0af 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2df3b9c4b2a4e4a11bb94dad1ecbd38df6669301 +e40995da7869c1c681b4200435ce87cc9c0ded47 From e8a975e884c158e1a2ccc8fde8cc303a9e29205d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 20 Jul 2023 07:38:53 -0700 Subject: [PATCH 0284/1547] Upgrade leak_tracker. (#130951) --- packages/flutter/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 6bfb18f9684ee..4a9290839beb8 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 8.0.1 + leak_tracker: 8.0.2 leak_tracker_testing: 1.0.2 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0cef +# PUBSPEC CHECKSUM: 16f0 From 1a804207d8010127e206990feaba141471877872 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 11:32:42 -0400 Subject: [PATCH 0285/1547] Roll Flutter Engine from e40995da7869 to c645eb6da8a9 (1 revision) (#130988) https://github.com/flutter/engine/compare/e40995da7869...c645eb6da8a9 2023-07-20 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ZwCUlo28olVzLlqTl... to hVAAd2NqYOjUF_I99... (flutter/engine#43850) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ZwCUlo28olVz to hVAAd2NqYOjU If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 871b12060b0af..06a2ce4132eb7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e40995da7869c1c681b4200435ce87cc9c0ded47 +c645eb6da8a9e3ca22d25a240b608fc643039a51 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index d49a87cd98622..fb906094015ea 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ZwCUlo28olVzLlqTljGEaAvE9GgjVdpEkfLlEIWXcx0C +hVAAd2NqYOjUF_I998LDRT_IJPf5jijhH6q441hFXo8C From 67e0e8786fc37067a2f2150dcf7b16c02133141e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 11:42:23 -0400 Subject: [PATCH 0286/1547] Roll Packages from 209db219ad73 to 674179f97bda (4 revisions) (#130989) https://github.com/flutter/packages/compare/209db219ad73...674179f97bda 2023-07-19 stuartmorgan@google.com [image_picker] Deprecate platform interface methods (flutter/packages#4520) 2023-07-19 47866232+chunhtai@users.noreply.github.com [go_router] Adds a parentNavigatorKey parameter to ShellRouteData. (flutter/packages#4409) 2023-07-19 stuartmorgan@google.com [ci] Shard Windows Dart unit tests (flutter/packages#4519) 2023-07-19 engine-flutter-autoroll@skia.org Roll Flutter from 6f09064e785b to d07e8aece184 (60 revisions) (flutter/packages#4522) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index ea845d2cb41d0..56d8a83d2a2c4 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -209db219ad736b5c299cde7a215ee71b1afb3f4e +674179f97bda7eab1aa5454a0be185ed7312af51 From 2afe8aa5d31cc094ec4679b4a991d33a33ad5c8e Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Thu, 20 Jul 2023 18:34:41 +0200 Subject: [PATCH 0287/1547] Update about tests for M3 (#130970) This PR updates unit tests in `about_test.dart` for M3 migration. More info in https://github.com/flutter/flutter/issues/127064 - Two tests were failing in M3 due to a memory leak. As the memory leak is now fixed, see https://github.com/flutter/flutter/pull/130720, this two tests does not depend anymore on the Material version. - Created several M3 tests related to typography and rendering changes. --- .../flutter/test/material/about_test.dart | 397 +++++++++++++++++- 1 file changed, 380 insertions(+), 17 deletions(-) diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 3c15de4ebb5de..cb7be72b992a0 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -58,7 +58,7 @@ void main() { expect(find.text('View licenses'), findsOneWidget); }); - testWidgetsWithLeakTracking('AboutListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -141,6 +141,89 @@ void main() { expect(find.text('Pirate license'), findsOneWidget); }); + testWidgetsWithLeakTracking('Material3 - AboutListTile control test', (WidgetTester tester) async { + const FlutterLogo logo = FlutterLogo(); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + title: 'Pirate app', + home: Scaffold( + appBar: AppBar( + title: const Text('Home'), + ), + drawer: Drawer( + child: ListView( + children: const [ + AboutListTile( + applicationVersion: '0.1.2', + applicationIcon: logo, + applicationLegalese: 'I am the very model of a modern major general.', + aboutBoxChildren: [ + Text('About box'), + ], + ), + ], + ), + ), + ), + ), + ); + + expect(find.text('About Pirate app'), findsNothing); + expect(find.text('0.1.2'), findsNothing); + expect(find.byWidget(logo), findsNothing); + expect( + find.text('I am the very model of a modern major general.'), + findsNothing, + ); + expect(find.text('About box'), findsNothing); + + await tester.tap(find.byType(IconButton)); + await tester.pumpAndSettle(); + + expect(find.text('About Pirate app'), findsOneWidget); + expect(find.text('0.1.2'), findsNothing); + expect(find.byWidget(logo), findsNothing); + expect( + find.text('I am the very model of a modern major general.'), + findsNothing, + ); + expect(find.text('About box'), findsNothing); + + await tester.tap(find.text('About Pirate app')); + await tester.pumpAndSettle(); + + expect(find.text('About Pirate app'), findsOneWidget); + expect(find.text('0.1.2'), findsOneWidget); + expect(find.byWidget(logo), findsOneWidget); + expect( + find.text('I am the very model of a modern major general.'), + findsOneWidget, + ); + expect(find.text('About box'), findsOneWidget); + + LicenseRegistry.addLicense(() { + return Stream.fromIterable([ + const LicenseEntryWithLineBreaks(['Pirate package '], 'Pirate license'), + ]); + }); + + await tester.tap(find.text('View licenses')); + await tester.pumpAndSettle(); + + expect(find.text('Pirate app'), findsOneWidget); + expect(find.text('0.1.2'), findsOneWidget); + expect(find.byWidget(logo), findsOneWidget); + expect( + find.text('I am the very model of a modern major general.'), + findsOneWidget, + ); + await tester.tap(find.text('Pirate package ')); + await tester.pumpAndSettle(); + expect(find.text('Pirate license'), findsOneWidget); + }); + testWidgetsWithLeakTracking('About box logic defaults to executable name for app name', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( @@ -168,9 +251,8 @@ void main() { }); await tester.pumpWidget( - MaterialApp( - theme: ThemeData(useMaterial3: false), - home: const Center( + const MaterialApp( + home: Center( child: LicensePage(), ), ), @@ -206,7 +288,7 @@ void main() { // TODO(polina-c): remove after fixing // https://github.com/flutter/flutter/issues/130354 notGCedAllowList: { - 'ValueNotifier<_OverlayEntryWidgetState?>':2, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, 'ValueNotifier': 1, }, )); @@ -230,10 +312,9 @@ void main() { }); await tester.pumpWidget( - MaterialApp( - theme: ThemeData(useMaterial3: false), + const MaterialApp( title: 'Pirate app', - home: const Center( + home: Center( child: LicensePage( applicationName: 'LicensePage test app', applicationVersion: '0.1.2', @@ -296,7 +377,7 @@ void main() { }, )); - testWidgetsWithLeakTracking('_PackageLicensePage title style without AppBarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - _PackageLicensePage title style without AppBarTheme', (WidgetTester tester) async { LicenseRegistry.addLicense(() { return Stream.fromIterable([ const LicenseEntryWithLineBreaks(['AAA'], 'BBB'), @@ -344,6 +425,54 @@ void main() { expect(subtitle.style, subtitleTextStyle); }); + testWidgetsWithLeakTracking('Material3 - _PackageLicensePage title style without AppBarTheme', (WidgetTester tester) async { + LicenseRegistry.addLicense(() { + return Stream.fromIterable([ + const LicenseEntryWithLineBreaks(['AAA'], 'BBB'), + ]); + }); + + const TextStyle titleTextStyle = TextStyle( + fontSize: 20, + color: Colors.black, + inherit: false, + ); + const TextStyle subtitleTextStyle = TextStyle( + fontSize: 15, + color: Colors.red, + inherit: false, + ); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + useMaterial3: true, + textTheme: const TextTheme( + titleLarge: titleTextStyle, + titleSmall: subtitleTextStyle, + ), + ), + home: const Center( + child: LicensePage(), + ), + ), + ); + await tester.pumpAndSettle(); + + // Check for packages. + expect(find.text('AAA'), findsOneWidget); + + // Check license is displayed after entering into license page for 'AAA'. + await tester.tap(find.text('AAA')); + await tester.pumpAndSettle(); + + // Check for titles style. + final Text title = tester.widget(find.text('AAA')); + expect(title.style, titleTextStyle); + final Text subtitle = tester.widget(find.text('1 license.')); + expect(subtitle.style, subtitleTextStyle); + }); + testWidgetsWithLeakTracking('_PackageLicensePage title style with AppBarTheme', (WidgetTester tester) async { LicenseRegistry.addLicense(() { return Stream.fromIterable([ @@ -394,7 +523,7 @@ void main() { expect(title.style, titleTextStyle); }); - testWidgetsWithLeakTracking('LicensePage respects the notch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - LicensePage respects the notch', (WidgetTester tester) async { const double safeareaPadding = 27.0; LicenseRegistry.addLicense(() { @@ -425,6 +554,37 @@ void main() { ); }); + testWidgetsWithLeakTracking('Material3 - LicensePage respects the notch', (WidgetTester tester) async { + const double safeareaPadding = 27.0; + + LicenseRegistry.addLicense(() { + return Stream.fromIterable([ + const LicenseEntryWithLineBreaks(['ABC'], 'DEF'), + ]); + }); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.all(safeareaPadding), + ), + child: LicensePage(), + ), + ), + ); + + await tester.pumpAndSettle(); + + // The position of the top left of app bar title should indicate whether + // the safe area is sufficiently respected. + expect( + tester.getTopLeft(find.text('Licenses')), + const Offset(16.0 + safeareaPadding, 14.0 + safeareaPadding), + ); + }); + testWidgetsWithLeakTracking('LicensePage returns early if unmounted', (WidgetTester tester) async { final Completer licenseCompleter = Completer(); LicenseRegistry.addLicense(() { @@ -846,7 +1006,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -20.0))); }); - testWidgetsWithLeakTracking("LicensePage's color must be same whether loading or done", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Material2 - LicensePage's color must be same whether loading or done", (WidgetTester tester) async { const Color scaffoldColor = Color(0xFF123456); const Color cardColor = Color(0xFF654321); @@ -893,6 +1053,53 @@ void main() { expect(materialDones[1].color, cardColor); }); + testWidgetsWithLeakTracking("Material3 - LicensePage's color must be same whether loading or done", (WidgetTester tester) async { + const Color scaffoldColor = Color(0xFF123456); + const Color cardColor = Color(0xFF654321); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData.light(useMaterial3: true).copyWith( + scaffoldBackgroundColor: scaffoldColor, + cardColor: cardColor, + ), + home: Scaffold( + body: Center( + child: Builder( + builder: (BuildContext context) => GestureDetector( + child: const Text('Show licenses'), + onTap: () { + showLicensePage( + context: context, + applicationName: 'MyApp', + applicationVersion: '1.0.0', + ); + }, + ), + ), + ), + ), + )); + + await tester.tap(find.text('Show licenses')); + await tester.pump(); + await tester.pump(); + + // Check color when loading. + final List materialLoadings = tester.widgetList(find.byType(Material)).toList(); + expect(materialLoadings.length, equals(5)); + expect(materialLoadings[1].color, scaffoldColor); + expect(materialLoadings[2].color, cardColor); + + await tester.pumpAndSettle(); + + // Check color when done. + expect(find.byKey(const ValueKey(ConnectionState.done)), findsOneWidget); + final List materialDones = tester.widgetList(find.byType(Material)).toList(); + expect(materialDones.length, equals(4)); + expect(materialDones[0].color, scaffoldColor); + expect(materialDones[1].color, cardColor); + }); + testWidgetsWithLeakTracking('Conflicting scrollbars are not applied by ScrollBehavior to _PackageLicensePage', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/83819 LicenseRegistry.addLicense(() { @@ -1070,7 +1277,7 @@ void main() { expect(appIconBottomPadding, 18.0); }); - testWidgetsWithLeakTracking('Error handling test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Error handling test', (WidgetTester tester) async { LicenseRegistry.addLicense(() => Stream.error(Exception('Injected failure'))); await tester.pumpWidget( MaterialApp( @@ -1093,7 +1300,30 @@ void main() { expect(find.text('Exception: Injected failure'), findsOneWidget); }); - testWidgetsWithLeakTracking('LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Error handling test', (WidgetTester tester) async { + LicenseRegistry.addLicense(() => Stream.error(Exception('Injected failure'))); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Material(child: AboutListTile()) + ) + ); + await tester.tap(find.byType(ListTile)); + await tester.pump(); + await tester.pump(const Duration(seconds: 2)); + await tester.tap(find.text('View licenses')); + await tester.pump(); + await tester.pump(const Duration(seconds: 2)); + final Finder finder = find.byWidgetPredicate((Widget widget) => widget.runtimeType.toString() == '_PackagesView'); + // force the stream to complete (has to be done in a runAsync block since it's areal async process) + await tester.runAsync(() => (tester.firstState(finder) as dynamic).licenses as Future); // ignore: avoid_dynamic_calls + expect(tester.takeException().toString(), 'Exception: Injected failure'); + await tester.pumpAndSettle(); + expect(tester.takeException().toString(), 'Exception: Injected failure'); + expect(find.text('Exception: Injected failure'), findsOneWidget); + }); + + testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1104,6 +1334,10 @@ void main() { ]); }); + addTearDown(() async { + await tester.binding.setSurfaceSize(null); + }); + // Configure to show the default layout. await tester.binding.setSurfaceSize(defaultSize); @@ -1152,12 +1386,74 @@ void main() { expect(titleOffset, const Offset(292.0, 136.0)); expect(titleOffset.dx, lessThan(wideSize.width - 320)); // Default master view width is 320.0. expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); + }); + + testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + const TextDirection textDirection = TextDirection.ltr; + const Size defaultSize = Size(800.0, 600.0); + const Size wideSize = Size(1200.0, 600.0); + const String title = 'License ABC'; + LicenseRegistry.addLicense(() { + return Stream.fromIterable([ + const LicenseEntryWithLineBreaks(['ABC'], 'DEF'), + ]); + }); + + addTearDown(() async { + await tester.binding.setSurfaceSize(null); + }); // Configure to show the default layout. await tester.binding.setSurfaceSize(defaultSize); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + title: title, + home: const Scaffold( + body: Directionality( + textDirection: textDirection, + child: LicensePage(), + ), + ), + ), + ); + + await tester.pumpAndSettle(); // Finish rendering the page. + + // If the layout width is less than 840.0 pixels, nested layout is + // used which positions license page title at the top center. + Offset titleOffset = tester.getCenter(find.text(title)); + expect(titleOffset, Offset(defaultSize.width / 2, 96.0)); + expect(tester.getCenter(find.byType(ListView)), Offset(defaultSize.width / 2, 328.0)); + + // Configure a wide window to show the lateral UI. + await tester.binding.setSurfaceSize(wideSize); + + await tester.pumpWidget( + const MaterialApp( + title: title, + home: Scaffold( + body: Directionality( + textDirection: textDirection, + child: LicensePage(), + ), + ), + ), + ); + + await tester.pumpAndSettle(); // Finish rendering the page. + + // If the layout width is greater than 840.0 pixels, lateral UI layout + // is used which positions license page title and packageList + // at the top left. + titleOffset = tester.getTopRight(find.text(title)); + expect(titleOffset, const Offset(292.0, 136.0)); + expect(titleOffset.dx, lessThan(wideSize.width - 320)); // Default master view width is 320.0. + expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgetsWithLeakTracking('LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1168,6 +1464,10 @@ void main() { ]); }); + addTearDown(() async { + await tester.binding.setSurfaceSize(null); + }); + // Configure to show the default layout. await tester.binding.setSurfaceSize(defaultSize); @@ -1216,9 +1516,71 @@ void main() { expect(titleOffset, const Offset(908.0, 136.0)); expect(titleOffset.dx, greaterThan(wideSize.width - 320)); // Default master view width is 320.0. expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); + }); + + testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + const TextDirection textDirection = TextDirection.rtl; + const Size defaultSize = Size(800.0, 600.0); + const Size wideSize = Size(1200.0, 600.0); + const String title = 'License ABC'; + LicenseRegistry.addLicense(() { + return Stream.fromIterable([ + const LicenseEntryWithLineBreaks(['ABC'], 'DEF'), + ]); + }); + + addTearDown(() async { + await tester.binding.setSurfaceSize(null); + }); // Configure to show the default layout. await tester.binding.setSurfaceSize(defaultSize); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + title: title, + home: const Scaffold( + body: Directionality( + textDirection: textDirection, + child: LicensePage(), + ), + ), + ), + ); + + await tester.pumpAndSettle(); // Finish rendering the page. + + // If the layout width is less than 840.0 pixels, nested layout is + // used which positions license page title at the top center. + Offset titleOffset = tester.getCenter(find.text(title)); + expect(titleOffset, Offset(defaultSize.width / 2, 96.0)); + expect(tester.getCenter(find.byType(ListView)), Offset(defaultSize.width / 2, 328.0)); + + // Configure a wide window to show the lateral UI. + await tester.binding.setSurfaceSize(wideSize); + + await tester.pumpWidget( + const MaterialApp( + title: title, + home: Scaffold( + body: Directionality( + textDirection: textDirection, + child: LicensePage(), + ), + ), + ), + ); + + await tester.pumpAndSettle(); // Finish rendering the page. + + // If the layout width is greater than 840.0 pixels, lateral UI layout + // is used which positions license page title and packageList + // at the top right. + titleOffset = tester.getTopLeft(find.text(title)); + expect(titleOffset, const Offset(908.0, 136.0)); + expect(titleOffset.dx, greaterThan(wideSize.width - 320)); // Default master view width is 320.0. + expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); testWidgetsWithLeakTracking('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { @@ -1234,6 +1596,10 @@ void main() { ]); }); + addTearDown(() async { + await tester.binding.setSurfaceSize(null); + }); + // Configure a wide window to show the lateral UI. await tester.binding.setSurfaceSize(const Size(1200.0, 600.0)); @@ -1256,9 +1622,6 @@ void main() { // License page title in the lateral UI uses default text style color. expect(renderParagraph.text.style!.color, theme.textTheme.titleLarge!.color); - - // Configure to show the default layout. - await tester.binding.setSurfaceSize(const Size(800.0, 600.0)); }); testWidgetsWithLeakTracking('License page default title text color in the nested UI', (WidgetTester tester) async { From 56da37106a4f54e95c6028944c0888465792e990 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Thu, 20 Jul 2023 18:34:43 +0200 Subject: [PATCH 0288/1547] Update AutoComplete test for M3 migration (#130883) This PR updates unit tests from autocomplete_test.dart for M3 migration. More info in https://github.com/flutter/flutter/issues/127064 I replaced magic numbers (64.0 and 187.0) and found ways to compute them without relying on the Material version. --- .../test/material/autocomplete_test.dart | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/packages/flutter/test/material/autocomplete_test.dart b/packages/flutter/test/material/autocomplete_test.dart index 45f028bc02237..4156a2f22ca74 100644 --- a/packages/flutter/test/material/autocomplete_test.dart +++ b/packages/flutter/test/material/autocomplete_test.dart @@ -459,9 +459,7 @@ void main() { const Color highlightColor = Color(0xFF112233); await tester.pumpWidget( MaterialApp( - theme: ThemeData.light(useMaterial3: false).copyWith( - focusColor: highlightColor, - ), + theme: ThemeData.light().copyWith(focusColor: highlightColor), home: Scaffold( body: Autocomplete( optionsBuilder: (TextEditingValue textEditingValue) { @@ -481,27 +479,39 @@ void main() { final ListView list = find.byType(ListView).evaluate().first.widget as ListView; expect(list.semanticChildCount, 6); - // Highlighted item should be at the top - expect(tester.getTopLeft(find.text('chameleon')).dy, equals(64.0)); + final Rect optionsGroupRect = tester.getRect(find.byType(ListView)); + const double optionsGroupPadding = 16.0; + + // Highlighted item should be at the top. checkOptionHighlight(tester, 'chameleon', highlightColor); + expect( + tester.getTopLeft(find.text('chameleon')).dy, + equals(optionsGroupRect.top + optionsGroupPadding), + ); - // Move down the list of options - await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pump(); - await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pump(); - await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pump(); - await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pump(); + // Move down the list of options. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Select 'elephant'. + await tester.pumpAndSettle(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Select 'goose'. + await tester.pumpAndSettle(); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Select 'lemur'. + await tester.pumpAndSettle(); - // First item should have scrolled off the top, and not be selected. - expect(find.text('chameleon'), findsNothing); + // Highlighted item 'lemur' should be centered in the options popup. + checkOptionHighlight(tester, 'lemur', highlightColor); + expect( + tester.getCenter(find.text('lemur')).dy, + equals(optionsGroupRect.center.dy), + ); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); // Select 'mouse'. + await tester.pumpAndSettle(); - // Highlighted item 'lemur' should be centered in the options popup - expect(tester.getTopLeft(find.text('mouse')).dy, equals(187.0)); checkOptionHighlight(tester, 'mouse', highlightColor); + // First item should have scrolled off the top, and not be selected. + expect(find.text('chameleon'), findsNothing); + // The other items on screen should not be selected. checkOptionHighlight(tester, 'goose', null); checkOptionHighlight(tester, 'lemur', null); From d4005a87acd6467a683fbb7689b0e2654ab83e29 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 12:34:43 -0400 Subject: [PATCH 0289/1547] Roll Flutter Engine from c645eb6da8a9 to 6d7842d25f81 (1 revision) (#130992) https://github.com/flutter/engine/compare/c645eb6da8a9...6d7842d25f81 2023-07-20 skia-flutter-autoroll@skia.org Roll Dart SDK from 603aacd8400f to 857c9a2ae14a (1 revision) (flutter/engine#43851) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 06a2ce4132eb7..8231b08aa16cc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c645eb6da8a9e3ca22d25a240b608fc643039a51 +6d7842d25f81004bbd3125ecbec167db69fa241f From 0ed17dd5a24676c897b5268da976717c22e68780 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Thu, 20 Jul 2023 09:34:46 -0700 Subject: [PATCH 0290/1547] Update `TextSelectionTheme`, `ThemeData`, `TimePicker`, and `TimePickerTheme` tests for M2/M3 (#130547) Updated unit tests for `TextSelectionTheme`, `ThemeData`, `TimePicker` and `TimePickerTheme` to have M2 and M3 versions. More info in #127064 --- .../material/text_selection_theme_test.dart | 72 ++- .../test/material/theme_defaults_test.dart | 84 ++- .../flutter/test/material/theme_test.dart | 57 +- .../test/material/time_picker_test.dart | 604 ++++++++++-------- .../test/material/time_picker_theme_test.dart | 554 +++++++++++----- 5 files changed, 901 insertions(+), 470 deletions(-) diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 42a11c12df071..7c767b5db17fc 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -60,12 +60,11 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Empty textSelectionTheme will use defaults', (WidgetTester tester) async { - final ThemeData theme = ThemeData(); - final bool material3 = theme.useMaterial3; - final Color defaultCursorColor = material3 ? theme.colorScheme.primary : const Color(0xff2196f3); - final Color defaultSelectionColor = material3 ? theme.colorScheme.primary.withOpacity(0.40) : const Color(0x662196f3); - final Color defaultSelectionHandleColor = material3 ? theme.colorScheme.primary : const Color(0xff2196f3); + testWidgetsWithLeakTracking('Material2 - Empty textSelectionTheme will use defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); + const Color defaultCursorColor = Color(0xff2196f3); + const Color defaultSelectionColor = Color(0x662196f3); + const Color defaultSelectionHandleColor = Color(0xff2196f3); EditableText.debugDeterministicCursor = true; addTearDown(() { @@ -91,6 +90,67 @@ void main() { // Test the selection handle color. await tester.pumpWidget( MaterialApp( + theme: theme, + home: Material( + child: Builder( + builder: (BuildContext context) { + return materialTextSelectionControls.buildHandle( + context, + TextSelectionHandleType.left, + 10.0, + ); + }, + ), + ), + ), + ); + await tester.pumpAndSettle(); + final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); + expect(handle, paints..path(color: defaultSelectionHandleColor)); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130469 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'ValueNotifier': 1, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, + 'ValueNotifier': 1, + }, + // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. + allowAllNotGCed: true, + )); + + testWidgetsWithLeakTracking('Material3 - Empty textSelectionTheme will use defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + final Color defaultCursorColor = theme.colorScheme.primary; + final Color defaultSelectionColor = theme.colorScheme.primary.withOpacity(0.40); + final Color defaultSelectionHandleColor = theme.colorScheme.primary; + + EditableText.debugDeterministicCursor = true; + addTearDown(() { + EditableText.debugDeterministicCursor = false; + }); + // Test TextField's cursor & selection color. + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Material( + child: TextField(autofocus: true), + ), + ), + ); + await tester.pump(); + await tester.pumpAndSettle(); + + final EditableTextState editableTextState = tester.firstState(find.byType(EditableText)); + final RenderEditable renderEditable = editableTextState.renderEditable; + expect(renderEditable.cursorColor, defaultCursorColor); + expect(renderEditable.selectionColor, defaultSelectionColor); + + // Test the selection handle color. + await tester.pumpWidget( + MaterialApp( + theme: theme, home: Material( child: Builder( builder: (BuildContext context) { diff --git a/packages/flutter/test/material/theme_defaults_test.dart b/packages/flutter/test/material/theme_defaults_test.dart index db8eec4b7e792..4f60fc1735629 100644 --- a/packages/flutter/test/material/theme_defaults_test.dart +++ b/packages/flutter/test/material/theme_defaults_test.dart @@ -14,9 +14,8 @@ void main() { const ShapeBorder defaultFABShapeM3 = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const EdgeInsets defaultFABPadding = EdgeInsets.zero; - testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { - final ThemeData theme = ThemeData.light(); - final bool material3 = theme.useMaterial3; + testWidgets('Material2 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( theme: theme, @@ -31,21 +30,48 @@ void main() { final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); expect(raw.enabled, true); - expect(raw.textStyle!.color, material3 ? theme.colorScheme.onPrimaryContainer : const Color(0xffffffff)); - expect(raw.fillColor, material3 ? theme.colorScheme.primaryContainer : const Color(0xff2196f3)); + expect(raw.textStyle!.color, const Color(0xffffffff)); + expect(raw.fillColor, const Color(0xff2196f3)); expect(raw.elevation, 6.0); - expect(raw.highlightElevation, material3 ? 6.0 : 12.0); + expect(raw.highlightElevation, 12.0); expect(raw.disabledElevation, 6.0); expect(raw.constraints, defaultFABConstraints); expect(raw.padding, defaultFABPadding); - expect(raw.shape, material3 ? defaultFABShapeM3 : defaultFABShape); + expect(raw.shape, defaultFABShape); expect(raw.animationDuration, defaultButtonDuration); expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); - testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { - final ThemeData theme = ThemeData.light(); - final bool material3 = theme.useMaterial3; + testWidgets('Material3 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Center( + child: FloatingActionButton( + onPressed: () { }, // button.enabled == true + child: const Icon(Icons.add), + ), + ), + ), + ); + + final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); + expect(raw.enabled, true); + expect(raw.textStyle!.color, theme.colorScheme.onPrimaryContainer); + expect(raw.fillColor, theme.colorScheme.primaryContainer); + expect(raw.elevation, 6.0); + expect(raw.highlightElevation, 6.0); + expect(raw.disabledElevation, 6.0); + expect(raw.constraints, defaultFABConstraints); + expect(raw.padding, defaultFABPadding); + expect(raw.shape, defaultFABShapeM3); + expect(raw.animationDuration, defaultButtonDuration); + expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); + }); + + testWidgets('Material2 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( theme: theme, @@ -60,16 +86,46 @@ void main() { final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); expect(raw.enabled, false); - expect(raw.textStyle!.color, material3 ? theme.colorScheme.onPrimaryContainer : const Color(0xffffffff)); - expect(raw.fillColor, material3 ? theme.colorScheme.primaryContainer : const Color(0xff2196f3)); + expect(raw.textStyle!.color, const Color(0xffffffff)); + expect(raw.fillColor, const Color(0xff2196f3)); + // highlightColor, disabled button can't be pressed + // splashColor, disabled button doesn't splash + expect(raw.elevation, 6.0); + expect(raw.highlightElevation, 12.0); + expect(raw.disabledElevation, 6.0); + expect(raw.constraints, defaultFABConstraints); + expect(raw.padding, defaultFABPadding); + expect(raw.shape, defaultFABShape); + expect(raw.animationDuration, defaultButtonDuration); + expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); + }); + + testWidgets('Material3 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Center( + child: FloatingActionButton( + onPressed: null, // button.enabled == false + child: Icon(Icons.add), + ), + ), + ), + ); + + final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); + expect(raw.enabled, false); + expect(raw.textStyle!.color, theme.colorScheme.onPrimaryContainer); + expect(raw.fillColor, theme.colorScheme.primaryContainer); // highlightColor, disabled button can't be pressed // splashColor, disabled button doesn't splash expect(raw.elevation, 6.0); - expect(raw.highlightElevation, material3 ? 6.0 : 12.0); + expect(raw.highlightElevation, 6.0); expect(raw.disabledElevation, 6.0); expect(raw.constraints, defaultFABConstraints); expect(raw.padding, defaultFABPadding); - expect(raw.shape, material3 ? defaultFABShapeM3 : defaultFABShape); + expect(raw.shape, defaultFABShapeM3); expect(raw.animationDuration, defaultButtonDuration); expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index 1cbcbca3002bf..63d133a0090f5 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -96,8 +96,7 @@ void main() { expect(tester.widget(find.byType(EditableText)).cursorColor, themeCursorColor); }); - testWidgets('Fallback theme', (WidgetTester tester) async { - // For material 2 + testWidgets('Material2 - Fallback theme', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( Theme( @@ -112,8 +111,9 @@ void main() { ); expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(useMaterial3: false), defaultGeometryTheme))); + }); - // For material 3 + testWidgets('Material3 - Fallback theme', (WidgetTester tester) async { late BuildContext capturedContextM3; await tester.pumpWidget( Theme( @@ -153,9 +153,12 @@ void main() { ); }); - testWidgets('ThemeData with null typography uses proper defaults', (WidgetTester tester) async { + testWidgets('Material2 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { final ThemeData m2Theme = ThemeData(useMaterial3: false); expect(m2Theme.typography, Typography.material2014()); + }); + + testWidgets('Material3 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { final ThemeData m3Theme = ThemeData(useMaterial3: true); expect(m3Theme.typography, Typography.material2021(colorScheme: m3Theme.colorScheme)); }); @@ -436,7 +439,7 @@ void main() { expect(actualFontSize, kMagicFontSize); }); - testWidgets('Default Theme provides all basic TextStyle properties - M2', (WidgetTester tester) async { + testWidgets('Material2 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { late ThemeData theme; await tester.pumpWidget(Theme( data: ThemeData(useMaterial3: false), @@ -494,7 +497,7 @@ void main() { expect(theme.textTheme.displayLarge!.debugLabel, '(englishLike displayLarge 2014).merge(blackMountainView displayLarge)'); }); - testWidgets('Default Theme provides all basic TextStyle properties - M3', (WidgetTester tester) async { + testWidgets('Material3 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { late ThemeData theme; await tester.pumpWidget(Theme( data: ThemeData(useMaterial3: true), @@ -579,9 +582,8 @@ void main() { context = null; }); - testWidgets('Default light theme has defaults', (WidgetTester tester) async { + testWidgets('Material2 - Default light theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData(useMaterial3: false)); - final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData(useMaterial3: true)); expect(themeM2.brightness, Brightness.light); expect(themeM2.primaryColor, Colors.blue); @@ -589,6 +591,10 @@ void main() { expect(themeM2.primaryContrastingColor, Colors.white); expect(themeM2.textTheme.textStyle.fontFamily, '.SF Pro Text'); expect(themeM2.textTheme.textStyle.fontSize, 17.0); + }); + + testWidgets('Material3 - Default light theme has defaults', (WidgetTester tester) async { + final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData(useMaterial3: true)); expect(themeM3.brightness, Brightness.light); expect(themeM3.primaryColor, const Color(0xff6750a4)); @@ -598,9 +604,8 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Dark theme has defaults', (WidgetTester tester) async { + testWidgets('Material2 - Dark theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData.dark(useMaterial3: false)); - final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData.dark(useMaterial3: true)); expect(themeM2.brightness, Brightness.dark); expect(themeM2.primaryColor, Colors.blue); @@ -608,6 +613,10 @@ void main() { expect(themeM2.scaffoldBackgroundColor, Colors.grey[850]); expect(themeM2.textTheme.textStyle.fontFamily, '.SF Pro Text'); expect(themeM2.textTheme.textStyle.fontSize, 17.0); + }); + + testWidgets('Material3 - Dark theme has defaults', (WidgetTester tester) async { + final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData.dark(useMaterial3: true)); expect(themeM3.brightness, Brightness.dark); expect(themeM3.primaryColor, const Color(0xffd0bcff)); @@ -638,7 +647,7 @@ void main() { expect(CupertinoTheme.brightnessOf(context!), Brightness.light); }); - testWidgets('Can override material theme', (WidgetTester tester) async { + testWidgets('Material2 - Can override material theme', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( scaffoldBackgroundColor: CupertinoColors.lightBackgroundGray, @@ -654,7 +663,9 @@ void main() { expect(themeM2.scaffoldBackgroundColor, CupertinoColors.lightBackgroundGray); expect(themeM2.textTheme.textStyle.fontFamily, '.SF Pro Text'); expect(themeM2.textTheme.textStyle.fontSize, 17.0); + }); + testWidgets('Material3 - Can override material theme', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( scaffoldBackgroundColor: CupertinoColors.lightBackgroundGray, @@ -672,7 +683,7 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Can override properties that are independent of material', (WidgetTester tester) async { + testWidgets('Material2 - Can override properties that are independent of material', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( // The bar colors ignore all things material except brightness. @@ -684,7 +695,9 @@ void main() { expect(themeM2.primaryColor, Colors.blue); // MaterialBasedCupertinoThemeData should also function like a normal CupertinoThemeData. expect(themeM2.barBackgroundColor, CupertinoColors.black); + }); + testWidgets('Material3 - Can override properties that are independent of material', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( // The bar colors ignore all things material except brightness. @@ -698,7 +711,7 @@ void main() { expect(themeM3.barBackgroundColor, CupertinoColors.black); }); - testWidgets('Changing material theme triggers rebuilds - M2', (WidgetTester tester) async { + testWidgets('Material2 - Changing material theme triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( useMaterial3: false, primarySwatch: Colors.red, @@ -716,7 +729,7 @@ void main() { expect(themeM2.primaryColor, Colors.orange); }); - testWidgets('Changing material theme triggers rebuilds - M3', (WidgetTester tester) async { + testWidgets('Material3 - Changing material theme triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( useMaterial3: true, colorScheme: const ColorScheme.light( @@ -745,8 +758,8 @@ void main() { const Color cupertinoIconColor = Colors.black; await testTheme(tester, ThemeData( - iconTheme: const IconThemeData(color: materialIconColor), - cupertinoOverrideTheme: const CupertinoThemeData(primaryColor: cupertinoIconColor), + iconTheme: const IconThemeData(color: materialIconColor), + cupertinoOverrideTheme: const CupertinoThemeData(primaryColor: cupertinoIconColor), )); expect(buildCount, 1); @@ -807,7 +820,7 @@ void main() { ); testWidgets( - 'Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden - M2', + 'Material2 - Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( useMaterial3: false, @@ -836,7 +849,7 @@ void main() { ); testWidgets( - 'Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden - M3', + 'Material3 - Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( useMaterial3: true, @@ -869,7 +882,7 @@ void main() { ); testWidgets( - 'copyWith only copies the overrides, not the material or cupertino derivatives - M2', + 'Material2 - copyWith only copies the overrides, not the material or cupertino derivatives', (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: false, @@ -896,7 +909,7 @@ void main() { ); testWidgets( - 'copyWith only copies the overrides, not the material or cupertino derivatives - M3', + 'Material3 - copyWith only copies the overrides, not the material or cupertino derivatives', (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: true, @@ -923,7 +936,7 @@ void main() { ); testWidgets( - "Material themes with no cupertino overrides can also be copyWith'ed - M2", + "Material2 - Material themes with no cupertino overrides can also be copyWith'ed", (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: false, @@ -946,7 +959,7 @@ void main() { ); testWidgets( - "Material themes with no cupertino overrides can also be copyWith'ed - M3", + "Material3 - Material themes with no cupertino overrides can also be copyWith'ed", (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: true, diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index b17d2e46d1303..1cb1c9a419c73 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -16,24 +16,216 @@ import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; void main() { - for (final MaterialType materialType in MaterialType.values) { - final String selectTimeString; - final String enterTimeString; - final String cancelString; - const String okString = 'OK'; - const String amString = 'AM'; - const String pmString = 'PM'; - switch (materialType) { - case MaterialType.material2: - selectTimeString = 'SELECT TIME'; - enterTimeString = 'ENTER TIME'; - cancelString = 'CANCEL'; - case MaterialType.material3: - selectTimeString = 'Select time'; - enterTimeString = 'Enter time'; - cancelString = 'Cancel'; - } + const String okString = 'OK'; + const String amString = 'AM'; + const String pmString = 'PM'; + Material getMaterialFromDialog(WidgetTester tester) { + return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first); + } + + testWidgets('Material2 - Dialog size - dial mode', (WidgetTester tester) async { + addTearDown(tester.view.reset); + + const Size timePickerPortraitSize = Size(310, 468); + const Size timePickerLandscapeSize = Size(524, 342); + const Size timePickerLandscapeSizeM2 = Size(508, 300); + const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8); + double width; + double height; + + // portrait + tester.view.physicalSize = const Size(800, 800.5); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate(tester, materialType: MaterialType.material2); + + width = timePickerPortraitSize.width + padding.horizontal; + height = timePickerPortraitSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + // landscape + tester.view.physicalSize = const Size(800.5, 800); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + materialType: MaterialType.material2, + ); + + width = timePickerLandscapeSize.width + padding.horizontal; + height = timePickerLandscapeSizeM2.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material2 - Dialog size - input mode', (WidgetTester tester) async { + const TimePickerEntryMode entryMode = TimePickerEntryMode.input; + const Size timePickerInputSize = Size(312, 216); + const Size dayPeriodPortraitSize = Size(52, 80); + const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8); + final double height = timePickerInputSize.height + padding.vertical; + double width; + + await mediaQueryBoilerplate( + tester, + entryMode: entryMode, + materialType: MaterialType.material2, + ); + + width = timePickerInputSize.width + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + entryMode: entryMode, + materialType: MaterialType.material2, + ); + width = timePickerInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal + 16; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + testWidgets('Material2 - respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material2); + + final List labels00To22 = List.generate(12, (int index) { + return (index * 2).toString().padLeft(2, '0'); + }); + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + // ignore: avoid_dynamic_calls + expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); + + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + // ignore: avoid_dynamic_calls + expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); + }); + + testWidgets('Material3 - Dialog size - dial mode', (WidgetTester tester) async { + addTearDown(tester.view.reset); + + const Size timePickerPortraitSize = Size(310, 468); + const Size timePickerLandscapeSize = Size(524, 342); + const EdgeInsets padding = EdgeInsets.all(24.0); + double width; + double height; + + // portrait + tester.view.physicalSize = const Size(800, 800.5); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate(tester, materialType: MaterialType.material3); + + width = timePickerPortraitSize.width + padding.horizontal; + height = timePickerPortraitSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + // landscape + tester.view.physicalSize = const Size(800.5, 800); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + materialType: MaterialType.material3, + ); + + width = timePickerLandscapeSize.width + padding.horizontal; + height = timePickerLandscapeSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material3 - Dialog size - input mode', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + const TimePickerEntryMode entryMode = TimePickerEntryMode.input; + const double textScaleFactor = 1.0; + const Size timePickerMinInputSize = Size(312, 216); + const Size dayPeriodPortraitSize = Size(52, 80); + const EdgeInsets padding = EdgeInsets.all(24.0); + final double height = timePickerMinInputSize.height * textScaleFactor + padding.vertical; + double width; + + await mediaQueryBoilerplate( + tester, + entryMode: entryMode, + materialType: MaterialType.material3, + ); + + width = timePickerMinInputSize.width - (theme.useMaterial3 ? 32 : 0) + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + entryMode: entryMode, + materialType: MaterialType.material3, + ); + + width = timePickerMinInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material3 - respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material3); + + final List labels00To23 = List.generate(24, (int index) { + return index == 0 ? '00' : index.toString(); + }); + final List inner0To23 = List.generate(24, (int index) => index >= 12); + + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + // ignore: avoid_dynamic_calls + expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); + // ignore: avoid_dynamic_calls + expect(primaryLabels.map((dynamic tp) => tp.inner as bool), inner0To23); + + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + // ignore: avoid_dynamic_calls + expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); + // ignore: avoid_dynamic_calls + expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); + }); + + for (final MaterialType materialType in MaterialType.values) { group('Dial (${materialType.name})', () { testWidgets('tap-select an hour', (WidgetTester tester) async { TimeOfDay? result; @@ -280,21 +472,32 @@ void main() { }); group('Dialog (${materialType.name})', () { - Material getMaterialFromDialog(WidgetTester tester) { - return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first); - } - - testWidgets('Widgets have correct label capitalization', (WidgetTester tester) async { - await startPicker(tester, (TimeOfDay? time) {}, materialType: materialType); - expect(find.text(selectTimeString), findsOneWidget); - expect(find.text(cancelString), findsOneWidget); + testWidgets('Material2 - Widgets have correct label capitalization', (WidgetTester tester) async { + await startPicker(tester, (TimeOfDay? time) {}, materialType: MaterialType.material2); + expect(find.text('SELECT TIME'), findsOneWidget); + expect(find.text('CANCEL'), findsOneWidget); }); - testWidgets('Widgets have correct label capitalization in input mode', (WidgetTester tester) async { + testWidgets('Material3 - Widgets have correct label capitalization', (WidgetTester tester) async { + await startPicker(tester, (TimeOfDay? time) {}, materialType: MaterialType.material3); + expect(find.text('Select time'), findsOneWidget); + expect(find.text('Cancel'), findsOneWidget); + }); + + testWidgets('Material2 - Widgets have correct label capitalization in input mode', (WidgetTester tester) async { await startPicker(tester, (TimeOfDay? time) {}, - entryMode: TimePickerEntryMode.input, materialType: materialType); - expect(find.text(enterTimeString), findsOneWidget); - expect(find.text(cancelString), findsOneWidget); + entryMode: TimePickerEntryMode.input, materialType: MaterialType.material2 + ); + expect(find.text('ENTER TIME'), findsOneWidget); + expect(find.text('CANCEL'), findsOneWidget); + }); + + testWidgets('Material3 - Widgets have correct label capitalization in input mode', (WidgetTester tester) async { + await startPicker(tester, (TimeOfDay? time) {}, + entryMode: TimePickerEntryMode.input, materialType: MaterialType.material3 + ); + expect(find.text('Enter time'), findsOneWidget); + expect(find.text('Cancel'), findsOneWidget); }); testWidgets('respects MediaQueryData.alwaysUse24HourFormat == false', (WidgetTester tester) async { @@ -314,211 +517,6 @@ void main() { expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels12To11); }); - switch (materialType) { - case MaterialType.material2: - testWidgets('Dialog size - dial mode', (WidgetTester tester) async { - addTearDown(tester.view.reset); - - const Size timePickerPortraitSize = Size(310, 468); - const Size timePickerLandscapeSize = Size(524, 342); - const Size timePickerLandscapeSizeM2 = Size(508, 300); - const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8); - double width; - double height; - - // portrait - tester.view.physicalSize = const Size(800, 800.5); - tester.view.devicePixelRatio = 1; - await mediaQueryBoilerplate(tester, materialType: materialType); - - width = timePickerPortraitSize.width + padding.horizontal; - height = timePickerPortraitSize.height + padding.vertical; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - - await tester.tap(find.text(okString)); // dismiss the dialog - await tester.pumpAndSettle(); - - // landscape - tester.view.physicalSize = const Size(800.5, 800); - tester.view.devicePixelRatio = 1; - await mediaQueryBoilerplate( - tester, - alwaysUse24HourFormat: true, - materialType: materialType, - ); - - width = timePickerLandscapeSize.width + padding.horizontal; - height = timePickerLandscapeSizeM2.height + padding.vertical; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - }); - - testWidgets('Dialog size - input mode', (WidgetTester tester) async { - const TimePickerEntryMode entryMode = TimePickerEntryMode.input; - const Size timePickerInputSize = Size(312, 216); - const Size dayPeriodPortraitSize = Size(52, 80); - const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8); - final double height = timePickerInputSize.height + padding.vertical; - double width; - - await mediaQueryBoilerplate( - tester, - entryMode: entryMode, - materialType: materialType, - ); - - width = timePickerInputSize.width + padding.horizontal; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - - await tester.tap(find.text(okString)); // dismiss the dialog - await tester.pumpAndSettle(); - - await mediaQueryBoilerplate( - tester, - alwaysUse24HourFormat: true, - entryMode: entryMode, - materialType: materialType, - ); - width = timePickerInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal + 16; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - }); - - testWidgets('respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { - await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: materialType); - - final List labels00To22 = List.generate(12, (int index) { - return (index * 2).toString().padLeft(2, '0'); - }); - final CustomPaint dialPaint = tester.widget(findDialPaint); - final dynamic dialPainter = dialPaint.painter; - // ignore: avoid_dynamic_calls - final List primaryLabels = dialPainter.primaryLabels as List; - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); - - // ignore: avoid_dynamic_calls - final List selectedLabels = dialPainter.selectedLabels as List; - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); - }); - case MaterialType.material3: - testWidgets('Dialog size - dial mode', (WidgetTester tester) async { - addTearDown(tester.view.reset); - - const Size timePickerPortraitSize = Size(310, 468); - const Size timePickerLandscapeSize = Size(524, 342); - const EdgeInsets padding = EdgeInsets.all(24.0); - double width; - double height; - - // portrait - tester.view.physicalSize = const Size(800, 800.5); - tester.view.devicePixelRatio = 1; - await mediaQueryBoilerplate(tester, materialType: materialType); - - width = timePickerPortraitSize.width + padding.horizontal; - height = timePickerPortraitSize.height + padding.vertical; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - - await tester.tap(find.text(okString)); // dismiss the dialog - await tester.pumpAndSettle(); - - // landscape - tester.view.physicalSize = const Size(800.5, 800); - tester.view.devicePixelRatio = 1; - await mediaQueryBoilerplate( - tester, - alwaysUse24HourFormat: true, - materialType: materialType, - ); - - width = timePickerLandscapeSize.width + padding.horizontal; - height = timePickerLandscapeSize.height + padding.vertical; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - }); - - testWidgets('Dialog size - input mode', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); - const TimePickerEntryMode entryMode = TimePickerEntryMode.input; - const double textScaleFactor = 1.0; - const Size timePickerMinInputSize = Size(312, 216); - const Size dayPeriodPortraitSize = Size(52, 80); - const EdgeInsets padding = EdgeInsets.all(24.0); - final double height = timePickerMinInputSize.height * textScaleFactor + padding.vertical; - double width; - - await mediaQueryBoilerplate( - tester, - entryMode: entryMode, - materialType: materialType, - ); - - width = timePickerMinInputSize.width - (theme.useMaterial3 ? 32 : 0) + padding.horizontal; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - - await tester.tap(find.text(okString)); // dismiss the dialog - await tester.pumpAndSettle(); - - await mediaQueryBoilerplate( - tester, - alwaysUse24HourFormat: true, - entryMode: entryMode, - materialType: materialType, - ); - - width = timePickerMinInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal; - expect( - tester.getSize(find.byWidget(getMaterialFromDialog(tester))), - Size(width, height), - ); - }); - - testWidgets('respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { - await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: materialType); - - final List labels00To23 = List.generate(24, (int index) { - return index == 0 ? '00' : index.toString(); - }); - final List inner0To23 = List.generate(24, (int index) => index >= 12); - - final CustomPaint dialPaint = tester.widget(findDialPaint); - final dynamic dialPainter = dialPaint.painter; - // ignore: avoid_dynamic_calls - final List primaryLabels = dialPainter.primaryLabels as List; - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.inner as bool), inner0To23); - - // ignore: avoid_dynamic_calls - final List selectedLabels = dialPainter.selectedLabels as List; - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); - }); - } - testWidgets('when change orientation, should reflect in render objects', (WidgetTester tester) async { addTearDown(tester.view.reset); @@ -708,10 +706,12 @@ void main() { expect(find.text(helperText), findsOneWidget); }); - testWidgets('OK Cancel button and helpText layout', (WidgetTester tester) async { + testWidgets('Material2 - OK Cancel button and helpText layout', (WidgetTester tester) async { + const String selectTimeString = 'SELECT TIME'; + const String cancelString = 'CANCEL'; Widget buildFrame(TextDirection textDirection) { return MaterialApp( - theme: ThemeData(useMaterial3: materialType == MaterialType.material3), + theme: ThemeData(useMaterial3: false), home: Material( child: Center( child: Builder( @@ -742,21 +742,13 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(); - switch (materialType) { - case MaterialType.material2: - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals( - ParagraphBuilder.shouldDisableRoundingHack ? const Offset(280.5, 165) : const Offset(281, 165), - )); - expect(tester.getBottomRight(find.text(okString)).dx, 644); - expect(tester.getBottomLeft(find.text(okString)).dx, 616); - expect(tester.getBottomRight(find.text(cancelString)).dx, 582); - case MaterialType.material3: - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(138, 129))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(295.0, 149.0))); - expect(tester.getBottomLeft(find.text(okString)).dx, 615.5); - expect(tester.getBottomRight(find.text(cancelString)).dx, 578); - } + expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155))); + expect(tester.getBottomRight(find.text(selectTimeString)), equals( + ParagraphBuilder.shouldDisableRoundingHack ? const Offset(280.5, 165) : const Offset(281, 165), + )); + expect(tester.getBottomRight(find.text(okString)).dx, 644); + expect(tester.getBottomLeft(find.text(okString)).dx, 616); + expect(tester.getBottomRight(find.text(cancelString)).dx, 582); await tester.tap(find.text(okString)); await tester.pumpAndSettle(); @@ -765,23 +757,72 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(); - switch (materialType) { - case MaterialType.material2: - expect(tester.getTopLeft(find.text(selectTimeString)), equals( - ParagraphBuilder.shouldDisableRoundingHack ? const Offset(519.5, 155) : const Offset(519, 155), - )); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165))); - expect(tester.getBottomLeft(find.text(okString)).dx, 156); - expect(tester.getBottomRight(find.text(okString)).dx, 184); - expect(tester.getBottomLeft(find.text(cancelString)).dx, 218); - case MaterialType.material3: - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(505.0, 129.0))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(662, 149))); - expect(tester.getBottomLeft(find.text(okString)).dx, 155.5); - expect(tester.getBottomRight(find.text(okString)).dx, 184.5); - expect(tester.getBottomLeft(find.text(cancelString)).dx, 222); + expect(tester.getTopLeft(find.text(selectTimeString)), equals( + ParagraphBuilder.shouldDisableRoundingHack ? const Offset(519.5, 155) : const Offset(519, 155), + )); + expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165))); + expect(tester.getBottomLeft(find.text(okString)).dx, 156); + expect(tester.getBottomRight(find.text(okString)).dx, 184); + expect(tester.getBottomLeft(find.text(cancelString)).dx, 218); + + await tester.tap(find.text(okString)); + await tester.pumpAndSettle(); + }); + + testWidgets('Material3 - OK Cancel button and helpText layout', (WidgetTester tester) async { + const String selectTimeString = 'Select time'; + const String cancelString = 'Cancel'; + Widget buildFrame(TextDirection textDirection) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () { + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + builder: (BuildContext context, Widget? child) { + return Directionality( + textDirection: textDirection, + child: child!, + ); + }, + ); + }, + ); + }, + ), + ), + ), + ); } + await tester.pumpWidget(buildFrame(TextDirection.ltr)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(138, 129))); + expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(295.0, 149.0))); + expect(tester.getBottomLeft(find.text(okString)).dx, 615.5); + expect(tester.getBottomRight(find.text(cancelString)).dx, 578); + + await tester.tap(find.text(okString)); + await tester.pumpAndSettle(); + + await tester.pumpWidget(buildFrame(TextDirection.rtl)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(505.0, 129.0))); + expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(662, 149))); + expect(tester.getBottomLeft(find.text(okString)).dx, 155.5); + expect(tester.getBottomRight(find.text(okString)).dx, 184.5); + expect(tester.getBottomLeft(find.text(cancelString)).dx, 222); + await tester.tap(find.text(okString)); await tester.pumpAndSettle(); }); @@ -996,9 +1037,34 @@ void main() { semantics.dispose(); }); - testWidgets('provides semantics information for header and footer', (WidgetTester tester) async { + testWidgets('Material2 - provides semantics information for header and footer', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: materialType); + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material2); + + expect(semantics, isNot(includesNodeWith(label: ':'))); + expect( + semantics.nodesWith(value: 'Select minutes 00'), + hasLength(1), + reason: '00 appears once in the header', + ); + expect( + semantics.nodesWith(value: 'Select hours 07'), + hasLength(1), + reason: '07 appears once in the header', + ); + expect(semantics, includesNodeWith(label: 'CANCEL')); + expect(semantics, includesNodeWith(label: okString)); + + // In 24-hour mode we don't have AM/PM control. + expect(semantics, isNot(includesNodeWith(label: amString))); + expect(semantics, isNot(includesNodeWith(label: pmString))); + + semantics.dispose(); + }); + + testWidgets('Material3 - provides semantics information for header and footer', (WidgetTester tester) async { + final SemanticsTester semantics = SemanticsTester(tester); + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material3); expect(semantics, isNot(includesNodeWith(label: ':'))); expect( @@ -1011,7 +1077,7 @@ void main() { hasLength(1), reason: '07 appears once in the header', ); - expect(semantics, includesNodeWith(label: cancelString)); + expect(semantics, includesNodeWith(label: 'Cancel')); expect(semantics, includesNodeWith(label: okString)); // In 24-hour mode we don't have AM/PM control. diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index dd2e5576908be..2c7ba77af88c0 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -98,89 +98,64 @@ void main() { ]); }); - testWidgets('Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { - final ThemeData defaultTheme = ThemeData(); - final bool material3 = defaultTheme.useMaterial3; + testWidgets('Material2 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final Material dialogMaterial = _dialogMaterial(tester); expect(dialogMaterial.color, defaultTheme.colorScheme.surface); - expect(dialogMaterial.shape, material3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))) - : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) + expect( + dialogMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), ); final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); expect( dial, - material3 - ? (paints - ..circle(color: defaultTheme.colorScheme.surfaceVariant.withOpacity(0.08)) // Dial background color. - ..circle(color: Color(defaultTheme.colorScheme.primary.value))) - : (paints - ..circle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.08)) // Dial background color. - ..circle(color: Color(defaultTheme.colorScheme.primary.value))), // Dial hand color. + paints + ..circle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.08)) // Dial background color. + ..circle(color: Color(defaultTheme.colorScheme.primary.value)) ); final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - material3 - ? (Typography.material2021().englishLike.displayLarge! - .merge(Typography.material2021().black.displayLarge) - .copyWith(color: defaultTheme.colorScheme.onPrimaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.displayMedium! - .merge(Typography.material2014().black.displayMedium) - .copyWith(color: defaultTheme.colorScheme.primary)), + Typography.material2014().englishLike.displayMedium! + .merge(Typography.material2014().black.displayMedium) + .copyWith(color: defaultTheme.colorScheme.primary) ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - material3 - ? (Typography.material2021().englishLike.displayLarge! - .merge(Typography.material2021().black.displayLarge) - .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.displayMedium! - .merge(Typography.material2014().black.displayMedium) - .copyWith(color: defaultTheme.colorScheme.onSurface)), + Typography.material2014().englishLike.displayMedium! + .merge(Typography.material2014().black.displayMedium) + .copyWith(color: defaultTheme.colorScheme.onSurface), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, - material3 - ? (Typography.material2021().englishLike.titleMedium! - .merge(Typography.material2021().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.onTertiaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.primary)), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .copyWith(color: defaultTheme.colorScheme.primary), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, - material3 - ? (Typography.material2021().englishLike.titleMedium! - .merge(Typography.material2021().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.onTertiaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6))), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6)), ); - final RenderParagraph helperText = _textRenderParagraph(tester, material3 ? 'Select time' : 'SELECT TIME'); + final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME'); expect( helperText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.labelSmall! - .merge(Typography.material2014().black.labelSmall)), + Typography.material2014().englishLike.labelSmall! + .merge(Typography.material2014().black.labelSmall), ); final CustomPaint dialPaint = tester.widget(findDialPaint); @@ -190,44 +165,36 @@ void main() { expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().black.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onSurface)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().black.bodyLarge) + .copyWith(color: defaultTheme.colorScheme.onSurface), ); // ignore: avoid_dynamic_calls final List selectedLabels = dialPainter.selectedLabels as List; expect( // ignore: avoid_dynamic_calls selectedLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onPrimary, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().white.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onPrimary)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().white.bodyLarge) + .copyWith(color: defaultTheme.colorScheme.onPrimary), ); final Material hourMaterial = _textMaterial(tester, '7'); - expect(hourMaterial.color, material3 ? defaultTheme.colorScheme.primaryContainer : defaultTheme.colorScheme.primary.withOpacity(0.12)); - expect(hourMaterial.shape, material3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) - : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) + expect(hourMaterial.color, defaultTheme.colorScheme.primary.withOpacity(0.12)); + expect( + hourMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), ); final Material minuteMaterial = _textMaterial(tester, '15'); - expect(minuteMaterial.color, material3 ? defaultTheme.colorScheme.surfaceVariant : defaultTheme.colorScheme.onSurface.withOpacity(0.12)); - expect(minuteMaterial.shape, material3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) - : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) + expect(minuteMaterial.color, defaultTheme.colorScheme.onSurface.withOpacity(0.12)); + expect( + minuteMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), ); final Material amMaterial = _textMaterial(tester, 'AM'); - expect(amMaterial.color, material3 ? defaultTheme.colorScheme.tertiaryContainer : defaultTheme.colorScheme.primary.withOpacity(0.12)); + expect(amMaterial.color, defaultTheme.colorScheme.primary.withOpacity(0.12)); final Material pmMaterial = _textMaterial(tester, 'PM'); expect(pmMaterial.color, Colors.transparent); @@ -239,61 +206,245 @@ void main() { final Material dayPeriodMaterial = _dayPeriodMaterial(tester); expect( dayPeriodMaterial.shape, - material3 - ? RoundedRectangleBorder( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - side: BorderSide(color: defaultTheme.colorScheme.outline), - ) : RoundedRectangleBorder( - borderRadius: const BorderRadius.all(Radius.circular(4.0)), - side: BorderSide(color: expectedBorderColor), - ), + RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(4.0)), + side: BorderSide(color: expectedBorderColor), + ), ); final Container dayPeriodDivider = _dayPeriodDivider(tester); expect( dayPeriodDivider.decoration, - material3 - ? BoxDecoration(border: Border(left: BorderSide(color: defaultTheme.colorScheme.outline))) - : BoxDecoration(border: Border(left: BorderSide(color: expectedBorderColor))), + BoxDecoration(border: Border(left: BorderSide(color: expectedBorderColor))), ); final IconButton entryModeIconButton = _entryModeIconButton(tester); expect( entryModeIconButton.color, - material3 ? null : defaultTheme.colorScheme.onSurface.withOpacity(0.6), + defaultTheme.colorScheme.onSurface.withOpacity(0.6), + ); + }); + + testWidgets('Material3 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: true); + await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final Material dialogMaterial = _dialogMaterial(tester); + expect(dialogMaterial.color, defaultTheme.colorScheme.surface); + expect( + dialogMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))), + ); + + final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); + expect( + dial, + paints + ..circle(color: defaultTheme.colorScheme.surfaceVariant.withOpacity(0.08)) // Dial background color. + ..circle(color: Color(defaultTheme.colorScheme.primary.value)), // Dial hand color. + ); + + final RenderParagraph hourText = _textRenderParagraph(tester, '7'); + expect( + hourText.text.style, + Typography.material2021().englishLike.displayLarge! + .merge(Typography.material2021().black.displayLarge) + .copyWith( + color: defaultTheme.colorScheme.onPrimaryContainer, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); + expect( + minuteText.text.style, + Typography.material2021().englishLike.displayLarge! + .merge(Typography.material2021().black.displayLarge) + .copyWith( + color: defaultTheme.colorScheme.onSurface, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); + expect( + amText.text.style, + Typography.material2021().englishLike.titleMedium! + .merge(Typography.material2021().black.titleMedium) + .copyWith( + color: defaultTheme.colorScheme.onTertiaryContainer, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); + expect( + pmText.text.style, + Typography.material2021().englishLike.titleMedium! + .merge(Typography.material2021().black.titleMedium) + .copyWith( + color: defaultTheme.colorScheme.onTertiaryContainer, + decorationColor: defaultTheme.colorScheme.onSurface + ) + ); + + final RenderParagraph helperText = _textRenderParagraph(tester, 'Select time'); + expect( + helperText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .copyWith( + color: defaultTheme.colorScheme.onSurface, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + expect( + // ignore: avoid_dynamic_calls + primaryLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith( + color: defaultTheme.colorScheme.onSurface, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + expect( + // ignore: avoid_dynamic_calls + selectedLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith( + color: defaultTheme.colorScheme.onPrimary, + decorationColor: defaultTheme.colorScheme.onSurface, + ), + ); + + final Material hourMaterial = _textMaterial(tester, '7'); + expect(hourMaterial.color, defaultTheme.colorScheme.primaryContainer); + expect( + hourMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) + ); + + final Material minuteMaterial = _textMaterial(tester, '15'); + expect(minuteMaterial.color, defaultTheme.colorScheme.surfaceVariant); + expect( + minuteMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), + ); + + final Material amMaterial = _textMaterial(tester, 'AM'); + expect(amMaterial.color, defaultTheme.colorScheme.tertiaryContainer); + + final Material pmMaterial = _textMaterial(tester, 'PM'); + expect(pmMaterial.color, Colors.transparent); + + final Material dayPeriodMaterial = _dayPeriodMaterial(tester); + expect( + dayPeriodMaterial.shape, + RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + side: BorderSide(color: defaultTheme.colorScheme.outline), + ), + ); + + final Container dayPeriodDivider = _dayPeriodDivider(tester); + expect( + dayPeriodDivider.decoration, + BoxDecoration(border: Border(left: BorderSide(color: defaultTheme.colorScheme.outline))), ); + + final IconButton entryModeIconButton = _entryModeIconButton(tester); + expect(entryModeIconButton.color, null); }); + testWidgets('Material2 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: false); + await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final InputDecoration hourDecoration = _textField(tester, '7').decoration!; + expect(hourDecoration.filled, true); + expect( + hourDecoration.fillColor, + MaterialStateColor.resolveWith((Set states) => + defaultTheme.colorScheme.onSurface.withOpacity(0.12)) + ); + expect( + hourDecoration.enabledBorder, + const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)) + ); + expect( + hourDecoration.errorBorder, + OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2)) + ); + expect( + hourDecoration.focusedBorder, + OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2)) + ); + expect( + hourDecoration.focusedErrorBorder, + OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2)) + ); + expect( + hourDecoration.hintStyle, + Typography.material2014().englishLike.displayMedium! + .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36))) + ); + }); - testWidgets('Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { - final ThemeData defaultTheme = ThemeData(); - final bool material3 = defaultTheme.useMaterial3; + testWidgets('Material3 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: true); await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final InputDecoration hourDecoration = _textField(tester, '7').decoration!; expect(hourDecoration.filled, true); - expect(hourDecoration.fillColor, material3 - ? defaultTheme.colorScheme.surfaceVariant - : MaterialStateColor.resolveWith((Set states) => defaultTheme.colorScheme.onSurface.withOpacity(0.12))); - expect(hourDecoration.enabledBorder, material3 ? const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: Colors.transparent)) : const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent))); - expect(hourDecoration.errorBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); - expect(hourDecoration.focusedBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2))); - expect(hourDecoration.focusedErrorBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); + expect(hourDecoration.fillColor, defaultTheme.colorScheme.surfaceVariant); + expect( + hourDecoration.enabledBorder, + const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: Colors.transparent)), + ); + expect( + hourDecoration.errorBorder, + OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)), + ); + expect( + hourDecoration.focusedBorder, + OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2.0)), + ); + expect( + hourDecoration.focusedErrorBorder, + OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)), + ); expect( hourDecoration.hintStyle, - material3 - ? TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)) - : (Typography.material2014().englishLike.displayMedium! - .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)))), + TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)) ); }); - testWidgets('Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { + testWidgets('Material2 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(); - final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); - final bool material3 = theme.useMaterial3; + final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); @@ -313,69 +464,45 @@ void main() { final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.bodyMedium! - .merge(Typography.material2014().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _selectedColor)), + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _selectedColor), ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.bodyMedium! - .merge(Typography.material2014().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _unselectedColor)), + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _unselectedColor), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .merge(timePickerTheme.dayPeriodTextStyle) - .copyWith(color: _selectedColor)), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .merge(timePickerTheme.dayPeriodTextStyle) + .copyWith(color: _selectedColor), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .merge(timePickerTheme.dayPeriodTextStyle) - .copyWith(color: _unselectedColor)), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .merge(timePickerTheme.dayPeriodTextStyle) + .copyWith(color: _unselectedColor), ); - final RenderParagraph helperText = _textRenderParagraph(tester, material3 ? 'Select time' : 'SELECT TIME'); + final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME'); expect( helperText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.helpTextStyle).copyWith(color: theme.colorScheme.onSurface, decorationColor: theme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyMedium! - .merge(Typography.material2014().black.bodyMedium) - .merge(timePickerTheme.helpTextStyle)), + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) + .merge(timePickerTheme.helpTextStyle), ); final CustomPaint dialPaint = tester.widget(findDialPaint); @@ -385,26 +512,18 @@ void main() { expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: _unselectedColor, decorationColor: theme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().black.bodyLarge) - .copyWith(color: _unselectedColor)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().black.bodyLarge) + .copyWith(color: _unselectedColor), ); // ignore: avoid_dynamic_calls final List selectedLabels = dialPainter.selectedLabels as List; expect( // ignore: avoid_dynamic_calls selectedLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: _selectedColor, decorationColor: theme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().white.bodyLarge) - .copyWith(color: _selectedColor)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().white.bodyLarge) + .copyWith(color: _selectedColor), ); final Material hourMaterial = _textMaterial(tester, '7'); @@ -436,8 +555,125 @@ void main() { final IconButton entryModeIconButton = _entryModeIconButton(tester); expect( entryModeIconButton.color, - material3 ? null : timePickerTheme.entryModeIconColor, + timePickerTheme.entryModeIconColor, + ); + }); + + testWidgets('Material3 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { + final TimePickerThemeData timePickerTheme = _timePickerTheme(); + final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: true); + await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final Material dialogMaterial = _dialogMaterial(tester); + expect(dialogMaterial.color, timePickerTheme.backgroundColor); + expect(dialogMaterial.shape, timePickerTheme.shape); + + final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); + expect( + dial, + paints + ..circle(color: Color(timePickerTheme.dialBackgroundColor!.value)) // Dial background color. + ..circle(color: Color(timePickerTheme.dialHandColor!.value)), // Dial hand color. + ); + + final RenderParagraph hourText = _textRenderParagraph(tester, '7'); + expect( + hourText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); + expect( + minuteText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); + expect( + amText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); + expect( + pmText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph helperText = _textRenderParagraph(tester, 'Select time'); + expect( + helperText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.helpTextStyle).copyWith( + color: theme.colorScheme.onSurface, + decorationColor: theme.colorScheme.onSurface + ), + ); + + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + expect( + // ignore: avoid_dynamic_calls + primaryLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith(color: _unselectedColor, decorationColor: theme.colorScheme.onSurface), + ); + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + expect( + // ignore: avoid_dynamic_calls + selectedLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith(color: _selectedColor, decorationColor: theme.colorScheme.onSurface), + ); + + final Material hourMaterial = _textMaterial(tester, '7'); + expect(hourMaterial.color, _selectedColor); + expect(hourMaterial.shape, timePickerTheme.hourMinuteShape); + + final Material minuteMaterial = _textMaterial(tester, '15'); + expect(minuteMaterial.color, _unselectedColor); + expect(minuteMaterial.shape, timePickerTheme.hourMinuteShape); + + final Material amMaterial = _textMaterial(tester, 'AM'); + expect(amMaterial.color, _selectedColor); + + final Material pmMaterial = _textMaterial(tester, 'PM'); + expect(pmMaterial.color, _unselectedColor); + + final Material dayPeriodMaterial = _dayPeriodMaterial(tester); + expect( + dayPeriodMaterial.shape, + timePickerTheme.dayPeriodShape!.copyWith(side: timePickerTheme.dayPeriodBorderSide), ); + + final Container dayPeriodDivider = _dayPeriodDivider(tester); + expect( + dayPeriodDivider.decoration, + BoxDecoration(border: Border(left: timePickerTheme.dayPeriodBorderSide!)), + ); + + final IconButton entryModeIconButton = _entryModeIconButton(tester); + expect(entryModeIconButton.color, null); }); testWidgets('Time picker uses values from TimePickerThemeData with InputDecorationTheme - input mode', (WidgetTester tester) async { From de26ad0a8a5373a64dae84fa2019821a2c984047 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 15:04:05 -0400 Subject: [PATCH 0291/1547] Roll Flutter Engine from 6d7842d25f81 to a3fc18514cd6 (2 revisions) (#131007) https://github.com/flutter/engine/compare/6d7842d25f81...a3fc18514cd6 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from b8133dda3a8c to a3aca7ae523e (1 revision) (flutter/engine#43855) 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from 401c85ab1e21 to b8133dda3a8c (4 revisions) (flutter/engine#43853) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8231b08aa16cc..6b44889fa6ec5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6d7842d25f81004bbd3125ecbec167db69fa241f +a3fc18514cd684bd5b8e3686fc12a1244185f12b From 038e57c0ad03c8e4795f906a997ec7cb27f8dd3e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 16:09:55 -0400 Subject: [PATCH 0292/1547] Roll Flutter Engine from a3fc18514cd6 to 062079ba30b6 (3 revisions) (#131010) https://github.com/flutter/engine/compare/a3fc18514cd6...062079ba30b6 2023-07-20 dnfield@google.com More validation logs for CommandEncoderVK submission (flutter/engine#43859) 2023-07-20 skia-flutter-autoroll@skia.org Roll Dart SDK from 857c9a2ae14a to 1df95f328d0c (1 revision) (flutter/engine#43858) 2023-07-20 mdebbar@google.com [web] Preserve correct CanvasKit Variant during test initialization (flutter/engine#43854) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6b44889fa6ec5..4b7041300af6d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a3fc18514cd684bd5b8e3686fc12a1244185f12b +062079ba30b6101a5d64df7a8b764fcecb709d15 From 93f7dc321d12e8329c16d56b91a49781245dcfdf Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Thu, 20 Jul 2023 13:12:34 -0700 Subject: [PATCH 0293/1547] Updated the ThemeData API example (#130954) --- .../lib/material/theme_data/theme_data.0.dart | 115 ++++++++++++++++++ .../theme_data/theme_data.0_test.dart | 36 ++++++ .../flutter/lib/src/material/theme_data.dart | 69 ++--------- 3 files changed, 159 insertions(+), 61 deletions(-) create mode 100644 examples/api/lib/material/theme_data/theme_data.0.dart create mode 100644 examples/api/test/material/theme_data/theme_data.0_test.dart diff --git a/examples/api/lib/material/theme_data/theme_data.0.dart b/examples/api/lib/material/theme_data/theme_data.0.dart new file mode 100644 index 0000000000000..ceec42105d3fc --- /dev/null +++ b/examples/api/lib/material/theme_data/theme_data.0.dart @@ -0,0 +1,115 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +void main() { + runApp(const ThemeDataExampleApp()); +} + +// This app's theme specifies an overall ColorScheme as well as overrides +// for the default configuration of FloatingActionButtons. To customize +// the appearance of other components, add additional component specific +// themes, rather than tweaking the color scheme. +// +// Creating an entire color scheme from a single seed color is a good +// way to ensure a visually appealing color palette where the default +// component colors have sufficient contrast for accessibility. Another +// good way to create an app's color scheme is to use +// ColorScheme.fromImageProvider. +// +// The color scheme reflects the platform's light or dark setting +// which is retrieved with `MediaQuery.platformBrightnessOf`. The color +// scheme's colors will be different for light and dark settings although +// they'll all be related to the seed color in both cases. +// +// Color scheme colors have been used where component defaults have +// been overidden so that the app will look good and remain accessible +// in both light and dark modes. +// +// Text styles are derived from the theme's textTheme (not the obsolete +// primaryTextTheme property) and then customized using copyWith. +// Using the _on_ version of a color scheme color as the foreground, +// as in `tertiary` and `onTertiary`, guarantees sufficient contrast +// for readability/accessibility. + +class ThemeDataExampleApp extends StatelessWidget { + const ThemeDataExampleApp({ super.key }); + + @override + Widget build(BuildContext context) { + final ColorScheme colorScheme = ColorScheme.fromSeed( + brightness: MediaQuery.platformBrightnessOf(context), + seedColor: Colors.indigo, + ); + return MaterialApp( + title: 'ThemeData Demo', + theme: ThemeData( + colorScheme: colorScheme, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: colorScheme.tertiary, + foregroundColor: colorScheme.onTertiary, + ), + ), + home: const Home(), + ); + } +} + +class Home extends StatefulWidget { + const Home({ super.key }); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + int buttonPressCount = 0; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final ColorScheme colorScheme = theme.colorScheme; + final double pointCount = 8 + (buttonPressCount % 6); + + return Scaffold( + appBar: AppBar( + title: const Text('Press the + Button'), + ), + // An AnimatedContainer makes the decoration changes entertaining. + body: AnimatedContainer( + duration: const Duration(milliseconds: 500), + margin: const EdgeInsets.all(32), + alignment: Alignment.center, + decoration: ShapeDecoration( + color: colorScheme.tertiaryContainer, + shape: StarBorder( + points: pointCount, + pointRounding: 0.4, + valleyRounding: 0.6, + side: BorderSide( + width: 9, + color: colorScheme.tertiary + ), + ), + ), + child: Text( + '${pointCount.toInt()} Points', + style: theme.textTheme.headlineMedium!.copyWith( + color: colorScheme.onPrimaryContainer, + ), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + setState(() { + buttonPressCount += 1; + }); + }, + tooltip: "Change the shape's point count", + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/examples/api/test/material/theme_data/theme_data.0_test.dart b/examples/api/test/material/theme_data/theme_data.0_test.dart new file mode 100644 index 0000000000000..bb1de2263877d --- /dev/null +++ b/examples/api/test/material/theme_data/theme_data.0_test.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/theme_data/theme_data.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + + testWidgets('ThemeData basics', (WidgetTester tester) async { + await tester.pumpWidget(const example.ThemeDataExampleApp()); + + final ColorScheme colorScheme = ColorScheme.fromSeed( + seedColor: Colors.indigo, + ); + + final Material fabMaterial = tester.widget( + find.descendant(of: find.byType(FloatingActionButton), matching: find.byType(Material)), + ); + expect(fabMaterial.color, colorScheme.tertiary); + + final RichText iconRichText = tester.widget( + find.descendant(of: find.byIcon(Icons.add), matching: find.byType(RichText)), + ); + expect(iconRichText.text.style!.color, colorScheme.onTertiary); + + expect(find.text('8 Points'), isNotNull); + await tester.tap(find.byType(FloatingActionButton)); + await tester.pumpAndSettle(); + expect(find.text('9 Points'), isNotNull); + await tester.tap(find.byType(FloatingActionButton)); + await tester.pumpAndSettle(); + expect(find.text('10 Points'), isNotNull); + }); +} diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index f4c2f4209b5fc..518c389348c0b 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -179,68 +179,15 @@ enum MaterialTapTargetSize { /// for the subtree that appears below the new [Theme], or insert a widget /// that creates a new BuildContext, like [Builder]. /// -/// {@tool snippet} -/// In this example, the [Container] widget uses [Theme.of] to retrieve the -/// primary color from the theme's [colorScheme] to draw an amber square. -/// The [Builder] widget separates the parent theme's [BuildContext] from the -/// child's [BuildContext]. -/// -/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/theme_data.png) -/// -/// ```dart -/// Theme( -/// data: ThemeData.from( -/// colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.amber), -/// ), -/// child: Builder( -/// builder: (BuildContext context) { -/// return Container( -/// width: 100, -/// height: 100, -/// color: Theme.of(context).colorScheme.primary, -/// ); -/// }, -/// ), -/// ) -/// ``` -/// {@end-tool} -/// -/// {@tool snippet} -/// -/// This sample creates a [MaterialApp] with a [Theme] whose -/// [ColorScheme] is based on [Colors.blue], but with the color -/// scheme's [ColorScheme.secondary] color overridden to be green. The -/// [AppBar] widget uses the color scheme's [ColorScheme.primary] as -/// its default background color and the [FloatingActionButton] widget -/// uses the color scheme's [ColorScheme.secondary] for its default -/// background. By default, the [Text] widget uses -/// [TextTheme.bodyMedium], and the color of that [TextStyle] has been -/// changed to purple. -/// -/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/material_app_theme_data.png) +/// {@tool dartpad} +/// This example demonstrates how a typical [MaterialApp] specifies +/// and uses a custom [Theme]. The theme's [ColorScheme] is based on a +/// single "seed" color and configures itself to match the platform's +/// current light or dark color configuration. The theme overrides the +/// default configuration of [FloatingActionButton] to show how to +/// customize the appearance a class of components. /// -/// ```dart -/// MaterialApp( -/// theme: ThemeData( -/// colorScheme: ColorScheme.fromSwatch().copyWith( -/// secondary: Colors.green, -/// ), -/// textTheme: const TextTheme(bodyMedium: TextStyle(color: Colors.purple)), -/// ), -/// home: Scaffold( -/// appBar: AppBar( -/// title: const Text('ThemeData Demo'), -/// ), -/// floatingActionButton: FloatingActionButton( -/// child: const Icon(Icons.add), -/// onPressed: () {}, -/// ), -/// body: const Center( -/// child: Text('Button pressed 0 times'), -/// ), -/// ), -/// ) -/// ``` +/// ** See code in examples/api/lib/material/theme_data/theme_data.0.dart ** /// {@end-tool} /// /// See for From 14c2153b31d49650846b963f504ccd4526b5b497 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 20 Jul 2023 13:37:04 -0700 Subject: [PATCH 0294/1547] Trivial grammar and wrapping fix for docs (#130955) --- .../lib/src/foundation/collections.dart | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/flutter/lib/src/foundation/collections.dart b/packages/flutter/lib/src/foundation/collections.dart index 7a0be1b07167c..e1e1499d856ba 100644 --- a/packages/flutter/lib/src/foundation/collections.dart +++ b/packages/flutter/lib/src/foundation/collections.dart @@ -10,10 +10,10 @@ /// the same length, and contain the same members. Returns false otherwise. /// Order is not compared. /// -/// If the elements are maps, lists, sets, or other collections/composite objects, -/// then the contents of those elements are not compared element by element unless their -/// equality operators ([Object.==]) do so. -/// For checking deep equality, consider using [DeepCollectionEquality] class. +/// If the elements are maps, lists, sets, or other collections/composite +/// objects, then the contents of those elements are not compared element by +/// element unless their equality operators ([Object.==]) do so. For checking +/// deep equality, consider using the [DeepCollectionEquality] class. /// /// See also: /// @@ -43,10 +43,10 @@ bool setEquals(Set? a, Set? b) { /// the same length, and contain the same members in the same order. Returns /// false otherwise. /// -/// If the elements are maps, lists, sets, or other collections/composite objects, -/// then the contents of those elements are not compared element by element unless their -/// equality operators ([Object.==]) do so. -/// For checking deep equality, consider using [DeepCollectionEquality] class. +/// If the elements are maps, lists, sets, or other collections/composite +/// objects, then the contents of those elements are not compared element by +/// element unless their equality operators ([Object.==]) do so. For checking +/// deep equality, consider using the [DeepCollectionEquality] class. /// /// See also: /// @@ -76,10 +76,10 @@ bool listEquals(List? a, List? b) { /// the same length, and contain the same keys associated with the same values. /// Returns false otherwise. /// -/// If the elements are maps, lists, sets, or other collections/composite objects, -/// then the contents of those elements are not compared element by element unless their -/// equality operators ([Object.==]) do so. -/// For checking deep equality, consider using [DeepCollectionEquality] class. +/// If the elements are maps, lists, sets, or other collections/composite +/// objects, then the contents of those elements are not compared element by +/// element unless their equality operators ([Object.==]) do so. For checking +/// deep equality, consider using the [DeepCollectionEquality] class. /// /// See also: /// @@ -103,7 +103,6 @@ bool mapEquals(Map? a, Map? b) { return true; } - /// Returns the position of `value` in the `sortedList`, if it exists. /// /// Returns `-1` if the `value` is not in the list. Requires the list items From 773b667b55c6860e1f7def2350f4e2b8d0a3729b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 17:00:14 -0400 Subject: [PATCH 0295/1547] Roll Flutter Engine from 062079ba30b6 to 9b2ebf2afe00 (2 revisions) (#131013) https://github.com/flutter/engine/compare/062079ba30b6...9b2ebf2afe00 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from a3aca7ae523e to 18e834916f47 (1 revision) (flutter/engine#43860) 2023-07-20 mdebbar@google.com Add url to get GoogleFonts API key (flutter/engine#43857) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4b7041300af6d..8fd3a989a33ae 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -062079ba30b6101a5d64df7a8b764fcecb709d15 +9b2ebf2afe008fd47f5cc81921d36ef442132c23 From d457287f6c972c9697be3337bbc5b250961cdb5e Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Thu, 20 Jul 2023 14:02:12 -0700 Subject: [PATCH 0296/1547] Migrate more integration tests to process result matcher (#130994) Part of https://github.com/flutter/flutter/issues/127135 --- ...id_gradle_print_app_link_domains_test.dart | 6 +- ...roid_gradle_print_application_id_test.dart | 6 +- .../build_macos_config_only_test.dart | 13 +--- .../command_output_test.dart | 24 +++++-- .../deferred_components_test.dart | 65 +++++++++---------- .../web_plugin_registrant_test.dart | 17 ++--- 6 files changed, 60 insertions(+), 71 deletions(-) diff --git a/packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart b/packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart index eed136cc72c0c..2533b264c535d 100644 --- a/packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart @@ -147,7 +147,7 @@ void main() { tempDir.path, '--project-name=testapp', ], workingDirectory: tempDir.path); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); // Adds intent filters for app links final String androidManifestPath = fileSystem.path.join(tempDir.path, 'android', 'app', 'src', 'main', 'AndroidManifest.xml'); final io.File androidManifestFile = io.File(androidManifestPath); @@ -166,7 +166,7 @@ void main() { 'apk', '--config-only', ], workingDirectory: tempDir.path); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); final Directory androidApp = tempDir.childDirectory('android'); result = await processManager.run([ @@ -176,7 +176,7 @@ void main() { 'printDebugAppLinkDomains', ], workingDirectory: androidApp.path); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); const List expectedLines = [ // Should only pick up the pure and hybrid intent filters diff --git a/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart b/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart index 563344660e067..82ec3c84f410e 100644 --- a/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart @@ -35,7 +35,7 @@ void main() { tempDir.path, '--project-name=testapp', ], workingDirectory: tempDir.path); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); // Ensure that gradle files exists from templates. result = await processManager.run([ flutterBin, @@ -43,7 +43,7 @@ void main() { 'apk', '--config-only', ], workingDirectory: tempDir.path); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); final Directory androidApp = tempDir.childDirectory('android'); result = await processManager.run([ @@ -53,7 +53,7 @@ void main() { 'printDebugApplicationId', ], workingDirectory: androidApp.path); // Verify that gradlew has a javaVersion task. - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); // Verify the format is a number on its own line. const List expectedLines = [ 'ApplicationId: com.example.testapp', diff --git a/packages/flutter_tools/test/integration.shard/build_macos_config_only_test.dart b/packages/flutter_tools/test/integration.shard/build_macos_config_only_test.dart index cb27c4025600d..6fd271c55aa15 100644 --- a/packages/flutter_tools/test/integration.shard/build_macos_config_only_test.dart +++ b/packages/flutter_tools/test/integration.shard/build_macos_config_only_test.dart @@ -36,13 +36,7 @@ void main() { ]; final ProcessResult firstRunResult = await processManager.run(buildCommand, workingDirectory: workingDirectory); - printOnFailure('Output of flutter build macOS:'); - final String firstRunStdout = firstRunResult.stdout.toString(); - printOnFailure('First run stdout: $firstRunStdout'); - printOnFailure('First run stderr: ${firstRunResult.stderr}'); - - expect(firstRunResult.exitCode, 0); - expect(firstRunStdout, contains('Running pod install')); + expect(firstRunResult, const ProcessResultMatcher(stdoutPattern: 'Running pod install')); final File generatedConfig = fileSystem.file(fileSystem.path.join( workingDirectory, @@ -73,10 +67,7 @@ void main() { // Run again with no changes. final ProcessResult secondRunResult = await processManager.run(buildCommand, workingDirectory: workingDirectory); - final String secondRunStdout = secondRunResult.stdout.toString(); - printOnFailure('Second run stdout: $secondRunStdout'); - printOnFailure('Second run stderr: ${secondRunResult.stderr}'); - expect(secondRunResult.exitCode, 0); + expect(secondRunResult, const ProcessResultMatcher()); }, skip: !platform.isMacOS); // [intended] macOS builds only work on macos. } diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart index e693ff1fe59c7..7b72ef67643b6 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -158,8 +158,10 @@ void main() { '--debug-url=http://127.0.0.1:3333*/', ], workingDirectory: helloWorld); - expect(result.exitCode, 1); - expect(result.stderr, contains('Invalid `--debug-url`: http://127.0.0.1:3333*/')); + expect( + result, + const ProcessResultMatcher(exitCode: 1, stderrPattern: 'Invalid `--debug-url`: http://127.0.0.1:3333*/'), + ); }); testWithoutContext('--debug-uri is an alias for --debug-url', () async { @@ -175,8 +177,14 @@ void main() { '--debug-uri=http://127.0.0.1:3333*/', // "uri" not "url" ], workingDirectory: helloWorld); - expect(result.exitCode, 1); - expect(result.stderr, contains('Invalid `--debug-url`: http://127.0.0.1:3333*/')); // _"url"_ not "uri"! + expect( + result, + const ProcessResultMatcher( + exitCode: 1, + // _"url"_ not "uri"! + stderrPattern: 'Invalid `--debug-url`: http://127.0.0.1:3333*/', + ), + ); }); testWithoutContext('will load bootstrap script before starting', () async { @@ -211,8 +219,10 @@ void main() { '--bundle-sksl-path=foo/bar/baz.json', // This file does not exist. ], workingDirectory: helloWorld); - expect(result.exitCode, 1); - expect(result.stderr, contains('No SkSL shader bundle found at foo/bar/baz.json')); + expect(result, const ProcessResultMatcher( + exitCode: 1, + stderrPattern: 'No SkSL shader bundle found at foo/bar/baz.json'), + ); }); testWithoutContext('flutter attach does not support --release', () async { @@ -257,7 +267,7 @@ void main() { 'json', ], workingDirectory: helloWorld); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); expect(result.stderr, isEmpty); }); } diff --git a/packages/flutter_tools/test/integration.shard/deferred_components_test.dart b/packages/flutter_tools/test/integration.shard/deferred_components_test.dart index 6cf038b5a0a47..f01ea24bf5976 100644 --- a/packages/flutter_tools/test/integration.shard/deferred_components_test.dart +++ b/packages/flutter_tools/test/integration.shard/deferred_components_test.dart @@ -39,10 +39,7 @@ void main() { '--target-platform=android-arm64', ], workingDirectory: tempDir.path); - printOnFailure('stdout:\n${result.stdout}'); - printOnFailure('stderr:\n${result.stderr}'); - expect(result.exitCode, 0); - expect(result.stdout.toString(), contains('app-release.aab')); + expect(result, const ProcessResultMatcher(stdoutPattern: 'app-release.aab')); expect(result.stdout.toString(), contains('Deferred components prebuild validation passed.')); expect(result.stdout.toString(), contains('Deferred components gen_snapshot validation passed.')); @@ -106,7 +103,7 @@ void main() { expect(archive.findFile('component1/assets/flutter_assets/test_assets/asset2.txt') != null, true); expect(archive.findFile('base/assets/flutter_assets/test_assets/asset1.txt') != null, true); - expect(result.exitCode, 0); + expect(result, const ProcessResultMatcher()); }); testWithoutContext('simple build appbundle no-deferred-components succeeds', () async { @@ -121,11 +118,9 @@ void main() { '--no-deferred-components', ], workingDirectory: tempDir.path); - printOnFailure('stdout:\n${result.stdout}'); - printOnFailure('stderr:\n${result.stderr}'); - expect(result.stdout.toString().contains('app-release.aab'), true); - expect(result.stdout.toString().contains('Deferred components prebuild validation passed.'), false); - expect(result.stdout.toString().contains('Deferred components gen_snapshot validation passed.'), false); + expect(result, const ProcessResultMatcher(stdoutPattern: 'app-release.aab')); + expect(result.stdout.toString(), isNot(contains('Deferred components prebuild validation passed.'))); + expect(result.stdout.toString(), isNot(contains('Deferred components gen_snapshot validation passed.'))); final String line = result.stdout.toString() .split('\n') @@ -153,8 +148,6 @@ void main() { expect(archive.findFile('component1/assets/flutter_assets/test_assets/asset2.txt') != null, false); expect(archive.findFile('base/assets/flutter_assets/test_assets/asset2.txt') != null, true); expect(archive.findFile('base/assets/flutter_assets/test_assets/asset1.txt') != null, true); - - expect(result.exitCode, 0); }); testWithoutContext('simple build appbundle mismatched golden no-validate-deferred-components succeeds', () async { @@ -169,14 +162,13 @@ void main() { '--no-validate-deferred-components', ], workingDirectory: tempDir.path); + expect(result, const ProcessResultMatcher(stdoutPattern: 'app-release.aab')); printOnFailure('stdout:\n${result.stdout}'); printOnFailure('stderr:\n${result.stderr}'); - expect(result.stdout.toString().contains('app-release.aab'), true); - expect(result.stdout.toString().contains('Deferred components prebuild validation passed.'), false); - expect(result.stdout.toString().contains('Deferred components gen_snapshot validation passed.'), false); - - expect(result.stdout.toString().contains('New loading units were found:'), false); - expect(result.stdout.toString().contains('Previously existing loading units no longer exist:'), false); + expect(result.stdout.toString(), isNot(contains('Deferred components prebuild validation passed.'))); + expect(result.stdout.toString(), isNot(contains('Deferred components gen_snapshot validation passed.'))); + expect(result.stdout.toString(), isNot(contains('New loading units were found:'))); + expect(result.stdout.toString(), isNot(contains('Previously existing loading units no longer exist:'))); final String line = result.stdout.toString() .split('\n') @@ -202,8 +194,6 @@ void main() { expect(archive.findFile('component1/assets/flutter_assets/test_assets/asset2.txt') != null, true); expect(archive.findFile('base/assets/flutter_assets/test_assets/asset1.txt') != null, true); - - expect(result.exitCode, 0); }); testWithoutContext('simple build appbundle missing android dynamic feature module fails', () async { @@ -217,16 +207,15 @@ void main() { 'appbundle', ], workingDirectory: tempDir.path); - expect(result.stdout.toString().contains('app-release.aab'), false); - expect(result.stdout.toString().contains('Deferred components prebuild validation passed.'), false); - expect(result.stdout.toString().contains('Deferred components gen_snapshot validation passed.'), false); + expect(result, const ProcessResultMatcher(exitCode: 1, stdoutPattern: 'Newly generated android files:')); + + expect(result.stdout.toString(), isNot(contains('app-release.aab'))); + expect(result.stdout.toString(), isNot(contains('Deferred components prebuild validation passed.'))); + expect(result.stdout.toString(), isNot(contains('Deferred components gen_snapshot validation passed.'))); - expect(result.stdout.toString(), contains('Newly generated android files:')); final String pathSeparator = fileSystem.path.separator; expect(result.stdout.toString(), contains('build${pathSeparator}android_deferred_components_setup_files${pathSeparator}component1${pathSeparator}build.gradle')); expect(result.stdout.toString(), contains('build${pathSeparator}android_deferred_components_setup_files${pathSeparator}component1${pathSeparator}src${pathSeparator}main${pathSeparator}AndroidManifest.xml')); - - expect(result.exitCode, 1); }); testWithoutContext('simple build appbundle missing golden fails', () async { @@ -240,16 +229,15 @@ void main() { 'appbundle', ], workingDirectory: tempDir.path); - expect(result.stdout.toString().contains('app-release.aab'), false); - expect(result.stdout.toString().contains('Deferred components prebuild validation passed.'), true); - expect(result.stdout.toString().contains('Deferred components gen_snapshot validation passed.'), false); + expect(result, const ProcessResultMatcher(exitCode: 1)); + expect(result.stdout.toString(), isNot(contains('app-release.aab'))); + expect(result.stdout.toString(), contains('Deferred components prebuild validation passed.')); + expect(result.stdout.toString(), isNot(contains('Deferred components gen_snapshot validation passed.'))); expect(result.stdout.toString(), contains('New loading units were found:')); expect(result.stdout.toString(), contains('- package:test/deferred_library.dart')); - expect(result.stdout.toString().contains('Previously existing loading units no longer exist:'), false); - - expect(result.exitCode, 1); + expect(result.stdout.toString(), isNot(contains('Previously existing loading units no longer exist:'))); }); testWithoutContext('simple build appbundle mismatched golden fails', () async { @@ -263,9 +251,15 @@ void main() { 'appbundle', ], workingDirectory: tempDir.path); - expect(result.stdout.toString().contains('app-release.aab'), false); - expect(result.stdout.toString().contains('Deferred components prebuild validation passed.'), true); - expect(result.stdout.toString().contains('Deferred components gen_snapshot validation passed.'), false); + expect( + result, + const ProcessResultMatcher( + exitCode: 1, + stdoutPattern: 'Deferred components prebuild validation passed.', + ), + ); + expect(result.stdout.toString(), isNot(contains('app-release.aab'))); + expect(result.stdout.toString(), isNot(contains('Deferred components gen_snapshot validation passed.'))); expect(result.stdout.toString(), contains('New loading units were found:')); expect(result.stdout.toString(), contains('- package:test/deferred_library.dart')); @@ -275,6 +269,5 @@ void main() { expect(result.stdout.toString(), contains('This loading unit check will not fail again on the next build attempt')); - expect(result.exitCode, 1); }); } diff --git a/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart b/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart index 47c07e70bd0e7..f3907b530fccd 100644 --- a/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart +++ b/packages/flutter_tools/test/integration.shard/web_plugin_registrant_test.dart @@ -18,6 +18,7 @@ import 'package:flutter_tools/src/globals.dart' as globals; import '../src/common.dart'; import '../src/context.dart'; import '../src/test_flutter_command_runner.dart'; +import 'test_utils.dart'; void main() { late Directory tempDir; @@ -275,7 +276,7 @@ Future _ensureFlutterToolsSnapshot() async { printOnFailure('Output of dart ${snapshotArgs.join(" ")}:'); printOnFailure(snapshotResult.stdout.toString()); printOnFailure(snapshotResult.stderr.toString()); - expect(snapshotResult.exitCode, 0); + expect(snapshotResult, const ProcessResultMatcher()); } Future _restoreFlutterToolsSnapshot() async { @@ -415,10 +416,7 @@ Future _analyzeEntity(FileSystemEntity target) async { args, workingDirectory: target is Directory ? target.path : target.dirname, ); - printOnFailure('Output of flutter analyze:'); - printOnFailure(exec.stdout.toString()); - printOnFailure(exec.stderr.toString()); - expect(exec.exitCode, 0); + expect(exec, const ProcessResultMatcher()); } Future _buildWebProject(Directory workingDir) async { @@ -445,17 +443,14 @@ Future _runFlutterSnapshot(List flutterCommandArgs, Directory work ); final List args = [ + globals.artifacts!.getArtifactPath(Artifact.engineDartBinary, platform: TargetPlatform.web_javascript), flutterToolsSnapshotPath, ...flutterCommandArgs ]; - final ProcessResult exec = await Process.run( - globals.artifacts!.getArtifactPath(Artifact.engineDartBinary, platform: TargetPlatform.web_javascript), + final ProcessResult exec = await globals.processManager.run( args, workingDirectory: workingDir.path, ); - printOnFailure('Output of flutter ${flutterCommandArgs.join(" ")}:'); - printOnFailure(exec.stdout.toString()); - printOnFailure(exec.stderr.toString()); - expect(exec.exitCode, 0); + expect(exec, const ProcessResultMatcher()); } From e4a39fa2edb9c3789c6e2de5405e9b281591a564 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Thu, 20 Jul 2023 15:11:20 -0700 Subject: [PATCH 0297/1547] Add applyFocusChangeIfNeeded, have menus restore focus before activating (#130536) ## Description This modifies the `MenuAnchor` `onPressed` activation to delay until after the current frame is built, and resolve any focus changes before it invokes the `onPressed`, so that actions that operate on the `primaryFocus` can have a chance of working on the focused item they were meant to work on. ## Related Issues - Fixes https://github.com/flutter/flutter/issues/118731 ## Tests - No tests yet (hence draft still) --- dev/manual_tests/lib/menu_anchor.dart | 12 +- .../checkbox_menu_button.0_test.dart | 4 +- .../menu_anchor/menu_anchor.0_test.dart | 2 +- .../menu_anchor/menu_anchor.1_test.dart | 6 +- .../material/menu_anchor/menu_bar.0_test.dart | 6 +- .../menu_anchor/radio_menu_button.0_test.dart | 2 +- .../flutter/lib/src/material/menu_anchor.dart | 8 +- .../lib/src/widgets/focus_manager.dart | 27 +++- .../test/material/menu_anchor_test.dart | 123 +++++++++++++----- 9 files changed, 140 insertions(+), 50 deletions(-) diff --git a/dev/manual_tests/lib/menu_anchor.dart b/dev/manual_tests/lib/menu_anchor.dart index b6f98d34b7e07..11a5ebd84eed5 100644 --- a/dev/manual_tests/lib/menu_anchor.dart +++ b/dev/manual_tests/lib/menu_anchor.dart @@ -706,6 +706,12 @@ List createTestMenus({ TestMenu.mainMenu3, menuChildren: [ menuItemButton(TestMenu.subMenu8), + MenuItemButton( + onPressed: () { + debugPrint('Focused Item: $primaryFocus'); + }, + child: const Text('Print Focused Item'), + ) ], ), submenuButton( @@ -734,7 +740,11 @@ List createTestMenus({ submenuButton( TestMenu.subSubMenu3, menuChildren: [ - menuItemButton(TestMenu.subSubSubMenu1), + for (int i=0; i < 100; ++i) + MenuItemButton( + onPressed: () {}, + child: Text('Menu Item $i'), + ), ], ), ], diff --git a/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart b/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart index 278d19af9ca8a..76d27b5693504 100644 --- a/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart +++ b/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart @@ -13,13 +13,13 @@ void main() { ); await tester.tap(find.byType(TextButton)); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text('Show Message'), findsOneWidget); expect(find.text(example.MenuApp.kMessage), findsNothing); await tester.tap(find.text('Show Message')); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text('Show Message'), findsNothing); expect(find.text(example.MenuApp.kMessage), findsOneWidget); diff --git a/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart b/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart index 54016dcf25732..dcbabb2cba249 100644 --- a/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart @@ -41,7 +41,7 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); await tester.sendKeyEvent(LogicalKeyboardKey.enter); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text(example.MenuApp.kMessage), findsOneWidget); expect(find.text('Last Selected: ${example.MenuEntry.showMessage.label}'), findsOneWidget); diff --git a/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart b/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart index b9dc670d1c8fc..0ac0e43ddb2bc 100644 --- a/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart +++ b/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart @@ -20,7 +20,7 @@ void main() { await tester.pumpWidget(const example.ContextMenuApp()); await tester.tapAt(const Offset(100, 200), buttons: kSecondaryButton); - await tester.pump(); + await tester.pumpAndSettle(); expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 433.0, 360.0))); // Make sure tapping in a different place causes the menu to move. @@ -46,7 +46,7 @@ void main() { expect(find.text('Background Color'), findsOneWidget); await tester.tap(find.text('Background Color')); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text(example.MenuEntry.colorRed.label), findsOneWidget); expect(find.text(example.MenuEntry.colorGreen.label), findsOneWidget); @@ -54,7 +54,7 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); await tester.sendKeyEvent(LogicalKeyboardKey.enter); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text(example.ContextMenuApp.kMessage), findsOneWidget); expect(find.text('Last Selected: ${example.MenuEntry.showMessage.label}'), findsOneWidget); diff --git a/examples/api/test/material/menu_anchor/menu_bar.0_test.dart b/examples/api/test/material/menu_anchor/menu_bar.0_test.dart index b508ba444497f..ccfe4c93577fa 100644 --- a/examples/api/test/material/menu_anchor/menu_bar.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_bar.0_test.dart @@ -20,7 +20,7 @@ void main() { final Finder menuButtonFinder = find.byType(SubmenuButton).first; await tester.tap(menuButtonFinder); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text('About'), findsOneWidget); expect(find.text('Show Message'), findsOneWidget); @@ -34,7 +34,7 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text('About'), findsOneWidget); expect(find.text('Show Message'), findsOneWidget); @@ -46,7 +46,7 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); await tester.sendKeyEvent(LogicalKeyboardKey.enter); - await tester.pump(); + await tester.pumpAndSettle(); expect(find.text(example.MenuBarApp.kMessage), findsOneWidget); expect(find.text('Last Selected: Show Message'), findsOneWidget); diff --git a/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart b/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart index ee33556142f7a..2b88a77522dac 100644 --- a/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart +++ b/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart @@ -24,7 +24,7 @@ void main() { expect(tester.widget(find.byType(Container)).color, equals(Colors.red)); await tester.tap(find.text('Green Background')); - await tester.pump(); + await tester.pumpAndSettle(); expect(tester.widget(find.byType(Container)).color, equals(Colors.green)); }); diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index 7980783745f30..37aca52459642 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -1099,10 +1099,16 @@ class _MenuItemButtonState extends State { void _handleSelect() { assert(_debugMenuInfo('Selected ${widget.child} menu')); - widget.onPressed?.call(); if (widget.closeOnActivate) { _MenuAnchorState._maybeOf(context)?._root._close(); } + // Delay the call to onPressed until post-frame so that the focus is + // restored to what it was before the menu was opened before the action is + // executed. + SchedulerBinding.instance.addPostFrameCallback((Duration _) { + FocusManager.instance.applyFocusChangesIfNeeded(); + widget.onPressed?.call(); + }); } void _createInternalFocusNodeIfNeeded() { diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index b167ed114d0fb..f534b992f7a8d 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -8,6 +8,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/painting.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'binding.dart'; @@ -1601,10 +1602,32 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { return; } _haveScheduledUpdate = true; - scheduleMicrotask(_applyFocusChange); + scheduleMicrotask(applyFocusChangesIfNeeded); } - void _applyFocusChange() { + /// Applies any pending focus changes and notifies listeners that the focus + /// has changed. + /// + /// Must not be called during the build phase. This method is meant to be + /// called in a post-frame callback or microtask when the pending focus + /// changes need to be resolved before something else occurs. + /// + /// It can't be called during the build phase because not all listeners are + /// safe to be called with an update during a build. + /// + /// Typically, this is called automatically by the [FocusManager], but + /// sometimes it is necessary to ensure that no focus changes are pending + /// before executing an action. For example, the [MenuAnchor] class uses this + /// to make sure that the previous focus has been restored before executing a + /// menu callback when a menu item is selected. + /// + /// It is safe to call this if no focus changes are pending. + void applyFocusChangesIfNeeded() { + assert( + SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks, + 'applyFocusChangesIfNeeded() should not be called during the build phase.' + ); + _haveScheduledUpdate = false; final FocusNode? previousFocus = _primaryFocus; diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index e48e855ff1d97..6de3e26a59c46 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -486,6 +486,53 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); + testWidgets('focus is returned to previous focus before invoking onPressed', (WidgetTester tester) async { + final FocusNode buttonFocus = FocusNode(debugLabel: 'Button Focus'); + FocusNode? focusInOnPressed; + + void onMenuSelected(TestMenu item) { + focusInOnPressed = FocusManager.instance.primaryFocus; + } + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Column( + children: [ + MenuBar( + controller: controller, + children: createTestMenus( + onPressed: onMenuSelected, + ), + ), + ElevatedButton( + autofocus: true, + onPressed: () {}, + focusNode: buttonFocus, + child: const Text('Press Me'), + ), + ], + ), + ), + ), + ); + + await tester.pump(); + expect(FocusManager.instance.primaryFocus, equals(buttonFocus)); + + await tester.tap(find.text(TestMenu.mainMenu1.label)); + await tester.pump(); + + await tester.tap(find.text(TestMenu.subMenu11.label)); + await tester.pump(); + + await tester.tap(find.text(TestMenu.subSubMenu110.label)); + await tester.pump(); + + expect(focusInOnPressed, equals(buttonFocus)); + expect(FocusManager.instance.primaryFocus, equals(buttonFocus)); + }); + group('Menu functions', () { testWidgets('basic menu structure', (WidgetTester tester) async { await tester.pumpWidget( @@ -3064,7 +3111,7 @@ void main() { child: Center( child: MenuItemButton( style: MenuItemButton.styleFrom(fixedSize: const Size(88.0, 36.0)), - onPressed: () { }, + onPressed: () {}, child: const Text('ABC'), ), ), @@ -3072,27 +3119,30 @@ void main() { ); // The flags should not have SemanticsFlag.isButton - expect(semantics, hasSemantics( - TestSemantics.root( - children: [ - TestSemantics.rootChild( - actions: [ - SemanticsAction.tap, - ], - label: 'ABC', - rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), - transform: Matrix4.translationValues(356.0, 276.0, 0.0), - flags: [ - SemanticsFlag.hasEnabledState, - SemanticsFlag.isEnabled, - SemanticsFlag.isFocusable, - ], - textDirection: TextDirection.ltr, - ), - ], + expect( + semantics, + hasSemantics( + TestSemantics.root( + children: [ + TestSemantics.rootChild( + actions: [ + SemanticsAction.tap, + ], + label: 'ABC', + rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), + transform: Matrix4.translationValues(356.0, 276.0, 0.0), + flags: [ + SemanticsFlag.hasEnabledState, + SemanticsFlag.isEnabled, + SemanticsFlag.isFocusable, + ], + textDirection: TextDirection.ltr, + ), + ], + ), + ignoreId: true, ), - ignoreId: true, - )); + ); semantics.dispose(); }); @@ -3114,22 +3164,23 @@ void main() { ); // The flags should not have SemanticsFlag.isButton - expect(semantics, hasSemantics( - TestSemantics.root( - children: [ - TestSemantics.rootChild( - label: 'ABC', - rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), - transform: Matrix4.translationValues(356.0, 276.0, 0.0), - flags: [ - SemanticsFlag.hasEnabledState, - ], - textDirection: TextDirection.ltr, - ), - ], + expect( + semantics, + hasSemantics( + TestSemantics.root( + children: [ + TestSemantics( + rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), + flags: [SemanticsFlag.hasEnabledState], + label: 'ABC', + textDirection: TextDirection.ltr, + ), + ], + ), + ignoreTransform: true, + ignoreId: true, ), - ignoreId: true, - )); + ); semantics.dispose(); }); From f17f7483cb72780741645e914e44a122cdfe0b1e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 18:15:06 -0400 Subject: [PATCH 0298/1547] Roll Flutter Engine from 9b2ebf2afe00 to ab7d424d4467 (4 revisions) (#131015) https://github.com/flutter/engine/compare/9b2ebf2afe00...ab7d424d4467 2023-07-20 jonahwilliams@google.com [Impeller] Provide fragment uniform data through varyings for solid color, glyph atlas, texture shaders. (flutter/engine#43838) 2023-07-20 skia-flutter-autoroll@skia.org Roll ANGLE from a4c283be741f to f2e0f8a0b236 (2 revisions) (flutter/engine#43864) 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from 18e834916f47 to 100d0f858f02 (7 revisions) (flutter/engine#43863) 2023-07-20 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from SmAtKPfGzPllC9gfO... to -SaPL-46jpiYbnCAu... (flutter/engine#43862) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from SmAtKPfGzPll to -SaPL-46jpiY If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8fd3a989a33ae..1c5bea6696eb1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9b2ebf2afe008fd47f5cc81921d36ef442132c23 +ab7d424d4467399d8e62938096237c494488d3d9 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 9ca77ea4f3c6e..64eb3399721d6 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -SmAtKPfGzPllC9gfOpu2NtueRGB1spsiuLFWR8bhThoC +-SaPL-46jpiYbnCAuxBqbPdjsZOg1mDtQVZIdr11GVkC From 0df683c09b7a07bc5b6a7ceccd91602e20566569 Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Thu, 20 Jul 2023 17:02:53 -0700 Subject: [PATCH 0299/1547] Roll pub packages (#131022) This PR was generated by `flutter update-packages --force-upgrade`. --- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 4 ++-- .../android_embedding_v2_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- dev/integration_tests/gradle_deprecated_settings/pubspec.yaml | 4 ++-- dev/integration_tests/hybrid_android_views/pubspec.yaml | 4 ++-- dev/integration_tests/ios_app_with_extensions/pubspec.yaml | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 995328458fdbc..7f8f450865718 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: e075 +# PUBSPEC CHECKSUM: fc76 diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index 01c60250358f0..172d2a4a5b3d1 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -32,7 +32,7 @@ dependencies: collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -96,4 +96,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 9e17 +# PUBSPEC CHECKSUM: c218 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index cd9b03e750718..6dc8cc87e1e70 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: abb6 +# PUBSPEC CHECKSUM: bab7 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index ade76b8cbfcdf..afd07da98a33d 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" url_launcher_ios: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 4004 +# PUBSPEC CHECKSUM: 7105 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index e2555a9ad85fb..1777e2beefdc0 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" quiver: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6604 +# PUBSPEC CHECKSUM: d205 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 388af25d65588..04d4e969a80b3 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: abb6 +# PUBSPEC CHECKSUM: bab7 diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index 08cab7f06ea3d..2cadc95facb3b 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: device_info_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: b172 +# PUBSPEC CHECKSUM: d573 From 273441eef2ae2f6cd0823a276bb287cdc973dc4a Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Thu, 20 Jul 2023 17:14:02 -0700 Subject: [PATCH 0300/1547] Use downgraded analyze for flutter/packages (#130878) Add the `--downgrade` flag to the flutter/packages analyze test, so that it won't get the latest version of dependencies, avoiding out-of-band failures in flutter/flutter due to package publishing events. Fixes https://github.com/flutter/flutter/issues/129633 --- dev/bots/test.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dev/bots/test.dart b/dev/bots/test.dart index d4aa4e7d232ca..7d7784ff58daf 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1460,6 +1460,13 @@ Future _runFlutterPackagesTests() async { 'run', toolScript, 'analyze', + // Fetch the oldest possible dependencies, rather than the newest, to + // insulate flutter/flutter from out-of-band failures when new versions + // of dependencies are published. This compensates for the fact that + // flutter/packages doesn't use pinned dependencies, and for the + // purposes of this test using old dependencies is fine. See + // https://github.com/flutter/flutter/issues/129633 + '--downgrade', '--custom-analysis=script/configs/custom_analysis.yaml', ], workingDirectory: checkout.path, From a6750235e87b9c272948f29ebf36b9f6916d00af Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 20:37:24 -0400 Subject: [PATCH 0301/1547] Roll Flutter Engine from ab7d424d4467 to 218b71cd7a45 (2 revisions) (#131024) https://github.com/flutter/engine/compare/ab7d424d4467...218b71cd7a45 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from 981146e6305d to 6f2b2e94ebbd (3 revisions) (flutter/engine#43871) 2023-07-20 skia-flutter-autoroll@skia.org Roll Skia from 100d0f858f02 to 981146e6305d (3 revisions) (flutter/engine#43866) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1c5bea6696eb1..564148780f544 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ab7d424d4467399d8e62938096237c494488d3d9 +218b71cd7a454d4c5c183f8174f6cbb961744615 From 83e5aca1c97693775f2d8ac5a65278708ae13125 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 20 Jul 2023 21:26:17 -0400 Subject: [PATCH 0302/1547] Roll Flutter Engine from 218b71cd7a45 to b5a6b1c9cba5 (1 revision) (#131025) https://github.com/flutter/engine/compare/218b71cd7a45...b5a6b1c9cba5 2023-07-20 dnfield@google.com [Impeller] [Vulkan] Add reset command buffer bit to command pools. (flutter/engine#43867) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 564148780f544..61cff96774a50 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -218b71cd7a454d4c5c183f8174f6cbb961744615 +b5a6b1c9cba571c9a77e012a870c53ed67260ff1 From 5c86e4d7981724c9a906065f270a25ef4187dd5f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 00:11:27 -0400 Subject: [PATCH 0303/1547] Roll Flutter Engine from b5a6b1c9cba5 to 8ff10f5a7667 (5 revisions) (#131029) https://github.com/flutter/engine/compare/b5a6b1c9cba5...8ff10f5a7667 2023-07-21 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from hVAAd2NqYOjUF_I99... to CWNVmH6f_iryKU05E... (flutter/engine#43877) 2023-07-21 skia-flutter-autoroll@skia.org Roll Dart SDK from 1df95f328d0c to 8662af7d9aa3 (1 revision) (flutter/engine#43876) 2023-07-21 ian@hixie.ch Add a breadcrumb for people who want to run the web tests (flutter/engine#43865) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 049f389db75b to bae54bbf49bd (2 revisions) (flutter/engine#43875) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 6f2b2e94ebbd to 049f389db75b (1 revision) (flutter/engine#43873) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from hVAAd2NqYOjU to CWNVmH6f_iry If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 61cff96774a50..4508c01e43280 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b5a6b1c9cba571c9a77e012a870c53ed67260ff1 +8ff10f5a76675167d21193500e5ada9406d5e987 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index fb906094015ea..ed9c610a644e3 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -hVAAd2NqYOjUF_I998LDRT_IJPf5jijhH6q441hFXo8C +CWNVmH6f_iryKU05EiESfYJWQcVriQa0kV5nqppE86cC From f629809938972f2ad8ffcf0e86c0ed4f5052cfcd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 02:09:23 -0400 Subject: [PATCH 0304/1547] Roll Flutter Engine from 8ff10f5a7667 to 264685f0aecb (1 revision) (#131031) https://github.com/flutter/engine/compare/8ff10f5a7667...264685f0aecb 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from bae54bbf49bd to 31b0ed0c0054 (1 revision) (flutter/engine#43879) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4508c01e43280..fbc6c0952a2b0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8ff10f5a76675167d21193500e5ada9406d5e987 +264685f0aecbac8459919aa3aa04ff82444a40bb From 9e8ee3061c4a40e3caedc3de2246183d69d3cd04 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 03:11:23 -0400 Subject: [PATCH 0305/1547] Roll Flutter Engine from 264685f0aecb to f812cf373b6b (1 revision) (#131032) https://github.com/flutter/engine/compare/264685f0aecb...f812cf373b6b 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 31b0ed0c0054 to 3dce2d4ee4f3 (1 revision) (flutter/engine#43880) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fbc6c0952a2b0..17c350b84fad6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -264685f0aecbac8459919aa3aa04ff82444a40bb +f812cf373b6b1ec9daf2158e90ddb696ee8d1c6b From d67d2c3d2d4fab90a35877f62f54a24713bbd82e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 04:04:31 -0400 Subject: [PATCH 0306/1547] Roll Flutter Engine from f812cf373b6b to f5c1650c7acc (1 revision) (#131037) https://github.com/flutter/engine/compare/f812cf373b6b...f5c1650c7acc 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 3dce2d4ee4f3 to 4857e876d8cf (1 revision) (flutter/engine#43882) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 17c350b84fad6..e149ba6f53b41 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f812cf373b6b1ec9daf2158e90ddb696ee8d1c6b +f5c1650c7acc5ed6dc66af59a0bd156344f813d0 From aafdbc6d12cd800450722543b4f6262a892ddfd4 Mon Sep 17 00:00:00 2001 From: hangyu Date: Fri, 21 Jul 2023 03:38:54 -0700 Subject: [PATCH 0307/1547] Add tests for navigation_drawer_theme_test.dart (#130465) fixes: https://github.com/flutter/flutter/issues/129618 --- .../lib/src/material/navigation_drawer.dart | 9 +- .../navigation_drawer_theme_test.dart | 291 ++++++++++++++++++ 2 files changed, 296 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_drawer.dart b/packages/flutter/lib/src/material/navigation_drawer.dart index f52e20274f8de..611a2d51d7644 100644 --- a/packages/flutter/lib/src/material/navigation_drawer.dart +++ b/packages/flutter/lib/src/material/navigation_drawer.dart @@ -165,12 +165,13 @@ class NavigationDrawer extends StatelessWidget { destinationIndex += 1; } } + final NavigationDrawerThemeData navigationDrawerTheme = NavigationDrawerTheme.of(context); return Drawer( - backgroundColor: backgroundColor, - shadowColor: shadowColor, - surfaceTintColor: surfaceTintColor, - elevation: elevation, + backgroundColor: backgroundColor ?? navigationDrawerTheme.backgroundColor, + shadowColor: shadowColor ?? navigationDrawerTheme.shadowColor, + surfaceTintColor: surfaceTintColor ?? navigationDrawerTheme.surfaceTintColor, + elevation: elevation ?? navigationDrawerTheme.elevation, child: SafeArea( bottom: false, child: ListView( diff --git a/packages/flutter/test/material/navigation_drawer_theme_test.dart b/packages/flutter/test/material/navigation_drawer_theme_test.dart index 411ad46d8e8ff..2df6b7edf2b59 100644 --- a/packages/flutter/test/material/navigation_drawer_theme_test.dart +++ b/packages/flutter/test/material/navigation_drawer_theme_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -16,4 +17,294 @@ void main() { const NavigationDrawerThemeData data = NavigationDrawerThemeData(); expect(identical(NavigationDrawerThemeData.lerp(data, data, 0.5), data), true); }); + + testWidgets('Default debugFillProperties', (WidgetTester tester) async { + final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); + const NavigationDrawerThemeData().debugFillProperties(builder); + + final List description = builder.properties + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); + + expect(description, []); + }); + + testWidgets('NavigationDrawerThemeData implements debugFillProperties', (WidgetTester tester) async { + final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); + const NavigationDrawerThemeData( + tileHeight: 50, + backgroundColor: Color(0x00000099), + elevation: 5.0, + shadowColor: Color(0x00000098), + surfaceTintColor: Color(0x00000097), + indicatorColor: Color(0x00000096), + indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), + indicatorSize: Size(10, 10), + labelTextStyle: MaterialStatePropertyAll(TextStyle(fontSize: 7.0)), + iconTheme: MaterialStatePropertyAll(IconThemeData(color: Color(0x00000095))), + ).debugFillProperties(builder); + + final List description = builder.properties + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); + + expect(description, equalsIgnoringHashCodes( + [ + 'tileHeight: 50.0', + 'backgroundColor: Color(0x00000099)', + 'elevation: 5.0', + 'shadowColor: Color(0x00000098)', + 'surfaceTintColor: Color(0x00000097)', + 'indicatorColor: Color(0x00000096)', + 'indicatorShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', + 'indicatorSize: Size(10.0, 10.0)', + 'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))', + 'iconTheme: MaterialStatePropertyAll(IconThemeData#00000(color: Color(0x00000095)))' + ], + )); + }); + + testWidgets( + 'NavigationDrawerThemeData values are used when no NavigationDrawer properties are specified', + (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + const NavigationDrawerThemeData navigationDrawerTheme = NavigationDrawerThemeData( + backgroundColor: Color(0x00000001), + elevation: 7.0, + shadowColor: Color(0x00000002), + surfaceTintColor: Color(0x00000003), + indicatorColor: Color(0x00000004), + indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topRight: Radius.circular(16.0))), + labelTextStyle:MaterialStatePropertyAll(TextStyle(fontSize: 7.0)), + iconTheme: MaterialStatePropertyAll(IconThemeData(color: Color(0x00000005))), + ); + + await tester.pumpWidget( + _buildWidget( + scaffoldKey, + NavigationDrawer( + children: const [ + Text('Headline'), + NavigationDrawerDestination( + icon: Icon(Icons.ac_unit), + label: Text('AC'), + ), + NavigationDrawerDestination( + icon: Icon(Icons.access_alarm), + label: Text('Alarm'), + ), + ], + onDestinationSelected: (int i) {}, + ), + theme: ThemeData( + navigationDrawerTheme: navigationDrawerTheme, + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pump(const Duration(seconds: 1)); + + // Test drawer Material. + expect(_getMaterial(tester).color, navigationDrawerTheme.backgroundColor); + expect(_getMaterial(tester).surfaceTintColor, navigationDrawerTheme.surfaceTintColor); + expect(_getMaterial(tester).shadowColor, navigationDrawerTheme.shadowColor); + expect(_getMaterial(tester).elevation, 7); + // Test indicator decoration. + expect(_getIndicatorDecoration(tester)?.color, navigationDrawerTheme.indicatorColor); + expect(_getIndicatorDecoration(tester)?.shape, navigationDrawerTheme.indicatorShape); + // Test icon. + expect( + _iconStyle(tester, Icons.ac_unit)?.color, + navigationDrawerTheme.iconTheme?.resolve({})?.color, + ); + expect( + _iconStyle(tester, Icons.access_alarm)?.color, + navigationDrawerTheme.iconTheme?.resolve({})?.color, + ); + // Test label. + expect( + _labelStyle(tester, 'AC'), + navigationDrawerTheme.labelTextStyle?.resolve({}) + ); + expect( + _labelStyle(tester, 'Alarm'), + navigationDrawerTheme.labelTextStyle?.resolve({}) + ); + }); + + testWidgets( + 'NavigationDrawer values take priority over NavigationDrawerThemeData values when both properties are specified', + (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + const NavigationDrawerThemeData navigationDrawerTheme = NavigationDrawerThemeData( + backgroundColor: Color(0x00000001), + elevation: 7.0, + shadowColor: Color(0x00000002), + surfaceTintColor: Color(0x00000003), + indicatorColor: Color(0x00000004), + indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topRight: Radius.circular(16.0))), + labelTextStyle:MaterialStatePropertyAll(TextStyle(fontSize: 7.0)), + iconTheme: MaterialStatePropertyAll(IconThemeData(color: Color(0x00000005))), + ); + const Color backgroundColor = Color(0x00000009); + const double elevation = 14.0; + const Color shadowColor = Color(0x00000008); + const Color surfaceTintColor = Color(0x00000007); + const RoundedRectangleBorder indicatorShape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(32.0))); + const Color indicatorColor = Color(0x00000006); + + await tester.pumpWidget( + _buildWidget( + scaffoldKey, + NavigationDrawer( + backgroundColor: backgroundColor, + elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, + indicatorShape: indicatorShape, + indicatorColor: indicatorColor, + children: const [ + Text('Headline'), + NavigationDrawerDestination( + icon: Icon(Icons.ac_unit), + label: Text('AC'), + ), + NavigationDrawerDestination( + icon: Icon(Icons.access_alarm), + label: Text('Alarm'), + ), + ], + onDestinationSelected: (int i) {}, + ), + theme: ThemeData( + navigationDrawerTheme: navigationDrawerTheme, + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pump(const Duration(seconds: 1)); + + // Test drawer Material. + expect(_getMaterial(tester).color, backgroundColor); + expect(_getMaterial(tester).surfaceTintColor, surfaceTintColor); + expect(_getMaterial(tester).shadowColor, shadowColor); + expect(_getMaterial(tester).elevation, elevation); + // Test indicator decoration. + expect(_getIndicatorDecoration(tester)?.color, indicatorColor); + expect(_getIndicatorDecoration(tester)?.shape, indicatorShape); + }); + + testWidgets('Local NavigationDrawerTheme takes priority over ThemeData.navigationDrawerTheme', (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + const Color backgroundColor = Color(0x00000009); + const double elevation = 7.0; + const Color shadowColor = Color(0x00000008); + const Color surfaceTintColor = Color(0x00000007); + const Color iconColor = Color(0x00000006); + const TextStyle labelStyle = TextStyle(fontSize: 7.0); + const ShapeBorder indicatorShape = CircleBorder(); + const Color indicatorColor = Color(0x00000005); + + await tester.pumpWidget( + _buildWidget( + scaffoldKey, + NavigationDrawerTheme( + data: const NavigationDrawerThemeData( + backgroundColor: backgroundColor, + elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, + indicatorShape: indicatorShape, + indicatorColor: indicatorColor, + labelTextStyle:MaterialStatePropertyAll(TextStyle(fontSize: 7.0)), + iconTheme: MaterialStatePropertyAll(IconThemeData(color: iconColor)), + ), + child: NavigationDrawer( + children: const [ + Text('Headline'), + NavigationDrawerDestination( + icon: Icon(Icons.ac_unit), + label: Text('AC'), + ), + NavigationDrawerDestination( + icon: Icon(Icons.access_alarm), + label: Text('Alarm'), + ), + ], + onDestinationSelected: (int i) {}, + ), + ), + theme: ThemeData( + navigationDrawerTheme: const NavigationDrawerThemeData( + backgroundColor: Color(0x00000001), + elevation: 7.0, + shadowColor: Color(0x00000002), + surfaceTintColor: Color(0x00000003), + indicatorColor: Color(0x00000004), + indicatorShape: RoundedRectangleBorder(borderRadius: BorderRadius.only(topRight: Radius.circular(16.0))), + labelTextStyle:MaterialStatePropertyAll(TextStyle(fontSize: 7.0)), + iconTheme: MaterialStatePropertyAll(IconThemeData(color: Color(0x00000005))), + ), + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pump(const Duration(seconds: 1)); + + // Test drawer Material. + expect(_getMaterial(tester).color, backgroundColor); + expect(_getMaterial(tester).surfaceTintColor, surfaceTintColor); + expect(_getMaterial(tester).shadowColor, shadowColor); + expect(_getMaterial(tester).elevation, elevation); + // Test indicator decoration. + expect(_getIndicatorDecoration(tester)?.color, indicatorColor); + expect(_getIndicatorDecoration(tester)?.shape, indicatorShape); + // Test icon. + expect(_iconStyle(tester, Icons.ac_unit)?.color, iconColor); + expect(_iconStyle(tester, Icons.access_alarm)?.color, iconColor); + // Test label. + expect(_labelStyle(tester, 'AC'), labelStyle); + expect(_labelStyle(tester, 'Alarm'), labelStyle); + }); +} + +Widget _buildWidget(GlobalKey scaffoldKey, Widget child, { ThemeData? theme }) { + return MaterialApp( + theme: theme, + home: Scaffold( + key: scaffoldKey, + drawer: child, + body: Container(), + ), + ); +} + +Material _getMaterial(WidgetTester tester) { + return tester.firstWidget(find.descendant( + of: find.byType(NavigationDrawer), + matching: find.byType(Material), + )); +} + +ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) { + return tester.firstWidget(find.descendant( + of: find.byType(FadeTransition), + matching: find.byType(Container), + )).decoration as ShapeDecoration?; +} + +TextStyle? _iconStyle(WidgetTester tester, IconData icon) { + return tester.widget( + find.descendant(of: find.byIcon(icon), + matching: find.byType(RichText)), + ).text.style; +} + +TextStyle? _labelStyle(WidgetTester tester, String label) { + return tester.widget(find.descendant( + of: find.text(label), + matching: find.byType(RichText), + )).text.style; } From 9cfbf6b9fd40780f69e49c0a82a5484b8eb62758 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 11:54:06 -0400 Subject: [PATCH 0308/1547] Roll Packages from 674179f97bda to 2266a7618ee3 (6 revisions) (#131058) https://github.com/flutter/packages/compare/674179f97bda...2266a7618ee3 2023-07-21 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.20.4 to 2.21.0 (flutter/packages#4525) 2023-07-20 34871572+gmackall@users.noreply.github.com [url_launcher_android] Set `buildFeatures.buildConfig` to true for compatibility with AGP 8.0+ (flutter/packages#4535) 2023-07-20 59682979+utamori@users.noreply.github.com [go_router] fix error handling page link (flutter/packages#4296) 2023-07-20 stuartmorgan@google.com [plugin_platform_interface] Adopt code-excerpts (flutter/packages#4534) 2023-07-20 stuartmorgan@google.com [ci] Simplify Dockerfile (flutter/packages#4530) 2023-07-20 stuartmorgan@google.com [ci] Enable Windows Dart unit test sharding (flutter/packages#4528) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 56d8a83d2a2c4..44863a37272e3 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -674179f97bda7eab1aa5454a0be185ed7312af51 +2266a7618ee3139da8698369c1073d3f852c2dfc From 0919fb86f1b61727ebcc39ff6ea4203cbfce0381 Mon Sep 17 00:00:00 2001 From: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> Date: Fri, 21 Jul 2023 19:07:39 +0200 Subject: [PATCH 0309/1547] Improve handling of certain icons in RTL (#130979) Fixes https://github.com/flutter/flutter/issues/130978 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- dev/tools/test/update_icons_test.dart | 57 ++++++++++++++++++++ dev/tools/update_icons.dart | 12 +++-- packages/flutter/lib/src/material/icons.dart | 40 +++++++------- 3 files changed, 84 insertions(+), 25 deletions(-) diff --git a/dev/tools/test/update_icons_test.dart b/dev/tools/test/update_icons_test.dart index b7fa706d93ad8..6b1fbe436294f 100644 --- a/dev/tools/test/update_icons_test.dart +++ b/dev/tools/test/update_icons_test.dart @@ -61,4 +61,61 @@ void main() { 'Icon(Icons.onetwothree_rounded),', ); }); + + test('certain icons should be mirrored in RTL', () { + // Exact match + expect( + Icon(const MapEntry('help', '')).isMirroredInRTL, + true, + ); + // Variant + expect( + Icon(const MapEntry('help_rounded', '')).isMirroredInRTL, + true, + ); + // Common suffixes + expect( + Icon(const MapEntry('help_alt', '')).isMirroredInRTL, + true, + ); + expect( + Icon(const MapEntry('help_new', '')).isMirroredInRTL, + true, + ); + expect( + Icon(const MapEntry('help_off', '')).isMirroredInRTL, + true, + ); + expect( + Icon(const MapEntry('help_on', '')).isMirroredInRTL, + true, + ); + // Common suffixes + variant + expect( + Icon(const MapEntry('help_alt_rounded', '')).isMirroredInRTL, + true, + ); + expect( + Icon(const MapEntry('help_new_rounded', '')).isMirroredInRTL, + true, + ); + expect( + Icon(const MapEntry('help_off_rounded', '')).isMirroredInRTL, + true, + ); + expect( + Icon(const MapEntry('help_on_rounded', '')).isMirroredInRTL, + true, + ); + // No match + expect( + Icon(const MapEntry('help_center_rounded', '')).isMirroredInRTL, + false, + ); + // No match + expect( + Icon(const MapEntry('arrow', '')).isMirroredInRTL, + false, + ); + }); } diff --git a/dev/tools/update_icons.dart b/dev/tools/update_icons.dart index bbe77f0459f15..9d56f540ba958 100644 --- a/dev/tools/update_icons.dart +++ b/dev/tools/update_icons.dart @@ -150,7 +150,7 @@ const Set _iconsMirroredWhenRTL = { 'navigate_next', 'next_week', 'note', - 'open_in_new', + 'open_in', 'playlist_add', 'queue_music', 'redo', @@ -513,12 +513,14 @@ class Icon { String get usage => 'Icon($className.$flutterId),'; - String get mirroredInRTL => _iconsMirroredWhenRTL.contains(shortId) - ? ', matchTextDirection: true' - : ''; + bool get isMirroredInRTL { + // Remove common suffixes (e.g. "_new" or "_alt") from the shortId. + final String normalizedShortId = shortId.replaceAll(RegExp(r'_(new|alt|off|on)$'), ''); + return _iconsMirroredWhenRTL.any((String shortIdMirroredWhenRTL) => normalizedShortId == shortIdMirroredWhenRTL); + } String get declaration => - "static const IconData $flutterId = IconData(0x$hexCodepoint, fontFamily: '$fontFamily'$mirroredInRTL);"; + "static const IconData $flutterId = IconData(0x$hexCodepoint, fontFamily: '$fontFamily'${isMirroredInRTL ? ', matchTextDirection: true' : ''});"; String get fullDeclaration => ''' diff --git a/packages/flutter/lib/src/material/icons.dart b/packages/flutter/lib/src/material/icons.dart index 59f3b088499f5..5d96c9914d370 100644 --- a/packages/flutter/lib/src/material/icons.dart +++ b/packages/flutter/lib/src/material/icons.dart @@ -2154,16 +2154,16 @@ abstract final class Icons { static const IconData arrow_back_ios_outlined = IconData(0xee84, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_back_ios_new — material icon named "arrow back ios new". - static const IconData arrow_back_ios_new = IconData(0xe094, fontFamily: 'MaterialIcons'); + static const IconData arrow_back_ios_new = IconData(0xe094, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_back_ios_new — material icon named "arrow back ios new" (sharp). - static const IconData arrow_back_ios_new_sharp = IconData(0xe791, fontFamily: 'MaterialIcons'); + static const IconData arrow_back_ios_new_sharp = IconData(0xe791, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_back_ios_new — material icon named "arrow back ios new" (round). - static const IconData arrow_back_ios_new_rounded = IconData(0xf570, fontFamily: 'MaterialIcons'); + static const IconData arrow_back_ios_new_rounded = IconData(0xf570, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_back_ios_new — material icon named "arrow back ios new" (outlined). - static const IconData arrow_back_ios_new_outlined = IconData(0xee83, fontFamily: 'MaterialIcons'); + static const IconData arrow_back_ios_new_outlined = IconData(0xee83, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_circle_down — material icon named "arrow circle down". static const IconData arrow_circle_down = IconData(0xe095, fontFamily: 'MaterialIcons'); @@ -2322,16 +2322,16 @@ abstract final class Icons { static const IconData arrow_right_outlined = IconData(0xee90, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_right_alt — material icon named "arrow right alt". - static const IconData arrow_right_alt = IconData(0xe09f, fontFamily: 'MaterialIcons'); + static const IconData arrow_right_alt = IconData(0xe09f, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_right_alt — material icon named "arrow right alt" (sharp). - static const IconData arrow_right_alt_sharp = IconData(0xe79d, fontFamily: 'MaterialIcons'); + static const IconData arrow_right_alt_sharp = IconData(0xe79d, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_right_alt — material icon named "arrow right alt" (round). - static const IconData arrow_right_alt_rounded = IconData(0xf57c, fontFamily: 'MaterialIcons'); + static const IconData arrow_right_alt_rounded = IconData(0xf57c, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_right_alt — material icon named "arrow right alt" (outlined). - static const IconData arrow_right_alt_outlined = IconData(0xee8f, fontFamily: 'MaterialIcons'); + static const IconData arrow_right_alt_outlined = IconData(0xee8f, fontFamily: 'MaterialIcons', matchTextDirection: true); /// arrow_upward — material icon named "arrow upward". static const IconData arrow_upward = IconData(0xe0a0, fontFamily: 'MaterialIcons'); @@ -12900,16 +12900,16 @@ abstract final class Icons { static const IconData label_important_outline_rounded = IconData(0xf839, fontFamily: 'MaterialIcons'); /// label_off — material icon named "label off". - static const IconData label_off = IconData(0xe363, fontFamily: 'MaterialIcons'); + static const IconData label_off = IconData(0xe363, fontFamily: 'MaterialIcons', matchTextDirection: true); /// label_off — material icon named "label off" (sharp). - static const IconData label_off_sharp = IconData(0xea5c, fontFamily: 'MaterialIcons'); + static const IconData label_off_sharp = IconData(0xea5c, fontFamily: 'MaterialIcons', matchTextDirection: true); /// label_off — material icon named "label off" (round). - static const IconData label_off_rounded = IconData(0xf83b, fontFamily: 'MaterialIcons'); + static const IconData label_off_rounded = IconData(0xf83b, fontFamily: 'MaterialIcons', matchTextDirection: true); /// label_off — material icon named "label off" (outlined). - static const IconData label_off_outlined = IconData(0xf14c, fontFamily: 'MaterialIcons'); + static const IconData label_off_outlined = IconData(0xf14c, fontFamily: 'MaterialIcons', matchTextDirection: true); /// label_outline — material icon named "label outline". static const IconData label_outline = IconData(0xe364, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -13362,16 +13362,16 @@ abstract final class Icons { static const IconData list_outlined = IconData(0xf16d, fontFamily: 'MaterialIcons', matchTextDirection: true); /// list_alt — material icon named "list alt". - static const IconData list_alt = IconData(0xe385, fontFamily: 'MaterialIcons'); + static const IconData list_alt = IconData(0xe385, fontFamily: 'MaterialIcons', matchTextDirection: true); /// list_alt — material icon named "list alt" (sharp). - static const IconData list_alt_sharp = IconData(0xea7e, fontFamily: 'MaterialIcons'); + static const IconData list_alt_sharp = IconData(0xea7e, fontFamily: 'MaterialIcons', matchTextDirection: true); /// list_alt — material icon named "list alt" (round). - static const IconData list_alt_rounded = IconData(0xf85d, fontFamily: 'MaterialIcons'); + static const IconData list_alt_rounded = IconData(0xf85d, fontFamily: 'MaterialIcons', matchTextDirection: true); /// list_alt — material icon named "list alt" (outlined). - static const IconData list_alt_outlined = IconData(0xf16c, fontFamily: 'MaterialIcons'); + static const IconData list_alt_outlined = IconData(0xf16c, fontFamily: 'MaterialIcons', matchTextDirection: true); /// live_help — material icon named "live help". static const IconData live_help = IconData(0xe386, fontFamily: 'MaterialIcons', matchTextDirection: true); @@ -16224,16 +16224,16 @@ abstract final class Icons { static const IconData note_add_outlined = IconData(0xf22e, fontFamily: 'MaterialIcons'); /// note_alt — material icon named "note alt". - static const IconData note_alt = IconData(0xe44b, fontFamily: 'MaterialIcons'); + static const IconData note_alt = IconData(0xe44b, fontFamily: 'MaterialIcons', matchTextDirection: true); /// note_alt — material icon named "note alt" (sharp). - static const IconData note_alt_sharp = IconData(0xeb42, fontFamily: 'MaterialIcons'); + static const IconData note_alt_sharp = IconData(0xeb42, fontFamily: 'MaterialIcons', matchTextDirection: true); /// note_alt — material icon named "note alt" (round). - static const IconData note_alt_rounded = IconData(0xf0021, fontFamily: 'MaterialIcons'); + static const IconData note_alt_rounded = IconData(0xf0021, fontFamily: 'MaterialIcons', matchTextDirection: true); /// note_alt — material icon named "note alt" (outlined). - static const IconData note_alt_outlined = IconData(0xf22f, fontFamily: 'MaterialIcons'); + static const IconData note_alt_outlined = IconData(0xf22f, fontFamily: 'MaterialIcons', matchTextDirection: true); /// notes — material icon named "notes". static const IconData notes = IconData(0xe44c, fontFamily: 'MaterialIcons'); From 764095ce1a313dd402aa87c8132b255a67a0188b Mon Sep 17 00:00:00 2001 From: Dan Field Date: Fri, 21 Jul 2023 11:21:22 -0700 Subject: [PATCH 0310/1547] [CI/FTL] Oriole to Panther, presubmit false (#130912) Alternative to https://github.com/flutter/flutter/pull/130868 Oriole is the Pixel 6, Panther is the Pixel 7. Panther is more available in FTL at this point. There's less value in running this on presubmit, since those can spawn many jobs multiple times over as people push new commits to branches. Let's just run it post submit to avoid overloading the capacity of FTL. --- .ci.yaml | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 3ebe720f1c12a..ce37a5f61b29d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -411,26 +411,9 @@ targets: - bin/** - .ci.yaml - - name: Linux firebase_oriol33_abstract_method_smoke_test - bringup: true - recipe: firebaselab/firebaselab - timeout: 60 - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "open_jdk", "version": "version:11"} - ] - tags: > - ["firebaselab"] - task_name: abstract_method_smoke_test - physical_devices: >- - ["--device", "model=oriole,version=33"] - virtual_devices: >- - [] - - name: Linux firebase_abstract_method_smoke_test bringup: false + presubmit: false recipe: firebaselab/firebaselab timeout: 60 properties: @@ -444,8 +427,8 @@ targets: task_name: abstract_method_smoke_test physical_devices: >- [ - "--device", "model=redfin,version=30", - "--device", "model=griffin,version=24" + "--device", "model=panther,version=33", + "--device", "model=redfin,version=30" ] # TODO(flutter/flutter#123331): This device is flaking. # "--device", "model=Nexus6P,version=25", @@ -454,6 +437,7 @@ targets: "--device", "model=Nexus5,version=21", "--device", "model=Nexus5,version=22", "--device", "model=Nexus5,version=23", + "--device", "model=Nexus5,version=24", "--device", "model=Nexus6P,version=26", "--device", "model=Nexus6P,version=27", "--device", "model=NexusLowRes,version=29" From be7c7e3e45f4bb7c420b2fbaba27ac64bfc8952d Mon Sep 17 00:00:00 2001 From: Valentin Vignal <32538273+ValentinVignal@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:09:25 +0800 Subject: [PATCH 0311/1547] Suggest a potential valid name for the flutter project when using `flutter create` (#130900) Fixes https://github.com/flutter/flutter/issues/109775 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/commands/create_base.dart | 30 +++++++++++++++++-- .../commands.shard/permeable/create_test.dart | 7 +++-- .../general.shard/create_config_test.dart | 12 ++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index 36e84c40f4d1f..b0de202c94baf 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -784,12 +784,38 @@ bool isValidPackageName(String name) { !_keywords.contains(name); } +/// Returns a potential valid name from the given [name]. +/// +/// If a valid name cannot be found, returns `null`. +@visibleForTesting +String? potentialValidPackageName(String name){ + String newName = name.toLowerCase(); + if (newName.startsWith(RegExp(r'[0-9]'))) { + newName = '_$newName'; + } + newName = newName.replaceAll('-', '_'); + if (isValidPackageName(newName)) { + return newName; + } else { + return null; + } +} + // Return null if the project name is legal. Return a validation message if // we should disallow the project name. String? _validateProjectName(String projectName) { if (!isValidPackageName(projectName)) { - return '"$projectName" is not a valid Dart package name.\n\n' - 'See https://dart.dev/tools/pub/pubspec#name for more information.'; + final String? potentialValidName = potentialValidPackageName(projectName); + + return [ + '"$projectName" is not a valid Dart package name.', + '\n\n', + 'The name should be all lowercase, with underscores to separate words, "just_like_this".', + 'Use only basic Latin letters and Arabic digits: [a-z0-9_].', + "Also, make sure the name is a valid Dart identifier—that it doesn't start with digits and isn't a reserved word.\n", + 'See https://dart.dev/tools/pub/pubspec#name for more information.', + if (potentialValidName != null) '\nTry "$potentialValidName" instead.', + ].join(); } if (_packageDependencies.contains(projectName)) { return "Invalid project name: '$projectName' - this will conflict with Flutter " diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 1663f8cdaf2ea..4e5488513fb03 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -735,10 +735,13 @@ void main() { testUsingContext('plugin project with invalid custom project name', () async { expect( () => _createProject(projectDir, - ['--no-pub', '--template=plugin', '--project-name', 'xyz.xyz', '--platforms', 'android,ios',], + ['--no-pub', '--template=plugin', '--project-name', 'xyz-xyz', '--platforms', 'android,ios',], [], ), - throwsToolExit(message: '"xyz.xyz" is not a valid Dart package name.'), + allOf( + throwsToolExit(message: '"xyz-xyz" is not a valid Dart package name.'), + throwsToolExit(message: 'Try "xyz_xyz" instead.'), + ), ); }); diff --git a/packages/flutter_tools/test/general.shard/create_config_test.dart b/packages/flutter_tools/test/general.shard/create_config_test.dart index 4d41ec9e965c7..bc48b2d998df1 100644 --- a/packages/flutter_tools/test/general.shard/create_config_test.dart +++ b/packages/flutter_tools/test/general.shard/create_config_test.dart @@ -20,6 +20,18 @@ void main() { expect(isValidPackageName('Foo_bar'), false); }); + test('Suggests a valid Pub package name', () { + expect(potentialValidPackageName('92'), '_92'); + expect(potentialValidPackageName('a-b-c'), 'a_b_c'); + + + expect(potentialValidPackageName('Foo_bar'), 'foo_bar'); + expect(potentialValidPackageName('foo-_bar'), 'foo__bar'); + + expect(potentialValidPackageName('잘못된 이름'), isNull, reason: 'It should return null if it cannot find a valid name.'); + + }); + test('kWindowsDrivePattern', () { expect(CreateBase.kWindowsDrivePattern.hasMatch(r'D:\'), isFalse); expect(CreateBase.kWindowsDrivePattern.hasMatch(r'z:\'), isFalse); From 65c77f4857887ba61838d5c615d7233e11575e9f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 17:05:50 -0400 Subject: [PATCH 0312/1547] Manual roll Flutter Engine from f5c1650c7acc to acb5d0640b6c (10 revisions) (#131070) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/f5c1650c7acc...acb5d0640b6c 2023-07-21 zanderso@users.noreply.github.com Revert Dart (flutter/engine#43895) 2023-07-21 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from CWNVmH6f_iryKU05E... to gpjF3QRGg_KH0guW5... (flutter/engine#43894) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 8388ec4d242c to e3d13d1b1c42 (1 revision) (flutter/engine#43893) 2023-07-21 skia-flutter-autoroll@skia.org Roll Dart SDK from 6e79151ce988 to 921613a055ff (1 revision) (flutter/engine#43892) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 3dd45617581b to 8388ec4d242c (1 revision) (flutter/engine#43891) 2023-07-21 skia-flutter-autoroll@skia.org Roll ANGLE from b60068009dca to 2e190280f5c5 (2 revisions) (flutter/engine#43890) 2023-07-21 skia-flutter-autoroll@skia.org Roll ANGLE from f2e0f8a0b236 to b60068009dca (1 revision) (flutter/engine#43887) 2023-07-21 skia-flutter-autoroll@skia.org Roll Dart SDK from 8662af7d9aa3 to 6e79151ce988 (2 revisions) (flutter/engine#43885) 2023-07-21 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from -SaPL-46jpiYbnCAu... to WH3AaCa4DtVERww1v... (flutter/engine#43884) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 4857e876d8cf to 3dd45617581b (1 revision) (flutter/engine#43883) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from CWNVmH6f_iry to gpjF3QRGg_KH fuchsia/sdk/core/mac-amd64 from -SaPL-46jpiY to WH3AaCa4DtVE If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e149ba6f53b41..4586c72e72648 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f5c1650c7acc5ed6dc66af59a0bd156344f813d0 +acb5d0640b6cb0ec44c0fc11fecee65699aedd04 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index ed9c610a644e3..04fafff75c913 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -CWNVmH6f_iryKU05EiESfYJWQcVriQa0kV5nqppE86cC +gpjF3QRGg_KH0guW5V-RoIr5LqkUU4ygjJrq5ubSBsEC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 64eb3399721d6..00707a234556e 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ --SaPL-46jpiYbnCAuxBqbPdjsZOg1mDtQVZIdr11GVkC +WH3AaCa4DtVERww1valVty052zggPUiRPskIJ4kgG9AC From 30c005f7f435637b45d890ff241be45960f0fd68 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 21 Jul 2023 14:26:42 -0700 Subject: [PATCH 0313/1547] Upgrade to newer leak_tracker. (#131085) --- dev/bots/pubspec.yaml | 5 +++-- dev/devicelab/pubspec.yaml | 5 +++-- packages/flutter/pubspec.yaml | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index ce8caef99192b..c26cc9065d80c 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,6 +49,7 @@ dependencies: pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pubspec_parse: 1.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + retry: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +73,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 16d6 +# PUBSPEC CHECKSUM: 0884 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 26227aef98648..4b6f3f215a0bd 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -38,6 +38,7 @@ dependencies: json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + retry: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -70,4 +71,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0c44 +# PUBSPEC CHECKSUM: cbf1 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 4a9290839beb8..7bcec909305d9 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,7 +22,7 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 8.0.2 + leak_tracker: 8.0.3 leak_tracker_testing: 1.0.2 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 16f0 +# PUBSPEC CHECKSUM: 20f1 From 99a4f7e1f99e65f8a671fa09e039a99e965fbd2e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 18:39:17 -0400 Subject: [PATCH 0314/1547] Manual roll Flutter Engine from acb5d0640b6c to 2d8cff44261b (3 revisions) (#131092) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/acb5d0640b6c...2d8cff44261b 2023-07-21 ychris@google.com Refactor: fix typo "setup" -> "set up" (flutter/engine#43824) 2023-07-21 jonahwilliams@google.com [engine] disable picture complexity raster caching (flutter/engine#43897) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from e3d13d1b1c42 to 1f84e9d51bba (1 revision) (flutter/engine#43896) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4586c72e72648..926da1685dfd5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -acb5d0640b6cb0ec44c0fc11fecee65699aedd04 +2d8cff44261bc8e04f204ca27da7d4554964b4bb From 9a726e8542681326d91d0d750d3f268941603d0c Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Fri, 21 Jul 2023 15:59:01 -0700 Subject: [PATCH 0315/1547] Remove obsolete work around for shadow drawing (#131066) Fixes https://github.com/flutter/flutter/issues/130737. --- packages/flutter/lib/src/rendering/proxy_box.dart | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index a089fbe145204..441ca66ea16c4 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -1908,8 +1908,6 @@ abstract class _RenderPhysicalModelBase extends _RenderCustomClip { } } -final Paint _transparentPaint = Paint()..color = const Color(0x00000000); - /// Creates a physical model layer that clips its child to a rounded /// rectangle. /// @@ -2113,7 +2111,6 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase { } _updateClip(); - final Rect offsetBounds = offset & size; final Path offsetPath = _clip!.shift(offset); bool paintShadows = true; assert(() { @@ -2134,14 +2131,6 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase { final Canvas canvas = context.canvas; if (elevation != 0.0 && paintShadows) { - // The drawShadow call doesn't add the region of the shadow to the - // picture's bounds, so we draw a hardcoded amount of extra space to - // account for the maximum potential area of the shadow. - // TODO(jsimmons): remove this when Skia does it for us. - canvas.drawRect( - offsetBounds.inflate(20.0), - _transparentPaint, - ); canvas.drawShadow( offsetPath, shadowColor, From 3e67e1998fa7110be3b8fd3c7071ca95f9afd92b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 21 Jul 2023 20:45:07 -0400 Subject: [PATCH 0316/1547] Roll Flutter Engine from 2d8cff44261b to 840bcc3449ff (11 revisions) (#131101) https://github.com/flutter/engine/compare/2d8cff44261b...840bcc3449ff 2023-07-21 skia-flutter-autoroll@skia.org Roll ANGLE from f586ec98d924 to 938ee1e80fc8 (1 revision) (flutter/engine#43912) 2023-07-21 skia-flutter-autoroll@skia.org Roll ANGLE from 085f25bbb1e3 to f586ec98d924 (1 revision) (flutter/engine#43908) 2023-07-21 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from WH3AaCa4DtVERww1v... to rMFZIJYvVmXEBGCay... (flutter/engine#43907) 2023-07-21 jason-simmons@users.noreply.github.com [Impeller] Do not use clear color optimization if the subpass is being collapsed into its parent (flutter/engine#43878) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 2e28fe9de378 to 359d4726e423 (1 revision) (flutter/engine#43906) 2023-07-21 bdero@google.com [Impeller] Disable color attachment removal for clips on VK (flutter/engine#43905) 2023-07-21 bdero@google.com [Impeller] Add a way to query the gfx backend type. (flutter/engine#43837) 2023-07-21 skia-flutter-autoroll@skia.org Roll ANGLE from 82d68c577b1d to 085f25bbb1e3 (1 revision) (flutter/engine#43904) 2023-07-21 skia-flutter-autoroll@skia.org Roll ANGLE from 2e190280f5c5 to 82d68c577b1d (1 revision) (flutter/engine#43901) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 497326dc66cd to 2e28fe9de378 (2 revisions) (flutter/engine#43900) 2023-07-21 skia-flutter-autoroll@skia.org Roll Skia from 1f84e9d51bba to 497326dc66cd (1 revision) (flutter/engine#43899) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from WH3AaCa4DtVE to rMFZIJYvVmXE If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 926da1685dfd5..313c55ed75883 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2d8cff44261bc8e04f204ca27da7d4554964b4bb +840bcc3449ff54cefe4b9b250d8daa5ada243d6a diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 00707a234556e..5f37b94750890 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -WH3AaCa4DtVERww1valVty052zggPUiRPskIJ4kgG9AC +rMFZIJYvVmXEBGCay-wjvn6m1nVIU-KymF2MIuEo6KkC From 6b97716d11d13739f55d2ce8ab320b5730296d61 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 00:18:14 -0400 Subject: [PATCH 0317/1547] Roll Flutter Engine from 840bcc3449ff to b47cf14fda0e (3 revisions) (#131109) https://github.com/flutter/engine/compare/840bcc3449ff...b47cf14fda0e 2023-07-22 jonahwilliams@google.com [Impeller] size command pools to npot of command count. (flutter/engine#43903) 2023-07-22 skia-flutter-autoroll@skia.org Roll Skia from c79c781a3ce3 to 80e101dc5813 (1 revision) (flutter/engine#43914) 2023-07-22 skia-flutter-autoroll@skia.org Roll Skia from 359d4726e423 to c79c781a3ce3 (2 revisions) (flutter/engine#43913) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 313c55ed75883..8ab0cd62b32c2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -840bcc3449ff54cefe4b9b250d8daa5ada243d6a +b47cf14fda0e2ea9be620d822e54c3edbf736bbd From fd2e6b8cd352e54ae5d78e0f048f447f84434edd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 04:54:21 -0400 Subject: [PATCH 0318/1547] Roll Flutter Engine from b47cf14fda0e to 6344b17a2e03 (1 revision) (#131114) https://github.com/flutter/engine/compare/b47cf14fda0e...6344b17a2e03 2023-07-22 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from gpjF3QRGg_KH0guW5... to LZJYHQeLdXALTMMmj... (flutter/engine#43917) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from gpjF3QRGg_KH to LZJYHQeLdXAL If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8ab0cd62b32c2..59f0a20623acd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b47cf14fda0e2ea9be620d822e54c3edbf736bbd +6344b17a2e030d5d226267026d7e899127ac4ca5 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 04fafff75c913..1bcee67244342 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -gpjF3QRGg_KH0guW5V-RoIr5LqkUU4ygjJrq5ubSBsEC +LZJYHQeLdXALTMMmjxIngbM_8F_RBx5-YiDR9mc0C5wC From d4608046cdb8933526dde5fdc46dbfd7ff05e2fe Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 07:39:22 -0400 Subject: [PATCH 0319/1547] Roll Flutter Engine from 6344b17a2e03 to 481684a6e276 (2 revisions) (#131118) https://github.com/flutter/engine/compare/6344b17a2e03...481684a6e276 2023-07-22 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from rMFZIJYvVmXEBGCay... to UgZ9epS2Jkz7Yrymp... (flutter/engine#43922) 2023-07-22 skia-flutter-autoroll@skia.org Roll Skia from 80e101dc5813 to 85e8d8403b45 (1 revision) (flutter/engine#43921) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from rMFZIJYvVmXE to UgZ9epS2Jkz7 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 59f0a20623acd..550290ba23306 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6344b17a2e030d5d226267026d7e899127ac4ca5 +481684a6e2768e480febdcc53972a21a517db1d4 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 5f37b94750890..a13f4b2cc5fed 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -rMFZIJYvVmXEBGCay-wjvn6m1nVIU-KymF2MIuEo6KkC +UgZ9epS2Jkz7Yrymp9fnT2vZnmIUtBJdIuN2a54v_SIC From e8b397caca6f55b903ebf21734c76c6e00f4c15a Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Sat, 22 Jul 2023 06:45:27 -0700 Subject: [PATCH 0320/1547] Setup leak tracking regression for material. (#130169) --- .../test/material/action_chip_test.dart | 8 +- .../material/action_icons_theme_test.dart | 2 +- .../test/material/animated_icons_test.dart | 21 +- .../test/material/app_builder_test.dart | 6 +- .../test/material/back_button_test.dart | 24 +-- .../flutter/test/material/badge_test.dart | 19 +- .../test/material/badge_theme_test.dart | 9 +- .../flutter/test/material/banner_test.dart | 54 +++--- .../test/material/banner_theme_test.dart | 26 +-- .../test/material/bottom_app_bar_test.dart | 43 +++-- .../material/bottom_app_bar_theme_test.dart | 32 ++-- .../material/bottom_navigation_bar_test.dart | 121 ++++++------ .../bottom_navigation_bar_theme_test.dart | 16 +- .../material/bottom_sheet_theme_test.dart | 20 +- .../test/material/button_bar_test.dart | 44 +++-- .../test/material/button_bar_theme_test.dart | 12 +- .../test/material/button_style_test.dart | 8 +- .../test/material/button_theme_test.dart | 1 + packages/flutter/test/material/card_test.dart | 13 +- .../material/checkbox_list_tile_test.dart | 51 ++--- .../test/material/checkbox_theme_test.dart | 15 +- packages/flutter/test/material/chip_test.dart | 133 ++++++------- .../test/material/chip_theme_test.dart | 29 +-- .../test/material/choice_chip_test.dart | 21 +- .../test/material/circle_avatar_test.dart | 27 +-- .../test/material/data_table_test.dart | 79 ++++---- .../test/material/data_table_theme_test.dart | 18 +- .../flutter/test/material/debug_test.dart | 8 +- ...op_text_selection_toolbar_button_test.dart | 6 +- .../desktop_text_selection_toolbar_test.dart | 4 +- .../flutter/test/material/dialog_test.dart | 105 +++++----- .../test/material/drawer_button_test.dart | 20 +- .../material/dropdown_form_field_test.dart | 47 ++--- .../material/dropdown_menu_theme_test.dart | 12 +- .../test/material/elevated_button_test.dart | 79 ++++---- .../material/elevated_button_theme_test.dart | 22 ++- .../test/material/expansion_panel_test.dart | 60 +++--- .../test/material/expansion_tile_test.dart | 58 +++--- .../material/expansion_tile_theme_test.dart | 10 +- .../flutter/test/material/feedback_test.dart | 13 +- .../test/material/filled_button_test.dart | 75 ++++---- .../material/filled_button_theme_test.dart | 18 +- .../test/material/filter_chip_test.dart | 25 +-- ...flexible_space_bar_collapse_mode_test.dart | 8 +- .../flexible_space_bar_stretch_mode_test.dart | 10 +- .../material/flexible_space_bar_test.dart | 23 +-- .../floating_action_button_location_test.dart | 4 +- .../material/floating_action_button_test.dart | 87 ++++----- .../floating_action_button_theme_test.dart | 30 +-- .../test/material/grid_title_test.dart | 4 +- .../test/material/icon_button_test.dart | 116 +++++------ .../test/material/icon_button_theme_test.dart | 18 +- .../flutter/test/material/icons_test.dart | 20 +- .../flutter/test/material/ink_paint_test.dart | 25 +-- .../test/material/ink_splash_test.dart | 5 +- .../flutter/test/material/ink_well_test.dart | 95 ++++----- .../test/material/input_chip_test.dart | 27 +-- .../input_date_picker_form_field_test.dart | 27 +-- .../flutter/test/material/list_tile_test.dart | 137 ++++++------- .../test/material/list_tile_theme_test.dart | 31 +-- .../test/material/localizations_test.dart | 8 +- .../flutter/test/material/magnifier_test.dart | 24 +-- .../test/material/material_button_test.dart | 37 ++-- .../material/material_state_mixin_test.dart | 18 +- .../test/material/menu_bar_theme_test.dart | 6 +- .../test/material/menu_style_test.dart | 12 +- .../test/material/menu_theme_test.dart | 6 +- .../material/mergeable_material_test.dart | 37 ++-- .../material/navigation_bar_theme_test.dart | 12 +- .../test/material/navigation_drawer_test.dart | 20 +- .../test/material/navigation_rail_test.dart | 181 +++++++++--------- .../test/material/outlined_button_test.dart | 79 ++++---- .../material/outlined_button_theme_test.dart | 22 ++- .../test/material/page_selector_test.dart | 14 +- .../material/page_transitions_theme_test.dart | 18 +- .../test/material/popup_menu_theme_test.dart | 18 +- .../material/progress_indicator_test.dart | 71 +++---- .../test/material/radio_theme_test.dart | 15 +- .../test/material/range_slider_test.dart | 89 ++++----- .../material/raw_material_button_test.dart | 35 ++-- .../test/material/scrollbar_paint_test.dart | 9 +- .../flutter/test/material/scrollbar_test.dart | 63 +++--- .../test/material/scrollbar_theme_test.dart | 21 +- .../test/material/search_bar_theme_test.dart | 18 +- .../test/material/search_view_theme_test.dart | 18 +- .../material/segmented_button_theme_test.dart | 12 +- .../test/material/selection_area_test.dart | 12 +- .../test/material/slider_theme_test.dart | 77 ++++---- ...gestions_toolbar_layout_delegate_test.dart | 4 +- .../spell_check_suggestions_toolbar_test.dart | 8 +- .../test/material/switch_list_tile_test.dart | 77 ++++---- .../flutter/test/material/switch_test.dart | 111 +++++------ .../test/material/switch_theme_test.dart | 25 +-- .../material/tabbed_scrollview_warp_test.dart | 4 +- .../test/material/text_button_test.dart | 75 ++++---- .../test/material/text_button_theme_test.dart | 22 ++- .../material/text_field_helper_text_test.dart | 4 +- .../test/material/text_field_splash_test.dart | 4 +- .../test/material/text_form_field_test.dart | 78 ++++---- .../material/text_selection_theme_test.dart | 6 +- .../material/text_selection_toolbar_test.dart | 5 +- ...xt_selection_toolbar_text_button_test.dart | 4 +- .../test/material/theme_data_test.dart | 40 ++-- packages/flutter/test/material/time_test.dart | 14 +- .../test/material/toggle_buttons_test.dart | 79 ++++---- .../material/toggle_buttons_theme_test.dart | 19 +- .../flutter/test/material/tooltip_test.dart | 6 +- .../test/material/tooltip_theme_test.dart | 61 +++--- .../material/tooltip_visibility_test.dart | 16 +- .../test/material/typography_test.dart | 4 +- .../user_accounts_drawer_header_test.dart | 25 +-- .../value_indicating_slider_test.dart | 18 +- 112 files changed, 1951 insertions(+), 1791 deletions(-) diff --git a/packages/flutter/test/material/action_chip_test.dart b/packages/flutter/test/material/action_chip_test.dart index f3f4d67fc1d23..8e554968e98c5 100644 --- a/packages/flutter/test/material/action_chip_test.dart +++ b/packages/flutter/test/material/action_chip_test.dart @@ -65,7 +65,7 @@ void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) { } void main() { - testWidgets('ActionChip defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionChip defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const String label = 'action chip'; @@ -136,7 +136,7 @@ void main() { expect(decoration.color, null); }); - testWidgets('ActionChip.elevated defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionChip.elevated defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const String label = 'action chip'; @@ -207,7 +207,7 @@ void main() { expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12)); }); - testWidgets('ActionChip.color resolves material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionChip.color resolves material states', (WidgetTester tester) async { const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); final MaterialStateProperty color = MaterialStateProperty.resolveWith((Set states) { @@ -266,7 +266,7 @@ void main() { ); }); - testWidgets('ActionChip uses provided state color properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionChip uses provided state color properties', (WidgetTester tester) async { const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); Widget buildApp({ required bool enabled, required bool selected }) { diff --git a/packages/flutter/test/material/action_icons_theme_test.dart b/packages/flutter/test/material/action_icons_theme_test.dart index c5e1ddd6da59b..f69ce2ac7e2ae 100644 --- a/packages/flutter/test/material/action_icons_theme_test.dart +++ b/packages/flutter/test/material/action_icons_theme_test.dart @@ -15,7 +15,7 @@ void main() { const ActionIconThemeData().copyWith().hashCode); }); - testWidgets('ActionIconThemeData copyWith overrides all properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionIconThemeData copyWith overrides all properties', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/126762. Widget originalButtonBuilder(BuildContext context) { return const SizedBox(); diff --git a/packages/flutter/test/material/animated_icons_test.dart b/packages/flutter/test/material/animated_icons_test.dart index 720dfa63172f8..b245000b02806 100644 --- a/packages/flutter/test/material/animated_icons_test.dart +++ b/packages/flutter/test/material/animated_icons_test.dart @@ -10,6 +10,7 @@ import 'dart:math' as math show pi; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; class MockCanvas extends Fake implements Canvas { @@ -95,7 +96,7 @@ class RecordedScale extends RecordedCanvasCall { } void main() { - testWidgets('IconTheme color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme color', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -116,7 +117,7 @@ void main() { expect(canvas.capturedPaint, hasColor(0xFF666666)); }); - testWidgets('IconTheme opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme opacity', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -138,7 +139,7 @@ void main() { expect(canvas.capturedPaint, hasColor(0x80666666)); }); - testWidgets('color overrides IconTheme color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('color overrides IconTheme color', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -160,7 +161,7 @@ void main() { expect(canvas.capturedPaint, hasColor(0xFF0000FF)); }); - testWidgets('IconTheme size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme size', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -184,7 +185,7 @@ void main() { expect(canvas.capturedSy, 0.25); }); - testWidgets('size overridesIconTheme size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('size overridesIconTheme size', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -209,7 +210,7 @@ void main() { expect(canvas.capturedSy, 2); }); - testWidgets('Semantic label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantic label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -229,7 +230,7 @@ void main() { semantics.dispose(); }); - testWidgets('Inherited text direction rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited text direction rtl', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.rtl, @@ -258,7 +259,7 @@ void main() { matchesGoldenFile('animated_icons_test.icon.rtl.png')); }); - testWidgets('Inherited text direction ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited text direction ltr', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -285,7 +286,7 @@ void main() { matchesGoldenFile('animated_icons_test.icon.ltr.png')); }); - testWidgets('Inherited text direction overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited text direction overridden', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -311,7 +312,7 @@ void main() { ]); }); - testWidgets('Direction has no effect on position of widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Direction has no effect on position of widget', (WidgetTester tester) async { const AnimatedIcon icon = AnimatedIcon( progress: AlwaysStoppedAnimation(0.0), icon: AnimatedIcons.arrow_menu, diff --git a/packages/flutter/test/material/app_builder_test.dart b/packages/flutter/test/material/app_builder_test.dart index cc28307f40689..aedf2b14f4962 100644 --- a/packages/flutter/test/material/app_builder_test.dart +++ b/packages/flutter/test/material/app_builder_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets("builder doesn't get called if app doesn't change", (WidgetTester tester) async { + testWidgetsWithLeakTracking("builder doesn't get called if app doesn't change", (WidgetTester tester) async { final List log = []; final Widget app = MaterialApp( home: const Placeholder(), @@ -33,7 +35,7 @@ void main() { expect(log, ['build']); }); - testWidgets("builder doesn't get called if app doesn't change", (WidgetTester tester) async { + testWidgetsWithLeakTracking("builder doesn't get called if app doesn't change", (WidgetTester tester) async { final List log = []; await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/back_button_test.dart b/packages/flutter/test/material/back_button_test.dart index afdba078a123e..ef0eb7d112251 100644 --- a/packages/flutter/test/material/back_button_test.dart +++ b/packages/flutter/test/material/back_button_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { testWidgets('BackButton control test', (WidgetTester tester) async { await tester.pumpWidget( @@ -34,7 +36,7 @@ void main() { expect(find.text('Home'), findsOneWidget); }); - testWidgets('BackButton onPressed overrides default pop behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton onPressed overrides default pop behavior', (WidgetTester tester) async { bool customCallbackWasCalled = false; await tester.pumpWidget( MaterialApp( @@ -67,7 +69,7 @@ void main() { expect(customCallbackWasCalled, true); }); - testWidgets('BackButton icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton icon', (WidgetTester tester) async { final Key androidKey = UniqueKey(); final Key iOSKey = UniqueKey(); final Key linuxKey = UniqueKey(); @@ -115,7 +117,7 @@ void main() { expect(windowsIcon.icon == androidIcon.icon, isTrue); }); - testWidgets('BackButton color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton color', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -133,7 +135,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('BackButton color with ButtonStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton color with ButtonStyle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -154,7 +156,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('BackButton.style.iconColor parameter overrides BackButton.color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton.style.iconColor parameter overrides BackButton.color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -177,7 +179,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('BackButton semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( MaterialApp( @@ -220,7 +222,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('CloseButton semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CloseButton semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( MaterialApp( @@ -263,7 +265,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('CloseButton color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CloseButton color', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -281,7 +283,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('CloseButton color with ButtonStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CloseButton color with ButtonStyle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -302,7 +304,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('CloseButton.style.iconColor parameter overrides CloseButton.color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CloseButton.style.iconColor parameter overrides CloseButton.color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -325,7 +327,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('CloseButton onPressed overrides default pop behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CloseButton onPressed overrides default pop behavior', (WidgetTester tester) async { bool customCallbackWasCalled = false; await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/badge_test.dart b/packages/flutter/test/material/badge_test.dart index 05691229a59bf..aa131f4d9754b 100644 --- a/packages/flutter/test/material/badge_test.dart +++ b/packages/flutter/test/material/badge_test.dart @@ -8,11 +8,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgets('Large Badge defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Large Badge defaults', (WidgetTester tester) async { late final ThemeData theme; await tester.pumpWidget( @@ -58,7 +59,7 @@ void main() { expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); }); - testWidgets('Large Badge defaults with RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Large Badge defaults with RTL', (WidgetTester tester) async { late final ThemeData theme; await tester.pumpWidget( @@ -101,7 +102,7 @@ void main() { }); // Essentially the same as 'Large Badge defaults' - testWidgets('Badge.count', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Badge.count', (WidgetTester tester) async { late final ThemeData theme; Widget buildFrame(int count) { @@ -160,7 +161,7 @@ void main() { expect(find.text('999+'), findsOneWidget); }); - testWidgets('Small Badge defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small Badge defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); await tester.pumpWidget( @@ -191,7 +192,7 @@ void main() { expect(box, paints..rrect(rrect: RRect.fromLTRBR(18, 0, 24, 6, const Radius.circular(3)), color: theme.colorScheme.error)); }); - testWidgets('Small Badge RTL defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small Badge RTL defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); await tester.pumpWidget( @@ -224,7 +225,7 @@ void main() { expect(box, paints..rrect(rrect: RRect.fromLTRBR(0, 0, 6, 6, const Radius.circular(3)), color: theme.colorScheme.error)); }); - testWidgets('Large Badge textStyle and colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Large Badge textStyle and colors', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); const Color green = Color(0xff00ff00); const Color black = Color(0xff000000); @@ -251,7 +252,7 @@ void main() { expect(tester.renderObject(find.byType(Badge)), paints..rrect(color: black)); }); - testWidgets('isLabelVisible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isLabelVisible', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.light(useMaterial3: true), @@ -275,7 +276,7 @@ void main() { expect(box, isNot(paints..rrect())); }); - testWidgets('Large Badge alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Large Badge alignment', (WidgetTester tester) async { const Radius badgeRadius = Radius.circular(8); Widget buildFrame(Alignment alignment, [Offset offset = Offset.zero]) { @@ -350,7 +351,7 @@ void main() { expect(box, paints..rrect(rrect: RRect.fromLTRBR(200 - 16, 200 - 16, 200, 200, badgeRadius).shift(offset))); }); - testWidgets('Small Badge alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small Badge alignment', (WidgetTester tester) async { const Radius badgeRadius = Radius.circular(3); Widget buildFrame(Alignment alignment, [Offset offset = Offset.zero]) { diff --git a/packages/flutter/test/material/badge_theme_test.dart b/packages/flutter/test/material/badge_theme_test.dart index ca820eef310c7..52c0b4ef3c557 100644 --- a/packages/flutter/test/material/badge_theme_test.dart +++ b/packages/flutter/test/material/badge_theme_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -32,7 +33,7 @@ void main() { expect(themeData.offset, null); }); - testWidgets('Default BadgeThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default BadgeThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BadgeThemeData().debugFillProperties(builder); @@ -44,7 +45,7 @@ void main() { expect(description, []); }); - testWidgets('BadgeThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BadgeThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BadgeThemeData( backgroundColor: Color(0xfffffff0), @@ -74,7 +75,7 @@ void main() { ]); }); - testWidgets('Badge uses ThemeData badge theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Badge uses ThemeData badge theme', (WidgetTester tester) async { const Color green = Color(0xff00ff00); const Color black = Color(0xff000000); const BadgeThemeData badgeTheme = BadgeThemeData( @@ -123,7 +124,7 @@ void main() { // This test is essentially the same as 'Badge uses ThemeData badge theme'. In // this case the theme is introduced with the BadgeTheme widget instead of // ThemeData.badgeTheme. - testWidgets('Badge uses BadgeTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Badge uses BadgeTheme', (WidgetTester tester) async { const Color green = Color(0xff00ff00); const Color black = Color(0xff000000); const BadgeThemeData badgeTheme = BadgeThemeData( diff --git a/packages/flutter/test/material/banner_test.dart b/packages/flutter/test/material/banner_test.dart index e1a8843c8be78..58e51ab256f9a 100644 --- a/packages/flutter/test/material/banner_test.dart +++ b/packages/flutter/test/material/banner_test.dart @@ -6,8 +6,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('MaterialBanner properties are respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner properties are respected', (WidgetTester tester) async { const String contentText = 'Content'; const Color backgroundColor = Colors.pink; const Color surfaceTintColor = Colors.green; @@ -47,7 +49,7 @@ void main() { expect(divider.color, dividerColor); }); - testWidgets('MaterialBanner properties are respected when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner properties are respected when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); const Color backgroundColor = Colors.pink; @@ -104,7 +106,7 @@ void main() { expect(divider.color, dividerColor); }); - testWidgets('Actions laid out below content if more than one action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions laid out below content if more than one action', (WidgetTester tester) async { const String contentText = 'Content'; await tester.pumpWidget( @@ -131,7 +133,7 @@ void main() { expect(contentBottomLeft.dx, lessThan(actionsTopLeft.dx)); }); - testWidgets('Actions laid out below content if more than one action when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions laid out below content if more than one action when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( @@ -174,7 +176,7 @@ void main() { expect(contentBottomLeft.dx, lessThan(actionsTopLeft.dx)); }); - testWidgets('Actions laid out beside content if only one action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions laid out beside content if only one action', (WidgetTester tester) async { const String contentText = 'Content'; await tester.pumpWidget( @@ -197,7 +199,7 @@ void main() { expect(contentBottomLeft.dx, lessThan(actionsTopRight.dx)); }); - testWidgets('Actions laid out beside content if only one action when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions laid out beside content if only one action when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( @@ -269,7 +271,7 @@ void main() { ); } - testWidgets('Elevation defaults to 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Elevation defaults to 0', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); await tester.pumpWidget(buildBanner(tapTarget)); @@ -294,7 +296,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Uses elevation of MaterialBannerTheme by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses elevation of MaterialBannerTheme by default', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); await tester.pumpWidget(buildBanner(tapTarget, themeElevation: 6.0)); @@ -312,7 +314,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Scaffold body is pushed down if elevation is 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold body is pushed down if elevation is 0', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); await tester.pumpWidget(buildBanner(tapTarget, elevation: 0.0)); @@ -327,7 +329,7 @@ void main() { }); }); - testWidgets('MaterialBanner control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner control test', (WidgetTester tester) async { const String helloMaterialBanner = 'Hello MaterialBanner'; const Key tapTarget = Key('tap-target'); const Key dismissTarget = Key('dismiss-target'); @@ -379,7 +381,7 @@ void main() { expect(find.text(helloMaterialBanner), findsNothing); }); - testWidgets('MaterialBanner twice test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner twice test', (WidgetTester tester) async { int materialBannerCount = 0; const Key tapTarget = Key('tap-target'); const Key dismissTarget = Key('dismiss-target'); @@ -461,7 +463,7 @@ void main() { expect(find.text('banner2'), findsNothing); }); - testWidgets('ScaffoldMessenger does not duplicate a MaterialBanner when presenting a SnackBar.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger does not duplicate a MaterialBanner when presenting a SnackBar.', (WidgetTester tester) async { const Key materialBannerTapTarget = Key('materialbanner-tap-target'); const Key snackBarTapTarget = Key('snackbar-tap-target'); const String snackBarText = 'SnackBar'; @@ -519,7 +521,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/39574 - testWidgets('Single action laid out beside content but aligned to the trailing edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Single action laid out beside content but aligned to the trailing edge', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: MaterialBanner( @@ -540,7 +542,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/39574 - testWidgets('Single action laid out beside content but aligned to the trailing edge when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Single action laid out beside content but aligned to the trailing edge when presented by ScaffoldMessenger', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -578,7 +580,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/39574 - testWidgets('Single action laid out beside content but aligned to the trailing edge - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Single action laid out beside content but aligned to the trailing edge - RTL', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -601,7 +603,7 @@ void main() { expect(actionsTopLeft.dx - 8, bannerTopLeft.dx); // actions OverflowBar is padded by 8 }); - testWidgets('Single action laid out beside content but aligned to the trailing edge when presented by ScaffoldMessenger - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Single action laid out beside content but aligned to the trailing edge when presented by ScaffoldMessenger - RTL', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( home: Directionality( @@ -641,7 +643,7 @@ void main() { expect(actionsTopLeft.dx - 8, bannerTopLeft.dx); // actions OverflowBar is padded by 8 }); - testWidgets('Actions laid out below content if forced override', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions laid out below content if forced override', (WidgetTester tester) async { const String contentText = 'Content'; await tester.pumpWidget( @@ -665,7 +667,7 @@ void main() { expect(contentBottomLeft.dx, lessThan(actionsTopLeft.dx)); }); - testWidgets('Actions laid out below content if forced override when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions laid out below content if forced override when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( @@ -705,7 +707,7 @@ void main() { expect(contentBottomLeft.dx, lessThan(actionsTopLeft.dx)); }); - testWidgets('Action widgets layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action widgets layout', (WidgetTester tester) async { // This regression test ensures that the action widgets layout matches what // it was, before ButtonBar was replaced by OverflowBar. Widget buildFrame(int actionCount, TextDirection textDirection) { @@ -749,7 +751,7 @@ void main() { expect(tester.getTopLeft(action2), const Offset(8, 130)); }); - testWidgets('Action widgets layout when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action widgets layout when presented by ScaffoldMessenger', (WidgetTester tester) async { // This regression test ensures that the action widgets layout matches what // it was, before ButtonBar was replaced by OverflowBar. @@ -836,7 +838,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Action widgets layout with overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action widgets layout with overflow', (WidgetTester tester) async { // This regression test ensures that the action widgets layout matches what // it was, before ButtonBar was replaced by OverflowBar. const int actionCount = 4; @@ -871,7 +873,7 @@ void main() { } }); - testWidgets('Action widgets layout with overflow when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action widgets layout with overflow when presented by ScaffoldMessenger', (WidgetTester tester) async { // This regression test ensures that the action widgets layout matches what // it was, before ButtonBar was replaced by OverflowBar. @@ -942,7 +944,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('[overflowAlignment] test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('[overflowAlignment] test', (WidgetTester tester) async { const int actionCount = 4; Widget buildFrame(TextDirection textDirection, OverflowBarAlignment overflowAlignment) { return MaterialApp( @@ -979,7 +981,7 @@ void main() { } }); - testWidgets('[overflowAlignment] test when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('[overflowAlignment] test when presented by ScaffoldMessenger', (WidgetTester tester) async { const int actionCount = 4; Widget buildFrame(TextDirection textDirection, OverflowBarAlignment overflowAlignment) { return MaterialApp( @@ -1054,7 +1056,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('ScaffoldMessenger will alert for MaterialBanners that cannot be presented', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger will alert for MaterialBanners that cannot be presented', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/103004 await tester.pumpWidget(const MaterialApp( home: Center(), @@ -1083,7 +1085,7 @@ void main() { ); }); - testWidgets('Custom Margin respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Margin respected', (WidgetTester tester) async { const EdgeInsets margin = EdgeInsets.all(30); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/banner_theme_test.dart b/packages/flutter/test/material/banner_theme_test.dart index ca4c9022d5940..04db7bba26b92 100644 --- a/packages/flutter/test/material/banner_theme_test.dart +++ b/packages/flutter/test/material/banner_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('MaterialBannerThemeData copyWith, ==, hashCode basics', () { expect(const MaterialBannerThemeData(), const MaterialBannerThemeData().copyWith()); @@ -24,7 +26,7 @@ void main() { expect(bannerTheme.leadingPadding, null); }); - testWidgets('Default MaterialBannerThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default MaterialBannerThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const MaterialBannerThemeData().debugFillProperties(builder); @@ -36,7 +38,7 @@ void main() { expect(description, []); }); - testWidgets('MaterialBannerThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBannerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const MaterialBannerThemeData( backgroundColor: Color(0xfffffff0), @@ -66,7 +68,7 @@ void main() { ]); }); - testWidgets('Material3 - Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { const String contentText = 'Content'; final ThemeData theme = ThemeData(useMaterial3: true); late final ThemeData localizedTheme; @@ -115,7 +117,7 @@ void main() { expect(divider.color, theme.colorScheme.outlineVariant); }); - testWidgets('Material3 - Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); final ThemeData theme = ThemeData(useMaterial3: true); @@ -178,7 +180,7 @@ void main() { expect(divider.color, theme.colorScheme.outlineVariant); }); - testWidgets('MaterialBanner uses values from MaterialBannerThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner uses values from MaterialBannerThemeData', (WidgetTester tester) async { final MaterialBannerThemeData bannerTheme = _bannerTheme(); const String contentText = 'Content'; await tester.pumpWidget(MaterialApp( @@ -217,7 +219,7 @@ void main() { expect(find.byType(Divider), findsNothing); }); - testWidgets('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async { final MaterialBannerThemeData bannerTheme = _bannerTheme(); const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); @@ -273,7 +275,7 @@ void main() { expect(find.byType(Divider), findsNothing); }); - testWidgets('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async { const Color backgroundColor = Colors.purple; const Color surfaceTintColor = Colors.red; const Color shadowColor = Colors.orange; @@ -324,7 +326,7 @@ void main() { expect(find.byType(Divider), findsNothing); }); - testWidgets('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async { const Color backgroundColor = Colors.purple; const double elevation = 6.0; const TextStyle textStyle = TextStyle(color: Colors.green); @@ -387,7 +389,7 @@ void main() { expect(find.byType(Divider), findsNothing); }); - testWidgets('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async { final ColorScheme colorScheme = const ColorScheme.light().copyWith(surface: Colors.purple); const String contentText = 'Content'; await tester.pumpWidget(MaterialApp( @@ -409,7 +411,7 @@ void main() { expect(material.color, colorScheme.surface); }); - testWidgets('MaterialBanner uses color scheme when necessary when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialBanner uses color scheme when necessary when presented by ScaffoldMessenger', (WidgetTester tester) async { final ColorScheme colorScheme = const ColorScheme.light().copyWith(surface: Colors.purple); const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); @@ -453,7 +455,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Material2 - Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async { const String contentText = 'Content'; await tester.pumpWidget(MaterialApp( @@ -499,7 +501,7 @@ void main() { expect(divider.color, null); }); - testWidgets('Material2 - Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async { const String contentText = 'Content'; const Key tapTarget = Key('tap-target'); diff --git a/packages/flutter/test/material/bottom_app_bar_test.dart b/packages/flutter/test/material/bottom_app_bar_test.dart index 5e2c9c82a6f36..fe90810ac0d99 100644 --- a/packages/flutter/test/material/bottom_app_bar_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_test.dart @@ -11,10 +11,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgets('shadow effect is not doubled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shadow effect is not doubled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123064 debugDisableShadows = false; @@ -40,7 +41,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('only one layer with `color` is painted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('only one layer with `color` is painted', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/122667 const Color bottomAppBarColor = Colors.black45; @@ -79,7 +80,7 @@ void main() { } }); - testWidgets('no overlap with floating action button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no overlap with floating action button', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -110,7 +111,7 @@ void main() { ); }); - testWidgets('custom shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('custom shape', (WidgetTester tester) async { final Key key = UniqueKey(); Future pump(FloatingActionButtonLocation location) async { await tester.pumpWidget( @@ -154,7 +155,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44572 - testWidgets('Custom Padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Padding', (WidgetTester tester) async { const EdgeInsets customPadding = EdgeInsets.all(10); await tester.pumpWidget( MaterialApp( @@ -186,7 +187,7 @@ void main() { expect(babRect, const Rect.fromLTRB(240, 520, 560, 600)); }); - testWidgets('Custom Padding in Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Padding in Material 3', (WidgetTester tester) async { const EdgeInsets customPadding = EdgeInsets.all(10); await tester.pumpWidget( MaterialApp( @@ -218,7 +219,7 @@ void main() { expect(babRect, const Rect.fromLTRB(240, 520, 560, 600)); }); - testWidgets('color defaults to Theme.bottomAppBarColor in M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('color defaults to Theme.bottomAppBarColor in M2', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -244,7 +245,7 @@ void main() { expect(physicalShape.color, const Color(0xffffff00)); }); - testWidgets('color overrides theme color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('color overrides theme color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -275,7 +276,7 @@ void main() { }); - testWidgets('color overrides theme color with Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('color overrides theme color with Material 3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.light(useMaterial3: true).copyWith( @@ -302,7 +303,7 @@ void main() { expect(physicalShape.color, const Color(0xff0000ff)); }); - testWidgets('Shadow color is transparent in Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shadow color is transparent in Material 3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true, @@ -324,7 +325,7 @@ void main() { expect(physicalShape.shadowColor, Colors.transparent); }); - testWidgets('dark theme applies an elevation overlay color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dark theme applies an elevation overlay color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(useMaterial3: false, colorScheme: const ColorScheme.dark()), @@ -345,7 +346,7 @@ void main() { // This is a regression test for a bug we had where toggling the notch on/off // would crash, as the shouldReclip method of ShapeBorderClipper or // _BottomAppBarClipper would try an illegal downcast. - testWidgets('toggle shape to null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toggle shape to null', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -375,7 +376,7 @@ void main() { ); }); - testWidgets('no notch when notch param is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no notch when notch param is null', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -405,7 +406,7 @@ void main() { ); }); - testWidgets('notch no margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('notch no margin', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -457,7 +458,7 @@ void main() { ); }); - testWidgets('notch with margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('notch with margin', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -509,7 +510,7 @@ void main() { ); }); - testWidgets('observes safe area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('observes safe area', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -534,7 +535,7 @@ void main() { ); }); - testWidgets('clipBehavior is propagated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clipBehavior is propagated', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -568,7 +569,7 @@ void main() { expect(physicalShape.clipBehavior, Clip.antiAliasWithSaveLayer); }); - testWidgets('BottomAppBar with shape when Scaffold.bottomNavigationBar == null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomAppBar with shape when Scaffold.bottomNavigationBar == null', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/80878 final ThemeData theme = ThemeData(); await tester.pumpWidget( @@ -604,7 +605,7 @@ void main() { expect(tester.getSize(find.byType(BottomAppBar)), theme.useMaterial3 ? const Size(800, 80) : const Size(800, 50)); }); - testWidgets('notch with margin and top padding, home safe area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('notch with margin and top padding, home safe area', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/90024 await tester.pumpWidget( const MediaQuery( @@ -665,7 +666,7 @@ void main() { ); }); - testWidgets('BottomAppBar does not apply custom clipper without FAB', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomAppBar does not apply custom clipper without FAB', (WidgetTester tester) async { Widget buildWidget({Widget? fab}) { return MaterialApp( home: Scaffold( @@ -690,7 +691,7 @@ void main() { expect(physicalShape.clipper.toString(), 'ShapeBorderClipper'); }); - testWidgets('BottomAppBar adds bottom padding to height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomAppBar adds bottom padding to height', (WidgetTester tester) async { const double bottomPadding = 35.0; await tester.pumpWidget( diff --git a/packages/flutter/test/material/bottom_app_bar_theme_test.dart b/packages/flutter/test/material/bottom_app_bar_theme_test.dart index bd08943f4250d..c4062a4ec9da0 100644 --- a/packages/flutter/test/material/bottom_app_bar_theme_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_theme_test.dart @@ -10,6 +10,8 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('BottomAppBarTheme lerp special cases', () { expect(BottomAppBarTheme.lerp(null, null, 0), const BottomAppBarTheme()); @@ -18,7 +20,7 @@ void main() { }); group('Material 2 tests', () { - testWidgets('BAB theme overrides color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme overrides color', (WidgetTester tester) async { const Color themedColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme(color: themedColor); @@ -28,7 +30,7 @@ void main() { expect(widget.color, themedColor); }); - testWidgets('BAB color - Widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB color - Widget', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const Color babColor = Colors.pink; @@ -47,7 +49,7 @@ void main() { expect(widget.color, babColor); }); - testWidgets('BAB color - BabTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB color - BabTheme', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); @@ -65,7 +67,7 @@ void main() { expect(widget.color, babThemeColor); }); - testWidgets('BAB color - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB color - Theme', (WidgetTester tester) async { const Color themeColor = Colors.white10; await tester.pumpWidget(MaterialApp( @@ -77,7 +79,7 @@ void main() { expect(widget.color, themeColor); }); - testWidgets('BAB color - Default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB color - Default', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold(body: BottomAppBar()), @@ -88,7 +90,7 @@ void main() { expect(widget.color, Colors.white); }); - testWidgets('BAB theme customizes shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme customizes shape', (WidgetTester tester) async { const BottomAppBarTheme theme = BottomAppBarTheme( color: Colors.white30, shape: CircularNotchedRectangle(), @@ -103,7 +105,7 @@ void main() { ); }); - testWidgets('BAB theme does not affect defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme does not affect defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold(body: BottomAppBar()), @@ -117,7 +119,7 @@ void main() { }); group('Material 3 tests', () { - testWidgets('BAB theme overrides color - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme overrides color - M3', (WidgetTester tester) async { const Color themedColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme( color: themedColor, @@ -129,7 +131,7 @@ void main() { expect(widget.color, themedColor); }); - testWidgets('BAB color - Widget - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB color - Widget - M3', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const Color babColor = Colors.pink; @@ -148,7 +150,7 @@ void main() { expect(widget.color, babColor); }); - testWidgets('BAB color - BabTheme - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB color - BabTheme - M3', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); @@ -166,7 +168,7 @@ void main() { expect(widget.color, babThemeColor); }); - testWidgets('BAB theme does not affect defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme does not affect defaults - M3', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, @@ -179,7 +181,7 @@ void main() { expect(widget.elevation, equals(3.0)); }); - testWidgets('BAB theme overrides surfaceTintColor - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme overrides surfaceTintColor - M3', (WidgetTester tester) async { const Color color = Colors.blue; // base color that the surface tint will be applied to const Color babThemeSurfaceTintColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme( @@ -191,7 +193,7 @@ void main() { expect(widget.color, ElevationOverlay.applySurfaceTint(color, babThemeSurfaceTintColor, 0)); }); - testWidgets('BAB theme overrides shadowColor - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB theme overrides shadowColor - M3', (WidgetTester tester) async { const Color babThemeShadowColor = Colors.yellow; const BottomAppBarTheme theme = BottomAppBarTheme( shadowColor: babThemeShadowColor, elevation: 0 @@ -202,7 +204,7 @@ void main() { expect(widget.shadowColor, babThemeShadowColor); }); - testWidgets('BAB surfaceTintColor - Widget - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB surfaceTintColor - Widget - M3', (WidgetTester tester) async { const Color color = Colors.white10; // base color that the surface tint will be applied to const Color themeSurfaceTintColor = Colors.white10; const Color babThemeSurfaceTintColor = Colors.black87; @@ -225,7 +227,7 @@ void main() { expect(widget.color, ElevationOverlay.applySurfaceTint(color, babSurfaceTintColor, 3.0)); }); - testWidgets('BAB surfaceTintColor - BabTheme - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BAB surfaceTintColor - BabTheme - M3', (WidgetTester tester) async { const Color color = Colors.blue; // base color that the surface tint will be applied to const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index a73239ad9c4c1..9fe03245592b5 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -14,12 +14,13 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart' show Vector3; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; void main() { - testWidgets('BottomNavigationBar callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar callback test', (WidgetTester tester) async { late int mutatedIndex; await tester.pumpWidget( @@ -49,7 +50,7 @@ void main() { expect(mutatedIndex, 1); }); - testWidgets('BottomNavigationBar content test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar content test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -76,7 +77,7 @@ void main() { expect(find.text('Alarm'), findsOneWidget); }); - testWidgets('Fixed BottomNavigationBar defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed BottomNavigationBar defaults', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000001); const Color unselectedWidgetColor = Color(0xFF000002); @@ -141,7 +142,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(8.0)); }); - testWidgets('Custom selected and unselected font styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom selected and unselected font styles', (WidgetTester tester) async { const TextStyle selectedTextStyle = TextStyle(fontWeight: FontWeight.w200, fontSize: 18.0); const TextStyle unselectedTextStyle = TextStyle(fontWeight: FontWeight.w600, fontSize: 12.0); @@ -178,7 +179,7 @@ void main() { expect(unselectedFontStyle.fontWeight, equals(unselectedTextStyle.fontWeight)); }); - testWidgets('font size on text styles overrides font size params', (WidgetTester tester) async { + testWidgetsWithLeakTracking('font size on text styles overrides font size params', (WidgetTester tester) async { const TextStyle selectedTextStyle = TextStyle(fontSize: 18.0); const TextStyle unselectedTextStyle = TextStyle(fontSize: 12.0); const double selectedFontSize = 17.0; @@ -216,7 +217,7 @@ void main() { ); }); - testWidgets('Custom selected and unselected icon themes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom selected and unselected icon themes', (WidgetTester tester) async { const IconThemeData selectedIconTheme = IconThemeData(size: 36, color: Color(0x00000001)); const IconThemeData unselectedIconTheme = IconThemeData(size: 18, color: Color(0x00000002)); @@ -250,7 +251,7 @@ void main() { expect(unselectedIcon.fontSize, equals(unselectedIconTheme.size)); }); - testWidgets('color on icon theme overrides selected and unselected item colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('color on icon theme overrides selected and unselected item colors', (WidgetTester tester) async { const IconThemeData selectedIconTheme = IconThemeData(size: 36, color: Color(0x00000001)); const IconThemeData unselectedIconTheme = IconThemeData(size: 18, color: Color(0x00000002)); const Color selectedItemColor = Color(0x00000003); @@ -290,7 +291,7 @@ void main() { expect(unselectedFontStyle.color, equals(unselectedItemColor)); }); - testWidgets('Padding is calculated properly on items - all labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding is calculated properly on items - all labels', (WidgetTester tester) async { const double selectedFontSize = 16.0; const double selectedIconSize = 36.0; const double unselectedIconSize = 20.0; @@ -331,7 +332,7 @@ void main() { expect(unselectedItemPadding.bottom, equals(expectedUnselectedPadding)); }); - testWidgets('Padding is calculated properly on items - selected labels only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding is calculated properly on items - selected labels only', (WidgetTester tester) async { const double selectedFontSize = 16.0; const double selectedIconSize = 36.0; const double unselectedIconSize = 20.0; @@ -371,7 +372,7 @@ void main() { expect(unselectedItemPadding.bottom, equals((selectedIconSize - unselectedIconSize) / 2.0)); }); - testWidgets('Padding is calculated properly on items - no labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding is calculated properly on items - no labels', (WidgetTester tester) async { const double selectedFontSize = 16.0; const double selectedIconSize = 36.0; const double unselectedIconSize = 20.0; @@ -411,7 +412,7 @@ void main() { expect(unselectedItemPadding.bottom, equals((selectedIconSize - unselectedIconSize) / 2.0)); }); - testWidgets('Shifting BottomNavigationBar defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shifting BottomNavigationBar defaults', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -440,7 +441,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(8.0)); }); - testWidgets('Fixed BottomNavigationBar custom font size, color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed BottomNavigationBar custom font size, color', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedColor = Color(0xFF0004FF); @@ -505,7 +506,7 @@ void main() { }); - testWidgets('Shifting BottomNavigationBar custom font size, color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shifting BottomNavigationBar custom font size, color', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedColor = Color(0xFF0004FF); @@ -552,7 +553,7 @@ void main() { expect(unselectedIcon.color, equals(unselectedColor)); }); - testWidgets('label style color should override itemColor only for the label for BottomNavigationBarType.fixed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label style color should override itemColor only for the label for BottomNavigationBarType.fixed', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedColor = Color(0xFF0004FF); @@ -598,7 +599,7 @@ void main() { expect(tester.renderObject(find.text('Alarm')).text.style!.color, equals(unselectedLabelColor)); }); - testWidgets('label style color should override itemColor only for the label for BottomNavigationBarType.shifting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label style color should override itemColor only for the label for BottomNavigationBarType.shifting', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedColor = Color(0xFF0004FF); @@ -644,7 +645,7 @@ void main() { expect(tester.renderObject(find.text('Alarm')).text.style!.color, equals(unselectedLabelColor)); }); - testWidgets('iconTheme color should override itemColor for BottomNavigationBarType.fixed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('iconTheme color should override itemColor for BottomNavigationBarType.fixed', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedColor = Color(0xFF0004FF); @@ -696,7 +697,7 @@ void main() { expect(unselectedIcon.color, equals(unselectedIconThemeColor)); }); - testWidgets('iconTheme color should override itemColor for BottomNavigationBarType.shifted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('iconTheme color should override itemColor for BottomNavigationBarType.shifted', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedLabelColor = Color(0xFFFF9900); @@ -744,7 +745,7 @@ void main() { expect(unselectedIcon.color, equals(unselectedIconThemeColor)); }); - testWidgets('iconTheme color should override itemColor color for BottomNavigationBarType.fixed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('iconTheme color should override itemColor color for BottomNavigationBarType.fixed', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedIconThemeColor = Color(0xFF1E7723); @@ -786,7 +787,7 @@ void main() { expect(unselectedIcon.color, equals(unselectedIconThemeColor)); }); - testWidgets('iconTheme color should override itemColor for BottomNavigationBarType.shifted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('iconTheme color should override itemColor for BottomNavigationBarType.shifted', (WidgetTester tester) async { const Color primaryColor = Color(0xFF000000); const Color unselectedWidgetColor = Color(0xFFD501FF); const Color selectedColor = Color(0xFF0004FF); @@ -832,7 +833,7 @@ void main() { expect(unselectedIcon.color, equals(unselectedIconThemeColor)); }); - testWidgets('Fixed BottomNavigationBar can hide unselected labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed BottomNavigationBar can hide unselected labels', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -858,7 +859,7 @@ void main() { expect(_getOpacity(tester, 'Alarm'), equals(0.0)); }); - testWidgets('Fixed BottomNavigationBar can update background color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed BottomNavigationBar can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; await tester.pumpWidget( @@ -885,7 +886,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgets('Shifting BottomNavigationBar background color is overridden by item color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shifting BottomNavigationBar background color is overridden by item color', (WidgetTester tester) async { const Color itemColor = Colors.yellow; const Color backgroundColor = Colors.blue; @@ -914,7 +915,7 @@ void main() { expect(_getMaterial(tester).color, equals(itemColor)); }); - testWidgets('Specifying both selectedItemColor and fixedColor asserts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Specifying both selectedItemColor and fixedColor asserts', (WidgetTester tester) async { expect( () { return BottomNavigationBar( @@ -936,7 +937,7 @@ void main() { ); }); - testWidgets('Fixed BottomNavigationBar uses fixedColor when selectedItemColor not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed BottomNavigationBar uses fixedColor when selectedItemColor not provided', (WidgetTester tester) async { const Color fixedColor = Colors.black; await tester.pumpWidget( @@ -963,7 +964,7 @@ void main() { expect(tester.renderObject(find.text('AC')).text.style!.color, equals(fixedColor)); }); - testWidgets('setting selectedFontSize to zero hides all labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setting selectedFontSize to zero hides all labels', (WidgetTester tester) async { const double customElevation = 3.0; await tester.pumpWidget( @@ -990,7 +991,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(customElevation)); }); - testWidgets('BottomNavigationBar adds bottom padding to height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar adds bottom padding to height', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1018,7 +1019,7 @@ void main() { expect(tester.getSize(find.byType(BottomNavigationBar)).height, expectedHeight); }); - testWidgets('BottomNavigationBar adds bottom padding to height with a custom font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar adds bottom padding to height with a custom font size', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: MediaQuery( @@ -1046,7 +1047,7 @@ void main() { expect(tester.getSize(find.byType(BottomNavigationBar)).height, expectedHeight); }); - testWidgets('BottomNavigationBar height will not change when toggle keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar height will not change when toggle keyboard', (WidgetTester tester) async { final Widget child = Scaffold( bottomNavigationBar: BottomNavigationBar( @@ -1098,7 +1099,7 @@ void main() { expect(tester.getSize(find.byType(BottomNavigationBar)).height, expectedHeight); }); - testWidgets('BottomNavigationBar action size test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar action size test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1153,7 +1154,7 @@ void main() { expect(actions.elementAt(1).size.width, 480.0); }); - testWidgets('BottomNavigationBar multiple taps test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar multiple taps test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1211,7 +1212,7 @@ void main() { expect(actions.elementAt(3).localToGlobal(Offset.zero), equals(originalOrigin)); }); - testWidgets('BottomNavigationBar inherits shadowed app theme for shifting navbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar inherits shadowed app theme for shifting navbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(brightness: Brightness.light), @@ -1249,7 +1250,7 @@ void main() { expect(Theme.of(tester.element(find.text('Alarm'))).brightness, equals(Brightness.dark)); }); - testWidgets('BottomNavigationBar inherits shadowed app theme for fixed navbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar inherits shadowed app theme for fixed navbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(brightness: Brightness.light), @@ -1287,7 +1288,7 @@ void main() { expect(Theme.of(tester.element(find.text('Alarm'))).brightness, equals(Brightness.dark)); }); - testWidgets('BottomNavigationBar iconSize test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar iconSize test', (WidgetTester tester) async { late double builderIconSize; await tester.pumpWidget( MaterialApp( @@ -1323,7 +1324,7 @@ void main() { expect(builderIconSize, 12.0); }); - testWidgets('BottomNavigationBar responds to textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar responds to textScaleFactor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1397,7 +1398,7 @@ void main() { expect(box.size.height, equals(56.0)); }); - testWidgets('BottomNavigationBar does not grow with textScaleFactor when labels are provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar does not grow with textScaleFactor when labels are provided', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1471,7 +1472,7 @@ void main() { expect(box.size.height, equals(kBottomNavigationBarHeight)); }); - testWidgets('BottomNavigationBar shows tool tips with text scaling on long press when labels are provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar shows tool tips with text scaling on long press when labels are provided', (WidgetTester tester) async { const String label = 'Foo'; Widget buildApp({ required double textScaleFactor }) { @@ -1529,7 +1530,7 @@ void main() { expect(tester.getSize(find.text(label).last), equals(const Size(168.0, 56.0))); }); - testWidgets('Different behaviour of tool tip in BottomNavigationBarItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Different behaviour of tool tip in BottomNavigationBarItem', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1568,7 +1569,7 @@ void main() { expect(find.byTooltip('C'), findsNothing); }); - testWidgets('BottomNavigationBar limits width of tiles with long labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar limits width of tiles with long labels', (WidgetTester tester) async { final String longTextA = List.generate(100, (int index) => 'A').toString(); final String longTextB = List.generate(100, (int index) => 'B').toString(); @@ -1601,7 +1602,7 @@ void main() { expect(itemBoxB.size, equals(const Size(400.0, 14.0))); }); - testWidgets('BottomNavigationBar paints circles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar paints circles', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( useMaterial3: false, @@ -1672,7 +1673,7 @@ void main() { ); }); - testWidgets('BottomNavigationBar inactiveIcon shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar inactiveIcon shown', (WidgetTester tester) async { const Key filled = Key('filled'); const Key stroked = Key('stroked'); int selectedItem = 0; @@ -1725,7 +1726,7 @@ void main() { expect(find.byKey(stroked), findsOneWidget); }); - testWidgets('BottomNavigationBar.fixed semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar.fixed semantics', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( textDirection: TextDirection.ltr, @@ -1778,7 +1779,7 @@ void main() { ); }); - testWidgets('BottomNavigationBar.shifting semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar.shifting semantics', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( textDirection: TextDirection.ltr, @@ -1832,7 +1833,7 @@ void main() { ); }); - testWidgets('BottomNavigationBar handles items.length changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar handles items.length changes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/10322 Widget buildFrame(int itemCount) { @@ -1870,7 +1871,7 @@ void main() { expect(find.text('item 3'), findsNothing); }); - testWidgets('BottomNavigationBar change backgroundColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar change backgroundColor test', (WidgetTester tester) async { // Regression test for: https://github.com/flutter/flutter/issues/19653 Color backgroundColor = Colors.red; @@ -1967,7 +1968,7 @@ void main() { ); } for (int pump = 1; pump < 9; pump++) { - testWidgets('pump $pump', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pump $pump', (WidgetTester tester) async { await tester.pumpWidget(runTest()); await tester.tap(find.text('Green')); @@ -1982,7 +1983,7 @@ void main() { } }); - testWidgets('BottomNavigationBar item label should not be nullable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar item label should not be nullable', (WidgetTester tester) async { expect(() { MaterialApp( home: Scaffold( @@ -2003,7 +2004,7 @@ void main() { }, throwsAssertionError); }); - testWidgets( + testWidgetsWithLeakTracking( 'BottomNavigationBar [showSelectedLabels]=false and [showUnselectedLabels]=false ' 'for shifting navbar, expect that there is no rendered text', (WidgetTester tester) async { @@ -2040,7 +2041,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'BottomNavigationBar [showSelectedLabels]=false and [showUnselectedLabels]=false ' 'for fixed navbar, expect that there is no rendered text', (WidgetTester tester) async { @@ -2078,7 +2079,7 @@ void main() { }, ); - testWidgets('BottomNavigationBar.fixed [showSelectedLabels]=false and [showUnselectedLabels]=false semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar.fixed [showSelectedLabels]=false and [showUnselectedLabels]=false semantics', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( textDirection: TextDirection.ltr, @@ -2120,7 +2121,7 @@ void main() { ); }); - testWidgets('BottomNavigationBar.shifting [showSelectedLabels]=false and [showUnselectedLabels]=false semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar.shifting [showSelectedLabels]=false and [showUnselectedLabels]=false semantics', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( textDirection: TextDirection.ltr, @@ -2163,7 +2164,7 @@ void main() { ); }); - testWidgets('BottomNavigationBar changes mouse cursor when the tile is hovered over', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar changes mouse cursor when the tile is hovered over', (WidgetTester tester) async { // Test BottomNavigationBar() constructor await tester.pumpWidget( MaterialApp( @@ -2239,7 +2240,7 @@ void main() { ); } - testWidgets('BottomNavigationBar with enabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar with enabled feedback', (WidgetTester tester) async { const bool enableFeedback = true; await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback)); @@ -2250,7 +2251,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('BottomNavigationBar with disabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar with disabled feedback', (WidgetTester tester) async { const bool enableFeedback = false; await tester.pumpWidget(feedbackBoilerplate(enableFeedback: enableFeedback)); @@ -2261,7 +2262,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('BottomNavigationBar with enabled feedback by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar with enabled feedback by default', (WidgetTester tester) async { await tester.pumpWidget(feedbackBoilerplate()); await tester.tap(find.byType(InkResponse).first); @@ -2270,7 +2271,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('BottomNavigationBar with disabled feedback using BottomNavigationBarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar with disabled feedback using BottomNavigationBarTheme', (WidgetTester tester) async { const bool enableFeedbackTheme = false; await tester.pumpWidget(feedbackBoilerplate(enableFeedbackTheme: enableFeedbackTheme)); @@ -2281,7 +2282,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('BottomNavigationBar.enableFeedback overrides BottomNavigationBarTheme.enableFeedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar.enableFeedback overrides BottomNavigationBarTheme.enableFeedback', (WidgetTester tester) async { const bool enableFeedbackTheme = false; const bool enableFeedback = true; @@ -2297,7 +2298,7 @@ void main() { }); }); - testWidgets('BottomNavigationBar excludes semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar excludes semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2368,7 +2369,7 @@ void main() { semantics.dispose(); }); - testWidgets('BottomNavigationBar default layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar default layout', (WidgetTester tester) async { final Key icon0 = UniqueKey(); final Key icon1 = UniqueKey(); @@ -2416,7 +2417,7 @@ void main() { expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(500.0, 560.0, 700.0, 570.0)); }); - testWidgets('BottomNavigationBar centered landscape layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar centered landscape layout', (WidgetTester tester) async { final Key icon0 = UniqueKey(); final Key icon1 = UniqueKey(); @@ -2462,7 +2463,7 @@ void main() { expect(tester.getRect(find.byKey(icon1)), const Rect.fromLTRB(450.0, 560.0, 650.0, 570.0)); }); - testWidgets('BottomNavigationBar linear landscape layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar linear landscape layout', (WidgetTester tester) async { final Key icon0 = UniqueKey(); final Key icon1 = UniqueKey(); diff --git a/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart b/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart index f68c66babefe3..59b93e01b8092 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart @@ -8,6 +8,8 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart' show Vector3; +import '../foundation/leak_tracking.dart'; + void main() { test('BottomNavigationBarThemeData copyWith, ==, hashCode basics', () { @@ -52,7 +54,7 @@ void main() { expect(themeData.mouseCursor, null); }); - testWidgets('Default BottomNavigationBarThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default BottomNavigationBarThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BottomNavigationBarThemeData().debugFillProperties(builder); @@ -64,7 +66,7 @@ void main() { expect(description, []); }); - testWidgets('BottomNavigationBarThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBarThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BottomNavigationBarThemeData( backgroundColor: Color(0xfffffff0), @@ -105,7 +107,7 @@ void main() { expect(description[11], 'mouseCursor: MaterialStateMouseCursor(clickable)'); }); - testWidgets('BottomNavigationBar is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar is themeable', (WidgetTester tester) async { const Color backgroundColor = Color(0xFF000001); const Color selectedItemColor = Color(0xFF000002); const Color unselectedItemColor = Color(0xFF000003); @@ -209,7 +211,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.move); }); - testWidgets('BottomNavigationBar properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar properties are taken over the theme values', (WidgetTester tester) async { const Color themeBackgroundColor = Color(0xFF000001); const Color themeSelectedItemColor = Color(0xFF000002); const Color themeUnselectedItemColor = Color(0xFF000003); @@ -336,7 +338,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('BottomNavigationBarTheme can be used to hide all labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBarTheme can be used to hide all labels', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66738. await tester.pumpWidget( MaterialApp( @@ -374,7 +376,7 @@ void main() { expect(tester.widget(findVisibility.at(1)).visible, false); }); - testWidgets('BottomNavigationBarTheme can be used to hide selected labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBarTheme can be used to hide selected labels', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66738. await tester.pumpWidget( MaterialApp( @@ -412,7 +414,7 @@ void main() { expect(tester.widget(findFadeTransition.at(1)).opacity.value, 1.0); }); - testWidgets('BottomNavigationBarTheme can be used to hide unselected labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBarTheme can be used to hide unselected labels', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/bottom_sheet_theme_test.dart b/packages/flutter/test/material/bottom_sheet_theme_test.dart index 7a965b59711b4..0e3593d04aca5 100644 --- a/packages/flutter/test/material/bottom_sheet_theme_test.dart +++ b/packages/flutter/test/material/bottom_sheet_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('BottomSheetThemeData copyWith, ==, hashCode basics', () { expect(const BottomSheetThemeData(), const BottomSheetThemeData().copyWith()); @@ -36,7 +38,7 @@ void main() { expect(bottomSheetTheme.dragHandleSize, null); }); - testWidgets('Default BottomSheetThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default BottomSheetThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BottomSheetThemeData().debugFillProperties(builder); @@ -48,7 +50,7 @@ void main() { expect(description, []); }); - testWidgets('BottomSheetThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomSheetThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const BottomSheetThemeData( backgroundColor: Color(0xFFFFFFFF), @@ -78,7 +80,7 @@ void main() { ]); }); - testWidgets('Passing no BottomSheetThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no BottomSheetThemeData returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -103,7 +105,7 @@ void main() { expect(material.clipBehavior, Clip.none); }); - testWidgets('BottomSheet uses values from BottomSheetThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomSheet uses values from BottomSheetThemeData', (WidgetTester tester) async { final BottomSheetThemeData bottomSheetTheme = _bottomSheetTheme(); await tester.pumpWidget(MaterialApp( @@ -130,7 +132,7 @@ void main() { expect(material.clipBehavior, bottomSheetTheme.clipBehavior); }); - testWidgets('BottomSheet widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomSheet widget properties take priority over theme', (WidgetTester tester) async { const Color backgroundColor = Colors.purple; const Color shadowColor = Colors.blue; const double elevation = 7.0; @@ -169,7 +171,7 @@ void main() { expect(material.clipBehavior, clipBehavior); }); - testWidgets('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { const double modalElevation = 5.0; const double persistentElevation = 7.0; const Color modalBackgroundColor = Colors.yellow; @@ -200,7 +202,7 @@ void main() { expect(modalBarrier.color, modalBarrierColor); }); - testWidgets('General bottom sheet parameters take priority over modal bottom sheet-specific parameters for persistent bottom sheets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('General bottom sheet parameters take priority over modal bottom sheet-specific parameters for persistent bottom sheets', (WidgetTester tester) async { const double modalElevation = 5.0; const double persistentElevation = 7.0; const Color modalBackgroundColor = Colors.yellow; @@ -226,7 +228,7 @@ void main() { expect(material.color, persistentBackgroundColor); }); - testWidgets("Modal bottom sheet-specific parameters don't apply to persistent bottom sheets", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Modal bottom sheet-specific parameters don't apply to persistent bottom sheets", (WidgetTester tester) async { const double modalElevation = 5.0; const Color modalBackgroundColor = Colors.yellow; const BottomSheetThemeData bottomSheetTheme = BottomSheetThemeData( @@ -248,7 +250,7 @@ void main() { expect(material.color, null); }); - testWidgets('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { const double lightElevation = 5.0; const double darkElevation = 3.0; const Color lightBackgroundColor = Colors.green; diff --git a/packages/flutter/test/material/button_bar_test.dart b/packages/flutter/test/material/button_bar_test.dart index 9207fc13953e2..16d4e84f0efeb 100644 --- a/packages/flutter/test/material/button_bar_test.dart +++ b/packages/flutter/test/material/button_bar_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('ButtonBar default control smoketest', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar default control smoketest', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -17,7 +19,7 @@ void main() { group('alignment', () { - testWidgets('default alignment is MainAxisAlignment.end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default alignment is MainAxisAlignment.end', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: ButtonBar( @@ -34,7 +36,7 @@ void main() { expect(tester.getRect(child).right, 792.0); // bar width - default padding }); - testWidgets('ButtonBarTheme.alignment overrides default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarTheme.alignment overrides default', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: ButtonBarTheme( @@ -56,7 +58,7 @@ void main() { expect(tester.getRect(child).right, 405.0); // (bar width - padding) / 2 - 10 / 2 + 10 }); - testWidgets('ButtonBar.alignment overrides ButtonBarTheme.alignment and default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar.alignment overrides ButtonBarTheme.alignment and default', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: ButtonBarTheme( @@ -83,7 +85,7 @@ void main() { group('mainAxisSize', () { - testWidgets('Default mainAxisSize is MainAxisSize.max', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default mainAxisSize is MainAxisSize.max', (WidgetTester tester) async { const Key buttonBarKey = Key('row'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -130,7 +132,7 @@ void main() { expect(childRect.right, 800.0); }); - testWidgets('ButtonBarTheme.mainAxisSize overrides default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarTheme.mainAxisSize overrides default', (WidgetTester tester) async { const Key buttonBarKey = Key('row'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -185,7 +187,7 @@ void main() { expect(childRect.left, ((800.0 - buttonBarRect.width) / 2.0) + 200.0); }); - testWidgets('ButtonBar.mainAxisSize overrides ButtonBarTheme.mainAxisSize and default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar.mainAxisSize overrides ButtonBarTheme.mainAxisSize and default', (WidgetTester tester) async { const Key buttonBarKey = Key('row'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -240,7 +242,7 @@ void main() { group('button properties override ButtonTheme', () { - testWidgets('default button properties override ButtonTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default button properties override ButtonTheme properties', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( MaterialApp( @@ -263,7 +265,7 @@ void main() { expect(buttonTheme.layoutBehavior, equals(ButtonBarLayoutBehavior.padded)); }); - testWidgets('ButtonBarTheme button properties override defaults and ButtonTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarTheme button properties override defaults and ButtonTheme properties', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( MaterialApp( @@ -296,7 +298,7 @@ void main() { expect(buttonTheme.layoutBehavior, equals(ButtonBarLayoutBehavior.constrained)); }); - testWidgets('ButtonBar button properties override ButtonBarTheme, defaults and ButtonTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar button properties override ButtonBarTheme, defaults and ButtonTheme properties', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( MaterialApp( @@ -339,7 +341,7 @@ void main() { group('layoutBehavior', () { - testWidgets('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( @@ -362,7 +364,7 @@ void main() { expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 52.0); }); - testWidgets('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( @@ -387,7 +389,7 @@ void main() { }); group("ButtonBar's children wrap when they overflow horizontally", () { - testWidgets("ButtonBar's children wrap when buttons overflow", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ButtonBar's children wrap when buttons overflow", (WidgetTester tester) async { final Key keyOne = UniqueKey(); final Key keyTwo = UniqueKey(); await tester.pumpWidget( @@ -409,7 +411,7 @@ void main() { expect(containerOneRect.left, containerTwoRect.left); }); - testWidgets( + testWidgetsWithLeakTracking( "ButtonBar's children overflow defaults - MainAxisAlignment.end", (WidgetTester tester) async { final Key keyOne = UniqueKey(); final Key keyTwo = UniqueKey(); @@ -437,7 +439,7 @@ void main() { }, ); - testWidgets("ButtonBar's children overflow - MainAxisAlignment.start", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ButtonBar's children overflow - MainAxisAlignment.start", (WidgetTester tester) async { final Key keyOne = UniqueKey(); final Key keyTwo = UniqueKey(); await tester.pumpWidget( @@ -464,7 +466,7 @@ void main() { expect(containerOneRect.left, buttonBarRect.left); }); - testWidgets("ButtonBar's children overflow - MainAxisAlignment.center", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ButtonBar's children overflow - MainAxisAlignment.center", (WidgetTester tester) async { final Key keyOne = UniqueKey(); final Key keyTwo = UniqueKey(); await tester.pumpWidget( @@ -491,7 +493,7 @@ void main() { expect(containerOneRect.center.dx, buttonBarRect.center.dx); }); - testWidgets( + testWidgetsWithLeakTracking( "ButtonBar's children default to MainAxisAlignment.start for horizontal " 'alignment when overflowing in spaceBetween, spaceAround and spaceEvenly ' 'cases when overflowing.', (WidgetTester tester) async { @@ -545,7 +547,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( "ButtonBar's children respects verticalDirection when overflowing", (WidgetTester tester) async { final Key keyOne = UniqueKey(); @@ -574,7 +576,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'ButtonBar has no spacing by default when overflowing', (WidgetTester tester) async { final Key keyOne = UniqueKey(); @@ -599,7 +601,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( "ButtonBar's children respects overflowButtonSpacing when overflowing", (WidgetTester tester) async { final Key keyOne = UniqueKey(); @@ -628,7 +630,7 @@ void main() { ); }); - testWidgets('_RenderButtonBarRow.constraints does not work before layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('_RenderButtonBarRow.constraints does not work before layout', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp(home: ButtonBar()), Duration.zero, diff --git a/packages/flutter/test/material/button_bar_theme_test.dart b/packages/flutter/test/material/button_bar_theme_test.dart index ab8037b1b5618..7e25d30493b21 100644 --- a/packages/flutter/test/material/button_bar_theme_test.dart +++ b/packages/flutter/test/material/button_bar_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('ButtonBarThemeData lerp special cases', () { @@ -36,7 +38,7 @@ void main() { expect(const ButtonBarThemeData().hashCode, const ButtonBarThemeData().copyWith().hashCode); }); - testWidgets('ButtonBarThemeData lerps correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarThemeData lerps correctly', (WidgetTester tester) async { const ButtonBarThemeData barThemePrimary = ButtonBarThemeData( alignment: MainAxisAlignment.end, mainAxisSize: MainAxisSize.min, @@ -72,7 +74,7 @@ void main() { expect(lerp.overflowDirection, equals(VerticalDirection.up)); }); - testWidgets('Default ButtonBarThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ButtonBarThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ButtonBarThemeData().debugFillProperties(builder); @@ -84,7 +86,7 @@ void main() { expect(description, []); }); - testWidgets('ButtonBarThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ButtonBarThemeData( alignment: MainAxisAlignment.center, @@ -116,7 +118,7 @@ void main() { ]); }); - testWidgets('ButtonBarTheme.of falls back to ThemeData.buttonBarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarTheme.of falls back to ThemeData.buttonBarTheme', (WidgetTester tester) async { const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0); late BuildContext capturedContext; await tester.pumpWidget( @@ -134,7 +136,7 @@ void main() { expect(ButtonBarTheme.of(capturedContext).buttonMinWidth, equals(42.0)); }); - testWidgets('ButtonBarTheme overrides ThemeData.buttonBarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBarTheme overrides ThemeData.buttonBarTheme', (WidgetTester tester) async { const ButtonBarThemeData defaultBarTheme = ButtonBarThemeData(buttonMinWidth: 42.0); const ButtonBarThemeData buttonBarTheme = ButtonBarThemeData(buttonMinWidth: 84.0); late BuildContext capturedContext; diff --git a/packages/flutter/test/material/button_style_test.dart b/packages/flutter/test/material/button_style_test.dart index 2244c2940a72d..6ccc97ece5319 100644 --- a/packages/flutter/test/material/button_style_test.dart +++ b/packages/flutter/test/material/button_style_test.dart @@ -7,6 +7,8 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('ButtonStyle copyWith, merge, ==, hashCode basics', () { expect(const ButtonStyle(), const ButtonStyle().copyWith()); @@ -44,7 +46,7 @@ void main() { expect(style.enableFeedback, null); }); - testWidgets('Default ButtonStyle debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ButtonStyle debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ButtonStyle().debugFillProperties(builder); @@ -56,7 +58,7 @@ void main() { expect(description, []); }); - testWidgets('ButtonStyle debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonStyle debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ButtonStyle( textStyle: MaterialStatePropertyAll(TextStyle(fontSize: 10.0)), @@ -106,7 +108,7 @@ void main() { ]); }); - testWidgets('ButtonStyle copyWith, merge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonStyle copyWith, merge', (WidgetTester tester) async { const MaterialStateProperty textStyle = MaterialStatePropertyAll(TextStyle(fontSize: 10)); const MaterialStateProperty backgroundColor = MaterialStatePropertyAll(Color(0xfffffff1)); const MaterialStateProperty foregroundColor = MaterialStatePropertyAll(Color(0xfffffff2)); diff --git a/packages/flutter/test/material/button_theme_test.dart b/packages/flutter/test/material/button_theme_test.dart index d33dbc71d562a..4657e1b5f4b13 100644 --- a/packages/flutter/test/material/button_theme_test.dart +++ b/packages/flutter/test/material/button_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; + void main() { test('ButtonThemeData defaults', () { const ButtonThemeData theme = ButtonThemeData(); diff --git a/packages/flutter/test/material/card_test.dart b/packages/flutter/test/material/card_test.dart index 738104686adf9..7c9f2658543c2 100644 --- a/packages/flutter/test/material/card_test.dart +++ b/packages/flutter/test/material/card_test.dart @@ -6,10 +6,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('Card can take semantic text from multiple children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card can take semantic text from multiple children', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -77,7 +78,7 @@ void main() { semantics.dispose(); }); - testWidgets('Card merges children when it is a semanticContainer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card merges children when it is a semanticContainer', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); debugResetSemanticsIdCounter(); @@ -116,7 +117,7 @@ void main() { semantics.dispose(); }); - testWidgets('Card margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card margin', (WidgetTester tester) async { const Key contentsKey = ValueKey('contents'); await tester.pumpWidget( @@ -163,7 +164,7 @@ void main() { expect(tester.getSize(find.byKey(contentsKey)), const Size(100.0, 100.0)); }); - testWidgets('Card clipBehavior property passes through to the Material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card clipBehavior property passes through to the Material', (WidgetTester tester) async { await tester.pumpWidget(const Card()); expect(tester.widget(find.byType(Material)).clipBehavior, Clip.none); @@ -171,7 +172,7 @@ void main() { expect(tester.widget(find.byType(Material)).clipBehavior, Clip.antiAlias); }); - testWidgets('Card clipBehavior property defers to theme when null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card clipBehavior property defers to theme when null', (WidgetTester tester) async { await tester.pumpWidget(Builder(builder: (BuildContext context) { final ThemeData themeData = Theme.of(context); return Theme( @@ -186,7 +187,7 @@ void main() { expect(tester.widget(find.byType(Material)).clipBehavior, Clip.antiAliasWithSaveLayer); }); - testWidgets('Card shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card shadowColor', (WidgetTester tester) async { Material getCardMaterial(WidgetTester tester) { return tester.widget( find.descendant( diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 5a7754e68847d..24f9cfb554d23 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import 'feedback_tester.dart'; @@ -22,7 +23,7 @@ Widget wrap({ required Widget child }) { } void main() { - testWidgets('CheckboxListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile control test', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(wrap( child: CheckboxListTile( @@ -37,7 +38,7 @@ void main() { expect(log, equals([false, '-', false])); }); - testWidgets('CheckboxListTile checkColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile checkColor test', (WidgetTester tester) async { const Color checkBoxBorderColor = Color(0xff2196f3); Color checkBoxCheckColor = const Color(0xffFFFFFF); @@ -69,7 +70,7 @@ void main() { expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); }); - testWidgets('CheckboxListTile activeColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile activeColor test', (WidgetTester tester) async { Widget buildFrame(Color? themeColor, Color? activeColor) { return wrap( child: Theme( @@ -101,7 +102,7 @@ void main() { expect(getCheckboxListTileRenderer(), paints..path(color: const Color(0xFFFFFFFF))); }); - testWidgets('CheckboxListTile can autofocus unless disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile can autofocus unless disabled.', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( @@ -133,7 +134,7 @@ void main() { expect(Focus.maybeOf(childKey.currentContext!)!.hasPrimaryFocus, isFalse); }); - testWidgets('CheckboxListTile contentPadding test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile contentPadding test', (WidgetTester tester) async { await tester.pumpWidget( wrap( child: const Center( @@ -163,7 +164,7 @@ void main() { expect(paddingRect.bottom, tallerWidget.bottom + remainingHeight / 2 + 2); }); - testWidgets('CheckboxListTile tristate test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile tristate test', (WidgetTester tester) async { bool? value = false; bool tristate = false; @@ -241,7 +242,7 @@ void main() { expect(value, false); }); - testWidgets('CheckboxListTile respects shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects shape', (WidgetTester tester) async { const ShapeBorder shapeBorder = RoundedRectangleBorder( borderRadius: BorderRadius.horizontal(right: Radius.circular(100)), ); @@ -258,7 +259,7 @@ void main() { expect(tester.widget(find.byType(InkWell)).customBorder, shapeBorder); }); - testWidgets('CheckboxListTile respects tileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects tileColor', (WidgetTester tester) async { final Color tileColor = Colors.red.shade500; await tester.pumpWidget( @@ -277,7 +278,7 @@ void main() { expect(find.byType(Material), paints..rect(color: tileColor)); }); - testWidgets('CheckboxListTile respects selectedTileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects selectedTileColor', (WidgetTester tester) async { final Color selectedTileColor = Colors.green.shade500; await tester.pumpWidget( @@ -297,7 +298,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('CheckboxListTile selected item text Color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile selected item text Color', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/76908 const Color activeColor = Color(0xff00ff00); @@ -336,7 +337,7 @@ void main() { expect(textColor('title'), activeColor); }); - testWidgets('CheckboxListTile respects checkbox shape and side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects checkbox shape and side', (WidgetTester tester) async { Widget buildApp(BorderSide side, OutlinedBorder shape) { return MaterialApp( home: Material( @@ -390,7 +391,7 @@ void main() { ); }); - testWidgets('CheckboxListTile respects visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects visualDensity', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( @@ -414,7 +415,7 @@ void main() { expect(box.size, equals(const Size(800, 56))); }); - testWidgets('CheckboxListTile respects focusNode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects focusNode', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( wrap( @@ -436,7 +437,7 @@ void main() { expect(tileNode.hasPrimaryFocus, isTrue); }); - testWidgets('CheckboxListTile onFocusChange callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile onFocusChange callback', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'CheckboxListTile onFocusChange'); bool gotFocus = false; await tester.pumpWidget( @@ -465,7 +466,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('CheckboxListTile can be disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile can be disabled', (WidgetTester tester) async { bool? value = false; bool enabled = true; @@ -506,7 +507,7 @@ void main() { expect(tester.widget(checkbox).value, true); }); - testWidgets('CheckboxListTile respects mouseCursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects mouseCursor when hovered', (WidgetTester tester) async { // Test Checkbox() constructor await tester.pumpWidget( wrap( @@ -577,7 +578,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('CheckboxListTile respects fillColor in enabled/disabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects fillColor in enabled/disabled states', (WidgetTester tester) async { const Color activeEnabledFillColor = Color(0xFF000001); const Color activeDisabledFillColor = Color(0xFF000002); @@ -613,7 +614,7 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: activeDisabledFillColor)); }); - testWidgets('CheckboxListTile respects fillColor in hovered state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects fillColor in hovered state', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredFillColor = Color(0xFF000001); @@ -657,7 +658,7 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: hoveredFillColor)); }); - testWidgets('CheckboxListTile respects hoverColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects hoverColor', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp({bool enabled = true}) { @@ -825,7 +826,7 @@ void main() { ); }); - testWidgets('CheckboxListTile respects splashRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects splashRadius', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; Widget buildApp() { @@ -854,7 +855,7 @@ void main() { ); }); - testWidgets('CheckboxListTile respects materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects materialTapTargetSize', (WidgetTester tester) async { await tester.pumpWidget( wrap( child: CheckboxListTile( @@ -880,7 +881,7 @@ void main() { expect(tester.getSize(find.byType(Checkbox)), const Size(48.0, 48.0)); }); - testWidgets('CheckboxListTile respects isError - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects isError - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; @@ -928,7 +929,7 @@ void main() { ); }); - testWidgets('CheckboxListTile.adaptive shows the correct checkbox platform widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile.adaptive shows the correct checkbox platform widget', (WidgetTester tester) async { Widget buildApp(TargetPlatform platform) { return MaterialApp( theme: ThemeData(platform: platform), @@ -971,7 +972,7 @@ void main() { feedback.dispose(); }); - testWidgets('CheckboxListTile respects enableFeedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile respects enableFeedback', (WidgetTester tester) async { Future buildTest(bool enableFeedback) async { return tester.pumpWidget( wrap( @@ -1000,7 +1001,7 @@ void main() { }); }); - testWidgets('CheckboxListTile has proper semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxListTile has proper semantics', (WidgetTester tester) async { final List log = []; final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget(wrap( diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index f14f975d8a80a..6ff8e2e016e59 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -41,7 +42,7 @@ void main() { expect(theme.data.visualDensity, null); }); - testWidgets('Default CheckboxThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default CheckboxThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const CheckboxThemeData().debugFillProperties(builder); @@ -53,7 +54,7 @@ void main() { expect(description, []); }); - testWidgets('CheckboxThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckboxThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const CheckboxThemeData( mouseCursor: MaterialStatePropertyAll(SystemMouseCursors.click), @@ -84,7 +85,7 @@ void main() { ); }); - testWidgets('Checkbox is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox is themeable', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const MouseCursor mouseCursor = SystemMouseCursors.text; @@ -166,7 +167,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)..path(color: focusedCheckColor)); }); - testWidgets('Checkbox properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox properties are taken over the theme values', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const MouseCursor themeMouseCursor = SystemMouseCursors.click; @@ -264,7 +265,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..circle(color: focusColor, radius: splashRadius)); }); - testWidgets('Checkbox activeColor property is taken over the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox activeColor property is taken over the theme', (WidgetTester tester) async { const Color themeSelectedFillColor = Color(0xfffffff1); const Color themeDefaultFillColor = Color(0xfffffff0); const Color selectedFillColor = Color(0xfffffff6); @@ -302,7 +303,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)); }); - testWidgets('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); @@ -363,7 +364,7 @@ void main() { ); }); - testWidgets('Local CheckboxTheme can override global CheckboxTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Local CheckboxTheme can override global CheckboxTheme', (WidgetTester tester) async { const Color globalThemeFillColor = Color(0xfffffff1); const Color globalThemeCheckColor = Color(0xff000000); const Color localThemeFillColor = Color(0xffff0000); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 4f90081c708ff..d7a8e9e802819 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -295,7 +296,7 @@ void main() { expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing); }); - testWidgets('M3 Chip defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 Chip defaults', (WidgetTester tester) async { late TextTheme textTheme; final ThemeData lightTheme = ThemeData.light(useMaterial3: true); final ThemeData darkTheme = ThemeData.dark(useMaterial3: true); @@ -376,7 +377,7 @@ void main() { expect(labelStyle.wordSpacing, textTheme.labelLarge?.wordSpacing); }); - testWidgets('Chip control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip control test', (WidgetTester tester) async { final FeedbackTester feedback = FeedbackTester(); final List deletedChipLabels = []; await tester.pumpWidget( @@ -425,7 +426,7 @@ void main() { feedback.dispose(); }); - testWidgets( + testWidgetsWithLeakTracking( 'Chip does not constrain size of label widget if it does not exceed ' 'the available space', (WidgetTester tester) async { @@ -461,7 +462,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Chip constrains the size of the label widget when it exceeds the ' 'available space', (WidgetTester tester) async { @@ -469,7 +470,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Chip constrains the size of the label widget when it exceeds the ' 'available space and the avatar is present', (WidgetTester tester) async { @@ -480,7 +481,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Chip constrains the size of the label widget when it exceeds the ' 'available space and the delete icon is present', (WidgetTester tester) async { @@ -491,7 +492,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Chip constrains the size of the label widget when it exceeds the ' 'available space and both avatar and delete icons are present', (WidgetTester tester) async { @@ -503,7 +504,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Chip constrains the avatar, label, and delete icons to the bounds of ' 'the chip when it exceeds the available space', (WidgetTester tester) async { @@ -578,7 +579,7 @@ void main() { }, ); - testWidgets('Chip in row works ok', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip in row works ok', (WidgetTester tester) async { const TextStyle style = TextStyle(fontSize: 10.0); await tester.pumpWidget( wrapForChip( @@ -616,7 +617,7 @@ void main() { expect(tester.getSize(find.byType(Chip)), const Size(800.0, 48.0)); }); - testWidgets('Chip responds to materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip responds to materialTapTargetSize', (WidgetTester tester) async { await tester.pumpWidget( wrapForChip( useMaterial3: false, @@ -639,7 +640,7 @@ void main() { }, ); - testWidgets('Delete button tap target is the right proportion of the chip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete button tap target is the right proportion of the chip', (WidgetTester tester) async { final UniqueKey deleteKey = UniqueKey(); bool calledDelete = false; await tester.pumpWidget( @@ -701,7 +702,7 @@ void main() { expect(calledDelete, isFalse); }); - testWidgets('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { final UniqueKey iconKey = UniqueKey(); final Widget test = Overlay( initialEntries: [ @@ -736,7 +737,7 @@ void main() { expect(tester.getCenter(find.text('ABC')).dx, lessThan(tester.getCenter(find.byKey(iconKey)).dx)); }); - testWidgets('Chip responds to textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip responds to textScaleFactor', (WidgetTester tester) async { await tester.pumpWidget( wrapForChip( useMaterial3: false, @@ -813,7 +814,7 @@ void main() { expect(tester.getSize(find.byType(Chip).last), const Size(132.0, 48.0)); }); - testWidgets('Labels can be non-text widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Labels can be non-text widgets', (WidgetTester tester) async { final Key keyA = GlobalKey(); final Key keyB = GlobalKey(); await tester.pumpWidget( @@ -840,7 +841,7 @@ void main() { expect(tester.getSize(find.byType(Chip).last), const Size(58.0, 48.0)); }); - testWidgets('Avatars can be non-circle avatar widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Avatars can be non-circle avatar widgets', (WidgetTester tester) async { final Key keyA = GlobalKey(); await tester.pumpWidget( wrapForChip( @@ -858,7 +859,7 @@ void main() { expect(tester.getSize(find.byKey(keyA)), equals(const Size(20.0, 20.0))); }); - testWidgets('Delete icons can be non-icon widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete icons can be non-icon widgets', (WidgetTester tester) async { final Key keyA = GlobalKey(); await tester.pumpWidget( wrapForChip( @@ -877,7 +878,7 @@ void main() { expect(tester.getSize(find.byKey(keyA)), equals(const Size(20.0, 20.0))); }); - testWidgets('Chip padding - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip padding - LTR', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -913,7 +914,7 @@ void main() { expect(tester.getBottomRight(find.byType(Icon)), const Offset(457.0, 309.0)); }); - testWidgets('Chip padding - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip padding - RTL', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -951,7 +952,7 @@ void main() { expect(tester.getBottomRight(find.byType(Icon)), const Offset(361.0, 309.0)); }); - testWidgets('Avatar drawer works as expected on RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Avatar drawer works as expected on RawChip', (WidgetTester tester) async { final GlobalKey labelKey = GlobalKey(); Future pushChip({ Widget? avatar }) async { return tester.pumpWidget( @@ -1064,7 +1065,7 @@ void main() { expect(find.byKey(avatarKey), findsNothing); }); - testWidgets('Delete button drawer works as expected on RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete button drawer works as expected on RawChip', (WidgetTester tester) async { const Key labelKey = Key('label'); const Key deleteButtonKey = Key('delete'); bool wasDeleted = false; @@ -1181,7 +1182,7 @@ void main() { expect(find.byKey(deleteButtonKey), findsNothing); }); - testWidgets('Delete button takes up at most half of the chip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete button takes up at most half of the chip', (WidgetTester tester) async { final UniqueKey chipKey = UniqueKey(); bool chipPressed = false; bool deletePressed = false; @@ -1217,7 +1218,7 @@ void main() { expect(deletePressed, isTrue); }); - testWidgets('Chip creates centered, unique ripple when label is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip creates centered, unique ripple when label is tapped', (WidgetTester tester) async { final UniqueKey labelKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey(); @@ -1267,7 +1268,7 @@ void main() { await gesture.up(); }); - testWidgets('Delete button is focusable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete button is focusable', (WidgetTester tester) async { final GlobalKey labelKey = GlobalKey(); final GlobalKey deleteButtonKey = GlobalKey(); @@ -1300,7 +1301,7 @@ void main() { expect(Focus.of(labelKey.currentContext!).hasPrimaryFocus, isTrue); }); - testWidgets('Delete button creates non-centered, unique ripple when tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete button creates non-centered, unique ripple when tapped', (WidgetTester tester) async { final UniqueKey labelKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey(); @@ -1354,7 +1355,7 @@ void main() { await gesture.up(); }); - testWidgets('Delete button in a chip with null onPressed creates ripple when tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delete button in a chip with null onPressed creates ripple when tapped', (WidgetTester tester) async { final UniqueKey labelKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey(); @@ -1409,7 +1410,7 @@ void main() { await gesture.up(); }); - testWidgets('RTL delete button responds to tap on the left of the chip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RTL delete button responds to tap on the left of the chip', (WidgetTester tester) async { // Creates an RTL chip with a delete button. final UniqueKey labelKey = UniqueKey(); final UniqueKey deleteButtonKey = UniqueKey(); @@ -1439,7 +1440,7 @@ void main() { await gesture.up(); }); - testWidgets('Chip without delete button creates correct ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip without delete button creates correct ripple', (WidgetTester tester) async { // Creates a chip with a delete button. final UniqueKey labelKey = UniqueKey(); @@ -1494,7 +1495,7 @@ void main() { await gesture.up(); }); - testWidgets('Selection with avatar works as expected on RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selection with avatar works as expected on RawChip', (WidgetTester tester) async { bool selected = false; final UniqueKey labelKey = UniqueKey(); Future pushChip({ Widget? avatar, bool selectable = false }) async { @@ -1575,7 +1576,7 @@ void main() { expect(getDeleteDrawerProgress(tester), equals(0.0)); }); - testWidgets('Selection without avatar works as expected on RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selection without avatar works as expected on RawChip', (WidgetTester tester) async { bool selected = false; final UniqueKey labelKey = UniqueKey(); Future pushChip({ bool selectable = false }) async { @@ -1649,7 +1650,7 @@ void main() { expect(getDeleteDrawerProgress(tester), equals(0.0)); }); - testWidgets('Activation works as expected on RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activation works as expected on RawChip', (WidgetTester tester) async { bool selected = false; final UniqueKey labelKey = UniqueKey(); Future pushChip({ Widget? avatar, bool selectable = false }) async { @@ -1706,7 +1707,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Chip uses ThemeData chip theme if present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses ThemeData chip theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: false, platform: TargetPlatform.android, @@ -1737,7 +1738,7 @@ void main() { expect(materialBox, paints..rrect(color: chipTheme.disabledColor)); }); - testWidgets('Chip merges ChipThemeData label style with the provided label style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip merges ChipThemeData label style with the provided label style', (WidgetTester tester) async { // The font family should be preserved even if the chip overrides some label style properties final ThemeData theme = ThemeData( fontFamily: 'MyFont', @@ -1763,7 +1764,7 @@ void main() { expect(labelStyle.fontWeight, FontWeight.w200); }); - testWidgets('ChipTheme labelStyle with inherit:true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChipTheme labelStyle with inherit:true', (WidgetTester tester) async { Widget buildChip() { return wrapForChip( child: Theme( @@ -1783,7 +1784,7 @@ void main() { expect(labelStyle.height, 4); }); - testWidgets('Chip does not merge inherit:false label style with the theme label style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip does not merge inherit:false label style with the theme label style', (WidgetTester tester) async { Widget buildChip() { return wrapForChip( child: Theme( @@ -1807,7 +1808,7 @@ void main() { expect(labelStyle.fontWeight, FontWeight.w200); }); - testWidgets('Chip size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { final Key key1 = UniqueKey(); await tester.pumpWidget( wrapForChip( @@ -1967,7 +1968,7 @@ void main() { }); group('Chip semantics', () { - testWidgets('label only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label only', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(const MaterialApp( @@ -2015,7 +2016,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('delete', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -2075,7 +2076,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('with onPressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with onPressed', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -2129,7 +2130,7 @@ void main() { }); - testWidgets('with onSelected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with onSelected', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); bool selected = false; @@ -2239,7 +2240,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -2291,7 +2292,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('tapEnabled explicitly false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tapEnabled explicitly false', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(const MaterialApp( @@ -2339,7 +2340,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('enabled when tapEnabled and canTap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('enabled when tapEnabled and canTap', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); // These settings make a Chip which can be tapped, both in general and at this moment. @@ -2393,7 +2394,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('disabled when tapEnabled but not canTap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled when tapEnabled but not canTap', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); // These settings make a Chip which _could_ be tapped, but not currently (ensures `canTap == false`). await tester.pumpWidget(const MaterialApp( @@ -2443,7 +2444,7 @@ void main() { }); }); - testWidgets('can be tapped outside of chip delete icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can be tapped outside of chip delete icon', (WidgetTester tester) async { bool deleted = false; await tester.pumpWidget( wrapForChip( @@ -2469,7 +2470,7 @@ void main() { expect(deleted, true); }); - testWidgets('Chips can be tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chips can be tapped', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -2484,7 +2485,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Chip elevation and shadow color work correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip elevation and shadow color work correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: false, platform: TargetPlatform.android, @@ -2535,7 +2536,7 @@ void main() { expect(material.shadowColor, Colors.blue); }); - testWidgets('can be tapped outside of chip body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can be tapped outside of chip body', (WidgetTester tester) async { bool pressed = false; await tester.pumpWidget( wrapForChip( @@ -2560,7 +2561,7 @@ void main() { expect(pressed, true); }); - testWidgets('is hitTestable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is hitTestable', (WidgetTester tester) async { await tester.pumpWidget( wrapForChip( child: InputChip( @@ -2581,7 +2582,7 @@ void main() { expect(materials.last.clipBehavior, clipBehavior); } - testWidgets('Chip clipBehavior properly passes through to the Material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip clipBehavior properly passes through to the Material', (WidgetTester tester) async { const Text label = Text('label'); await tester.pumpWidget(wrapForChip(child: const Chip(label: label))); checkChipMaterialClipBehavior(tester, Clip.none); @@ -2618,7 +2619,7 @@ void main() { ])); }); - testWidgets('Chips should use InkWell instead of InkResponse.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chips should use InkWell instead of InkResponse.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28646 await tester.pumpWidget( MaterialApp( @@ -2633,7 +2634,7 @@ void main() { expect(find.byType(InkWell), findsOneWidget); }); - testWidgets('Chip uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2721,7 +2722,7 @@ void main() { expect(textColor(), disabledColor); }); - testWidgets('Chip uses stateful border side color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful border side color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2801,7 +2802,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgets('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2882,7 +2883,7 @@ void main() { }); - testWidgets('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2971,7 +2972,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgets('Chip uses stateful shape in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful shape in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); OutlinedBorder? getShape(Set states) { @@ -3042,7 +3043,7 @@ void main() { expect(getMaterial(tester).shape, isA()); }); - testWidgets('Chip defers to theme, if shape and side resolves to null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip defers to theme, if shape and side resolves to null', (WidgetTester tester) async { const OutlinedBorder themeShape = StadiumBorder(); const OutlinedBorder selectedShape = RoundedRectangleBorder(); const BorderSide themeBorderSide = BorderSide(color: Color(0x00000001)); @@ -3094,7 +3095,7 @@ void main() { expect(find.byType(RawChip), paints..rect()..drrect(color: selectedBorderSide.color)); }); - testWidgets('Chip responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key textKey = Key('test text'); const Key iconKey = Key('test icon'); @@ -3200,7 +3201,7 @@ void main() { expect(box.size, equals(const Size(128, 24.0 + 16.0))); }); - testWidgets('Chip delete button tooltip can be disabled using useDeleteButtonTooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip delete button tooltip can be disabled using useDeleteButtonTooltip', (WidgetTester tester) async { await tester.pumpWidget( chipWithOptionalDeleteButton( deletable: true, @@ -3225,7 +3226,7 @@ void main() { await tapGesture.up(); }); - testWidgets('Chip delete button tooltip is disabled if deleteButtonTooltipMessage is empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip delete button tooltip is disabled if deleteButtonTooltipMessage is empty', (WidgetTester tester) async { final UniqueKey deleteButtonKey = UniqueKey(); await tester.pumpWidget( chipWithOptionalDeleteButton( @@ -3250,7 +3251,7 @@ void main() { expect(findTooltipContainer(''), findsNothing); }); - testWidgets('Disabling delete button tooltip does not disable chip tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabling delete button tooltip does not disable chip tooltip', (WidgetTester tester) async { final UniqueKey deleteButtonKey = UniqueKey(); await tester.pumpWidget( chipWithOptionalDeleteButton( @@ -3278,7 +3279,7 @@ void main() { expect(findTooltipContainer('Chip Tooltip'), findsOneWidget); }); - testWidgets('Triggering delete button tooltip does not trigger Chip tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Triggering delete button tooltip does not trigger Chip tooltip', (WidgetTester tester) async { final UniqueKey deleteButtonKey = UniqueKey(); await tester.pumpWidget( chipWithOptionalDeleteButton( @@ -3305,7 +3306,7 @@ void main() { expect(findTooltipContainer('Delete'), findsOneWidget); }); - testWidgets('intrinsicHeight implementation meets constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('intrinsicHeight implementation meets constraints', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/49478. await tester.pumpWidget(wrapForChip( child: const Chip( @@ -3317,7 +3318,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Chip background color and shape are drawn on Ink', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip background color and shape are drawn on Ink', (WidgetTester tester) async { const Color backgroundColor = Color(0xff00ff00); const OutlinedBorder shape = ContinuousRectangleBorder(); @@ -3339,7 +3340,7 @@ void main() { expect(decoration.shape, shape); }); - testWidgets('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'RawChip'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color backgroundColor = Color(0xff00ff00); @@ -3367,7 +3368,7 @@ void main() { ); }); - testWidgets('RawChip.color resolves material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawChip.color resolves material states', (WidgetTester tester) async { const Color disabledSelectedColor = Color(0xffffff00); const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); @@ -3423,7 +3424,7 @@ void main() { expect(getMaterialBox(tester), paints..rrect(color: disabledSelectedColor)); }); - testWidgets('RawChip uses provided state color properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawChip uses provided state color properties', (WidgetTester tester) async { const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); const Color selectedColor = Color(0xffff0000); diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 85e901b2a1064..5da0b0a428fdf 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; RenderBox getMaterialBox(WidgetTester tester) { @@ -72,7 +73,7 @@ void main() { expect(themeData.pressElevation, null); }); - testWidgets('Default ChipThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ChipThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ChipThemeData().debugFillProperties(builder); @@ -84,7 +85,7 @@ void main() { expect(description, []); }); - testWidgets('ChipThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChipThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ChipThemeData( color: MaterialStatePropertyAll(Color(0xfffffff0)), @@ -138,7 +139,7 @@ void main() { ]); }); - testWidgets('Chip uses ThemeData chip theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses ThemeData chip theme', (WidgetTester tester) async { const ChipThemeData chipTheme = ChipThemeData( backgroundColor: Color(0xff112233), elevation: 4, @@ -175,7 +176,7 @@ void main() { expect(getLabelStyle(tester).style.fontSize, 32); }); - testWidgets('Chip uses ChipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses ChipTheme', (WidgetTester tester) async { const ChipThemeData chipTheme = ChipThemeData( backgroundColor: Color(0xff112233), elevation: 4, @@ -228,7 +229,7 @@ void main() { expect(getLabelStyle(tester).style.fontSize, 32); }); - testWidgets('Chip uses constructor parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses constructor parameters', (WidgetTester tester) async { const ChipThemeData shadowedChipTheme = ChipThemeData( backgroundColor: Color(0xff112233), elevation: 4, @@ -281,7 +282,7 @@ void main() { expect(getLabelStyle(tester).style.fontSize, 32); }); - testWidgets('ChipTheme.fromDefaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChipTheme.fromDefaults', (WidgetTester tester) async { const TextStyle labelStyle = TextStyle(); ChipThemeData chipTheme = ChipThemeData.fromDefaults( brightness: Brightness.light, @@ -333,7 +334,7 @@ void main() { expect(chipTheme.pressElevation, 8.0); }); - testWidgets('ChipThemeData generates correct opacities for defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChipThemeData generates correct opacities for defaults', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); final TextStyle customStyle = ThemeData.fallback().textTheme.bodyLarge!.copyWith(color: customColor2); @@ -396,7 +397,7 @@ void main() { expect(customTheme.brightness, equals(Brightness.light)); }); - testWidgets('ChipThemeData lerps correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChipThemeData lerps correctly', (WidgetTester tester) async { final ChipThemeData chipThemeBlack = ChipThemeData.fromDefaults( secondaryColor: Colors.black, brightness: Brightness.dark, @@ -544,7 +545,7 @@ void main() { expect(lerp.iconTheme, isNull); }); - testWidgets('Chip uses stateful color from chip theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful color from chip theme', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -640,7 +641,7 @@ void main() { expect(textColor(), disabledColor); }); - testWidgets('Chip uses stateful border side from resolveWith pattern', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful border side from resolveWith pattern', (WidgetTester tester) async { const Color selectedColor = Color(0x00000001); const Color defaultColor = Color(0x00000002); @@ -681,7 +682,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: selectedColor)); }); - testWidgets('Chip uses stateful border side from chip theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful border side from chip theme', (WidgetTester tester) async { const Color selectedColor = Color(0x00000001); const Color defaultColor = Color(0x00000002); @@ -723,7 +724,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: selectedColor)); }); - testWidgets('Chip uses stateful shape from chip theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful shape from chip theme', (WidgetTester tester) async { OutlinedBorder? getShape(Set states) { if (states.contains(MaterialState.selected)) { return const RoundedRectangleBorder(); @@ -763,7 +764,7 @@ void main() { expect(getMaterial(tester).shape, isA()); }); - testWidgets('RawChip uses material state color from ChipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawChip uses material state color from ChipTheme', (WidgetTester tester) async { const Color disabledSelectedColor = Color(0xffffff00); const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); @@ -827,7 +828,7 @@ void main() { expect(getMaterialBox(tester), paints..rrect(color: disabledSelectedColor)); }); - testWidgets('RawChip uses state colors from ChipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawChip uses state colors from ChipTheme', (WidgetTester tester) async { const ChipThemeData chipTheme = ChipThemeData( disabledColor: Color(0xadfefafe), backgroundColor: Color(0xcafefeed), diff --git a/packages/flutter/test/material/choice_chip_test.dart b/packages/flutter/test/material/choice_chip_test.dart index 187ec8fd2cef9..da5277eccedd8 100644 --- a/packages/flutter/test/material/choice_chip_test.dart +++ b/packages/flutter/test/material/choice_chip_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; RenderBox getMaterialBox(WidgetTester tester, Finder type) { @@ -64,7 +65,7 @@ void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) { } void main() { - testWidgets('ChoiceChip defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const String label = 'choice chip'; @@ -196,7 +197,7 @@ void main() { expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12)); }); - testWidgets('ChoiceChip.elevated defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip.elevated defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const String label = 'choice chip'; @@ -328,7 +329,7 @@ void main() { expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12)); }); - testWidgets('ChoiceChip.color resolves material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip.color resolves material states', (WidgetTester tester) async { const Color disabledSelectedColor = Color(0xffffff00); const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); @@ -427,7 +428,7 @@ void main() { ); }); - testWidgets('ChoiceChip uses provided state color properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip uses provided state color properties', (WidgetTester tester) async { const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); const Color selectedColor = Color(0xffff0000); @@ -502,7 +503,7 @@ void main() { ); }); - testWidgets('ChoiceChip can be tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip can be tapped', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -518,7 +519,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('ChoiceChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { const Text label = Text('label'); await tester.pumpWidget(wrapForChip(child: const ChoiceChip(label: label, selected: false))); checkChipMaterialClipBehavior(tester, Clip.none); @@ -527,7 +528,7 @@ void main() { checkChipMaterialClipBehavior(tester, Clip.antiAlias); }); - testWidgets('ChoiceChip passes iconTheme property to RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip passes iconTheme property to RawChip', (WidgetTester tester) async { const IconThemeData iconTheme = IconThemeData(color: Colors.red); await tester.pumpWidget(wrapForChip( child: const ChoiceChip( @@ -539,7 +540,7 @@ void main() { expect(rawChip.iconTheme, iconTheme); }); - testWidgets('ChoiceChip passes showCheckmark from ChipTheme to RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip passes showCheckmark from ChipTheme to RawChip', (WidgetTester tester) async { const bool showCheckmark = false; await tester.pumpWidget(wrapForChip( child: const ChipTheme( @@ -555,7 +556,7 @@ void main() { expect(rawChip.showCheckmark, showCheckmark); }); - testWidgets('ChoiceChip passes checkmark properties to RawChip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip passes checkmark properties to RawChip', (WidgetTester tester) async { const bool showCheckmark = false; const Color checkmarkColor = Color(0xff0000ff); await tester.pumpWidget(wrapForChip( @@ -575,7 +576,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('ChoiceChip defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ChoiceChip defaults', (WidgetTester tester) async { Widget buildFrame(Brightness brightness) { return MaterialApp( theme: ThemeData(useMaterial3: false, brightness: brightness), diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart index bf4ffe919d00b..93ede89c0c7a6 100644 --- a/packages/flutter/test/material/circle_avatar_test.dart +++ b/packages/flutter/test/material/circle_avatar_test.dart @@ -13,11 +13,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../image_data.dart'; import '../painting/mocks_for_image_cache.dart'; void main() { - testWidgets('CircleAvatar with dark background color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar with dark background color', (WidgetTester tester) async { final Color backgroundColor = Colors.blue.shade900; await tester.pumpWidget( wrap( @@ -39,7 +40,7 @@ void main() { expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight)); }); - testWidgets('CircleAvatar with light background color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar with light background color', (WidgetTester tester) async { final Color backgroundColor = Colors.blue.shade100; await tester.pumpWidget( wrap( @@ -61,7 +62,7 @@ void main() { expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorDark)); }); - testWidgets('CircleAvatar with image background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar with image background', (WidgetTester tester) async { await tester.pumpWidget( wrap( child: CircleAvatar( @@ -78,7 +79,7 @@ void main() { expect(decoration.image!.fit, equals(BoxFit.cover)); }); - testWidgets('CircleAvatar with image foreground', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar with image foreground', (WidgetTester tester) async { await tester.pumpWidget( wrap( child: CircleAvatar( @@ -95,7 +96,7 @@ void main() { expect(decoration.image!.fit, equals(BoxFit.cover)); }); - testWidgets('CircleAvatar backgroundImage is used as a fallback for foregroundImage', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar backgroundImage is used as a fallback for foregroundImage', (WidgetTester tester) async { final ErrorImageProvider errorImage = ErrorImageProvider(); bool caughtForegroundImageError = false; await tester.pumpWidget( @@ -123,7 +124,7 @@ void main() { ); }); - testWidgets('CircleAvatar with foreground color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar with foreground color', (WidgetTester tester) async { final Color foregroundColor = Colors.red.shade100; await tester.pumpWidget( wrap( @@ -146,7 +147,7 @@ void main() { expect(paragraph.text.style!.color, equals(foregroundColor)); }); - testWidgets('CircleAvatar default colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar default colors', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( wrap( @@ -168,7 +169,7 @@ void main() { expect(paragraph.text.style!.color, equals(theme.colorScheme.onPrimaryContainer)); }); - testWidgets('CircleAvatar text does not expand with textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar text does not expand with textScaleFactor', (WidgetTester tester) async { final Color foregroundColor = Colors.red.shade100; await tester.pumpWidget( wrap( @@ -212,7 +213,7 @@ void main() { expect(tester.getSize(find.text('Z')), equals(const Size(16.0, 16.0))); }); - testWidgets('CircleAvatar respects minRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar respects minRadius', (WidgetTester tester) async { final Color backgroundColor = Colors.blue.shade900; await tester.pumpWidget( wrap( @@ -236,7 +237,7 @@ void main() { expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight)); }); - testWidgets('CircleAvatar respects maxRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar respects maxRadius', (WidgetTester tester) async { final Color backgroundColor = Colors.blue.shade900; await tester.pumpWidget( wrap( @@ -258,7 +259,7 @@ void main() { expect(paragraph.text.style!.color, equals(ThemeData.fallback().primaryColorLight)); }); - testWidgets('CircleAvatar respects setting both minRadius and maxRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar respects setting both minRadius and maxRadius', (WidgetTester tester) async { final Color backgroundColor = Colors.blue.shade900; await tester.pumpWidget( wrap( @@ -286,7 +287,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('CircleAvatar default colors with light theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar default colors with light theme', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false, primaryColor: Colors.grey.shade100); await tester.pumpWidget( wrap( @@ -308,7 +309,7 @@ void main() { expect(paragraph.text.style!.color, equals(theme.primaryTextTheme.titleLarge!.color)); }); - testWidgets('CircleAvatar default colors with dark theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircleAvatar default colors with dark theme', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false, primaryColor: Colors.grey.shade800); await tester.pumpWidget( wrap( diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 4e9d0af6e9f12..8dfdece1229ed 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -13,11 +13,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart' show Matrix3; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import 'data_table_test_utils.dart'; void main() { - testWidgets('DataTable control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable control test', (WidgetTester tester) async { final List log = []; Widget buildTable({ int? sortColumnIndex, bool sortAscending = true }) { @@ -160,7 +161,7 @@ void main() { log.clear(); }); - testWidgets('DataTable control test - tristate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable control test - tristate', (WidgetTester tester) async { final List log = []; const int numItems = 3; Widget buildTable(List selected, {int? disabledIndex}) { @@ -230,7 +231,7 @@ void main() { log.clear(); }); - testWidgets('DataTable control test - no checkboxes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable control test - no checkboxes', (WidgetTester tester) async { final List log = []; Widget buildTable({ bool checkboxes = false }) { @@ -296,7 +297,7 @@ void main() { log.clear(); }); - testWidgets('DataTable overflow test - header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable overflow test - header', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -329,7 +330,7 @@ void main() { expect(tester.takeException(), isNull); // column overflows table, but text doesn't overflow cell }); - testWidgets('DataTable overflow test - header with spaces', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable overflow test - header with spaces', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -357,7 +358,7 @@ void main() { expect(tester.takeException(), isNull); // column overflows table, but text doesn't overflow cell }, skip: true); // https://github.com/flutter/flutter/issues/13512 - testWidgets('DataTable overflow test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable overflow test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -385,7 +386,7 @@ void main() { expect(tester.takeException(), isNull); // cell overflows table, but text doesn't overflow cell }); - testWidgets('DataTable overflow test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable overflow test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -413,7 +414,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('DataTable column onSort test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable column onSort test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -441,7 +442,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('DataTable sort indicator orientation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable sort indicator orientation', (WidgetTester tester) async { Widget buildTable({ bool sortAscending = true }) { return DataTable( sortColumnIndex: 0, @@ -493,7 +494,7 @@ void main() { ); }); - testWidgets('DataTable sort indicator orientation does not change on state update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable sort indicator orientation does not change on state update', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/43724 Widget buildTable({String title = 'Name1'}) { return DataTable( @@ -545,7 +546,7 @@ void main() { ); }); - testWidgets('DataTable sort indicator orientation does not change on state update - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable sort indicator orientation does not change on state update - reverse', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/43724 Widget buildTable({String title = 'Name1'}) { return DataTable( @@ -598,7 +599,7 @@ void main() { ); }); - testWidgets('DataTable row onSelectChanged test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable row onSelectChanged test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -626,7 +627,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('DataTable custom row height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable custom row height', (WidgetTester tester) async { Widget buildCustomTable({ int? sortColumnIndex, bool sortAscending = true, @@ -739,7 +740,7 @@ void main() { expect(tester.getSize(findFirstContainerFor('Frozen yogurt')).height, greaterThan(0.0)); }); - testWidgets('DataTable custom row height one row taller than others', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable custom row height one row taller than others', (WidgetTester tester) async { const String multilineText = 'Line one.\nLine two.\nLine three.\nLine four.'; Widget buildCustomTable({ @@ -780,7 +781,7 @@ void main() { expect(multilineRowHeight, greaterThan(singleLineRowHeight)); }); - testWidgets('DataTable custom row height - separate test for deprecated dataRowHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable custom row height - separate test for deprecated dataRowHeight', (WidgetTester tester) async { Widget buildCustomTable({ double dataRowHeight = 48.0, }) { @@ -830,7 +831,7 @@ void main() { expect(tester.getSize(findFirstContainerFor('Frozen yogurt')).height, 30.0); }); - testWidgets('DataTable custom horizontal padding - checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable custom horizontal padding - checkbox', (WidgetTester tester) async { const double defaultHorizontalMargin = 24.0; const double defaultColumnSpacing = 56.0; const double customHorizontalMargin = 10.0; @@ -1053,7 +1054,7 @@ void main() { ); }); - testWidgets('DataTable custom horizontal padding - no checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable custom horizontal padding - no checkbox', (WidgetTester tester) async { const double defaultHorizontalMargin = 24.0; const double defaultColumnSpacing = 56.0; const double customHorizontalMargin = 10.0; @@ -1247,7 +1248,7 @@ void main() { ); }); - testWidgets('DataTable set border width test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable set border width test', (WidgetTester tester) async { const List columns = [ DataColumn(label: Text('column1')), DataColumn(label: Text('column2')), @@ -1299,7 +1300,7 @@ void main() { expect(boxDecoration.border!.top.width, thickness); }); - testWidgets('DataTable set show bottom border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable set show bottom border', (WidgetTester tester) async { const List columns = [ DataColumn(label: Text('column1')), DataColumn(label: Text('column2')), @@ -1348,7 +1349,7 @@ void main() { expect(boxDecoration.border!.bottom.width, 0.0); }); - testWidgets('DataTable column heading cell - with and without sorting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable column heading cell - with and without sorting', (WidgetTester tester) async { Widget buildTable({ int? sortColumnIndex, bool sortEnabled = true }) { return DataTable( sortColumnIndex: sortColumnIndex, @@ -1412,7 +1413,7 @@ void main() { } }); - testWidgets('DataTable correctly renders with a mouse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable correctly renders with a mouse', (WidgetTester tester) async { // Regression test for a bug described in // https://github.com/flutter/flutter/pull/43735#issuecomment-589459947 // Filed at https://github.com/flutter/flutter/issues/51152 @@ -1460,7 +1461,7 @@ void main() { await tester.pumpAndSettle(const Duration(seconds: 1)); }); - testWidgets('DataRow renders default selected row colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow renders default selected row colors', (WidgetTester tester) async { final ThemeData themeData = ThemeData.light(); Widget buildTable({bool selected = false}) { return MaterialApp( @@ -1502,7 +1503,7 @@ void main() { ); }); - testWidgets('DataRow renders checkbox with colors from CheckboxTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow renders checkbox with colors from CheckboxTheme', (WidgetTester tester) async { const Color fillColor = Color(0xFF00FF00); const Color checkColor = Color(0xFF0000FF); @@ -1547,7 +1548,7 @@ void main() { ); }); - testWidgets('DataRow renders custom colors when selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow renders custom colors when selected', (WidgetTester tester) async { const Color selectedColor = Colors.green; const Color defaultColor = Colors.red; @@ -1596,7 +1597,7 @@ void main() { expect(lastTableRowBoxDecoration().color, selectedColor); }); - testWidgets('DataRow renders custom colors when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow renders custom colors when disabled', (WidgetTester tester) async { const Color disabledColor = Colors.grey; const Color defaultColor = Colors.red; @@ -1651,7 +1652,7 @@ void main() { expect(lastTableRowBoxDecoration().color, disabledColor); }); - testWidgets('DataRow renders custom colors when pressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow renders custom colors when pressed', (WidgetTester tester) async { const Color pressedColor = Color(0xff4caf50); Widget buildTable() { return DataTable( @@ -1691,7 +1692,7 @@ void main() { await gesture.up(); }); - testWidgets('DataTable can render inside an AlertDialog', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable can render inside an AlertDialog', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1713,7 +1714,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('DataTable renders with border and background decoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable renders with border and background decoration', (WidgetTester tester) async { const double width = 800; const double height = 600; const double borderHorizontal = 5.0; @@ -1762,7 +1763,7 @@ void main() { ); }); - testWidgets('checkboxHorizontalMargin properly applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('checkboxHorizontalMargin properly applied', (WidgetTester tester) async { const double customCheckboxHorizontalMargin = 15.0; const double customHorizontalMargin = 10.0; Finder cellContent; @@ -1851,7 +1852,7 @@ void main() { ); }); - testWidgets('DataRow is disabled when onSelectChanged is not set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow is disabled when onSelectChanged is not set', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1886,7 +1887,7 @@ void main() { expect(find.widgetWithText(TableRowInkWell, 'GitHub'), findsNothing); }); - testWidgets('DataTable set interior border test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable set interior border test', (WidgetTester tester) async { const List columns = [ DataColumn(label: Text('column1')), DataColumn(label: Text('column2')), @@ -1952,7 +1953,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/100952 - testWidgets('Do not crashes when paint borders in a narrow space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crashes when paint borders in a narrow space', (WidgetTester tester) async { const List columns = [ DataColumn(label: Text('column1')), DataColumn(label: Text('column2')), @@ -1989,7 +1990,7 @@ void main() { }); - testWidgets('DataTable clip behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable clip behavior', (WidgetTester tester) async { const Color selectedColor = Colors.green; const Color defaultColor = Colors.red; const BorderRadius borderRadius = BorderRadius.all(Radius.circular(30)); @@ -2038,7 +2039,7 @@ void main() { expect(material.borderRadius, borderRadius); }); - testWidgets('DataTable dataRowMinHeight smaller or equal dataRowMaxHeight validation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable dataRowMinHeight smaller or equal dataRowMaxHeight validation', (WidgetTester tester) async { DataTable createDataTable() => DataTable( columns: const [DataColumn(label: Text('Column1'))], @@ -2051,7 +2052,7 @@ void main() { e.toString().contains('dataRowMaxHeight >= dataRowMinHeight')))); }); - testWidgets('DataTable dataRowHeight is not used together with dataRowMinHeight or dataRowMaxHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable dataRowHeight is not used together with dataRowMinHeight or dataRowMaxHeight', (WidgetTester tester) async { DataTable createDataTable({double? dataRowHeight, double? dataRowMinHeight, double? dataRowMaxHeight}) => DataTable( columns: const [DataColumn(label: Text('Column1'))], @@ -2072,7 +2073,7 @@ void main() { }); group('TableRowInkWell', () { - testWidgets('can handle secondary taps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can handle secondary taps', (WidgetTester tester) async { bool secondaryTapped = false; bool secondaryTappedDown = false; @@ -2116,7 +2117,7 @@ void main() { }); }); - testWidgets('Heading cell cursor resolves MaterialStateMouseCursor correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heading cell cursor resolves MaterialStateMouseCursor correctly', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -2177,7 +2178,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden); }); - testWidgets('DataRow cursor resolves MaterialStateMouseCursor correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataRow cursor resolves MaterialStateMouseCursor correctly', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -2238,7 +2239,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.copy); }); - testWidgets("DataRow cursor doesn't update checkbox cursor", (WidgetTester tester) async { + testWidgetsWithLeakTracking("DataRow cursor doesn't update checkbox cursor", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/data_table_theme_test.dart b/packages/flutter/test/material/data_table_theme_test.dart index e08169cdd4651..0f922cb0a4801 100644 --- a/packages/flutter/test/material/data_table_theme_test.dart +++ b/packages/flutter/test/material/data_table_theme_test.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('DataTableThemeData copyWith, ==, hashCode basics', () { expect(const DataTableThemeData(), const DataTableThemeData().copyWith()); @@ -64,7 +66,7 @@ void main() { expect(theme.data.dataRowCursor, null); }); - testWidgets('Default DataTableThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default DataTableThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DataTableThemeData().debugFillProperties(builder); @@ -76,7 +78,7 @@ void main() { expect(description, []); }); - testWidgets('DataTableThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTableThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); DataTableThemeData( decoration: const BoxDecoration(color: Color(0xfffffff0)), @@ -120,7 +122,7 @@ void main() { expect(description[13], 'dataRowCursor: MaterialStatePropertyAll(SystemMouseCursor(forbidden))'); }); - testWidgets('DataTable is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable is themeable', (WidgetTester tester) async { const BoxDecoration decoration = BoxDecoration(color: Color(0xfffffff0)); const MaterialStateProperty dataRowColor = MaterialStatePropertyAll(Color(0xfffffff1)); const double minMaxDataRowHeight = 41.0; @@ -207,7 +209,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden); }); - testWidgets('DataTable is themeable - separate test for deprecated dataRowHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable is themeable - separate test for deprecated dataRowHeight', (WidgetTester tester) async { const double dataRowHeight = 51.0; await tester.pumpWidget( @@ -241,7 +243,7 @@ void main() { expect(tester.getSize(_findFirstContainerFor('Data')).height, dataRowHeight); }); - testWidgets('DataTable properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable properties are taken over the theme values', (WidgetTester tester) async { const BoxDecoration themeDecoration = BoxDecoration(color: Color(0xfffffff1)); const MaterialStateProperty themeDataRowColor = MaterialStatePropertyAll(Color(0xfffffff0)); const double minMaxThemeDataRowHeight = 50.0; @@ -354,7 +356,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), dataRowCursor.resolve({})); }); - testWidgets('DataTable properties are taken over the theme values - separate test for deprecated dataRowHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DataTable properties are taken over the theme values - separate test for deprecated dataRowHeight', (WidgetTester tester) async { const double themeDataRowHeight = 50.0; const double dataRowHeight = 51.0; @@ -390,7 +392,7 @@ void main() { expect(tester.getSize(_findFirstContainerFor('Data')).height, dataRowHeight); }); - testWidgets('Local DataTableTheme can override global DataTableTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Local DataTableTheme can override global DataTableTheme', (WidgetTester tester) async { const BoxDecoration globalThemeDecoration = BoxDecoration(color: Color(0xfffffff1)); const MaterialStateProperty globalThemeDataRowColor = MaterialStatePropertyAll(Color(0xfffffff0)); const double minMaxGlobalThemeDataRowHeight = 50.0; @@ -507,7 +509,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), localDataRowCursor.resolve({})); }); - testWidgets('Local DataTableTheme can override global DataTableTheme - separate test for deprecated dataRowHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Local DataTableTheme can override global DataTableTheme - separate test for deprecated dataRowHeight', (WidgetTester tester) async { const double globalThemeDataRowHeight = 50.0; const double localThemeDataRowHeight = 51.0; diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index 5b36a71c2bad3..d3d01556d4bae 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -6,8 +6,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('debugCheckHasMaterial control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasMaterial control test', (WidgetTester tester) async { await tester.pumpWidget(const Center(child: Chip(label: Text('label')))); final dynamic exception = tester.takeException(); expect(exception, isFlutterError); @@ -47,7 +49,7 @@ void main() { )); }); - testWidgets('debugCheckHasMaterialLocalizations control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasMaterialLocalizations control test', (WidgetTester tester) async { await tester.pumpWidget(const Center(child: BackButton())); final dynamic exception = tester.takeException(); expect(exception, isFlutterError); @@ -84,7 +86,7 @@ void main() { )); }); - testWidgets('debugCheckHasScaffold control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasScaffold control test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart b/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart index 80a82acaa25bb..d42cbc638cffe 100644 --- a/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart +++ b/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart @@ -5,10 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('can press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can press', (WidgetTester tester) async { bool pressed = false; await tester.pumpWidget( MaterialApp( @@ -29,7 +31,7 @@ void main() { expect(pressed, true); }); - testWidgets('passing null to onPressed disables the button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing null to onPressed disables the button', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Center( diff --git a/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart b/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart index 3052356febf2f..5eb0c67c549b8 100644 --- a/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart @@ -5,10 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('positions itself at the anchor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positions itself at the anchor', (WidgetTester tester) async { // An arbitrary point on the screen to position at. const Offset anchor = Offset(30.0, 40.0); diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 7e467635a6eb5..4ba0c9b5e0cdb 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; MaterialApp _buildAppWithDialog( @@ -69,7 +70,7 @@ void main() { final ThemeData material3Theme = ThemeData(useMaterial3: true, brightness: Brightness.dark); final ThemeData material2Theme = ThemeData(useMaterial3: false, brightness: Brightness.dark); - testWidgets('Dialog is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog is scrollable', (WidgetTester tester) async { bool didPressOk = false; final AlertDialog dialog = AlertDialog( content: Container( @@ -96,7 +97,7 @@ void main() { expect(didPressOk, true); }); - testWidgets('Dialog background color from AlertDialog', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog background color from AlertDialog', (WidgetTester tester) async { const Color customColor = Colors.pink; const AlertDialog dialog = AlertDialog( backgroundColor: customColor, @@ -193,7 +194,7 @@ void main() { expect(find.text(dialogTextM3), findsNothing); }); - testWidgets('Custom dialog elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom dialog elevation', (WidgetTester tester) async { const double customElevation = 12.0; const Color shadowColor = Color(0xFF000001); const Color surfaceTintColor = Color(0xFF000002); @@ -214,7 +215,7 @@ void main() { expect(materialWidget.surfaceTintColor, surfaceTintColor); }); - testWidgets('Custom Title Text Style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Title Text Style', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( @@ -231,7 +232,7 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Custom Content Text Style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Content Text Style', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( @@ -248,7 +249,7 @@ void main() { expect(content.text.style, contentTextStyle); }); - testWidgets('AlertDialog custom clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog custom clipBehavior', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( actions: [], clipBehavior: Clip.antiAlias, @@ -262,7 +263,7 @@ void main() { expect(materialWidget.clipBehavior, Clip.antiAlias); }); - testWidgets('SimpleDialog custom clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SimpleDialog custom clipBehavior', (WidgetTester tester) async { const SimpleDialog dialog = SimpleDialog( clipBehavior: Clip.antiAlias, children: [], @@ -276,7 +277,7 @@ void main() { expect(materialWidget.clipBehavior, Clip.antiAlias); }); - testWidgets('Custom dialog shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom dialog shape', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -292,7 +293,7 @@ void main() { expect(materialWidget.shape, customBorder); }); - testWidgets('Null dialog shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Null dialog shape', (WidgetTester tester) async { final ThemeData theme = ThemeData(); const AlertDialog dialog = AlertDialog( actions: [ ], @@ -306,7 +307,7 @@ void main() { expect(materialWidget.shape, theme.useMaterial3 ? _defaultM3DialogShape : _defaultM2DialogShape); }); - testWidgets('Rectangular dialog shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rectangular dialog shape', (WidgetTester tester) async { const ShapeBorder customBorder = Border(); const AlertDialog dialog = AlertDialog( actions: [ ], @@ -321,7 +322,7 @@ void main() { expect(materialWidget.shape, customBorder); }); - testWidgets('Custom dialog alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom dialog alignment', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( actions: [ ], alignment: Alignment.bottomLeft, @@ -338,7 +339,7 @@ void main() { expect(bottomLeft.dy, 576.0); }); - testWidgets('Simple dialog control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simple dialog control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -381,7 +382,7 @@ void main() { expect(await result, equals(42)); }); - testWidgets('Can show dialog using navigator global key', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can show dialog using navigator global key', (WidgetTester tester) async { final GlobalKey navigator = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -421,7 +422,7 @@ void main() { expect(await result, equals(42)); }); - testWidgets('Custom padding on SimpleDialogOption', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom padding on SimpleDialogOption', (WidgetTester tester) async { const EdgeInsets customPadding = EdgeInsets.fromLTRB(4, 10, 8, 6); final SimpleDialog dialog = SimpleDialog( title: const Text('Title'), @@ -508,7 +509,7 @@ void main() { }); - testWidgets('Barrier color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier color', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Center(child: Text('Test')), @@ -539,7 +540,7 @@ void main() { expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); }); - testWidgets('Dialog hides underlying semantics tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog hides underlying semantics tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const String buttonText = 'A button covered by dialog overlay'; await tester.pumpWidget( @@ -575,7 +576,7 @@ void main() { semantics.dispose(); }); - testWidgets('AlertDialog.actionsPadding defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog.actionsPadding defaults', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( title: const Text('title'), content: const Text('content'), @@ -608,7 +609,7 @@ void main() { expect(actionsSize.width, dialogSize.width); }); - testWidgets('AlertDialog.actionsPadding surrounds actions with padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog.actionsPadding surrounds actions with padding', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( title: const Text('title'), content: const Text('content'), @@ -742,7 +743,7 @@ void main() { ); // right }); - testWidgets('AlertDialog.buttonPadding custom values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog.buttonPadding custom values', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -944,7 +945,7 @@ void main() { ]; for (final double textScaleFactor in textScaleFactors) { - testWidgets('AlertDialog padding is correct when only icon and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog padding is correct when only icon and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( icon: icon, actions: actions, @@ -996,7 +997,7 @@ void main() { ); }); - testWidgets('AlertDialog padding is correct when only icon, title and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog padding is correct when only icon, title and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( icon: icon, title: title, @@ -1068,7 +1069,7 @@ void main() { }); for (final bool isM3 in [true, false]) { - testWidgets('AlertDialog padding is correct when only icon, content and actions are specified [textScaleFactor]=$textScaleFactor [isM3]=$isM3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog padding is correct when only icon, content and actions are specified [textScaleFactor]=$textScaleFactor [isM3]=$isM3', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( icon: icon, content: content, @@ -1140,7 +1141,7 @@ void main() { }); } - testWidgets('AlertDialog padding is correct when only title and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog padding is correct when only title and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( title: title, actions: actions, @@ -1192,7 +1193,7 @@ void main() { ); }); - testWidgets('AlertDialog padding is correct when only content and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog padding is correct when only content and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( content: content, actions: actions, @@ -1244,7 +1245,7 @@ void main() { ); }); - testWidgets('AlertDialog padding is correct when title, content, and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog padding is correct when title, content, and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog( title: title, content: content, @@ -1315,7 +1316,7 @@ void main() { ); }); - testWidgets('SimpleDialog padding is correct when only children are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SimpleDialog padding is correct when only children are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final SimpleDialog dialog = SimpleDialog( children: children, ); @@ -1348,7 +1349,7 @@ void main() { ); }); - testWidgets('SimpleDialog padding is correct when title and children are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SimpleDialog padding is correct when title and children are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async { final SimpleDialog dialog = SimpleDialog( title: title, children: children, @@ -1402,7 +1403,7 @@ void main() { } }); - testWidgets('Dialogs can set the vertical direction of overflowing actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialogs can set the vertical direction of overflowing actions', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -1437,7 +1438,7 @@ void main() { expect(buttonTwoRect.bottom, lessThanOrEqualTo(buttonOneRect.top)); }); - testWidgets('Dialogs have no spacing by default for overflowing actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialogs have no spacing by default for overflowing actions', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -1470,7 +1471,7 @@ void main() { expect(buttonOneRect.bottom, buttonTwoRect.top); }); - testWidgets('Dialogs can set the button spacing of overflowing actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialogs can set the button spacing of overflowing actions', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -1504,7 +1505,7 @@ void main() { expect(buttonOneRect.bottom, buttonTwoRect.top - 10.0); }); - testWidgets('Dialogs can set the alignment of the OverflowBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialogs can set the alignment of the OverflowBar', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -1538,7 +1539,7 @@ void main() { expect(buttonOneRect.center.dx, buttonTwoRect.center.dx); }); - testWidgets('Dialogs removes MediaQuery padding and view insets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialogs removes MediaQuery padding and view insets', (WidgetTester tester) async { late BuildContext outerContext; late BuildContext routeContext; late BuildContext dialogContext; @@ -1593,7 +1594,7 @@ void main() { expect(MediaQuery.of(dialogContext).viewInsets, EdgeInsets.zero); }); - testWidgets('Dialog widget insets by viewInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog widget insets by viewInsets', (WidgetTester tester) async { await tester.pumpWidget( const MediaQuery( data: MediaQueryData( @@ -1627,7 +1628,7 @@ void main() { ); }); - testWidgets('Dialog insetPadding added to outside of dialog', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog insetPadding added to outside of dialog', (WidgetTester tester) async { // The default testing screen (800, 600) const Rect screenRect = Rect.fromLTRB(0.0, 0.0, 800.0, 600.0); @@ -1667,7 +1668,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/78229. - testWidgets('AlertDialog has correct semantics for content in iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog has correct semantics for content in iOS', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1732,7 +1733,7 @@ void main() { semantics.dispose(); }); - testWidgets('AlertDialog widget always contains alert route semantics for android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog widget always contains alert route semantics for android', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1788,7 +1789,7 @@ void main() { semantics.dispose(); }); - testWidgets('SimpleDialog does not introduce additional node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SimpleDialog does not introduce additional node', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1831,7 +1832,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/78229. - testWidgets('SimpleDialog has correct semantics for title in iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SimpleDialog has correct semantics for title in iOS', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2113,7 +2114,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('showDialog uses root navigator by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showDialog uses root navigator by default', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); final DialogObserver nestedObserver = DialogObserver(); @@ -2148,7 +2149,7 @@ void main() { expect(nestedObserver.dialogCount, 0); }); - testWidgets('showDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); final DialogObserver nestedObserver = DialogObserver(); @@ -2184,7 +2185,7 @@ void main() { expect(nestedObserver.dialogCount, 1); }); - testWidgets('showDialog throws a friendly user message when context is not active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showDialog throws a friendly user message when context is not active', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/12467 await tester.pumpWidget( const MaterialApp( @@ -2220,7 +2221,7 @@ void main() { }); group('showDialog avoids overlapping display features', () { - testWidgets('positioning with anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with anchorPoint', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -2258,7 +2259,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('positioning with Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with Directionality', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -2298,7 +2299,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('positioning by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -2337,7 +2338,7 @@ void main() { }); group('AlertDialog.scrollable: ', () { - testWidgets('Title is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Title is scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final AlertDialog dialog = AlertDialog( title: Container( @@ -2357,7 +2358,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0))); }); - testWidgets('Content is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Content is scrollable', (WidgetTester tester) async { final Key contentKey = UniqueKey(); final AlertDialog dialog = AlertDialog( content: Container( @@ -2377,7 +2378,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0))); }); - testWidgets('Title and content are scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Title and content are scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final Key contentKey = UniqueKey(); final AlertDialog dialog = AlertDialog( @@ -2470,7 +2471,7 @@ void main() { expect(currentRouteSetting.name, '/'); }); - testWidgets('showDialog - custom barrierLabel', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showDialog - custom barrierLabel', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2510,7 +2511,7 @@ void main() { semantics.dispose(); }); - testWidgets('DialogRoute is state restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DialogRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -2540,7 +2541,7 @@ void main() { expect(find.byType(AlertDialog), findsOneWidget); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('AlertDialog.actionsAlignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog.actionsAlignment', (WidgetTester tester) async { final Key actionKey = UniqueKey(); Widget buildFrame(MainAxisAlignment? alignment) { @@ -2593,7 +2594,7 @@ void main() { expect(tester.getTopRight(find.byKey(actionKey)).dx, (800 - 20) / 2 + 20); }); - testWidgets('Uses closed loop focus traversal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses closed loop focus traversal', (WidgetTester tester) async { final FocusNode okNode = FocusNode(); final FocusNode cancelNode = FocusNode(); @@ -2763,7 +2764,7 @@ void main() { expect(find.text('Dialog2'), findsOneWidget); }); - testWidgets('Uses open focus traversal when overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses open focus traversal when overridden', (WidgetTester tester) async { final FocusNode okNode = FocusNode(); final FocusNode cancelNode = FocusNode(); diff --git a/packages/flutter/test/material/drawer_button_test.dart b/packages/flutter/test/material/drawer_button_test.dart index 2979788ed5015..872e633e7b1e6 100644 --- a/packages/flutter/test/material/drawer_button_test.dart +++ b/packages/flutter/test/material/drawer_button_test.dart @@ -6,8 +6,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('DrawerButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -28,7 +30,7 @@ void main() { expect(find.byType(Drawer), findsOneWidget); }); - testWidgets('DrawerButton onPressed overrides default end drawer open behaviour', + testWidgetsWithLeakTracking('DrawerButton onPressed overrides default end drawer open behaviour', (WidgetTester tester) async { bool customCallbackWasCalled = false; await tester.pumpWidget( @@ -57,7 +59,7 @@ void main() { expect(customCallbackWasCalled, true); }); - testWidgets('DrawerButton icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerButton icon', (WidgetTester tester) async { final Key androidKey = UniqueKey(); final Key iOSKey = UniqueKey(); final Key linuxKey = UniqueKey(); @@ -111,7 +113,7 @@ void main() { expect(windowsIcon.icon == androidIcon.icon, isTrue); }); - testWidgets('DrawerButton color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerButton color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -132,7 +134,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('DrawerButton semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerButton semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const MaterialApp( @@ -169,7 +171,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('EndDrawerButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EndDrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -190,7 +192,7 @@ void main() { expect(find.byType(Drawer), findsOneWidget); }); - testWidgets('EndDrawerButton semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EndDrawerButton semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const MaterialApp( @@ -226,7 +228,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('EndDrawerButton color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EndDrawerButton color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -247,7 +249,7 @@ void main() { expect(iconText.text.style!.color, Colors.red); }); - testWidgets('EndDrawerButton onPressed overrides default end drawer open behaviour', + testWidgetsWithLeakTracking('EndDrawerButton onPressed overrides default end drawer open behaviour', (WidgetTester tester) async { bool customCallbackWasCalled = false; await tester.pumpWidget( diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index c46c560e7e3ae..b4e067f08f9b8 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -7,6 +7,7 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; const List menuItems = ['one', 'two', 'three', 'four']; @@ -200,7 +201,7 @@ void main() { expect(hintEmptyLabel, oneValueLabel); }); - testWidgets('label position test - show disabledHint: disable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: disable', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -238,7 +239,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -263,7 +264,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -313,7 +314,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -351,7 +352,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 24.0)); }); - testWidgets('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { const int value = 1; await tester.pumpWidget( @@ -391,7 +392,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/82910 - testWidgets('null value test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null value test', (WidgetTester tester) async { int? value = 1; await tester.pumpWidget( @@ -492,7 +493,7 @@ void main() { expect(value, equals('three')); }); - testWidgets('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); // There shouldn't be overflow when expanded although list contains longer items. @@ -527,7 +528,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -567,7 +568,7 @@ void main() { } }); - testWidgets('DropdownButtonFormField with isDense:true does not clip large scale text', + testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true does not clip large scale text', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -606,7 +607,7 @@ void main() { expect(box.size.height, 72.0); }); - testWidgets('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46844 final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -637,7 +638,7 @@ void main() { expect(box.size.height, 48.0); }); - testWidgets('DropdownButtonFormField - custom text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - custom text style', (WidgetTester tester) async { const String value = 'foo'; final UniqueKey itemKey = UniqueKey(); @@ -675,7 +676,7 @@ void main() { expect(richText.text.style!.fontSize, 20.0); }); - testWidgets('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -698,7 +699,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgets( + testWidgetsWithLeakTracking( 'DropdownButtonFormField - hint displays when the items list is ' 'empty, items is null, and disabledHint is null', (WidgetTester tester) async { @@ -722,7 +723,7 @@ void main() { }, ); - testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -742,7 +743,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -762,7 +763,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items, ValueChanged? onChanged }) { @@ -780,7 +781,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items}) { @@ -805,7 +806,7 @@ void main() { expect(enabledHintBox.size, equals(disabledHintBox.size)); }); - testWidgets('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { final Key iconKey = UniqueKey(); final Icon customIcon = Icon(Icons.assessment, key: iconKey); @@ -838,7 +839,7 @@ void main() { expect(disabledRichText.text.style!.color, Colors.orange); }); - testWidgets('DropdownButtonFormField - default elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - default elevation', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); debugDisableShadows = false; await tester.pumpWidget(buildFormFrame( @@ -895,7 +896,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'c'] .map>((String value) { return DropdownMenuItem( @@ -924,7 +925,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'd'] .map>((String value) { return DropdownMenuItem( @@ -1089,7 +1090,7 @@ void main() { expect(find.text(currentValue), findsOneWidget); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -1118,7 +1119,7 @@ void main() { expect(validateCalled, 1); }); - testWidgets('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { await tester.pumpWidget(buildFormFrame( buttonAlignment: AlignmentDirectional.center, items: ['one'], diff --git a/packages/flutter/test/material/dropdown_menu_theme_test.dart b/packages/flutter/test/material/dropdown_menu_theme_test.dart index e91f3a3959a9a..dcfd4ff75e45f 100644 --- a/packages/flutter/test/material/dropdown_menu_theme_test.dart +++ b/packages/flutter/test/material/dropdown_menu_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('DropdownMenuThemeData copyWith, ==, hashCode basics', () { expect(const DropdownMenuThemeData(), const DropdownMenuThemeData().copyWith()); @@ -30,7 +32,7 @@ void main() { expect(identical(DropdownMenuThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default DropdownMenuThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default DropdownMenuThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DropdownMenuThemeData().debugFillProperties(builder); @@ -42,7 +44,7 @@ void main() { expect(description, []); }); - testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -99,7 +101,7 @@ void main() { expect(material.textStyle?.color, themeData.colorScheme.onSurface); }); - testWidgets('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( dropdownMenuTheme: DropdownMenuThemeData( textStyle: TextStyle( @@ -178,7 +180,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, @@ -281,7 +283,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index 6c9cc205a54fa..ae41aa252e855 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -8,11 +8,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('ElevatedButton, ElevatedButton.icon defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton, ElevatedButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: colorScheme); final bool material3 = theme.useMaterial3; @@ -200,7 +201,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('ElevatedButton default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -261,7 +262,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); }); - testWidgets('ElevatedButton uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -337,7 +338,7 @@ void main() { }); - testWidgets('ElevatedButton uses stateful color for icon color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton uses stateful color for icon color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final Key buttonKey = UniqueKey(); @@ -412,7 +413,7 @@ void main() { expect(iconColor(), pressedColor); }); - testWidgets('ElevatedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { bool wasPressed; Finder elevatedButton; @@ -455,7 +456,7 @@ void main() { expect(tester.widget(elevatedButton).enabled, false); }); - testWidgets('ElevatedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -486,7 +487,7 @@ void main() { expect(didLongPressButton, isTrue); }); - testWidgets("ElevatedButton response doesn't hover when disabled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ElevatedButton response doesn't hover when disabled", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'ElevatedButton Focus'); final GlobalKey childKey = GlobalKey(); @@ -536,7 +537,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('disabled and hovered ElevatedButton responds to mouse-exit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled and hovered ElevatedButton responds to mouse-exit', (WidgetTester tester) async { int onHoverCount = 0; late bool hover; @@ -598,7 +599,7 @@ void main() { expect(hover, false); }); - testWidgets('Can set ElevatedButton focus and Can set unFocus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set ElevatedButton focus and Can set unFocus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'ElevatedButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -627,7 +628,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('When ElevatedButton disable, Can not set ElevatedButton focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When ElevatedButton disable, Can not set ElevatedButton focus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'ElevatedButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -650,7 +651,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('Does ElevatedButton work with hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does ElevatedButton work with hover', (WidgetTester tester) async { const Color hoverColor = Color(0xff001122); await tester.pumpWidget( @@ -677,7 +678,7 @@ void main() { expect(inkFeatures, paints..rect(color: hoverColor)); }); - testWidgets('Does ElevatedButton work with focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does ElevatedButton work with focus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); final FocusNode focusNode = FocusNode(debugLabel: 'ElevatedButton Node'); @@ -705,7 +706,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('Does ElevatedButton work with autofocus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does ElevatedButton work with autofocus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -735,7 +736,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('Does ElevatedButton contribute semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does ElevatedButton contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Theme( @@ -783,7 +784,7 @@ void main() { semantics.dispose(); }); - testWidgets('ElevatedButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { const ButtonStyle style = ButtonStyle( // Specifying minimumSize to mimic the original minimumSize for // RaisedButton so that the corresponding button size matches @@ -817,7 +818,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); }); - testWidgets('ElevatedButton has no clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton has no clip by default', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -834,7 +835,7 @@ void main() { ); }); - testWidgets('ElevatedButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key childKey = Key('test child'); @@ -903,7 +904,7 @@ void main() { expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); }); - testWidgets('ElevatedButton.icon responds to applied padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton.icon responds to applied padding', (WidgetTester tester) async { const Key buttonKey = Key('test'); const Key labelKey = Key('label'); await tester.pumpWidget( @@ -1030,7 +1031,7 @@ void main() { if (textDirection == TextDirection.rtl) 'RTL', ].join(', '); - testWidgets(testName, (WidgetTester tester) async { + testWidgetsWithLeakTracking(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1172,7 +1173,7 @@ void main() { } }); - testWidgets('Override ElevatedButton default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override ElevatedButton default padding', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(colorScheme: const ColorScheme.light()), @@ -1206,7 +1207,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.all(22)); }); - testWidgets('M3 ElevatedButton has correct padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 ElevatedButton has correct padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1232,7 +1233,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.symmetric(horizontal: 24)); }); - testWidgets('M3 ElevatedButton.icon has correct padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 ElevatedButton.icon has correct padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1259,7 +1260,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 24.0, 0.0)); }); - testWidgets('Elevated buttons animate elevation before color on disable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Elevated buttons animate elevation before color on disable', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/387 const ColorScheme colorScheme = ColorScheme.light(); @@ -1306,7 +1307,7 @@ void main() { expect(physicalShape().color, disabledBackgroundColor); }); - testWidgets('By default, ElevatedButton shape outline is defined by shape.side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('By default, ElevatedButton shape outline is defined by shape.side', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/69544 const Color borderColor = Color(0xff4caf50); @@ -1337,7 +1338,7 @@ void main() { ); }); - testWidgets('Fixed size ElevatedButtons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size ElevatedButtons', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1370,7 +1371,7 @@ void main() { expect(tester.getSize(find.widgetWithText(ElevatedButton, 'wx200')).height, 200); }); - testWidgets('ElevatedButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) { return MaterialApp( home: Scaffold( @@ -1410,7 +1411,7 @@ void main() { } }); - testWidgets('ElevatedButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -1437,7 +1438,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('ElevatedButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( @@ -1459,7 +1460,7 @@ void main() { expect(buttonInkWell.splashFactory, equals(InkRipple.splashFactory)); }, variant: TargetPlatformVariant.all()); - testWidgets('ElevatedButton.icon does not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton.icon does not overflow', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/77815 await tester.pumpWidget( MaterialApp( @@ -1480,7 +1481,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('ElevatedButton.icon icon,label layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton.icon icon,label layout', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); final Key iconKey = UniqueKey(); final Key labelKey = UniqueKey(); @@ -1517,7 +1518,7 @@ void main() { expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0)); }); - testWidgets('ElevatedButton maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton maximumSize', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); @@ -1559,7 +1560,7 @@ void main() { expect(tester.getSize(find.byKey(key1)), const Size(104.0, 224.0)); }); - testWidgets('Fixed size ElevatedButton, same as minimumSize == maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size ElevatedButton, same as minimumSize == maximumSize', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1589,7 +1590,7 @@ void main() { expect(tester.getSize(find.widgetWithText(ElevatedButton, '200,200')), const Size(200, 200)); }); - testWidgets('ElevatedButton changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1667,7 +1668,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1690,7 +1691,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('Ink Response shape matches Material shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ink Response shape matches Material shape', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/91844 Widget buildFrame({BorderSide? side}) { @@ -1735,7 +1736,7 @@ void main() { ); }); - testWidgets('ElevatedButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1865,15 +1866,15 @@ void main() { await gesture.removePointer(); } - testWidgets('ElevatedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('ElevatedButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled ElevatedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled ElevatedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/elevated_button_theme_test.dart b/packages/flutter/test/material/elevated_button_theme_test.dart index 1957b7463874e..449da915d49a1 100644 --- a/packages/flutter/test/material/elevated_button_theme_test.dart +++ b/packages/flutter/test/material/elevated_button_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('ElevatedButtonThemeData lerp special cases', () { expect(ElevatedButtonThemeData.lerp(null, null, 0), null); @@ -12,7 +14,7 @@ void main() { expect(identical(ElevatedButtonThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Material3: Passing no ElevatedButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: Passing no ElevatedButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -49,7 +51,7 @@ void main() { expect(align.alignment, Alignment.center); }); - testWidgets('Material2: Passing no ElevatedButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: Passing no ElevatedButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -189,19 +191,19 @@ void main() { expect(align.alignment, alignment); } - testWidgets('Button style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(themeStyle: style)); await tester.pumpAndSettle(); checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallStyle: style)); await tester.pumpAndSettle(); checkButton(tester); @@ -209,26 +211,26 @@ void main() { // Same as the previous tests with empty ButtonStyle's instead of null. - testWidgets('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style, themeStyle: const ButtonStyle(), overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), themeStyle: style, overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), overallStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); }); - testWidgets('Material 3: Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material 3: Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); @@ -299,7 +301,7 @@ void main() { expect(material.shadowColor, shadowColor); }); - testWidgets('Material 2: Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material 2: Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); diff --git a/packages/flutter/test/material/expansion_panel_test.dart b/packages/flutter/test/material/expansion_panel_test.dart index 7c2fc32a49bd9..0f3c1e6e14496 100644 --- a/packages/flutter/test/material/expansion_panel_test.dart +++ b/packages/flutter/test/material/expansion_panel_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + class SimpleExpansionPanelListTestWidget extends StatefulWidget { const SimpleExpansionPanelListTestWidget({ super.key, @@ -112,7 +114,7 @@ class ExpansionPanelListSemanticsTestState extends State demoItemsRadio = [ ExpansionPanelRadio( headerBuilder: (BuildContext context, bool isExpanded) { @@ -498,7 +500,7 @@ void main() { expect(find.text('F'), findsNothing); }); - testWidgets('Radio mode calls expansionCallback once if other panels closed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio mode calls expansionCallback once if other panels closed', (WidgetTester tester) async { final List demoItemsRadio = [ ExpansionPanelRadio( headerBuilder: (BuildContext context, bool isExpanded) { @@ -569,7 +571,7 @@ void main() { expect(callbackHistory.last['isExpanded'], equals(false)); }); - testWidgets('Radio mode calls expansionCallback twice if other panel open prior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio mode calls expansionCallback twice if other panel open prior', (WidgetTester tester) async { final List demoItemsRadio = [ ExpansionPanelRadio( headerBuilder: (BuildContext context, bool isExpanded) { @@ -649,7 +651,7 @@ void main() { expect(callbackResults['isExpanded'], equals(true)); }); - testWidgets('ExpansionPanelList.radio callback displays true or false based on the visibility of a list item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList.radio callback displays true or false based on the visibility of a list item', (WidgetTester tester) async { late int lastExpanded; bool topElementExpanded = false; bool bottomElementExpanded = false; @@ -744,7 +746,7 @@ void main() { expect(find.text('D'), findsNothing); }); - testWidgets( + testWidgetsWithLeakTracking( 'didUpdateWidget accounts for toggling between ExpansionPanelList ' 'and ExpansionPaneList.radio', (WidgetTester tester) async { @@ -998,7 +1000,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Panel header has semantics, canTapOnHeader = false ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Panel header has semantics, canTapOnHeader = false ', (WidgetTester tester) async { const Key expandedKey = Key('expanded'); const Key collapsedKey = Key('collapsed'); const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations(); @@ -1083,7 +1085,7 @@ void main() { handle.dispose(); }); - testWidgets('Panel header has semantics, canTapOnHeader = true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Panel header has semantics, canTapOnHeader = true', (WidgetTester tester) async { const Key expandedKey = Key('expanded'); const Key collapsedKey = Key('collapsed'); final SemanticsHandle handle = tester.ensureSemantics(); @@ -1136,7 +1138,7 @@ void main() { handle.dispose(); }); - testWidgets('Ensure canTapOnHeader is false by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ensure canTapOnHeader is false by default', (WidgetTester tester) async { final ExpansionPanel expansionPanel = ExpansionPanel( headerBuilder: (BuildContext context, bool isExpanded) => const Text('Demo'), body: const SizedBox(height: 100.0), @@ -1145,7 +1147,7 @@ void main() { expect(expansionPanel.canTapOnHeader, isFalse); }); - testWidgets('Toggle ExpansionPanelRadio when tapping header and canTapOnHeader is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggle ExpansionPanelRadio when tapping header and canTapOnHeader is true', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); const Key secondPanelKey = Key('secondPanelKey'); @@ -1205,7 +1207,7 @@ void main() { expect(find.text('D'), findsOneWidget); }); - testWidgets('Toggle ExpansionPanel when tapping header and canTapOnHeader is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggle ExpansionPanel when tapping header and canTapOnHeader is true', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); const Key secondPanelKey = Key('secondPanelKey'); @@ -1264,7 +1266,7 @@ void main() { expect(find.text('D'), findsNothing); }); - testWidgets('Do not toggle ExpansionPanel when tapping header and canTapOnHeader is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not toggle ExpansionPanel when tapping header and canTapOnHeader is false', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); const Key secondPanelKey = Key('secondPanelKey'); @@ -1304,7 +1306,7 @@ void main() { expect(find.text('D'), findsNothing); }); - testWidgets('Do not toggle ExpansionPanelRadio when tapping header and canTapOnHeader is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not toggle ExpansionPanelRadio when tapping header and canTapOnHeader is false', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); const Key secondPanelKey = Key('secondPanelKey'); @@ -1362,7 +1364,7 @@ void main() { expect(find.text('D'), findsNothing); }); - testWidgets('Correct default header padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Correct default header padding', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); await tester.pumpWidget( @@ -1400,7 +1402,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/5848. - testWidgets('The AnimatedContainer and IconButton have the same height of 48px', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The AnimatedContainer and IconButton have the same height of 48px', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); await tester.pumpWidget( @@ -1425,7 +1427,7 @@ void main() { expect(boxOfContainer.size.height, equals(48.0)); // Header should have 48px height according to Material 2 Design spec. }); - testWidgets("The AnimatedContainer's height is at least kMinInteractiveDimension", (WidgetTester tester) async { + testWidgetsWithLeakTracking("The AnimatedContainer's height is at least kMinInteractiveDimension", (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); await tester.pumpWidget( @@ -1448,7 +1450,7 @@ void main() { expect(box.size.height, greaterThanOrEqualTo(kMinInteractiveDimension)); }); - testWidgets('Correct custom header padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Correct custom header padding', (WidgetTester tester) async { const Key firstPanelKey = Key('firstPanelKey'); await tester.pumpWidget( @@ -1486,7 +1488,7 @@ void main() { expect(box.size.width, equals(744.0)); }); - testWidgets('ExpansionPanelList respects dividerColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList respects dividerColor', (WidgetTester tester) async { const Color dividerColor = Colors.red; await tester.pumpWidget(const MaterialApp( home: SingleChildScrollView( @@ -1503,7 +1505,7 @@ void main() { expect(decoration.border!.top.color, dividerColor); }); - testWidgets('ExpansionPanelList.radio respects DividerColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList.radio respects DividerColor', (WidgetTester tester) async { const Color dividerColor = Colors.red; await tester.pumpWidget(MaterialApp( home: SingleChildScrollView( @@ -1536,7 +1538,7 @@ void main() { expect(boxDecoration.border!.top.color, dividerColor); }); - testWidgets('ExpansionPanelList respects expandIconColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList respects expandIconColor', (WidgetTester tester) async { const Color expandIconColor = Colors.blue; await tester.pumpWidget(MaterialApp( home: SingleChildScrollView( @@ -1560,7 +1562,7 @@ void main() { expect(expandIcon.color, expandIconColor); }); - testWidgets('ExpansionPanelList.radio respects expandIconColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList.radio respects expandIconColor', (WidgetTester tester) async { const Color expandIconColor = Colors.blue; await tester.pumpWidget(MaterialApp( home: SingleChildScrollView( @@ -1627,7 +1629,7 @@ void main() { expect(tester.widget(find.byType(MergeableMaterial)).elevation, elevation); }); - testWidgets('Using a value non defined value throws assertion error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Using a value non defined value throws assertion error', (WidgetTester tester) async { // It should throw an AssertionError since, 19 is not defined in kElevationToShadow. await tester.pumpWidget(const MaterialApp( @@ -1646,7 +1648,7 @@ void main() { )); }); - testWidgets('ExpansionPanel.panelColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanel.panelColor test', (WidgetTester tester) async { const Color firstPanelColor = Colors.red; const Color secondPanelColor = Colors.brown; @@ -1682,7 +1684,7 @@ void main() { expect((mergeableMaterial.children.last as MaterialSlice).color, secondPanelColor); }); - testWidgets('ExpansionPanelRadio.backgroundColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelRadio.backgroundColor test', (WidgetTester tester) async { const Color firstPanelColor = Colors.red; const Color secondPanelColor = Colors.brown; @@ -1717,7 +1719,7 @@ void main() { expect((mergeableMaterial.children.last as MaterialSlice).color, secondPanelColor); }); - testWidgets('ExpansionPanelList.materialGapSize defaults to 16.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList.materialGapSize defaults to 16.0', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SingleChildScrollView( child: ExpansionPanelList( @@ -1738,7 +1740,7 @@ void main() { expect(expansionPanelList.materialGapSize, 16); }); - testWidgets('ExpansionPanelList respects materialGapSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionPanelList respects materialGapSize', (WidgetTester tester) async { Widget buildWidgetForTest({double materialGapSize = 16}) { return MaterialApp( home: SingleChildScrollView( diff --git a/packages/flutter/test/material/expansion_tile_test.dart b/packages/flutter/test/material/expansion_tile_test.dart index 9d6fba1a42058..67634911786ec 100644 --- a/packages/flutter/test/material/expansion_tile_test.dart +++ b/packages/flutter/test/material/expansion_tile_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + class TestIcon extends StatefulWidget { const TestIcon({super.key}); @@ -48,7 +50,7 @@ void main() { const Color unselectedWidgetColor = Colors.black54; const Color headerColor = Colors.black45; - testWidgets('ExpansionTile initial state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile initial state', (WidgetTester tester) async { final Key topKey = UniqueKey(); const Key expandedKey = PageStorageKey('expanded'); const Key collapsedKey = PageStorageKey('collapsed'); @@ -158,7 +160,7 @@ void main() { expect((collapsedContainerDecoration.shape as Border).bottom.color, dividerColor); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('ExpansionTile Theme dependencies', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile Theme dependencies', (WidgetTester tester) async { final Key expandedTitleKey = UniqueKey(); final Key collapsedTitleKey = UniqueKey(); final Key expandedIconKey = UniqueKey(); @@ -217,7 +219,7 @@ void main() { expect(iconColor(collapsedIconKey), foregroundColor); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('ExpansionTile subtitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile subtitle', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -233,7 +235,7 @@ void main() { expect(find.text('Subtitle'), findsOneWidget); }); - testWidgets('ExpansionTile maintainState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile maintainState', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -271,7 +273,7 @@ void main() { expect(find.text('Discarding State'), findsNothing); }); - testWidgets('ExpansionTile padding test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile padding test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: Center( @@ -298,7 +300,7 @@ void main() { expect(listTileRect.bottom, tallerWidget.bottom + remainingHeight / 2 + 10); }); - testWidgets('ExpansionTile expandedAlignment test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile expandedAlignment test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: Center( @@ -327,7 +329,7 @@ void main() { expect(columnRect.right, 100.0); }); - testWidgets('ExpansionTile expandedCrossAxisAlignment test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile expandedCrossAxisAlignment test', (WidgetTester tester) async { const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -371,7 +373,7 @@ void main() { expect(child1Rect.left, 700.0); }); - testWidgets('CrossAxisAlignment.baseline is not allowed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CrossAxisAlignment.baseline is not allowed', (WidgetTester tester) async { expect( () { MaterialApp( @@ -391,7 +393,7 @@ void main() { ); }); - testWidgets('expandedCrossAxisAlignment and expandedAlignment default values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('expandedCrossAxisAlignment and expandedAlignment default values', (WidgetTester tester) async { const Key child1Key = Key('child1'); await tester.pumpWidget(const MaterialApp( @@ -426,7 +428,7 @@ void main() { }); - testWidgets('childrenPadding default value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('childrenPadding default value', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -456,7 +458,7 @@ void main() { expect(columnRect.bottom, paddingRect.bottom); }); - testWidgets('ExpansionTile childrenPadding test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile childrenPadding test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -487,7 +489,7 @@ void main() { expect(columnRect.bottom, paddingRect.bottom - 4); }); - testWidgets('ExpansionTile.collapsedBackgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile.collapsedBackgroundColor', (WidgetTester tester) async { const Key expansionTileKey = Key('expansionTileKey'); const Color backgroundColor = Colors.red; const Color collapsedBackgroundColor = Colors.brown; @@ -524,7 +526,7 @@ void main() { expect(shapeDecoration.color, backgroundColor); }); - testWidgets('ExpansionTile default iconColor, textColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile default iconColor, textColor', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( @@ -553,7 +555,7 @@ void main() { expect(getTextColor(), theme.colorScheme.onSurface); }); - testWidgets('ExpansionTile iconColor, textColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile iconColor, textColor', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/78281 const Color iconColor = Color(0xff00ff00); @@ -590,7 +592,7 @@ void main() { expect(getTextColor(), textColor); }); - testWidgets('ExpansionTile Border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile Border', (WidgetTester tester) async { const Key expansionTileKey = PageStorageKey('expansionTile'); const Border collapsedShape = Border( @@ -638,7 +640,7 @@ void main() { expect(expandedContainerDecoration.shape, shape); }); - testWidgets('ExpansionTile platform controlAffinity test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile platform controlAffinity test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: ExpansionTile( @@ -652,7 +654,7 @@ void main() { expect(listTile.trailing.runtimeType, RotationTransition); }); - testWidgets('ExpansionTile trailing controlAffinity test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile trailing controlAffinity test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: ExpansionTile( @@ -667,7 +669,7 @@ void main() { expect(listTile.trailing.runtimeType, RotationTransition); }); - testWidgets('ExpansionTile leading controlAffinity test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile leading controlAffinity test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: ExpansionTile( @@ -682,7 +684,7 @@ void main() { expect(listTile.trailing, isNull); }); - testWidgets('ExpansionTile override rotating icon test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile override rotating icon test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: ExpansionTile( @@ -698,7 +700,7 @@ void main() { expect(listTile.trailing, isNull); }); - testWidgets('Nested ListTile Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested ListTile Semantics', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final SemanticsHandle handle = tester.ensureSemantics(); @@ -753,7 +755,7 @@ void main() { handle.dispose(); }); - testWidgets('ExpansionTile Semantics announcement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile Semantics announcement', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations(); await tester.pumpWidget( @@ -792,7 +794,7 @@ void main() { handle.dispose(); }); - testWidgets('Semantics with the onTapHint is an ancestor of ListTile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics with the onTapHint is an ancestor of ListTile', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/pull/121624 final SemanticsHandle handle = tester.ensureSemantics(); const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations(); @@ -844,7 +846,7 @@ void main() { handle.dispose(); }); - testWidgets('Semantics hint for iOS and macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics hint for iOS and macOS', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); const DefaultMaterialLocalizations localizations = DefaultMaterialLocalizations(); @@ -897,7 +899,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('ExpansionTile default iconColor, textColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTile default iconColor, textColor', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget(MaterialApp( @@ -927,7 +929,7 @@ void main() { }); }); - testWidgets('ExpansionTileController isExpanded, expand() and collapse()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTileController isExpanded, expand() and collapse()', (WidgetTester tester) async { final ExpansionTileController controller = ExpansionTileController(); await tester.pumpWidget(MaterialApp( @@ -955,7 +957,7 @@ void main() { expect(find.text('Child 0'), findsNothing); }); - testWidgets('Calling ExpansionTileController.expand/collapsed has no effect if it is already expanded/collapsed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Calling ExpansionTileController.expand/collapsed has no effect if it is already expanded/collapsed', (WidgetTester tester) async { final ExpansionTileController controller = ExpansionTileController(); await tester.pumpWidget(MaterialApp( @@ -991,7 +993,7 @@ void main() { expect(tester.hasRunningAnimations, isFalse); }); - testWidgets('Call to ExpansionTileController.of()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Call to ExpansionTileController.of()', (WidgetTester tester) async { final GlobalKey titleKey = GlobalKey(); final GlobalKey childKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -1015,7 +1017,7 @@ void main() { expect(controller1, controller2); }); - testWidgets('Call to ExpansionTile.maybeOf()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Call to ExpansionTile.maybeOf()', (WidgetTester tester) async { final GlobalKey titleKey = GlobalKey(); final GlobalKey nonDescendantKey = GlobalKey(); await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/expansion_tile_theme_test.dart b/packages/flutter/test/material/expansion_tile_theme_test.dart index cb29a397e5cd6..582d2486e4400 100644 --- a/packages/flutter/test/material/expansion_tile_theme_test.dart +++ b/packages/flutter/test/material/expansion_tile_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + class TestIcon extends StatefulWidget { const TestIcon({super.key}); @@ -69,7 +71,7 @@ void main() { expect(theme.clipBehavior, null); }); - testWidgets('Default ExpansionTileThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ExpansionTileThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TooltipThemeData().debugFillProperties(builder); @@ -81,7 +83,7 @@ void main() { expect(description, []); }); - testWidgets('ExpansionTileThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTileThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ExpansionTileThemeData( backgroundColor: Color(0xff000000), @@ -119,7 +121,7 @@ void main() { ]); }); - testWidgets('ExpansionTileTheme - collapsed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTileTheme - collapsed', (WidgetTester tester) async { final Key tileKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key iconKey = UniqueKey(); @@ -211,7 +213,7 @@ void main() { expect(shapeDecoration.shape, collapsedShape); }); - testWidgets('ExpansionTileTheme - expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ExpansionTileTheme - expanded', (WidgetTester tester) async { final Key tileKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key iconKey = UniqueKey(); diff --git a/packages/flutter/test/material/feedback_test.dart b/packages/flutter/test/material/feedback_test.dart index f4507df0052c8..1a1a4ef2a1b29 100644 --- a/packages/flutter/test/material/feedback_test.dart +++ b/packages/flutter/test/material/feedback_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -37,7 +38,7 @@ void main () { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('forTap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forTap', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(TestWidget( @@ -66,7 +67,7 @@ void main () { semanticsTester.dispose(); }); - testWidgets('forTap Wrapper', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forTap Wrapper', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); int callbackCount = 0; @@ -101,7 +102,7 @@ void main () { semanticsTester.dispose(); }); - testWidgets('forLongPress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forLongPress', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(TestWidget( @@ -129,7 +130,7 @@ void main () { semanticsTester.dispose(); }); - testWidgets('forLongPress Wrapper', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forLongPress Wrapper', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); int callbackCount = 0; void callback() { @@ -166,7 +167,7 @@ void main () { }); group('Feedback on iOS', () { - testWidgets('forTap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forTap', (WidgetTester tester) async { await tester.pumpWidget(Theme( data: ThemeData(platform: TargetPlatform.iOS), child: TestWidget( @@ -182,7 +183,7 @@ void main () { expect(feedback.clickSoundCount, 0); }); - testWidgets('forLongPress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forLongPress', (WidgetTester tester) async { await tester.pumpWidget(Theme( data: ThemeData(platform: TargetPlatform.iOS), child: TestWidget( diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index 5469933ba0358..d9aa268dc23f6 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; @@ -277,7 +278,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('FilledButton default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -342,7 +343,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); }); - testWidgets('FilledButton.tonal default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.tonal default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -407,7 +408,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); }); - testWidgets('FilledButton uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -483,7 +484,7 @@ void main() { }); - testWidgets('FilledButton uses stateful color for icon color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton uses stateful color for icon color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final Key buttonKey = UniqueKey(); @@ -558,7 +559,7 @@ void main() { expect(iconColor(), pressedColor); }); - testWidgets('FilledButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { bool wasPressed; Finder filledButton; @@ -601,7 +602,7 @@ void main() { expect(tester.widget(filledButton).enabled, false); }); - testWidgets('FilledButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -632,7 +633,7 @@ void main() { expect(didLongPressButton, isTrue); }); - testWidgets("FilledButton response doesn't hover when disabled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("FilledButton response doesn't hover when disabled", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'FilledButton Focus'); final GlobalKey childKey = GlobalKey(); @@ -682,7 +683,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('disabled and hovered FilledButton responds to mouse-exit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled and hovered FilledButton responds to mouse-exit', (WidgetTester tester) async { int onHoverCount = 0; late bool hover; @@ -744,7 +745,7 @@ void main() { expect(hover, false); }); - testWidgets('Can set FilledButton focus and Can set unFocus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set FilledButton focus and Can set unFocus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'FilledButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -773,7 +774,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('When FilledButton disable, Can not set FilledButton focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When FilledButton disable, Can not set FilledButton focus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'FilledButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -796,7 +797,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('Does FilledButton work with hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does FilledButton work with hover', (WidgetTester tester) async { const Color hoverColor = Color(0xff001122); await tester.pumpWidget( @@ -823,7 +824,7 @@ void main() { expect(inkFeatures, paints..rect(color: hoverColor)); }); - testWidgets('Does FilledButton work with focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does FilledButton work with focus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); final FocusNode focusNode = FocusNode(debugLabel: 'FilledButton Node'); @@ -851,7 +852,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('Does FilledButton work with autofocus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does FilledButton work with autofocus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -881,7 +882,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('Does FilledButton contribute semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does FilledButton contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Theme( @@ -929,7 +930,7 @@ void main() { semantics.dispose(); }); - testWidgets('FilledButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { const ButtonStyle style = ButtonStyle( // Specifying minimumSize to mimic the original minimumSize for // RaisedButton so that the corresponding button size matches @@ -963,7 +964,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); }); - testWidgets('FilledButton has no clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton has no clip by default', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -980,7 +981,7 @@ void main() { ); }); - testWidgets('FilledButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key childKey = Key('test child'); @@ -1049,7 +1050,7 @@ void main() { expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); }); - testWidgets('FilledButton.icon responds to applied padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.icon responds to applied padding', (WidgetTester tester) async { const Key buttonKey = Key('test'); const Key labelKey = Key('label'); await tester.pumpWidget( @@ -1176,7 +1177,7 @@ void main() { if (textDirection == TextDirection.rtl) 'RTL', ].join(', '); - testWidgets(testName, (WidgetTester tester) async { + testWidgetsWithLeakTracking(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1317,7 +1318,7 @@ void main() { } }); - testWidgets('Override FilledButton default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override FilledButton default padding', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(colorScheme: const ColorScheme.light()), @@ -1351,7 +1352,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.all(22)); }); - testWidgets('M3 FilledButton has correct padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 FilledButton has correct padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1377,7 +1378,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.symmetric(horizontal: 24)); }); - testWidgets('M3 FilledButton.icon has correct padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 FilledButton.icon has correct padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1404,7 +1405,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 24.0, 0.0)); }); - testWidgets('By default, FilledButton shape outline is defined by shape.side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('By default, FilledButton shape outline is defined by shape.side', (WidgetTester tester) async { const Color borderColor = Color(0xff4caf50); await tester.pumpWidget( MaterialApp( @@ -1433,7 +1434,7 @@ void main() { ); }); - testWidgets('Fixed size FilledButtons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size FilledButtons', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1466,7 +1467,7 @@ void main() { expect(tester.getSize(find.widgetWithText(FilledButton, 'wx200')).height, 200); }); - testWidgets('FilledButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) { return MaterialApp( home: Scaffold( @@ -1506,7 +1507,7 @@ void main() { } }); - testWidgets('FilledButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -1533,7 +1534,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('FilledButton.icon does not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.icon does not overflow', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/77815 await tester.pumpWidget( MaterialApp( @@ -1554,7 +1555,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('FilledButton.icon icon,label layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.icon icon,label layout', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); final Key iconKey = UniqueKey(); final Key labelKey = UniqueKey(); @@ -1591,7 +1592,7 @@ void main() { expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0)); }); - testWidgets('FilledButton maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton maximumSize', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); @@ -1633,7 +1634,7 @@ void main() { expect(tester.getSize(find.byKey(key1)), const Size(104.0, 224.0)); }); - testWidgets('Fixed size FilledButton, same as minimumSize == maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size FilledButton, same as minimumSize == maximumSize', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1663,7 +1664,7 @@ void main() { expect(tester.getSize(find.widgetWithText(FilledButton, '200,200')), const Size(200, 200)); }); - testWidgets('FilledButton changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1741,7 +1742,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1764,7 +1765,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('Ink Response shape matches Material shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ink Response shape matches Material shape', (WidgetTester tester) async { Widget buildFrame({BorderSide? side}) { return MaterialApp( home: Scaffold( @@ -1807,7 +1808,7 @@ void main() { ); }); - testWidgets('FilledButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1937,15 +1938,15 @@ void main() { await gesture.removePointer(); } - testWidgets('FilledButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('FilledButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled FilledButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled FilledButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/filled_button_theme_test.dart b/packages/flutter/test/material/filled_button_theme_test.dart index 5b0d7c4dbe52f..ab30f3c60e305 100644 --- a/packages/flutter/test/material/filled_button_theme_test.dart +++ b/packages/flutter/test/material/filled_button_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('FilledButtonThemeData lerp special cases', () { expect(FilledButtonThemeData.lerp(null, null, 0), null); @@ -12,7 +14,7 @@ void main() { expect(identical(FilledButtonThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Passing no FilledButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no FilledButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -153,19 +155,19 @@ void main() { expect(align.alignment, alignment); } - testWidgets('Button style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(themeStyle: style)); await tester.pumpAndSettle(); checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallStyle: style)); await tester.pumpAndSettle(); checkButton(tester); @@ -173,26 +175,26 @@ void main() { // Same as the previous tests with empty ButtonStyle's instead of null. - testWidgets('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style, themeStyle: const ButtonStyle(), overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), themeStyle: style, overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), overallStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); }); - testWidgets('Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); diff --git a/packages/flutter/test/material/filter_chip_test.dart b/packages/flutter/test/material/filter_chip_test.dart index c4aaa40a06f28..5c17e9a062fe3 100644 --- a/packages/flutter/test/material/filter_chip_test.dart +++ b/packages/flutter/test/material/filter_chip_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; /// Adds the basic requirements for a Chip. @@ -115,7 +116,7 @@ DefaultTextStyle getLabelStyle(WidgetTester tester, String labelText) { } void main() { - testWidgets('FilterChip defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilterChip defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const String label = 'filter chip'; @@ -247,7 +248,7 @@ void main() { expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12)); }); - testWidgets('FilterChip.elevated defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilterChip.elevated defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const String label = 'filter chip'; @@ -379,7 +380,7 @@ void main() { expect(decoration.color, theme.colorScheme.onSurface.withOpacity(0.12)); }); - testWidgets('FilterChip.color resolves material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilterChip.color resolves material states', (WidgetTester tester) async { const Color disabledSelectedColor = Color(0xffffff00); const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); @@ -479,7 +480,7 @@ void main() { ); }); - testWidgets('FilterChip uses provided state color properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilterChip uses provided state color properties', (WidgetTester tester) async { const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); const Color selectedColor = Color(0xffff0000); @@ -554,7 +555,7 @@ void main() { ); }); - testWidgets('FilterChip can be tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilterChip can be tapped', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -570,7 +571,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Filter chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Filter chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { await pumpCheckmarkChip( theme: ThemeData(useMaterial3: false), tester, @@ -583,7 +584,7 @@ void main() { ); }); - testWidgets('Filter chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Filter chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedFilterChip(), @@ -597,7 +598,7 @@ void main() { ); }); - testWidgets('Filter chip check mark color can be set by the chip theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Filter chip check mark color can be set by the chip theme', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedFilterChip(), @@ -610,7 +611,7 @@ void main() { ); }); - testWidgets('Filter chip check mark color can be set by the chip constructor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Filter chip check mark color can be set by the chip constructor', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedFilterChip(checkmarkColor: const Color(0xff00ff00)), @@ -622,7 +623,7 @@ void main() { ); }); - testWidgets('Filter chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Filter chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedFilterChip(checkmarkColor: const Color(0xffff0000)), @@ -635,7 +636,7 @@ void main() { ); }); - testWidgets('FilterChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilterChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { const Text label = Text('label'); await tester.pumpWidget(wrapForChip(child: FilterChip(label: label, onSelected: (bool b) { }))); checkChipMaterialClipBehavior(tester, Clip.none); @@ -644,7 +645,7 @@ void main() { checkChipMaterialClipBehavior(tester, Clip.antiAlias); }); - testWidgets('M3 width should not change with selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 width should not change with selection', (WidgetTester tester) async { // Regression tests for: https://github.com/flutter/flutter/issues/110645 // For the text "FilterChip" the chip should default to 175 regardless of selection. diff --git a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart index ebd7a21896391..4d481b87b75f7 100644 --- a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart @@ -6,12 +6,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + final Key blockKey = UniqueKey(); const double expandedAppbarHeight = 250.0; final Key appbarContainerKey = UniqueKey(); void main() { - testWidgets('FlexibleSpaceBar collapse mode none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode none', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), @@ -49,7 +51,7 @@ void main() { expect(topAfterScroll.dy, equals(0.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgets('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), @@ -87,7 +89,7 @@ void main() { expect(topAfterScroll.dy, equals(-100.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgets('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), diff --git a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart index 86efe7056f7bc..4fa49ea9344be 100644 --- a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart @@ -10,12 +10,14 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + final Key blockKey = UniqueKey(); const double expandedAppbarHeight = 250.0; final Key finderKey = UniqueKey(); void main() { - testWidgets('FlexibleSpaceBar stretch mode default zoomBackground', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode default zoomBackground', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -50,7 +52,7 @@ void main() { expect(sizeBeforeScroll.height, lessThan(sizeAfterScroll.height)); }); - testWidgets('FlexibleSpaceBar stretch mode blurBackground', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode blurBackground', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -90,7 +92,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -134,7 +136,7 @@ void main() { expect(opacityWidget.opacity, equals(0.0)); }); - testWidgets('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index a643d4a0c3137..1de3f896b7cc7 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -13,10 +13,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('FlexibleSpaceBar centers title on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar centers title on iOS', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.android), @@ -59,7 +60,7 @@ void main() { } }); - testWidgets('FlexibleSpaceBarSettings provides settings to a FlexibleSpaceBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBarSettings provides settings to a FlexibleSpaceBar', (WidgetTester tester) async { const double minExtent = 100.0; const double initExtent = 200.0; const double maxExtent = 300.0; @@ -135,7 +136,7 @@ void main() { expect(clipRect.size.height, minExtent); }); - testWidgets('FlexibleSpaceBar.background is visible when using height other than kToolbarHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar.background is visible when using height other than kToolbarHeight', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/80451 await tester.pumpWidget( MaterialApp( @@ -170,7 +171,7 @@ void main() { expect(backgroundOpacity.opacity, 1.0); }); - testWidgets('Collapsed FlexibleSpaceBar has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Collapsed FlexibleSpaceBar has correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const double expandedHeight = 200; await tester.pumpWidget( @@ -436,7 +437,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/14227 - testWidgets('FlexibleSpaceBar sets width constraints for the title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar sets width constraints for the title', (WidgetTester tester) async { const double titleFontSize = 20.0; const double height = 300.0; late double width; @@ -485,7 +486,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar sets constraints for the title - override expandedTitleScale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar sets constraints for the title - override expandedTitleScale', (WidgetTester tester) async { const double titleFontSize = 20.0; const double height = 300.0; const double expandedTitleScale = 3.0; @@ -556,7 +557,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar scaled title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar scaled title', (WidgetTester tester) async { const double titleFontSize = 20.0; const double height = 300.0; await tester.pumpWidget( @@ -616,7 +617,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar scaled title - override expandedTitleScale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar scaled title - override expandedTitleScale', (WidgetTester tester) async { const double titleFontSize = 20.0; const double height = 300.0; const double expandedTitleScale = 3.0; @@ -679,7 +680,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar test titlePadding defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar test titlePadding defaults', (WidgetTester tester) async { Widget buildFrame(TargetPlatform platform, bool? centerTitle) { return MaterialApp( theme: ThemeData(platform: platform, useMaterial3: false), @@ -729,7 +730,7 @@ void main() { }); - testWidgets('FlexibleSpaceBar test titlePadding override', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar test titlePadding override', (WidgetTester tester) async { Widget buildFrame(TargetPlatform platform, bool? centerTitle) { return MaterialApp( theme: ThemeData(platform: platform, useMaterial3: false), @@ -797,7 +798,7 @@ void main() { expect(getTitleBottomLeft(), const Offset(390.0, 0.0)); }); - testWidgets('FlexibleSpaceBar rebuilds when scrolling.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar rebuilds when scrolling.', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SubCategoryScreenView(), )); diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 5b937e0757503..932b632617a7f 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -440,7 +440,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _dockedOffsetY)); }); - testWidgetsWithLeakTracking('endDocked', (WidgetTester tester) async { + testWidgets('endDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _dockedOffsetY)); @@ -502,7 +502,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _topOffsetY)); }); - testWidgets('miniStartFloat, RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartFloat, RTL', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniStartFloat, textDirection: TextDirection.rtl)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniRightOffsetX, _miniFloatOffsetY)); diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 2511fade5f177..b7977105fe663 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -14,6 +14,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -22,7 +23,7 @@ void main() { final ThemeData material3Theme = ThemeData(useMaterial3: true); final ThemeData material2Theme = ThemeData(useMaterial3: false); - testWidgets('Floating Action Button control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button control test', (WidgetTester tester) async { bool didPressButton = false; await tester.pumpWidget( Directionality( @@ -43,7 +44,7 @@ void main() { expect(didPressButton, isTrue); }); - testWidgets('Floating Action Button tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button tooltip', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -61,7 +62,7 @@ void main() { }); // Regression test for: https://github.com/flutter/flutter/pull/21084 - testWidgets('Floating Action Button tooltip (long press button edge)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button tooltip (long press button edge)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -82,7 +83,7 @@ void main() { }); // Regression test for: https://github.com/flutter/flutter/pull/21084 - testWidgets('Floating Action Button tooltip (long press button edge - no child)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button tooltip (long press button edge - no child)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -101,7 +102,7 @@ void main() { expect(find.text('Add'), findsOneWidget); }); - testWidgets('Floating Action Button tooltip (no child)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button tooltip (no child)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -136,7 +137,7 @@ void main() { expect(find.text('Add'), findsOneWidget); }); - testWidgets('Floating Action Button tooltip reacts when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button tooltip reacts when disabled', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -172,7 +173,7 @@ void main() { expect(find.text('Add'), findsOneWidget); }); - testWidgets('Floating Action Button elevation when highlighted - effect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when highlighted - effect', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: material3Theme, @@ -210,7 +211,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button elevation when disabled - defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when disabled - defaults', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -225,7 +226,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button elevation when disabled - override', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when disabled - override', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -240,7 +241,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 0.0); }); - testWidgets('Floating Action Button elevation when disabled - effect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when disabled - effect', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -279,7 +280,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button elevation when disabled while highlighted - effect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when disabled while highlighted - effect', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: material3Theme, @@ -326,7 +327,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -370,7 +371,7 @@ void main() { expect(getFABWidget(fabFinder).elevation, 6); }); - testWidgets('FlatActionButton mini size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlatActionButton mini size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { final Key key1 = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -408,7 +409,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(40.0, 40.0)); }); - testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.isExtended', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: material3Theme, @@ -480,7 +481,7 @@ void main() { expect(tester.getSize(fabFinder).width, 168); }); - testWidgets('FloatingActionButton.isExtended (without icon)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.isExtended (without icon)', (WidgetTester tester) async { final Finder fabFinder = find.byType(FloatingActionButton); FloatingActionButton getFabWidget() { @@ -533,7 +534,7 @@ void main() { expect(tester.getSize(fabFinder).width, 140); }); - testWidgets('Floating Action Button heroTag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button heroTag', (WidgetTester tester) async { late BuildContext theContext; await tester.pumpWidget( MaterialApp( @@ -556,7 +557,7 @@ void main() { await tester.pump(); // this would fail if heroTag was the same on both FloatingActionButtons (see below). }); - testWidgets('Floating Action Button heroTag - with duplicate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button heroTag - with duplicate', (WidgetTester tester) async { late BuildContext theContext; await tester.pumpWidget( MaterialApp( @@ -580,7 +581,7 @@ void main() { expect(tester.takeException().toString(), contains('FloatingActionButton')); }); - testWidgets('Floating Action Button heroTag - with duplicate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button heroTag - with duplicate', (WidgetTester tester) async { late BuildContext theContext; await tester.pumpWidget( MaterialApp( @@ -604,7 +605,7 @@ void main() { expect(tester.takeException().toString(), contains('xyzzy')); }); - testWidgets('Floating Action Button semantics (enabled)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button semantics (enabled)', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -639,7 +640,7 @@ void main() { semantics.dispose(); }); - testWidgets('Floating Action Button semantics (disabled)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button semantics (disabled)', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -669,7 +670,7 @@ void main() { semantics.dispose(); }); - testWidgets('Tooltip is used as semantics tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip is used as semantics tooltip', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -785,7 +786,7 @@ void main() { }); // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -813,7 +814,7 @@ void main() { ); }); - testWidgets('Floating Action Button changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -890,7 +891,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('Floating Action Button has no clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button has no clip by default', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( Directionality( @@ -911,7 +912,7 @@ void main() { ); }); - testWidgets('Can find FloatingActionButton semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can find FloatingActionButton semantics', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: FloatingActionButton(onPressed: () {}), )); @@ -928,7 +929,7 @@ void main() { ); }); - testWidgets('Foreground color applies to icon on fab', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Foreground color applies to icon on fab', (WidgetTester tester) async { const Color foregroundColor = Color(0xcafefeed); await tester.pumpWidget(MaterialApp( @@ -945,7 +946,7 @@ void main() { expect(iconRichText.text.style!.color, foregroundColor); }); - testWidgets('FloatingActionButton uses custom splash color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton uses custom splash color', (WidgetTester tester) async { const Color splashColor = Color(0xcafefeed); await tester.pumpWidget(MaterialApp( @@ -966,7 +967,7 @@ void main() { ); }); - testWidgets('extended FAB does not show label when isExtended is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extended FAB does not show label when isExtended is false', (WidgetTester tester) async { const Key iconKey = Key('icon'); const Key labelKey = Key('label'); @@ -987,7 +988,7 @@ void main() { expect(find.byKey(labelKey), findsNothing); }); - testWidgets('FloatingActionButton.small configures correct size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.small configures correct size', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1004,7 +1005,7 @@ void main() { expect(tester.getSize(find.byKey(key)), const Size(40.0, 40.0)); }); - testWidgets('FloatingActionButton.large configures correct size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.large configures correct size', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1020,7 +1021,7 @@ void main() { expect(tester.getSize(find.byKey(key)), const Size(96.0, 96.0)); }); - testWidgets('FloatingActionButton.extended can customize spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.extended can customize spacing', (WidgetTester tester) async { const Key iconKey = Key('icon'); const Key labelKey = Key('label'); const double spacing = 33.0; @@ -1045,7 +1046,7 @@ void main() { expect(tester.getTopRight(find.byType(FloatingActionButton)).dx - tester.getTopRight(find.byKey(labelKey)).dx, padding.end); }); - testWidgets('FloatingActionButton.extended can customize text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.extended can customize text style', (WidgetTester tester) async { const Key labelKey = Key('label'); const TextStyle style = TextStyle(letterSpacing: 2.0); @@ -1078,7 +1079,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Floating Action Button elevation when highlighted - effect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when highlighted - effect', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: material2Theme, @@ -1117,7 +1118,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button elevation when disabled while highlighted - effect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button elevation when disabled while highlighted - effect', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: material2Theme, @@ -1164,7 +1165,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -1208,7 +1209,7 @@ void main() { expect(getFABWidget(fabFinder).elevation, 12); }); - testWidgets('FloatingActionButton.isExtended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.isExtended', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: material2Theme, @@ -1275,7 +1276,7 @@ void main() { expect(tester.getSize(fabFinder).width, 168); }); - testWidgets('FloatingActionButton.isExtended (without icon)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.isExtended (without icon)', (WidgetTester tester) async { final Finder fabFinder = find.byType(FloatingActionButton); FloatingActionButton getFabWidget() { @@ -1327,7 +1328,7 @@ void main() { // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -1367,7 +1368,7 @@ void main() { feedback.dispose(); }); - testWidgets('FloatingActionButton with enabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton with enabled feedback', (WidgetTester tester) async { const bool enableFeedback = true; await tester.pumpWidget(MaterialApp( @@ -1384,7 +1385,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('FloatingActionButton with disabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton with disabled feedback', (WidgetTester tester) async { const bool enableFeedback = false; await tester.pumpWidget(MaterialApp( @@ -1401,7 +1402,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('FloatingActionButton with enabled feedback by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton with enabled feedback by default', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: FloatingActionButton( onPressed: () {}, @@ -1415,7 +1416,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('FloatingActionButton with disabled feedback using FloatingActionButtonTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton with disabled feedback using FloatingActionButtonTheme', (WidgetTester tester) async { const bool enableFeedbackTheme = false; final ThemeData theme = ThemeData( floatingActionButtonTheme: const FloatingActionButtonThemeData( @@ -1439,7 +1440,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('FloatingActionButton.enableFeedback is overridden by FloatingActionButtonThemeData.enableFeedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.enableFeedback is overridden by FloatingActionButtonThemeData.enableFeedback', (WidgetTester tester) async { const bool enableFeedbackTheme = false; const bool enableFeedback = true; final ThemeData theme = ThemeData( diff --git a/packages/flutter/test/material/floating_action_button_theme_test.dart b/packages/flutter/test/material/floating_action_button_theme_test.dart index f3d54f69957ea..dcc68ce96cdb8 100644 --- a/packages/flutter/test/material/floating_action_button_theme_test.dart +++ b/packages/flutter/test/material/floating_action_button_theme_test.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('FloatingActionButtonThemeData copyWith, ==, hashCode basics', () { expect(const FloatingActionButtonThemeData(), const FloatingActionButtonThemeData().copyWith()); @@ -19,7 +21,7 @@ void main() { expect(identical(FloatingActionButtonThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Material3: Default values are used when no FloatingActionButton or FloatingActionButtonThemeData properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: Default values are used when no FloatingActionButton or FloatingActionButtonThemeData properties are specified', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget(MaterialApp( theme: ThemeData.from(useMaterial3: true, colorScheme: colorScheme), @@ -44,7 +46,7 @@ void main() { expect(_getIconSize(tester).height, 24.0); }); - testWidgets('Material2: Default values are used when no FloatingActionButton or FloatingActionButtonThemeData properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: Default values are used when no FloatingActionButton or FloatingActionButtonThemeData properties are specified', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget(MaterialApp( theme: ThemeData.from(useMaterial3: false, colorScheme: colorScheme), @@ -69,7 +71,7 @@ void main() { expect(_getIconSize(tester).height, 24.0); }); - testWidgets('FloatingActionButtonThemeData values are used when no FloatingActionButton properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButtonThemeData values are used when no FloatingActionButton properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0xBEEFBEEF); const Color foregroundColor = Color(0xFACEFACE); const Color splashColor = Color(0xCAFEFEED); @@ -110,7 +112,7 @@ void main() { expect(_getRawMaterialButton(tester).constraints, constraints); }); - testWidgets('FloatingActionButton values take priority over FloatingActionButtonThemeData values when both properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton values take priority over FloatingActionButtonThemeData values when both properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0x00000001); const Color foregroundColor = Color(0x00000002); const Color splashColor = Color(0x00000003); @@ -155,7 +157,7 @@ void main() { expect(_getRawMaterialButton(tester).splashColor, splashColor); }); - testWidgets('FloatingActionButton uses a custom shape when specified in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton uses a custom shape when specified in the theme', (WidgetTester tester) async { const ShapeBorder customShape = BeveledRectangleBorder(); await tester.pumpWidget(MaterialApp( @@ -170,7 +172,7 @@ void main() { expect(_getRawMaterialButton(tester).shape, customShape); }); - testWidgets('FloatingActionButton.small uses custom constraints when specified in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.small uses custom constraints when specified in the theme', (WidgetTester tester) async { const BoxConstraints constraints = BoxConstraints.tightFor(width: 100.0, height: 100.0); const double iconSize = 24.0; @@ -193,7 +195,7 @@ void main() { expect(_getIconSize(tester).height, iconSize); }); - testWidgets('FloatingActionButton.large uses custom constraints when specified in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.large uses custom constraints when specified in the theme', (WidgetTester tester) async { const BoxConstraints constraints = BoxConstraints.tightFor(width: 100.0, height: 100.0); const double iconSize = 36.0; @@ -216,7 +218,7 @@ void main() { expect(_getIconSize(tester).height, iconSize); }); - testWidgets('Material3: FloatingActionButton.extended uses custom properties when specified in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: FloatingActionButton.extended uses custom properties when specified in the theme', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Key iconKey = Key('icon'); const Key labelKey = Key('label'); @@ -253,7 +255,7 @@ void main() { expect(_getRawMaterialButton(tester).textStyle, textStyle.copyWith(color: colorScheme.onPrimaryContainer)); }); - testWidgets('Material2: FloatingActionButton.extended uses custom properties when specified in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: FloatingActionButton.extended uses custom properties when specified in the theme', (WidgetTester tester) async { const Key iconKey = Key('icon'); const Key labelKey = Key('label'); const BoxConstraints constraints = BoxConstraints.tightFor(height: 100.0); @@ -287,7 +289,7 @@ void main() { expect(_getRawMaterialButton(tester).textStyle, textStyle.copyWith(color: const Color(0xffffffff))); }); - testWidgets('Material3: FloatingActionButton.extended custom properties takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: FloatingActionButton.extended custom properties takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Key iconKey = Key('icon'); const Key labelKey = Key('label'); @@ -324,7 +326,7 @@ void main() { expect(_getRawMaterialButton(tester).textStyle, textStyle.copyWith(color: colorScheme.onPrimaryContainer)); }); - testWidgets('Material2: FloatingActionButton.extended custom properties takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: FloatingActionButton.extended custom properties takes priority over FloatingActionButtonThemeData spacing', (WidgetTester tester) async { const Key iconKey = Key('icon'); const Key labelKey = Key('label'); const double iconLabelSpacing = 33.0; @@ -358,7 +360,7 @@ void main() { expect(_getRawMaterialButton(tester).textStyle, textStyle.copyWith(color: const Color(0xffffffff))); }); - testWidgets('default FloatingActionButton debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default FloatingActionButton debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const FloatingActionButtonThemeData ().debugFillProperties(builder); @@ -370,7 +372,7 @@ void main() { expect(description, []); }); - testWidgets('Material implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const FloatingActionButtonThemeData( foregroundColor: Color(0xFEEDFEED), @@ -426,7 +428,7 @@ void main() { ]); }); - testWidgets('FloatingActionButton.mouseCursor uses FloatingActionButtonThemeData.mouseCursor when specified.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton.mouseCursor uses FloatingActionButtonThemeData.mouseCursor when specified.', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData().copyWith( floatingActionButtonTheme: FloatingActionButtonThemeData( diff --git a/packages/flutter/test/material/grid_title_test.dart b/packages/flutter/test/material/grid_title_test.dart index b3f1f1c85696b..bd4f17297bee3 100644 --- a/packages/flutter/test/material/grid_title_test.dart +++ b/packages/flutter/test/material/grid_title_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('GridTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridTile control test', (WidgetTester tester) async { final Key headerKey = UniqueKey(); final Key footerKey = UniqueKey(); diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index bd8b6c3b5b0e7..eea26984ef371 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -29,7 +29,7 @@ void main() { mockOnPressedFunction = MockOnPressedFunction(); }); - testWidgets('test icon is findable by key', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test icon is findable by key', (WidgetTester tester) async { const ValueKey key = ValueKey('icon-button'); await tester.pumpWidget( wrap( @@ -45,7 +45,7 @@ void main() { expect(find.byKey(key), findsOneWidget); }); - testWidgets('test default icon buttons are sized up to 48', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test default icon buttons are sized up to 48', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -64,7 +64,7 @@ void main() { expect(mockOnPressedFunction.called, 1); }); - testWidgets('test small icons are sized up to 48dp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test small icons are sized up to 48dp', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -81,7 +81,7 @@ void main() { expect(iconButton.size, const Size(48.0, 48.0)); }); - testWidgets('test icons can be small when total size is >48dp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test icons can be small when total size is >48dp', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -99,7 +99,7 @@ void main() { expect(iconButton.size, const Size(70.0, 70.0)); }); - testWidgets('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -203,7 +203,7 @@ void main() { expect(icon.size, const Size(10.0, 10.0)); }); - testWidgets('when non-null, iconSize precedes IconTheme.of(context).size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when non-null, iconSize precedes IconTheme.of(context).size', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -223,7 +223,7 @@ void main() { expect(icon.size, const Size(10.0, 10.0)); }); - testWidgets('Small icons with non-null constraints can be <48dp for M2, but =48dp for M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small icons with non-null constraints can be <48dp for M2, but =48dp for M3', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -248,7 +248,7 @@ void main() { expect(icon.size, const Size(10.0, 10.0)); }); - testWidgets('Small icons with non-null constraints and custom padding can be <48dp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small icons with non-null constraints and custom padding can be <48dp', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( wrap( @@ -274,7 +274,7 @@ void main() { expect(icon.size, const Size(10.0, 10.0)); }); - testWidgets('Small icons comply with VisualDensity requirements', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small icons comply with VisualDensity requirements', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; final ThemeData themeDataM2 = ThemeData( useMaterial3: material3, @@ -312,7 +312,7 @@ void main() { expect(iconButton.size, material3 ? const Size(52.0, 44.0) : const Size(36.0, 28.0)); }); - testWidgets('test default icon buttons are constrained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test default icon buttons are constrained', (WidgetTester tester) async { await tester.pumpWidget( wrap( useMaterial3: theme.useMaterial3, @@ -373,7 +373,7 @@ void main() { expect(boxM3.size, const Size(48.0, 600.0)); }); - testWidgets('test default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test default padding', (WidgetTester tester) async { await tester.pumpWidget( wrap( useMaterial3: theme.useMaterial3, @@ -389,7 +389,7 @@ void main() { expect(box.size, const Size(96.0, 96.0)); }); - testWidgets('test default alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test default alignment', (WidgetTester tester) async { await tester.pumpWidget( wrap( useMaterial3: theme.useMaterial3, @@ -447,7 +447,7 @@ void main() { expect(mockOnPressedFunction.called, 1); }); - testWidgets('IconButton AppBar size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton AppBar size', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( MaterialApp( @@ -474,7 +474,7 @@ void main() { // This test is very similar to the '...explicit splashColor and highlightColor' test // in buttons_test.dart. If you change this one, you may want to also change that one. - testWidgets('IconButton with explicit splashColor and highlightColor - M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton with explicit splashColor and highlightColor - M2', (WidgetTester tester) async { const Color directSplashColor = Color(0xFF00000F); const Color directHighlightColor = Color(0xFF0000F0); @@ -560,7 +560,7 @@ void main() { await gesture.up(); }); - testWidgets('IconButton with explicit splash radius - M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton with explicit splash radius - M2', (WidgetTester tester) async { const double splashRadius = 30.0; await tester.pumpWidget( MaterialApp( @@ -591,7 +591,7 @@ void main() { await gesture.up(); }); - testWidgets('IconButton Semantics (enabled) - M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton Semantics (enabled) - M2', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -625,7 +625,7 @@ void main() { semantics.dispose(); }); - testWidgets('IconButton Semantics (disabled) - M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton Semantics (disabled) - M2', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -654,7 +654,7 @@ void main() { semantics.dispose(); }); - testWidgets('IconButton Semantics (selected) - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton Semantics (selected) - M3', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -710,7 +710,7 @@ void main() { semantics.dispose(); }); - testWidgets('IconButton loses focus when disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton loses focus when disabled.', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'IconButton'); await tester.pumpWidget( wrap( @@ -742,7 +742,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('IconButton keeps focus when disabled in directional navigation mode.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton keeps focus when disabled in directional navigation mode.', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'IconButton'); await tester.pumpWidget( wrap( @@ -784,7 +784,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isTrue); }); - testWidgets("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: 'IconButton 1'); final FocusNode focusNode2 = FocusNode(debugLabel: 'IconButton 2'); @@ -831,7 +831,7 @@ void main() { feedback.dispose(); }); - testWidgets('IconButton with disabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton with disabled feedback', (WidgetTester tester) async { final Widget button = Directionality( textDirection: TextDirection.ltr, child: Center( @@ -854,7 +854,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('IconButton with enabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton with enabled feedback', (WidgetTester tester) async { final Widget button = Directionality( textDirection: TextDirection.ltr, child: Center( @@ -876,7 +876,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('IconButton with enabled feedback by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton with enabled feedback by default', (WidgetTester tester) async { final Widget button = Directionality( textDirection: TextDirection.ltr, child: Center( @@ -899,7 +899,7 @@ void main() { }); }); - testWidgets('IconButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); final bool material3 = theme.useMaterial3; Future buildTest(VisualDensity visualDensity) async { @@ -943,7 +943,7 @@ void main() { expect(box.size, equals(material3 ? const Size(64, 36) : const Size(60, 40))); }); - testWidgets('IconButton.mouseCursor changes cursor on hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.mouseCursor changes cursor on hover', (WidgetTester tester) async { // Test argument works await tester.pumpWidget( MaterialApp( @@ -991,7 +991,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('disabled IconButton has basic mouse cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled IconButton has basic mouse cursor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: theme, @@ -1017,7 +1017,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('IconButton.mouseCursor overrides implicit setting of mouse cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.mouseCursor overrides implicit setting of mouse cursor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: theme, @@ -1064,7 +1064,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.none); }); - testWidgets('IconTheme opacity test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme opacity test', (WidgetTester tester) async { final ThemeData theme = ThemeData.from(colorScheme: colorScheme, useMaterial3: false); await tester.pumpWidget( @@ -1107,7 +1107,7 @@ void main() { expect(iconColorWithOpacity(), Colors.purple.withOpacity(0.5)); }); - testWidgets('IconButton defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled IconButton @@ -1190,7 +1190,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('IconButton default overlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton default overlayColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -1243,7 +1243,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.12))); }); - testWidgets('IconButton.fill defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.fill defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled IconButton @@ -1329,7 +1329,7 @@ void main() { expect(iconColor(), colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('IconButton.fill default overlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.fill default overlayColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -1382,7 +1382,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); }); - testWidgets('Toggleable IconButton.fill defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggleable IconButton.fill defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled selected IconButton @@ -1497,7 +1497,7 @@ void main() { expect(iconColor(), colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('IconButton.filledTonal defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.filledTonal defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled IconButton.tonal @@ -1583,7 +1583,7 @@ void main() { expect(iconColor(), colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('IconButton.filledTonal default overlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.filledTonal default overlayColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -1636,7 +1636,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); }); - testWidgets('Toggleable IconButton.filledTonal defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggleable IconButton.filledTonal defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled selected IconButton @@ -1751,7 +1751,7 @@ void main() { expect(iconColor(), colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('IconButton.outlined defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.outlined defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled IconButton.tonal @@ -1837,7 +1837,7 @@ void main() { expect(iconColor(), colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('IconButton.outlined default overlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton.outlined default overlayColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -1890,7 +1890,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.08))); }); - testWidgets('Toggleable IconButton.outlined defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggleable IconButton.outlined defaults - M3', (WidgetTester tester) async { final ThemeData themeM3 = ThemeData.from(colorScheme: colorScheme, useMaterial3: true); // Enabled selected IconButton @@ -2052,7 +2052,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('IconButton uses stateful color for icon color in different states - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton uses stateful color for icon color in different states - M3', (WidgetTester tester) async { bool isSelected = false; final FocusNode focusNode = FocusNode(); @@ -2138,7 +2138,7 @@ void main() { expect(iconColor(), pressedColor); }); - testWidgets('Does IconButton contribute semantics - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does IconButton contribute semantics - M3', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -2185,7 +2185,7 @@ void main() { semantics.dispose(); }); - testWidgets('IconButton size is configurable by ThemeData.materialTapTargetSize - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconButton size is configurable by ThemeData.materialTapTargetSize - M3', (WidgetTester tester) async { Widget buildFrame(MaterialTapTargetSize tapTargetSize) { return Theme( data: ThemeData(materialTapTargetSize: tapTargetSize, useMaterial3: true), @@ -2209,7 +2209,7 @@ void main() { expect(tester.getSize(find.byType(IconButton)), const Size(40.0, 40.0)); }); - testWidgets('Override IconButton default padding - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override IconButton default padding - M3', (WidgetTester tester) async { // Use [IconButton]'s padding property to override default value. await tester.pumpWidget( MaterialApp( @@ -2285,7 +2285,7 @@ void main() { expect(paddingWidget3.padding, const EdgeInsets.all(22)); }); - testWidgets('Default IconButton is not selectable - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default IconButton is not selectable - M3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true), @@ -2319,7 +2319,7 @@ void main() { expect(buttonMaterial().color, Colors.transparent); }); - testWidgets('Icon button is selectable when isSelected is not null - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon button is selectable when isSelected is not null - M3', (WidgetTester tester) async { bool isSelected = false; await tester.pumpWidget( MaterialApp( @@ -2372,7 +2372,7 @@ void main() { expect(buttonMaterial().color, Colors.transparent); }); - testWidgets('The IconButton is in selected status if isSelected is true by default - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The IconButton is in selected status if isSelected is true by default - M3', (WidgetTester tester) async { bool isSelected = true; await tester.pumpWidget( MaterialApp( @@ -2418,7 +2418,7 @@ void main() { expect(buttonMaterial().color, Colors.transparent); }); - testWidgets("The selectedIcon is used if it's not null and the button is clicked" , (WidgetTester tester) async { + testWidgetsWithLeakTracking("The selectedIcon is used if it's not null and the button is clicked" , (WidgetTester tester) async { bool isSelected = false; await tester.pumpWidget( MaterialApp( @@ -2458,7 +2458,7 @@ void main() { expect(find.byIcon(Icons.account_box), findsNothing); }); - testWidgets('The original icon is used for selected and unselected status when selectedIcon is null' , (WidgetTester tester) async { + testWidgetsWithLeakTracking('The original icon is used for selected and unselected status when selectedIcon is null' , (WidgetTester tester) async { bool isSelected = false; await tester.pumpWidget( MaterialApp( @@ -2494,7 +2494,7 @@ void main() { expect(find.byIcon(Icons.account_box), findsOneWidget); }); - testWidgets('The selectedIcon is used for disabled button if isSelected is true - M3' , (WidgetTester tester) async { + testWidgetsWithLeakTracking('The selectedIcon is used for disabled button if isSelected is true - M3' , (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true), @@ -2515,7 +2515,7 @@ void main() { expect(find.byIcon(Icons.ac_unit), findsOneWidget); }); - testWidgets('The visualDensity of M3 IconButton can be configured by IconButtonTheme, ' + testWidgetsWithLeakTracking('The visualDensity of M3 IconButton can be configured by IconButtonTheme, ' 'but cannot be configured by ThemeData - M3' , (WidgetTester tester) async { Future buildTest({VisualDensity? iconButtonThemeVisualDensity, VisualDensity? themeVisualDensity}) async { return tester.pumpWidget( @@ -2609,7 +2609,7 @@ void main() { expect(tester.getSize(find.byIcon(Icons.account_box)), equals(const Size(35, 35)),); }); - testWidgets('Theme IconButtonTheme overrides IconTheme in Material3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme IconButtonTheme overrides IconTheme in Material3', (WidgetTester tester) async { // When IconButtonTheme and IconTheme both exist in ThemeData, the IconButtonTheme can override IconTheme. await tester.pumpWidget( MaterialApp( @@ -2632,7 +2632,7 @@ void main() { expect(tester.getSize(find.byIcon(Icons.account_box)), equals(const Size(27, 27)),); }); - testWidgets('Button IconButtonTheme always overrides IconTheme in Material3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button IconButtonTheme always overrides IconTheme in Material3', (WidgetTester tester) async { // When IconButtonTheme is closer to IconButton, IconButtonTheme overrides IconTheme await tester.pumpWidget( MaterialApp( @@ -2682,7 +2682,7 @@ void main() { expect(tester.getSize(find.byIcon(Icons.account_box)), equals(const Size(36, 36)),); }); - testWidgets('White icon color defined by users shows correctly in Material3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('White icon color defined by users shows correctly in Material3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from( @@ -2702,7 +2702,7 @@ void main() { expect(iconColor1(), Colors.white); }); - testWidgets('In light mode, icon color is M3 default color instead of IconTheme.of(context).color, ' + testWidgetsWithLeakTracking('In light mode, icon color is M3 default color instead of IconTheme.of(context).color, ' 'if only setting color in IconTheme', (WidgetTester tester) async { final ColorScheme darkScheme = const ColorScheme.dark().copyWith(onSurfaceVariant: const Color(0xffe91e60)); // Brightness.dark @@ -2725,7 +2725,7 @@ void main() { expect(iconColor0(), darkScheme.onSurfaceVariant); // onSurfaceVariant }); - testWidgets('In dark mode, icon color is M3 default color instead of IconTheme.of(context).color, ' + testWidgetsWithLeakTracking('In dark mode, icon color is M3 default color instead of IconTheme.of(context).color, ' 'if only setting color in IconTheme', (WidgetTester tester) async { final ColorScheme lightScheme = const ColorScheme.light().copyWith(onSurfaceVariant: const Color(0xffe91e60)); // Brightness.dark @@ -2748,11 +2748,11 @@ void main() { expect(iconColor0(), lightScheme.onSurfaceVariant); // onSurfaceVariant }); - testWidgets('black87 icon color defined by users shows correctly in Material3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('black87 icon color defined by users shows correctly in Material3', (WidgetTester tester) async { }); - testWidgets("IconButton.styleFrom doesn't throw exception on passing only one cursor", (WidgetTester tester) async { + testWidgetsWithLeakTracking("IconButton.styleFrom doesn't throw exception on passing only one cursor", (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/118071. await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/material/icon_button_theme_test.dart b/packages/flutter/test/material/icon_button_theme_test.dart index 7cc64cf8744ff..20b2889b85d30 100644 --- a/packages/flutter/test/material/icon_button_theme_test.dart +++ b/packages/flutter/test/material/icon_button_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('IconButtonThemeData lerp special cases', () { expect(IconButtonThemeData.lerp(null, null, 0), null); @@ -12,7 +14,7 @@ void main() { expect(identical(IconButtonThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Passing no IconButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no IconButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -146,19 +148,19 @@ void main() { expect(align.alignment, alignment); } - testWidgets('Button style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(themeStyle: style)); await tester.pumpAndSettle(); checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallStyle: style)); await tester.pumpAndSettle(); checkButton(tester); @@ -166,26 +168,26 @@ void main() { // Same as the previous tests with empty ButtonStyle's instead of null. - testWidgets('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style, themeStyle: const ButtonStyle(), overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), themeStyle: style, overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), overallStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); }); - testWidgets('Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); diff --git a/packages/flutter/test/material/icons_test.dart b/packages/flutter/test/material/icons_test.dart index 01106758c97f0..01bd6c4cd19b4 100644 --- a/packages/flutter/test/material/icons_test.dart +++ b/packages/flutter/test/material/icons_test.dart @@ -14,19 +14,21 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:platform/platform.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('IconData object test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconData object test', (WidgetTester tester) async { expect(Icons.account_balance, isNot(equals(Icons.account_box))); expect(Icons.account_balance.hashCode, isNot(equals(Icons.account_box.hashCode))); expect(Icons.account_balance, hasOneLineDescription); }); - testWidgets('Icons specify the material font', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icons specify the material font', (WidgetTester tester) async { expect(Icons.clear.fontFamily, 'MaterialIcons'); expect(Icons.search.fontFamily, 'MaterialIcons'); }); - testWidgets('Certain icons (and their variants) match text direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Certain icons (and their variants) match text direction', (WidgetTester tester) async { expect(Icons.arrow_back.matchTextDirection, true); expect(Icons.arrow_back_rounded.matchTextDirection, true); expect(Icons.arrow_back_outlined.matchTextDirection, true); @@ -38,7 +40,7 @@ void main() { expect(Icons.access_time_sharp.matchTextDirection, false); }); - testWidgets('Adaptive icons are correct on cupertino platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adaptive icons are correct on cupertino platforms', (WidgetTester tester) async { expect(Icons.adaptive.arrow_back, Icons.arrow_back_ios); expect(Icons.adaptive.arrow_back_outlined, Icons.arrow_back_ios_outlined); }, @@ -48,7 +50,7 @@ void main() { }), ); - testWidgets('Adaptive icons are correct on non-cupertino platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adaptive icons are correct on non-cupertino platforms', (WidgetTester tester) async { expect(Icons.adaptive.arrow_back, Icons.arrow_back); expect(Icons.adaptive.arrow_back_outlined, Icons.arrow_back_outlined); }, @@ -60,7 +62,7 @@ void main() { }), ); - testWidgets('A sample of icons look as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A sample of icons look as expected', (WidgetTester tester) async { await _loadIconFont(); await tester.pumpWidget(const MaterialApp( @@ -84,7 +86,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/39998 // Regression test for https://github.com/flutter/flutter/issues/95886 - testWidgets('Another sample of icons look as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Another sample of icons look as expected', (WidgetTester tester) async { await _loadIconFont(); await tester.pumpWidget(const MaterialApp( @@ -104,7 +106,7 @@ void main() { await expectLater(find.byType(Wrap), matchesGoldenFile('test.icons.sample2.png')); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/39998 - testWidgets('Another sample of icons look as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Another sample of icons look as expected', (WidgetTester tester) async { await _loadIconFont(); await tester.pumpWidget(const MaterialApp( @@ -125,7 +127,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/39998 // Regression test for https://github.com/flutter/flutter/issues/103202. - testWidgets('Another sample of icons look as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Another sample of icons look as expected', (WidgetTester tester) async { await _loadIconFont(); await tester.pumpWidget(const MaterialApp( diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index e62cc7b7107c7..7461ca8c4c4ab 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -6,10 +6,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgets('The Ink widget expands when no dimensions are set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The Ink widget expands when no dimensions are set', (WidgetTester tester) async { await tester.pumpWidget( Material( child: Ink(), @@ -19,7 +20,7 @@ void main() { expect(tester.getSize(find.byType(Ink)), const Size(800.0, 600.0)); }); - testWidgets('The Ink widget fits the specified size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The Ink widget fits the specified size', (WidgetTester tester) async { const double height = 150.0; const double width = 200.0; await tester.pumpWidget( @@ -37,7 +38,7 @@ void main() { expect(tester.getSize(find.byType(Ink)), const Size(width, height)); }); - testWidgets('The Ink widget expands on a unspecified dimension', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The Ink widget expands on a unspecified dimension', (WidgetTester tester) async { const double height = 150.0; await tester.pumpWidget( Material( @@ -53,7 +54,7 @@ void main() { expect(tester.getSize(find.byType(Ink)), const Size(800, height)); }); - testWidgets('The InkWell widget renders an ink splash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget renders an ink splash', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xAA0000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); @@ -102,7 +103,7 @@ void main() { await gesture.up(); }); - testWidgets('The InkWell widget renders an ink ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget renders an ink ripple', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); @@ -188,7 +189,7 @@ void main() { expect(box, ripplePattern(inkWellCenter - tapDownOffset, 105.0, 0)); }); - testWidgets('Does the Ink widget render anything', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does the Ink widget render anything', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -271,7 +272,7 @@ void main() { await gesture.up(); }); - testWidgets('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); @@ -371,7 +372,7 @@ void main() { expect(box, ripplePattern(105.0, 0)); }); - testWidgets('Cancel an InkRipple that was disposed when its animation ended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cancel an InkRipple that was disposed when its animation ended', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/14391 await tester.pumpWidget( Directionality( @@ -404,7 +405,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Cancel an InkRipple that was disposed when its animation ended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cancel an InkRipple that was disposed when its animation ended', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); @@ -454,7 +455,7 @@ void main() { })); }); - testWidgets('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { final OverlayPortalController controller = OverlayPortalController(); controller.show(); await tester.pumpWidget( @@ -514,7 +515,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Custom rectCallback renders an ink splash from its center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom rectCallback renders an ink splash from its center', (WidgetTester tester) async { const Color splashColor = Color(0xff00ff00); Widget buildWidget({InteractiveInkFeatureFactory? splashFactory}) { @@ -569,7 +570,7 @@ void main() { ); }); - testWidgets('Ink with isVisible=false does not paint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ink with isVisible=false does not paint', (WidgetTester tester) async { const Color testColor = Color(0xffff1234); Widget inkWidget({required bool isVisible}) { return Material( diff --git a/packages/flutter/test/material/ink_splash_test.dart b/packages/flutter/test/material/ink_splash_test.dart index f178004ebceea..bcc8e40d25b77 100644 --- a/packages/flutter/test/material/ink_splash_test.dart +++ b/packages/flutter/test/material/ink_splash_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/21506. - testWidgets('InkSplash receives textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSplash receives textDirection', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Button Border Test')), @@ -27,7 +28,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('InkWell with NoSplash splashFactory paints nothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell with NoSplash splashFactory paints nothing', (WidgetTester tester) async { Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) { return MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index 60d64ed420d8e..c7a655ae4f400 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -8,12 +8,13 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/services/keyboard_key.g.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; void main() { - testWidgets('InkWell gestures control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell gestures control test', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(Directionality( @@ -80,7 +81,7 @@ void main() { expect(log, equals(['tap-down', 'tap-cancel'])); }); - testWidgets('InkWell only onTapDown enables gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell only onTapDown enables gestures', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/96030 bool downTapped = false; await tester.pumpWidget(Directionality( @@ -100,7 +101,7 @@ void main() { expect(downTapped, true); }); - testWidgets('InkWell invokes activation actions when expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell invokes activation actions when expected', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(Directionality( @@ -132,7 +133,7 @@ void main() { expect(log, equals(['tap'])); }); - testWidgets('long-press and tap on disabled should not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long-press and tap on disabled should not throw', (WidgetTester tester) async { await tester.pumpWidget(const Material( child: Directionality( textDirection: TextDirection.ltr, @@ -147,7 +148,7 @@ void main() { await tester.pump(const Duration(seconds: 1)); }); - testWidgets('ink well changes color on hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink well changes color on hover', (WidgetTester tester) async { await tester.pumpWidget(Material( child: Directionality( textDirection: TextDirection.ltr, @@ -176,7 +177,7 @@ void main() { expect(inkFeatures, paints..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff00ff00))); }); - testWidgets('ink well changes color on hover with overlayColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink well changes color on hover with overlayColor', (WidgetTester tester) async { // Same test as 'ink well changes color on hover' except that the // hover color is specified with the overlayColor parameter. await tester.pumpWidget(Material( @@ -215,7 +216,7 @@ void main() { expect(inkFeatures, paints..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff00ff00))); }); - testWidgets('ink response changes color on focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink response changes color on focus', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( @@ -252,7 +253,7 @@ void main() { ); }); - testWidgets('ink response changes color on focus with overlayColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink response changes color on focus with overlayColor', (WidgetTester tester) async { // Same test as 'ink well changes color on focus' except that the // hover color is specified with the overlayColor parameter. FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -300,7 +301,7 @@ void main() { ); }); - testWidgets('ink well changes color on pressed with overlayColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink well changes color on pressed with overlayColor', (WidgetTester tester) async { const Color pressedColor = Color(0xffdd00ff); await tester.pumpWidget(Material( @@ -334,7 +335,7 @@ void main() { await gesture.up(); }); - testWidgets('ink response splashColor matches splashColor parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink response splashColor matches splashColor parameter', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); const Color splashColor = Color(0xffff0000); @@ -372,7 +373,7 @@ void main() { await gesture.up(); }); - testWidgets('ink response splashColor matches resolved overlayColor for MaterialState.pressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink response splashColor matches resolved overlayColor for MaterialState.pressed', (WidgetTester tester) async { // Same test as 'ink response splashColor matches splashColor // parameter' except that the splash color is specified with the // overlayColor parameter. @@ -421,7 +422,7 @@ void main() { await gesture.up(); }); - testWidgets('ink response uses radius for focus highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink response uses radius for focus highlight', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( @@ -451,7 +452,7 @@ void main() { expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); }); - testWidgets('InkWell uses borderRadius for focus highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell uses borderRadius for focus highlight', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( @@ -487,7 +488,7 @@ void main() { )); }); - testWidgets('InkWell uses borderRadius for hover highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell uses borderRadius for hover highlight', (WidgetTester tester) async { await tester.pumpWidget( Material( child: Directionality( @@ -524,7 +525,7 @@ void main() { )); }); - testWidgets('InkWell customBorder clips for focus highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell customBorder clips for focus highlight', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( @@ -578,7 +579,7 @@ void main() { ); }); - testWidgets('InkWell customBorder clips for hover highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell customBorder clips for hover highlight', (WidgetTester tester) async { await tester.pumpWidget( Material( child: Directionality( @@ -631,7 +632,7 @@ void main() { ); }); -testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { +testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); Widget boilerplate(double radius) { @@ -669,7 +670,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); }); - testWidgets('InkResponse highlightShape can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkResponse highlightShape can be updated', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); Widget boilerplate(BoxShape shape) { @@ -710,7 +711,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1)); }); - testWidgets('InkWell borderRadius can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell borderRadius can be updated', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); Widget boilerplate(BorderRadius borderRadius) { @@ -755,7 +756,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { )); }); - testWidgets('InkWell customBorder can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell customBorder can be updated', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); Widget boilerplate(BorderRadius borderRadius) { @@ -822,7 +823,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { ); }); - testWidgets('InkWell splash customBorder can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell splash customBorder can be updated', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/121626. final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); Widget boilerplate(BorderRadius borderRadius) { @@ -910,7 +911,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { await gesture.up(); }); - testWidgets("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget(Material( @@ -942,7 +943,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(inkFeatures, paintsExactlyCountTimes(#drawRect, 0)); }); - testWidgets('InkWell.mouseCursor changes cursor on hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell.mouseCursor changes cursor on hover', (WidgetTester tester) async { final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); await gesture.addPointer(location: const Offset(1, 1)); @@ -1029,7 +1030,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1061,7 +1062,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { feedback.dispose(); }); - testWidgets('enabled (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('enabled (default)', (WidgetTester tester) async { await tester.pumpWidget(Material( child: Directionality( textDirection: TextDirection.ltr, @@ -1089,7 +1090,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(feedback.hapticCount, 1); }); - testWidgets('disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled', (WidgetTester tester) async { await tester.pumpWidget(Material( child: Directionality( textDirection: TextDirection.ltr, @@ -1114,7 +1115,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { }); }); - testWidgets('splashing survives scrolling when keep-alive is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('splashing survives scrolling when keep-alive is enabled', (WidgetTester tester) async { Future runTest(bool keepAlive) async { await tester.pumpWidget( MaterialApp( @@ -1155,7 +1156,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { await runTest(false); }); - testWidgets('excludeFromSemantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('excludeFromSemantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( @@ -1184,7 +1185,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { semantics.dispose(); }); - testWidgets("ink response doesn't focus when disabled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ink response doesn't focus when disabled", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); final GlobalKey childKey = GlobalKey(); @@ -1220,7 +1221,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('ink response accepts focus when disabled in directional navigation mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink response accepts focus when disabled in directional navigation mode', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); final GlobalKey childKey = GlobalKey(); @@ -1266,7 +1267,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(focusNode.hasPrimaryFocus, isTrue); }); - testWidgets("ink response doesn't hover when disabled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ink response doesn't hover when disabled", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); final GlobalKey childKey = GlobalKey(); @@ -1319,7 +1320,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('When ink wells are nested, only the inner one is triggered by tap splash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When ink wells are nested, only the inner one is triggered by tap splash', (WidgetTester tester) async { final GlobalKey middleKey = GlobalKey(); final GlobalKey innerKey = GlobalKey(); Widget paddedInkWell({Key? key, Widget? child}) { @@ -1388,7 +1389,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { await gesture2.up(); }); - testWidgets('Reparenting parent should allow both inkwells to show splash afterwards', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reparenting parent should allow both inkwells to show splash afterwards', (WidgetTester tester) async { final GlobalKey middleKey = GlobalKey(); final GlobalKey innerKey = GlobalKey(); Widget paddedInkWell({Key? key, Widget? child}) { @@ -1482,7 +1483,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(material, paintsExactlyCountTimes(#drawCircle, 2)); }); - testWidgets('Parent inkwell does not block child inkwells from splashes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Parent inkwell does not block child inkwells from splashes', (WidgetTester tester) async { final GlobalKey middleKey = GlobalKey(); final GlobalKey innerKey = GlobalKey(); Widget paddedInkWell({Key? key, Widget? child}) { @@ -1530,7 +1531,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(material, paintsExactlyCountTimes(#drawCircle, 2)); }); - testWidgets('Parent inkwell can count the number of pressed children to prevent splash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Parent inkwell can count the number of pressed children to prevent splash', (WidgetTester tester) async { final GlobalKey parentKey = GlobalKey(); final GlobalKey leftKey = GlobalKey(); final GlobalKey rightKey = GlobalKey(); @@ -1623,7 +1624,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { await gesture3.up(); }); - testWidgets('When ink wells are reparented, the old parent can display splash while the new parent can not', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When ink wells are reparented, the old parent can display splash while the new parent can not', (WidgetTester tester) async { final GlobalKey innerKey = GlobalKey(); final GlobalKey leftKey = GlobalKey(); final GlobalKey rightKey = GlobalKey(); @@ -1738,7 +1739,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { await gesture2.up(); }); - testWidgets("Ink wells's splash starts before tap is confirmed and disappear after tap is canceled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Ink wells's splash starts before tap is confirmed and disappear after tap is canceled", (WidgetTester tester) async { final GlobalKey innerKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -1795,7 +1796,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(material, paintsExactlyCountTimes(#drawCircle, 1)); }); - testWidgets('disabled and hovered inkwell responds to mouse-exit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled and hovered inkwell responds to mouse-exit', (WidgetTester tester) async { int onHoverCount = 0; late bool hover; @@ -1858,7 +1859,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(hover, false); }); - testWidgets('hovered ink well draws a transparent highlight when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hovered ink well draws a transparent highlight when disabled', (WidgetTester tester) async { Widget buildFrame({ required bool enabled }) { return Material( child: Directionality( @@ -1908,7 +1909,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { }); - testWidgets('Changing InkWell.enabled should not trigger TextButton setState()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing InkWell.enabled should not trigger TextButton setState()', (WidgetTester tester) async { Widget buildFrame({ required bool enabled }) { return Material( child: Directionality( @@ -1942,7 +1943,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { await tester.pumpAndSettle(); }); - testWidgets('InkWell does not attach semantics handler for onTap if it was not provided an onTap handler', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell does not attach semantics handler for onTap if it was not provided an onTap handler', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Material( @@ -1985,7 +1986,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { )); }); - testWidgets('InkWell highlight should not survive after [onTapDown, onDoubleTap] sequence', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell highlight should not survive after [onTapDown, onDoubleTap] sequence', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(Directionality( @@ -2026,7 +2027,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(inkFeatures, paintsExactlyCountTimes(#drawRect, 0)); }); - testWidgets('InkWell splash should not survive after [onTapDown, onTapDown, onTapCancel, onDoubleTap] sequence', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell splash should not survive after [onTapDown, onTapDown, onTapCancel, onDoubleTap] sequence', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(Directionality( @@ -2071,7 +2072,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); }); - testWidgets('InkWell dispose statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell dispose statesController', (WidgetTester tester) async { int tapCount = 0; Widget buildFrame(MaterialStatesController? statesController) { return MaterialApp( @@ -2114,7 +2115,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(pressedCount, 2); }); - testWidgets('ink well overlayColor opacity fades from 0xff when hover ends', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ink well overlayColor opacity fades from 0xff when hover ends', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110266 await tester.pumpWidget(Material( child: Directionality( @@ -2152,7 +2153,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { expect(inkFeatures, paints..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0x8000ff00))); }); - testWidgets('InkWell secondary tap test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell secondary tap test', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(Directionality( @@ -2190,7 +2191,7 @@ testWidgets('InkResponse radius can be updated', (WidgetTester tester) async { }); // Regression test for https://github.com/flutter/flutter/issues/124328. - testWidgets('InkWell secondary tap should not draw a splash when no secondary callbacks are defined', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell secondary tap should not draw a splash when no secondary callbacks are defined', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Material( diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index 7fec3ace8afdf..41dec6d6c0f62 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; /// Adds the basic requirements for a Chip. @@ -101,7 +102,7 @@ void checkChipMaterialClipBehavior(WidgetTester tester, Clip clipBehavior) { } void main() { - testWidgets('InputChip.color resolves material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputChip.color resolves material states', (WidgetTester tester) async { const Color disabledSelectedColor = Color(0xffffff00); const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); @@ -157,7 +158,7 @@ void main() { expect(getMaterialBox(tester), paints..rrect(color: disabledSelectedColor)); }); - testWidgets('InputChip uses provided state color properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputChip uses provided state color properties', (WidgetTester tester) async { const Color disabledColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff0000ff); const Color selectedColor = Color(0xffff0000); @@ -196,7 +197,7 @@ void main() { expect(getMaterialBox(tester), paints..rrect(color: selectedColor)); }); - testWidgets('InputChip can be tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputChip can be tapped', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -211,7 +212,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('loses focus when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('loses focus when disabled', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'InputChip'); await tester.pumpWidget( wrapForChip( @@ -243,7 +244,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('cannot be traversed to when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cannot be traversed to when disabled', (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: 'InputChip 1'); final FocusNode focusNode2 = FocusNode(debugLabel: 'InputChip 2'); await tester.pumpWidget( @@ -278,7 +279,7 @@ void main() { expect(focusNode2.hasPrimaryFocus, isFalse); }); - testWidgets('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedInputChip(), @@ -290,7 +291,7 @@ void main() { ); }); - testWidgets('Input chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip check mark color is determined by platform brightness when dark', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedInputChip(), @@ -303,7 +304,7 @@ void main() { ); }); - testWidgets('Input chip check mark color can be set by the chip theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip check mark color can be set by the chip theme', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedInputChip(), @@ -316,7 +317,7 @@ void main() { ); }); - testWidgets('Input chip check mark color can be set by the chip constructor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip check mark color can be set by the chip constructor', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedInputChip(checkmarkColor: const Color(0xff00ff00)), @@ -328,7 +329,7 @@ void main() { ); }); - testWidgets('Input chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip check mark color is set by chip constructor even when a theme color is specified', (WidgetTester tester) async { await pumpCheckmarkChip( tester, chip: selectedInputChip(checkmarkColor: const Color(0xffff0000)), @@ -341,7 +342,7 @@ void main() { ); }); - testWidgets('InputChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputChip clipBehavior properly passes through to the Material', (WidgetTester tester) async { const Text label = Text('label'); await tester.pumpWidget(wrapForChip(child: const InputChip(label: label))); checkChipMaterialClipBehavior(tester, Clip.none); @@ -350,7 +351,7 @@ void main() { checkChipMaterialClipBehavior(tester, Clip.antiAlias); }); - testWidgets('Input chip has correct selected color when enabled - M3 defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip has correct selected color when enabled - M3 defaults', (WidgetTester tester) async { final ChipThemeData material3ChipDefaults = ThemeData(useMaterial3: true).chipTheme; await pumpCheckmarkChip( tester, @@ -362,7 +363,7 @@ void main() { expect(materialBox, paints..rrect(color: material3ChipDefaults.backgroundColor)); }); - testWidgets('Input chip has correct selected color when disabled - M3 defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input chip has correct selected color when disabled - M3 defaults', (WidgetTester tester) async { final ChipThemeData material3ChipDefaults = ThemeData(useMaterial3: true).chipTheme; await pumpCheckmarkChip( tester, diff --git a/packages/flutter/test/material/input_date_picker_form_field_test.dart b/packages/flutter/test/material/input_date_picker_form_field_test.dart index 076b3978f41a0..50275ffe79cca 100644 --- a/packages/flutter/test/material/input_date_picker_form_field_test.dart +++ b/packages/flutter/test/material/input_date_picker_form_field_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/clipboard_utils.dart'; class TestMaterialLocalizations extends DefaultMaterialLocalizations { @@ -97,7 +98,7 @@ void main() { group('InputDatePickerFormField', () { - testWidgets('Initial date is the default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); final DateTime initialDate = DateTime(2016, DateTime.february, 21); DateTime? inputDate; @@ -111,7 +112,7 @@ void main() { expect(inputDate, equals(initialDate)); }); - testWidgets('Changing initial date is reflected in text value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing initial date is reflected in text value', (WidgetTester tester) async { final DateTime initialDate = DateTime(2016, DateTime.february, 21); final DateTime updatedInitialDate = DateTime(2016, DateTime.february, 23); await tester.pumpWidget(inputDatePickerField( @@ -126,7 +127,7 @@ void main() { expect(textFieldController(tester).value.text, equals('02/23/2016')); }); - testWidgets('Valid date entry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Valid date entry', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -139,7 +140,7 @@ void main() { expect(inputDate, equals(DateTime(2016, DateTime.february, 21))); }); - testWidgets('Invalid text entry shows errorFormat text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Invalid text entry shows errorFormat text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -166,7 +167,7 @@ void main() { expect(find.text('That is not a date.'), findsOneWidget); }); - testWidgets('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -201,7 +202,7 @@ void main() { expect(find.text('Not in given range.'), findsOneWidget); }); - testWidgets('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -227,7 +228,7 @@ void main() { expect(find.text('Out of range.'), findsNothing); }); - testWidgets('Empty field shows hint text when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty field shows hint text when focused', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Focus on it await tester.tap(find.byType(TextField)); @@ -250,7 +251,7 @@ void main() { expect(textOpacity(tester, 'Enter some date'), equals(0.0)); }); - testWidgets('Label text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Label text', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Default label expect(find.text('Enter Date'), findsOneWidget); @@ -262,7 +263,7 @@ void main() { expect(find.text('Give me a date!'), findsOneWidget); }); - testWidgets('Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); // Fill the clipboard so that the Paste option is available in the text @@ -291,7 +292,7 @@ void main() { semantics.dispose(); }); - testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme is honored', (WidgetTester tester) async { const InputBorder border = InputBorder.none; await tester.pumpWidget(inputDatePickerField( theme: ThemeData.from(colorScheme: const ColorScheme.light()).copyWith( @@ -325,7 +326,7 @@ void main() { expect(containerColor, equals(Colors.transparent)); }); - testWidgets('Date text localization', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Date text localization', (WidgetTester tester) async { final Iterable> delegates = >[ TestMaterialLocalizationsDelegate(), DefaultWidgetsLocalizations.delegate, @@ -348,7 +349,7 @@ void main() { ); }); - testWidgets('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( @@ -363,7 +364,7 @@ void main() { expect(find.text(errorFormatText), findsNothing); }); - testWidgets('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index d18beb02620fb..dbc1cedeea598 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -52,7 +53,7 @@ class TestTextState extends State { } void main() { - testWidgets('ListTile geometry (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile geometry (LTR)', (WidgetTester tester) async { // See https://material.io/go/design-lists final Key leadingKey = GlobalKey(); @@ -174,7 +175,7 @@ void main() { testVerticalGeometry(hasIssue99933 ? 193 : 192.0); }); - testWidgets('ListTile geometry (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile geometry (RTL)', (WidgetTester tester) async { const double leftPadding = 10.0; const double rightPadding = 20.0; await tester.pumpWidget(MaterialApp( @@ -210,7 +211,7 @@ void main() { testHorizontalGeometry(); }); - testWidgets('ListTile.divideTiles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.divideTiles', (WidgetTester tester) async { final List titles = [ 'first', 'second', 'third' ]; await tester.pumpWidget(MaterialApp( @@ -233,17 +234,17 @@ void main() { expect(find.text('third'), findsOneWidget); }); - testWidgets('ListTile.divideTiles with empty list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.divideTiles with empty list', (WidgetTester tester) async { final Iterable output = ListTile.divideTiles(tiles: [], color: Colors.grey); expect(output, isEmpty); }); - testWidgets('ListTile.divideTiles with single item list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.divideTiles with single item list', (WidgetTester tester) async { final Iterable output = ListTile.divideTiles(tiles: const [SizedBox()], color: Colors.grey); expect(output.single, isA()); }); - testWidgets('ListTile.divideTiles only runs the generator once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.divideTiles only runs the generator once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/78879 int callCount = 0; Iterable generator() sync* { @@ -257,7 +258,7 @@ void main() { expect(callCount, 1); }); - testWidgets('ListTile semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -336,7 +337,7 @@ void main() { semantics.dispose(); }); - testWidgets('ListTile contentPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile contentPadding', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection) { return MediaQuery( data: const MediaQueryData(), @@ -378,7 +379,7 @@ void main() { expect(right('L'), 790.0); // 800 - contentPadding.start }); - testWidgets('ListTile wide leading Widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile wide leading Widget', (WidgetTester tester) async { const Key leadingKey = ValueKey('L'); Widget buildFrame(double leadingWidth, TextDirection textDirection) { @@ -444,7 +445,7 @@ void main() { expect(right('subtitle'), 800.0 - 72.0); }); - testWidgets('ListTile leading and trailing positions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile leading and trailing positions', (WidgetTester tester) async { // This test is based on the redlines at // https://material.io/design/components/lists.html#specs @@ -585,7 +586,7 @@ void main() { expect(tester.getRect(find.byType(Placeholder).at(3)), const Rect.fromLTWH(800.0 - 24.0 - 24.0, 328.0 + 16.0, 24.0, 24.0)); }); - testWidgets('ListTile leading icon height does not exceed ListTile height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile leading icon height does not exceed ListTile height', (WidgetTester tester) async { // regression test for https://github.com/flutter/flutter/issues/28765 const SizedBox oversizedWidget = SizedBox(height: 80.0, width: 24.0, child: Placeholder()); @@ -668,7 +669,7 @@ void main() { expect(tester.getRect(find.byType(Placeholder).at(1)), const Rect.fromLTWH(16.0, 88.0 + 8.0, 24.0, 56.0)); }); - testWidgets('ListTile trailing icon height does not exceed ListTile height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile trailing icon height does not exceed ListTile height', (WidgetTester tester) async { // regression test for https://github.com/flutter/flutter/issues/28765 const SizedBox oversizedWidget = SizedBox(height: 80.0, width: 24.0, child: Placeholder()); @@ -757,7 +758,7 @@ void main() { expect(tester.getRect(find.byType(Placeholder).at(1)), const Rect.fromLTWH(800.0 - 24.0 - 24.0, 88.0 + 8.0, 24.0, 56.0)); }); - testWidgets('ListTile only accepts focus when enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile only accepts focus when enabled', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( @@ -804,7 +805,7 @@ void main() { expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isFalse); }); - testWidgets('ListTile can autofocus unless disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile can autofocus unless disabled.', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( @@ -849,7 +850,7 @@ void main() { expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isFalse); }); - testWidgets('ListTile is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'ListTile'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; Widget buildApp({bool enabled = true}) { @@ -906,7 +907,7 @@ void main() { ); }); - testWidgets('ListTile can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; Widget buildApp({bool enabled = true}) { return MaterialApp( @@ -989,7 +990,7 @@ void main() { ); }); - testWidgets('ListTile can be splashed and has correct splash color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile can be splashed and has correct splash color', (WidgetTester tester) async { final Widget buildApp = MaterialApp( theme: ThemeData(useMaterial3: false), home: Material( @@ -1014,7 +1015,7 @@ void main() { await gesture.up(); }); - testWidgets('ListTile can be triggered by keyboard shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile can be triggered by keyboard shortcuts', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Key tileKey = Key('ListTile'); bool tapped = false; @@ -1053,7 +1054,7 @@ void main() { expect(tapped, isTrue); }); - testWidgets('ListTile responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( @@ -1090,7 +1091,7 @@ void main() { expect(box.size, equals(const Size(800, 44))); }); - testWidgets('ListTile shape is painted correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile shape is painted correctly', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/63877 const ShapeBorder rectShape = RoundedRectangleBorder(); const ShapeBorder stadiumShape = StadiumBorder(); @@ -1130,7 +1131,7 @@ void main() { ); }); - testWidgets('ListTile changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile changes mouse cursor when hovered', (WidgetTester tester) async { // Test ListTile() constructor await tester.pumpWidget( MaterialApp( @@ -1208,7 +1209,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('ListTile onFocusChange callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile onFocusChange callback', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'ListTile Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -1236,7 +1237,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('ListTile respects tileColor & selectedTileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile respects tileColor & selectedTileColor', (WidgetTester tester) async { bool isSelected = false; final Color tileColor = Colors.green.shade500; final Color selectedTileColor = Colors.red.shade500; @@ -1274,7 +1275,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('ListTile shows Material ripple effects on top of tileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile shows Material ripple effects on top of tileColor', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/73616 final Color tileColor = Colors.red.shade500; @@ -1309,7 +1310,7 @@ void main() { ); }); - testWidgets('ListTile default tile color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile default tile color', (WidgetTester tester) async { bool isSelected = false; final ThemeData theme = ThemeData(useMaterial3: true); const Color defaultColor = Colors.transparent; @@ -1344,7 +1345,7 @@ void main() { expect(find.byType(Material), paints..rect(color: defaultColor)); }); - testWidgets('Default tile color when ListTile is wrapped with an elevated widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default tile color when ListTile is wrapped with an elevated widget', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117700 bool isSelected = false; final ThemeData theme = ThemeData(useMaterial3: true); @@ -1397,7 +1398,7 @@ void main() { expect(find.byType(Material), paints..rect(color: defaultColor)); }); - testWidgets('ListTile layout at zero size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile layout at zero size', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66636 const Key key = Key('key'); @@ -1428,7 +1429,7 @@ void main() { feedback.dispose(); }); - testWidgets('ListTile with disabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile with disabled feedback', (WidgetTester tester) async { const bool enableFeedback = false; await tester.pumpWidget( @@ -1449,7 +1450,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('ListTile with enabled feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile with enabled feedback', (WidgetTester tester) async { const bool enableFeedback = true; await tester.pumpWidget( @@ -1470,7 +1471,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('ListTile with enabled feedback by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile with enabled feedback by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( @@ -1489,7 +1490,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('ListTile with disabled feedback using ListTileTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile with disabled feedback using ListTileTheme', (WidgetTester tester) async { const bool enableFeedbackTheme = false; await tester.pumpWidget( @@ -1512,7 +1513,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('ListTile.enableFeedback overrides ListTileTheme.enableFeedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.enableFeedback overrides ListTileTheme.enableFeedback', (WidgetTester tester) async { const bool enableFeedbackTheme = false; const bool enableFeedback = true; @@ -1537,7 +1538,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('ListTile.mouseCursor overrides ListTileTheme.mouseCursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.mouseCursor overrides ListTileTheme.mouseCursor', (WidgetTester tester) async { final Key tileKey = UniqueKey(); await tester.pumpWidget( @@ -1565,7 +1566,7 @@ void main() { }); }); - testWidgets('ListTile horizontalTitleGap = 0.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile horizontalTitleGap = 0.0', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection, { double? themeHorizontalTitleGap, double? widgetHorizontalTitleGap }) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1617,7 +1618,7 @@ void main() { expect(right('title'), 760.0); }); - testWidgets('ListTile horizontalTitleGap = (default) && ListTile minLeadingWidth = (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile horizontalTitleGap = (default) && ListTile minLeadingWidth = (default)', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1653,7 +1654,7 @@ void main() { expect(right('title'), 744.0); }); - testWidgets('ListTile horizontalTitleGap with visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile horizontalTitleGap with visualDensity', (WidgetTester tester) async { Widget buildFrame({ double? horizontalTitleGap, VisualDensity? visualDensity, @@ -1698,7 +1699,7 @@ void main() { expect(left('title'), 42.0); }); - testWidgets('ListTile minVerticalPadding = 80.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile minVerticalPadding = 80.0', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection, { double? themeMinVerticalPadding, double? widgetMinVerticalPadding }) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1744,7 +1745,7 @@ void main() { expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 184.0)); }); - testWidgets('ListTile minLeadingWidth = 60.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile minLeadingWidth = 60.0', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection, { double? themeMinLeadingWidth, double? widgetMinLeadingWidth }) { return MediaQuery( data: const MediaQueryData(), @@ -1799,7 +1800,7 @@ void main() { expect(right('title'), 708.0); }); - testWidgets('colors are applied to leading and trailing text widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('colors are applied to leading and trailing text widgets', (WidgetTester tester) async { final Key leadingKey = UniqueKey(); final Key trailingKey = UniqueKey(); @@ -1851,7 +1852,7 @@ void main() { expect(textColor(trailingKey), theme.disabledColor); }); - testWidgets('selected, enabled ListTile default icon color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selected, enabled ListTile default icon color', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colorScheme = theme.colorScheme; final Key leadingKey = UniqueKey(); @@ -1891,7 +1892,7 @@ void main() { expect(iconColor(trailingKey), colorScheme.onSurfaceVariant); }); - testWidgets('ListTile font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile font size', (WidgetTester tester) async { Widget buildFrame() { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1924,7 +1925,7 @@ void main() { expect(trailing.text.style!.fontSize, 11.0); }); - testWidgets('ListTile text color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile text color', (WidgetTester tester) async { Widget buildFrame() { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1959,7 +1960,7 @@ void main() { expect(trailing.text.style!.color, theme.colorScheme.onSurfaceVariant); }); - testWidgets('Default ListTile debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ListTile debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ListTile().debugFillProperties(builder); @@ -1971,7 +1972,7 @@ void main() { expect(description, []); }); - testWidgets('ListTile implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ListTile( leading: Text('leading'), @@ -2044,7 +2045,7 @@ void main() { ); }); - testWidgets('ListTile.textColor respects MaterialStateColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.textColor respects MaterialStateColor', (WidgetTester tester) async { bool enabled = false; bool selected = false; const Color defaultColor = Colors.blue; @@ -2100,7 +2101,7 @@ void main() { expect(title.text.style!.color, selectedColor); }); - testWidgets('ListTile.iconColor respects MaterialStateColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.iconColor respects MaterialStateColor', (WidgetTester tester) async { bool enabled = false; bool selected = false; const Color defaultColor = Colors.blue; @@ -2155,7 +2156,7 @@ void main() { expect(iconColor(leadingKey), selectedColor); }); - testWidgets('ListTile.iconColor respects iconColor property with icon buttons Material 3 in presence of IconButtonTheme override', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.iconColor respects iconColor property with icon buttons Material 3 in presence of IconButtonTheme override', (WidgetTester tester) async { const Color iconButtonThemeColor = Colors.blue; const Color listTileIconColor = Colors.green; const Icon leadingIcon = Icon(Icons.favorite); @@ -2199,7 +2200,7 @@ void main() { expect(getIconStyle(tester, trailingIcon.icon!)?.color, listTileIconColor); }); - testWidgets('ListTile.dense does not throw assertion', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile.dense does not throw assertion', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/pull/116908 Widget buildFrame({required bool useMaterial3}) { @@ -2227,7 +2228,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('titleAlignment position with title widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('titleAlignment position with title widget', (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const double leadingHeight = 24.0; @@ -2326,7 +2327,7 @@ void main() { expect(trailingOffset.dy - tileOffset.dy, bottomPosition); }); - testWidgets('titleAlignment position with title and subtitle widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('titleAlignment position with title and subtitle widgets', (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const double leadingHeight = 24.0; @@ -2426,7 +2427,7 @@ void main() { expect(trailingOffset.dy - tileOffset.dy, bottomPosition); }); - testWidgets("ListTile.isThreeLine updates ListTileTitleAlignment.threeLine's alignment", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ListTile.isThreeLine updates ListTileTitleAlignment.threeLine's alignment", (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const double leadingHeight = 24.0; @@ -2486,7 +2487,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('ListTile geometry (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile geometry (LTR)', (WidgetTester tester) async { // See https://material.io/go/design-lists final Key leadingKey = GlobalKey(); @@ -2634,7 +2635,7 @@ void main() { testVerticalGeometry(128.0); }); - testWidgets('ListTile geometry (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile geometry (RTL)', (WidgetTester tester) async { const double leftPadding = 10.0; const double rightPadding = 20.0; await tester.pumpWidget(MaterialApp( @@ -2670,7 +2671,7 @@ void main() { testHorizontalGeometry(); }); - testWidgets('ListTile leading and trailing positions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile leading and trailing positions', (WidgetTester tester) async { // This test is based on the redlines at // https://material.io/design/components/lists.html#specs @@ -2905,7 +2906,7 @@ void main() { expect(tester.getRect(find.byType(Placeholder).at(3)), const Rect.fromLTWH(800.0 - 24.0 - 16.0, 216.0 + 16.0, 24.0, 24.0)); }); - testWidgets('ListTile leading icon height does not exceed ListTile height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile leading icon height does not exceed ListTile height', (WidgetTester tester) async { // regression test for https://github.com/flutter/flutter/issues/28765 const SizedBox oversizedWidget = SizedBox(height: 80.0, width: 24.0, child: Placeholder()); @@ -3078,7 +3079,7 @@ void main() { expect(tester.getRect(find.byType(Placeholder).at(1)), const Rect.fromLTWH(16.0, 88.0 + 16.0, 24.0, 56.0)); }); - testWidgets('ListTile trailing icon height does not exceed ListTile height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile trailing icon height does not exceed ListTile height', (WidgetTester tester) async { // regression test for https://github.com/flutter/flutter/issues/28765 const SizedBox oversizedWidget = SizedBox(height: 80.0, width: 24.0, child: Placeholder()); @@ -3251,7 +3252,7 @@ void main() { expect(tester.getRect(find.byType(Placeholder).at(1)), const Rect.fromLTWH(800.0 - 16.0 - 24.0, 88.0 + 16.0, 24.0, 56.0)); }); - testWidgets('ListTile wide leading Widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile wide leading Widget', (WidgetTester tester) async { const Key leadingKey = ValueKey('L'); Widget buildFrame(double leadingWidth, TextDirection textDirection) { @@ -3316,7 +3317,7 @@ void main() { expect(right('subtitle'), 800.0 - 72.0); }); - testWidgets('ListTile horizontalTitleGap = 0.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile horizontalTitleGap = 0.0', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection, { double? themeHorizontalTitleGap, double? widgetHorizontalTitleGap }) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -3368,7 +3369,7 @@ void main() { expect(right('title'), 744.0); }); - testWidgets('ListTile horizontalTitleGap = (default) && ListTile minLeadingWidth = (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile horizontalTitleGap = (default) && ListTile minLeadingWidth = (default)', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -3404,7 +3405,7 @@ void main() { expect(right('title'), 728.0); }); - testWidgets('ListTile horizontalTitleGap with visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile horizontalTitleGap with visualDensity', (WidgetTester tester) async { Widget buildFrame({ double? horizontalTitleGap, VisualDensity? visualDensity, @@ -3449,7 +3450,7 @@ void main() { expect(left('title'), 58.0); }); - testWidgets('ListTile minVerticalPadding = 80.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile minVerticalPadding = 80.0', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection, { double? themeMinVerticalPadding, double? widgetMinVerticalPadding }) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -3495,7 +3496,7 @@ void main() { expect(tester.getSize(find.byType(ListTile)), const Size(800.0, 176.0)); }); - testWidgets('ListTile font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile font size', (WidgetTester tester) async { Widget buildFrame({ bool dense = false, bool enabled = true, @@ -3573,7 +3574,7 @@ void main() { expect(trailing.text.style!.fontSize, 14.0); }); - testWidgets('ListTile text color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile text color', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); Widget buildFrame({ bool dense = false, @@ -3628,7 +3629,7 @@ void main() { expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color); }); - testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/77004 const ColorScheme lightColorScheme = ColorScheme.light(); @@ -3688,7 +3689,7 @@ void main() { expect(iconColor(trailingKey), Colors.white); }); - testWidgets('ListTile default tile color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile default tile color', (WidgetTester tester) async { bool isSelected = false; const Color defaultColor = Colors.transparent; @@ -3722,7 +3723,7 @@ void main() { expect(find.byType(Material), paints..rect(color: defaultColor)); }); - testWidgets('titleAlignment position with title widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('titleAlignment position with title widget', (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const double leadingHeight = 24.0; @@ -3821,7 +3822,7 @@ void main() { expect(trailingOffset.dy - tileOffset.dy, bottomPosition); }); - testWidgets('titleAlignment position with title and subtitle widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('titleAlignment position with title and subtitle widgets', (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const double leadingHeight = 24.0; @@ -3921,7 +3922,7 @@ void main() { expect(trailingOffset.dy - tileOffset.dy, bottomPosition); }); - testWidgets("ListTile.isThreeLine updates ListTileTitleAlignment.threeLine's alignment", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ListTile.isThreeLine updates ListTileTitleAlignment.threeLine's alignment", (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const double leadingHeight = 24.0; diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index c18921ba8f932..88bfddfb3254f 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; class TestIcon extends StatefulWidget { @@ -80,7 +81,7 @@ void main() { expect(themeData.titleAlignment, null); }); - testWidgets('Default ListTileThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ListTileThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ListTileThemeData().debugFillProperties(builder); @@ -92,7 +93,7 @@ void main() { expect(description, []); }); - testWidgets('ListTileThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ListTileThemeData( dense: true, @@ -147,7 +148,7 @@ void main() { ); }); - testWidgets('ListTileTheme backwards compatibility constructor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileTheme backwards compatibility constructor', (WidgetTester tester) async { late ListTileThemeData theme; await tester.pumpWidget( @@ -197,7 +198,7 @@ void main() { expect(theme.mouseCursor, MaterialStateMouseCursor.clickable); }); - testWidgets('ListTileTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileTheme', (WidgetTester tester) async { final Key listTileKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key subtitleKey = UniqueKey(); @@ -333,7 +334,7 @@ void main() { expect(trailingOffset.dy - titleOffset.dy, 6); }); - testWidgets('ListTileTheme colors are applied to leading and trailing text widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileTheme colors are applied to leading and trailing text widgets', (WidgetTester tester) async { final Key leadingKey = UniqueKey(); final Key trailingKey = UniqueKey(); @@ -393,7 +394,7 @@ void main() { expect(textColor(trailingKey), theme.disabledColor); }); - testWidgets( + testWidgetsWithLeakTracking( "ListTile respects ListTileTheme's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle", (WidgetTester tester) async { final ThemeData theme = ThemeData( @@ -436,7 +437,7 @@ void main() { expect(trailing.text.style!.fontSize, 15.0); }); - testWidgets( + testWidgetsWithLeakTracking( "ListTile's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle are overridden by ListTile properties", (WidgetTester tester) async { final ThemeData theme = ThemeData( @@ -486,7 +487,7 @@ void main() { expect(trailing.text.style!.fontSize, 18.0); }); - testWidgets("ListTile respects ListTileTheme's tileColor & selectedTileColor", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ListTile respects ListTileTheme's tileColor & selectedTileColor", (WidgetTester tester) async { late ListTileThemeData theme; bool isSelected = false; @@ -526,7 +527,7 @@ void main() { expect(find.byType(Material), paints..rect(color: theme.selectedTileColor)); }); - testWidgets("ListTileTheme's tileColor & selectedTileColor are overridden by ListTile properties", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ListTileTheme's tileColor & selectedTileColor are overridden by ListTile properties", (WidgetTester tester) async { bool isSelected = false; final Color tileColor = Colors.green.shade500; final Color selectedTileColor = Colors.red.shade500; @@ -568,7 +569,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/106303 final GlobalKey scaffoldKey = GlobalKey(); @@ -601,7 +602,7 @@ void main() { expect(inkWellBorder, shapeBorder); }); - testWidgets('ListTile respects MaterialStateColor LisTileTheme.textColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile respects MaterialStateColor LisTileTheme.textColor', (WidgetTester tester) async { bool enabled = false; bool selected = false; const Color defaultColor = Colors.blue; @@ -661,7 +662,7 @@ void main() { expect(title.text.style!.color, selectedColor); }); - testWidgets('ListTile respects MaterialStateColor LisTileTheme.iconColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile respects MaterialStateColor LisTileTheme.iconColor', (WidgetTester tester) async { bool enabled = false; bool selected = false; const Color defaultColor = Colors.blue; @@ -720,7 +721,7 @@ void main() { expect(iconColor(leadingKey), selectedColor); }); - testWidgets('ListTileThemeData copyWith overrides all properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileThemeData copyWith overrides all properties', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/119734 const ListTileThemeData original = ListTileThemeData( @@ -782,7 +783,7 @@ void main() { expect(copy.titleAlignment, ListTileTitleAlignment.top); }); - testWidgets('ListTileTheme.titleAlignment is overridden by ListTile.titleAlignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileTheme.titleAlignment is overridden by ListTile.titleAlignment', (WidgetTester tester) async { final Key leadingKey = GlobalKey(); final Key trailingKey = GlobalKey(); const String titleText = '\nHeadline Text\n'; @@ -818,7 +819,7 @@ void main() { expect(trailingOffset.dy - tileOffset.dy, 8.0); }); - testWidgets('ListTileTheme.merge supports all properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileTheme.merge supports all properties', (WidgetTester tester) async { Widget buildFrame() { return MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart index 9e303fef9fad3..c6695ebdfc7fc 100644 --- a/packages/flutter/test/material/localizations_test.dart +++ b/packages/flutter/test/material/localizations_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('English translations exist for all MaterialLocalizations properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('English translations exist for all MaterialLocalizations properties', (WidgetTester tester) async { const MaterialLocalizations localizations = DefaultMaterialLocalizations(); expect(localizations.openAppDrawerTooltip, isNotNull); @@ -166,7 +168,7 @@ void main() { expect(localizations.licensesPackageDetailText(100).contains(r'$licensesCount'), isFalse); }); - testWidgets('MaterialLocalizations.of throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialLocalizations.of throws', (WidgetTester tester) async { final GlobalKey noLocalizationsAvailable = GlobalKey(); final GlobalKey localizationsAvailable = GlobalKey(); @@ -190,7 +192,7 @@ void main() { expect(MaterialLocalizations.of(localizationsAvailable.currentContext!), isA()); }); - testWidgets("parseCompactDate doesn't throw an exception on invalid text", (WidgetTester tester) async { + testWidgetsWithLeakTracking("parseCompactDate doesn't throw an exception on invalid text", (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/126397. final GlobalKey localizations = GlobalKey(); diff --git a/packages/flutter/test/material/magnifier_test.dart b/packages/flutter/test/material/magnifier_test.dart index 9abf8906b2fcd..f700ca40c95ae 100644 --- a/packages/flutter/test/material/magnifier_test.dart +++ b/packages/flutter/test/material/magnifier_test.dart @@ -9,6 +9,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { final MagnifierController magnifierController = MagnifierController(); const Rect reasonableTextField = Rect.fromLTRB(50, 100, 200, 100); @@ -110,7 +112,7 @@ void main() { group('magnifier', () { group('position', () { - testWidgets( + testWidgetsWithLeakTracking( 'should be at gesture position if does not violate any positioning rules', (WidgetTester tester) async { final Key textField = UniqueKey(); @@ -166,7 +168,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'should never move outside the right bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -199,7 +201,7 @@ void main() { lessThanOrEqualTo(reasonableTextField.right)); }); - testWidgets( + testWidgetsWithLeakTracking( 'should never move outside the left bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -231,7 +233,7 @@ void main() { greaterThanOrEqualTo(reasonableTextField.left)); }); - testWidgets('should position vertically at the center of the line', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should position vertically at the center of the line', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), )); @@ -254,7 +256,7 @@ void main() { reasonableTextField.center.dy - basicOffset.dy); }); - testWidgets('should reposition vertically if mashed against the ceiling', + testWidgetsWithLeakTracking('should reposition vertically if mashed against the ceiling', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = Rect.fromPoints(Offset.zero, const Offset(200, 0)); @@ -289,7 +291,7 @@ void main() { return magnifier.additionalFocalPointOffset; } - testWidgets( + testWidgetsWithLeakTracking( 'should shift focal point so that the lens sees nothing out of bounds', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( @@ -317,7 +319,7 @@ void main() { lessThan(reasonableTextField.left)); }); - testWidgets( + testWidgetsWithLeakTracking( 'focal point should shift if mashed against the top to always point to text', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = @@ -354,7 +356,7 @@ void main() { return animatedPositioned.duration.compareTo(Duration.zero) != 0; } - testWidgets('should not be animated on the initial state', + testWidgetsWithLeakTracking('should not be animated on the initial state', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -379,7 +381,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgets('should not be animated on horizontal shifts', + testWidgetsWithLeakTracking('should not be animated on horizontal shifts', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -413,7 +415,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgets('should be animated on vertical shifts', + testWidgetsWithLeakTracking('should be animated on vertical shifts', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); @@ -449,7 +451,7 @@ void main() { expect(getIsAnimated(tester), true); }); - testWidgets('should stop being animated when timer is up', + testWidgetsWithLeakTracking('should stop being animated when timer is up', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); diff --git a/packages/flutter/test/material/material_button_test.dart b/packages/flutter/test/material/material_button_test.dart index 1b329a19485c5..c9718923ab811 100644 --- a/packages/flutter/test/material/material_button_test.dart +++ b/packages/flutter/test/material/material_button_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; @@ -15,7 +16,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('MaterialButton defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton defaults', (WidgetTester tester) async { final Finder rawButtonMaterial = find.descendant( of: find.byType(MaterialButton), matching: find.byType(Material), @@ -98,7 +99,7 @@ void main() { expect(material.type, MaterialType.transparency); }); - testWidgets('Does MaterialButton work with hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does MaterialButton work with hover', (WidgetTester tester) async { const Color hoverColor = Color(0xff001122); await tester.pumpWidget( @@ -121,7 +122,7 @@ void main() { expect(inkFeatures, paints..rect(color: hoverColor)); }); - testWidgets('Does MaterialButton work with focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does MaterialButton work with focus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); final FocusNode focusNode = FocusNode(debugLabel: 'MaterialButton Node'); @@ -145,7 +146,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('MaterialButton elevation and colors have proper precedence', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton elevation and colors have proper precedence', (WidgetTester tester) async { const double elevation = 10.0; const double focusElevation = 11.0; const double hoverElevation = 12.0; @@ -217,7 +218,7 @@ void main() { await gesture2.up(); }); - testWidgets("MaterialButton's disabledColor takes precedence over its default disabled color.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("MaterialButton's disabledColor takes precedence over its default disabled color.", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/30012. final Finder rawButtonMaterial = find.descendant( @@ -267,7 +268,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('MaterialButton gets focus when autofocus is set.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton gets focus when autofocus is set.', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'MaterialButton'); await tester.pumpWidget( MaterialApp( @@ -301,7 +302,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isTrue); }); - testWidgets('MaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { bool wasPressed; Finder materialButton; @@ -345,7 +346,7 @@ void main() { expect(tester.widget(materialButton).enabled, false); }); - testWidgets('MaterialButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -376,7 +377,7 @@ void main() { expect(didLongPressButton, isTrue); }); - testWidgets('MaterialButton changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -430,7 +431,7 @@ void main() { // This test is very similar to the '...explicit splashColor and highlightColor' test // in icon_button_test.dart. If you change this one, you may want to also change that one. - testWidgets('MaterialButton with explicit splashColor and highlightColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton with explicit splashColor and highlightColor', (WidgetTester tester) async { const Color directSplashColor = Color(0xFF000011); const Color directHighlightColor = Color(0xFF000011); @@ -544,7 +545,7 @@ void main() { await gesture.up(); }); - testWidgets('MaterialButton has no clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton has no clip by default', (WidgetTester tester) async { final GlobalKey buttonKey = GlobalKey(); final Widget buttonWidget = Center( child: MaterialButton( @@ -571,7 +572,7 @@ void main() { ); }); - testWidgets('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled MaterialButton has same semantic size as enabled and exposes disabled semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const Rect expectedButtonSize = Rect.fromLTRB(0.0, 0.0, 116.0, 48.0); @@ -658,7 +659,7 @@ void main() { semantics.dispose(); }); - testWidgets('MaterialButton minWidth and height parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton minWidth and height parameters', (WidgetTester tester) async { Widget buildFrame({ double? minWidth, double? height, EdgeInsets padding = EdgeInsets.zero, Widget? child }) { return Directionality( textDirection: TextDirection.ltr, @@ -725,7 +726,7 @@ void main() { expect(tester.getSize(find.byType(MaterialButton)), const Size(18.0, 18.0)); }); - testWidgets('MaterialButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { final Key key1 = UniqueKey(); await tester.pumpWidget( Theme( @@ -765,7 +766,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(88.0, 36.0)); }); - testWidgets('MaterialButton shape overrides ButtonTheme shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton shape overrides ButtonTheme shape', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/29146 await tester.pumpWidget( Directionality( @@ -785,7 +786,7 @@ void main() { expect(tester.widget(rawButtonMaterial).shape, const StadiumBorder()); }); - testWidgets('MaterialButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key childKey = Key('test child'); @@ -846,7 +847,7 @@ void main() { expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); }); - testWidgets('disabledElevation is passed to RawMaterialButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabledElevation is passed to RawMaterialButton', (WidgetTester tester) async { const double disabledElevation = 16; final Finder rawMaterialButtonFinder = find.descendant( @@ -869,7 +870,7 @@ void main() { expect(rawMaterialButton.disabledElevation, equals(disabledElevation)); }); - testWidgets('MaterialButton.disabledElevation defaults to 0.0 when not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialButton.disabledElevation defaults to 0.0 when not provided', (WidgetTester tester) async { final Finder rawMaterialButtonFinder = find.descendant( of: find.byType(MaterialButton), matching: find.byType(RawMaterialButton), diff --git a/packages/flutter/test/material/material_state_mixin_test.dart b/packages/flutter/test/material/material_state_mixin_test.dart index be13d84dcd28c..684fe32e34fc7 100644 --- a/packages/flutter/test/material/material_state_mixin_test.dart +++ b/packages/flutter/test/material/material_state_mixin_test.dart @@ -7,6 +7,8 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + const Key key = Key('testContainer'); const Color trueColor = Colors.red; const Color falseColor = Colors.green; @@ -83,7 +85,7 @@ void main() { expect(tester.widget(find.byKey(key)).color, falseColor); } - testWidgets('MaterialState.pressed is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.pressed is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -93,7 +95,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.focused is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.focused is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -103,7 +105,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.hovered is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.hovered is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -113,7 +115,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.disabled is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.disabled is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -123,7 +125,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.selected is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.selected is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -133,7 +135,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.scrolledUnder is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.scrolledUnder is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -143,7 +145,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.dragged is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.dragged is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, @@ -153,7 +155,7 @@ void main() { await verify(tester, widget, controller); }); - testWidgets('MaterialState.error is tracked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialState.error is tracked', (WidgetTester tester) async { final StreamController controller = StreamController(); final _MyWidget widget = _MyWidget( controller: controller, diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index 003ff987ed27c..e5a8536754946 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { void onPressed(TestMenu item) {} @@ -52,7 +54,7 @@ void main() { expect(identical(MenuBarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('theme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -105,7 +107,7 @@ void main() { expect(subMenuMaterial.color, equals(Colors.green)); }); - testWidgets('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_style_test.dart b/packages/flutter/test/material/menu_style_test.dart index 9f1de88855344..acc6d2079761f 100644 --- a/packages/flutter/test/material/menu_style_test.dart +++ b/packages/flutter/test/material/menu_style_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { Finder findMenuPanels() { return find.byWidgetPredicate((Widget widget) => widget.runtimeType.toString() == '_MenuPanel'); @@ -41,7 +43,7 @@ void main() { expect(identical(MenuStyle.lerp(data, data, 0.5), data), true); }); - testWidgets('fixedSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fixedSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -84,7 +86,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgets('maximumSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maximumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -127,7 +129,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgets('minimumSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('minimumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -170,7 +172,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(300.0, 300.0))); }); - testWidgets('Material parameters are honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material parameters are honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -236,7 +238,7 @@ void main() { expect(panelPadding.padding, equals(const EdgeInsets.all(20))); }); - testWidgets('visual density', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visual density', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index f6fb5d324e3e4..868d4eb7f93de 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { void onPressed(TestMenu item) {} @@ -52,7 +54,7 @@ void main() { expect(identical(MenuThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('theme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -105,7 +107,7 @@ void main() { expect(subMenuMaterial.color, equals(Colors.red)); }); - testWidgets('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/mergeable_material_test.dart b/packages/flutter/test/material/mergeable_material_test.dart index 08b3fc735da94..b50f9de0e0a21 100644 --- a/packages/flutter/test/material/mergeable_material_test.dart +++ b/packages/flutter/test/material/mergeable_material_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; enum RadiusType { @@ -65,7 +66,7 @@ BorderRadius? getBorderRadius(WidgetTester tester, int index) { } void main() { - testWidgets('MergeableMaterial empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial empty', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -80,7 +81,7 @@ void main() { expect(box.size.height, equals(0)); }); - testWidgets('MergeableMaterial update slice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial update slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -128,7 +129,7 @@ void main() { expect(box.size.height, equals(200.0)); }); - testWidgets('MergeableMaterial swap slices', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial swap slices', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -199,7 +200,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round); }); - testWidgets('MergeableMaterial paints shadows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial paints shadows', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( MaterialApp( @@ -234,7 +235,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( const MaterialApp( @@ -264,7 +265,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('MergeableMaterial merge gap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial merge gap', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -341,7 +342,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round); }); - testWidgets('MergeableMaterial separate slices', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial separate slices', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -418,7 +419,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round); }); - testWidgets('MergeableMaterial separate merge separate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial separate merge separate', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -577,7 +578,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round); }); - testWidgets('MergeableMaterial insert slice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial insert slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -652,7 +653,7 @@ void main() { matches(getBorderRadius(tester, 2), RadiusType.Sharp, RadiusType.Round); }); - testWidgets('MergeableMaterial remove slice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial remove slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -728,7 +729,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round); }); - testWidgets('MergeableMaterial insert chunk', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial insert chunk', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -817,7 +818,7 @@ void main() { matches(getBorderRadius(tester, 2), RadiusType.Round, RadiusType.Round); }); - testWidgets('MergeableMaterial remove chunk', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial remove chunk', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -905,7 +906,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Sharp, RadiusType.Round); }); - testWidgets('MergeableMaterial replace gap with chunk', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial replace gap with chunk', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -997,7 +998,7 @@ void main() { matches(getBorderRadius(tester, 2), RadiusType.Round, RadiusType.Round); }); - testWidgets('MergeableMaterial replace chunk with gap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial replace chunk with gap', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -1088,7 +1089,7 @@ void main() { matches(getBorderRadius(tester, 1), RadiusType.Round, RadiusType.Round); }); - testWidgets('MergeableMaterial insert and separate slice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial insert and separate slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -1168,7 +1169,7 @@ void main() { ); } - testWidgets('MergeableMaterial dividers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial dividers', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1293,7 +1294,7 @@ void main() { expect(isDivider(boxes[offset + 3], true, false), isTrue); }); - testWidgets('MergeableMaterial respects dividerColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial respects dividerColor', (WidgetTester tester) async { const Color dividerColor = Colors.red; await tester.pumpWidget( const MaterialApp( @@ -1330,7 +1331,7 @@ void main() { expect(decoration.border!.top.color, dividerColor); }); - testWidgets('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { const Color themeCardColor = Colors.red; const Color materialSliceColor = Colors.green; diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index 201b6a246ca23..0e1ce6dafb091 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -12,6 +12,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('copyWith, ==, hashCode basics', () { expect(const NavigationBarThemeData(), const NavigationBarThemeData().copyWith()); @@ -24,7 +26,7 @@ void main() { expect(identical(NavigationBarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationBarThemeData().debugFillProperties(builder); @@ -36,7 +38,7 @@ void main() { expect(description, []); }); - testWidgets('Custom debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationBarThemeData( height: 200.0, @@ -68,7 +70,7 @@ void main() { expect(description[7], 'labelBehavior: NavigationDestinationLabelBehavior.alwaysHide'); }); - testWidgets('NavigationBarThemeData values are used when no NavigationBar properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationBarThemeData values are used when no NavigationBar properties are specified', (WidgetTester tester) async { const double height = 200.0; const Color backgroundColor = Color(0x00000001); const double elevation = 42.0; @@ -140,7 +142,7 @@ void main() { expect(_labelBehavior(tester), labelBehavior); }); - testWidgets('NavigationBar values take priority over NavigationBarThemeData values when both properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationBar values take priority over NavigationBarThemeData values when both properties are specified', (WidgetTester tester) async { const double height = 200.0; const Color backgroundColor = Color(0x00000001); const double elevation = 42.0; @@ -174,7 +176,7 @@ void main() { expect(_labelBehavior(tester), labelBehavior); }); - testWidgets('Custom label style renders ink ripple properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom label style renders ink ripple properly', (WidgetTester tester) async { Widget buildWidget({ NavigationDestinationLabelBehavior? labelBehavior }) { return MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index cde4e4eb0eace..2e8befad6de7f 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('Navigation drawer updates destinations when tapped', + testWidgetsWithLeakTracking('Navigation drawer updates destinations when tapped', (WidgetTester tester) async { int mutatedIndex = -1; final GlobalKey scaffoldKey = GlobalKey(); @@ -49,7 +51,7 @@ void main() { expect(mutatedIndex, 0); }); - testWidgets('NavigationDrawer can update background color', + testWidgetsWithLeakTracking('NavigationDrawer can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; final GlobalKey scaffoldKey = GlobalKey(); @@ -82,7 +84,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgets('NavigationDrawer can update elevation', + testWidgetsWithLeakTracking('NavigationDrawer can update elevation', (WidgetTester tester) async { const double elevation = 42.0; final GlobalKey scaffoldKey = GlobalKey(); @@ -114,7 +116,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(elevation)); }); - testWidgets( + testWidgetsWithLeakTracking( 'NavigationDrawer uses proper defaults when no parameters are given', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -163,7 +165,7 @@ void main() { expect(iconBox.size, const Size(24.0, 24.0)); }); - testWidgets('Navigation drawer is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation drawer is scrollable', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 500, viewHeight: 300); await tester.pumpWidget( @@ -210,7 +212,7 @@ void main() { expect(find.text('Label10'), findsNothing); }); - testWidgets('Safe Area test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe Area test', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const double viewHeight = 300; widgetSetup(tester, 500, viewHeight: viewHeight); @@ -251,7 +253,7 @@ void main() { expect(tester.getBottomRight(find.widgetWithText(NavigationDrawerDestination,'Label4')).dy, viewHeight); }); - testWidgets('Navigation drawer semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation drawer semantics', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme= ThemeData.from(colorScheme: const ColorScheme.light()); Widget widget({int selectedIndex = 0}) { @@ -321,7 +323,7 @@ void main() { ); }); - testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation destination updates indicator color and shape', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); @@ -372,7 +374,7 @@ void main() { expect(_getInkWell(tester)?.customBorder, shape); }); - testWidgets('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 3000, viewHeight: 3000); final Widget widget = _buildWidget( diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index eeeb5c411a8fe..4088b54f7ae57 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -10,11 +10,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('Custom selected and unselected textStyles are honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom selected and unselected textStyles are honored', (WidgetTester tester) async { const TextStyle selectedTextStyle = TextStyle(fontWeight: FontWeight.w300, fontSize: 17.0); const TextStyle unselectedTextStyle = TextStyle(fontWeight: FontWeight.w800, fontSize: 11.0); @@ -37,7 +38,7 @@ void main() { expect(actualUnselectedTextStyle.fontWeight, equals(actualUnselectedTextStyle.fontWeight)); }); - testWidgets('Custom selected and unselected iconThemes are honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom selected and unselected iconThemes are honored', (WidgetTester tester) async { const IconThemeData selectedIconTheme = IconThemeData(size: 36, color: Color(0x00000001)); const IconThemeData unselectedIconTheme = IconThemeData(size: 18, color: Color(0x00000002)); @@ -60,7 +61,7 @@ void main() { expect(actualUnselectedIconTheme.fontSize, equals(unselectedIconTheme.size)); }); - testWidgets('No selected destination when selectedIndex is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No selected destination when selectedIndex is null', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -73,7 +74,7 @@ void main() { expect(semantics.where((Semantics s) => s.properties.selected ?? false), isEmpty); }); - testWidgets('backgroundColor can be changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor can be changed', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -98,7 +99,7 @@ void main() { expect(_railMaterial(tester).color, equals(Colors.green)); }); - testWidgets('elevation can be changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('elevation can be changed', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -123,7 +124,7 @@ void main() { expect(_railMaterial(tester).elevation, equals(7)); }); - testWidgets('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -136,7 +137,7 @@ void main() { expect(renderBox.size.width, 80.0); }); - testWidgets('Renders at the correct default width - [labelType]=selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders at the correct default width - [labelType]=selected', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -150,7 +151,7 @@ void main() { expect(renderBox.size.width, 80.0); }); - testWidgets('Renders at the correct default width - [labelType]=all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders at the correct default width - [labelType]=all', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -164,7 +165,7 @@ void main() { expect(renderBox.size.width, 80.0); }); - testWidgets('Renders wider for a destination with a long label - [labelType]=all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders wider for a destination with a long label - [labelType]=all', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -190,7 +191,7 @@ void main() { expect(renderBox.size.width, _labelRenderBox(tester, 'Longer Label').size.width + 16.0); }); - testWidgets('Renders only icons - [labelType]=none (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders only icons - [labelType]=none (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -211,7 +212,7 @@ void main() { expect(_labelOpacity(tester, 'Jkl'), 0); }); - testWidgets('Renders icons and labels - [labelType]=all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders icons and labels - [labelType]=all', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -238,7 +239,7 @@ void main() { expect(_opacityAboveLabel('Jkl'), findsNothing); }); - testWidgets('Renders icons and selected label - [labelType]=selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders icons and selected label - [labelType]=selected', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -260,7 +261,7 @@ void main() { expect(_labelOpacity(tester, 'Jkl'), 0); }); - testWidgets('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -334,7 +335,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=3.0', (WidgetTester tester) async { // Since the rail is icon only, its destinations should not be affected by // textScaleFactor. @@ -412,7 +413,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=0.75', (WidgetTester tester) async { // Since the rail is icon only, its destinations should not be affected by // textScaleFactor. @@ -490,7 +491,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -581,7 +582,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=3.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -673,7 +674,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=0.75', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -765,7 +766,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=all, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -856,7 +857,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=all, [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=3.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -948,7 +949,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=all, [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=0.75', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1040,7 +1041,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1115,7 +1116,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=3.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1193,7 +1194,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=0.75', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1271,7 +1272,7 @@ void main() { ); }); - testWidgets('Group alignment works - [groupAlignment]=-1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group alignment works - [groupAlignment]=-1.0 (default)', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1345,7 +1346,7 @@ void main() { ); }); - testWidgets('Group alignment works - [groupAlignment]=0.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group alignment works - [groupAlignment]=0.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1420,7 +1421,7 @@ void main() { ); }); - testWidgets('Group alignment works - [groupAlignment]=1.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group alignment works - [groupAlignment]=1.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1495,7 +1496,7 @@ void main() { ); }); - testWidgets('Leading and trailing appear in the correct places', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Leading and trailing appear in the correct places', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -1512,7 +1513,7 @@ void main() { expect(trailing.localToGlobal(Offset.zero), Offset((80 - trailing.size.width) / 2, 248.0)); }); - testWidgets('Extended rail animates the width and labels appear - [textDirection]=LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail animates the width and labels appear - [textDirection]=LTR', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1658,7 +1659,7 @@ void main() { ); }); - testWidgets('Extended rail animates the width and labels appear - [textDirection]=RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail animates the width and labels appear - [textDirection]=RTL', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. @@ -1811,7 +1812,7 @@ void main() { ); }); - testWidgets('Extended rail gets wider with longer labels are larger text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail gets wider with longer labels are larger text scale', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -1870,7 +1871,7 @@ void main() { expect(rail.size.width, equals(526.0)); }); - testWidgets('Extended rail final width can be changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail final width can be changed', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -1913,7 +1914,7 @@ void main() { }); /// Regression test for https://github.com/flutter/flutter/issues/65657 - testWidgets('Extended rail transition does not jump from the beginning', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail transition does not jump from the beginning', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -1972,7 +1973,7 @@ void main() { expect(tester.getSize(rail).width, closeTo(80.0, 1.0)); }); - testWidgets('Extended rail animation can be consumed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail animation can be consumed', (WidgetTester tester) async { bool extended = false; late Animation animation; late StateSetter stateSetter; @@ -2017,7 +2018,7 @@ void main() { expect(animation.isCompleted, isTrue); }); - testWidgets('onDestinationSelected is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onDestinationSelected is called', (WidgetTester tester) async { late int selectedIndex; await _pumpNavigationRail( @@ -2042,7 +2043,7 @@ void main() { tester.pumpAndSettle(); }); - testWidgets('onDestinationSelected is not called if null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onDestinationSelected is not called if null', (WidgetTester tester) async { const int selectedIndex = 0; await _pumpNavigationRail( tester, @@ -2060,7 +2061,7 @@ void main() { tester.pumpAndSettle(); }); - testWidgets('Changing destinations animate when [labelType]=selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing destinations animate when [labelType]=selected', (WidgetTester tester) async { int selectedIndex = 0; await tester.pumpWidget( @@ -2125,7 +2126,7 @@ void main() { expect(_labelOpacity(tester, 'Ghi'), equals(1.0)); }); - testWidgets('Changing destinations animate for selectedIndex=null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing destinations animate for selectedIndex=null', (WidgetTester tester) async { int? selectedIndex = 0; late StateSetter stateSetter; @@ -2180,7 +2181,7 @@ void main() { expect(_labelOpacity(tester, 'Abc'), equals(1.0)); }); - testWidgets('Changing destinations animate when selectedIndex=null during transition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing destinations animate when selectedIndex=null during transition', (WidgetTester tester) async { int? selectedIndex = 0; late StateSetter stateSetter; @@ -2235,7 +2236,7 @@ void main() { expect(_labelOpacity(tester, 'Def'), equals(0.0)); }); - testWidgets('Semantics - labelType=[none]', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics - labelType=[none]', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await _pumpLocalizedTestRail(tester, labelType: NavigationRailLabelType.none); @@ -2245,7 +2246,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics - labelType=[selected]', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics - labelType=[selected]', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await _pumpLocalizedTestRail(tester, labelType: NavigationRailLabelType.selected); @@ -2255,7 +2256,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics - labelType=[all]', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics - labelType=[all]', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await _pumpLocalizedTestRail(tester, labelType: NavigationRailLabelType.all); @@ -2265,7 +2266,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics - extended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics - extended', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await _pumpLocalizedTestRail(tester, extended: true); @@ -2275,7 +2276,7 @@ void main() { semantics.dispose(); }); - testWidgets('NavigationRailDestination padding properly applied - NavigationRailLabelType.all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination padding properly applied - NavigationRailLabelType.all', (WidgetTester tester) async { const EdgeInsets defaultPadding = EdgeInsets.symmetric(horizontal: 8.0); const EdgeInsets secondItemPadding = EdgeInsets.symmetric(vertical: 30.0); const EdgeInsets thirdItemPadding = EdgeInsets.symmetric(horizontal: 10.0); @@ -2332,7 +2333,7 @@ void main() { expect(thirdItem.padding, thirdItemPadding); }); - testWidgets('NavigationRailDestination padding properly applied - NavigationRailLabelType.selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination padding properly applied - NavigationRailLabelType.selected', (WidgetTester tester) async { const EdgeInsets defaultPadding = EdgeInsets.symmetric(horizontal: 8.0); const EdgeInsets secondItemPadding = EdgeInsets.symmetric(vertical: 30.0); const EdgeInsets thirdItemPadding = EdgeInsets.symmetric(horizontal: 10.0); @@ -2389,7 +2390,7 @@ void main() { expect(thirdItem.padding, thirdItemPadding); }); - testWidgets('NavigationRailDestination padding properly applied - NavigationRailLabelType.none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination padding properly applied - NavigationRailLabelType.none', (WidgetTester tester) async { const EdgeInsets defaultPadding = EdgeInsets.zero; const EdgeInsets secondItemPadding = EdgeInsets.symmetric(vertical: 30.0); const EdgeInsets thirdItemPadding = EdgeInsets.symmetric(horizontal: 10.0); @@ -2446,7 +2447,7 @@ void main() { expect(thirdItem.padding, thirdItemPadding); }); - testWidgets('NavigationRailDestination adds indicator by default when ThemeData.useMaterial3 is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination adds indicator by default when ThemeData.useMaterial3 is true', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2475,7 +2476,7 @@ void main() { expect(find.byType(NavigationIndicator), findsWidgets); }); - testWidgets('NavigationRailDestination adds indicator when useIndicator is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination adds indicator when useIndicator is true', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2505,7 +2506,7 @@ void main() { expect(find.byType(NavigationIndicator), findsWidgets); }); - testWidgets('NavigationRailDestination does not add indicator when useIndicator is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination does not add indicator when useIndicator is false', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2535,7 +2536,7 @@ void main() { expect(find.byType(NavigationIndicator), findsNothing); }); - testWidgets('NavigationRailDestination adds an oval indicator when no labels are present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination adds an oval indicator when no labels are present', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2568,7 +2569,7 @@ void main() { expect(indicator.height, 32); }); - testWidgets('NavigationRailDestination adds an oval indicator when selected labels are present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination adds an oval indicator when selected labels are present', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2601,7 +2602,7 @@ void main() { expect(indicator.height, 32); }); - testWidgets('NavigationRailDestination adds an oval indicator when all labels are present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination adds an oval indicator when all labels are present', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2634,7 +2635,7 @@ void main() { expect(indicator.height, 32); }); - testWidgets('NavigationRailDestination has center aligned indicator - [labelType]=none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination has center aligned indicator - [labelType]=none', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/97753 await _pumpNavigationRail( @@ -2678,7 +2679,7 @@ void main() { expect(lastIndicator.localToGlobal(Offset.zero).dx, 28.0); }); - testWidgets('NavigationRail respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async { const double safeAreaPadding = 40.0; NavigationRail navigationRail() { return NavigationRail( @@ -2731,7 +2732,7 @@ void main() { expect(updatedWidthRTL, defaultWidth + safeAreaPadding); }); - testWidgets('NavigationRail indicator renders ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail indicator renders ripple', (WidgetTester tester) async { await _pumpNavigationRail( tester, navigationRail: NavigationRail( @@ -2792,7 +2793,7 @@ void main() { ); }); - testWidgets('NavigationRail indicator renders ripple - extended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail indicator renders ripple - extended', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117126 await _pumpNavigationRail( tester, @@ -2855,7 +2856,7 @@ void main() { ); }); - testWidgets('NavigationRail indicator renders properly when padding is applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail indicator renders properly when padding is applied', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117126 await _pumpNavigationRail( tester, @@ -2920,7 +2921,7 @@ void main() { ); }); - testWidgets('Indicator renders properly when NavigationRai.minWidth < default minWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Indicator renders properly when NavigationRai.minWidth < default minWidth', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117126 await _pumpNavigationRail( tester, @@ -2984,7 +2985,7 @@ void main() { ); }); - testWidgets('NavigationRail indicator renders properly with custom padding and minWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail indicator renders properly with custom padding and minWidth', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117126 await _pumpNavigationRail( tester, @@ -3050,7 +3051,7 @@ void main() { ); }); - testWidgets('NavigationRail indicator renders properly with long labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail indicator renders properly with long labels', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/128005. await _pumpNavigationRail( tester, @@ -3125,7 +3126,7 @@ void main() { ); }); - testWidgets('NavigationRail indicator scale transform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail indicator scale transform', (WidgetTester tester) async { int selectedIndex = 0; Future buildWidget() async { await _pumpNavigationRail( @@ -3169,7 +3170,7 @@ void main() { expect(transform.getColumn(0)[0], 1.0); }); - testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation destination updates indicator color and shape', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); const ShapeBorder shape = RoundedRectangleBorder(); @@ -3213,7 +3214,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, shape); }); - testWidgets("Destination's respect their disabled state", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Destination's respect their disabled state", (WidgetTester tester) async { late int selectedIndex; await _pumpNavigationRail( tester, @@ -3262,7 +3263,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3276,7 +3277,7 @@ void main() { expect(renderBox.size.width, 72.0); }); - testWidgets('Renders at the correct default width - [labelType]=selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders at the correct default width - [labelType]=selected', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3291,7 +3292,7 @@ void main() { expect(renderBox.size.width, 72.0); }); - testWidgets('Renders at the correct default width - [labelType]=all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Renders at the correct default width - [labelType]=all', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3306,7 +3307,7 @@ void main() { expect(renderBox.size.width, 72.0); }); - testWidgets('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3373,7 +3374,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=3.0', (WidgetTester tester) async { // Since the rail is icon only, its destinations should not be affected by // textScaleFactor. await _pumpNavigationRail( @@ -3443,7 +3444,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=0.75', (WidgetTester tester) async { // Since the rail is icon only, its destinations should not be affected by // textScaleFactor. await _pumpNavigationRail( @@ -3513,7 +3514,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3591,7 +3592,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=3.0', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3670,7 +3671,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=0.75', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3749,7 +3750,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=all, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3857,7 +3858,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=all, [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=3.0', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -3964,7 +3965,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct - [labelType]=all, [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=0.75', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4074,7 +4075,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4142,7 +4143,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=3.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=3.0', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4213,7 +4214,7 @@ void main() { ); }); - testWidgets('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=0.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=0.75', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4284,7 +4285,7 @@ void main() { ); }); - testWidgets('Group alignment works - [groupAlignment]=-1.0 (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group alignment works - [groupAlignment]=-1.0 (default)', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4348,7 +4349,7 @@ void main() { ); }); - testWidgets('Group alignment works - [groupAlignment]=0.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group alignment works - [groupAlignment]=0.0', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4411,7 +4412,7 @@ void main() { ); }); - testWidgets('Group alignment works - [groupAlignment]=1.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group alignment works - [groupAlignment]=1.0', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4474,7 +4475,7 @@ void main() { ); }); - testWidgets('Leading and trailing appear in the correct places', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Leading and trailing appear in the correct places', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4492,7 +4493,7 @@ void main() { expect(trailing.localToGlobal(Offset.zero), Offset((72 - trailing.size.width) / 2.0, 360.0)); }); - testWidgets('Extended rail animates the width and labels appear - [textDirection]=LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail animates the width and labels appear - [textDirection]=LTR', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -4630,7 +4631,7 @@ void main() { ); }); - testWidgets('Extended rail animates the width and labels appear - [textDirection]=RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail animates the width and labels appear - [textDirection]=RTL', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -4775,7 +4776,7 @@ void main() { ); }); - testWidgets('Extended rail gets wider with longer labels are larger text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail gets wider with longer labels are larger text scale', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -4834,7 +4835,7 @@ void main() { expect(rail.size.width, equals(584.0)); }); - testWidgets('Extended rail final width can be changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail final width can be changed', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -4877,7 +4878,7 @@ void main() { }); /// Regression test for https://github.com/flutter/flutter/issues/65657 - testWidgets('Extended rail transition does not jump from the beginning', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Extended rail transition does not jump from the beginning', (WidgetTester tester) async { bool extended = false; late StateSetter stateSetter; @@ -4936,7 +4937,7 @@ void main() { expect(tester.getSize(rail).width, closeTo(72.0, 1.0)); }); - testWidgets('NavigationRailDestination adds circular indicator when no labels are present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination adds circular indicator when no labels are present', (WidgetTester tester) async { await _pumpNavigationRail( tester, useMaterial3: false, @@ -4970,7 +4971,7 @@ void main() { expect(indicator.height, 56); }); - testWidgets('NavigationRailDestination has center aligned indicator - [labelType]=none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailDestination has center aligned indicator - [labelType]=none', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/97753 await _pumpNavigationRail( @@ -5015,7 +5016,7 @@ void main() { expect(lastIndicator.localToGlobal(Offset.zero).dx, 24.0); }); - testWidgets('NavigationRail respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail respects the notch/system navigation bar in landscape mode', (WidgetTester tester) async { const double safeAreaPadding = 40.0; NavigationRail navigationRail() { return NavigationRail( diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 704c7a7a3a1e1..54596df58e149 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -10,11 +10,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('OutlinedButton, OutlinedButton.icon defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton, OutlinedButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: colorScheme); final bool material3 = theme.useMaterial3; @@ -178,7 +179,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('OutlinedButton default overlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton default overlayColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -231,7 +232,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); }); - testWidgets('Does OutlinedButton work with hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does OutlinedButton work with hover', (WidgetTester tester) async { const Color hoverColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -259,7 +260,7 @@ void main() { expect(inkFeatures, paints..rect(color: hoverColor)); }); - testWidgets('Does OutlinedButton work with focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does OutlinedButton work with focus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -289,7 +290,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('Does OutlinedButton work with autofocus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does OutlinedButton work with autofocus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -435,7 +436,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('OutlinedButton uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -502,7 +503,7 @@ void main() { expect(textColor(), pressedColor); }); - testWidgets('OutlinedButton uses stateful color for icon color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton uses stateful color for icon color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final Key buttonKey = UniqueKey(); @@ -569,7 +570,7 @@ void main() { expect(iconColor(), pressedColor); }); - testWidgets('OutlinedButton uses stateful color for border color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton uses stateful color for border color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -637,7 +638,7 @@ void main() { expect(outlinedButton, paints..drrect(color: pressedColor)); }); - testWidgets('OutlinedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { bool wasPressed; Finder outlinedButton; @@ -681,7 +682,7 @@ void main() { expect(tester.widget(outlinedButton).enabled, false); }); - testWidgets("OutlinedButton response doesn't hover when disabled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("OutlinedButton response doesn't hover when disabled", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'OutlinedButton Focus'); final GlobalKey childKey = GlobalKey(); @@ -731,7 +732,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('disabled and hovered OutlinedButton responds to mouse-exit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled and hovered OutlinedButton responds to mouse-exit', (WidgetTester tester) async { int onHoverCount = 0; late bool hover; @@ -793,7 +794,7 @@ void main() { expect(hover, false); }); - testWidgets('Can set OutlinedButton focus and Can set unFocus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set OutlinedButton focus and Can set unFocus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'OutlinedButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -822,7 +823,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('When OutlinedButton disable, Can not set OutlinedButton focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When OutlinedButton disable, Can not set OutlinedButton focus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'OutlinedButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -845,7 +846,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets("Outline button doesn't crash if disabled during a gesture", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Outline button doesn't crash if disabled during a gesture", (WidgetTester tester) async { Widget buildFrame(VoidCallback? onPressed) { return Directionality( textDirection: TextDirection.ltr, @@ -865,7 +866,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('OutlinedButton shape and border component overrides', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton shape and border component overrides', (WidgetTester tester) async { const Color fillColor = Color(0xFF00FF00); const BorderSide disabledBorderSide = BorderSide(color: Color(0xFFFF0000), width: 3); const BorderSide enabledBorderSide = BorderSide(color: Color(0xFFFF00FF), width: 4); @@ -943,7 +944,7 @@ void main() { expect(getBorderSide(), enabledBorderSide); }); - testWidgets('OutlinedButton has no clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton has no clip by default', (WidgetTester tester) async { final GlobalKey buttonKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -965,7 +966,7 @@ void main() { }); - testWidgets('OutlinedButton contributes semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton contributes semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Theme( @@ -1013,7 +1014,7 @@ void main() { semantics.dispose(); }); - testWidgets('OutlinedButton scales textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton scales textScaleFactor', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -1096,7 +1097,7 @@ void main() { expect(tester.getSize(find.byType(Text)), const Size(126.0, 42.0)); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/122066 - testWidgets('OutlinedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -1127,7 +1128,7 @@ void main() { expect(didLongPressButton, isTrue); }); - testWidgets('OutlinedButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key childKey = Key('test child'); @@ -1260,7 +1261,7 @@ void main() { if (textDirection == TextDirection.rtl) 'RTL', ].join(', '); - testWidgets(testName, (WidgetTester tester) async { + testWidgetsWithLeakTracking(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1404,7 +1405,7 @@ void main() { } }); - testWidgets('Override OutlinedButton default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override OutlinedButton default padding', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1438,7 +1439,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.all(22)); }); - testWidgets('M3 OutlinedButton has correct padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 OutlinedButton has correct padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1464,7 +1465,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.symmetric(horizontal: 24)); }); - testWidgets('M3 OutlinedButton.icon has correct padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 OutlinedButton.icon has correct padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1491,7 +1492,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 24.0, 0.0)); }); - testWidgets('Fixed size OutlinedButtons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size OutlinedButtons', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1524,7 +1525,7 @@ void main() { expect(tester.getSize(find.widgetWithText(OutlinedButton, 'wx200')).height, 200); }); - testWidgets('OutlinedButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) { return MaterialApp( home: Scaffold( @@ -1564,7 +1565,7 @@ void main() { } }); - testWidgets('OutlinedButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -1591,7 +1592,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('OutlinedButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( @@ -1613,7 +1614,7 @@ void main() { expect(buttonInkWell.splashFactory, equals(InkRipple.splashFactory)); }, variant: TargetPlatformVariant.all()); - testWidgets('OutlinedButton.icon does not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton.icon does not overflow', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/77815 await tester.pumpWidget( MaterialApp( @@ -1634,7 +1635,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('OutlinedButton.icon icon,label layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton.icon icon,label layout', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); final Key iconKey = UniqueKey(); final Key labelKey = UniqueKey(); @@ -1671,7 +1672,7 @@ void main() { expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0)); }); - testWidgets('OutlinedButton maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton maximumSize', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); @@ -1713,7 +1714,7 @@ void main() { expect(tester.getSize(find.byKey(key1)), const Size(104.0, 224.0)); }); - testWidgets('Fixed size OutlinedButton, same as minimumSize == maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size OutlinedButton, same as minimumSize == maximumSize', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1743,7 +1744,7 @@ void main() { expect(tester.getSize(find.widgetWithText(OutlinedButton, '200,200')), const Size(200, 200)); }); - testWidgets('OutlinedButton changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1821,7 +1822,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1844,7 +1845,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('OutlinedButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1974,15 +1975,15 @@ void main() { await gesture.removePointer(); } - testWidgets('OutlinedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('OutlinedButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled OutlinedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled OutlinedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; @@ -2005,7 +2006,7 @@ void main() { expect(count, 1); }); - testWidgets("OutlinedButton.styleFrom doesn't throw exception on passing only one cursor", (WidgetTester tester) async { + testWidgetsWithLeakTracking("OutlinedButton.styleFrom doesn't throw exception on passing only one cursor", (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/118071. await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/material/outlined_button_theme_test.dart b/packages/flutter/test/material/outlined_button_theme_test.dart index 93e10033f7549..57a57f4e7bf4b 100644 --- a/packages/flutter/test/material/outlined_button_theme_test.dart +++ b/packages/flutter/test/material/outlined_button_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('OutlinedButtonThemeData lerp special cases', () { expect(OutlinedButtonThemeData.lerp(null, null, 0), null); @@ -12,7 +14,7 @@ void main() { expect(identical(OutlinedButtonThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Material3: Passing no OutlinedButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: Passing no OutlinedButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -53,7 +55,7 @@ void main() { expect(align.alignment, Alignment.center); }); - testWidgets('Material2: Passing no OutlinedButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: Passing no OutlinedButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -196,19 +198,19 @@ void main() { expect(align.alignment, alignment); } - testWidgets('Button style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(themeStyle: style)); await tester.pumpAndSettle(); checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallStyle: style)); await tester.pumpAndSettle(); checkButton(tester); @@ -216,26 +218,26 @@ void main() { // Same as the previous tests with empty ButtonStyle's instead of null. - testWidgets('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style, themeStyle: const ButtonStyle(), overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), themeStyle: style, overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), overallStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); }); - testWidgets('Material3: Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); @@ -306,7 +308,7 @@ void main() { expect(material.shadowColor, shadowColor); }); - testWidgets('Material2: Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 538f718c19c44..2a46455781e12 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + const Color kSelectedColor = Color(0xFF00FF00); const Color kUnselectedColor = Colors.transparent; @@ -64,7 +66,7 @@ List indicatorColors(WidgetTester tester) { } void main() { - testWidgets('PageSelector responds correctly to setting the TabController index', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector responds correctly to setting the TabController index', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), length: 3, @@ -85,7 +87,7 @@ void main() { expect(indicatorColors(tester), const [kUnselectedColor, kUnselectedColor, kSelectedColor]); }); - testWidgets('PageSelector responds correctly to TabController.animateTo()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector responds correctly to TabController.animateTo()', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), length: 3, @@ -128,7 +130,7 @@ void main() { expect(indicatorColors(tester), const [kUnselectedColor, kUnselectedColor, kSelectedColor]); }); - testWidgets('PageSelector responds correctly to TabBarView drags', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector responds correctly to TabBarView drags', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, @@ -187,7 +189,7 @@ void main() { }); - testWidgets('PageSelector indicatorColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector indicatorColors', (WidgetTester tester) async { const Color kRed = Color(0xFFFF0000); const Color kBlue = Color(0xFF0000FF); @@ -206,7 +208,7 @@ void main() { expect(indicatorColors(tester), const [kBlue, kRed, kRed]); }); - testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, @@ -227,7 +229,7 @@ void main() { expect(tester.getSize(find.byType(TabPageSelector)).height, 24.0); }); - testWidgets('PageSelector circle border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector circle border', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart index 323d4ed0c03d2..d43fdc737c424 100644 --- a/packages/flutter/test/material/page_transitions_theme_test.dart +++ b/packages/flutter/test/material/page_transitions_theme_test.dart @@ -8,8 +8,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('Default PageTransitionsTheme platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default PageTransitionsTheme platform', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Text('home'))); final PageTransitionsTheme theme = Theme.of(tester.element(find.text('home'))).pageTransitionsTheme; expect(theme.builders, isNotNull); @@ -35,7 +37,7 @@ void main() { } }); - testWidgets('Default PageTransitionsTheme builds a CupertinoPageTransition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default PageTransitionsTheme builds a CupertinoPageTransition', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => Material( child: TextButton( @@ -61,7 +63,7 @@ void main() { expect(find.byType(CupertinoPageTransition), findsOneWidget); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Default PageTransitionsTheme builds a _ZoomPageTransition for android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default PageTransitionsTheme builds a _ZoomPageTransition for android', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => Material( child: TextButton( @@ -94,7 +96,7 @@ void main() { expect(findZoomPageTransition(), findsOneWidget); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('PageTransitionsTheme override builds a _OpenUpwardsPageTransition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageTransitionsTheme override builds a _OpenUpwardsPageTransition', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => Material( child: TextButton( @@ -134,7 +136,7 @@ void main() { expect(findOpenUpwardsPageTransition(), findsOneWidget); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('PageTransitionsTheme override builds a _FadeUpwardsTransition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageTransitionsTheme override builds a _FadeUpwardsTransition', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => Material( child: TextButton( @@ -214,7 +216,7 @@ void main() { return !(hasOneOpacityLayer && hasOneTransformLayer); } - testWidgets('ZoomPageTransitionsBuilder default route snapshotting behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ZoomPageTransitionsBuilder default route snapshotting behavior', (WidgetTester tester) async { await tester.pumpWidget( boilerplate(themeAllowSnapshotting: true), ); @@ -247,7 +249,7 @@ void main() { expect(isTransitioningWithSnapshotting(tester, page1), isTrue); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - testWidgets('ZoomPageTransitionsBuilder.allowSnapshotting can disable route snapshotting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ZoomPageTransitionsBuilder.allowSnapshotting can disable route snapshotting', (WidgetTester tester) async { await tester.pumpWidget( boilerplate(themeAllowSnapshotting: false), ); @@ -280,7 +282,7 @@ void main() { expect(isTransitioningWithSnapshotting(tester, page1), isFalse); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - testWidgets('Setting PageRoute.allowSnapshotting to false overrides ZoomPageTransitionsBuilder.allowSnapshotting = true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting PageRoute.allowSnapshotting to false overrides ZoomPageTransitionsBuilder.allowSnapshotting = true', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( themeAllowSnapshotting: true, diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index 4b37dedb96a3c..8b61cbc39a63a 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + PopupMenuThemeData _popupMenuThemeM2() { return PopupMenuThemeData( color: Colors.orange, @@ -69,7 +71,7 @@ void main() { expect(popupMenuTheme.mouseCursor, null); }); - testWidgets('Default PopupMenuThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default PopupMenuThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const PopupMenuThemeData().debugFillProperties(builder); @@ -81,7 +83,7 @@ void main() { expect(description, []); }); - testWidgets('PopupMenuThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); PopupMenuThemeData( color: const Color(0xFFFFFFFF), @@ -116,7 +118,7 @@ void main() { ]); }); - testWidgets('Passing no PopupMenuThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no PopupMenuThemeData returns defaults', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); final Key enabledPopupItemKey = UniqueKey(); @@ -217,7 +219,7 @@ void main() { ); }); - testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { final PopupMenuThemeData popupMenuTheme = _popupMenuThemeM3(); final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); @@ -315,7 +317,7 @@ void main() { ); }); - testWidgets('Popup menu widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu widget properties take priority over theme', (WidgetTester tester) async { final PopupMenuThemeData popupMenuTheme = _popupMenuThemeM3(); final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); @@ -404,7 +406,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Passing no PopupMenuThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no PopupMenuThemeData returns defaults', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); final Key enabledPopupItemKey = UniqueKey(); @@ -503,7 +505,7 @@ void main() { ); }); - testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { final PopupMenuThemeData popupMenuTheme = _popupMenuThemeM2(); final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); @@ -589,7 +591,7 @@ void main() { ); }); - testWidgets('Popup menu widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu widget properties take priority over theme', (WidgetTester tester) async { final PopupMenuThemeData popupMenuTheme = _popupMenuThemeM2(); final Key popupButtonKey = UniqueKey(); final Key popupButtonApp = UniqueKey(); diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index c68e3507a8975..875ab00e30d3e 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -18,6 +18,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -26,7 +27,7 @@ void main() { // The "can be constructed" tests that follow are primarily to ensure that any // animations started by the progress indicators are stopped at dispose() time. - testWidgets('LinearProgressIndicator(value: 0.0) can be constructed and has empty semantics by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator(value: 0.0) can be constructed and has empty semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Theme( @@ -47,7 +48,7 @@ void main() { handle.dispose(); }); - testWidgets('LinearProgressIndicator(value: null) can be constructed and has empty semantics by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator(value: null) can be constructed and has empty semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Theme( @@ -68,7 +69,7 @@ void main() { handle.dispose(); }); - testWidgets('LinearProgressIndicator custom minHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator custom minHeight', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -117,7 +118,7 @@ void main() { ); }); - testWidgets('LinearProgressIndicator paint (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator paint (LTR)', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -143,7 +144,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -169,7 +170,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('LinearProgressIndicator indeterminate (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator indeterminate (LTR)', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -199,7 +200,7 @@ void main() { expect(tester.binding.transientCallbackCount, 1); }); - testWidgets('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator paint (RTL)', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -229,7 +230,7 @@ void main() { expect(tester.binding.transientCallbackCount, 1); }); - testWidgets('LinearProgressIndicator with colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator with colors', (WidgetTester tester) async { // With valueColor & color provided await tester.pumpWidget( Theme( @@ -349,7 +350,7 @@ void main() { }); - testWidgets('LinearProgressIndicator with animation with null colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator with animation with null colors', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -377,7 +378,7 @@ void main() { ); }); - testWidgets('CircularProgressIndicator(value: 0.0) can be constructed and has value semantics by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator(value: 0.0) can be constructed and has value semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Theme( @@ -398,7 +399,7 @@ void main() { handle.dispose(); }); - testWidgets('CircularProgressIndicator(value: null) can be constructed and has empty semantics by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator(value: null) can be constructed and has empty semantics by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Theme( @@ -413,7 +414,7 @@ void main() { handle.dispose(); }); - testWidgets('LinearProgressIndicator causes a repaint when it changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator causes a repaint when it changes', (WidgetTester tester) async { await tester.pumpWidget(Theme( data: theme, child: Directionality( @@ -433,7 +434,7 @@ void main() { expect(layers1, isNot(equals(layers2))); }); - testWidgets('CircularProgressIndicator stroke width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator stroke width', (WidgetTester tester) async { await tester.pumpWidget(Theme(data: theme, child: const CircularProgressIndicator())); expect(find.byType(CircularProgressIndicator), paints..arc(strokeWidth: 4.0)); @@ -443,7 +444,7 @@ void main() { expect(find.byType(CircularProgressIndicator), paints..arc(strokeWidth: 16.0)); }); - testWidgets('CircularProgressIndicator strokeAlign', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator strokeAlign', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -484,7 +485,7 @@ void main() { expect(find.byType(CircularProgressIndicator), paints..arc(rect: const Offset(-4.0, -4.0) & const Size(808.0, 608.0))); }); - testWidgets('CircularProgressIndicator with strokeCap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator with strokeCap', (WidgetTester tester) async { await tester.pumpWidget(const CircularProgressIndicator()); expect(find.byType(CircularProgressIndicator), paints..arc(strokeCap: StrokeCap.square), @@ -506,7 +507,7 @@ void main() { expect(find.byType(CircularProgressIndicator), paints..arc(strokeCap: StrokeCap.round)); }); - testWidgets('LinearProgressIndicator with indicatorBorderRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator with indicatorBorderRadius', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -541,7 +542,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('CircularProgressIndicator paint colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator paint colors', (WidgetTester tester) async { const Color green = Color(0xFF00FF00); const Color blue = Color(0xFF0000FF); const Color red = Color(0xFFFF0000); @@ -598,7 +599,7 @@ void main() { expect(find.byType(CircularProgressIndicator), paints..arc(color: blue)..arc(color: green)); }); - testWidgets('RefreshProgressIndicator paint colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshProgressIndicator paint colors', (WidgetTester tester) async { const Color green = Color(0xFF00FF00); const Color blue = Color(0xFF0000FF); const Color red = Color(0xFFFF0000); @@ -667,7 +668,7 @@ void main() { expect(themeBackgroundMaterial.color, blue); }); - testWidgets('RefreshProgressIndicator with a round indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshProgressIndicator with a round indicator', (WidgetTester tester) async { await tester.pumpWidget(const RefreshProgressIndicator()); expect(find.byType(RefreshProgressIndicator), paints..arc(strokeCap: StrokeCap.square), @@ -690,7 +691,7 @@ void main() { expect(find.byType(RefreshProgressIndicator), paints..arc(strokeCap: StrokeCap.round)); }); - testWidgets('Indeterminate RefreshProgressIndicator keeps spinning until end of time (approximate)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Indeterminate RefreshProgressIndicator keeps spinning until end of time (approximate)', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/13782 await tester.pumpWidget( @@ -735,7 +736,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgets('Determinate CircularProgressIndicator stops the animator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Determinate CircularProgressIndicator stops the animator', (WidgetTester tester) async { double? progressValue; late StateSetter setState; await tester.pumpWidget( @@ -765,7 +766,7 @@ void main() { expect(tester.hasRunningAnimations, isTrue); }); - testWidgets('LinearProgressIndicator with height 12.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator with height 12.0', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -790,7 +791,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('LinearProgressIndicator with a height less than the minimum', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator with a height less than the minimum', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -815,7 +816,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('LinearProgressIndicator with default height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator with default height', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme, @@ -840,7 +841,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('LinearProgressIndicator can be made accessible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator can be made accessible', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; @@ -869,7 +870,7 @@ void main() { handle.dispose(); }); - testWidgets('LinearProgressIndicator that is determinate gets default a11y value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator that is determinate gets default a11y value', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; @@ -896,7 +897,7 @@ void main() { handle.dispose(); }); - testWidgets('LinearProgressIndicator that is determinate does not default a11y value when label is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator that is determinate does not default a11y value when label is null', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -917,7 +918,7 @@ void main() { handle.dispose(); }); - testWidgets('LinearProgressIndicator that is indeterminate does not default a11y value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinearProgressIndicator that is indeterminate does not default a11y value', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Progress'; @@ -943,7 +944,7 @@ void main() { handle.dispose(); }); - testWidgets('CircularProgressIndicator can be made accessible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CircularProgressIndicator can be made accessible', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; @@ -972,7 +973,7 @@ void main() { handle.dispose(); }); - testWidgets('RefreshProgressIndicator can be made accessible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RefreshProgressIndicator can be made accessible', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey key = GlobalKey(); const String label = 'Label'; @@ -1022,7 +1023,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgets( + testWidgetsWithLeakTracking( 'Adaptive CircularProgressIndicator displays CupertinoActivityIndicator in iOS', (WidgetTester tester) async { await tester.pumpWidget( @@ -1044,7 +1045,7 @@ void main() { }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Adaptive CircularProgressIndicator can use backgroundColor to change tick color for iOS', (WidgetTester tester) async { await tester.pumpWidget( @@ -1073,7 +1074,7 @@ void main() { }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Adaptive CircularProgressIndicator does not display CupertinoActivityIndicator in non-iOS', (WidgetTester tester) async { await tester.pumpWidget( @@ -1097,7 +1098,7 @@ void main() { }), ); - testWidgets('ProgressIndicatorTheme.wrap() always creates a new ProgressIndicatorTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ProgressIndicatorTheme.wrap() always creates a new ProgressIndicatorTheme', (WidgetTester tester) async { late BuildContext builderContext; @@ -1128,7 +1129,7 @@ void main() { expect((wrappedTheme as ProgressIndicatorTheme).data, themeData); }); - testWidgets('default size of CircularProgressIndicator is 36x36 - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default size of CircularProgressIndicator is 36x36 - M3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: theme.copyWith(useMaterial3: true), diff --git a/packages/flutter/test/material/radio_theme_test.dart b/packages/flutter/test/material/radio_theme_test.dart index b263547fb1cf8..c2d22b1f24882 100644 --- a/packages/flutter/test/material/radio_theme_test.dart +++ b/packages/flutter/test/material/radio_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -39,7 +40,7 @@ void main() { expect(theme.data.visualDensity, null); }); - testWidgets('Default RadioThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default RadioThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const RadioThemeData().debugFillProperties(builder); @@ -51,7 +52,7 @@ void main() { expect(description, []); }); - testWidgets('RadioThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const RadioThemeData( mouseCursor: MaterialStatePropertyAll(SystemMouseCursors.click), @@ -80,7 +81,7 @@ void main() { ); }); - testWidgets('Radio is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio is themeable', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const MouseCursor mouseCursor = SystemMouseCursors.text; @@ -153,7 +154,7 @@ void main() { expect(_getRadioMaterial(tester), paints..circle(color: focusOverlayColor, radius: splashRadius)); }); - testWidgets('Radio properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio properties are taken over the theme values', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const MouseCursor themeMouseCursor = SystemMouseCursors.click; @@ -247,7 +248,7 @@ void main() { expect(_getRadioMaterial(tester), paints..circle(color: focusColor, radius: splashRadius)); }); - testWidgets('Radio activeColor property is taken over the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio activeColor property is taken over the theme', (WidgetTester tester) async { const Color themeDefaultFillColor = Color(0xfffffff0); const Color themeSelectedFillColor = Color(0xfffffff1); @@ -288,7 +289,7 @@ void main() { expect(_getRadioMaterial(tester), paints..circle(color: selectedFillColor)); }); - testWidgets('Radio theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); @@ -350,7 +351,7 @@ void main() { ); }); - testWidgets('Local RadioTheme can override global RadioTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Local RadioTheme can override global RadioTheme', (WidgetTester tester) async { const Color globalThemeFillColor = Color(0xfffffff1); const Color localThemeFillColor = Color(0xffff0000); diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index 12c5eabdbb667..b1feb110ec642 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -9,11 +9,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/105833 - testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag gesture uses provided gesture settings', (WidgetTester tester) async { RangeValues values = const RangeValues(0.1, 0.5); bool dragStarted = false; final Key sliderKey = UniqueKey(); @@ -119,7 +120,7 @@ void main() { expect(dragStarted, false); }); - testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -173,7 +174,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgets('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -227,7 +228,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgets('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -285,7 +286,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgets('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -343,7 +344,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -387,7 +388,7 @@ void main() { expect(values.end, equals(1)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -431,7 +432,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -477,7 +478,7 @@ void main() { expect(values.end, equals(100)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -523,7 +524,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -573,7 +574,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -623,7 +624,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -675,7 +676,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -727,7 +728,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -777,7 +778,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -827,7 +828,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -879,7 +880,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -931,7 +932,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); RangeValues? startValues; RangeValues? endValues; @@ -985,7 +986,7 @@ void main() { expect(endValues!.end, moreOrLessEquals(70, epsilon: 1)); }); - testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); late RangeValues startValues; late RangeValues endValues; @@ -1100,7 +1101,7 @@ void main() { ); } - testWidgets('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1129,7 +1130,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1157,7 +1158,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1184,7 +1185,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1217,7 +1218,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1247,7 +1248,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1288,7 +1289,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1308,7 +1309,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1497,7 +1498,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1564,7 +1565,7 @@ void main() { ); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1638,7 +1639,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1715,7 +1716,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1796,7 +1797,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101868 - testWidgets('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1854,7 +1855,7 @@ void main() { ); }); - testWidgets('Range Slider Semantics - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider Semantics - ltr', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1938,7 +1939,7 @@ void main() { ]); }); - testWidgets('Range Slider Semantics - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider Semantics - rtl', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -2020,7 +2021,7 @@ void main() { ]); }); - testWidgets('Range Slider implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); RangeSlider( @@ -2051,7 +2052,7 @@ void main() { ]); }); - testWidgets('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -2090,7 +2091,7 @@ void main() { ); }); - testWidgets('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -2135,7 +2136,7 @@ void main() { ); }); - testWidgets('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { // Regress test for https://github.com/flutter/flutter/issues/65943 Widget buildFrame(double maxValue) { return MaterialApp( @@ -2179,7 +2180,7 @@ void main() { expect(nearEqual(activeTrackRect.right, (800.0 - 24.0 - 24.0) * (8 / 15) + 24.0, 0.01), true); }); - testWidgets('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { const RangeValues values = RangeValues(50, 70); // Test default cursor. @@ -2234,7 +2235,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { RangeValues values = const RangeValues(50, 70); const MouseCursor disabledCursor = SystemMouseCursors.basic; const MouseCursor hoveredCursor = SystemMouseCursors.grab; @@ -2308,7 +2309,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), draggedCursor); }); - testWidgets('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2371,7 +2372,7 @@ void main() { ); }); - testWidgets('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2427,7 +2428,7 @@ void main() { ); }); - testWidgets('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); const Color hoverColor = Color(0xffff0000); @@ -2542,7 +2543,7 @@ void main() { ); }); - testWidgets('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128433 int startFired = 0; diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index 7935a4d3dc2e6..32f3430f64896 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -9,11 +9,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/services/keyboard_key.g.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('RawMaterialButton responds when tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton responds when tapped', (WidgetTester tester) async { bool pressed = false; const Color splashColor = Color(0xff00ff00); await tester.pumpWidget( @@ -43,7 +44,7 @@ void main() { expect(pressed, isTrue); }); - testWidgets('RawMaterialButton responds to shortcut when activated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton responds to shortcut when activated', (WidgetTester tester) async { bool pressed = false; final FocusNode focusNode = FocusNode(debugLabel: 'Test Button'); const Color splashColor = Color(0xff00ff00); @@ -110,7 +111,7 @@ void main() { expect(pressed, isTrue); }); - testWidgets('materialTapTargetSize.padded expands hit test area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('materialTapTargetSize.padded expands hit test area', (WidgetTester tester) async { int pressed = 0; await tester.pumpWidget( @@ -132,7 +133,7 @@ void main() { expect(pressed, 1); }); - testWidgets('materialTapTargetSize.padded expands semantics area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('materialTapTargetSize.padded expands semantics area', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -175,7 +176,7 @@ void main() { semantics.dispose(); }); - testWidgets('Ink splash from center tap originates in correct location', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ink splash from center tap originates in correct location', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xAA0000FF); const Color fillColor = Color(0xFFEF5350); @@ -210,7 +211,7 @@ void main() { await gesture.up(); }); - testWidgets('Ink splash from tap above material originates in correct location', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ink splash from tap above material originates in correct location', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xAA0000FF); const Color fillColor = Color(0xFFEF5350); @@ -244,7 +245,7 @@ void main() { await gesture.up(); }); - testWidgets('off-center child is hit testable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('off-center child is hit testable', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Column( @@ -274,7 +275,7 @@ void main() { expect(find.text('Material').hitTestable(), findsOneWidget); }); - testWidgets('smaller child is hit testable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('smaller child is hit testable', (WidgetTester tester) async { const Key key = Key('test'); await tester.pumpWidget( MaterialApp( @@ -299,7 +300,7 @@ void main() { expect(find.byKey(key).hitTestable(), findsOneWidget); }); - testWidgets('RawMaterialButton can be expanded by parent constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton can be expanded by parent constraints', (WidgetTester tester) async { const Key key = Key('test'); await tester.pumpWidget( MaterialApp( @@ -319,7 +320,7 @@ void main() { expect(tester.getSize(find.byKey(key)), const Size(800.0, 48.0)); }); - testWidgets('RawMaterialButton handles focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton handles focus', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Button Focus'); const Key key = Key('test'); const Color focusColor = Color(0xff00ff00); @@ -347,7 +348,7 @@ void main() { expect(box, paints..rect(color: focusColor)); }); - testWidgets('RawMaterialButton loses focus when disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton loses focus when disabled.', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'RawMaterialButton'); await tester.pumpWidget( MaterialApp( @@ -381,7 +382,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets("Disabled RawMaterialButton can't be traversed to.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Disabled RawMaterialButton can't be traversed to.", (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: '$RawMaterialButton 1'); final FocusNode focusNode2 = FocusNode(debugLabel: '$RawMaterialButton 2'); @@ -421,7 +422,7 @@ void main() { expect(focusNode2.hasPrimaryFocus, isFalse); }); - testWidgets('RawMaterialButton handles hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton handles hover', (WidgetTester tester) async { const Key key = Key('test'); const Color hoverColor = Color(0xff00ff00); @@ -450,7 +451,7 @@ void main() { expect(box, paints..rect(color: hoverColor)); }); - testWidgets('RawMaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { bool wasPressed; Finder rawMaterialButton; @@ -494,7 +495,7 @@ void main() { expect(tester.widget(rawMaterialButton).enabled, false); }); - testWidgets('RawMaterialButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -525,7 +526,7 @@ void main() { expect(didLongPressButton, isTrue); }); - testWidgets('RawMaterialButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key childKey = Key('test child'); @@ -586,7 +587,7 @@ void main() { expect(childRect, equals(const Rect.fromLTRB(372.0, 293.0, 428.0, 307.0))); }); - testWidgets('RawMaterialButton changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawMaterialButton changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/material/scrollbar_paint_test.dart b/packages/flutter/test/material/scrollbar_paint_test.dart index 42ce23133f54f..b261a6ef6845d 100644 --- a/packages/flutter/test/material/scrollbar_paint_test.dart +++ b/packages/flutter/test/material/scrollbar_paint_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; const Color _kAndroidThumbIdleColor = Color(0xffbcbcbc); @@ -26,7 +27,7 @@ Widget _buildSingleChildScrollViewWithScrollbar({ } void main() { - testWidgets('Viewport basic test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport basic test (LTR)', (WidgetTester tester) async { await tester.pumpWidget(_buildSingleChildScrollViewWithScrollbar( child: const SizedBox(width: 4000.0, height: 4000.0), )); @@ -52,7 +53,7 @@ void main() { ); }); - testWidgets('Viewport basic test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport basic test (RTL)', (WidgetTester tester) async { await tester.pumpWidget(_buildSingleChildScrollViewWithScrollbar( textDirection: TextDirection.rtl, child: const SizedBox(width: 4000.0, height: 4000.0), @@ -79,7 +80,7 @@ void main() { ); }); - testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with MaterialApp and Scaffold', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -123,7 +124,7 @@ void main() { ); }); - testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { + testWidgetsWithLeakTracking("should not paint when there isn't enough space", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index 44addd4fc5c47..e7f0d3f1b37bd 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -17,6 +17,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300); @@ -72,7 +73,7 @@ class NoScrollbarBehavior extends MaterialScrollBehavior { } void main() { - testWidgets("Scrollbar doesn't show when tapping list", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Scrollbar doesn't show when tapping list", (WidgetTester tester) async { await tester.pumpWidget( _buildBoilerplate( child: Center( @@ -116,7 +117,7 @@ void main() { await tester.pump(const Duration(milliseconds: 200)); }); - testWidgets('ScrollbarPainter does not divide by zero', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarPainter does not divide by zero', (WidgetTester tester) async { await tester.pumpWidget( _buildBoilerplate(child: SizedBox( height: 200.0, @@ -158,7 +159,7 @@ void main() { expect(canvas.invocations.isEmpty, isTrue); }); - testWidgets('When thumbVisibility is true, must pass a controller or find PrimaryScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When thumbVisibility is true, must pass a controller or find PrimaryScrollController', (WidgetTester tester) async { Widget viewWithScroll() { return _buildBoilerplate( child: Theme( @@ -181,7 +182,7 @@ void main() { expect(exception, isAssertionError); }); - testWidgets('When thumbVisibility is true, must pass a controller that is attached to a scroll view or find PrimaryScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When thumbVisibility is true, must pass a controller that is attached to a scroll view or find PrimaryScrollController', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll() { return _buildBoilerplate( @@ -206,7 +207,7 @@ void main() { expect(exception, isAssertionError); }); - testWidgets('On first render with thumbVisibility: true, the thumb shows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll() { return _buildBoilerplate( @@ -232,7 +233,7 @@ void main() { expect(find.byType(Scrollbar), paints..rect()); }); - testWidgets('On first render with thumbVisibility: true, the thumb shows with PrimaryScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows with PrimaryScrollController', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll() { return _buildBoilerplate( @@ -264,7 +265,7 @@ void main() { expect(find.byType(Scrollbar), paints..rect()); }); - testWidgets( + testWidgetsWithLeakTracking( 'When thumbVisibility is true, must pass a controller or find PrimaryScrollController', (WidgetTester tester) async { Widget viewWithScroll() { @@ -290,7 +291,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'When thumbVisibility is true, must pass a controller that is attached to a scroll view or find PrimaryScrollController', (WidgetTester tester) async { final ScrollController controller = ScrollController(); @@ -318,7 +319,7 @@ void main() { }, ); - testWidgets('On first render with thumbVisibility: true, the thumb shows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll() { return _buildBoilerplate( @@ -344,7 +345,7 @@ void main() { expect(find.byType(Scrollbar), paints..rect()); }); - testWidgets('On first render with thumbVisibility: true, the thumb shows with PrimaryScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows with PrimaryScrollController', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll() { return _buildBoilerplate( @@ -376,7 +377,7 @@ void main() { expect(find.byType(Scrollbar), paints..rect()); }); - testWidgets('On first render with thumbVisibility: false, the thumb is hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('On first render with thumbVisibility: false, the thumb is hidden', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll() { return _buildBoilerplate( @@ -402,7 +403,7 @@ void main() { expect(find.byType(Scrollbar), isNot(paints..rect())); }); - testWidgets( + testWidgetsWithLeakTracking( 'With thumbVisibility: true, fling a scroll. While it is still scrolling, set thumbVisibility: false. The thumb should not fade out until the scrolling stops.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); @@ -456,7 +457,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'With thumbVisibility: false, set thumbVisibility: true. The thumb should be always shown directly', (WidgetTester tester) async { final ScrollController controller = ScrollController(); @@ -505,7 +506,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'With thumbVisibility: false, fling a scroll. While it is still scrolling, set thumbVisibility: true. The thumb should not fade even after the scrolling stops', (WidgetTester tester) async { final ScrollController controller = ScrollController(); @@ -565,7 +566,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Toggling thumbVisibility while not scrolling fades the thumb in/out. This works even when you have never scrolled at all yet', (WidgetTester tester) async { final ScrollController controller = ScrollController(); @@ -614,7 +615,7 @@ void main() { }, ); - testWidgets('Scrollbar respects thickness and radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar respects thickness and radius', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll({Radius? radius}) { return _buildBoilerplate( @@ -676,7 +677,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Tapping the track area pages the Scroll View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping the track area pages the Scroll View', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( Directionality( @@ -847,7 +848,7 @@ void main() { ); }); - testWidgets('Scrollbar thumb can be dragged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb can be dragged', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( MaterialApp( @@ -939,7 +940,7 @@ void main() { ); }); - testWidgets('Scrollbar thumb color completes a hover animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb color completes a hover animation', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -987,7 +988,7 @@ void main() { }), ); - testWidgets('Hover animation is not triggered by tap gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hover animation is not triggered by tap gestures', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1062,7 +1063,7 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.linux }), ); - testWidgets('ScrollbarThemeData.thickness replaces hoverThickness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarThemeData.thickness replaces hoverThickness', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1134,7 +1135,7 @@ void main() { }), ); - testWidgets('ScrollbarThemeData.trackVisibility replaces showTrackOnHover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarThemeData.trackVisibility replaces showTrackOnHover', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1202,7 +1203,7 @@ void main() { }), ); - testWidgets('Scrollbar showTrackOnHover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar showTrackOnHover', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1265,7 +1266,7 @@ void main() { }), ); - testWidgets('Adaptive scrollbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adaptive scrollbar', (WidgetTester tester) async { Widget viewWithScroll(TargetPlatform platform) { return _buildBoilerplate( child: Theme( @@ -1302,7 +1303,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Scrollbar passes controller to CupertinoScrollbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar passes controller to CupertinoScrollbar', (WidgetTester tester) async { final ScrollController controller = ScrollController(); Widget viewWithScroll(TargetPlatform? platform) { return _buildBoilerplate( @@ -1334,7 +1335,7 @@ void main() { expect(scrollbar.controller, isNotNull); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); - testWidgets("Scrollbar doesn't show when scroll the inner scrollable widget", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Scrollbar doesn't show when scroll the inner scrollable widget", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); final GlobalKey outerKey = GlobalKey(); @@ -1397,7 +1398,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('Scrollbar dragging can be disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar dragging can be disabled', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( MaterialApp( @@ -1466,7 +1467,7 @@ void main() { expect(scrollController.offset, scrollAmount); }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); - testWidgets('Scrollbar dragging is disabled by default on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar dragging is disabled by default on Android', (WidgetTester tester) async { int tapCount = 0; final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -1560,7 +1561,7 @@ void main() { expect(tapCount, 2); }); - testWidgets('Simultaneous dragging and pointer scrolling does not cause a crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simultaneous dragging and pointer scrolling does not cause a crash', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/70105 final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -1732,7 +1733,7 @@ void main() { ); }); - testWidgets('Scrollbar.thumbVisibility triggers assertion when multiple ScrollPositions are attached.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar.thumbVisibility triggers assertion when multiple ScrollPositions are attached.', (WidgetTester tester) async { Widget getTabContent({ ScrollController? scrollController }) { return Scrollbar( thumbVisibility: true, @@ -1799,7 +1800,7 @@ void main() { ); }); - testWidgets('Scrollbar scrollOrientation works correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar scrollOrientation works correctly', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); Widget buildScrollWithOrientation(ScrollbarOrientation orientation) { diff --git a/packages/flutter/test/material/scrollbar_theme_test.dart b/packages/flutter/test/material/scrollbar_theme_test.dart index 50c6ba74f6ad7..286c4af61162d 100644 --- a/packages/flutter/test/material/scrollbar_theme_test.dart +++ b/packages/flutter/test/material/scrollbar_theme_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; // The const represents the starting position of the scrollbar thumb for @@ -31,7 +32,7 @@ void main() { expect(identical(ScrollbarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Passing no ScrollbarTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no ScrollbarTheme returns defaults', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( MaterialApp( @@ -122,7 +123,7 @@ void main() { }), ); - testWidgets('Scrollbar uses values from ScrollbarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar uses values from ScrollbarTheme', (WidgetTester tester) async { final ScrollbarThemeData scrollbarTheme = _scrollbarTheme(); final ScrollController scrollController = ScrollController(); await tester.pumpWidget(MaterialApp( @@ -213,7 +214,7 @@ void main() { }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Scrollbar uses values from ScrollbarTheme if exists instead of values from Theme', (WidgetTester tester) async { final ScrollbarThemeData scrollbarTheme = _scrollbarTheme(); @@ -257,7 +258,7 @@ void main() { }, ); - testWidgets('ScrollbarTheme can disable gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarTheme can disable gestures', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false, scrollbarTheme: const ScrollbarThemeData(interactive: false)), @@ -304,7 +305,7 @@ void main() { ); }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); - testWidgets('Scrollbar.interactive takes priority over ScrollbarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar.interactive takes priority over ScrollbarTheme', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false, scrollbarTheme: const ScrollbarThemeData(interactive: false)), @@ -352,7 +353,7 @@ void main() { ); }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); - testWidgets('Scrollbar widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar widget properties take priority over theme', (WidgetTester tester) async { const double thickness = 4.0; const bool showTrackOnHover = true; const Radius radius = Radius.circular(3.0); @@ -451,7 +452,7 @@ void main() { }), ); - testWidgets('ThemeData colorScheme is used when no ScrollbarTheme is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData colorScheme is used when no ScrollbarTheme is set', (WidgetTester tester) async { Widget buildFrame(ThemeData appTheme) { final ScrollController scrollController = ScrollController(); return MaterialApp( @@ -619,7 +620,7 @@ void main() { }), ); - testWidgets('ScrollbarThemeData.trackVisibility test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarThemeData.trackVisibility test', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); bool? getTrackVisibility(Set states) { return true; @@ -665,7 +666,7 @@ void main() { }), ); - testWidgets('Default ScrollbarTheme debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ScrollbarTheme debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ScrollbarThemeData().debugFillProperties(builder); @@ -677,7 +678,7 @@ void main() { expect(description, []); }); - testWidgets('ScrollbarTheme implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarTheme implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); ScrollbarThemeData( thickness: MaterialStateProperty.resolveWith(_getThickness), diff --git a/packages/flutter/test/material/search_bar_theme_test.dart b/packages/flutter/test/material/search_bar_theme_test.dart index 7a6ef96865896..d6a2593797748 100644 --- a/packages/flutter/test/material/search_bar_theme_test.dart +++ b/packages/flutter/test/material/search_bar_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('SearchBarThemeData copyWith, ==, hashCode basics', () { expect(const SearchBarThemeData(), const SearchBarThemeData().copyWith()); @@ -48,7 +50,7 @@ void main() { expect(theme.data.constraints, null); }); - testWidgets('Default SearchBarThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SearchBarThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SearchBarThemeData().debugFillProperties(builder); @@ -60,7 +62,7 @@ void main() { expect(description, []); }); - testWidgets('SearchBarThemeData implements debugFillProperties', ( + testWidgetsWithLeakTracking('SearchBarThemeData implements debugFillProperties', ( WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SearchBarThemeData( @@ -233,19 +235,19 @@ void main() { expect(trailingRect.right, barRect.right - 16.0); } - testWidgets('SearchBar properties overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgets('SearchBar theme data overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); }); - testWidgets('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); @@ -253,7 +255,7 @@ void main() { // Same as the previous tests with empty SearchBarThemeData's instead of null. - testWidgets('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true, searchBarThemeData: const SearchBarThemeData(), overallTheme: const SearchBarThemeData())); @@ -261,14 +263,14 @@ void main() { checkSearchBar(tester); }); - testWidgets('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme, overallTheme: const SearchBarThemeData())); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgets('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); diff --git a/packages/flutter/test/material/search_view_theme_test.dart b/packages/flutter/test/material/search_view_theme_test.dart index b85c61ef57cd1..98e8e379cc6dd 100644 --- a/packages/flutter/test/material/search_view_theme_test.dart +++ b/packages/flutter/test/material/search_view_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('SearchViewThemeData copyWith, ==, hashCode basics', () { expect(const SearchViewThemeData(), const SearchViewThemeData().copyWith()); @@ -44,7 +46,7 @@ void main() { expect(theme.data.dividerColor, null); }); - testWidgets('Default SearchViewThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SearchViewThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SearchViewThemeData().debugFillProperties(builder); @@ -56,7 +58,7 @@ void main() { expect(description, []); }); - testWidgets('SearchViewThemeData implements debugFillProperties', ( + testWidgetsWithLeakTracking('SearchViewThemeData implements debugFillProperties', ( WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SearchViewThemeData( @@ -195,21 +197,21 @@ void main() { expect(inputText.style.fontSize, headerTextStyle.fontSize); } - testWidgets('SearchView properties overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchView(tester); }); - testWidgets('SearchView theme data overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); checkSearchView(tester); }); - testWidgets('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); @@ -218,7 +220,7 @@ void main() { // Same as the previous tests with empty SearchViewThemeData's instead of null. - testWidgets('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true, searchViewThemeData: const SearchViewThemeData(), overallTheme: const SearchViewThemeData())); @@ -227,7 +229,7 @@ void main() { checkSearchView(tester); }); - testWidgets('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme, overallTheme: const SearchViewThemeData())); await tester.tap(find.byIcon(Icons.search)); @@ -235,7 +237,7 @@ void main() { checkSearchView(tester); }); - testWidgets('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish diff --git a/packages/flutter/test/material/segmented_button_theme_test.dart b/packages/flutter/test/material/segmented_button_theme_test.dart index f978b4bb4a768..6c2cf45a0df6b 100644 --- a/packages/flutter/test/material/segmented_button_theme_test.dart +++ b/packages/flutter/test/material/segmented_button_theme_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('SegmentedButtonThemeData copyWith, ==, hashCode basics', () { @@ -29,7 +31,7 @@ void main() { expect(identical(SegmentedButtonThemeData.lerp(theme, theme, 0.5), theme), true); }); - testWidgets('Default SegmentedButtonThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SegmentedButtonThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SegmentedButtonThemeData().debugFillProperties(builder); @@ -41,7 +43,7 @@ void main() { expect(description, []); }); - testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -108,7 +110,7 @@ void main() { } }); - testWidgets('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: true, segmentedButtonTheme: SegmentedButtonThemeData( @@ -201,7 +203,7 @@ void main() { } }); - testWidgets('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { @@ -328,7 +330,7 @@ void main() { } }); - testWidgets('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index b9fb37c582d6e..c5d110b1ad9a8 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -9,6 +9,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0); final Offset localOffset = paragraph.getOffsetForCaret(TextPosition(offset: offset), caret); @@ -16,7 +18,7 @@ Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { } void main() { - testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectionArea uses correct selection controls', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('abc'), @@ -38,7 +40,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123378 await tester.pumpWidget( const MaterialApp( @@ -69,7 +71,7 @@ void main() { }); - testWidgets('builds the default context menu by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds the default context menu by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SelectionArea( @@ -96,7 +98,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('builds a custom context menu if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds a custom context menu if provided', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -132,7 +134,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes', (WidgetTester tester) async { SelectedContent? content; await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 4f3a41e1f9fce..c4bbe9527569f 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -20,7 +21,7 @@ void main() { expect(identical(SliderThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData().debugFillProperties(builder); @@ -32,7 +33,7 @@ void main() { expect(description, []); }); - testWidgets('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData( trackHeight: 7.0, @@ -502,7 +503,7 @@ void main() { } }); - testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider parameters overrides theme properties', (WidgetTester tester) async { debugDisableShadows = false; const Color activeTrackColor = Color(0xffff0001); const Color inactiveTrackColor = Color(0xffff0002); @@ -556,7 +557,7 @@ void main() { } }); - testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -580,7 +581,7 @@ void main() { ); }); - testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -604,7 +605,7 @@ void main() { ); }); - testWidgets('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -634,7 +635,7 @@ void main() { expect(sliderTheme.valueIndicatorTextStyle!.color, equals(customColor4)); }); - testWidgets('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -658,7 +659,7 @@ void main() { expect(sliderTheme.rangeValueIndicatorShape, const PaddleRangeSliderValueIndicatorShape()); }); - testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData lerps correctly', (WidgetTester tester) async { final SliderThemeData sliderThemeBlack = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -692,7 +693,7 @@ void main() { expect(lerp.valueIndicatorTextStyle!.color, equals(middleGrey.withAlpha(0xff))); }); - testWidgets('Default slider track draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider track draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -728,7 +729,7 @@ void main() { ); }); - testWidgets('Default slider overlay draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider overlay draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -789,7 +790,7 @@ void main() { ); }); - testWidgets('Slider can use theme overlay with material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can use theme overlay with material states', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -848,7 +849,7 @@ void main() { ); }); - testWidgets('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -892,7 +893,7 @@ void main() { ); }); - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1076,7 +1077,7 @@ void main() { } }); - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1260,7 +1261,7 @@ void main() { } }); - testWidgets('The slider track height can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider track height can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(trackHeight: 16); const Radius radius = Radius.circular(8); const Radius activatedRadius = Radius.circular(9); @@ -1290,7 +1291,7 @@ void main() { ); }); - testWidgets('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 7, @@ -1315,7 +1316,7 @@ void main() { ); }); - testWidgets('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 9, @@ -1338,7 +1339,7 @@ void main() { ); }); - testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5), activeTickMarkColor: const Color(0xfadedead), @@ -1371,7 +1372,7 @@ void main() { ); }); - testWidgets('The default slider overlay shape size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider overlay shape size can be overridden', (WidgetTester tester) async { const double uniqueOverlayRadius = 23; final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: const RoundSliderOverlayShape( @@ -1398,7 +1399,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/74503 - testWidgets('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1439,7 +1440,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/125467 - testWidgets('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1490,7 +1491,7 @@ void main() { // // The value indicator can be skipped by passing the appropriate // [ShowValueIndicator]. - testWidgets('The slider can skip all of its component painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all of its component painting', (WidgetTester tester) async { // Pump a slider with all shapes skipped. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1511,7 +1512,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the track', (WidgetTester tester) async { // Pump a slider with just a track. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1532,7 +1533,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { // Pump a slider with just tick marks. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1556,7 +1557,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the thumb', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a thumb. @@ -1582,7 +1583,7 @@ void main() { } }); - testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the overlay', (WidgetTester tester) async { // Pump a slider with just an overlay. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1610,7 +1611,7 @@ void main() { await gesture.up(); }); - testWidgets('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1640,7 +1641,7 @@ void main() { await gesture.up(); }); - testWidgets('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1675,7 +1676,7 @@ void main() { await gesture.up(); }); - testWidgets('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1707,7 +1708,7 @@ void main() { }); - testWidgets('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1757,7 +1758,7 @@ void main() { } }); - testWidgets('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { debugDisableShadows = true; final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -1803,7 +1804,7 @@ void main() { await gesture.up(); }); - testWidgets('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1837,7 +1838,7 @@ void main() { } }); - testWidgets('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1873,7 +1874,7 @@ void main() { } }); - testWidgets('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( trackShape: const RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight( @@ -1900,7 +1901,7 @@ void main() { ); }); - testWidgets('The mouse cursor is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The mouse cursor is themeable', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( mouseCursor: const MaterialStatePropertyAll(SystemMouseCursors.text), @@ -1915,7 +1916,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { double value = 0.0; Widget buildApp({ @@ -2022,7 +2023,7 @@ void main() { await gesture.up(); }); - testWidgets('Default value indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -2235,7 +2236,7 @@ void main() { } }); - testWidgets('Default value indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( diff --git a/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart b/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart index 2346513651263..002aba3fecc26 100644 --- a/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart +++ b/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('positions itself at anchorAbove if it fits and shifts up when not', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positions itself at anchorAbove if it fits and shifts up when not', (WidgetTester tester) async { late StateSetter setState; const double toolbarOverlap = 100; const double height = 500; diff --git a/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart b/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart index 66c668f671b02..6a97355d0b107 100644 --- a/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart +++ b/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + // Vertical position at which to anchor the toolbar for testing. const double _kAnchor = 200; // Amount for toolbar to overlap bottom padding for testing. @@ -47,7 +49,7 @@ void main() { ); } - testWidgets('positions toolbar below anchor when it fits above bottom view padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positions toolbar below anchor when it fits above bottom view padding', (WidgetTester tester) async { // We expect the toolbar to be positioned right below the anchor with padding accounted for. await tester.pumpWidget( MaterialApp( @@ -64,7 +66,7 @@ void main() { expect(toolbarY, equals(_kAnchor)); }); - testWidgets('re-positions toolbar higher below anchor when it does not fit above bottom view padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('re-positions toolbar higher below anchor when it does not fit above bottom view padding', (WidgetTester tester) async { // We expect the toolbar to be positioned _kTestToolbarOverlap pixels above the anchor. const double expectedToolbarY = _kAnchor - _kTestToolbarOverlap; @@ -83,7 +85,7 @@ void main() { expect(toolbarY, equals(expectedToolbarY)); }); - testWidgets('more than three suggestions throws an error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('more than three suggestions throws an error', (WidgetTester tester) async { Future pumpToolbar(List suggestions) async { await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index e1ffc363765f4..6a57dbf5e2adb 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; @@ -23,7 +24,7 @@ Widget wrap({ required Widget child }) { } void main() { - testWidgets('SwitchListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile control test', (WidgetTester tester) async { final List log = []; await tester.pumpWidget(wrap( child: SwitchListTile( @@ -38,7 +39,7 @@ void main() { expect(log, equals([false, '-', false])); }); - testWidgets('SwitchListTile semantics test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile semantics test', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(wrap( child: Column( @@ -116,7 +117,7 @@ void main() { semantics.dispose(); }); - testWidgets('Material2 - SwitchListTile has the right colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SwitchListTile has the right colors', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( MediaQuery( @@ -170,7 +171,7 @@ void main() { ); }); - testWidgets('Material3 - SwitchListTile has the right colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile has the right colors', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( MediaQuery( @@ -221,7 +222,7 @@ void main() { ); }); - testWidgets('SwitchListTile.adaptive delegates to', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile.adaptive delegates to', (WidgetTester tester) async { bool value = false; Widget buildFrame(TargetPlatform platform) { @@ -268,7 +269,7 @@ void main() { } }); - testWidgets('SwitchListTile contentPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile contentPadding', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection) { return MediaQuery( data: const MediaQueryData(), @@ -306,7 +307,7 @@ void main() { expect(tester.getTopRight(find.text('L')).dx, 790.0); // 800 - contentPadding.start }); - testWidgets('SwitchListTile can autofocus unless disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile can autofocus unless disabled.', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( @@ -350,7 +351,7 @@ void main() { expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isFalse); }); - testWidgets('SwitchListTile controlAffinity test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile controlAffinity test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: SwitchListTile( @@ -370,7 +371,7 @@ void main() { expect(listTile.trailing.runtimeType, Icon); }); - testWidgets('SwitchListTile controlAffinity default value test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile controlAffinity default value test', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: SwitchListTile( @@ -390,7 +391,7 @@ void main() { expect(listTile.trailing.runtimeType, Switch); }); - testWidgets('SwitchListTile respects shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects shape', (WidgetTester tester) async { const ShapeBorder shapeBorder = RoundedRectangleBorder( borderRadius: BorderRadius.horizontal(right: Radius.circular(100)), ); @@ -409,7 +410,7 @@ void main() { expect(tester.widget(find.byType(InkWell)).customBorder, shapeBorder); }); - testWidgets('SwitchListTile respects tileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects tileColor', (WidgetTester tester) async { final Color tileColor = Colors.red.shade500; await tester.pumpWidget( @@ -428,7 +429,7 @@ void main() { expect(find.byType(Material), paints..rect(color: tileColor)); }); - testWidgets('SwitchListTile respects selectedTileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects selectedTileColor', (WidgetTester tester) async { final Color selectedTileColor = Colors.green.shade500; await tester.pumpWidget( @@ -448,7 +449,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('SwitchListTile selected item text Color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile selected item text Color', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/76909 const Color activeColor = Color(0xff00ff00); @@ -487,7 +488,7 @@ void main() { expect(textColor('title'), activeColor); }); - testWidgets('SwitchListTile respects visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects visualDensity', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( @@ -511,7 +512,7 @@ void main() { expect(box.size, equals(const Size(800, 56))); }); - testWidgets('SwitchListTile respects focusNode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects focusNode', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( wrap( @@ -533,7 +534,7 @@ void main() { expect(tileNode.hasPrimaryFocus, isTrue); }); - testWidgets('SwitchListTile onFocusChange callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile onFocusChange callback', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'SwitchListTile onFocusChange'); bool gotFocus = false; await tester.pumpWidget( @@ -562,7 +563,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('SwitchListTile.adaptive onFocusChange Callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile.adaptive onFocusChange Callback', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'SwitchListTile.adaptive onFocusChange'); bool gotFocus = false; await tester.pumpWidget( @@ -602,7 +603,7 @@ void main() { feedback.dispose(); }); - testWidgets('SwitchListTile respects enableFeedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects enableFeedback', (WidgetTester tester) async { Future buildTest(bool enableFeedback) async { return tester.pumpWidget( wrap( @@ -631,7 +632,7 @@ void main() { }); }); - testWidgets('SwitchListTile respects hoverColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects hoverColor', (WidgetTester tester) async { const Key key = Key('test'); await tester.pumpWidget( wrap( @@ -671,7 +672,7 @@ void main() { ); }); - testWidgets('Material2 - SwitchListTile respects thumbColor in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SwitchListTile respects thumbColor in active/enabled states', (WidgetTester tester) async { const Color activeEnabledThumbColor = Color(0xFF000001); const Color activeDisabledThumbColor = Color(0xFF000002); const Color inactiveEnabledThumbColor = Color(0xFF000003); @@ -739,7 +740,7 @@ void main() { ); }); - testWidgets('Material3 - SwitchListTile respects thumbColor in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile respects thumbColor in active/enabled states', (WidgetTester tester) async { const Color activeEnabledThumbColor = Color(0xFF000001); const Color activeDisabledThumbColor = Color(0xFF000002); const Color inactiveEnabledThumbColor = Color(0xFF000003); @@ -807,7 +808,7 @@ void main() { ); }); - testWidgets('Material2 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF4caf50); const Color pressedThumbColor = Color(0xFFF44336); @@ -863,7 +864,7 @@ void main() { ); }); - testWidgets('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF4caf50); const Color pressedThumbColor = Color(0xFFF44336); @@ -919,7 +920,7 @@ void main() { ); }); - testWidgets('SwitchListTile respects trackColor in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects trackColor in active/enabled states', (WidgetTester tester) async { const Color activeEnabledTrackColor = Color(0xFF000001); const Color activeDisabledTrackColor = Color(0xFF000002); const Color inactiveEnabledTrackColor = Color(0xFF000003); @@ -984,7 +985,7 @@ void main() { ); }); - testWidgets('SwitchListTile respects trackColor in hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects trackColor in hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredTrackColor = Color(0xFF4caf50); @@ -1025,7 +1026,7 @@ void main() { ); }); - testWidgets('SwitchListTile respects thumbIcon - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects thumbIcon - M3', (WidgetTester tester) async { const Icon activeIcon = Icon(Icons.check); const Icon inactiveIcon = Icon(Icons.close); @@ -1110,7 +1111,7 @@ void main() { ); }); - testWidgets('Material2 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { Widget buildSwitchListTile(MaterialTapTargetSize materialTapTargetSize) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1138,7 +1139,7 @@ void main() { expect(tester.getSize(find.byType(Switch)), const Size(59.0, 40.0)); }); - testWidgets('Material3 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { Widget buildSwitchListTile(MaterialTapTargetSize materialTapTargetSize) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1166,7 +1167,7 @@ void main() { expect(tester.getSize(find.byType(Switch)), const Size(60.0, 40.0)); }); - testWidgets('Material2 - SwitchListTile.adaptive respects applyCupertinoTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SwitchListTile.adaptive respects applyCupertinoTheme', (WidgetTester tester) async { Widget buildSwitchListTile(bool applyCupertinoTheme, TargetPlatform platform) { return MaterialApp( theme: ThemeData(useMaterial3: false, platform: platform), @@ -1202,7 +1203,7 @@ void main() { } }); - testWidgets('Material3 - SwitchListTile.adaptive respects applyCupertinoTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile.adaptive respects applyCupertinoTheme', (WidgetTester tester) async { Widget buildSwitchListTile(bool applyCupertinoTheme, TargetPlatform platform) { return MaterialApp( theme: ThemeData(useMaterial3: true, platform: platform), @@ -1238,7 +1239,7 @@ void main() { } }); - testWidgets('Material2 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { Widget buildSwitchListTile(MaterialTapTargetSize materialTapTargetSize) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1266,7 +1267,7 @@ void main() { expect(tester.getSize(find.byType(Switch)), const Size(59.0, 40.0)); }); - testWidgets('Material3 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile respects materialTapTargetSize', (WidgetTester tester) async { Widget buildSwitchListTile(MaterialTapTargetSize materialTapTargetSize) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1294,7 +1295,7 @@ void main() { expect(tester.getSize(find.byType(Switch)), const Size(60.0, 40.0)); }); - testWidgets('SwitchListTile passes the value of dragStartBehavior to Switch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile passes the value of dragStartBehavior to Switch', (WidgetTester tester) async { Widget buildSwitchListTile(DragStartBehavior dragStartBehavior) { return wrap( child: StatefulBuilder( @@ -1317,7 +1318,7 @@ void main() { expect(switchWidget1.dragStartBehavior, DragStartBehavior.down); }); - testWidgets('Switch on SwitchListTile changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch on SwitchListTile changes mouse cursor when hovered', (WidgetTester tester) async { // Test SwitchListTile.adaptive() constructor await tester.pumpWidget(wrap( child: StatefulBuilder( @@ -1378,7 +1379,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('Switch with splash radius set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch with splash radius set', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 35; await tester.pumpWidget(wrap( @@ -1404,7 +1405,7 @@ void main() { ); }); - testWidgets('The overlay color for the thumb of the switch resolves in active/pressed/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The overlay color for the thumb of the switch resolves in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color activeThumbColor = Color(0xFF000000); const Color inactiveThumbColor = Color(0xFF000010); @@ -1525,7 +1526,7 @@ void main() { ); }); - testWidgets('SwitchListTile respects trackOutlineColor in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects trackOutlineColor in active/enabled states', (WidgetTester tester) async { const Color activeEnabledTrackOutlineColor = Color(0xFF000001); const Color activeDisabledTrackOutlineColor = Color(0xFF000002); const Color inactiveEnabledTrackOutlineColor = Color(0xFF000003); @@ -1594,7 +1595,7 @@ void main() { ); }); - testWidgets('SwitchListTile respects trackOutlineColor in hovered state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchListTile respects trackOutlineColor in hovered state', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredTrackColor = Color(0xFF4caf50); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index f7377f97d3d42..c1fad4ed82c95 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -18,13 +18,14 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { final ThemeData theme = ThemeData(); - testWidgets('Switch can toggle on tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch can toggle on tap', (WidgetTester tester) async { final Key switchKey = UniqueKey(); bool value = false; @@ -60,7 +61,7 @@ void main() { expect(value, isTrue); }); - testWidgets('Switch size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; await tester.pumpWidget( Theme( @@ -106,7 +107,7 @@ void main() { expect(tester.getSize(find.byType(Switch)), material3 ? const Size(60.0, 40.0) : const Size(59.0, 40.0)); }); - testWidgets('Material2 - Switch does not get distorted upon changing constraints with parent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch does not get distorted upon changing constraints with parent', (WidgetTester tester) async { const double maxWidth = 300; const double maxHeight = 100; @@ -158,7 +159,7 @@ void main() { ); }); - testWidgets('Material3 - Switch does not get distorted upon changing constraints with parent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch does not get distorted upon changing constraints with parent', (WidgetTester tester) async { const double maxWidth = 300; const double maxHeight = 100; @@ -210,7 +211,7 @@ void main() { ); }); - testWidgets('Switch can drag (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch can drag (LTR)', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( @@ -260,7 +261,7 @@ void main() { expect(value, isFalse); }); - testWidgets('Switch can drag with dragStartBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch can drag with dragStartBehavior', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( @@ -352,7 +353,7 @@ void main() { expect(value, isFalse); }); - testWidgets('Switch can drag (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch can drag (RTL)', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( @@ -400,7 +401,7 @@ void main() { expect(value, isFalse); }); - testWidgets('Material2 - Switch has default colors when enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch has default colors when enabled', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( MaterialApp( @@ -459,7 +460,7 @@ void main() { ); }); - testWidgets('Material3 - Switch has default colors when enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch has default colors when enabled', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colors = theme.colorScheme; bool value = false; @@ -524,7 +525,7 @@ void main() { ); }); - testWidgets('Material2 - Switch has default colors when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch has default colors when disabled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -588,7 +589,7 @@ void main() { ); }); - testWidgets('Material3 - Inactive Switch has default colors when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Inactive Switch has default colors when disabled', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; @@ -626,7 +627,7 @@ void main() { ); }); - testWidgets('Material3 - Active Switch has default colors when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Active Switch has default colors when disabled', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; await tester.pumpWidget(MaterialApp( @@ -659,7 +660,7 @@ void main() { ); }); - testWidgets('Material2 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; Finder findSwitch() { @@ -703,7 +704,7 @@ void main() { ); }); - testWidgets('Material3 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -748,7 +749,7 @@ void main() { ); }); - testWidgets('Material2 - Switch can be set color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch can be set color', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( MaterialApp( @@ -809,7 +810,7 @@ void main() { ); }); - testWidgets('Material3 - Switch can be set color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch can be set color', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; @@ -874,7 +875,7 @@ void main() { ); }); - testWidgets('Drag ends after animation completes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag ends after animation completes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17773 bool value = false; @@ -919,7 +920,7 @@ void main() { expect(tester.hasRunningAnimations, false); }); - testWidgets('can veto switch dragging result', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can veto switch dragging result', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( @@ -1000,7 +1001,7 @@ void main() { expect(state.position.value, 1.0); }); - testWidgets('switch has semantic events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('switch has semantic events', (WidgetTester tester) async { dynamic semanticEvent; bool value = false; tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, (dynamic message) async { @@ -1047,7 +1048,7 @@ void main() { tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('switch sends semantic events from parent if fully merged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('switch sends semantic events from parent if fully merged', (WidgetTester tester) async { dynamic semanticEvent; bool value = false; tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, (dynamic message) async { @@ -1098,7 +1099,7 @@ void main() { tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('Switch.adaptive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch.adaptive', (WidgetTester tester) async { bool value = false; const Color activeTrackColor = Color(0xffff1200); const Color inactiveTrackColor = Color(0xffff12ff); @@ -1158,7 +1159,7 @@ void main() { } }); - testWidgets('Material2 - Switch is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool value = true; @@ -1240,7 +1241,7 @@ void main() { ); }); - testWidgets('Material3 - Switch is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch is focusable and has correct focus color', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); @@ -1327,7 +1328,7 @@ void main() { ); }); - testWidgets('Switch with splash radius set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch with splash radius set', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; Widget buildApp() { @@ -1354,7 +1355,7 @@ void main() { ); }); - testWidgets('Material2 - Switch can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool value = true; Widget buildApp({bool enabled = true}) { @@ -1430,7 +1431,7 @@ void main() { ); }); - testWidgets('Material3 - Switch can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch can be hovered and has correct hover color', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -1502,7 +1503,7 @@ void main() { ); }); - testWidgets('Switch can be toggled by keyboard shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch can be toggled by keyboard shortcuts', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool value = true; Widget buildApp({bool enabled = true}) { @@ -1543,7 +1544,7 @@ void main() { expect(value, isTrue); }); - testWidgets('Switch changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch changes mouse cursor when hovered', (WidgetTester tester) async { // Test Switch.adaptive() constructor await tester.pumpWidget( MaterialApp( @@ -1647,7 +1648,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Material switch should not recreate its render object when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material switch should not recreate its render object when disabled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/61247. bool value = true; bool enabled = true; @@ -1694,7 +1695,7 @@ void main() { expect(updatedSwitchState.position.isDismissed, false); }); - testWidgets('Material2 - Switch thumb color resolves in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch thumb color resolves in active/enabled states', (WidgetTester tester) async { const Color activeEnabledThumbColor = Color(0xFF000001); const Color activeDisabledThumbColor = Color(0xFF000002); const Color inactiveEnabledThumbColor = Color(0xFF000003); @@ -1802,7 +1803,7 @@ void main() { ); }); - testWidgets('Material3 - Switch thumb color resolves in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch thumb color resolves in active/enabled states', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; const Color activeEnabledThumbColor = Color(0xFF000001); @@ -1911,7 +1912,7 @@ void main() { ); }); - testWidgets('Material2 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF000001); @@ -1987,7 +1988,7 @@ void main() { ); }); - testWidgets('Material3 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); @@ -2063,7 +2064,7 @@ void main() { ); }); - testWidgets('Material2 - Track color resolves in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Track color resolves in active/enabled states', (WidgetTester tester) async { const Color activeEnabledTrackColor = Color(0xFF000001); const Color activeDisabledTrackColor = Color(0xFF000002); const Color inactiveEnabledTrackColor = Color(0xFF000003); @@ -2152,7 +2153,7 @@ void main() { ); }); - testWidgets('Material3 - Track color resolves in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Track color resolves in active/enabled states', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); const Color activeEnabledTrackColor = Color(0xFF000001); const Color activeDisabledTrackColor = Color(0xFF000002); @@ -2245,7 +2246,7 @@ void main() { ); }); - testWidgets('Material2 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredTrackColor = Color(0xFF000001); @@ -2314,7 +2315,7 @@ void main() { ); }); - testWidgets('Material3 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -2384,7 +2385,7 @@ void main() { ); }); - testWidgets('Material2 - Switch thumb color is blended against surface color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch thumb color is blended against surface color', (WidgetTester tester) async { final Color activeDisabledThumbColor = Colors.blue.withOpacity(.60); final ThemeData theme = ThemeData.light(useMaterial3: false); @@ -2435,7 +2436,7 @@ void main() { ); }); - testWidgets('Material3 - Switch thumb color is blended against surface color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch thumb color is blended against surface color', (WidgetTester tester) async { final Color activeDisabledThumbColor = Colors.blue.withOpacity(.60); final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colors = theme.colorScheme; @@ -2485,7 +2486,7 @@ void main() { ); }); - testWidgets('Switch overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -2636,7 +2637,7 @@ void main() { ); }); - testWidgets('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { Widget buildSwitch(bool show) { return MaterialApp( theme: theme, @@ -2660,7 +2661,7 @@ void main() { await gesture.up(); }); - testWidgets('disabled switch shows tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled switch shows tooltip', (WidgetTester tester) async { const String longPressTooltip = 'long press tooltip'; const String tapTooltip = 'tap tooltip'; await tester.pumpWidget( @@ -2727,7 +2728,7 @@ void main() { image = await createTestImage(width: 100, height: 100); }); - testWidgets('thumb image shows up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('thumb image shows up', (WidgetTester tester) async { imageCache.clear(); final _TestImageProvider provider1 = _TestImageProvider(); final _TestImageProvider provider2 = _TestImageProvider(); @@ -2768,7 +2769,7 @@ void main() { expect(imageCache.liveImageCount, 2); }); - testWidgets('do not crash when imageProvider completes after Switch is disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('do not crash when imageProvider completes after Switch is disposed', (WidgetTester tester) async { final DelayedImageProvider imageProvider = DelayedImageProvider(image); await tester.pumpWidget( @@ -2796,7 +2797,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('do not crash when previous imageProvider completes after Switch is disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('do not crash when previous imageProvider completes after Switch is disposed', (WidgetTester tester) async { final DelayedImageProvider imageProvider1 = DelayedImageProvider(image); final DelayedImageProvider imageProvider2 = DelayedImageProvider(image); @@ -2837,7 +2838,7 @@ void main() { }); group('Switch M3 only tests', () { - testWidgets('M3 Switch has a 300-millisecond animation in total', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 Switch has a 300-millisecond animation in total', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); bool value = false; await tester.pumpWidget( @@ -2877,7 +2878,7 @@ void main() { expect(tester.hasRunningAnimations, false); }); - testWidgets('M3 Switch has a stadium shape in the middle of the track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 Switch has a stadium shape in the middle of the track', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true, colorSchemeSeed: Colors.deepPurple); bool value = false; await tester.pumpWidget( @@ -2922,7 +2923,7 @@ void main() { ); }); - testWidgets('M3 Switch thumb bounces in the end of the animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 Switch thumb bounces in the end of the animation', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); bool value = false; await tester.pumpWidget( @@ -3054,7 +3055,7 @@ void main() { ); }, variant: TargetPlatformVariant.mobile()); - testWidgets('Track outline color resolves in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Track outline color resolves in active/enabled states', (WidgetTester tester) async { const Color activeEnabledTrackOutlineColor = Color(0xFF000001); const Color activeDisabledTrackOutlineColor = Color(0xFF000002); const Color inactiveEnabledTrackOutlineColor = Color(0xFF000003); @@ -3130,7 +3131,7 @@ void main() { ); }); - testWidgets('Switch track outline color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch track outline color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredTrackOutlineColor = Color(0xFF000001); @@ -3189,7 +3190,7 @@ void main() { ); }); - testWidgets('Track outline width resolves in active/enabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Track outline width resolves in active/enabled states', (WidgetTester tester) async { const double activeEnabledTrackOutlineWidth = 1.0; const double activeDisabledTrackOutlineWidth = 2.0; const double inactiveEnabledTrackOutlineWidth = 3.0; @@ -3265,7 +3266,7 @@ void main() { ); }); - testWidgets('Switch track outline width resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch track outline width resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double hoveredTrackOutlineWidth = 4.0; @@ -3324,7 +3325,7 @@ void main() { ); }); - testWidgets('Switch can set icon - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch can set icon - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData( useMaterial3: true, colorSchemeSeed: const Color(0xff6750a4), @@ -3405,7 +3406,7 @@ void main() { }); }); - testWidgets('Switch.adaptive(Cupertino) is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch.adaptive(Cupertino) is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch.adaptive'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool value = true; @@ -3488,7 +3489,7 @@ void main() { ); }); - testWidgets('Switch.onFocusChange callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch.onFocusChange callback', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Switch'); bool focused = false; await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/switch_theme_test.dart b/packages/flutter/test/material/switch_theme_test.dart index 159defb60b811..86a459167ee01 100644 --- a/packages/flutter/test/material/switch_theme_test.dart +++ b/packages/flutter/test/material/switch_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { @@ -44,7 +45,7 @@ void main() { expect(theme.data.thumbIcon, null); }); - testWidgets('Default SwitchThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SwitchThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SwitchThemeData().debugFillProperties(builder); @@ -56,7 +57,7 @@ void main() { expect(description, []); }); - testWidgets('SwitchThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SwitchThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SwitchThemeData( thumbColor: MaterialStatePropertyAll(Color(0xfffffff0)), @@ -86,7 +87,7 @@ void main() { expect(description[8], 'thumbIcon: MaterialStatePropertyAll(Icon(IconData(U+0007B)))'); }); - testWidgets('Material2 - Switch is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch is themeable', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color defaultThumbColor = Color(0xfffffff0); @@ -209,7 +210,7 @@ void main() { expect(_getSwitchMaterial(tester), paints..circle(color: focusOverlayColor, radius: splashRadius)); }); - testWidgets('Material3 - Switch is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch is themeable', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color defaultThumbColor = Color(0xfffffff0); @@ -327,7 +328,7 @@ void main() { expect(_getSwitchMaterial(tester), paints..circle(color: focusOverlayColor, radius: splashRadius)); }); - testWidgets('Material2 - Switch properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch properties are taken over the theme values', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color themeDefaultThumbColor = Color(0xfffffff0); @@ -497,7 +498,7 @@ void main() { expect(_getSwitchMaterial(tester), paints..circle(color: focusColor, radius: splashRadius)); }); - testWidgets('Material3 - Switch properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch properties are taken over the theme values', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color themeDefaultThumbColor = Color(0xfffffff0); @@ -660,7 +661,7 @@ void main() { expect(_getSwitchMaterial(tester), paints..circle(color: focusColor, radius: splashRadius)); }); - testWidgets('Material2 - Switch active and inactive properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch active and inactive properties are taken over the theme values', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color themeDefaultThumbColor = Color(0xfffffff0); @@ -735,7 +736,7 @@ void main() { ); }); - testWidgets('Material3 - Switch active and inactive properties are taken over the theme values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch active and inactive properties are taken over the theme values', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color themeDefaultThumbColor = Color(0xfffffff0); @@ -806,7 +807,7 @@ void main() { ); }); - testWidgets('Material2 - Switch theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Switch theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); @@ -871,7 +872,7 @@ void main() { ); }); - testWidgets('Material3 - Switch theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Switch theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); @@ -937,7 +938,7 @@ void main() { ); }); - testWidgets('Material2 - Local SwitchTheme can override global SwitchTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Local SwitchTheme can override global SwitchTheme', (WidgetTester tester) async { const Color globalThemeThumbColor = Color(0xfffffff1); const Color globalThemeTrackColor = Color(0xfffffff2); const Color globalThemeOutlineColor = Color(0xfffffff3); @@ -991,7 +992,7 @@ void main() { ); }); - testWidgets('Material3 - Local SwitchTheme can override global SwitchTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Local SwitchTheme can override global SwitchTheme', (WidgetTester tester) async { const Color globalThemeThumbColor = Color(0xfffffff1); const Color globalThemeTrackColor = Color(0xfffffff2); const Color globalThemeOutlineColor = Color(0xfffffff3); diff --git a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart index 176b7aee4242a..6f495bf9a3824 100644 --- a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart +++ b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + // This is a regression test for https://github.com/flutter/flutter/issues/10549 // which was failing because _SliverPersistentHeaderElement.visitChildren() // didn't check child != null before visiting its child. @@ -74,7 +76,7 @@ class _MyHomePageState extends State with TickerProviderStateMixin { } void main() { - testWidgets('Tabbed CustomScrollViews, warp from tab 1 to 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tabbed CustomScrollViews, warp from tab 1 to 3', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: MyHomePage())); // should not crash. diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index a86fed59648d9..2db314e85e12c 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -10,11 +10,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('TextButton, TextButton.icon defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton, TextButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: colorScheme); final bool material3 = theme.useMaterial3; @@ -271,7 +272,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('TextButton default overlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton default overlayColor resolves pressed state', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final ThemeData theme = ThemeData(useMaterial3: true); @@ -324,7 +325,7 @@ void main() { expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); }); - testWidgets('TextButton uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -391,7 +392,7 @@ void main() { expect(textColor(), pressedColor); }); - testWidgets('TextButton uses stateful color for icon color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton uses stateful color for icon color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); final Key buttonKey = UniqueKey(); @@ -458,7 +459,7 @@ void main() { expect(iconColor(), pressedColor); }); - testWidgets('TextButton has no clip by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton has no clip by default', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -475,7 +476,7 @@ void main() { ); }); - testWidgets('Does TextButton work with hover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does TextButton work with hover', (WidgetTester tester) async { const Color hoverColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -504,7 +505,7 @@ void main() { expect(inkFeatures, paints..rect(color: hoverColor)); }); - testWidgets('Does TextButton work with focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does TextButton work with focus', (WidgetTester tester) async { const Color focusColor = Color(0xff001122); Color? getOverlayColor(Set states) { @@ -534,7 +535,7 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); }); - testWidgets('Does TextButton contribute semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does TextButton contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -579,7 +580,7 @@ void main() { semantics.dispose(); }); - testWidgets('Does TextButton scale with font scale changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does TextButton scale with font scale changes', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -652,7 +653,7 @@ void main() { expect(tester.getSize(find.byType(Text)), const Size(126.0, 42.0)); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/61016 - testWidgets('TextButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { return Theme( data: ThemeData(useMaterial3: false, materialTapTargetSize: tapTargetSize), @@ -679,7 +680,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(66.0, 36.0)); }); - testWidgets('TextButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { bool wasPressed; Finder textButton; @@ -722,7 +723,7 @@ void main() { expect(tester.widget(textButton).enabled, false); }); - testWidgets('TextButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton onPressed and onLongPress callbacks are distinctly recognized', (WidgetTester tester) async { bool didPressButton = false; bool didLongPressButton = false; @@ -753,7 +754,7 @@ void main() { expect(didLongPressButton, isTrue); }); - testWidgets("TextButton response doesn't hover when disabled", (WidgetTester tester) async { + testWidgetsWithLeakTracking("TextButton response doesn't hover when disabled", (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTouch; final FocusNode focusNode = FocusNode(debugLabel: 'TextButton Focus'); final GlobalKey childKey = GlobalKey(); @@ -803,7 +804,7 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }); - testWidgets('disabled and hovered TextButton responds to mouse-exit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled and hovered TextButton responds to mouse-exit', (WidgetTester tester) async { int onHoverCount = 0; late bool hover; @@ -865,7 +866,7 @@ void main() { expect(hover, false); }); - testWidgets('Can set TextButton focus and Can set unFocus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set TextButton focus and Can set unFocus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'TextButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -894,7 +895,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('When TextButton disable, Can not set TextButton focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When TextButton disable, Can not set TextButton focus.', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'TextButton Focus'); bool gotFocus = false; await tester.pumpWidget( @@ -917,7 +918,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('TextButton responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); const Key childKey = Key('test child'); @@ -1060,7 +1061,7 @@ void main() { 'RTL', ].join(', '); - testWidgets(testName, (WidgetTester tester) async { + testWidgetsWithLeakTracking(testName, (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -1208,7 +1209,7 @@ void main() { } }); - testWidgets('Override TextButton default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override TextButton default padding', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(colorScheme: const ColorScheme.light()), @@ -1242,7 +1243,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.all(22)); }); - testWidgets('M3 TextButton has correct default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 TextButton has correct default padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1268,7 +1269,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsets.symmetric(horizontal: 12,vertical: 8)); }); - testWidgets('M3 TextButton.icon has correct default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M3 TextButton.icon has correct default padding', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1295,7 +1296,7 @@ void main() { expect(paddingWidget.padding, const EdgeInsetsDirectional.fromSTEB(12, 8, 16, 8)); }); - testWidgets('Fixed size TextButtons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size TextButtons', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1328,7 +1329,7 @@ void main() { expect(tester.getSize(find.widgetWithText(TextButton, 'wx200')).height, 200); }); - testWidgets('TextButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton with NoSplash splashFactory paints nothing', (WidgetTester tester) async { Widget buildFrame({ InteractiveInkFeatureFactory? splashFactory }) { return MaterialApp( home: Scaffold( @@ -1368,7 +1369,7 @@ void main() { } }); - testWidgets('TextButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton uses InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -1395,7 +1396,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('TextButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton uses InkRipple when useMaterial3 is false', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( @@ -1417,7 +1418,7 @@ void main() { expect(buttonInkWell.splashFactory, equals(InkRipple.splashFactory)); }, variant: TargetPlatformVariant.all()); - testWidgets('TextButton.icon does not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton.icon does not overflow', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/77815 await tester.pumpWidget( MaterialApp( @@ -1438,7 +1439,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('TextButton.icon icon,label layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton.icon icon,label layout', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); final Key iconKey = UniqueKey(); final Key labelKey = UniqueKey(); @@ -1475,7 +1476,7 @@ void main() { expect(tester.getRect(find.byKey(labelKey)), const Rect.fromLTRB(104.0, 0.0, 154.0, 100.0)); }); - testWidgets('TextButton maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton maximumSize', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); @@ -1517,7 +1518,7 @@ void main() { expect(tester.getSize(find.byKey(key1)), const Size(104.0, 128.0)); }); - testWidgets('Fixed size TextButton, same as minimumSize == maximumSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fixed size TextButton, same as minimumSize == maximumSize', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1547,7 +1548,7 @@ void main() { expect(tester.getSize(find.widgetWithText(TextButton, '200,200')), const Size(200, 200)); }); - testWidgets('TextButton changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1625,7 +1626,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1648,7 +1649,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('TextButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton.styleFrom can be used to set foreground and background colors', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1778,15 +1779,15 @@ void main() { await gesture.removePointer(); } - testWidgets('TextButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('TextButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled TextButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled TextButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; @@ -1809,7 +1810,7 @@ void main() { expect(count, 1); }); - testWidgets('icon color can be different from the text color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('icon color can be different from the text color', (WidgetTester tester) async { final Key iconButtonKey = UniqueKey(); const ColorScheme colorScheme = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: colorScheme); @@ -1865,7 +1866,7 @@ void main() { expect(iconColor(), equals(Colors.blue)); }); - testWidgets("TextButton.styleFrom doesn't throw exception on passing only one cursor", (WidgetTester tester) async { + testWidgetsWithLeakTracking("TextButton.styleFrom doesn't throw exception on passing only one cursor", (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/118071. await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/material/text_button_theme_test.dart b/packages/flutter/test/material/text_button_theme_test.dart index 473e0a64473e7..fc0d023cc177b 100644 --- a/packages/flutter/test/material/text_button_theme_test.dart +++ b/packages/flutter/test/material/text_button_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('TextButtonTheme lerp special cases', () { expect(TextButtonThemeData.lerp(null, null, 0), null); @@ -12,7 +14,7 @@ void main() { expect(identical(TextButtonThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Material3: Passing no TextButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: Passing no TextButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -49,7 +51,7 @@ void main() { expect(align.alignment, Alignment.center); }); - testWidgets('Material2: Passing no TextButtonTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: Passing no TextButtonTheme returns defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); await tester.pumpWidget( MaterialApp( @@ -187,19 +189,19 @@ void main() { expect(align.alignment, alignment); } - testWidgets('Button style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(themeStyle: style)); await tester.pumpAndSettle(); checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallStyle: style)); await tester.pumpAndSettle(); checkButton(tester); @@ -207,26 +209,26 @@ void main() { // Same as the previous tests with empty ButtonStyle's instead of null. - testWidgets('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button style overrides defaults, empty theme and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: style, themeStyle: const ButtonStyle(), overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button theme style overrides defaults, empty button and overall styles', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), themeStyle: style, overallStyle: const ButtonStyle())); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); - testWidgets('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme button theme style overrides defaults, null theme and empty overall style', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(buttonStyle: const ButtonStyle(), overallStyle: style)); await tester.pumpAndSettle(); // allow the animations to finish checkButton(tester); }); }); - testWidgets('Material3: Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3: Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); @@ -297,7 +299,7 @@ void main() { expect(material.shadowColor, shadowColor); }); - testWidgets('Material2: Theme shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2: Theme shadowColor', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); const Color shadowColor = Color(0xff000001); const Color overriddenColor = Color(0xff000002); diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart index a5b4a06a421fd..21934175279ed 100644 --- a/packages/flutter/test/material/text_field_helper_text_test.dart +++ b/packages/flutter/test/material/text_field_helper_text_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField works correctly when changing helperText', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(1)); await tester.pump(const Duration(milliseconds: 100)); diff --git a/packages/flutter/test/material/text_field_splash_test.dart b/packages/flutter/test/material/text_field_splash_test.dart index b16f0ced9b951..ab26df41cbe0d 100644 --- a/packages/flutter/test/material/text_field_splash_test.dart +++ b/packages/flutter/test/material/text_field_splash_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/gestures.dart' show kPressTimeout; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + bool confirmCalled = false; bool cancelCalled = false; @@ -135,7 +137,7 @@ void main() { expect(cancelCalled, isFalse); }); - testWidgets('Splash should never be created or canceled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Splash should never be created or canceled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 12996a6e399f1..058828d4f39bd 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -253,7 +253,7 @@ void main() { leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: {'ValueNotifier<_OverlayEntryWidgetState?>': 16}), ); - testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); @@ -348,7 +348,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { bool asserted; try { TextFormField( @@ -361,7 +361,7 @@ void main() { expect(asserted, false); }); - testWidgets('Passes textAlign to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textAlign to underlying TextField', (WidgetTester tester) async { const TextAlign alignment = TextAlign.center; await tester.pumpWidget( @@ -383,7 +383,7 @@ void main() { expect(textFieldWidget.textAlign, alignment); }); - testWidgets('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { const ScrollPhysics scrollPhysics = ScrollPhysics(); await tester.pumpWidget( @@ -405,7 +405,7 @@ void main() { expect(textFieldWidget.scrollPhysics, scrollPhysics); }); - testWidgets('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { const TextAlignVertical textAlignVertical = TextAlignVertical.bottom; await tester.pumpWidget( @@ -427,7 +427,7 @@ void main() { expect(textFieldWidget.textAlignVertical, textAlignVertical); }); - testWidgets('Passes textInputAction to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textInputAction to underlying TextField', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -447,7 +447,7 @@ void main() { expect(textFieldWidget.textInputAction, TextInputAction.next); }); - testWidgets('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { void onEditingComplete() { } await tester.pumpWidget( @@ -469,7 +469,7 @@ void main() { expect(textFieldWidget.onEditingComplete, onEditingComplete); }); - testWidgets('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { const double cursorWidth = 3.14; const double cursorHeight = 6.28; const Radius cursorRadius = Radius.circular(4); @@ -521,7 +521,7 @@ void main() { expect(called, true); }); - testWidgets('onChanged callbacks are called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callbacks are called', (WidgetTester tester) async { late String value; await tester.pumpWidget( @@ -543,7 +543,7 @@ void main() { expect(value, 'Soup'); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -568,7 +568,7 @@ void main() { expect(validateCalled, 2); }); - testWidgets('validate is called if widget is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('validate is called if widget is enabled', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -595,7 +595,7 @@ void main() { }); - testWidgets('Disabled field hides helper and counter in M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled field hides helper and counter in M2', (WidgetTester tester) async { const String helperText = 'helper text'; const String counterText = 'counter text'; const String errorText = 'error text'; @@ -643,7 +643,7 @@ void main() { expect(errorWidget.style!.color, equals(Colors.transparent)); }); - testWidgets('passing a buildCounter shows returned widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing a buildCounter shows returned widget', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -708,7 +708,7 @@ void main() { expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); }, skip: isBrowser); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgets('onTap is called upon tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( MaterialApp( @@ -735,7 +735,7 @@ void main() { expect(tapCount, 3); }); - testWidgets('onTapOutside is called upon tap outside', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTapOutside is called upon tap outside', (WidgetTester tester) async { int tapOutsideCount = 0; await tester.pumpWidget( MaterialApp( @@ -766,7 +766,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgets('reset resets the text fields value to the initialValue', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reset resets the text fields value to the initialValue', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -789,7 +789,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgets("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { + testWidgetsWithLeakTracking("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -812,7 +812,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgets("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { + testWidgetsWithLeakTracking("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -835,7 +835,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgets('didChange changes text fields value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didChange changes text fields value', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -857,7 +857,7 @@ void main() { expect(find.text('changedValue'), findsOneWidget); }); - testWidgets('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { bool called = false; late FormFieldState state; @@ -884,7 +884,7 @@ void main() { expect(called, true); }); - testWidgets('autofillHints is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autofillHints is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -901,7 +901,7 @@ void main() { expect(widget.autofillHints, equals(const [AutofillHints.countryName])); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -926,7 +926,7 @@ void main() { expect(validateCalled, 1); }); - testWidgets('textSelectionControls is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textSelectionControls is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -943,7 +943,7 @@ void main() { expect(widget.selectionControls, equals(materialTextSelectionControls)); }); - testWidgets('TextFormField respects hintTextDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField respects hintTextDirection', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Directionality( @@ -985,7 +985,7 @@ void main() { expect(textDirection, TextDirection.rtl); }); - testWidgets('Passes scrollController to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scrollController to underlying TextField', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -1007,7 +1007,7 @@ void main() { expect(textFieldWidget.scrollController, scrollController); }); - testWidgets('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1152,7 +1152,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { final SpellCheckConfiguration mySpellCheckConfiguration = SpellCheckConfiguration( spellCheckService: DefaultSpellCheckService(), misspelledTextStyle: TextField.materialMisspelledTextStyle, @@ -1182,7 +1182,7 @@ void main() { ); }); - testWidgets('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { final TextMagnifierConfiguration myTextMagnifierConfiguration = TextMagnifierConfiguration( magnifierBuilder: (BuildContext context, MagnifierController controller, ValueNotifier notifier) { return const Placeholder(); @@ -1203,7 +1203,7 @@ void main() { expect(editableText.magnifierConfiguration, equals(myTextMagnifierConfiguration)); }); - testWidgets('Passes undoController to undoController TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes undoController to undoController TextField', (WidgetTester tester) async { final UndoHistoryController undoController = UndoHistoryController(value: UndoHistoryValue.empty); await tester.pumpWidget( @@ -1225,7 +1225,7 @@ void main() { expect(textFieldWidget.undoController, undoController); }); - testWidgets('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { const bool cursorOpacityAnimates = true; await tester.pumpWidget( @@ -1247,7 +1247,7 @@ void main() { expect(textFieldWidget.cursorOpacityAnimates, cursorOpacityAnimates); }); - testWidgets('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { final ContentInsertionConfiguration contentInsertionConfiguration = ContentInsertionConfiguration(onContentInserted: (KeyboardInsertedContent value) {}); @@ -1270,7 +1270,7 @@ void main() { expect(textFieldWidget.contentInsertionConfiguration, contentInsertionConfiguration); }); - testWidgets('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { const Clip clipBehavior = Clip.antiAlias; await tester.pumpWidget( @@ -1292,7 +1292,7 @@ void main() { expect(textFieldWidget.clipBehavior, clipBehavior); }); - testWidgets('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { const bool scribbleEnabled = false; await tester.pumpWidget( @@ -1314,7 +1314,7 @@ void main() { expect(textFieldWidget.scribbleEnabled, scribbleEnabled); }); - testWidgets('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { const bool canRequestFocus = false; await tester.pumpWidget( @@ -1336,7 +1336,7 @@ void main() { expect(textFieldWidget.canRequestFocus, canRequestFocus); }); - testWidgets('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { void onAppPrivateCommand(String p0, Map p1) {} await tester.pumpWidget( @@ -1358,7 +1358,7 @@ void main() { expect(textFieldWidget.onAppPrivateCommand, onAppPrivateCommand); }); - testWidgets('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { const BoxHeightStyle selectionHeightStyle = BoxHeightStyle.max; await tester.pumpWidget( @@ -1380,7 +1380,7 @@ void main() { expect(textFieldWidget.selectionHeightStyle, selectionHeightStyle); }); - testWidgets('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { const BoxWidthStyle selectionWidthStyle = BoxWidthStyle.max; await tester.pumpWidget( @@ -1402,7 +1402,7 @@ void main() { expect(textFieldWidget.selectionWidthStyle, selectionWidthStyle); }); - testWidgets('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { const DragStartBehavior dragStartBehavior = DragStartBehavior.down; await tester.pumpWidget( @@ -1424,7 +1424,7 @@ void main() { expect(textFieldWidget.dragStartBehavior, dragStartBehavior); }); - testWidgets('Error color for cursor while validating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Error color for cursor while validating', (WidgetTester tester) async { const Color errorColor = Color(0xff123456); await tester.pumpWidget(MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 7c767b5db17fc..b613e5c7904aa 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -28,7 +28,7 @@ void main() { expect(theme.selectionHandleColor, null); }); - testWidgets('Default TextSelectionThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default TextSelectionThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TextSelectionThemeData().debugFillProperties(builder); @@ -40,7 +40,7 @@ void main() { expect(description, []); }); - testWidgets('TextSelectionThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextSelectionThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TextSelectionThemeData( cursorColor: Color(0xffeeffaa), @@ -344,7 +344,7 @@ void main() { expect(renderSelectable.cursorColor, cursorColor.withAlpha(0)); }); - testWidgets('TextSelectionThem overrides DefaultSelectionStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextSelectionThem overrides DefaultSelectionStyle', (WidgetTester tester) async { const Color themeSelectionColor = Color(0xffaabbcc); const Color themeCursorColor = Color(0x00ccbbaa); const Color defaultSelectionColor = Color(0xffaa1111); diff --git a/packages/flutter/test/material/text_selection_toolbar_test.dart b/packages/flutter/test/material/text_selection_toolbar_test.dart index 33183cd826a4e..bac41d5ee6949 100644 --- a/packages/flutter/test/material/text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/editable_text_utils.dart' show textOffsetToPosition; const double _kToolbarContentDistance = 8.0; @@ -75,7 +76,7 @@ void main() { Finder findOverflowButton() => findPrivate('_TextSelectionToolbarOverflowButton'); - testWidgets('puts children in an overflow menu if they overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('puts children in an overflow menu if they overflow', (WidgetTester tester) async { late StateSetter setState; final List children = List.generate(7, (int i) => const TestBox()); @@ -172,7 +173,7 @@ void main() { expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); }); - testWidgets('can create and use a custom toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart index e584366920e0e..19900069529fc 100644 --- a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart @@ -5,10 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('position in the toolbar changes width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('position in the toolbar changes width', (WidgetTester tester) async { late StateSetter setState; int index = 1; int total = 3; diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index a69ff727cf270..b5b67bd6c9bac 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('Theme data control test', () { final ThemeData dark = ThemeData.dark(); @@ -83,7 +85,7 @@ void main() { expect(fallbackTheme.typography, Typography.material2021(colorScheme: fallbackTheme.colorScheme)); }); - testWidgets('Defaults to MaterialTapTargetBehavior.padded on mobile platforms and MaterialTapTargetBehavior.shrinkWrap on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Defaults to MaterialTapTargetBehavior.padded on mobile platforms and MaterialTapTargetBehavior.shrinkWrap on desktop', (WidgetTester tester) async { final ThemeData themeData = ThemeData(platform: defaultTargetPlatform); switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -370,7 +372,7 @@ void main() { expect(theme.applyElevationOverlayColor, true); }); - testWidgets('ThemeData.from a light color scheme sets appropriate values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.from a light color scheme sets appropriate values', (WidgetTester tester) async { const ColorScheme lightColors = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: lightColors); @@ -385,7 +387,7 @@ void main() { expect(theme.applyElevationOverlayColor, isFalse); }); - testWidgets('ThemeData.from a dark color scheme sets appropriate values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.from a dark color scheme sets appropriate values', (WidgetTester tester) async { const ColorScheme darkColors = ColorScheme.dark(); final ThemeData theme = ThemeData.from(colorScheme: darkColors); @@ -401,7 +403,7 @@ void main() { expect(theme.applyElevationOverlayColor, isTrue); }); - testWidgets('splashFactory is InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('splashFactory is InkSparkle only for Android non-web when useMaterial3 is true', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); // Basic check that this theme is in fact using material 3. @@ -423,7 +425,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('splashFactory is InkSplash for every platform scenario, including Android non-web, when useMaterial3 is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('splashFactory is InkSplash for every platform scenario, including Android non-web, when useMaterial3 is false', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); switch (debugDefaultTargetPlatformOverride!) { @@ -437,7 +439,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('VisualDensity.adaptivePlatformDensity returns adaptive values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('VisualDensity.adaptivePlatformDensity returns adaptive values', (WidgetTester tester) async { switch (debugDefaultTargetPlatformOverride!) { case TargetPlatform.android: case TargetPlatform.iOS: @@ -450,7 +452,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('VisualDensity.getDensityForPlatform returns adaptive values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('VisualDensity.getDensityForPlatform returns adaptive values', (WidgetTester tester) async { switch (debugDefaultTargetPlatformOverride!) { case TargetPlatform.android: case TargetPlatform.iOS: @@ -463,7 +465,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('VisualDensity in ThemeData defaults to "compact" on desktop and "standard" on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('VisualDensity in ThemeData defaults to "compact" on desktop and "standard" on mobile', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); switch (debugDefaultTargetPlatformOverride!) { case TargetPlatform.android: @@ -477,7 +479,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('VisualDensity in ThemeData defaults to the right thing when a platform is supplied to it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('VisualDensity in ThemeData defaults to the right thing when a platform is supplied to it', (WidgetTester tester) async { final ThemeData themeData = ThemeData(platform: debugDefaultTargetPlatformOverride! == TargetPlatform.android ? TargetPlatform.linux : TargetPlatform.android); switch (debugDefaultTargetPlatformOverride!) { case TargetPlatform.iOS: @@ -491,7 +493,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Ensure Visual Density effective constraints are clamped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ensure Visual Density effective constraints are clamped', (WidgetTester tester) async { const BoxConstraints square = BoxConstraints.tightFor(width: 35, height: 35); BoxConstraints expanded = const VisualDensity(horizontal: 4.0, vertical: 4.0).effectiveConstraints(square); expect(expanded.minWidth, equals(35)); @@ -519,7 +521,7 @@ void main() { expect(expanded.maxHeight, equals(4)); }); - testWidgets('Ensure Visual Density effective constraints expand and contract', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ensure Visual Density effective constraints expand and contract', (WidgetTester tester) async { const BoxConstraints square = BoxConstraints(); final BoxConstraints expanded = const VisualDensity(horizontal: 4.0, vertical: 4.0).effectiveConstraints(square); expect(expanded.minWidth, equals(16)); @@ -537,7 +539,7 @@ void main() { group('Theme extensions', () { const Key containerKey = Key('container'); - testWidgets('can be obtained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can be obtained', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -564,7 +566,7 @@ void main() { expect(theme.extension()!.textStyle, const TextStyle(fontSize: 50)); }); - testWidgets('can use copyWith', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use copyWith', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -587,7 +589,7 @@ void main() { expect(theme.extension()!.color2, Colors.amber); }); - testWidgets('can lerp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can lerp', (WidgetTester tester) async { const MyThemeExtensionA extensionA1 = MyThemeExtensionA( color1: Colors.black, color2: Colors.amber, @@ -663,7 +665,7 @@ void main() { expect(lerped.extension()!.textStyle, const TextStyle(fontSize: 100)); // Not lerped }); - testWidgets('should return null on extension not found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should return null on extension not found', (WidgetTester tester) async { final ThemeData theme = ThemeData( extensions: const >{}, ); @@ -695,7 +697,7 @@ void main() { expect(hoverColorBlack.hashCode != hoverColorWhite.hashCode, true); }); - testWidgets('ThemeData.copyWith correctly creates new ThemeData with all copied arguments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.copyWith correctly creates new ThemeData with all copied arguments', (WidgetTester tester) async { final SliderThemeData sliderTheme = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -1140,7 +1142,7 @@ void main() { expect(themeDataCopy.bottomAppBarColor, equals(otherTheme.bottomAppBarColor)); }); - testWidgets('ThemeData.toString has less than 200 characters output', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.toString has less than 200 characters output', (WidgetTester tester) async { // This test makes sure that the ThemeData debug output doesn't get too // verbose, which has been a problem in the past. @@ -1155,12 +1157,12 @@ void main() { expect(lightTheme.toString().length, lessThan(200)); }); - testWidgets('ThemeData brightness parameter overrides ColorScheme brightness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData brightness parameter overrides ColorScheme brightness', (WidgetTester tester) async { const ColorScheme lightColors = ColorScheme.light(); expect(() => ThemeData(colorScheme: lightColors, brightness: Brightness.dark), throwsAssertionError); }); - testWidgets('ThemeData.copyWith brightness parameter overrides ColorScheme brightness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.copyWith brightness parameter overrides ColorScheme brightness', (WidgetTester tester) async { const ColorScheme lightColors = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: lightColors).copyWith(brightness: Brightness.dark); diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index e577a9b1a03d9..7c6d42c2fa396 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -5,9 +5,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { group('TimeOfDay.format', () { - testWidgets('respects alwaysUse24HourFormat option', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects alwaysUse24HourFormat option', (WidgetTester tester) async { Future pumpTest(bool alwaysUse24HourFormat) async { late String formattedValue; await tester.pumpWidget(MaterialApp( @@ -27,7 +29,7 @@ void main() { }); }); - testWidgets('hourOfPeriod returns correct value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hourOfPeriod returns correct value', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59158. expect(const TimeOfDay(minute: 0, hour: 0).hourOfPeriod, 12); expect(const TimeOfDay(minute: 0, hour: 1).hourOfPeriod, 1); @@ -56,11 +58,11 @@ void main() { }); group('RestorableTimeOfDay tests', () { - testWidgets('value is not accessible when not registered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('value is not accessible when not registered', (WidgetTester tester) async { expect(() => RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)).value, throwsAssertionError); }); - testWidgets('work when not in restoration scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); final _RestorableWidgetState state = tester.state(find.byType(_RestorableWidget)); @@ -105,7 +107,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 2, minute: 2)); }); - testWidgets('restore to older state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restore to older state', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -136,7 +138,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 10, minute: 5)); }); - testWidgets('call notifiers when value changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('call notifiers when value changes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index ebf81c391f15c..8e4a059694bdd 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; @@ -37,7 +38,7 @@ Widget boilerplate({ } void main() { - testWidgets('Initial toggle state is reflected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial toggle state is reflected', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { return tester.widget(find.descendant( of: find.widgetWithText(TextButton, text), @@ -68,7 +69,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'onPressed is triggered on button tap', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { @@ -127,7 +128,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'onPressed that is null disables buttons', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { @@ -179,7 +180,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'children and isSelected properties have to be the same length', (WidgetTester tester) async { await expectLater( @@ -206,7 +207,7 @@ void main() { }, ); - testWidgets('Default text style is applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default text style is applied', (WidgetTester tester) async { final ThemeData theme = ThemeData(); await tester.pumpWidget( boilerplate( @@ -237,7 +238,7 @@ void main() { expect(textStyle.decoration, theme.textTheme.bodyMedium!.decoration); }); - testWidgets('Custom text style except color is applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom text style except color is applied', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: ToggleButtons( @@ -274,7 +275,7 @@ void main() { expect(textStyle.color, isNot(Colors.orange)); }); - testWidgets('Default BoxConstraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default BoxConstraints', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: ToggleButtons( @@ -300,7 +301,7 @@ void main() { expect(thirdRect.height, 48.0); }); - testWidgets('Custom BoxConstraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom BoxConstraints', (WidgetTester tester) async { // Test for minimum constraints await tester.pumpWidget( boilerplate( @@ -361,7 +362,7 @@ void main() { expect(thirdRect.height, 10.0); }); - testWidgets( + testWidgetsWithLeakTracking( 'Default text/icon colors for enabled, selected and disabled states', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { @@ -453,7 +454,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Custom text/icon colors for enabled, selected and disabled states', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { @@ -539,7 +540,7 @@ void main() { }, ); - testWidgets('Default button fillColor - unselected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default button fillColor - unselected', (WidgetTester tester) async { final ThemeData theme = ThemeData(); await tester.pumpWidget( boilerplate( @@ -566,7 +567,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Default button fillColor - selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default button fillColor - selected', (WidgetTester tester) async { final ThemeData theme = ThemeData(); await tester.pumpWidget( boilerplate( @@ -593,7 +594,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Default button fillColor - disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default button fillColor - disabled', (WidgetTester tester) async { final ThemeData theme = ThemeData(); await tester.pumpWidget( boilerplate( @@ -619,7 +620,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Custom button fillColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom button fillColor', (WidgetTester tester) async { const Color customFillColor = Colors.green; await tester.pumpWidget( boilerplate( @@ -644,7 +645,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Custom button fillColor - Non MaterialState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom button fillColor - Non MaterialState', (WidgetTester tester) async { Material buttonColor(String text) { return tester.widget( find.descendant( @@ -695,7 +696,7 @@ void main() { expect(buttonColor('Second child').color, theme.colorScheme.surface.withOpacity(0.0)); }); - testWidgets('Custom button fillColor - MaterialState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom button fillColor - MaterialState', (WidgetTester tester) async { Material buttonColor(String text) { return tester.widget( find.descendant( @@ -754,7 +755,7 @@ void main() { expect(buttonColor('Second child').color, defaultFillColor); }); - testWidgets('Default InkWell colors - unselected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default InkWell colors - unselected', (WidgetTester tester) async { final ThemeData theme = ThemeData(); final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -819,7 +820,7 @@ void main() { await hoverGesture.removePointer(); }); - testWidgets('Default InkWell colors - selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default InkWell colors - selected', (WidgetTester tester) async { final ThemeData theme = ThemeData(); final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -884,7 +885,7 @@ void main() { await hoverGesture.removePointer(); }); - testWidgets('Custom InkWell colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom InkWell colors', (WidgetTester tester) async { const Color splashColor = Color(0xff4caf50); const Color highlightColor = Color(0xffcddc39); const Color hoverColor = Color(0xffffeb3b); @@ -953,7 +954,7 @@ void main() { await hoverGesture.removePointer(); }); - testWidgets( + testWidgetsWithLeakTracking( 'Default border width and border colors for enabled, selected and disabled states', (WidgetTester tester) async { final ThemeData theme = ThemeData(); @@ -1041,7 +1042,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Custom border width and border colors for enabled, selected and disabled states', (WidgetTester tester) async { const Color borderColor = Color(0xff4caf50); @@ -1138,7 +1139,7 @@ void main() { }, ); - testWidgets('Height of segmented control is determined by tallest widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Height of segmented control is determined by tallest widget', (WidgetTester tester) async { final List children = [ Container( constraints: const BoxConstraints.tightFor(height: 100.0), @@ -1170,7 +1171,7 @@ void main() { } }); - testWidgets('Sizes of toggle buttons rebuilds with the correct dimensions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sizes of toggle buttons rebuilds with the correct dimensions', (WidgetTester tester) async { final List children = [ Container( constraints: const BoxConstraints.tightFor( @@ -1269,7 +1270,7 @@ void main() { } }); - testWidgets('ToggleButtons text baseline alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ToggleButtons text baseline alignment', (WidgetTester tester) async { // The point size of the fonts must be a multiple of 4 until // https://github.com/flutter/flutter/issues/122066 is resolved. await tester.pumpWidget( @@ -1319,7 +1320,7 @@ void main() { expect(firstToggleButtonDy, textDy - 5.0); }); - testWidgets('Directionality test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directionality test', (WidgetTester tester) async { await tester.pumpWidget( Material( child: Directionality( @@ -1367,7 +1368,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'Properly draws borders based on state', (WidgetTester tester) async { final ThemeData theme = ThemeData(); @@ -1447,7 +1448,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Properly draws borders based on state when direction is vertical and verticalDirection is down.', (WidgetTester tester) async { final ThemeData theme = ThemeData(); @@ -1534,7 +1535,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'VerticalDirection test when direction is vertical.', (WidgetTester tester) async { await tester.pumpWidget( @@ -1560,7 +1561,7 @@ void main() { }, ); - testWidgets('Tap target size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap target size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { return boilerplate( useMaterial3: false, @@ -1588,7 +1589,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(228.0, 34.0)); }); - testWidgets('Tap target size is configurable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap target size is configurable', (WidgetTester tester) async { Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { return boilerplate( useMaterial3: false, @@ -1616,7 +1617,7 @@ void main() { expect(tester.getSize(find.byKey(key2)), const Size(228.0, 34.0)); }); - testWidgets('Tap target size is configurable for vertical axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap target size is configurable for vertical axis', (WidgetTester tester) async { Widget buildFrame(MaterialTapTargetSize tapTargetSize, Key key) { return boilerplate( child: ToggleButtons( @@ -1645,7 +1646,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/73725 - testWidgets('Border radius paint test when there is only one button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Border radius paint test when there is only one button', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( boilerplate( @@ -1690,7 +1691,7 @@ void main() { ); }); - testWidgets('Border radius paint test when Radius.x or Radius.y equal 0.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Border radius paint test when Radius.x or Radius.y equal 0.0', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( useMaterial3: false, @@ -1718,7 +1719,7 @@ void main() { ); }); - testWidgets('ToggleButtons implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ToggleButtons implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); ToggleButtons( @@ -1756,7 +1757,7 @@ void main() { ]); }); - testWidgets('ToggleButtons changes mouse cursor when the button is hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ToggleButtons changes mouse cursor when the button is hovered', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: MouseRegion( @@ -1819,7 +1820,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('ToggleButtons focus, hover, and highlight elevations are 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ToggleButtons focus, hover, and highlight elevations are 0', (WidgetTester tester) async { final List focusNodes = [FocusNode(), FocusNode()]; await tester.pumpWidget( boilerplate( @@ -1865,7 +1866,7 @@ void main() { await hoverGesture.removePointer(); }); - testWidgets('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: ToggleButtons( @@ -1888,7 +1889,7 @@ void main() { expect(thirdRect.height, 48.0); }); - testWidgets('Toggle buttons constraints size does not affect minimum input padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggle buttons constraints size does not affect minimum input padding', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/97302 final SemanticsTester semantics = SemanticsTester(tester); @@ -1975,7 +1976,7 @@ void main() { semantics.dispose(); }); - testWidgets('Toggle buttons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggle buttons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index 5dfb0701911f1..0bcd18bab899d 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; Widget boilerplate({required Widget child}) { @@ -64,7 +65,7 @@ void main() { expect(theme.data.borderWidth, null); }); - testWidgets('Default ToggleButtonsThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ToggleButtonsThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ToggleButtonsThemeData().debugFillProperties(builder); @@ -76,7 +77,7 @@ void main() { expect(description, []); }); - testWidgets('ToggleButtonsThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ToggleButtonsThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const ToggleButtonsThemeData( textStyle: TextStyle(fontSize: 10), @@ -121,7 +122,7 @@ void main() { ]); }); - testWidgets('Theme text style, except color, is applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme text style, except color, is applied', (WidgetTester tester) async { await tester.pumpWidget( Material( child: boilerplate( @@ -164,7 +165,7 @@ void main() { expect(textStyle.color, isNot(Colors.orange)); }); - testWidgets('Custom BoxConstraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom BoxConstraints', (WidgetTester tester) async { // Test for minimum constraints await tester.pumpWidget( Material( @@ -238,7 +239,7 @@ void main() { expect(thirdRect.height, 10.0); }); - testWidgets( + testWidgetsWithLeakTracking( 'Theme text/icon colors for enabled, selected and disabled states', (WidgetTester tester) async { TextStyle buttonTextStyle(String text) { @@ -342,7 +343,7 @@ void main() { }, ); - testWidgets('Theme button fillColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme button fillColor', (WidgetTester tester) async { const Color customFillColor = Colors.green; await tester.pumpWidget( Material( @@ -371,7 +372,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Custom Theme button fillColor in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Theme button fillColor in different states', (WidgetTester tester) async { Material buttonColor(String text) { return tester.widget( find.descendant( @@ -438,7 +439,7 @@ void main() { expect(buttonColor('Second child').color, disabledFillColor); }); - testWidgets('Theme InkWell colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme InkWell colors', (WidgetTester tester) async { const Color splashColor = Color(0xff4caf50); const Color highlightColor = Color(0xffcddc39); const Color hoverColor = Color(0xffffeb3b); @@ -514,7 +515,7 @@ void main() { await hoverGesture.removePointer(); }); - testWidgets( + testWidgetsWithLeakTracking( 'Theme border width and border colors for enabled, selected and disabled states', (WidgetTester tester) async { const Color borderColor = Color(0xff4caf50); diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 84d637190d762..a08eb1693994d 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -924,7 +924,7 @@ void main() { await gesture.up(); }); - testWidgets('Tooltip dismiss countdown begins on long press release', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip dismiss countdown begins on long press release', (WidgetTester tester) async { // Specs: https://github.com/flutter/flutter/issues/4182 const Duration showDuration = Duration(seconds: 1); const Duration eternity = Duration(days: 9999); @@ -1868,7 +1868,7 @@ void main() { expect(onTriggeredCalled, false); }); - testWidgets('dismissAllToolTips dismisses hovered tooltips', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dismissAllToolTips dismisses hovered tooltips', (WidgetTester tester) async { const Duration waitDuration = Duration.zero; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(); @@ -1904,7 +1904,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Hovered tooltips do not dismiss after showDuration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovered tooltips do not dismiss after showDuration', (WidgetTester tester) async { const Duration waitDuration = Duration.zero; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(); diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index b2961b6e56746..53ad6fe124fa0 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; @@ -59,7 +60,7 @@ void main() { expect(theme.enableFeedback, null); }); - testWidgets('Default TooltipThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default TooltipThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TooltipThemeData().debugFillProperties(builder); @@ -71,7 +72,7 @@ void main() { expect(description, []); }); - testWidgets('TooltipThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TooltipThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const Duration wait = Duration(milliseconds: 100); const Duration show = Duration(milliseconds: 200); @@ -113,7 +114,7 @@ void main() { ]); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -170,7 +171,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -225,7 +226,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -293,7 +294,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -359,7 +360,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -415,7 +416,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -469,7 +470,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip margin - ThemeData', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -524,7 +525,7 @@ void main() { expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); }); - testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip margin - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -577,7 +578,7 @@ void main() { expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); }); - testWidgets('Tooltip message textStyle - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip message textStyle - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp( theme: ThemeData( @@ -607,7 +608,7 @@ void main() { expect(textStyle.decoration, TextDecoration.underline); }); - testWidgets('Tooltip message textStyle - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip message textStyle - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp( home: TooltipTheme( @@ -636,7 +637,7 @@ void main() { expect(textStyle.decoration, TextDecoration.underline); }); - testWidgets('Tooltip message textAlign - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip message textAlign - TooltipTheme', (WidgetTester tester) async { Future pumpTooltipWithTextAlign({TextAlign? textAlign}) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( @@ -675,7 +676,7 @@ void main() { expect(textAlign, TextAlign.end); }); - testWidgets('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -717,7 +718,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgets('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -757,7 +758,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgets('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingVal = 20.0; @@ -804,7 +805,7 @@ void main() { expect(content.size.width, equals(tip.size.width - 2 * customPaddingVal)); }); - testWidgets('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingValue = 20.0; @@ -849,7 +850,7 @@ void main() { expect(content.size.width, equals(tip.size.width - 2 * customPaddingValue)); }); - testWidgets('Tooltip waitDuration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip waitDuration - ThemeData.tooltipTheme', (WidgetTester tester) async { const Duration customWaitDuration = Duration(milliseconds: 500); final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(); @@ -896,7 +897,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip waitDuration - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip waitDuration - TooltipTheme', (WidgetTester tester) async { const Duration customWaitDuration = Duration(milliseconds: 500); final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(); @@ -939,7 +940,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip showDuration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip showDuration - ThemeData.tooltipTheme', (WidgetTester tester) async { const Duration customShowDuration = Duration(milliseconds: 3000); await tester.pumpWidget( MaterialApp( @@ -976,7 +977,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip showDuration - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip showDuration - TooltipTheme', (WidgetTester tester) async { const Duration customShowDuration = Duration(milliseconds: 3000); await tester.pumpWidget( const MaterialApp( @@ -1009,7 +1010,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip triggerMode - ThemeData.triggerMode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip triggerMode - ThemeData.triggerMode', (WidgetTester tester) async { const TooltipTriggerMode triggerMode = TooltipTriggerMode.tap; await tester.pumpWidget( MaterialApp( @@ -1034,7 +1035,7 @@ void main() { expect(find.text(tooltipText), findsOneWidget); // Tooltip should show immediately after tap }); - testWidgets('Tooltip triggerMode - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip triggerMode - TooltipTheme', (WidgetTester tester) async { const TooltipTriggerMode triggerMode = TooltipTriggerMode.tap; await tester.pumpWidget( const MaterialApp( @@ -1057,7 +1058,7 @@ void main() { expect(find.text(tooltipText), findsOneWidget); // Tooltip should show immediately after tap }); - testWidgets('Semantics included by default - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics included by default - ThemeData.tooltipTheme', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1098,7 +1099,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics included by default - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics included by default - TooltipTheme', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1141,7 +1142,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics excluded - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics excluded - ThemeData.tooltipTheme', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1185,7 +1186,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics excluded - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics excluded - TooltipTheme', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1227,7 +1228,7 @@ void main() { semantics.dispose(); }); - testWidgets('has semantic events by default - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantic events by default - ThemeData.tooltipTheme', (WidgetTester tester) async { final List semanticEvents = []; tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, (dynamic message) async { semanticEvents.add(message); @@ -1270,7 +1271,7 @@ void main() { tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('has semantic events by default - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantic events by default - TooltipTheme', (WidgetTester tester) async { final List semanticEvents = []; tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, (dynamic message) async { semanticEvents.add(message); @@ -1315,7 +1316,7 @@ void main() { tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('default Tooltip debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default Tooltip debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const Tooltip(message: 'message').debugFillProperties(builder); diff --git a/packages/flutter/test/material/tooltip_visibility_test.dart b/packages/flutter/test/material/tooltip_visibility_test.dart index ec5764271f2c1..c1f88e5e4691e 100644 --- a/packages/flutter/test/material/tooltip_visibility_test.dart +++ b/packages/flutter/test/material/tooltip_visibility_test.dart @@ -8,10 +8,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + const String tooltipText = 'TIP'; void main() { - testWidgets('Tooltip does not build MouseRegion when mouse is detected and in TooltipVisibility with visibility = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip does not build MouseRegion when mouse is detected and in TooltipVisibility with visibility = false', (WidgetTester tester) async { final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); addTearDown(() async { return gesture.removePointer(); @@ -39,7 +41,7 @@ void main() { expect(find.descendant(of: find.byType(Tooltip), matching: find.byType(MouseRegion)), findsNothing); }); - testWidgets('Tooltip does not show when hovered when in TooltipVisibility with visible = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip does not show when hovered when in TooltipVisibility with visible = false', (WidgetTester tester) async { const Duration waitDuration = Duration.zero; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); addTearDown(() async { @@ -78,7 +80,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip shows when hovered when in TooltipVisibility with visible = true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip shows when hovered when in TooltipVisibility with visible = true', (WidgetTester tester) async { const Duration waitDuration = Duration.zero; TestGesture? gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); addTearDown(() async { @@ -126,13 +128,13 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip does not build GestureDetector when in TooltipVisibility with visibility = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip does not build GestureDetector when in TooltipVisibility with visibility = false', (WidgetTester tester) async { await setWidgetForTooltipMode(tester, TooltipTriggerMode.tap, false); expect(find.byType(GestureDetector), findsNothing); }); - testWidgets('Tooltip triggers on tap when trigger mode is tap and in TooltipVisibility with visible = true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip triggers on tap when trigger mode is tap and in TooltipVisibility with visible = true', (WidgetTester tester) async { await setWidgetForTooltipMode(tester, TooltipTriggerMode.tap, true); final Finder tooltip = find.byType(Tooltip); @@ -142,7 +144,7 @@ void main() { expect(find.text(tooltipText), findsOneWidget); }); - testWidgets('Tooltip does not trigger manually when in TooltipVisibility with visible = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip does not trigger manually when in TooltipVisibility with visible = false', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -162,7 +164,7 @@ void main() { expect(find.text(tooltipText), findsNothing); }); - testWidgets('Tooltip triggers manually when in TooltipVisibility with visible = true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip triggers manually when in TooltipVisibility with visible = true', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart index 87bc4b821fba2..515c90e76be03 100644 --- a/packages/flutter/test/material/typography_test.dart +++ b/packages/flutter/test/material/typography_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('Typography is defined for all target platforms', () { for (final TargetPlatform platform in TargetPlatform.values) { @@ -89,7 +91,7 @@ void main() { } }); - testWidgets('Typography implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Typography implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Typography.material2014( black: Typography.blackCupertino, diff --git a/packages/flutter/test/material/user_accounts_drawer_header_test.dart b/packages/flutter/test/material/user_accounts_drawer_header_test.dart index 08efb09f05a84..65dac36e4cdee 100644 --- a/packages/flutter/test/material/user_accounts_drawer_header_test.dart +++ b/packages/flutter/test/material/user_accounts_drawer_header_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; const Key avatarA = Key('A'); @@ -82,7 +83,7 @@ void main() { matching: find.byType(Transform), ); - testWidgets('UserAccountsDrawerHeader inherits ColorScheme.primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader inherits ColorScheme.primary', (WidgetTester tester) async { const Color primaryColor = Color(0xff00ff00); const Color colorSchemePrimary = Color(0xff0000ff); @@ -95,7 +96,7 @@ void main() { expect(boxDecoration?.color == colorSchemePrimary, true); }); - testWidgets('UserAccountsDrawerHeader test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader test', (WidgetTester tester) async { await pumpTestWidget(tester); expect(find.text('A'), findsOneWidget); @@ -133,7 +134,7 @@ void main() { expect(avatarDTopRight.dx - avatarCTopRight.dx, equals(40.0 + 16.0)); // size + space between }); - testWidgets('UserAccountsDrawerHeader change default size test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader change default size test', (WidgetTester tester) async { const Size currentAccountPictureSize = Size.square(60.0); const Size otherAccountsPictureSize = Size.square(30.0); @@ -150,7 +151,7 @@ void main() { expect(otherAccountRenderBox.size, otherAccountsPictureSize); }); - testWidgets('UserAccountsDrawerHeader icon rotation test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader icon rotation test', (WidgetTester tester) async { await pumpTestWidget(tester); Transform transformWidget = tester.firstWidget(findTransform); @@ -186,7 +187,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/25801. - testWidgets('UserAccountsDrawerHeader icon does not rotate after setState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader icon does not rotate after setState', (WidgetTester tester) async { late StateSetter testSetState; await tester.pumpWidget(MaterialApp( home: Material( @@ -221,7 +222,7 @@ void main() { expect(transformWidget.transform.getRotation()[4], 1.0); }); - testWidgets('UserAccountsDrawerHeader icon rotation test speeeeeedy', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader icon rotation test speeeeeedy', (WidgetTester tester) async { await pumpTestWidget(tester); Transform transformWidget = tester.firstWidget(findTransform); @@ -262,7 +263,7 @@ void main() { expect(transformWidget.transform.getRotation()[4], 1.0); }); - testWidgets('UserAccountsDrawerHeader icon color changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader icon color changes', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: UserAccountsDrawerHeader( @@ -293,7 +294,7 @@ void main() { expect(iconWidget.color, arrowColor); }); - testWidgets('UserAccountsDrawerHeader null parameters LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader null parameters LTR', (WidgetTester tester) async { Widget buildFrame({ Widget? currentAccountPicture, List? otherAccountsPictures, @@ -401,7 +402,7 @@ void main() { ); }); - testWidgets('UserAccountsDrawerHeader null parameters RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader null parameters RTL', (WidgetTester tester) async { Widget buildFrame({ Widget? currentAccountPicture, List? otherAccountsPictures, @@ -512,7 +513,7 @@ void main() { ); }); - testWidgets('UserAccountsDrawerHeader provides semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader provides semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await pumpTestWidget(tester); @@ -568,7 +569,7 @@ void main() { semantics.dispose(); }); - testWidgets('alternative account selectors have sufficient tap targets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('alternative account selectors have sufficient tap targets', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await pumpTestWidget(tester); @@ -589,7 +590,7 @@ void main() { handle.dispose(); }); - testWidgets('UserAccountsDrawerHeader provides semantics with missing properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UserAccountsDrawerHeader provides semantics with missing properties', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await pumpTestWidget( tester, diff --git a/packages/flutter/test/material/value_indicating_slider_test.dart b/packages/flutter/test/material/value_indicating_slider_test.dart index 4e1e46575e1aa..fb8029b935ab7 100644 --- a/packages/flutter/test/material/value_indicating_slider_test.dart +++ b/packages/flutter/test/material/value_indicating_slider_test.dart @@ -10,8 +10,10 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('Slider value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -52,7 +54,7 @@ void main() { ); }); - testWidgets('Slider value indicator wide text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -96,7 +98,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator large text scale', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -140,7 +142,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale and wide text', + testWidgetsWithLeakTracking('Slider value indicator large text scale and wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, @@ -193,7 +195,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Slider value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -231,7 +233,7 @@ void main() { ); }); - testWidgets('Slider value indicator wide text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -272,7 +274,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator large text scale', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -313,7 +315,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale and wide text', + testWidgetsWithLeakTracking('Slider value indicator large text scale and wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, From bf94af1906719a4b1bde7743602a46b1d52c7402 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 12:45:11 -0400 Subject: [PATCH 0321/1547] Roll Flutter Engine from 481684a6e276 to 7d8c0e38f7ea (1 revision) (#131128) https://github.com/flutter/engine/compare/481684a6e276...7d8c0e38f7ea 2023-07-22 skia-flutter-autoroll@skia.org Roll Skia from 85e8d8403b45 to 0d3c35804162 (1 revision) (flutter/engine#43924) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 550290ba23306..67ab95ade033e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -481684a6e2768e480febdcc53972a21a517db1d4 +7d8c0e38f7ea71b176168060211db89f2095d253 From ea1bf240a5f236b3e2560c29e141e3461869ee12 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 15:12:40 -0400 Subject: [PATCH 0322/1547] Roll Flutter Engine from 7d8c0e38f7ea to 7cea0b59494c (1 revision) (#131131) https://github.com/flutter/engine/compare/7d8c0e38f7ea...7cea0b59494c 2023-07-22 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from LZJYHQeLdXALTMMmj... to UA1voLfMc1q4Lpc3f... (flutter/engine#43925) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from LZJYHQeLdXAL to UA1voLfMc1q4 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 67ab95ade033e..99acd2d72f1f7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7d8c0e38f7ea71b176168060211db89f2095d253 +7cea0b59494c5c8651a1d60b6e92f9ed806cd391 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 1bcee67244342..f8e56eddd13f3 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -LZJYHQeLdXALTMMmjxIngbM_8F_RBx5-YiDR9mc0C5wC +UA1voLfMc1q4Lpc3fd3FTLM3SQ4GSzLRkRu3oa751E0C From 2ec2d79eeb867535c6fe74a3f851d1059b673cc3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 16:09:29 -0400 Subject: [PATCH 0323/1547] Roll Flutter Engine from 7cea0b59494c to 8e8e4577b01b (1 revision) (#131134) https://github.com/flutter/engine/compare/7cea0b59494c...8e8e4577b01b 2023-07-22 bdero@google.com [Impeller] Propagate PopulateGlyphAtlas through filters. (flutter/engine#43920) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 99acd2d72f1f7..d49bc28958eba 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7cea0b59494c5c8651a1d60b6e92f9ed806cd391 +8e8e4577b01bc48c8bd3ccc74089ba65ee2d0946 From 2171a001200de4a71f24e8b1f2ea46b3a67f0b0d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 17:45:41 -0400 Subject: [PATCH 0324/1547] Roll Flutter Engine from 8e8e4577b01b to 30f0f6b2abde (1 revision) (#131135) https://github.com/flutter/engine/compare/8e8e4577b01b...30f0f6b2abde 2023-07-22 skia-flutter-autoroll@skia.org Roll Skia from 0d3c35804162 to 6f9ee612c32e (1 revision) (flutter/engine#43926) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d49bc28958eba..6d7a517cde47d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8e8e4577b01bc48c8bd3ccc74089ba65ee2d0946 +30f0f6b2abdee6f6c734c1f221b57fa4791ca471 From 6ff87d0cf257af6ef569ff03aad8a23cfc0b3030 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 19:09:36 -0400 Subject: [PATCH 0325/1547] Roll Flutter Engine from 30f0f6b2abde to 4ad970f718e8 (1 revision) (#131136) https://github.com/flutter/engine/compare/30f0f6b2abde...4ad970f718e8 2023-07-22 bdero@google.com [Impeller] Fix text glyph bounds on Android. (flutter/engine#43919) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6d7a517cde47d..c93a1fa9c16d6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -30f0f6b2abdee6f6c734c1f221b57fa4791ca471 +4ad970f718e87f968af2658a7da53c543a68ed49 From 101f3f5e44e23f91878e4e7d4de5ce05ee6f28cd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 22 Jul 2023 21:25:23 -0400 Subject: [PATCH 0326/1547] Roll Flutter Engine from 4ad970f718e8 to 46ef96dc4b9f (1 revision) (#131139) https://github.com/flutter/engine/compare/4ad970f718e8...46ef96dc4b9f 2023-07-22 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from UgZ9epS2Jkz7Yrymp... to EpYT1-xhJrcojs93J... (flutter/engine#43928) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from UgZ9epS2Jkz7 to EpYT1-xhJrco If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c93a1fa9c16d6..bf28d8af477a9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4ad970f718e87f968af2658a7da53c543a68ed49 +46ef96dc4b9f83086d646a27a210e7e8e9926697 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index a13f4b2cc5fed..5cec1e118404c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -UgZ9epS2Jkz7Yrymp9fnT2vZnmIUtBJdIuN2a54v_SIC +EpYT1-xhJrcojs93JiAYPoWPy9QRTHNgtwWtqyHPHDAC From fa356ab9f1e2a6c7bf45dd0ff2b67d0c1aef0ec9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 00:33:37 -0400 Subject: [PATCH 0327/1547] Roll Flutter Engine from 46ef96dc4b9f to b8017629f974 (1 revision) (#131142) https://github.com/flutter/engine/compare/46ef96dc4b9f...b8017629f974 2023-07-23 skia-flutter-autoroll@skia.org Roll ANGLE from 938ee1e80fc8 to 430a4f559cbc (1 revision) (flutter/engine#43930) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bf28d8af477a9..de13dfcd05bfe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -46ef96dc4b9f83086d646a27a210e7e8e9926697 +b8017629f97420dd2e7b5774b389a36e05752d1c From bf7029dd3744bd920c7ced3dc1036e2714afa887 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 01:49:23 -0400 Subject: [PATCH 0328/1547] Roll Flutter Engine from b8017629f974 to 265c2c681ab8 (1 revision) (#131143) https://github.com/flutter/engine/compare/b8017629f974...265c2c681ab8 2023-07-23 skia-flutter-autoroll@skia.org Roll Skia from 6f9ee612c32e to dba4713e79b2 (1 revision) (flutter/engine#43931) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index de13dfcd05bfe..e090a07f4e550 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b8017629f97420dd2e7b5774b389a36e05752d1c +265c2c681ab844b26e00fbc178fbcfb06affadf0 From 23d9a6299bfb261aec68a973de61017ccfefd799 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 03:59:24 -0400 Subject: [PATCH 0329/1547] Roll Flutter Engine from 265c2c681ab8 to b56ecc7bf721 (1 revision) (#131148) https://github.com/flutter/engine/compare/265c2c681ab8...b56ecc7bf721 2023-07-23 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from UA1voLfMc1q4Lpc3f... to ybLfhFrKOi6jaYUv7... (flutter/engine#43932) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from UA1voLfMc1q4 to ybLfhFrKOi6j If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e090a07f4e550..d3e0e0661ae08 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -265c2c681ab844b26e00fbc178fbcfb06affadf0 +b56ecc7bf721b51201c400e8ec99c777b57a1fcf diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index f8e56eddd13f3..d57acb6856421 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -UA1voLfMc1q4Lpc3fd3FTLM3SQ4GSzLRkRu3oa751E0C +ybLfhFrKOi6jaYUv7Ky5rXafCGy_pZCXeNbFR8y2V0IC From 31e46c5bb77b44b3a3dd62890e5cd4f951b62b56 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 06:28:23 -0400 Subject: [PATCH 0330/1547] Roll Flutter Engine from b56ecc7bf721 to 46aab05450d9 (1 revision) (#131153) https://github.com/flutter/engine/compare/b56ecc7bf721...46aab05450d9 2023-07-23 skia-flutter-autoroll@skia.org Roll Skia from dba4713e79b2 to 964f26400b7a (1 revision) (flutter/engine#43933) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d3e0e0661ae08..909f5d88ba253 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b56ecc7bf721b51201c400e8ec99c777b57a1fcf +46aab05450d9bbee571bde3dc4abf02f036d7ed8 From a8c8c5598c85d7e3466ae9e29402e195284f8b02 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 10:24:38 -0400 Subject: [PATCH 0331/1547] Roll Flutter Engine from 46aab05450d9 to b314a29830f8 (1 revision) (#131159) https://github.com/flutter/engine/compare/46aab05450d9...b314a29830f8 2023-07-23 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from EpYT1-xhJrcojs93J... to Xm1-SWnXPhSRxNol-... (flutter/engine#43934) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from EpYT1-xhJrco to Xm1-SWnXPhSR If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 909f5d88ba253..6cc8bd26c26ac 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -46aab05450d9bbee571bde3dc4abf02f036d7ed8 +b314a29830f809cd9bce339f4b0e50cc53c162a8 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 5cec1e118404c..c4c4de89295c4 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -EpYT1-xhJrcojs93JiAYPoWPy9QRTHNgtwWtqyHPHDAC +Xm1-SWnXPhSRxNol-UPe_caD1SxhcbvbUXYQe2hCCAsC From bae6546915c96843d023e56ac11ca77a042789d4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 21:45:06 -0400 Subject: [PATCH 0332/1547] Roll Flutter Engine from b314a29830f8 to 2ec1183e0dc3 (1 revision) (#131167) https://github.com/flutter/engine/compare/b314a29830f8...2ec1183e0dc3 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from 964f26400b7a to ce49fc71bc7c (1 revision) (flutter/engine#43939) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6cc8bd26c26ac..13e276a1dcc85 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b314a29830f809cd9bce339f4b0e50cc53c162a8 +2ec1183e0dc3fba512485a766ec6f1175f8c8408 From 2b9ec67e8c98de45dfc43d8be63d91804d7bf6ba Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 23 Jul 2023 22:55:23 -0400 Subject: [PATCH 0333/1547] Roll Flutter Engine from 2ec1183e0dc3 to 35eab1bcf335 (1 revision) (#131169) https://github.com/flutter/engine/compare/2ec1183e0dc3...35eab1bcf335 2023-07-24 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ybLfhFrKOi6jaYUv7... to A02P1GsGg001-Mpn3... (flutter/engine#43940) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ybLfhFrKOi6j to A02P1GsGg001 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 13e276a1dcc85..f3fc444278ec9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2ec1183e0dc3fba512485a766ec6f1175f8c8408 +35eab1bcf3358629b533b1811e337c6f56433e61 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index d57acb6856421..41a4991fa7c7e 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ybLfhFrKOi6jaYUv7Ky5rXafCGy_pZCXeNbFR8y2V0IC +A02P1GsGg001-Mpn3gH1a5yc1P9CeyzlzeA2ZhA9V14C From 47315808bddb645b509486b199c089476ab4256f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 00:13:35 -0400 Subject: [PATCH 0334/1547] Roll Flutter Engine from 35eab1bcf335 to c2c54f6406df (2 revisions) (#131173) https://github.com/flutter/engine/compare/35eab1bcf335...c2c54f6406df 2023-07-24 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Xm1-SWnXPhSRxNol-... to hUgYN9tEps515M1lg... (flutter/engine#43941) 2023-07-24 chinmaygarde@google.com [Impeller] Fix typo in help for compiler switches. (flutter/engine#43937) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from Xm1-SWnXPhSR to hUgYN9tEps51 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f3fc444278ec9..40633fec3c71b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -35eab1bcf3358629b533b1811e337c6f56433e61 +c2c54f6406dff48a9bbec8a9be9a0d78572788e5 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c4c4de89295c4..2a104d67f6257 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Xm1-SWnXPhSRxNol-UPe_caD1SxhcbvbUXYQe2hCCAsC +hUgYN9tEps515M1lgt42j4fCvfXRlF_Ls36xgAbzcmEC From e57c0effb7fd3e6da8277721c2e25418a0533de4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 02:43:23 -0400 Subject: [PATCH 0335/1547] Roll Flutter Engine from c2c54f6406df to 402bceec81f4 (1 revision) (#131174) https://github.com/flutter/engine/compare/c2c54f6406df...402bceec81f4 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from ce49fc71bc7c to f512e7eedaef (1 revision) (flutter/engine#43944) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 40633fec3c71b..691ce29e12537 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c2c54f6406dff48a9bbec8a9be9a0d78572788e5 +402bceec81f4d2f4533c57f40e7eb2051c62f7d5 From acdd96b2f93fdf437c83696c0665318e1c9a5667 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 04:41:07 -0400 Subject: [PATCH 0336/1547] Roll Flutter Engine from 402bceec81f4 to 4734a709cbf2 (2 revisions) (#131175) https://github.com/flutter/engine/compare/402bceec81f4...4734a709cbf2 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from db314e2867bc to 860f12775838 (1 revision) (flutter/engine#43947) 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from f512e7eedaef to db314e2867bc (1 revision) (flutter/engine#43945) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 691ce29e12537..0294fdee593c1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -402bceec81f4d2f4533c57f40e7eb2051c62f7d5 +4734a709cbf28fb907f9396a77c306dbd25ebc3e From 9c10151508bdb8ddd9d7b56484373d23755d8431 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Mon, 24 Jul 2023 11:26:05 +0200 Subject: [PATCH 0337/1547] Use utf8.encode() instead of longer const Utf8Encoder.convert() (#130567) The change in [0] has propagated now everywhere, so we can use `utf8.encode()` instead of the longer `const Utf8Encoder.convert()`. Also it cleans up code like ``` TypedData bytes; bytes.buffer.asByteData(); ``` as that is not guaranteed to be correct, the correct version would be ``` TypedData bytes; bytes.buffer.asByteData(bytes.offsetInBytes, bytes.lengthInBytes); ``` a shorter hand for that is: ``` TypedData bytes; ByteData.sublistView(bytes); ``` [0] https://github.com/dart-lang/sdk/issues/52801 --- .../lib/src/services/asset_bundle.dart | 27 +++++++++---------- .../lib/src/services/message_codecs.dart | 7 +++-- packages/flutter/lib/src/widgets/basic.dart | 2 +- .../test/services/asset_bundle_test.dart | 9 +++---- .../flutter/test/services/binding_test.dart | 2 +- .../test/services/channel_buffers_test.dart | 9 ++----- .../default_binary_messenger_test.dart | 6 +---- 7 files changed, 25 insertions(+), 37 deletions(-) diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart index 7ade7f8569852..238467b27db6c 100644 --- a/packages/flutter/lib/src/services/asset_bundle.dart +++ b/packages/flutter/lib/src/services/asset_bundle.dart @@ -57,11 +57,10 @@ abstract class AssetBundle { /// Throws an exception if the asset is not found. /// /// The returned [ByteData] can be converted to a [Uint8List] (a list of bytes) - /// using [ByteData.buffer] to obtain a [ByteBuffer], and then - /// [ByteBuffer.asUint8List] to obtain the byte list. Lists of bytes can be - /// used with APIs that accept [Uint8List] objects, such as - /// [decodeImageFromList], as well as any API that accepts a [List], such - /// as [File.writeAsBytes] or [Utf8Codec.decode] (accessible via [utf8]). + /// using [Uint8List.sublistView]. Lists of bytes can be used with APIs that + /// accept [Uint8List] objects, such as [decodeImageFromList], as well as any + /// API that accepts a [List], such as [File.writeAsBytes] or + /// [Utf8Codec.decode] (accessible via [utf8]). Future load(String key); /// Retrieve a binary resource from the asset bundle as an immutable @@ -70,7 +69,7 @@ abstract class AssetBundle { /// Throws an exception if the asset is not found. Future loadBuffer(String key) async { final ByteData data = await load(key); - return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List()); + return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(data)); } /// Retrieve a string from the asset bundle. @@ -91,7 +90,7 @@ abstract class AssetBundle { // 50 KB of data should take 2-3 ms to parse on a Moto G4, and about 400 μs // on a Pixel 4. if (data.lengthInBytes < 50 * 1024) { - return utf8.decode(data.buffer.asUint8List()); + return utf8.decode(Uint8List.sublistView(data)); } // For strings larger than 50 KB, run the computation in an isolate to // avoid causing main thread jank. @@ -99,7 +98,7 @@ abstract class AssetBundle { } static String _utf8decode(ByteData data) { - return utf8.decode(data.buffer.asUint8List()); + return utf8.decode(Uint8List.sublistView(data)); } /// Retrieve a string from the asset bundle, parse it with the given function, @@ -161,7 +160,7 @@ class NetworkAssetBundle extends AssetBundle { ]); } final Uint8List bytes = await consolidateHttpClientResponseBytes(response); - return bytes.buffer.asByteData(); + return ByteData.sublistView(bytes); } // TODO(ianh): Once the underlying network logic learns about caching, we @@ -308,7 +307,7 @@ abstract class CachingAssetBundle extends AssetBundle { @override Future loadBuffer(String key) async { final ByteData data = await load(key); - return ui.ImmutableBuffer.fromUint8List(data.buffer.asUint8List()); + return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(data)); } } @@ -316,10 +315,10 @@ abstract class CachingAssetBundle extends AssetBundle { class PlatformAssetBundle extends CachingAssetBundle { @override Future load(String key) { - final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull(key)).path); + final Uint8List encoded = utf8.encode(Uri(path: Uri.encodeFull(key)).path); final Future? future = ServicesBinding.instance.defaultBinaryMessenger.send( 'flutter/assets', - encoded.buffer.asByteData(), + ByteData.sublistView(encoded), )?.then((ByteData? asset) { if (asset == null) { throw FlutterError.fromParts([ @@ -342,7 +341,7 @@ class PlatformAssetBundle extends CachingAssetBundle { Future loadBuffer(String key) async { if (kIsWeb) { final ByteData bytes = await load(key); - return ui.ImmutableBuffer.fromUint8List(bytes.buffer.asUint8List()); + return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(bytes)); } bool debugUsePlatformChannel = false; assert(() { @@ -358,7 +357,7 @@ class PlatformAssetBundle extends CachingAssetBundle { }()); if (debugUsePlatformChannel) { final ByteData bytes = await load(key); - return ui.ImmutableBuffer.fromUint8List(bytes.buffer.asUint8List()); + return ui.ImmutableBuffer.fromUint8List(Uint8List.sublistView(bytes)); } try { return await ui.ImmutableBuffer.fromAsset(key); diff --git a/packages/flutter/lib/src/services/message_codecs.dart b/packages/flutter/lib/src/services/message_codecs.dart index fcd90731caf10..2b103d9624cc5 100644 --- a/packages/flutter/lib/src/services/message_codecs.dart +++ b/packages/flutter/lib/src/services/message_codecs.dart @@ -50,7 +50,7 @@ class StringCodec implements MessageCodec { if (message == null) { return null; } - return utf8.decoder.convert(message.buffer.asUint8List(message.offsetInBytes, message.lengthInBytes)); + return utf8.decode(Uint8List.sublistView(message)); } @override @@ -58,8 +58,7 @@ class StringCodec implements MessageCodec { if (message == null) { return null; } - final Uint8List encoded = utf8.encoder.convert(message); - return encoded.buffer.asByteData(); + return ByteData.sublistView(utf8.encode(message)); } } @@ -415,7 +414,7 @@ class StandardMessageCodec implements MessageCodec { if (char <= 0x7f) { asciiBytes[i] = char; } else { - utf8Bytes = utf8.encoder.convert(value.substring(i)); + utf8Bytes = utf8.encode(value.substring(i)); utf8Offset = i; break; } diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index a6c55db080e0a..eab287bddb19a 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -6176,7 +6176,7 @@ class RawImage extends LeafRenderObjectWidget { /// @override /// Future load(String key) async { /// if (key == 'resources/test') { -/// return ByteData.view(Uint8List.fromList(utf8.encode('Hello World!')).buffer); +/// return ByteData.sublistView(utf8.encode('Hello World!')); /// } /// return ByteData(0); /// } diff --git a/packages/flutter/test/services/asset_bundle_test.dart b/packages/flutter/test/services/asset_bundle_test.dart index 5f7b7c738c8d6..c6946425d2256 100644 --- a/packages/flutter/test/services/asset_bundle_test.dart +++ b/packages/flutter/test/services/asset_bundle_test.dart @@ -16,17 +16,16 @@ class TestAssetBundle extends CachingAssetBundle { Future load(String key) async { loadCallCount[key] = (loadCallCount[key] ?? 0) + 1; if (key == 'AssetManifest.json') { - return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert('{"one": ["one"]}')).buffer); + return ByteData.sublistView(utf8.encode('{"one": ["one"]}')); } if (key == 'AssetManifest.bin') { - return const StandardMessageCodec().encodeMessage({ - 'one': [] - })!; + return const StandardMessageCodec() + .encodeMessage({'one': []})!; } if (key == 'counter') { - return ByteData.view(Uint8List.fromList(const Utf8Encoder().convert(loadCallCount[key]!.toString())).buffer); + return ByteData.sublistView(utf8.encode(loadCallCount[key]!.toString())); } if (key == 'one') { diff --git a/packages/flutter/test/services/binding_test.dart b/packages/flutter/test/services/binding_test.dart index 1aff214478eba..3f3439e62abc2 100644 --- a/packages/flutter/test/services/binding_test.dart +++ b/packages/flutter/test/services/binding_test.dart @@ -89,7 +89,7 @@ void main() { int flutterAssetsCallCount = 0; binding.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async { flutterAssetsCallCount += 1; - return Uint8List.fromList('test_asset_data'.codeUnits).buffer.asByteData(); + return ByteData.sublistView(utf8.encode('test_asset_data')); }); await rootBundle.loadString('test_asset'); diff --git a/packages/flutter/test/services/channel_buffers_test.dart b/packages/flutter/test/services/channel_buffers_test.dart index 09eeec03eaa2a..2c48f10cd3b2f 100644 --- a/packages/flutter/test/services/channel_buffers_test.dart +++ b/packages/flutter/test/services/channel_buffers_test.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'dart:convert'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; @@ -14,15 +13,11 @@ class TestChannelBuffersFlutterBinding extends BindingBase with SchedulerBinding void main() { ByteData makeByteData(String str) { - final List list = utf8.encode(str); - final ByteBuffer buffer = list is Uint8List ? list.buffer : Uint8List.fromList(list).buffer; - return ByteData.view(buffer); + return ByteData.sublistView(utf8.encode(str)); } String getString(ByteData data) { - final ByteBuffer buffer = data.buffer; - final List list = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); - return utf8.decode(list); + return utf8.decode(Uint8List.sublistView(data)); } test('does drain channel buffers', () async { diff --git a/packages/flutter/test/services/default_binary_messenger_test.dart b/packages/flutter/test/services/default_binary_messenger_test.dart index 690493d46acdf..72702f5208b58 100644 --- a/packages/flutter/test/services/default_binary_messenger_test.dart +++ b/packages/flutter/test/services/default_binary_messenger_test.dart @@ -4,7 +4,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:typed_data'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -13,10 +12,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); ByteData makeByteData(String str) { - final List list = utf8.encode(str); - final ByteBuffer buffer = - list is Uint8List ? list.buffer : Uint8List.fromList(list).buffer; - return ByteData.view(buffer); + return ByteData.sublistView(utf8.encode(str)); } test('default binary messenger calls callback once', () async { From d7ed5dc2e212d164fd8733f34a832af10481cd8b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 10:27:39 -0400 Subject: [PATCH 0338/1547] Roll Flutter Engine from 4734a709cbf2 to aa876f6bec69 (2 revisions) (#131190) https://github.com/flutter/engine/compare/4734a709cbf2...aa876f6bec69 2023-07-24 skia-flutter-autoroll@skia.org Roll ANGLE from 430a4f559cbc to e28575f66ae5 (1 revision) (flutter/engine#43951) 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from 860f12775838 to a56bc23bfec7 (1 revision) (flutter/engine#43950) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0294fdee593c1..ec13d66ee2b53 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4734a709cbf28fb907f9396a77c306dbd25ebc3e +aa876f6bec69c1f6327017460dc7e8a6872c5fdf From 9690ef58cfe10f0282d78729de860eb0d21d6cf1 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Mon, 24 Jul 2023 08:06:07 -0700 Subject: [PATCH 0339/1547] Update Gallery demo app themes for Material3 compatibility (#131093) --- .../flutter_gallery/lib/demo/pesto_demo.dart | 3 ++- .../flutter_gallery/lib/demo/shrine/app.dart | 1 + .../flutter_gallery/lib/demo/shrine/login.dart | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dev/integration_tests/flutter_gallery/lib/demo/pesto_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/pesto_demo.dart index fd36fe6c6917c..5d40dbeaf8228 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/pesto_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/pesto_demo.dart @@ -23,8 +23,9 @@ const double _kRecipePageMaxWidth = 500.0; final Set _favoriteRecipes = {}; final ThemeData _kTheme = ThemeData( + appBarTheme: const AppBarTheme(foregroundColor: Colors.white, backgroundColor: Colors.teal), brightness: Brightness.light, - primarySwatch: Colors.teal, + floatingActionButtonTheme: const FloatingActionButtonThemeData(foregroundColor: Colors.white), ); class PestoHome extends StatelessWidget { diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart index dd9db3b926ecd..0b4ff755f49a7 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/app.dart @@ -92,6 +92,7 @@ ThemeData _buildShrineTheme() { textTheme: _buildShrineTextTheme(base.textTheme), primaryTextTheme: _buildShrineTextTheme(base.primaryTextTheme), iconTheme: _customIconTheme(base.iconTheme), + appBarTheme: const AppBarTheme(backgroundColor: kShrinePink100), ); } diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart index ba11ceaa0bc65..c78279068a169 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/login.dart @@ -99,7 +99,7 @@ class _LoginPageState extends State { // of Shrine completely. Navigator.of(context, rootNavigator: true).pop(); }, - child: const Text('CANCEL'), + child: Text('CANCEL', style: Theme.of(context).textTheme.bodySmall), ), ElevatedButton( style: ElevatedButton.styleFrom( @@ -111,7 +111,7 @@ class _LoginPageState extends State { onPressed: () { Navigator.pop(context); }, - child: const Text('NEXT'), + child: Text('NEXT', style: Theme.of(context).textTheme.bodySmall), ), ], ), From 2a1f26c4e1c65913943baa004151343c8529b775 Mon Sep 17 00:00:00 2001 From: Lexycon Date: Mon, 24 Jul 2023 18:03:05 +0200 Subject: [PATCH 0340/1547] Fix material date picker behavior when changing year (#130486) This PR changes the material date picker behavior when changing the year so that it matches the native picker and the material component guideline. (#81547) See material component guideline for the date picker: [Material component date-picker behavior](https://m3.material.io/components/date-pickers/guidelines#1531a81f-4052-4a75-a20d-228c7e110156) See also: [Material components android discussion](https://github.com/material-components/material-components-android/issues/1723) When selecting another year in the native picker, the same day will be selected (by respecting the boundaries of the date picker). The current material date picker does not select any day when changing the year. This will lead to confusion if the user presses OK and the year does not get updated. So here is my suggestion: It will try to preselect the day like the native picker: - respecting the boundaries of the date picker (firstDate, lastDate) - changing from leapyear 29th february will set 28th february if not a leapyear is selected - only set the day if it is selectable (selectableDayPredicate) The calendar shown in the recording was setup with this parameters: ``` firstDate: DateTime(2016, DateTime.june, 9), initialDate: DateTime(2018, DateTime.may, 4), lastDate: DateTime(2021, DateTime.january, 15), ``` https://github.com/flutter/flutter/assets/13588771/3041c296-b9d0-4078-88cd-d1135fc343b3 Fixes #81547 --- .../src/material/calendar_date_picker.dart | 13 +++++++++ .../material/calendar_date_picker_test.dart | 29 +++++++++++++++++-- .../test/material/date_picker_test.dart | 4 +-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 3bdddf3a57677..46bccac26f57f 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -237,6 +237,10 @@ class _CalendarDatePickerState extends State { void _handleYearChanged(DateTime value) { _vibrate(); + final int daysInMonth = DateUtils.getDaysInMonth(value.year, value.month); + final int preferredDay = math.min(_selectedDate.day, daysInMonth); + value = value.copyWith(day: preferredDay); + if (value.isBefore(widget.firstDate)) { value = widget.firstDate; } else if (value.isAfter(widget.lastDate)) { @@ -246,6 +250,11 @@ class _CalendarDatePickerState extends State { setState(() { _mode = DatePickerMode.day; _handleMonthChanged(value); + + if (_isSelectable(value)) { + _selectedDate = value; + widget.onDateChanged(_selectedDate); + } }); } @@ -257,6 +266,10 @@ class _CalendarDatePickerState extends State { }); } + bool _isSelectable(DateTime date) { + return widget.selectableDayPredicate == null || widget.selectableDayPredicate!.call(date); + } + Widget _buildPicker() { switch (_mode) { case DatePickerMode.day: diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index 038302dfd7afc..a678bb401837b 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -147,7 +147,7 @@ void main() { expect(find.text('31'), findsNothing); }); - testWidgets('Changing year does not change selected date', (WidgetTester tester) async { + testWidgets('Changing year does change selected date', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( onDateChanged: (DateTime date) => selectedDate = date, @@ -158,7 +158,26 @@ void main() { await tester.pumpAndSettle(); await tester.tap(find.text('2018')); await tester.pumpAndSettle(); - expect(selectedDate, equals(DateTime(2016, DateTime.january, 4))); + expect(selectedDate, equals(DateTime(2018, DateTime.january, 4))); + }); + + testWidgets('Changing year for february 29th', (WidgetTester tester) async { + DateTime? selectedDate; + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2020, DateTime.february, 29), + onDateChanged: (DateTime date) => selectedDate = date, + )); + await tester.tap(find.text('February 2020')); + await tester.pumpAndSettle(); + await tester.tap(find.text('2018')); + await tester.pumpAndSettle(); + expect(selectedDate, equals(DateTime(2018, DateTime.february, 28))); + await tester.tap(find.text('February 2018')); + await tester.pumpAndSettle(); + await tester.tap(find.text('2020')); + await tester.pumpAndSettle(); + // Changing back to 2020 the 29th is not selected anymore. + expect(selectedDate, equals(DateTime(2020, DateTime.february, 28))); }); testWidgets('Changing year does not change the month', (WidgetTester tester) async { @@ -260,11 +279,13 @@ void main() { }); testWidgets('Selecting firstDate year respects firstDate', (WidgetTester tester) async { + DateTime? selectedDate; DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( firstDate: DateTime(2016, DateTime.june, 9), initialDate: DateTime(2018, DateTime.may, 4), lastDate: DateTime(2019, DateTime.january, 15), + onDateChanged: (DateTime date) => selectedDate = date, onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, )); await tester.tap(find.text('May 2018')); @@ -274,14 +295,17 @@ void main() { // Month should be clamped to June as the range starts at June 2016. expect(find.text('June 2016'), findsOneWidget); expect(displayedMonth, DateTime(2016, DateTime.june)); + expect(selectedDate, DateTime(2016, DateTime.june, 9)); }); testWidgets('Selecting lastDate year respects lastDate', (WidgetTester tester) async { + DateTime? selectedDate; DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( firstDate: DateTime(2016, DateTime.june, 9), initialDate: DateTime(2018, DateTime.may, 4), lastDate: DateTime(2019, DateTime.january, 15), + onDateChanged: (DateTime date) => selectedDate = date, onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, )); await tester.tap(find.text('May 2018')); @@ -291,6 +315,7 @@ void main() { // Month should be clamped to January as the range ends at January 2019. expect(find.text('January 2019'), findsOneWidget); expect(displayedMonth, DateTime(2019)); + expect(selectedDate, DateTime(2019, DateTime.january, 15)); }); testWidgets('Only predicate days are selectable', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 514a5f4c28b43..3a7830806e05e 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -874,14 +874,14 @@ void main() { }); }); - testWidgets('Changing year does not change selected date', (WidgetTester tester) async { + testWidgets('Changing year does change selected date', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('January 2016')); await tester.pump(); await tester.tap(find.text('2018')); await tester.pump(); await tester.tap(find.text('OK')); - expect(await date, equals(DateTime(2016, DateTime.january, 15))); + expect(await date, equals(DateTime(2018, DateTime.january, 15))); }); }); From f2ba0a2b0a3201b934d7093e7434651e8e0c6b6f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 12:28:23 -0400 Subject: [PATCH 0341/1547] Roll Packages from 2266a7618ee3 to 8028cafa1f0c (13 revisions) (#131196) https://github.com/flutter/packages/compare/2266a7618ee3...8028cafa1f0c 2023-07-24 engine-flutter-autoroll@skia.org Roll Flutter from a8c8c5598c85 to d7ed5dc2e212 (7 revisions) (flutter/packages#4556) 2023-07-23 engine-flutter-autoroll@skia.org Roll Flutter from e8b397caca6f to a8c8c5598c85 (11 revisions) (flutter/packages#4552) 2023-07-22 engine-flutter-autoroll@skia.org Roll Flutter from 9cfbf6b9fd40 to e8b397caca6f (12 revisions) (flutter/packages#4550) 2023-07-21 stuartmorgan@google.com [ci] Clean up except exclusion list (flutter/packages#4547) 2023-07-21 47866232+chunhtai@users.noreply.github.com [go_router] Replaces uri related properties in GoRouterState (flutter/packages#4392) 2023-07-21 10687576+bparrishMines@users.noreply.github.com [webview_flutter_wkwebview] Updates pigeon version to `10.1.4` (flutter/packages#4548) 2023-07-21 tarrinneal@gmail.com [pigeon] Adds package name to method channel. (flutter/packages#4443) 2023-07-21 stuartmorgan@google.com [ci] Migrate remaing unblocked repo checks to LUCI (flutter/packages#4543) 2023-07-21 stuartmorgan@google.com [go_router] Remove unused dependency (flutter/packages#4545) 2023-07-21 engine-flutter-autoroll@skia.org Roll Flutter from d07e8aece184 to 9cfbf6b9fd40 (58 revisions) (flutter/packages#4544) 2023-07-21 43640732+dancamdev@users.noreply.github.com Adding myself and Michele to AUTHORS (flutter/packages#4527) 2023-07-21 32538273+ValentinVignal@users.noreply.github.com [go_router_builder] Removes `path_to_regexp` from the dependencies (flutter/packages#4524) 2023-07-21 rexios@rexios.dev [google_maps_flutter_web] Adds options for gesture handling and tilt controls. (flutter/packages#4521) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 44863a37272e3..549edcac752fe 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -2266a7618ee3139da8698369c1073d3f852c2dfc +8028cafa1f0c1bd1f7f678c455f48e64bc8a4e15 From 43afac1e29cacab6398f7024620d527688864f6a Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Mon, 24 Jul 2023 10:22:25 -0700 Subject: [PATCH 0342/1547] Reduce usage of testUsingContext (#131078) Part of https://github.com/flutter/flutter/issues/47161 --- packages/flutter_tools/lib/src/cmake.dart | 24 ++-- .../lib/src/commands/build_linux.dart | 6 +- .../lib/src/linux/build_linux.dart | 23 ++-- .../lib/src/linux/linux_device.dart | 3 + .../lib/src/reporting/events.dart | 4 +- packages/flutter_tools/lib/src/run_hot.dart | 4 + .../lib/src/windows/build_windows.dart | 2 +- .../test/general.shard/cmake_test.dart | 109 +++++------------- .../test/general.shard/hot_test.dart | 1 + .../test/general.shard/run_hot_test.dart | 7 +- 10 files changed, 79 insertions(+), 104 deletions(-) diff --git a/packages/flutter_tools/lib/src/cmake.dart b/packages/flutter_tools/lib/src/cmake.dart index 09adc69f8e673..2ac7d88e31bfd 100644 --- a/packages/flutter_tools/lib/src/cmake.dart +++ b/packages/flutter_tools/lib/src/cmake.dart @@ -4,9 +4,9 @@ import 'package:pub_semver/pub_semver.dart'; +import 'base/logger.dart'; import 'build_info.dart'; import 'cmake_project.dart'; -import 'globals.dart' as globals; /// Extracts the `BINARY_NAME` from a project's CMake file. /// @@ -41,12 +41,12 @@ String _determineVersionString(CmakeBasedProject project, BuildInfo buildInfo) { : buildName; } -Version _determineVersion(CmakeBasedProject project, BuildInfo buildInfo) { +Version _determineVersion(CmakeBasedProject project, BuildInfo buildInfo, Logger logger) { final String version = _determineVersionString(project, buildInfo); try { return Version.parse(version); } on FormatException { - globals.printWarning('Warning: could not parse version $version, defaulting to 1.0.0.'); + logger.printWarning('Warning: could not parse version $version, defaulting to 1.0.0.'); return Version(1, 0, 0); } @@ -74,25 +74,27 @@ void writeGeneratedCmakeConfig( String flutterRoot, CmakeBasedProject project, BuildInfo buildInfo, - Map environment) { + Map environment, + Logger logger, +) { // Only a limited set of variables are needed by the CMake files themselves, // the rest are put into a list to pass to the re-entrant build step. final String escapedFlutterRoot = _escapeBackslashes(flutterRoot); final String escapedProjectDir = _escapeBackslashes(project.parent.directory.path); - final Version version = _determineVersion(project, buildInfo); + final Version version = _determineVersion(project, buildInfo, logger); final int? buildVersion = _tryDetermineBuildVersion(version); // Since complex Dart build identifiers cannot be converted into integers, // different Dart versions may be converted into the same Windows numeric version. // Warn the user as some Windows installers, like MSI, don't update files if their versions are equal. if (buildVersion == null && project is WindowsProject) { - final String buildIdentifier = version.build.join('.'); - globals.printWarning( - 'Warning: build identifier $buildIdentifier in version $version is not numeric ' - 'and cannot be converted into a Windows build version number. Defaulting to 0.\n' - 'This may cause issues with Windows installers.' - ); + final String buildIdentifier = version.build.join('.'); + logger.printWarning( + 'Warning: build identifier $buildIdentifier in version $version is not numeric ' + 'and cannot be converted into a Windows build version number. Defaulting to 0.\n' + 'This may cause issues with Windows installers.' + ); } final StringBuffer buffer = StringBuffer(''' diff --git a/packages/flutter_tools/lib/src/commands/build_linux.dart b/packages/flutter_tools/lib/src/commands/build_linux.dart index 78515070034c5..dc709fc02b73b 100644 --- a/packages/flutter_tools/lib/src/commands/build_linux.dart +++ b/packages/flutter_tools/lib/src/commands/build_linux.dart @@ -2,8 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. + import '../base/analyze_size.dart'; import '../base/common.dart'; +import '../base/logger.dart'; import '../base/os.dart'; import '../build_info.dart'; import '../cache.dart'; @@ -83,18 +85,20 @@ class BuildLinuxCommand extends BuildSubCommand { 'Cross-build from Linux x64 host to Linux arm64 target is not currently supported.'); } displayNullSafetyMode(buildInfo); + final Logger logger = globals.logger; await buildLinux( flutterProject.linux, buildInfo, target: targetFile, sizeAnalyzer: SizeAnalyzer( fileSystem: globals.fs, - logger: globals.logger, + logger: logger, flutterUsage: globals.flutterUsage, ), needCrossBuild: needCrossBuild, targetPlatform: targetPlatform, targetSysroot: stringArg('target-sysroot')!, + logger: logger, ); return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index fb1b937ddfe9d..81a8d775ddb63 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -29,12 +29,13 @@ final RegExp errorMatcher = RegExp(r'(?:(?:.*:\d+:\d+|clang):\s)?(fatal\s)?(?:er Future buildLinux( LinuxProject linuxProject, BuildInfo buildInfo, { - String? target, - SizeAnalyzer? sizeAnalyzer, - bool needCrossBuild = false, - required TargetPlatform targetPlatform, - String targetSysroot = '/', - }) async { + String? target, + SizeAnalyzer? sizeAnalyzer, + bool needCrossBuild = false, + required TargetPlatform targetPlatform, + String targetSysroot = '/', + required Logger logger, +}) async { target ??= 'lib/main.dart'; if (!linuxProject.cmakeFile.existsSync()) { throwToolExit('No Linux desktop project configured. See ' @@ -43,7 +44,7 @@ Future buildLinux( } final List migrators = [ - CmakeCustomCommandMigration(linuxProject, globals.logger), + CmakeCustomCommandMigration(linuxProject, logger), ]; final ProjectMigration migration = ProjectMigration(migrators); @@ -59,11 +60,11 @@ Future buildLinux( environmentConfig['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); environmentConfig['LOCAL_ENGINE'] = localEngineInfo.localEngineName; } - writeGeneratedCmakeConfig(Cache.flutterRoot!, linuxProject, buildInfo, environmentConfig); + writeGeneratedCmakeConfig(Cache.flutterRoot!, linuxProject, buildInfo, environmentConfig, logger); createPluginSymlinks(linuxProject.parent); - final Status status = globals.logger.startProgress( + final Status status = logger.startProgress( 'Building Linux application...', ); try { @@ -97,13 +98,13 @@ Future buildLinux( .childDirectory('.flutter-devtools'), 'linux-code-size-analysis', 'json', )..writeAsStringSync(jsonEncode(output)); // This message is used as a sentinel in analyze_apk_size_test.dart - globals.printStatus( + logger.printStatus( 'A summary of your Linux bundle analysis can be found at: ${outputFile.path}', ); // DevTools expects a file path relative to the .flutter-devtools/ dir. final String relativeAppSizePath = outputFile.path.split('.flutter-devtools/').last.trim(); - globals.printStatus( + logger.printStatus( '\nTo analyze your app size in Dart DevTools, run the following command:\n' 'dart devtools --appSizeBase=$relativeAppSizePath' ); diff --git a/packages/flutter_tools/lib/src/linux/linux_device.dart b/packages/flutter_tools/lib/src/linux/linux_device.dart index 8e6b141a949ac..7d210ee049da4 100644 --- a/packages/flutter_tools/lib/src/linux/linux_device.dart +++ b/packages/flutter_tools/lib/src/linux/linux_device.dart @@ -25,6 +25,7 @@ class LinuxDevice extends DesktopDevice { required FileSystem fileSystem, required OperatingSystemUtils operatingSystemUtils, }) : _operatingSystemUtils = operatingSystemUtils, + _logger = logger, super( 'linux', platformType: PlatformType.linux, @@ -36,6 +37,7 @@ class LinuxDevice extends DesktopDevice { ); final OperatingSystemUtils _operatingSystemUtils; + final Logger _logger; @override bool isSupported() => true; @@ -66,6 +68,7 @@ class LinuxDevice extends DesktopDevice { buildInfo, target: mainPath, targetPlatform: await targetPlatform, + logger: _logger, ); } diff --git a/packages/flutter_tools/lib/src/reporting/events.dart b/packages/flutter_tools/lib/src/reporting/events.dart index 5ffcb2d584f3b..ae0028f214f93 100644 --- a/packages/flutter_tools/lib/src/reporting/events.dart +++ b/packages/flutter_tools/lib/src/reporting/events.dart @@ -54,7 +54,9 @@ class HotEvent extends UsageEvent { this.scannedSourcesCount, this.reassembleTimeInMs, this.reloadVMTimeInMs, - }) : super('hot', parameter, flutterUsage: globals.flutterUsage); + // TODO(fujino): make this required + Usage? usage, + }) : super('hot', parameter, flutterUsage: usage ?? globals.flutterUsage); final String? reason; final String targetPlatform; diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 57e4e0eac3ea9..d687012fdeab0 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -950,6 +950,7 @@ class HotRunner extends ResidentRunner { sdkName, emulator, reason, + globals.flutterUsage, ); if (result.code != 0) { return result; @@ -1172,6 +1173,7 @@ typedef ReloadSourcesHelper = Future Function( String? sdkName, bool? emulator, String? reason, + Usage usage, ); @visibleForTesting @@ -1184,6 +1186,7 @@ Future defaultReloadSourcesHelper( String? sdkName, bool? emulator, String? reason, + Usage usage, ) async { final Stopwatch vmReloadTimer = Stopwatch()..start(); const String entryPath = 'main.dart.incremental.dill'; @@ -1223,6 +1226,7 @@ Future defaultReloadSourcesHelper( fullRestart: false, reason: reason, fastReassemble: false, + usage: usage, ).send(); // Reset devFS lastCompileTime to ensure the file will still be marked // as dirty on subsequent reloads. diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index 6351b66c7ad6c..7ffb4a69d7b64 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -242,7 +242,7 @@ void _writeGeneratedFlutterConfig( environment['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); environment['LOCAL_ENGINE'] = localEngineInfo.localEngineName; } - writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, buildInfo, environment); + writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, buildInfo, environment, globals.logger); } // Works around the Visual Studio 17.1.0 CMake bug described in diff --git a/packages/flutter_tools/test/general.shard/cmake_test.dart b/packages/flutter_tools/test/general.shard/cmake_test.dart index 091251e3c64d0..861a2e44846b5 100644 --- a/packages/flutter_tools/test/general.shard/cmake_test.dart +++ b/packages/flutter_tools/test/general.shard/cmake_test.dart @@ -11,23 +11,20 @@ import 'package:flutter_tools/src/cmake.dart'; import 'package:flutter_tools/src/project.dart'; import '../src/common.dart'; -import '../src/context.dart'; const String _kTestFlutterRoot = '/flutter'; const String _kTestWindowsFlutterRoot = r'C:\flutter'; void main() { late FileSystem fileSystem; - late ProcessManager processManager; late BufferLogger logger; setUp(() { - processManager = FakeProcessManager.any(); fileSystem = MemoryFileSystem.test(); logger = BufferLogger.test(); }); - testUsingContext('parses executable name from cmake file', () async { + testWithoutContext('parses executable name from cmake file', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); @@ -38,24 +35,18 @@ void main() { final String? name = getCmakeExecutableName(cmakeProject); expect(name, 'hello'); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('defaults executable name to null if cmake config does not exist', () async { + testWithoutContext('defaults executable name to null if cmake config does not exist', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); final String? name = getCmakeExecutableName(cmakeProject); expect(name, isNull); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generates config', () async { + testWithoutContext('generates config', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo(BuildMode.release, null, treeShakeIcons: false); @@ -66,6 +57,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -91,12 +83,9 @@ void main() { r' "PROJECT_DIR=/"', r')', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('config escapes backslashes', () async { + testWithoutContext('config escapes backslashes', () async { fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); @@ -112,6 +101,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -138,12 +128,9 @@ void main() { r' "TEST=hello\\world"', r')', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses pubspec version', () async { + testWithoutContext('generated config uses pubspec version', () async { fileSystem.file('pubspec.yaml') ..createSync() ..writeAsStringSync('version: 1.2.3+4'); @@ -158,6 +145,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -173,12 +161,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 4 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses build name', () async { + testWithoutContext('generated config uses build name', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -194,6 +179,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -209,12 +195,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 0 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses build number', () async { + testWithoutContext('generated config uses build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -230,6 +213,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -245,12 +229,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 0 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 4 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses build name and build number', () async { + testWithoutContext('generated config uses build name and build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -267,6 +248,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -282,12 +264,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 4 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses build name over pubspec version', () async { + testWithoutContext('generated config uses build name over pubspec version', () async { fileSystem.file('pubspec.yaml') ..createSync() ..writeAsStringSync('version: 9.9.9+9'); @@ -307,6 +286,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -322,12 +302,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 0 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses build number over pubspec version', () async { + testWithoutContext('generated config uses build number over pubspec version', () async { fileSystem.file('pubspec.yaml') ..createSync() ..writeAsStringSync('version: 1.2.3+4'); @@ -347,6 +324,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -362,12 +340,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 5 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config uses build name and build number over pubspec version', () async { + testWithoutContext('generated config uses build name and build number over pubspec version', () async { fileSystem.file('pubspec.yaml') ..createSync() ..writeAsStringSync('version: 9.9.9+9'); @@ -388,6 +363,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -403,12 +379,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 4 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, }); - testUsingContext('generated config ignores invalid build name', () async { + testWithoutContext('generated config ignores invalid build name', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -424,6 +397,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -441,13 +415,9 @@ void main() { ])); expect(logger.warningText, contains('Warning: could not parse version hello.world, defaulting to 1.0.0.')); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Logger: () => logger, }); - testUsingContext('generated config ignores invalid build number', () async { + testWithoutContext('generated config ignores invalid build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -464,6 +434,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); final File cmakeConfig = cmakeProject.generatedCmakeConfigFile; @@ -481,13 +452,9 @@ void main() { ])); expect(logger.warningText, contains('Warning: could not parse version 1.2.3+foo_bar, defaulting to 1.0.0.')); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Logger: () => logger, }); - testUsingContext('generated config handles non-numeric build number', () async { + testWithoutContext('generated config handles non-numeric build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -504,6 +471,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); expect(logger.warningText, isEmpty); @@ -521,13 +489,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 0 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Logger: () => logger, }); - testUsingContext('generated config handles complex build number', () async { + testWithoutContext('generated config handles complex build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = _FakeProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -544,6 +508,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); expect(logger.warningText, isEmpty); @@ -561,13 +526,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 0 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Logger: () => logger, }); - testUsingContext('generated config warns on Windows project with non-numeric build number', () async { + testWithoutContext('generated config warns on Windows project with non-numeric build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = WindowsProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -584,6 +545,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); expect(logger.warningText, contains( @@ -605,13 +567,9 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 0 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Logger: () => logger, }); - testUsingContext('generated config warns on Windows project with complex build number', () async { + testWithoutContext('generated config warns on Windows project with complex build number', () async { final FlutterProject project = FlutterProject.fromDirectoryTest(fileSystem.currentDirectory); final CmakeBasedProject cmakeProject = WindowsProject.fromFlutter(project); const BuildInfo buildInfo = BuildInfo( @@ -628,6 +586,7 @@ void main() { cmakeProject, buildInfo, environment, + logger, ); expect(logger.warningText, contains( @@ -649,10 +608,6 @@ void main() { 'set(FLUTTER_VERSION_PATCH 3 PARENT_SCOPE)', 'set(FLUTTER_VERSION_BUILD 0 PARENT_SCOPE)', ])); - }, overrides: { - FileSystem: () => fileSystem, - ProcessManager: () => processManager, - Logger: () => logger, }); } diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index 8060f80ef00ad..110b59a08cd09 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -366,6 +366,7 @@ void main() { String? sdkName, bool? emulator, String? reason, + Usage usage, ) async { firstReloadDetails['finalLibraryCount'] = 2; firstReloadDetails['receivedLibraryCount'] = 3; diff --git a/packages/flutter_tools/test/general.shard/run_hot_test.dart b/packages/flutter_tools/test/general.shard/run_hot_test.dart index bcd367e76a711..df83239d8003b 100644 --- a/packages/flutter_tools/test/general.shard/run_hot_test.dart +++ b/packages/flutter_tools/test/general.shard/run_hot_test.dart @@ -3,16 +3,18 @@ // found in the LICENSE file. import 'package:flutter_tools/src/devfs.dart'; +import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/vmservice.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; -import '../src/context.dart'; +//import '../src/context.dart'; +import '../src/common.dart'; void main() { - testUsingContext('defaultReloadSourcesHelper() handles empty DeviceReloadReports)', () { + testWithoutContext('defaultReloadSourcesHelper() handles empty DeviceReloadReports)', () { defaultReloadSourcesHelper( _FakeHotRunner(), [_FakeFlutterDevice()], @@ -22,6 +24,7 @@ void main() { 'flutter-sdk', false, 'test-reason', + TestUsage(), ); }); } From c65cab8fa3c13c481849e5fbaed572fc3e53c08b Mon Sep 17 00:00:00 2001 From: Sabin Neupane <61322712+sabin26@users.noreply.github.com> Date: Tue, 25 Jul 2023 00:00:53 +0545 Subject: [PATCH 0343/1547] [DropdownMenu] Close menu after editing is complete (#130710) Fixes: #130674 Before: The dropdown menu was not closed if empty text was provided After: The dropdown menu is closed even if empty text is provided https://github.com/flutter/flutter/assets/61322712/fccac501-9fca-4f60-8a94-abfc50552ec9 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/material/dropdown_menu.dart | 4 +-- .../test/material/dropdown_menu_test.dart | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 4bf3cee5975f0..51a972a3398a6 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -612,9 +612,7 @@ class _DropdownMenuState extends State> { if (!widget.enableSearch) { currentHighlight = null; } - if (_textEditingController.text.isNotEmpty) { - controller.close(); - } + controller.close(); }, onTap: () { handlePressed(controller); diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index d61d1764a8227..a721cfdb87a2b 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -1050,6 +1050,34 @@ void main() { expect(controller.text, 'New Item'); }); + testWidgets('The menu should be closed after text editing is complete', (WidgetTester tester) async { + final ThemeData themeData = ThemeData(); + final TextEditingController controller = TextEditingController(); + await tester.pumpWidget(MaterialApp( + theme: themeData, + home: Scaffold( + body: DropdownMenu( + requestFocusOnTap: true, + enableFilter: true, + dropdownMenuEntries: menuChildren, + controller: controller, + ), + ), + )); + // Access the MenuAnchor + final MenuAnchor menuAnchor = tester.widget(find.byType(MenuAnchor)); + + // Open the menu + await tester.tap(find.byType(DropdownMenu)); + await tester.pumpAndSettle(); + expect(menuAnchor.controller!.isOpen, true); + + // Simulate `TextInputAction.done` on textfield + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pumpAndSettle(); + expect(menuAnchor.controller!.isOpen, false); + }); + testWidgets('The onSelected gets called only when a selection is made', (WidgetTester tester) async { int selectionCount = 0; From 8a37b8ba3539540e56eb980e5e8055cff2467660 Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Mon, 24 Jul 2023 11:19:03 -0700 Subject: [PATCH 0344/1547] Optimize SliverMainAxisGroup/SliverCrossAxisGroup paint function (#129310) This PR changes the paint functions for SliverMainAxisGroup and SliverCrossAxisGroup so that only visible slivers are painted. Fixes https://github.com/flutter/flutter/issues/129214. --- .../lib/src/rendering/sliver_group.dart | 12 ++-- .../flutter/test/rendering/sliver_utils.dart | 36 +++++++++++ .../widgets/sliver_cross_axis_group_test.dart | 58 ++++++++++++++++++ .../widgets/sliver_main_axis_group_test.dart | 60 +++++++++++++++++++ 4 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 packages/flutter/test/rendering/sliver_utils.dart diff --git a/packages/flutter/lib/src/rendering/sliver_group.dart b/packages/flutter/lib/src/rendering/sliver_group.dart index 6057be87add96..831590840894a 100644 --- a/packages/flutter/lib/src/rendering/sliver_group.dart +++ b/packages/flutter/lib/src/rendering/sliver_group.dart @@ -129,8 +129,10 @@ class RenderSliverCrossAxisGroup extends RenderSliver with ContainerRenderObject RenderSliver? child = firstChild; while (child != null) { - final SliverPhysicalParentData childParentData = child.parentData! as SliverPhysicalParentData; - context.paintChild(child, offset + childParentData.paintOffset); + if (child.geometry!.visible) { + final SliverPhysicalParentData childParentData = child.parentData! as SliverPhysicalParentData; + context.paintChild(child, offset + childParentData.paintOffset); + } child = childAfter(child); } } @@ -294,8 +296,10 @@ class RenderSliverMainAxisGroup extends RenderSliver with ContainerRenderObjectM RenderSliver? child = lastChild; while (child != null) { - final SliverPhysicalParentData childParentData = child.parentData! as SliverPhysicalParentData; - context.paintChild(child, offset + childParentData.paintOffset); + if (child.geometry!.visible) { + final SliverPhysicalParentData childParentData = child.parentData! as SliverPhysicalParentData; + context.paintChild(child, offset + childParentData.paintOffset); + } child = childBefore(child); } } diff --git a/packages/flutter/test/rendering/sliver_utils.dart b/packages/flutter/test/rendering/sliver_utils.dart new file mode 100644 index 0000000000000..8fbe123d0959e --- /dev/null +++ b/packages/flutter/test/rendering/sliver_utils.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test sliver which always attempts to paint itself whether it is visible or not. +// Use for checking if slivers which take sliver children paints optimally. +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +class RenderMockSliverToBoxAdapter extends RenderSliverToBoxAdapter { + RenderMockSliverToBoxAdapter({ + super.child, + required this.incrementCounter, + }); + final void Function() incrementCounter; + + @override + void paint(PaintingContext context, Offset offset) { + incrementCounter(); + } +} + +class MockSliverToBoxAdapter extends SingleChildRenderObjectWidget { + /// Creates a sliver that contains a single box widget. + const MockSliverToBoxAdapter({ + super.key, + super.child, + required this.incrementCounter, + }); + + final void Function() incrementCounter; + + @override + RenderMockSliverToBoxAdapter createRenderObject(BuildContext context) => + RenderMockSliverToBoxAdapter(incrementCounter: incrementCounter); +} diff --git a/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart b/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart index 745f2c28ff403..a3d4dc8fd906b 100644 --- a/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart @@ -6,6 +6,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../rendering/sliver_utils.dart'; + + const double VIEWPORT_HEIGHT = 600; const double VIEWPORT_WIDTH = 300; @@ -806,8 +809,63 @@ void main() { // If renderHeader._lastStartedScrollDirection is not ScrollDirection.forward, then we shouldn't see the header at all. expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); + + testWidgets('SliverCrossAxisGroup skips painting invisible children', (WidgetTester tester) async { + final ScrollController controller = ScrollController(); + + int counter = 0; + void incrementCounter() { + counter += 1; + } + + await tester.pumpWidget( + _buildSliverCrossAxisGroup( + controller: controller, + slivers: [ + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 1000, + decoration: const BoxDecoration(color: Colors.amber), + ), + ), + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 400, + decoration: const BoxDecoration(color: Colors.amber) + ), + ), + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 500, + decoration: const BoxDecoration(color: Colors.amber) + ), + ), + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 300, + decoration: const BoxDecoration(color: Colors.amber) + ), + ), + ], + ), + ); + expect(counter, equals(4)); + + // Reset paint counter. + counter = 0; + controller.jumpTo(400); + await tester.pumpAndSettle(); + + expect(controller.offset, 400); + expect(counter, equals(2)); + }); } + Widget _buildSliverList({ double itemMainAxisExtent = 100, List items = const [], diff --git a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart index 7851cb430c44f..597c196acb3e7 100644 --- a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart @@ -6,6 +6,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../rendering/sliver_utils.dart'; + + const double VIEWPORT_HEIGHT = 600; const double VIEWPORT_WIDTH = 300; @@ -604,6 +607,63 @@ void main() { expect(renderHeader.geometry!.paintExtent, equals(60.0)); expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(-50.0)); }); + + testWidgets('SliverMainAxisGroup skips painting invisible children', (WidgetTester tester) async { + final ScrollController controller = ScrollController(); + + int counter = 0; + void incrementCounter() { + counter += 1; + } + + await tester.pumpWidget( + _buildSliverMainAxisGroup( + controller: controller, + slivers: [ + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 1000, + decoration: const BoxDecoration(color: Colors.amber), + ), + ), + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 400, + decoration: const BoxDecoration(color: Colors.amber) + ), + ), + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 500, + decoration: const BoxDecoration(color: Colors.amber) + ), + ), + MockSliverToBoxAdapter( + incrementCounter: incrementCounter, + child: Container( + height: 300, + decoration: const BoxDecoration(color: Colors.amber) + ), + ), + ], + ), + ); + + // Can only see top sliver. + expect(counter, equals(1)); + + // Reset paint counter. + counter = 0; + controller.jumpTo(1000); + await tester.pumpAndSettle(); + + // Can only see second and third slivers. + expect(controller.offset, 1000); + expect(counter, equals(2)); + }); } Widget _buildSliverList({ From 283437a2d2f8a894e6d89702020fb94100b207ea Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Mon, 24 Jul 2023 11:23:49 -0700 Subject: [PATCH 0345/1547] Update link to unbounded constraints error (#131205) Fixes https://github.com/flutter/flutter/issues/130805. --- packages/flutter/lib/src/rendering/flex.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart index 6d10cf38c1af4..db6df8757269f 100644 --- a/packages/flutter/lib/src/rendering/flex.dart +++ b/packages/flutter/lib/src/rendering/flex.dart @@ -730,7 +730,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin Date: Mon, 24 Jul 2023 20:25:04 +0200 Subject: [PATCH 0346/1547] Fix floating SnackBar throws when FAB is on the top (#129274) ## Description This PR updates how a floating snack bar is positionned when a `Scaffold` defines a FAB with `Scaffold.floatingActionButtonLocation` sets to one of the top locations. **Before this PR:** - When a FAB location is set to the top of the `Scaffold`, a floating `SnackBar` can't be displayed and an assert throws in debug mode. **After this PR:** - When a FAB location is set to the top of the `Scaffold`, a floating `SnackBar` will be displayed at the bottom of the screen, above a `NavigationBar` for instance (the top FAB is ignored when computing the floating snack bar position). ![image](https://github.com/flutter/flutter/assets/840911/08fcee6c-b286-4749-ad0b-ba09e653bd94) ## Motivation This is a edge case related to a discrepancy between the Material spec and the Flutter `Scaffold` customizability: - Material spec states that a floating `SnackBar` should be displayed above a FAB. But, in Material spec, FABs are expected to be on the bottom. - Since https://github.com/flutter/flutter/issues/51465, Flutter `Scaffold` makes it valid to show a FAB on the top of the `Scaffold`. ## Related Issue fixes https://github.com/flutter/flutter/issues/128150 ## Tests Adds 1 test. --- .../flutter/lib/src/material/scaffold.dart | 26 ++++++++- .../lib/src/material/snack_bar_theme.dart | 15 +++--- .../flutter/test/material/snack_bar_test.dart | 53 +++++++++++++++++++ 3 files changed, 87 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index 110cbbbfb1c89..f86355bb11253 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1142,7 +1142,31 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { } final double snackBarYOffsetBase; - if (floatingActionButtonRect.size != Size.zero && isSnackBarFloating) { + final bool showAboveFab = switch (currentFloatingActionButtonLocation) { + FloatingActionButtonLocation.startTop + || FloatingActionButtonLocation.centerTop + || FloatingActionButtonLocation.endTop + || FloatingActionButtonLocation.miniStartTop + || FloatingActionButtonLocation.miniCenterTop + || FloatingActionButtonLocation.miniEndTop => false, + FloatingActionButtonLocation.startDocked + || FloatingActionButtonLocation.startFloat + || FloatingActionButtonLocation.centerDocked + || FloatingActionButtonLocation.centerFloat + || FloatingActionButtonLocation.endContained + || FloatingActionButtonLocation.endDocked + || FloatingActionButtonLocation.endFloat + || FloatingActionButtonLocation.miniStartDocked + || FloatingActionButtonLocation.miniStartFloat + || FloatingActionButtonLocation.miniCenterDocked + || FloatingActionButtonLocation.miniCenterFloat + || FloatingActionButtonLocation.miniEndDocked + || FloatingActionButtonLocation.miniEndFloat => true, + FloatingActionButtonLocation() => throw FlutterError( + '$currentFloatingActionButtonLocation is an unknown FloatingActionButtonLocation value.' + ), + }; + if (floatingActionButtonRect.size != Size.zero && isSnackBarFloating && showAboveFab) { snackBarYOffsetBase = floatingActionButtonRect.top; } else { // SnackBarBehavior.fixed applies a SafeArea automatically. diff --git a/packages/flutter/lib/src/material/snack_bar_theme.dart b/packages/flutter/lib/src/material/snack_bar_theme.dart index 5f976148d70fc..dae0804f863d6 100644 --- a/packages/flutter/lib/src/material/snack_bar_theme.dart +++ b/packages/flutter/lib/src/material/snack_bar_theme.dart @@ -12,19 +12,22 @@ import 'theme.dart'; /// Defines where a [SnackBar] should appear within a [Scaffold] and how its /// location should be adjusted when the scaffold also includes a -/// [FloatingActionButton] or a [BottomNavigationBar]. +/// [FloatingActionButton], a [BottomNavigationBar], or a [NavigationBar]. enum SnackBarBehavior { /// Fixes the [SnackBar] at the bottom of the [Scaffold]. /// /// The exception is that the [SnackBar] will be shown above a - /// [BottomNavigationBar]. Additionally, the [SnackBar] will cause other - /// non-fixed widgets inside [Scaffold] to be pushed above (for example, the - /// [FloatingActionButton]). + /// [BottomNavigationBar] or a [NavigationBar]. Additionally, the [SnackBar] + /// will cause other non-fixed widgets inside [Scaffold] to be pushed above + /// (for example, the [FloatingActionButton]). fixed, /// This behavior will cause [SnackBar] to be shown above other widgets in the - /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] - /// and a [FloatingActionButton]. + /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] or + /// a [NavigationBar], and a [FloatingActionButton] when its location is on the + /// bottom. When the floating action button location is on the top, this behavior + /// will cause the [SnackBar] to be shown above other widgets in the [Scaffold] + /// except the floating action button. /// /// See for more details. floating, diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index 9436f743b4e30..22d43cc3c99e5 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -2071,6 +2071,59 @@ void main() { }, ); + testWidgets( + '${SnackBarBehavior.floating} should not align SnackBar with the top of FloatingActionButton ' + 'when Scaffold has a FloatingActionButton and floatingActionButtonLocation is set to a top position', + (WidgetTester tester) async { + Future pumpApp({required FloatingActionButtonLocation fabLocation}) async { + return tester.pumpWidget(MaterialApp( + home: Scaffold( + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.send), + onPressed: () {}, + ), + floatingActionButtonLocation: fabLocation, + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + behavior: SnackBarBehavior.floating, + )); + }, + child: const Text('X'), + ); + }, + ), + ), + )); + } + + const List topLocations = [ + FloatingActionButtonLocation.startTop, + FloatingActionButtonLocation.centerTop, + FloatingActionButtonLocation.endTop, + FloatingActionButtonLocation.miniStartTop, + FloatingActionButtonLocation.miniCenterTop, + FloatingActionButtonLocation.miniEndTop, + ]; + + for (final FloatingActionButtonLocation location in topLocations) { + await pumpApp(fabLocation: location); + + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + + expect(snackBarBottomLeft.dy, 600); // Device height is 600. + } + }, + ); + testWidgets( '${SnackBarBehavior.fixed} should align SnackBar with the top of BottomNavigationBar ' 'when Scaffold has a BottomNavigationBar and FloatingActionButton', From 5554b0eeb3780d3fac90370d75dc57893733ae71 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 24 Jul 2023 21:30:23 +0300 Subject: [PATCH 0347/1547] Fix M3 TimePicker dial background uses incorrect color (#131045) fixes [Material3: TimePicker clock dial use wrong spec color and its web spec has a mistake](https://github.com/flutter/flutter/issues/118657) ### Description This PR fixes the default color used for the Material 3 dial background. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { final ThemeData theme = ThemeData(useMaterial3: true); return MaterialApp( debugShowCheckedModeBanner: false, // theme: theme, theme: theme.copyWith( colorScheme: theme.colorScheme.copyWith( surfaceVariant: const Color(0xffffbf00), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sample'), ), body: Center( child: ElevatedButton( onPressed: () { showTimePicker( context: context, initialTime: TimeOfDay.now(), ); }, child: const Text('Open Time Picker'), ), ), ); } } ```
### Default dial background color | Before | After | | --------------- | --------------- | | | | ### Custom color scheme | Before | After | | --------------- | --------------- | | | | --- .../lib/time_picker_template.dart | 2 +- .../flutter/lib/src/material/time_picker.dart | 2 +- .../lib/src/material/time_picker_theme.dart | 10 ++- .../test/material/time_picker_test.dart | 65 +++++++++++++++++++ .../test/material/time_picker_theme_test.dart | 2 +- 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/dev/tools/gen_defaults/lib/time_picker_template.dart b/dev/tools/gen_defaults/lib/time_picker_template.dart index b1aa65ecda63e..a10e5b35c57c0 100644 --- a/dev/tools/gen_defaults/lib/time_picker_template.dart +++ b/dev/tools/gen_defaults/lib/time_picker_template.dart @@ -132,7 +132,7 @@ class _${blockName}DefaultsM3 extends _TimePickerDefaults { @override Color get dialBackgroundColor { - return ${componentColor(dialComponent)}.withOpacity(_colors.brightness == Brightness.dark ? 0.12 : 0.08); + return ${componentColor(dialComponent)}; } @override diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 1d2e9dc2a9ca6..bde201785a510 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -3434,7 +3434,7 @@ class _TimePickerDefaultsM3 extends _TimePickerDefaults { @override Color get dialBackgroundColor { - return _colors.surfaceVariant.withOpacity(_colors.brightness == Brightness.dark ? 0.12 : 0.08); + return _colors.surfaceVariant; } @override diff --git a/packages/flutter/lib/src/material/time_picker_theme.dart b/packages/flutter/lib/src/material/time_picker_theme.dart index e340cf9edf402..cb18b266456fd 100644 --- a/packages/flutter/lib/src/material/time_picker_theme.dart +++ b/packages/flutter/lib/src/material/time_picker_theme.dart @@ -136,8 +136,14 @@ class TimePickerThemeData with Diagnosticable { /// The background color of the time picker dial when the entry mode is /// [TimePickerEntryMode.dial] or [TimePickerEntryMode.dialOnly]. /// - /// If this is null, the time picker defaults to the overall theme's - /// [ColorScheme.primary]. + /// If this is null and [ThemeData.useMaterial3] is true, the time picker + /// dial background color defaults [ColorScheme.surfaceVariant] color. + /// + /// If this is null and [ThemeData.useMaterial3] is false, the time picker + /// dial background color defaults to [ColorScheme.onSurface] color with + /// an opacity of 0.08 when the overall theme's brightness is [Brightness.light] + /// and [ColorScheme.onSurface] color with an opacity of 0.12 when the overall + /// theme's brightness is [Brightness.dark]. final Color? dialBackgroundColor; /// The color of the time picker dial's hand when the entry mode is diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 1cb1c9a419c73..86a0f32d6b550 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -225,6 +226,70 @@ void main() { expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); }); + testWidgets('Material3 - Dial background uses correct default color', (WidgetTester tester) async { + ThemeData theme = ThemeData(useMaterial3: true); + Widget buildTimePicker(ThemeData themeData) { + return MaterialApp( + theme: themeData, + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () { + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ); + }, + ); + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildTimePicker(theme)); + + // Open the time picker dialog. + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + // Test default dial background color. + RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); + expect( + dial, + paints + ..circle(color: theme.colorScheme.surfaceVariant) // Dial background color. + ..circle(color: Color(theme.colorScheme.primary.value)), // Dial hand color. + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + // Test dial background color when theme color scheme is changed. + theme = theme.copyWith( + colorScheme: theme.colorScheme.copyWith( + surfaceVariant: const Color(0xffff0000), + ), + ); + await tester.pumpWidget(buildTimePicker(theme)); + + // Open the time picker dialog. + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + dial = tester.firstRenderObject(find.byType(CustomPaint)); + expect( + dial, + paints + ..circle(color: const Color(0xffff0000)) // Dial background color. + ..circle(color: Color(theme.colorScheme.primary.value)), // Dial hand color. + ); + }); + for (final MaterialType materialType in MaterialType.values) { group('Dial (${materialType.name})', () { testWidgets('tap-select an hour', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index 2c7ba77af88c0..9f07d5e38f2e8 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -242,7 +242,7 @@ void main() { expect( dial, paints - ..circle(color: defaultTheme.colorScheme.surfaceVariant.withOpacity(0.08)) // Dial background color. + ..circle(color: defaultTheme.colorScheme.surfaceVariant) // Dial background color. ..circle(color: Color(defaultTheme.colorScheme.primary.value)), // Dial hand color. ); From c53cfc555eaaeedee8e94984a3a2dd8471df0b06 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 15:44:22 -0400 Subject: [PATCH 0348/1547] Roll Flutter Engine from aa876f6bec69 to 2b8d83fa20e3 (3 revisions) (#131207) https://github.com/flutter/engine/compare/aa876f6bec69...2b8d83fa20e3 2023-07-24 zanderso@users.noreply.github.com Revert "Remove more calls to SkCanvas::flush() and SkSurface::flush()" (flutter/engine#43957) 2023-07-24 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from A02P1GsGg001-Mpn3... to DOxjABQZ-mA_9Lllw... (flutter/engine#43953) 2023-07-24 kjlubick@users.noreply.github.com Remove more calls to SkCanvas::flush() and SkSurface::flush() (flutter/engine#43902) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from A02P1GsGg001 to DOxjABQZ-mA_ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ec13d66ee2b53..d55ca1349d65a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -aa876f6bec69c1f6327017460dc7e8a6872c5fdf +2b8d83fa20e302ef48dc5eed328ca4c19499ff22 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 41a4991fa7c7e..0e90d2579c729 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -A02P1GsGg001-Mpn3gH1a5yc1P9CeyzlzeA2ZhA9V14C +DOxjABQZ-mA_9Lllw-zabKlcUWR6k4czzl1NQUSqOBwC From 8a01c9b7078b69f791ba465356d7744aeb4c581e Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Mon, 24 Jul 2023 12:59:06 -0700 Subject: [PATCH 0349/1547] Use toStringAsFixed in DecorationImage.toString (#131026) This makes the output less sensitive on JS int vs double shenanigans. --- .../flutter/lib/src/painting/decoration_image.dart | 4 ++-- packages/flutter/test/painting/decoration_test.dart | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index 87ed9e0eefeaf..5c8ed9df0390d 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -236,8 +236,8 @@ class DecorationImage { '$repeat', if (matchTextDirection) 'match text direction', - 'scale $scale', - 'opacity $opacity', + 'scale ${scale.toStringAsFixed(1)}', + 'opacity ${opacity.toStringAsFixed(1)}', '$filterQuality', if (invertColors) 'invert colors', diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart index 649acd124753b..8750ba5e4862d 100644 --- a/packages/flutter/test/painting/decoration_test.dart +++ b/packages/flutter/test/painting/decoration_test.dart @@ -333,6 +333,19 @@ void main() { expect(paint.invertColors, !kIsWeb); }); + test('DecorationImage.toString', () async { + expect( + DecorationImage( + image: SynchronousTestImageProvider( + await createTestImage(width: 100, height: 100), + ), + opacity: 0.99, + scale: 2.01, + ).toString(), + 'DecorationImage(SynchronousTestImageProvider(), Alignment.center, scale 2.0, opacity 1.0, FilterQuality.low)', + ); + }); + test('DecorationImage with null textDirection configuration should throw Error', () async { const ColorFilter colorFilter = ui.ColorFilter.mode(Color(0xFF00FF00), BlendMode.src); final ui.Image image = await createTestImage(width: 100, height: 100); From 2efd0719ba718c257de65ffa7aa7c404ca09792a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 16:40:15 -0400 Subject: [PATCH 0350/1547] Roll Flutter Engine from 2b8d83fa20e3 to 815b97157dc7 (5 revisions) (#131214) https://github.com/flutter/engine/compare/2b8d83fa20e3...815b97157dc7 2023-07-24 findyou795@gmail.com Fix missing dispose VirtualDisplayController (flutter/engine#43807) 2023-07-24 jonahwilliams@google.com [Impeller] provide cull rect to Canvas in GL/Vulakn impeller backend. (flutter/engine#43961) 2023-07-24 bdero@google.com [Impeller] Fix clip pipeline validation failure; add dedicated clip shaders. (flutter/engine#43946) 2023-07-24 skia-flutter-autoroll@skia.org Roll ANGLE from e28575f66ae5 to 5e21d7f02425 (4 revisions) (flutter/engine#43964) 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from a56bc23bfec7 to 99e8dc51ba53 (5 revisions) (flutter/engine#43963) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d55ca1349d65a..9a30eeecf56e1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2b8d83fa20e302ef48dc5eed328ca4c19499ff22 +815b97157dc72fe1d312c66b1af887c452475a05 From 660ce07b67d62d48480fb5eb0395184480d19eb1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 17:34:40 -0400 Subject: [PATCH 0351/1547] Roll Flutter Engine from 815b97157dc7 to a489c7496268 (3 revisions) (#131218) https://github.com/flutter/engine/compare/815b97157dc7...a489c7496268 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from 99e8dc51ba53 to 6c219acc30a5 (4 revisions) (flutter/engine#43970) 2023-07-24 ian@hixie.ch add ColorFilter.toString to web_ui (flutter/engine#43874) 2023-07-24 skia-flutter-autoroll@skia.org Roll ANGLE from 5e21d7f02425 to 2d999f744809 (1 revision) (flutter/engine#43968) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9a30eeecf56e1..87bfbcd3598a7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -815b97157dc72fe1d312c66b1af887c452475a05 +a489c74962684f84438a270c31303c85172f1060 From e06c023822077fd958f414ca9d02c7edce80e49e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 18:25:46 -0400 Subject: [PATCH 0352/1547] Roll Flutter Engine from a489c7496268 to ff02fa72acce (1 revision) (#131221) https://github.com/flutter/engine/compare/a489c7496268...ff02fa72acce 2023-07-24 233583+mossmana@users.noreply.github.com Replace deprecated [UIScreen mainScreen] in FlutterViewController.mm and FlutterViewControllerTest.mm (flutter/engine#43690) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 87bfbcd3598a7..3bb43d1f9b061 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a489c74962684f84438a270c31303c85172f1060 +ff02fa72acce8eb9708a8b1b67b2988f7a8114ab From b1a25bd4a1b96c544c485c1ebaae2942ab84b55a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 20:08:24 -0400 Subject: [PATCH 0353/1547] Roll Flutter Engine from ff02fa72acce to 4fded78e5a01 (2 revisions) (#131225) https://github.com/flutter/engine/compare/ff02fa72acce...4fded78e5a01 2023-07-24 skia-flutter-autoroll@skia.org Roll Skia from 6c219acc30a5 to 4554d1b35b6e (4 revisions) (flutter/engine#43973) 2023-07-24 bdero@google.com [Impeller] Fix MatrixFilter multiplication ordering for subpasses. (flutter/engine#43943) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3bb43d1f9b061..cd09feb388675 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ff02fa72acce8eb9708a8b1b67b2988f7a8114ab +4fded78e5a01f6cf90f0c7f0539b824abb95122d From 9c6ee77f8801a31f58ba6d95571b74ac1109a1c8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 21:01:23 -0400 Subject: [PATCH 0354/1547] Roll Flutter Engine from 4fded78e5a01 to ceb2674e82b4 (2 revisions) (#131229) https://github.com/flutter/engine/compare/4fded78e5a01...ceb2674e82b4 2023-07-24 jonahwilliams@google.com [Impeller] presentKHR from background worker. (flutter/engine#43976) 2023-07-24 bdero@google.com Revert "[Impeller] Fix MatrixFilter multiplication ordering for subpasses." (flutter/engine#43978) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cd09feb388675..5d606e623aad9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4fded78e5a01f6cf90f0c7f0539b824abb95122d +ceb2674e82b4f0fa136c18ed37690f10adc66c93 From 0733c96e7dd67d65d706a28bf535c52151659168 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 24 Jul 2023 21:55:24 -0400 Subject: [PATCH 0355/1547] Roll Flutter Engine from ceb2674e82b4 to 9a0192d965e0 (3 revisions) (#131230) https://github.com/flutter/engine/compare/ceb2674e82b4...9a0192d965e0 2023-07-25 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from hUgYN9tEps515M1lg... to DO73K2Twew-a51xHm... (flutter/engine#43981) 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from 4554d1b35b6e to e99aea2cffef (2 revisions) (flutter/engine#43980) 2023-07-25 bdero@google.com [Impeller] Skip rect clips that do nothing. (flutter/engine#43948) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from hUgYN9tEps51 to DO73K2Twew-a If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5d606e623aad9..0c790dcbd4ae3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ceb2674e82b4f0fa136c18ed37690f10adc66c93 +9a0192d965e04de32d7624639620f82e9f526af9 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 2a104d67f6257..8a9f0a813d296 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -hUgYN9tEps515M1lgt42j4fCvfXRlF_Ls36xgAbzcmEC +DO73K2Twew-a51xHmckh0RK_5BUC2HvIkLrY8We-jKcC From 018876631f6b068a3a0b748f808aafe7c4f72661 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 03:33:22 -0400 Subject: [PATCH 0356/1547] Roll Flutter Engine from 9a0192d965e0 to 3baca2fe55c8 (1 revision) (#131241) https://github.com/flutter/engine/compare/9a0192d965e0...3baca2fe55c8 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from e99aea2cffef to 4bfaf9944a68 (2 revisions) (flutter/engine#43989) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0c790dcbd4ae3..ee6a744e7b4f1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9a0192d965e04de32d7624639620f82e9f526af9 +3baca2fe55c8b47e84722b0d901dc71195fd9ed3 From e8e10b143b4546646cd442dd7819d85ce0d706c2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 04:34:08 -0400 Subject: [PATCH 0357/1547] Roll Flutter Engine from 3baca2fe55c8 to a7a842ee9ccd (1 revision) (#131243) https://github.com/flutter/engine/compare/3baca2fe55c8...a7a842ee9ccd 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from 4bfaf9944a68 to 1d55f968ca23 (1 revision) (flutter/engine#43991) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ee6a744e7b4f1..ceafda84061de 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3baca2fe55c8b47e84722b0d901dc71195fd9ed3 +a7a842ee9ccd2ffe5d59154efe80687ecc36b909 From c8b9b15e4cd14de5ba46fafb476ac198da63fea5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 05:24:25 -0400 Subject: [PATCH 0358/1547] Roll Flutter Engine from a7a842ee9ccd to 036c58f79307 (1 revision) (#131244) https://github.com/flutter/engine/compare/a7a842ee9ccd...036c58f79307 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from 1d55f968ca23 to 81ea617ee386 (1 revision) (flutter/engine#43992) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ceafda84061de..8989525503d23 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a7a842ee9ccd2ffe5d59154efe80687ecc36b909 +036c58f79307ed8fc385825ba245fd27e17cdc97 From 9def8f6bc56b4d32975c0a5a02526bfdce7d56b7 Mon Sep 17 00:00:00 2001 From: Seiya Kokushi Date: Wed, 26 Jul 2023 00:32:20 +0900 Subject: [PATCH 0359/1547] Proposal to add barrier configs for showDatePicker, showTimePicker and showAboutDialog. (#130484) ### Overview Add `barrierDismissible`, `barrierColor` and `barrierLabel` parameters to `showDatePicker`, `showTimePicker` and `showAboutDialog` which calls `showDialog` internally. We can change these parameters with `showDialog` and Dialog widgets (like `DatePickerDialog`, `TimePickerDialog` or `AboutDialog`) directly. But, I think it is prefer to provide interfaces same as `showDialog` to keep application wide unified looks if it is used internally. Fixes #130971 --- packages/flutter/lib/src/material/about.dart | 12 +- .../flutter/lib/src/material/date_picker.dart | 26 ++- packages/flutter/lib/src/material/dialog.dart | 6 +- .../flutter/lib/src/material/time_picker.dart | 11 +- .../flutter/test/material/about_test.dart | 162 +++++++++++++++ .../test/material/date_picker_test.dart | 192 ++++++++++++++++++ .../test/material/time_picker_test.dart | 169 +++++++++++++++ 7 files changed, 564 insertions(+), 14 deletions(-) diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 280ef14b252cb..44d4e7b1cf4f8 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -170,9 +170,9 @@ class AboutListTile extends StatelessWidget { /// The licenses shown on the [LicensePage] are those returned by the /// [LicenseRegistry] API, which can be used to add more licenses to the list. /// -/// The [context], [useRootNavigator], [routeSettings] and [anchorPoint] -/// arguments are passed to [showDialog], the documentation for which discusses -/// how it is used. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator], [routeSettings] and [anchorPoint] arguments are +/// passed to [showDialog], the documentation for which discusses how it is used. void showAboutDialog({ required BuildContext context, String? applicationName, @@ -180,12 +180,18 @@ void showAboutDialog({ Widget? applicationIcon, String? applicationLegalese, List? children, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, Offset? anchorPoint, }) { showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, builder: (BuildContext context) { return AboutDialog( diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 2fb95113d0dad..93c699cc9d7f3 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -113,9 +113,10 @@ const double _kMaxTextScaleFactor = 1.3; /// [locale] and [textDirection] are non-null, [textDirection] overrides the /// direction chosen for the [locale]. /// -/// The [context], [useRootNavigator] and [routeSettings] arguments are passed to -/// [showDialog], the documentation for which discusses how it is used. [context] -/// and [useRootNavigator] must be non-null. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], +/// the documentation for which discusses how it is used. +/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -169,6 +170,9 @@ Future showDatePicker({ String? cancelText, String? confirmText, Locale? locale, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, TextDirection? textDirection, @@ -243,6 +247,9 @@ Future showDatePicker({ return showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, routeSettings: routeSettings, builder: (BuildContext context) { @@ -967,9 +974,10 @@ class _DatePickerHeader extends StatelessWidget { /// [locale] and [textDirection] are non-null, [textDirection] overrides the /// direction chosen for the [locale]. /// -/// The [context], [useRootNavigator] and [routeSettings] arguments are passed -/// to [showDialog], the documentation for which discusses how it is used. -/// [context] and [useRootNavigator] must be non-null. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], +/// the documentation for which discusses how it is used. +/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -1022,6 +1030,9 @@ Future showDateRangePicker({ String? fieldStartLabelText, String? fieldEndLabelText, Locale? locale, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, TextDirection? textDirection, @@ -1100,6 +1111,9 @@ Future showDateRangePicker({ return showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, routeSettings: routeSettings, useSafeArea: false, diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 57300b56011a4..b717e9a4a8a14 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -1404,7 +1404,7 @@ Future showDialog({ required BuildContext context, required WidgetBuilder builder, bool barrierDismissible = true, - Color? barrierColor = Colors.black54, + Color? barrierColor, String? barrierLabel, bool useSafeArea = true, bool useRootNavigator = true, @@ -1426,7 +1426,7 @@ Future showDialog({ return Navigator.of(context, rootNavigator: useRootNavigator).push(DialogRoute( context: context, builder: builder, - barrierColor: barrierColor, + barrierColor: barrierColor ?? Colors.black54, barrierDismissible: barrierDismissible, barrierLabel: barrierLabel, useSafeArea: useSafeArea, @@ -1449,7 +1449,7 @@ Future showAdaptiveDialog({ required BuildContext context, required WidgetBuilder builder, bool? barrierDismissible, - Color? barrierColor = Colors.black54, + Color? barrierColor, String? barrierLabel, bool useSafeArea = true, bool useRootNavigator = true, diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index bde201785a510..86ebd1f3dac68 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2874,8 +2874,9 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin { /// ``` /// {@end-tool} /// -/// The [context], [useRootNavigator] and [routeSettings] arguments are passed -/// to [showDialog], the documentation for which discusses how it is used. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], +/// the documentation for which discusses how it is used. /// /// The [builder] parameter can be used to wrap the dialog widget to add /// inherited widgets like [Localizations.override], [Directionality], or @@ -2954,6 +2955,9 @@ Future showTimePicker({ required BuildContext context, required TimeOfDay initialTime, TransitionBuilder? builder, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, TimePickerEntryMode initialEntryMode = TimePickerEntryMode.dial, String? cancelText, @@ -2983,6 +2987,9 @@ Future showTimePicker({ ); return showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, builder: (BuildContext context) { return builder == null ? dialog : builder(context, dialog); diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index cb7be72b992a0..ff93053939f72 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -742,6 +742,160 @@ void main() { expect(nestedObserver.licensePageCount, 0); }); + group('Barrier dismissible', () { + late AboutDialogObserver rootObserver; + + setUpAll(() { + rootObserver = AboutDialogObserver(); + }); + + testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 1); + + // Tap on the barrier. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 0); + }); + + testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + barrierDismissible: false + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 1); + + // Tap on the barrier, which shouldn't do anything this time. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 1); + }); + }); + + testWidgets('Barrier color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); + + // Dismiss the dialog. + await tester.tapAt(const Offset(10.0, 10.0)); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + barrierColor: Colors.pink, + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); + }); + + testWidgets('Barrier Label', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + barrierLabel: 'Custom Label', + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); + }); + testWidgetsWithLeakTracking('showAboutDialog uses root navigator by default', (WidgetTester tester) async { final AboutDialogObserver rootObserver = AboutDialogObserver(); final AboutDialogObserver nestedObserver = AboutDialogObserver(); @@ -1741,4 +1895,12 @@ class AboutDialogObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } + + @override + void didPop(Route route, Route? previousRoute) { + if (route is DialogRoute) { + dialogCount--; + } + super.didPop(route, previousRoute); + } } diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 3a7830806e05e..218c5f8668d9c 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -335,6 +335,190 @@ void main() { expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight); }); + group('Barrier dismissible', () { + late _DatePickerObserver rootObserver; + + setUpAll(() { + rootObserver = _DatePickerObserver(); + }); + + testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 1); + + // Tap on the barrier. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 0); + }); + + testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + barrierDismissible: false, + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 1); + + // Tap on the barrier, which shouldn't do anything this time. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 1); + }); + }); + + testWidgets('Barrier color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); + + // Dismiss the dialog. + await tester.tapAt(const Offset(10.0, 10.0)); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + barrierColor: Colors.pink, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); + }); + + testWidgets('Barrier Label', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + barrierLabel: 'Custom Label', + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); + }); + testWidgets('uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final _DatePickerObserver rootObserver = _DatePickerObserver(); final _DatePickerObserver nestedObserver = _DatePickerObserver(); @@ -2035,4 +2219,12 @@ class _DatePickerObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } + + @override + void didPop(Route route, Route? previousRoute) { + if (route is DialogRoute) { + datePickerCount--; + } + super.didPop(route, previousRoute); + } } diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 86a0f32d6b550..5f654138f9012 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -668,6 +668,167 @@ void main() { expect(tester.getBottomLeft(find.text(okString)).dx, 800 - ltrOkRight); }); + group('Barrier dismissible', () { + late PickerObserver rootObserver; + + setUpAll(() { + rootObserver = PickerObserver(); + }); + + testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 1); + + // Tap on the barrier. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 0); + }); + + testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showTimePicker( + context: context, + barrierDismissible: false, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 1); + + // Tap on the barrier, which shouldn't do anything this time. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 1); + }); + }); + + testWidgets('Barrier color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); + + // Dismiss the dialog. + await tester.tapAt(const Offset(10.0, 10.0)); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showTimePicker( + context: context, + barrierColor: Colors.pink, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); + }); + + testWidgets('Barrier Label', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showTimePicker( + context: context, + barrierLabel: 'Custom Label', + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); + }); + testWidgets('uses root navigator by default', (WidgetTester tester) async { final PickerObserver rootObserver = PickerObserver(); final PickerObserver nestedObserver = PickerObserver(); @@ -1807,6 +1968,14 @@ class PickerObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } + + @override + void didPop(Route route, Route? previousRoute) { + if (route is DialogRoute) { + pickerCount--; + } + super.didPop(route, previousRoute); + } } Future mediaQueryBoilerplate( From 62adfcf737b289f376f66bb2df0747b0b7ce8916 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 25 Jul 2023 18:37:17 +0300 Subject: [PATCH 0360/1547] Fix `RawChip` doesn't use `ChipTheme.showCheckmark` value (#131257) fixes [`RawChip` doesn't use `ChipThemeData.showCheckmark` value](https://github.com/flutter/flutter/issues/119163) ### Description `RawChip.showCheckmark` is nullable yet the constructor falsely assigns a default which breaks `ChipTheme` support. This PR removes the falsely assigned default value. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(useMaterial3: true, chipTheme: const ChipThemeData( showCheckmark: false, ) ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sample'), ), body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ const RawChip( selected: true, label: Text('RawChip'), ), FilterChip( selected: true, label: const Text('RawChip'), onSelected: (bool value) { }, ), ], ), ), ); } } ```
### Before ![before](https://github.com/flutter/flutter/assets/48603081/c8050c28-d988-4c72-8e0a-6455aa02d119) ### After ![after](https://github.com/flutter/flutter/assets/48603081/d5e83e81-6c12-4594-a2fd-8f113d6c9b54) --- packages/flutter/lib/src/material/chip.dart | 2 +- .../test/material/chip_theme_test.dart | 64 ++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index adbe71273708b..3e1eb6d7bacf1 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -748,7 +748,7 @@ class RawChip extends StatefulWidget this.surfaceTintColor, this.iconTheme, this.selectedShadowColor, - this.showCheckmark = true, + this.showCheckmark, this.checkmarkColor, this.avatarBorder = const CircleBorder(), @Deprecated( diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 5da0b0a428fdf..3cd47209e63da 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -71,6 +71,7 @@ void main() { expect(themeData.brightness, null); expect(themeData.elevation, null); expect(themeData.pressElevation, null); + expect(themeData.iconTheme, null); }); testWidgetsWithLeakTracking('Default ChipThemeData debugFillProperties', (WidgetTester tester) async { @@ -108,6 +109,7 @@ void main() { brightness: Brightness.dark, elevation: 5, pressElevation: 6, + iconTheme: IconThemeData(color: Color(0xffffff10)), ).debugFillProperties(builder); final List description = builder.properties @@ -115,7 +117,7 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect(description, [ + expect(description, equalsIgnoringHashCodes([ 'color: MaterialStatePropertyAll(Color(0xfffffff0))', 'backgroundColor: Color(0xfffffff1)', 'deleteIconColor: Color(0xfffffff2)', @@ -136,7 +138,8 @@ void main() { 'brightness: dark', 'elevation: 5.0', 'pressElevation: 6.0', - ]); + 'iconTheme: IconThemeData#00000(color: Color(0xffffff10))' + ])); }); testWidgetsWithLeakTracking('Chip uses ThemeData chip theme', (WidgetTester tester) async { @@ -868,6 +871,63 @@ void main() { // Enabled & selected chip should have the provided selectedColor. expect(getMaterialBox(tester), paints..rrect(color: chipTheme.selectedColor)); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/119163. + testWidgetsWithLeakTracking('RawChip respects checkmark properties from ChipTheme', (WidgetTester tester) async { + Widget buildRawChip({ChipThemeData? chipTheme}) { + return MaterialApp( + theme: ThemeData.light(useMaterial3: false).copyWith( + chipTheme: chipTheme, + ), + home: Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: RawChip( + selected: true, + label: const SizedBox(width: 100, height: 100), + onSelected: (bool newValue) { }, + ), + ), + ), + ), + ); + } + + // Test that the checkmark is painted. + await tester.pumpWidget(buildRawChip( + chipTheme: const ChipThemeData( + checkmarkColor: Color(0xffff0000), + ), + )); + + RenderBox materialBox = getMaterialBox(tester); + expect( + materialBox, + paints..path( + color: const Color(0xffff0000), + style: PaintingStyle.stroke, + ), + ); + + // Test that the checkmark is not painted when ChipThemeData.showCheckmark is false. + await tester.pumpWidget(buildRawChip( + chipTheme: const ChipThemeData( + showCheckmark: false, + checkmarkColor: Color(0xffff0000), + ), + )); + await tester.pumpAndSettle(); + + materialBox = getMaterialBox(tester); + expect( + materialBox, + isNot(paints..path( + color: const Color(0xffff0000), + style: PaintingStyle.stroke, + )), + ); + }); } class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder { From 2da3bdd4724b1ec5f1a81d07e5a211bc99e2c126 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 11:37:19 -0400 Subject: [PATCH 0361/1547] Roll Flutter Engine from 036c58f79307 to 0a5c6cdd5d02 (1 revision) (#131256) https://github.com/flutter/engine/compare/036c58f79307...0a5c6cdd5d02 2023-07-25 skia-flutter-autoroll@skia.org Roll ANGLE from 2d999f744809 to 1b17c91e4231 (1 revision) (flutter/engine#43993) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8989525503d23..3e99a6e1260c8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -036c58f79307ed8fc385825ba245fd27e17cdc97 +0a5c6cdd5d02f38e89b555b1b9a4f01d9afae5f1 From 300c5d828532cad079c69fada84313d09de9d12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Tue, 25 Jul 2023 11:20:31 -0700 Subject: [PATCH 0362/1547] Revert "Proposal to add barrier configs for showDatePicker, showTimePicker and showAboutDialog." (#131278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts flutter/flutter#130484. /cc @ronnnnn Example failure: https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20framework_tests_libraries/12185/overview
Failure logs... ``` 04:51 +5379 ~18: /Volumes/Work/s/w/ir/x/w/flutter/packages/flutter/test/material/about_test.dart: Barrier dismissible Barrier is dismissible with default parameter ══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ The following TestFailure was thrown running a test: Expected: <1> Actual: <2> When the exception was thrown, this was the stack: #4 main.. (file:///Volumes/Work/s/w/ir/x/w/flutter/packages/flutter/test/material/about_test.dart:776:7) #5 testWidgets.. (package:flutter_test/src/widget_tester.dart:165:15) #6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1008:5) (elided one frame from package:stack_trace) This was caught by the test expectation on the following line: file:///Volumes/Work/s/w/ir/x/w/flutter/packages/flutter/test/material/about_test.dart line 776 The test description was: Barrier is dismissible with default parameter ════════════════════════════════════════════════════════════════════════════════════════════════════ 04:51 +5379 ~18 -1: /Volumes/Work/s/w/ir/x/w/flutter/packages/flutter/test/material/about_test.dart: Barrier dismissible Barrier is dismissible with default parameter [E] Test failed. See exception logs above. The test description was: Barrier is dismissible with default parameter To run this test again: /Volumes/Work/s/w/ir/x/w/flutter/bin/cache/dart-sdk/bin/dart test /Volumes/Work/s/w/ir/x/w/flutter/packages/flutter/test/material/about_test.dart -p vm --plain-name 'Barrier dismissible Barrier is dismissible with default parameter' ```
--- packages/flutter/lib/src/material/about.dart | 12 +- .../flutter/lib/src/material/date_picker.dart | 26 +-- packages/flutter/lib/src/material/dialog.dart | 6 +- .../flutter/lib/src/material/time_picker.dart | 11 +- .../flutter/test/material/about_test.dart | 162 --------------- .../test/material/date_picker_test.dart | 192 ------------------ .../test/material/time_picker_test.dart | 169 --------------- 7 files changed, 14 insertions(+), 564 deletions(-) diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 44d4e7b1cf4f8..280ef14b252cb 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -170,9 +170,9 @@ class AboutListTile extends StatelessWidget { /// The licenses shown on the [LicensePage] are those returned by the /// [LicenseRegistry] API, which can be used to add more licenses to the list. /// -/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], -/// [useRootNavigator], [routeSettings] and [anchorPoint] arguments are -/// passed to [showDialog], the documentation for which discusses how it is used. +/// The [context], [useRootNavigator], [routeSettings] and [anchorPoint] +/// arguments are passed to [showDialog], the documentation for which discusses +/// how it is used. void showAboutDialog({ required BuildContext context, String? applicationName, @@ -180,18 +180,12 @@ void showAboutDialog({ Widget? applicationIcon, String? applicationLegalese, List? children, - bool barrierDismissible = true, - Color? barrierColor, - String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, Offset? anchorPoint, }) { showDialog( context: context, - barrierDismissible: barrierDismissible, - barrierColor: barrierColor, - barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, builder: (BuildContext context) { return AboutDialog( diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 93c699cc9d7f3..2fb95113d0dad 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -113,10 +113,9 @@ const double _kMaxTextScaleFactor = 1.3; /// [locale] and [textDirection] are non-null, [textDirection] overrides the /// direction chosen for the [locale]. /// -/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], -/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], -/// the documentation for which discusses how it is used. -/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. +/// The [context], [useRootNavigator] and [routeSettings] arguments are passed to +/// [showDialog], the documentation for which discusses how it is used. [context] +/// and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -170,9 +169,6 @@ Future showDatePicker({ String? cancelText, String? confirmText, Locale? locale, - bool barrierDismissible = true, - Color? barrierColor, - String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, TextDirection? textDirection, @@ -247,9 +243,6 @@ Future showDatePicker({ return showDialog( context: context, - barrierDismissible: barrierDismissible, - barrierColor: barrierColor, - barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, routeSettings: routeSettings, builder: (BuildContext context) { @@ -974,10 +967,9 @@ class _DatePickerHeader extends StatelessWidget { /// [locale] and [textDirection] are non-null, [textDirection] overrides the /// direction chosen for the [locale]. /// -/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], -/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], -/// the documentation for which discusses how it is used. -/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. +/// The [context], [useRootNavigator] and [routeSettings] arguments are passed +/// to [showDialog], the documentation for which discusses how it is used. +/// [context] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -1030,9 +1022,6 @@ Future showDateRangePicker({ String? fieldStartLabelText, String? fieldEndLabelText, Locale? locale, - bool barrierDismissible = true, - Color? barrierColor, - String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, TextDirection? textDirection, @@ -1111,9 +1100,6 @@ Future showDateRangePicker({ return showDialog( context: context, - barrierDismissible: barrierDismissible, - barrierColor: barrierColor, - barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, routeSettings: routeSettings, useSafeArea: false, diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index b717e9a4a8a14..57300b56011a4 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -1404,7 +1404,7 @@ Future showDialog({ required BuildContext context, required WidgetBuilder builder, bool barrierDismissible = true, - Color? barrierColor, + Color? barrierColor = Colors.black54, String? barrierLabel, bool useSafeArea = true, bool useRootNavigator = true, @@ -1426,7 +1426,7 @@ Future showDialog({ return Navigator.of(context, rootNavigator: useRootNavigator).push(DialogRoute( context: context, builder: builder, - barrierColor: barrierColor ?? Colors.black54, + barrierColor: barrierColor, barrierDismissible: barrierDismissible, barrierLabel: barrierLabel, useSafeArea: useSafeArea, @@ -1449,7 +1449,7 @@ Future showAdaptiveDialog({ required BuildContext context, required WidgetBuilder builder, bool? barrierDismissible, - Color? barrierColor, + Color? barrierColor = Colors.black54, String? barrierLabel, bool useSafeArea = true, bool useRootNavigator = true, diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 86ebd1f3dac68..bde201785a510 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2874,9 +2874,8 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin { /// ``` /// {@end-tool} /// -/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], -/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], -/// the documentation for which discusses how it is used. +/// The [context], [useRootNavigator] and [routeSettings] arguments are passed +/// to [showDialog], the documentation for which discusses how it is used. /// /// The [builder] parameter can be used to wrap the dialog widget to add /// inherited widgets like [Localizations.override], [Directionality], or @@ -2955,9 +2954,6 @@ Future showTimePicker({ required BuildContext context, required TimeOfDay initialTime, TransitionBuilder? builder, - bool barrierDismissible = true, - Color? barrierColor, - String? barrierLabel, bool useRootNavigator = true, TimePickerEntryMode initialEntryMode = TimePickerEntryMode.dial, String? cancelText, @@ -2987,9 +2983,6 @@ Future showTimePicker({ ); return showDialog( context: context, - barrierDismissible: barrierDismissible, - barrierColor: barrierColor, - barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, builder: (BuildContext context) { return builder == null ? dialog : builder(context, dialog); diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index ff93053939f72..cb7be72b992a0 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -742,160 +742,6 @@ void main() { expect(nestedObserver.licensePageCount, 0); }); - group('Barrier dismissible', () { - late AboutDialogObserver rootObserver; - - setUpAll(() { - rootObserver = AboutDialogObserver(); - }); - - testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [rootObserver], - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showAboutDialog( - context: context, - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(rootObserver.dialogCount, 1); - - // Tap on the barrier. - await tester.tapAt(const Offset(10.0, 10.0)); - await tester.pumpAndSettle(); - expect(rootObserver.dialogCount, 0); - }); - - testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [rootObserver], - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showAboutDialog( - context: context, - barrierDismissible: false - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(rootObserver.dialogCount, 1); - - // Tap on the barrier, which shouldn't do anything this time. - await tester.tapAt(const Offset(10.0, 10.0)); - await tester.pumpAndSettle(); - expect(rootObserver.dialogCount, 1); - }); - }); - - testWidgets('Barrier color', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showAboutDialog( - context: context, - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); - - // Dismiss the dialog. - await tester.tapAt(const Offset(10.0, 10.0)); - - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showAboutDialog( - context: context, - barrierColor: Colors.pink, - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); - }); - - testWidgets('Barrier Label', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showAboutDialog( - context: context, - barrierLabel: 'Custom Label', - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); - }); - testWidgetsWithLeakTracking('showAboutDialog uses root navigator by default', (WidgetTester tester) async { final AboutDialogObserver rootObserver = AboutDialogObserver(); final AboutDialogObserver nestedObserver = AboutDialogObserver(); @@ -1895,12 +1741,4 @@ class AboutDialogObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } - - @override - void didPop(Route route, Route? previousRoute) { - if (route is DialogRoute) { - dialogCount--; - } - super.didPop(route, previousRoute); - } } diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 218c5f8668d9c..3a7830806e05e 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -335,190 +335,6 @@ void main() { expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight); }); - group('Barrier dismissible', () { - late _DatePickerObserver rootObserver; - - setUpAll(() { - rootObserver = _DatePickerObserver(); - }); - - testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [rootObserver], - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2018), - lastDate: DateTime(2030), - builder: (BuildContext context, - Widget? child) => const SizedBox(), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(rootObserver.datePickerCount, 1); - - // Tap on the barrier. - await tester.tapAt(const Offset(10.0, 10.0)); - await tester.pumpAndSettle(); - expect(rootObserver.datePickerCount, 0); - }); - - testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [rootObserver], - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2018), - lastDate: DateTime(2030), - barrierDismissible: false, - builder: (BuildContext context, - Widget? child) => const SizedBox(), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(rootObserver.datePickerCount, 1); - - // Tap on the barrier, which shouldn't do anything this time. - await tester.tapAt(const Offset(10.0, 10.0)); - await tester.pumpAndSettle(); - expect(rootObserver.datePickerCount, 1); - }); - }); - - testWidgets('Barrier color', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2018), - lastDate: DateTime(2030), - builder: (BuildContext context, - Widget? child) => const SizedBox(), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); - - // Dismiss the dialog. - await tester.tapAt(const Offset(10.0, 10.0)); - - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showDatePicker( - context: context, - barrierColor: Colors.pink, - initialDate: DateTime.now(), - firstDate: DateTime(2018), - lastDate: DateTime(2030), - builder: (BuildContext context, - Widget? child) => const SizedBox(), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); - }); - - testWidgets('Barrier Label', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showDatePicker( - context: context, - barrierLabel: 'Custom Label', - initialDate: DateTime.now(), - firstDate: DateTime(2018), - lastDate: DateTime(2030), - builder: (BuildContext context, - Widget? child) => const SizedBox(), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); - }); - testWidgets('uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final _DatePickerObserver rootObserver = _DatePickerObserver(); final _DatePickerObserver nestedObserver = _DatePickerObserver(); @@ -2219,12 +2035,4 @@ class _DatePickerObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } - - @override - void didPop(Route route, Route? previousRoute) { - if (route is DialogRoute) { - datePickerCount--; - } - super.didPop(route, previousRoute); - } } diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 5f654138f9012..86a0f32d6b550 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -668,167 +668,6 @@ void main() { expect(tester.getBottomLeft(find.text(okString)).dx, 800 - ltrOkRight); }); - group('Barrier dismissible', () { - late PickerObserver rootObserver; - - setUpAll(() { - rootObserver = PickerObserver(); - }); - - testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [rootObserver], - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showTimePicker( - context: context, - initialTime: const TimeOfDay(hour: 7, minute: 0), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(rootObserver.pickerCount, 1); - - // Tap on the barrier. - await tester.tapAt(const Offset(10.0, 10.0)); - await tester.pumpAndSettle(); - expect(rootObserver.pickerCount, 0); - }); - - testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - navigatorObservers: [rootObserver], - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => - showTimePicker( - context: context, - barrierDismissible: false, - initialTime: const TimeOfDay(hour: 7, minute: 0), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(rootObserver.pickerCount, 1); - - // Tap on the barrier, which shouldn't do anything this time. - await tester.tapAt(const Offset(10.0, 10.0)); - await tester.pumpAndSettle(); - expect(rootObserver.pickerCount, 1); - }); - }); - - testWidgets('Barrier color', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showTimePicker( - context: context, - initialTime: const TimeOfDay(hour: 7, minute: 0), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); - - // Dismiss the dialog. - await tester.tapAt(const Offset(10.0, 10.0)); - - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showTimePicker( - context: context, - barrierColor: Colors.pink, - initialTime: const TimeOfDay(hour: 7, minute: 0), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); - }); - - testWidgets('Barrier Label', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Center( - child: Builder( - builder: (BuildContext context) { - return ElevatedButton( - child: const Text('X'), - onPressed: () => showTimePicker( - context: context, - barrierLabel: 'Custom Label', - initialTime: const TimeOfDay(hour: 7, minute: 0), - ), - ); - }, - ), - ), - ), - ), - ); - - // Open the dialog. - await tester.tap(find.byType(ElevatedButton)); - await tester.pumpAndSettle(); - expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); - }); - testWidgets('uses root navigator by default', (WidgetTester tester) async { final PickerObserver rootObserver = PickerObserver(); final PickerObserver nestedObserver = PickerObserver(); @@ -1968,14 +1807,6 @@ class PickerObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } - - @override - void didPop(Route route, Route? previousRoute) { - if (route is DialogRoute) { - pickerCount--; - } - super.didPop(route, previousRoute); - } } Future mediaQueryBoilerplate( From 9f374f12ea890d31f81b3373face5f99cf88e8bc Mon Sep 17 00:00:00 2001 From: Alex Li Date: Wed, 26 Jul 2023 02:24:43 +0800 Subject: [PATCH 0363/1547] =?UTF-8?q?=F0=9F=9A=80=20Expose=20`scrollContro?= =?UTF-8?q?lDisabledMaxHeightRatio`=20to=20the=20modal=20bottom=20sheet=20?= =?UTF-8?q?(#129688)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adding the `scrollControlDisabledMaxHeightRatio` parameter for modal bottom sheet widgets, and using the default value `9.0 / 16.0` to avoid breaking. Resolves #129690. --- .../lib/src/material/bottom_sheet.dart | 49 +++++++++++++---- .../test/material/bottom_sheet_test.dart | 54 ++++++++++++++++++- 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index c59afd7889124..f84cfe9ae1ffd 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -26,6 +26,7 @@ const Duration _bottomSheetExitDuration = Duration(milliseconds: 200); const Curve _modalBottomSheetCurve = decelerateEasing; const double _minFlingVelocity = 700.0; const double _closeProgressThreshold = 0.5; +const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0; /// A callback for when the user begins dragging the bottom sheet. /// @@ -471,24 +472,26 @@ class _DragHandle extends StatelessWidget { } class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget { - const _BottomSheetLayoutWithSizeListener({ + required this.onChildSizeChanged, required this.animationValue, required this.isScrollControlled, - required this.onChildSizeChanged, + required this.scrollControlDisabledMaxHeightRatio, super.child, }); + final _SizeChangeCallback onChildSizeChanged; final double animationValue; final bool isScrollControlled; - final _SizeChangeCallback onChildSizeChanged; + final double scrollControlDisabledMaxHeightRatio; @override _RenderBottomSheetLayoutWithSizeListener createRenderObject(BuildContext context) { return _RenderBottomSheetLayoutWithSizeListener( + onChildSizeChanged: onChildSizeChanged, animationValue: animationValue, isScrollControlled: isScrollControlled, - onChildSizeChanged: onChildSizeChanged, + scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio, ); } @@ -497,6 +500,7 @@ class _BottomSheetLayoutWithSizeListener extends SingleChildRenderObjectWidget { renderObject.onChildSizeChanged = onChildSizeChanged; renderObject.animationValue = animationValue; renderObject.isScrollControlled = isScrollControlled; + renderObject.scrollControlDisabledMaxHeightRatio = scrollControlDisabledMaxHeightRatio; } } @@ -506,9 +510,11 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { required _SizeChangeCallback onChildSizeChanged, required double animationValue, required bool isScrollControlled, - }) : _animationValue = animationValue, + required double scrollControlDisabledMaxHeightRatio, + }) : _onChildSizeChanged = onChildSizeChanged, + _animationValue = animationValue, _isScrollControlled = isScrollControlled, - _onChildSizeChanged = onChildSizeChanged, + _scrollControlDisabledMaxHeightRatio = scrollControlDisabledMaxHeightRatio, super(child); Size _lastSize = Size.zero; @@ -546,6 +552,17 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { markNeedsLayout(); } + double get scrollControlDisabledMaxHeightRatio => _scrollControlDisabledMaxHeightRatio; + double _scrollControlDisabledMaxHeightRatio; + set scrollControlDisabledMaxHeightRatio(double newValue) { + if (_scrollControlDisabledMaxHeightRatio == newValue) { + return; + } + + _scrollControlDisabledMaxHeightRatio = newValue; + markNeedsLayout(); + } + Size _getSize(BoxConstraints constraints) { return constraints.constrain(constraints.biggest); } @@ -591,13 +608,13 @@ class _RenderBottomSheetLayoutWithSizeListener extends RenderShiftedBox { return _getSize(constraints); } - BoxConstraints _getConstraintsForChild(BoxConstraints constraints) { + BoxConstraints _getConstraintsForChild(BoxConstraints constraints) { return BoxConstraints( minWidth: constraints.maxWidth, maxWidth: constraints.maxWidth, maxHeight: isScrollControlled - ? constraints.maxHeight - : constraints.maxHeight * 9.0 / 16.0, + ? constraints.maxHeight + : constraints.maxHeight * scrollControlDisabledMaxHeightRatio, ); } @@ -634,12 +651,14 @@ class _ModalBottomSheet extends StatefulWidget { this.clipBehavior, this.constraints, this.isScrollControlled = false, + this.scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio, this.enableDrag = true, this.showDragHandle = false, }); final ModalBottomSheetRoute route; final bool isScrollControlled; + final double scrollControlDisabledMaxHeightRatio; final Color? backgroundColor; final double? elevation; final ShapeBorder? shape; @@ -730,6 +749,7 @@ class _ModalBottomSheetState extends State<_ModalBottomSheet> { }, animationValue: animationValue, isScrollControlled: widget.isScrollControlled, + scrollControlDisabledMaxHeightRatio: widget.scrollControlDisabledMaxHeightRatio, child: child, ), ), @@ -815,6 +835,7 @@ class ModalBottomSheetRoute extends PopupRoute { this.enableDrag = true, this.showDragHandle, required this.isScrollControlled, + this.scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio, super.settings, this.transitionAnimationController, this.anchorPoint, @@ -842,6 +863,13 @@ class ModalBottomSheetRoute extends PopupRoute { /// to have the bottom sheet be draggable. final bool isScrollControlled; + /// The max height constraint ratio for the bottom sheet + /// when [isScrollControlled] set to false, + /// no ratio will be applied when [isScrollControlled] set to true. + /// + /// Defaults to 9 / 16. + final double scrollControlDisabledMaxHeightRatio; + /// The bottom sheet's background color. /// /// Defines the bottom sheet's [Material.color]. @@ -1026,6 +1054,7 @@ class ModalBottomSheetRoute extends PopupRoute { clipBehavior: clipBehavior, constraints: constraints, isScrollControlled: isScrollControlled, + scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio, enableDrag: enableDrag, showDragHandle: showDragHandle ?? (enableDrag && (sheetTheme.showDragHandle ?? false)), ); @@ -1192,6 +1221,7 @@ Future showModalBottomSheet({ BoxConstraints? constraints, Color? barrierColor, bool isScrollControlled = false, + double scrollControlDisabledMaxHeightRatio = _defaultScrollControlDisabledMaxHeightRatio, bool useRootNavigator = false, bool isDismissible = true, bool enableDrag = true, @@ -1210,6 +1240,7 @@ Future showModalBottomSheet({ builder: builder, capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), isScrollControlled: isScrollControlled, + scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio, barrierLabel: barrierLabel ?? localizations.scrimLabel, barrierOnTapHint: localizations.scrimOnTapHint(localizations.bottomSheetLabel), backgroundColor: backgroundColor, diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index b6e5db84011c8..49695c859fa29 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -1789,7 +1789,7 @@ void main() { }); group('constraints', () { - testWidgets('default constraints are max width 640 in material 3', (WidgetTester tester) async { + testWidgets('default constraints are max width 640 in material 3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.light(useMaterial3: true), @@ -2045,6 +2045,58 @@ void main() { ); }); + group('scrollControlDisabledMaxHeightRatio', () { + Future test( + WidgetTester tester, + bool isScrollControlled, + double scrollControlDisabledMaxHeightRatio, + ) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder(builder: (BuildContext context) { + return Center( + child: ElevatedButton( + child: const Text('Press me'), + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: isScrollControlled, + scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio, + builder: (BuildContext context) => const SizedBox.expand( + child: Text('BottomSheet'), + ), + ); + }, + ), + ); + }), + ), + ), + ); + await tester.tap(find.text('Press me')); + await tester.pumpAndSettle(); + expect( + tester.getRect(find.text('BottomSheet')), + Rect.fromLTRB( + 80, + 600 * (isScrollControlled ? 0 : (1 - scrollControlDisabledMaxHeightRatio)), + 720, + 600, + ), + ); + } + + testWidgets('works at 9 / 16', (WidgetTester tester) { + return test(tester, false, 9.0 / 16.0); + }); + testWidgets('works at 8 / 16', (WidgetTester tester) { + return test(tester, false, 8.0 / 16.0); + }); + testWidgets('works at isScrollControlled', (WidgetTester tester) { + return test(tester, true, 8.0 / 16.0); + }); + }); }); group('showModalBottomSheet modalBarrierDismissLabel', () { From 35a6fc8acf7bb97ae50e16dd3d883cb09e3d244f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 15:49:24 -0400 Subject: [PATCH 0364/1547] Roll Flutter Engine from 0a5c6cdd5d02 to f5fbfa859b63 (8 revisions) (#131283) https://github.com/flutter/engine/compare/0a5c6cdd5d02...f5fbfa859b63 2023-07-25 jonahwilliams@google.com [Impeller] round scale for glyph atlas cache to 2 decimal places. (flutter/engine#43752) 2023-07-25 skia-flutter-autoroll@skia.org Roll ANGLE from 7ae6458b664f to 2d5fb09d7f0a (2 revisions) (flutter/engine#44002) 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from 04ab62b4f8c9 to eb5b5bc4fb86 (2 revisions) (flutter/engine#44001) 2023-07-25 skia-flutter-autoroll@skia.org Roll ANGLE from e8c8c5651223 to 7ae6458b664f (1 revision) (flutter/engine#43999) 2023-07-25 bdero@google.com [Impeller] Use basis of effect transform in MatrixFilter. (flutter/engine#43990) 2023-07-25 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from DO73K2Twew-a51xHm... to 0StTjIqUxGkc3nOWT... (flutter/engine#43996) 2023-07-25 skia-flutter-autoroll@skia.org Roll ANGLE from 1b17c91e4231 to e8c8c5651223 (2 revisions) (flutter/engine#43997) 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from 81ea617ee386 to 04ab62b4f8c9 (1 revision) (flutter/engine#43994) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from DO73K2Twew-a to 0StTjIqUxGkc If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3e99a6e1260c8..3961aa66a3913 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0a5c6cdd5d02f38e89b555b1b9a4f01d9afae5f1 +f5fbfa859b63fc6c6d9023006b5441e08870774a diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 8a9f0a813d296..3bca4f8e4186b 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -DO73K2Twew-a51xHmckh0RK_5BUC2HvIkLrY8We-jKcC +0StTjIqUxGkc3nOWTPdEl-TR153yqChYQ6s1W4_EA-cC From fb7a763c640d247d090cbb373e4b3a0459ac171b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 15:51:05 -0400 Subject: [PATCH 0365/1547] Roll Packages from 8028cafa1f0c to 406eac1ad976 (4 revisions) (#131285) https://github.com/flutter/packages/compare/8028cafa1f0c...406eac1ad976 2023-07-25 engine-flutter-autoroll@skia.org Roll Flutter from d7ed5dc2e212 to 9def8f6bc56b (21 revisions) (flutter/packages#4561) 2023-07-25 10687576+bparrishMines@users.noreply.github.com [webview_flutter_android][webview_flutter_wkwebview] Fixes bug where `PlatformWebViewWidget` doesn't rebuild when the controller changes (flutter/packages#4533) 2023-07-24 stuartmorgan@google.com [ci] Enable Android emulator-based tests (flutter/packages#4494) 2023-07-24 rexios@rexios.dev [google_maps_flutter_web] Options to disable tilt controls and configure gesture handling (flutter/packages#3258) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 549edcac752fe..0a2f19f4665ba 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -8028cafa1f0c1bd1f7f678c455f48e64bc8a4e15 +406eac1ad976bf9317422b1538615e03d057eb7b From 0a092daa22217c98cb4e3da8241f48e793d5df23 Mon Sep 17 00:00:00 2001 From: Sabin Neupane <61322712+sabin26@users.noreply.github.com> Date: Wed, 26 Jul 2023 04:34:45 +0545 Subject: [PATCH 0366/1547] Add Sabin Neupane to AUTHORS (#131237) Reference: [author:sabin26](https://github.com/flutter/flutter/issues?q=author%3Asabin26) --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index f557468d0dbf0..974b9c9705715 100644 --- a/AUTHORS +++ b/AUTHORS @@ -116,3 +116,4 @@ Mike Rydstrom Harish Anbalagan Kim Jiun LinXunFeng +Sabin Neupane From 147e12d13d2b63e8c7bd9cd2561372e9ab157a0d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 18:49:47 -0400 Subject: [PATCH 0367/1547] Roll Flutter Engine from f5fbfa859b63 to 3fff7316dc8d (4 revisions) (#131286) https://github.com/flutter/engine/compare/f5fbfa859b63...3fff7316dc8d 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from 7cec4e4e6f6e to 12d41b6f66ed (2 revisions) (flutter/engine#44008) 2023-07-25 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 8662af7d9aa3 to 61ab5422fb7b (12 revisions) (flutter/engine#44007) 2023-07-25 skia-flutter-autoroll@skia.org Roll Skia from eb5b5bc4fb86 to 7cec4e4e6f6e (1 revision) (flutter/engine#44003) 2023-07-25 kjlubick@users.noreply.github.com Reland "Remove more calls to SkCanvas::flush() and SkSurface::flush()" (flutter/engine#43965) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3961aa66a3913..80ad5912355f1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f5fbfa859b63fc6c6d9023006b5441e08870774a +3fff7316dc8dd8e8127e12e3f329c17cfa3da589 From eb4891226e23f0f15c4a60309ce9539020957fc2 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Wed, 26 Jul 2023 00:56:49 +0200 Subject: [PATCH 0368/1547] Update BottomAppBar and BottomAppBarTheme tests for M3 (#130983) This PR updates `BottomAppBar` and `BottomAppBarTheme` tests for M3 migration. More info in https://github.com/flutter/flutter/issues/127064 - Some tests are M2 or M3 only. - Added several M3 tests. - One golden change. --- .../test/material/bottom_app_bar_test.dart | 191 +++++++++++++----- .../material/bottom_app_bar_theme_test.dart | 42 ++-- 2 files changed, 166 insertions(+), 67 deletions(-) diff --git a/packages/flutter/test/material/bottom_app_bar_test.dart b/packages/flutter/test/material/bottom_app_bar_test.dart index fe90810ac0d99..d02ee48eb8f9c 100644 --- a/packages/flutter/test/material/bottom_app_bar_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_test.dart @@ -15,7 +15,7 @@ import '../foundation/leak_tracking.dart'; import '../rendering/mock_canvas.dart'; void main() { - testWidgetsWithLeakTracking('shadow effect is not doubled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Shadow effect is not doubled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123064 debugDisableShadows = false; @@ -41,7 +41,7 @@ void main() { debugDisableShadows = true; }); - testWidgetsWithLeakTracking('only one layer with `color` is painted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Only one layer with `color` is painted', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/122667 const Color bottomAppBarColor = Colors.black45; @@ -51,7 +51,6 @@ void main() { home: const Scaffold( bottomNavigationBar: BottomAppBar( color: bottomAppBarColor, - // Avoid getting a surface tint color, to keep the color check below simple elevation: 0, ), @@ -80,7 +79,7 @@ void main() { } }); - testWidgetsWithLeakTracking('no overlap with floating action button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No overlap with floating action button', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -111,7 +110,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('custom shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Custom shape', (WidgetTester tester) async { final Key key = UniqueKey(); Future pump(FloatingActionButtonLocation location) async { await tester.pumpWidget( @@ -145,53 +144,65 @@ void main() { await pump(FloatingActionButtonLocation.endDocked); await expectLater( find.byKey(key), - matchesGoldenFile('bottom_app_bar.custom_shape.1.png'), + matchesGoldenFile('m2_bottom_app_bar.custom_shape.1.png'), ); await pump(FloatingActionButtonLocation.centerDocked); await tester.pumpAndSettle(); await expectLater( find.byKey(key), - matchesGoldenFile('bottom_app_bar.custom_shape.2.png'), + matchesGoldenFile('m2_bottom_app_bar.custom_shape.2.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44572 - testWidgetsWithLeakTracking('Custom Padding', (WidgetTester tester) async { - const EdgeInsets customPadding = EdgeInsets.all(10); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), - home: Builder( - builder: (BuildContext context) { - return const Scaffold( - body: Align( - alignment: Alignment.bottomCenter, - child: BottomAppBar( - padding: customPadding, - child: ColoredBox( - color: Colors.green, - child: SizedBox(width: 300, height: 60), + testWidgetsWithLeakTracking('Material3 - Custom shape', (WidgetTester tester) async { + final Key key = UniqueKey(); + Future pump(FloatingActionButtonLocation location) async { + await tester.pumpWidget( + SizedBox( + width: 200, + height: 200, + child: RepaintBoundary( + key: key, + child: MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + floatingActionButton: FloatingActionButton( + onPressed: () { }, + ), + floatingActionButtonLocation: location, + bottomNavigationBar: const BottomAppBar( + shape: AutomaticNotchedShape( + BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(50.0))), + ContinuousRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30.0))), ), + notchMargin: 10.0, + color: Colors.green, + child: SizedBox(height: 100.0), ), ), - ); - }, + ), + ), ), - ), + ); + } + await pump(FloatingActionButtonLocation.endDocked); + await expectLater( + find.byKey(key), + matchesGoldenFile('m3_bottom_app_bar.custom_shape.1.png'), ); + await pump(FloatingActionButtonLocation.centerDocked); + await tester.pumpAndSettle(); + await expectLater( + find.byKey(key), + matchesGoldenFile('m3_bottom_app_bar.custom_shape.2.png'), + ); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44572 - final BottomAppBar bottomAppBar = tester.widget(find.byType(BottomAppBar)); - expect(bottomAppBar.padding, customPadding); - final Rect babRect = tester.getRect(find.byType(BottomAppBar)); - final Rect childRect = tester.getRect(find.byType(ColoredBox)); - expect(childRect, const Rect.fromLTRB(250, 530, 550, 590)); - expect(babRect, const Rect.fromLTRB(240, 520, 560, 600)); - }); - - testWidgetsWithLeakTracking('Custom Padding in Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Padding', (WidgetTester tester) async { const EdgeInsets customPadding = EdgeInsets.all(10); await tester.pumpWidget( MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true), + theme: ThemeData.from(colorScheme: const ColorScheme.light()), home: Builder( builder: (BuildContext context) { return const Scaffold( @@ -219,7 +230,7 @@ void main() { expect(babRect, const Rect.fromLTRB(240, 520, 560, 600)); }); - testWidgetsWithLeakTracking('color defaults to Theme.bottomAppBarColor in M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Color defaults to Theme.bottomAppBarColor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -245,7 +256,7 @@ void main() { expect(physicalShape.color, const Color(0xffffff00)); }); - testWidgetsWithLeakTracking('color overrides theme color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Color overrides theme color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -276,11 +287,12 @@ void main() { }); - testWidgetsWithLeakTracking('color overrides theme color with Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Color overrides theme color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.light(useMaterial3: true).copyWith( - bottomAppBarColor: const Color(0xffffff00)), + bottomAppBarColor: const Color(0xffffff00), + ), home: Builder( builder: (BuildContext context) { return const Scaffold( @@ -303,7 +315,7 @@ void main() { expect(physicalShape.color, const Color(0xff0000ff)); }); - testWidgetsWithLeakTracking('Shadow color is transparent in Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Shadow color is transparent', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true, @@ -325,7 +337,7 @@ void main() { expect(physicalShape.shadowColor, Colors.transparent); }); - testWidgetsWithLeakTracking('dark theme applies an elevation overlay color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Dark theme applies an elevation overlay color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.from(useMaterial3: false, colorScheme: const ColorScheme.dark()), @@ -343,6 +355,26 @@ void main() { expect(physicalShape.color, const Color(0xFF2D2D2D)); }); + testWidgetsWithLeakTracking('Material3 - Dark theme applies an elevation overlay color', (WidgetTester tester) async { + const ColorScheme colorScheme = ColorScheme.dark(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.from(useMaterial3: true, colorScheme: colorScheme), + home: Scaffold( + bottomNavigationBar: BottomAppBar( + color: colorScheme.surface, + ), + ), + ), + ); + + final PhysicalShape physicalShape = tester.widget(find.byType(PhysicalShape).at(0)); + + const double elevation = 3.0; // Default for M3. + final Color overlayColor = ElevationOverlay.applySurfaceTint(colorScheme.surface, colorScheme.surfaceTint, elevation); + expect(physicalShape.color, overlayColor); + }); + // This is a regression test for a bug we had where toggling the notch on/off // would crash, as the shouldReclip method of ShapeBorderClipper or // _BottomAppBarClipper would try an illegal downcast. @@ -510,7 +542,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('observes safe area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Observes safe area', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -535,6 +567,37 @@ void main() { ); }); + testWidgetsWithLeakTracking('Material3 - Observes safe area', (WidgetTester tester) async { + const double safeAreaPadding = 50.0; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.all(safeAreaPadding), + ), + child: Scaffold( + bottomNavigationBar: BottomAppBar( + child: Center( + child: Text('safe'), + ), + ), + ), + ), + ), + ); + + const double appBarVerticalPadding = 12.0; + const double appBarHorizontalPadding = 16.0; + expect( + tester.getBottomLeft(find.widgetWithText(Center, 'safe')), + const Offset( + safeAreaPadding + appBarHorizontalPadding, + 600 - safeAreaPadding - appBarVerticalPadding, + ), + ); + }); + testWidgetsWithLeakTracking('clipBehavior is propagated', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( @@ -569,9 +632,45 @@ void main() { expect(physicalShape.clipBehavior, Clip.antiAliasWithSaveLayer); }); - testWidgetsWithLeakTracking('BottomAppBar with shape when Scaffold.bottomNavigationBar == null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BottomAppBar with shape when Scaffold.bottomNavigationBar == null', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/80878 + final ThemeData theme = ThemeData(useMaterial3: false); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Scaffold( + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + floatingActionButton: FloatingActionButton( + backgroundColor: Colors.green, + child: const Icon(Icons.home), + onPressed: () {}, + ), + body: Stack( + children: [ + Container( + color: Colors.amber, + ), + Container( + alignment: Alignment.bottomCenter, + child: BottomAppBar( + color: Colors.green, + shape: const CircularNotchedRectangle(), + child: Container(height: 50), + ), + ), + ], + ), + ), + ), + ); + + expect(tester.getRect(find.byType(FloatingActionButton)), const Rect.fromLTRB(372, 528, 428, 584)); + expect(tester.getSize(find.byType(BottomAppBar)), const Size(800, 50)); + }); + + testWidgetsWithLeakTracking('Material3 - BottomAppBar with shape when Scaffold.bottomNavigationBar == null', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/80878 - final ThemeData theme = ThemeData(); + final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( theme: theme, @@ -602,7 +701,7 @@ void main() { ); expect(tester.getRect(find.byType(FloatingActionButton)), const Rect.fromLTRB(372, 528, 428, 584)); - expect(tester.getSize(find.byType(BottomAppBar)), theme.useMaterial3 ? const Size(800, 80) : const Size(800, 50)); + expect(tester.getSize(find.byType(BottomAppBar)), const Size(800, 80)); }); testWidgetsWithLeakTracking('notch with margin and top padding, home safe area', (WidgetTester tester) async { @@ -691,7 +790,7 @@ void main() { expect(physicalShape.clipper.toString(), 'ShapeBorderClipper'); }); - testWidgetsWithLeakTracking('BottomAppBar adds bottom padding to height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BottomAppBar adds bottom padding to height', (WidgetTester tester) async { const double bottomPadding = 35.0; await tester.pumpWidget( diff --git a/packages/flutter/test/material/bottom_app_bar_theme_test.dart b/packages/flutter/test/material/bottom_app_bar_theme_test.dart index c4062a4ec9da0..eed8f3e01bad9 100644 --- a/packages/flutter/test/material/bottom_app_bar_theme_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_theme_test.dart @@ -20,17 +20,17 @@ void main() { }); group('Material 2 tests', () { - testWidgetsWithLeakTracking('BAB theme overrides color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB theme overrides color', (WidgetTester tester) async { const Color themedColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme(color: themedColor); - await tester.pumpWidget(_withTheme(theme)); + await tester.pumpWidget(_withTheme(theme, useMaterial3: false)); final PhysicalShape widget = _getBabRenderObject(tester); expect(widget.color, themedColor); }); - testWidgetsWithLeakTracking('BAB color - Widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB color - Widget', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const Color babColor = Colors.pink; @@ -49,7 +49,7 @@ void main() { expect(widget.color, babColor); }); - testWidgetsWithLeakTracking('BAB color - BabTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB color - BabTheme', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); @@ -67,7 +67,7 @@ void main() { expect(widget.color, babThemeColor); }); - testWidgetsWithLeakTracking('BAB color - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB color - Theme', (WidgetTester tester) async { const Color themeColor = Colors.white10; await tester.pumpWidget(MaterialApp( @@ -79,7 +79,7 @@ void main() { expect(widget.color, themeColor); }); - testWidgetsWithLeakTracking('BAB color - Default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB color - Default', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold(body: BottomAppBar()), @@ -90,14 +90,14 @@ void main() { expect(widget.color, Colors.white); }); - testWidgetsWithLeakTracking('BAB theme customizes shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB theme customizes shape', (WidgetTester tester) async { const BottomAppBarTheme theme = BottomAppBarTheme( color: Colors.white30, shape: CircularNotchedRectangle(), elevation: 1.0, ); - await tester.pumpWidget(_withTheme(theme)); + await tester.pumpWidget(_withTheme(theme, useMaterial3: false)); await expectLater( find.byKey(_painterKey), @@ -105,7 +105,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('BAB theme does not affect defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BAB theme does not affect defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold(body: BottomAppBar()), @@ -119,19 +119,19 @@ void main() { }); group('Material 3 tests', () { - testWidgetsWithLeakTracking('BAB theme overrides color - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB theme overrides color', (WidgetTester tester) async { const Color themedColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme( color: themedColor, elevation: 0 ); - await tester.pumpWidget(_withTheme(theme, true)); + await tester.pumpWidget(_withTheme(theme, useMaterial3: true)); final PhysicalShape widget = _getBabRenderObject(tester); expect(widget.color, themedColor); }); - testWidgetsWithLeakTracking('BAB color - Widget - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB color - Widget', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const Color babColor = Colors.pink; @@ -150,7 +150,7 @@ void main() { expect(widget.color, babColor); }); - testWidgetsWithLeakTracking('BAB color - BabTheme - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB color - BabTheme', (WidgetTester tester) async { const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme(color: babThemeColor); @@ -168,7 +168,7 @@ void main() { expect(widget.color, babThemeColor); }); - testWidgetsWithLeakTracking('BAB theme does not affect defaults - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB theme does not affect defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, @@ -181,30 +181,30 @@ void main() { expect(widget.elevation, equals(3.0)); }); - testWidgetsWithLeakTracking('BAB theme overrides surfaceTintColor - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB theme overrides surfaceTintColor', (WidgetTester tester) async { const Color color = Colors.blue; // base color that the surface tint will be applied to const Color babThemeSurfaceTintColor = Colors.black87; const BottomAppBarTheme theme = BottomAppBarTheme( color: color, surfaceTintColor: babThemeSurfaceTintColor, elevation: 0, ); - await tester.pumpWidget(_withTheme(theme, true)); + await tester.pumpWidget(_withTheme(theme, useMaterial3: true)); final PhysicalShape widget = _getBabRenderObject(tester); expect(widget.color, ElevationOverlay.applySurfaceTint(color, babThemeSurfaceTintColor, 0)); }); - testWidgetsWithLeakTracking('BAB theme overrides shadowColor - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB theme overrides shadowColor', (WidgetTester tester) async { const Color babThemeShadowColor = Colors.yellow; const BottomAppBarTheme theme = BottomAppBarTheme( shadowColor: babThemeShadowColor, elevation: 0 ); - await tester.pumpWidget(_withTheme(theme, true)); + await tester.pumpWidget(_withTheme(theme, useMaterial3: true)); final PhysicalShape widget = _getBabRenderObject(tester); expect(widget.shadowColor, babThemeShadowColor); }); - testWidgetsWithLeakTracking('BAB surfaceTintColor - Widget - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB surfaceTintColor - Widget', (WidgetTester tester) async { const Color color = Colors.white10; // base color that the surface tint will be applied to const Color themeSurfaceTintColor = Colors.white10; const Color babThemeSurfaceTintColor = Colors.black87; @@ -227,7 +227,7 @@ void main() { expect(widget.color, ElevationOverlay.applySurfaceTint(color, babSurfaceTintColor, 3.0)); }); - testWidgetsWithLeakTracking('BAB surfaceTintColor - BabTheme - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BAB surfaceTintColor - BabTheme', (WidgetTester tester) async { const Color color = Colors.blue; // base color that the surface tint will be applied to const Color themeColor = Colors.white10; const Color babThemeColor = Colors.black87; @@ -261,7 +261,7 @@ PhysicalShape _getBabRenderObject(WidgetTester tester) { final Key _painterKey = UniqueKey(); -Widget _withTheme(BottomAppBarTheme theme, [bool useMaterial3 = false]) { +Widget _withTheme(BottomAppBarTheme theme, {required bool useMaterial3}) { return MaterialApp( theme: ThemeData(useMaterial3: useMaterial3, bottomAppBarTheme: theme), home: Scaffold( From efa69ba95b92e6dd38d997a7dcd0caa9d81dd147 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 25 Jul 2023 16:07:51 -0700 Subject: [PATCH 0369/1547] Add example for locking screen orientation in a letterboxing environment (#131266) Android may choose to letterbox applications that lock orientation. This gets particularly bad on foldable devices, where a developer may want to lock orientation when the devices is folded and unlock when unfolded. However, if the app is letterboxed when unfolded, the `MediaQuery.of(context).size` will never report the full display size, only the letterboxed window size. This may result in an application getting "stuck" in portrait mode. /cc @TytaniumDev --- .../lib/src/services/system_chrome.dart | 68 +++++++++++++++++++ packages/flutter/lib/src/widgets/binding.dart | 7 +- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/services/system_chrome.dart b/packages/flutter/lib/src/services/system_chrome.dart index a1d4c5395de88..3d6881d658bf1 100644 --- a/packages/flutter/lib/src/services/system_chrome.dart +++ b/packages/flutter/lib/src/services/system_chrome.dart @@ -368,6 +368,74 @@ abstract final class SystemChrome { /// /// ## Limitations /// + /// ### Android + /// + /// Android screens may choose to [letterbox](https://developer.android.com/guide/practices/enhanced-letterboxing) + /// applications that lock orientation, particularly on larger screens. When + /// letterboxing occurs on Android, the [MediaQueryData.size] reports the + /// letterboxed size, not the full screen size. Applications that make + /// decisions about whether to lock orientation based on the screen size + /// must use the `display` property of the current [FlutterView]. + /// + /// ```dart + /// // A widget that locks the screen to portrait if it is less than 600 + /// // logical pixels wide. + /// class MyApp extends StatefulWidget { + /// const MyApp({ super.key }); + /// + /// @override + /// State createState() => _MyAppState(); + /// } + /// + /// class _MyAppState extends State with WidgetsBindingObserver { + /// ui.Display? _display; + /// static const double kOrientationLockBreakpoint = 600; + /// + /// @override + /// void initState() { + /// super.initState(); + /// WidgetsBinding.instance.addObserver(this); + /// } + /// + /// @override + /// void didChangeDependencies() { + /// super.didChangeDependencies(); + /// _display = View.maybeOf(context)?.display; + /// } + /// + /// @override + /// void dispose() { + /// WidgetsBinding.instance.removeObserver(this); + /// _display = null; + /// super.dispose(); + /// } + /// + /// @override + /// void didChangeMetrics() { + /// final ui.Display? display = _display; + /// if (display == null) { + /// return; + /// } + /// if (display.size.width / display.devicePixelRatio < kOrientationLockBreakpoint) { + /// SystemChrome.setPreferredOrientations([ + /// DeviceOrientation.portraitUp, + /// ]); + /// } else { + /// SystemChrome.setPreferredOrientations([]); + /// } + /// } + /// + /// @override + /// Widget build(BuildContext context) { + /// return const MaterialApp( + /// home: Placeholder(), + /// ); + /// } + /// } + /// ``` + /// + /// ### iOS + /// /// This setting will only be respected on iPad if multitasking is disabled. /// /// You can decide to opt out of multitasking on iPad, then diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index f4778adfb3008..14235ac8a8660 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -139,10 +139,15 @@ abstract mixin class WidgetsBindingObserver { /// @override /// void initState() { /// super.initState(); + /// WidgetsBinding.instance.addObserver(this); + /// } + /// + /// @override + /// void didChangeDependencies() { + /// super.didChangeDependencies(); /// // [View.of] exposes the view from `WidgetsBinding.instance.platformDispatcher.views` /// // into which this widget is drawn. /// _lastSize = View.of(context).physicalSize; - /// WidgetsBinding.instance.addObserver(this); /// } /// /// @override From 548aa6fa10628f25781b7f76105223692315cfcc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 19:41:15 -0400 Subject: [PATCH 0370/1547] Roll Flutter Engine from 3fff7316dc8d to 9e00c11eb519 (1 revision) (#131299) https://github.com/flutter/engine/compare/3fff7316dc8d...9e00c11eb519 2023-07-25 skia-flutter-autoroll@skia.org Roll ANGLE from 2d5fb09d7f0a to b0b71d59391c (2 revisions) (flutter/engine#44009) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 80ad5912355f1..4451c41381c1e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3fff7316dc8dd8e8127e12e3f329c17cfa3da589 +9e00c11eb519076292c7b70b0353c82466234ac7 From aab5747fc457e1b3604e8faa7dc3e6dcd2fb146d Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Tue, 25 Jul 2023 17:07:07 -0700 Subject: [PATCH 0371/1547] Ignore unused parameters in snippet code (#131068) Add `unused_element_parameter` to the codes ignored while analyzing snippets. Fixes https://github.com/flutter/flutter/issues/131067 --- dev/bots/analyze_snippet_code.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index 5669f0cb404bd..edcbd88cb00f2 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -459,6 +459,7 @@ class _SnippetChecker { '// ignore_for_file: unnecessary_import', '// ignore_for_file: unreachable_from_main', '// ignore_for_file: unused_element', + '// ignore_for_file: unused_element_parameter', '// ignore_for_file: unused_local_variable', ]; From 76fe7e86ca1c2c16bf3b2655f6fb8f3c82c24207 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 22:29:09 -0400 Subject: [PATCH 0372/1547] Roll Flutter Engine from 9e00c11eb519 to db711f14842b (3 revisions) (#131307) https://github.com/flutter/engine/compare/9e00c11eb519...db711f14842b 2023-07-26 matanlurey@users.noreply.github.com [Impeller] ToColor should produce a DlColor, not SkColor. (flutter/engine#43987) 2023-07-26 skia-flutter-autoroll@skia.org Roll ANGLE from b0b71d59391c to 84f5295c9782 (3 revisions) (flutter/engine#44025) 2023-07-25 smartercallum@gmail.com Uncap framerate for `iOSAppOnMac` (flutter/engine#43840) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4451c41381c1e..cbdc1c5e1936a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9e00c11eb519076292c7b70b0353c82466234ac7 +db711f14842b9d2b45886ec46cc549e74aec1f30 From a4f7906692ffeefe13b4a8f1db2b04d4a6d644d2 Mon Sep 17 00:00:00 2001 From: Caffeinix Date: Tue, 25 Jul 2023 20:07:27 -0700 Subject: [PATCH 0373/1547] Reorders menu item button shortcuts on Mac-like platforms (#129309) The Apple Human Interface Guidelines give a specific ordering of the symbols used as modifier keys in menu shortcuts. These guidelines are encoded into the native Cocoa or UIKit menu classes, and are intended to ensure that symbols are always aligned into columns of like symbols and do not move around in the case of dynamic menu items (for example, holding Option will transform certain menu items into different versions that take the Option key, so the Option key symbol appears to the left of most other symbols to avoid reordering). The Material spec says to use symbols for modifier keys on Mac and iOS, as this is what users there are familiar with. It stands to reason that we should follow the platform guidelines fully, so this changes the MenuItemButton class to honor the HIG-compliant symbol ordering on Mac and iOS. Fixed: #129308 --- .../flutter/lib/src/material/menu_anchor.dart | 96 ++++++++++++------- .../test/material/menu_anchor_test.dart | 12 ++- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index 37aca52459642..f10d133ae1de3 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -1072,7 +1072,7 @@ class _MenuItemButtonState extends State { ), ); - if (_platformSupportsAccelerators() && widget.enabled) { + if (_platformSupportsAccelerators && widget.enabled) { child = MenuAcceleratorCallbackBinding( onInvoke: _handleSelect, child: child, @@ -1920,7 +1920,7 @@ class _SubmenuButtonState extends State { ), ); - if (_enabled && _platformSupportsAccelerators()) { + if (_enabled && _platformSupportsAccelerators) { return MenuAcceleratorCallbackBinding( onInvoke: () => toggleShowMenu(context), hasSubmenu: true, @@ -2049,33 +2049,44 @@ class _LocalizedShortcutLabeler { String getShortcutLabel(MenuSerializableShortcut shortcut, MaterialLocalizations localizations) { final ShortcutSerialization serialized = shortcut.serializeForMenu(); final String keySeparator; - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: + if (_usesSymbolicModifiers) { // Use "⌃ ⇧ A" style on macOS and iOS. keySeparator = ' '; - case TargetPlatform.android: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: + } else { // Use "Ctrl+Shift+A" style. keySeparator = '+'; } if (serialized.trigger != null) { final List modifiers = []; final LogicalKeyboardKey trigger = serialized.trigger!; - // These should be in this order, to match the LogicalKeySet version. - if (serialized.alt!) { - modifiers.add(_getModifierLabel(LogicalKeyboardKey.alt, localizations)); - } - if (serialized.control!) { - modifiers.add(_getModifierLabel(LogicalKeyboardKey.control, localizations)); - } - if (serialized.meta!) { - modifiers.add(_getModifierLabel(LogicalKeyboardKey.meta, localizations)); - } - if (serialized.shift!) { - modifiers.add(_getModifierLabel(LogicalKeyboardKey.shift, localizations)); + if (_usesSymbolicModifiers) { + // macOS/iOS platform convention uses this ordering, with ⌘ always last. + if (serialized.control!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.control, localizations)); + } + if (serialized.alt!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.alt, localizations)); + } + if (serialized.shift!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.shift, localizations)); + } + if (serialized.meta!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.meta, localizations)); + } + } else { + // These should be in this order, to match the LogicalKeySet version. + if (serialized.alt!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.alt, localizations)); + } + if (serialized.control!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.control, localizations)); + } + if (serialized.meta!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.meta, localizations)); + } + if (serialized.shift!) { + modifiers.add(_getModifierLabel(LogicalKeyboardKey.shift, localizations)); + } } String? shortcutTrigger; final int logicalKeyId = trigger.keyId; @@ -2848,7 +2859,7 @@ class _MenuAcceleratorLabelState extends State { @override void initState() { super.initState(); - if (_platformSupportsAccelerators()) { + if (_platformSupportsAccelerators) { _showAccelerators = _altIsPressed(); HardwareKeyboard.instance.addHandler(_handleKeyEvent); } @@ -2857,9 +2868,9 @@ class _MenuAcceleratorLabelState extends State { @override void dispose() { - assert(_platformSupportsAccelerators() || _shortcutRegistryEntry == null); + assert(_platformSupportsAccelerators || _shortcutRegistryEntry == null); _displayLabel = ''; - if (_platformSupportsAccelerators()) { + if (_platformSupportsAccelerators) { _shortcutRegistryEntry?.dispose(); _shortcutRegistryEntry = null; _shortcutRegistry = null; @@ -2872,7 +2883,7 @@ class _MenuAcceleratorLabelState extends State { @override void didChangeDependencies() { super.didChangeDependencies(); - if (!_platformSupportsAccelerators()) { + if (!_platformSupportsAccelerators) { return; } _binding = MenuAcceleratorCallbackBinding.maybeOf(context); @@ -2900,7 +2911,7 @@ class _MenuAcceleratorLabelState extends State { } bool _handleKeyEvent(KeyEvent event) { - assert(_platformSupportsAccelerators()); + assert(_platformSupportsAccelerators); final bool altIsPressed = _altIsPressed(); if (altIsPressed != _showAccelerators) { setState(() { @@ -2913,7 +2924,7 @@ class _MenuAcceleratorLabelState extends State { } void _updateAcceleratorShortcut() { - assert(_platformSupportsAccelerators()); + assert(_platformSupportsAccelerators); _shortcutRegistryEntry?.dispose(); _shortcutRegistryEntry = null; // Before registering an accelerator as a shortcut it should meet these @@ -3566,23 +3577,38 @@ bool _debugMenuInfo(String message, [Iterable? details]) { return true; } -bool _platformSupportsAccelerators() { +/// Whether [defaultTargetPlatform] is an Apple platform (Mac or iOS). +bool get _isApple { switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return true; case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - return true; - case TargetPlatform.iOS: - case TargetPlatform.macOS: - // On iOS and macOS, pressing the Option key (a.k.a. the Alt key) causes a - // different set of characters to be generated, and the native menus don't - // support accelerators anyhow, so we just disable accelerators on these - // platforms. return false; } } +/// Whether [defaultTargetPlatform] is one that uses symbolic shortcuts. +/// +/// Mac and iOS use special symbols for modifier keys instead of their names, +/// render them in a particular order defined by Apple's human interface +/// guidelines, and format them so that the modifier keys always align. +bool get _usesSymbolicModifiers { + return _isApple; +} + + +bool get _platformSupportsAccelerators { + // On iOS and macOS, pressing the Option key (a.k.a. the Alt key) causes a + // different set of characters to be generated, and the native menus don't + // support accelerators anyhow, so we just disable accelerators on these + // platforms. + return !_isApple; +} + // BEGIN GENERATED TOKEN PROPERTIES - Menu // Do not edit by hand. The code between the "BEGIN GENERATED" and diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index 6de3e26a59c46..f29f01126644b 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -2944,7 +2944,17 @@ void main() { shift: true, alt: true, ); - final String allExpected = [expectedAlt, expectedCtrl, expectedMeta, expectedShift, 'A'].join(expectedSeparator); + late String allExpected; + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + allExpected = [expectedAlt, expectedCtrl, expectedMeta, expectedShift, 'A'].join(expectedSeparator); + case TargetPlatform.iOS: + case TargetPlatform.macOS: + allExpected = [expectedCtrl, expectedAlt, expectedShift, expectedMeta, 'A'].join(expectedSeparator); + } const CharacterActivator charShortcuts = CharacterActivator('ñ'); const String charExpected = 'ñ'; await tester.pumpWidget( From 9ea520b46f688a541d004182c8bf15c8ac24d70e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 25 Jul 2023 23:24:28 -0400 Subject: [PATCH 0374/1547] Roll Flutter Engine from db711f14842b to 7f3b0d6b7250 (4 revisions) (#131309) https://github.com/flutter/engine/compare/db711f14842b...7f3b0d6b7250 2023-07-26 jacksongardner@google.com Roll fallback fonts. (flutter/engine#44000) 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from 12d41b6f66ed to 28773cec6e8d (2 revisions) (flutter/engine#44011) 2023-07-26 paulberry@google.com Prepare flutter engine for enabling private final field promotion. (flutter/engine#43959) 2023-07-26 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 61ab5422fb7b to b1e82e2e55b2 (3 revisions) (flutter/engine#44018) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cbdc1c5e1936a..d59205e4cc931 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -db711f14842b9d2b45886ec46cc549e74aec1f30 +7f3b0d6b72503abce728963237023b9904d42cd1 From af08b11aaa89739fb207957514a38fb692a8ac6d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 00:12:07 -0400 Subject: [PATCH 0375/1547] Roll Flutter Engine from 7f3b0d6b7250 to 43f727e4748a (1 revision) (#131311) https://github.com/flutter/engine/compare/7f3b0d6b7250...43f727e4748a 2023-07-26 skia-flutter-autoroll@skia.org Roll ANGLE from 84f5295c9782 to a09773110c4a (1 revision) (flutter/engine#44028) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d59205e4cc931..6f5e5b53874ed 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7f3b0d6b72503abce728963237023b9904d42cd1 +43f727e4748af3793a0948eae231cd8098956b50 From 618ef7f23687ccc37bd0e072a20a3d90ce8aa7ed Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 02:31:08 -0400 Subject: [PATCH 0376/1547] Roll Flutter Engine from 43f727e4748a to df12fff329a1 (3 revisions) (#131314) https://github.com/flutter/engine/compare/43f727e4748a...df12fff329a1 2023-07-26 ditman@gmail.com [web] Preserve canvaskit variant during tests. (flutter/engine#43868) 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from 28773cec6e8d to 826e38ba8db3 (5 revisions) (flutter/engine#44031) 2023-07-26 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 0StTjIqUxGkc3nOWT... to d6O9t74z-k2svOmvz... (flutter/engine#44030) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 0StTjIqUxGkc to d6O9t74z-k2s If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6f5e5b53874ed..02a1cfb6736f5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -43f727e4748af3793a0948eae231cd8098956b50 +df12fff329a12c514c80503fccb84f397854a432 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 3bca4f8e4186b..9d8ba60fba1ae 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -0StTjIqUxGkc3nOWTPdEl-TR153yqChYQ6s1W4_EA-cC +d6O9t74z-k2svOmvzcrHJWB8fJmLJ7qu70VmFQYRF_kC From 532a84cd1554186c7d5ee5afef889273a7b80393 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 03:24:30 -0400 Subject: [PATCH 0377/1547] Roll Flutter Engine from df12fff329a1 to 4bdceccff964 (2 revisions) (#131316) https://github.com/flutter/engine/compare/df12fff329a1...4bdceccff964 2023-07-26 dnfield@google.com [Impeller] Remove duplicated code. (flutter/engine#44024) 2023-07-26 bdero@google.com [Impeller] Only strip the translation from backdrop filter effect transforms. (flutter/engine#44029) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 02a1cfb6736f5..91f30c97dc431 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -df12fff329a12c514c80503fccb84f397854a432 +4bdceccff964ac12e1e322beebf05861ae982f0d From 35e4e2a2416d925767d52b73b65ad315921c1de8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 04:39:12 -0400 Subject: [PATCH 0378/1547] Roll Flutter Engine from 4bdceccff964 to b3cd1c599abe (1 revision) (#131317) https://github.com/flutter/engine/compare/4bdceccff964...b3cd1c599abe 2023-07-26 leroux_bruno@yahoo.fr [macOS] Return keyboard pressed state (flutter/engine#42878) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 91f30c97dc431..e0ff91ef3601b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4bdceccff964ac12e1e322beebf05861ae982f0d +b3cd1c599abecd64e74f0e88fcb90572e6d08c67 From 110c8a41c0945f9aa458f510b6bc8b1e88226fac Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 05:57:35 -0400 Subject: [PATCH 0379/1547] Roll Flutter Engine from b3cd1c599abe to 89203002f455 (1 revision) (#131323) https://github.com/flutter/engine/compare/b3cd1c599abe...89203002f455 2023-07-26 skia-flutter-autoroll@skia.org Roll ANGLE from a09773110c4a to 58cb5c8396a3 (1 revision) (flutter/engine#44033) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e0ff91ef3601b..cf1e3b267c2bd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b3cd1c599abecd64e74f0e88fcb90572e6d08c67 +89203002f4550a852ed21ea55b00d54d2c94ed3c From 285f901eba582226da346c3649bffbca45b0aafd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 07:12:40 -0400 Subject: [PATCH 0380/1547] Roll Flutter Engine from 89203002f455 to ba83c144f84e (1 revision) (#131329) https://github.com/flutter/engine/compare/89203002f455...ba83c144f84e 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from 826e38ba8db3 to 5ace549dfae6 (2 revisions) (flutter/engine#44034) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cf1e3b267c2bd..e39dfee411af4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -89203002f4550a852ed21ea55b00d54d2c94ed3c +ba83c144f84eef9a89c8b941021809ee26774666 From 9bd87ec984a6c4ae5fc43ac1cf75d80bab86b866 Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Wed, 26 Jul 2023 06:31:29 -0700 Subject: [PATCH 0381/1547] [flutter roll] Revert "Fix floating SnackBar throws when FAB is on the top" (#131303) Reverts flutter/flutter#129274 temporarily putting up a revert in case a fix is difficult context: [b/293202068](http://b/293202068) youtube integration tests failed --- .../flutter/lib/src/material/scaffold.dart | 26 +-------- .../lib/src/material/snack_bar_theme.dart | 15 +++--- .../flutter/test/material/snack_bar_test.dart | 53 ------------------- 3 files changed, 7 insertions(+), 87 deletions(-) diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index f86355bb11253..110cbbbfb1c89 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1142,31 +1142,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { } final double snackBarYOffsetBase; - final bool showAboveFab = switch (currentFloatingActionButtonLocation) { - FloatingActionButtonLocation.startTop - || FloatingActionButtonLocation.centerTop - || FloatingActionButtonLocation.endTop - || FloatingActionButtonLocation.miniStartTop - || FloatingActionButtonLocation.miniCenterTop - || FloatingActionButtonLocation.miniEndTop => false, - FloatingActionButtonLocation.startDocked - || FloatingActionButtonLocation.startFloat - || FloatingActionButtonLocation.centerDocked - || FloatingActionButtonLocation.centerFloat - || FloatingActionButtonLocation.endContained - || FloatingActionButtonLocation.endDocked - || FloatingActionButtonLocation.endFloat - || FloatingActionButtonLocation.miniStartDocked - || FloatingActionButtonLocation.miniStartFloat - || FloatingActionButtonLocation.miniCenterDocked - || FloatingActionButtonLocation.miniCenterFloat - || FloatingActionButtonLocation.miniEndDocked - || FloatingActionButtonLocation.miniEndFloat => true, - FloatingActionButtonLocation() => throw FlutterError( - '$currentFloatingActionButtonLocation is an unknown FloatingActionButtonLocation value.' - ), - }; - if (floatingActionButtonRect.size != Size.zero && isSnackBarFloating && showAboveFab) { + if (floatingActionButtonRect.size != Size.zero && isSnackBarFloating) { snackBarYOffsetBase = floatingActionButtonRect.top; } else { // SnackBarBehavior.fixed applies a SafeArea automatically. diff --git a/packages/flutter/lib/src/material/snack_bar_theme.dart b/packages/flutter/lib/src/material/snack_bar_theme.dart index dae0804f863d6..5f976148d70fc 100644 --- a/packages/flutter/lib/src/material/snack_bar_theme.dart +++ b/packages/flutter/lib/src/material/snack_bar_theme.dart @@ -12,22 +12,19 @@ import 'theme.dart'; /// Defines where a [SnackBar] should appear within a [Scaffold] and how its /// location should be adjusted when the scaffold also includes a -/// [FloatingActionButton], a [BottomNavigationBar], or a [NavigationBar]. +/// [FloatingActionButton] or a [BottomNavigationBar]. enum SnackBarBehavior { /// Fixes the [SnackBar] at the bottom of the [Scaffold]. /// /// The exception is that the [SnackBar] will be shown above a - /// [BottomNavigationBar] or a [NavigationBar]. Additionally, the [SnackBar] - /// will cause other non-fixed widgets inside [Scaffold] to be pushed above - /// (for example, the [FloatingActionButton]). + /// [BottomNavigationBar]. Additionally, the [SnackBar] will cause other + /// non-fixed widgets inside [Scaffold] to be pushed above (for example, the + /// [FloatingActionButton]). fixed, /// This behavior will cause [SnackBar] to be shown above other widgets in the - /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] or - /// a [NavigationBar], and a [FloatingActionButton] when its location is on the - /// bottom. When the floating action button location is on the top, this behavior - /// will cause the [SnackBar] to be shown above other widgets in the [Scaffold] - /// except the floating action button. + /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] + /// and a [FloatingActionButton]. /// /// See for more details. floating, diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index 22d43cc3c99e5..9436f743b4e30 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -2071,59 +2071,6 @@ void main() { }, ); - testWidgets( - '${SnackBarBehavior.floating} should not align SnackBar with the top of FloatingActionButton ' - 'when Scaffold has a FloatingActionButton and floatingActionButtonLocation is set to a top position', - (WidgetTester tester) async { - Future pumpApp({required FloatingActionButtonLocation fabLocation}) async { - return tester.pumpWidget(MaterialApp( - home: Scaffold( - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.send), - onPressed: () {}, - ), - floatingActionButtonLocation: fabLocation, - body: Builder( - builder: (BuildContext context) { - return GestureDetector( - onTap: () { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: const Text('I am a snack bar.'), - duration: const Duration(seconds: 2), - action: SnackBarAction(label: 'ACTION', onPressed: () {}), - behavior: SnackBarBehavior.floating, - )); - }, - child: const Text('X'), - ); - }, - ), - ), - )); - } - - const List topLocations = [ - FloatingActionButtonLocation.startTop, - FloatingActionButtonLocation.centerTop, - FloatingActionButtonLocation.endTop, - FloatingActionButtonLocation.miniStartTop, - FloatingActionButtonLocation.miniCenterTop, - FloatingActionButtonLocation.miniEndTop, - ]; - - for (final FloatingActionButtonLocation location in topLocations) { - await pumpApp(fabLocation: location); - - await tester.tap(find.text('X')); - await tester.pumpAndSettle(); // Have the SnackBar fully animate out. - - final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); - - expect(snackBarBottomLeft.dy, 600); // Device height is 600. - } - }, - ); - testWidgets( '${SnackBarBehavior.fixed} should align SnackBar with the top of BottomNavigationBar ' 'when Scaffold has a BottomNavigationBar and FloatingActionButton', From 21d7eeeb5f475beb533dc6448ce3259f7501b4c0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 11:52:06 -0400 Subject: [PATCH 0382/1547] Roll Packages from 406eac1ad976 to a99fc8765de9 (1 revision) (#131336) https://github.com/flutter/packages/compare/406eac1ad976...a99fc8765de9 2023-07-26 stuartmorgan@google.com [tool/ci] Add iOS/macOS and Dart support to `fetch-deps` (flutter/packages#4562) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 0a2f19f4665ba..3b4dd57c7e677 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -406eac1ad976bf9317422b1538615e03d057eb7b +a99fc8765de9db56ba6d202d091b54668c1def13 From d4d57546fd9b1aa79b7a6ebf550bd3ed2a316f6b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 26 Jul 2023 13:06:06 -0400 Subject: [PATCH 0383/1547] Roll Flutter Engine from ba83c144f84e to faf1121d010c (2 revisions) (#131339) https://github.com/flutter/engine/compare/ba83c144f84e...faf1121d010c 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from 5ace549dfae6 to ca48e45a0262 (4 revisions) (flutter/engine#44038) 2023-07-26 mdebbar@google.com [web] Provide convenient default factories for platform views (flutter/engine#43828) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e39dfee411af4..54109d0c8ff96 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ba83c144f84eef9a89c8b941021809ee26774666 +faf1121d010cea08932b01d8c0397595060b9851 From 8046e1337306ad3f57d522aacdae38dd2d73fdde Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 26 Jul 2023 10:10:07 -0700 Subject: [PATCH 0384/1547] Run benchmarks with `--omit-type-checks` (#131102) We've decided to use the `--omit-type-checks` flag for our dart2wasm benchmarks. Right now, many of the benchmark results are dominated by type checks and most of what we are actually trying to measure get drowned out in the noise. --- .ci.yaml | 2 -- dev/devicelab/lib/tasks/web_benchmarks.dart | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index ce37a5f61b29d..22ccf43eebb12 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1079,7 +1079,6 @@ targets: - name: Linux web_benchmarks_html recipe: devicelab/devicelab_drone - presubmit: false timeout: 60 properties: dependencies: >- @@ -1096,7 +1095,6 @@ targets: - .ci.yaml - name: Linux web_benchmarks_skwasm - bringup: true recipe: devicelab/devicelab_drone presubmit: false timeout: 60 diff --git a/dev/devicelab/lib/tasks/web_benchmarks.dart b/dev/devicelab/lib/tasks/web_benchmarks.dart index 051133c70db7b..a4748b8f9f85e 100644 --- a/dev/devicelab/lib/tasks/web_benchmarks.dart +++ b/dev/devicelab/lib/tasks/web_benchmarks.dart @@ -36,6 +36,7 @@ Future runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async { if (benchmarkOptions.useWasm) ...[ '--wasm', '--wasm-opt=debug', + '--omit-type-checks', ], '--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true', '--web-renderer=${benchmarkOptions.webRenderer}', From 552700999d12411968a9ab7e454b465bcc164d3a Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 26 Jul 2023 10:31:21 -0700 Subject: [PATCH 0385/1547] Document the Flow/Opacity/hit-test issues (#131239) Closes https://github.com/flutter/flutter/issues/6100. --- packages/flutter/lib/src/widgets/basic.dart | 57 +++++++++++++++---- .../lib/src/widgets/implicit_animations.dart | 37 ++++++++++++ .../flutter/lib/src/widgets/transitions.dart | 41 +++++++++++++ 3 files changed, 124 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index eab287bddb19a..afa0def4dbcdb 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -290,6 +290,22 @@ class Directionality extends _UbiquitousInheritedWidget { /// Drawing content into the offscreen buffer may also trigger render target /// switches and such switching is particularly slow in older GPUs. /// +/// ## Hit testing +/// +/// Setting the [opacity] to zero does not prevent hit testing from being applied +/// to the descendants of the [Opacity] widget. This can be confusing for the +/// user, who may not see anything, and may believe the area of the interface +/// where the [Opacity] is hiding a widget to be non-interactive. +/// +/// With certain widgets, such as [Flow], that compute their positions only when +/// they are painted, this can actually lead to bugs (from unexpected geometry +/// to exceptions), because those widgets are not painted by the [Opacity] +/// widget at all when the [opacity] is zero. +/// +/// To avoid such problems, it is generally a good idea to use an +/// [IgnorePointer] widget when setting the [opacity] to zero. This prevents +/// interactions with any children in the subtree. +/// /// See also: /// /// * [Visibility], which can hide a child more efficiently (albeit less @@ -5574,27 +5590,46 @@ class Wrap extends MultiChildRenderObjectWidget { /// this animation and repaint whenever the animation ticks, avoiding both the /// build and layout phases of the pipeline. /// +/// {@tool dartpad} +/// This example uses the [Flow] widget to create a menu that opens and closes +/// as it is interacted with, shown above. The color of the button in the menu +/// changes to indicate which one has been selected. +/// +/// ** See code in examples/api/lib/widgets/basic/flow.0.dart ** +/// {@end-tool} +/// +/// ## Hit testing and hidden [Flow] widgets +/// +/// The [Flow] widget recomputers its children's positions (as used by hit +/// testing) during the _paint_ phase rather than during the _layout_ phase. +/// +/// Widgets like [Opacity] avoid painting their children when those children +/// would be invisible due to their opacity being zero. +/// +/// Unfortunately, this means that hiding a [Flow] widget using an [Opacity] +/// widget will cause bugs when the user attempts to interact with the hidden +/// region, for example, by tapping it or clicking it. +/// +/// Such bugs will manifest either as out-of-date geometry (taps going to +/// different widgets than might be expected by the currently-specified +/// [FlowDelegate]s), or exceptions (e.g. if the last time the [Flow] was +/// painted, a different set of children was specified). +/// +/// To avoid this, when hiding a [Flow] widget with an [Opacity] widget (or +/// [AnimatedOpacity] or similar), it is wise to also disable hit testing on the +/// widget by using [IgnorePointer]. This is generally good advice anyway as +/// hit-testing invisible widgets is often confusing for the user. +/// /// See also: /// /// * [Wrap], which provides the layout model that some other frameworks call /// "flow", and is otherwise unrelated to [Flow]. -/// * [FlowDelegate], which controls the visual presentation of the children. /// * [Stack], which arranges children relative to the edges of the container. /// * [CustomSingleChildLayout], which uses a delegate to control the layout of /// a single child. /// * [CustomMultiChildLayout], which uses a delegate to position multiple /// children. /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). -/// -/// -/// {@tool dartpad} -/// This example uses the [Flow] widget to create a menu that opens and closes -/// as it is interacted with, shown above. The color of the button in the menu -/// changes to indicate which one has been selected. -/// -/// ** See code in examples/api/lib/widgets/basic/flow.0.dart ** -/// {@end-tool} -/// class Flow extends MultiChildRenderObjectWidget { /// Creates a flow layout. /// diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index f9fd981bb4c34..90ad122c211d0 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -1674,6 +1674,24 @@ class _AnimatedSlideState extends ImplicitlyAnimatedWidgetState { /// ``` /// {@end-tool} /// +/// ## Hit testing +/// +/// Setting the [opacity] to zero does not prevent hit testing from being +/// applied to the descendants of the [AnimatedOpacity] widget. This can be +/// confusing for the user, who may not see anything, and may believe the area +/// of the interface where the [AnimatedOpacity] is hiding a widget to be +/// non-interactive. +/// +/// With certain widgets, such as [Flow], that compute their positions only when +/// they are painted, this can actually lead to bugs (from unexpected geometry +/// to exceptions), because those widgets are not painted by the [AnimatedOpacity] +/// widget at all when the [opacity] animation reaches zero. +/// +/// To avoid such problems, it is generally a good idea to use an +/// [IgnorePointer] widget when setting the [opacity] to zero. This prevents +/// interactions with any children in the subtree when the [child] is animating +/// away. +/// /// See also: /// /// * [AnimatedCrossFade], for fading between two children. @@ -1771,6 +1789,25 @@ class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState Date: Wed, 26 Jul 2023 10:31:23 -0700 Subject: [PATCH 0386/1547] ImageDecoration.lerp (#130533) This primarily implements DecorationImage.lerp(). It also makes some minor tweaks, the main one of which is defering to dart:ui for `clampDouble` instead of duplicating it in package:foundation. Fixes https://github.com/flutter/flutter/issues/12452 --- analysis_options.yaml | 2 +- packages/flutter/lib/foundation.dart | 1 - packages/flutter/lib/src/foundation/README.md | 9 +- .../flutter/lib/src/foundation/binding.dart | 2 +- .../lib/src/foundation/diagnostics.dart | 2 +- packages/flutter/lib/src/foundation/math.dart | 23 - packages/flutter/lib/src/material/dialog.dart | 3 +- .../lib/src/painting/box_decoration.dart | 4 +- .../lib/src/painting/decoration_image.dart | 183 +++++++- .../lib/src/painting/shape_decoration.dart | 2 +- .../painting/decoration_image_lerp_test.dart | 440 ++++++++++++++++++ 11 files changed, 612 insertions(+), 59 deletions(-) delete mode 100644 packages/flutter/lib/src/foundation/math.dart create mode 100644 packages/flutter/test/painting/decoration_image_lerp_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 747d8e24b4750..a9d29631e12eb 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -50,7 +50,7 @@ linter: - avoid_field_initializers_in_const_classes # - avoid_final_parameters # incompatible with prefer_final_parameters - avoid_function_literals_in_foreach_calls - - avoid_implementing_value_types + # - avoid_implementing_value_types # see https://github.com/dart-lang/linter/issues/4558 - avoid_init_to_null - avoid_js_rounded_ints # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to diff --git a/packages/flutter/lib/foundation.dart b/packages/flutter/lib/foundation.dart index 43ac8133870bf..378b206d74265 100644 --- a/packages/flutter/lib/foundation.dart +++ b/packages/flutter/lib/foundation.dart @@ -34,7 +34,6 @@ export 'src/foundation/diagnostics.dart'; export 'src/foundation/isolates.dart'; export 'src/foundation/key.dart'; export 'src/foundation/licenses.dart'; -export 'src/foundation/math.dart'; export 'src/foundation/memory_allocations.dart'; export 'src/foundation/node.dart'; export 'src/foundation/object.dart'; diff --git a/packages/flutter/lib/src/foundation/README.md b/packages/flutter/lib/src/foundation/README.md index 5e4de0755a288..d32effc8c2381 100644 --- a/packages/flutter/lib/src/foundation/README.md +++ b/packages/flutter/lib/src/foundation/README.md @@ -3,9 +3,9 @@ nothing but core Dart packages. They can't depend on `dart:ui`, they can't depend on any `package:`, and they can't depend on anything outside this directory. -Currently they do depend on dart:ui, but only for `VoidCallback` (and -maybe one day `lerpDouble`), which are all intended to be moved out -of `dart:ui` and into `dart:core`. +Currently they do depend on dart:ui, but only for `VoidCallback` and +`clampDouble` (and maybe one day `lerpDouble`), which are all intended +to be moved out of `dart:ui` and into `dart:core`. There is currently also an unfortunate dependency on the platform dispatcher logic (SingletonFlutterWindow, Brightness, @@ -14,5 +14,4 @@ PlatformDispatcher, window), though that should probably move to the See also: - * https://github.com/dart-lang/sdk/issues/27791 (`VoidCallback`) - * https://github.com/dart-lang/sdk/issues/25217 (`hashValues`, `hashList`, and `lerpDouble`) + * https://github.com/dart-lang/sdk/issues/25217 diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index de0bac79bc6ab..83204bd57b227 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -22,7 +22,7 @@ import 'print.dart'; import 'service_extensions.dart'; import 'timeline.dart'; -export 'dart:ui' show PlatformDispatcher, SingletonFlutterWindow; // ignore: deprecated_member_use +export 'dart:ui' show PlatformDispatcher, SingletonFlutterWindow, clampDouble; // ignore: deprecated_member_use export 'basic_types.dart' show AsyncCallback, AsyncValueGetter, AsyncValueSetter; diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index f4f9d5c4c0bc9..e5c1345ade8cc 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. import 'dart:math' as math; +import 'dart:ui' show clampDouble; import 'package:meta/meta.dart'; import 'assertions.dart'; import 'constants.dart'; import 'debug.dart'; -import 'math.dart' show clampDouble; import 'object.dart'; // Examples can assume: diff --git a/packages/flutter/lib/src/foundation/math.dart b/packages/flutter/lib/src/foundation/math.dart deleted file mode 100644 index 053192ad506eb..0000000000000 --- a/packages/flutter/lib/src/foundation/math.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/// Same as [num.clamp] but optimized for non-null [double]. -/// -/// This is faster because it avoids polymorphism, boxing, and special cases for -/// floating point numbers. -// -// See also: //dev/benchmarks/microbenchmarks/lib/foundation/clamp.dart -double clampDouble(double x, double min, double max) { - assert(min <= max && !max.isNaN && !min.isNaN); - if (x < min) { - return min; - } - if (x > max) { - return max; - } - if (x.isNaN) { - return max; - } - return x; -} diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 57300b56011a4..0b13366825c88 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui'; +import 'dart:ui' show clampDouble, lerpDouble; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart' show clampDouble; import 'color_scheme.dart'; import 'colors.dart'; diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart index 444eb40608130..e076247d99165 100644 --- a/packages/flutter/lib/src/painting/box_decoration.dart +++ b/packages/flutter/lib/src/painting/box_decoration.dart @@ -232,7 +232,7 @@ class BoxDecoration extends Decoration { BoxDecoration scale(double factor) { return BoxDecoration( color: Color.lerp(null, color, factor), - image: image, // TODO(ianh): fade the image from transparent + image: DecorationImage.lerp(null, image, factor), border: BoxBorder.lerp(null, border, factor), borderRadius: BorderRadiusGeometry.lerp(null, borderRadius, factor), boxShadow: BoxShadow.lerpList(null, boxShadow, factor), @@ -307,7 +307,7 @@ class BoxDecoration extends Decoration { } return BoxDecoration( color: Color.lerp(a.color, b.color, t), - image: t < 0.5 ? a.image : b.image, // TODO(ianh): cross-fade the image + image: DecorationImage.lerp(a.image, b.image, t), border: BoxBorder.lerp(a.border, b.border, t), borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, b.borderRadius, t), boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t), diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index 5c8ed9df0390d..c91a9f083341d 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -177,7 +177,7 @@ class DecorationImage { /// image needs to be repainted, e.g. because it is loading incrementally or /// because it is animated. DecorationImagePainter createPainter(VoidCallback onChanged) { - return DecorationImagePainter._(this, onChanged); + return _DecorationImagePainter._(this, onChanged); } @override @@ -246,6 +246,28 @@ class DecorationImage { ]; return '${objectRuntimeType(this, 'DecorationImage')}(${properties.join(", ")})'; } + + /// Linearly interpolates between two [DecorationImage]s. + /// + /// The `t` argument represents position on the timeline, with 0.0 meaning + /// that the interpolation has not started, returning `a`, 1.0 meaning that + /// the interpolation has finished, returning `b`, and values in between + /// meaning that the interpolation is at the relevant point on the timeline + /// between `a` and `this`. The interpolation can be extrapolated beyond 0.0 + /// and 1.0, so negative values and values greater than 1.0 are valid (and can + /// easily be generated by curves such as [Curves.elasticInOut]). + /// + /// Values for `t` are usually obtained from an [Animation], such as + /// an [AnimationController]. + static DecorationImage? lerp(DecorationImage? a, DecorationImage? b, double t) { + if (identical(a, b) || t == 0.0) { + return a; + } + if (t == 1.0) { + return b; + } + return _BlendedDecorationImage(a, b, t); + } } /// The painter for a [DecorationImage]. @@ -259,15 +281,7 @@ class DecorationImage { /// /// This object should be disposed using the [dispose] method when it is no /// longer needed. -class DecorationImagePainter { - DecorationImagePainter._(this._details, this._onChanged); - - final DecorationImage _details; - final VoidCallback _onChanged; - - ImageStream? _imageStream; - ImageInfo? _image; - +abstract interface class DecorationImagePainter { /// Draw the image onto the given canvas. /// /// The image is drawn at the position and size given by the `rect` argument. @@ -282,8 +296,34 @@ class DecorationImagePainter { /// because it had not yet been loaded the first time this method was called, /// then the `onChanged` callback passed to [DecorationImage.createPainter] /// will be called. - void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration) { + /// + /// The `blend` argument specifies the opacity that should be applied to the + /// image due to this image being blended with another. The `blendMode` + /// argument can be specified to override the [DecorationImagePainter]'s + /// default [BlendMode] behavior. It is usually set to [BlendMode.srcOver] if + /// this is the first or only image being blended, and [BlendMode.plus] if it + /// is being blended with an image below. + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }); + /// Releases the resources used by this painter. + /// + /// This should be called whenever the painter is no longer needed. + /// + /// After this method has been called, the object is no longer usable. + void dispose(); +} + +class _DecorationImagePainter implements DecorationImagePainter { + _DecorationImagePainter._(this._details, this._onChanged); + + final DecorationImage _details; + final VoidCallback _onChanged; + + ImageStream? _imageStream; + ImageInfo? _image; + + @override + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { bool flipHorizontally = false; if (_details.matchTextDirection) { assert(() { @@ -338,10 +378,11 @@ class DecorationImagePainter { centerSlice: _details.centerSlice, repeat: _details.repeat, flipHorizontally: flipHorizontally, - opacity: _details.opacity, + opacity: _details.opacity * blend, filterQuality: _details.filterQuality, invertColors: _details.invertColors, isAntiAlias: _details.isAntiAlias, + blendMode: blendMode, ); if (clipPath != null) { @@ -364,12 +405,7 @@ class DecorationImagePainter { } } - /// Releases the resources used by this painter. - /// - /// This should be called whenever the painter is no longer needed. - /// - /// After this method has been called, the object is no longer usable. - @mustCallSuper + @override void dispose() { _imageStream?.removeListener(ImageStreamListener( _handleImage, @@ -444,7 +480,7 @@ void debugFlushLastFrameImageSizeInfo() { /// corners of the destination rectangle defined by applying `fit`. The /// remaining five regions are drawn by stretching them to fit such that they /// exactly cover the destination rectangle while maintaining their relative -/// positions. +/// positions. See also [Canvas.drawImageNine]. /// /// * `repeat`: If the image does not fill `rect`, whether and how the image /// should be repeated to fill `rect`. By default, the image is not repeated. @@ -490,6 +526,7 @@ void paintImage({ bool invertColors = false, FilterQuality filterQuality = FilterQuality.low, bool isAntiAlias = false, + BlendMode blendMode = BlendMode.srcOver, }) { assert( image.debugGetOpenHandleStackTraces()?.isNotEmpty ?? true, @@ -530,9 +567,10 @@ void paintImage({ if (colorFilter != null) { paint.colorFilter = colorFilter; } - paint.color = Color.fromRGBO(0, 0, 0, opacity); + paint.color = Color.fromRGBO(0, 0, 0, clampDouble(opacity, 0.0, 1.0)); paint.filterQuality = filterQuality; paint.invertColors = invertColors; + paint.blendMode = blendMode; final double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0; final double halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0; final double dx = halfWidthDelta + (flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta; @@ -543,6 +581,12 @@ void paintImage({ // Set to true if we added a saveLayer to the canvas to invert/flip the image. bool invertedCanvas = false; // Output size and destination rect are fully calculated. + + // Implement debug-mode and profile-mode features: + // - cacheWidth/cacheHeight warning + // - debugInvertOversizedImages + // - debugOnPaintImage + // - Flutter.ImageSizesForFrame events in timeline if (!kReleaseMode) { // We can use the devicePixelRatio of the views directly here (instead of // going through a MediaQuery) because if it changes, whatever is aware of @@ -554,7 +598,6 @@ void paintImage({ 0.0, (double previousValue, ui.FlutterView view) => math.max(previousValue, view.devicePixelRatio), ); - final ImageSizeInfo sizeInfo = ImageSizeInfo( // Some ImageProvider implementations may not have given this. source: debugImageLabel ?? '', @@ -599,7 +642,7 @@ void paintImage({ return true; }()); // Avoid emitting events that are the same as those emitted in the last frame. - if (!kReleaseMode && !_lastFrameImageSizeInfo.contains(sizeInfo)) { + if (!_lastFrameImageSizeInfo.contains(sizeInfo)) { final ImageSizeInfo? existingSizeInfo = _pendingImageSizeInfo[sizeInfo.source]; if (existingSizeInfo == null || existingSizeInfo.displaySizeInBytes < sizeInfo.displaySizeInBytes) { _pendingImageSizeInfo[sizeInfo.source!] = sizeInfo; @@ -691,3 +734,99 @@ Iterable _generateImageTileRects(Rect outputRect, Rect fundamentalRect, Im } Rect _scaleRect(Rect rect, double scale) => Rect.fromLTRB(rect.left * scale, rect.top * scale, rect.right * scale, rect.bottom * scale); + +// Implements DecorationImage.lerp when the image is different. +// +// This class just paints both decorations on top of each other, blended together. +// +// The Decoration properties are faked by just forwarded to the target image. +class _BlendedDecorationImage implements DecorationImage { + const _BlendedDecorationImage(this.a, this.b, this.t) : assert(a != null || b != null); + + final DecorationImage? a; + final DecorationImage? b; + final double t; + + @override + ImageProvider get image => b?.image ?? a!.image; + @override + ImageErrorListener? get onError => b?.onError ?? a!.onError; + @override + ColorFilter? get colorFilter => b?.colorFilter ?? a!.colorFilter; + @override + BoxFit? get fit => b?.fit ?? a!.fit; + @override + AlignmentGeometry get alignment => b?.alignment ?? a!.alignment; + @override + Rect? get centerSlice => b?.centerSlice ?? a!.centerSlice; + @override + ImageRepeat get repeat => b?.repeat ?? a!.repeat; + @override + bool get matchTextDirection => b?.matchTextDirection ?? a!.matchTextDirection; + @override + double get scale => b?.scale ?? a!.scale; + @override + double get opacity => b?.opacity ?? a!.opacity; + @override + FilterQuality get filterQuality => b?.filterQuality ?? a!.filterQuality; + @override + bool get invertColors => b?.invertColors ?? a!.invertColors; + @override + bool get isAntiAlias => b?.isAntiAlias ?? a!.isAntiAlias; + + @override + DecorationImagePainter createPainter(VoidCallback onChanged) { + return _BlendedDecorationImagePainter._( + a?.createPainter(onChanged), + b?.createPainter(onChanged), + t, + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (other.runtimeType != runtimeType) { + return false; + } + return other is _BlendedDecorationImage + && other.a == a + && other.b == b + && other.t == t; + } + + @override + int get hashCode => Object.hash(a, b, t); + + @override + String toString() { + return '${objectRuntimeType(this, '_BlendedDecorationImage')}($a, $b, $t)'; + } +} + +class _BlendedDecorationImagePainter implements DecorationImagePainter { + _BlendedDecorationImagePainter._(this.a, this.b, this.t); + + final DecorationImagePainter? a; + final DecorationImagePainter? b; + final double t; + + @override + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { + a?.paint(canvas, rect, clipPath, configuration, blend: blend * (1.0 - t), blendMode: blendMode); + b?.paint(canvas, rect, clipPath, configuration, blend: blend * t, blendMode: a != null ? BlendMode.plus : blendMode); + } + + @override + void dispose() { + a?.dispose(); + b?.dispose(); + } + + @override + String toString() { + return '${objectRuntimeType(this, '_BlendedDecorationImagePainter')}($a, $b, $t)'; + } +} diff --git a/packages/flutter/lib/src/painting/shape_decoration.dart b/packages/flutter/lib/src/painting/shape_decoration.dart index 20785bced2150..bf7a0e872d132 100644 --- a/packages/flutter/lib/src/painting/shape_decoration.dart +++ b/packages/flutter/lib/src/painting/shape_decoration.dart @@ -237,7 +237,7 @@ class ShapeDecoration extends Decoration { return ShapeDecoration( color: Color.lerp(a?.color, b?.color, t), gradient: Gradient.lerp(a?.gradient, b?.gradient, t), - image: t < 0.5 ? a?.image : b?.image, // TODO(ianh): cross-fade the image + image: DecorationImage.lerp(a?.image, b?.image, t), shadows: BoxShadow.lerpList(a?.shadows, b?.shadows, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t)!, ); diff --git a/packages/flutter/test/painting/decoration_image_lerp_test.dart b/packages/flutter/test/painting/decoration_image_lerp_test.dart new file mode 100644 index 0000000000000..1e0f6f4998cc8 --- /dev/null +++ b/packages/flutter/test/painting/decoration_image_lerp_test.dart @@ -0,0 +1,440 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is run as part of a reduced test set in CI on Mac and Windows +// machines because it contains golden tests; see: +// https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter#reduced-test-set-tag +@Tags(['reduced-test-set']) +library; + +import 'dart:async'; +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('ImageDecoration.lerp', (WidgetTester tester) async { + final MemoryImage green = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, + 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0x00, 0x34, 0x5e, 0xc0, 0xa8, + 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82, + ])); + final MemoryImage red = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, + 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x00, 0x00, 0x19, 0xe2, 0x09, 0x37, + 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82, + ])); + + await tester.runAsync(() async { + await load(green); + await load(red); + }); + + await tester.pumpWidget( + ColoredBox( + color: Colors.white, + child: Align( + alignment: Alignment.topLeft, + child: RepaintBoundary( + child: Wrap( + textDirection: TextDirection.ltr, + children: [ + TestImage( + DecorationImage(image: green, repeat: ImageRepeat.repeat) + ), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.1, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.2, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.8, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.9, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 1.0, + )), + TestImage( + DecorationImage(image: red, repeat: ImageRepeat.repeat), + ), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + t, + )), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + t, + )), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + t, + )), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + t, + )), + ], + ), + ), + ), + ), + ); + + await expectLater( + find.byType(Wrap), + matchesGoldenFile('decoration_image.lerp.0.png'), + ); + + if (!kIsWeb) { // TODO(ianh): https://github.com/flutter/flutter/issues/130610 + final ui.Image image = (await tester.binding.runAsync(() => captureImage(find.byType(Wrap).evaluate().single)))!; + final Uint8List bytes = (await tester.binding.runAsync(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!.buffer.asUint8List(); + expect(image.width, 792); + expect(image.height, 48); + expect(bytes, hasLength(image.width * image.height * 4)); + Color getPixel(int x, int y) { + final int offset = (x + y * image.width) * 4; + return Color.fromARGB(0xFF, bytes[offset], bytes[offset + 1], bytes[offset + 2]); + } + Color getBlockPixel(int index) { + int x = 12 + index * 24; + final int y = 12 + (x ~/ image.width) * 24; + x %= image.width; + return getPixel(x, y); + } + const Color lime = Color(0xFF00FF00); + expect(getBlockPixel(0), lime); // pure green + expect(getBlockPixel(1), lime); // 100% green 0% red + expect(getBlockPixel(2), const Color(0xFF19E600)); + expect(getBlockPixel(3), const Color(0xFF33CC00)); + expect(getBlockPixel(4), const Color(0xFF808000)); // 50-50 mix green/red + expect(getBlockPixel(5), const Color(0xFFCD3200)); + expect(getBlockPixel(6), const Color(0xFFE61900)); + expect(getBlockPixel(7), const Color(0xFFFF0000)); // 0% green 100% red + expect(getBlockPixel(8), const Color(0xFFFF0000)); // pure red + for (int index = 9; index < 40; index += 1) { + expect(getBlockPixel(index), lime); + } + } + }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 + + testWidgets('ImageDecoration.lerp', (WidgetTester tester) async { + final MemoryImage cmyk = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, + 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x4c, 0x59, 0x13, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x63, 0x60, 0x05, 0xc2, 0xf5, 0x0c, 0xeb, 0x01, 0x03, 0x00, 0x01, 0x69, 0x19, + 0xea, 0x34, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + ])); + final MemoryImage wrgb = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, + 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0x00, 0x1e, 0x46, 0xbb, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x63, 0xe0, 0x07, 0xc2, 0xa5, 0x0c, 0x4b, 0x01, 0x03, 0x50, 0x01, 0x69, 0x4a, + 0x78, 0x1d, 0x41, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + ])); + + await tester.runAsync(() async { + await load(cmyk); + await load(wrgb); + }); + + await tester.pumpWidget( + ColoredBox( + color: Colors.white, + child: Align( + alignment: Alignment.topLeft, + child: RepaintBoundary( + child: Wrap( + textDirection: TextDirection.ltr, + children: [ + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.1, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.2, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.8, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.9, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 1.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.cover), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeatY), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeatX), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, scale: 0.5, repeat: ImageRepeat.repeatX), + DecorationImage(image: cmyk, scale: 0.25, repeat: ImageRepeat.repeatY), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 1.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 1.0, + )), + ], + ), + ), + ), + ), + ); + + await expectLater( + find.byType(Wrap), + matchesGoldenFile('decoration_image.lerp.1.png'), + ); + + if (!kIsWeb) { // TODO(ianh): https://github.com/flutter/flutter/issues/130610 + final ui.Image image = (await tester.binding.runAsync(() => captureImage(find.byType(Wrap).evaluate().single)))!; + final Uint8List bytes = (await tester.binding.runAsync(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!.buffer.asUint8List(); + expect(image.width, 24 * 24); + expect(image.height, 1 * 24); + expect(bytes, hasLength(image.width * image.height * 4)); + Color getPixel(int x, int y) { + final int offset = (x + y * image.width) * 4; + return Color.fromARGB(0xFF, bytes[offset], bytes[offset + 1], bytes[offset + 2]); + } + Color getPixelFromBlock(int index, int dx, int dy) { + const int padding = 2; + int x = index * 24 + dx + padding; + final int y = (x ~/ image.width) * 24 + dy + padding; + x %= image.width; + return getPixel(x, y); + } + // wrgb image + expect(getPixelFromBlock(0, 5, 5), const Color(0xFFFFFFFF)); + expect(getPixelFromBlock(0, 15, 5), const Color(0xFFFF0000)); + expect(getPixelFromBlock(0, 5, 15), const Color(0xFF00FF00)); + expect(getPixelFromBlock(0, 15, 15), const Color(0xFF0000FF)); + // wrgb/cmyk 50/50 blended image + expect(getPixelFromBlock(3, 5, 5), const Color(0xFF80FFFF)); + expect(getPixelFromBlock(3, 15, 5), const Color(0xFFFF0080)); + expect(getPixelFromBlock(3, 5, 15), const Color(0xFF80FF00)); + expect(getPixelFromBlock(3, 15, 15), const Color(0xFF000080)); + // cmyk image + expect(getPixelFromBlock(6, 5, 5), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(6, 15, 5), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(6, 5, 15), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(6, 15, 15), const Color(0xFF000000)); + // top left corner control + expect(getPixelFromBlock(14, 0, 0), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(14, 1, 1), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(14, 2, 0), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(14, 19, 0), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(14, 0, 2), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(14, 0, 19), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(14, 2, 2), const Color(0xFF000000)); + expect(getPixelFromBlock(14, 19, 19), const Color(0xFF000000)); + // bottom right corner control + expect(getPixelFromBlock(19, 0, 0), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(19, 17, 17), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(19, 19, 0), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(19, 19, 17), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(19, 0, 19), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(19, 17, 19), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(19, 18, 18), const Color(0xFF000000)); + expect(getPixelFromBlock(19, 19, 19), const Color(0xFF000000)); + } + }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 +} + +Future load(MemoryImage image) { + final ImageStream stream = image.resolve(ImageConfiguration.empty); + final Completer completer = Completer(); + void listener(ImageInfo image, bool syncCall) { + completer.complete(image); + } + stream.addListener(ImageStreamListener(listener)); + return completer.future; +} + +class TestImage extends StatelessWidget { + TestImage(this.image); // ignore: use_key_in_widget_constructors, prefer_const_constructors_in_immutables + + final DecorationImage? image; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(2.0), + child: SizedBox( + width: 20, + height: 20, + child: DecoratedBox( + decoration: BoxDecoration( + image: image, + ), + ), + ), + ); + } +} From 27e912316f7ad67099d843f8b1249f66663f5631 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 26 Jul 2023 11:09:59 -0700 Subject: [PATCH 0387/1547] Revert "ImageDecoration.lerp" (#131347) Reverts flutter/flutter#130533 Tree breakage. --- analysis_options.yaml | 2 +- packages/flutter/lib/foundation.dart | 1 + packages/flutter/lib/src/foundation/README.md | 9 +- .../flutter/lib/src/foundation/binding.dart | 2 +- .../lib/src/foundation/diagnostics.dart | 2 +- packages/flutter/lib/src/foundation/math.dart | 23 + packages/flutter/lib/src/material/dialog.dart | 3 +- .../lib/src/painting/box_decoration.dart | 4 +- .../lib/src/painting/decoration_image.dart | 183 +------- .../lib/src/painting/shape_decoration.dart | 2 +- .../painting/decoration_image_lerp_test.dart | 440 ------------------ 11 files changed, 59 insertions(+), 612 deletions(-) create mode 100644 packages/flutter/lib/src/foundation/math.dart delete mode 100644 packages/flutter/test/painting/decoration_image_lerp_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index a9d29631e12eb..747d8e24b4750 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -50,7 +50,7 @@ linter: - avoid_field_initializers_in_const_classes # - avoid_final_parameters # incompatible with prefer_final_parameters - avoid_function_literals_in_foreach_calls - # - avoid_implementing_value_types # see https://github.com/dart-lang/linter/issues/4558 + - avoid_implementing_value_types - avoid_init_to_null - avoid_js_rounded_ints # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to diff --git a/packages/flutter/lib/foundation.dart b/packages/flutter/lib/foundation.dart index 378b206d74265..43ac8133870bf 100644 --- a/packages/flutter/lib/foundation.dart +++ b/packages/flutter/lib/foundation.dart @@ -34,6 +34,7 @@ export 'src/foundation/diagnostics.dart'; export 'src/foundation/isolates.dart'; export 'src/foundation/key.dart'; export 'src/foundation/licenses.dart'; +export 'src/foundation/math.dart'; export 'src/foundation/memory_allocations.dart'; export 'src/foundation/node.dart'; export 'src/foundation/object.dart'; diff --git a/packages/flutter/lib/src/foundation/README.md b/packages/flutter/lib/src/foundation/README.md index d32effc8c2381..5e4de0755a288 100644 --- a/packages/flutter/lib/src/foundation/README.md +++ b/packages/flutter/lib/src/foundation/README.md @@ -3,9 +3,9 @@ nothing but core Dart packages. They can't depend on `dart:ui`, they can't depend on any `package:`, and they can't depend on anything outside this directory. -Currently they do depend on dart:ui, but only for `VoidCallback` and -`clampDouble` (and maybe one day `lerpDouble`), which are all intended -to be moved out of `dart:ui` and into `dart:core`. +Currently they do depend on dart:ui, but only for `VoidCallback` (and +maybe one day `lerpDouble`), which are all intended to be moved out +of `dart:ui` and into `dart:core`. There is currently also an unfortunate dependency on the platform dispatcher logic (SingletonFlutterWindow, Brightness, @@ -14,4 +14,5 @@ PlatformDispatcher, window), though that should probably move to the See also: - * https://github.com/dart-lang/sdk/issues/25217 + * https://github.com/dart-lang/sdk/issues/27791 (`VoidCallback`) + * https://github.com/dart-lang/sdk/issues/25217 (`hashValues`, `hashList`, and `lerpDouble`) diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index 83204bd57b227..de0bac79bc6ab 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -22,7 +22,7 @@ import 'print.dart'; import 'service_extensions.dart'; import 'timeline.dart'; -export 'dart:ui' show PlatformDispatcher, SingletonFlutterWindow, clampDouble; // ignore: deprecated_member_use +export 'dart:ui' show PlatformDispatcher, SingletonFlutterWindow; // ignore: deprecated_member_use export 'basic_types.dart' show AsyncCallback, AsyncValueGetter, AsyncValueSetter; diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index e5c1345ade8cc..f4f9d5c4c0bc9 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. import 'dart:math' as math; -import 'dart:ui' show clampDouble; import 'package:meta/meta.dart'; import 'assertions.dart'; import 'constants.dart'; import 'debug.dart'; +import 'math.dart' show clampDouble; import 'object.dart'; // Examples can assume: diff --git a/packages/flutter/lib/src/foundation/math.dart b/packages/flutter/lib/src/foundation/math.dart new file mode 100644 index 0000000000000..053192ad506eb --- /dev/null +++ b/packages/flutter/lib/src/foundation/math.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// Same as [num.clamp] but optimized for non-null [double]. +/// +/// This is faster because it avoids polymorphism, boxing, and special cases for +/// floating point numbers. +// +// See also: //dev/benchmarks/microbenchmarks/lib/foundation/clamp.dart +double clampDouble(double x, double min, double max) { + assert(min <= max && !max.isNaN && !min.isNaN); + if (x < min) { + return min; + } + if (x > max) { + return max; + } + if (x.isNaN) { + return max; + } + return x; +} diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 0b13366825c88..57300b56011a4 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' show clampDouble, lerpDouble; +import 'dart:ui'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart' show clampDouble; import 'color_scheme.dart'; import 'colors.dart'; diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart index e076247d99165..444eb40608130 100644 --- a/packages/flutter/lib/src/painting/box_decoration.dart +++ b/packages/flutter/lib/src/painting/box_decoration.dart @@ -232,7 +232,7 @@ class BoxDecoration extends Decoration { BoxDecoration scale(double factor) { return BoxDecoration( color: Color.lerp(null, color, factor), - image: DecorationImage.lerp(null, image, factor), + image: image, // TODO(ianh): fade the image from transparent border: BoxBorder.lerp(null, border, factor), borderRadius: BorderRadiusGeometry.lerp(null, borderRadius, factor), boxShadow: BoxShadow.lerpList(null, boxShadow, factor), @@ -307,7 +307,7 @@ class BoxDecoration extends Decoration { } return BoxDecoration( color: Color.lerp(a.color, b.color, t), - image: DecorationImage.lerp(a.image, b.image, t), + image: t < 0.5 ? a.image : b.image, // TODO(ianh): cross-fade the image border: BoxBorder.lerp(a.border, b.border, t), borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, b.borderRadius, t), boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t), diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index c91a9f083341d..5c8ed9df0390d 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -177,7 +177,7 @@ class DecorationImage { /// image needs to be repainted, e.g. because it is loading incrementally or /// because it is animated. DecorationImagePainter createPainter(VoidCallback onChanged) { - return _DecorationImagePainter._(this, onChanged); + return DecorationImagePainter._(this, onChanged); } @override @@ -246,28 +246,6 @@ class DecorationImage { ]; return '${objectRuntimeType(this, 'DecorationImage')}(${properties.join(", ")})'; } - - /// Linearly interpolates between two [DecorationImage]s. - /// - /// The `t` argument represents position on the timeline, with 0.0 meaning - /// that the interpolation has not started, returning `a`, 1.0 meaning that - /// the interpolation has finished, returning `b`, and values in between - /// meaning that the interpolation is at the relevant point on the timeline - /// between `a` and `this`. The interpolation can be extrapolated beyond 0.0 - /// and 1.0, so negative values and values greater than 1.0 are valid (and can - /// easily be generated by curves such as [Curves.elasticInOut]). - /// - /// Values for `t` are usually obtained from an [Animation], such as - /// an [AnimationController]. - static DecorationImage? lerp(DecorationImage? a, DecorationImage? b, double t) { - if (identical(a, b) || t == 0.0) { - return a; - } - if (t == 1.0) { - return b; - } - return _BlendedDecorationImage(a, b, t); - } } /// The painter for a [DecorationImage]. @@ -281,7 +259,15 @@ class DecorationImage { /// /// This object should be disposed using the [dispose] method when it is no /// longer needed. -abstract interface class DecorationImagePainter { +class DecorationImagePainter { + DecorationImagePainter._(this._details, this._onChanged); + + final DecorationImage _details; + final VoidCallback _onChanged; + + ImageStream? _imageStream; + ImageInfo? _image; + /// Draw the image onto the given canvas. /// /// The image is drawn at the position and size given by the `rect` argument. @@ -296,34 +282,8 @@ abstract interface class DecorationImagePainter { /// because it had not yet been loaded the first time this method was called, /// then the `onChanged` callback passed to [DecorationImage.createPainter] /// will be called. - /// - /// The `blend` argument specifies the opacity that should be applied to the - /// image due to this image being blended with another. The `blendMode` - /// argument can be specified to override the [DecorationImagePainter]'s - /// default [BlendMode] behavior. It is usually set to [BlendMode.srcOver] if - /// this is the first or only image being blended, and [BlendMode.plus] if it - /// is being blended with an image below. - void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }); + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration) { - /// Releases the resources used by this painter. - /// - /// This should be called whenever the painter is no longer needed. - /// - /// After this method has been called, the object is no longer usable. - void dispose(); -} - -class _DecorationImagePainter implements DecorationImagePainter { - _DecorationImagePainter._(this._details, this._onChanged); - - final DecorationImage _details; - final VoidCallback _onChanged; - - ImageStream? _imageStream; - ImageInfo? _image; - - @override - void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { bool flipHorizontally = false; if (_details.matchTextDirection) { assert(() { @@ -378,11 +338,10 @@ class _DecorationImagePainter implements DecorationImagePainter { centerSlice: _details.centerSlice, repeat: _details.repeat, flipHorizontally: flipHorizontally, - opacity: _details.opacity * blend, + opacity: _details.opacity, filterQuality: _details.filterQuality, invertColors: _details.invertColors, isAntiAlias: _details.isAntiAlias, - blendMode: blendMode, ); if (clipPath != null) { @@ -405,7 +364,12 @@ class _DecorationImagePainter implements DecorationImagePainter { } } - @override + /// Releases the resources used by this painter. + /// + /// This should be called whenever the painter is no longer needed. + /// + /// After this method has been called, the object is no longer usable. + @mustCallSuper void dispose() { _imageStream?.removeListener(ImageStreamListener( _handleImage, @@ -480,7 +444,7 @@ void debugFlushLastFrameImageSizeInfo() { /// corners of the destination rectangle defined by applying `fit`. The /// remaining five regions are drawn by stretching them to fit such that they /// exactly cover the destination rectangle while maintaining their relative -/// positions. See also [Canvas.drawImageNine]. +/// positions. /// /// * `repeat`: If the image does not fill `rect`, whether and how the image /// should be repeated to fill `rect`. By default, the image is not repeated. @@ -526,7 +490,6 @@ void paintImage({ bool invertColors = false, FilterQuality filterQuality = FilterQuality.low, bool isAntiAlias = false, - BlendMode blendMode = BlendMode.srcOver, }) { assert( image.debugGetOpenHandleStackTraces()?.isNotEmpty ?? true, @@ -567,10 +530,9 @@ void paintImage({ if (colorFilter != null) { paint.colorFilter = colorFilter; } - paint.color = Color.fromRGBO(0, 0, 0, clampDouble(opacity, 0.0, 1.0)); + paint.color = Color.fromRGBO(0, 0, 0, opacity); paint.filterQuality = filterQuality; paint.invertColors = invertColors; - paint.blendMode = blendMode; final double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0; final double halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0; final double dx = halfWidthDelta + (flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta; @@ -581,12 +543,6 @@ void paintImage({ // Set to true if we added a saveLayer to the canvas to invert/flip the image. bool invertedCanvas = false; // Output size and destination rect are fully calculated. - - // Implement debug-mode and profile-mode features: - // - cacheWidth/cacheHeight warning - // - debugInvertOversizedImages - // - debugOnPaintImage - // - Flutter.ImageSizesForFrame events in timeline if (!kReleaseMode) { // We can use the devicePixelRatio of the views directly here (instead of // going through a MediaQuery) because if it changes, whatever is aware of @@ -598,6 +554,7 @@ void paintImage({ 0.0, (double previousValue, ui.FlutterView view) => math.max(previousValue, view.devicePixelRatio), ); + final ImageSizeInfo sizeInfo = ImageSizeInfo( // Some ImageProvider implementations may not have given this. source: debugImageLabel ?? '', @@ -642,7 +599,7 @@ void paintImage({ return true; }()); // Avoid emitting events that are the same as those emitted in the last frame. - if (!_lastFrameImageSizeInfo.contains(sizeInfo)) { + if (!kReleaseMode && !_lastFrameImageSizeInfo.contains(sizeInfo)) { final ImageSizeInfo? existingSizeInfo = _pendingImageSizeInfo[sizeInfo.source]; if (existingSizeInfo == null || existingSizeInfo.displaySizeInBytes < sizeInfo.displaySizeInBytes) { _pendingImageSizeInfo[sizeInfo.source!] = sizeInfo; @@ -734,99 +691,3 @@ Iterable _generateImageTileRects(Rect outputRect, Rect fundamentalRect, Im } Rect _scaleRect(Rect rect, double scale) => Rect.fromLTRB(rect.left * scale, rect.top * scale, rect.right * scale, rect.bottom * scale); - -// Implements DecorationImage.lerp when the image is different. -// -// This class just paints both decorations on top of each other, blended together. -// -// The Decoration properties are faked by just forwarded to the target image. -class _BlendedDecorationImage implements DecorationImage { - const _BlendedDecorationImage(this.a, this.b, this.t) : assert(a != null || b != null); - - final DecorationImage? a; - final DecorationImage? b; - final double t; - - @override - ImageProvider get image => b?.image ?? a!.image; - @override - ImageErrorListener? get onError => b?.onError ?? a!.onError; - @override - ColorFilter? get colorFilter => b?.colorFilter ?? a!.colorFilter; - @override - BoxFit? get fit => b?.fit ?? a!.fit; - @override - AlignmentGeometry get alignment => b?.alignment ?? a!.alignment; - @override - Rect? get centerSlice => b?.centerSlice ?? a!.centerSlice; - @override - ImageRepeat get repeat => b?.repeat ?? a!.repeat; - @override - bool get matchTextDirection => b?.matchTextDirection ?? a!.matchTextDirection; - @override - double get scale => b?.scale ?? a!.scale; - @override - double get opacity => b?.opacity ?? a!.opacity; - @override - FilterQuality get filterQuality => b?.filterQuality ?? a!.filterQuality; - @override - bool get invertColors => b?.invertColors ?? a!.invertColors; - @override - bool get isAntiAlias => b?.isAntiAlias ?? a!.isAntiAlias; - - @override - DecorationImagePainter createPainter(VoidCallback onChanged) { - return _BlendedDecorationImagePainter._( - a?.createPainter(onChanged), - b?.createPainter(onChanged), - t, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) { - return true; - } - if (other.runtimeType != runtimeType) { - return false; - } - return other is _BlendedDecorationImage - && other.a == a - && other.b == b - && other.t == t; - } - - @override - int get hashCode => Object.hash(a, b, t); - - @override - String toString() { - return '${objectRuntimeType(this, '_BlendedDecorationImage')}($a, $b, $t)'; - } -} - -class _BlendedDecorationImagePainter implements DecorationImagePainter { - _BlendedDecorationImagePainter._(this.a, this.b, this.t); - - final DecorationImagePainter? a; - final DecorationImagePainter? b; - final double t; - - @override - void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { - a?.paint(canvas, rect, clipPath, configuration, blend: blend * (1.0 - t), blendMode: blendMode); - b?.paint(canvas, rect, clipPath, configuration, blend: blend * t, blendMode: a != null ? BlendMode.plus : blendMode); - } - - @override - void dispose() { - a?.dispose(); - b?.dispose(); - } - - @override - String toString() { - return '${objectRuntimeType(this, '_BlendedDecorationImagePainter')}($a, $b, $t)'; - } -} diff --git a/packages/flutter/lib/src/painting/shape_decoration.dart b/packages/flutter/lib/src/painting/shape_decoration.dart index bf7a0e872d132..20785bced2150 100644 --- a/packages/flutter/lib/src/painting/shape_decoration.dart +++ b/packages/flutter/lib/src/painting/shape_decoration.dart @@ -237,7 +237,7 @@ class ShapeDecoration extends Decoration { return ShapeDecoration( color: Color.lerp(a?.color, b?.color, t), gradient: Gradient.lerp(a?.gradient, b?.gradient, t), - image: DecorationImage.lerp(a?.image, b?.image, t), + image: t < 0.5 ? a?.image : b?.image, // TODO(ianh): cross-fade the image shadows: BoxShadow.lerpList(a?.shadows, b?.shadows, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t)!, ); diff --git a/packages/flutter/test/painting/decoration_image_lerp_test.dart b/packages/flutter/test/painting/decoration_image_lerp_test.dart deleted file mode 100644 index 1e0f6f4998cc8..0000000000000 --- a/packages/flutter/test/painting/decoration_image_lerp_test.dart +++ /dev/null @@ -1,440 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This file is run as part of a reduced test set in CI on Mac and Windows -// machines because it contains golden tests; see: -// https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter#reduced-test-set-tag -@Tags(['reduced-test-set']) -library; - -import 'dart:async'; -import 'dart:ui' as ui; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('ImageDecoration.lerp', (WidgetTester tester) async { - final MemoryImage green = MemoryImage(Uint8List.fromList([ - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, - 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0x00, 0x34, 0x5e, 0xc0, 0xa8, - 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, - 0x60, 0x82, - ])); - final MemoryImage red = MemoryImage(Uint8List.fromList([ - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, - 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x00, 0x00, 0x19, 0xe2, 0x09, 0x37, - 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, - 0x60, 0x82, - ])); - - await tester.runAsync(() async { - await load(green); - await load(red); - }); - - await tester.pumpWidget( - ColoredBox( - color: Colors.white, - child: Align( - alignment: Alignment.topLeft, - child: RepaintBoundary( - child: Wrap( - textDirection: TextDirection.ltr, - children: [ - TestImage( - DecorationImage(image: green, repeat: ImageRepeat.repeat) - ), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 0.0, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 0.1, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 0.2, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 0.8, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 0.9, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: red, repeat: ImageRepeat.repeat), - 1.0, - )), - TestImage( - DecorationImage(image: red, repeat: ImageRepeat.repeat), - ), - for (double t = 0.0; t < 1.0; t += 0.125) - TestImage(DecorationImage.lerp( - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - t, - ), - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - t, - ), - t, - )), - for (double t = 0.0; t < 1.0; t += 0.125) - TestImage(DecorationImage.lerp( - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - 1.0 - t, - ), - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - t, - ), - t, - )), - for (double t = 0.0; t < 1.0; t += 0.125) - TestImage(DecorationImage.lerp( - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - t, - ), - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - 1.0 - t, - ), - t, - )), - for (double t = 0.0; t < 1.0; t += 0.125) - TestImage(DecorationImage.lerp( - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - 1.0 - t, - ), - DecorationImage.lerp( - DecorationImage(image: green, repeat: ImageRepeat.repeat), - DecorationImage(image: green, repeat: ImageRepeat.repeat), - 1.0 - t, - ), - t, - )), - ], - ), - ), - ), - ), - ); - - await expectLater( - find.byType(Wrap), - matchesGoldenFile('decoration_image.lerp.0.png'), - ); - - if (!kIsWeb) { // TODO(ianh): https://github.com/flutter/flutter/issues/130610 - final ui.Image image = (await tester.binding.runAsync(() => captureImage(find.byType(Wrap).evaluate().single)))!; - final Uint8List bytes = (await tester.binding.runAsync(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!.buffer.asUint8List(); - expect(image.width, 792); - expect(image.height, 48); - expect(bytes, hasLength(image.width * image.height * 4)); - Color getPixel(int x, int y) { - final int offset = (x + y * image.width) * 4; - return Color.fromARGB(0xFF, bytes[offset], bytes[offset + 1], bytes[offset + 2]); - } - Color getBlockPixel(int index) { - int x = 12 + index * 24; - final int y = 12 + (x ~/ image.width) * 24; - x %= image.width; - return getPixel(x, y); - } - const Color lime = Color(0xFF00FF00); - expect(getBlockPixel(0), lime); // pure green - expect(getBlockPixel(1), lime); // 100% green 0% red - expect(getBlockPixel(2), const Color(0xFF19E600)); - expect(getBlockPixel(3), const Color(0xFF33CC00)); - expect(getBlockPixel(4), const Color(0xFF808000)); // 50-50 mix green/red - expect(getBlockPixel(5), const Color(0xFFCD3200)); - expect(getBlockPixel(6), const Color(0xFFE61900)); - expect(getBlockPixel(7), const Color(0xFFFF0000)); // 0% green 100% red - expect(getBlockPixel(8), const Color(0xFFFF0000)); // pure red - for (int index = 9; index < 40; index += 1) { - expect(getBlockPixel(index), lime); - } - } - }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 - - testWidgets('ImageDecoration.lerp', (WidgetTester tester) async { - final MemoryImage cmyk = MemoryImage(Uint8List.fromList([ - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, - 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x4c, 0x59, 0x13, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, - 0x54, 0x08, 0xd7, 0x63, 0x60, 0x05, 0xc2, 0xf5, 0x0c, 0xeb, 0x01, 0x03, 0x00, 0x01, 0x69, 0x19, - 0xea, 0x34, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, - ])); - final MemoryImage wrgb = MemoryImage(Uint8List.fromList([ - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, - 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, - 0xff, 0x00, 0xff, 0x00, 0x00, 0x1e, 0x46, 0xbb, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, - 0x54, 0x08, 0xd7, 0x63, 0xe0, 0x07, 0xc2, 0xa5, 0x0c, 0x4b, 0x01, 0x03, 0x50, 0x01, 0x69, 0x4a, - 0x78, 0x1d, 0x41, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, - ])); - - await tester.runAsync(() async { - await load(cmyk); - await load(wrgb); - }); - - await tester.pumpWidget( - ColoredBox( - color: Colors.white, - child: Align( - alignment: Alignment.topLeft, - child: RepaintBoundary( - child: Wrap( - textDirection: TextDirection.ltr, - children: [ - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 0.0, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 0.1, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 0.2, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 0.8, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 0.9, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.contain), - DecorationImage(image: cmyk, fit: BoxFit.contain), - 1.0, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, fit: BoxFit.cover), - DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, repeat: ImageRepeat.repeat), - DecorationImage(image: cmyk, repeat: ImageRepeat.repeatY), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, repeat: ImageRepeat.repeatX), - DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), - DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), - 0.25, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), - DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), - DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), - 0.75, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: wrgb, scale: 0.5, repeat: ImageRepeat.repeatX), - DecorationImage(image: cmyk, scale: 0.25, repeat: ImageRepeat.repeatY), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.0, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.25, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.75, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 1.0, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.0, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.25, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.5, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 0.75, - )), - TestImage(DecorationImage.lerp( - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), - DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), - 1.0, - )), - ], - ), - ), - ), - ), - ); - - await expectLater( - find.byType(Wrap), - matchesGoldenFile('decoration_image.lerp.1.png'), - ); - - if (!kIsWeb) { // TODO(ianh): https://github.com/flutter/flutter/issues/130610 - final ui.Image image = (await tester.binding.runAsync(() => captureImage(find.byType(Wrap).evaluate().single)))!; - final Uint8List bytes = (await tester.binding.runAsync(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!.buffer.asUint8List(); - expect(image.width, 24 * 24); - expect(image.height, 1 * 24); - expect(bytes, hasLength(image.width * image.height * 4)); - Color getPixel(int x, int y) { - final int offset = (x + y * image.width) * 4; - return Color.fromARGB(0xFF, bytes[offset], bytes[offset + 1], bytes[offset + 2]); - } - Color getPixelFromBlock(int index, int dx, int dy) { - const int padding = 2; - int x = index * 24 + dx + padding; - final int y = (x ~/ image.width) * 24 + dy + padding; - x %= image.width; - return getPixel(x, y); - } - // wrgb image - expect(getPixelFromBlock(0, 5, 5), const Color(0xFFFFFFFF)); - expect(getPixelFromBlock(0, 15, 5), const Color(0xFFFF0000)); - expect(getPixelFromBlock(0, 5, 15), const Color(0xFF00FF00)); - expect(getPixelFromBlock(0, 15, 15), const Color(0xFF0000FF)); - // wrgb/cmyk 50/50 blended image - expect(getPixelFromBlock(3, 5, 5), const Color(0xFF80FFFF)); - expect(getPixelFromBlock(3, 15, 5), const Color(0xFFFF0080)); - expect(getPixelFromBlock(3, 5, 15), const Color(0xFF80FF00)); - expect(getPixelFromBlock(3, 15, 15), const Color(0xFF000080)); - // cmyk image - expect(getPixelFromBlock(6, 5, 5), const Color(0xFF00FFFF)); - expect(getPixelFromBlock(6, 15, 5), const Color(0xFFFF00FF)); - expect(getPixelFromBlock(6, 5, 15), const Color(0xFFFFFF00)); - expect(getPixelFromBlock(6, 15, 15), const Color(0xFF000000)); - // top left corner control - expect(getPixelFromBlock(14, 0, 0), const Color(0xFF00FFFF)); - expect(getPixelFromBlock(14, 1, 1), const Color(0xFF00FFFF)); - expect(getPixelFromBlock(14, 2, 0), const Color(0xFFFF00FF)); - expect(getPixelFromBlock(14, 19, 0), const Color(0xFFFF00FF)); - expect(getPixelFromBlock(14, 0, 2), const Color(0xFFFFFF00)); - expect(getPixelFromBlock(14, 0, 19), const Color(0xFFFFFF00)); - expect(getPixelFromBlock(14, 2, 2), const Color(0xFF000000)); - expect(getPixelFromBlock(14, 19, 19), const Color(0xFF000000)); - // bottom right corner control - expect(getPixelFromBlock(19, 0, 0), const Color(0xFF00FFFF)); - expect(getPixelFromBlock(19, 17, 17), const Color(0xFF00FFFF)); - expect(getPixelFromBlock(19, 19, 0), const Color(0xFFFF00FF)); - expect(getPixelFromBlock(19, 19, 17), const Color(0xFFFF00FF)); - expect(getPixelFromBlock(19, 0, 19), const Color(0xFFFFFF00)); - expect(getPixelFromBlock(19, 17, 19), const Color(0xFFFFFF00)); - expect(getPixelFromBlock(19, 18, 18), const Color(0xFF000000)); - expect(getPixelFromBlock(19, 19, 19), const Color(0xFF000000)); - } - }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 -} - -Future load(MemoryImage image) { - final ImageStream stream = image.resolve(ImageConfiguration.empty); - final Completer completer = Completer(); - void listener(ImageInfo image, bool syncCall) { - completer.complete(image); - } - stream.addListener(ImageStreamListener(listener)); - return completer.future; -} - -class TestImage extends StatelessWidget { - TestImage(this.image); // ignore: use_key_in_widget_constructors, prefer_const_constructors_in_immutables - - final DecorationImage? image; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(2.0), - child: SizedBox( - width: 20, - height: 20, - child: DecoratedBox( - decoration: BoxDecoration( - image: image, - ), - ), - ), - ); - } -} From 81b0e9f1113c390f9e0b09d0eea1b4c13029c615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:23:37 -0700 Subject: [PATCH 0388/1547] Revert "Run benchmarks with `--omit-type-checks`" (#131353) Reverts flutter/flutter#131102 as it closed the tree due to `Linux web_benchmarks_skwasm` failures. The test seems to be timing out without completing. Example failure: https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20web_benchmarks_skwasm/1/overview --- .ci.yaml | 2 ++ dev/devicelab/lib/tasks/web_benchmarks.dart | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 22ccf43eebb12..ce37a5f61b29d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1079,6 +1079,7 @@ targets: - name: Linux web_benchmarks_html recipe: devicelab/devicelab_drone + presubmit: false timeout: 60 properties: dependencies: >- @@ -1095,6 +1096,7 @@ targets: - .ci.yaml - name: Linux web_benchmarks_skwasm + bringup: true recipe: devicelab/devicelab_drone presubmit: false timeout: 60 diff --git a/dev/devicelab/lib/tasks/web_benchmarks.dart b/dev/devicelab/lib/tasks/web_benchmarks.dart index a4748b8f9f85e..051133c70db7b 100644 --- a/dev/devicelab/lib/tasks/web_benchmarks.dart +++ b/dev/devicelab/lib/tasks/web_benchmarks.dart @@ -36,7 +36,6 @@ Future runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async { if (benchmarkOptions.useWasm) ...[ '--wasm', '--wasm-opt=debug', - '--omit-type-checks', ], '--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true', '--web-renderer=${benchmarkOptions.webRenderer}', From 5d76d1a561240dd7aaf7173dcbe91d5725bc8750 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Wed, 26 Jul 2023 14:24:29 -0700 Subject: [PATCH 0389/1547] Update Unit Tests for M2/M3 (#131292) Updated golden tests in * ink_sparkle_test.dart * material_test.dart * page_test.dart * progress_indicator_test.dart to have M2 and M3 versions. More info in #127064 --- .../test/material/icon_button_test.dart | 2 +- .../test/material/ink_sparkle_test.dart | 65 +++++++++++++- .../flutter/test/material/material_test.dart | 87 ++++++++++++++++++- packages/flutter/test/material/page_test.dart | 47 +++++++++- .../material/progress_indicator_test.dart | 46 +++++++++- 5 files changed, 231 insertions(+), 16 deletions(-) diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index eea26984ef371..81ea567224a95 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -790,7 +790,7 @@ void main() { await tester.pumpWidget( wrap( - useMaterial3: false, + useMaterial3: theme.useMaterial3, child: Column( children: [ IconButton( diff --git a/packages/flutter/test/material/ink_sparkle_test.dart b/packages/flutter/test/material/ink_sparkle_test.dart index b0a44de48949f..1cd3c006896e5 100644 --- a/packages/flutter/test/material/ink_sparkle_test.dart +++ b/packages/flutter/test/material/ink_sparkle_test.dart @@ -93,23 +93,41 @@ void main() { // Goldens // ///////////// - testWidgetsWithLeakTracking('InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'top_left', 0.2); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgetsWithLeakTracking('InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { + await _runM3Test(tester, 'top_left', 0.2); + }, + skip: kIsWeb, // [intended] shaders are not yet supported for web. + ); + + testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'center', 0.5); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgetsWithLeakTracking('InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { + await _runM3Test(tester, 'center', 0.5); + }, + skip: kIsWeb, // [intended] shaders are not yet supported for web. + ); + + testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'bottom_right', 0.8); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); + + testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { + await _runM3Test(tester, 'bottom_right', 0.8); + }, + skip: kIsWeb, // [intended] shaders are not yet supported for web. + ); } Future _runTest(WidgetTester tester, String positionName, double distanceFromTopLeft) async { @@ -146,7 +164,46 @@ Future _runTest(WidgetTester tester, String positionName, double distanceF await tester.pump(const Duration(milliseconds: 50)); await expectLater( repaintFinder, - matchesGoldenFile('ink_sparkle.$positionName.$i.png'), + matchesGoldenFile('m2_ink_sparkle.$positionName.$i.png'), + ); + } +} + +Future _runM3Test(WidgetTester tester, String positionName, double distanceFromTopLeft) async { + final Key repaintKey = UniqueKey(); + final Key buttonKey = UniqueKey(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: Center( + child: RepaintBoundary( + key: repaintKey, + child: ElevatedButton( + key: buttonKey, + style: ElevatedButton.styleFrom(splashFactory: InkSparkle.constantTurbulenceSeedSplashFactory), + child: const Text('Sparkle!'), + onPressed: () { }, + ), + ), + ), + ), + )); + + final Finder buttonFinder = find.byKey(buttonKey); + final Finder repaintFinder = find.byKey(repaintKey); + final Offset topLeft = tester.getTopLeft(buttonFinder); + final Offset bottomRight = tester.getBottomRight(buttonFinder); + + await _warmUpShader(tester, buttonFinder); + + final Offset target = topLeft + (bottomRight - topLeft) * distanceFromTopLeft; + await tester.tapAt(target); + for (int i = 0; i <= 5; i++) { + await tester.pump(const Duration(milliseconds: 50)); + await expectLater( + repaintFinder, + matchesGoldenFile('m3_ink_sparkle.$positionName.$i.png'), ); } } diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index 2832acb09e8cd..33bc9c85b246a 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -921,7 +921,7 @@ void main() { expect(box, isNot(paints..circle())); }); - testWidgetsWithLeakTracking('border is painted above child by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - border is painted above child by default', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -956,11 +956,50 @@ void main() { await expectLater( find.byKey(painterKey), - matchesGoldenFile('material.border_paint_above.png'), + matchesGoldenFile('m2_material.border_paint_above.png'), ); }); - testWidgetsWithLeakTracking('border is painted below child when specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - border is painted above child by default', (WidgetTester tester) async { + final Key painterKey = UniqueKey(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: RepaintBoundary( + key: painterKey, + child: Card( + child: SizedBox( + width: 200, + height: 300, + child: Material( + clipBehavior: Clip.hardEdge, + shape: const RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 6), + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + child: Column( + children: [ + Container( + color: Colors.green, + height: 150, + ), + ], + ), + ), + ), + ), + ), + ), + )); + + await expectLater( + find.byKey(painterKey), + matchesGoldenFile('m3_material.border_paint_above.png'), + ); + }); + + testWidgetsWithLeakTracking('Material2 - border is painted below child when specified', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -996,7 +1035,47 @@ void main() { await expectLater( find.byKey(painterKey), - matchesGoldenFile('material.border_paint_below.png'), + matchesGoldenFile('m2_material.border_paint_below.png'), + ); + }); + + testWidgetsWithLeakTracking('Material3 - border is painted below child when specified', (WidgetTester tester) async { + final Key painterKey = UniqueKey(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: RepaintBoundary( + key: painterKey, + child: Card( + child: SizedBox( + width: 200, + height: 300, + child: Material( + clipBehavior: Clip.hardEdge, + shape: const RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 6), + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + borderOnForeground: false, + child: Column( + children: [ + Container( + color: Colors.green, + height: 150, + ), + ], + ), + ), + ), + ), + ), + ), + )); + + await expectLater( + find.byKey(painterKey), + matchesGoldenFile('m3_material.border_paint_below.png'), ); }); }); diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index b0486a9cfac82..a09d980067bf9 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -240,7 +240,7 @@ void main() { expect(find.text('Page 2'), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + testWidgets('Material2 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1000, 1000); tester.view.viewInsets = FakeViewPadding.zero; @@ -270,7 +270,7 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); - await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.small.png')); + await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.small.png')); // Change the view insets. tester.view.viewInsets = const FakeViewPadding(bottom: 500); @@ -278,7 +278,48 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); - await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.big.png')); + await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.big.png')); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. + + testWidgets('Material3 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + addTearDown(tester.view.reset); + tester.view.physicalSize = const Size(1000, 1000); + tester.view.viewInsets = FakeViewPadding.zero; + + // Intentionally use nested scaffolds to simulate the view insets being + // consumed. + final Key key = GlobalKey(); + await tester.pumpWidget( + RepaintBoundary( + key: key, + child: MaterialApp( + theme: ThemeData(useMaterial3: true), + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + builder: (BuildContext context) { + return const Scaffold(body: Scaffold( + body: Material(child: SizedBox.shrink()) + )); + }, + ); + }, + ), + ), + ); + + tester.state(find.byType(Navigator)).pushNamed('/next'); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.small.png')); + + // Change the view insets. + tester.view.viewInsets = const FakeViewPadding(bottom: 500); + + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.big.png')); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. testWidgets( diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 875ab00e30d3e..886539bc361bb 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -720,7 +720,7 @@ void main() { expect(tester.hasRunningAnimations, isTrue); }); - testWidgets('RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgets('Material2 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); await tester.pumpFrames(animationSheet.record( @@ -732,7 +732,23 @@ void main() { await expectLater( await animationSheet.collate(20), - matchesGoldenFile('material.refresh_progress_indicator.png'), + matchesGoldenFile('m2_material.refresh_progress_indicator.png'), + ); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + + testWidgets('Material3 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); + + await tester.pumpFrames(animationSheet.record( + Theme( + data: ThemeData(useMaterial3: true), + child: const _RefreshProgressIndicatorGolden() + ), + ), const Duration(seconds: 3)); + + await expectLater( + await animationSheet.collate(20), + matchesGoldenFile('m3_material.refresh_progress_indicator.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 @@ -1001,7 +1017,7 @@ void main() { handle.dispose(); }); - testWidgets('Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgets('Material2 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); await tester.pumpFrames(animationSheet.record( @@ -1019,7 +1035,29 @@ void main() { await expectLater( await animationSheet.collate(20), - matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'), + matchesGoldenFile('m2_material.circular_progress_indicator.indeterminate.png'), + ); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + + testWidgets('Material3 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); + + await tester.pumpFrames(animationSheet.record( + Theme( + data: ThemeData(useMaterial3: true), + child: const Directionality( + textDirection: TextDirection.ltr, + child: Padding( + padding: EdgeInsets.all(4), + child: CircularProgressIndicator(), + ), + ), + ), + ), const Duration(seconds: 2)); + + await expectLater( + await animationSheet.collate(20), + matchesGoldenFile('m3_material.circular_progress_indicator.indeterminate.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 From f359d9e27a5e53324173d6b7dbcab3b696d6bedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 26 Jul 2023 15:46:20 -0700 Subject: [PATCH 0390/1547] Revert "Update Unit Tests for M2/M3" (#131368) Reverts flutter/flutter#131292 This PR is affected by https://g-issues.skia.org/issues/40045533. See @Piinks's [explanation](https://discord.com/channels/608014603317936148/613398423093116959/1133885989358678076): > The mirror is probably out of sync. The failing commit introduced new changes, but they have not been updated yet. I would revert the PR until we can check the mirror. Last week it went 2+ hours out of sync so rerunning it may not green the tree for a while. --- .../test/material/icon_button_test.dart | 2 +- .../test/material/ink_sparkle_test.dart | 65 +------------- .../flutter/test/material/material_test.dart | 87 +------------------ packages/flutter/test/material/page_test.dart | 47 +--------- .../material/progress_indicator_test.dart | 46 +--------- 5 files changed, 16 insertions(+), 231 deletions(-) diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 81ea567224a95..eea26984ef371 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -790,7 +790,7 @@ void main() { await tester.pumpWidget( wrap( - useMaterial3: theme.useMaterial3, + useMaterial3: false, child: Column( children: [ IconButton( diff --git a/packages/flutter/test/material/ink_sparkle_test.dart b/packages/flutter/test/material/ink_sparkle_test.dart index 1cd3c006896e5..b0a44de48949f 100644 --- a/packages/flutter/test/material/ink_sparkle_test.dart +++ b/packages/flutter/test/material/ink_sparkle_test.dart @@ -93,41 +93,23 @@ void main() { // Goldens // ///////////// - testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'top_left', 0.2); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { - await _runM3Test(tester, 'top_left', 0.2); - }, - skip: kIsWeb, // [intended] shaders are not yet supported for web. - ); - - testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'center', 0.5); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { - await _runM3Test(tester, 'center', 0.5); - }, - skip: kIsWeb, // [intended] shaders are not yet supported for web. - ); - - testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'bottom_right', 0.8); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - - testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { - await _runM3Test(tester, 'bottom_right', 0.8); - }, - skip: kIsWeb, // [intended] shaders are not yet supported for web. - ); } Future _runTest(WidgetTester tester, String positionName, double distanceFromTopLeft) async { @@ -164,46 +146,7 @@ Future _runTest(WidgetTester tester, String positionName, double distanceF await tester.pump(const Duration(milliseconds: 50)); await expectLater( repaintFinder, - matchesGoldenFile('m2_ink_sparkle.$positionName.$i.png'), - ); - } -} - -Future _runM3Test(WidgetTester tester, String positionName, double distanceFromTopLeft) async { - final Key repaintKey = UniqueKey(); - final Key buttonKey = UniqueKey(); - - await tester.pumpWidget(MaterialApp( - theme: ThemeData(useMaterial3: true), - home: Scaffold( - body: Center( - child: RepaintBoundary( - key: repaintKey, - child: ElevatedButton( - key: buttonKey, - style: ElevatedButton.styleFrom(splashFactory: InkSparkle.constantTurbulenceSeedSplashFactory), - child: const Text('Sparkle!'), - onPressed: () { }, - ), - ), - ), - ), - )); - - final Finder buttonFinder = find.byKey(buttonKey); - final Finder repaintFinder = find.byKey(repaintKey); - final Offset topLeft = tester.getTopLeft(buttonFinder); - final Offset bottomRight = tester.getBottomRight(buttonFinder); - - await _warmUpShader(tester, buttonFinder); - - final Offset target = topLeft + (bottomRight - topLeft) * distanceFromTopLeft; - await tester.tapAt(target); - for (int i = 0; i <= 5; i++) { - await tester.pump(const Duration(milliseconds: 50)); - await expectLater( - repaintFinder, - matchesGoldenFile('m3_ink_sparkle.$positionName.$i.png'), + matchesGoldenFile('ink_sparkle.$positionName.$i.png'), ); } } diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index 33bc9c85b246a..2832acb09e8cd 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -921,7 +921,7 @@ void main() { expect(box, isNot(paints..circle())); }); - testWidgetsWithLeakTracking('Material2 - border is painted above child by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is painted above child by default', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -956,50 +956,11 @@ void main() { await expectLater( find.byKey(painterKey), - matchesGoldenFile('m2_material.border_paint_above.png'), + matchesGoldenFile('material.border_paint_above.png'), ); }); - testWidgetsWithLeakTracking('Material3 - border is painted above child by default', (WidgetTester tester) async { - final Key painterKey = UniqueKey(); - - await tester.pumpWidget(MaterialApp( - theme: ThemeData(useMaterial3: true), - home: Scaffold( - body: RepaintBoundary( - key: painterKey, - child: Card( - child: SizedBox( - width: 200, - height: 300, - child: Material( - clipBehavior: Clip.hardEdge, - shape: const RoundedRectangleBorder( - side: BorderSide(color: Colors.grey, width: 6), - borderRadius: BorderRadius.all(Radius.circular(8)), - ), - child: Column( - children: [ - Container( - color: Colors.green, - height: 150, - ), - ], - ), - ), - ), - ), - ), - ), - )); - - await expectLater( - find.byKey(painterKey), - matchesGoldenFile('m3_material.border_paint_above.png'), - ); - }); - - testWidgetsWithLeakTracking('Material2 - border is painted below child when specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('border is painted below child when specified', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -1035,47 +996,7 @@ void main() { await expectLater( find.byKey(painterKey), - matchesGoldenFile('m2_material.border_paint_below.png'), - ); - }); - - testWidgetsWithLeakTracking('Material3 - border is painted below child when specified', (WidgetTester tester) async { - final Key painterKey = UniqueKey(); - - await tester.pumpWidget(MaterialApp( - theme: ThemeData(useMaterial3: true), - home: Scaffold( - body: RepaintBoundary( - key: painterKey, - child: Card( - child: SizedBox( - width: 200, - height: 300, - child: Material( - clipBehavior: Clip.hardEdge, - shape: const RoundedRectangleBorder( - side: BorderSide(color: Colors.grey, width: 6), - borderRadius: BorderRadius.all(Radius.circular(8)), - ), - borderOnForeground: false, - child: Column( - children: [ - Container( - color: Colors.green, - height: 150, - ), - ], - ), - ), - ), - ), - ), - ), - )); - - await expectLater( - find.byKey(painterKey), - matchesGoldenFile('m3_material.border_paint_below.png'), + matchesGoldenFile('material.border_paint_below.png'), ); }); }); diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index a09d980067bf9..b0486a9cfac82 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -240,7 +240,7 @@ void main() { expect(find.text('Page 2'), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Material2 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + testWidgets('test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1000, 1000); tester.view.viewInsets = FakeViewPadding.zero; @@ -270,7 +270,7 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); - await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.small.png')); + await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.small.png')); // Change the view insets. tester.view.viewInsets = const FakeViewPadding(bottom: 500); @@ -278,48 +278,7 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); - await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.big.png')); - }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - - testWidgets('Material3 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { - addTearDown(tester.view.reset); - tester.view.physicalSize = const Size(1000, 1000); - tester.view.viewInsets = FakeViewPadding.zero; - - // Intentionally use nested scaffolds to simulate the view insets being - // consumed. - final Key key = GlobalKey(); - await tester.pumpWidget( - RepaintBoundary( - key: key, - child: MaterialApp( - theme: ThemeData(useMaterial3: true), - onGenerateRoute: (RouteSettings settings) { - return MaterialPageRoute( - builder: (BuildContext context) { - return const Scaffold(body: Scaffold( - body: Material(child: SizedBox.shrink()) - )); - }, - ); - }, - ), - ), - ); - - tester.state(find.byType(Navigator)).pushNamed('/next'); - await tester.pump(); - await tester.pump(const Duration(milliseconds: 50)); - - await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.small.png')); - - // Change the view insets. - tester.view.viewInsets = const FakeViewPadding(bottom: 500); - - await tester.pump(); - await tester.pump(const Duration(milliseconds: 50)); - - await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.big.png')); + await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.big.png')); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. testWidgets( diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 886539bc361bb..875ab00e30d3e 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -720,7 +720,7 @@ void main() { expect(tester.hasRunningAnimations, isTrue); }); - testWidgets('Material2 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgets('RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); await tester.pumpFrames(animationSheet.record( @@ -732,23 +732,7 @@ void main() { await expectLater( await animationSheet.collate(20), - matchesGoldenFile('m2_material.refresh_progress_indicator.png'), - ); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - - testWidgets('Material3 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { - final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); - - await tester.pumpFrames(animationSheet.record( - Theme( - data: ThemeData(useMaterial3: true), - child: const _RefreshProgressIndicatorGolden() - ), - ), const Duration(seconds: 3)); - - await expectLater( - await animationSheet.collate(20), - matchesGoldenFile('m3_material.refresh_progress_indicator.png'), + matchesGoldenFile('material.refresh_progress_indicator.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 @@ -1017,7 +1001,7 @@ void main() { handle.dispose(); }); - testWidgets('Material2 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgets('Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); await tester.pumpFrames(animationSheet.record( @@ -1035,29 +1019,7 @@ void main() { await expectLater( await animationSheet.collate(20), - matchesGoldenFile('m2_material.circular_progress_indicator.indeterminate.png'), - ); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - - testWidgets('Material3 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { - final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); - - await tester.pumpFrames(animationSheet.record( - Theme( - data: ThemeData(useMaterial3: true), - child: const Directionality( - textDirection: TextDirection.ltr, - child: Padding( - padding: EdgeInsets.all(4), - child: CircularProgressIndicator(), - ), - ), - ), - ), const Duration(seconds: 2)); - - await expectLater( - await animationSheet.collate(20), - matchesGoldenFile('m3_material.circular_progress_indicator.indeterminate.png'), + matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 From bb0c3172f84abb5d55986df48ed76a60e8efc0e4 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 26 Jul 2023 18:21:05 -0500 Subject: [PATCH 0391/1547] Minor adjustments on 2D APIs (#131358) These tweaks came from https://github.com/flutter/packages/pull/4536 - The TwoDimensionalChildBuilderDelegate asserts that maxXIndex and maxYIndex are null or >= 0 - The TwoDimensionalChildDelegate setter in RenderTwoDimensionalViewport has a covariant to allow type safety for subclasses of RenderTwoDimensionalViewport implementing with other subclasses of TwoDimensionalChildDelegate I'd like to cherry pick this so https://github.com/flutter/packages/pull/4536 will not have to wait for it to reach stable. --- .../lib/src/widgets/scroll_delegate.dart | 8 +- .../src/widgets/two_dimensional_viewport.dart | 2 +- .../two_dimensional_viewport_test.dart | 97 +++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/scroll_delegate.dart b/packages/flutter/lib/src/widgets/scroll_delegate.dart index 28f9e28e13a3a..765bf31d8a1a7 100644 --- a/packages/flutter/lib/src/widgets/scroll_delegate.dart +++ b/packages/flutter/lib/src/widgets/scroll_delegate.dart @@ -933,7 +933,9 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { required this.builder, int? maxXIndex, int? maxYIndex, - }) : _maxYIndex = maxYIndex, + }) : assert(maxYIndex == null || maxYIndex >= 0), + assert(maxXIndex == null || maxXIndex >= 0), + _maxYIndex = maxYIndex, _maxXIndex = maxXIndex; /// Called to build children on demand. @@ -974,6 +976,8 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { /// [TwoDimensionalViewport] subclass to learn how this value is applied in /// the specific use case. /// + /// If not null, the value must be non-negative. + /// /// If the value changes, the delegate will call [notifyListeners]. This /// informs the [RenderTwoDimensionalViewport] that any cached information /// from the delegate is invalid. @@ -993,6 +997,7 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { if (value == maxXIndex) { return; } + assert(value == null || value >= 0); _maxXIndex = value; notifyListeners(); } @@ -1015,6 +1020,7 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { if (maxYIndex == value) { return; } + assert(value == null || value >= 0); _maxYIndex = value; notifyListeners(); } diff --git a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart index 69976eb1e48c7..82befbce08432 100644 --- a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart +++ b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart @@ -612,7 +612,7 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA /// Supplies children for layout in the viewport. TwoDimensionalChildDelegate get delegate => _delegate; TwoDimensionalChildDelegate _delegate; - set delegate(TwoDimensionalChildDelegate value) { + set delegate(covariant TwoDimensionalChildDelegate value) { if (_delegate == value) { return; } diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index b44fac359e337..a445d3412c97b 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -111,6 +111,78 @@ void main() { ); }, variant: TargetPlatformVariant.all()); + test('maxXIndex and maxYIndex assertions', () { + final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( + maxXIndex: 0, + maxYIndex: 0, + builder: (BuildContext context, ChildVicinity vicinity) { + return const SizedBox.shrink(); + } + ); + // Update + expect( + () { + delegate.maxXIndex = -1; + }, + throwsA( + isA().having( + (AssertionError error) => error.toString(), + 'description', + contains('value == null || value >= 0'), + ), + ), + ); + expect( + () { + delegate.maxYIndex = -1; + }, + throwsA( + isA().having( + (AssertionError error) => error.toString(), + 'description', + contains('value == null || value >= 0'), + ), + ), + ); + // Constructor + expect( + () { + TwoDimensionalChildBuilderDelegate( + maxXIndex: -1, + maxYIndex: 0, + builder: (BuildContext context, ChildVicinity vicinity) { + return const SizedBox.shrink(); + } + ); + }, + throwsA( + isA().having( + (AssertionError error) => error.toString(), + 'description', + contains('maxXIndex == null || maxXIndex >= 0'), + ), + ), + ); + expect( + () { + TwoDimensionalChildBuilderDelegate( + maxXIndex: 0, + maxYIndex: -1, + builder: (BuildContext context, ChildVicinity vicinity) { + return const SizedBox.shrink(); + } + ); + }, + throwsA( + isA().having( + (AssertionError error) => error.toString(), + 'description', + contains('maxYIndex == null || maxYIndex >= 0'), + ), + ), + ); + }); + testWidgets('throws an error when builder throws', (WidgetTester tester) async { final List exceptions = []; final FlutterExceptionHandler? oldHandler = FlutterError.onError; @@ -1822,3 +1894,28 @@ Future restoreScrollAndVerify(WidgetTester tester) async { 100.0, ); } + +// Validates covariant through analysis. +mixin _SomeDelegateMixin on TwoDimensionalChildDelegate {} + +class _SomeRenderTwoDimensionalViewport extends RenderTwoDimensionalViewport { // ignore: unused_element + _SomeRenderTwoDimensionalViewport({ + required super.horizontalOffset, + required super.horizontalAxisDirection, + required super.verticalOffset, + required super.verticalAxisDirection, + required _SomeDelegateMixin super.delegate, + required super.mainAxis, + required super.childManager, + }); + + @override + _SomeDelegateMixin get delegate => super.delegate as _SomeDelegateMixin; + @override + set delegate(_SomeDelegateMixin value) { // Analysis would fail without covariant + super.delegate = value; + } + + @override + void layoutChildSequence() {} +} From 33e9fd89347a4d52c24fc6378d76ec3e9657f2ab Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 26 Jul 2023 16:48:08 -0700 Subject: [PATCH 0392/1547] ImageDecoration.lerp (#130533) (#131349) This primarily implements DecorationImage.lerp(). It also makes some minor tweaks, the main one of which is defering to dart:ui for `clampDouble` instead of duplicating it in package:foundation. Fixes https://github.com/flutter/flutter/issues/12452 This was first landed in https://github.com/flutter/flutter/pull/130533 and reverted in https://github.com/flutter/flutter/pull/131347. --- analysis_options.yaml | 2 +- packages/flutter/lib/foundation.dart | 1 - packages/flutter/lib/src/foundation/README.md | 9 +- .../flutter/lib/src/foundation/binding.dart | 2 +- .../lib/src/foundation/diagnostics.dart | 2 +- packages/flutter/lib/src/foundation/math.dart | 23 - packages/flutter/lib/src/material/dialog.dart | 3 +- .../lib/src/painting/box_decoration.dart | 4 +- .../lib/src/painting/decoration_image.dart | 183 +++++++- .../lib/src/painting/shape_decoration.dart | 2 +- .../painting/decoration_image_lerp_test.dart | 440 ++++++++++++++++++ 11 files changed, 612 insertions(+), 59 deletions(-) delete mode 100644 packages/flutter/lib/src/foundation/math.dart create mode 100644 packages/flutter/test/painting/decoration_image_lerp_test.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 747d8e24b4750..a9d29631e12eb 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -50,7 +50,7 @@ linter: - avoid_field_initializers_in_const_classes # - avoid_final_parameters # incompatible with prefer_final_parameters - avoid_function_literals_in_foreach_calls - - avoid_implementing_value_types + # - avoid_implementing_value_types # see https://github.com/dart-lang/linter/issues/4558 - avoid_init_to_null - avoid_js_rounded_ints # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to diff --git a/packages/flutter/lib/foundation.dart b/packages/flutter/lib/foundation.dart index 43ac8133870bf..378b206d74265 100644 --- a/packages/flutter/lib/foundation.dart +++ b/packages/flutter/lib/foundation.dart @@ -34,7 +34,6 @@ export 'src/foundation/diagnostics.dart'; export 'src/foundation/isolates.dart'; export 'src/foundation/key.dart'; export 'src/foundation/licenses.dart'; -export 'src/foundation/math.dart'; export 'src/foundation/memory_allocations.dart'; export 'src/foundation/node.dart'; export 'src/foundation/object.dart'; diff --git a/packages/flutter/lib/src/foundation/README.md b/packages/flutter/lib/src/foundation/README.md index 5e4de0755a288..d32effc8c2381 100644 --- a/packages/flutter/lib/src/foundation/README.md +++ b/packages/flutter/lib/src/foundation/README.md @@ -3,9 +3,9 @@ nothing but core Dart packages. They can't depend on `dart:ui`, they can't depend on any `package:`, and they can't depend on anything outside this directory. -Currently they do depend on dart:ui, but only for `VoidCallback` (and -maybe one day `lerpDouble`), which are all intended to be moved out -of `dart:ui` and into `dart:core`. +Currently they do depend on dart:ui, but only for `VoidCallback` and +`clampDouble` (and maybe one day `lerpDouble`), which are all intended +to be moved out of `dart:ui` and into `dart:core`. There is currently also an unfortunate dependency on the platform dispatcher logic (SingletonFlutterWindow, Brightness, @@ -14,5 +14,4 @@ PlatformDispatcher, window), though that should probably move to the See also: - * https://github.com/dart-lang/sdk/issues/27791 (`VoidCallback`) - * https://github.com/dart-lang/sdk/issues/25217 (`hashValues`, `hashList`, and `lerpDouble`) + * https://github.com/dart-lang/sdk/issues/25217 diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index de0bac79bc6ab..83204bd57b227 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -22,7 +22,7 @@ import 'print.dart'; import 'service_extensions.dart'; import 'timeline.dart'; -export 'dart:ui' show PlatformDispatcher, SingletonFlutterWindow; // ignore: deprecated_member_use +export 'dart:ui' show PlatformDispatcher, SingletonFlutterWindow, clampDouble; // ignore: deprecated_member_use export 'basic_types.dart' show AsyncCallback, AsyncValueGetter, AsyncValueSetter; diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index f4f9d5c4c0bc9..e5c1345ade8cc 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -3,13 +3,13 @@ // found in the LICENSE file. import 'dart:math' as math; +import 'dart:ui' show clampDouble; import 'package:meta/meta.dart'; import 'assertions.dart'; import 'constants.dart'; import 'debug.dart'; -import 'math.dart' show clampDouble; import 'object.dart'; // Examples can assume: diff --git a/packages/flutter/lib/src/foundation/math.dart b/packages/flutter/lib/src/foundation/math.dart deleted file mode 100644 index 053192ad506eb..0000000000000 --- a/packages/flutter/lib/src/foundation/math.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/// Same as [num.clamp] but optimized for non-null [double]. -/// -/// This is faster because it avoids polymorphism, boxing, and special cases for -/// floating point numbers. -// -// See also: //dev/benchmarks/microbenchmarks/lib/foundation/clamp.dart -double clampDouble(double x, double min, double max) { - assert(min <= max && !max.isNaN && !min.isNaN); - if (x < min) { - return min; - } - if (x > max) { - return max; - } - if (x.isNaN) { - return max; - } - return x; -} diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 57300b56011a4..0b13366825c88 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui'; +import 'dart:ui' show clampDouble, lerpDouble; import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart' show clampDouble; import 'color_scheme.dart'; import 'colors.dart'; diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart index 444eb40608130..e076247d99165 100644 --- a/packages/flutter/lib/src/painting/box_decoration.dart +++ b/packages/flutter/lib/src/painting/box_decoration.dart @@ -232,7 +232,7 @@ class BoxDecoration extends Decoration { BoxDecoration scale(double factor) { return BoxDecoration( color: Color.lerp(null, color, factor), - image: image, // TODO(ianh): fade the image from transparent + image: DecorationImage.lerp(null, image, factor), border: BoxBorder.lerp(null, border, factor), borderRadius: BorderRadiusGeometry.lerp(null, borderRadius, factor), boxShadow: BoxShadow.lerpList(null, boxShadow, factor), @@ -307,7 +307,7 @@ class BoxDecoration extends Decoration { } return BoxDecoration( color: Color.lerp(a.color, b.color, t), - image: t < 0.5 ? a.image : b.image, // TODO(ianh): cross-fade the image + image: DecorationImage.lerp(a.image, b.image, t), border: BoxBorder.lerp(a.border, b.border, t), borderRadius: BorderRadiusGeometry.lerp(a.borderRadius, b.borderRadius, t), boxShadow: BoxShadow.lerpList(a.boxShadow, b.boxShadow, t), diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index 5c8ed9df0390d..c91a9f083341d 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -177,7 +177,7 @@ class DecorationImage { /// image needs to be repainted, e.g. because it is loading incrementally or /// because it is animated. DecorationImagePainter createPainter(VoidCallback onChanged) { - return DecorationImagePainter._(this, onChanged); + return _DecorationImagePainter._(this, onChanged); } @override @@ -246,6 +246,28 @@ class DecorationImage { ]; return '${objectRuntimeType(this, 'DecorationImage')}(${properties.join(", ")})'; } + + /// Linearly interpolates between two [DecorationImage]s. + /// + /// The `t` argument represents position on the timeline, with 0.0 meaning + /// that the interpolation has not started, returning `a`, 1.0 meaning that + /// the interpolation has finished, returning `b`, and values in between + /// meaning that the interpolation is at the relevant point on the timeline + /// between `a` and `this`. The interpolation can be extrapolated beyond 0.0 + /// and 1.0, so negative values and values greater than 1.0 are valid (and can + /// easily be generated by curves such as [Curves.elasticInOut]). + /// + /// Values for `t` are usually obtained from an [Animation], such as + /// an [AnimationController]. + static DecorationImage? lerp(DecorationImage? a, DecorationImage? b, double t) { + if (identical(a, b) || t == 0.0) { + return a; + } + if (t == 1.0) { + return b; + } + return _BlendedDecorationImage(a, b, t); + } } /// The painter for a [DecorationImage]. @@ -259,15 +281,7 @@ class DecorationImage { /// /// This object should be disposed using the [dispose] method when it is no /// longer needed. -class DecorationImagePainter { - DecorationImagePainter._(this._details, this._onChanged); - - final DecorationImage _details; - final VoidCallback _onChanged; - - ImageStream? _imageStream; - ImageInfo? _image; - +abstract interface class DecorationImagePainter { /// Draw the image onto the given canvas. /// /// The image is drawn at the position and size given by the `rect` argument. @@ -282,8 +296,34 @@ class DecorationImagePainter { /// because it had not yet been loaded the first time this method was called, /// then the `onChanged` callback passed to [DecorationImage.createPainter] /// will be called. - void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration) { + /// + /// The `blend` argument specifies the opacity that should be applied to the + /// image due to this image being blended with another. The `blendMode` + /// argument can be specified to override the [DecorationImagePainter]'s + /// default [BlendMode] behavior. It is usually set to [BlendMode.srcOver] if + /// this is the first or only image being blended, and [BlendMode.plus] if it + /// is being blended with an image below. + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }); + /// Releases the resources used by this painter. + /// + /// This should be called whenever the painter is no longer needed. + /// + /// After this method has been called, the object is no longer usable. + void dispose(); +} + +class _DecorationImagePainter implements DecorationImagePainter { + _DecorationImagePainter._(this._details, this._onChanged); + + final DecorationImage _details; + final VoidCallback _onChanged; + + ImageStream? _imageStream; + ImageInfo? _image; + + @override + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { bool flipHorizontally = false; if (_details.matchTextDirection) { assert(() { @@ -338,10 +378,11 @@ class DecorationImagePainter { centerSlice: _details.centerSlice, repeat: _details.repeat, flipHorizontally: flipHorizontally, - opacity: _details.opacity, + opacity: _details.opacity * blend, filterQuality: _details.filterQuality, invertColors: _details.invertColors, isAntiAlias: _details.isAntiAlias, + blendMode: blendMode, ); if (clipPath != null) { @@ -364,12 +405,7 @@ class DecorationImagePainter { } } - /// Releases the resources used by this painter. - /// - /// This should be called whenever the painter is no longer needed. - /// - /// After this method has been called, the object is no longer usable. - @mustCallSuper + @override void dispose() { _imageStream?.removeListener(ImageStreamListener( _handleImage, @@ -444,7 +480,7 @@ void debugFlushLastFrameImageSizeInfo() { /// corners of the destination rectangle defined by applying `fit`. The /// remaining five regions are drawn by stretching them to fit such that they /// exactly cover the destination rectangle while maintaining their relative -/// positions. +/// positions. See also [Canvas.drawImageNine]. /// /// * `repeat`: If the image does not fill `rect`, whether and how the image /// should be repeated to fill `rect`. By default, the image is not repeated. @@ -490,6 +526,7 @@ void paintImage({ bool invertColors = false, FilterQuality filterQuality = FilterQuality.low, bool isAntiAlias = false, + BlendMode blendMode = BlendMode.srcOver, }) { assert( image.debugGetOpenHandleStackTraces()?.isNotEmpty ?? true, @@ -530,9 +567,10 @@ void paintImage({ if (colorFilter != null) { paint.colorFilter = colorFilter; } - paint.color = Color.fromRGBO(0, 0, 0, opacity); + paint.color = Color.fromRGBO(0, 0, 0, clampDouble(opacity, 0.0, 1.0)); paint.filterQuality = filterQuality; paint.invertColors = invertColors; + paint.blendMode = blendMode; final double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0; final double halfHeightDelta = (outputSize.height - destinationSize.height) / 2.0; final double dx = halfWidthDelta + (flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta; @@ -543,6 +581,12 @@ void paintImage({ // Set to true if we added a saveLayer to the canvas to invert/flip the image. bool invertedCanvas = false; // Output size and destination rect are fully calculated. + + // Implement debug-mode and profile-mode features: + // - cacheWidth/cacheHeight warning + // - debugInvertOversizedImages + // - debugOnPaintImage + // - Flutter.ImageSizesForFrame events in timeline if (!kReleaseMode) { // We can use the devicePixelRatio of the views directly here (instead of // going through a MediaQuery) because if it changes, whatever is aware of @@ -554,7 +598,6 @@ void paintImage({ 0.0, (double previousValue, ui.FlutterView view) => math.max(previousValue, view.devicePixelRatio), ); - final ImageSizeInfo sizeInfo = ImageSizeInfo( // Some ImageProvider implementations may not have given this. source: debugImageLabel ?? '', @@ -599,7 +642,7 @@ void paintImage({ return true; }()); // Avoid emitting events that are the same as those emitted in the last frame. - if (!kReleaseMode && !_lastFrameImageSizeInfo.contains(sizeInfo)) { + if (!_lastFrameImageSizeInfo.contains(sizeInfo)) { final ImageSizeInfo? existingSizeInfo = _pendingImageSizeInfo[sizeInfo.source]; if (existingSizeInfo == null || existingSizeInfo.displaySizeInBytes < sizeInfo.displaySizeInBytes) { _pendingImageSizeInfo[sizeInfo.source!] = sizeInfo; @@ -691,3 +734,99 @@ Iterable _generateImageTileRects(Rect outputRect, Rect fundamentalRect, Im } Rect _scaleRect(Rect rect, double scale) => Rect.fromLTRB(rect.left * scale, rect.top * scale, rect.right * scale, rect.bottom * scale); + +// Implements DecorationImage.lerp when the image is different. +// +// This class just paints both decorations on top of each other, blended together. +// +// The Decoration properties are faked by just forwarded to the target image. +class _BlendedDecorationImage implements DecorationImage { + const _BlendedDecorationImage(this.a, this.b, this.t) : assert(a != null || b != null); + + final DecorationImage? a; + final DecorationImage? b; + final double t; + + @override + ImageProvider get image => b?.image ?? a!.image; + @override + ImageErrorListener? get onError => b?.onError ?? a!.onError; + @override + ColorFilter? get colorFilter => b?.colorFilter ?? a!.colorFilter; + @override + BoxFit? get fit => b?.fit ?? a!.fit; + @override + AlignmentGeometry get alignment => b?.alignment ?? a!.alignment; + @override + Rect? get centerSlice => b?.centerSlice ?? a!.centerSlice; + @override + ImageRepeat get repeat => b?.repeat ?? a!.repeat; + @override + bool get matchTextDirection => b?.matchTextDirection ?? a!.matchTextDirection; + @override + double get scale => b?.scale ?? a!.scale; + @override + double get opacity => b?.opacity ?? a!.opacity; + @override + FilterQuality get filterQuality => b?.filterQuality ?? a!.filterQuality; + @override + bool get invertColors => b?.invertColors ?? a!.invertColors; + @override + bool get isAntiAlias => b?.isAntiAlias ?? a!.isAntiAlias; + + @override + DecorationImagePainter createPainter(VoidCallback onChanged) { + return _BlendedDecorationImagePainter._( + a?.createPainter(onChanged), + b?.createPainter(onChanged), + t, + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (other.runtimeType != runtimeType) { + return false; + } + return other is _BlendedDecorationImage + && other.a == a + && other.b == b + && other.t == t; + } + + @override + int get hashCode => Object.hash(a, b, t); + + @override + String toString() { + return '${objectRuntimeType(this, '_BlendedDecorationImage')}($a, $b, $t)'; + } +} + +class _BlendedDecorationImagePainter implements DecorationImagePainter { + _BlendedDecorationImagePainter._(this.a, this.b, this.t); + + final DecorationImagePainter? a; + final DecorationImagePainter? b; + final double t; + + @override + void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { + a?.paint(canvas, rect, clipPath, configuration, blend: blend * (1.0 - t), blendMode: blendMode); + b?.paint(canvas, rect, clipPath, configuration, blend: blend * t, blendMode: a != null ? BlendMode.plus : blendMode); + } + + @override + void dispose() { + a?.dispose(); + b?.dispose(); + } + + @override + String toString() { + return '${objectRuntimeType(this, '_BlendedDecorationImagePainter')}($a, $b, $t)'; + } +} diff --git a/packages/flutter/lib/src/painting/shape_decoration.dart b/packages/flutter/lib/src/painting/shape_decoration.dart index 20785bced2150..bf7a0e872d132 100644 --- a/packages/flutter/lib/src/painting/shape_decoration.dart +++ b/packages/flutter/lib/src/painting/shape_decoration.dart @@ -237,7 +237,7 @@ class ShapeDecoration extends Decoration { return ShapeDecoration( color: Color.lerp(a?.color, b?.color, t), gradient: Gradient.lerp(a?.gradient, b?.gradient, t), - image: t < 0.5 ? a?.image : b?.image, // TODO(ianh): cross-fade the image + image: DecorationImage.lerp(a?.image, b?.image, t), shadows: BoxShadow.lerpList(a?.shadows, b?.shadows, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t)!, ); diff --git a/packages/flutter/test/painting/decoration_image_lerp_test.dart b/packages/flutter/test/painting/decoration_image_lerp_test.dart new file mode 100644 index 0000000000000..1e0f6f4998cc8 --- /dev/null +++ b/packages/flutter/test/painting/decoration_image_lerp_test.dart @@ -0,0 +1,440 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is run as part of a reduced test set in CI on Mac and Windows +// machines because it contains golden tests; see: +// https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter#reduced-test-set-tag +@Tags(['reduced-test-set']) +library; + +import 'dart:async'; +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('ImageDecoration.lerp', (WidgetTester tester) async { + final MemoryImage green = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, + 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0x00, 0x34, 0x5e, 0xc0, 0xa8, + 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82, + ])); + final MemoryImage red = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, + 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x00, 0x00, 0x19, 0xe2, 0x09, 0x37, + 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, + 0x60, 0x82, + ])); + + await tester.runAsync(() async { + await load(green); + await load(red); + }); + + await tester.pumpWidget( + ColoredBox( + color: Colors.white, + child: Align( + alignment: Alignment.topLeft, + child: RepaintBoundary( + child: Wrap( + textDirection: TextDirection.ltr, + children: [ + TestImage( + DecorationImage(image: green, repeat: ImageRepeat.repeat) + ), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.1, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.2, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.8, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 0.9, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: red, repeat: ImageRepeat.repeat), + 1.0, + )), + TestImage( + DecorationImage(image: red, repeat: ImageRepeat.repeat), + ), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + t, + )), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + t, + )), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + t, + )), + for (double t = 0.0; t < 1.0; t += 0.125) + TestImage(DecorationImage.lerp( + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + DecorationImage.lerp( + DecorationImage(image: green, repeat: ImageRepeat.repeat), + DecorationImage(image: green, repeat: ImageRepeat.repeat), + 1.0 - t, + ), + t, + )), + ], + ), + ), + ), + ), + ); + + await expectLater( + find.byType(Wrap), + matchesGoldenFile('decoration_image.lerp.0.png'), + ); + + if (!kIsWeb) { // TODO(ianh): https://github.com/flutter/flutter/issues/130610 + final ui.Image image = (await tester.binding.runAsync(() => captureImage(find.byType(Wrap).evaluate().single)))!; + final Uint8List bytes = (await tester.binding.runAsync(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!.buffer.asUint8List(); + expect(image.width, 792); + expect(image.height, 48); + expect(bytes, hasLength(image.width * image.height * 4)); + Color getPixel(int x, int y) { + final int offset = (x + y * image.width) * 4; + return Color.fromARGB(0xFF, bytes[offset], bytes[offset + 1], bytes[offset + 2]); + } + Color getBlockPixel(int index) { + int x = 12 + index * 24; + final int y = 12 + (x ~/ image.width) * 24; + x %= image.width; + return getPixel(x, y); + } + const Color lime = Color(0xFF00FF00); + expect(getBlockPixel(0), lime); // pure green + expect(getBlockPixel(1), lime); // 100% green 0% red + expect(getBlockPixel(2), const Color(0xFF19E600)); + expect(getBlockPixel(3), const Color(0xFF33CC00)); + expect(getBlockPixel(4), const Color(0xFF808000)); // 50-50 mix green/red + expect(getBlockPixel(5), const Color(0xFFCD3200)); + expect(getBlockPixel(6), const Color(0xFFE61900)); + expect(getBlockPixel(7), const Color(0xFFFF0000)); // 0% green 100% red + expect(getBlockPixel(8), const Color(0xFFFF0000)); // pure red + for (int index = 9; index < 40; index += 1) { + expect(getBlockPixel(index), lime); + } + } + }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 + + testWidgets('ImageDecoration.lerp', (WidgetTester tester) async { + final MemoryImage cmyk = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, + 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x4c, 0x59, 0x13, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x63, 0x60, 0x05, 0xc2, 0xf5, 0x0c, 0xeb, 0x01, 0x03, 0x00, 0x01, 0x69, 0x19, + 0xea, 0x34, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + ])); + final MemoryImage wrgb = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, + 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0x00, 0x1e, 0x46, 0xbb, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x63, 0xe0, 0x07, 0xc2, 0xa5, 0x0c, 0x4b, 0x01, 0x03, 0x50, 0x01, 0x69, 0x4a, + 0x78, 0x1d, 0x41, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + ])); + + await tester.runAsync(() async { + await load(cmyk); + await load(wrgb); + }); + + await tester.pumpWidget( + ColoredBox( + color: Colors.white, + child: Align( + alignment: Alignment.topLeft, + child: RepaintBoundary( + child: Wrap( + textDirection: TextDirection.ltr, + children: [ + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.1, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.2, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.8, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.9, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 1.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.cover), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeatY), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeatX), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, scale: 0.5, repeat: ImageRepeat.repeatX), + DecorationImage(image: cmyk, scale: 0.25, repeat: ImageRepeat.repeatY), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 1.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 1.0, + )), + ], + ), + ), + ), + ), + ); + + await expectLater( + find.byType(Wrap), + matchesGoldenFile('decoration_image.lerp.1.png'), + ); + + if (!kIsWeb) { // TODO(ianh): https://github.com/flutter/flutter/issues/130610 + final ui.Image image = (await tester.binding.runAsync(() => captureImage(find.byType(Wrap).evaluate().single)))!; + final Uint8List bytes = (await tester.binding.runAsync(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!.buffer.asUint8List(); + expect(image.width, 24 * 24); + expect(image.height, 1 * 24); + expect(bytes, hasLength(image.width * image.height * 4)); + Color getPixel(int x, int y) { + final int offset = (x + y * image.width) * 4; + return Color.fromARGB(0xFF, bytes[offset], bytes[offset + 1], bytes[offset + 2]); + } + Color getPixelFromBlock(int index, int dx, int dy) { + const int padding = 2; + int x = index * 24 + dx + padding; + final int y = (x ~/ image.width) * 24 + dy + padding; + x %= image.width; + return getPixel(x, y); + } + // wrgb image + expect(getPixelFromBlock(0, 5, 5), const Color(0xFFFFFFFF)); + expect(getPixelFromBlock(0, 15, 5), const Color(0xFFFF0000)); + expect(getPixelFromBlock(0, 5, 15), const Color(0xFF00FF00)); + expect(getPixelFromBlock(0, 15, 15), const Color(0xFF0000FF)); + // wrgb/cmyk 50/50 blended image + expect(getPixelFromBlock(3, 5, 5), const Color(0xFF80FFFF)); + expect(getPixelFromBlock(3, 15, 5), const Color(0xFFFF0080)); + expect(getPixelFromBlock(3, 5, 15), const Color(0xFF80FF00)); + expect(getPixelFromBlock(3, 15, 15), const Color(0xFF000080)); + // cmyk image + expect(getPixelFromBlock(6, 5, 5), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(6, 15, 5), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(6, 5, 15), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(6, 15, 15), const Color(0xFF000000)); + // top left corner control + expect(getPixelFromBlock(14, 0, 0), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(14, 1, 1), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(14, 2, 0), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(14, 19, 0), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(14, 0, 2), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(14, 0, 19), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(14, 2, 2), const Color(0xFF000000)); + expect(getPixelFromBlock(14, 19, 19), const Color(0xFF000000)); + // bottom right corner control + expect(getPixelFromBlock(19, 0, 0), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(19, 17, 17), const Color(0xFF00FFFF)); + expect(getPixelFromBlock(19, 19, 0), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(19, 19, 17), const Color(0xFFFF00FF)); + expect(getPixelFromBlock(19, 0, 19), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(19, 17, 19), const Color(0xFFFFFF00)); + expect(getPixelFromBlock(19, 18, 18), const Color(0xFF000000)); + expect(getPixelFromBlock(19, 19, 19), const Color(0xFF000000)); + } + }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 +} + +Future load(MemoryImage image) { + final ImageStream stream = image.resolve(ImageConfiguration.empty); + final Completer completer = Completer(); + void listener(ImageInfo image, bool syncCall) { + completer.complete(image); + } + stream.addListener(ImageStreamListener(listener)); + return completer.future; +} + +class TestImage extends StatelessWidget { + TestImage(this.image); // ignore: use_key_in_widget_constructors, prefer_const_constructors_in_immutables + + final DecorationImage? image; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(2.0), + child: SizedBox( + width: 20, + height: 20, + child: DecoratedBox( + decoration: BoxDecoration( + image: image, + ), + ), + ), + ); + } +} From 61fd11db2b7aeb429995278803473ae0f7da061b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:58:55 -0700 Subject: [PATCH 0393/1547] Add the 'a: desktop' label to labeler.yml (#130933) The desktop team uses the [`a: desktop`](https://github.com/flutter/engine/pulls?q=is%3Aopen+label%3A%22affects%3A+desktop%22+sort%3Aupdated-desc) label to [triage](https://github.com/flutter/flutter/wiki/Triage#desktop-platforms-team-team-desktop) pull requests. --- .github/labeler.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index 9571981ef296c..bda4edfa98d5e 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -13,6 +13,11 @@ - '**/animation/*' - '**/*animation*' +'a: desktop': + - '**/linux/**/*' + - '**/macos/**/*' + - '**/windows/**/*' + 'a: internationalization': - packages/flutter_localizations/**/* From 224064935871ee04f6b953c99f45838771800974 Mon Sep 17 00:00:00 2001 From: Chris Evans Date: Thu, 27 Jul 2023 02:30:23 +0100 Subject: [PATCH 0394/1547] Add 'vm:keep-name' pragmas to platform channel classes (#131271) Pragma will allow future proofing Dart snapshot utilities to work by preserving the names of important classes used in platform channel communication @Hixie --- packages/flutter/lib/src/services/message_codec.dart | 1 + packages/flutter/lib/src/services/platform_channel.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/flutter/lib/src/services/message_codec.dart b/packages/flutter/lib/src/services/message_codec.dart index cc2efd41a3d47..d9b87721e6f03 100644 --- a/packages/flutter/lib/src/services/message_codec.dart +++ b/packages/flutter/lib/src/services/message_codec.dart @@ -30,6 +30,7 @@ abstract class MessageCodec { } /// A command object representing the invocation of a named method. +@pragma('vm:keep-name') @immutable class MethodCall { /// Creates a [MethodCall] representing the invocation of [method] with the diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index 259583f2e0bb4..426893ab3333f 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart @@ -246,6 +246,7 @@ class BasicMessageChannel { /// {@endtemplate} /// /// See: +@pragma('vm:keep-name') class MethodChannel { /// Creates a [MethodChannel] with the specified [name]. /// From 48f08e3db23f14e41051d672ed3da1bc65caa87d Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 26 Jul 2023 22:59:17 -0700 Subject: [PATCH 0395/1547] IgnoreBaseline widget (#131220) Fixes https://github.com/flutter/flutter/issues/7037 --- packages/flutter/lib/src/rendering/flex.dart | 2 +- .../flutter/lib/src/rendering/proxy_box.dart | 13 +++++ packages/flutter/lib/src/widgets/basic.dart | 22 +++++++- .../flutter/test/rendering/baseline_test.dart | 52 +++++++++++++++++ packages/flutter/test/widgets/basic_test.dart | 56 +++++++++++++++++++ 5 files changed, 142 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart index db6df8757269f..5737ce92a1e56 100644 --- a/packages/flutter/lib/src/rendering/flex.dart +++ b/packages/flutter/lib/src/rendering/flex.dart @@ -916,7 +916,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin[ + a = RenderParagraph( + const TextSpan(text: 'a', style: TextStyle(fontSize: 128.0, fontFamily: 'FlutterTest')), // places baseline at y=96 + textDirection: TextDirection.ltr, + ), + b = RenderParagraph( + const TextSpan(text: 'b', style: TextStyle(fontSize: 32.0, fontFamily: 'FlutterTest')), // 24 above baseline, 8 below baseline + textDirection: TextDirection.ltr, + ), + ], + ); + layout(root); + + final Offset aPos = a.localToGlobal(Offset.zero); + final Offset bPos = b.localToGlobal(Offset.zero); + expect(aPos.dy, 0.0); + expect(bPos.dy, 96.0 - 24.0); + }); + + test('RenderFlex and RenderIgnoreBaseline (with ignored baseline)', () { + final RenderBox a, b; + final RenderBox root = RenderFlex( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + textDirection: TextDirection.ltr, + children: [ + RenderIgnoreBaseline( + child: a = RenderParagraph( + const TextSpan(text: 'a', style: TextStyle(fontSize: 128.0, fontFamily: 'FlutterTest')), + textDirection: TextDirection.ltr, + ), + ), + b = RenderParagraph( + const TextSpan(text: 'b', style: TextStyle(fontSize: 32.0, fontFamily: 'FlutterTest')), + textDirection: TextDirection.ltr, + ), + ], + ); + layout(root); + + final Offset aPos = a.localToGlobal(Offset.zero); + final Offset bPos = b.localToGlobal(Offset.zero); + expect(aPos.dy, 0.0); + expect(bPos.dy, 0.0); + }); } diff --git a/packages/flutter/test/widgets/basic_test.dart b/packages/flutter/test/widgets/basic_test.dart index 5fb6bc82ef0b7..86782c7700f09 100644 --- a/packages/flutter/test/widgets/basic_test.dart +++ b/packages/flutter/test/widgets/basic_test.dart @@ -1135,6 +1135,62 @@ void main() { contains('verticalDirection: up'), ])); }); + + testWidgets('Row and IgnoreBaseline (control -- with baseline)', (WidgetTester tester) async { + await tester.pumpWidget( + const Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + textDirection: TextDirection.ltr, + children: [ + Text( + 'a', + textDirection: TextDirection.ltr, + style: TextStyle(fontSize: 128.0, fontFamily: 'FlutterTest'), // places baseline at y=96 + ), + Text( + 'b', + textDirection: TextDirection.ltr, + style: TextStyle(fontSize: 32.0, fontFamily: 'FlutterTest'), // 24 above baseline, 8 below baseline + ), + ], + ), + ); + + final Offset aPos = tester.getTopLeft(find.text('a')); + final Offset bPos = tester.getTopLeft(find.text('b')); + expect(aPos.dy, 0.0); + expect(bPos.dy, 96.0 - 24.0); + }); + + testWidgets('Row and IgnoreBaseline (with ignored baseline)', (WidgetTester tester) async { + await tester.pumpWidget( + const Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + textDirection: TextDirection.ltr, + children: [ + IgnoreBaseline( + child: Text( + 'a', + textDirection: TextDirection.ltr, + style: TextStyle(fontSize: 128.0, fontFamily: 'FlutterTest'), // places baseline at y=96 + ), + ), + Text( + 'b', + textDirection: TextDirection.ltr, + style: TextStyle(fontSize: 32.0, fontFamily: 'FlutterTest'), // 24 above baseline, 8 below baseline + ), + ], + ), + ); + + final Offset aPos = tester.getTopLeft(find.text('a')); + final Offset bPos = tester.getTopLeft(find.text('b')); + expect(aPos.dy, 0.0); + expect(bPos.dy, 0.0); + }); } HitsRenderBox hits(RenderBox renderBox) => HitsRenderBox(renderBox); From cfafb9105f74a17ee7ad3d863bc014d74e0fd460 Mon Sep 17 00:00:00 2001 From: keyonghan <54558023+keyonghan@users.noreply.github.com> Date: Thu, 27 Jul 2023 08:16:09 -0700 Subject: [PATCH 0396/1547] Add DeviceLab build+test separation doc (#131365) This PR add instructions to separate DeviceLab tasks to build and test model. --- dev/devicelab/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/dev/devicelab/README.md b/dev/devicelab/README.md index 39cd020fe509e..afa8300f1534c 100644 --- a/dev/devicelab/README.md +++ b/dev/devicelab/README.md @@ -19,6 +19,7 @@ for information on using the dashboards. * [Adding tests to continuous integration](#adding-tests-to-continuous-integration) * [Adding tests to presubmit](#adding-tests-to-presubmit) +* [Migrating to build and test model](#migrating-to-build-and-test-model) ## How the DeviceLab runs tests @@ -226,3 +227,33 @@ target for each operating system. Flutter's DeviceLab has a limited capacity in presubmit. File an infra ticket to investigate feasibility of adding a test to presubmit. + +## Migrating to build and test model + +To better utilize limited DeviceLab testbed resources and speed up commit validation +time, it is now supported to separate building artifacts (.apk/.app) from testing them. +The artifact will be built on a host only bot, a VM or physical bot without a device, +and the test will run based on the artifact against a testbed with a device. + +Steps: + +1. Update the task class to extend [`BuildTestTask`](https://github.com/flutter/flutter/blob/master/dev/devicelab/lib/tasks/build_test_task.dart) + - Override function `getBuildArgs` + - Override function `getTestArgs` + - Override function `parseTaskResult` + - Override function `getApplicationBinaryPath` +2. Update the `bin/tasks/{TEST}.dart` to point to the new task class +3. Validate the task locally + - build only: `dart bin/test_runner.dart test -t {NAME_OR_PATH_OF_TEST} --task-args build --task-args application-binary-path={PATH_TO_ARTIFACT}` + - test only: `dart bin/test_runner.dart test -t {NAME_OR_PATH_OF_TEST} --task-args test --task-args application-binary-path={PATH_TO_ARTIFACT}` +4. Add tasks to continuous integration + - Mirror a target with platform `Linux_build_test` or `Mac_build_test` + - The only difference from regular targets is the artifact property: if omitted, it will use the `task_name`. +5. Once validated in CI, enable the target in `PROD` by removing `bringup: true` and deleting the old target entry without build+test model. + +Take gallery tasks for example: + +1. Linux android + - Separating PR: https://github.com/flutter/flutter/pull/103550 + - Switching PR: https://github.com/flutter/flutter/pull/110533 +2. Mac iOS: https://github.com/flutter/flutter/pull/111164 \ No newline at end of file From 4e609f1abb2d2709c59a30422a2bb0146ecca7c0 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Thu, 27 Jul 2023 18:37:41 +0200 Subject: [PATCH 0397/1547] Fix ios_add2app Podfile (#131263) Fixes: * https://github.com/flutter/flutter/issues/131261 --- dev/integration_tests/ios_add2app_life_cycle/Podfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/integration_tests/ios_add2app_life_cycle/Podfile b/dev/integration_tests/ios_add2app_life_cycle/Podfile index c844f4ea5ae48..d3b1bf4ef7fcb 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/Podfile +++ b/dev/integration_tests/ios_add2app_life_cycle/Podfile @@ -10,7 +10,7 @@ target 'ios_add2app' do end target 'ios_add2appTests' do - install_flutter_engine_pod + install_flutter_engine_pod(flutter_application_path) pod 'EarlGreyTest' end From dd9764ec3447018abd5a9f0a6be1c7e4474a99c7 Mon Sep 17 00:00:00 2001 From: Seiya Kokushi Date: Fri, 28 Jul 2023 01:57:27 +0900 Subject: [PATCH 0398/1547] Proposal to add barrier configs for showDatePicker, showTimePicker and showAboutDialog. (#131306) Can configure modal barriers in Flutter's built-in dialogs. --- packages/flutter/lib/src/material/about.dart | 12 +- .../flutter/lib/src/material/date_picker.dart | 26 ++- packages/flutter/lib/src/material/dialog.dart | 6 +- .../flutter/lib/src/material/time_picker.dart | 11 +- .../flutter/test/material/about_test.dart | 162 +++++++++++++++ .../test/material/date_picker_test.dart | 192 ++++++++++++++++++ .../test/material/time_picker_test.dart | 169 +++++++++++++++ 7 files changed, 564 insertions(+), 14 deletions(-) diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 280ef14b252cb..44d4e7b1cf4f8 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -170,9 +170,9 @@ class AboutListTile extends StatelessWidget { /// The licenses shown on the [LicensePage] are those returned by the /// [LicenseRegistry] API, which can be used to add more licenses to the list. /// -/// The [context], [useRootNavigator], [routeSettings] and [anchorPoint] -/// arguments are passed to [showDialog], the documentation for which discusses -/// how it is used. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator], [routeSettings] and [anchorPoint] arguments are +/// passed to [showDialog], the documentation for which discusses how it is used. void showAboutDialog({ required BuildContext context, String? applicationName, @@ -180,12 +180,18 @@ void showAboutDialog({ Widget? applicationIcon, String? applicationLegalese, List? children, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, Offset? anchorPoint, }) { showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, builder: (BuildContext context) { return AboutDialog( diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 2fb95113d0dad..93c699cc9d7f3 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -113,9 +113,10 @@ const double _kMaxTextScaleFactor = 1.3; /// [locale] and [textDirection] are non-null, [textDirection] overrides the /// direction chosen for the [locale]. /// -/// The [context], [useRootNavigator] and [routeSettings] arguments are passed to -/// [showDialog], the documentation for which discusses how it is used. [context] -/// and [useRootNavigator] must be non-null. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], +/// the documentation for which discusses how it is used. +/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -169,6 +170,9 @@ Future showDatePicker({ String? cancelText, String? confirmText, Locale? locale, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, TextDirection? textDirection, @@ -243,6 +247,9 @@ Future showDatePicker({ return showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, routeSettings: routeSettings, builder: (BuildContext context) { @@ -967,9 +974,10 @@ class _DatePickerHeader extends StatelessWidget { /// [locale] and [textDirection] are non-null, [textDirection] overrides the /// direction chosen for the [locale]. /// -/// The [context], [useRootNavigator] and [routeSettings] arguments are passed -/// to [showDialog], the documentation for which discusses how it is used. -/// [context] and [useRootNavigator] must be non-null. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], +/// the documentation for which discusses how it is used. +/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -1022,6 +1030,9 @@ Future showDateRangePicker({ String? fieldStartLabelText, String? fieldEndLabelText, Locale? locale, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, RouteSettings? routeSettings, TextDirection? textDirection, @@ -1100,6 +1111,9 @@ Future showDateRangePicker({ return showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, routeSettings: routeSettings, useSafeArea: false, diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 0b13366825c88..16c05049a2eca 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -1403,7 +1403,7 @@ Future showDialog({ required BuildContext context, required WidgetBuilder builder, bool barrierDismissible = true, - Color? barrierColor = Colors.black54, + Color? barrierColor, String? barrierLabel, bool useSafeArea = true, bool useRootNavigator = true, @@ -1425,7 +1425,7 @@ Future showDialog({ return Navigator.of(context, rootNavigator: useRootNavigator).push(DialogRoute( context: context, builder: builder, - barrierColor: barrierColor, + barrierColor: barrierColor ?? Colors.black54, barrierDismissible: barrierDismissible, barrierLabel: barrierLabel, useSafeArea: useSafeArea, @@ -1448,7 +1448,7 @@ Future showAdaptiveDialog({ required BuildContext context, required WidgetBuilder builder, bool? barrierDismissible, - Color? barrierColor = Colors.black54, + Color? barrierColor, String? barrierLabel, bool useSafeArea = true, bool useRootNavigator = true, diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index bde201785a510..86ebd1f3dac68 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2874,8 +2874,9 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin { /// ``` /// {@end-tool} /// -/// The [context], [useRootNavigator] and [routeSettings] arguments are passed -/// to [showDialog], the documentation for which discusses how it is used. +/// The [context], [barrierDismissible], [barrierColor], [barrierLabel], +/// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], +/// the documentation for which discusses how it is used. /// /// The [builder] parameter can be used to wrap the dialog widget to add /// inherited widgets like [Localizations.override], [Directionality], or @@ -2954,6 +2955,9 @@ Future showTimePicker({ required BuildContext context, required TimeOfDay initialTime, TransitionBuilder? builder, + bool barrierDismissible = true, + Color? barrierColor, + String? barrierLabel, bool useRootNavigator = true, TimePickerEntryMode initialEntryMode = TimePickerEntryMode.dial, String? cancelText, @@ -2983,6 +2987,9 @@ Future showTimePicker({ ); return showDialog( context: context, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor, + barrierLabel: barrierLabel, useRootNavigator: useRootNavigator, builder: (BuildContext context) { return builder == null ? dialog : builder(context, dialog); diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index cb7be72b992a0..7e38905b8dbe1 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -742,6 +742,160 @@ void main() { expect(nestedObserver.licensePageCount, 0); }); + group('Barrier dismissible', () { + late AboutDialogObserver rootObserver; + + setUp(() { + rootObserver = AboutDialogObserver(); + }); + + testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 1); + + // Tap on the barrier. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 0); + }); + + testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + barrierDismissible: false + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 1); + + // Tap on the barrier, which shouldn't do anything this time. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.dialogCount, 1); + }); + }); + + testWidgets('Barrier color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); + + // Dismiss the dialog. + await tester.tapAt(const Offset(10.0, 10.0)); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + barrierColor: Colors.pink, + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); + }); + + testWidgets('Barrier Label', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showAboutDialog( + context: context, + barrierLabel: 'Custom Label', + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); + }); + testWidgetsWithLeakTracking('showAboutDialog uses root navigator by default', (WidgetTester tester) async { final AboutDialogObserver rootObserver = AboutDialogObserver(); final AboutDialogObserver nestedObserver = AboutDialogObserver(); @@ -1741,4 +1895,12 @@ class AboutDialogObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } + + @override + void didPop(Route route, Route? previousRoute) { + if (route is DialogRoute) { + dialogCount--; + } + super.didPop(route, previousRoute); + } } diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 3a7830806e05e..a9b4783a8fe33 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -335,6 +335,190 @@ void main() { expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight); }); + group('Barrier dismissible', () { + late _DatePickerObserver rootObserver; + + setUp(() { + rootObserver = _DatePickerObserver(); + }); + + testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 1); + + // Tap on the barrier. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 0); + }); + + testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + barrierDismissible: false, + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 1); + + // Tap on the barrier, which shouldn't do anything this time. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.datePickerCount, 1); + }); + }); + + testWidgets('Barrier color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); + + // Dismiss the dialog. + await tester.tapAt(const Offset(10.0, 10.0)); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + barrierColor: Colors.pink, + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); + }); + + testWidgets('Barrier Label', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showDatePicker( + context: context, + barrierLabel: 'Custom Label', + initialDate: DateTime.now(), + firstDate: DateTime(2018), + lastDate: DateTime(2030), + builder: (BuildContext context, + Widget? child) => const SizedBox(), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); + }); + testWidgets('uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final _DatePickerObserver rootObserver = _DatePickerObserver(); final _DatePickerObserver nestedObserver = _DatePickerObserver(); @@ -2035,4 +2219,12 @@ class _DatePickerObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } + + @override + void didPop(Route route, Route? previousRoute) { + if (route is DialogRoute) { + datePickerCount--; + } + super.didPop(route, previousRoute); + } } diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 86a0f32d6b550..6ea61ec228a4c 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -668,6 +668,167 @@ void main() { expect(tester.getBottomLeft(find.text(okString)).dx, 800 - ltrOkRight); }); + group('Barrier dismissible', () { + late PickerObserver rootObserver; + + setUp(() { + rootObserver = PickerObserver(); + }); + + testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 1); + + // Tap on the barrier. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 0); + }); + + testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + navigatorObservers: [rootObserver], + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => + showTimePicker( + context: context, + barrierDismissible: false, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 1); + + // Tap on the barrier, which shouldn't do anything this time. + await tester.tapAt(const Offset(10.0, 10.0)); + await tester.pumpAndSettle(); + expect(rootObserver.pickerCount, 1); + }); + }); + + testWidgets('Barrier color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.black54); + + // Dismiss the dialog. + await tester.tapAt(const Offset(10.0, 10.0)); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showTimePicker( + context: context, + barrierColor: Colors.pink, + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); + }); + + testWidgets('Barrier Label', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () => showTimePicker( + context: context, + barrierLabel: 'Custom Label', + initialTime: const TimeOfDay(hour: 7, minute: 0), + ), + ); + }, + ), + ), + ), + ), + ); + + // Open the dialog. + await tester.tap(find.byType(ElevatedButton)); + await tester.pumpAndSettle(); + expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); + }); + testWidgets('uses root navigator by default', (WidgetTester tester) async { final PickerObserver rootObserver = PickerObserver(); final PickerObserver nestedObserver = PickerObserver(); @@ -1807,6 +1968,14 @@ class PickerObserver extends NavigatorObserver { } super.didPush(route, previousRoute); } + + @override + void didPop(Route route, Route? previousRoute) { + if (route is DialogRoute) { + pickerCount--; + } + super.didPop(route, previousRoute); + } } Future mediaQueryBoilerplate( From 8a84437989ff6045ce8fb2490fbcb7e3bd9ebdc8 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 27 Jul 2023 10:33:07 -0700 Subject: [PATCH 0399/1547] Manual roll to engine commit 9b14c382 using Dart SDK version 3.2.x (#131371) Dart SDK 3.2.x requires a new version of the dart_internal package. --- bin/internal/engine.version | 2 +- dev/automated_tests/pubspec.yaml | 6 +++--- dev/benchmarks/complex_layout/pubspec.yaml | 6 +++--- dev/benchmarks/macrobenchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/microbenchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 6 +++--- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/platform_views_layout/pubspec.yaml | 6 +++--- .../platform_views_layout_hybrid_composition/pubspec.yaml | 6 +++--- dev/benchmarks/test_apps/stocks/pubspec.yaml | 6 +++--- dev/bots/pubspec.yaml | 6 +++--- dev/conductor/core/pubspec.yaml | 6 +++--- dev/customer_testing/pubspec.yaml | 6 +++--- dev/devicelab/pubspec.yaml | 6 +++--- dev/forbidden_from_release_tests/pubspec.yaml | 4 ++-- .../abstract_method_smoke_test/pubspec.yaml | 4 ++-- .../android_embedding_v2_smoke_test/pubspec.yaml | 4 ++-- .../android_semantics_testing/pubspec.yaml | 6 +++--- dev/integration_tests/android_views/pubspec.yaml | 8 ++++---- dev/integration_tests/channels/pubspec.yaml | 4 ++-- .../deferred_components_test/pubspec.yaml | 6 +++--- dev/integration_tests/external_ui/pubspec.yaml | 6 +++--- dev/integration_tests/flavors/pubspec.yaml | 6 +++--- dev/integration_tests/flutter_gallery/pubspec.yaml | 6 +++--- .../gradle_deprecated_settings/pubspec.yaml | 4 ++-- dev/integration_tests/hybrid_android_views/pubspec.yaml | 8 ++++---- .../ios_add2app_life_cycle/flutterapp/pubspec.yaml | 4 ++-- .../ios_app_with_extensions/pubspec.yaml | 4 ++-- .../ios_platform_view_tests/pubspec.yaml | 6 +++--- dev/integration_tests/non_nullable/pubspec.yaml | 4 ++-- dev/integration_tests/platform_interaction/pubspec.yaml | 6 +++--- dev/integration_tests/release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 6 +++--- dev/integration_tests/web/pubspec.yaml | 4 ++-- dev/integration_tests/web_compile_tests/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 6 +++--- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- dev/integration_tests/windows_startup_test/pubspec.yaml | 6 +++--- dev/manual_tests/pubspec.yaml | 4 ++-- dev/tools/gen_defaults/pubspec.yaml | 6 +++--- dev/tools/gen_keycodes/pubspec.yaml | 6 +++--- dev/tools/pubspec.yaml | 6 +++--- dev/tools/vitool/pubspec.yaml | 4 ++-- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 6 +++--- examples/flutter_view/pubspec.yaml | 4 ++-- examples/hello_world/pubspec.yaml | 6 +++--- examples/image_list/pubspec.yaml | 4 ++-- examples/layers/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 6 +++--- examples/platform_channel_swift/pubspec.yaml | 6 +++--- examples/platform_view/pubspec.yaml | 4 ++-- examples/splash/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 6 +++--- packages/flutter/pubspec.yaml | 6 +++--- packages/flutter/test_private/pubspec.yaml | 4 ++-- packages/flutter/test_private/test/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 6 +++--- packages/flutter_goldens/pubspec.yaml | 4 ++-- packages/flutter_goldens_client/pubspec.yaml | 4 ++-- packages/flutter_localizations/pubspec.yaml | 4 ++-- packages/flutter_test/pubspec.yaml | 4 ++-- packages/flutter_tools/pubspec.yaml | 6 +++--- packages/flutter_web_plugins/pubspec.yaml | 4 ++-- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 6 +++--- packages/integration_test/example/pubspec.yaml | 6 +++--- .../integration_test/integration_test_macos/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 69 files changed, 177 insertions(+), 177 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 54109d0c8ff96..d3f134f9ff01c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -faf1121d010cea08932b01d8c0397595060b9851 +9b14c382eebfe6eb01b10acf68fa73897ccb4ac6 diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 56cba7ffe116f..c0a62d1a08618 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -22,11 +22,11 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: a0e0 +# PUBSPEC CHECKSUM: 28e0 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 540d800d05924..acdb8de51b4bb 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,7 +51,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 00b9 +# PUBSPEC CHECKSUM: 87b9 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 6ab3a87e4404e..d6397655afc67 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,7 +53,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -211,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 00b9 +# PUBSPEC CHECKSUM: 87b9 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index d8b83e1034d0b..679cae2d6423d 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -22,11 +22,11 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -138,4 +138,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 9331 +# PUBSPEC CHECKSUM: 1b31 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 7f8f450865718..fa9ecc2c357e6 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" ffi: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http: 0.13.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -37,7 +37,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: fc76 +# PUBSPEC CHECKSUM: 2d76 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index 47ceda0564f0b..a2198d8130049 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -23,11 +23,11 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_gallery_assets: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 431c +# PUBSPEC CHECKSUM: 9e1c diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 0a769e35b444e..aa43706aa29c7 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,7 +49,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 00b9 +# PUBSPEC CHECKSUM: 87b9 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index c0de6537855f9..6653e07385db1 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,7 +49,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 00b9 +# PUBSPEC CHECKSUM: 87b9 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 7ddb24b28193a..139500290bded 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -41,7 +41,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 85db +# PUBSPEC CHECKSUM: 0ddb diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index c26cc9065d80c..c7a9622885446 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -26,10 +26,10 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 0884 +# PUBSPEC CHECKSUM: 8f84 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 33940c2c93d05..b04b3142dc95a 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -38,7 +38,7 @@ dev_dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4bbc +# PUBSPEC CHECKSUM: d2bc diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index a5bbf7d46aced..3546fe3719c65 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: meta: 1.9.1 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,7 +26,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +56,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f00a +# PUBSPEC CHECKSUM: 780a diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 4b6f3f215a0bd..bffd8cfd6db6e 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,7 +53,7 @@ dev_dependencies: analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: cbf1 +# PUBSPEC CHECKSUM: 53f1 diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index 38a767f90b6d1..d94649f5b2173 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -12,8 +12,8 @@ dependencies: process: 4.2.4 vm_snapshot_analysis: 0.7.6 - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5e6b +# PUBSPEC CHECKSUM: 846a diff --git a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml index 737b9e663c40c..d86e14fd533a3 100644 --- a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml +++ b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +20,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a9c0 +# PUBSPEC CHECKSUM: 16bf diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index 172d2a4a5b3d1..dfc3dd210bcf4 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: battery_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -96,4 +96,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: c218 +# PUBSPEC CHECKSUM: 8917 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 778543bed908d..b538a5edefcb8 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -20,11 +20,11 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b7d9 +# PUBSPEC CHECKSUM: 3fd9 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 6dc8cc87e1e70..60370cd921c34 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: # This made non-transitive to allow exact pinning # https://github.com/flutter/flutter/issues/116376 path_provider_android: 2.0.27 - collection: 1.17.2 + collection: 1.18.0 assets_for_android_views: git: url: https://github.com/flutter/goldens.git @@ -48,7 +48,7 @@ dependencies: vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -63,7 +63,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bab7 +# PUBSPEC CHECKSUM: 85b8 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index dbae723619e5b..74dcaaa5356b8 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,4 +43,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0c37 +# PUBSPEC CHECKSUM: c436 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 5b34a7ce41ddc..4cb76b4fea79d 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -44,7 +44,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index f27bd9f7b0b20..a9f29aba76240 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -17,11 +17,11 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e162 +# PUBSPEC CHECKSUM: 6962 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 43d0b1b66bc8c..3e25708121fa8 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -19,11 +19,11 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index afd07da98a33d..e2b86e36d6da0 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: flutter: sdk: flutter - collection: 1.17.2 + collection: 1.18.0 device_info: 2.0.3 intl: 0.18.1 connectivity: 3.0.6 @@ -70,7 +70,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 7105 +# PUBSPEC CHECKSUM: cf05 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 1777e2beefdc0..8279a95bdb4d9 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.1+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.3+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_plugin_android_lifecycle: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d205 +# PUBSPEC CHECKSUM: 1704 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 04d4e969a80b3..848b4297d76eb 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: flutter_driver: sdk: flutter path_provider: 2.0.15 - collection: 1.17.2 + collection: 1.18.0 assets_for_android_views: git: url: https://github.com/flutter/goldens.git @@ -46,7 +46,7 @@ dependencies: vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -61,7 +61,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bab7 +# PUBSPEC CHECKSUM: 85b8 diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index d7c0aa5f4aa14..698feeebb8bb9 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: cupertino_icons: 1.0.5 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -99,4 +99,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: beec +# PUBSPEC CHECKSUM: c5eb diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index 2cadc95facb3b..784d8671ca485 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: device_info: 2.0.3 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" device_info_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: d573 +# PUBSPEC CHECKSUM: 5a72 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 66217c52f6e2a..42d268423eae2 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -44,7 +44,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,4 +78,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index 16142b2ae9673..bd7361e39858e 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: cupertino_icons: 1.0.5 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: beec +# PUBSPEC CHECKSUM: c5eb diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 284708d57ebc7..27b9924f85250 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -17,11 +17,11 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e162 +# PUBSPEC CHECKSUM: 6962 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 44016266a04cf..eef94284f63ae 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ebfd +# PUBSPEC CHECKSUM: fafc diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index 7f5fcdc2ff351..5cac435310e57 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: cupertino_icons: 1.0.5 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: bea5 +# PUBSPEC CHECKSUM: a1a4 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 07aa059c3607f..f96ec2d90fb4c 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -19,11 +19,11 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index 71008e7ea2266..b8a0604b50ba9 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -15,10 +15,10 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a9c0 +# PUBSPEC CHECKSUM: 16bf diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index 9dc5925ff4257..cc4bd2c9612b7 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -7,10 +7,10 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a9c0 +# PUBSPEC CHECKSUM: 16bf diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 2b811d248cfb3..6e3a9eb3d9096 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,7 +57,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4204 +# PUBSPEC CHECKSUM: c904 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index 06e2922c978e1..64e053b776b3e 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -41,4 +41,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ebfd +# PUBSPEC CHECKSUM: fafc diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index fd8de2469cac3..d09a8b5e7c705 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -17,11 +17,11 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +63,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e162 +# PUBSPEC CHECKSUM: 6962 diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index c69dd938a9468..68e63d7b2a28c 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7f45 +# PUBSPEC CHECKSUM: b244 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 8dd67d33b4e65..46bead99921a3 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -16,11 +16,11 @@ dev_dependencies: analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +56,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f00a +# PUBSPEC CHECKSUM: 780a diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index e06fa8947e618..b0bcbc29c7898 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: platform: 3.1.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -29,7 +29,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,4 +58,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d201 +# PUBSPEC CHECKSUM: 5a01 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 3b8fccad2aba3..9a4f7364a949a 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,7 +34,7 @@ dev_dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,4 +62,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 691b +# PUBSPEC CHECKSUM: f01b diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 26c882044daa7..c88a5033c853e 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: xml: 6.3.0 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -37,4 +37,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f7ed +# PUBSPEC CHECKSUM: f2ec diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index f9755ff87a314..cac5764fd5c47 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: vm_service: 11.8.0 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ebfd +# PUBSPEC CHECKSUM: fafc diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 38499d6262ddc..a8298fa79802d 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,7 +42,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +86,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 80cd +# PUBSPEC CHECKSUM: dbcd diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index e8d77492ba79b..c60c5f2cdbcd8 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +20,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: a9c0 +# PUBSPEC CHECKSUM: 16bf diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 264313489b832..0e25b3d6ada52 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,4 +69,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index b082083a7a6da..a52f0df8f06f3 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: cupertino_icons: 1.0.5 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,4 +54,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: beec +# PUBSPEC CHECKSUM: c5eb diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index 4a83ace90ddba..ab1ffaef8d2b1 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,4 +36,4 @@ flutter: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: 7f45 +# PUBSPEC CHECKSUM: b244 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 0d4d725a3217e..cd672421266a3 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 1aecf2c579eb1..984b2fcc0ab17 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: dc1f +# PUBSPEC CHECKSUM: 641f diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index 6d1111bc69050..c1bc2cbf392d8 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +20,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: a9c0 +# PUBSPEC CHECKSUM: 16bf diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 864fe341bf3e1..a9f123f19594f 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,4 +31,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7f45 +# PUBSPEC CHECKSUM: b244 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 4d7b54f59d587..43d51a03f4f72 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,7 +28,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b7d9 +# PUBSPEC CHECKSUM: 3fd9 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 7bcec909305d9..c519ebe33767c 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -8,7 +8,7 @@ environment: dependencies: # To update these, use "flutter update-packages --force-upgrade". characters: 1.3.0 - collection: 1.17.2 + collection: 1.18.0 material_color_utilities: 0.5.0 meta: 1.9.1 vector_math: 2.1.4 @@ -34,7 +34,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 20f1 +# PUBSPEC CHECKSUM: a7f1 diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index 84443b3ce2526..29ed2ec175574 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bc90 +# PUBSPEC CHECKSUM: 198f diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index dbdcd862d75ec..7a7e554f0a821 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sky_engine: sdk: flutter characters: 1.3.0 - collection: 1.17.2 + collection: 1.18.0 meta: 1.9.1 vector_math: 2.1.4 @@ -39,4 +39,4 @@ dev_dependencies: platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3540 +# PUBSPEC CHECKSUM: 183f diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 625779d3820b5..18eb711548570 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,7 +47,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8726 +# PUBSPEC CHECKSUM: 0f26 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index ad47b7a980b2b..f4bb87e85f86c 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,4 +36,4 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 99a1 +# PUBSPEC CHECKSUM: 40a0 diff --git a/packages/flutter_goldens_client/pubspec.yaml b/packages/flutter_goldens_client/pubspec.yaml index 340c1756ac28c..b676838563b61 100644 --- a/packages/flutter_goldens_client/pubspec.yaml +++ b/packages/flutter_goldens_client/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: platform: 3.1.0 process: 4.2.4 - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -19,4 +19,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: c70c +# PUBSPEC CHECKSUM: 120b diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index f5ebaae2f8859..0c6726ca5e1c1 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4c7f +# PUBSPEC CHECKSUM: 677e diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index fc8a02ede2d34..0d4595b09d196 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ dependencies: dev_dependencies: file: 6.1.4 -# PUBSPEC CHECKSUM: 4039 +# PUBSPEC CHECKSUM: 5d38 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index a3e273d8b2222..2203d0fbd4eb5 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -68,7 +68,7 @@ dependencies: clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dds_service_extensions: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" devtools_shared: 2.25.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -94,7 +94,7 @@ dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - collection: 1.17.2 + collection: 1.18.0 file_testing: 3.0.0 pubspec_parse: 1.2.3 @@ -107,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 5033 +# PUBSPEC CHECKSUM: 8733 diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index d5efee980c04d..a0d29127b4648 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -33,4 +33,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7f45 +# PUBSPEC CHECKSUM: b244 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index f2bd16ab49b33..35a1e6dac60e9 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -23,11 +23,11 @@ dev_dependencies: args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +64,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: a611 +# PUBSPEC CHECKSUM: 2e11 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 7ace2b654a7dd..26bf165799f1c 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: cupertino_icons: 1.0.5 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,7 +43,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2e8d +# PUBSPEC CHECKSUM: 898d diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 5628fc13372fa..07164b3cc5cce 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,4 +26,4 @@ dependencies: dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: 4387 +# PUBSPEC CHECKSUM: 8f86 diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 8ae84f8cc7399..e9d6687087c77 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - collection: 1.17.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 0c37 +# PUBSPEC CHECKSUM: c436 From e7cc21a4ca619d7dad3ac23b9f471857badc2df3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 14:08:06 -0400 Subject: [PATCH 0400/1547] Roll Packages from a99fc8765de9 to f4ae9336ebb7 (3 revisions) (#131422) https://github.com/flutter/packages/compare/a99fc8765de9...f4ae9336ebb7 2023-07-27 engine-flutter-autoroll@skia.org Manual roll Flutter from bae1ac2f6f35 to 61fd11db2b7a (7 revisions) (flutter/packages#4572) 2023-07-26 engine-flutter-autoroll@skia.org Roll Flutter from 9def8f6bc56b to bae1ac2f6f35 (27 revisions) (flutter/packages#4570) 2023-07-26 60025677+sdoshi983@users.noreply.github.com [go_router] fix(docs): improve docs and fix typo (flutter/packages#4414) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 3b4dd57c7e677..e207becb7e0be 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -a99fc8765de9db56ba6d202d091b54668c1def13 +f4ae9336ebb7d9865e5e2fb6efc5657918c6ee6d From 7e7a0a811a330779fafa19f9b57d931fa3cbbd94 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 14:38:06 -0400 Subject: [PATCH 0401/1547] Roll Flutter Engine from 9b14c382eebf to 08050cdecf94 (22 revisions) (#131426) https://github.com/flutter/engine/compare/9b14c382eebf...08050cdecf94 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 90048a938eb5 to 26ec2772960b (2 revisions) (flutter/engine#44070) 2023-07-27 skia-flutter-autoroll@skia.org Roll ANGLE from 8aa3ca9d177c to d5ddb710e5bd (1 revision) (flutter/engine#44069) 2023-07-27 30870216+gaaclarke@users.noreply.github.com [Impeller] trimmed 3 bytes off of each Glyph (flutter/engine#44054) 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 6571d88db5b3 to 90048a938eb5 (1 revision) (flutter/engine#44066) 2023-07-27 skia-flutter-autoroll@skia.org Roll ANGLE from af5bf5b8245e to 8aa3ca9d177c (1 revision) (flutter/engine#44065) 2023-07-27 skia-flutter-autoroll@skia.org Roll Dart SDK from b6747a06be06 to dcbaffbd09dd (1 revision) (flutter/engine#44064) 2023-07-27 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from pgJmG2-qZVMzlMuq8... to EpwAiaHKf6M6Yejtk... (flutter/engine#44063) 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 26ed0d2ab04c to 6571d88db5b3 (1 revision) (flutter/engine#44062) 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from e85c64d63787 to 26ed0d2ab04c (3 revisions) (flutter/engine#44061) 2023-07-27 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from DOxjABQZ-mA_9Lllw... to FwIA6BaHtZg2mRS-0... (flutter/engine#44060) 2023-07-27 jason-simmons@users.noreply.github.com Ignore the NOTICE.fuchsia file in the new license script (flutter/engine#44021) 2023-07-27 dnfield@google.com Embed a license readme in every zip archive (flutter/engine#43974) 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 750d7f8ed4d7 to e85c64d63787 (4 revisions) (flutter/engine#44056) 2023-07-27 skia-flutter-autoroll@skia.org Roll Dart SDK from 8961d36eaa0c to b6747a06be06 (1 revision) (flutter/engine#44053) 2023-07-26 skia-flutter-autoroll@skia.org Roll ANGLE from 451b3c31a1fa to af5bf5b8245e (1 revision) (flutter/engine#44050) 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from fdf224be4f98 to 750d7f8ed4d7 (3 revisions) (flutter/engine#44049) 2023-07-26 skia-flutter-autoroll@skia.org Roll Dart SDK from b5710782b91c to 8961d36eaa0c (1 revision) (flutter/engine#44048) 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from 990aa6016ff6 to fdf224be4f98 (3 revisions) (flutter/engine#44046) 2023-07-26 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from d6O9t74z-k2svOmvz... to pgJmG2-qZVMzlMuq8... (flutter/engine#44045) 2023-07-26 skia-flutter-autoroll@skia.org Roll ANGLE from 58cb5c8396a3 to 451b3c31a1fa (1 revision) (flutter/engine#44044) 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from d76a9c3bb3fd to 990aa6016ff6 (4 revisions) (flutter/engine#44043) 2023-07-26 skia-flutter-autoroll@skia.org Roll Skia from ca48e45a0262 to d76a9c3bb3fd (1 revision) (flutter/engine#44042) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from DOxjABQZ-mA_ to FwIA6BaHtZg2 fuchsia/sdk/core/mac-amd64 from d6O9t74z-k2s to EpwAiaHKf6M6 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d3f134f9ff01c..5509fea7c32fd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9b14c382eebfe6eb01b10acf68fa73897ccb4ac6 +08050cdecf9472e3c42b666290c99b0cca347780 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 0e90d2579c729..9eaaf39819d41 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -DOxjABQZ-mA_9Lllw-zabKlcUWR6k4czzl1NQUSqOBwC +FwIA6BaHtZg2mRS-0-VTUsPTeCQ8E0aEo2-B8u5TjLoC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 9d8ba60fba1ae..be7e5b1933007 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -d6O9t74z-k2svOmvzcrHJWB8fJmLJ7qu70VmFQYRF_kC +EpwAiaHKf6M6YejtkAYHoX2uVmznnHYMFpeDjsu44tYC From 16826e062b8d844e4a16540ea69740fea4d06dca Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:23:42 -0700 Subject: [PATCH 0402/1547] Preliminary PR for engine changes for Expanded/Collapsed Submenu button (#131359) This PR is to skip some unit tests in order to merging an [engine change](https://github.com/flutter/engine/pull/43983). --- packages/flutter/test/widgets/custom_painter_test.dart | 2 +- packages/flutter/test/widgets/semantics_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/widgets/custom_painter_test.dart b/packages/flutter/test/widgets/custom_painter_test.dart index 3d102a4699c0a..bb991a88e0e0c 100644 --- a/packages/flutter/test/widgets/custom_painter_test.dart +++ b/packages/flutter/test/widgets/custom_painter_test.dart @@ -520,7 +520,7 @@ void _defineTests() { ); expect(semantics, hasSemantics(expectedSemantics, ignoreRect: true, ignoreTransform: true)); semantics.dispose(); - }); + }, skip: true); // https://github.com/flutter/flutter/issues/127617 group('diffing', () { testWidgets('complains about duplicate keys', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart index 809eb09c8cdfc..bfe86488b2542 100644 --- a/packages/flutter/test/widgets/semantics_test.dart +++ b/packages/flutter/test/widgets/semantics_test.dart @@ -706,7 +706,7 @@ void main() { ], ); expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); - }); + }, skip: true); // https://github.com/flutter/flutter/issues/127617 testWidgets('Actions can be replaced without triggering semantics update', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); From e099d67c7bba258ead47ca9a7bccc36c9e050eb3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 15:37:24 -0400 Subject: [PATCH 0403/1547] Roll Flutter Engine from 08050cdecf94 to f3317dbab388 (1 revision) (#131432) https://github.com/flutter/engine/compare/08050cdecf94...f3317dbab388 2023-07-27 skia-flutter-autoroll@skia.org Roll Dart SDK from dcbaffbd09dd to e851b8e49ade (2 revisions) (flutter/engine#44072) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5509fea7c32fd..abd81fe74837a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -08050cdecf9472e3c42b666290c99b0cca347780 +f3317dbab3887df5ffb3ea7ddcffb0b5dce9dede From eab2087a0ffe3f2b5949c219bcf3184a0dbd9423 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 28 Jul 2023 04:04:07 +0800 Subject: [PATCH 0404/1547] =?UTF-8?q?=F0=9F=90=9B=20Only=20format=20Dart?= =?UTF-8?q?=20files=20for=20`gen-l10n`=20(#131232)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improves #119596. The tests remain valid, so no tests were updated in the request. This does not resolve issue #128932, it's handled by another part of the code. --- .../lib/src/localizations/gen_l10n.dart | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 84d37b5e33d56..206dedbaf1dc3 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -80,15 +80,11 @@ Future generateLocalizations({ throwToolExit(e.message); } - final List outputFileList = generator.outputFileList; - final File? untranslatedMessagesFile = generator.untranslatedMessagesFile; - if (options.format) { - final List formatFileList = outputFileList.toList(); - if (untranslatedMessagesFile != null) { - // Don't format the messages file using `dart format`. - formatFileList.remove(untranslatedMessagesFile.absolute.path); - } + // Only format Dart files using `dart format`. + final List formatFileList = generator.outputFileList + .where((String e) => e.endsWith('.dart')) + .toList(growable: false); if (formatFileList.isEmpty) { return generator; } From 252973c64beefa3562261e90562db16b01da60b1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 17:16:45 -0400 Subject: [PATCH 0405/1547] Roll Flutter Engine from f3317dbab388 to 9a935ecbf73a (1 revision) (#131437) https://github.com/flutter/engine/compare/f3317dbab388...9a935ecbf73a 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 26ec2772960b to b522808eb0af (1 revision) (flutter/engine#44075) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index abd81fe74837a..26213c26674a2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f3317dbab3887df5ffb3ea7ddcffb0b5dce9dede +9a935ecbf73a9df9cf76ef234a4f7cd62b1da854 From 7d64c676dde9280b1d93f2e1a68d1c8411beb2b6 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Fri, 28 Jul 2023 06:09:03 +0800 Subject: [PATCH 0406/1547] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Add=20`ssh://git?= =?UTF-8?q?@github.com/flutter/flutter.git`=20as=20a=20standard=20remote?= =?UTF-8?q?=20(#131333)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #98020. --- packages/flutter_tools/lib/src/version.dart | 1 + packages/flutter_tools/test/general.shard/version_test.dart | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index 0702b35e7ec51..e3b66ffd94e54 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -689,6 +689,7 @@ class VersionUpstreamValidator { static final List _standardRemotes = [ 'https://github.com/flutter/flutter.git', 'git@github.com:flutter/flutter.git', + 'ssh://git@github.com/flutter/flutter.git', ]; // Strips ".git" suffix from a given string, preferably an url. diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index ab4c730d444d5..0d82dedc5b032 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -325,6 +325,7 @@ void main() { const String flutterStandardUrlDotGit = 'https://github.com/flutter/flutter.git'; const String flutterNonStandardUrlDotGit = 'https://githubmirror.com/flutter/flutter.git'; const String flutterStandardSshUrlDotGit = 'git@github.com:flutter/flutter.git'; + const String flutterFullSshUrlDotGit = 'ssh://git@github.com/flutter/flutter.git'; VersionCheckError? runUpstreamValidator({ String? versionUpstreamUrl, @@ -394,6 +395,10 @@ void main() { expect(runUpstreamValidator(versionUpstreamUrl: flutterStandardSshUrlDotGit), isNull); }); + testWithoutContext('does not return error at full ssh url with FLUTTER_GIT_URL unset', () { + expect(runUpstreamValidator(versionUpstreamUrl: flutterFullSshUrlDotGit), isNull); + }); + testWithoutContext('stripDotGit removes ".git" suffix if any', () { expect(VersionUpstreamValidator.stripDotGit('https://github.com/flutter/flutter.git'), 'https://github.com/flutter/flutter'); expect(VersionUpstreamValidator.stripDotGit('https://github.com/flutter/flutter'), 'https://github.com/flutter/flutter'); From 4a86d6de23de4c67d9f1366392a78af0d3365848 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 18:15:10 -0400 Subject: [PATCH 0407/1547] Roll Flutter Engine from 9a935ecbf73a to 284771da323c (3 revisions) (#131439) https://github.com/flutter/engine/compare/9a935ecbf73a...284771da323c 2023-07-27 jonahwilliams@google.com Revert "[engine] disable picture complexity raster caching" (flutter/engine#44026) 2023-07-27 jonahwilliams@google.com [Impeller] Move glyph atlas state from context into lazy glyph atlas. (flutter/engine#43748) 2023-07-27 ian@hixie.ch Hide some log lines from release builds (flutter/engine#44073) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 26213c26674a2..5a5ad2c0d2b93 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9a935ecbf73a9df9cf76ef234a4f7cd62b1da854 +284771da323cdc9900c1416263b278d12d167235 From 80c7dd7245247022136b63bdd33a6cf92245e29a Mon Sep 17 00:00:00 2001 From: David <39445938+DavidIsa@users.noreply.github.com> Date: Fri, 28 Jul 2023 00:42:16 +0200 Subject: [PATCH 0408/1547] Fix template app documentation (#131125) The PR fixes template app documentation --- packages/flutter_tools/templates/app/lib/main.dart.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_tools/templates/app/lib/main.dart.tmpl b/packages/flutter_tools/templates/app/lib/main.dart.tmpl index 7768a8e4191c4..e7ad70d7544f0 100644 --- a/packages/flutter_tools/templates/app/lib/main.dart.tmpl +++ b/packages/flutter_tools/templates/app/lib/main.dart.tmpl @@ -50,7 +50,7 @@ class MyApp extends StatelessWidget { // This is the theme of your application. // // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a blue toolbar. Then, without quitting the app, + // the application has a purple toolbar. Then, without quitting the app, // try changing the seedColor in the colorScheme below to Colors.green // and then invoke "hot reload" (save your changes or press the "hot // reload" button in a Flutter-supported IDE, or press "r" if you used From 46d074014b20300168afe7894550fb53a8fb53ac Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 27 Jul 2023 16:25:04 -0700 Subject: [PATCH 0409/1547] [framework] clean up image provider documentation. (#131416) Fixes https://github.com/flutter/flutter/issues/130524 loadBuffer was superseded by loadImage --- .../lib/src/painting/image_provider.dart | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index cc929d8701aa1..57aabc1de984e 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -162,8 +162,8 @@ class ImageConfiguration { /// Performs the decode process for use in [ImageProvider.load]. /// -/// This typedef is deprecated. Use [DecoderBufferCallback] with -/// [ImageProvider.loadBuffer] instead. +/// This typedef is deprecated. Use [ImageDecoderCallback] with +/// [ImageProvider.loadImage] instead. /// /// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and /// `allowUpscaling` parameters from implementations of [ImageProvider] that do @@ -247,16 +247,16 @@ typedef ImageDecoderCallback = Future Function( /// using that key. This is handled by [resolveStreamForKey]. That method /// may fizzle if it determines the image is no longer necessary, use the /// provided [ImageErrorListener] to report an error, set the completer -/// from the cache if possible, or call [loadBuffer] to fetch the encoded image +/// from the cache if possible, or call [loadImage] to fetch the encoded image /// bytes and schedule decoding. -/// 4. The [loadBuffer] method is responsible for both fetching the encoded bytes +/// 4. The [loadImage] method is responsible for both fetching the encoded bytes /// and decoding them using the provided [DecoderCallback]. It is called /// in a context that uses the [ImageErrorListener] to report errors back. /// -/// Subclasses normally only have to implement the [loadBuffer] and [obtainKey] +/// Subclasses normally only have to implement the [loadImage] and [obtainKey] /// methods. A subclass that needs finer grained control over the [ImageStream] /// type must override [createStream]. A subclass that needs finer grained -/// control over the resolution, such as delaying calling [loadBuffer], must override +/// control over the resolution, such as delaying calling [loadImage], must override /// [resolveStreamForKey]. /// /// The [resolve] method is marked as [nonVirtual] so that [ImageProvider]s can @@ -610,9 +610,9 @@ abstract class ImageProvider { /// Converts a key into an [ImageStreamCompleter], and begins fetching the /// image. /// - /// This method is deprecated. Implement [loadBuffer] for faster image - /// loading. Only one of [load] and [loadBuffer] must be implemented, and - /// [loadBuffer] is preferred. + /// This method is deprecated. Implement [loadImage] for faster image + /// loading. Only one of [load] and [loadImage] must be implemented, and + /// [loadImage] is preferred. /// /// The [decode] callback provides the logic to obtain the codec for the /// image. @@ -626,7 +626,7 @@ abstract class ImageProvider { 'This feature was deprecated after v2.13.0-1.0.pre.', ) ImageStreamCompleter load(T key, DecoderCallback decode) { - throw UnsupportedError('Implement loadBuffer for faster image loading'); + throw UnsupportedError('Implement loadImage for faster image loading'); } /// Converts a key into an [ImageStreamCompleter], and begins fetching the From f8afcd5aa01b3ae6c55cb6e4c9fa4171e27a92f6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 19:34:03 -0400 Subject: [PATCH 0410/1547] Roll Flutter Engine from 284771da323c to 196474bd96b0 (3 revisions) (#131443) https://github.com/flutter/engine/compare/284771da323c...196474bd96b0 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 20108acef7d2 to d3a7efb77af3 (2 revisions) (flutter/engine#44082) 2023-07-27 rmolivares@renzo-olivares.dev [iOS] TextInputPlugin should batch TextEditingDeltas and dispatch on the next runLoop (flutter/engine#43267) 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from b522808eb0af to 20108acef7d2 (3 revisions) (flutter/engine#44079) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5a5ad2c0d2b93..6495b3ca50585 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -284771da323cdc9900c1416263b278d12d167235 +196474bd96b025cac400d2433779061e423ccdcf From 10dd50ab5f80a68cf100bc86d179639e12f0a5b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 20:25:40 -0400 Subject: [PATCH 0411/1547] Roll Flutter Engine from 196474bd96b0 to 01bb0a3ef922 (3 revisions) (#131447) https://github.com/flutter/engine/compare/196474bd96b0...01bb0a3ef922 2023-07-27 skia-flutter-autoroll@skia.org Roll ANGLE from d5ddb710e5bd to 179924cbfaf3 (3 revisions) (flutter/engine#44085) 2023-07-27 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from FwIA6BaHtZg2mRS-0... to wgkZmRBHTT7DehhUL... (flutter/engine#44084) 2023-07-27 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from EpwAiaHKf6M6Yejtk... to e_QdQPRjE5lCfa2Hy... (flutter/engine#44083) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from FwIA6BaHtZg2 to wgkZmRBHTT7D fuchsia/sdk/core/mac-amd64 from EpwAiaHKf6M6 to e_QdQPRjE5lC If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6495b3ca50585..a86301fcae8fe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -196474bd96b025cac400d2433779061e423ccdcf +01bb0a3ef9229a31f65e6f716a2d1820a5915ecc diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 9eaaf39819d41..e94ea1802e401 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -FwIA6BaHtZg2mRS-0-VTUsPTeCQ8E0aEo2-B8u5TjLoC +wgkZmRBHTT7DehhULrQ8SrVkdx_WwjSJq7RfVtyI85sC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index be7e5b1933007..760c2f8e27f87 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -EpwAiaHKf6M6YejtkAYHoX2uVmznnHYMFpeDjsu44tYC +e_QdQPRjE5lCfa2HyVLehbHm-XAfLRGPUDPNldy4gaMC From 254010372b80bd9fc2d06a57b5d8f5e247d789fe Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 21:21:16 -0400 Subject: [PATCH 0412/1547] Roll Flutter Engine from 01bb0a3ef922 to 0713d91c2e64 (2 revisions) (#131451) https://github.com/flutter/engine/compare/01bb0a3ef922...0713d91c2e64 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from 100d67ed0b61 to 5403af73dfef (4 revisions) (flutter/engine#44088) 2023-07-27 skia-flutter-autoroll@skia.org Roll Skia from d3a7efb77af3 to 100d67ed0b61 (1 revision) (flutter/engine#44086) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a86301fcae8fe..2d74186cc3453 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -01bb0a3ef9229a31f65e6f716a2d1820a5915ecc +0713d91c2e6485062555c20bcdee04d2e1b4fad4 From 04391d85ac4dce788612b08f45ba91c0c381363d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 27 Jul 2023 22:43:48 -0400 Subject: [PATCH 0413/1547] Roll Flutter Engine from 0713d91c2e64 to b0d97ba45f46 (1 revision) (#131453) https://github.com/flutter/engine/compare/0713d91c2e64...b0d97ba45f46 2023-07-28 36861262+QuncCccccc@users.noreply.github.com Add Expanded/Collapsed state for `SubmenuButton` (flutter/engine#43983) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2d74186cc3453..e06333bdcb089 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0713d91c2e6485062555c20bcdee04d2e1b4fad4 +b0d97ba45f46c95a1328cd7b4c8787a62638aeea From c61f07cf1bd0d088eb9a257ff31a9c4f51c31ef4 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Thu, 27 Jul 2023 21:48:38 -0700 Subject: [PATCH 0414/1547] Updated integration_tests/platform_interaction test_step.dart (#131301) Force the line height of the TextStyle used in test_step.dart to be 1.0 for all Text widgets. The test started failing after https://github.com/flutter/flutter/pull/129724 landed. Assuming that the vertical layout of the test was tight and that the change in the default font's line height is the source of the problem (see https://github.com/flutter/flutter/issues/130732#issuecomment-1639089638). Fixes https://github.com/flutter/flutter/issues/130732 --- .../platform_interaction/lib/src/test_step.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev/integration_tests/platform_interaction/lib/src/test_step.dart b/dev/integration_tests/platform_interaction/lib/src/test_step.dart index a75fd70197955..4bd004b5feb34 100644 --- a/dev/integration_tests/platform_interaction/lib/src/test_step.dart +++ b/dev/integration_tests/platform_interaction/lib/src/test_step.dart @@ -37,7 +37,8 @@ class TestStepResult { final String description; final TestStatus status; - static const TextStyle bold = TextStyle(fontWeight: FontWeight.bold); + static const TextStyle normal = TextStyle(height: 1.0); + static const TextStyle bold = TextStyle(fontWeight: FontWeight.bold, height: 1.0); static const TestStepResult complete = TestStepResult( 'Test complete', nothing, @@ -49,8 +50,8 @@ class TestStepResult { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Step: $name', style: bold), - Text(description), - const Text(' '), + Text(description, style: normal), + const Text(' ', style: normal), Text( status.toString().substring('TestStatus.'.length), key: ValueKey( From 61752e095dd9fbe1c148900cddec4c2ad6c7cdd4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 03:17:10 -0400 Subject: [PATCH 0415/1547] Roll Flutter Engine from b0d97ba45f46 to dc8618da9eb0 (3 revisions) (#131460) https://github.com/flutter/engine/compare/b0d97ba45f46...dc8618da9eb0 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from 5403af73dfef to f2362d22abcf (1 revision) (flutter/engine#44094) 2023-07-28 skia-flutter-autoroll@skia.org Roll ANGLE from 179924cbfaf3 to 613eefa3a70f (1 revision) (flutter/engine#44093) 2023-07-28 skia-flutter-autoroll@skia.org Roll Dart SDK from e851b8e49ade to aab0233f76b7 (2 revisions) (flutter/engine#44092) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e06333bdcb089..60921b631cf62 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b0d97ba45f46c95a1328cd7b4c8787a62638aeea +dc8618da9eb079435084c673b2515d79a0f58730 From 0ff68b8c610d54dd88585d0f97531208988f80b3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 04:09:52 -0400 Subject: [PATCH 0416/1547] Roll Flutter Engine from dc8618da9eb0 to cfa5427dc452 (3 revisions) (#131464) https://github.com/flutter/engine/compare/dc8618da9eb0...cfa5427dc452 2023-07-28 skia-flutter-autoroll@skia.org Roll Dart SDK from aab0233f76b7 to 1b85515a995b (1 revision) (flutter/engine#44096) 2023-07-28 matanlurey@users.noreply.github.com [Impeller] Set 'enable_vulkan_validation_layers' if --unopt and Vulkan is enabled. (flutter/engine#44055) 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from f2362d22abcf to 8739fd6d422c (1 revision) (flutter/engine#44095) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 60921b631cf62..d633bd1f76301 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -dc8618da9eb079435084c673b2515d79a0f58730 +cfa5427dc452cd99386b11fef83167883eb94695 From e4ce8e059798d49dbd5714001d3b202929b70442 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 09:36:59 -0400 Subject: [PATCH 0417/1547] Roll Flutter Engine from cfa5427dc452 to e97014c71014 (3 revisions) (#131477) https://github.com/flutter/engine/compare/cfa5427dc452...e97014c71014 2023-07-28 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from wgkZmRBHTT7DehhUL... to OMmwdXn8XxipooPBo... (flutter/engine#44101) 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from 8739fd6d422c to f538575451a8 (1 revision) (flutter/engine#44100) 2023-07-28 skia-flutter-autoroll@skia.org Roll ANGLE from 613eefa3a70f to 99f1178a9e81 (1 revision) (flutter/engine#44098) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from wgkZmRBHTT7D to OMmwdXn8Xxip If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d633bd1f76301..813ec07c6af22 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cfa5427dc452cd99386b11fef83167883eb94695 +e97014c7101430d42dd4d6211d3c1b8ccb432c57 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index e94ea1802e401..34703859a96ed 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -wgkZmRBHTT7DehhULrQ8SrVkdx_WwjSJq7RfVtyI85sC +OMmwdXn8XxipooPBos19JXsr9NEghQ6xeM3bGPJnE9oC From 7d89617a92b7c008dbee6914cf04f67f36912b40 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 28 Jul 2023 17:11:23 +0300 Subject: [PATCH 0418/1547] Fix `TimePicker` defaults for `hourMinuteTextStyle` and `dayPeriodTextColor` for Material 3 (#131253) fixes [`TimePicker` color and visual issues](https://github.com/flutter/flutter/issues/127035) ## Description - fixes default text style for `TimePicker`s `hourMinuteTextStyle` and added a todo for https://github.com/flutter/flutter/issues/131247 - fixes correct default color not being accessed for `dayPeriodTextColor` - Updates tests ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(useMaterial3: true), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sample'), ), body: Center( child: ElevatedButton( onPressed: () { showTimePicker( context: context, orientation: Orientation.portrait, initialEntryMode: TimePickerEntryMode.input, initialTime: TimeOfDay.now(), builder: (BuildContext context, Widget? child) { return MediaQuery( data: MediaQuery.of(context) .copyWith(alwaysUse24HourFormat: true), child: child!, ); }, ); }, child: const Text('Open Time Picker'), ), ), ); } } ```
### Before ![ezgif com-video-to-gif](https://github.com/flutter/flutter/assets/48603081/b791501f-aed3-44f3-8f75-70a1e28038c6) ### After ![ezgif com-video-to-gif (1)](https://github.com/flutter/flutter/assets/48603081/1bb32064-a9b1-416d-8290-7d22b0d4fdb9) --- .../gen_defaults/generated/used_tokens.csv | 2 +- .../lib/time_picker_template.dart | 55 +++++++------------ .../flutter/lib/src/material/time_picker.dart | 55 +++++++------------ .../test/material/time_picker_theme_test.dart | 18 +++--- 4 files changed, 52 insertions(+), 78 deletions(-) diff --git a/dev/tools/gen_defaults/generated/used_tokens.csv b/dev/tools/gen_defaults/generated/used_tokens.csv index 28ec7c57f4746..c7eb2a390b733 100644 --- a/dev/tools/gen_defaults/generated/used_tokens.csv +++ b/dev/tools/gen_defaults/generated/used_tokens.csv @@ -737,6 +737,7 @@ md.comp.time-picker.period-selector.selected.label-text.color, md.comp.time-picker.period-selector.selected.pressed.label-text.color, md.comp.time-picker.period-selector.unselected.focus.label-text.color, md.comp.time-picker.period-selector.unselected.hover.label-text.color, +md.comp.time-picker.period-selector.unselected.label-text.color, md.comp.time-picker.period-selector.unselected.pressed.label-text.color, md.comp.time-picker.period-selector.vertical.container.height, md.comp.time-picker.period-selector.vertical.container.width, @@ -746,7 +747,6 @@ md.comp.time-picker.time-selector.container.shape, md.comp.time-picker.time-selector.container.width, md.comp.time-picker.time-selector.focus.state-layer.opacity, md.comp.time-picker.time-selector.hover.state-layer.opacity, -md.comp.time-picker.time-selector.label-text.text-style, md.comp.time-picker.time-selector.selected.container.color, md.comp.time-picker.time-selector.selected.focus.label-text.color, md.comp.time-picker.time-selector.selected.focus.state-layer.color, diff --git a/dev/tools/gen_defaults/lib/time_picker_template.dart b/dev/tools/gen_defaults/lib/time_picker_template.dart index a10e5b35c57c0..af359acf6cd90 100644 --- a/dev/tools/gen_defaults/lib/time_picker_template.dart +++ b/dev/tools/gen_defaults/lib/time_picker_template.dart @@ -84,44 +84,28 @@ class _${blockName}DefaultsM3 extends _TimePickerDefaults { @override Color get dayPeriodTextColor { return MaterialStateColor.resolveWith((Set states) { - return _dayPeriodForegroundColor.resolve(states); - }); - } - - MaterialStateProperty get _dayPeriodForegroundColor { - return MaterialStateProperty.resolveWith((Set states) { - Color? textColor; if (states.contains(MaterialState.selected)) { - if (states.contains(MaterialState.pressed)) { - textColor = ${componentColor("$dayPeriodComponent.selected.pressed.label-text")}; - } else { - // not pressed - if (states.contains(MaterialState.hovered)) { - textColor = ${componentColor("$dayPeriodComponent.selected.hover.label-text")}; - } else { - // not hovered - if (states.contains(MaterialState.focused)) { - textColor = ${componentColor("$dayPeriodComponent.selected.focus.label-text")}; - } - } + if (states.contains(MaterialState.focused)) { + return ${componentColor("$dayPeriodComponent.selected.focus.label-text")}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor("$dayPeriodComponent.selected.hover.label-text")}; } - } else { - // unselected if (states.contains(MaterialState.pressed)) { - textColor = ${componentColor("$dayPeriodComponent.unselected.pressed.label-text")}; - } else { - // not pressed - if (states.contains(MaterialState.hovered)) { - textColor = ${componentColor("$dayPeriodComponent.unselected.hover.label-text")}; - } else { - // not hovered - if (states.contains(MaterialState.focused)) { - textColor = ${componentColor("$dayPeriodComponent.unselected.focus.label-text")}; - } - } + return ${componentColor("$dayPeriodComponent.selected.pressed.label-text")}; } + return ${componentColor("$dayPeriodComponent.selected.label-text")}; + } + if (states.contains(MaterialState.focused)) { + return ${componentColor("$dayPeriodComponent.unselected.focus.label-text")}; + } + if (states.contains(MaterialState.hovered)) { + return ${componentColor("$dayPeriodComponent.unselected.hover.label-text")}; + } + if (states.contains(MaterialState.pressed)) { + return ${componentColor("$dayPeriodComponent.unselected.pressed.label-text")}; } - return textColor ?? ${componentColor("$dayPeriodComponent.selected.label-text")}; + return ${componentColor("$dayPeriodComponent.unselected.label-text")}; }); } @@ -297,7 +281,10 @@ class _${blockName}DefaultsM3 extends _TimePickerDefaults { @override TextStyle get hourMinuteTextStyle { return MaterialStateTextStyle.resolveWith((Set states) { - return ${textStyle('$hourMinuteComponent.label-text')}!.copyWith(color: _hourMinuteTextColor.resolve(states)); + // TODO(tahatesser): Update this when https://github.com/flutter/flutter/issues/127035 is fixed. + // This is using the correct text style from Material 3 spec. + // https://m3.material.io/components/time-pickers/specs#fd0b6939-edab-4058-82e1-93d163945215 + return _textTheme.displayMedium!.copyWith(color: _hourMinuteTextColor.resolve(states)); }); } diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 86ebd1f3dac68..7a4b526eb8ac4 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -3393,44 +3393,28 @@ class _TimePickerDefaultsM3 extends _TimePickerDefaults { @override Color get dayPeriodTextColor { return MaterialStateColor.resolveWith((Set states) { - return _dayPeriodForegroundColor.resolve(states); - }); - } - - MaterialStateProperty get _dayPeriodForegroundColor { - return MaterialStateProperty.resolveWith((Set states) { - Color? textColor; if (states.contains(MaterialState.selected)) { - if (states.contains(MaterialState.pressed)) { - textColor = _colors.onTertiaryContainer; - } else { - // not pressed - if (states.contains(MaterialState.hovered)) { - textColor = _colors.onTertiaryContainer; - } else { - // not hovered - if (states.contains(MaterialState.focused)) { - textColor = _colors.onTertiaryContainer; - } - } + if (states.contains(MaterialState.focused)) { + return _colors.onTertiaryContainer; + } + if (states.contains(MaterialState.hovered)) { + return _colors.onTertiaryContainer; } - } else { - // unselected if (states.contains(MaterialState.pressed)) { - textColor = _colors.onSurfaceVariant; - } else { - // not pressed - if (states.contains(MaterialState.hovered)) { - textColor = _colors.onSurfaceVariant; - } else { - // not hovered - if (states.contains(MaterialState.focused)) { - textColor = _colors.onSurfaceVariant; - } - } + return _colors.onTertiaryContainer; } + return _colors.onTertiaryContainer; + } + if (states.contains(MaterialState.focused)) { + return _colors.onSurfaceVariant; + } + if (states.contains(MaterialState.hovered)) { + return _colors.onSurfaceVariant; + } + if (states.contains(MaterialState.pressed)) { + return _colors.onSurfaceVariant; } - return textColor ?? _colors.onTertiaryContainer; + return _colors.onSurfaceVariant; }); } @@ -3606,7 +3590,10 @@ class _TimePickerDefaultsM3 extends _TimePickerDefaults { @override TextStyle get hourMinuteTextStyle { return MaterialStateTextStyle.resolveWith((Set states) { - return _textTheme.displayLarge!.copyWith(color: _hourMinuteTextColor.resolve(states)); + // TODO(tahatesser): Update this when https://github.com/flutter/flutter/issues/127035 is fixed. + // This is using the correct text style from Material 3 spec. + // https://m3.material.io/components/time-pickers/specs#fd0b6939-edab-4058-82e1-93d163945215 + return _textTheme.displayMedium!.copyWith(color: _hourMinuteTextColor.resolve(states)); }); } diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index 9f07d5e38f2e8..f9a291a4c6c3b 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -249,8 +249,8 @@ void main() { final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - Typography.material2021().englishLike.displayLarge! - .merge(Typography.material2021().black.displayLarge) + Typography.material2021().englishLike.displayMedium! + .merge(Typography.material2021().black.displayMedium) .copyWith( color: defaultTheme.colorScheme.onPrimaryContainer, decorationColor: defaultTheme.colorScheme.onSurface @@ -260,8 +260,8 @@ void main() { final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - Typography.material2021().englishLike.displayLarge! - .merge(Typography.material2021().black.displayLarge) + Typography.material2021().englishLike.displayMedium! + .merge(Typography.material2021().black.displayMedium) .copyWith( color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface @@ -275,7 +275,7 @@ void main() { .merge(Typography.material2021().black.titleMedium) .copyWith( color: defaultTheme.colorScheme.onTertiaryContainer, - decorationColor: defaultTheme.colorScheme.onSurface + decorationColor: defaultTheme.colorScheme.onSurface, ), ); @@ -285,8 +285,8 @@ void main() { Typography.material2021().englishLike.titleMedium! .merge(Typography.material2021().black.titleMedium) .copyWith( - color: defaultTheme.colorScheme.onTertiaryContainer, - decorationColor: defaultTheme.colorScheme.onSurface + color: defaultTheme.colorScheme.onSurfaceVariant, + decorationColor: defaultTheme.colorScheme.onSurface, ) ); @@ -297,7 +297,7 @@ void main() { .merge(Typography.material2021().black.bodyMedium) .copyWith( color: defaultTheme.colorScheme.onSurface, - decorationColor: defaultTheme.colorScheme.onSurface + decorationColor: defaultTheme.colorScheme.onSurface, ), ); @@ -312,7 +312,7 @@ void main() { .merge(Typography.material2021().black.bodyLarge) .copyWith( color: defaultTheme.colorScheme.onSurface, - decorationColor: defaultTheme.colorScheme.onSurface + decorationColor: defaultTheme.colorScheme.onSurface, ), ); // ignore: avoid_dynamic_calls From e81907e07a385e79e67734162d435b11f5339000 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 28 Jul 2023 08:04:19 -0700 Subject: [PATCH 0419/1547] Update Chrome to 115, and remove `bringup: true` from skwasm benchmarks. (#131430) Recent changes to binaryen cause us to need to update to Chrome 115 for our wasm benchmarks. --- .ci.yaml | 148 +++++++++++++++++++++++++++---------------------------- 1 file changed, 73 insertions(+), 75 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index ce37a5f61b29d..9663ae9ef2b9f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -142,7 +142,7 @@ platform_properties: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] os: Mac-12 @@ -200,7 +200,7 @@ platform_properties: [ {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "certs", "version": "version:9563bb"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] os: Windows-10 @@ -276,7 +276,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, @@ -295,7 +295,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, @@ -314,7 +314,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, @@ -400,7 +400,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -646,7 +646,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -664,7 +664,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -682,7 +682,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -700,7 +700,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -718,7 +718,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -736,7 +736,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -755,7 +755,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"} + {"dependency": "chrome_and_driver", "version": "version:115.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -773,7 +773,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -792,7 +792,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -811,7 +811,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -909,7 +909,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"} + {"dependency": "chrome_and_driver", "version": "version:115.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -935,7 +935,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -959,7 +959,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -983,7 +983,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -1007,7 +1007,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -1071,7 +1071,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"} + {"dependency": "chrome_and_driver", "version": "version:115.0"} ] tags: > ["devicelab","hostonly", "linux"] @@ -1079,13 +1079,12 @@ targets: - name: Linux web_benchmarks_html recipe: devicelab/devicelab_drone - presubmit: false timeout: 60 properties: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"} + {"dependency": "chrome_and_driver", "version": "version:115.0"} ] tags: > ["devicelab"] @@ -1096,7 +1095,6 @@ targets: - .ci.yaml - name: Linux web_benchmarks_skwasm - bringup: true recipe: devicelab/devicelab_drone presubmit: false timeout: 60 @@ -1104,7 +1102,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"} + {"dependency": "chrome_and_driver", "version": "version:115.0"} ] tags: > ["devicelab"] @@ -1121,7 +1119,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1141,7 +1139,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1161,7 +1159,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1181,7 +1179,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1201,7 +1199,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1221,7 +1219,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1241,7 +1239,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1261,7 +1259,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1281,7 +1279,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1301,7 +1299,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1321,7 +1319,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1341,7 +1339,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1361,7 +1359,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1381,7 +1379,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1401,7 +1399,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1421,7 +1419,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1441,7 +1439,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1461,7 +1459,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1481,7 +1479,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1501,7 +1499,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1521,7 +1519,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1541,7 +1539,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] @@ -2695,7 +2693,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -2713,7 +2711,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -2731,7 +2729,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -2749,7 +2747,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3230,7 +3228,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3254,7 +3252,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3278,7 +3276,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3302,7 +3300,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3384,7 +3382,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] @@ -4135,7 +4133,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4153,7 +4151,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4171,7 +4169,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4189,7 +4187,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4296,7 +4294,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4327,7 +4325,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4346,7 +4344,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4365,7 +4363,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4397,7 +4395,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4416,7 +4414,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4489,7 +4487,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4513,7 +4511,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4537,7 +4535,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4561,7 +4559,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4585,7 +4583,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4609,7 +4607,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4672,7 +4670,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] @@ -4693,7 +4691,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:114.0"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] From 058f1660e7ac6197fcf76d87fb41eef1fab50b92 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 28 Jul 2023 18:28:11 +0300 Subject: [PATCH 0420/1547] Update `Card.color` documentation for Material 3 (#131468) fixes [Card color parameter not respected while using Material 3](https://github.com/flutter/flutter/issues/122177) --- packages/flutter/lib/src/material/card.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/flutter/lib/src/material/card.dart b/packages/flutter/lib/src/material/card.dart index a39ff240b08d0..085d88d9c7afe 100644 --- a/packages/flutter/lib/src/material/card.dart +++ b/packages/flutter/lib/src/material/card.dart @@ -78,6 +78,12 @@ class Card extends StatelessWidget { /// /// Defines the card's [Material.color]. /// + /// In Material 3, [surfaceTintColor] is drawn on top of this color + /// when the card is elevated. This might make the appearance of + /// the card slightly different than in Material 2. To disable this + /// feature, set [surfaceTintColor] to [Colors.transparent]. + /// See [Material.surfaceTintColor] for more details. + /// /// If this property is null then the ambient [CardTheme.color] is used. If that is null, /// and [ThemeData.useMaterial3] is true, then [ColorScheme.surface] of /// [ThemeData.colorScheme] is used. Otherwise, [ThemeData.cardColor] is used. From 3c8c3004f379569e3152ed71117bbbfe63bf945b Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 28 Jul 2023 08:42:35 -0700 Subject: [PATCH 0421/1547] Move ios_app_with_extensions_test to host only (#131441) `ios_app_with_extensions_test` only builds the artifact, it does not need a device to run. This PR adds the copies of these tests to run hostonly. When the new tests pass in post submit, we should remove the old ones. --- .ci.yaml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 9663ae9ef2b9f..84972a0d89810 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3764,6 +3764,26 @@ targets: ["devicelab", "ios", "mac", "arm64"] task_name: ios_app_with_extensions_test + - name: Mac_x64 ios_app_with_extensions_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "mac"] + task_name: ios_app_with_extensions_test + bringup: true + + - name: Mac_arm64 ios_app_with_extensions_test + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "mac", "arm64"] + task_name: ios_app_with_extensions_test + bringup: true + - name: Mac_ios ios_content_validation_test recipe: devicelab/devicelab_drone presubmit: false From 6b6f5f0639ed31861c4e8a0492773ef7d1fe765e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 11:52:39 -0400 Subject: [PATCH 0422/1547] Roll Packages from f4ae9336ebb7 to 10aab445d985 (4 revisions) (#131483) https://github.com/flutter/packages/compare/f4ae9336ebb7...10aab445d985 2023-07-28 tarrinneal@gmail.com remove unneeded imports (flutter/packages#4579) 2023-07-27 43054281+camsim99@users.noreply.github.com [camerax] Wrap classes to implement resolution configuration for image capture, image analysis, and preview (flutter/packages#4523) 2023-07-27 50643541+Mairramer@users.noreply.github.com [camera_android] Provides a default exposure point if null. (flutter/packages#3851) 2023-07-27 engine-flutter-autoroll@skia.org Roll Flutter from 61fd11db2b7a to dd9764ec3447 (5 revisions) (flutter/packages#4577) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index e207becb7e0be..d0635fa7d063e 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -f4ae9336ebb7d9865e5e2fb6efc5657918c6ee6d +10aab445d98562ee22ab816283ea72f186ad677f From f0163c0cd05f7d6960b4b57b1dd9b667b73ae0a9 Mon Sep 17 00:00:00 2001 From: Daniel Chevalier Date: Fri, 28 Jul 2023 11:53:26 -0400 Subject: [PATCH 0423/1547] Shared state to support multi screen inspection (#129452) ![](https://media.giphy.com/media/KY2dtJNlGPH08w41FN/giphy.gif) Fixes https://github.com/flutter/devtools/issues/5931 With Multi View applications on the way, we need to be able to manage the state of multiple Inspector widgets in a consistent way. Previously each Widget inspector would manage the state of it's own inspection. This made for a confusing and inconsistent experience when clicking on the widget inspector of different views. This PR changes the state management to the WidgetInspectorService static instance so that all widget inspectors can share that state. # Demo https://github.com/flutter/flutter/assets/1386322/70fd18dc-5827-4dcd-8cb7-ef20e6221291 --- .../lib/src/widgets/widget_inspector.dart | 104 ++++++++------- .../test/widgets/widget_inspector_test.dart | 126 ++++++++++++++---- .../widgets/widget_inspector_test_utils.dart | 7 + 3 files changed, 162 insertions(+), 75 deletions(-) diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index d3ffc09525ea0..35cf0baa80d57 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -716,7 +716,15 @@ class InspectorReferenceData { } // Production implementation of [WidgetInspectorService]. -class _WidgetInspectorService = Object with WidgetInspectorService; +class _WidgetInspectorService with WidgetInspectorService { + _WidgetInspectorService() { + selection.addListener(() { + if (selectionChangedCallback != null) { + selectionChangedCallback!(); + } + }); + } +} /// Service used by GUI tools to interact with the [WidgetInspector]. /// @@ -747,6 +755,15 @@ mixin WidgetInspectorService { /// The current [WidgetInspectorService]. static WidgetInspectorService get instance => _instance; static WidgetInspectorService _instance = _WidgetInspectorService(); + + /// Whether the inspector is in select mode. + /// + /// In select mode, pointer interactions trigger widget selection instead of + /// normal interactions. Otherwise the previously selected widget is + /// highlighted but the application can be interacted with normally. + @visibleForTesting + final ValueNotifier isSelectMode = ValueNotifier(true); + @protected static set instance(WidgetInspectorService instance) { _instance = instance; @@ -1562,18 +1579,7 @@ mixin WidgetInspectorService { selection.current = object! as RenderObject; _sendInspectEvent(selection.current); } - if (selectionChangedCallback != null) { - if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) { - selectionChangedCallback!(); - } else { - // It isn't safe to trigger the selection change callback if we are in - // the middle of rendering the frame. - SchedulerBinding.instance.scheduleTask( - selectionChangedCallback!, - Priority.touch, - ); - } - } + return true; } return false; @@ -2675,18 +2681,13 @@ class WidgetInspector extends StatefulWidget { class _WidgetInspectorState extends State with WidgetsBindingObserver { - _WidgetInspectorState() : selection = WidgetInspectorService.instance.selection; + _WidgetInspectorState(); Offset? _lastPointerLocation; - final InspectorSelection selection; + late InspectorSelection selection; - /// Whether the inspector is in select mode. - /// - /// In select mode, pointer interactions trigger widget selection instead of - /// normal interactions. Otherwise the previously selected widget is - /// highlighted but the application can be interacted with normally. - bool isSelectMode = true; + late bool isSelectMode; final GlobalKey _ignorePointerKey = GlobalKey(); @@ -2694,28 +2695,32 @@ class _WidgetInspectorState extends State /// as selecting the edge of the bounding box. static const double _edgeHitMargin = 2.0; - InspectorSelectionChangedCallback? _selectionChangedCallback; @override void initState() { super.initState(); - _selectionChangedCallback = () { - setState(() { - // The [selection] property which the build method depends on has - // changed. - }); - }; - WidgetInspectorService.instance.selectionChangedCallback = _selectionChangedCallback; + WidgetInspectorService.instance.selection + .addListener(_selectionInformationChanged); + WidgetInspectorService.instance.isSelectMode + .addListener(_selectionInformationChanged); + selection = WidgetInspectorService.instance.selection; + isSelectMode = WidgetInspectorService.instance.isSelectMode.value; } @override void dispose() { - if (WidgetInspectorService.instance.selectionChangedCallback == _selectionChangedCallback) { - WidgetInspectorService.instance.selectionChangedCallback = null; - } + WidgetInspectorService.instance.selection + .removeListener(_selectionInformationChanged); + WidgetInspectorService.instance.isSelectMode + .removeListener(_selectionInformationChanged); super.dispose(); } + void _selectionInformationChanged() => setState((){ + selection = WidgetInspectorService.instance.selection; + isSelectMode = WidgetInspectorService.instance.isSelectMode.value; + }); + bool _hitTestHelper( List hits, List edgeHits, @@ -2802,9 +2807,7 @@ class _WidgetInspectorState extends State final RenderObject userRender = ignorePointer.child!; final List selected = hitTest(position, userRender); - setState(() { - selection.candidates = selected; - }); + selection.candidates = selected; } void _handlePanDown(DragDownDetails event) { @@ -2826,9 +2829,7 @@ class _WidgetInspectorState extends State final ui.FlutterView view = View.of(context); final Rect bounds = (Offset.zero & (view.physicalSize / view.devicePixelRatio)).deflate(_kOffScreenMargin); if (!bounds.contains(_lastPointerLocation!)) { - setState(() { - selection.clear(); - }); + selection.clear(); } } @@ -2840,18 +2841,15 @@ class _WidgetInspectorState extends State _inspectAt(_lastPointerLocation!); WidgetInspectorService.instance._sendInspectEvent(selection.current); } - setState(() { - // Only exit select mode if there is a button to return to select mode. - if (widget.selectButtonBuilder != null) { - isSelectMode = false; - } - }); + + // Only exit select mode if there is a button to return to select mode. + if (widget.selectButtonBuilder != null) { + WidgetInspectorService.instance.isSelectMode.value = false; + } } void _handleEnableSelect() { - setState(() { - isSelectMode = true; - }); + WidgetInspectorService.instance.isSelectMode.value = true; } @override @@ -2885,7 +2883,7 @@ class _WidgetInspectorState extends State } /// Mutable selection state of the inspector. -class InspectorSelection { +class InspectorSelection with ChangeNotifier { /// Render objects that are candidates to be selected. /// /// Tools may wish to iterate through the list of candidates. @@ -2924,6 +2922,7 @@ class InspectorSelection { if (_current != value) { _current = value; _currentElement = (value?.debugCreator as DebugCreator?)?.element; + notifyListeners(); } } @@ -2941,11 +2940,13 @@ class InspectorSelection { if (element?.debugIsDefunct ?? false) { _currentElement = null; _current = null; + notifyListeners(); return; } if (currentElement != element) { _currentElement = element; _current = element!.findRenderObject(); + notifyListeners(); } } @@ -2953,9 +2954,11 @@ class InspectorSelection { if (_index < candidates.length) { _current = candidates[index]; _currentElement = (_current?.debugCreator as DebugCreator?)?.element; + notifyListeners(); } else { _current = null; _currentElement = null; + notifyListeners(); } } @@ -3234,7 +3237,10 @@ class _InspectorOverlayLayer extends Layer { Rect targetRect, ) { canvas.save(); - final double maxWidth = size.width - 2 * (_kScreenEdgeMargin + _kTooltipPadding); + final double maxWidth = math.max( + size.width - 2 * (_kScreenEdgeMargin + _kTooltipPadding), + 0, + ); final TextSpan? textSpan = _textPainter?.text as TextSpan?; if (_textPainter == null || textSpan!.text != message || _textPainterMaxWidth != maxWidth) { _textPainterMaxWidth = maxWidth; diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 9e00c5352bab3..125f3b83afce0 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -284,7 +284,9 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { static void runTests() { final TestWidgetInspectorService service = TestWidgetInspectorService(); WidgetInspectorService.instance = service; - + setUp(() { + WidgetInspectorService.instance.isSelectMode.value = true; + }); tearDown(() async { service.resetAllState(); @@ -358,8 +360,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { Widget selectButtonBuilder(BuildContext context, VoidCallback onPressed) { return Material(child: ElevatedButton(onPressed: onPressed, key: selectButtonKey, child: null)); } - // State type is private, hence using dynamic. - dynamic getInspectorState() => inspectorKey.currentState; + String paragraphText(RenderParagraph paragraph) { final TextSpan textSpan = paragraph.text as TextSpan; return textSpan.text!; @@ -394,16 +395,23 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ), ); - expect(getInspectorState().selection.current, isNull); // ignore: avoid_dynamic_calls + expect(WidgetInspectorService.instance.selection.current, isNull); await tester.tap(find.text('TOP'), warnIfMissed: false); await tester.pump(); // Tap intercepted by the inspector expect(log, equals([])); // ignore: avoid_dynamic_calls - final InspectorSelection selection = getInspectorState().selection as InspectorSelection; - expect(paragraphText(selection.current! as RenderParagraph), equals('TOP')); + expect( + paragraphText( + WidgetInspectorService.instance.selection.current! as RenderParagraph, + ), + equals('TOP'), + ); final RenderObject topButton = find.byKey(topButtonKey).evaluate().first.renderObject!; - expect(selection.candidates, contains(topButton)); + expect( + WidgetInspectorService.instance.selection.candidates, + contains(topButton), + ); await tester.tap(find.text('TOP')); expect(log, equals(['top'])); @@ -414,7 +422,12 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { log.clear(); // Ensure the inspector selection has not changed to bottom. // ignore: avoid_dynamic_calls - expect(paragraphText(getInspectorState().selection.current as RenderParagraph), equals('TOP')); + expect( + paragraphText( + WidgetInspectorService.instance.selection.current! as RenderParagraph, + ), + equals('TOP'), + ); await tester.tap(find.byKey(selectButtonKey)); await tester.pump(); @@ -425,7 +438,12 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(log, equals([])); log.clear(); // ignore: avoid_dynamic_calls - expect(paragraphText(getInspectorState().selection.current as RenderParagraph), equals('BOTTOM')); + expect( + paragraphText( + WidgetInspectorService.instance.selection.current! as RenderParagraph, + ), + equals('BOTTOM'), + ); }); testWidgets('WidgetInspector non-invertible transform regression test', (WidgetTester tester) async { @@ -461,8 +479,6 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { Widget selectButtonBuilder(BuildContext context, VoidCallback onPressed) { return Material(child: ElevatedButton(onPressed: onPressed, key: selectButtonKey, child: null)); } - // State type is private, hence using dynamic. - dynamic getInspectorState() => inspectorKey.currentState; await tester.pumpWidget( Directionality( @@ -498,7 +514,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { await tester.tap(find.byType(ListView), warnIfMissed: false); await tester.pump(); - expect(getInspectorState().selection.current, isNotNull); // ignore: avoid_dynamic_calls + expect(WidgetInspectorService.instance.selection.current, isNotNull); // Now out of inspect mode due to the click. await tester.fling(find.byType(ListView), const Offset(0.0, -200.0), 200.0); @@ -582,17 +598,23 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ); await tester.longPress(find.byKey(clickTarget), warnIfMissed: false); - // State type is private, hence using dynamic. - final dynamic inspectorState = inspectorKey.currentState; // The object with width 95.0 wins over the object with width 94.0 because // the subtree with width 94.0 is offstage. // ignore: avoid_dynamic_calls - expect(inspectorState.selection.current.semanticBounds.width, equals(95.0)); + expect( + WidgetInspectorService.instance.selection.current?.semanticBounds.width, + equals(95.0), + ); // Exactly 2 out of the 3 text elements should be in the candidate list of // objects to select as only 2 are onstage. // ignore: avoid_dynamic_calls - expect(inspectorState.selection.candidates.where((RenderObject object) => object is RenderParagraph).length, equals(2)); + expect( + WidgetInspectorService.instance.selection.candidates + .whereType() + .length, + equals(2), + ); }); testWidgets('WidgetInspector with Transform above', (WidgetTester tester) async { @@ -661,9 +683,6 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { }; } - // State type is private, hence using dynamic. - // The inspector state is static, so it's enough with reading one of them. - dynamic getInspectorState() => inspector1Key.currentState; String paragraphText(RenderParagraph paragraph) { final TextSpan textSpan = paragraph.text as TextSpan; return textSpan.text!; @@ -699,18 +718,27 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { ), ); - // ignore: avoid_dynamic_calls - final InspectorSelection selection = getInspectorState().selection as InspectorSelection; - // The selection is static, so it may be initialized from previous tests. - selection.clear(); - await tester.tap(find.text('Child 1'), warnIfMissed: false); await tester.pump(); - expect(paragraphText(selection.current! as RenderParagraph), equals('Child 1')); + expect( + paragraphText( + WidgetInspectorService.instance.selection.current! as RenderParagraph, + ), + equals('Child 1'), + ); + + // Re-enable select mode since it's state is shared between the + // WidgetInspectors + WidgetInspectorService.instance.isSelectMode.value = true; await tester.tap(find.text('Child 2'), warnIfMissed: false); await tester.pump(); - expect(paragraphText(selection.current! as RenderParagraph), equals('Child 2')); + expect( + paragraphText( + WidgetInspectorService.instance.selection.current! as RenderParagraph, + ), + equals('Child 2'), + ); }); test('WidgetInspectorService null id', () { @@ -2001,6 +2029,52 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { skip: !WidgetInspectorService.instance.isWidgetCreationTracked(), // [intended] Test requires --track-widget-creation flag. ); + group('InspectorSelection', () { + testWidgets('receives notifications when selection changes', + (WidgetTester tester) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: [ + Text('a'), + Text('b'), + ], + ), + ), + ); + final InspectorSelection selection = InspectorSelection(); + int count = 0; + selection.addListener(() { + count++; + }); + final RenderParagraph renderObjectA = + tester.renderObject(find.text('a')); + final RenderParagraph renderObjectB = + tester.renderObject(find.text('b')); + final Element elementA = find.text('a').evaluate().first; + + selection.candidates = [renderObjectA, renderObjectB]; + await tester.pump(); + expect(count, equals(1)); + + selection.index = 1; + await tester.pump(); + expect(count, equals(2)); + + selection.clear(); + await tester.pump(); + expect(count, equals(3)); + + selection.current = renderObjectA; + await tester.pump(); + expect(count, equals(4)); + + selection.currentElement = elementA; + expect(count, equals(5)); + }); + }); + test('ext.flutter.inspector.disposeGroup', () async { final Object a = Object(); const String group1 = 'group-1'; diff --git a/packages/flutter/test/widgets/widget_inspector_test_utils.dart b/packages/flutter/test/widgets/widget_inspector_test_utils.dart index c43e388b36364..843b76e3e8522 100644 --- a/packages/flutter/test/widgets/widget_inspector_test_utils.dart +++ b/packages/flutter/test/widgets/widget_inspector_test_utils.dart @@ -37,6 +37,13 @@ class DispatchedEventKey { } class TestWidgetInspectorService extends Object with WidgetInspectorService { + TestWidgetInspectorService() { + selection.addListener(() { + if (selectionChangedCallback != null) { + selectionChangedCallback!(); + } + }); + } final Map extensions = {}; final Map>> eventsDispatched = From d822f6627e0ca75d128c73a608b324bdfbd0dd07 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 12:19:13 -0400 Subject: [PATCH 0424/1547] Roll Flutter Engine from e97014c71014 to 73615d66b2fe (3 revisions) (#131485) https://github.com/flutter/engine/compare/e97014c71014...73615d66b2fe 2023-07-28 skia-flutter-autoroll@skia.org Roll Dart SDK from 1b85515a995b to e9bdbe308478 (1 revision) (flutter/engine#44104) 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from f538575451a8 to c98a755dff8e (1 revision) (flutter/engine#44103) 2023-07-28 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from e_QdQPRjE5lCfa2Hy... to vTivaP4a62tRMYue1... (flutter/engine#44102) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from e_QdQPRjE5lC to vTivaP4a62tR If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 813ec07c6af22..ecf5ece6a9868 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e97014c7101430d42dd4d6211d3c1b8ccb432c57 +73615d66b2fe1315e0b76f3ced6d07f9677b4c33 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 760c2f8e27f87..732454d26f355 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -e_QdQPRjE5lCfa2HyVLehbHm-XAfLRGPUDPNldy4gaMC +vTivaP4a62tRMYue1jFX3rppEAZqwWa_8tjz5CydwCUC From 79033ed83b76209db84fcbbaa7feefb9ce5c0aa7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 28 Jul 2023 09:21:16 -0700 Subject: [PATCH 0425/1547] Remove obsolete `complex_layout_ios__compile.dart` test (#131487) The test is obsolete. --- TESTOWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/TESTOWNERS b/TESTOWNERS index 49f579e8527eb..8f0be05514b1a 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -154,7 +154,6 @@ /dev/devicelab/bin/tasks/channels_integration_test_ios.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/codegen_integration_mac.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/color_filter_and_fade_perf_ios__e2e_summary.dart @cyanglaz @flutter/engine -/dev/devicelab/bin/tasks/complex_layout_ios__compile.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/complex_layout_ios__start_up.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/complex_layout_scroll_perf_bad_ios__timeline_summary.dart @jonahwilliams @flutter/engine /dev/devicelab/bin/tasks/complex_layout_scroll_perf_ios__timeline_summary.dart @cyanglaz @flutter/engine From 038ec62b285d483469b87275b183cd371448a85e Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 28 Jul 2023 20:16:04 +0300 Subject: [PATCH 0426/1547] =?UTF-8?q?Add=20`CheckedPopupMenuItem=E2=80=8E.?= =?UTF-8?q?labelTextStyle`=20and=20update=20default=20text=20style=20for?= =?UTF-8?q?=20Material=203=20(#131060)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes [Update `CheckedPopupMenuItem‎` for Material 3](https://github.com/flutter/flutter/issues/128576) ### Description - This adds the missing ``CheckedPopupMenuItem‎.labelTextStyle` parameter - Fixes default text style for `CheckedPopupMenuItem‎`. It used `ListTile`'s `bodyLarge` instead of `LabelLarge` similar to `PopupMenuItem`. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, textTheme: const TextTheme( labelLarge: TextStyle( fontWeight: FontWeight.bold, fontStyle: FontStyle.italic, letterSpacing: 5.0, ), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Sample'), actions: [ PopupMenuButton( icon: const Icon(Icons.more_vert), itemBuilder: (BuildContext context) => >[ const CheckedPopupMenuItem( // labelTextStyle: MaterialStateProperty.resolveWith( // (Set states) { // if (states.contains(MaterialState.selected)) { // return const TextStyle( // color: Colors.red, // fontStyle: FontStyle.italic, // fontWeight: FontWeight.bold, // ); // } // return const TextStyle( // color: Colors.amber, // fontStyle: FontStyle.italic, // fontWeight: FontWeight.bold, // ); // }), child: Text('Mild'), ), const CheckedPopupMenuItem( checked: true, // labelTextStyle: MaterialStateProperty.resolveWith( // (Set states) { // if (states.contains(MaterialState.selected)) { // return const TextStyle( // color: Colors.red, // fontStyle: FontStyle.italic, // fontWeight: FontWeight.bold, // ); // } // return const TextStyle( // color: Colors.amber, // fontStyle: FontStyle.italic, // fontWeight: FontWeight.bold, // ); // }), child: Text('Spicy'), ), const PopupMenuDivider(), const PopupMenuItem( value: 'Close', child: Text('Close'), ), ], ) ], ), ); } } ```
### Customized `textTheme.labelLarge` text theme. | Before | After | | --------------- | --------------- | | | | ### New `CheckedPopupMenuItem‎.labelTextStyle` parameter with material states support --- .../flutter/lib/src/material/popup_menu.dart | 11 ++ .../test/material/popup_menu_test.dart | 118 ++++++++++++++++++ .../test/material/popup_menu_theme_test.dart | 58 +++++++-- 3 files changed, 178 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 1d80305e74d62..60081cf0a619c 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -475,6 +475,7 @@ class CheckedPopupMenuItem extends PopupMenuItem { super.enabled, super.padding, super.height, + super.labelTextStyle, super.mouseCursor, super.child, }); @@ -529,9 +530,19 @@ class _CheckedPopupMenuItemState extends PopupMenuItemState states = { + if (widget.checked) MaterialState.selected, + }; + final MaterialStateProperty? effectiveLabelTextStyle = widget.labelTextStyle + ?? popupMenuTheme.labelTextStyle + ?? defaults.labelTextStyle; return IgnorePointer( child: ListTile( enabled: widget.enabled, + titleTextStyle: effectiveLabelTextStyle?.resolve(states), leading: FadeTransition( opacity: _opacity, child: Icon(_controller.isDismissed ? null : Icons.done), diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index ea3c47668eb15..3a8b4e2040e76 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -3307,6 +3307,117 @@ void main() { final Finder modalBottomSheet = find.text('ModalBottomSheet'); expect(modalBottomSheet, findsOneWidget); }); + + testWidgets('Material3 - CheckedPopupMenuItem.labelTextStyle uses correct text style', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + ThemeData theme = ThemeData(useMaterial3: true); + + Widget buildMenu() { + return MaterialApp( + theme: theme, + home: Scaffold( + appBar: AppBar( + actions: [ + PopupMenuButton( + key: popupMenuButtonKey, + itemBuilder: (BuildContext context) => >[ + const CheckedPopupMenuItem( + child: Text('Item 1'), + ), + const CheckedPopupMenuItem( + checked: true, + child: Text('Item 2'), + ), + ], + ), + ], + ), + ), + ); + } + + await tester.pumpWidget(buildMenu()); + + // Show the menu + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + // Test default text style. + expect(_labelStyle(tester, 'Item 1')!.fontSize, 14.0); + expect(_labelStyle(tester, 'Item 1')!.color, theme.colorScheme.onSurface); + + // Close the menu. + await tester.tapAt(const Offset(20.0, 20.0)); + await tester.pumpAndSettle(); + + // Test custom text theme text style. + theme = theme.copyWith( + textTheme: theme.textTheme.copyWith( + labelLarge: const TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + ) + ), + ); + await tester.pumpWidget(buildMenu()); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + expect(_labelStyle(tester, 'Item 1')!.fontSize, 20.0); + expect(_labelStyle(tester, 'Item 1')!.fontWeight, FontWeight.bold); + }); + + testWidgets('CheckedPopupMenuItem.labelTextStyle resolve material states', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + final MaterialStateProperty labelTextStyle = MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.selected)) { + return const TextStyle(color: Colors.red, fontSize: 24.0); + } + + return const TextStyle(color: Colors.amber, fontSize: 20.0); + }); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + appBar: AppBar( + actions: [ + PopupMenuButton( + key: popupMenuButtonKey, + itemBuilder: (BuildContext context) => >[ + CheckedPopupMenuItem( + labelTextStyle: labelTextStyle, + child: const Text('Item 1'), + ), + CheckedPopupMenuItem( + checked: true, + labelTextStyle: labelTextStyle, + child: const Text('Item 2'), + ), + ], + ), + ], + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + expect( + _labelStyle(tester, 'Item 1'), + labelTextStyle.resolve({}) + ); + expect( + _labelStyle(tester, 'Item 2'), + labelTextStyle.resolve({MaterialState.selected}) + ); + }); } class TestApp extends StatelessWidget { @@ -3377,3 +3488,10 @@ class _ClosureNavigatorObserver extends NavigatorObserver { @override void didReplace({Route? newRoute, Route? oldRoute}) => onDidChange(newRoute!); } + +TextStyle? _labelStyle(WidgetTester tester, String label) { + return tester.widget(find.descendant( + of: find.text(label), + matching: find.byType(RichText), + )).text.style; +} diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index 8b61cbc39a63a..e2b5ba6444803 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -149,6 +149,13 @@ void main() { enabled: false, child: const Text('Disabled PopupMenuItem'), ), + const CheckedPopupMenuItem( + child: Text('Unchecked item'), + ), + const CheckedPopupMenuItem( + checked: true, + child: Text('Checked item'), + ), ]; }, ), @@ -181,22 +188,23 @@ void main() { /// [PopupMenuItem] specified above, so by finding the last descendent of /// popupItemKey that is of type DefaultTextStyle, this code retrieves the /// built [PopupMenuItem]. - final DefaultTextStyle enabledText = tester.widget( + DefaultTextStyle popupMenuItemLabel = tester.widget( find.descendant( of: find.byKey(enabledPopupItemKey), matching: find.byType(DefaultTextStyle), ).last, ); - expect(enabledText.style.fontFamily, 'Roboto'); - expect(enabledText.style.color, theme.colorScheme.onSurface); + expect(popupMenuItemLabel.style.fontFamily, 'Roboto'); + expect(popupMenuItemLabel.style.color, theme.colorScheme.onSurface); + /// Test disabled text color - final DefaultTextStyle disabledText = tester.widget( + popupMenuItemLabel = tester.widget( find.descendant( of: find.byKey(disabledPopupItemKey), matching: find.byType(DefaultTextStyle), ).last, ); - expect(disabledText.style.color, theme.colorScheme.onSurface.withOpacity(0.38)); + expect(popupMenuItemLabel.style.color, theme.colorScheme.onSurface.withOpacity(0.38)); final Offset topLeftButton = tester.getTopLeft(find.byType(PopupMenuButton)); final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); @@ -217,6 +225,14 @@ void main() { RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click, ); + + // Test unchecked CheckedPopupMenuItem label. + ListTile listTile = tester.widget(find.byType(ListTile).first); + expect(listTile.titleTextStyle?.color, theme.colorScheme.onSurface); + + // Test checked CheckedPopupMenuItem label. + listTile = tester.widget(find.byType(ListTile).last); + expect(listTile.titleTextStyle?.color, theme.colorScheme.onSurface); }); testWidgetsWithLeakTracking('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { @@ -251,6 +267,13 @@ void main() { onTap: () { }, child: const Text('enabled'), ), + const CheckedPopupMenuItem( + child: Text('Unchecked item'), + ), + const CheckedPopupMenuItem( + checked: true, + child: Text('Checked item'), + ), ]; }, ), @@ -278,25 +301,25 @@ void main() { expect(button.shape, const BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12)))); expect(button.elevation, 12.0); - final DefaultTextStyle enabledText = tester.widget( + DefaultTextStyle popupMenuItemLabel = tester.widget( find.descendant( of: find.byKey(enabledPopupItemKey), matching: find.byType(DefaultTextStyle), ).last, ); expect( - enabledText.style, + popupMenuItemLabel.style, popupMenuTheme.labelTextStyle?.resolve(enabled), ); /// Test disabled text color - final DefaultTextStyle disabledText = tester.widget( + popupMenuItemLabel = tester.widget( find.descendant( of: find.byKey(disabledPopupItemKey), matching: find.byType(DefaultTextStyle), ).last, ); expect( - disabledText.style, + popupMenuItemLabel.style, popupMenuTheme.labelTextStyle?.resolve(disabled), ); @@ -315,6 +338,14 @@ void main() { RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), popupMenuTheme.mouseCursor?.resolve(enabled), ); + + // Test unchecked CheckedPopupMenuItem label. + ListTile listTile = tester.widget(find.byType(ListTile).first); + expect(listTile.titleTextStyle, popupMenuTheme.labelTextStyle?.resolve(enabled)); + + // Test checked CheckedPopupMenuItem label. + listTile = tester.widget(find.byType(ListTile).last); + expect(listTile.titleTextStyle, popupMenuTheme.labelTextStyle?.resolve(enabled)); }); testWidgetsWithLeakTracking('Popup menu widget properties take priority over theme', (WidgetTester tester) async { @@ -354,6 +385,11 @@ void main() { mouseCursor: cursor, child: const Text('Example'), ), + CheckedPopupMenuItem( + checked: true, + labelTextStyle: MaterialStateProperty.all(textStyle), + child: const Text('Checked item'), + ) ]; }, ), @@ -399,6 +435,10 @@ void main() { await gesture.moveTo(tester.getCenter(find.byKey(popupItemKey))); await tester.pumpAndSettle(); expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), cursor); + + // Test CheckedPopupMenuItem label. + final ListTile listTile = tester.widget(find.byType(ListTile).first); + expect(listTile.titleTextStyle, textStyle); }); group('Material 2', () { From 9cdde86fb3b938ab7e9e02337d0c02b16651777e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 13:29:02 -0400 Subject: [PATCH 0427/1547] Roll Flutter Engine from 73615d66b2fe to 182e1189873b (2 revisions) (#131492) https://github.com/flutter/engine/compare/73615d66b2fe...182e1189873b 2023-07-28 dnfield@google.com [Impeller] Avoid culling when the current matrix has perspective. (flutter/engine#44089) 2023-07-28 jacksongardner@google.com Roll Chrome to 115 (flutter/engine#44076) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ecf5ece6a9868..be3867d7184a2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -73615d66b2fe1315e0b76f3ced6d07f9677b4c33 +182e1189873bbec33d96b59f20d3b365e7aaf9ba From 3567140d9e1898ee6a51d4e9be3421cdc836c61e Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Fri, 28 Jul 2023 10:31:53 -0700 Subject: [PATCH 0428/1547] Deprecate `useMaterial3` parameter in `ThemeData.copyWith()` (#131455) --- .../lib/fix_data/fix_material/fix_theme_data.yaml | 11 +++++++++++ packages/flutter/lib/src/material/theme_data.dart | 9 ++++++++- packages/flutter/test_fixes/material/theme_data.dart | 3 +++ .../test_fixes/material/theme_data.dart.expect | 3 +++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/fix_data/fix_material/fix_theme_data.yaml b/packages/flutter/lib/fix_data/fix_material/fix_theme_data.yaml index fda29f5209ed6..f3742f88e7b74 100644 --- a/packages/flutter/lib/fix_data/fix_material/fix_theme_data.yaml +++ b/packages/flutter/lib/fix_data/fix_material/fix_theme_data.yaml @@ -1686,4 +1686,15 @@ transforms: kind: 'fragment' value: 'arguments[colorScheme]' + # Changes made in https://github.com/flutter/flutter/pull/131455 + - title: "Remove 'useMaterial3'" + date: 2023-07-27 + element: + uris: [ 'material.dart' ] + method: 'copyWith' + inClass: 'ThemeData' + changes: + - kind: 'removeParameter' + name: 'useMaterial3' + # Before adding a new fix: read instructions at the top of this file. diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 518c389348c0b..fdb5d5c98d1ff 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -1525,7 +1525,6 @@ class ThemeData with Diagnosticable { TargetPlatform? platform, ScrollbarThemeData? scrollbarTheme, InteractiveInkFeatureFactory? splashFactory, - bool? useMaterial3, VisualDensity? visualDensity, // COLOR // [colorScheme] is the preferred way to configure colors. The other color @@ -1637,6 +1636,14 @@ class ThemeData with Diagnosticable { 'This feature was deprecated after v3.3.0-0.6.pre.', ) Color? bottomAppBarColor, + @Deprecated( + 'Use a ThemeData constructor (.from, .light, or .dark) instead. ' + 'These constructors all have a useMaterial3 argument, ' + 'and they set appropriate default values based on its value. ' + 'See the useMaterial3 API documentation for full details. ' + 'This feature was deprecated after v3.13.0-0.2.pre.', + ) + bool? useMaterial3, }) { cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault(); return ThemeData.raw( diff --git a/packages/flutter/test_fixes/material/theme_data.dart b/packages/flutter/test_fixes/material/theme_data.dart index 7c4d4e50f85e0..c9c5d929cb5bc 100644 --- a/packages/flutter/test_fixes/material/theme_data.dart +++ b/packages/flutter/test_fixes/material/theme_data.dart @@ -234,4 +234,7 @@ void main() { themeData = ThemeData(bottomAppBarColor: Colors.green); themeData = ThemeData.raw(bottomAppBarColor: Colors.green); themeData = ThemeData.copyWith(bottomAppBarColor: Colors.green); + + // Changes made in https://github.com/flutter/flutter/pull/131455 + ThemeData themeData = ThemeData.copyWith(useMaterial3: false); } diff --git a/packages/flutter/test_fixes/material/theme_data.dart.expect b/packages/flutter/test_fixes/material/theme_data.dart.expect index 0992a721fa38c..9430d934e38f6 100644 --- a/packages/flutter/test_fixes/material/theme_data.dart.expect +++ b/packages/flutter/test_fixes/material/theme_data.dart.expect @@ -440,4 +440,7 @@ void main() { themeData = ThemeData(bottomAppBarTheme: BottomAppBarTheme(color: Colors.green)); themeData = ThemeData.raw(bottomAppBarTheme: BottomAppBarTheme(color: Colors.green)); themeData = ThemeData.copyWith(bottomAppBarTheme: BottomAppBarTheme(color: Colors.green)); + + // Changes made in https://github.com/flutter/flutter/pull/131455 + ThemeData themeData = ThemeData.copyWith(); } From 48d47ade9d65733a891a46e612257e715710d628 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 28 Jul 2023 22:17:28 +0300 Subject: [PATCH 0429/1547] Update `BottomSheet.enableDrag` & `BottomSheet.showDragHandle` docs for animation controller (#131484) fixes [`AnimationController` must be provided when `BottomSheet.enableDrag` or `BottomSheet.showDragHandle` is true](https://github.com/flutter/flutter/issues/127093) --- packages/flutter/lib/src/material/bottom_sheet.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index f84cfe9ae1ffd..0d683e3f23d87 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -123,6 +123,10 @@ class BottomSheet extends StatefulWidget { /// because the drag handle is always draggable. /// /// Default is true. + /// + /// If this is true, the [animationController] must not be null. + /// Use [BottomSheet.createAnimationController] to create one, or provide + /// another AnimationController. final bool enableDrag; /// Specifies whether a drag handle is shown. @@ -134,6 +138,10 @@ class BottomSheet extends StatefulWidget { /// /// If null, then the value of [BottomSheetThemeData.showDragHandle] is used. If /// that is also null, defaults to false. + /// + /// If this is true, the [animationController] must not be null. + /// Use [BottomSheet.createAnimationController] to create one, or provide + /// another AnimationController. final bool? showDragHandle; /// The bottom sheet drag handle's color. From 096b7c3c50a39ddbf0e4e5ba14bb027dc2d4abdd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 15:19:16 -0400 Subject: [PATCH 0430/1547] Roll Flutter Engine from 182e1189873b to aa1278eb7b84 (2 revisions) (#131500) https://github.com/flutter/engine/compare/182e1189873b...aa1278eb7b84 2023-07-28 skia-flutter-autoroll@skia.org Roll ANGLE from 99f1178a9e81 to c319f34c4c8c (1 revision) (flutter/engine#44109) 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from c98a755dff8e to 8f734fbb34a7 (3 revisions) (flutter/engine#44108) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index be3867d7184a2..172369251ceff 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -182e1189873bbec33d96b59f20d3b365e7aaf9ba +aa1278eb7b848f4f44d073d11c78e554cc6dac0f From 3396ec7b888e437407bfa5702656e6c82c243424 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 28 Jul 2023 14:37:00 -0700 Subject: [PATCH 0431/1547] Device discovery output cleanup (#131223) Fixes https://github.com/flutter/flutter/issues/6538 --- .../lib/src/commands/devices.dart | 55 ++--- packages/flutter_tools/lib/src/device.dart | 6 +- .../commands.shard/hermetic/devices_test.dart | 231 ++++++++++-------- 3 files changed, 163 insertions(+), 129 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/devices.dart b/packages/flutter_tools/lib/src/commands/devices.dart index 9792a3d9f4be2..b71259248d52a 100644 --- a/packages/flutter_tools/lib/src/commands/devices.dart +++ b/packages/flutter_tools/lib/src/commands/devices.dart @@ -168,48 +168,43 @@ class DevicesCommandOutput { } if (allDevices.isEmpty) { - _printNoDevicesDetected(); + _logger.printStatus('No authorized devices detected.'); } else { if (attachedDevices.isNotEmpty) { - _logger.printStatus('${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:\n'); - await Device.printDevices(attachedDevices, _logger); + _logger.printStatus('Found ${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:'); + await Device.printDevices(attachedDevices, _logger, prefix: ' '); } if (wirelessDevices.isNotEmpty) { if (attachedDevices.isNotEmpty) { _logger.printStatus(''); } - _logger.printStatus('${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:\n'); - await Device.printDevices(wirelessDevices, _logger); + _logger.printStatus('Found ${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:'); + await Device.printDevices(wirelessDevices, _logger, prefix: ' '); } } - await _printDiagnostics(); + await _printDiagnostics(foundAny: allDevices.isNotEmpty); } - void _printNoDevicesDetected() { - final StringBuffer status = StringBuffer('No devices detected.'); - status.writeln(); + Future _printDiagnostics({ required bool foundAny }) async { + final StringBuffer status = StringBuffer(); status.writeln(); + final List diagnostics = await _deviceManager?.getDeviceDiagnostics() ?? []; + if (diagnostics.isNotEmpty) { + for (final String diagnostic in diagnostics) { + status.writeln(diagnostic); + status.writeln(); + } + } status.writeln('Run "flutter emulators" to list and start any available device emulators.'); status.writeln(); - status.write('If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. '); + status.write('If you expected ${ foundAny ? 'another' : 'a' } device to be detected, please run "flutter doctor" to diagnose potential issues. '); if (deviceDiscoveryTimeout == null) { - status.write('You may also try increasing the time to wait for connected devices with the --${FlutterOptions.kDeviceTimeout} flag. '); + status.write('You may also try increasing the time to wait for connected devices with the "--${FlutterOptions.kDeviceTimeout}" flag. '); } status.write('Visit https://flutter.dev/setup/ for troubleshooting tips.'); - _logger.printStatus(status.toString()); } - Future _printDiagnostics() async { - final List diagnostics = await _deviceManager?.getDeviceDiagnostics() ?? []; - if (diagnostics.isNotEmpty) { - _logger.printStatus(''); - for (final String diagnostic in diagnostics) { - _logger.printStatus('• $diagnostic', hangingIndent: 2); - } - } - } - Future printDevicesAsJson(List devices) async { _logger.printStatus( const JsonEncoder.withIndent(' ').convert( @@ -266,8 +261,8 @@ class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCom // Display list of attached devices. if (attachedDevices.isNotEmpty) { - _logger.printStatus('${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:\n'); - await Device.printDevices(attachedDevices, _logger); + _logger.printStatus('Found ${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:'); + await Device.printDevices(attachedDevices, _logger, prefix: ' '); _logger.printStatus(''); numLinesToClear += 1; } @@ -292,8 +287,8 @@ class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCom if (_logger.isVerbose && _includeAttachedDevices) { // Reprint the attach devices. if (attachedDevices.isNotEmpty) { - _logger.printStatus('\n${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:\n'); - await Device.printDevices(attachedDevices, _logger); + _logger.printStatus('\nFound ${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:'); + await Device.printDevices(attachedDevices, _logger, prefix: ' '); } } else if (terminal.supportsColor && terminal is AnsiTerminal) { _logger.printStatus( @@ -309,16 +304,16 @@ class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCom if (wirelessDevices.isEmpty) { if (attachedDevices.isEmpty) { // No wireless or attached devices were found. - _printNoDevicesDetected(); + _logger.printStatus('No authorized devices detected.'); } else { // Attached devices found, wireless devices not found. _logger.printStatus(_noWirelessDevicesFoundMessage); } } else { // Display list of wireless devices. - _logger.printStatus('${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:\n'); - await Device.printDevices(wirelessDevices, _logger); + _logger.printStatus('Found ${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:'); + await Device.printDevices(wirelessDevices, _logger, prefix: ' '); } - await _printDiagnostics(); + await _printDiagnostics(foundAny: wirelessDevices.isNotEmpty || attachedDevices.isNotEmpty); } } diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 83d13746d29f8..c789e31652ae9 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -849,8 +849,10 @@ abstract class Device { ]; } - static Future printDevices(List devices, Logger logger) async { - (await descriptions(devices)).forEach(logger.printStatus); + static Future printDevices(List devices, Logger logger, { String prefix = '' }) async { + for (final String line in await descriptions(devices)) { + logger.printStatus('$prefix$line'); + } } static List devicesPlatformTypes(List devices) { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart index 86b8d1f74b7f0..7ffae20854d06 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart @@ -77,11 +77,11 @@ void main() { expect( testLogger.statusText, equals(''' -No devices detected. +No authorized devices detected. Run "flutter emulators" to list and start any available device emulators. -If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the --device-timeout flag. Visit https://flutter.dev/setup/ for troubleshooting tips. +If you expected a device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''), ); }, overrides: { @@ -178,16 +178,18 @@ If you expected your device to be detected, please run "flutter doctor" to diagn final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices']); expect(testLogger.statusText, ''' -2 connected devices: +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 1 wirelessly connected device: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -1 wirelessly connected device: +Cannot connect to device ABC -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -200,12 +202,15 @@ wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2 final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices', '--device-connection', 'attached']); expect(testLogger.statusText, ''' -2 connected devices: +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) + +Cannot connect to device ABC -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -217,11 +222,14 @@ webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulato final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices', '--device-connection', 'wireless']); expect(testLogger.statusText, ''' -1 wirelessly connected device: +Found 1 wirelessly connected device: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) +Cannot connect to device ABC + +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -244,12 +252,15 @@ wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2 final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices']); expect(testLogger.statusText, ''' -2 connected devices: +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Cannot connect to device ABC -• Cannot connect to device ABC +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -270,11 +281,14 @@ webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulato final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices']); expect(testLogger.statusText, ''' -1 wirelessly connected device: +Found 1 wirelessly connected device: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) +Cannot connect to device ABC -• Cannot connect to device ABC +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -308,11 +322,11 @@ wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2 equals(''' No devices found yet. Checking for wireless devices... -No devices detected. +No authorized devices detected. Run "flutter emulators" to list and start any available device emulators. -If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the --device-timeout flag. Visit https://flutter.dev/setup/ for troubleshooting tips. +If you expected a device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''), ); }, overrides: { @@ -329,11 +343,11 @@ If you expected your device to be detected, please run "flutter doctor" to diagn final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices', '--device-connection', 'attached']); expect(testLogger.statusText, ''' -No devices detected. +No authorized devices detected. Run "flutter emulators" to list and start any available device emulators. -If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the --device-timeout flag. Visit https://flutter.dev/setup/ for troubleshooting tips. +If you expected a device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => NoDevicesManager(), @@ -347,11 +361,11 @@ If you expected your device to be detected, please run "flutter doctor" to diagn expect(testLogger.statusText, ''' Checking for wireless devices... -No devices detected. +No authorized devices detected. Run "flutter emulators" to list and start any available device emulators. -If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the --device-timeout flag. Visit https://flutter.dev/setup/ for troubleshooting tips. +If you expected a device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => NoDevicesManager(), @@ -449,19 +463,21 @@ If you expected your device to be detected, please run "flutter doctor" to diagn final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices']); expect(testLogger.statusText, ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) Checking for wireless devices... -2 wirelessly connected devices: +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Cannot connect to device ABC -• Cannot connect to device ABC +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -477,10 +493,9 @@ wireless ios (mobile) • wireless-ios • ios • iOS 16 (simul terminal = FakeTerminal(supportsColor: true); fakeLogger = FakeBufferLogger(terminal: terminal); fakeLogger.originalStatusText = ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) Checking for wireless devices... '''; @@ -491,17 +506,19 @@ Checking for wireless devices... await createTestCommandRunner(command).run(['devices']); expect(fakeLogger.statusText, ''' -2 connected devices: +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) -2 wirelessly connected devices: +Cannot connect to device ABC -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => @@ -525,24 +542,25 @@ wireless ios (mobile) • wireless-ios • ios • iOS 16 (simul await createTestCommandRunner(command).run(['devices']); expect(fakeLogger.statusText, ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) Checking for wireless devices... -2 connected devices: +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) -2 wirelessly connected devices: +Cannot connect to device ABC -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager( @@ -560,12 +578,15 @@ wireless ios (mobile) • wireless-ios • ios • iOS 16 (simul expect(testLogger.statusText, ''' Checking for wireless devices... -2 wirelessly connected devices: +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) + +Cannot connect to device ABC -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -588,16 +609,19 @@ wireless ios (mobile) • wireless-ios • ios • iOS 16 (simul final DevicesCommand command = DevicesCommand(); await createTestCommandRunner(command).run(['devices']); expect(testLogger.statusText, ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) Checking for wireless devices... No wireless devices were found. -• Cannot connect to device ABC +Cannot connect to device ABC + +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -613,10 +637,9 @@ No wireless devices were found. terminal = FakeTerminal(supportsColor: true); fakeLogger = FakeBufferLogger(terminal: terminal); fakeLogger.originalStatusText = ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) Checking for wireless devices... '''; @@ -627,14 +650,17 @@ Checking for wireless devices... await createTestCommandRunner(command).run(['devices']); expect(fakeLogger.statusText, ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) No wireless devices were found. -• Cannot connect to device ABC +Cannot connect to device ABC + +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager( @@ -660,21 +686,23 @@ No wireless devices were found. await createTestCommandRunner(command).run(['devices']); expect(fakeLogger.statusText, ''' -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) Checking for wireless devices... -2 connected devices: - -ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) -webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) +Found 2 connected devices: + ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator) + webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator) No wireless devices were found. -• Cannot connect to device ABC +Cannot connect to device ABC + +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager( @@ -703,12 +731,15 @@ No wireless devices were found. expect(testLogger.statusText, ''' No devices found yet. Checking for wireless devices... -2 wirelessly connected devices: +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Cannot connect to device ABC + +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager(devices: deviceList), @@ -733,12 +764,15 @@ No devices found yet. Checking for wireless devices... await createTestCommandRunner(command).run(['devices']); expect(fakeLogger.statusText, ''' -2 wirelessly connected devices: +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Cannot connect to device ABC -• Cannot connect to device ABC +Run "flutter emulators" to list and start any available device emulators. + +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager( @@ -766,12 +800,15 @@ wireless ios (mobile) • wireless-ios • ios • iOS 16 (simul expect(fakeLogger.statusText, ''' No devices found yet. Checking for wireless devices... -2 wirelessly connected devices: +Found 2 wirelessly connected devices: + wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) + wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) -wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator) -wireless ios (mobile) • wireless-ios • ios • iOS 16 (simulator) +Cannot connect to device ABC + +Run "flutter emulators" to list and start any available device emulators. -• Cannot connect to device ABC +If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for troubleshooting tips. '''); }, overrides: { DeviceManager: () => _FakeDeviceManager( From 7b6af17f6e060244e390826f8c25aaa646661705 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Sat, 29 Jul 2023 00:00:20 +0200 Subject: [PATCH 0432/1547] Reland - Fix floating SnackBar throws when FAB is on the top (#131475) ## Description This PR is a reland of https://github.com/flutter/flutter/pull/129274 with a fix and new test related to the revert (https://github.com/flutter/flutter/pull/131303). It updates how a floating snack bar is positionned when a `Scaffold` defines a FAB with `Scaffold.floatingActionButtonLocation` sets to one of the top locations. **Before this PR:** - When a FAB location is set to the top of the `Scaffold`, a floating `SnackBar` can't be displayed and an assert throws in debug mode. **After this PR:** - When a FAB location is set to the top of the `Scaffold`, a floating `SnackBar` will be displayed at the bottom of the screen, above a `NavigationBar` for instance (the top FAB is ignored when computing the floating snack bar position). ![image](https://github.com/flutter/flutter/assets/840911/08fcee6c-b286-4749-ad0b-ba09e653bd94) ## Motivation This is a edge case related to a discrepancy between the Material spec and the Flutter `Scaffold` customizability: - Material spec states that a floating `SnackBar` should be displayed above a FAB. But, in Material spec, FABs are expected to be on the bottom. - Since https://github.com/flutter/flutter/issues/51465, Flutter `Scaffold` makes it valid to show a FAB on the top of the `Scaffold`. ## Related Issue fixes https://github.com/flutter/flutter/issues/128150 ## Tests Adds 2 tests. --- .../flutter/lib/src/material/scaffold.dart | 24 +++- .../lib/src/material/snack_bar_theme.dart | 13 +- .../flutter/test/material/snack_bar_test.dart | 126 ++++++++++++++++++ 3 files changed, 157 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index 110cbbbfb1c89..f1e820b3bcf40 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1142,7 +1142,29 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate { } final double snackBarYOffsetBase; - if (floatingActionButtonRect.size != Size.zero && isSnackBarFloating) { + final bool showAboveFab = switch (currentFloatingActionButtonLocation) { + FloatingActionButtonLocation.startTop + || FloatingActionButtonLocation.centerTop + || FloatingActionButtonLocation.endTop + || FloatingActionButtonLocation.miniStartTop + || FloatingActionButtonLocation.miniCenterTop + || FloatingActionButtonLocation.miniEndTop => false, + FloatingActionButtonLocation.startDocked + || FloatingActionButtonLocation.startFloat + || FloatingActionButtonLocation.centerDocked + || FloatingActionButtonLocation.centerFloat + || FloatingActionButtonLocation.endContained + || FloatingActionButtonLocation.endDocked + || FloatingActionButtonLocation.endFloat + || FloatingActionButtonLocation.miniStartDocked + || FloatingActionButtonLocation.miniStartFloat + || FloatingActionButtonLocation.miniCenterDocked + || FloatingActionButtonLocation.miniCenterFloat + || FloatingActionButtonLocation.miniEndDocked + || FloatingActionButtonLocation.miniEndFloat => true, + FloatingActionButtonLocation() => true, + }; + if (floatingActionButtonRect.size != Size.zero && isSnackBarFloating && showAboveFab) { snackBarYOffsetBase = floatingActionButtonRect.top; } else { // SnackBarBehavior.fixed applies a SafeArea automatically. diff --git a/packages/flutter/lib/src/material/snack_bar_theme.dart b/packages/flutter/lib/src/material/snack_bar_theme.dart index 5f976148d70fc..faf8ea72fe2e5 100644 --- a/packages/flutter/lib/src/material/snack_bar_theme.dart +++ b/packages/flutter/lib/src/material/snack_bar_theme.dart @@ -17,14 +17,17 @@ enum SnackBarBehavior { /// Fixes the [SnackBar] at the bottom of the [Scaffold]. /// /// The exception is that the [SnackBar] will be shown above a - /// [BottomNavigationBar]. Additionally, the [SnackBar] will cause other - /// non-fixed widgets inside [Scaffold] to be pushed above (for example, the - /// [FloatingActionButton]). + /// [BottomNavigationBar] or a [NavigationBar]. Additionally, the [SnackBar] + /// will cause other non-fixed widgets inside [Scaffold] to be pushed above + /// (for example, the [FloatingActionButton]). fixed, /// This behavior will cause [SnackBar] to be shown above other widgets in the - /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] - /// and a [FloatingActionButton]. + /// [Scaffold]. This includes being displayed above a [BottomNavigationBar] or + /// a [NavigationBar], and a [FloatingActionButton] when its location is on the + /// bottom. When the floating action button location is on the top, this behavior + /// will cause the [SnackBar] to be shown above other widgets in the [Scaffold] + /// except the floating action button. /// /// See for more details. floating, diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index 9436f743b4e30..9720578de9117 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -2071,6 +2071,127 @@ void main() { }, ); + testWidgets( + '${SnackBarBehavior.floating} should not align SnackBar with the top of FloatingActionButton ' + 'when Scaffold has a FloatingActionButton and floatingActionButtonLocation is set to a top position', + (WidgetTester tester) async { + Future pumpApp({required FloatingActionButtonLocation fabLocation}) async { + return tester.pumpWidget(MaterialApp( + home: Scaffold( + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.send), + onPressed: () {}, + ), + floatingActionButtonLocation: fabLocation, + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + behavior: SnackBarBehavior.floating, + )); + }, + child: const Text('X'), + ); + }, + ), + ), + )); + } + + const List topLocations = [ + FloatingActionButtonLocation.startTop, + FloatingActionButtonLocation.centerTop, + FloatingActionButtonLocation.endTop, + FloatingActionButtonLocation.miniStartTop, + FloatingActionButtonLocation.miniCenterTop, + FloatingActionButtonLocation.miniEndTop, + ]; + + for (final FloatingActionButtonLocation location in topLocations) { + await pumpApp(fabLocation: location); + + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + + expect(snackBarBottomLeft.dy, 600); // Device height is 600. + } + }, + ); + + testWidgets( + '${SnackBarBehavior.floating} should align SnackBar with the top of FloatingActionButton ' + 'when Scaffold has a FloatingActionButton and floatingActionButtonLocation is not set to a top position', + (WidgetTester tester) async { + Future pumpApp({required FloatingActionButtonLocation fabLocation}) async { + return tester.pumpWidget(MaterialApp( + home: Scaffold( + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.send), + onPressed: () {}, + ), + floatingActionButtonLocation: fabLocation, + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTap: () { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: const Text('I am a snack bar.'), + duration: const Duration(seconds: 2), + action: SnackBarAction(label: 'ACTION', onPressed: () {}), + behavior: SnackBarBehavior.floating, + )); + }, + child: const Text('X'), + ); + }, + ), + ), + )); + } + + const List nonTopLocations = [ + FloatingActionButtonLocation.startDocked, + FloatingActionButtonLocation.startFloat, + FloatingActionButtonLocation.centerDocked, + FloatingActionButtonLocation.centerFloat, + FloatingActionButtonLocation.endContained, + FloatingActionButtonLocation.endDocked, + FloatingActionButtonLocation.endFloat, + FloatingActionButtonLocation.miniStartDocked, + FloatingActionButtonLocation.miniStartFloat, + FloatingActionButtonLocation.miniCenterDocked, + FloatingActionButtonLocation.miniCenterFloat, + FloatingActionButtonLocation.miniEndDocked, + FloatingActionButtonLocation.miniEndFloat, + // Regression test related to https://github.com/flutter/flutter/pull/131303. + _CustomFloatingActionButtonLocation(), + ]; + + + for (final FloatingActionButtonLocation location in nonTopLocations) { + await pumpApp(fabLocation: location); + + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); // Have the SnackBar fully animate out. + + final Offset snackBarBottomLeft = tester.getBottomLeft(find.byType(SnackBar)); + final Offset floatingActionButtonTopLeft = tester.getTopLeft( + find.byType(FloatingActionButton), + ); + + // Since padding between the SnackBar and the FAB is created by the SnackBar, + // the bottom offset of the SnackBar should be equal to the top offset of the FAB + expect(snackBarBottomLeft.dy, floatingActionButtonTopLeft.dy); + } + }, + ); + testWidgets( '${SnackBarBehavior.fixed} should align SnackBar with the top of BottomNavigationBar ' 'when Scaffold has a BottomNavigationBar and FloatingActionButton', @@ -3749,3 +3870,8 @@ class _TestMaterialStateColor extends MaterialStateColor { return const Color(_colorRed); } } + +class _CustomFloatingActionButtonLocation extends StandardFabLocation + with FabEndOffsetX, FabFloatOffsetY { + const _CustomFloatingActionButtonLocation(); +} From 7f99e33443697dbd0f4626e1c57592ec9101b1a8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 18:17:08 -0400 Subject: [PATCH 0433/1547] Roll Flutter Engine from aa1278eb7b84 to da3721adba65 (5 revisions) (#131514) https://github.com/flutter/engine/compare/aa1278eb7b84...da3721adba65 2023-07-28 109111084+yaakovschectman@users.noreply.github.com Listen to window notifications to update application lifecycle (flutter/engine#43558) 2023-07-28 skia-flutter-autoroll@skia.org Roll ANGLE from 391bfa35798d to 0abd6f549ff1 (2 revisions) (flutter/engine#44114) 2023-07-28 dkwingsmt@users.noreply.github.com Remove a temporary lint ignore (flutter/engine#44091) 2023-07-28 skia-flutter-autoroll@skia.org Roll ANGLE from c319f34c4c8c to 391bfa35798d (1 revision) (flutter/engine#44112) 2023-07-28 43054281+camsim99@users.noreply.github.com [Android] Removes handling of Flutter splash screen (flutter/engine#44047) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 172369251ceff..a8cba5d475773 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -aa1278eb7b848f4f44d073d11c78e554cc6dac0f +da3721adba6563ded903f156b0e83ee91552a571 From d32c9ed5ddb1ed4a6b067aca51b11d4e01504f13 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 19:15:24 -0400 Subject: [PATCH 0434/1547] Roll Flutter Engine from da3721adba65 to b4bf592279d6 (2 revisions) (#131519) https://github.com/flutter/engine/compare/da3721adba65...b4bf592279d6 2023-07-28 jason-simmons@users.noreply.github.com Set the required Android API level when Vulkan validation layers are automatically enabled for android_debug_unopt_arm64 builds (flutter/engine#44116) 2023-07-28 skia-flutter-autoroll@skia.org Roll Dart SDK from e9bdbe308478 to 69c96c505f05 (1 revision) (flutter/engine#44118) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a8cba5d475773..103c1118fe985 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -da3721adba6563ded903f156b0e83ee91552a571 +b4bf592279d611e7df34f868cae929186d854729 From 6ae6dae3f3c616cb0eb1a212c77c0c2ead6d5615 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 20:07:41 -0400 Subject: [PATCH 0435/1547] Roll Flutter Engine from b4bf592279d6 to f5c17f0e2406 (1 revision) (#131525) https://github.com/flutter/engine/compare/b4bf592279d6...f5c17f0e2406 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from 8f734fbb34a7 to 4c3594988d77 (9 revisions) (flutter/engine#44119) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 103c1118fe985..b3f572bcb2a81 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b4bf592279d611e7df34f868cae929186d854729 +f5c17f0e24060be7d16c06ae687ccc71154dda9e From ee9ee5b60df167b0f1f8a532640765ee0fe5d9ca Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 21:01:24 -0400 Subject: [PATCH 0436/1547] Roll Flutter Engine from f5c17f0e2406 to 0a5b2f521539 (2 revisions) (#131529) https://github.com/flutter/engine/compare/f5c17f0e2406...0a5b2f521539 2023-07-28 skia-flutter-autoroll@skia.org Roll Skia from 4c3594988d77 to 7fe2e36ea05e (1 revision) (flutter/engine#44120) 2023-07-28 jonahwilliams@google.com [Impeller] revert removal of wait until scheduled. (flutter/engine#44121) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b3f572bcb2a81..1ed63c80fed16 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f5c17f0e24060be7d16c06ae687ccc71154dda9e +0a5b2f52153946e0d03ba5bbd9e5ad5c2f827952 From 0693d14bb24a004686068eef4e6bd9344ad042a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 29 Jul 2023 01:17:50 +0000 Subject: [PATCH 0437/1547] Bump github/codeql-action from 2.21.0 to 2.21.2 (#131512) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.0 to 2.21.2.
Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

[UNRELEASED]

No user facing changes.

2.21.2 - 28 Jul 2023

  • Update default CodeQL bundle version to 2.14.1. #1797
  • Avoid duplicating the analysis summary within the logs. #1811

2.21.1 - 26 Jul 2023

  • Improve the handling of fatal errors from the CodeQL CLI. #1795
  • Add the sarif-output output to the analyze action that contains the path to the directory of the generated SARIF. #1799

2.21.0 - 19 Jul 2023

  • CodeQL Action now requires CodeQL CLI 2.9.4 or later. For more information, see the corresponding changelog entry for CodeQL Action version 2.20.4. #1724

2.20.4 - 14 Jul 2023

  • This is the last release of the Action that supports CodeQL CLI versions 2.8.5 to 2.9.3. These versions of the CodeQL CLI were deprecated on June 20, 2023 alongside GitHub Enterprise Server 3.5 and will not be supported by the next release of the CodeQL Action (2.21.0).
    • If you are using one of these versions, please update to CodeQL CLI version 2.9.4 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
    • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.8.5 and 2.9.3, you can replace 'github/codeql-action/@​v2' by 'github/codeql-action/@​v2.20.4' in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
  • We are rolling out a feature in July 2023 that will slightly reduce the default amount of RAM used for query execution, in proportion to the runner's total memory. This will help to avoid out-of-memory failures on larger runners. #1760
  • Update default CodeQL bundle version to 2.14.0. #1762

2.20.3 - 06 Jul 2023

  • Update default CodeQL bundle version to 2.13.5. #1743

2.20.2 - 03 Jul 2023

No user facing changes.

2.20.1 - 21 Jun 2023

  • Update default CodeQL bundle version to 2.13.4. #1721
  • Experimental: add a new resolve-environment action which attempts to infer a configuration for the build environment that is required to build a given project. Do not use this in production as it is part of an internal experiment and subject to change at any time.

2.20.0 - 13 Jun 2023

  • Bump the version of the Action to 2.20.0. This ensures that users who received a Dependabot upgrade to cdcdbb5, which was mistakenly marked as Action version 2.13.4, continue to receive updates to the CodeQL Action. Full details in #1729

2.3.6 - 01 Jun 2023

  • Update default CodeQL bundle version to 2.13.3. #1698

... (truncated)

Commits
  • 0ba4244 Merge pull request #1813 from github/update-v2.21.2-10c6bfee1
  • a9a416c Update changelog for v2.21.2
  • 10c6bfe Merge pull request #1811 from github/henrymercer/print-summary-once
  • feea86e Merge pull request #1810 from github/henrymercer/ci/use-platform-specific-bun...
  • 2e6f8c0 Add changelog note
  • 8342844 Only print the analysis summary once
  • 679aac1 Use platform specific bundles in PR checks
  • de6681c Merge pull request #1797 from github/update-bundle/codeql-bundle-v2.14.1
  • f6fe5c5 Merge branch 'main' into update-bundle/codeql-bundle-v2.14.1
  • 6276217 Merge pull request #1808 from github/mergeback/v2.21.1-to-main-6ca1aa8c
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.21.0&new-version=2.21.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 0e3a7abbf06f8..cdeabc9526a93 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@1813ca74c3faaa3a2da2070b9b8a0b3e7373a0d8 + uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 with: sarif_file: results.sarif From 7c27b63c46f465b20e14d68b1951af8bc66c0ea9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 21:58:30 -0400 Subject: [PATCH 0438/1547] Roll Flutter Engine from 0a5b2f521539 to b854fdea2715 (1 revision) (#131530) https://github.com/flutter/engine/compare/0a5b2f521539...b854fdea2715 2023-07-28 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from OMmwdXn8XxipooPBo... to 1KABCKdr8VToJTlt-... (flutter/engine#44123) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from OMmwdXn8Xxip to 1KABCKdr8VTo If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1ed63c80fed16..a973709e8dcb4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0a5b2f52153946e0d03ba5bbd9e5ad5c2f827952 +b854fdea2715f4f619e13adbd2bbdc80f3a99b68 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 34703859a96ed..7e1caaad5c5d3 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -OMmwdXn8XxipooPBos19JXsr9NEghQ6xeM3bGPJnE9oC +1KABCKdr8VToJTlt-wmaa2O7OhO7yrIHNJFUWsuorXcC From 75c7cafa3157caedbec0cfa1575e0388daabd274 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jul 2023 23:00:24 -0400 Subject: [PATCH 0439/1547] Roll Flutter Engine from b854fdea2715 to 69b5b77edaf7 (1 revision) (#131532) https://github.com/flutter/engine/compare/b854fdea2715...69b5b77edaf7 2023-07-29 skia-flutter-autoroll@skia.org Roll Dart SDK from 69c96c505f05 to c2dadcad3224 (1 revision) (flutter/engine#44125) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a973709e8dcb4..3ba92721b519b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b854fdea2715f4f619e13adbd2bbdc80f3a99b68 +69b5b77edaf7e8a96ba749328677c0174b51b37c From 12924d37f191a10a5fc5347227ffbe40b56adc6a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 00:22:39 -0400 Subject: [PATCH 0440/1547] Roll Flutter Engine from 69b5b77edaf7 to 27128f29a066 (1 revision) (#131533) https://github.com/flutter/engine/compare/69b5b77edaf7...27128f29a066 2023-07-29 skia-flutter-autoroll@skia.org Roll Skia from 7fe2e36ea05e to 7dca9cd5bf70 (1 revision) (flutter/engine#44126) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3ba92721b519b..7d110be590c6a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -69b5b77edaf7e8a96ba749328677c0174b51b37c +27128f29a0666df9303085334e95f54ec351e5f4 From cc0cce7527efff4773d2c7a0e37d33068f5e2c9e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 02:28:30 -0400 Subject: [PATCH 0441/1547] Roll Flutter Engine from 27128f29a066 to 90bc483524fe (2 revisions) (#131535) https://github.com/flutter/engine/compare/27128f29a066...90bc483524fe 2023-07-29 skia-flutter-autoroll@skia.org Roll Dart SDK from c2dadcad3224 to 4fd35600b477 (1 revision) (flutter/engine#44129) 2023-07-29 skia-flutter-autoroll@skia.org Roll Skia from 7dca9cd5bf70 to 2c964e925435 (1 revision) (flutter/engine#44128) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7d110be590c6a..d6d0e414d7d5c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -27128f29a0666df9303085334e95f54ec351e5f4 +90bc483524fe5afd2fa68b5c74c9fcce664bfb2e From e94e185c364c122277798c03d39744471970d7de Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 03:33:30 -0400 Subject: [PATCH 0442/1547] Roll Flutter Engine from 90bc483524fe to 24ccd8fffbcb (1 revision) (#131540) https://github.com/flutter/engine/compare/90bc483524fe...24ccd8fffbcb 2023-07-29 skia-flutter-autoroll@skia.org Roll Skia from 2c964e925435 to 72348f7deb8d (1 revision) (flutter/engine#44130) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d6d0e414d7d5c..98ec5edbd70a9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -90bc483524fe5afd2fa68b5c74c9fcce664bfb2e +24ccd8fffbcb5ee5e5730935e3241bdcc3fa7286 From c2b40ca7013bf938acac6b0a962743ee8a3500f8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 13:42:30 -0400 Subject: [PATCH 0443/1547] Roll Flutter Engine from 24ccd8fffbcb to 5184062f7543 (2 revisions) (#131554) https://github.com/flutter/engine/compare/24ccd8fffbcb...5184062f7543 2023-07-29 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from vTivaP4a62tRMYue1... to VIjw2bdybUo-rgC0t... (flutter/engine#44137) 2023-07-29 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 1KABCKdr8VToJTlt-... to -5L2wI7BjRNgnccfl... (flutter/engine#44136) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 1KABCKdr8VTo to -5L2wI7BjRNg fuchsia/sdk/core/mac-amd64 from vTivaP4a62tR to VIjw2bdybUo- If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 98ec5edbd70a9..c161b1df84d1e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -24ccd8fffbcb5ee5e5730935e3241bdcc3fa7286 +5184062f75438073d6bba22e662590ca99a2ea60 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 7e1caaad5c5d3..776d464cb2a3c 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -1KABCKdr8VToJTlt-wmaa2O7OhO7yrIHNJFUWsuorXcC +-5L2wI7BjRNgnccfl7cJM5YVPF3VVvAscZJg7wy1yjsC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 732454d26f355..6b453f3b0e7c7 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -vTivaP4a62tRMYue1jFX3rppEAZqwWa_8tjz5CydwCUC +VIjw2bdybUo-rgC0t6Sam8yl_fIMJttcNX20tJmnZ5YC From c973f3ae031775d5b39d5e157ce16cdf0a735b0d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 16:20:25 -0400 Subject: [PATCH 0444/1547] Roll Flutter Engine from 5184062f7543 to 2b1af6df4e7c (1 revision) (#131560) https://github.com/flutter/engine/compare/5184062f7543...2b1af6df4e7c 2023-07-29 skia-flutter-autoroll@skia.org Roll Skia from 72348f7deb8d to c33c0619b892 (1 revision) (flutter/engine#44140) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c161b1df84d1e..6d3710d2e09a2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5184062f75438073d6bba22e662590ca99a2ea60 +2b1af6df4e7cc2bbdf5db861b75fd5e71c12adac From 068efb3a0c814b7e6b9ab55f29d080451295358c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 19:58:14 -0400 Subject: [PATCH 0445/1547] Roll Flutter Engine from 2b1af6df4e7c to 590ff28649eb (1 revision) (#131561) https://github.com/flutter/engine/compare/2b1af6df4e7c...590ff28649eb 2023-07-29 chinmaygarde@google.com [Impeller] Update documentation on RenderDoc frame capture. (flutter/engine#44124) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6d3710d2e09a2..6deacc189fed7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2b1af6df4e7cc2bbdf5db861b75fd5e71c12adac +590ff28649eb547b6f4dd4ac162a7c373d1042be From 4d245a8460383898f4d199857f79dcc09e302b04 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 29 Jul 2023 23:05:36 -0400 Subject: [PATCH 0446/1547] Roll Flutter Engine from 590ff28649eb to 12ce9f013cef (2 revisions) (#131562) https://github.com/flutter/engine/compare/590ff28649eb...12ce9f013cef 2023-07-30 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -5L2wI7BjRNgnccfl... to 38hspwoyzrqU6GbsM... (flutter/engine#44145) 2023-07-30 skia-flutter-autoroll@skia.org Roll ANGLE from 0abd6f549ff1 to 143fa68f50b7 (1 revision) (flutter/engine#44144) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from -5L2wI7BjRNg to 38hspwoyzrqU If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6deacc189fed7..93f6b610a15d0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -590ff28649eb547b6f4dd4ac162a7c373d1042be +12ce9f013cef3fb0d18a67e6fca9b257976e3818 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 776d464cb2a3c..fd955fc942b3d 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ --5L2wI7BjRNgnccfl7cJM5YVPF3VVvAscZJg7wy1yjsC +38hspwoyzrqU6GbsMhcLAMpKyQa-Jc6V53-ElMuevakC From 9758d773c4c8e9e4f2e2bfecd7871b54a0536200 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 30 Jul 2023 03:10:14 -0400 Subject: [PATCH 0447/1547] Roll Flutter Engine from 12ce9f013cef to 9d4bf38f987f (1 revision) (#131564) https://github.com/flutter/engine/compare/12ce9f013cef...9d4bf38f987f 2023-07-30 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from VIjw2bdybUo-rgC0t... to 17au0GOALWDVfQnwu... (flutter/engine#44148) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from VIjw2bdybUo- to 17au0GOALWDV If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 93f6b610a15d0..7708f59b25dec 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -12ce9f013cef3fb0d18a67e6fca9b257976e3818 +9d4bf38f987f7a9cda685cfed04e5b40333e1814 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 6b453f3b0e7c7..7855d04771299 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -VIjw2bdybUo-rgC0t6Sam8yl_fIMJttcNX20tJmnZ5YC +17au0GOALWDVfQnwuqwCCDD5BM8I3qR6pAIGhlvrd8wC From 7d258cb4f561e8f0f1673516dc4389ffcd3602c1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 30 Jul 2023 07:55:10 -0400 Subject: [PATCH 0448/1547] Roll Flutter Engine from 9d4bf38f987f to f3d1e004f7b1 (1 revision) (#131569) https://github.com/flutter/engine/compare/9d4bf38f987f...f3d1e004f7b1 2023-07-30 skia-flutter-autoroll@skia.org Roll Skia from c33c0619b892 to 01451297ae1b (1 revision) (flutter/engine#44150) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7708f59b25dec..12684fd32fdd5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9d4bf38f987f7a9cda685cfed04e5b40333e1814 +f3d1e004f7b1e1fd54e5257740c3270ff5f518bf From 063d68b1732ae0180de368a9a2f415de4c3fd2e1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 30 Jul 2023 09:55:20 -0400 Subject: [PATCH 0449/1547] Roll Flutter Engine from f3d1e004f7b1 to 0ccff9a2bad3 (1 revision) (#131571) https://github.com/flutter/engine/compare/f3d1e004f7b1...0ccff9a2bad3 2023-07-30 skia-flutter-autoroll@skia.org Roll Skia from 01451297ae1b to 0e62d11175aa (1 revision) (flutter/engine#44151) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 12684fd32fdd5..caf176a152dde 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f3d1e004f7b1e1fd54e5257740c3270ff5f518bf +0ccff9a2bad37707052d860073e76e7188d594f9 From 1d44fbd8b906950d3844c1de387b4062b5274243 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 30 Jul 2023 14:43:24 -0400 Subject: [PATCH 0450/1547] Roll Flutter Engine from 0ccff9a2bad3 to d95adb9c8bc6 (1 revision) (#131578) https://github.com/flutter/engine/compare/0ccff9a2bad3...d95adb9c8bc6 2023-07-30 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 38hspwoyzrqU6GbsM... to 5tPeR3pmLZVAbR1iy... (flutter/engine#44152) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 38hspwoyzrqU to 5tPeR3pmLZVA If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index caf176a152dde..bf75d73586241 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0ccff9a2bad37707052d860073e76e7188d594f9 +d95adb9c8bc6a3fea73a6d64954b600da48c1816 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index fd955fc942b3d..9a7c10de6f147 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -38hspwoyzrqU6GbsMhcLAMpKyQa-Jc6V53-ElMuevakC +5tPeR3pmLZVAbR1iygE0AAMuyYGz9hYaiZPLjD_7QWMC From 46f83ce6368e28dbb23f411752b540e745a3fed5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 30 Jul 2023 22:31:35 -0400 Subject: [PATCH 0451/1547] Roll Flutter Engine from d95adb9c8bc6 to b84c93601684 (1 revision) (#131585) https://github.com/flutter/engine/compare/d95adb9c8bc6...b84c93601684 2023-07-30 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 17au0GOALWDVfQnwu... to c0Pr9uG-46yC83ZVy... (flutter/engine#44154) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 17au0GOALWDV to c0Pr9uG-46yC If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bf75d73586241..75482f761ab0a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d95adb9c8bc6a3fea73a6d64954b600da48c1816 +b84c936016846c25475dab2befa10b47798d80d6 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7855d04771299..dc0d8ddca2e46 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -17au0GOALWDVfQnwuqwCCDD5BM8I3qR6pAIGhlvrd8wC +c0Pr9uG-46yC83ZVyXxcwx3Gm7d-fPDraC6robzSXDUC From af5d9c198bb7944e7a17f6924c4e9b454eb0ed99 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 03:05:27 -0400 Subject: [PATCH 0452/1547] Roll Flutter Engine from b84c93601684 to 22f9aad5aba5 (3 revisions) (#131592) https://github.com/flutter/engine/compare/b84c93601684...22f9aad5aba5 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 3febb7d97cb0 to 1146dd2212ba (1 revision) (flutter/engine#44158) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 0e62d11175aa to 3febb7d97cb0 (1 revision) (flutter/engine#44156) 2023-07-31 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 5tPeR3pmLZVAbR1iy... to SqCbKBft29XeD2Qvw... (flutter/engine#44155) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 5tPeR3pmLZVA to SqCbKBft29Xe If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 75482f761ab0a..fbcdb6614fecb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b84c936016846c25475dab2befa10b47798d80d6 +22f9aad5aba5d5b56e11a5c53898496f5d329f11 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 9a7c10de6f147..681cec544cd96 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -5tPeR3pmLZVAbR1iygE0AAMuyYGz9hYaiZPLjD_7QWMC +SqCbKBft29XeD2QvwCTbO3aqeNoNPgJs7NXiVmR9kX8C From f43755d321b3828b78ca5a0cecb96f66697771dd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 04:41:25 -0400 Subject: [PATCH 0453/1547] Roll Flutter Engine from 22f9aad5aba5 to b11a832ea7d4 (2 revisions) (#131597) https://github.com/flutter/engine/compare/22f9aad5aba5...b11a832ea7d4 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 91b838fe533d to 6ee21fa70879 (1 revision) (flutter/engine#44160) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 1146dd2212ba to 91b838fe533d (1 revision) (flutter/engine#44159) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fbcdb6614fecb..ee8c7c1b82edd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -22f9aad5aba5d5b56e11a5c53898496f5d329f11 +b11a832ea7d4b680131bf0435f543365928f7ffb From c05c3d3930ba44e21966e526c93443d95260f3c0 Mon Sep 17 00:00:00 2001 From: Donghyun Kim Date: Mon, 31 Jul 2023 19:09:24 +0900 Subject: [PATCH 0454/1547] Use Flutter app project's NDK version from FFI plugin (#131141) image In most cases, a FFI plugin doesn't need its own specific Android NDK version. Just following the Flutter app project's NDK version is enough. If a Flutter app project depends on multiple FFI plugins that use different Android NDK versions, it can be quite wasteful and use excessive disk space due to multiple NDK installations. Using Flutter app project's NDK version is also less error-prone because upgrading the Flutter SDK would be enough when upgrading FFI plugins(If project's `ndkVersion` is `flutter.ndkVersion`), without messing with Android NDK installations. This problem was discussed in some actual FFI plugin repositories, and they are striving to find their own solutions: - https://github.com/superlistapp/super_native_extensions/issues/143#issuecomment-1646207706 - https://github.com/cunarist/rust-in-flutter/discussions/60#discussioncomment-6484218 - https://github.com/rive-app/rive-flutter/issues/320 - https://github.com/juicycleff/flutter-unity-view-widget/issues/832 --- .../templates/plugin_ffi/android.tmpl/build.gradle.tmpl | 8 +++++--- .../android_plugin_ndkversion_mismatch_test.dart | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/templates/plugin_ffi/android.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/plugin_ffi/android.tmpl/build.gradle.tmpl index 74511b59ced82..319ed1f910a0a 100644 --- a/packages/flutter_tools/templates/plugin_ffi/android.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/plugin_ffi/android.tmpl/build.gradle.tmpl @@ -33,9 +33,11 @@ android { // to bump the version in their app. compileSdkVersion {{compileSdkVersion}} - // Bumping the plugin ndkVersion requires all clients of this plugin to bump - // the version in their app and to download a newer version of the NDK. - ndkVersion "{{ndkVersion}}" + // Use the NDK version + // declared in /android/app/build.gradle file of the Flutter project. + // Replace it with a version number if this plugin requires a specfic NDK version. + // (e.g. ndkVersion "23.1.7779620") + ndkVersion android.ndkVersion // Invoke the shared CMake build with the Android Gradle Plugin. externalNativeBuild { diff --git a/packages/flutter_tools/test/integration.shard/android_plugin_ndkversion_mismatch_test.dart b/packages/flutter_tools/test/integration.shard/android_plugin_ndkversion_mismatch_test.dart index c567c08e4782b..2580c4d16ea8d 100644 --- a/packages/flutter_tools/test/integration.shard/android_plugin_ndkversion_mismatch_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_plugin_ndkversion_mismatch_test.dart @@ -46,7 +46,7 @@ void main() { final String pluginBuildGradle = pluginGradleFile.readAsStringSync(); // Bump up plugin ndkVersion to 21.4.7075529. - final RegExp androidNdkVersionRegExp = RegExp(r'ndkVersion (\"[0-9\.]+\"|flutter.ndkVersion)'); + final RegExp androidNdkVersionRegExp = RegExp(r'ndkVersion (\"[0-9\.]+\"|flutter.ndkVersion|android.ndkVersion)'); final String newPluginGradleFile = pluginBuildGradle.replaceAll(androidNdkVersionRegExp, 'ndkVersion "21.4.7075529"'); expect(newPluginGradleFile, contains('21.4.7075529')); pluginGradleFile.writeAsStringSync(newPluginGradleFile); From fceaa005cd1837cd3d664414e336b10b828caf28 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Mon, 31 Jul 2023 13:05:11 +0200 Subject: [PATCH 0455/1547] [doc] Fix module_test_ios comments (#131470) --- dev/devicelab/bin/tasks/module_test_ios.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index 86d47afe35763..a213bbee26fef 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -27,8 +27,8 @@ Future main() async { }, ); - // this variable cannot be `late`, as we reference it in the `finally` block - // which may execute before this field has been initialized + // This variable cannot be `late`, as we reference it in the `finally` block + // which may execute before this field has been initialized. String? simulatorDeviceId; section('Create Flutter module project'); @@ -51,7 +51,7 @@ Future main() async { final Directory flutterModuleLibSource = Directory(path.join(flutterDirectory.path, 'dev', 'integration_tests', 'ios_host_app', 'flutterapp', 'lib')); final Directory flutterModuleLibDestination = Directory(path.join(projectDir.path, 'lib')); - // These test files don't have a .dart prefix so the analyzer will ignore them. They aren't in a + // These test files don't have a .dart extension so the analyzer will ignore them. They aren't in a // package and don't work on their own outside of the test module just created. final File main = File(path.join(flutterModuleLibSource.path, 'main')); main.copySync(path.join(flutterModuleLibDestination.path, 'main.dart')); From 0386f910d1448333d30d3cd0793f46e315103178 Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Mon, 31 Jul 2023 13:03:26 +0100 Subject: [PATCH 0456/1547] [flutter_tools/dap] Improve rendering of structured errors via DAP (#131251) In the legacy VS Code DAP, we would deserialise the Flutter.Error event and provide some basic colouring (eg. stack frames are faded if not from user code and the text is split between stdout/stderr to allow the client to colour it). In the new DAPs we originally used `renderedErrorText` which didn't support either of these. This change adds changes to use the structured data (with some basic parsing because the source classes are in package:flutter and not accessible here) to provide a similar experience. It would be nicer if we could use the real underlying Flutter classes for this deserialisation, but extracting them from `package:flutter` and removing all dependencies on Flutter is a much larger job and I don't think should hold up providing improved error formatting for the new DAPs. Some comparisons: ![1_comparison](https://github.com/flutter/flutter/assets/1078012/74e7e6d6-c8d0-471f-b584-37ae148b0ce7) ![2_comparison](https://github.com/flutter/flutter/assets/1078012/21888934-6f2f-4048-86d7-bdf92d5c7301) --- .../src/debug_adapters/error_formatter.dart | 187 ++++++++++++++++++ .../src/debug_adapters/flutter_adapter.dart | 12 +- .../debug_adapters/flutter_adapter_args.dart | 2 + .../debug_adapter/flutter_adapter_test.dart | 113 +++++++++-- .../debug_adapter/test_client.dart | 2 + .../debug_adapter/test_support.dart | 2 +- 6 files changed, 292 insertions(+), 26 deletions(-) create mode 100644 packages/flutter_tools/lib/src/debug_adapters/error_formatter.dart diff --git a/packages/flutter_tools/lib/src/debug_adapters/error_formatter.dart b/packages/flutter_tools/lib/src/debug_adapters/error_formatter.dart new file mode 100644 index 0000000000000..e55c235ea45ce --- /dev/null +++ b/packages/flutter_tools/lib/src/debug_adapters/error_formatter.dart @@ -0,0 +1,187 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; + +typedef _OutputSender = void Function(String category, String message, {bool? parseStackFrames, int? variablesReference}); + +/// A formatter for improving the display of Flutter structured errors over DAP. +/// +/// The formatter deserializes a `Flutter.Error` event and produces output +/// similar to the `renderedErrorText` field, but may include ansi color codes +/// to provide improved formatting (such as making stack frames from non-user +/// code faint) if the client indicated support. +/// +/// Lines that look like stack frames will be marked so they can be parsed by +/// the base adapter and attached as [Source]s to allow them to be clickable +/// in the client. +class FlutterErrorFormatter { + final List<_BatchedOutput> batchedOutput = <_BatchedOutput>[]; + + /// Formats a Flutter error. + /// + /// If this is not the first error since the reload, only a summary will be + /// included. + void formatError(Map errorData) { + final _ErrorData data = _ErrorData(errorData); + + const int assumedTerminalSize = 80; + const String barChar = '═'; + final String headerPrefix = barChar * 8; + final String headerSuffix = barChar * math.max( assumedTerminalSize - (data.description?.length ?? 0) - 2 - headerPrefix.length, 0); + final String header = '$headerPrefix ${data.description} $headerSuffix'; + _write(''); + _write(header, isError: true); + + if (data.errorsSinceReload == 0) { + data.properties.forEach(_writeNode); + data.children.forEach(_writeNode); + } else { + data.properties.forEach(_writeSummary); + } + + _write(barChar * header.length, isError: true); + } + + /// Sends all collected output through [sendOutput]. + void sendOutput(_OutputSender sendOutput) { + for (final _BatchedOutput output in batchedOutput) { + sendOutput( + output.isError ? 'stderr' : 'stdout', + output.output, + parseStackFrames: output.parseStackFrames, + ); + } + } + + /// Writes [text] to the output. + /// + /// If the last item in the batch has the same settings as this item, it will + /// be appended to the same item, otherwise a new item will be added to the + /// batch. + void _write( + String? text, { + int indent = 0, + bool isError = false, + bool parseStackFrames = false, + }) { + if (text != null) { + final String indentString = ' ' * indent; + final String message = '$indentString${text.trim()}'; + + _BatchedOutput? output = batchedOutput.lastOrNull; + if (output == null || output.isError != isError || output.parseStackFrames != parseStackFrames) { + batchedOutput.add(output = _BatchedOutput(isError, parseStackFrames: parseStackFrames)); + } + output.writeln(message); + } + } + + /// Writes [node] to the output using [indent], recursing unless [recursive] + /// is `false`. + void _writeNode(_ErrorNode node, {int indent = 0, bool recursive = true}) { + // Errors, summaries and lines starting "Exception:" are marked as errors so + // they go to stderr instead of stdout (this may cause the client to colour + // them like errors). + final bool showAsError = node.level == _DiagnosticsNodeLevel.error || + node.level == _DiagnosticsNodeLevel.summary || + (node.description?.startsWith('Exception: ') ?? false); + + if (node.showName && node.name != null) { + _write('${node.name}: ${node.description}', indent: indent, isError: showAsError); + } else if (node.description?.startsWith('#') ?? false) { + // Possible stack frame. + _write(node.description, indent: indent, isError: showAsError, parseStackFrames: true); + } else { + _write(node.description, indent: indent, isError: showAsError); + } + + if (recursive) { + if (node.style != _DiagnosticsNodeStyle.flat) { + indent++; + } + _writeNodes(node.properties, indent: indent); + _writeNodes(node.children, indent: indent); + } + } + + /// Writes [nodes] to the output. + void _writeNodes(List<_ErrorNode> nodes, {int indent = 0, bool recursive = true}) { + for (final _ErrorNode child in nodes) { + _writeNode(child, indent: indent, recursive: recursive); + } + } + + /// Writes a simple summary of [node] to the output. + void _writeSummary(_ErrorNode node) { + final bool allChildrenAreLeaf = node.children.isNotEmpty && + !node.children.any((_ErrorNode child) => child.children.isNotEmpty); + if (node.level == _DiagnosticsNodeLevel.summary || allChildrenAreLeaf) { + _writeNode(node, recursive: false); + } + } +} + +/// A container for output to be sent to the client. +/// +/// When multiple lines are being sent, they may be written to the same batch +/// if the output options (error/stackFrame) are the same. +class _BatchedOutput { + _BatchedOutput(this.isError, {this.parseStackFrames = false}); + + final bool isError; + final bool parseStackFrames; + final StringBuffer _buffer = StringBuffer(); + + String get output => _buffer.toString(); + + void writeln(String output) => _buffer.writeln(output); +} + +enum _DiagnosticsNodeLevel { + error, + summary, +} + +enum _DiagnosticsNodeStyle { + flat, +} + +class _ErrorData extends _ErrorNode { + _ErrorData(super.data); + + int get errorsSinceReload => data['errorsSinceReload'] as int? ?? 0; + String get renderedErrorText => data['renderedErrorText'] as String? ?? ''; +} + +class _ErrorNode { + _ErrorNode(this.data); + + final Map data; + + List<_ErrorNode> get children => asList('children', _ErrorNode.new); + String? get description => asString('description'); + _DiagnosticsNodeLevel? get level => asEnum('level', _DiagnosticsNodeLevel.values); + String? get name => asString('name'); + List<_ErrorNode> get properties => asList('properties', _ErrorNode.new); + bool get showName => data['showName'] != false; + _DiagnosticsNodeStyle? get style => asEnum('style', _DiagnosticsNodeStyle.values); + + String? asString(String field) { + final Object? value = data[field]; + return value is String ? value : null; + } + + T? asEnum(String field, Iterable enumValues) { + final String? value = asString(field); + return value != null ? enumValues.asNameMap()[value] : null; + } + + List asList(String field, T Function(Map) constructor) { + final Object? objects = data[field]; + return objects is List && objects.every((Object? element) => element is Map) + ? objects.cast>().map(constructor).toList() + : []; + } +} diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart index e0e3402bb4466..891ba224a4d6d 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart @@ -12,6 +12,7 @@ import '../base/io.dart'; import '../cache.dart'; import '../convert.dart'; import '../globals.dart' as globals show fs; +import 'error_formatter.dart'; import 'flutter_adapter_args.dart'; import 'flutter_base_adapter.dart'; @@ -219,17 +220,14 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter with VmServiceInfoFile /// Sends OutputEvents to the client for a Flutter.Error event. void _handleFlutterErrorEvent(vm.ExtensionData? data) { - final Map? errorData = data?.data; + final Map? errorData = data?.data; if (errorData == null) { return; } - final String errorText = (errorData['renderedErrorText'] as String?) - ?? (errorData['description'] as String?) - // We should never not error text, but if we do at least send something - // so it's not just completely silent. - ?? 'Unknown error in Flutter.Error event'; - sendOutput('stderr', '$errorText\n'); + FlutterErrorFormatter() + ..formatError(errorData) + ..sendOutput(sendOutput); } /// Called by [launchRequest] to request that we actually start the app to be run/debugged. diff --git a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart index 8e90a6e9b6147..5943a27d356e5 100644 --- a/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart +++ b/packages/flutter_tools/lib/src/debug_adapters/flutter_adapter_args.dart @@ -24,6 +24,7 @@ class FlutterAttachRequestArguments super.cwd, super.env, super.additionalProjectPaths, + super.allowAnsiColorOutput, super.debugSdkLibraries, super.debugExternalPackageLibraries, super.evaluateGettersInDebugViews, @@ -109,6 +110,7 @@ class FlutterLaunchRequestArguments super.cwd, super.env, super.additionalProjectPaths, + super.allowAnsiColorOutput, super.debugSdkLibraries, super.debugExternalPackageLibraries, super.evaluateGettersInDebugViews, diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart index a717a6dfdb72d..8de1a2bddf638 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/flutter_adapter_test.dart @@ -13,6 +13,7 @@ import 'package:flutter_tools/src/globals.dart' as globals; import '../../src/common.dart'; import '../test_data/basic_project.dart'; import '../test_data/compile_error_project.dart'; +import '../test_data/project.dart'; import '../test_utils.dart'; import 'test_client.dart'; import 'test_server.dart'; @@ -187,13 +188,18 @@ void main() { expect(output, contains('Exited (1)')); }); - /// Helper that tests exception output in either debug or noDebug mode. - Future testExceptionOutput({required bool noDebug}) async { - final BasicProjectThatThrows project = BasicProjectThatThrows(); + group('structured errors', () { + /// Helper that runs [project] and collects the output. + /// + /// Line and column numbers are replaced with "1" to avoid fragile tests. + Future getExceptionOutput( + Project project, { + required bool noDebug, + required bool ansiColors, + }) async { await project.setUpIn(tempDir); - final List outputEvents = - await dap.client.collectAllOutput(launch: () { + final List outputEvents = await dap.client.collectAllOutput(launch: () { // Terminate the app after we see the exception because otherwise // it will keep running and `collectAllOutput` won't end. dap.client.output @@ -203,23 +209,85 @@ void main() { noDebug: noDebug, cwd: project.dir.path, toolArgs: ['-d', 'flutter-tester'], + allowAnsiColorOutput: ansiColors, ); }); - final String output = _uniqueOutputLines(outputEvents); - final List outputLines = output.split('\n'); - expect( outputLines, containsAllInOrder([ - '══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════', - 'The following _Exception was thrown building App(dirty):', - 'Exception: c', - 'The relevant error-causing widget was:', - ])); - expect(output, contains('App:${Uri.file(project.dir.path)}/lib/main.dart:24:12')); - } + String output = _uniqueOutputLines(outputEvents); + + // Replace out any line/columns to make tests less fragile. + output = output.replaceAll(RegExp(r'\.dart:\d+:\d+'), '.dart:1:1'); + + return output; + } + + testWithoutContext('correctly outputs exceptions in debug mode', () async { + final BasicProjectThatThrows project = BasicProjectThatThrows(); + final String output = await getExceptionOutput(project, noDebug: false, ansiColors: false); - testWithoutContext('correctly outputs exceptions in debug mode', () => testExceptionOutput(noDebug: false)); + expect( + output, + contains(''' +════════ Exception caught by widgets library ═══════════════════════════════════ +The following _Exception was thrown building App(dirty): +Exception: c - testWithoutContext('correctly outputs exceptions in noDebug mode', () => testExceptionOutput(noDebug: true)); +The relevant error-causing widget was: + App App:${Uri.file(project.dir.path)}/lib/main.dart:1:1'''), + ); + }); + + testWithoutContext('correctly outputs colored exceptions when supported', () async { + final BasicProjectThatThrows project = BasicProjectThatThrows(); + final String output = await getExceptionOutput(project, noDebug: false, ansiColors: true); + + // Frames in the stack trace that are the users own code will be unformatted, but + // frames from the framework are faint (starting with `\x1B[2m`). + + expect( + output, + contains(''' +════════ Exception caught by widgets library ═══════════════════════════════════ +The following _Exception was thrown building App(dirty): +Exception: c + +The relevant error-causing widget was: + App App:${Uri.file(project.dir.path)}/lib/main.dart:1:1 + +When the exception was thrown, this was the stack: +#0 c (package:test/main.dart:1:1) + ^ source: package:test/main.dart +#1 App.build (package:test/main.dart:1:1) + ^ source: package:test/main.dart +\x1B[2m#2 StatelessElement.build (package:flutter/src/widgets/framework.dart:1:1)\x1B[0m + ^ source: package:flutter/src/widgets/framework.dart +\x1B[2m#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:1:1)\x1B[0m + ^ source: package:flutter/src/widgets/framework.dart'''), + ); + }); + + testWithoutContext('correctly outputs exceptions in noDebug mode', () async { + final BasicProjectThatThrows project = BasicProjectThatThrows(); + final String output = await getExceptionOutput(project, noDebug: true, ansiColors: false); + + // When running in noDebug mode, we don't get the Flutter.Error event so + // we get the basic Flutter-formatted version of the error. + expect( + output, + contains(''' +══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ +The following _Exception was thrown building App(dirty): +Exception: c + +The relevant error-causing widget was: + App'''), + ); + expect( + output, + contains('App:${Uri.file(project.dir.path)}/lib/main.dart:1:1'), + ); + }); + }); testWithoutContext('can hot reload', () async { final BasicProject project = BasicProject(); @@ -630,10 +698,19 @@ void main() { /// Extracts the output from a set of [OutputEventBody], removing any /// adjacent duplicates and combining into a single string. +/// +/// If the output event contains a [Source], the name will be shown on the +/// following line indented and prefixed with `^ source:`. String _uniqueOutputLines(List outputEvents) { String? lastItem; return outputEvents - .map((OutputEventBody e) => e.output) + .map((OutputEventBody e) { + final String output = e.output; + final Source? source = e.source; + return source != null + ? '$output ^ source: ${source.name}\n' + : output; + }) .where((String output) { // Skip the item if it's the same as the previous one. final bool isDupe = output == lastItem; diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart index 8857d4dd2dfb2..2e211f075ad34 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/test_client.dart @@ -155,6 +155,7 @@ class DapTestClient { String? cwd, bool? noDebug, List? additionalProjectPaths, + bool? allowAnsiColorOutput, bool? debugSdkLibraries, bool? debugExternalPackageLibraries, bool? evaluateGettersInDebugViews, @@ -169,6 +170,7 @@ class DapTestClient { args: args, toolArgs: toolArgs, additionalProjectPaths: additionalProjectPaths, + allowAnsiColorOutput: allowAnsiColorOutput, debugSdkLibraries: debugSdkLibraries, debugExternalPackageLibraries: debugExternalPackageLibraries, evaluateGettersInDebugViews: evaluateGettersInDebugViews, diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/test_support.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/test_support.dart index 35147c6dfc934..baa66bc630a33 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/test_support.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/test_support.dart @@ -31,7 +31,7 @@ final bool useInProcessDap = Platform.environment['DAP_TEST_INTERNAL'] == 'true' /// Service traffic (wrapped in a custom 'dart.log' event). final bool verboseLogging = Platform.environment['DAP_TEST_VERBOSE'] == 'true'; -const String endOfErrorOutputMarker = '════════════════════════════════════════════════════════════════════════════════════════════════════'; +const String endOfErrorOutputMarker = '════════════════════════════════════════════════════════════════════════════════'; /// Expects the lines in [actual] to match the relevant matcher in [expected], /// ignoring differences in line endings and trailing whitespace. From 28ee5581784eedc234d673fb80131bb16267c746 Mon Sep 17 00:00:00 2001 From: Pierre-Louis <6655696+guidezpl@users.noreply.github.com> Date: Mon, 31 Jul 2023 14:26:11 +0200 Subject: [PATCH 0457/1547] Fix dartdoc for `ButtonSegment` constructor (#131400) https://github.com/flutter/flutter/issues/103529 --- packages/flutter/lib/src/material/segmented_button.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/segmented_button.dart b/packages/flutter/lib/src/material/segmented_button.dart index 9e056b37d1f46..1e23716b90a7b 100644 --- a/packages/flutter/lib/src/material/segmented_button.dart +++ b/packages/flutter/lib/src/material/segmented_button.dart @@ -21,7 +21,7 @@ import 'tooltip.dart'; /// Data describing a segment of a [SegmentedButton]. class ButtonSegment { - /// Construct a SegmentData + /// Construct a [ButtonSegment]. /// /// One of [icon] or [label] must be non-null. const ButtonSegment({ From 0881d07e135d42b02ce331292f12e291800f8297 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 11:54:51 -0400 Subject: [PATCH 0458/1547] Roll Packages from 10aab445d985 to 60e9a542f94e (6 revisions) (#131607) https://github.com/flutter/packages/compare/10aab445d985...60e9a542f94e 2023-07-30 engine-flutter-autoroll@skia.org Manual roll Flutter from c2b40ca7013b to 1d44fbd8b906 (7 revisions) (flutter/packages#4592) 2023-07-29 engine-flutter-autoroll@skia.org Roll Flutter from e81907e07a38 to c2b40ca7013b (24 revisions) (flutter/packages#4588) 2023-07-28 stuartmorgan@google.com [ci] Switch FTL to LUCI (flutter/packages#4583) 2023-07-28 jhy03261997@gmail.com [go_router_builder] support v10.0.0 go_router (flutter/packages#4578) 2023-07-28 engine-flutter-autoroll@skia.org Roll Flutter from dd9764ec3447 to e81907e07a38 (21 revisions) (flutter/packages#4582) 2023-07-28 stuartmorgan@google.com [ci] Add LUCI version of Android FTL tests in bringup mode (flutter/packages#4571) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index d0635fa7d063e..6222baf83aa43 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -10aab445d98562ee22ab816283ea72f186ad677f +60e9a542f94e0c0389e264c6419fc604ea7911ab From 972d36c4efeee7e3bb16c050fd233389625a6470 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 13:03:04 -0400 Subject: [PATCH 0459/1547] Roll Flutter Engine from b11a832ea7d4 to ae6d1d60df95 (1 revision) (#131611) https://github.com/flutter/engine/compare/b11a832ea7d4...ae6d1d60df95 2023-07-31 skia-flutter-autoroll@skia.org Roll ANGLE from 143fa68f50b7 to fb37e0542c7c (1 revision) (flutter/engine#44161) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ee8c7c1b82edd..683cb71bdca37 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b11a832ea7d4b680131bf0435f543365928f7ffb +ae6d1d60df95556527d54aaad752d41d8ccbac4a From ae750e57f5e9062bd5f283c4087675d47d21e8ae Mon Sep 17 00:00:00 2001 From: gmackall <34871572+gmackall@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:10:24 -0700 Subject: [PATCH 0460/1547] Upgrade compile and target sdk versions in tests and benchmarks (#131428) Partially fixes/related to: https://github.com/flutter/flutter/issues/131425 --- dev/benchmarks/multiple_flutters/android/app/build.gradle | 4 ++-- .../android_custom_host_app/SampleApp/build.gradle | 2 +- .../android_host_app_v2_embedding/app/build.gradle | 2 +- .../deferred_components_test/android/component1/build.gradle | 4 ++-- .../app/build.gradle | 2 +- .../module/android/deferred_component/build.gradle.tmpl | 4 ++-- packages/flutter_tools/test/general.shard/project_test.dart | 4 ++-- .../test_data/deferred_components_config.dart | 4 ++-- .../test/integration.shard/test_data/multidex_project.dart | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dev/benchmarks/multiple_flutters/android/app/build.gradle b/dev/benchmarks/multiple_flutters/android/app/build.gradle index 8e2b72d7c70d9..1df6b8ce74052 100644 --- a/dev/benchmarks/multiple_flutters/android/app/build.gradle +++ b/dev/benchmarks/multiple_flutters/android/app/build.gradle @@ -14,7 +14,7 @@ android { } namespace "dev.flutter.multipleflutters" - compileSdkVersion 31 + compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -28,7 +28,7 @@ android { defaultConfig { applicationId "dev.flutter.multipleflutters" minSdkVersion 24 - targetSdkVersion 31 + targetSdkVersion 33 versionCode 1 versionName "1.0" diff --git a/dev/integration_tests/android_custom_host_app/SampleApp/build.gradle b/dev/integration_tests/android_custom_host_app/SampleApp/build.gradle index 9d8b6ebcd18ca..a05c46a0a3483 100644 --- a/dev/integration_tests/android_custom_host_app/SampleApp/build.gradle +++ b/dev/integration_tests/android_custom_host_app/SampleApp/build.gradle @@ -15,7 +15,7 @@ android { defaultConfig { applicationId "io.flutter.add2app" minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionCode 1 versionName "1.0" } diff --git a/dev/integration_tests/android_host_app_v2_embedding/app/build.gradle b/dev/integration_tests/android_host_app_v2_embedding/app/build.gradle index f653bc3792fca..c23b1b6db927c 100644 --- a/dev/integration_tests/android_host_app_v2_embedding/app/build.gradle +++ b/dev/integration_tests/android_host_app_v2_embedding/app/build.gradle @@ -15,7 +15,7 @@ android { defaultConfig { applicationId "io.flutter.add2app" minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionCode 1 versionName "1.0" } diff --git a/dev/integration_tests/deferred_components_test/android/component1/build.gradle b/dev/integration_tests/deferred_components_test/android/component1/build.gradle index 728ff955c1aa0..3cf18c577423a 100644 --- a/dev/integration_tests/deferred_components_test/android/component1/build.gradle +++ b/dev/integration_tests/deferred_components_test/android/component1/build.gradle @@ -24,7 +24,7 @@ apply plugin: "com.android.dynamic-feature" android { namespace "io.flutter.integration.deferred_components_test.component1" - compileSdkVersion 31 + compileSdkVersion 33 sourceSets { applicationVariants.all { variant -> @@ -35,7 +35,7 @@ android { defaultConfig { minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/dev/integration_tests/module_host_with_custom_build_v2_embedding/app/build.gradle b/dev/integration_tests/module_host_with_custom_build_v2_embedding/app/build.gradle index 4cf5470e824c6..2ca993f2d7cae 100644 --- a/dev/integration_tests/module_host_with_custom_build_v2_embedding/app/build.gradle +++ b/dev/integration_tests/module_host_with_custom_build_v2_embedding/app/build.gradle @@ -15,7 +15,7 @@ android { defaultConfig { applicationId "io.flutter.addtoapp" minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionCode 1 versionName "1.0" } diff --git a/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl b/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl index 502aa70449aaa..8a728d654336c 100644 --- a/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl +++ b/packages/flutter_tools/templates/module/android/deferred_component/build.gradle.tmpl @@ -34,8 +34,8 @@ android { } defaultConfig { - minSdkVersion 19 - targetSdkVersion 31 + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 85918adcc4d1b..e80ba79de56c9 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -1617,7 +1617,7 @@ String gradleFileWithApplicationId(String id) { return ''' apply plugin: 'com.android.application' android { - compileSdkVersion 31 + compileSdkVersion 33 defaultConfig { applicationId '$id' @@ -1634,7 +1634,7 @@ version '1.0-SNAPSHOT' apply plugin: 'com.android.library' android { - compileSdkVersion 31 + compileSdkVersion 33 } '''; } diff --git a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart index 859cc69e31a37..f3377e04078c7 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_config.dart @@ -77,7 +77,7 @@ class DeferredComponentModule { apply plugin: "com.android.dynamic-feature" android { - compileSdkVersion 31 + compileSdkVersion 33 sourceSets { applicationVariants.all { variant -> @@ -88,7 +88,7 @@ class DeferredComponentModule { defaultConfig { minSdkVersion 19 - targetSdkVersion 31 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart index 5773666b73e2d..ea958e983ce9e 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart @@ -144,7 +144,7 @@ class MultidexProject extends Project { apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 31 + compileSdkVersion 33 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -163,7 +163,7 @@ class MultidexProject extends Project { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.multidextest2" minSdkVersion 19 - targetSdkVersion 30 + targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } From 544c0408968615b302c34915da933bf8ea7bb829 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 14:14:21 -0400 Subject: [PATCH 0461/1547] Roll Flutter Engine from ae6d1d60df95 to b83172a4e995 (4 revisions) (#131614) https://github.com/flutter/engine/compare/ae6d1d60df95...b83172a4e995 2023-07-31 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from c0Pr9uG-46yC83ZVy... to Dd4To9QyMtoPGPIpl... (flutter/engine#44168) 2023-07-31 skia-flutter-autoroll@skia.org Roll ANGLE from fb37e0542c7c to 2755f73a3461 (1 revision) (flutter/engine#44167) 2023-07-31 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from SqCbKBft29XeD2Qvw... to wIpcCOc0TtDYasQbl... (flutter/engine#44166) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 6ee21fa70879 to cb61dd4af8a5 (1 revision) (flutter/engine#44165) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from SqCbKBft29Xe to wIpcCOc0TtDY fuchsia/sdk/core/mac-amd64 from c0Pr9uG-46yC to Dd4To9QyMtoP If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 683cb71bdca37..7ffa444c14f09 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ae6d1d60df95556527d54aaad752d41d8ccbac4a +b83172a4e995894b3203b43b32cd3742299771d7 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 681cec544cd96..83da38c771dab 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -SqCbKBft29XeD2QvwCTbO3aqeNoNPgJs7NXiVmR9kX8C +wIpcCOc0TtDYasQblklIoNg4iEgxO-hlO4aTGflWrmYC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index dc0d8ddca2e46..46f24a0248d2c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -c0Pr9uG-46yC83ZVyXxcwx3Gm7d-fPDraC6robzSXDUC +Dd4To9QyMtoPGPIplD3HfhZe21ZbHJB7tHW2KWe9elcC From e0b6b6c451d4e841458c05da876150385ed328fc Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:51:27 -0700 Subject: [PATCH 0462/1547] Reland - "Update Unit Tests for M2/M3" (#131504) Reverts flutter/flutter#131368 Original PR: https://github.com/flutter/flutter/pull/131292 . The flutter mirror was out of date and tree was closed, so the original PR was reverted. Now should be safe to have a reland. --- .../test/material/icon_button_test.dart | 2 +- .../test/material/ink_sparkle_test.dart | 65 +++++++++++++- .../flutter/test/material/material_test.dart | 87 ++++++++++++++++++- packages/flutter/test/material/page_test.dart | 47 +++++++++- .../material/progress_indicator_test.dart | 46 +++++++++- 5 files changed, 231 insertions(+), 16 deletions(-) diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index eea26984ef371..81ea567224a95 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -790,7 +790,7 @@ void main() { await tester.pumpWidget( wrap( - useMaterial3: false, + useMaterial3: theme.useMaterial3, child: Column( children: [ IconButton( diff --git a/packages/flutter/test/material/ink_sparkle_test.dart b/packages/flutter/test/material/ink_sparkle_test.dart index b0a44de48949f..1cd3c006896e5 100644 --- a/packages/flutter/test/material/ink_sparkle_test.dart +++ b/packages/flutter/test/material/ink_sparkle_test.dart @@ -93,23 +93,41 @@ void main() { // Goldens // ///////////// - testWidgetsWithLeakTracking('InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'top_left', 0.2); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgetsWithLeakTracking('InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when top left of button is tapped', (WidgetTester tester) async { + await _runM3Test(tester, 'top_left', 0.2); + }, + skip: kIsWeb, // [intended] shaders are not yet supported for web. + ); + + testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'center', 0.5); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); - testWidgetsWithLeakTracking('InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when center of button is tapped', (WidgetTester tester) async { + await _runM3Test(tester, 'center', 0.5); + }, + skip: kIsWeb, // [intended] shaders are not yet supported for web. + ); + + testWidgetsWithLeakTracking('Material2 - InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { await _runTest(tester, 'bottom_right', 0.8); }, skip: kIsWeb, // [intended] shaders are not yet supported for web. ); + + testWidgetsWithLeakTracking('Material3 - InkSparkle renders with sparkles when bottom right of button is tapped', (WidgetTester tester) async { + await _runM3Test(tester, 'bottom_right', 0.8); + }, + skip: kIsWeb, // [intended] shaders are not yet supported for web. + ); } Future _runTest(WidgetTester tester, String positionName, double distanceFromTopLeft) async { @@ -146,7 +164,46 @@ Future _runTest(WidgetTester tester, String positionName, double distanceF await tester.pump(const Duration(milliseconds: 50)); await expectLater( repaintFinder, - matchesGoldenFile('ink_sparkle.$positionName.$i.png'), + matchesGoldenFile('m2_ink_sparkle.$positionName.$i.png'), + ); + } +} + +Future _runM3Test(WidgetTester tester, String positionName, double distanceFromTopLeft) async { + final Key repaintKey = UniqueKey(); + final Key buttonKey = UniqueKey(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: Center( + child: RepaintBoundary( + key: repaintKey, + child: ElevatedButton( + key: buttonKey, + style: ElevatedButton.styleFrom(splashFactory: InkSparkle.constantTurbulenceSeedSplashFactory), + child: const Text('Sparkle!'), + onPressed: () { }, + ), + ), + ), + ), + )); + + final Finder buttonFinder = find.byKey(buttonKey); + final Finder repaintFinder = find.byKey(repaintKey); + final Offset topLeft = tester.getTopLeft(buttonFinder); + final Offset bottomRight = tester.getBottomRight(buttonFinder); + + await _warmUpShader(tester, buttonFinder); + + final Offset target = topLeft + (bottomRight - topLeft) * distanceFromTopLeft; + await tester.tapAt(target); + for (int i = 0; i <= 5; i++) { + await tester.pump(const Duration(milliseconds: 50)); + await expectLater( + repaintFinder, + matchesGoldenFile('m3_ink_sparkle.$positionName.$i.png'), ); } } diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index 2832acb09e8cd..33bc9c85b246a 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -921,7 +921,7 @@ void main() { expect(box, isNot(paints..circle())); }); - testWidgetsWithLeakTracking('border is painted above child by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - border is painted above child by default', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -956,11 +956,50 @@ void main() { await expectLater( find.byKey(painterKey), - matchesGoldenFile('material.border_paint_above.png'), + matchesGoldenFile('m2_material.border_paint_above.png'), ); }); - testWidgetsWithLeakTracking('border is painted below child when specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - border is painted above child by default', (WidgetTester tester) async { + final Key painterKey = UniqueKey(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: RepaintBoundary( + key: painterKey, + child: Card( + child: SizedBox( + width: 200, + height: 300, + child: Material( + clipBehavior: Clip.hardEdge, + shape: const RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 6), + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + child: Column( + children: [ + Container( + color: Colors.green, + height: 150, + ), + ], + ), + ), + ), + ), + ), + ), + )); + + await expectLater( + find.byKey(painterKey), + matchesGoldenFile('m3_material.border_paint_above.png'), + ); + }); + + testWidgetsWithLeakTracking('Material2 - border is painted below child when specified', (WidgetTester tester) async { final Key painterKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -996,7 +1035,47 @@ void main() { await expectLater( find.byKey(painterKey), - matchesGoldenFile('material.border_paint_below.png'), + matchesGoldenFile('m2_material.border_paint_below.png'), + ); + }); + + testWidgetsWithLeakTracking('Material3 - border is painted below child when specified', (WidgetTester tester) async { + final Key painterKey = UniqueKey(); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: RepaintBoundary( + key: painterKey, + child: Card( + child: SizedBox( + width: 200, + height: 300, + child: Material( + clipBehavior: Clip.hardEdge, + shape: const RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 6), + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + borderOnForeground: false, + child: Column( + children: [ + Container( + color: Colors.green, + height: 150, + ), + ], + ), + ), + ), + ), + ), + ), + )); + + await expectLater( + find.byKey(painterKey), + matchesGoldenFile('m3_material.border_paint_below.png'), ); }); }); diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index b0486a9cfac82..a09d980067bf9 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -240,7 +240,7 @@ void main() { expect(find.text('Page 2'), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + testWidgets('Material2 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1000, 1000); tester.view.viewInsets = FakeViewPadding.zero; @@ -270,7 +270,7 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); - await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.small.png')); + await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.small.png')); // Change the view insets. tester.view.viewInsets = const FakeViewPadding(bottom: 500); @@ -278,7 +278,48 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 50)); - await expectLater(find.byKey(key), matchesGoldenFile('zoom_page_transition.big.png')); + await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.big.png')); + }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. + + testWidgets('Material3 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + addTearDown(tester.view.reset); + tester.view.physicalSize = const Size(1000, 1000); + tester.view.viewInsets = FakeViewPadding.zero; + + // Intentionally use nested scaffolds to simulate the view insets being + // consumed. + final Key key = GlobalKey(); + await tester.pumpWidget( + RepaintBoundary( + key: key, + child: MaterialApp( + theme: ThemeData(useMaterial3: true), + onGenerateRoute: (RouteSettings settings) { + return MaterialPageRoute( + builder: (BuildContext context) { + return const Scaffold(body: Scaffold( + body: Material(child: SizedBox.shrink()) + )); + }, + ); + }, + ), + ), + ); + + tester.state(find.byType(Navigator)).pushNamed('/next'); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.small.png')); + + // Change the view insets. + tester.view.viewInsets = const FakeViewPadding(bottom: 500); + + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.big.png')); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. testWidgets( diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 875ab00e30d3e..886539bc361bb 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -720,7 +720,7 @@ void main() { expect(tester.hasRunningAnimations, isTrue); }); - testWidgets('RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgets('Material2 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); await tester.pumpFrames(animationSheet.record( @@ -732,7 +732,23 @@ void main() { await expectLater( await animationSheet.collate(20), - matchesGoldenFile('material.refresh_progress_indicator.png'), + matchesGoldenFile('m2_material.refresh_progress_indicator.png'), + ); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + + testWidgets('Material3 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); + + await tester.pumpFrames(animationSheet.record( + Theme( + data: ThemeData(useMaterial3: true), + child: const _RefreshProgressIndicatorGolden() + ), + ), const Duration(seconds: 3)); + + await expectLater( + await animationSheet.collate(20), + matchesGoldenFile('m3_material.refresh_progress_indicator.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 @@ -1001,7 +1017,7 @@ void main() { handle.dispose(); }); - testWidgets('Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgets('Material2 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); await tester.pumpFrames(animationSheet.record( @@ -1019,7 +1035,29 @@ void main() { await expectLater( await animationSheet.collate(20), - matchesGoldenFile('material.circular_progress_indicator.indeterminate.png'), + matchesGoldenFile('m2_material.circular_progress_indicator.indeterminate.png'), + ); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + + testWidgets('Material3 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); + + await tester.pumpFrames(animationSheet.record( + Theme( + data: ThemeData(useMaterial3: true), + child: const Directionality( + textDirection: TextDirection.ltr, + child: Padding( + padding: EdgeInsets.all(4), + child: CircularProgressIndicator(), + ), + ), + ), + ), const Duration(seconds: 2)); + + await expectLater( + await animationSheet.collate(20), + matchesGoldenFile('m3_material.circular_progress_indicator.indeterminate.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 From 71d96ddf9ce2a015eab49ccf73faae926c64e0bf Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Mon, 31 Jul 2023 12:09:27 -0700 Subject: [PATCH 0463/1547] Add Expanded/Collapsed State for Semantics (#131233) --- .../flutter/lib/src/material/menu_anchor.dart | 32 +++-- .../lib/src/rendering/custom_paint.dart | 3 + .../flutter/lib/src/rendering/proxy_box.dart | 3 + .../flutter/lib/src/semantics/semantics.dart | 24 ++++ packages/flutter/lib/src/widgets/basic.dart | 2 + .../test/material/menu_anchor_test.dart | 128 +++++++++++++++++- .../test/widgets/custom_painter_test.dart | 4 +- .../flutter/test/widgets/semantics_test.dart | 4 +- packages/flutter_test/lib/src/matchers.dart | 12 ++ packages/flutter_test/test/matchers_test.dart | 6 + 10 files changed, 201 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index f10d133ae1de3..dd293e43405d2 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -1079,7 +1079,7 @@ class _MenuItemButtonState extends State { ); } - return child; + return MergeSemantics(child: child); } void _handleFocusChange() { @@ -1904,19 +1904,23 @@ class _SubmenuButtonState extends State { controller._anchor!._focusButton(); } } - - child = TextButton( - style: mergedStyle, - focusNode: _buttonFocusNode, - onHover: _enabled ? (bool hovering) => handleHover(hovering, context) : null, - onPressed: _enabled ? () => toggleShowMenu(context) : null, - isSemanticButton: null, - child: _MenuItemLabel( - leadingIcon: widget.leadingIcon, - trailingIcon: widget.trailingIcon, - hasSubmenu: true, - showDecoration: (controller._anchor!._parent?._orientation ?? Axis.horizontal) == Axis.vertical, - child: child ?? const SizedBox(), + child = MergeSemantics( + child: Semantics( + expanded: controller.isOpen, + child: TextButton( + style: mergedStyle, + focusNode: _buttonFocusNode, + onHover: _enabled ? (bool hovering) => handleHover(hovering, context) : null, + onPressed: _enabled ? () => toggleShowMenu(context) : null, + isSemanticButton: null, + child: _MenuItemLabel( + leadingIcon: widget.leadingIcon, + trailingIcon: widget.trailingIcon, + hasSubmenu: true, + showDecoration: (controller._anchor!._parent?._orientation ?? Axis.horizontal) == Axis.vertical, + child: child ?? const SizedBox(), + ), + ), ), ); diff --git a/packages/flutter/lib/src/rendering/custom_paint.dart b/packages/flutter/lib/src/rendering/custom_paint.dart index cb2142315ce1d..320640a9fad86 100644 --- a/packages/flutter/lib/src/rendering/custom_paint.dart +++ b/packages/flutter/lib/src/rendering/custom_paint.dart @@ -900,6 +900,9 @@ class RenderCustomPaint extends RenderProxyBox { if (properties.button != null) { config.isButton = properties.button!; } + if (properties.expanded != null) { + config.isExpanded = properties.expanded; + } if (properties.link != null) { config.isLink = properties.link!; } diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 1026d40d2de84..5e6f2e740f580 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -4319,6 +4319,9 @@ class RenderSemanticsAnnotations extends RenderProxyBox { if (_properties.button != null) { config.isButton = _properties.button!; } + if (_properties.expanded != null) { + config.isExpanded = _properties.expanded; + } if (_properties.link != null) { config.isLink = _properties.link!; } diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index 53d03c274bcb6..21e14f3d18892 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -870,6 +870,7 @@ class SemanticsProperties extends DiagnosticableTree { this.enabled, this.checked, this.mixed, + this.expanded, this.selected, this.toggled, this.button, @@ -964,6 +965,14 @@ class SemanticsProperties extends DiagnosticableTree { /// This is mutually exclusive with [checked] and [toggled]. final bool? mixed; + /// If non-null, indicates that this subtree represents something + /// that can be in an "expanded" or "collapsed" state. + /// + /// For example, if a [SubmenuButton] is opened, this property + /// should be set to true; otherwise, this property should be + /// false. + final bool? expanded; + /// If non-null, indicates that this subtree represents a toggle switch /// or similar widget with an "on" state, and what its current /// state is. @@ -1612,6 +1621,7 @@ class SemanticsProperties extends DiagnosticableTree { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('checked', checked, defaultValue: null)); properties.add(DiagnosticsProperty('mixed', mixed, defaultValue: null)); + properties.add(DiagnosticsProperty('expanded', expanded, defaultValue: null)); properties.add(DiagnosticsProperty('selected', selected, defaultValue: null)); properties.add(StringProperty('label', label, defaultValue: null)); properties.add(AttributedStringProperty('attributedLabel', attributedLabel, defaultValue: null)); @@ -4398,6 +4408,20 @@ class SemanticsConfiguration { _setFlag(SemanticsFlag.isSelected, value); } + /// If this node has Boolean state that can be controlled by the user, whether + /// that state is expanded or collapsed, corresponding to true and false, respectively. + /// + /// Do not call the setter for this field if the owning [RenderObject] doesn't + /// have expanded/collapsed state that can be controlled by the user. + /// + /// The getter returns null if the owning [RenderObject] does not have + /// expanded/collapsed state. + bool? get isExpanded => _hasFlag(SemanticsFlag.hasExpandedState) ? _hasFlag(SemanticsFlag.isExpanded) : null; + set isExpanded(bool? value) { + _setFlag(SemanticsFlag.hasExpandedState, true); + _setFlag(SemanticsFlag.isExpanded, value!); + } + /// Whether the owning [RenderObject] is currently enabled. /// /// A disabled object does not respond to user interactions. Only objects that diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index bc45977e0412f..bd69cf4ea251e 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -7138,6 +7138,7 @@ class Semantics extends SingleChildRenderObjectWidget { bool? hidden, bool? image, bool? liveRegion, + bool? expanded, int? maxValueLength, int? currentValueLength, String? label, @@ -7186,6 +7187,7 @@ class Semantics extends SingleChildRenderObjectWidget { enabled: enabled, checked: checked, mixed: mixed, + expanded: expanded, toggled: toggled, selected: selected, button: button, diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index f29f01126644b..220e7922405c8 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -3181,7 +3181,8 @@ void main() { children: [ TestSemantics( rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), - flags: [SemanticsFlag.hasEnabledState], + flags: [SemanticsFlag.hasEnabledState, + SemanticsFlag.hasExpandedState], label: 'ABC', textDirection: TextDirection.ltr, ), @@ -3194,6 +3195,131 @@ void main() { semantics.dispose(); }); + + testWidgets('SubmenuButton expanded/collapsed state', (WidgetTester tester) async { + final SemanticsTester semantics = SemanticsTester(tester); + await tester.pumpWidget( + MaterialApp( + home: Center( + child: SubmenuButton( + onHover: (bool value) {}, + style: SubmenuButton.styleFrom(fixedSize: const Size(88.0, 36.0)), + menuChildren: [ + MenuItemButton( + child: const Text('Item 0'), + onPressed: () {}, + ), + ], + child: const Text('ABC'), + ), + ), + ), + ); + + // Test expanded state. + await tester.tap(find.text('ABC')); + await tester.pumpAndSettle(); + expect( + semantics, + hasSemantics( + TestSemantics.root( + children: [ + TestSemantics( + id: 1, + rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0), + children: [ + TestSemantics( + id: 2, + rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0), + children: [ + TestSemantics( + id: 3, + rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0), + flags: [SemanticsFlag.scopesRoute], + children: [ + TestSemantics( + id: 4, + flags: [SemanticsFlag.hasExpandedState, SemanticsFlag.isExpanded, SemanticsFlag.isFocused, SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled, + SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + label: 'ABC', + rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), + ) + ] + ) + ] + ), + TestSemantics( + id: 6, + rect: const Rect.fromLTRB(0.0, 0.0, 123.0, 64.0), + children: [ + TestSemantics( + id: 7, + rect: const Rect.fromLTRB(0.0, 0.0, 123.0, 48.0), + flags: [SemanticsFlag.hasImplicitScrolling], + children: [ + TestSemantics( + id: 8, + label: 'Item 0', + rect: const Rect.fromLTRB(0.0, 0.0, 123.0, 48.0), + flags: [SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled, SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + ), + ], + ), + ], + ), + ], + ), + ], + ), + ignoreTransform: true, + ), + ); + + // Test collapsed state. + await tester.tap(find.text('ABC')); + await tester.pumpAndSettle(); + expect( + semantics, + hasSemantics( + TestSemantics.root( + children: [ + TestSemantics( + id: 1, + rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0), + children: [ + TestSemantics( + id: 2, + rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0), + children: [ + TestSemantics( + id: 3, + rect: const Rect.fromLTRB(0.0, 0.0, 800.0, 600.0), + flags: [SemanticsFlag.scopesRoute], + children: [ + TestSemantics( + id: 4, + flags: [SemanticsFlag.hasExpandedState, SemanticsFlag.isFocused, SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled, + SemanticsFlag.isFocusable], + actions: [SemanticsAction.tap], + label: 'ABC', + rect: const Rect.fromLTRB(0.0, 0.0, 88.0, 48.0), + ) + ] + ) + ] + ), + ], + ), + ], + ), + ignoreTransform: true, + ), + ); + + semantics.dispose(); + }); }); } diff --git a/packages/flutter/test/widgets/custom_painter_test.dart b/packages/flutter/test/widgets/custom_painter_test.dart index bb991a88e0e0c..e9320e21df167 100644 --- a/packages/flutter/test/widgets/custom_painter_test.dart +++ b/packages/flutter/test/widgets/custom_painter_test.dart @@ -440,6 +440,7 @@ void _defineTests() { image: true, liveRegion: true, toggled: true, + expanded: true, ), ), ), @@ -494,6 +495,7 @@ void _defineTests() { namesRoute: true, image: true, liveRegion: true, + expanded: true, ), ), ), @@ -520,7 +522,7 @@ void _defineTests() { ); expect(semantics, hasSemantics(expectedSemantics, ignoreRect: true, ignoreTransform: true)); semantics.dispose(); - }, skip: true); // https://github.com/flutter/flutter/issues/127617 + }); group('diffing', () { testWidgets('complains about duplicate keys', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart index bfe86488b2542..8a95217212fcd 100644 --- a/packages/flutter/test/widgets/semantics_test.dart +++ b/packages/flutter/test/widgets/semantics_test.dart @@ -609,6 +609,7 @@ void main() { namesRoute: true, image: true, liveRegion: true, + expanded: true, ), ); final List flags = SemanticsFlag.values.toList(); @@ -691,6 +692,7 @@ void main() { namesRoute: true, image: true, liveRegion: true, + expanded: true, ), ); flags @@ -706,7 +708,7 @@ void main() { ], ); expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); - }, skip: true); // https://github.com/flutter/flutter/issues/127617 + }); testWidgets('Actions can be replaced without triggering semantics update', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index 3cc1bb6ce2e99..7da2de31aa4f7 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -564,6 +564,8 @@ Matcher matchesSemantics({ bool hasToggledState = false, bool isToggled = false, bool hasImplicitScrolling = false, + bool hasExpandedState = false, + bool isExpanded = false, // Actions // bool hasTapAction = false, bool hasLongPressAction = false, @@ -640,6 +642,8 @@ Matcher matchesSemantics({ hasToggledState: hasToggledState, isToggled: isToggled, hasImplicitScrolling: hasImplicitScrolling, + hasExpandedState: hasExpandedState, + isExpanded: isExpanded, // Actions hasTapAction: hasTapAction, hasLongPressAction: hasLongPressAction, @@ -737,6 +741,8 @@ Matcher containsSemantics({ bool? hasToggledState, bool? isToggled, bool? hasImplicitScrolling, + bool? hasExpandedState, + bool? isExpanded, // Actions bool? hasTapAction, bool? hasLongPressAction, @@ -813,6 +819,8 @@ Matcher containsSemantics({ hasToggledState: hasToggledState, isToggled: isToggled, hasImplicitScrolling: hasImplicitScrolling, + hasExpandedState: hasExpandedState, + isExpanded: isExpanded, // Actions hasTapAction: hasTapAction, hasLongPressAction: hasLongPressAction, @@ -2111,6 +2119,8 @@ class _MatchesSemanticsData extends Matcher { required bool? hasToggledState, required bool? isToggled, required bool? hasImplicitScrolling, + required bool? hasExpandedState, + required bool? isExpanded, // Actions required bool? hasTapAction, required bool? hasLongPressAction, @@ -2166,6 +2176,8 @@ class _MatchesSemanticsData extends Matcher { if (isToggled != null) SemanticsFlag.isToggled: isToggled, if (hasImplicitScrolling != null) SemanticsFlag.hasImplicitScrolling: hasImplicitScrolling, if (isSlider != null) SemanticsFlag.isSlider: isSlider, + if (hasExpandedState != null) SemanticsFlag.hasExpandedState: hasExpandedState, + if (isExpanded != null) SemanticsFlag.isExpanded: isExpanded, }, actions = { if (hasTapAction != null) SemanticsAction.tap: hasTapAction, diff --git a/packages/flutter_test/test/matchers_test.dart b/packages/flutter_test/test/matchers_test.dart index b4be731f6e203..87d5fffa40ab7 100644 --- a/packages/flutter_test/test/matchers_test.dart +++ b/packages/flutter_test/test/matchers_test.dart @@ -683,6 +683,8 @@ void main() { hasToggledState: true, isToggled: true, hasImplicitScrolling: true, + hasExpandedState: true, + isExpanded: true, /* Actions */ hasTapAction: true, hasLongPressAction: true, @@ -966,6 +968,8 @@ void main() { hasToggledState: true, isToggled: true, hasImplicitScrolling: true, + hasExpandedState: true, + isExpanded: true, /* Actions */ hasTapAction: true, hasLongPressAction: true, @@ -1055,6 +1059,8 @@ void main() { hasToggledState: false, isToggled: false, hasImplicitScrolling: false, + hasExpandedState: false, + isExpanded: false, /* Actions */ hasTapAction: false, hasLongPressAction: false, From d5ebf5395014302084bdf794f9cb19c4f14fc1f7 Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Mon, 31 Jul 2023 12:57:20 -0700 Subject: [PATCH 0464/1547] Update the cirrus key jul-31-2023 (#131624) Updating the cirrus key. *List which issues are fixed by this PR. You must list at least one issue.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .cirrus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cirrus.yml b/.cirrus.yml index cdcba477e7631..1a699600e49ad 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -12,7 +12,7 @@ environment: # dependency on precisely how Cirrus is detected by our tools. BOT: "true" -gcp_credentials: ENCRYPTED[!9c8e92e8da192ce2a51b7d4ed9948c4250d0bae3660193d9b901196c9692abbebe784d4a32e9f38b328571d65f6e7aed!] +gcp_credentials: ENCRYPTED[!9409b709ab4de7293a70606cca13eaf42e9cbc704e8a6b4e3d2b09484cf997cbd2334e1eeafe23626ad07a726106df90!] # LINUX SHARDS task: From b928b3c1c312d5565f4789d25756b62f90e997c5 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Mon, 31 Jul 2023 13:17:34 -0700 Subject: [PATCH 0465/1547] Reland --omit-type-checks for benchmarks. (#131493) Because the cost of type checks dominate our dart2wasm benchmarks, we've decided to pass `--omit-type-checks` for now. This was previously reverted because the skwasm benchmarks were broken in general for a separate reason, and my getting rid of `bringup: true` broke the tree. I ended up fixing the benchmarks and getting rid of `bringup: true` in a separate commit, so this just adds the flag only. --- dev/devicelab/lib/tasks/web_benchmarks.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/devicelab/lib/tasks/web_benchmarks.dart b/dev/devicelab/lib/tasks/web_benchmarks.dart index 051133c70db7b..a4748b8f9f85e 100644 --- a/dev/devicelab/lib/tasks/web_benchmarks.dart +++ b/dev/devicelab/lib/tasks/web_benchmarks.dart @@ -36,6 +36,7 @@ Future runWebBenchmark(WebBenchmarkOptions benchmarkOptions) async { if (benchmarkOptions.useWasm) ...[ '--wasm', '--wasm-opt=debug', + '--omit-type-checks', ], '--dart-define=FLUTTER_WEB_ENABLE_PROFILING=true', '--web-renderer=${benchmarkOptions.webRenderer}', From 3cf206ba2cfec7d4d29438b9baa7bfb0acf0f722 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:24:48 -0700 Subject: [PATCH 0466/1547] Update `CheckboxListTile` and `CalendarDatePicker` tests for M2/M3 (#131363) --- .../material/calendar_date_picker_test.dart | 99 ++++++++++- .../material/checkbox_list_tile_test.dart | 162 +++++++++++++++++- 2 files changed, 254 insertions(+), 7 deletions(-) diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index a678bb401837b..c4d356a04ae02 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -26,9 +26,10 @@ void main() { DatePickerMode initialCalendarMode = DatePickerMode.day, SelectableDayPredicate? selectableDayPredicate, TextDirection textDirection = TextDirection.ltr, + bool? useMaterial3, }) { return MaterialApp( - theme: ThemeData(useMaterial3: false), + theme: ThemeData(useMaterial3: useMaterial3), home: Material( child: Directionality( textDirection: textDirection, @@ -347,8 +348,9 @@ void main() { expect(find.text('January 2018'), findsOneWidget); }); - testWidgets('currentDate is highlighted', (WidgetTester tester) async { + testWidgets('Material2 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( + useMaterial3: false, currentDate: DateTime(2016, 1, 2), )); const Color todayColor = Color(0xff2196f3); // default primary color @@ -363,8 +365,26 @@ void main() { ); }); - testWidgets('currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + testWidgets('Material3 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( + useMaterial3: true, + currentDate: DateTime(2016, 1, 2), + )); + const Color todayColor = Color(0xff6750a4); // default primary color + expect( + Material.of(tester.element(find.text('2'))), + // The current day should be painted with a circle outline. + paints..circle( + color: todayColor, + style: PaintingStyle.stroke, + strokeWidth: 1.0, + ), + ); + }); + + testWidgets('Material2 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + await tester.pumpWidget(calendarDatePicker( + useMaterial3: false, firstDate: DateTime(2016, 1, 3), lastDate: DateTime(2016, 1, 31), currentDate: DateTime(2016, 1, 2), // not between first and last @@ -383,6 +403,27 @@ void main() { ); }); + testWidgets('Material3 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + await tester.pumpWidget(calendarDatePicker( + useMaterial3: true, + firstDate: DateTime(2016, 1, 3), + lastDate: DateTime(2016, 1, 31), + currentDate: DateTime(2016, 1, 2), // not between first and last + initialDate: DateTime(2016, 1, 5), + )); + const Color disabledColor = Color(0x616750a4); // default disabled color + expect( + Material.of(tester.element(find.text('2'))), + // The current day should be painted with a circle outline. + paints + ..circle( + color: disabledColor, + style: PaintingStyle.stroke, + strokeWidth: 1.0, + ), + ); + }); + testWidgets('Selecting date does not switch picker to year selection', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2020, DateTime.may, 10), @@ -397,7 +438,7 @@ void main() { expect(find.text('2017'), findsNothing); }); - testWidgets('Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { + testWidgets('Material2 - Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { final Key pickerKey = UniqueKey(); final DateTime initialDate = DateTime(2020, 1, 21); final DateTime updatedDate = DateTime(1976, 2, 23); @@ -407,6 +448,55 @@ void main() { await tester.pumpWidget(calendarDatePicker( key: pickerKey, + useMaterial3: false, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + onDateChanged: (DateTime value) {}, + )); + await tester.pumpAndSettle(); + + // Month should show as January 2020 + expect(find.text('January 2020'), findsOneWidget); + // Selected date should be painted with a colored circle. + expect( + Material.of(tester.element(find.text('21'))), + paints..circle(color: selectedColor, style: PaintingStyle.fill), + ); + + // Change to the updated initialDate + await tester.pumpWidget(calendarDatePicker( + key: pickerKey, + useMaterial3: false, + initialDate: updatedDate, + firstDate: firstDate, + lastDate: lastDate, + onDateChanged: (DateTime value) {}, + )); + // Wait for the page scroll animation to finish. + await tester.pumpAndSettle(const Duration(milliseconds: 200)); + + // Month should show as February 1976 + expect(find.text('January 2020'), findsNothing); + expect(find.text('February 1976'), findsOneWidget); + // Selected date should be painted with a colored circle. + expect( + Material.of(tester.element(find.text('23'))), + paints..circle(color: selectedColor, style: PaintingStyle.fill), + ); + }); + + testWidgets('Material3 - Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { + final Key pickerKey = UniqueKey(); + final DateTime initialDate = DateTime(2020, 1, 21); + final DateTime updatedDate = DateTime(1976, 2, 23); + final DateTime firstDate = DateTime(1970); + final DateTime lastDate = DateTime(2099, 31, 12); + const Color selectedColor = Color(0xff6750a4); // default primary color + + await tester.pumpWidget(calendarDatePicker( + key: pickerKey, + useMaterial3: true, initialDate: initialDate, firstDate: firstDate, lastDate: lastDate, @@ -425,6 +515,7 @@ void main() { // Change to the updated initialDate await tester.pumpWidget(calendarDatePicker( key: pickerKey, + useMaterial3: true, initialDate: updatedDate, firstDate: firstDate, lastDate: lastDate, diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 24f9cfb554d23..3ae0bf9ffa24e 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -38,7 +39,7 @@ void main() { expect(log, equals([false, '-', false])); }); - testWidgetsWithLeakTracking('CheckboxListTile checkColor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - CheckboxListTile checkColor test', (WidgetTester tester) async { const Color checkBoxBorderColor = Color(0xff2196f3); Color checkBoxCheckColor = const Color(0xffFFFFFF); @@ -70,6 +71,38 @@ void main() { expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); }); + testWidgetsWithLeakTracking('Material3 - CheckboxListTile checkColor test', (WidgetTester tester) async { + const Color checkBoxBorderColor = Color(0xff6750a4); + Color checkBoxCheckColor = const Color(0xffFFFFFF); + + Widget buildFrame(Color? color) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: CheckboxListTile( + value: true, + checkColor: color, + onChanged: (bool? value) {}, + ), + ), + ); + } + + RenderBox getCheckboxListTileRenderer() { + return tester.renderObject(find.byType(CheckboxListTile)); + } + + await tester.pumpWidget(buildFrame(null)); + await tester.pumpAndSettle(); + expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); + + checkBoxCheckColor = const Color(0xFF000000); + + await tester.pumpWidget(buildFrame(checkBoxCheckColor)); + await tester.pumpAndSettle(); + expect(getCheckboxListTileRenderer(), paints..path(color: checkBoxBorderColor)..path(color: checkBoxCheckColor)); + }); + testWidgetsWithLeakTracking('CheckboxListTile activeColor test', (WidgetTester tester) async { Widget buildFrame(Color? themeColor, Color? activeColor) { return wrap( @@ -710,7 +743,7 @@ void main() { ); }); - testWidgets('CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgets('Material2 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -826,6 +859,129 @@ void main() { ); }); + testWidgets('Material3 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + + const Color fillColor = Color(0xFF000000); + const Color activePressedOverlayColor = Color(0xFF000001); + const Color inactivePressedOverlayColor = Color(0xFF000002); + const Color hoverOverlayColor = Color(0xFF000003); + const Color hoverColor = Color(0xFF000005); + + Color? getOverlayColor(Set states) { + if (states.contains(MaterialState.pressed)) { + if (states.contains(MaterialState.selected)) { + return activePressedOverlayColor; + } + return inactivePressedOverlayColor; + } + if (states.contains(MaterialState.hovered)) { + return hoverOverlayColor; + } + return null; + } + const double splashRadius = 24.0; + + Widget buildCheckbox({bool active = false, bool useOverlay = true}) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: CheckboxListTile( + value: active, + onChanged: (_) { }, + fillColor: const MaterialStatePropertyAll(fillColor), + overlayColor: useOverlay ? MaterialStateProperty.resolveWith(getOverlayColor) : null, + hoverColor: hoverColor, + splashRadius: splashRadius, + ), + ), + ); + } + + await tester.pumpWidget(buildCheckbox(useOverlay: false)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )) : (paints..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )), + reason: 'Default inactive pressed Checkbox should have overlay color from fillColor', + ); + + await tester.pumpWidget(buildCheckbox(active: true, useOverlay: false)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )) : (paints..circle( + color: fillColor.withAlpha(kRadialReactionAlpha), + radius: splashRadius, + )), + reason: 'Default active pressed Checkbox should have overlay color from fillColor', + ); + + await tester.pumpWidget(buildCheckbox()); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: inactivePressedOverlayColor, + radius: splashRadius, + )) : (paints..circle( + color: inactivePressedOverlayColor, + radius: splashRadius, + )), + reason: 'Inactive pressed Checkbox should have overlay color: $inactivePressedOverlayColor', + ); + + await tester.pumpWidget(buildCheckbox(active: true)); + await tester.startGesture(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + kIsWeb ? (paints..circle()..circle( + color: activePressedOverlayColor, + radius: splashRadius, + )) : (paints..circle( + color: activePressedOverlayColor, + radius: splashRadius, + )), + reason: 'Active pressed Checkbox should have overlay color: $activePressedOverlayColor', + ); + + // Start hovering + await tester.pumpWidget(Container()); + await tester.pumpWidget(buildCheckbox()); + await tester.pumpAndSettle(); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(Checkbox))); + await tester.pumpAndSettle(); + + expect( + Material.of(tester.element(find.byType(Checkbox))), + paints..circle( + color: hoverOverlayColor, + radius: splashRadius, + ), + reason: 'Hovered Checkbox should use overlay color $hoverOverlayColor over $hoverColor', + ); + }); + testWidgetsWithLeakTracking('CheckboxListTile respects splashRadius', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; @@ -881,7 +1037,7 @@ void main() { expect(tester.getSize(find.byType(Checkbox)), const Size(48.0, 48.0)); }); - testWidgetsWithLeakTracking('CheckboxListTile respects isError - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - CheckboxListTile respects isError', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; From efc9e16ea35d106adf81a45326a5c0541c6d9b32 Mon Sep 17 00:00:00 2001 From: Jay Mehta <31812582+thisisjaymehta@users.noreply.github.com> Date: Tue, 1 Aug 2023 02:12:09 +0530 Subject: [PATCH 0467/1547] Fixed regex to show missing assets file error (#131160) Added Regex to match error message from verbos build as suggested by @stuartmorgan [here](https://github.com/flutter/flutter/pull/98137#discussion_r810559589). Modified Windows Build Test Fixes #97065 --- .../lib/src/windows/build_windows.dart | 11 +++++- .../hermetic/build_windows_test.dart | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index 7ffb4a69d7b64..c63b1dc3bc601 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -190,7 +190,16 @@ Future _runBuild( // MSBuild sends all output to stdout, including build errors. This surfaces // known error patterns. - final RegExp errorMatcher = RegExp(r':\s*(?:warning|(?:fatal )?error).*?:'); + final RegExp errorMatcher = RegExp( + [ + // Known error messages + r'(:\s*(?:warning|(?:fatal )?error).*?:)', + r'Error detected in pubspec\.yaml:', + + // Known secondary error lines for pubspec.yaml + r'No file or variants found for asset:', + ].join('|'), + ); int result; try { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index 921b14ecfa30f..4dbed14f96ced 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -962,6 +962,41 @@ if %errorlevel% neq 0 goto :VCEnd ProcessManager: () => FakeProcessManager.any(), FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), }); + + // Tests the case where stdout contains the error about pubspec.yaml + // And tests the case where stdout contains the error about missing assets + testUsingContext('Windows build extracts errors related to pubspec.yaml from stdout', () async { + final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + ..visualStudioOverride = fakeVisualStudio; + setUpMockProjectFilesForBuild(); + + const String stdout = r''' +Error detected in pubspec.yaml: +No file or variants found for asset: images/a_dot_burr.jpeg. +'''; + + processManager = FakeProcessManager.list([ + cmakeGenerationCommand(), + buildCommand('Release', + stdout: stdout, + ), + ]); + + await createTestCommandRunner(command).run( + const ['windows', '--no-pub'] + ); + // Just the warnings and errors should be surfaced. + expect(testLogger.errorText, r''' +Error detected in pubspec.yaml: +No file or variants found for asset: images/a_dot_burr.jpeg. +'''); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + Platform: () => windowsPlatform, + FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), + }); } class FakeVisualStudio extends Fake implements VisualStudio { From 1d59196bafdb682b6403edf14ebef0e86a453cdd Mon Sep 17 00:00:00 2001 From: Sumit Bikram Maity Date: Tue, 1 Aug 2023 02:12:11 +0530 Subject: [PATCH 0468/1547] Appended period remove & Uri parsing fix. (#131293) Fixed code for the Uri as it includes the period at the end as the part of Uri parsing previously. As for example: ``` A crash report has been written to /Users/andrewkolos/Desktop/asset_transformers_test/flutter_03.log. ``` Many terminals are unable to follow the link because it includes the period in the end as part of it. This PR simply removes the period in the end so that it is clickable in many systems (e.g. by `alt` -clicking on it in an embedded bash terminal, VSCode). ``` A crash report has been written to /Users/andrewkolos/Desktop/asset_transformers_test/flutter_03.log ``` Fixes: #131166 --- packages/flutter_tools/lib/src/reporting/crash_reporting.dart | 2 +- .../flutter_tools/test/general.shard/crash_reporting_test.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/lib/src/reporting/crash_reporting.dart b/packages/flutter_tools/lib/src/reporting/crash_reporting.dart index a8fd8da753ac7..df68535ae59f7 100644 --- a/packages/flutter_tools/lib/src/reporting/crash_reporting.dart +++ b/packages/flutter_tools/lib/src/reporting/crash_reporting.dart @@ -69,7 +69,7 @@ class CrashReporter { /// Prints instructions for filing a bug about the crash. Future informUser(CrashDetails details, File crashFile) async { - _logger.printError('A crash report has been written to ${crashFile.path}.'); + _logger.printError('A crash report has been written to ${crashFile.path}'); _logger.printStatus('This crash may already be reported. Check GitHub for similar crashes.', emphasis: true); final String similarIssuesURL = GitHubTemplateCreator.toolCrashSimilarIssuesURL(details.error.toString()); diff --git a/packages/flutter_tools/test/general.shard/crash_reporting_test.dart b/packages/flutter_tools/test/general.shard/crash_reporting_test.dart index 5bb3fa36759ba..be8e2394375d2 100644 --- a/packages/flutter_tools/test/general.shard/crash_reporting_test.dart +++ b/packages/flutter_tools/test/general.shard/crash_reporting_test.dart @@ -100,7 +100,7 @@ void main() { expect(logger.statusText, contains('NoPIIFakeDoctorText')); expect(logger.statusText, isNot(contains('Ignored'))); expect(logger.statusText, contains('https://github.com/flutter/flutter/issues/new')); - expect(logger.errorText, contains('A crash report has been written to ${file.path}.')); + expect(logger.errorText.trim(), 'A crash report has been written to ${file.path}'); }); testWithoutContext('suppress analytics', () async { From 40a9d3f1db9a4c34a6f67e70637e4d4cef73c58c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 19:54:41 -0400 Subject: [PATCH 0469/1547] Roll Flutter Engine from b83172a4e995 to fe2369565f59 (12 revisions) (#131638) https://github.com/flutter/engine/compare/b83172a4e995...fe2369565f59 2023-07-31 skia-flutter-autoroll@skia.org Roll ANGLE from faca95f7e81b to 196713767078 (7 revisions) (flutter/engine#44191) 2023-07-31 ian@hixie.ch Mention the point of BlendMode.plus and advise on using it. (flutter/engine#44189) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from db813f4043fe to 2e5f08012a92 (1 revision) (flutter/engine#44187) 2023-07-31 chinmaygarde@google.com [Impeller] Update guidance on how to try Impeller on macOS Desktop. (flutter/engine#44186) 2023-07-31 chinmaygarde@google.com [Impeller] Add a descriptive blurb about newer Impeller components and fix links. (flutter/engine#44183) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 06174bc8f4d5 to db813f4043fe (1 revision) (flutter/engine#44182) 2023-07-31 jason-simmons@users.noreply.github.com [Impeller] Create a wrapper Impeller context for each Vulkan surface and its swapchain (flutter/engine#44171) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from ea0c9c0935ae to 06174bc8f4d5 (2 revisions) (flutter/engine#44179) 2023-07-31 skia-flutter-autoroll@skia.org Roll ANGLE from 2755f73a3461 to faca95f7e81b (1 revision) (flutter/engine#44178) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 9c12eb0e158a to ea0c9c0935ae (4 revisions) (flutter/engine#44177) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from 685e29df6704 to 9c12eb0e158a (2 revisions) (flutter/engine#44173) 2023-07-31 skia-flutter-autoroll@skia.org Roll Skia from cb61dd4af8a5 to 685e29df6704 (2 revisions) (flutter/engine#44170) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7ffa444c14f09..ab7e940f03874 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b83172a4e995894b3203b43b32cd3742299771d7 +fe2369565f591c4020c0991facd10876e322ad12 From d250fa62a1f6e6528c3a014693937a276a9fd91b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 21:01:05 -0400 Subject: [PATCH 0470/1547] Roll Flutter Engine from fe2369565f59 to bb2a903c934c (3 revisions) (#131639) https://github.com/flutter/engine/compare/fe2369565f59...bb2a903c934c 2023-07-31 skia-flutter-autoroll@skia.org Roll ANGLE from 196713767078 to cb4b1f3641ae (1 revision) (flutter/engine#44193) 2023-07-31 a-siva@users.noreply.github.com Manual roll of Dart with fixups to zircon system.dart (flutter/engine#44185) 2023-07-31 chinmaygarde@google.com [Impeller] Update guidance on how to run with Metal validation without Xcode. (flutter/engine#44190) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ab7e940f03874..5dd1e4b3c61de 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fe2369565f591c4020c0991facd10876e322ad12 +bb2a903c934cc800c9d4c6649e3acf863fee5436 From f2db93df014739c42c1525a04e5a33803c0bbe84 Mon Sep 17 00:00:00 2001 From: Alex Li Date: Tue, 1 Aug 2023 09:27:54 +0800 Subject: [PATCH 0471/1547] =?UTF-8?q?=F0=9F=90=9B=20Treat=20empty=20ARB=20?= =?UTF-8?q?content=20as=20empty=20map=20when=20decoding=20(#131242)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #128932. --- .../lib/src/localizations/gen_l10n_types.dart | 43 ++++++++++++------- .../hermetic/generate_localizations_test.dart | 30 +++++++++++++ 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart index 0ea3050e6152c..d17988dd1e39b 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart @@ -566,13 +566,18 @@ class Message { } } -// Represents the contents of one ARB file. +/// Represents the contents of one ARB file. class AppResourceBundle { + /// Assuming that the caller has verified that the file exists and is readable. factory AppResourceBundle(File file) { - // Assuming that the caller has verified that the file exists and is readable. - Map resources; + final Map resources; try { - resources = json.decode(file.readAsStringSync()) as Map; + final String content = file.readAsStringSync().trim(); + if (content.isEmpty) { + resources = {}; + } else { + resources = json.decode(content) as Map; + } } on FormatException catch (e) { throw L10nException( 'The arb file ${file.path} has the following formatting issue: \n' @@ -657,20 +662,26 @@ class AppResourceBundleCollection { final RegExp filenameRE = RegExp(r'(\w+)\.arb$'); final Map localeToBundle = {}; final Map> languageToLocales = >{}; - final List files = directory.listSync().whereType().toList()..sort(sortFilesByPath); + // We require the list of files to be sorted so that + // "languageToLocales[bundle.locale.languageCode]" is not null + // by the time we handle locales with country codes. + final List files = directory + .listSync() + .whereType() + .where((File e) => filenameRE.hasMatch(e.path)) + .toList() + ..sort(sortFilesByPath); for (final File file in files) { - if (filenameRE.hasMatch(file.path)) { - final AppResourceBundle bundle = AppResourceBundle(file); - if (localeToBundle[bundle.locale] != null) { - throw L10nException( - "Multiple arb files with the same '${bundle.locale}' locale detected. \n" - 'Ensure that there is exactly one arb file for each locale.' - ); - } - localeToBundle[bundle.locale] = bundle; - languageToLocales[bundle.locale.languageCode] ??= []; - languageToLocales[bundle.locale.languageCode]!.add(bundle.locale); + final AppResourceBundle bundle = AppResourceBundle(file); + if (localeToBundle[bundle.locale] != null) { + throw L10nException( + "Multiple arb files with the same '${bundle.locale}' locale detected. \n" + 'Ensure that there is exactly one arb file for each locale.' + ); } + localeToBundle[bundle.locale] = bundle; + languageToLocales[bundle.locale.languageCode] ??= []; + languageToLocales[bundle.locale.languageCode]!.add(bundle.locale); } languageToLocales.forEach((String language, List listOfCorrespondingLocales) { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart index e2556a6e58c73..263254ddc8bdd 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart @@ -10,6 +10,7 @@ import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/targets/localizations.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/generate_localizations.dart'; +import 'package:flutter_tools/src/localizations/gen_l10n_types.dart'; import '../../integration.shard/test_data/basic_project.dart'; import '../../src/common.dart'; @@ -501,4 +502,33 @@ format: true throwsToolExit(message: 'Unexpected positional argument "false".') ); }); + + group(AppResourceBundle, () { + testWithoutContext("can be parsed without FormatException when it's content is empty", () { + final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')) + ..createSync(recursive: true); + expect(AppResourceBundle(arbFile), isA()); + }); + + testUsingContext("would not fail the gen-l10n command when it's content is empty", () async { + fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')).createSync(recursive: true); + final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync(); + pubspecFile.writeAsStringSync(BasicProjectWithFlutterGen().pubspec); + final GenerateLocalizationsCommand command = GenerateLocalizationsCommand( + fileSystem: fileSystem, + logger: logger, + artifacts: artifacts, + processManager: processManager, + ); + await createTestCommandRunner(command).run(['gen-l10n']); + + final Directory outputDirectory = fileSystem.directory(fileSystem.path.join('.dart_tool', 'flutter_gen', 'gen_l10n')); + expect(outputDirectory.existsSync(), true); + expect(outputDirectory.childFile('app_localizations_en.dart').existsSync(), true); + expect(outputDirectory.childFile('app_localizations.dart').existsSync(), true); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + }); } From c851efaa3af8d619fbfd1753fb9288b1fabbb312 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 31 Jul 2023 22:40:26 -0400 Subject: [PATCH 0472/1547] Roll Flutter Engine from bb2a903c934c to 791f505c8c6e (4 revisions) (#131645) https://github.com/flutter/engine/compare/bb2a903c934c...791f505c8c6e 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from 2e5f08012a92 to 177897b13a89 (1 revision) (flutter/engine#44199) 2023-08-01 skia-flutter-autoroll@skia.org Roll ANGLE from cb4b1f3641ae to 6dc0c9d62755 (2 revisions) (flutter/engine#44198) 2023-08-01 chinmaygarde@google.com [Impeller] Document the fiddly bits about setting up Metal shader source debugging. (flutter/engine#44195) 2023-07-31 chinmaygarde@google.com [Impeller] Add documentation on how to enable Metal Profiling HUD without Xcode. (flutter/engine#44196) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5dd1e4b3c61de..776c3d026b636 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bb2a903c934cc800c9d4c6649e3acf863fee5436 +791f505c8c6e7d9a53671606f1bbd906c8ddf7f0 From 5d028a2851ab4bea4816ce797eb4c88eb0641921 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 00:43:51 -0400 Subject: [PATCH 0473/1547] Roll Flutter Engine from 791f505c8c6e to 1433e23c8a3d (1 revision) (#131647) https://github.com/flutter/engine/compare/791f505c8c6e...1433e23c8a3d 2023-08-01 matanlurey@users.noreply.github.com [Impeller] Implement, non user-facing, dithering for LinearGradients. (flutter/engine#44181) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 776c3d026b636..491f8a7d1eb70 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -791f505c8c6e7d9a53671606f1bbd906c8ddf7f0 +1433e23c8a3de80561f7ac143de40ebb948054ed From 8bd985f139cbee1f89fd23759e3d7fcffd55a6a4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 01:49:06 -0400 Subject: [PATCH 0474/1547] Roll Flutter Engine from 1433e23c8a3d to 7651b3cba6ba (2 revisions) (#131648) https://github.com/flutter/engine/compare/1433e23c8a3d...7651b3cba6ba 2023-08-01 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 0e02245635ea to a58ca112af1c (1 revision) (flutter/engine#44197) 2023-08-01 dworsham@google.com [fuchsia] Only use upstream vulkan headers (flutter/engine#44157) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 491f8a7d1eb70..2a49d716d53aa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1433e23c8a3de80561f7ac143de40ebb948054ed +7651b3cba6bacd2e60e7338ba9f22b04dd976a00 From fcd5a6c4788718e124af5c9775678d2276184990 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 06:06:40 -0400 Subject: [PATCH 0475/1547] Roll Flutter Engine from 7651b3cba6ba to 25b9d1088d09 (4 revisions) (#131655) https://github.com/flutter/engine/compare/7651b3cba6ba...25b9d1088d09 2023-08-01 skia-flutter-autoroll@skia.org Roll ANGLE from 6dc0c9d62755 to b53d99d87e6a (1 revision) (flutter/engine#44211) 2023-08-01 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Dd4To9QyMtoPGPIpl... to g0dgOL2IlZQJCK4El... (flutter/engine#44210) 2023-08-01 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from wIpcCOc0TtDYasQbl... to lwCo6le6r0X-Srvx3... (flutter/engine#44208) 2023-08-01 skia-flutter-autoroll@skia.org Manual roll Dart SDK from a58ca112af1c to aca45d2e133c (2 revisions) (flutter/engine#44203) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from wIpcCOc0TtDY to lwCo6le6r0X- fuchsia/sdk/core/mac-amd64 from Dd4To9QyMtoP to g0dgOL2IlZQJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2a49d716d53aa..8e4a9797b27c9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7651b3cba6bacd2e60e7338ba9f22b04dd976a00 +25b9d1088d09d937416c514aa40a58038f18eb23 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 83da38c771dab..356f0535291d1 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -wIpcCOc0TtDYasQblklIoNg4iEgxO-hlO4aTGflWrmYC +lwCo6le6r0X-Srvx31N-hp4SodcF_-U6Q5J9SpLc9zoC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 46f24a0248d2c..d485d5338e2ab 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Dd4To9QyMtoPGPIplD3HfhZe21ZbHJB7tHW2KWe9elcC +g0dgOL2IlZQJCK4ElZLeLCjBZgNGtbUXHXCRguBgBREC From 3ec088c129da65a43a94fa4e4bdc9e9198ebecfe Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 07:56:24 -0400 Subject: [PATCH 0476/1547] Roll Flutter Engine from 25b9d1088d09 to 2583c07f6a69 (1 revision) (#131661) https://github.com/flutter/engine/compare/25b9d1088d09...2583c07f6a69 2023-08-01 skia-flutter-autoroll@skia.org Roll ICU from e8c3bc9ea97d to de4ce0071eb4 (3 revisions) (flutter/engine#44212) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8e4a9797b27c9..e3439ef9ab73e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -25b9d1088d09d937416c514aa40a58038f18eb23 +2583c07f6a69d57fae660cee05fe3411d9aa5626 From de5b9670ddddeb72bead390dd1078880e86f5dd7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 09:18:27 -0400 Subject: [PATCH 0477/1547] Roll Flutter Engine from 2583c07f6a69 to f1c80ce98499 (1 revision) (#131663) https://github.com/flutter/engine/compare/2583c07f6a69...f1c80ce98499 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from 177897b13a89 to c74c10128334 (4 revisions) (flutter/engine#44213) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e3439ef9ab73e..93fbe8ea65f95 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2583c07f6a69d57fae660cee05fe3411d9aa5626 +f1c80ce98499bb354aad6e65b3f8eec107f35b35 From bd64bf5f923fa79635f2971531d9dfd717046963 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 10:43:06 -0400 Subject: [PATCH 0478/1547] Roll Flutter Engine from f1c80ce98499 to 703d45539059 (1 revision) (#131668) https://github.com/flutter/engine/compare/f1c80ce98499...703d45539059 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from c74c10128334 to bddb07184f88 (1 revision) (flutter/engine#44214) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 93fbe8ea65f95..90185a85e9287 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f1c80ce98499bb354aad6e65b3f8eec107f35b35 +703d455390594cc90fb3e3a29a26a5b74fdd8d3f From 5d2c9d0933b9946d2eff8477edaceb9c91f61998 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 12:31:10 -0400 Subject: [PATCH 0479/1547] Roll Flutter Engine from 703d45539059 to ae535c024146 (4 revisions) (#131679) https://github.com/flutter/engine/compare/703d45539059...ae535c024146 2023-08-01 skia-flutter-autoroll@skia.org Roll Dart SDK from 45405dd4ea87 to 197fc0d7fea2 (1 revision) (flutter/engine#44217) 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from 45290179e017 to a7a3646c2c8a (1 revision) (flutter/engine#44216) 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from bddb07184f88 to 45290179e017 (1 revision) (flutter/engine#44215) 2023-08-01 skia-flutter-autoroll@skia.org Manual roll Dart SDK from aca45d2e133c to 45405dd4ea87 (2 revisions) (flutter/engine#44204) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 90185a85e9287..347769678f155 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -703d455390594cc90fb3e3a29a26a5b74fdd8d3f +ae535c02414681ca93a1409a0a57b765292ccafd From b9c3f1f74c075a1766fd74418b5d79f528cf8c74 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 13:42:41 -0400 Subject: [PATCH 0480/1547] Roll Flutter Engine from ae535c024146 to e3f817ce9953 (1 revision) (#131687) https://github.com/flutter/engine/compare/ae535c024146...e3f817ce9953 2023-08-01 30870216+gaaclarke@users.noreply.github.com [Impeller] moved to one staging buffer pool (flutter/engine#44172) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 347769678f155..c80b5ef24859f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ae535c02414681ca93a1409a0a57b765292ccafd +e3f817ce9953046e20b15c4516301b599dbfd4bc From c57169835a4e8596b9debbb07867ffc0dd983cd4 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Tue, 1 Aug 2023 11:38:40 -0700 Subject: [PATCH 0481/1547] Avoid concurrent modification of persistent frame callbacks (#131677) Fixes https://github.com/flutter/flutter/issues/131415 We should do an audit of all such cases though, filed https://github.com/flutter/flutter/issues/131678 --- packages/flutter/lib/src/scheduler/binding.dart | 2 +- .../flutter/test/scheduler/binding_test.dart | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 0ff4b85c7f790..73b0971eb9622 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -1227,7 +1227,7 @@ mixin SchedulerBinding on BindingBase { try { // PERSISTENT FRAME CALLBACKS _schedulerPhase = SchedulerPhase.persistentCallbacks; - for (final FrameCallback callback in _persistentCallbacks) { + for (final FrameCallback callback in List.of(_persistentCallbacks)) { _invokeFrameCallback(callback, _currentFrameTimeStamp!); } diff --git a/packages/flutter/test/scheduler/binding_test.dart b/packages/flutter/test/scheduler/binding_test.dart index 233e12c94af03..5079db9266fed 100644 --- a/packages/flutter/test/scheduler/binding_test.dart +++ b/packages/flutter/test/scheduler/binding_test.dart @@ -28,4 +28,21 @@ void main() { ); timeDilation = 1.0; }); + + test('Adding a persistent frame callback during a persistent frame callback', () { + bool calledBack = false; + SchedulerBinding.instance.addPersistentFrameCallback((Duration timeStamp) { + if (!calledBack) { + SchedulerBinding.instance.addPersistentFrameCallback((Duration timeStamp) { + calledBack = true; + }); + } + }); + SchedulerBinding.instance.handleBeginFrame(null); + SchedulerBinding.instance.handleDrawFrame(); + expect(calledBack, false); + SchedulerBinding.instance.handleBeginFrame(null); + SchedulerBinding.instance.handleDrawFrame(); + expect(calledBack, true); + }); } From abb1e4c76c158efc654fc09054d31952743cdcf4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 14:38:42 -0400 Subject: [PATCH 0482/1547] Roll Packages from 60e9a542f94e to 3dc00c1a32f6 (5 revisions) (#131692) https://github.com/flutter/packages/compare/60e9a542f94e...3dc00c1a32f6 2023-08-01 engine-flutter-autoroll@skia.org Manual roll Flutter from 1d44fbd8b906 to 1d59196bafdb (18 revisions) (flutter/packages#4621) 2023-07-31 32242716+ricardoamador@users.noreply.github.com Update the cirrus key jul-31-2023 (flutter/packages#4618) 2023-07-31 jpnurmi@gmail.com [path_provider_platform_interface] Add getApplicationCachePath() (flutter/packages#4614) 2023-07-31 elitree@gmail.com [google_maps_flutter_web] Initial support for custom overlays (flutter/packages#3538) 2023-07-31 34410554+maciejbrzezinski@users.noreply.github.com [camera] Removed the microphone permission request from availableCameras on Web (flutter/packages#4263) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 6222baf83aa43..1ccb7c53b9f35 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -60e9a542f94e0c0389e264c6419fc604ea7911ab +3dc00c1a32f6659206f4e038ce989bb49bdfb36f From de004293d83c4c7f9087b6382e4cb59c5d98b3f7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 14:38:43 -0400 Subject: [PATCH 0483/1547] Roll Flutter Engine from e3f817ce9953 to 1aadc75dd5a7 (2 revisions) (#131691) https://github.com/flutter/engine/compare/e3f817ce9953...1aadc75dd5a7 2023-08-01 zanderso@users.noreply.github.com Manual clang roll to ebd0b8a0472b865b7eb6e1a32af97ae31d829033 (flutter/engine#44220) 2023-08-01 30870216+gaaclarke@users.noreply.github.com [Impeller] Made the clear optimization handle backdrop filters. (flutter/engine#44192) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c80b5ef24859f..c0edf15a4d0a9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e3f817ce9953046e20b15c4516301b599dbfd4bc +1aadc75dd5a70778fbd949631de9468189091fe6 From 5c424aa87fab58181a6cd8e4d85ea795ffd40fc2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 15:31:50 -0400 Subject: [PATCH 0484/1547] Roll Flutter Engine from 1aadc75dd5a7 to 10a1f9cb74c9 (1 revision) (#131696) https://github.com/flutter/engine/compare/1aadc75dd5a7...10a1f9cb74c9 2023-08-01 30870216+gaaclarke@users.noreply.github.com [Impeller] Started using a pool for HostBuffers. (flutter/engine#44081) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c0edf15a4d0a9..86629ecf2b26b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1aadc75dd5a70778fbd949631de9468189091fe6 +10a1f9cb74c938f313517675b4aad48956414e95 From 35213ceabd4d3f33e1d71dc8d4ce79f08b83c0f7 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 1 Aug 2023 12:59:47 -0700 Subject: [PATCH 0485/1547] Upgrade Flutter libraries. (#131700) --- dev/automated_tests/pubspec.yaml | 6 +++--- dev/benchmarks/complex_layout/pubspec.yaml | 6 +++--- dev/benchmarks/macrobenchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/microbenchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 4 ++-- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/platform_views_layout/pubspec.yaml | 6 +++--- .../platform_views_layout_hybrid_composition/pubspec.yaml | 6 +++--- dev/benchmarks/test_apps/stocks/pubspec.yaml | 6 +++--- dev/bots/pubspec.yaml | 6 +++--- dev/conductor/core/pubspec.yaml | 6 +++--- dev/customer_testing/pubspec.yaml | 6 +++--- dev/devicelab/pubspec.yaml | 6 +++--- .../android_semantics_testing/pubspec.yaml | 6 +++--- dev/integration_tests/android_views/pubspec.yaml | 8 ++++---- .../deferred_components_test/pubspec.yaml | 6 +++--- dev/integration_tests/external_ui/pubspec.yaml | 6 +++--- dev/integration_tests/flavors/pubspec.yaml | 6 +++--- dev/integration_tests/flutter_gallery/pubspec.yaml | 6 +++--- .../gradle_deprecated_settings/pubspec.yaml | 6 +++--- dev/integration_tests/hybrid_android_views/pubspec.yaml | 8 ++++---- .../ios_platform_view_tests/pubspec.yaml | 6 +++--- dev/integration_tests/platform_interaction/pubspec.yaml | 6 +++--- dev/integration_tests/ui/pubspec.yaml | 6 +++--- dev/integration_tests/web_e2e_tests/pubspec.yaml | 6 +++--- dev/integration_tests/windows_startup_test/pubspec.yaml | 6 +++--- dev/tools/gen_defaults/pubspec.yaml | 6 +++--- dev/tools/gen_keycodes/pubspec.yaml | 6 +++--- dev/tools/pubspec.yaml | 6 +++--- examples/api/pubspec.yaml | 6 +++--- examples/hello_world/pubspec.yaml | 6 +++--- examples/platform_channel/pubspec.yaml | 6 +++--- examples/platform_channel_swift/pubspec.yaml | 6 +++--- examples/texture/pubspec.yaml | 6 +++--- packages/flutter/pubspec.yaml | 6 +++--- packages/flutter_driver/pubspec.yaml | 6 +++--- packages/flutter_tools/pubspec.yaml | 6 +++--- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 6 +++--- packages/integration_test/example/pubspec.yaml | 6 +++--- 39 files changed, 118 insertions(+), 118 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index c0a62d1a08618..2d57886812a7c 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: integration_test: sdk: flutter platform: 3.1.0 - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,7 +58,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 28e0 +# PUBSPEC CHECKSUM: c6e2 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index acdb8de51b4bb..4ec0f8016d327 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 integration_test: sdk: flutter @@ -71,7 +71,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 87b9 +# PUBSPEC CHECKSUM: 66bb diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index d6397655afc67..1260f8897ed6d 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -43,7 +43,7 @@ dependencies: webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 integration_test: sdk: flutter @@ -72,7 +72,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -211,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 87b9 +# PUBSPEC CHECKSUM: 66bb diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 679cae2d6423d..714e4de81f9c6 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter stocks: path: ../test_apps/stocks - test: 1.24.4 + test: 1.24.5 flutter_gallery_assets: 1.0.2 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,7 +59,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -138,4 +138,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 1b31 +# PUBSPEC CHECKSUM: b933 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index fa9ecc2c357e6..4d9589f0bf97c 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: path_provider_android: 2.0.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 2d76 +# PUBSPEC CHECKSUM: b371 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index a2198d8130049..a19c761161024 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -58,9 +58,9 @@ dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9e1c +# PUBSPEC CHECKSUM: 3d1e diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index aa43706aa29c7..926509b892b17 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,7 +69,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 87b9 +# PUBSPEC CHECKSUM: 66bb diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 6653e07385db1..b97911a615388 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,7 +69,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 87b9 +# PUBSPEC CHECKSUM: 66bb diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 139500290bded..a1ef29dc6899b 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -32,7 +32,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,7 +66,7 @@ dev_dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0ddb +# PUBSPEC CHECKSUM: ebdd diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index c7a9622885446..892a662a87645 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: path: 1.8.3 platform: 3.1.0 process: 4.2.4 - test: 1.24.4 + test: 1.24.5 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,7 +61,7 @@ dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 8f84 +# PUBSPEC CHECKSUM: e586 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index b04b3142dc95a..6b37f619e19ea 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 test_api: 0.6.1 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,11 +59,11 @@ dev_dependencies: source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d2bc +# PUBSPEC CHECKSUM: ecbe diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 3546fe3719c65..f880aafd5d2ba 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,7 +48,7 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +56,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 780a +# PUBSPEC CHECKSUM: 920c diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index bffd8cfd6db6e..e9a76d4aa94ea 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -47,7 +47,7 @@ dependencies: yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,8 +67,8 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 53f1 +# PUBSPEC CHECKSUM: a9f3 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index b538a5edefcb8..9f97cd0a1f195 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter_test: sdk: flutter pub_semver: 2.1.4 - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,7 +54,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3fd9 +# PUBSPEC CHECKSUM: dddb diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 60370cd921c34..9379533135c0d 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,7 +54,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,7 +83,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 85b8 +# PUBSPEC CHECKSUM: b4b5 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 4cb76b4fea79d..92dc493fb4638 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,7 +64,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index a9f29aba76240..c3aa62c27c642 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +52,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6962 +# PUBSPEC CHECKSUM: 4864 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 3e25708121fa8..0736526f6a77b 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,7 +54,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index e2b86e36d6da0..6be149b91ac3c 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -58,7 +58,7 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter - test: 1.24.4 + test: 1.24.5 integration_test: sdk: flutter @@ -98,7 +98,7 @@ dev_dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: cf05 +# PUBSPEC CHECKSUM: 4307 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 8279a95bdb4d9..bc2faa5edf60e 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_web: 0.3.1+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_web: 0.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.3+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1704 +# PUBSPEC CHECKSUM: f4a6 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 848b4297d76eb..7dc77788d5e14 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: path_provider_android: 2.0.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +52,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,7 +81,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 85b8 +# PUBSPEC CHECKSUM: b4b5 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 42d268423eae2..93e6ac1f48ec3 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,7 +64,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,4 +78,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 27b9924f85250..a1f60fe0547c2 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +52,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6962 +# PUBSPEC CHECKSUM: 4864 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index f96ec2d90fb4c..f1b26da6b4c23 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,7 +53,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 6e3a9eb3d9096..ae064d5555006 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -49,7 +49,7 @@ dev_dependencies: flutter_goldens: sdk: flutter http: 0.13.6 - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,11 +78,11 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c904 +# PUBSPEC CHECKSUM: a806 diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index d09a8b5e7c705..c170a101effe6 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +52,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +63,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6962 +# PUBSPEC CHECKSUM: 4864 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 46bead99921a3..f87f7a27f8867 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: dev_dependencies: path: 1.8.3 - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,7 +48,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +56,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 780a +# PUBSPEC CHECKSUM: 920c diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index b0bcbc29c7898..973f4f0199812 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 test_api: 0.6.1 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,11 +51,11 @@ dev_dependencies: source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5a01 +# PUBSPEC CHECKSUM: 7403 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 9a4f7364a949a..1f546e55143f3 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 test_api: 0.6.1 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,11 +55,11 @@ dev_dependencies: source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f01b +# PUBSPEC CHECKSUM: 0b1d diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index a8298fa79802d..029da2df16af1 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -31,7 +31,7 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,7 +74,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +86,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: dbcd +# PUBSPEC CHECKSUM: bacf diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 0e25b3d6ada52..8b383ba160e9d 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +60,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,4 +69,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index cd672421266a3..c1959a8b8a7be 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +60,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 984b2fcc0ab17..4a9b133989c3f 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -19,7 +19,7 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +60,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 641f +# PUBSPEC CHECKSUM: 4321 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 43d51a03f4f72..cbd036192225d 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,7 +57,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3fd9 +# PUBSPEC CHECKSUM: dddb diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index c519ebe33767c..c1f59c37b81da 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -64,9 +64,9 @@ dev_dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a7f1 +# PUBSPEC CHECKSUM: 46f3 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 18eb711548570..1b22bf112dea0 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: dev_dependencies: fake_async: 1.3.1 - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,11 +66,11 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0f26 +# PUBSPEC CHECKSUM: ed28 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 2203d0fbd4eb5..b34f743767ba3 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. test_api: 0.6.1 - test_core: 0.5.4 + test_core: 0.5.5 vm_service: 11.8.0 @@ -101,10 +101,10 @@ dev_dependencies: checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 8733 +# PUBSPEC CHECKSUM: 3335 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 35a1e6dac60e9..79f1eb0f3d747 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.4 + test: 1.24.5 _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,7 +53,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +64,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 2e11 +# PUBSPEC CHECKSUM: 4813 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 26bf165799f1c..15c7145917035 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -28,7 +28,7 @@ dev_dependencies: sdk: flutter integration_test_macos: path: ../integration_test_macos - test: 1.24.4 + test: 1.24.5 pedantic: 1.11.1 # For information on the generic Dart part of this file, see the @@ -73,7 +73,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 898d +# PUBSPEC CHECKSUM: 688f From f5f36ec05d924e246b96fc36da281ed7b0dc26d8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 1 Aug 2023 20:31:51 -0400 Subject: [PATCH 0486/1547] Roll Flutter Engine from 10a1f9cb74c9 to 9dae7b708bda (4 revisions) (#131706) https://github.com/flutter/engine/compare/10a1f9cb74c9...9dae7b708bda 2023-08-01 30870216+gaaclarke@users.noreply.github.com Made the licenses script output all problems (flutter/engine#44223) 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from a7a3646c2c8a to d53f7b880651 (6 revisions) (flutter/engine#44226) 2023-08-01 skia-flutter-autoroll@skia.org Roll Clang from ebd0b8a0472b to 07c592048780 (flutter/engine#44224) 2023-08-01 ychris@google.com [iOS] Add darwin_extension_safe flag and use UIScene api when building for extensions (flutter/engine#43449) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 86629ecf2b26b..333ffeb265989 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -10a1f9cb74c938f313517675b4aad48956414e95 +9dae7b708bdabf57d8ce4025f308707ff080401f From 9c471a9499e09a411aa63e3a42d221048e0ff1ee Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 1 Aug 2023 17:38:06 -0700 Subject: [PATCH 0487/1547] ImageProvider.toString uses double.toStringAsFixed (#131348) This provides consistency for web vs VM (and is more consistent with how we do doubles everywhere else in toStrings). --- packages/flutter/lib/src/painting/_network_image_io.dart | 2 +- packages/flutter/lib/src/painting/_network_image_web.dart | 3 +-- packages/flutter/lib/src/painting/image_provider.dart | 6 +++--- packages/flutter/test/painting/image_provider_test.dart | 6 ++++++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/painting/_network_image_io.dart b/packages/flutter/lib/src/painting/_network_image_io.dart index 8105227deda09..05dd8cb722291 100644 --- a/packages/flutter/lib/src/painting/_network_image_io.dart +++ b/packages/flutter/lib/src/painting/_network_image_io.dart @@ -185,5 +185,5 @@ class NetworkImage extends image_provider.ImageProvider Object.hash(url, scale); @override - String toString() => '${objectRuntimeType(this, 'NetworkImage')}("$url", scale: $scale)'; + String toString() => '${objectRuntimeType(this, 'NetworkImage')}("$url", scale: ${scale.toStringAsFixed(1)})'; } diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index ceb012e65a80b..95e97e0c2853f 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -215,6 +215,5 @@ class NetworkImage int get hashCode => Object.hash(url, scale); @override - String toString() => - '${objectRuntimeType(this, 'NetworkImage')}("$url", scale: $scale)'; + String toString() => '${objectRuntimeType(this, 'NetworkImage')}("$url", scale: ${scale.toStringAsFixed(1)})'; } diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index 57aabc1de984e..728ccbff0e44d 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -1618,7 +1618,7 @@ class FileImage extends ImageProvider { int get hashCode => Object.hash(file.path, scale); @override - String toString() => '${objectRuntimeType(this, 'FileImage')}("${file.path}", scale: $scale)'; + String toString() => '${objectRuntimeType(this, 'FileImage')}("${file.path}", scale: ${scale.toStringAsFixed(1)})'; } /// Decodes the given [Uint8List] buffer as an image, associating it with the @@ -1722,7 +1722,7 @@ class MemoryImage extends ImageProvider { int get hashCode => Object.hash(bytes.hashCode, scale); @override - String toString() => '${objectRuntimeType(this, 'MemoryImage')}(${describeIdentity(bytes)}, scale: $scale)'; + String toString() => '${objectRuntimeType(this, 'MemoryImage')}(${describeIdentity(bytes)}, scale: ${scale.toStringAsFixed(1)})'; } /// Fetches an image from an [AssetBundle], associating it with the given scale. @@ -1863,7 +1863,7 @@ class ExactAssetImage extends AssetBundleImageProvider { int get hashCode => Object.hash(keyName, scale, bundle); @override - String toString() => '${objectRuntimeType(this, 'ExactAssetImage')}(name: "$keyName", scale: $scale, bundle: $bundle)'; + String toString() => '${objectRuntimeType(this, 'ExactAssetImage')}(name: "$keyName", scale: ${scale.toStringAsFixed(1)}, bundle: $bundle)'; } // A completer used when resolving an image fails sync. diff --git a/packages/flutter/test/painting/image_provider_test.dart b/packages/flutter/test/painting/image_provider_test.dart index 05d3030a2b74c..737471dfeecbc 100644 --- a/packages/flutter/test/painting/image_provider_test.dart +++ b/packages/flutter/test/painting/image_provider_test.dart @@ -159,6 +159,12 @@ void main() { expect(imageCache.statusForKey(provider).untracked, false); expect(imageCache.pendingImageCount, 1); }, skip: kIsWeb); // [intended] The web cannot load files. + + test('ImageProvider toStrings', () async { + expect(const NetworkImage('test', scale: 1.21).toString(), 'NetworkImage("test", scale: 1.2)'); + expect(const ExactAssetImage('test', scale: 1.21).toString(), 'ExactAssetImage(name: "test", scale: 1.2, bundle: null)'); + expect(MemoryImage(Uint8List(0), scale: 1.21).toString(), equalsIgnoringHashCodes('MemoryImage(Uint8List#00000, scale: 1.2)')); + }); } class FakeCodec implements Codec { From 2c71881f505b0dc0997e959b3ac37664d221fad8 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 2 Aug 2023 03:48:06 +0300 Subject: [PATCH 0488/1547] Fix Scrollable `TabBar` for Material 3 (#131409) fixes [Material 3 `TabBar` does not take full width when `isScrollable: true`](https://github.com/flutter/flutter/issues/117722) ### Description 1. Fixed the divider doesn't stretch to take all the available width in the scrollable tab bar in M3 2. Added `dividerHeight` property. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [TabBar]. void main() => runApp(const TabBarApp()); class TabBarApp extends StatelessWidget { const TabBarApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: TabBarExample(), ); } } class TabBarExample extends StatefulWidget { const TabBarExample({super.key}); @override State createState() => _TabBarExampleState(); } class _TabBarExampleState extends State { bool rtl = false; bool customColors = false; bool removeDivider = false; Color dividerColor = Colors.amber; Color indicatorColor = Colors.red; @override Widget build(BuildContext context) { return DefaultTabController( initialIndex: 1, length: 3, child: Directionality( textDirection: rtl ? TextDirection.rtl : TextDirection.ltr, child: Scaffold( appBar: AppBar( title: const Text('TabBar Sample'), actions: [ IconButton.filledTonal( tooltip: 'Switch direction', icon: const Icon(Icons.swap_horiz), onPressed: () { setState(() { rtl = !rtl; }); }, ), IconButton.filledTonal( tooltip: 'Use custom colors', icon: const Icon(Icons.color_lens), onPressed: () { setState(() { customColors = !customColors; }); }, ), IconButton.filledTonal( tooltip: 'Show/hide divider', icon: const Icon(Icons.remove_rounded), onPressed: () { setState(() { removeDivider = !removeDivider; }); }, ), ], ), body: Column( children: [ const Spacer(), const Text('Scrollable - TabAlignment.start'), TabBar( isScrollable: true, tabAlignment: TabAlignment.start, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Text('Scrollable - TabAlignment.startOffset'), TabBar( isScrollable: true, tabAlignment: TabAlignment.startOffset, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Text('Scrollable - TabAlignment.center'), TabBar( isScrollable: true, tabAlignment: TabAlignment.center, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Spacer(), const Text('Non-scrollable - TabAlignment.fill'), TabBar( tabAlignment: TabAlignment.fill, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Text('Non-scrollable - TabAlignment.center'), TabBar( tabAlignment: TabAlignment.center, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Spacer(), const Text('Secondary - TabAlignment.fill'), TabBar.secondary( tabAlignment: TabAlignment.fill, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Text('Secondary - TabAlignment.center'), TabBar.secondary( tabAlignment: TabAlignment.center, dividerColor: customColors ? dividerColor : null, indicatorColor: customColors ? indicatorColor : null, dividerHeight: removeDivider ? 0 : null, tabs: const [ Tab( icon: Icon(Icons.cloud_outlined), ), Tab( icon: Icon(Icons.beach_access_sharp), ), Tab( icon: Icon(Icons.brightness_5_sharp), ), ], ), const Spacer(), ], ), ), ), ); } } ```
### Before ![Screenshot 2023-07-27 at 14 12 36](https://github.com/flutter/flutter/assets/48603081/1c08a9d2-ac15-4d33-8fa1-c765b4b10f92) ### After ![Screenshot 2023-07-27 at 14 13 12](https://github.com/flutter/flutter/assets/48603081/7e662dfe-9f32-46c9-a128-3024a4782882) This also contains regression test for https://github.com/flutter/flutter/pull/125974#discussion_r1239089151 ```dart // This is a regression test for https://github.com/flutter/flutter/pull/125974#discussion_r1239089151. testWidgets('Divider can be constrained', (WidgetTester tester) async { ``` ![Screenshot 2023-07-27 at 14 16 37](https://github.com/flutter/flutter/assets/48603081/ac2ef49b-2410-46d0-8ae2-d9b77236abba) --- .../gen_defaults/generated/used_tokens.csv | 2 + dev/tools/gen_defaults/lib/tabs_template.dart | 10 +- .../lib/src/material/tab_bar_theme.dart | 9 + packages/flutter/lib/src/material/tabs.dart | 98 ++- .../test/material/tab_bar_theme_test.dart | 371 +++++++++++- packages/flutter/test/material/tabs_test.dart | 572 ++++++++++++++++-- 6 files changed, 967 insertions(+), 95 deletions(-) diff --git a/dev/tools/gen_defaults/generated/used_tokens.csv b/dev/tools/gen_defaults/generated/used_tokens.csv index c7eb2a390b733..12754860bc581 100644 --- a/dev/tools/gen_defaults/generated/used_tokens.csv +++ b/dev/tools/gen_defaults/generated/used_tokens.csv @@ -530,6 +530,7 @@ md.comp.primary-navigation-tab.active.hover.state-layer.opacity, md.comp.primary-navigation-tab.active.pressed.state-layer.color, md.comp.primary-navigation-tab.active.pressed.state-layer.opacity, md.comp.primary-navigation-tab.divider.color, +md.comp.primary-navigation-tab.divider.height, md.comp.primary-navigation-tab.inactive.focus.state-layer.color, md.comp.primary-navigation-tab.inactive.focus.state-layer.opacity, md.comp.primary-navigation-tab.inactive.hover.state-layer.color, @@ -589,6 +590,7 @@ md.comp.search-view.header.supporting-text.color, md.comp.search-view.header.supporting-text.text-style, md.comp.secondary-navigation-tab.active.label-text.color, md.comp.secondary-navigation-tab.divider.color, +md.comp.secondary-navigation-tab.divider.height, md.comp.secondary-navigation-tab.focus.state-layer.color, md.comp.secondary-navigation-tab.focus.state-layer.opacity, md.comp.secondary-navigation-tab.hover.state-layer.color, diff --git a/dev/tools/gen_defaults/lib/tabs_template.dart b/dev/tools/gen_defaults/lib/tabs_template.dart index f6388a87458d3..f520f617b2012 100644 --- a/dev/tools/gen_defaults/lib/tabs_template.dart +++ b/dev/tools/gen_defaults/lib/tabs_template.dart @@ -24,6 +24,9 @@ class _${blockName}PrimaryDefaultsM3 extends TabBarTheme { @override Color? get dividerColor => ${componentColor("md.comp.primary-navigation-tab.divider")}; + @override + double? get dividerHeight => ${getToken('md.comp.primary-navigation-tab.divider.height')}; + @override Color? get indicatorColor => ${componentColor("md.comp.primary-navigation-tab.active-indicator")}; @@ -71,7 +74,7 @@ class _${blockName}PrimaryDefaultsM3 extends TabBarTheme { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @override - TabAlignment? get tabAlignment => isScrollable ? TabAlignment.start : TabAlignment.fill; + TabAlignment? get tabAlignment => isScrollable ? TabAlignment.startOffset : TabAlignment.fill; static double indicatorWeight = ${getToken('md.comp.primary-navigation-tab.active-indicator.height')}; } @@ -88,6 +91,9 @@ class _${blockName}SecondaryDefaultsM3 extends TabBarTheme { @override Color? get dividerColor => ${componentColor("md.comp.secondary-navigation-tab.divider")}; + @override + double? get dividerHeight => ${getToken('md.comp.secondary-navigation-tab.divider.height')}; + @override Color? get indicatorColor => ${componentColor("md.comp.primary-navigation-tab.active-indicator")}; @@ -135,7 +141,7 @@ class _${blockName}SecondaryDefaultsM3 extends TabBarTheme { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @override - TabAlignment? get tabAlignment => isScrollable ? TabAlignment.start : TabAlignment.fill; + TabAlignment? get tabAlignment => isScrollable ? TabAlignment.startOffset : TabAlignment.fill; } '''; diff --git a/packages/flutter/lib/src/material/tab_bar_theme.dart b/packages/flutter/lib/src/material/tab_bar_theme.dart index 87c43d7acf3bc..e65e8b3c4db82 100644 --- a/packages/flutter/lib/src/material/tab_bar_theme.dart +++ b/packages/flutter/lib/src/material/tab_bar_theme.dart @@ -32,6 +32,7 @@ class TabBarTheme with Diagnosticable { this.indicatorColor, this.indicatorSize, this.dividerColor, + this.dividerHeight, this.labelColor, this.labelPadding, this.labelStyle, @@ -55,6 +56,9 @@ class TabBarTheme with Diagnosticable { /// Overrides the default value for [TabBar.dividerColor]. final Color? dividerColor; + /// Overrides the default value for [TabBar.dividerHeight]. + final double? dividerHeight; + /// Overrides the default value for [TabBar.labelColor]. /// /// If [labelColor] is a [MaterialStateColor], then the effective color will @@ -101,6 +105,7 @@ class TabBarTheme with Diagnosticable { Color? indicatorColor, TabBarIndicatorSize? indicatorSize, Color? dividerColor, + double? dividerHeight, Color? labelColor, EdgeInsetsGeometry? labelPadding, TextStyle? labelStyle, @@ -116,6 +121,7 @@ class TabBarTheme with Diagnosticable { indicatorColor: indicatorColor ?? this.indicatorColor, indicatorSize: indicatorSize ?? this.indicatorSize, dividerColor: dividerColor ?? this.dividerColor, + dividerHeight: dividerHeight ?? this.dividerHeight, labelColor: labelColor ?? this.labelColor, labelPadding: labelPadding ?? this.labelPadding, labelStyle: labelStyle ?? this.labelStyle, @@ -147,6 +153,7 @@ class TabBarTheme with Diagnosticable { indicatorColor: Color.lerp(a.indicatorColor, b.indicatorColor, t), indicatorSize: t < 0.5 ? a.indicatorSize : b.indicatorSize, dividerColor: Color.lerp(a.dividerColor, b.dividerColor, t), + dividerHeight: t < 0.5 ? a.dividerHeight : b.dividerHeight, labelColor: Color.lerp(a.labelColor, b.labelColor, t), labelPadding: EdgeInsetsGeometry.lerp(a.labelPadding, b.labelPadding, t), labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t), @@ -165,6 +172,7 @@ class TabBarTheme with Diagnosticable { indicatorColor, indicatorSize, dividerColor, + dividerHeight, labelColor, labelPadding, labelStyle, @@ -189,6 +197,7 @@ class TabBarTheme with Diagnosticable { && other.indicatorColor == indicatorColor && other.indicatorSize == indicatorSize && other.dividerColor == dividerColor + && other.dividerHeight == dividerHeight && other.labelColor == labelColor && other.labelPadding == labelPadding && other.labelStyle == labelStyle diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 756e61c7f2dbc..2bb5f44971931 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -387,6 +387,39 @@ double _indexChangeProgress(TabController controller) { return (controllerValue - currentIndex).abs() / (currentIndex - previousIndex).abs(); } +class _DividerPainter extends CustomPainter { + _DividerPainter({ + required this.dividerColor, + required this.dividerHeight, + }); + + final Color dividerColor; + final double dividerHeight; + + @override + void paint(Canvas canvas, Size size) { + if (dividerHeight <= 0.0) { + return; + } + + final Paint paint = Paint() + ..color = dividerColor + ..strokeWidth = dividerHeight; + + canvas.drawLine( + Offset(0, size.height - (paint.strokeWidth / 2)), + Offset(size.width, size.height - (paint.strokeWidth / 2)), + paint, + ); + } + + @override + bool shouldRepaint(_DividerPainter oldDelegate) { + return oldDelegate.dividerColor != dividerColor + || oldDelegate.dividerHeight != dividerHeight; + } +} + class _IndicatorPainter extends CustomPainter { _IndicatorPainter({ required this.controller, @@ -397,6 +430,8 @@ class _IndicatorPainter extends CustomPainter { required this.indicatorPadding, required this.labelPaddings, this.dividerColor, + this.dividerHeight, + required this.showDivider, }) : super(repaint: controller.animation) { if (old != null) { saveTabOffsets(old._currentTabOffsets, old._currentTextDirection); @@ -408,8 +443,10 @@ class _IndicatorPainter extends CustomPainter { final TabBarIndicatorSize? indicatorSize; final EdgeInsetsGeometry indicatorPadding; final List tabKeys; - final Color? dividerColor; final List labelPaddings; + final Color? dividerColor; + final double? dividerHeight; + final bool showDivider; // _currentTabOffsets and _currentTextDirection are set each time TabBar // layout is completed. These values can be null when TabBar contains no @@ -501,9 +538,11 @@ class _IndicatorPainter extends CustomPainter { size: _currentRect!.size, textDirection: _currentTextDirection, ); - if (dividerColor != null) { - final Paint dividerPaint = Paint()..color = dividerColor!..strokeWidth = 1; - canvas.drawLine(Offset(0, size.height), Offset(size.width, size.height), dividerPaint); + if (showDivider && dividerHeight !> 0) { + final Paint dividerPaint = Paint()..color = dividerColor!..strokeWidth = dividerHeight!; + final Offset dividerP1 = Offset(0, size.height - (dividerPaint.strokeWidth / 2)); + final Offset dividerP2 = Offset(size.width, size.height - (dividerPaint.strokeWidth / 2)); + canvas.drawLine(dividerP1, dividerP2, dividerPaint); } _painter!.paint(canvas, _currentRect!.topLeft, configuration); } @@ -718,6 +757,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { this.indicator, this.indicatorSize, this.dividerColor, + this.dividerHeight, this.labelColor, this.labelStyle, this.labelPadding, @@ -768,6 +808,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { this.indicator, this.indicatorSize, this.dividerColor, + this.dividerHeight, this.labelColor, this.labelStyle, this.labelPadding, @@ -895,6 +936,13 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// [ColorScheme.surfaceVariant] will be used, otherwise divider will not be drawn. final Color? dividerColor; + /// The height of the divider. + /// + /// If null and [ThemeData.useMaterial3] is true, [TabBarTheme.dividerHeight] is used. + /// If that is also null and [ThemeData.useMaterial3] is true, 1.0 will be used. + /// Otherwise divider will not be drawn. + final double? dividerHeight; + /// The color of selected tab labels. /// /// If null, then [TabBarTheme.labelColor] is used. If that is also null and @@ -1154,8 +1202,8 @@ class _TabBarState extends State { TabBarTheme get _defaults { if (Theme.of(context).useMaterial3) { return widget._isPrimary - ? _TabsPrimaryDefaultsM3(context, widget.isScrollable) - : _TabsSecondaryDefaultsM3(context, widget.isScrollable); + ? _TabsPrimaryDefaultsM3(context, widget.isScrollable) + : _TabsSecondaryDefaultsM3(context, widget.isScrollable); } else { return _TabsDefaultsM2(context, widget.isScrollable); } @@ -1269,8 +1317,10 @@ class _TabBarState extends State { indicatorPadding: widget.indicatorPadding, tabKeys: _tabKeys, old: _indicatorPainter, - dividerColor: theme.useMaterial3 ? widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor : null, labelPaddings: _labelPaddings, + dividerColor: widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor, + dividerHeight: widget.dividerHeight ?? tabBarTheme.dividerHeight ?? _defaults.dividerHeight, + showDivider: theme.useMaterial3 && !widget.isScrollable, ); } @@ -1299,7 +1349,9 @@ class _TabBarState extends State { widget.indicatorWeight != oldWidget.indicatorWeight || widget.indicatorSize != oldWidget.indicatorSize || widget.indicatorPadding != oldWidget.indicatorPadding || - widget.indicator != oldWidget.indicator) { + widget.indicator != oldWidget.indicator || + widget.dividerColor != oldWidget.dividerColor || + widget.dividerHeight != oldWidget.dividerHeight) { _initIndicatorPainter(); } @@ -1475,6 +1527,7 @@ class _TabBarState extends State { Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); assert(_debugScheduleCheckHasValidTabsCount()); + final ThemeData theme = Theme.of(context); final TabBarTheme tabBarTheme = TabBarTheme.of(context); final TabAlignment effectiveTabAlignment = widget.tabAlignment ?? tabBarTheme.tabAlignment ?? _defaults.tabAlignment!; assert(_debugTabAlignmentIsValid(effectiveTabAlignment)); @@ -1486,7 +1539,6 @@ class _TabBarState extends State { ); } - final List wrappedTabs = List.generate(widget.tabs.length, (int index) { const double verticalAdjustment = (_kTextAndIconTabHeight - _kTabHeight)/2.0; EdgeInsetsGeometry? adjustedPadding; @@ -1627,6 +1679,24 @@ class _TabBarState extends State { child: tabBar, ), ); + if (theme.useMaterial3) { + final AlignmentGeometry effectiveAlignment = switch (effectiveTabAlignment) { + TabAlignment.center => Alignment.center, + TabAlignment.start || TabAlignment.startOffset || TabAlignment.fill => AlignmentDirectional.centerStart, + }; + + tabBar = CustomPaint( + painter: _DividerPainter( + dividerColor: widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor!, + dividerHeight: widget.dividerHeight ?? tabBarTheme.dividerHeight ?? _defaults.dividerHeight!, + ), + child: Align( + heightFactor: 1.0, + alignment: effectiveAlignment, + child: tabBar, + ), + ); + } } else if (widget.padding != null) { tabBar = Padding( padding: widget.padding!, @@ -2177,6 +2247,9 @@ class _TabsPrimaryDefaultsM3 extends TabBarTheme { @override Color? get dividerColor => _colors.surfaceVariant; + @override + double? get dividerHeight => 1.0; + @override Color? get indicatorColor => _colors.primary; @@ -2224,7 +2297,7 @@ class _TabsPrimaryDefaultsM3 extends TabBarTheme { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @override - TabAlignment? get tabAlignment => isScrollable ? TabAlignment.start : TabAlignment.fill; + TabAlignment? get tabAlignment => isScrollable ? TabAlignment.startOffset : TabAlignment.fill; static double indicatorWeight = 3.0; } @@ -2241,6 +2314,9 @@ class _TabsSecondaryDefaultsM3 extends TabBarTheme { @override Color? get dividerColor => _colors.surfaceVariant; + @override + double? get dividerHeight => 1.0; + @override Color? get indicatorColor => _colors.primary; @@ -2288,7 +2364,7 @@ class _TabsSecondaryDefaultsM3 extends TabBarTheme { InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory; @override - TabAlignment? get tabAlignment => isScrollable ? TabAlignment.start : TabAlignment.fill; + TabAlignment? get tabAlignment => isScrollable ? TabAlignment.startOffset : TabAlignment.fill; } // END GENERATED TOKEN PROPERTIES - Tabs diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 3b686c185ddc4..0f69b1019043c 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -90,6 +90,7 @@ void main() { expect(const TabBarTheme().indicatorColor, null); expect(const TabBarTheme().indicatorSize, null); expect(const TabBarTheme().dividerColor, null); + expect(const TabBarTheme().dividerHeight, null); expect(const TabBarTheme().labelColor, null); expect(const TabBarTheme().labelPadding, null); expect(const TabBarTheme().labelStyle, null); @@ -127,27 +128,32 @@ void main() { final Rect tabBar = tester.getRect(find.byType(TabBar)); final Rect tabOneRect = tester.getRect(find.byKey(_sizedTabs[0].key!)); final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!)); + const double tabStartOffset = 52.0; // Verify tabOne coordinates. - expect(tabOneRect.left, equals(kTabLabelPadding.left)); + expect(tabOneRect.left, equals(kTabLabelPadding.left + tabStartOffset)); expect(tabOneRect.top, equals(kTabLabelPadding.top)); expect(tabOneRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight)); // Verify tabTwo coordinates. - expect(tabTwoRect.right, equals(tabBar.width - kTabLabelPadding.right)); + final double tabTwoRight = tabStartOffset + kTabLabelPadding.horizontal + tabOneRect.width + + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, tabTwoRight); expect(tabTwoRect.top, equals(kTabLabelPadding.top)); expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight)); - // Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo. + // Verify tabOne and tabTwo are separated by right padding of tabOne and left padding of tabTwo. expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right)); - // Test default indicator color and divider color. + // Test default indicator & divider color. final RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); expect( tabBarBox, paints - ..line(color: theme.colorScheme.surfaceVariant) - // Indicator is a rrect in the primary tab bar. + ..line( + color: theme.colorScheme.surfaceVariant, + strokeWidth: 1.0, + ) ..rrect(color: theme.colorScheme.primary), ); }); @@ -178,29 +184,34 @@ void main() { final Rect tabBar = tester.getRect(find.byType(TabBar)); final Rect tabOneRect = tester.getRect(find.byKey(_sizedTabs[0].key!)); final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!)); + const double tabStartOffset = 52.0; // Verify tabOne coordinates. - expect(tabOneRect.left, equals(kTabLabelPadding.left)); + expect(tabOneRect.left, equals(kTabLabelPadding.left + tabStartOffset)); expect(tabOneRect.top, equals(kTabLabelPadding.top)); expect(tabOneRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight)); // Verify tabTwo coordinates. - expect(tabTwoRect.right, equals(tabBar.width - kTabLabelPadding.right)); + final double tabTwoRight = tabStartOffset + kTabLabelPadding.horizontal + tabOneRect.width + + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, tabTwoRight); expect(tabTwoRect.top, equals(kTabLabelPadding.top)); expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight)); - // Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo. + // Verify tabOne and tabTwo are separated by right padding of tabOne and left padding of tabTwo. expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right)); - // Test default indicator color and divider color. + // Test default indicator & divider color. final RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); expect( tabBarBox, paints - ..line(color: theme.colorScheme.surfaceVariant) - // Indicator is a line in the secondary tab bar. + ..line( + color: theme.colorScheme.surfaceVariant, + strokeWidth: 1.0, + ) ..line(color: theme.colorScheme.primary), - ); + ); }); testWidgets('Tab bar theme overrides label color (selected)', (WidgetTester tester) async { @@ -315,7 +326,7 @@ void main() { expect(unselectedLabel.text.style!.fontFamily, equals(unselectedLabelStyle.fontFamily)); }); - testWidgets('Tab bar label padding overrides theme label padding', (WidgetTester tester) async { + testWidgets('Material2 - Tab bar label padding overrides theme label padding', (WidgetTester tester) async { const double verticalPadding = 10.0; const double horizontalPadding = 10.0; const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric( @@ -336,7 +347,7 @@ void main() { await tester.pumpWidget( MaterialApp( - theme: ThemeData(tabBarTheme: tabBarTheme), + theme: ThemeData(tabBarTheme: tabBarTheme, useMaterial3: false), home: Scaffold(body: RepaintBoundary( key: _painterKey, @@ -369,6 +380,61 @@ void main() { expect(tabOneRect.right, equals(tabTwoRect.left - (2 * horizontalPadding))); }); + testWidgets('Material3 - Tab bar label padding overrides theme label padding', (WidgetTester tester) async { + const double tabStartOffset = 52.0; + const double verticalPadding = 10.0; + const double horizontalPadding = 10.0; + const EdgeInsetsGeometry labelPadding = EdgeInsets.symmetric( + vertical: verticalPadding, + horizontal: horizontalPadding, + ); + + const double verticalThemePadding = 20.0; + const double horizontalThemePadding = 20.0; + const EdgeInsetsGeometry themeLabelPadding = EdgeInsets.symmetric( + vertical: verticalThemePadding, + horizontal: horizontalThemePadding, + ); + + const double indicatorWeight = 2.0; // default value + + const TabBarTheme tabBarTheme = TabBarTheme(labelPadding: themeLabelPadding); + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(tabBarTheme: tabBarTheme, useMaterial3: true), + home: Scaffold(body: + RepaintBoundary( + key: _painterKey, + child: TabBar( + tabs: _sizedTabs, + isScrollable: true, + controller: TabController(length: _sizedTabs.length, vsync: const TestVSync()), + labelPadding: labelPadding, + ), + ), + ), + ), + ); + + final Rect tabBar = tester.getRect(find.byType(TabBar)); + final Rect tabOneRect = tester.getRect(find.byKey(_sizedTabs[0].key!)); + final Rect tabTwoRect = tester.getRect(find.byKey(_sizedTabs[1].key!)); + + // verify coordinates of tabOne + expect(tabOneRect.left, equals(horizontalPadding + tabStartOffset)); + expect(tabOneRect.top, equals(verticalPadding)); + expect(tabOneRect.bottom, equals(tabBar.bottom - verticalPadding - indicatorWeight)); + + // verify coordinates of tabTwo + expect(tabTwoRect.right, equals(tabStartOffset + horizontalThemePadding + tabOneRect.width + tabTwoRect.width + (horizontalThemePadding / 2))); + expect(tabTwoRect.top, equals(verticalPadding)); + expect(tabTwoRect.bottom, equals(tabBar.bottom - verticalPadding - indicatorWeight)); + + // verify tabOne and tabTwo are separated by 2x horizontalPadding + expect(tabOneRect.right, equals(tabTwoRect.left - (2 * horizontalPadding))); + }); + testWidgets('Tab bar theme overrides label color (unselected)', (WidgetTester tester) async { const Color unselectedLabelColor = Colors.black; const TabBarTheme tabBarTheme = TabBarTheme(unselectedLabelColor: unselectedLabelColor); @@ -381,7 +447,7 @@ void main() { expect(iconRenderObject.text.style!.color, equals(unselectedLabelColor)); }); - testWidgets('Tab bar default tab indicator size', (WidgetTester tester) async { + testWidgets('Tab bar default tab indicator size (primary)', (WidgetTester tester) async { await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true)); await expectLater( @@ -390,12 +456,12 @@ void main() { ); }); - testWidgets('Tab bar default tab indicator size', (WidgetTester tester) async { + testWidgets('Tab bar default tab indicator size (secondary)', (WidgetTester tester) async { await tester.pumpWidget(buildTabBar(useMaterial3: true, isScrollable: true)); await expectLater( find.byKey(_painterKey), - matchesGoldenFile('tab_bar.default.tab_indicator_size.png'), + matchesGoldenFile('tab_bar_secondary.default.tab_indicator_size.png'), ); }); @@ -549,11 +615,12 @@ void main() { expect( tabBarBox, paints - // Divider + // Divider. ..line( color: theme.colorScheme.surfaceVariant, + strokeWidth: 1.0, ) - // Tab indicator + // Tab indicator. ..line( color: theme.colorScheme.primary, strokeWidth: indicatorWeight, @@ -601,9 +668,10 @@ void main() { expect( tabBarBox, paints - // Divider + // Divider. ..line( color: theme.colorScheme.surfaceVariant, + strokeWidth: 1.0, ) // Tab indicator ..line( @@ -615,6 +683,202 @@ void main() { ); }); + testWidgets('TabBar divider can use TabBarTheme.dividerColor & TabBarTheme.dividerHeight', (WidgetTester tester) async { + const Color dividerColor = Color(0xff00ff00); + const double dividerHeight = 10.0; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme( + dividerColor: dividerColor, + dividerHeight: dividerHeight, + ), + useMaterial3: true, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + controller: TabController(length: 3, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 2'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + final RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + // Test divider color. + expect(tabBarBox, paints..line(color: dividerColor, strokeWidth: dividerHeight)); + }); + + testWidgets('dividerColor & dividerHeight overrides TabBarTheme.dividerColor', (WidgetTester tester) async { + const Color dividerColor = Color(0xff0000ff); + const double dividerHeight = 8.0; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + useMaterial3: true, + tabBarTheme: const TabBarTheme( + dividerColor: Colors.pink, + dividerHeight: 5.0, + ), + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + dividerColor: dividerColor, + dividerHeight: dividerHeight, + controller: TabController(length: 3, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 2'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + final RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + // Test divider color. + expect(tabBarBox, paints..line(color: dividerColor, strokeWidth: dividerHeight)); + }); + + testWidgets('TabBar respects TabBarTheme.tabAlignment', (WidgetTester tester) async { + // Test non-scrollable tab bar. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme(tabAlignment: TabAlignment.center), + useMaterial3: true, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + controller: TabController(length: 2, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + const double availableWidth = 800.0; + Rect tabOneRect = tester.getRect(find.byType(Tab).first); + Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + double tabOneLeft = (availableWidth / 2) - tabOneRect.width - kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + double tabTwoRight = (availableWidth / 2) + tabTwoRect.width + kTabLabelPadding.right; + expect(tabTwoRect.right, equals(tabTwoRight)); + + // Test scrollable tab bar. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme(tabAlignment: TabAlignment.start), + useMaterial3: true, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + isScrollable: true, + controller: TabController(length: 2, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + tabOneLeft = kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); + + testWidgets('TabBar.tabAlignment overrides TabBarTheme.tabAlignment', (WidgetTester tester) async { + /// Test non-scrollable tab bar. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme(tabAlignment: TabAlignment.fill), + useMaterial3: true, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + tabAlignment: TabAlignment.center, + controller: TabController(length: 2, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + const double availableWidth = 800.0; + Rect tabOneRect = tester.getRect(find.byType(Tab).first); + Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + double tabOneLeft = (availableWidth / 2) - tabOneRect.width - kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + double tabTwoRight = (availableWidth / 2) + tabTwoRect.width + kTabLabelPadding.right; + expect(tabTwoRect.right, equals(tabTwoRight)); + + /// Test scrollable tab bar. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme(tabAlignment: TabAlignment.center), + useMaterial3: true, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + isScrollable: true, + tabAlignment: TabAlignment.start, + controller: TabController(length: 2, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + tabOneLeft = kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests @@ -692,7 +956,7 @@ void main() { expect(tabTwoRect.top, equals(kTabLabelPadding.top)); expect(tabTwoRect.bottom, equals(tabBar.bottom - kTabLabelPadding.bottom - indicatorWeight)); - // Verify tabOne and tabTwo is separated by right padding of tabOne and left padding of tabTwo. + // Verify tabOne and tabTwo are separated by right padding of tabOne and left padding of tabTwo. expect(tabOneRect.right, equals(tabTwoRect.left - kTabLabelPadding.left - kTabLabelPadding.right)); // Test default indicator color. @@ -806,5 +1070,68 @@ void main() { ), ); }); + + testWidgets('TabBar respects TabBarTheme.tabAlignment', (WidgetTester tester) async { + // Test non-scrollable tab bar. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme(tabAlignment: TabAlignment.center), + useMaterial3: false, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + controller: TabController(length: 2, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + final Rect tabOneRect = tester.getRect(find.byType(Tab).first); + final Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + final double tabOneLeft = (800 / 2) - tabOneRect.width - kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + final double tabTwoRight = (800 / 2) + tabTwoRect.width + kTabLabelPadding.right; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); + + testWidgets('TabBar.tabAlignment overrides TabBarTheme.tabAlignment', (WidgetTester tester) async { + // Test non-scrollable tab bar. + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + tabBarTheme: const TabBarTheme(tabAlignment: TabAlignment.fill), + useMaterial3: false, + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + tabAlignment: TabAlignment.center, + controller: TabController(length: 2, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + final Rect tabOneRect = tester.getRect(find.byType(Tab).first); + final Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + final double tabOneLeft = (800 / 2) - tabOneRect.width - kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + final double tabTwoRight = (800 / 2) + tabTwoRect.width + kTabLabelPadding.right; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); }); } diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 62e4f172fd09f..df4d34c3767d4 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -701,10 +701,16 @@ void main() { expect(controller.index, 0); }); - testWidgets('Scrollable TabBar tap centers selected tab', (WidgetTester tester) async { + testWidgets('Material2 - Scrollable TabBar tap centers selected tab', (WidgetTester tester) async { final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; const Key tabBarKey = Key('TabBar'); - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey)); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAAAA', + isScrollable: true, + tabBarKey: tabBarKey, + useMaterial3: false, + )); final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA'))); expect(controller, isNotNull); expect(controller.index, 0); @@ -720,12 +726,44 @@ void main() { expect(tester.getCenter(find.text('FFFFFF')).dx, moreOrLessEquals(400.0, epsilon: 1.0)); }); - testWidgets('Scrollable TabBar, with padding, tap centers selected tab', (WidgetTester tester) async { + testWidgets('Material3 - Scrollable TabBar tap centers selected tab', (WidgetTester tester) async { + final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; + const Key tabBarKey = Key('TabBar'); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAAAA', + isScrollable: true, + tabBarKey: tabBarKey, + useMaterial3: true, + )); + final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA'))); + expect(controller, isNotNull); + expect(controller.index, 0); + + expect(tester.getSize(find.byKey(tabBarKey)).width, equals(800.0)); + // The center of the FFFFFF item is to the right of the TabBar's center + expect(tester.getCenter(find.text('FFFFFF')).dx, greaterThan(401.0)); + + await tester.tap(find.text('FFFFFF')); + await tester.pumpAndSettle(); + expect(controller.index, 5); + // The center of the FFFFFF item is now at the TabBar's center + expect(tester.getCenter(find.text('FFFFFF')).dx, moreOrLessEquals(452.0, epsilon: 1.0)); + }); + + testWidgets('Material2 - Scrollable TabBar, with padding, tap centers selected tab', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/112776 final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; const Key tabBarKey = Key('TabBar'); const EdgeInsetsGeometry padding = EdgeInsets.only(right: 30, left: 60); - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAAAA', isScrollable: true, tabBarKey: tabBarKey, padding: padding)); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAAAA', + isScrollable: true, + tabBarKey: tabBarKey, + padding: padding, + useMaterial3: false, + )); final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA'))); expect(controller, isNotNull); expect(controller.index, 0); @@ -741,7 +779,35 @@ void main() { expect(tester.getCenter(find.text('FFFFFF')).dx, moreOrLessEquals(400.0, epsilon: 1.0)); }); - testWidgets('Scrollable TabBar, with padding and TextDirection.rtl, tap centers selected tab', (WidgetTester tester) async { + testWidgets('Material3 - Scrollable TabBar, with padding, tap centers selected tab', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/112776 + final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; + const Key tabBarKey = Key('TabBar'); + const EdgeInsetsGeometry padding = EdgeInsets.only(right: 30, left: 60); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAAAA', + isScrollable: true, + tabBarKey: tabBarKey, + padding: padding, + useMaterial3: true, + )); + final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA'))); + expect(controller, isNotNull); + expect(controller.index, 0); + + expect(tester.getSize(find.byKey(tabBarKey)).width, equals(800.0)); + // The center of the FFFFFF item is to the right of the TabBar's center + expect(tester.getCenter(find.text('FFFFFF')).dx, greaterThan(401.0)); + + await tester.tap(find.text('FFFFFF')); + await tester.pumpAndSettle(); + expect(controller.index, 5); + // The center of the FFFFFF item is now at the TabBar's center + expect(tester.getCenter(find.text('FFFFFF')).dx, moreOrLessEquals(452.0, epsilon: 1.0)); + }); + + testWidgets('Material2 - Scrollable TabBar, with padding and TextDirection.rtl, tap centers selected tab', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/112776 final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; const Key tabBarKey = Key('TabBar'); @@ -753,6 +819,7 @@ void main() { tabBarKey: tabBarKey, padding: padding, textDirection: TextDirection.rtl, + useMaterial3: false, )); final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA'))); expect(controller, isNotNull); @@ -769,10 +836,45 @@ void main() { expect(tester.getCenter(find.text('FFFFFF')).dx, moreOrLessEquals(400.0, epsilon: 1.0)); }); - testWidgets('TabBar can be scrolled independent of the selection', (WidgetTester tester) async { + testWidgets('Material3 - Scrollable TabBar, with padding and TextDirection.rtl, tap centers selected tab', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/112776 + final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE', 'FFFFFF', 'GGGGGG', 'HHHHHH', 'IIIIII', 'JJJJJJ', 'KKKKKK', 'LLLLLL']; + const Key tabBarKey = Key('TabBar'); + const EdgeInsetsGeometry padding = EdgeInsets.only(right: 30, left: 60); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAAAA', + isScrollable: true, + tabBarKey: tabBarKey, + padding: padding, + textDirection: TextDirection.rtl, + useMaterial3: true, + )); + final TabController controller = DefaultTabController.of(tester.element(find.text('AAAAAA'))); + expect(controller, isNotNull); + expect(controller.index, 0); + + expect(tester.getSize(find.byKey(tabBarKey)).width, equals(800.0)); + // The center of the FFFFFF item is to the left of the TabBar's center + expect(tester.getCenter(find.text('FFFFFF')).dx, lessThan(401.0)); + + await tester.tap(find.text('FFFFFF')); + await tester.pumpAndSettle(); + expect(controller.index, 5); + // The center of the FFFFFF item is now at the TabBar's center + expect(tester.getCenter(find.text('FFFFFF')).dx, moreOrLessEquals(348.0, epsilon: 1.0)); + }); + + testWidgets('Material2 - TabBar can be scrolled independent of the selection', (WidgetTester tester) async { final List tabs = ['AAAA', 'BBBB', 'CCCC', 'DDDD', 'EEEE', 'FFFF', 'GGGG', 'HHHH', 'IIII', 'JJJJ', 'KKKK', 'LLLL']; const Key tabBarKey = Key('TabBar'); - await tester.pumpWidget(buildFrame(tabs: tabs, value: 'AAAA', isScrollable: true, tabBarKey: tabBarKey)); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAA', + isScrollable: true, + tabBarKey: tabBarKey, + useMaterial3: false, + )); final TabController controller = DefaultTabController.of(tester.element(find.text('AAAA'))); expect(controller, isNotNull); expect(controller.index, 0); @@ -788,6 +890,31 @@ void main() { expect(controller.index, 0); }); + testWidgets('Material3 - TabBar can be scrolled independent of the selection', (WidgetTester tester) async { + final List tabs = ['AAAA', 'BBBB', 'CCCC', 'DDDD', 'EEEE', 'FFFF', 'GGGG', 'HHHH', 'IIII', 'JJJJ', 'KKKK', 'LLLL']; + const Key tabBarKey = Key('TabBar'); + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'AAAA', + isScrollable: true, + tabBarKey: tabBarKey, + useMaterial3: true, + )); + final TabController controller = DefaultTabController.of(tester.element(find.text('AAAA'))); + expect(controller, isNotNull); + expect(controller.index, 0); + + // Fling-scroll the TabBar to the left + expect(tester.getCenter(find.text('HHHH')).dx, lessThan(720.0)); + await tester.fling(find.byKey(tabBarKey), const Offset(-200.0, 0.0), 10000.0); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); // finish the scroll animation + expect(tester.getCenter(find.text('HHHH')).dx, lessThan(500.0)); + + // Scrolling the TabBar doesn't change the selection + expect(controller.index, 0); + }); + testWidgets('TabBarView maintains state', (WidgetTester tester) async { final List tabs = ['AAAAAA', 'BBBBBB', 'CCCCCC', 'DDDDDD', 'EEEEEE']; String value = tabs[0]; @@ -2981,9 +3108,10 @@ void main() { expect(tabBarBox.size.width, tabRight); }); - testWidgets('TabBar with padding isScrollable: true', (WidgetTester tester) async { + testWidgets('Material3 - TabBar with padding isScrollable: true', (WidgetTester tester) async { const double indicatorWeight = 2.0; // default indicator weight const EdgeInsets padding = EdgeInsets.only(left: 3.0, top: 7.0, right: 5.0, bottom: 3.0); + const double tabStartOffset = 52.0; final List tabs = [ SizedBox(key: UniqueKey(), width: 130.0, height: 30.0), @@ -3008,6 +3136,7 @@ void main() { tabs: tabs, ), ), + useMaterial3: true, ), ); @@ -3016,7 +3145,7 @@ void main() { expect(tabBarBox.size.height, tabBarHeight); // Tab0 width = 130, height = 30 - double tabLeft = padding.left; + double tabLeft = padding.left + tabStartOffset; double tabRight = tabLeft + 130.0; double tabTop = (tabBarHeight - indicatorWeight + (padding.top - padding.bottom) - 30.0) / 2.0; double tabBottom = tabTop + 30.0; @@ -3040,7 +3169,7 @@ void main() { expect(tester.getRect(find.byKey(tabs[2].key!)), tabRect); tabRight += padding.right; - expect(tabBarBox.size.width, tabRight); + expect(tabBarBox.size.width, tabRight + 320.0); // Right tab + remaining space of the stretched tab bar. }); testWidgets('TabBar with labelPadding', (WidgetTester tester) async { @@ -5950,15 +6079,12 @@ void main() { ); }); - testWidgets('Default TabAlignment', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); + testWidgets('Material3 - Default TabAlignment', (WidgetTester tester) async { final List tabs = ['A', 'B']; + const double tabStartOffset = 52.0; // Test default TabAlignment when isScrollable is false. - await tester.pumpWidget(MaterialApp( - theme: theme, - home: buildFrame(tabs: tabs, value: 'B'), - )); + await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', useMaterial3: true)); final Rect tabBar = tester.getRect(find.byType(TabBar)); Rect tabOneRect = tester.getRect(find.byType(Tab).first); @@ -5971,18 +6097,20 @@ void main() { expect(tabTwoRect.right, equals(tabTwoRight)); // Test default TabAlignment when isScrollable is true. - await tester.pumpWidget(MaterialApp( - theme: theme, - home: buildFrame(tabs: tabs, value: 'B', isScrollable: true), + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + useMaterial3: true, )); tabOneRect = tester.getRect(find.byType(Tab).first); tabTwoRect = tester.getRect(find.byType(Tab).last); // Tabs should be aligned to the start of the TabBar. - tabOneLeft = kTabLabelPadding.left; + tabOneLeft = kTabLabelPadding.left + tabStartOffset; expect(tabOneRect.left, equals(tabOneLeft)); - tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; + tabTwoRight = kTabLabelPadding.horizontal + tabStartOffset + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; expect(tabTwoRect.right, equals(tabTwoRight)); }); @@ -6044,6 +6172,262 @@ void main() { expect(tester.takeException(), isAssertionError); }); + testWidgets('Material3 - TabAlignment updates tabs alignment (non-scrollable TabBar)', (WidgetTester tester) async { + final List tabs = ['A', 'B']; + + // Test TabAlignment.fill (default) when isScrollable is false. + await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', useMaterial3: true)); + + const double availableWidth = 800.0; + Rect tabOneRect = tester.getRect(find.byType(Tab).first); + Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + // By defaults tabs should fill the width of the TabBar. + double tabOneLeft = ((availableWidth / 2) - tabOneRect.width) / 2; + expect(tabOneRect.left, equals(tabOneLeft)); + double tabTwoRight = availableWidth - ((availableWidth / 2) - tabTwoRect.width) / 2; + expect(tabTwoRect.right, equals(tabTwoRight)); + + // Test TabAlignment.center when isScrollable is false. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + tabAlignment: TabAlignment.center, + useMaterial3: true, + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should not fill the width of the TabBar. + tabOneLeft = kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); + + testWidgets('Material3 - TabAlignment updates tabs alignment (scrollable TabBar)', (WidgetTester tester) async { + final List tabs = ['A', 'B']; + const double tabStartOffset = 52.0; + + // Test TabAlignment.startOffset (default) when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + useMaterial3: true, + )); + + final Rect tabBar = tester.getRect(find.byType(TabBar)); + Rect tabOneRect = tester.getRect(find.byType(Tab).first); + Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + // By default tabs should be aligned to the start of the TabBar with + // an horizontal offset of 52.0 pixels. + double tabOneLeft = kTabLabelPadding.left + tabStartOffset; + expect(tabOneRect.left, equals(tabOneLeft)); + double tabTwoRight = tabStartOffset + kTabLabelPadding.horizontal + tabOneRect.width + + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + + // Test TabAlignment.start when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + tabAlignment: TabAlignment.start, + useMaterial3: true, + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should be aligned to the start of the TabBar. + tabOneLeft = kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + + // Test TabAlignment.center when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + tabAlignment: TabAlignment.center, + useMaterial3: true, + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should be centered in the TabBar. + tabOneLeft = (tabBar.width / 2) - tabOneRect.width - kTabLabelPadding.right; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = (tabBar.width / 2) + tabTwoRect.width + kTabLabelPadding.left; + expect(tabTwoRect.right, equals(tabTwoRight)); + + // Test TabAlignment.startOffset when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + tabAlignment: TabAlignment.startOffset, + useMaterial3: true, + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should be aligned to the start of the TabBar with an + // horizontal offset of 52.0 pixels. + tabOneLeft = kTabLabelPadding.left + tabStartOffset; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = tabStartOffset + kTabLabelPadding.horizontal + tabOneRect.width + + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); + + testWidgets('Material3 - TabAlignment.start & TabAlignment.startOffset respects TextDirection.rtl', (WidgetTester tester) async { + final List tabs = ['A', 'B']; + const double tabStartOffset = 52.0; + + // Test TabAlignment.startOffset (default) when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + textDirection: TextDirection.rtl, + useMaterial3: true, + )); + + final Rect tabBar = tester.getRect(find.byType(TabBar)); + Rect tabOneRect = tester.getRect(find.byType(Tab).first); + Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should be aligned to the start of the TabBar with an + // horizontal offset of 52.0 pixels. + double tabOneRight = tabBar.width - kTabLabelPadding.right - tabStartOffset; + expect(tabOneRect.right, equals(tabOneRight)); + double tabTwoLeft = tabBar.width - tabStartOffset - kTabLabelPadding.horizontal - tabOneRect.width + - kTabLabelPadding.right - tabTwoRect.width; + expect(tabTwoRect.left, equals(tabTwoLeft)); + + // Test TabAlignment.start when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + tabAlignment: TabAlignment.start, + textDirection: TextDirection.rtl, + useMaterial3: true, + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should be aligned to the start of the TabBar. + tabOneRight = tabBar.width - kTabLabelPadding.right; + expect(tabOneRect.right, equals(tabOneRight)); + tabTwoLeft = tabBar.width - kTabLabelPadding.horizontal - tabOneRect.width + - kTabLabelPadding.left - tabTwoRect.width; + expect(tabTwoRect.left, equals(tabTwoLeft)); + + // Test TabAlignment.startOffset when isScrollable is true. + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + tabAlignment: TabAlignment.startOffset, + textDirection: TextDirection.rtl, + useMaterial3: true, + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should be aligned to the start of the TabBar with an + // horizontal offset of 52.0 pixels. + tabOneRight = tabBar.width - kTabLabelPadding.right - tabStartOffset; + expect(tabOneRect.right, equals(tabOneRight)); + tabTwoLeft = tabBar.width - tabStartOffset - kTabLabelPadding.horizontal - tabOneRect.width + - kTabLabelPadding.right - tabTwoRect.width; + expect(tabTwoRect.left, equals(tabTwoLeft)); + }); + + testWidgets('Material3 - TabBar inherits the dividerColor of TabBarTheme', (WidgetTester tester) async { + const Color dividerColor = Colors.yellow; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + useMaterial3: true, + tabBarTheme: const TabBarTheme(dividerColor: dividerColor), + ), + home: Scaffold( + appBar: AppBar( + bottom: TabBar( + controller: TabController(length: 3, vsync: const TestVSync()), + tabs: const [ + Tab(text: 'Tab 1'), + Tab(text: 'Tab 2'), + Tab(text: 'Tab 3'), + ], + ), + ), + ), + ), + ); + + // Test painter's divider color. + final CustomPaint paint = tester.widget(find.byType(CustomPaint).last); + // ignore: avoid_dynamic_calls + expect((paint.painter as dynamic).dividerColor, dividerColor); + }); + + // This is a regression test for https://github.com/flutter/flutter/pull/125974#discussion_r1239089151. + testWidgets('Divider can be constrained', (WidgetTester tester) async { + const Color dividerColor = Colors.yellow; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + useMaterial3: true, + tabBarTheme: const TabBarTheme(dividerColor: dividerColor), + ), + home: Scaffold( + body: DefaultTabController( + length: 2, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 360), + child: ColoredBox( + color: Colors.grey[200]!, + child: const TabBar.secondary( + tabAlignment: TabAlignment.start, + isScrollable: true, + tabs: [ + Tab(text: 'Test 1'), + Tab(text: 'Test 2'), + ], + ), + ) + ), + ), + ), + ), + ), + ); + + // Test tab bar width. + expect(tester.getSize(find.byType(TabBar)).width, 360); + // Test divider width. + expect(tester.getSize(find.byType(CustomPaint).at(1)).width, 360); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests @@ -6104,45 +6488,11 @@ void main() { ); }); - testWidgets('Material3 - TabBar inherits the dividerColor of TabBarTheme', (WidgetTester tester) async { - const Color dividerColor = Colors.yellow; - - await tester.pumpWidget( - MaterialApp( - theme: ThemeData( - useMaterial3: true, - tabBarTheme: const TabBarTheme(dividerColor: dividerColor), - ), - home: Scaffold( - appBar: AppBar( - bottom: TabBar( - controller: TabController(length: 3, vsync: const TestVSync()), - tabs: const [ - Tab(text: 'Tab 1'), - Tab(text: 'Tab 2'), - Tab(text: 'Tab 3'), - ], - ), - ), - ), - ), - ); - - // Test painter's divider color. - final CustomPaint paint = tester.widget(find.byType(CustomPaint).last); - // ignore: avoid_dynamic_calls - expect((paint.painter as dynamic).dividerColor, dividerColor); - }); - - testWidgets('Default TabAlignment', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: false); + testWidgets('Material2 - Default TabAlignment', (WidgetTester tester) async { final List tabs = ['A', 'B']; // Test default TabAlignment when isScrollable is false. - await tester.pumpWidget(MaterialApp( - theme: theme, - home: buildFrame(tabs: tabs, value: 'B'), - )); + await tester.pumpWidget(buildFrame(tabs: tabs, value: 'B', useMaterial3: false)); final Rect tabBar = tester.getRect(find.byType(TabBar)); Rect tabOneRect = tester.getRect(find.byType(Tab).first); @@ -6155,9 +6505,11 @@ void main() { expect(tabTwoRect.right, equals(tabTwoRight)); // Test default TabAlignment when isScrollable is true. - await tester.pumpWidget(MaterialApp( - theme: theme, - home: buildFrame(tabs: tabs, value: 'B', isScrollable: true), + await tester.pumpWidget(buildFrame( + tabs: tabs, + value: 'B', + isScrollable: true, + useMaterial3: false, )); tabOneRect = tester.getRect(find.byType(Tab).first); @@ -6261,6 +6613,106 @@ void main() { ), ); }); + + testWidgets('Material2 - TabBar with padding isScrollable: true', (WidgetTester tester) async { + const double indicatorWeight = 2.0; // default indicator weight + const EdgeInsets padding = EdgeInsets.only(left: 3.0, top: 7.0, right: 5.0, bottom: 3.0); + + final List tabs = [ + SizedBox(key: UniqueKey(), width: 130.0, height: 30.0), + SizedBox(key: UniqueKey(), width: 140.0, height: 40.0), + SizedBox(key: UniqueKey(), width: 150.0, height: 50.0), + ]; + + final TabController controller = TabController( + vsync: const TestVSync(), + length: tabs.length, + ); + + await tester.pumpWidget( + boilerplate( + child: Container( + alignment: Alignment.topLeft, + child: TabBar( + padding: padding, + labelPadding: EdgeInsets.zero, + isScrollable: true, + controller: controller, + tabs: tabs, + ), + ), + useMaterial3: false, + ), + ); + + final RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + final double tabBarHeight = 50.0 + indicatorWeight + padding.top + padding.bottom; // 50 = max tab height + expect(tabBarBox.size.height, tabBarHeight); + + // Tab0 width = 130, height = 30 + double tabLeft = padding.left; + double tabRight = tabLeft + 130.0; + double tabTop = (tabBarHeight - indicatorWeight + (padding.top - padding.bottom) - 30.0) / 2.0; + double tabBottom = tabTop + 30.0; + Rect tabRect = Rect.fromLTRB(tabLeft, tabTop, tabRight, tabBottom); + expect(tester.getRect(find.byKey(tabs[0].key!)), tabRect); + + // Tab1 width = 140, height = 40 + tabLeft = tabRight; + tabRight = tabLeft + 140.0; + tabTop = (tabBarHeight - indicatorWeight + (padding.top - padding.bottom) - 40.0) / 2.0; + tabBottom = tabTop + 40.0; + tabRect = Rect.fromLTRB(tabLeft, tabTop, tabRight, tabBottom); + expect(tester.getRect(find.byKey(tabs[1].key!)), tabRect); + + // Tab2 width = 150, height = 50 + tabLeft = tabRight; + tabRight = tabLeft + 150.0; + tabTop = (tabBarHeight - indicatorWeight + (padding.top - padding.bottom) - 50.0) / 2.0; + tabBottom = tabTop + 50.0; + tabRect = Rect.fromLTRB(tabLeft, tabTop, tabRight, tabBottom); + expect(tester.getRect(find.byKey(tabs[2].key!)), tabRect); + + tabRight += padding.right; + expect(tabBarBox.size.width, tabRight); + }); + + testWidgets('Material2 - TabAlignment updates tabs alignment (non-scrollable TabBar)', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); + final List tabs = ['A', 'B']; + + // Test TabAlignment.fill (default) when isScrollable is false. + await tester.pumpWidget(MaterialApp( + theme: theme, + home: buildFrame(tabs: tabs, value: 'B'), + )); + + final Rect tabBar = tester.getRect(find.byType(TabBar)); + Rect tabOneRect = tester.getRect(find.byType(Tab).first); + Rect tabTwoRect = tester.getRect(find.byType(Tab).last); + + // By default tabs should fill the width of the TabBar. + double tabOneLeft = ((tabBar.width / 2) - tabOneRect.width) / 2; + expect(tabOneRect.left, equals(tabOneLeft)); + double tabTwoRight = tabBar.width - ((tabBar.width / 2) - tabTwoRect.width) / 2; + expect(tabTwoRect.right, equals(tabTwoRight)); + + // Test TabAlignment.center when isScrollable is false. + await tester.pumpWidget(MaterialApp( + theme: theme, + home: buildFrame(tabs: tabs, value: 'B', tabAlignment: TabAlignment.center), + )); + await tester.pumpAndSettle(); + + tabOneRect = tester.getRect(find.byType(Tab).first); + tabTwoRect = tester.getRect(find.byType(Tab).last); + + // Tabs should not fill the width of the TabBar. + tabOneLeft = kTabLabelPadding.left; + expect(tabOneRect.left, equals(tabOneLeft)); + tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; + expect(tabTwoRect.right, equals(tabTwoRight)); + }); }); } From c51aa3d2de8d599f45031ec1bb40ecb60699ae32 Mon Sep 17 00:00:00 2001 From: LiangXiang Shen Date: Wed, 2 Aug 2023 11:42:06 +0800 Subject: [PATCH 0489/1547] Update `ThemeData`'s factory method documents (#123984) Catch up document. As Material 3 actually use a purple theme. https://github.com/flutter/flutter/blob/d8cbaf62615497fdb1e51167d0eb306a2d7b7bcf/packages/flutter/lib/src/material/theme_data.dart#L2777-L2856 --- packages/flutter/lib/src/material/theme_data.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index fdb5d5c98d1ff..d93ae531f9cad 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -850,7 +850,7 @@ class ThemeData with Diagnosticable { ); } - /// A default light blue theme. + /// A default light theme. /// /// This theme does not contain text geometry. Instead, it is expected that /// this theme is localized using text geometry using [ThemeData.localize]. @@ -859,7 +859,7 @@ class ThemeData with Diagnosticable { useMaterial3: useMaterial3, ); - /// A default dark theme with a teal secondary [ColorScheme] color. + /// A default dark theme. /// /// This theme does not contain text geometry. Instead, it is expected that /// this theme is localized using text geometry using [ThemeData.localize]. From 9c184d475b232033e5b7ec2d28effe62c49ca254 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 06:57:35 +0000 Subject: [PATCH 0490/1547] Bump codecov/codecov-action from 3.1.3 to 3.1.4 (#126885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3.1.3 to 3.1.4.
Release notes

Sourced from codecov/codecov-action's releases.

3.1.4

What's Changed

New Contributors

Full Changelog: https://github.com/codecov/codecov-action/compare/v3.1.3...v3.1.4

Changelog

Sourced from codecov/codecov-action's changelog.

3.1.4

Fixes

  • #967 Fix typo in README.md
  • #971 fix: add back in working dir
  • #969 fix: CLI option names for uploader

Dependencies

  • #970 build(deps-dev): bump @​types/node from 18.15.12 to 18.16.3
  • #979 build(deps-dev): bump @​types/node from 20.1.0 to 20.1.2
  • #981 build(deps-dev): bump @​types/node from 20.1.2 to 20.1.4

3.1.3

Fixes

  • #960 fix: allow for aarch64 build

Dependencies

  • #957 build(deps-dev): bump jest-junit from 15.0.0 to 16.0.0
  • #958 build(deps): bump openpgp from 5.7.0 to 5.8.0
  • #959 build(deps-dev): bump @​types/node from 18.15.10 to 18.15.12

3.1.2

Fixes

  • #718 Update README.md
  • #851 Remove unsupported path_to_write_report argument
  • #898 codeql-analysis.yml
  • #901 Update README to contain correct information - inputs and negate feature
  • #955 fix: add in all the extra arguments for uploader

Dependencies

  • #819 build(deps): bump openpgp from 5.4.0 to 5.5.0
  • #835 build(deps): bump node-fetch from 3.2.4 to 3.2.10
  • #840 build(deps): bump ossf/scorecard-action from 1.1.1 to 2.0.4
  • #841 build(deps): bump @​actions/core from 1.9.1 to 1.10.0
  • #843 build(deps): bump @​actions/github from 5.0.3 to 5.1.1
  • #869 build(deps): bump node-fetch from 3.2.10 to 3.3.0
  • #872 build(deps-dev): bump jest-junit from 13.2.0 to 15.0.0
  • #879 build(deps): bump decode-uri-component from 0.2.0 to 0.2.2
  • #889 build(deps): bump ossf/scorecard-action from 1.1.1 to 2.1.2
  • #895 build(deps): bump json5 from 2.2.1 to 2.2.3
  • #896 build(deps): bump actions/upload-artifact from 3.1.0 to 3.1.2
  • #900 build(deps-dev): bump @​vercel/ncc from 0.34.0 to 0.36.1
  • #905 build(deps-dev): bump typescript from 4.7.4 to 4.9.5
  • #911 build(deps-dev): bump @​types/node from 16.11.40 to 18.13.0
  • #922 build(deps-dev): bump @​types/node from 18.13.0 to 18.14.0
  • #924 build(deps): bump openpgp from 5.5.0 to 5.7.0
  • #927 build(deps-dev): bump @​types/node from 18.14.0 to 18.14.2
  • #933 build(deps-dev): bump @​types/node from 18.14.2 to 18.14.6
  • #937 build(deps-dev): bump @​types/node from 18.14.6 to 18.15.0
  • #938 build(deps): bump node-fetch from 3.3.0 to 3.3.1
  • #945 build(deps-dev): bump @​types/node from 18.15.0 to 18.15.5

... (truncated)

Commits
  • eaaf4be release: 3.1.4 (#983)
  • c2ab9ab build(deps-dev): bump @​types/node from 20.1.2 to 20.1.4 (#981)
  • 49c20db build(deps-dev): bump @​types/node from 20.1.0 to 20.1.2 (#979)
  • cf8e3e4 build(deps-dev): bump @​types/node from 18.16.3 to 20.1.0 (#975)
  • 1c34415 fix: CLI option names for uploader (#969)
  • b4dfea7 fix: add back in working dir (#971)
  • 5bf2504 Fix typo in README.md (#967)
  • 1dd0ce3 build(deps-dev): bump @​types/node from 18.15.12 to 18.16.3 (#970)
  • See full diff in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codecov/codecov-action&package-manager=github_actions&previous-version=3.1.3&new-version=3.1.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. --- .github/workflows/coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 3d5816c9aef03..ff34165310d01 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,7 +23,7 @@ jobs: - name: ./bin/flutter test --coverage run: pushd packages/flutter;../../bin/flutter test --coverage -j 1;popd - name: upload coverage - uses: codecov/codecov-action@894ff025c7b54547a9a2a1e9f228beae737ad3c2 + uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d with: files: packages/flutter/coverage/lcov.info verbose: true From e8ebbfa2a804f3ed9820fb1059a094f922e48743 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 07:29:08 +0000 Subject: [PATCH 0491/1547] Bump dessant/lock-threads from 4.0.0 to 4.0.1 (#128741) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 4.0.0 to 4.0.1.
Release notes

Sourced from dessant/lock-threads's releases.

v4.0.1

Learn more about this release from the changelog.

Changelog

Sourced from dessant/lock-threads's changelog.

Changelog

All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

4.0.1 (2023-06-12)

Bug Fixes

  • retry and throttle GitHub API requests (1618e91), closes #35

4.0.0 (2022-12-04)

⚠ BREAKING CHANGES

  • the action now requires Node.js 16

Bug Fixes

3.0.0 (2021-09-27)

⚠ BREAKING CHANGES

  • input parameter names have changed

    Rename the following input parameters when upgrading from v2 to v3:

    • issue-lock-inactive-days --> issue-inactive-days
    • issue-exclude-created-before --> exclude-issue-created-before
    • issue-exclude-labels --> exclude-any-issue-labels
    • issue-lock-labels --> add-issue-labels
    • issue-lock-comment --> issue-comment
    • pr-lock-inactive-days --> pr-inactive-days
    • pr-exclude-created-before --> exclude-pr-created-before
    • pr-exclude-labels --> exclude-any-pr-labels
    • pr-lock-labels --> add-pr-labels
    • pr-lock-comment --> pr-comment

Features

  • add new filtering and labeling options, update input parameter names (26fd836)
  • allow manual triggering (a0c7da3)

2.1.2 (2021-08-17)

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=dessant/lock-threads&package-manager=github_actions&previous-version=4.0.0&new-version=4.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. --- .github/workflows/lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml index a587024ef761f..072d4d2de5812 100644 --- a/.github/workflows/lock.yaml +++ b/.github/workflows/lock.yaml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.repository == 'flutter/flutter' }} steps: - - uses: dessant/lock-threads@c1b35aecc5cdb1a34539d14196df55838bb2f836 + - uses: dessant/lock-threads@be8aa5be94131386884a6da4189effda9b14aa21 with: process-only: 'issues' github-token: ${{ github.token }} From dc4ab0f5dfa5acda859d6791d436675b87d73b47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 07:40:14 +0000 Subject: [PATCH 0492/1547] Bump google/mirror-branch-action from 1.0 to 2.0 (#126600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [google/mirror-branch-action](https://github.com/google/mirror-branch-action) from 1.0 to 2.0.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google/mirror-branch-action&package-manager=github_actions&previous-version=1.0&new-version=2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. --- .github/workflows/mirror.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index 1f6b0d0f57539..a568c78265469 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Mirror action step id: mirror - uses: google/mirror-branch-action@c6b07e441a7ffc5ae15860c1d0a8107a3a151db8 + uses: google/mirror-branch-action@30c52ee21f5d3bd7fb28b95501c11aae7f17eebb with: github-token: ${{ secrets.FLUTTERMIRRORINGBOT_TOKEN }} source: 'master' From f80ff55a7675e86147fefcd2ce54e176b584078b Mon Sep 17 00:00:00 2001 From: Daniel Chevalier Date: Wed, 2 Aug 2023 09:23:57 -0400 Subject: [PATCH 0493/1547] Fix for endless recursion for getLayoutExplorerNode on a Tooltip (#131486) ![](https://media.giphy.com/media/l0ExdBwqD6YkeEhQ4/giphy-downsized.gif) Fixes https://github.com/flutter/devtools/issues/5946 While preparing DevTools for the Multi View changes, I noticed that inspecting a Tooltip causes an stack overflow. This PR addresses that issue by fixing the scope of the subtreeDepth variable and adding some other idiomatic fixes --- .../lib/src/widgets/widget_inspector.dart | 23 ++++++--- .../test/widgets/widget_inspector_test.dart | 47 +++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 35cf0baa80d57..7c56bed8ec91f 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2109,24 +2109,35 @@ mixin WidgetInspectorService { summaryTree: true, subtreeDepth: subtreeDepth, service: this, - addAdditionalPropertiesCallback: (DiagnosticsNode node, InspectorSerializationDelegate delegate) { + addAdditionalPropertiesCallback: + (DiagnosticsNode node, InspectorSerializationDelegate delegate) { final Object? value = node.value; - final RenderObject? renderObject = value is Element ? value.renderObject : null; + final RenderObject? renderObject = + value is Element ? value.renderObject : null; if (renderObject == null) { return const {}; } - final DiagnosticsSerializationDelegate renderObjectSerializationDelegate = delegate.copyWith( + final DiagnosticsSerializationDelegate + renderObjectSerializationDelegate = delegate.copyWith( subtreeDepth: 0, includeProperties: true, expandPropertyValues: false, ); final Map additionalJson = { - 'renderObject': renderObject.toDiagnosticsNode().toJsonMap(renderObjectSerializationDelegate), + // Only include renderObject properties separately if this value is not already the renderObject. + // Only include if we are expanding property values to mitigate the risk of infinite loops if + // RenderObjects have properties that are Element objects. + if (value is! RenderObject && delegate.expandPropertyValues) + 'renderObject': renderObject + .toDiagnosticsNode() + .toJsonMap(renderObjectSerializationDelegate), }; final RenderObject? renderParent = renderObject.parent; - if (renderParent is RenderObject && subtreeDepth > 0) { + if (renderParent != null && + delegate.subtreeDepth > 0 && + delegate.expandPropertyValues) { final Object? parentCreator = renderParent.debugCreator; if (parentCreator is DebugCreator) { additionalJson['parentRenderElement'] = @@ -2147,7 +2158,7 @@ mixin WidgetInspectorService { if (!renderObject.debugNeedsLayout) { // ignore: invalid_use_of_protected_member final Constraints constraints = renderObject.constraints; - final MapconstraintsProperty = { + final Map constraintsProperty = { 'type': constraints.runtimeType.toString(), 'description': constraints.toString(), }; diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 125f3b83afce0..29d6b33b36635 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -4771,6 +4771,53 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { } expect(error, isNull); }); + + testWidgets( + 'ext.flutter.inspector.getLayoutExplorerNode, on a ToolTip, does not throw StackOverflowError', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/devtools/issues/5946 + const Widget widget = MaterialApp( + home: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Row( + children: [ + Flexible( + child: ColoredBox( + color: Colors.green, + child: Tooltip( + message: 'a', + child: ElevatedButton( + onPressed: null, + child: Text('a'), + ), + ), + ), + ), + ], + ), + ), + ), + ); + await tester.pumpWidget(widget); + + final Element elevatedButton = + tester.element(find.byType(ElevatedButton).first); + service.setSelection(elevatedButton, group); + + final String id = service.toId(elevatedButton, group)!; + + Object? error; + try { + await service.testExtension( + WidgetInspectorServiceExtensions.getLayoutExplorerNode.name, + {'id': id, 'groupName': group, 'subtreeDepth': '1'}, + ); + } catch (e) { + error = e; + } + expect(error, isNull); + }); }); test('ext.flutter.inspector.structuredErrors', () async { From 6cf50ef9427ef1ea1d5bc9090d8dd7efc359c52c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 16:12:31 +0000 Subject: [PATCH 0494/1547] Bump ubuntu from `f8f6584` to `c9820a4` in /dev/ci/docker_linux (#130292) Bumps ubuntu from `f8f6584` to `c9820a4`. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ubuntu&package-manager=docker&previous-version=focal&new-version=focal)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- dev/ci/docker_linux/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/ci/docker_linux/Dockerfile b/dev/ci/docker_linux/Dockerfile index db58a1a3a6261..9cba6dcdbf1de 100644 --- a/dev/ci/docker_linux/Dockerfile +++ b/dev/ci/docker_linux/Dockerfile @@ -12,7 +12,7 @@ # Last manual update 2021-09-24 (changing this comment will re-build image) -FROM ubuntu:focal@sha256:f8f658407c35733471596f25fdb4ed748b80e545ab57e84efbdb1dbbb01bd70e +FROM ubuntu:focal@sha256:c9820a44b950956a790c354700c1166a7ec648bc0d215fa438d3a339812f1d01 MAINTAINER Flutter Developers ENV TZ=America/Los_Angeles From 4b176a716c4404593b37f182bd9d83e1d0356dc5 Mon Sep 17 00:00:00 2001 From: fzyzcjy <5236035+fzyzcjy@users.noreply.github.com> Date: Thu, 3 Aug 2023 00:21:54 +0800 Subject: [PATCH 0495/1547] Tiny remove outdated comments (#130387) I get confused when reading this comment. It seems that this code never calls `AnimationController.fling` (but only things like `animateTo`). Therefore, I do not think discussing the duration of `AnimationController.fling` is helpful - maybe it is just an outdated comment? --- packages/flutter/lib/src/cupertino/route.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index 1c3ad869f8c9c..f922eaf33e946 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -724,8 +724,6 @@ class _CupertinoBackGestureController { /// [fractionalVelocity] as a fraction of screen width per second. void dragEnd(double velocity) { // Fling in the appropriate direction. - // AnimationController.fling is guaranteed to - // take at least one frame. // // This curve has been determined through rigorously eyeballing native iOS // animations. From 947367aaa2fbcb8e8324c54764a31b4ed5a7c80f Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Wed, 2 Aug 2023 09:40:07 -0700 Subject: [PATCH 0496/1547] Added standard deviation to rasterizer results. (#131781) This calculation is important if you want to calculate the probability that one thing is better than another. --- dev/devicelab/lib/tasks/gallery.dart | 1 + .../lib/src/driver/timeline_summary.dart | 18 ++++++++++++++++++ .../src/real_tests/timeline_summary_test.dart | 2 ++ 3 files changed, 21 insertions(+) diff --git a/dev/devicelab/lib/tasks/gallery.dart b/dev/devicelab/lib/tasks/gallery.dart index 887d960d3f907..f9ae9a058c481 100644 --- a/dev/devicelab/lib/tasks/gallery.dart +++ b/dev/devicelab/lib/tasks/gallery.dart @@ -189,6 +189,7 @@ class GalleryTransitionTest { '90th_percentile_frame_build_time_millis', '99th_percentile_frame_build_time_millis', 'average_frame_rasterizer_time_millis', + 'stddev_frame_rasterizer_time_millis', 'worst_frame_rasterizer_time_millis', '90th_percentile_frame_rasterizer_time_millis', '99th_percentile_frame_rasterizer_time_millis', diff --git a/packages/flutter_driver/lib/src/driver/timeline_summary.dart b/packages/flutter_driver/lib/src/driver/timeline_summary.dart index cd7451c2998cc..ac36850f45824 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -82,6 +82,20 @@ class TimelineSummary { return _averageInMillis(_extractGpuRasterizerDrawDurations()); } + /// Standard deviation amount of time spent per frame in the engine rasterizer. + /// + /// Throws a [StateError] if this summary contains no timeline events. + double computeStandardDeviationFrameRasterizerTimeMillis() { + final List durations = _extractGpuRasterizerDrawDurations(); + final double average = _averageInMillis(durations); + double tally = 0.0; + for (final Duration duration in durations) { + final double time = duration.inMicroseconds.toDouble() / 1000.0; + tally += (average - time).abs(); + } + return tally / durations.length; + } + /// The longest frame rasterization time in milliseconds. /// /// Throws a [StateError] if this summary contains no timeline events. @@ -146,6 +160,9 @@ class TimelineSummary { /// * "average_frame_rasterizer_time_millis": Average amount of time spent /// per frame in the engine rasterizer. /// See [computeAverageFrameRasterizerTimeMillis]. + /// * "stddev_frame_rasterizer_time_millis": Standard deviation of the amount + /// of time spent per frame in the engine rasterizer. + /// See [computeStandardDeviationFrameRasterizerTimeMillis]. /// * "90th_percentile_frame_rasterizer_time_millis" and /// "99th_percentile_frame_rasterizer_time_millis": The 90/99-th percentile /// frame rasterization time in milliseconds. @@ -240,6 +257,7 @@ class TimelineSummary { 'worst_frame_build_time_millis': computeWorstFrameBuildTimeMillis(), 'missed_frame_build_budget_count': computeMissedFrameBuildBudgetCount(), 'average_frame_rasterizer_time_millis': computeAverageFrameRasterizerTimeMillis(), + 'stddev_frame_rasterizer_time_millis': computeStandardDeviationFrameRasterizerTimeMillis(), '90th_percentile_frame_rasterizer_time_millis': computePercentileFrameRasterizerTimeMillis(90.0), '99th_percentile_frame_rasterizer_time_millis': computePercentileFrameRasterizerTimeMillis(99.0), 'worst_frame_rasterizer_time_millis': computeWorstFrameRasterizerTimeMillis(), diff --git a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart index b94249191e4e4..430df503df9c9 100644 --- a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart +++ b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart @@ -463,6 +463,7 @@ void main() { 'worst_frame_build_time_millis': 19.0, 'missed_frame_build_budget_count': 2, 'average_frame_rasterizer_time_millis': 16.0, + 'stddev_frame_rasterizer_time_millis': 4.0, '90th_percentile_frame_rasterizer_time_millis': 20.0, '99th_percentile_frame_rasterizer_time_millis': 20.0, 'worst_frame_rasterizer_time_millis': 20.0, @@ -578,6 +579,7 @@ void main() { '99th_percentile_frame_build_time_millis': 19.0, 'missed_frame_build_budget_count': 2, 'average_frame_rasterizer_time_millis': 16.0, + 'stddev_frame_rasterizer_time_millis': 4.0, '90th_percentile_frame_rasterizer_time_millis': 20.0, '99th_percentile_frame_rasterizer_time_millis': 20.0, 'worst_frame_rasterizer_time_millis': 20.0, From f9e4567ff6557ad48fb60b072c251b2f764ce011 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 2 Aug 2023 12:54:47 -0400 Subject: [PATCH 0497/1547] Manual roll Flutter Engine from 9dae7b708bda to d6b962d0e36d (25 revisions) (#131785) Manual roll requested by jacksongardner@google.com https://github.com/flutter/engine/compare/9dae7b708bda...d6b962d0e36d 2023-08-02 zanderso@users.noreply.github.com Revert "[Impeller] Support for rendering Android Platform Views into a HardwareBuffer backed texture." (flutter/engine#44262) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from c6577d328585 to 6009cc6d7d80 (2 revisions) (flutter/engine#44264) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from 11cef17b53ac to d61a50c155bd (1 revision) (flutter/engine#44261) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 1c0bba7c1053 to c6577d328585 (2 revisions) (flutter/engine#44260) 2023-08-02 skia-flutter-autoroll@skia.org Roll Dart SDK from 8ff03ebf7eaa to afbaf4216fc8 (1 revision) (flutter/engine#44259) 2023-08-02 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 3JSF6hXLRdAK1wUN1... to Hx7ap5qcoqRIknnnG... (flutter/engine#44258) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from a21631c02e45 to 11cef17b53ac (1 revision) (flutter/engine#44256) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 6807d8b8a9d3 to 1c0bba7c1053 (1 revision) (flutter/engine#44255) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from 5d4b3645d0dc to a21631c02e45 (1 revision) (flutter/engine#44252) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 6087a5224c6f to 6807d8b8a9d3 (2 revisions) (flutter/engine#44250) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 6cb888889ad8 to 6087a5224c6f (1 revision) (flutter/engine#44249) 2023-08-02 jonahwilliams@google.com [Impeller] Give a fixed timeout for acquireNextImageKHR. (flutter/engine#44241) 2023-08-02 skia-flutter-autoroll@skia.org Roll Dart SDK from 7c03426705da to 8ff03ebf7eaa (2 revisions) (flutter/engine#44243) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 4deae93198f9 to 6cb888889ad8 (1 revision) (flutter/engine#44240) 2023-08-01 hterkelsen@users.noreply.github.com [canvaskit] Enable CanvasKit to compute tight SkPicture bounds (flutter/engine#43361) 2023-08-01 skia-flutter-autoroll@skia.org Roll Dart SDK from 197fc0d7fea2 to 7c03426705da (2 revisions) (flutter/engine#44237) 2023-08-01 john@johnmccutchan.com [Impeller] Support for rendering Android Platform Views into a HardwareBuffer backed texture. (flutter/engine#44087) 2023-08-01 yjbanov@google.com [web:a11y] add platform view role (flutter/engine#44188) 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from 18cf818e044f to 4deae93198f9 (1 revision) (flutter/engine#44236) 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from 58c031441cbb to 18cf818e044f (6 revisions) (flutter/engine#44234) 2023-08-01 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from g0dgOL2IlZQJCK4El... to 3JSF6hXLRdAK1wUN1... (flutter/engine#44233) 2023-08-01 skia-flutter-autoroll@skia.org Roll ANGLE from b53d99d87e6a to 5d4b3645d0dc (1 revision) (flutter/engine#44231) 2023-08-01 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from lwCo6le6r0X-Srvx3... to KPSWBhOvG6piddBQG... (flutter/engine#44230) 2023-08-01 skia-flutter-autoroll@skia.org Roll Skia from d53f7b880651 to 58c031441cbb (2 revisions) (flutter/engine#44229) 2023-08-01 58529443+srujzs@users.noreply.github.com Remove extends JSTypedArray from JSUint8Array1 (flutter/engine#44175) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from lwCo6le6r0X- to KPSWBhOvG6pi fuchsia/sdk/core/mac-amd64 from g0dgOL2IlZQJ to Hx7ap5qcoqRI If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 333ffeb265989..e8a8031f027dc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9dae7b708bdabf57d8ce4025f308707ff080401f +d6b962d0e36d7b99a24800e42e5622a1ecec78b5 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 356f0535291d1..e0c529c8fd139 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -lwCo6le6r0X-Srvx31N-hp4SodcF_-U6Q5J9SpLc9zoC +KPSWBhOvG6piddBQGjbnutOw4JoLbHNwd9UmvtJ2IxwC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index d485d5338e2ab..660bf09f4f2e4 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -g0dgOL2IlZQJCK4ElZLeLCjBZgNGtbUXHXCRguBgBREC +Hx7ap5qcoqRIknnnGW8qLcMHWOj04Yw6urras7NxW_0C From a120342922924f9610a2fbf86a7e2f432e3ad1eb Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 2 Aug 2023 12:00:48 -0500 Subject: [PATCH 0498/1547] Fix flex methods for min and max column widths (#131724) Fixes https://github.com/flutter/flutter/issues/131467 An error in the flex methods of min and max column width would produce different results based on the position of the widths that were provided: `MaxColumnWidth(a, b) != MaxColumnWidth(b, a)` This fixes that. --- packages/flutter/lib/src/rendering/table.dart | 18 +++++----- .../flutter/test/rendering/table_test.dart | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/rendering/table.dart b/packages/flutter/lib/src/rendering/table.dart index 2208664399fc3..2cc86091ce050 100644 --- a/packages/flutter/lib/src/rendering/table.dart +++ b/packages/flutter/lib/src/rendering/table.dart @@ -263,12 +263,11 @@ class MaxColumnWidth extends TableColumnWidth { @override double? flex(Iterable cells) { final double? aFlex = a.flex(cells); - if (aFlex == null) { - return b.flex(cells); - } final double? bFlex = b.flex(cells); - if (bFlex == null) { - return null; + if (aFlex == null) { + return bFlex; + } else if (bFlex == null) { + return aFlex; } return math.max(aFlex, bFlex); } @@ -316,12 +315,11 @@ class MinColumnWidth extends TableColumnWidth { @override double? flex(Iterable cells) { final double? aFlex = a.flex(cells); - if (aFlex == null) { - return b.flex(cells); - } final double? bFlex = b.flex(cells); - if (bFlex == null) { - return null; + if (aFlex == null) { + return bFlex; + } else if (bFlex == null) { + return aFlex; } return math.min(aFlex, bFlex); } diff --git a/packages/flutter/test/rendering/table_test.dart b/packages/flutter/test/rendering/table_test.dart index 12ff18b0352a0..78386e7c26084 100644 --- a/packages/flutter/test/rendering/table_test.dart +++ b/packages/flutter/test/rendering/table_test.dart @@ -277,4 +277,37 @@ void main() { ); }); + test('MaxColumnWidth.flex returns the correct result', () { + MaxColumnWidth columnWidth = const MaxColumnWidth( + FixedColumnWidth(100), // returns null from .flex + FlexColumnWidth(), // returns 1 from .flex + ); + final double? flexValue = columnWidth.flex([]); + expect(flexValue, 1.0); + + // Swap a and b, check for same result. + columnWidth = const MaxColumnWidth( + FlexColumnWidth(), // returns 1 from .flex + FixedColumnWidth(100), // returns null from .flex + ); + // Same result. + expect(columnWidth.flex([]), flexValue); + }); + + test('MinColumnWidth.flex returns the correct result', () { + MinColumnWidth columnWidth = const MinColumnWidth( + FixedColumnWidth(100), // returns null from .flex + FlexColumnWidth(), // returns 1 from .flex + ); + final double? flexValue = columnWidth.flex([]); + expect(flexValue, 1.0); + + // Swap a and b, check for same result. + columnWidth = const MinColumnWidth( + FlexColumnWidth(), // returns 1 from .flex + FixedColumnWidth(100), // returns null from .flex + ); + // Same result. + expect(columnWidth.flex([]), flexValue); + }); } From aff8ef13d428395725ce8f836ca771b8bf2d87db Mon Sep 17 00:00:00 2001 From: Elias Yishak <42216813+eliasyishak@users.noreply.github.com> Date: Wed, 2 Aug 2023 13:26:44 -0400 Subject: [PATCH 0499/1547] Update .ci.yaml to add new shard to prevent timeouts (#131712) Fixes: - https://github.com/flutter/flutter/issues/131327 It was observed that the tests would hit their 30 minute timeout so this PR adds another shard to reduce how many tests are run per shard to reduce test run time --- .ci.yaml | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 84972a0d89810..bd92cd051d906 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4145,7 +4145,8 @@ targets: - bin/** - .ci.yaml - - name: Windows build_tests_1_4 + - name: Windows build_tests_1_5 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4159,11 +4160,12 @@ targets: {"dependency": "vs_build", "version": "version:vs2019"} ] shard: build_tests - subshard: "1_4" + subshard: "1_5" tags: > ["framework", "hostonly", "shard", "windows"] - - name: Windows build_tests_2_4 + - name: Windows build_tests_2_5 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4177,11 +4179,12 @@ targets: {"dependency": "vs_build", "version": "version:vs2019"} ] shard: build_tests - subshard: "2_4" + subshard: "2_5" tags: > ["framework", "hostonly", "shard", "windows"] - - name: Windows build_tests_3_4 + - name: Windows build_tests_3_5 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4195,11 +4198,12 @@ targets: {"dependency": "vs_build", "version": "version:vs2019"} ] shard: build_tests - subshard: "3_4" + subshard: "3_5" tags: > ["framework", "hostonly", "shard", "windows"] - - name: Windows build_tests_4_4 + - name: Windows build_tests_4_5 + bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4213,7 +4217,26 @@ targets: {"dependency": "vs_build", "version": "version:vs2019"} ] shard: build_tests - subshard: "4_4" + subshard: "4_5" + tags: > + ["framework", "hostonly", "shard", "windows"] + + - name: Windows build_tests_5_5 + bringup: true + recipe: flutter/flutter_drone + timeout: 60 + properties: + add_recipes_cq: "true" + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "open_jdk", "version": "version:17"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "vs_build", "version": "version:vs2019"} + ] + shard: build_tests + subshard: "5_5" tags: > ["framework", "hostonly", "shard", "windows"] From b3f99ffe610a48cea02289608bbabc834719ab27 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Wed, 2 Aug 2023 10:29:50 -0700 Subject: [PATCH 0500/1547] Fix reentrancy with WidgetBindingObserver callbacks (#131774) Part of https://github.com/flutter/flutter/issues/131678 Fixes up callsites for WidgetsBindingObserver related callbacks. --- packages/flutter/lib/src/widgets/binding.dart | 21 ++-- .../flutter/test/widgets/binding_test.dart | 108 ++++++++++++++++++ 2 files changed, 120 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 14235ac8a8660..7c8bf3b8df209 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -623,7 +623,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override Future handleRequestAppExit() async { bool didCancel = false; - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { if ((await observer.didRequestAppExit()) == AppExitResponse.cancel) { didCancel = true; // Don't early return. For the case where someone is just using the @@ -637,7 +637,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override void handleMetricsChanged() { super.handleMetricsChanged(); - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangeMetrics(); } } @@ -645,7 +645,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override void handleTextScaleFactorChanged() { super.handleTextScaleFactorChanged(); - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangeTextScaleFactor(); } } @@ -653,7 +653,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override void handlePlatformBrightnessChanged() { super.handlePlatformBrightnessChanged(); - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangePlatformBrightness(); } } @@ -661,7 +661,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override void handleAccessibilityFeaturesChanged() { super.handleAccessibilityFeaturesChanged(); - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangeAccessibilityFeatures(); } } @@ -673,6 +673,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// See [dart:ui.PlatformDispatcher.onLocaleChanged]. @protected @mustCallSuper + @visibleForTesting void handleLocaleChanged() { dispatchLocalesChanged(platformDispatcher.locales); } @@ -686,7 +687,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @protected @mustCallSuper void dispatchLocalesChanged(List? locales) { - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangeLocales(locales); } } @@ -700,7 +701,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @protected @mustCallSuper void dispatchAccessibilityFeaturesChanged() { - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangeAccessibilityFeatures(); } } @@ -720,6 +721,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. @protected + @visibleForTesting Future handlePopRoute() async { for (final WidgetsBindingObserver observer in List.of(_observers)) { if (await observer.didPopRoute()) { @@ -741,6 +743,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// [SystemChannels.navigation]. @protected @mustCallSuper + @visibleForTesting Future handlePushRoute(String route) async { final RouteInformation routeInformation = RouteInformation(uri: Uri.parse(route)); for (final WidgetsBindingObserver observer in List.of(_observers)) { @@ -777,7 +780,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override void handleAppLifecycleStateChanged(AppLifecycleState state) { super.handleAppLifecycleStateChanged(state); - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didChangeAppLifecycleState(state); } } @@ -785,7 +788,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @override void handleMemoryPressure() { super.handleMemoryPressure(); - for (final WidgetsBindingObserver observer in _observers) { + for (final WidgetsBindingObserver observer in List.of(_observers)) { observer.didHaveMemoryPressure(); } } diff --git a/packages/flutter/test/widgets/binding_test.dart b/packages/flutter/test/widgets/binding_test.dart index 928fc1fa948c2..b42df5fe09430 100644 --- a/packages/flutter/test/widgets/binding_test.dart +++ b/packages/flutter/test/widgets/binding_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui'; + import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -45,6 +47,94 @@ class PushRouteInformationObserver with WidgetsBindingObserver { } } +// Implements to make sure all methods get coverage. +class RentrantObserver implements WidgetsBindingObserver { + RentrantObserver() { + WidgetsBinding.instance.addObserver(this); + } + + bool active = true; + + int removeSelf() { + active = false; + int count = 0; + while (WidgetsBinding.instance.removeObserver(this)) { + count += 1; + } + return count; + } + + @override + void didChangeAccessibilityFeatures() { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangeLocales(List? locales) { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangeMetrics() { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangePlatformBrightness() { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didChangeTextScaleFactor() { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + void didHaveMemoryPressure() { + assert(active); + WidgetsBinding.instance.addObserver(this); + } + + @override + Future didPopRoute() { + assert(active); + WidgetsBinding.instance.addObserver(this); + return Future.value(true); + } + + @override + Future didPushRoute(String route) { + assert(active); + WidgetsBinding.instance.addObserver(this); + return Future.value(true); + } + + @override + Future didPushRouteInformation(RouteInformation routeInformation) { + assert(active); + WidgetsBinding.instance.addObserver(this); + return Future.value(true); + } + + @override + Future didRequestAppExit() { + assert(active); + WidgetsBinding.instance.addObserver(this); + return Future.value(AppExitResponse.exit); + } +} + void main() { Future setAppLifeCycleState(AppLifecycleState state) async { final ByteData? message = @@ -53,6 +143,23 @@ void main() { .handlePlatformMessage('flutter/lifecycle', message, (_) { }); } + testWidgets('Rentrant observer callbacks do not result in exceptions', (WidgetTester tester) async { + final RentrantObserver observer = RentrantObserver(); + WidgetsBinding.instance.handleAccessibilityFeaturesChanged(); + WidgetsBinding.instance.handleAppLifecycleStateChanged(AppLifecycleState.resumed); + WidgetsBinding.instance.handleLocaleChanged(); + WidgetsBinding.instance.handleMetricsChanged(); + WidgetsBinding.instance.handlePlatformBrightnessChanged(); + WidgetsBinding.instance.handleTextScaleFactorChanged(); + WidgetsBinding.instance.handleMemoryPressure(); + WidgetsBinding.instance.handlePopRoute(); + WidgetsBinding.instance.handlePushRoute('/'); + WidgetsBinding.instance.handleRequestAppExit(); + await tester.idle(); + expect(observer.removeSelf(), greaterThan(1)); + expect(observer.removeSelf(), 0); + }); + testWidgets('didHaveMemoryPressure callback', (WidgetTester tester) async { final MemoryPressureObserver observer = MemoryPressureObserver(); WidgetsBinding.instance.addObserver(observer); @@ -118,6 +225,7 @@ void main() { observer.accumulatedStates.clear(); await expectLater(() async => setAppLifeCycleState(AppLifecycleState.detached), throwsAssertionError); + WidgetsBinding.instance.removeObserver(observer); }); testWidgets('didPushRoute callback', (WidgetTester tester) async { From 55bb3e553802c05ef316a63050cbb6e93b8cf31d Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Wed, 2 Aug 2023 10:42:52 -0700 Subject: [PATCH 0501/1547] [flutter_tools] set terminal.singleCharMode to false after attach finishes (#131723) Fixes https://github.com/flutter/flutter/issues/131511 Similar fix to https://github.com/flutter/flutter/commit/84c8abd0f6776455e91e9c375c7d7ed8f3291e75#diff-38f3e3415d9806f22a78060fafb3206d1a006f74631fac04e7a680a64e06ccf0 --- .../lib/src/commands/attach.dart | 7 ++ .../commands.shard/hermetic/attach_test.dart | 80 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 6bd6539181917..9093a2c569071 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -502,6 +502,13 @@ known, it can be explicitly provided to attach via the command-line, e.g. for (final ForwardedPort port in ports) { await device.portForwarder!.unforward(port); } + // However we exited from the runner, ensure the terminal has line mode + // and echo mode enabled before we return the user to the shell. + try { + _terminal.singleCharMode = false; + } on StdinException { + // Do nothing, if the STDIN handle is no longer available, there is nothing actionable for us to do at this point + } } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index dd2de79fcb539..2f0d9d0f667ec 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -164,6 +164,71 @@ void main() { ), }); + testUsingContext('restores terminal to singleCharMode == false on command exit', () async { + final FakeIOSDevice device = FakeIOSDevice( + portForwarder: portForwarder, + majorSdkVersion: 12, + onGetLogReader: () { + fakeLogReader.addLine('Foo'); + fakeLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:$devicePort'); + return fakeLogReader; + }, + ); + testDeviceManager.devices = [device]; + final Completer completer = Completer(); + final StreamSubscription loggerSubscription = logger.stream.listen((String message) { + if (message == '[verbose] VM Service URL on device: http://127.0.0.1:$devicePort') { + // The "VM Service URL on device" message is output by the ProtocolDiscovery when it found the VM Service. + completer.complete(); + } + }); + final FakeHotRunner hotRunner = FakeHotRunner(); + hotRunner.onAttach = ( + Completer? connectionInfoCompleter, + Completer? appStartedCompleter, + bool allowExistingDdsInstance, + bool enableDevTools, + ) async { + appStartedCompleter?.complete(); + return 0; + }; + hotRunner.exited = false; + hotRunner.isWaitingForVmService = false; + final FakeHotRunnerFactory hotRunnerFactory = FakeHotRunnerFactory() + ..hotRunner = hotRunner; + + await createTestCommandRunner(AttachCommand( + hotRunnerFactory: hotRunnerFactory, + artifacts: artifacts, + stdio: stdio, + logger: logger, + terminal: terminal, + signals: signals, + platform: platform, + processInfo: processInfo, + fileSystem: testFileSystem, + )).run(['attach']); + await Future.wait(>[ + completer.future, + fakeLogReader.dispose(), + loggerSubscription.cancel(), + ]); + + expect(terminal.singleCharMode, isFalse); + }, overrides: { + FileSystem: () => testFileSystem, + ProcessManager: () => FakeProcessManager.any(), + Logger: () => logger, + DeviceManager: () => testDeviceManager, + MDnsVmServiceDiscovery: () => MDnsVmServiceDiscovery( + mdnsClient: FakeMDnsClient([], >{}), + preliminaryMDnsClient: FakeMDnsClient([], >{}), + logger: logger, + flutterUsage: TestUsage(), + ), + Signals: () => FakeSignals(), + }); + testUsingContext('succeeds with iOS device with mDNS', () async { final FakeIOSDevice device = FakeIOSDevice( portForwarder: portForwarder, @@ -1053,6 +1118,15 @@ class FakeHotRunner extends Fake implements HotRunner { }) { return onAttach(connectionInfoCompleter, appStartedCompleter, allowExistingDdsInstance, enableDevTools); } + + @override + bool supportsServiceProtocol = false; + + @override + bool stayResident = true; + + @override + void printHelp({required bool details}) {} } class FakeHotRunnerFactory extends Fake implements HotRunnerFactory { @@ -1479,4 +1553,10 @@ class FakeTerminal extends Fake implements AnsiTerminal { @override bool usesTerminalUi = false; + + @override + bool singleCharMode = false; + + @override + Stream get keystrokes => StreamController().stream; } From aa77d1f4cce2c29600bdc273da45343753f52155 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 2 Aug 2023 14:14:21 -0400 Subject: [PATCH 0502/1547] Roll Flutter Engine from d6b962d0e36d to 9304c0074d29 (4 revisions) (#131790) https://github.com/flutter/engine/compare/d6b962d0e36d...9304c0074d29 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from d29f946d6180 to 01ee134bb223 (1 revision) (flutter/engine#44269) 2023-08-02 ychris@google.com [iOS][A11Y] fix hittest with non-SemanticsObject (flutter/engine#44014) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from d61a50c155bd to d29f946d6180 (1 revision) (flutter/engine#44267) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 6009cc6d7d80 to 514c66ce0471 (2 revisions) (flutter/engine#44268) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e8a8031f027dc..3da89ffabb5e2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d6b962d0e36d7b99a24800e42e5622a1ecec78b5 +9304c0074d290e2e1c64578e33f393e05f09f14d From 12b8e0cb0ed6460abbb2bebcb3b9c6e0e3c713a1 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 2 Aug 2023 11:37:06 -0700 Subject: [PATCH 0503/1547] add gem dependency to the ios_app_with_extensions_test (#131713) Adds gem dependency to the tests Fixes https://github.com/flutter/flutter/issues/131693 --- .ci.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index bd92cd051d906..74e9d417f308d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3769,6 +3769,10 @@ targets: presubmit: false timeout: 60 properties: + dependencies: >- + [ + {"dependency": "gems", "version": "v3.3.14"} + ] tags: > ["devicelab", "hostonly", "mac"] task_name: ios_app_with_extensions_test @@ -3779,6 +3783,10 @@ targets: presubmit: false timeout: 60 properties: + dependencies: >- + [ + {"dependency": "gems", "version": "v3.3.14"} + ] tags: > ["devicelab", "hostonly", "mac", "arm64"] task_name: ios_app_with_extensions_test From 5720dead6bfd85323f2f5d665daf4a40e627520b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 2 Aug 2023 15:04:34 -0400 Subject: [PATCH 0504/1547] Roll Packages from 3dc00c1a32f6 to 4e4961a24b3d (1 revision) (#131788) https://github.com/flutter/packages/compare/3dc00c1a32f6...4e4961a24b3d 2023-08-02 43054281+camsim99@users.noreply.github.com [google_maps_flutter_android] Disable flaky `testToggleInfo` test (flutter/packages#4629) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 1ccb7c53b9f35..f77200909786a 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -3dc00c1a32f6659206f4e038ce989bb49bdfb36f +4e4961a24b3d169a62080cf285e66580eaca7e7a From 253bd3d475dfa4e5231fd0308efbf87fef89e1b9 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 2 Aug 2023 12:51:41 -0700 Subject: [PATCH 0505/1547] [framework] lerp images in a save layer. (#131703) Without a saveLayer, the BlendMode.plus will add itself to the backdrop and not just the previous image. Pushing without tests to see if existing goldens fail, but otherwise I have some good examples locally. This is necessary uncondtionally, and lerping lerped images has the same issue. Fixes https://github.com/flutter/flutter/issues/131617 ### Before ![flutter_02](https://github.com/flutter/flutter/assets/8975114/1e783285-2fc2-429f-9fd8-6d04d4a155e1) ### After ![flutter_03](https://github.com/flutter/flutter/assets/8975114/3d08b187-26aa-4471-926d-e9ed5946a206) --- .../lib/src/painting/decoration_image.dart | 2 + .../painting/decoration_image_lerp_test.dart | 163 ++++++++++++++++++ 2 files changed, 165 insertions(+) diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index c91a9f083341d..66c1be27ff33e 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -815,8 +815,10 @@ class _BlendedDecorationImagePainter implements DecorationImagePainter { @override void paint(Canvas canvas, Rect rect, Path? clipPath, ImageConfiguration configuration, { double blend = 1.0, BlendMode blendMode = BlendMode.srcOver }) { + canvas.saveLayer(null, Paint()); a?.paint(canvas, rect, clipPath, configuration, blend: blend * (1.0 - t), blendMode: blendMode); b?.paint(canvas, rect, clipPath, configuration, blend: blend * t, blendMode: a != null ? BlendMode.plus : blendMode); + canvas.restore(); } @override diff --git a/packages/flutter/test/painting/decoration_image_lerp_test.dart b/packages/flutter/test/painting/decoration_image_lerp_test.dart index 1e0f6f4998cc8..44d2e3ede8293 100644 --- a/packages/flutter/test/painting/decoration_image_lerp_test.dart +++ b/packages/flutter/test/painting/decoration_image_lerp_test.dart @@ -405,6 +405,169 @@ void main() { expect(getPixelFromBlock(19, 19, 19), const Color(0xFF000000)); } }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 + + testWidgets('ImageDecoration.lerp with colored background', (WidgetTester tester) async { + final MemoryImage cmyk = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, + 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x4c, 0x59, 0x13, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x63, 0x60, 0x05, 0xc2, 0xf5, 0x0c, 0xeb, 0x01, 0x03, 0x00, 0x01, 0x69, 0x19, + 0xea, 0x34, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + ])); + final MemoryImage wrgb = MemoryImage(Uint8List.fromList([ + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x00, 0xd4, 0x9f, 0x76, + 0xed, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, + 0xff, 0x00, 0xff, 0x00, 0x00, 0x1e, 0x46, 0xbb, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x49, 0x44, 0x41, + 0x54, 0x08, 0xd7, 0x63, 0xe0, 0x07, 0xc2, 0xa5, 0x0c, 0x4b, 0x01, 0x03, 0x50, 0x01, 0x69, 0x4a, + 0x78, 0x1d, 0x41, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, + ])); + + await tester.runAsync(() async { + await load(cmyk); + await load(wrgb); + }); + + await tester.pumpWidget( + ColoredBox( + color: Colors.pink, + child: Align( + alignment: Alignment.topLeft, + child: Wrap( + textDirection: TextDirection.ltr, + children: [ + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.1, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.2, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.8, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 0.9, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.contain), + DecorationImage(image: cmyk, fit: BoxFit.contain), + 1.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, fit: BoxFit.cover), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeatY), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeatX), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, repeat: ImageRepeat.repeat, opacity: 0.2), + DecorationImage(image: cmyk, repeat: ImageRepeat.repeat, opacity: 0.2), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: wrgb, scale: 0.5, repeat: ImageRepeat.repeatX), + DecorationImage(image: cmyk, scale: 0.25, repeat: ImageRepeat.repeatY), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 1.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.0, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.25, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.5, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 0.75, + )), + TestImage(DecorationImage.lerp( + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0)), + DecorationImage(image: cmyk, centerSlice: const Rect.fromLTWH(2.0, 2.0, 1.0, 1.0)), + 1.0, + )), + ], + ), + ), + ), + ); + + await expectLater( + find.byType(Wrap), + matchesGoldenFile('decoration_image.lerp.2.png'), + ); + }, skip: kIsWeb); // TODO(ianh): https://github.com/flutter/flutter/issues/130612, https://github.com/flutter/flutter/issues/130609 } Future load(MemoryImage image) { From 00a8323533d4d1b887bc2eb1988f4586860dfca4 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Wed, 2 Aug 2023 12:56:03 -0700 Subject: [PATCH 0506/1547] Add documentation in flutter.groovy noting that we always use the latest available android version (#131705) Last piece of/ Fixes https://github.com/flutter/flutter/issues/131425 Also added a period to a comment line that was missing one. --- .../flutter_tools/gradle/src/main/groovy/flutter.groovy | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index 798c19e4cb739..c0102b4ff2199 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -49,13 +49,18 @@ class FlutterExtension { /** Sets the minSdkVersion used by default in Flutter app projects. */ static int minSdkVersion = 19 - /** Sets the targetSdkVersion used by default in Flutter app projects. */ + /** + * Sets the targetSdkVersion used by default in Flutter app projects. + * targetSdkVersion should always be the latest available stable version. + * + * See https://developer.android.com/guide/topics/manifest/uses-sdk-element. + */ static int targetSdkVersion = 33 /** * Sets the ndkVersion used by default in Flutter app projects. * Chosen as default version of the AGP version below as found in - * https://developer.android.com/studio/projects/install-ndk#default-ndk-per-agp + * https://developer.android.com/studio/projects/install-ndk#default-ndk-per-agp. */ static String ndkVersion = "23.1.7779620" From f0197895656e8b42f294ac845dc5169cc7b2b7b0 Mon Sep 17 00:00:00 2001 From: LouiseHsu Date: Wed, 2 Aug 2023 13:20:39 -0700 Subject: [PATCH 0507/1547] [framework] Add Look Up to selection controls for iOS (#131798) This PR adds framework support for the Look Up feature in iOS. https://github.com/flutter/flutter/assets/36148254/d301df79-4e23-454f-8742-2f8e39c2960c The corresponding merged engine PR can be found [here](https://github.com/flutter/engine/pull/43308). This PR addresses https://github.com/flutter/flutter/issues/82907 More details are available in this [design doc.](flutter.dev/go/add-missing-features-to-selection-controls) This is the same PR as https://github.com/flutter/flutter/pull/130532, this is an attempt to fix the Google Testing issue --- .../adaptive_text_selection_toolbar.dart | 2 + .../lib/src/cupertino/localizations.dart | 7 + .../text_selection_toolbar_button.dart | 3 + .../adaptive_text_selection_toolbar.dart | 4 + .../src/material/material_localizations.dart | 6 + .../flutter/lib/src/services/text_input.dart | 3 + .../src/widgets/context_menu_button_item.dart | 3 + .../lib/src/widgets/editable_text.dart | 34 +++ .../adaptive_text_selection_toolbar_test.dart | 9 +- .../test/cupertino/text_field_test.dart | 179 ++++++++++--- .../test/cupertino/text_selection_test.dart | 51 +++- .../adaptive_text_selection_toolbar_test.dart | 9 +- .../test/material/localizations_test.dart | 1 + .../test/material/text_field_test.dart | 49 ++-- .../test/widgets/editable_text_test.dart | 1 + .../test/widgets/selectable_text_test.dart | 33 ++- .../lib/src/l10n/cupertino_af.arb | 3 +- .../lib/src/l10n/cupertino_am.arb | 3 +- .../lib/src/l10n/cupertino_ar.arb | 3 +- .../lib/src/l10n/cupertino_as.arb | 3 +- .../lib/src/l10n/cupertino_az.arb | 3 +- .../lib/src/l10n/cupertino_be.arb | 3 +- .../lib/src/l10n/cupertino_bg.arb | 3 +- .../lib/src/l10n/cupertino_bn.arb | 3 +- .../lib/src/l10n/cupertino_bs.arb | 3 +- .../lib/src/l10n/cupertino_ca.arb | 3 +- .../lib/src/l10n/cupertino_cs.arb | 3 +- .../lib/src/l10n/cupertino_cy.arb | 3 +- .../lib/src/l10n/cupertino_da.arb | 3 +- .../lib/src/l10n/cupertino_de.arb | 3 +- .../lib/src/l10n/cupertino_el.arb | 3 +- .../lib/src/l10n/cupertino_en.arb | 5 + .../lib/src/l10n/cupertino_es.arb | 3 +- .../lib/src/l10n/cupertino_et.arb | 3 +- .../lib/src/l10n/cupertino_eu.arb | 3 +- .../lib/src/l10n/cupertino_fa.arb | 3 +- .../lib/src/l10n/cupertino_fi.arb | 3 +- .../lib/src/l10n/cupertino_fil.arb | 3 +- .../lib/src/l10n/cupertino_fr.arb | 3 +- .../lib/src/l10n/cupertino_gl.arb | 3 +- .../lib/src/l10n/cupertino_gsw.arb | 3 +- .../lib/src/l10n/cupertino_gu.arb | 3 +- .../lib/src/l10n/cupertino_he.arb | 3 +- .../lib/src/l10n/cupertino_hi.arb | 3 +- .../lib/src/l10n/cupertino_hr.arb | 3 +- .../lib/src/l10n/cupertino_hu.arb | 3 +- .../lib/src/l10n/cupertino_hy.arb | 3 +- .../lib/src/l10n/cupertino_id.arb | 3 +- .../lib/src/l10n/cupertino_is.arb | 3 +- .../lib/src/l10n/cupertino_it.arb | 3 +- .../lib/src/l10n/cupertino_ja.arb | 3 +- .../lib/src/l10n/cupertino_ka.arb | 3 +- .../lib/src/l10n/cupertino_kk.arb | 3 +- .../lib/src/l10n/cupertino_km.arb | 3 +- .../lib/src/l10n/cupertino_kn.arb | 3 +- .../lib/src/l10n/cupertino_ko.arb | 3 +- .../lib/src/l10n/cupertino_ky.arb | 3 +- .../lib/src/l10n/cupertino_lo.arb | 3 +- .../lib/src/l10n/cupertino_lt.arb | 3 +- .../lib/src/l10n/cupertino_lv.arb | 3 +- .../lib/src/l10n/cupertino_mk.arb | 3 +- .../lib/src/l10n/cupertino_ml.arb | 3 +- .../lib/src/l10n/cupertino_mn.arb | 3 +- .../lib/src/l10n/cupertino_mr.arb | 3 +- .../lib/src/l10n/cupertino_ms.arb | 3 +- .../lib/src/l10n/cupertino_my.arb | 3 +- .../lib/src/l10n/cupertino_nb.arb | 3 +- .../lib/src/l10n/cupertino_ne.arb | 3 +- .../lib/src/l10n/cupertino_nl.arb | 3 +- .../lib/src/l10n/cupertino_no.arb | 3 +- .../lib/src/l10n/cupertino_or.arb | 3 +- .../lib/src/l10n/cupertino_pa.arb | 3 +- .../lib/src/l10n/cupertino_pl.arb | 3 +- .../lib/src/l10n/cupertino_pt.arb | 3 +- .../lib/src/l10n/cupertino_ro.arb | 3 +- .../lib/src/l10n/cupertino_ru.arb | 3 +- .../lib/src/l10n/cupertino_si.arb | 3 +- .../lib/src/l10n/cupertino_sk.arb | 3 +- .../lib/src/l10n/cupertino_sl.arb | 3 +- .../lib/src/l10n/cupertino_sq.arb | 3 +- .../lib/src/l10n/cupertino_sr.arb | 3 +- .../lib/src/l10n/cupertino_sv.arb | 3 +- .../lib/src/l10n/cupertino_sw.arb | 3 +- .../lib/src/l10n/cupertino_ta.arb | 3 +- .../lib/src/l10n/cupertino_te.arb | 3 +- .../lib/src/l10n/cupertino_th.arb | 3 +- .../lib/src/l10n/cupertino_tl.arb | 3 +- .../lib/src/l10n/cupertino_tr.arb | 3 +- .../lib/src/l10n/cupertino_uk.arb | 3 +- .../lib/src/l10n/cupertino_ur.arb | 3 +- .../lib/src/l10n/cupertino_uz.arb | 3 +- .../lib/src/l10n/cupertino_vi.arb | 3 +- .../lib/src/l10n/cupertino_zh.arb | 3 +- .../lib/src/l10n/cupertino_zu.arb | 3 +- .../generated_cupertino_localizations.dart | 234 +++++++++++++++++ .../generated_material_localizations.dart | 237 ++++++++++++++++++ .../lib/src/l10n/material_af.arb | 3 +- .../lib/src/l10n/material_am.arb | 3 +- .../lib/src/l10n/material_ar.arb | 3 +- .../lib/src/l10n/material_as.arb | 3 +- .../lib/src/l10n/material_az.arb | 3 +- .../lib/src/l10n/material_be.arb | 3 +- .../lib/src/l10n/material_bg.arb | 3 +- .../lib/src/l10n/material_bn.arb | 3 +- .../lib/src/l10n/material_bs.arb | 3 +- .../lib/src/l10n/material_ca.arb | 3 +- .../lib/src/l10n/material_cs.arb | 3 +- .../lib/src/l10n/material_cy.arb | 3 +- .../lib/src/l10n/material_da.arb | 3 +- .../lib/src/l10n/material_de.arb | 3 +- .../lib/src/l10n/material_el.arb | 3 +- .../lib/src/l10n/material_en.arb | 5 + .../lib/src/l10n/material_es.arb | 3 +- .../lib/src/l10n/material_et.arb | 3 +- .../lib/src/l10n/material_eu.arb | 3 +- .../lib/src/l10n/material_fa.arb | 3 +- .../lib/src/l10n/material_fi.arb | 3 +- .../lib/src/l10n/material_fil.arb | 3 +- .../lib/src/l10n/material_fr.arb | 3 +- .../lib/src/l10n/material_gl.arb | 3 +- .../lib/src/l10n/material_gsw.arb | 3 +- .../lib/src/l10n/material_gu.arb | 3 +- .../lib/src/l10n/material_he.arb | 3 +- .../lib/src/l10n/material_hi.arb | 3 +- .../lib/src/l10n/material_hr.arb | 3 +- .../lib/src/l10n/material_hu.arb | 3 +- .../lib/src/l10n/material_hy.arb | 3 +- .../lib/src/l10n/material_id.arb | 3 +- .../lib/src/l10n/material_is.arb | 3 +- .../lib/src/l10n/material_it.arb | 3 +- .../lib/src/l10n/material_ja.arb | 3 +- .../lib/src/l10n/material_ka.arb | 3 +- .../lib/src/l10n/material_kk.arb | 3 +- .../lib/src/l10n/material_km.arb | 3 +- .../lib/src/l10n/material_kn.arb | 3 +- .../lib/src/l10n/material_ko.arb | 3 +- .../lib/src/l10n/material_ky.arb | 3 +- .../lib/src/l10n/material_lo.arb | 3 +- .../lib/src/l10n/material_lt.arb | 3 +- .../lib/src/l10n/material_lv.arb | 3 +- .../lib/src/l10n/material_mk.arb | 3 +- .../lib/src/l10n/material_ml.arb | 3 +- .../lib/src/l10n/material_mn.arb | 3 +- .../lib/src/l10n/material_mr.arb | 3 +- .../lib/src/l10n/material_ms.arb | 3 +- .../lib/src/l10n/material_my.arb | 3 +- .../lib/src/l10n/material_nb.arb | 3 +- .../lib/src/l10n/material_ne.arb | 3 +- .../lib/src/l10n/material_nl.arb | 3 +- .../lib/src/l10n/material_no.arb | 3 +- .../lib/src/l10n/material_or.arb | 3 +- .../lib/src/l10n/material_pa.arb | 3 +- .../lib/src/l10n/material_pl.arb | 3 +- .../lib/src/l10n/material_ps.arb | 3 +- .../lib/src/l10n/material_pt.arb | 3 +- .../lib/src/l10n/material_ro.arb | 3 +- .../lib/src/l10n/material_ru.arb | 3 +- .../lib/src/l10n/material_si.arb | 3 +- .../lib/src/l10n/material_sk.arb | 3 +- .../lib/src/l10n/material_sl.arb | 3 +- .../lib/src/l10n/material_sq.arb | 3 +- .../lib/src/l10n/material_sr.arb | 3 +- .../lib/src/l10n/material_sv.arb | 3 +- .../lib/src/l10n/material_sw.arb | 3 +- .../lib/src/l10n/material_ta.arb | 3 +- .../lib/src/l10n/material_te.arb | 3 +- .../lib/src/l10n/material_th.arb | 3 +- .../lib/src/l10n/material_tl.arb | 3 +- .../lib/src/l10n/material_tr.arb | 3 +- .../lib/src/l10n/material_uk.arb | 3 +- .../lib/src/l10n/material_ur.arb | 3 +- .../lib/src/l10n/material_uz.arb | 3 +- .../lib/src/l10n/material_vi.arb | 3 +- .../lib/src/l10n/material_zh.arb | 3 +- .../lib/src/l10n/material_zu.arb | 3 +- 175 files changed, 1094 insertions(+), 246 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart b/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart index 33f5e502eabac..37dc76e042c5a 100644 --- a/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart +++ b/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart @@ -94,6 +94,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback? onCut, required VoidCallback? onPaste, required VoidCallback? onSelectAll, + required VoidCallback? onLookUp, required VoidCallback? onLiveTextInput, required this.anchors, }) : children = null, @@ -103,6 +104,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { onCut: onCut, onPaste: onPaste, onSelectAll: onSelectAll, + onLookUp: onLookUp, onLiveTextInput: onLiveTextInput ); diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index c3456e82ae417..2109b13de71cd 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -245,6 +245,10 @@ abstract class CupertinoLocalizations { // The global version uses the translated string from the arb file. String get selectAllButtonLabel; + /// The term used for looking up a selection. + // The global version uses the translated string from the arb file. + String get lookUpButtonLabel; + /// The default placeholder used in [CupertinoSearchTextField]. // The global version uses the translated string from the arb file. String get searchTextFieldPlaceholderLabel; @@ -455,6 +459,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { @override String get selectAllButtonLabel => 'Select All'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get searchTextFieldPlaceholderLabel => 'Search'; diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart index f07d88e4b5ec6..74f9b60f43998 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart @@ -105,6 +105,8 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget { return localizations.pasteButtonLabel; case ContextMenuButtonType.selectAll: return localizations.selectAllButtonLabel; + case ContextMenuButtonType.lookUp: + return localizations.lookUpButtonLabel; case ContextMenuButtonType.liveTextInput: case ContextMenuButtonType.delete: case ContextMenuButtonType.custom: @@ -189,6 +191,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State 'Select all'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get viewLicensesButtonLabel => 'View licenses'; diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index f9f475fa1d440..2ab806d391365 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1050,6 +1050,9 @@ mixin TextSelectionDelegate { /// Whether select all is enabled, must not be null. bool get selectAllEnabled => true; + /// Whether look up is enabled, must not be null. + bool get lookUpEnabled => true; + /// Whether Live Text input is enabled. /// /// See also: diff --git a/packages/flutter/lib/src/widgets/context_menu_button_item.dart b/packages/flutter/lib/src/widgets/context_menu_button_item.dart index e355ab41e3da0..1a214be5c0455 100644 --- a/packages/flutter/lib/src/widgets/context_menu_button_item.dart +++ b/packages/flutter/lib/src/widgets/context_menu_button_item.dart @@ -26,6 +26,9 @@ enum ContextMenuButtonType { /// A button that deletes the current text selection. delete, + /// A button that looks up the current text selection. + lookUp, + /// A button for starting Live Text input. /// /// See also: diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index d23229d536d24..7f5e7c0c7cc34 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1852,6 +1852,7 @@ class EditableText extends StatefulWidget { required final VoidCallback? onCut, required final VoidCallback? onPaste, required final VoidCallback? onSelectAll, + required final VoidCallback? onLookUp, required final VoidCallback? onLiveTextInput, }) { final List resultButtonItem = []; @@ -1882,6 +1883,11 @@ class EditableText extends StatefulWidget { onPressed: onSelectAll, type: ContextMenuButtonType.selectAll, ), + if (onLookUp != null) + ContextMenuButtonItem( + onPressed: onLookUp, + type: ContextMenuButtonType.lookUp, + ), ]); } @@ -2232,6 +2238,15 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } + @override + bool get lookUpEnabled { + if (defaultTargetPlatform != TargetPlatform.iOS) { + return false; + } + return !widget.obscureText + && !textEditingValue.selection.isCollapsed; + } + @override bool get liveTextInputEnabled { return _liveTextInputStatus?.value == LiveTextInputStatus.enabled && @@ -2397,6 +2412,22 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } + /// Look up the current selection, as in the "Look Up" edit menu button on iOS. + /// Currently this is only implemented for iOS. + /// Throws an error if the selection is empty or collapsed. + Future lookUpSelection(SelectionChangedCause cause) async { + assert(!widget.obscureText); + + final String text = textEditingValue.selection.textInside(textEditingValue.text); + if (widget.obscureText || text.isEmpty) { + return; + } + await SystemChannels.platform.invokeMethod( + 'LookUp.invoke', + text, + ); + } + void _startLiveTextInput(SelectionChangedCause cause) { if (!liveTextInputEnabled) { return; @@ -2623,6 +2654,9 @@ class EditableTextState extends State with AutomaticKeepAliveClien onSelectAll: selectAllEnabled ? () => selectAll(SelectionChangedCause.toolbar) : null, + onLookUp: lookUpEnabled + ? () => lookUpSelection(SelectionChangedCause.toolbar) + : null, onLiveTextInput: liveTextInputEnabled ? () => _startLiveTextInput(SelectionChangedCause.toolbar) : null, diff --git a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart index d0c6c1a57855f..93f2e93cff941 100644 --- a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart @@ -168,6 +168,7 @@ void main() { onPaste: () {}, onSelectAll: () {}, onLiveTextInput: () {}, + onLookUp: () {}, ), ), )); @@ -180,16 +181,16 @@ void main() { switch (defaultTargetPlatform) { case TargetPlatform.android: - expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); case TargetPlatform.fuchsia: - expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); case TargetPlatform.iOS: - expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); expect(findLiveTextButton(), findsOneWidget); case TargetPlatform.macOS: case TargetPlatform.linux: case TargetPlatform.windows: - expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(6)); } }, skip: kIsWeb, // [intended] on web the browser handles the context menu. diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index ab0b3fbf86dad..dfe73bee44312 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -201,6 +201,7 @@ void main() { setUp(() async { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall); + EditableText.debugDeterministicCursor = false; // Fill the clipboard so that the Paste option is available in the text // selection menu. @@ -250,6 +251,104 @@ void main() { }, ); + testWidgets('Look Up shows up on iOS only (CupertinoTextField)', (WidgetTester tester) async { + String? lastLookUp; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'LookUp.invoke') { + expect(methodCall.arguments, isA()); + lastLookUp = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test', + ); + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Look Up'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Look Up')); + expect(lastLookUp, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + + testWidgets('Look Up shows up on iOS only (TextField)', (WidgetTester tester) async { + String? lastLookUp; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'LookUp.invoke') { + expect(methodCall.arguments, isA()); + lastLookUp = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test ', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Look Up'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Look Up')); + expect(lastLookUp, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + testWidgets('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', @@ -1859,7 +1958,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -1879,10 +1978,10 @@ void main() { // Plain collapsed selection. expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 6); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 7 : 6); // Toolbar shows on mobile. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(2) : findsNothing); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(2) : findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -2014,7 +2113,7 @@ void main() { ); // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Tap the selected word to hide the toolbar and retain the selection. await tester.tapAt(vPos); @@ -2032,7 +2131,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 24, extentOffset: 35), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Tap past the selected word to move the cursor and hide the toolbar. await tester.tapAt(ePos); @@ -2145,8 +2244,8 @@ void main() { } else { switch (defaultTargetPlatform) { case TargetPlatform.macOS: - case TargetPlatform.iOS: expect(find.byType(CupertinoButton), findsNWidgets(3)); + case TargetPlatform.iOS: case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: @@ -2329,7 +2428,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -2351,7 +2450,7 @@ void main() { await tester.pump(const Duration(milliseconds: 50)); // First tap moved the cursor. expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 12 : 9); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 12 : 9); await tester.tapAt(pPos); await tester.pumpAndSettle(); @@ -2363,7 +2462,7 @@ void main() { ); // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -2433,7 +2532,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -2451,7 +2550,7 @@ void main() { await tester.pump(const Duration(milliseconds: 50)); // First tap moved the cursor. expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 12 : 9); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 12 : 9); await tester.tapAt(pPos); await tester.pump(const Duration(milliseconds: 500)); @@ -2464,7 +2563,7 @@ void main() { // you tapped instead of the edge like every other single tap. This is // likely a bug in iOS 12 and not present in other versions. expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 6); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 7 : 6); // No toolbar. expect(find.byType(CupertinoButton), findsNothing); @@ -2949,18 +3048,18 @@ void main() { await tester.longPressAt(ePos); await tester.pump(const Duration(milliseconds: 50)); - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; if (kIsWeb) { expect(find.byType(CupertinoButton), findsNothing); } else { - expect(find.byType(CupertinoButton), findsNWidgets(isTargetPlatformMobile ? 2 : 1)); + expect(find.byType(CupertinoButton), findsNWidgets(isTargetPlatformIOS ? 2 : 1)); } expect(controller.selection.isCollapsed, isTrue); expect(controller.selection.baseOffset, 6); // Tap in a slightly different position to avoid hitting the context menu // on desktop. - final Offset secondTapPos = isTargetPlatformMobile + final Offset secondTapPos = isTargetPlatformIOS ? ePos : ePos + const Offset(-1.0, 0.0); await tester.tapAt(secondTapPos); @@ -3308,7 +3407,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -3326,7 +3425,7 @@ void main() { await tester.pump(const Duration(milliseconds: 50)); // First tap moved the cursor to the beginning of the second word. expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 12 : 9); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 12 : 9); await tester.tapAt(pPos); await tester.pump(const Duration(milliseconds: 500)); @@ -3360,7 +3459,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -3388,7 +3487,7 @@ void main() { if (isContextMenuProvidedByPlatform) { expect(find.byType(CupertinoButton), findsNothing); } else { - expect(find.byType(CupertinoButton), isTargetPlatformMobile ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); } await tester.tapAt(pPos); @@ -3397,7 +3496,7 @@ void main() { // First tap moved the cursor. expect(find.byType(CupertinoButton), findsNothing); expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 12 : 9); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 12 : 9); await tester.tapAt(pPos); await tester.pumpAndSettle(); @@ -3408,7 +3507,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); // Shows toolbar. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -3428,6 +3527,7 @@ void main() { ); final Offset textFieldStart = tester.getTopLeft(find.byType(CupertinoTextField)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.tapAt(textFieldStart + const Offset(50.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3441,7 +3541,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Double tap selecting the same word somewhere else is fine. await tester.tapAt(textFieldStart + const Offset(100.0, 5.0)); @@ -3461,7 +3561,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); await tester.tapAt(textFieldStart + const Offset(150.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3477,7 +3577,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); group('Triple tap/click', () { @@ -3717,6 +3817,7 @@ void main() { ); final Offset textfieldStart = tester.getTopLeft(find.byType(CupertinoTextField)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3729,7 +3830,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(kDoubleTapTimeout); @@ -3755,7 +3856,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); // Third tap shows the toolbar and selects the paragraph. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -3764,7 +3865,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 36), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); await tester.tapAt(textfieldStart + const Offset(150.0, 25.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3782,7 +3883,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 44, extentOffset: 50), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); // Third tap selects the paragraph and shows the toolbar. await tester.tapAt(textfieldStart + const Offset(150.0, 25.0)); @@ -3791,7 +3892,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 36, extentOffset: 66), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -4794,7 +4895,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -4824,7 +4925,7 @@ void main() { // Fall back to a single tap which selects the edge of the word on iOS, and // a precise position on macOS. expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 12 : 9); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 12 : 9); await tester.pump(); // Falling back to a single tap doesn't trigger a toolbar. @@ -4837,7 +4938,7 @@ void main() { ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. // On macOS, we select the precise position of the tap. - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( @@ -4856,7 +4957,7 @@ void main() { await tester.tapAt(ePos, pointer: 7); await tester.pump(const Duration(milliseconds: 50)); expect(controller.selection.isCollapsed, isTrue); - expect(controller.selection.baseOffset, isTargetPlatformMobile ? 7 : 5); + expect(controller.selection.baseOffset, isTargetPlatformIOS ? 7 : 5); await tester.tapAt(ePos, pointer: 7); await tester.pumpAndSettle(); expect(controller.selection.baseOffset, 4); @@ -8142,7 +8243,7 @@ void main() { final TextEditingController controller = TextEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -8167,7 +8268,7 @@ void main() { kind: PointerDeviceKind.mouse, ); await tester.pumpAndSettle(); - if (isTargetPlatformMobile) { + if (isTargetPlatformIOS) { await gesture.up(); // Not a double tap + drag. await tester.pumpAndSettle(kDoubleTapTimeout); @@ -8176,7 +8277,7 @@ void main() { expect(controller.selection.extentOffset, 23); // Expand the selection a bit. - if (isTargetPlatformMobile) { + if (isTargetPlatformIOS) { await gesture.down(textOffsetToPosition(tester, 24)); await tester.pumpAndSettle(); } @@ -8355,7 +8456,7 @@ void main() { final TextEditingController controller = TextEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); - final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( CupertinoApp( home: Center( @@ -8380,7 +8481,7 @@ void main() { kind: PointerDeviceKind.mouse, ); await tester.pumpAndSettle(); - if (isTargetPlatformMobile) { + if (isTargetPlatformIOS) { await gesture.up(); // Not a double tap + drag. await tester.pumpAndSettle(kDoubleTapTimeout); @@ -8390,7 +8491,7 @@ void main() { expect(controller.selection.extentOffset, 8); // Expand the selection a bit. - if (isTargetPlatformMobile) { + if (isTargetPlatformIOS) { await gesture.down(textOffsetToPosition(tester, 7)); await tester.pumpAndSettle(); } diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart index b679eb6d46f00..b154e9ad88535 100644 --- a/packages/flutter/test/cupertino/text_selection_test.dart +++ b/packages/flutter/test/cupertino/text_selection_test.dart @@ -247,7 +247,7 @@ void main() { testWidgets("When a menu item doesn't fit, a second page is used.", (WidgetTester tester) async { // Set the screen size to more narrow, so that Paste can't fit. - tester.view.physicalSize = const Size(800, 800); + tester.view.physicalSize = const Size(900, 800); addTearDown(tester.view.reset); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); @@ -270,6 +270,7 @@ void main() { expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsNothing); @@ -285,27 +286,43 @@ void main() { expect(find.text('Copy'), findsOneWidget); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); + // Tapping the next button shows both the overflow, back, and next buttons. + await tester.tapAt(tester.getCenter(findOverflowNextButton())); + await tester.pumpAndSettle(); + expect(find.text('Cut'), findsNothing); + expect(find.text('Copy'), findsNothing); + expect(find.text('Paste'), findsOneWidget); + expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); + expect(findOverflowBackButton(), findsOneWidget); + expect(findOverflowNextButton(), findsOneWidget); + // Tapping the next button shows the overflowing button and the next // button is hidden as the last page is shown. await tester.tapAt(tester.getCenter(findOverflowNextButton())); await tester.pumpAndSettle(); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); - expect(find.text('Paste'), findsOneWidget); + expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsOneWidget); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsNothing); // Tapping the back button shows the first page again with the next button. await tester.tapAt(tester.getCenter(findOverflowBackButton())); await tester.pumpAndSettle(); + await tester.tapAt(tester.getCenter(findOverflowBackButton())); + await tester.pumpAndSettle(); expect(find.text('Cut'), findsOneWidget); expect(find.text('Copy'), findsOneWidget); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); }, @@ -340,6 +357,7 @@ void main() { expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsNothing); @@ -356,6 +374,7 @@ void main() { expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); @@ -367,22 +386,36 @@ void main() { expect(find.text('Copy'), findsOneWidget); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); - // Tapping the next button again shows Paste and hides the next button as - // the last page is shown. + // Tapping the next button again shows Paste await tester.tapAt(tester.getCenter(findOverflowNextButton())); await tester.pumpAndSettle(); - expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(2)); + expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(3)); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsOneWidget); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); + expect(findOverflowBackButton(), findsOneWidget); + expect(findOverflowNextButton(), findsOneWidget); + + // Tapping the next button again shows the last page. + await tester.tapAt(tester.getCenter(findOverflowNextButton())); + await tester.pumpAndSettle(); + expect(find.text('Cut'), findsNothing); + expect(find.text('Copy'), findsNothing); + expect(find.text('Paste'), findsNothing); + expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsOneWidget); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsNothing); - // Tapping the back button shows the second page again with the next button. + // Tapping the back button twice shows the second page again with the next button. + await tester.tapAt(tester.getCenter(findOverflowBackButton())); + await tester.pumpAndSettle(); await tester.tapAt(tester.getCenter(findOverflowBackButton())); await tester.pumpAndSettle(); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(3)); @@ -390,6 +423,7 @@ void main() { expect(find.text('Copy'), findsOneWidget); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); @@ -401,6 +435,7 @@ void main() { expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); }, @@ -485,7 +520,7 @@ void main() { expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); - // Tap next to go to the third and final page. + // Tap twice to go to the third page. await tester.tapAt(tester.getCenter(findOverflowNextButton())); await tester.pumpAndSettle(); expect(find.text(_longLocalizations.cutButtonLabel), findsNothing); @@ -493,7 +528,7 @@ void main() { expect(find.text(_longLocalizations.pasteButtonLabel), findsOneWidget); expect(find.text(_longLocalizations.selectAllButtonLabel), findsNothing); expect(findOverflowBackButton(), findsOneWidget); - expect(findOverflowNextButton(), findsNothing); + expect(findOverflowNextButton(), findsOneWidget); // Tap back to go to the second page again. await tester.tapAt(tester.getCenter(findOverflowBackButton())); diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index 3d85f3ea76c09..e94c1f4efd571 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -186,6 +186,7 @@ void main() { onPaste: () {}, onSelectAll: () {}, onLiveTextInput: () {}, + onLookUp: () {}, ), ), ), @@ -201,18 +202,18 @@ void main() { case TargetPlatform.android: case TargetPlatform.fuchsia: expect(find.text('Select all'), findsOneWidget); - expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(5)); + expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(6)); case TargetPlatform.iOS: expect(find.text('Select All'), findsOneWidget); expect(findLiveTextButton(), findsOneWidget); - expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); case TargetPlatform.linux: case TargetPlatform.windows: expect(find.text('Select all'), findsOneWidget); - expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(6)); case TargetPlatform.macOS: expect(find.text('Select All'), findsOneWidget); - expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(5)); + expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(6)); } }, skip: kIsWeb, // [intended] on web the browser handles the context menu. diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart index c6695ebdfc7fc..da3731684f2a0 100644 --- a/packages/flutter/test/material/localizations_test.dart +++ b/packages/flutter/test/material/localizations_test.dart @@ -31,6 +31,7 @@ void main() { expect(localizations.copyButtonLabel, isNotNull); expect(localizations.cutButtonLabel, isNotNull); expect(localizations.scanTextButtonLabel, isNotNull); + expect(localizations.lookUpButtonLabel, isNotNull); expect(localizations.okButtonLabel, isNotNull); expect(localizations.pasteButtonLabel, isNotNull); expect(localizations.selectAllButtonLabel, isNotNull); diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 9b3af744d3bca..3998f97500323 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -9216,8 +9216,8 @@ void main() { const TextSelection(baseOffset: 24, extentOffset: 35), ); - // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + // Selected text shows 4 toolbar buttons. + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Tap the selected word to hide the toolbar and retain the selection. await tester.tapAt(vPos); @@ -9235,7 +9235,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 24, extentOffset: 35), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Tap past the selected word to move the cursor and hide the toolbar. await tester.tapAt(ePos); @@ -9290,7 +9290,7 @@ void main() { ); // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -9859,7 +9859,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(kDoubleTapTimeout); @@ -9883,7 +9883,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Third tap shows the toolbar and selects the paragraph. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -9892,7 +9892,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 36), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); await tester.tapAt(textfieldStart + const Offset(150.0, 50.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -9909,7 +9909,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 44, extentOffset: 50), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Third tap selects the paragraph and shows the toolbar. await tester.tapAt(textfieldStart + const Offset(150.0, 50.0)); @@ -9918,7 +9918,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 36, extentOffset: 66), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -11110,6 +11110,7 @@ void main() { ); final Offset textfieldStart = tester.getTopLeft(find.byType(TextField)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -11123,8 +11124,8 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + // Selected text shows 4 toolbar buttons on iOS, and 3 on macOS. + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); await gesture.up(); await tester.pump(); @@ -11134,8 +11135,9 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); + // The toolbar is still showing. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -11253,6 +11255,7 @@ void main() { ); final Offset textfieldStart = tester.getTopLeft(find.byType(TextField)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.longPressAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(); @@ -11266,7 +11269,7 @@ void main() { // Collapsed toolbar shows 3 buttons. expect( find.byType(CupertinoButton), - isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3), + isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3) ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), @@ -11525,6 +11528,7 @@ void main() { ); final Offset textfieldStart = tester.getTopLeft(find.byType(TextField)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; final TestGesture gesture = await tester.startGesture(textfieldStart + const Offset(50.0, 9.0)); @@ -11569,10 +11573,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 23), ); // The toolbar now shows up. - expect( - find.byType(CupertinoButton), - isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3), - ); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -11684,6 +11685,7 @@ void main() { ); final RenderEditable renderEditable = findRenderEditable(tester); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; List lastCharEndpoint = renderEditable.getEndpointsForSelection( const TextSelection.collapsed(offset: 66), // Last character's position. @@ -11737,7 +11739,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 66, affinity: TextAffinity.upstream), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); lastCharEndpoint = renderEditable.getEndpointsForSelection( const TextSelection.collapsed(offset: 66), // Last character's position. @@ -12330,7 +12332,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(4) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -12414,6 +12416,7 @@ void main() { ); final Offset textfieldStart = tester.getTopLeft(find.byType(TextField)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -12427,7 +12430,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Double tap selecting the same word somewhere else is fine. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -12447,7 +12450,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -12463,7 +12466,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -12890,7 +12893,7 @@ void main() { await gesture.up(); await tester.pumpAndSettle(); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 4cc86a032ac4d..3c8ebd855cd31 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -154,6 +154,7 @@ void main() { onCut: null, onPaste: null, onSelectAll: null, + onLookUp: null, onLiveTextInput: () { invokedLiveTextInputSuccessfully = true; }, diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 033d5c2f451a8..6b8f03051b4e4 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -2930,6 +2930,7 @@ void main() { ), ); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; final Offset selectableTextStart = tester.getTopLeft(find.byType(SelectableText)); // This tap just puts the cursor somewhere different than where the double @@ -2957,8 +2958,8 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - // Selected text shows 1 toolbar buttons. - expect(find.byType(CupertinoButton), findsNWidgets(1)); + // Selected text shows 1 toolbar buttons on MacOS, 2 on iOS. + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3071,6 +3072,7 @@ void main() { ); final Offset selectableTextStart = tester.getTopLeft(find.byType(SelectableText)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.tapAt(selectableTextStart + const Offset(150.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3087,8 +3089,8 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - // Selected text shows 1 toolbar buttons. - expect(find.byType(CupertinoButton), findsNWidgets(1)); + // Selected text shows 2 toolbar buttons for iOS, 1 for macOS. + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); await gesture.up(); await tester.pump(); @@ -3099,7 +3101,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); // The toolbar is still showing. - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3198,6 +3200,7 @@ void main() { ); final Offset selectableTextStart = tester.getTopLeft(find.byType(SelectableText)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.longPressAt(selectableTextStart + const Offset(50.0, 5.0)); await tester.pump(); @@ -3215,7 +3218,7 @@ void main() { ); // Toolbar shows one button. - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3480,6 +3483,7 @@ void main() { await tester.startGesture(textOffsetToPosition(tester, 18)); await tester.pump(const Duration(milliseconds: 500)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; final EditableText editableTextWidget = tester.widget(find.byType(EditableText).first); final TextEditingController controller = editableTextWidget.controller; @@ -3550,7 +3554,7 @@ void main() { ), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -3778,7 +3782,7 @@ void main() { ); // Long press toolbar. - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), findsNWidgets(2)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -3841,6 +3845,7 @@ void main() { ); final Offset selectableTextStart = tester.getTopLeft(find.byType(SelectableText)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.longPressAt(selectableTextStart + const Offset(50.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3870,7 +3875,8 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), findsNWidgets(1)); + + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3887,6 +3893,7 @@ void main() { ), ); final Offset selectableTextStart = tester.getTopLeft(find.byType(SelectableText)); + final bool isTargetPlatformIOS = defaultTargetPlatform == TargetPlatform.iOS; await tester.tapAt(selectableTextStart + const Offset(50.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3904,7 +3911,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); // Double tap selecting the same word somewhere else is fine. await tester.pumpAndSettle(kDoubleTapTimeout); @@ -3921,7 +3928,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); // Hide the toolbar so it doesn't interfere with taps on the text. final EditableTextState editableTextState = @@ -3943,7 +3950,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -4022,7 +4029,7 @@ void main() { await gesture.up(); await tester.pump(); - expect(find.byType(CupertinoButton), findsNWidgets(1)); + expect(find.byType(CupertinoButton), findsNWidgets(2)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb index c3e82eaebc0a0..69bc6c4ddded2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Maak toe", "searchTextFieldPlaceholderLabel": "Soek", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb index d3c01ffb78aa0..453a1e81fc506 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "አሰናብት", "searchTextFieldPlaceholderLabel": "ፍለጋ", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb index 3e439036b05c1..b9ad5a4b20696 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb @@ -43,5 +43,6 @@ "modalBarrierDismissLabel": "رفض", "searchTextFieldPlaceholderLabel": "بحث", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb index 7c39f67115a0c..048bd85d5ccc1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "অগ্ৰাহ্য কৰক", "searchTextFieldPlaceholderLabel": "সন্ধান কৰক", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb index 4b949456fb8bc..5f736959241b2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "İmtina edin", "searchTextFieldPlaceholderLabel": "Axtarın", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb index 2cad6127ace52..3fbd1bbb98b65 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Адхіліць", "searchTextFieldPlaceholderLabel": "Пошук", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb index 6841210327718..47470b61054af 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Отхвърляне", "searchTextFieldPlaceholderLabel": "Търсене", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb index b29431eb359a4..9aa5492749e15 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "খারিজ করুন", "searchTextFieldPlaceholderLabel": "সার্চ করুন", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb index 96b76cc3c60a1..79f845fbe568c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb @@ -28,5 +28,6 @@ "modalBarrierDismissLabel": "Odbaci", "searchTextFieldPlaceholderLabel": "Pretraživanje", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb index 81a0aa8e00478..b310231de1c16 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Ignora", "searchTextFieldPlaceholderLabel": "Cerca", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb index d243990e6e54f..d391a3c07ac18 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Zavřít", "searchTextFieldPlaceholderLabel": "Hledat", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb index cfaae3d864671..ffa34dfb1f36a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb @@ -43,5 +43,6 @@ "searchTextFieldPlaceholderLabel": "Chwilio", "modalBarrierDismissLabel": "Diystyru", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb index 295f08cac4ac0..7dd1e44f940dd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Afvis", "searchTextFieldPlaceholderLabel": "Søg", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb index 72ce2888964b9..bf8d283700333 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Schließen", "searchTextFieldPlaceholderLabel": "Suche", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb index bdc52dad8b193..dca5eb8ee5d07 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Παράβλεψη", "searchTextFieldPlaceholderLabel": "Αναζήτηση", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb index 716a4efd1a5b0..0cc970d109028 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb @@ -165,6 +165,11 @@ "description": "The label for select-all buttons and menu items. The reference abbreviation is what iOS shows on text selection toolbars." }, + "lookUpButtonLabel": "Look Up", + "@lookUpButtonLabel": { + "description": "The label for the Look Up button and menu items on iOS." + }, + "noSpellCheckReplacementsLabel": "No Replacements Found", "@noSpellCheckReplacementsLabel": { "description": "The label shown in the text selection context menu on iOS when a misspelled word is tapped but the spell checker found no reasonable fixes for it." diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb index 03d833ddebeb3..8f992fd2bec3a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Cerrar", "searchTextFieldPlaceholderLabel": "Buscar", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb index f8a35ae34ec5d..52886d8d96c2f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Loobu", "searchTextFieldPlaceholderLabel": "Otsige", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb index ea93034f1093f..659c70457d997 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Baztertu", "searchTextFieldPlaceholderLabel": "Bilatu", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb index aee3c9bd86830..e640762476027 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "نپذیرفتن", "searchTextFieldPlaceholderLabel": "جستجو", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb index ff85e706ce315..4afd7f22b6d40 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Ohita", "searchTextFieldPlaceholderLabel": "Hae", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb index 3946ce990464d..4e15997b414a2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "I-dismiss", "searchTextFieldPlaceholderLabel": "Hanapin", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb index f3b5ac58f196d..31921f0e8ce76 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Ignorer", "searchTextFieldPlaceholderLabel": "Rechercher", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb index 9a454cdc5877c..95502c805af52 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Ignorar", "searchTextFieldPlaceholderLabel": "Fai unha busca", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb index 72ce2888964b9..bf8d283700333 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Schließen", "searchTextFieldPlaceholderLabel": "Suche", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb index f29d316ec11b2..9269f0380c871 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "છોડી દો", "searchTextFieldPlaceholderLabel": "શોધો", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb index 83cb32cdbbf5b..ba34f4d83205e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "סגירה", "searchTextFieldPlaceholderLabel": "חיפוש", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb index a412f37607a85..ceaf9b91ecdc9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "खारिज करें", "searchTextFieldPlaceholderLabel": "खोजें", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb index b05fd416210ff..3c8c9ef6debcb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb @@ -28,5 +28,6 @@ "modalBarrierDismissLabel": "Odbaci", "searchTextFieldPlaceholderLabel": "Pretraživanje", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb index bfabfb5297c20..c2d64af3bde08 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Elvetés", "searchTextFieldPlaceholderLabel": "Keresés", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb index 886965d3512a1..abbf09b15e2a0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Փակել", "searchTextFieldPlaceholderLabel": "Որոնում", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb index 97cd510b712c2..2c7c7ce3c02fc 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Tutup", "searchTextFieldPlaceholderLabel": "Telusuri", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb index e2a270959f508..035ff2c3e33dc 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Hunsa", "searchTextFieldPlaceholderLabel": "Leit", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb index 1effc1a6a4274..f370b29df45b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Ignora", "searchTextFieldPlaceholderLabel": "Cerca", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb index 4e015ce3bc360..f97148f8ccb22 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "閉じる", "searchTextFieldPlaceholderLabel": "検索", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb index 012e7e6ccda3b..3dbcb4ba5cec9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "დახურვა", "searchTextFieldPlaceholderLabel": "ძიება", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb index 9cfac67781959..323d4f6c2d78d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Жабу", "searchTextFieldPlaceholderLabel": "Іздеу", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb index 75f748456a27b..ecc1d7ec21306 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ច្រាន​ចោល", "searchTextFieldPlaceholderLabel": "ស្វែងរក", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb index 42e61640714bf..f4c9dec32b7b3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb @@ -23,5 +23,6 @@ "tabSemanticsLabel": "\u0024\u0074\u0061\u0062\u0043\u006f\u0075\u006e\u0074\u0020\u0cb0\u0cb2\u0ccd\u0cb2\u0cbf\u0ca8\u0020\u0024\u0074\u0061\u0062\u0049\u006e\u0064\u0065\u0078\u0020\u0c9f\u0ccd\u0caf\u0cbe\u0cac\u0ccd", "searchTextFieldPlaceholderLabel": "\u0cb9\u0cc1\u0ca1\u0cc1\u0c95\u0cbf", "noSpellCheckReplacementsLabel": "\u004e\u006f\u0020\u0052\u0065\u0070\u006c\u0061\u0063\u0065\u006d\u0065\u006e\u0074\u0073\u0020\u0046\u006f\u0075\u006e\u0064", - "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075" + "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075", + "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb index ace3363484991..55a27170adb7e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "닫기", "searchTextFieldPlaceholderLabel": "검색", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb index 504bf52c57365..1ea6f15519099 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Жабуу", "searchTextFieldPlaceholderLabel": "Издөө", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb index f34735251cfe1..3d375eb44c64c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ປິດໄວ້", "searchTextFieldPlaceholderLabel": "ຊອກຫາ", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb index 1516e209e86a1..d90f28137f453 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Atsisakyti", "searchTextFieldPlaceholderLabel": "Paieška", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb index 59c683fea8e3a..b7ca96dd5f8c5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb @@ -28,5 +28,6 @@ "modalBarrierDismissLabel": "Nerādīt", "searchTextFieldPlaceholderLabel": "Meklēšana", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb index 425255ea7cf7a..5599a7b292cb1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Отфрли", "searchTextFieldPlaceholderLabel": "Пребарувајте", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb index 446a4f4242db1..ebdaa61ae3f0a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "നിരസിക്കുക", "searchTextFieldPlaceholderLabel": "തിരയുക", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb index e06bc778a4db6..6c6d8e73b4312 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Үл хэрэгсэх", "searchTextFieldPlaceholderLabel": "Хайх", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb index 35128260ff35f..47aa29e683324 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "डिसमिस करा", "searchTextFieldPlaceholderLabel": "शोधा", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb index 691435092c478..1730882db8dd4 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Tolak", "searchTextFieldPlaceholderLabel": "Cari", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb index fb56c0d12adb0..a6b191504ca79 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ပယ်ရန်", "searchTextFieldPlaceholderLabel": "ရှာရန်", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb index a392f965e259b..06a32b6a95fc2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Avvis", "searchTextFieldPlaceholderLabel": "Søk", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb index 939e892bd3b08..dacaa307948c9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "खारेज गर्नुहोस्", "searchTextFieldPlaceholderLabel": "खोज्नुहोस्", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb index 723afd6234b21..9db7bda20e328 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Sluiten", "searchTextFieldPlaceholderLabel": "Zoeken", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb index a392f965e259b..06a32b6a95fc2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Avvis", "searchTextFieldPlaceholderLabel": "Søk", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb index aea767ba97421..06bf3b6db4352 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ଖାରଜ କରନ୍ତୁ", "searchTextFieldPlaceholderLabel": "ସନ୍ଧାନ କରନ୍ତୁ", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb index 0abfd5d27a591..5e2bbab9314cf 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ਖਾਰਜ ਕਰੋ", "searchTextFieldPlaceholderLabel": "ਖੋਜੋ", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb index 8a5d3470bf0a7..7d74843c48560 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Zamknij", "searchTextFieldPlaceholderLabel": "Szukaj", "noSpellCheckReplacementsLabel": "Nie znaleziono zastąpień", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb index 0129b43f45173..6c461691d10e0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Dispensar", "searchTextFieldPlaceholderLabel": "Pesquisar", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb index 2a2260d95940c..f455a42995b1e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb @@ -28,5 +28,6 @@ "modalBarrierDismissLabel": "Închideți", "searchTextFieldPlaceholderLabel": "Căutați", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb index 9da4b9b91585b..94e53fe023675 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Закрыть", "searchTextFieldPlaceholderLabel": "Поиск", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb index 14c8cb01588d1..8b2ea75ec7ebe 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ඉවත ලන්න", "searchTextFieldPlaceholderLabel": "සෙවීම", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb index 45f209c585760..ac03577d4672e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Odmietnuť", "searchTextFieldPlaceholderLabel": "Hľadať", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb index 7b84c38117c41..e83f6f3287529 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Opusti", "searchTextFieldPlaceholderLabel": "Iskanje", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb index f7012fedd4ea6..9a954c3e3afff 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Hiq", "searchTextFieldPlaceholderLabel": "Kërko", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb index c8013a5cdc71e..3fd0749276fde 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb @@ -28,5 +28,6 @@ "modalBarrierDismissLabel": "Одбаци", "searchTextFieldPlaceholderLabel": "Претражите", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb index cc2a1c68d6040..756a6984a4f77 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Stäng", "searchTextFieldPlaceholderLabel": "Sök", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb index 8d297653ca6f2..7e1cb2359e309 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Ondoa", "searchTextFieldPlaceholderLabel": "Tafuta", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb index a680ab68d364e..ae344cddf049b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "நிராகரிக்கும்", "searchTextFieldPlaceholderLabel": "தேடுக", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb index 360d0ac66555e..869edfce216ea 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "విస్మరించు", "searchTextFieldPlaceholderLabel": "సెర్చ్ చేయి", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb index e573711075409..8c2ce23a2e12f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "ปิด", "searchTextFieldPlaceholderLabel": "ค้นหา", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb index 3946ce990464d..4e15997b414a2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "I-dismiss", "searchTextFieldPlaceholderLabel": "Hanapin", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb index 24ef72c1f5c8a..85fdf406f985d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Kapat", "searchTextFieldPlaceholderLabel": "Ara", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb index 3c5a80503539b..77949d298f1ca 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb @@ -33,5 +33,6 @@ "modalBarrierDismissLabel": "Закрити", "searchTextFieldPlaceholderLabel": "Шукайте", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb index d0d0027e216d9..0e004933dccf7 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "برخاست کریں", "searchTextFieldPlaceholderLabel": "تلاش کریں", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb index d64d15b6dd150..d3dec79d37b84 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Yopish", "searchTextFieldPlaceholderLabel": "Qidiruv", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb index 4682ba9d5d5b0..8ea93152745e2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Bỏ qua", "searchTextFieldPlaceholderLabel": "Tìm kiếm", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb index 9ee7ce9442d4d..ed0bbdc3e70c8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "关闭", "searchTextFieldPlaceholderLabel": "搜索", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb index f4caee097c3b0..87a31e7fbc405 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb @@ -23,5 +23,6 @@ "modalBarrierDismissLabel": "Cashisa", "searchTextFieldPlaceholderLabel": "Sesha", "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index e7584c9398ce9..3078d50367b3e 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -91,6 +91,9 @@ class CupertinoLocalizationAf extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -244,6 +247,9 @@ class CupertinoLocalizationAm extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -397,6 +403,9 @@ class CupertinoLocalizationAr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => r'$minute دقيقة​'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -550,6 +559,9 @@ class CupertinoLocalizationAs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -703,6 +715,9 @@ class CupertinoLocalizationAz extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -856,6 +871,9 @@ class CupertinoLocalizationBe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1009,6 +1027,9 @@ class CupertinoLocalizationBg extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1162,6 +1183,9 @@ class CupertinoLocalizationBn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1315,6 +1339,9 @@ class CupertinoLocalizationBs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1468,6 +1495,9 @@ class CupertinoLocalizationCa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1621,6 +1651,9 @@ class CupertinoLocalizationCs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1774,6 +1807,9 @@ class CupertinoLocalizationCy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => r'$minute munud'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -1927,6 +1963,9 @@ class CupertinoLocalizationDa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -2080,6 +2119,9 @@ class CupertinoLocalizationDe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -2254,6 +2296,9 @@ class CupertinoLocalizationEl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -2407,6 +2452,9 @@ class CupertinoLocalizationEn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -2752,6 +2800,9 @@ class CupertinoLocalizationEs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -3565,6 +3616,9 @@ class CupertinoLocalizationEt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -3718,6 +3772,9 @@ class CupertinoLocalizationEu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -3871,6 +3928,9 @@ class CupertinoLocalizationFa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4024,6 +4084,9 @@ class CupertinoLocalizationFi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4177,6 +4240,9 @@ class CupertinoLocalizationFil extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4330,6 +4396,9 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4525,6 +4594,9 @@ class CupertinoLocalizationGl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4678,6 +4750,9 @@ class CupertinoLocalizationGsw extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4831,6 +4906,9 @@ class CupertinoLocalizationGu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -4984,6 +5062,9 @@ class CupertinoLocalizationHe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -5137,6 +5218,9 @@ class CupertinoLocalizationHi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -5290,6 +5374,9 @@ class CupertinoLocalizationHr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -5443,6 +5530,9 @@ class CupertinoLocalizationHu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -5596,6 +5686,9 @@ class CupertinoLocalizationHy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -5749,6 +5842,9 @@ class CupertinoLocalizationId extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -5902,6 +5998,9 @@ class CupertinoLocalizationIs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6055,6 +6154,9 @@ class CupertinoLocalizationIt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6208,6 +6310,9 @@ class CupertinoLocalizationJa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6361,6 +6466,9 @@ class CupertinoLocalizationKa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6514,6 +6622,9 @@ class CupertinoLocalizationKk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6667,6 +6778,9 @@ class CupertinoLocalizationKm extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6820,6 +6934,9 @@ class CupertinoLocalizationKn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -6973,6 +7090,9 @@ class CupertinoLocalizationKo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -7126,6 +7246,9 @@ class CupertinoLocalizationKy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -7279,6 +7402,9 @@ class CupertinoLocalizationLo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -7432,6 +7558,9 @@ class CupertinoLocalizationLt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -7585,6 +7714,9 @@ class CupertinoLocalizationLv extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => r'$minute minūtes'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -7738,6 +7870,9 @@ class CupertinoLocalizationMk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -7891,6 +8026,9 @@ class CupertinoLocalizationMl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8044,6 +8182,9 @@ class CupertinoLocalizationMn extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8197,6 +8338,9 @@ class CupertinoLocalizationMr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8350,6 +8494,9 @@ class CupertinoLocalizationMs extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8503,6 +8650,9 @@ class CupertinoLocalizationMy extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8656,6 +8806,9 @@ class CupertinoLocalizationNb extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8809,6 +8962,9 @@ class CupertinoLocalizationNe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -8962,6 +9118,9 @@ class CupertinoLocalizationNl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -9115,6 +9274,9 @@ class CupertinoLocalizationNo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -9268,6 +9430,9 @@ class CupertinoLocalizationOr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -9421,6 +9586,9 @@ class CupertinoLocalizationPa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -9574,6 +9742,9 @@ class CupertinoLocalizationPl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -9727,6 +9898,9 @@ class CupertinoLocalizationPt extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -9916,6 +10090,9 @@ class CupertinoLocalizationRo extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -10069,6 +10246,9 @@ class CupertinoLocalizationRu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -10222,6 +10402,9 @@ class CupertinoLocalizationSi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -10375,6 +10558,9 @@ class CupertinoLocalizationSk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -10528,6 +10714,9 @@ class CupertinoLocalizationSl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -10681,6 +10870,9 @@ class CupertinoLocalizationSq extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -10834,6 +11026,9 @@ class CupertinoLocalizationSr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -11101,6 +11296,9 @@ class CupertinoLocalizationSv extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -11254,6 +11452,9 @@ class CupertinoLocalizationSw extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -11407,6 +11608,9 @@ class CupertinoLocalizationTa extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -11560,6 +11764,9 @@ class CupertinoLocalizationTe extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -11713,6 +11920,9 @@ class CupertinoLocalizationTh extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -11866,6 +12076,9 @@ class CupertinoLocalizationTl extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -12019,6 +12232,9 @@ class CupertinoLocalizationTr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -12172,6 +12388,9 @@ class CupertinoLocalizationUk extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -12325,6 +12544,9 @@ class CupertinoLocalizationUr extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -12478,6 +12700,9 @@ class CupertinoLocalizationUz extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -12631,6 +12856,9 @@ class CupertinoLocalizationVi extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -12784,6 +13012,9 @@ class CupertinoLocalizationZh extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; @@ -13084,6 +13315,9 @@ class CupertinoLocalizationZu extends GlobalCupertinoLocalizations { @override String? get datePickerMinuteSemanticsLabelZero => null; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuDismissLabel => 'Dismiss menu'; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index efff5a5f81e5a..5227d58f67bd7 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -329,6 +329,9 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisensies'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Kieslysbalkkieslys'; @@ -810,6 +813,9 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ፈቃዶች'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'የምናሌ አሞሌ ምናሌ'; @@ -1291,6 +1297,9 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'التراخيص'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'قائمة شريط القوائم'; @@ -1772,6 +1781,9 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'অনুজ্ঞাপত্ৰসমূহ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'মেনু বাৰ মেনু'; @@ -2253,6 +2265,9 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisenziyalar'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menyu paneli menyusu'; @@ -2734,6 +2749,9 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Ліцэнзіі'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Меню "Панэль меню"'; @@ -3215,6 +3233,9 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Лицензи'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Меню на лентата с менюта'; @@ -3696,6 +3717,9 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'লাইসেন্স'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'মেনু বার মেনু'; @@ -4177,6 +4201,9 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licence'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Meni trake menija'; @@ -4658,6 +4685,9 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Llicències'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menú de la barra de menú'; @@ -5139,6 +5169,9 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licence'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Nabídka na liště s nabídkou'; @@ -5620,6 +5653,9 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Trwyddedau'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Dewislen bar dewislen'; @@ -6101,6 +6137,9 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenser'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menuen for menulinjen'; @@ -6582,6 +6621,9 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lizenzen'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menü in der Menüleiste'; @@ -7127,6 +7169,9 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Άδειες'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Μενού γραμμής μενού'; @@ -7608,6 +7653,9 @@ class MaterialLocalizationEn extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenses'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu bar menu'; @@ -8823,6 +8871,9 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licencias'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menú de la barra de menú'; @@ -12687,6 +12738,9 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Litsentsid'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menüüriba menüü'; @@ -13168,6 +13222,9 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lizentziak'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu-barraren menua'; @@ -13649,6 +13706,9 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'مجوزها'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'منوی نوار منو'; @@ -14130,6 +14190,9 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisenssit'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Valikkopalkki'; @@ -14611,6 +14674,9 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Mga Lisensya'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu sa menu bar'; @@ -15092,6 +15158,9 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licences'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu de la barre de menu'; @@ -15715,6 +15784,9 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenzas'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menú da barra de menú'; @@ -16196,6 +16268,9 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lizenzen'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menü in der Menüleiste'; @@ -16677,6 +16752,9 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'લાઇસન્સ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'મેનૂ બાર મેનૂ'; @@ -17158,6 +17236,9 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'רישיונות'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'תפריט בסרגל התפריטים'; @@ -17639,6 +17720,9 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'लाइसेंस'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'मेन्यू बार का मेन्यू'; @@ -18120,6 +18204,9 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licence'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Izbornik trake izbornika'; @@ -18601,6 +18688,9 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licencek'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menüsor menüje'; @@ -19082,6 +19172,9 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Արտոնագրեր'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Ընտրացանկի գոտու ընտրացանկ'; @@ -19563,6 +19656,9 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisensi'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu panel menu'; @@ -20044,6 +20140,9 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Leyfi'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Valmyndarstika'; @@ -20525,6 +20624,9 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenze'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu barra dei menu'; @@ -21006,6 +21108,9 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ライセンス'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'メニューバーのメニュー'; @@ -21487,6 +21592,9 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ლიცენზიები'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'მენიუს ზოლის მენიუ'; @@ -21968,6 +22076,9 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Лицензиялар'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Мәзір жолағының мәзірі'; @@ -22449,6 +22560,9 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'អាជ្ញាបណ្ណ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'ម៉ឺនុយរបារម៉ឺនុយ'; @@ -22930,6 +23044,9 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { @override String get licensesPageTitle => '\u{caa}\u{cb0}\u{cb5}\u{cbe}\u{ca8}\u{c97}\u{cbf}\u{c97}\u{cb3}\u{cc1}'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => '\u{cae}\u{cc6}\u{ca8}\u{cc1}\u{20}\u{cac}\u{cbe}\u{cb0}\u{ccd}\u{200c}\u{20}\u{cae}\u{cc6}\u{ca8}\u{cc1}'; @@ -23411,6 +23528,9 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { @override String get licensesPageTitle => '라이선스'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => '메뉴 바 메뉴'; @@ -23892,6 +24012,9 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Уруксаттамалар'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Меню тилкеси менюсу'; @@ -24373,6 +24496,9 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ໃບອະນຸຍາດ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'ເມນູແຖບເມນູ'; @@ -24854,6 +24980,9 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licencijos'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Meniu juostos meniu'; @@ -25335,6 +25464,9 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licences'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Izvēļņu joslas izvēlne'; @@ -25816,6 +25948,9 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Лиценци'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Мени на лентата со мени'; @@ -26297,6 +26432,9 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ലൈസൻസുകൾ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'മെനു ബാർ മെനു'; @@ -26778,6 +26916,9 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Лиценз'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Цэсний талбарын цэс'; @@ -27259,6 +27400,9 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'परवाने'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'मेनू बार मेनू'; @@ -27740,6 +27884,9 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lesen'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu bar menu'; @@ -28221,6 +28368,9 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'လိုင်စင်များ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'မီနူးဘား မီနူး'; @@ -28702,6 +28852,9 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisenser'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Meny med menylinje'; @@ -29183,6 +29336,9 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'इजाजतपत्रहरू'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => '"मेनु बार" मेनु'; @@ -29664,6 +29820,9 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenties'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu van menubalk'; @@ -30145,6 +30304,9 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisenser'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Meny med menylinje'; @@ -30626,6 +30788,9 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ଲାଇସେନ୍ସଗୁଡ଼କ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'ମେନୁ ବାର ମେନୁ'; @@ -31107,6 +31272,9 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ਲਾਇਸੰਸ'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'ਮੀਨੂ ਬਾਰ ਮੀਨੂ'; @@ -31588,6 +31756,9 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licencje'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Pasek menu'; @@ -32069,6 +32240,9 @@ class MaterialLocalizationPs extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'جوازونه'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu bar menu'; @@ -32550,6 +32724,9 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenças'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu da barra de menus'; @@ -33182,6 +33359,9 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licențe'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Bară de meniu'; @@ -33663,6 +33843,9 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Лицензии'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Строка меню'; @@ -34144,6 +34327,9 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'බලපත්‍ර'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'මෙනු තීරු මෙනුව'; @@ -34625,6 +34811,9 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licencie'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Ponuka panela s ponukami'; @@ -35106,6 +35295,9 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licence'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Meni menijske vrstice'; @@ -35587,6 +35779,9 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licencat'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menyja e shiritit të menysë'; @@ -36068,6 +36263,9 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Лиценце'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Мени трака менија'; @@ -36863,6 +37061,9 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Licenser'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menyrad'; @@ -37344,6 +37545,9 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Leseni'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menyu ya upau wa menyu'; @@ -37825,6 +38029,9 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'உரிமங்கள்'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'மெனு பட்டியின் மெனு'; @@ -38306,6 +38513,9 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'లైసెన్స్‌లు'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'మెనూ బార్ మెనూ'; @@ -38787,6 +38997,9 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'ใบอนุญาต'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'เมนูในแถบเมนู'; @@ -39268,6 +39481,9 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Mga Lisensya'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menu sa menu bar'; @@ -39749,6 +39965,9 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Lisanslar'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menü çubuğu menüsü'; @@ -40230,6 +40449,9 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Ліцензії'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Панель меню'; @@ -40711,6 +40933,9 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'لائسنسز'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'مینیو بار کا مینیو'; @@ -41192,6 +41417,9 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Litsenziyalar'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Menyu paneli'; @@ -41673,6 +41901,9 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Giấy phép'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Trình đơn của thanh trình đơn'; @@ -42154,6 +42385,9 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { @override String get licensesPageTitle => '许可'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => '菜单栏的菜单'; @@ -43128,6 +43362,9 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { @override String get licensesPageTitle => 'Amalayisense'; + @override + String get lookUpButtonLabel => 'Look Up'; + @override String get menuBarMenuLabel => 'Imenyu yebha yemenyu'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_af.arb b/packages/flutter_localizations/lib/src/l10n/material_af.arb index 4ecc36d39d470..89f67a9e1a622 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_af.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_am.arb b/packages/flutter_localizations/lib/src/l10n/material_am.arb index 695ebefec6a07..f6e368abe9880 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_am.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ar.arb b/packages/flutter_localizations/lib/src/l10n/material_ar.arb index ecd809e069b4c..33ef73c5a6e8a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ar.arb @@ -152,5 +152,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_as.arb b/packages/flutter_localizations/lib/src/l10n/material_as.arb index 39471cbf3d28f..a744d5f2b29b3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_as.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_az.arb b/packages/flutter_localizations/lib/src/l10n/material_az.arb index 6067f4e1da6cd..5c1271381a4c3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_az.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_be.arb b/packages/flutter_localizations/lib/src/l10n/material_be.arb index 8f46fc18e887a..d8a19c8f8cc81 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_be.arb @@ -147,5 +147,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bg.arb b/packages/flutter_localizations/lib/src/l10n/material_bg.arb index e5ad3fc8e3b53..1cbba57b7ea47 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bg.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bn.arb b/packages/flutter_localizations/lib/src/l10n/material_bn.arb index 8bbc98ddfe74a..f5feaf34ab50f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bn.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bs.arb b/packages/flutter_localizations/lib/src/l10n/material_bs.arb index d4f65852b946c..3ea58673589e1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bs.arb @@ -145,5 +145,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ca.arb b/packages/flutter_localizations/lib/src/l10n/material_ca.arb index ca15e6cad3ca4..f2c3a743f4f9d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ca.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cs.arb b/packages/flutter_localizations/lib/src/l10n/material_cs.arb index 77a8a955ca4be..876fd054e2db6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cs.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cy.arb b/packages/flutter_localizations/lib/src/l10n/material_cy.arb index d91a63187f4f2..cc12773c1a1fe 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cy.arb @@ -152,5 +152,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "scanTextButtonLabel": "Scan text", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_da.arb b/packages/flutter_localizations/lib/src/l10n/material_da.arb index cfab5e7b0e184..171128b75a9d1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_da.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_de.arb b/packages/flutter_localizations/lib/src/l10n/material_de.arb index b70005ba37d4f..fa22cbeaded4d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_de.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_el.arb b/packages/flutter_localizations/lib/src/l10n/material_el.arb index 903ff89327cbf..67adc3873f7a9 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_el.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb index 511cc30c4ed1b..84ef000ea6ada 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb @@ -197,6 +197,11 @@ "description": "The label for scan text buttons and menu items for starting the insertion of text via OCR." }, + "lookUpButtonLabel": "Look Up", + "@lookUpButtonLabel": { + "description": "The label for the Look Up button and menu items on iOS." + }, + "okButtonLabel": "OK", "@okButtonLabel": { "description": "The label for OK buttons and menu items." diff --git a/packages/flutter_localizations/lib/src/l10n/material_es.arb b/packages/flutter_localizations/lib/src/l10n/material_es.arb index f4d7fd2d4baae..ccc011feaf9fe 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_et.arb b/packages/flutter_localizations/lib/src/l10n/material_et.arb index b7751aa65328a..8c26ccfcd6863 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_et.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_eu.arb b/packages/flutter_localizations/lib/src/l10n/material_eu.arb index cafff7255f7fc..afb1554a4824e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_eu.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fa.arb b/packages/flutter_localizations/lib/src/l10n/material_fa.arb index d4dd6e5b06bab..e5ab93e1eb0e6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fa.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index 649b1671d3359..be327d1cd3fe2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fil.arb b/packages/flutter_localizations/lib/src/l10n/material_fil.arb index 96c45b3285820..915496928d341 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fil.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr.arb b/packages/flutter_localizations/lib/src/l10n/material_fr.arb index 8d3795231c9d7..6c0c97837aeed 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fr.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gl.arb b/packages/flutter_localizations/lib/src/l10n/material_gl.arb index 4383f4ddbb440..ddfc0e830d09c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gl.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb index 15d7095df0dd5..7c14e4953e6c5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gu.arb b/packages/flutter_localizations/lib/src/l10n/material_gu.arb index cfcf9594584dd..b6a4911067059 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gu.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_he.arb b/packages/flutter_localizations/lib/src/l10n/material_he.arb index 63ad41324daca..a625567ce82f5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_he.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hi.arb b/packages/flutter_localizations/lib/src/l10n/material_hi.arb index 3104031e4b117..e2c94f427f20b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hi.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hr.arb b/packages/flutter_localizations/lib/src/l10n/material_hr.arb index 005ccce3578b2..64c42dede56c8 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hr.arb @@ -145,5 +145,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hu.arb b/packages/flutter_localizations/lib/src/l10n/material_hu.arb index 798524a354918..d17aa27aeb548 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hu.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hy.arb b/packages/flutter_localizations/lib/src/l10n/material_hy.arb index 030323d659e24..500f4a0d7e322 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hy.arb @@ -147,5 +147,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_id.arb b/packages/flutter_localizations/lib/src/l10n/material_id.arb index 85b954c03d225..5472e1cab7436 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_id.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_is.arb b/packages/flutter_localizations/lib/src/l10n/material_is.arb index 595971efd8a40..19bf822b72c5a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_is.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_it.arb b/packages/flutter_localizations/lib/src/l10n/material_it.arb index 605172effe21c..ee6ef2be0b21e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_it.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ja.arb b/packages/flutter_localizations/lib/src/l10n/material_ja.arb index 6fc3e26eebcbc..787e221ec897b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ja.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ka.arb b/packages/flutter_localizations/lib/src/l10n/material_ka.arb index febdb70b8fc4c..be14522256a9d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ka.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kk.arb b/packages/flutter_localizations/lib/src/l10n/material_kk.arb index 055ea2b636fe3..10659bf78178c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kk.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_km.arb b/packages/flutter_localizations/lib/src/l10n/material_km.arb index a34049213d67b..5e42cd5be6c71 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_km.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kn.arb b/packages/flutter_localizations/lib/src/l10n/material_kn.arb index cda53f81e57d4..bd834ddb70216 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kn.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0020\u0066\u006f\u0072\u0020\u006d\u006f\u0072\u0065\u0020\u0064\u0065\u0074\u0061\u0069\u006c\u0073", "expandedHint": "\u0043\u006f\u006c\u006c\u0061\u0070\u0073\u0065\u0064", "collapsedHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0065\u0064", - "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075" + "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075", + "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ko.arb b/packages/flutter_localizations/lib/src/l10n/material_ko.arb index c022f36f9316a..e810dc7b7765d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ko.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ky.arb b/packages/flutter_localizations/lib/src/l10n/material_ky.arb index 6b02039d9d1bd..562f451ba7e11 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ky.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lo.arb b/packages/flutter_localizations/lib/src/l10n/material_lo.arb index 1007feaebe2eb..b8e975951b475 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lo.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lt.arb b/packages/flutter_localizations/lib/src/l10n/material_lt.arb index f0e1503adc1fe..6821d2e7a12df 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lt.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lv.arb b/packages/flutter_localizations/lib/src/l10n/material_lv.arb index f61b4dab93529..bf75ba058e772 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lv.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mk.arb b/packages/flutter_localizations/lib/src/l10n/material_mk.arb index 47e2ffc5b466f..d275b5c283467 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mk.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ml.arb b/packages/flutter_localizations/lib/src/l10n/material_ml.arb index 1af3e2454f20f..420bed007a8b0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ml.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mn.arb b/packages/flutter_localizations/lib/src/l10n/material_mn.arb index 7fe558525649a..0ea6af64bbf97 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mn.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mr.arb b/packages/flutter_localizations/lib/src/l10n/material_mr.arb index 21ceeee708d77..97a345d5dc225 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mr.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ms.arb b/packages/flutter_localizations/lib/src/l10n/material_ms.arb index c8ef18c21455b..319c1f05e5ec4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ms.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_my.arb b/packages/flutter_localizations/lib/src/l10n/material_my.arb index 969b66435df97..abebb39aa0523 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_my.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nb.arb b/packages/flutter_localizations/lib/src/l10n/material_nb.arb index 27ab7e9e93212..6dcfbd771365f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nb.arb @@ -140,5 +140,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ne.arb b/packages/flutter_localizations/lib/src/l10n/material_ne.arb index 3721981ee1b6d..a1568dbdc313b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ne.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nl.arb b/packages/flutter_localizations/lib/src/l10n/material_nl.arb index 04e4774d90327..b42de577e8cfb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nl.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_no.arb b/packages/flutter_localizations/lib/src/l10n/material_no.arb index 2cceaff489886..102fa6b3c0980 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_no.arb @@ -140,5 +140,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_or.arb b/packages/flutter_localizations/lib/src/l10n/material_or.arb index e0af6322b0ec0..df12f1862ece4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_or.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pa.arb b/packages/flutter_localizations/lib/src/l10n/material_pa.arb index 7ec370e66b538..0b5384fb56dc2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pa.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pl.arb b/packages/flutter_localizations/lib/src/l10n/material_pl.arb index 114ce4e7b2b6c..b2f1fd2f2da93 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pl.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ps.arb b/packages/flutter_localizations/lib/src/l10n/material_ps.arb index 6f51f1fdb57e8..f9af707827d70 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ps.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ps.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb index a85ca3885a760..b68e7658efebe 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb @@ -144,5 +144,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ro.arb b/packages/flutter_localizations/lib/src/l10n/material_ro.arb index 6731bb241c094..4f440ffd017de 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ro.arb @@ -146,5 +146,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ru.arb b/packages/flutter_localizations/lib/src/l10n/material_ru.arb index e682daadbfa64..c1a223c043102 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ru.arb @@ -149,5 +149,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_si.arb b/packages/flutter_localizations/lib/src/l10n/material_si.arb index b71bf1d94f7a0..6d987a15fd146 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_si.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sk.arb b/packages/flutter_localizations/lib/src/l10n/material_sk.arb index bcbea02c2288d..355a42abb835d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sk.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sl.arb b/packages/flutter_localizations/lib/src/l10n/material_sl.arb index 059e5033a9c59..529e6b790330d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sl.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sq.arb b/packages/flutter_localizations/lib/src/l10n/material_sq.arb index c5c93fe2d931d..a357d1bec50b6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sq.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sr.arb b/packages/flutter_localizations/lib/src/l10n/material_sr.arb index f370d680f954b..9e7517049452c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sr.arb @@ -145,5 +145,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sv.arb b/packages/flutter_localizations/lib/src/l10n/material_sv.arb index 5bfd5156aa57c..7a86f4d21113f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sv.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sw.arb b/packages/flutter_localizations/lib/src/l10n/material_sw.arb index 79eb4868c0db7..3bb66ec41a4cf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sw.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ta.arb b/packages/flutter_localizations/lib/src/l10n/material_ta.arb index 25e586e735ab0..0670820f74d52 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ta.arb @@ -143,5 +143,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_te.arb b/packages/flutter_localizations/lib/src/l10n/material_te.arb index aecf93193d730..61421700e6ffb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_te.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_th.arb b/packages/flutter_localizations/lib/src/l10n/material_th.arb index 7fa35000392be..b00364a340d6c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_th.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tl.arb b/packages/flutter_localizations/lib/src/l10n/material_tl.arb index 96c45b3285820..915496928d341 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tl.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tr.arb b/packages/flutter_localizations/lib/src/l10n/material_tr.arb index 3e3a129722319..521444307879e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tr.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uk.arb b/packages/flutter_localizations/lib/src/l10n/material_uk.arb index ef73b586a8ad2..ea8064eaf5801 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uk.arb @@ -148,5 +148,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ur.arb b/packages/flutter_localizations/lib/src/l10n/material_ur.arb index fa092aefce639..ead97a99eec6d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ur.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uz.arb b/packages/flutter_localizations/lib/src/l10n/material_uz.arb index cb62c2a556a6f..142c03e2e751a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uz.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_vi.arb b/packages/flutter_localizations/lib/src/l10n/material_vi.arb index a33f5cbb8aeae..f55143dc197ba 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_vi.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh.arb b/packages/flutter_localizations/lib/src/l10n/material_zh.arb index aa48e08adc600..51fa714be58b5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh.arb @@ -142,5 +142,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zu.arb b/packages/flutter_localizations/lib/src/l10n/material_zu.arb index ea76791c9fa89..4966a33debfc3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zu.arb @@ -141,5 +141,6 @@ "expansionTileCollapsedTapHint": "Expand for more details", "expandedHint": "Collapsed", "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu" + "menuDismissLabel": "Dismiss menu", + "lookUpButtonLabel": "Look Up" } From 47b188ec22bbf7f9aba2a9893f0f039c2d26ff63 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 2 Aug 2023 14:14:59 -0700 Subject: [PATCH 0508/1547] Mention that the widget tree is not disposed on exit (#131637) --- packages/flutter/lib/src/widgets/binding.dart | 14 ++++++++++++++ packages/flutter/lib/src/widgets/framework.dart | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 7c8bf3b8df209..900d34fe77232 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -1152,6 +1152,20 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// /// Initializes the binding using [WidgetsFlutterBinding] if necessary. /// +/// ## Application shutdown +/// +/// This widget tree is not torn down when the application shuts down, because +/// there is no way to predict when that will happen. For example, a user could +/// physically remove power from their device, or the application could crash +/// unexpectedly, or the malware on the device could forcibly terminate the +/// process. +/// +/// Applications are responsible for ensuring that they are well-behaved +/// even in the face of a rapid unscheduled termination. +/// +/// To artificially cause the entire widget tree to be disposed, consider +/// calling [runApp] with a widget such as [SizedBox.shrink]. +/// /// See also: /// /// * [WidgetsBinding.attachRootWidget], which creates the root widget for the diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 8628b57ba4a82..abd202dd943ba 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1238,6 +1238,20 @@ abstract class State with Diagnosticable { /// Implementations of this method should end with a call to the inherited /// method, as in `super.dispose()`. /// + /// ## Application shutdown + /// + /// This method is _not_ invoked when the application shuts down, because + /// there is no way to predict when that will happen. For example, a user's + /// battery could catch fire, or the user could drop the device into a + /// swimming pool, or the operating system could unilaterally terminate the + /// application process due to memory pressure. + /// + /// Applications are responsible for ensuring that they are well-behaved + /// even in the face of a rapid unscheduled termination. + /// + /// To artificially cause the entire widget tree to be disposed, consider + /// calling [runApp] with a widget such as [SizedBox.shrink]. + /// /// See also: /// /// * [deactivate], which is called prior to [dispose]. From 9cda30923fd6ba4819cf990dbe4bba7b6544c505 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 2 Aug 2023 14:16:46 -0700 Subject: [PATCH 0509/1547] Replace TextField.canRequestFocus with TextField.focusNode.canRequestFocus (#130164) Simplifying the TextField API. --- .../lib/src/material/dropdown_menu.dart | 23 +++++++++++++++++-- .../flutter/lib/src/material/text_field.dart | 20 ++++++++++++---- .../test/material/dropdown_menu_test.dart | 7 +++--- .../test/material/text_field_test.dart | 5 +++- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 51a972a3398a6..53003486f6b1c 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; +import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -309,6 +310,7 @@ class _DropdownMenuState extends State> { int? currentHighlight; double? leadingPadding; bool _menuHasEnabledItem = false; + late final FocusNode _focusNode; @override void initState() { @@ -326,6 +328,18 @@ class _DropdownMenuState extends State> { TextSelection.collapsed(offset: _textEditingController.text.length); } refreshLeadingPadding(); + _focusNode = FocusNode( + canRequestFocus: canRequestFocus(), + ); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final bool widgetCanRequestFocus = canRequestFocus(); + if (widgetCanRequestFocus != _focusNode.canRequestFocus) { + _focusNode.canRequestFocus = widgetCanRequestFocus; + } } @override @@ -353,6 +367,10 @@ class _DropdownMenuState extends State> { TextSelection.collapsed(offset: _textEditingController.text.length); } } + final bool widgetCanRequestFocus = canRequestFocus(); + if (widgetCanRequestFocus != _focusNode.canRequestFocus) { + _focusNode.canRequestFocus = widgetCanRequestFocus; + } } bool canRequestFocus() { @@ -360,7 +378,7 @@ class _DropdownMenuState extends State> { return widget.requestFocusOnTap!; } - switch (Theme.of(context).platform) { + switch (defaultTargetPlatform) { case TargetPlatform.iOS: case TargetPlatform.android: case TargetPlatform.fuchsia: @@ -592,7 +610,8 @@ class _DropdownMenuState extends State> { final Widget textField = TextField( key: _anchorKey, mouseCursor: effectiveMouseCursor, - canRequestFocus: canRequestFocus(), + focusNode: _focusNode, + readOnly: !canRequestFocus(), enableInteractiveSelection: canRequestFocus(), textAlignVertical: TextAlignVertical.center, style: effectiveTextStyle, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index aa8f715bf905b..7d6ea5b865ac4 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -314,6 +314,10 @@ class TextField extends StatefulWidget { this.scribbleEnabled = true, this.enableIMEPersonalizedLearning = true, this.contextMenuBuilder = _defaultContextMenuBuilder, + @Deprecated( + 'Use `focusNode` instead. ' + 'This feature was deprecated after v3.12.0-14.0.pre.', + ) this.canRequestFocus = true, this.spellCheckConfiguration, this.magnifierConfiguration, @@ -776,6 +780,10 @@ class TextField extends StatefulWidget { /// Defaults to true. If false, the text field will not request focus /// when tapped, or when its context menu is displayed. If false it will not /// be possible to move the focus to the text field with tab key. + @Deprecated( + 'Use `focusNode` instead. ' + 'This feature was deprecated after v3.12.0-14.0.pre.', + ) final bool canRequestFocus; /// {@macro flutter.widgets.undoHistory.controller} @@ -1026,7 +1034,9 @@ class _TextFieldState extends State with RestorationMixin implements if (widget.controller == null) { _createLocalController(); } - _effectiveFocusNode.canRequestFocus = widget.canRequestFocus && _isEnabled; + _effectiveFocusNode.canRequestFocus = widget.focusNode == null + ? widget.canRequestFocus && _isEnabled + : widget.focusNode!.canRequestFocus && _isEnabled; _effectiveFocusNode.addListener(_handleFocusChanged); } @@ -1034,7 +1044,9 @@ class _TextFieldState extends State with RestorationMixin implements final NavigationMode mode = MediaQuery.maybeNavigationModeOf(context) ?? NavigationMode.traditional; switch (mode) { case NavigationMode.traditional: - return widget.canRequestFocus && _isEnabled; + return widget.focusNode == null + ? widget.canRequestFocus && _isEnabled + : widget.focusNode!.canRequestFocus && _isEnabled; case NavigationMode.directional: return true; } @@ -1086,8 +1098,8 @@ class _TextFieldState extends State with RestorationMixin implements void _createLocalController([TextEditingValue? value]) { assert(_controller == null); _controller = value == null - ? RestorableTextEditingController() - : RestorableTextEditingController.fromValue(value); + ? RestorableTextEditingController() + : RestorableTextEditingController.fromValue(value); if (!restorePending) { _registerController(); } diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index a721cfdb87a2b..898c835f9272a 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -1232,7 +1232,7 @@ void main() { final Finder textFieldFinder = find.byType(TextField); final TextField result = tester.widget(textFieldFinder); - expect(result.canRequestFocus, false); + expect(result.focusNode!.canRequestFocus, false); }, variant: TargetPlatformVariant.mobile()); testWidgets('The text input field should be focused on desktop platforms ' @@ -1300,7 +1300,7 @@ void main() { final Finder textFieldFinder1 = find.byType(TextField); final TextField textField1 = tester.widget(textFieldFinder1); - expect(textField1.canRequestFocus, false); + expect(textField1.focusNode!.canRequestFocus, false); // Open the dropdown menu. await tester.tap(textFieldFinder1); await tester.pump(); @@ -1329,7 +1329,7 @@ void main() { final Finder textFieldFinder = find.byType(TextField); final TextField textField = tester.widget(textFieldFinder); - expect(textField.canRequestFocus, false); + expect(textField.focusNode!.canRequestFocus, false); final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); await gesture.moveTo(tester.getCenter(textFieldFinder)); @@ -1526,7 +1526,6 @@ void main() { // Item 5 should show up. expect(find.text('Item 5').hitTestable(), findsOneWidget); }); - } enum TestMenu { diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 3998f97500323..8339d81cd9023 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -15568,6 +15568,7 @@ void main() { expect(focusNode.hasFocus, isTrue); // Set canRequestFocus to false: the text field cannot be focused when it is tapped/long pressed. + focusNode.canRequestFocus = false; await tester.pumpWidget( boilerplate( child: TextField( @@ -15749,7 +15750,9 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets('Right clicking cannot request focus if canRequestFocus is false', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + final FocusNode focusNode = FocusNode( + canRequestFocus: false, + ); final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( From 0ad45f2421134a103e797337d649cd347d61432f Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 2 Aug 2023 16:57:15 -0700 Subject: [PATCH 0510/1547] Update stack_frame.dart to parse unexpected error format to null. (#131786) Fixes https://github.com/flutter/flutter/issues/131627 Originally this code sometimes was returning null and sometimes was failing, when stack frame is in unexpected format. This PR updates for one of the code paths from failing to returning null. --- .../lib/src/foundation/stack_frame.dart | 30 +++++++++++++------ .../test/foundation/stack_frame_test.dart | 4 +++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/foundation/stack_frame.dart b/packages/flutter/lib/src/foundation/stack_frame.dart index 5e22e1e82ac0f..fc126821fe9f7 100644 --- a/packages/flutter/lib/src/foundation/stack_frame.dart +++ b/packages/flutter/lib/src/foundation/stack_frame.dart @@ -82,28 +82,38 @@ class StackFrame { .toList(); } - static StackFrame? _parseWebFrame(String line) { + /// Parses a single [StackFrame] from a line of a [StackTrace]. + /// + /// Returns null if format is not as expected. + static StackFrame? _tryParseWebFrame(String line) { if (kDebugMode) { - return _parseWebDebugFrame(line); + return _tryParseWebDebugFrame(line); } else { - return _parseWebNonDebugFrame(line); + return _tryParseWebNonDebugFrame(line); } } - static StackFrame _parseWebDebugFrame(String line) { + /// Parses a single [StackFrame] from a line of a [StackTrace]. + /// + /// Returns null if format is not as expected. + static StackFrame? _tryParseWebDebugFrame(String line) { // This RegExp is only partially correct for flutter run/test differences. // https://github.com/flutter/flutter/issues/52685 final bool hasPackage = line.startsWith('package'); final RegExp parser = hasPackage ? RegExp(r'^(package.+) (\d+):(\d+)\s+(.+)$') : RegExp(r'^(.+) (\d+):(\d+)\s+(.+)$'); - Match? match = parser.firstMatch(line); - assert(match != null, 'Expected $line to match $parser.'); - match = match!; + + final Match? match = parser.firstMatch(line); + + if (match == null) { + return null; + } String package = ''; String packageScheme = ''; String packagePath = ''; + if (hasPackage) { packageScheme = 'package'; final Uri packageUri = Uri.parse(match.group(1)!); @@ -132,7 +142,7 @@ class StackFrame { // Parses `line` as a stack frame in profile and release Web builds. If not // recognized as a stack frame, returns null. - static StackFrame? _parseWebNonDebugFrame(String line) { + static StackFrame? _tryParseWebNonDebugFrame(String line) { final Match? match = _webNonDebugFramePattern.firstMatch(line); if (match == null) { // On the Web in non-debug builds the stack trace includes the exception @@ -169,6 +179,8 @@ class StackFrame { } /// Parses a single [StackFrame] from a single line of a [StackTrace]. + /// + /// Returns null if format is not as expected. static StackFrame? fromStackTraceLine(String line) { if (line == '') { return asynchronousSuspension; @@ -185,7 +197,7 @@ class StackFrame { // Web frames. if (!line.startsWith('#')) { - return _parseWebFrame(line); + return _tryParseWebFrame(line); } final RegExp parser = RegExp(r'^#(\d+) +(.+) \((.+?):?(\d+){0,1}:?(\d+){0,1}\)$'); diff --git a/packages/flutter/test/foundation/stack_frame_test.dart b/packages/flutter/test/foundation/stack_frame_test.dart index 63138c7352e6a..e3052188cb8b0 100644 --- a/packages/flutter/test/foundation/stack_frame_test.dart +++ b/packages/flutter/test/foundation/stack_frame_test.dart @@ -99,6 +99,10 @@ void main() { ), ); }); + + test('Parses to null for wrong format.', () { + expect(StackFrame.fromStackTraceLine('wrong stack trace format'), null); + }); } const String stackString = ''' From b3a4decda677012b8f7cfea39b7741d707c82693 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 2 Aug 2023 19:18:13 -0500 Subject: [PATCH 0511/1547] Assert against infinite values of control points in CatmullRomSpline (#131820) When providing infinite values for the control points of CatmullRomSpline, a StackOverflowError occurs. This asserts against that and provides a helpful error message. Fixes https://github.com/flutter/flutter/issues/131246 --- .../flutter/lib/src/animation/curves.dart | 21 ++++++++++ .../flutter/test/animation/curves_test.dart | 40 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/packages/flutter/lib/src/animation/curves.dart b/packages/flutter/lib/src/animation/curves.dart index d824c8221ace3..0c54a653f0361 100644 --- a/packages/flutter/lib/src/animation/curves.dart +++ b/packages/flutter/lib/src/animation/curves.dart @@ -705,6 +705,27 @@ class CatmullRomSpline extends Curve2D { Offset? startHandle, Offset? endHandle, }) { + assert( + startHandle == null || startHandle.isFinite, + 'The provided startHandle of CatmullRomSpline must be finite. The ' + 'startHandle given was $startHandle.' + ); + assert( + endHandle == null || endHandle.isFinite, + 'The provided endHandle of CatmullRomSpline must be finite. The endHandle ' + 'given was $endHandle.' + ); + assert(() { + for (int index = 0; index < controlPoints.length; index++) { + if (!controlPoints[index].isFinite) { + throw FlutterError( + 'The provided CatmullRomSpline control point at index $index is not ' + 'finite. The control point given was ${controlPoints[index]}.' + ); + } + } + return true; + }()); // If not specified, select the first and last control points (which are // handles: they are not intersected by the resulting curve) so that they // extend the first and last segments, respectively. diff --git a/packages/flutter/test/animation/curves_test.dart b/packages/flutter/test/animation/curves_test.dart index 62f426870f55e..f7b0757fd5d8e 100644 --- a/packages/flutter/test/animation/curves_test.dart +++ b/packages/flutter/test/animation/curves_test.dart @@ -305,6 +305,28 @@ void main() { expect(() { CatmullRomSpline(const [Offset.zero, Offset.zero, Offset.zero, Offset.zero], tension: 2.0); }, throwsAssertionError); + expect(() { + CatmullRomSpline( + const [Offset(double.infinity, 0.0), Offset.zero, Offset.zero, Offset.zero], + ).generateSamples(); + }, throwsAssertionError); + expect(() { + CatmullRomSpline( + const [Offset(0.0, double.infinity), Offset.zero, Offset.zero, Offset.zero], + ).generateSamples(); + }, throwsAssertionError); + expect(() { + CatmullRomSpline( + startHandle: const Offset(0.0, double.infinity), + const [Offset.zero, Offset.zero, Offset.zero, Offset.zero], + ).generateSamples(); + }, throwsAssertionError); + expect(() { + CatmullRomSpline( + endHandle: const Offset(0.0, double.infinity), + const [Offset.zero, Offset.zero, Offset.zero, Offset.zero], + ).generateSamples(); + }, throwsAssertionError); }); test('CatmullRomSpline interpolates values properly when precomputed', () { @@ -353,6 +375,24 @@ void main() { expect(() { CatmullRomSpline.precompute(const [Offset.zero, Offset.zero, Offset.zero, Offset.zero], tension: 2.0); }, throwsAssertionError); + expect(() { + CatmullRomSpline.precompute(const [Offset(double.infinity, 0.0), Offset.zero, Offset.zero, Offset.zero]); + }, throwsAssertionError); + expect(() { + CatmullRomSpline.precompute(const [Offset(0.0, double.infinity), Offset.zero, Offset.zero, Offset.zero]); + }, throwsAssertionError); + expect(() { + CatmullRomSpline.precompute( + startHandle: const Offset(0.0, double.infinity), + const [Offset.zero, Offset.zero, Offset.zero, Offset.zero], + ); + }, throwsAssertionError); + expect(() { + CatmullRomSpline.precompute( + endHandle: const Offset(0.0, double.infinity), + const [Offset.zero, Offset.zero, Offset.zero, Offset.zero], + ); + }, throwsAssertionError); }); test('CatmullRomCurve interpolates given points correctly', () { From c00d241938b1b1ddf09121ce7e1cc62873f7af91 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 02:56:52 -0400 Subject: [PATCH 0512/1547] Manual roll Flutter Engine from 9304c0074d29 to 4c1157b9da54 (24 revisions) (#131830) Manual roll requested by jacksongardner@google.com https://github.com/flutter/engine/compare/9304c0074d29...4c1157b9da54 2023-08-03 jacksongardner@google.com Revert Android Hardware Texture PRs (flutter/engine#44310) 2023-08-03 skia-flutter-autoroll@skia.org Roll Dart SDK from 87df1bbcea5e to 3b9af2825d47 (2 revisions) (flutter/engine#44308) 2023-08-03 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Hx7ap5qcoqRIknnnG... to WwFjJuQF_rpToCYPJ... (flutter/engine#44306) 2023-08-03 jason-simmons@users.noreply.github.com Check whether the lookup of android.hardware.HardwareBuffer found a class (flutter/engine#44304) 2023-08-02 bdero@google.com [Impeller] Add placeholder filter input. (flutter/engine#44290) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from 6c1bab070220 to 6a09e41ce6ea (1 revision) (flutter/engine#44300) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from fd5bd67d532f to c0956a252f30 (1 revision) (flutter/engine#44296) 2023-08-02 chris@bracken.jp [iOS] Fix use-after-free in setBinaryMessenger (flutter/engine#44294) 2023-08-02 louiseh0313@gmail.com Add Search Web to selection controls on iOS (flutter/engine#43324) 2023-08-02 jason-simmons@users.noreply.github.com Improve logging in the clang-tidy script (flutter/engine#44228) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from 335c6b86d70b to 6c1bab070220 (1 revision) (flutter/engine#44291) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 25f5a32367ad to fd5bd67d532f (2 revisions) (flutter/engine#44289) 2023-08-02 john@johnmccutchan.com Be sure to clear exceptions after a failed JNI lookup (flutter/engine#44293) 2023-08-02 derekx@google.com Handle deprecation of Dart_TimelineEvent Embedder API (flutter/engine#42497) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from ccc17f784e5d to 25f5a32367ad (4 revisions) (flutter/engine#44283) 2023-08-02 skia-flutter-autoroll@skia.org Roll ANGLE from 01ee134bb223 to 335c6b86d70b (2 revisions) (flutter/engine#44287) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 7104d0e8863f to ccc17f784e5d (2 revisions) (flutter/engine#44279) 2023-08-02 41930132+hellohuanlin@users.noreply.github.com [ios][autocorrection]disable auto-correction highlight in iOS 17 (flutter/engine#44176) 2023-08-02 john@johnmccutchan.com Reland Introduce TextureRegistry.ImageTexture and HardwareBufferExternalTextureGL (flutter/engine#44278) 2023-08-02 skia-flutter-autoroll@skia.org Roll Dart SDK from afbaf4216fc8 to 87df1bbcea5e (1 revision) (flutter/engine#44276) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 93764a98b866 to 7104d0e8863f (4 revisions) (flutter/engine#44273) 2023-08-02 jason-simmons@users.noreply.github.com [Impeller] Fix leak of wrapped TextureMTL objects in the Metal embedder API (flutter/engine#44245) 2023-08-02 737941+loic-sharma@users.noreply.github.com Revert "Listen to window notifications to update application lifecycle" (flutter/engine#44275) 2023-08-02 skia-flutter-autoroll@skia.org Roll Skia from 514c66ce0471 to 93764a98b866 (1 revision) (flutter/engine#44270) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from Hx7ap5qcoqRI to WwFjJuQF_rpT If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3da89ffabb5e2..fa1fc8dc78f0b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9304c0074d290e2e1c64578e33f393e05f09f14d +4c1157b9da54724002993e59a76a4f4e40253b12 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 660bf09f4f2e4..e16f31716a14d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Hx7ap5qcoqRIknnnGW8qLcMHWOj04Yw6urras7NxW_0C +WwFjJuQF_rpToCYPJ3yjlNSYb07ecmP2dIyh7of3O9MC From b4c75017d813a46475cc4f66ad61ab6ba4ec10c1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 11:17:19 -0400 Subject: [PATCH 0513/1547] Manual roll Flutter Engine from 4c1157b9da54 to 46f3e099ad04 (3 revisions) (#131848) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/4c1157b9da54...46f3e099ad04 2023-08-03 skia-flutter-autoroll@skia.org Roll Dart SDK from 3b9af2825d47 to fac111d4acb3 (2 revisions) (flutter/engine#44315) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from d9d5ef855d75 to b81084128325 (2 revisions) (flutter/engine#44313) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from c0956a252f30 to d9d5ef855d75 (2 revisions) (flutter/engine#44311) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fa1fc8dc78f0b..adc806f526c3a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4c1157b9da54724002993e59a76a4f4e40253b12 +46f3e099ad045ec9aaa976ba9b4852209d348958 From 22f029e5824629ed58ef37e948da1c63c062526d Mon Sep 17 00:00:00 2001 From: Mahmoud Zayad <60728110+MahmoudZayad@users.noreply.github.com> Date: Thu, 3 Aug 2023 10:50:59 -0500 Subject: [PATCH 0514/1547] Remove target Staging_build_linux framework_tests_misc (#126959) I deleted the target mentioned in the issue listed below. This is my first time contributing to open source please explain if I did anything wrong in the process or wrong with the changes. Best *List which issues are fixed by this PR. You must list at least one issue.* Resolves [#126278](https://github.com/flutter/flutter/issues/126278) --- .ci.yaml | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 74e9d417f308d..0dc8e4069badc 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2601,40 +2601,6 @@ targets: validation: analyze validation_name: Analyze - - name: Staging_build_linux framework_tests_misc - presubmit: false - bringup: true - recipe: flutter/flutter_drone - timeout: 60 - properties: - ignore_flakiness: "true" - dependencies: >- - [ - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, - {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "cmake", "version": "build_id:8787856497187628321"}, - {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "android_sdk", "version": "version:33v6"} - ] - shard: framework_tests - subshard: misc - tags: > - ["framework", "hostonly", "shard", "linux"] - runIf: - - dev/** - - examples/api/** - - packages/flutter/** - - packages/flutter_driver/** - - packages/integration_test/** - - packages/flutter_localizations/** - - packages/fuchsia_remote_debug_protocol/** - - packages/flutter_test/** - - packages/flutter_goldens/** - - packages/flutter_tools/** - - bin/** - - .ci.yaml - - name: Mac_benchmark animated_complex_opacity_perf_macos__e2e_summary presubmit: false recipe: devicelab/devicelab_drone From 3d74b0b737ddbef2df31aef7ea4d476c21937075 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 3 Aug 2023 09:15:14 -0700 Subject: [PATCH 0515/1547] Adds a11y assessment sample app (#131716) This app will be use for a11y assessments. See [design doc](http://go/flutter-gar-reporting-q3-2023) (internal only) --- dev/a11y_assessments/.gitignore | 44 ++ dev/a11y_assessments/.metadata | 45 ++ dev/a11y_assessments/README.md | 3 + dev/a11y_assessments/analysis_options.yaml | 1 + dev/a11y_assessments/android/.gitignore | 13 + dev/a11y_assessments/android/app/build.gradle | 71 ++ .../android/app/src/debug/AndroidManifest.xml | 11 + .../android/app/src/main/AndroidManifest.xml | 37 + .../example/a11y_assessments/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 16 + .../main/res/drawable/launch_background.xml | 16 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 22 + .../app/src/main/res/values/styles.xml | 22 + .../app/src/profile/AndroidManifest.xml | 11 + dev/a11y_assessments/android/build.gradle | 35 + .../android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + dev/a11y_assessments/android/settings.gradle | 24 + dev/a11y_assessments/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../ios/Flutter/Debug.xcconfig | 1 + .../ios/Flutter/Release.xcconfig | 1 + .../ios/Runner.xcodeproj/project.pbxproj | 617 ++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../ios/Runner/AppDelegate.swift | 17 + .../AppIcon.appiconset/Contents.json | 122 +++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + dev/a11y_assessments/ios/Runner/Info.plist | 49 ++ .../ios/Runner/Runner-Bridging-Header.h | 5 + .../ios/RunnerTests/RunnerTests.swift | 16 + dev/a11y_assessments/lib/main.dart | 65 ++ .../lib/use_cases/check_box_list_tile.dart | 46 ++ .../check_box_list_tile_disabled.dart | 47 ++ .../lib/use_cases/use_cases.dart | 19 + dev/a11y_assessments/linux/.gitignore | 1 + dev/a11y_assessments/linux/CMakeLists.txt | 139 ++++ .../linux/flutter/CMakeLists.txt | 88 +++ dev/a11y_assessments/linux/main.cc | 10 + dev/a11y_assessments/linux/my_application.cc | 108 +++ dev/a11y_assessments/linux/my_application.h | 22 + dev/a11y_assessments/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 1 + .../macos/Flutter/Flutter-Release.xcconfig | 1 + .../macos/Runner.xcodeproj/project.pbxproj | 695 ++++++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../macos/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 68 ++ .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 46993 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 3276 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 1429 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 5933 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1243 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 14800 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 1874 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 +++++++++ .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 12 + dev/a11y_assessments/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 19 + .../macos/Runner/Release.entitlements | 8 + .../macos/RunnerTests/RunnerTests.swift | 16 + dev/a11y_assessments/pubspec.yaml | 38 + .../test/accessibility_guideline_test.dart | 23 + dev/a11y_assessments/web/favicon.png | Bin 0 -> 917 bytes dev/a11y_assessments/web/icons/Icon-192.png | Bin 0 -> 5292 bytes dev/a11y_assessments/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../web/icons/Icon-maskable-192.png | Bin 0 -> 5292 bytes .../web/icons/Icon-maskable-512.png | Bin 0 -> 8252 bytes dev/a11y_assessments/web/index.html | 63 ++ dev/a11y_assessments/web/manifest.json | 35 + dev/a11y_assessments/windows/.gitignore | 17 + dev/a11y_assessments/windows/CMakeLists.txt | 102 +++ .../windows/flutter/CMakeLists.txt | 104 +++ .../windows/runner/CMakeLists.txt | 40 + dev/a11y_assessments/windows/runner/Runner.rc | 121 +++ .../windows/runner/flutter_window.cpp | 75 ++ .../windows/runner/flutter_window.h | 37 + dev/a11y_assessments/windows/runner/main.cpp | 47 ++ .../windows/runner/resource.h | 20 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 787 bytes .../windows/runner/runner.exe.manifest | 20 + dev/a11y_assessments/windows/runner/utils.cpp | 69 ++ dev/a11y_assessments/windows/runner/utils.h | 23 + .../windows/runner/win32_window.cpp | 292 ++++++++ .../windows/runner/win32_window.h | 106 +++ dev/bots/test.dart | 4 + 124 files changed, 4656 insertions(+) create mode 100644 dev/a11y_assessments/.gitignore create mode 100644 dev/a11y_assessments/.metadata create mode 100644 dev/a11y_assessments/README.md create mode 100644 dev/a11y_assessments/analysis_options.yaml create mode 100644 dev/a11y_assessments/android/.gitignore create mode 100644 dev/a11y_assessments/android/app/build.gradle create mode 100644 dev/a11y_assessments/android/app/src/debug/AndroidManifest.xml create mode 100644 dev/a11y_assessments/android/app/src/main/AndroidManifest.xml create mode 100644 dev/a11y_assessments/android/app/src/main/kotlin/com/example/a11y_assessments/MainActivity.kt create mode 100644 dev/a11y_assessments/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 dev/a11y_assessments/android/app/src/main/res/drawable/launch_background.xml create mode 100644 dev/a11y_assessments/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 dev/a11y_assessments/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 dev/a11y_assessments/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 dev/a11y_assessments/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 dev/a11y_assessments/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 dev/a11y_assessments/android/app/src/main/res/values-night/styles.xml create mode 100644 dev/a11y_assessments/android/app/src/main/res/values/styles.xml create mode 100644 dev/a11y_assessments/android/app/src/profile/AndroidManifest.xml create mode 100644 dev/a11y_assessments/android/build.gradle create mode 100644 dev/a11y_assessments/android/gradle.properties create mode 100644 dev/a11y_assessments/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 dev/a11y_assessments/android/settings.gradle create mode 100644 dev/a11y_assessments/ios/.gitignore create mode 100644 dev/a11y_assessments/ios/Flutter/AppFrameworkInfo.plist create mode 100644 dev/a11y_assessments/ios/Flutter/Debug.xcconfig create mode 100644 dev/a11y_assessments/ios/Flutter/Release.xcconfig create mode 100644 dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj create mode 100644 dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 dev/a11y_assessments/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 dev/a11y_assessments/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 dev/a11y_assessments/ios/Runner/AppDelegate.swift create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 dev/a11y_assessments/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 dev/a11y_assessments/ios/Runner/Base.lproj/Main.storyboard create mode 100644 dev/a11y_assessments/ios/Runner/Info.plist create mode 100644 dev/a11y_assessments/ios/Runner/Runner-Bridging-Header.h create mode 100644 dev/a11y_assessments/ios/RunnerTests/RunnerTests.swift create mode 100644 dev/a11y_assessments/lib/main.dart create mode 100644 dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart create mode 100644 dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart create mode 100644 dev/a11y_assessments/lib/use_cases/use_cases.dart create mode 100644 dev/a11y_assessments/linux/.gitignore create mode 100644 dev/a11y_assessments/linux/CMakeLists.txt create mode 100644 dev/a11y_assessments/linux/flutter/CMakeLists.txt create mode 100644 dev/a11y_assessments/linux/main.cc create mode 100644 dev/a11y_assessments/linux/my_application.cc create mode 100644 dev/a11y_assessments/linux/my_application.h create mode 100644 dev/a11y_assessments/macos/.gitignore create mode 100644 dev/a11y_assessments/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 dev/a11y_assessments/macos/Flutter/Flutter-Release.xcconfig create mode 100644 dev/a11y_assessments/macos/Runner.xcodeproj/project.pbxproj create mode 100644 dev/a11y_assessments/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 dev/a11y_assessments/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 dev/a11y_assessments/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 dev/a11y_assessments/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 dev/a11y_assessments/macos/Runner/AppDelegate.swift create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 dev/a11y_assessments/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 dev/a11y_assessments/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 dev/a11y_assessments/macos/Runner/Configs/Debug.xcconfig create mode 100644 dev/a11y_assessments/macos/Runner/Configs/Release.xcconfig create mode 100644 dev/a11y_assessments/macos/Runner/Configs/Warnings.xcconfig create mode 100644 dev/a11y_assessments/macos/Runner/DebugProfile.entitlements create mode 100644 dev/a11y_assessments/macos/Runner/Info.plist create mode 100644 dev/a11y_assessments/macos/Runner/MainFlutterWindow.swift create mode 100644 dev/a11y_assessments/macos/Runner/Release.entitlements create mode 100644 dev/a11y_assessments/macos/RunnerTests/RunnerTests.swift create mode 100644 dev/a11y_assessments/pubspec.yaml create mode 100644 dev/a11y_assessments/test/accessibility_guideline_test.dart create mode 100644 dev/a11y_assessments/web/favicon.png create mode 100644 dev/a11y_assessments/web/icons/Icon-192.png create mode 100644 dev/a11y_assessments/web/icons/Icon-512.png create mode 100644 dev/a11y_assessments/web/icons/Icon-maskable-192.png create mode 100644 dev/a11y_assessments/web/icons/Icon-maskable-512.png create mode 100644 dev/a11y_assessments/web/index.html create mode 100644 dev/a11y_assessments/web/manifest.json create mode 100644 dev/a11y_assessments/windows/.gitignore create mode 100644 dev/a11y_assessments/windows/CMakeLists.txt create mode 100644 dev/a11y_assessments/windows/flutter/CMakeLists.txt create mode 100644 dev/a11y_assessments/windows/runner/CMakeLists.txt create mode 100644 dev/a11y_assessments/windows/runner/Runner.rc create mode 100644 dev/a11y_assessments/windows/runner/flutter_window.cpp create mode 100644 dev/a11y_assessments/windows/runner/flutter_window.h create mode 100644 dev/a11y_assessments/windows/runner/main.cpp create mode 100644 dev/a11y_assessments/windows/runner/resource.h create mode 100644 dev/a11y_assessments/windows/runner/resources/app_icon.ico create mode 100644 dev/a11y_assessments/windows/runner/runner.exe.manifest create mode 100644 dev/a11y_assessments/windows/runner/utils.cpp create mode 100644 dev/a11y_assessments/windows/runner/utils.h create mode 100644 dev/a11y_assessments/windows/runner/win32_window.cpp create mode 100644 dev/a11y_assessments/windows/runner/win32_window.h diff --git a/dev/a11y_assessments/.gitignore b/dev/a11y_assessments/.gitignore new file mode 100644 index 0000000000000..24476c5d1eb55 --- /dev/null +++ b/dev/a11y_assessments/.gitignore @@ -0,0 +1,44 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/dev/a11y_assessments/.metadata b/dev/a11y_assessments/.metadata new file mode 100644 index 0000000000000..f35b49906d8e5 --- /dev/null +++ b/dev/a11y_assessments/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "b9c3f1f74c075a1766fd74418b5d79f528cf8c74" + channel: "master" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + - platform: android + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + - platform: ios + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + - platform: linux + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + - platform: macos + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + - platform: web + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + - platform: windows + create_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + base_revision: b9c3f1f74c075a1766fd74418b5d79f528cf8c74 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/dev/a11y_assessments/README.md b/dev/a11y_assessments/README.md new file mode 100644 index 0000000000000..1f8a64cafb983 --- /dev/null +++ b/dev/a11y_assessments/README.md @@ -0,0 +1,3 @@ +# a11y_assessments + +An application to conduct accessibility assessments. diff --git a/dev/a11y_assessments/analysis_options.yaml b/dev/a11y_assessments/analysis_options.yaml new file mode 100644 index 0000000000000..f04c6cf0f30d4 --- /dev/null +++ b/dev/a11y_assessments/analysis_options.yaml @@ -0,0 +1 @@ +include: ../../analysis_options.yaml diff --git a/dev/a11y_assessments/android/.gitignore b/dev/a11y_assessments/android/.gitignore new file mode 100644 index 0000000000000..6f568019d3c69 --- /dev/null +++ b/dev/a11y_assessments/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/dev/a11y_assessments/android/app/build.gradle b/dev/a11y_assessments/android/app/build.gradle new file mode 100644 index 0000000000000..dcf73d660939c --- /dev/null +++ b/dev/a11y_assessments/android/app/build.gradle @@ -0,0 +1,71 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.a11y_assessments" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.a11y_assessments" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} + +dependencies {} diff --git a/dev/a11y_assessments/android/app/src/debug/AndroidManifest.xml b/dev/a11y_assessments/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000000000..e00f903eae2aa --- /dev/null +++ b/dev/a11y_assessments/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/dev/a11y_assessments/android/app/src/main/AndroidManifest.xml b/dev/a11y_assessments/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000..a1c931a7a55b9 --- /dev/null +++ b/dev/a11y_assessments/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/android/app/src/main/kotlin/com/example/a11y_assessments/MainActivity.kt b/dev/a11y_assessments/android/app/src/main/kotlin/com/example/a11y_assessments/MainActivity.kt new file mode 100644 index 0000000000000..43273ce8d8255 --- /dev/null +++ b/dev/a11y_assessments/android/app/src/main/kotlin/com/example/a11y_assessments/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.a11y_assessments + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/dev/a11y_assessments/android/app/src/main/res/drawable-v21/launch_background.xml b/dev/a11y_assessments/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000000000..9f19e2f90407e --- /dev/null +++ b/dev/a11y_assessments/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/dev/a11y_assessments/android/app/src/main/res/drawable/launch_background.xml b/dev/a11y_assessments/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000000000..3727f9e00a029 --- /dev/null +++ b/dev/a11y_assessments/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/dev/a11y_assessments/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/dev/a11y_assessments/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/dev/a11y_assessments/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/dev/a11y_assessments/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/dev/a11y_assessments/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/android/app/src/main/res/values-night/styles.xml b/dev/a11y_assessments/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000000000..f3ab3e83cd361 --- /dev/null +++ b/dev/a11y_assessments/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/dev/a11y_assessments/android/app/src/main/res/values/styles.xml b/dev/a11y_assessments/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000000..9a0ead3c04f75 --- /dev/null +++ b/dev/a11y_assessments/android/app/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/dev/a11y_assessments/android/app/src/profile/AndroidManifest.xml b/dev/a11y_assessments/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000000000..e00f903eae2aa --- /dev/null +++ b/dev/a11y_assessments/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/dev/a11y_assessments/android/build.gradle b/dev/a11y_assessments/android/build.gradle new file mode 100644 index 0000000000000..d93b7eb6e10e2 --- /dev/null +++ b/dev/a11y_assessments/android/build.gradle @@ -0,0 +1,35 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +buildscript { + ext.kotlin_version = '1.7.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.3.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/dev/a11y_assessments/android/gradle.properties b/dev/a11y_assessments/android/gradle.properties new file mode 100644 index 0000000000000..94adc3a3f97aa --- /dev/null +++ b/dev/a11y_assessments/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/dev/a11y_assessments/android/gradle/wrapper/gradle-wrapper.properties b/dev/a11y_assessments/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000..3c472b99c6f35 --- /dev/null +++ b/dev/a11y_assessments/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/dev/a11y_assessments/android/settings.gradle b/dev/a11y_assessments/android/settings.gradle new file mode 100644 index 0000000000000..13766f66084b4 --- /dev/null +++ b/dev/a11y_assessments/android/settings.gradle @@ -0,0 +1,24 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + } + settings.ext.flutterSdkPath = flutterSdkPath() + + includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + + plugins { + id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false + } +} + +include ":app" + +apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/dev/a11y_assessments/ios/.gitignore b/dev/a11y_assessments/ios/.gitignore new file mode 100644 index 0000000000000..7a7f9873ad7dc --- /dev/null +++ b/dev/a11y_assessments/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/dev/a11y_assessments/ios/Flutter/AppFrameworkInfo.plist b/dev/a11y_assessments/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000000000..9625e105df39e --- /dev/null +++ b/dev/a11y_assessments/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 11.0 + + diff --git a/dev/a11y_assessments/ios/Flutter/Debug.xcconfig b/dev/a11y_assessments/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000000000..592ceee85b89b --- /dev/null +++ b/dev/a11y_assessments/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/dev/a11y_assessments/ios/Flutter/Release.xcconfig b/dev/a11y_assessments/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000000000..592ceee85b89b --- /dev/null +++ b/dev/a11y_assessments/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj b/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..9711fbb0f3ef8 --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,617 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807E294A63A400263BE5 /* Frameworks */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000..919434a6254f0 --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000000..f9b0d7c5ea15f --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/dev/a11y_assessments/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/a11y_assessments/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000000..87131a09bea5d --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/ios/Runner.xcworkspace/contents.xcworkspacedata b/dev/a11y_assessments/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000..1d526a16ed0f1 --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000000..f9b0d7c5ea15f --- /dev/null +++ b/dev/a11y_assessments/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/dev/a11y_assessments/ios/Runner/AppDelegate.swift b/dev/a11y_assessments/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000000000..d815fed684a8a --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/AppDelegate.swift @@ -0,0 +1,17 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000000..d36b1fab2d9de --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..b6a5d3f48e4e0fec02ff52437b182c553efd1c00 GIT binary patch literal 10932 zcmeHN2~<R zh`|8`A_N>jnSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi z?<@|nSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9BsoHJVErigKH1~P zRX-!ho@ofe4MPw){D}J+K>~~rq}d%o%+4Xmgze|kRxX4C>Km5XEI|PAFFNzuNd%dm zzjVoB`=H9!8Yl0Kvc-9w0G$6dx!kMW*Eju^=3f?0o-t$U)GHRB-_ptGc%r}RxlL{U z594Nx3LA0oOp3q$3;sZ^!++3&bGZ!o-*6w?;oOhf z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzyeSa3=9=_98)_7Z{SspqgJ$MRU z7xBn&41zpQ)%5dr4e`tmh%S+$3-JLRk&DLFC>t)q21$H5$O+fat1-`o21z628fpkq z%4%l9b!-re!W?9SX#5_6SYrFgL8%ToSju{TFz-VEme}QC0T5fO(BEZ111RaK=Dg2f z5CAIHecf9c*?Z1bUB4>>q^w7hD!A0r-@Nu_!`#dr(LXj|=UESd?^DGgGQV zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R$T3=% zw_KuOF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u3P6hNsXG=bRq5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0zcWx+)(|LcH)C(o z+}(GY=-?=3)7W4_?Q{Q0u{Y{(cO23&btXGIBDO`WmK40*!ocNIY9`h75Z-$KsZ2!zFrOk|!6UjMqS5(xo``OXh!SF(p`X|wQ4OBgWTy&c zrJlHsJ342pHlO?@Yo}THY9hUf4xw~h5E@UJo}6uNM=gyRReO?fvmWw#c89M$MLHl< zc9H6&Dm63IL}Uxdb`NU5NH#cJ?FZ@FL}tPIqF3ujhzxaj+_A!rT#alxAUj8`emyrM zooYSVTN6jtI#3&J`M%@$Dr%$TP}x7JscBm6e`)^WFdrFQ#R%1m}p5adKOe%!(b=~k4Pr3ST71A^!liwxZi zU8=2RhXm;muH-Vf_yc|f)q~9#D@Z4gD;Tz#b>k@SAwL`}Uq?atPjTHu?-U-y5kaQV zL0{LMUQJmabFkc=n%Hy6;Tb=Ugh%3^N)A%+TWkcA2|M(VZ+^_!1^q@^H|dbW&%`Qd z{8ZOD6nycipcvXt$GYz+#SqRR2OA3Bewyn9dg5=cpE+1jKwn%dA3>>D9OXKSGSiZi zhATIk7dulx^(Eh|EO(~1?D-}!h42E*^i|HDH0ISi_bI`m**kn_E3c)+FMo8lwpJc> zHWEf3Y?mz)(k?751$kMwJA2pd;9TDRJ=u=`COUl{llx&=TCfX-IhmNaeumUf4VE4? zq=(Nxy9TR*RRtEOagwx{)xZQ+8iwt=%NT! z@jrD-Zp+7gV5xLREK3$8;JVl8X(zU<=7WtAu{s;}{YJ>-yD4kHp>m-X*;xG;n20#jAXL_Zi8pcBvR6QHv+W+nZ>!3d5riYyP3FV_ub$Cjt zA*xRKlm(s+udE4?*#dDpGB`H z;v)2P)S~gW-}}c?*C--}LqF~QWNb8E@paLNIO>)|#V=Ay$1XxDNL@Q^) z_LSsYc^*^~9+}a2GIX0eachMtQg;?&3elpgrucCEP05s^_JCfpr2Pnweah3Y>7io5 z67!%O$p+6!SHoZ;rVuwiatg7Sm;&>V4X$Jg)~5eOtF!_&kz z1jb1s9!Lw8Zc@R)u%L|jFNGs+CzP>7vrQRGbf%=Sus4dvNn@c0&K;Hgmdg>$bJ2)z zX%_KWorRjs%xHe&=SXmheMCNUYqg^KVQ|5HQS?8`fF$9xrvdi5QXX|IsJ#e3r8#2k zz)0lzHJzwOXILd`kuqh8R?LW7F zto6|*7P`B?qTJb(TJlmJksxpP=6d=d)CVbYP-r4$hD(H~TG)0xL?8CLh&OVTkMk-T zYf%$taM2kgpbJnS{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{UGe4M>-69@p)*(? zjXQZ$8^nfSen%a_j*T$pNowo{xiGEk$%Ck1aQhHUKjJH96XbLPXv+jk%ard#fu=@Q z$Ae`aWvE^{%tDfK>8GjkdLD zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>-~WDNlpjSc3gQv9KOcK7kcp@|d?yaTmB^ zp5c!0;B$vxS|SszusMMj6at-EMMVAie!Jx@!qYTk4F?d_gm71T(<{~2|~P{jfGpsD)~-x0)E$>*ZI~~A9P&w>UQl#UV;;z84N0lGr|1L zSi9ujWZJT6tAQj&F1RgW=?As3v}+V|9>#&uNemd+Fz9$vG#Ptk>uT06bO8x@A;%l< zs1=QYC1|k&tv5E^`673|y8<1D=Kr$^2dBrL?(?NwQSo7n4S(Rni< zAH5;N4F}v$&{9>Efo*PB>T$&r1*^*`OTx4|ikV{d?B6HY;F25k{`OcZZ(us-RVwDx zUzJrCTBD$uz1ZFiSZ*$yX3c`ghG5WdBE$2g%&V7_F4c<#8j)TF_jFlKGTcdj@|Z>a z&kp09GVs!Zxsh^jG)}C)*I3ZD8$|Um`{D)nU=LKaEvnyx_J5%i-6Va?@*>=3(dQy` zOv%$_9l2B|+(t>qohkuU4r_P=R^6L#w%ZAlgKJTXc>KY|z0I<0!!XKF%RN#tUh0?7 zo&mDd(BFBOR&YFsKR7D3LD+X>+T1Br0a|9Osmff5CbBflb<2D8g-JfK* z&ZCu}gHBWT%@VZXv4*#$GWVcz4NS zUW`Eg+eXYmHkD1U{gn^+a}pPJ=0!^MIpSWCc{@wHRxyXEuuB9^>U&o{c{uJSWzxA? zIl8{#kiso|tAS zJ+q(EKiggeBE{==4|GRL3f6|STvOzrWuQXbl?gVyz6IGi_Fpz@ z*l9Y$SgA(5Gbj>Rgj|%pvYjZuATa9jajTL0f%JVr3$DIV=`lSHl=Iv;EjuGkBaI zeVE~2*A(04mm4xso+$46l@+Wh53?O{n~J^pIdZh0=Wv#F_x4jPQ5@=o*VJ2BgG|si z>ZrLz|6Kp12$kN)Z{fh5FRMn&7IYZ)PLhAQLHrCXG7h^`+LPWMU>I6Sd2b?2^&VUP z1Qhl1xY>ONWd8z^+p~G>JuTN9fcYtG_D&GH{Miv-sxTN`l%t(YbEz9F9xXKr=0Ku& zm6>b>n01zeRy%Y~EuQb9JgAJ~W;b@xFt>s)z?wvy+^9@5E zPXC!M_uSEUI`4}G7JcbX1;k{xzHz}qEwrfopdbEQjt{#bhkMSj9=f^owdGH z1I@eMYi%}qUg35bU1C}UczWu<%`!vIvL@`T@YT%Ta#XB=nln3Qo1q)s3`4aC?zx;F zSt-HW9An~W8hSVJo4;sq4wS41J6?MtJI-e@WmAidnb;xYu)>HrR)@pq(<#!Dfae!s zo|#R!(@U{z4EoffZ08Fd?K2!>`(9mai{BHgHJZk@&1dKaA{&>Wud{h8dSxpHj#i=1 z9QwPn9-zAvth)s)-=^0QQ}V4{H63R!0XCZ{wArJ->!S(c9fIO(SaI(R>#?;jn+OE8v|d4$70@itAv-IDZQ-52WupGq1TysYHl%a`h9KG&d=cJK>fv1Ebo5xhS-Ar zvt%Z8nVnxOXUe&LV`4lk(^J6_*J9gOQ;RbUzS3MDGQBin|MkX%O_c51=S#({;Lfue zto3N{=Udk39IJo%Jg#`YLDzw=mHDlG7hfhk+*Sc)W8m{%1f*xdszr^)0IQ^Lx` zpIbjMN0%Ag)Uz__E1C|xwqPM!KuGN;$Mzeg>UAA3{hMfE&oWtca8X2>Htg?=zSeg~ zrA+HbR%P-187KQ3CoTtVtc30fsd#cilcH%wm^{ODAAPnw=PYY^Rd zP`vw`VY?Q0tcN1-#x5B%efC82agDZewt(Dk;yv|q&R8nG{7pY^mgW>M9d7^0^__{^ zTTG}JL2ObO)11MSQ%rocU*d3cbi?1F^Zw(2mB<)!gwV3p?*61$o9U zD4_y&MiN8&3NFdJU-D~E*LB)QmitYz!z6Ap58^9g%T1=)In69Vc;kkIC4raRs?*d>YhqC7fH-(4sb`kP%CSX>jK1)FKaE{W0W3YK}+mApyv zpSCez4#NZ<8|p~*7v9{=QgD9~0qQ>u_P% zuinytH*uo%Uk=n?^8x($kWN_c+$s50H3Il80BpV8H=AS!3i|{7SpMQQtxKFU=FYmH zeY^jJh+g<4`m8v!^O>-NFLn~-RqlNxnZl2wd2A{Yc1G=Fa$d+Q&(N&rnPf+b7ser4x_TgJjitU_f4Z z;4Ro~ut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L=(1M_DvEN~_~+xmZkm8A0Ga zQSWONI17_su5wpHg3sI?i9D+_Y|pCqVuHJNdHUauTD=R$Jb&2K_liQisqG$(sm=k9;L* z!L?*4B~hf6uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T zE1WWz*>GPWKZ0%&@%6=fyx)5rzUpI;vy`u(RKzNG_1sI}IFCZ&UsR?8S! z!65@`-;RKl12LMka0L8&HsaA8{tWv8W-<}F|Nn<Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 zcmV-m2cP(fP)x~L`~4d)Rspd&<9kFh{hn*KP1LP0~$;u(LfAu zp%fx&qLBcRHx$G|3q(bv@+b;o0*D|jwD-Q9uQR(l*ST}s+uPgQ-MeFwZ#GS?b332? z&Tk$&_miXn3IGq)AmQ)3sisq{raD4(k*bHvpCe-TdWq^NRTEVM)i9xbgQ&ccnUVx* zEY%vS%gDcSg=!tuIK8$Th2_((_h^+7;R|G{n06&O2#6%LK`a}n?h_fL18btz<@lFG za}xS}u?#DBMB> zw^b($1Z)`9G?eP95EKi&$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD? zmr-s{0wRmxUnbDrYfRvnZ@d z6johZ2sMX{YkGSKWd}m|@V7`Degt-43=2M?+jR%8{(H$&MLLmS;-|JxnX2pnz;el1jsvqQz}pGSF<`mqEXRQ5sC4#BbwnB_4` zc5bFE-Gb#JV3tox9fp-vVEN{(tOCpRse`S+@)?%pz+zVJXSooTrNCUg`R6`hxwb{) zC@{O6MKY8tfZ5@!yy=p5Y|#+myRL=^{tc(6YgAnkg3I(Cd!r5l;|;l-MQ8B`;*SCE z{u)uP^C$lOPM z5d~UhKhRRmvv{LIa^|oavk1$QiEApSrP@~Jjbg`<*dW4TO?4qG%a%sTPUFz(QtW5( zM)lA+5)0TvH~aBaOAs|}?u2FO;yc-CZ1gNM1dAxJ?%m?YsGR`}-xk2*dxC}r5j$d* zE!#Vtbo69h>V4V`BL%_&$} z+oJAo@jQ^Tk`;%xw-4G>hhb&)B?##U+(6Fi7nno`C<|#PVA%$Y{}N-?(Gc$1%tr4Pc}}hm~yY#fTOe!@v9s-ik$dX~|ygArPhByaXn8 zpI^FUjNWMsTFKTP3X7m?UK)3m zp6rI^_zxRYrx6_QmhoWoDR`fp4R7gu6;gdO)!KexaoO2D88F9x#TM1(9Bn7g;|?|o z)~$n&Lh#hCP6_LOPD>a)NmhW})LADx2kq=X7}7wYRj-0?dXr&bHaRWCfSqvzFa=sn z-8^gSyn-RmH=BZ{AJZ~!8n5621GbUJV7Qvs%JNv&$%Q17s_X%s-41vAPfIR>;x0Wlqr5?09S>x#%Qkt>?(&XjFRY}*L6BeQ3 z<6XEBh^S7>AbwGm@XP{RkeEKj6@_o%oV?hDuUpUJ+r#JZO?!IUc;r0R?>mi)*ZpQ) z#((dn=A#i_&EQn|hd)N$#A*fjBFuiHcYvo?@y1 z5|fV=a^a~d!c-%ZbMNqkMKiSzM{Yq=7_c&1H!mXk60Uv32dV;vMg&-kQ)Q{+PFtwc zj|-uQ;b^gts??J*9VxxOro}W~Q9j4Em|zSRv)(WSO9$F$s=Ydu%Q+5DOid~lwk&we zY%W(Z@ofdwPHncEZzZgmqS|!gTj3wQq9rxQy+^eNYKr1mj&?tm@wkO*9@UtnRMG>c aR{jt9+;fr}hV%pg00001^@s67{VYS000c7NklQEG_j zup^)eW&WUIApqy$=APz8jE@awGp)!bsTjDbrJO`$x^ZR^dr;>)LW>{ zs70vpsD38v)19rI=GNk1b(0?Js9~rjsQsu*K;@SD40RB-3^gKU-MYC7G!Bw{fZsqp zih4iIi;Hr_xZ033Iu{sQxLS=}yBXgLMn40d++>aQ0#%8D1EbGZp7+ z5=mK?t31BkVYbGOxE9`i748x`YgCMwL$qMsChbSGSE1`p{nSmadR zcQ#R)(?!~dmtD0+D2!K zR9%!Xp1oOJzm(vbLvT^$IKp@+W2=-}qTzTgVtQ!#Y7Gxz}stUIm<1;oBQ^Sh2X{F4ibaOOx;5ZGSNK z0maF^@(UtV$=p6DXLgRURwF95C=|U8?osGhgOED*b z7woJ_PWXBD>V-NjQAm{~T%sjyJ{5tn2f{G%?J!KRSrrGvQ1(^`YLA5B!~eycY(e5_ z*%aa{at13SxC(=7JT7$IQF~R3sy`Nn%EMv!$-8ZEAryB*yB1k&stni)=)8-ODo41g zkJu~roIgAih94tb=YsL%iH5@^b~kU9M-=aqgXIrbtxMpFy5mekFm#edF9z7RQ6V}R zBIhbXs~pMzt0VWy1Fi$^fh+1xxLDoK09&5&MJl(q#THjPm(0=z2H2Yfm^a&E)V+a5 zbi>08u;bJsDRUKR9(INSc7XyuWv(JsD+BB*0hS)FO&l&7MdViuur@-<-EHw>kHRGY zqoT}3fDv2-m{NhBG8X}+rgOEZ;amh*DqN?jEfQdqxdj08`Sr=C-KmT)qU1 z+9Cl)a1mgXxhQiHVB}l`m;-RpmKy?0*|yl?FXvJkFxuu!fKlcmz$kN(a}i*saM3nr z0!;a~_%Xqy24IxA2rz<+08=B-Q|2PT)O4;EaxP^6qixOv7-cRh?*T?zZU`{nIM-at zTKYWr9rJ=tppQ9I#Z#mLgINVB!pO-^FOcvFw6NhV0gztuO?g ztoA*C-52Q-Z-P#xB4HAY3KQVd%dz1S4PA3vHp0aa=zAO?FCt zC_GaTyVBg2F!bBr3U@Zy2iJgIAt>1sf$JWA9kh{;L+P*HfUBX1Zy{4MgNbDfBV_ly z!y#+753arsZUt@366jIC0klaC@ckuk!qu=pAyf7&QmiBUT^L1&tOHzsK)4n|pmrVT zs2($4=?s~VejTFHbFdDOwG;_58LkIj1Fh@{glkO#F1>a==ymJS$z;gdedT1zPx4Kj ztjS`y_C}%af-RtpehdQDt3a<=W5C4$)9W@QAse;WUry$WYmr51ml9lkeunUrE`-3e zmq1SgSOPNEE-Mf+AGJ$g0M;3@w!$Ej;hMh=v=I+Lpz^n%Pg^MgwyqOkNyu2c^of)C z1~ALor3}}+RiF*K4+4{(1%1j3pif1>sv0r^mTZ?5Jd-It!tfPfiG_p$AY*Vfak%FG z4z#;wLtw&E&?}w+eKG^=#jF7HQzr8rV0mY<1YAJ_uGz~$E13p?F^fPSzXSn$8UcI$ z8er9{5w5iv0qf8%70zV71T1IBB1N}R5Kp%NO0=5wJalZt8;xYp;b{1K) zHY>2wW-`Sl{=NpR%iu3(u6l&)rc%%cSA#aV7WCowfbFR4wcc{LQZv~o1u_`}EJA3>ki`?9CKYTA!rhO)if*zRdd}Kn zEPfYbhoVE~!FI_2YbC5qAj1kq;xP6%J8+?2PAs?`V3}nyFVD#sV3+uP`pi}{$l9U^ zSz}_M9f7RgnnRhaoIJgT8us!1aB&4!*vYF07Hp&}L zCRlop0oK4DL@ISz{2_BPlezc;xj2|I z23RlDNpi9LgTG_#(w%cMaS)%N`e>~1&a3<{Xy}>?WbF>OOLuO+j&hc^YohQ$4F&ze z+hwnro1puQjnKm;vFG~o>`kCeUIlkA-2tI?WBKCFLMBY=J{hpSsQ=PDtU$=duS_hq zHpymHt^uuV1q@uc4bFb{MdG*|VoW@15Osrqt2@8ll0qO=j*uOXn{M0UJX#SUztui9FN4)K3{9!y8PC-AHHvpVTU;x|-7P+taAtyglk#rjlH2 z5Gq8ik}BPaGiM{#Woyg;*&N9R2{J0V+WGB69cEtH7F?U~Kbi6ksi*`CFXsi931q7Y zGO82?whBhN%w1iDetv%~wM*Y;E^)@Vl?VDj-f*RX>{;o_=$fU!&KAXbuadYZ46Zbg z&6jMF=49$uL^73y;;N5jaHYv)BTyfh&`qVLYn?`o6BCA_z-0niZz=qPG!vonK3MW_ zo$V96zM!+kJRs{P-5-rQVse0VBH*n6A58)4uc&gfHMa{gIhV2fGf{st>E8sKyP-$8zp~wJX^A*@DI&-;8>gANXZj zU)R+Y)PB?=)a|Kj>8NXEu^S_h^7R`~Q&7*Kn!xyvzVv&^>?^iu;S~R2e-2fJx-oUb cX)(b1KSk$MOV07*qoM6N<$f&6$jw%VRuvdN2+38CZWny1cRtlsl+0_KtW)EU14Ei(F!UtWuj4IK+3{sK@>rh zs1Z;=(DD&U6+tlyL?UnHVN^&g6QhFi2#HS+*qz;(>63G(`|jRtW|nz$Pv7qTovP!^ zP_jES{mr@O-02w%!^a?^1ZP!_KmQiz0L~jZ=W@Qt`8wzOoclQsAS<5YdH;a(4bGLE zk8s}1If(PSIgVi!XE!5kA?~z*sobvNyohr;=Q_@h2@$6Flyej3J)D-6YfheRGl`HEcPk|~huT_2-U?PfL=4BPV)f1o!%rQ!NMt_MYw-5bUSwQ9Z&zC>u zOrl~UJglJNa%f50Ok}?WB{on`Ci`p^Y!xBA?m@rcJXLxtrE0FhRF3d*ir>yzO|BD$ z3V}HpFcCh6bTzY}Nt_(W%QYd3NG)jJ4<`F<1Od) zfQblTdC&h2lCz`>y?>|9o2CdvC8qZeIZt%jN;B7Hdn2l*k4M4MFEtq`q_#5?}c$b$pf_3y{Y!cRDafZBEj-*OD|gz#PBDeu3QoueOesLzB+O zxjf2wvf6Wwz>@AiOo2mO4=TkAV+g~%_n&R;)l#!cBxjuoD$aS-`IIJv7cdX%2{WT7 zOm%5rs(wqyPE^k5SIpUZ!&Lq4<~%{*>_Hu$2|~Xa;iX*tz8~G6O3uFOS?+)tWtdi| zV2b#;zRN!m@H&jd=!$7YY6_}|=!IU@=SjvGDFtL;aCtw06U;-v^0%k0FOyESt z1Wv$={b_H&8FiRV?MrzoHWd>%v6KTRU;-v^Miiz+@q`(BoT!+<37CKhoKb)|8!+RG z6BQFU^@fRW;s8!mOf2QViKQGk0TVER6EG1`#;Nm39Do^PoT!+<37AD!%oJe86(=et zZ~|sLzU>V-qYiU6V8$0GmU7_K8|Fd0B?+9Un1BhKAz#V~Fk^`mJtlCX#{^8^M8!me z8Yg;8-~>!e<-iG;h*0B1kBKm}hItVGY6WnjVpgnTTAC$rqQ^v)4KvOtpY|sIj@WYg zyw##ZZ5AC2IKNC;^hwg9BPk0wLStlmBr;E|$5GoAo$&Ui_;S9WY62n3)i49|T%C#i017z3J=$RF|KyZWnci*@lW4 z=AKhNN6+m`Q!V3Ye68|8y@%=am>YD0nG99M)NWc20%)gwO!96j7muR}Fr&54SxKP2 zP30S~lt=a*qDlbu3+Av57=9v&vr<6g0&`!8E2fq>I|EJGKs}t|{h7+KT@)LfIV-3K zK)r_fr2?}FFyn*MYoLC>oV-J~eavL2ho4a4^r{E-8m2hi>~hA?_vIG4a*KT;2eyl1 zh_hUvUJpNCFwBvRq5BI*srSle>c6%n`#VNsyC|MGa{(P&08p=C9+WUw9Hl<1o9T4M zdD=_C0F7#o8A_bRR?sFNmU0R6tW`ElnF8p53IdHo#S9(JoZCz}fHwJ6F<&?qrpVqE zte|m%89JQD+XwaPU#%#lVs-@-OL);|MdfINd6!XwP2h(eyafTUsoRkA%&@fe?9m@jw-v(yTTiV2(*fthQH9}SqmsRPVnwwbV$1E(_lkmo&S zF-truCU914_$jpqjr(>Ha4HkM4YMT>m~NosUu&UZ>zirfHo%N6PPs9^_o$WqPA0#5 z%tG>qFCL+b*0s?sZ;Sht0nE7Kl>OVXy=gjWxxK;OJ3yGd7-pZf7JYNcZo2*1SF`u6 zHJyRRxGw9mDlOiXqVMsNe#WX`fC`vrtjSQ%KmLcl(lC>ZOQzG^%iql2w-f_K@r?OE zwCICifM#L-HJyc7Gm>Ern?+Sk3&|Khmu4(~3qa$(m6Ub^U0E5RHq49za|XklN#?kP zl;EstdW?(_4D>kwjWy2f!LM)y?F94kyU3`W!6+AyId-89v}sXJpuic^NLL7GJItl~ zsiuB98AI-(#Mnm|=A-R6&2fwJ0JVSY#Q>&3$zFh|@;#%0qeF=j5Ajq@4i0tIIW z&}sk$&fGwoJpe&u-JeGLi^r?dO`m=y(QO{@h zQqAC7$rvz&5+mo3IqE?h=a~6m>%r5Quapvzq;{y~p zJpyXOBgD9VrW7@#p6l7O?o3feml(DtSL>D^R) zZUY%T2b0-vBAFN7VB;M88!~HuOXi4KcI6aRQ&h|XQ0A?m%j2=l1f0cGP}h(oVfJ`N zz#PpmFC*ieab)zJK<4?^k=g%OjPnkANzbAbmGZHoVRk*mTfm75s_cWVa`l*f$B@xu z5E*?&@seIo#*Y~1rBm!7sF9~~u6Wrj5oICUOuz}CS)jdNIznfzCA(stJ(7$c^e5wN z?lt>eYgbA!kvAR7zYSD&*r1$b|(@;9dcZ^67R0 zXAXJKa|5Sdmj!g578Nwt6d$sXuc&MWezA0Whd`94$h{{?1IwXP4)Tx4obDK%xoFZ_Z zjjHJ_P@R_e5blG@yEjnaJb`l;s%Lb2&=8$&Ct-fV`E^4CUs)=jTk!I}2d&n!f@)bm z@ z_4Dc86+3l2*p|~;o-Sb~oXb_RuLmoifDU^&Te$*FevycC0*nE3Xws8gsWp|Rj2>SM zns)qcYj?^2sd8?N!_w~4v+f-HCF|a$TNZDoNl$I1Uq87euoNgKb6&r26TNrfkUa@o zfdiFA@p{K&mH3b8i!lcoz)V{n8Q@g(vR4ns4r6w;K z>1~ecQR0-<^J|Ndg5fvVUM9g;lbu-){#ghGw(fg>L zh)T5Ljb%lWE;V9L!;Cqk>AV1(rULYF07ZBJbGb9qbSoLAd;in9{)95YqX$J43-dY7YU*k~vrM25 zxh5_IqO0LYZW%oxQ5HOzmk4x{atE*vipUk}sh88$b2tn?!ujEHn`tQLe&vo}nMb&{ zio`xzZ&GG6&ZyN3jnaQy#iVqXE9VT(3tWY$n-)uWDQ|tc{`?fq2F`oQ{;d3aWPg4Hp-(iE{ry>MIPWL> iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000000000..89c2725b70f18 --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/dev/a11y_assessments/ios/Runner/Base.lproj/LaunchScreen.storyboard b/dev/a11y_assessments/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000000000..f2e259c7c9390 --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/ios/Runner/Base.lproj/Main.storyboard b/dev/a11y_assessments/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000000000..f3c28516fb38e --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/ios/Runner/Info.plist b/dev/a11y_assessments/ios/Runner/Info.plist new file mode 100644 index 0000000000000..74b9bb41e71fc --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + A11y Assessments + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + a11y_assessments + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/dev/a11y_assessments/ios/Runner/Runner-Bridging-Header.h b/dev/a11y_assessments/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000000000..95b7baf386d06 --- /dev/null +++ b/dev/a11y_assessments/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1,5 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GeneratedPluginRegistrant.h" diff --git a/dev/a11y_assessments/ios/RunnerTests/RunnerTests.swift b/dev/a11y_assessments/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000000..6bfa573763f8b --- /dev/null +++ b/dev/a11y_assessments/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/dev/a11y_assessments/lib/main.dart b/dev/a11y_assessments/lib/main.dart new file mode 100644 index 0000000000000..9bf39a96c8455 --- /dev/null +++ b/dev/a11y_assessments/lib/main.dart @@ -0,0 +1,65 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases/use_cases.dart'; + +void main() { + runApp(const App()); +} + +class App extends StatelessWidget { + const App({super.key}); + + @override + Widget build(BuildContext context) { + + final Map routes = Map.fromEntries( + useCases.map((UseCase useCase) => MapEntry(useCase.route, useCase.build)), + ); + return MaterialApp( + title: 'Accessibility Assessments', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + routes: { + '/': (_) => const HomePage(), + ...routes + }, + ); + } +} + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + Widget _buildUseCaseItem(UseCase useCase) { + return Padding( + padding: const EdgeInsets.all(10), + child: Builder( + builder: (BuildContext context) { + return TextButton( + key: Key(useCase.name), + onPressed: () => Navigator.of(context).pushNamed(useCase.route), + child: Text(useCase.name), + ); + } + ) + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Accessibility Assessments')), + body: Center( + child: ListView( + children: useCases.map(_buildUseCaseItem).toList(), + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart b/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart new file mode 100644 index 0000000000000..ecdf03427a5fa --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart @@ -0,0 +1,46 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class CheckBoxListTile extends UseCase { + + @override + String get name => 'CheckBoxListTile'; + + @override + String get route => '/check-box-list-tile'; + + @override + Widget build(BuildContext context) => _MainWidget(); +} + +class _MainWidget extends StatefulWidget { + @override + State<_MainWidget> createState() => _MainWidgetState(); +} + +class _MainWidgetState extends State<_MainWidget> { + bool _checked = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('CheckBoxListTile')), + body: Center( + child: CheckboxListTile( + value: _checked, + onChanged: (bool? value) { + setState(() { + _checked = value!; + }); + }, + title: const Text('a check box list title'), + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart b/dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart new file mode 100644 index 0000000000000..fe4d7e2be0f3a --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart @@ -0,0 +1,47 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class CheckBoxListTileDisabled extends UseCase { + + @override + String get name => 'CheckBoxListTile Disabled'; + + @override + String get route => '/check-box-list-tile-disabled'; + + @override + Widget build(BuildContext context) => _MainWidget(); +} + +class _MainWidget extends StatefulWidget { + @override + State<_MainWidget> createState() => _MainWidgetState(); +} + +class _MainWidgetState extends State<_MainWidget> { + bool _checked = false; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('CheckBoxListTile Disabled')), + body: Center( + child: CheckboxListTile( + value: _checked, + onChanged: (bool? value) { + setState(() { + _checked = value!; + }); + }, + title: const Text('a disabled check box list title'), + enabled: false, + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/use_cases.dart b/dev/a11y_assessments/lib/use_cases/use_cases.dart new file mode 100644 index 0000000000000..139109fa64600 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/use_cases.dart @@ -0,0 +1,19 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; + +import 'check_box_list_tile.dart'; +import 'check_box_list_tile_disabled.dart'; + +abstract class UseCase { + String get name; + String get route; + Widget build(BuildContext context); +} + +final List useCases = [ + CheckBoxListTile(), + CheckBoxListTileDisabled(), +]; diff --git a/dev/a11y_assessments/linux/.gitignore b/dev/a11y_assessments/linux/.gitignore new file mode 100644 index 0000000000000..d3896c98444fb --- /dev/null +++ b/dev/a11y_assessments/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/dev/a11y_assessments/linux/CMakeLists.txt b/dev/a11y_assessments/linux/CMakeLists.txt new file mode 100644 index 0000000000000..07dc63e3803d9 --- /dev/null +++ b/dev/a11y_assessments/linux/CMakeLists.txt @@ -0,0 +1,139 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "a11y_assessments") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.a11y_assessments") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/dev/a11y_assessments/linux/flutter/CMakeLists.txt b/dev/a11y_assessments/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000000000..d5bd01648a96d --- /dev/null +++ b/dev/a11y_assessments/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/dev/a11y_assessments/linux/main.cc b/dev/a11y_assessments/linux/main.cc new file mode 100644 index 0000000000000..281a29e16b599 --- /dev/null +++ b/dev/a11y_assessments/linux/main.cc @@ -0,0 +1,10 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/dev/a11y_assessments/linux/my_application.cc b/dev/a11y_assessments/linux/my_application.cc new file mode 100644 index 0000000000000..05e5133c60566 --- /dev/null +++ b/dev/a11y_assessments/linux/my_application.cc @@ -0,0 +1,108 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "a11y_assessments"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "a11y_assessments"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/dev/a11y_assessments/linux/my_application.h b/dev/a11y_assessments/linux/my_application.h new file mode 100644 index 0000000000000..8c66ec485434d --- /dev/null +++ b/dev/a11y_assessments/linux/my_application.h @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/dev/a11y_assessments/macos/.gitignore b/dev/a11y_assessments/macos/.gitignore new file mode 100644 index 0000000000000..746adbb6b9e14 --- /dev/null +++ b/dev/a11y_assessments/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/dev/a11y_assessments/macos/Flutter/Flutter-Debug.xcconfig b/dev/a11y_assessments/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000000000..c2efd0b608ba8 --- /dev/null +++ b/dev/a11y_assessments/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/dev/a11y_assessments/macos/Flutter/Flutter-Release.xcconfig b/dev/a11y_assessments/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000000000..c2efd0b608ba8 --- /dev/null +++ b/dev/a11y_assessments/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/dev/a11y_assessments/macos/Runner.xcodeproj/project.pbxproj b/dev/a11y_assessments/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000..1da16b798e668 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,695 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* a11y_assessments.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "a11y_assessments.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* a11y_assessments.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* a11y_assessments.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/a11y_assessments.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/a11y_assessments"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/a11y_assessments.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/a11y_assessments"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/a11y_assessments.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/a11y_assessments"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/dev/a11y_assessments/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/a11y_assessments/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/dev/a11y_assessments/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/a11y_assessments/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/a11y_assessments/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000000000..f33a76e7500bc --- /dev/null +++ b/dev/a11y_assessments/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/macos/Runner.xcworkspace/contents.xcworkspacedata b/dev/a11y_assessments/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000..1d526a16ed0f1 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/dev/a11y_assessments/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/dev/a11y_assessments/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/dev/a11y_assessments/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/dev/a11y_assessments/macos/Runner/AppDelegate.swift b/dev/a11y_assessments/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000000000..d080d41951d35 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000000..a2ec33f19f110 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..3c4935a7ca84f0976aca34b7f2895d65fb94d1ea GIT binary patch literal 46993 zcmZ5|3p`X?`~OCwR3s6~xD(})N~M}fiXn6%NvKp3QYhuNN0*apqmfHdR7#ShNQ99j zQi+P9nwlXbmnktZ_WnO>bl&&<{m*;O=RK!cd#$zCdM@AR`#jH%+2~+BeX7b-48x|= zZLBt9*d+MZNtpCx_&asa{+CselLUV<<&ceQ5QfRjLjQDSL-t4eq}5znmIXDtfA|D+VRV$*2jxU)JopC)!37FtD<6L^&{ia zgVf1p(e;c3|HY;%uD5<-oSFkC2JRh- z&2RTL)HBG`)j5di8ys|$z_9LSm^22*uH-%MmUJs|nHKLHxy4xTmG+)JoA`BN7#6IN zK-ylvs+~KN#4NWaH~o5Wuwd@W?H@diExdcTl0!JJq9ZOA24b|-TkkeG=Q(pJw7O;i z`@q+n|@eeW7@ z&*NP+)wOyu^5oNJ=yi4~s_+N)#M|@8nfw=2#^BpML$~dJ6yu}2JNuq!)!;Uwxic(z zM@Wa-v|U{v|GX4;P+s#=_1PD7h<%8ey$kxVsS1xt&%8M}eOF98&Rx7W<)gY(fCdmo{y*FPC{My!t`i=PS1cdV7DD=3S1J?b2<5BevW7!rWJ%6Q?D9UljULd*7SxX05PP^5AklWu^y` z-m9&Oq-XNSRjd|)hZ44DK?3>G%kFHSJ8|ZXbAcRb`gH~jk}Iwkl$@lqg!vu)ihSl= zjhBh%%Hq|`Vm>T7+SYyf4bI-MgiBq4mZlZmsKv+S>p$uAOoNxPT)R6owU%t*#aV}B z5@)X8nhtaBhH=={w;Du=-S*xvcPz26EI!gt{(hf;TllHrvku`^8wMj7-9=By>n{b= zHzQ?Wn|y=;)XM#St@o%#8idxfc`!oVz@Lv_=y(t-kUC`W)c0H2TX}Lop4121;RHE(PPHKfe_e_@DoHiPbVP%JzNudGc$|EnIv`qww1F5HwF#@l(=V zyM!JQO>Rt_PTRF1hI|u^2Uo#w*rdF*LXJky0?|fhl4-M%zN_2RP#HFhSATE3&{sos zIE_?MdIn!sUH*vjs(teJ$7^7#|M_7m`T>r>qHw>TQh?yhhc8=TJk2B;KNXw3HhnQs za(Uaz2VwP;82rTy(T3FJNKA86Y7;L(K=~BW_Q=jjRh=-k_=wh-$`nY+#au+v^C4VV z)U?X(v-_#i=3bAylP1S*pM_y*DB z2fR!imng6Dk$>dl*K@AIj<~zw_f$T!-xLO8r{OkE(l?W#W<={460Y02*K#)O4xp?W zAN+isO}!*|mN7B#jUt&!KNyFOpUxv&ybM>jmkfn8z^llBslztv!!`TBEPwu;#eR3d z@_VDa)|ByvXx1V=^Up4{;M8ji3FC7gm(C7Ty-#1gs+U<{Ouc(iV67{< zam#KwvR&s=k4W<13`}DxzJ9{TUa97N-cgWkCDc+C339)EEnC@^HQK6OvKDSCvNz(S zOFAF_6omgG!+zaPC8fBO3kH8YVBx9_AoM?->pv~@$saf(Myo|e@onD`a=;kO*Utem ze=eUH&;JB2I4}?Pm@=VnE+yb$PD~sA5+)|iH3bi|s?ExIePeoAMd(Z4Z%$mCu{t;B9(sgdG~Q}0ShAwe!l8nw0tJn zJ+m?ogrgty$3=T&6+JJa!1oS3AtQQ1gJ z3gR1<=hXU>{SB-zq!okl4c+V9N;vo4{fyGeqtgBIt%TPC1P&k!pR-GZ7O8b}9=%>3 zQrV%FQdB+CcCRKK)0}v>U25rbQk(1^9Ax|WcAo5?L(H&H@%zAoT2RH$iN6boyXpsYqME}WJZI6T%OMlkWXK>R`^7AHG&31 z&MIU}igQ7$;)7AEm#dXA+!I&6ymb7n6D;F7c$tO3Ql(`ht z1sFrzIk_q5#=!#D(e~#SdWz5K;tPF*R883Yu>*@jTeOGUjQekw zM+7HlfP{y8p}jA9bLfyKC_Ti8k#;AVp@RML^9MQp-E+Ns-Y zKA!aAZV-sfm<23fy#@TZZlQVQxH%R7rD}00LxHPUF!Yg3%OX ziDe4m<4fp{7ivBS?*AlJz$~vw5m)Ei8`|+~xOSqJ$waA0+Yys$z$9iN9TIXu8 zaYacjd09uRAsU|)g|03w`F|b1Xg#K~*Mp2X^K^)r3P^juoc}-me&YhkW3#G|H<~jK zoKD?lE@jOw7>4cpKkh!8qU!bF(i~Oa8a!EGy-j46eZYbKUvF=^^nq`EtWFK}gwrsB zeu<6~?mk+;+$whP)8ud8vjqh+NofU+Nu`~|pb&CN1y_idxxf6cGbT=fBZR_hl&G)GgnW$*oDrN-zz;cKs18n+dAn95w z)Y>l6!5eYpebJGw7it~Q5m}8$7@%p&KS=VtydFj4HPJ{xqUVS_Ih}c(^4nUdwG|0% zw8Fnm{IT`8MqoL(1BNtu_#7alS@3WSUUOFT@U*`V!zrPIeCbbO=pE%|g92$EU|lw; z^;^AqMVWVf-R5^OI79TzIyYf}HX%0Y)=aYH;EKo}?=R~ZM&s&F;W>u%hFUfNafb;- z8OkmkK3k||J#3`xdLuMJAhj9oPI?Cjt}cDN7hw26n7irWS0hsy`fs&Y?Y&(QF*Nu! z!p`NggHXaBU6$P42LkqnKsPG@363DHYGXg{!|z6VMAQt??>FK1B4x4{j;iY8A+7o% z*!0qt&w+w#Ob@pQp;q)u0;v^9FlY=AK>2!qku)!%TO<^lNBr!6R8X)iXgXi^1p`T8 z6sU@Y_Fsp6E89E1*jz~Tm2kF=mjYz_q99r^v0h-l7SP6azzL%woM6!7>IFWyizrNwAqoia3nN0q343q zFztMPh0)?ugQg5Izbk{5$EGcMzt*|=S8ZFK%O&^YV@V;ZRL>f!iG?s5z{(*Xq20c^ z(hkk~PljBo%U`$q>mz!ir7chKlE-oHA2&0i@hn4O5scsI&nIWsM>sYg;Ph5IO~VpT z%c-3_{^N>4kECzk?2~Z@V|jWio&a&no;boiNxqXOpS;ph)gEDFJ6E=zPJ$>y5w`U0 z;h9_6ncIEY?#j1+IDUuixRg&(hw+QSSEmFi%_$ua$^K%(*jUynGU@FlvsyThxqMRw z7_ALpqTj~jOSu2_(@wc_Z?>X&(5jezB6w-@0X_34f&cZ=cA-t%#}>L7Q3QRx1$qyh zG>NF=Ts>)wA)fZIlk-kz%Xa;)SE(PLu(oEC8>9GUBgd$(^_(G6Y((Hi{fsV; zt*!IBWx_$5D4D&ezICAdtEU!WS3`YmC_?+o&1RDSfTbuOx<*v`G<2SP;5Q4TqFV&q zJL=90Lcm^TL7a9xck}XPMRnQ`l0%w-fi@bRI&c*VDj!W4nj=qaQd$2U?^9RTT{*qS_)Q9OL>s}2P3&da^Pf(*?> z#&2bt;Q7N2`P{{KH@>)Tf5&za?crRmQ%8xZi<9f=EV3={K zwMet=oA0-@`8F;u`8j-!8G~0TiH5yKemY+HU@Zw3``1nT>D ziK465-m?Nm^~@G@RW2xH&*C#PrvCWU)#M4jQ`I*>_^BZB_c!z5Wn9W&eCBE(oc1pw zmMr)iu74Xl5>pf&D7Ml>%uhpFGJGyj6Mx=t#`}Mt3tDZQDn~K`gp0d)P>>4{FGiP$sPK*ExVs!1)aGgAX z6eA;-9@@Muti3xYv$8U{?*NxlHxs?)(6%!Iw&&l79K86h+Z8;)m9+(zzX?cS zH*~)yk)X^H1?AfL!xctY-8T0G0Vh~kcP=8%Wg*zZxm*;eb)TEh&lGuNkqJib_}i;l z*35qQ@}I#v;EwCGM2phE1{=^T4gT63m`;UEf5x2Get-WSWmt6%T6NJM`|tk-~4<#HHwCXuduB4+vW!BywlH8murH@|32CNxx7} zAoF?Gu02vpSl|q1IFO0tNEvKwyH5V^3ZtEO(su1sIYOr{t@Tr-Ot@&N*enq;Je38} zOY+C1bZ?P~1=Qb%oStI-HcO#|WHrpgIDR0GY|t)QhhTg*pMA|%C~>;R4t_~H1J3!i zyvQeDi&|930wZlA$`Wa9)m(cB!lPKD>+Ag$5v-}9%87`|7mxoNbq7r^U!%%ctxiNS zM6pV6?m~jCQEKtF3vLnpag``|bx+eJ8h=(8b;R+8rzueQvXgFhAW*9y$!DgSJgJj% zWIm~}9(R6LdlXEg{Y3g_i7dP^98=-3qa z$*j&xC_$5btF!80{D&2*mp(`rNLAM$JhkB@3al3s=1k^Ud6HHontlcZw&y?`uPT#a za8$RD%e8!ph8Ow7kqI@_vd7lgRhkMvpzp@4XJ`9dA@+Xk1wYf`0Dk!hIrBxhnRR(_ z%jd(~x^oqA>r>`~!TEyhSyrwNA(i}={W+feUD^8XtX^7^Z#c7att{ot#q6B;;t~oq zct7WAa?UK0rj0yhRuY$7RPVoO29JV$o1Z|sJzG5<%;7pCu%L-deUon-X_wAtzY@_d z6S}&5xXBtsf8TZ13chR&vOMYs0F1?SJcvPn>SFe#+P3r=6=VIqcCU7<6-vxR*BZUm zO^DkE{(r8!e56)2U;+8jH4tuD2c(ptk0R{@wWK?%Wz?fJckr9vpIU27^UN*Q$}VyHWx)reWgmEls}t+2#Zm z_I5?+htcQl)}OTqF<`wht89>W*2f6e)-ewk^XU5!sW2A2VtaI=lggR&I z;Rw{xd)WMqw`VUPbhrx!!1Eg_*O0Si6t@ny)~X^Gu8wZZDockr)5)6tm+<=z+rYu? zCof+;!nq6r9MAfh zp4|^2w^-3vFK~{JFX|F5BIWecBJkkEuE%iP8AZ z^&e|C+VEH&i(4Y|oWPCa#C3T$129o5xaJa=y8f(!k&q+x=M|rq{?Zw_n?1X-bt&bP zD{*>Io`F4(i+5eE2oEo6iF}jNAZ52VN&Cp>LD{MyB=mCeiwP+v#gRvr%W)}?JBTMY z_hc2r8*SksC%(pp$KGmWSa|fx;r^9c;~Q(Jqw1%;$#azZf}#Fca9NZOh{*YxV9(1ivVA^2Wz>!A&Xvmm-~{y8n!^Jdl8c>`J#=2~!P{ zC1g_5Ye3={{fB`R%Q|%9<1p1;XmPo5lH5PHvX$bCIYzQhGqj7hZ?@P4M0^mkejD|H zVzARm7LRy|8`jSG^GpxRIs=aD>Y{Cb>^IwGEKCMd5LAoI;b{Q<-G}x*e>86R8dNAV z<@jb1q%@QQanW1S72kOQ$9_E#O?o}l{mHd=%Dl{WQcPio$baXZN!j{2m)TH1hfAp{ zM`EQ=4J`fMj4c&T+xKT!I0CfT^UpcgJK22vC962ulgV7FrUrII5!rx1;{@FMg(dIf zAC}stNqooiVol%%TegMuWnOkWKKA}hg6c)ssp~EnTUVUI98;a}_8UeTgT|<%G3J=n zKL;GzAhIQ_@$rDqqc1PljwpfUwiB)w!#cLAkgR_af;>}(BhnC9N zqL|q8-?jsO&Srv54TxVuJ=rfcX=C7{JNV zSmW@s0;$(#!hNuU0|YyXLs{9$_y2^fRmM&g#toh}!K8P}tlJvYyrs6yjTtHU>TB0} zNy9~t5F47ocE_+%V1(D!mKNBQc{bnrAbfPC2KO?qdnCv8DJzEBeDbW}gd!g2pyRyK`H6TVU^~K# z488@^*&{foHKthLu?AF6l-wEE&g1CTKV|hN7nP+KJnkd0sagHm&k{^SE-woW9^fYD z7y?g*jh+ELt;$OgP>Se3o#~w9qS}!%#vBvB?|I-;GM63oYrJ}HFRW6D+{54v@PN8K z2kG8`!VVc+DHl^8y#cevo4VCnTaPTzCB%*)sr&+=p{Hh#(MwaJbeuvvd!5fd67J_W za`oKxTR=mtM7P}i2qHG8=A(39l)_rHHKduDVA@^_Ueb7bq1A5#zHAi**|^H@fD`_W z#URdSG86hhQ#&S-Vf_8b`TIAmM55XhaHX7}Ci-^(ZDs*yb-WrWV&(oAQu3vMv%u$5 zc;!ADkeNBN_@47r!;%G3iFzo;?k)xTS-;1D-YeS5QXN7`p2PzGK~e6ib;8COBa5)p zfMn}dA--&A12~zr&GVk?qnBGfIEo`5yir;-Q;ZLn{Fimdrk;e!)q`sAkYh^~^>4Q@ zN5RT>s38+`V{|6@k&vZW!W0*BEqV&~34d+Ev8h)ObYL7Bd_hgbUzjdJaXP=S@Dp6X z)i013q3K4Gr5d%2YIp>218pYK!xwH;k)j?uUrT-yVKLg*L3y~=a+qd!RWGTL`z>29 z-Zb4Y{%pT%`R-iA#?T58c-i@?jf-Ckol9O>HAZPUxN%Z=<4ad9BL7n`_kH0i#E(m& zaNb039+z~ONUCLsf_a|x*&ptU?`=R*n}rm-tOdCDrS!@>>xBg)B3Sy8?x^e=U=i8< zy7H-^BPfM}$hf*d_`Qhk_V$dRYZw<)_mbC~gPPxf0$EeXhl-!(ZH3rkDnf`Nrf4$+ zh?jsRS+?Zc9Cx7Vzg?q53ffpp43po22^8i1Obih&$oBufMR;cT2bHlSZ#fDMZZr~u zXIfM5SRjBj4N1}#0Ez|lHjSPQoL&QiT4mZn=SxHJg~R`ZjP!+hJ?&~tf$N!spvKPi zfY;x~laI9X`&#i#Z}RJ`0+MO_j^3#3TQJu2r;A-maLD8xfI+2Y*iDf4LsQ$9xiu?~ z?^wHEf^qlgtjdj(u_(W5sbGx1;maVPDHvI-76u2uUywf;>()=e>0le;bO0LIvs)iy z*lJTO+7gyf^)2uS-PhS_O-+RToQmc6VT>ej^y^stNkwIxUg?E|YMAAwQ}U!dC&cXL ziXKU?zT~xbh6C};rICGbdX~;8Z%L~Jdg|`senVEJo-CiDsX47Kc`;EiXWO<9o)(`4 zGj(9@c+Me=F~y(HUehcAy!tkoM&e1y#(qqCkE(0lik_U>wg8vOhGR(=gBGFSbR`mh zn-%j3VTD4 zwA1Kqw!OSgi_v0;6?=Bk4Z{l-7Fl4`ZT535OC{73{rBwpNHMPH>((4G`sh zZhr!v{zM@4Q$5?8)Jm;v$A2v$Yp9qFG7y`9j7O-zhzC+7wr3Cb8sS$O{yOFOODdL) zV2pU{=nHne51{?^kh%a$WEro~o(rKQmM!p?#>5Pt`;!{0$2jkmVzsl|Nr^UF^IHxG z8?HmZEVMY~ec%Ow6hjfg6!9hCC4xY?V;5Ipo-myV=3TmfT^@XkKME`+=_inm4h7ki z->K~a+20?)zic^zc&7h=0)T{Aa24FU_}(O|9DMW3Bf>MW=O%~8{unFxp4}B+>>_KN zU%rKs3Va&&27&OX4-o&y2ie|sN2p-=S^V<2wa2NUQ4)?0e|hgna*1R7(#R_ys3xmG zE#(ry+q=O~&t|RX@ZMD`-)0QmE*x%SBc(Yvq60JtCQ4RL(gdA(@=}0rYo5yKz36bW zkvLOosP6I?7qH!rce(}q@cH-{oM2ThKV2RZe+{{25hkc?T>=Tky12xHr0jmfH@SZi zLHPJ@^Oo^Zo%`gZk_hrbCzS+t|=O!Bt zWi|>M8mz~sD|Z>C1ZPf_Cs&R!S5E2qK+@j*UpP>;5_|+h+y{gb=zub7#QKSUabet# zFH2H0ul;zO+uc+V=W_W@_Ig-791T7J9&=5)wrBE?JEHS_A6P~VQ)u6s1)Pu|VxP(aYJV*(e<)(42R zm3AK>dr1QLbC1RMoQ|M5k+TWBjY9q+_vY=K-tUte35m4RWl51A<4O0ptqV3)KzL7U z0gpp-I1)|zvtA8V7-e-o9H)lB_Rx6;Bu7A2yE)6)SuDqWDs}~Ojfk?DFwI% z3E1(>LbbB7I(&E@B7nlulhvY=Wa1mGXD@ijD7WF^y@L1e55h)-hzoq}eWe!fh9m3V{)x^6F8?ed1z>+4;qW6A4hYYj zZCYP=c#I8+$pAIVyiY*#%!j3ySAnH`tp|=^lh{)#JimWaP_rXK40A0WcsEUj`G1}O zG?XQ~qK4F!lqauv6-BL_Up3+-l1=kVfD;D*C)yr>o9>W=%mIyATtn_OBLK+h@p)j5jRAb;m&Ok?TZH-5Q)~#UwdYFp~rEE{judWa9E)z zE>135C-xMdHYY&AZGR)tb`K}s0CK9 z1!))p^ZaUC*e50t`sL+)@`)#kJ}?C_cCMH@k{f4wh~0`OFnGQ2nzUuuu;=r4BYRcI z){G#a6Y$S(mIc6B#YS;jFcU{0`c)Raa$nG+hV(K|2|^ZWOI566zlF0N;t~$jD<_AX zjnD?HN-G>xRmHwtL3BcJX7)Q^YGfc?cS4Nj=yYl5MB(uBD?r@VTB|mIYs=au$e)e{ zLHWd!+EN*v2*(=y%G1JzyQdY&%|?~R5NPb)`S2dw1AJW8O;L=p?yVxJs=X?U#-l1O zk6xh8yyY;OTR7aF{P=kQ>y`*EFivnw%rQioA-I67WS+~hVamG4_sI)(Jo4vHS|@F@ zqrBHbxHd_Y8+?8Gfq=Z1O^Fs5moGayCHVUHY^8)^j)Aj*RB!S2-FA?4#-`puwBW`` zJ_6OQj(FGo8DotHYRKq;;$4xDn9=4rgw}5xvxhi)?n?W5{*%4%h9Tg)zlQl&fN~Z1)gL(Dn7X!P428I zwA+U-x5!cQ57g1N=2bLqAWF z!&cbvsD)dvYoqP5vaQz%rL@kv*J>0AMzWAKn~Mxi5g2GlI7qvVZo)Z5oj=#O!M&*O z`3O3)uvrjNTeremC}nW@(m%#E-sITB>j-!yBM#(=FN`~c#@XjL3e)SjR9&%QO%tUg zzGv=SLH()`ZIt?Ayym;9VG1Muq+a+7Zo+59?SuRu_`k>@S4!yS3roMnq+SDO?`C7V#2 z8vHf4&0k;{kLT)fa==7EILSu3e|ZnxtFO;1 zGqP-;Xo(>_QKcYUhsi-X72BqH#7Zb-TsiNIF>G9xOHT3XoA*qX^10+#XCU0)UO4_%A_s_vO=uDd3_Q%D{OsvLMW9wGvuuRnF52{2vH06D~7N672!bIMt@it_D}& zwjZ7gV!RzZ86*wbEB5cnMJRbEqMM{G!K)bfJjyPH^9nGnrOI9S{~!dm4~P#&b*~)h zCMwM8mR+y5i~E5*JAopwZ>F`=ORfA&IF%O8(aS<}^H6wcY1g^=lYLPtFpyvW9F z3;FCS-TGFYPr#Y$ue>}?rTYrmWr^VbUu>!eL$cEdh1e>5_UDnZ@Mu$l*KVo_NDEu^ zBn*!qVnzYv>t|<(>nt8%CoNPhN!qGP|sANRN^#+2YSSYHa>R1mss->c0f=#g@U58@? zA4sUbrA7)&KrTddS0M6pTSRaz)wqUgsT3&8-0eG|d;ULOUztdaiD3~>!10H`rRHWY z1iNu6=UaA8LUBoaH9G*;m`Mzm6d1d+A#I8sdkl*zfvbmV0}+u` zDMv=HJJm?IOwbP;f~yn|AI_J7`~+5&bPq6Iv?ILo2kk$%vIlGsI0%nf1z9Mth8cy! zWumMn=RL1O9^~bVEFJ}QVvss?tHIwci#ldC`~&KFS~DU5K5zzneq_Q91T~%-SVU4S zJ6nVI5jeqfh~*2{AY#b(R*Ny95RQBGIp^fxDK{I9nG0uHCqc-Ib;pUUh$t0-4wX*< z=RzW~;iR3xfRnW<>5Jr5O1MP)brA3+ei@H8Hjkt7yuYIpd7c-4j%U=8vn8HD#TPJo zSe+7~Db}4U3Y^4dl1)4XuKZ67f(ZP;?TYg9te>hbAr4R_0K$oq3y5m-gb?fR$UtF9 zS~S^=aDyFSE}9W2;Okj%uoG-Um^&Qo^bB#!W?|%=6+P>``bumeA2E7ti7Aj%Fr~qm z2gbOY{WTyX$!s5_0jPGPQQ0#&zQ0Zj0=_74X8|(#FMzl`&9G_zX*j$NMf?i3M;FCU z6EUr4vnUOnZd`*)Uw#6yI!hSIXr%OF5H z5QlF8$-|yjc^Y89Qfl!Er_H$@khM6&N*VKjIZ15?&DB?);muI`r;7r0{mI03v9#31 z#4O*vNqb=1b}TjLY`&ww@u^SE{4ZiO=jOP3!|6cKUV2*@kI9Aw0ASwn-OAV~0843$1_FGl7}eF6C57dJb3grW)*jtoUd zpqXvfJSCIv4G*_@XZE?> z4Lt=jTSc*hG3`qVq!PVMR2~G-1P{%amYoIg!8Odf4~nv6wnEVrBt-R5Au=g~4=X|n zHRJGVd|$>4@y#w;g!wz>+z%x?XM^xY%iw%QoqY@`vSqg0c>n_}g^lrV))+9n$zGOP zs%d&JWT2Jjxaz`_V%XtANP$#kLLlW=OG2?!Q%#ThY#Sj}*XzMsYis2HiU2OlfeC>d z8n8j-{Npr1ri$Jv2E_QqKsbc$6vedBiugD~S`_0QjTTtX(mS}j6)6e;xdh*sp5U0aMpuN}qTP=^_Qn zh~0padPWs&aXmf6b~}{7Raglc)$~p?G89N4)&a}`izf|bA)IUmFLQ8UM$T!6siQxr z=%)pPsWYXWCNdGMS3fK6cxVuhp7>mug|>DVtxGd~O8v@NFz<+l`8^#e^KS3})bovWb^ zILp4a_9#%Y*b6m$VH8#)2NL@6a9|q!@#XOXyU-oAe)RR$Auj6?p2LEp*lD!KP{%(- z@5}`S$R)Kxf@m68b}Tr7eUTO=dh2wBjlx;PuO~gbbS2~9KK1szxbz$R|Frl8NqGn= z2RDp@$u5Obk&sxp!<;h=C=ZKPZB+jk zBxrCc_gxabNnh6Gl;RR6>Yt8c$vkv>_o@KDMFW1bM-3krWm|>RG>U`VedjCz2lAB1 zg(qb_C@Z~^cR=_BmGB@f;-Is3Z=*>wR2?r({x}qymVe?YnczkKG%k?McZ2v3OVpT* z(O$vnv}*Tle9WVK_@X@%tR^Z!3?FT_3s@jb3KBVf#)4!p~AFGgmn%1fBbZe3T53$_+UX_A!@Kz63qSLeH@8(augJDJ;RA>6rNxQYkd6t(sqK=*zv4j;O#N(%*2cdD z3FjN6`owjbF%UFbCO=haP<;Y1KozVgUy(nnnoV7{_l5OYK>DKEgy%~)Rjb0meL49X z7Fg;d!~;Wh63AcY--x{1XWn^J%DQMg*;dLKxs$;db`_0so$qO!>~yPDNd-CrdN!ea zMgHt24mD%(w>*7*z-@bNFaTJlz;N0SU4@J(zDH*@!0V00y{QfFTt>Vx7y5o2Mv9*( z1J#J27gHPEI3{!^cbKr^;T8 z{knt%bS@nrExJq1{mz2x~tc$Dm+yw=~vZD|A3q>d534za^{X9e7qF29H5yu};J)vlJkKq}< zXObu*@ioXGp!F=WVG3eUtfIA$GGgv0N?d&3C47`Zo)ms*qO}A9BAEke!nh#AfQ0d_ z&_N)E>5BsoR0rPqZb)YN}b~6Ppjyev;MMis-HkWF!az%G? z#&it84hv!%_Q>bnwch!nZKxB05M=jgiFaB^M=e-sj1xR?dPYUzZ#jua`ggyCAcWY> z-L$r#a{=;JP5X}9(ZPC&PdG~h5>_8SueX($_)Qu(;()N3*ZQH(VGnkWq^C}0r)~G3_?a10y*LsFz zokU5AKsW9DUr-ylK61shLS#4@vPcteK-Ga9xvRnPq=xSD_zC=Q_%6IuM?GpL(9aDx z|8d_;^6_D4{IQ1ndMAcFz5ZaT+Ww0wWN`xP(U#^=POs(BpKm;(H(lmYp+XCb7Kaw0 z;LT945Ev3IkhP6$lQBiMgr+vAL}{8xO&IObqJBEP4Y^x&V?iGC=1lVIbH^Z!eXxr@ zz)D7Fon`z~N|Pq>Bsue&_T9d;G+d8#@k^cq~F^I8ETsZ*cGOf*gZ4ghlAzW|aZ;WA13^B!Tlr0sWA zosgXD-%zvO-*GLU@hVV(bbQ`s@f~Ux=4}(@7O)%o5EH((gYflccBC@jbLF3IgPozv zglX2IL}kL1rtn4mu~`J(MMY83Rz6gc1}cX4RB+tZO2~;3FI# z@dU(xa5J_KvL0)oSkvwz9|!QcEA$jKR@a-4^SU3O449TrO+x$1fkBU<<=E_IHnF6> zPmZ7I2E+9A_>j6og$>Nih~b2F_^@6ef|Hm-K2(>`6ag{Vpd`g35n`yW|Jme78-cSy z2Jz7V#5=~u#0eLSh3U4uM3Smk31>xEh^-Os%&5tK6hSAX83jJi%5l!MmL4E?=FerNG#3lj^;-F1VISY!4E)__J~gY zP{o~Xo!8DW{5lsBFKL~OJiQoH>yBZ+b^};UL&UUs!Hbu7Gsf<9sLAsOPD4?-3CP{Q zIDu8jLk6(U3VQPyTP{Esf)1-trW5Mi#zfpgoc-!H>F$J#8uDRwDwOaohB(_I%SuHg zGP)11((V9rRAG>80NrW}d`=G(Kh>nzPa1M?sP;UNfGQaOMG1@_D0EMIWhIn#$u2_$ zlG-ED(PU+v<1Dd?q-O#bsA)LwrwL>q#_&75H)_X4sJK{n%SGvVsWH7@1QZqq|LM`l zDhX8m%Pe5`p1qR{^wuQ&>A+{{KWhXs<4RD< z=qU6)+btESL>kZWH8w}Q%=>NJTj=b%SKV3q%jSW>r*Qv1j$bX>}sQ%KO7Il zm?7>4%Q6Nk!2^z})Kchu%6lv-7i=rS26q7)-02q?2$yNt7Y={z<^<+wy6ja-_X6P4 zoqZ1PW#`qSqD4qH&UR57+z0-hm1lRO2-*(xN-42|%wl2i^h8I{d8lS+b=v9_>2C2> zz(-(%#s*fpe18pFi+EIHHeQvxJT*^HFj2QyP0cHJw?Kg+hC?21K&4>=jmwcu-dOqEs{%c+yaQ z2z6rB>nPdwuUR*j{BvM-)_XMd^S1U|6kOQ$rR`lHO3z~*QZ71(y(42g`csRZ1M@K7 zGeZ27hWA%v`&zQExDnc@cm9?ZO?$?0mWaO7E(Js|3_MAlXFB$^4#Zpo;x~xOEbay( zq=N;ZD9RVV7`dZNzz+p@YqH@dW*ij8g053Cbd=Mo!Ad8*L<5m1c4Kk ziuca5CyQ05z7gOMecqu!vU=y93p+$+;m=;s-(45taf_P(2%vER<8q3}actBuhfk)( zf7nccmO{8zL?N5oynmJM4T?8E))e;;+HfHZHr` zdK}~!JG}R#5Bk%M5FlTSPv}Eb9qs1r0ZH{tSk@I{KB|$|16@&`0h3m7S+)$k*3QbQ zasW2`9>hwc)dVNgx46{Io zZ}aJHHNf1?!K|P;>g7(>TefcLJk%!vM`gH8V3!b= z>YS+)1nw9U(G&;7;PV4eIl{=6DT^Vw<2Elnox;u@xF5ad*9Fo|yKgq<>*?C$jaG2j z|29>K)fI^U!v?55+kQ*d2#3}*libC4>Dl4 zIo3Jvsk?)edMnpH<|*l<*0Pf{2#KedIt>~-QiB{4+KEpSjUAYOhGDpn3H_N9$lxaP ztZwagSRY~x@81bqe^3fb;|_A7{FmMBvwHN*Xu006qKo{1i!RbN__2q!Q*A;U*g-Mz zg)-3FZ`VJdognZ~WrWW^2J$ArQAr1&jl~kWhn+osG5wAlE5W&V%GI{8iMQ!5lmV~# zeb3SKZ@?7p;?7{uviY6`Oz16t0=B70`im=`D@xJa16j2eHoCtElU*~7={YUzN41sE z#Th>DvJq-#UwEpJGKx;;wfDhShgO0cM|e!Ej){RX#~>a?)c2|7Hjhh2d=)VUVJL<^Aq|>_df4DX>b9W2$_DM zTjF#j(9?Co`yor?pK<16@{h#F&F8~1PG|qQNZPX^b!L*L&?PH#W8za0c~v6I2W($Jderl%4gufl z#s;C*7APQJP46xHqw;mUyKp3}W^hjJ-Dj>h%`^XS7WAab^C^aRu1?*vh-k2df&y9E z=0p*sn0<83UL4w30FqnZ0EvXCBIMVSY9Zf?H1%IrwQybOvn~4*NKYubcyVkBZ4F$z zkqcP*S>k6!_MiTKIdGlG+pfw>o{ni`;Z7pup#g z4tDx3Kl$)-msHd1r(YpVz7`VW=fx9{ zP}U8rJ-IP)m}~5t&0Y$~Quyjflm!-eXC?_LMGCkZtNDZf0?w<{f^zp&@U@sQxcPOZ zBbfQTFDWL_>HytC*QQG_=K7ZRbL!`q{m8IjE0cz(t`V0Ee}v!C74^!Fy~-~?@}rdn zABORRmgOLz8{r!anhFgghZc>0l7EpqWKU|tG$`VM=141@!EQ$=@Zmjc zTs`)!A&yNGY6WfKa?)h>zHn!)=Jd73@T^(m_j|Z;f?avJ{EOr~O~Q2gox6dkyY@%M zBU+#=T?P8tvGG|D5JTR}XXwjgbH(uwnW%W?9<-OQU9|6H{09v#+jmnxwaQ-V;q{v% zA8srmJX7Fn@7mr*ZQ@)haPjWVN@e3K z_`+@X$k*ocx*uF^_mTqJpwpuhBX~CSu=zPE(Sy%fYz&lzZmz3xo4~-xBBvU0Ao?;I-81*Z%8Do+*}pqg>bt^{w-`V6Sj>{Znj+ z70GS2evXinf|S#9=NNoXoS;$BTW*G0!xuTSZUY45yPE+~*&a-XC+3_YPqhd*&aQ>f z$oMUq^jjA;x#?iJKrpAqa<2<21h*_lx9a}VMib;a6c$~=PJOj6XJXJ|+rc7O7PEN5uE7!4n9nllo@BI4$VW2Nf_jqnkz%cvU4O4umV z#n6oXGWOt3tuIjmX*b!!$t~94@a@QgybLpQo3icAyU`iNbY~XNAArFAn$nFJ()d-U zFaO#nxxVF-%J{UB**uRo0*+?S>=^il)1m7v-u`PDy*ln%|3E-{3U~R=QcE&zhiG_c zDnGMgf1}3h1gWz8IV0Oc7FmEt>6W?Eva;J`(!;IIny}PvD?vztz`F6su_tUO`M%K5 z%C#=nXbX})#uE!zcq2mB;hPUVU1!`9^2K303XfOIVS{mlnMqJyt}FV=$&fgoquO+N zU6!gWoL%3N1kyrhd^3!u>?l6|cIl*t4$Z$=ihyzD7FFY~U~{RaZmfyO4+$kC7+m zo+-*f-VwpUjTi_Idyl~efx)!$GpE!h+in4G1WQkoUr<#2BtxLNn*2A>a-2BL#z%QO@w0v^{s=`*I6=ew2nUj1=mvi%^U@2#Wf& zs1@q6l8WqrqGm!)Yr|*``||#A+4#du6`mR^_#?CymIr}O!8Zm?(XY$u-RGH;?HFMGIEYVuA1& z`3RlG_y0%Mo5w@-_W$E&#>g6j5|y1)2$hg(6k<{&NsACgQQ0c8&8Tdth-{@srKE*I zAW64%AvJJ+Z-|I~8`+eWv&+k8vhdJk5%jolc%e`^%_vul0~U8t)>=bU&^ z6qXW&GDP%~1{L1-nKK>IsFgDJrh>!wr3?Vu-cmi#wn`;F`$GNc_>D|>RSuC8Vh21N z|G;J1%1YxwLZDD400Ggw+FirsoXVWYtOwg-srm}6woBb!8@OIc`P$!?kH>E55zbMB z8rdpODYfVmf>cF`1;>9N>Fl(Rov!pm=okW>I(GNJoNZ6jfIunKna-h6zXZPoZ9E2PythpyYk3HRN%xhq2c?gT$?4}Ybl42kip$QiA+ab zf-!EqBXkT1OLW>C4;|irG4sMfh;hYVSD_t6!MISn-IW)w#8kgY0cI>A`yl?j@x)hc z=wMU^=%71lcELG|Q-og8R{RC9cZ%6f7a#815zaPmyWPN*LS3co#vcvJ%G+>a3sYE`9Xc&ucfU0bB}c_3*W#V7btcG|iC>LctSZUfMOK zlIUt>NBmx6Ed}w_WQARG+9fLiRjS1;g49srN1Xi&DRd|r+zz*OPLWOu>M?V>@!i49 zPLZ3Q(99%(t|l%5=+9=t$slX0Pq(K@S`^n|MKTZL_Sj+DUZY?GU8sG=*6xu)k5V3v zd-flrufs*;j-rU9;qM zyJMlz(uBh0IkV<(HkUxJ747~|gDR6xFu?QvXn`Kr|IWY-Y!UsDCEqsE#Jp*RQpnc# z8y3RX%c2lY9D*aL!VS`xgQ^u0rvl#61yjg03CBER7-#t7Z++5h_4pw{ZZ~j0n_S_g zR=eVrlZDiH4y2}EZMq2(0#uU|XHnU!+}(H*l~J&)BUDN~&$ju@&a=s$tH5L`_wLeB z944k;)JIH^T9GEFlXiNJ6JRymqtLGZc?#Mqk2XIWMuGIt#z#*kJtnk+uS;Gp}zp$(O%LOC|U4ibw%ce-6>id$j5^y?wv zp1At~Sp7Fp_z24oIbOREU!Mji-M;a|15$#ZnBpa^h+HS&4TCU-ul0{^n1aPzkSi1i zuGcMSC@(3Ac6tdQ&TkMI|5n7(6P4(qUTCr)vt5F&iIj9_%tlb|fQ{DyVu!X(gn<3c zCN6?RwFjgCJ2EfV&6mjcfgKQ^rpUedLTsEu8z7=q;WsYb>)E}8qeLhxjhj9K**-Ti z9Z2A=gg+}6%r9HXF!Z~du|jPz&{zgWHpcE+j@p0WhyHpkA6`@q{wXl6g6rL5Z|j~G zbBS~X7QXr3Pq0$@mUH1Snk^1WJ0Fx2nTyCGkWKok$bJZV0*W?kjT|mkUpK<)_!_K^OoTjMc+CWc^~{ZP8vgm`f&=ppzKtw}cxwV^gppu}^df1|va7Q?@=(076-( z4KJVmu?l(aQwmQ*y_mke>YLW^^Rsj@diLY$uUBHL3yGMwNwb7OR3VD%%4tDW(nC984jBWCd90yY(GEdE8s(j>(uPfknLwh!i6*LX}@vvrRCG`c?EdB8uYU zqgsI4=akCeC+&iMNpVu56Fj2xZQHs6SdWssIF#Q@u@f9kab0&y*PlG+PynjHy`}GT zg%aTjRs2+7CknhTQKI%YZhFq1quSM{u24Oy2As@4g(bpbi%y1i0^TwI)%1Whpa~qE zX4MD(PgFEK@jZBPXkFd437aL6#COs$WrNT#U=er-X1FX{{v9!0AS$HR{!_u;zldwY zKko!`w2u@($c&k_3uLFE0Z*2vms?uw1A{AqZw^jwg$|D7jAY20j`s*l##=4Ne_K5) zOtu6_kziEF@vPsS7+@UwqOW6>OUwF$j{r4=nOSf-{UC(rEKidie7IUn>5`UoNJ9k) zxJXXEBQifng+Pte3mPQ76pVlZ<`jnI##F1*YFA*)ZCEncvgF-%)0dUXV*pXTT^L`n zL=?A5Vty#{R9W4K)m$`me~*_(&a88M?Eon$P-YdVG}#Gq4=hh#w=`>8f`9}}zhv;~ za?I=Gb3v$Ln?-SDTBow0J5Tt&xPlw|%`*VTyVee1Oh<-&;mA|;$ zoPl;^f7Q~}km#_#HT2|!;LEqORn%~KJaM)r#x_{PstSGOiZ!zX2c}^!ea3+HSWrwE z=6SJ!7sNDPdbVr#vnUf}hr&g@7_Yj&=sY=q(v^BwLKQm|oSB}172GpPlj?a3GqX#B zJko4zRRttIY>Fv#2b#A<_DLx=T@eUj+f}!u?p)hmN)u4(Jp(`9j58ze{&~rV?WVbP z%A=|J96mQjtD037%>=yk3lkF5EOIYwcE;uQ5J6wRfI^P3{9U$(b>BlcJF$2O;>-{+a1l4;FSlb z_LRpoy$L%S<&ATf#SE z;L?-lQlUDX_s&jz;Q1Lr@5>p_RPPReGnBNxgpD!5R#3)#thAI3ufgc^L)u%Rr+Hlb zT(pLDt%wP7<%z(utq=l%1M78jveI@T$dF#su(&>JkE(#=f4;D54l*%(-^(nfbCUQe)FV9non9F%K+KZ(4_`uOciy82CO)OolxisUd0m^cqueIRnY< z;BgA4S1&XC3uUP?U$}4o&r|0VCC7fkuMZBa|2n4asR>*5`zBaOJPWT$bNn(W_CK%L$c2AsfSlwq?A8Q6 zhK&USSV=^-4vZ^5<}pnAOb&IKseHNxv_!|B{g@d^&w%{?x;i3iSo)+vt^VnMmS!v) zM)W)05vXqzH5^hOWWw~$#&7HoIw}}DD3bCQgc=I8Rv|G5fM8O^58?--_-*>%Nwk)j zIfvfok0n05!w%tZ=-dpffezI7(+}yX5XhwYk#0@KW%PkR;%#t|P6Ze_K*N6ns%jOt zNeW(bRsv0BK7ah~9U~UBAVA_L34F+;14x6-;I|o=%>?sS3@dpRv|GKxilsa#7N#@! z!RX~>&JX&r{A^^>S~n_hPKkPR_(~~g>SuPj5Kx6VI%8BOa(Iit&xSMU8B#EY-Wr?9 zOaRPw0PEbVSW@Wk{8kkVn34;D1pV2mUXnXWp{V-M9+d}|qfb6F`!a9JQO_-wlH?zf z4Sn0F4-q-tzkaJ?1fV0+cJBF$f0g6*DL6U3y`Tr`1wzCiwY#muw7Q-Ki)uN}{MoCWP%tQ@~J4}tyr1^_bV9PScNKQHK=BZFV!`0gRe?mVxhcA4hW5?p0B<5oK+?vG^NM%B%NDOvu0FMq#)u&zt_-g&2 z7?z%~p&32OAUSQV{<=pc_j2^<;)`8$zxCEomh=rvMiliShS?ahdYI1grE-M&+qkK_ zD=5Hexi<&8qb4hgtgj81OD(tfX3EJSqy9KFcxpeBerG`apI4!#93xpEFT??vLt>kf zac28;86CpMu=BWIe$NOT~+Es!y#+$ zvm2s*c`J9Gy*ERvLSI<9<=j*O=0xUG>7rYh^R4bGsvz;j-SBO|P^OQ1>G9_akF}D; zlRmB@k3c5!s|Vz3OMZ8M*n0AMTiSt5ZpRy+R1|ckna&w`UQjklt9f&0Z~=->XImVA zLXizO2h=<|wM~w>%}3q1!E{oSq7LBPwQ~93p-peDq-W?wCm8NOKgTSz-P)|cm}S5&HBsx#C@Ba5;hzi#Yw@y-kC~)@u4}Rf?KV0$lPjv}} zcFpNy=YJfsS||9&!-JFjw=@NU96ESzU^gme0_oNy?})II`>Sy>bUCHs_(m&)vn^&isCl+`F~qu8elAO z)-ZP7`gYE2H(1)5tKalz&NJbcutAU&&JFV~$Jrai31^j>vZ|HV1f}#C1<5>F8 zS1RWIzM%b{@2dAF^$+i4p>TC8-weiLAPN+Aa#(bxXo9%Vz2NEkgF&s#_>V?YPye^_ z`` z-h3Cv^m6K%28I$e2i=cFdhZN?JTWhqJC{Q9mg0Vg|FiPEWDl&K)_;Bz_K`jH7W7QX^d$WQF*iF@#4_P*D36w9&iJr2E{w?LRFapwZIIVHGH ziTp*5>T{=;(E}z{1VL4;_H`BAXA~&zpeWX!gN9m|AfcJ{`!XVz48O^&+0Gd|w;udP zzU|DbGTS|7qZoEoDZEH9Kb0%DZvCaWDzuJ=8jZz}pqPn+I!c_+*~>m>BQqN2560*< z$6sx_y8WRqj$SugYGip+et$;iJ!SQAx=HgVSh_3e)MOFHuXD@sg>Yi_p8Sh`{lP=5 zo?AFv1h;KqR`Yj!8Pjji3lr+qae2|a1GmlxE*su%_V)K0Xu0(#2LcO!*k11w*V12$ z;f~i{kI#9PzvFLZ3pz@d558HeK2BTvk*JvS^J8L^_?q4q z);;4Z!DsV!P*M>F>FiF*{|p_nUgy;pDh?J8vwO;emgOAAcxrgDXiSDS5ag?0l*jj< z(khZ3-)>eiwPwpb6T9meeL)!2C-K@z9fF`0j|t@;^f5+dx86R3ZM{bnx9Hm1O$s)N zk$OvZR0u2`Z^QP8V%{8sEhW~_xbZMad2jtz&0+ekxmp;9`ae;_f%-ltk5E%)VT*a6 zRbMnpCLPnalu+1TafJ4M0xNV8g}U4Mjk{le6MA|0y0rk)is}M%Z9tUU22SvIAh7`w zTysd{Pztfkk=jD^*!lA+rBcqb)Fx`A5iaU2tl&XdL1D)U@pLEXdu%#YB*ol1N?4ti zHBQcU#_%UqiQ1)J^u-ovU@-7l?`YzYFvA2#tM0mEh3?CpyEh_NUuVajD16t zyg$C*5du9R=K~6mCJ`W+dFI$9WZZauO)p2H)*SKpHVsIu2CxfJvi2>; zcit#57RP7DpSwMF-VBm|4V5d=tRgX7RM9%KQ0JRo6d<)RmiIPWe2zh6tmswP`fs^) zwy};#jk|NXMqCSfwIR3QZ#W2`(%sJ>qvk=53CYoLmQt9q|2Gm$sB;rEuBqGJA1OUM zoyl4Wy-HYn0J6L=cad8o)R!Ea^;`rSMg9hYo3?Fw6B9dUq75a-MSb56n8~AAsS(JP zZ!1khPu}!GRpsj+jvl`N1tDD8m1myJCI3c-c<9U-1Vg`xJO~}5_wvPXYh^=Boo^|V z3Tp}|lH!9m4Ipa_$p;b8fjUd=zc4iO7vr)M&Xs0_m$fgY@+hB9%K~4*9$p0d)m2bO ze5JH`W0fnIKdcW!oO#^g1YceSQ4u->{>u@>tLi!fky)o&$h(=he?Fe_6?}O~iSf(F zV&(P~*5h>BW{3e1H%8*7#_%L1#>W97b0@jHtliES^w6w5oldI7QL+?I(Pl$DaN>~d5nXx z;CO1E+S?3E2PLq~)-?ygkHAO1m&hOYmj7?;2XM!$D^f0l9K4P{n}mgb{CoYH6RJ8o ztydc6dNqA)`CG?=Gd~EIbi`UM)eyzGF^+i?&TOdyW~mFH_^Gye(D}clDVFQ@V2Tvy z7rQIaq8Xx`kC;AO-_{k%VI2e6X@bIy^mupEX%{u0=KDUGu~r6lS*7GOeppy{&I&Ly zjOTz=9~jC|qWXznRbrfjg!1`cE!Hzyjzw6l{%>X)TK(UEGi9Uy3f9D6bbn0gT-s`< z8%$Msh!^8WidX7S;)n2jh_n1-QCtSyOAKcPQc(Xlf0*Q|5CSBjo(I-u!R0GJgzTkL z|6QdQRrUMbUO|q0dQ%+d^4)*Mjbm$R}RUcz(7|E0Bq-bAYY@)OsM<+2>}CV zzPBgeD~kBHE(Y+@l2orJrdtV7XXq_V8IETas%7OCYo`oi)+h&v#YN!Qpp7drXFS>6 z?r-q7px+(rIy+bo1uU#I2A5s@ASe01FgGMbouFkhbkm-9yZ8Q2@Q1vuhDQ3D3L+zA z(uz8^rc24VmE5r0Gbd;yOrXnQKAEBfa3@T7fcF$#QYv^00)VZPYehpSc@?^8we}o{ zlX0~o_I<`xSfI8xF(WXO-DX1>wJ`XN?4rw@}_RLD*${$}UaXL=oM(=SDMIxZj1Ji#jAcrH7nYG`r z#ewodj>F5Bf9j(j`a;>)=*2j_ZN}vf!~Hq`2Eyt;9UH1_(yjq1OUO(1M0lI3FZ2j-fU9)L59v&OiQ>5$;d!jg?Fo{Svf5t5FCZbb?)* zJN=Q!?2BztV$7)CWtG0MO~Lr4E5>aoHD5N4(+@~gQEbZTc4s3HrIl_G23PCng4Y3f zbLZK1A-x9x!)WwuI=UBkQ5QyE^&Nrw?@fsRKK41G9-xq=#VyO%CEo`{_eioDj%M!3x=>I zfOPFiFX{1t-|+3E@?UuK=0miGN04hW0=JnJrEyWw{Bg-jMvAA}cg<5LN1c5BQdrIZ z#+bxj9Jbu`11@IUjU|RKfL(UzRlVB4XT ze|(WaxL$KiRqkgCr3^Al(19!_Y7b=E(4Xm7LCO$y5+k;Fu6B#=OSzW`-7p{zRv-_) zPr!|km?8aF}+3hm)QG92YaI+jctX&5IrvTUGf{Y$)TK6)s9v!SMhU=HIpEC~2 z4>o14mG$El2sTA(Ct?xS!l*x7^)oo}|3+BF8QNe;bBHcqdHVmb?#cbS*NqZ%mYS~z z`KLoq7B#KULt%9a#DE%VTEo4TV03T2nr`FK5jUTA$FP0JH6F9oD*|0z1Yf2b5?H0_ zD|K|_5Zk`uu?ZN0U! z_mL>>F;mnHU=@to!Vv*s4;TQr9y)L@1BXXz^a85NSifPTL4h6I>+m_S3~FkXB{N?E zS<3ue_(wqaIS5;4e9{HB`Okl9Y}iFiju+oTqb)BY)QT?~3Oag7nGu-NB5VCOFsiRs zs@m%Ruwl^FuJ1b}g^=*_R?=SYJQ@7o>c9j>)1HgB zyN9LI9ifwu{Shlb6QO2#MWhxq~IG!U^I!6%5}(sbi>=bq8!8@s;4Iaun#kvh7NPwX34Rjbp2f!D)cF&sNIO%9~;C`cs&ZY2=d@c3PpN$YZjUT}X7rY`dlWX$yc znw(7=fzWapI=KzQnJ(6!o0K_aDk!^dZ#)pSTif+jQtQXga$bPApM z=);jZ5c*?*GoeGMnV0=RrZucRRYBjx>tx`A3OuY)#tp2w7mh}&kj)SKoAvbbf;uO! z?+RItUow0xc*6StuO4D--+qY!o}Isy}s;ts5aM5X~eJUZoLOq@dGv=a4hHJD<* z5q{dZSN{bv_(Vj#pFm7Q<$C;MwL|Qizm~QCFx~xQyJoCOZ$`sYD}}q>PwRZjb<=E< zAeMP?qVfM>xu2}Il2xT6={KBdDIstxY-`5IWXN zUiWV&Oiy5R_=2X9Y$ug9Ee=ZSCaza!>dWBMYWrq7uqp>25`btLn^@ydwz?+v?-?2V z?yVwD=rAO!JEABUU1hQ|cY+_OZ14Hb-Ef`qemxp+ZSK?Z;r!gDkJ}&ayJBx+7>#~^ zTm<>LzxR^t-P;1x3$h;-xzQgveY$^C28?jNM6@8$uJiY81sCwNi~+F=78qJZ@bIsz1CO! zgtPM~p6kaCR~-M>zpRCpQI}kUfaiZS`ez6%P6%*!$YCfF=sn}dg!593GFRw>OV2nQ ztTF6uB&}1J`r>gJuBP(z%KW{I^Uz%(^r5#$SK~%w1agl)Gg9Zy9fSK0kyLE24Z(34 zYtihZMQO^*=eY=<5R6LztHaB1AcuIrXoFuQ=7&C}L{c?Z$rto$%n=!whqoqG>#vvC z2%J5LVkU%Ta8hoM($p1WqN}wurA!d@#mQGU5Nb>~#XC84EYH)Zf&DZR!uY+-;VqS< z@q?$ggdX#auS#%%%oS^EN)?JhSR4JYpSgGRQZD<9!YvvF+zp0>C#$!x*x}l8U|Bb& zv?v*im5Bq_(5Wi40b1^nKun$XTST(a8yOAcqQZmKTgGLo)Ig6JuEh5J9NnqJXin@Gxzz-k6xXWYJ&@=JZw=$+ zFPGde%HsR`gI+y`rtiPaMYwbtyp!sVb!pX~;c3zLoPO0eaZSV+O_z z%9H@UhqNowzBTPcMfL6kC>LRaFF6KVaSv1R@%4}rtleX!EMnL`rethYrhTLj1x$tj z;)H!fKo08&T(;i|FT&rPgZ*D0d=B2dXuO_(Uaoi9+vEhs4%{AD{Fl@4^|`X=PvH(s zI7$6bWJiWndP$;&!kSCIR1l57F2?yzmZm~lA5%JKVb;1rQwj*O=^WW~`+n*+fQkK0 zydInOU1Be2`jhA!rnk1iRWR=1SOZpzFoU5{OPpc&A#j6Oc?D&>fAw=>x@H7?SN;d^ z-o&}WR;E|OR`QKItu(y4mT)%Pgqju-3uyH?Y@5>oSLO2Y(0(P!?_xOL=@5+R7rWw# z3J8%Hb@%Pzf^`=J6fEJ_aG6+e7>OUnhaO1(R1<6>f}L z?d@Wnqw9?^;2?q(b@?Wd=T6r_8a@Z4)*_@Q7A`+ zW3w?j!HW0KbhxF%D`9d2HpvIrBxM!36W3Yh5=8_0qYfnHm*yiLB?Ay|V10N%F9XYq zanaDtDk$rS+|_H_r|a${C}C7b{E)Ii20-a?Grff$E?&|gWF<#Ern2GqhCiS0~Y%knIi8zY^lE4qLaR-3M;_Rkz(s;wu z9207W1PXIe#4h4Zw}dvdV&FYcnUlD5_C4hzJ@bPSBVBLpl$&52mi+wwH;svyVIzAB zoA+NQ;Hpqh?A}^Et~xhl>YQNQwh20!muW{ zq}|Pg3jHZWnDBN?r1KhiVG$%Sm-4+=Q2MZzlNr3{#Abqb9j}KK%sHZj{Vr2y4~GIQ zA3Mz1DjQ3q(CC~OyCaZn0M2!){)S!!L~t>-wA&%01?-*H5?nzW?LJB`{r&)vLB4!K zrSm({8SeZ0w(bL9%ZZAZ*^jf=8mAjK^ZR0q9004|3%73z#`-Npqx*X^Ozbja!C1MW z-M~84#=rU1r>p{+h9JU<#K_x$eWqJ+aP%e?7KTSK&1>dlxwhQmkr69uG~0iD@y|L- zlY0vSR2|IhZoS6PpfUai_AhKo2HfdD&mhv#k51CX;T z*sU)XbDyfKjxYC$*_^(U)2-c0>GJ(zVm$CihHKlFSw&1A$mq$vsRt-!$jJe3GTaZ6 z3GcVvmwZ0D>`U+f3i*pQ>${p1UeyF~G9g~g-n{ThVOuC#9=ok`Zgz@qKCSN!1&P`N z=pdlGNwal%9;)ujwWH*#K6CQG*fJDAQiKlO2vKJHeA1lj&WQC+VU^@ea8$#~UOX$*Q!V^8L- zL0$W5(Y3=??%&j_WUq6*x>=?BfmI*d8fmDF*-!XVvxL8p7$r+}Igd_(&`|D*;Z#GE zqm{tHx&aHBpXw&~l6>7-FlyiSPJtTJblAjLU5Ho$FeN0mDguFAq?r+6^~o6|b+rfE zGVcZ&O-X~tE3liGcdI~hHSCT+&F&uH8rr&f{6pr^1y5061`fu~=^_|Idrgti5+*U7 zQOb9G?Rz$j-G0Y}x+i{HB0!4ZmKzykB<0;Rbmo2)T4|VdcwujI_otLG@@8OOKg3kw zP|0ST0D4@zT?O=(0Pikp)Rpwxw_VsmW4!^j^sFd6r5l zw}SG_HQPs>ae%Bq{sye_SaBX%|F-}&^)Wz@Xi<)YNbO?lPs7z@3c;$b^Aw@>E%mOj zW^c%IdtC(Kk@s*}9NbKxEf8SZtP+32ZTxjnrNWS7;W&D~ft{QY?oqOmxlV7JP!kW!Yj`Ur{QbbM1h=0KMaIAmWiISb7TKd4=gMeo+Tcz2>e#NihnOV%iNdx` zeiuoOK^{}D+M+p(Y7EC=&-`$B0F< zQ=zHaM;&QQR4jM$sG=N&sqOvD_Bx*drQ6c@u0()g05cwl`Xm{!S_Nuaa2KlL*rmmk z51yPE)q?Bl$sNM474Y!=zZ zc{EVGpdJ!Su{Qq%llR5O6#zK8l(ld*UVl87@|iaH@C3+*;XBxjEg&fsQrzpMo3EEG zv*Tpms7a;7!|iz8WY7={0a$0ItO-(ajXl;wX_$$yzEF5k9nc>L3wv!p{8h2)G0W?h z{v6vH=7+>$Ho^+)9hDtCd+S_yh8pzS9$)hYev-=eDu?lGIR;-fgz+dr+wcmM-^dZp z9}`&kAf$~z1ovF)>Hgxc!Xe3cju-jQRluCm;c_1=PYQygb?Oxe z!QG0L3sT_k=WpfOPL#|EPlD^t;ENCC39O?tHd<(kfx7SOcxl+E#;ff19_+{vbkZSvbS$I{#>31KZj^$n%ayX0jj}EvsgnHg16P z_A6Y)pdp>kLW<;PtR*Vs#mVb%)ao7AXw{O&hBDmD;?mc3iMH;Ac@rZZ_BQa8CQ~|0 z&d1L{in-z--lBO|pxqc%bqy^~LAGv=E*eaVU~OeuVV{d`Vv#-_W7EYdTDzVraG9H+LC_dWcgZMn~KcP)XvKWbcr5&d+=a>{*(Ha6Y1$==bR z{O-?$7H;`2dt0B%Vm?6`_?ZOjJkyu9ZJsh^WH*+es&^@KDcR%Zej%3PJ*XovgyhTbaH(!H1H_OF~=*f55Jr8A%uW zz5IoAB~1e2-tDGp9}`MnavAMy?jgPM5F%y`%$}dFLrz_* zIrO=afT8+AkK5B1s3{ZDVP$g6y$-*U*=?-fh!cNyn3q6YhNhfRxW&GLIJ2#>9bYMD7-F%{|Iw%@a=DoAAU;3k9p$`V zImKm{5HU~wq|nQFwab)_7lNckW#1z2$|oW5x7vDbBURVjw8674P?L1ogMKpHoV>;# zO%*1OwI|($UOr#hL(*M~qsn3PF%_|15uc%Hy9@D>_~N|?<%lig6yKX0a#1s$o(^Laj8bF#5fGPOFMGmMiUaxSwE}Qf#SG_f79d2Iv=TFBXzTpr$^avJ?=|arh2<+ce}&248Kw0} zhlva`wD6X~s7|37la4FnFOgIHhBiFo`lw~?lSbk{>)P(3jyVhM4O)a=GX3(sW1vIC zz0mJ>;J{!eN5#nf2>$u=3Kq>`7u9QnChi8>CjONBN-b+W_UQIuN#{N$Q<$}IOvpQP zB&5ZrY{V&D=4)voh;6<1U`PFA>V%XUW73S9D^J>cQYfzIyIV5i35WNb5K9c^|M}=* zN_C3rnjCZP1^v{;EaGK7Tp5z~B#?f5NZaAsFUOLK)mI~bJTaL8DF_eRikE{%^J?y9-n_U32EKHPCkB^ZN2*zk{bC=GM%_I z61}nkr+Plg6S0V=mY>H_KQU&)P~=y3$#$*U8FunXkb_e1O-7t@m$5re%u!_G%^?_| zRIJzg+lX$}+ba|qx)Ec6c^ip;`_QfQrD~SPa4MoyRUOtX&~^XWcO^a}KBkXK9J{ZFOA~rovYa0!7btTC*=xNQrwJ)$Eu`TT$;%V&2@y@$ISdNn ztbM7|nO+U9r;ae{{;QiNEYpe4nrFq_x3 z4Tvf^b(I@_3odwhVe!aC0X&~inrYFu# zh)+eF__8ly&nLr4KlLWl%B_ZMo=zCH2QfO^$lJ zBvU*LQ#M(5HQ}2Z9_^y~i@C#h)1C*?N3v68pY+7DD09nxowdG#_AAM5z&*|-9NcB{ z_xKUY>Ya7>TO#Bat}yM}o(~8Ck^!QHnIj8N9}c*uyIs}IEqGn`xP;q3vhW6gsqUe>`m1 z)~ad@y1=?H`1SNl?ANCs5ZD`8tG&Hi=j|R%pP(%gB8pd)Q--E?hWU@)e?>SLV4s(- z!_I^oVC0x97@I(;cnEm$ttKBnI3gXE>>`K?vAq~SK?0YSBsx{@s1ZdiKfFb|zf}ju z7@rJb3mC{U`$R`YS(Z#KyxQx_*nU`kf;}QL%bw17%5~6!mMao^-{FFmX}|ItFuR~F zAAvTF%f4XKYo>2-PJ~ro@Ly#t@Sf69CrA+rmMRpihqH7V&SXX+$Sw`HZF`I*_3Vjz z%kPMyN0J3sl>X{-h12)j&XRhAAI;Aou%%z}gI>G+32z*qpZg{m`CezFrzg#&yc<1` z%j~}PN!F5Ddq(>R{+t0v{j6v^0XwWGu@5+`-$m`_>pCzM`r}wz*8Qv=$|P0R$%tJp z>D+N4GZ|Tg>XL<6XP9_wQRGDs^1icY*5GP4>*7mGMr;V zI%kT_^_SQml6$#uRE4Ps>}?ES)_XI8m-%GN{o^itb^S7e_bM$-wo_Ws)W? zx4_6#*X;T$n2N==N0#xzb~BQU#%^NF6|~898JGDbQxjK(ex;Q}_Qn@?Y>!kkUYUeY z&VclG1#eDPU78K@^p3tAUvZi1(nFfk6AAVHWt)Wbi7dPbjA4isOY~?*1&asp!wg#Q zSpSI6*!TGn3|-%vuJE<9V_1EKkz_0%z}Mb7;E!uz)+0^k;@x+<5tzj5 z!InbRtc`YwNCbCac{plY&Y}hWp#PC{o@5UsBj#tv3f^ns^`;$MVN?>q!pW+MYeC7= zkWr1kAX(0xVQ<{qny&CO*|g1{Mk_yE>1t}_YT<5#p8P7QXf;o|s>XQ#SoA&!ddE+8 zOM&VsxsRGS(Spli?P$^pK7Ty{v86RP_6h|MU^J z`J>vn0|BG3Vf!uR0zM|GwtiTPZNb;a@@1+V5+$P4GI_&$%6m!YRGL=lz5kh?z#5f55 z76COi1`R(5p69;ThuQnJ$R3w?I?jigai2arApagd=^tT~oMUWp^u|H_@zXBjpI)Dv zEFc^_`mVu5U*;ClT?x-t9{#fto_+92GF^dotz0sFWTDwZ`s40AY@mv+Qh5c-Ts8Zp z!(v7!zPvFhUZ-xkR!IvaW`{PqN|k)L4*anbtmK+UU&K*awl?DhxRalbtmDw`$#VzK zYFaG}?$F)1j`Qx7wbn|XzMJ&g@3Ai#u5M?%CLPghk;lD^)-|21{Sr+M(suBU4}6CMTMxc_tD;X;z<1-{FeHte=kh1B9O6Hl z!v2i$d1VFC&z&58zU0`G#7^K3Cs@9LYN16O%Vz)?-iQL!G6&sg6aaX>DBZmm@lFrRJpcL{K3(;+`$9GDFDw62Mud@LZjabzVC=w$dx>TQa}U z-{dhKYTYx*C=Fio`ez@wrzx+p%Fk3i&v?6ENXMb3p^?;_&huLLueDwr zpRqHbU%i;9TmexFxCS8F1rPo-ea3!}!ew7{(($76Rdnfa`~$9{8H@f7U&0&HjZ3TZ zuBc||%FljS_e&wNZ$1ezT$*})XAfm??$_cY_?13vM^tT0EKY2ptb+v5P10}a%aTk_ zh8@_T{ns2@jTFhv`)-Vxh}u(0DiL0MUi(We_eic$;gCoqj(T_S{jDo^PahnKJUp3@ zMOk+%weP*c%K6VFXR2icY`J~-&fVMYUg6fsFI->jlA|9`+07y~$Fsz}^;w;mNk$ms zu?y)VA@QH__tvYDudhEWuDD20H&uvrf_boY{($?5{s-SDjyRxSC%%2Xs5d2dpjdk$ zU*NURD#ovwIfd^H{fXR@UuaooJtQr7$d0+(K+1UEwtG9_T?sb$ExV$e-bpf}a@YUe zuzInI59w!x;<)>Be;a7ukLW>V=8~J6nKU<0@H+SQ!Be;1Za_pw#hiuW_PMPBo8W2G z*WDtiIAN<>HQOmh)DMi{s-0H^GmV3QMf4Zu(zXT!-c;2)uv4gUwt(-}-N*|KUOo$h z+Ak^R)h8yB5UD8 zsSjHgY}KguNi?xV=tdCWqJR!~dDpFQoRJOwxrWH^vfRq4%)v;sDfIjsLXF^)uy>!i z*S8Njd7yfa`+7(|8H9j73Rh|TwFpF(8H-p;RLLIU>k<*qI%A*SL{u$%<=X@Jm1QFe zVkQ(X8P4Tohl?_tSO__^aqaI?k$CC8uNLv2mp_zD@4oDaZfEN5;3#XY!L{8B!;Dtt zb~Zge@JF|#Gsk^5$-|(OPI73po|WZh<`UxaH#Y2!&p05Ph?H)d3Bc3J4sDi$f(6K`?&D&~eHVuE@_Prkt>_&8&aq=OzoN!ANkvho;qIX(g|d#EKQbJ@;-%_iARmgSF1fEK z@B4W@5mDME7AzfL**c&2#B7xO9>rA4x$rM{N=%0=goumK1kL{TF@CSk0yvqR2oo&m z)?nyiL$9~Jt(qnEuWt9Hc_duim%|zJQYiaF*~orVNDvJB;`%ZW_2x%Uu01LeX-JP& zD&fas6d3=igAgcfeki79{5!XPHHYR#nfLYRKv^wkv~cnEbLHMwQ8%yCZI^rK!D2qT zk40Vg;e!_!3d56&umIuidN?6MTZFzHot}AdqKzDh#w0s`)cV!2A74RSH1@lDXtC38 z+UhO4A9?oZEOV{bIgGd1{2qMR&xT+}q!=I8m)W23v!W2WPC?Tf!F!e%_(m^lQZtq* zYwi}gY(KZ*Y^OWRNj$Ph#uEEBM+wtN8QFQ@^`GDOln^ioNrmtvzNNi*qS5lPHxI96#sMil*teLVaa%$msF>@5p#SjT%q8|<4ZOUB#!-kG+|eFSED z!|3c8fXaym9qH`L;pmqTWcG}WE$(h1sZ3seM>)E3ptoP<;~h~qe6XA)lGVanf&->P zjZwi;_;Dt+bYdAeD_XSQ-DgXRXqLv`3Wcgl}myA-JlzBBIh zWq4Q*9#(zjAk_H8VS_AJ`?OS*^gB-rp|~qt;v(C5ef=SErv;~zL64hW`#g!UZQcvZ zF6Ra@S@YhVSkSWVAY=Z1w)w-hfJDRwKTUH0o-OG5TlW0HDH36hIjnP=?A+8u1)Qyy5U8Gi$! zt^!vy|f=YHfQ`ZRK?D zXXn*kItRg50vr2+_hV5kjOleg#s~z(J2p#`=1Tq4#JS`MC^e4p&s7Ir=3m(K$LW#` z=ULCoWtna!so+QQ*JHb~6Ps9_&Ag>9qsUskp0pKbi`n?(u3&@QT!?}N}rXn z>1eHi6(@LicU*AR1obe+nbzTCD#VTJ`PFLRT(nc$NWrhsgRwFni*D(#?W^x=J6?|b zENSc^D}s>Y55)PzFs2d_2;yh89E0ZIgs&>6JV=pL6k9g_(`$04EoY+Zjn}}8e#n83 zJ=zB>BU<253Erdo$wE4^+@QQJFZyAj#(InFlN;!UGg96R@{Y&%OlGG;dM)^X8=Ddw@&2Vx?zui$tO z-{zgaU7&F!xs=e`Mn}r+xrdIAmkraRN_7P1?qu1|TZ%1QR(Mn?k+pq`Xys2v9Gs=a z?r@g&;UKcM#?36r9k*eVD(}9qe8?irotsn0+eHH8*4 zPX@Lusr)$J%8jarx5ssEJ?twFyu4kAbrf`96_z{6at^&UkyDzFa69RXP>PeK+dAWqE5<5P+aHa zs<<*+OO_2ObTXau%y)Nn{(p5`XIPWlvi|asjYcui;E@)Ig{YKBXi}spqC!-P5owwL z3L*+9;0C0G!xoN;4KNfDaElv>1#DMDglI&MAVoK2+c2Pr8&sl*1dYj=^>NRS`{O&%YV25@5*eoOvpD_(xdKsnqb^`T}bm;n0BN9ben1Ynyi*OOf;qLpf^ z!T{}GzkXSszN_Xqzp>}S*Im)_Y8~2|B*ybw(U=Q)5_NcMkT;)1&52YQJB)Tn%kPK! z@3;^AI){B(&UOv<{v9KKJrInkdcXV0%O1%1=7vYV*j?v(Kp~arZio$#(A@$kYB3aM zRdm4!^Je15%66($EkCIWGhi@=kNAyLJ3ydlJnCpPuxH0+OA}J)+t8d7nT->##Nz4w-L=S7ExQt=Rx}S*mpT91(>t~qe7tM%e|O)TIO^dP zfo61GNS=cJbLutqUh84?7X#bq)bv57s&D_zm{+xNv7vHjb=_}j-Lrj-Ss*pcD@ts$ z)5Dol8Z_&*1@JdAQE7SL$*!TXI|YE7q=YGkIiUeLvT0)14Q-ivs|+cqeT6DTi9eQ)h?Pu9pqmH51B* zFMd|;l2@D4*56|EhMFlDxl2i<8qq=c+AhMYS3(A28#3DZ;_Ln>RA3q#IAdJq7M#N> zTZ8t=_>lq0=W&w|bdQ^sy&m^@KR)mNi3|1<6|OL(0KLtP#I6ix$2b{-Y9GP5I7 z8AJUSCnlia5vWawX%ZLWTC2UV$cn^sfv68W!6)QO;ZjnX=7#`$ZPRG~irfl)ZUJ^D z{lUk?(*SU7XIiS^H{Lpxn%542#PgxdeG)Ociej#(uvX)z;Z3)<16Yhd z-sv?qQ5D4a)ZYoYPRep2Zvom@U)HKq*54ZEwdaEq^FZG#(CyG!=Vw(0j8CCmP~`_z z=OR^i&WkDCf2cLvWm@d?)mEgme{hA(o#xAL023LZ3(82SGRg6jJF7$kZ4! z6*FTm4y6v~CP!3$+fxg{QeFo24<3iucgI!oyjV|9Dsx}r~4X@lt^VaH$u zD?87}1Jh=?G8OYg*ts2k;X9{f*Za?yu8IUUfyuQ**wbcWT+KncjD^qQ3h&w2+S(Mj zZM~?Ot%ggTIHwkBkL-4&jI5R=B+MCOR42bKzC2M>l?1%x2Iv7amIfQ1B#wwfD`z|m z+E?G+o(tde*Ws?;Wo4p#Yy>Nnf|*b<nj@-s(rZ)-U@ z(Xe(qZ1(_dH|J3yWu|bAPINK}DwF(kZ>FKx(?ZmU^KFC6*bh$;FKGh~pH1 zozA+kgcIk9@2aAwEJ=VYizT!sxDXX$N?XDiGKaaT-OU@Ib=~4DmgEk&{2D@IvyjF* zuF@sDcuuqx_FAgx;B@@8gqjMh!kQeEKA*y4+q+^4&uc0|>M;$Xb+ z@X%eUx1m%$WSP}Qchx68NQ?dO!h`6;Quq+A1(RORsQ-;6bZ90vj#^0(7>cLR+-_;9 zCd@b~B5V>$tpjkQU#BD%9^zu7-l>U8nzt+XuX5cYDCHYaX5t~~3?lpa;)Mr>q;5XW zu(Th;fr}-GkP`K)u97(#UB|L3f;H7Cd#Pox+auV`=m?a=mSv1v)(V!E=$%gkIJZ;` zZj{Lb@bhs%bRa znZw9cD$cDFVHPtpXwY1K)wys@LS~;!qdqkR>@&RtP>?M^>xe{4N#EtZy4zZ5Ar$ZF zV=X=(!xin-58MC<+b~;jk8Q|3B3THGIA$cM8Bg)Yd6ygP#i?4VrX3OvP_k5i{Cppw z-{$XwrJ-+X$ccJ(Q{|?T@U9=-?qlsfA43%8t247KZn?`+C4e`b-e^(df*iW66=Oc2 z3w9UhohfdY@pH1MZ}vc<1osV(2CGG)Ree$E-T;8>$zw*>x-505b&4(shMGIjbAfLS zEZ3ys(`SmCWc(75)^=aKer}>67qj^nGKtCK{35I|tA}wQa!uM!suX%Gb~ylORGGc( ze^|m|N!}G0#Ph|;wSXz`SByQM>lPM#8>mdSQs`7RxkXaSAADYA24u6xWqkIXY?o%z z%TEFL+wNW^&nrvaA1_#P%&Hbzrjl!*hIft>F0@g0IVydUU4MJgS3_3Js8{*>|G2jC z4%n#cOy9b2Xf&Pw=14;0Dtf00C^Z$I-v05OqtvN9>sAC&oV1Tk;;ku7VR`sQK4oFq zQ8)yoZNuTwV$t13|GCUIC{ID_r7M5&R*zhsxbrkg;EgMtL|9ne=^}BM!dxV!KDeXkWA^MfQTkQEt8~t>JznNh%ULvn@dbQ2cyf} z|C%ns#NJU}SHU(7Pg$<&8uDK>d5GZJ&`;CcfGP(~b-#UusXevc^q!km1X6_wVMqGk z^m&ZS6#42?p4c_t1TA$_+}h1L2c<<=$k%;v+D!<@j5hs|{>d18>~~v#oq4yGyS@QP zgTX2oJbEy@eJbo-f{ZQ>-nmB-#AqWcHbMQXFi*T)0n!(HIexz=pp<(O*DMh7CMupX z)ei1ZYuIW~E={-ND*nD;okiZdm!?^|LjLZhs*FHZvWld5TDj zcvWB)`-1Me9bu`*4M=CO6ye=pMgxlgYvsh2rV#5Z$hFKw0GX30%oufb=hJ0BFIJH` z+Fii4gQ+7!)8K^yc*PVEW^#f!|BW0Q5*`IewQ5YDFh?{x1L7tlaUAX@3Y+D>6FPVf zJzOGex~H34`8eq+TL$FsHm+27RS>3$CG;>0Jj4*1ukX$za})*b^S5p}I2jbFCHLsA zzYwAyftMz`uo2c8ieQcy-p&9iP3fMk(uRw+OlBPm`KCLei6g!|Vnk*-kjs>A25MTE z5GLDMV$70AC0j-tx*0sCruvKh{fSM)3X}13U>m|KeaOb`9^}v^44!$`06-JHf@L4EKyxV)M!8cL zi5p9kF97RiAT92!e?%9CP=qX3wyv^A8q!w%07d(9f-U))uDgsr4FDVL;|%r)fw}-@ zlB$F79X^EKYF%8J7mU?3VzJoYQ0<;NczW1jH4=4kEh_)q|^9wj zIsn-SsmRx0_EJ7(6WypwptIwZ)-T<__UgUu?BXt zoIf|a!5`?&JEb$w2PZSqhA>J;GIA^rJ-Cpz8MKX~bcqZNOUzPtu|NMvEP>+cO;V*W zNQ8YPENkr!)lN+tlxB79RUD20$)+_P6Jc`+4q@%Kno{F+#1qR*zrj%T>nTSceO?a5 zyqGDa59#G6k*RXu6+#=e=e!~i1Y&15!cHmE6sLh_K%Ppv$tFE-Le3RQs-nx5LB>gy z5A))kwkxWSy73{@I{%{DY8X+2o{CLJb~R$3r=oT^P~Xo$2lKz8?Z!3QLn$5l#L2k2 zb1=?UT&c<8!&9gW1M&jI!5%dhJbD3nQXpaeNJ>=zR+EL!4iY(nMBQI+|2J+Hw-WMr z08Mt9h8(PGbY?zKtk=cqw(yW}1A#htn* z8&}5Y>$uc>Lv!bSuWQ5UB&ct7*jiZAFpxz|%xO&5kg zzlf?6xy7H3G^*wvP5scW*Wf(<&eP!YIUf%&HT?K)RWmKg$G^=mSoi~;&9dU%{o}WV z#BX;9+q)fpVU`>Vdo~AtYK)`7z*H;dc-e|q6Qt;3J0APUL!~g&Q literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..ed4cc16421680a50164ba74381b4b35ceaa0ccfc GIT binary patch literal 3276 zcmZ`*X*|?x8~)E?#xi3t91%vcMKbnsIy2_j%QE2ziLq8HEtbf{7%?Q-9a%z_Y^9`> zEHh*&vUG%uWkg7pKTS-`$veH@-Vg8ZdG7oAJ@<88AMX3Z{d}TU-4*=KI1-hF6u>DKF2moPt09c{` zfN3rO$X+gJI&oA$AbgKoTL8PiPI1eFOhHBDvW+$&oPl1s$+O5y3$30Jx9nC_?fg%8Om)@;^P;Ee~8ibejUNlSR{FL7-+ zCzU}3UT98m{kYI^@`mgCOJ))+D#erb#$UWt&((j-5*t1id2Zak{`aS^W*K5^gM02# zUAhZn-JAUK>i+SNuFbWWd*7n1^!}>7qZ1CqCl*T+WoAy&z9pm~0AUt1cCV24f z3M@&G~UKrjVHa zjcE@a`2;M>eV&ocly&W3h{`Kt`1Fpp?_h~9!Uj5>0eXw@$opV(@!pixIux}s5pvEqF5$OEMG0;c zAfMxC(-;nx_`}8!F?OqK19MeaswOomKeifCG-!9PiHSU$yamJhcjXiq)-}9`M<&Au|H!nKY(0`^x16f205i2i;E%(4!?0lLq0sH_%)Wzij)B{HZxYWRl3DLaN5`)L zx=x=|^RA?d*TRCwF%`zN6wn_1C4n;lZG(9kT;2Uhl&2jQYtC1TbwQlP^BZHY!MoHm zjQ9)uu_K)ObgvvPb}!SIXFCtN!-%sBQe{6NU=&AtZJS%}eE$i}FIll!r>~b$6gt)V z7x>OFE}YetHPc-tWeu!P@qIWb@Z$bd!*!*udxwO6&gJ)q24$RSU^2Mb%-_`dR2`nW z)}7_4=iR`Tp$TPfd+uieo)8B}Q9#?Szmy!`gcROB@NIehK|?!3`r^1>av?}e<$Qo` zo{Qn#X4ktRy<-+f#c@vILAm;*sfS}r(3rl+{op?Hx|~DU#qsDcQDTvP*!c>h*nXU6 zR=Un;i9D!LcnC(AQ$lTUv^pgv4Z`T@vRP3{&xb^drmjvOruIBJ%3rQAFLl7d9_S64 zN-Uv?R`EzkbYIo)af7_M=X$2p`!u?nr?XqQ_*F-@@(V zFbNeVEzbr;i2fefJ@Gir3-s`syC93he_krL1eb;r(}0yUkuEK34aYvC@(yGi`*oq? zw5g_abg=`5Fdh1Z+clSv*N*Jifmh&3Ghm0A=^s4be*z5N!i^FzLiShgkrkwsHfMjf z*7&-G@W>p6En#dk<^s@G?$7gi_l)y7k`ZY=?ThvvVKL~kM{ehG7-q6=#%Q8F&VsB* zeW^I zUq+tV(~D&Ii_=gn-2QbF3;Fx#%ajjgO05lfF8#kIllzHc=P}a3$S_XsuZI0?0__%O zjiL!@(C0$Nr+r$>bHk(_oc!BUz;)>Xm!s*C!32m1W<*z$^&xRwa+AaAG= z9t4X~7UJht1-z88yEKjJ68HSze5|nKKF9(Chw`{OoG{eG0mo`^93gaJmAP_i_jF8a z({|&fX70PXVE(#wb11j&g4f{_n>)wUYIY#vo>Rit(J=`A-NYYowTnl(N6&9XKIV(G z1aD!>hY!RCd^Sy#GL^0IgYF~)b-lczn+X}+eaa)%FFw41P#f8n2fm9=-4j7}ULi@Z zm=H8~9;)ShkOUAitb!1fvv%;2Q+o)<;_YA1O=??ie>JmIiTy6g+1B-1#A(NAr$JNL znVhfBc8=aoz&yqgrN|{VlpAniZVM?>0%bwB6>}S1n_OURps$}g1t%)YmCA6+5)W#B z=G^KX>C7x|X|$~;K;cc2x8RGO2{{zmjPFrfkr6AVEeW2$J9*~H-4~G&}~b+Pb}JJdODU|$n1<7GPa_>l>;{NmA^y_eXTiv z)T61teOA9Q$_5GEA_ox`1gjz>3lT2b?YY_0UJayin z64qq|Nb7^UhikaEz3M8BKhNDhLIf};)NMeS8(8?3U$ThSMIh0HG;;CW$lAp0db@s0 zu&jbmCCLGE*NktXVfP3NB;MQ>p?;*$-|htv>R`#4>OG<$_n)YvUN7bwzbWEsxAGF~ zn0Vfs?Dn4}Vd|Cf5T-#a52Knf0f*#2D4Lq>-Su4g`$q={+5L$Ta|N8yfZ}rgQm;&b z0A4?$Hg5UkzI)29=>XSzdH4wH8B@_KE{mSc>e3{yGbeiBY_+?^t_a#2^*x_AmN&J$ zf9@<5N15~ty+uwrz0g5k$sL9*mKQazK2h19UW~#H_X83ap-GAGf#8Q5b8n@B8N2HvTiZu&Mg+xhthyG3#0uIny33r?t&kzBuyI$igd`%RIcO8{s$$R3+Z zt{ENUO)pqm_&<(vPf*$q1FvC}W&G)HQOJd%x4PbxogX2a4eW-%KqA5+x#x`g)fN&@ zLjG8|!rCj3y0%N)NkbJVJgDu5tOdMWS|y|Tsb)Z04-oAVZ%Mb311P}}SG#!q_ffMV z@*L#25zW6Ho?-x~8pKw4u9X)qFI7TRC)LlEL6oQ9#!*0k{=p?Vf_^?4YR(M z`uD+8&I-M*`sz5af#gd$8rr|oRMVgeI~soPKB{Q{FwV-FW)>BlS?inI8girWs=mo5b18{#~CJz!miCgQYU>KtCPt()StN;x)c2P3bMVB$o(QUh z$cRQlo_?#k`7A{Tw z!~_YKSd(%1dBM+KE!5I2)ZZsGz|`+*fB*n}yxtKVyx14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>GbI`Jdw*pGcA%L+*Q#&*YQOJ$_%U#(BDn``;rKxi&&)LfRxIZ*98z8UWRslDo@Xu)QVh}rB>bKwe@Bjzwg%m$hd zG)gFMgHZlPxGcm3paLLb44yHI|Ag0wdp!_yD5R<|B29Ui~27`?vfy#ktk_KyHWMDA42{J=Uq-o}i z*%kZ@45mQ-Rw?0?K+z{&5KFc}xc5Q%1PFAbL_xCmpj?JNAm>L6SjrCMpiK}5LG0ZE zO>_%)r1c48n{Iv*t(u1=&kH zeO=ifbFy+6aSK)V_5t;NKhE#$Iz=+Oii|KDJ}W>g}0%`Svgra*tnS6TRU4iTH*e=dj~I` zym|EM*}I1?pT2#3`oZ(|3I-Y$DkeHMN=8~%YSR?;>=X?(Emci*ZIz9+t<|S1>hE8$ zVa1LmTh{DZv}x6@Wz!a}+qZDz%AHHMuHCzM^XlEpr!QPzf9QzkS_0!&1MPx*ICxe}RFdTH+c}l9E`G zYL#4+3Zxi}3=A!G4S>ir#L(2r)WFKnP}jiR%D`ZOPH`@ZhTQy=%(P0}8ZH)|z6jL7 N;OXk;vd$@?2>?>Ex^Vyi literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000000000000000000000000000000000000..bcbf36df2f2aaaa0a63c7dabc94e600184229d0d GIT binary patch literal 5933 zcmZ{Idpwix|Np(&m_yAF>K&UIn{t*2ZOdsShYs(MibU!|=pZCJq~7E>B$QJr)hC5| zmk?V?ES039lQ~RC!kjkl-TU4?|NZ{>J$CPLUH9vHy`Hbhhnc~SD_vpzBp6Xw4`$%jfmPw(;etLCccvfU-s)1A zLl8-RiSx!#?Kwzd0E&>h;Fc z^;S84cUH7gMe#2}MHYcDXgbkI+Qh^X4BV~6y<@s`gMSNX!4@g8?ojjj5hZj5X4g9D zavr_NoeZ=4vim%!Y`GnF-?2_Gb)g$xAo>#zCOLB-jPww8a%c|r&DC=eVdE;y+HwH@ zy`JK(oq+Yw^-hLvWO4B8orWwLiKT!hX!?xw`kz%INd5f)>k1PZ`ZfM&&Ngw)HiXA| ze=+%KkiLe1hd>h!ZO2O$45alH0O|E+>G2oCiJ|3y2c$;XedBozx93BprOr$#d{W5sb*hQQ~M@+v_m!8s?9+{Q0adM?ip3qQ*P5$R~dFvP+5KOH_^A+l-qu5flE*KLJp!rtjqTVqJsmpc1 zo>T>*ja-V&ma7)K?CE9RTsKQKk7lhx$L`9d6-Gq`_zKDa6*>csToQ{&0rWf$mD7x~S3{oA z1wUZl&^{qbX>y*T71~3NWd1Wfgjg)<~BnK96Ro#om&~8mU{}D!Fu# zTrKKSM8gY^*47b2Vr|ZZe&m9Y`n+Y8lHvtlBbIjNl3pGxU{!#Crl5RPIO~!L5Y({ym~8%Ox-9g>IW8 zSz2G6D#F|L^lcotrZx4cFdfw6f){tqITj6>HSW&ijlgTJTGbc7Q#=)*Be0-s0$fCk z^YaG;7Q1dfJq#p|EJ~YYmqjs`M0jPl=E`Id{+h%Lo*|8xp6K7yfgjqiH7{61$4x~A zNnH+65?QCtL;_w(|mDNJXybin=rOy-i7A@lXEu z&jY(5jhjlP{TsjMe$*b^2kp8LeAXu~*q&5;|3v|4w4Ij_4c{4GG8={;=K#lh{#C8v z&t9d7bf{@9aUaE94V~4wtQ|LMT*Ruuu0Ndjj*vh2pWW@|KeeXi(vt!YXi~I6?r5PG z$_{M*wrccE6x42nPaJUO#tBu$l#MInrZhej_Tqki{;BT0VZeb$Ba%;>L!##cvieb2 zwn(_+o!zhMk@l~$$}hivyebloEnNQmOy6biopy`GL?=hN&2)hsA0@fj=A^uEv~TFE z<|ZJIWplBEmufYI)<>IXMv(c+I^y6qBthESbAnk?0N(PI>4{ASayV1ErZ&dsM4Z@E-)F&V0>tIF+Oubl zin^4Qx@`Un4kRiPq+LX5{4*+twI#F~PE7g{FpJ`{)K()FH+VG^>)C-VgK>S=PH!m^ zE$+Cfz!Ja`s^Vo(fd&+U{W|K$e(|{YG;^9{D|UdadmUW;j;&V!rU)W_@kqQj*Frp~ z7=kRxk)d1$$38B03-E_|v=<*~p3>)2w*eXo(vk%HCXeT5lf_Z+D}(Uju=(WdZ4xa( zg>98lC^Z_`s-=ra9ZC^lAF?rIvQZpAMz8-#EgX;`lc6*53ckpxG}(pJp~0XBd9?RP zq!J-f`h0dC*nWxKUh~8YqN{SjiJ6vLBkMRo?;|eA(I!akhGm^}JXoL_sHYkGEQWWf zTR_u*Ga~Y!hUuqb`h|`DS-T)yCiF#s<KR}hC~F%m)?xjzj6w#Za%~XsXFS@P0E3t*qs)tR43%!OUxs(|FTR4Sjz(N zppN>{Ip2l3esk9rtB#+To92s~*WGK`G+ECt6D>Bvm|0`>Img`jUr$r@##&!1Ud{r| zgC@cPkNL_na`74%fIk)NaP-0UGq`|9gB}oHRoRU7U>Uqe!U61fY7*Nj(JiFa-B7Av z;VNDv7Xx&CTwh(C2ZT{ot`!E~1i1kK;VtIh?;a1iLWifv8121n6X!{C%kw|h-Z8_U z9Y8M38M2QG^=h+dW*$CJFmuVcrvD*0hbFOD=~wU?C5VqNiIgAs#4axofE*WFYd|K;Et18?xaI|v-0hN#D#7j z5I{XH)+v0)ZYF=-qloGQ>!)q_2S(Lg3<=UsLn%O)V-mhI-nc_cJZu(QWRY)*1il%n zOR5Kdi)zL-5w~lOixilSSF9YQ29*H+Br2*T2lJ?aSLKBwv7}*ZfICEb$t>z&A+O3C z^@_rpf0S7MO<3?73G5{LWrDWfhy-c7%M}E>0!Q(Iu71MYB(|gk$2`jH?!>ND0?xZu z1V|&*VsEG9U zm)!4#oTcgOO6Hqt3^vcHx>n}%pyf|NSNyTZX*f+TODT`F%IyvCpY?BGELP#s<|D{U z9lUTj%P6>^0Y$fvIdSj5*=&VVMy&nms=!=2y<5DP8x;Z13#YXf7}G)sc$_TQQ=4BD zQ1Le^y+BwHl7T6)`Q&9H&A2fJ@IPa;On5n!VNqWUiA*XXOnvoSjEIKW<$V~1?#zts>enlSTQaG2A|Ck4WkZWQoeOu(te znV;souKbA2W=)YWldqW@fV^$6EuB`lFmXYm%WqI}X?I1I7(mQ8U-pm+Ya* z|7o6wac&1>GuQfIvzU7YHIz_|V;J*CMLJolXMx^9CI;I+{Nph?sf2pX@%OKT;N@Uz9Y zzuNq11Ccdwtr(TDLx}N!>?weLLkv~i!xfI0HGWff*!12E*?7QzzZT%TX{5b7{8^*A z3ut^C4uxSDf=~t4wZ%L%gO_WS7SR4Ok7hJ;tvZ9QBfVE%2)6hE>xu9y*2%X5y%g$8 z*8&(XxwN?dO?2b4VSa@On~5A?zZZ{^s3rXm54Cfi-%4hBFSk|zY9u(3d1ButJuZ1@ zfOHtpSt)uJnL`zg9bBvUkjbPO0xNr{^{h0~$I$XQzel_OIEkgT5L!dW1uSnKsEMVp z9t^dfkxq=BneR9`%b#nWSdj)u1G=Ehv0$L@xe_eG$Ac%f7 zy`*X(p0r3FdCTa1AX^BtmPJNR4%S1nyu-AM-8)~t-KII9GEJU)W^ng7C@3%&3lj$2 z4niLa8)fJ2g>%`;;!re+Vh{3V^}9osx@pH8>b0#d8p`Dgm{I?y@dUJ4QcSB<+FAuT)O9gMlwrERIy z6)DFLaEhJkQ7S4^Qr!JA6*SYni$THFtE)0@%!vAw%X7y~!#k0?-|&6VIpFY9>5GhK zr;nM-Z`Omh>1>7;&?VC5JQoKi<`!BU_&GLzR%92V$kMohNpMDB=&NzMB&w-^SF~_# zNsTca>J{Y555+z|IT75yW;wi5A1Z zyzv|4l|xZ-Oy8r8_c8X)h%|a8#(oWcgS5P6gtuCA_vA!t=)IFTL{nnh8iW!B$i=Kd zj1ILrL;ht_4aRKF(l1%^dUyVxgK!2QsL)-{x$`q5wWjjN6B!Cj)jB=bii;9&Ee-;< zJfVk(8EOrbM&5mUciP49{Z43|TLoE#j(nQN_MaKt16dp#T6jF7z?^5*KwoT-Y`rs$ z?}8)#5Dg-Rx!PTa2R5; zx0zhW{BOpx_wKPlTu;4ev-0dUwp;g3qqIi|UMC@A?zEb3RXY`z_}gbwju zzlNht0WR%g@R5CVvg#+fb)o!I*Zpe?{_+oGq*wOmCWQ=(Ra-Q9mx#6SsqWAp*-Jzb zKvuPthpH(Fn_k>2XPu!=+C{vZsF8<9p!T}U+ICbNtO}IAqxa57*L&T>M6I0ogt&l> z^3k#b#S1--$byAaU&sZL$6(6mrf)OqZXpUPbVW%T|4T}20q9SQ&;3?oRz6rSDP4`b z(}J^?+mzbp>MQDD{ziSS0K(2^V4_anz9JV|Y_5{kF3spgW%EO6JpJ(rnnIN%;xkKf zn~;I&OGHKII3ZQ&?sHlEy)jqCyfeusjPMo7sLVr~??NAknqCbuDmo+7tp8vrKykMb z(y`R)pVp}ZgTErmi+z`UyQU*G5stQRsx*J^XW}LHi_af?(bJ8DPho0b)^PT|(`_A$ zFCYCCF={BknK&KYTAVaHE{lqJs4g6B@O&^5oTPLkmqAB#T#m!l9?wz!C}#a6w)Z~Z z6jx{dsXhI(|D)x%Yu49%ioD-~4}+hCA8Q;w_A$79%n+X84jbf?Nh?kRNRzyAi{_oV zU)LqH-yRdPxp;>vBAWqH4E z(WL)}-rb<_R^B~fI%ddj?Qxhp^5_~)6-aB`D~Nd$S`LY_O&&Fme>Id)+iI>%9V-68 z3crl=15^%0qA~}ksw@^dpZ`p;m=ury;-OV63*;zQyRs4?1?8lbUL!bR+C~2Zz1O+E@6ZQW!wvv z|NLqSP0^*J2Twq@yws%~V0^h05B8BMNHv_ZZT+=d%T#i{faiqN+ut5Bc`uQPM zgO+b1uj;)i!N94RJ>5RjTNXN{gAZel|L8S4r!NT{7)_=|`}D~ElU#2er}8~UE$Q>g zZryBhOd|J-U72{1q;Lb!^3mf+H$x6(hJHn$ZJRqCp^In_PD+>6KWnCnCXA35(}g!X z;3YI1luR&*1IvESL~*aF8(?4deU`9!cxB{8IO?PpZ{O5&uY<0DIERh2wEoAP@bayv z#$WTjR*$bN8^~AGZu+85uHo&AulFjmh*pupai?o?+>rZ7@@Xk4muI}ZqH`n&<@_Vn zvT!GF-_Ngd$B7kLge~&3qC;TE=tEid(nQB*qzXI0m46ma*2d(Sd*M%@Zc{kCFcs;1 zky%U)Pyg3wm_g12J`lS4n+Sg=L)-Y`bU705E5wk&zVEZw`eM#~AHHW96@D>bz#7?- zV`xlac^e`Zh_O+B5-kO=$04{<cKUG?R&#bnF}-?4(Jq+?Ph!9g zx@s~F)Uwub>Ratv&v85!6}3{n$bYb+p!w(l8Na6cSyEx#{r7>^YvIj8L?c*{mcB^x zqnv*lu-B1ORFtrmhfe}$I8~h*3!Ys%FNQv!P2tA^wjbH f$KZHO*s&vt|9^w-6P?|#0pRK8NSwWJ?9znhg z3{`3j3=J&|48MRv4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!ItFh?!xdN1Q+aGJ{c&& zS>O>_%)r1c48n{Iv*t(u1=&kHeO=ifbFy+6aSK)V_AxLppYn8Z42d|rc6w}vOsL55 z`t&mC&y2@JTEyg!eDiFX^k#CC!jq%>erB=yHqUP0XcDOTw6ko}L zX;EmMrq(fKk*eygEuA616;0)>@A{TK|55PV@70 z$OfzS*(VJxQev3J?yY?O=ul(v`fp}?u9z`JK3ugibK>)DyCwImZOF4d{xK%%Ks1*} zv$oa)9anR%lXIBUqYnhLmT>VOzHfNP?ZwJNZ!5$s9M08RynIvaXw>@G^T9@r9^KH1 zVy??F&uuk)bH9Y4pQY!hP58i_H6 znl-NcuCpLV6ZWU;4C zu@9exF&OZi`Bovq_m%T+WhU2kvkz@^_LpycBvqm3bMpLw8X-Or5sL>0AKE1$(k_L=_Zc=CUq#=x1-QZf)G7nHu@fmsQ1eN_N3+nTEz`4HI4Z6uVlE zJH+X&det8JU?tO?upcM4Z=cV!JV;yF>FfL5Q$M|W_2Z!P`S=}Wzp|_1^#d%e?_H`> zV@%vA$+bFVqhw9`U;TfP|5|PD{||OiYdor8P*i??|NJcb%kzT_73*7WE?Ua5hAnR2 z=7WE=PhTlJ#ZeRznjTUb;`E(wkMZrj4e|Hilz-mK>9cZHQY**5TUPw~u}k;u73KI}xAx!0m-)GVia|x^d3p~s_9gh83jA&Ra<8rM%`>U3x69t&NzbwWY}7Ar?)FK#IZ0z|d0H0EkRO w3{9;}4Xg|ebq&m|3=9_N6z8I7$jwj5OsmAL;bP(Gi$Dzwp00i_>zopr02+f8CIA2c literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/dev/a11y_assessments/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000000000000000000000000000000000000..e71a726136a47ed24125c7efc79d68a4a01961b4 GIT binary patch literal 14800 zcmZ{Lc|26@`~R6Crm_qwyCLMMh!)vm)F@HWt|+6V6lE=CaHfcnn4;2x(VilEl9-V} zsce-cGK|WaF}4{T=lt&J`Fy_L-|vs#>v^7+XU=`!*L|PszSj43o%o$Dj`9mM7C;ar z@3hrnHw59q|KcHn4EQr~{_70*BYk4yj*SqM&s>NcnFoIBdT-sm1A@YrK@dF#f+SPu z{Sb8441xx|AjtYQ1gQq5z1g(^49Fba=I8)nl7BMGpQeB(^8>dY41u79Dw6+j(A_jO z@K83?X~$;S-ud$gYZfZg5|bdvlI`TMaqs!>e}3%9HXev<6;dZZT8Yx`&;pKnN*iCJ z&x_ycWo9{*O}Gc$JHU`%s*$C%@v73hd+Mf%%9ph_Y1juXamcTAHd9tkwoua7yBu?V zgROzw>LbxAw3^;bZU~ZGnnHW?=7r9ZAK#wxT;0O<*z~_>^uV+VCU9B@)|r z*z^v>$!oH7%WZYrwf)zjGU|(8I%9PoktcsH8`z^%$48u z(O_}1U25s@Q*9{-3O!+t?w*QHo;~P99;6-KTGO{Cb#ADDYWF!eATsx{xh-!YMBiuE z%bJc7j^^B$Sa|27XRxg(XTaxWoFI}VFfV>0py8mMM;b^vH}49j;kwCA+Lw=q8lptk z?Pe`{wHI39A&xYkltf5*y%;-DF>5v`-lm0vydYtmqo0sClh5ueHCLJ+6$0y67Z zO-_LCT|JXi3tN7fB-!0_Kn#I+=tyUj87uR5*0>|SZ zy3x2;aql87`{aPZ@UbBwY0;Z-a*lYL90YApOAMKur7YgOiqA~Cne6%b&{V-t>Am2c z{eyEuKl!GsA*jF2H_gvX?bP~v46%3ax$r~B$HnZQ;UiCmRl`ROK8v>;Zs~upH9}qu1ZA3kn-AY2k2@CaH=Qh7K6`nU z3ib(Bk%H*^_omL6N4_G5NpY20UXGi}a$!}#lf<&J4~nhRwRM5cCB3Zvv#6+N1$g@W zj9?qmQ`zz-G9HTpoNl~bCOaEQqlTVYi7G0WmB5E34;f{SGcLvFpOb`+Zm)C(wjqLA z2;+nmB6~QDXbxZGWKLt38I%X$Q!;h zup9S~byxKv=$x|^YEV;l0l67jH~E8BU45ft_7xomac-48oq4PZpSNJbw<7DTM4mmz z!$)z#04cy%b8w@cOvjmb36o;gwYIOLwy+{I#3dJj#W4QdOWwJQ2#20AL49`hSFUa7 zFNAN3OD==G3_kbr1d96>l`_cI`<=thKNh5>hgg7FV>5TfC6d#u)9BNXi@p1K*;2Is zz+x;l4GbSt#*%>1iq}jGIebXYJY5;PGG0y(^{>SSuZY89aL`sDghOM&&pyP6ABJ#w zYwK~4^1eUQD)4!GL>`zrWeHV z-W!6JZbW*Ngo;Edhp_cOysYr!uhKS}vIg_UC}x z=jXxQfV@4B3`5 z!u#byBVXV5GtrSx_8bnT@iKv=Uc6n)Zpa`<9N>+!J~Loxptl5$Z`!u<3a)-+P)say z#=jc7^mJzPMI2;yMhCmN7YN78E7-^S(t8E}FklC;z|4PL{bO|JieM#p1mBjwyZMEm zkX^A1RXPGeS2YqtPMX~~t^$~oeFfWAU#jVLi%Z@l2hle^3|e(q?(uS=BVauF?VF{j z(owKLJuze;_@5p1OtRyrT`EFXf)NfMYb-)E8RVVdr<@}M>4R&~P=;B`c1L%o|8YfB z-a(LB-i8jc5!&B5cowyI2~M^YID&@Xt(D9v{|DB z959W z*vEA77fh3*w*UJ`4Y(bxsoEy6hm7_Wc5gT0^cvso%Ow>9<&@9Q>mxb6-^pv)5yc>n zQ~^!qY(lPQ1EDGkr%_*y*D8T^YbCa52^MVqYpTLhgJ;N5PfCQ{SXk|plD#Sm+g4c- zFeL2Dih35W4{_qb75U`4Rb#S0FEo%F85dOhXSX0huPOxdAid{&p6P;+9}I)XU7^=3RZu9M(g0dLyz_7$8K{`AddBLOfU&B_QNHtmsnNXq`hy~% zvJ{vtz~Yt9X|o}5vXX)9ZCHaRq8iAb zUDj8%(MpzJN39LferYKvIc!)z^5T-eW@j3h9a6d%WZ!%@2^@4+6%Z9W1GHZbOj|sb z0cU$}*~G$fYvDC|XulSC_;m}?KC2jg5pxES$Bt!hA|@EX*2+O!UEb5sn_^d>z;>;r~ zmO3BivdXboPY*}amsO&`xk|e)S*u=`o67MC(1WTB;OwG+ua4UV7T5Wvy%?U{Pa5cO zMoLG>#@chO{Oc72XPyX8f3jC7P`$j4$)0wc(b50COaDP3_Cm}aPAglUa7kRXAqmo5 z0KDD7G>Gmnpons40WJNYn+pxko92GXy@PvSErKE-Ou3)3UiRr7!L4+0%+5}sD{bf)uj^ounQ-Yn2%%JoZ%FjUv%yjS?Ks4u_88Jh%tNliYW~817IV@fqd1T zi(?;Fv-s3rQEn=9G*E-QzSl%YS|^fe*yn}Aqh!&P<5%#oB?*{wZMa5$PYa*A{VA8! zbOfS1W!W}cTo%g~iP$>WhE_x7#O4?h$jq=>{M77>bTAK_ z6uU0tl6HARboGi}=4krr6WP`9`aAt&P5ON1v(+H{T?jZuJ}B{L-=z3VX)}mZwzrqH zpf?T!k&$?{&{0_p>b`kdJbSb(p~tFcuG4zh6}hfl@ues6CfJu<-P+!>FlYMlD_3!E z9$6VE==tlxNYe(s;@8@+4c4jQ$R2g8t0QwE>Et|)5)@kJj6^yaqFYY?0LEM2C!+7+ z+FN|UxR1GCy1KA`{T_%24U+Vserchr5h`;U7TZPr@43x#MMN{@vV?KSII}R@5k`7cVK}E;c)$f~_{ZLDOoL|-01p~oafxi4F zG$?Wha&a*rTnz-nTI-bAJ*SLb!5(L!#iRdvLEyo>7D_=H78-qZrm=6{hkUR{tR{H! z`ZTOV$Oi6^qX5=_{f}V9h}WJAO%h9)kEUF#*-JyYDbOGZ>Nfs%7L}4p zopIul&&Bbn!C9o83ypC6W4F$X=_|pex$V4!Whm#48Wfm3*oAW0Gc&#&b+oq<8>aZR z2BLpouQQwyf$aHpQUK3pMRj(mS^^t#s$IC3{j*m9&l7sQt@RU{o_}N-xI_lh`rND^ zX~-8$o(;p^wf3_5-WZ^qgW`e8T@37{`J)e2KJdSSCUpX6KZu0Ga&U*+u3*PDAs1uK zpl)40+fROA@Vo#vK?^@Pq%w8DO9HdfmH+~vNinZ$5GRz?sD|k246NepqZd`>81P^P z#x#3kUS-}x4k%&~iEUrsb&-X#_;;?y9oCP4crMkC`=q58#NxQ| z*NXNA;GR4X=GiGXwab5=&M3j04fQw%2UxM`S(aE)_PlgJttBX96$$lY@Q%0xV^IbcHqzw^Uk&E=vFB;EQ@kzVIeM8lDIW_Q_ zrfy)l6s2QBApF;J2xTD_@wuNMlwDfsdfMyzRq)<>qG{M)Yt}9F1{1HaI_X7=F=7>& zYB54VaKlxu0lIgS;Ac&25Aw(tcf@K~(cvPi8(OChzhlYp6}#<_MVhU95sD&)n0FtL zmxm4w$~s(S9jmHOgyovpG!x4uLfJsMsJn^QMraKAa1Ix?{zkV!a7{f%-!u2{NqZ&) zo+^XB`eFQ4 zk-(;_>T#pTKyvW${yL|XXbcv?CE2Tp<3(PjeXhu^Jrp6^Mj}lg_)jamK{g;C+q^Da ztb!gV!q5)B7G1%lVanA2b>Xs?%hzCgJ{Hc!ldr9dnz7k^xG#4pDpr|0ZmxxiUVl}j zbD_rg3yAFQ>nnc)0>71D==715jRj4XsRb2#_lJoSOwky&c4957V-|m)@>b^Nak1!8 z@DsIOS8>Oe^T>tgB)WX3Y^I^65Uae+2M;$RxX_C)Aoo0dltvoRRIVQkpnegWj;D#G z+TwFIRUN%bZW3(K{8yN8!(1i0O!X3YN?Zo08L5D~)_tWQA8&|CvuQb8Od?p_x=GMF z-B@v9iNLYS1lUsbb`!%f5+1ev8RFPk7xyx5*G;ybRw(PW*yEZ$unu2`wpH)7b@ZXEz4Jr{?KZKYl!+3^)Q z)~^g?KlPGtT!{yQU&(Z&^rVjPu>ueeZN86AnhRwc)m|;5NvM&W3xD%n`+Hjg5$e8M zKh1Ju82L~&^ z-IQ5bYhsjqJfr38iwi~8<{oeREh|3l)*Enj4&Q$+mM$15YqwXeufK9P^(O=pj=F-1 zD+&REgwY~!W#ZPccSEi(*jiKJ5)Q|zX;hP}S2T9j_);epH9JQs{n>RG}{Nak)vIbfa zFQm?H;D+tzrBN2)6{?Mo%fzN6;6d_h0Qyn61)+XT63=!T*WQyRUoB_x0_)Ir`$FtS zak07C(mOaWN5m%bk?F9X&@mEVKN%{R6obt(9qw&p>w&p;R*l2th9$D^*`pC}NmB+v z>bk;OJ(C8p$G;jNvRsBbt=a!!tKnjJ`9*yQFgjEN1HcC<&>u9aStT3>Oq=MOQV!#WOZ6{cv$YVmlJdovPRV}<=IZUPeBVh5DC z91-?kimq3JUr;UMQ@0?h52gupvG=~(5AVdP(2(%*sL8!#K1-L$9B7MrWGdt(h&whR@vz~0oEHF8u3U1Q zdGdaIytJj4x@eF*E+^zgi{nPCA8tkjN}UoR8WhDzM3-zLqx0z?2tTdDKyENM={fp8VC@3Dt`AiK$;K#H$K2{08mrHG%jgEOLX3MCsG>afZm_0mLPS4jmYUJp~Dm! z5AUe_vEaOAT3zWdwl#cLvqwd1^lwW?gt7(92wEsOE6c#<0}{szFV4(uO70?3>=((! zQr}1{J?Wx2ZmjxYL_8OB*m&mimfojzYn~PiJ2g8R&ZRx-i^yF#sdhEWXAUIZ@J?T$ zs3PgT2<&Ki>Bob_n(@S>kUIvE+nY~ti9~6j;O9VAG#{oZ!DZCW)}i6iA!Tgsyz+hC z1VVyvbQ_nwgdZSEP=U4d#U`2*`e~d4y8uM4Bcmm%!jidaee#4WqN!ZnlBmbYpuaO! z!rU3`Kl2 z0O7PD&fQ|_b)Ub!g9^s;C2e>1i*2&?1$6yEn?~Y zI)-WIN8N(5s9;grW+J@K@I%g#?G&hzmlgV=L}ZA{f>3YCMx^P{u@c5Z;U1qmdk#)L zvX6z1!sL>+@vxO8qVn#k3YxYi?8ggV){?Rn@j$+Fd4-QkuH1@)j#3-=f82GZ!nl~{ zzZ(?kO`ANttVeHSo%xmH!NmNZECh*{s!-8S>ALoe5xOPs>|P5BbUmP@rlV8`d(c=7 zypcpLaI*FM^;GM%@q`GAb8kO`$oE|R48yn)?p(c1t>5;Wwn5r6ck&uw4}TnT80jI`IS~J%q8CpaVgIze<8IykSpVBg8~E! zW_tGqB;GO47r_er05y+Kwrcn{VLxL*1;HMv@*sd}MB6DH4zaP~u4Y;>@Nw7?F8S?c zfVIY(^ntnGgWlD|idzGz$Y+Oh(Ra=&VIf4!K2W*a)(%5%78s}8qxOknAGtDAq+HMO zM+Nu;0OgQRn36 zA@~a8`uVQ~v9?d!BxnsVaB-z-djypO44BjQAmg7&eVoaew|~)wH$SgefJ2$7_RiY+ z_7ACGoFM6Lhvho+eUG@pU&0X(Uy(*j;9pr?ET?FHTXadlfXC|MReZoU5>AG`mTM<% zc~*I@E*u0|hwVTdFA~4^b2VT7_~}~tCueNY{de3og=ASFQ`)0dhC2~Ne<}}Rc?ptA zi}+bQE%N9o*hpSUMH)9xt%Zlz&^p&5=cW}{m#f85iVX64^{!(vhClT<I)+c)RuiyrZqIw4v`z%YK&;_Fh4_+0B?qAGxMfAM`LzG_bjD>ib4;KGT4_1I>sxvL&&qp40ajgQOqIE^9=Az4w#ymo)bW-Vg{T!n=l&|nR_ zw+wcH|FxUH63)~{M;goHepmD{Fe?W9sO|eJP9L$G<{e_7FxxuXQ+)(Z^@;X8I1=%k zTK$gbHA1^4W<`q~ubQ0M_C^CA5#Z&*nGc(T?4Y_2jLu&FJDQYpCSiRny->$+nC9Jl z?avTW`ZXYT51%SrEq!}dXNM&!pM6nmL^lce=%S7{_TS)ckN8;{p*LT~LMgmlE~dpL zEBQy-jDj%cSK6N3)|CCR0LQ$N6iDM~+-1Oz|LAdkip(VZcO`gqCuJ+(Mm{m6@P%_; zBtF|MMVMP;E`5NJ{&@4j^JE5j&}(Jq{lCGL(P^#uqvbD`2)FVyfNgy|pvT!XY;02Z zZWbgGsvi6#!*$Zxwd{Xk6_M{+^yV_K@%_SAW(x)Lg|*AuG-%g2#GQYk8F?W&8|2dU z;00ppzrQnnYXnT`(S%_qF2#QNz&@Y$zcq+O8p>Gto2&4z8(^#cY?DuQwBQP4Fe?qUK_-yh4xT{8O@gb`uh` z>Q%jrgPAnANn4_)->n;w{Mei#J)F+`12&+-MLKSRzF6bL3;4O~oy~v7 zL0K-=m?>>(^qDCgvFRLBI@`04EGdTxe5}xBg#7#Wb!aUED;?5BLDEvZ@tai4*Rh8& z4V)cOr}DJ0&(FjWH%50Y+&=WtB42^eEVsmaHG)Il#j265oK&Bot(+-IIn`6InmuE# z;)qXs+X{fSb8^rYb#46X5?KCzH9X0>ppBQi(aKS--;4yA%0N|D<#8RZlOS(8n26=u zv~y;KC>`ypW=aqj`&x9 z0Zm>NKp}hPJu1+QDo(_U(Gt0SZ`IJWnp%QK`pye>Bm!w{sG>;VU^2 z4lZhV1}tCE8(?zu#j99|l3-qRBcz3bG+DlyxPGB$^6B^ssc_qYQ6lG0q~EAI?1$?( zahfn%etVvuKwB7R=>JDQluP97nLDM6*5;b0Ox#b{4nIgZA*+?IvyDN{K9WGnlA=Ju z+)6hjr}{;GxQQIDr3*lf32lRp{nHP8uiz^Fa|K+dUc@wD4Kf5RPxVkUZFCdtZH{+=c$AC)G2T-Qn@BPbr zZigIhKhKrVYy`!Mlc#HVr=CURVrhUjExhI~gZ%a=WM9BwvnN?=z!_ZQ$(sP?X;2Jy zyI$}H^^SvH2tf6+Uk$pJww@ngzPp856-l9g6WtW+%Yf>N^A}->#1W2n=WJ%sZ0<){Z&#% z^Kzl$>Km)sIxKLFjtc;}bZeoaZSpL4>`jCmAeRM-NP9sQ&-mi@p0j7Iq>1n&z@8?M z%dM7K^SgE5z)@i5w#rLE4+8%|^J`a6wYr`3BlvdD>7xW?Dd>`0HC0o{w7r_ot~h*G z2gI7Y!AUZ6YN+z$=GNzns@Tu7BxgAb3MBha30-ZG7a%rckU5}y{df`lj@^+34kr5> z988PPbWYdHye~=?>uZ4N&MN@4RBLk_?9W*b$}jqt0j%>yO9QOV(*!#cX~=wRdVL&S zhPQ{${0CGU-rfdS&b@u|IK{hV2Z=(*B2d0?&jwWfT=?Gk`4T9TfMQ)CfNgpLQa#>Q z%6A$w#QNc&qOtrHAbqY>J782@!X{9Y@N(HMSr;PP^;0DlJNxfC`oMB%Ocg zC*hnEsF|p*=CVe^dT)>BTL0yff)uo!U<+_2o3p)CE8quU1JI(=6)9$KxVdJYD*S*~ zzNeSkzFIQyqK}578+qq6X8rrRdgX z4k&R=AGex~a)MoB0pK&|yA<(*J#P&tR?ImBVD)ZTA4VH5L5DxXe<-*s`Aox%H1{-^Qa`kG_DGXD%QX-;l1#&#IVQP6>kir ztO@~ZvJDPnTvKt>fc*(j$W^)JhWk{4kWwbpFIXzuPt2V%M4H19-i5Gn*6(D`4_c1+ zYoI1@yT^~9JF~t>2eVM6p=GP3b*;daJpQOhAMNO|LKnwE2B5n8y9mf;q=)-L_FfD0 z<}YIRBO{k)6AHAn8iG>pYT+3bJ7jvP9}LSMR1nZW$5HR%PD1rFz z{4XE^Vmi-QX#?|Farz=CYS_8!%$E#G%4j2+;Avz|9QBj|YIExYk?y-1(j}0h{$$MnC_*F0U2*ExSi1ZCb_S9aV zTgyGP0Cl=m`emxM4Qih1E{`J{4oJo8K}WnH`@js^pR7Z-vTBK5F5JIFCDN}7pU^_nV>NTz@2$|Kcc5o+L&^Db_AQ);F?)X5BF*QJRCdLI-a%gW z++DZM)x=6*fNrSaUA&hf&CUqC$F*y^CJC-MAm9gd*5#^mh;-dR1?a&<3-hp3@}XN! z&8dcwo6=MQua%0KFvYbi>O{j)RrbDQo3S*y!oEJ~2=}^-v%zn~@hnmKGOvX6JLr;>DNC3)={8OM9n5Zs*(DlS*|%JTniJX2Uav7sOFT0vdIiUOC5pEtY?EF)@Fh9pCfD%N zXskZ8b^ldI{HHj{-l?iWo@IW6Nr`hAS>f8S*8FGc*gmcK^f2JS+>I&r#Gcewy=-JM zv0*w<5qBa6UQB@`esOG*4*t@7c9AkrTpM`v=eY?cO#z17H9B%Xy4m!}LhW}*iZ27w1?HrevgB1SZ1q2X$mm@FK@Qt7o z!s~Lio^IRdwzyvQ80{5iYeTV@mAo=2o5>KepRH0d{*Szlg~n%w2)S5v2|K8}pj;c{ zoDRLvYJO1@?x-=mq+LVhD{l-1-Dw4`7M?3@+ z`fu7?1#9W++6Y46N=H0+bD|CJH~q*CdEBm8D##VS7`cXy4~+x=ZC17rJeBh zI~qW^&FU`+e!{AKO3(>z5Ghh14bUT$=4B>@DVm(cj* zSLA*j!?z!=SLuVvAPh_EFKx}JE8T8;Gx)LH^H136=#Jn3Bo*@?=S`5M{WJPY&~ODs z+^V57DhJ2kD^Z|&;H}eoN~sxS8~cN5u1eW{t&y{!ouH`%p4(yDZaqw$%dlm4A0f0| z8H}XZFDs?3QuqI^PEy}T;r!5+QpfKEt&V|D)Z*xoJ?XXZ+k!sU2X!rcTF4tg8vWPM zr-JE>iu9DZK`#R5gQO{nyGDALY!l@M&eZsc*j*H~l4lD)8S?R*nrdxn?ELUR4kxK? zH(t9IM~^mfPs9WxR>J{agadQg@N6%=tUQ8Bn++TC|Hbqn*q;WydeNIS@gt|3j!P`w zxCKoeKQ*WBlF%l4-apIhERKl(hXS1vVk$U?Wifi)&lL6vF@bmFXmQEe{=$iG)Zt*l z0df@_)B-P_^K2P7h=>OIQ6f0Q-E@|M?$Z5n^oN>2_sBCpN>q(LnqUoef{tm^5^L$# z{<SL zKmH78cHX`4cBKIY8u1x*lwrgP^fJ%E&&AmHrRY7^hH*=2OA9K?!+|~Aeia=nAA`5~ z#zI=h#I>@FXaGk(n)0uqelNY;A5I9obE~OjsuW!%^NxK*52CfBPWYuw--v<1v|B>h z8R=#$TS-Pt3?d@P+xqmYpL4oB8- z>w99}%xqy9W!A^ODfLq8iA@z}10u?o#nG#MXumSaybi(S{`wIM z&nE3n2gWWMu93EvtofWzvG2{v;$ysuw^8q?3n}y=pB1vUr5gi++PjiyBH3jzKBRny zSO~O++1ZLdy7v7VzS&$yY;^Z7*j_#BI`PK`dAzJa9G1{9ahPqPi1C}ti+L)WHii*= z+RZ^+at-tlatc4|akPa&9H;%gn9aS`X_kfb>n>#NTyUVM6m4NCIfLm(28>qaYv7}t zn`M;XcONtXoa3#u3{L-ytd_&g z2mO$8CnE?460w#eSm|smlnNwFHM;A&IxSKLzVkV7nNVqZ*A`)eI{Nbg6WxsarAFuc=FFf1z|%#eTvBgUhY}N zsCT>`_YO>14i^vFX0KXbARLItzT{TeD%N~=ovGtZ6j{>PxkuYlHNTe0!u>rgw#?td z{)n=QrGvgCDE6BUem$Rh(1y!$@(Bn!k3E0|>PQ(8O==zN`?yBhAqlWyq+c%+h?p^- zE&OtLind}^_=>pbhxOgOIC0q9{cLK6p6*eg_|S+p9$W~_u4wzx@N?$QmFg2S)m~^R znni$X{U*!lHgdS@fI;|Owl=9Gwi?dr0m#>yL<8<}bLW_Kpl| zSGesADX&n?qmHC`2GyIev^hi~ka}ISZ^Y4w-yUzyPxaJB0mm%ww^>if3<;P^U+L5=s+cifT-ct*;!dOOk#SOZNv@a^J|DrS3YtSn8EEAlabX1NV3RfHwZn_41Xa z4;$taa6JJR()-FQ<#0G~WlML<l5I+IPnqDpW(PP>hRcQ+S2zU?tbG^(y z1K_?1R){jF;OKGw0WYjnm>aPxnmr5?bP?^B-|Fv`TT4ecH3O`Z3`X_r;vgFn>t1tE zGE6W2PODPKUj+@a%3lB;lS?srE5lp(tZ;uvzrPb){f~n7v_^z! z=16!Vdm!Q0q#?jy0qY%#0d^J8D9o)A;Rj!~j%u>KPs-tB08{4s1ry9VS>gW~5o^L; z7vyjmfXDGRVFa@-mis2!a$GI@9kE*pe3y_C3-$iVGUTQzZE+%>vT0=r|2%xMDBC@>WlkGU4CjoWs@D(rZ zS1NB#e69fvI^O#5r$Hj;bhHPEE4)4q5*t5Gyjzyc{)o459VkEhJ$%hJUC&67k z7gdo`Q*Jm3R&?ueqBezPTa}OI9wqcc;FRTcfVXob^z|dNIB0hMkHV26$zA%YgR$sM zTKM61S}#wJ#u+0UDE3N+U*~Tz1nnV;W<8Akz&6M7-6mIF(Pq`wJ1A%loYL( zIS;&2((xbyL7zoyaY2Sa%BBYBxo6Aa*53`~e@|RA`MP+?iI4KZ+y4EU&I zS_|(#*&j2hxpELa3r0O7ok&5!ijRiRu9i-_3cdnydZU9Mp6Y);skv%!$~`i-J7e-g zj@EoHf+gtcrKf;tY5`4iLnWSHa)9brUM$XmEzG3T0BXTG_+0}p7uGLs^(uYh0j$;~ zT1&~S%_Y5VImvf1EkD7vP-@F%hRlBe{a@T!SW(4WEQd1!O47*Crf@u-TS==48iR5x z!*`Ul4AJI^vIVaN3u5UifXBX{fJ@z>4Q2#1?jpcdLocwymBgKrZ+^Cb@QuIxl58B* zD{t-W3;M;{MGHm_@&n(6A-AsD;JO#>J3o4ru{hy;k;8?=rkp0tadEEcHNECoTI(W31`El-CI0eWQ zWD4&2ehvACkLCjG`82T`L^cNNC4Oo2IH(T4e;C75IwkJ&`|ArqSKD}TX_-E*eeiU& ziUuAC)A?d>-;@9Jcmsdca>@q1`6vzo^3etEH%1Gco&gvC{;Y-qyJ$Re`#A!5Kd((5 z6sSiKnA20uPX0**Mu&6tNgTunUR1sodoNmDst1&wz8v7AG3=^huypTi`S7+GrO$D6 z)0Ja-y5r?QQ+&jVQBjitIZ`z2Ia}iXWf#=#>nU+ zL29$)Q>f#o<#4deo!Kuo@WX{G(`eLaf%(_Nc}E`q=BXHMS(Os{!g%(|&tTDIczE_# z5y%wjCp9S?&*8bS3imJi_9_COC)-_;6D9~8Om@?U2PGQpM^7LKG7Q~(AoSRgP#tZfVDF_zr;_U*!F9qsbVQ@un9O2>T4M5tr0B~~v_@a=w^8h510a#=L z;8+9zhV}57uajb+9DbZm1G`_NqOuKN`bQ2fw9A*v*Kdb_E-SA`?2 z)OFIY-%uD`JZUZg?D4lHtNegKgWr!1m%hOpu5`R+bZ2K#&)*R-7ElKYo0$0xYxIL8 zLg%u|4oZixz}ILB-@aS4=XOe)z!VL6@?dX{LW^YCPjKtyw44)xT=H;h(fmFr>R?p%r5*}W z7_bo0drVDRq9V9QL4_!dazughK6t}tVVvBq={T0+3(1zmb>f+|;{D%J?^xnZcqio5 z%H?@L+L-CIdO=x6QrALL9&PwvjrZi5NS)1e<*%V8ntw~S2PF}zH}B5f_DHyB=I3m@ z_;^TpN|sesCU}qxQ`~jIwF>#8wGvxg9kdMT$}us8BM&W>OzZ|ry2BB)+UY*_yH+&L zl_=Jy9BNzIZs}D~Yv_H%HPjVGNV=xT3xpIW!Np1F^G#9Y8X zl)c_V1(DhYu-v%H3-m&n%M_}}c{E5Wu+6*>R24gW_A7$(U=9D|H$r;;;@o zJ)c_CmVf9l*;4SyJ}E{+4)}^C>SIJ*_bul7OJ{v&0oO>jG(5xzYP0$I%*YH|Mwu#r zubNW5VZ9^X#Phw<;?=^G?Kg&C)^x1FVsKGZ*n+{C1znj~YHSP?6PS(k5e9qGvS4X* z=1kA_27(iV65a(i+Sicmd@Vzf^2@*Wed-`aYQ~em=-h%Pu`gHfz)&@$hpr<&mNO={ zl^kI0HP0wTbbh{d(>5a#;zT2_=ppef?;D4;2^}&kZjB^yl%LBJ;|> zkLc)JEg*5rpQ;_)w?PnKynWtv!@ z>}+am{@(g$KKM+e$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/macos/Runner/Configs/AppInfo.xcconfig b/dev/a11y_assessments/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000000000..d209bdba247d7 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = a11y_assessments + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/dev/a11y_assessments/macos/Runner/Configs/Debug.xcconfig b/dev/a11y_assessments/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000000000..36b0fd9464f45 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/dev/a11y_assessments/macos/Runner/Configs/Release.xcconfig b/dev/a11y_assessments/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000000000..dff4f49561c81 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/dev/a11y_assessments/macos/Runner/Configs/Warnings.xcconfig b/dev/a11y_assessments/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000000000..42bcbf4780b18 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/dev/a11y_assessments/macos/Runner/DebugProfile.entitlements b/dev/a11y_assessments/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000000000..dddb8a30c851e --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/dev/a11y_assessments/macos/Runner/Info.plist b/dev/a11y_assessments/macos/Runner/Info.plist new file mode 100644 index 0000000000000..4789daa6a443e --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/dev/a11y_assessments/macos/Runner/MainFlutterWindow.swift b/dev/a11y_assessments/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000000000..a6a6b9af83072 --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,19 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/dev/a11y_assessments/macos/Runner/Release.entitlements b/dev/a11y_assessments/macos/Runner/Release.entitlements new file mode 100644 index 0000000000000..852fa1a4728ae --- /dev/null +++ b/dev/a11y_assessments/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/dev/a11y_assessments/macos/RunnerTests/RunnerTests.swift b/dev/a11y_assessments/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000000000..102c76116822b --- /dev/null +++ b/dev/a11y_assessments/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml new file mode 100644 index 0000000000000..81dc3007cc185 --- /dev/null +++ b/dev/a11y_assessments/pubspec.yaml @@ -0,0 +1,38 @@ +name: a11y_assessments +description: "A new Flutter project." + +environment: + sdk: '>=3.2.0-22.0.dev <4.0.0' + +dependencies: + flutter: + sdk: flutter + + characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +dev_dependencies: + flutter_test: + sdk: flutter + + async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +flutter: + uses-material-design: true + +# PUBSPEC CHECKSUM: b244 diff --git a/dev/a11y_assessments/test/accessibility_guideline_test.dart b/dev/a11y_assessments/test/accessibility_guideline_test.dart new file mode 100644 index 0000000000000..7bb1c56fcc3c9 --- /dev/null +++ b/dev/a11y_assessments/test/accessibility_guideline_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/main.dart'; +import 'package:a11y_assessments/use_cases/use_cases.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + for (final UseCase useCase in useCases) { + testWidgets('testing accessibility guideline for ${useCase.name}', (WidgetTester tester) async { + await tester.pumpWidget(const App()); + await tester.tap(find.byKey(Key(useCase.name))); + await tester.pumpAndSettle(); + + await expectLater(tester, meetsGuideline(textContrastGuideline)); + await expectLater(tester, meetsGuideline(androidTapTargetGuideline)); + await expectLater(tester, meetsGuideline(iOSTapTargetGuideline)); + await expectLater(tester, meetsGuideline(labeledTapTargetGuideline)); + }); + } +} diff --git a/dev/a11y_assessments/web/favicon.png b/dev/a11y_assessments/web/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1 GIT binary patch literal 917 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7 zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2 zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1AfjnEK zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8 zTYqUsf!gYFyJnXpu0!n&N*SYAX-%d(5gVjrHJWqXQshj@!Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/web/icons/Icon-192.png b/dev/a11y_assessments/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 zcmZ`-2T+sGz6~)*FVZ`aW+(v>MIm&M-g^@e2u-B-DoB?qO+b1Tq<5uCCv>ESfRum& zp%X;f!~1{tzL__3=gjVJ=j=J>+nMj%ncXj1Q(b|Ckbw{Y0FWpt%4y%$uD=Z*c-x~o zE;IoE;xa#7Ll5nj-e4CuXB&G*IM~D21rCP$*xLXAK8rIMCSHuSu%bL&S3)8YI~vyp@KBu9Ph7R_pvKQ@xv>NQ`dZp(u{Z8K3yOB zn7-AR+d2JkW)KiGx0hosml;+eCXp6+w%@STjFY*CJ?udJ64&{BCbuebcuH;}(($@@ znNlgBA@ZXB)mcl9nbX#F!f_5Z=W>0kh|UVWnf!At4V*LQP%*gPdCXd6P@J4Td;!Ur z<2ZLmwr(NG`u#gDEMP19UcSzRTL@HsK+PnIXbVBT@oHm53DZr?~V(0{rsalAfwgo zEh=GviaqkF;}F_5-yA!1u3!gxaR&Mj)hLuj5Q-N-@Lra{%<4ONja8pycD90&>yMB` zchhd>0CsH`^|&TstH-8+R`CfoWqmTTF_0?zDOY`E`b)cVi!$4xA@oO;SyOjJyP^_j zx^@Gdf+w|FW@DMdOi8=4+LJl$#@R&&=UM`)G!y%6ZzQLoSL%*KE8IO0~&5XYR9 z&N)?goEiWA(YoRfT{06&D6Yuu@Qt&XVbuW@COb;>SP9~aRc+z`m`80pB2o%`#{xD@ zI3RAlukL5L>px6b?QW1Ac_0>ew%NM!XB2(H+1Y3AJC?C?O`GGs`331Nd4ZvG~bMo{lh~GeL zSL|tT*fF-HXxXYtfu5z+T5Mx9OdP7J4g%@oeC2FaWO1D{=NvL|DNZ}GO?O3`+H*SI z=grGv=7dL{+oY0eJFGO!Qe(e2F?CHW(i!!XkGo2tUvsQ)I9ev`H&=;`N%Z{L zO?vV%rDv$y(@1Yj@xfr7Kzr<~0{^T8wM80xf7IGQF_S-2c0)0D6b0~yD7BsCy+(zL z#N~%&e4iAwi4F$&dI7x6cE|B{f@lY5epaDh=2-(4N05VO~A zQT3hanGy_&p+7Fb^I#ewGsjyCEUmSCaP6JDB*=_()FgQ(-pZ28-{qx~2foO4%pM9e z*_63RT8XjgiaWY|*xydf;8MKLd{HnfZ2kM%iq}fstImB-K6A79B~YoPVa@tYN@T_$ zea+9)<%?=Fl!kd(Y!G(-o}ko28hg2!MR-o5BEa_72uj7Mrc&{lRh3u2%Y=Xk9^-qa zBPWaD=2qcuJ&@Tf6ue&)4_V*45=zWk@Z}Q?f5)*z)-+E|-yC4fs5CE6L_PH3=zI8p z*Z3!it{1e5_^(sF*v=0{`U9C741&lub89gdhKp|Y8CeC{_{wYK-LSbp{h)b~9^j!s z7e?Y{Z3pZv0J)(VL=g>l;<}xk=T*O5YR|hg0eg4u98f2IrA-MY+StQIuK-(*J6TRR z|IM(%uI~?`wsfyO6Tgmsy1b3a)j6M&-jgUjVg+mP*oTKdHg?5E`!r`7AE_#?Fc)&a z08KCq>Gc=ne{PCbRvs6gVW|tKdcE1#7C4e`M|j$C5EYZ~Y=jUtc zj`+?p4ba3uy7><7wIokM79jPza``{Lx0)zGWg;FW1^NKY+GpEi=rHJ+fVRGfXO zPHV52k?jxei_!YYAw1HIz}y8ZMwdZqU%ESwMn7~t zdI5%B;U7RF=jzRz^NuY9nM)&<%M>x>0(e$GpU9th%rHiZsIT>_qp%V~ILlyt^V`=d z!1+DX@ah?RnB$X!0xpTA0}lN@9V-ePx>wQ?-xrJr^qDlw?#O(RsXeAvM%}rg0NT#t z!CsT;-vB=B87ShG`GwO;OEbeL;a}LIu=&@9cb~Rsx(ZPNQ!NT7H{@j0e(DiLea>QD zPmpe90gEKHEZ8oQ@6%E7k-Ptn#z)b9NbD@_GTxEhbS+}Bb74WUaRy{w;E|MgDAvHw zL)ycgM7mB?XVh^OzbC?LKFMotw3r@i&VdUV%^Efdib)3@soX%vWCbnOyt@Y4swW925@bt45y0HY3YI~BnnzZYrinFy;L?2D3BAL`UQ zEj))+f>H7~g8*VuWQ83EtGcx`hun$QvuurSMg3l4IP8Fe`#C|N6mbYJ=n;+}EQm;< z!!N=5j1aAr_uEnnzrEV%_E|JpTb#1p1*}5!Ce!R@d$EtMR~%9# zd;h8=QGT)KMW2IKu_fA_>p_und#-;Q)p%%l0XZOXQicfX8M~7?8}@U^ihu;mizj)t zgV7wk%n-UOb z#!P5q?Ex+*Kx@*p`o$q8FWL*E^$&1*!gpv?Za$YO~{BHeGY*5%4HXUKa_A~~^d z=E*gf6&+LFF^`j4$T~dR)%{I)T?>@Ma?D!gi9I^HqvjPc3-v~=qpX1Mne@*rzT&Xw zQ9DXsSV@PqpEJO-g4A&L{F&;K6W60D!_vs?Vx!?w27XbEuJJP&);)^+VF1nHqHBWu z^>kI$M9yfOY8~|hZ9WB!q-9u&mKhEcRjlf2nm_@s;0D#c|@ED7NZE% zzR;>P5B{o4fzlfsn3CkBK&`OSb-YNrqx@N#4CK!>bQ(V(D#9|l!e9(%sz~PYk@8zt zPN9oK78&-IL_F zhsk1$6p;GqFbtB^ZHHP+cjMvA0(LqlskbdYE_rda>gvQLTiqOQ1~*7lg%z*&p`Ry& zRcG^DbbPj_jOKHTr8uk^15Boj6>hA2S-QY(W-6!FIq8h$<>MI>PYYRenQDBamO#Fv zAH5&ImqKBDn0v5kb|8i0wFhUBJTpT!rB-`zK)^SNnRmLraZcPYK7b{I@+}wXVdW-{Ps17qdRA3JatEd?rPV z4@}(DAMf5EqXCr4-B+~H1P#;t@O}B)tIJ(W6$LrK&0plTmnPpb1TKn3?f?Kk``?D+ zQ!MFqOX7JbsXfQrz`-M@hq7xlfNz;_B{^wbpG8des56x(Q)H)5eLeDwCrVR}hzr~= zM{yXR6IM?kXxauLza#@#u?Y|o;904HCqF<8yT~~c-xyRc0-vxofnxG^(x%>bj5r}N zyFT+xnn-?B`ohA>{+ZZQem=*Xpqz{=j8i2TAC#x-m;;mo{{sLB_z(UoAqD=A#*juZ zCv=J~i*O8;F}A^Wf#+zx;~3B{57xtoxC&j^ie^?**T`WT2OPRtC`xj~+3Kprn=rVM zVJ|h5ux%S{dO}!mq93}P+h36mZ5aZg1-?vhL$ke1d52qIiXSE(llCr5i=QUS?LIjc zV$4q=-)aaR4wsrQv}^shL5u%6;`uiSEs<1nG^?$kl$^6DL z43CjY`M*p}ew}}3rXc7Xck@k41jx}c;NgEIhKZ*jsBRZUP-x2cm;F1<5$jefl|ppO zmZd%%?gMJ^g9=RZ^#8Mf5aWNVhjAS^|DQO+q$)oeob_&ZLFL(zur$)); zU19yRm)z<4&4-M}7!9+^Wl}Uk?`S$#V2%pQ*SIH5KI-mn%i;Z7-)m$mN9CnI$G7?# zo`zVrUwoSL&_dJ92YhX5TKqaRkfPgC4=Q&=K+;_aDs&OU0&{WFH}kKX6uNQC6%oUH z2DZa1s3%Vtk|bglbxep-w)PbFG!J17`<$g8lVhqD2w;Z0zGsh-r zxZ13G$G<48leNqR!DCVt9)@}(zMI5w6Wo=N zpP1*3DI;~h2WDWgcKn*f!+ORD)f$DZFwgKBafEZmeXQMAsq9sxP9A)7zOYnkHT9JU zRA`umgmP9d6=PHmFIgx=0$(sjb>+0CHG)K@cPG{IxaJ&Ueo8)0RWgV9+gO7+Bl1(F z7!BslJ2MP*PWJ;x)QXbR$6jEr5q3 z(3}F@YO_P1NyTdEXRLU6fp?9V2-S=E+YaeLL{Y)W%6`k7$(EW8EZSA*(+;e5@jgD^I zaJQ2|oCM1n!A&-8`;#RDcZyk*+RPkn_r8?Ak@agHiSp*qFNX)&i21HE?yuZ;-C<3C zwJGd1lx5UzViP7sZJ&|LqH*mryb}y|%AOw+v)yc`qM)03qyyrqhX?ub`Cjwx2PrR! z)_z>5*!*$x1=Qa-0uE7jy0z`>|Ni#X+uV|%_81F7)b+nf%iz=`fF4g5UfHS_?PHbr zB;0$bK@=di?f`dS(j{l3-tSCfp~zUuva+=EWxJcRfp(<$@vd(GigM&~vaYZ0c#BTs z3ijkxMl=vw5AS&DcXQ%eeKt!uKvh2l3W?&3=dBHU=Gz?O!40S&&~ei2vg**c$o;i89~6DVns zG>9a*`k5)NI9|?W!@9>rzJ;9EJ=YlJTx1r1BA?H`LWijk(rTax9(OAu;q4_wTj-yj z1%W4GW&K4T=uEGb+E!>W0SD_C0RR91 literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/web/icons/Icon-512.png b/dev/a11y_assessments/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 zcmd5=2T+s!lYZ%-(h(2@5fr2dC?F^$C=i-}R6$UX8af(!je;W5yC_|HmujSgN*6?W z3knF*TL1$|?oD*=zPbBVex*RUIKsL<(&Rj9%^UD2IK3W?2j>D?eWQgvS-HLymHo9%~|N2Q{~j za?*X-{b9JRowv_*Mh|;*-kPFn>PI;r<#kFaxFqbn?aq|PduQg=2Q;~Qc}#z)_T%x9 zE|0!a70`58wjREmAH38H1)#gof)U3g9FZ^ zF7&-0^Hy{4XHWLoC*hOG(dg~2g6&?-wqcpf{ z&3=o8vw7lMi22jCG9RQbv8H}`+}9^zSk`nlR8?Z&G2dlDy$4#+WOlg;VHqzuE=fM@ z?OI6HEJH4&tA?FVG}9>jAnq_^tlw8NbjNhfqk2rQr?h(F&WiKy03Sn=-;ZJRh~JrD zbt)zLbnabttEZ>zUiu`N*u4sfQaLE8-WDn@tHp50uD(^r-}UsUUu)`!Rl1PozAc!a z?uj|2QDQ%oV-jxUJmJycySBINSKdX{kDYRS=+`HgR2GO19fg&lZKyBFbbXhQV~v~L za^U944F1_GtuFXtvDdDNDvp<`fqy);>Vw=ncy!NB85Tw{&sT5&Ox%-p%8fTS;OzlRBwErvO+ROe?{%q-Zge=%Up|D4L#>4K@Ke=x%?*^_^P*KD zgXueMiS63!sEw@fNLB-i^F|@Oib+S4bcy{eu&e}Xvb^(mA!=U=Xr3||IpV~3K zQWzEsUeX_qBe6fky#M zzOJm5b+l;~>=sdp%i}}0h zO?B?i*W;Ndn02Y0GUUPxERG`3Bjtj!NroLoYtyVdLtl?SE*CYpf4|_${ku2s`*_)k zN=a}V8_2R5QANlxsq!1BkT6$4>9=-Ix4As@FSS;1q^#TXPrBsw>hJ}$jZ{kUHoP+H zvoYiR39gX}2OHIBYCa~6ERRPJ#V}RIIZakUmuIoLF*{sO8rAUEB9|+A#C|@kw5>u0 zBd=F!4I)Be8ycH*)X1-VPiZ+Ts8_GB;YW&ZFFUo|Sw|x~ZajLsp+_3gv((Q#N>?Jz zFBf`~p_#^${zhPIIJY~yo!7$-xi2LK%3&RkFg}Ax)3+dFCjGgKv^1;lUzQlPo^E{K zmCnrwJ)NuSaJEmueEPO@(_6h3f5mFffhkU9r8A8(JC5eOkux{gPmx_$Uv&|hyj)gN zd>JP8l2U&81@1Hc>#*su2xd{)T`Yw< zN$dSLUN}dfx)Fu`NcY}TuZ)SdviT{JHaiYgP4~@`x{&h*Hd>c3K_To9BnQi@;tuoL z%PYQo&{|IsM)_>BrF1oB~+`2_uZQ48z9!)mtUR zdfKE+b*w8cPu;F6RYJiYyV;PRBbThqHBEu_(U{(gGtjM}Zi$pL8Whx}<JwE3RM0F8x7%!!s)UJVq|TVd#hf1zVLya$;mYp(^oZQ2>=ZXU1c$}f zm|7kfk>=4KoQoQ!2&SOW5|JP1)%#55C$M(u4%SP~tHa&M+=;YsW=v(Old9L3(j)`u z2?#fK&1vtS?G6aOt@E`gZ9*qCmyvc>Ma@Q8^I4y~f3gs7*d=ATlP>1S zyF=k&6p2;7dn^8?+!wZO5r~B+;@KXFEn^&C=6ma1J7Au6y29iMIxd7#iW%=iUzq&C=$aPLa^Q zncia$@TIy6UT@69=nbty5epP>*fVW@5qbUcb2~Gg75dNd{COFLdiz3}kODn^U*=@E z0*$7u7Rl2u)=%fk4m8EK1ctR!6%Ve`e!O20L$0LkM#f+)n9h^dn{n`T*^~d+l*Qlx z$;JC0P9+en2Wlxjwq#z^a6pdnD6fJM!GV7_%8%c)kc5LZs_G^qvw)&J#6WSp< zmsd~1-(GrgjC56Pdf6#!dt^y8Rg}!#UXf)W%~PeU+kU`FeSZHk)%sFv++#Dujk-~m zFHvVJC}UBn2jN& zs!@nZ?e(iyZPNo`p1i#~wsv9l@#Z|ag3JR>0#u1iW9M1RK1iF6-RbJ4KYg?B`dET9 zyR~DjZ>%_vWYm*Z9_+^~hJ_|SNTzBKx=U0l9 z9x(J96b{`R)UVQ$I`wTJ@$_}`)_DyUNOso6=WOmQKI1e`oyYy1C&%AQU<0-`(ow)1 zT}gYdwWdm4wW6|K)LcfMe&psE0XGhMy&xS`@vLi|1#Za{D6l@#D!?nW87wcscUZgELT{Cz**^;Zb~7 z(~WFRO`~!WvyZAW-8v!6n&j*PLm9NlN}BuUN}@E^TX*4Or#dMMF?V9KBeLSiLO4?B zcE3WNIa-H{ThrlCoN=XjOGk1dT=xwwrmt<1a)mrRzg{35`@C!T?&_;Q4Ce=5=>z^*zE_c(0*vWo2_#TD<2)pLXV$FlwP}Ik74IdDQU@yhkCr5h zn5aa>B7PWy5NQ!vf7@p_qtC*{dZ8zLS;JetPkHi>IvPjtJ#ThGQD|Lq#@vE2xdl%`x4A8xOln}BiQ92Po zW;0%A?I5CQ_O`@Ad=`2BLPPbBuPUp@Hb%a_OOI}y{Rwa<#h z5^6M}s7VzE)2&I*33pA>e71d78QpF>sNK;?lj^Kl#wU7G++`N_oL4QPd-iPqBhhs| z(uVM}$ItF-onXuuXO}o$t)emBO3Hjfyil@*+GF;9j?`&67GBM;TGkLHi>@)rkS4Nj zAEk;u)`jc4C$qN6WV2dVd#q}2X6nKt&X*}I@jP%Srs%%DS92lpDY^K*Sx4`l;aql$ zt*-V{U&$DM>pdO?%jt$t=vg5|p+Rw?SPaLW zB6nvZ69$ne4Z(s$3=Rf&RX8L9PWMV*S0@R zuIk&ba#s6sxVZ51^4Kon46X^9`?DC9mEhWB3f+o4#2EXFqy0(UTc>GU| zGCJmI|Dn-dX#7|_6(fT)>&YQ0H&&JX3cTvAq(a@ydM4>5Njnuere{J8p;3?1az60* z$1E7Yyxt^ytULeokgDnRVKQw9vzHg1>X@@jM$n$HBlveIrKP5-GJq%iWH#odVwV6cF^kKX(@#%%uQVb>#T6L^mC@)%SMd4DF? zVky!~ge27>cpUP1Vi}Z32lbLV+CQy+T5Wdmva6Fg^lKb!zrg|HPU=5Qu}k;4GVH+x z%;&pN1LOce0w@9i1Mo-Y|7|z}fbch@BPp2{&R-5{GLoeu8@limQmFF zaJRR|^;kW_nw~0V^ zfTnR!Ni*;-%oSHG1yItARs~uxra|O?YJxBzLjpeE-=~TO3Dn`JL5Gz;F~O1u3|FE- zvK2Vve`ylc`a}G`gpHg58Cqc9fMoy1L}7x7T>%~b&irrNMo?np3`q;d3d;zTK>nrK zOjPS{@&74-fA7j)8uT9~*g23uGnxwIVj9HorzUX#s0pcp2?GH6i}~+kv9fWChtPa_ z@T3m+$0pbjdQw7jcnHn;Pi85hk_u2-1^}c)LNvjdam8K-XJ+KgKQ%!?2n_!#{$H|| zLO=%;hRo6EDmnOBKCL9Cg~ETU##@u^W_5joZ%Et%X_n##%JDOcsO=0VL|Lkk!VdRJ z^|~2pB@PUspT?NOeO?=0Vb+fAGc!j%Ufn-cB`s2A~W{Zj{`wqWq_-w0wr@6VrM zbzni@8c>WS!7c&|ZR$cQ;`niRw{4kG#e z70e!uX8VmP23SuJ*)#(&R=;SxGAvq|&>geL&!5Z7@0Z(No*W561n#u$Uc`f9pD70# z=sKOSK|bF~#khTTn)B28h^a1{;>EaRnHj~>i=Fnr3+Fa4 z`^+O5_itS#7kPd20rq66_wH`%?HNzWk@XFK0n;Z@Cx{kx==2L22zWH$Yg?7 zvDj|u{{+NR3JvUH({;b*$b(U5U z7(lF!1bz2%06+|-v(D?2KgwNw7( zJB#Tz+ZRi&U$i?f34m7>uTzO#+E5cbaiQ&L}UxyOQq~afbNB4EI{E04ZWg53w0A{O%qo=lF8d zf~ktGvIgf-a~zQoWf>loF7pOodrd0a2|BzwwPDV}ShauTK8*fmF6NRbO>Iw9zZU}u zw8Ya}?seBnEGQDmH#XpUUkj}N49tP<2jYwTFp!P+&Fd(%Z#yo80|5@zN(D{_pNow*&4%ql zW~&yp@scb-+Qj-EmErY+Tu=dUmf@*BoXY2&oKT8U?8?s1d}4a`Aq>7SV800m$FE~? zjmz(LY+Xx9sDX$;vU`xgw*jLw7dWOnWWCO8o|;}f>cu0Q&`0I{YudMn;P;L3R-uz# zfns_mZED_IakFBPP2r_S8XM$X)@O-xVKi4`7373Jkd5{2$M#%cRhWer3M(vr{S6>h zj{givZJ3(`yFL@``(afn&~iNx@B1|-qfYiZu?-_&Z8+R~v`d6R-}EX9IVXWO-!hL5 z*k6T#^2zAXdardU3Ao~I)4DGdAv2bx{4nOK`20rJo>rmk3S2ZDu}))8Z1m}CKigf0 z3L`3Y`{huj`xj9@`$xTZzZc3je?n^yG<8sw$`Y%}9mUsjUR%T!?k^(q)6FH6Af^b6 zlPg~IEwg0y;`t9y;#D+uz!oE4VP&Je!<#q*F?m5L5?J3i@!0J6q#eu z!RRU`-)HeqGi_UJZ(n~|PSNsv+Wgl{P-TvaUQ9j?ZCtvb^37U$sFpBrkT{7Jpd?HpIvj2!}RIq zH{9~+gErN2+}J`>Jvng2hwM`=PLNkc7pkjblKW|+Fk9rc)G1R>Ww>RC=r-|!m-u7( zc(a$9NG}w#PjWNMS~)o=i~WA&4L(YIW25@AL9+H9!?3Y}sv#MOdY{bb9j>p`{?O(P zIvb`n?_(gP2w3P#&91JX*md+bBEr%xUHMVqfB;(f?OPtMnAZ#rm5q5mh;a2f_si2_ z3oXWB?{NF(JtkAn6F(O{z@b76OIqMC$&oJ_&S|YbFJ*)3qVX_uNf5b8(!vGX19hsG z(OP>RmZp29KH9Ge2kKjKigUmOe^K_!UXP`von)PR8Qz$%=EmOB9xS(ZxE_tnyzo}7 z=6~$~9k0M~v}`w={AeqF?_)9q{m8K#6M{a&(;u;O41j)I$^T?lx5(zlebpY@NT&#N zR+1bB)-1-xj}R8uwqwf=iP1GbxBjneCC%UrSdSxK1vM^i9;bUkS#iRZw2H>rS<2<$ zNT3|sDH>{tXb=zq7XZi*K?#Zsa1h1{h5!Tq_YbKFm_*=A5-<~j63he;4`77!|LBlo zR^~tR3yxcU=gDFbshyF6>o0bdp$qmHS7D}m3;^QZq9kBBU|9$N-~oU?G5;jyFR7>z hN`IR97YZXIo@y!QgFWddJ3|0`sjFx!m))><{BI=FK%f8s literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/web/icons/Icon-maskable-192.png b/dev/a11y_assessments/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 zcmZ`-2T+sGz6~)*FVZ`aW+(v>MIm&M-g^@e2u-B-DoB?qO+b1Tq<5uCCv>ESfRum& zp%X;f!~1{tzL__3=gjVJ=j=J>+nMj%ncXj1Q(b|Ckbw{Y0FWpt%4y%$uD=Z*c-x~o zE;IoE;xa#7Ll5nj-e4CuXB&G*IM~D21rCP$*xLXAK8rIMCSHuSu%bL&S3)8YI~vyp@KBu9Ph7R_pvKQ@xv>NQ`dZp(u{Z8K3yOB zn7-AR+d2JkW)KiGx0hosml;+eCXp6+w%@STjFY*CJ?udJ64&{BCbuebcuH;}(($@@ znNlgBA@ZXB)mcl9nbX#F!f_5Z=W>0kh|UVWnf!At4V*LQP%*gPdCXd6P@J4Td;!Ur z<2ZLmwr(NG`u#gDEMP19UcSzRTL@HsK+PnIXbVBT@oHm53DZr?~V(0{rsalAfwgo zEh=GviaqkF;}F_5-yA!1u3!gxaR&Mj)hLuj5Q-N-@Lra{%<4ONja8pycD90&>yMB` zchhd>0CsH`^|&TstH-8+R`CfoWqmTTF_0?zDOY`E`b)cVi!$4xA@oO;SyOjJyP^_j zx^@Gdf+w|FW@DMdOi8=4+LJl$#@R&&=UM`)G!y%6ZzQLoSL%*KE8IO0~&5XYR9 z&N)?goEiWA(YoRfT{06&D6Yuu@Qt&XVbuW@COb;>SP9~aRc+z`m`80pB2o%`#{xD@ zI3RAlukL5L>px6b?QW1Ac_0>ew%NM!XB2(H+1Y3AJC?C?O`GGs`331Nd4ZvG~bMo{lh~GeL zSL|tT*fF-HXxXYtfu5z+T5Mx9OdP7J4g%@oeC2FaWO1D{=NvL|DNZ}GO?O3`+H*SI z=grGv=7dL{+oY0eJFGO!Qe(e2F?CHW(i!!XkGo2tUvsQ)I9ev`H&=;`N%Z{L zO?vV%rDv$y(@1Yj@xfr7Kzr<~0{^T8wM80xf7IGQF_S-2c0)0D6b0~yD7BsCy+(zL z#N~%&e4iAwi4F$&dI7x6cE|B{f@lY5epaDh=2-(4N05VO~A zQT3hanGy_&p+7Fb^I#ewGsjyCEUmSCaP6JDB*=_()FgQ(-pZ28-{qx~2foO4%pM9e z*_63RT8XjgiaWY|*xydf;8MKLd{HnfZ2kM%iq}fstImB-K6A79B~YoPVa@tYN@T_$ zea+9)<%?=Fl!kd(Y!G(-o}ko28hg2!MR-o5BEa_72uj7Mrc&{lRh3u2%Y=Xk9^-qa zBPWaD=2qcuJ&@Tf6ue&)4_V*45=zWk@Z}Q?f5)*z)-+E|-yC4fs5CE6L_PH3=zI8p z*Z3!it{1e5_^(sF*v=0{`U9C741&lub89gdhKp|Y8CeC{_{wYK-LSbp{h)b~9^j!s z7e?Y{Z3pZv0J)(VL=g>l;<}xk=T*O5YR|hg0eg4u98f2IrA-MY+StQIuK-(*J6TRR z|IM(%uI~?`wsfyO6Tgmsy1b3a)j6M&-jgUjVg+mP*oTKdHg?5E`!r`7AE_#?Fc)&a z08KCq>Gc=ne{PCbRvs6gVW|tKdcE1#7C4e`M|j$C5EYZ~Y=jUtc zj`+?p4ba3uy7><7wIokM79jPza``{Lx0)zGWg;FW1^NKY+GpEi=rHJ+fVRGfXO zPHV52k?jxei_!YYAw1HIz}y8ZMwdZqU%ESwMn7~t zdI5%B;U7RF=jzRz^NuY9nM)&<%M>x>0(e$GpU9th%rHiZsIT>_qp%V~ILlyt^V`=d z!1+DX@ah?RnB$X!0xpTA0}lN@9V-ePx>wQ?-xrJr^qDlw?#O(RsXeAvM%}rg0NT#t z!CsT;-vB=B87ShG`GwO;OEbeL;a}LIu=&@9cb~Rsx(ZPNQ!NT7H{@j0e(DiLea>QD zPmpe90gEKHEZ8oQ@6%E7k-Ptn#z)b9NbD@_GTxEhbS+}Bb74WUaRy{w;E|MgDAvHw zL)ycgM7mB?XVh^OzbC?LKFMotw3r@i&VdUV%^Efdib)3@soX%vWCbnOyt@Y4swW925@bt45y0HY3YI~BnnzZYrinFy;L?2D3BAL`UQ zEj))+f>H7~g8*VuWQ83EtGcx`hun$QvuurSMg3l4IP8Fe`#C|N6mbYJ=n;+}EQm;< z!!N=5j1aAr_uEnnzrEV%_E|JpTb#1p1*}5!Ce!R@d$EtMR~%9# zd;h8=QGT)KMW2IKu_fA_>p_und#-;Q)p%%l0XZOXQicfX8M~7?8}@U^ihu;mizj)t zgV7wk%n-UOb z#!P5q?Ex+*Kx@*p`o$q8FWL*E^$&1*!gpv?Za$YO~{BHeGY*5%4HXUKa_A~~^d z=E*gf6&+LFF^`j4$T~dR)%{I)T?>@Ma?D!gi9I^HqvjPc3-v~=qpX1Mne@*rzT&Xw zQ9DXsSV@PqpEJO-g4A&L{F&;K6W60D!_vs?Vx!?w27XbEuJJP&);)^+VF1nHqHBWu z^>kI$M9yfOY8~|hZ9WB!q-9u&mKhEcRjlf2nm_@s;0D#c|@ED7NZE% zzR;>P5B{o4fzlfsn3CkBK&`OSb-YNrqx@N#4CK!>bQ(V(D#9|l!e9(%sz~PYk@8zt zPN9oK78&-IL_F zhsk1$6p;GqFbtB^ZHHP+cjMvA0(LqlskbdYE_rda>gvQLTiqOQ1~*7lg%z*&p`Ry& zRcG^DbbPj_jOKHTr8uk^15Boj6>hA2S-QY(W-6!FIq8h$<>MI>PYYRenQDBamO#Fv zAH5&ImqKBDn0v5kb|8i0wFhUBJTpT!rB-`zK)^SNnRmLraZcPYK7b{I@+}wXVdW-{Ps17qdRA3JatEd?rPV z4@}(DAMf5EqXCr4-B+~H1P#;t@O}B)tIJ(W6$LrK&0plTmnPpb1TKn3?f?Kk``?D+ zQ!MFqOX7JbsXfQrz`-M@hq7xlfNz;_B{^wbpG8des56x(Q)H)5eLeDwCrVR}hzr~= zM{yXR6IM?kXxauLza#@#u?Y|o;904HCqF<8yT~~c-xyRc0-vxofnxG^(x%>bj5r}N zyFT+xnn-?B`ohA>{+ZZQem=*Xpqz{=j8i2TAC#x-m;;mo{{sLB_z(UoAqD=A#*juZ zCv=J~i*O8;F}A^Wf#+zx;~3B{57xtoxC&j^ie^?**T`WT2OPRtC`xj~+3Kprn=rVM zVJ|h5ux%S{dO}!mq93}P+h36mZ5aZg1-?vhL$ke1d52qIiXSE(llCr5i=QUS?LIjc zV$4q=-)aaR4wsrQv}^shL5u%6;`uiSEs<1nG^?$kl$^6DL z43CjY`M*p}ew}}3rXc7Xck@k41jx}c;NgEIhKZ*jsBRZUP-x2cm;F1<5$jefl|ppO zmZd%%?gMJ^g9=RZ^#8Mf5aWNVhjAS^|DQO+q$)oeob_&ZLFL(zur$)); zU19yRm)z<4&4-M}7!9+^Wl}Uk?`S$#V2%pQ*SIH5KI-mn%i;Z7-)m$mN9CnI$G7?# zo`zVrUwoSL&_dJ92YhX5TKqaRkfPgC4=Q&=K+;_aDs&OU0&{WFH}kKX6uNQC6%oUH z2DZa1s3%Vtk|bglbxep-w)PbFG!J17`<$g8lVhqD2w;Z0zGsh-r zxZ13G$G<48leNqR!DCVt9)@}(zMI5w6Wo=N zpP1*3DI;~h2WDWgcKn*f!+ORD)f$DZFwgKBafEZmeXQMAsq9sxP9A)7zOYnkHT9JU zRA`umgmP9d6=PHmFIgx=0$(sjb>+0CHG)K@cPG{IxaJ&Ueo8)0RWgV9+gO7+Bl1(F z7!BslJ2MP*PWJ;x)QXbR$6jEr5q3 z(3}F@YO_P1NyTdEXRLU6fp?9V2-S=E+YaeLL{Y)W%6`k7$(EW8EZSA*(+;e5@jgD^I zaJQ2|oCM1n!A&-8`;#RDcZyk*+RPkn_r8?Ak@agHiSp*qFNX)&i21HE?yuZ;-C<3C zwJGd1lx5UzViP7sZJ&|LqH*mryb}y|%AOw+v)yc`qM)03qyyrqhX?ub`Cjwx2PrR! z)_z>5*!*$x1=Qa-0uE7jy0z`>|Ni#X+uV|%_81F7)b+nf%iz=`fF4g5UfHS_?PHbr zB;0$bK@=di?f`dS(j{l3-tSCfp~zUuva+=EWxJcRfp(<$@vd(GigM&~vaYZ0c#BTs z3ijkxMl=vw5AS&DcXQ%eeKt!uKvh2l3W?&3=dBHU=Gz?O!40S&&~ei2vg**c$o;i89~6DVns zG>9a*`k5)NI9|?W!@9>rzJ;9EJ=YlJTx1r1BA?H`LWijk(rTax9(OAu;q4_wTj-yj z1%W4GW&K4T=uEGb+E!>W0SD_C0RR91 literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/web/icons/Icon-maskable-512.png b/dev/a11y_assessments/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 zcmd5=2T+s!lYZ%-(h(2@5fr2dC?F^$C=i-}R6$UX8af(!je;W5yC_|HmujSgN*6?W z3knF*TL1$|?oD*=zPbBVex*RUIKsL<(&Rj9%^UD2IK3W?2j>D?eWQgvS-HLymHo9%~|N2Q{~j za?*X-{b9JRowv_*Mh|;*-kPFn>PI;r<#kFaxFqbn?aq|PduQg=2Q;~Qc}#z)_T%x9 zE|0!a70`58wjREmAH38H1)#gof)U3g9FZ^ zF7&-0^Hy{4XHWLoC*hOG(dg~2g6&?-wqcpf{ z&3=o8vw7lMi22jCG9RQbv8H}`+}9^zSk`nlR8?Z&G2dlDy$4#+WOlg;VHqzuE=fM@ z?OI6HEJH4&tA?FVG}9>jAnq_^tlw8NbjNhfqk2rQr?h(F&WiKy03Sn=-;ZJRh~JrD zbt)zLbnabttEZ>zUiu`N*u4sfQaLE8-WDn@tHp50uD(^r-}UsUUu)`!Rl1PozAc!a z?uj|2QDQ%oV-jxUJmJycySBINSKdX{kDYRS=+`HgR2GO19fg&lZKyBFbbXhQV~v~L za^U944F1_GtuFXtvDdDNDvp<`fqy);>Vw=ncy!NB85Tw{&sT5&Ox%-p%8fTS;OzlRBwErvO+ROe?{%q-Zge=%Up|D4L#>4K@Ke=x%?*^_^P*KD zgXueMiS63!sEw@fNLB-i^F|@Oib+S4bcy{eu&e}Xvb^(mA!=U=Xr3||IpV~3K zQWzEsUeX_qBe6fky#M zzOJm5b+l;~>=sdp%i}}0h zO?B?i*W;Ndn02Y0GUUPxERG`3Bjtj!NroLoYtyVdLtl?SE*CYpf4|_${ku2s`*_)k zN=a}V8_2R5QANlxsq!1BkT6$4>9=-Ix4As@FSS;1q^#TXPrBsw>hJ}$jZ{kUHoP+H zvoYiR39gX}2OHIBYCa~6ERRPJ#V}RIIZakUmuIoLF*{sO8rAUEB9|+A#C|@kw5>u0 zBd=F!4I)Be8ycH*)X1-VPiZ+Ts8_GB;YW&ZFFUo|Sw|x~ZajLsp+_3gv((Q#N>?Jz zFBf`~p_#^${zhPIIJY~yo!7$-xi2LK%3&RkFg}Ax)3+dFCjGgKv^1;lUzQlPo^E{K zmCnrwJ)NuSaJEmueEPO@(_6h3f5mFffhkU9r8A8(JC5eOkux{gPmx_$Uv&|hyj)gN zd>JP8l2U&81@1Hc>#*su2xd{)T`Yw< zN$dSLUN}dfx)Fu`NcY}TuZ)SdviT{JHaiYgP4~@`x{&h*Hd>c3K_To9BnQi@;tuoL z%PYQo&{|IsM)_>BrF1oB~+`2_uZQ48z9!)mtUR zdfKE+b*w8cPu;F6RYJiYyV;PRBbThqHBEu_(U{(gGtjM}Zi$pL8Whx}<JwE3RM0F8x7%!!s)UJVq|TVd#hf1zVLya$;mYp(^oZQ2>=ZXU1c$}f zm|7kfk>=4KoQoQ!2&SOW5|JP1)%#55C$M(u4%SP~tHa&M+=;YsW=v(Old9L3(j)`u z2?#fK&1vtS?G6aOt@E`gZ9*qCmyvc>Ma@Q8^I4y~f3gs7*d=ATlP>1S zyF=k&6p2;7dn^8?+!wZO5r~B+;@KXFEn^&C=6ma1J7Au6y29iMIxd7#iW%=iUzq&C=$aPLa^Q zncia$@TIy6UT@69=nbty5epP>*fVW@5qbUcb2~Gg75dNd{COFLdiz3}kODn^U*=@E z0*$7u7Rl2u)=%fk4m8EK1ctR!6%Ve`e!O20L$0LkM#f+)n9h^dn{n`T*^~d+l*Qlx z$;JC0P9+en2Wlxjwq#z^a6pdnD6fJM!GV7_%8%c)kc5LZs_G^qvw)&J#6WSp< zmsd~1-(GrgjC56Pdf6#!dt^y8Rg}!#UXf)W%~PeU+kU`FeSZHk)%sFv++#Dujk-~m zFHvVJC}UBn2jN& zs!@nZ?e(iyZPNo`p1i#~wsv9l@#Z|ag3JR>0#u1iW9M1RK1iF6-RbJ4KYg?B`dET9 zyR~DjZ>%_vWYm*Z9_+^~hJ_|SNTzBKx=U0l9 z9x(J96b{`R)UVQ$I`wTJ@$_}`)_DyUNOso6=WOmQKI1e`oyYy1C&%AQU<0-`(ow)1 zT}gYdwWdm4wW6|K)LcfMe&psE0XGhMy&xS`@vLi|1#Za{D6l@#D!?nW87wcscUZgELT{Cz**^;Zb~7 z(~WFRO`~!WvyZAW-8v!6n&j*PLm9NlN}BuUN}@E^TX*4Or#dMMF?V9KBeLSiLO4?B zcE3WNIa-H{ThrlCoN=XjOGk1dT=xwwrmt<1a)mrRzg{35`@C!T?&_;Q4Ce=5=>z^*zE_c(0*vWo2_#TD<2)pLXV$FlwP}Ik74IdDQU@yhkCr5h zn5aa>B7PWy5NQ!vf7@p_qtC*{dZ8zLS;JetPkHi>IvPjtJ#ThGQD|Lq#@vE2xdl%`x4A8xOln}BiQ92Po zW;0%A?I5CQ_O`@Ad=`2BLPPbBuPUp@Hb%a_OOI}y{Rwa<#h z5^6M}s7VzE)2&I*33pA>e71d78QpF>sNK;?lj^Kl#wU7G++`N_oL4QPd-iPqBhhs| z(uVM}$ItF-onXuuXO}o$t)emBO3Hjfyil@*+GF;9j?`&67GBM;TGkLHi>@)rkS4Nj zAEk;u)`jc4C$qN6WV2dVd#q}2X6nKt&X*}I@jP%Srs%%DS92lpDY^K*Sx4`l;aql$ zt*-V{U&$DM>pdO?%jt$t=vg5|p+Rw?SPaLW zB6nvZ69$ne4Z(s$3=Rf&RX8L9PWMV*S0@R zuIk&ba#s6sxVZ51^4Kon46X^9`?DC9mEhWB3f+o4#2EXFqy0(UTc>GU| zGCJmI|Dn-dX#7|_6(fT)>&YQ0H&&JX3cTvAq(a@ydM4>5Njnuere{J8p;3?1az60* z$1E7Yyxt^ytULeokgDnRVKQw9vzHg1>X@@jM$n$HBlveIrKP5-GJq%iWH#odVwV6cF^kKX(@#%%uQVb>#T6L^mC@)%SMd4DF? zVky!~ge27>cpUP1Vi}Z32lbLV+CQy+T5Wdmva6Fg^lKb!zrg|HPU=5Qu}k;4GVH+x z%;&pN1LOce0w@9i1Mo-Y|7|z}fbch@BPp2{&R-5{GLoeu8@limQmFF zaJRR|^;kW_nw~0V^ zfTnR!Ni*;-%oSHG1yItARs~uxra|O?YJxBzLjpeE-=~TO3Dn`JL5Gz;F~O1u3|FE- zvK2Vve`ylc`a}G`gpHg58Cqc9fMoy1L}7x7T>%~b&irrNMo?np3`q;d3d;zTK>nrK zOjPS{@&74-fA7j)8uT9~*g23uGnxwIVj9HorzUX#s0pcp2?GH6i}~+kv9fWChtPa_ z@T3m+$0pbjdQw7jcnHn;Pi85hk_u2-1^}c)LNvjdam8K-XJ+KgKQ%!?2n_!#{$H|| zLO=%;hRo6EDmnOBKCL9Cg~ETU##@u^W_5joZ%Et%X_n##%JDOcsO=0VL|Lkk!VdRJ z^|~2pB@PUspT?NOeO?=0Vb+fAGc!j%Ufn-cB`s2A~W{Zj{`wqWq_-w0wr@6VrM zbzni@8c>WS!7c&|ZR$cQ;`niRw{4kG#e z70e!uX8VmP23SuJ*)#(&R=;SxGAvq|&>geL&!5Z7@0Z(No*W561n#u$Uc`f9pD70# z=sKOSK|bF~#khTTn)B28h^a1{;>EaRnHj~>i=Fnr3+Fa4 z`^+O5_itS#7kPd20rq66_wH`%?HNzWk@XFK0n;Z@Cx{kx==2L22zWH$Yg?7 zvDj|u{{+NR3JvUH({;b*$b(U5U z7(lF!1bz2%06+|-v(D?2KgwNw7( zJB#Tz+ZRi&U$i?f34m7>uTzO#+E5cbaiQ&L}UxyOQq~afbNB4EI{E04ZWg53w0A{O%qo=lF8d zf~ktGvIgf-a~zQoWf>loF7pOodrd0a2|BzwwPDV}ShauTK8*fmF6NRbO>Iw9zZU}u zw8Ya}?seBnEGQDmH#XpUUkj}N49tP<2jYwTFp!P+&Fd(%Z#yo80|5@zN(D{_pNow*&4%ql zW~&yp@scb-+Qj-EmErY+Tu=dUmf@*BoXY2&oKT8U?8?s1d}4a`Aq>7SV800m$FE~? zjmz(LY+Xx9sDX$;vU`xgw*jLw7dWOnWWCO8o|;}f>cu0Q&`0I{YudMn;P;L3R-uz# zfns_mZED_IakFBPP2r_S8XM$X)@O-xVKi4`7373Jkd5{2$M#%cRhWer3M(vr{S6>h zj{givZJ3(`yFL@``(afn&~iNx@B1|-qfYiZu?-_&Z8+R~v`d6R-}EX9IVXWO-!hL5 z*k6T#^2zAXdardU3Ao~I)4DGdAv2bx{4nOK`20rJo>rmk3S2ZDu}))8Z1m}CKigf0 z3L`3Y`{huj`xj9@`$xTZzZc3je?n^yG<8sw$`Y%}9mUsjUR%T!?k^(q)6FH6Af^b6 zlPg~IEwg0y;`t9y;#D+uz!oE4VP&Je!<#q*F?m5L5?J3i@!0J6q#eu z!RRU`-)HeqGi_UJZ(n~|PSNsv+Wgl{P-TvaUQ9j?ZCtvb^37U$sFpBrkT{7Jpd?HpIvj2!}RIq zH{9~+gErN2+}J`>Jvng2hwM`=PLNkc7pkjblKW|+Fk9rc)G1R>Ww>RC=r-|!m-u7( zc(a$9NG}w#PjWNMS~)o=i~WA&4L(YIW25@AL9+H9!?3Y}sv#MOdY{bb9j>p`{?O(P zIvb`n?_(gP2w3P#&91JX*md+bBEr%xUHMVqfB;(f?OPtMnAZ#rm5q5mh;a2f_si2_ z3oXWB?{NF(JtkAn6F(O{z@b76OIqMC$&oJ_&S|YbFJ*)3qVX_uNf5b8(!vGX19hsG z(OP>RmZp29KH9Ge2kKjKigUmOe^K_!UXP`von)PR8Qz$%=EmOB9xS(ZxE_tnyzo}7 z=6~$~9k0M~v}`w={AeqF?_)9q{m8K#6M{a&(;u;O41j)I$^T?lx5(zlebpY@NT&#N zR+1bB)-1-xj}R8uwqwf=iP1GbxBjneCC%UrSdSxK1vM^i9;bUkS#iRZw2H>rS<2<$ zNT3|sDH>{tXb=zq7XZi*K?#Zsa1h1{h5!Tq_YbKFm_*=A5-<~j63he;4`77!|LBlo zR^~tR3yxcU=gDFbshyF6>o0bdp$qmHS7D}m3;^QZq9kBBU|9$N-~oU?G5;jyFR7>z hN`IR97YZXIo@y!QgFWddJ3|0`sjFx!m))><{BI=FK%f8s literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/web/index.html b/dev/a11y_assessments/web/index.html new file mode 100644 index 0000000000000..a074dee382c97 --- /dev/null +++ b/dev/a11y_assessments/web/index.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + a11y_assessments + + + + + + + + + + diff --git a/dev/a11y_assessments/web/manifest.json b/dev/a11y_assessments/web/manifest.json new file mode 100644 index 0000000000000..9a2a11fa46b37 --- /dev/null +++ b/dev/a11y_assessments/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "a11y_assessments", + "short_name": "a11y_assessments", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": ""A new Flutter project."", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/dev/a11y_assessments/windows/.gitignore b/dev/a11y_assessments/windows/.gitignore new file mode 100644 index 0000000000000..d492d0d98c8fd --- /dev/null +++ b/dev/a11y_assessments/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/dev/a11y_assessments/windows/CMakeLists.txt b/dev/a11y_assessments/windows/CMakeLists.txt new file mode 100644 index 0000000000000..b2bc836676f14 --- /dev/null +++ b/dev/a11y_assessments/windows/CMakeLists.txt @@ -0,0 +1,102 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(a11y_assessments LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "a11y_assessments") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/dev/a11y_assessments/windows/flutter/CMakeLists.txt b/dev/a11y_assessments/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000000000..930d2071a324e --- /dev/null +++ b/dev/a11y_assessments/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/dev/a11y_assessments/windows/runner/CMakeLists.txt b/dev/a11y_assessments/windows/runner/CMakeLists.txt new file mode 100644 index 0000000000000..394917c053a04 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/dev/a11y_assessments/windows/runner/Runner.rc b/dev/a11y_assessments/windows/runner/Runner.rc new file mode 100644 index 0000000000000..9b5eba68d5484 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "a11y_assessments" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "a11y_assessments" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "a11y_assessments.exe" "\0" + VALUE "ProductName", "a11y_assessments" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/dev/a11y_assessments/windows/runner/flutter_window.cpp b/dev/a11y_assessments/windows/runner/flutter_window.cpp new file mode 100644 index 0000000000000..252aa267868b6 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/flutter_window.cpp @@ -0,0 +1,75 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/dev/a11y_assessments/windows/runner/flutter_window.h b/dev/a11y_assessments/windows/runner/flutter_window.h new file mode 100644 index 0000000000000..bbc5836c018a2 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/flutter_window.h @@ -0,0 +1,37 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/dev/a11y_assessments/windows/runner/main.cpp b/dev/a11y_assessments/windows/runner/main.cpp new file mode 100644 index 0000000000000..125d42ba57ff2 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/main.cpp @@ -0,0 +1,47 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"a11y_assessments", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/dev/a11y_assessments/windows/runner/resource.h b/dev/a11y_assessments/windows/runner/resource.h new file mode 100644 index 0000000000000..c245ff19cb580 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/resource.h @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/dev/a11y_assessments/windows/runner/resources/app_icon.ico b/dev/a11y_assessments/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2e4cc829b07d6ce44fb5c1a9ade8070767724e8c GIT binary patch literal 787 zcmV+u1MK{XP)n7bpJ_;IC> zCYE;Tt!%ADOV>j1uTiiSxeX|y1X2W|o#F?!5e-@dLSPfH6C}yWC0XBixx#SC&d$C! z@6EXnmOYkbc7DH|@7n=rqKW@HjJ6Ej{Mdhprv-wf7MHF~XJt3Fl)?A#loBMBxxlL` z0mSfkqpAW@@G1mI!ix)#h8Go}0bWdi7I+Z>n&5*A&;}n=fJXRW0<^*h5uh2KU4V9Y zRsk`Y3x9QWZ((P@5Qpa)3YWr<-h8)XU@kFY@EnsNXZX=I zPYERO)YIY0@SYOL;3*eGz!$!v1X6es0cGI=?pK?LC%k@P5Ao$-P>Q;{WZ>NY8b14_XO(q&L-rqU%|kf z$Fb^ER=l{!wtB=i9sYJ>#&y{IFMPfM`RWP`U>0-tH+!kM{kRvM03Qkct?!VpEF=8P z2!0f764)0+TqW#pe1?4aIl?DcF>SVrlee%)2(ltnCSh;=6XY+SzyVAnycxn5;~daS z2(=`3s)XGyA0U7F2o8((@IrAk%$6+$W^5ZxDj}GFaS|;2_A`XHy>ScQeu6z`atVKT zPJ<_xAo8iK?IICA-CpX!QTGbKh06f##3!lRU8LB@(w$omdV^v%J<-|+mmvDN{Bbc( z36k=bAiiNjT7rr#Gm;Y2Y?_jiplaWsgamaPCs6{~#z~ZrK@&|haaQ~hU;qgkt*1!I RvP=K~002ovPDHLkV1o3TVfFw3 literal 0 HcmV?d00001 diff --git a/dev/a11y_assessments/windows/runner/runner.exe.manifest b/dev/a11y_assessments/windows/runner/runner.exe.manifest new file mode 100644 index 0000000000000..a42ea7687cb67 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/dev/a11y_assessments/windows/runner/utils.cpp b/dev/a11y_assessments/windows/runner/utils.cpp new file mode 100644 index 0000000000000..f677d8d5f7141 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/utils.cpp @@ -0,0 +1,69 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/dev/a11y_assessments/windows/runner/utils.h b/dev/a11y_assessments/windows/runner/utils.h new file mode 100644 index 0000000000000..54414c989ba71 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/utils.h @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/dev/a11y_assessments/windows/runner/win32_window.cpp b/dev/a11y_assessments/windows/runner/win32_window.cpp new file mode 100644 index 0000000000000..14a183d7eaa27 --- /dev/null +++ b/dev/a11y_assessments/windows/runner/win32_window.cpp @@ -0,0 +1,292 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/dev/a11y_assessments/windows/runner/win32_window.h b/dev/a11y_assessments/windows/runner/win32_window.h new file mode 100644 index 0000000000000..bb93e8879162e --- /dev/null +++ b/dev/a11y_assessments/windows/runner/win32_window.h @@ -0,0 +1,106 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 7d7784ff58daf..be3405c79e9f9 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -979,6 +979,10 @@ Future _runFrameworkTests() async { printProgress('${green}Running package tests$reset for directories other than packages/flutter'); await _runTestHarnessTests(); await runExampleTests(); + await _runFlutterTest( + path.join(flutterRoot, 'dev', 'a11y_assessments'), + tests: [ 'test' ], + ); await _runDartTest(path.join(flutterRoot, 'dev', 'bots')); await _runDartTest(path.join(flutterRoot, 'dev', 'devicelab'), ensurePrecompiledTool: false); // See https://github.com/flutter/flutter/issues/86209 await _runDartTest(path.join(flutterRoot, 'dev', 'conductor', 'core'), forceSingleCore: true); From 4df8d23e976ada28bfbbc9f92e9a0dee0c44d648 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 12:16:41 -0400 Subject: [PATCH 0516/1547] Roll Flutter Engine from 46f3e099ad04 to 4cc0b3dab001 (3 revisions) (#131854) https://github.com/flutter/engine/compare/46f3e099ad04...4cc0b3dab001 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from b81084128325 to 8a377a9545b8 (1 revision) (flutter/engine#44319) 2023-08-03 skia-flutter-autoroll@skia.org Roll Dart SDK from fac111d4acb3 to dcd09f5726b7 (1 revision) (flutter/engine#44317) 2023-08-03 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from WwFjJuQF_rpToCYPJ... to Qo3dJIXjK-Ia8j42J... (flutter/engine#44316) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from WwFjJuQF_rpT to Qo3dJIXjK-Ia If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index adc806f526c3a..7285f8154602a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -46f3e099ad045ec9aaa976ba9b4852209d348958 +4cc0b3dab001f5a12873b46f9d52b7d00f1cb827 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index e16f31716a14d..7178e8bf9362c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -WwFjJuQF_rpToCYPJ3yjlNSYb07ecmP2dIyh7of3O9MC +Qo3dJIXjK-Ia8j42JByo585ZGQ85ddt1EdqV71Vd6bMC From 13ff16cba9c71794dd6c226ef6228b80a8e6c399 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 3 Aug 2023 09:28:58 -0700 Subject: [PATCH 0517/1547] remove Mac_ios ios_app_with_extensions_test (#131806) Removing the extension test that unnecessarily running with devices. The new hostonly tests were added in https://github.com/flutter/flutter/pull/131441 --- .ci.yaml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 0dc8e4069badc..a750ba905c04f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3712,24 +3712,6 @@ targets: ["devicelab", "ios", "mac"] task_name: integration_ui_ios_textfield - - name: Mac_ios ios_app_with_extensions_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "ios", "mac"] - task_name: ios_app_with_extensions_test - - - name: Mac_arm64_ios ios_app_with_extensions_test - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "ios", "mac", "arm64"] - task_name: ios_app_with_extensions_test - - name: Mac_x64 ios_app_with_extensions_test recipe: devicelab/devicelab_drone presubmit: false @@ -3742,7 +3724,6 @@ targets: tags: > ["devicelab", "hostonly", "mac"] task_name: ios_app_with_extensions_test - bringup: true - name: Mac_arm64 ios_app_with_extensions_test recipe: devicelab/devicelab_drone @@ -3756,7 +3737,6 @@ targets: tags: > ["devicelab", "hostonly", "mac", "arm64"] task_name: ios_app_with_extensions_test - bringup: true - name: Mac_ios ios_content_validation_test recipe: devicelab/devicelab_drone From 0d628b0fbe85a0162556eb96784a9deafee187bf Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Thu, 3 Aug 2023 10:33:07 -0700 Subject: [PATCH 0518/1547] manual pub package roll (#131804) manually ran `flutter update-packages --force-upgrade` --- packages/flutter_tools/pubspec.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index b34f743767ba3..105c80989ced2 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: archive: 3.3.2 args: 2.4.2 browser_launcher: 1.1.1 - dds: 2.9.2 + dds: 2.9.4 dwds: 19.0.2 completion: 1.0.1 coverage: 1.6.3 @@ -70,7 +70,7 @@ dependencies: dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dds_service_extensions: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - devtools_shared: 2.25.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + devtools_shared: 2.26.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -92,6 +92,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + yaml_edit: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: collection: 1.18.0 @@ -107,4 +108,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 3335 +# PUBSPEC CHECKSUM: 3540 From 4f9a7e294053ce50e646f379536c060b6e3a531e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 14:00:45 -0400 Subject: [PATCH 0519/1547] Roll Packages from 4e4961a24b3d to d00c1f9eb01c (10 revisions) (#131866) https://github.com/flutter/packages/compare/4e4961a24b3d...d00c1f9eb01c 2023-08-03 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.1 to 2.21.2 (flutter/packages#4637) 2023-08-03 engine-flutter-autoroll@skia.org Roll Flutter from b3f99ffe610a to c00d241938b1 (12 revisions) (flutter/packages#4640) 2023-08-03 jpnurmi@gmail.com [path_provider] Add getApplicationCachePath() - implementations (flutter/packages#4619) 2023-08-03 109253501+pdblasi-google@users.noreply.github.com [various] Removed references to deprecated `TestWindow` APIs (flutter/packages#4558) 2023-08-02 49699333+dependabot[bot]@users.noreply.github.com Bump actions/labeler from 4.1.0 to 4.3.0 (flutter/packages#4432) 2023-08-02 jhy03261997@gmail.com [go_router_builder] Add go_router StatefulShellRoute support to go_router_builder (flutter/packages#4238) 2023-08-02 reidbaker@google.com [Tooling] Add google owned cache for dependencies as an option in ci (flutter/packages#4567) 2023-08-02 engine-flutter-autoroll@skia.org Roll Flutter from 1d59196bafdb to b3f99ffe610a (32 revisions) (flutter/packages#4634) 2023-08-02 32538273+ValentinVignal@users.noreply.github.com [go_router_builder] Support `ShellRouteData` without `const` constructor (flutter/packages#4627) 2023-08-02 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.0 to 2.21.1 (flutter/packages#4573) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index f77200909786a..4ef31c05dceda 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -4e4961a24b3d169a62080cf285e66580eaca7e7a +d00c1f9eb01c764615c857a749f5d772905cbfad From 4247e1eff1d15ca03017c0c90e451c2c755eb4f7 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Thu, 3 Aug 2023 12:25:29 -0700 Subject: [PATCH 0520/1547] Added new gallery benchmark test that forces opengles. (#131796) fixes https://github.com/flutter/flutter/issues/131782 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Xilai Zhang --- .ci.yaml | 11 ++ TESTOWNERS | 1 + dev/bots/pubspec.yaml | 4 +- ...ry_opengles_impeller__transition_perf.dart | 24 +++ dev/devicelab/lib/tasks/new_gallery.dart | 1 + dev/devicelab/lib/tasks/perf_tests.dart | 138 ++++++++++++++---- dev/devicelab/pubspec.yaml | 4 +- 7 files changed, 151 insertions(+), 32 deletions(-) create mode 100644 dev/devicelab/bin/tasks/new_gallery_opengles_impeller__transition_perf.dart diff --git a/.ci.yaml b/.ci.yaml index a750ba905c04f..5405ed69e956d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2309,6 +2309,17 @@ targets: ["devicelab", "android", "linux", "samsung", "s10"] task_name: new_gallery_impeller__transition_perf + - name: Linux_samsung_s10 new_gallery_opengles_impeller__transition_perf + bringup: true + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: new_gallery_opengles_impeller__transition_perf + - name: Linux_android picture_cache_perf__e2e_summary recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index 8f0be05514b1a..79d161f98cfe4 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -137,6 +137,7 @@ /dev/devicelab/bin/tasks/microbenchmarks.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/new_gallery__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/new_gallery_impeller__transition_perf.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/new_gallery_opengles_impeller__transition_perf.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/picture_cache_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_channel_sample_test.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/platform_interaction_test.dart @stuartmorgan @flutter/plugin diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 892a662a87645..d3c6bfcbf1c1d 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pubspec_parse: 1.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,9 +69,10 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xml: 6.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: e586 +# PUBSPEC CHECKSUM: 7431 diff --git a/dev/devicelab/bin/tasks/new_gallery_opengles_impeller__transition_perf.dart b/dev/devicelab/bin/tasks/new_gallery_opengles_impeller__transition_perf.dart new file mode 100644 index 0000000000000..2a33ce72a8e79 --- /dev/null +++ b/dev/devicelab/bin/tasks/new_gallery_opengles_impeller__transition_perf.dart @@ -0,0 +1,24 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/framework/utils.dart'; +import 'package:flutter_devicelab/tasks/new_gallery.dart'; +import 'package:path/path.dart' as path; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + + final Directory galleryParentDir = Directory.systemTemp.createTempSync('flutter_new_gallery_test.'); + final Directory galleryDir = Directory(path.join(galleryParentDir.path, 'gallery')); + + try { + await task(NewGalleryPerfTest(galleryDir, enableImpeller: true, forceOpenGLES: true).run); + } finally { + rmTree(galleryParentDir); + } +} diff --git a/dev/devicelab/lib/tasks/new_gallery.dart b/dev/devicelab/lib/tasks/new_gallery.dart index dcc52ff56a268..6f8b998b4be75 100644 --- a/dev/devicelab/lib/tasks/new_gallery.dart +++ b/dev/devicelab/lib/tasks/new_gallery.dart @@ -16,6 +16,7 @@ class NewGalleryPerfTest extends PerfTest { String dartDefine = '', super.enableImpeller, super.timeoutSeconds, + super.forceOpenGLES, }) : super( galleryDir.path, 'test_driver/transitions_perf.dart', diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 0f018ad7accba..2d36b93615278 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -9,6 +9,7 @@ import 'dart:math' as math; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; +import 'package:xml/xml.dart'; import '../framework/devices.dart'; import '../framework/framework.dart'; @@ -691,6 +692,63 @@ Map _average(List> results, int iterations return tally; } +/// Opens the file at testDirectory + 'android/app/src/main/AndroidManifest.xml' +/// and adds the following entry to the application. +/// +void _addOpenGLESToManifest(String testDirectory) { + final String manifestPath = path.join( + testDirectory, 'android', 'app', 'src', 'main', 'AndroidManifest.xml'); + final File file = File(manifestPath); + + if (!file.existsSync()) { + throw Exception('AndroidManifest.xml not found at $manifestPath'); + } + + final String xmlStr = file.readAsStringSync(); + final XmlDocument xmlDoc = XmlDocument.parse(xmlStr); + const String key = 'io.flutter.embedding.android.ImpellerBackend'; + const String value = 'opengles'; + + final XmlElement applicationNode = + xmlDoc.findAllElements('application').first; + + // Check if the meta-data node already exists. + final Iterable existingMetaData = applicationNode + .findAllElements('meta-data') + .where((XmlElement node) => node.getAttribute('android:name') == key); + + if (existingMetaData.isNotEmpty) { + final XmlElement existingEntry = existingMetaData.first; + existingEntry.setAttribute('android:value', value); + } else { + final XmlElement metaData = XmlElement( + XmlName('meta-data'), + [ + XmlAttribute(XmlName('android:name'), key), + XmlAttribute(XmlName('android:value'), value) + ], + ); + + applicationNode.children.add(metaData); + } + + file.writeAsStringSync(xmlDoc.toXmlString(pretty: true, indent: ' ')); +} + +Future _resetManifest(String testDirectory) async { + final String manifestPath = path.join( + testDirectory, 'android', 'app', 'src', 'main', 'AndroidManifest.xml'); + final File file = File(manifestPath); + + if (!file.existsSync()) { + throw Exception('AndroidManifest.xml not found at $manifestPath'); + } + + await exec('git', ['checkout', file.path]); +} + /// Measure application startup performance. class StartupTest { const StartupTest(this.testDirectory, { this.reportMetrics = true, this.target = 'lib/main.dart' }); @@ -978,6 +1036,7 @@ class PerfTest { this.flutterDriveCallback, this.timeoutSeconds, this.enableImpeller, + this.forceOpenGLES, }): _resultFilename = resultFilename; const PerfTest.e2e( @@ -995,6 +1054,7 @@ class PerfTest { this.flutterDriveCallback, this.timeoutSeconds, this.enableImpeller, + this.forceOpenGLES, }) : saveTraceFile = false, timelineFileName = null, _resultFilename = resultFilename; /// The directory where the app under test is defined. @@ -1031,6 +1091,9 @@ class PerfTest { /// Whether the perf test should enable Impeller. final bool? enableImpeller; + /// Whether the perf test force Impeller's OpenGLES backend. + final bool? forceOpenGLES; + /// Number of seconds to time out the test after, allowing debug callbacks to run. final int? timeoutSeconds; @@ -1079,40 +1142,55 @@ class PerfTest { final String? localEngine = localEngineFromEnv; final String? localEngineSrcPath = localEngineSrcPathFromEnv; - final List options = [ - if (localEngine != null) - ...['--local-engine', localEngine], - if (localEngineSrcPath != null) - ...['--local-engine-src-path', localEngineSrcPath], - '--no-dds', - '--no-android-gradle-daemon', - '-v', - '--verbose-system-logs', - '--profile', - if (timeoutSeconds != null) - ...[ + Future Function()? manifestReset; + if (forceOpenGLES ?? false) { + assert(enableImpeller!); + _addOpenGLESToManifest(testDirectory); + manifestReset = () => _resetManifest(testDirectory); + } + + try { + final List options = [ + if (localEngine != null) ...['--local-engine', localEngine], + if (localEngineSrcPath != null) ...[ + '--local-engine-src-path', + localEngineSrcPath + ], + '--no-dds', + '--no-android-gradle-daemon', + '-v', + '--verbose-system-logs', + '--profile', + if (timeoutSeconds != null) ...[ '--timeout', timeoutSeconds.toString(), ], - if (needsFullTimeline) - '--trace-startup', // Enables "endless" timeline event buffering. - '-t', testTarget, - if (testDriver != null) - ...['--driver', testDriver!], - if (existingApp != null) - ...['--use-existing-app', existingApp], - if (dartDefine.isNotEmpty) - ...['--dart-define', dartDefine], - if (enableImpeller != null && enableImpeller!) '--enable-impeller', - if (enableImpeller != null && !enableImpeller!) '--no-enable-impeller', - '-d', - deviceId, - ]; - if (flutterDriveCallback != null) { - flutterDriveCallback!(options); - } else { - await flutter('drive', options: options); + if (needsFullTimeline) + '--trace-startup', // Enables "endless" timeline event buffering. + '-t', testTarget, + if (testDriver != null) ...['--driver', testDriver!], + if (existingApp != null) ...[ + '--use-existing-app', + existingApp + ], + if (dartDefine.isNotEmpty) ...['--dart-define', dartDefine], + if (enableImpeller != null && enableImpeller!) '--enable-impeller', + if (enableImpeller != null && !enableImpeller!) + '--no-enable-impeller', + '-d', + deviceId, + ]; + if (flutterDriveCallback != null) { + flutterDriveCallback!(options); + } else { + await flutter('drive', options: options); + } + } finally { + if (manifestReset != null) { + await manifestReset(); + } } + final Map data = json.decode( file('${_testOutputDirectory(testDirectory)}/$resultFilename.json').readAsStringSync(), ) as Map; diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index e9a76d4aa94ea..5c76b6c12de6e 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -23,6 +23,7 @@ dependencies: vm_service: 11.8.0 web: 0.1.4-beta webkit_inspection_protocol: 1.2.0 + xml: 6.3.0 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -37,6 +38,7 @@ dependencies: js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" retry: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +73,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a9f3 +# PUBSPEC CHECKSUM: 289e From 8f85bb35adbbfccd702de8e327a0f35e50c2c907 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 16:18:06 -0400 Subject: [PATCH 0521/1547] Manual roll Flutter Engine from 4cc0b3dab001 to b08e1410a06a (9 revisions) (#131880) Manual roll requested by jacksongardner@google.com https://github.com/flutter/engine/compare/4cc0b3dab001...b08e1410a06a 2023-08-03 john@johnmccutchan.com Add @Keep annotations to avoid dead code elimination of classes only referenced by JNI (flutter/engine#44337) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from bd3ee535e246 to 36072a994f11 (2 revisions) (flutter/engine#44329) 2023-08-03 skia-flutter-autoroll@skia.org Roll Dart SDK from dcd09f5726b7 to e3d2b4a190aa (1 revision) (flutter/engine#44330) 2023-08-03 30870216+gaaclarke@users.noreply.github.com [Impeller] updated validation layers documentation (flutter/engine#44328) 2023-08-03 41930132+hellohuanlin@users.noreply.github.com [ios]make the screenIfViewLoaded and windowSceneIfLoaded helpers reusable (flutter/engine#44303) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from 768050436c0a to bd3ee535e246 (2 revisions) (flutter/engine#44327) 2023-08-03 john@johnmccutchan.com Re-Re-Land Support for rendering Android Platform Views into a HardwareBuffer backed texture (flutter/engine#44326) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from 8a377a9545b8 to 768050436c0a (1 revision) (flutter/engine#44320) 2023-08-03 bdero@google.com [Flutter GPU] Export symbols from engine, stub for testing on CI. (flutter/engine#44280) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7285f8154602a..6eddf86326264 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4cc0b3dab001f5a12873b46f9d52b7d00f1cb827 +b08e1410a06a521087a1d178e16bf76e6a0e678e From 948900979050838b1f91701d24d89a7ce4d3fbf7 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 3 Aug 2023 15:21:09 -0700 Subject: [PATCH 0522/1547] Revert "Manual roll Flutter Engine from 4cc0b3dab001 to b08e1410a06a (9 revisions)" (#131896) Reverts flutter/flutter#131880 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6eddf86326264..7285f8154602a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b08e1410a06a521087a1d178e16bf76e6a0e678e +4cc0b3dab001f5a12873b46f9d52b7d00f1cb827 From f0e39349c988445359025effa65b5e4bac680910 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:31:06 -0700 Subject: [PATCH 0523/1547] [Impeller] Add animated_blur_backdrop_filter_perf execution on samsung vulkan and opengles (#131864) issue: https://github.com/flutter/flutter/issues/131784 --- .ci.yaml | 22 +++++++++++++++++++ TESTOWNERS | 1 + ...ilter_perf_opengles__timeline_summary.dart | 15 +++++++++++++ dev/devicelab/lib/tasks/perf_tests.dart | 2 ++ 4 files changed, 40 insertions(+) create mode 100644 dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart diff --git a/.ci.yaml b/.ci.yaml index 5405ed69e956d..3e60fbbfd0e60 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2600,6 +2600,28 @@ targets: ["devicelab", "android", "linux"] task_name: animated_blur_backdrop_filter_perf__timeline_summary + - name: Linux_samsung_s10 animated_blur_backdrop_filter_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: animated_blur_backdrop_filter_perf__timeline_summary + + - name: Linux_samsung_s10 animated_blur_backdrop_filter_perf_opengles__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: animated_blur_backdrop_filter_perf_opengles__timeline_summary + - name: Staging_build_linux analyze presubmit: false bringup: true diff --git a/TESTOWNERS b/TESTOWNERS index 79d161f98cfe4..cb1a439ef9d56 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -92,6 +92,7 @@ /dev/devicelab/bin/tasks/web_size__compile_test.dart @yjbanov @flutter/web /dev/devicelab/bin/tasks/wide_gamut_ios.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/slider_perf_android.dart @tahatesser @flutter/framework ## Windows Android DeviceLab tests diff --git a/dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart b/dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart new file mode 100644 index 0000000000000..83e4c6d0546dd --- /dev/null +++ b/dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart @@ -0,0 +1,15 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createAnimatedBlurBackropFilterPerfTest( + enableImpeller: true, forceOpenGLES: true)); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 2d36b93615278..680dfc2fb394f 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -630,12 +630,14 @@ TaskFunction createGradientStaticPerfE2ETest() { TaskFunction createAnimatedBlurBackropFilterPerfTest({ bool? enableImpeller, + bool? forceOpenGLES, }) { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', 'test_driver/run_app.dart', 'animated_blur_backdrop_filter_perf', enableImpeller: enableImpeller, + forceOpenGLES: forceOpenGLES, testDriver: 'test_driver/animated_blur_backdrop_filter_perf_test.dart', saveTraceFile: true, ).run; From 0192f88328fbf6c11e59ffcb6b2f16ed2d5b35fd Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 4 Aug 2023 01:32:57 +0300 Subject: [PATCH 0524/1547] Fix TimePicker token issue link (#131863) Fix issue reference for https://github.com/flutter/flutter/issues/131247 (it was added in the bug fix PR https://github.com/flutter/flutter/pull/131253) --- dev/tools/gen_defaults/lib/time_picker_template.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tools/gen_defaults/lib/time_picker_template.dart b/dev/tools/gen_defaults/lib/time_picker_template.dart index af359acf6cd90..4d60175f88281 100644 --- a/dev/tools/gen_defaults/lib/time_picker_template.dart +++ b/dev/tools/gen_defaults/lib/time_picker_template.dart @@ -281,7 +281,7 @@ class _${blockName}DefaultsM3 extends _TimePickerDefaults { @override TextStyle get hourMinuteTextStyle { return MaterialStateTextStyle.resolveWith((Set states) { - // TODO(tahatesser): Update this when https://github.com/flutter/flutter/issues/127035 is fixed. + // TODO(tahatesser): Update this when https://github.com/flutter/flutter/issues/131247 is fixed. // This is using the correct text style from Material 3 spec. // https://m3.material.io/components/time-pickers/specs#fd0b6939-edab-4058-82e1-93d163945215 return _textTheme.displayMedium!.copyWith(color: _hourMinuteTextColor.resolve(states)); From fd000dcd427e6725c48108a15650eebde47d2da2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 19:18:41 -0400 Subject: [PATCH 0525/1547] Roll Flutter Engine from b08e1410a06a to 0c1de9b8afba (9 revisions) (#131897) https://github.com/flutter/engine/compare/b08e1410a06a...0c1de9b8afba 2023-08-03 yjbanov@google.com [web] fix clicks on merged semantic nodes (flutter/engine#43620) 2023-08-03 john@johnmccutchan.com Remove WARNINGs from JNI load path as we can't suppress them (flutter/engine#44348) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from 872dc53233cf to bae32428c1c7 (3 revisions) (flutter/engine#44341) 2023-08-03 ychris@google.com Build iOS unittest target in unopt builds (flutter/engine#44301) 2023-08-03 chris@bracken.jp [darwin] Move common targets to common/BUILD.gn (flutter/engine#44335) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from 2babe68de295 to 872dc53233cf (2 revisions) (flutter/engine#44339) 2023-08-03 kjlubick@users.noreply.github.com Migrate GL calls of GrBackend* (flutter/engine#44334) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from 36072a994f11 to 2babe68de295 (1 revision) (flutter/engine#44336) 2023-08-03 skia-flutter-autoroll@skia.org Roll Clang from 07c592048780 to 020d2fb7711d (flutter/engine#44332) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --------- Co-authored-by: Zachary Anderson --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7285f8154602a..c79e468d011e3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4cc0b3dab001f5a12873b46f9d52b7d00f1cb827 +0c1de9b8afbabe3857a3b495cc9b0bcfdf1ac305 From cfdf72951a46f134f34fdab0eccb7d9e3391dbac Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 20:13:07 -0400 Subject: [PATCH 0526/1547] Roll Flutter Engine from 0c1de9b8afba to 4c62dd81d136 (4 revisions) (#131902) https://github.com/flutter/engine/compare/0c1de9b8afba...4c62dd81d136 2023-08-03 matanlurey@users.noreply.github.com [Impeller] Run clangd tidy, opting out in 2 cases. (flutter/engine#44351) 2023-08-03 1961493+harryterkelsen@users.noreply.github.com Reland "[web] Update text editing test skips" (flutter/engine#37655) 2023-08-03 jason-simmons@users.noreply.github.com [Impeller] Discard invalid command buffer handles after destroying a command pool (flutter/engine#44194) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from bae32428c1c7 to 3b3c1a617544 (1 revision) (flutter/engine#44345) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c79e468d011e3..0943f549c6ea7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0c1de9b8afbabe3857a3b495cc9b0bcfdf1ac305 +4c62dd81d1368a9d073d92652d9480e6e88bd4d4 From 821a825e50be7a5009b3d868d737d347300744e4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 21:05:51 -0400 Subject: [PATCH 0527/1547] Roll Flutter Engine from 4c62dd81d136 to 098ec489585e (2 revisions) (#131903) https://github.com/flutter/engine/compare/4c62dd81d136...098ec489585e 2023-08-03 dnfield@google.com [Impeller] Fail loudly if --enable-software-rendering is used. (flutter/engine#44346) 2023-08-03 skia-flutter-autoroll@skia.org Roll Skia from 3b3c1a617544 to 0a376550f218 (3 revisions) (flutter/engine#44353) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0943f549c6ea7..62a53a34271df 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4c62dd81d1368a9d073d92652d9480e6e88bd4d4 +098ec489585ecc1ef8c4b03c4e52b64a447ef86b From f7b68919ac5436d250309efe12d5a5c9cbdc1f96 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 22:37:30 -0400 Subject: [PATCH 0528/1547] Roll Flutter Engine from 098ec489585e to ca8d852eddfc (2 revisions) (#131905) https://github.com/flutter/engine/compare/098ec489585e...ca8d852eddfc 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 0a376550f218 to a3d2051afa4a (4 revisions) (flutter/engine#44362) 2023-08-03 ychris@google.com Revert "Build iOS unittest target in unopt builds" (flutter/engine#44356) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 62a53a34271df..4c58054012f45 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -098ec489585ecc1ef8c4b03c4e52b64a447ef86b +ca8d852eddfc5ca6aa5adb9a6f99bd561550e2be From b23813480cb5006192027ce093ef005f4c8eac79 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 3 Aug 2023 23:36:28 -0400 Subject: [PATCH 0529/1547] Roll Flutter Engine from ca8d852eddfc to e3f75650ac5f (1 revision) (#131907) https://github.com/flutter/engine/compare/ca8d852eddfc...e3f75650ac5f 2023-08-04 skia-flutter-autoroll@skia.org Roll Dart SDK from e3d2b4a190aa to eb7670788799 (1 revision) (flutter/engine#44363) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4c58054012f45..5a567c45618dc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ca8d852eddfc5ca6aa5adb9a6f99bd561550e2be +e3f75650ac5f93a056af249331bd9fb9d2e6ec8d From 30692ee4b787998ac5cd0babaccb8b85b7cfcdfa Mon Sep 17 00:00:00 2001 From: Andrew Kolos Date: Thu, 3 Aug 2023 21:00:12 -0700 Subject: [PATCH 0530/1547] make `--dart-define` override redundant values in `--dart-define-from-file` (#131088) Fixes #130604 --- .../lib/src/runner/flutter_command.dart | 16 ++++---- .../hermetic/assemble_test.dart | 2 +- .../permeable/build_bundle_test.dart | 38 ++++++++++++++++++- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 204782e3d403a..737def1f3a0c1 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -646,7 +646,8 @@ abstract class FlutterCommand extends Command { help: 'The path of a .json or .env file containing key-value pairs that will be available as environment variables.\n' 'These can be accessed using the String.fromEnvironment, bool.fromEnvironment, and int.fromEnvironment constructors.\n' - 'Multiple defines can be passed by repeating "--${FlutterOptions.kDartDefineFromFileOption}" multiple times.', + 'Multiple defines can be passed by repeating "--${FlutterOptions.kDartDefineFromFileOption}" multiple times.\n' + 'Entries from "--${FlutterOptions.kDartDefinesOption}" with identical keys take precedence over entries from these files.', valueHelp: 'use-define-config.json|.env', splitCommas: false, ); @@ -1351,14 +1352,14 @@ abstract class FlutterCommand extends Command { List extractDartDefines({required Map defineConfigJsonMap}) { final List dartDefines = []; - if (argParser.options.containsKey(FlutterOptions.kDartDefinesOption)) { - dartDefines.addAll(stringsArg(FlutterOptions.kDartDefinesOption)); - } - defineConfigJsonMap.forEach((String key, Object? value) { dartDefines.add('$key=$value'); }); + if (argParser.options.containsKey(FlutterOptions.kDartDefinesOption)) { + dartDefines.addAll(stringsArg(FlutterOptions.kDartDefinesOption)); + } + return dartDefines; } @@ -1372,9 +1373,8 @@ abstract class FlutterCommand extends Command { for (final String path in configFilePaths) { if (!globals.fs.isFileSync(path)) { - throwToolExit('Json config define file "--${FlutterOptions - .kDartDefineFromFileOption}=$path" is not a file, ' - 'please fix first!'); + throwToolExit('Did not find the file passed to "--${FlutterOptions + .kDartDefineFromFileOption}". Path: $path'); } final String configRaw = globals.fs.file(path).readAsStringSync(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart index bf0434b3ca250..09f2c56444f46 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart @@ -302,7 +302,7 @@ void main() { 'debug_macos_bundle_flutter_assets', '--dart-define=k=v', '--dart-define-from-file=config']), - throwsToolExit(message: 'Json config define file "--dart-define-from-file=config" is not a file, please fix first!')); + throwsToolExit(message: 'Did not find the file passed to "--dart-define-from-file". Path: config')); }, overrides: { Cache: () => Cache.test(processManager: FakeProcessManager.any()), FileSystem: () => MemoryFileSystem.test(), diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart index c4a501897f551..a0d34ace2777b 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart @@ -559,6 +559,42 @@ void main() { ProcessManager: () => FakeProcessManager.any(), }); + testUsingContext('values from --dart-define supersede values from --dart-define-from-file', () async { + globals.fs + .file(globals.fs.path.join('lib', 'main.dart')) + .createSync(recursive: true); + globals.fs.file('pubspec.yaml').createSync(); + globals.fs.file('.packages').createSync(); + globals.fs.file('.env').writeAsStringSync(''' + MY_VALUE=VALUE_FROM_ENV_FILE + '''); + final CommandRunner runner = + createTestCommandRunner(BuildBundleCommand( + logger: BufferLogger.test(), + )); + + await runner.run([ + 'bundle', + '--no-pub', + '--dart-define=MY_VALUE=VALUE_FROM_COMMAND', + '--dart-define-from-file=.env', + ]); + + }, overrides: { + BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), + (Target target, Environment environment) { + expect( + _decodeDartDefines(environment), + containsAllInOrder(const [ + 'MY_VALUE=VALUE_FROM_ENV_FILE', + 'MY_VALUE=VALUE_FROM_COMMAND', + ]), + ); + }), + FileSystem: fsFactory, + ProcessManager: () => FakeProcessManager.any(), + }); + testUsingContext('--dart-define-from-file correctly parses a valid env file', () async { globals.fs .file(globals.fs.path.join('lib', 'main.dart')) @@ -763,7 +799,7 @@ void main() { 'bundle', '--no-pub', '--dart-define-from-file=config', - ]), throwsToolExit(message: 'Json config define file "--dart-define-from-file=config" is not a file, please fix first!')); + ]), throwsToolExit(message: 'Did not find the file passed to "--dart-define-from-file". Path: config')); }, overrides: { FileSystem: fsFactory, BuildSystem: () => TestBuildSystem.all(BuildResult(success: true)), From a353826b70302d47a68afc1f53a2eb0735eb2136 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 02:07:07 -0400 Subject: [PATCH 0531/1547] Roll Flutter Engine from e3f75650ac5f to de0ec1c971ab (2 revisions) (#131910) https://github.com/flutter/engine/compare/e3f75650ac5f...de0ec1c971ab 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from a3d2051afa4a to 1f884c208390 (5 revisions) (flutter/engine#44369) 2023-08-04 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Qo3dJIXjK-Ia8j42J... to FAGt3OEY8Yi1-SaFj... (flutter/engine#44366) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from Qo3dJIXjK-Ia to FAGt3OEY8Yi1 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5a567c45618dc..d1659e9584673 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e3f75650ac5f93a056af249331bd9fb9d2e6ec8d +de0ec1c971ab3a57ba472b7421d215cc7cc7e536 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7178e8bf9362c..0a6d957dbc7e6 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Qo3dJIXjK-Ia8j42JByo585ZGQ85ddt1EdqV71Vd6bMC +FAGt3OEY8Yi1-SaFjOXzB2-fTZowtLUMLTdxBoqLGhIC From 3349ec6228c46173fff4e3bec01ed7cf86b3027e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 03:00:14 -0400 Subject: [PATCH 0532/1547] Roll Flutter Engine from de0ec1c971ab to 03137a3b9b81 (1 revision) (#131912) https://github.com/flutter/engine/compare/de0ec1c971ab...03137a3b9b81 2023-08-04 skia-flutter-autoroll@skia.org Roll Dart SDK from eb7670788799 to 5573a23b0312 (1 revision) (flutter/engine#44370) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d1659e9584673..77dfca54f11e5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -de0ec1c971ab3a57ba472b7421d215cc7cc7e536 +03137a3b9b811092f2fde7ad72263c2e051d2028 From 229386cd7fe3a14cb10dc944525225bcc2c82660 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 03:57:11 -0400 Subject: [PATCH 0533/1547] Roll Flutter Engine from 03137a3b9b81 to c912e3417e68 (2 revisions) (#131913) https://github.com/flutter/engine/compare/03137a3b9b81...c912e3417e68 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 03cc525d4485 to 3b36347d4449 (1 revision) (flutter/engine#44373) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 1f884c208390 to 03cc525d4485 (1 revision) (flutter/engine#44371) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 77dfca54f11e5..c737e52093525 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -03137a3b9b811092f2fde7ad72263c2e051d2028 +c912e3417e687bf5a8e6d10298c0ad427693c5b6 From 3507f48ea8ae38c794cb27f5b1bd5d82343dd331 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 05:50:24 -0400 Subject: [PATCH 0534/1547] Roll Flutter Engine from c912e3417e68 to 0725a6f519d0 (2 revisions) (#131917) https://github.com/flutter/engine/compare/c912e3417e68...0725a6f519d0 2023-08-04 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from KPSWBhOvG6piddBQG... to ZvUiUZL9vUp2LcvHG... (flutter/engine#44377) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 3b36347d4449 to 9e35fa235af9 (1 revision) (flutter/engine#44374) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from KPSWBhOvG6pi to ZvUiUZL9vUp2 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c737e52093525..2538690133ddf 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c912e3417e687bf5a8e6d10298c0ad427693c5b6 +0725a6f519d0c6257409b6c912d976a8bc29d8ce diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index e0c529c8fd139..2cdc362fe1e10 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -KPSWBhOvG6piddBQGjbnutOw4JoLbHNwd9UmvtJ2IxwC +ZvUiUZL9vUp2LcvHGHnjFis6tKvXuAzUQe5Ax_6XLCsC From 6636b64c9bb046c63c376ab735ef523f760f0fb7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 08:14:14 -0400 Subject: [PATCH 0535/1547] Roll Flutter Engine from 0725a6f519d0 to d15a02a8191c (2 revisions) (#131924) https://github.com/flutter/engine/compare/0725a6f519d0...d15a02a8191c 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 9e35fa235af9 to 100bf3248bf0 (1 revision) (flutter/engine#44381) 2023-08-04 skia-flutter-autoroll@skia.org Roll Dart SDK from 5573a23b0312 to 6415ba55bf6a (1 revision) (flutter/engine#44380) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2538690133ddf..11cebecb047cb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0725a6f519d0c6257409b6c912d976a8bc29d8ce +d15a02a8191c266624ba22d1089ffdc1c60cb201 From 2c10295904ab9975670b2682bfa4fcfd2f8e1c08 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 4 Aug 2023 08:09:00 -0700 Subject: [PATCH 0536/1547] Upgrade packages. (#131927) --- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/complex_layout/pubspec.yaml | 4 ++-- dev/benchmarks/macrobenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/microbenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 10 +++++----- .../platform_channels_benchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_views_layout/pubspec.yaml | 4 ++-- .../pubspec.yaml | 4 ++-- dev/benchmarks/test_apps/stocks/pubspec.yaml | 4 ++-- dev/bots/pubspec.yaml | 4 ++-- dev/conductor/core/pubspec.yaml | 4 ++-- dev/customer_testing/pubspec.yaml | 4 ++-- dev/devicelab/pubspec.yaml | 4 ++-- .../android_semantics_testing/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 12 ++++++------ dev/integration_tests/channels/pubspec.yaml | 4 ++-- .../deferred_components_test/pubspec.yaml | 4 ++-- dev/integration_tests/external_ui/pubspec.yaml | 4 ++-- dev/integration_tests/flavors/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- .../hybrid_android_views/pubspec.yaml | 12 ++++++------ .../ios_platform_view_tests/pubspec.yaml | 4 ++-- .../platform_interaction/pubspec.yaml | 4 ++-- .../release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- .../windows_startup_test/pubspec.yaml | 4 ++-- dev/tools/gen_defaults/pubspec.yaml | 4 ++-- dev/tools/gen_keycodes/pubspec.yaml | 4 ++-- dev/tools/pubspec.yaml | 4 ++-- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 4 ++-- examples/hello_world/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 4 ++-- examples/platform_channel_swift/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 4 ++-- packages/flutter/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_tools/pubspec.yaml | 4 ++-- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 4 ++-- packages/integration_test/example/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 44 files changed, 99 insertions(+), 99 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 2d57886812a7c..3af15f456dfb0 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -61,7 +61,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: c6e2 +# PUBSPEC CHECKSUM: 90e3 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 4ec0f8016d327..0add398c2f9d8 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 66bb +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 1260f8897ed6d..60e156a59bc06 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -211,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 66bb +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 714e4de81f9c6..02c8cee8cb2ee 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -138,4 +138,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: b933 +# PUBSPEC CHECKSUM: 8334 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 4d9589f0bf97c..2817865c68728 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -24,11 +24,11 @@ dependencies: meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.0.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_android: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: b371 +# PUBSPEC CHECKSUM: 91fe diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index a19c761161024..bbc27ebff51c2 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3d1e +# PUBSPEC CHECKSUM: 071f diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 926509b892b17..cd3b965385088 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 66bb +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index b97911a615388..c9519591cc9e2 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 66bb +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index a1ef29dc6899b..49f2cdc6d5a59 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -67,7 +67,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ebdd +# PUBSPEC CHECKSUM: d5de diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index d3c6bfcbf1c1d..aa7f54ee036a6 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 7431 +# PUBSPEC CHECKSUM: 5232 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 6b37f619e19ea..0d9f0d93585ef 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -60,10 +60,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ecbe +# PUBSPEC CHECKSUM: 98bf diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index f880aafd5d2ba..8165b2ecf7351 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -50,10 +50,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 920c +# PUBSPEC CHECKSUM: 3e0d diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 5c76b6c12de6e..4a0f12ca8a78e 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: shelf: 1.4.1 shelf_static: 1.1.2 stack_trace: 1.11.1 - vm_service: 11.8.0 + vm_service: 11.9.0 web: 0.1.4-beta webkit_inspection_protocol: 1.2.0 xml: 6.3.0 @@ -73,4 +73,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 289e +# PUBSPEC CHECKSUM: 069f diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 9f97cd0a1f195..4bb0c77fd3db9 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -57,7 +57,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: dddb +# PUBSPEC CHECKSUM: a7dc diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 9379533135c0d..7d269f49cd637 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: path_provider: 2.0.15 # This made non-transitive to allow exact pinning # https://github.com/flutter/flutter/issues/116376 - path_provider_android: 2.0.27 + path_provider_android: 2.1.0 collection: 1.18.0 assets_for_android_views: git: @@ -31,10 +31,10 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,7 +45,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b4b5 +# PUBSPEC CHECKSUM: 7544 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index 74dcaaa5356b8..baa0f3f86e1b6 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -37,10 +37,10 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: c436 +# PUBSPEC CHECKSUM: 0837 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 92dc493fb4638..815f51e13395d 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index c3aa62c27c642..a98b678a049dd 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4864 +# PUBSPEC CHECKSUM: 3265 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 0736526f6a77b..b58bd6965a1df 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -57,7 +57,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 6be149b91ac3c..beadeb0f2bd9a 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -100,7 +100,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 4307 +# PUBSPEC CHECKSUM: 2d08 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 7dc77788d5e14..fdcce7bc03c39 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -28,11 +28,11 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.0.27 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.1.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_android: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,7 +43,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b4b5 +# PUBSPEC CHECKSUM: 7544 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 93e6ac1f48ec3..ca8b8b2c4529c 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,4 +78,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index a1f60fe0547c2..1ca2802ac64f4 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4864 +# PUBSPEC CHECKSUM: 3265 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index eef94284f63ae..290bd144a9b07 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -32,6 +32,6 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: fafc +# PUBSPEC CHECKSUM: 1efd diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index 5cac435310e57..914fb126edb33 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -66,7 +66,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: a1a4 +# PUBSPEC CHECKSUM: c4a5 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index f1b26da6b4c23..e01cef777b9f3 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index ae064d5555006..50782ae127044 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a806 +# PUBSPEC CHECKSUM: 9207 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index 64e053b776b3e..2cf2d44bfc83b 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -36,9 +36,9 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fafc +# PUBSPEC CHECKSUM: 1efd diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index c170a101effe6..5ad79e827bd63 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +63,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4864 +# PUBSPEC CHECKSUM: 3265 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index f87f7a27f8867..4fd3370b262d9 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -50,10 +50,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 920c +# PUBSPEC CHECKSUM: 3e0d diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 973f4f0199812..1c543406e9959 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -52,10 +52,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7403 +# PUBSPEC CHECKSUM: 2004 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 1f546e55143f3..71bb08f68b1e4 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -56,10 +56,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0b1d +# PUBSPEC CHECKSUM: b61e diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index cac5764fd5c47..1792a44f6d6d0 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: flutter: sdk: flutter - vm_service: 11.8.0 + vm_service: 11.9.0 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: fafc +# PUBSPEC CHECKSUM: 1efd diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 029da2df16af1..94019eda081f4 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -76,7 +76,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +86,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bacf +# PUBSPEC CHECKSUM: a4d0 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 8b383ba160e9d..658b6ebb2f29e 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -62,11 +62,11 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index c1959a8b8a7be..771b425a71c3c 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -62,7 +62,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 4a9b133989c3f..b0174fe733b92 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -62,7 +62,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4321 +# PUBSPEC CHECKSUM: 2d22 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index cbd036192225d..0c7254667ccf2 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -59,10 +59,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: dddb +# PUBSPEC CHECKSUM: a7dc diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index c1f59c37b81da..4397753e04a96 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -68,10 +68,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 46f3 +# PUBSPEC CHECKSUM: 10f4 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 1b22bf112dea0..e51fc3f4fd7f9 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: sdk: flutter path: 1.8.3 meta: 1.9.1 - vm_service: 11.8.0 + vm_service: 11.9.0 webdriver: 3.0.2 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ed28 +# PUBSPEC CHECKSUM: d729 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 105c80989ced2..4fa470fb15965 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_api: 0.6.1 test_core: 0.5.5 - vm_service: 11.8.0 + vm_service: 11.9.0 standard_message_codec: 0.0.1+3 @@ -108,4 +108,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 3540 +# PUBSPEC CHECKSUM: 6b41 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 79f1eb0f3d747..1b9eec759ca1d 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -8,7 +8,7 @@ environment: dependencies: process: 4.2.4 - vm_service: 11.8.0 + vm_service: 11.9.0 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +64,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 4813 +# PUBSPEC CHECKSUM: f314 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 15c7145917035..aff039587fdef 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -75,7 +75,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.8.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 688f +# PUBSPEC CHECKSUM: 5290 diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index e9d6687087c77..7568c7237539f 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: flutter_test: sdk: flutter path: 1.8.3 - vm_service: 11.8.0 + vm_service: 11.9.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: c436 +# PUBSPEC CHECKSUM: 0837 From 2ba9f7bdfe169f514e31509dba8906fd9860c795 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 11:23:02 -0400 Subject: [PATCH 0537/1547] Roll Flutter Engine from d15a02a8191c to badca1f7f8c9 (1 revision) (#131928) https://github.com/flutter/engine/compare/d15a02a8191c...badca1f7f8c9 2023-08-04 skia-flutter-autoroll@skia.org Roll Dart SDK from 6415ba55bf6a to b3372378e487 (1 revision) (flutter/engine#44383) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 11cebecb047cb..235cfa17f7e96 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d15a02a8191c266624ba22d1089ffdc1c60cb201 +badca1f7f8c90f3b47ce149dde302a8f3d7ff3fb From 1cf3907407cbc91be7cec2c38b348a2d66041dd5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 12:04:08 -0400 Subject: [PATCH 0538/1547] Roll Packages from d00c1f9eb01c to ce53da1bd741 (3 revisions) (#131935) https://github.com/flutter/packages/compare/d00c1f9eb01c...ce53da1bd741 2023-08-04 ditman@gmail.com [image_picker_web] Listens to file input cancel event. (flutter/packages#4453) 2023-08-04 maurits@vnbskm.nl [in_app_purchase] Updates handling of subscription price changes in README. (flutter/packages#4643) 2023-08-03 stuartmorgan@google.com [pigeon] Consolidate main Dart unit tests (flutter/packages#4641) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 4ef31c05dceda..2fc596952bc8d 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -d00c1f9eb01c764615c857a749f5d772905cbfad +ce53da1bd7411f1d356706363fdb42c55d7c4cc8 From b39604e02de64c50c46abe796991382609b29a1f Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 4 Aug 2023 12:14:06 -0500 Subject: [PATCH 0539/1547] Check for simulator runtime in flutter doctor (#131795) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Redo of https://github.com/flutter/flutter/pull/130728 - code is the same as before. That PR was stuck in Google testing and then I messed up the rebase so started over. ---- Starting in Xcode 15, the simulator is no longer included in Xcode and must be downloaded and installed separately. This adds a validation to `flutter doctor` to warn when the needed simulator runtime is missing. Validation message looks like: ``` [!] Xcode - develop for iOS and macOS (Xcode 15.0) ! iOS 17.0 Simulator not installed; this may be necessary for iOS and macOS development. To download and install the platform, open Xcode, select Xcode > Settings > Platforms, and click the GET button for the required platform. For more information, please visit: https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes ``` It may also show an error like this when something goes wrong when checking for the simulator: ``` [!] Xcode - develop for iOS and macOS (Xcode 15.0) ✗ Unable to find the iPhone Simulator SDK. ``` Note: I'm unsure of in the future if the SDK and the simulator runtime will need to match the exact version or just the major. For now, it only checks against the major version. Part 3 of https://github.com/flutter/flutter/issues/129558. --- packages/flutter_tools/lib/src/doctor.dart | 9 +- .../flutter_tools/lib/src/ios/simulators.dart | 107 +++++++++ .../flutter_tools/lib/src/macos/xcode.dart | 21 +- .../lib/src/macos/xcode_validator.dart | 66 +++++- .../general.shard/ios/simulators_test.dart | 158 ++++++++++++- .../test/general.shard/macos/xcode_test.dart | 56 +++++ .../macos/xcode_validator_test.dart | 211 +++++++++++++++++- packages/flutter_tools/test/src/context.dart | 3 + 8 files changed, 617 insertions(+), 14 deletions(-) diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index eb975fc17e047..255e938ef8caa 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -138,7 +138,14 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { if (androidWorkflow!.appliesToHostPlatform) GroupedValidator([androidValidator!, androidLicenseValidator!]), if (globals.iosWorkflow!.appliesToHostPlatform || macOSWorkflow.appliesToHostPlatform) - GroupedValidator([XcodeValidator(xcode: globals.xcode!, userMessages: userMessages), globals.cocoapodsValidator!]), + GroupedValidator([ + XcodeValidator( + xcode: globals.xcode!, + userMessages: userMessages, + iosSimulatorUtils: globals.iosSimulatorUtils!, + ), + globals.cocoapodsValidator!, + ]), if (webWorkflow.appliesToHostPlatform) ChromeValidator( chromiumLauncher: ChromiumLauncher( diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 06211c67a07a2..49a6bad2b4627 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart @@ -15,6 +15,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; import '../base/utils.dart'; +import '../base/version.dart'; import '../build_info.dart'; import '../convert.dart'; import '../devfs.dart'; @@ -91,6 +92,14 @@ class IOSSimulatorUtils { ); }).whereType().toList(); } + + Future> getAvailableIOSRuntimes() async { + if (!_xcode.isInstalledAndMeetsVersionCheck) { + return []; + } + + return _simControl.listAvailableIOSRuntimes(); + } } /// A wrapper around the `simctl` command line tool. @@ -293,6 +302,46 @@ class SimControl { _logger.printError('Unable to take screenshot of $deviceId:\n$exception'); } } + + /// Runs `simctl list runtimes available iOS --json` and returns all available iOS simulator runtimes. + Future> listAvailableIOSRuntimes() async { + final List runtimes = []; + final RunResult results = await _processUtils.run( + [ + ..._xcode.xcrunCommand(), + 'simctl', + 'list', + 'runtimes', + 'available', + 'iOS', + '--json', + ], + ); + + if (results.exitCode != 0) { + _logger.printError('Error executing simctl: ${results.exitCode}\n${results.stderr}'); + return runtimes; + } + + try { + final Object? decodeResult = (json.decode(results.stdout) as Map)['runtimes']; + if (decodeResult is List) { + for (final Object? runtimeData in decodeResult) { + if (runtimeData is Map) { + runtimes.add(IOSSimulatorRuntime.fromJson(runtimeData)); + } + } + } + + return runtimes; + } on FormatException { + // We failed to parse the simctl output, or it returned junk. + // One known message is "Install Started" isn't valid JSON but is + // returned sometimes. + _logger.printError('simctl returned non-JSON response: ${results.stdout}'); + return runtimes; + } + } } @@ -624,6 +673,64 @@ class IOSSimulator extends Device { } } +class IOSSimulatorRuntime { + IOSSimulatorRuntime._({ + this.bundlePath, + this.buildVersion, + this.platform, + this.runtimeRoot, + this.identifier, + this.version, + this.isInternal, + this.isAvailable, + this.name, + }); + + // Example: + // { + // "bundlePath" : "\/Library\/Developer\/CoreSimulator\/Volumes\/iOS_21A5277g\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS 17.0.simruntime", + // "buildversion" : "21A5277g", + // "platform" : "iOS", + // "runtimeRoot" : "\/Library\/Developer\/CoreSimulator\/Volumes\/iOS_21A5277g\/Library\/Developer\/CoreSimulator\/Profiles\/Runtimes\/iOS 17.0.simruntime\/Contents\/Resources\/RuntimeRoot", + // "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-17-0", + // "version" : "17.0", + // "isInternal" : false, + // "isAvailable" : true, + // "name" : "iOS 17.0", + // "supportedDeviceTypes" : [ + // { + // "bundlePath" : "\/Applications\/Xcode.app\/Contents\/Developer\/Platforms\/iPhoneOS.platform\/Library\/Developer\/CoreSimulator\/Profiles\/DeviceTypes\/iPhone 8.simdevicetype", + // "name" : "iPhone 8", + // "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8", + // "productFamily" : "iPhone" + // } + // ] + // }, + factory IOSSimulatorRuntime.fromJson(Map data) { + return IOSSimulatorRuntime._( + bundlePath: data['bundlePath']?.toString(), + buildVersion: data['buildversion']?.toString(), + platform: data['platform']?.toString(), + runtimeRoot: data['runtimeRoot']?.toString(), + identifier: data['identifier']?.toString(), + version: Version.parse(data['version']?.toString()), + isInternal: data['isInternal'] is bool? ? data['isInternal'] as bool? : null, + isAvailable: data['isAvailable'] is bool? ? data['isAvailable'] as bool? : null, + name: data['name']?.toString(), + ); + } + + final String? bundlePath; + final String? buildVersion; + final String? platform; + final String? runtimeRoot; + final String? identifier; + final Version? version; + final bool? isInternal; + final bool? isAvailable; + final String? name; +} + /// Launches the device log reader process on the host and parses the syslog. @visibleForTesting Future launchDeviceSystemLogTool(IOSSimulator device) async { diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart index ff0b89e7e7f9a..4784013da8e70 100644 --- a/packages/flutter_tools/lib/src/macos/xcode.dart +++ b/packages/flutter_tools/lib/src/macos/xcode.dart @@ -48,7 +48,8 @@ class Xcode { _fileSystem = fileSystem, _xcodeProjectInterpreter = xcodeProjectInterpreter, _processUtils = - ProcessUtils(logger: logger, processManager: processManager); + ProcessUtils(logger: logger, processManager: processManager), + _logger = logger; /// Create an [Xcode] for testing. /// @@ -60,16 +61,18 @@ class Xcode { XcodeProjectInterpreter? xcodeProjectInterpreter, Platform? platform, FileSystem? fileSystem, + Logger? logger, }) { platform ??= FakePlatform( operatingSystem: 'macos', environment: {}, ); + logger ??= BufferLogger.test(); return Xcode( platform: platform, processManager: processManager, fileSystem: fileSystem ?? MemoryFileSystem.test(), - logger: BufferLogger.test(), + logger: logger, xcodeProjectInterpreter: xcodeProjectInterpreter ?? XcodeProjectInterpreter.test(processManager: processManager), ); } @@ -78,6 +81,7 @@ class Xcode { final ProcessUtils _processUtils; final FileSystem _fileSystem; final XcodeProjectInterpreter _xcodeProjectInterpreter; + final Logger _logger; bool get isInstalledAndMeetsVersionCheck => _platform.isMacOS && isInstalled && isRequiredVersionSatisfactory; @@ -198,6 +202,19 @@ class Xcode { final String appPath = _fileSystem.path.join(selectPath, 'Applications', 'Simulator.app'); return _fileSystem.directory(appPath).existsSync() ? appPath : null; } + + /// Gets the version number of the platform for the selected SDK. + Future sdkPlatformVersion(EnvironmentType environmentType) async { + final RunResult runResult = await _processUtils.run( + [...xcrunCommand(), '--sdk', getSDKNameForIOSEnvironmentType(environmentType), '--show-sdk-platform-version'], + ); + if (runResult.exitCode != 0) { + _logger.printError('Could not find SDK Platform Version: ${runResult.stderr}'); + return null; + } + final String versionString = runResult.stdout.trim(); + return Version.parse(versionString); + } } EnvironmentType? environmentTypeFromSdkroot(String sdkroot, FileSystem fileSystem) { diff --git a/packages/flutter_tools/lib/src/macos/xcode_validator.dart b/packages/flutter_tools/lib/src/macos/xcode_validator.dart index c45351c6728b3..1604876fb9c0c 100644 --- a/packages/flutter_tools/lib/src/macos/xcode_validator.dart +++ b/packages/flutter_tools/lib/src/macos/xcode_validator.dart @@ -3,18 +3,32 @@ // found in the LICENSE file. import '../base/user_messages.dart'; +import '../base/version.dart'; +import '../build_info.dart'; import '../doctor_validator.dart'; +import '../ios/simulators.dart'; import 'xcode.dart'; +String _iOSSimulatorMissing(String version) => ''' +iOS $version Simulator not installed; this may be necessary for iOS and macOS development. +To download and install the platform, open Xcode, select Xcode > Settings > Platforms, +and click the GET button for the required platform. + +For more information, please visit: + https://developer.apple.com/documentation/xcode/installing-additional-simulator-runtimes'''; + class XcodeValidator extends DoctorValidator { XcodeValidator({ required Xcode xcode, + required IOSSimulatorUtils iosSimulatorUtils, required UserMessages userMessages, - }) : _xcode = xcode, - _userMessages = userMessages, - super('Xcode - develop for iOS and macOS'); + }) : _xcode = xcode, + _iosSimulatorUtils = iosSimulatorUtils, + _userMessages = userMessages, + super('Xcode - develop for iOS and macOS'); final Xcode _xcode; + final IOSSimulatorUtils _iosSimulatorUtils; final UserMessages _userMessages; @override @@ -57,6 +71,11 @@ class XcodeValidator extends DoctorValidator { messages.add(ValidationMessage.error(_userMessages.xcodeMissingSimct)); } + final ValidationMessage? missingSimulatorMessage = await _validateSimulatorRuntimeInstalled(); + if (missingSimulatorMessage != null) { + xcodeStatus = ValidationType.partial; + messages.add(missingSimulatorMessage); + } } else { xcodeStatus = ValidationType.missing; if (xcodeSelectPath == null || xcodeSelectPath.isEmpty) { @@ -68,4 +87,45 @@ class XcodeValidator extends DoctorValidator { return ValidationResult(xcodeStatus, messages, statusInfo: xcodeVersionInfo); } + + /// Validate the Xcode-installed iOS simulator SDK has a corresponding iOS + /// simulator runtime installed. + /// + /// Starting with Xcode 15, the iOS simulator runtime is no longer downloaded + /// with Xcode and must be downloaded and installed separately. + /// iOS applications cannot be run without it. + Future _validateSimulatorRuntimeInstalled() async { + // Skip this validation if Xcode is not installed, Xcode is a version less + // than 15, simctl is not installed, or if the EULA is not signed. + if (!_xcode.isInstalled || + _xcode.currentVersion == null || + _xcode.currentVersion!.major < 15 || + !_xcode.isSimctlInstalled || + !_xcode.eulaSigned) { + return null; + } + + final Version? platformSDKVersion = await _xcode.sdkPlatformVersion(EnvironmentType.simulator); + if (platformSDKVersion == null) { + return const ValidationMessage.error('Unable to find the iPhone Simulator SDK.'); + } + + final List runtimes = await _iosSimulatorUtils.getAvailableIOSRuntimes(); + if (runtimes.isEmpty) { + return const ValidationMessage.error('Unable to get list of installed Simulator runtimes.'); + } + + // Verify there is a simulator runtime installed matching the + // iphonesimulator SDK major version. + try { + runtimes.firstWhere( + (IOSSimulatorRuntime runtime) => + runtime.version?.major == platformSDKVersion.major, + ); + } on StateError { + return ValidationMessage.hint(_iOSSimulatorMissing(platformSDKVersion.toString())); + } + + return null; + } } diff --git a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart index e28578305ef69..f3830d0a09005 100644 --- a/packages/flutter_tools/test/general.shard/ios/simulators_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/simulators_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/process.dart'; +import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; @@ -771,14 +772,16 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''' late FakeProcessManager fakeProcessManager; Xcode xcode; late SimControl simControl; + late BufferLogger logger; const String deviceId = 'smart-phone'; const String appId = 'flutterApp'; setUp(() { fakeProcessManager = FakeProcessManager.empty(); xcode = Xcode.test(processManager: FakeProcessManager.any()); + logger = BufferLogger.test(); simControl = SimControl( - logger: BufferLogger.test(), + logger: logger, processManager: fakeProcessManager, xcode: xcode, ); @@ -931,6 +934,159 @@ Dec 20 17:04:32 md32-11-vm1 Another App[88374]: Ignore this text''' expect(await iosSimulator.stopApp(null), isFalse); }); + + testWithoutContext('listAvailableIOSRuntimes succeeds', () async { + const String validRuntimesOutput = ''' +{ + "runtimes" : [ + { + "bundlePath" : "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 15.4.simruntime", + "buildversion" : "19E240", + "platform" : "iOS", + "runtimeRoot" : "/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 15.4.simruntime/Contents/Resources/RuntimeRoot", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-15-4", + "version" : "15.4", + "isInternal" : false, + "isAvailable" : true, + "name" : "iOS 15.4", + "supportedDeviceTypes" : [ + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 6s.simdevicetype", + "name" : "iPhone 6s", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s", + "productFamily" : "iPhone" + }, + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 6s Plus.simdevicetype", + "name" : "iPhone 6s Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-6s-Plus", + "productFamily" : "iPhone" + } + ] + }, + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime", + "buildversion" : "20E247", + "platform" : "iOS", + "runtimeRoot" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-16-4", + "version" : "16.4", + "isInternal" : false, + "isAvailable" : true, + "name" : "iOS 16.4", + "supportedDeviceTypes" : [ + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 8.simdevicetype", + "name" : "iPhone 8", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8", + "productFamily" : "iPhone" + }, + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 8 Plus.simdevicetype", + "name" : "iPhone 8 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus", + "productFamily" : "iPhone" + } + ] + }, + { + "bundlePath" : "/Library/Developer/CoreSimulator/Volumes/iOS_21A5268h/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime", + "buildversion" : "21A5268h", + "platform" : "iOS", + "runtimeRoot" : "/Library/Developer/CoreSimulator/Volumes/iOS_21A5268h/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime/Contents/Resources/RuntimeRoot", + "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-17-0", + "version" : "17.0", + "isInternal" : false, + "isAvailable" : true, + "name" : "iOS 17.0", + "supportedDeviceTypes" : [ + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 8.simdevicetype", + "name" : "iPhone 8", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8", + "productFamily" : "iPhone" + }, + { + "bundlePath" : "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/DeviceTypes/iPhone 8 Plus.simdevicetype", + "name" : "iPhone 8 Plus", + "identifier" : "com.apple.CoreSimulator.SimDeviceType.iPhone-8-Plus", + "productFamily" : "iPhone" + } + ] + } + ] +} + +'''; + fakeProcessManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'simctl', + 'list', + 'runtimes', + 'available', + 'iOS', + '--json', + ], + stdout: validRuntimesOutput, + )); + + final List runtimes = await simControl.listAvailableIOSRuntimes(); + + final IOSSimulatorRuntime runtime1 = runtimes[0]; + expect(runtime1.bundlePath, '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 15.4.simruntime'); + expect(runtime1.buildVersion, '19E240'); + expect(runtime1.platform, 'iOS'); + expect(runtime1.runtimeRoot, '/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 15.4.simruntime/Contents/Resources/RuntimeRoot'); + expect(runtime1.identifier, 'com.apple.CoreSimulator.SimRuntime.iOS-15-4'); + expect(runtime1.version, Version(15, 4, null)); + expect(runtime1.isInternal, false); + expect(runtime1.isAvailable, true); + expect(runtime1.name, 'iOS 15.4'); + + final IOSSimulatorRuntime runtime2 = runtimes[1]; + expect(runtime2.bundlePath, '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime'); + expect(runtime2.buildVersion, '20E247'); + expect(runtime2.platform, 'iOS'); + expect(runtime2.runtimeRoot, '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot'); + expect(runtime2.identifier, 'com.apple.CoreSimulator.SimRuntime.iOS-16-4'); + expect(runtime2.version, Version(16, 4, null)); + expect(runtime2.isInternal, false); + expect(runtime2.isAvailable, true); + expect(runtime2.name, 'iOS 16.4'); + + final IOSSimulatorRuntime runtime3 = runtimes[2]; + expect(runtime3.bundlePath, '/Library/Developer/CoreSimulator/Volumes/iOS_21A5268h/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime'); + expect(runtime3.buildVersion, '21A5268h'); + expect(runtime3.platform, 'iOS'); + expect(runtime3.runtimeRoot, '/Library/Developer/CoreSimulator/Volumes/iOS_21A5268h/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime/Contents/Resources/RuntimeRoot'); + expect(runtime3.identifier, 'com.apple.CoreSimulator.SimRuntime.iOS-17-0'); + expect(runtime3.version, Version(17, 0, null)); + expect(runtime3.isInternal, false); + expect(runtime3.isAvailable, true); + expect(runtime3.name, 'iOS 17.0'); + }); + + testWithoutContext('listAvailableIOSRuntimes handles bad simctl output', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'simctl', + 'list', + 'runtimes', + 'available', + 'iOS', + '--json', + ], + stdout: 'Install Started', + )); + + final List runtimes = await simControl.listAvailableIOSRuntimes(); + + expect(runtimes, isEmpty); + expect(logger.errorText, contains('simctl returned non-JSON response:')); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); }); group('startApp', () { diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart index f2b2142090073..887712ad2e5c3 100644 --- a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart @@ -99,12 +99,15 @@ void main() { group('macOS', () { late Xcode xcode; + late BufferLogger logger; setUp(() { xcodeProjectInterpreter = FakeXcodeProjectInterpreter(); + logger = BufferLogger.test(); xcode = Xcode.test( processManager: fakeProcessManager, xcodeProjectInterpreter: xcodeProjectInterpreter, + logger: logger, ); }); @@ -277,6 +280,59 @@ void main() { expect(fakeProcessManager, hasNoRemainingExpectations); }); }); + + group('SDK Platform Version', () { + testWithoutContext('--show-sdk-platform-version iphonesimulator', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: '16.4', + )); + + expect(await xcode.sdkPlatformVersion(EnvironmentType.simulator), Version(16, 4, null)); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('--show-sdk-platform-version iphonesimulator with leading and trailing new line', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: '\n16.4\n', + )); + + expect(await xcode.sdkPlatformVersion(EnvironmentType.simulator), Version(16, 4, null)); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('--show-sdk-platform-version returns version followed by text', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: '13.2 (a) 12344', + )); + + expect(await xcode.sdkPlatformVersion(EnvironmentType.simulator), Version(13, 2, null, text: '13.2 (a) 12344')); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('--show-sdk-platform-version returns something unexpected', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: 'bogus', + )); + + expect(await xcode.sdkPlatformVersion(EnvironmentType.simulator), null); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('--show-sdk-platform-version fails', () async { + fakeProcessManager.addCommand(const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + exitCode: 1, + stderr: 'xcrun: error:', + )); + expect(await xcode.sdkPlatformVersion(EnvironmentType.simulator), null); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('Could not find SDK Platform Version')); + }); + }); }); }); diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart index bb6668e7ace64..70a454a57d3ab 100644 --- a/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/xcode_validator_test.dart @@ -5,9 +5,11 @@ import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; +import 'package:flutter_tools/src/ios/simulators.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/macos/xcode_validator.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/fake_process_manager.dart'; @@ -20,7 +22,11 @@ void main() { processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: null), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.missing); expect(result.statusInfo, isNull); @@ -39,7 +45,11 @@ void main() { processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: null), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.missing); expect(result.messages.last.type, ValidationMessageType.error); @@ -52,7 +62,11 @@ void main() { processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(7, 0, 1)), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.partial); expect(result.messages.last.type, ValidationMessageType.error); @@ -65,7 +79,11 @@ void main() { processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(12, 4, null)), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.partial); expect(result.messages.last.type, ValidationMessageType.hint); @@ -105,11 +123,16 @@ void main() { processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.partial); expect(result.messages.last.type, ValidationMessageType.error); expect(result.messages.last.message, contains('code end user license agreement not signed')); + expect(processManager, hasNoRemainingExpectations); }); testWithoutContext('Emits partial status when simctl is not installed', () async { @@ -143,11 +166,156 @@ void main() { processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.partial); expect(result.messages.last.type, ValidationMessageType.error); expect(result.messages.last.message, contains('Xcode requires additional components')); + expect(processManager, hasNoRemainingExpectations); + }); + + testWithoutContext('Emits partial status when unable to find simulator SDK', () async { + final ProcessManager processManager = FakeProcessManager.list([ + const FakeCommand( + command: ['/usr/bin/xcode-select', '--print-path'], + stdout: '/Library/Developer/CommandLineTools', + ), + const FakeCommand( + command: [ + 'which', + 'sysctl', + ], + ), + const FakeCommand( + command: [ + 'sysctl', + 'hw.optional.arm64', + ], + exitCode: 1, + ), + const FakeCommand( + command: ['xcrun', 'clang'], + ), + const FakeCommand( + command: ['xcrun', 'simctl', 'list', 'devices', 'booted'], + ), + const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + ), + ]); + final Xcode xcode = Xcode.test( + processManager: processManager, + xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager), + ); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); + final ValidationResult result = await validator.validate(); + expect(result.type, ValidationType.partial); + expect(result.messages.last.type, ValidationMessageType.error); + expect(result.messages.last.message, contains('Unable to find the iPhone Simulator SDK')); + expect(processManager, hasNoRemainingExpectations); + }); + + testWithoutContext('Emits partial status when unable to get simulator runtimes', () async { + final ProcessManager processManager = FakeProcessManager.list([ + const FakeCommand( + command: ['/usr/bin/xcode-select', '--print-path'], + stdout: '/Library/Developer/CommandLineTools', + ), + const FakeCommand( + command: [ + 'which', + 'sysctl', + ], + ), + const FakeCommand( + command: [ + 'sysctl', + 'hw.optional.arm64', + ], + exitCode: 1, + ), + const FakeCommand( + command: ['xcrun', 'clang'], + ), + const FakeCommand( + command: ['xcrun', 'simctl', 'list', 'devices', 'booted'], + ), + const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: '17.0' + ), + ]); + final Xcode xcode = Xcode.test( + processManager: processManager, + xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager), + ); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: FakeIOSSimulatorUtils(), + ); + final ValidationResult result = await validator.validate(); + expect(result.type, ValidationType.partial); + expect(result.messages.last.type, ValidationMessageType.error); + expect(result.messages.last.message, contains('Unable to get list of installed Simulator runtimes')); + expect(processManager, hasNoRemainingExpectations); + }); + + testWithoutContext('Emits partial status with hint when simulator runtimes do not match SDK', () async { + final ProcessManager processManager = FakeProcessManager.list([ + const FakeCommand( + command: ['/usr/bin/xcode-select', '--print-path'], + stdout: '/Library/Developer/CommandLineTools', + ), + const FakeCommand( + command: [ + 'which', + 'sysctl', + ], + ), + const FakeCommand( + command: [ + 'sysctl', + 'hw.optional.arm64', + ], + exitCode: 1, + ), + const FakeCommand( + command: ['xcrun', 'clang'], + ), + const FakeCommand( + command: ['xcrun', 'simctl', 'list', 'devices', 'booted'], + ), + const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: '17.0' + ), + ]); + final Xcode xcode = Xcode.test( + processManager: processManager, + xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager), + ); + final FakeIOSSimulatorUtils simulatorUtils = FakeIOSSimulatorUtils(runtimes: [ + IOSSimulatorRuntime.fromJson({'version': '16.0'}), + ]); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: simulatorUtils, + ); + final ValidationResult result = await validator.validate(); + expect(result.type, ValidationType.partial); + expect(result.messages.last.type, ValidationMessageType.hint); + expect(result.messages.last.message, contains('iOS 17.0 Simulator not installed')); + expect(processManager, hasNoRemainingExpectations); }); testWithoutContext('Succeeds when all checks pass', () async { @@ -175,12 +343,23 @@ void main() { const FakeCommand( command: ['xcrun', 'simctl', 'list', 'devices', 'booted'], ), + const FakeCommand( + command: ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-platform-version'], + stdout: '17.0' + ), ]); final Xcode xcode = Xcode.test( processManager: processManager, xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager), ); - final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); + final FakeIOSSimulatorUtils simulatorUtils = FakeIOSSimulatorUtils(runtimes: [ + IOSSimulatorRuntime.fromJson({'version': '17.0'}), + ]); + final XcodeValidator validator = XcodeValidator( + xcode: xcode, + userMessages: UserMessages(), + iosSimulatorUtils: simulatorUtils, + ); final ValidationResult result = await validator.validate(); expect(result.type, ValidationType.success); expect(result.messages.length, 2); @@ -189,6 +368,24 @@ void main() { expect(firstMessage.message, 'Xcode at /Library/Developer/CommandLineTools'); expect(result.statusInfo, '1000.0.0'); expect(result.messages[1].message, 'Build 13C100'); + expect(processManager, hasNoRemainingExpectations); }); }); } + +class FakeIOSSimulatorUtils extends Fake implements IOSSimulatorUtils { + FakeIOSSimulatorUtils({ + this.runtimes, + }); + + List? runtimes; + + List get _runtimesList { + return runtimes ?? []; + } + + @override + Future> getAvailableIOSRuntimes() async { + return _runtimesList; + } +} diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart index 0a70b2fd46799..7bea7532c3f5b 100644 --- a/packages/flutter_tools/test/src/context.dart +++ b/packages/flutter_tools/test/src/context.dart @@ -319,6 +319,9 @@ class NoopIOSSimulatorUtils implements IOSSimulatorUtils { @override Future> getAttachedDevices() async => []; + + @override + Future> getAvailableIOSRuntimes() async => []; } class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter { From 05f9a96ea4c521844a19b55fa3b51b8e19c03584 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 4 Aug 2023 20:38:07 +0300 Subject: [PATCH 0540/1547] Mention `showTimePicker` function be can be used to show dialog with the time picker in the `TimePickerDialog` docs (#131932) fixes https://github.com/flutter/flutter/issues/131931 Every time I search for the time picker in the API docs I end up in the `TimePickerDialog` docs. We should link `showTimePicker` so it can be easier to reach it and mention it can be used directly to show a dialog with a time picker. --- packages/flutter/lib/src/material/time_picker.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 7a4b526eb8ac4..d2d9e428fde3e 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2104,6 +2104,8 @@ typedef EntryModeChangeCallback = void Function(TimePickerEntryMode); /// selected [TimeOfDay] if the user taps the "OK" button, or null if the user /// taps the "CANCEL" button. The selected time is reported by calling /// [Navigator.pop]. +/// +/// Use [showTimePicker] to show a dialog already containing a [TimePickerDialog]. class TimePickerDialog extends StatefulWidget { /// Creates a Material Design time picker. /// @@ -3590,7 +3592,7 @@ class _TimePickerDefaultsM3 extends _TimePickerDefaults { @override TextStyle get hourMinuteTextStyle { return MaterialStateTextStyle.resolveWith((Set states) { - // TODO(tahatesser): Update this when https://github.com/flutter/flutter/issues/127035 is fixed. + // TODO(tahatesser): Update this when https://github.com/flutter/flutter/issues/131247 is fixed. // This is using the correct text style from Material 3 spec. // https://m3.material.io/components/time-pickers/specs#fd0b6939-edab-4058-82e1-93d163945215 return _textTheme.displayMedium!.copyWith(color: _hourMinuteTextColor.resolve(states)); From ceb70d1afbf7ab99e102b81d2116dab4876df87d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 14:34:55 -0400 Subject: [PATCH 0541/1547] Roll Flutter Engine from badca1f7f8c9 to e9f80bff0703 (6 revisions) (#131943) https://github.com/flutter/engine/compare/badca1f7f8c9...e9f80bff0703 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from c40343629a6b to 5eef2e2b94b4 (1 revision) (flutter/engine#44391) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 03874e298589 to c40343629a6b (4 revisions) (flutter/engine#44389) 2023-08-04 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from FAGt3OEY8Yi1-SaFj... to jMLeVECzwzDoe9dYS... (flutter/engine#44388) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 636077ca3a50 to 03874e298589 (1 revision) (flutter/engine#44386) 2023-08-04 vegorov@google.com Roll buildroot to a067408d923ccf80742571bb7a71705499f5779e (flutter/engine#44385) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 100bf3248bf0 to 636077ca3a50 (1 revision) (flutter/engine#44384) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from FAGt3OEY8Yi1 to jMLeVECzwzDo If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 235cfa17f7e96..988d134aadce4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -badca1f7f8c90f3b47ce149dde302a8f3d7ff3fb +e9f80bff070324f482ffea65b411b7fd423b9278 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 0a6d957dbc7e6..57b73e3ce3c1e 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -FAGt3OEY8Yi1-SaFjOXzB2-fTZowtLUMLTdxBoqLGhIC +jMLeVECzwzDoe9dYSKqrkHFMapXsDwwcFRAOp3FGf3sC From daf5827975b8b0235e58e442c0b8fc906ece5ea9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 15:30:28 -0400 Subject: [PATCH 0542/1547] Roll Flutter Engine from e9f80bff0703 to a7bea8621f4b (3 revisions) (#131948) https://github.com/flutter/engine/compare/e9f80bff0703...a7bea8621f4b 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 5eef2e2b94b4 to 85938bb68e75 (1 revision) (flutter/engine#44392) 2023-08-04 dnfield@google.com [Impeller] DlCanvas implementation wrapping Aiks canvas (flutter/engine#44248) 2023-08-04 30870216+gaaclarke@users.noreply.github.com [Impeller] Added a doc page to point out important impeller benchmarks (flutter/engine#44333) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 988d134aadce4..55583b601dd27 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e9f80bff070324f482ffea65b411b7fd423b9278 +a7bea8621f4b05e758ea4d3616031f77b6863eed From dedd100ebdf0497af94d423beb9e4fc7be5e34ec Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Fri, 4 Aug 2023 13:44:44 -0700 Subject: [PATCH 0543/1547] Predictive back support for root routes (#120385) This PR aims to support Android's predictive back gesture when popping the entire Flutter app. Predictive route transitions between routes inside of a Flutter app will come later. ### Trying it out If you want to try this feature yourself, here are the necessary steps: 1. Run Android 33 or above. 1. Enable the feature flag for predictive back on the device under "Developer options". 1. Create a Flutter project, or clone [my example project](https://github.com/justinmc/flutter_predictive_back_examples). 1. Set `android:enableOnBackInvokedCallback="true"` in android/app/src/main/AndroidManifest.xml (already done in the example project). 1. Check out this branch. 1. Run the app. Perform a back gesture (swipe from the left side of the screen). You should see the predictive back animation like in the animation above and be able to commit or cancel it. ### go_router support go_router works with predictive back out of the box because it uses a Navigator internally that dispatches NavigationNotifications! ~~go_router can be supported by adding a listener to the router and updating SystemNavigator.setFrameworkHandlesBack.~~ Similar to with nested Navigators, nested go_routers is supported by using a PopScope widget.
Full example of nested go_routers ```dart // Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:go_router/go_router.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; void main() => runApp(_MyApp()); class _MyApp extends StatelessWidget { final GoRouter router = GoRouter( routes: [ GoRoute( path: '/', builder: (BuildContext context, GoRouterState state) => _HomePage(), ), GoRoute( path: '/nested_navigators', builder: (BuildContext context, GoRouterState state) => _NestedGoRoutersPage(), ), ], ); @override Widget build(BuildContext context) { return MaterialApp.router( routerConfig: router, ); } } class _HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Nested Navigators Example'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('Home Page'), const Text('A system back gesture here will exit the app.'), const SizedBox(height: 20.0), ListTile( title: const Text('Nested go_router route'), subtitle: const Text('This route has another go_router in addition to the one used with MaterialApp above.'), onTap: () { context.push('/nested_navigators'); }, ), ], ), ), ); } } class _NestedGoRoutersPage extends StatefulWidget { @override State<_NestedGoRoutersPage> createState() => _NestedGoRoutersPageState(); } class _NestedGoRoutersPageState extends State<_NestedGoRoutersPage> { late final GoRouter _router; final GlobalKey _nestedNavigatorKey = GlobalKey(); // If the nested navigator has routes that can be popped, then we want to // block the root navigator from handling the pop so that the nested navigator // can handle it instead. bool get _popEnabled { // canPop will throw an error if called before build. Is this the best way // to avoid that? return _nestedNavigatorKey.currentState == null ? true : !_router.canPop(); } void _onRouterChanged() { // Here the _router reports the location correctly, but canPop is still out // of date. Hence the post frame callback. SchedulerBinding.instance.addPostFrameCallback((Duration duration) { setState(() {}); }); } @override void initState() { super.initState(); final BuildContext rootContext = context; _router = GoRouter( navigatorKey: _nestedNavigatorKey, routes: [ GoRoute( path: '/', builder: (BuildContext context, GoRouterState state) => _LinksPage( title: 'Nested once - home route', backgroundColor: Colors.indigo, onBack: () { rootContext.pop(); }, buttons: [ TextButton( onPressed: () { context.push('/two'); }, child: const Text('Go to another route in this nested Navigator'), ), ], ), ), GoRoute( path: '/two', builder: (BuildContext context, GoRouterState state) => _LinksPage( backgroundColor: Colors.indigo.withBlue(255), title: 'Nested once - page two', ), ), ], ); _router.addListener(_onRouterChanged); } @override void dispose() { _router.removeListener(_onRouterChanged); super.dispose(); } @override Widget build(BuildContext context) { return PopScope( popEnabled: _popEnabled, onPopped: (bool success) { if (success) { return; } _router.pop(); }, child: Router.withConfig( restorationScopeId: 'router-2', config: _router, ), ); } } class _LinksPage extends StatelessWidget { const _LinksPage ({ required this.backgroundColor, this.buttons = const [], this.onBack, required this.title, }); final Color backgroundColor; final List buttons; final VoidCallback? onBack; final String title; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: backgroundColor, body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(title), //const Text('A system back here will go back to Nested Navigators Page One'), ...buttons, TextButton( onPressed: onBack ?? () { context.pop(); }, child: const Text('Go back'), ), ], ), ), ); } } ``` ### Resources Fixes https://github.com/flutter/flutter/issues/109513 Depends on engine PR https://github.com/flutter/engine/pull/39208 :heavy_check_mark: Design doc: https://docs.google.com/document/d/1BGCWy1_LRrXEB6qeqTAKlk-U2CZlKJ5xI97g45U7azk/edit# Migration guide: https://github.com/flutter/website/pull/8952 --- .../cupertino/cupertino_navigation_demo.dart | 4 +- .../material/full_screen_dialog_demo.dart | 31 +- .../demo/material/text_form_field_demo.dart | 19 +- .../demo/shrine/expanding_bottom_sheet.dart | 14 +- .../flutter_gallery/lib/gallery/home.dart | 14 +- .../navigation_bar/navigation_bar.2.dart | 8 +- examples/api/lib/widgets/form/form.1.dart | 166 ++++ .../navigator_pop_handler.0.dart | 164 ++++ .../navigator_pop_handler.1.dart | 250 +++++ .../lib/widgets/pop_scope/pop_scope.0.dart | 128 +++ .../will_pop_scope/will_pop_scope.0.dart | 77 -- .../api/test/widgets/form/form.1_test.dart | 37 + .../navigator_pop_handler.0_test.dart | 48 + .../navigator_pop_handler.1_test.dart | 38 + .../api/test/widgets/navigator_utils.dart | 20 + .../widgets/pop_scope/pop_scope.0_test.dart | 66 ++ .../will_pop_scope/will_pop_scope.0_test.dart | 32 - packages/flutter/lib/src/cupertino/app.dart | 6 + packages/flutter/lib/src/cupertino/route.dart | 3 +- .../flutter/lib/src/cupertino/tab_view.dart | 28 +- packages/flutter/lib/src/material/about.dart | 13 +- packages/flutter/lib/src/material/app.dart | 6 + .../lib/src/services/system_navigator.dart | 34 + packages/flutter/lib/src/widgets/app.dart | 80 +- packages/flutter/lib/src/widgets/binding.dart | 28 +- packages/flutter/lib/src/widgets/form.dart | 59 +- .../flutter/lib/src/widgets/navigator.dart | 309 ++++++- .../src/widgets/navigator_pop_handler.dart | 110 +++ .../flutter/lib/src/widgets/pop_scope.dart | 137 +++ packages/flutter/lib/src/widgets/routes.dart | 217 +++-- .../lib/src/widgets/will_pop_scope.dart | 17 +- packages/flutter/lib/widgets.dart | 2 + .../test/cupertino/tab_scaffold_test.dart | 131 ++- .../flutter/test/widgets/navigator_test.dart | 866 ++++++++++++++++++ .../flutter/test/widgets/navigator_utils.dart | 20 + .../flutter/test/widgets/pop_scope_test.dart | 361 ++++++++ 36 files changed, 3241 insertions(+), 302 deletions(-) create mode 100644 examples/api/lib/widgets/form/form.1.dart create mode 100644 examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart create mode 100644 examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart create mode 100644 examples/api/lib/widgets/pop_scope/pop_scope.0.dart delete mode 100644 examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart create mode 100644 examples/api/test/widgets/form/form.1_test.dart create mode 100644 examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart create mode 100644 examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart create mode 100644 examples/api/test/widgets/navigator_utils.dart create mode 100644 examples/api/test/widgets/pop_scope/pop_scope.0_test.dart delete mode 100644 examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart create mode 100644 packages/flutter/lib/src/widgets/navigator_pop_handler.dart create mode 100644 packages/flutter/lib/src/widgets/pop_scope.dart create mode 100644 packages/flutter/test/widgets/navigator_utils.dart create mode 100644 packages/flutter/test/widgets/pop_scope_test.dart diff --git a/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart index f6626b85e20dd..a68c2a194c9b7 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart @@ -48,9 +48,9 @@ class CupertinoNavigationDemo extends StatelessWidget { @override Widget build(BuildContext context) { - return WillPopScope( + return PopScope( // Prevent swipe popping of this page. Use explicit exit buttons only. - onWillPop: () => Future.value(true), + canPop: false, child: DefaultTextStyle( style: CupertinoTheme.of(context).textTheme.textStyle, child: CupertinoTabScaffold( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart index b6f7bbe6b6afb..81ee4dacd8643 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; // This demo is based on @@ -109,16 +110,15 @@ class FullScreenDialogDemoState extends State { bool _hasName = false; late String _eventName; - Future _onWillPop() async { - _saveNeeded = _hasLocation || _hasName || _saveNeeded; - if (!_saveNeeded) { - return true; + Future _handlePopInvoked(bool didPop) async { + if (didPop) { + return; } final ThemeData theme = Theme.of(context); final TextStyle dialogTextStyle = theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); - return showDialog( + final bool? shouldDiscard = await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( @@ -130,19 +130,31 @@ class FullScreenDialogDemoState extends State { TextButton( child: const Text('CANCEL'), onPressed: () { - Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page. + // Pop the confirmation dialog and indicate that the page should + // not be popped. + Navigator.of(context).pop(false); }, ), TextButton( child: const Text('DISCARD'), onPressed: () { - Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again. + // Pop the confirmation dialog and indicate that the page should + // be popped, too. + Navigator.of(context).pop(true); }, ), ], ); }, - ) as Future; + ); + + if (shouldDiscard ?? false) { + // Since this is the root route, quit the app where possible by invoking + // the SystemNavigator. If this wasn't the root route, then + // Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + } } @override @@ -162,7 +174,8 @@ class FullScreenDialogDemoState extends State { ], ), body: Form( - onWillPop: _onWillPop, + canPop: !_saveNeeded && !_hasLocation && !_hasName, + onPopInvoked: _handlePopInvoked, child: Scrollbar( child: ListView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart index 5d3fee8d60f0c..c6f644ee74cd3 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart @@ -143,10 +143,9 @@ class TextFormFieldDemoState extends State { return null; } - Future _warnUserAboutInvalidData() async { - final FormState? form = _formKey.currentState; - if (form == null || !_formWasEdited || form.validate()) { - return true; + Future _handlePopInvoked(bool didPop) async { + if (didPop) { + return; } final bool? result = await showDialog( @@ -168,7 +167,14 @@ class TextFormFieldDemoState extends State { ); }, ); - return result!; + + if (result ?? false) { + // Since this is the root route, quit the app where possible by invoking + // the SystemNavigator. If this wasn't the root route, then + // Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + } } @override @@ -185,7 +191,8 @@ class TextFormFieldDemoState extends State { child: Form( key: _formKey, autovalidateMode: _autovalidateMode, - onWillPop: _warnUserAboutInvalidData, + canPop: _formKey.currentState == null || !_formWasEdited || _formKey.currentState!.validate(), + onPopInvoked: _handlePopInvoked, child: Scrollbar( child: SingleChildScrollView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart index 0391ef95bee47..de2cfa43ef714 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:scoped_model/scoped_model.dart'; import 'colors.dart'; @@ -361,14 +360,12 @@ class ExpandingBottomSheetState extends State with TickerP // Closes the cart if the cart is open, otherwise exits the app (this should // only be relevant for Android). - Future _onWillPop() async { - if (!_isOpen) { - await SystemNavigator.pop(); - return true; + void _handlePopInvoked(bool didPop) { + if (didPop) { + return; } close(); - return true; } @override @@ -378,8 +375,9 @@ class ExpandingBottomSheetState extends State with TickerP duration: const Duration(milliseconds: 225), curve: Curves.easeInOut, alignment: FractionalOffset.topLeft, - child: WillPopScope( - onWillPop: _onWillPop, + child: PopScope( + canPop: !_isOpen, + onPopInvoked: _handlePopInvoked, child: AnimatedBuilder( animation: widget.hideController, builder: _buildSlideAnimation, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart index c661ce64486cd..4a5f01fede8de 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart @@ -325,14 +325,14 @@ class _GalleryHomeState extends State with SingleTickerProviderStat backgroundColor: isDark ? _kFlutterBlue : theme.primaryColor, body: SafeArea( bottom: false, - child: WillPopScope( - onWillPop: () { - // Pop the category page if Android back button is pressed. - if (_category != null) { - setState(() => _category = null); - return Future.value(false); + child: PopScope( + canPop: _category == null, + onPopInvoked: (bool didPop) { + if (didPop) { + return; } - return Future.value(true); + // Pop the category page if Android back button is pressed. + setState(() => _category = null); }, child: Backdrop( backTitle: const Text('Options'), diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart index 7af02cfe00708..981eb5d81216a 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart @@ -71,14 +71,10 @@ class _HomeState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { + return NavigatorPopHandler( + onPop: () { final NavigatorState navigator = navigatorKeys[selectedIndex].currentState!; - if (!navigator.canPop()) { - return true; - } navigator.pop(); - return false; }, child: Scaffold( body: SafeArea( diff --git a/examples/api/lib/widgets/form/form.1.dart b/examples/api/lib/widgets/form/form.1.dart new file mode 100644 index 0000000000000..b5e8b6e09ca1f --- /dev/null +++ b/examples/api/lib/widgets/form/form.1.dart @@ -0,0 +1,166 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +/// This sample demonstrates showing a confirmation dialog when the user +/// attempts to navigate away from a page with unsaved [Form] data. + +void main() => runApp(const FormApp()); + +class FormApp extends StatelessWidget { + const FormApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Confirmation Dialog Example'), + ), + body: Center( + child: _SaveableForm(), + ), + ), + ); + } +} + +class _SaveableForm extends StatefulWidget { + @override + State<_SaveableForm> createState() => _SaveableFormState(); +} + +class _SaveableFormState extends State<_SaveableForm> { + final TextEditingController _controller = TextEditingController(); + String _savedValue = ''; + bool _isDirty = false; + + @override + void initState() { + super.initState(); + _controller.addListener(_onChanged); + } + + @override + void dispose() { + _controller.removeListener(_onChanged); + super.dispose(); + } + + void _onChanged() { + final bool nextIsDirty = _savedValue != _controller.text; + if (nextIsDirty == _isDirty) { + return; + } + setState(() { + _isDirty = nextIsDirty; + }); + } + + Future _showDialog() async { + final bool? shouldDiscard = await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Are you sure?'), + content: const Text('Any unsaved changes will be lost!'), + actions: [ + TextButton( + child: const Text('Yes, discard my changes'), + onPressed: () { + Navigator.pop(context, true); + }, + ), + TextButton( + child: const Text('No, continue editing'), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ], + ); + }, + ); + + if (shouldDiscard ?? false) { + // Since this is the root route, quit the app where possible by invoking + // the SystemNavigator. If this wasn't the root route, then + // Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + } + } + + void _save(String? value) { + setState(() { + _savedValue = value ?? ''; + }); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('If the field below is unsaved, a confirmation dialog will be shown on back.'), + const SizedBox(height: 20.0), + Form( + canPop: !_isDirty, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + _showDialog(); + }, + autovalidateMode: AutovalidateMode.always, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFormField( + controller: _controller, + onFieldSubmitted: (String? value) { + _save(value); + }, + ), + TextButton( + onPressed: () { + _save(_controller.text); + }, + child: Row( + children: [ + const Text('Save'), + if (_controller.text.isNotEmpty) + Icon( + _isDirty ? Icons.warning : Icons.check, + ), + ], + ), + ), + ], + ), + ), + TextButton( + onPressed: () { + if (_isDirty) { + _showDialog(); + return; + } + // Since this is the root route, quit the app where possible by + // invoking the SystemNavigator. If this wasn't the root route, + // then Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + }, + child: const Text('Go back'), + ), + ], + ), + ); + } +} diff --git a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart new file mode 100644 index 0000000000000..d81b74f65f714 --- /dev/null +++ b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart @@ -0,0 +1,164 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// This sample demonstrates using [NavigatorPopHandler] to handle system back +/// gestures when there are nested [Navigator] widgets by delegating to the +/// current [Navigator]. + +void main() => runApp(const NavigatorPopHandlerApp()); + +class NavigatorPopHandlerApp extends StatelessWidget { + const NavigatorPopHandlerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _HomePage(), + '/nested_navigators': (BuildContext context) => const NestedNavigatorsPage(), + }, + ); + } +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Nested Navigators Example'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Home Page'), + const Text('A system back gesture here will exit the app.'), + const SizedBox(height: 20.0), + ListTile( + title: const Text('Nested Navigator route'), + subtitle: const Text('This route has another Navigator widget in addition to the one inside MaterialApp above.'), + onTap: () { + Navigator.of(context).pushNamed('/nested_navigators'); + }, + ), + ], + ), + ), + ); + } +} + +class NestedNavigatorsPage extends StatefulWidget { + const NestedNavigatorsPage({super.key}); + + @override + State createState() => _NestedNavigatorsPageState(); +} + +class _NestedNavigatorsPageState extends State { + final GlobalKey _nestedNavigatorKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return NavigatorPopHandler( + onPop: () { + _nestedNavigatorKey.currentState!.maybePop(); + }, + child: Navigator( + key: _nestedNavigatorKey, + initialRoute: 'nested_navigators/one', + onGenerateRoute: (RouteSettings settings) { + switch (settings.name) { + case 'nested_navigators/one': + final BuildContext rootContext = context; + return MaterialPageRoute( + builder: (BuildContext context) => NestedNavigatorsPageOne( + onBack: () { + Navigator.of(rootContext).pop(); + }, + ), + ); + case 'nested_navigators/one/another_one': + return MaterialPageRoute( + builder: (BuildContext context) => const NestedNavigatorsPageTwo( + ), + ); + default: + throw Exception('Invalid route: ${settings.name}'); + } + }, + ), + ); + } +} + +class NestedNavigatorsPageOne extends StatelessWidget { + const NestedNavigatorsPageOne({ + required this.onBack, + super.key, + }); + + final VoidCallback onBack; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Nested Navigators Page One'), + const Text('A system back here returns to the home page.'), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('nested_navigators/one/another_one'); + }, + child: const Text('Go to another route in this nested Navigator'), + ), + TextButton( + // Can't use Navigator.of(context).pop() because this is the root + // route, so it can't be popped. The Navigator above this needs to + // be popped. + onPressed: onBack, + child: const Text('Go back'), + ), + ], + ), + ), + ); + } +} + +class NestedNavigatorsPageTwo extends StatelessWidget { + const NestedNavigatorsPageTwo({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey.withBlue(180), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Nested Navigators Page Two'), + const Text('A system back here will go back to Nested Navigators Page One'), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Go back'), + ), + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart new file mode 100644 index 0000000000000..04fbdedd34e56 --- /dev/null +++ b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart @@ -0,0 +1,250 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This sample demonstrates nested navigation in a bottom navigation bar. + +import 'package:flutter/material.dart'; + +// There are three possible tabs. +enum _Tab { + home, + one, + two, +} + +// Each tab has two possible pages. +enum _TabPage { + home, + one, +} + +typedef _TabPageCallback = void Function(List<_TabPage> pages); + +void main() => runApp(const NavigatorPopHandlerApp()); + +class NavigatorPopHandlerApp extends StatelessWidget { + const NavigatorPopHandlerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + initialRoute: '/home', + routes: { + '/home': (BuildContext context) => const _BottomNavPage( + ), + }, + ); + } +} + +class _BottomNavPage extends StatefulWidget { + const _BottomNavPage(); + + @override + State<_BottomNavPage> createState() => _BottomNavPageState(); +} + +class _BottomNavPageState extends State<_BottomNavPage> { + _Tab _tab = _Tab.home; + + final GlobalKey _tabHomeKey = GlobalKey(); + final GlobalKey _tabOneKey = GlobalKey(); + final GlobalKey _tabTwoKey = GlobalKey(); + + List<_TabPage> _tabHomePages = <_TabPage>[_TabPage.home]; + List<_TabPage> _tabOnePages = <_TabPage>[_TabPage.home]; + List<_TabPage> _tabTwoPages = <_TabPage>[_TabPage.home]; + + BottomNavigationBarItem _itemForPage(_Tab page) { + switch (page) { + case _Tab.home: + return const BottomNavigationBarItem( + icon: Icon(Icons.home), + label: 'Go to Home', + ); + case _Tab.one: + return const BottomNavigationBarItem( + icon: Icon(Icons.one_k), + label: 'Go to One', + ); + case _Tab.two: + return const BottomNavigationBarItem( + icon: Icon(Icons.two_k), + label: 'Go to Two', + ); + } + } + + Widget _getPage(_Tab page) { + switch (page) { + case _Tab.home: + return _BottomNavTab( + key: _tabHomeKey, + title: 'Home Tab', + color: Colors.grey, + pages: _tabHomePages, + onChangedPages: (List<_TabPage> pages) { + setState(() { + _tabHomePages = pages; + }); + }, + ); + case _Tab.one: + return _BottomNavTab( + key: _tabOneKey, + title: 'Tab One', + color: Colors.amber, + pages: _tabOnePages, + onChangedPages: (List<_TabPage> pages) { + setState(() { + _tabOnePages = pages; + }); + }, + ); + case _Tab.two: + return _BottomNavTab( + key: _tabTwoKey, + title: 'Tab Two', + color: Colors.blueGrey, + pages: _tabTwoPages, + onChangedPages: (List<_TabPage> pages) { + setState(() { + _tabTwoPages = pages; + }); + }, + ); + } + } + + void _onItemTapped(int index) { + setState(() { + _tab = _Tab.values.elementAt(index); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: _getPage(_tab), + ), + bottomNavigationBar: BottomNavigationBar( + items: _Tab.values.map(_itemForPage).toList(), + currentIndex: _Tab.values.indexOf(_tab), + selectedItemColor: Colors.amber[800], + onTap: _onItemTapped, + ), + ); + } +} + +class _BottomNavTab extends StatefulWidget { + const _BottomNavTab({ + super.key, + required this.color, + required this.onChangedPages, + required this.pages, + required this.title, + }); + + final Color color; + final _TabPageCallback onChangedPages; + final List<_TabPage> pages; + final String title; + + @override + State<_BottomNavTab> createState() => _BottomNavTabState(); +} + +class _BottomNavTabState extends State<_BottomNavTab> { + final GlobalKey _navigatorKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return NavigatorPopHandler( + onPop: () { + _navigatorKey.currentState?.maybePop(); + }, + child: Navigator( + key: _navigatorKey, + onPopPage: (Route route, void result) { + if (!route.didPop(null)) { + return false; + } + widget.onChangedPages(<_TabPage>[ + ...widget.pages, + ]..removeLast()); + return true; + }, + pages: widget.pages.map((_TabPage page) { + switch (page) { + case _TabPage.home: + return MaterialPage( + child: _LinksPage( + title: 'Bottom nav - tab ${widget.title} - route $page', + backgroundColor: widget.color, + buttons: [ + TextButton( + onPressed: () { + widget.onChangedPages(<_TabPage>[ + ...widget.pages, + _TabPage.one, + ]); + }, + child: const Text('Go to another route in this nested Navigator'), + ), + ], + ), + ); + case _TabPage.one: + return MaterialPage( + child: _LinksPage( + backgroundColor: widget.color, + title: 'Bottom nav - tab ${widget.title} - route $page', + buttons: [ + TextButton( + onPressed: () { + widget.onChangedPages(<_TabPage>[ + ...widget.pages, + ]..removeLast()); + }, + child: const Text('Go back'), + ), + ], + ), + ); + } + }).toList(), + ), + ); + } +} + +class _LinksPage extends StatelessWidget { + const _LinksPage ({ + required this.backgroundColor, + this.buttons = const [], + required this.title, + }); + + final Color backgroundColor; + final List buttons; + final String title; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: backgroundColor, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(title), + ...buttons, + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/pop_scope/pop_scope.0.dart b/examples/api/lib/widgets/pop_scope/pop_scope.0.dart new file mode 100644 index 0000000000000..6d144bd088de1 --- /dev/null +++ b/examples/api/lib/widgets/pop_scope/pop_scope.0.dart @@ -0,0 +1,128 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This sample demonstrates showing a confirmation dialog before navigating +// away from a page. + +import 'package:flutter/material.dart'; + +void main() => runApp(const NavigatorPopHandlerApp()); + +class NavigatorPopHandlerApp extends StatelessWidget { + const NavigatorPopHandlerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + initialRoute: '/home', + routes: { + '/home': (BuildContext context) => const _HomePage(), + '/two': (BuildContext context) => const _PageTwo(), + }, + ); + } +} + +class _HomePage extends StatefulWidget { + const _HomePage(); + + @override + State<_HomePage> createState() => _HomePageState(); +} + +class _HomePageState extends State<_HomePage> { + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Page One'), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/two'); + }, + child: const Text('Next page'), + ), + ], + ), + ), + ); + } +} + +class _PageTwo extends StatefulWidget { + const _PageTwo(); + + @override + State<_PageTwo> createState() => _PageTwoState(); +} + +class _PageTwoState extends State<_PageTwo> { + void _showBackDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Are you sure?'), + content: const Text( + 'Are you sure you want to leave this page?', + ), + actions: [ + TextButton( + style: TextButton.styleFrom( + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: const Text('Nevermind'), + onPressed: () { + Navigator.pop(context); + }, + ), + TextButton( + style: TextButton.styleFrom( + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: const Text('Leave'), + onPressed: () { + Navigator.pop(context); + Navigator.pop(context); + }, + ), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Page Two'), + PopScope( + canPop: false, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + _showBackDialog(); + }, + child: TextButton( + onPressed: () { + _showBackDialog(); + }, + child: const Text('Go back'), + ), + ), + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart b/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart deleted file mode 100644 index 46dafa57b98ce..0000000000000 --- a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -/// Flutter code sample for [WillPopScope]. - -void main() => runApp(const WillPopScopeExampleApp()); - -class WillPopScopeExampleApp extends StatelessWidget { - const WillPopScopeExampleApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: WillPopScopeExample(), - ); - } -} - -class WillPopScopeExample extends StatefulWidget { - const WillPopScopeExample({super.key}); - - @override - State createState() => _WillPopScopeExampleState(); -} - -class _WillPopScopeExampleState extends State { - bool shouldPop = true; - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - return shouldPop; - }, - child: Scaffold( - appBar: AppBar( - title: const Text('Flutter WillPopScope demo'), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - OutlinedButton( - child: const Text('Push'), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return const WillPopScopeExample(); - }, - ), - ); - }, - ), - OutlinedButton( - child: Text('shouldPop: $shouldPop'), - onPressed: () { - setState( - () { - shouldPop = !shouldPop; - }, - ); - }, - ), - const Text('Push to a new screen, then tap on shouldPop ' - 'button to toggle its value. Press the back ' - 'button in the appBar to check its behavior ' - 'for different values of shouldPop'), - ], - ), - ), - ), - ); - } -} diff --git a/examples/api/test/widgets/form/form.1_test.dart b/examples/api/test/widgets/form/form.1_test.dart new file mode 100644 index 0000000000000..f9ccd71d521e8 --- /dev/null +++ b/examples/api/test/widgets/form/form.1_test.dart @@ -0,0 +1,37 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/form/form.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Can go back when form is clean', (WidgetTester tester) async { + await tester.pumpWidget( + const example.FormApp(), + ); + + expect(find.text('Are you sure?'), findsNothing); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Are you sure?'), findsNothing); + }); + + testWidgets('Cannot go back when form is dirty', (WidgetTester tester) async { + await tester.pumpWidget( + const example.FormApp(), + ); + + expect(find.text('Are you sure?'), findsNothing); + + await tester.enterText(find.byType(TextFormField), 'some new text'); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Are you sure?'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart new file mode 100644 index 0000000000000..88f29223f60a4 --- /dev/null +++ b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart @@ -0,0 +1,48 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/navigator_pop_handler/navigator_pop_handler.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +import '../navigator_utils.dart'; + +void main() { + testWidgets('Can go back with system back gesture', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Nested Navigators Example'), findsOneWidget); + expect(find.text('Nested Navigators Page One'), findsNothing); + expect(find.text('Nested Navigators Page Two'), findsNothing); + + await tester.tap(find.text('Nested Navigator route')); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsNothing); + expect(find.text('Nested Navigators Page One'), findsOneWidget); + expect(find.text('Nested Navigators Page Two'), findsNothing); + + await tester.tap(find.text('Go to another route in this nested Navigator')); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsNothing); + expect(find.text('Nested Navigators Page One'), findsNothing); + expect(find.text('Nested Navigators Page Two'), findsOneWidget); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsNothing); + expect(find.text('Nested Navigators Page One'), findsOneWidget); + expect(find.text('Nested Navigators Page Two'), findsNothing); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsOneWidget); + expect(find.text('Nested Navigators Page One'), findsNothing); + expect(find.text('Nested Navigators Page Two'), findsNothing); + }); +} diff --git a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart new file mode 100644 index 0000000000000..a6ea0ac82806f --- /dev/null +++ b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart @@ -0,0 +1,38 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/navigator_pop_handler/navigator_pop_handler.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +import '../navigator_utils.dart'; + +void main() { + testWidgets("System back gesture operates on current tab's nested Navigator", (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.home'), findsOneWidget); + + // Go to the next route in this tab. + await tester.tap(find.text('Go to another route in this nested Navigator')); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.one'), findsOneWidget); + + // Go to another tab. + await tester.tap(find.text('Go to One')); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Tab One - route _TabPage.home'), findsOneWidget); + + // Return to the home tab. The navigation state is preserved. + await tester.tap(find.text('Go to Home')); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.one'), findsOneWidget); + + // A back pops the navigation stack of the current tab's nested Navigator. + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.home'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/navigator_utils.dart b/examples/api/test/widgets/navigator_utils.dart new file mode 100644 index 0000000000000..46f1f9b1ac469 --- /dev/null +++ b/examples/api/test/widgets/navigator_utils.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Simulates a system back, like a back gesture on Android. +/// +/// Sends the same platform channel message that the engine sends when it +/// receives a system back. +Future simulateSystemBack() { + return TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + 'flutter/navigation', + const JSONMessageCodec().encodeMessage({ + 'method': 'popRoute', + }), + (ByteData? _) {}, + ); +} diff --git a/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart b/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart new file mode 100644 index 0000000000000..ac334fc3222f2 --- /dev/null +++ b/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart @@ -0,0 +1,66 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/pop_scope/pop_scope.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +import '../navigator_utils.dart'; + +void main() { + testWidgets('Can choose to stay on page', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Page One'), findsOneWidget); + expect(find.text('Page Two'), findsNothing); + expect(find.text('Are you sure?'), findsNothing); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsNothing); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsOneWidget); + + await tester.tap(find.text('Nevermind')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsNothing); + }); + + testWidgets('Can choose to go back', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Page One'), findsOneWidget); + expect(find.text('Page Two'), findsNothing); + expect(find.text('Are you sure?'), findsNothing); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsNothing); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsOneWidget); + + await tester.tap(find.text('Leave')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsOneWidget); + expect(find.text('Page Two'), findsNothing); + expect(find.text('Are you sure?'), findsNothing); + }); +} diff --git a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart b/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart deleted file mode 100644 index ad05943108708..0000000000000 --- a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter_api_samples/widgets/will_pop_scope/will_pop_scope.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('pressing shouldPop button changes shouldPop', (WidgetTester tester) async { - await tester.pumpWidget( - const example.WillPopScopeExampleApp(), - ); - - final Finder buttonFinder = find.text('shouldPop: true'); - expect(buttonFinder, findsOneWidget); - await tester.tap(buttonFinder); - await tester.pump(); - expect(find.text('shouldPop: false'), findsOneWidget); - }); - testWidgets('pressing Push button pushes route', (WidgetTester tester) async { - await tester.pumpWidget( - const example.WillPopScopeExampleApp(), - ); - - final Finder buttonFinder = find.text('Push'); - expect(buttonFinder, findsOneWidget); - expect(find.byType(example.WillPopScopeExample), findsOneWidget); - await tester.tap(buttonFinder); - await tester.pumpAndSettle(); - expect(find.byType(example.WillPopScopeExample, skipOffstage: false), findsNWidgets(2)); - }); -} diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index 47e45b198b0b9..6501b9cee30c5 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -157,6 +157,7 @@ class CupertinoApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, + this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, List this.navigatorObservers = const [], this.builder, this.title = '', @@ -202,6 +203,7 @@ class CupertinoApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, + this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, this.color, this.locale, this.localizationsDelegates, @@ -268,6 +270,9 @@ class CupertinoApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} final RouteFactory? onUnknownRoute; + /// {@macro flutter.widgets.widgetsApp.onNavigationNotification} + final NotificationListenerCallback? onNavigationNotification; + /// {@macro flutter.widgets.widgetsApp.navigatorObservers} final List? navigatorObservers; @@ -573,6 +578,7 @@ class _CupertinoAppState extends State { onGenerateRoute: widget.onGenerateRoute, onGenerateInitialRoutes: widget.onGenerateInitialRoutes, onUnknownRoute: widget.onUnknownRoute, + onNavigationNotification: widget.onNavigationNotification, builder: widget.builder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index f922eaf33e946..211578214871d 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -196,7 +196,8 @@ mixin CupertinoRouteTransitionMixin on PageRoute { } // If attempts to dismiss this route might be vetoed such as in a page // with forms, then do not allow the user to dismiss the route with a swipe. - if (route.hasScopedWillPopCallback) { + if (route.hasScopedWillPopCallback + || route.popDisposition == RoutePopDisposition.doNotPop) { return false; } // Fullscreen dialogs aren't dismissible by back swipe. diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart index 8728196eee9b8..f41d0a4a3175d 100644 --- a/packages/flutter/lib/src/cupertino/tab_view.dart +++ b/packages/flutter/lib/src/cupertino/tab_view.dart @@ -162,15 +162,39 @@ class _CupertinoTabViewState extends State { ..add(_heroController); } + GlobalKey? _ownedNavigatorKey; + GlobalKey get _navigatorKey { + if (widget.navigatorKey != null) { + return widget.navigatorKey!; + } + _ownedNavigatorKey ??= GlobalKey(); + return _ownedNavigatorKey!; + } + + // Whether this tab is currently the active tab. + bool get _isActive => TickerMode.of(context); + @override Widget build(BuildContext context) { - return Navigator( - key: widget.navigatorKey, + final Widget child = Navigator( + key: _navigatorKey, onGenerateRoute: _onGenerateRoute, onUnknownRoute: _onUnknownRoute, observers: _navigatorObservers, restorationScopeId: widget.restorationScopeId, ); + + // Handle system back gestures only if the tab is currently active. + return NavigatorPopHandler( + enabled: _isActive, + onPop: () { + if (!_isActive) { + return; + } + _navigatorKey.currentState!.pop(); + }, + child: child, + ); } Route? _onGenerateRoute(RouteSettings settings) { diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 44d4e7b1cf4f8..76462c8c6033f 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -1179,9 +1179,10 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp _builtLayout = _LayoutMode.nested; final MaterialPageRoute masterPageRoute = _masterPageRoute(context); - return WillPopScope( - // Push pop check into nested navigator. - onWillPop: () async => !(await _navigatorKey.currentState!.maybePop()), + return NavigatorPopHandler( + onPop: () { + _navigatorKey.currentState!.maybePop(); + }, child: Navigator( key: _navigatorKey, initialRoute: 'initial', @@ -1234,12 +1235,10 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp MaterialPageRoute _detailPageRoute(Object? arguments) { return MaterialPageRoute(builder: (BuildContext context) { - return WillPopScope( - onWillPop: () async { + return PopScope( + onPopInvoked: (bool didPop) { // No need for setState() as rebuild happens on navigation pop. focus = _Focus.master; - Navigator.of(context).pop(); - return false; }, child: BlockSemantics(child: widget.detailPageBuilder(context, arguments, null)), ); diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index 2438c45828989..62f0385935065 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -214,6 +214,7 @@ class MaterialApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, + this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, List this.navigatorObservers = const [], this.builder, this.title = '', @@ -267,6 +268,7 @@ class MaterialApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, + this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, this.color, this.theme, this.darkTheme, @@ -343,6 +345,9 @@ class MaterialApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} final RouteFactory? onUnknownRoute; + /// {@macro flutter.widgets.widgetsApp.onNavigationNotification} + final NotificationListenerCallback? onNavigationNotification; + /// {@macro flutter.widgets.widgetsApp.navigatorObservers} final List? navigatorObservers; @@ -1019,6 +1024,7 @@ class _MaterialAppState extends State { onGenerateRoute: widget.onGenerateRoute, onGenerateInitialRoutes: widget.onGenerateInitialRoutes, onUnknownRoute: widget.onUnknownRoute, + onNavigationNotification: widget.onNavigationNotification, builder: _materialBuilder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/services/system_navigator.dart b/packages/flutter/lib/src/services/system_navigator.dart index 9edff64b3cdf8..1ea16f921ac91 100644 --- a/packages/flutter/lib/src/services/system_navigator.dart +++ b/packages/flutter/lib/src/services/system_navigator.dart @@ -2,10 +2,44 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; + import 'system_channels.dart'; /// Controls specific aspects of the system navigation stack. abstract final class SystemNavigator { + /// Informs the platform of whether or not the Flutter framework will handle + /// back events. + /// + /// Currently, this is used only on Android to inform its use of the + /// predictive back gesture when exiting the app. When true, predictive back + /// is disabled. + /// + /// See also: + /// + /// * The + /// [migration guide](https://developer.android.com/guide/navigation/predictive-back-gesture) + /// for predictive back in native Android apps. + static Future setFrameworkHandlesBack(bool frameworkHandlesBack) async { + // Currently, this method call is only relevant on Android. + if (kIsWeb) { + return; + } + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + case TargetPlatform.macOS: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return; + case TargetPlatform.android: + return SystemChannels.platform.invokeMethod( + 'SystemNavigator.setFrameworkHandlesBack', + frameworkHandlesBack, + ); + } + } + /// Removes the topmost Flutter instance, presenting what was before /// it. /// diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index af5d404c43033..5d402c67bc3fd 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -19,6 +19,7 @@ import 'framework.dart'; import 'localizations.dart'; import 'media_query.dart'; import 'navigator.dart'; +import 'notification_listener.dart'; import 'pages.dart'; import 'performance_overlay.dart'; import 'restoration.dart'; @@ -313,6 +314,7 @@ class WidgetsApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, + this.onNavigationNotification = defaultOnNavigationNotification, List this.navigatorObservers = const [], this.initialRoute, this.pageRouteBuilder, @@ -420,6 +422,7 @@ class WidgetsApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, + this.onNavigationNotification = defaultOnNavigationNotification, this.textStyle, required this.color, this.locale, @@ -701,6 +704,17 @@ class WidgetsApp extends StatefulWidget { /// {@endtemplate} final RouteFactory? onUnknownRoute; + /// {@template flutter.widgets.widgetsApp.onNavigationNotification} + /// The callback to use when receiving a [NavigationNotification]. + /// + /// By default set to [WidgetsApp.defaultOnNavigationNotification], which + /// updates the engine with the navigation status. + /// + /// If null, [NavigationNotification] is not listened for at all, and so will + /// continue to propagate. + /// {@endtemplate} + final NotificationListenerCallback? onNavigationNotification; + /// {@template flutter.widgets.widgetsApp.initialRoute} /// The name of the first route to show, if a [Navigator] is built. /// @@ -1314,6 +1328,15 @@ class WidgetsApp extends StatefulWidget { VoidCallbackIntent: VoidCallbackAction(), }; + /// The default value for [onNavigationNotification]. + /// + /// Updates the platform with [NavigationNotification.canHandlePop] and stops + /// bubbling. + static bool defaultOnNavigationNotification(NavigationNotification notification) { + SystemNavigator.setFrameworkHandlesBack(notification.canHandlePop); + return true; + } + @override State createState() => _WidgetsAppState(); } @@ -1748,30 +1771,25 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { assert(_debugCheckLocalizations(appLocale)); - return RootRestorationScope( - restorationId: widget.restorationScopeId, - child: SharedAppData( - child: Shortcuts( - debugLabel: '', - shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, - // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can - // fall through to the defaultShortcuts. - child: DefaultTextEditingShortcuts( - child: Actions( - actions: widget.actions ?? >{ - ...WidgetsApp.defaultActions, - ScrollIntent: Action.overridable(context: context, defaultAction: ScrollAction()), - }, - child: FocusTraversalGroup( - policy: ReadingOrderTraversalPolicy(), - child: TapRegionSurface( - child: ShortcutRegistrar( - child: Localizations( - locale: appLocale, - delegates: _localizationsDelegates.toList(), - child: title, - ), - ), + Widget child = Shortcuts( + debugLabel: '', + shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, + // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can + // fall through to the defaultShortcuts. + child: DefaultTextEditingShortcuts( + child: Actions( + actions: widget.actions ?? >{ + ...WidgetsApp.defaultActions, + ScrollIntent: Action.overridable(context: context, defaultAction: ScrollAction()), + }, + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: TapRegionSurface( + child: ShortcutRegistrar( + child: Localizations( + locale: appLocale, + delegates: _localizationsDelegates.toList(), + child: title, ), ), ), @@ -1779,5 +1797,19 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { ), ), ); + + if (widget.onNavigationNotification != null) { + child = NotificationListener( + onNotification: widget.onNavigationNotification, + child: child, + ); + } + + return RootRestorationScope( + restorationId: widget.restorationScopeId, + child: SharedAppData( + child: child, + ), + ); } } diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 900d34fe77232..13efd54f53c35 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -54,9 +54,8 @@ export 'dart:ui' show AppLifecycleState, Locale; /// ** See code in examples/api/lib/widgets/binding/widget_binding_observer.0.dart ** /// {@end-tool} abstract mixin class WidgetsBindingObserver { - /// Called when the system tells the app to pop the current route. - /// For example, on Android, this is called when the user presses - /// the back button. + /// Called when the system tells the app to pop the current route, such as + /// after a system back button press or back gesture. /// /// Observers are notified in registration order until one returns /// true. If none return true, the application quits. @@ -69,6 +68,8 @@ abstract mixin class WidgetsBindingObserver { /// /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. + /// + /// {@macro flutter.widgets.AndroidPredictiveBack} Future didPopRoute() => Future.value(false); /// Called when the host tells the application to push a new route onto the @@ -720,6 +721,27 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. + /// + /// {@template flutter.widgets.AndroidPredictiveBack} + /// ## Handling backs ahead of time + /// + /// Not all system backs will result in a call to this method. Some are + /// handled entirely by the system without informing the Flutter framework. + /// + /// Android API 33+ introduced a feature called predictive back, which allows + /// the user to peek behind the current app or route during a back gesture and + /// then decide to cancel or commit the back. Flutter enables or disables this + /// feature ahead of time, before a back gesture occurs, and back gestures + /// that trigger predictive back are handled entirely by the system and do not + /// trigger this method here in the framework. + /// + /// By default, the framework communicates when it would like to handle system + /// back gestures using [SystemNavigator.setFrameworkHandlesBack] in + /// [WidgetsApp.defaultOnNavigationNotification]. This is done automatically + /// based on the status of the [Navigator] stack and the state of any + /// [PopScope] widgets present. Developers can manually set this by calling + /// the method directly or by using [NavigationNotification]. + /// {@endtemplate} @protected @visibleForTesting Future handlePopRoute() async { diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 76e8521ab9196..05ad8554a64c6 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -10,8 +10,10 @@ import 'package:flutter/rendering.dart'; import 'basic.dart'; import 'framework.dart'; import 'navigator.dart'; +import 'pop_scope.dart'; import 'restoration.dart'; import 'restoration_properties.dart'; +import 'routes.dart'; import 'will_pop_scope.dart'; // Duration for delay before announcement in IOS so that the announcement won't be interrupted. @@ -52,10 +54,17 @@ class Form extends StatefulWidget { const Form({ super.key, required this.child, + this.canPop, + this.onPopInvoked, + @Deprecated( + 'Use canPop and/or onPopInvoked instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) this.onWillPop, this.onChanged, AutovalidateMode? autovalidateMode, - }) : autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled; + }) : autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled, + assert((onPopInvoked == null && canPop == null) || onWillPop == null, 'onWillPop is deprecated; use canPop and/or onPopInvoked.'); /// Returns the [FormState] of the closest [Form] widget which encloses the /// given context, or null if none is found. @@ -134,8 +143,44 @@ class Form extends StatefulWidget { /// /// * [WillPopScope], another widget that provides a way to intercept the /// back button. + @Deprecated( + 'Use canPop and/or onPopInvoked instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) final WillPopCallback? onWillPop; + /// {@macro flutter.widgets.PopScope.canPop} + /// + /// {@tool dartpad} + /// This sample demonstrates how to use this parameter to show a confirmation + /// dialog when a navigation pop would cause form data to be lost. + /// + /// ** See code in examples/api/lib/widgets/form/form.1.dart ** + /// {@end-tool} + /// + /// See also: + /// + /// * [onPopInvoked], which also comes from [PopScope] and is often used in + /// conjunction with this parameter. + /// * [PopScope.canPop], which is what [Form] delegates to internally. + final bool? canPop; + + /// {@macro flutter.widgets.navigator.onPopInvoked} + /// + /// {@tool dartpad} + /// This sample demonstrates how to use this parameter to show a confirmation + /// dialog when a navigation pop would cause form data to be lost. + /// + /// ** See code in examples/api/lib/widgets/form/form.1.dart ** + /// {@end-tool} + /// + /// See also: + /// + /// * [canPop], which also comes from [PopScope] and is often used in + /// conjunction with this parameter. + /// * [PopScope.onPopInvoked], which is what [Form] delegates to internally. + final PopInvokedCallback? onPopInvoked; + /// Called when one of the form fields changes. /// /// In addition to this callback being invoked, all the form fields themselves @@ -200,6 +245,18 @@ class FormState extends State
{ break; } + if (widget.canPop != null || widget.onPopInvoked != null) { + return PopScope( + canPop: widget.canPop ?? true, + onPopInvoked: widget.onPopInvoked, + child: _FormScope( + formState: this, + generation: _generation, + child: widget.child, + ), + ); + } + return WillPopScope( onWillPop: widget.onWillPop, child: _FormScope( diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 43156aa44e26e..f366dfb2aee0f 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -20,6 +20,7 @@ import 'focus_scope.dart'; import 'focus_traversal.dart'; import 'framework.dart'; import 'heroes.dart'; +import 'notification_listener.dart'; import 'overlay.dart'; import 'restoration.dart'; import 'restoration_properties.dart'; @@ -67,6 +68,10 @@ typedef RoutePredicate = bool Function(Route route); /// /// Used by [Form.onWillPop], [ModalRoute.addScopedWillPopCallback], /// [ModalRoute.removeScopedWillPopCallback], and [WillPopScope]. +@Deprecated( + 'Use PopInvokedCallback instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', +) typedef WillPopCallback = Future Function(); /// Signature for the [Navigator.onPopPage] callback. @@ -89,19 +94,21 @@ typedef PopPageCallback = bool Function(Route route, dynamic result); enum RoutePopDisposition { /// Pop the route. /// - /// If [Route.willPop] returns [pop] then the back button will actually pop - /// the current route. + /// If [Route.willPop] or [Route.popDisposition] return [pop] then the back + /// button will actually pop the current route. pop, /// Do not pop the route. /// - /// If [Route.willPop] returns [doNotPop] then the back button will be ignored. + /// If [Route.willPop] or [Route.popDisposition] return [doNotPop] then the + /// back button will be ignored. doNotPop, /// Delegate this to the next level of navigation. /// - /// If [Route.willPop] returns [bubble] then the back button will be handled - /// by the [SystemNavigator], which will usually close the application. + /// If [Route.willPop] or [Route.popDisposition] return [bubble] then the back + /// button will be handled by the [SystemNavigator], which will usually close + /// the application. bubble, } @@ -294,10 +301,51 @@ abstract class Route { /// mechanism. /// * [WillPopScope], another widget that provides a way to intercept the /// back button. + @Deprecated( + 'Use popDisposition instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) Future willPop() async { return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop; } + /// Returns whether calling [Navigator.maybePop] when this [Route] is current + /// ([isCurrent]) should do anything. + /// + /// [Navigator.maybePop] is usually used instead of [Navigator.pop] to handle + /// the system back button, when it hasn't been disabled via + /// [SystemNavigator.setFrameworkHandlesBack]. + /// + /// By default, if a [Route] is the first route in the history (i.e., if + /// [isFirst]), it reports that pops should be bubbled + /// ([RoutePopDisposition.bubble]). This behavior prevents the user from + /// popping the first route off the history and being stranded at a blank + /// screen; instead, the larger scope is popped (e.g. the application quits, + /// so that the user returns to the previous application). + /// + /// In other cases, the default behavior is to accept the pop + /// ([RoutePopDisposition.pop]). + /// + /// The third possible value is [RoutePopDisposition.doNotPop], which causes + /// the pop request to be ignored entirely. + /// + /// See also: + /// + /// * [Form], which provides a [Form.canPop] boolean that is similar. + /// * [PopScope], a widget that provides a way to intercept the back button. + RoutePopDisposition get popDisposition { + return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop; + } + + /// {@template flutter.widgets.navigator.onPopInvoked} + /// Called after a route pop was handled. + /// + /// Even when the pop is canceled, for example by a [PopScope] widget, this + /// will still be called. The `didPop` parameter indicates whether or not the + /// back navigation actually happened successfully. + /// {@endtemplate} + void onPopInvoked(bool didPop) {} + /// Whether calling [didPop] would return false. bool get willHandlePopInternally => false; @@ -2415,6 +2463,9 @@ class Navigator extends StatefulWidget { /// the initial route. /// /// If there is no [Navigator] in scope, returns false. + /// + /// Does not consider anything that might externally prevent popping, such as + /// [PopEntry]. /// {@endtemplate} /// /// See also: @@ -2426,21 +2477,22 @@ class Navigator extends StatefulWidget { return navigator != null && navigator.canPop(); } - /// Consults the current route's [Route.willPop] method, and acts accordingly, - /// potentially popping the route as a result; returns whether the pop request - /// should be considered handled. + /// Consults the current route's [Route.popDisposition] getter or + /// [Route.willPop] method, and acts accordingly, potentially popping the + /// route as a result; returns whether the pop request should be considered + /// handled. /// /// {@template flutter.widgets.navigator.maybePop} - /// If [Route.willPop] returns [RoutePopDisposition.pop], then the [pop] + /// If the [RoutePopDisposition] is [RoutePopDisposition.pop], then the [pop] /// method is called, and this method returns true, indicating that it handled /// the pop request. /// - /// If [Route.willPop] returns [RoutePopDisposition.doNotPop], then this + /// If the [RoutePopDisposition] is [RoutePopDisposition.doNotPop], then this /// method returns true, but does not do anything beyond that. /// - /// If [Route.willPop] returns [RoutePopDisposition.bubble], then this method - /// returns false, and the caller is responsible for sending the request to - /// the containing scope (e.g. by closing the application). + /// If the [RoutePopDisposition] is [RoutePopDisposition.bubble], then this + /// method returns false, and the caller is responsible for sending the + /// request to the containing scope (e.g. by closing the application). /// /// This method is typically called for a user-initiated [pop]. For example on /// Android it's called by the binding for the system's back button. @@ -3015,6 +3067,7 @@ class _RouteEntry extends RouteTransitionRecord { assert(isPresent); pendingResult = result; currentState = _RouteLifecycle.pop; + route.onPopInvoked(true); } bool _reportRemovalToObserver = true; @@ -3295,12 +3348,93 @@ class _NavigatorReplaceObservation extends _NavigatorObservation { } } +typedef _IndexWhereCallback = bool Function(_RouteEntry element); + +/// A collection of _RouteEntries representing a navigation history. +/// +/// Acts as a ChangeNotifier and notifies after its List of _RouteEntries is +/// mutated. +class _History extends Iterable<_RouteEntry> with ChangeNotifier implements Iterator<_RouteEntry> { + final List<_RouteEntry> _value = <_RouteEntry>[]; + + int indexWhere(_IndexWhereCallback test, [int start = 0]) { + return _value.indexWhere(test, start); + } + + void add(_RouteEntry element) { + _value.add(element); + notifyListeners(); + } + + void addAll(Iterable<_RouteEntry> elements) { + _value.addAll(elements); + if (elements.isNotEmpty) { + notifyListeners(); + } + } + + void clear() { + final bool valueWasEmpty = _value.isEmpty; + _value.clear(); + if (!valueWasEmpty) { + notifyListeners(); + } + } + + void insert(int index, _RouteEntry element) { + _value.insert(index, element); + notifyListeners(); + } + + _RouteEntry removeAt(int index) { + final _RouteEntry entry = _value.removeAt(index); + notifyListeners(); + return entry; + } + + _RouteEntry removeLast() { + final _RouteEntry entry = _value.removeLast(); + notifyListeners(); + return entry; + } + + // Begin Iterator. + + int _i = 0; + + _RouteEntry operator [](int index) { + return _value[index]; + } + + @override + Iterator<_RouteEntry> get iterator { + return _value.iterator; + } + + @override + _RouteEntry get current => _value[_i]; + + @override + bool moveNext() { + _i++; + return _i <= _value.length - 1; + } + + // End Iterator. + + @override + String toString() { + return _value.toString(); + } +} + /// The state for a [Navigator] widget. /// /// A reference to this class can be obtained by calling [Navigator.of]. class NavigatorState extends State with TickerProviderStateMixin, RestorationMixin { late GlobalKey _overlayKey; - List<_RouteEntry> _history = <_RouteEntry>[]; + final _History _history = _History(); + /// A set for entries that are waiting to dispose until their subtrees are /// disposed. /// @@ -3330,12 +3464,43 @@ class NavigatorState extends State with TickerProviderStateMixin, Res late List _effectiveObservers; + bool get _usingPagesAPI => widget.pages != const >[]; + + void _handleHistoryChanged() { + final bool navigatorCanPop = canPop(); + late final bool routeBlocksPop; + if (!navigatorCanPop) { + final _RouteEntry? lastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate); + routeBlocksPop = lastEntry != null + && lastEntry.route.popDisposition == RoutePopDisposition.doNotPop; + } else { + routeBlocksPop = false; + } + final NavigationNotification notification = NavigationNotification( + canHandlePop: navigatorCanPop || routeBlocksPop, + ); + // Avoid dispatching a notification in the middle of a build. + switch (SchedulerBinding.instance.schedulerPhase) { + case SchedulerPhase.postFrameCallbacks: + notification.dispatch(context); + case SchedulerPhase.idle: + case SchedulerPhase.midFrameMicrotasks: + case SchedulerPhase.persistentCallbacks: + case SchedulerPhase.transientCallbacks: + SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { + if (!mounted) { + return; + } + notification.dispatch(context); + }); + } + } + @override void initState() { super.initState(); assert(() { - if (widget.pages != const >[]) { - // This navigator uses page API. + if (_usingPagesAPI) { if (widget.pages.isEmpty) { FlutterError.reportError( FlutterErrorDetails( @@ -3378,6 +3543,8 @@ class NavigatorState extends State with TickerProviderStateMixin, Res if (widget.reportsRouteUpdateToEngine) { SystemNavigator.selectSingleEntryHistory(); } + + _history.addListener(_handleHistoryChanged); } // Use [_nextPagelessRestorationScopeId] to get the next id. @@ -3560,7 +3727,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res void didUpdateWidget(Navigator oldWidget) { super.didUpdateWidget(oldWidget); assert(() { - if (widget.pages != const >[]) { + if (_usingPagesAPI) { // This navigator uses page API. if (widget.pages.isEmpty) { FlutterError.reportError( @@ -3672,6 +3839,8 @@ class NavigatorState extends State with TickerProviderStateMixin, Res _rawNextPagelessRestorationScopeId.dispose(); _serializableHistory.dispose(); userGestureInProgressNotifier.dispose(); + _history.removeListener(_handleHistoryChanged); + _history.dispose(); super.dispose(); // don't unlock, so that the object becomes unusable assert(_debugLocked); @@ -3957,7 +4126,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res pageRouteToPagelessRoutes: pageRouteToPagelessRoutes, ).cast<_RouteEntry>(); } - _history = <_RouteEntry>[]; + _history.clear(); // Adds the leading pageless routes if there is any. if (pageRouteToPagelessRoutes.containsKey(null)) { _history.addAll(pageRouteToPagelessRoutes[null]!); @@ -4973,17 +5142,17 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return true; // there's at least two routes, so we can pop } - /// Consults the current route's [Route.willPop] method, and acts accordingly, - /// potentially popping the route as a result; returns whether the pop request - /// should be considered handled. + /// Consults the current route's [Route.popDisposition] method, and acts + /// accordingly, potentially popping the route as a result; returns whether + /// the pop request should be considered handled. /// /// {@macro flutter.widgets.navigator.maybePop} /// /// See also: /// - /// * [Form], which provides an `onWillPop` callback that enables the form - /// to veto a [pop] initiated by the app's back button. - /// * [ModalRoute], which provides a `scopedWillPopCallback` that can be used + /// * [Form], which provides a [Form.canPop] boolean that enables the + /// form to prevent any [pop]s initiated by the app's back button. + /// * [ModalRoute], which provides a `scopedOnPopCallback` that can be used /// to define the route's `willPop` method. @optionalTypeArgs Future maybePop([ T? result ]) async { @@ -4992,23 +5161,31 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return false; } assert(lastEntry.route._navigator == this); - final RoutePopDisposition disposition = await lastEntry.route.willPop(); // this is asynchronous + + // TODO(justinmc): When the deprecated willPop method is removed, delete + // this code and use only popDisposition, below. + final RoutePopDisposition willPopDisposition = await lastEntry.route.willPop(); if (!mounted) { // Forget about this pop, we were disposed in the meantime. return true; } + if (willPopDisposition == RoutePopDisposition.doNotPop) { + return true; + } final _RouteEntry? newLastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate); if (lastEntry != newLastEntry) { // Forget about this pop, something happened to our history in the meantime. return true; } - switch (disposition) { + + switch (lastEntry.route.popDisposition) { case RoutePopDisposition.bubble: return false; case RoutePopDisposition.pop: pop(result); return true; case RoutePopDisposition.doNotPop: + lastEntry.route.onPopInvoked(false); return true; } } @@ -5298,29 +5475,46 @@ class NavigatorState extends State with TickerProviderStateMixin, Res Widget build(BuildContext context) { assert(!_debugLocked); assert(_history.isNotEmpty); + // Hides the HeroControllerScope for the widget subtree so that the other // nested navigator underneath will not pick up the hero controller above // this level. return HeroControllerScope.none( - child: Listener( - onPointerDown: _handlePointerDown, - onPointerUp: _handlePointerUpOrCancel, - onPointerCancel: _handlePointerUpOrCancel, - child: AbsorbPointer( - absorbing: false, // it's mutated directly by _cancelActivePointers above - child: FocusTraversalGroup( - policy: FocusTraversalGroup.maybeOf(context), - child: Focus( - focusNode: focusNode, - autofocus: true, - skipTraversal: true, - includeSemantics: false, - child: UnmanagedRestorationScope( - bucket: bucket, - child: Overlay( - key: _overlayKey, - clipBehavior: widget.clipBehavior, - initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], + child: NotificationListener( + onNotification: (NavigationNotification notification) { + // If the state of this Navigator does not change whether or not the + // whole framework can pop, propagate the Notification as-is. + if (notification.canHandlePop || !canPop()) { + return false; + } + // Otherwise, dispatch a new Notification with the correct canPop and + // stop the propagation of the old Notification. + const NavigationNotification nextNotification = NavigationNotification( + canHandlePop: true, + ); + nextNotification.dispatch(context); + return true; + }, + child: Listener( + onPointerDown: _handlePointerDown, + onPointerUp: _handlePointerUpOrCancel, + onPointerCancel: _handlePointerUpOrCancel, + child: AbsorbPointer( + absorbing: false, // it's mutated directly by _cancelActivePointers above + child: FocusTraversalGroup( + policy: FocusTraversalGroup.maybeOf(context), + child: Focus( + focusNode: focusNode, + autofocus: true, + skipTraversal: true, + includeSemantics: false, + child: UnmanagedRestorationScope( + bucket: bucket, + child: Overlay( + key: _overlayKey, + clipBehavior: widget.clipBehavior, + initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], + ), ), ), ), @@ -5481,7 +5675,7 @@ class _HistoryProperty extends RestorableProperty>?> { // Updating. - void update(List<_RouteEntry> history) { + void update(_History history) { assert(isRegistered); final bool wasUninitialized = _pageToPagelessRoutes == null; bool needsSerialization = wasUninitialized; @@ -5804,3 +5998,26 @@ class RestorableRouteFuture extends RestorableProperty { static NavigatorState _defaultNavigatorFinder(BuildContext context) => Navigator.of(context); } + +/// A notification that a change in navigation has taken place. +/// +/// Specifically, this notification indicates that at least one of the following +/// has occurred: +/// +/// * That route stack of a [Navigator] has changed in any way. +/// * The ability to pop has changed, such as controlled by [PopScope]. +class NavigationNotification extends Notification { + /// Creates a notification that some change in navigation has happened. + const NavigationNotification({ + required this.canHandlePop, + }); + + /// Indicates that the originator of this [Notification] is capable of + /// handling a navigation pop. + final bool canHandlePop; + + @override + String toString() { + return 'NavigationNotification canHandlePop: $canHandlePop'; + } +} diff --git a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart new file mode 100644 index 0000000000000..203a85beded18 --- /dev/null +++ b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart @@ -0,0 +1,110 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'framework.dart'; +import 'navigator.dart'; +import 'notification_listener.dart'; +import 'pop_scope.dart'; + +/// Enables the handling of system back gestures. +/// +/// Typically wraps a nested [Navigator] widget and allows it to handle system +/// back gestures in the [onPop] callback. +/// +/// {@tool dartpad} +/// This sample demonstrates how to use this widget to properly handle system +/// back gestures when using nested [Navigator]s. +/// +/// ** See code in examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This sample demonstrates how to use this widget to properly handle system +/// back gestures with a bottom navigation bar whose tabs each have their own +/// nested [Navigator]s. +/// +/// ** See code in examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [PopScope], which allows toggling the ability of a [Navigator] to +/// handle pops. +/// * [NavigationNotification], which indicates whether a [Navigator] in a +/// subtree can handle pops. +class NavigatorPopHandler extends StatefulWidget { + /// Creates an instance of [NavigatorPopHandler]. + const NavigatorPopHandler({ + super.key, + this.onPop, + this.enabled = true, + required this.child, + }); + + /// The widget to place below this in the widget tree. + /// + /// Typically this is a [Navigator] that will handle the pop when [onPop] is + /// called. + final Widget child; + + /// Whether this widget's ability to handle system back gestures is enabled or + /// disabled. + /// + /// When false, there will be no effect on system back gestures. If provided, + /// [onPop] will still be called. + /// + /// This can be used, for example, when the nested [Navigator] is no longer + /// active but remains in the widget tree, such as in an inactive tab. + /// + /// Defaults to true. + final bool enabled; + + /// Called when a handleable pop event happens. + /// + /// For example, a pop is handleable when a [Navigator] in [child] has + /// multiple routes on its stack. It's not handleable when it has only a + /// single route, and so [onPop] will not be called. + /// + /// Typically this is used to pop the [Navigator] in [child]. See the sample + /// code on [NavigatorPopHandler] for a full example of this. + final VoidCallback? onPop; + + @override + State createState() => _NavigatorPopHandlerState(); +} + +class _NavigatorPopHandlerState extends State { + bool _canPop = true; + + @override + Widget build(BuildContext context) { + // When the widget subtree indicates it can handle a pop, disable popping + // here, so that it can be manually handled in canPop. + return PopScope( + canPop: !widget.enabled || _canPop, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + widget.onPop?.call(); + }, + // Listen to changes in the navigation stack in the widget subtree. + child: NotificationListener( + onNotification: (NavigationNotification notification) { + // If this subtree cannot handle pop, then set canPop to true so + // that our PopScope will allow the Navigator higher in the tree to + // handle the pop instead. + final bool nextCanPop = !notification.canHandlePop; + if (nextCanPop != _canPop) { + setState(() { + _canPop = nextCanPop; + }); + } + return false; + }, + child: widget.child, + ), + ); + } +} diff --git a/packages/flutter/lib/src/widgets/pop_scope.dart b/packages/flutter/lib/src/widgets/pop_scope.dart new file mode 100644 index 0000000000000..b47d83fcdbbd0 --- /dev/null +++ b/packages/flutter/lib/src/widgets/pop_scope.dart @@ -0,0 +1,137 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; + +import 'framework.dart'; +import 'navigator.dart'; +import 'routes.dart'; + +/// Manages system back gestures. +/// +/// The [canPop] parameter can be used to disable system back gestures. Defaults +/// to true, meaning that back gestures happen as usual. +/// +/// The [onPopInvoked] parameter reports when system back gestures occur, +/// regardless of whether or not they were successful. +/// +/// If [canPop] is false, then a system back gesture will not pop the route off +/// of the enclosing [Navigator]. [onPopInvoked] will still be called, and +/// `didPop` will be `false`. +/// +/// If [canPop] is true, then a system back gesture will cause the enclosing +/// [Navigator] to receive a pop as usual. [onPopInvoked] will be called with +/// `didPop` as `true`, unless the pop failed for reasons unrelated to +/// [PopScope], in which case it will be `false`. +/// +/// {@tool dartpad} +/// This sample demonstrates how to use this widget to handle nested navigation +/// in a bottom navigation bar. +/// +/// ** See code in examples/api/lib/widgets/pop_scope/pop_scope.0.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [NavigatorPopHandler], which is a less verbose way to handle system back +/// gestures in simple cases of nested [Navigator]s. +/// * [Form.canPop] and [Form.onPopInvoked], which can be used to handle system +/// back gestures in the case of a form with unsaved data. +/// * [ModalRoute.registerPopEntry] and [ModalRoute.unregisterPopEntry], +/// which this widget uses to integrate with Flutter's navigation system. +class PopScope extends StatefulWidget { + /// Creates a widget that registers a callback to veto attempts by the user to + /// dismiss the enclosing [ModalRoute]. + const PopScope({ + super.key, + required this.child, + this.canPop = true, + this.onPopInvoked, + }); + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget child; + + /// {@template flutter.widgets.PopScope.onPopInvoked} + /// Called after a route pop was handled. + /// {@endtemplate} + /// + /// It's not possible to prevent the pop from happening at the time that this + /// method is called; the pop has already happened. Use [canPop] to + /// disable pops in advance. + /// + /// This will still be called even when the pop is canceled. A pop is canceled + /// when the relevant [Route.popDisposition] returns false, such as when + /// [canPop] is set to false on a [PopScope]. The `didPop` parameter + /// indicates whether or not the back navigation actually happened + /// successfully. + /// + /// See also: + /// + /// * [Route.onPopInvoked], which is similar. + final PopInvokedCallback? onPopInvoked; + + /// {@template flutter.widgets.PopScope.canPop} + /// When false, blocks the current route from being popped. + /// + /// This includes the root route, where upon popping, the Flutter app would + /// exit. + /// + /// If multiple [PopScope] widgets appear in a route's widget subtree, then + /// each and every `canPop` must be `true` in order for the route to be + /// able to pop. + /// + /// [Android's predictive back](https://developer.android.com/guide/navigation/predictive-back-gesture) + /// feature will not animate when this boolean is false. + /// {@endtemplate} + final bool canPop; + + @override + State createState() => _PopScopeState(); +} + +class _PopScopeState extends State implements PopEntry { + ModalRoute? _route; + + @override + PopInvokedCallback? get onPopInvoked => widget.onPopInvoked; + + @override + late final ValueNotifier canPopNotifier; + + @override + void initState() { + super.initState(); + canPopNotifier = ValueNotifier(widget.canPop); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final ModalRoute? nextRoute = ModalRoute.of(context); + if (nextRoute != _route) { + _route?.unregisterPopEntry(this); + _route = nextRoute; + _route?.registerPopEntry(this); + } + } + + @override + void didUpdateWidget(PopScope oldWidget) { + super.didUpdateWidget(oldWidget); + canPopNotifier.value = widget.canPop; + } + + @override + void dispose() { + _route?.unregisterPopEntry(this); + canPopNotifier.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) => widget.child; +} diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index 441486e5ed676..e54e46ab3c7b8 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -717,6 +717,10 @@ mixin LocalHistoryRoute on Route { } } + @Deprecated( + 'Use popDisposition instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) @override Future willPop() async { if (willHandlePopInternally) { @@ -725,6 +729,14 @@ mixin LocalHistoryRoute on Route { return super.willPop(); } + @override + RoutePopDisposition get popDisposition { + if (willHandlePopInternally) { + return RoutePopDisposition.pop; + } + return super.popDisposition; + } + @override bool didPop(T? result) { if (_localHistory != null && _localHistory!.isNotEmpty) { @@ -1490,6 +1502,8 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute _willPopCallbacks = []; + final Set _popEntries = {}; + /// Returns [RoutePopDisposition.doNotPop] if any of callbacks added with /// [addScopedWillPopCallback] returns either false or null. If they all /// return true, the base [Route.willPop]'s result will be returned. The @@ -1508,6 +1522,10 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute willPop() async { final _ModalScopeState? scope = _scopeKey.currentState; @@ -1520,25 +1538,43 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute { - /// ModalRoute? _route; - /// - /// // ... - /// - /// @override - /// void didChangeDependencies() { - /// super.didChangeDependencies(); - /// _route?.removeScopedWillPopCallback(askTheUserIfTheyAreSure); - /// _route = ModalRoute.of(context); - /// _route?.addScopedWillPopCallback(askTheUserIfTheyAreSure); - /// } - /// } - /// ``` - /// {@end-tool} - /// - /// {@tool snippet} - /// If you register a callback manually, be sure to remove the callback with - /// [removeScopedWillPopCallback] by the time the widget has been disposed. A - /// stateful widget can do this in its dispose method (continuing the previous - /// example): - /// - /// ```dart - /// abstract class _MyWidgetState2 extends State { - /// ModalRoute? _route; - /// - /// // ... - /// - /// @override - /// void dispose() { - /// _route?.removeScopedWillPopCallback(askTheUserIfTheyAreSure); - /// _route = null; - /// super.dispose(); - /// } - /// } - /// ``` - /// {@end-tool} - /// /// See also: /// /// * [WillPopScope], which manages the registration and unregistration @@ -1599,6 +1592,10 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute '${objectRuntimeType(this, 'ModalRoute')}($settings, animation: $_animation)'; } @@ -2212,3 +2279,33 @@ typedef RoutePageBuilder = Widget Function(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child); + +/// A callback type for informing that a navigation pop has been invoked, +/// whether or not it was handled successfully. +/// +/// Accepts a didPop boolean indicating whether or not back navigation +/// succeeded. +typedef PopInvokedCallback = void Function(bool didPop); + +/// Allows listening to and preventing pops. +/// +/// Can be registered in [ModalRoute] to listen to pops with [onPopInvoked] or +/// to enable/disable them with [canPopNotifier]. +/// +/// See also: +/// +/// * [PopScope], which provides similar functionality in a widget. +/// * [ModalRoute.registerPopEntry], which unregisters instances of this. +/// * [ModalRoute.unregisterPopEntry], which unregisters instances of this. +abstract class PopEntry { + /// {@macro flutter.widgets.PopScope.onPopInvoked} + PopInvokedCallback? get onPopInvoked; + + /// {@macro flutter.widgets.PopScope.canPop} + ValueListenable get canPopNotifier; + + @override + String toString() { + return 'PopEntry canPop: ${canPopNotifier.value}, onPopInvoked: $onPopInvoked'; + } +} diff --git a/packages/flutter/lib/src/widgets/will_pop_scope.dart b/packages/flutter/lib/src/widgets/will_pop_scope.dart index ab90c7f49de01..eefe437983375 100644 --- a/packages/flutter/lib/src/widgets/will_pop_scope.dart +++ b/packages/flutter/lib/src/widgets/will_pop_scope.dart @@ -9,26 +9,25 @@ import 'routes.dart'; /// Registers a callback to veto attempts by the user to dismiss the enclosing /// [ModalRoute]. /// -/// {@tool dartpad} -/// Whenever the back button is pressed, you will get a callback at [onWillPop], -/// which returns a [Future]. If the [Future] returns true, the screen is -/// popped. -/// -/// ** See code in examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart ** -/// {@end-tool} -/// /// See also: /// /// * [ModalRoute.addScopedWillPopCallback] and [ModalRoute.removeScopedWillPopCallback], /// which this widget uses to register and unregister [onWillPop]. /// * [Form], which provides an `onWillPop` callback that enables the form /// to veto a `pop` initiated by the app's back button. -/// +@Deprecated( + 'Use PopScope instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', +) class WillPopScope extends StatefulWidget { /// Creates a widget that registers a callback to veto attempts by the user to /// dismiss the enclosing [ModalRoute]. /// /// The [child] argument must not be null. + @Deprecated( + 'Use PopScope instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) const WillPopScope({ super.key, required this.child, diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 539d6aac62956..3ca0999b994d0 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -81,6 +81,7 @@ export 'src/widgets/media_query.dart'; export 'src/widgets/modal_barrier.dart'; export 'src/widgets/navigation_toolbar.dart'; export 'src/widgets/navigator.dart'; +export 'src/widgets/navigator_pop_handler.dart'; export 'src/widgets/nested_scroll_view.dart'; export 'src/widgets/notification_listener.dart'; export 'src/widgets/orientation_builder.dart'; @@ -95,6 +96,7 @@ export 'src/widgets/placeholder.dart'; export 'src/widgets/platform_menu_bar.dart'; export 'src/widgets/platform_selectable_region_context_menu.dart'; export 'src/widgets/platform_view.dart'; +export 'src/widgets/pop_scope.dart'; export 'src/widgets/preferred_size.dart'; export 'src/widgets/primary_scroll_controller.dart'; export 'src/widgets/raw_keyboard_listener.dart'; diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index a8a43b510277d..b376a92ecf276 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; - import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../image_data.dart'; import '../rendering/rendering_tester.dart' show TestCallbackPainter; +import '../widgets/navigator_utils.dart'; late List selectedTabs; @@ -1215,6 +1216,132 @@ void main() { expect(find.text('Content 2'), findsNothing); expect(find.text('Content 3'), findsNothing); }); + + group('Android Predictive Back', () { + bool? lastFrameworkHandlesBack; + setUp(() { + // Initialize to false. Because this uses a static boolean internally, it + // is not reset between tests or calls to pumpWidget. Explicitly setting + // it to false before each test makes them behave deterministically. + SystemNavigator.setFrameworkHandlesBack(false); + lastFrameworkHandlesBack = null; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + lastFrameworkHandlesBack = methodCall.arguments as bool; + } + return; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + SystemNavigator.setFrameworkHandlesBack(true); + }); + + testWidgets('System back navigation inside of tabs', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: MediaQuery( + data: const MediaQueryData( + viewInsets: EdgeInsets.only(bottom: 200), + ), + child: CupertinoTabScaffold( + tabBar: _buildTabBar(), + tabBuilder: (BuildContext context, int index) { + return CupertinoTabView( + builder: (BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text('Page 1 of tab ${index + 1}'), + ), + child: Center( + child: CupertinoButton( + child: const Text('Next page'), + onPressed: () { + Navigator.of(context).push( + CupertinoPageRoute( + builder: (BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text('Page 2 of tab ${index + 1}'), + ), + child: Center( + child: CupertinoButton( + child: const Text('Back'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + ); + }, + ), + ); + }, + ), + ), + ); + }, + ); + }, + ), + ), + ), + ); + + expect(find.text('Page 1 of tab 1'), findsOneWidget); + expect(find.text('Page 2 of tab 1'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsNothing); + expect(find.text('Page 2 of tab 1'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsOneWidget); + expect(find.text('Page 2 of tab 1'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsNothing); + expect(find.text('Page 2 of tab 1'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Tab 2')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 2'), findsOneWidget); + expect(find.text('Page 2 of tab 2'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Tab 1')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsNothing); + expect(find.text('Page 2 of tab 1'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsOneWidget); + expect(find.text('Page 2 of tab 1'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Tab 2')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 2'), findsOneWidget); + expect(find.text('Page 2 of tab 2'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: kIsWeb, // [intended] frameworkHandlesBack not used on web. + ); + }); } CupertinoTabBar _buildTabBar({ int selectedTab = 0 }) { diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 26d1463639259..d403ceba9c80f 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -6,9 +6,12 @@ import 'dart:ui' show FlutterView; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'navigator_utils.dart'; import 'observer_tester.dart'; import 'semantics_tester.dart'; @@ -4153,6 +4156,719 @@ void main() { expect(const RouteSettings().toString(), 'RouteSettings(none, null)'); }); }); + + group('Android Predictive Back', () { + bool? lastFrameworkHandlesBack; + setUp(() { + // Initialize to false. Because this uses a static boolean internally, it + // is not reset between tests or calls to pumpWidget. Explicitly setting + // it to false before each test makes them behave deterministically. + SystemNavigator.setFrameworkHandlesBack(false); + lastFrameworkHandlesBack = null; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + lastFrameworkHandlesBack = methodCall.arguments as bool; + } + return; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + SystemNavigator.setFrameworkHandlesBack(true); + }); + + testWidgets('a single route is already defaulted to false', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: Text('home'), + ) + ) + ); + + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('navigating around a single Navigator with .pop', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/one/one': (BuildContext context) => const _LinksPage( + title: 'Page one - one', + ), + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to one/one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one - one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('navigating around a single Navigator with system back', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/one/one': (BuildContext context) => const _LinksPage( + title: 'Page one - one', + ), + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to one/one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one - one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('a single Navigator with a PopScope that defaults to enabled', (WidgetTester tester) async { + bool canPop = true; + late StateSetter setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + canPop: canPop, + ), + }, + ); + }, + ), + ); + + expect(lastFrameworkHandlesBack, isFalse); + + setState(() { + canPop = false; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = true; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('a single Navigator with a PopScope that defaults to disabled', (WidgetTester tester) async { + bool canPop = false; + late StateSetter setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + canPop: canPop, + ), + }, + ); + }, + ), + ); + + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = true; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isFalse); + + setState(() { + canPop = false; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isTrue); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + // Test both system back gestures and Navigator.pop. + for (final _BackType backType in _BackType.values) { + testWidgets('navigating around nested Navigators', (WidgetTester tester) async { + final GlobalKey nav = GlobalKey(); + final GlobalKey nestedNav = GlobalKey(); + Future goBack() async { + switch (backType) { + case _BackType.systemBack: + return simulateSystemBack(); + case _BackType.navigatorPop: + if (nestedNav.currentState != null) { + if (nestedNav.currentState!.mounted && nestedNav.currentState!.canPop()) { + return nestedNav.currentState?.pop(); + } + } + return nav.currentState?.pop(); + } + } + await tester.pumpWidget( + MaterialApp( + navigatorKey: nav, + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/nested'); + }, + child: const Text('Go to nested'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/nested': (BuildContext context) => _NestedNavigatorsPage( + navigatorKey: nestedNav, + ), + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await goBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to nested')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to nested/one')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await goBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await goBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + } + + testWidgets('nested Navigators with a nested PopScope', (WidgetTester tester) async { + bool canPop = true; + late StateSetter setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/nested'); + }, + child: const Text('Go to nested'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/nested': (BuildContext context) => _NestedNavigatorsPage( + popScopePageEnabled: canPop, + ), + }, + ); + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to nested')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to nested/popscope')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - PopScope'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + // Going back works because canPop is true. + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to nested/popscope')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - PopScope'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = false; + }); + await tester.pumpAndSettle(); + + expect(lastFrameworkHandlesBack, isTrue); + + // Now going back doesn't work because canPop is false, but it still + // has no effect on the system navigator due to all of the other routes. + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - PopScope'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = true; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isTrue); + + // And going back works again after switching canPop back to true. + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + group('Navigator page API', () { + testWidgets('starting with one route as usual', (WidgetTester tester) async { + late StateSetter builderSetState; + final List<_Page> pages = <_Page>[_Page.home]; + bool canPop() => pages.length <= 1; + + await tester.pumpWidget( + MaterialApp( + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + builderSetState = setState; + return PopScope( + canPop: canPop(), + onPopInvoked: (bool success) { + if (success || pages.last == _Page.noPop) { + return; + } + setState(() { + pages.removeLast(); + }); + }, + child: Navigator( + onPopPage: (Route route, void result) { + if (!route.didPop(null)) { + return false; + } + setState(() { + pages.removeLast(); + }); + return true; + }, + pages: pages.map((_Page page) { + switch (page) { + case _Page.home: + return MaterialPage( + child: _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.one); + }); + }, + child: const Text('Go to _Page.one'), + ), + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.noPop); + }); + }, + child: const Text('Go to _Page.noPop'), + ), + ], + ), + ); + case _Page.one: + return const MaterialPage( + child: _LinksPage( + title: 'Page one', + ), + ); + case _Page.noPop: + return const MaterialPage( + child: _LinksPage( + title: 'Cannot pop page', + canPop: false, + ), + ); + } + }).toList(), + ), + ); + }, + ), + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to _Page.one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to _Page.noPop')); + await tester.pumpAndSettle(); + + expect(find.text('Cannot pop page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Cannot pop page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + // Circumvent "Cannot pop page" by directly modifying pages. + builderSetState(() { + pages.removeLast(); + }); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('starting with existing route history', (WidgetTester tester) async { + final List<_Page> pages = <_Page>[_Page.home, _Page.one]; + bool canPop() => pages.length <= 1; + + await tester.pumpWidget( + MaterialApp( + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return PopScope( + canPop: canPop(), + onPopInvoked: (bool success) { + if (success || pages.last == _Page.noPop) { + return; + } + setState(() { + pages.removeLast(); + }); + }, + child: Navigator( + onPopPage: (Route route, void result) { + if (!route.didPop(null)) { + return false; + } + setState(() { + pages.removeLast(); + }); + return true; + }, + pages: pages.map((_Page page) { + switch (page) { + case _Page.home: + return MaterialPage( + child: _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.one); + }); + }, + child: const Text('Go to _Page.one'), + ), + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.noPop); + }); + }, + child: const Text('Go to _Page.noPop'), + ), + ], + ), + ); + case _Page.one: + return const MaterialPage( + child: _LinksPage( + title: 'Page one', + ), + ); + case _Page.noPop: + return const MaterialPage( + child: _LinksPage( + title: 'Cannot pop page', + canPop: false, + ), + ); + } + }).toList(), + ), + ); + }, + ), + ), + ); + + expect(find.text('Home page'), findsNothing); + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(find.text('Page one'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + }); + }); } typedef AnnouncementCallBack = void Function(Route?); @@ -4435,3 +5151,153 @@ class TestDependencies extends StatelessWidget { ); } } + +enum _BackType { + systemBack, + navigatorPop, +} + +enum _Page { + home, + one, + noPop, +} + +class _LinksPage extends StatelessWidget { + const _LinksPage ({ + this.buttons = const [], + this.canPop, + required this.title, + this.onBack, + }); + + final List buttons; + final bool? canPop; + final VoidCallback? onBack; + final String title; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(title), + ...buttons, + if (Navigator.of(context).canPop()) + TextButton( + onPressed: onBack ?? () { + Navigator.of(context).pop(); + }, + child: const Text('Go back'), + ), + if (canPop != null) + PopScope( + canPop: canPop!, + child: const SizedBox.shrink(), + ), + ], + ), + ), + ); + } +} + +class _NestedNavigatorsPage extends StatefulWidget { + const _NestedNavigatorsPage({ + this.popScopePageEnabled, + this.navigatorKey, + }); + + /// Whether the PopScope on the /popscope page is enabled. + /// + /// If null, then no PopScope is built at all. + final bool? popScopePageEnabled; + + final GlobalKey? navigatorKey; + + @override + State<_NestedNavigatorsPage> createState() => _NestedNavigatorsPageState(); +} + +class _NestedNavigatorsPageState extends State<_NestedNavigatorsPage> { + late final GlobalKey _navigatorKey; + + @override + void initState() { + super.initState(); + _navigatorKey = widget.navigatorKey ?? GlobalKey(); + } + + @override + Widget build(BuildContext context) { + final BuildContext rootContext = context; + return NavigatorPopHandler( + onPop: () { + if (widget.popScopePageEnabled == false) { + return; + } + _navigatorKey.currentState!.pop(); + }, + child: Navigator( + key: _navigatorKey, + initialRoute: '/', + onGenerateRoute: (RouteSettings settings) { + switch (settings.name) { + case '/': + return MaterialPageRoute( + builder: (BuildContext context) { + return _LinksPage( + title: 'Nested - home', + onBack: () { + Navigator.of(rootContext).pop(); + }, + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to nested/one'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/popscope'); + }, + child: const Text('Go to nested/popscope'), + ), + TextButton( + onPressed: () { + Navigator.of(rootContext).pop(); + }, + child: const Text('Go back out of nested nav'), + ), + ], + ); + }, + ); + case '/one': + return MaterialPageRoute( + builder: (BuildContext context) { + return const _LinksPage( + title: 'Nested - page one', + ); + }, + ); + case '/popscope': + return MaterialPageRoute( + builder: (BuildContext context) { + return _LinksPage( + canPop: widget.popScopePageEnabled, + title: 'Nested - PopScope', + ); + }, + ); + default: + throw Exception('Invalid route: ${settings.name}'); + } + }, + ), + ); + } +} diff --git a/packages/flutter/test/widgets/navigator_utils.dart b/packages/flutter/test/widgets/navigator_utils.dart new file mode 100644 index 0000000000000..46f1f9b1ac469 --- /dev/null +++ b/packages/flutter/test/widgets/navigator_utils.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Simulates a system back, like a back gesture on Android. +/// +/// Sends the same platform channel message that the engine sends when it +/// receives a system back. +Future simulateSystemBack() { + return TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + 'flutter/navigation', + const JSONMessageCodec().encodeMessage({ + 'method': 'popRoute', + }), + (ByteData? _) {}, + ); +} diff --git a/packages/flutter/test/widgets/pop_scope_test.dart b/packages/flutter/test/widgets/pop_scope_test.dart new file mode 100644 index 0000000000000..c5d0e88545034 --- /dev/null +++ b/packages/flutter/test/widgets/pop_scope_test.dart @@ -0,0 +1,361 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'navigator_utils.dart'; + +void main() { + bool? lastFrameworkHandlesBack; + setUp(() { + // Initialize to false. Because this uses a static boolean internally, it + // is not reset between tests or calls to pumpWidget. Explicitly setting + // it to false before each test makes them behave deterministically. + SystemNavigator.setFrameworkHandlesBack(false); + lastFrameworkHandlesBack = null; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + lastFrameworkHandlesBack = methodCall.arguments as bool; + } + return; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + SystemNavigator.setFrameworkHandlesBack(true); + }); + + testWidgets('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { + bool canPop = false; + late StateSetter setState; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext buildContext) => Scaffold( + body: StatefulBuilder( + builder: (BuildContext buildContext, StateSetter stateSetter) { + context = buildContext; + setState = stateSetter; + return PopScope( + canPop: canPop, + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Home/PopScope Page'), + ], + ), + ), + ); + }, + ), + ), + }, + ), + ); + + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + setState(() { + canPop = true; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); + }, + variant: TargetPlatformVariant.all(), + ); + + testWidgets('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async { + final GlobalKey nav = GlobalKey(); + bool canPop = true; + late StateSetter setState; + late BuildContext homeContext; + late BuildContext oneContext; + late bool lastPopSuccess; + await tester.pumpWidget( + MaterialApp( + navigatorKey: nav, + initialRoute: '/', + routes: { + '/': (BuildContext context) { + homeContext = context; + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Home Page'), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Next'), + ), + ], + ), + ), + ); + }, + '/one': (BuildContext context) => Scaffold( + body: StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + oneContext = context; + setState = stateSetter; + return PopScope( + canPop: canPop, + onPopInvoked: (bool didPop) { + lastPopSuccess = didPop; + }, + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('PopScope Page'), + ], + ), + ), + ); + }, + ), + ), + }, + ), + ); + + expect(find.text('Home Page'), findsOneWidget); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + // When canPop is true, can use pop to go back. + nav.currentState!.maybePop(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + // When canPop is true, can use system back to go back. + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + setState(() { + canPop = false; + }); + await tester.pump(); + + // When canPop is false, can't use pop to go back. + nav.currentState!.maybePop(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, false); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.doNotPop); + + // When canPop is false, can't use system back to go back. + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, false); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.doNotPop); + + // Toggle canPop back to true and back works again. + setState(() { + canPop = true; + }); + await tester.pump(); + + nav.currentState!.maybePop(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + }, + variant: TargetPlatformVariant.all(), + ); + + testWidgets('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async { + bool usePopScope = true; + late StateSetter setState; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext buildContext) => Scaffold( + body: StatefulBuilder( + builder: (BuildContext buildContext, StateSetter stateSetter) { + context = buildContext; + setState = stateSetter; + const Widget child = Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Home/PopScope Page'), + ], + ), + ); + if (!usePopScope) { + return child; + } + return const PopScope( + canPop: false, + child: child, + ); + }, + ), + ), + }, + ), + ); + + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + setState(() { + usePopScope = false; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); + }, + variant: TargetPlatformVariant.all(), + ); + + testWidgets('identical PopScopes', (WidgetTester tester) async { + bool usePopScope1 = true; + bool usePopScope2 = true; + late StateSetter setState; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: StatefulBuilder( + builder: (BuildContext buildContext, StateSetter stateSetter) { + context = buildContext; + setState = stateSetter; + return Column( + children: [ + if (usePopScope1) + const PopScope( + canPop: false, + child: Text('hello'), + ), + if (usePopScope2) + const PopScope( + canPop: false, + child: Text('hello'), + ), + ], + ); + }, + ), + ), + ), + ); + + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + // Despite being in the widget tree twice, the ModalRoute has only ever + // registered one PopScopeInterface for it. Removing one makes it think that + // both have been removed. + setState(() { + usePopScope1 = false; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + setState(() { + usePopScope2 = false; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); + }, + variant: TargetPlatformVariant.all(), + ); +} From b7acafa0bbf6a23943c447eb98a6b21b1adcbe93 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 16:47:08 -0400 Subject: [PATCH 0544/1547] Roll Flutter Engine from a7bea8621f4b to c254deb8fbda (3 revisions) (#131950) https://github.com/flutter/engine/compare/a7bea8621f4b...c254deb8fbda 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 85938bb68e75 to 45c0a830d805 (3 revisions) (flutter/engine#44397) 2023-08-04 55360120+Matt2D@users.noreply.github.com Flutter iOS Interactive Keyboard: Take Screenshot and Handle Pointer Movement (flutter/engine#43972) 2023-08-04 skia-flutter-autoroll@skia.org Roll Dart SDK from b3372378e487 to a0b59bac20fc (1 revision) (flutter/engine#44393) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 55583b601dd27..414c949fd4f98 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a7bea8621f4b05e758ea4d3616031f77b6863eed +c254deb8fbda9c895db9765ce5521f0751bda403 From 53082f65b57a5f008d5b6c1d48510f5450b4e246 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 17:46:24 -0400 Subject: [PATCH 0545/1547] Roll Flutter Engine from c254deb8fbda to 4f4734cd48da (2 revisions) (#131955) https://github.com/flutter/engine/compare/c254deb8fbda...4f4734cd48da 2023-08-04 chris@bracken.jp [Darwin] Enable ARC in darwin/common unit tests (flutter/engine#44396) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 45c0a830d805 to 6dc76e862f90 (2 revisions) (flutter/engine#44399) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 414c949fd4f98..1942f3dd99b54 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c254deb8fbda9c895db9765ce5521f0751bda403 +4f4734cd48da77d757f492b0f55b99dda6cee815 From 11025e4acd50a30965f5e698e7aa8a384e930b6f Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 4 Aug 2023 16:41:24 -0700 Subject: [PATCH 0546/1547] Sped up the time to find macrobenchmarks. (#131959) This reduce the execution time of macrobenchmarks driver tests. I tried to find the exact size to scroll the screen but I couldn't find a way to do that with driver tests. --- dev/benchmarks/macrobenchmarks/test_driver/util.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dev/benchmarks/macrobenchmarks/test_driver/util.dart b/dev/benchmarks/macrobenchmarks/test_driver/util.dart index bf74fbf8ec5ba..87b8fd2507804 100644 --- a/dev/benchmarks/macrobenchmarks/test_driver/util.dart +++ b/dev/benchmarks/macrobenchmarks/test_driver/util.dart @@ -23,7 +23,11 @@ Future runDriverTestForRoute(String routeName, DriverTestCallBack body) as expect(scrollable, isNotNull); final SerializableFinder button = find.byValueKey(routeName); expect(button, isNotNull); - await driver.scrollUntilVisible(scrollable, button, dyScroll: -100.0); + // -320 comes from the logical pixels for a full screen scroll for the + // smallest reference device, iPhone 4, whose physical screen dimensions are + // 960px × 640px. + const double dyScroll = -320.0; + await driver.scrollUntilVisible(scrollable, button, dyScroll: dyScroll); await driver.tap(button); await body(driver); From a2fa60cc4d6013f98e3f12bf185bea6038875fdf Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Fri, 4 Aug 2023 18:00:14 -0700 Subject: [PATCH 0547/1547] mark linux packages_autoroller flaky because of token issue (#131970) unblock tree from https://github.com/flutter/flutter/issues/131968 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 3e60fbbfd0e60..109407119a201 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -245,6 +245,7 @@ targets: presubmit: false recipe: pub_autoroller/pub_autoroller timeout: 30 + bringup: true # https://github.com/flutter/flutter/issues/131968 enabled_branches: # Don't run this on release branches - master From 45383deffa7c7b648dfc6eeb11d86de04bb3f1be Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:18:10 -0700 Subject: [PATCH 0548/1547] Mark the ci_yaml roller task so that it is not backfilled. (#131966) In order to avoid new tasks from not being scheduled we are not going to backfill the autoroller because it can sometimes play transactions out of order causing issues with tasks that are scheduled but not known. *List which issues are fixed by this PR. You must list at least one issue.* Part of https://github.com/flutter/flutter/issues/127063 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 109407119a201..1e5874e72e65d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -333,6 +333,7 @@ targets: properties: tags: > ["framework", "hostonly", "shard", "linux"] + backfill: "false" runIf: - .ci.yaml From 0da0479702ca2b803529d489efba68f89f61e98f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 21:22:17 -0400 Subject: [PATCH 0549/1547] Manual roll Flutter Engine from 4f4734cd48da to a0d650e37f5d (3 revisions) (#131967) Manual roll requested by jacksongardner@google.com Cannot build log URL because revision "a0d650e37f5d" is invalid: Luci builds of "Linux Web Framework tests" for a0d650e37f5d715468d8797519c622998ff5ab27 was FAILURE 2023-08-04 skia-flutter-autoroll@skia.org Roll Dart SDK from a0b59bac20fc to 8a3277696c52 (1 revision) (flutter/engine#44405) 2023-08-04 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ZvUiUZL9vUp2LcvHG... to 3uzA1Z-yaMQE_Cz5f... (flutter/engine#44403) 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 6dc76e862f90 to 7cf7e2da3557 (1 revision) (flutter/engine#44402) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ZvUiUZL9vUp2 to 3uzA1Z-yaMQE If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- dev/tracing_tests/test/common.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1942f3dd99b54..f0e194ccfb948 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4f4734cd48da77d757f492b0f55b99dda6cee815 +a0d650e37f5d715468d8797519c622998ff5ab27 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 2cdc362fe1e10..494f0427bacda 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ZvUiUZL9vUp2LcvHGHnjFis6tKvXuAzUQe5Ax_6XLCsC +3uzA1Z-yaMQE_Cz5fKhxhQDh2rPVHRfbeldiVBTH0GEC diff --git a/dev/tracing_tests/test/common.dart b/dev/tracing_tests/test/common.dart index 29a60372a3763..7c534348805cd 100644 --- a/dev/tracing_tests/test/common.dart +++ b/dev/tracing_tests/test/common.dart @@ -26,7 +26,7 @@ void initTimelineTests() { } _vmService = await vmServiceConnectUri('ws://localhost:${info.serverUri!.port}${info.serverUri!.path}ws'); await _vmService.setVMTimelineFlags(['Dart']); - isolateId = developer.Service.getIsolateID(isolate.Isolate.current)!; + isolateId = developer.Service.getIsolateId(isolate.Isolate.current)!; }); } From d5f8ca7281df77fae69b0cb254cfab2d90580f4a Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 4 Aug 2023 18:28:03 -0700 Subject: [PATCH 0550/1547] Add TODO to refactor error handling. (#131878) --- packages/flutter/lib/src/foundation/stack_frame.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/flutter/lib/src/foundation/stack_frame.dart b/packages/flutter/lib/src/foundation/stack_frame.dart index fc126821fe9f7..8a2f0d61945f4 100644 --- a/packages/flutter/lib/src/foundation/stack_frame.dart +++ b/packages/flutter/lib/src/foundation/stack_frame.dart @@ -78,6 +78,9 @@ class StackFrame { // On the Web in non-debug builds the stack trace includes the exception // message that precedes the stack trace itself. fromStackTraceLine will // return null in that case. We will skip it here. + // TODO(polina-c): if one of lines was parsed to null, the entire stack trace + // is in unexpected format and should be returned as is, without partial parsing. + // https://github.com/flutter/flutter/issues/131877 .whereType() .toList(); } From 57ebf3739278db29d7dd647d52019c3da0ebeecd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 4 Aug 2023 22:39:23 -0400 Subject: [PATCH 0551/1547] Roll Flutter Engine from a0d650e37f5d to 138a1ea9a692 (2 revisions) (#131972) https://github.com/flutter/engine/compare/a0d650e37f5d...138a1ea9a692 2023-08-04 skia-flutter-autoroll@skia.org Roll Skia from 7cf7e2da3557 to b2a0382bb587 (1 revision) (flutter/engine#44407) 2023-08-04 chris@bracken.jp [Darwin] Move FlutterBinaryMessengerRelay to common (flutter/engine#44395) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f0e194ccfb948..8d1e1dd181ba4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a0d650e37f5d715468d8797519c622998ff5ab27 +138a1ea9a69235342f479d61399fe7394fc1f3cb From 317f788a60644b0bcd133d508b033aa7094fd44a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 5 Aug 2023 00:09:27 -0400 Subject: [PATCH 0552/1547] Roll Flutter Engine from 138a1ea9a692 to 7302a678e58e (2 revisions) (#131975) https://github.com/flutter/engine/compare/138a1ea9a692...7302a678e58e 2023-08-05 skia-flutter-autoroll@skia.org Roll Skia from b2a0382bb587 to 275bcb6d874d (3 revisions) (flutter/engine#44413) 2023-08-05 32242716+ricardoamador@users.noreply.github.com Mark the ci.yaml roller task so it is not backfilled. (flutter/engine#44409) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8d1e1dd181ba4..1e25d377a6509 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -138a1ea9a69235342f479d61399fe7394fc1f3cb +7302a678e58ef8dac45f6a3e027c2dde841db857 From 26c198c15766eb8b6514426a49f06772585e0535 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 5 Aug 2023 01:13:24 -0400 Subject: [PATCH 0553/1547] Roll Flutter Engine from 7302a678e58e to 628b086265f2 (1 revision) (#131976) https://github.com/flutter/engine/compare/7302a678e58e...628b086265f2 2023-08-05 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from jMLeVECzwzDoe9dYS... to UpzOzWyiGYKrIuKmG... (flutter/engine#44414) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from jMLeVECzwzDo to UpzOzWyiGYKr If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1e25d377a6509..1874f69e9fdd7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7302a678e58ef8dac45f6a3e027c2dde841db857 +628b086265f2b68718721ee65c5c86daca044c99 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 57b73e3ce3c1e..07aef53add799 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -jMLeVECzwzDoe9dYSKqrkHFMapXsDwwcFRAOp3FGf3sC +UpzOzWyiGYKrIuKmG4iYsnQtEOaG6GKsiUyMOS2fPzIC From e1f56f18c4b0cad8b24c5f8d544c6aebab7915c1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 5 Aug 2023 07:22:33 -0400 Subject: [PATCH 0554/1547] Roll Flutter Engine from 628b086265f2 to 2ce2913acbe4 (1 revision) (#131983) https://github.com/flutter/engine/compare/628b086265f2...2ce2913acbe4 2023-08-05 skia-flutter-autoroll@skia.org Roll Dart SDK from 8a3277696c52 to 0816d590a220 (1 revision) (flutter/engine#44415) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1874f69e9fdd7..01b35b5a14f0c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -628b086265f2b68718721ee65c5c86daca044c99 +2ce2913acbe4bb2309fd3fe3d2c2c0785100051d From 53609ef83811b587c11e9e4b07298d25dbbb20e3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 5 Aug 2023 08:40:33 -0400 Subject: [PATCH 0555/1547] Roll Flutter Engine from 2ce2913acbe4 to d26b8c8fb60c (1 revision) (#131986) https://github.com/flutter/engine/compare/2ce2913acbe4...d26b8c8fb60c 2023-08-05 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 3uzA1Z-yaMQE_Cz5f... to QazMbN_0ttbJpf36s... (flutter/engine#44418) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 3uzA1Z-yaMQE to QazMbN_0ttbJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 01b35b5a14f0c..8c73c963ee3b4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2ce2913acbe4bb2309fd3fe3d2c2c0785100051d +d26b8c8fb60c7eb815635bd2ec731cda0f16efcd diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 494f0427bacda..415f3f649d932 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -3uzA1Z-yaMQE_Cz5fKhxhQDh2rPVHRfbeldiVBTH0GEC +QazMbN_0ttbJpf36sBFAVqaW8mgcs5tOP-B6OYvkCl8C From 545ecd29f2da8395dbf8156a70baea041f69f29e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 5 Aug 2023 09:32:33 -0400 Subject: [PATCH 0556/1547] Roll Flutter Engine from d26b8c8fb60c to b512df490c94 (1 revision) (#131987) https://github.com/flutter/engine/compare/d26b8c8fb60c...b512df490c94 2023-08-05 skia-flutter-autoroll@skia.org Roll Skia from 275bcb6d874d to 1d390344bfca (1 revision) (flutter/engine#44419) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8c73c963ee3b4..2aefa14175ebd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d26b8c8fb60c7eb815635bd2ec731cda0f16efcd +b512df490c94f725799a1ffe5934f8b6c020e367 From bc4cacac0d348a2420a4494422a5d91b3338947e Mon Sep 17 00:00:00 2001 From: Tomasz Gucio <72562119+tgucio@users.noreply.github.com> Date: Sat, 5 Aug 2023 15:36:54 +0200 Subject: [PATCH 0557/1547] Take paint offset into account for inline children hit test in Editable (#131675) --- .../flutter/lib/src/rendering/editable.dart | 4 +- .../flutter/test/rendering/editable_test.dart | 83 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index d03d5f6b2d428..7952912b1b4bb 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -1916,9 +1916,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, @override @protected bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { + final Offset effectivePosition = position - _paintOffset; final InlineSpan? textSpan = _textPainter.text; if (textSpan != null) { - final Offset effectivePosition = position - _paintOffset; final TextPosition textPosition = _textPainter.getPositionForOffset(effectivePosition); final Object? span = textSpan.getSpanForPosition(textPosition); if (span is HitTestTarget) { @@ -1926,7 +1926,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, return true; } } - return hitTestInlineChildren(result, position); + return hitTestInlineChildren(result, effectivePosition); } late TapGestureRecognizer _tap; diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index 118f1adbf694b..d859ec1c63c92 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -1721,6 +1721,89 @@ void main() { editable.hitTest(result, position: const Offset(5.0, 15.0)); expect(result.path, hasLength(0)); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61020 + + test('hits correct WidgetSpan when scrolled', () { + final String text = '${"\n" * 10}test'; + final TextSelectionDelegate delegate = _FakeEditableTextState() + ..textEditingValue = TextEditingValue( + text: text, + selection: const TextSelection.collapsed(offset: 13), + ); + final List renderBoxes = [ + RenderParagraph(const TextSpan(text: 'a'), textDirection: TextDirection.ltr), + RenderParagraph(const TextSpan(text: 'b'), textDirection: TextDirection.ltr), + RenderParagraph(const TextSpan(text: 'c'), textDirection: TextDirection.ltr), + ]; + final RenderEditable editable = RenderEditable( + maxLines: null, + text: TextSpan( + style: const TextStyle(height: 1.0, fontSize: 10.0), + children: [ + TextSpan(text: text), + const WidgetSpan(child: Text('a')), + const TextSpan(children: [ + WidgetSpan(child: Text('b')), + WidgetSpan(child: Text('c')), + ], + ), + ], + ), + startHandleLayerLink: LayerLink(), + endHandleLayerLink: LayerLink(), + textDirection: TextDirection.ltr, + offset: ViewportOffset.fixed(100.0), // equal to the height of the 10 empty lines + textSelectionDelegate: delegate, + selection: const TextSelection.collapsed( + offset: 0, + ), + children: renderBoxes, + ); + _applyParentData(renderBoxes, editable.text!); + layout(editable, constraints: BoxConstraints.loose(const Size(500.0, 500.0))); + // Prepare for painting after layout. + pumpFrame(phase: EnginePhase.compositingBits); + BoxHitTestResult result = BoxHitTestResult(); + editable.hitTest(result, position: Offset.zero); + // We expect two hit test entries in the path because the RenderEditable + // will add itself as well. + expect(result.path, hasLength(2)); + HitTestTarget target = result.path.first.target; + expect(target, isA()); + expect((target as TextSpan).text, text); + // Only testing the RenderEditable entry here once, not anymore below. + expect(result.path.last.target, isA()); + result = BoxHitTestResult(); + editable.hitTest(result, position: const Offset(15.0, 0.0)); + expect(result.path, hasLength(2)); + target = result.path.first.target; + expect(target, isA()); + expect((target as TextSpan).text, text); + + result = BoxHitTestResult(); + editable.hitTest(result, position: const Offset(41.0, 0.0)); + expect(result.path, hasLength(3)); + target = result.path.first.target; + expect(target, isA()); + expect((target as TextSpan).text, 'a'); + + result = BoxHitTestResult(); + editable.hitTest(result, position: const Offset(55.0, 0.0)); + expect(result.path, hasLength(3)); + target = result.path.first.target; + expect(target, isA()); + expect((target as TextSpan).text, 'b'); + + result = BoxHitTestResult(); + editable.hitTest(result, position: const Offset(69.0, 5.0)); + expect(result.path, hasLength(3)); + target = result.path.first.target; + expect(target, isA()); + expect((target as TextSpan).text, 'c'); + + result = BoxHitTestResult(); + editable.hitTest(result, position: const Offset(5.0, 15.0)); + expect(result.path, hasLength(2)); + }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61020 }); test('does not skip TextPainter.layout because of invalid cache', () { From c09a9b4c46a27bb35d98477814587da4c9baffc2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 5 Aug 2023 19:20:34 -0400 Subject: [PATCH 0558/1547] Roll Flutter Engine from b512df490c94 to cdafc05a7217 (1 revision) (#131996) https://github.com/flutter/engine/compare/b512df490c94...cdafc05a7217 2023-08-05 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from UpzOzWyiGYKrIuKmG... to 4pA5pP6XaVIJBXuq0... (flutter/engine#44420) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from UpzOzWyiGYKr to 4pA5pP6XaVIJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2aefa14175ebd..1d01a599667d7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b512df490c94f725799a1ffe5934f8b6c020e367 +cdafc05a7217fbaeccb52b9ee26f2690e06eb67e diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 07aef53add799..e98aff67ee19d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -UpzOzWyiGYKrIuKmG4iYsnQtEOaG6GKsiUyMOS2fPzIC +4pA5pP6XaVIJBXuq00d8de0RMcWZKPakoxE66Emo_U0C From 91d64391f014b48a15c1a6e3b749628d095365e0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 6 Aug 2023 02:47:35 -0400 Subject: [PATCH 0559/1547] Roll Flutter Engine from cdafc05a7217 to af7aaae2f1f9 (2 revisions) (#132004) https://github.com/flutter/engine/compare/cdafc05a7217...af7aaae2f1f9 2023-08-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 4pA5pP6XaVIJBXuq0... to iY3v8FawLUo9HvTeR... (flutter/engine#44422) 2023-08-05 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from QazMbN_0ttbJpf36s... to E0vw_CD-BaFAcSoH4... (flutter/engine#44421) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from QazMbN_0ttbJ to E0vw_CD-BaFA fuchsia/sdk/core/mac-amd64 from 4pA5pP6XaVIJ to iY3v8FawLUo9 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1d01a599667d7..e0ec106e65412 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cdafc05a7217fbaeccb52b9ee26f2690e06eb67e +af7aaae2f1f9b287183a35ce30b938b44a779b81 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 415f3f649d932..304dd60dcd1fe 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -QazMbN_0ttbJpf36sBFAVqaW8mgcs5tOP-B6OYvkCl8C +E0vw_CD-BaFAcSoH4dY6vm3vqhbQAoDZJHQZ5LF2-i8C diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index e98aff67ee19d..d6c5e754c2b31 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -4pA5pP6XaVIJBXuq00d8de0RMcWZKPakoxE66Emo_U0C +iY3v8FawLUo9HvTeRJLJ5HJsqCjAIW2MtSx8u26cffQC From 11d9846074a38e9e46c30604aea52f01aaedd546 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 6 Aug 2023 06:11:24 -0400 Subject: [PATCH 0560/1547] Roll Flutter Engine from af7aaae2f1f9 to 060c95f94364 (1 revision) (#132006) https://github.com/flutter/engine/compare/af7aaae2f1f9...060c95f94364 2023-08-06 skia-flutter-autoroll@skia.org Roll Skia from 1d390344bfca to 72264deb9f05 (1 revision) (flutter/engine#44423) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e0ec106e65412..e702e98c48ecb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -af7aaae2f1f9b287183a35ce30b938b44a779b81 +060c95f94364c4e6382a005754648340c4112869 From 310e911466945aede7515d5ad288bf4048b4a601 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 6 Aug 2023 08:45:22 -0400 Subject: [PATCH 0561/1547] Roll Flutter Engine from 060c95f94364 to c9bd380ccbb0 (1 revision) (#132008) https://github.com/flutter/engine/compare/060c95f94364...c9bd380ccbb0 2023-08-06 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from E0vw_CD-BaFAcSoH4... to fwCoUCWKEqZSJGPE8... (flutter/engine#44424) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from E0vw_CD-BaFA to fwCoUCWKEqZS If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e702e98c48ecb..81e7c9c37ca9c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -060c95f94364c4e6382a005754648340c4112869 +c9bd380ccbb0e1a177e6a2a9bb7313e943697d58 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 304dd60dcd1fe..27017cefe7ea7 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -E0vw_CD-BaFAcSoH4dY6vm3vqhbQAoDZJHQZ5LF2-i8C +fwCoUCWKEqZSJGPE8ON7RxiilHiQ0NjHa4VkQ8IrLrMC From ecef964a2e59c6fe38b514460d6a8ba29b997b2c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 6 Aug 2023 15:21:24 -0400 Subject: [PATCH 0562/1547] Roll Flutter Engine from c9bd380ccbb0 to a1d513f78bbb (1 revision) (#132015) https://github.com/flutter/engine/compare/c9bd380ccbb0...a1d513f78bbb 2023-08-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from iY3v8FawLUo9HvTeR... to 9QyQ03F49oT_9slFF... (flutter/engine#44425) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from iY3v8FawLUo9 to 9QyQ03F49oT_ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 81e7c9c37ca9c..5db1a412de1ae 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c9bd380ccbb0e1a177e6a2a9bb7313e943697d58 +a1d513f78bbb1a3a425d0dda7c2c6fd5a4cf0ca0 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index d6c5e754c2b31..1f7888cad39db 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -iY3v8FawLUo9HvTeRJLJ5HJsqCjAIW2MtSx8u26cffQC +9QyQ03F49oT_9slFF9rw-QsLc2iRS73Zur8YEaBih9AC From bfbe79feb2d864f9fe45d1d8276222d2697ab691 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 6 Aug 2023 21:47:34 -0400 Subject: [PATCH 0563/1547] Roll Flutter Engine from a1d513f78bbb to 15b5707af406 (2 revisions) (#132020) https://github.com/flutter/engine/compare/a1d513f78bbb...15b5707af406 2023-08-07 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from fwCoUCWKEqZSJGPE8... to zVfdIYcZ93Loob7VG... (flutter/engine#44428) 2023-08-06 skia-flutter-autoroll@skia.org Roll Skia from 72264deb9f05 to 9c4cfcd16529 (1 revision) (flutter/engine#44427) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from fwCoUCWKEqZS to zVfdIYcZ93Lo If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5db1a412de1ae..0be8d62fd12e1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a1d513f78bbb1a3a425d0dda7c2c6fd5a4cf0ca0 +15b5707af40644516e62df4457c4e9d6ac7c21c2 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 27017cefe7ea7..4536fc2c48699 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -fwCoUCWKEqZSJGPE8ON7RxiilHiQ0NjHa4VkQ8IrLrMC +zVfdIYcZ93Loob7VGT5tEssH6U3u-V2Z2LMhkYBSSi0C From 7de053b2b8108e35b7769b558da86fde44f640e9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 03:51:33 -0400 Subject: [PATCH 0564/1547] Roll Flutter Engine from 15b5707af406 to eb91441398a1 (1 revision) (#132025) https://github.com/flutter/engine/compare/15b5707af406...eb91441398a1 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 9c4cfcd16529 to b7a1f4fdedc1 (2 revisions) (flutter/engine#44430) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0be8d62fd12e1..19fb49bcdfd65 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -15b5707af40644516e62df4457c4e9d6ac7c21c2 +eb91441398a114bb0bcedb1b4d7e34dd74b12e6b From 55044a605fed74532d0f709fa437acc2adcc24dd Mon Sep 17 00:00:00 2001 From: Tomasz Gucio <72562119+tgucio@users.noreply.github.com> Date: Mon, 7 Aug 2023 10:28:07 +0200 Subject: [PATCH 0565/1547] Constrain _RenderScaledInlineWidget child size in computeDryLayout (#131765) --- packages/flutter/lib/src/widgets/widget_span.dart | 2 +- packages/flutter/test/widgets/text_test.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/widgets/widget_span.dart b/packages/flutter/lib/src/widgets/widget_span.dart index 65427e7ed2d3b..242cb3033c4ad 100644 --- a/packages/flutter/lib/src/widgets/widget_span.dart +++ b/packages/flutter/lib/src/widgets/widget_span.dart @@ -385,7 +385,7 @@ class _RenderScaledInlineWidget extends RenderBox with RenderObjectWithChildMixi Size computeDryLayout(BoxConstraints constraints) { assert(!constraints.hasBoundedHeight); final Size unscaledSize = child?.computeDryLayout(BoxConstraints(maxWidth: constraints.maxWidth / scale)) ?? Size.zero; - return unscaledSize * scale; + return constraints.constrain(unscaledSize * scale); } @override diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index c535fbd9c52de..5c2f69694c10d 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -273,8 +273,8 @@ void main() { textDirection: TextDirection.ltr, child: Center( child: SizedBox( - width: 100.3, - child: Text.rich(WidgetSpan(child: Row()), textScaleFactor: 0.3), + width: 502.5454545454545, + child: Text.rich(WidgetSpan(child: Row()), textScaleFactor: 0.95), ), ), ), From fd61c4a40591d36be63cef00358ee3b21cb1ca70 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 04:43:29 -0400 Subject: [PATCH 0566/1547] Roll Flutter Engine from eb91441398a1 to 4304d6180264 (1 revision) (#132031) https://github.com/flutter/engine/compare/eb91441398a1...4304d6180264 2023-08-07 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 9QyQ03F49oT_9slFF... to mlT1Bm0L9bVynvMFF... (flutter/engine#44431) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 9QyQ03F49oT_ to mlT1Bm0L9bVy If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 19fb49bcdfd65..6e89bfe884c98 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -eb91441398a114bb0bcedb1b4d7e34dd74b12e6b +4304d6180264dad645367edcf7612fc501b35ad1 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 1f7888cad39db..e0ff642b4a706 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -9QyQ03F49oT_9slFF9rw-QsLc2iRS73Zur8YEaBih9AC +mlT1Bm0L9bVynvMFF3lpUMOuUpsv0P8aWBdkIb3UmWYC From c11ac7be9a3dd443ab9bbc83681db14b357690a1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 05:43:32 -0400 Subject: [PATCH 0567/1547] Roll Flutter Engine from 4304d6180264 to b10891e0d8d8 (1 revision) (#132037) https://github.com/flutter/engine/compare/4304d6180264...b10891e0d8d8 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from b7a1f4fdedc1 to 558d9754241d (1 revision) (flutter/engine#44432) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6e89bfe884c98..6a28dccba8c89 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4304d6180264dad645367edcf7612fc501b35ad1 +b10891e0d8d84793563e955f358b4ad4799f1df7 From ad0aa8de75120f532463e493d5671cb72354250b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 07:21:39 -0400 Subject: [PATCH 0568/1547] Roll Flutter Engine from b10891e0d8d8 to 5b47c0577060 (1 revision) (#132040) https://github.com/flutter/engine/compare/b10891e0d8d8...5b47c0577060 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 558d9754241d to f4047f002891 (1 revision) (flutter/engine#44433) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6a28dccba8c89..7253fac8e36a8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b10891e0d8d84793563e955f358b4ad4799f1df7 +5b47c05770609a6f10d84e624c43c94bc7b4de4d From 122c42951a042d452dff5fe920d30137ab795c51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 11:49:03 -0400 Subject: [PATCH 0569/1547] Roll Packages from ce53da1bd741 to d7ee75ad59ad (7 revisions) (#132058) https://github.com/flutter/packages/compare/ce53da1bd741...d7ee75ad59ad 2023-08-05 stuartmorgan@google.com [tool] Skip pathified analysis on resolver errors (flutter/packages#4647) 2023-08-05 stuartmorgan@google.com [ci] Remove tools from Dockerfile (flutter/packages#4649) 2023-08-05 32242716+ricardoamador@users.noreply.github.com Update to not backfill the ci.yaml roller task. (flutter/packages#4651) 2023-08-04 stuartmorgan@google.com [pigeon] Consolidate mock handler tests (flutter/packages#4642) 2023-08-04 stuartmorgan@google.com [camera_web] Adopt code excerpts in README (flutter/packages#4584) 2023-08-04 stuartmorgan@google.com [image_picker] Allows 3.0 web implementation (flutter/packages#4648) 2023-08-04 engine-flutter-autoroll@skia.org Roll Flutter from c00d241938b1 to 2ba9f7bdfe16 (25 revisions) (flutter/packages#4646) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 2fc596952bc8d..71499212697b0 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -ce53da1bd7411f1d356706363fdb42c55d7c4cc8 +d7ee75ad59ad7bc45e659d0599e935e9e7981ea1 From 06ca902dfcb9647d54031500c7327989d5298344 Mon Sep 17 00:00:00 2001 From: Mingyu Date: Tue, 8 Aug 2023 00:03:23 +0800 Subject: [PATCH 0570/1547] Slider should check `mounted` before start interaction (#132010) This is a follow up to the following pull requests: - https://github.com/flutter/flutter/pull/124514 I was finally able to reproduce this bug and found out why it was happening. Consider this code: ```dart GestureDetector( behavior: HitTestBehavior.translucent, // Note: Make sure onTap is not null to ensure events // are captured by `GestureDetector` onTap: () {}, child: _shouldShowSlider ? Slider(value: _value, onChanged: _handleSlide) : const SizedBox.shrink(). ) ``` Runtime exception happens when: 1. User taps and holds the Slider (drag callback captured by `GestureDetector`) 2. `_shouldShowSlider` changes to false, Slider disappears and unmounts, and unregisters `_handleSlide`. But the callback is still registered by `GestureDetector` 3. Users moves finger as if Slider were still there 4. Drag callback is invoked, `_SliderState.showValueIndicator` is called 5. Exception - Slider is already disposed This pull request fixes it by adding a mounted check inside `_SliderState.showValueIndicator` to ensure the Slider is actually mounted at the time of invoking drag event callback. I've added a unit test that will fail without this change. The error stack trace is: ``` The following assertion was thrown while handling a gesture: This widget has been unmounted, so the State no longer has a context (and should be considered defunct). Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active. When the exception was thrown, this was the stack: #0 State.context. (package:flutter/src/widgets/framework.dart:950:9) #1 State.context (package:flutter/src/widgets/framework.dart:956:6) #2 _SliderState.showValueIndicator (package:flutter/src/material/slider.dart:968:18) #3 _RenderSlider._startInteraction (package:flutter/src/material/slider.dart:1487:12) #4 _RenderSlider._handleDragStart (package:flutter/src/material/slider.dart:1541:5) #5 DragGestureRecognizer._checkStart. (package:flutter/src/gestures/monodrag.dart:531:53) #6 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:275:24) #7 DragGestureRecognizer._checkStart (package:flutter/src/gestures/monodrag.dart:531:7) #8 DragGestureRecognizer._checkDrag (package:flutter/src/gestures/monodrag.dart:498:5) #9 DragGestureRecognizer.acceptGesture (package:flutter/src/gestures/monodrag.dart:431:7) #10 _CombiningGestureArenaMember.acceptGesture (package:flutter/src/gestures/team.dart:45:14) #11 GestureArenaManager._resolveInFavorOf (package:flutter/src/gestures/arena.dart:281:12) #12 GestureArenaManager._resolve (package:flutter/src/gestures/arena.dart:239:9) #13 GestureArenaEntry.resolve (package:flutter/src/gestures/arena.dart:53:12) #14 _CombiningGestureArenaMember._resolve (package:flutter/src/gestures/team.dart:85:15) #15 _CombiningGestureArenaEntry.resolve (package:flutter/src/gestures/team.dart:19:15) #16 OneSequenceGestureRecognizer.resolve (package:flutter/src/gestures/recognizer.dart:375:13) #17 DragGestureRecognizer.handleEvent (package:flutter/src/gestures/monodrag.dart:414:13) #18 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:98:12) #19 PointerRouter._dispatchEventToRoutes. (package:flutter/src/gestures/pointer_router.dart:143:9) #20 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13) #21 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:141:18) #22 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:127:7) #23 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:488:19) #24 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:468:22) #25 RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:439:11) #26 GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:413:7) #27 GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:376:5) #28 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:323:7) #29 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:292:9) #30 _invoke1 (dart:ui/hooks.dart:186:13) #31 PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:433:7) #32 _dispatchPointerDataPacket (dart:ui/hooks.dart:119:31) Handler: "onStart" Recognizer: HorizontalDragGestureRecognizer#a5df2 ``` *List which issues are fixed by this PR. You must list at least one issue.* Internal bug: b/273666179, b/192329942 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- packages/flutter/lib/src/material/slider.dart | 3 ++ .../flutter/test/material/slider_test.dart | 43 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 61acbf04eee65..34b806c87c64e 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -1484,6 +1484,9 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { } void _startInteraction(Offset globalPosition) { + if (!_state.mounted) { + return; + } _state.showValueIndicator(); if (!_active && isInteractive) { switch (allowedInteraction) { diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index a8bf69325ccea..3b7de2c878590 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -3654,16 +3654,22 @@ void main() { child: ValueListenableBuilder( valueListenable: shouldShowSliderListenable, builder: (BuildContext context, bool shouldShowSlider, _) { - return shouldShowSlider - ? Slider( - value: value, - onChanged: (double newValue) { - setState(() { - value = newValue; - }); - }, - ) - : const SizedBox.shrink(); + return GestureDetector( + behavior: HitTestBehavior.translucent, + // Note: it is important that `onTap` is non-null so + // [GestureDetector] will register tap events. + onTap: () {}, + child: shouldShowSlider + ? Slider( + value: value, + onChanged: (double newValue) { + setState(() { + value = newValue; + }); + }, + ) + : const SizedBox.expand(), + ); }, ), ), @@ -3674,20 +3680,19 @@ void main() { ), ); + // Move Slider. final TestGesture gesture = await tester - .startGesture(tester.getRect(find.byType(Slider)).centerLeft); + .startGesture(tester.getRect(find.byType(Slider)).center); + await gesture.moveBy(const Offset(1.0, 0.0)); + await tester.pumpAndSettle(); - // Intentionally not calling `await tester.pumpAndSettle()` to allow drag - // event performed on `Slider` before it is about to get unmounted. + // Hide Slider. Slider will dispose and unmount. shouldShowSliderListenable.value = false; - - await tester.drag(find.byType(Slider), const Offset(1.0, 0.0)); await tester.pumpAndSettle(); - expect(value, equals(0.0)); - - // This is supposed to trigger animation on `Slider` if it is mounted. - await gesture.up(); + // Move Slider after unmounted. + await gesture.moveBy(const Offset(1.0, 0.0)); + await tester.pumpAndSettle(); expect(tester.takeException(), null); }); From 1a31682e6cf8ed8c5e1614ca332d60880867f168 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 12:04:53 -0400 Subject: [PATCH 0571/1547] Roll Flutter Engine from 5b47c0577060 to 39ce1c097bce (3 revisions) (#132057) https://github.com/flutter/engine/compare/5b47c0577060...39ce1c097bce 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 7a98630e0de9 to e327eb094605 (2 revisions) (flutter/engine#44437) 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from f4047f002891 to 7a98630e0de9 (1 revision) (flutter/engine#44436) 2023-08-07 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from zVfdIYcZ93Loob7VG... to 0Jd9VPJCX145RGnqr... (flutter/engine#44435) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from zVfdIYcZ93Lo to 0Jd9VPJCX145 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7253fac8e36a8..9968714ddb5a8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5b47c05770609a6f10d84e624c43c94bc7b4de4d +39ce1c097bcede18ede792ac1f6c10a5155fa6d5 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 4536fc2c48699..7d661b23979cd 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -zVfdIYcZ93Loob7VGT5tEssH6U3u-V2Z2LMhkYBSSi0C +0Jd9VPJCX145RGnqrZ-yxgc9-QoGboEeDDGf8cbwiyMC From ff5b0e1457ba25b4cc82e86a4e1573d23bd2de73 Mon Sep 17 00:00:00 2001 From: xhzq233 Date: Tue, 8 Aug 2023 00:30:21 +0800 Subject: [PATCH 0572/1547] CupertinoContextMenu improvement (#131030) Fixes overlapping gestures in CupertinoContextMenu's subtree --- .../lib/src/cupertino/context_menu.dart | 23 +++--- .../test/cupertino/context_menu_test.dart | 71 +++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index 1a98cf5bf4e43..da2aed2a092a8 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -6,7 +6,7 @@ import 'dart:math' as math; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart' show kMinFlingVelocity; +import 'package:flutter/gestures.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart' show HapticFeedback; import 'package:flutter/widgets.dart'; @@ -480,6 +480,7 @@ class _CupertinoContextMenuState extends State with Ticker OverlayEntry? _lastOverlayEntry; _ContextMenuRoute? _route; final double _midpoint = CupertinoContextMenu.animationOpensAt / 2; + late final TapGestureRecognizer _tapGestureRecognizer; @override void initState() { @@ -490,13 +491,20 @@ class _CupertinoContextMenuState extends State with Ticker upperBound: CupertinoContextMenu.animationOpensAt, ); _openController.addStatusListener(_onDecoyAnimationStatusChange); + _tapGestureRecognizer = TapGestureRecognizer() + ..onTapCancel = _onTapCancel + ..onTapDown = _onTapDown + ..onTapUp = _onTapUp + ..onTap = _onTap; } void _listenerCallback() { if (_openController.status != AnimationStatus.reverse && - _openController.value >= _midpoint && - widget.enableHapticFeedback) { - HapticFeedback.heavyImpact(); + _openController.value >= _midpoint) { + if (widget.enableHapticFeedback) { + HapticFeedback.heavyImpact(); + } + _tapGestureRecognizer.resolve(GestureDisposition.accepted); _openController.removeListener(_listenerCallback); } } @@ -663,11 +671,8 @@ class _CupertinoContextMenuState extends State with Ticker Widget build(BuildContext context) { return MouseRegion( cursor: kIsWeb ? SystemMouseCursors.click : MouseCursor.defer, - child: GestureDetector( - onTapCancel: _onTapCancel, - onTapDown: _onTapDown, - onTapUp: _onTapUp, - onTap: _onTap, + child: Listener( + onPointerDown: _tapGestureRecognizer.addPointer, child: TickerMode( enabled: !_childHidden, child: Visibility.maintain( diff --git a/packages/flutter/test/cupertino/context_menu_test.dart b/packages/flutter/test/cupertino/context_menu_test.dart index 146b15192b6e0..06817cbb3b67b 100644 --- a/packages/flutter/test/cupertino/context_menu_test.dart +++ b/packages/flutter/test/cupertino/context_menu_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:clock/clock.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -810,4 +811,74 @@ void main() { expect(right.dx, lessThan(left.dx)); }); }); + + testWidgets('Conflicting gesture detectors', (WidgetTester tester) async { + int? onPointerDownTime; + int? onPointerUpTime; + bool insideTapTriggered = false; + // The required duration of the route to be pushed in is [500, 900]ms. + // 500ms is calculated from kPressTimeout+_previewLongPressTimeout/2. + // 900ms is calculated from kPressTimeout+_previewLongPressTimeout. + const Duration pressDuration = Duration(milliseconds: 501); + + int now() => clock.now().millisecondsSinceEpoch; + + await tester.pumpWidget(Listener( + onPointerDown: (PointerDownEvent event) => onPointerDownTime = now(), + onPointerUp: (PointerUpEvent event) => onPointerUpTime = now(), + child: CupertinoApp( + home: Align( + child: CupertinoContextMenu( + actions: const [ + CupertinoContextMenuAction( + child: Text('CupertinoContextMenuAction'), + ), + ], + child: GestureDetector( + onTap: () => insideTapTriggered = true, + child: Container( + width: 200, + height: 200, + key: const Key('container'), + color: const Color(0xFF00FF00), + ), + ), + ), + ), + ), + )); + + // Start a press on the child. + final TestGesture gesture = await tester.createGesture(); + await gesture.down(tester.getCenter(find.byKey(const Key('container')))); + // Simulate the actual situation: + // the user keeps pressing and requesting frames. + // If there is only one frame, + // the animation is mutant and cannot drive the value of the animation controller. + for (int i = 0; i < 100; i++) { + await tester.pump(pressDuration ~/ 100); + } + await gesture.up(); + // Await pushing route. + await tester.pumpAndSettle(); + + // Judge whether _ContextMenuRouteStatic present on the screen. + final Finder routeStatic = find.byWidgetPredicate( + (Widget w) => '${w.runtimeType}' == '_ContextMenuRouteStatic', + ); + + // The insideTap and the route should not be triggered at the same time. + if (insideTapTriggered) { + // Calculate the actual duration. + final int actualDuration = onPointerUpTime! - onPointerDownTime!; + + expect(routeStatic, findsNothing, + reason: 'When actualDuration($actualDuration) is in the range of 500ms~900ms, ' + 'which means the route is pushed, ' + 'but insideTap should not be triggered at the same time.'); + } else { + // The route should be pushed when the insideTap is not triggered. + expect(routeStatic, findsOneWidget); + } + }); } From 9cc4f94397f1f4b4d49ff38a02e5a0708dc9d68e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 13:00:25 -0400 Subject: [PATCH 0573/1547] Roll Flutter Engine from 39ce1c097bce to 39a575f65d50 (2 revisions) (#132064) https://github.com/flutter/engine/compare/39ce1c097bce...39a575f65d50 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from e327eb094605 to 359808ec2cb1 (2 revisions) (flutter/engine#44438) 2023-08-07 jason-simmons@users.noreply.github.com Do not log exceptions from JNI lookups of APIs that are known to be unavailable on older devices (flutter/engine#44357) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9968714ddb5a8..2e563364eb0bd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -39ce1c097bcede18ede792ac1f6c10a5155fa6d5 +39a575f65d50b8bedf52dc2be35aed85b3c690c2 From ebbb4b3887e54b171892e7872254bdf7990242c9 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 7 Aug 2023 13:59:08 -0700 Subject: [PATCH 0574/1547] Android context menu theming and visual update (#131816) Fixes https://github.com/flutter/flutter/issues/89939 and updates the look of the Android context menu to match API 34. ## The problem Before this PR, setting `surface` in the color scheme caused the background color of the Android context menu to change, but it wasn't possible to change the text color. ```dart MaterialApp( theme: ThemeData( // Using a dark theme made the context menu text color be white. colorScheme: ThemeData.dark().colorScheme.copyWith( // Setting the surface here worked. surface: Colors.white, // But there was no way to set the text color. This didn't work. onSurface: Colors.black, ), ), ), ``` | Expected (after PR) | Actual (before PR) | | --- | --- | | Screenshot 2023-08-07 at 11 45 37 AM | Screenshot 2023-08-07 at 11 51 10 AM | ## Other examples
Scenario Result
```dart MaterialApp( theme: ThemeData( colorScheme: ThemeData.light(), ), ... ), ``` Screenshot 2023-08-07 at 11 42 05 AM
```dart MaterialApp( theme: ThemeData( colorScheme: ThemeData.dark(), ), ... ), ``` Screenshot 2023-08-07 at 11 42 23 AM
```dart MaterialApp( theme: ThemeData( colorScheme: ThemeData.light().colorScheme.copyWith( surface: Colors.blue, onSurface: Colors.red, ), ), ... ), ``` Screenshot 2023-08-07 at 11 43 06 AM
```dart MaterialApp( theme: ThemeData( colorScheme: ThemeData.light().colorScheme.copyWith( surface: Colors.blue, onSurface: Colors.red, ), ), ... ), ``` Screenshot 2023-08-07 at 11 42 47 AM
--- .../src/material/text_selection_toolbar.dart | 27 +++++- .../text_selection_toolbar_text_button.dart | 34 +++++-- .../material/text_selection_toolbar_test.dart | 89 +++++++++++++++++++ ...xt_selection_toolbar_text_button_test.dart | 63 +++++++++++++ 4 files changed, 204 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/material/text_selection_toolbar.dart b/packages/flutter/lib/src/material/text_selection_toolbar.dart index 9927cd11bd4d4..61b047a3cc966 100644 --- a/packages/flutter/lib/src/material/text_selection_toolbar.dart +++ b/packages/flutter/lib/src/material/text_selection_toolbar.dart @@ -8,11 +8,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart' show listEquals; import 'package:flutter/rendering.dart'; +import 'color_scheme.dart'; import 'debug.dart'; import 'icon_button.dart'; import 'icons.dart'; import 'material.dart'; import 'material_localizations.dart'; +import 'theme.dart'; const double _kToolbarHeight = 44.0; const double _kToolbarContentDistance = 8.0; @@ -650,13 +652,34 @@ class _TextSelectionToolbarContainer extends StatelessWidget { final Widget child; + // These colors were taken from a screenshot of a Pixel 6 emulator running + // Android API level 34. + static const Color _defaultColorLight = Color(0xffffffff); + static const Color _defaultColorDark = Color(0xff424242); + + static Color _getColor(ColorScheme colorScheme) { + final bool isDefaultSurface = switch (colorScheme.brightness) { + Brightness.light => identical(ThemeData().colorScheme.surface, colorScheme.surface), + Brightness.dark => identical(ThemeData.dark().colorScheme.surface, colorScheme.surface), + }; + if (!isDefaultSurface) { + return colorScheme.surface; + } + return switch (colorScheme.brightness) { + Brightness.light => _defaultColorLight, + Brightness.dark => _defaultColorDark, + }; + } + @override Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); return Material( // This value was eyeballed to match the native text selection menu on - // a Pixel 2 running Android 10. - borderRadius: const BorderRadius.all(Radius.circular(7.0)), + // a Pixel 6 emulator running Android API level 34. + borderRadius: const BorderRadius.all(Radius.circular(_kToolbarHeight / 2)), clipBehavior: Clip.antiAlias, + color: _getColor(theme.colorScheme), elevation: 1.0, type: MaterialType.card, child: child, diff --git a/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart b/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart index ca7e3c0ab291f..e4ac077c14a5d 100644 --- a/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart +++ b/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart @@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart'; -import 'colors.dart'; +import 'color_scheme.dart'; import 'constants.dart'; import 'text_button.dart'; import 'theme.dart'; @@ -130,20 +130,40 @@ class TextSelectionToolbarTextButton extends StatelessWidget { ); } + // These colors were taken from a screenshot of a Pixel 6 emulator running + // Android API level 34. + static const Color _defaultForegroundColorLight = Color(0xff000000); + static const Color _defaultForegroundColorDark = Color(0xffffffff); + + static Color _getForegroundColor(ColorScheme colorScheme) { + final bool isDefaultOnSurface = switch (colorScheme.brightness) { + Brightness.light => identical(ThemeData().colorScheme.onSurface, colorScheme.onSurface), + Brightness.dark => identical(ThemeData.dark().colorScheme.onSurface, colorScheme.onSurface), + }; + if (!isDefaultOnSurface) { + return colorScheme.onSurface; + } + return switch (colorScheme.brightness) { + Brightness.light => _defaultForegroundColorLight, + Brightness.dark => _defaultForegroundColorDark, + }; + } + @override Widget build(BuildContext context) { - // TODO(hansmuller): Should be colorScheme.onSurface - final ThemeData theme = Theme.of(context); - final bool isDark = theme.colorScheme.brightness == Brightness.dark; - final Color foregroundColor = isDark ? Colors.white : Colors.black87; - + final ColorScheme colorScheme = Theme.of(context).colorScheme; return TextButton( style: TextButton.styleFrom( - foregroundColor: foregroundColor, + foregroundColor: _getForegroundColor(colorScheme), shape: const RoundedRectangleBorder(), minimumSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension), padding: padding, alignment: alignment, + textStyle: const TextStyle( + // This value was eyeballed from a screenshot of a Pixel 6 emulator + // running Android API level 34. + fontWeight: FontWeight.w400, + ), ), onPressed: onPressed, child: child, diff --git a/packages/flutter/test/material/text_selection_toolbar_test.dart b/packages/flutter/test/material/text_selection_toolbar_test.dart index bac41d5ee6949..f37714db21c24 100644 --- a/packages/flutter/test/material/text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_test.dart @@ -204,4 +204,93 @@ void main() { expect(find.text('Paste'), findsNothing); expect(find.text('Select all'), findsNothing); }, skip: kIsWeb); // [intended] We don't show the toolbar on the web. + + for (final ColorScheme colorScheme in [ThemeData.light().colorScheme, ThemeData.dark().colorScheme]) { + testWidgetsWithLeakTracking('default background color', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: colorScheme, + ), + home: Scaffold( + body: Center( + child: TextSelectionToolbar( + anchorAbove: Offset.zero, + anchorBelow: Offset.zero, + children: [ + TextSelectionToolbarTextButton( + padding: TextSelectionToolbarTextButton.getPadding(0, 1), + onPressed: () {}, + child: const Text('Custom button'), + ), + ], + ), + ), + ), + ), + ); + + Finder findToolbarContainer() { + return find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionToolbarContainer'), + matching: find.byType(Material), + ); + } + expect(findToolbarContainer(), findsAtLeastNWidgets(1)); + + final Material toolbarContainer = tester.widget(findToolbarContainer().first); + expect( + toolbarContainer.color, + // The default colors are hardcoded and don't take the default value of + // the theme's surface color. + switch (colorScheme.brightness) { + Brightness.light => const Color(0xffffffff), + Brightness.dark => const Color(0xff424242), + }, + ); + }); + + testWidgetsWithLeakTracking('custom background color', (WidgetTester tester) async { + const Color customBackgroundColor = Colors.red; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: colorScheme.copyWith( + surface: customBackgroundColor, + ), + ), + home: Scaffold( + body: Center( + child: TextSelectionToolbar( + anchorAbove: Offset.zero, + anchorBelow: Offset.zero, + children: [ + TextSelectionToolbarTextButton( + padding: TextSelectionToolbarTextButton.getPadding(0, 1), + onPressed: () {}, + child: const Text('Custom button'), + ), + ], + ), + ), + ), + ), + ); + + Finder findToolbarContainer() { + return find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionToolbarContainer'), + matching: find.byType(Material), + ); + } + expect(findToolbarContainer(), findsAtLeastNWidgets(1)); + + final Material toolbarContainer = tester.widget(findToolbarContainer().first); + expect( + toolbarContainer.color, + customBackgroundColor, + ); + }); + } } diff --git a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart index 19900069529fc..a6d6faaa82df4 100644 --- a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart @@ -62,4 +62,67 @@ void main() { expect(onlySize.width, greaterThan(firstSize.width)); expect(onlySize.width, greaterThan(lastSize.width)); }); + + for (final ColorScheme colorScheme in [ThemeData.light().colorScheme, ThemeData.dark().colorScheme]) { + testWidgetsWithLeakTracking('foreground color by default', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: colorScheme, + ), + home: Scaffold( + body: Center( + child: TextSelectionToolbarTextButton( + padding: TextSelectionToolbarTextButton.getPadding(0, 1), + child: const Text('button'), + ), + ), + ), + ), + ); + + expect(find.byType(TextButton), findsOneWidget); + + final TextButton textButton = tester.widget(find.byType(TextButton)); + // The foreground color is hardcoded to black or white by default, not the + // default value from ColorScheme.onSurface. + expect( + textButton.style!.foregroundColor!.resolve({}), + switch (colorScheme.brightness) { + Brightness.light => const Color(0xff000000), + Brightness.dark => const Color(0xffffffff), + }, + ); + }); + + testWidgetsWithLeakTracking('custom foreground color', (WidgetTester tester) async { + const Color customForegroundColor = Colors.red; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: colorScheme.copyWith( + onSurface: customForegroundColor, + ), + ), + home: Scaffold( + body: Center( + child: TextSelectionToolbarTextButton( + padding: TextSelectionToolbarTextButton.getPadding(0, 1), + child: const Text('button'), + ), + ), + ), + ), + ); + + expect(find.byType(TextButton), findsOneWidget); + + final TextButton textButton = tester.widget(find.byType(TextButton)); + expect( + textButton.style!.foregroundColor!.resolve({}), + customForegroundColor, + ); + }); + } } From 0448a11c86dbe3a5e100f3753a739a53f24231cd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 17:00:49 -0400 Subject: [PATCH 0575/1547] Roll Flutter Engine from 39a575f65d50 to be085f6699b6 (1 revision) (#132069) https://github.com/flutter/engine/compare/39a575f65d50...be085f6699b6 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 359808ec2cb1 to f19578685d17 (1 revision) (flutter/engine#44439) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2e563364eb0bd..867f9e7f6502f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -39a575f65d50b8bedf52dc2be35aed85b3c690c2 +be085f6699b668e90891b6b3fafc2f06749a72d8 From ad0dbc8de5f98c6b8a374ae1b7e18b32a660d21a Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Mon, 7 Aug 2023 17:27:11 -0400 Subject: [PATCH 0576/1547] [web] Remove usage of `ui.webOnlyInitializePlatform()` (#131344) Part of https://github.com/flutter/flutter/issues/126831 --- packages/flutter_tools/lib/src/web/bootstrap.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/web/bootstrap.dart b/packages/flutter_tools/lib/src/web/bootstrap.dart index de08019febe0c..814a9a680902a 100644 --- a/packages/flutter_tools/lib/src/web/bootstrap.dart +++ b/packages/flutter_tools/lib/src/web/bootstrap.dart @@ -229,7 +229,7 @@ String generateTestEntrypoint({ Future main() async { ui_web.debugEmulateFlutterTesterEnvironment = true; - await ui.webOnlyInitializePlatform(); + await ui_web.bootstrapEngine(); webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('${Uri.file(absolutePath)}')); (ui.window as dynamic).debugOverrideDevicePixelRatio(3.0); (ui.window as dynamic).webOnlyDebugPhysicalSizeOverride = const ui.Size(2400, 1800); From 1c7e2afce994009658f6178bf379f6defee35eb9 Mon Sep 17 00:00:00 2001 From: Matej Knopp Date: Tue, 8 Aug 2023 01:39:49 +0200 Subject: [PATCH 0577/1547] Add static_path_tessellation macrobenchmark (#131837) This adds a macrobenchmark representative of a real world application that uses SVG icons. The scenario of rasterizing complex paths that don't change over time does not seem to be covered by any other macrobenchmark and shows a significantly slower impeller performance compared to skia. It's actually bit problematic to measure this because on A15 the CPU load with impeller is high enough to trigger CPU frequency change. So in order to get consistent reading I had to add a spinning background thread that would keep the CPU at highest frequency. ```objc [NSThread detachNewThreadWithBlock:^{ while (true) { pthread_yield_np(); } }]; ``` ```bash flutter drive --profile --local-engine=ios_profile -t test_driver/run_app.dart --driver test_driver/path_tessellation_static_perf_test.dart ``` | average_frame_build_time_millis |Time| |--|--| | Impeller | 0.46686524822695047 | | Skia | 0.4625749999999999 | | Skia - No RasterCache | 0.47173750000000086| | average_frame_rasterizer_time_millis | Time | |--|--| | Impeller | 6.654328519855595 | | Skia - Raster Cache | 0.2534123711340209 * | | Skia - No RasterCache | 0.53424375 | * Adding the `GeometryPainter` seems to have triggered the complexity threshold for raster cache. screenshot --- .../macrobenchmarks/lib/common.dart | 1 + dev/benchmarks/macrobenchmarks/lib/main.dart | 9 + .../lib/src/path_tessellation.dart | 341 ++++++++++++++++++ .../macos/Runner.xcodeproj/project.pbxproj | 18 - .../path_tessellation_dynamic_perf_test.dart | 23 ++ .../path_tessellation_static_perf_test.dart | 31 ++ 6 files changed, 405 insertions(+), 18 deletions(-) create mode 100644 dev/benchmarks/macrobenchmarks/lib/src/path_tessellation.dart create mode 100644 dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_dynamic_perf_test.dart create mode 100644 dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_static_perf_test.dart diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart index b8f158c8cad94..ad04770adb6a3 100644 --- a/dev/benchmarks/macrobenchmarks/lib/common.dart +++ b/dev/benchmarks/macrobenchmarks/lib/common.dart @@ -11,6 +11,7 @@ const String kPictureCacheRouteName = '/picture_cache'; const String kPictureCacheComplexityScoringRouteName = '/picture_cache_complexity_scoring'; const String kLargeImageChangerRouteName = '/large_image_changer'; const String kLargeImagesRouteName = '/large_images'; +const String kPathTessellationRouteName = '/path_tessellation'; const String kTextRouteName = '/text'; const String kFullscreenTextRouteName = '/fullscreen_text'; const String kAnimatedPlaceholderRouteName = '/animated_placeholder'; diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart index 464c792632803..64e37e1224d70 100644 --- a/dev/benchmarks/macrobenchmarks/lib/main.dart +++ b/dev/benchmarks/macrobenchmarks/lib/main.dart @@ -28,6 +28,7 @@ import 'src/large_images.dart'; import 'src/list_text_layout.dart'; import 'src/multi_widget_construction.dart'; import 'src/opacity_peephole.dart'; +import 'src/path_tessellation.dart'; import 'src/picture_cache.dart'; import 'src/picture_cache_complexity_scoring.dart'; import 'src/post_backdrop_filter.dart'; @@ -63,6 +64,7 @@ class MacrobenchmarksApp extends StatelessWidget { kLargeImageChangerRouteName: (BuildContext context) => const LargeImageChangerPage(), kLargeImagesRouteName: (BuildContext context) => const LargeImagesPage(), kTextRouteName: (BuildContext context) => const TextPage(), + kPathTessellationRouteName: (BuildContext context) => const PathTessellationPage(), kFullscreenTextRouteName: (BuildContext context) => const TextFieldPage(), kAnimatedPlaceholderRouteName: (BuildContext context) => const AnimatedPlaceholderPage(), kClipperCacheRouteName: (BuildContext context) => const ClipperCachePage(), @@ -162,6 +164,13 @@ class HomePage extends StatelessWidget { Navigator.pushNamed(context, kLargeImagesRouteName); }, ), + ElevatedButton( + key: const Key(kPathTessellationRouteName), + child: const Text('Path Tessellation'), + onPressed: () { + Navigator.pushNamed(context, kPathTessellationRouteName); + }, + ), ElevatedButton( key: const Key(kTextRouteName), child: const Text('Text'), diff --git a/dev/benchmarks/macrobenchmarks/lib/src/path_tessellation.dart b/dev/benchmarks/macrobenchmarks/lib/src/path_tessellation.dart new file mode 100644 index 0000000000000..6fc395aba9041 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/path_tessellation.dart @@ -0,0 +1,341 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +class PathTessellationPage extends StatefulWidget { + const PathTessellationPage({super.key}); + + @override + State createState() => _PathTessellationPageState(); +} + +class _PathTessellationPageState extends State + with SingleTickerProviderStateMixin { + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = + AnimationController(vsync: this, lowerBound: 1.0, upperBound: 1.3); + _controller.addListener(() { + setState(() {}); + }); + } + + @override + Widget build(BuildContext context) { + final double scale = _controller.value; + return SafeArea( + child: ColoredBox( + color: Colors.black, + child: Stack( + fit: StackFit.expand, + children: [ + ListView.builder( + key: const Key( + 'list_view'), // this key is used by the driver test, + itemBuilder: (BuildContext context, int index) { + return Container( + margin: const EdgeInsets.all(1.0), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.2), + ), + child: IconRow(iconSize: (30 + 0.5 * (index % 10)) * scale), + ); + }, + itemCount: 200, + itemExtent: 50, + ), + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + color: Colors.black.withOpacity(0.7), + height: 100, + child: IconRow(iconSize: 50.0 * scale), + ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: ColoredBox( + color: Colors.black.withOpacity(0.7), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 100, + child: IconRow(iconSize: 55.0 * scale), + ), + MaterialButton( + textColor: Colors.white, + key: const Key( + 'animate_button'), // this key is used by the driver test + child: const Text('Animate'), + onPressed: () { + if (_controller.isAnimating) { + _controller.stop(); + } else { + _controller.repeat( + period: const Duration(seconds: 1), + reverse: true, + ); + } + }, + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} + +class IconRow extends StatelessWidget { + const IconRow({ + super.key, + required this.iconSize, + }); + + final double iconSize; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox.square( + dimension: iconSize, + child: CustomPaint( + painter: _SettingsIconPainter(), + willChange: true, + ), + ), + SizedBox.square( + dimension: iconSize, + child: CustomPaint( + painter: _CameraIconPainter(), + willChange: true, + ), + ), + SizedBox.square( + dimension: iconSize, + child: CustomPaint( + painter: _CalendarIconPainter(), + willChange: true, + ), + ), + SizedBox.square( + dimension: iconSize, + child: CustomPaint( + painter: _ConversationIconPainter(), + willChange: true, + ), + ), + SizedBox.square( + dimension: iconSize, + child: CustomPaint( + painter: _GeometryIconPainter(), + willChange: true, + ), + ), + ], + ); + } +} + +/// Parses SVG path data into a [Path] object. +Path _pathFromString(String pathString) { + int start = 0; + final RegExp pattern = RegExp('[MLCHVZ]'); + Offset current = Offset.zero; + final Path path = Path(); + + void performCommand(String command) { + final String type = command[0]; + final List arguments = command + .substring(1) + .split(' ') + .where((String element) => element.isNotEmpty) + .map((String e) => double.parse(e)) + .toList(growable: false); + switch (type) { + case 'M': + path.moveTo(arguments[0], arguments[1]); + current = Offset(arguments[0], arguments[1]); + case 'L': + path.lineTo(arguments[0], arguments[1]); + current = Offset(arguments[0], arguments[1]); + case 'C': + path.cubicTo(arguments[0], arguments[1], arguments[2], arguments[3], + arguments[4], arguments[5]); + current = Offset(arguments[4], arguments[5]); + case 'H': + path.lineTo(arguments[0], current.dy); + current = Offset(arguments[0], current.dy); + case 'V': + path.lineTo(current.dx, arguments[0]); + current = Offset(current.dx, arguments[0]); + } + } + + while (true) { + start = pathString.indexOf(pattern, start); + if (start == -1) { + break; + } + int end = pathString.indexOf(pattern, start + 1); + if (end == -1) { + end = pathString.length; + } + final String command = pathString.substring(start, end); + performCommand(command); + start = end; + } + return path; +} + +class _SettingsIconPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Matrix4 scale = + Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0); + + Path path; + path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0x60F84F39)); + + path = _path2.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0xFFF84F39)); + + path = _path3.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0xFFF84F39)); + } + + static final Path _path1 = _pathFromString( + 'M8.3252 2.675L7.7877 4.0625L5.93771 5.1125L4.4627 4.8875C4.2171 4.85416 3.96713 4.89459 3.74456 5.00365C3.52199 5.11271 3.33686 5.28548 3.21271 5.5L2.7127 6.375C2.58458 6.59294 2.52555 6.8446 2.5434 7.09678C2.56126 7.34895 2.65516 7.58979 2.8127 7.7875L3.7502 8.95V11.05L2.8377 12.2125C2.68016 12.4102 2.58626 12.651 2.5684 12.9032C2.55055 13.1554 2.60958 13.4071 2.73771 13.625L3.2377 14.5C3.36186 14.7145 3.54699 14.8873 3.76956 14.9963C3.99213 15.1054 4.2421 15.1458 4.4877 15.1125L5.96271 14.8875L7.7877 15.9375L8.3252 17.325C8.41585 17.5599 8.57534 17.762 8.78277 17.9047C8.9902 18.0475 9.2359 18.1243 9.48771 18.125H10.5377C10.7895 18.1243 11.0352 18.0475 11.2426 17.9047C11.4501 17.762 11.6096 17.5599 11.7002 17.325L12.2377 15.9375L14.0627 14.8875L15.5377 15.1125C15.7833 15.1458 16.0333 15.1054 16.2559 14.9963C16.4784 14.8873 16.6636 14.7145 16.7877 14.5L17.2877 13.625C17.4158 13.4071 17.4749 13.1554 17.457 12.9032C17.4392 12.651 17.3453 12.4102 17.1877 12.2125L16.2502 11.05V8.95L17.1627 7.7875C17.3203 7.58979 17.4142 7.34895 17.432 7.09678C17.4499 6.8446 17.3908 6.59294 17.2627 6.375L16.7627 5.5C16.6386 5.28548 16.4534 5.11271 16.2309 5.00365C16.0083 4.89459 15.7583 4.85416 15.5127 4.8875L14.0377 5.1125L12.2127 4.0625L11.6752 2.675C11.5846 2.44008 11.4251 2.23801 11.2176 2.09527C11.0102 1.95252 10.7645 1.87574 10.5127 1.875H9.48771C9.2359 1.87574 8.9902 1.95252 8.78277 2.09527C8.57534 2.23801 8.41585 2.44008 8.3252 2.675ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z'); + static final Path _path2 = _pathFromString( + 'M9.48771 1.25L9.48586 1.25001C9.10816 1.25112 8.7396 1.36628 8.42845 1.5804C8.11747 1.79441 7.87833 2.0973 7.74232 2.44945L7.2854 3.62894L5.81769 4.46197L4.55695 4.26965L4.54677 4.26818C4.17836 4.21818 3.80341 4.27882 3.46955 4.44241C3.13569 4.606 2.858 4.86515 2.67177 5.18693L2.17177 6.06191C1.98107 6.38797 1.89329 6.76406 1.91997 7.14092C1.94675 7.51918 2.08759 7.88043 2.32392 8.177L3.12521 9.17062V10.834L2.34736 11.825C2.11197 12.1212 1.97169 12.4817 1.94497 12.8591C1.91828 13.236 2.00608 13.6121 2.1968 13.9381L2.69505 14.8101L2.69677 14.8131C2.883 15.1349 3.16069 15.394 3.49455 15.5576C3.82841 15.7212 4.20336 15.7818 4.57177 15.7318L5.84067 15.5383L7.28466 16.3691L7.28539 16.3711L7.74211 17.55C7.87812 17.9021 8.11745 18.2056 8.42843 18.4196C8.73958 18.6337 9.10814 18.7489 9.48584 18.75L9.48769 18.75L10.5145 18.75C10.8922 18.7489 11.2608 18.6337 11.5719 18.4196C11.8829 18.2056 12.1473 17.9021 12.2833 17.55L12.7408 16.3691L14.1847 15.5383L15.4434 15.7304L15.4536 15.7318C15.822 15.7818 16.197 15.7212 16.5309 15.5576C16.8647 15.394 17.1424 15.1349 17.3286 14.8131L17.3304 14.8101L17.8287 13.9381C18.0193 13.612 18.1071 13.2359 18.0804 12.8591C18.0537 12.4808 17.9128 12.1196 17.6765 11.823L16.8752 10.8294V9.166L17.6515 8.177L17.6531 8.17502C17.8884 7.87883 18.0287 7.51834 18.0554 7.14092C18.0821 6.76407 17.9943 6.38798 17.8036 6.06192L17.3054 5.18991L17.3036 5.18693C17.1174 4.86515 16.8397 4.606 16.5059 4.44241C16.172 4.27882 15.797 4.21809 15.4286 4.2681L14.1597 4.46166L12.7158 3.63087L12.258 2.44923C12.122 2.09718 11.8829 1.79437 11.572 1.5804C11.2608 1.36628 10.8923 1.25112 10.5146 1.25L9.48771 1.25ZM10.5116 2.5H9.48879C9.36315 2.50053 9.24059 2.5389 9.13708 2.61013C9.03337 2.68151 8.95363 2.78254 8.9083 2.9L8.3705 4.28827C8.31845 4.42266 8.22154 4.53492 8.09621 4.60606L6.24621 5.65606C6.12411 5.72535 5.98224 5.75153 5.84346 5.73036L4.37442 5.50627C4.25298 5.49062 4.12958 5.51099 4.01957 5.5649C3.90871 5.61922 3.81643 5.70515 3.75436 5.81183L3.25154 6.69178C3.18747 6.80075 3.15792 6.92655 3.16684 7.05264C3.17574 7.17824 3.22235 7.2982 3.30057 7.39684L4.23671 8.55766C4.32633 8.66878 4.37521 8.80724 4.37521 8.95V11.05C4.37521 11.1899 4.32824 11.3258 4.24184 11.4359L3.32651 12.602C3.24773 12.7009 3.20077 12.8213 3.19184 12.9474C3.18292 13.0735 3.21243 13.1993 3.27649 13.3083L3.2804 13.3149L3.77864 14.1869L3.77933 14.1881C3.8414 14.2948 3.93369 14.3808 4.04457 14.4351C4.15457 14.489 4.27796 14.5094 4.39939 14.4937L5.86846 14.2696C6.00848 14.2483 6.15161 14.2751 6.27439 14.3458L8.09939 15.3958C8.22322 15.467 8.3189 15.5785 8.3705 15.7117L8.908 17.0992C8.95333 17.2167 9.03337 17.3185 9.13708 17.3899C9.24061 17.4611 9.36321 17.4995 9.48887 17.5H10.5365C10.6622 17.4995 10.7848 17.4611 10.8883 17.3899C10.992 17.3185 11.0718 17.2175 11.1171 17.1L11.6549 15.7117C11.7065 15.5785 11.8022 15.467 11.926 15.3958L13.751 14.3458C13.8738 14.2751 14.0169 14.2483 14.157 14.2696L15.626 14.4937C15.7475 14.5094 15.8708 14.489 15.9808 14.4351C16.0917 14.3808 16.184 14.2949 16.2461 14.1882L16.2468 14.1869L16.7489 13.3082C16.8129 13.1993 16.8425 13.0735 16.8336 12.9474C16.8247 12.8218 16.7781 12.7019 16.6999 12.6032L16.6989 12.602L15.7637 11.4423C15.6741 11.3312 15.6252 11.1928 15.6252 11.05V8.95C15.6252 8.81006 15.6722 8.67418 15.7586 8.5641L16.6711 7.4016L16.6739 7.398C16.7527 7.29915 16.7996 7.17873 16.8086 7.05264C16.8175 6.92655 16.788 6.80072 16.7239 6.69175L16.72 6.68511L16.2218 5.81307L16.2211 5.81187C16.159 5.70517 16.0667 5.61923 15.9558 5.5649C15.8458 5.51099 15.7224 5.49062 15.601 5.50627L14.132 5.73036C13.9919 5.75172 13.8488 5.72488 13.726 5.65424L11.901 4.60424C11.7772 4.533 11.6815 4.42148 11.6299 4.28827L11.0924 2.90077C11.0471 2.78331 10.967 2.68151 10.8633 2.61013C10.7598 2.5389 10.6373 2.50053 10.5116 2.5Z'); + static final Path _path3 = _pathFromString( + 'M10.0002 6.875C9.1714 6.875 8.37655 7.20424 7.7905 7.79029C7.20445 8.37635 6.87521 9.1712 6.87521 10C6.87521 10.6181 7.05848 11.2223 7.40186 11.7362C7.74524 12.2501 8.2333 12.6506 8.80432 12.8871C9.37534 13.1237 10.0037 13.1855 10.6099 13.065C11.2161 12.9444 11.7729 12.6467 12.2099 12.2097C12.647 11.7727 12.9446 11.2159 13.0652 10.6097C13.1857 10.0035 13.1239 9.37514 12.8873 8.80412C12.6508 8.2331 12.2503 7.74504 11.7364 7.40166C11.2225 7.05828 10.6183 6.875 10.0002 6.875ZM10.0002 8.125C9.50292 8.125 9.02601 8.32255 8.67438 8.67418C8.32275 9.02581 8.12521 9.50272 8.12521 10C8.12521 10.3708 8.23517 10.7334 8.4412 11.0417C8.64723 11.35 8.94006 11.5904 9.28267 11.7323C9.62529 11.8742 10.0023 11.9113 10.366 11.839C10.7297 11.7666 11.0638 11.5881 11.326 11.3258C11.5883 11.0636 11.7668 10.7295 11.8392 10.3658C11.9115 10.0021 11.8744 9.62508 11.7325 9.28247C11.5906 8.93986 11.3502 8.64703 11.0419 8.441C10.7336 8.23497 10.371 8.125 10.0002 8.125Z'); + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} + +class _CameraIconPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Matrix4 scale = + Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0); + + Path path; + path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0xFFF84F39)); + + path = _path2.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0x60F84F39)); + } + + static final Path _path1 = _pathFromString( + 'M3.26366 17H16.7363C17.4857 17 18.0503 16.8123 18.4302 16.4369C18.8101 16.0615 19 15.5035 19 14.7631V7.01229C19 6.27188 18.8101 5.71397 18.4302 5.33855C18.0503 4.96313 17.4857 4.77542 16.7363 4.77542H14.6132C14.4154 4.77542 14.2567 4.76238 14.137 4.73631C14.0173 4.70503 13.9107 4.65549 13.817 4.58771C13.7233 4.51471 13.6219 4.41825 13.5126 4.29832L12.9115 3.61788C12.7242 3.41453 12.5212 3.26071 12.3027 3.15642C12.0893 3.05214 11.7953 3 11.4206 3H8.50911C8.13443 3 7.83781 3.05214 7.61925 3.15642C7.4059 3.26071 7.20555 3.41453 7.01821 3.61788L6.41717 4.29832C6.24545 4.48082 6.09193 4.60596 5.95663 4.67374C5.82134 4.74153 5.61058 4.77542 5.32437 4.77542H3.26366C2.50911 4.77542 1.94189 4.96313 1.56201 5.33855C1.18734 5.71397 1 6.27188 1 7.01229V14.7631C1 15.5035 1.18734 16.0615 1.56201 16.4369C1.94189 16.8123 2.50911 17 3.26366 17ZM3.27927 15.9207C2.89419 15.9207 2.59757 15.819 2.38942 15.6156C2.18647 15.4123 2.085 15.1099 2.085 14.7084V7.07486C2.085 6.67337 2.18647 6.37095 2.38942 6.1676C2.59757 5.95903 2.89419 5.85475 3.27927 5.85475H5.57415C5.9072 5.85475 6.1752 5.81825 6.37814 5.74525C6.58109 5.67225 6.77624 5.53147 6.96357 5.32291L7.55681 4.6581C7.76496 4.42346 7.9497 4.26965 8.11101 4.19665C8.27233 4.12365 8.50911 4.08715 8.82134 4.08715H11.1084C11.4258 4.08715 11.6626 4.12365 11.8187 4.19665C11.9801 4.26965 12.1648 4.42346 12.3729 4.6581L12.9662 5.32291C13.1535 5.53147 13.3487 5.67225 13.5516 5.74525C13.7546 5.81825 14.0225 5.85475 14.3556 5.85475H16.7207C17.1058 5.85475 17.4024 5.95903 17.6106 6.1676C17.8187 6.37095 17.9228 6.67337 17.9228 7.07486V14.7084C17.9228 15.1099 17.8187 15.4123 17.6106 15.6156C17.4024 15.819 17.1058 15.9207 16.7207 15.9207H3.27927ZM10 14.8101C10.7493 14.8101 11.4284 14.6302 12.0373 14.2704C12.6461 13.9054 13.1301 13.4179 13.4892 12.8078C13.8534 12.1926 14.0356 11.5095 14.0356 10.7587C14.0356 10.0078 13.8534 9.32477 13.4892 8.7095C13.1301 8.09423 12.6461 7.6067 12.0373 7.24693C11.4284 6.88194 10.7493 6.69944 10 6.69944C9.25585 6.69944 8.57676 6.88194 7.96271 7.24693C7.35386 7.6067 6.8673 8.09423 6.50304 8.7095C6.14397 9.32477 5.96444 10.0078 5.96444 10.7587C5.96444 11.5095 6.14397 12.1926 6.50304 12.8078C6.8673 13.4179 7.35386 13.9054 7.96271 14.2704C8.57676 14.6302 9.25585 14.8101 10 14.8101ZM10 13.7855C9.4484 13.7855 8.94363 13.6499 8.48569 13.3788C8.03296 13.1076 7.66869 12.7426 7.39289 12.2838C7.12229 11.825 6.98699 11.3166 6.98699 10.7587C6.98699 10.1955 7.12229 9.68454 7.39289 9.2257C7.66349 8.76685 8.02775 8.40447 8.48569 8.13855C8.94363 7.86741 9.4484 7.73184 10 7.73184C10.5568 7.73184 11.0616 7.86741 11.5143 8.13855C11.9722 8.40447 12.3365 8.76685 12.6071 9.2257C12.8829 9.68454 13.0208 10.1955 13.0208 10.7587C13.0208 11.3166 12.8829 11.825 12.6071 12.2838C12.3365 12.7426 11.9722 13.1076 11.5143 13.3788C11.0616 13.6499 10.5568 13.7855 10 13.7855ZM14.3556 8.04469C14.3556 8.30019 14.4467 8.51657 14.6288 8.69385C14.8109 8.86592 15.0269 8.95196 15.2767 8.95196C15.516 8.94674 15.7242 8.8581 15.9011 8.68603C16.0833 8.50875 16.1743 8.29497 16.1743 8.04469C16.1743 7.79963 16.0833 7.58845 15.9011 7.41117C15.7242 7.22868 15.516 7.13743 15.2767 7.13743C15.0269 7.13743 14.8109 7.22868 14.6288 7.41117C14.4467 7.58845 14.3556 7.79963 14.3556 8.04469Z'); + static final Path _path2 = _pathFromString( + 'M2.30754 15.6907C2.51782 15.8969 2.81748 16 3.20651 16H16.7856C17.1746 16 17.4743 15.8969 17.6846 15.6907C17.8949 15.4845 18 15.1778 18 14.7707V7.02974C18 6.6226 17.8949 6.31593 17.6846 6.10972C17.4743 5.89822 17.1746 5.79247 16.7856 5.79247H14.3963C14.0598 5.79247 13.7891 5.75545 13.584 5.68143C13.379 5.6074 13.1819 5.46464 12.9926 5.25314L12.3933 4.57898C12.183 4.34104 11.9964 4.18506 11.8334 4.11104C11.6757 4.03701 11.4365 4 11.1158 4H8.80532C8.4899 4 8.2507 4.03701 8.08773 4.11104C7.92476 4.18506 7.73813 4.34104 7.52785 4.57898L6.92854 5.25314C6.73928 5.46464 6.54214 5.6074 6.33711 5.68143C6.13208 5.75545 5.86134 5.79247 5.52489 5.79247H3.20651C2.81748 5.79247 2.51782 5.89822 2.30754 6.10972C2.10251 6.31593 2 6.6226 2 7.02974V14.7707C2 15.1778 2.10251 15.4845 2.30754 15.6907ZM9.99547 14C9.99547 14 8.76994 13.8432 8.23868 13.5297C7.71345 13.2162 7.29086 12.7941 6.97089 12.2636C6.65696 11.733 6.5 11.1451 6.5 10.5C6.5 9.84884 6.65696 9.25797 6.97089 8.72739C7.28482 8.19681 7.70742 7.77778 8.23868 7.47028C8.76994 7.15676 9.35554 7 9.99547 7C10.6414 7 11.7523 7.47028 11.7523 7.47028C11.7523 7.47028 12.7061 8.19681 13.0201 8.72739C13.34 9.25797 13.5 9.84884 13.5 10.5C13.5 11.1451 13.34 11.733 13.0201 12.2636C12.7061 12.7941 12.2835 13.2162 11.7523 13.5297C11.227 13.8432 9.99547 14 9.99547 14Z'); + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} + +class _CalendarIconPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Matrix4 scale = + Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0); + + Path path; + path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0x60F84F39)); + + path = _path2.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0xFFF84F39)); + } + + static final Path _path1 = _pathFromString( + 'M16.7812 6.85938H3.28125V4.5L5 3H15L16.7812 4.5V6.85938Z'); + static final Path _path2 = _pathFromString( + 'M6.5606 11.2462C7.07732 11.2462 7.4962 10.8273 7.4962 10.3106C7.4962 9.79388 7.07732 9.375 6.5606 9.375C6.04388 9.375 5.625 9.79388 5.625 10.3106C5.625 10.8273 6.04388 11.2462 6.5606 11.2462ZM7.4962 13.4356C7.4962 13.9523 7.07732 14.3712 6.5606 14.3712C6.04388 14.3712 5.625 13.9523 5.625 13.4356C5.625 12.9189 6.04388 12.5 6.5606 12.5C7.07732 12.5 7.4962 12.9189 7.4962 13.4356ZM10.0005 11.2462C10.5173 11.2462 10.9361 10.8273 10.9361 10.3106C10.9361 9.79388 10.5173 9.375 10.0005 9.375C9.48382 9.375 9.06494 9.79388 9.06494 10.3106C9.06494 10.8273 9.48382 11.2462 10.0005 11.2462ZM10.9361 13.4356C10.9361 13.9523 10.5173 14.3712 10.0005 14.3712C9.48382 14.3712 9.06494 13.9523 9.06494 13.4356C9.06494 12.9189 9.48382 12.5 10.0005 12.5C10.5173 12.5 10.9361 12.9189 10.9361 13.4356ZM13.4356 11.2462C13.9523 11.2462 14.3712 10.8273 14.3712 10.3106C14.3712 9.79388 13.9523 9.375 13.4356 9.375C12.9189 9.375 12.5 9.79388 12.5 10.3106C12.5 10.8273 12.9189 11.2462 13.4356 11.2462ZM17.5 5.625C17.5 3.89911 16.1009 2.5 14.375 2.5H5.625C3.89911 2.5 2.5 3.89911 2.5 5.625V14.375C2.5 16.1009 3.89911 17.5 5.625 17.5H14.375C16.1009 17.5 17.5 16.1009 17.5 14.375V5.625ZM3.75 7.5H16.25V14.375C16.25 15.4105 15.4105 16.25 14.375 16.25H5.625C4.58947 16.25 3.75 15.4105 3.75 14.375V7.5ZM5.625 3.75H14.375C15.4105 3.75 16.25 4.58947 16.25 5.625V6.25H3.75V5.625C3.75 4.58947 4.58947 3.75 5.625 3.75Z'); + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} + +class _ConversationIconPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Matrix4 scale = + Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0); + + Path path; + path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0x60F84F39)); + + path = _path2.transform(scale.storage)..fillType = PathFillType.evenOdd; + canvas.drawPath(path, Paint()..color = const Color(0xFFF84F39)); + } + + static final Path _path1 = _pathFromString( + 'M14.4141 8.33333C14.4141 11.555 11.8024 14.1667 8.58073 14.1667C7.64487 14.1667 6.76047 13.9463 5.97663 13.5546L2.65625 14.4661L3.70864 11.5424C3.10106 10.6218 2.7474 9.51887 2.7474 8.33333C2.7474 5.11167 5.35907 2.5 8.58073 2.5C11.8024 2.5 14.4141 5.11167 14.4141 8.33333Z'); + static final Path _path2 = _pathFromString( + 'M8.5382 1.81665C4.84709 1.81665 1.85486 4.80888 1.85486 8.49998C1.85486 9.65241 2.1471 10.7384 2.66182 11.686L1.89645 13.6887C1.5494 14.5968 2.38481 15.5128 3.32097 15.2506L5.74289 14.5723C6.59409 14.9647 7.54146 15.1833 8.5382 15.1833C12.2293 15.1833 15.2215 12.1911 15.2215 8.49998C15.2215 4.80888 12.2293 1.81665 8.5382 1.81665ZM3.22153 8.49998C3.22153 5.56367 5.60188 3.18332 8.5382 3.18332C11.4745 3.18332 13.8549 5.56367 13.8549 8.49998C13.8549 11.4363 11.4745 13.8167 8.5382 13.8167C7.66578 13.8167 6.84431 13.607 6.11952 13.2361L5.88143 13.1142L3.30309 13.8364L4.17436 11.5565L3.99903 11.2698C3.5059 10.4636 3.22153 9.51607 3.22153 8.49998ZM16.5636 7.07206L16.1464 6.61586L16.2475 7.22577C16.317 7.64558 16.3533 8.07677 16.3533 8.51656C16.3533 8.69251 16.3475 8.86707 16.3361 9.04007L16.3328 9.08869L16.3542 9.13249C16.6951 9.83163 16.8175 10.5975 16.8175 11.5C16.8175 12.5161 16.5332 13.4636 16.04 14.2698L15.8647 14.5565L16.736 16.8363L14.1576 16.1142L13.9195 16.2361C13.1948 16.607 12.3733 16.8166 11.5009 16.8166C10.5879 16.8166 9.87033 16.6947 9.19041 16.3496L9.14498 16.3266L9.09417 16.3303C8.90419 16.3441 8.71231 16.3511 8.51875 16.3511C8.10958 16.3511 7.70785 16.3197 7.31582 16.2593L6.72389 16.1681L7.16334 16.575C8.31731 17.6436 9.75888 18.1833 11.5009 18.1833C12.4976 18.1833 13.445 17.9647 14.2962 17.5723L16.7181 18.2506C17.6543 18.5128 18.4897 17.5968 18.1426 16.6887L17.3772 14.6859C17.892 13.7384 18.1842 12.6524 18.1842 11.5C18.1842 9.75761 17.6387 8.24759 16.5636 7.07206Z'); + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} + +class _GeometryIconPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size canvasSize) { + const Size size = Size(20, 20); + canvas.scale( + canvasSize.width / size.width, canvasSize.height / size.height); + + final Paint paint = Paint()..color = const Color(0xFFF84F39); + final Rect frame = Offset.zero & size; + canvas.drawDRRect( + RRect.fromRectAndRadius(frame, const Radius.elliptical(5, 4)), + RRect.fromRectAndRadius( + frame.deflate(1), const Radius.elliptical(4, 3)), + paint); + canvas.drawRRect( + RRect.fromRectAndRadius( + const Rect.fromLTWH(3, 3, 6, 6), const Radius.elliptical(2, 1)), + paint); + canvas.drawRRect( + RRect.fromRectAndRadius( + const Rect.fromLTWH(11, 11, 6, 6), const Radius.elliptical(2, 1)), + paint); + canvas.drawCircle(const Offset(14, 6), 3, paint); + canvas.drawCircle(const Offset(6, 14), 3, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return false; + } +} diff --git a/dev/benchmarks/macrobenchmarks/macos/Runner.xcodeproj/project.pbxproj b/dev/benchmarks/macrobenchmarks/macos/Runner.xcodeproj/project.pbxproj index 5f2846150efb5..1b628dcde2b6f 100644 --- a/dev/benchmarks/macrobenchmarks/macos/Runner.xcodeproj/project.pbxproj +++ b/dev/benchmarks/macrobenchmarks/macos/Runner.xcodeproj/project.pbxproj @@ -181,7 +181,6 @@ 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - A7656B4F0E64AD6C5DDAE467 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -310,23 +309,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - A7656B4F0E64AD6C5DDAE467 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_dynamic_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_dynamic_perf_test.dart new file mode 100644 index 0000000000000..c18701fdb7dd7 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_dynamic_perf_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTest( + 'tessellation_perf_dynamic', + kPathTessellationRouteName, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 10), + setupOps: (FlutterDriver driver) async { + final SerializableFinder animateButton = + find.byValueKey('animate_button'); + await driver.tap(animateButton); + await Future.delayed(const Duration(seconds: 1)); + }, + ); +} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_static_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_static_perf_test.dart new file mode 100644 index 0000000000000..5be534bda7924 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test_driver/path_tessellation_static_perf_test.dart @@ -0,0 +1,31 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_driver/flutter_driver.dart'; +import 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTest( + 'tessellation_perf_static', + kPathTessellationRouteName, + pageDelay: const Duration(seconds: 1), + driverOps: (FlutterDriver driver) async { + final SerializableFinder listView = find.byValueKey('list_view'); + Future scrollOnce(double offset) async { + await driver.scroll( + listView, 0.0, offset, const Duration(milliseconds: 450)); + await Future.delayed(const Duration(milliseconds: 500)); + } + + for (int i = 0; i < 3; i += 1) { + await scrollOnce(-600.0); + await scrollOnce(-600.0); + await scrollOnce(600.0); + await scrollOnce(600.0); + } + }, + ); +} From f054f5aa09f3de0c9e81ea8885141f5f881e73d8 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Mon, 7 Aug 2023 18:43:03 -0500 Subject: [PATCH 0578/1547] Move mock canvas to flutter_test (#131631) Fixes https://github.com/flutter/flutter/issues/59413 This relocates `mock_canvas.dart` and `recording_canvas.dart` from `flutter/test/rendering` to `flutter_test`. The testing functionality afforded by mock_canvas should be available to everyone, not just the framework. :) mock_canvas.dart needed a bit of cleanup - things like formatting and super parameters. --- .../cupertino/activity_indicator_test.dart | 2 - .../flutter/test/cupertino/checkbox_test.dart | 1 - .../flutter/test/cupertino/colors_test.dart | 2 - .../cupertino/context_menu_action_test.dart | 2 - .../flutter/test/cupertino/dialog_test.dart | 1 - .../flutter/test/cupertino/nav_bar_test.dart | 1 - .../flutter/test/cupertino/picker_test.dart | 1 - .../flutter/test/cupertino/radio_test.dart | 1 - .../flutter/test/cupertino/route_test.dart | 1 - .../flutter/test/cupertino/scaffold_test.dart | 1 - .../test/cupertino/scrollbar_paint_test.dart | 2 - .../test/cupertino/scrollbar_test.dart | 2 - .../flutter/test/cupertino/slider_test.dart | 1 - .../flutter/test/cupertino/switch_test.dart | 2 - .../test/cupertino/text_field_test.dart | 1 - .../cupertino/text_form_field_row_test.dart | 2 - .../text_selection_toolbar_test.dart | 1 - .../test/material/action_chip_test.dart | 1 - .../flutter/test/material/app_bar_test.dart | 1 - packages/flutter/test/material/app_test.dart | 2 - .../test/material/autocomplete_test.dart | 2 - .../flutter/test/material/badge_test.dart | 1 - .../test/material/badge_theme_test.dart | 1 - .../test/material/bottom_app_bar_test.dart | 2 - .../material/bottom_navigation_bar_test.dart | 1 - .../material/calendar_date_picker_test.dart | 1 - .../material/checkbox_list_tile_test.dart | 1 - .../flutter/test/material/checkbox_test.dart | 1 - .../test/material/checkbox_theme_test.dart | 1 - packages/flutter/test/material/chip_test.dart | 1 - .../test/material/chip_theme_test.dart | 1 - .../test/material/choice_chip_test.dart | 1 - .../test/material/data_table_test.dart | 1 - .../test/material/date_picker_test.dart | 2 - .../test/material/date_picker_theme_test.dart | 2 - .../flutter/test/material/divider_test.dart | 2 - .../material/dropdown_form_field_test.dart | 1 - .../flutter/test/material/dropdown_test.dart | 1 - .../test/material/elevated_button_test.dart | 1 - .../test/material/filled_button_test.dart | 1 - .../test/material/filter_chip_test.dart | 1 - .../material/floating_action_button_test.dart | 1 - .../test/material/icon_button_test.dart | 1 - .../test/material/inherited_theme_test.dart | 2 - .../flutter/test/material/ink_paint_test.dart | 1 - .../test/material/ink_sparkle_test.dart | 1 - .../test/material/ink_splash_test.dart | 1 - .../flutter/test/material/ink_well_test.dart | 1 - .../test/material/input_chip_test.dart | 1 - .../test/material/input_decorator_test.dart | 2 - .../flutter/test/material/list_tile_test.dart | 1 - .../test/material/list_tile_theme_test.dart | 1 - .../test/material/material_button_test.dart | 1 - .../flutter/test/material/material_test.dart | 1 - .../test/material/menu_anchor_test.dart | 1 - .../material/mergeable_material_test.dart | 1 - .../test/material/navigation_bar_test.dart | 1 - .../test/material/navigation_rail_test.dart | 1 - .../test/material/outlined_button_test.dart | 1 - packages/flutter/test/material/page_test.dart | 2 - .../test/material/popup_menu_test.dart | 1 - .../material/progress_indicator_test.dart | 1 - .../test/material/radio_list_tile_test.dart | 1 - .../flutter/test/material/radio_test.dart | 1 - .../test/material/radio_theme_test.dart | 1 - .../test/material/range_slider_test.dart | 1 - .../material/raw_material_button_test.dart | 1 - .../test/material/scrollbar_paint_test.dart | 1 - .../flutter/test/material/scrollbar_test.dart | 1 - .../test/material/scrollbar_theme_test.dart | 1 - .../test/material/search_anchor_test.dart | 2 - .../test/material/segmented_button_test.dart | 1 - .../flutter/test/material/slider_test.dart | 1 - .../test/material/slider_theme_test.dart | 1 - .../test/material/switch_list_tile_test.dart | 1 - .../flutter/test/material/switch_test.dart | 1 - .../test/material/switch_theme_test.dart | 1 - .../test/material/tab_bar_theme_test.dart | 2 - packages/flutter/test/material/tabs_test.dart | 2 - .../test/material/text_button_test.dart | 1 - .../test/material/text_form_field_test.dart | 1 - .../material/text_selection_theme_test.dart | 1 - .../test/material/time_picker_test.dart | 1 - .../test/material/time_picker_theme_test.dart | 2 - .../test/material/toggle_buttons_test.dart | 1 - .../material/toggle_buttons_theme_test.dart | 1 - .../flutter/test/material/tooltip_test.dart | 1 - .../test/material/tooltip_theme_test.dart | 1 - .../beveled_rectangle_border_test.dart | 2 - .../test/painting/border_rtl_test.dart | 2 - .../test/painting/box_decoration_test.dart | 2 - .../test/painting/circle_border_test.dart | 1 - .../test/painting/common_matchers.dart | 2 - .../continuous_rectangle_border_test.dart | 2 - .../test/painting/linear_border_test.dart | 3 - .../test/painting/oval_border_test.dart | 2 - .../rounded_rectangle_border_test.dart | 1 - .../test/painting/shape_border_test.dart | 2 - .../test/painting/shape_decoration_test.dart | 1 - .../test/painting/stadium_border_test.dart | 1 - .../debug_overflow_indicator_test.dart | 2 - .../flutter/test/rendering/debug_test.dart | 1 - .../flutter/test/rendering/editable_test.dart | 2 - .../flutter/test/rendering/error_test.dart | 2 - .../test/rendering/flex_overflow_test.dart | 2 - .../test/rendering/proxy_box_test.dart | 1 - .../flutter/test/rendering/table_test.dart | 1 - .../flutter/test/rendering/view_test.dart | 1 - .../flutter/test/widgets/banner_test.dart | 2 - .../test/widgets/box_decoration_test.dart | 1 - packages/flutter/test/widgets/clip_test.dart | 1 - .../flutter/test/widgets/container_test.dart | 2 - .../test/widgets/decorated_sliver_test.dart | 2 - .../widgets/editable_text_cursor_test.dart | 1 - .../test/widgets/editable_text_test.dart | 1 - .../widgets/error_widget_builder_test.dart | 2 - .../flutter/test/widgets/grid_view_test.dart | 1 - .../flutter/test/widgets/image_rtl_test.dart | 2 - .../flutter/test/widgets/list_view_test.dart | 1 - .../widgets/list_view_viewporting_test.dart | 1 - .../widgets/list_wheel_scroll_view_test.dart | 1 - .../flutter/test/widgets/opacity_test.dart | 1 - .../flutter/test/widgets/overlay_test.dart | 1 - .../widgets/overscroll_indicator_test.dart | 2 - .../test/widgets/placeholder_test.dart | 2 - .../widgets/render_object_widget_test.dart | 2 - .../flutter/test/widgets/scrollbar_test.dart | 2 - .../test/widgets/shape_decoration_test.dart | 1 - .../test/widgets/sliver_visibility_test.dart | 1 - .../test/widgets/slivers_block_test.dart | 2 - .../flutter/test/widgets/slivers_test.dart | 1 - .../slotted_render_object_widget_test.dart | 2 - packages/flutter/test/widgets/text_test.dart | 1 - .../flutter/test/widgets/visibility_test.dart | 1 - packages/flutter/test/widgets/wrap_test.dart | 2 - packages/flutter_test/lib/flutter_test.dart | 2 + .../lib/src}/mock_canvas.dart | 440 ++++++++++++------ .../lib/src}/recording_canvas.dart | 3 +- .../test}/mock_canvas_test.dart | 6 +- 139 files changed, 304 insertions(+), 327 deletions(-) rename packages/{flutter/test/rendering => flutter_test/lib/src}/mock_canvas.dart (82%) rename packages/{flutter/test/rendering => flutter_test/lib/src}/recording_canvas.dart (99%) rename packages/{flutter/test/rendering => flutter_test/test}/mock_canvas_test.dart (98%) diff --git a/packages/flutter/test/cupertino/activity_indicator_test.dart b/packages/flutter/test/cupertino/activity_indicator_test.dart index 3151fc1887ae7..dcb8ac43156d5 100644 --- a/packages/flutter/test/cupertino/activity_indicator_test.dart +++ b/packages/flutter/test/cupertino/activity_indicator_test.dart @@ -11,8 +11,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('Activity indicator animate property works', (WidgetTester tester) async { await tester.pumpWidget(buildCupertinoActivityIndicator()); diff --git a/packages/flutter/test/cupertino/checkbox_test.dart b/packages/flutter/test/cupertino/checkbox_test.dart index 6fc2a2f6f31ad..601aef991d884 100644 --- a/packages/flutter/test/cupertino/checkbox_test.dart +++ b/packages/flutter/test/cupertino/checkbox_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/cupertino/colors_test.dart b/packages/flutter/test/cupertino/colors_test.dart index 91e10b59ccfc0..f334426d29b78 100644 --- a/packages/flutter/test/cupertino/colors_test.dart +++ b/packages/flutter/test/cupertino/colors_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - class DependentWidget extends StatelessWidget { const DependentWidget({ super.key, diff --git a/packages/flutter/test/cupertino/context_menu_action_test.dart b/packages/flutter/test/cupertino/context_menu_action_test.dart index 26c8dd78ec1ab..ad6a52b9c313e 100644 --- a/packages/flutter/test/cupertino/context_menu_action_test.dart +++ b/packages/flutter/test/cupertino/context_menu_action_test.dart @@ -8,8 +8,6 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { // Constants taken from _ContextMenuActionState. const CupertinoDynamicColor kBackgroundColor = diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart index 64b15d38ca4ed..388c1097ec55f 100644 --- a/packages/flutter/test/cupertino/dialog_test.dart +++ b/packages/flutter/test/cupertino/dialog_test.dart @@ -16,7 +16,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index 4f86b395d8f23..fa6d3019993b2 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; int count = 0; diff --git a/packages/flutter/test/cupertino/picker_test.dart b/packages/flutter/test/cupertino/picker_test.dart index 1be766651335b..2522ada1c8fdb 100644 --- a/packages/flutter/test/cupertino/picker_test.dart +++ b/packages/flutter/test/cupertino/picker_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../rendering/rendering_tester.dart'; class SpyFixedExtentScrollController extends FixedExtentScrollController { diff --git a/packages/flutter/test/cupertino/radio_test.dart b/packages/flutter/test/cupertino/radio_test.dart index 343d97b525944..0a7d3460c3ea2 100644 --- a/packages/flutter/test/cupertino/radio_test.dart +++ b/packages/flutter/test/cupertino/radio_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index f3b66c8a72206..92a0d96951c93 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -13,7 +13,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/cupertino/scaffold_test.dart b/packages/flutter/test/cupertino/scaffold_test.dart index 833c484f26cd9..2dd4f74dd374a 100644 --- a/packages/flutter/test/cupertino/scaffold_test.dart +++ b/packages/flutter/test/cupertino/scaffold_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; import '../image_data.dart'; -import '../rendering/mock_canvas.dart'; /// Integration tests testing both [CupertinoPageScaffold] and [CupertinoTabScaffold]. void main() { diff --git a/packages/flutter/test/cupertino/scrollbar_paint_test.dart b/packages/flutter/test/cupertino/scrollbar_paint_test.dart index a8189246a1bf8..a19a3ca8567f1 100644 --- a/packages/flutter/test/cupertino/scrollbar_paint_test.dart +++ b/packages/flutter/test/cupertino/scrollbar_paint_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - const Color _kScrollbarColor = Color(0x59000000); // The `y` offset has to be larger than `ScrollDragController._bigThresholdBreakDistance` diff --git a/packages/flutter/test/cupertino/scrollbar_test.dart b/packages/flutter/test/cupertino/scrollbar_test.dart index 84ff11748ce3a..e8a1277ef7494 100644 --- a/packages/flutter/test/cupertino/scrollbar_test.dart +++ b/packages/flutter/test/cupertino/scrollbar_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - const CupertinoDynamicColor _kScrollbarColor = CupertinoDynamicColor.withBrightness( color: Color(0x59000000), darkColor: Color(0x80FFFFFF), diff --git a/packages/flutter/test/cupertino/slider_test.dart b/packages/flutter/test/cupertino/slider_test.dart index d0f67ebd827a4..a205276e0e7ba 100644 --- a/packages/flutter/test/cupertino/slider_test.dart +++ b/packages/flutter/test/cupertino/slider_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; const CupertinoDynamicColor _kSystemFill = CupertinoDynamicColor( diff --git a/packages/flutter/test/cupertino/switch_test.dart b/packages/flutter/test/cupertino/switch_test.dart index af9a1336de652..e6b484bda281e 100644 --- a/packages/flutter/test/cupertino/switch_test.dart +++ b/packages/flutter/test/cupertino/switch_test.dart @@ -15,8 +15,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('Switch can toggle on tap', (WidgetTester tester) async { final Key switchKey = UniqueKey(); diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index dfe73bee44312..c7d9c8135b6b0 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -18,7 +18,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart' show OverflowWidgetTextEditingController; import '../widgets/live_text_utils.dart'; diff --git a/packages/flutter/test/cupertino/text_form_field_row_test.dart b/packages/flutter/test/cupertino/text_form_field_row_test.dart index 830431848e653..ff48a0e2a8462 100644 --- a/packages/flutter/test/cupertino/text_form_field_row_test.dart +++ b/packages/flutter/test/cupertino/text_form_field_row_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('Passes textAlign to underlying CupertinoTextField', (WidgetTester tester) async { const TextAlign alignment = TextAlign.center; diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart index 5c110b22e9620..a84a5b2ebd63c 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/editable_text_utils.dart' show textOffsetToPosition; // These constants are copied from cupertino/text_selection_toolbar.dart. diff --git a/packages/flutter/test/material/action_chip_test.dart b/packages/flutter/test/material/action_chip_test.dart index 8e554968e98c5..f1fa44830cc63 100644 --- a/packages/flutter/test/material/action_chip_test.dart +++ b/packages/flutter/test/material/action_chip_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; /// Adds the basic requirements for a Chip. Widget wrapForChip({ diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index eb51024e1de1d..1d748fc5786b4 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; Widget buildSliverAppBarApp({ diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 108970ae20061..d22565e195bea 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - class StateMarker extends StatefulWidget { const StateMarker({ super.key, this.child }); diff --git a/packages/flutter/test/material/autocomplete_test.dart b/packages/flutter/test/material/autocomplete_test.dart index 4156a2f22ca74..2113bf6387eff 100644 --- a/packages/flutter/test/material/autocomplete_test.dart +++ b/packages/flutter/test/material/autocomplete_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - class User { const User({ required this.email, diff --git a/packages/flutter/test/material/badge_test.dart b/packages/flutter/test/material/badge_test.dart index aa131f4d9754b..6fe8c70fb4312 100644 --- a/packages/flutter/test/material/badge_test.dart +++ b/packages/flutter/test/material/badge_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { diff --git a/packages/flutter/test/material/badge_theme_test.dart b/packages/flutter/test/material/badge_theme_test.dart index 52c0b4ef3c557..9786e5639f1e1 100644 --- a/packages/flutter/test/material/badge_theme_test.dart +++ b/packages/flutter/test/material/badge_theme_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { test('BadgeThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/bottom_app_bar_test.dart b/packages/flutter/test/material/bottom_app_bar_test.dart index d02ee48eb8f9c..2c26051617d7b 100644 --- a/packages/flutter/test/material/bottom_app_bar_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_test.dart @@ -12,8 +12,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgetsWithLeakTracking('Material3 - Shadow effect is not doubled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123064 diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index 9fe03245592b5..92a1ec9af20e1 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -15,7 +15,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart' show Vector3; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index c4d356a04ae02..d952a67860f8d 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'feedback_tester.dart'; void main() { diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 3ae0bf9ffa24e..4732591978bdd 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import 'feedback_tester.dart'; Widget wrap({ required Widget child }) { diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart index 919ee8d267165..fb9aabe4ebc0c 100644 --- a/packages/flutter/test/material/checkbox_test.dart +++ b/packages/flutter/test/material/checkbox_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/services.dart'; import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index 6ff8e2e016e59..5beec65073f31 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { test('CheckboxThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index d7a8e9e802819..a8cba15354e4a 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 3cd47209e63da..13fa9dbf02900 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; RenderBox getMaterialBox(WidgetTester tester) { return tester.firstRenderObject( diff --git a/packages/flutter/test/material/choice_chip_test.dart b/packages/flutter/test/material/choice_chip_test.dart index da5277eccedd8..fcf584c2ceccd 100644 --- a/packages/flutter/test/material/choice_chip_test.dart +++ b/packages/flutter/test/material/choice_chip_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; RenderBox getMaterialBox(WidgetTester tester, Finder type) { return tester.firstRenderObject( diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 8dfdece1229ed..356301629fdfa 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -14,7 +14,6 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart' show Matrix3; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import 'data_table_test_utils.dart'; void main() { diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index a9b4783a8fe33..e91af3ac65f4b 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/packages/flutter/test/material/date_picker_theme_test.dart b/packages/flutter/test/material/date_picker_theme_test.dart index 681591cf8aa6c..4eaaff12d5899 100644 --- a/packages/flutter/test/material/date_picker_theme_test.dart +++ b/packages/flutter/test/material/date_picker_theme_test.dart @@ -8,8 +8,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { const DatePickerThemeData datePickerTheme = DatePickerThemeData( backgroundColor: Color(0xfffffff0), diff --git a/packages/flutter/test/material/divider_test.dart b/packages/flutter/test/material/divider_test.dart index 127af32dbaff3..c3326e70ec02d 100644 --- a/packages/flutter/test/material/divider_test.dart +++ b/packages/flutter/test/material/divider_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('Material3 - Divider control test', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index b4e067f08f9b8..149733508f81a 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; const List menuItems = ['one', 'two', 'three', 'four']; void onChanged(T _) { } diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index d2a3c9d14f86e..af49dca265ebe 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -23,7 +23,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index ae41aa252e855..0f504b52838c2 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index d9aa268dc23f6..b2d29c7142cac 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/filter_chip_test.dart b/packages/flutter/test/material/filter_chip_test.dart index 5c17e9a062fe3..68a94dd1178b5 100644 --- a/packages/flutter/test/material/filter_chip_test.dart +++ b/packages/flutter/test/material/filter_chip_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; /// Adds the basic requirements for a Chip. Widget wrapForChip({ diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index b7977105fe663..189573dfc0ccf 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -15,7 +15,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 81ea567224a95..19ea27f0ad222 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/inherited_theme_test.dart b/packages/flutter/test/material/inherited_theme_test.dart index 9cffa4706e76d..6f58948a794f5 100644 --- a/packages/flutter/test/material/inherited_theme_test.dart +++ b/packages/flutter/test/material/inherited_theme_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('Theme.wrap()', (WidgetTester tester) async { const Color primaryColor = Color(0xFF00FF00); diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index 7461ca8c4c4ab..5dc4710697c9c 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { testWidgetsWithLeakTracking('The Ink widget expands when no dimensions are set', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/ink_sparkle_test.dart b/packages/flutter/test/material/ink_sparkle_test.dart index 1cd3c006896e5..707c0d934d6af 100644 --- a/packages/flutter/test/material/ink_sparkle_test.dart +++ b/packages/flutter/test/material/ink_sparkle_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/src/foundation/constants.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { testWidgetsWithLeakTracking('InkSparkle in a Button compiles and does not crash', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/ink_splash_test.dart b/packages/flutter/test/material/ink_splash_test.dart index bcc8e40d25b77..aee79794695ad 100644 --- a/packages/flutter/test/material/ink_splash_test.dart +++ b/packages/flutter/test/material/ink_splash_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/21506. diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index c7a655ae4f400..1019d9bf4cab6 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/src/services/keyboard_key.g.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index 41dec6d6c0f62..a7f341072de94 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; /// Adds the basic requirements for a Chip. Widget wrapForChip({ diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 088cd67a5d1c7..28b44c614ea07 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -15,8 +15,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - Widget buildInputDecorator({ InputDecoration decoration = const InputDecoration(), ThemeData? theme, diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index dbc1cedeea598..962e31854cdfe 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index 88bfddfb3254f..f07f79528b6a3 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; class TestIcon extends StatefulWidget { const TestIcon({ super.key }); diff --git a/packages/flutter/test/material/material_button_test.dart b/packages/flutter/test/material/material_button_test.dart index c9718923ab811..1e79a48320e01 100644 --- a/packages/flutter/test/material/material_button_test.dart +++ b/packages/flutter/test/material/material_button_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index 33bc9c85b246a..e717fb242eafc 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/test_border.dart' show TestBorder; class NotifyMaterial extends StatelessWidget { diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index 220e7922405c8..e7a745490fd4f 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/mergeable_material_test.dart b/packages/flutter/test/material/mergeable_material_test.dart index b50f9de0e0a21..1d184edb0f5eb 100644 --- a/packages/flutter/test/material/mergeable_material_test.dart +++ b/packages/flutter/test/material/mergeable_material_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; enum RadiusType { Sharp, diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index f54f45e973bbd..63019b9a68f36 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -15,7 +15,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { testWidgetsWithLeakTracking('Navigation bar updates destinations when tapped', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index 4088b54f7ae57..ec1159c8a3e2e 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -11,7 +11,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 54596df58e149..1bc1fe8b29602 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -11,7 +11,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index a09d980067bf9..6f6728af70eff 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -13,8 +13,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('test page transition (_FadeUpwardsPageTransition)', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 3a8b4e2040e76..c986b90586077 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 886539bc361bb..21545cb3f83b2 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -19,7 +19,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { final ThemeData theme = ThemeData(); diff --git a/packages/flutter/test/material/radio_list_tile_test.dart b/packages/flutter/test/material/radio_list_tile_test.dart index b5c555083c5b8..84fcbe5d35e97 100644 --- a/packages/flutter/test/material/radio_list_tile_test.dart +++ b/packages/flutter/test/material/radio_list_tile_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index 04ab76fa01b3f..4ad6e7e9cbdcd 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -18,7 +18,6 @@ import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/radio_theme_test.dart b/packages/flutter/test/material/radio_theme_test.dart index c2d22b1f24882..d763972842ae5 100644 --- a/packages/flutter/test/material/radio_theme_test.dart +++ b/packages/flutter/test/material/radio_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { test('RadioThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index b1feb110ec642..0f4f2270469f9 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/105833 diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index 32f3430f64896..2306e083df160 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/src/services/keyboard_key.g.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/scrollbar_paint_test.dart b/packages/flutter/test/material/scrollbar_paint_test.dart index b261a6ef6845d..1686ff52e495d 100644 --- a/packages/flutter/test/material/scrollbar_paint_test.dart +++ b/packages/flutter/test/material/scrollbar_paint_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; const Color _kAndroidThumbIdleColor = Color(0xffbcbcbc); diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index e7f0d3f1b37bd..ffbaafea47512 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -18,7 +18,6 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300); const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600); diff --git a/packages/flutter/test/material/scrollbar_theme_test.dart b/packages/flutter/test/material/scrollbar_theme_test.dart index 286c4af61162d..15bb54f9f7d96 100644 --- a/packages/flutter/test/material/scrollbar_theme_test.dart +++ b/packages/flutter/test/material/scrollbar_theme_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; // The const represents the starting position of the scrollbar thumb for // the below tests. The thumb is 90 pixels long, and 8 pixels wide, with a 2 diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index d30cd8e0a67d6..60251704e9ca5 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -7,8 +7,6 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('SearchBar defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index a4641423e25e2..bc0caa645fb1b 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -11,7 +11,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; Widget boilerplate({required Widget child}) { diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 3b7de2c878590..10117fc38afba 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -14,7 +14,6 @@ import 'package:flutter/services.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; // A thumb shape that also logs its repaint center. diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index c4bbe9527569f..935e959afff4d 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { test('SliderThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index 6a57dbf5e2adb..c3801a8fcbb4d 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index c1fad4ed82c95..fa89e561f7fc6 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -19,7 +19,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/switch_theme_test.dart b/packages/flutter/test/material/switch_theme_test.dart index 86a459167ee01..900e0bc06a665 100644 --- a/packages/flutter/test/material/switch_theme_test.dart +++ b/packages/flutter/test/material/switch_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { test('SwitchThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 0f69b1019043c..4a6f518b6b2a4 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -14,8 +14,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - const String _tab1Text = 'tab 1'; const String _tab2Text = 'tab 2'; const String _tab3Text = 'tab 3'; diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index df4d34c3767d4..4b78963de5321 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -10,8 +10,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; -import '../rendering/recording_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 2db314e85e12c..1c3b757d2fa24 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -11,7 +11,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 058828d4f39bd..36373fec387cf 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -13,7 +13,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart'; diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index b613e5c7904aa..1e7ba83ced5b5 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; void main() { test('TextSelectionThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 6ea61ec228a4c..fca0bc614b0e4 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index f9a291a4c6c3b..44b480702a38c 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { test('TimePickerThemeData copyWith, ==, hashCode basics', () { expect(const TimePickerThemeData(), const TimePickerThemeData().copyWith()); diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index 8e4a059694bdd..a14363033b86e 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -13,7 +13,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; const double _defaultBorderWidth = 1.0; diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index 0bcd18bab899d..7b67cbe901edc 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; Widget boilerplate({required Widget child}) { return Directionality( diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index a08eb1693994d..8b68be4cbdf5f 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index 53ad6fe124fa0..75d623b1f0ed5 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/semantics_tester.dart'; const String tooltipText = 'TIP'; diff --git a/packages/flutter/test/painting/beveled_rectangle_border_test.dart b/packages/flutter/test/painting/beveled_rectangle_border_test.dart index c3d433040c548..4449af24ac3ee 100644 --- a/packages/flutter/test/painting/beveled_rectangle_border_test.dart +++ b/packages/flutter/test/painting/beveled_rectangle_border_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { test('BeveledRectangleBorder defaults', () { const BeveledRectangleBorder border = BeveledRectangleBorder(); diff --git a/packages/flutter/test/painting/border_rtl_test.dart b/packages/flutter/test/painting/border_rtl_test.dart index 47b4f1da4c8a2..bf5d47630f7fc 100644 --- a/packages/flutter/test/painting/border_rtl_test.dart +++ b/packages/flutter/test/painting/border_rtl_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/foundation.dart' show DiagnosticLevel, FlutterError; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - class SillyBorder extends BoxBorder { const SillyBorder(); diff --git a/packages/flutter/test/painting/box_decoration_test.dart b/packages/flutter/test/painting/box_decoration_test.dart index 94ff46b87f6af..d233439589dcc 100644 --- a/packages/flutter/test/painting/box_decoration_test.dart +++ b/packages/flutter/test/painting/box_decoration_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { test('BoxDecoration.lerp identical a,b', () { expect(BoxDecoration.lerp(null, null, 0), null); diff --git a/packages/flutter/test/painting/circle_border_test.dart b/packages/flutter/test/painting/circle_border_test.dart index 6bd15000e9e7f..9c56db5c2c95a 100644 --- a/packages/flutter/test/painting/circle_border_test.dart +++ b/packages/flutter/test/painting/circle_border_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'common_matchers.dart'; void main() { diff --git a/packages/flutter/test/painting/common_matchers.dart b/packages/flutter/test/painting/common_matchers.dart index 96c04b66ac61e..7c98519ef24f8 100644 --- a/packages/flutter/test/painting/common_matchers.dart +++ b/packages/flutter/test/painting/common_matchers.dart @@ -4,8 +4,6 @@ import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - final Matcher isUnitCircle = isPathThat( includes: [ const Offset(-0.6035617555492896, 0.2230970398703236), diff --git a/packages/flutter/test/painting/continuous_rectangle_border_test.dart b/packages/flutter/test/painting/continuous_rectangle_border_test.dart index 1f74c3c130b8d..47c48cd4e6405 100644 --- a/packages/flutter/test/painting/continuous_rectangle_border_test.dart +++ b/packages/flutter/test/painting/continuous_rectangle_border_test.dart @@ -10,8 +10,6 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { test('ContinuousRectangleBorder defaults', () { const ContinuousRectangleBorder border = ContinuousRectangleBorder(); diff --git a/packages/flutter/test/painting/linear_border_test.dart b/packages/flutter/test/painting/linear_border_test.dart index 7f14b691a007d..ed335221dae47 100644 --- a/packages/flutter/test/painting/linear_border_test.dart +++ b/packages/flutter/test/painting/linear_border_test.dart @@ -5,9 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - - const Rect canvasRect = Rect.fromLTWH(0, 0, 100, 100); const BorderSide borderSide = BorderSide(width: 4, color: Color(0x0f00ff00)); diff --git a/packages/flutter/test/painting/oval_border_test.dart b/packages/flutter/test/painting/oval_border_test.dart index 4b26dedfd6bb2..aabee9a7b32ad 100644 --- a/packages/flutter/test/painting/oval_border_test.dart +++ b/packages/flutter/test/painting/oval_border_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { test('OvalBorder defaults', () { const OvalBorder border = OvalBorder(); diff --git a/packages/flutter/test/painting/rounded_rectangle_border_test.dart b/packages/flutter/test/painting/rounded_rectangle_border_test.dart index 94acd9c660c06..8a8ec49cfac95 100644 --- a/packages/flutter/test/painting/rounded_rectangle_border_test.dart +++ b/packages/flutter/test/painting/rounded_rectangle_border_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'common_matchers.dart'; void main() { diff --git a/packages/flutter/test/painting/shape_border_test.dart b/packages/flutter/test/painting/shape_border_test.dart index 958d33fa47caa..d1a854bdb606e 100644 --- a/packages/flutter/test/painting/shape_border_test.dart +++ b/packages/flutter/test/painting/shape_border_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { test('Border.lerp identical a,b', () { expect(Border.lerp(null, null, 0), null); diff --git a/packages/flutter/test/painting/shape_decoration_test.dart b/packages/flutter/test/painting/shape_decoration_test.dart index 402aa70c3b6e1..8a193a5faafff 100644 --- a/packages/flutter/test/painting/shape_decoration_test.dart +++ b/packages/flutter/test/painting/shape_decoration_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../rendering/rendering_tester.dart'; void main() { diff --git a/packages/flutter/test/painting/stadium_border_test.dart b/packages/flutter/test/painting/stadium_border_test.dart index 257aa4a1516ff..2347e264e46c3 100644 --- a/packages/flutter/test/painting/stadium_border_test.dart +++ b/packages/flutter/test/painting/stadium_border_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/painting.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'common_matchers.dart'; void main() { diff --git a/packages/flutter/test/rendering/debug_overflow_indicator_test.dart b/packages/flutter/test/rendering/debug_overflow_indicator_test.dart index 8186f1714031e..7e49c164fa9c3 100644 --- a/packages/flutter/test/rendering/debug_overflow_indicator_test.dart +++ b/packages/flutter/test/rendering/debug_overflow_indicator_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('overflow indicator is not shown when not overflowing', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/rendering/debug_test.dart b/packages/flutter/test/rendering/debug_test.dart index 034f0144076a5..e3e73b9ff3a97 100644 --- a/packages/flutter/test/rendering/debug_test.dart +++ b/packages/flutter/test/rendering/debug_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:vector_math/vector_math_64.dart'; -import 'mock_canvas.dart'; import 'rendering_tester.dart'; void main() { diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart index d859ec1c63c92..c980447eaf093 100644 --- a/packages/flutter/test/rendering/editable_test.dart +++ b/packages/flutter/test/rendering/editable_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/services/text_input.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'mock_canvas.dart'; -import 'recording_canvas.dart'; import 'rendering_tester.dart'; void _applyParentData(List inlineRenderBoxes, InlineSpan span) { diff --git a/packages/flutter/test/rendering/error_test.dart b/packages/flutter/test/rendering/error_test.dart index adc98034a623f..8804f3319c6a5 100644 --- a/packages/flutter/test/rendering/error_test.dart +++ b/packages/flutter/test/rendering/error_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - /// Unit tests error.dart's usage via ErrorWidget. void main() { const String errorMessage = 'Some error message'; diff --git a/packages/flutter/test/rendering/flex_overflow_test.dart b/packages/flutter/test/rendering/flex_overflow_test.dart index 7774400da177e..0119c83919545 100644 --- a/packages/flutter/test/rendering/flex_overflow_test.dart +++ b/packages/flutter/test/rendering/flex_overflow_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'mock_canvas.dart'; - void main() { testWidgets('Flex overflow indicator', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/rendering/proxy_box_test.dart b/packages/flutter/test/rendering/proxy_box_test.dart index 38fe9a0a0b47a..45b34a1235e71 100644 --- a/packages/flutter/test/rendering/proxy_box_test.dart +++ b/packages/flutter/test/rendering/proxy_box_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'mock_canvas.dart'; import 'rendering_tester.dart'; void main() { diff --git a/packages/flutter/test/rendering/table_test.dart b/packages/flutter/test/rendering/table_test.dart index 78386e7c26084..521e695ada9eb 100644 --- a/packages/flutter/test/rendering/table_test.dart +++ b/packages/flutter/test/rendering/table_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'mock_canvas.dart'; import 'rendering_tester.dart'; RenderBox sizedBox(double width, double height) { diff --git a/packages/flutter/test/rendering/view_test.dart b/packages/flutter/test/rendering/view_test.dart index 6344c7a53b3b2..9caed8c544ac5 100644 --- a/packages/flutter/test/rendering/view_test.dart +++ b/packages/flutter/test/rendering/view_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'mock_canvas.dart'; import 'rendering_tester.dart'; void main() { diff --git a/packages/flutter/test/widgets/banner_test.dart b/packages/flutter/test/widgets/banner_test.dart index 06745df4af2af..2282d73143911 100644 --- a/packages/flutter/test/widgets/banner_test.dart +++ b/packages/flutter/test/widgets/banner_test.dart @@ -7,8 +7,6 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - class TestCanvas implements Canvas { final List invocations = []; diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index 0d9d4e1e95e03..42f36c0657e3e 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -11,7 +11,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../image_data.dart'; -import '../rendering/mock_canvas.dart'; class TestImageProvider extends ImageProvider { TestImageProvider(this.future); diff --git a/packages/flutter/test/widgets/clip_test.dart b/packages/flutter/test/widgets/clip_test.dart index 1a50011f61c8f..a959fa047cc49 100644 --- a/packages/flutter/test/widgets/clip_test.dart +++ b/packages/flutter/test/widgets/clip_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'test_border.dart' show TestBorder; final List log = []; diff --git a/packages/flutter/test/widgets/container_test.dart b/packages/flutter/test/widgets/container_test.dart index 37f08221419fe..fd5cc476f0b66 100644 --- a/packages/flutter/test/widgets/container_test.dart +++ b/packages/flutter/test/widgets/container_test.dart @@ -10,8 +10,6 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { group('Container control tests:', () { final Container container = Container( diff --git a/packages/flutter/test/widgets/decorated_sliver_test.dart b/packages/flutter/test/widgets/decorated_sliver_test.dart index a3d328fe72cd7..e5815243fdaae 100644 --- a/packages/flutter/test/widgets/decorated_sliver_test.dart +++ b/packages/flutter/test/widgets/decorated_sliver_test.dart @@ -10,8 +10,6 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('DecoratedSliver creates, paints, and disposes BoxPainter', (WidgetTester tester) async { final TestDecoration decoration = TestDecoration(); diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart index 62640cb5c1a2d..e52e7bcf91bf8 100644 --- a/packages/flutter/test/widgets/editable_text_cursor_test.dart +++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart @@ -16,7 +16,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'editable_text_utils.dart'; final TextEditingController controller = TextEditingController(); diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 3c8ebd855cd31..b1f15136b89c6 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../widgets/clipboard_utils.dart'; import 'editable_text_utils.dart'; import 'live_text_utils.dart'; diff --git a/packages/flutter/test/widgets/error_widget_builder_test.dart b/packages/flutter/test/widgets/error_widget_builder_test.dart index 6e9fa6eaaa13b..141f522209d71 100644 --- a/packages/flutter/test/widgets/error_widget_builder_test.dart +++ b/packages/flutter/test/widgets/error_widget_builder_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('ErrorWidget.builder', (WidgetTester tester) async { final ErrorWidgetBuilder oldBuilder = ErrorWidget.builder; diff --git a/packages/flutter/test/widgets/grid_view_test.dart b/packages/flutter/test/widgets/grid_view_test.dart index 1a4f29cedaf3a..90b9a945eb1fa 100644 --- a/packages/flutter/test/widgets/grid_view_test.dart +++ b/packages/flutter/test/widgets/grid_view_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; import 'states.dart'; diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 6d574d524ee1e..2fb1aa68771db 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -8,8 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - class TestImageProvider extends ImageProvider { const TestImageProvider(this.image); diff --git a/packages/flutter/test/widgets/list_view_test.dart b/packages/flutter/test/widgets/list_view_test.dart index 7187f6a726e2f..ab9185d18442b 100644 --- a/packages/flutter/test/widgets/list_view_test.dart +++ b/packages/flutter/test/widgets/list_view_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; class TestSliverChildListDelegate extends SliverChildListDelegate { diff --git a/packages/flutter/test/widgets/list_view_viewporting_test.dart b/packages/flutter/test/widgets/list_view_viewporting_test.dart index 43739d6a74fc4..0648cf99d57d0 100644 --- a/packages/flutter/test/widgets/list_view_viewporting_test.dart +++ b/packages/flutter/test/widgets/list_view_viewporting_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'test_widgets.dart'; void main() { diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart index a762693219cb0..a0e14026f8d93 100644 --- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart +++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart @@ -12,7 +12,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import '../rendering/rendering_tester.dart' show TestCallbackPainter, TestClipPaintingContext; void main() { diff --git a/packages/flutter/test/widgets/opacity_test.dart b/packages/flutter/test/widgets/opacity_test.dart index 804f35a0dbbc8..197720dcc22a1 100644 --- a/packages/flutter/test/widgets/opacity_test.dart +++ b/packages/flutter/test/widgets/opacity_test.dart @@ -11,7 +11,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/widgets/overlay_test.dart b/packages/flutter/test/widgets/overlay_test.dart index abb1d07f31e81..0914b06dff971 100644 --- a/packages/flutter/test/widgets/overlay_test.dart +++ b/packages/flutter/test/widgets/overlay_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/widgets/overscroll_indicator_test.dart b/packages/flutter/test/widgets/overscroll_indicator_test.dart index 3f4116d1070ad..340871db3230b 100644 --- a/packages/flutter/test/widgets/overscroll_indicator_test.dart +++ b/packages/flutter/test/widgets/overscroll_indicator_test.dart @@ -7,8 +7,6 @@ import 'dart:math' as math; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - final Matcher doesNotOverscroll = isNot(paints..circle()); Future slowDrag(WidgetTester tester, Offset start, Offset offset) async { diff --git a/packages/flutter/test/widgets/placeholder_test.dart b/packages/flutter/test/widgets/placeholder_test.dart index dcbdfdf8223b9..980f6473edc77 100644 --- a/packages/flutter/test/widgets/placeholder_test.dart +++ b/packages/flutter/test/widgets/placeholder_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void main() { testWidgets('Placeholder', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); diff --git a/packages/flutter/test/widgets/render_object_widget_test.dart b/packages/flutter/test/widgets/render_object_widget_test.dart index 39241cb18666a..e6ba52fd82307 100644 --- a/packages/flutter/test/widgets/render_object_widget_test.dart +++ b/packages/flutter/test/widgets/render_object_widget_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/recording_canvas.dart'; - final BoxDecoration kBoxDecorationA = BoxDecoration(border: nonconst(null)); final BoxDecoration kBoxDecorationB = BoxDecoration(border: nonconst(null)); final BoxDecoration kBoxDecorationC = BoxDecoration(border: nonconst(null)); diff --git a/packages/flutter/test/widgets/scrollbar_test.dart b/packages/flutter/test/widgets/scrollbar_test.dart index 4a20a61c183fa..1e2c831a44e09 100644 --- a/packages/flutter/test/widgets/scrollbar_test.dart +++ b/packages/flutter/test/widgets/scrollbar_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - const Color _kScrollbarColor = Color(0xFF123456); const double _kThickness = 2.5; const double _kMinThumbExtent = 18.0; diff --git a/packages/flutter/test/widgets/shape_decoration_test.dart b/packages/flutter/test/widgets/shape_decoration_test.dart index 36a0b4b4362d5..1926745869c43 100644 --- a/packages/flutter/test/widgets/shape_decoration_test.dart +++ b/packages/flutter/test/widgets/shape_decoration_test.dart @@ -10,7 +10,6 @@ import 'package:flutter_test/flutter_test.dart'; import '../image_data.dart'; import '../painting/mocks_for_image_cache.dart'; -import '../rendering/mock_canvas.dart'; import 'test_border.dart' show TestBorder; Future main() async { diff --git a/packages/flutter/test/widgets/sliver_visibility_test.dart b/packages/flutter/test/widgets/sliver_visibility_test.dart index bb02a1ceb6d2c..841563452f473 100644 --- a/packages/flutter/test/widgets/sliver_visibility_test.dart +++ b/packages/flutter/test/widgets/sliver_visibility_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'semantics_tester.dart'; class TestState extends StatefulWidget { diff --git a/packages/flutter/test/widgets/slivers_block_test.dart b/packages/flutter/test/widgets/slivers_block_test.dart index 7b7e771458b90..7b76ab452b551 100644 --- a/packages/flutter/test/widgets/slivers_block_test.dart +++ b/packages/flutter/test/widgets/slivers_block_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - Future test(WidgetTester tester, double offset) { return tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/slivers_test.dart b/packages/flutter/test/widgets/slivers_test.dart index 8f7bab5655438..0685d126a21f5 100644 --- a/packages/flutter/test/widgets/slivers_test.dart +++ b/packages/flutter/test/widgets/slivers_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'semantics_tester.dart'; Future test(WidgetTester tester, double offset, { double anchor = 0.0 }) { diff --git a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart index 1ec23fa8081f6..55b222b24fb80 100644 --- a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart +++ b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart @@ -8,8 +8,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - const Color green = Color(0xFF00FF00); const Color yellow = Color(0xFFFFFF00); diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index 5c2f69694c10d..fa09e584c5e25 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/widgets/visibility_test.dart b/packages/flutter/test/widgets/visibility_test.dart index 7f433146fbb47..cd11376111d50 100644 --- a/packages/flutter/test/widgets/visibility_test.dart +++ b/packages/flutter/test/widgets/visibility_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; import 'semantics_tester.dart'; class TestState extends StatefulWidget { diff --git a/packages/flutter/test/widgets/wrap_test.dart b/packages/flutter/test/widgets/wrap_test.dart index 70cd91dd139fd..1a132ef0255f2 100644 --- a/packages/flutter/test/widgets/wrap_test.dart +++ b/packages/flutter/test/widgets/wrap_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../rendering/mock_canvas.dart'; - void verify(WidgetTester tester, List answerKey) { final List testAnswers = tester.renderObjectList(find.byType(SizedBox)).map( (RenderBox target) => target.localToGlobal(Offset.zero), diff --git a/packages/flutter_test/lib/flutter_test.dart b/packages/flutter_test/lib/flutter_test.dart index 55e0d20ff160d..74483c1561bf4 100644 --- a/packages/flutter_test/lib/flutter_test.dart +++ b/packages/flutter_test/lib/flutter_test.dart @@ -69,9 +69,11 @@ export 'src/frame_timing_summarizer.dart'; export 'src/goldens.dart'; export 'src/image.dart'; export 'src/matchers.dart'; +export 'src/mock_canvas.dart'; export 'src/mock_event_channel.dart'; export 'src/nonconst.dart'; export 'src/platform.dart'; +export 'src/recording_canvas.dart'; export 'src/restoration.dart'; export 'src/stack_manipulation.dart'; export 'src/test_async_utils.dart'; diff --git a/packages/flutter/test/rendering/mock_canvas.dart b/packages/flutter_test/lib/src/mock_canvas.dart similarity index 82% rename from packages/flutter/test/rendering/mock_canvas.dart rename to packages/flutter_test/lib/src/mock_canvas.dart index 61a0aac9ef43e..f448aef1accef 100644 --- a/packages/flutter/test/rendering/mock_canvas.dart +++ b/packages/flutter_test/lib/src/mock_canvas.dart @@ -5,10 +5,12 @@ import 'dart:ui' as ui show Image, Paragraph; import 'package:flutter/foundation.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/widgets.dart'; +import 'package:matcher/expect.dart'; +import 'finders.dart'; import 'recording_canvas.dart'; +import 'test_async_utils.dart'; /// Matches objects or functions that paint a display list that matches the /// canvas calls described by the pattern. @@ -48,7 +50,8 @@ Matcher get paintsNothing => _TestRecordingCanvasPaintsNothingMatcher(); /// Matches objects or functions that assert when they try to paint. Matcher get paintsAssertion => _TestRecordingCanvasPaintsAssertionMatcher(); -/// Matches objects or functions that draw `methodName` exactly `count` number of times. +/// Matches objects or functions that draw `methodName` exactly `count` number +/// of times. Matcher paintsExactlyCountTimes(Symbol methodName, int count) { return _TestRecordingCanvasPaintsCountMatcher(methodName, count); } @@ -324,7 +327,8 @@ abstract class PaintPattern { /// /// Calls are skipped until a call to [Canvas.drawParagraph] is found. Any /// arguments that are passed to this method are compared to the actual - /// [Canvas.drawParagraph] call's argument, and any mismatches result in failure. + /// [Canvas.drawParagraph] call's argument, and any mismatches result in + /// failure. /// /// The `offset` argument can be either an [Offset] or a [Matcher]. If it is /// an [Offset] then the actual value must match the expected offset @@ -333,7 +337,8 @@ abstract class PaintPattern { /// assert that the actual offset is within a given distance from the expected /// offset. /// - /// If no call to [Canvas.drawParagraph] was made, then this results in failure. + /// If no call to [Canvas.drawParagraph] was made, then this results in + /// failure. void paragraph({ ui.Paragraph? paragraph, dynamic offset }); /// Indicates that a shadow is expected next. @@ -398,7 +403,8 @@ abstract class PaintPattern { /// Each method call after the last matched call (if any) will be passed to /// the given predicate, along with the values of its (positional) arguments. /// - /// For each one, the predicate must either return a boolean or throw a [String]. + /// For each one, the predicate must either return a boolean or throw a + /// [String]. /// /// If the predicate returns true, the call is considered a successful match /// and the next step in the pattern is examined. If this was the last step, @@ -421,7 +427,8 @@ abstract class PaintPattern { /// Each method call after the last matched call (if any) will be passed to /// the given predicate, along with the values of its (positional) arguments. /// - /// For each one, the predicate must either return a boolean or throw a [String]. + /// For each one, the predicate must either return a boolean or throw a + /// [String]. /// /// The predicate will be applied to each [Canvas] call until it returns false /// or all of the method calls have been tested. @@ -470,7 +477,8 @@ class _PathMatcher extends Matcher { if (errors.isEmpty) { return true; } - matchState[this] = 'Not all the given points were inside or outside the path as expected:\n ${errors.join("\n ")}'; + matchState[this] = 'Not all the given points were inside or outside the ' + 'path as expected:\n ${errors.join("\n ")}'; return false; } @@ -483,7 +491,8 @@ class _PathMatcher extends Matcher { } return '$count particular points'; } - return description.add('A Path that contains ${points(includes)} but does not contain ${points(excludes)}.'); + return description.add('A Path that contains ${points(includes)} but does ' + 'not contain ${points(excludes)}.'); } @override @@ -497,8 +506,8 @@ class _PathMatcher extends Matcher { } } -class _MismatchedCall { - const _MismatchedCall(this.message, this.callIntroduction, this.call); +class _MismatchedCall extends Error { + _MismatchedCall(this.message, this.callIntroduction, this.call); final String message; final String callIntroduction; final RecordedInvocation call; @@ -537,7 +546,8 @@ abstract class _TestRecordingCanvasMatcher extends Matcher { bool result = false; try { if (!_evaluatePainter(object, canvas, context)) { - matchState[this] = 'was not one of the supported objects for the "paints" matcher.'; + matchState[this] = 'was not one of the supported objects for the ' + '"paints" matcher.'; return false; } result = _evaluatePredicates(canvas.invocations, description); @@ -645,7 +655,8 @@ class _TestRecordingCanvasPaintsAssertionMatcher extends Matcher { bool result = false; try { if (!_evaluatePainter(object, canvas, context)) { - matchState[this] = 'was not one of the supported objects for the "paints" matcher.'; + matchState[this] = 'was not one of the supported objects for the ' + '"paints" matcher.'; return false; } prefixMessage = 'did not assert.'; @@ -823,8 +834,9 @@ class _TestRecordingCanvasPatternMatcher extends _TestRecordingCanvasMatcher imp } if (_predicates.isEmpty) { description.writeln( - 'It painted something, but you must now add a pattern to the paints matcher ' - 'in the test to verify that it matches the important parts of the following.', + 'It painted something, but you must now add a pattern to the paints ' + 'matcher in the test to verify that it matches the important parts of ' + 'the following.', ); return false; } @@ -864,11 +876,12 @@ abstract class _PaintPredicate { others += 1; if (!call.moveNext()) { throw _MismatchedCall( - 'It called $others other method${ others == 1 ? "" : "s" } on the canvas, ' - 'the first of which was $firstCall, but did not ' - 'call ${_symbolName(symbol)}() at the time where $this was expected.', - 'The first method that was called when the call to ${_symbolName(symbol)}() ' - 'was expected, $firstCall, was called with the following stack:', + 'It called $others other method${ others == 1 ? "" : "s" } on the ' + 'canvas, the first of which was $firstCall, but did not call ' + '${_symbolName(symbol)}() at the time where $this was expected.', + 'The first method that was called when the call to ' + '${_symbolName(symbol)}() was expected, $firstCall, was called with ' + 'the following stack:', firstCall, ); } @@ -911,7 +924,11 @@ abstract class _DrawCommandPaintPredicate extends _PaintPredicate { checkMethod(call, symbol); final int actualArgumentCount = call.current.invocation.positionalArguments.length; if (actualArgumentCount != argumentCount) { - throw 'It called $methodName with $actualArgumentCount argument${actualArgumentCount == 1 ? "" : "s"}; expected $argumentCount.'; + throw FlutterError( + 'It called $methodName with $actualArgumentCount ' + 'argument${actualArgumentCount == 1 ? "" : "s"}; expected ' + '$argumentCount.' + ); } verifyArguments(call.current.invocation.positionalArguments); call.moveNext(); @@ -922,23 +939,43 @@ abstract class _DrawCommandPaintPredicate extends _PaintPredicate { void verifyArguments(List arguments) { final Paint paintArgument = arguments[paintArgumentIndex] as Paint; if (color != null && paintArgument.color != color) { - throw 'It called $methodName with a paint whose color, ${paintArgument.color}, was not exactly the expected color ($color).'; + throw FlutterError( + 'It called $methodName with a paint whose color, ' + '${paintArgument.color}, was not exactly the expected color ($color).' + ); } if (strokeWidth != null && paintArgument.strokeWidth != strokeWidth) { - throw 'It called $methodName with a paint whose strokeWidth, ${paintArgument.strokeWidth}, was not exactly the expected strokeWidth ($strokeWidth).'; + throw FlutterError( + 'It called $methodName with a paint whose strokeWidth, ' + '${paintArgument.strokeWidth}, was not exactly the expected ' + 'strokeWidth ($strokeWidth).' + ); } if (hasMaskFilter != null && (paintArgument.maskFilter != null) != hasMaskFilter) { if (hasMaskFilter!) { - throw 'It called $methodName with a paint that did not have a mask filter, despite expecting one.'; + throw FlutterError( + 'It called $methodName with a paint that did not have a mask filter, ' + 'despite expecting one.' + ); } else { - throw 'It called $methodName with a paint that did have a mask filter, despite not expecting one.'; + throw FlutterError( + 'It called $methodName with a paint that had a mask filter, ' + 'despite not expecting one.' + ); } } if (style != null && paintArgument.style != style) { - throw 'It called $methodName with a paint whose style, ${paintArgument.style}, was not exactly the expected style ($style).'; + throw FlutterError( + 'It called $methodName with a paint whose style, ' + '${paintArgument.style}, was not exactly the expected style ($style).' + ); } if (strokeCap != null && paintArgument.strokeCap != strokeCap) { - throw 'It called $methodName with a paint whose strokeCap, ${paintArgument.strokeCap}, was not exactly the expected strokeCap ($strokeCap).'; + throw FlutterError( + 'It called $methodName with a paint whose strokeCap, ' + '${paintArgument.strokeCap}, was not exactly the expected ' + 'strokeCap ($strokeCap).' + ); } } @@ -976,20 +1013,11 @@ class _OneParameterPaintPredicate extends _DrawCommandPaintPredicate { Symbol symbol, String name, { required this.expected, - required Color? color, - required double? strokeWidth, - required bool? hasMaskFilter, - required PaintingStyle? style, - }) : super( - symbol, - name, - 2, - 1, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + required super.color, + required super.strokeWidth, + required super.hasMaskFilter, + required super.style, + }) : super(symbol, name, 2, 1); final T? expected; @@ -998,7 +1026,10 @@ class _OneParameterPaintPredicate extends _DrawCommandPaintPredicate { super.verifyArguments(arguments); final T actual = arguments[0] as T; if (expected != null && actual != expected) { - throw 'It called $methodName with $T, $actual, which was not exactly the expected $T ($expected).'; + throw FlutterError( + 'It called $methodName with $T, $actual, which was not exactly the ' + 'expected $T ($expected).' + ); } } @@ -1021,20 +1052,11 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { String name, { required this.expected1, required this.expected2, - required Color? color, - required double? strokeWidth, - required bool? hasMaskFilter, - required PaintingStyle? style, - }) : super( - symbol, - name, - 3, - 2, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + required super.color, + required super.strokeWidth, + required super.hasMaskFilter, + required super.style, + }) : super(symbol, name, 3, 2); final T1? expected1; @@ -1045,11 +1067,17 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { super.verifyArguments(arguments); final T1 actual1 = arguments[0] as T1; if (expected1 != null && actual1 != expected1) { - throw 'It called $methodName with its first argument (a $T1), $actual1, which was not exactly the expected $T1 ($expected1).'; + throw FlutterError( + 'It called $methodName with its first argument (a $T1), $actual1, ' + 'which was not exactly the expected $T1 ($expected1).' + ); } final T2 actual2 = arguments[1] as T2; if (expected2 != null && actual2 != expected2) { - throw 'It called $methodName with its second argument (a $T2), $actual2, which was not exactly the expected $T2 ($expected2).'; + throw FlutterError( + 'It called $methodName with its second argument (a $T2), $actual2, ' + 'which was not exactly the expected $T2 ($expected2).' + ); } } @@ -1074,28 +1102,23 @@ class _TwoParameterPaintPredicate extends _DrawCommandPaintPredicate { } class _RectPaintPredicate extends _OneParameterPaintPredicate { - _RectPaintPredicate({ Rect? rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawRect, - 'a rectangle', - expected: rect, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _RectPaintPredicate({ + Rect? rect, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawRect, 'a rectangle', expected: rect); } class _RRectPaintPredicate extends _DrawCommandPaintPredicate { - _RRectPaintPredicate({ this.rrect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawRRect, - 'a rounded rectangle', - 2, - 1, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _RRectPaintPredicate({ + this.rrect, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawRRect, 'a rounded rectangle', 2, 1); final RRect? rrect; @@ -1117,7 +1140,10 @@ class _RRectPaintPredicate extends _DrawCommandPaintPredicate { (actual.tlRadiusY - rrect!.tlRadiusY).abs() > eps || (actual.trRadiusX - rrect!.trRadiusX).abs() > eps || (actual.trRadiusY - rrect!.trRadiusY).abs() > eps)) { - throw 'It called $methodName with RRect, $actual, which was not exactly the expected RRect ($rrect).'; + throw FlutterError( + 'It called $methodName with RRect, $actual, which was not exactly the ' + 'expected RRect ($rrect).' + ); } } @@ -1131,22 +1157,26 @@ class _RRectPaintPredicate extends _DrawCommandPaintPredicate { } class _DRRectPaintPredicate extends _TwoParameterPaintPredicate { - _DRRectPaintPredicate({ RRect? inner, RRect? outer, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawDRRect, - 'a rounded rectangle outline', - expected1: outer, - expected2: inner, - color: color, - strokeWidth: strokeWidth, - hasMaskFilter: hasMaskFilter, - style: style, - ); + _DRRectPaintPredicate({ + RRect? inner, + RRect? outer, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawDRRect, 'a rounded rectangle outline', expected1: outer, expected2: inner); } class _CirclePaintPredicate extends _DrawCommandPaintPredicate { - _CirclePaintPredicate({ this.x, this.y, this.radius, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawCircle, 'a circle', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _CirclePaintPredicate({ + this.x, + this.y, + this.radius, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawCircle, 'a circle', 3, 2); final double? x; final double? y; @@ -1159,19 +1189,34 @@ class _CirclePaintPredicate extends _DrawCommandPaintPredicate { if (x != null && y != null) { final Offset point = Offset(x!, y!); if (point != pointArgument) { - throw 'It called $methodName with a center coordinate, $pointArgument, which was not exactly the expected coordinate ($point).'; + throw FlutterError( + 'It called $methodName with a center coordinate, $pointArgument, ' + 'which was not exactly the expected coordinate ($point).' + ); } } else { if (x != null && pointArgument.dx != x) { - throw 'It called $methodName with a center coordinate, $pointArgument, whose x-coordinate not exactly the expected coordinate (${x!.toStringAsFixed(1)}).'; + throw FlutterError( + 'It called $methodName with a center coordinate, $pointArgument, ' + 'whose x-coordinate was not exactly the expected coordinate ' + '(${x!.toStringAsFixed(1)}).' + ); } if (y != null && pointArgument.dy != y) { - throw 'It called $methodName with a center coordinate, $pointArgument, whose y-coordinate not exactly the expected coordinate (${y!.toStringAsFixed(1)}).'; + throw FlutterError( + 'It called $methodName with a center coordinate, $pointArgument, ' + 'whose y-coordinate was not exactly the expected coordinate ' + '(${y!.toStringAsFixed(1)}).' + ); } } final double radiusArgument = arguments[1] as double; if (radius != null && radiusArgument != radius) { - throw 'It called $methodName with radius, ${radiusArgument.toStringAsFixed(1)}, which was not exactly the expected radius (${radius!.toStringAsFixed(1)}).'; + throw FlutterError( + 'It called $methodName with radius, ' + '${radiusArgument.toStringAsFixed(1)}, which was not exactly the ' + 'expected radius (${radius!.toStringAsFixed(1)}).' + ); } } @@ -1195,9 +1240,14 @@ class _CirclePaintPredicate extends _DrawCommandPaintPredicate { } class _PathPaintPredicate extends _DrawCommandPaintPredicate { - _PathPaintPredicate({ this.includes, this.excludes, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawPath, 'a path', 2, 1, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _PathPaintPredicate({ + this.includes, + this.excludes, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawPath, 'a path', 2, 1); final Iterable? includes; final Iterable? excludes; @@ -1209,14 +1259,20 @@ class _PathPaintPredicate extends _DrawCommandPaintPredicate { if (includes != null) { for (final Offset offset in includes!) { if (!pathArgument.contains(offset)) { - throw 'It called $methodName with a path that unexpectedly did not contain $offset.'; + throw FlutterError( + 'It called $methodName with a path that unexpectedly did not ' + 'contain $offset.' + ); } } } if (excludes != null) { for (final Offset offset in excludes!) { if (pathArgument.contains(offset)) { - throw 'It called $methodName with a path that unexpectedly contained $offset.'; + throw FlutterError( + 'It called $methodName with a path that unexpectedly contained ' + '$offset.' + ); } } } @@ -1237,9 +1293,14 @@ class _PathPaintPredicate extends _DrawCommandPaintPredicate { // TODO(ianh): add arguments to test the length, angle, that kind of thing class _LinePaintPredicate extends _DrawCommandPaintPredicate { - _LinePaintPredicate({ this.p1, this.p2, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawLine, 'a line', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _LinePaintPredicate({ + this.p1, + this.p2, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawLine, 'a line', 3, 2); final Offset? p1; final Offset? p2; @@ -1248,15 +1309,23 @@ class _LinePaintPredicate extends _DrawCommandPaintPredicate { void verifyArguments(List arguments) { super.verifyArguments(arguments); // Checks the 3rd argument, a Paint if (arguments.length != 3) { - throw 'It called $methodName with ${arguments.length} arguments; expected 3.'; + throw FlutterError( + 'It called $methodName with ${arguments.length} arguments; expected 3.' + ); } final Offset p1Argument = arguments[0] as Offset; final Offset p2Argument = arguments[1] as Offset; if (p1 != null && p1Argument != p1) { - throw 'It called $methodName with p1 endpoint, $p1Argument, which was not exactly the expected endpoint ($p1).'; + throw FlutterError( + 'It called $methodName with p1 endpoint, $p1Argument, which was not ' + 'exactly the expected endpoint ($p1).' + ); } if (p2 != null && p2Argument != p2) { - throw 'It called $methodName with p2 endpoint, $p2Argument, which was not exactly the expected endpoint ($p2).'; + throw FlutterError( + 'It called $methodName with p2 endpoint, $p2Argument, which was not ' + 'exactly the expected endpoint ($p2).' + ); } } @@ -1273,9 +1342,14 @@ class _LinePaintPredicate extends _DrawCommandPaintPredicate { } class _ArcPaintPredicate extends _DrawCommandPaintPredicate { - _ArcPaintPredicate({ this.rect, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style, StrokeCap? strokeCap }) : super( - #drawArc, 'an arc', 5, 4, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, strokeCap: strokeCap, - ); + _ArcPaintPredicate({ + this.rect, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + super.strokeCap, + }) : super(#drawArc, 'an arc', 5, 4); final Rect? rect; @@ -1284,7 +1358,10 @@ class _ArcPaintPredicate extends _DrawCommandPaintPredicate { super.verifyArguments(arguments); final Rect rectArgument = arguments[0] as Rect; if (rect != null && rectArgument != rect) { - throw 'It called $methodName with a paint whose rect, $rectArgument, was not exactly the expected rect ($rect).'; + throw FlutterError( + 'It called $methodName with a paint whose rect, $rectArgument, was not ' + 'exactly the expected rect ($rect).' + ); } } @@ -1312,34 +1389,52 @@ class _ShadowPredicate extends _PaintPredicate { @protected void verifyArguments(List arguments) { if (arguments.length != 4) { - throw 'It called $methodName with ${arguments.length} arguments; expected 4.'; + throw FlutterError( + 'It called $methodName with ${arguments.length} arguments; expected 4.' + ); } final Path pathArgument = arguments[0] as Path; if (includes != null) { for (final Offset offset in includes!) { if (!pathArgument.contains(offset)) { - throw 'It called $methodName with a path that unexpectedly did not contain $offset.'; + throw FlutterError( + 'It called $methodName with a path that unexpectedly did not ' + 'contain $offset.' + ); } } } if (excludes != null) { for (final Offset offset in excludes!) { if (pathArgument.contains(offset)) { - throw 'It called $methodName with a path that unexpectedly contained $offset.'; + throw FlutterError( + 'It called $methodName with a path that unexpectedly contained ' + '$offset.' + ); } } } final Color actualColor = arguments[1] as Color; if (color != null && actualColor != color) { - throw 'It called $methodName with a color, $actualColor, which was not exactly the expected color ($color).'; + throw FlutterError( + 'It called $methodName with a color, $actualColor, which was not ' + 'exactly the expected color ($color).' + ); } final double actualElevation = arguments[2] as double; if (elevation != null && actualElevation != elevation) { - throw 'It called $methodName with an elevation, $actualElevation, which was not exactly the expected value ($elevation).'; + throw FlutterError( + 'It called $methodName with an elevation, $actualElevation, which was ' + 'not exactly the expected value ($elevation).' + ); } final bool actualTransparentOccluder = arguments[3] as bool; if (transparentOccluder != null && actualTransparentOccluder != transparentOccluder) { - throw 'It called $methodName with a transparentOccluder value, $actualTransparentOccluder, which was not exactly the expected value ($transparentOccluder).'; + throw FlutterError( + 'It called $methodName with a transparentOccluder value, ' + '$actualTransparentOccluder, which was not exactly the expected value ' + '($transparentOccluder).' + ); } } @@ -1383,9 +1478,15 @@ class _ShadowPredicate extends _PaintPredicate { } class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { - _DrawImagePaintPredicate({ this.image, this.x, this.y, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawImage, 'an image', 3, 2, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _DrawImagePaintPredicate({ + this.image, + this.x, + this.y, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawImage, 'an image', 3, 2); final ui.Image? image; final double? x; @@ -1396,20 +1497,34 @@ class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { super.verifyArguments(arguments); final ui.Image imageArgument = arguments[0] as ui.Image; if (image != null && !image!.isCloneOf(imageArgument)) { - throw 'It called $methodName with an image, $imageArgument, which was not exactly the expected image ($image).'; + throw FlutterError( + 'It called $methodName with an image, $imageArgument, which was not ' + 'exactly the expected image ($image).' + ); } final Offset pointArgument = arguments[0] as Offset; if (x != null && y != null) { final Offset point = Offset(x!, y!); if (point != pointArgument) { - throw 'It called $methodName with an offset coordinate, $pointArgument, which was not exactly the expected coordinate ($point).'; + throw FlutterError( + 'It called $methodName with an offset coordinate, $pointArgument, ' + 'which was not exactly the expected coordinate ($point).' + ); } } else { if (x != null && pointArgument.dx != x) { - throw 'It called $methodName with an offset coordinate, $pointArgument, whose x-coordinate not exactly the expected coordinate (${x!.toStringAsFixed(1)}).'; + throw FlutterError( + 'It called $methodName with an offset coordinate, $pointArgument, ' + 'whose x-coordinate was not exactly the expected coordinate ' + '(${x!.toStringAsFixed(1)}).' + ); } if (y != null && pointArgument.dy != y) { - throw 'It called $methodName with an offset coordinate, $pointArgument, whose y-coordinate not exactly the expected coordinate (${y!.toStringAsFixed(1)}).'; + throw FlutterError( + 'It called $methodName with an offset coordinate, $pointArgument, ' + 'whose y-coordinate was not exactly the expected coordinate ' + '(${y!.toStringAsFixed(1)}).' + ); } } } @@ -1434,9 +1549,15 @@ class _DrawImagePaintPredicate extends _DrawCommandPaintPredicate { } class _DrawImageRectPaintPredicate extends _DrawCommandPaintPredicate { - _DrawImageRectPaintPredicate({ this.image, this.source, this.destination, Color? color, double? strokeWidth, bool? hasMaskFilter, PaintingStyle? style }) : super( - #drawImageRect, 'an image', 4, 3, color: color, strokeWidth: strokeWidth, hasMaskFilter: hasMaskFilter, style: style, - ); + _DrawImageRectPaintPredicate({ + this.image, + this.source, + this.destination, + super.color, + super.strokeWidth, + super.hasMaskFilter, + super.style, + }) : super(#drawImageRect, 'an image', 4, 3); final ui.Image? image; final Rect? source; @@ -1447,15 +1568,25 @@ class _DrawImageRectPaintPredicate extends _DrawCommandPaintPredicate { super.verifyArguments(arguments); final ui.Image imageArgument = arguments[0] as ui.Image; if (image != null && !image!.isCloneOf(imageArgument)) { - throw 'It called $methodName with an image, $imageArgument, which was not exactly the expected image ($image).'; + throw FlutterError( + 'It called $methodName with an image, $imageArgument, which was not ' + 'exactly the expected image ($image).' + ); } final Rect sourceArgument = arguments[1] as Rect; if (source != null && sourceArgument != source) { - throw 'It called $methodName with a source rectangle, $sourceArgument, which was not exactly the expected rectangle ($source).'; + throw FlutterError( + 'It called $methodName with a source rectangle, $sourceArgument, which ' + 'was not exactly the expected rectangle ($source).' + ); } final Rect destinationArgument = arguments[2] as Rect; if (destination != null && destinationArgument != destination) { - throw 'It called $methodName with a destination rectangle, $destinationArgument, which was not exactly the expected rectangle ($destination).'; + throw FlutterError( + 'It called $methodName with a destination rectangle, ' + '$destinationArgument, which was not exactly the expected rectangle ' + '($destination).' + ); } } @@ -1485,12 +1616,17 @@ class _SomethingPaintPredicate extends _PaintPredicate { bool testedAllCalls = false; do { if (testedAllCalls) { - throw 'It painted methods that the predicate passed to a "something" step, ' - 'in the paint pattern, none of which were considered correct.'; + throw FlutterError( + 'It painted methods that the predicate passed to a "something" step, ' + 'in the paint pattern, none of which were considered correct.' + ); } currentCall = call.current; if (!currentCall.invocation.isMethod) { - throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; + throw FlutterError( + 'It called $currentCall, which was not a method, when the paint ' + 'pattern expected a method call' + ); } testedAllCalls = !call.moveNext(); } while (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)); @@ -1500,8 +1636,10 @@ class _SomethingPaintPredicate extends _PaintPredicate { try { return predicate(methodName, arguments); } on String catch (s) { - throw 'It painted something that the predicate passed to a "something" step ' - 'in the paint pattern considered incorrect:\n $s\n '; + throw FlutterError( + 'It painted something that the predicate passed to a "something" step ' + 'in the paint pattern considered incorrect:\n $s\n ' + ); } } @@ -1519,11 +1657,16 @@ class _EverythingPaintPredicate extends _PaintPredicate { do { final RecordedInvocation currentCall = call.current; if (!currentCall.invocation.isMethod) { - throw 'It called $currentCall, which was not a method, when the paint pattern expected a method call'; + throw FlutterError( + 'It called $currentCall, which was not a method, when the paint ' + 'pattern expected a method call' + ); } if (!_runPredicate(currentCall.invocation.memberName, currentCall.invocation.positionalArguments)) { - throw 'It painted something that the predicate passed to an "everything" step ' - 'in the paint pattern considered incorrect.\n'; + throw FlutterError( + 'It painted something that the predicate passed to an "everything" ' + 'step in the paint pattern considered incorrect.\n' + ); } } while (call.moveNext()); } @@ -1532,8 +1675,10 @@ class _EverythingPaintPredicate extends _PaintPredicate { try { return predicate(methodName, arguments); } on String catch (s) { - throw 'It painted something that the predicate passed to an "everything" step ' - 'in the paint pattern considered incorrect:\n $s\n '; + throw FlutterError( + 'It painted something that the predicate passed to an "everything" step ' + 'in the paint pattern considered incorrect:\n $s\n ' + ); } } @@ -1552,7 +1697,11 @@ class _FunctionPaintPredicate extends _PaintPredicate { void match(Iterator call) { checkMethod(call, symbol); if (call.current.invocation.positionalArguments.length != arguments.length) { - throw 'It called ${_symbolName(symbol)} with ${call.current.invocation.positionalArguments.length} arguments; expected ${arguments.length}.'; + throw FlutterError( + 'It called ${_symbolName(symbol)} with ' + '${call.current.invocation.positionalArguments.length} arguments; ' + 'expected ${arguments.length}.' + ); } for (int index = 0; index < arguments.length; index += 1) { final dynamic actualArgument = call.current.invocation.positionalArguments[index]; @@ -1561,7 +1710,11 @@ class _FunctionPaintPredicate extends _PaintPredicate { if (desiredArgument is Matcher) { expect(actualArgument, desiredArgument); } else if (desiredArgument != null && desiredArgument != actualArgument) { - throw 'It called ${_symbolName(symbol)} with argument $index having value ${_valueName(actualArgument)} when ${_valueName(desiredArgument)} was expected.'; + throw FlutterError( + 'It called ${_symbolName(symbol)} with argument $index having value ' + '${_valueName(actualArgument)} when ${_valueName(desiredArgument)} ' + 'was expected.' + ); } } call.moveNext(); @@ -1584,7 +1737,10 @@ class _SaveRestorePairPaintPredicate extends _PaintPredicate { int depth = 1; while (depth > 0) { if (!call.moveNext()) { - throw 'It did not have a matching restore() for the save() that was found where $this was expected.'; + throw FlutterError( + 'It did not have a matching restore() for the save() that was found ' + 'where $this was expected.' + ); } if (call.current.invocation.isMethod) { if (call.current.invocation.memberName == #save) { diff --git a/packages/flutter/test/rendering/recording_canvas.dart b/packages/flutter_test/lib/src/recording_canvas.dart similarity index 99% rename from packages/flutter/test/rendering/recording_canvas.dart rename to packages/flutter_test/lib/src/recording_canvas.dart index 62031fd07fbe5..04bda6f451e30 100644 --- a/packages/flutter/test/rendering/recording_canvas.dart +++ b/packages/flutter_test/lib/src/recording_canvas.dart @@ -26,7 +26,8 @@ class RecordedInvocation { @override String toString() => _describeInvocation(invocation); - /// Converts [stack] to a string using the [FlutterError.defaultStackFilter] logic. + /// Converts [stack] to a string using the [FlutterError.defaultStackFilter] + /// logic. String stackToString({ String indent = '' }) { return indent + FlutterError.defaultStackFilter( stack.toString().trimRight().split('\n'), diff --git a/packages/flutter/test/rendering/mock_canvas_test.dart b/packages/flutter_test/test/mock_canvas_test.dart similarity index 98% rename from packages/flutter/test/rendering/mock_canvas_test.dart rename to packages/flutter_test/test/mock_canvas_test.dart index 82cccc1bde075..5980b9e2fbc74 100644 --- a/packages/flutter/test/rendering/mock_canvas_test.dart +++ b/packages/flutter_test/test/mock_canvas_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'mock_canvas.dart'; - class MyPainter extends CustomPainter { const MyPainter({ required this.color, @@ -131,7 +129,7 @@ void main() { return false; } if (method == #drawColor) { - throw 'fail'; + fail('fail'); } return true; }), @@ -225,7 +223,7 @@ void main() { paints..everything((Symbol method, List arguments) { methodsAndArguments.add(MethodAndArguments(method, arguments)); if (method == #drawColor) { - throw 'failed '; + fail('failed '); } return true; }), From 55fe41be598a391b88490c9175f03e8feaa7759f Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Mon, 7 Aug 2023 19:45:19 -0400 Subject: [PATCH 0579/1547] [web] New HtmlElementView.fromTagName constructor (#130513) This wraps up the platform view improvements discussed in https://github.com/flutter/flutter/issues/127030. - Splits `HtmlElementView` into 2 files that are conditionally imported. - The non-web version can be instantiated but it throws if it ends up being built in a widget tree. - Out-of-the-box view factories that create visible & invisible DOM elements given a `tagName` parameter. - New `HtmlElementView.fromTagName()` constructor that uses the default factories to create DOM elements. - Tests covering the new API. Depends on https://github.com/flutter/engine/pull/43828 Fixes https://github.com/flutter/flutter/issues/127030 --- .../src/widgets/_html_element_view_io.dart | 34 ++ .../src/widgets/_html_element_view_web.dart | 136 ++++++++ .../lib/src/widgets/platform_view.dart | 133 ++++---- .../test/services/fake_platform_views.dart | 99 ------ .../test/widgets/html_element_view_test.dart | 300 +++++++++++++++--- .../test/widgets/platform_view_test.dart | 2 +- 6 files changed, 487 insertions(+), 217 deletions(-) create mode 100644 packages/flutter/lib/src/widgets/_html_element_view_io.dart create mode 100644 packages/flutter/lib/src/widgets/_html_element_view_web.dart diff --git a/packages/flutter/lib/src/widgets/_html_element_view_io.dart b/packages/flutter/lib/src/widgets/_html_element_view_io.dart new file mode 100644 index 0000000000000..e1c23e2d9ebf0 --- /dev/null +++ b/packages/flutter/lib/src/widgets/_html_element_view_io.dart @@ -0,0 +1,34 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: prefer_const_constructors_in_immutables +// ignore_for_file: avoid_unused_constructor_parameters + +import 'framework.dart'; +import 'platform_view.dart'; + +/// The platform-specific implementation of [HtmlElementView]. +extension HtmlElementViewImpl on HtmlElementView { + /// Creates an [HtmlElementView] that renders a DOM element with the given + /// [tagName]. + static HtmlElementView createFromTagName({ + Key? key, + required String tagName, + bool isVisible = true, + ElementCreatedCallback? onElementCreated, + }) { + throw UnimplementedError('HtmlElementView is only available on Flutter Web'); + } + + /// Called from [HtmlElementView.build] to build the widget tree. + /// + /// This is not expected to be invoked in non-web environments. It throws if + /// that happens. + /// + /// The implementation on Flutter Web builds a platform view and handles its + /// lifecycle. + Widget buildImpl(BuildContext context) { + throw UnimplementedError('HtmlElementView is only available on Flutter Web'); + } +} diff --git a/packages/flutter/lib/src/widgets/_html_element_view_web.dart b/packages/flutter/lib/src/widgets/_html_element_view_web.dart new file mode 100644 index 0000000000000..fa7060e6adfe7 --- /dev/null +++ b/packages/flutter/lib/src/widgets/_html_element_view_web.dart @@ -0,0 +1,136 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui_web' as ui_web; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; + +import 'framework.dart'; +import 'platform_view.dart'; + +/// The platform-specific implementation of [HtmlElementView]. +extension HtmlElementViewImpl on HtmlElementView { + /// Creates an [HtmlElementView] that renders a DOM element with the given + /// [tagName]. + static HtmlElementView createFromTagName({ + Key? key, + required String tagName, + bool isVisible = true, + ElementCreatedCallback? onElementCreated, + }) { + return HtmlElementView( + key: key, + viewType: isVisible ? ui_web.PlatformViewRegistry.defaultVisibleViewType : ui_web.PlatformViewRegistry.defaultInvisibleViewType, + onPlatformViewCreated: _createPlatformViewCallbackForElementCallback(onElementCreated), + creationParams: {'tagName': tagName}, + ); + } + + /// The implementation of [HtmlElementView.build]. + /// + /// This is not expected to be invoked in non-web environments. It throws if + /// that happens. + /// + /// The implementation on Flutter Web builds an HTML platform view and handles + /// its lifecycle. + Widget buildImpl(BuildContext context) { + return PlatformViewLink( + viewType: viewType, + onCreatePlatformView: _createController, + surfaceFactory: (BuildContext context, PlatformViewController controller) { + return PlatformViewSurface( + controller: controller, + gestureRecognizers: const >{}, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + ); + } + + /// Creates the controller and kicks off its initialization. + _HtmlElementViewController _createController( + PlatformViewCreationParams params, + ) { + final _HtmlElementViewController controller = _HtmlElementViewController( + params.id, + viewType, + creationParams, + ); + controller._initialize().then((_) { + params.onPlatformViewCreated(params.id); + onPlatformViewCreated?.call(params.id); + }); + return controller; + } +} + +PlatformViewCreatedCallback? _createPlatformViewCallbackForElementCallback( + ElementCreatedCallback? onElementCreated, +) { + if (onElementCreated == null) { + return null; + } + return (int id) { + onElementCreated(_platformViewsRegistry.getViewById(id)); + }; +} + +class _HtmlElementViewController extends PlatformViewController { + _HtmlElementViewController( + this.viewId, + this.viewType, + this.creationParams, + ); + + @override + final int viewId; + + /// The unique identifier for the HTML view type to be embedded by this widget. + /// + /// A PlatformViewFactory for this type must have been registered. + final String viewType; + + final dynamic creationParams; + + bool _initialized = false; + + Future _initialize() async { + final Map args = { + 'id': viewId, + 'viewType': viewType, + 'params': creationParams, + }; + await SystemChannels.platform_views.invokeMethod('create', args); + _initialized = true; + } + + @override + Future clearFocus() async { + // Currently this does nothing on Flutter Web. + // TODO(het): Implement this. See https://github.com/flutter/flutter/issues/39496 + } + + @override + Future dispatchPointerEvent(PointerEvent event) async { + // We do not dispatch pointer events to HTML views because they may contain + // cross-origin iframes, which only accept user-generated events. + } + + @override + Future dispose() async { + if (_initialized) { + await SystemChannels.platform_views.invokeMethod('dispose', viewId); + } + } +} + +/// Overrides the [ui_web.PlatformViewRegistry] used by [HtmlElementView]. +/// +/// This is used for testing view factory registration. +@visibleForTesting +ui_web.PlatformViewRegistry? debugOverridePlatformViewRegistry; +ui_web.PlatformViewRegistry get _platformViewsRegistry => debugOverridePlatformViewRegistry ?? ui_web.platformViewRegistry; diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index a780994ff68dd..96389c014b6a4 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; +import '_html_element_view_io.dart' if (dart.library.js_util) '_html_element_view_web.dart'; import 'basic.dart'; import 'debug.dart'; import 'focus_manager.dart'; @@ -324,6 +325,14 @@ class UiKitView extends _DarwinView { State createState() => _UiKitViewState(); } +/// Callback signature for when the platform view's DOM element was created. +/// +/// [element] is the DOM element that was created. +/// +/// Also see [HtmlElementView.fromTagName] that uses this callback +/// signature. +typedef ElementCreatedCallback = void Function(Object element); + /// Embeds an HTML element in the Widget hierarchy in Flutter Web. /// /// *NOTE*: This only works in Flutter Web. To embed web content on other @@ -368,6 +377,52 @@ class HtmlElementView extends StatelessWidget { this.creationParams, }); + /// Creates a platform view that creates a DOM element specified by [tagName]. + /// + /// [isVisible] indicates whether the view is visible to the user or not. + /// Setting this to false allows the rendering pipeline to perform extra + /// optimizations knowing that the view will not result in any pixels painted + /// on the screen. + /// + /// [onElementCreated] is called when the DOM element is created. It can be + /// used by the app to customize the element by adding attributes and styles. + /// + /// ```dart + /// import 'package:flutter/widgets.dart'; + /// import 'package:web/web.dart' as web; + /// + /// // ... + /// + /// class MyWidget extends StatelessWidget { + /// const MyWidget({super.key}); + /// + /// @override + /// Widget build(BuildContext context) { + /// return HtmlElementView.fromTagName( + /// tagName: 'div', + /// onElementCreated: (Object element) { + /// element as web.HTMLElement; + /// element.style + /// ..backgroundColor = 'blue' + /// ..border = '1px solid red'; + /// }, + /// ); + /// } + /// } + /// ``` + factory HtmlElementView.fromTagName({ + Key? key, + required String tagName, + bool isVisible = true, + ElementCreatedCallback? onElementCreated, + }) => + HtmlElementViewImpl.createFromTagName( + key: key, + tagName: tagName, + isVisible: isVisible, + onElementCreated: onElementCreated, + ); + /// The unique identifier for the HTML view type to be embedded by this widget. /// /// A PlatformViewFactory for this type must have been registered. @@ -382,83 +437,7 @@ class HtmlElementView extends StatelessWidget { final Object? creationParams; @override - Widget build(BuildContext context) { - assert(kIsWeb, 'HtmlElementView is only available on Flutter Web.'); - return PlatformViewLink( - viewType: viewType, - onCreatePlatformView: _createHtmlElementView, - surfaceFactory: (BuildContext context, PlatformViewController controller) { - return PlatformViewSurface( - controller: controller, - gestureRecognizers: const >{}, - hitTestBehavior: PlatformViewHitTestBehavior.opaque, - ); - }, - ); - } - - /// Creates the controller and kicks off its initialization. - _HtmlElementViewController _createHtmlElementView(PlatformViewCreationParams params) { - final _HtmlElementViewController controller = _HtmlElementViewController( - params.id, - viewType, - creationParams, - ); - controller._initialize().then((_) { - params.onPlatformViewCreated(params.id); - onPlatformViewCreated?.call(params.id); - }); - return controller; - } -} - -class _HtmlElementViewController extends PlatformViewController { - _HtmlElementViewController( - this.viewId, - this.viewType, - this.creationParams, - ); - - @override - final int viewId; - - /// The unique identifier for the HTML view type to be embedded by this widget. - /// - /// A PlatformViewFactory for this type must have been registered. - final String viewType; - - final dynamic creationParams; - - bool _initialized = false; - - Future _initialize() async { - final Map args = { - 'id': viewId, - 'viewType': viewType, - 'params': creationParams, - }; - await SystemChannels.platform_views.invokeMethod('create', args); - _initialized = true; - } - - @override - Future clearFocus() async { - // Currently this does nothing on Flutter Web. - // TODO(het): Implement this. See https://github.com/flutter/flutter/issues/39496 - } - - @override - Future dispatchPointerEvent(PointerEvent event) async { - // We do not dispatch pointer events to HTML views because they may contain - // cross-origin iframes, which only accept user-generated events. - } - - @override - Future dispose() async { - if (_initialized) { - await SystemChannels.platform_views.invokeMethod('dispose', viewId); - } - } + Widget build(BuildContext context) => buildImpl(context); } class _AndroidViewState extends State { diff --git a/packages/flutter/test/services/fake_platform_views.dart b/packages/flutter/test/services/fake_platform_views.dart index 7d85e93733f32..e3dfdd5adaa49 100644 --- a/packages/flutter/test/services/fake_platform_views.dart +++ b/packages/flutter/test/services/fake_platform_views.dart @@ -471,77 +471,6 @@ class FakeIosPlatformViewsController { } } -class FakeHtmlPlatformViewsController { - FakeHtmlPlatformViewsController() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall); - } - - Iterable get views => _views.values; - final Map _views = {}; - - final Set _registeredViewTypes = {}; - - late Completer resizeCompleter; - - Completer? createCompleter; - - void registerViewType(String viewType) { - _registeredViewTypes.add(viewType); - } - - Future _onMethodCall(MethodCall call) { - switch (call.method) { - case 'create': - return _create(call); - case 'dispose': - return _dispose(call); - } - return Future.sync(() => null); - } - - Future _create(MethodCall call) async { - final Map args = call.arguments as Map; - final int id = args['id'] as int; - final String viewType = args['viewType'] as String; - final Object? params = args['params']; - - if (_views.containsKey(id)) { - throw PlatformException( - code: 'error', - message: 'Trying to create an already created platform view, view id: $id', - ); - } - - if (!_registeredViewTypes.contains(viewType)) { - throw PlatformException( - code: 'error', - message: 'Trying to create a platform view of unregistered type: $viewType', - ); - } - - if (createCompleter != null) { - await createCompleter!.future; - } - - _views[id] = FakeHtmlPlatformView(id, viewType, params); - return Future.sync(() => null); - } - - Future _dispose(MethodCall call) { - final int id = call.arguments as int; - - if (!_views.containsKey(id)) { - throw PlatformException( - code: 'error', - message: 'Trying to dispose a platform view with unknown id: $id', - ); - } - - _views.remove(id); - return Future.sync(() => null); - } -} - @immutable class FakeAndroidPlatformView { const FakeAndroidPlatformView(this.id, this.type, this.size, this.layoutDirection, @@ -656,31 +585,3 @@ class FakeUiKitView { return 'FakeUiKitView(id: $id, type: $type, creationParams: $creationParams)'; } } - -@immutable -class FakeHtmlPlatformView { - const FakeHtmlPlatformView(this.id, this.type, [this.creationParams]); - - final int id; - final String type; - final Object? creationParams; - - @override - bool operator ==(Object other) { - if (other.runtimeType != runtimeType) { - return false; - } - return other is FakeHtmlPlatformView - && other.id == id - && other.type == type - && other.creationParams == creationParams; - } - - @override - int get hashCode => Object.hash(id, type, creationParams); - - @override - String toString() { - return 'FakeHtmlPlatformView(id: $id, type: $type, params: $creationParams)'; - } -} diff --git a/packages/flutter/test/widgets/html_element_view_test.dart b/packages/flutter/test/widgets/html_element_view_test.dart index b485aef6c9235..dd8866e9faafe 100644 --- a/packages/flutter/test/widgets/html_element_view_test.dart +++ b/packages/flutter/test/widgets/html_element_view_test.dart @@ -6,20 +6,45 @@ library; import 'dart:async'; +import 'dart:ui_web' as ui_web; +import 'package:collection/collection.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/src/widgets/_html_element_view_web.dart' + show debugOverridePlatformViewRegistry; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:web/web.dart' as web; -import '../services/fake_platform_views.dart'; +final Object _mockHtmlElement = Object(); +Object _mockViewFactory(int id, {Object? params}) { + return _mockHtmlElement; +} void main() { + late FakePlatformViewRegistry fakePlatformViewRegistry; + + setUp(() { + fakePlatformViewRegistry = FakePlatformViewRegistry(); + + // Simulate the engine registering default factores. + fakePlatformViewRegistry.registerViewFactory(ui_web.PlatformViewRegistry.defaultVisibleViewType, (int viewId, {Object? params}) { + params!; + params as Map; + return web.document.createElement(params['tagName']! as String); + }); + fakePlatformViewRegistry.registerViewFactory(ui_web.PlatformViewRegistry.defaultInvisibleViewType, (int viewId, {Object? params}) { + params!; + params as Map; + return web.document.createElement(params['tagName']! as String); + }); + }); + group('HtmlElementView', () { testWidgets('Create HTML view', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); await tester.pumpWidget( const Center( @@ -32,17 +57,16 @@ void main() { ); expect( - viewsController.views, - unorderedEquals([ - FakeHtmlPlatformView(currentViewId + 1, 'webview'), + fakePlatformViewRegistry.views, + unorderedEquals([ + (id: currentViewId + 1, viewType: 'webview', params: null, htmlElement: _mockHtmlElement), ]), ); }); testWidgets('Create HTML view with PlatformViewCreatedCallback', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); bool hasPlatformViewCreated = false; void onPlatformViewCreatedCallBack(int id) { @@ -66,17 +90,16 @@ void main() { expect(hasPlatformViewCreated, true); expect( - viewsController.views, - unorderedEquals([ - FakeHtmlPlatformView(currentViewId + 1, 'webview'), + fakePlatformViewRegistry.views, + unorderedEquals([ + (id: currentViewId + 1, viewType: 'webview', params: null, htmlElement: _mockHtmlElement), ]), ); }); testWidgets('Create HTML view with creation params', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); await tester.pumpWidget( const Column( children: [ @@ -101,18 +124,17 @@ void main() { ); expect( - viewsController.views, - unorderedEquals([ - FakeHtmlPlatformView(currentViewId + 1, 'webview', 'foobar'), - FakeHtmlPlatformView(currentViewId + 2, 'webview', 123), + fakePlatformViewRegistry.views, + unorderedEquals([ + (id: currentViewId + 1, viewType: 'webview', params: 'foobar', htmlElement: _mockHtmlElement), + (id: currentViewId + 2, viewType: 'webview', params: 123, htmlElement: _mockHtmlElement), ]), ); }); testWidgets('Resize HTML view', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); await tester.pumpWidget( const Center( child: SizedBox( @@ -123,7 +145,7 @@ void main() { ), ); - viewsController.resizeCompleter = Completer(); + final Completer resizeCompleter = Completer(); await tester.pumpWidget( const Center( @@ -135,22 +157,21 @@ void main() { ), ); - viewsController.resizeCompleter.complete(); + resizeCompleter.complete(); await tester.pump(); expect( - viewsController.views, - unorderedEquals([ - FakeHtmlPlatformView(currentViewId + 1, 'webview'), + fakePlatformViewRegistry.views, + unorderedEquals([ + (id: currentViewId + 1, viewType: 'webview', params: null, htmlElement: _mockHtmlElement), ]), ); }); testWidgets('Change HTML view type', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); - viewsController.registerViewType('maps'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); + fakePlatformViewRegistry.registerViewFactory('maps', _mockViewFactory); await tester.pumpWidget( const Center( child: SizedBox( @@ -172,16 +193,15 @@ void main() { ); expect( - viewsController.views, - unorderedEquals([ - FakeHtmlPlatformView(currentViewId + 2, 'maps'), + fakePlatformViewRegistry.views, + unorderedEquals([ + (id: currentViewId + 2, viewType: 'maps', params: null, htmlElement: _mockHtmlElement), ]), ); }); testWidgets('Dispose HTML view', (WidgetTester tester) async { - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); await tester.pumpWidget( const Center( child: SizedBox( @@ -202,15 +222,14 @@ void main() { ); expect( - viewsController.views, + fakePlatformViewRegistry.views, isEmpty, ); }); testWidgets('HTML view survives widget tree change', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); final GlobalKey key = GlobalKey(); await tester.pumpWidget( Center( @@ -233,9 +252,9 @@ void main() { ); expect( - viewsController.views, - unorderedEquals([ - FakeHtmlPlatformView(currentViewId + 1, 'webview'), + fakePlatformViewRegistry.views, + unorderedEquals([ + (id: currentViewId + 1, viewType: 'webview', params: null, htmlElement: _mockHtmlElement), ]), ); }); @@ -244,8 +263,7 @@ void main() { final SemanticsHandle handle = tester.ensureSemantics(); final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); expect(currentViewId, greaterThanOrEqualTo(0)); - final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); - viewsController.registerViewType('webview'); + fakePlatformViewRegistry.registerViewFactory('webview', _mockViewFactory); await tester.pumpWidget( Semantics( @@ -278,4 +296,206 @@ void main() { handle.dispose(); }); }); + + group('HtmlElementView.fromTagName', () { + setUp(() { + debugOverridePlatformViewRegistry = fakePlatformViewRegistry; + }); + + tearDown(() { + debugOverridePlatformViewRegistry = null; + }); + + testWidgets('Create platform view from tagName', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + + await tester.pumpWidget( + Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: HtmlElementView.fromTagName(tagName: 'div'), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(fakePlatformViewRegistry.views, hasLength(1)); + final FakePlatformView fakePlatformView = fakePlatformViewRegistry.views.single; + expect(fakePlatformView.id, currentViewId + 1); + expect(fakePlatformView.viewType, ui_web.PlatformViewRegistry.defaultVisibleViewType); + expect(fakePlatformView.params, {'tagName': 'div'}); + + // The HTML element should be a div. + final web.HTMLElement htmlElement = fakePlatformView.htmlElement as web.HTMLElement; + expect(htmlElement.tagName, equalsIgnoringCase('div')); + }); + + testWidgets('Create invisible platform view', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + + await tester.pumpWidget( + Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: HtmlElementView.fromTagName(tagName: 'script', isVisible: false), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(fakePlatformViewRegistry.views, hasLength(1)); + final FakePlatformView fakePlatformView = fakePlatformViewRegistry.views.single; + expect(fakePlatformView.id, currentViewId + 1); + // The view should be invisible. + expect(fakePlatformView.viewType, ui_web.PlatformViewRegistry.defaultInvisibleViewType); + expect(fakePlatformView.params, {'tagName': 'script'}); + + // The HTML element should be a script. + final web.HTMLElement htmlElement = fakePlatformView.htmlElement as web.HTMLElement; + expect(htmlElement.tagName, equalsIgnoringCase('script')); + }); + + testWidgets('onElementCreated', (WidgetTester tester) async { + final List createdElements = []; + void onElementCreated(Object element) { + createdElements.add(element); + } + + await tester.pumpWidget( + Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: HtmlElementView.fromTagName( + tagName: 'table', + onElementCreated: onElementCreated, + ), + ), + ), + ); + await tester.pumpAndSettle(); + + expect(fakePlatformViewRegistry.views, hasLength(1)); + final FakePlatformView fakePlatformView = fakePlatformViewRegistry.views.single; + + expect(createdElements, hasLength(1)); + final Object createdElement = createdElements.single; + + expect(createdElement, fakePlatformView.htmlElement); + }); + }); +} + +typedef FakeViewFactory = ({ + String viewType, + bool isVisible, + Function viewFactory, +}); + +typedef FakePlatformView = ({ + int id, + String viewType, + Object? params, + Object htmlElement, +}); + +class FakePlatformViewRegistry implements ui_web.PlatformViewRegistry { + FakePlatformViewRegistry() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall); + } + + Set get views => Set.unmodifiable(_views); + final Set _views = {}; + + final Set _registeredViewTypes = {}; + + @override + bool registerViewFactory(String viewType, Function viewFactory, {bool isVisible = true}) { + if (_findRegisteredViewFactory(viewType) != null) { + return false; + } + _registeredViewTypes.add(( + viewType: viewType, + isVisible: isVisible, + viewFactory: viewFactory, + )); + return true; + } + + @override + Object getViewById(int viewId) { + return _findViewById(viewId)!.htmlElement; + } + + FakeViewFactory? _findRegisteredViewFactory(String viewType) { + return _registeredViewTypes.singleWhereOrNull( + (FakeViewFactory registered) => registered.viewType == viewType, + ); + } + + FakePlatformView? _findViewById(int viewId) { + return _views.singleWhereOrNull( + (FakePlatformView view) => view.id == viewId, + ); + } + + Future _onMethodCall(MethodCall call) { + switch (call.method) { + case 'create': + return _create(call); + case 'dispose': + return _dispose(call); + } + return Future.sync(() => null); + } + + Future _create(MethodCall call) async { + final Map args = call.arguments as Map; + final int id = args['id'] as int; + final String viewType = args['viewType'] as String; + final Object? params = args['params']; + + if (_findViewById(id) != null) { + throw PlatformException( + code: 'error', + message: 'Trying to create an already created platform view, view id: $id', + ); + } + + final FakeViewFactory? registered = _findRegisteredViewFactory(viewType); + if (registered == null) { + throw PlatformException( + code: 'error', + message: 'Trying to create a platform view of unregistered type: $viewType', + ); + } + + final ui_web.ParameterizedPlatformViewFactory viewFactory = + registered.viewFactory as ui_web.ParameterizedPlatformViewFactory; + + _views.add(( + id: id, + viewType: viewType, + params: params, + htmlElement: viewFactory(id, params: params), + )); + return null; + } + + Future _dispose(MethodCall call) async { + final int id = call.arguments as int; + + final FakePlatformView? view = _findViewById(id); + if (view == null) { + throw PlatformException( + code: 'error', + message: 'Trying to dispose a platform view with unknown id: $id', + ); + } + + _views.remove(view); + return null; + } } diff --git a/packages/flutter/test/widgets/platform_view_test.dart b/packages/flutter/test/widgets/platform_view_test.dart index 7b4bc720370ec..d9164b59c350f 100644 --- a/packages/flutter/test/widgets/platform_view_test.dart +++ b/packages/flutter/test/widgets/platform_view_test.dart @@ -3189,7 +3189,7 @@ void main() { // This file runs on non-web platforms, so we expect `HtmlElementView` to // fail. final dynamic exception = tester.takeException(); - expect(exception, isAssertionError); + expect(exception, isUnimplementedError); expect(exception.toString(), contains('HtmlElementView is only available on Flutter Web')); }); } From b01cb301cfa2de0b2ac13296b79bdfe4c60c8678 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:59:48 -0700 Subject: [PATCH 0580/1547] Adds more documentations around ignoreSemantics deprecations. (#131287) migration guide update https://github.com/flutter/website/pull/9124 fixes the concerns in https://github.com/flutter/flutter/pull/120619 --- .../flutter/lib/src/rendering/proxy_box.dart | 26 +++++-- .../lib/src/rendering/proxy_sliver.dart | 13 +++- packages/flutter/lib/src/widgets/basic.dart | 69 +++++++++++++------ packages/flutter/lib/src/widgets/sliver.dart | 13 +++- 4 files changed, 88 insertions(+), 33 deletions(-) diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 5e6f2e740f580..25c32741b7b16 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -3547,7 +3547,14 @@ class RenderRepaintBoundary extends RenderProxyBox { /// as usual. It just cannot be the target of located events, because its render /// object returns false from [hitTest]. /// -/// {@macro flutter.widgets.IgnorePointer.Semantics} +/// ## Semantics +/// +/// Using this class may also affect how the semantics subtree underneath is +/// collected. +/// +/// {@macro flutter.widgets.IgnorePointer.semantics} +/// +/// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} /// /// See also: /// @@ -3574,7 +3581,7 @@ class RenderIgnorePointer extends RenderProxyBox { /// Regardless of whether this render object is ignored during hit testing, it /// will still consume space during layout and be visible during painting. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.semantics} bool get ignoring => _ignoring; bool _ignoring; set ignoring(bool value) { @@ -3589,7 +3596,7 @@ class RenderIgnorePointer extends RenderProxyBox { /// Whether the semantics of this render object is ignored when compiling the semantics tree. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} /// /// See [SemanticsNode] for additional information about the semantics tree. @Deprecated( @@ -3790,7 +3797,14 @@ class RenderOffstage extends RenderProxyBox { /// its children from being the target of located events, because its render /// object returns true from [hitTest]. /// -/// {@macro flutter.widgets.AbsorbPointer.Semantics} +/// ## Semantics +/// +/// Using this class may also affect how the semantics subtree underneath is +/// collected. +/// +/// {@macro flutter.widgets.AbsorbPointer.semantics} +/// +/// {@macro flutter.widgets.AbsorbPointer.ignoringSemantics} /// /// See also: /// @@ -3818,7 +3832,7 @@ class RenderAbsorbPointer extends RenderProxyBox { /// testing, it will still consume space during layout and be visible during /// painting. /// - /// {@macro flutter.widgets.AbsorbPointer.Semantics} + /// {@macro flutter.widgets.AbsorbPointer.semantics} bool get absorbing => _absorbing; bool _absorbing; set absorbing(bool value) { @@ -3834,7 +3848,7 @@ class RenderAbsorbPointer extends RenderProxyBox { /// Whether the semantics of this render object is ignored when compiling the /// semantics tree. /// - /// {@macro flutter.widgets.AbsorbPointer.Semantics} + /// {@macro flutter.widgets.AbsorbPointer.ignoringSemantics} /// /// See [SemanticsNode] for additional information about the semantics tree. @Deprecated( diff --git a/packages/flutter/lib/src/rendering/proxy_sliver.dart b/packages/flutter/lib/src/rendering/proxy_sliver.dart index bd7feec4cd4d3..2425cb8ebc7e0 100644 --- a/packages/flutter/lib/src/rendering/proxy_sliver.dart +++ b/packages/flutter/lib/src/rendering/proxy_sliver.dart @@ -205,7 +205,14 @@ class RenderSliverOpacity extends RenderProxySliver { /// child as usual. It just cannot be the target of located events, because its /// render object returns false from [hitTest]. /// -/// {@macro flutter.widgets.IgnorePointer.Semantics} +/// ## Semantics +/// +/// Using this class may also affect how the semantics subtree underneath is +/// collected. +/// +/// {@macro flutter.widgets.IgnorePointer.semantics} +/// +/// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} class RenderSliverIgnorePointer extends RenderProxySliver { /// Creates a render object that is invisible to hit testing. /// @@ -228,7 +235,7 @@ class RenderSliverIgnorePointer extends RenderProxySliver { /// Regardless of whether this render object is ignored during hit testing, it /// will still consume space during layout and be visible during painting. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.semantics} bool get ignoring => _ignoring; bool _ignoring; set ignoring(bool value) { @@ -244,7 +251,7 @@ class RenderSliverIgnorePointer extends RenderProxySliver { /// Whether the semantics of this render object is ignored when compiling the /// semantics tree. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} @Deprecated( 'Create a custom sliver ignore pointer widget instead. ' 'This feature was deprecated after v3.8.0-12.0.pre.' diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index bd69cf4ea251e..a8820921e7c1d 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -6839,20 +6839,33 @@ class RepaintBoundary extends SingleChildRenderObjectWidget { /// /// ## Semantics /// -/// Using this widget may also affect how the semantics subtree underneath this -/// widget is collected. +/// Using this class may also affect how the semantics subtree underneath is +/// collected. +/// +/// {@template flutter.widgets.IgnorePointer.semantics} +/// If [ignoring] is true, pointer-related [SemanticsAction]s are removed from +/// the semantics subtree. Otherwise, the subtree remains untouched. +/// {@endtemplate} +/// +/// {@template flutter.widgets.IgnorePointer.ignoringSemantics} +/// The usages of [ignoringSemantics] are deprecated and not recommended. This +/// property was introduced to workaround the semantics behavior of the +/// [IgnorePointer] and its friends before v3.8.0-12.0.pre. +/// +/// Before that version, entire semantics subtree is dropped if [ignoring] is +/// true. Developers can only use [ignoringSemantics] to preserver the semantics +/// subtrees. +/// +/// After that version, with [ignoring] set to true, it only prevents semantics +/// user actions in the semantics subtree but leaves the other +/// [SemanticsProperties] intact. Therefore, the [ignoringSemantics] is no +/// longer needed. /// -/// {@template flutter.widgets.IgnorePointer.Semantics} /// If [ignoringSemantics] is true, the semantics subtree is dropped. Therefore, /// the subtree will be invisible to assistive technologies. /// /// If [ignoringSemantics] is false, the semantics subtree is collected as /// usual. -/// -/// If [ignoringSemantics] is not set, then [ignoring] decides how the -/// semantics subtree is collected. If [ignoring] is true, pointer-related -/// [SemanticsAction]s are removed from the semantics subtree. Otherwise, the -/// subtree remains untouched. /// {@endtemplate} /// /// See also: @@ -6880,7 +6893,7 @@ class IgnorePointer extends SingleChildRenderObjectWidget { /// Regardless of whether this widget is ignored during hit testing, it will /// still consume space during layout and be visible during painting. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.semantics} /// /// Defaults to true. final bool ignoring; @@ -6888,7 +6901,7 @@ class IgnorePointer extends SingleChildRenderObjectWidget { /// Whether the semantics of this widget is ignored when compiling the /// semantics subtree. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} /// /// See [SemanticsNode] for additional information about the semantics tree. @Deprecated( @@ -6943,19 +6956,33 @@ class IgnorePointer extends SingleChildRenderObjectWidget { /// /// ## Semantics /// -/// Using this widget may also affect how the semantics subtree underneath this -/// widget is collected. +/// Using this class may also affect how the semantics subtree underneath is +/// collected. +/// +/// {@template flutter.widgets.AbsorbPointer.semantics} +/// If [absorbing] is true, pointer-related [SemanticsAction]s are removed from +/// the semantics subtree. Otherwise, the subtree remains untouched. +/// {@endtemplate} +/// +/// {@template flutter.widgets.AbsorbPointer.ignoringSemantics} +/// The usages of [ignoringSemantics] are deprecated and not recommended. This +/// property was introduced to workaround the semantics behavior of the +/// [IgnorePointer] and its friends before v3.8.0-12.0.pre. /// -/// {@template flutter.widgets.AbsorbPointer.Semantics} -/// If [ignoringSemantics] is true, the semantics subtree is dropped. +/// Before that version, entire semantics subtree is dropped if [absorbing] is +/// true. Developers can only use [ignoringSemantics] to preserver the semantics +/// subtrees. +/// +/// After that version, with [absorbing] set to true, it only prevents semantics +/// user actions in the semantics subtree but leaves the other +/// [SemanticsProperties] intact. Therefore, the [ignoringSemantics] is no +/// longer needed. +/// +/// If [ignoringSemantics] is true, the semantics subtree is dropped. Therefore, +/// the subtree will be invisible to assistive technologies. /// /// If [ignoringSemantics] is false, the semantics subtree is collected as /// usual. -/// -/// If [ignoringSemantics] is not set, then [absorbing] decides how the -/// semantics subtree is collected. If [absorbing] is true, pointer-related -/// [SemanticsAction]s are removed from the semantics subtree. Otherwise, the -/// subtree remains untouched. /// {@endtemplate} /// /// See also: @@ -6983,7 +7010,7 @@ class AbsorbPointer extends SingleChildRenderObjectWidget { /// testing, it will still consume space during layout and be visible during /// painting. /// - /// {@macro flutter.widgets.AbsorbPointer.Semantics} + /// {@macro flutter.widgets.AbsorbPointer.semantics} /// /// Defaults to true. final bool absorbing; @@ -6991,7 +7018,7 @@ class AbsorbPointer extends SingleChildRenderObjectWidget { /// Whether the semantics of this render object is ignored when compiling the /// semantics tree. /// - /// {@macro flutter.widgets.AbsorbPointer.Semantics} + /// {@macro flutter.widgets.AbsorbPointer.ignoringSemantics} /// /// See [SemanticsNode] for additional information about the semantics tree. @Deprecated( diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart index 0090198cb3893..f5240dd7b73d6 100644 --- a/packages/flutter/lib/src/widgets/sliver.dart +++ b/packages/flutter/lib/src/widgets/sliver.dart @@ -1178,7 +1178,14 @@ class SliverOpacity extends SingleChildRenderObjectWidget { /// child as usual. It just cannot be the target of located events, because it /// returns false from [RenderSliver.hitTest]. /// -/// {@macro flutter.widgets.IgnorePointer.Semantics} +/// ## Semantics +/// +/// Using this class may also affect how the semantics subtree underneath is +/// collected. +/// +/// {@macro flutter.widgets.IgnorePointer.semantics} +/// +/// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} /// /// See also: /// @@ -1203,13 +1210,13 @@ class SliverIgnorePointer extends SingleChildRenderObjectWidget { /// Regardless of whether this sliver is ignored during hit testing, it will /// still consume space during layout and be visible during painting. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.semantics} final bool ignoring; /// Whether the semantics of this sliver is ignored when compiling the /// semantics tree. /// - /// {@macro flutter.widgets.IgnorePointer.Semantics} + /// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} @Deprecated( 'Create a custom sliver ignore pointer widget instead. ' 'This feature was deprecated after v3.8.0-12.0.pre.' From 915c52453b7f28f5ff87b743c15c3a2575883d51 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 7 Aug 2023 17:28:16 -0700 Subject: [PATCH 0581/1547] [Impeller] add drawVertices and drawAtlas benchmarks. (#132080) Adds impeller benchmarks to track the progress of improvements made in https://github.com/flutter/flutter/issues/131345 --- .../macrobenchmarks/lib/common.dart | 2 + dev/benchmarks/macrobenchmarks/lib/main.dart | 20 ++- .../macrobenchmarks/lib/src/draw_atlas.dart | 116 ++++++++++++++++++ .../lib/src/draw_vertices.dart | 114 +++++++++++++++++ .../test_driver/draw_atlas_perf_test.dart | 16 +++ .../test_driver/draw_vertices_perf_test.dart | 16 +++ 6 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 dev/benchmarks/macrobenchmarks/lib/src/draw_atlas.dart create mode 100644 dev/benchmarks/macrobenchmarks/lib/src/draw_vertices.dart create mode 100644 dev/benchmarks/macrobenchmarks/test_driver/draw_atlas_perf_test.dart create mode 100644 dev/benchmarks/macrobenchmarks/test_driver/draw_vertices_perf_test.dart diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart index ad04770adb6a3..ee6407e01005c 100644 --- a/dev/benchmarks/macrobenchmarks/lib/common.dart +++ b/dev/benchmarks/macrobenchmarks/lib/common.dart @@ -37,6 +37,8 @@ const String kListTextLayoutRouteName = '/list_text_layout'; const String kAnimatedBlurBackdropFilter = '/animated_blur_backdrop_filter'; const String kSlidersRouteName = '/sliders'; const String kDrawPointsPageRougeName = '/draw_points'; +const String kDrawVerticesPageRouteName = '/draw_vertices'; +const String kDrawAtlasPageRouteName = '/draw_atlas'; const String kOpacityPeepholeOneRectRouteName = '$kOpacityPeepholeRouteName/one_big_rect'; const String kOpacityPeepholeColumnOfOpacityRouteName = '$kOpacityPeepholeRouteName/column_of_opacity'; diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart index 64e37e1224d70..a74b50732c729 100644 --- a/dev/benchmarks/macrobenchmarks/lib/main.dart +++ b/dev/benchmarks/macrobenchmarks/lib/main.dart @@ -18,7 +18,9 @@ import 'src/color_filter_cache.dart'; import 'src/color_filter_with_unstable_child.dart'; import 'src/cubic_bezier.dart'; import 'src/cull_opacity.dart'; +import 'src/draw_atlas.dart'; import 'src/draw_points.dart'; +import 'src/draw_vertices.dart'; import 'src/filtered_child_animation.dart'; import 'src/fullscreen_textfield.dart'; import 'src/gradient_perf.dart'; @@ -91,6 +93,8 @@ class MacrobenchmarksApp extends StatelessWidget { kAnimatedBlurBackdropFilter: (BuildContext context) => const AnimatedBlurBackdropFilter(), kSlidersRouteName: (BuildContext context) => const SlidersPage(), kDrawPointsPageRougeName: (BuildContext context) => const DrawPointsPage(), + kDrawVerticesPageRouteName: (BuildContext context) => const DrawVerticesPage(), + kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(), }, ); } @@ -345,7 +349,21 @@ class HomePage extends StatelessWidget { onPressed: () { Navigator.pushNamed(context, kDrawPointsPageRougeName); }, - ) + ), + ElevatedButton( + key: const Key(kDrawVerticesPageRouteName), + child: const Text('Draw Vertices'), + onPressed: () { + Navigator.pushNamed(context, kDrawVerticesPageRouteName); + }, + ), + ElevatedButton( + key: const Key(kDrawAtlasPageRouteName), + child: const Text('Draw Atlas'), + onPressed: () { + Navigator.pushNamed(context, kDrawAtlasPageRouteName); + }, + ), ], ), ); diff --git a/dev/benchmarks/macrobenchmarks/lib/src/draw_atlas.dart b/dev/benchmarks/macrobenchmarks/lib/src/draw_atlas.dart new file mode 100644 index 0000000000000..742301fb36753 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/draw_atlas.dart @@ -0,0 +1,116 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +Future loadImage(String asset) async { + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset); + final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + return frameInfo.image; +} + +class DrawAtlasPage extends StatefulWidget { + const DrawAtlasPage({super.key}); + + @override + State createState() => _DrawAtlasPageState(); +} + +class _DrawAtlasPageState extends State with SingleTickerProviderStateMixin { + late final AnimationController controller; + double tick = 0.0; + ui.Image? image; + + @override + void initState() { + super.initState(); + loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((ui.Image pending) { + setState(() { + image = pending; + }); + }); + controller = AnimationController(vsync: this, duration: const Duration(hours: 1)); + controller.addListener(() { + setState(() { + tick += 1; + }); + }); + controller.forward(from: 0); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + if (image == null) { + return const Placeholder(); + } + return CustomPaint( + size: const Size(500, 500), + painter: VerticesPainter(tick, image!), + child: Container(), + ); + } +} + +class VerticesPainter extends CustomPainter { + VerticesPainter(this.tick, this.image); + + final double tick; + final ui.Image image; + + @override + void paint(Canvas canvas, Size size) { + canvas.translate(0, tick); + canvas.drawAtlas( + image, + [RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 0, translateY: 0)], + [Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], + [Colors.red], + BlendMode.plus, + null, + Paint() + ); + canvas.drawAtlas( + image, + [RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 250, translateY: 0)], + [Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], + [Colors.green], + BlendMode.plus, + null, + Paint() + ); + canvas.drawAtlas( + image, + [RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 0, translateY: 250)], + [Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], + [Colors.blue], + BlendMode.plus, + null, + Paint() + ); + canvas.drawAtlas( + image, + [RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 250, translateY: 250)], + [Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())], + [Colors.yellow], + BlendMode.plus, + null, + Paint() + ); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/dev/benchmarks/macrobenchmarks/lib/src/draw_vertices.dart b/dev/benchmarks/macrobenchmarks/lib/src/draw_vertices.dart new file mode 100644 index 0000000000000..669919d4bcde0 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/draw_vertices.dart @@ -0,0 +1,114 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +Future loadImage(String asset) async { + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset); + final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); + final ui.FrameInfo frameInfo = await codec.getNextFrame(); + return frameInfo.image; +} + +class DrawVerticesPage extends StatefulWidget { + const DrawVerticesPage({super.key}); + + @override + State createState() => _DrawVerticesPageState(); +} + +class _DrawVerticesPageState extends State with SingleTickerProviderStateMixin { + late final AnimationController controller; + double tick = 0.0; + ui.Image? image; + + @override + void initState() { + super.initState(); + loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((ui.Image pending) { + setState(() { + image = pending; + }); + }); + controller = AnimationController(vsync: this, duration: const Duration(hours: 1)); + controller.addListener(() { + setState(() { + tick += 1; + }); + }); + controller.forward(from: 0); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + + @override + Widget build(BuildContext context) { + if (image == null) { + return const Placeholder(); + } + return CustomPaint( + size: const Size(500, 500), + painter: VerticesPainter(tick, image!), + child: Container(), + ); + } +} + +class VerticesPainter extends CustomPainter { + VerticesPainter(this.tick, this.image); + + final double tick; + final ui.Image image; + + @override + void paint(Canvas canvas, Size size) { + canvas.translate(0, tick); + final ui.Vertices vertices = ui.Vertices( + VertexMode.triangles, + const [ + Offset.zero, + Offset(0, 250), + Offset(250, 0), + Offset(0, 250), + Offset(250, 0), + Offset(250, 250) + ], + textureCoordinates: [ + Offset.zero, + Offset(0, image.height.toDouble()), + Offset(image.width.toDouble(), 0), + Offset(0, image.height.toDouble()), + Offset(image.width.toDouble(), 0), + Offset(image.width.toDouble(), image.height.toDouble()) + ], + colors: [ + Colors.red, + Colors.blue, + Colors.green, + Colors.red, + Colors.blue, + Colors.green, + ] + ); + canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); + canvas.translate(250, 0); + canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); + canvas.translate(0, 250); + canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); + canvas.translate(-250, 0); + canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage)); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/draw_atlas_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/draw_atlas_perf_test.dart new file mode 100644 index 0000000000000..a25028c1516a7 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test_driver/draw_atlas_perf_test.dart @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTest( + 'draw_atlas_perf', + kDrawAtlasPageRouteName, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 10), + ); +} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/draw_vertices_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/draw_vertices_perf_test.dart new file mode 100644 index 0000000000000..e0c578656175e --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test_driver/draw_vertices_perf_test.dart @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTest( + 'draw_vertices_perf', + kDrawVerticesPageRouteName, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 10), + ); +} From cef00d0c53e3860857df34d81f6d6aa854567d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20S=20Guerrero?= Date: Mon, 7 Aug 2023 17:30:07 -0700 Subject: [PATCH 0582/1547] Revert "Replace TextField.canRequestFocus with TextField.focusNode.canRequestFocus" (#132104) Reverts flutter/flutter#130164 reverting because it cause internal google testing failures b/294917394 --- .../lib/src/material/dropdown_menu.dart | 23 ++----------------- .../flutter/lib/src/material/text_field.dart | 20 ++++------------ .../test/material/dropdown_menu_test.dart | 7 +++--- .../test/material/text_field_test.dart | 5 +--- 4 files changed, 11 insertions(+), 44 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 53003486f6b1c..51a972a3398a6 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -4,7 +4,6 @@ import 'dart:math' as math; -import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -310,7 +309,6 @@ class _DropdownMenuState extends State> { int? currentHighlight; double? leadingPadding; bool _menuHasEnabledItem = false; - late final FocusNode _focusNode; @override void initState() { @@ -328,18 +326,6 @@ class _DropdownMenuState extends State> { TextSelection.collapsed(offset: _textEditingController.text.length); } refreshLeadingPadding(); - _focusNode = FocusNode( - canRequestFocus: canRequestFocus(), - ); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final bool widgetCanRequestFocus = canRequestFocus(); - if (widgetCanRequestFocus != _focusNode.canRequestFocus) { - _focusNode.canRequestFocus = widgetCanRequestFocus; - } } @override @@ -367,10 +353,6 @@ class _DropdownMenuState extends State> { TextSelection.collapsed(offset: _textEditingController.text.length); } } - final bool widgetCanRequestFocus = canRequestFocus(); - if (widgetCanRequestFocus != _focusNode.canRequestFocus) { - _focusNode.canRequestFocus = widgetCanRequestFocus; - } } bool canRequestFocus() { @@ -378,7 +360,7 @@ class _DropdownMenuState extends State> { return widget.requestFocusOnTap!; } - switch (defaultTargetPlatform) { + switch (Theme.of(context).platform) { case TargetPlatform.iOS: case TargetPlatform.android: case TargetPlatform.fuchsia: @@ -610,8 +592,7 @@ class _DropdownMenuState extends State> { final Widget textField = TextField( key: _anchorKey, mouseCursor: effectiveMouseCursor, - focusNode: _focusNode, - readOnly: !canRequestFocus(), + canRequestFocus: canRequestFocus(), enableInteractiveSelection: canRequestFocus(), textAlignVertical: TextAlignVertical.center, style: effectiveTextStyle, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 7d6ea5b865ac4..aa8f715bf905b 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -314,10 +314,6 @@ class TextField extends StatefulWidget { this.scribbleEnabled = true, this.enableIMEPersonalizedLearning = true, this.contextMenuBuilder = _defaultContextMenuBuilder, - @Deprecated( - 'Use `focusNode` instead. ' - 'This feature was deprecated after v3.12.0-14.0.pre.', - ) this.canRequestFocus = true, this.spellCheckConfiguration, this.magnifierConfiguration, @@ -780,10 +776,6 @@ class TextField extends StatefulWidget { /// Defaults to true. If false, the text field will not request focus /// when tapped, or when its context menu is displayed. If false it will not /// be possible to move the focus to the text field with tab key. - @Deprecated( - 'Use `focusNode` instead. ' - 'This feature was deprecated after v3.12.0-14.0.pre.', - ) final bool canRequestFocus; /// {@macro flutter.widgets.undoHistory.controller} @@ -1034,9 +1026,7 @@ class _TextFieldState extends State with RestorationMixin implements if (widget.controller == null) { _createLocalController(); } - _effectiveFocusNode.canRequestFocus = widget.focusNode == null - ? widget.canRequestFocus && _isEnabled - : widget.focusNode!.canRequestFocus && _isEnabled; + _effectiveFocusNode.canRequestFocus = widget.canRequestFocus && _isEnabled; _effectiveFocusNode.addListener(_handleFocusChanged); } @@ -1044,9 +1034,7 @@ class _TextFieldState extends State with RestorationMixin implements final NavigationMode mode = MediaQuery.maybeNavigationModeOf(context) ?? NavigationMode.traditional; switch (mode) { case NavigationMode.traditional: - return widget.focusNode == null - ? widget.canRequestFocus && _isEnabled - : widget.focusNode!.canRequestFocus && _isEnabled; + return widget.canRequestFocus && _isEnabled; case NavigationMode.directional: return true; } @@ -1098,8 +1086,8 @@ class _TextFieldState extends State with RestorationMixin implements void _createLocalController([TextEditingValue? value]) { assert(_controller == null); _controller = value == null - ? RestorableTextEditingController() - : RestorableTextEditingController.fromValue(value); + ? RestorableTextEditingController() + : RestorableTextEditingController.fromValue(value); if (!restorePending) { _registerController(); } diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 898c835f9272a..a721cfdb87a2b 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -1232,7 +1232,7 @@ void main() { final Finder textFieldFinder = find.byType(TextField); final TextField result = tester.widget(textFieldFinder); - expect(result.focusNode!.canRequestFocus, false); + expect(result.canRequestFocus, false); }, variant: TargetPlatformVariant.mobile()); testWidgets('The text input field should be focused on desktop platforms ' @@ -1300,7 +1300,7 @@ void main() { final Finder textFieldFinder1 = find.byType(TextField); final TextField textField1 = tester.widget(textFieldFinder1); - expect(textField1.focusNode!.canRequestFocus, false); + expect(textField1.canRequestFocus, false); // Open the dropdown menu. await tester.tap(textFieldFinder1); await tester.pump(); @@ -1329,7 +1329,7 @@ void main() { final Finder textFieldFinder = find.byType(TextField); final TextField textField = tester.widget(textFieldFinder); - expect(textField.focusNode!.canRequestFocus, false); + expect(textField.canRequestFocus, false); final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); await gesture.moveTo(tester.getCenter(textFieldFinder)); @@ -1526,6 +1526,7 @@ void main() { // Item 5 should show up. expect(find.text('Item 5').hitTestable(), findsOneWidget); }); + } enum TestMenu { diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 8339d81cd9023..3998f97500323 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -15568,7 +15568,6 @@ void main() { expect(focusNode.hasFocus, isTrue); // Set canRequestFocus to false: the text field cannot be focused when it is tapped/long pressed. - focusNode.canRequestFocus = false; await tester.pumpWidget( boilerplate( child: TextField( @@ -15750,9 +15749,7 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets('Right clicking cannot request focus if canRequestFocus is false', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode( - canRequestFocus: false, - ); + final FocusNode focusNode = FocusNode(); final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( From 73e1f9f5242e95107e9677396a21c6ed00bd71bb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 21:14:51 -0400 Subject: [PATCH 0583/1547] Roll Flutter Engine from be085f6699b6 to c27109291e22 (3 revisions) (#132086) https://github.com/flutter/engine/compare/be085f6699b6...c27109291e22 2023-08-07 yjbanov@google.com [web] remove leftover comments from semantics tester (flutter/engine#44350) 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 77007f51bf81 to 9fbd7296de9a (4 revisions) (flutter/engine#44443) 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from f19578685d17 to 77007f51bf81 (1 revision) (flutter/engine#44440) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 867f9e7f6502f..91821956df2fb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -be085f6699b668e90891b6b3fafc2f06749a72d8 +c27109291e2226ac48a11fdfa05b846554befb27 From 08b2c44413dae8e4e7936afcbd12ec2164afea32 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 7 Aug 2023 22:59:25 -0400 Subject: [PATCH 0584/1547] Roll Flutter Engine from c27109291e22 to 9c83d90b01bd (5 revisions) (#132108) https://github.com/flutter/engine/compare/c27109291e22...9c83d90b01bd 2023-08-07 skia-flutter-autoroll@skia.org Roll Dart SDK from 0816d590a220 to f664f4b9c50d (1 revision) (flutter/engine#44462) 2023-08-07 bdero@google.com [Impeller] Flutter GPU: Add GpuContext. (flutter/engine#44359) 2023-08-07 ftsui@google.com Fix use-after-free crash in glfw embedder (flutter/engine#44358) 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 9fbd7296de9a to d1ada6624536 (1 revision) (flutter/engine#44447) 2023-08-07 zanderso@users.noreply.github.com Revert clang back to 6d667d4b261e81f325756fdfd5bb43b3b3d2451d (flutter/engine#44442) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 91821956df2fb..5c65749a4d37e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c27109291e2226ac48a11fdfa05b846554befb27 +9c83d90b01bdde5362d28da5d13ae63fbdcb2cc1 From 436df69a4684aaf7d0d1b09b61bb29c75b32ad61 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 01:58:16 -0400 Subject: [PATCH 0585/1547] Roll Flutter Engine from 9c83d90b01bd to 146c4c9487fc (6 revisions) (#132112) https://github.com/flutter/engine/compare/9c83d90b01bd...146c4c9487fc 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from b4a893827b2a to f7162d33afb2 (1 revision) (flutter/engine#44479) 2023-08-07 jason-simmons@users.noreply.github.com Revert "[Impeller] DlCanvas implementation wrapping Aiks canvas" (flutter/engine#44466) 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from 5dd88a48f7e2 to b4a893827b2a (3 revisions) (flutter/engine#44470) 2023-08-07 mdebbar@google.com [web] Silence `pub get` when it's successful (flutter/engine#44445) 2023-08-07 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from mlT1Bm0L9bVynvMFF... to r0vBgWqKSvQ6zzFam... (flutter/engine#44463) 2023-08-07 skia-flutter-autoroll@skia.org Roll Skia from d1ada6624536 to 5dd88a48f7e2 (8 revisions) (flutter/engine#44465) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from mlT1Bm0L9bVy to r0vBgWqKSvQ6 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5c65749a4d37e..b8de52efaaf27 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9c83d90b01bdde5362d28da5d13ae63fbdcb2cc1 +146c4c9487fc68ff97dbf900bf3c760c60ed251a diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index e0ff642b4a706..1afeb0edd76e8 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -mlT1Bm0L9bVynvMFF3lpUMOuUpsv0P8aWBdkIb3UmWYC +r0vBgWqKSvQ6zzFamHmmAbL3yPAgG5OsLM-AlH87TUUC From acd636f7baab45d9a45fad72140e57f68646ee90 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 8 Aug 2023 09:39:19 -0700 Subject: [PATCH 0586/1547] Handle breaking changes in leak_tracker. (#131998) --- dev/automated_tests/pubspec.yaml | 7 +- dev/benchmarks/complex_layout/pubspec.yaml | 7 +- dev/benchmarks/macrobenchmarks/pubspec.yaml | 7 +- dev/benchmarks/microbenchmarks/pubspec.yaml | 7 +- .../platform_channels_benchmarks/pubspec.yaml | 7 +- .../platform_views_layout/pubspec.yaml | 7 +- .../pubspec.yaml | 7 +- dev/benchmarks/test_apps/stocks/pubspec.yaml | 7 +- dev/bots/pubspec.yaml | 7 +- dev/conductor/core/pubspec.yaml | 7 +- dev/customer_testing/pubspec.yaml | 7 +- dev/devicelab/pubspec.yaml | 7 +- .../android_semantics_testing/pubspec.yaml | 7 +- .../android_views/pubspec.yaml | 7 +- .../deferred_components_test/pubspec.yaml | 7 +- .../external_ui/pubspec.yaml | 7 +- dev/integration_tests/flavors/pubspec.yaml | 7 +- .../flutter_gallery/pubspec.yaml | 7 +- .../gradle_deprecated_settings/pubspec.yaml | 4 +- .../hybrid_android_views/pubspec.yaml | 7 +- .../ios_platform_view_tests/pubspec.yaml | 7 +- .../platform_interaction/pubspec.yaml | 7 +- dev/integration_tests/ui/pubspec.yaml | 7 +- .../web_e2e_tests/pubspec.yaml | 7 +- .../windows_startup_test/pubspec.yaml | 7 +- dev/tools/gen_defaults/pubspec.yaml | 7 +- dev/tools/gen_keycodes/pubspec.yaml | 7 +- dev/tools/pubspec.yaml | 7 +- examples/api/pubspec.yaml | 7 +- examples/hello_world/pubspec.yaml | 7 +- examples/platform_channel/pubspec.yaml | 7 +- examples/platform_channel_swift/pubspec.yaml | 7 +- examples/texture/pubspec.yaml | 7 +- packages/flutter/pubspec.yaml | 11 +- .../test/animation/animation_sheet_test.dart | 5 +- .../test/animation/live_binding_test.dart | 2 +- .../flutter/test/flutter_test_config.dart | 2 +- .../test/foundation/leak_tracking.dart | 311 ++++++++++-------- .../test/foundation/leak_tracking_test.dart | 235 ------------- .../foundation/leak_tracking_test/README.md | 4 + .../leak_tracking_config_test/constants.dart | 8 + .../flutter_test_config.dart | 132 ++++++++ .../leak_tracking_config_test.dart | 57 ++++ .../leak_tracking_test/leaking_widget.dart | 49 +++ .../leak_tracking_test/no_config_test.dart | 51 +++ .../leak_tracking_test/no_tracking_test.dart | 21 ++ .../gestures/transformed_monodrag_test.dart | 2 +- .../test/gestures/transformed_scale_test.dart | 4 +- .../flutter/test/material/about_test.dart | 14 +- .../adaptive_text_selection_toolbar_test.dart | 6 +- .../material/bottom_sheet_theme_test.dart | 4 +- .../test/material/button_bar_test.dart | 4 +- .../material/checkbox_list_tile_test.dart | 2 + .../test/material/checkbox_theme_test.dart | 2 +- packages/flutter/test/material/chip_test.dart | 18 +- .../test/material/chip_theme_test.dart | 2 + .../test/material/date_range_picker_test.dart | 1 + .../flutter/test/material/dialog_test.dart | 11 +- .../test/material/drawer_button_test.dart | 4 +- .../material/dropdown_form_field_test.dart | 48 ++- .../material/dropdown_menu_theme_test.dart | 8 +- .../test/material/elevated_button_test.dart | 26 +- .../test/material/filled_button_test.dart | 17 +- ...flexible_space_bar_collapse_mode_test.dart | 4 +- .../flexible_space_bar_stretch_mode_test.dart | 4 +- .../floating_action_button_location_test.dart | 6 +- .../material/floating_action_button_test.dart | 14 +- .../test/material/icon_button_test.dart | 24 +- .../flutter/test/material/ink_paint_test.dart | 4 +- .../flutter/test/material/ink_well_test.dart | 20 +- .../test/material/input_chip_test.dart | 5 + .../input_date_picker_form_field_test.dart | 27 +- .../flutter/test/material/list_tile_test.dart | 4 + .../test/material/list_tile_theme_test.dart | 2 +- .../flutter/test/material/magnifier_test.dart | 24 +- .../test/material/material_button_test.dart | 6 + .../test/material/menu_bar_theme_test.dart | 6 +- .../test/material/menu_style_test.dart | 11 +- .../test/material/menu_theme_test.dart | 5 +- .../material/mergeable_material_test.dart | 8 +- .../test/material/navigation_drawer_test.dart | 20 +- .../test/material/outlined_button_test.dart | 30 +- .../test/material/page_selector_test.dart | 2 +- .../persistent_bottom_sheet_test.dart | 10 +- .../flutter/test/material/radio_test.dart | 16 + .../test/material/range_slider_test.dart | 90 +++-- .../material/raw_material_button_test.dart | 6 + .../test/material/scrollbar_paint_test.dart | 4 +- .../test/material/search_bar_theme_test.dart | 12 +- .../test/material/search_view_theme_test.dart | 12 +- .../test/material/segmented_button_test.dart | 13 +- .../material/segmented_button_theme_test.dart | 8 +- .../test/material/selection_area_test.dart | 11 +- .../test/material/slider_theme_test.dart | 78 +++-- .../test/material/switch_list_tile_test.dart | 4 +- .../flutter/test/material/switch_test.dart | 26 ++ .../test/material/text_button_test.dart | 26 +- .../material/text_field_helper_text_test.dart | 4 +- .../test/material/text_field_splash_test.dart | 4 +- .../test/material/text_form_field_test.dart | 80 ++--- .../material/text_selection_theme_test.dart | 6 +- .../material/text_selection_toolbar_test.dart | 2 +- packages/flutter/test/material/time_test.dart | 6 +- .../test/material/toggle_buttons_test.dart | 10 + .../material/toggle_buttons_theme_test.dart | 2 + .../flutter/test/material/tooltip_test.dart | 26 +- .../test/material/tooltip_theme_test.dart | 24 +- .../value_indicating_slider_test.dart | 17 +- packages/flutter_driver/pubspec.yaml | 7 +- packages/flutter_tools/pubspec.yaml | 7 +- .../pubspec.yaml | 7 +- .../integration_test/example/pubspec.yaml | 7 +- 112 files changed, 1141 insertions(+), 899 deletions(-) delete mode 100644 packages/flutter/test/foundation/leak_tracking_test.dart create mode 100644 packages/flutter/test/foundation/leak_tracking_test/README.md create mode 100644 packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart create mode 100644 packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart create mode 100644 packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart create mode 100644 packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart create mode 100644 packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart create mode 100644 packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 3af15f456dfb0..a4a4790e1b537 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: platform: 3.1.0 test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,7 +26,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 90e3 +# PUBSPEC CHECKSUM: ab27 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 0add398c2f9d8..a7c9649e45e26 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -44,14 +44,13 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 3c00 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 60e156a59bc06..4550c210916e7 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -47,13 +47,12 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -211,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 3c00 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 02c8cee8cb2ee..4f51250aebe2d 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: test: 1.24.5 flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,7 +26,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -138,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 8334 +# PUBSPEC CHECKSUM: 9677 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index bbc27ebff51c2..ac4a14597871d 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../microbenchmarks cupertino_icons: 1.0.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,7 +27,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_gallery_assets: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 071f +# PUBSPEC CHECKSUM: 4862 diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index cd3b965385088..00014aadce0e0 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -42,14 +42,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 3c00 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index c9519591cc9e2..2a7103b641c22 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -42,14 +42,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 3c00 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 49f2cdc6d5a59..4acbad26a7fb2 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -34,14 +34,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d5de +# PUBSPEC CHECKSUM: 7c22 diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index aa7f54ee036a6..2ffa5fb3676b3 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -19,8 +19,8 @@ dependencies: test: 1.24.5 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -29,7 +29,6 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +74,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 5232 +# PUBSPEC CHECKSUM: 3f75 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 0d9f0d93585ef..40a5184c9e971 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -33,12 +33,11 @@ dev_dependencies: test: 1.24.5 test_api: 0.6.1 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +65,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 98bf +# PUBSPEC CHECKSUM: ab03 diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 8165b2ecf7351..9617948993566 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -20,13 +20,12 @@ dependencies: dev_dependencies: test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +55,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3e0d +# PUBSPEC CHECKSUM: 4e50 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 4a0f12ca8a78e..ad62dd955cd1b 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -51,11 +51,10 @@ dependencies: dev_dependencies: test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 069f +# PUBSPEC CHECKSUM: 42e2 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 4bb0c77fd3db9..0c9e67ed3a2d6 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: pub_semver: 2.1.4 test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,7 +24,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a7dc +# PUBSPEC CHECKSUM: 8520 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 7d269f49cd637..62c592cf7485e 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -56,14 +56,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7544 +# PUBSPEC CHECKSUM: de87 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 815f51e13395d..aa734541e64ba 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -37,14 +37,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index a98b678a049dd..902a7465f4e36 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,7 +21,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 8fa8 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index b58bd6965a1df..a3cde6756075c 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,7 +23,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index beadeb0f2bd9a..12474cabd99b5 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -62,15 +62,14 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 2d08 +# PUBSPEC CHECKSUM: e14b diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index bc2faa5edf60e..52967e25af7e9 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: camera_android: 0.10.8+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_web: 0.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_web: 0.3.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.3+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: f4a6 +# PUBSPEC CHECKSUM: b503 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index fdcce7bc03c39..3a50abe04baa7 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -54,14 +54,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7544 +# PUBSPEC CHECKSUM: de87 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index ca8b8b2c4529c..0cb3b4a8e3242 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -37,14 +37,13 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 1ca2802ac64f4..5008671db678a 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,7 +21,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 8fa8 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index e01cef777b9f3..f08d5df9e5086 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,7 +23,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 50782ae127044..dacee6e168353 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -51,13 +51,12 @@ dev_dependencies: http: 0.13.6 test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +84,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 9207 +# PUBSPEC CHECKSUM: 0a4a diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 5ad79e827bd63..6064142e29d2b 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,7 +21,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +62,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 8fa8 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 4fd3370b262d9..e50faf86f4131 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -12,15 +12,14 @@ dev_dependencies: path: 1.8.3 test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +55,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3e0d +# PUBSPEC CHECKSUM: 4e50 diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 1c543406e9959..3bb78151a7f13 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -23,13 +23,12 @@ dev_dependencies: test: 1.24.5 test_api: 0.6.1 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,4 +57,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2004 +# PUBSPEC CHECKSUM: 6047 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 71bb08f68b1e4..98cb94a0e8411 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -29,12 +29,11 @@ dev_dependencies: test: 1.24.5 test_api: 0.6.1 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,4 +61,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b61e +# PUBSPEC CHECKSUM: 1361 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 94019eda081f4..3fc0c60e30849 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -33,8 +33,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,7 +42,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a4d0 +# PUBSPEC CHECKSUM: b614 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 658b6ebb2f29e..6ffd23fd91f38 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,4 +68,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 771b425a71c3c..8aecce16ef679 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index b0174fe733b92..c5b0a96f59920 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: db65 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 0c7254667ccf2..00dc34f9775eb 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -19,8 +19,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,7 +28,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +64,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a7dc +# PUBSPEC CHECKSUM: 8520 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 4397753e04a96..ee23653fb2b17 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,11 +22,11 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 8.0.3 - leak_tracker_testing: 1.0.2 + leak_tracker: 9.0.3 + leak_tracker_testing: 1.0.3 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,7 +34,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 10f4 +# PUBSPEC CHECKSUM: 8b3a diff --git a/packages/flutter/test/animation/animation_sheet_test.dart b/packages/flutter/test/animation/animation_sheet_test.dart index 4c26669abec4f..0d60746c45dfb 100644 --- a/packages/flutter/test/animation/animation_sheet_test.dart +++ b/packages/flutter/test/animation/animation_sheet_test.dart @@ -12,7 +12,6 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; void main() { /* @@ -20,7 +19,7 @@ void main() { * because [matchesGoldenFile] does not use Skia Gold in its native package. */ - testWidgetsWithLeakTracking('correctly records frames using collate', (WidgetTester tester) async { + testWidgets('correctly records frames using collate', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); await tester.pumpFrames( @@ -57,7 +56,7 @@ void main() { image.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgetsWithLeakTracking('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { + testWidgets('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder( frameSize: const Size(8, 2), allLayers: true, diff --git a/packages/flutter/test/animation/live_binding_test.dart b/packages/flutter/test/animation/live_binding_test.dart index 4928e6a6762f0..9a75509e3b423 100644 --- a/packages/flutter/test/animation/live_binding_test.dart +++ b/packages/flutter/test/animation/live_binding_test.dart @@ -80,7 +80,7 @@ void main() { // Currently skipped due to daily flake: https://github.com/flutter/flutter/issues/87588 }, skip: true); // Typically skip: isBrowser https://github.com/flutter/flutter/issues/42767 - testWidgetsWithLeakTracking('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { + testWidgets('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(200, 200), allLayers: true); final List taps = []; Widget target({bool recording = true}) => Container( diff --git a/packages/flutter/test/flutter_test_config.dart b/packages/flutter/test/flutter_test_config.dart index e8d488aff5fe2..731ca40f00489 100644 --- a/packages/flutter/test/flutter_test_config.dart +++ b/packages/flutter/test/flutter_test_config.dart @@ -23,7 +23,7 @@ Future testExecutable(FutureOr Function() testMain) { // receive the event. WidgetController.hitTestWarningShouldBeFatal = true; - LeakTrackerGlobalSettings.warnForNonSupportedPlatforms = false; + LeakTracking.warnForUnsupportedPlatforms = false; // Enable golden file testing using Skia Gold. return flutter_goldens.testExecutable(testMain); diff --git a/packages/flutter/test/foundation/leak_tracking.dart b/packages/flutter/test/foundation/leak_tracking.dart index 1ed364c9fa469..b56fca80bb399 100644 --- a/packages/flutter/test/foundation/leak_tracking.dart +++ b/packages/flutter/test/foundation/leak_tracking.dart @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// TODO(polina-c): start referencing this code in leak_tracker_flutter +// https://github.com/dart-lang/leak_tracker/issues/52 + import 'dart:core'; import 'package:flutter/foundation.dart'; @@ -10,41 +13,84 @@ import 'package:leak_tracker/leak_tracker.dart'; import 'package:leak_tracker_testing/leak_tracker_testing.dart'; import 'package:meta/meta.dart'; -export 'package:leak_tracker/leak_tracker.dart' show LeakDiagnosticConfig, LeakTrackingTestConfig; +export 'package:leak_tracker/leak_tracker.dart' show LeakDiagnosticConfig; -/// Set of objects, that does not hold the objects from garbage collection. -/// -/// The objects are referenced by hash codes and can duplicate with low probability. -@visibleForTesting -class WeakSet { - final Set _objectCodes = {}; - String _toCode(int hashCode, String type) => '$type-$hashCode'; +void _flutterEventToLeakTracker(ObjectEvent event) { + return LeakTracking.dispatchObjectEvent(event.toMap()); +} - void add(Object object) { - _objectCodes.add(_toCode(identityHashCode(object), object.runtimeType.toString())); +void _setUpTestingWithLeakTracking() { + _printPlatformWarningIfNeeded(); + if (!_isPlatformSupported) { + return; } - void addByCode(int hashCode, String type) { - _objectCodes.add(_toCode(hashCode, type)); + LeakTracking.phase = const PhaseSettings.paused(); + LeakTracking.start(config: LeakTrackingConfig.passive()); + + MemoryAllocations.instance.addListener(_flutterEventToLeakTracker); +} + +bool _stopConfiguringTearDown = false; + +/// Sets [tearDownAll] to tear down leak tracking if it is started. +/// +/// [configureOnce] is true tear down will be created just once, +/// not for every test. +/// Multiple [tearDownAll] is needed to handle test groups that have +/// own [tearDownAll]. +void configureLeakTrackingTearDown({ + LeaksCallback? onLeaks, + bool configureOnce = false, +}) { + if (_isPlatformSupported && !_stopConfiguringTearDown) { + tearDownAll(() async { + if (LeakTracking.isStarted) { + await _tearDownTestingWithLeakTracking(onLeaks); + } + }); + } + if (configureOnce) { + _stopConfiguringTearDown = true; } +} - bool contains(int hashCode, String type) { - final bool result = _objectCodes.contains(_toCode(hashCode, type)); - return result; +Future _tearDownTestingWithLeakTracking(LeaksCallback? onLeaks) async { + if (!LeakTracking.isStarted) { + return; + } + if (!_isPlatformSupported) { + return; + } + + MemoryAllocations.instance.removeListener(_flutterEventToLeakTracker); + await forceGC(fullGcCycles: 3); + final Leaks leaks = await LeakTracking.collectLeaks(); + + LeakTracking.stop(); + + if (leaks.total == 0) { + return; + } + if (onLeaks == null) { + expect(leaks, isLeakFree); + } else { + onLeaks(leaks); } } /// Wrapper for [testWidgets] with memory leak tracking. /// -/// The method will fail if instrumented objects in [callback] are -/// garbage collected without being disposed. +/// The test will fail if instrumented objects in [callback] are +/// garbage collected without being disposed or not garbage +/// collected soon after disposal. +/// +/// [testExecutableWithLeakTracking] must be invoked +/// for this test run. /// /// More about leak tracking: /// https://github.com/dart-lang/leak_tracker. -/// -/// See https://github.com/flutter/devtools/issues/3951 for plans -/// on leak tracking. @isTest void testWidgetsWithLeakTracking( String description, @@ -54,19 +100,32 @@ void testWidgetsWithLeakTracking( bool semanticsEnabled = true, TestVariant variant = const DefaultTestVariant(), dynamic tags, - LeakTrackingTestConfig leakTrackingTestConfig = const LeakTrackingTestConfig(), + LeakTrackingTestConfig leakTrackingTestConfig = + const LeakTrackingTestConfig(), }) { - Future wrappedCallback(WidgetTester tester) async { - await _withFlutterLeakTracking( - () async => callback(tester), - tester, - leakTrackingTestConfig, - ); + configureLeakTrackingTearDown(); + + final PhaseSettings phase = PhaseSettings( + name: description, + leakDiagnosticConfig: leakTrackingTestConfig.leakDiagnosticConfig, + notGCedAllowList: leakTrackingTestConfig.notGCedAllowList, + notDisposedAllowList: leakTrackingTestConfig.notDisposedAllowList, + allowAllNotDisposed: leakTrackingTestConfig.allowAllNotDisposed, + allowAllNotGCed: leakTrackingTestConfig.allowAllNotGCed, + ); + + Future wrappedCallBack(WidgetTester tester) async { + if (!LeakTracking.isStarted) { + _setUpTestingWithLeakTracking(); + } + LeakTracking.phase = phase; + await callback(tester); + LeakTracking.phase = const PhaseSettings.paused(); } testWidgets( description, - wrappedCallback, + wrappedCallBack, skip: skip, timeout: timeout, semanticsEnabled: semanticsEnabled, @@ -75,132 +134,92 @@ void testWidgetsWithLeakTracking( ); } -bool _webWarningPrinted = false; - -/// Runs [callback] with leak tracking. -/// -/// Wrapper for [withLeakTracking] with Flutter specific functionality. -/// -/// The method will fail if wrapped code contains memory leaks. -/// -/// See details in documentation for `withLeakTracking` at -/// https://github.com/dart-lang/leak_tracker/blob/main/lib/src/leak_tracking/orchestration.dart -/// -/// The Flutter related enhancements are: -/// 1. Listens to [MemoryAllocations] events. -/// 2. Uses `tester.runAsync` for leak detection if [tester] is provided. -/// -/// Pass [config] to troubleshoot or exempt leaks. See [LeakTrackingTestConfig] -/// for details. -Future _withFlutterLeakTracking( - DartAsyncCallback callback, - WidgetTester tester, - LeakTrackingTestConfig config, -) async { - // Leak tracker does not work for web platform. +bool _notSupportedWarningPrinted = false; +bool get _isPlatformSupported => !kIsWeb; +void _printPlatformWarningIfNeeded() { if (kIsWeb) { - final bool shouldPrintWarning = !_webWarningPrinted && LeakTrackerGlobalSettings.warnForNonSupportedPlatforms; + final bool shouldPrintWarning = !_notSupportedWarningPrinted && + LeakTracking.warnForUnsupportedPlatforms; if (shouldPrintWarning) { - _webWarningPrinted = true; - debugPrint('Leak tracking is not supported on web platform.\nTo turn off this message, set `LeakTrackingTestConfig.warnForNonSupportedPlatforms` to false.'); + _notSupportedWarningPrinted = true; + debugPrint( + 'Leak tracking is not supported on web platform.\nTo turn off this message, set `LeakTracking.warnForNotSupportedPlatforms` to false.', + ); } - await callback(); return; } - - void flutterEventToLeakTracker(ObjectEvent event) { - return dispatchObjectEvent(event.toMap()); - } - - return TestAsyncUtils.guard(() async { - MemoryAllocations.instance.addListener(flutterEventToLeakTracker); - Future asyncCodeRunner(DartAsyncCallback action) async => tester.runAsync(action); - - try { - Leaks leaks = await withLeakTracking( - callback, - asyncCodeRunner: asyncCodeRunner, - leakDiagnosticConfig: config.leakDiagnosticConfig, - shouldThrowOnLeaks: false, - ); - - leaks = LeakCleaner(config).clean(leaks); - - if (leaks.total > 0) { - config.onLeaks?.call(leaks); - if (config.failTestOnLeaks) { - expect(leaks, isLeakFree); - } - } - } finally { - MemoryAllocations.instance.removeListener(flutterEventToLeakTracker); - } - }); + assert(_isPlatformSupported); } -/// Cleans leaks that are allowed by [config]. -@visibleForTesting -class LeakCleaner { - LeakCleaner(this.config); - - final LeakTrackingTestConfig config; - - static Map<(String, LeakType), int> _countByClassAndType(Leaks leaks) { - final Map<(String, LeakType), int> result = <(String, LeakType), int>{}; - - for (final MapEntry> entry in leaks.byType.entries) { - for (final LeakReport leak in entry.value) { - final (String, LeakType) classAndType = (leak.type, entry.key); - result[classAndType] = (result[classAndType] ?? 0) + 1; - } - } - return result; - } - - Leaks clean(Leaks leaks) { - final Map<(String, LeakType), int> countByClassAndType = _countByClassAndType(leaks); - - final Leaks result = Leaks(>{ - for (final LeakType leakType in leaks.byType.keys) - leakType: leaks.byType[leakType]!.where((LeakReport leak) => _shouldReportLeak(leakType, leak, countByClassAndType)).toList() - }); - return result; - } - - /// Returns true if [leak] should be reported as failure. - bool _shouldReportLeak(LeakType leakType, LeakReport leak, Map<(String, LeakType), int> countByClassAndType) { - switch (leakType) { - case LeakType.notDisposed: - if (config.allowAllNotDisposed) { - return false; - } - case LeakType.notGCed: - case LeakType.gcedLate: - if (config.allowAllNotGCed) { - return false; - } - } +/// Configuration for leak tracking in unit tests. +/// +/// Customized configuration is needed only for test debugging, +/// not for regular test runs. +class LeakTrackingTestConfig { + /// Creates a new instance of [LeakTrackingTestConfig]. + const LeakTrackingTestConfig({ + this.leakDiagnosticConfig = const LeakDiagnosticConfig(), + this.notGCedAllowList = const {}, + this.notDisposedAllowList = const {}, + this.allowAllNotDisposed = false, + this.allowAllNotGCed = false, + }); - final String leakingClass = leak.type; - final (String, LeakType) classAndType = (leakingClass, leakType); + /// Creates a new instance of [LeakTrackingTestConfig] for debugging leaks. + /// + /// This configuration will collect stack traces on start and disposal, + /// and retaining path for notGCed objects. + LeakTrackingTestConfig.debug({ + this.leakDiagnosticConfig = const LeakDiagnosticConfig( + collectStackTraceOnStart: true, + collectStackTraceOnDisposal: true, + collectRetainingPathForNotGCed: true, + ), + this.notGCedAllowList = const {}, + this.notDisposedAllowList = const {}, + this.allowAllNotDisposed = false, + this.allowAllNotGCed = false, + }); - bool isAllowedForClass(Map allowList) { - if (!allowList.containsKey(leakingClass)) { - return false; - } - final int? allowedCount = allowList[leakingClass]; - if (allowedCount == null) { - return true; - } - return allowedCount >= countByClassAndType[classAndType]!; - } + /// Creates a new instance of [LeakTrackingTestConfig] to collect retaining path. + /// + /// This configuration will not collect stack traces, + /// and will collect retaining path for notGCed objects. + LeakTrackingTestConfig.retainingPath({ + this.leakDiagnosticConfig = const LeakDiagnosticConfig( + collectRetainingPathForNotGCed: true, + ), + this.notGCedAllowList = const {}, + this.notDisposedAllowList = const {}, + this.allowAllNotDisposed = false, + this.allowAllNotGCed = false, + }); - switch (leakType) { - case LeakType.notDisposed: - return !isAllowedForClass(config.notDisposedAllowList); - case LeakType.notGCed: - case LeakType.gcedLate: - return !isAllowedForClass(config.notGCedAllowList); - } - } + /// Classes that are allowed to be not garbage collected after disposal. + /// + /// Maps name of the class, as returned by `object.runtimeType.toString()`, + /// to the number of instances of the class that are allowed to be not GCed. + /// + /// If number of instances is [null], any number of instances is allowed. + final Map notGCedAllowList; + + /// Classes that are allowed to be garbage collected without being disposed. + /// + /// Maps name of the class, as returned by `object.runtimeType.toString()`, + /// to the number of instances of the class that are allowed to be not disposed. + /// + /// If number of instances is [null], any number of instances is allowed. + final Map notDisposedAllowList; + + /// If true, all notDisposed leaks will be allowed. + final bool allowAllNotDisposed; + + /// If true, all notGCed leaks will be allowed. + final bool allowAllNotGCed; + + /// When to collect stack trace information. + /// + /// Knowing call stack may help to troubleshoot memory leaks. + /// Customize this parameter to collect stack traces when needed. + final LeakDiagnosticConfig leakDiagnosticConfig; } diff --git a/packages/flutter/test/foundation/leak_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test.dart deleted file mode 100644 index bd02bd2c781dd..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test.dart +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; -import 'package:leak_tracker_testing/leak_tracker_testing.dart'; - -import 'leak_tracking.dart'; - -final String _leakTrackedClassName = '$_LeakTrackedClass'; - -Leaks _leaksOfAllTypes() => Leaks(> { - LeakType.notDisposed: [LeakReport(code: 1, context: {}, type:'myNotDisposedClass', trackedClass: 'myTrackedClass')], - LeakType.notGCed: [LeakReport(code: 2, context: {}, type:'myNotGCedClass', trackedClass: 'myTrackedClass')], - LeakType.gcedLate: [LeakReport(code: 3, context: {}, type:'myGCedLateClass', trackedClass: 'myTrackedClass')], -}); - -Future main() async { - test('Trivial $LeakCleaner returns all leaks.', () { - final LeakCleaner leakCleaner = LeakCleaner(const LeakTrackingTestConfig()); - final Leaks leaks = _leaksOfAllTypes(); - final int leakTotal = leaks.total; - - final Leaks cleanedLeaks = leakCleaner.clean(leaks); - - expect(leaks.total, leakTotal); - expect(cleanedLeaks.total, 3); - }); - - test('$LeakCleaner catches extra leaks', () { - Leaks leaks = _leaksOfAllTypes(); - final LeakReport leak = leaks.notDisposed.first; - leaks.notDisposed.add(leak); - - final LeakTrackingTestConfig config = LeakTrackingTestConfig( - notDisposedAllowList: {leak.type: 1}, - ); - leaks = LeakCleaner(config).clean(leaks); - - expect(leaks.notDisposed, hasLength(2)); - }); - - group('Leak tracking works for non-web, and', () { - testWidgetsWithLeakTracking( - 'respects all allow lists', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - notDisposedAllowList: {_leakTrackedClassName: null}, - notGCedAllowList: {_leakTrackedClassName: null}, - ), - ); - - testWidgetsWithLeakTracking( - 'respects allowAllNotDisposed', - (WidgetTester tester) async { - // ignore: avoid_redundant_argument_values, for readability. - await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: true, notGCed: false)); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - allowAllNotDisposed: true, - ), - ); - - testWidgetsWithLeakTracking( - 'respects allowAllNotGCed', - (WidgetTester tester) async { - // ignore: avoid_redundant_argument_values, for readability. - await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: false, notGCed: true)); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - allowAllNotGCed: true, - ), - ); - - testWidgetsWithLeakTracking( - 'respects count in allow lists', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - notDisposedAllowList: {_leakTrackedClassName: 1}, - notGCedAllowList: {_leakTrackedClassName: 1}, - ), - ); - - group('fails if number or leaks is more than allowed', () { - // This test cannot run inside other tests because test nesting is forbidden. - // So, `expect` happens outside the tests, in `tearDown`. - late Leaks leaks; - - testWidgetsWithLeakTracking( - 'for $_StatelessLeakingWidget', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - onLeaks: (Leaks theLeaks) { - leaks = theLeaks; - }, - failTestOnLeaks: false, - notDisposedAllowList: {_leakTrackedClassName: 1}, - ), - ); - - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 2, expectedNotGCed: 2, shouldContainDebugInfo: false)); - }); - - group('respects notGCed allow lists', () { - // These tests cannot run inside other tests because test nesting is forbidden. - // So, `expect` happens outside the tests, in `tearDown`. - late Leaks leaks; - - testWidgetsWithLeakTracking( - 'when $_StatelessLeakingWidget leaks', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - onLeaks: (Leaks theLeaks) { - leaks = theLeaks; - }, - failTestOnLeaks: false, - notGCedAllowList: {_leakTrackedClassName: null}, - ), - ); - - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, shouldContainDebugInfo: false)); - }); - - group('catches that', () { - // These test cannot run inside other tests because test nesting is forbidden. - // So, `expect` happens outside the tests, in `tearDown`. - late Leaks leaks; - - testWidgetsWithLeakTracking( - '$_StatelessLeakingWidget leaks', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - onLeaks: (Leaks theLeaks) { - leaks = theLeaks; - }, - failTestOnLeaks: false, - ), - ); - - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, expectedNotGCed: 1, shouldContainDebugInfo: false)); - }); - }, - skip: isBrowser); // [intended] Leak detection is off for web. - - testWidgetsWithLeakTracking('Leak tracking is no-op for web', (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - skip: !isBrowser); // [intended] Leaks detection is off for web. -} - -/// Verifies [leaks] contains expected number of leaks for [_LeakTrackedClass]. -void _verifyLeaks( - Leaks leaks, { - int expectedNotDisposed = 0, - int expectedNotGCed = 0, - required bool shouldContainDebugInfo, -}) { - const String linkToLeakTracker = 'https://github.com/dart-lang/leak_tracker'; - - expect( - () => expect(leaks, isLeakFree), - throwsA( - predicate((Object? e) { - return e is TestFailure && e.toString().contains(linkToLeakTracker); - }), - ), - ); - - _verifyLeakList(leaks.notDisposed, expectedNotDisposed, shouldContainDebugInfo); - _verifyLeakList(leaks.notGCed, expectedNotGCed, shouldContainDebugInfo); -} - -void _verifyLeakList(List list, int expectedCount, bool shouldContainDebugInfo){ - expect(list.length, expectedCount); - - for (final LeakReport leak in list) { - if (shouldContainDebugInfo) { - expect(leak.context, isNotEmpty); - } else { - expect(leak.context ?? {}, isEmpty); - } - - expect(leak.trackedClass, contains(_LeakTrackedClass.library)); - expect(leak.trackedClass, contains(_leakTrackedClassName)); - } -} - -/// Storage to keep disposed objects, to generate not-gced leaks. -final List<_LeakTrackedClass> _notGcedStorage = <_LeakTrackedClass>[]; - -class _StatelessLeakingWidget extends StatelessWidget { - _StatelessLeakingWidget({bool notDisposed = true, bool notGCed = true}) { - if (notDisposed) { - // ignore: unused_local_variable, the variable is used to create non disposed leak - final _LeakTrackedClass notDisposed = _LeakTrackedClass(); - } - if (notGCed) { - _notGcedStorage.add(_LeakTrackedClass()..dispose()); - } - } - - @override - Widget build(BuildContext context) { - return const Placeholder(); - } -} - -class _LeakTrackedClass { - _LeakTrackedClass() { - dispatchObjectCreated( - library: library, - className: '$_LeakTrackedClass', - object: this, - ); - } - - static const String library = 'package:my_package/lib/src/my_lib.dart'; - - void dispose() { - dispatchObjectDisposed(object: this); - } -} diff --git a/packages/flutter/test/foundation/leak_tracking_test/README.md b/packages/flutter/test/foundation/leak_tracking_test/README.md new file mode 100644 index 0000000000000..2da6b59a3cd67 --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/README.md @@ -0,0 +1,4 @@ +Code in this folder is copied from leak_tracker. + +TODO(polina-c): start referencing this code in leak_tracker_flutter +https://github.com/dart-lang/leak_tracker/issues/52 diff --git a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart new file mode 100644 index 0000000000000..44ae5a2b8de5a --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart @@ -0,0 +1,8 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const String test1TrackingOnNoLeaks = 'test1, tracking-on, no leaks'; +const String test2TrackingOffLeaks = 'test2, tracking-off, leaks'; +const String test3TrackingOnLeaks = 'test3, tracking-on, leaks'; +const String test4TrackingOnWithStackTrace = 'test4, tracking-on, with stack trace'; diff --git a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart new file mode 100644 index 0000000000000..05f85bba8c986 --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart @@ -0,0 +1,132 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker/leak_tracker.dart'; +import 'package:leak_tracker_testing/leak_tracker_testing.dart'; + +import '../../leak_tracking.dart'; +import '../leaking_widget.dart'; +import 'constants.dart'; + +/// Test configuration for each test library in this directory. +/// +/// See https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html. +Future testExecutable(FutureOr Function() testMain) async { + bool leaksDetected = false; + + // This tear down should be set before leak tracking tear down in + // order to happen after it and verify that leaks are found. + tearDownAll(() async { + if (!kIsWeb) { + expect(leaksDetected, true, reason: 'leaks should be detected'); + } + }); + + configureLeakTrackingTearDown( + configureOnce: true, + onLeaks: (Leaks leaks) { + expect(leaks.total, greaterThan(0)); + leaksDetected = true; + + try { + expect(leaks, isLeakFree); + } catch (e) { + if (e is! TestFailure) { + rethrow; + } + expect(e.message, isNot(contains(test1TrackingOnNoLeaks))); + expect(e.message, isNot(contains(test2TrackingOffLeaks))); + expect(e.message, contains('test: $test3TrackingOnLeaks')); + expect(e.message, contains('test: $test4TrackingOnWithStackTrace')); + } + + _verifyLeaks( + leaks, + test3TrackingOnLeaks, + notDisposed: 1, + notGCed: 1, + shouldContainDebugInfo: false, + ); + _verifyLeaks( + leaks, + test4TrackingOnWithStackTrace, + notDisposed: 1, + notGCed: 1, + shouldContainDebugInfo: true, + ); + }, + ); + + setUpAll(() { + LeakTracking.warnForUnsupportedPlatforms = false; + }); + + await testMain(); +} + +/// Verifies [allLeaks] contains expected number of leaks for the test [testName]. +/// +/// [notDisposed] and [notGCed] set number for expected leaks by leak type. +void _verifyLeaks( + Leaks allLeaks, + String testName, { + int notDisposed = 0, + int notGCed = 0, + required bool shouldContainDebugInfo, +}) { + const String linkToLeakTracker = 'https://github.com/dart-lang/leak_tracker'; + + final Leaks leaks = Leaks( + allLeaks.byType.map( + (LeakType key, List value) => + MapEntry>(key, value.where((LeakReport leak) => leak.phase == testName).toList()), + ), + ); + + if (notDisposed + notGCed > 0) { + expect( + () => expect(leaks, isLeakFree), + throwsA( + predicate((Object? e) { + return e is TestFailure && e.toString().contains(linkToLeakTracker); + }), + ), + ); + } else { + expect(leaks, isLeakFree); + } + + _verifyLeakList( + leaks.notDisposed, + notDisposed, + shouldContainDebugInfo, + ); + _verifyLeakList( + leaks.notGCed, + notGCed, + shouldContainDebugInfo, + ); +} + +void _verifyLeakList( + List list, + int expectedCount, + bool shouldContainDebugInfo, +) { + expect(list.length, expectedCount); + + for (final LeakReport leak in list) { + if (shouldContainDebugInfo) { + expect(leak.context, isNotEmpty); + } else { + expect(leak.context ?? {}, isEmpty); + } + expect(leak.trackedClass, contains(LeakTrackedClass.library)); + expect(leak.trackedClass, contains('$LeakTrackedClass')); + } +} diff --git a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart new file mode 100644 index 0000000000000..0856db01b1f1b --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart @@ -0,0 +1,57 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/src/foundation/constants.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker/leak_tracker.dart'; + +import '../../leak_tracking.dart'; +import '../leaking_widget.dart'; + +const String test1TrackingOnNoLeaks = 'test1, tracking-on, no leaks'; +const String test2TrackingOffLeaks = 'test2, tracking-off, leaks'; +const String test3TrackingOnLeaks = 'test3, tracking-on, leaks'; +const String test4TrackingOnWithStackTrace = 'test4, tracking-on, with stack trace'; + +bool get _isTrackingOn => !LeakTracking.phase.isPaused && LeakTracking.isStarted; + +/// For these tests `expect` for found leaks happens in flutter_test_config.dart. +void main() { + group('group', () { + testWidgetsWithLeakTracking(test1TrackingOnNoLeaks, (WidgetTester widgetTester) async { + expect(_isTrackingOn, true); + expect(LeakTracking.phase.name, test1TrackingOnNoLeaks); + await widgetTester.pumpWidget(Container()); + }); + + testWidgets(test2TrackingOffLeaks, (WidgetTester widgetTester) async { + expect(LeakTracking.phase.name, null); + expect(_isTrackingOn, false); + await widgetTester.pumpWidget(StatelessLeakingWidget()); + }); + }, + skip: kIsWeb); // [intended] Leak tracking is off for web. + + testWidgetsWithLeakTracking(test3TrackingOnLeaks, (WidgetTester widgetTester) async { + expect(_isTrackingOn, true); + expect(LeakTracking.phase.name, test3TrackingOnLeaks); + await widgetTester.pumpWidget(StatelessLeakingWidget()); + }, + skip: kIsWeb); // [intended] Leak tracking is off for web. + + testWidgetsWithLeakTracking( + test4TrackingOnWithStackTrace, + (WidgetTester widgetTester) async { + expect(_isTrackingOn, true); + expect(LeakTracking.phase.name, test4TrackingOnWithStackTrace); + await widgetTester.pumpWidget(StatelessLeakingWidget()); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + leakDiagnosticConfig: LeakDiagnosticConfig( + collectStackTraceOnStart: true, + ), + ), + skip: kIsWeb); // [intended] Leak tracking is off for web. +} diff --git a/packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart b/packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart new file mode 100644 index 0000000000000..411079733b649 --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart @@ -0,0 +1,49 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:leak_tracker/leak_tracker.dart'; + +class LeakTrackedClass { + LeakTrackedClass() { + LeakTracking.dispatchObjectCreated( + library: library, + className: '$LeakTrackedClass', + object: this, + ); + } + + static const String library = 'package:my_package/lib/src/my_lib.dart'; + + void dispose() { + LeakTracking.dispatchObjectDisposed(object: this); + } +} + +final List _notGcedStorage = []; + + +class StatelessLeakingWidget extends StatelessWidget { + StatelessLeakingWidget({ + super.key, + this.notGCed = true, + this.notDisposed = true, + }) { + if (notGCed) { + _notGcedStorage.add(LeakTrackedClass()..dispose()); + } + if (notDisposed) { + // ignore: unused_local_variable + final LeakTrackedClass notDisposedObject = LeakTrackedClass(); + } + } + + final bool notGCed; + final bool notDisposed; + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart b/packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart new file mode 100644 index 0000000000000..8e319c66fcaed --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart @@ -0,0 +1,51 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker/leak_tracker.dart'; + +import '../leak_tracking.dart'; +import 'leaking_widget.dart'; + +const String _test0TrackingOffLeaks = 'test0, tracking-off'; +const String _test1TrackingOn = 'test1, tracking-on'; +const String _test2TrackingOffLeaks = 'test2, tracking-off'; +const String _test3TrackingOn = 'test3, tracking-on'; + +bool get _isTrackingOn => !LeakTracking.phase.isPaused && LeakTracking.isStarted; + +/// Tests with default leak tracking configuration. +/// +/// This set of tests verifies that if `testWidgetsWithLeakTracking` is used at least once, +/// leak tracking is configured as expected, and is noop for `testWidgets`. +void main() { + group('groups are handled', () { + testWidgets(_test0TrackingOffLeaks, (WidgetTester widgetTester) async { + // Flutter test engine may change test order. + expect(_isTrackingOn, false); + expect(LeakTracking.phase.name, null); + await widgetTester.pumpWidget(StatelessLeakingWidget()); + }); + + testWidgetsWithLeakTracking(_test1TrackingOn, (WidgetTester widgetTester) async { + expect(_isTrackingOn, true); + expect(LeakTracking.phase.name, _test1TrackingOn); + }); + + testWidgets(_test2TrackingOffLeaks, (WidgetTester widgetTester) async { + expect(_isTrackingOn, false); + expect(LeakTracking.phase.name, null); + await widgetTester.pumpWidget(StatelessLeakingWidget()); + }); + }, + skip: kIsWeb); // [intended] Leak tracking is off for web. + + testWidgetsWithLeakTracking(_test3TrackingOn, (WidgetTester widgetTester) async { + expect(_isTrackingOn, true); + expect(LeakTracking.phase.name, _test3TrackingOn); + expect(LeakTracking.phase.isPaused, false); + }, + skip: kIsWeb); // [intended] Leak tracking is off for web. +} diff --git a/packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart new file mode 100644 index 0000000000000..3e6209c31ff27 --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker/leak_tracker.dart'; + +import 'leaking_widget.dart'; + +void main() { + testWidgets( + 'Leak tracking is not started without `testWidgetsWithLeakTracking`', + (WidgetTester widgetTester) async { + expect(LeakTracking.isStarted, false); + expect(LeakTracking.phase.name, null); + await widgetTester.pumpWidget(StatelessLeakingWidget()); + + }, + skip: kIsWeb); // [intended] Leak tracking is off for web. +} diff --git a/packages/flutter/test/gestures/transformed_monodrag_test.dart b/packages/flutter/test/gestures/transformed_monodrag_test.dart index c85bf24cd0c86..a0de4a94c58a6 100644 --- a/packages/flutter/test/gestures/transformed_monodrag_test.dart +++ b/packages/flutter/test/gestures/transformed_monodrag_test.dart @@ -12,7 +12,7 @@ import '../foundation/leak_tracking.dart'; void main() { group('Horizontal', () { - testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { + testWidgets('gets local coordinates', (WidgetTester tester) async { int dragCancelCount = 0; final List downDetails = []; final List endDetails = []; diff --git a/packages/flutter/test/gestures/transformed_scale_test.dart b/packages/flutter/test/gestures/transformed_scale_test.dart index c01c6548ad3e4..f48b5e8a14d05 100644 --- a/packages/flutter/test/gestures/transformed_scale_test.dart +++ b/packages/flutter/test/gestures/transformed_scale_test.dart @@ -5,10 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { - testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { + testWidgets('gets local coordinates', (WidgetTester tester) async { final List startDetails = []; final List updateDetails = []; diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 7e38905b8dbe1..0f40fd9821ea2 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -58,7 +58,7 @@ void main() { expect(find.text('View licenses'), findsOneWidget); }); - testWidgetsWithLeakTracking('Material2 - AboutListTile control test', (WidgetTester tester) async { + testWidgets('Material2 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -141,7 +141,7 @@ void main() { expect(find.text('Pirate license'), findsOneWidget); }); - testWidgetsWithLeakTracking('Material3 - AboutListTile control test', (WidgetTester tester) async { + testWidgets('Material3 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -1477,7 +1477,7 @@ void main() { expect(find.text('Exception: Injected failure'), findsOneWidget); }); - testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgets('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1542,7 +1542,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgets('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1607,7 +1607,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgets('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1672,7 +1672,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgets('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1737,7 +1737,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgetsWithLeakTracking('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { + testWidgets('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/108991 final ThemeData theme = ThemeData( appBarTheme: const AppBarTheme(foregroundColor: Color(0xFFFFFFFF)), diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index e94c1f4efd571..4a4ddc6492ae4 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -105,7 +105,7 @@ void main() { expect(find.byKey(key), findsOneWidget); }); - testWidgetsWithLeakTracking('Can build from EditableTextState', (WidgetTester tester) async { + testWidgets('Can build from EditableTextState', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -221,7 +221,7 @@ void main() { ); group('buttonItems', () { - testWidgetsWithLeakTracking('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { + testWidgets('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { // Fill the clipboard so that the Paste option is available in the text // selection menu. await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); @@ -316,7 +316,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgetsWithLeakTracking('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { + testWidgets('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { const String buttonText = 'Click me'; await tester.pumpWidget( diff --git a/packages/flutter/test/material/bottom_sheet_theme_test.dart b/packages/flutter/test/material/bottom_sheet_theme_test.dart index 0e3593d04aca5..71c78577ac19e 100644 --- a/packages/flutter/test/material/bottom_sheet_theme_test.dart +++ b/packages/flutter/test/material/bottom_sheet_theme_test.dart @@ -171,7 +171,7 @@ void main() { expect(material.clipBehavior, clipBehavior); }); - testWidgetsWithLeakTracking('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { + testWidgets('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { const double modalElevation = 5.0; const double persistentElevation = 7.0; const Color modalBackgroundColor = Colors.yellow; @@ -250,7 +250,7 @@ void main() { expect(material.color, null); }); - testWidgetsWithLeakTracking('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { + testWidgets('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { const double lightElevation = 5.0; const double darkElevation = 3.0; const Color lightBackgroundColor = Colors.green; diff --git a/packages/flutter/test/material/button_bar_test.dart b/packages/flutter/test/material/button_bar_test.dart index 16d4e84f0efeb..4666135d1bf0c 100644 --- a/packages/flutter/test/material/button_bar_test.dart +++ b/packages/flutter/test/material/button_bar_test.dart @@ -341,7 +341,7 @@ void main() { group('layoutBehavior', () { - testWidgetsWithLeakTracking('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { + testWidgets('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( @@ -364,7 +364,7 @@ void main() { expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 52.0); }); - testWidgetsWithLeakTracking('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { + testWidgets('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 4732591978bdd..95b8170a17e35 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -496,6 +496,8 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('CheckboxListTile can be disabled', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index 5beec65073f31..6c3781910fcf5 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -302,7 +302,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)); }); - testWidgetsWithLeakTracking('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgets('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index a8cba15354e4a..b82a391def87d 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -701,7 +701,7 @@ void main() { expect(calledDelete, isFalse); }); - testWidgetsWithLeakTracking('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { + testWidgets('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { final UniqueKey iconKey = UniqueKey(); final Widget test = Overlay( initialEntries: [ @@ -877,7 +877,7 @@ void main() { expect(tester.getSize(find.byKey(keyA)), equals(const Size(20.0, 20.0))); }); - testWidgetsWithLeakTracking('Chip padding - LTR', (WidgetTester tester) async { + testWidgets('Chip padding - LTR', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -913,7 +913,7 @@ void main() { expect(tester.getBottomRight(find.byType(Icon)), const Offset(457.0, 309.0)); }); - testWidgetsWithLeakTracking('Chip padding - RTL', (WidgetTester tester) async { + testWidgets('Chip padding - RTL', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -2633,7 +2633,7 @@ void main() { expect(find.byType(InkWell), findsOneWidget); }); - testWidgetsWithLeakTracking('Chip uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgets('Chip uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2721,7 +2721,7 @@ void main() { expect(textColor(), disabledColor); }); - testWidgetsWithLeakTracking('Chip uses stateful border side color in different states', (WidgetTester tester) async { + testWidgets('Chip uses stateful border side color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2801,7 +2801,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgetsWithLeakTracking('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { + testWidgets('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2882,7 +2882,7 @@ void main() { }); - testWidgetsWithLeakTracking('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { + testWidgets('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2971,7 +2971,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgetsWithLeakTracking('Chip uses stateful shape in different states', (WidgetTester tester) async { + testWidgets('Chip uses stateful shape in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); OutlinedBorder? getShape(Set states) { @@ -3339,7 +3339,7 @@ void main() { expect(decoration.shape, shape); }); - testWidgetsWithLeakTracking('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { + testWidgets('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'RawChip'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color backgroundColor = Color(0xff00ff00); diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 13fa9dbf02900..3eded54048f35 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -641,6 +641,8 @@ void main() { await tester.pumpWidget(chipWidget(enabled: false)); await tester.pumpAndSettle(); expect(textColor(), disabledColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Chip uses stateful border side from resolveWith pattern', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index baf135666ab9d..c6181480d1ff0 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -261,6 +261,7 @@ void main() { // https://github.com/flutter/flutter/issues/130354 leakTrackingTestConfig: const LeakTrackingTestConfig( allowAllNotGCed: true, + allowAllNotDisposed: true, )); }); diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 4ba0c9b5e0cdb..3b68e578fa070 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -2338,7 +2338,7 @@ void main() { }); group('AlertDialog.scrollable: ', () { - testWidgetsWithLeakTracking('Title is scrollable', (WidgetTester tester) async { + testWidgets('Title is scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final AlertDialog dialog = AlertDialog( title: Container( @@ -2378,7 +2378,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0))); }); - testWidgetsWithLeakTracking('Title and content are scrollable', (WidgetTester tester) async { + testWidgets('Title and content are scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final Key contentKey = UniqueKey(); final AlertDialog dialog = AlertDialog( @@ -2511,7 +2511,7 @@ void main() { semantics.dispose(); }); - testWidgetsWithLeakTracking('DialogRoute is state restorable', (WidgetTester tester) async { + testWidgets('DialogRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -2660,6 +2660,9 @@ void main() { expect(await previousFocus(), true); expect(okNode.hasFocus, true); expect(cancelNode.hasFocus, false); + + cancelNode.dispose(); + okNode.dispose(); }); testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { @@ -2764,7 +2767,7 @@ void main() { expect(find.text('Dialog2'), findsOneWidget); }); - testWidgetsWithLeakTracking('Uses open focus traversal when overridden', (WidgetTester tester) async { + testWidgets('Uses open focus traversal when overridden', (WidgetTester tester) async { final FocusNode okNode = FocusNode(); final FocusNode cancelNode = FocusNode(); diff --git a/packages/flutter/test/material/drawer_button_test.dart b/packages/flutter/test/material/drawer_button_test.dart index 872e633e7b1e6..5b3c253796ade 100644 --- a/packages/flutter/test/material/drawer_button_test.dart +++ b/packages/flutter/test/material/drawer_button_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; void main() { - testWidgetsWithLeakTracking('DrawerButton control test', (WidgetTester tester) async { + testWidgets('DrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -171,7 +171,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgetsWithLeakTracking('EndDrawerButton control test', (WidgetTester tester) async { + testWidgets('EndDrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index 149733508f81a..306b379460ce4 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -7,8 +7,6 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - const List menuItems = ['one', 'two', 'three', 'four']; void onChanged(T _) { } final Type dropdownButtonType = DropdownButton( @@ -200,7 +198,7 @@ void main() { expect(hintEmptyLabel, oneValueLabel); }); - testWidgetsWithLeakTracking('label position test - show disabledHint: disable', (WidgetTester tester) async { + testWidgets('label position test - show disabledHint: disable', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -238,7 +236,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgetsWithLeakTracking('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { + testWidgets('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -263,7 +261,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgetsWithLeakTracking('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { + testWidgets('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -313,7 +311,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgetsWithLeakTracking('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { + testWidgets('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -351,7 +349,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 24.0)); }); - testWidgetsWithLeakTracking('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { + testWidgets('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { const int value = 1; await tester.pumpWidget( @@ -391,7 +389,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/82910 - testWidgetsWithLeakTracking('null value test', (WidgetTester tester) async { + testWidgets('null value test', (WidgetTester tester) async { int? value = 1; await tester.pumpWidget( @@ -492,7 +490,7 @@ void main() { expect(value, equals('three')); }); - testWidgetsWithLeakTracking('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); // There shouldn't be overflow when expanded although list contains longer items. @@ -527,7 +525,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -567,7 +565,7 @@ void main() { } }); - testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true does not clip large scale text', + testWidgets('DropdownButtonFormField with isDense:true does not clip large scale text', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -606,7 +604,7 @@ void main() { expect(box.size.height, 72.0); }); - testWidgetsWithLeakTracking('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46844 final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -637,7 +635,7 @@ void main() { expect(box.size.height, 48.0); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - custom text style', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - custom text style', (WidgetTester tester) async { const String value = 'foo'; final UniqueKey itemKey = UniqueKey(); @@ -675,7 +673,7 @@ void main() { expect(richText.text.style!.fontSize, 20.0); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -698,7 +696,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking( + testWidgets( 'DropdownButtonFormField - hint displays when the items list is ' 'empty, items is null, and disabledHint is null', (WidgetTester tester) async { @@ -722,7 +720,7 @@ void main() { }, ); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -742,7 +740,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -762,7 +760,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items, ValueChanged? onChanged }) { @@ -780,7 +778,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items}) { @@ -805,7 +803,7 @@ void main() { expect(enabledHintBox.size, equals(disabledHintBox.size)); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { final Key iconKey = UniqueKey(); final Icon customIcon = Icon(Icons.assessment, key: iconKey); @@ -838,7 +836,7 @@ void main() { expect(disabledRichText.text.style!.color, Colors.orange); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - default elevation', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - default elevation', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); debugDisableShadows = false; await tester.pumpWidget(buildFormFrame( @@ -895,7 +893,7 @@ void main() { debugDisableShadows = true; }); - testWidgetsWithLeakTracking('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'c'] .map>((String value) { return DropdownMenuItem( @@ -924,7 +922,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'd'] .map>((String value) { return DropdownMenuItem( @@ -1089,7 +1087,7 @@ void main() { expect(find.text(currentValue), findsOneWidget); }); - testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -1118,7 +1116,7 @@ void main() { expect(validateCalled, 1); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { await tester.pumpWidget(buildFormFrame( buttonAlignment: AlignmentDirectional.center, items: ['one'], diff --git a/packages/flutter/test/material/dropdown_menu_theme_test.dart b/packages/flutter/test/material/dropdown_menu_theme_test.dart index dcfd4ff75e45f..d770f734caa60 100644 --- a/packages/flutter/test/material/dropdown_menu_theme_test.dart +++ b/packages/flutter/test/material/dropdown_menu_theme_test.dart @@ -44,7 +44,7 @@ void main() { expect(description, []); }); - testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -101,7 +101,7 @@ void main() { expect(material.textStyle?.color, themeData.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { + testWidgets('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( dropdownMenuTheme: DropdownMenuThemeData( textStyle: TextStyle( @@ -180,7 +180,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgets('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, @@ -283,7 +283,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgets('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index 0f504b52838c2..4374738b4ecbb 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -196,6 +196,7 @@ void main() { await gesture.moveTo(center); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -259,6 +260,8 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 1.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('ElevatedButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -334,6 +337,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + + focusNode.dispose(); }); @@ -410,6 +415,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('ElevatedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -534,6 +541,8 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered ElevatedButton responds to mouse-exit', (WidgetTester tester) async { @@ -625,6 +634,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('When ElevatedButton disable, Can not set ElevatedButton focus.', (WidgetTester tester) async { @@ -648,6 +659,9 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + + node.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton work with hover', (WidgetTester tester) async { @@ -703,6 +717,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton work with autofocus', (WidgetTester tester) async { @@ -733,6 +749,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton contribute semantics', (WidgetTester tester) async { @@ -1667,7 +1685,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1865,15 +1883,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('ElevatedButton statesController', (WidgetTester tester) async { + testWidgets('ElevatedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('ElevatedButton.icon statesController', (WidgetTester tester) async { + testWidgets('ElevatedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled ElevatedButton statesController', (WidgetTester tester) async { + testWidgets('Disabled ElevatedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index b2d29c7142cac..dc03ac8be41ce 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -340,6 +340,7 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 0.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton.tonal default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { @@ -405,6 +406,7 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 0.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -480,6 +482,7 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + focusNode.dispose(); }); @@ -556,6 +559,7 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -680,6 +684,7 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered FilledButton responds to mouse-exit', (WidgetTester tester) async { @@ -771,6 +776,7 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); testWidgetsWithLeakTracking('When FilledButton disable, Can not set FilledButton focus.', (WidgetTester tester) async { @@ -794,6 +800,7 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton work with hover', (WidgetTester tester) async { @@ -849,6 +856,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton work with autofocus', (WidgetTester tester) async { @@ -879,6 +887,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton contribute semantics', (WidgetTester tester) async { @@ -1741,7 +1750,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1937,15 +1946,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('FilledButton statesController', (WidgetTester tester) async { + testWidgets('FilledButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('FilledButton.icon statesController', (WidgetTester tester) async { + testWidgets('FilledButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled FilledButton statesController', (WidgetTester tester) async { + testWidgets('Disabled FilledButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart index 4d481b87b75f7..b3c3adac92429 100644 --- a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart @@ -51,7 +51,7 @@ void main() { expect(topAfterScroll.dy, equals(0.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), @@ -89,7 +89,7 @@ void main() { expect(topAfterScroll.dy, equals(-100.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), diff --git a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart index 4fa49ea9344be..207b50b519d72 100644 --- a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart @@ -92,7 +92,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -136,7 +136,7 @@ void main() { expect(opacityWidget.opacity, equals(0.0)); }); - testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 932b632617a7f..643377e209931 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -185,7 +185,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('interrupting motion towards the StartTop location.', (WidgetTester tester) async { + testWidgets('interrupting motion towards the StartTop location.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -198,7 +198,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('interrupting entrance to remove the fab.', (WidgetTester tester) async { + testWidgets('interrupting entrance to remove the fab.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(fab: null, location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -217,7 +217,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('interrupting entrance of a new fab.', (WidgetTester tester) async { + testWidgets('interrupting entrance of a new fab.', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( fab: null, diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 189573dfc0ccf..575299d2640df 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -326,7 +326,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -368,6 +368,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(getFABWidget(fabFinder).elevation, 6); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('FlatActionButton mini size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { @@ -785,7 +787,7 @@ void main() { }); // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -909,6 +911,8 @@ void main() { tester.renderObject(find.byType(FloatingActionButton)), paintsExactlyCountTimes(#clipPath, 0), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Can find FloatingActionButton semantics', (WidgetTester tester) async { @@ -1164,7 +1168,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -1206,6 +1210,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(getFABWidget(fabFinder).elevation, 12); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('FloatingActionButton.isExtended', (WidgetTester tester) async { @@ -1327,7 +1333,7 @@ void main() { // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 19ea27f0ad222..749ba84bdeab6 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -100,13 +100,14 @@ void main() { testWidgetsWithLeakTracking('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; + final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( wrap( useMaterial3: material3, child: IconTheme( data: const IconThemeData(), child: IconButton( - focusNode: FocusNode(debugLabel: 'Ink Focus'), + focusNode: focusNode, onPressed: mockOnPressedFunction.handler, icon: const Icon(Icons.link), ), @@ -116,6 +117,8 @@ void main() { final RenderBox icon = tester.renderObject(find.byType(Icon)); expect(icon.size, const Size(24.0, 24.0)); + + focusNode.dispose(); }); testWidgets('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async { @@ -739,6 +742,8 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('IconButton keeps focus when disabled in directional navigation mode.', (WidgetTester tester) async { @@ -781,6 +786,8 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isTrue); + + focusNode.dispose(); }); testWidgetsWithLeakTracking("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { @@ -817,6 +824,9 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); group('feedback', () { @@ -1240,6 +1250,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('IconButton.fill defaults - M3', (WidgetTester tester) async { @@ -1379,6 +1391,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.fill defaults - M3', (WidgetTester tester) async { @@ -1633,6 +1647,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.filledTonal defaults - M3', (WidgetTester tester) async { @@ -1887,6 +1903,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.08))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.outlined defaults - M3', (WidgetTester tester) async { @@ -2047,6 +2065,8 @@ void main() { await expectLater(tester, meetsGuideline(textContrastGuideline)); await gesture.removePointer(); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -2135,6 +2155,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does IconButton contribute semantics - M3', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index 5dc4710697c9c..e24a1b3072ba4 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -271,7 +271,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { + testWidgets('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); @@ -454,7 +454,7 @@ void main() { })); }); - testWidgetsWithLeakTracking('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { + testWidgets('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { final OverlayPortalController controller = OverlayPortalController(); controller.show(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index 1019d9bf4cab6..e444b00a9f10a 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -250,6 +250,7 @@ void main() { inkFeatures, paints ..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response changes color on focus with overlayColor', (WidgetTester tester) async { @@ -298,6 +299,7 @@ void main() { inkFeatures, paints..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink well changes color on pressed with overlayColor', (WidgetTester tester) async { @@ -370,6 +372,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..circle(x: 50, y: 50, color: splashColor)); await gesture.up(); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response splashColor matches resolved overlayColor for MaterialState.pressed', (WidgetTester tester) async { @@ -419,6 +422,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..circle(x: 50, y: 50, color: splashColor)); await gesture.up(); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response uses radius for focus highlight', (WidgetTester tester) async { @@ -449,6 +453,7 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell uses borderRadius for focus highlight', (WidgetTester tester) async { @@ -485,6 +490,7 @@ void main() { rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(10)), color: const Color(0xff0000ff), )); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell uses borderRadius for hover highlight', (WidgetTester tester) async { @@ -576,6 +582,7 @@ void main() { sampleSize: 100, )), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell customBorder clips for hover highlight', (WidgetTester tester) async { @@ -667,6 +674,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 1)); expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkResponse highlightShape can be updated', (WidgetTester tester) async { @@ -708,6 +716,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell borderRadius can be updated', (WidgetTester tester) async { @@ -753,6 +762,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(30)), color: const Color(0xff0000ff), )); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell customBorder can be updated', (WidgetTester tester) async { @@ -820,6 +830,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t sampleSize: 100, )), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell splash customBorder can be updated', (WidgetTester tester) async { @@ -908,6 +919,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await gesture.up(); + focusNode.dispose(); }); testWidgetsWithLeakTracking("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async { @@ -940,6 +952,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t focusNode.requestFocus(); await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawRect, 0)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell.mouseCursor changes cursor on hover', (WidgetTester tester) async { @@ -1029,7 +1042,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1218,6 +1231,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response accepts focus when disabled in directional navigation mode', (WidgetTester tester) async { @@ -1264,6 +1278,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isTrue); + focusNode.dispose(); }); testWidgetsWithLeakTracking("ink response doesn't hover when disabled", (WidgetTester tester) async { @@ -1317,6 +1332,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking('When ink wells are nested, only the inner one is triggered by tap splash', (WidgetTester tester) async { @@ -2071,7 +2087,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); }); - testWidgetsWithLeakTracking('InkWell dispose statesController', (WidgetTester tester) async { + testWidgets('InkWell disposes statesController', (WidgetTester tester) async { int tapCount = 0; Widget buildFrame(MaterialStatesController? statesController) { return MaterialApp( diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index a7f341072de94..b4285c04ed689 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -241,6 +241,8 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('cannot be traversed to when disabled', (WidgetTester tester) async { @@ -276,6 +278,9 @@ void main() { await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); testWidgetsWithLeakTracking('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/input_date_picker_form_field_test.dart b/packages/flutter/test/material/input_date_picker_form_field_test.dart index 50275ffe79cca..076b3978f41a0 100644 --- a/packages/flutter/test/material/input_date_picker_form_field_test.dart +++ b/packages/flutter/test/material/input_date_picker_form_field_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; import '../widgets/clipboard_utils.dart'; class TestMaterialLocalizations extends DefaultMaterialLocalizations { @@ -98,7 +97,7 @@ void main() { group('InputDatePickerFormField', () { - testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { + testWidgets('Initial date is the default', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); final DateTime initialDate = DateTime(2016, DateTime.february, 21); DateTime? inputDate; @@ -112,7 +111,7 @@ void main() { expect(inputDate, equals(initialDate)); }); - testWidgetsWithLeakTracking('Changing initial date is reflected in text value', (WidgetTester tester) async { + testWidgets('Changing initial date is reflected in text value', (WidgetTester tester) async { final DateTime initialDate = DateTime(2016, DateTime.february, 21); final DateTime updatedInitialDate = DateTime(2016, DateTime.february, 23); await tester.pumpWidget(inputDatePickerField( @@ -127,7 +126,7 @@ void main() { expect(textFieldController(tester).value.text, equals('02/23/2016')); }); - testWidgetsWithLeakTracking('Valid date entry', (WidgetTester tester) async { + testWidgets('Valid date entry', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -140,7 +139,7 @@ void main() { expect(inputDate, equals(DateTime(2016, DateTime.february, 21))); }); - testWidgetsWithLeakTracking('Invalid text entry shows errorFormat text', (WidgetTester tester) async { + testWidgets('Invalid text entry shows errorFormat text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -167,7 +166,7 @@ void main() { expect(find.text('That is not a date.'), findsOneWidget); }); - testWidgetsWithLeakTracking('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { + testWidgets('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -202,7 +201,7 @@ void main() { expect(find.text('Not in given range.'), findsOneWidget); }); - testWidgetsWithLeakTracking('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { + testWidgets('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -228,7 +227,7 @@ void main() { expect(find.text('Out of range.'), findsNothing); }); - testWidgetsWithLeakTracking('Empty field shows hint text when focused', (WidgetTester tester) async { + testWidgets('Empty field shows hint text when focused', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Focus on it await tester.tap(find.byType(TextField)); @@ -251,7 +250,7 @@ void main() { expect(textOpacity(tester, 'Enter some date'), equals(0.0)); }); - testWidgetsWithLeakTracking('Label text', (WidgetTester tester) async { + testWidgets('Label text', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Default label expect(find.text('Enter Date'), findsOneWidget); @@ -263,7 +262,7 @@ void main() { expect(find.text('Give me a date!'), findsOneWidget); }); - testWidgetsWithLeakTracking('Semantics', (WidgetTester tester) async { + testWidgets('Semantics', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); // Fill the clipboard so that the Paste option is available in the text @@ -292,7 +291,7 @@ void main() { semantics.dispose(); }); - testWidgetsWithLeakTracking('InputDecorationTheme is honored', (WidgetTester tester) async { + testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async { const InputBorder border = InputBorder.none; await tester.pumpWidget(inputDatePickerField( theme: ThemeData.from(colorScheme: const ColorScheme.light()).copyWith( @@ -326,7 +325,7 @@ void main() { expect(containerColor, equals(Colors.transparent)); }); - testWidgetsWithLeakTracking('Date text localization', (WidgetTester tester) async { + testWidgets('Date text localization', (WidgetTester tester) async { final Iterable> delegates = >[ TestMaterialLocalizationsDelegate(), DefaultWidgetsLocalizations.delegate, @@ -349,7 +348,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { + testWidgets('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( @@ -364,7 +363,7 @@ void main() { expect(find.text(errorFormatText), findsNothing); }); - testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { + testWidgets('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index 962e31854cdfe..b388421bb4a78 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -904,6 +904,8 @@ void main() { rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), ), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('ListTile can be hovered and has correct hover color', (WidgetTester tester) async { @@ -1234,6 +1236,8 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('ListTile respects tileColor & selectedTileColor', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index f07f79528b6a3..6a1e70fc4c464 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -568,7 +568,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgetsWithLeakTracking('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { + testWidgets('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/106303 final GlobalKey scaffoldKey = GlobalKey(); diff --git a/packages/flutter/test/material/magnifier_test.dart b/packages/flutter/test/material/magnifier_test.dart index f700ca40c95ae..9abf8906b2fcd 100644 --- a/packages/flutter/test/material/magnifier_test.dart +++ b/packages/flutter/test/material/magnifier_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { final MagnifierController magnifierController = MagnifierController(); const Rect reasonableTextField = Rect.fromLTRB(50, 100, 200, 100); @@ -112,7 +110,7 @@ void main() { group('magnifier', () { group('position', () { - testWidgetsWithLeakTracking( + testWidgets( 'should be at gesture position if does not violate any positioning rules', (WidgetTester tester) async { final Key textField = UniqueKey(); @@ -168,7 +166,7 @@ void main() { ); }); - testWidgetsWithLeakTracking( + testWidgets( 'should never move outside the right bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -201,7 +199,7 @@ void main() { lessThanOrEqualTo(reasonableTextField.right)); }); - testWidgetsWithLeakTracking( + testWidgets( 'should never move outside the left bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -233,7 +231,7 @@ void main() { greaterThanOrEqualTo(reasonableTextField.left)); }); - testWidgetsWithLeakTracking('should position vertically at the center of the line', (WidgetTester tester) async { + testWidgets('should position vertically at the center of the line', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), )); @@ -256,7 +254,7 @@ void main() { reasonableTextField.center.dy - basicOffset.dy); }); - testWidgetsWithLeakTracking('should reposition vertically if mashed against the ceiling', + testWidgets('should reposition vertically if mashed against the ceiling', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = Rect.fromPoints(Offset.zero, const Offset(200, 0)); @@ -291,7 +289,7 @@ void main() { return magnifier.additionalFocalPointOffset; } - testWidgetsWithLeakTracking( + testWidgets( 'should shift focal point so that the lens sees nothing out of bounds', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( @@ -319,7 +317,7 @@ void main() { lessThan(reasonableTextField.left)); }); - testWidgetsWithLeakTracking( + testWidgets( 'focal point should shift if mashed against the top to always point to text', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = @@ -356,7 +354,7 @@ void main() { return animatedPositioned.duration.compareTo(Duration.zero) != 0; } - testWidgetsWithLeakTracking('should not be animated on the initial state', + testWidgets('should not be animated on the initial state', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -381,7 +379,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgetsWithLeakTracking('should not be animated on horizontal shifts', + testWidgets('should not be animated on horizontal shifts', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -415,7 +413,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgetsWithLeakTracking('should be animated on vertical shifts', + testWidgets('should be animated on vertical shifts', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); @@ -451,7 +449,7 @@ void main() { expect(getIsAnimated(tester), true); }); - testWidgetsWithLeakTracking('should stop being animated when timer is up', + testWidgets('should stop being animated when timer is up', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); diff --git a/packages/flutter/test/material/material_button_test.dart b/packages/flutter/test/material/material_button_test.dart index 1e79a48320e01..cf611f7c8efd8 100644 --- a/packages/flutter/test/material/material_button_test.dart +++ b/packages/flutter/test/material/material_button_test.dart @@ -143,6 +143,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('MaterialButton elevation and colors have proper precedence', (WidgetTester tester) async { @@ -215,6 +217,8 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)..rect(color: highlightColor)); expect(material.elevation, equals(highlightElevation)); await gesture2.up(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking("MaterialButton's disabledColor takes precedence over its default disabled color.", (WidgetTester tester) async { @@ -299,6 +303,8 @@ void main() { await tester.pump(); expect(focusNode.hasPrimaryFocus, isTrue); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('MaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index e5a8536754946..003ff987ed27c 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -5,8 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { void onPressed(TestMenu item) {} @@ -54,7 +52,7 @@ void main() { expect(identical(MenuBarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { + testWidgets('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -107,7 +105,7 @@ void main() { expect(subMenuMaterial.color, equals(Colors.green)); }); - testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgets('Constructor parameters override theme parameters', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_style_test.dart b/packages/flutter/test/material/menu_style_test.dart index acc6d2079761f..dc501b68bc386 100644 --- a/packages/flutter/test/material/menu_style_test.dart +++ b/packages/flutter/test/material/menu_style_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; void main() { Finder findMenuPanels() { @@ -43,7 +42,7 @@ void main() { expect(identical(MenuStyle.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('fixedSize affects geometry', (WidgetTester tester) async { + testWidgets('fixedSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -86,7 +85,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgetsWithLeakTracking('maximumSize affects geometry', (WidgetTester tester) async { + testWidgets('maximumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -129,7 +128,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgetsWithLeakTracking('minimumSize affects geometry', (WidgetTester tester) async { + testWidgets('minimumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -172,7 +171,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(300.0, 300.0))); }); - testWidgetsWithLeakTracking('Material parameters are honored', (WidgetTester tester) async { + testWidgets('Material parameters are honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -238,7 +237,7 @@ void main() { expect(panelPadding.padding, equals(const EdgeInsets.all(20))); }); - testWidgetsWithLeakTracking('visual density', (WidgetTester tester) async { + testWidgets('visual density', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index 868d4eb7f93de..38c727025f6c6 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; void main() { void onPressed(TestMenu item) {} @@ -54,7 +53,7 @@ void main() { expect(identical(MenuThemeData.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { + testWidgets('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -107,7 +106,7 @@ void main() { expect(subMenuMaterial.color, equals(Colors.red)); }); - testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgets('Constructor parameters override theme parameters', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/mergeable_material_test.dart b/packages/flutter/test/material/mergeable_material_test.dart index 1d184edb0f5eb..6b2a98d4b7307 100644 --- a/packages/flutter/test/material/mergeable_material_test.dart +++ b/packages/flutter/test/material/mergeable_material_test.dart @@ -80,7 +80,7 @@ void main() { expect(box.size.height, equals(0)); }); - testWidgetsWithLeakTracking('MergeableMaterial update slice', (WidgetTester tester) async { + testWidgets('MergeableMaterial update slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -234,7 +234,7 @@ void main() { debugDisableShadows = true; }); - testWidgetsWithLeakTracking('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { + testWidgets('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( const MaterialApp( @@ -1168,7 +1168,7 @@ void main() { ); } - testWidgetsWithLeakTracking('MergeableMaterial dividers', (WidgetTester tester) async { + testWidgets('MergeableMaterial dividers', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1330,7 +1330,7 @@ void main() { expect(decoration.border!.top.color, dividerColor); }); - testWidgetsWithLeakTracking('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { + testWidgets('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { const Color themeCardColor = Colors.red; const Color materialSliceColor = Colors.green; diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index 2e8befad6de7f..cde4e4eb0eace 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -5,10 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { - testWidgetsWithLeakTracking('Navigation drawer updates destinations when tapped', + testWidgets('Navigation drawer updates destinations when tapped', (WidgetTester tester) async { int mutatedIndex = -1; final GlobalKey scaffoldKey = GlobalKey(); @@ -51,7 +49,7 @@ void main() { expect(mutatedIndex, 0); }); - testWidgetsWithLeakTracking('NavigationDrawer can update background color', + testWidgets('NavigationDrawer can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; final GlobalKey scaffoldKey = GlobalKey(); @@ -84,7 +82,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgetsWithLeakTracking('NavigationDrawer can update elevation', + testWidgets('NavigationDrawer can update elevation', (WidgetTester tester) async { const double elevation = 42.0; final GlobalKey scaffoldKey = GlobalKey(); @@ -116,7 +114,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(elevation)); }); - testWidgetsWithLeakTracking( + testWidgets( 'NavigationDrawer uses proper defaults when no parameters are given', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -165,7 +163,7 @@ void main() { expect(iconBox.size, const Size(24.0, 24.0)); }); - testWidgetsWithLeakTracking('Navigation drawer is scrollable', (WidgetTester tester) async { + testWidgets('Navigation drawer is scrollable', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 500, viewHeight: 300); await tester.pumpWidget( @@ -212,7 +210,7 @@ void main() { expect(find.text('Label10'), findsNothing); }); - testWidgetsWithLeakTracking('Safe Area test', (WidgetTester tester) async { + testWidgets('Safe Area test', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const double viewHeight = 300; widgetSetup(tester, 500, viewHeight: viewHeight); @@ -253,7 +251,7 @@ void main() { expect(tester.getBottomRight(find.widgetWithText(NavigationDrawerDestination,'Label4')).dy, viewHeight); }); - testWidgetsWithLeakTracking('Navigation drawer semantics', (WidgetTester tester) async { + testWidgets('Navigation drawer semantics', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme= ThemeData.from(colorScheme: const ColorScheme.light()); Widget widget({int selectedIndex = 0}) { @@ -323,7 +321,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); @@ -374,7 +372,7 @@ void main() { expect(_getInkWell(tester)?.customBorder, shape); }); - testWidgetsWithLeakTracking('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { + testWidgets('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 3000, viewHeight: 3000); final Widget widget = _buildWidget( diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 1bc1fe8b29602..1c8a26e7d47bd 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -229,6 +229,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does OutlinedButton work with hover', (WidgetTester tester) async { @@ -287,6 +289,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does OutlinedButton work with autofocus', (WidgetTester tester) async { @@ -317,6 +321,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgets('Default OutlinedButton meets a11y contrast guidelines', (WidgetTester tester) async { @@ -362,6 +368,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -431,6 +439,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -500,6 +510,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton uses stateful color for icon color in different states', (WidgetTester tester) async { @@ -567,6 +579,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton uses stateful color for border color in different states', (WidgetTester tester) async { @@ -635,6 +649,8 @@ void main() { await gesture.down(center); await tester.pumpAndSettle(); expect(outlinedButton, paints..drrect(color: pressedColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -729,6 +745,8 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered OutlinedButton responds to mouse-exit', (WidgetTester tester) async { @@ -820,6 +838,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('When OutlinedButton disable, Can not set OutlinedButton focus.', (WidgetTester tester) async { @@ -843,6 +863,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking("Outline button doesn't crash if disabled during a gesture", (WidgetTester tester) async { @@ -1821,7 +1843,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1974,15 +1996,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('OutlinedButton statesController', (WidgetTester tester) async { + testWidgets('OutlinedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('OutlinedButton.icon statesController', (WidgetTester tester) async { + testWidgets('OutlinedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled OutlinedButton statesController', (WidgetTester tester) async { + testWidgets('Disabled OutlinedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 2a46455781e12..27556b443f9ff 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -208,7 +208,7 @@ void main() { expect(indicatorColors(tester), const [kBlue, kRed, kRed]); }); - testWidgetsWithLeakTracking('PageSelector indicatorSize', (WidgetTester tester) async { + testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, diff --git a/packages/flutter/test/material/persistent_bottom_sheet_test.dart b/packages/flutter/test/material/persistent_bottom_sheet_test.dart index eb7c6eec93f7d..21d693bfe8b3b 100644 --- a/packages/flutter/test/material/persistent_bottom_sheet_test.dart +++ b/packages/flutter/test/material/persistent_bottom_sheet_test.dart @@ -124,7 +124,7 @@ void main() { expect(buildCount, equals(2)); }); - testWidgetsWithLeakTracking('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { + testWidgets('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: const Center(child: Text('body')), @@ -187,7 +187,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgetsWithLeakTracking('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { + testWidgets('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -299,7 +299,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgetsWithLeakTracking('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { + testWidgets('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -410,7 +410,7 @@ void main() { expect(find.text('Item 22'), findsNothing); }); - testWidgetsWithLeakTracking('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { + testWidgets('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -590,7 +590,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/71435 - testWidgetsWithLeakTracking( + testWidgets( 'Scaffold.bottomSheet should be updated without creating a new RO' ' when the new widget has the same key and type.', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index 4ad6e7e9cbdcd..eca0c83ae642a 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -584,6 +584,7 @@ void main() { ..circle(color: const Color(0x61000000)) ..circle(color: const Color(0x61000000)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio is focusable and has correct focus color', (WidgetTester tester) async { @@ -662,6 +663,7 @@ void main() { ..circle(color: theme.colorScheme.onSurface.withOpacity(0.38)) ..circle(color: theme.colorScheme.onSurface.withOpacity(0.38)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { @@ -908,6 +910,8 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.space); await tester.pumpAndSettle(); expect(groupValue, equals(2)); + + focusNode2.dispose(); }); testWidgetsWithLeakTracking('Radio responds to density changes.', (WidgetTester tester) async { @@ -1224,6 +1228,8 @@ void main() { ..circle(color: theme.hoverColor) ..circle(color: hoveredFillColor), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { @@ -1302,6 +1308,8 @@ void main() { ..circle(color: theme.colorScheme.primary.withOpacity(0.08)) ..circle(color: hoveredFillColor), ); + + focusNode.dispose(); }); testWidgets('Radio overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { @@ -1447,6 +1455,8 @@ void main() { ), reason: 'Hovered Radio should use overlay color $hoverOverlayColor over $hoverColor', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { @@ -1710,6 +1720,8 @@ void main() { Material.of(tester.element(find.byType(Radio))), paints..circle(color: theme.hoverColor)..circle(color: colors.secondary) ); + + focusNode.dispose(); }); testWidgets('Material3 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { @@ -1796,6 +1808,8 @@ void main() { Material.of(tester.element(find.byType(Radio))), paints..circle(color: colors.primary.withOpacity(0.08))..circle(color: colors.primary.withOpacity(1)) ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Radio.adaptive shows the correct platform widget', (WidgetTester tester) async { @@ -1892,6 +1906,7 @@ void main() { ..circle(color: theme.focusColor) ..circle(color: theme.colorScheme.secondary) ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { @@ -1957,5 +1972,6 @@ void main() { ..circle(color: theme.colorScheme.primary.withOpacity(0.12)) ..circle(color: theme.colorScheme.primary) ); + focusNode.dispose(); }); } diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index 0f4f2270469f9..f89cfe9957337 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -9,11 +9,9 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { // Regression test for https://github.com/flutter/flutter/issues/105833 - testWidgetsWithLeakTracking('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { RangeValues values = const RangeValues(0.1, 0.5); bool dragStarted = false; final Key sliderKey = UniqueKey(); @@ -119,7 +117,7 @@ void main() { expect(dragStarted, false); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -173,7 +171,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -227,7 +225,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -285,7 +283,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -343,7 +341,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -387,7 +385,7 @@ void main() { expect(values.end, equals(1)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -431,7 +429,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -477,7 +475,7 @@ void main() { expect(values.end, equals(100)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -523,7 +521,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -573,7 +571,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -623,7 +621,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -675,7 +673,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -727,7 +725,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -777,7 +775,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -827,7 +825,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -879,7 +877,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -931,7 +929,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { + testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); RangeValues? startValues; RangeValues? endValues; @@ -985,7 +983,7 @@ void main() { expect(endValues!.end, moreOrLessEquals(70, epsilon: 1)); }); - testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { + testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); late RangeValues startValues; late RangeValues endValues; @@ -1100,7 +1098,7 @@ void main() { ); } - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1129,7 +1127,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1157,7 +1155,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1184,7 +1182,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1217,7 +1215,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1247,7 +1245,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1288,7 +1286,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1308,7 +1306,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1497,7 +1495,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1564,7 +1562,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1638,7 +1636,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { + testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1715,7 +1713,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1796,7 +1794,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101868 - testWidgetsWithLeakTracking('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { + testWidgets('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1854,7 +1852,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Range Slider Semantics - ltr', (WidgetTester tester) async { + testWidgets('Range Slider Semantics - ltr', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1938,7 +1936,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Range Slider Semantics - rtl', (WidgetTester tester) async { + testWidgets('Range Slider Semantics - rtl', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -2020,7 +2018,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Range Slider implements debugFillProperties', (WidgetTester tester) async { + testWidgets('Range Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); RangeSlider( @@ -2051,7 +2049,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { + testWidgets('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -2090,7 +2088,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { + testWidgets('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -2135,7 +2133,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { + testWidgets('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { // Regress test for https://github.com/flutter/flutter/issues/65943 Widget buildFrame(double maxValue) { return MaterialApp( @@ -2179,7 +2177,7 @@ void main() { expect(nearEqual(activeTrackRect.right, (800.0 - 24.0 - 24.0) * (8 / 15) + 24.0, 0.01), true); }); - testWidgetsWithLeakTracking('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { const RangeValues values = RangeValues(50, 70); // Test default cursor. @@ -2234,7 +2232,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgetsWithLeakTracking('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { + testWidgets('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { RangeValues values = const RangeValues(50, 70); const MouseCursor disabledCursor = SystemMouseCursors.basic; const MouseCursor hoveredCursor = SystemMouseCursors.grab; @@ -2308,7 +2306,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), draggedCursor); }); - testWidgetsWithLeakTracking('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgets('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2371,7 +2369,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgets('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2427,7 +2425,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { + testWidgets('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); const Color hoverColor = Color(0xffff0000); @@ -2542,7 +2540,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgets('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128433 int startFired = 0; diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index 2306e083df160..9f18984196d94 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -108,6 +108,7 @@ void main() { await tester.pumpAndSettle(); expect(pressed, isTrue); + focusNode.dispose(); }); testWidgetsWithLeakTracking('materialTapTargetSize.padded expands hit test area', (WidgetTester tester) async { @@ -345,6 +346,7 @@ void main() { await tester.pumpAndSettle(const Duration(seconds: 1)); expect(box, paints..rect(color: focusColor)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('RawMaterialButton loses focus when disabled.', (WidgetTester tester) async { @@ -379,6 +381,7 @@ void main() { await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking("Disabled RawMaterialButton can't be traversed to.", (WidgetTester tester) async { @@ -419,6 +422,9 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); testWidgetsWithLeakTracking('RawMaterialButton handles hover', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/scrollbar_paint_test.dart b/packages/flutter/test/material/scrollbar_paint_test.dart index 1686ff52e495d..0b86294e5cf2a 100644 --- a/packages/flutter/test/material/scrollbar_paint_test.dart +++ b/packages/flutter/test/material/scrollbar_paint_test.dart @@ -79,7 +79,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('works with MaterialApp and Scaffold', (WidgetTester tester) async { + testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -123,7 +123,7 @@ void main() { ); }); - testWidgetsWithLeakTracking("should not paint when there isn't enough space", (WidgetTester tester) async { + testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( diff --git a/packages/flutter/test/material/search_bar_theme_test.dart b/packages/flutter/test/material/search_bar_theme_test.dart index d6a2593797748..626fe20912010 100644 --- a/packages/flutter/test/material/search_bar_theme_test.dart +++ b/packages/flutter/test/material/search_bar_theme_test.dart @@ -235,19 +235,19 @@ void main() { expect(trailingRect.right, barRect.right - 16.0); } - testWidgetsWithLeakTracking('SearchBar properties overrides defaults', (WidgetTester tester) async { + testWidgets('SearchBar properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgetsWithLeakTracking('SearchBar theme data overrides defaults', (WidgetTester tester) async { + testWidgets('SearchBar theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { + testWidgets('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); @@ -255,7 +255,7 @@ void main() { // Same as the previous tests with empty SearchBarThemeData's instead of null. - testWidgetsWithLeakTracking('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgets('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true, searchBarThemeData: const SearchBarThemeData(), overallTheme: const SearchBarThemeData())); @@ -263,14 +263,14 @@ void main() { checkSearchBar(tester); }); - testWidgetsWithLeakTracking('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgets('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme, overallTheme: const SearchBarThemeData())); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgets('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); diff --git a/packages/flutter/test/material/search_view_theme_test.dart b/packages/flutter/test/material/search_view_theme_test.dart index 98e8e379cc6dd..adc8ff87f8874 100644 --- a/packages/flutter/test/material/search_view_theme_test.dart +++ b/packages/flutter/test/material/search_view_theme_test.dart @@ -197,21 +197,21 @@ void main() { expect(inputText.style.fontSize, headerTextStyle.fontSize); } - testWidgetsWithLeakTracking('SearchView properties overrides defaults', (WidgetTester tester) async { + testWidgets('SearchView properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchView(tester); }); - testWidgetsWithLeakTracking('SearchView theme data overrides defaults', (WidgetTester tester) async { + testWidgets('SearchView theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); checkSearchView(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { + testWidgets('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); @@ -220,7 +220,7 @@ void main() { // Same as the previous tests with empty SearchViewThemeData's instead of null. - testWidgetsWithLeakTracking('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgets('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true, searchViewThemeData: const SearchViewThemeData(), overallTheme: const SearchViewThemeData())); @@ -229,7 +229,7 @@ void main() { checkSearchView(tester); }); - testWidgetsWithLeakTracking('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgets('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme, overallTheme: const SearchViewThemeData())); await tester.tap(find.byIcon(Icons.search)); @@ -237,7 +237,7 @@ void main() { checkSearchView(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgets('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index bc0caa645fb1b..57b31588e8862 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; Widget boilerplate({required Widget child}) { @@ -22,7 +21,7 @@ Widget boilerplate({required Widget child}) { void main() { - testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { + testWidgets('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -330,7 +329,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgetsWithLeakTracking('SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgets('SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -409,7 +408,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgetsWithLeakTracking('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgets('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -486,7 +485,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes semantics.dispose(); }); - testWidgetsWithLeakTracking('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { + testWidgets('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -534,7 +533,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('SegmentedButton has no tooltips by default', (WidgetTester tester) async { + testWidgets('SegmentedButton has no tooltips by default', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -558,7 +557,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byType(Tooltip), findsNothing); }); - testWidgetsWithLeakTracking('SegmentedButton has correct tooltips', (WidgetTester tester) async { + testWidgets('SegmentedButton has correct tooltips', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/segmented_button_theme_test.dart b/packages/flutter/test/material/segmented_button_theme_test.dart index 6c2cf45a0df6b..ce19b4b476be2 100644 --- a/packages/flutter/test/material/segmented_button_theme_test.dart +++ b/packages/flutter/test/material/segmented_button_theme_test.dart @@ -43,7 +43,7 @@ void main() { expect(description, []); }); - testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -110,7 +110,7 @@ void main() { } }); - testWidgetsWithLeakTracking('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { + testWidgets('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: true, segmentedButtonTheme: SegmentedButtonThemeData( @@ -203,7 +203,7 @@ void main() { } }); - testWidgetsWithLeakTracking('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgets('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { @@ -330,7 +330,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgets('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index c5d110b1ad9a8..db8434b831c52 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0); @@ -18,7 +17,7 @@ Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { } void main() { - testWidgetsWithLeakTracking('SelectionArea uses correct selection controls', (WidgetTester tester) async { + testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('abc'), @@ -40,7 +39,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgetsWithLeakTracking('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { + testWidgets('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123378 await tester.pumpWidget( const MaterialApp( @@ -71,7 +70,7 @@ void main() { }); - testWidgetsWithLeakTracking('builds the default context menu by default', (WidgetTester tester) async { + testWidgets('builds the default context menu by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SelectionArea( @@ -98,7 +97,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgetsWithLeakTracking('builds a custom context menu if provided', (WidgetTester tester) async { + testWidgets('builds a custom context menu if provided', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -134,7 +133,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { SelectedContent? content; await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 935e959afff4d..383dc49d4f9b8 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -7,8 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { test('SliderThemeData copyWith, ==, hashCode basics', () { expect(const SliderThemeData(), const SliderThemeData().copyWith()); @@ -20,7 +18,7 @@ void main() { expect(identical(SliderThemeData.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { + testWidgets('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData().debugFillProperties(builder); @@ -32,7 +30,7 @@ void main() { expect(description, []); }); - testWidgetsWithLeakTracking('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgets('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData( trackHeight: 7.0, @@ -502,7 +500,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Slider parameters overrides theme properties', (WidgetTester tester) async { + testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async { debugDisableShadows = false; const Color activeTrackColor = Color(0xffff0001); const Color inactiveTrackColor = Color(0xffff0002); @@ -556,7 +554,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { + testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -580,7 +578,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { + testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -604,7 +602,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { + testWidgets('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -634,7 +632,7 @@ void main() { expect(sliderTheme.valueIndicatorTextStyle!.color, equals(customColor4)); }); - testWidgetsWithLeakTracking('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { + testWidgets('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -658,7 +656,7 @@ void main() { expect(sliderTheme.rangeValueIndicatorShape, const PaddleRangeSliderValueIndicatorShape()); }); - testWidgetsWithLeakTracking('SliderThemeData lerps correctly', (WidgetTester tester) async { + testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async { final SliderThemeData sliderThemeBlack = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -692,7 +690,7 @@ void main() { expect(lerp.valueIndicatorTextStyle!.color, equals(middleGrey.withAlpha(0xff))); }); - testWidgetsWithLeakTracking('Default slider track draws correctly', (WidgetTester tester) async { + testWidgets('Default slider track draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -728,7 +726,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Default slider overlay draws correctly', (WidgetTester tester) async { + testWidgets('Default slider overlay draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -789,7 +787,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider can use theme overlay with material states', (WidgetTester tester) async { + testWidgets('Slider can use theme overlay with material states', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -848,7 +846,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { + testWidgets('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -892,7 +890,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1076,7 +1074,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1260,7 +1258,7 @@ void main() { } }); - testWidgetsWithLeakTracking('The slider track height can be overridden', (WidgetTester tester) async { + testWidgets('The slider track height can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(trackHeight: 16); const Radius radius = Radius.circular(8); const Radius activatedRadius = Radius.circular(9); @@ -1290,7 +1288,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { + testWidgets('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 7, @@ -1315,7 +1313,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { + testWidgets('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 9, @@ -1338,7 +1336,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { + testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5), activeTickMarkColor: const Color(0xfadedead), @@ -1371,7 +1369,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider overlay shape size can be overridden', (WidgetTester tester) async { + testWidgets('The default slider overlay shape size can be overridden', (WidgetTester tester) async { const double uniqueOverlayRadius = 23; final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: const RoundSliderOverlayShape( @@ -1398,7 +1396,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/74503 - testWidgetsWithLeakTracking('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgets('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1439,7 +1437,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/125467 - testWidgetsWithLeakTracking('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgets('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1490,7 +1488,7 @@ void main() { // // The value indicator can be skipped by passing the appropriate // [ShowValueIndicator]. - testWidgetsWithLeakTracking('The slider can skip all of its component painting', (WidgetTester tester) async { + testWidgets('The slider can skip all of its component painting', (WidgetTester tester) async { // Pump a slider with all shapes skipped. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1511,7 +1509,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the track', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the track', (WidgetTester tester) async { // Pump a slider with just a track. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1532,7 +1530,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { // Pump a slider with just tick marks. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1556,7 +1554,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the thumb', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a thumb. @@ -1582,7 +1580,7 @@ void main() { } }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the overlay', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async { // Pump a slider with just an overlay. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1610,7 +1608,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1640,7 +1638,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1675,7 +1673,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1707,7 +1705,7 @@ void main() { }); - testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1757,7 +1755,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { + testWidgets('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { debugDisableShadows = true; final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -1803,7 +1801,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1837,7 +1835,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1873,7 +1871,7 @@ void main() { } }); - testWidgetsWithLeakTracking('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { + testWidgets('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( trackShape: const RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight( @@ -1900,7 +1898,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The mouse cursor is themeable', (WidgetTester tester) async { + testWidgets('The mouse cursor is themeable', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( mouseCursor: const MaterialStatePropertyAll(SystemMouseCursors.text), @@ -1915,7 +1913,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgetsWithLeakTracking('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { + testWidgets('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { double value = 0.0; Widget buildApp({ @@ -2022,7 +2020,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { + testWidgets('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -2235,7 +2233,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { + testWidgets('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index c3801a8fcbb4d..45880b19e66c1 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -560,6 +560,7 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); testWidgetsWithLeakTracking('SwitchListTile.adaptive onFocusChange Callback', (WidgetTester tester) async { @@ -589,6 +590,7 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); group('feedback', () { @@ -863,7 +865,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { + testWidgets('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF4caf50); const Color pressedThumbColor = Color(0xFFF44336); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index fa89e561f7fc6..d8b3c703455fb 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -701,6 +701,8 @@ void main() { expect(getSwitchMaterial(tester), paints..circle(color: theme.hoverColor) ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { @@ -746,6 +748,8 @@ void main() { expect(getSwitchMaterial(tester), paints..circle(color: theme.colorScheme.primary.withOpacity(0.08)) ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Switch can be set color', (WidgetTester tester) async { @@ -1238,6 +1242,8 @@ void main() { ..rrect(color: const Color(0x1f000000)) ..rrect(color: const Color(0xffbdbdbd)), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch is focusable and has correct focus color', (WidgetTester tester) async { @@ -1325,6 +1331,8 @@ void main() { ) ..rrect(color: Color.alphaBlend(colors.onSurface.withOpacity(0.38), colors.surface)), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch with splash radius set', (WidgetTester tester) async { @@ -1985,6 +1993,8 @@ void main() { ..rrect(color: hoveredThumbColor), reason: 'Inactive disabled switch should default track and custom thumb color', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { @@ -2061,6 +2071,8 @@ void main() { ..rrect(color: hoveredThumbColor), reason: 'active enabled switch should default track and custom thumb color', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Track color resolves in active/enabled states', (WidgetTester tester) async { @@ -2312,6 +2324,8 @@ void main() { ), reason: 'Inactive enabled switch should match these colors', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { @@ -2382,6 +2396,8 @@ void main() { ), reason: 'Active enabled switch should match these colors', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Switch thumb color is blended against surface color', (WidgetTester tester) async { @@ -2634,6 +2650,8 @@ void main() { ), reason: 'Hovered Switch should use overlay color $hoverOverlayColor over $hoverColor', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { @@ -3187,6 +3205,8 @@ void main() { ..rrect(color: hoveredTrackOutlineColor, style: PaintingStyle.stroke), reason: 'Active enabled switch track outline should match this color', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Track outline width resolves in active/enabled states', (WidgetTester tester) async { @@ -3322,6 +3342,8 @@ void main() { ..rrect(strokeWidth: hoveredTrackOutlineWidth, style: PaintingStyle.stroke), reason: 'Active enabled switch track outline width should be 4.0', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch can set icon - M3', (WidgetTester tester) async { @@ -3486,6 +3508,8 @@ void main() { ..rrect(color: const Color(0x0a000000)) ..rrect(color: const Color(0xffffffff)), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch.onFocusChange callback', (WidgetTester tester) async { @@ -3515,6 +3539,8 @@ void main() { await tester.pump(); expect(focused, isFalse); expect(focusNode.hasFocus, isFalse); + + focusNode.dispose(); }); } diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 1c3b757d2fa24..836a6592d2e5a 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -200,6 +200,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -267,6 +269,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -322,6 +326,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -389,6 +395,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton uses stateful color for icon color in different states', (WidgetTester tester) async { @@ -456,6 +464,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton has no clip by default', (WidgetTester tester) async { @@ -532,6 +542,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does TextButton contribute semantics', (WidgetTester tester) async { @@ -801,6 +813,8 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered TextButton responds to mouse-exit', (WidgetTester tester) async { @@ -892,6 +906,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('When TextButton disable, Can not set TextButton focus.', (WidgetTester tester) async { @@ -915,6 +931,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('TextButton responds to density changes.', (WidgetTester tester) async { @@ -1625,7 +1643,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1778,15 +1796,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('TextButton statesController', (WidgetTester tester) async { + testWidgets('TextButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('TextButton.icon statesController', (WidgetTester tester) async { + testWidgets('TextButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled TextButton statesController', (WidgetTester tester) async { + testWidgets('Disabled TextButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart index 21934175279ed..a5b4a06a421fd 100644 --- a/packages/flutter/test/material/text_field_helper_text_test.dart +++ b/packages/flutter/test/material/text_field_helper_text_test.dart @@ -5,10 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { - testWidgetsWithLeakTracking('TextField works correctly when changing helperText', (WidgetTester tester) async { + testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(1)); await tester.pump(const Duration(milliseconds: 100)); diff --git a/packages/flutter/test/material/text_field_splash_test.dart b/packages/flutter/test/material/text_field_splash_test.dart index ab26df41cbe0d..b16f0ced9b951 100644 --- a/packages/flutter/test/material/text_field_splash_test.dart +++ b/packages/flutter/test/material/text_field_splash_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/gestures.dart' show kPressTimeout; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - bool confirmCalled = false; bool cancelCalled = false; @@ -137,7 +135,7 @@ void main() { expect(cancelCalled, isFalse); }); - testWidgetsWithLeakTracking('Splash should never be created or canceled', (WidgetTester tester) async { + testWidgets('Splash should never be created or canceled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 36373fec387cf..80be8ea948091 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -249,10 +249,10 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. // TODO(polina-c): remove after fixing // https://github.com/flutter/flutter/issues/130467 - leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: {'ValueNotifier<_OverlayEntryWidgetState?>': 16}), + leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true, allowAllNotGCed: true), ); - testWidgetsWithLeakTracking('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { + testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); @@ -347,7 +347,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgetsWithLeakTracking('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { + testWidgets('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { bool asserted; try { TextFormField( @@ -360,7 +360,7 @@ void main() { expect(asserted, false); }); - testWidgetsWithLeakTracking('Passes textAlign to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes textAlign to underlying TextField', (WidgetTester tester) async { const TextAlign alignment = TextAlign.center; await tester.pumpWidget( @@ -382,7 +382,7 @@ void main() { expect(textFieldWidget.textAlign, alignment); }); - testWidgetsWithLeakTracking('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { const ScrollPhysics scrollPhysics = ScrollPhysics(); await tester.pumpWidget( @@ -404,7 +404,7 @@ void main() { expect(textFieldWidget.scrollPhysics, scrollPhysics); }); - testWidgetsWithLeakTracking('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { const TextAlignVertical textAlignVertical = TextAlignVertical.bottom; await tester.pumpWidget( @@ -426,7 +426,7 @@ void main() { expect(textFieldWidget.textAlignVertical, textAlignVertical); }); - testWidgetsWithLeakTracking('Passes textInputAction to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes textInputAction to underlying TextField', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -446,7 +446,7 @@ void main() { expect(textFieldWidget.textInputAction, TextInputAction.next); }); - testWidgetsWithLeakTracking('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { void onEditingComplete() { } await tester.pumpWidget( @@ -468,7 +468,7 @@ void main() { expect(textFieldWidget.onEditingComplete, onEditingComplete); }); - testWidgetsWithLeakTracking('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { const double cursorWidth = 3.14; const double cursorHeight = 6.28; const Radius cursorRadius = Radius.circular(4); @@ -520,7 +520,7 @@ void main() { expect(called, true); }); - testWidgetsWithLeakTracking('onChanged callbacks are called', (WidgetTester tester) async { + testWidgets('onChanged callbacks are called', (WidgetTester tester) async { late String value; await tester.pumpWidget( @@ -542,7 +542,7 @@ void main() { expect(value, 'Soup'); }); - testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -567,7 +567,7 @@ void main() { expect(validateCalled, 2); }); - testWidgetsWithLeakTracking('validate is called if widget is enabled', (WidgetTester tester) async { + testWidgets('validate is called if widget is enabled', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -594,7 +594,7 @@ void main() { }); - testWidgetsWithLeakTracking('Disabled field hides helper and counter in M2', (WidgetTester tester) async { + testWidgets('Disabled field hides helper and counter in M2', (WidgetTester tester) async { const String helperText = 'helper text'; const String counterText = 'counter text'; const String errorText = 'error text'; @@ -642,7 +642,7 @@ void main() { expect(errorWidget.style!.color, equals(Colors.transparent)); }); - testWidgetsWithLeakTracking('passing a buildCounter shows returned widget', (WidgetTester tester) async { + testWidgets('passing a buildCounter shows returned widget', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -707,7 +707,7 @@ void main() { expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); }, skip: isBrowser); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { + testWidgets('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( MaterialApp( @@ -734,7 +734,7 @@ void main() { expect(tapCount, 3); }); - testWidgetsWithLeakTracking('onTapOutside is called upon tap outside', (WidgetTester tester) async { + testWidgets('onTapOutside is called upon tap outside', (WidgetTester tester) async { int tapOutsideCount = 0; await tester.pumpWidget( MaterialApp( @@ -765,7 +765,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgetsWithLeakTracking('reset resets the text fields value to the initialValue', (WidgetTester tester) async { + testWidgets('reset resets the text fields value to the initialValue', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -788,7 +788,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgetsWithLeakTracking("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { + testWidgets("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -811,7 +811,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgetsWithLeakTracking("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { + testWidgets("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -834,7 +834,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgetsWithLeakTracking('didChange changes text fields value', (WidgetTester tester) async { + testWidgets('didChange changes text fields value', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -856,7 +856,7 @@ void main() { expect(find.text('changedValue'), findsOneWidget); }); - testWidgetsWithLeakTracking('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { + testWidgets('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { bool called = false; late FormFieldState state; @@ -883,7 +883,7 @@ void main() { expect(called, true); }); - testWidgetsWithLeakTracking('autofillHints is passed to super', (WidgetTester tester) async { + testWidgets('autofillHints is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -900,7 +900,7 @@ void main() { expect(widget.autofillHints, equals(const [AutofillHints.countryName])); }); - testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -925,7 +925,7 @@ void main() { expect(validateCalled, 1); }); - testWidgetsWithLeakTracking('textSelectionControls is passed to super', (WidgetTester tester) async { + testWidgets('textSelectionControls is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -942,7 +942,7 @@ void main() { expect(widget.selectionControls, equals(materialTextSelectionControls)); }); - testWidgetsWithLeakTracking('TextFormField respects hintTextDirection', (WidgetTester tester) async { + testWidgets('TextFormField respects hintTextDirection', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Directionality( @@ -984,7 +984,7 @@ void main() { expect(textDirection, TextDirection.rtl); }); - testWidgetsWithLeakTracking('Passes scrollController to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes scrollController to underlying TextField', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -1006,7 +1006,7 @@ void main() { expect(textFieldWidget.scrollController, scrollController); }); - testWidgetsWithLeakTracking('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1151,7 +1151,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgetsWithLeakTracking('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgets('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { final SpellCheckConfiguration mySpellCheckConfiguration = SpellCheckConfiguration( spellCheckService: DefaultSpellCheckService(), misspelledTextStyle: TextField.materialMisspelledTextStyle, @@ -1181,7 +1181,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgets('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { final TextMagnifierConfiguration myTextMagnifierConfiguration = TextMagnifierConfiguration( magnifierBuilder: (BuildContext context, MagnifierController controller, ValueNotifier notifier) { return const Placeholder(); @@ -1202,7 +1202,7 @@ void main() { expect(editableText.magnifierConfiguration, equals(myTextMagnifierConfiguration)); }); - testWidgetsWithLeakTracking('Passes undoController to undoController TextField', (WidgetTester tester) async { + testWidgets('Passes undoController to undoController TextField', (WidgetTester tester) async { final UndoHistoryController undoController = UndoHistoryController(value: UndoHistoryValue.empty); await tester.pumpWidget( @@ -1224,7 +1224,7 @@ void main() { expect(textFieldWidget.undoController, undoController); }); - testWidgetsWithLeakTracking('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { + testWidgets('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { const bool cursorOpacityAnimates = true; await tester.pumpWidget( @@ -1246,7 +1246,7 @@ void main() { expect(textFieldWidget.cursorOpacityAnimates, cursorOpacityAnimates); }); - testWidgetsWithLeakTracking('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { + testWidgets('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { final ContentInsertionConfiguration contentInsertionConfiguration = ContentInsertionConfiguration(onContentInserted: (KeyboardInsertedContent value) {}); @@ -1269,7 +1269,7 @@ void main() { expect(textFieldWidget.contentInsertionConfiguration, contentInsertionConfiguration); }); - testWidgetsWithLeakTracking('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { + testWidgets('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { const Clip clipBehavior = Clip.antiAlias; await tester.pumpWidget( @@ -1291,7 +1291,7 @@ void main() { expect(textFieldWidget.clipBehavior, clipBehavior); }); - testWidgetsWithLeakTracking('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { + testWidgets('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { const bool scribbleEnabled = false; await tester.pumpWidget( @@ -1313,7 +1313,7 @@ void main() { expect(textFieldWidget.scribbleEnabled, scribbleEnabled); }); - testWidgetsWithLeakTracking('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { + testWidgets('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { const bool canRequestFocus = false; await tester.pumpWidget( @@ -1335,7 +1335,7 @@ void main() { expect(textFieldWidget.canRequestFocus, canRequestFocus); }); - testWidgetsWithLeakTracking('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { + testWidgets('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { void onAppPrivateCommand(String p0, Map p1) {} await tester.pumpWidget( @@ -1357,7 +1357,7 @@ void main() { expect(textFieldWidget.onAppPrivateCommand, onAppPrivateCommand); }); - testWidgetsWithLeakTracking('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { + testWidgets('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { const BoxHeightStyle selectionHeightStyle = BoxHeightStyle.max; await tester.pumpWidget( @@ -1379,7 +1379,7 @@ void main() { expect(textFieldWidget.selectionHeightStyle, selectionHeightStyle); }); - testWidgetsWithLeakTracking('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { + testWidgets('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { const BoxWidthStyle selectionWidthStyle = BoxWidthStyle.max; await tester.pumpWidget( @@ -1401,7 +1401,7 @@ void main() { expect(textFieldWidget.selectionWidthStyle, selectionWidthStyle); }); - testWidgetsWithLeakTracking('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { + testWidgets('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { const DragStartBehavior dragStartBehavior = DragStartBehavior.down; await tester.pumpWidget( @@ -1423,7 +1423,7 @@ void main() { expect(textFieldWidget.dragStartBehavior, dragStartBehavior); }); - testWidgetsWithLeakTracking('Error color for cursor while validating', (WidgetTester tester) async { + testWidgets('Error color for cursor while validating', (WidgetTester tester) async { const Color errorColor = Color(0xff123456); await tester.pumpWidget(MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 1e7ba83ced5b5..07d565b9316f8 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -113,7 +113,8 @@ void main() { notDisposedAllowList: { 'ValueNotifier': 1, 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 1, + 'ValueNotifier': 2, + '_InputBorderGap': 1, }, // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. allowAllNotGCed: true, @@ -173,7 +174,8 @@ void main() { notDisposedAllowList: { 'ValueNotifier': 1, 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 1, + 'ValueNotifier': 2, + '_InputBorderGap': 1, }, // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. allowAllNotGCed: true, diff --git a/packages/flutter/test/material/text_selection_toolbar_test.dart b/packages/flutter/test/material/text_selection_toolbar_test.dart index f37714db21c24..41ecd8c878c4c 100644 --- a/packages/flutter/test/material/text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_test.dart @@ -173,7 +173,7 @@ void main() { expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); }); - testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { + testWidgets('can create and use a custom toolbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index 7c6d42c2fa396..517fecd6b1544 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -62,7 +62,7 @@ void main() { expect(() => RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)).value, throwsAssertionError); }); - testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { + testWidgets('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); final _RestorableWidgetState state = tester.state(find.byType(_RestorableWidget)); @@ -107,7 +107,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 2, minute: 2)); }); - testWidgetsWithLeakTracking('restore to older state', (WidgetTester tester) async { + testWidgets('restore to older state', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -138,7 +138,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 10, minute: 5)); }); - testWidgetsWithLeakTracking('call notifiers when value changes', (WidgetTester tester) async { + testWidgets('call notifiers when value changes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index a14363033b86e..7a03deee05bba 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -817,6 +817,8 @@ void main() { expect(inkFeatures, paints..rect(color: theme.colorScheme.onSurface.withOpacity(0.12))); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Default InkWell colors - selected', (WidgetTester tester) async { @@ -882,6 +884,8 @@ void main() { expect(inkFeatures, paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Custom InkWell colors', (WidgetTester tester) async { @@ -951,6 +955,8 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking( @@ -1863,6 +1869,10 @@ void main() { expect(toggleButtonElevation('two'), 0); await hoverGesture.removePointer(); + + for (final FocusNode n in focusNodes) { + n.dispose(); + } }); testWidgetsWithLeakTracking('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index 7b67cbe901edc..dfd7df499a7f6 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -512,6 +512,8 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking( diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 8b68be4cbdf5f..9d9bd888476aa 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -25,7 +25,7 @@ Finder _findTooltipContainer(String tooltipText) { } void main() { - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -79,7 +79,7 @@ void main() { expect(tipInGlobal.dy, 20.0); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -138,7 +138,7 @@ void main() { expect(tipInGlobal.dy, 40.0); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - top left', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -192,7 +192,7 @@ void main() { expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0))); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -245,7 +245,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -309,7 +309,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -361,7 +361,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -418,7 +418,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -475,7 +475,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgetsWithLeakTracking('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { + testWidgets('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23666 Widget materialAppWithViewInsets(double viewInsetsHeight) { final Widget scaffold = Scaffold( @@ -530,7 +530,7 @@ void main() { expect(tooltipTopRight.dy, lessThan(fabTopRight.dy)); }); - testWidgetsWithLeakTracking('Custom tooltip margin', (WidgetTester tester) async { + testWidgets('Custom tooltip margin', (WidgetTester tester) async { const double customMarginValue = 10.0; final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( @@ -767,7 +767,7 @@ void main() { expect(textStyle.decorationStyle, isNot(TextDecorationStyle.double)); }); - testWidgetsWithLeakTracking('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { + testWidgets('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -835,7 +835,7 @@ void main() { expect(tooltipContainer.padding, const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0)); }, variant: const TargetPlatformVariant({TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows})); - testWidgetsWithLeakTracking('Can tooltip decoration be customized', (WidgetTester tester) async { + testWidgets('Can tooltip decoration be customized', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -1393,7 +1393,7 @@ void main() { await tester.pump(waitDuration); }); - testWidgetsWithLeakTracking('Does tooltip contribute semantics', (WidgetTester tester) async { + testWidgets('Does tooltip contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey tooltipKey = GlobalKey(); diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index 75d623b1f0ed5..b0352255e1159 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -113,7 +113,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -170,7 +170,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -225,7 +225,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -293,7 +293,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -359,7 +359,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -415,7 +415,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -469,7 +469,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgetsWithLeakTracking('Tooltip margin - ThemeData', (WidgetTester tester) async { + testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -524,7 +524,7 @@ void main() { expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); }); - testWidgetsWithLeakTracking('Tooltip margin - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -675,7 +675,7 @@ void main() { expect(textAlign, TextAlign.end); }); - testWidgetsWithLeakTracking('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -717,7 +717,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgetsWithLeakTracking('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -757,7 +757,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgetsWithLeakTracking('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingVal = 20.0; @@ -804,7 +804,7 @@ void main() { expect(content.size.width, equals(tip.size.width - 2 * customPaddingVal)); }); - testWidgetsWithLeakTracking('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingValue = 20.0; diff --git a/packages/flutter/test/material/value_indicating_slider_test.dart b/packages/flutter/test/material/value_indicating_slider_test.dart index fb8029b935ab7..070d362515ee2 100644 --- a/packages/flutter/test/material/value_indicating_slider_test.dart +++ b/packages/flutter/test/material/value_indicating_slider_test.dart @@ -10,10 +10,9 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; void main() { - testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { + testWidgets('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -54,7 +53,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { + testWidgets('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -98,7 +97,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator large text scale', (WidgetTester tester) async { + testWidgets('Slider value indicator large text scale', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -142,7 +141,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator large text scale and wide text', + testWidgets('Slider value indicator large text scale and wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, @@ -195,7 +194,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { + testWidgets('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -233,7 +232,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { + testWidgets('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -274,7 +273,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator large text scale', (WidgetTester tester) async { + testWidgets('Slider value indicator large text scale', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -315,7 +314,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator large text scale and wide text', + testWidgets('Slider value indicator large text scale and wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index e51fc3f4fd7f9..47aa1b7bb207c 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -41,13 +41,12 @@ dev_dependencies: fake_async: 1.3.1 test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +72,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d729 +# PUBSPEC CHECKSUM: c36c diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 4fa470fb15965..4fbfb2c97a5c2 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -60,15 +60,14 @@ dependencies: standard_message_codec: 0.0.1+3 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_value: 8.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dds_service_extensions: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" devtools_shared: 2.26.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -108,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 6b41 +# PUBSPEC CHECKSUM: 2e84 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 1b9eec759ca1d..b6bae54575431 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -18,8 +18,8 @@ dependencies: dev_dependencies: test: 1.24.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,7 +27,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +63,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: f314 +# PUBSPEC CHECKSUM: 4157 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index aff039587fdef..eb3571d200a22 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -34,8 +34,8 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,7 +43,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +84,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 5290 +# PUBSPEC CHECKSUM: 8fd3 From 3886b0039c26fa20c294c688a7dc546849b70206 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 12:53:24 -0400 Subject: [PATCH 0587/1547] Roll Packages from d7ee75ad59ad to ac4137624a13 (8 revisions) (#132133) https://github.com/flutter/packages/compare/d7ee75ad59ad...ac4137624a13 2023-08-08 engine-flutter-autoroll@skia.org Roll Flutter from ad0aa8de7512 to 436df69a4684 (17 revisions) (flutter/packages#4663) 2023-08-08 10687576+bparrishMines@users.noreply.github.com [webview_flutter_wkwebview] Repeatedly pump WebViews until one is garbage collected (flutter/packages#4662) 2023-08-08 erikgerman917@gmail.com [xdg_directories] Add example app (flutter/packages#4554) 2023-08-08 70025277+Nitin-Poojary@users.noreply.github.com [pigeon] Recursively create output target files (flutter/packages#4458) 2023-08-07 jpnurmi@gmail.com [path_provider] Add getApplicationCachePath() (flutter/packages#4483) 2023-08-07 10687576+bparrishMines@users.noreply.github.com [flutter_markdown] Adopt code excerpts in README (flutter/packages#4656) 2023-08-07 reidbaker@google.com [All] Expand artifact hub to all plugins (flutter/packages#4645) 2023-08-07 engine-flutter-autoroll@skia.org Roll Flutter from 2ba9f7bdfe16 to ad0aa8de7512 (31 revisions) (flutter/packages#4659) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 71499212697b0..fb5f2301718fe 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -d7ee75ad59ad7bc45e659d0599e935e9e7981ea1 +ac4137624a13c87f20781795b9a56891cdadff11 From 23041cb2bb20cb12c9cd8a9f6b44f513d604829a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 13:09:18 -0400 Subject: [PATCH 0588/1547] Roll Flutter Engine from 146c4c9487fc to 99fdac88f3c6 (3 revisions) (#132135) https://github.com/flutter/engine/compare/146c4c9487fc...99fdac88f3c6 2023-08-08 zanderso@users.noreply.github.com Excludes entity_pass.cc from clang-tidy due to timeouts (flutter/engine#44495) 2023-08-08 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 0Jd9VPJCX145RGnqr... to 9Pl8nd13UI8rrS3JD... (flutter/engine#44494) 2023-08-08 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from r0vBgWqKSvQ6zzFam... to c18Y3Ga7cvdrmy8FQ... (flutter/engine#44492) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 0Jd9VPJCX145 to 9Pl8nd13UI8r fuchsia/sdk/core/mac-amd64 from r0vBgWqKSvQ6 to c18Y3Ga7cvdr If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b8de52efaaf27..0e0fe234270c8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -146c4c9487fc68ff97dbf900bf3c760c60ed251a +99fdac88f3c620f56acb46b898760c53e702beae diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 7d661b23979cd..471bfbfd9ac9c 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -0Jd9VPJCX145RGnqrZ-yxgc9-QoGboEeDDGf8cbwiyMC +9Pl8nd13UI8rrS3JDriZPjP71hxAFS9t3dU3klvDmKMC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 1afeb0edd76e8..697b6664f2adc 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -r0vBgWqKSvQ6zzFamHmmAbL3yPAgG5OsLM-AlH87TUUC +c18Y3Ga7cvdrmy8FQG_Pie4boO7nSoI8zSUksOjUaWEC From 9dbd1e9872cce50ea4974c94920e59998761ebe6 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 8 Aug 2023 10:11:15 -0700 Subject: [PATCH 0589/1547] More documentation about warm-up frames (#132085) --- .../flutter/lib/src/scheduler/binding.dart | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 73b0971eb9622..2035b84927a11 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -933,6 +933,30 @@ mixin SchedulerBinding on BindingBase { /// [scheduleWarmUpFrame] was already called, this call will be ignored. /// /// Prefer [scheduleFrame] to update the display in normal operation. + /// + /// ## Design discussion + /// + /// The Flutter engine prompts the framework to generate frames when it + /// receives a request from the operating system (known for historical reasons + /// as a vsync). However, this may not happen for several milliseconds after + /// the app starts (or after a hot reload). To make use of the time between + /// when the widget tree is first configured and when the engine requests an + /// update, the framework schedules a _warm-up frame_. + /// + /// A warm-up frame may never actually render (as the engine did not request + /// it and therefore does not have a valid context in which to paint), but it + /// will cause the framework to go through the steps of building, laying out, + /// and painting, which can together take several milliseconds. Thus, when the + /// engine requests a real frame, much of the work will already have been + /// completed, and the framework can generate the frame with minimal + /// additional effort. + /// + /// Warm-up frames are scheduled by [runApp] on startup, and by + /// [RendererBinding.performReassemble] during a hot reload. + /// + /// Warm-up frames are also scheduled when the framework is unblocked by a + /// call to [RendererBinding.allowFirstFrame] (corresponding to a call to + /// [RendererBinding.deferFirstFrame] that blocked the rendering). void scheduleWarmUpFrame() { if (_warmUpFrame || schedulerPhase != SchedulerPhase.idle) { return; From e60dc3012e4c37bcc079c481b32f7d0327f1d2c1 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 8 Aug 2023 10:12:52 -0700 Subject: [PATCH 0590/1547] Update dartdoc driver to match current behaviour (#132078) --- dev/tools/dartdoc.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart index b60c96133cf92..8bd8b39d73ac2 100644 --- a/dev/tools/dartdoc.dart +++ b/dev/tools/dartdoc.dart @@ -116,7 +116,7 @@ Future main(List arguments) async { final List dartdocBaseArgs = [ 'global', 'run', - if (args['checked'] as bool) '-c', + if (args['checked'] as bool) '--enable-asserts', 'dartdoc', ]; @@ -229,8 +229,7 @@ Future main(List arguments) async { )); printStream(process.stdout, prefix: args['json'] as bool ? '' : 'dartdoc:stdout: ', filter: args['verbose'] as bool ? const [] : [ - RegExp(r'^generating docs for library '), // unnecessary verbosity - RegExp(r'^pars'), // unnecessary verbosity + RegExp(r'^Generating docs for library '), // unnecessary verbosity ], ); printStream(process.stderr, prefix: args['json'] as bool ? '' : 'dartdoc:stderr: ', @@ -259,7 +258,7 @@ ArgParser _createArgsParser() { 'filter out some known false positives (off). Shut this off ' 'locally if you want to address Flutter-specific issues.'); parser.addFlag('checked', abbr: 'c', - help: 'Run dartdoc in checked mode.'); + help: 'Run dartdoc with asserts enabled.'); parser.addFlag('json', help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); parser.addFlag('validate-links', From 9655311545d3fbec7cf3236f17594ac9f528fdf5 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Tue, 8 Aug 2023 10:25:27 -0700 Subject: [PATCH 0591/1547] Remove Iterator from _History (#132101) Cleaning up private code in Navigator. --- packages/flutter/lib/src/widgets/navigator.dart | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index f366dfb2aee0f..9a5485368b316 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -3354,7 +3354,7 @@ typedef _IndexWhereCallback = bool Function(_RouteEntry element); /// /// Acts as a ChangeNotifier and notifies after its List of _RouteEntries is /// mutated. -class _History extends Iterable<_RouteEntry> with ChangeNotifier implements Iterator<_RouteEntry> { +class _History extends Iterable<_RouteEntry> with ChangeNotifier { final List<_RouteEntry> _value = <_RouteEntry>[]; int indexWhere(_IndexWhereCallback test, [int start = 0]) { @@ -3398,10 +3398,6 @@ class _History extends Iterable<_RouteEntry> with ChangeNotifier implements Iter return entry; } - // Begin Iterator. - - int _i = 0; - _RouteEntry operator [](int index) { return _value[index]; } @@ -3411,17 +3407,6 @@ class _History extends Iterable<_RouteEntry> with ChangeNotifier implements Iter return _value.iterator; } - @override - _RouteEntry get current => _value[_i]; - - @override - bool moveNext() { - _i++; - return _i <= _value.length - 1; - } - - // End Iterator. - @override String toString() { return _value.toString(); From d9cb50e63de79aa71caa97ecb50f8d06596b3aa0 Mon Sep 17 00:00:00 2001 From: LouiseHsu Date: Tue, 8 Aug 2023 10:34:17 -0700 Subject: [PATCH 0592/1547] [framework] Add Search Web to selection controls for iOS (#131898) This PR adds framework support for the Search Web feature in iOS. https://github.com/flutter/flutter/assets/36148254/c159f0d9-8f14-45e7-b295-e065b0826fab The corresponding merged engine PR can be found [here](https://github.com/flutter/engine/pull/43324). This PR addresses https://github.com/flutter/flutter/issues/82907 More details are available in this [design doc](https://docs.google.com/document/d/1QizXwBiO-2REIcEovl5pK06BaLPOWYmNwOE5jactJZA/edit?resourcekey=0-1pb9mJiAq29Gesmt25GAug) --- .../adaptive_text_selection_toolbar.dart | 2 + .../lib/src/cupertino/localizations.dart | 7 + .../text_selection_toolbar_button.dart | 3 + .../adaptive_text_selection_toolbar.dart | 4 + .../src/material/material_localizations.dart | 6 + .../flutter/lib/src/services/text_input.dart | 3 + .../src/widgets/context_menu_button_item.dart | 3 + .../lib/src/widgets/editable_text.dart | 44 +++- .../adaptive_text_selection_toolbar_test.dart | 14 +- .../test/cupertino/text_field_test.dart | 128 ++++++++-- .../test/cupertino/text_selection_test.dart | 104 +++++--- .../text_selection_toolbar_test.dart | 17 +- .../adaptive_text_selection_toolbar_test.dart | 20 +- .../test/material/localizations_test.dart | 1 + .../test/material/text_field_test.dart | 38 +-- .../test/widgets/editable_text_test.dart | 1 + .../test/widgets/selectable_text_test.dart | 22 +- .../lib/src/l10n/cupertino_af.arb | 3 +- .../lib/src/l10n/cupertino_am.arb | 3 +- .../lib/src/l10n/cupertino_ar.arb | 3 +- .../lib/src/l10n/cupertino_as.arb | 3 +- .../lib/src/l10n/cupertino_az.arb | 3 +- .../lib/src/l10n/cupertino_be.arb | 3 +- .../lib/src/l10n/cupertino_bg.arb | 3 +- .../lib/src/l10n/cupertino_bn.arb | 3 +- .../lib/src/l10n/cupertino_bs.arb | 3 +- .../lib/src/l10n/cupertino_ca.arb | 3 +- .../lib/src/l10n/cupertino_cs.arb | 3 +- .../lib/src/l10n/cupertino_cy.arb | 3 +- .../lib/src/l10n/cupertino_da.arb | 3 +- .../lib/src/l10n/cupertino_de.arb | 3 +- .../lib/src/l10n/cupertino_el.arb | 3 +- .../lib/src/l10n/cupertino_en.arb | 5 + .../lib/src/l10n/cupertino_es.arb | 3 +- .../lib/src/l10n/cupertino_et.arb | 3 +- .../lib/src/l10n/cupertino_eu.arb | 3 +- .../lib/src/l10n/cupertino_fa.arb | 3 +- .../lib/src/l10n/cupertino_fi.arb | 3 +- .../lib/src/l10n/cupertino_fil.arb | 3 +- .../lib/src/l10n/cupertino_fr.arb | 3 +- .../lib/src/l10n/cupertino_gl.arb | 3 +- .../lib/src/l10n/cupertino_gsw.arb | 3 +- .../lib/src/l10n/cupertino_gu.arb | 3 +- .../lib/src/l10n/cupertino_he.arb | 3 +- .../lib/src/l10n/cupertino_hi.arb | 3 +- .../lib/src/l10n/cupertino_hr.arb | 3 +- .../lib/src/l10n/cupertino_hu.arb | 3 +- .../lib/src/l10n/cupertino_hy.arb | 3 +- .../lib/src/l10n/cupertino_id.arb | 3 +- .../lib/src/l10n/cupertino_is.arb | 3 +- .../lib/src/l10n/cupertino_it.arb | 3 +- .../lib/src/l10n/cupertino_ja.arb | 3 +- .../lib/src/l10n/cupertino_ka.arb | 3 +- .../lib/src/l10n/cupertino_kk.arb | 3 +- .../lib/src/l10n/cupertino_km.arb | 3 +- .../lib/src/l10n/cupertino_kn.arb | 3 +- .../lib/src/l10n/cupertino_ko.arb | 3 +- .../lib/src/l10n/cupertino_ky.arb | 3 +- .../lib/src/l10n/cupertino_lo.arb | 3 +- .../lib/src/l10n/cupertino_lt.arb | 3 +- .../lib/src/l10n/cupertino_lv.arb | 3 +- .../lib/src/l10n/cupertino_mk.arb | 3 +- .../lib/src/l10n/cupertino_ml.arb | 3 +- .../lib/src/l10n/cupertino_mn.arb | 3 +- .../lib/src/l10n/cupertino_mr.arb | 3 +- .../lib/src/l10n/cupertino_ms.arb | 3 +- .../lib/src/l10n/cupertino_my.arb | 3 +- .../lib/src/l10n/cupertino_nb.arb | 3 +- .../lib/src/l10n/cupertino_ne.arb | 3 +- .../lib/src/l10n/cupertino_nl.arb | 3 +- .../lib/src/l10n/cupertino_no.arb | 3 +- .../lib/src/l10n/cupertino_or.arb | 3 +- .../lib/src/l10n/cupertino_pa.arb | 3 +- .../lib/src/l10n/cupertino_pl.arb | 3 +- .../lib/src/l10n/cupertino_pt.arb | 3 +- .../lib/src/l10n/cupertino_ro.arb | 3 +- .../lib/src/l10n/cupertino_ru.arb | 3 +- .../lib/src/l10n/cupertino_si.arb | 3 +- .../lib/src/l10n/cupertino_sk.arb | 3 +- .../lib/src/l10n/cupertino_sl.arb | 3 +- .../lib/src/l10n/cupertino_sq.arb | 3 +- .../lib/src/l10n/cupertino_sr.arb | 3 +- .../lib/src/l10n/cupertino_sv.arb | 3 +- .../lib/src/l10n/cupertino_sw.arb | 3 +- .../lib/src/l10n/cupertino_ta.arb | 3 +- .../lib/src/l10n/cupertino_te.arb | 3 +- .../lib/src/l10n/cupertino_th.arb | 3 +- .../lib/src/l10n/cupertino_tl.arb | 3 +- .../lib/src/l10n/cupertino_tr.arb | 3 +- .../lib/src/l10n/cupertino_uk.arb | 3 +- .../lib/src/l10n/cupertino_ur.arb | 3 +- .../lib/src/l10n/cupertino_uz.arb | 3 +- .../lib/src/l10n/cupertino_vi.arb | 3 +- .../lib/src/l10n/cupertino_zh.arb | 3 +- .../lib/src/l10n/cupertino_zu.arb | 3 +- .../generated_cupertino_localizations.dart | 234 +++++++++++++++++ .../generated_material_localizations.dart | 237 ++++++++++++++++++ .../lib/src/l10n/material_af.arb | 3 +- .../lib/src/l10n/material_am.arb | 3 +- .../lib/src/l10n/material_ar.arb | 3 +- .../lib/src/l10n/material_as.arb | 3 +- .../lib/src/l10n/material_az.arb | 3 +- .../lib/src/l10n/material_be.arb | 3 +- .../lib/src/l10n/material_bg.arb | 3 +- .../lib/src/l10n/material_bn.arb | 3 +- .../lib/src/l10n/material_bs.arb | 3 +- .../lib/src/l10n/material_ca.arb | 3 +- .../lib/src/l10n/material_cs.arb | 3 +- .../lib/src/l10n/material_cy.arb | 3 +- .../lib/src/l10n/material_da.arb | 3 +- .../lib/src/l10n/material_de.arb | 3 +- .../lib/src/l10n/material_el.arb | 3 +- .../lib/src/l10n/material_en.arb | 5 + .../lib/src/l10n/material_es.arb | 3 +- .../lib/src/l10n/material_et.arb | 3 +- .../lib/src/l10n/material_eu.arb | 3 +- .../lib/src/l10n/material_fa.arb | 3 +- .../lib/src/l10n/material_fi.arb | 3 +- .../lib/src/l10n/material_fil.arb | 3 +- .../lib/src/l10n/material_fr.arb | 3 +- .../lib/src/l10n/material_gl.arb | 3 +- .../lib/src/l10n/material_gsw.arb | 3 +- .../lib/src/l10n/material_gu.arb | 3 +- .../lib/src/l10n/material_he.arb | 3 +- .../lib/src/l10n/material_hi.arb | 3 +- .../lib/src/l10n/material_hr.arb | 3 +- .../lib/src/l10n/material_hu.arb | 3 +- .../lib/src/l10n/material_hy.arb | 3 +- .../lib/src/l10n/material_id.arb | 3 +- .../lib/src/l10n/material_is.arb | 3 +- .../lib/src/l10n/material_it.arb | 3 +- .../lib/src/l10n/material_ja.arb | 3 +- .../lib/src/l10n/material_ka.arb | 3 +- .../lib/src/l10n/material_kk.arb | 3 +- .../lib/src/l10n/material_km.arb | 3 +- .../lib/src/l10n/material_kn.arb | 3 +- .../lib/src/l10n/material_ko.arb | 3 +- .../lib/src/l10n/material_ky.arb | 3 +- .../lib/src/l10n/material_lo.arb | 3 +- .../lib/src/l10n/material_lt.arb | 3 +- .../lib/src/l10n/material_lv.arb | 3 +- .../lib/src/l10n/material_mk.arb | 3 +- .../lib/src/l10n/material_ml.arb | 3 +- .../lib/src/l10n/material_mn.arb | 3 +- .../lib/src/l10n/material_mr.arb | 3 +- .../lib/src/l10n/material_ms.arb | 3 +- .../lib/src/l10n/material_my.arb | 3 +- .../lib/src/l10n/material_nb.arb | 3 +- .../lib/src/l10n/material_ne.arb | 3 +- .../lib/src/l10n/material_nl.arb | 3 +- .../lib/src/l10n/material_no.arb | 3 +- .../lib/src/l10n/material_or.arb | 3 +- .../lib/src/l10n/material_pa.arb | 3 +- .../lib/src/l10n/material_pl.arb | 3 +- .../lib/src/l10n/material_ps.arb | 3 +- .../lib/src/l10n/material_pt.arb | 3 +- .../lib/src/l10n/material_ro.arb | 3 +- .../lib/src/l10n/material_ru.arb | 3 +- .../lib/src/l10n/material_si.arb | 3 +- .../lib/src/l10n/material_sk.arb | 3 +- .../lib/src/l10n/material_sl.arb | 3 +- .../lib/src/l10n/material_sq.arb | 3 +- .../lib/src/l10n/material_sr.arb | 3 +- .../lib/src/l10n/material_sv.arb | 3 +- .../lib/src/l10n/material_sw.arb | 3 +- .../lib/src/l10n/material_ta.arb | 3 +- .../lib/src/l10n/material_te.arb | 3 +- .../lib/src/l10n/material_th.arb | 3 +- .../lib/src/l10n/material_tl.arb | 3 +- .../lib/src/l10n/material_tr.arb | 3 +- .../lib/src/l10n/material_uk.arb | 3 +- .../lib/src/l10n/material_ur.arb | 3 +- .../lib/src/l10n/material_uz.arb | 3 +- .../lib/src/l10n/material_vi.arb | 3 +- .../lib/src/l10n/material_zh.arb | 3 +- .../lib/src/l10n/material_zu.arb | 3 +- 176 files changed, 1122 insertions(+), 241 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart b/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart index 37dc76e042c5a..3db3f35f2e03e 100644 --- a/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart +++ b/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart @@ -95,6 +95,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback? onPaste, required VoidCallback? onSelectAll, required VoidCallback? onLookUp, + required VoidCallback? onSearchWeb, required VoidCallback? onLiveTextInput, required this.anchors, }) : children = null, @@ -105,6 +106,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { onPaste: onPaste, onSelectAll: onSelectAll, onLookUp: onLookUp, + onSearchWeb: onSearchWeb, onLiveTextInput: onLiveTextInput ); diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index 2109b13de71cd..ca00238129544 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -249,6 +249,10 @@ abstract class CupertinoLocalizations { // The global version uses the translated string from the arb file. String get lookUpButtonLabel; + /// The term used for launching a web search on a selection. + // The global version uses the translated string from the arb file. + String get searchWebButtonLabel; + /// The default placeholder used in [CupertinoSearchTextField]. // The global version uses the translated string from the arb file. String get searchTextFieldPlaceholderLabel; @@ -462,6 +466,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { @override String get lookUpButtonLabel => 'Look Up'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get searchTextFieldPlaceholderLabel => 'Search'; diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart index 74f9b60f43998..93ffd737e1296 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart @@ -107,6 +107,8 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget { return localizations.selectAllButtonLabel; case ContextMenuButtonType.lookUp: return localizations.lookUpButtonLabel; + case ContextMenuButtonType.searchWeb: + return localizations.searchWebButtonLabel; case ContextMenuButtonType.liveTextInput: case ContextMenuButtonType.delete: case ContextMenuButtonType.custom: @@ -192,6 +194,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State 'Look Up'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get viewLicensesButtonLabel => 'View licenses'; diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 2ab806d391365..cad6abd56dd72 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1053,6 +1053,9 @@ mixin TextSelectionDelegate { /// Whether look up is enabled, must not be null. bool get lookUpEnabled => true; + /// Whether search web is enabled, must not be null. + bool get searchWebEnabled => true; + /// Whether Live Text input is enabled. /// /// See also: diff --git a/packages/flutter/lib/src/widgets/context_menu_button_item.dart b/packages/flutter/lib/src/widgets/context_menu_button_item.dart index 1a214be5c0455..9c2bf132e3154 100644 --- a/packages/flutter/lib/src/widgets/context_menu_button_item.dart +++ b/packages/flutter/lib/src/widgets/context_menu_button_item.dart @@ -29,6 +29,9 @@ enum ContextMenuButtonType { /// A button that looks up the current text selection. lookUp, + /// A button that launches a web search for the current text selection. + searchWeb, + /// A button for starting Live Text input. /// /// See also: diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 7f5e7c0c7cc34..f371290e7508d 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1853,6 +1853,7 @@ class EditableText extends StatefulWidget { required final VoidCallback? onPaste, required final VoidCallback? onSelectAll, required final VoidCallback? onLookUp, + required final VoidCallback? onSearchWeb, required final VoidCallback? onLiveTextInput, }) { final List resultButtonItem = []; @@ -1888,6 +1889,11 @@ class EditableText extends StatefulWidget { onPressed: onLookUp, type: ContextMenuButtonType.lookUp, ), + if (onSearchWeb != null) + ContextMenuButtonItem( + onPressed: onSearchWeb, + type: ContextMenuButtonType.searchWeb, + ), ]); } @@ -2244,7 +2250,19 @@ class EditableTextState extends State with AutomaticKeepAliveClien return false; } return !widget.obscureText - && !textEditingValue.selection.isCollapsed; + && !textEditingValue.selection.isCollapsed + && textEditingValue.selection.textInside(textEditingValue.text).trim() != ''; + } + + @override + bool get searchWebEnabled { + if (defaultTargetPlatform != TargetPlatform.iOS) { + return false; + } + + return !widget.obscureText + && !textEditingValue.selection.isCollapsed + && textEditingValue.selection.textInside(textEditingValue.text).trim() != ''; } @override @@ -2428,6 +2446,27 @@ class EditableTextState extends State with AutomaticKeepAliveClien ); } + /// Launch a web search on the current selection, + /// as in the "Search Web" edit menu button on iOS. + /// + /// Currently this is only implemented for iOS. + /// When 'obscureText' is true or the selection is empty, + /// this function will not do anything + Future searchWebForSelection(SelectionChangedCause cause) async { + assert(!widget.obscureText); + if (widget.obscureText) { + return; + } + + final String text = textEditingValue.selection.textInside(textEditingValue.text); + if (text.isNotEmpty) { + await SystemChannels.platform.invokeMethod( + 'SearchWeb.invoke', + text, + ); + } + } + void _startLiveTextInput(SelectionChangedCause cause) { if (!liveTextInputEnabled) { return; @@ -2657,6 +2696,9 @@ class EditableTextState extends State with AutomaticKeepAliveClien onLookUp: lookUpEnabled ? () => lookUpSelection(SelectionChangedCause.toolbar) : null, + onSearchWeb: searchWebEnabled + ? () => searchWebForSelection(SelectionChangedCause.toolbar) + : null, onLiveTextInput: liveTextInputEnabled ? () => _startLiveTextInput(SelectionChangedCause.toolbar) : null, diff --git a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart index 93f2e93cff941..83c535c461472 100644 --- a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart @@ -30,6 +30,13 @@ void main() { ); }); + Finder findOverflowNextButton() { + return find.byWidgetPredicate((Widget widget) => + widget is CustomPaint && + '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter', + ); + } + testWidgets('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async { const String buttonText = 'Click me'; @@ -169,6 +176,7 @@ void main() { onSelectAll: () {}, onLiveTextInput: () {}, onLookUp: () {}, + onSearchWeb: () {}, ), ), )); @@ -178,6 +186,7 @@ void main() { expect(find.text('Cut'), findsOneWidget); expect(find.text('Select All'), findsOneWidget); expect(find.text('Paste'), findsOneWidget); + expect(find.text('Look Up'), findsOneWidget); switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -186,11 +195,14 @@ void main() { expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); case TargetPlatform.iOS: expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); + expect(findOverflowNextButton(), findsOneWidget); + await tester.tapAt(tester.getCenter(findOverflowNextButton())); + await tester.pumpAndSettle(); expect(findLiveTextButton(), findsOneWidget); case TargetPlatform.macOS: case TargetPlatform.linux: case TargetPlatform.windows: - expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(6)); + expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(7)); } }, skip: kIsWeb, // [intended] on web the browser handles the context menu. diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index c7d9c8135b6b0..2bc31a4dabeee 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -348,6 +348,104 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); + testWidgets('Search Web shows up on iOS only (CupertinoTextField)', (WidgetTester tester) async { + String? lastLookUp; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SearchWeb.invoke') { + expect(methodCall.arguments, isA()); + lastLookUp = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test', + ); + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Search Web'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Search Web')); + expect(lastLookUp, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + + testWidgets('Search Web shows up on iOS only (TextField)', (WidgetTester tester) async { + String? lastLookUp; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SearchWeb.invoke') { + expect(methodCall.arguments, isA()); + lastLookUp = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test ', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Search Web'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Search Web')); + expect(lastLookUp, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + testWidgets('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', @@ -2111,8 +2209,8 @@ void main() { const TextSelection(baseOffset: 24, extentOffset: 35), ); - // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + // Selected text shows 5 toolbar buttons. + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Tap the selected word to hide the toolbar and retain the selection. await tester.tapAt(vPos); @@ -2130,7 +2228,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 24, extentOffset: 35), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Tap past the selected word to move the cursor and hide the toolbar. await tester.tapAt(ePos); @@ -2186,7 +2284,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - // Selected text shows 3 toolbar buttons. + // Selected text shows 4 toolbar buttons. expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); // Tap somewhere else to move the cursor. @@ -2249,7 +2347,7 @@ void main() { case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - expect(find.byType(CupertinoButton), findsNWidgets(4)); + expect(find.byType(CupertinoButton), findsNWidgets(5)); } } }, @@ -2461,7 +2559,7 @@ void main() { ); // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -3506,7 +3604,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); // Shows toolbar. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -3540,7 +3638,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Double tap selecting the same word somewhere else is fine. await tester.tapAt(textFieldStart + const Offset(100.0, 5.0)); @@ -3560,7 +3658,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); await tester.tapAt(textFieldStart + const Offset(150.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3576,7 +3674,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); group('Triple tap/click', () { @@ -3829,7 +3927,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(kDoubleTapTimeout); @@ -3855,7 +3953,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); // Third tap shows the toolbar and selects the paragraph. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -3864,7 +3962,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 36), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); await tester.tapAt(textfieldStart + const Offset(150.0, 25.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3882,7 +3980,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 44, extentOffset: 50), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); // Third tap selects the paragraph and shows the toolbar. await tester.tapAt(textfieldStart + const Offset(150.0, 25.0)); @@ -3891,7 +3989,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 36, extentOffset: 66), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart index b154e9ad88535..f3ee78c2a9ab7 100644 --- a/packages/flutter/test/cupertino/text_selection_test.dart +++ b/packages/flutter/test/cupertino/text_selection_test.dart @@ -179,10 +179,13 @@ void main() { }); group('Text selection menu overflow (iOS)', () { - Finder findOverflowNextButton() => find.byWidgetPredicate((Widget widget) => + Finder findOverflowNextButton() { + return find.byWidgetPredicate((Widget widget) => widget is CustomPaint && - '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter', - ); + '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter', + ); + } + Finder findOverflowBackButton() => find.byWidgetPredicate((Widget widget) => widget is CustomPaint && '${widget.painter?.runtimeType}' == '_LeftCupertinoChevronPainter', @@ -247,7 +250,7 @@ void main() { testWidgets("When a menu item doesn't fit, a second page is used.", (WidgetTester tester) async { // Set the screen size to more narrow, so that Paste can't fit. - tester.view.physicalSize = const Size(900, 800); + tester.view.physicalSize = const Size(1000, 800); addTearDown(tester.view.reset); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); @@ -265,12 +268,23 @@ void main() { ), )); + Future tapNextButton() async { + await tester.tapAt(tester.getCenter(findOverflowNextButton())); + await tester.pumpAndSettle(); + } + + Future tapBackButton() async { + await tester.tapAt(tester.getCenter(findOverflowBackButton())); + await tester.pumpAndSettle(); + } + // Initially, the menu isn't shown at all. expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsNothing); @@ -287,42 +301,53 @@ void main() { expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); // Tapping the next button shows both the overflow, back, and next buttons. - await tester.tapAt(tester.getCenter(findOverflowNextButton())); - await tester.pumpAndSettle(); + await tapNextButton(); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsOneWidget); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); - // Tapping the next button shows the overflowing button and the next - // button is hidden as the last page is shown. - await tester.tapAt(tester.getCenter(findOverflowNextButton())); - await tester.pumpAndSettle(); + // Tapping the next button shows the next, back, and Look Up button + await tapNextButton(); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsOneWidget); + expect(find.text('Search Web'), findsNothing); + expect(findOverflowBackButton(), findsOneWidget); + expect(findOverflowNextButton(), findsOneWidget); + + // Tapping the next button shows the back and Search Web button + await tapNextButton(); + expect(find.text('Cut'), findsNothing); + expect(find.text('Copy'), findsNothing); + expect(find.text('Paste'), findsNothing); + expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsOneWidget); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsNothing); - // Tapping the back button shows the first page again with the next button. - await tester.tapAt(tester.getCenter(findOverflowBackButton())); - await tester.pumpAndSettle(); - await tester.tapAt(tester.getCenter(findOverflowBackButton())); - await tester.pumpAndSettle(); + // Tapping the back button thrice shows the first page again with the next button. + await tapBackButton(); + await tapBackButton(); + await tapBackButton(); expect(find.text('Cut'), findsOneWidget); expect(find.text('Copy'), findsOneWidget); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); }, @@ -351,6 +376,16 @@ void main() { ), )); + Future tapNextButton() async { + await tester.tapAt(tester.getCenter(findOverflowNextButton())); + await tester.pumpAndSettle(); + } + + Future tapBackButton() async { + await tester.tapAt(tester.getCenter(findOverflowBackButton())); + await tester.pumpAndSettle(); + } + // Initially, the menu isn't shown at all. expect(find.byType(CupertinoTextSelectionToolbarButton), findsNothing); expect(find.text('Cut'), findsNothing); @@ -358,6 +393,7 @@ void main() { expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsNothing); @@ -375,49 +411,60 @@ void main() { expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); // Tapping the next button shows Copy. - await tester.tapAt(tester.getCenter(findOverflowNextButton())); - await tester.pumpAndSettle(); + await tapNextButton(); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(3)); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsOneWidget); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); // Tapping the next button again shows Paste - await tester.tapAt(tester.getCenter(findOverflowNextButton())); - await tester.pumpAndSettle(); + await tapNextButton(); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(3)); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsOneWidget); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); - // Tapping the next button again shows the last page. - await tester.tapAt(tester.getCenter(findOverflowNextButton())); - await tester.pumpAndSettle(); + // Tapping the next button again shows the Look Up Button. + await tapNextButton(); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsOneWidget); + expect(find.text('Search Web'), findsNothing); + expect(findOverflowBackButton(), findsOneWidget); + expect(findOverflowNextButton(), findsOneWidget); + + // Tapping the next button again shows the last page. + await tapNextButton(); + expect(find.text('Cut'), findsNothing); + expect(find.text('Copy'), findsNothing); + expect(find.text('Paste'), findsNothing); + expect(find.text('Select All'), findsNothing); + expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsOneWidget); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsNothing); - // Tapping the back button twice shows the second page again with the next button. - await tester.tapAt(tester.getCenter(findOverflowBackButton())); - await tester.pumpAndSettle(); - await tester.tapAt(tester.getCenter(findOverflowBackButton())); - await tester.pumpAndSettle(); + // Tapping the back button thrice shows the second page again with the next button. + await tapBackButton(); + await tapBackButton(); + await tapBackButton(); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(3)); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsOneWidget); @@ -428,8 +475,7 @@ void main() { expect(findOverflowNextButton(), findsOneWidget); // Tapping the back button again shows the first page again. - await tester.tapAt(tester.getCenter(findOverflowBackButton())); - await tester.pumpAndSettle(); + await tapBackButton(); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(2)); expect(find.text('Cut'), findsOneWidget); expect(find.text('Copy'), findsNothing); diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart index a84a5b2ebd63c..f1cf29c4ab8b5 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart @@ -92,14 +92,19 @@ void main() { ..line(p1: const Offset(7.5, 0), p2: const Offset(2.5, 5)) ..line(p1: const Offset(2.5, 5), p2: const Offset(7.5, 10)); - Finder findOverflowNextButton() => find.byWidgetPredicate((Widget widget) => + Finder findOverflowNextButton() { + return find.byWidgetPredicate((Widget widget) => widget is CustomPaint && - '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter', - ); - Finder findOverflowBackButton() => find.byWidgetPredicate((Widget widget) => + '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter', + ); + } + + Finder findOverflowBackButton() { + return find.byWidgetPredicate((Widget widget) => widget is CustomPaint && - '${widget.painter?.runtimeType}' == '_LeftCupertinoChevronPainter', - ); + '${widget.painter?.runtimeType}' == '_LeftCupertinoChevronPainter', + ); + } testWidgets('chevrons point to the correct side', (WidgetTester tester) async { // Add enough TestBoxes to need 3 pages. diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index 4a4ddc6492ae4..66bbe6e121785 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -27,6 +27,13 @@ void main() { await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); }); + Finder findOverflowNextButton() { + return find.byWidgetPredicate((Widget widget) => + widget is CustomPaint && + '${widget.painter?.runtimeType}' == '_RightCupertinoChevronPainter', + ); + } + testWidgetsWithLeakTracking('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async { const String buttonText = 'Click me'; @@ -187,6 +194,7 @@ void main() { onSelectAll: () {}, onLiveTextInput: () {}, onLookUp: () {}, + onSearchWeb: () {}, ), ), ), @@ -200,20 +208,24 @@ void main() { switch (defaultTargetPlatform) { case TargetPlatform.android: - case TargetPlatform.fuchsia: expect(find.text('Select all'), findsOneWidget); expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(6)); + case TargetPlatform.fuchsia: + expect(find.text('Select all'), findsOneWidget); + expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(7)); case TargetPlatform.iOS: expect(find.text('Select All'), findsOneWidget); - expect(findLiveTextButton(), findsOneWidget); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); + await tester.tapAt(tester.getCenter(findOverflowNextButton())); + await tester.pumpAndSettle(); + expect(findLiveTextButton(), findsOneWidget); case TargetPlatform.linux: case TargetPlatform.windows: expect(find.text('Select all'), findsOneWidget); - expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(6)); + expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(7)); case TargetPlatform.macOS: expect(find.text('Select All'), findsOneWidget); - expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(6)); + expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(7)); } }, skip: kIsWeb, // [intended] on web the browser handles the context menu. diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart index da3731684f2a0..83b3738f0577e 100644 --- a/packages/flutter/test/material/localizations_test.dart +++ b/packages/flutter/test/material/localizations_test.dart @@ -32,6 +32,7 @@ void main() { expect(localizations.cutButtonLabel, isNotNull); expect(localizations.scanTextButtonLabel, isNotNull); expect(localizations.lookUpButtonLabel, isNotNull); + expect(localizations.searchWebButtonLabel, isNotNull); expect(localizations.okButtonLabel, isNotNull); expect(localizations.pasteButtonLabel, isNotNull); expect(localizations.selectAllButtonLabel, isNotNull); diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 3998f97500323..966ff68b0dcfe 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -9217,7 +9217,7 @@ void main() { ); // Selected text shows 4 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Tap the selected word to hide the toolbar and retain the selection. await tester.tapAt(vPos); @@ -9235,7 +9235,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 24, extentOffset: 35), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Tap past the selected word to move the cursor and hide the toolbar. await tester.tapAt(ePos); @@ -9289,8 +9289,8 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + // Selected text shows 5 toolbar buttons. + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -9859,7 +9859,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(kDoubleTapTimeout); @@ -9883,7 +9883,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Third tap shows the toolbar and selects the paragraph. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -9892,7 +9892,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 36), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); await tester.tapAt(textfieldStart + const Offset(150.0, 50.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -9909,7 +9909,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 44, extentOffset: 50), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Third tap selects the paragraph and shows the toolbar. await tester.tapAt(textfieldStart + const Offset(150.0, 50.0)); @@ -9918,7 +9918,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 36, extentOffset: 66), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -11125,7 +11125,7 @@ void main() { ); // Selected text shows 4 toolbar buttons on iOS, and 3 on macOS. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); await gesture.up(); await tester.pump(); @@ -11137,7 +11137,7 @@ void main() { ); // The toolbar is still showing. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -11269,7 +11269,7 @@ void main() { // Collapsed toolbar shows 3 buttons. expect( find.byType(CupertinoButton), - isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3) + isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3) ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), @@ -11573,7 +11573,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 23), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -11739,7 +11739,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 66, affinity: TextAffinity.upstream), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); lastCharEndpoint = renderEditable.getEndpointsForSelection( const TextSelection.collapsed(offset: 66), // Last character's position. @@ -12332,7 +12332,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(5) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -12430,7 +12430,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); // Double tap selecting the same word somewhere else is fine. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -12450,7 +12450,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -12466,7 +12466,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -12893,7 +12893,7 @@ void main() { await gesture.up(); await tester.pumpAndSettle(); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(4)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index b1f15136b89c6..6d008132e8591 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -154,6 +154,7 @@ void main() { onPaste: null, onSelectAll: null, onLookUp: null, + onSearchWeb: null, onLiveTextInput: () { invokedLiveTextInputSuccessfully = true; }, diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 6b8f03051b4e4..d23761c672f0f 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -2959,7 +2959,7 @@ void main() { ); // Selected text shows 1 toolbar buttons on MacOS, 2 on iOS. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3090,7 +3090,7 @@ void main() { ); // Selected text shows 2 toolbar buttons for iOS, 1 for macOS. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); await gesture.up(); await tester.pump(); @@ -3101,7 +3101,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); // The toolbar is still showing. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3218,7 +3218,7 @@ void main() { ); // Toolbar shows one button. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3554,7 +3554,7 @@ void main() { ), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -3782,7 +3782,7 @@ void main() { ); // Long press toolbar. - expect(find.byType(CupertinoButton), findsNWidgets(2)); + expect(find.byType(CupertinoButton), findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -3876,7 +3876,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3911,7 +3911,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); // Double tap selecting the same word somewhere else is fine. await tester.pumpAndSettle(kDoubleTapTimeout); @@ -3928,7 +3928,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); // Hide the toolbar so it doesn't interfere with taps on the text. final EditableTextState editableTextState = @@ -3950,7 +3950,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(2) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -4029,7 +4029,7 @@ void main() { await gesture.up(); await tester.pump(); - expect(find.byType(CupertinoButton), findsNWidgets(2)); + expect(find.byType(CupertinoButton), findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb index 69bc6c4ddded2..94d7a4ed7cb99 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Soek", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb index 453a1e81fc506..3e01785574cbd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ፍለጋ", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb index b9ad5a4b20696..f4cf67ea05f1e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb @@ -44,5 +44,6 @@ "searchTextFieldPlaceholderLabel": "بحث", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb index 048bd85d5ccc1..09fcc0fcd4c82 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "সন্ধান কৰক", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb index 5f736959241b2..c3335169b91c1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Axtarın", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb index 3fbd1bbb98b65..5ec31f0feadaf 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Пошук", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb index 47470b61054af..4b5719a451f66 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Търсене", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb index 9aa5492749e15..bcdd58d9bb016 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "সার্চ করুন", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb index 79f845fbe568c..d7167c0925dd7 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb @@ -29,5 +29,6 @@ "searchTextFieldPlaceholderLabel": "Pretraživanje", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb index b310231de1c16..a8ee35a10a8f9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Cerca", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb index d391a3c07ac18..472815c54ab89 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Hledat", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb index ffa34dfb1f36a..506fec1c1173a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb @@ -44,5 +44,6 @@ "modalBarrierDismissLabel": "Diystyru", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb index 7dd1e44f940dd..a0272a2c30973 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Søg", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb index bf8d283700333..1a2a336c4e147 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Suche", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb index dca5eb8ee5d07..65c8a97f0922b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Αναζήτηση", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb index 0cc970d109028..c3342e6c90ec6 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb @@ -170,6 +170,11 @@ "description": "The label for the Look Up button and menu items on iOS." }, + "searchWebButtonLabel": "Search Web", + "@searchWebButtonLabel": { + "description": "The label for the Search Web button and menu items on iOS." + }, + "noSpellCheckReplacementsLabel": "No Replacements Found", "@noSpellCheckReplacementsLabel": { "description": "The label shown in the text selection context menu on iOS when a misspelled word is tapped but the spell checker found no reasonable fixes for it." diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb index 8f992fd2bec3a..f71e5ff039147 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Buscar", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb index 52886d8d96c2f..ff2040a479a4d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Otsige", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb index 659c70457d997..114793a757f53 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Bilatu", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb index e640762476027..11f9426338725 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "جستجو", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb index 4afd7f22b6d40..bfbedbc5668b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Hae", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb index 4e15997b414a2..d93a590c16b4b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Hanapin", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb index 31921f0e8ce76..437984e92a8a7 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Rechercher", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb index 95502c805af52..481510c245a6b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Fai unha busca", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb index bf8d283700333..1a2a336c4e147 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Suche", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb index 9269f0380c871..952f10ad3db81 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "શોધો", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb index ba34f4d83205e..666a3f49ccc19 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "חיפוש", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb index ceaf9b91ecdc9..9bff606750884 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "खोजें", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb index 3c8c9ef6debcb..ac04d54e64e64 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb @@ -29,5 +29,6 @@ "searchTextFieldPlaceholderLabel": "Pretraživanje", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb index c2d64af3bde08..e9de9a1e04777 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Keresés", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb index abbf09b15e2a0..56f6b5f4c7155 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Որոնում", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb index 2c7c7ce3c02fc..6b94a0f6d2bff 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Telusuri", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb index 035ff2c3e33dc..bc77d218be1a3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Leit", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb index f370b29df45b9..91238cb5974bc 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Cerca", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb index f97148f8ccb22..adc131a0e968f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "検索", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb index 3dbcb4ba5cec9..595f23b90aedd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ძიება", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb index 323d4f6c2d78d..55fa59f72863f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Іздеу", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb index ecc1d7ec21306..bb1905a163c14 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ស្វែងរក", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb index f4c9dec32b7b3..8ead9138ac398 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "\u0cb9\u0cc1\u0ca1\u0cc1\u0c95\u0cbf", "noSpellCheckReplacementsLabel": "\u004e\u006f\u0020\u0052\u0065\u0070\u006c\u0061\u0063\u0065\u006d\u0065\u006e\u0074\u0073\u0020\u0046\u006f\u0075\u006e\u0064", "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075", - "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070" + "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070", + "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb index 55a27170adb7e..01ddb986283b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "검색", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb index 1ea6f15519099..7943ddd689ede 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Издөө", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb index 3d375eb44c64c..0f9cfbff57475 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ຊອກຫາ", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb index d90f28137f453..8b05726e0f463 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Paieška", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb index b7ca96dd5f8c5..8fd972f8fe312 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb @@ -29,5 +29,6 @@ "searchTextFieldPlaceholderLabel": "Meklēšana", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb index 5599a7b292cb1..6a4318fcf832e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Пребарувајте", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb index ebdaa61ae3f0a..f1a077d4111e4 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "തിരയുക", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb index 6c6d8e73b4312..c980229358da2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Хайх", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb index 47aa29e683324..11cdfb2bcebe6 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "शोधा", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb index 1730882db8dd4..87c839cfe6695 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Cari", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb index a6b191504ca79..bea64b6130084 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ရှာရန်", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb index 06a32b6a95fc2..03b48b0e7943d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Søk", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb index dacaa307948c9..d205f044aa6bd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "खोज्नुहोस्", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb index 9db7bda20e328..523e3f9f4b5d8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Zoeken", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb index 06a32b6a95fc2..03b48b0e7943d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Søk", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb index 06bf3b6db4352..c0065d3cce524 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ସନ୍ଧାନ କରନ୍ତୁ", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb index 5e2bbab9314cf..22d75077719a1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ਖੋਜੋ", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb index 7d74843c48560..689f5166a80d5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Szukaj", "noSpellCheckReplacementsLabel": "Nie znaleziono zastąpień", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb index 6c461691d10e0..0a9b39e58b128 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Pesquisar", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb index f455a42995b1e..002be304894fe 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb @@ -29,5 +29,6 @@ "searchTextFieldPlaceholderLabel": "Căutați", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb index 94e53fe023675..284c0c269d243 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Поиск", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb index 8b2ea75ec7ebe..caa2ad12dba2c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "සෙවීම", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb index ac03577d4672e..b113e8c6f5706 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Hľadať", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb index e83f6f3287529..c65a8444caf20 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Iskanje", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb index 9a954c3e3afff..cbc57e60595eb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Kërko", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb index 3fd0749276fde..87ff451e119dd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb @@ -29,5 +29,6 @@ "searchTextFieldPlaceholderLabel": "Претражите", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb index 756a6984a4f77..ac79e55ad3d8b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Sök", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb index 7e1cb2359e309..2b7c122864865 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Tafuta", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb index ae344cddf049b..52fa98d643649 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "தேடுக", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb index 869edfce216ea..e474ded6c27f3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "సెర్చ్ చేయి", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb index 8c2ce23a2e12f..c27d9861ec3d1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "ค้นหา", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb index 4e15997b414a2..d93a590c16b4b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Hanapin", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb index 85fdf406f985d..33f1f935426b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Ara", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb index 77949d298f1ca..ebbc49d33eecb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb @@ -34,5 +34,6 @@ "searchTextFieldPlaceholderLabel": "Шукайте", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb index 0e004933dccf7..252b1ac93796f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "تلاش کریں", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb index d3dec79d37b84..1f6536d099fff 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Qidiruv", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb index 8ea93152745e2..7abb213939468 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Tìm kiếm", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb index ed0bbdc3e70c8..0d406c85263f8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "搜索", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb index 87a31e7fbc405..d391b3c9c5def 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb @@ -24,5 +24,6 @@ "searchTextFieldPlaceholderLabel": "Sesha", "noSpellCheckReplacementsLabel": "No Replacements Found", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index 3078d50367b3e..12e56119dfb99 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -112,6 +112,9 @@ class CupertinoLocalizationAf extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Soek'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Kies alles'; @@ -268,6 +271,9 @@ class CupertinoLocalizationAm extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ፍለጋ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ሁሉንም ምረጥ'; @@ -424,6 +430,9 @@ class CupertinoLocalizationAr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'بحث'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'اختيار الكل'; @@ -580,6 +589,9 @@ class CupertinoLocalizationAs extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'সন্ধান কৰক'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'সকলো বাছনি কৰক'; @@ -736,6 +748,9 @@ class CupertinoLocalizationAz extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Axtarın'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Hamısını seçin'; @@ -892,6 +907,9 @@ class CupertinoLocalizationBe extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Пошук'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Выбраць усе'; @@ -1048,6 +1066,9 @@ class CupertinoLocalizationBg extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Търсене'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Избиране на всички'; @@ -1204,6 +1225,9 @@ class CupertinoLocalizationBn extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'সার্চ করুন'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'সব বেছে নিন'; @@ -1360,6 +1384,9 @@ class CupertinoLocalizationBs extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Pretraživanje'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Odaberi sve'; @@ -1516,6 +1543,9 @@ class CupertinoLocalizationCa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Cerca'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Selecciona-ho tot'; @@ -1672,6 +1702,9 @@ class CupertinoLocalizationCs extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Hledat'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vybrat vše'; @@ -1828,6 +1861,9 @@ class CupertinoLocalizationCy extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Chwilio'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Dewis y Cyfan'; @@ -1984,6 +2020,9 @@ class CupertinoLocalizationDa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Søg'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vælg alle'; @@ -2140,6 +2179,9 @@ class CupertinoLocalizationDe extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Suche'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Alles auswählen'; @@ -2317,6 +2359,9 @@ class CupertinoLocalizationEl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Αναζήτηση'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Επιλογή όλων'; @@ -2473,6 +2518,9 @@ class CupertinoLocalizationEn extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Search'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Select All'; @@ -2821,6 +2869,9 @@ class CupertinoLocalizationEs extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Buscar'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Seleccionar todo'; @@ -3637,6 +3688,9 @@ class CupertinoLocalizationEt extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Otsige'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vali kõik'; @@ -3793,6 +3847,9 @@ class CupertinoLocalizationEu extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Bilatu'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Hautatu guztiak'; @@ -3949,6 +4006,9 @@ class CupertinoLocalizationFa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'جستجو'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'انتخاب همه'; @@ -4105,6 +4165,9 @@ class CupertinoLocalizationFi extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Hae'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Valitse kaikki'; @@ -4261,6 +4324,9 @@ class CupertinoLocalizationFil extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Hanapin'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Piliin Lahat'; @@ -4417,6 +4483,9 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Rechercher'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Tout sélect.'; @@ -4615,6 +4684,9 @@ class CupertinoLocalizationGl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Fai unha busca'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Seleccionar todo'; @@ -4771,6 +4843,9 @@ class CupertinoLocalizationGsw extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Suche'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Alles auswählen'; @@ -4927,6 +5002,9 @@ class CupertinoLocalizationGu extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'શોધો'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'બધા પસંદ કરો'; @@ -5083,6 +5161,9 @@ class CupertinoLocalizationHe extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'חיפוש'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'בחירת הכול'; @@ -5239,6 +5320,9 @@ class CupertinoLocalizationHi extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'खोजें'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'सभी चुनें'; @@ -5395,6 +5479,9 @@ class CupertinoLocalizationHr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Pretraživanje'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Odaberi sve'; @@ -5551,6 +5638,9 @@ class CupertinoLocalizationHu extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Keresés'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Összes kijelölése'; @@ -5707,6 +5797,9 @@ class CupertinoLocalizationHy extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Որոնում'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Նշել բոլորը'; @@ -5863,6 +5956,9 @@ class CupertinoLocalizationId extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Telusuri'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Pilih Semua'; @@ -6019,6 +6115,9 @@ class CupertinoLocalizationIs extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Leit'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Velja allt'; @@ -6175,6 +6274,9 @@ class CupertinoLocalizationIt extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Cerca'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Seleziona tutto'; @@ -6331,6 +6433,9 @@ class CupertinoLocalizationJa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => '検索'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'すべて選択'; @@ -6487,6 +6592,9 @@ class CupertinoLocalizationKa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ძიება'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ყველას არჩევა'; @@ -6643,6 +6751,9 @@ class CupertinoLocalizationKk extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Іздеу'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Барлығын таңдау'; @@ -6799,6 +6910,9 @@ class CupertinoLocalizationKm extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ស្វែងរក'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ជ្រើសរើស​ទាំងអស់'; @@ -6955,6 +7069,9 @@ class CupertinoLocalizationKn extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => '\u{cb9}\u{cc1}\u{ca1}\u{cc1}\u{c95}\u{cbf}'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => '\u{c8e}\u{cb2}\u{ccd}\u{cb2}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc2}\u{20}\u{c86}\u{caf}\u{ccd}\u{c95}\u{cc6}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; @@ -7111,6 +7228,9 @@ class CupertinoLocalizationKo extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => '검색'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => '전체 선택'; @@ -7267,6 +7387,9 @@ class CupertinoLocalizationKy extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Издөө'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Баарын тандоо'; @@ -7423,6 +7546,9 @@ class CupertinoLocalizationLo extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ຊອກຫາ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ເລືອກທັງໝົດ'; @@ -7579,6 +7705,9 @@ class CupertinoLocalizationLt extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Paieška'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Pasirinkti viską'; @@ -7735,6 +7864,9 @@ class CupertinoLocalizationLv extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Meklēšana'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Atlasīt visu'; @@ -7891,6 +8023,9 @@ class CupertinoLocalizationMk extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Пребарувајте'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Избери ги сите'; @@ -8047,6 +8182,9 @@ class CupertinoLocalizationMl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'തിരയുക'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'എല്ലാം തിരഞ്ഞെടുക്കുക'; @@ -8203,6 +8341,9 @@ class CupertinoLocalizationMn extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Хайх'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Бүгдийг сонгох'; @@ -8359,6 +8500,9 @@ class CupertinoLocalizationMr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'शोधा'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'सर्व निवडा'; @@ -8515,6 +8659,9 @@ class CupertinoLocalizationMs extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Cari'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Pilih Semua'; @@ -8671,6 +8818,9 @@ class CupertinoLocalizationMy extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ရှာရန်'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'အားလုံး ရွေးရန်'; @@ -8827,6 +8977,9 @@ class CupertinoLocalizationNb extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Søk'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Velg alle'; @@ -8983,6 +9136,9 @@ class CupertinoLocalizationNe extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'खोज्नुहोस्'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'सबै चयन गर्नुहोस्'; @@ -9139,6 +9295,9 @@ class CupertinoLocalizationNl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Zoeken'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Alles selecteren'; @@ -9295,6 +9454,9 @@ class CupertinoLocalizationNo extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Søk'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Velg alle'; @@ -9451,6 +9613,9 @@ class CupertinoLocalizationOr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ସନ୍ଧାନ କରନ୍ତୁ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ସମସ୍ତ ଚୟନ କରନ୍ତୁ'; @@ -9607,6 +9772,9 @@ class CupertinoLocalizationPa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ਖੋਜੋ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ਸਭ ਚੁਣੋ'; @@ -9763,6 +9931,9 @@ class CupertinoLocalizationPl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Szukaj'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Zaznacz wszystko'; @@ -9919,6 +10090,9 @@ class CupertinoLocalizationPt extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Pesquisar'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Selecionar tudo'; @@ -10111,6 +10285,9 @@ class CupertinoLocalizationRo extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Căutați'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Selectați-le pe toate'; @@ -10267,6 +10444,9 @@ class CupertinoLocalizationRu extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Поиск'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Выбрать все'; @@ -10423,6 +10603,9 @@ class CupertinoLocalizationSi extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'සෙවීම'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'සියල්ල තෝරන්න'; @@ -10579,6 +10762,9 @@ class CupertinoLocalizationSk extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Hľadať'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vybrať všetko'; @@ -10735,6 +10921,9 @@ class CupertinoLocalizationSl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Iskanje'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Izberi vse'; @@ -10891,6 +11080,9 @@ class CupertinoLocalizationSq extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Kërko'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Zgjidhi të gjitha'; @@ -11047,6 +11239,9 @@ class CupertinoLocalizationSr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Претражите'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Изабери све'; @@ -11317,6 +11512,9 @@ class CupertinoLocalizationSv extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Sök'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Markera alla'; @@ -11473,6 +11671,9 @@ class CupertinoLocalizationSw extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Tafuta'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Teua Zote'; @@ -11629,6 +11830,9 @@ class CupertinoLocalizationTa extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'தேடுக'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'எல்லாம் தேர்ந்தெடு'; @@ -11785,6 +11989,9 @@ class CupertinoLocalizationTe extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'సెర్చ్ చేయి'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'అన్నింటినీ ఎంచుకోండి'; @@ -11941,6 +12148,9 @@ class CupertinoLocalizationTh extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'ค้นหา'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'เลือกทั้งหมด'; @@ -12097,6 +12307,9 @@ class CupertinoLocalizationTl extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Hanapin'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Piliin Lahat'; @@ -12253,6 +12466,9 @@ class CupertinoLocalizationTr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Ara'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Tümünü Seç'; @@ -12409,6 +12625,9 @@ class CupertinoLocalizationUk extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Шукайте'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Вибрати все'; @@ -12565,6 +12784,9 @@ class CupertinoLocalizationUr extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'تلاش کریں'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'سبھی منتخب کریں'; @@ -12721,6 +12943,9 @@ class CupertinoLocalizationUz extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Qidiruv'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Barchasini tanlash'; @@ -12877,6 +13102,9 @@ class CupertinoLocalizationVi extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Tìm kiếm'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Chọn tất cả'; @@ -13033,6 +13261,9 @@ class CupertinoLocalizationZh extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => '搜索'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => '全选'; @@ -13336,6 +13567,9 @@ class CupertinoLocalizationZu extends GlobalCupertinoLocalizations { @override String get searchTextFieldPlaceholderLabel => 'Sesha'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Khetha konke'; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index 5227d58f67bd7..01b9d055c5d1a 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -437,6 +437,9 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Soek'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Kies alles'; @@ -921,6 +924,9 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ይፈልጉ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ሁሉንም ምረጥ'; @@ -1405,6 +1411,9 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'بحث'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'اختيار الكل'; @@ -1889,6 +1898,9 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'সন্ধান কৰক'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'সকলো বাছনি কৰক'; @@ -2373,6 +2385,9 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Axtarın'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Hamısını seçin'; @@ -2857,6 +2872,9 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Пошук'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Выбраць усе'; @@ -3341,6 +3359,9 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Търсене'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Избиране на всички'; @@ -3825,6 +3846,9 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'খুঁজুন'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'সব বেছে নিন'; @@ -4309,6 +4333,9 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Pretražite'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Odaberi sve'; @@ -4793,6 +4820,9 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Cerca'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Selecciona-ho tot'; @@ -5277,6 +5307,9 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Hledat'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vybrat vše'; @@ -5761,6 +5794,9 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Chwilio'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Dewis y Cyfan'; @@ -6245,6 +6281,9 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Søg'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Markér alt'; @@ -6729,6 +6768,9 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Suchen'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Alle auswählen'; @@ -7277,6 +7319,9 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Αναζήτηση'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Επιλογή όλων'; @@ -7761,6 +7806,9 @@ class MaterialLocalizationEn extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Search'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Select all'; @@ -8979,6 +9027,9 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Buscar'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Seleccionar todo'; @@ -12846,6 +12897,9 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Otsing'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vali kõik'; @@ -13330,6 +13384,9 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Bilatu'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Hautatu guztiak'; @@ -13814,6 +13871,9 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'جستجو'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'انتخاب همه'; @@ -14298,6 +14358,9 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Haku'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Valitse kaikki'; @@ -14782,6 +14845,9 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Maghanap'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Piliin lahat'; @@ -15266,6 +15332,9 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Rechercher'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Tout sélectionner'; @@ -15892,6 +15961,9 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Buscar'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Seleccionar todo'; @@ -16376,6 +16448,9 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Suchen'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Alle auswählen'; @@ -16860,6 +16935,9 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'શોધો'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'બધા પસંદ કરો'; @@ -17344,6 +17422,9 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'חיפוש'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'בחירת הכול'; @@ -17828,6 +17909,9 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'खोजें'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'सभी को चुनें'; @@ -18312,6 +18396,9 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Pretražite'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Odaberi sve'; @@ -18796,6 +18883,9 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Keresés'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Összes kijelölése'; @@ -19280,6 +19370,9 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Որոնել'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Նշել բոլորը'; @@ -19764,6 +19857,9 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Telusuri'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Pilih semua'; @@ -20248,6 +20344,9 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Leit'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Velja allt'; @@ -20732,6 +20831,9 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Cerca'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Seleziona tutto'; @@ -21216,6 +21318,9 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => '検索'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'すべて選択'; @@ -21700,6 +21805,9 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ძიება'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ყველას არჩევა'; @@ -22184,6 +22292,9 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Іздеу'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Барлығын таңдау'; @@ -22668,6 +22779,9 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ស្វែងរក'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ជ្រើសរើស​ទាំងអស់'; @@ -23152,6 +23266,9 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { @override String get searchFieldLabel => '\u{cb9}\u{cc1}\u{ca1}\u{cc1}\u{c95}\u{cbf}'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => '\u{c8e}\u{cb2}\u{ccd}\u{cb2}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc2}\u{20}\u{c86}\u{caf}\u{ccd}\u{c95}\u{cc6}\u{20}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; @@ -23636,6 +23753,9 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { @override String get searchFieldLabel => '검색'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => '전체 선택'; @@ -24120,6 +24240,9 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Издөө'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Баарын тандоо'; @@ -24604,6 +24727,9 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ຊອກຫາ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ເລືອກທັງໝົດ'; @@ -25088,6 +25214,9 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Paieška'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Pasirinkti viską'; @@ -25572,6 +25701,9 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Meklēt'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Atlasīt visu'; @@ -26056,6 +26188,9 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Пребарувајте'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Избери ги сите'; @@ -26540,6 +26675,9 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'തിരയുക'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'എല്ലാം തിരഞ്ഞെടുക്കുക'; @@ -27024,6 +27162,9 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Хайх'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Бүгдийг сонгох'; @@ -27508,6 +27649,9 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'शोध'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'सर्व निवडा'; @@ -27992,6 +28136,9 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Cari'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Pilih semua'; @@ -28476,6 +28623,9 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ရှာဖွေရန်'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'အားလုံး ရွေးရန်'; @@ -28960,6 +29110,9 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Søk'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Velg alle'; @@ -29444,6 +29597,9 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'खोज्नुहोस्'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'सबै बटनहरू चयन गर्नुहोस्'; @@ -29928,6 +30084,9 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Zoeken'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Alles selecteren'; @@ -30412,6 +30571,9 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Søk'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Velg alle'; @@ -30896,6 +31058,9 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ସନ୍ଧାନ କରନ୍ତୁ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ସବୁ ଚୟନ କରନ୍ତୁ'; @@ -31380,6 +31545,9 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ਖੋਜੋ'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'ਸਭ ਚੁਣੋ'; @@ -31864,6 +32032,9 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Szukaj'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Zaznacz wszystko'; @@ -32348,6 +32519,9 @@ class MaterialLocalizationPs extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'لټون'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'غوره کړئ'; @@ -32832,6 +33006,9 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Pesquisa'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Selecionar tudo'; @@ -33467,6 +33644,9 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Căutați'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Selectați tot'; @@ -33951,6 +34131,9 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Поиск'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Выбрать все'; @@ -34435,6 +34618,9 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'සෙවීම'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'සියල්ල තෝරන්න'; @@ -34919,6 +35105,9 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Hľadať'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Vybrať všetko'; @@ -35403,6 +35592,9 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Iskanje'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Izberi vse'; @@ -35887,6 +36079,9 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Kërko'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Zgjidh të gjitha'; @@ -36371,6 +36566,9 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Претражите'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Изабери све'; @@ -37169,6 +37367,9 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Sök'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Markera allt'; @@ -37653,6 +37854,9 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Tafuta'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Chagua vyote'; @@ -38137,6 +38341,9 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'தேடல்'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'அனைத்தையும் தேர்ந்தெடு'; @@ -38621,6 +38828,9 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'వెతకండి'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'అన్నింటినీ ఎంచుకోండి'; @@ -39105,6 +39315,9 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'ค้นหา'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'เลือกทั้งหมด'; @@ -39589,6 +39802,9 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Maghanap'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Piliin lahat'; @@ -40073,6 +40289,9 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Ara'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Tümünü seç'; @@ -40557,6 +40776,9 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Пошук'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Вибрати всі'; @@ -41041,6 +41263,9 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'تلاش'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'سبھی کو منتخب کریں'; @@ -41525,6 +41750,9 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Qidirish'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Hammasi'; @@ -42009,6 +42237,9 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Tìm kiếm'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Chọn tất cả'; @@ -42493,6 +42724,9 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { @override String get searchFieldLabel => '搜索'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => '全选'; @@ -43470,6 +43704,9 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { @override String get searchFieldLabel => 'Sesha'; + @override + String get searchWebButtonLabel => 'Search Web'; + @override String get selectAllButtonLabel => 'Khetha konke'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_af.arb b/packages/flutter_localizations/lib/src/l10n/material_af.arb index 89f67a9e1a622..8800c726c4f5f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_af.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_am.arb b/packages/flutter_localizations/lib/src/l10n/material_am.arb index f6e368abe9880..cbd036bce09db 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_am.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ar.arb b/packages/flutter_localizations/lib/src/l10n/material_ar.arb index 33ef73c5a6e8a..30fae912e1675 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ar.arb @@ -153,5 +153,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_as.arb b/packages/flutter_localizations/lib/src/l10n/material_as.arb index a744d5f2b29b3..3a6f0b12a19ce 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_as.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_az.arb b/packages/flutter_localizations/lib/src/l10n/material_az.arb index 5c1271381a4c3..2945f9c89756c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_az.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_be.arb b/packages/flutter_localizations/lib/src/l10n/material_be.arb index d8a19c8f8cc81..73de6bcb29265 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_be.arb @@ -148,5 +148,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bg.arb b/packages/flutter_localizations/lib/src/l10n/material_bg.arb index 1cbba57b7ea47..923ce87574843 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bg.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bn.arb b/packages/flutter_localizations/lib/src/l10n/material_bn.arb index f5feaf34ab50f..edf3c6ff6ebcf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bn.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bs.arb b/packages/flutter_localizations/lib/src/l10n/material_bs.arb index 3ea58673589e1..3d6e27879e633 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bs.arb @@ -146,5 +146,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ca.arb b/packages/flutter_localizations/lib/src/l10n/material_ca.arb index f2c3a743f4f9d..fb83253b72520 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ca.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cs.arb b/packages/flutter_localizations/lib/src/l10n/material_cs.arb index 876fd054e2db6..db1c55b026410 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cs.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cy.arb b/packages/flutter_localizations/lib/src/l10n/material_cy.arb index cc12773c1a1fe..8d4c1e08cd5a0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cy.arb @@ -153,5 +153,6 @@ "collapsedHint": "Expanded", "scanTextButtonLabel": "Scan text", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_da.arb b/packages/flutter_localizations/lib/src/l10n/material_da.arb index 171128b75a9d1..dab575d99a9aa 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_da.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_de.arb b/packages/flutter_localizations/lib/src/l10n/material_de.arb index fa22cbeaded4d..47ae9d44eefb0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_de.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_el.arb b/packages/flutter_localizations/lib/src/l10n/material_el.arb index 67adc3873f7a9..3dfb34c4a0c86 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_el.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb index 84ef000ea6ada..4a43629e0c8ef 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb @@ -202,6 +202,11 @@ "description": "The label for the Look Up button and menu items on iOS." }, + "searchWebButtonLabel": "Search Web", + "@searchWebButtonLabel": { + "description": "The label for the Search Web button and menu items on iOS." + }, + "okButtonLabel": "OK", "@okButtonLabel": { "description": "The label for OK buttons and menu items." diff --git a/packages/flutter_localizations/lib/src/l10n/material_es.arb b/packages/flutter_localizations/lib/src/l10n/material_es.arb index ccc011feaf9fe..4371c85c368f9 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_et.arb b/packages/flutter_localizations/lib/src/l10n/material_et.arb index 8c26ccfcd6863..527eb0afe9955 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_et.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_eu.arb b/packages/flutter_localizations/lib/src/l10n/material_eu.arb index afb1554a4824e..6147f261fbefd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_eu.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fa.arb b/packages/flutter_localizations/lib/src/l10n/material_fa.arb index e5ab93e1eb0e6..2983f4562fc76 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fa.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index be327d1cd3fe2..421da7341385e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fil.arb b/packages/flutter_localizations/lib/src/l10n/material_fil.arb index 915496928d341..ca2f1d0d6aab6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fil.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr.arb b/packages/flutter_localizations/lib/src/l10n/material_fr.arb index 6c0c97837aeed..68639742ce871 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fr.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gl.arb b/packages/flutter_localizations/lib/src/l10n/material_gl.arb index ddfc0e830d09c..9c1116dee4d67 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gl.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb index 7c14e4953e6c5..0128e802d9966 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gu.arb b/packages/flutter_localizations/lib/src/l10n/material_gu.arb index b6a4911067059..908e9095bf820 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gu.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_he.arb b/packages/flutter_localizations/lib/src/l10n/material_he.arb index a625567ce82f5..a046c2b7a4772 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_he.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hi.arb b/packages/flutter_localizations/lib/src/l10n/material_hi.arb index e2c94f427f20b..92674b1e32139 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hi.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hr.arb b/packages/flutter_localizations/lib/src/l10n/material_hr.arb index 64c42dede56c8..a403da631c873 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hr.arb @@ -146,5 +146,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hu.arb b/packages/flutter_localizations/lib/src/l10n/material_hu.arb index d17aa27aeb548..d8bf8b03ddfe8 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hu.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hy.arb b/packages/flutter_localizations/lib/src/l10n/material_hy.arb index 500f4a0d7e322..301d14496e1b5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hy.arb @@ -148,5 +148,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_id.arb b/packages/flutter_localizations/lib/src/l10n/material_id.arb index 5472e1cab7436..b6784a082d319 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_id.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_is.arb b/packages/flutter_localizations/lib/src/l10n/material_is.arb index 19bf822b72c5a..0df7c9f2af066 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_is.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_it.arb b/packages/flutter_localizations/lib/src/l10n/material_it.arb index ee6ef2be0b21e..e85f7f21d8a09 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_it.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ja.arb b/packages/flutter_localizations/lib/src/l10n/material_ja.arb index 787e221ec897b..59403b89dbc91 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ja.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ka.arb b/packages/flutter_localizations/lib/src/l10n/material_ka.arb index be14522256a9d..4d163cec2ed5c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ka.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kk.arb b/packages/flutter_localizations/lib/src/l10n/material_kk.arb index 10659bf78178c..ba13d29d0f03e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kk.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_km.arb b/packages/flutter_localizations/lib/src/l10n/material_km.arb index 5e42cd5be6c71..255a891804a76 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_km.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kn.arb b/packages/flutter_localizations/lib/src/l10n/material_kn.arb index bd834ddb70216..812d4f0c99abc 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kn.arb @@ -142,5 +142,6 @@ "expandedHint": "\u0043\u006f\u006c\u006c\u0061\u0070\u0073\u0065\u0064", "collapsedHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0065\u0064", "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075", - "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070" + "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070", + "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ko.arb b/packages/flutter_localizations/lib/src/l10n/material_ko.arb index e810dc7b7765d..b44fd61d9614d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ko.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ky.arb b/packages/flutter_localizations/lib/src/l10n/material_ky.arb index 562f451ba7e11..d38c569890b0a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ky.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lo.arb b/packages/flutter_localizations/lib/src/l10n/material_lo.arb index b8e975951b475..7524ff85f6b83 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lo.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lt.arb b/packages/flutter_localizations/lib/src/l10n/material_lt.arb index 6821d2e7a12df..4674beef1c2ac 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lt.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lv.arb b/packages/flutter_localizations/lib/src/l10n/material_lv.arb index bf75ba058e772..79da575af0c82 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lv.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mk.arb b/packages/flutter_localizations/lib/src/l10n/material_mk.arb index d275b5c283467..6bf86027bd7b0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mk.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ml.arb b/packages/flutter_localizations/lib/src/l10n/material_ml.arb index 420bed007a8b0..0d4c8c709319a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ml.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mn.arb b/packages/flutter_localizations/lib/src/l10n/material_mn.arb index 0ea6af64bbf97..b9da64a90350d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mn.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mr.arb b/packages/flutter_localizations/lib/src/l10n/material_mr.arb index 97a345d5dc225..56929db97f310 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mr.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ms.arb b/packages/flutter_localizations/lib/src/l10n/material_ms.arb index 319c1f05e5ec4..b7a24560f3476 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ms.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_my.arb b/packages/flutter_localizations/lib/src/l10n/material_my.arb index abebb39aa0523..9eaae92c0db3b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_my.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nb.arb b/packages/flutter_localizations/lib/src/l10n/material_nb.arb index 6dcfbd771365f..64eff83b6ad78 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nb.arb @@ -141,5 +141,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ne.arb b/packages/flutter_localizations/lib/src/l10n/material_ne.arb index a1568dbdc313b..d9e0498acd36f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ne.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nl.arb b/packages/flutter_localizations/lib/src/l10n/material_nl.arb index b42de577e8cfb..babfbb6d403fc 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nl.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_no.arb b/packages/flutter_localizations/lib/src/l10n/material_no.arb index 102fa6b3c0980..160a5eef09a97 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_no.arb @@ -141,5 +141,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_or.arb b/packages/flutter_localizations/lib/src/l10n/material_or.arb index df12f1862ece4..fe6b2b9685fd4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_or.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pa.arb b/packages/flutter_localizations/lib/src/l10n/material_pa.arb index 0b5384fb56dc2..509d64f52f069 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pa.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pl.arb b/packages/flutter_localizations/lib/src/l10n/material_pl.arb index b2f1fd2f2da93..4da82533e582e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pl.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ps.arb b/packages/flutter_localizations/lib/src/l10n/material_ps.arb index f9af707827d70..12905fde08770 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ps.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ps.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb index b68e7658efebe..73a4ced4e3196 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb @@ -145,5 +145,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ro.arb b/packages/flutter_localizations/lib/src/l10n/material_ro.arb index 4f440ffd017de..d74d8794147a6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ro.arb @@ -147,5 +147,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ru.arb b/packages/flutter_localizations/lib/src/l10n/material_ru.arb index c1a223c043102..cb5e76d961870 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ru.arb @@ -150,5 +150,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_si.arb b/packages/flutter_localizations/lib/src/l10n/material_si.arb index 6d987a15fd146..126f539754936 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_si.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sk.arb b/packages/flutter_localizations/lib/src/l10n/material_sk.arb index 355a42abb835d..417d590716cad 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sk.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sl.arb b/packages/flutter_localizations/lib/src/l10n/material_sl.arb index 529e6b790330d..6f761ed20e3cb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sl.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sq.arb b/packages/flutter_localizations/lib/src/l10n/material_sq.arb index a357d1bec50b6..465e0e51b8a26 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sq.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sr.arb b/packages/flutter_localizations/lib/src/l10n/material_sr.arb index 9e7517049452c..522698184ef9b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sr.arb @@ -146,5 +146,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sv.arb b/packages/flutter_localizations/lib/src/l10n/material_sv.arb index 7a86f4d21113f..39975feb0e964 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sv.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sw.arb b/packages/flutter_localizations/lib/src/l10n/material_sw.arb index 3bb66ec41a4cf..df3189e392086 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sw.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ta.arb b/packages/flutter_localizations/lib/src/l10n/material_ta.arb index 0670820f74d52..68eb4b6a35b34 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ta.arb @@ -144,5 +144,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_te.arb b/packages/flutter_localizations/lib/src/l10n/material_te.arb index 61421700e6ffb..159ae42834ee2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_te.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_th.arb b/packages/flutter_localizations/lib/src/l10n/material_th.arb index b00364a340d6c..93ad1fa828494 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_th.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tl.arb b/packages/flutter_localizations/lib/src/l10n/material_tl.arb index 915496928d341..ca2f1d0d6aab6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tl.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tr.arb b/packages/flutter_localizations/lib/src/l10n/material_tr.arb index 521444307879e..a494cd85bd1b4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tr.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uk.arb b/packages/flutter_localizations/lib/src/l10n/material_uk.arb index ea8064eaf5801..bccecc7fbb3a4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uk.arb @@ -149,5 +149,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ur.arb b/packages/flutter_localizations/lib/src/l10n/material_ur.arb index ead97a99eec6d..a4a191c49bf33 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ur.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uz.arb b/packages/flutter_localizations/lib/src/l10n/material_uz.arb index 142c03e2e751a..79087e036c220 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uz.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_vi.arb b/packages/flutter_localizations/lib/src/l10n/material_vi.arb index f55143dc197ba..ebb79d3b19311 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_vi.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh.arb b/packages/flutter_localizations/lib/src/l10n/material_zh.arb index 51fa714be58b5..cd473bbb924b0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh.arb @@ -143,5 +143,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zu.arb b/packages/flutter_localizations/lib/src/l10n/material_zu.arb index 4966a33debfc3..83f7755064085 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zu.arb @@ -142,5 +142,6 @@ "expandedHint": "Collapsed", "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up" + "lookUpButtonLabel": "Look Up", + "searchWebButtonLabel": "Search Web" } From f10a6ef75883fd9723f2711910eecaf5f7a4825a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 13:55:08 -0400 Subject: [PATCH 0593/1547] Roll Flutter Engine from 99fdac88f3c6 to 22bd35a19352 (3 revisions) (#132141) https://github.com/flutter/engine/compare/99fdac88f3c6...22bd35a19352 2023-08-08 chris@bracken.jp [macOS] Fix engine/binaryMessenger retain cycle (flutter/engine#44471) 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from f7162d33afb2 to 66ba512c613c (8 revisions) (flutter/engine#44497) 2023-08-08 mdebbar@google.com [web] Expose the benchmark callback through dart:ui_web (flutter/engine#44461) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0e0fe234270c8..d6a8393744976 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -99fdac88f3c620f56acb46b898760c53e702beae +22bd35a1935233fd360d1aa3bd6614de13232ee4 From a2f48a360f1cd516752bbd08a78e392000c4848b Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Tue, 8 Aug 2023 14:54:21 -0400 Subject: [PATCH 0594/1547] [web] Use benchmark callback from `dart:ui_web` (#132087) Depends on https://github.com/flutter/engine/pull/44461 Fixes https://github.com/flutter/flutter/issues/130175 Part of https://github.com/flutter/flutter/issues/126831 --- dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart index 3e867ac23f0bb..a119268ce3464 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart @@ -10,6 +10,7 @@ import 'dart:js_interop'; import 'dart:js_interop_unsafe'; import 'dart:math' as math; import 'dart:ui'; +import 'dart:ui_web' as ui_web; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -1335,8 +1336,7 @@ void registerEngineBenchmarkValueListener(String name, EngineBenchmarkValueListe if (_engineBenchmarkListeners.isEmpty) { // The first listener is being registered. Register the global listener. - web.window['_flutter_internal_on_benchmark'.toJS] = - _dispatchEngineBenchmarkValue.toJS; + ui_web.benchmarkValueCallback = _dispatchEngineBenchmarkValue; } _engineBenchmarkListeners[name] = listener; } @@ -1347,7 +1347,7 @@ void stopListeningToEngineBenchmarkValues(String name) { if (_engineBenchmarkListeners.isEmpty) { // The last listener unregistered. Remove the global listener. - web.window['_flutter_internal_on_benchmark'.toJS] = null; + ui_web.benchmarkValueCallback = null; } } From 0b81347897b97641b05978f3530cee8d745f2dc3 Mon Sep 17 00:00:00 2001 From: Aakash Pamnani <76067278+aakash-pamnani@users.noreply.github.com> Date: Wed, 9 Aug 2023 00:55:53 +0530 Subject: [PATCH 0595/1547] Paginated Data Table : Fixed Row number at footer in last page (#130389) Fixed the row count in the footer. Before ![image](https://github.com/flutter/flutter/assets/76067278/2365b85f-d896-4cea-a5b3-f043970bec98) After ![image](https://github.com/flutter/flutter/assets/76067278/69b18ecb-a3c9-44ea-961f-b4073ee0384d) *Issues Resolved* Fixes #80421 --- .../src/material/paginated_data_table.dart | 2 +- .../material/paginated_data_table_test.dart | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index 56dc56fbb0212..3c5fcdf5381dc 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -456,7 +456,7 @@ class PaginatedDataTableState extends State { Text( localizations.pageRowsInfoTitle( _firstRowIndex + 1, - _firstRowIndex + widget.rowsPerPage, + math.min(_firstRowIndex + widget.rowsPerPage, _rowCount), _rowCount, _rowCountApproximate, ), diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index b68223c4b18b6..6a10073823a11 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -170,6 +170,137 @@ void main() { log.clear(); }); + testWidgets('PaginatedDataTable footer page number', (WidgetTester tester) async { + final TestDataSource source = TestDataSource(); + int rowsPerPage = 2; + + Widget buildTable(TestDataSource source, int rowsPerPage) { + return PaginatedDataTable( + header: const Text('Test table'), + source: source, + rowsPerPage: rowsPerPage, + showFirstLastButtons: true, + availableRowsPerPage: const [ + 2, 3, 4, 5, 7, 8, + ], + onRowsPerPageChanged: (int? rowsPerPage) { + }, + onPageChanged: (int rowIndex) { + }, + columns: const [ + DataColumn(label: Text('Name')), + DataColumn(label: Text('Calories'), numeric: true), + DataColumn(label: Text('Generation')), + ], + ); + } + + await tester.pumpWidget(MaterialApp( + home: buildTable(source, rowsPerPage) + )); + + expect(find.text('1–2 of 500'), findsOneWidget); + + await tester.tap(find.byTooltip('Next page')); + await tester.pump(); + + expect(find.text('3–4 of 500'), findsOneWidget); + + final Finder lastPageButton = find.ancestor( + of: find.byTooltip('Last page'), + matching: find.byWidgetPredicate((Widget widget) => widget is IconButton), + ); + + expect(tester.widget(lastPageButton).onPressed, isNotNull); + + await tester.tap(lastPageButton); + await tester.pump(); + + expect(find.text('499–500 of 500'), findsOneWidget); + + final PaginatedDataTableState state = tester.state(find.byType(PaginatedDataTable)); + + state.pageTo(1); + rowsPerPage = 3; + + await tester.pumpWidget(MaterialApp( + home: buildTable(source, rowsPerPage) + )); + + expect(find.textContaining('1–3 of 500'), findsOneWidget); + + await tester.tap(find.byTooltip('Next page')); + await tester.pump(); + + expect(find.text('4–6 of 500'), findsOneWidget); + expect(tester.widget(lastPageButton).onPressed, isNotNull); + + await tester.tap(lastPageButton); + await tester.pump(); + + expect(find.text('499–500 of 500'), findsOneWidget); + + state.pageTo(1); + rowsPerPage = 4; + + await tester.pumpWidget(MaterialApp( + home: buildTable(source, rowsPerPage) + )); + + expect(find.textContaining('1–4 of 500'), findsOneWidget); + + await tester.tap(find.byTooltip('Next page')); + await tester.pump(); + + expect(find.text('5–8 of 500'), findsOneWidget); + expect(tester.widget(lastPageButton).onPressed, isNotNull); + + await tester.tap(lastPageButton); + await tester.pump(); + + expect(find.text('497–500 of 500'), findsOneWidget); + + state.pageTo(1); + rowsPerPage = 5; + + await tester.pumpWidget(MaterialApp( + home: buildTable(source, rowsPerPage) + )); + + expect(find.textContaining('1–5 of 500'), findsOneWidget); + + await tester.tap(find.byTooltip('Next page')); + await tester.pump(); + + expect(find.text('6–10 of 500'), findsOneWidget); + expect(tester.widget(lastPageButton).onPressed, isNotNull); + + await tester.tap(lastPageButton); + await tester.pump(); + + expect(find.text('496–500 of 500'), findsOneWidget); + + state.pageTo(1); + rowsPerPage = 8; + + await tester.pumpWidget(MaterialApp( + home: buildTable(source, rowsPerPage) + )); + + expect(find.textContaining('1–8 of 500'), findsOneWidget); + + await tester.tap(find.byTooltip('Next page')); + await tester.pump(); + + expect(find.text('9–16 of 500'), findsOneWidget); + expect(tester.widget(lastPageButton).onPressed, isNotNull); + + await tester.tap(lastPageButton); + await tester.pump(); + + expect(find.text('497–500 of 500'), findsOneWidget); + }); + testWidgets('PaginatedDataTable control test', (WidgetTester tester) async { TestDataSource source = TestDataSource() ..generation = 42; From ee47267d265bbe0691c2a1b5c3bd3e9e903c07a6 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 8 Aug 2023 22:37:16 +0300 Subject: [PATCH 0596/1547] Fix `TabBarTheme.indicatorColor` not applied in Material 2 (#132123) fixes [[Proposal] Improve TabBarTheme styling API for indicator color ](https://github.com/flutter/flutter/issues/130392) ### Description This fixes an issue where the `TabBarTheme.indicator` isn't applied in Material 2 and also adds indicator color tests for both M3 and M2. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [TabBar]. void main() => runApp(const TabBarApp()); class TabBarApp extends StatelessWidget { const TabBarApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( useMaterial3: false, tabBarTheme: const TabBarTheme( indicatorColor: Colors.amber, ) ), home: const TabBarExample(), ); } } class TabBarExample extends StatelessWidget { const TabBarExample({super.key}); @override Widget build(BuildContext context) { return DefaultTabController( initialIndex: 1, length: 3, child: Scaffold( appBar: AppBar( title: const Text('TabBar Sample'), bottom: const TabBar( tabs: [ Tab( icon: Icon(Icons.cloud_outlined), text: 'Cloudy', ), Tab( icon: Icon(Icons.beach_access_sharp), text: 'Sunny', ), Tab( icon: Icon(Icons.brightness_5_sharp), text: 'Rainy', ), ], ), ), body: const TabBarView( children: [ Center( child: Text("It's cloudy here"), ), Center( child: Text("It's rainy here"), ), Center( child: Text("It's sunny here"), ), ], ), ), ); } } ```
### Before ![Screenshot 2023-08-08 at 15 39 24](https://github.com/flutter/flutter/assets/48603081/9030e025-8615-45d0-a337-87ba2fdf6ca3) ### After ![Screenshot 2023-08-08 at 15 39 07](https://github.com/flutter/flutter/assets/48603081/4b98ac55-2d51-4a4c-93ba-7d36dc4be1d8) --- packages/flutter/lib/src/material/tabs.dart | 5 +- .../test/material/tab_bar_theme_test.dart | 86 +++++++++++++++++++ packages/flutter/test/material/tabs_test.dart | 1 - 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 2bb5f44971931..79e9954051f98 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -1220,10 +1220,7 @@ class _TabBarState extends State { return tabBarTheme.indicator!; } - Color color = widget.indicatorColor - ?? (theme.useMaterial3 - ? tabBarTheme.indicatorColor ?? _defaults.indicatorColor! - : Theme.of(context).indicatorColor); + Color color = widget.indicatorColor ?? tabBarTheme.indicatorColor ?? _defaults.indicatorColor!; // ThemeData tries to avoid this by having indicatorColor avoid being the // primaryColor. However, it's possible that the tab bar is on a // Material that isn't the primaryColor. In that case, if the indicator diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 4a6f518b6b2a4..e137c541ad963 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -1132,4 +1132,90 @@ void main() { expect(tabTwoRect.right, equals(tabTwoRight)); }); }); + + testWidgets('Material3 - TabBar indicator respects TabBarTheme.indicatorColor', (WidgetTester tester) async { + final List tabs = List.generate(4, (int index) { + return Tab(text: 'Tab $index'); + }); + + final TabController controller = TabController( + vsync: const TestVSync(), + length: tabs.length, + ); + + const Color tabBarThemeIndicatorColor = Color(0xffff0000); + + Widget buildTabBar({ required ThemeData theme }) { + return MaterialApp( + theme: theme, + home: Material( + child: Container( + alignment: Alignment.topLeft, + child: TabBar( + controller: controller, + tabs: tabs, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildTabBar(theme: ThemeData(useMaterial3: true))); + + RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + expect(tabBarBox,paints..rrect(color: ThemeData(useMaterial3: true).colorScheme.primary)); + + await tester.pumpWidget(buildTabBar(theme: ThemeData( + useMaterial3: true, + tabBarTheme: const TabBarTheme(indicatorColor: tabBarThemeIndicatorColor) + ))); + await tester.pumpAndSettle(); + + tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + expect(tabBarBox,paints..rrect(color: tabBarThemeIndicatorColor)); + }); + + testWidgets('Material2 - TabBar indicator respects TabBarTheme.indicatorColor', (WidgetTester tester) async { + final List tabs = List.generate(4, (int index) { + return Tab(text: 'Tab $index'); + }); + + final TabController controller = TabController( + vsync: const TestVSync(), + length: tabs.length, + ); + + const Color themeIndicatorColor = Color(0xffff0000); + const Color tabBarThemeIndicatorColor = Color(0xffffff00); + + Widget buildTabBar({ Color? themeIndicatorColor, Color? tabBarThemeIndicatorColor }) { + return MaterialApp( + theme: ThemeData( + indicatorColor: themeIndicatorColor, + tabBarTheme: TabBarTheme(indicatorColor: tabBarThemeIndicatorColor), + useMaterial3: false, + ), + home: Material( + child: Container( + alignment: Alignment.topLeft, + child: TabBar( + controller: controller, + tabs: tabs, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildTabBar(themeIndicatorColor: themeIndicatorColor)); + + RenderBox tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + expect(tabBarBox,paints..line(color: themeIndicatorColor)); + + await tester.pumpWidget(buildTabBar(tabBarThemeIndicatorColor: tabBarThemeIndicatorColor)); + await tester.pumpAndSettle(); + + tabBarBox = tester.firstRenderObject(find.byType(TabBar)); + expect(tabBarBox,paints..line(color: tabBarThemeIndicatorColor)); + }); } diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 4b78963de5321..1dc8234f5c562 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -488,7 +488,6 @@ void main() { const double indicatorWeight = 3.0; - final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack ? RRect.fromLTRBAndCorners( 64.75, From e2badf38570db7ee6526b778549d300b7d1c9ba5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 15:49:11 -0400 Subject: [PATCH 0597/1547] Roll Flutter Engine from 22bd35a19352 to dd03fae51d38 (3 revisions) (#132149) https://github.com/flutter/engine/compare/22bd35a19352...dd03fae51d38 2023-08-08 10456171+caroqliu@users.noreply.github.com Remove GFX branches from Flutter engine (flutter/engine#44401) 2023-08-08 jason-simmons@users.noreply.github.com Use the Clang unreachable code warning flag in the engine tree (flutter/engine#44458) 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 66ba512c613c to 30c0319e7e42 (3 revisions) (flutter/engine#44500) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d6a8393744976..431adbc18e247 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -22bd35a1935233fd360d1aa3bd6614de13232ee4 +dd03fae51d386a9ac0d0b3575e6d534d7529c1ee From 547bdefba810c0060bd0bfe4fe11ce604f8aa90a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 17:20:50 -0400 Subject: [PATCH 0598/1547] Roll Flutter Engine from dd03fae51d38 to 934ebb005d02 (4 revisions) (#132159) https://github.com/flutter/engine/compare/dd03fae51d38...934ebb005d02 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 6fa6fdd04783 to 5c8c7faf9131 (3 revisions) (flutter/engine#44506) 2023-08-08 55360120+Matt2D@users.noreply.github.com Flutter iOS Interactive Keyboard: Handle Pointer Up (flutter/engine#44457) 2023-08-08 30870216+gaaclarke@users.noreply.github.com [Impeller] improved glyph hashing performance (flutter/engine#44502) 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 30c0319e7e42 to 6fa6fdd04783 (2 revisions) (flutter/engine#44503) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 431adbc18e247..c08aadb7d9564 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -dd03fae51d386a9ac0d0b3575e6d534d7529c1ee +934ebb005d02785deb50650f620fc5241719fa7e From d5a0fcd5af87220e5ad6e9492da538e2f341a226 Mon Sep 17 00:00:00 2001 From: Lau Ching Jun Date: Tue, 8 Aug 2023 14:43:00 -0700 Subject: [PATCH 0599/1547] Locate the template directory using a TemplatePathProvider. (#132156) So that the paths can be overridden. --- .../lib/src/ios/application_package.dart | 2 +- packages/flutter_tools/lib/src/template.dart | 67 +++++++++++-------- .../test/general.shard/template_test.dart | 9 +-- 3 files changed, 44 insertions(+), 34 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/application_package.dart b/packages/flutter_tools/lib/src/ios/application_package.dart index 514b7d6798115..c760492cd4746 100644 --- a/packages/flutter_tools/lib/src/ios/application_package.dart +++ b/packages/flutter_tools/lib/src/ios/application_package.dart @@ -191,7 +191,7 @@ class BuildableIOSApp extends IOSApp { // Template asset's images are in flutter_template_images package. Future _templateImageAssetDirNameForImages(String asset) async { - final Directory imageTemplate = await templateImageDirectory(null, globals.fs, globals.logger); + final Directory imageTemplate = await templatePathProvider.imageDirectory(null, globals.fs, globals.logger); return globals.fs.path.join(imageTemplate.path, _templateImageAssetDirNameSuffix(asset)); } diff --git a/packages/flutter_tools/lib/src/template.dart b/packages/flutter_tools/lib/src/template.dart index 19a8c948a7382..b86046ae94a36 100644 --- a/packages/flutter_tools/lib/src/template.dart +++ b/packages/flutter_tools/lib/src/template.dart @@ -7,6 +7,7 @@ import 'package:package_config/package_config.dart'; import 'package:package_config/package_config_types.dart'; import 'base/common.dart'; +import 'base/context.dart'; import 'base/file_system.dart'; import 'base/logger.dart'; import 'base/template.dart'; @@ -19,6 +20,38 @@ import 'dart/package_map.dart'; /// https://kotlinlang.org/docs/keyword-reference.html const List kReservedKotlinKeywords = ['when', 'in', 'is']; +/// Provides the path where templates used by flutter_tools are stored. +class TemplatePathProvider { + const TemplatePathProvider(); + + /// Returns the directory containing the 'name' template directory. + Directory directoryInPackage(String name, FileSystem fileSystem) { + final String templatesDir = fileSystem.path.join(Cache.flutterRoot!, + 'packages', 'flutter_tools', 'templates'); + return fileSystem.directory(fileSystem.path.join(templatesDir, name)); + } + + /// Returns the directory containing the 'name' template directory in + /// flutter_template_images, to resolve image placeholder against. + /// if 'name' is null, return the parent template directory. + Future imageDirectory(String? name, FileSystem fileSystem, Logger logger) async { + final String toolPackagePath = fileSystem.path.join( + Cache.flutterRoot!, 'packages', 'flutter_tools'); + final String packageFilePath = fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json'); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + fileSystem.file(packageFilePath), + logger: logger, + ); + final Uri? imagePackageLibDir = packageConfig['flutter_template_images']?.packageUriRoot; + final Directory templateDirectory = fileSystem.directory(imagePackageLibDir) + .parent + .childDirectory('templates'); + return name == null ? templateDirectory : templateDirectory.childDirectory(name); + } +} + +TemplatePathProvider get templatePathProvider => context.get() ?? const TemplatePathProvider(); + /// Expands templates in a directory to a destination. All files that must /// undergo template expansion should end with the '.tmpl' extension. All files /// that should be replaced with the corresponding image from @@ -100,8 +133,8 @@ class Template { required TemplateRenderer templateRenderer, }) async { // All named templates are placed in the 'templates' directory - final Directory templateDir = _templateDirectoryInPackage(name, fileSystem); - final Directory imageDir = await templateImageDirectory(name, fileSystem, logger); + final Directory templateDir = templatePathProvider.directoryInPackage(name, fileSystem); + final Directory imageDir = await templatePathProvider.imageDirectory(name, fileSystem, logger); return Template._( [templateDir], [imageDir], @@ -122,12 +155,12 @@ class Template { return Template._( [ for (final String name in names) - _templateDirectoryInPackage(name, fileSystem), + templatePathProvider.directoryInPackage(name, fileSystem), ], [ for (final String name in names) - if ((await templateImageDirectory(name, fileSystem, logger)).existsSync()) - await templateImageDirectory(name, fileSystem, logger), + if ((await templatePathProvider.imageDirectory(name, fileSystem, logger)).existsSync()) + await templatePathProvider.imageDirectory(name, fileSystem, logger), ], fileSystem: fileSystem, logger: logger, @@ -344,30 +377,6 @@ class Template { } } -Directory _templateDirectoryInPackage(String name, FileSystem fileSystem) { - final String templatesDir = fileSystem.path.join(Cache.flutterRoot!, - 'packages', 'flutter_tools', 'templates'); - return fileSystem.directory(fileSystem.path.join(templatesDir, name)); -} - -/// Returns the directory containing the 'name' template directory in -/// flutter_template_images, to resolve image placeholder against. -/// if 'name' is null, return the parent template directory. -Future templateImageDirectory(String? name, FileSystem fileSystem, Logger logger) async { - final String toolPackagePath = fileSystem.path.join( - Cache.flutterRoot!, 'packages', 'flutter_tools'); - final String packageFilePath = fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json'); - final PackageConfig packageConfig = await loadPackageConfigWithLogging( - fileSystem.file(packageFilePath), - logger: logger, - ); - final Uri? imagePackageLibDir = packageConfig['flutter_template_images']?.packageUriRoot; - final Directory templateDirectory = fileSystem.directory(imagePackageLibDir) - .parent - .childDirectory('templates'); - return name == null ? templateDirectory : templateDirectory.childDirectory(name); -} - String _escapeKotlinKeywords(String androidIdentifier) { final List segments = androidIdentifier.split('.'); final List correctedSegments = segments.map( diff --git a/packages/flutter_tools/test/general.shard/template_test.dart b/packages/flutter_tools/test/general.shard/template_test.dart index 4f3cc55334d66..fa4bf6823df30 100644 --- a/packages/flutter_tools/test/general.shard/template_test.dart +++ b/packages/flutter_tools/test/general.shard/template_test.dart @@ -51,8 +51,9 @@ void main() { FileSystem: () => MemoryFileSystem.test(), ProcessManager: () => FakeProcessManager.any(), }; + const TemplatePathProvider templatePathProvider = TemplatePathProvider(); - testUsingContext('templateImageDirectory returns parent template directory if passed null name', () async { + testUsingContext('templatePathProvider.imageDirectory returns parent template directory if passed null name', () async { final String packageConfigPath = globals.fs.path.join( Cache.flutterRoot!, 'packages', @@ -77,7 +78,7 @@ void main() { } '''); expect( - (await templateImageDirectory(null, globals.fs, globals.logger)).path, + (await templatePathProvider.imageDirectory(null, globals.fs, globals.logger)).path, globals.fs.path.absolute( 'flutter_template_images', 'templates', @@ -85,7 +86,7 @@ void main() { ); }, overrides: overrides); - testUsingContext('templateImageDirectory returns the directory containing the `name` template directory', () async { + testUsingContext('templatePathProvider.imageDirectory returns the directory containing the `name` template directory', () async { final String packageConfigPath = globals.fs.path.join( Cache.flutterRoot!, 'packages', @@ -109,7 +110,7 @@ void main() { } '''); expect( - (await templateImageDirectory('app_shared', globals.fs, globals.logger)).path, + (await templatePathProvider.imageDirectory('app_shared', globals.fs, globals.logger)).path, globals.fs.path.absolute( 'flutter_template_images', 'templates', From b29069ec0bacfd76168d2fd8d6e2cdc9852920d3 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 8 Aug 2023 15:08:30 -0700 Subject: [PATCH 0600/1547] Document that missed_frame_build_budget_count is misleading (#132137) Fixes https://github.com/flutter/flutter/issues/109745 --- .../lib/src/driver/timeline_summary.dart | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/packages/flutter_driver/lib/src/driver/timeline_summary.dart b/packages/flutter_driver/lib/src/driver/timeline_summary.dart index ac36850f45824..6d580bd551b96 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -31,7 +31,11 @@ generated by the interaction. '''; /// The maximum amount of time considered safe to spend for a frame's build -/// phase. Anything past that is in the danger of missing the frame as 60FPS. +/// phase. Anything past that is in the danger of missing the frame at 60FPS. +/// +/// This is a hard-coded number and does not take into account the real device +/// frame rate. Prefer using percentiles on the total build or raster time +/// than metrics based on this value. const Duration kBuildBudget = Duration(milliseconds: 16); /// The name of the framework frame build events we need to filter or extract. @@ -71,9 +75,14 @@ class TimelineSummary { /// The number of frames that missed the [kBuildBudget] and therefore are /// in the danger of missing frames. - int computeMissedFrameBuildBudgetCount([ Duration frameBuildBudget = kBuildBudget ]) => _extractFrameDurations() - .where((Duration duration) => duration > kBuildBudget) - .length; + /// + /// This does not take into account the real device frame rate. Prefer using + /// [computePercentileFrameBuildTimeMillis] for evaluating performance. + int computeMissedFrameBuildBudgetCount() { + return _extractFrameDurations() + .where((Duration duration) => duration > kBuildBudget) + .length; + } /// Average amount of time spent per frame in the engine rasterizer. /// @@ -112,9 +121,14 @@ class TimelineSummary { /// The number of frames that missed the [kBuildBudget] on the raster thread /// and therefore are in the danger of missing frames. - int computeMissedFrameRasterizerBudgetCount([ Duration frameBuildBudget = kBuildBudget ]) => _extractGpuRasterizerDrawDurations() - .where((Duration duration) => duration > kBuildBudget) - .length; + /// + /// This does not take into account the real device frame rate. Prefer using + /// [computePercentileFrameRasterizerTimeMillis] for evaluating performance. + int computeMissedFrameRasterizerBudgetCount() { + return _extractGpuRasterizerDrawDurations() + .where((Duration duration) => duration > kBuildBudget) + .length; + } /// The total number of frames recorded in the timeline. int countFrames() => _extractFrameDurations().length; @@ -156,7 +170,8 @@ class TimelineSummary { /// See [computeWorstFrameBuildTimeMillis]. /// * "missed_frame_build_budget_count': The number of frames that missed /// the [kBuildBudget] and therefore are in the danger of missing frames. - /// See [computeMissedFrameBuildBudgetCount]. + /// See [computeMissedFrameBuildBudgetCount]. Because [kBuildBudget] is a + /// constant, this does not represent a real missed frame count. /// * "average_frame_rasterizer_time_millis": Average amount of time spent /// per frame in the engine rasterizer. /// See [computeAverageFrameRasterizerTimeMillis]. @@ -172,8 +187,9 @@ class TimelineSummary { /// See [computeWorstFrameRasterizerTimeMillis]. /// * "missed_frame_rasterizer_budget_count": The number of frames that missed /// the [kBuildBudget] on the raster thread and therefore are in the danger - /// of missing frames. - /// See [computeMissedFrameRasterizerBudgetCount]. + /// of missing frames. See [computeMissedFrameRasterizerBudgetCount]. + /// Because [kBuildBudget] is a constant, this does not represent a real + /// missed frame count. /// * "frame_count": The total number of frames recorded in the timeline. This /// is also the length of the "frame_build_times" and the "frame_begin_times" /// lists. From e65c37ee45d8dfe19ea64da159cc0e5f1e07ae9d Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 8 Aug 2023 15:08:32 -0700 Subject: [PATCH 0601/1547] More PageStorage clarity in the documentation (#131954) Fixes https://github.com/flutter/flutter/issues/10867 --- .../lib/src/material/expansion_tile.dart | 6 ++-- .../src/material/paginated_data_table.dart | 3 ++ .../flutter/lib/src/widgets/page_storage.dart | 28 ++++++++++--------- .../flutter/lib/src/widgets/page_view.dart | 8 ++++++ .../lib/src/widgets/scroll_position.dart | 2 -- .../flutter/lib/src/widgets/scroll_view.dart | 16 +++++++++++ .../flutter/lib/src/widgets/scrollable.dart | 8 ++++++ .../src/widgets/single_child_scroll_view.dart | 2 ++ 8 files changed, 55 insertions(+), 18 deletions(-) diff --git a/packages/flutter/lib/src/material/expansion_tile.dart b/packages/flutter/lib/src/material/expansion_tile.dart index 3dc8e99f8647b..bf865d39f4360 100644 --- a/packages/flutter/lib/src/material/expansion_tile.dart +++ b/packages/flutter/lib/src/material/expansion_tile.dart @@ -184,9 +184,9 @@ class ExpansionTileController { /// A single-line [ListTile] with an expansion arrow icon that expands or collapses /// the tile to reveal or hide the [children]. /// -/// This widget is typically used with [ListView] to create an -/// "expand / collapse" list entry. When used with scrolling widgets like -/// [ListView], a unique [PageStorageKey] must be specified to enable the +/// This widget is typically used with [ListView] to create an "expand / +/// collapse" list entry. When used with scrolling widgets like [ListView], a +/// unique [PageStorageKey] must be specified as the [key], to enable the /// [ExpansionTile] to save and restore its expanded state when it is scrolled /// in and out of view. /// diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index 3c5fcdf5381dc..ef85796455910 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -28,6 +28,9 @@ import 'theme.dart'; /// Data is read lazily from a [DataTableSource]. The widget is presented /// as a [Card]. /// +/// If the [key] is a [PageStorageKey], the [initialFirstRowIndex] is persisted +/// to [PageStorage]. +/// /// See also: /// /// * [DataTable], which is not paginated. diff --git a/packages/flutter/lib/src/widgets/page_storage.dart b/packages/flutter/lib/src/widgets/page_storage.dart index 1cedea07b1419..0a0da4e4103ba 100644 --- a/packages/flutter/lib/src/widgets/page_storage.dart +++ b/packages/flutter/lib/src/widgets/page_storage.dart @@ -9,17 +9,19 @@ import 'framework.dart'; // Examples can assume: // late BuildContext context; -/// A key can be used to persist the widget state in storage after -/// the destruction and will be restored when recreated. +/// A [Key] that can be used to persist the widget state in storage after the +/// destruction and will be restored when recreated. /// -/// Each key with its value plus the ancestor chain of other PageStorageKeys need to -/// be unique within the widget's closest ancestor [PageStorage]. To make it possible for a -/// saved value to be found when a widget is recreated, the key's value must -/// not be objects whose identity will change each time the widget is created. +/// Each key with its value plus the ancestor chain of other [PageStorageKey]s +/// need to be unique within the widget's closest ancestor [PageStorage]. To +/// make it possible for a saved value to be found when a widget is recreated, +/// the key's value must not be objects whose identity will change each time the +/// widget is created. /// /// See also: /// -/// * [PageStorage], which is the closet ancestor for [PageStorageKey]. +/// * [PageStorage], which manages the data storage for widgets using +/// [PageStorageKey]s. class PageStorageKey extends ValueKey { /// Creates a [ValueKey] that defines where [PageStorage] values will be saved. const PageStorageKey(super.value); @@ -136,12 +138,12 @@ class PageStorageBucket { /// included in routes. /// /// [PageStorageKey] is used by [Scrollable] if [ScrollController.keepScrollOffset] -/// is enabled to save their [ScrollPosition]s. When more than one -/// scrollable ([ListView], [SingleChildScrollView], [TextField], etc.) appears -/// within the widget's closest ancestor [PageStorage] (such as within the same route), -/// if you want to save all of their positions independently, -/// you should give each of them unique [PageStorageKey]s, or set some of their -/// `keepScrollOffset` false to prevent saving. +/// is enabled to save their [ScrollPosition]s. When more than one scrollable +/// ([ListView], [SingleChildScrollView], [TextField], etc.) appears within the +/// widget's closest ancestor [PageStorage] (such as within the same route), to +/// save all of their positions independently, one must give each of them unique +/// [PageStorageKey]s, or set the `keepScrollOffset` property of some such +/// widgets to false to prevent saving. /// /// {@tool dartpad} /// This sample shows how to explicitly use a [PageStorage] to diff --git a/packages/flutter/lib/src/widgets/page_view.dart b/packages/flutter/lib/src/widgets/page_view.dart index 9660ddefb3dbe..5d75be724366e 100644 --- a/packages/flutter/lib/src/widgets/page_view.dart +++ b/packages/flutter/lib/src/widgets/page_view.dart @@ -612,6 +612,14 @@ const PageScrollPhysics _kPagePhysics = PageScrollPhysics(); /// ** See code in examples/api/lib/widgets/page_view/page_view.0.dart ** /// {@end-tool} /// +/// ## Persisting the scroll position during a session +/// +/// Scroll views attempt to persist their scroll position using [PageStorage]. +/// For a [PageView], this can be disabled by setting [PageController.keepPage] +/// to false on the [controller]. If it is enabled, using a [PageStorageKey] for +/// the [key] of this widget is recommended to help disambiguate different +/// scroll views from each other. +/// /// See also: /// /// * [PageController], which controls which page is visible in the view. diff --git a/packages/flutter/lib/src/widgets/scroll_position.dart b/packages/flutter/lib/src/widgets/scroll_position.dart index e9154a1218afb..6311b1aae493c 100644 --- a/packages/flutter/lib/src/widgets/scroll_position.dart +++ b/packages/flutter/lib/src/widgets/scroll_position.dart @@ -178,8 +178,6 @@ enum ScrollPositionAlignmentPolicy { abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { /// Creates an object that determines which portion of the content is visible /// in a scroll view. - /// - /// The [physics], [context], and [keepScrollOffset] parameters must not be null. ScrollPosition({ required this.physics, required this.context, diff --git a/packages/flutter/lib/src/widgets/scroll_view.dart b/packages/flutter/lib/src/widgets/scroll_view.dart index 33708cc11d648..47a1bddc3ab08 100644 --- a/packages/flutter/lib/src/widgets/scroll_view.dart +++ b/packages/flutter/lib/src/widgets/scroll_view.dart @@ -61,6 +61,16 @@ enum ScrollViewKeyboardDismissBehavior { /// To control the initial scroll offset of the scroll view, provide a /// [controller] with its [ScrollController.initialScrollOffset] property set. /// +/// {@template flutter.widgets.ScrollView.PageStorage} +/// ## Persisting the scroll position during a session +/// +/// Scroll views attempt to persist their scroll position using [PageStorage]. +/// This can be disabled by setting [ScrollController.keepScrollOffset] to false +/// on the [controller]. If it is enabled, using a [PageStorageKey] for the +/// [key] of this widget is recommended to help disambiguate different scroll +/// views from each other. +/// {@endtemplate} +/// /// See also: /// /// * [ListView], which is a commonly used [ScrollView] that displays a @@ -619,6 +629,8 @@ abstract class ScrollView extends StatelessWidget { /// parameter `semanticChildCount`. This should always be the same as the /// number of widgets wrapped in [IndexedSemantics]. /// +/// {@macro flutter.widgets.ScrollView.PageStorage} +/// /// See also: /// /// * [SliverList], which is a sliver that displays linear list of children. @@ -1165,6 +1177,8 @@ abstract class BoxScrollView extends ScrollView { /// /// {@macro flutter.widgets.BoxScroll.scrollBehaviour} /// +/// {@macro flutter.widgets.ScrollView.PageStorage} +/// /// See also: /// /// * [SingleChildScrollView], which is a scrollable widget that has a single @@ -1810,6 +1824,8 @@ class ListView extends BoxScrollView { /// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart ** /// {@end-tool} /// +/// {@macro flutter.widgets.ScrollView.PageStorage} +/// /// See also: /// /// * [SingleChildScrollView], which is a scrollable widget that has a single diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index 17a90007d42bb..1331de1d57de0 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -72,6 +72,14 @@ typedef TwoDimensionalViewportBuilder = Widget Function(BuildContext context, Vi /// [PageController], which creates a page-oriented scroll position subclass /// that keeps the same page visible when the [Scrollable] resizes. /// +/// ## Persisting the scroll position during a session +/// +/// Scrollables attempt to persist their scroll position using [PageStorage]. +/// This can be disabled by setting [ScrollController.keepScrollOffset] to false +/// on the [controller]. If it is enabled, using a [PageStorageKey] for the +/// [key] of this widget (or one of its ancestors, e.g. a [ScrollView]) is +/// recommended to help disambiguate different [Scrollable]s from each other. +/// /// See also: /// /// * [ListView], which is a commonly used [ScrollView] that displays a diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index 818a8a1ad4487..3255c328eb641 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -130,6 +130,8 @@ import 'scrollable.dart'; /// ** See code in examples/api/lib/widgets/single_child_scroll_view/single_child_scroll_view.1.dart ** /// {@end-tool} /// +/// {@macro flutter.widgets.ScrollView.PageStorage} +/// /// See also: /// /// * [ListView], which handles multiple children in a scrolling list. From b77b149df653cfb43d823bfd2838b4f122ce652b Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 9 Aug 2023 01:23:30 +0300 Subject: [PATCH 0602/1547] Add `PopupMenuButton.iconColor`, `PopupMenuTheme.iconSize` and fix button icon using unexpected color propert (#132054) fixes [PopupMenuButton uses color property for icon color](https://github.com/flutter/flutter/issues/127802) fixes [`popup_menu_test.dart` lacks default icon color tests.](https://github.com/flutter/flutter/issues/132050) ### Description - Add `PopupMenuButton..iconColor` and fix the PopupMenu button icon using an unexpected color property. - Add the missing `PopupMenuTheme.iconSize`. - Clean up some tests and minor improvements. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [PopupMenuButton]. // This is the type used by the popup menu below. enum SampleItem { itemOne, itemTwo, itemThree } void main() => runApp(const PopupMenuApp()); class PopupMenuApp extends StatelessWidget { const PopupMenuApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( popupMenuTheme: PopupMenuThemeData( // iconSize: 75, // iconColor: Colors.amber, color: Colors.deepPurple[100], ), ), home: const PopupMenuExample(), ); } } class PopupMenuExample extends StatefulWidget { const PopupMenuExample({super.key}); @override State createState() => _PopupMenuExampleState(); } class _PopupMenuExampleState extends State { SampleItem? selectedMenu; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('PopupMenuButton')), body: Center( child: PopupMenuButton( iconSize: 75, // iconColor: Colors.amber, color: Colors.deepPurple[100], initialValue: selectedMenu, // Callback that sets the selected popup menu item. onSelected: (SampleItem item) { setState(() { selectedMenu = item; }); }, itemBuilder: (BuildContext context) => >[ const PopupMenuItem( value: SampleItem.itemOne, child: Text('Item 1'), ), const PopupMenuItem( value: SampleItem.itemTwo, child: Text('Item 2'), ), const PopupMenuDivider(), const CheckedPopupMenuItem( value: SampleItem.itemThree, checked: true, child: Text('Item 3'), ), ], ), ), ); } } ```
![Group 2](https://github.com/flutter/flutter/assets/48603081/eb5404ae-2a07-4374-9821-66a0bbea041e) ![Group 1](https://github.com/flutter/flutter/assets/48603081/464e3957-1afb-4118-abcc-aad12591dc51) --- .../flutter/lib/src/material/popup_menu.dart | 13 +++- .../lib/src/material/popup_menu_theme.dart | 22 ++++++- .../test/material/popup_menu_test.dart | 59 ++++++++++--------- .../test/material/popup_menu_theme_test.dart | 58 +++++++++++++----- 4 files changed, 108 insertions(+), 44 deletions(-) diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 60081cf0a619c..ef8f4367c6b43 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -1111,6 +1111,7 @@ class PopupMenuButton extends StatefulWidget { this.enabled = true, this.shape, this.color, + this.iconColor, this.enableFeedback, this.constraints, this.position, @@ -1221,6 +1222,13 @@ class PopupMenuButton extends StatefulWidget { /// Theme.of(context).cardColor is used. final Color? color; + /// If provided, this color is used for the button icon. + /// + /// If this property is null, then [PopupMenuThemeData.iconColor] is used. + /// If [PopupMenuThemeData.iconColor] is also null then defaults to + /// [IconThemeData.color]. + final Color? iconColor; + /// Whether detected gestures should provide acoustic and/or haptic feedback. /// /// For example, on Android a tap will produce a clicking sound and a @@ -1355,6 +1363,7 @@ class PopupMenuButtonState extends State> { @override Widget build(BuildContext context) { final IconThemeData iconTheme = IconTheme.of(context); + final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context); final bool enableFeedback = widget.enableFeedback ?? PopupMenuTheme.of(context).enableFeedback ?? true; @@ -1378,8 +1387,8 @@ class PopupMenuButtonState extends State> { icon: widget.icon ?? Icon(Icons.adaptive.more), padding: widget.padding, splashRadius: widget.splashRadius, - iconSize: widget.iconSize ?? iconTheme.size, - color: widget.color ?? iconTheme.color, + iconSize: widget.iconSize ?? popupMenuTheme.iconSize ?? iconTheme.size, + color: widget.iconColor ?? popupMenuTheme.iconColor ?? iconTheme.color, tooltip: widget.tooltip ?? MaterialLocalizations.of(context).showMenuTooltip, onPressed: widget.enabled ? showButtonMenu : null, enableFeedback: enableFeedback, diff --git a/packages/flutter/lib/src/material/popup_menu_theme.dart b/packages/flutter/lib/src/material/popup_menu_theme.dart index 368492d0c51a3..eeda6177114b2 100644 --- a/packages/flutter/lib/src/material/popup_menu_theme.dart +++ b/packages/flutter/lib/src/material/popup_menu_theme.dart @@ -55,6 +55,8 @@ class PopupMenuThemeData with Diagnosticable { this.enableFeedback, this.mouseCursor, this.position, + this.iconColor, + this.iconSize, }); /// The background color of the popup menu. @@ -95,6 +97,12 @@ class PopupMenuThemeData with Diagnosticable { /// popup menu appear directly over the button that was used to create it. final PopupMenuPosition? position; + /// The color of the icon in the popup menu button. + final Color? iconColor; + + /// The size of the icon in the popup menu button. + final double? iconSize; + /// Creates a copy of this object with the given fields replaced with the /// new values. PopupMenuThemeData copyWith({ @@ -108,6 +116,8 @@ class PopupMenuThemeData with Diagnosticable { bool? enableFeedback, MaterialStateProperty? mouseCursor, PopupMenuPosition? position, + Color? iconColor, + double? iconSize, }) { return PopupMenuThemeData( color: color ?? this.color, @@ -120,6 +130,8 @@ class PopupMenuThemeData with Diagnosticable { enableFeedback: enableFeedback ?? this.enableFeedback, mouseCursor: mouseCursor ?? this.mouseCursor, position: position ?? this.position, + iconColor: iconColor ?? this.iconColor, + iconSize: iconSize ?? this.iconSize, ); } @@ -143,6 +155,8 @@ class PopupMenuThemeData with Diagnosticable { enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback, mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, position: t < 0.5 ? a?.position : b?.position, + iconColor: Color.lerp(a?.iconColor, b?.iconColor, t), + iconSize: lerpDouble(a?.iconSize, b?.iconSize, t), ); } @@ -158,6 +172,8 @@ class PopupMenuThemeData with Diagnosticable { enableFeedback, mouseCursor, position, + iconColor, + iconSize, ); @override @@ -178,7 +194,9 @@ class PopupMenuThemeData with Diagnosticable { && other.labelTextStyle == labelTextStyle && other.enableFeedback == enableFeedback && other.mouseCursor == mouseCursor - && other.position == position; + && other.position == position + && other.iconColor == iconColor + && other.iconSize == iconSize; } @override @@ -194,6 +212,8 @@ class PopupMenuThemeData with Diagnosticable { properties.add(DiagnosticsProperty('enableFeedback', enableFeedback, defaultValue: null)); properties.add(DiagnosticsProperty>('mouseCursor', mouseCursor, defaultValue: null)); properties.add(EnumProperty('position', position, defaultValue: null)); + properties.add(ColorProperty('iconColor', iconColor, defaultValue: null)); + properties.add(DoubleProperty('iconSize', iconSize, defaultValue: null)); } } diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index c986b90586077..f26ed5a03adc7 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -199,7 +199,7 @@ void main() { expect(cancels, equals(2)); }); - testWidgets('disabled PopupMenuButton will not call itemBuilder, onOpened, onSelected or onCanceled', (WidgetTester tester) async { + testWidgets('Disabled PopupMenuButton will not call itemBuilder, onOpened, onSelected or onCanceled', (WidgetTester tester) async { final GlobalKey popupButtonKey = GlobalKey(); bool itemBuilderCalled = false; bool onOpenedCalled = false; @@ -326,7 +326,7 @@ void main() { expect(onSelectedCalled, isFalse); }); - testWidgets('disabled PopupMenuButton is focusable with directional navigation', (WidgetTester tester) async { + testWidgets('Disabled PopupMenuButton is focusable with directional navigation', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final GlobalKey childKey = GlobalKey(); @@ -1084,7 +1084,7 @@ void main() { expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), const Offset(50.0, 50.0)); }); - testWidgets('open PopupMenu has correct semantics', (WidgetTester tester) async { + testWidgets('Opened PopupMenu has correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( MaterialApp( @@ -1296,7 +1296,7 @@ void main() { semantics.dispose(); }); - testWidgets('disabled PopupMenuItem has correct semantics', (WidgetTester tester) async { + testWidgets('Disabled PopupMenuItem has correct semantics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/45044. final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2576,32 +2576,30 @@ void main() { }); }); - testWidgets('iconSize parameter tests', (WidgetTester tester) async { - Future buildFrame({double? iconSize}) { - return tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Center( - child: PopupMenuButton( - iconSize: iconSize, - itemBuilder: (_) => >[ - const PopupMenuItem( - value: 'value', - child: Text('child'), - ), - ], - ), + testWidgets('Can customize PopupMenuButton icon', (WidgetTester tester) async { + const Color iconColor = Color(0xffffff00); + const double iconSize = 29.5; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Center( + child: PopupMenuButton( + iconColor: iconColor, + iconSize: iconSize, + itemBuilder: (_) => >[ + const PopupMenuItem( + value: 'value', + child: Text('child'), + ), + ], ), ), ), - ); - } - - await buildFrame(); - expect(tester.getSize(find.byIcon(Icons.adaptive.more)), const Size(24, 24)); + ), + ); - await buildFrame(iconSize: 50); - expect(tester.getSize(find.byIcon(Icons.adaptive.more)), const Size(50, 50)); + expect(_iconStyle(tester, Icons.adaptive.more)?.color, iconColor); + expect(tester.getSize(find.byIcon(Icons.adaptive.more)), const Size(iconSize, iconSize)); }); testWidgets('does not crash in small overlay', (WidgetTester tester) async { @@ -3265,7 +3263,7 @@ void main() { expect(childBottomLeft, menuTopLeft); }); - testWidgets('PopupmenuItem onTap should be calling after Navigator.pop', (WidgetTester tester) async { + testWidgets('PopupMenuItem onTap should be calling after Navigator.pop', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -3494,3 +3492,10 @@ TextStyle? _labelStyle(WidgetTester tester, String label) { matching: find.byType(RichText), )).text.style; } + +TextStyle? _iconStyle(WidgetTester tester, IconData icon) { + return tester.widget(find.descendant( + of: find.byIcon(icon), + matching: find.byType(RichText), + )).text.style; +} diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index e2b5ba6444803..4096d698f8e5f 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -43,6 +43,8 @@ PopupMenuThemeData _popupMenuThemeM3() { } return SystemMouseCursors.alias; }), + iconColor: const Color(0xfff12099), + iconSize: 17.0, ); } @@ -86,19 +88,23 @@ void main() { testWidgetsWithLeakTracking('PopupMenuThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); PopupMenuThemeData( - color: const Color(0xFFFFFFFF), + color: const Color(0xfffffff1), shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), elevation: 2.0, - shadowColor: const Color(0xff00ff00), - surfaceTintColor: const Color(0xff00ff00), - textStyle: const TextStyle(color: Color(0xffffffff)), + shadowColor: const Color(0xfffffff2), + surfaceTintColor: const Color(0xfffffff3), + textStyle: const TextStyle(color: Color(0xfffffff4)), labelTextStyle: MaterialStateProperty.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { - return const TextStyle(color: Color(0xfff99ff0), fontSize: 12.0); + return const TextStyle(color: Color(0xfffffff5), fontSize: 12.0); } - return const TextStyle(color: Color(0xfff12099), fontSize: 17.0); + return const TextStyle(color: Color(0xfffffff6), fontSize: 17.0); }), + enableFeedback: false, mouseCursor: MaterialStateMouseCursor.clickable, + position: PopupMenuPosition.over, + iconColor: const Color(0xfffffff8), + iconSize: 31.0, ).debugFillProperties(builder); final List description = builder.properties @@ -107,14 +113,18 @@ void main() { .toList(); expect(description, [ - 'color: Color(0xffffffff)', + 'color: Color(0xfffffff1)', 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'elevation: 2.0', - 'shadowColor: Color(0xff00ff00)', - 'surfaceTintColor: Color(0xff00ff00)', - 'text style: TextStyle(inherit: true, color: Color(0xffffffff))', + 'shadowColor: Color(0xfffffff2)', + 'surfaceTintColor: Color(0xfffffff3)', + 'text style: TextStyle(inherit: true, color: Color(0xfffffff4))', "labelTextStyle: Instance of '_MaterialStatePropertyWith'", + 'enableFeedback: false', 'mouseCursor: MaterialStateMouseCursor(clickable)', + 'position: over', + 'iconColor: Color(0xfffffff8)', + 'iconSize: 31.0' ]); }); @@ -165,6 +175,9 @@ void main() { ), )); + // Test default button icon color. + expect(_iconStyle(tester, Icons.adaptive.more)?.color, theme.iconTheme.color); + await tester.tap(find.byKey(popupButtonKey)); await tester.pumpAndSettle(); @@ -282,6 +295,9 @@ void main() { ), )); + expect(_iconStyle(tester, Icons.adaptive.more)?.color, popupMenuTheme.iconColor); + expect(tester.getSize(find.byIcon(Icons.adaptive.more)), Size(popupMenuTheme.iconSize!, popupMenuTheme.iconSize!)); + await tester.tap(find.byKey(popupButtonKey)); await tester.pumpAndSettle(); @@ -354,15 +370,17 @@ void main() { final Key popupButtonApp = UniqueKey(); final Key popupItemKey = UniqueKey(); - const Color color = Colors.purple; - const Color surfaceTintColor = Colors.amber; - const Color shadowColor = Colors.green; + const Color color = Color(0xfff11fff); + const Color surfaceTintColor = Color(0xfff12fff); + const Color shadowColor = Color(0xfff13fff); const ShapeBorder shape = RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(9.0)), ); const double elevation = 7.0; - const TextStyle textStyle = TextStyle(color: Color(0xffffffef), fontSize: 19.0); + const TextStyle textStyle = TextStyle(color: Color(0xfff14fff), fontSize: 19.0); const MouseCursor cursor = SystemMouseCursors.forbidden; + const Color iconColor = Color(0xfff15fff); + const double iconSize = 21.5; await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true, popupMenuTheme: popupMenuTheme), @@ -377,6 +395,8 @@ void main() { surfaceTintColor: surfaceTintColor, color: color, shape: shape, + iconColor: iconColor, + iconSize: iconSize, itemBuilder: (BuildContext context) { return >[ PopupMenuItem( @@ -398,6 +418,9 @@ void main() { ), )); + expect(_iconStyle(tester, Icons.adaptive.more)?.color, iconColor); + expect(tester.getSize(find.byIcon(Icons.adaptive.more)), const Size(iconSize, iconSize)); + await tester.tap(find.byKey(popupButtonKey)); await tester.pumpAndSettle(); @@ -719,3 +742,10 @@ void main() { Set enabled = {}; Set disabled = {MaterialState.disabled}; + +TextStyle? _iconStyle(WidgetTester tester, IconData icon) { + return tester.widget(find.descendant( + of: find.byIcon(icon), + matching: find.byType(RichText), + )).text.style; +} From 2728ba0f23aeed05ae752cdd60e940dadf942ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20S=20Guerrero?= Date: Tue, 8 Aug 2023 16:16:52 -0700 Subject: [PATCH 0603/1547] Revert of #120385 (#132167) Breaking google testing revert of: https://github.com/flutter/flutter/pull/120385 b/295065534 --- .../cupertino/cupertino_navigation_demo.dart | 4 +- .../material/full_screen_dialog_demo.dart | 31 +- .../demo/material/text_form_field_demo.dart | 19 +- .../demo/shrine/expanding_bottom_sheet.dart | 14 +- .../flutter_gallery/lib/gallery/home.dart | 14 +- .../navigation_bar/navigation_bar.2.dart | 8 +- examples/api/lib/widgets/form/form.1.dart | 166 ---- .../navigator_pop_handler.0.dart | 164 ---- .../navigator_pop_handler.1.dart | 250 ----- .../lib/widgets/pop_scope/pop_scope.0.dart | 128 --- .../will_pop_scope/will_pop_scope.0.dart | 77 ++ .../api/test/widgets/form/form.1_test.dart | 37 - .../navigator_pop_handler.0_test.dart | 48 - .../navigator_pop_handler.1_test.dart | 38 - .../api/test/widgets/navigator_utils.dart | 20 - .../widgets/pop_scope/pop_scope.0_test.dart | 66 -- .../will_pop_scope/will_pop_scope.0_test.dart | 32 + packages/flutter/lib/src/cupertino/app.dart | 6 - packages/flutter/lib/src/cupertino/route.dart | 3 +- .../flutter/lib/src/cupertino/tab_view.dart | 28 +- packages/flutter/lib/src/material/about.dart | 13 +- packages/flutter/lib/src/material/app.dart | 6 - .../lib/src/services/system_navigator.dart | 34 - packages/flutter/lib/src/widgets/app.dart | 80 +- packages/flutter/lib/src/widgets/binding.dart | 28 +- packages/flutter/lib/src/widgets/form.dart | 59 +- .../flutter/lib/src/widgets/navigator.dart | 294 +----- .../src/widgets/navigator_pop_handler.dart | 110 --- .../flutter/lib/src/widgets/pop_scope.dart | 137 --- packages/flutter/lib/src/widgets/routes.dart | 217 ++--- .../lib/src/widgets/will_pop_scope.dart | 17 +- packages/flutter/lib/widgets.dart | 2 - .../test/cupertino/tab_scaffold_test.dart | 131 +-- .../flutter/test/widgets/navigator_test.dart | 866 ------------------ .../flutter/test/widgets/navigator_utils.dart | 20 - .../flutter/test/widgets/pop_scope_test.dart | 361 -------- 36 files changed, 302 insertions(+), 3226 deletions(-) delete mode 100644 examples/api/lib/widgets/form/form.1.dart delete mode 100644 examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart delete mode 100644 examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart delete mode 100644 examples/api/lib/widgets/pop_scope/pop_scope.0.dart create mode 100644 examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart delete mode 100644 examples/api/test/widgets/form/form.1_test.dart delete mode 100644 examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart delete mode 100644 examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart delete mode 100644 examples/api/test/widgets/navigator_utils.dart delete mode 100644 examples/api/test/widgets/pop_scope/pop_scope.0_test.dart create mode 100644 examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart delete mode 100644 packages/flutter/lib/src/widgets/navigator_pop_handler.dart delete mode 100644 packages/flutter/lib/src/widgets/pop_scope.dart delete mode 100644 packages/flutter/test/widgets/navigator_utils.dart delete mode 100644 packages/flutter/test/widgets/pop_scope_test.dart diff --git a/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart index a68c2a194c9b7..f6626b85e20dd 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart @@ -48,9 +48,9 @@ class CupertinoNavigationDemo extends StatelessWidget { @override Widget build(BuildContext context) { - return PopScope( + return WillPopScope( // Prevent swipe popping of this page. Use explicit exit buttons only. - canPop: false, + onWillPop: () => Future.value(true), child: DefaultTextStyle( style: CupertinoTheme.of(context).textTheme.textStyle, child: CupertinoTabScaffold( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart index 81ee4dacd8643..b6f7bbe6b6afb 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; // This demo is based on @@ -110,15 +109,16 @@ class FullScreenDialogDemoState extends State { bool _hasName = false; late String _eventName; - Future _handlePopInvoked(bool didPop) async { - if (didPop) { - return; + Future _onWillPop() async { + _saveNeeded = _hasLocation || _hasName || _saveNeeded; + if (!_saveNeeded) { + return true; } final ThemeData theme = Theme.of(context); final TextStyle dialogTextStyle = theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); - final bool? shouldDiscard = await showDialog( + return showDialog( context: context, builder: (BuildContext context) { return AlertDialog( @@ -130,31 +130,19 @@ class FullScreenDialogDemoState extends State { TextButton( child: const Text('CANCEL'), onPressed: () { - // Pop the confirmation dialog and indicate that the page should - // not be popped. - Navigator.of(context).pop(false); + Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page. }, ), TextButton( child: const Text('DISCARD'), onPressed: () { - // Pop the confirmation dialog and indicate that the page should - // be popped, too. - Navigator.of(context).pop(true); + Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again. }, ), ], ); }, - ); - - if (shouldDiscard ?? false) { - // Since this is the root route, quit the app where possible by invoking - // the SystemNavigator. If this wasn't the root route, then - // Navigator.maybePop could be used instead. - // See https://github.com/flutter/flutter/issues/11490 - SystemNavigator.pop(); - } + ) as Future; } @override @@ -174,8 +162,7 @@ class FullScreenDialogDemoState extends State { ], ), body: Form( - canPop: !_saveNeeded && !_hasLocation && !_hasName, - onPopInvoked: _handlePopInvoked, + onWillPop: _onWillPop, child: Scrollbar( child: ListView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart index c6f644ee74cd3..5d3fee8d60f0c 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart @@ -143,9 +143,10 @@ class TextFormFieldDemoState extends State { return null; } - Future _handlePopInvoked(bool didPop) async { - if (didPop) { - return; + Future _warnUserAboutInvalidData() async { + final FormState? form = _formKey.currentState; + if (form == null || !_formWasEdited || form.validate()) { + return true; } final bool? result = await showDialog( @@ -167,14 +168,7 @@ class TextFormFieldDemoState extends State { ); }, ); - - if (result ?? false) { - // Since this is the root route, quit the app where possible by invoking - // the SystemNavigator. If this wasn't the root route, then - // Navigator.maybePop could be used instead. - // See https://github.com/flutter/flutter/issues/11490 - SystemNavigator.pop(); - } + return result!; } @override @@ -191,8 +185,7 @@ class TextFormFieldDemoState extends State { child: Form( key: _formKey, autovalidateMode: _autovalidateMode, - canPop: _formKey.currentState == null || !_formWasEdited || _formKey.currentState!.validate(), - onPopInvoked: _handlePopInvoked, + onWillPop: _warnUserAboutInvalidData, child: Scrollbar( child: SingleChildScrollView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart index de2cfa43ef714..0391ef95bee47 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:scoped_model/scoped_model.dart'; import 'colors.dart'; @@ -360,12 +361,14 @@ class ExpandingBottomSheetState extends State with TickerP // Closes the cart if the cart is open, otherwise exits the app (this should // only be relevant for Android). - void _handlePopInvoked(bool didPop) { - if (didPop) { - return; + Future _onWillPop() async { + if (!_isOpen) { + await SystemNavigator.pop(); + return true; } close(); + return true; } @override @@ -375,9 +378,8 @@ class ExpandingBottomSheetState extends State with TickerP duration: const Duration(milliseconds: 225), curve: Curves.easeInOut, alignment: FractionalOffset.topLeft, - child: PopScope( - canPop: !_isOpen, - onPopInvoked: _handlePopInvoked, + child: WillPopScope( + onWillPop: _onWillPop, child: AnimatedBuilder( animation: widget.hideController, builder: _buildSlideAnimation, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart index 4a5f01fede8de..c661ce64486cd 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart @@ -325,14 +325,14 @@ class _GalleryHomeState extends State with SingleTickerProviderStat backgroundColor: isDark ? _kFlutterBlue : theme.primaryColor, body: SafeArea( bottom: false, - child: PopScope( - canPop: _category == null, - onPopInvoked: (bool didPop) { - if (didPop) { - return; - } + child: WillPopScope( + onWillPop: () { // Pop the category page if Android back button is pressed. - setState(() => _category = null); + if (_category != null) { + setState(() => _category = null); + return Future.value(false); + } + return Future.value(true); }, child: Backdrop( backTitle: const Text('Options'), diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart index 981eb5d81216a..7af02cfe00708 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart @@ -71,10 +71,14 @@ class _HomeState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - return NavigatorPopHandler( - onPop: () { + return WillPopScope( + onWillPop: () async { final NavigatorState navigator = navigatorKeys[selectedIndex].currentState!; + if (!navigator.canPop()) { + return true; + } navigator.pop(); + return false; }, child: Scaffold( body: SafeArea( diff --git a/examples/api/lib/widgets/form/form.1.dart b/examples/api/lib/widgets/form/form.1.dart deleted file mode 100644 index b5e8b6e09ca1f..0000000000000 --- a/examples/api/lib/widgets/form/form.1.dart +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -/// This sample demonstrates showing a confirmation dialog when the user -/// attempts to navigate away from a page with unsaved [Form] data. - -void main() => runApp(const FormApp()); - -class FormApp extends StatelessWidget { - const FormApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Confirmation Dialog Example'), - ), - body: Center( - child: _SaveableForm(), - ), - ), - ); - } -} - -class _SaveableForm extends StatefulWidget { - @override - State<_SaveableForm> createState() => _SaveableFormState(); -} - -class _SaveableFormState extends State<_SaveableForm> { - final TextEditingController _controller = TextEditingController(); - String _savedValue = ''; - bool _isDirty = false; - - @override - void initState() { - super.initState(); - _controller.addListener(_onChanged); - } - - @override - void dispose() { - _controller.removeListener(_onChanged); - super.dispose(); - } - - void _onChanged() { - final bool nextIsDirty = _savedValue != _controller.text; - if (nextIsDirty == _isDirty) { - return; - } - setState(() { - _isDirty = nextIsDirty; - }); - } - - Future _showDialog() async { - final bool? shouldDiscard = await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Are you sure?'), - content: const Text('Any unsaved changes will be lost!'), - actions: [ - TextButton( - child: const Text('Yes, discard my changes'), - onPressed: () { - Navigator.pop(context, true); - }, - ), - TextButton( - child: const Text('No, continue editing'), - onPressed: () { - Navigator.pop(context, false); - }, - ), - ], - ); - }, - ); - - if (shouldDiscard ?? false) { - // Since this is the root route, quit the app where possible by invoking - // the SystemNavigator. If this wasn't the root route, then - // Navigator.maybePop could be used instead. - // See https://github.com/flutter/flutter/issues/11490 - SystemNavigator.pop(); - } - } - - void _save(String? value) { - setState(() { - _savedValue = value ?? ''; - }); - } - - @override - Widget build(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('If the field below is unsaved, a confirmation dialog will be shown on back.'), - const SizedBox(height: 20.0), - Form( - canPop: !_isDirty, - onPopInvoked: (bool didPop) { - if (didPop) { - return; - } - _showDialog(); - }, - autovalidateMode: AutovalidateMode.always, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextFormField( - controller: _controller, - onFieldSubmitted: (String? value) { - _save(value); - }, - ), - TextButton( - onPressed: () { - _save(_controller.text); - }, - child: Row( - children: [ - const Text('Save'), - if (_controller.text.isNotEmpty) - Icon( - _isDirty ? Icons.warning : Icons.check, - ), - ], - ), - ), - ], - ), - ), - TextButton( - onPressed: () { - if (_isDirty) { - _showDialog(); - return; - } - // Since this is the root route, quit the app where possible by - // invoking the SystemNavigator. If this wasn't the root route, - // then Navigator.maybePop could be used instead. - // See https://github.com/flutter/flutter/issues/11490 - SystemNavigator.pop(); - }, - child: const Text('Go back'), - ), - ], - ), - ); - } -} diff --git a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart deleted file mode 100644 index d81b74f65f714..0000000000000 --- a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -/// This sample demonstrates using [NavigatorPopHandler] to handle system back -/// gestures when there are nested [Navigator] widgets by delegating to the -/// current [Navigator]. - -void main() => runApp(const NavigatorPopHandlerApp()); - -class NavigatorPopHandlerApp extends StatelessWidget { - const NavigatorPopHandlerApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext context) => _HomePage(), - '/nested_navigators': (BuildContext context) => const NestedNavigatorsPage(), - }, - ); - } -} - -class _HomePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Nested Navigators Example'), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Home Page'), - const Text('A system back gesture here will exit the app.'), - const SizedBox(height: 20.0), - ListTile( - title: const Text('Nested Navigator route'), - subtitle: const Text('This route has another Navigator widget in addition to the one inside MaterialApp above.'), - onTap: () { - Navigator.of(context).pushNamed('/nested_navigators'); - }, - ), - ], - ), - ), - ); - } -} - -class NestedNavigatorsPage extends StatefulWidget { - const NestedNavigatorsPage({super.key}); - - @override - State createState() => _NestedNavigatorsPageState(); -} - -class _NestedNavigatorsPageState extends State { - final GlobalKey _nestedNavigatorKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return NavigatorPopHandler( - onPop: () { - _nestedNavigatorKey.currentState!.maybePop(); - }, - child: Navigator( - key: _nestedNavigatorKey, - initialRoute: 'nested_navigators/one', - onGenerateRoute: (RouteSettings settings) { - switch (settings.name) { - case 'nested_navigators/one': - final BuildContext rootContext = context; - return MaterialPageRoute( - builder: (BuildContext context) => NestedNavigatorsPageOne( - onBack: () { - Navigator.of(rootContext).pop(); - }, - ), - ); - case 'nested_navigators/one/another_one': - return MaterialPageRoute( - builder: (BuildContext context) => const NestedNavigatorsPageTwo( - ), - ); - default: - throw Exception('Invalid route: ${settings.name}'); - } - }, - ), - ); - } -} - -class NestedNavigatorsPageOne extends StatelessWidget { - const NestedNavigatorsPageOne({ - required this.onBack, - super.key, - }); - - final VoidCallback onBack; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.grey, - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Nested Navigators Page One'), - const Text('A system back here returns to the home page.'), - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('nested_navigators/one/another_one'); - }, - child: const Text('Go to another route in this nested Navigator'), - ), - TextButton( - // Can't use Navigator.of(context).pop() because this is the root - // route, so it can't be popped. The Navigator above this needs to - // be popped. - onPressed: onBack, - child: const Text('Go back'), - ), - ], - ), - ), - ); - } -} - -class NestedNavigatorsPageTwo extends StatelessWidget { - const NestedNavigatorsPageTwo({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.grey.withBlue(180), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Nested Navigators Page Two'), - const Text('A system back here will go back to Nested Navigators Page One'), - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Go back'), - ), - ], - ), - ), - ); - } -} diff --git a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart deleted file mode 100644 index 04fbdedd34e56..0000000000000 --- a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This sample demonstrates nested navigation in a bottom navigation bar. - -import 'package:flutter/material.dart'; - -// There are three possible tabs. -enum _Tab { - home, - one, - two, -} - -// Each tab has two possible pages. -enum _TabPage { - home, - one, -} - -typedef _TabPageCallback = void Function(List<_TabPage> pages); - -void main() => runApp(const NavigatorPopHandlerApp()); - -class NavigatorPopHandlerApp extends StatelessWidget { - const NavigatorPopHandlerApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - initialRoute: '/home', - routes: { - '/home': (BuildContext context) => const _BottomNavPage( - ), - }, - ); - } -} - -class _BottomNavPage extends StatefulWidget { - const _BottomNavPage(); - - @override - State<_BottomNavPage> createState() => _BottomNavPageState(); -} - -class _BottomNavPageState extends State<_BottomNavPage> { - _Tab _tab = _Tab.home; - - final GlobalKey _tabHomeKey = GlobalKey(); - final GlobalKey _tabOneKey = GlobalKey(); - final GlobalKey _tabTwoKey = GlobalKey(); - - List<_TabPage> _tabHomePages = <_TabPage>[_TabPage.home]; - List<_TabPage> _tabOnePages = <_TabPage>[_TabPage.home]; - List<_TabPage> _tabTwoPages = <_TabPage>[_TabPage.home]; - - BottomNavigationBarItem _itemForPage(_Tab page) { - switch (page) { - case _Tab.home: - return const BottomNavigationBarItem( - icon: Icon(Icons.home), - label: 'Go to Home', - ); - case _Tab.one: - return const BottomNavigationBarItem( - icon: Icon(Icons.one_k), - label: 'Go to One', - ); - case _Tab.two: - return const BottomNavigationBarItem( - icon: Icon(Icons.two_k), - label: 'Go to Two', - ); - } - } - - Widget _getPage(_Tab page) { - switch (page) { - case _Tab.home: - return _BottomNavTab( - key: _tabHomeKey, - title: 'Home Tab', - color: Colors.grey, - pages: _tabHomePages, - onChangedPages: (List<_TabPage> pages) { - setState(() { - _tabHomePages = pages; - }); - }, - ); - case _Tab.one: - return _BottomNavTab( - key: _tabOneKey, - title: 'Tab One', - color: Colors.amber, - pages: _tabOnePages, - onChangedPages: (List<_TabPage> pages) { - setState(() { - _tabOnePages = pages; - }); - }, - ); - case _Tab.two: - return _BottomNavTab( - key: _tabTwoKey, - title: 'Tab Two', - color: Colors.blueGrey, - pages: _tabTwoPages, - onChangedPages: (List<_TabPage> pages) { - setState(() { - _tabTwoPages = pages; - }); - }, - ); - } - } - - void _onItemTapped(int index) { - setState(() { - _tab = _Tab.values.elementAt(index); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: _getPage(_tab), - ), - bottomNavigationBar: BottomNavigationBar( - items: _Tab.values.map(_itemForPage).toList(), - currentIndex: _Tab.values.indexOf(_tab), - selectedItemColor: Colors.amber[800], - onTap: _onItemTapped, - ), - ); - } -} - -class _BottomNavTab extends StatefulWidget { - const _BottomNavTab({ - super.key, - required this.color, - required this.onChangedPages, - required this.pages, - required this.title, - }); - - final Color color; - final _TabPageCallback onChangedPages; - final List<_TabPage> pages; - final String title; - - @override - State<_BottomNavTab> createState() => _BottomNavTabState(); -} - -class _BottomNavTabState extends State<_BottomNavTab> { - final GlobalKey _navigatorKey = GlobalKey(); - - @override - Widget build(BuildContext context) { - return NavigatorPopHandler( - onPop: () { - _navigatorKey.currentState?.maybePop(); - }, - child: Navigator( - key: _navigatorKey, - onPopPage: (Route route, void result) { - if (!route.didPop(null)) { - return false; - } - widget.onChangedPages(<_TabPage>[ - ...widget.pages, - ]..removeLast()); - return true; - }, - pages: widget.pages.map((_TabPage page) { - switch (page) { - case _TabPage.home: - return MaterialPage( - child: _LinksPage( - title: 'Bottom nav - tab ${widget.title} - route $page', - backgroundColor: widget.color, - buttons: [ - TextButton( - onPressed: () { - widget.onChangedPages(<_TabPage>[ - ...widget.pages, - _TabPage.one, - ]); - }, - child: const Text('Go to another route in this nested Navigator'), - ), - ], - ), - ); - case _TabPage.one: - return MaterialPage( - child: _LinksPage( - backgroundColor: widget.color, - title: 'Bottom nav - tab ${widget.title} - route $page', - buttons: [ - TextButton( - onPressed: () { - widget.onChangedPages(<_TabPage>[ - ...widget.pages, - ]..removeLast()); - }, - child: const Text('Go back'), - ), - ], - ), - ); - } - }).toList(), - ), - ); - } -} - -class _LinksPage extends StatelessWidget { - const _LinksPage ({ - required this.backgroundColor, - this.buttons = const [], - required this.title, - }); - - final Color backgroundColor; - final List buttons; - final String title; - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: backgroundColor, - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(title), - ...buttons, - ], - ), - ), - ); - } -} diff --git a/examples/api/lib/widgets/pop_scope/pop_scope.0.dart b/examples/api/lib/widgets/pop_scope/pop_scope.0.dart deleted file mode 100644 index 6d144bd088de1..0000000000000 --- a/examples/api/lib/widgets/pop_scope/pop_scope.0.dart +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// This sample demonstrates showing a confirmation dialog before navigating -// away from a page. - -import 'package:flutter/material.dart'; - -void main() => runApp(const NavigatorPopHandlerApp()); - -class NavigatorPopHandlerApp extends StatelessWidget { - const NavigatorPopHandlerApp({super.key}); - - @override - Widget build(BuildContext context) { - return MaterialApp( - initialRoute: '/home', - routes: { - '/home': (BuildContext context) => const _HomePage(), - '/two': (BuildContext context) => const _PageTwo(), - }, - ); - } -} - -class _HomePage extends StatefulWidget { - const _HomePage(); - - @override - State<_HomePage> createState() => _HomePageState(); -} - -class _HomePageState extends State<_HomePage> { - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Page One'), - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/two'); - }, - child: const Text('Next page'), - ), - ], - ), - ), - ); - } -} - -class _PageTwo extends StatefulWidget { - const _PageTwo(); - - @override - State<_PageTwo> createState() => _PageTwoState(); -} - -class _PageTwoState extends State<_PageTwo> { - void _showBackDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Are you sure?'), - content: const Text( - 'Are you sure you want to leave this page?', - ), - actions: [ - TextButton( - style: TextButton.styleFrom( - textStyle: Theme.of(context).textTheme.labelLarge, - ), - child: const Text('Nevermind'), - onPressed: () { - Navigator.pop(context); - }, - ), - TextButton( - style: TextButton.styleFrom( - textStyle: Theme.of(context).textTheme.labelLarge, - ), - child: const Text('Leave'), - onPressed: () { - Navigator.pop(context); - Navigator.pop(context); - }, - ), - ], - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Page Two'), - PopScope( - canPop: false, - onPopInvoked: (bool didPop) { - if (didPop) { - return; - } - _showBackDialog(); - }, - child: TextButton( - onPressed: () { - _showBackDialog(); - }, - child: const Text('Go back'), - ), - ), - ], - ), - ), - ); - } -} diff --git a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart b/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart new file mode 100644 index 0000000000000..46dafa57b98ce --- /dev/null +++ b/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart @@ -0,0 +1,77 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [WillPopScope]. + +void main() => runApp(const WillPopScopeExampleApp()); + +class WillPopScopeExampleApp extends StatelessWidget { + const WillPopScopeExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: WillPopScopeExample(), + ); + } +} + +class WillPopScopeExample extends StatefulWidget { + const WillPopScopeExample({super.key}); + + @override + State createState() => _WillPopScopeExampleState(); +} + +class _WillPopScopeExampleState extends State { + bool shouldPop = true; + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + return shouldPop; + }, + child: Scaffold( + appBar: AppBar( + title: const Text('Flutter WillPopScope demo'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + OutlinedButton( + child: const Text('Push'), + onPressed: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) { + return const WillPopScopeExample(); + }, + ), + ); + }, + ), + OutlinedButton( + child: Text('shouldPop: $shouldPop'), + onPressed: () { + setState( + () { + shouldPop = !shouldPop; + }, + ); + }, + ), + const Text('Push to a new screen, then tap on shouldPop ' + 'button to toggle its value. Press the back ' + 'button in the appBar to check its behavior ' + 'for different values of shouldPop'), + ], + ), + ), + ), + ); + } +} diff --git a/examples/api/test/widgets/form/form.1_test.dart b/examples/api/test/widgets/form/form.1_test.dart deleted file mode 100644 index f9ccd71d521e8..0000000000000 --- a/examples/api/test/widgets/form/form.1_test.dart +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/widgets/form/form.1.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('Can go back when form is clean', (WidgetTester tester) async { - await tester.pumpWidget( - const example.FormApp(), - ); - - expect(find.text('Are you sure?'), findsNothing); - - await tester.tap(find.text('Go back')); - await tester.pumpAndSettle(); - - expect(find.text('Are you sure?'), findsNothing); - }); - - testWidgets('Cannot go back when form is dirty', (WidgetTester tester) async { - await tester.pumpWidget( - const example.FormApp(), - ); - - expect(find.text('Are you sure?'), findsNothing); - - await tester.enterText(find.byType(TextFormField), 'some new text'); - - await tester.tap(find.text('Go back')); - await tester.pumpAndSettle(); - - expect(find.text('Are you sure?'), findsOneWidget); - }); -} diff --git a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart deleted file mode 100644 index 88f29223f60a4..0000000000000 --- a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter_api_samples/widgets/navigator_pop_handler/navigator_pop_handler.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -import '../navigator_utils.dart'; - -void main() { - testWidgets('Can go back with system back gesture', (WidgetTester tester) async { - await tester.pumpWidget( - const example.NavigatorPopHandlerApp(), - ); - - expect(find.text('Nested Navigators Example'), findsOneWidget); - expect(find.text('Nested Navigators Page One'), findsNothing); - expect(find.text('Nested Navigators Page Two'), findsNothing); - - await tester.tap(find.text('Nested Navigator route')); - await tester.pumpAndSettle(); - - expect(find.text('Nested Navigators Example'), findsNothing); - expect(find.text('Nested Navigators Page One'), findsOneWidget); - expect(find.text('Nested Navigators Page Two'), findsNothing); - - await tester.tap(find.text('Go to another route in this nested Navigator')); - await tester.pumpAndSettle(); - - expect(find.text('Nested Navigators Example'), findsNothing); - expect(find.text('Nested Navigators Page One'), findsNothing); - expect(find.text('Nested Navigators Page Two'), findsOneWidget); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Nested Navigators Example'), findsNothing); - expect(find.text('Nested Navigators Page One'), findsOneWidget); - expect(find.text('Nested Navigators Page Two'), findsNothing); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Nested Navigators Example'), findsOneWidget); - expect(find.text('Nested Navigators Page One'), findsNothing); - expect(find.text('Nested Navigators Page Two'), findsNothing); - }); -} diff --git a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart deleted file mode 100644 index a6ea0ac82806f..0000000000000 --- a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter_api_samples/widgets/navigator_pop_handler/navigator_pop_handler.1.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -import '../navigator_utils.dart'; - -void main() { - testWidgets("System back gesture operates on current tab's nested Navigator", (WidgetTester tester) async { - await tester.pumpWidget( - const example.NavigatorPopHandlerApp(), - ); - - expect(find.text('Bottom nav - tab Home Tab - route _TabPage.home'), findsOneWidget); - - // Go to the next route in this tab. - await tester.tap(find.text('Go to another route in this nested Navigator')); - await tester.pumpAndSettle(); - expect(find.text('Bottom nav - tab Home Tab - route _TabPage.one'), findsOneWidget); - - // Go to another tab. - await tester.tap(find.text('Go to One')); - await tester.pumpAndSettle(); - expect(find.text('Bottom nav - tab Tab One - route _TabPage.home'), findsOneWidget); - - // Return to the home tab. The navigation state is preserved. - await tester.tap(find.text('Go to Home')); - await tester.pumpAndSettle(); - expect(find.text('Bottom nav - tab Home Tab - route _TabPage.one'), findsOneWidget); - - // A back pops the navigation stack of the current tab's nested Navigator. - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(find.text('Bottom nav - tab Home Tab - route _TabPage.home'), findsOneWidget); - }); -} diff --git a/examples/api/test/widgets/navigator_utils.dart b/examples/api/test/widgets/navigator_utils.dart deleted file mode 100644 index 46f1f9b1ac469..0000000000000 --- a/examples/api/test/widgets/navigator_utils.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; - -/// Simulates a system back, like a back gesture on Android. -/// -/// Sends the same platform channel message that the engine sends when it -/// receives a system back. -Future simulateSystemBack() { - return TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage( - 'flutter/navigation', - const JSONMessageCodec().encodeMessage({ - 'method': 'popRoute', - }), - (ByteData? _) {}, - ); -} diff --git a/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart b/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart deleted file mode 100644 index ac334fc3222f2..0000000000000 --- a/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter_api_samples/widgets/pop_scope/pop_scope.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -import '../navigator_utils.dart'; - -void main() { - testWidgets('Can choose to stay on page', (WidgetTester tester) async { - await tester.pumpWidget( - const example.NavigatorPopHandlerApp(), - ); - - expect(find.text('Page One'), findsOneWidget); - expect(find.text('Page Two'), findsNothing); - expect(find.text('Are you sure?'), findsNothing); - - await tester.tap(find.text('Next page')); - await tester.pumpAndSettle(); - expect(find.text('Page One'), findsNothing); - expect(find.text('Page Two'), findsOneWidget); - expect(find.text('Are you sure?'), findsNothing); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(find.text('Page One'), findsNothing); - expect(find.text('Page Two'), findsOneWidget); - expect(find.text('Are you sure?'), findsOneWidget); - - await tester.tap(find.text('Nevermind')); - await tester.pumpAndSettle(); - expect(find.text('Page One'), findsNothing); - expect(find.text('Page Two'), findsOneWidget); - expect(find.text('Are you sure?'), findsNothing); - }); - - testWidgets('Can choose to go back', (WidgetTester tester) async { - await tester.pumpWidget( - const example.NavigatorPopHandlerApp(), - ); - - expect(find.text('Page One'), findsOneWidget); - expect(find.text('Page Two'), findsNothing); - expect(find.text('Are you sure?'), findsNothing); - - await tester.tap(find.text('Next page')); - await tester.pumpAndSettle(); - expect(find.text('Page One'), findsNothing); - expect(find.text('Page Two'), findsOneWidget); - expect(find.text('Are you sure?'), findsNothing); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(find.text('Page One'), findsNothing); - expect(find.text('Page Two'), findsOneWidget); - expect(find.text('Are you sure?'), findsOneWidget); - - await tester.tap(find.text('Leave')); - await tester.pumpAndSettle(); - expect(find.text('Page One'), findsOneWidget); - expect(find.text('Page Two'), findsNothing); - expect(find.text('Are you sure?'), findsNothing); - }); -} diff --git a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart b/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart new file mode 100644 index 0000000000000..ad05943108708 --- /dev/null +++ b/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart @@ -0,0 +1,32 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/will_pop_scope/will_pop_scope.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('pressing shouldPop button changes shouldPop', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WillPopScopeExampleApp(), + ); + + final Finder buttonFinder = find.text('shouldPop: true'); + expect(buttonFinder, findsOneWidget); + await tester.tap(buttonFinder); + await tester.pump(); + expect(find.text('shouldPop: false'), findsOneWidget); + }); + testWidgets('pressing Push button pushes route', (WidgetTester tester) async { + await tester.pumpWidget( + const example.WillPopScopeExampleApp(), + ); + + final Finder buttonFinder = find.text('Push'); + expect(buttonFinder, findsOneWidget); + expect(find.byType(example.WillPopScopeExample), findsOneWidget); + await tester.tap(buttonFinder); + await tester.pumpAndSettle(); + expect(find.byType(example.WillPopScopeExample, skipOffstage: false), findsNWidgets(2)); + }); +} diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index 6501b9cee30c5..47e45b198b0b9 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -157,7 +157,6 @@ class CupertinoApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, - this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, List this.navigatorObservers = const [], this.builder, this.title = '', @@ -203,7 +202,6 @@ class CupertinoApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, - this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, this.color, this.locale, this.localizationsDelegates, @@ -270,9 +268,6 @@ class CupertinoApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} final RouteFactory? onUnknownRoute; - /// {@macro flutter.widgets.widgetsApp.onNavigationNotification} - final NotificationListenerCallback? onNavigationNotification; - /// {@macro flutter.widgets.widgetsApp.navigatorObservers} final List? navigatorObservers; @@ -578,7 +573,6 @@ class _CupertinoAppState extends State { onGenerateRoute: widget.onGenerateRoute, onGenerateInitialRoutes: widget.onGenerateInitialRoutes, onUnknownRoute: widget.onUnknownRoute, - onNavigationNotification: widget.onNavigationNotification, builder: widget.builder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index 211578214871d..f922eaf33e946 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -196,8 +196,7 @@ mixin CupertinoRouteTransitionMixin on PageRoute { } // If attempts to dismiss this route might be vetoed such as in a page // with forms, then do not allow the user to dismiss the route with a swipe. - if (route.hasScopedWillPopCallback - || route.popDisposition == RoutePopDisposition.doNotPop) { + if (route.hasScopedWillPopCallback) { return false; } // Fullscreen dialogs aren't dismissible by back swipe. diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart index f41d0a4a3175d..8728196eee9b8 100644 --- a/packages/flutter/lib/src/cupertino/tab_view.dart +++ b/packages/flutter/lib/src/cupertino/tab_view.dart @@ -162,39 +162,15 @@ class _CupertinoTabViewState extends State { ..add(_heroController); } - GlobalKey? _ownedNavigatorKey; - GlobalKey get _navigatorKey { - if (widget.navigatorKey != null) { - return widget.navigatorKey!; - } - _ownedNavigatorKey ??= GlobalKey(); - return _ownedNavigatorKey!; - } - - // Whether this tab is currently the active tab. - bool get _isActive => TickerMode.of(context); - @override Widget build(BuildContext context) { - final Widget child = Navigator( - key: _navigatorKey, + return Navigator( + key: widget.navigatorKey, onGenerateRoute: _onGenerateRoute, onUnknownRoute: _onUnknownRoute, observers: _navigatorObservers, restorationScopeId: widget.restorationScopeId, ); - - // Handle system back gestures only if the tab is currently active. - return NavigatorPopHandler( - enabled: _isActive, - onPop: () { - if (!_isActive) { - return; - } - _navigatorKey.currentState!.pop(); - }, - child: child, - ); } Route? _onGenerateRoute(RouteSettings settings) { diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 76462c8c6033f..44d4e7b1cf4f8 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -1179,10 +1179,9 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp _builtLayout = _LayoutMode.nested; final MaterialPageRoute masterPageRoute = _masterPageRoute(context); - return NavigatorPopHandler( - onPop: () { - _navigatorKey.currentState!.maybePop(); - }, + return WillPopScope( + // Push pop check into nested navigator. + onWillPop: () async => !(await _navigatorKey.currentState!.maybePop()), child: Navigator( key: _navigatorKey, initialRoute: 'initial', @@ -1235,10 +1234,12 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp MaterialPageRoute _detailPageRoute(Object? arguments) { return MaterialPageRoute(builder: (BuildContext context) { - return PopScope( - onPopInvoked: (bool didPop) { + return WillPopScope( + onWillPop: () async { // No need for setState() as rebuild happens on navigation pop. focus = _Focus.master; + Navigator.of(context).pop(); + return false; }, child: BlockSemantics(child: widget.detailPageBuilder(context, arguments, null)), ); diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index 62f0385935065..2438c45828989 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -214,7 +214,6 @@ class MaterialApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, - this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, List this.navigatorObservers = const [], this.builder, this.title = '', @@ -268,7 +267,6 @@ class MaterialApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, - this.onNavigationNotification = WidgetsApp.defaultOnNavigationNotification, this.color, this.theme, this.darkTheme, @@ -345,9 +343,6 @@ class MaterialApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} final RouteFactory? onUnknownRoute; - /// {@macro flutter.widgets.widgetsApp.onNavigationNotification} - final NotificationListenerCallback? onNavigationNotification; - /// {@macro flutter.widgets.widgetsApp.navigatorObservers} final List? navigatorObservers; @@ -1024,7 +1019,6 @@ class _MaterialAppState extends State { onGenerateRoute: widget.onGenerateRoute, onGenerateInitialRoutes: widget.onGenerateInitialRoutes, onUnknownRoute: widget.onUnknownRoute, - onNavigationNotification: widget.onNavigationNotification, builder: _materialBuilder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/services/system_navigator.dart b/packages/flutter/lib/src/services/system_navigator.dart index 1ea16f921ac91..9edff64b3cdf8 100644 --- a/packages/flutter/lib/src/services/system_navigator.dart +++ b/packages/flutter/lib/src/services/system_navigator.dart @@ -2,44 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart'; - import 'system_channels.dart'; /// Controls specific aspects of the system navigation stack. abstract final class SystemNavigator { - /// Informs the platform of whether or not the Flutter framework will handle - /// back events. - /// - /// Currently, this is used only on Android to inform its use of the - /// predictive back gesture when exiting the app. When true, predictive back - /// is disabled. - /// - /// See also: - /// - /// * The - /// [migration guide](https://developer.android.com/guide/navigation/predictive-back-gesture) - /// for predictive back in native Android apps. - static Future setFrameworkHandlesBack(bool frameworkHandlesBack) async { - // Currently, this method call is only relevant on Android. - if (kIsWeb) { - return; - } - switch (defaultTargetPlatform) { - case TargetPlatform.iOS: - case TargetPlatform.macOS: - case TargetPlatform.fuchsia: - case TargetPlatform.linux: - case TargetPlatform.windows: - return; - case TargetPlatform.android: - return SystemChannels.platform.invokeMethod( - 'SystemNavigator.setFrameworkHandlesBack', - frameworkHandlesBack, - ); - } - } - /// Removes the topmost Flutter instance, presenting what was before /// it. /// diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index 5d402c67bc3fd..af5d404c43033 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -19,7 +19,6 @@ import 'framework.dart'; import 'localizations.dart'; import 'media_query.dart'; import 'navigator.dart'; -import 'notification_listener.dart'; import 'pages.dart'; import 'performance_overlay.dart'; import 'restoration.dart'; @@ -314,7 +313,6 @@ class WidgetsApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, - this.onNavigationNotification = defaultOnNavigationNotification, List this.navigatorObservers = const [], this.initialRoute, this.pageRouteBuilder, @@ -422,7 +420,6 @@ class WidgetsApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, - this.onNavigationNotification = defaultOnNavigationNotification, this.textStyle, required this.color, this.locale, @@ -704,17 +701,6 @@ class WidgetsApp extends StatefulWidget { /// {@endtemplate} final RouteFactory? onUnknownRoute; - /// {@template flutter.widgets.widgetsApp.onNavigationNotification} - /// The callback to use when receiving a [NavigationNotification]. - /// - /// By default set to [WidgetsApp.defaultOnNavigationNotification], which - /// updates the engine with the navigation status. - /// - /// If null, [NavigationNotification] is not listened for at all, and so will - /// continue to propagate. - /// {@endtemplate} - final NotificationListenerCallback? onNavigationNotification; - /// {@template flutter.widgets.widgetsApp.initialRoute} /// The name of the first route to show, if a [Navigator] is built. /// @@ -1328,15 +1314,6 @@ class WidgetsApp extends StatefulWidget { VoidCallbackIntent: VoidCallbackAction(), }; - /// The default value for [onNavigationNotification]. - /// - /// Updates the platform with [NavigationNotification.canHandlePop] and stops - /// bubbling. - static bool defaultOnNavigationNotification(NavigationNotification notification) { - SystemNavigator.setFrameworkHandlesBack(notification.canHandlePop); - return true; - } - @override State createState() => _WidgetsAppState(); } @@ -1771,25 +1748,30 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { assert(_debugCheckLocalizations(appLocale)); - Widget child = Shortcuts( - debugLabel: '', - shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, - // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can - // fall through to the defaultShortcuts. - child: DefaultTextEditingShortcuts( - child: Actions( - actions: widget.actions ?? >{ - ...WidgetsApp.defaultActions, - ScrollIntent: Action.overridable(context: context, defaultAction: ScrollAction()), - }, - child: FocusTraversalGroup( - policy: ReadingOrderTraversalPolicy(), - child: TapRegionSurface( - child: ShortcutRegistrar( - child: Localizations( - locale: appLocale, - delegates: _localizationsDelegates.toList(), - child: title, + return RootRestorationScope( + restorationId: widget.restorationScopeId, + child: SharedAppData( + child: Shortcuts( + debugLabel: '', + shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, + // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can + // fall through to the defaultShortcuts. + child: DefaultTextEditingShortcuts( + child: Actions( + actions: widget.actions ?? >{ + ...WidgetsApp.defaultActions, + ScrollIntent: Action.overridable(context: context, defaultAction: ScrollAction()), + }, + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: TapRegionSurface( + child: ShortcutRegistrar( + child: Localizations( + locale: appLocale, + delegates: _localizationsDelegates.toList(), + child: title, + ), + ), ), ), ), @@ -1797,19 +1779,5 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { ), ), ); - - if (widget.onNavigationNotification != null) { - child = NotificationListener( - onNotification: widget.onNavigationNotification, - child: child, - ); - } - - return RootRestorationScope( - restorationId: widget.restorationScopeId, - child: SharedAppData( - child: child, - ), - ); } } diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 13efd54f53c35..900d34fe77232 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -54,8 +54,9 @@ export 'dart:ui' show AppLifecycleState, Locale; /// ** See code in examples/api/lib/widgets/binding/widget_binding_observer.0.dart ** /// {@end-tool} abstract mixin class WidgetsBindingObserver { - /// Called when the system tells the app to pop the current route, such as - /// after a system back button press or back gesture. + /// Called when the system tells the app to pop the current route. + /// For example, on Android, this is called when the user presses + /// the back button. /// /// Observers are notified in registration order until one returns /// true. If none return true, the application quits. @@ -68,8 +69,6 @@ abstract mixin class WidgetsBindingObserver { /// /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. - /// - /// {@macro flutter.widgets.AndroidPredictiveBack} Future didPopRoute() => Future.value(false); /// Called when the host tells the application to push a new route onto the @@ -721,27 +720,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. - /// - /// {@template flutter.widgets.AndroidPredictiveBack} - /// ## Handling backs ahead of time - /// - /// Not all system backs will result in a call to this method. Some are - /// handled entirely by the system without informing the Flutter framework. - /// - /// Android API 33+ introduced a feature called predictive back, which allows - /// the user to peek behind the current app or route during a back gesture and - /// then decide to cancel or commit the back. Flutter enables or disables this - /// feature ahead of time, before a back gesture occurs, and back gestures - /// that trigger predictive back are handled entirely by the system and do not - /// trigger this method here in the framework. - /// - /// By default, the framework communicates when it would like to handle system - /// back gestures using [SystemNavigator.setFrameworkHandlesBack] in - /// [WidgetsApp.defaultOnNavigationNotification]. This is done automatically - /// based on the status of the [Navigator] stack and the state of any - /// [PopScope] widgets present. Developers can manually set this by calling - /// the method directly or by using [NavigationNotification]. - /// {@endtemplate} @protected @visibleForTesting Future handlePopRoute() async { diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 05ad8554a64c6..76e8521ab9196 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -10,10 +10,8 @@ import 'package:flutter/rendering.dart'; import 'basic.dart'; import 'framework.dart'; import 'navigator.dart'; -import 'pop_scope.dart'; import 'restoration.dart'; import 'restoration_properties.dart'; -import 'routes.dart'; import 'will_pop_scope.dart'; // Duration for delay before announcement in IOS so that the announcement won't be interrupted. @@ -54,17 +52,10 @@ class Form extends StatefulWidget { const Form({ super.key, required this.child, - this.canPop, - this.onPopInvoked, - @Deprecated( - 'Use canPop and/or onPopInvoked instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', - ) this.onWillPop, this.onChanged, AutovalidateMode? autovalidateMode, - }) : autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled, - assert((onPopInvoked == null && canPop == null) || onWillPop == null, 'onWillPop is deprecated; use canPop and/or onPopInvoked.'); + }) : autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled; /// Returns the [FormState] of the closest [Form] widget which encloses the /// given context, or null if none is found. @@ -143,44 +134,8 @@ class Form extends StatefulWidget { /// /// * [WillPopScope], another widget that provides a way to intercept the /// back button. - @Deprecated( - 'Use canPop and/or onPopInvoked instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', - ) final WillPopCallback? onWillPop; - /// {@macro flutter.widgets.PopScope.canPop} - /// - /// {@tool dartpad} - /// This sample demonstrates how to use this parameter to show a confirmation - /// dialog when a navigation pop would cause form data to be lost. - /// - /// ** See code in examples/api/lib/widgets/form/form.1.dart ** - /// {@end-tool} - /// - /// See also: - /// - /// * [onPopInvoked], which also comes from [PopScope] and is often used in - /// conjunction with this parameter. - /// * [PopScope.canPop], which is what [Form] delegates to internally. - final bool? canPop; - - /// {@macro flutter.widgets.navigator.onPopInvoked} - /// - /// {@tool dartpad} - /// This sample demonstrates how to use this parameter to show a confirmation - /// dialog when a navigation pop would cause form data to be lost. - /// - /// ** See code in examples/api/lib/widgets/form/form.1.dart ** - /// {@end-tool} - /// - /// See also: - /// - /// * [canPop], which also comes from [PopScope] and is often used in - /// conjunction with this parameter. - /// * [PopScope.onPopInvoked], which is what [Form] delegates to internally. - final PopInvokedCallback? onPopInvoked; - /// Called when one of the form fields changes. /// /// In addition to this callback being invoked, all the form fields themselves @@ -245,18 +200,6 @@ class FormState extends State { break; } - if (widget.canPop != null || widget.onPopInvoked != null) { - return PopScope( - canPop: widget.canPop ?? true, - onPopInvoked: widget.onPopInvoked, - child: _FormScope( - formState: this, - generation: _generation, - child: widget.child, - ), - ); - } - return WillPopScope( onWillPop: widget.onWillPop, child: _FormScope( diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 9a5485368b316..43156aa44e26e 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -20,7 +20,6 @@ import 'focus_scope.dart'; import 'focus_traversal.dart'; import 'framework.dart'; import 'heroes.dart'; -import 'notification_listener.dart'; import 'overlay.dart'; import 'restoration.dart'; import 'restoration_properties.dart'; @@ -68,10 +67,6 @@ typedef RoutePredicate = bool Function(Route route); /// /// Used by [Form.onWillPop], [ModalRoute.addScopedWillPopCallback], /// [ModalRoute.removeScopedWillPopCallback], and [WillPopScope]. -@Deprecated( - 'Use PopInvokedCallback instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', -) typedef WillPopCallback = Future Function(); /// Signature for the [Navigator.onPopPage] callback. @@ -94,21 +89,19 @@ typedef PopPageCallback = bool Function(Route route, dynamic result); enum RoutePopDisposition { /// Pop the route. /// - /// If [Route.willPop] or [Route.popDisposition] return [pop] then the back - /// button will actually pop the current route. + /// If [Route.willPop] returns [pop] then the back button will actually pop + /// the current route. pop, /// Do not pop the route. /// - /// If [Route.willPop] or [Route.popDisposition] return [doNotPop] then the - /// back button will be ignored. + /// If [Route.willPop] returns [doNotPop] then the back button will be ignored. doNotPop, /// Delegate this to the next level of navigation. /// - /// If [Route.willPop] or [Route.popDisposition] return [bubble] then the back - /// button will be handled by the [SystemNavigator], which will usually close - /// the application. + /// If [Route.willPop] returns [bubble] then the back button will be handled + /// by the [SystemNavigator], which will usually close the application. bubble, } @@ -301,51 +294,10 @@ abstract class Route { /// mechanism. /// * [WillPopScope], another widget that provides a way to intercept the /// back button. - @Deprecated( - 'Use popDisposition instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', - ) Future willPop() async { return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop; } - /// Returns whether calling [Navigator.maybePop] when this [Route] is current - /// ([isCurrent]) should do anything. - /// - /// [Navigator.maybePop] is usually used instead of [Navigator.pop] to handle - /// the system back button, when it hasn't been disabled via - /// [SystemNavigator.setFrameworkHandlesBack]. - /// - /// By default, if a [Route] is the first route in the history (i.e., if - /// [isFirst]), it reports that pops should be bubbled - /// ([RoutePopDisposition.bubble]). This behavior prevents the user from - /// popping the first route off the history and being stranded at a blank - /// screen; instead, the larger scope is popped (e.g. the application quits, - /// so that the user returns to the previous application). - /// - /// In other cases, the default behavior is to accept the pop - /// ([RoutePopDisposition.pop]). - /// - /// The third possible value is [RoutePopDisposition.doNotPop], which causes - /// the pop request to be ignored entirely. - /// - /// See also: - /// - /// * [Form], which provides a [Form.canPop] boolean that is similar. - /// * [PopScope], a widget that provides a way to intercept the back button. - RoutePopDisposition get popDisposition { - return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop; - } - - /// {@template flutter.widgets.navigator.onPopInvoked} - /// Called after a route pop was handled. - /// - /// Even when the pop is canceled, for example by a [PopScope] widget, this - /// will still be called. The `didPop` parameter indicates whether or not the - /// back navigation actually happened successfully. - /// {@endtemplate} - void onPopInvoked(bool didPop) {} - /// Whether calling [didPop] would return false. bool get willHandlePopInternally => false; @@ -2463,9 +2415,6 @@ class Navigator extends StatefulWidget { /// the initial route. /// /// If there is no [Navigator] in scope, returns false. - /// - /// Does not consider anything that might externally prevent popping, such as - /// [PopEntry]. /// {@endtemplate} /// /// See also: @@ -2477,22 +2426,21 @@ class Navigator extends StatefulWidget { return navigator != null && navigator.canPop(); } - /// Consults the current route's [Route.popDisposition] getter or - /// [Route.willPop] method, and acts accordingly, potentially popping the - /// route as a result; returns whether the pop request should be considered - /// handled. + /// Consults the current route's [Route.willPop] method, and acts accordingly, + /// potentially popping the route as a result; returns whether the pop request + /// should be considered handled. /// /// {@template flutter.widgets.navigator.maybePop} - /// If the [RoutePopDisposition] is [RoutePopDisposition.pop], then the [pop] + /// If [Route.willPop] returns [RoutePopDisposition.pop], then the [pop] /// method is called, and this method returns true, indicating that it handled /// the pop request. /// - /// If the [RoutePopDisposition] is [RoutePopDisposition.doNotPop], then this + /// If [Route.willPop] returns [RoutePopDisposition.doNotPop], then this /// method returns true, but does not do anything beyond that. /// - /// If the [RoutePopDisposition] is [RoutePopDisposition.bubble], then this - /// method returns false, and the caller is responsible for sending the - /// request to the containing scope (e.g. by closing the application). + /// If [Route.willPop] returns [RoutePopDisposition.bubble], then this method + /// returns false, and the caller is responsible for sending the request to + /// the containing scope (e.g. by closing the application). /// /// This method is typically called for a user-initiated [pop]. For example on /// Android it's called by the binding for the system's back button. @@ -3067,7 +3015,6 @@ class _RouteEntry extends RouteTransitionRecord { assert(isPresent); pendingResult = result; currentState = _RouteLifecycle.pop; - route.onPopInvoked(true); } bool _reportRemovalToObserver = true; @@ -3348,78 +3295,12 @@ class _NavigatorReplaceObservation extends _NavigatorObservation { } } -typedef _IndexWhereCallback = bool Function(_RouteEntry element); - -/// A collection of _RouteEntries representing a navigation history. -/// -/// Acts as a ChangeNotifier and notifies after its List of _RouteEntries is -/// mutated. -class _History extends Iterable<_RouteEntry> with ChangeNotifier { - final List<_RouteEntry> _value = <_RouteEntry>[]; - - int indexWhere(_IndexWhereCallback test, [int start = 0]) { - return _value.indexWhere(test, start); - } - - void add(_RouteEntry element) { - _value.add(element); - notifyListeners(); - } - - void addAll(Iterable<_RouteEntry> elements) { - _value.addAll(elements); - if (elements.isNotEmpty) { - notifyListeners(); - } - } - - void clear() { - final bool valueWasEmpty = _value.isEmpty; - _value.clear(); - if (!valueWasEmpty) { - notifyListeners(); - } - } - - void insert(int index, _RouteEntry element) { - _value.insert(index, element); - notifyListeners(); - } - - _RouteEntry removeAt(int index) { - final _RouteEntry entry = _value.removeAt(index); - notifyListeners(); - return entry; - } - - _RouteEntry removeLast() { - final _RouteEntry entry = _value.removeLast(); - notifyListeners(); - return entry; - } - - _RouteEntry operator [](int index) { - return _value[index]; - } - - @override - Iterator<_RouteEntry> get iterator { - return _value.iterator; - } - - @override - String toString() { - return _value.toString(); - } -} - /// The state for a [Navigator] widget. /// /// A reference to this class can be obtained by calling [Navigator.of]. class NavigatorState extends State with TickerProviderStateMixin, RestorationMixin { late GlobalKey _overlayKey; - final _History _history = _History(); - + List<_RouteEntry> _history = <_RouteEntry>[]; /// A set for entries that are waiting to dispose until their subtrees are /// disposed. /// @@ -3449,43 +3330,12 @@ class NavigatorState extends State with TickerProviderStateMixin, Res late List _effectiveObservers; - bool get _usingPagesAPI => widget.pages != const >[]; - - void _handleHistoryChanged() { - final bool navigatorCanPop = canPop(); - late final bool routeBlocksPop; - if (!navigatorCanPop) { - final _RouteEntry? lastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate); - routeBlocksPop = lastEntry != null - && lastEntry.route.popDisposition == RoutePopDisposition.doNotPop; - } else { - routeBlocksPop = false; - } - final NavigationNotification notification = NavigationNotification( - canHandlePop: navigatorCanPop || routeBlocksPop, - ); - // Avoid dispatching a notification in the middle of a build. - switch (SchedulerBinding.instance.schedulerPhase) { - case SchedulerPhase.postFrameCallbacks: - notification.dispatch(context); - case SchedulerPhase.idle: - case SchedulerPhase.midFrameMicrotasks: - case SchedulerPhase.persistentCallbacks: - case SchedulerPhase.transientCallbacks: - SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { - if (!mounted) { - return; - } - notification.dispatch(context); - }); - } - } - @override void initState() { super.initState(); assert(() { - if (_usingPagesAPI) { + if (widget.pages != const >[]) { + // This navigator uses page API. if (widget.pages.isEmpty) { FlutterError.reportError( FlutterErrorDetails( @@ -3528,8 +3378,6 @@ class NavigatorState extends State with TickerProviderStateMixin, Res if (widget.reportsRouteUpdateToEngine) { SystemNavigator.selectSingleEntryHistory(); } - - _history.addListener(_handleHistoryChanged); } // Use [_nextPagelessRestorationScopeId] to get the next id. @@ -3712,7 +3560,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res void didUpdateWidget(Navigator oldWidget) { super.didUpdateWidget(oldWidget); assert(() { - if (_usingPagesAPI) { + if (widget.pages != const >[]) { // This navigator uses page API. if (widget.pages.isEmpty) { FlutterError.reportError( @@ -3824,8 +3672,6 @@ class NavigatorState extends State with TickerProviderStateMixin, Res _rawNextPagelessRestorationScopeId.dispose(); _serializableHistory.dispose(); userGestureInProgressNotifier.dispose(); - _history.removeListener(_handleHistoryChanged); - _history.dispose(); super.dispose(); // don't unlock, so that the object becomes unusable assert(_debugLocked); @@ -4111,7 +3957,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res pageRouteToPagelessRoutes: pageRouteToPagelessRoutes, ).cast<_RouteEntry>(); } - _history.clear(); + _history = <_RouteEntry>[]; // Adds the leading pageless routes if there is any. if (pageRouteToPagelessRoutes.containsKey(null)) { _history.addAll(pageRouteToPagelessRoutes[null]!); @@ -5127,17 +4973,17 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return true; // there's at least two routes, so we can pop } - /// Consults the current route's [Route.popDisposition] method, and acts - /// accordingly, potentially popping the route as a result; returns whether - /// the pop request should be considered handled. + /// Consults the current route's [Route.willPop] method, and acts accordingly, + /// potentially popping the route as a result; returns whether the pop request + /// should be considered handled. /// /// {@macro flutter.widgets.navigator.maybePop} /// /// See also: /// - /// * [Form], which provides a [Form.canPop] boolean that enables the - /// form to prevent any [pop]s initiated by the app's back button. - /// * [ModalRoute], which provides a `scopedOnPopCallback` that can be used + /// * [Form], which provides an `onWillPop` callback that enables the form + /// to veto a [pop] initiated by the app's back button. + /// * [ModalRoute], which provides a `scopedWillPopCallback` that can be used /// to define the route's `willPop` method. @optionalTypeArgs Future maybePop([ T? result ]) async { @@ -5146,31 +4992,23 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return false; } assert(lastEntry.route._navigator == this); - - // TODO(justinmc): When the deprecated willPop method is removed, delete - // this code and use only popDisposition, below. - final RoutePopDisposition willPopDisposition = await lastEntry.route.willPop(); + final RoutePopDisposition disposition = await lastEntry.route.willPop(); // this is asynchronous if (!mounted) { // Forget about this pop, we were disposed in the meantime. return true; } - if (willPopDisposition == RoutePopDisposition.doNotPop) { - return true; - } final _RouteEntry? newLastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate); if (lastEntry != newLastEntry) { // Forget about this pop, something happened to our history in the meantime. return true; } - - switch (lastEntry.route.popDisposition) { + switch (disposition) { case RoutePopDisposition.bubble: return false; case RoutePopDisposition.pop: pop(result); return true; case RoutePopDisposition.doNotPop: - lastEntry.route.onPopInvoked(false); return true; } } @@ -5460,46 +5298,29 @@ class NavigatorState extends State with TickerProviderStateMixin, Res Widget build(BuildContext context) { assert(!_debugLocked); assert(_history.isNotEmpty); - // Hides the HeroControllerScope for the widget subtree so that the other // nested navigator underneath will not pick up the hero controller above // this level. return HeroControllerScope.none( - child: NotificationListener( - onNotification: (NavigationNotification notification) { - // If the state of this Navigator does not change whether or not the - // whole framework can pop, propagate the Notification as-is. - if (notification.canHandlePop || !canPop()) { - return false; - } - // Otherwise, dispatch a new Notification with the correct canPop and - // stop the propagation of the old Notification. - const NavigationNotification nextNotification = NavigationNotification( - canHandlePop: true, - ); - nextNotification.dispatch(context); - return true; - }, - child: Listener( - onPointerDown: _handlePointerDown, - onPointerUp: _handlePointerUpOrCancel, - onPointerCancel: _handlePointerUpOrCancel, - child: AbsorbPointer( - absorbing: false, // it's mutated directly by _cancelActivePointers above - child: FocusTraversalGroup( - policy: FocusTraversalGroup.maybeOf(context), - child: Focus( - focusNode: focusNode, - autofocus: true, - skipTraversal: true, - includeSemantics: false, - child: UnmanagedRestorationScope( - bucket: bucket, - child: Overlay( - key: _overlayKey, - clipBehavior: widget.clipBehavior, - initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], - ), + child: Listener( + onPointerDown: _handlePointerDown, + onPointerUp: _handlePointerUpOrCancel, + onPointerCancel: _handlePointerUpOrCancel, + child: AbsorbPointer( + absorbing: false, // it's mutated directly by _cancelActivePointers above + child: FocusTraversalGroup( + policy: FocusTraversalGroup.maybeOf(context), + child: Focus( + focusNode: focusNode, + autofocus: true, + skipTraversal: true, + includeSemantics: false, + child: UnmanagedRestorationScope( + bucket: bucket, + child: Overlay( + key: _overlayKey, + clipBehavior: widget.clipBehavior, + initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], ), ), ), @@ -5660,7 +5481,7 @@ class _HistoryProperty extends RestorableProperty>?> { // Updating. - void update(_History history) { + void update(List<_RouteEntry> history) { assert(isRegistered); final bool wasUninitialized = _pageToPagelessRoutes == null; bool needsSerialization = wasUninitialized; @@ -5983,26 +5804,3 @@ class RestorableRouteFuture extends RestorableProperty { static NavigatorState _defaultNavigatorFinder(BuildContext context) => Navigator.of(context); } - -/// A notification that a change in navigation has taken place. -/// -/// Specifically, this notification indicates that at least one of the following -/// has occurred: -/// -/// * That route stack of a [Navigator] has changed in any way. -/// * The ability to pop has changed, such as controlled by [PopScope]. -class NavigationNotification extends Notification { - /// Creates a notification that some change in navigation has happened. - const NavigationNotification({ - required this.canHandlePop, - }); - - /// Indicates that the originator of this [Notification] is capable of - /// handling a navigation pop. - final bool canHandlePop; - - @override - String toString() { - return 'NavigationNotification canHandlePop: $canHandlePop'; - } -} diff --git a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart deleted file mode 100644 index 203a85beded18..0000000000000 --- a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'framework.dart'; -import 'navigator.dart'; -import 'notification_listener.dart'; -import 'pop_scope.dart'; - -/// Enables the handling of system back gestures. -/// -/// Typically wraps a nested [Navigator] widget and allows it to handle system -/// back gestures in the [onPop] callback. -/// -/// {@tool dartpad} -/// This sample demonstrates how to use this widget to properly handle system -/// back gestures when using nested [Navigator]s. -/// -/// ** See code in examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart ** -/// {@end-tool} -/// -/// {@tool dartpad} -/// This sample demonstrates how to use this widget to properly handle system -/// back gestures with a bottom navigation bar whose tabs each have their own -/// nested [Navigator]s. -/// -/// ** See code in examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart ** -/// {@end-tool} -/// -/// See also: -/// -/// * [PopScope], which allows toggling the ability of a [Navigator] to -/// handle pops. -/// * [NavigationNotification], which indicates whether a [Navigator] in a -/// subtree can handle pops. -class NavigatorPopHandler extends StatefulWidget { - /// Creates an instance of [NavigatorPopHandler]. - const NavigatorPopHandler({ - super.key, - this.onPop, - this.enabled = true, - required this.child, - }); - - /// The widget to place below this in the widget tree. - /// - /// Typically this is a [Navigator] that will handle the pop when [onPop] is - /// called. - final Widget child; - - /// Whether this widget's ability to handle system back gestures is enabled or - /// disabled. - /// - /// When false, there will be no effect on system back gestures. If provided, - /// [onPop] will still be called. - /// - /// This can be used, for example, when the nested [Navigator] is no longer - /// active but remains in the widget tree, such as in an inactive tab. - /// - /// Defaults to true. - final bool enabled; - - /// Called when a handleable pop event happens. - /// - /// For example, a pop is handleable when a [Navigator] in [child] has - /// multiple routes on its stack. It's not handleable when it has only a - /// single route, and so [onPop] will not be called. - /// - /// Typically this is used to pop the [Navigator] in [child]. See the sample - /// code on [NavigatorPopHandler] for a full example of this. - final VoidCallback? onPop; - - @override - State createState() => _NavigatorPopHandlerState(); -} - -class _NavigatorPopHandlerState extends State { - bool _canPop = true; - - @override - Widget build(BuildContext context) { - // When the widget subtree indicates it can handle a pop, disable popping - // here, so that it can be manually handled in canPop. - return PopScope( - canPop: !widget.enabled || _canPop, - onPopInvoked: (bool didPop) { - if (didPop) { - return; - } - widget.onPop?.call(); - }, - // Listen to changes in the navigation stack in the widget subtree. - child: NotificationListener( - onNotification: (NavigationNotification notification) { - // If this subtree cannot handle pop, then set canPop to true so - // that our PopScope will allow the Navigator higher in the tree to - // handle the pop instead. - final bool nextCanPop = !notification.canHandlePop; - if (nextCanPop != _canPop) { - setState(() { - _canPop = nextCanPop; - }); - } - return false; - }, - child: widget.child, - ), - ); - } -} diff --git a/packages/flutter/lib/src/widgets/pop_scope.dart b/packages/flutter/lib/src/widgets/pop_scope.dart deleted file mode 100644 index b47d83fcdbbd0..0000000000000 --- a/packages/flutter/lib/src/widgets/pop_scope.dart +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; - -import 'framework.dart'; -import 'navigator.dart'; -import 'routes.dart'; - -/// Manages system back gestures. -/// -/// The [canPop] parameter can be used to disable system back gestures. Defaults -/// to true, meaning that back gestures happen as usual. -/// -/// The [onPopInvoked] parameter reports when system back gestures occur, -/// regardless of whether or not they were successful. -/// -/// If [canPop] is false, then a system back gesture will not pop the route off -/// of the enclosing [Navigator]. [onPopInvoked] will still be called, and -/// `didPop` will be `false`. -/// -/// If [canPop] is true, then a system back gesture will cause the enclosing -/// [Navigator] to receive a pop as usual. [onPopInvoked] will be called with -/// `didPop` as `true`, unless the pop failed for reasons unrelated to -/// [PopScope], in which case it will be `false`. -/// -/// {@tool dartpad} -/// This sample demonstrates how to use this widget to handle nested navigation -/// in a bottom navigation bar. -/// -/// ** See code in examples/api/lib/widgets/pop_scope/pop_scope.0.dart ** -/// {@end-tool} -/// -/// See also: -/// -/// * [NavigatorPopHandler], which is a less verbose way to handle system back -/// gestures in simple cases of nested [Navigator]s. -/// * [Form.canPop] and [Form.onPopInvoked], which can be used to handle system -/// back gestures in the case of a form with unsaved data. -/// * [ModalRoute.registerPopEntry] and [ModalRoute.unregisterPopEntry], -/// which this widget uses to integrate with Flutter's navigation system. -class PopScope extends StatefulWidget { - /// Creates a widget that registers a callback to veto attempts by the user to - /// dismiss the enclosing [ModalRoute]. - const PopScope({ - super.key, - required this.child, - this.canPop = true, - this.onPopInvoked, - }); - - /// The widget below this widget in the tree. - /// - /// {@macro flutter.widgets.ProxyWidget.child} - final Widget child; - - /// {@template flutter.widgets.PopScope.onPopInvoked} - /// Called after a route pop was handled. - /// {@endtemplate} - /// - /// It's not possible to prevent the pop from happening at the time that this - /// method is called; the pop has already happened. Use [canPop] to - /// disable pops in advance. - /// - /// This will still be called even when the pop is canceled. A pop is canceled - /// when the relevant [Route.popDisposition] returns false, such as when - /// [canPop] is set to false on a [PopScope]. The `didPop` parameter - /// indicates whether or not the back navigation actually happened - /// successfully. - /// - /// See also: - /// - /// * [Route.onPopInvoked], which is similar. - final PopInvokedCallback? onPopInvoked; - - /// {@template flutter.widgets.PopScope.canPop} - /// When false, blocks the current route from being popped. - /// - /// This includes the root route, where upon popping, the Flutter app would - /// exit. - /// - /// If multiple [PopScope] widgets appear in a route's widget subtree, then - /// each and every `canPop` must be `true` in order for the route to be - /// able to pop. - /// - /// [Android's predictive back](https://developer.android.com/guide/navigation/predictive-back-gesture) - /// feature will not animate when this boolean is false. - /// {@endtemplate} - final bool canPop; - - @override - State createState() => _PopScopeState(); -} - -class _PopScopeState extends State implements PopEntry { - ModalRoute? _route; - - @override - PopInvokedCallback? get onPopInvoked => widget.onPopInvoked; - - @override - late final ValueNotifier canPopNotifier; - - @override - void initState() { - super.initState(); - canPopNotifier = ValueNotifier(widget.canPop); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - final ModalRoute? nextRoute = ModalRoute.of(context); - if (nextRoute != _route) { - _route?.unregisterPopEntry(this); - _route = nextRoute; - _route?.registerPopEntry(this); - } - } - - @override - void didUpdateWidget(PopScope oldWidget) { - super.didUpdateWidget(oldWidget); - canPopNotifier.value = widget.canPop; - } - - @override - void dispose() { - _route?.unregisterPopEntry(this); - canPopNotifier.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) => widget.child; -} diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index e54e46ab3c7b8..441486e5ed676 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -717,10 +717,6 @@ mixin LocalHistoryRoute on Route { } } - @Deprecated( - 'Use popDisposition instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', - ) @override Future willPop() async { if (willHandlePopInternally) { @@ -729,14 +725,6 @@ mixin LocalHistoryRoute on Route { return super.willPop(); } - @override - RoutePopDisposition get popDisposition { - if (willHandlePopInternally) { - return RoutePopDisposition.pop; - } - return super.popDisposition; - } - @override bool didPop(T? result) { if (_localHistory != null && _localHistory!.isNotEmpty) { @@ -1502,8 +1490,6 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute _willPopCallbacks = []; - final Set _popEntries = {}; - /// Returns [RoutePopDisposition.doNotPop] if any of callbacks added with /// [addScopedWillPopCallback] returns either false or null. If they all /// return true, the base [Route.willPop]'s result will be returned. The @@ -1522,10 +1508,6 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute willPop() async { final _ModalScopeState? scope = _scopeKey.currentState; @@ -1538,43 +1520,25 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute { + /// ModalRoute? _route; + /// + /// // ... + /// + /// @override + /// void didChangeDependencies() { + /// super.didChangeDependencies(); + /// _route?.removeScopedWillPopCallback(askTheUserIfTheyAreSure); + /// _route = ModalRoute.of(context); + /// _route?.addScopedWillPopCallback(askTheUserIfTheyAreSure); + /// } + /// } + /// ``` + /// {@end-tool} + /// + /// {@tool snippet} + /// If you register a callback manually, be sure to remove the callback with + /// [removeScopedWillPopCallback] by the time the widget has been disposed. A + /// stateful widget can do this in its dispose method (continuing the previous + /// example): + /// + /// ```dart + /// abstract class _MyWidgetState2 extends State { + /// ModalRoute? _route; + /// + /// // ... + /// + /// @override + /// void dispose() { + /// _route?.removeScopedWillPopCallback(askTheUserIfTheyAreSure); + /// _route = null; + /// super.dispose(); + /// } + /// } + /// ``` + /// {@end-tool} + /// /// See also: /// /// * [WillPopScope], which manages the registration and unregistration @@ -1592,10 +1599,6 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute '${objectRuntimeType(this, 'ModalRoute')}($settings, animation: $_animation)'; } @@ -2279,33 +2212,3 @@ typedef RoutePageBuilder = Widget Function(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child); - -/// A callback type for informing that a navigation pop has been invoked, -/// whether or not it was handled successfully. -/// -/// Accepts a didPop boolean indicating whether or not back navigation -/// succeeded. -typedef PopInvokedCallback = void Function(bool didPop); - -/// Allows listening to and preventing pops. -/// -/// Can be registered in [ModalRoute] to listen to pops with [onPopInvoked] or -/// to enable/disable them with [canPopNotifier]. -/// -/// See also: -/// -/// * [PopScope], which provides similar functionality in a widget. -/// * [ModalRoute.registerPopEntry], which unregisters instances of this. -/// * [ModalRoute.unregisterPopEntry], which unregisters instances of this. -abstract class PopEntry { - /// {@macro flutter.widgets.PopScope.onPopInvoked} - PopInvokedCallback? get onPopInvoked; - - /// {@macro flutter.widgets.PopScope.canPop} - ValueListenable get canPopNotifier; - - @override - String toString() { - return 'PopEntry canPop: ${canPopNotifier.value}, onPopInvoked: $onPopInvoked'; - } -} diff --git a/packages/flutter/lib/src/widgets/will_pop_scope.dart b/packages/flutter/lib/src/widgets/will_pop_scope.dart index eefe437983375..ab90c7f49de01 100644 --- a/packages/flutter/lib/src/widgets/will_pop_scope.dart +++ b/packages/flutter/lib/src/widgets/will_pop_scope.dart @@ -9,25 +9,26 @@ import 'routes.dart'; /// Registers a callback to veto attempts by the user to dismiss the enclosing /// [ModalRoute]. /// +/// {@tool dartpad} +/// Whenever the back button is pressed, you will get a callback at [onWillPop], +/// which returns a [Future]. If the [Future] returns true, the screen is +/// popped. +/// +/// ** See code in examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [ModalRoute.addScopedWillPopCallback] and [ModalRoute.removeScopedWillPopCallback], /// which this widget uses to register and unregister [onWillPop]. /// * [Form], which provides an `onWillPop` callback that enables the form /// to veto a `pop` initiated by the app's back button. -@Deprecated( - 'Use PopScope instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', -) +/// class WillPopScope extends StatefulWidget { /// Creates a widget that registers a callback to veto attempts by the user to /// dismiss the enclosing [ModalRoute]. /// /// The [child] argument must not be null. - @Deprecated( - 'Use PopScope instead. ' - 'This feature was deprecated after v3.12.0-1.0.pre.', - ) const WillPopScope({ super.key, required this.child, diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 3ca0999b994d0..539d6aac62956 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -81,7 +81,6 @@ export 'src/widgets/media_query.dart'; export 'src/widgets/modal_barrier.dart'; export 'src/widgets/navigation_toolbar.dart'; export 'src/widgets/navigator.dart'; -export 'src/widgets/navigator_pop_handler.dart'; export 'src/widgets/nested_scroll_view.dart'; export 'src/widgets/notification_listener.dart'; export 'src/widgets/orientation_builder.dart'; @@ -96,7 +95,6 @@ export 'src/widgets/placeholder.dart'; export 'src/widgets/platform_menu_bar.dart'; export 'src/widgets/platform_selectable_region_context_menu.dart'; export 'src/widgets/platform_view.dart'; -export 'src/widgets/pop_scope.dart'; export 'src/widgets/preferred_size.dart'; export 'src/widgets/primary_scroll_controller.dart'; export 'src/widgets/raw_keyboard_listener.dart'; diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index b376a92ecf276..a8a43b510277d 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; + import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../image_data.dart'; import '../rendering/rendering_tester.dart' show TestCallbackPainter; -import '../widgets/navigator_utils.dart'; late List selectedTabs; @@ -1216,132 +1215,6 @@ void main() { expect(find.text('Content 2'), findsNothing); expect(find.text('Content 3'), findsNothing); }); - - group('Android Predictive Back', () { - bool? lastFrameworkHandlesBack; - setUp(() { - // Initialize to false. Because this uses a static boolean internally, it - // is not reset between tests or calls to pumpWidget. Explicitly setting - // it to false before each test makes them behave deterministically. - SystemNavigator.setFrameworkHandlesBack(false); - lastFrameworkHandlesBack = null; - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { - if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { - expect(methodCall.arguments, isA()); - lastFrameworkHandlesBack = methodCall.arguments as bool; - } - return; - }); - }); - - tearDown(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, null); - SystemNavigator.setFrameworkHandlesBack(true); - }); - - testWidgets('System back navigation inside of tabs', (WidgetTester tester) async { - await tester.pumpWidget( - CupertinoApp( - home: MediaQuery( - data: const MediaQueryData( - viewInsets: EdgeInsets.only(bottom: 200), - ), - child: CupertinoTabScaffold( - tabBar: _buildTabBar(), - tabBuilder: (BuildContext context, int index) { - return CupertinoTabView( - builder: (BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text('Page 1 of tab ${index + 1}'), - ), - child: Center( - child: CupertinoButton( - child: const Text('Next page'), - onPressed: () { - Navigator.of(context).push( - CupertinoPageRoute( - builder: (BuildContext context) { - return CupertinoPageScaffold( - navigationBar: CupertinoNavigationBar( - middle: Text('Page 2 of tab ${index + 1}'), - ), - child: Center( - child: CupertinoButton( - child: const Text('Back'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ), - ); - }, - ), - ); - }, - ), - ), - ); - }, - ); - }, - ), - ), - ), - ); - - expect(find.text('Page 1 of tab 1'), findsOneWidget); - expect(find.text('Page 2 of tab 1'), findsNothing); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Next page')); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 1'), findsNothing); - expect(find.text('Page 2 of tab 1'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 1'), findsOneWidget); - expect(find.text('Page 2 of tab 1'), findsNothing); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Next page')); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 1'), findsNothing); - expect(find.text('Page 2 of tab 1'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Tab 2')); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 2'), findsOneWidget); - expect(find.text('Page 2 of tab 2'), findsNothing); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Tab 1')); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 1'), findsNothing); - expect(find.text('Page 2 of tab 1'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 1'), findsOneWidget); - expect(find.text('Page 2 of tab 1'), findsNothing); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Tab 2')); - await tester.pumpAndSettle(); - expect(find.text('Page 1 of tab 2'), findsOneWidget); - expect(find.text('Page 2 of tab 2'), findsNothing); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: kIsWeb, // [intended] frameworkHandlesBack not used on web. - ); - }); } CupertinoTabBar _buildTabBar({ int selectedTab = 0 }) { diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index d403ceba9c80f..26d1463639259 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -6,12 +6,9 @@ import 'dart:ui' show FlutterView; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'navigator_utils.dart'; import 'observer_tester.dart'; import 'semantics_tester.dart'; @@ -4156,719 +4153,6 @@ void main() { expect(const RouteSettings().toString(), 'RouteSettings(none, null)'); }); }); - - group('Android Predictive Back', () { - bool? lastFrameworkHandlesBack; - setUp(() { - // Initialize to false. Because this uses a static boolean internally, it - // is not reset between tests or calls to pumpWidget. Explicitly setting - // it to false before each test makes them behave deterministically. - SystemNavigator.setFrameworkHandlesBack(false); - lastFrameworkHandlesBack = null; - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { - if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { - expect(methodCall.arguments, isA()); - lastFrameworkHandlesBack = methodCall.arguments as bool; - } - return; - }); - }); - - tearDown(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, null); - SystemNavigator.setFrameworkHandlesBack(true); - }); - - testWidgets('a single route is already defaulted to false', (WidgetTester tester) async { - await tester.pumpWidget( - const MaterialApp( - home: Scaffold( - body: Text('home'), - ) - ) - ); - - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - testWidgets('navigating around a single Navigator with .pop', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext context) => _LinksPage( - title: 'Home page', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one'); - }, - child: const Text('Go to one'), - ), - ], - ), - '/one': (BuildContext context) => _LinksPage( - title: 'Page one', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one/one'); - }, - child: const Text('Go to one/one'), - ), - ], - ), - '/one/one': (BuildContext context) => const _LinksPage( - title: 'Page one - one', - ), - }, - ), - ); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go back')); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go to one/one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one - one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go back')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go back')); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - testWidgets('navigating around a single Navigator with system back', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext context) => _LinksPage( - title: 'Home page', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one'); - }, - child: const Text('Go to one'), - ), - ], - ), - '/one': (BuildContext context) => _LinksPage( - title: 'Page one', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one/one'); - }, - child: const Text('Go to one/one'), - ), - ], - ), - '/one/one': (BuildContext context) => const _LinksPage( - title: 'Page one - one', - ), - }, - ), - ); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go to one/one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one - one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - testWidgets('a single Navigator with a PopScope that defaults to enabled', (WidgetTester tester) async { - bool canPop = true; - late StateSetter setState; - await tester.pumpWidget( - StatefulBuilder( - builder: (BuildContext context, StateSetter setter) { - setState = setter; - return MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext context) => _LinksPage( - title: 'Home page', - canPop: canPop, - ), - }, - ); - }, - ), - ); - - expect(lastFrameworkHandlesBack, isFalse); - - setState(() { - canPop = false; - }); - await tester.pump(); - - expect(lastFrameworkHandlesBack, isTrue); - - setState(() { - canPop = true; - }); - await tester.pump(); - - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - testWidgets('a single Navigator with a PopScope that defaults to disabled', (WidgetTester tester) async { - bool canPop = false; - late StateSetter setState; - await tester.pumpWidget( - StatefulBuilder( - builder: (BuildContext context, StateSetter setter) { - setState = setter; - return MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext context) => _LinksPage( - title: 'Home page', - canPop: canPop, - ), - }, - ); - }, - ), - ); - - expect(lastFrameworkHandlesBack, isTrue); - - setState(() { - canPop = true; - }); - await tester.pump(); - - expect(lastFrameworkHandlesBack, isFalse); - - setState(() { - canPop = false; - }); - await tester.pump(); - - expect(lastFrameworkHandlesBack, isTrue); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - // Test both system back gestures and Navigator.pop. - for (final _BackType backType in _BackType.values) { - testWidgets('navigating around nested Navigators', (WidgetTester tester) async { - final GlobalKey nav = GlobalKey(); - final GlobalKey nestedNav = GlobalKey(); - Future goBack() async { - switch (backType) { - case _BackType.systemBack: - return simulateSystemBack(); - case _BackType.navigatorPop: - if (nestedNav.currentState != null) { - if (nestedNav.currentState!.mounted && nestedNav.currentState!.canPop()) { - return nestedNav.currentState?.pop(); - } - } - return nav.currentState?.pop(); - } - } - await tester.pumpWidget( - MaterialApp( - navigatorKey: nav, - initialRoute: '/', - routes: { - '/': (BuildContext context) => _LinksPage( - title: 'Home page', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one'); - }, - child: const Text('Go to one'), - ), - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/nested'); - }, - child: const Text('Go to nested'), - ), - ], - ), - '/one': (BuildContext context) => _LinksPage( - title: 'Page one', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one/one'); - }, - child: const Text('Go to one/one'), - ), - ], - ), - '/nested': (BuildContext context) => _NestedNavigatorsPage( - navigatorKey: nestedNav, - ), - }, - ), - ); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await goBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to nested')); - await tester.pumpAndSettle(); - - expect(find.text('Nested - home'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go to nested/one')); - await tester.pumpAndSettle(); - - expect(find.text('Nested - page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await goBack(); - await tester.pumpAndSettle(); - - expect(find.text('Nested - home'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await goBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - } - - testWidgets('nested Navigators with a nested PopScope', (WidgetTester tester) async { - bool canPop = true; - late StateSetter setState; - await tester.pumpWidget( - StatefulBuilder( - builder: (BuildContext context, StateSetter setter) { - setState = setter; - return MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext context) => _LinksPage( - title: 'Home page', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one'); - }, - child: const Text('Go to one'), - ), - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/nested'); - }, - child: const Text('Go to nested'), - ), - ], - ), - '/one': (BuildContext context) => _LinksPage( - title: 'Page one', - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one/one'); - }, - child: const Text('Go to one/one'), - ), - ], - ), - '/nested': (BuildContext context) => _NestedNavigatorsPage( - popScopePageEnabled: canPop, - ), - }, - ); - }, - ), - ); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to nested')); - await tester.pumpAndSettle(); - - expect(find.text('Nested - home'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go to nested/popscope')); - await tester.pumpAndSettle(); - - expect(find.text('Nested - PopScope'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - // Going back works because canPop is true. - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Nested - home'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await tester.tap(find.text('Go to nested/popscope')); - await tester.pumpAndSettle(); - - expect(find.text('Nested - PopScope'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - setState(() { - canPop = false; - }); - await tester.pumpAndSettle(); - - expect(lastFrameworkHandlesBack, isTrue); - - // Now going back doesn't work because canPop is false, but it still - // has no effect on the system navigator due to all of the other routes. - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Nested - PopScope'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - setState(() { - canPop = true; - }); - await tester.pump(); - - expect(lastFrameworkHandlesBack, isTrue); - - // And going back works again after switching canPop back to true. - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Nested - home'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - group('Navigator page API', () { - testWidgets('starting with one route as usual', (WidgetTester tester) async { - late StateSetter builderSetState; - final List<_Page> pages = <_Page>[_Page.home]; - bool canPop() => pages.length <= 1; - - await tester.pumpWidget( - MaterialApp( - home: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - builderSetState = setState; - return PopScope( - canPop: canPop(), - onPopInvoked: (bool success) { - if (success || pages.last == _Page.noPop) { - return; - } - setState(() { - pages.removeLast(); - }); - }, - child: Navigator( - onPopPage: (Route route, void result) { - if (!route.didPop(null)) { - return false; - } - setState(() { - pages.removeLast(); - }); - return true; - }, - pages: pages.map((_Page page) { - switch (page) { - case _Page.home: - return MaterialPage( - child: _LinksPage( - title: 'Home page', - buttons: [ - TextButton( - onPressed: () { - setState(() { - pages.add(_Page.one); - }); - }, - child: const Text('Go to _Page.one'), - ), - TextButton( - onPressed: () { - setState(() { - pages.add(_Page.noPop); - }); - }, - child: const Text('Go to _Page.noPop'), - ), - ], - ), - ); - case _Page.one: - return const MaterialPage( - child: _LinksPage( - title: 'Page one', - ), - ); - case _Page.noPop: - return const MaterialPage( - child: _LinksPage( - title: 'Cannot pop page', - canPop: false, - ), - ); - } - }).toList(), - ), - ); - }, - ), - ), - ); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to _Page.one')); - await tester.pumpAndSettle(); - - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - - await tester.tap(find.text('Go to _Page.noPop')); - await tester.pumpAndSettle(); - - expect(find.text('Cannot pop page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Cannot pop page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - // Circumvent "Cannot pop page" by directly modifying pages. - builderSetState(() { - pages.removeLast(); - }); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - - testWidgets('starting with existing route history', (WidgetTester tester) async { - final List<_Page> pages = <_Page>[_Page.home, _Page.one]; - bool canPop() => pages.length <= 1; - - await tester.pumpWidget( - MaterialApp( - home: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return PopScope( - canPop: canPop(), - onPopInvoked: (bool success) { - if (success || pages.last == _Page.noPop) { - return; - } - setState(() { - pages.removeLast(); - }); - }, - child: Navigator( - onPopPage: (Route route, void result) { - if (!route.didPop(null)) { - return false; - } - setState(() { - pages.removeLast(); - }); - return true; - }, - pages: pages.map((_Page page) { - switch (page) { - case _Page.home: - return MaterialPage( - child: _LinksPage( - title: 'Home page', - buttons: [ - TextButton( - onPressed: () { - setState(() { - pages.add(_Page.one); - }); - }, - child: const Text('Go to _Page.one'), - ), - TextButton( - onPressed: () { - setState(() { - pages.add(_Page.noPop); - }); - }, - child: const Text('Go to _Page.noPop'), - ), - ], - ), - ); - case _Page.one: - return const MaterialPage( - child: _LinksPage( - title: 'Page one', - ), - ); - case _Page.noPop: - return const MaterialPage( - child: _LinksPage( - title: 'Cannot pop page', - canPop: false, - ), - ); - } - }).toList(), - ), - ); - }, - ), - ), - ); - - expect(find.text('Home page'), findsNothing); - expect(find.text('Page one'), findsOneWidget); - expect(lastFrameworkHandlesBack, isTrue); - - await simulateSystemBack(); - await tester.pumpAndSettle(); - - expect(find.text('Home page'), findsOneWidget); - expect(find.text('Page one'), findsNothing); - expect(lastFrameworkHandlesBack, isFalse); - }, - variant: const TargetPlatformVariant({ TargetPlatform.android }), - skip: isBrowser, // [intended] only non-web Android supports predictive back. - ); - }); - }); } typedef AnnouncementCallBack = void Function(Route?); @@ -5151,153 +4435,3 @@ class TestDependencies extends StatelessWidget { ); } } - -enum _BackType { - systemBack, - navigatorPop, -} - -enum _Page { - home, - one, - noPop, -} - -class _LinksPage extends StatelessWidget { - const _LinksPage ({ - this.buttons = const [], - this.canPop, - required this.title, - this.onBack, - }); - - final List buttons; - final bool? canPop; - final VoidCallback? onBack; - final String title; - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(title), - ...buttons, - if (Navigator.of(context).canPop()) - TextButton( - onPressed: onBack ?? () { - Navigator.of(context).pop(); - }, - child: const Text('Go back'), - ), - if (canPop != null) - PopScope( - canPop: canPop!, - child: const SizedBox.shrink(), - ), - ], - ), - ), - ); - } -} - -class _NestedNavigatorsPage extends StatefulWidget { - const _NestedNavigatorsPage({ - this.popScopePageEnabled, - this.navigatorKey, - }); - - /// Whether the PopScope on the /popscope page is enabled. - /// - /// If null, then no PopScope is built at all. - final bool? popScopePageEnabled; - - final GlobalKey? navigatorKey; - - @override - State<_NestedNavigatorsPage> createState() => _NestedNavigatorsPageState(); -} - -class _NestedNavigatorsPageState extends State<_NestedNavigatorsPage> { - late final GlobalKey _navigatorKey; - - @override - void initState() { - super.initState(); - _navigatorKey = widget.navigatorKey ?? GlobalKey(); - } - - @override - Widget build(BuildContext context) { - final BuildContext rootContext = context; - return NavigatorPopHandler( - onPop: () { - if (widget.popScopePageEnabled == false) { - return; - } - _navigatorKey.currentState!.pop(); - }, - child: Navigator( - key: _navigatorKey, - initialRoute: '/', - onGenerateRoute: (RouteSettings settings) { - switch (settings.name) { - case '/': - return MaterialPageRoute( - builder: (BuildContext context) { - return _LinksPage( - title: 'Nested - home', - onBack: () { - Navigator.of(rootContext).pop(); - }, - buttons: [ - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one'); - }, - child: const Text('Go to nested/one'), - ), - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/popscope'); - }, - child: const Text('Go to nested/popscope'), - ), - TextButton( - onPressed: () { - Navigator.of(rootContext).pop(); - }, - child: const Text('Go back out of nested nav'), - ), - ], - ); - }, - ); - case '/one': - return MaterialPageRoute( - builder: (BuildContext context) { - return const _LinksPage( - title: 'Nested - page one', - ); - }, - ); - case '/popscope': - return MaterialPageRoute( - builder: (BuildContext context) { - return _LinksPage( - canPop: widget.popScopePageEnabled, - title: 'Nested - PopScope', - ); - }, - ); - default: - throw Exception('Invalid route: ${settings.name}'); - } - }, - ), - ); - } -} diff --git a/packages/flutter/test/widgets/navigator_utils.dart b/packages/flutter/test/widgets/navigator_utils.dart deleted file mode 100644 index 46f1f9b1ac469..0000000000000 --- a/packages/flutter/test/widgets/navigator_utils.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; - -/// Simulates a system back, like a back gesture on Android. -/// -/// Sends the same platform channel message that the engine sends when it -/// receives a system back. -Future simulateSystemBack() { - return TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage( - 'flutter/navigation', - const JSONMessageCodec().encodeMessage({ - 'method': 'popRoute', - }), - (ByteData? _) {}, - ); -} diff --git a/packages/flutter/test/widgets/pop_scope_test.dart b/packages/flutter/test/widgets/pop_scope_test.dart deleted file mode 100644 index c5d0e88545034..0000000000000 --- a/packages/flutter/test/widgets/pop_scope_test.dart +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'navigator_utils.dart'; - -void main() { - bool? lastFrameworkHandlesBack; - setUp(() { - // Initialize to false. Because this uses a static boolean internally, it - // is not reset between tests or calls to pumpWidget. Explicitly setting - // it to false before each test makes them behave deterministically. - SystemNavigator.setFrameworkHandlesBack(false); - lastFrameworkHandlesBack = null; - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { - if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { - expect(methodCall.arguments, isA()); - lastFrameworkHandlesBack = methodCall.arguments as bool; - } - return; - }); - }); - - tearDown(() { - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, null); - SystemNavigator.setFrameworkHandlesBack(true); - }); - - testWidgets('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { - bool canPop = false; - late StateSetter setState; - late BuildContext context; - await tester.pumpWidget( - MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext buildContext) => Scaffold( - body: StatefulBuilder( - builder: (BuildContext buildContext, StateSetter stateSetter) { - context = buildContext; - setState = stateSetter; - return PopScope( - canPop: canPop, - child: const Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Home/PopScope Page'), - ], - ), - ), - ); - }, - ), - ), - }, - ), - ); - - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); - - setState(() { - canPop = true; - }); - await tester.pump(); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); - }, - variant: TargetPlatformVariant.all(), - ); - - testWidgets('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async { - final GlobalKey nav = GlobalKey(); - bool canPop = true; - late StateSetter setState; - late BuildContext homeContext; - late BuildContext oneContext; - late bool lastPopSuccess; - await tester.pumpWidget( - MaterialApp( - navigatorKey: nav, - initialRoute: '/', - routes: { - '/': (BuildContext context) { - homeContext = context; - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Home Page'), - TextButton( - onPressed: () { - Navigator.of(context).pushNamed('/one'); - }, - child: const Text('Next'), - ), - ], - ), - ), - ); - }, - '/one': (BuildContext context) => Scaffold( - body: StatefulBuilder( - builder: (BuildContext context, StateSetter stateSetter) { - oneContext = context; - setState = stateSetter; - return PopScope( - canPop: canPop, - onPopInvoked: (bool didPop) { - lastPopSuccess = didPop; - }, - child: const Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('PopScope Page'), - ], - ), - ), - ); - }, - ), - ), - }, - ), - ); - - expect(find.text('Home Page'), findsOneWidget); - expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); - - await tester.tap(find.text('Next')); - await tester.pumpAndSettle(); - expect(find.text('PopScope Page'), findsOneWidget); - expect(find.text('Home Page'), findsNothing); - expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - - // When canPop is true, can use pop to go back. - nav.currentState!.maybePop(); - await tester.pumpAndSettle(); - expect(lastPopSuccess, true); - expect(find.text('Home Page'), findsOneWidget); - expect(find.text('PopScope Page'), findsNothing); - expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - - await tester.tap(find.text('Next')); - await tester.pumpAndSettle(); - expect(find.text('PopScope Page'), findsOneWidget); - expect(find.text('Home Page'), findsNothing); - expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - - // When canPop is true, can use system back to go back. - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(lastPopSuccess, true); - expect(find.text('Home Page'), findsOneWidget); - expect(find.text('PopScope Page'), findsNothing); - expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - - await tester.tap(find.text('Next')); - await tester.pumpAndSettle(); - expect(find.text('PopScope Page'), findsOneWidget); - expect(find.text('Home Page'), findsNothing); - expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - - setState(() { - canPop = false; - }); - await tester.pump(); - - // When canPop is false, can't use pop to go back. - nav.currentState!.maybePop(); - await tester.pumpAndSettle(); - expect(lastPopSuccess, false); - expect(find.text('PopScope Page'), findsOneWidget); - expect(find.text('Home Page'), findsNothing); - expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.doNotPop); - - // When canPop is false, can't use system back to go back. - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(lastPopSuccess, false); - expect(find.text('PopScope Page'), findsOneWidget); - expect(find.text('Home Page'), findsNothing); - expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.doNotPop); - - // Toggle canPop back to true and back works again. - setState(() { - canPop = true; - }); - await tester.pump(); - - nav.currentState!.maybePop(); - await tester.pumpAndSettle(); - expect(lastPopSuccess, true); - expect(find.text('Home Page'), findsOneWidget); - expect(find.text('PopScope Page'), findsNothing); - expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - - await tester.tap(find.text('Next')); - await tester.pumpAndSettle(); - expect(find.text('PopScope Page'), findsOneWidget); - expect(find.text('Home Page'), findsNothing); - expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - - await simulateSystemBack(); - await tester.pumpAndSettle(); - expect(lastPopSuccess, true); - expect(find.text('Home Page'), findsOneWidget); - expect(find.text('PopScope Page'), findsNothing); - expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - }, - variant: TargetPlatformVariant.all(), - ); - - testWidgets('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async { - bool usePopScope = true; - late StateSetter setState; - late BuildContext context; - await tester.pumpWidget( - MaterialApp( - initialRoute: '/', - routes: { - '/': (BuildContext buildContext) => Scaffold( - body: StatefulBuilder( - builder: (BuildContext buildContext, StateSetter stateSetter) { - context = buildContext; - setState = stateSetter; - const Widget child = Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Home/PopScope Page'), - ], - ), - ); - if (!usePopScope) { - return child; - } - return const PopScope( - canPop: false, - child: child, - ); - }, - ), - ), - }, - ), - ); - - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); - - setState(() { - usePopScope = false; - }); - await tester.pump(); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); - }, - variant: TargetPlatformVariant.all(), - ); - - testWidgets('identical PopScopes', (WidgetTester tester) async { - bool usePopScope1 = true; - bool usePopScope2 = true; - late StateSetter setState; - late BuildContext context; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: StatefulBuilder( - builder: (BuildContext buildContext, StateSetter stateSetter) { - context = buildContext; - setState = stateSetter; - return Column( - children: [ - if (usePopScope1) - const PopScope( - canPop: false, - child: Text('hello'), - ), - if (usePopScope2) - const PopScope( - canPop: false, - child: Text('hello'), - ), - ], - ); - }, - ), - ), - ), - ); - - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); - - // Despite being in the widget tree twice, the ModalRoute has only ever - // registered one PopScopeInterface for it. Removing one makes it think that - // both have been removed. - setState(() { - usePopScope1 = false; - }); - await tester.pump(); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isTrue); - } - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); - - setState(() { - usePopScope2 = false; - }); - await tester.pump(); - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { - expect(lastFrameworkHandlesBack, isFalse); - } - expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); - }, - variant: TargetPlatformVariant.all(), - ); -} From 9b261a77001d93a4b37c1e87e3a66bd7e7dc4043 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 23:24:14 +0000 Subject: [PATCH 0604/1547] Bump github/codeql-action from 2.21.2 to 2.21.3 (#132165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.2 to 2.21.3.
Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

[UNRELEASED]

No user facing changes.

2.21.3 - 08 Aug 2023

  • We are rolling out a feature in August 2023 that will improve multi-threaded performance on larger runners. #1817
  • We are rolling out a feature in August 2023 that adds beta support for Project Lombok when analyzing Java. #1809
  • Reduce disk space usage when downloading the CodeQL bundle. #1820

2.21.2 - 28 Jul 2023

  • Update default CodeQL bundle version to 2.14.1. #1797
  • Avoid duplicating the analysis summary within the logs. #1811

2.21.1 - 26 Jul 2023

  • Improve the handling of fatal errors from the CodeQL CLI. #1795
  • Add the sarif-output output to the analyze action that contains the path to the directory of the generated SARIF. #1799

2.21.0 - 19 Jul 2023

  • CodeQL Action now requires CodeQL CLI 2.9.4 or later. For more information, see the corresponding changelog entry for CodeQL Action version 2.20.4. #1724

2.20.4 - 14 Jul 2023

  • This is the last release of the Action that supports CodeQL CLI versions 2.8.5 to 2.9.3. These versions of the CodeQL CLI were deprecated on June 20, 2023 alongside GitHub Enterprise Server 3.5 and will not be supported by the next release of the CodeQL Action (2.21.0).
    • If you are using one of these versions, please update to CodeQL CLI version 2.9.4 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
    • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.8.5 and 2.9.3, you can replace 'github/codeql-action/@​v2' by 'github/codeql-action/@​v2.20.4' in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
  • We are rolling out a feature in July 2023 that will slightly reduce the default amount of RAM used for query execution, in proportion to the runner's total memory. This will help to avoid out-of-memory failures on larger runners. #1760
  • Update default CodeQL bundle version to 2.14.0. #1762

2.20.3 - 06 Jul 2023

  • Update default CodeQL bundle version to 2.13.5. #1743

2.20.2 - 03 Jul 2023

No user facing changes.

2.20.1 - 21 Jun 2023

  • Update default CodeQL bundle version to 2.13.4. #1721
  • Experimental: add a new resolve-environment action which attempts to infer a configuration for the build environment that is required to build a given project. Do not use this in production as it is part of an internal experiment and subject to change at any time.

2.20.0 - 13 Jun 2023

... (truncated)

Commits
  • 5b6282e Merge pull request #1829 from github/update-v2.21.3-f9a7c6738
  • f0f7a35 Add changenote for Lombok rollout
  • dda4ed3 Update changelog for v2.21.3
  • f9a7c67 Merge pull request #1827 from github/dependabot/npm_and_yarn/npm-5103036bd1
  • 31b9dd1 Update checked-in dependencies
  • 7e2f56a Bump the npm group with 3 updates
  • 878ae4a Merge pull request #1823 from github/henrymercer/setup-swift-more-consistent
  • 63602c0 Merge pull request #1824 from github/henrymercer/cli-notifications-fix
  • 66dc883 Merge pull request #1826 from github/henrymercer/increase-reserved-scaling-fa...
  • 2203178 Increase scaling factor for reserved RAM to 5%
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.21.2&new-version=2.21.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index cdeabc9526a93..91d4aa072ae3e 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05 + uses: github/codeql-action/upload-sarif@5b6282e01c62d02e720b81eb8a51204f527c3624 with: sarif_file: results.sarif From 40a3e4817e2d609896a3b3b89032c0112682d133 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 19:24:16 -0400 Subject: [PATCH 0605/1547] Roll Flutter Engine from 934ebb005d02 to 82292b8390cb (3 revisions) (#132166) https://github.com/flutter/engine/compare/934ebb005d02...82292b8390cb 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 9fa8ebdfdbb8 to 68b80f663be6 (1 revision) (flutter/engine#44511) 2023-08-08 31859944+LongCatIsLooong@users.noreply.github.com Disable HTML renderer paragraph input width flooring (flutter/engine#44478) 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 5c8c7faf9131 to 9fa8ebdfdbb8 (2 revisions) (flutter/engine#44507) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c08aadb7d9564..f5771a7758a1a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -934ebb005d02785deb50650f620fc5241719fa7e +82292b8390cb5f8122bfc39d4e5ced0f922017e3 From 0bc5a2bca440ba853629ee575e59700b39de2ab6 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:24:19 -0700 Subject: [PATCH 0606/1547] Add `textCapitalization` property for `SearchBar` and `SearchAnchor` (#131459) This is to add `textCapitalization` property for `SearchBar` and `SearchAnchor`. Fixes: #131260 --- .../gen_defaults/lib/search_bar_template.dart | 3 + .../lib/src/material/search_anchor.dart | 23 ++++ .../lib/src/material/search_bar_theme.dart | 13 ++- .../test/material/search_anchor_test.dart | 102 ++++++++++++++++++ .../test/material/search_bar_theme_test.dart | 8 ++ 5 files changed, 148 insertions(+), 1 deletion(-) diff --git a/dev/tools/gen_defaults/lib/search_bar_template.dart b/dev/tools/gen_defaults/lib/search_bar_template.dart index 5a6d7a660c1ac..670121b9cb505 100644 --- a/dev/tools/gen_defaults/lib/search_bar_template.dart +++ b/dev/tools/gen_defaults/lib/search_bar_template.dart @@ -71,6 +71,9 @@ class _SearchBarDefaultsM3 extends SearchBarThemeData { @override BoxConstraints get constraints => const BoxConstraints(minWidth: 360.0, maxWidth: 800.0, minHeight: ${getToken('md.comp.search-bar.container.height')}); + + @override + TextCapitalization get textCapitalization => TextCapitalization.none; } '''; } diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index fbb4682c8ee7e..6cb8c22c1c627 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -126,6 +126,7 @@ class SearchAnchor extends StatefulWidget { this.headerHintStyle, this.dividerColor, this.viewConstraints, + this.textCapitalization, required this.builder, required this.suggestionsBuilder, }); @@ -170,6 +171,7 @@ class SearchAnchor extends StatefulWidget { BoxConstraints? viewConstraints, bool? isFullScreen, SearchController searchController, + TextCapitalization textCapitalization, required SuggestionsBuilder suggestionsBuilder }) = _SearchAnchorWithSearchBar; @@ -286,6 +288,9 @@ class SearchAnchor extends StatefulWidget { /// ``` final BoxConstraints? viewConstraints; + /// {@macro flutter.widgets.editableText.textCapitalization} + final TextCapitalization? textCapitalization; + /// Called to create a widget which can open a search view route when it is tapped. /// /// The widget returned by this builder is faded out when it is tapped. @@ -361,6 +366,7 @@ class _SearchAnchorState extends State { anchorKey: _anchorKey, searchController: _searchController, suggestionsBuilder: widget.suggestionsBuilder, + textCapitalization: widget.textCapitalization, )); } @@ -426,6 +432,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { this.viewHeaderHintStyle, this.dividerColor, this.viewConstraints, + this.textCapitalization, required this.showFullScreenView, required this.anchorKey, required this.searchController, @@ -447,6 +454,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { final TextStyle? viewHeaderHintStyle; final Color? dividerColor; final BoxConstraints? viewConstraints; + final TextCapitalization? textCapitalization; final bool showFullScreenView; final GlobalKey anchorKey; final SearchController searchController; @@ -595,6 +603,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { viewBuilder: viewBuilder, searchController: searchController, suggestionsBuilder: suggestionsBuilder, + textCapitalization: textCapitalization, ), ); } @@ -620,6 +629,7 @@ class _ViewContent extends StatefulWidget { this.viewHeaderTextStyle, this.viewHeaderHintStyle, this.dividerColor, + this.textCapitalization, required this.showFullScreenView, required this.topPadding, required this.animation, @@ -644,6 +654,7 @@ class _ViewContent extends StatefulWidget { final TextStyle? viewHeaderTextStyle; final TextStyle? viewHeaderHintStyle; final Color? dividerColor; + final TextCapitalization? textCapitalization; final bool showFullScreenView; final double topPadding; final Animation animation; @@ -824,6 +835,7 @@ class _ViewContentState extends State<_ViewContent> { onChanged: (_) { updateSuggestions(); }, + textCapitalization: widget.textCapitalization, ), ), ), @@ -884,6 +896,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor { super.viewConstraints, super.isFullScreen, super.searchController, + super.textCapitalization, required super.suggestionsBuilder }) : super( viewHintText: viewHintText ?? barHintText, @@ -911,6 +924,7 @@ class _SearchAnchorWithSearchBar extends SearchAnchor { padding: barPadding ?? const MaterialStatePropertyAll(EdgeInsets.symmetric(horizontal: 16.0)), leading: barLeading ?? const Icon(Icons.search), trailing: barTrailing, + textCapitalization: textCapitalization, ); } ); @@ -1022,6 +1036,7 @@ class SearchBar extends StatefulWidget { this.padding, this.textStyle, this.hintStyle, + this.textCapitalization, }); /// Controls the text being edited in the search bar's text field. @@ -1140,6 +1155,9 @@ class SearchBar extends StatefulWidget { /// The default text color is [ColorScheme.onSurfaceVariant]. final MaterialStateProperty? hintStyle; + /// {@macro flutter.widgets.editableText.textCapitalization} + final TextCapitalization? textCapitalization; + @override State createState() => _SearchBarState(); } @@ -1190,6 +1208,7 @@ class _SearchBarState extends State { final BorderSide? effectiveSide = resolve(widget.side, searchBarTheme.side, defaults.side); final EdgeInsetsGeometry? effectivePadding = resolve(widget.padding, searchBarTheme.padding, defaults.padding); final MaterialStateProperty? effectiveOverlayColor = widget.overlayColor ?? searchBarTheme.overlayColor ?? defaults.overlayColor; + final TextCapitalization effectiveTextCapitalization = widget.textCapitalization ?? searchBarTheme.textCapitalization ?? defaults.textCapitalization!; final Set states = _internalStatesController.value; final TextStyle? effectiveHintStyle = widget.hintStyle?.resolve(states) @@ -1273,6 +1292,7 @@ class _SearchBarState extends State { // smaller than 48.0 isDense: true, )), + textCapitalization: effectiveTextCapitalization, ), ), ) @@ -1353,6 +1373,9 @@ class _SearchBarDefaultsM3 extends SearchBarThemeData { @override BoxConstraints get constraints => const BoxConstraints(minWidth: 360.0, maxWidth: 800.0, minHeight: 56.0); + + @override + TextCapitalization get textCapitalization => TextCapitalization.none; } // END GENERATED TOKEN PROPERTIES - SearchBar diff --git a/packages/flutter/lib/src/material/search_bar_theme.dart b/packages/flutter/lib/src/material/search_bar_theme.dart index c738d0e9e7813..94e225dd0ccd9 100644 --- a/packages/flutter/lib/src/material/search_bar_theme.dart +++ b/packages/flutter/lib/src/material/search_bar_theme.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; +import '../../services.dart'; import 'material_state.dart'; import 'theme.dart'; @@ -47,6 +48,7 @@ class SearchBarThemeData with Diagnosticable { this.textStyle, this.hintStyle, this.constraints, + this.textCapitalization, }); /// Overrides the default value of the [SearchBar.elevation]. @@ -82,6 +84,9 @@ class SearchBarThemeData with Diagnosticable { /// Overrides the value of size constraints for [SearchBar]. final BoxConstraints? constraints; + /// Overrides the value of [SearchBar.textCapitalization]. + final TextCapitalization? textCapitalization; + /// Creates a copy of this object but with the given fields replaced with the /// new values. SearchBarThemeData copyWith({ @@ -96,6 +101,7 @@ class SearchBarThemeData with Diagnosticable { MaterialStateProperty? textStyle, MaterialStateProperty? hintStyle, BoxConstraints? constraints, + TextCapitalization? textCapitalization, }) { return SearchBarThemeData( elevation: elevation ?? this.elevation, @@ -109,6 +115,7 @@ class SearchBarThemeData with Diagnosticable { textStyle: textStyle ?? this.textStyle, hintStyle: hintStyle ?? this.hintStyle, constraints: constraints ?? this.constraints, + textCapitalization: textCapitalization ?? this.textCapitalization, ); } @@ -131,6 +138,7 @@ class SearchBarThemeData with Diagnosticable { textStyle: MaterialStateProperty.lerp(a?.textStyle, b?.textStyle, t, TextStyle.lerp), hintStyle: MaterialStateProperty.lerp(a?.hintStyle, b?.hintStyle, t, TextStyle.lerp), constraints: BoxConstraints.lerp(a?.constraints, b?.constraints, t), + textCapitalization: t < 0.5 ? a?.textCapitalization : b?.textCapitalization, ); } @@ -147,6 +155,7 @@ class SearchBarThemeData with Diagnosticable { textStyle, hintStyle, constraints, + textCapitalization, ); @override @@ -168,7 +177,8 @@ class SearchBarThemeData with Diagnosticable { && other.padding == padding && other.textStyle == textStyle && other.hintStyle == hintStyle - && other.constraints == constraints; + && other.constraints == constraints + && other.textCapitalization == textCapitalization; } @override @@ -185,6 +195,7 @@ class SearchBarThemeData with Diagnosticable { properties.add(DiagnosticsProperty>('textStyle', textStyle, defaultValue: null)); properties.add(DiagnosticsProperty>('hintStyle', hintStyle, defaultValue: null)); properties.add(DiagnosticsProperty('constraints', constraints, defaultValue: null)); + properties.add(DiagnosticsProperty('textCapitalization', textCapitalization, defaultValue: null)); } // Special case because BorderSide.lerp() doesn't support null arguments diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index 60251704e9ca5..c044bdfc0a4db 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -691,6 +691,108 @@ void main() { expect(inputText.style.color, focusedColor); }); + testWidgets('SearchBar respects textCapitalization property', (WidgetTester tester) async { + Widget buildSearchBar(TextCapitalization textCapitalization) { + return MaterialApp( + home: Center( + child: Material( + child: SearchBar( + textCapitalization: textCapitalization, + ), + ), + ), + ); + } + await tester.pumpWidget(buildSearchBar(TextCapitalization.characters)); + await tester.pump(); + TextField textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.characters); + + await tester.pumpWidget(buildSearchBar(TextCapitalization.sentences)); + await tester.pump(); + textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.sentences); + + await tester.pumpWidget(buildSearchBar(TextCapitalization.words)); + await tester.pump(); + textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.words); + + await tester.pumpWidget(buildSearchBar(TextCapitalization.none)); + await tester.pump(); + textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.none); + }); + + testWidgets('SearchAnchor respects textCapitalization property', (WidgetTester tester) async { + Widget buildSearchAnchor(TextCapitalization textCapitalization) { + return MaterialApp( + home: Center( + child: Material( + child: SearchAnchor( + textCapitalization: textCapitalization, + builder: (BuildContext context, SearchController controller) { + return IconButton( + icon: const Icon(Icons.ac_unit), + onPressed: () { + controller.openView(); + }, + ); + }, + suggestionsBuilder: (BuildContext context, SearchController controller) { + return []; + }, + ), + ), + ), + ); + } + await tester.pumpWidget(buildSearchAnchor(TextCapitalization.characters)); + await tester.pump(); + await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit)); + await tester.pumpAndSettle(); + TextField textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.characters); + await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_back)); + await tester.pump(); + + await tester.pumpWidget(buildSearchAnchor(TextCapitalization.none)); + await tester.pump(); + await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit)); + await tester.pumpAndSettle(); + textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.none); + }); + + testWidgets('SearchAnchor.bar respects textCapitalization property', (WidgetTester tester) async { + Widget buildSearchAnchor(TextCapitalization textCapitalization) { + return MaterialApp( + home: Center( + child: Material( + child: SearchAnchor.bar( + textCapitalization: textCapitalization, + suggestionsBuilder: (BuildContext context, SearchController controller) { + return []; + }, + ), + ), + ), + ); + } + await tester.pumpWidget(buildSearchAnchor(TextCapitalization.characters)); + await tester.pump(); + await tester.tap(find.byType(SearchBar)); // Open search view. + await tester.pumpAndSettle(); + final Finder textFieldFinder = find.descendant(of: findViewContent(), matching: find.byType(TextField)); + final TextField textFieldInView = tester.widget(textFieldFinder); + expect(textFieldInView.textCapitalization, TextCapitalization.characters); + // Close search view. + await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_back)); + await tester.pumpAndSettle(); + final TextField textField = tester.widget(find.byType(TextField)); + expect(textField.textCapitalization, TextCapitalization.characters); + }); + testWidgets('hintStyle can override textStyle for hintText', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/search_bar_theme_test.dart b/packages/flutter/test/material/search_bar_theme_test.dart index 626fe20912010..781984124b521 100644 --- a/packages/flutter/test/material/search_bar_theme_test.dart +++ b/packages/flutter/test/material/search_bar_theme_test.dart @@ -35,6 +35,7 @@ void main() { expect(themeData.textStyle, null); expect(themeData.hintStyle, null); expect(themeData.constraints, null); + expect(themeData.textCapitalization, null); const SearchBarTheme theme = SearchBarTheme(data: SearchBarThemeData(), child: SizedBox()); expect(theme.data.elevation, null); @@ -48,6 +49,7 @@ void main() { expect(theme.data.textStyle, null); expect(theme.data.hintStyle, null); expect(theme.data.constraints, null); + expect(theme.data.textCapitalization, null); }); testWidgetsWithLeakTracking('Default SearchBarThemeData debugFillProperties', (WidgetTester tester) async { @@ -77,6 +79,7 @@ void main() { textStyle: MaterialStatePropertyAll(TextStyle(fontSize: 24.0)), hintStyle: MaterialStatePropertyAll(TextStyle(fontSize: 16.0)), constraints: BoxConstraints(minWidth: 350, maxWidth: 850), + textCapitalization: TextCapitalization.characters, ).debugFillProperties(builder); final List description = builder.properties @@ -95,6 +98,7 @@ void main() { expect(description[8], 'textStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 24.0))'); expect(description[9], 'hintStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 16.0))'); expect(description[10], 'constraints: BoxConstraints(350.0<=w<=850.0, 0.0<=h<=Infinity)'); + expect(description[11], 'textCapitalization: TextCapitalization.characters'); }); group('[Theme, SearchBarTheme, SearchBar properties overrides]', () { @@ -120,6 +124,7 @@ void main() { const MaterialStateProperty textStyle = MaterialStatePropertyAll(textStyleValue); const MaterialStateProperty hintStyle = MaterialStatePropertyAll(hintStyleValue); const BoxConstraints constraints = BoxConstraints(minWidth: 250.0, maxWidth: 300.0, minHeight: 80.0); + const TextCapitalization textCapitalization = TextCapitalization.words; const SearchBarThemeData searchBarTheme = SearchBarThemeData( elevation: elevation, @@ -133,6 +138,7 @@ void main() { textStyle: textStyle, hintStyle: hintStyle, constraints: constraints, + textCapitalization: textCapitalization, ); Widget buildFrame({ @@ -164,6 +170,7 @@ void main() { textStyle: textStyle, hintStyle: hintStyle, constraints: constraints, + textCapitalization: textCapitalization, ); }, ); @@ -223,6 +230,7 @@ void main() { final EditableText inputText = tester.widget(find.text('input')); expect(inputText.style.color, textStyleValue.color); expect(inputText.style.fontSize, textStyleValue.fontSize); + expect(inputText.textCapitalization, textCapitalization); final Rect barRect = tester.getRect(find.byType(SearchBar)); final Rect leadingRect = tester.getRect(find.byIcon(Icons.search)); From 5de6684b9c74d5b44b409d2d3c784f66a1bb8dc3 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:53:10 -0700 Subject: [PATCH 0607/1547] Add more info to `OverlayState.insert` error messages (#129363) I was debugging an Overlay issue and felt I could have identified the problem faster if the existing assertions provided more information about the current state of the OverlayEntry and Overlay. --- packages/flutter/lib/src/widgets/overlay.dart | 65 ++++++++++++++---- .../flutter/test/widgets/overlay_test.dart | 66 +++++++++++++++++++ 2 files changed, 119 insertions(+), 12 deletions(-) diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index 04c71fab73f0e..f62b5fddc169f 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -222,7 +222,7 @@ class OverlayEntry implements Listenable { } @override - String toString() => '${describeIdentity(this)}(opaque: $opaque; maintainState: $maintainState)'; + String toString() => '${describeIdentity(this)}(opaque: $opaque; maintainState: $maintainState)${_disposedByOwner ? "(DISPOSED)" : ""}'; } class _OverlayEntryWidget extends StatefulWidget { @@ -296,7 +296,7 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> { late final Iterable _hitTestOrderIterable = _createChildIterable(reversed: true); // The following uses sync* because hit-testing is lazy, and LinkedList as a - // Iterable doesn't support current modification. + // Iterable doesn't support concurrent modification. Iterable _createChildIterable({ required bool reversed }) sync* { final LinkedList<_OverlayEntryLocation>? children = _sortedTheaterSiblings; if (children == null || children.isEmpty) { @@ -543,6 +543,55 @@ class OverlayState extends State with TickerProviderStateMixin { return _entries.length; } + bool _debugCanInsertEntry(OverlayEntry entry) { + final List operandsInformation = [ + DiagnosticsProperty('The OverlayEntry was', entry, style: DiagnosticsTreeStyle.errorProperty), + DiagnosticsProperty( + 'The Overlay the OverlayEntry was trying to insert to was', this, style: DiagnosticsTreeStyle.errorProperty, + ), + ]; + + if (!mounted) { + throw FlutterError.fromParts([ + ErrorSummary('Attempted to insert an OverlayEntry to an already disposed Overlay.'), + ...operandsInformation, + ]); + } + + final OverlayState? currentOverlay = entry._overlay; + final bool alreadyContainsEntry = _entries.contains(entry); + + if (alreadyContainsEntry) { + final bool inconsistentOverlayState = !identical(currentOverlay, this); + throw FlutterError.fromParts([ + ErrorSummary('The specified entry is already present in the target Overlay.'), + ...operandsInformation, + if (inconsistentOverlayState) ErrorHint('This could be an error in the Flutter framework.') + else ErrorHint( + 'Consider calling remove on the OverlayEntry before inserting it to a different Overlay, ' + 'or switching to the OverlayPortal API to avoid manual OverlayEntry management.' + ), + if (inconsistentOverlayState) DiagnosticsProperty( + "The OverlayEntry's current Overlay was", currentOverlay, style: DiagnosticsTreeStyle.errorProperty, + ), + ]); + } + + if (currentOverlay == null) { + return true; + } + + throw FlutterError.fromParts([ + ErrorSummary('The specified entry is already present in a different Overlay.'), + ...operandsInformation, + DiagnosticsProperty("The OverlayEntry's current Overlay was", currentOverlay, style: DiagnosticsTreeStyle.errorProperty,), + ErrorHint( + 'Consider calling remove on the OverlayEntry before inserting it to a different Overlay, ' + 'or switching to the OverlayPortal API to avoid manual OverlayEntry management.' + ) + ]); + } + /// Insert the given entry into the overlay. /// /// If `below` is non-null, the entry is inserted just below `below`. @@ -552,8 +601,7 @@ class OverlayState extends State with TickerProviderStateMixin { /// It is an error to specify both `above` and `below`. void insert(OverlayEntry entry, { OverlayEntry? below, OverlayEntry? above }) { assert(_debugVerifyInsertPosition(above, below)); - assert(!_entries.contains(entry), 'The specified entry is already present in the Overlay.'); - assert(entry._overlay == null, 'The specified entry is already present in another Overlay.'); + assert(_debugCanInsertEntry(entry)); entry._overlay = this; setState(() { _entries.insert(_insertionIndex(below, above), entry); @@ -569,14 +617,7 @@ class OverlayState extends State with TickerProviderStateMixin { /// It is an error to specify both `above` and `below`. void insertAll(Iterable entries, { OverlayEntry? below, OverlayEntry? above }) { assert(_debugVerifyInsertPosition(above, below)); - assert( - entries.every((OverlayEntry entry) => !_entries.contains(entry)), - 'One or more of the specified entries are already present in the Overlay.', - ); - assert( - entries.every((OverlayEntry entry) => entry._overlay == null), - 'One or more of the specified entries are already present in another Overlay.', - ); + assert(entries.every(_debugCanInsertEntry)); if (entries.isEmpty) { return; } diff --git a/packages/flutter/test/widgets/overlay_test.dart b/packages/flutter/test/widgets/overlay_test.dart index 0914b06dff971..66663e061adb6 100644 --- a/packages/flutter/test/widgets/overlay_test.dart +++ b/packages/flutter/test/widgets/overlay_test.dart @@ -1139,6 +1139,72 @@ void main() { ); }); + testWidgets('OverlayEntry throws if inserted to an invalid Overlay', (WidgetTester tester) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Overlay(), + ), + ); + final OverlayState overlay = tester.state(find.byType(Overlay)); + final OverlayEntry entry = OverlayEntry(builder: (BuildContext context) => const SizedBox()); + expect( + () => overlay.insert(entry), + returnsNormally, + ); + + // Throws when inserted to the same Overlay. + expect( + () => overlay.insert(entry), + throwsA(isA().having( + (FlutterError error) => error.toString(), + 'toString()', + allOf( + contains('The specified entry is already present in the target Overlay.'), + contains('The OverlayEntry was'), + contains('The Overlay the OverlayEntry was trying to insert to was'), + ), + )), + ); + + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: SizedBox(child: Overlay()), + ), + ); + + // Throws if inserted to an already disposed Overlay. + expect( + () => overlay.insert(entry), + throwsA(isA().having( + (FlutterError error) => error.toString(), + 'toString()', + allOf( + contains('Attempted to insert an OverlayEntry to an already disposed Overlay.'), + contains('The OverlayEntry was'), + contains('The Overlay the OverlayEntry was trying to insert to was'), + ), + )), + ); + + final OverlayState newOverlay = tester.state(find.byType(Overlay)); + // Throws when inserted to a different Overlay without calling remove. + expect( + () => newOverlay.insert(entry), + throwsA(isA().having( + (FlutterError error) => error.toString(), + 'toString()', + allOf( + contains('The specified entry is already present in a different Overlay.'), + contains('The OverlayEntry was'), + contains('The Overlay the OverlayEntry was trying to insert to was'), + contains("The OverlayEntry's current Overlay was"), + ), + )), + ); + }); + group('OverlayEntry listenable', () { final GlobalKey overlayKey = GlobalKey(); final Widget emptyOverlay = Directionality( From bf729dcd0feeb74810660cd91704750ed7cc7db9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 20:54:55 -0400 Subject: [PATCH 0608/1547] Roll Flutter Engine from 82292b8390cb to 29b117aa4192 (5 revisions) (#132179) https://github.com/flutter/engine/compare/82292b8390cb...29b117aa4192 2023-08-08 matanlurey@users.noreply.github.com [Impeller] Add gradient dithering for Radial/Sweep/Conical gradients (flutter/engine#44331) 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 68b80f663be6 to 1fbe521b2c56 (2 revisions) (flutter/engine#44518) 2023-08-08 chris@bracken.jp [macOS] Improve engine retain cycle testing (flutter/engine#44509) 2023-08-08 34871572+gmackall@users.noreply.github.com Fix name in description of 'create_cipd_packages.sh' (flutter/engine#44513) 2023-08-08 30870216+gaaclarke@users.noreply.github.com [Impeller] started std::moving `Command`s instead of copying (flutter/engine#44508) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f5771a7758a1a..67aca03289709 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -82292b8390cb5f8122bfc39d4e5ced0f922017e3 +29b117aa4192fbe1757d98ed37913675ff4390d3 From 886d676acf368c77b1a459d4a68c3f52e63f72ee Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 21:40:37 -0400 Subject: [PATCH 0609/1547] Roll Flutter Engine from 29b117aa4192 to 6839b88283b6 (1 revision) (#132181) https://github.com/flutter/engine/compare/29b117aa4192...6839b88283b6 2023-08-08 skia-flutter-autoroll@skia.org Roll Skia from 1fbe521b2c56 to e904a9f2010e (3 revisions) (flutter/engine#44520) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 67aca03289709..bf361254b398d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -29b117aa4192fbe1757d98ed37913675ff4390d3 +6839b88283b6aba59303744a7645fda251d6b31a From d7877d1fe0b874e022a7a6695892bc982e0a7940 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 8 Aug 2023 22:27:24 -0400 Subject: [PATCH 0610/1547] Roll Flutter Engine from 6839b88283b6 to 8ec575168d44 (1 revision) (#132182) https://github.com/flutter/engine/compare/6839b88283b6...8ec575168d44 2023-08-09 matanlurey@users.noreply.github.com [Impeller] Plumb Paint.enableDithering to backend (flutter/engine#44522) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bf361254b398d..13fe261ddae03 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6839b88283b6aba59303744a7645fda251d6b31a +8ec575168d44af07ede1a1fb2cdaff12dabef4f2 From aac018974fcaa5e22603baf49bd33e85cc9e8ae5 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Tue, 8 Aug 2023 21:43:57 -0700 Subject: [PATCH 0611/1547] Use pattern matching to avoid strange type annotations (#131964) Addresses https://github.com/flutter/flutter/pull/131640#discussion_r1284861384 --- packages/flutter/lib/src/rendering/editable.dart | 10 ++++------ packages/flutter/lib/src/rendering/paragraph.dart | 11 ++++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 7952912b1b4bb..779e38371f3cf 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -1918,15 +1918,13 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { final Offset effectivePosition = position - _paintOffset; final InlineSpan? textSpan = _textPainter.text; - if (textSpan != null) { - final TextPosition textPosition = _textPainter.getPositionForOffset(effectivePosition); - final Object? span = textSpan.getSpanForPosition(textPosition); - if (span is HitTestTarget) { + switch (textSpan?.getSpanForPosition(_textPainter.getPositionForOffset(effectivePosition))) { + case final HitTestTarget span: result.add(HitTestEntry(span)); return true; - } + case _: + return hitTestInlineChildren(result, effectivePosition); } - return hitTestInlineChildren(result, effectivePosition); } late TapGestureRecognizer _tap; diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index d53720c869bf9..345bc75c340ca 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -725,12 +725,13 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin Date: Wed, 9 Aug 2023 03:08:20 -0400 Subject: [PATCH 0612/1547] Roll Flutter Engine from 8ec575168d44 to 3d3fb4faed02 (3 revisions) (#132193) https://github.com/flutter/engine/compare/8ec575168d44...3d3fb4faed02 2023-08-09 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from c18Y3Ga7cvdrmy8FQ... to e7bMhkfY-RPMrSMhB... (flutter/engine#44531) 2023-08-09 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 9Pl8nd13UI8rrS3JD... to tO6r8iQqnmsYkLcvZ... (flutter/engine#44529) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from e904a9f2010e to d097852dc928 (1 revision) (flutter/engine#44525) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 9Pl8nd13UI8r to tO6r8iQqnmsY fuchsia/sdk/core/mac-amd64 from c18Y3Ga7cvdr to e7bMhkfY-RPM If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 13fe261ddae03..03649142e5fc3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8ec575168d44af07ede1a1fb2cdaff12dabef4f2 +3d3fb4faed02356ca616a269d827e3736a4b80e3 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 471bfbfd9ac9c..4a09256afc848 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -9Pl8nd13UI8rrS3JDriZPjP71hxAFS9t3dU3klvDmKMC +tO6r8iQqnmsYkLcvZA4V78wIgYbJaaz3RO_wyttfBLgC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 697b6664f2adc..0f9e018d963c0 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -c18Y3Ga7cvdrmy8FQG_Pie4boO7nSoI8zSUksOjUaWEC +e7bMhkfY-RPMrSMhBlm8WZT3x0sZhGnCxtkXrrLWuyYC From f4c25bbb351cc59ffdefe980c0c993196a8a6d47 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 9 Aug 2023 08:14:39 -0700 Subject: [PATCH 0613/1547] Revert "Handle breaking changes in leak_tracker." (#132223) Reverts flutter/flutter#131998 Reverting for https://github.com/flutter/flutter/issues/132222 --- dev/automated_tests/pubspec.yaml | 7 +- dev/benchmarks/complex_layout/pubspec.yaml | 7 +- dev/benchmarks/macrobenchmarks/pubspec.yaml | 7 +- dev/benchmarks/microbenchmarks/pubspec.yaml | 7 +- .../platform_channels_benchmarks/pubspec.yaml | 7 +- .../platform_views_layout/pubspec.yaml | 7 +- .../pubspec.yaml | 7 +- dev/benchmarks/test_apps/stocks/pubspec.yaml | 7 +- dev/bots/pubspec.yaml | 7 +- dev/conductor/core/pubspec.yaml | 7 +- dev/customer_testing/pubspec.yaml | 7 +- dev/devicelab/pubspec.yaml | 7 +- .../android_semantics_testing/pubspec.yaml | 7 +- .../android_views/pubspec.yaml | 7 +- .../deferred_components_test/pubspec.yaml | 7 +- .../external_ui/pubspec.yaml | 7 +- dev/integration_tests/flavors/pubspec.yaml | 7 +- .../flutter_gallery/pubspec.yaml | 7 +- .../gradle_deprecated_settings/pubspec.yaml | 4 +- .../hybrid_android_views/pubspec.yaml | 7 +- .../ios_platform_view_tests/pubspec.yaml | 7 +- .../platform_interaction/pubspec.yaml | 7 +- dev/integration_tests/ui/pubspec.yaml | 7 +- .../web_e2e_tests/pubspec.yaml | 7 +- .../windows_startup_test/pubspec.yaml | 7 +- dev/tools/gen_defaults/pubspec.yaml | 7 +- dev/tools/gen_keycodes/pubspec.yaml | 7 +- dev/tools/pubspec.yaml | 7 +- examples/api/pubspec.yaml | 7 +- examples/hello_world/pubspec.yaml | 7 +- examples/platform_channel/pubspec.yaml | 7 +- examples/platform_channel_swift/pubspec.yaml | 7 +- examples/texture/pubspec.yaml | 7 +- packages/flutter/pubspec.yaml | 11 +- .../test/animation/animation_sheet_test.dart | 5 +- .../test/animation/live_binding_test.dart | 2 +- .../flutter/test/flutter_test_config.dart | 2 +- .../test/foundation/leak_tracking.dart | 311 ++++++++---------- .../test/foundation/leak_tracking_test.dart | 235 +++++++++++++ .../foundation/leak_tracking_test/README.md | 4 - .../leak_tracking_config_test/constants.dart | 8 - .../flutter_test_config.dart | 132 -------- .../leak_tracking_config_test.dart | 57 ---- .../leak_tracking_test/leaking_widget.dart | 49 --- .../leak_tracking_test/no_config_test.dart | 51 --- .../leak_tracking_test/no_tracking_test.dart | 21 -- .../gestures/transformed_monodrag_test.dart | 2 +- .../test/gestures/transformed_scale_test.dart | 4 +- .../flutter/test/material/about_test.dart | 14 +- .../adaptive_text_selection_toolbar_test.dart | 6 +- .../material/bottom_sheet_theme_test.dart | 4 +- .../test/material/button_bar_test.dart | 4 +- .../material/checkbox_list_tile_test.dart | 2 - .../test/material/checkbox_theme_test.dart | 2 +- packages/flutter/test/material/chip_test.dart | 18 +- .../test/material/chip_theme_test.dart | 2 - .../test/material/date_range_picker_test.dart | 1 - .../flutter/test/material/dialog_test.dart | 11 +- .../test/material/drawer_button_test.dart | 4 +- .../material/dropdown_form_field_test.dart | 48 +-- .../material/dropdown_menu_theme_test.dart | 8 +- .../test/material/elevated_button_test.dart | 26 +- .../test/material/filled_button_test.dart | 17 +- ...flexible_space_bar_collapse_mode_test.dart | 4 +- .../flexible_space_bar_stretch_mode_test.dart | 4 +- .../floating_action_button_location_test.dart | 6 +- .../material/floating_action_button_test.dart | 14 +- .../test/material/icon_button_test.dart | 24 +- .../flutter/test/material/ink_paint_test.dart | 4 +- .../flutter/test/material/ink_well_test.dart | 20 +- .../test/material/input_chip_test.dart | 5 - .../input_date_picker_form_field_test.dart | 27 +- .../flutter/test/material/list_tile_test.dart | 4 - .../test/material/list_tile_theme_test.dart | 2 +- .../flutter/test/material/magnifier_test.dart | 24 +- .../test/material/material_button_test.dart | 6 - .../test/material/menu_bar_theme_test.dart | 6 +- .../test/material/menu_style_test.dart | 11 +- .../test/material/menu_theme_test.dart | 5 +- .../material/mergeable_material_test.dart | 8 +- .../test/material/navigation_drawer_test.dart | 20 +- .../test/material/outlined_button_test.dart | 30 +- .../test/material/page_selector_test.dart | 2 +- .../persistent_bottom_sheet_test.dart | 10 +- .../flutter/test/material/radio_test.dart | 16 - .../test/material/range_slider_test.dart | 90 ++--- .../material/raw_material_button_test.dart | 6 - .../test/material/scrollbar_paint_test.dart | 4 +- .../test/material/search_bar_theme_test.dart | 12 +- .../test/material/search_view_theme_test.dart | 12 +- .../test/material/segmented_button_test.dart | 13 +- .../material/segmented_button_theme_test.dart | 8 +- .../test/material/selection_area_test.dart | 11 +- .../test/material/slider_theme_test.dart | 78 ++--- .../test/material/switch_list_tile_test.dart | 4 +- .../flutter/test/material/switch_test.dart | 26 -- .../test/material/text_button_test.dart | 26 +- .../material/text_field_helper_text_test.dart | 4 +- .../test/material/text_field_splash_test.dart | 4 +- .../test/material/text_form_field_test.dart | 80 ++--- .../material/text_selection_theme_test.dart | 6 +- .../material/text_selection_toolbar_test.dart | 2 +- packages/flutter/test/material/time_test.dart | 6 +- .../test/material/toggle_buttons_test.dart | 10 - .../material/toggle_buttons_theme_test.dart | 2 - .../flutter/test/material/tooltip_test.dart | 26 +- .../test/material/tooltip_theme_test.dart | 24 +- .../value_indicating_slider_test.dart | 17 +- packages/flutter_driver/pubspec.yaml | 7 +- packages/flutter_tools/pubspec.yaml | 7 +- .../pubspec.yaml | 7 +- .../integration_test/example/pubspec.yaml | 7 +- 112 files changed, 899 insertions(+), 1141 deletions(-) create mode 100644 packages/flutter/test/foundation/leak_tracking_test.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/README.md delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index a4a4790e1b537..3af15f456dfb0 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: platform: 3.1.0 test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,6 +26,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +73,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: ab27 +# PUBSPEC CHECKSUM: 90e3 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index a7c9649e45e26..0add398c2f9d8 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -44,13 +44,14 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,4 +84,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 3c00 +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 4550c210916e7..60e156a59bc06 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -47,12 +47,13 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -210,4 +211,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 3c00 +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 4f51250aebe2d..02c8cee8cb2ee 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: test: 1.24.5 flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,6 +26,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -137,4 +138,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 9677 +# PUBSPEC CHECKSUM: 8334 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index ac4a14597871d..bbc27ebff51c2 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../microbenchmarks cupertino_icons: 1.0.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,6 +27,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_gallery_assets: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4862 +# PUBSPEC CHECKSUM: 071f diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 00014aadce0e0..cd3b965385088 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -42,13 +42,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 3c00 +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 2a7103b641c22..c9519591cc9e2 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -42,13 +42,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +82,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 3c00 +# PUBSPEC CHECKSUM: 50bc diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 4acbad26a7fb2..49f2cdc6d5a59 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -34,13 +34,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +77,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7c22 +# PUBSPEC CHECKSUM: d5de diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 2ffa5fb3676b3..aa7f54ee036a6 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -19,8 +19,8 @@ dependencies: test: 1.24.5 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -29,6 +29,7 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +75,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 3f75 +# PUBSPEC CHECKSUM: 5232 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 40a5184c9e971..0d9f0d93585ef 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -33,11 +33,12 @@ dev_dependencies: test: 1.24.5 test_api: 0.6.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +66,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ab03 +# PUBSPEC CHECKSUM: 98bf diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 9617948993566..8165b2ecf7351 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -20,12 +20,13 @@ dependencies: dev_dependencies: test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,4 +56,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4e50 +# PUBSPEC CHECKSUM: 3e0d diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index ad62dd955cd1b..4a0f12ca8a78e 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -51,10 +51,11 @@ dependencies: dev_dependencies: test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +73,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 42e2 +# PUBSPEC CHECKSUM: 069f diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 0c9e67ed3a2d6..4bb0c77fd3db9 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: pub_semver: 2.1.4 test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,6 +24,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +67,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 8520 +# PUBSPEC CHECKSUM: a7dc diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 62c592cf7485e..7d269f49cd637 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -56,13 +56,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -92,4 +93,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: de87 +# PUBSPEC CHECKSUM: 7544 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index aa734541e64ba..815f51e13395d 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -37,13 +37,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -80,4 +81,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index 902a7465f4e36..a98b678a049dd 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,6 +21,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 8fa8 +# PUBSPEC CHECKSUM: 3265 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index a3cde6756075c..b58bd6965a1df 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,6 +23,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +75,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 12474cabd99b5..beadeb0f2bd9a 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -62,14 +62,15 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -276,4 +277,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: e14b +# PUBSPEC CHECKSUM: 2d08 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 52967e25af7e9..bc2faa5edf60e 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: camera_android: 0.10.8+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_web: 0.3.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_web: 0.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.3+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b503 +# PUBSPEC CHECKSUM: f4a6 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 3a50abe04baa7..fdcce7bc03c39 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -54,13 +54,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -90,4 +91,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: de87 +# PUBSPEC CHECKSUM: 7544 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 0cb3b4a8e3242..ca8b8b2c4529c 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -37,13 +37,14 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +78,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 5008671db678a..1ca2802ac64f4 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,6 +21,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 8fa8 +# PUBSPEC CHECKSUM: 3265 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index f08d5df9e5086..e01cef777b9f3 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,6 +23,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +77,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index dacee6e168353..50782ae127044 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -51,12 +51,13 @@ dev_dependencies: http: 0.13.6 test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +85,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0a4a +# PUBSPEC CHECKSUM: 9207 diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 6064142e29d2b..5ad79e827bd63 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,6 +21,7 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,4 +63,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8fa8 +# PUBSPEC CHECKSUM: 3265 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index e50faf86f4131..4fd3370b262d9 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -12,14 +12,15 @@ dev_dependencies: path: 1.8.3 test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,4 +56,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4e50 +# PUBSPEC CHECKSUM: 3e0d diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 3bb78151a7f13..1c543406e9959 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -23,12 +23,13 @@ dev_dependencies: test: 1.24.5 test_api: 0.6.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,4 +58,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6047 +# PUBSPEC CHECKSUM: 2004 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 98cb94a0e8411..71bb08f68b1e4 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -29,11 +29,12 @@ dev_dependencies: test: 1.24.5 test_api: 0.6.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,4 +62,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1361 +# PUBSPEC CHECKSUM: b61e diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 3fc0c60e30849..94019eda081f4 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -33,8 +33,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,6 +42,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +86,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b614 +# PUBSPEC CHECKSUM: a4d0 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 6ffd23fd91f38..658b6ebb2f29e 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,6 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,4 +69,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 8aecce16ef679..771b425a71c3c 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,6 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index c5b0a96f59920..b0174fe733b92 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,6 +30,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +72,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: db65 +# PUBSPEC CHECKSUM: 2d22 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 00dc34f9775eb..0c7254667ccf2 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -19,8 +19,8 @@ dev_dependencies: sdk: flutter test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,6 +28,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +65,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8520 +# PUBSPEC CHECKSUM: a7dc diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index ee23653fb2b17..4397753e04a96 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,11 +22,11 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 9.0.3 - leak_tracker_testing: 1.0.3 + leak_tracker: 8.0.3 + leak_tracker_testing: 1.0.2 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,6 +34,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8b3a +# PUBSPEC CHECKSUM: 10f4 diff --git a/packages/flutter/test/animation/animation_sheet_test.dart b/packages/flutter/test/animation/animation_sheet_test.dart index 0d60746c45dfb..4c26669abec4f 100644 --- a/packages/flutter/test/animation/animation_sheet_test.dart +++ b/packages/flutter/test/animation/animation_sheet_test.dart @@ -12,6 +12,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; void main() { /* @@ -19,7 +20,7 @@ void main() { * because [matchesGoldenFile] does not use Skia Gold in its native package. */ - testWidgets('correctly records frames using collate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly records frames using collate', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); await tester.pumpFrames( @@ -56,7 +57,7 @@ void main() { image.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgets('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder( frameSize: const Size(8, 2), allLayers: true, diff --git a/packages/flutter/test/animation/live_binding_test.dart b/packages/flutter/test/animation/live_binding_test.dart index 9a75509e3b423..4928e6a6762f0 100644 --- a/packages/flutter/test/animation/live_binding_test.dart +++ b/packages/flutter/test/animation/live_binding_test.dart @@ -80,7 +80,7 @@ void main() { // Currently skipped due to daily flake: https://github.com/flutter/flutter/issues/87588 }, skip: true); // Typically skip: isBrowser https://github.com/flutter/flutter/issues/42767 - testWidgets('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(200, 200), allLayers: true); final List taps = []; Widget target({bool recording = true}) => Container( diff --git a/packages/flutter/test/flutter_test_config.dart b/packages/flutter/test/flutter_test_config.dart index 731ca40f00489..e8d488aff5fe2 100644 --- a/packages/flutter/test/flutter_test_config.dart +++ b/packages/flutter/test/flutter_test_config.dart @@ -23,7 +23,7 @@ Future testExecutable(FutureOr Function() testMain) { // receive the event. WidgetController.hitTestWarningShouldBeFatal = true; - LeakTracking.warnForUnsupportedPlatforms = false; + LeakTrackerGlobalSettings.warnForNonSupportedPlatforms = false; // Enable golden file testing using Skia Gold. return flutter_goldens.testExecutable(testMain); diff --git a/packages/flutter/test/foundation/leak_tracking.dart b/packages/flutter/test/foundation/leak_tracking.dart index b56fca80bb399..1ed364c9fa469 100644 --- a/packages/flutter/test/foundation/leak_tracking.dart +++ b/packages/flutter/test/foundation/leak_tracking.dart @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(polina-c): start referencing this code in leak_tracker_flutter -// https://github.com/dart-lang/leak_tracker/issues/52 - import 'dart:core'; import 'package:flutter/foundation.dart'; @@ -13,84 +10,41 @@ import 'package:leak_tracker/leak_tracker.dart'; import 'package:leak_tracker_testing/leak_tracker_testing.dart'; import 'package:meta/meta.dart'; -export 'package:leak_tracker/leak_tracker.dart' show LeakDiagnosticConfig; +export 'package:leak_tracker/leak_tracker.dart' show LeakDiagnosticConfig, LeakTrackingTestConfig; +/// Set of objects, that does not hold the objects from garbage collection. +/// +/// The objects are referenced by hash codes and can duplicate with low probability. +@visibleForTesting +class WeakSet { + final Set _objectCodes = {}; -void _flutterEventToLeakTracker(ObjectEvent event) { - return LeakTracking.dispatchObjectEvent(event.toMap()); -} + String _toCode(int hashCode, String type) => '$type-$hashCode'; -void _setUpTestingWithLeakTracking() { - _printPlatformWarningIfNeeded(); - if (!_isPlatformSupported) { - return; + void add(Object object) { + _objectCodes.add(_toCode(identityHashCode(object), object.runtimeType.toString())); } - LeakTracking.phase = const PhaseSettings.paused(); - LeakTracking.start(config: LeakTrackingConfig.passive()); - - MemoryAllocations.instance.addListener(_flutterEventToLeakTracker); -} - -bool _stopConfiguringTearDown = false; - -/// Sets [tearDownAll] to tear down leak tracking if it is started. -/// -/// [configureOnce] is true tear down will be created just once, -/// not for every test. -/// Multiple [tearDownAll] is needed to handle test groups that have -/// own [tearDownAll]. -void configureLeakTrackingTearDown({ - LeaksCallback? onLeaks, - bool configureOnce = false, -}) { - if (_isPlatformSupported && !_stopConfiguringTearDown) { - tearDownAll(() async { - if (LeakTracking.isStarted) { - await _tearDownTestingWithLeakTracking(onLeaks); - } - }); - } - if (configureOnce) { - _stopConfiguringTearDown = true; + void addByCode(int hashCode, String type) { + _objectCodes.add(_toCode(hashCode, type)); } -} -Future _tearDownTestingWithLeakTracking(LeaksCallback? onLeaks) async { - if (!LeakTracking.isStarted) { - return; - } - if (!_isPlatformSupported) { - return; - } - - MemoryAllocations.instance.removeListener(_flutterEventToLeakTracker); - await forceGC(fullGcCycles: 3); - final Leaks leaks = await LeakTracking.collectLeaks(); - - LeakTracking.stop(); - - if (leaks.total == 0) { - return; - } - if (onLeaks == null) { - expect(leaks, isLeakFree); - } else { - onLeaks(leaks); + bool contains(int hashCode, String type) { + final bool result = _objectCodes.contains(_toCode(hashCode, type)); + return result; } } /// Wrapper for [testWidgets] with memory leak tracking. /// -/// The test will fail if instrumented objects in [callback] are -/// garbage collected without being disposed or not garbage -/// collected soon after disposal. -/// -/// [testExecutableWithLeakTracking] must be invoked -/// for this test run. +/// The method will fail if instrumented objects in [callback] are +/// garbage collected without being disposed. /// /// More about leak tracking: /// https://github.com/dart-lang/leak_tracker. +/// +/// See https://github.com/flutter/devtools/issues/3951 for plans +/// on leak tracking. @isTest void testWidgetsWithLeakTracking( String description, @@ -100,32 +54,19 @@ void testWidgetsWithLeakTracking( bool semanticsEnabled = true, TestVariant variant = const DefaultTestVariant(), dynamic tags, - LeakTrackingTestConfig leakTrackingTestConfig = - const LeakTrackingTestConfig(), + LeakTrackingTestConfig leakTrackingTestConfig = const LeakTrackingTestConfig(), }) { - configureLeakTrackingTearDown(); - - final PhaseSettings phase = PhaseSettings( - name: description, - leakDiagnosticConfig: leakTrackingTestConfig.leakDiagnosticConfig, - notGCedAllowList: leakTrackingTestConfig.notGCedAllowList, - notDisposedAllowList: leakTrackingTestConfig.notDisposedAllowList, - allowAllNotDisposed: leakTrackingTestConfig.allowAllNotDisposed, - allowAllNotGCed: leakTrackingTestConfig.allowAllNotGCed, - ); - - Future wrappedCallBack(WidgetTester tester) async { - if (!LeakTracking.isStarted) { - _setUpTestingWithLeakTracking(); - } - LeakTracking.phase = phase; - await callback(tester); - LeakTracking.phase = const PhaseSettings.paused(); + Future wrappedCallback(WidgetTester tester) async { + await _withFlutterLeakTracking( + () async => callback(tester), + tester, + leakTrackingTestConfig, + ); } testWidgets( description, - wrappedCallBack, + wrappedCallback, skip: skip, timeout: timeout, semanticsEnabled: semanticsEnabled, @@ -134,92 +75,132 @@ void testWidgetsWithLeakTracking( ); } -bool _notSupportedWarningPrinted = false; -bool get _isPlatformSupported => !kIsWeb; -void _printPlatformWarningIfNeeded() { +bool _webWarningPrinted = false; + +/// Runs [callback] with leak tracking. +/// +/// Wrapper for [withLeakTracking] with Flutter specific functionality. +/// +/// The method will fail if wrapped code contains memory leaks. +/// +/// See details in documentation for `withLeakTracking` at +/// https://github.com/dart-lang/leak_tracker/blob/main/lib/src/leak_tracking/orchestration.dart +/// +/// The Flutter related enhancements are: +/// 1. Listens to [MemoryAllocations] events. +/// 2. Uses `tester.runAsync` for leak detection if [tester] is provided. +/// +/// Pass [config] to troubleshoot or exempt leaks. See [LeakTrackingTestConfig] +/// for details. +Future _withFlutterLeakTracking( + DartAsyncCallback callback, + WidgetTester tester, + LeakTrackingTestConfig config, +) async { + // Leak tracker does not work for web platform. if (kIsWeb) { - final bool shouldPrintWarning = !_notSupportedWarningPrinted && - LeakTracking.warnForUnsupportedPlatforms; + final bool shouldPrintWarning = !_webWarningPrinted && LeakTrackerGlobalSettings.warnForNonSupportedPlatforms; if (shouldPrintWarning) { - _notSupportedWarningPrinted = true; - debugPrint( - 'Leak tracking is not supported on web platform.\nTo turn off this message, set `LeakTracking.warnForNotSupportedPlatforms` to false.', - ); + _webWarningPrinted = true; + debugPrint('Leak tracking is not supported on web platform.\nTo turn off this message, set `LeakTrackingTestConfig.warnForNonSupportedPlatforms` to false.'); } + await callback(); return; } - assert(_isPlatformSupported); -} -/// Configuration for leak tracking in unit tests. -/// -/// Customized configuration is needed only for test debugging, -/// not for regular test runs. -class LeakTrackingTestConfig { - /// Creates a new instance of [LeakTrackingTestConfig]. - const LeakTrackingTestConfig({ - this.leakDiagnosticConfig = const LeakDiagnosticConfig(), - this.notGCedAllowList = const {}, - this.notDisposedAllowList = const {}, - this.allowAllNotDisposed = false, - this.allowAllNotGCed = false, - }); + void flutterEventToLeakTracker(ObjectEvent event) { + return dispatchObjectEvent(event.toMap()); + } - /// Creates a new instance of [LeakTrackingTestConfig] for debugging leaks. - /// - /// This configuration will collect stack traces on start and disposal, - /// and retaining path for notGCed objects. - LeakTrackingTestConfig.debug({ - this.leakDiagnosticConfig = const LeakDiagnosticConfig( - collectStackTraceOnStart: true, - collectStackTraceOnDisposal: true, - collectRetainingPathForNotGCed: true, - ), - this.notGCedAllowList = const {}, - this.notDisposedAllowList = const {}, - this.allowAllNotDisposed = false, - this.allowAllNotGCed = false, - }); + return TestAsyncUtils.guard(() async { + MemoryAllocations.instance.addListener(flutterEventToLeakTracker); + Future asyncCodeRunner(DartAsyncCallback action) async => tester.runAsync(action); + + try { + Leaks leaks = await withLeakTracking( + callback, + asyncCodeRunner: asyncCodeRunner, + leakDiagnosticConfig: config.leakDiagnosticConfig, + shouldThrowOnLeaks: false, + ); - /// Creates a new instance of [LeakTrackingTestConfig] to collect retaining path. - /// - /// This configuration will not collect stack traces, - /// and will collect retaining path for notGCed objects. - LeakTrackingTestConfig.retainingPath({ - this.leakDiagnosticConfig = const LeakDiagnosticConfig( - collectRetainingPathForNotGCed: true, - ), - this.notGCedAllowList = const {}, - this.notDisposedAllowList = const {}, - this.allowAllNotDisposed = false, - this.allowAllNotGCed = false, + leaks = LeakCleaner(config).clean(leaks); + + if (leaks.total > 0) { + config.onLeaks?.call(leaks); + if (config.failTestOnLeaks) { + expect(leaks, isLeakFree); + } + } + } finally { + MemoryAllocations.instance.removeListener(flutterEventToLeakTracker); + } }); +} - /// Classes that are allowed to be not garbage collected after disposal. - /// - /// Maps name of the class, as returned by `object.runtimeType.toString()`, - /// to the number of instances of the class that are allowed to be not GCed. - /// - /// If number of instances is [null], any number of instances is allowed. - final Map notGCedAllowList; - - /// Classes that are allowed to be garbage collected without being disposed. - /// - /// Maps name of the class, as returned by `object.runtimeType.toString()`, - /// to the number of instances of the class that are allowed to be not disposed. - /// - /// If number of instances is [null], any number of instances is allowed. - final Map notDisposedAllowList; - - /// If true, all notDisposed leaks will be allowed. - final bool allowAllNotDisposed; - - /// If true, all notGCed leaks will be allowed. - final bool allowAllNotGCed; - - /// When to collect stack trace information. - /// - /// Knowing call stack may help to troubleshoot memory leaks. - /// Customize this parameter to collect stack traces when needed. - final LeakDiagnosticConfig leakDiagnosticConfig; +/// Cleans leaks that are allowed by [config]. +@visibleForTesting +class LeakCleaner { + LeakCleaner(this.config); + + final LeakTrackingTestConfig config; + + static Map<(String, LeakType), int> _countByClassAndType(Leaks leaks) { + final Map<(String, LeakType), int> result = <(String, LeakType), int>{}; + + for (final MapEntry> entry in leaks.byType.entries) { + for (final LeakReport leak in entry.value) { + final (String, LeakType) classAndType = (leak.type, entry.key); + result[classAndType] = (result[classAndType] ?? 0) + 1; + } + } + return result; + } + + Leaks clean(Leaks leaks) { + final Map<(String, LeakType), int> countByClassAndType = _countByClassAndType(leaks); + + final Leaks result = Leaks(>{ + for (final LeakType leakType in leaks.byType.keys) + leakType: leaks.byType[leakType]!.where((LeakReport leak) => _shouldReportLeak(leakType, leak, countByClassAndType)).toList() + }); + return result; + } + + /// Returns true if [leak] should be reported as failure. + bool _shouldReportLeak(LeakType leakType, LeakReport leak, Map<(String, LeakType), int> countByClassAndType) { + switch (leakType) { + case LeakType.notDisposed: + if (config.allowAllNotDisposed) { + return false; + } + case LeakType.notGCed: + case LeakType.gcedLate: + if (config.allowAllNotGCed) { + return false; + } + } + + final String leakingClass = leak.type; + final (String, LeakType) classAndType = (leakingClass, leakType); + + bool isAllowedForClass(Map allowList) { + if (!allowList.containsKey(leakingClass)) { + return false; + } + final int? allowedCount = allowList[leakingClass]; + if (allowedCount == null) { + return true; + } + return allowedCount >= countByClassAndType[classAndType]!; + } + + switch (leakType) { + case LeakType.notDisposed: + return !isAllowedForClass(config.notDisposedAllowList); + case LeakType.notGCed: + case LeakType.gcedLate: + return !isAllowedForClass(config.notGCedAllowList); + } + } } diff --git a/packages/flutter/test/foundation/leak_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test.dart new file mode 100644 index 0000000000000..bd02bd2c781dd --- /dev/null +++ b/packages/flutter/test/foundation/leak_tracking_test.dart @@ -0,0 +1,235 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker/leak_tracker.dart'; +import 'package:leak_tracker_testing/leak_tracker_testing.dart'; + +import 'leak_tracking.dart'; + +final String _leakTrackedClassName = '$_LeakTrackedClass'; + +Leaks _leaksOfAllTypes() => Leaks(> { + LeakType.notDisposed: [LeakReport(code: 1, context: {}, type:'myNotDisposedClass', trackedClass: 'myTrackedClass')], + LeakType.notGCed: [LeakReport(code: 2, context: {}, type:'myNotGCedClass', trackedClass: 'myTrackedClass')], + LeakType.gcedLate: [LeakReport(code: 3, context: {}, type:'myGCedLateClass', trackedClass: 'myTrackedClass')], +}); + +Future main() async { + test('Trivial $LeakCleaner returns all leaks.', () { + final LeakCleaner leakCleaner = LeakCleaner(const LeakTrackingTestConfig()); + final Leaks leaks = _leaksOfAllTypes(); + final int leakTotal = leaks.total; + + final Leaks cleanedLeaks = leakCleaner.clean(leaks); + + expect(leaks.total, leakTotal); + expect(cleanedLeaks.total, 3); + }); + + test('$LeakCleaner catches extra leaks', () { + Leaks leaks = _leaksOfAllTypes(); + final LeakReport leak = leaks.notDisposed.first; + leaks.notDisposed.add(leak); + + final LeakTrackingTestConfig config = LeakTrackingTestConfig( + notDisposedAllowList: {leak.type: 1}, + ); + leaks = LeakCleaner(config).clean(leaks); + + expect(leaks.notDisposed, hasLength(2)); + }); + + group('Leak tracking works for non-web, and', () { + testWidgetsWithLeakTracking( + 'respects all allow lists', + (WidgetTester tester) async { + await tester.pumpWidget(_StatelessLeakingWidget()); + }, + leakTrackingTestConfig: LeakTrackingTestConfig( + notDisposedAllowList: {_leakTrackedClassName: null}, + notGCedAllowList: {_leakTrackedClassName: null}, + ), + ); + + testWidgetsWithLeakTracking( + 'respects allowAllNotDisposed', + (WidgetTester tester) async { + // ignore: avoid_redundant_argument_values, for readability. + await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: true, notGCed: false)); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + ), + ); + + testWidgetsWithLeakTracking( + 'respects allowAllNotGCed', + (WidgetTester tester) async { + // ignore: avoid_redundant_argument_values, for readability. + await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: false, notGCed: true)); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotGCed: true, + ), + ); + + testWidgetsWithLeakTracking( + 'respects count in allow lists', + (WidgetTester tester) async { + await tester.pumpWidget(_StatelessLeakingWidget()); + }, + leakTrackingTestConfig: LeakTrackingTestConfig( + notDisposedAllowList: {_leakTrackedClassName: 1}, + notGCedAllowList: {_leakTrackedClassName: 1}, + ), + ); + + group('fails if number or leaks is more than allowed', () { + // This test cannot run inside other tests because test nesting is forbidden. + // So, `expect` happens outside the tests, in `tearDown`. + late Leaks leaks; + + testWidgetsWithLeakTracking( + 'for $_StatelessLeakingWidget', + (WidgetTester tester) async { + await tester.pumpWidget(_StatelessLeakingWidget()); + await tester.pumpWidget(_StatelessLeakingWidget()); + }, + leakTrackingTestConfig: LeakTrackingTestConfig( + onLeaks: (Leaks theLeaks) { + leaks = theLeaks; + }, + failTestOnLeaks: false, + notDisposedAllowList: {_leakTrackedClassName: 1}, + ), + ); + + tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 2, expectedNotGCed: 2, shouldContainDebugInfo: false)); + }); + + group('respects notGCed allow lists', () { + // These tests cannot run inside other tests because test nesting is forbidden. + // So, `expect` happens outside the tests, in `tearDown`. + late Leaks leaks; + + testWidgetsWithLeakTracking( + 'when $_StatelessLeakingWidget leaks', + (WidgetTester tester) async { + await tester.pumpWidget(_StatelessLeakingWidget()); + }, + leakTrackingTestConfig: LeakTrackingTestConfig( + onLeaks: (Leaks theLeaks) { + leaks = theLeaks; + }, + failTestOnLeaks: false, + notGCedAllowList: {_leakTrackedClassName: null}, + ), + ); + + tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, shouldContainDebugInfo: false)); + }); + + group('catches that', () { + // These test cannot run inside other tests because test nesting is forbidden. + // So, `expect` happens outside the tests, in `tearDown`. + late Leaks leaks; + + testWidgetsWithLeakTracking( + '$_StatelessLeakingWidget leaks', + (WidgetTester tester) async { + await tester.pumpWidget(_StatelessLeakingWidget()); + }, + leakTrackingTestConfig: LeakTrackingTestConfig( + onLeaks: (Leaks theLeaks) { + leaks = theLeaks; + }, + failTestOnLeaks: false, + ), + ); + + tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, expectedNotGCed: 1, shouldContainDebugInfo: false)); + }); + }, + skip: isBrowser); // [intended] Leak detection is off for web. + + testWidgetsWithLeakTracking('Leak tracking is no-op for web', (WidgetTester tester) async { + await tester.pumpWidget(_StatelessLeakingWidget()); + }, + skip: !isBrowser); // [intended] Leaks detection is off for web. +} + +/// Verifies [leaks] contains expected number of leaks for [_LeakTrackedClass]. +void _verifyLeaks( + Leaks leaks, { + int expectedNotDisposed = 0, + int expectedNotGCed = 0, + required bool shouldContainDebugInfo, +}) { + const String linkToLeakTracker = 'https://github.com/dart-lang/leak_tracker'; + + expect( + () => expect(leaks, isLeakFree), + throwsA( + predicate((Object? e) { + return e is TestFailure && e.toString().contains(linkToLeakTracker); + }), + ), + ); + + _verifyLeakList(leaks.notDisposed, expectedNotDisposed, shouldContainDebugInfo); + _verifyLeakList(leaks.notGCed, expectedNotGCed, shouldContainDebugInfo); +} + +void _verifyLeakList(List list, int expectedCount, bool shouldContainDebugInfo){ + expect(list.length, expectedCount); + + for (final LeakReport leak in list) { + if (shouldContainDebugInfo) { + expect(leak.context, isNotEmpty); + } else { + expect(leak.context ?? {}, isEmpty); + } + + expect(leak.trackedClass, contains(_LeakTrackedClass.library)); + expect(leak.trackedClass, contains(_leakTrackedClassName)); + } +} + +/// Storage to keep disposed objects, to generate not-gced leaks. +final List<_LeakTrackedClass> _notGcedStorage = <_LeakTrackedClass>[]; + +class _StatelessLeakingWidget extends StatelessWidget { + _StatelessLeakingWidget({bool notDisposed = true, bool notGCed = true}) { + if (notDisposed) { + // ignore: unused_local_variable, the variable is used to create non disposed leak + final _LeakTrackedClass notDisposed = _LeakTrackedClass(); + } + if (notGCed) { + _notGcedStorage.add(_LeakTrackedClass()..dispose()); + } + } + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} + +class _LeakTrackedClass { + _LeakTrackedClass() { + dispatchObjectCreated( + library: library, + className: '$_LeakTrackedClass', + object: this, + ); + } + + static const String library = 'package:my_package/lib/src/my_lib.dart'; + + void dispose() { + dispatchObjectDisposed(object: this); + } +} diff --git a/packages/flutter/test/foundation/leak_tracking_test/README.md b/packages/flutter/test/foundation/leak_tracking_test/README.md deleted file mode 100644 index 2da6b59a3cd67..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Code in this folder is copied from leak_tracker. - -TODO(polina-c): start referencing this code in leak_tracker_flutter -https://github.com/dart-lang/leak_tracker/issues/52 diff --git a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart deleted file mode 100644 index 44ae5a2b8de5a..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/constants.dart +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -const String test1TrackingOnNoLeaks = 'test1, tracking-on, no leaks'; -const String test2TrackingOffLeaks = 'test2, tracking-off, leaks'; -const String test3TrackingOnLeaks = 'test3, tracking-on, leaks'; -const String test4TrackingOnWithStackTrace = 'test4, tracking-on, with stack trace'; diff --git a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart deleted file mode 100644 index 05f85bba8c986..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/flutter_test_config.dart +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; -import 'package:leak_tracker_testing/leak_tracker_testing.dart'; - -import '../../leak_tracking.dart'; -import '../leaking_widget.dart'; -import 'constants.dart'; - -/// Test configuration for each test library in this directory. -/// -/// See https://api.flutter.dev/flutter/flutter_test/flutter_test-library.html. -Future testExecutable(FutureOr Function() testMain) async { - bool leaksDetected = false; - - // This tear down should be set before leak tracking tear down in - // order to happen after it and verify that leaks are found. - tearDownAll(() async { - if (!kIsWeb) { - expect(leaksDetected, true, reason: 'leaks should be detected'); - } - }); - - configureLeakTrackingTearDown( - configureOnce: true, - onLeaks: (Leaks leaks) { - expect(leaks.total, greaterThan(0)); - leaksDetected = true; - - try { - expect(leaks, isLeakFree); - } catch (e) { - if (e is! TestFailure) { - rethrow; - } - expect(e.message, isNot(contains(test1TrackingOnNoLeaks))); - expect(e.message, isNot(contains(test2TrackingOffLeaks))); - expect(e.message, contains('test: $test3TrackingOnLeaks')); - expect(e.message, contains('test: $test4TrackingOnWithStackTrace')); - } - - _verifyLeaks( - leaks, - test3TrackingOnLeaks, - notDisposed: 1, - notGCed: 1, - shouldContainDebugInfo: false, - ); - _verifyLeaks( - leaks, - test4TrackingOnWithStackTrace, - notDisposed: 1, - notGCed: 1, - shouldContainDebugInfo: true, - ); - }, - ); - - setUpAll(() { - LeakTracking.warnForUnsupportedPlatforms = false; - }); - - await testMain(); -} - -/// Verifies [allLeaks] contains expected number of leaks for the test [testName]. -/// -/// [notDisposed] and [notGCed] set number for expected leaks by leak type. -void _verifyLeaks( - Leaks allLeaks, - String testName, { - int notDisposed = 0, - int notGCed = 0, - required bool shouldContainDebugInfo, -}) { - const String linkToLeakTracker = 'https://github.com/dart-lang/leak_tracker'; - - final Leaks leaks = Leaks( - allLeaks.byType.map( - (LeakType key, List value) => - MapEntry>(key, value.where((LeakReport leak) => leak.phase == testName).toList()), - ), - ); - - if (notDisposed + notGCed > 0) { - expect( - () => expect(leaks, isLeakFree), - throwsA( - predicate((Object? e) { - return e is TestFailure && e.toString().contains(linkToLeakTracker); - }), - ), - ); - } else { - expect(leaks, isLeakFree); - } - - _verifyLeakList( - leaks.notDisposed, - notDisposed, - shouldContainDebugInfo, - ); - _verifyLeakList( - leaks.notGCed, - notGCed, - shouldContainDebugInfo, - ); -} - -void _verifyLeakList( - List list, - int expectedCount, - bool shouldContainDebugInfo, -) { - expect(list.length, expectedCount); - - for (final LeakReport leak in list) { - if (shouldContainDebugInfo) { - expect(leak.context, isNotEmpty); - } else { - expect(leak.context ?? {}, isEmpty); - } - expect(leak.trackedClass, contains(LeakTrackedClass.library)); - expect(leak.trackedClass, contains('$LeakTrackedClass')); - } -} diff --git a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart b/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart deleted file mode 100644 index 0856db01b1f1b..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/leak_tracking_config_test/leak_tracking_config_test.dart +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/src/foundation/constants.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; - -import '../../leak_tracking.dart'; -import '../leaking_widget.dart'; - -const String test1TrackingOnNoLeaks = 'test1, tracking-on, no leaks'; -const String test2TrackingOffLeaks = 'test2, tracking-off, leaks'; -const String test3TrackingOnLeaks = 'test3, tracking-on, leaks'; -const String test4TrackingOnWithStackTrace = 'test4, tracking-on, with stack trace'; - -bool get _isTrackingOn => !LeakTracking.phase.isPaused && LeakTracking.isStarted; - -/// For these tests `expect` for found leaks happens in flutter_test_config.dart. -void main() { - group('group', () { - testWidgetsWithLeakTracking(test1TrackingOnNoLeaks, (WidgetTester widgetTester) async { - expect(_isTrackingOn, true); - expect(LeakTracking.phase.name, test1TrackingOnNoLeaks); - await widgetTester.pumpWidget(Container()); - }); - - testWidgets(test2TrackingOffLeaks, (WidgetTester widgetTester) async { - expect(LeakTracking.phase.name, null); - expect(_isTrackingOn, false); - await widgetTester.pumpWidget(StatelessLeakingWidget()); - }); - }, - skip: kIsWeb); // [intended] Leak tracking is off for web. - - testWidgetsWithLeakTracking(test3TrackingOnLeaks, (WidgetTester widgetTester) async { - expect(_isTrackingOn, true); - expect(LeakTracking.phase.name, test3TrackingOnLeaks); - await widgetTester.pumpWidget(StatelessLeakingWidget()); - }, - skip: kIsWeb); // [intended] Leak tracking is off for web. - - testWidgetsWithLeakTracking( - test4TrackingOnWithStackTrace, - (WidgetTester widgetTester) async { - expect(_isTrackingOn, true); - expect(LeakTracking.phase.name, test4TrackingOnWithStackTrace); - await widgetTester.pumpWidget(StatelessLeakingWidget()); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - leakDiagnosticConfig: LeakDiagnosticConfig( - collectStackTraceOnStart: true, - ), - ), - skip: kIsWeb); // [intended] Leak tracking is off for web. -} diff --git a/packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart b/packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart deleted file mode 100644 index 411079733b649..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/leaking_widget.dart +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/widgets.dart'; -import 'package:leak_tracker/leak_tracker.dart'; - -class LeakTrackedClass { - LeakTrackedClass() { - LeakTracking.dispatchObjectCreated( - library: library, - className: '$LeakTrackedClass', - object: this, - ); - } - - static const String library = 'package:my_package/lib/src/my_lib.dart'; - - void dispose() { - LeakTracking.dispatchObjectDisposed(object: this); - } -} - -final List _notGcedStorage = []; - - -class StatelessLeakingWidget extends StatelessWidget { - StatelessLeakingWidget({ - super.key, - this.notGCed = true, - this.notDisposed = true, - }) { - if (notGCed) { - _notGcedStorage.add(LeakTrackedClass()..dispose()); - } - if (notDisposed) { - // ignore: unused_local_variable - final LeakTrackedClass notDisposedObject = LeakTrackedClass(); - } - } - - final bool notGCed; - final bool notDisposed; - - @override - Widget build(BuildContext context) { - return const Placeholder(); - } -} diff --git a/packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart b/packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart deleted file mode 100644 index 8e319c66fcaed..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/no_config_test.dart +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; - -import '../leak_tracking.dart'; -import 'leaking_widget.dart'; - -const String _test0TrackingOffLeaks = 'test0, tracking-off'; -const String _test1TrackingOn = 'test1, tracking-on'; -const String _test2TrackingOffLeaks = 'test2, tracking-off'; -const String _test3TrackingOn = 'test3, tracking-on'; - -bool get _isTrackingOn => !LeakTracking.phase.isPaused && LeakTracking.isStarted; - -/// Tests with default leak tracking configuration. -/// -/// This set of tests verifies that if `testWidgetsWithLeakTracking` is used at least once, -/// leak tracking is configured as expected, and is noop for `testWidgets`. -void main() { - group('groups are handled', () { - testWidgets(_test0TrackingOffLeaks, (WidgetTester widgetTester) async { - // Flutter test engine may change test order. - expect(_isTrackingOn, false); - expect(LeakTracking.phase.name, null); - await widgetTester.pumpWidget(StatelessLeakingWidget()); - }); - - testWidgetsWithLeakTracking(_test1TrackingOn, (WidgetTester widgetTester) async { - expect(_isTrackingOn, true); - expect(LeakTracking.phase.name, _test1TrackingOn); - }); - - testWidgets(_test2TrackingOffLeaks, (WidgetTester widgetTester) async { - expect(_isTrackingOn, false); - expect(LeakTracking.phase.name, null); - await widgetTester.pumpWidget(StatelessLeakingWidget()); - }); - }, - skip: kIsWeb); // [intended] Leak tracking is off for web. - - testWidgetsWithLeakTracking(_test3TrackingOn, (WidgetTester widgetTester) async { - expect(_isTrackingOn, true); - expect(LeakTracking.phase.name, _test3TrackingOn); - expect(LeakTracking.phase.isPaused, false); - }, - skip: kIsWeb); // [intended] Leak tracking is off for web. -} diff --git a/packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart deleted file mode 100644 index 3e6209c31ff27..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test/no_tracking_test.dart +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; - -import 'leaking_widget.dart'; - -void main() { - testWidgets( - 'Leak tracking is not started without `testWidgetsWithLeakTracking`', - (WidgetTester widgetTester) async { - expect(LeakTracking.isStarted, false); - expect(LeakTracking.phase.name, null); - await widgetTester.pumpWidget(StatelessLeakingWidget()); - - }, - skip: kIsWeb); // [intended] Leak tracking is off for web. -} diff --git a/packages/flutter/test/gestures/transformed_monodrag_test.dart b/packages/flutter/test/gestures/transformed_monodrag_test.dart index a0de4a94c58a6..c85bf24cd0c86 100644 --- a/packages/flutter/test/gestures/transformed_monodrag_test.dart +++ b/packages/flutter/test/gestures/transformed_monodrag_test.dart @@ -12,7 +12,7 @@ import '../foundation/leak_tracking.dart'; void main() { group('Horizontal', () { - testWidgets('gets local coordinates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { int dragCancelCount = 0; final List downDetails = []; final List endDetails = []; diff --git a/packages/flutter/test/gestures/transformed_scale_test.dart b/packages/flutter/test/gestures/transformed_scale_test.dart index f48b5e8a14d05..c01c6548ad3e4 100644 --- a/packages/flutter/test/gestures/transformed_scale_test.dart +++ b/packages/flutter/test/gestures/transformed_scale_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('gets local coordinates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { final List startDetails = []; final List updateDetails = []; diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 0f40fd9821ea2..7e38905b8dbe1 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -58,7 +58,7 @@ void main() { expect(find.text('View licenses'), findsOneWidget); }); - testWidgets('Material2 - AboutListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -141,7 +141,7 @@ void main() { expect(find.text('Pirate license'), findsOneWidget); }); - testWidgets('Material3 - AboutListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -1477,7 +1477,7 @@ void main() { expect(find.text('Exception: Injected failure'), findsOneWidget); }); - testWidgets('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1542,7 +1542,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgets('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1607,7 +1607,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgets('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1672,7 +1672,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgets('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1737,7 +1737,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgets('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/108991 final ThemeData theme = ThemeData( appBarTheme: const AppBarTheme(foregroundColor: Color(0xFFFFFFFF)), diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index 66bbe6e121785..41ad77aec6a21 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -112,7 +112,7 @@ void main() { expect(find.byKey(key), findsOneWidget); }); - testWidgets('Can build from EditableTextState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can build from EditableTextState', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -233,7 +233,7 @@ void main() { ); group('buttonItems', () { - testWidgets('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { // Fill the clipboard so that the Paste option is available in the text // selection menu. await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); @@ -328,7 +328,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { const String buttonText = 'Click me'; await tester.pumpWidget( diff --git a/packages/flutter/test/material/bottom_sheet_theme_test.dart b/packages/flutter/test/material/bottom_sheet_theme_test.dart index 71c78577ac19e..0e3593d04aca5 100644 --- a/packages/flutter/test/material/bottom_sheet_theme_test.dart +++ b/packages/flutter/test/material/bottom_sheet_theme_test.dart @@ -171,7 +171,7 @@ void main() { expect(material.clipBehavior, clipBehavior); }); - testWidgets('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { const double modalElevation = 5.0; const double persistentElevation = 7.0; const Color modalBackgroundColor = Colors.yellow; @@ -250,7 +250,7 @@ void main() { expect(material.color, null); }); - testWidgets('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { const double lightElevation = 5.0; const double darkElevation = 3.0; const Color lightBackgroundColor = Colors.green; diff --git a/packages/flutter/test/material/button_bar_test.dart b/packages/flutter/test/material/button_bar_test.dart index 4666135d1bf0c..16d4e84f0efeb 100644 --- a/packages/flutter/test/material/button_bar_test.dart +++ b/packages/flutter/test/material/button_bar_test.dart @@ -341,7 +341,7 @@ void main() { group('layoutBehavior', () { - testWidgets('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( @@ -364,7 +364,7 @@ void main() { expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 52.0); }); - testWidgets('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 95b8170a17e35..4732591978bdd 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -496,8 +496,6 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking('CheckboxListTile can be disabled', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index 6c3781910fcf5..5beec65073f31 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -302,7 +302,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)); }); - testWidgets('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index b82a391def87d..a8cba15354e4a 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -701,7 +701,7 @@ void main() { expect(calledDelete, isFalse); }); - testWidgets('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { final UniqueKey iconKey = UniqueKey(); final Widget test = Overlay( initialEntries: [ @@ -877,7 +877,7 @@ void main() { expect(tester.getSize(find.byKey(keyA)), equals(const Size(20.0, 20.0))); }); - testWidgets('Chip padding - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip padding - LTR', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -913,7 +913,7 @@ void main() { expect(tester.getBottomRight(find.byType(Icon)), const Offset(457.0, 309.0)); }); - testWidgets('Chip padding - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip padding - RTL', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -2633,7 +2633,7 @@ void main() { expect(find.byType(InkWell), findsOneWidget); }); - testWidgets('Chip uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2721,7 +2721,7 @@ void main() { expect(textColor(), disabledColor); }); - testWidgets('Chip uses stateful border side color in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful border side color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2801,7 +2801,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgets('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2882,7 +2882,7 @@ void main() { }); - testWidgets('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2971,7 +2971,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgets('Chip uses stateful shape in different states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip uses stateful shape in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); OutlinedBorder? getShape(Set states) { @@ -3339,7 +3339,7 @@ void main() { expect(decoration.shape, shape); }); - testWidgets('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'RawChip'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color backgroundColor = Color(0xff00ff00); diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 3eded54048f35..13fa9dbf02900 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -641,8 +641,6 @@ void main() { await tester.pumpWidget(chipWidget(enabled: false)); await tester.pumpAndSettle(); expect(textColor(), disabledColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Chip uses stateful border side from resolveWith pattern', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index c6181480d1ff0..baf135666ab9d 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -261,7 +261,6 @@ void main() { // https://github.com/flutter/flutter/issues/130354 leakTrackingTestConfig: const LeakTrackingTestConfig( allowAllNotGCed: true, - allowAllNotDisposed: true, )); }); diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 3b68e578fa070..4ba0c9b5e0cdb 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -2338,7 +2338,7 @@ void main() { }); group('AlertDialog.scrollable: ', () { - testWidgets('Title is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Title is scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final AlertDialog dialog = AlertDialog( title: Container( @@ -2378,7 +2378,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0))); }); - testWidgets('Title and content are scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Title and content are scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final Key contentKey = UniqueKey(); final AlertDialog dialog = AlertDialog( @@ -2511,7 +2511,7 @@ void main() { semantics.dispose(); }); - testWidgets('DialogRoute is state restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DialogRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -2660,9 +2660,6 @@ void main() { expect(await previousFocus(), true); expect(okNode.hasFocus, true); expect(cancelNode.hasFocus, false); - - cancelNode.dispose(); - okNode.dispose(); }); testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { @@ -2767,7 +2764,7 @@ void main() { expect(find.text('Dialog2'), findsOneWidget); }); - testWidgets('Uses open focus traversal when overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses open focus traversal when overridden', (WidgetTester tester) async { final FocusNode okNode = FocusNode(); final FocusNode cancelNode = FocusNode(); diff --git a/packages/flutter/test/material/drawer_button_test.dart b/packages/flutter/test/material/drawer_button_test.dart index 5b3c253796ade..872e633e7b1e6 100644 --- a/packages/flutter/test/material/drawer_button_test.dart +++ b/packages/flutter/test/material/drawer_button_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import '../foundation/leak_tracking.dart'; void main() { - testWidgets('DrawerButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -171,7 +171,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('EndDrawerButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EndDrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index 306b379460ce4..149733508f81a 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -7,6 +7,8 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + const List menuItems = ['one', 'two', 'three', 'four']; void onChanged(T _) { } final Type dropdownButtonType = DropdownButton( @@ -198,7 +200,7 @@ void main() { expect(hintEmptyLabel, oneValueLabel); }); - testWidgets('label position test - show disabledHint: disable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: disable', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -236,7 +238,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -261,7 +263,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -311,7 +313,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -349,7 +351,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 24.0)); }); - testWidgets('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { const int value = 1; await tester.pumpWidget( @@ -389,7 +391,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/82910 - testWidgets('null value test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null value test', (WidgetTester tester) async { int? value = 1; await tester.pumpWidget( @@ -490,7 +492,7 @@ void main() { expect(value, equals('three')); }); - testWidgets('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); // There shouldn't be overflow when expanded although list contains longer items. @@ -525,7 +527,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -565,7 +567,7 @@ void main() { } }); - testWidgets('DropdownButtonFormField with isDense:true does not clip large scale text', + testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true does not clip large scale text', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -604,7 +606,7 @@ void main() { expect(box.size.height, 72.0); }); - testWidgets('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46844 final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -635,7 +637,7 @@ void main() { expect(box.size.height, 48.0); }); - testWidgets('DropdownButtonFormField - custom text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - custom text style', (WidgetTester tester) async { const String value = 'foo'; final UniqueKey itemKey = UniqueKey(); @@ -673,7 +675,7 @@ void main() { expect(richText.text.style!.fontSize, 20.0); }); - testWidgets('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -696,7 +698,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgets( + testWidgetsWithLeakTracking( 'DropdownButtonFormField - hint displays when the items list is ' 'empty, items is null, and disabledHint is null', (WidgetTester tester) async { @@ -720,7 +722,7 @@ void main() { }, ); - testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -740,7 +742,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -760,7 +762,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items, ValueChanged? onChanged }) { @@ -778,7 +780,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items}) { @@ -803,7 +805,7 @@ void main() { expect(enabledHintBox.size, equals(disabledHintBox.size)); }); - testWidgets('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { final Key iconKey = UniqueKey(); final Icon customIcon = Icon(Icons.assessment, key: iconKey); @@ -836,7 +838,7 @@ void main() { expect(disabledRichText.text.style!.color, Colors.orange); }); - testWidgets('DropdownButtonFormField - default elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - default elevation', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); debugDisableShadows = false; await tester.pumpWidget(buildFormFrame( @@ -893,7 +895,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'c'] .map>((String value) { return DropdownMenuItem( @@ -922,7 +924,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'd'] .map>((String value) { return DropdownMenuItem( @@ -1087,7 +1089,7 @@ void main() { expect(find.text(currentValue), findsOneWidget); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -1116,7 +1118,7 @@ void main() { expect(validateCalled, 1); }); - testWidgets('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { await tester.pumpWidget(buildFormFrame( buttonAlignment: AlignmentDirectional.center, items: ['one'], diff --git a/packages/flutter/test/material/dropdown_menu_theme_test.dart b/packages/flutter/test/material/dropdown_menu_theme_test.dart index d770f734caa60..dcfd4ff75e45f 100644 --- a/packages/flutter/test/material/dropdown_menu_theme_test.dart +++ b/packages/flutter/test/material/dropdown_menu_theme_test.dart @@ -44,7 +44,7 @@ void main() { expect(description, []); }); - testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -101,7 +101,7 @@ void main() { expect(material.textStyle?.color, themeData.colorScheme.onSurface); }); - testWidgets('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( dropdownMenuTheme: DropdownMenuThemeData( textStyle: TextStyle( @@ -180,7 +180,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, @@ -283,7 +283,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index 4374738b4ecbb..0f504b52838c2 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -196,7 +196,6 @@ void main() { await gesture.moveTo(center); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); - focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -260,8 +259,6 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 1.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('ElevatedButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -337,8 +334,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); - - focusNode.dispose(); }); @@ -415,8 +410,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('ElevatedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -541,8 +534,6 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered ElevatedButton responds to mouse-exit', (WidgetTester tester) async { @@ -634,8 +625,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking('When ElevatedButton disable, Can not set ElevatedButton focus.', (WidgetTester tester) async { @@ -659,9 +648,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - - node.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton work with hover', (WidgetTester tester) async { @@ -717,8 +703,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton work with autofocus', (WidgetTester tester) async { @@ -749,8 +733,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton contribute semantics', (WidgetTester tester) async { @@ -1685,7 +1667,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1883,15 +1865,15 @@ void main() { await gesture.removePointer(); } - testWidgets('ElevatedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('ElevatedButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ElevatedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled ElevatedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled ElevatedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index dc03ac8be41ce..b2d29c7142cac 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -340,7 +340,6 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 0.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); - focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton.tonal default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { @@ -406,7 +405,6 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 0.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); - focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -482,7 +480,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); - focusNode.dispose(); }); @@ -559,7 +556,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); - focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -684,7 +680,6 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); - focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered FilledButton responds to mouse-exit', (WidgetTester tester) async { @@ -776,7 +771,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - node.dispose(); }); testWidgetsWithLeakTracking('When FilledButton disable, Can not set FilledButton focus.', (WidgetTester tester) async { @@ -800,7 +794,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - node.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton work with hover', (WidgetTester tester) async { @@ -856,7 +849,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton work with autofocus', (WidgetTester tester) async { @@ -887,7 +879,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton contribute semantics', (WidgetTester tester) async { @@ -1750,7 +1741,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1946,15 +1937,15 @@ void main() { await gesture.removePointer(); } - testWidgets('FilledButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('FilledButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled FilledButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled FilledButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart index b3c3adac92429..4d481b87b75f7 100644 --- a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart @@ -51,7 +51,7 @@ void main() { expect(topAfterScroll.dy, equals(0.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgets('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), @@ -89,7 +89,7 @@ void main() { expect(topAfterScroll.dy, equals(-100.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgets('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), diff --git a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart index 207b50b519d72..4fa49ea9344be 100644 --- a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart @@ -92,7 +92,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -136,7 +136,7 @@ void main() { expect(opacityWidget.opacity, equals(0.0)); }); - testWidgets('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 643377e209931..932b632617a7f 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -185,7 +185,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting motion towards the StartTop location.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting motion towards the StartTop location.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -198,7 +198,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting entrance to remove the fab.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting entrance to remove the fab.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(fab: null, location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -217,7 +217,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting entrance of a new fab.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting entrance of a new fab.', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( fab: null, diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 575299d2640df..189573dfc0ccf 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -326,7 +326,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -368,8 +368,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(getFABWidget(fabFinder).elevation, 6); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('FlatActionButton mini size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { @@ -787,7 +785,7 @@ void main() { }); // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -911,8 +909,6 @@ void main() { tester.renderObject(find.byType(FloatingActionButton)), paintsExactlyCountTimes(#clipPath, 0), ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Can find FloatingActionButton semantics', (WidgetTester tester) async { @@ -1168,7 +1164,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -1210,8 +1206,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(getFABWidget(fabFinder).elevation, 12); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('FloatingActionButton.isExtended', (WidgetTester tester) async { @@ -1333,7 +1327,7 @@ void main() { // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 749ba84bdeab6..19ea27f0ad222 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -100,14 +100,13 @@ void main() { testWidgetsWithLeakTracking('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; - final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( wrap( useMaterial3: material3, child: IconTheme( data: const IconThemeData(), child: IconButton( - focusNode: focusNode, + focusNode: FocusNode(debugLabel: 'Ink Focus'), onPressed: mockOnPressedFunction.handler, icon: const Icon(Icons.link), ), @@ -117,8 +116,6 @@ void main() { final RenderBox icon = tester.renderObject(find.byType(Icon)); expect(icon.size, const Size(24.0, 24.0)); - - focusNode.dispose(); }); testWidgets('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async { @@ -742,8 +739,6 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('IconButton keeps focus when disabled in directional navigation mode.', (WidgetTester tester) async { @@ -786,8 +781,6 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isTrue); - - focusNode.dispose(); }); testWidgetsWithLeakTracking("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { @@ -824,9 +817,6 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - - focusNode1.dispose(); - focusNode2.dispose(); }); group('feedback', () { @@ -1250,8 +1240,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.12))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('IconButton.fill defaults - M3', (WidgetTester tester) async { @@ -1391,8 +1379,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.fill defaults - M3', (WidgetTester tester) async { @@ -1647,8 +1633,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.filledTonal defaults - M3', (WidgetTester tester) async { @@ -1903,8 +1887,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.08))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.outlined defaults - M3', (WidgetTester tester) async { @@ -2065,8 +2047,6 @@ void main() { await expectLater(tester, meetsGuideline(textContrastGuideline)); await gesture.removePointer(); - - focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -2155,8 +2135,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does IconButton contribute semantics - M3', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index e24a1b3072ba4..5dc4710697c9c 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -271,7 +271,7 @@ void main() { await gesture.up(); }); - testWidgets('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); @@ -454,7 +454,7 @@ void main() { })); }); - testWidgets('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { final OverlayPortalController controller = OverlayPortalController(); controller.show(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index e444b00a9f10a..1019d9bf4cab6 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -250,7 +250,6 @@ void main() { inkFeatures, paints ..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff)), ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response changes color on focus with overlayColor', (WidgetTester tester) async { @@ -299,7 +298,6 @@ void main() { inkFeatures, paints..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff)), ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('ink well changes color on pressed with overlayColor', (WidgetTester tester) async { @@ -372,7 +370,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..circle(x: 50, y: 50, color: splashColor)); await gesture.up(); - focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response splashColor matches resolved overlayColor for MaterialState.pressed', (WidgetTester tester) async { @@ -422,7 +419,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..circle(x: 50, y: 50, color: splashColor)); await gesture.up(); - focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response uses radius for focus highlight', (WidgetTester tester) async { @@ -453,7 +449,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell uses borderRadius for focus highlight', (WidgetTester tester) async { @@ -490,7 +485,6 @@ void main() { rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(10)), color: const Color(0xff0000ff), )); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell uses borderRadius for hover highlight', (WidgetTester tester) async { @@ -582,7 +576,6 @@ void main() { sampleSize: 100, )), ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell customBorder clips for hover highlight', (WidgetTester tester) async { @@ -674,7 +667,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 1)); expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkResponse highlightShape can be updated', (WidgetTester tester) async { @@ -716,7 +708,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1)); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell borderRadius can be updated', (WidgetTester tester) async { @@ -762,7 +753,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(30)), color: const Color(0xff0000ff), )); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell customBorder can be updated', (WidgetTester tester) async { @@ -830,7 +820,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t sampleSize: 100, )), ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell splash customBorder can be updated', (WidgetTester tester) async { @@ -919,7 +908,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await gesture.up(); - focusNode.dispose(); }); testWidgetsWithLeakTracking("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async { @@ -952,7 +940,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t focusNode.requestFocus(); await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawRect, 0)); - focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell.mouseCursor changes cursor on hover', (WidgetTester tester) async { @@ -1042,7 +1029,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1231,7 +1218,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); - focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response accepts focus when disabled in directional navigation mode', (WidgetTester tester) async { @@ -1278,7 +1264,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isTrue); - focusNode.dispose(); }); testWidgetsWithLeakTracking("ink response doesn't hover when disabled", (WidgetTester tester) async { @@ -1332,7 +1317,6 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); - focusNode.dispose(); }); testWidgetsWithLeakTracking('When ink wells are nested, only the inner one is triggered by tap splash', (WidgetTester tester) async { @@ -2087,7 +2071,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); }); - testWidgets('InkWell disposes statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell dispose statesController', (WidgetTester tester) async { int tapCount = 0; Widget buildFrame(MaterialStatesController? statesController) { return MaterialApp( diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index b4285c04ed689..a7f341072de94 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -241,8 +241,6 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('cannot be traversed to when disabled', (WidgetTester tester) async { @@ -278,9 +276,6 @@ void main() { await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - - focusNode1.dispose(); - focusNode2.dispose(); }); testWidgetsWithLeakTracking('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/input_date_picker_form_field_test.dart b/packages/flutter/test/material/input_date_picker_form_field_test.dart index 076b3978f41a0..50275ffe79cca 100644 --- a/packages/flutter/test/material/input_date_picker_form_field_test.dart +++ b/packages/flutter/test/material/input_date_picker_form_field_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/clipboard_utils.dart'; class TestMaterialLocalizations extends DefaultMaterialLocalizations { @@ -97,7 +98,7 @@ void main() { group('InputDatePickerFormField', () { - testWidgets('Initial date is the default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); final DateTime initialDate = DateTime(2016, DateTime.february, 21); DateTime? inputDate; @@ -111,7 +112,7 @@ void main() { expect(inputDate, equals(initialDate)); }); - testWidgets('Changing initial date is reflected in text value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing initial date is reflected in text value', (WidgetTester tester) async { final DateTime initialDate = DateTime(2016, DateTime.february, 21); final DateTime updatedInitialDate = DateTime(2016, DateTime.february, 23); await tester.pumpWidget(inputDatePickerField( @@ -126,7 +127,7 @@ void main() { expect(textFieldController(tester).value.text, equals('02/23/2016')); }); - testWidgets('Valid date entry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Valid date entry', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -139,7 +140,7 @@ void main() { expect(inputDate, equals(DateTime(2016, DateTime.february, 21))); }); - testWidgets('Invalid text entry shows errorFormat text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Invalid text entry shows errorFormat text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -166,7 +167,7 @@ void main() { expect(find.text('That is not a date.'), findsOneWidget); }); - testWidgets('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -201,7 +202,7 @@ void main() { expect(find.text('Not in given range.'), findsOneWidget); }); - testWidgets('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -227,7 +228,7 @@ void main() { expect(find.text('Out of range.'), findsNothing); }); - testWidgets('Empty field shows hint text when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty field shows hint text when focused', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Focus on it await tester.tap(find.byType(TextField)); @@ -250,7 +251,7 @@ void main() { expect(textOpacity(tester, 'Enter some date'), equals(0.0)); }); - testWidgets('Label text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Label text', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Default label expect(find.text('Enter Date'), findsOneWidget); @@ -262,7 +263,7 @@ void main() { expect(find.text('Give me a date!'), findsOneWidget); }); - testWidgets('Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); // Fill the clipboard so that the Paste option is available in the text @@ -291,7 +292,7 @@ void main() { semantics.dispose(); }); - testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme is honored', (WidgetTester tester) async { const InputBorder border = InputBorder.none; await tester.pumpWidget(inputDatePickerField( theme: ThemeData.from(colorScheme: const ColorScheme.light()).copyWith( @@ -325,7 +326,7 @@ void main() { expect(containerColor, equals(Colors.transparent)); }); - testWidgets('Date text localization', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Date text localization', (WidgetTester tester) async { final Iterable> delegates = >[ TestMaterialLocalizationsDelegate(), DefaultWidgetsLocalizations.delegate, @@ -348,7 +349,7 @@ void main() { ); }); - testWidgets('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( @@ -363,7 +364,7 @@ void main() { expect(find.text(errorFormatText), findsNothing); }); - testWidgets('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index b388421bb4a78..962e31854cdfe 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -904,8 +904,6 @@ void main() { rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), ), ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('ListTile can be hovered and has correct hover color', (WidgetTester tester) async { @@ -1236,8 +1234,6 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking('ListTile respects tileColor & selectedTileColor', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index 6a1e70fc4c464..f07f79528b6a3 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -568,7 +568,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/106303 final GlobalKey scaffoldKey = GlobalKey(); diff --git a/packages/flutter/test/material/magnifier_test.dart b/packages/flutter/test/material/magnifier_test.dart index 9abf8906b2fcd..f700ca40c95ae 100644 --- a/packages/flutter/test/material/magnifier_test.dart +++ b/packages/flutter/test/material/magnifier_test.dart @@ -9,6 +9,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { final MagnifierController magnifierController = MagnifierController(); const Rect reasonableTextField = Rect.fromLTRB(50, 100, 200, 100); @@ -110,7 +112,7 @@ void main() { group('magnifier', () { group('position', () { - testWidgets( + testWidgetsWithLeakTracking( 'should be at gesture position if does not violate any positioning rules', (WidgetTester tester) async { final Key textField = UniqueKey(); @@ -166,7 +168,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'should never move outside the right bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -199,7 +201,7 @@ void main() { lessThanOrEqualTo(reasonableTextField.right)); }); - testWidgets( + testWidgetsWithLeakTracking( 'should never move outside the left bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -231,7 +233,7 @@ void main() { greaterThanOrEqualTo(reasonableTextField.left)); }); - testWidgets('should position vertically at the center of the line', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should position vertically at the center of the line', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), )); @@ -254,7 +256,7 @@ void main() { reasonableTextField.center.dy - basicOffset.dy); }); - testWidgets('should reposition vertically if mashed against the ceiling', + testWidgetsWithLeakTracking('should reposition vertically if mashed against the ceiling', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = Rect.fromPoints(Offset.zero, const Offset(200, 0)); @@ -289,7 +291,7 @@ void main() { return magnifier.additionalFocalPointOffset; } - testWidgets( + testWidgetsWithLeakTracking( 'should shift focal point so that the lens sees nothing out of bounds', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( @@ -317,7 +319,7 @@ void main() { lessThan(reasonableTextField.left)); }); - testWidgets( + testWidgetsWithLeakTracking( 'focal point should shift if mashed against the top to always point to text', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = @@ -354,7 +356,7 @@ void main() { return animatedPositioned.duration.compareTo(Duration.zero) != 0; } - testWidgets('should not be animated on the initial state', + testWidgetsWithLeakTracking('should not be animated on the initial state', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -379,7 +381,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgets('should not be animated on horizontal shifts', + testWidgetsWithLeakTracking('should not be animated on horizontal shifts', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -413,7 +415,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgets('should be animated on vertical shifts', + testWidgetsWithLeakTracking('should be animated on vertical shifts', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); @@ -449,7 +451,7 @@ void main() { expect(getIsAnimated(tester), true); }); - testWidgets('should stop being animated when timer is up', + testWidgetsWithLeakTracking('should stop being animated when timer is up', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); diff --git a/packages/flutter/test/material/material_button_test.dart b/packages/flutter/test/material/material_button_test.dart index cf611f7c8efd8..1e79a48320e01 100644 --- a/packages/flutter/test/material/material_button_test.dart +++ b/packages/flutter/test/material/material_button_test.dart @@ -143,8 +143,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('MaterialButton elevation and colors have proper precedence', (WidgetTester tester) async { @@ -217,8 +215,6 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)..rect(color: highlightColor)); expect(material.elevation, equals(highlightElevation)); await gesture2.up(); - - focusNode.dispose(); }); testWidgetsWithLeakTracking("MaterialButton's disabledColor takes precedence over its default disabled color.", (WidgetTester tester) async { @@ -303,8 +299,6 @@ void main() { await tester.pump(); expect(focusNode.hasPrimaryFocus, isTrue); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('MaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index 003ff987ed27c..e5a8536754946 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -5,6 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { void onPressed(TestMenu item) {} @@ -52,7 +54,7 @@ void main() { expect(identical(MenuBarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('theme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -105,7 +107,7 @@ void main() { expect(subMenuMaterial.color, equals(Colors.green)); }); - testWidgets('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_style_test.dart b/packages/flutter/test/material/menu_style_test.dart index dc501b68bc386..acc6d2079761f 100644 --- a/packages/flutter/test/material/menu_style_test.dart +++ b/packages/flutter/test/material/menu_style_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; void main() { Finder findMenuPanels() { @@ -42,7 +43,7 @@ void main() { expect(identical(MenuStyle.lerp(data, data, 0.5), data), true); }); - testWidgets('fixedSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fixedSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -85,7 +86,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgets('maximumSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maximumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -128,7 +129,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgets('minimumSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('minimumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -171,7 +172,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(300.0, 300.0))); }); - testWidgets('Material parameters are honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material parameters are honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -237,7 +238,7 @@ void main() { expect(panelPadding.padding, equals(const EdgeInsets.all(20))); }); - testWidgets('visual density', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visual density', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index 38c727025f6c6..868d4eb7f93de 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; void main() { void onPressed(TestMenu item) {} @@ -53,7 +54,7 @@ void main() { expect(identical(MenuThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('theme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -106,7 +107,7 @@ void main() { expect(subMenuMaterial.color, equals(Colors.red)); }); - testWidgets('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/mergeable_material_test.dart b/packages/flutter/test/material/mergeable_material_test.dart index 6b2a98d4b7307..1d184edb0f5eb 100644 --- a/packages/flutter/test/material/mergeable_material_test.dart +++ b/packages/flutter/test/material/mergeable_material_test.dart @@ -80,7 +80,7 @@ void main() { expect(box.size.height, equals(0)); }); - testWidgets('MergeableMaterial update slice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial update slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -234,7 +234,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( const MaterialApp( @@ -1168,7 +1168,7 @@ void main() { ); } - testWidgets('MergeableMaterial dividers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial dividers', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1330,7 +1330,7 @@ void main() { expect(decoration.border!.top.color, dividerColor); }); - testWidgets('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { const Color themeCardColor = Colors.red; const Color materialSliceColor = Colors.green; diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index cde4e4eb0eace..2e8befad6de7f 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('Navigation drawer updates destinations when tapped', + testWidgetsWithLeakTracking('Navigation drawer updates destinations when tapped', (WidgetTester tester) async { int mutatedIndex = -1; final GlobalKey scaffoldKey = GlobalKey(); @@ -49,7 +51,7 @@ void main() { expect(mutatedIndex, 0); }); - testWidgets('NavigationDrawer can update background color', + testWidgetsWithLeakTracking('NavigationDrawer can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; final GlobalKey scaffoldKey = GlobalKey(); @@ -82,7 +84,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgets('NavigationDrawer can update elevation', + testWidgetsWithLeakTracking('NavigationDrawer can update elevation', (WidgetTester tester) async { const double elevation = 42.0; final GlobalKey scaffoldKey = GlobalKey(); @@ -114,7 +116,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(elevation)); }); - testWidgets( + testWidgetsWithLeakTracking( 'NavigationDrawer uses proper defaults when no parameters are given', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -163,7 +165,7 @@ void main() { expect(iconBox.size, const Size(24.0, 24.0)); }); - testWidgets('Navigation drawer is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation drawer is scrollable', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 500, viewHeight: 300); await tester.pumpWidget( @@ -210,7 +212,7 @@ void main() { expect(find.text('Label10'), findsNothing); }); - testWidgets('Safe Area test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe Area test', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const double viewHeight = 300; widgetSetup(tester, 500, viewHeight: viewHeight); @@ -251,7 +253,7 @@ void main() { expect(tester.getBottomRight(find.widgetWithText(NavigationDrawerDestination,'Label4')).dy, viewHeight); }); - testWidgets('Navigation drawer semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation drawer semantics', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme= ThemeData.from(colorScheme: const ColorScheme.light()); Widget widget({int selectedIndex = 0}) { @@ -321,7 +323,7 @@ void main() { ); }); - testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation destination updates indicator color and shape', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); @@ -372,7 +374,7 @@ void main() { expect(_getInkWell(tester)?.customBorder, shape); }); - testWidgets('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 3000, viewHeight: 3000); final Widget widget = _buildWidget( diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 1c8a26e7d47bd..1bc1fe8b29602 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -229,8 +229,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does OutlinedButton work with hover', (WidgetTester tester) async { @@ -289,8 +287,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does OutlinedButton work with autofocus', (WidgetTester tester) async { @@ -321,8 +317,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - - focusNode.dispose(); }); testWidgets('Default OutlinedButton meets a11y contrast guidelines', (WidgetTester tester) async { @@ -368,8 +362,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); - - focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -439,8 +431,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. await expectLater(tester, meetsGuideline(textContrastGuideline)); - - focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -510,8 +500,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton uses stateful color for icon color in different states', (WidgetTester tester) async { @@ -579,8 +567,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton uses stateful color for border color in different states', (WidgetTester tester) async { @@ -649,8 +635,6 @@ void main() { await gesture.down(center); await tester.pumpAndSettle(); expect(outlinedButton, paints..drrect(color: pressedColor)); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -745,8 +729,6 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered OutlinedButton responds to mouse-exit', (WidgetTester tester) async { @@ -838,8 +820,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking('When OutlinedButton disable, Can not set OutlinedButton focus.', (WidgetTester tester) async { @@ -863,8 +843,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking("Outline button doesn't crash if disabled during a gesture", (WidgetTester tester) async { @@ -1843,7 +1821,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1996,15 +1974,15 @@ void main() { await gesture.removePointer(); } - testWidgets('OutlinedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('OutlinedButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled OutlinedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled OutlinedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 27556b443f9ff..2a46455781e12 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -208,7 +208,7 @@ void main() { expect(indicatorColors(tester), const [kBlue, kRed, kRed]); }); - testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, diff --git a/packages/flutter/test/material/persistent_bottom_sheet_test.dart b/packages/flutter/test/material/persistent_bottom_sheet_test.dart index 21d693bfe8b3b..eb7c6eec93f7d 100644 --- a/packages/flutter/test/material/persistent_bottom_sheet_test.dart +++ b/packages/flutter/test/material/persistent_bottom_sheet_test.dart @@ -124,7 +124,7 @@ void main() { expect(buildCount, equals(2)); }); - testWidgets('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: const Center(child: Text('body')), @@ -187,7 +187,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -299,7 +299,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -410,7 +410,7 @@ void main() { expect(find.text('Item 22'), findsNothing); }); - testWidgets('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -590,7 +590,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/71435 - testWidgets( + testWidgetsWithLeakTracking( 'Scaffold.bottomSheet should be updated without creating a new RO' ' when the new widget has the same key and type.', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index eca0c83ae642a..4ad6e7e9cbdcd 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -584,7 +584,6 @@ void main() { ..circle(color: const Color(0x61000000)) ..circle(color: const Color(0x61000000)), ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio is focusable and has correct focus color', (WidgetTester tester) async { @@ -663,7 +662,6 @@ void main() { ..circle(color: theme.colorScheme.onSurface.withOpacity(0.38)) ..circle(color: theme.colorScheme.onSurface.withOpacity(0.38)), ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { @@ -910,8 +908,6 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.space); await tester.pumpAndSettle(); expect(groupValue, equals(2)); - - focusNode2.dispose(); }); testWidgetsWithLeakTracking('Radio responds to density changes.', (WidgetTester tester) async { @@ -1228,8 +1224,6 @@ void main() { ..circle(color: theme.hoverColor) ..circle(color: hoveredFillColor), ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { @@ -1308,8 +1302,6 @@ void main() { ..circle(color: theme.colorScheme.primary.withOpacity(0.08)) ..circle(color: hoveredFillColor), ); - - focusNode.dispose(); }); testWidgets('Radio overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { @@ -1455,8 +1447,6 @@ void main() { ), reason: 'Hovered Radio should use overlay color $hoverOverlayColor over $hoverColor', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { @@ -1720,8 +1710,6 @@ void main() { Material.of(tester.element(find.byType(Radio))), paints..circle(color: theme.hoverColor)..circle(color: colors.secondary) ); - - focusNode.dispose(); }); testWidgets('Material3 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { @@ -1808,8 +1796,6 @@ void main() { Material.of(tester.element(find.byType(Radio))), paints..circle(color: colors.primary.withOpacity(0.08))..circle(color: colors.primary.withOpacity(1)) ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Radio.adaptive shows the correct platform widget', (WidgetTester tester) async { @@ -1906,7 +1892,6 @@ void main() { ..circle(color: theme.focusColor) ..circle(color: theme.colorScheme.secondary) ); - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { @@ -1972,6 +1957,5 @@ void main() { ..circle(color: theme.colorScheme.primary.withOpacity(0.12)) ..circle(color: theme.colorScheme.primary) ); - focusNode.dispose(); }); } diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index f89cfe9957337..0f4f2270469f9 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -9,9 +9,11 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { // Regression test for https://github.com/flutter/flutter/issues/105833 - testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag gesture uses provided gesture settings', (WidgetTester tester) async { RangeValues values = const RangeValues(0.1, 0.5); bool dragStarted = false; final Key sliderKey = UniqueKey(); @@ -117,7 +119,7 @@ void main() { expect(dragStarted, false); }); - testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -171,7 +173,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgets('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -225,7 +227,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgets('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -283,7 +285,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgets('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -341,7 +343,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -385,7 +387,7 @@ void main() { expect(values.end, equals(1)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -429,7 +431,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -475,7 +477,7 @@ void main() { expect(values.end, equals(100)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -521,7 +523,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -571,7 +573,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -621,7 +623,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -673,7 +675,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -725,7 +727,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -775,7 +777,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -825,7 +827,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -877,7 +879,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -929,7 +931,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); RangeValues? startValues; RangeValues? endValues; @@ -983,7 +985,7 @@ void main() { expect(endValues!.end, moreOrLessEquals(70, epsilon: 1)); }); - testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); late RangeValues startValues; late RangeValues endValues; @@ -1098,7 +1100,7 @@ void main() { ); } - testWidgets('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1127,7 +1129,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1155,7 +1157,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1182,7 +1184,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1215,7 +1217,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1245,7 +1247,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1286,7 +1288,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1306,7 +1308,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1495,7 +1497,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1562,7 +1564,7 @@ void main() { ); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1636,7 +1638,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1713,7 +1715,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1794,7 +1796,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101868 - testWidgets('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1852,7 +1854,7 @@ void main() { ); }); - testWidgets('Range Slider Semantics - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider Semantics - ltr', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1936,7 +1938,7 @@ void main() { ]); }); - testWidgets('Range Slider Semantics - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider Semantics - rtl', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -2018,7 +2020,7 @@ void main() { ]); }); - testWidgets('Range Slider implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); RangeSlider( @@ -2049,7 +2051,7 @@ void main() { ]); }); - testWidgets('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -2088,7 +2090,7 @@ void main() { ); }); - testWidgets('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -2133,7 +2135,7 @@ void main() { ); }); - testWidgets('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { // Regress test for https://github.com/flutter/flutter/issues/65943 Widget buildFrame(double maxValue) { return MaterialApp( @@ -2177,7 +2179,7 @@ void main() { expect(nearEqual(activeTrackRect.right, (800.0 - 24.0 - 24.0) * (8 / 15) + 24.0, 0.01), true); }); - testWidgets('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { const RangeValues values = RangeValues(50, 70); // Test default cursor. @@ -2232,7 +2234,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { RangeValues values = const RangeValues(50, 70); const MouseCursor disabledCursor = SystemMouseCursors.basic; const MouseCursor hoveredCursor = SystemMouseCursors.grab; @@ -2306,7 +2308,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), draggedCursor); }); - testWidgets('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2369,7 +2371,7 @@ void main() { ); }); - testWidgets('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2425,7 +2427,7 @@ void main() { ); }); - testWidgets('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); const Color hoverColor = Color(0xffff0000); @@ -2540,7 +2542,7 @@ void main() { ); }); - testWidgets('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128433 int startFired = 0; diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index 9f18984196d94..2306e083df160 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -108,7 +108,6 @@ void main() { await tester.pumpAndSettle(); expect(pressed, isTrue); - focusNode.dispose(); }); testWidgetsWithLeakTracking('materialTapTargetSize.padded expands hit test area', (WidgetTester tester) async { @@ -346,7 +345,6 @@ void main() { await tester.pumpAndSettle(const Duration(seconds: 1)); expect(box, paints..rect(color: focusColor)); - focusNode.dispose(); }); testWidgetsWithLeakTracking('RawMaterialButton loses focus when disabled.', (WidgetTester tester) async { @@ -381,7 +379,6 @@ void main() { await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); - focusNode.dispose(); }); testWidgetsWithLeakTracking("Disabled RawMaterialButton can't be traversed to.", (WidgetTester tester) async { @@ -422,9 +419,6 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); - - focusNode1.dispose(); - focusNode2.dispose(); }); testWidgetsWithLeakTracking('RawMaterialButton handles hover', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/scrollbar_paint_test.dart b/packages/flutter/test/material/scrollbar_paint_test.dart index 0b86294e5cf2a..1686ff52e495d 100644 --- a/packages/flutter/test/material/scrollbar_paint_test.dart +++ b/packages/flutter/test/material/scrollbar_paint_test.dart @@ -79,7 +79,7 @@ void main() { ); }); - testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with MaterialApp and Scaffold', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -123,7 +123,7 @@ void main() { ); }); - testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { + testWidgetsWithLeakTracking("should not paint when there isn't enough space", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( diff --git a/packages/flutter/test/material/search_bar_theme_test.dart b/packages/flutter/test/material/search_bar_theme_test.dart index 781984124b521..ce85e73e3c932 100644 --- a/packages/flutter/test/material/search_bar_theme_test.dart +++ b/packages/flutter/test/material/search_bar_theme_test.dart @@ -243,19 +243,19 @@ void main() { expect(trailingRect.right, barRect.right - 16.0); } - testWidgets('SearchBar properties overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgets('SearchBar theme data overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); }); - testWidgets('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); @@ -263,7 +263,7 @@ void main() { // Same as the previous tests with empty SearchBarThemeData's instead of null. - testWidgets('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true, searchBarThemeData: const SearchBarThemeData(), overallTheme: const SearchBarThemeData())); @@ -271,14 +271,14 @@ void main() { checkSearchBar(tester); }); - testWidgets('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme, overallTheme: const SearchBarThemeData())); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgets('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); diff --git a/packages/flutter/test/material/search_view_theme_test.dart b/packages/flutter/test/material/search_view_theme_test.dart index adc8ff87f8874..98e8e379cc6dd 100644 --- a/packages/flutter/test/material/search_view_theme_test.dart +++ b/packages/flutter/test/material/search_view_theme_test.dart @@ -197,21 +197,21 @@ void main() { expect(inputText.style.fontSize, headerTextStyle.fontSize); } - testWidgets('SearchView properties overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchView(tester); }); - testWidgets('SearchView theme data overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); checkSearchView(tester); }); - testWidgets('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); @@ -220,7 +220,7 @@ void main() { // Same as the previous tests with empty SearchViewThemeData's instead of null. - testWidgets('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true, searchViewThemeData: const SearchViewThemeData(), overallTheme: const SearchViewThemeData())); @@ -229,7 +229,7 @@ void main() { checkSearchView(tester); }); - testWidgets('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme, overallTheme: const SearchViewThemeData())); await tester.tap(find.byIcon(Icons.search)); @@ -237,7 +237,7 @@ void main() { checkSearchView(tester); }); - testWidgets('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index 57b31588e8862..bc0caa645fb1b 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; Widget boilerplate({required Widget child}) { @@ -21,7 +22,7 @@ Widget boilerplate({required Widget child}) { void main() { - testWidgets('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -329,7 +330,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgets('SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -408,7 +409,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgets('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -485,7 +486,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes semantics.dispose(); }); - testWidgets('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -533,7 +534,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('SegmentedButton has no tooltips by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton has no tooltips by default', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -557,7 +558,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byType(Tooltip), findsNothing); }); - testWidgets('SegmentedButton has correct tooltips', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton has correct tooltips', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/segmented_button_theme_test.dart b/packages/flutter/test/material/segmented_button_theme_test.dart index ce19b4b476be2..6c2cf45a0df6b 100644 --- a/packages/flutter/test/material/segmented_button_theme_test.dart +++ b/packages/flutter/test/material/segmented_button_theme_test.dart @@ -43,7 +43,7 @@ void main() { expect(description, []); }); - testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -110,7 +110,7 @@ void main() { } }); - testWidgets('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: true, segmentedButtonTheme: SegmentedButtonThemeData( @@ -203,7 +203,7 @@ void main() { } }); - testWidgets('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { @@ -330,7 +330,7 @@ void main() { } }); - testWidgets('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index db8434b831c52..c5d110b1ad9a8 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0); @@ -17,7 +18,7 @@ Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { } void main() { - testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectionArea uses correct selection controls', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('abc'), @@ -39,7 +40,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123378 await tester.pumpWidget( const MaterialApp( @@ -70,7 +71,7 @@ void main() { }); - testWidgets('builds the default context menu by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds the default context menu by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SelectionArea( @@ -97,7 +98,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('builds a custom context menu if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds a custom context menu if provided', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -133,7 +134,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes', (WidgetTester tester) async { SelectedContent? content; await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 383dc49d4f9b8..935e959afff4d 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { test('SliderThemeData copyWith, ==, hashCode basics', () { expect(const SliderThemeData(), const SliderThemeData().copyWith()); @@ -18,7 +20,7 @@ void main() { expect(identical(SliderThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData().debugFillProperties(builder); @@ -30,7 +32,7 @@ void main() { expect(description, []); }); - testWidgets('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData( trackHeight: 7.0, @@ -500,7 +502,7 @@ void main() { } }); - testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider parameters overrides theme properties', (WidgetTester tester) async { debugDisableShadows = false; const Color activeTrackColor = Color(0xffff0001); const Color inactiveTrackColor = Color(0xffff0002); @@ -554,7 +556,7 @@ void main() { } }); - testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -578,7 +580,7 @@ void main() { ); }); - testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -602,7 +604,7 @@ void main() { ); }); - testWidgets('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -632,7 +634,7 @@ void main() { expect(sliderTheme.valueIndicatorTextStyle!.color, equals(customColor4)); }); - testWidgets('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -656,7 +658,7 @@ void main() { expect(sliderTheme.rangeValueIndicatorShape, const PaddleRangeSliderValueIndicatorShape()); }); - testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData lerps correctly', (WidgetTester tester) async { final SliderThemeData sliderThemeBlack = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -690,7 +692,7 @@ void main() { expect(lerp.valueIndicatorTextStyle!.color, equals(middleGrey.withAlpha(0xff))); }); - testWidgets('Default slider track draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider track draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -726,7 +728,7 @@ void main() { ); }); - testWidgets('Default slider overlay draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider overlay draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -787,7 +789,7 @@ void main() { ); }); - testWidgets('Slider can use theme overlay with material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can use theme overlay with material states', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -846,7 +848,7 @@ void main() { ); }); - testWidgets('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -890,7 +892,7 @@ void main() { ); }); - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1074,7 +1076,7 @@ void main() { } }); - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1258,7 +1260,7 @@ void main() { } }); - testWidgets('The slider track height can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider track height can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(trackHeight: 16); const Radius radius = Radius.circular(8); const Radius activatedRadius = Radius.circular(9); @@ -1288,7 +1290,7 @@ void main() { ); }); - testWidgets('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 7, @@ -1313,7 +1315,7 @@ void main() { ); }); - testWidgets('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 9, @@ -1336,7 +1338,7 @@ void main() { ); }); - testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5), activeTickMarkColor: const Color(0xfadedead), @@ -1369,7 +1371,7 @@ void main() { ); }); - testWidgets('The default slider overlay shape size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider overlay shape size can be overridden', (WidgetTester tester) async { const double uniqueOverlayRadius = 23; final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: const RoundSliderOverlayShape( @@ -1396,7 +1398,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/74503 - testWidgets('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1437,7 +1439,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/125467 - testWidgets('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1488,7 +1490,7 @@ void main() { // // The value indicator can be skipped by passing the appropriate // [ShowValueIndicator]. - testWidgets('The slider can skip all of its component painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all of its component painting', (WidgetTester tester) async { // Pump a slider with all shapes skipped. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1509,7 +1511,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the track', (WidgetTester tester) async { // Pump a slider with just a track. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1530,7 +1532,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { // Pump a slider with just tick marks. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1554,7 +1556,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the thumb', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a thumb. @@ -1580,7 +1582,7 @@ void main() { } }); - testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the overlay', (WidgetTester tester) async { // Pump a slider with just an overlay. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1608,7 +1610,7 @@ void main() { await gesture.up(); }); - testWidgets('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1638,7 +1640,7 @@ void main() { await gesture.up(); }); - testWidgets('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1673,7 +1675,7 @@ void main() { await gesture.up(); }); - testWidgets('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1705,7 +1707,7 @@ void main() { }); - testWidgets('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1755,7 +1757,7 @@ void main() { } }); - testWidgets('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { debugDisableShadows = true; final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -1801,7 +1803,7 @@ void main() { await gesture.up(); }); - testWidgets('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1835,7 +1837,7 @@ void main() { } }); - testWidgets('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1871,7 +1873,7 @@ void main() { } }); - testWidgets('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( trackShape: const RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight( @@ -1898,7 +1900,7 @@ void main() { ); }); - testWidgets('The mouse cursor is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The mouse cursor is themeable', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( mouseCursor: const MaterialStatePropertyAll(SystemMouseCursors.text), @@ -1913,7 +1915,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { double value = 0.0; Widget buildApp({ @@ -2020,7 +2022,7 @@ void main() { await gesture.up(); }); - testWidgets('Default value indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -2233,7 +2235,7 @@ void main() { } }); - testWidgets('Default value indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index 45880b19e66c1..c3801a8fcbb4d 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -560,7 +560,6 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - node.dispose(); }); testWidgetsWithLeakTracking('SwitchListTile.adaptive onFocusChange Callback', (WidgetTester tester) async { @@ -590,7 +589,6 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - node.dispose(); }); group('feedback', () { @@ -865,7 +863,7 @@ void main() { ); }); - testWidgets('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF4caf50); const Color pressedThumbColor = Color(0xFFF44336); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index d8b3c703455fb..fa89e561f7fc6 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -701,8 +701,6 @@ void main() { expect(getSwitchMaterial(tester), paints..circle(color: theme.hoverColor) ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { @@ -748,8 +746,6 @@ void main() { expect(getSwitchMaterial(tester), paints..circle(color: theme.colorScheme.primary.withOpacity(0.08)) ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Switch can be set color', (WidgetTester tester) async { @@ -1242,8 +1238,6 @@ void main() { ..rrect(color: const Color(0x1f000000)) ..rrect(color: const Color(0xffbdbdbd)), ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch is focusable and has correct focus color', (WidgetTester tester) async { @@ -1331,8 +1325,6 @@ void main() { ) ..rrect(color: Color.alphaBlend(colors.onSurface.withOpacity(0.38), colors.surface)), ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch with splash radius set', (WidgetTester tester) async { @@ -1993,8 +1985,6 @@ void main() { ..rrect(color: hoveredThumbColor), reason: 'Inactive disabled switch should default track and custom thumb color', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { @@ -2071,8 +2061,6 @@ void main() { ..rrect(color: hoveredThumbColor), reason: 'active enabled switch should default track and custom thumb color', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Track color resolves in active/enabled states', (WidgetTester tester) async { @@ -2324,8 +2312,6 @@ void main() { ), reason: 'Inactive enabled switch should match these colors', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { @@ -2396,8 +2382,6 @@ void main() { ), reason: 'Active enabled switch should match these colors', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Switch thumb color is blended against surface color', (WidgetTester tester) async { @@ -2650,8 +2634,6 @@ void main() { ), reason: 'Hovered Switch should use overlay color $hoverOverlayColor over $hoverColor', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { @@ -3205,8 +3187,6 @@ void main() { ..rrect(color: hoveredTrackOutlineColor, style: PaintingStyle.stroke), reason: 'Active enabled switch track outline should match this color', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Track outline width resolves in active/enabled states', (WidgetTester tester) async { @@ -3342,8 +3322,6 @@ void main() { ..rrect(strokeWidth: hoveredTrackOutlineWidth, style: PaintingStyle.stroke), reason: 'Active enabled switch track outline width should be 4.0', ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch can set icon - M3', (WidgetTester tester) async { @@ -3508,8 +3486,6 @@ void main() { ..rrect(color: const Color(0x0a000000)) ..rrect(color: const Color(0xffffffff)), ); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch.onFocusChange callback', (WidgetTester tester) async { @@ -3539,8 +3515,6 @@ void main() { await tester.pump(); expect(focused, isFalse); expect(focusNode.hasFocus, isFalse); - - focusNode.dispose(); }); } diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 836a6592d2e5a..1c3b757d2fa24 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -200,8 +200,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); - - focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -269,8 +267,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. await expectLater(tester, meetsGuideline(textContrastGuideline)); - - focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -326,8 +322,6 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -395,8 +389,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton uses stateful color for icon color in different states', (WidgetTester tester) async { @@ -464,8 +456,6 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton has no clip by default', (WidgetTester tester) async { @@ -542,8 +532,6 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Does TextButton contribute semantics', (WidgetTester tester) async { @@ -813,8 +801,6 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered TextButton responds to mouse-exit', (WidgetTester tester) async { @@ -906,8 +892,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking('When TextButton disable, Can not set TextButton focus.', (WidgetTester tester) async { @@ -931,8 +915,6 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); - - node.dispose(); }); testWidgetsWithLeakTracking('TextButton responds to density changes.', (WidgetTester tester) async { @@ -1643,7 +1625,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1796,15 +1778,15 @@ void main() { await gesture.removePointer(); } - testWidgets('TextButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('TextButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled TextButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled TextButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart index a5b4a06a421fd..21934175279ed 100644 --- a/packages/flutter/test/material/text_field_helper_text_test.dart +++ b/packages/flutter/test/material/text_field_helper_text_test.dart @@ -5,8 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + void main() { - testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField works correctly when changing helperText', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(1)); await tester.pump(const Duration(milliseconds: 100)); diff --git a/packages/flutter/test/material/text_field_splash_test.dart b/packages/flutter/test/material/text_field_splash_test.dart index b16f0ced9b951..ab26df41cbe0d 100644 --- a/packages/flutter/test/material/text_field_splash_test.dart +++ b/packages/flutter/test/material/text_field_splash_test.dart @@ -6,6 +6,8 @@ import 'package:flutter/gestures.dart' show kPressTimeout; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; + bool confirmCalled = false; bool cancelCalled = false; @@ -135,7 +137,7 @@ void main() { expect(cancelCalled, isFalse); }); - testWidgets('Splash should never be created or canceled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Splash should never be created or canceled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 80be8ea948091..36373fec387cf 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -249,10 +249,10 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. // TODO(polina-c): remove after fixing // https://github.com/flutter/flutter/issues/130467 - leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true, allowAllNotGCed: true), + leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: {'ValueNotifier<_OverlayEntryWidgetState?>': 16}), ); - testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); @@ -347,7 +347,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { bool asserted; try { TextFormField( @@ -360,7 +360,7 @@ void main() { expect(asserted, false); }); - testWidgets('Passes textAlign to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textAlign to underlying TextField', (WidgetTester tester) async { const TextAlign alignment = TextAlign.center; await tester.pumpWidget( @@ -382,7 +382,7 @@ void main() { expect(textFieldWidget.textAlign, alignment); }); - testWidgets('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { const ScrollPhysics scrollPhysics = ScrollPhysics(); await tester.pumpWidget( @@ -404,7 +404,7 @@ void main() { expect(textFieldWidget.scrollPhysics, scrollPhysics); }); - testWidgets('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { const TextAlignVertical textAlignVertical = TextAlignVertical.bottom; await tester.pumpWidget( @@ -426,7 +426,7 @@ void main() { expect(textFieldWidget.textAlignVertical, textAlignVertical); }); - testWidgets('Passes textInputAction to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textInputAction to underlying TextField', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -446,7 +446,7 @@ void main() { expect(textFieldWidget.textInputAction, TextInputAction.next); }); - testWidgets('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { void onEditingComplete() { } await tester.pumpWidget( @@ -468,7 +468,7 @@ void main() { expect(textFieldWidget.onEditingComplete, onEditingComplete); }); - testWidgets('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { const double cursorWidth = 3.14; const double cursorHeight = 6.28; const Radius cursorRadius = Radius.circular(4); @@ -520,7 +520,7 @@ void main() { expect(called, true); }); - testWidgets('onChanged callbacks are called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callbacks are called', (WidgetTester tester) async { late String value; await tester.pumpWidget( @@ -542,7 +542,7 @@ void main() { expect(value, 'Soup'); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -567,7 +567,7 @@ void main() { expect(validateCalled, 2); }); - testWidgets('validate is called if widget is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('validate is called if widget is enabled', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -594,7 +594,7 @@ void main() { }); - testWidgets('Disabled field hides helper and counter in M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled field hides helper and counter in M2', (WidgetTester tester) async { const String helperText = 'helper text'; const String counterText = 'counter text'; const String errorText = 'error text'; @@ -642,7 +642,7 @@ void main() { expect(errorWidget.style!.color, equals(Colors.transparent)); }); - testWidgets('passing a buildCounter shows returned widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing a buildCounter shows returned widget', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -707,7 +707,7 @@ void main() { expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); }, skip: isBrowser); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgets('onTap is called upon tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( MaterialApp( @@ -734,7 +734,7 @@ void main() { expect(tapCount, 3); }); - testWidgets('onTapOutside is called upon tap outside', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTapOutside is called upon tap outside', (WidgetTester tester) async { int tapOutsideCount = 0; await tester.pumpWidget( MaterialApp( @@ -765,7 +765,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgets('reset resets the text fields value to the initialValue', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reset resets the text fields value to the initialValue', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -788,7 +788,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgets("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { + testWidgetsWithLeakTracking("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -811,7 +811,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgets("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { + testWidgetsWithLeakTracking("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -834,7 +834,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgets('didChange changes text fields value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didChange changes text fields value', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -856,7 +856,7 @@ void main() { expect(find.text('changedValue'), findsOneWidget); }); - testWidgets('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { bool called = false; late FormFieldState state; @@ -883,7 +883,7 @@ void main() { expect(called, true); }); - testWidgets('autofillHints is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autofillHints is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -900,7 +900,7 @@ void main() { expect(widget.autofillHints, equals(const [AutofillHints.countryName])); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -925,7 +925,7 @@ void main() { expect(validateCalled, 1); }); - testWidgets('textSelectionControls is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textSelectionControls is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -942,7 +942,7 @@ void main() { expect(widget.selectionControls, equals(materialTextSelectionControls)); }); - testWidgets('TextFormField respects hintTextDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField respects hintTextDirection', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Directionality( @@ -984,7 +984,7 @@ void main() { expect(textDirection, TextDirection.rtl); }); - testWidgets('Passes scrollController to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scrollController to underlying TextField', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -1006,7 +1006,7 @@ void main() { expect(textFieldWidget.scrollController, scrollController); }); - testWidgets('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1151,7 +1151,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { final SpellCheckConfiguration mySpellCheckConfiguration = SpellCheckConfiguration( spellCheckService: DefaultSpellCheckService(), misspelledTextStyle: TextField.materialMisspelledTextStyle, @@ -1181,7 +1181,7 @@ void main() { ); }); - testWidgets('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { final TextMagnifierConfiguration myTextMagnifierConfiguration = TextMagnifierConfiguration( magnifierBuilder: (BuildContext context, MagnifierController controller, ValueNotifier notifier) { return const Placeholder(); @@ -1202,7 +1202,7 @@ void main() { expect(editableText.magnifierConfiguration, equals(myTextMagnifierConfiguration)); }); - testWidgets('Passes undoController to undoController TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes undoController to undoController TextField', (WidgetTester tester) async { final UndoHistoryController undoController = UndoHistoryController(value: UndoHistoryValue.empty); await tester.pumpWidget( @@ -1224,7 +1224,7 @@ void main() { expect(textFieldWidget.undoController, undoController); }); - testWidgets('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { const bool cursorOpacityAnimates = true; await tester.pumpWidget( @@ -1246,7 +1246,7 @@ void main() { expect(textFieldWidget.cursorOpacityAnimates, cursorOpacityAnimates); }); - testWidgets('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { final ContentInsertionConfiguration contentInsertionConfiguration = ContentInsertionConfiguration(onContentInserted: (KeyboardInsertedContent value) {}); @@ -1269,7 +1269,7 @@ void main() { expect(textFieldWidget.contentInsertionConfiguration, contentInsertionConfiguration); }); - testWidgets('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { const Clip clipBehavior = Clip.antiAlias; await tester.pumpWidget( @@ -1291,7 +1291,7 @@ void main() { expect(textFieldWidget.clipBehavior, clipBehavior); }); - testWidgets('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { const bool scribbleEnabled = false; await tester.pumpWidget( @@ -1313,7 +1313,7 @@ void main() { expect(textFieldWidget.scribbleEnabled, scribbleEnabled); }); - testWidgets('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { const bool canRequestFocus = false; await tester.pumpWidget( @@ -1335,7 +1335,7 @@ void main() { expect(textFieldWidget.canRequestFocus, canRequestFocus); }); - testWidgets('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { void onAppPrivateCommand(String p0, Map p1) {} await tester.pumpWidget( @@ -1357,7 +1357,7 @@ void main() { expect(textFieldWidget.onAppPrivateCommand, onAppPrivateCommand); }); - testWidgets('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { const BoxHeightStyle selectionHeightStyle = BoxHeightStyle.max; await tester.pumpWidget( @@ -1379,7 +1379,7 @@ void main() { expect(textFieldWidget.selectionHeightStyle, selectionHeightStyle); }); - testWidgets('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { const BoxWidthStyle selectionWidthStyle = BoxWidthStyle.max; await tester.pumpWidget( @@ -1401,7 +1401,7 @@ void main() { expect(textFieldWidget.selectionWidthStyle, selectionWidthStyle); }); - testWidgets('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { const DragStartBehavior dragStartBehavior = DragStartBehavior.down; await tester.pumpWidget( @@ -1423,7 +1423,7 @@ void main() { expect(textFieldWidget.dragStartBehavior, dragStartBehavior); }); - testWidgets('Error color for cursor while validating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Error color for cursor while validating', (WidgetTester tester) async { const Color errorColor = Color(0xff123456); await tester.pumpWidget(MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 07d565b9316f8..1e7ba83ced5b5 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -113,8 +113,7 @@ void main() { notDisposedAllowList: { 'ValueNotifier': 1, 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, + 'ValueNotifier': 1, }, // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. allowAllNotGCed: true, @@ -174,8 +173,7 @@ void main() { notDisposedAllowList: { 'ValueNotifier': 1, 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, + 'ValueNotifier': 1, }, // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. allowAllNotGCed: true, diff --git a/packages/flutter/test/material/text_selection_toolbar_test.dart b/packages/flutter/test/material/text_selection_toolbar_test.dart index 41ecd8c878c4c..f37714db21c24 100644 --- a/packages/flutter/test/material/text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_test.dart @@ -173,7 +173,7 @@ void main() { expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); }); - testWidgets('can create and use a custom toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index 517fecd6b1544..7c6d42c2fa396 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -62,7 +62,7 @@ void main() { expect(() => RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)).value, throwsAssertionError); }); - testWidgets('work when not in restoration scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); final _RestorableWidgetState state = tester.state(find.byType(_RestorableWidget)); @@ -107,7 +107,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 2, minute: 2)); }); - testWidgets('restore to older state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restore to older state', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -138,7 +138,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 10, minute: 5)); }); - testWidgets('call notifiers when value changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('call notifiers when value changes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index 7a03deee05bba..a14363033b86e 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -817,8 +817,6 @@ void main() { expect(inkFeatures, paints..rect(color: theme.colorScheme.onSurface.withOpacity(0.12))); await hoverGesture.removePointer(); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Default InkWell colors - selected', (WidgetTester tester) async { @@ -884,8 +882,6 @@ void main() { expect(inkFeatures, paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); await hoverGesture.removePointer(); - - focusNode.dispose(); }); testWidgetsWithLeakTracking('Custom InkWell colors', (WidgetTester tester) async { @@ -955,8 +951,6 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); await hoverGesture.removePointer(); - - focusNode.dispose(); }); testWidgetsWithLeakTracking( @@ -1869,10 +1863,6 @@ void main() { expect(toggleButtonElevation('two'), 0); await hoverGesture.removePointer(); - - for (final FocusNode n in focusNodes) { - n.dispose(); - } }); testWidgetsWithLeakTracking('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index dfd7df499a7f6..7b67cbe901edc 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -512,8 +512,6 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); await hoverGesture.removePointer(); - - focusNode.dispose(); }); testWidgetsWithLeakTracking( diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 9d9bd888476aa..8b68be4cbdf5f 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -25,7 +25,7 @@ Finder _findTooltipContainer(String tooltipText) { } void main() { - testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -79,7 +79,7 @@ void main() { expect(tipInGlobal.dy, 20.0); }); - testWidgets('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -138,7 +138,7 @@ void main() { expect(tipInGlobal.dy, 40.0); }); - testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - top left', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -192,7 +192,7 @@ void main() { expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0))); }); - testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -245,7 +245,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -309,7 +309,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -361,7 +361,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -418,7 +418,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -475,7 +475,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgets('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23666 Widget materialAppWithViewInsets(double viewInsetsHeight) { final Widget scaffold = Scaffold( @@ -530,7 +530,7 @@ void main() { expect(tooltipTopRight.dy, lessThan(fabTopRight.dy)); }); - testWidgets('Custom tooltip margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom tooltip margin', (WidgetTester tester) async { const double customMarginValue = 10.0; final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( @@ -767,7 +767,7 @@ void main() { expect(textStyle.decorationStyle, isNot(TextDecorationStyle.double)); }); - testWidgets('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -835,7 +835,7 @@ void main() { expect(tooltipContainer.padding, const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0)); }, variant: const TargetPlatformVariant({TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows})); - testWidgets('Can tooltip decoration be customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can tooltip decoration be customized', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -1393,7 +1393,7 @@ void main() { await tester.pump(waitDuration); }); - testWidgets('Does tooltip contribute semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey tooltipKey = GlobalKey(); diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index b0352255e1159..75d623b1f0ed5 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -113,7 +113,7 @@ void main() { ]); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -170,7 +170,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -225,7 +225,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -293,7 +293,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -359,7 +359,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -415,7 +415,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -469,7 +469,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip margin - ThemeData', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -524,7 +524,7 @@ void main() { expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); }); - testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip margin - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -675,7 +675,7 @@ void main() { expect(textAlign, TextAlign.end); }); - testWidgets('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -717,7 +717,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgets('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -757,7 +757,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgets('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingVal = 20.0; @@ -804,7 +804,7 @@ void main() { expect(content.size.width, equals(tip.size.width - 2 * customPaddingVal)); }); - testWidgets('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingValue = 20.0; diff --git a/packages/flutter/test/material/value_indicating_slider_test.dart b/packages/flutter/test/material/value_indicating_slider_test.dart index 070d362515ee2..fb8029b935ab7 100644 --- a/packages/flutter/test/material/value_indicating_slider_test.dart +++ b/packages/flutter/test/material/value_indicating_slider_test.dart @@ -10,9 +10,10 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../foundation/leak_tracking.dart'; void main() { - testWidgets('Slider value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -53,7 +54,7 @@ void main() { ); }); - testWidgets('Slider value indicator wide text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -97,7 +98,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator large text scale', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -141,7 +142,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale and wide text', + testWidgetsWithLeakTracking('Slider value indicator large text scale and wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, @@ -194,7 +195,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Slider value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -232,7 +233,7 @@ void main() { ); }); - testWidgets('Slider value indicator wide text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -273,7 +274,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator large text scale', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -314,7 +315,7 @@ void main() { ); }); - testWidgets('Slider value indicator large text scale and wide text', + testWidgetsWithLeakTracking('Slider value indicator large text scale and wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 47aa1b7bb207c..e51fc3f4fd7f9 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -41,12 +41,13 @@ dev_dependencies: fake_async: 1.3.1 test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c36c +# PUBSPEC CHECKSUM: d729 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 4fbfb2c97a5c2..4fa470fb15965 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -60,14 +60,15 @@ dependencies: standard_message_codec: 0.0.1+3 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_value: 8.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dds_service_extensions: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" devtools_shared: 2.26.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -107,4 +108,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 2e84 +# PUBSPEC CHECKSUM: 6b41 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index b6bae54575431..1b9eec759ca1d 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -18,8 +18,8 @@ dependencies: dev_dependencies: test: 1.24.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,6 +27,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +64,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 4157 +# PUBSPEC CHECKSUM: f314 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index eb3571d200a22..aff039587fdef 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -34,8 +34,8 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,6 +43,7 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 8fd3 +# PUBSPEC CHECKSUM: 5290 From fa88170a4f9c320f73a501858cd5ba52076d5f09 Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Wed, 9 Aug 2023 17:05:27 +0000 Subject: [PATCH 0614/1547] Update material and cupertino localizations (#131212) See title. Fixes https://github.com/flutter/flutter/issues/130874. --------- Co-authored-by: Xilai Zhang --- .../lib/src/l10n/cupertino_af.arb | 4 +- .../lib/src/l10n/cupertino_am.arb | 4 +- .../lib/src/l10n/cupertino_ar.arb | 4 +- .../lib/src/l10n/cupertino_as.arb | 4 +- .../lib/src/l10n/cupertino_az.arb | 4 +- .../lib/src/l10n/cupertino_be.arb | 4 +- .../lib/src/l10n/cupertino_bg.arb | 4 +- .../lib/src/l10n/cupertino_bn.arb | 4 +- .../lib/src/l10n/cupertino_bs.arb | 6 +- .../lib/src/l10n/cupertino_ca.arb | 4 +- .../lib/src/l10n/cupertino_cs.arb | 4 +- .../lib/src/l10n/cupertino_cy.arb | 4 +- .../lib/src/l10n/cupertino_da.arb | 4 +- .../lib/src/l10n/cupertino_de.arb | 4 +- .../lib/src/l10n/cupertino_el.arb | 4 +- .../lib/src/l10n/cupertino_en_AU.arb | 3 + .../lib/src/l10n/cupertino_en_GB.arb | 3 + .../lib/src/l10n/cupertino_en_IE.arb | 3 + .../lib/src/l10n/cupertino_en_IN.arb | 3 + .../lib/src/l10n/cupertino_en_NZ.arb | 3 + .../lib/src/l10n/cupertino_en_SG.arb | 3 + .../lib/src/l10n/cupertino_en_ZA.arb | 3 + .../lib/src/l10n/cupertino_es.arb | 4 +- .../lib/src/l10n/cupertino_es_419.arb | 5 +- .../lib/src/l10n/cupertino_es_AR.arb | 5 +- .../lib/src/l10n/cupertino_es_BO.arb | 5 +- .../lib/src/l10n/cupertino_es_CL.arb | 5 +- .../lib/src/l10n/cupertino_es_CO.arb | 5 +- .../lib/src/l10n/cupertino_es_CR.arb | 5 +- .../lib/src/l10n/cupertino_es_DO.arb | 5 +- .../lib/src/l10n/cupertino_es_EC.arb | 5 +- .../lib/src/l10n/cupertino_es_GT.arb | 5 +- .../lib/src/l10n/cupertino_es_HN.arb | 5 +- .../lib/src/l10n/cupertino_es_MX.arb | 5 +- .../lib/src/l10n/cupertino_es_NI.arb | 5 +- .../lib/src/l10n/cupertino_es_PA.arb | 5 +- .../lib/src/l10n/cupertino_es_PE.arb | 5 +- .../lib/src/l10n/cupertino_es_PR.arb | 5 +- .../lib/src/l10n/cupertino_es_PY.arb | 5 +- .../lib/src/l10n/cupertino_es_SV.arb | 5 +- .../lib/src/l10n/cupertino_es_US.arb | 5 +- .../lib/src/l10n/cupertino_es_UY.arb | 5 +- .../lib/src/l10n/cupertino_es_VE.arb | 5 +- .../lib/src/l10n/cupertino_et.arb | 4 +- .../lib/src/l10n/cupertino_eu.arb | 6 +- .../lib/src/l10n/cupertino_fa.arb | 4 +- .../lib/src/l10n/cupertino_fi.arb | 4 +- .../lib/src/l10n/cupertino_fil.arb | 6 +- .../lib/src/l10n/cupertino_fr.arb | 4 +- .../lib/src/l10n/cupertino_fr_CA.arb | 2 + .../lib/src/l10n/cupertino_gl.arb | 6 +- .../lib/src/l10n/cupertino_gsw.arb | 4 +- .../lib/src/l10n/cupertino_gu.arb | 4 +- .../lib/src/l10n/cupertino_he.arb | 4 +- .../lib/src/l10n/cupertino_hi.arb | 4 +- .../lib/src/l10n/cupertino_hr.arb | 6 +- .../lib/src/l10n/cupertino_hu.arb | 6 +- .../lib/src/l10n/cupertino_hy.arb | 4 +- .../lib/src/l10n/cupertino_id.arb | 4 +- .../lib/src/l10n/cupertino_is.arb | 4 +- .../lib/src/l10n/cupertino_it.arb | 6 +- .../lib/src/l10n/cupertino_ja.arb | 6 +- .../lib/src/l10n/cupertino_ka.arb | 4 +- .../lib/src/l10n/cupertino_kk.arb | 4 +- .../lib/src/l10n/cupertino_km.arb | 6 +- .../lib/src/l10n/cupertino_kn.arb | 4 +- .../lib/src/l10n/cupertino_ko.arb | 4 +- .../lib/src/l10n/cupertino_ky.arb | 4 +- .../lib/src/l10n/cupertino_lo.arb | 4 +- .../lib/src/l10n/cupertino_lt.arb | 4 +- .../lib/src/l10n/cupertino_lv.arb | 4 +- .../lib/src/l10n/cupertino_mk.arb | 4 +- .../lib/src/l10n/cupertino_ml.arb | 6 +- .../lib/src/l10n/cupertino_mn.arb | 4 +- .../lib/src/l10n/cupertino_mr.arb | 4 +- .../lib/src/l10n/cupertino_ms.arb | 6 +- .../lib/src/l10n/cupertino_my.arb | 4 +- .../lib/src/l10n/cupertino_nb.arb | 4 +- .../lib/src/l10n/cupertino_ne.arb | 4 +- .../lib/src/l10n/cupertino_nl.arb | 4 +- .../lib/src/l10n/cupertino_no.arb | 4 +- .../lib/src/l10n/cupertino_or.arb | 4 +- .../lib/src/l10n/cupertino_pa.arb | 4 +- .../lib/src/l10n/cupertino_pl.arb | 8 +- .../lib/src/l10n/cupertino_pt.arb | 8 +- .../lib/src/l10n/cupertino_pt_PT.arb | 3 + .../lib/src/l10n/cupertino_ro.arb | 4 +- .../lib/src/l10n/cupertino_ru.arb | 4 +- .../lib/src/l10n/cupertino_si.arb | 4 +- .../lib/src/l10n/cupertino_sk.arb | 4 +- .../lib/src/l10n/cupertino_sl.arb | 4 +- .../lib/src/l10n/cupertino_sq.arb | 4 +- .../lib/src/l10n/cupertino_sr.arb | 4 +- .../lib/src/l10n/cupertino_sr_Latn.arb | 2 + .../lib/src/l10n/cupertino_sv.arb | 4 +- .../lib/src/l10n/cupertino_sw.arb | 4 +- .../lib/src/l10n/cupertino_ta.arb | 4 +- .../lib/src/l10n/cupertino_te.arb | 4 +- .../lib/src/l10n/cupertino_th.arb | 4 +- .../lib/src/l10n/cupertino_tl.arb | 6 +- .../lib/src/l10n/cupertino_tr.arb | 4 +- .../lib/src/l10n/cupertino_uk.arb | 4 +- .../lib/src/l10n/cupertino_ur.arb | 4 +- .../lib/src/l10n/cupertino_uz.arb | 6 +- .../lib/src/l10n/cupertino_vi.arb | 4 +- .../lib/src/l10n/cupertino_zh.arb | 4 +- .../lib/src/l10n/cupertino_zh_HK.arb | 3 + .../lib/src/l10n/cupertino_zh_TW.arb | 2 + .../lib/src/l10n/cupertino_zu.arb | 4 +- .../generated_cupertino_localizations.dart | 660 ++++-- .../generated_material_localizations.dart | 1802 +++++++++++------ .../lib/src/l10n/material_af.arb | 16 +- .../lib/src/l10n/material_am.arb | 24 +- .../lib/src/l10n/material_ar.arb | 16 +- .../lib/src/l10n/material_as.arb | 16 +- .../lib/src/l10n/material_az.arb | 14 +- .../lib/src/l10n/material_be.arb | 16 +- .../lib/src/l10n/material_bg.arb | 16 +- .../lib/src/l10n/material_bn.arb | 16 +- .../lib/src/l10n/material_bs.arb | 16 +- .../lib/src/l10n/material_ca.arb | 16 +- .../lib/src/l10n/material_cs.arb | 16 +- .../lib/src/l10n/material_cy.arb | 16 +- .../lib/src/l10n/material_da.arb | 14 +- .../lib/src/l10n/material_de.arb | 14 +- .../lib/src/l10n/material_el.arb | 14 +- .../lib/src/l10n/material_en_AU.arb | 9 + .../lib/src/l10n/material_en_GB.arb | 9 + .../lib/src/l10n/material_en_IE.arb | 9 + .../lib/src/l10n/material_en_IN.arb | 9 + .../lib/src/l10n/material_en_NZ.arb | 9 + .../lib/src/l10n/material_en_SG.arb | 9 + .../lib/src/l10n/material_en_ZA.arb | 9 + .../lib/src/l10n/material_es.arb | 14 +- .../lib/src/l10n/material_es_419.arb | 9 + .../lib/src/l10n/material_es_AR.arb | 9 + .../lib/src/l10n/material_es_BO.arb | 9 + .../lib/src/l10n/material_es_CL.arb | 9 + .../lib/src/l10n/material_es_CO.arb | 9 + .../lib/src/l10n/material_es_CR.arb | 9 + .../lib/src/l10n/material_es_DO.arb | 9 + .../lib/src/l10n/material_es_EC.arb | 9 + .../lib/src/l10n/material_es_GT.arb | 9 + .../lib/src/l10n/material_es_HN.arb | 9 + .../lib/src/l10n/material_es_MX.arb | 9 + .../lib/src/l10n/material_es_NI.arb | 9 + .../lib/src/l10n/material_es_PA.arb | 9 + .../lib/src/l10n/material_es_PE.arb | 9 + .../lib/src/l10n/material_es_PR.arb | 9 + .../lib/src/l10n/material_es_PY.arb | 9 + .../lib/src/l10n/material_es_SV.arb | 9 + .../lib/src/l10n/material_es_US.arb | 9 + .../lib/src/l10n/material_es_UY.arb | 9 + .../lib/src/l10n/material_es_VE.arb | 9 + .../lib/src/l10n/material_et.arb | 16 +- .../lib/src/l10n/material_eu.arb | 14 +- .../lib/src/l10n/material_fa.arb | 20 +- .../lib/src/l10n/material_fi.arb | 14 +- .../lib/src/l10n/material_fil.arb | 16 +- .../lib/src/l10n/material_fr.arb | 16 +- .../lib/src/l10n/material_fr_CA.arb | 8 + .../lib/src/l10n/material_gl.arb | 16 +- .../lib/src/l10n/material_gsw.arb | 14 +- .../lib/src/l10n/material_gu.arb | 16 +- .../lib/src/l10n/material_he.arb | 16 +- .../lib/src/l10n/material_hi.arb | 16 +- .../lib/src/l10n/material_hr.arb | 18 +- .../lib/src/l10n/material_hu.arb | 16 +- .../lib/src/l10n/material_hy.arb | 16 +- .../lib/src/l10n/material_id.arb | 14 +- .../lib/src/l10n/material_is.arb | 16 +- .../lib/src/l10n/material_it.arb | 18 +- .../lib/src/l10n/material_ja.arb | 16 +- .../lib/src/l10n/material_ka.arb | 14 +- .../lib/src/l10n/material_kk.arb | 14 +- .../lib/src/l10n/material_km.arb | 18 +- .../lib/src/l10n/material_kn.arb | 16 +- .../lib/src/l10n/material_ko.arb | 16 +- .../lib/src/l10n/material_ky.arb | 14 +- .../lib/src/l10n/material_lo.arb | 14 +- .../lib/src/l10n/material_lt.arb | 14 +- .../lib/src/l10n/material_lv.arb | 14 +- .../lib/src/l10n/material_mk.arb | 18 +- .../lib/src/l10n/material_ml.arb | 18 +- .../lib/src/l10n/material_mn.arb | 16 +- .../lib/src/l10n/material_mr.arb | 14 +- .../lib/src/l10n/material_ms.arb | 18 +- .../lib/src/l10n/material_my.arb | 16 +- .../lib/src/l10n/material_nb.arb | 16 +- .../lib/src/l10n/material_ne.arb | 18 +- .../lib/src/l10n/material_nl.arb | 14 +- .../lib/src/l10n/material_no.arb | 14 +- .../lib/src/l10n/material_or.arb | 16 +- .../lib/src/l10n/material_pa.arb | 16 +- .../lib/src/l10n/material_pl.arb | 18 +- .../lib/src/l10n/material_pt.arb | 20 +- .../lib/src/l10n/material_pt_PT.arb | 9 + .../lib/src/l10n/material_ro.arb | 14 +- .../lib/src/l10n/material_ru.arb | 14 +- .../lib/src/l10n/material_si.arb | 16 +- .../lib/src/l10n/material_sk.arb | 16 +- .../lib/src/l10n/material_sl.arb | 16 +- .../lib/src/l10n/material_sq.arb | 16 +- .../lib/src/l10n/material_sr.arb | 16 +- .../lib/src/l10n/material_sr_Latn.arb | 8 + .../lib/src/l10n/material_sv.arb | 14 +- .../lib/src/l10n/material_sw.arb | 14 +- .../lib/src/l10n/material_ta.arb | 16 +- .../lib/src/l10n/material_te.arb | 16 +- .../lib/src/l10n/material_th.arb | 14 +- .../lib/src/l10n/material_tl.arb | 16 +- .../lib/src/l10n/material_tr.arb | 16 +- .../lib/src/l10n/material_uk.arb | 16 +- .../lib/src/l10n/material_ur.arb | 16 +- .../lib/src/l10n/material_uz.arb | 16 +- .../lib/src/l10n/material_vi.arb | 14 +- .../lib/src/l10n/material_zh.arb | 16 +- .../lib/src/l10n/material_zh_HK.arb | 9 + .../lib/src/l10n/material_zh_TW.arb | 8 + .../lib/src/l10n/material_zu.arb | 14 +- .../test/cupertino/translations_test.dart | 54 + 221 files changed, 2914 insertions(+), 1576 deletions(-) diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb index 94d7a4ed7cb99..63fdff3a35bb3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Oortjie $tabIndex van $tabCount", "modalBarrierDismissLabel": "Maak toe", "searchTextFieldPlaceholderLabel": "Soek", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Geen plaasvervangers gevind nie", + "menuDismissLabel": "Maak kieslys toe", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb index 3e01785574cbd..8868f33d05943 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "ትር $tabIndex ከ$tabCount", "modalBarrierDismissLabel": "አሰናብት", "searchTextFieldPlaceholderLabel": "ፍለጋ", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "ምንም ተተኪዎች አልተገኙም", + "menuDismissLabel": "ምናሌን አሰናብት", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb index f4cf67ea05f1e..94f8b4f694a4f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb @@ -42,8 +42,8 @@ "tabSemanticsLabel": "علامة التبويب $tabIndex من $tabCount", "modalBarrierDismissLabel": "رفض", "searchTextFieldPlaceholderLabel": "بحث", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "لم يتم العثور على بدائل", + "menuDismissLabel": "إغلاق القائمة", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb index 09fcc0fcd4c82..66e5a29399e8f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount টা টেবৰ $tabIndex নম্বৰটো", "modalBarrierDismissLabel": "অগ্ৰাহ্য কৰক", "searchTextFieldPlaceholderLabel": "সন্ধান কৰক", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "এইটোৰ সলনি ব্যৱহাৰ কৰিব পৰা শব্দ পোৱা নগ’ল", + "menuDismissLabel": "অগ্ৰাহ্য কৰাৰ মেনু", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb index c3335169b91c1..6cbbc9c80246a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex/$tabCount", "modalBarrierDismissLabel": "İmtina edin", "searchTextFieldPlaceholderLabel": "Axtarın", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Əvəzləmə Tapılmadı", + "menuDismissLabel": "Menyunu qapadın", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb index 5ec31f0feadaf..1eea20f397934 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "Укладка $tabIndex з $tabCount", "modalBarrierDismissLabel": "Адхіліць", "searchTextFieldPlaceholderLabel": "Пошук", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Замен не знойдзена", + "menuDismissLabel": "Закрыць меню", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb index 4b5719a451f66..0612ebb1c26a8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Раздел $tabIndex от $tabCount", "modalBarrierDismissLabel": "Отхвърляне", "searchTextFieldPlaceholderLabel": "Търсене", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Не бяха намерени замествания", + "menuDismissLabel": "Отхвърляне на менюто", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb index bcdd58d9bb016..7dacc3e55ee8f 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount-এর মধ্যে $tabIndex নম্বর ট্যাব", "modalBarrierDismissLabel": "খারিজ করুন", "searchTextFieldPlaceholderLabel": "সার্চ করুন", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "কোনও বিকল্প বানান দেখানো হয়নি", + "menuDismissLabel": "বাতিল করার মেনু", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb index d7167c0925dd7..1f7f39829c9ae 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb @@ -27,8 +27,8 @@ "tabSemanticsLabel": "Kartica $tabIndex od $tabCount", "modalBarrierDismissLabel": "Odbaci", "searchTextFieldPlaceholderLabel": "Pretraživanje", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Nije pronađena nijedna zamjena", + "menuDismissLabel": "Odbacivanje menija", + "lookUpButtonLabel": "Pogled prema gore", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb index a8ee35a10a8f9..9e1ca020a3589 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Pestanya $tabIndex de $tabCount", "modalBarrierDismissLabel": "Ignora", "searchTextFieldPlaceholderLabel": "Cerca", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "No s'ha trobat cap substitució", + "menuDismissLabel": "Ignora el menú", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb index 472815c54ab89..4ff2ecea1f904 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "Karta $tabIndex z $tabCount", "modalBarrierDismissLabel": "Zavřít", "searchTextFieldPlaceholderLabel": "Hledat", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Žádná nahrazení nenalezena", + "menuDismissLabel": "Zavřít nabídku", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb index 506fec1c1173a..e2fb99160786a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb @@ -42,8 +42,8 @@ "selectAllButtonLabel": "Dewis y Cyfan", "searchTextFieldPlaceholderLabel": "Chwilio", "modalBarrierDismissLabel": "Diystyru", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Dim Ailosodiadau wedi'u Canfod", + "menuDismissLabel": "Diystyru'r ddewislen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb index a0272a2c30973..be0462ef5dc19 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Fane $tabIndex af $tabCount", "modalBarrierDismissLabel": "Afvis", "searchTextFieldPlaceholderLabel": "Søg", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Der blev ikke fundet nogen erstatninger", + "menuDismissLabel": "Luk menu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb index 1a2a336c4e147..e9e966833b674 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex von $tabCount", "modalBarrierDismissLabel": "Schließen", "searchTextFieldPlaceholderLabel": "Suche", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Keine Ersetzungen gefunden", + "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb index 65c8a97f0922b..b8760eb5fb2e5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Καρτέλα $tabIndex από $tabCount", "modalBarrierDismissLabel": "Παράβλεψη", "searchTextFieldPlaceholderLabel": "Αναζήτηση", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Δεν βρέθηκαν αντικαταστάσεις", + "menuDismissLabel": "Παράβλεψη μενού", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_AU.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_AU.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_AU.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_AU.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_GB.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_GB.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_GB.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_GB.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_IE.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_IE.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_IE.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_IE.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_IN.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_IN.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_IN.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_IN.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_NZ.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_NZ.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_NZ.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_NZ.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_SG.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_SG.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_SG.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_SG.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en_ZA.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en_ZA.arb index a9fac71f82f0f..c0780fe62b876 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en_ZA.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en_ZA.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Look up", + "noSpellCheckReplacementsLabel": "No replacements found", + "menuDismissLabel": "Dismiss menu", "searchTextFieldPlaceholderLabel": "Search", "tabSemanticsLabel": "Tab $tabIndex of $tabCount", "datePickerHourSemanticsLabelOne": "$hour o'clock", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb index f71e5ff039147..8e56f84da6486 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "modalBarrierDismissLabel": "Cerrar", "searchTextFieldPlaceholderLabel": "Buscar", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "No se ha encontrado ninguna sustitución", + "menuDismissLabel": "Cerrar menú", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_419.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_419.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_419.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_419.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_AR.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_AR.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_AR.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_AR.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_BO.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_BO.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_BO.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_BO.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_CL.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_CL.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_CL.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_CL.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_CO.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_CO.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_CO.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_CO.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_CR.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_CR.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_CR.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_CR.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_DO.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_DO.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_DO.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_DO.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_EC.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_EC.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_EC.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_EC.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_GT.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_GT.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_GT.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_GT.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_HN.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_HN.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_HN.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_HN.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_MX.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_MX.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_MX.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_MX.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_NI.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_NI.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_NI.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_NI.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PA.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PA.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PA.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PA.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PE.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PE.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PE.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PE.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PR.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PR.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PR.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PR.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PY.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PY.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_PY.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_PY.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_SV.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_SV.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_SV.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_SV.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_US.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_US.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_US.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_US.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_UY.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_UY.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_UY.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_UY.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es_VE.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es_VE.arb index 272e2aea1a2c3..b716dc2b5bb91 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es_VE.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es_VE.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Mirar hacia arriba", + "noSpellCheckReplacementsLabel": "No se encontraron reemplazos", + "menuDismissLabel": "Descartar menú", "searchTextFieldPlaceholderLabel": "Buscar", "tabSemanticsLabel": "Pestaña $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour en punto", @@ -20,6 +23,6 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Pegar", - "selectAllButtonLabel": "Seleccionar todo", + "selectAllButtonLabel": "Seleccionar todos", "modalBarrierDismissLabel": "Descartar" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb index ff2040a479a4d..a9d95e26670a6 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabIndex. vaheleht $tabCount-st", "modalBarrierDismissLabel": "Loobu", "searchTextFieldPlaceholderLabel": "Otsige", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Asendusi ei leitud", + "menuDismissLabel": "Sulge menüü", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb index 114793a757f53..486038ec12388 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb @@ -18,12 +18,12 @@ "cutButtonLabel": "Ebaki", "copyButtonLabel": "Kopiatu", "pasteButtonLabel": "Itsatsi", - "selectAllButtonLabel": "Hautatu guztiak", + "selectAllButtonLabel": "Hautatu dena", "tabSemanticsLabel": "$tabIndex/$tabCount fitxa", "modalBarrierDismissLabel": "Baztertu", "searchTextFieldPlaceholderLabel": "Bilatu", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Ez da aurkitu ordezteko hitzik", + "menuDismissLabel": "Baztertu menua", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb index 11f9426338725..9e7746e8e7ee8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "برگه $tabIndex از $tabCount", "modalBarrierDismissLabel": "نپذیرفتن", "searchTextFieldPlaceholderLabel": "جستجو", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "جایگزینی پیدا نشد", + "menuDismissLabel": "بستن منو", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb index bfbedbc5668b9..f60f9befe4ad0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Välilehti $tabIndex kautta $tabCount", "modalBarrierDismissLabel": "Ohita", "searchTextFieldPlaceholderLabel": "Hae", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Korvaavia sanoja ei löydy", + "menuDismissLabel": "Hylkää valikko", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb index d93a590c16b4b..5a3169db878f2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex ng $tabCount", "modalBarrierDismissLabel": "I-dismiss", "searchTextFieldPlaceholderLabel": "Hanapin", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Walang Nahanap na Kapalit", + "menuDismissLabel": "I-dismiss ang menu", + "lookUpButtonLabel": "Tumingin sa Itaas", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb index 437984e92a8a7..c2f57d3c634b4 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Onglet $tabIndex sur $tabCount", "modalBarrierDismissLabel": "Ignorer", "searchTextFieldPlaceholderLabel": "Rechercher", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Aucun remplacement trouvé", + "menuDismissLabel": "Fermer le menu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fr_CA.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fr_CA.arb index e127661efbd4e..f86963fca218a 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fr_CA.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fr_CA.arb @@ -1,4 +1,6 @@ { + "noSpellCheckReplacementsLabel": "Aucun remplacement trouvé", + "menuDismissLabel": "Ignorer le menu", "searchTextFieldPlaceholderLabel": "Rechercher", "tabSemanticsLabel": "Onglet $tabIndex sur $tabCount", "datePickerHourSemanticsLabelOne": "$hour heure", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb index 481510c245a6b..4abf412a8b200 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Pestana $tabIndex de $tabCount", "modalBarrierDismissLabel": "Ignorar", "searchTextFieldPlaceholderLabel": "Fai unha busca", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Non se encontrou ningunha substitución", + "menuDismissLabel": "Pechar menú", + "lookUpButtonLabel": "Mirar cara arriba", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb index 1a2a336c4e147..e9e966833b674 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex von $tabCount", "modalBarrierDismissLabel": "Schließen", "searchTextFieldPlaceholderLabel": "Suche", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Keine Ersetzungen gefunden", + "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb index 952f10ad3db81..b36d349787617 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCountમાંથી $tabIndex ટૅબ", "modalBarrierDismissLabel": "છોડી દો", "searchTextFieldPlaceholderLabel": "શોધો", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "બદલવા માટે કોઈ શબ્દ મળ્યો નથી", + "menuDismissLabel": "મેનૂ છોડી દો", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb index 666a3f49ccc19..1fc4c3fb38481 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "כרטיסייה $tabIndex מתוך $tabCount", "modalBarrierDismissLabel": "סגירה", "searchTextFieldPlaceholderLabel": "חיפוש", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "לא נמצאו חלופות", + "menuDismissLabel": "סגירת התפריט", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb index 9bff606750884..bf2c4efca730b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount का टैब $tabIndex", "modalBarrierDismissLabel": "खारिज करें", "searchTextFieldPlaceholderLabel": "खोजें", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "सही वर्तनी वाला कोई शब्द नहीं मिला", + "menuDismissLabel": "मेन्यू खारिज करें", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb index ac04d54e64e64..fbacf98ca93c3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb @@ -27,8 +27,8 @@ "tabSemanticsLabel": "Kartica $tabIndex od $tabCount", "modalBarrierDismissLabel": "Odbaci", "searchTextFieldPlaceholderLabel": "Pretraživanje", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Nema pronađenih zamjena", + "menuDismissLabel": "Odbacivanje izbornika", + "lookUpButtonLabel": "Pogled prema gore", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb index e9de9a1e04777..df30e15e3cc24 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount/$tabIndex. lap", "modalBarrierDismissLabel": "Elvetés", "searchTextFieldPlaceholderLabel": "Keresés", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Nem található javítás", + "menuDismissLabel": "Menü bezárása", + "lookUpButtonLabel": "Felfelé nézés", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb index 56f6b5f4c7155..24717182f339d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Ներդիր $tabIndex՝ $tabCount-ից", "modalBarrierDismissLabel": "Փակել", "searchTextFieldPlaceholderLabel": "Որոնում", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Փոխարինումներ չեն գտնվել", + "menuDismissLabel": "Փակել ընտրացանկը", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb index 6b94a0f6d2bff..f0fa3b0184e67 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex dari $tabCount", "modalBarrierDismissLabel": "Tutup", "searchTextFieldPlaceholderLabel": "Telusuri", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Penggantian Tidak Ditemukan", + "menuDismissLabel": "Tutup menu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb index bc77d218be1a3..110a1f4c1bd7c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Flipi $tabIndex af $tabCount", "modalBarrierDismissLabel": "Hunsa", "searchTextFieldPlaceholderLabel": "Leit", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Engir staðgenglar fundust", + "menuDismissLabel": "Loka valmynd", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb index 91238cb5974bc..d3279d1f8af06 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Scheda $tabIndex di $tabCount", "modalBarrierDismissLabel": "Ignora", "searchTextFieldPlaceholderLabel": "Cerca", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Nessuna sostituzione trovata", + "menuDismissLabel": "Ignora menu", + "lookUpButtonLabel": "Cerca", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb index adc131a0e968f..8fe4d8254fcd5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "タブ: $tabIndex/$tabCount", "modalBarrierDismissLabel": "閉じる", "searchTextFieldPlaceholderLabel": "検索", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "置き換えるものがありません", + "menuDismissLabel": "メニューを閉じる", + "lookUpButtonLabel": "調べる", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb index 595f23b90aedd..a0c5f673c93ba 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "ჩანართი $tabIndex / $tabCount-დან", "modalBarrierDismissLabel": "დახურვა", "searchTextFieldPlaceholderLabel": "ძიება", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "ჩანაცვლება არ მოიძებნა", + "menuDismissLabel": "მენიუს უარყოფა", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb index 55fa59f72863f..41ab324684ccd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Қойынды: $tabIndex/$tabCount", "modalBarrierDismissLabel": "Жабу", "searchTextFieldPlaceholderLabel": "Іздеу", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Ауыстыратын ешнәрсе табылмады.", + "menuDismissLabel": "Мәзірді жабу", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb index bb1905a163c14..3d5ab7f762f6e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "ផ្ទាំងទី $tabIndex នៃ $tabCount", "modalBarrierDismissLabel": "ច្រាន​ចោល", "searchTextFieldPlaceholderLabel": "ស្វែងរក", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "រកមិនឃើញ​ការជំនួសទេ", + "menuDismissLabel": "ច្រានចោល​ម៉ឺនុយ", + "lookUpButtonLabel": "រកមើល", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb index 8ead9138ac398..df58925efc06b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb @@ -22,8 +22,8 @@ "modalBarrierDismissLabel": "\u0cb5\u0c9c\u0cbe\u0c97\u0cca\u0cb3\u0cbf\u0cb8\u0cbf", "tabSemanticsLabel": "\u0024\u0074\u0061\u0062\u0043\u006f\u0075\u006e\u0074\u0020\u0cb0\u0cb2\u0ccd\u0cb2\u0cbf\u0ca8\u0020\u0024\u0074\u0061\u0062\u0049\u006e\u0064\u0065\u0078\u0020\u0c9f\u0ccd\u0caf\u0cbe\u0cac\u0ccd", "searchTextFieldPlaceholderLabel": "\u0cb9\u0cc1\u0ca1\u0cc1\u0c95\u0cbf", - "noSpellCheckReplacementsLabel": "\u004e\u006f\u0020\u0052\u0065\u0070\u006c\u0061\u0063\u0065\u006d\u0065\u006e\u0074\u0073\u0020\u0046\u006f\u0075\u006e\u0064", - "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075", + "noSpellCheckReplacementsLabel": "\u0caf\u0cbe\u0cb5\u0cc1\u0ca6\u0cc7\u0020\u0cac\u0ca6\u0cb2\u0cbe\u0cb5\u0ca3\u0cc6\u0c97\u0cb3\u0cc1\u0020\u0c95\u0c82\u0ca1\u0cc1\u0cac\u0c82\u0ca6\u0cbf\u0cb2\u0ccd\u0cb2", + "menuDismissLabel": "\u0cae\u0cc6\u0ca8\u0cc1\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0cb5\u0c9c\u0cbe\u0c97\u0cc6\u0cc2\u0cb3\u0cbf\u0cb8\u0cbf", "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070", "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb index 01ddb986283b9..e2675a47012f4 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "탭 $tabCount개 중 $tabIndex번째", "modalBarrierDismissLabel": "닫기", "searchTextFieldPlaceholderLabel": "검색", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "수정사항 없음", + "menuDismissLabel": "메뉴 닫기", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb index 7943ddd689ede..c519944a5f6bb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount ичинен $tabIndex-өтмөк", "modalBarrierDismissLabel": "Жабуу", "searchTextFieldPlaceholderLabel": "Издөө", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Алмаштыруу үчүн сөз табылган жок", + "menuDismissLabel": "Менюну жабуу", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb index 0f9cfbff57475..ec0da5f846749 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "ແຖບທີ $tabIndex ຈາກທັງໝົດ $tabCount", "modalBarrierDismissLabel": "ປິດໄວ້", "searchTextFieldPlaceholderLabel": "ຊອກຫາ", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "ບໍ່ພົບການແທນທີ່", + "menuDismissLabel": "ປິດເມນູ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb index 8b05726e0f463..1d292f3af76af 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "$tabIndex skirtukas iš $tabCount", "modalBarrierDismissLabel": "Atsisakyti", "searchTextFieldPlaceholderLabel": "Paieška", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Nerasta jokių pakeitimų", + "menuDismissLabel": "Atsisakyti meniu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb index 8fd972f8fe312..032d59fc39e12 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb @@ -27,8 +27,8 @@ "tabSemanticsLabel": "$tabIndex. cilne no $tabCount", "modalBarrierDismissLabel": "Nerādīt", "searchTextFieldPlaceholderLabel": "Meklēšana", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Netika atrasts neviens vārds aizstāšanai", + "menuDismissLabel": "Nerādīt izvēlni", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb index 6a4318fcf832e..12221747737b3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Картичка $tabIndex од $tabCount", "modalBarrierDismissLabel": "Отфрли", "searchTextFieldPlaceholderLabel": "Пребарувајте", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Не се најдени заменски зборови", + "menuDismissLabel": "Отфрлете го менито", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb index f1a077d4111e4..d08cabfcd6d53 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount ടാബിൽ $tabIndex-ാമത്തേത്", "modalBarrierDismissLabel": "നിരസിക്കുക", "searchTextFieldPlaceholderLabel": "തിരയുക", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "റീപ്ലേസ്‌മെന്റുകളൊന്നും കണ്ടെത്തിയില്ല", + "menuDismissLabel": "മെനു ഡിസ്മിസ് ചെയ്യുക", + "lookUpButtonLabel": "മുകളിലേക്ക് നോക്കുക", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb index c980229358da2..165bfc7b780a5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount-н $tabIndex-р таб", "modalBarrierDismissLabel": "Үл хэрэгсэх", "searchTextFieldPlaceholderLabel": "Хайх", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Ямар ч орлуулалт олдсонгүй", + "menuDismissLabel": "Цэсийг хаах", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb index 11cdfb2bcebe6..0f73502e156b1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount पैकी $tabIndex टॅब", "modalBarrierDismissLabel": "डिसमिस करा", "searchTextFieldPlaceholderLabel": "शोधा", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "कोणतेही बदल आढळले नाहीत", + "menuDismissLabel": "मेनू डिसमिस करा", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb index 87c839cfe6695..46cfe286821f0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex daripada $tabCount", "modalBarrierDismissLabel": "Tolak", "searchTextFieldPlaceholderLabel": "Cari", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Tiada Penggantian Ditemukan", + "menuDismissLabel": "Ketepikan menu", + "lookUpButtonLabel": "Lihat ke Atas", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb index bea64b6130084..da28217742deb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "တဘ် $tabCount ခုအနက် $tabIndex ခု", "modalBarrierDismissLabel": "ပယ်ရန်", "searchTextFieldPlaceholderLabel": "ရှာရန်", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "အစားထိုးမှုများ မတွေ့ပါ", + "menuDismissLabel": "မီနူးကိုပယ်ပါ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb index 03b48b0e7943d..042c9abb17524 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb @@ -22,8 +22,8 @@ "selectAllButtonLabel": "Velg alle", "modalBarrierDismissLabel": "Avvis", "searchTextFieldPlaceholderLabel": "Søk", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Fant ingen erstatninger", + "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb index d205f044aa6bd..cd5b3d0c5d209 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount मध्ये $tabIndex ट्याब", "modalBarrierDismissLabel": "खारेज गर्नुहोस्", "searchTextFieldPlaceholderLabel": "खोज्नुहोस्", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "बदल्नु पर्ने कुनै पनि कुरा भेटिएन", + "menuDismissLabel": "मेनु खारेज गर्नुहोस्", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb index 523e3f9f4b5d8..90e2b9c098006 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tabblad $tabIndex van $tabCount", "modalBarrierDismissLabel": "Sluiten", "searchTextFieldPlaceholderLabel": "Zoeken", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Geen vervangingen gevonden", + "menuDismissLabel": "Menu sluiten", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb index 03b48b0e7943d..042c9abb17524 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb @@ -22,8 +22,8 @@ "selectAllButtonLabel": "Velg alle", "modalBarrierDismissLabel": "Avvis", "searchTextFieldPlaceholderLabel": "Søk", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Fant ingen erstatninger", + "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb index c0065d3cce524..d978bab219ff5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCountର $tabIndex ଟାବ୍", "modalBarrierDismissLabel": "ଖାରଜ କରନ୍ତୁ", "searchTextFieldPlaceholderLabel": "ସନ୍ଧାନ କରନ୍ତୁ", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "କୌଣସି ରିପ୍ଲେସମେଣ୍ଟ ମିଳିଲା ନାହିଁ", + "menuDismissLabel": "ମେନୁ ଖାରଜ କରନ୍ତୁ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb index 22d75077719a1..9d7bc0bbf93a0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount ਵਿੱਚੋਂ $tabIndex ਟੈਬ", "modalBarrierDismissLabel": "ਖਾਰਜ ਕਰੋ", "searchTextFieldPlaceholderLabel": "ਖੋਜੋ", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "ਕੋਈ ਸੁਝਾਅ ਨਹੀਂ ਮਿਲਿਆ", + "menuDismissLabel": "ਮੀਨੂ ਖਾਰਜ ਕਰੋ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb index 689f5166a80d5..8beef78c9007e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb @@ -28,12 +28,12 @@ "cutButtonLabel": "Wytnij", "copyButtonLabel": "Kopiuj", "pasteButtonLabel": "Wklej", - "selectAllButtonLabel": "Zaznacz wszystko", + "selectAllButtonLabel": "Wybierz wszystkie", "tabSemanticsLabel": "Karta $tabIndex z $tabCount", "modalBarrierDismissLabel": "Zamknij", "searchTextFieldPlaceholderLabel": "Szukaj", - "noSpellCheckReplacementsLabel": "Nie znaleziono zastąpień", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Brak wyników zamieniania", + "menuDismissLabel": "Zamknij menu", + "lookUpButtonLabel": "Sprawdź", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb index 0a9b39e58b128..93dab0c53b3d3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb @@ -18,12 +18,12 @@ "cutButtonLabel": "Cortar", "copyButtonLabel": "Copiar", "pasteButtonLabel": "Colar", - "selectAllButtonLabel": "Selecionar tudo", + "selectAllButtonLabel": "Selecionar Tudo", "tabSemanticsLabel": "Guia $tabIndex de $tabCount", "modalBarrierDismissLabel": "Dispensar", "searchTextFieldPlaceholderLabel": "Pesquisar", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Nenhuma alternativa encontrada", + "menuDismissLabel": "Dispensar menu", + "lookUpButtonLabel": "Pesquisar", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pt_PT.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pt_PT.arb index 8b9610777212d..986e169d53cc4 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pt_PT.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pt_PT.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "Procurar", + "noSpellCheckReplacementsLabel": "Não foram encontradas substituições", + "menuDismissLabel": "Ignorar menu", "searchTextFieldPlaceholderLabel": "Pesquise", "tabSemanticsLabel": "Separador $tabIndex de $tabCount", "datePickerHourSemanticsLabelOne": "$hour hora", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb index 002be304894fe..ffd6a6015135c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb @@ -27,8 +27,8 @@ "tabSemanticsLabel": "Fila $tabIndex din $tabCount", "modalBarrierDismissLabel": "Închideți", "searchTextFieldPlaceholderLabel": "Căutați", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Nu s-au găsit înlocuiri", + "menuDismissLabel": "Respingeți meniul", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb index 284c0c269d243..6a5be8cd7af6c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "Вкладка $tabIndex из $tabCount", "modalBarrierDismissLabel": "Закрыть", "searchTextFieldPlaceholderLabel": "Поиск", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Варианты замены не найдены", + "menuDismissLabel": "Закрыть меню", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb index caa2ad12dba2c..6d36ab10c912c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "ටැබ $tabCount න් $tabIndex", "modalBarrierDismissLabel": "ඉවත ලන්න", "searchTextFieldPlaceholderLabel": "සෙවීම", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "ප්‍රතිස්ථාපන හමු නොවිණි", + "menuDismissLabel": "මෙනුව අස් කරන්න", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb index b113e8c6f5706..677cf0000896e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "Karta $tabIndex z $tabCount", "modalBarrierDismissLabel": "Odmietnuť", "searchTextFieldPlaceholderLabel": "Hľadať", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Nenašli sa žiadne náhrady", + "menuDismissLabel": "Zavrieť ponuku", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb index c65a8444caf20..35ac090121100 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "Zavihek $tabIndex od $tabCount", "modalBarrierDismissLabel": "Opusti", "searchTextFieldPlaceholderLabel": "Iskanje", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Ni zamenjav", + "menuDismissLabel": "Opusti meni", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb index cbc57e60595eb..60ac372323932 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Skeda $tabIndex nga $tabCount", "modalBarrierDismissLabel": "Hiq", "searchTextFieldPlaceholderLabel": "Kërko", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Nuk u gjetën zëvendësime", + "menuDismissLabel": "Hiqe menynë", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb index 87ff451e119dd..9333954f5624c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb @@ -27,8 +27,8 @@ "tabSemanticsLabel": "$tabIndex. картица од $tabCount", "modalBarrierDismissLabel": "Одбаци", "searchTextFieldPlaceholderLabel": "Претражите", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Нису пронађене замене", + "menuDismissLabel": "Одбаците мени", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sr_Latn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sr_Latn.arb index 3adac6d344c05..02c2db4f38591 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sr_Latn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sr_Latn.arb @@ -1,4 +1,6 @@ { + "noSpellCheckReplacementsLabel": "Nisu pronađene zamene", + "menuDismissLabel": "Odbacite meni", "searchTextFieldPlaceholderLabel": "Pretražite", "tabSemanticsLabel": "$tabIndex. kartica od $tabCount", "datePickerHourSemanticsLabelFew": "$hour sata", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb index ac79e55ad3d8b..710d31c53154b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Flik $tabIndex av $tabCount", "modalBarrierDismissLabel": "Stäng", "searchTextFieldPlaceholderLabel": "Sök", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Inga ersättningar hittades", + "menuDismissLabel": "Stäng menyn", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb index 2b7c122864865..9b6e6f46fdb31 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Kichupo cha $tabIndex kati ya $tabCount", "modalBarrierDismissLabel": "Ondoa", "searchTextFieldPlaceholderLabel": "Tafuta", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Hakuna Neno Mbadala Lilopatikana", + "menuDismissLabel": "Ondoa menyu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb index 52fa98d643649..f194d76ba4ced 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "தாவல் $tabIndex / $tabCount", "modalBarrierDismissLabel": "நிராகரிக்கும்", "searchTextFieldPlaceholderLabel": "தேடுக", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "மாற்று வார்த்தைகள் கிடைக்கவில்லை", + "menuDismissLabel": "மெனுவை மூடும்", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb index e474ded6c27f3..ff56d35e2ff76 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCountలో $tabIndexవ ట్యాబ్", "modalBarrierDismissLabel": "విస్మరించు", "searchTextFieldPlaceholderLabel": "సెర్చ్ చేయి", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "రీప్లేస్‌మెంట్‌లు ఏవీ కనుగొనబడలేదు", + "menuDismissLabel": "మెనూను తీసివేయండి", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb index c27d9861ec3d1..fa71c08e8efa1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "แท็บที่ $tabIndex จาก $tabCount", "modalBarrierDismissLabel": "ปิด", "searchTextFieldPlaceholderLabel": "ค้นหา", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "ไม่พบรายการแทนที่", + "menuDismissLabel": "ปิดเมนู", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb index d93a590c16b4b..5a3169db878f2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Tab $tabIndex ng $tabCount", "modalBarrierDismissLabel": "I-dismiss", "searchTextFieldPlaceholderLabel": "Hanapin", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Walang Nahanap na Kapalit", + "menuDismissLabel": "I-dismiss ang menu", + "lookUpButtonLabel": "Tumingin sa Itaas", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb index 33f1f935426b9..e199c28f20064 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Sekme $tabIndex/$tabCount", "modalBarrierDismissLabel": "Kapat", "searchTextFieldPlaceholderLabel": "Ara", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Yerine Kelime Bulunamadı", + "menuDismissLabel": "Menüyü kapat", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb index ebbc49d33eecb..6e5197872f241 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb @@ -32,8 +32,8 @@ "tabSemanticsLabel": "Вкладка $tabIndex з $tabCount", "modalBarrierDismissLabel": "Закрити", "searchTextFieldPlaceholderLabel": "Шукайте", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Замін не знайдено", + "menuDismissLabel": "Закрити меню", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb index 252b1ac93796f..bc46e9886c6c5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount میں سے $tabIndex ٹیب", "modalBarrierDismissLabel": "برخاست کریں", "searchTextFieldPlaceholderLabel": "تلاش کریں", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "کوئی تبدیلیاں نہیں ملیں", + "menuDismissLabel": "مینو برخاست کریں", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb index 1f6536d099fff..b2f27001f6a9d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "$tabCount varaqdan $tabIndex", "modalBarrierDismissLabel": "Yopish", "searchTextFieldPlaceholderLabel": "Qidiruv", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "noSpellCheckReplacementsLabel": "Almashtirish uchun soʻz topilmadi", + "menuDismissLabel": "Menyuni yopish", + "lookUpButtonLabel": "Tepaga qarang", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb index 7abb213939468..46d8e91db9aa7 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Thẻ $tabIndex/$tabCount", "modalBarrierDismissLabel": "Bỏ qua", "searchTextFieldPlaceholderLabel": "Tìm kiếm", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Không tìm thấy phương án thay thế", + "menuDismissLabel": "Đóng trình đơn", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb index 0d406c85263f8..d8ab8311f321d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "第 $tabIndex 个标签,共 $tabCount 个", "modalBarrierDismissLabel": "关闭", "searchTextFieldPlaceholderLabel": "搜索", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "找不到替换文字", + "menuDismissLabel": "关闭菜单", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh_HK.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh_HK.arb index 4f518784300e8..5cac05b161314 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh_HK.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh_HK.arb @@ -1,4 +1,7 @@ { + "lookUpButtonLabel": "查詢", + "noSpellCheckReplacementsLabel": "找不到替換字詞", + "menuDismissLabel": "閂選單", "searchTextFieldPlaceholderLabel": "搜尋", "tabSemanticsLabel": "$tabCount 個分頁中嘅第 $tabIndex 個", "datePickerHourSemanticsLabelOne": "$hour 點", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh_TW.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh_TW.arb index a3dd35c7cee2e..2c1190da6c0fc 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh_TW.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh_TW.arb @@ -1,4 +1,6 @@ { + "noSpellCheckReplacementsLabel": "找不到替代文字", + "menuDismissLabel": "關閉選單", "searchTextFieldPlaceholderLabel": "搜尋", "tabSemanticsLabel": "第 $tabIndex 個分頁標籤,共 $tabCount 個", "datePickerHourSemanticsLabelOne": "$hour 點", diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb index d391b3c9c5def..89eda26ed6230 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb @@ -22,8 +22,8 @@ "tabSemanticsLabel": "Ithebhu $tabIndex kwangu-$tabCount", "modalBarrierDismissLabel": "Cashisa", "searchTextFieldPlaceholderLabel": "Sesha", - "noSpellCheckReplacementsLabel": "No Replacements Found", - "menuDismissLabel": "Dismiss menu", + "noSpellCheckReplacementsLabel": "Akukho Okuzofakwa Esikhundleni Okutholakele", + "menuDismissLabel": "Chitha imenyu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index 12e56119dfb99..912ff7165b7fa 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -95,13 +95,13 @@ class CupertinoLocalizationAf extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Maak kieslys toe'; @override String get modalBarrierDismissLabel => 'Maak toe'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Geen plaasvervangers gevind nie'; @override String get pasteButtonLabel => 'Plak'; @@ -254,13 +254,13 @@ class CupertinoLocalizationAm extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ምናሌን አሰናብት'; @override String get modalBarrierDismissLabel => 'አሰናብት'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'ምንም ተተኪዎች አልተገኙም'; @override String get pasteButtonLabel => 'ለጥፍ'; @@ -413,13 +413,13 @@ class CupertinoLocalizationAr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'إغلاق القائمة'; @override String get modalBarrierDismissLabel => 'رفض'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'لم يتم العثور على بدائل'; @override String get pasteButtonLabel => 'لصق'; @@ -572,13 +572,13 @@ class CupertinoLocalizationAs extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'অগ্ৰাহ্য কৰাৰ মেনু'; @override String get modalBarrierDismissLabel => 'অগ্ৰাহ্য কৰক'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'এইটোৰ সলনি ব্যৱহাৰ কৰিব পৰা শব্দ পোৱা নগ’ল'; @override String get pasteButtonLabel => "পে'ষ্ট কৰক"; @@ -731,13 +731,13 @@ class CupertinoLocalizationAz extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menyunu qapadın'; @override String get modalBarrierDismissLabel => 'İmtina edin'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Əvəzləmə Tapılmadı'; @override String get pasteButtonLabel => 'Yerləşdirin'; @@ -890,13 +890,13 @@ class CupertinoLocalizationBe extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Закрыць меню'; @override String get modalBarrierDismissLabel => 'Адхіліць'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Замен не знойдзена'; @override String get pasteButtonLabel => 'Уставіць'; @@ -1049,13 +1049,13 @@ class CupertinoLocalizationBg extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Отхвърляне на менюто'; @override String get modalBarrierDismissLabel => 'Отхвърляне'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Не бяха намерени замествания'; @override String get pasteButtonLabel => 'Поставяне'; @@ -1208,13 +1208,13 @@ class CupertinoLocalizationBn extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'বাতিল করার মেনু'; @override String get modalBarrierDismissLabel => 'খারিজ করুন'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'কোনও বিকল্প বানান দেখানো হয়নি'; @override String get pasteButtonLabel => 'পেস্ট করুন'; @@ -1364,16 +1364,16 @@ class CupertinoLocalizationBs extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Pogled prema gore'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Odbacivanje menija'; @override String get modalBarrierDismissLabel => 'Odbaci'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nije pronađena nijedna zamjena'; @override String get pasteButtonLabel => 'Zalijepi'; @@ -1526,13 +1526,13 @@ class CupertinoLocalizationCa extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ignora el menú'; @override String get modalBarrierDismissLabel => 'Ignora'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => "No s'ha trobat cap substitució"; @override String get pasteButtonLabel => 'Enganxa'; @@ -1685,13 +1685,13 @@ class CupertinoLocalizationCs extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Zavřít nabídku'; @override String get modalBarrierDismissLabel => 'Zavřít'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Žádná nahrazení nenalezena'; @override String get pasteButtonLabel => 'Vložit'; @@ -1844,13 +1844,13 @@ class CupertinoLocalizationCy extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => "Diystyru'r ddewislen"; @override String get modalBarrierDismissLabel => 'Diystyru'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => "Dim Ailosodiadau wedi'u Canfod"; @override String get pasteButtonLabel => 'Gludo'; @@ -2003,13 +2003,13 @@ class CupertinoLocalizationDa extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Luk menu'; @override String get modalBarrierDismissLabel => 'Afvis'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Der blev ikke fundet nogen erstatninger'; @override String get pasteButtonLabel => 'Indsæt'; @@ -2162,13 +2162,13 @@ class CupertinoLocalizationDe extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menü schließen'; @override String get modalBarrierDismissLabel => 'Schließen'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Keine Ersetzungen gefunden'; @override String get pasteButtonLabel => 'Einsetzen'; @@ -2342,13 +2342,13 @@ class CupertinoLocalizationEl extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Παράβλεψη μενού'; @override String get modalBarrierDismissLabel => 'Παράβλεψη'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Δεν βρέθηκαν αντικαταστάσεις'; @override String get pasteButtonLabel => 'Επικόλληση'; @@ -2602,6 +2602,12 @@ class CupertinoLocalizationEnAu extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2650,6 +2656,12 @@ class CupertinoLocalizationEnGb extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2674,6 +2686,12 @@ class CupertinoLocalizationEnIe extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2698,6 +2716,12 @@ class CupertinoLocalizationEnIn extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2722,6 +2746,12 @@ class CupertinoLocalizationEnNz extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2746,6 +2776,12 @@ class CupertinoLocalizationEnSg extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2770,6 +2806,12 @@ class CupertinoLocalizationEnZa extends CupertinoLocalizationEn { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get noSpellCheckReplacementsLabel => 'No replacements found'; + @override String get datePickerDateOrderString => 'dmy'; @@ -2852,13 +2894,13 @@ class CupertinoLocalizationEs extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Cerrar menú'; @override String get modalBarrierDismissLabel => 'Cerrar'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'No se ha encontrado ninguna sustitución'; @override String get pasteButtonLabel => 'Pegar'; @@ -2953,6 +2995,15 @@ class CupertinoLocalizationEs419 extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -2965,6 +3016,9 @@ class CupertinoLocalizationEs419 extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -2986,6 +3040,15 @@ class CupertinoLocalizationEsAr extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -2998,6 +3061,9 @@ class CupertinoLocalizationEsAr extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3019,6 +3085,15 @@ class CupertinoLocalizationEsBo extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3031,6 +3106,9 @@ class CupertinoLocalizationEsBo extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3052,6 +3130,15 @@ class CupertinoLocalizationEsCl extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3064,6 +3151,9 @@ class CupertinoLocalizationEsCl extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3085,6 +3175,15 @@ class CupertinoLocalizationEsCo extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3097,6 +3196,9 @@ class CupertinoLocalizationEsCo extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3118,6 +3220,15 @@ class CupertinoLocalizationEsCr extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3130,6 +3241,9 @@ class CupertinoLocalizationEsCr extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3151,6 +3265,15 @@ class CupertinoLocalizationEsDo extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3163,6 +3286,9 @@ class CupertinoLocalizationEsDo extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3184,6 +3310,15 @@ class CupertinoLocalizationEsEc extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3196,6 +3331,9 @@ class CupertinoLocalizationEsEc extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3217,6 +3355,15 @@ class CupertinoLocalizationEsGt extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3229,6 +3376,9 @@ class CupertinoLocalizationEsGt extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3250,6 +3400,15 @@ class CupertinoLocalizationEsHn extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3262,6 +3421,9 @@ class CupertinoLocalizationEsHn extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3283,6 +3445,15 @@ class CupertinoLocalizationEsMx extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3295,6 +3466,9 @@ class CupertinoLocalizationEsMx extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3316,6 +3490,15 @@ class CupertinoLocalizationEsNi extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3328,6 +3511,9 @@ class CupertinoLocalizationEsNi extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3349,6 +3535,15 @@ class CupertinoLocalizationEsPa extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3361,6 +3556,9 @@ class CupertinoLocalizationEsPa extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3382,6 +3580,15 @@ class CupertinoLocalizationEsPe extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3394,6 +3601,9 @@ class CupertinoLocalizationEsPe extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3415,6 +3625,15 @@ class CupertinoLocalizationEsPr extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3427,6 +3646,9 @@ class CupertinoLocalizationEsPr extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3448,6 +3670,15 @@ class CupertinoLocalizationEsPy extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3460,6 +3691,9 @@ class CupertinoLocalizationEsPy extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3481,6 +3715,15 @@ class CupertinoLocalizationEsSv extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3493,6 +3736,9 @@ class CupertinoLocalizationEsSv extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3514,6 +3760,15 @@ class CupertinoLocalizationEsUs extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3526,6 +3781,9 @@ class CupertinoLocalizationEsUs extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3547,6 +3805,15 @@ class CupertinoLocalizationEsUy extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3559,6 +3826,9 @@ class CupertinoLocalizationEsUy extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3580,6 +3850,15 @@ class CupertinoLocalizationEsVe extends CupertinoLocalizationEs { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get noSpellCheckReplacementsLabel => 'No se encontraron reemplazos'; + + @override + String get menuDismissLabel => 'Descartar menú'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour en punto'; @@ -3592,6 +3871,9 @@ class CupertinoLocalizationEsVe extends CupertinoLocalizationEs { @override String get postMeridiemAbbreviation => 'p.m.'; + @override + String get selectAllButtonLabel => 'Seleccionar todos'; + @override String get modalBarrierDismissLabel => 'Descartar'; } @@ -3671,13 +3953,13 @@ class CupertinoLocalizationEt extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Sulge menüü'; @override String get modalBarrierDismissLabel => 'Loobu'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Asendusi ei leitud'; @override String get pasteButtonLabel => 'Kleebi'; @@ -3830,13 +4112,13 @@ class CupertinoLocalizationEu extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Baztertu menua'; @override String get modalBarrierDismissLabel => 'Baztertu'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Ez da aurkitu ordezteko hitzik'; @override String get pasteButtonLabel => 'Itsatsi'; @@ -3851,7 +4133,7 @@ class CupertinoLocalizationEu extends GlobalCupertinoLocalizations { String get searchWebButtonLabel => 'Search Web'; @override - String get selectAllButtonLabel => 'Hautatu guztiak'; + String get selectAllButtonLabel => 'Hautatu dena'; @override String get tabSemanticsLabelRaw => r'$tabIndex/$tabCount fitxa'; @@ -3989,13 +4271,13 @@ class CupertinoLocalizationFa extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'بستن منو'; @override String get modalBarrierDismissLabel => 'نپذیرفتن'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'جایگزینی پیدا نشد'; @override String get pasteButtonLabel => 'جای‌گذاری'; @@ -4148,13 +4430,13 @@ class CupertinoLocalizationFi extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Hylkää valikko'; @override String get modalBarrierDismissLabel => 'Ohita'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Korvaavia sanoja ei löydy'; @override String get pasteButtonLabel => 'Liitä'; @@ -4304,16 +4586,16 @@ class CupertinoLocalizationFil extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Tumingin sa Itaas'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'I-dismiss ang menu'; @override String get modalBarrierDismissLabel => 'I-dismiss'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Walang Nahanap na Kapalit'; @override String get pasteButtonLabel => 'I-paste'; @@ -4466,13 +4748,13 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Fermer le menu'; @override String get modalBarrierDismissLabel => 'Ignorer'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Aucun remplacement trouvé'; @override String get pasteButtonLabel => 'Coller'; @@ -4567,6 +4849,9 @@ class CupertinoLocalizationFrCa extends CupertinoLocalizationFr { required super.decimalFormat, }); + @override + String get menuDismissLabel => 'Ignorer le menu'; + @override String? get datePickerHourSemanticsLabelOne => r'$hour heure'; @@ -4664,16 +4949,16 @@ class CupertinoLocalizationGl extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Mirar cara arriba'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Pechar menú'; @override String get modalBarrierDismissLabel => 'Ignorar'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Non se encontrou ningunha substitución'; @override String get pasteButtonLabel => 'Pegar'; @@ -4826,13 +5111,13 @@ class CupertinoLocalizationGsw extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menü schließen'; @override String get modalBarrierDismissLabel => 'Schließen'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Keine Ersetzungen gefunden'; @override String get pasteButtonLabel => 'Einsetzen'; @@ -4985,13 +5270,13 @@ class CupertinoLocalizationGu extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'મેનૂ છોડી દો'; @override String get modalBarrierDismissLabel => 'છોડી દો'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'બદલવા માટે કોઈ શબ્દ મળ્યો નથી'; @override String get pasteButtonLabel => 'પેસ્ટ કરો'; @@ -5144,13 +5429,13 @@ class CupertinoLocalizationHe extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'סגירת התפריט'; @override String get modalBarrierDismissLabel => 'סגירה'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'לא נמצאו חלופות'; @override String get pasteButtonLabel => 'הדבקה'; @@ -5303,13 +5588,13 @@ class CupertinoLocalizationHi extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'मेन्यू खारिज करें'; @override String get modalBarrierDismissLabel => 'खारिज करें'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'सही वर्तनी वाला कोई शब्द नहीं मिला'; @override String get pasteButtonLabel => 'चिपकाएं'; @@ -5459,16 +5744,16 @@ class CupertinoLocalizationHr extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Pogled prema gore'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Odbacivanje izbornika'; @override String get modalBarrierDismissLabel => 'Odbaci'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nema pronađenih zamjena'; @override String get pasteButtonLabel => 'Zalijepi'; @@ -5618,16 +5903,16 @@ class CupertinoLocalizationHu extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Felfelé nézés'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menü bezárása'; @override String get modalBarrierDismissLabel => 'Elvetés'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nem található javítás'; @override String get pasteButtonLabel => 'Beillesztés'; @@ -5780,13 +6065,13 @@ class CupertinoLocalizationHy extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Փակել ընտրացանկը'; @override String get modalBarrierDismissLabel => 'Փակել'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Փոխարինումներ չեն գտնվել'; @override String get pasteButtonLabel => 'Տեղադրել'; @@ -5939,13 +6224,13 @@ class CupertinoLocalizationId extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Tutup menu'; @override String get modalBarrierDismissLabel => 'Tutup'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Penggantian Tidak Ditemukan'; @override String get pasteButtonLabel => 'Tempel'; @@ -6098,13 +6383,13 @@ class CupertinoLocalizationIs extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Loka valmynd'; @override String get modalBarrierDismissLabel => 'Hunsa'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Engir staðgenglar fundust'; @override String get pasteButtonLabel => 'Líma'; @@ -6254,16 +6539,16 @@ class CupertinoLocalizationIt extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Cerca'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ignora menu'; @override String get modalBarrierDismissLabel => 'Ignora'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nessuna sostituzione trovata'; @override String get pasteButtonLabel => 'Incolla'; @@ -6413,16 +6698,16 @@ class CupertinoLocalizationJa extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => '調べる'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'メニューを閉じる'; @override String get modalBarrierDismissLabel => '閉じる'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => '置き換えるものがありません'; @override String get pasteButtonLabel => '貼り付け'; @@ -6575,13 +6860,13 @@ class CupertinoLocalizationKa extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'მენიუს უარყოფა'; @override String get modalBarrierDismissLabel => 'დახურვა'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'ჩანაცვლება არ მოიძებნა'; @override String get pasteButtonLabel => 'ჩასმა'; @@ -6734,13 +7019,13 @@ class CupertinoLocalizationKk extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Мәзірді жабу'; @override String get modalBarrierDismissLabel => 'Жабу'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Ауыстыратын ешнәрсе табылмады.'; @override String get pasteButtonLabel => 'Қою'; @@ -6890,16 +7175,16 @@ class CupertinoLocalizationKm extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'រកមើល'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ច្រានចោល​ម៉ឺនុយ'; @override String get modalBarrierDismissLabel => 'ច្រាន​ចោល'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'រកមិនឃើញ​ការជំនួសទេ'; @override String get pasteButtonLabel => 'ដាក់​ចូល'; @@ -7052,13 +7337,13 @@ class CupertinoLocalizationKn extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => '\u{cae}\u{cc6}\u{ca8}\u{cc1}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc1}\u{20}\u{cb5}\u{c9c}\u{cbe}\u{c97}\u{cc6}\u{cc2}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; @override String get modalBarrierDismissLabel => '\u{cb5}\u{c9c}\u{cbe}\u{c97}\u{cca}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => '\u{caf}\u{cbe}\u{cb5}\u{cc1}\u{ca6}\u{cc7}\u{20}\u{cac}\u{ca6}\u{cb2}\u{cbe}\u{cb5}\u{ca3}\u{cc6}\u{c97}\u{cb3}\u{cc1}\u{20}\u{c95}\u{c82}\u{ca1}\u{cc1}\u{cac}\u{c82}\u{ca6}\u{cbf}\u{cb2}\u{ccd}\u{cb2}'; @override String get pasteButtonLabel => '\u{c85}\u{c82}\u{c9f}\u{cbf}\u{cb8}\u{cbf}'; @@ -7211,13 +7496,13 @@ class CupertinoLocalizationKo extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => '메뉴 닫기'; @override String get modalBarrierDismissLabel => '닫기'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => '수정사항 없음'; @override String get pasteButtonLabel => '붙여넣기'; @@ -7370,13 +7655,13 @@ class CupertinoLocalizationKy extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Менюну жабуу'; @override String get modalBarrierDismissLabel => 'Жабуу'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Алмаштыруу үчүн сөз табылган жок'; @override String get pasteButtonLabel => 'Чаптоо'; @@ -7529,13 +7814,13 @@ class CupertinoLocalizationLo extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ປິດເມນູ'; @override String get modalBarrierDismissLabel => 'ປິດໄວ້'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'ບໍ່ພົບການແທນທີ່'; @override String get pasteButtonLabel => 'ວາງ'; @@ -7688,13 +7973,13 @@ class CupertinoLocalizationLt extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Atsisakyti meniu'; @override String get modalBarrierDismissLabel => 'Atsisakyti'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nerasta jokių pakeitimų'; @override String get pasteButtonLabel => 'Įklijuoti'; @@ -7847,13 +8132,13 @@ class CupertinoLocalizationLv extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Nerādīt izvēlni'; @override String get modalBarrierDismissLabel => 'Nerādīt'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Netika atrasts neviens vārds aizstāšanai'; @override String get pasteButtonLabel => 'Ielīmēt'; @@ -8006,13 +8291,13 @@ class CupertinoLocalizationMk extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Отфрлете го менито'; @override String get modalBarrierDismissLabel => 'Отфрли'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Не се најдени заменски зборови'; @override String get pasteButtonLabel => 'Залепи'; @@ -8162,16 +8447,16 @@ class CupertinoLocalizationMl extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'മുകളിലേക്ക് നോക്കുക'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'മെനു ഡിസ്മിസ് ചെയ്യുക'; @override String get modalBarrierDismissLabel => 'നിരസിക്കുക'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'റീപ്ലേസ്‌മെന്റുകളൊന്നും കണ്ടെത്തിയില്ല'; @override String get pasteButtonLabel => 'ഒട്ടിക്കുക'; @@ -8324,13 +8609,13 @@ class CupertinoLocalizationMn extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Цэсийг хаах'; @override String get modalBarrierDismissLabel => 'Үл хэрэгсэх'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Ямар ч орлуулалт олдсонгүй'; @override String get pasteButtonLabel => 'Буулгах'; @@ -8483,13 +8768,13 @@ class CupertinoLocalizationMr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'मेनू डिसमिस करा'; @override String get modalBarrierDismissLabel => 'डिसमिस करा'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'कोणतेही बदल आढळले नाहीत'; @override String get pasteButtonLabel => 'पेस्ट करा'; @@ -8639,16 +8924,16 @@ class CupertinoLocalizationMs extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Lihat ke Atas'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ketepikan menu'; @override String get modalBarrierDismissLabel => 'Tolak'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Tiada Penggantian Ditemukan'; @override String get pasteButtonLabel => 'Tampal'; @@ -8801,13 +9086,13 @@ class CupertinoLocalizationMy extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'မီနူးကိုပယ်ပါ'; @override String get modalBarrierDismissLabel => 'ပယ်ရန်'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'အစားထိုးမှုများ မတွေ့ပါ'; @override String get pasteButtonLabel => 'ကူးထည့်ရန်'; @@ -8960,13 +9245,13 @@ class CupertinoLocalizationNb extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Lukk menyen'; @override String get modalBarrierDismissLabel => 'Avvis'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Fant ingen erstatninger'; @override String get pasteButtonLabel => 'Lim inn'; @@ -9119,13 +9404,13 @@ class CupertinoLocalizationNe extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'मेनु खारेज गर्नुहोस्'; @override String get modalBarrierDismissLabel => 'खारेज गर्नुहोस्'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'बदल्नु पर्ने कुनै पनि कुरा भेटिएन'; @override String get pasteButtonLabel => 'टाँस्नुहोस्'; @@ -9278,13 +9563,13 @@ class CupertinoLocalizationNl extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menu sluiten'; @override String get modalBarrierDismissLabel => 'Sluiten'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Geen vervangingen gevonden'; @override String get pasteButtonLabel => 'Plakken'; @@ -9437,13 +9722,13 @@ class CupertinoLocalizationNo extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Lukk menyen'; @override String get modalBarrierDismissLabel => 'Avvis'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Fant ingen erstatninger'; @override String get pasteButtonLabel => 'Lim inn'; @@ -9596,13 +9881,13 @@ class CupertinoLocalizationOr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ମେନୁ ଖାରଜ କରନ୍ତୁ'; @override String get modalBarrierDismissLabel => 'ଖାରଜ କରନ୍ତୁ'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'କୌଣସି ରିପ୍ଲେସମେଣ୍ଟ ମିଳିଲା ନାହିଁ'; @override String get pasteButtonLabel => 'ପେଷ୍ଟ କରନ୍ତୁ'; @@ -9755,13 +10040,13 @@ class CupertinoLocalizationPa extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ਮੀਨੂ ਖਾਰਜ ਕਰੋ'; @override String get modalBarrierDismissLabel => 'ਖਾਰਜ ਕਰੋ'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'ਕੋਈ ਸੁਝਾਅ ਨਹੀਂ ਮਿਲਿਆ'; @override String get pasteButtonLabel => 'ਪੇਸਟ ਕਰੋ'; @@ -9911,16 +10196,16 @@ class CupertinoLocalizationPl extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Sprawdź'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Zamknij menu'; @override String get modalBarrierDismissLabel => 'Zamknij'; @override - String get noSpellCheckReplacementsLabel => 'Nie znaleziono zastąpień'; + String get noSpellCheckReplacementsLabel => 'Brak wyników zamieniania'; @override String get pasteButtonLabel => 'Wklej'; @@ -9935,7 +10220,7 @@ class CupertinoLocalizationPl extends GlobalCupertinoLocalizations { String get searchWebButtonLabel => 'Search Web'; @override - String get selectAllButtonLabel => 'Zaznacz wszystko'; + String get selectAllButtonLabel => 'Wybierz wszystkie'; @override String get tabSemanticsLabelRaw => r'Karta $tabIndex z $tabCount'; @@ -10070,16 +10355,16 @@ class CupertinoLocalizationPt extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Pesquisar'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Dispensar menu'; @override String get modalBarrierDismissLabel => 'Dispensar'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nenhuma alternativa encontrada'; @override String get pasteButtonLabel => 'Colar'; @@ -10094,7 +10379,7 @@ class CupertinoLocalizationPt extends GlobalCupertinoLocalizations { String get searchWebButtonLabel => 'Search Web'; @override - String get selectAllButtonLabel => 'Selecionar tudo'; + String get selectAllButtonLabel => 'Selecionar Tudo'; @override String get tabSemanticsLabelRaw => r'Guia $tabIndex de $tabCount'; @@ -10174,6 +10459,15 @@ class CupertinoLocalizationPtPt extends CupertinoLocalizationPt { required super.decimalFormat, }); + @override + String get lookUpButtonLabel => 'Procurar'; + + @override + String get noSpellCheckReplacementsLabel => 'Não foram encontradas substituições'; + + @override + String get menuDismissLabel => 'Ignorar menu'; + @override String get searchTextFieldPlaceholderLabel => 'Pesquise'; @@ -10189,6 +10483,9 @@ class CupertinoLocalizationPtPt extends CupertinoLocalizationPt { @override String get timerPickerSecondLabelOther => 'seg'; + @override + String get selectAllButtonLabel => 'Selecionar tudo'; + @override String get modalBarrierDismissLabel => 'Ignorar'; } @@ -10268,13 +10565,13 @@ class CupertinoLocalizationRo extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Respingeți meniul'; @override String get modalBarrierDismissLabel => 'Închideți'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nu s-au găsit înlocuiri'; @override String get pasteButtonLabel => 'Inserați'; @@ -10427,13 +10724,13 @@ class CupertinoLocalizationRu extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Закрыть меню'; @override String get modalBarrierDismissLabel => 'Закрыть'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Варианты замены не найдены'; @override String get pasteButtonLabel => 'Вставить'; @@ -10586,13 +10883,13 @@ class CupertinoLocalizationSi extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'මෙනුව අස් කරන්න'; @override String get modalBarrierDismissLabel => 'ඉවත ලන්න'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'ප්‍රතිස්ථාපන හමු නොවිණි'; @override String get pasteButtonLabel => 'අලවන්න'; @@ -10745,13 +11042,13 @@ class CupertinoLocalizationSk extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Zavrieť ponuku'; @override String get modalBarrierDismissLabel => 'Odmietnuť'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nenašli sa žiadne náhrady'; @override String get pasteButtonLabel => 'Prilepiť'; @@ -10904,13 +11201,13 @@ class CupertinoLocalizationSl extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Opusti meni'; @override String get modalBarrierDismissLabel => 'Opusti'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Ni zamenjav'; @override String get pasteButtonLabel => 'Prilepi'; @@ -11063,13 +11360,13 @@ class CupertinoLocalizationSq extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Hiqe menynë'; @override String get modalBarrierDismissLabel => 'Hiq'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Nuk u gjetën zëvendësime'; @override String get pasteButtonLabel => 'Ngjit'; @@ -11222,13 +11519,13 @@ class CupertinoLocalizationSr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Одбаците мени'; @override String get modalBarrierDismissLabel => 'Одбаци'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Нису пронађене замене'; @override String get pasteButtonLabel => 'Налепи'; @@ -11371,9 +11668,15 @@ class CupertinoLocalizationSrLatn extends CupertinoLocalizationSr { @override String get datePickerMinuteSemanticsLabelOther => r'$minute minuta'; + @override + String get menuDismissLabel => 'Odbacite meni'; + @override String get modalBarrierDismissLabel => 'Odbaci'; + @override + String get noSpellCheckReplacementsLabel => 'Nisu pronađene zamene'; + @override String get pasteButtonLabel => 'Nalepi'; @@ -11495,13 +11798,13 @@ class CupertinoLocalizationSv extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Stäng menyn'; @override String get modalBarrierDismissLabel => 'Stäng'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Inga ersättningar hittades'; @override String get pasteButtonLabel => 'Klistra in'; @@ -11654,13 +11957,13 @@ class CupertinoLocalizationSw extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ondoa menyu'; @override String get modalBarrierDismissLabel => 'Ondoa'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Hakuna Neno Mbadala Lilopatikana'; @override String get pasteButtonLabel => 'Bandika'; @@ -11813,13 +12116,13 @@ class CupertinoLocalizationTa extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'மெனுவை மூடும்'; @override String get modalBarrierDismissLabel => 'நிராகரிக்கும்'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'மாற்று வார்த்தைகள் கிடைக்கவில்லை'; @override String get pasteButtonLabel => 'ஒட்டு'; @@ -11972,13 +12275,13 @@ class CupertinoLocalizationTe extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'మెనూను తీసివేయండి'; @override String get modalBarrierDismissLabel => 'విస్మరించు'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'రీప్లేస్‌మెంట్‌లు ఏవీ కనుగొనబడలేదు'; @override String get pasteButtonLabel => 'పేస్ట్ చేయండి'; @@ -12131,13 +12434,13 @@ class CupertinoLocalizationTh extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ปิดเมนู'; @override String get modalBarrierDismissLabel => 'ปิด'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'ไม่พบรายการแทนที่'; @override String get pasteButtonLabel => 'วาง'; @@ -12287,16 +12590,16 @@ class CupertinoLocalizationTl extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Tumingin sa Itaas'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'I-dismiss ang menu'; @override String get modalBarrierDismissLabel => 'I-dismiss'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Walang Nahanap na Kapalit'; @override String get pasteButtonLabel => 'I-paste'; @@ -12449,13 +12752,13 @@ class CupertinoLocalizationTr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menüyü kapat'; @override String get modalBarrierDismissLabel => 'Kapat'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Yerine Kelime Bulunamadı'; @override String get pasteButtonLabel => 'Yapıştır'; @@ -12608,13 +12911,13 @@ class CupertinoLocalizationUk extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Закрити меню'; @override String get modalBarrierDismissLabel => 'Закрити'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Замін не знайдено'; @override String get pasteButtonLabel => 'Вставити'; @@ -12767,13 +13070,13 @@ class CupertinoLocalizationUr extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'مینو برخاست کریں'; @override String get modalBarrierDismissLabel => 'برخاست کریں'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'کوئی تبدیلیاں نہیں ملیں'; @override String get pasteButtonLabel => 'پیسٹ کریں'; @@ -12923,16 +13226,16 @@ class CupertinoLocalizationUz extends GlobalCupertinoLocalizations { String? get datePickerMinuteSemanticsLabelZero => null; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Tepaga qarang'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menyuni yopish'; @override String get modalBarrierDismissLabel => 'Yopish'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Almashtirish uchun soʻz topilmadi'; @override String get pasteButtonLabel => 'Joylash'; @@ -13085,13 +13388,13 @@ class CupertinoLocalizationVi extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Đóng trình đơn'; @override String get modalBarrierDismissLabel => 'Bỏ qua'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Không tìm thấy phương án thay thế'; @override String get pasteButtonLabel => 'Dán'; @@ -13244,13 +13547,13 @@ class CupertinoLocalizationZh extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => '关闭菜单'; @override String get modalBarrierDismissLabel => '关闭'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => '找不到替换文字'; @override String get pasteButtonLabel => '粘贴'; @@ -13387,9 +13690,18 @@ class CupertinoLocalizationZhHant extends CupertinoLocalizationZh { @override String get datePickerMinuteSemanticsLabelOther => r'$minute 分鐘'; + @override + String get lookUpButtonLabel => '查詢'; + + @override + String get menuDismissLabel => '閂選單'; + @override String get modalBarrierDismissLabel => '拒絕'; + @override + String get noSpellCheckReplacementsLabel => '找不到替換字詞'; + @override String get pasteButtonLabel => '貼上'; @@ -13450,6 +13762,12 @@ class CupertinoLocalizationZhHantTw extends CupertinoLocalizationZhHant { required super.decimalFormat, }); + @override + String get noSpellCheckReplacementsLabel => '找不到替代文字'; + + @override + String get menuDismissLabel => '關閉選單'; + @override String get tabSemanticsLabelRaw => r'第 $tabIndex 個分頁標籤,共 $tabCount 個'; @@ -13550,13 +13868,13 @@ class CupertinoLocalizationZu extends GlobalCupertinoLocalizations { String get lookUpButtonLabel => 'Look Up'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Chitha imenyu'; @override String get modalBarrierDismissLabel => 'Cashisa'; @override - String get noSpellCheckReplacementsLabel => 'No Replacements Found'; + String get noSpellCheckReplacementsLabel => 'Akukho Okuzofakwa Esikhundleni Okutholakele'; @override String get pasteButtonLabel => 'Namathisela'; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index 01b9d055c5d1a..2bed33afb469c 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -66,7 +66,7 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Maak toe'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Uitgevou'; @override String get collapsedIconTapHint => 'Vou uit'; @@ -126,22 +126,22 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigasiekieslys'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Ingevou'; @override String get expandedIconTapHint => 'Vou in'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dubbeltik om uit te vou'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Vou uit vir meer besonderhede'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dubbeltik om in te vou'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Vou in'; @override String get firstPageTooltip => 'Eerste bladsy'; @@ -336,7 +336,7 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Kieslysbalkkieslys'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Maak kieslys toe'; @override String get modalBarrierDismissLabel => 'Maak toe'; @@ -423,7 +423,7 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Stoor'; @override - String get scanTextButtonLabel => 'Skena umbhalo'; + String get scanTextButtonLabel => 'Skandeer teks'; @override String get scrimLabel => 'Skerm'; @@ -553,7 +553,7 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'ዝጋ'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ተዘርግቷል'; @override String get collapsedIconTapHint => 'ዘርጋ'; @@ -613,25 +613,25 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get drawerLabel => 'የዳሰሳ ምናሌ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ተሰብስቧል'; @override String get expandedIconTapHint => 'ሰብስብ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ለመዘርጋት ድርብ ሁለቴ መታ ያድርጉ'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ለተጨማሪ ዝርዝሮች ይዘርጉ'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ለመሰብሰብ ሁለቴ መታ ያድርጉ'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ሰብስብ'; @override - String get firstPageTooltip => 'የመጀመሪያው ገጽ'; + String get firstPageTooltip => 'የመጀመሪያው ገፅ'; @override String get hideAccountsLabel => 'መለያዎችን ደብቅ'; @@ -793,7 +793,7 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get keyboardKeySpace => 'ክፍተት'; @override - String get lastPageTooltip => 'የመጨረሻው ገጽ'; + String get lastPageTooltip => 'የመጨረሻው ገፅ'; @override String? get licensesPackageDetailTextFew => null; @@ -823,7 +823,7 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'የምናሌ አሞሌ ምናሌ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ምናሌን አሰናብት'; @override String get modalBarrierDismissLabel => 'አሰናብት'; @@ -835,7 +835,7 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get nextMonthTooltip => 'ቀጣይ ወር'; @override - String get nextPageTooltip => 'ቀጣይ ገጽ'; + String get nextPageTooltip => 'ቀጣይ ገፅ'; @override String get okButtonLabel => 'እሺ'; @@ -862,7 +862,7 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get previousMonthTooltip => 'ቀዳሚ ወር'; @override - String get previousPageTooltip => 'ቀዳሚ ገጽ'; + String get previousPageTooltip => 'ቀዳሚ ገፅ'; @override String get refreshIndicatorSemanticLabel => 'አድስ'; @@ -910,7 +910,7 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { String get saveButtonLabel => 'አስቀምጥ'; @override - String get scanTextButtonLabel => 'ጽሑፍ ይቃኙ'; + String get scanTextButtonLabel => 'ጽሁፍን ቃኝ'; @override String get scrimLabel => 'ገዳቢ'; @@ -1040,7 +1040,7 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'إغلاق'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'موسَّع'; @override String get collapsedIconTapHint => 'توسيع'; @@ -1100,22 +1100,22 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { String get drawerLabel => 'قائمة تنقل'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'مصغَّر'; @override String get expandedIconTapHint => 'تصغير'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'انقر مرّتين للتوسيع'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'وسِّع المربّع لعرض مزيد من التفاصيل.'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'يُرجى النقر مرّتين للتصغير.'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'تصغير'; @override String get firstPageTooltip => 'الصفحة الأولى'; @@ -1310,7 +1310,7 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'قائمة شريط القوائم'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'إغلاق القائمة'; @override String get modalBarrierDismissLabel => 'رفض'; @@ -1397,7 +1397,7 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'الحفظ'; @override - String get scanTextButtonLabel => 'مسح النص'; + String get scanTextButtonLabel => 'مسح النص ضوئيًا'; @override String get scrimLabel => 'تمويه'; @@ -1527,7 +1527,7 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'বন্ধ কৰক'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'বিস্তাৰ কৰা আছে'; @override String get collapsedIconTapHint => 'বিস্তাৰ কৰক'; @@ -1587,22 +1587,22 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { String get drawerLabel => 'নেভিগেশ্বন মেনু'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'সংকোচন কৰা আছে'; @override String get expandedIconTapHint => 'সংকোচন কৰক'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'বিস্তাৰ কৰিবলৈ দুবাৰ টিপক'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'অধিক সবিশেষ জানিবলৈ বিস্তাৰ কৰক'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'সংকোচন কৰিবলৈ দুবাৰ টিপক'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'সংকোচন কৰক'; @override String get firstPageTooltip => 'প্রথম পৃষ্ঠা'; @@ -1797,7 +1797,7 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'মেনু বাৰ মেনু'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'অগ্ৰাহ্য কৰাৰ মেনু'; @override String get modalBarrierDismissLabel => 'অগ্ৰাহ্য কৰক'; @@ -1884,7 +1884,7 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { String get saveButtonLabel => 'ছেভ কৰক'; @override - String get scanTextButtonLabel => 'স্কেন টেক্সট'; + String get scanTextButtonLabel => 'পাঠ স্কেন কৰক'; @override String get scrimLabel => 'স্ক্ৰিম'; @@ -2014,7 +2014,7 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Bağlayın'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Genişləndirildi'; @override String get collapsedIconTapHint => 'Genişləndirin'; @@ -2074,22 +2074,22 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { String get drawerLabel => 'Naviqasiya menyusu'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Yığcamlaşdırıldı'; @override String get expandedIconTapHint => 'Yığcamlaşdırın'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'genişləndirmək üçün iki dəfə toxunun'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Daha çox detallar üçün genişləndirin'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'yığcamlaşdırmaq üçün iki dəfə toxunun'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Yığcamlaşdırın'; @override String get firstPageTooltip => 'Birinci səhifə'; @@ -2284,7 +2284,7 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menyu paneli menyusu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menyunu qapadın'; @override String get modalBarrierDismissLabel => 'İmtina edin'; @@ -2501,7 +2501,7 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Закрыць'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Разгорнута'; @override String get collapsedIconTapHint => 'Разгарнуць'; @@ -2561,22 +2561,22 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { String get drawerLabel => 'Меню навігацыі'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Згорнута'; @override String get expandedIconTapHint => 'Згарнуць'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'двойчы націснуць, каб разгарнуць'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Разгарніце, каб даведацца больш'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'двойчы націснуць, каб згарнуць'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Згарнуць'; @override String get firstPageTooltip => 'На першую старонку'; @@ -2771,7 +2771,7 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Меню "Панэль меню"'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Закрыць меню'; @override String get modalBarrierDismissLabel => 'Адхіліць'; @@ -2858,7 +2858,7 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Захаваць'; @override - String get scanTextButtonLabel => 'Сканаваць тэкст'; + String get scanTextButtonLabel => 'Сканіраваць тэкст'; @override String get scrimLabel => 'Палатно'; @@ -2988,7 +2988,7 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Затваряне'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Разгънато'; @override String get collapsedIconTapHint => 'Разгъване'; @@ -3048,22 +3048,22 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { String get drawerLabel => 'Меню за навигация'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Свито'; @override String get expandedIconTapHint => 'Свиване'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'докоснете два пъти за разгъване'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Разгъване за още подробности'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'докоснете два пъти за свиване'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Свиване'; @override String get firstPageTooltip => 'Първа страница'; @@ -3258,7 +3258,7 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Меню на лентата с менюта'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Отхвърляне на менюто'; @override String get modalBarrierDismissLabel => 'Отхвърляне'; @@ -3345,7 +3345,7 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Запазване'; @override - String get scanTextButtonLabel => 'Сканиране на текст'; + String get scanTextButtonLabel => 'Сканирайте текст'; @override String get scrimLabel => 'Скрим'; @@ -3475,7 +3475,7 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'বন্ধ করুন'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'বড় করা হয়েছে'; @override String get collapsedIconTapHint => 'বড় করুন'; @@ -3535,22 +3535,22 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { String get drawerLabel => 'নেভিগেশান মেনু'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'আড়াল করা হয়েছে'; @override String get expandedIconTapHint => 'আড়াল করুন'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'বড় করে দেখতে ডবল ট্যাপ করুন'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'আরও বিবরণ পেতে বড় করে দেখুন'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'আড়াল করতে ডবল ট্যাপ করুন'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'আড়াল করুন'; @override String get firstPageTooltip => 'প্রথম পৃষ্ঠা'; @@ -3745,7 +3745,7 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'মেনু বার মেনু'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'বাতিল করার মেনু'; @override String get modalBarrierDismissLabel => 'খারিজ করুন'; @@ -3832,7 +3832,7 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { String get saveButtonLabel => 'সেভ করুন'; @override - String get scanTextButtonLabel => 'পাঠ্য স্ক্যান করুন'; + String get scanTextButtonLabel => 'টেক্সট স্ক্যান করুন'; @override String get scrimLabel => 'স্ক্রিম'; @@ -3962,7 +3962,7 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Zatvaranje'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Prošireno'; @override String get collapsedIconTapHint => 'Proširi'; @@ -4022,22 +4022,22 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { String get drawerLabel => 'Meni za navigaciju'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Suženo'; @override String get expandedIconTapHint => 'Suzi'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'proširivanje dvostrukim dodirom'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Proširivanje za više detalja'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'sužavanje dvostrukim dodirom'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Sužavanje'; @override String get firstPageTooltip => 'Prva stranica'; @@ -4226,13 +4226,13 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licence'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Pogled prema gore'; @override String get menuBarMenuLabel => 'Meni trake menija'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Odbacivanje menija'; @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -4449,7 +4449,7 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Tanca'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => "S'ha desplegat"; @override String get collapsedIconTapHint => 'Desplega'; @@ -4509,22 +4509,22 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { String get drawerLabel => 'Menú de navegació'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => "S'ha replegat"; @override String get expandedIconTapHint => 'Replega'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'fes doble toc per desplegar'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Desplega per obtenir més informació'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'fes doble toc per replegar'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Replega'; @override String get firstPageTooltip => 'Primera pàgina'; @@ -4719,7 +4719,7 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menú de la barra de menú'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ignora el menú'; @override String get modalBarrierDismissLabel => 'Ignora'; @@ -4806,7 +4806,7 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Desa'; @override - String get scanTextButtonLabel => 'Escaneja el text'; + String get scanTextButtonLabel => 'Escaneja text'; @override String get scrimLabel => 'Fons atenuat'; @@ -4936,7 +4936,7 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Zavřít'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Rozbaleno'; @override String get collapsedIconTapHint => 'Rozbalit'; @@ -4996,22 +4996,22 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigační nabídka'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Sbaleno'; @override String get expandedIconTapHint => 'Sbalit'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dvojitým klepnutím rozbalíte'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Rozbalte pro další podrobnosti'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dvojitým klepnutím sbalíte'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Sbalit'; @override String get firstPageTooltip => 'První stránka'; @@ -5206,7 +5206,7 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Nabídka na liště s nabídkou'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Zavřít nabídku'; @override String get modalBarrierDismissLabel => 'Zavřít'; @@ -5293,7 +5293,7 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Uložit'; @override - String get scanTextButtonLabel => 'Naskenujte text'; + String get scanTextButtonLabel => 'Naskenovat text'; @override String get scrimLabel => 'Scrim'; @@ -5423,7 +5423,7 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Cau'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => "Wedi'i ehangu"; @override String get collapsedIconTapHint => 'Ehangu'; @@ -5483,22 +5483,22 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { String get drawerLabel => 'Dewislen llywio'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => "Wedi'i grebachu"; @override String get expandedIconTapHint => 'Crebachu'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'tapiwch ddwywaith i ehangu'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Ehangwch am ragor o fanylion'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'tapiwch ddwywaith i grebachu'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Crebachu'; @override String get firstPageTooltip => 'Tudalen gyntaf'; @@ -5693,7 +5693,7 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Dewislen bar dewislen'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => "Diystyru'r ddewislen"; @override String get modalBarrierDismissLabel => 'Diystyru'; @@ -5780,7 +5780,7 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Cadw'; @override - String get scanTextButtonLabel => 'Scan text'; + String get scanTextButtonLabel => 'Sganio testun'; @override String get scrimLabel => 'Scrim'; @@ -5910,7 +5910,7 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Luk'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Udvidet'; @override String get collapsedIconTapHint => 'Udvid'; @@ -5970,22 +5970,22 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigationsmenu'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Skjult'; @override String get expandedIconTapHint => 'Skjul'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'tryk to gange for at udvide'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Udvid for at få flere oplysninger'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'tryk to gange for at skjule'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Skjul'; @override String get firstPageTooltip => 'Første side'; @@ -6180,7 +6180,7 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menuen for menulinjen'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Luk menu'; @override String get modalBarrierDismissLabel => 'Afvis'; @@ -6397,7 +6397,7 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Schließen'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Maximiert'; @override String get collapsedIconTapHint => 'Maximieren'; @@ -6457,22 +6457,22 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigationsmenü'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Minimiert'; @override String get expandedIconTapHint => 'Minimieren'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'Zum Maximieren doppeltippen'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Für weitere Details maximieren'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'Zum Minimieren doppeltippen'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Minimieren'; @override String get firstPageTooltip => 'Erste Seite'; @@ -6667,7 +6667,7 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menü in der Menüleiste'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menü schließen'; @override String get modalBarrierDismissLabel => 'Schließen'; @@ -6948,7 +6948,7 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Κλείσιμο'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Αναπτύχθηκε'; @override String get collapsedIconTapHint => 'Ανάπτυξη'; @@ -7008,22 +7008,22 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { String get drawerLabel => 'Μενού πλοήγησης'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Συμπτύχθηκε'; @override String get expandedIconTapHint => 'Σύμπτυξη'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'πατήστε δύο φορές για ανάπτυξη'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Ανάπτυξη για περισσότερες λεπτομέρειες'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'πατήστε δύο φορές για σύμπτυξη'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Σύμπτυξη'; @override String get firstPageTooltip => 'Πρώτη σελίδα'; @@ -7218,7 +7218,7 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Μενού γραμμής μενού'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Παράβλεψη μενού'; @override String get modalBarrierDismissLabel => 'Παράβλεψη'; @@ -7894,6 +7894,15 @@ class MaterialLocalizationEnAu extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8091,6 +8100,15 @@ class MaterialLocalizationEnGb extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8182,6 +8200,15 @@ class MaterialLocalizationEnIe extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8273,6 +8300,15 @@ class MaterialLocalizationEnIn extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8361,6 +8397,15 @@ class MaterialLocalizationEnNz extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8449,6 +8494,15 @@ class MaterialLocalizationEnSg extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8537,6 +8591,15 @@ class MaterialLocalizationEnZa extends MaterialLocalizationEn { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Look up'; + + @override + String get expansionTileExpandedHint => 'double-tap to collapse'; + + @override + String get expansionTileCollapsedHint => 'double-tap to expand'; + @override String get bottomSheetLabel => 'Bottom sheet'; @@ -8656,7 +8719,7 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Cerrar'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Desplegado'; @override String get collapsedIconTapHint => 'Mostrar'; @@ -8716,22 +8779,22 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { String get drawerLabel => 'Menú de navegación'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Contraído'; @override String get expandedIconTapHint => 'Ocultar'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'toca dos veces para desplegar'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Desplegar para ver más detalles'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'toca dos veces para contraer'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Contraer'; @override String get firstPageTooltip => 'Primera página'; @@ -8926,7 +8989,7 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menú de la barra de menú'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Cerrar menú'; @override String get modalBarrierDismissLabel => 'Cerrar'; @@ -9115,6 +9178,27 @@ class MaterialLocalizationEs419 extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -9284,6 +9368,27 @@ class MaterialLocalizationEsAr extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -9453,6 +9558,27 @@ class MaterialLocalizationEsBo extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -9622,6 +9748,27 @@ class MaterialLocalizationEsCl extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -9791,6 +9938,27 @@ class MaterialLocalizationEsCo extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -9960,6 +10128,27 @@ class MaterialLocalizationEsCr extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -10129,6 +10318,27 @@ class MaterialLocalizationEsDo extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -10298,6 +10508,27 @@ class MaterialLocalizationEsEc extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -10467,6 +10698,27 @@ class MaterialLocalizationEsGt extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -10636,6 +10888,27 @@ class MaterialLocalizationEsHn extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -10805,6 +11078,27 @@ class MaterialLocalizationEsMx extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -10974,6 +11268,27 @@ class MaterialLocalizationEsNi extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -11143,6 +11458,27 @@ class MaterialLocalizationEsPa extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -11312,6 +11648,27 @@ class MaterialLocalizationEsPe extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -11481,6 +11838,27 @@ class MaterialLocalizationEsPr extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -11650,6 +12028,27 @@ class MaterialLocalizationEsPy extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -11819,6 +12218,27 @@ class MaterialLocalizationEsSv extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -11988,6 +12408,27 @@ class MaterialLocalizationEsUs extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -12160,6 +12601,27 @@ class MaterialLocalizationEsUy extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -12329,6 +12791,27 @@ class MaterialLocalizationEsVe extends MaterialLocalizationEs { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Analizar texto'; + + @override + String get lookUpButtonLabel => 'Mirar hacia arriba'; + + @override + String get menuDismissLabel => 'Descartar menú'; + + @override + String get expansionTileExpandedHint => 'presiona dos veces para contraer'; + + @override + String get expansionTileCollapsedHint => 'presiona dos veces para expandir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para ver más detalles'; + + @override + String get collapsedHint => 'Expandido'; + @override String get scrimLabel => 'Lámina'; @@ -12526,7 +13009,7 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Sule'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Laiendatud'; @override String get collapsedIconTapHint => 'Laienda'; @@ -12586,22 +13069,22 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigeerimismenüü'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Ahendatud'; @override String get expandedIconTapHint => 'Ahenda'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'topeltpuudutage laiendamiseks'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Laiendage lisateabe nägemiseks'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'topeltpuudutage ahendamiseks'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Ahenda'; @override String get firstPageTooltip => 'Esimene leht'; @@ -12796,7 +13279,7 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menüüriba menüü'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Sulge menüü'; @override String get modalBarrierDismissLabel => 'Loobu'; @@ -12883,7 +13366,7 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Salvesta'; @override - String get scanTextButtonLabel => 'Skanni teksti'; + String get scanTextButtonLabel => 'Skanni tekst'; @override String get scrimLabel => 'Sirm'; @@ -13013,7 +13496,7 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Itxi'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Zabalduta'; @override String get collapsedIconTapHint => 'Zabaldu'; @@ -13073,22 +13556,22 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { String get drawerLabel => 'Nabigazio-menua'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Tolestuta'; @override String get expandedIconTapHint => 'Tolestu'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'zabaltzeko, sakatu birritan'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Zabaldu hau xehetasun gehiago lortzeko'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'tolesteko, sakatu birritan'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Tolestu'; @override String get firstPageTooltip => 'Lehenengo orria'; @@ -13283,7 +13766,7 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menu-barraren menua'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Baztertu menua'; @override String get modalBarrierDismissLabel => 'Baztertu'; @@ -13500,7 +13983,7 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'بستن'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ازهم بازشده'; @override String get collapsedIconTapHint => 'بزرگ کردن'; @@ -13560,22 +14043,22 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { String get drawerLabel => 'منوی پیمایش'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'جمع‌شده'; @override String get expandedIconTapHint => 'کوچک کردن'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'برای ازهم بازکردن، دوضربه بزنید'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ازهم بازکردن برای جزئیات بیشتر'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'برای جمع کردن، دوضربه بزنید'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'جمع کردن'; @override String get firstPageTooltip => 'صفحه اول'; @@ -13608,7 +14091,7 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { String get keyboardKeyBackspace => 'پس‌بَر'; @override - String get keyboardKeyCapsLock => 'حالت حروف بزرگ'; + String get keyboardKeyCapsLock => 'Caps Lock'; @override String get keyboardKeyChannelDown => 'کانال پایین'; @@ -13761,7 +14244,7 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { String? get licensesPackageDetailTextZero => 'No licenses'; @override - String get licensesPageTitle => 'مجوزها'; + String get licensesPageTitle => 'پروانه‌ها'; @override String get lookUpButtonLabel => 'Look Up'; @@ -13770,7 +14253,7 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'منوی نوار منو'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'بستن منو'; @override String get modalBarrierDismissLabel => 'نپذیرفتن'; @@ -13857,7 +14340,7 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { String get saveButtonLabel => 'ذخیره'; @override - String get scanTextButtonLabel => 'اسکن متن'; + String get scanTextButtonLabel => 'اسکن کردن نوشتار'; @override String get scrimLabel => 'رویه'; @@ -13987,7 +14470,7 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Sulje'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Laajennettu'; @override String get collapsedIconTapHint => 'Laajenna'; @@ -14047,22 +14530,22 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigointivalikko'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Tiivistetty'; @override String get expandedIconTapHint => 'Tiivistä'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'laajenna kaksoisnapauttamalla'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Katso lisätietoja laajentamalla'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'tiivistä kaksoisnapauttamalla'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Tiivistä'; @override String get firstPageTooltip => 'Ensimmäinen sivu'; @@ -14257,7 +14740,7 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Valikkopalkki'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Hylkää valikko'; @override String get modalBarrierDismissLabel => 'Ohita'; @@ -14474,7 +14957,7 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Isara'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Naka-expand'; @override String get collapsedIconTapHint => 'I-expand'; @@ -14534,22 +15017,22 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu ng navigation'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Naka-collapse'; @override String get expandedIconTapHint => 'I-collapse'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'i-double tap para i-expand'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'I-expand para sa higit pang detalye'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'i-double tap para i-collapse'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'I-collapse'; @override String get firstPageTooltip => 'Unang page'; @@ -14738,13 +15221,13 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Mga Lisensya'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Tumingin sa Itaas'; @override String get menuBarMenuLabel => 'Menu sa menu bar'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'I-dismiss ang menu'; @override String get modalBarrierDismissLabel => 'I-dismiss'; @@ -14961,7 +15444,7 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Fermer'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Développé'; @override String get collapsedIconTapHint => 'Développer'; @@ -15021,22 +15504,22 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu de navigation'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Réduit'; @override String get expandedIconTapHint => 'Réduire'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'appuyez deux fois pour développer'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Développer pour en savoir plus'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'appuyez deux fois pour réduire'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Réduire'; @override String get firstPageTooltip => 'Première page'; @@ -15231,7 +15714,7 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menu de la barre de menu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Fermer le menu'; @override String get modalBarrierDismissLabel => 'Ignorer'; @@ -15318,7 +15801,7 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Enregistrer'; @override - String get scanTextButtonLabel => 'Numériser du texte'; + String get scanTextButtonLabel => 'Scanner du texte'; @override String get scrimLabel => 'Fond'; @@ -15420,6 +15903,21 @@ class MaterialLocalizationFrCa extends MaterialLocalizationFr { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => 'Balayer un texte'; + + @override + String get menuDismissLabel => 'Ignorer le menu'; + + @override + String get expansionTileExpandedHint => 'toucher deux fois pour réduire'; + + @override + String get expansionTileCollapsedHint => 'toucher deux fois pour développer'; + + @override + String get expansionTileCollapsedTapHint => 'Développer le panneau pour plus de détails'; + @override String get scrimLabel => 'Grille'; @@ -15590,7 +16088,7 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Pechar'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Despregado'; @override String get collapsedIconTapHint => 'Despregar'; @@ -15650,22 +16148,22 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { String get drawerLabel => 'Menú de navegación'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Contraído'; @override String get expandedIconTapHint => 'Contraer'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'tocar dúas veces para despregar'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Despregar para obter máis detalles'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'toca dúas veces para contraer'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Contraer'; @override String get firstPageTooltip => 'Primeira páxina'; @@ -15854,13 +16352,13 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licenzas'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Mirar cara arriba'; @override String get menuBarMenuLabel => 'Menú da barra de menú'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Pechar menú'; @override String get modalBarrierDismissLabel => 'Ignorar'; @@ -16077,7 +16575,7 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Schließen'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Maximiert'; @override String get collapsedIconTapHint => 'Maximieren'; @@ -16137,22 +16635,22 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigationsmenü'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Minimiert'; @override String get expandedIconTapHint => 'Minimieren'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'Zum Maximieren doppeltippen'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Für weitere Details maximieren'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'Zum Minimieren doppeltippen'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Minimieren'; @override String get firstPageTooltip => 'Erste Seite'; @@ -16347,7 +16845,7 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menü in der Menüleiste'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menü schließen'; @override String get modalBarrierDismissLabel => 'Schließen'; @@ -16564,7 +17062,7 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'બંધ કરો'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'મોટી કરી'; @override String get collapsedIconTapHint => 'વિસ્તૃત કરો'; @@ -16624,22 +17122,22 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { String get drawerLabel => 'નૅવિગેશન મેનૂ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'નાની કરી'; @override String get expandedIconTapHint => 'સંકુચિત કરો'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'મોટી કરવા માટે બે વાર ટૅપ કરો'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'વધુ વિગતો માટે મોટી કરો'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'નાની કરવા માટે બે વાર ટૅપ કરો'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'નાની કરો'; @override String get firstPageTooltip => 'પહેલું પેજ'; @@ -16834,7 +17332,7 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'મેનૂ બાર મેનૂ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'મેનૂ છોડી દો'; @override String get modalBarrierDismissLabel => 'છોડી દો'; @@ -16921,7 +17419,7 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { String get saveButtonLabel => 'સાચવો'; @override - String get scanTextButtonLabel => 'ટેક્સ્ટ સ્કેન કરો'; + String get scanTextButtonLabel => 'ટેક્સ્ટ સ્કૅન કરો'; @override String get scrimLabel => 'સ્ક્રિમ'; @@ -17051,7 +17549,7 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'סגירה'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'מורחב'; @override String get collapsedIconTapHint => 'הרחבה'; @@ -17111,22 +17609,22 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { String get drawerLabel => 'תפריט ניווט'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'מכווץ'; @override String get expandedIconTapHint => 'כיווץ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'כדי להרחיב, יש להקיש הקשה כפולה'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ניתן להרחיב להצגת פרטים נוספים'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'כדי לכווץ, יש להקיש הקשה כפולה'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'כיווץ'; @override String get firstPageTooltip => 'לדף הראשון'; @@ -17321,7 +17819,7 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'תפריט בסרגל התפריטים'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'סגירת התפריט'; @override String get modalBarrierDismissLabel => 'סגירה'; @@ -17408,7 +17906,7 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { String get saveButtonLabel => 'שמירה'; @override - String get scanTextButtonLabel => 'סרוק טקסט'; + String get scanTextButtonLabel => 'סריקת טקסט'; @override String get scrimLabel => 'מיסוך'; @@ -17538,7 +18036,7 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'बंद करें'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'बड़ा किया गया'; @override String get collapsedIconTapHint => 'बड़ा करें'; @@ -17598,22 +18096,22 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { String get drawerLabel => 'नेविगेशन मेन्यू'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'छोटा किया गया'; @override String get expandedIconTapHint => 'छोटा करें'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'बड़ा करने के लिए दो बार टैप करें'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ज़्यादा जानकारी के लिए बड़ा करें'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'छोटा करने के लिए दो बार टैप करें'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'छोटा करें'; @override String get firstPageTooltip => 'पहला पेज'; @@ -17808,7 +18306,7 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'मेन्यू बार का मेन्यू'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'मेन्यू खारिज करें'; @override String get modalBarrierDismissLabel => 'खारिज करें'; @@ -17895,7 +18393,7 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { String get saveButtonLabel => 'सेव करें'; @override - String get scanTextButtonLabel => 'पाठ स्कैन करें'; + String get scanTextButtonLabel => 'टेक्स्ट स्कैन करें'; @override String get scrimLabel => 'स्क्रिम'; @@ -18025,7 +18523,7 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Zatvaranje'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Prošireno'; @override String get collapsedIconTapHint => 'Proširi'; @@ -18085,22 +18583,22 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigacijski izbornik'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Sažeto'; @override String get expandedIconTapHint => 'Sažmi'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dvaput dodirnite za proširivanje'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Proširite da biste saznali više'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dvaput dodirnite za sažimanje'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Sažmi'; @override String get firstPageTooltip => 'Prva stranica'; @@ -18289,13 +18787,13 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licence'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Pogled prema gore'; @override String get menuBarMenuLabel => 'Izbornik trake izbornika'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Odbacivanje izbornika'; @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -18382,7 +18880,7 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Spremi'; @override - String get scanTextButtonLabel => 'Skeniraj tekst'; + String get scanTextButtonLabel => 'Skeniranje teksta'; @override String get scrimLabel => 'Rubno'; @@ -18512,7 +19010,7 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Bezárás'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Kibontva'; @override String get collapsedIconTapHint => 'Kibontás'; @@ -18572,22 +19070,22 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigációs menü'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Összecsukva'; @override String get expandedIconTapHint => 'Összecsukás'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'duplán koppintva kibonthatja'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Bontsa ki a további részletek megtekintéséhez'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'duplán koppintva összecsukhatja'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Összecsukás'; @override String get firstPageTooltip => 'Első oldal'; @@ -18776,13 +19274,13 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licencek'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Felfelé nézés'; @override String get menuBarMenuLabel => 'Menüsor menüje'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menü bezárása'; @override String get modalBarrierDismissLabel => 'Elvetés'; @@ -18999,7 +19497,7 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Փակել'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Ծավալված է'; @override String get collapsedIconTapHint => 'Ծավալել'; @@ -19059,22 +19557,22 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { String get drawerLabel => 'Նավիգացիայի ընտրացանկ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Ծալված է'; @override String get expandedIconTapHint => 'Ծալել'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'կրկնակի հպեք ծավալելու համար'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ծավալեք՝ մանրամասները տեսնելու համար'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'կրկնակի հպեք ծալելու համար'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Ծալել'; @override String get firstPageTooltip => 'Առաջին էջ'; @@ -19269,7 +19767,7 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Ընտրացանկի գոտու ընտրացանկ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Փակել ընտրացանկը'; @override String get modalBarrierDismissLabel => 'Փակել'; @@ -19356,7 +19854,7 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Պահել'; @override - String get scanTextButtonLabel => 'Սկանավորեք տեքստը'; + String get scanTextButtonLabel => 'Սկանավորել տեքստ'; @override String get scrimLabel => 'Դիմակ'; @@ -19486,7 +19984,7 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Tutup'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Diluaskan'; @override String get collapsedIconTapHint => 'Luaskan'; @@ -19546,22 +20044,22 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu navigasi'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Diciutkan'; @override String get expandedIconTapHint => 'Ciutkan'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ketuk dua kali untuk meluaskan'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Luaskan untuk mengetahui detail selengkapnya'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ketuk dua kali untuk menciutkan'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Ciutkan'; @override String get firstPageTooltip => 'Halaman pertama'; @@ -19756,7 +20254,7 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menu panel menu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Tutup menu'; @override String get modalBarrierDismissLabel => 'Tutup'; @@ -19973,7 +20471,7 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Loka'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Stækkað'; @override String get collapsedIconTapHint => 'Stækka'; @@ -20033,22 +20531,22 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { String get drawerLabel => 'Yfirlitsvalmynd'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Minnkað'; @override String get expandedIconTapHint => 'Draga saman'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ýttu tvisvar til að stækka'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Stækka til að sjá frekari upplýsingar'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ýttu tvisvar til að minnka'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Minnka'; @override String get firstPageTooltip => 'Fyrsta síða'; @@ -20243,7 +20741,7 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Valmyndarstika'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Loka valmynd'; @override String get modalBarrierDismissLabel => 'Hunsa'; @@ -20330,7 +20828,7 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Vista'; @override - String get scanTextButtonLabel => 'Skannaðu texta'; + String get scanTextButtonLabel => 'Skanna texta'; @override String get scrimLabel => 'Möskvi'; @@ -20460,7 +20958,7 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Chiudi'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Espanso'; @override String get collapsedIconTapHint => 'Espandi'; @@ -20520,22 +21018,22 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu di navigazione'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Compresso'; @override String get expandedIconTapHint => 'Comprimi'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'Tocca due volte per espandere'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'espandere e visualizzare altri dettagli'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'tocca due volte per comprimere'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'comprimere'; @override String get firstPageTooltip => 'Prima pagina'; @@ -20724,13 +21222,13 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licenze'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Cerca'; @override String get menuBarMenuLabel => 'Menu barra dei menu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ignora menu'; @override String get modalBarrierDismissLabel => 'Ignora'; @@ -20817,7 +21315,7 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Salva'; @override - String get scanTextButtonLabel => 'Scansiona il testo'; + String get scanTextButtonLabel => 'Scansiona testo'; @override String get scrimLabel => 'Rete'; @@ -20947,7 +21445,7 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { String get closeButtonTooltip => '閉じる'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => '開きました'; @override String get collapsedIconTapHint => '展開'; @@ -21007,22 +21505,22 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { String get drawerLabel => 'ナビゲーション メニュー'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => '閉じました'; @override String get expandedIconTapHint => '折りたたむ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => '開くにはダブルタップします'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => '開いて詳細を表示'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ダブルタップすると閉じます'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => '閉じる'; @override String get firstPageTooltip => '最初のページ'; @@ -21211,13 +21709,13 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { String get licensesPageTitle => 'ライセンス'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => '調べる'; @override String get menuBarMenuLabel => 'メニューバーのメニュー'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'メニューを閉じる'; @override String get modalBarrierDismissLabel => '閉じる'; @@ -21434,7 +21932,7 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'დახურვა'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'გაფართოებულია'; @override String get collapsedIconTapHint => 'გაშლა'; @@ -21494,22 +21992,22 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { String get drawerLabel => 'ნავიგაციის მენიუ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ჩაკეცილია'; @override String get expandedIconTapHint => 'ჩაკეცვა'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'გასაფართოებლად ორჯერ შეეხეთ'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'მეტი დეტალებისთვის გააფართოეთ'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ორმაგად შეეხეთ ჩასაკეცად'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ჩაკეცვა'; @override String get firstPageTooltip => 'პირველი გვერდი'; @@ -21704,7 +22202,7 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'მენიუს ზოლის მენიუ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'მენიუს უარყოფა'; @override String get modalBarrierDismissLabel => 'დახურვა'; @@ -21921,7 +22419,7 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Жабу'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Жайылды'; @override String get collapsedIconTapHint => 'Жаю'; @@ -21981,22 +22479,22 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { String get drawerLabel => 'Навигация мәзірі'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Жиылды'; @override String get expandedIconTapHint => 'Жию'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'жаю үшін екі рет түртіңіз'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Толық мәлімет алу үшін жайыңыз.'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'жию үшін екі рет түртіңіз'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Жию'; @override String get firstPageTooltip => 'Бірінші бет'; @@ -22191,7 +22689,7 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Мәзір жолағының мәзірі'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Мәзірді жабу'; @override String get modalBarrierDismissLabel => 'Жабу'; @@ -22408,7 +22906,7 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'បិទ'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'បាន​ពង្រីក'; @override String get collapsedIconTapHint => 'ពង្រីក'; @@ -22468,22 +22966,22 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { String get drawerLabel => 'ម៉ឺនុយរុករក'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'បាន​បង្រួម'; @override String get expandedIconTapHint => 'បង្រួម'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ចុចពីរដង ដើម្បីពង្រីក'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ពង្រីក​ដើម្បីទទួលបាន​ព័ត៌មានលម្អិត​បន្ថែម'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ចុចពីរដង ដើម្បីបង្រួម'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'បង្រួម'; @override String get firstPageTooltip => 'ទំព័រ​ដំបូង'; @@ -22672,13 +23170,13 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { String get licensesPageTitle => 'អាជ្ញាបណ្ណ'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'រកមើល'; @override String get menuBarMenuLabel => 'ម៉ឺនុយរបារម៉ឺនុយ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ច្រានចោល​ម៉ឺនុយ'; @override String get modalBarrierDismissLabel => 'ច្រាន​ចោល'; @@ -22765,7 +23263,7 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { String get saveButtonLabel => 'រក្សាទុក'; @override - String get scanTextButtonLabel => 'ស្កេនអត្ថបទ'; + String get scanTextButtonLabel => 'ស្កេន​អក្សរ'; @override String get scrimLabel => 'ផ្ទាំងស្រអាប់'; @@ -22895,7 +23393,7 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { String get closeButtonTooltip => '\u{cae}\u{cc1}\u{c9a}\u{ccd}\u{c9a}\u{cbf}\u{cb0}\u{cbf}'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => '\u{cb5}\u{cbf}\u{cb8}\u{ccd}\u{ca4}\u{cb0}\u{cbf}\u{cb8}\u{cb2}\u{cbe}\u{c97}\u{cbf}\u{ca6}\u{cc6}'; @override String get collapsedIconTapHint => '\u{cb5}\u{cbf}\u{cb8}\u{ccd}\u{ca4}\u{cb0}\u{cbf}\u{cb8}\u{cbf}'; @@ -22955,22 +23453,22 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { String get drawerLabel => '\u{ca8}\u{ccd}\u{caf}\u{cbe}\u{cb5}\u{cbf}\u{c97}\u{cc7}\u{cb6}\u{ca8}\u{ccd}\u{200c}\u{20}\u{cae}\u{cc6}\u{ca8}\u{cc1}'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => '\u{c95}\u{cc1}\u{c97}\u{ccd}\u{c97}\u{cbf}\u{cb8}\u{cb2}\u{cbe}\u{c97}\u{cbf}\u{ca6}\u{cc6}'; @override String get expandedIconTapHint => '\u{c95}\u{cc1}\u{c97}\u{ccd}\u{c97}\u{cbf}\u{cb8}\u{cbf}'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => '\u{cb5}\u{cbf}\u{cb8}\u{ccd}\u{ca4}\u{cb0}\u{cbf}\u{cb8}\u{cb2}\u{cc1}\u{20}\u{ca1}\u{cac}\u{cb2}\u{ccd}\u{20}\u{c9f}\u{ccd}\u{caf}\u{cbe}\u{caa}\u{ccd}\u{20}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => '\u{c87}\u{ca8}\u{ccd}\u{ca8}\u{cb7}\u{ccd}\u{c9f}\u{cc1}\u{20}\u{cb5}\u{cbf}\u{cb5}\u{cb0}\u{c97}\u{cb3}\u{cbf}\u{c97}\u{cbe}\u{c97}\u{cbf}\u{20}\u{cb5}\u{cbf}\u{cb8}\u{ccd}\u{ca4}\u{cb0}\u{cbf}\u{cb8}\u{cbf}'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => '\u{c95}\u{cc1}\u{c97}\u{ccd}\u{c97}\u{cbf}\u{cb8}\u{cb2}\u{cc1}\u{20}\u{ca1}\u{cac}\u{cb2}\u{ccd}\u{20}\u{c9f}\u{ccd}\u{caf}\u{cbe}\u{caa}\u{ccd}\u{20}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => '\u{c95}\u{cc1}\u{c97}\u{ccd}\u{c97}\u{cbf}\u{cb8}\u{cbf}'; @override String get firstPageTooltip => '\u{cae}\u{cca}\u{ca6}\u{cb2}\u{20}\u{caa}\u{cc1}\u{c9f}'; @@ -23165,7 +23663,7 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { String get menuBarMenuLabel => '\u{cae}\u{cc6}\u{ca8}\u{cc1}\u{20}\u{cac}\u{cbe}\u{cb0}\u{ccd}\u{200c}\u{20}\u{cae}\u{cc6}\u{ca8}\u{cc1}'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => '\u{cae}\u{cc6}\u{ca8}\u{cc1}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc1}\u{20}\u{cb5}\u{c9c}\u{cbe}\u{c97}\u{cc6}\u{cc2}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; @override String get modalBarrierDismissLabel => '\u{cb5}\u{c9c}\u{cbe}\u{c97}\u{cca}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; @@ -23249,7 +23747,7 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { String get rowsPerPageTitle => '\u{caa}\u{ccd}\u{cb0}\u{ca4}\u{cbf}\u{20}\u{caa}\u{cc1}\u{c9f}\u{c95}\u{ccd}\u{c95}\u{cc6}\u{20}\u{cb8}\u{cbe}\u{cb2}\u{cc1}\u{c97}\u{cb3}\u{cc1}\u{3a}'; @override - String get saveButtonLabel => '\u{c89}\u{cb3}\u{cbf}\u{cb8}\u{cbf}'; + String get saveButtonLabel => '\u{cb8}\u{cc7}\u{cb5}\u{ccd}\u{20}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; @override String get scanTextButtonLabel => '\u{caa}\u{ca0}\u{ccd}\u{caf}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc1}\u{20}\u{cb8}\u{ccd}\u{c95}\u{ccd}\u{caf}\u{cbe}\u{ca8}\u{ccd}\u{20}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; @@ -23382,7 +23880,7 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { String get closeButtonTooltip => '닫기'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => '펼침'; @override String get collapsedIconTapHint => '펼치기'; @@ -23442,22 +23940,22 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { String get drawerLabel => '탐색 메뉴'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => '접힘'; @override String get expandedIconTapHint => '접기'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => '두 번 탭하여 펼치기'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => '자세히 알아보려면 펼치기'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => '두 번 탭하여 접기'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => '접기'; @override String get firstPageTooltip => '첫 페이지'; @@ -23652,7 +24150,7 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { String get menuBarMenuLabel => '메뉴 바 메뉴'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => '메뉴 닫기'; @override String get modalBarrierDismissLabel => '닫기'; @@ -23739,7 +24237,7 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { String get saveButtonLabel => '저장'; @override - String get scanTextButtonLabel => '스캔 텍스트'; + String get scanTextButtonLabel => '텍스트 스캔'; @override String get scrimLabel => '스크림'; @@ -23869,7 +24367,7 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Жабуу'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Жайылып көрсөтүлдү'; @override String get collapsedIconTapHint => 'Жайып көрсөтүү'; @@ -23929,22 +24427,22 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { String get drawerLabel => 'Чабыттоо менюсу'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Жыйыштырылды'; @override String get expandedIconTapHint => 'Жыйыштыруу'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'жайып көрсөтүү үчүн эки жолу таптаңыз'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Толук маалымат алуу үчүн жайып көрүңүз'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'жыйыштыруу үчүн эки жолу таптаңыз'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Жыйыштыруу'; @override String get firstPageTooltip => 'Биринчи бет'; @@ -24139,7 +24637,7 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Меню тилкеси менюсу'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Менюну жабуу'; @override String get modalBarrierDismissLabel => 'Жабуу'; @@ -24356,7 +24854,7 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'ປິດ'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ຂະຫຍາຍແລ້ວ'; @override String get collapsedIconTapHint => 'ຂະຫຍາຍ'; @@ -24416,22 +24914,22 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { String get drawerLabel => 'ເມນູນຳທາງ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ຫຍໍ້ລົງແລ້ວ'; @override String get expandedIconTapHint => 'ຫຍໍ້ເຂົ້າ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ແຕະສອງເທື່ອເພື່ອຂະຫຍາຍ'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ຂະຫຍາຍສຳລັບຂໍ້ມູນເພີ່ມເຕີມ'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ແຕະສອງເທື່ອເພື່ອຫຍໍ້ລົງ'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ຫຍໍ້ລົງ'; @override String get firstPageTooltip => 'ໜ້າທຳອິດ'; @@ -24626,7 +25124,7 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'ເມນູແຖບເມນູ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ປິດເມນູ'; @override String get modalBarrierDismissLabel => 'ປິດໄວ້'; @@ -24843,7 +25341,7 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Uždaryti'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Išskleista'; @override String get collapsedIconTapHint => 'Išskleisti'; @@ -24903,22 +25401,22 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { String get drawerLabel => 'Naršymo meniu'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Sutraukta'; @override String get expandedIconTapHint => 'Sutraukti'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dukart palieskite, kad išskleistumėte'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Išskleiskite, jei reikia daugiau išsamios informacijos'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dukart palieskite, kad sutrauktumėte'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Sutraukti'; @override String get firstPageTooltip => 'Pirmas puslapis'; @@ -25113,7 +25611,7 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Meniu juostos meniu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Atsisakyti meniu'; @override String get modalBarrierDismissLabel => 'Atsisakyti'; @@ -25330,7 +25828,7 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Aizvērt'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Izvērsts'; @override String get collapsedIconTapHint => 'Izvērst'; @@ -25390,22 +25888,22 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigācijas izvēlne'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Sakļauts'; @override String get expandedIconTapHint => 'Sakļaut'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dubultskāriens, lai izvērstu'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Izvērst, lai iegūtu plašāku informāciju'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dubultskāriens, lai sakļautu'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Sakļaut'; @override String get firstPageTooltip => 'Pirmā lapa'; @@ -25600,7 +26098,7 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Izvēļņu joslas izvēlne'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Nerādīt izvēlni'; @override String get modalBarrierDismissLabel => 'Nerādīt'; @@ -25817,7 +26315,7 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Затвори'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Проширено'; @override String get collapsedIconTapHint => 'Прошири'; @@ -25877,28 +26375,28 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { String get drawerLabel => 'Мени за навигација'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Собрано'; @override String get expandedIconTapHint => 'Собери'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'допри двапати за проширување'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Прошири за повеќе детали'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'допрете двапати за собирање'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Собери'; @override String get firstPageTooltip => 'Прва страница'; @override - String get hideAccountsLabel => 'Сокриј сметки'; + String get hideAccountsLabel => 'Скриј сметки'; @override String get inputDateModeButtonLabel => 'Префрли на внесување'; @@ -26087,7 +26585,7 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Мени на лентата со мени'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Отфрлете го менито'; @override String get modalBarrierDismissLabel => 'Отфрли'; @@ -26174,7 +26672,7 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Зачувај'; @override - String get scanTextButtonLabel => 'Скенирајте текст'; + String get scanTextButtonLabel => 'Скенирајте го текстот'; @override String get scrimLabel => 'Скрим'; @@ -26304,7 +26802,7 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'അടയ്‌ക്കുക'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'വികസിപ്പിച്ചു'; @override String get collapsedIconTapHint => 'വികസിപ്പിക്കുക'; @@ -26364,22 +26862,22 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { String get drawerLabel => 'നാവിഗേഷൻ മെനു'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ചുരുക്കി'; @override String get expandedIconTapHint => 'ചുരുക്കുക'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'വികസിപ്പിക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'കൂടുതൽ വിശദാംശങ്ങൾക്ക് വികസിപ്പിക്കുക'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ചുരുക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ചുരുക്കുക'; @override String get firstPageTooltip => 'ആദ്യ പേജ്'; @@ -26568,13 +27066,13 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { String get licensesPageTitle => 'ലൈസൻസുകൾ'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'മുകളിലേക്ക് നോക്കുക'; @override String get menuBarMenuLabel => 'മെനു ബാർ മെനു'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'മെനു ഡിസ്മിസ് ചെയ്യുക'; @override String get modalBarrierDismissLabel => 'നിരസിക്കുക'; @@ -26661,7 +27159,7 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { String get saveButtonLabel => 'സംരക്ഷിക്കുക'; @override - String get scanTextButtonLabel => 'ടെക്സ്റ്റ് സ്കാൻ ചെയ്യുക'; + String get scanTextButtonLabel => 'ടെക്സ്റ്റ് സ്‌കാൻ ചെയ്യുക'; @override String get scrimLabel => 'സ്ക്രിം'; @@ -26791,7 +27289,7 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Хаах'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Дэлгэсэн'; @override String get collapsedIconTapHint => 'Дэлгэх'; @@ -26851,22 +27349,22 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { String get drawerLabel => 'Навигацын цэс'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Хураасан'; @override String get expandedIconTapHint => 'Буулгах'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'дэлгэхийн тулд хоёр товшино уу'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Илүү дэлгэрэнгүй авах бол дэлгэнэ үү'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'хураахын тулд хоёр товшино уу'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Хураах'; @override String get firstPageTooltip => 'Эхний хуудас'; @@ -27061,7 +27559,7 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Цэсний талбарын цэс'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Цэсийг хаах'; @override String get modalBarrierDismissLabel => 'Үл хэрэгсэх'; @@ -27148,7 +27646,7 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Хадгалах'; @override - String get scanTextButtonLabel => 'Текст сканнердах'; + String get scanTextButtonLabel => 'Текстийг скан хийх'; @override String get scrimLabel => 'Скрим'; @@ -27278,7 +27776,7 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'बंद करा'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'विस्तार केले'; @override String get collapsedIconTapHint => 'विस्तार करा'; @@ -27338,22 +27836,22 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { String get drawerLabel => 'नेव्हिगेशन मेनू'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'कोलॅप्स केले'; @override String get expandedIconTapHint => 'कोलॅप्स करा'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'विस्तार करण्‍यासाठी दोनदा टॅप करा'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'आणखी तपशिलांसाठी विस्तार करा'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'कोलॅप्स करण्यासाठी दोनदा टॅप करा'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'कोलॅप्स करा'; @override String get firstPageTooltip => 'पहिले पेज'; @@ -27548,7 +28046,7 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'मेनू बार मेनू'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'मेनू डिसमिस करा'; @override String get modalBarrierDismissLabel => 'डिसमिस करा'; @@ -27765,7 +28263,7 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Tutup'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Dikembangkan'; @override String get collapsedIconTapHint => 'Kembangkan'; @@ -27825,22 +28323,22 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu navigasi'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Dikuncupkan'; @override String get expandedIconTapHint => 'Runtuhkan'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ketik dua kali untuk kembangkan'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Kembangkan untuk mendapatkan butiran lanjut'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ketik dua kali untuk kuncupkan'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Kuncupkan'; @override String get firstPageTooltip => 'Halaman pertama'; @@ -28029,13 +28527,13 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Lesen'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Lihat ke Atas'; @override String get menuBarMenuLabel => 'Menu bar menu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ketepikan menu'; @override String get modalBarrierDismissLabel => 'Tolak'; @@ -28122,7 +28620,7 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Simpan'; @override - String get scanTextButtonLabel => 'Pindai teks'; + String get scanTextButtonLabel => 'Imbas teks'; @override String get scrimLabel => 'Scrim'; @@ -28252,7 +28750,7 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'ပိတ်ရန်'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ဖြန့်ထားသည်'; @override String get collapsedIconTapHint => 'ချဲ့ရန်'; @@ -28312,22 +28810,22 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { String get drawerLabel => 'လမ်းညွှန် မီနူး'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ခေါက်ထားသည်'; @override String get expandedIconTapHint => 'လျှော့ပြရန်'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ဖြန့်ရန် နှစ်ချက်တို့ပါ'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'အသေးစိတ်အတွက် ဖြန့်ရန်'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ခေါက်ရန် နှစ်ချက်တို့ပါ'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ခေါက်ရန်'; @override String get firstPageTooltip => 'ပထမ စာမျက်နှာ'; @@ -28522,7 +29020,7 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'မီနူးဘား မီနူး'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'မီနူးကိုပယ်ပါ'; @override String get modalBarrierDismissLabel => 'ပယ်ရန်'; @@ -28609,7 +29107,7 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { String get saveButtonLabel => 'သိမ်းရန်'; @override - String get scanTextButtonLabel => 'စာသားကို စကင်ဖတ်ပါ။'; + String get scanTextButtonLabel => 'စာသား စကင်ဖတ်ရန်'; @override String get scrimLabel => 'Scrim'; @@ -28739,7 +29237,7 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Lukk'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Vises'; @override String get collapsedIconTapHint => 'Vis'; @@ -28799,22 +29297,22 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigasjonsmeny'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Skjules'; @override String get expandedIconTapHint => 'Skjul'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dobbelttrykk for å vise'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Vis for å se mer informasjon'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dobbelttrykk for å skjule'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Skjul'; @override String get firstPageTooltip => 'Første side'; @@ -29009,7 +29507,7 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Meny med menylinje'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Lukk menyen'; @override String get modalBarrierDismissLabel => 'Avvis'; @@ -29096,7 +29594,7 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Lagre'; @override - String get scanTextButtonLabel => 'Scan tekst'; + String get scanTextButtonLabel => 'Skann tekst'; @override String get scrimLabel => 'Vev'; @@ -29226,7 +29724,7 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'बन्द गर्नुहोस्'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'एक्स्पान्ड गरियो'; @override String get collapsedIconTapHint => 'विस्तार गर्नुहोस्'; @@ -29286,22 +29784,22 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { String get drawerLabel => 'नेभिगेसन मेनु'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'कोल्याप्स गरियो'; @override String get expandedIconTapHint => 'संक्षिप्त गर्नुहोस्'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'एक्स्पान्ड गर्न डबल ट्याप गर्नुहोस्'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'थप विवरण हेर्न एक्स्पान्ड गर्नुहोस्'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'कोल्याप्स गर्न डबल ट्याप गर्नुहोस्'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'कोल्याप्स गर्नुहोस्'; @override String get firstPageTooltip => 'प्रथम पेज'; @@ -29496,7 +29994,7 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { String get menuBarMenuLabel => '"मेनु बार" मेनु'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'मेनु खारेज गर्नुहोस्'; @override String get modalBarrierDismissLabel => 'खारेज गर्नुहोस्'; @@ -29508,7 +30006,7 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { String get nextMonthTooltip => 'अर्को महिना'; @override - String get nextPageTooltip => 'अर्को पृष्ठ'; + String get nextPageTooltip => 'अर्को पेज'; @override String get okButtonLabel => 'ठिक छ'; @@ -29583,7 +30081,7 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { String get saveButtonLabel => 'सेभ गर्नुहोस्'; @override - String get scanTextButtonLabel => 'पाठ स्क्यान गर्नुहोस्'; + String get scanTextButtonLabel => 'टेक्स्ट स्क्यान गर्नुहोस्'; @override String get scrimLabel => 'स्क्रिम'; @@ -29713,7 +30211,7 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Sluiten'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Uitgevouwen'; @override String get collapsedIconTapHint => 'Uitvouwen'; @@ -29773,22 +30271,22 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigatiemenu'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Samengevouwen'; @override String get expandedIconTapHint => 'Samenvouwen'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dubbeltik om uit te vouwen'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Uitvouwen voor meer informatie'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dubbeltik om samen te vouwen'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Samenvouwen'; @override String get firstPageTooltip => 'Eerste pagina'; @@ -29983,7 +30481,7 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menu van menubalk'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menu sluiten'; @override String get modalBarrierDismissLabel => 'Sluiten'; @@ -30200,7 +30698,7 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Lukk'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Vises'; @override String get collapsedIconTapHint => 'Vis'; @@ -30260,22 +30758,22 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigasjonsmeny'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Skjules'; @override String get expandedIconTapHint => 'Skjul'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'dobbelttrykk for å vise'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Vis for å se mer informasjon'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'dobbelttrykk for å skjule'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Skjul'; @override String get firstPageTooltip => 'Første side'; @@ -30470,7 +30968,7 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Meny med menylinje'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Lukk menyen'; @override String get modalBarrierDismissLabel => 'Avvis'; @@ -30687,7 +31185,7 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'ବନ୍ଦ କରନ୍ତୁ'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ବିସ୍ତାର କରାଯାଇଛି'; @override String get collapsedIconTapHint => 'ପ୍ରସାରିତ କରନ୍ତୁ'; @@ -30747,22 +31245,22 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { String get drawerLabel => 'ନେଭିଗେସନ୍ ମେନୁ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ସଙ୍କୁଚିତ କରାଯାଇଛି'; @override String get expandedIconTapHint => 'ସଙ୍କୁଚିତ କରନ୍ତୁ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ବିସ୍ତାର କରିବା ପାଇଁ ଦୁଇଥର ଟାପ କରନ୍ତୁ'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ଅଧିକ ବିବରଣୀ ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ସଙ୍କୁଚିତ କରିବା ପାଇଁ ଦୁଇଥର ଟାପ କରନ୍ତୁ'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ସଙ୍କୁଚିତ କରନ୍ତୁ'; @override String get firstPageTooltip => 'ପ୍ରଥମ ପୃଷ୍ଠା'; @@ -30957,7 +31455,7 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'ମେନୁ ବାର ମେନୁ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ମେନୁ ଖାରଜ କରନ୍ତୁ'; @override String get modalBarrierDismissLabel => 'ଖାରଜ କରନ୍ତୁ'; @@ -31044,7 +31542,7 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'ସେଭ କରନ୍ତୁ'; @override - String get scanTextButtonLabel => 'ପାଠ୍ୟ ସ୍କାନ୍ କରନ୍ତୁ'; + String get scanTextButtonLabel => 'ଟେକ୍ସଟ୍ ସ୍କାନ୍ କରନ୍ତୁ'; @override String get scrimLabel => 'ସ୍କ୍ରିମ'; @@ -31174,7 +31672,7 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'ਬੰਦ ਕਰੋ'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ'; @override String get collapsedIconTapHint => 'ਵਿਸਤਾਰ ਕਰੋ'; @@ -31234,22 +31732,22 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { String get drawerLabel => 'ਨੈਵੀਗੇਸ਼ਨ ਮੀਨੂ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ਸਮੇਟਿਆ ਗਿਆ'; @override String get expandedIconTapHint => 'ਸਮੇਟੋ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'ਵਿਸਤਾਰ ਕਰਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ਹੋਰ ਵੇਰਵਿਆਂ ਲਈ ਵਿਸਤਾਰ ਕਰੋ'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'ਸਮੇਟਣ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ਸਮੇਟੋ'; @override String get firstPageTooltip => 'ਪਹਿਲਾ ਪੰਨਾ'; @@ -31444,7 +31942,7 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'ਮੀਨੂ ਬਾਰ ਮੀਨੂ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ਮੀਨੂ ਖਾਰਜ ਕਰੋ'; @override String get modalBarrierDismissLabel => 'ਖਾਰਜ ਕਰੋ'; @@ -31531,7 +32029,7 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { String get saveButtonLabel => 'ਰੱਖਿਅਤ ਕਰੋ'; @override - String get scanTextButtonLabel => 'ਟੈਕਸਟ ਸਕੈਨ ਕਰੋ'; + String get scanTextButtonLabel => 'ਲਿਖਤ ਨੂੰ ਸਕੈਨ ਕਰੋ'; @override String get scrimLabel => 'ਸਕ੍ਰਿਮ'; @@ -31661,7 +32159,7 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Zamknij'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Rozwinięto'; @override String get collapsedIconTapHint => 'Rozwiń'; @@ -31721,22 +32219,22 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu nawigacyjne'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Zwinięto'; @override String get expandedIconTapHint => 'Zwiń'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'kliknij dwukrotnie, aby rozwinąć'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Rozwiń, aby wyświetlić więcej informacji'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'kliknij dwukrotnie, aby zwinąć'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Zwiń'; @override String get firstPageTooltip => 'Pierwsza strona'; @@ -31925,13 +32423,13 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licencje'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Sprawdź'; @override String get menuBarMenuLabel => 'Pasek menu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Zamknij menu'; @override String get modalBarrierDismissLabel => 'Zamknij'; @@ -32018,7 +32516,7 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Zapisz'; @override - String get scanTextButtonLabel => 'Zeskanuj tekst'; + String get scanTextButtonLabel => 'Skanuj tekst'; @override String get scrimLabel => 'Siatka'; @@ -32635,7 +33133,7 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Fechar'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Aberto.'; @override String get collapsedIconTapHint => 'Abrir'; @@ -32686,7 +33184,7 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { String get deleteButtonTooltip => 'Excluir'; @override - String get dialModeButtonLabel => 'Alternar para o modo de seleção de discagem'; + String get dialModeButtonLabel => 'Mudar para o modo de seleção de discagem'; @override String get dialogLabel => 'Caixa de diálogo'; @@ -32695,22 +33193,22 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu de navegação'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Fechado.'; @override String get expandedIconTapHint => 'Recolher'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'Toque duas vezes para abrir'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Abra para mostrar mais detalhes'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'toque duas vezes para fechar'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Feche'; @override String get firstPageTooltip => 'Primeira página'; @@ -32722,7 +33220,7 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { String get inputDateModeButtonLabel => 'Mudar para modo de entrada'; @override - String get inputTimeModeButtonLabel => 'Alternar para o modo de entrada de texto'; + String get inputTimeModeButtonLabel => 'Mudar para o modo de entrada de texto'; @override String get invalidDateFormatLabel => 'Formato inválido.'; @@ -32899,13 +33397,13 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Licenças'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Pesquisar'; @override String get menuBarMenuLabel => 'Menu da barra de menus'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Dispensar menu'; @override String get modalBarrierDismissLabel => 'Dispensar'; @@ -33094,6 +33592,30 @@ class MaterialLocalizationPtPt extends MaterialLocalizationPt { required super.twoDigitZeroPaddedFormat, }); + @override + String get lookUpButtonLabel => 'Procurar'; + + @override + String get menuDismissLabel => 'Ignorar menu'; + + @override + String get expansionTileExpandedHint => 'toque duas vezes para reduzir'; + + @override + String get expansionTileCollapsedHint => 'toque duas vezes para expandir'; + + @override + String get expansionTileExpandedTapHint => 'Reduzir'; + + @override + String get expansionTileCollapsedTapHint => 'Expandir para obter mais detalhes'; + + @override + String get expandedHint => 'Reduzido'; + + @override + String get collapsedHint => 'Expandido'; + @override String get bottomSheetLabel => 'Secção inferior'; @@ -33273,7 +33795,7 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Închideți'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Extins'; @override String get collapsedIconTapHint => 'Extindeți'; @@ -33333,22 +33855,22 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { String get drawerLabel => 'Meniu de navigare'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Restrâns'; @override String get expandedIconTapHint => 'Restrângeți'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'atingeți de două ori pentru a extinde'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Extindeți pentru mai multe detalii'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'atingeți de două ori pentru a restrânge'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Restrângeți'; @override String get firstPageTooltip => 'Prima pagină'; @@ -33543,7 +34065,7 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Bară de meniu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Respingeți meniul'; @override String get modalBarrierDismissLabel => 'Închideți'; @@ -33760,7 +34282,7 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Закрыть'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Развернуто'; @override String get collapsedIconTapHint => 'Развернуть'; @@ -33820,22 +34342,22 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { String get drawerLabel => 'Меню навигации'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Свернуто'; @override String get expandedIconTapHint => 'Свернуть'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'нажмите дважды, чтобы развернуть'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Развернуть дополнительные сведения'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'нажмите дважды, чтобы свернуть'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Свернуть'; @override String get firstPageTooltip => 'Первая страница'; @@ -34030,7 +34552,7 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Строка меню'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Закрыть меню'; @override String get modalBarrierDismissLabel => 'Закрыть'; @@ -34247,7 +34769,7 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'වසන්න'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'දිග හරින ලදි'; @override String get collapsedIconTapHint => 'දිග හරින්න'; @@ -34307,22 +34829,22 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { String get drawerLabel => 'සංචාලන මෙනුව'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'හකුළන ලදි'; @override String get expandedIconTapHint => 'හකුළන්න'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'විහිදුවීමට දෙවරක් තට්ටු කරන්න'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'වැඩි විස්තර සඳහා පුළුල් කරන්න'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'හැකිළවීමට දෙවරක් තට්ටු කරන්න'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'හකුළන්න'; @override String get firstPageTooltip => 'පළමු පිටුව'; @@ -34517,7 +35039,7 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'මෙනු තීරු මෙනුව'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'මෙනුව අස් කරන්න'; @override String get modalBarrierDismissLabel => 'ඉවත ලන්න'; @@ -34604,7 +35126,7 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { String get saveButtonLabel => 'සුරකින්න'; @override - String get scanTextButtonLabel => 'පෙළ පරිලෝකනය කරන්න'; + String get scanTextButtonLabel => 'පෙළ ස්කෑන් කරන්න'; @override String get scrimLabel => 'ස්ක්‍රිම්'; @@ -34734,7 +35256,7 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Zavrieť'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Rozbalené'; @override String get collapsedIconTapHint => 'Rozbaliť'; @@ -34794,22 +35316,22 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigačná ponuka'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Zbalené'; @override String get expandedIconTapHint => 'Zbaliť'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'rozbalíte dvojitým klepnutím'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Rozbaliť a zobraziť ďalšie podrobnosti'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'zbalíte dvojitým klepnutím'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Zbaliť'; @override String get firstPageTooltip => 'Prvá strana'; @@ -35004,7 +35526,7 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Ponuka panela s ponukami'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Zavrieť ponuku'; @override String get modalBarrierDismissLabel => 'Odmietnuť'; @@ -35091,7 +35613,7 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Uložiť'; @override - String get scanTextButtonLabel => 'Naskenujte text'; + String get scanTextButtonLabel => 'Naskenovať text'; @override String get scrimLabel => 'Scrim'; @@ -35221,7 +35743,7 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Zapiranje'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Razširjeno'; @override String get collapsedIconTapHint => 'Razširiti'; @@ -35281,22 +35803,22 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { String get drawerLabel => 'Meni za krmarjenje'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Strnjeno'; @override String get expandedIconTapHint => 'Strniti'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'za razširitev se dvakrat dotaknite'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Razširitev za več podrobnosti'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'za strnitev se dvakrat dotaknite'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Strni'; @override String get firstPageTooltip => 'Prva stran'; @@ -35491,7 +36013,7 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Meni menijske vrstice'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Opusti meni'; @override String get modalBarrierDismissLabel => 'Opusti'; @@ -35578,7 +36100,7 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Shrani'; @override - String get scanTextButtonLabel => 'Skeniraj besedilo'; + String get scanTextButtonLabel => 'Optično preberite besedilo'; @override String get scrimLabel => 'Scrim'; @@ -35708,7 +36230,7 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Mbyll'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'U zgjerua'; @override String get collapsedIconTapHint => 'Zgjero'; @@ -35768,22 +36290,22 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { String get drawerLabel => 'Menyja e navigimit'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'U palos'; @override String get expandedIconTapHint => 'Palos'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'trokit dy herë për ta zgjeruar'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Zgjero për më shumë detaje'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'trokit dy herë për ta palosur'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Palos'; @override String get firstPageTooltip => 'Faqja e parë'; @@ -35978,7 +36500,7 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menyja e shiritit të menysë'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Hiqe menynë'; @override String get modalBarrierDismissLabel => 'Hiq'; @@ -36065,7 +36587,7 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Ruaj'; @override - String get scanTextButtonLabel => 'Skanoni tekstin'; + String get scanTextButtonLabel => 'Skano tekstin'; @override String get scrimLabel => 'Kanavacë'; @@ -36195,7 +36717,7 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Затворите'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Проширено је'; @override String get collapsedIconTapHint => 'Прошири'; @@ -36255,22 +36777,22 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { String get drawerLabel => 'Мени за навигацију'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Скупљено је'; @override String get expandedIconTapHint => 'Скупи'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'двапут додирните да бисте проширили'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Проширите за још детаља'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'двапут додирните да бисте скупили'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Скупите'; @override String get firstPageTooltip => 'Прва страница'; @@ -36465,7 +36987,7 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Мени трака менија'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Одбаците мени'; @override String get modalBarrierDismissLabel => 'Одбаци'; @@ -36552,7 +37074,7 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Сачувај'; @override - String get scanTextButtonLabel => 'Скенирајте текст'; + String get scanTextButtonLabel => 'Скенирај текст'; @override String get scrimLabel => 'Скрим'; @@ -36700,6 +37222,9 @@ class MaterialLocalizationSrLatn extends MaterialLocalizationSr { @override String get closeButtonTooltip => 'Zatvorite'; + @override + String get collapsedHint => 'Prošireno je'; + @override String get collapsedIconTapHint => 'Proširi'; @@ -36754,9 +37279,24 @@ class MaterialLocalizationSrLatn extends MaterialLocalizationSr { @override String get drawerLabel => 'Meni za navigaciju'; + @override + String get expandedHint => 'Skupljeno je'; + @override String get expandedIconTapHint => 'Skupi'; + @override + String get expansionTileCollapsedHint => 'dvaput dodirnite da biste proširili'; + + @override + String get expansionTileCollapsedTapHint => 'Proširite za još detalja'; + + @override + String get expansionTileExpandedHint => 'dvaput dodirnite da biste skupili'; + + @override + String get expansionTileExpandedTapHint => 'Skupite'; + @override String get firstPageTooltip => 'Prva stranica'; @@ -36811,6 +37351,9 @@ class MaterialLocalizationSrLatn extends MaterialLocalizationSr { @override String get menuBarMenuLabel => 'Meni traka menija'; + @override + String get menuDismissLabel => 'Odbacite meni'; + @override String get modalBarrierDismissLabel => 'Odbaci'; @@ -36886,6 +37429,9 @@ class MaterialLocalizationSrLatn extends MaterialLocalizationSr { @override String get saveButtonLabel => 'Sačuvaj'; + @override + String get scanTextButtonLabel => 'Skeniraj tekst'; + @override String get scrimLabel => 'Skrim'; @@ -36996,7 +37542,7 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Stäng'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Utökades'; @override String get collapsedIconTapHint => 'Utöka'; @@ -37056,22 +37602,22 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigeringsmeny'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Komprimerades'; @override String get expandedIconTapHint => 'Dölj'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'tryck snabbt två gånger för att utöka'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Utöka för mer information'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'tryck snabbt två gånger för att komprimera'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Komprimera'; @override String get firstPageTooltip => 'Första sidan'; @@ -37266,7 +37812,7 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menyrad'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Stäng menyn'; @override String get modalBarrierDismissLabel => 'Stäng'; @@ -37483,7 +38029,7 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Funga'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Imepanuliwa'; @override String get collapsedIconTapHint => 'Panua'; @@ -37543,22 +38089,22 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { String get drawerLabel => 'Menyu ya kusogeza'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Imekunjwa'; @override String get expandedIconTapHint => 'Kunja'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'gusa mara mbili ili upanue'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Panua ili upate maelezo zaidi'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'gusa mara mbili ili ukunje'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Kunja'; @override String get firstPageTooltip => 'Ukurasa wa kwanza'; @@ -37753,7 +38299,7 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menyu ya upau wa menyu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Ondoa menyu'; @override String get modalBarrierDismissLabel => 'Ondoa'; @@ -37970,7 +38516,7 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'மூடுக'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'விரிவாக்கப்பட்டது'; @override String get collapsedIconTapHint => 'விரிக்கும்'; @@ -38030,22 +38576,22 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { String get drawerLabel => 'வழிசெலுத்தல் மெனு'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'சுருக்கப்பட்டது'; @override String get expandedIconTapHint => 'சுருக்கும்'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'விரிவாக்க இருமுறை தட்டுங்கள்'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'கூடுதல் விவரங்களுக்கு விரிவாக்கலாம்'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'சுருக்க இருமுறை தட்டவும்'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'சுருக்கும்'; @override String get firstPageTooltip => 'முதல் பக்கத்திற்குச் செல்லும்'; @@ -38240,7 +38786,7 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'மெனு பட்டியின் மெனு'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'மெனுவை மூடும்'; @override String get modalBarrierDismissLabel => 'நிராகரிக்கும்'; @@ -38327,7 +38873,7 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { String get saveButtonLabel => 'சேமி'; @override - String get scanTextButtonLabel => 'உரையை ஸ்கேன் செய்யவும்'; + String get scanTextButtonLabel => 'வார்த்தைகளை ஸ்கேன் செய்'; @override String get scrimLabel => 'ஸ்க்ரிம்'; @@ -38457,7 +39003,7 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'మూసివేయి'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'విస్తరించబడింది'; @override String get collapsedIconTapHint => 'విస్తరించు'; @@ -38517,22 +39063,22 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { String get drawerLabel => 'నావిగేషన్ మెనూ'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'కుదించబడింది'; @override String get expandedIconTapHint => 'కుదించు'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'విస్తరించడానికి డబుల్ ట్యాప్ చేయండి'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'మరిన్ని వివరాల కోసం విస్తరించండి'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'కుదించడానికి డబుల్ ట్యాప్ చేయండి'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'కుదించండి'; @override String get firstPageTooltip => 'మొదటి పేజీ'; @@ -38727,7 +39273,7 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'మెనూ బార్ మెనూ'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'మెనూను తీసివేయండి'; @override String get modalBarrierDismissLabel => 'విస్మరించు'; @@ -38814,7 +39360,7 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { String get saveButtonLabel => 'సేవ్ చేయండి'; @override - String get scanTextButtonLabel => 'వచనాన్ని స్కాన్ చేయండి'; + String get scanTextButtonLabel => 'టెక్స్ట్‌ను స్కాన్ చేయండి'; @override String get scrimLabel => 'స్క్రిమ్'; @@ -38944,7 +39490,7 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'ปิด'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'ขยาย'; @override String get collapsedIconTapHint => 'ขยาย'; @@ -39004,22 +39550,22 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { String get drawerLabel => 'เมนูการนำทาง'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'ยุบ'; @override String get expandedIconTapHint => 'ยุบ'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'แตะสองครั้งเพื่อขยาย'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'ขยายเพื่อดูรายละเอียดเพิ่มเติม'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'แตะสองครั้งเพื่อยุบ'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'ยุบ'; @override String get firstPageTooltip => 'หน้าแรก'; @@ -39214,7 +39760,7 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'เมนูในแถบเมนู'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'ปิดเมนู'; @override String get modalBarrierDismissLabel => 'ปิด'; @@ -39431,7 +39977,7 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Isara'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Naka-expand'; @override String get collapsedIconTapHint => 'I-expand'; @@ -39491,22 +40037,22 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu ng navigation'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Naka-collapse'; @override String get expandedIconTapHint => 'I-collapse'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'i-double tap para i-expand'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'I-expand para sa higit pang detalye'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'i-double tap para i-collapse'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'I-collapse'; @override String get firstPageTooltip => 'Unang page'; @@ -39695,13 +40241,13 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Mga Lisensya'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Tumingin sa Itaas'; @override String get menuBarMenuLabel => 'Menu sa menu bar'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'I-dismiss ang menu'; @override String get modalBarrierDismissLabel => 'I-dismiss'; @@ -39918,7 +40464,7 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Kapat'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Genişletildi'; @override String get collapsedIconTapHint => 'Genişlet'; @@ -39978,22 +40524,22 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { String get drawerLabel => 'Gezinme menüsü'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Daraltıldı'; @override String get expandedIconTapHint => 'Daralt'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'genişletmek için iki kez dokunun'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Daha fazla ayrıntı için genişletin'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'daraltmak için iki kez dokunun'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Daralt'; @override String get firstPageTooltip => 'İlk sayfa'; @@ -40188,7 +40734,7 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Menü çubuğu menüsü'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menüyü kapat'; @override String get modalBarrierDismissLabel => 'Kapat'; @@ -40275,7 +40821,7 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Kaydet'; @override - String get scanTextButtonLabel => 'Metni tara'; + String get scanTextButtonLabel => 'Metin tara'; @override String get scrimLabel => 'opaklık katmanı'; @@ -40405,7 +40951,7 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Закрити'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Розгорнуто'; @override String get collapsedIconTapHint => 'Розгорнути'; @@ -40465,22 +41011,22 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { String get drawerLabel => 'Меню навігації'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Згорнуто'; @override String get expandedIconTapHint => 'Згорнути'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'двічі торкніться, щоб розгорнути'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Розгорнути й дізнатися більше'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'двічі торкніться, щоб згорнути'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Згорнути'; @override String get firstPageTooltip => 'Перша сторінка'; @@ -40675,7 +41221,7 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Панель меню'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Закрити меню'; @override String get modalBarrierDismissLabel => 'Закрити'; @@ -40762,7 +41308,7 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { String get saveButtonLabel => 'Зберегти'; @override - String get scanTextButtonLabel => 'Сканувати текст'; + String get scanTextButtonLabel => 'Відсканувати текст'; @override String get scrimLabel => 'Маскувальний фон'; @@ -40892,7 +41438,7 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'بند کریں'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'پھیلا ہوا'; @override String get collapsedIconTapHint => 'پھیلائیں'; @@ -40952,22 +41498,22 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { String get drawerLabel => 'نیویگیشن مینیو'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'سکڑا ہوا'; @override String get expandedIconTapHint => 'سکیڑیں'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'پھیلانے کے لیے دوبار تھپتھپائیں'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'مزید تفصیلات کے لیے پھیلائیں'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'سکیڑنے کے لیے دوبار تھپتھپائیں'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'سکیڑیں'; @override String get firstPageTooltip => 'پہلا صفحہ'; @@ -41162,7 +41708,7 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'مینیو بار کا مینیو'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'مینو برخاست کریں'; @override String get modalBarrierDismissLabel => 'برخاست کریں'; @@ -41249,7 +41795,7 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { String get saveButtonLabel => 'محفوظ کریں'; @override - String get scanTextButtonLabel => 'متن کو اسکین کریں'; + String get scanTextButtonLabel => 'ٹیکسٹ اسکین کریں'; @override String get scrimLabel => 'اسکریم'; @@ -41379,7 +41925,7 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Yopish'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Yoyilgan'; @override String get collapsedIconTapHint => 'Yoyish'; @@ -41439,22 +41985,22 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { String get drawerLabel => 'Navigatsiya menyusi'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Yigʻilgan'; @override String get expandedIconTapHint => 'Kichraytirish'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'yoyish uchun ikki marta bosing'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Batafsil koʻrish uchun yoying'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'yigʻish uchun ikki marta bosing'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Yigʻish'; @override String get firstPageTooltip => 'Birinchi sahifa'; @@ -41643,13 +42189,13 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { String get licensesPageTitle => 'Litsenziyalar'; @override - String get lookUpButtonLabel => 'Look Up'; + String get lookUpButtonLabel => 'Tepaga qarang'; @override String get menuBarMenuLabel => 'Menyu paneli'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Menyuni yopish'; @override String get modalBarrierDismissLabel => 'Yopish'; @@ -41866,7 +42412,7 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Đóng'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Đã mở rộng'; @override String get collapsedIconTapHint => 'Mở rộng'; @@ -41926,22 +42472,22 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { String get drawerLabel => 'Menu di chuyển'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Đã thu gọn'; @override String get expandedIconTapHint => 'Thu gọn'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'nhấn đúp để mở rộng'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Mở rộng để xem thêm chi tiết'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'nhấn đúp để thu gọn'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Thu gọn'; @override String get firstPageTooltip => 'Trang đầu'; @@ -42136,7 +42682,7 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Trình đơn của thanh trình đơn'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Đóng trình đơn'; @override String get modalBarrierDismissLabel => 'Bỏ qua'; @@ -42353,7 +42899,7 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { String get closeButtonTooltip => '关闭'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => '已展开'; @override String get collapsedIconTapHint => '展开'; @@ -42413,22 +42959,22 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { String get drawerLabel => '导航菜单'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => '已收起'; @override String get expandedIconTapHint => '收起'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => '点按两次即可展开'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => '展开查看更多详情'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => '点按两次即可收起'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => '收起'; @override String get firstPageTooltip => '第一页'; @@ -42623,7 +43169,7 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { String get menuBarMenuLabel => '菜单栏的菜单'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => '关闭菜单'; @override String get modalBarrierDismissLabel => '关闭'; @@ -42710,7 +43256,7 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { String get saveButtonLabel => '保存'; @override - String get scanTextButtonLabel => '扫描文本'; + String get scanTextButtonLabel => '扫描文字'; @override String get scrimLabel => '纱罩'; @@ -42849,6 +43395,9 @@ class MaterialLocalizationZhHant extends MaterialLocalizationZh { @override String get closeButtonTooltip => '關閉'; + @override + String get collapsedHint => '已展開'; + @override String get collapsedIconTapHint => '展開'; @@ -42900,9 +43449,24 @@ class MaterialLocalizationZhHant extends MaterialLocalizationZh { @override String get drawerLabel => '導覽選單'; + @override + String get expandedHint => '已收合'; + @override String get expandedIconTapHint => '收合'; + @override + String get expansionTileCollapsedHint => '㩒兩下就可以展開'; + + @override + String get expansionTileCollapsedTapHint => '展開就可以查看詳情'; + + @override + String get expansionTileExpandedHint => '㩒兩下就可以收合'; + + @override + String get expansionTileExpandedTapHint => '收合'; + @override String get firstPageTooltip => '第一頁'; @@ -43026,9 +43590,15 @@ class MaterialLocalizationZhHant extends MaterialLocalizationZh { @override String get licensesPageTitle => '授權'; + @override + String get lookUpButtonLabel => '查詢'; + @override String get menuBarMenuLabel => '選單列選單'; + @override + String get menuDismissLabel => '閂選單'; + @override String get modalBarrierDismissLabel => '拒絕'; @@ -43095,6 +43665,9 @@ class MaterialLocalizationZhHant extends MaterialLocalizationZh { @override String get saveButtonLabel => '儲存'; + @override + String get scanTextButtonLabel => '掃瞄文字'; + @override String get scrimLabel => 'Scrim'; @@ -43190,6 +43763,21 @@ class MaterialLocalizationZhHantTw extends MaterialLocalizationZhHant { required super.twoDigitZeroPaddedFormat, }); + @override + String get scanTextButtonLabel => '掃描文字'; + + @override + String get menuDismissLabel => '關閉選單'; + + @override + String get expansionTileExpandedHint => '輕觸兩下即可收合'; + + @override + String get expansionTileCollapsedHint => '輕觸兩下即可展開'; + + @override + String get expansionTileCollapsedTapHint => '展開更多詳細資料'; + @override String get scrimLabel => '紗罩'; @@ -43333,7 +43921,7 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { String get closeButtonTooltip => 'Vala'; @override - String get collapsedHint => 'Expanded'; + String get collapsedHint => 'Kunwetshiwe'; @override String get collapsedIconTapHint => 'Nweba'; @@ -43393,22 +43981,22 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { String get drawerLabel => 'Imenyu yokuzulazula'; @override - String get expandedHint => 'Collapsed'; + String get expandedHint => 'Kugoqiwe'; @override String get expandedIconTapHint => 'Goqa'; @override - String get expansionTileCollapsedHint => 'double tap to expand'; + String get expansionTileCollapsedHint => 'Thepha kabili ukuze unwebe'; @override - String get expansionTileCollapsedTapHint => 'Expand for more details'; + String get expansionTileCollapsedTapHint => 'Nweba ukuze uthole imininingwane eyengeziwe'; @override - String get expansionTileExpandedHint => "double tap to collapse'"; + String get expansionTileExpandedHint => 'thepha kabili ukuze ugoqe'; @override - String get expansionTileExpandedTapHint => 'Collapse'; + String get expansionTileExpandedTapHint => 'Goqa'; @override String get firstPageTooltip => 'Ikhasi lokuqala'; @@ -43603,7 +44191,7 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { String get menuBarMenuLabel => 'Imenyu yebha yemenyu'; @override - String get menuDismissLabel => 'Dismiss menu'; + String get menuDismissLabel => 'Chitha imenyu'; @override String get modalBarrierDismissLabel => 'Cashisa'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_af.arb b/packages/flutter_localizations/lib/src/l10n/material_af.arb index 8800c726c4f5f..3e1e66d314473 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_af.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Gaan voort", "copyButtonLabel": "Kopieer", "cutButtonLabel": "Knip", - "scanTextButtonLabel": "Skena umbhalo", + "scanTextButtonLabel": "Skandeer teks", "okButtonLabel": "OK", "pasteButtonLabel": "Plak", "selectAllButtonLabel": "Kies alles", @@ -135,13 +135,13 @@ "bottomSheetLabel": "Onderste blad", "scrimOnTapHint": "Maak $modalRouteContentName toe", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dubbeltik om in te vou", + "expansionTileCollapsedHint": "dubbeltik om uit te vou", + "expansionTileExpandedTapHint": "Vou in", + "expansionTileCollapsedTapHint": "Vou uit vir meer besonderhede", + "expandedHint": "Ingevou", + "collapsedHint": "Uitgevou", + "menuDismissLabel": "Maak kieslys toe", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_am.arb b/packages/flutter_localizations/lib/src/l10n/material_am.arb index cbd036bce09db..6caf83f4384aa 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_am.arb @@ -7,10 +7,10 @@ "deleteButtonTooltip": "ሰርዝ", "nextMonthTooltip": "ቀጣይ ወር", "previousMonthTooltip": "ቀዳሚ ወር", - "nextPageTooltip": "ቀጣይ ገጽ", - "firstPageTooltip": "የመጀመሪያው ገጽ", - "lastPageTooltip": "የመጨረሻው ገጽ", - "previousPageTooltip": "ቀዳሚ ገጽ", + "nextPageTooltip": "ቀጣይ ገፅ", + "firstPageTooltip": "የመጀመሪያው ገፅ", + "lastPageTooltip": "የመጨረሻው ገፅ", + "previousPageTooltip": "ቀዳሚ ገፅ", "showMenuTooltip": "ምናሌን አሳይ", "aboutListTileTitle": "ስለ $applicationName", "licensesPageTitle": "ፈቃዶች", @@ -25,7 +25,7 @@ "continueButtonLabel": "ቀጥል", "copyButtonLabel": "ቅዳ", "cutButtonLabel": "ቁረጥ", - "scanTextButtonLabel": "ጽሑፍ ይቃኙ", + "scanTextButtonLabel": "ጽሁፍን ቃኝ", "okButtonLabel": "እሺ", "pasteButtonLabel": "ለጥፍ", "selectAllButtonLabel": "ሁሉንም ምረጥ", @@ -135,13 +135,13 @@ "bottomSheetLabel": "የግርጌ ሉህ", "scrimOnTapHint": "$modalRouteContentNameን ዝጋ", "keyboardKeyShift": "ቀያይር", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ለመሰብሰብ ሁለቴ መታ ያድርጉ", + "expansionTileCollapsedHint": "ለመዘርጋት ድርብ ሁለቴ መታ ያድርጉ", + "expansionTileExpandedTapHint": "ሰብስብ", + "expansionTileCollapsedTapHint": "ለተጨማሪ ዝርዝሮች ይዘርጉ", + "expandedHint": "ተሰብስቧል", + "collapsedHint": "ተዘርግቷል", + "menuDismissLabel": "ምናሌን አሰናብት", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ar.arb b/packages/flutter_localizations/lib/src/l10n/material_ar.arb index 30fae912e1675..a5b7b99d7e6fa 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ar.arb @@ -35,7 +35,7 @@ "continueButtonLabel": "المتابعة", "copyButtonLabel": "نسخ", "cutButtonLabel": "قص", - "scanTextButtonLabel": "مسح النص", + "scanTextButtonLabel": "مسح النص ضوئيًا", "okButtonLabel": "حسنًا", "pasteButtonLabel": "لصق", "selectAllButtonLabel": "اختيار الكل", @@ -146,13 +146,13 @@ "bottomSheetLabel": "بطاقة سفلية", "scrimOnTapHint": "إغلاق \"$modalRouteContentName\"", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "يُرجى النقر مرّتين للتصغير.", + "expansionTileCollapsedHint": "انقر مرّتين للتوسيع", + "expansionTileExpandedTapHint": "تصغير", + "expansionTileCollapsedTapHint": "وسِّع المربّع لعرض مزيد من التفاصيل.", + "expandedHint": "مصغَّر", + "collapsedHint": "موسَّع", + "menuDismissLabel": "إغلاق القائمة", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_as.arb b/packages/flutter_localizations/lib/src/l10n/material_as.arb index 3a6f0b12a19ce..61c41c07cbdcc 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_as.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "অব্যাহত ৰাখক", "copyButtonLabel": "প্ৰতিলিপি কৰক", "cutButtonLabel": "কাট কৰক", - "scanTextButtonLabel": "স্কেন টেক্সট", + "scanTextButtonLabel": "পাঠ স্কেন কৰক", "okButtonLabel": "ঠিক আছে", "pasteButtonLabel": "পে'ষ্ট কৰক", "selectAllButtonLabel": "সকলো বাছনি কৰক", @@ -135,13 +135,13 @@ "bottomSheetLabel": "তলৰ শ্বীট", "scrimOnTapHint": "$modalRouteContentName বন্ধ কৰক", "keyboardKeyShift": "শ্বিফ্ট", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "সংকোচন কৰিবলৈ দুবাৰ টিপক", + "expansionTileCollapsedHint": "বিস্তাৰ কৰিবলৈ দুবাৰ টিপক", + "expansionTileExpandedTapHint": "সংকোচন কৰক", + "expansionTileCollapsedTapHint": "অধিক সবিশেষ জানিবলৈ বিস্তাৰ কৰক", + "expandedHint": "সংকোচন কৰা আছে", + "collapsedHint": "বিস্তাৰ কৰা আছে", + "menuDismissLabel": "অগ্ৰাহ্য কৰাৰ মেনু", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_az.arb b/packages/flutter_localizations/lib/src/l10n/material_az.arb index 2945f9c89756c..262f0d13d1e18 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_az.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "Aşağıdakı Vərəq", "scrimOnTapHint": "Bağlayın: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "yığcamlaşdırmaq üçün iki dəfə toxunun", + "expansionTileCollapsedHint": "genişləndirmək üçün iki dəfə toxunun", + "expansionTileExpandedTapHint": "Yığcamlaşdırın", + "expansionTileCollapsedTapHint": "Daha çox detallar üçün genişləndirin", + "expandedHint": "Yığcamlaşdırıldı", + "collapsedHint": "Genişləndirildi", + "menuDismissLabel": "Menyunu qapadın", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_be.arb b/packages/flutter_localizations/lib/src/l10n/material_be.arb index 73de6bcb29265..f4d12ae8d02d5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_be.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "Працягнуць", "copyButtonLabel": "Капіраваць", "cutButtonLabel": "Выразаць", - "scanTextButtonLabel": "Сканаваць тэкст", + "scanTextButtonLabel": "Сканіраваць тэкст", "okButtonLabel": "ОК", "pasteButtonLabel": "Уставіць", "selectAllButtonLabel": "Выбраць усе", @@ -141,13 +141,13 @@ "bottomSheetLabel": "Ніжні аркуш", "scrimOnTapHint": "Закрыць: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "двойчы націснуць, каб згарнуць", + "expansionTileCollapsedHint": "двойчы націснуць, каб разгарнуць", + "expansionTileExpandedTapHint": "Згарнуць", + "expansionTileCollapsedTapHint": "Разгарніце, каб даведацца больш", + "expandedHint": "Згорнута", + "collapsedHint": "Разгорнута", + "menuDismissLabel": "Закрыць меню", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bg.arb b/packages/flutter_localizations/lib/src/l10n/material_bg.arb index 923ce87574843..24680a1248730 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bg.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Напред", "copyButtonLabel": "Копиране", "cutButtonLabel": "Изрязване", - "scanTextButtonLabel": "Сканиране на текст", + "scanTextButtonLabel": "Сканирайте текст", "okButtonLabel": "OK", "pasteButtonLabel": "Поставяне", "selectAllButtonLabel": "Избиране на всички", @@ -136,13 +136,13 @@ "bottomSheetLabel": "Долен лист", "scrimOnTapHint": "Затваряне на $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "докоснете два пъти за свиване", + "expansionTileCollapsedHint": "докоснете два пъти за разгъване", + "expansionTileExpandedTapHint": "Свиване", + "expansionTileCollapsedTapHint": "Разгъване за още подробности", + "expandedHint": "Свито", + "collapsedHint": "Разгънато", + "menuDismissLabel": "Отхвърляне на менюто", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bn.arb b/packages/flutter_localizations/lib/src/l10n/material_bn.arb index edf3c6ff6ebcf..eafd2c5da81dc 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bn.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "চালিয়ে যান", "copyButtonLabel": "কপি করুন", "cutButtonLabel": "কাট করুন", - "scanTextButtonLabel": "পাঠ্য স্ক্যান করুন", + "scanTextButtonLabel": "টেক্সট স্ক্যান করুন", "okButtonLabel": "ঠিক আছে", "pasteButtonLabel": "পেস্ট করুন", "selectAllButtonLabel": "সব বেছে নিন", @@ -135,13 +135,13 @@ "bottomSheetLabel": "স্ক্রিনের নিচে অ্যাটাচ করা শিট", "scrimOnTapHint": "$modalRouteContentName বন্ধ করুন", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "আড়াল করতে ডবল ট্যাপ করুন", + "expansionTileCollapsedHint": "বড় করে দেখতে ডবল ট্যাপ করুন", + "expansionTileExpandedTapHint": "আড়াল করুন", + "expansionTileCollapsedTapHint": "আরও বিবরণ পেতে বড় করে দেখুন", + "expandedHint": "আড়াল করা হয়েছে", + "collapsedHint": "বড় করা হয়েছে", + "menuDismissLabel": "বাতিল করার মেনু", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bs.arb b/packages/flutter_localizations/lib/src/l10n/material_bs.arb index 3d6e27879e633..c60645b4a35a5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bs.arb @@ -139,13 +139,13 @@ "bottomSheetLabel": "Donja tabela", "scrimOnTapHint": "Zatvori: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "sužavanje dvostrukim dodirom", + "expansionTileCollapsedHint": "proširivanje dvostrukim dodirom", + "expansionTileExpandedTapHint": "Sužavanje", + "expansionTileCollapsedTapHint": "Proširivanje za više detalja", + "expandedHint": "Suženo", + "collapsedHint": "Prošireno", + "menuDismissLabel": "Odbacivanje menija", + "lookUpButtonLabel": "Pogled prema gore", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ca.arb b/packages/flutter_localizations/lib/src/l10n/material_ca.arb index fb83253b72520..77d9a9df476fb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ca.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Continua", "copyButtonLabel": "Copia", "cutButtonLabel": "Retalla", - "scanTextButtonLabel": "Escaneja el text", + "scanTextButtonLabel": "Escaneja text", "okButtonLabel": "D'ACORD", "pasteButtonLabel": "Enganxa", "selectAllButtonLabel": "Selecciona-ho tot", @@ -136,13 +136,13 @@ "bottomSheetLabel": "Full inferior", "scrimOnTapHint": "Tanca $modalRouteContentName", "keyboardKeyShift": "Maj", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "fes doble toc per replegar", + "expansionTileCollapsedHint": "fes doble toc per desplegar", + "expansionTileExpandedTapHint": "Replega", + "expansionTileCollapsedTapHint": "Desplega per obtenir més informació", + "expandedHint": "S'ha replegat", + "collapsedHint": "S'ha desplegat", + "menuDismissLabel": "Ignora el menú", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cs.arb b/packages/flutter_localizations/lib/src/l10n/material_cs.arb index db1c55b026410..e2965db5da5ae 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cs.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "Pokračovat", "copyButtonLabel": "Kopírovat", "cutButtonLabel": "Vyjmout", - "scanTextButtonLabel": "Naskenujte text", + "scanTextButtonLabel": "Naskenovat text", "okButtonLabel": "OK", "pasteButtonLabel": "Vložit", "selectAllButtonLabel": "Vybrat vše", @@ -142,13 +142,13 @@ "bottomSheetLabel": "Spodní tabulka", "scrimOnTapHint": "Zavřít $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dvojitým klepnutím sbalíte", + "expansionTileCollapsedHint": "dvojitým klepnutím rozbalíte", + "expansionTileExpandedTapHint": "Sbalit", + "expansionTileCollapsedTapHint": "Rozbalte pro další podrobnosti", + "expandedHint": "Sbaleno", + "collapsedHint": "Rozbaleno", + "menuDismissLabel": "Zavřít nabídku", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cy.arb b/packages/flutter_localizations/lib/src/l10n/material_cy.arb index 8d4c1e08cd5a0..e7de18926689a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cy.arb @@ -145,14 +145,14 @@ "keyboardKeySelect": "Select", "keyboardKeyShift": "Shift", "keyboardKeySpace": "Space", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "scanTextButtonLabel": "Scan text", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "tapiwch ddwywaith i grebachu", + "expansionTileCollapsedHint": "tapiwch ddwywaith i ehangu", + "expansionTileExpandedTapHint": "Crebachu", + "expansionTileCollapsedTapHint": "Ehangwch am ragor o fanylion", + "expandedHint": "Wedi'i grebachu", + "collapsedHint": "Wedi'i ehangu", + "scanTextButtonLabel": "Sganio testun", + "menuDismissLabel": "Diystyru'r ddewislen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_da.arb b/packages/flutter_localizations/lib/src/l10n/material_da.arb index dab575d99a9aa..96784884cd051 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_da.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Felt i bunden", "scrimOnTapHint": "Luk $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "tryk to gange for at skjule", + "expansionTileCollapsedHint": "tryk to gange for at udvide", + "expansionTileExpandedTapHint": "Skjul", + "expansionTileCollapsedTapHint": "Udvid for at få flere oplysninger", + "expandedHint": "Skjult", + "collapsedHint": "Udvidet", + "menuDismissLabel": "Luk menu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_de.arb b/packages/flutter_localizations/lib/src/l10n/material_de.arb index 47ae9d44eefb0..a877c493bc7e3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_de.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "Ansicht am unteren Rand", "scrimOnTapHint": "$modalRouteContentName schließen", "keyboardKeyShift": "Umschalttaste", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "Zum Minimieren doppeltippen", + "expansionTileCollapsedHint": "Zum Maximieren doppeltippen", + "expansionTileExpandedTapHint": "Minimieren", + "expansionTileCollapsedTapHint": "Für weitere Details maximieren", + "expandedHint": "Minimiert", + "collapsedHint": "Maximiert", + "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_el.arb b/packages/flutter_localizations/lib/src/l10n/material_el.arb index 3dfb34c4a0c86..ab3f8fc8f89d1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_el.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Φύλλο κάτω μέρους", "scrimOnTapHint": "Κλείσιμο $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "πατήστε δύο φορές για σύμπτυξη", + "expansionTileCollapsedHint": "πατήστε δύο φορές για ανάπτυξη", + "expansionTileExpandedTapHint": "Σύμπτυξη", + "expansionTileCollapsedTapHint": "Ανάπτυξη για περισσότερες λεπτομέρειες", + "expandedHint": "Συμπτύχθηκε", + "collapsedHint": "Αναπτύχθηκε", + "menuDismissLabel": "Παράβλεψη μενού", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_AU.arb b/packages/flutter_localizations/lib/src/l10n/material_en_AU.arb index b2cc211b94cc5..e9891cde9b804 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_AU.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_AU.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_GB.arb b/packages/flutter_localizations/lib/src/l10n/material_en_GB.arb index 4ff18cdd7898b..22a307061e77c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_GB.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_GB.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_IE.arb b/packages/flutter_localizations/lib/src/l10n/material_en_IE.arb index 4ff18cdd7898b..22a307061e77c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_IE.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_IE.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_IN.arb b/packages/flutter_localizations/lib/src/l10n/material_en_IN.arb index b2cc211b94cc5..e9891cde9b804 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_IN.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_IN.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_NZ.arb b/packages/flutter_localizations/lib/src/l10n/material_en_NZ.arb index a4962bf652008..2fc0ba78f24f1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_NZ.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_NZ.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_SG.arb b/packages/flutter_localizations/lib/src/l10n/material_en_SG.arb index b2cc211b94cc5..e9891cde9b804 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_SG.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_SG.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_en_ZA.arb b/packages/flutter_localizations/lib/src/l10n/material_en_ZA.arb index 4ff18cdd7898b..22a307061e77c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en_ZA.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en_ZA.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Scan text", + "lookUpButtonLabel": "Look up", + "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "double-tap to collapse", + "expansionTileCollapsedHint": "double-tap to expand", + "expansionTileExpandedTapHint": "Collapse", + "expansionTileCollapsedTapHint": "Expand for more details", + "expandedHint": "Collapsed", + "collapsedHint": "Expanded", "scrimLabel": "Scrim", "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Close $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es.arb b/packages/flutter_localizations/lib/src/l10n/material_es.arb index 4371c85c368f9..581574c0e18c1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", "keyboardKeyShift": "Mayús", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "toca dos veces para contraer", + "expansionTileCollapsedHint": "toca dos veces para desplegar", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Desplegar para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Desplegado", + "menuDismissLabel": "Cerrar menú", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_419.arb b/packages/flutter_localizations/lib/src/l10n/material_es_419.arb index f5b6bed2e5812..12d41aa41ffbb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_419.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_419.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_AR.arb b/packages/flutter_localizations/lib/src/l10n/material_es_AR.arb index f5b6bed2e5812..12d41aa41ffbb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_AR.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_AR.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_BO.arb b/packages/flutter_localizations/lib/src/l10n/material_es_BO.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_BO.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_BO.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_CL.arb b/packages/flutter_localizations/lib/src/l10n/material_es_CL.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_CL.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_CL.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_CO.arb b/packages/flutter_localizations/lib/src/l10n/material_es_CO.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_CO.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_CO.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_CR.arb b/packages/flutter_localizations/lib/src/l10n/material_es_CR.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_CR.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_CR.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_DO.arb b/packages/flutter_localizations/lib/src/l10n/material_es_DO.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_DO.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_DO.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_EC.arb b/packages/flutter_localizations/lib/src/l10n/material_es_EC.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_EC.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_EC.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_GT.arb b/packages/flutter_localizations/lib/src/l10n/material_es_GT.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_GT.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_GT.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_HN.arb b/packages/flutter_localizations/lib/src/l10n/material_es_HN.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_HN.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_HN.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_MX.arb b/packages/flutter_localizations/lib/src/l10n/material_es_MX.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_MX.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_MX.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_NI.arb b/packages/flutter_localizations/lib/src/l10n/material_es_NI.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_NI.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_NI.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_PA.arb b/packages/flutter_localizations/lib/src/l10n/material_es_PA.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_PA.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_PA.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_PE.arb b/packages/flutter_localizations/lib/src/l10n/material_es_PE.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_PE.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_PE.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_PR.arb b/packages/flutter_localizations/lib/src/l10n/material_es_PR.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_PR.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_PR.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_PY.arb b/packages/flutter_localizations/lib/src/l10n/material_es_PY.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_PY.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_PY.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_SV.arb b/packages/flutter_localizations/lib/src/l10n/material_es_SV.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_SV.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_SV.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_US.arb b/packages/flutter_localizations/lib/src/l10n/material_es_US.arb index 677ed109cf03a..47144eb6515d5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_US.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_US.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_UY.arb b/packages/flutter_localizations/lib/src/l10n/material_es_UY.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_UY.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_UY.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_es_VE.arb b/packages/flutter_localizations/lib/src/l10n/material_es_VE.arb index 266a3b710b537..9e7f8d7fffe25 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es_VE.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es_VE.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Analizar texto", + "lookUpButtonLabel": "Mirar hacia arriba", + "menuDismissLabel": "Descartar menú", + "expansionTileExpandedHint": "presiona dos veces para contraer", + "expansionTileCollapsedHint": "presiona dos veces para expandir", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Expandir para ver más detalles", + "expandedHint": "Contraído", + "collapsedHint": "Expandido", "scrimLabel": "Lámina", "bottomSheetLabel": "Hoja inferior", "scrimOnTapHint": "Cerrar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_et.arb b/packages/flutter_localizations/lib/src/l10n/material_et.arb index 527eb0afe9955..88dfb1a62734c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_et.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Jätka", "copyButtonLabel": "Kopeeri", "cutButtonLabel": "Lõika", - "scanTextButtonLabel": "Skanni teksti", + "scanTextButtonLabel": "Skanni tekst", "okButtonLabel": "OK", "pasteButtonLabel": "Kleebi", "selectAllButtonLabel": "Vali kõik", @@ -136,13 +136,13 @@ "bottomSheetLabel": "Alumine leht", "scrimOnTapHint": "Sule $modalRouteContentName", "keyboardKeyShift": "Tõstuklahv", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "topeltpuudutage ahendamiseks", + "expansionTileCollapsedHint": "topeltpuudutage laiendamiseks", + "expansionTileExpandedTapHint": "Ahenda", + "expansionTileCollapsedTapHint": "Laiendage lisateabe nägemiseks", + "expandedHint": "Ahendatud", + "collapsedHint": "Laiendatud", + "menuDismissLabel": "Sulge menüü", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_eu.arb b/packages/flutter_localizations/lib/src/l10n/material_eu.arb index 6147f261fbefd..d3a312a150b79 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_eu.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "Behealdeko orria", "scrimOnTapHint": "Itxi $modalRouteContentName", "keyboardKeyShift": "Maius", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "tolesteko, sakatu birritan", + "expansionTileCollapsedHint": "zabaltzeko, sakatu birritan", + "expansionTileExpandedTapHint": "Tolestu", + "expansionTileCollapsedTapHint": "Zabaldu hau xehetasun gehiago lortzeko", + "expandedHint": "Tolestuta", + "collapsedHint": "Zabalduta", + "menuDismissLabel": "Baztertu menua", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fa.arb b/packages/flutter_localizations/lib/src/l10n/material_fa.arb index 2983f4562fc76..0b574b15e080f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fa.arb @@ -14,7 +14,7 @@ "lastPageTooltip": "صفحه آخر", "showMenuTooltip": "نمایش منو", "aboutListTileTitle": "درباره $applicationName", - "licensesPageTitle": "مجوزها", + "licensesPageTitle": "پروانه‌ها", "pageRowsInfoTitle": "$firstRow–$lastRow از $rowCount", "pageRowsInfoTitleApproximate": "$firstRow–$lastRow از حدود $rowCount", "rowsPerPageTitle": "ردیف در هر صفحه:", @@ -25,7 +25,7 @@ "continueButtonLabel": "ادامه", "copyButtonLabel": "کپی", "cutButtonLabel": "برش", - "scanTextButtonLabel": "اسکن متن", + "scanTextButtonLabel": "اسکن کردن نوشتار", "okButtonLabel": "تأیید", "pasteButtonLabel": "جای‌گذاری", "selectAllButtonLabel": "انتخاب همه", @@ -87,7 +87,7 @@ "keyboardKeyAlt": "دگرساز", "keyboardKeyAltGraph": "دگرساز راست", "keyboardKeyBackspace": "پس‌بَر", - "keyboardKeyCapsLock": "حالت حروف بزرگ", + "keyboardKeyCapsLock": "Caps Lock", "keyboardKeyChannelDown": "کانال پایین", "keyboardKeyChannelUp": "کانال بالا", "keyboardKeyControl": "مهار", @@ -136,13 +136,13 @@ "bottomSheetLabel": "برگ زیرین", "scrimOnTapHint": "بستن $modalRouteContentName", "keyboardKeyShift": "کلید تبدیل", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "برای جمع کردن، دوضربه بزنید", + "expansionTileCollapsedHint": "برای ازهم بازکردن، دوضربه بزنید", + "expansionTileExpandedTapHint": "جمع کردن", + "expansionTileCollapsedTapHint": "ازهم بازکردن برای جزئیات بیشتر", + "expandedHint": "جمع‌شده", + "collapsedHint": "ازهم بازشده", + "menuDismissLabel": "بستن منو", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index 421da7341385e..a121b4f5e93c1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Alapaneeli", "scrimOnTapHint": "Sulje $modalRouteContentName", "keyboardKeyShift": "Vaihto", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "tiivistä kaksoisnapauttamalla", + "expansionTileCollapsedHint": "laajenna kaksoisnapauttamalla", + "expansionTileExpandedTapHint": "Tiivistä", + "expansionTileCollapsedTapHint": "Katso lisätietoja laajentamalla", + "expandedHint": "Tiivistetty", + "collapsedHint": "Laajennettu", + "menuDismissLabel": "Hylkää valikko", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fil.arb b/packages/flutter_localizations/lib/src/l10n/material_fil.arb index ca2f1d0d6aab6..fe87826b1efab 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fil.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Bottom Sheet", "scrimOnTapHint": "Isara ang $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "i-double tap para i-collapse", + "expansionTileCollapsedHint": "i-double tap para i-expand", + "expansionTileExpandedTapHint": "I-collapse", + "expansionTileCollapsedTapHint": "I-expand para sa higit pang detalye", + "expandedHint": "Naka-collapse", + "collapsedHint": "Naka-expand", + "menuDismissLabel": "I-dismiss ang menu", + "lookUpButtonLabel": "Tumingin sa Itaas", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr.arb b/packages/flutter_localizations/lib/src/l10n/material_fr.arb index 68639742ce871..c0852da9b94c3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fr.arb @@ -26,7 +26,7 @@ "continueButtonLabel": "Continuer", "copyButtonLabel": "Copier", "cutButtonLabel": "Couper", - "scanTextButtonLabel": "Numériser du texte", + "scanTextButtonLabel": "Scanner du texte", "okButtonLabel": "OK", "pasteButtonLabel": "Coller", "selectAllButtonLabel": "Tout sélectionner", @@ -137,13 +137,13 @@ "bottomSheetLabel": "Bottom sheet", "scrimOnTapHint": "Fermer $modalRouteContentName", "keyboardKeyShift": "Maj", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "appuyez deux fois pour réduire", + "expansionTileCollapsedHint": "appuyez deux fois pour développer", + "expansionTileExpandedTapHint": "Réduire", + "expansionTileCollapsedTapHint": "Développer pour en savoir plus", + "expandedHint": "Réduit", + "collapsedHint": "Développé", + "menuDismissLabel": "Fermer le menu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr_CA.arb b/packages/flutter_localizations/lib/src/l10n/material_fr_CA.arb index 62fb9071bb3a5..0764fcca20a9a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fr_CA.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fr_CA.arb @@ -1,4 +1,12 @@ { + "scanTextButtonLabel": "Balayer un texte", + "menuDismissLabel": "Ignorer le menu", + "expansionTileExpandedHint": "toucher deux fois pour réduire", + "expansionTileCollapsedHint": "toucher deux fois pour développer", + "expansionTileExpandedTapHint": "Réduire", + "expansionTileCollapsedTapHint": "Développer le panneau pour plus de détails", + "expandedHint": "Réduit", + "collapsedHint": "Développé", "scrimLabel": "Grille", "bottomSheetLabel": "Zone de contenu dans le bas de l'écran", "scrimOnTapHint": "Fermer $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_gl.arb b/packages/flutter_localizations/lib/src/l10n/material_gl.arb index 9c1116dee4d67..4e95b281bf9df 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gl.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "Panel inferior", "scrimOnTapHint": "Pechar $modalRouteContentName", "keyboardKeyShift": "Maiús", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "toca dúas veces para contraer", + "expansionTileCollapsedHint": "tocar dúas veces para despregar", + "expansionTileExpandedTapHint": "Contraer", + "expansionTileCollapsedTapHint": "Despregar para obter máis detalles", + "expandedHint": "Contraído", + "collapsedHint": "Despregado", + "menuDismissLabel": "Pechar menú", + "lookUpButtonLabel": "Mirar cara arriba", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb index 0128e802d9966..b191f16cd703a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Ansicht am unteren Rand", "scrimOnTapHint": "$modalRouteContentName schließen", "keyboardKeyShift": "Umschalttaste", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "Zum Minimieren doppeltippen", + "expansionTileCollapsedHint": "Zum Maximieren doppeltippen", + "expansionTileExpandedTapHint": "Minimieren", + "expansionTileCollapsedTapHint": "Für weitere Details maximieren", + "expandedHint": "Minimiert", + "collapsedHint": "Maximiert", + "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gu.arb b/packages/flutter_localizations/lib/src/l10n/material_gu.arb index 908e9095bf820..39b25a6a23327 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gu.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "ચાલુ રાખો", "copyButtonLabel": "કૉપિ કરો", "cutButtonLabel": "કાપો", - "scanTextButtonLabel": "ટેક્સ્ટ સ્કેન કરો", + "scanTextButtonLabel": "ટેક્સ્ટ સ્કૅન કરો", "okButtonLabel": "ઓકે", "pasteButtonLabel": "પેસ્ટ કરો", "selectAllButtonLabel": "બધા પસંદ કરો", @@ -135,13 +135,13 @@ "bottomSheetLabel": "બોટમ શીટ", "scrimOnTapHint": "$modalRouteContentNameને બંધ કરો", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "નાની કરવા માટે બે વાર ટૅપ કરો", + "expansionTileCollapsedHint": "મોટી કરવા માટે બે વાર ટૅપ કરો", + "expansionTileExpandedTapHint": "નાની કરો", + "expansionTileCollapsedTapHint": "વધુ વિગતો માટે મોટી કરો", + "expandedHint": "નાની કરી", + "collapsedHint": "મોટી કરી", + "menuDismissLabel": "મેનૂ છોડી દો", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_he.arb b/packages/flutter_localizations/lib/src/l10n/material_he.arb index a046c2b7a4772..7b3d765f40bf8 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_he.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "המשך", "copyButtonLabel": "העתקה", "cutButtonLabel": "גזירה", - "scanTextButtonLabel": "סרוק טקסט", + "scanTextButtonLabel": "סריקת טקסט", "okButtonLabel": "אישור", "pasteButtonLabel": "הדבקה", "selectAllButtonLabel": "בחירת הכול", @@ -142,13 +142,13 @@ "bottomSheetLabel": "גיליון תחתון", "scrimOnTapHint": "סגירת $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "כדי לכווץ, יש להקיש הקשה כפולה", + "expansionTileCollapsedHint": "כדי להרחיב, יש להקיש הקשה כפולה", + "expansionTileExpandedTapHint": "כיווץ", + "expansionTileCollapsedTapHint": "ניתן להרחיב להצגת פרטים נוספים", + "expandedHint": "מכווץ", + "collapsedHint": "מורחב", + "menuDismissLabel": "סגירת התפריט", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hi.arb b/packages/flutter_localizations/lib/src/l10n/material_hi.arb index 92674b1e32139..e8e20261a3765 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hi.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "जारी रखें", "copyButtonLabel": "कॉपी करें", "cutButtonLabel": "काटें", - "scanTextButtonLabel": "पाठ स्कैन करें", + "scanTextButtonLabel": "टेक्स्ट स्कैन करें", "okButtonLabel": "ठीक है", "pasteButtonLabel": "चिपकाएं", "selectAllButtonLabel": "सभी को चुनें", @@ -136,13 +136,13 @@ "bottomSheetLabel": "बॉटम शीट", "scrimOnTapHint": "$modalRouteContentName को बंद करें", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "छोटा करने के लिए दो बार टैप करें", + "expansionTileCollapsedHint": "बड़ा करने के लिए दो बार टैप करें", + "expansionTileExpandedTapHint": "छोटा करें", + "expansionTileCollapsedTapHint": "ज़्यादा जानकारी के लिए बड़ा करें", + "expandedHint": "छोटा किया गया", + "collapsedHint": "बड़ा किया गया", + "menuDismissLabel": "मेन्यू खारिज करें", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hr.arb b/packages/flutter_localizations/lib/src/l10n/material_hr.arb index a403da631c873..a9de4551a4605 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hr.arb @@ -28,7 +28,7 @@ "continueButtonLabel": "Nastavi", "copyButtonLabel": "Kopiraj", "cutButtonLabel": "Izreži", - "scanTextButtonLabel": "Skeniraj tekst", + "scanTextButtonLabel": "Skeniranje teksta", "okButtonLabel": "U REDU", "pasteButtonLabel": "Zalijepi", "selectAllButtonLabel": "Odaberi sve", @@ -139,13 +139,13 @@ "bottomSheetLabel": "Donja tablica", "scrimOnTapHint": "Zatvori $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "dvaput dodirnite za sažimanje", + "expansionTileCollapsedHint": "dvaput dodirnite za proširivanje", + "expansionTileExpandedTapHint": "Sažmi", + "expansionTileCollapsedTapHint": "Proširite da biste saznali više", + "expandedHint": "Sažeto", + "collapsedHint": "Prošireno", + "menuDismissLabel": "Odbacivanje izbornika", + "lookUpButtonLabel": "Pogled prema gore", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hu.arb b/packages/flutter_localizations/lib/src/l10n/material_hu.arb index d8bf8b03ddfe8..3ae117f266446 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hu.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Alsó lap", "scrimOnTapHint": "$modalRouteContentName bezárása", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "duplán koppintva összecsukhatja", + "expansionTileCollapsedHint": "duplán koppintva kibonthatja", + "expansionTileExpandedTapHint": "Összecsukás", + "expansionTileCollapsedTapHint": "Bontsa ki a további részletek megtekintéséhez", + "expandedHint": "Összecsukva", + "collapsedHint": "Kibontva", + "menuDismissLabel": "Menü bezárása", + "lookUpButtonLabel": "Felfelé nézés", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hy.arb b/packages/flutter_localizations/lib/src/l10n/material_hy.arb index 301d14496e1b5..60b330e90e5b9 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hy.arb @@ -30,7 +30,7 @@ "continueButtonLabel": "Շարունակել", "copyButtonLabel": "Պատճենել", "cutButtonLabel": "Կտրել", - "scanTextButtonLabel": "Սկանավորեք տեքստը", + "scanTextButtonLabel": "Սկանավորել տեքստ", "okButtonLabel": "Եղավ", "pasteButtonLabel": "Տեղադրել", "selectAllButtonLabel": "Նշել բոլորը", @@ -141,13 +141,13 @@ "bottomSheetLabel": "Ներքևի էկրան", "scrimOnTapHint": "Փակել՝ $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "կրկնակի հպեք ծալելու համար", + "expansionTileCollapsedHint": "կրկնակի հպեք ծավալելու համար", + "expansionTileExpandedTapHint": "Ծալել", + "expansionTileCollapsedTapHint": "ծավալեք՝ մանրամասները տեսնելու համար", + "expandedHint": "Ծալված է", + "collapsedHint": "Ծավալված է", + "menuDismissLabel": "Փակել ընտրացանկը", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_id.arb b/packages/flutter_localizations/lib/src/l10n/material_id.arb index b6784a082d319..0702678801668 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_id.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Sheet Bawah", "scrimOnTapHint": "Tutup $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ketuk dua kali untuk menciutkan", + "expansionTileCollapsedHint": "ketuk dua kali untuk meluaskan", + "expansionTileExpandedTapHint": "Ciutkan", + "expansionTileCollapsedTapHint": "Luaskan untuk mengetahui detail selengkapnya", + "expandedHint": "Diciutkan", + "collapsedHint": "Diluaskan", + "menuDismissLabel": "Tutup menu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_is.arb b/packages/flutter_localizations/lib/src/l10n/material_is.arb index 0df7c9f2af066..d4a1d4d9c3ccf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_is.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Áfram", "copyButtonLabel": "Afrita", "cutButtonLabel": "Klippa", - "scanTextButtonLabel": "Skannaðu texta", + "scanTextButtonLabel": "Skanna texta", "okButtonLabel": "Í lagi", "pasteButtonLabel": "Líma", "selectAllButtonLabel": "Velja allt", @@ -135,13 +135,13 @@ "bottomSheetLabel": "Blað neðst", "scrimOnTapHint": "Loka $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ýttu tvisvar til að minnka", + "expansionTileCollapsedHint": "ýttu tvisvar til að stækka", + "expansionTileExpandedTapHint": "Minnka", + "expansionTileCollapsedTapHint": "Stækka til að sjá frekari upplýsingar", + "expandedHint": "Minnkað", + "collapsedHint": "Stækkað", + "menuDismissLabel": "Loka valmynd", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_it.arb b/packages/flutter_localizations/lib/src/l10n/material_it.arb index e85f7f21d8a09..8315404a73ad4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_it.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Continua", "copyButtonLabel": "Copia", "cutButtonLabel": "Taglia", - "scanTextButtonLabel": "Scansiona il testo", + "scanTextButtonLabel": "Scansiona testo", "okButtonLabel": "OK", "pasteButtonLabel": "Incolla", "selectAllButtonLabel": "Seleziona tutto", @@ -136,13 +136,13 @@ "bottomSheetLabel": "Riquadro inferiore", "scrimOnTapHint": "Chiudi $modalRouteContentName", "keyboardKeyShift": "Maiusc", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "tocca due volte per comprimere", + "expansionTileCollapsedHint": "Tocca due volte per espandere", + "expansionTileExpandedTapHint": "comprimere", + "expansionTileCollapsedTapHint": "espandere e visualizzare altri dettagli", + "expandedHint": "Compresso", + "collapsedHint": "Espanso", + "menuDismissLabel": "Ignora menu", + "lookUpButtonLabel": "Cerca", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ja.arb b/packages/flutter_localizations/lib/src/l10n/material_ja.arb index 59403b89dbc91..5aaef029ecfde 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ja.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "ボトムシート", "scrimOnTapHint": "$modalRouteContentName を閉じる", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "ダブルタップすると閉じます", + "expansionTileCollapsedHint": "開くにはダブルタップします", + "expansionTileExpandedTapHint": "閉じる", + "expansionTileCollapsedTapHint": "開いて詳細を表示", + "expandedHint": "閉じました", + "collapsedHint": "開きました", + "menuDismissLabel": "メニューを閉じる", + "lookUpButtonLabel": "調べる", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ka.arb b/packages/flutter_localizations/lib/src/l10n/material_ka.arb index 4d163cec2ed5c..3dda9b4d7c7cf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ka.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "ქვედა ფურცელი", "scrimOnTapHint": "$modalRouteContentName-ის დახურვა", "keyboardKeyShift": "ცვლა", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ორმაგად შეეხეთ ჩასაკეცად", + "expansionTileCollapsedHint": "გასაფართოებლად ორჯერ შეეხეთ", + "expansionTileExpandedTapHint": "ჩაკეცვა", + "expansionTileCollapsedTapHint": "მეტი დეტალებისთვის გააფართოეთ", + "expandedHint": "ჩაკეცილია", + "collapsedHint": "გაფართოებულია", + "menuDismissLabel": "მენიუს უარყოფა", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kk.arb b/packages/flutter_localizations/lib/src/l10n/material_kk.arb index ba13d29d0f03e..a858f1c95ca6e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kk.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "Төменгі парақша", "scrimOnTapHint": "$modalRouteContentName жабу", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "жию үшін екі рет түртіңіз", + "expansionTileCollapsedHint": "жаю үшін екі рет түртіңіз", + "expansionTileExpandedTapHint": "Жию", + "expansionTileCollapsedTapHint": "Толық мәлімет алу үшін жайыңыз.", + "expandedHint": "Жиылды", + "collapsedHint": "Жайылды", + "menuDismissLabel": "Мәзірді жабу", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_km.arb b/packages/flutter_localizations/lib/src/l10n/material_km.arb index 255a891804a76..b73f086693a18 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_km.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "បន្ត", "copyButtonLabel": "ចម្លង", "cutButtonLabel": "កាត់", - "scanTextButtonLabel": "ស្កេនអត្ថបទ", + "scanTextButtonLabel": "ស្កេន​អក្សរ", "okButtonLabel": "យល់ព្រម", "pasteButtonLabel": "ដាក់​ចូល", "selectAllButtonLabel": "ជ្រើសរើស​ទាំងអស់", @@ -136,13 +136,13 @@ "bottomSheetLabel": "សន្លឹក​ខាងក្រោម", "scrimOnTapHint": "បិទ $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "ចុចពីរដង ដើម្បីបង្រួម", + "expansionTileCollapsedHint": "ចុចពីរដង ដើម្បីពង្រីក", + "expansionTileExpandedTapHint": "បង្រួម", + "expansionTileCollapsedTapHint": "ពង្រីក​ដើម្បីទទួលបាន​ព័ត៌មានលម្អិត​បន្ថែម", + "expandedHint": "បាន​បង្រួម", + "collapsedHint": "បាន​ពង្រីក", + "menuDismissLabel": "ច្រានចោល​ម៉ឺនុយ", + "lookUpButtonLabel": "រកមើល", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kn.arb b/packages/flutter_localizations/lib/src/l10n/material_kn.arb index 812d4f0c99abc..4dd80f0c0022d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kn.arb @@ -68,7 +68,7 @@ "invalidDateFormatLabel": "\u0c85\u0cae\u0cbe\u0ca8\u0ccd\u0caf\u0cb5\u0cbe\u0ca6\u0020\u0cab\u0cbe\u0cb0\u0ccd\u0cae\u0ccd\u0caf\u0cbe\u0c9f\u0ccd\u002e", "invalidDateRangeLabel": "\u0c85\u0cae\u0cbe\u0ca8\u0ccd\u0caf\u0020\u0cb6\u0ccd\u0cb0\u0cc7\u0ca3\u0cbf\u002e", "dateOutOfRangeLabel": "\u0cb5\u0ccd\u0caf\u0cbe\u0caa\u0ccd\u0ca4\u0cbf\u0caf\u0020\u0cb9\u0cca\u0cb0\u0c97\u0cbf\u0ca6\u0cc6", - "saveButtonLabel": "\u0c89\u0cb3\u0cbf\u0cb8\u0cbf", + "saveButtonLabel": "\u0cb8\u0cc7\u0cb5\u0ccd\u0020\u0cae\u0cbe\u0ca1\u0cbf", "datePickerHelpText": "\u0ca6\u0cbf\u0ca8\u0cbe\u0c82\u0c95\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0c86\u0caf\u0ccd\u0c95\u0cc6\u0cae\u0cbe\u0ca1\u0cbf", "dateRangePickerHelpText": "\u0ca6\u0cbf\u0ca8\u0cbe\u0c82\u0c95\u0ca6\u0020\u0cb5\u0ccd\u0caf\u0cbe\u0caa\u0ccd\u0ca4\u0cbf\u0caf\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0c86\u0caf\u0ccd\u0c95\u0cc6\u0cae\u0cbe\u0ca1\u0cbf", "calendarModeButtonLabel": "\u0c95\u0ccd\u0caf\u0cbe\u0cb2\u0cc6\u0c82\u0ca1\u0cb0\u0ccd\u200c\u0c97\u0cc6\u0020\u0cac\u0ca6\u0cb2\u0cbf\u0cb8\u0cbf", @@ -135,13 +135,13 @@ "bottomSheetLabel": "\u0c95\u0cc6\u0cb3\u0cad\u0cbe\u0c97\u0ca6\u0020\u0cb6\u0cc0\u0c9f\u0ccd", "scrimOnTapHint": "\u0024\u006d\u006f\u0064\u0061\u006c\u0052\u006f\u0075\u0074\u0065\u0043\u006f\u006e\u0074\u0065\u006e\u0074\u004e\u0061\u006d\u0065\u0020\u0c85\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0cae\u0cc1\u0c9a\u0ccd\u0c9a\u0cbf\u0cb0\u0cbf", "keyboardKeyShift": "\u0053\u0068\u0069\u0066\u0074", - "expansionTileExpandedHint": "\u0064\u006f\u0075\u0062\u006c\u0065\u0020\u0074\u0061\u0070\u0020\u0074\u006f\u0020\u0063\u006f\u006c\u006c\u0061\u0070\u0073\u0065\u0027", - "expansionTileCollapsedHint": "\u0064\u006f\u0075\u0062\u006c\u0065\u0020\u0074\u0061\u0070\u0020\u0074\u006f\u0020\u0065\u0078\u0070\u0061\u006e\u0064", - "expansionTileExpandedTapHint": "\u0043\u006f\u006c\u006c\u0061\u0070\u0073\u0065", - "expansionTileCollapsedTapHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0020\u0066\u006f\u0072\u0020\u006d\u006f\u0072\u0065\u0020\u0064\u0065\u0074\u0061\u0069\u006c\u0073", - "expandedHint": "\u0043\u006f\u006c\u006c\u0061\u0070\u0073\u0065\u0064", - "collapsedHint": "\u0045\u0078\u0070\u0061\u006e\u0064\u0065\u0064", - "menuDismissLabel": "\u0044\u0069\u0073\u006d\u0069\u0073\u0073\u0020\u006d\u0065\u006e\u0075", + "expansionTileExpandedHint": "\u0c95\u0cc1\u0c97\u0ccd\u0c97\u0cbf\u0cb8\u0cb2\u0cc1\u0020\u0ca1\u0cac\u0cb2\u0ccd\u0020\u0c9f\u0ccd\u0caf\u0cbe\u0caa\u0ccd\u0020\u0cae\u0cbe\u0ca1\u0cbf", + "expansionTileCollapsedHint": "\u0cb5\u0cbf\u0cb8\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cb2\u0cc1\u0020\u0ca1\u0cac\u0cb2\u0ccd\u0020\u0c9f\u0ccd\u0caf\u0cbe\u0caa\u0ccd\u0020\u0cae\u0cbe\u0ca1\u0cbf", + "expansionTileExpandedTapHint": "\u0c95\u0cc1\u0c97\u0ccd\u0c97\u0cbf\u0cb8\u0cbf", + "expansionTileCollapsedTapHint": "\u0c87\u0ca8\u0ccd\u0ca8\u0cb7\u0ccd\u0c9f\u0cc1\u0020\u0cb5\u0cbf\u0cb5\u0cb0\u0c97\u0cb3\u0cbf\u0c97\u0cbe\u0c97\u0cbf\u0020\u0cb5\u0cbf\u0cb8\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cbf", + "expandedHint": "\u0c95\u0cc1\u0c97\u0ccd\u0c97\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6", + "collapsedHint": "\u0cb5\u0cbf\u0cb8\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6", + "menuDismissLabel": "\u0cae\u0cc6\u0ca8\u0cc1\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0cb5\u0c9c\u0cbe\u0c97\u0cc6\u0cc2\u0cb3\u0cbf\u0cb8\u0cbf", "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070", "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ko.arb b/packages/flutter_localizations/lib/src/l10n/material_ko.arb index b44fd61d9614d..b4910e20b76cd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ko.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "계속", "copyButtonLabel": "복사", "cutButtonLabel": "잘라냄", - "scanTextButtonLabel": "스캔 텍스트", + "scanTextButtonLabel": "텍스트 스캔", "okButtonLabel": "확인", "pasteButtonLabel": "붙여넣기", "selectAllButtonLabel": "전체 선택", @@ -136,13 +136,13 @@ "bottomSheetLabel": "하단 시트", "scrimOnTapHint": "$modalRouteContentName 닫기", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "두 번 탭하여 접기", + "expansionTileCollapsedHint": "두 번 탭하여 펼치기", + "expansionTileExpandedTapHint": "접기", + "expansionTileCollapsedTapHint": "자세히 알아보려면 펼치기", + "expandedHint": "접힘", + "collapsedHint": "펼침", + "menuDismissLabel": "메뉴 닫기", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ky.arb b/packages/flutter_localizations/lib/src/l10n/material_ky.arb index d38c569890b0a..c835a8a6063d6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ky.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "Ылдыйкы экран", "scrimOnTapHint": "$modalRouteContentName жабуу", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "жыйыштыруу үчүн эки жолу таптаңыз", + "expansionTileCollapsedHint": "жайып көрсөтүү үчүн эки жолу таптаңыз", + "expansionTileExpandedTapHint": "Жыйыштыруу", + "expansionTileCollapsedTapHint": "Толук маалымат алуу үчүн жайып көрүңүз", + "expandedHint": "Жыйыштырылды", + "collapsedHint": "Жайылып көрсөтүлдү", + "menuDismissLabel": "Менюну жабуу", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lo.arb b/packages/flutter_localizations/lib/src/l10n/material_lo.arb index 7524ff85f6b83..552d3bb39cd22 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lo.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "ຊີດລຸ່ມສຸດ", "scrimOnTapHint": "ປິດ $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ແຕະສອງເທື່ອເພື່ອຫຍໍ້ລົງ", + "expansionTileCollapsedHint": "ແຕະສອງເທື່ອເພື່ອຂະຫຍາຍ", + "expansionTileExpandedTapHint": "ຫຍໍ້ລົງ", + "expansionTileCollapsedTapHint": "ຂະຫຍາຍສຳລັບຂໍ້ມູນເພີ່ມເຕີມ", + "expandedHint": "ຫຍໍ້ລົງແລ້ວ", + "collapsedHint": "ຂະຫຍາຍແລ້ວ", + "menuDismissLabel": "ປິດເມນູ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lt.arb b/packages/flutter_localizations/lib/src/l10n/material_lt.arb index 4674beef1c2ac..67f7266f7e094 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lt.arb @@ -142,13 +142,13 @@ "bottomSheetLabel": "Apatinis lapas", "scrimOnTapHint": "Uždaryti „$modalRouteContentName“", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dukart palieskite, kad sutrauktumėte", + "expansionTileCollapsedHint": "dukart palieskite, kad išskleistumėte", + "expansionTileExpandedTapHint": "Sutraukti", + "expansionTileCollapsedTapHint": "Išskleiskite, jei reikia daugiau išsamios informacijos", + "expandedHint": "Sutraukta", + "collapsedHint": "Išskleista", + "menuDismissLabel": "Atsisakyti meniu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lv.arb b/packages/flutter_localizations/lib/src/l10n/material_lv.arb index 79da575af0c82..a7afb08c9692d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lv.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "Ekrāna apakšdaļas lapa", "scrimOnTapHint": "Aizvērt $modalRouteContentName", "keyboardKeyShift": "Pārslēgšanas taustiņš", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dubultskāriens, lai sakļautu", + "expansionTileCollapsedHint": "dubultskāriens, lai izvērstu", + "expansionTileExpandedTapHint": "Sakļaut", + "expansionTileCollapsedTapHint": "Izvērst, lai iegūtu plašāku informāciju", + "expandedHint": "Sakļauts", + "collapsedHint": "Izvērsts", + "menuDismissLabel": "Nerādīt izvēlni", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mk.arb b/packages/flutter_localizations/lib/src/l10n/material_mk.arb index 6bf86027bd7b0..bd2227b5adc5b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mk.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Продолжи", "copyButtonLabel": "Копирај", "cutButtonLabel": "Исечи", - "scanTextButtonLabel": "Скенирајте текст", + "scanTextButtonLabel": "Скенирајте го текстот", "okButtonLabel": "Во ред", "pasteButtonLabel": "Залепи", "selectAllButtonLabel": "Избери ги сите", @@ -36,7 +36,7 @@ "timePickerMinuteModeAnnouncement": "Изберете минути", "modalBarrierDismissLabel": "Отфрли", "signedInLabel": "Најавени сте", - "hideAccountsLabel": "Сокриј сметки", + "hideAccountsLabel": "Скриј сметки", "showAccountsLabel": "Прикажи сметки", "drawerLabel": "Мени за навигација", "popupMenuLabel": "Скокачко мени", @@ -135,13 +135,13 @@ "bottomSheetLabel": "Долен лист", "scrimOnTapHint": "Затворете ја $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "допрете двапати за собирање", + "expansionTileCollapsedHint": "допри двапати за проширување", + "expansionTileExpandedTapHint": "Собери", + "expansionTileCollapsedTapHint": "Прошири за повеќе детали", + "expandedHint": "Собрано", + "collapsedHint": "Проширено", + "menuDismissLabel": "Отфрлете го менито", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ml.arb b/packages/flutter_localizations/lib/src/l10n/material_ml.arb index 0d4c8c709319a..2bffcdd5b3634 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ml.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "തുടരുക", "copyButtonLabel": "പകർത്തുക", "cutButtonLabel": "മുറിക്കുക", - "scanTextButtonLabel": "ടെക്സ്റ്റ് സ്കാൻ ചെയ്യുക", + "scanTextButtonLabel": "ടെക്സ്റ്റ് സ്‌കാൻ ചെയ്യുക", "okButtonLabel": "ശരി", "pasteButtonLabel": "ഒട്ടിക്കുക", "selectAllButtonLabel": "എല്ലാം തിരഞ്ഞെടുക്കുക", @@ -135,13 +135,13 @@ "bottomSheetLabel": "ബോട്ടം ഷീറ്റ്", "scrimOnTapHint": "$modalRouteContentName അടയ്ക്കുക", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "ചുരുക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക", + "expansionTileCollapsedHint": "വികസിപ്പിക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യുക", + "expansionTileExpandedTapHint": "ചുരുക്കുക", + "expansionTileCollapsedTapHint": "കൂടുതൽ വിശദാംശങ്ങൾക്ക് വികസിപ്പിക്കുക", + "expandedHint": "ചുരുക്കി", + "collapsedHint": "വികസിപ്പിച്ചു", + "menuDismissLabel": "മെനു ഡിസ്മിസ് ചെയ്യുക", + "lookUpButtonLabel": "മുകളിലേക്ക് നോക്കുക", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mn.arb b/packages/flutter_localizations/lib/src/l10n/material_mn.arb index b9da64a90350d..add93c96dd470 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mn.arb @@ -26,7 +26,7 @@ "continueButtonLabel": "Үргэлжлүүлэх", "copyButtonLabel": "Хуулах", "cutButtonLabel": "Таслах", - "scanTextButtonLabel": "Текст сканнердах", + "scanTextButtonLabel": "Текстийг скан хийх", "okButtonLabel": "OK", "pasteButtonLabel": "Буулгах", "selectAllButtonLabel": "Бүгдийг сонгох", @@ -137,13 +137,13 @@ "bottomSheetLabel": "Доод хүснэгт", "scrimOnTapHint": "$modalRouteContentName-г хаах", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "хураахын тулд хоёр товшино уу", + "expansionTileCollapsedHint": "дэлгэхийн тулд хоёр товшино уу", + "expansionTileExpandedTapHint": "Хураах", + "expansionTileCollapsedTapHint": "Илүү дэлгэрэнгүй авах бол дэлгэнэ үү", + "expandedHint": "Хураасан", + "collapsedHint": "Дэлгэсэн", + "menuDismissLabel": "Цэсийг хаах", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mr.arb b/packages/flutter_localizations/lib/src/l10n/material_mr.arb index 56929db97f310..f6bcd09d85ddd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mr.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "तळाशी असलेली शीट", "scrimOnTapHint": "$modalRouteContentName बंद करा", "keyboardKeyShift": "शिफ्ट", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "कोलॅप्स करण्यासाठी दोनदा टॅप करा", + "expansionTileCollapsedHint": "विस्तार करण्‍यासाठी दोनदा टॅप करा", + "expansionTileExpandedTapHint": "कोलॅप्स करा", + "expansionTileCollapsedTapHint": "आणखी तपशिलांसाठी विस्तार करा", + "expandedHint": "कोलॅप्स केले", + "collapsedHint": "विस्तार केले", + "menuDismissLabel": "मेनू डिसमिस करा", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ms.arb b/packages/flutter_localizations/lib/src/l10n/material_ms.arb index b7a24560f3476..a1ce5e8f95282 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ms.arb @@ -26,7 +26,7 @@ "continueButtonLabel": "Teruskan", "copyButtonLabel": "Salin", "cutButtonLabel": "Potong", - "scanTextButtonLabel": "Pindai teks", + "scanTextButtonLabel": "Imbas teks", "okButtonLabel": "OK", "pasteButtonLabel": "Tampal", "selectAllButtonLabel": "Pilih semua", @@ -137,13 +137,13 @@ "bottomSheetLabel": "Helaian Bawah", "scrimOnTapHint": "Tutup $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "ketik dua kali untuk kuncupkan", + "expansionTileCollapsedHint": "ketik dua kali untuk kembangkan", + "expansionTileExpandedTapHint": "Kuncupkan", + "expansionTileCollapsedTapHint": "Kembangkan untuk mendapatkan butiran lanjut", + "expandedHint": "Dikuncupkan", + "collapsedHint": "Dikembangkan", + "menuDismissLabel": "Ketepikan menu", + "lookUpButtonLabel": "Lihat ke Atas", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_my.arb b/packages/flutter_localizations/lib/src/l10n/material_my.arb index 9eaae92c0db3b..0f126392b2a1a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_my.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "ရှေ့ဆက်ရန်", "copyButtonLabel": "မိတ္တူကူးရန်", "cutButtonLabel": "ဖြတ်ယူရန်", - "scanTextButtonLabel": "စာသားကို စကင်ဖတ်ပါ။", + "scanTextButtonLabel": "စာသား စကင်ဖတ်ရန်", "okButtonLabel": "OK", "pasteButtonLabel": "ကူးထည့်ရန်", "selectAllButtonLabel": "အားလုံး ရွေးရန်", @@ -135,13 +135,13 @@ "bottomSheetLabel": "အောက်ခြေအပိုဆောင်း စာမျက်နှာ", "scrimOnTapHint": "$modalRouteContentName ပိတ်ရန်", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ခေါက်ရန် နှစ်ချက်တို့ပါ", + "expansionTileCollapsedHint": "ဖြန့်ရန် နှစ်ချက်တို့ပါ", + "expansionTileExpandedTapHint": "ခေါက်ရန်", + "expansionTileCollapsedTapHint": "အသေးစိတ်အတွက် ဖြန့်ရန်", + "expandedHint": "ခေါက်ထားသည်", + "collapsedHint": "ဖြန့်ထားသည်", + "menuDismissLabel": "မီနူးကိုပယ်ပါ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nb.arb b/packages/flutter_localizations/lib/src/l10n/material_nb.arb index 64eff83b6ad78..a575c85b87bb4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nb.arb @@ -28,7 +28,7 @@ "continueButtonLabel": "Fortsett", "copyButtonLabel": "Kopiér", "cutButtonLabel": "Klipp ut", - "scanTextButtonLabel": "Scan tekst", + "scanTextButtonLabel": "Skann tekst", "okButtonLabel": "OK", "pasteButtonLabel": "Lim inn", "selectAllButtonLabel": "Velg alle", @@ -134,13 +134,13 @@ "bottomSheetLabel": "Felt nederst", "scrimOnTapHint": "Lukk $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dobbelttrykk for å skjule", + "expansionTileCollapsedHint": "dobbelttrykk for å vise", + "expansionTileExpandedTapHint": "Skjul", + "expansionTileCollapsedTapHint": "Vis for å se mer informasjon", + "expandedHint": "Skjules", + "collapsedHint": "Vises", + "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ne.arb b/packages/flutter_localizations/lib/src/l10n/material_ne.arb index d9e0498acd36f..82ad492e0c036 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ne.arb @@ -7,7 +7,7 @@ "deleteButtonTooltip": "मेट्नुहोस्", "nextMonthTooltip": "अर्को महिना", "previousMonthTooltip": "अघिल्लो महिना", - "nextPageTooltip": "अर्को पृष्ठ", + "nextPageTooltip": "अर्को पेज", "previousPageTooltip": "अघिल्लो पृष्ठ", "firstPageTooltip": "प्रथम पेज", "lastPageTooltip": "अन्तिम पेज", @@ -25,7 +25,7 @@ "continueButtonLabel": "जारी राख्नुहोस्", "copyButtonLabel": "प्रतिलिपि गर्नुहोस्", "cutButtonLabel": "काट्नुहोस्", - "scanTextButtonLabel": "पाठ स्क्यान गर्नुहोस्", + "scanTextButtonLabel": "टेक्स्ट स्क्यान गर्नुहोस्", "okButtonLabel": "ठिक छ", "pasteButtonLabel": "टाँस्नुहोस्", "selectAllButtonLabel": "सबै बटनहरू चयन गर्नुहोस्", @@ -135,13 +135,13 @@ "bottomSheetLabel": "पुछारको पाना", "scrimOnTapHint": "$modalRouteContentName बन्द गर्नुहोस्", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "कोल्याप्स गर्न डबल ट्याप गर्नुहोस्", + "expansionTileCollapsedHint": "एक्स्पान्ड गर्न डबल ट्याप गर्नुहोस्", + "expansionTileExpandedTapHint": "कोल्याप्स गर्नुहोस्", + "expansionTileCollapsedTapHint": "थप विवरण हेर्न एक्स्पान्ड गर्नुहोस्", + "expandedHint": "कोल्याप्स गरियो", + "collapsedHint": "एक्स्पान्ड गरियो", + "menuDismissLabel": "मेनु खारेज गर्नुहोस्", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nl.arb b/packages/flutter_localizations/lib/src/l10n/material_nl.arb index babfbb6d403fc..3c9f1c1003c9c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nl.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Blad onderaan", "scrimOnTapHint": "$modalRouteContentName sluiten", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dubbeltik om samen te vouwen", + "expansionTileCollapsedHint": "dubbeltik om uit te vouwen", + "expansionTileExpandedTapHint": "Samenvouwen", + "expansionTileCollapsedTapHint": "Uitvouwen voor meer informatie", + "expandedHint": "Samengevouwen", + "collapsedHint": "Uitgevouwen", + "menuDismissLabel": "Menu sluiten", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_no.arb b/packages/flutter_localizations/lib/src/l10n/material_no.arb index 160a5eef09a97..a575c85b87bb4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_no.arb @@ -134,13 +134,13 @@ "bottomSheetLabel": "Felt nederst", "scrimOnTapHint": "Lukk $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "dobbelttrykk for å skjule", + "expansionTileCollapsedHint": "dobbelttrykk for å vise", + "expansionTileExpandedTapHint": "Skjul", + "expansionTileCollapsedTapHint": "Vis for å se mer informasjon", + "expandedHint": "Skjules", + "collapsedHint": "Vises", + "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_or.arb b/packages/flutter_localizations/lib/src/l10n/material_or.arb index fe6b2b9685fd4..1270c6debcf43 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_or.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "ଜାରି ରଖନ୍ତୁ", "copyButtonLabel": "କପି କରନ୍ତୁ", "cutButtonLabel": "କଟ୍ କରନ୍ତୁ", - "scanTextButtonLabel": "ପାଠ୍ୟ ସ୍କାନ୍ କରନ୍ତୁ", + "scanTextButtonLabel": "ଟେକ୍ସଟ୍ ସ୍କାନ୍ କରନ୍ତୁ", "okButtonLabel": "ଠିକ୍ ଅଛି", "pasteButtonLabel": "ପେଷ୍ଟ କରନ୍ତୁ", "selectAllButtonLabel": "ସବୁ ଚୟନ କରନ୍ତୁ", @@ -135,13 +135,13 @@ "bottomSheetLabel": "ବଟମ ସିଟ", "scrimOnTapHint": "$modalRouteContentNameକୁ ବନ୍ଦ କରନ୍ତୁ", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ସଙ୍କୁଚିତ କରିବା ପାଇଁ ଦୁଇଥର ଟାପ କରନ୍ତୁ", + "expansionTileCollapsedHint": "ବିସ୍ତାର କରିବା ପାଇଁ ଦୁଇଥର ଟାପ କରନ୍ତୁ", + "expansionTileExpandedTapHint": "ସଙ୍କୁଚିତ କରନ୍ତୁ", + "expansionTileCollapsedTapHint": "ଅଧିକ ବିବରଣୀ ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ", + "expandedHint": "ସଙ୍କୁଚିତ କରାଯାଇଛି", + "collapsedHint": "ବିସ୍ତାର କରାଯାଇଛି", + "menuDismissLabel": "ମେନୁ ଖାରଜ କରନ୍ତୁ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pa.arb b/packages/flutter_localizations/lib/src/l10n/material_pa.arb index 509d64f52f069..f6b7804cbe47e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pa.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "ਜਾਰੀ ਰੱਖੋ", "copyButtonLabel": "ਕਾਪੀ ਕਰੋ", "cutButtonLabel": "ਕੱਟ ਕਰੋ", - "scanTextButtonLabel": "ਟੈਕਸਟ ਸਕੈਨ ਕਰੋ", + "scanTextButtonLabel": "ਲਿਖਤ ਨੂੰ ਸਕੈਨ ਕਰੋ", "okButtonLabel": "ਠੀਕ ਹੈ", "pasteButtonLabel": "ਪੇਸਟ ਕਰੋ", "selectAllButtonLabel": "ਸਭ ਚੁਣੋ", @@ -135,13 +135,13 @@ "bottomSheetLabel": "ਹੇਠਲੀ ਸ਼ੀਟ", "scrimOnTapHint": "$modalRouteContentName ਨੂੰ ਬੰਦ ਕਰੋ", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "ਸਮੇਟਣ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ", + "expansionTileCollapsedHint": "ਵਿਸਤਾਰ ਕਰਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰੋ", + "expansionTileExpandedTapHint": "ਸਮੇਟੋ", + "expansionTileCollapsedTapHint": "ਹੋਰ ਵੇਰਵਿਆਂ ਲਈ ਵਿਸਤਾਰ ਕਰੋ", + "expandedHint": "ਸਮੇਟਿਆ ਗਿਆ", + "collapsedHint": "ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ", + "menuDismissLabel": "ਮੀਨੂ ਖਾਰਜ ਕਰੋ", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pl.arb b/packages/flutter_localizations/lib/src/l10n/material_pl.arb index 4da82533e582e..69826d57c4872 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pl.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "Dalej", "copyButtonLabel": "Kopiuj", "cutButtonLabel": "Wytnij", - "scanTextButtonLabel": "Zeskanuj tekst", + "scanTextButtonLabel": "Skanuj tekst", "okButtonLabel": "OK", "pasteButtonLabel": "Wklej", "selectAllButtonLabel": "Zaznacz wszystko", @@ -142,13 +142,13 @@ "bottomSheetLabel": "Plansza dolna", "scrimOnTapHint": "Zamknij: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "kliknij dwukrotnie, aby zwinąć", + "expansionTileCollapsedHint": "kliknij dwukrotnie, aby rozwinąć", + "expansionTileExpandedTapHint": "Zwiń", + "expansionTileCollapsedTapHint": "Rozwiń, aby wyświetlić więcej informacji", + "expandedHint": "Zwinięto", + "collapsedHint": "Rozwinięto", + "menuDismissLabel": "Zamknij menu", + "lookUpButtonLabel": "Sprawdź", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb index 73a4ced4e3196..6a8e0e31e7e42 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb @@ -81,8 +81,8 @@ "timePickerHourLabel": "Hora", "timePickerMinuteLabel": "Minuto", "invalidTimeLabel": "Insira um horário válido", - "dialModeButtonLabel": "Alternar para o modo de seleção de discagem", - "inputTimeModeButtonLabel": "Alternar para o modo de entrada de texto", + "dialModeButtonLabel": "Mudar para o modo de seleção de discagem", + "inputTimeModeButtonLabel": "Mudar para o modo de entrada de texto", "licensesPackageDetailTextZero": "No licenses", "licensesPackageDetailTextOne": "1 licença", "licensesPackageDetailTextOther": "$licenseCount licenças", @@ -138,13 +138,13 @@ "bottomSheetLabel": "Página inferior", "scrimOnTapHint": "Fechar $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "toque duas vezes para fechar", + "expansionTileCollapsedHint": "Toque duas vezes para abrir", + "expansionTileExpandedTapHint": "Feche", + "expansionTileCollapsedTapHint": "Abra para mostrar mais detalhes", + "expandedHint": "Fechado.", + "collapsedHint": "Aberto.", + "menuDismissLabel": "Dispensar menu", + "lookUpButtonLabel": "Pesquisar", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt_PT.arb b/packages/flutter_localizations/lib/src/l10n/material_pt_PT.arb index fbddcae14b80f..a7aa74964fe41 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt_PT.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt_PT.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "Digitalizar texto", + "lookUpButtonLabel": "Procurar", + "menuDismissLabel": "Ignorar menu", + "expansionTileExpandedHint": "toque duas vezes para reduzir", + "expansionTileCollapsedHint": "toque duas vezes para expandir", + "expansionTileExpandedTapHint": "Reduzir", + "expansionTileCollapsedTapHint": "Expandir para obter mais detalhes", + "expandedHint": "Reduzido", + "collapsedHint": "Expandido", "scrimLabel": "Scrim", "bottomSheetLabel": "Secção inferior", "scrimOnTapHint": "Fechar $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_ro.arb b/packages/flutter_localizations/lib/src/l10n/material_ro.arb index d74d8794147a6..0f952ecc87638 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ro.arb @@ -140,13 +140,13 @@ "bottomSheetLabel": "Foaie din partea de jos", "scrimOnTapHint": "Închideți $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "atingeți de două ori pentru a restrânge", + "expansionTileCollapsedHint": "atingeți de două ori pentru a extinde", + "expansionTileExpandedTapHint": "Restrângeți", + "expansionTileCollapsedTapHint": "Extindeți pentru mai multe detalii", + "expandedHint": "Restrâns", + "collapsedHint": "Extins", + "menuDismissLabel": "Respingeți meniul", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ru.arb b/packages/flutter_localizations/lib/src/l10n/material_ru.arb index cb5e76d961870..1d71fd7e9e90c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ru.arb @@ -143,13 +143,13 @@ "bottomSheetLabel": "Нижний экран", "scrimOnTapHint": "Закрыть $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "нажмите дважды, чтобы свернуть", + "expansionTileCollapsedHint": "нажмите дважды, чтобы развернуть", + "expansionTileExpandedTapHint": "Свернуть", + "expansionTileCollapsedTapHint": "Развернуть дополнительные сведения", + "expandedHint": "Свернуто", + "collapsedHint": "Развернуто", + "menuDismissLabel": "Закрыть меню", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_si.arb b/packages/flutter_localizations/lib/src/l10n/material_si.arb index 126f539754936..60ea033025342 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_si.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "ඉදිරියට යන්න", "copyButtonLabel": "පිටපත් කරන්න", "cutButtonLabel": "කපන්න", - "scanTextButtonLabel": "පෙළ පරිලෝකනය කරන්න", + "scanTextButtonLabel": "පෙළ ස්කෑන් කරන්න", "okButtonLabel": "හරි", "pasteButtonLabel": "අලවන්න", "selectAllButtonLabel": "සියල්ල තෝරන්න", @@ -135,13 +135,13 @@ "bottomSheetLabel": "පහළම පත්‍රය", "scrimOnTapHint": "$modalRouteContentName වසන්න", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "හැකිළවීමට දෙවරක් තට්ටු කරන්න", + "expansionTileCollapsedHint": "විහිදුවීමට දෙවරක් තට්ටු කරන්න", + "expansionTileExpandedTapHint": "හකුළන්න", + "expansionTileCollapsedTapHint": "වැඩි විස්තර සඳහා පුළුල් කරන්න", + "expandedHint": "හකුළන ලදි", + "collapsedHint": "දිග හරින ලදි", + "menuDismissLabel": "මෙනුව අස් කරන්න", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sk.arb b/packages/flutter_localizations/lib/src/l10n/material_sk.arb index 417d590716cad..27b838e489a00 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sk.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "Pokračovať", "copyButtonLabel": "Kopírovať", "cutButtonLabel": "Vystrihnúť", - "scanTextButtonLabel": "Naskenujte text", + "scanTextButtonLabel": "Naskenovať text", "okButtonLabel": "OK", "pasteButtonLabel": "Prilepiť", "selectAllButtonLabel": "Vybrať všetko", @@ -142,13 +142,13 @@ "bottomSheetLabel": "Dolný hárok", "scrimOnTapHint": "Zavrieť $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "zbalíte dvojitým klepnutím", + "expansionTileCollapsedHint": "rozbalíte dvojitým klepnutím", + "expansionTileExpandedTapHint": "Zbaliť", + "expansionTileCollapsedTapHint": "Rozbaliť a zobraziť ďalšie podrobnosti", + "expandedHint": "Zbalené", + "collapsedHint": "Rozbalené", + "menuDismissLabel": "Zavrieť ponuku", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sl.arb b/packages/flutter_localizations/lib/src/l10n/material_sl.arb index 6f761ed20e3cb..5371dc0f55d33 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sl.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "Naprej", "copyButtonLabel": "Kopiraj", "cutButtonLabel": "Izreži", - "scanTextButtonLabel": "Skeniraj besedilo", + "scanTextButtonLabel": "Optično preberite besedilo", "okButtonLabel": "V REDU", "pasteButtonLabel": "Prilepi", "selectAllButtonLabel": "Izberi vse", @@ -142,13 +142,13 @@ "bottomSheetLabel": "Razdelek na dnu zaslona", "scrimOnTapHint": "Zapiranje »$modalRouteContentName«", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "za strnitev se dvakrat dotaknite", + "expansionTileCollapsedHint": "za razširitev se dvakrat dotaknite", + "expansionTileExpandedTapHint": "Strni", + "expansionTileCollapsedTapHint": "Razširitev za več podrobnosti", + "expandedHint": "Strnjeno", + "collapsedHint": "Razširjeno", + "menuDismissLabel": "Opusti meni", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sq.arb b/packages/flutter_localizations/lib/src/l10n/material_sq.arb index 465e0e51b8a26..593342090c10b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sq.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Vazhdo", "copyButtonLabel": "Kopjo", "cutButtonLabel": "Prit", - "scanTextButtonLabel": "Skanoni tekstin", + "scanTextButtonLabel": "Skano tekstin", "okButtonLabel": "Në rregull", "pasteButtonLabel": "Ngjit", "selectAllButtonLabel": "Zgjidh të gjitha", @@ -135,13 +135,13 @@ "bottomSheetLabel": "Fleta e poshtme", "scrimOnTapHint": "Mbyll $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "trokit dy herë për ta palosur", + "expansionTileCollapsedHint": "trokit dy herë për ta zgjeruar", + "expansionTileExpandedTapHint": "Palos", + "expansionTileCollapsedTapHint": "Zgjero për më shumë detaje", + "expandedHint": "U palos", + "collapsedHint": "U zgjerua", + "menuDismissLabel": "Hiqe menynë", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sr.arb b/packages/flutter_localizations/lib/src/l10n/material_sr.arb index 522698184ef9b..db5d3c9991f65 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sr.arb @@ -28,7 +28,7 @@ "continueButtonLabel": "Настави", "copyButtonLabel": "Копирај", "cutButtonLabel": "Исеци", - "scanTextButtonLabel": "Скенирајте текст", + "scanTextButtonLabel": "Скенирај текст", "okButtonLabel": "Потврди", "pasteButtonLabel": "Налепи", "selectAllButtonLabel": "Изабери све", @@ -139,13 +139,13 @@ "bottomSheetLabel": "Доња табела", "scrimOnTapHint": "Затвори: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "двапут додирните да бисте скупили", + "expansionTileCollapsedHint": "двапут додирните да бисте проширили", + "expansionTileExpandedTapHint": "Скупите", + "expansionTileCollapsedTapHint": "Проширите за још детаља", + "expandedHint": "Скупљено је", + "collapsedHint": "Проширено је", + "menuDismissLabel": "Одбаците мени", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sr_Latn.arb b/packages/flutter_localizations/lib/src/l10n/material_sr_Latn.arb index 624b55cf0a643..d320ce96f4d9e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sr_Latn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sr_Latn.arb @@ -1,4 +1,12 @@ { + "scanTextButtonLabel": "Skeniraj tekst", + "menuDismissLabel": "Odbacite meni", + "expansionTileExpandedHint": "dvaput dodirnite da biste skupili", + "expansionTileCollapsedHint": "dvaput dodirnite da biste proširili", + "expansionTileExpandedTapHint": "Skupite", + "expansionTileCollapsedTapHint": "Proširite za još detalja", + "expandedHint": "Skupljeno je", + "collapsedHint": "Prošireno je", "scrimLabel": "Skrim", "bottomSheetLabel": "Donja tabela", "scrimOnTapHint": "Zatvori: $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_sv.arb b/packages/flutter_localizations/lib/src/l10n/material_sv.arb index 39975feb0e964..83cf62ad9898a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sv.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Ark på nedre delen av skärmen", "scrimOnTapHint": "Stäng $modalRouteContentName", "keyboardKeyShift": "Skift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "tryck snabbt två gånger för att komprimera", + "expansionTileCollapsedHint": "tryck snabbt två gånger för att utöka", + "expansionTileExpandedTapHint": "Komprimera", + "expansionTileCollapsedTapHint": "Utöka för mer information", + "expandedHint": "Komprimerades", + "collapsedHint": "Utökades", + "menuDismissLabel": "Stäng menyn", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sw.arb b/packages/flutter_localizations/lib/src/l10n/material_sw.arb index df3189e392086..456a35e35fda9 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sw.arb @@ -137,13 +137,13 @@ "bottomSheetLabel": "Safu ya Chini", "scrimOnTapHint": "Funga $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "gusa mara mbili ili ukunje", + "expansionTileCollapsedHint": "gusa mara mbili ili upanue", + "expansionTileExpandedTapHint": "Kunja", + "expansionTileCollapsedTapHint": "Panua ili upate maelezo zaidi", + "expandedHint": "Imekunjwa", + "collapsedHint": "Imepanuliwa", + "menuDismissLabel": "Ondoa menyu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ta.arb b/packages/flutter_localizations/lib/src/l10n/material_ta.arb index 68eb4b6a35b34..0654dce9c02d9 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ta.arb @@ -17,7 +17,7 @@ "reorderItemLeft": "இடப்புறம் நகர்த்தவும்", "reorderItemRight": "வலப்புறம் நகர்த்தவும்", "cutButtonLabel": "வெட்டு", - "scanTextButtonLabel": "உரையை ஸ்கேன் செய்யவும்", + "scanTextButtonLabel": "வார்த்தைகளை ஸ்கேன் செய்", "pasteButtonLabel": "ஒட்டு", "previousMonthTooltip": "முந்தைய மாதம்", "nextMonthTooltip": "அடுத்த மாதம்", @@ -137,13 +137,13 @@ "bottomSheetLabel": "கீழ்த் திரை", "scrimOnTapHint": "$modalRouteContentName ஐ மூடுக", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "சுருக்க இருமுறை தட்டவும்", + "expansionTileCollapsedHint": "விரிவாக்க இருமுறை தட்டுங்கள்", + "expansionTileExpandedTapHint": "சுருக்கும்", + "expansionTileCollapsedTapHint": "கூடுதல் விவரங்களுக்கு விரிவாக்கலாம்", + "expandedHint": "சுருக்கப்பட்டது", + "collapsedHint": "விரிவாக்கப்பட்டது", + "menuDismissLabel": "மெனுவை மூடும்", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_te.arb b/packages/flutter_localizations/lib/src/l10n/material_te.arb index 159ae42834ee2..84e3bd000e472 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_te.arb @@ -24,7 +24,7 @@ "closeButtonLabel": "మూసివేయండి", "continueButtonLabel": "కొనసాగించండి", "copyButtonLabel": "కాపీ చేయి", - "scanTextButtonLabel": "వచనాన్ని స్కాన్ చేయండి", + "scanTextButtonLabel": "టెక్స్ట్‌ను స్కాన్ చేయండి", "cutButtonLabel": "కత్తిరించండి", "okButtonLabel": "సరే", "pasteButtonLabel": "పేస్ట్ చేయండి", @@ -135,13 +135,13 @@ "bottomSheetLabel": "దిగువున ఉన్న షీట్", "scrimOnTapHint": "$modalRouteContentName‌ను మూసివేయండి", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "కుదించడానికి డబుల్ ట్యాప్ చేయండి", + "expansionTileCollapsedHint": "విస్తరించడానికి డబుల్ ట్యాప్ చేయండి", + "expansionTileExpandedTapHint": "కుదించండి", + "expansionTileCollapsedTapHint": "మరిన్ని వివరాల కోసం విస్తరించండి", + "expandedHint": "కుదించబడింది", + "collapsedHint": "విస్తరించబడింది", + "menuDismissLabel": "మెనూను తీసివేయండి", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_th.arb b/packages/flutter_localizations/lib/src/l10n/material_th.arb index 93ad1fa828494..d29a952478b16 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_th.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Bottom Sheet", "scrimOnTapHint": "ปิด $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "แตะสองครั้งเพื่อยุบ", + "expansionTileCollapsedHint": "แตะสองครั้งเพื่อขยาย", + "expansionTileExpandedTapHint": "ยุบ", + "expansionTileCollapsedTapHint": "ขยายเพื่อดูรายละเอียดเพิ่มเติม", + "expandedHint": "ยุบ", + "collapsedHint": "ขยาย", + "menuDismissLabel": "ปิดเมนู", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tl.arb b/packages/flutter_localizations/lib/src/l10n/material_tl.arb index ca2f1d0d6aab6..fe87826b1efab 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tl.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Bottom Sheet", "scrimOnTapHint": "Isara ang $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "i-double tap para i-collapse", + "expansionTileCollapsedHint": "i-double tap para i-expand", + "expansionTileExpandedTapHint": "I-collapse", + "expansionTileCollapsedTapHint": "I-expand para sa higit pang detalye", + "expandedHint": "Naka-collapse", + "collapsedHint": "Naka-expand", + "menuDismissLabel": "I-dismiss ang menu", + "lookUpButtonLabel": "Tumingin sa Itaas", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tr.arb b/packages/flutter_localizations/lib/src/l10n/material_tr.arb index a494cd85bd1b4..f92fb50a73f9c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tr.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "Devam", "copyButtonLabel": "Kopyala", "cutButtonLabel": "Kes", - "scanTextButtonLabel": "Metni tara", + "scanTextButtonLabel": "Metin tara", "okButtonLabel": "Tamam", "pasteButtonLabel": "Yapıştır", "selectAllButtonLabel": "Tümünü seç", @@ -136,13 +136,13 @@ "bottomSheetLabel": "alt sayfa", "scrimOnTapHint": "$modalRouteContentName içeriğini kapat", "keyboardKeyShift": "üst karakter", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "daraltmak için iki kez dokunun", + "expansionTileCollapsedHint": "genişletmek için iki kez dokunun", + "expansionTileExpandedTapHint": "Daralt", + "expansionTileCollapsedTapHint": "Daha fazla ayrıntı için genişletin", + "expandedHint": "Daraltıldı", + "collapsedHint": "Genişletildi", + "menuDismissLabel": "Menüyü kapat", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uk.arb b/packages/flutter_localizations/lib/src/l10n/material_uk.arb index bccecc7fbb3a4..c6e8f62de2770 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uk.arb @@ -31,7 +31,7 @@ "continueButtonLabel": "Продовжити", "copyButtonLabel": "Копіювати", "cutButtonLabel": "Вирізати", - "scanTextButtonLabel": "Сканувати текст", + "scanTextButtonLabel": "Відсканувати текст", "okButtonLabel": "OK", "pasteButtonLabel": "Вставити", "selectAllButtonLabel": "Вибрати всі", @@ -142,13 +142,13 @@ "bottomSheetLabel": "Нижній екран", "scrimOnTapHint": "Закрити: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "двічі торкніться, щоб згорнути", + "expansionTileCollapsedHint": "двічі торкніться, щоб розгорнути", + "expansionTileExpandedTapHint": "Згорнути", + "expansionTileCollapsedTapHint": "Розгорнути й дізнатися більше", + "expandedHint": "Згорнуто", + "collapsedHint": "Розгорнуто", + "menuDismissLabel": "Закрити меню", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ur.arb b/packages/flutter_localizations/lib/src/l10n/material_ur.arb index a4a191c49bf33..ea8fe8549ee09 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ur.arb @@ -25,7 +25,7 @@ "continueButtonLabel": "جاری رکھیں", "copyButtonLabel": "کاپی کریں", "cutButtonLabel": "کٹ کریں", - "scanTextButtonLabel": "متن کو اسکین کریں", + "scanTextButtonLabel": "ٹیکسٹ اسکین کریں", "okButtonLabel": "ٹھیک ہے", "pasteButtonLabel": "پیسٹ کریں", "selectAllButtonLabel": "سبھی کو منتخب کریں", @@ -136,13 +136,13 @@ "bottomSheetLabel": "نیچے کی شیٹ", "scrimOnTapHint": "$modalRouteContentName بند کریں", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "سکیڑنے کے لیے دوبار تھپتھپائیں", + "expansionTileCollapsedHint": "پھیلانے کے لیے دوبار تھپتھپائیں", + "expansionTileExpandedTapHint": "سکیڑیں", + "expansionTileCollapsedTapHint": "مزید تفصیلات کے لیے پھیلائیں", + "expandedHint": "سکڑا ہوا", + "collapsedHint": "پھیلا ہوا", + "menuDismissLabel": "مینو برخاست کریں", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uz.arb b/packages/flutter_localizations/lib/src/l10n/material_uz.arb index 79087e036c220..8a1b5cdb92f1d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uz.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "Quyi ekran", "scrimOnTapHint": "Yopish: $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", - "lookUpButtonLabel": "Look Up", + "expansionTileExpandedHint": "yigʻish uchun ikki marta bosing", + "expansionTileCollapsedHint": "yoyish uchun ikki marta bosing", + "expansionTileExpandedTapHint": "Yigʻish", + "expansionTileCollapsedTapHint": "Batafsil koʻrish uchun yoying", + "expandedHint": "Yigʻilgan", + "collapsedHint": "Yoyilgan", + "menuDismissLabel": "Menyuni yopish", + "lookUpButtonLabel": "Tepaga qarang", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_vi.arb b/packages/flutter_localizations/lib/src/l10n/material_vi.arb index ebb79d3b19311..65c677158aaad 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_vi.arb @@ -136,13 +136,13 @@ "bottomSheetLabel": "Bảng dưới cùng", "scrimOnTapHint": "Đóng $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "nhấn đúp để thu gọn", + "expansionTileCollapsedHint": "nhấn đúp để mở rộng", + "expansionTileExpandedTapHint": "Thu gọn", + "expansionTileCollapsedTapHint": "Mở rộng để xem thêm chi tiết", + "expandedHint": "Đã thu gọn", + "collapsedHint": "Đã mở rộng", + "menuDismissLabel": "Đóng trình đơn", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh.arb b/packages/flutter_localizations/lib/src/l10n/material_zh.arb index cd473bbb924b0..e05be57f3ed1b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh.arb @@ -21,7 +21,7 @@ "closeButtonLabel": "关闭", "copyButtonLabel": "复制", "cutButtonLabel": "剪切", - "scanTextButtonLabel": "扫描文本", + "scanTextButtonLabel": "扫描文字", "okButtonLabel": "确定", "pasteButtonLabel": "粘贴", "selectAllButtonLabel": "全选", @@ -136,13 +136,13 @@ "bottomSheetLabel": "底部动作条", "scrimOnTapHint": "关闭 $modalRouteContentName", "keyboardKeyShift": "Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "点按两次即可收起", + "expansionTileCollapsedHint": "点按两次即可展开", + "expansionTileExpandedTapHint": "收起", + "expansionTileCollapsedTapHint": "展开查看更多详情", + "expandedHint": "已收起", + "collapsedHint": "已展开", + "menuDismissLabel": "关闭菜单", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh_HK.arb b/packages/flutter_localizations/lib/src/l10n/material_zh_HK.arb index e3b44e58ec62b..efadc607395fe 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh_HK.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh_HK.arb @@ -1,4 +1,13 @@ { + "scanTextButtonLabel": "掃瞄文字", + "lookUpButtonLabel": "查詢", + "menuDismissLabel": "閂選單", + "expansionTileExpandedHint": "㩒兩下就可以收合", + "expansionTileCollapsedHint": "㩒兩下就可以展開", + "expansionTileExpandedTapHint": "收合", + "expansionTileCollapsedTapHint": "展開就可以查看詳情", + "expandedHint": "已收合", + "collapsedHint": "已展開", "scrimLabel": "Scrim", "bottomSheetLabel": "頁底面板", "scrimOnTapHint": "關閉 $modalRouteContentName", diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh_TW.arb b/packages/flutter_localizations/lib/src/l10n/material_zh_TW.arb index 610a3fbd1d463..33564f3ad11b6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh_TW.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh_TW.arb @@ -1,4 +1,12 @@ { + "scanTextButtonLabel": "掃描文字", + "menuDismissLabel": "關閉選單", + "expansionTileExpandedHint": "輕觸兩下即可收合", + "expansionTileCollapsedHint": "輕觸兩下即可展開", + "expansionTileExpandedTapHint": "收合", + "expansionTileCollapsedTapHint": "展開更多詳細資料", + "expandedHint": "已收合", + "collapsedHint": "已展開", "scrimLabel": "紗罩", "bottomSheetLabel": "底部功能表", "scrimOnTapHint": "關閉「$modalRouteContentName」", diff --git a/packages/flutter_localizations/lib/src/l10n/material_zu.arb b/packages/flutter_localizations/lib/src/l10n/material_zu.arb index 83f7755064085..04dbf5af003be 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zu.arb @@ -135,13 +135,13 @@ "bottomSheetLabel": "Ishidi Eliphansi", "scrimOnTapHint": "Vala i-$modalRouteContentName", "keyboardKeyShift": "U-Shift", - "expansionTileExpandedHint": "double tap to collapse'", - "expansionTileCollapsedHint": "double tap to expand", - "expansionTileExpandedTapHint": "Collapse", - "expansionTileCollapsedTapHint": "Expand for more details", - "expandedHint": "Collapsed", - "collapsedHint": "Expanded", - "menuDismissLabel": "Dismiss menu", + "expansionTileExpandedHint": "thepha kabili ukuze ugoqe", + "expansionTileCollapsedHint": "Thepha kabili ukuze unwebe", + "expansionTileExpandedTapHint": "Goqa", + "expansionTileCollapsedTapHint": "Nweba ukuze uthole imininingwane eyengeziwe", + "expandedHint": "Kugoqiwe", + "collapsedHint": "Kunwetshiwe", + "menuDismissLabel": "Chitha imenyu", "lookUpButtonLabel": "Look Up", "searchWebButtonLabel": "Search Web" } diff --git a/packages/flutter_localizations/test/cupertino/translations_test.dart b/packages/flutter_localizations/test/cupertino/translations_test.dart index 652c8c105b17b..736e5ddb25779 100644 --- a/packages/flutter_localizations/test/cupertino/translations_test.dart +++ b/packages/flutter_localizations/test/cupertino/translations_test.dart @@ -6,6 +6,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as path; @@ -203,4 +204,57 @@ void main() { expect(localizations, isA()); expect(localizations.tabSemanticsLabel(tabIndex: 1, tabCount: 2), 'Välilehti 1 kautta 2'); }); + + // Regression test for https://github.com/flutter/flutter/issues/130874. + testWidgets('buildButtonItems builds a localized "No Replacements found" button when no suggestions', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + locale: const Locale('ru'), + localizationsDelegates: GlobalCupertinoLocalizations.delegates, + supportedLocales: const [Locale('en'), Locale('ru')], + home: _FakeEditableText() + ), + ); + final _FakeEditableTextState editableTextState = + tester.state(find.byType(_FakeEditableText)); + final List? buttonItems = + CupertinoSpellCheckSuggestionsToolbar.buildButtonItems(editableTextState); + + expect(buttonItems, isNotNull); + expect(buttonItems, hasLength(1)); + expect(buttonItems!.first.label, 'Варианты замены не найдены'); + expect(buttonItems.first.onPressed, isNull); + }); + +} + +class _FakeEditableText extends EditableText { + _FakeEditableText() : super( + controller: TextEditingController(), + focusNode: FocusNode(), + backgroundCursorColor: CupertinoColors.white, + cursorColor: CupertinoColors.white, + style: const TextStyle(), + ); + + @override + _FakeEditableTextState createState() => _FakeEditableTextState(); +} + +class _FakeEditableTextState extends EditableTextState { + _FakeEditableTextState(); + + @override + TextEditingValue get currentTextEditingValue => TextEditingValue.empty; + + @override + SuggestionSpan? findSuggestionSpanAtCursorIndex(int cursorIndex) { + return const SuggestionSpan( + TextRange( + start: 0, + end: 0, + ), + [], + ); + } } From 26a9c6e9d9f6aef7ce81046cd9411616d2ff60dd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 9 Aug 2023 13:11:01 -0400 Subject: [PATCH 0615/1547] Roll Flutter Engine from 3d3fb4faed02 to 30e7780efacc (8 revisions) (#132233) https://github.com/flutter/engine/compare/3d3fb4faed02...30e7780efacc 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from 3e85749702f4 to 17ba2122707b (2 revisions) (flutter/engine#44540) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from e892c300a7c4 to 3e85749702f4 (1 revision) (flutter/engine#44539) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from ff6d82573f69 to e892c300a7c4 (1 revision) (flutter/engine#44538) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from e2885a01f134 to ff6d82573f69 (3 revisions) (flutter/engine#44536) 2023-08-09 10456171+caroqliu@users.noreply.github.com Remove GFX and Scenic dependencies from Fuchsia integration tests (flutter/engine#44498) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from ac2b25fec6eb to e2885a01f134 (1 revision) (flutter/engine#44534) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from d097852dc928 to ac2b25fec6eb (3 revisions) (flutter/engine#44533) 2023-08-09 leroux_bruno@yahoo.fr [Windows] Return keyboard pressed state (flutter/engine#43998) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 03649142e5fc3..ab4951db231f2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3d3fb4faed02356ca616a269d827e3736a4b80e3 +30e7780efaccc4c3af6a474bdb758056c2ff8b08 From c4954968e2d68e7076c6b4bf97500e02ca9a538e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 9 Aug 2023 13:13:07 -0400 Subject: [PATCH 0616/1547] Roll Packages from ac4137624a13 to 881c1f552d0f (3 revisions) (#132234) https://github.com/flutter/packages/compare/ac4137624a13...881c1f552d0f 2023-08-09 engine-flutter-autoroll@skia.org Roll Flutter from 436df69a4684 to f4c25bbb351c (28 revisions) (flutter/packages#4666) 2023-08-09 reidbaker@google.com [url_launcher] Android API 34 support (flutter/packages#4660) 2023-08-08 67326251+Franreno@users.noreply.github.com Migrating styleFrom API to new version. (flutter/packages#4540) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index fb5f2301718fe..ede5fd9daadee 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -ac4137624a13c87f20781795b9a56891cdadff11 +881c1f552d0fbc335e419d95565e16f667d343b7 From 1ff82af54029f7bb1299030a266585a56ef31088 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Wed, 9 Aug 2023 10:57:35 -0700 Subject: [PATCH 0617/1547] [Impeller] Adds advanced blend benchmark (#131893) issue: https://github.com/flutter/flutter/issues/131784 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 32 +++++++ TESTOWNERS | 3 + .../ios/Runner.xcodeproj/project.pbxproj | 18 +++- .../xcshareddata/xcschemes/Runner.xcscheme | 11 +-- .../macrobenchmarks/lib/common.dart | 1 + dev/benchmarks/macrobenchmarks/lib/main.dart | 9 ++ .../lib/src/animated_advanced_blend.dart | 83 +++++++++++++++++++ .../animated_advanced_blend_perf_test.dart | 16 ++++ ...advanced_blend_perf__timeline_summary.dart | 14 ++++ ...nced_blend_perf_ios__timeline_summary.dart | 14 ++++ ...blend_perf_opengles__timeline_summary.dart | 15 ++++ dev/devicelab/lib/tasks/perf_tests.dart | 15 ++++ 12 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 dev/benchmarks/macrobenchmarks/lib/src/animated_advanced_blend.dart create mode 100644 dev/benchmarks/macrobenchmarks/test_driver/animated_advanced_blend_perf_test.dart create mode 100644 dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/animated_advanced_blend_perf_ios__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/animated_advanced_blend_perf_opengles__timeline_summary.dart diff --git a/.ci.yaml b/.ci.yaml index 1e5874e72e65d..65067287e2ea3 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2613,6 +2613,38 @@ targets: ["devicelab", "android", "linux", "samsung", "s10"] task_name: animated_blur_backdrop_filter_perf__timeline_summary + - name: Linux_samsung_s10 animated_advanced_blend_perf_opengles__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: animated_advanced_blend_perf_opengles__timeline_summary + + - name: Linux_samsung_s10 animated_advanced_blend_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: animated_advanced_blend_perf__timeline_summary + + - name: Mac_ios animated_advanced_blend_perf_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + bringup: true + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: animated_advanced_blend_perf_ios__timeline_summary + - name: Linux_samsung_s10 animated_blur_backdrop_filter_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index cb1a439ef9d56..11a3dc6eb9a27 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -91,6 +91,9 @@ /dev/devicelab/bin/tasks/textfield_perf__e2e_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/web_size__compile_test.dart @yjbanov @flutter/web /dev/devicelab/bin/tasks/wide_gamut_ios.dart @gaaclarke @flutter/engine +/dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart @gaaclarke @flutter/engine +/dev/devicelab/bin/tasks/animated_advanced_blend_perf_ios__timeline_summary.dart @gaaclarke @flutter/engine +/dev/devicelab/bin/tasks/animated_advanced_blend_perf_opengles__timeline_summary.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf__timeline_summary.dart @jonahwilliams @flutter/engine /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/slider_perf_android.dart @tahatesser @flutter/framework diff --git a/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/project.pbxproj b/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/project.pbxproj index e319fa8e46387..4cdd00ac38a27 100644 --- a/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/project.pbxproj +++ b/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/project.pbxproj @@ -132,7 +132,6 @@ 1842E3C5134E282C88C541B8 /* Pods-Runner.release.xcconfig */, F269DC09D76325C7B7334781 /* Pods-Runner.profile.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -351,7 +350,10 @@ DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.example.macrobenchmarks; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; @@ -464,9 +466,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.example.macrobenchmarks; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; @@ -479,9 +485,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = S8QB4VV633; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.example.macrobenchmarks; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; diff --git a/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 9997cfd251cd2..098cec7a297ed 100644 --- a/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/dev/benchmarks/macrobenchmarks/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,10 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + @@ -63,8 +60,6 @@ ReferencedContainer = "container:Runner.xcodeproj"> - - const DrawPointsPage(), kDrawVerticesPageRouteName: (BuildContext context) => const DrawVerticesPage(), kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(), + kAnimatedAdvancedBlend: (BuildContext context) => const AnimatedAdvancedBlend(), }, ); } @@ -364,6 +366,13 @@ class HomePage extends StatelessWidget { Navigator.pushNamed(context, kDrawAtlasPageRouteName); }, ), + ElevatedButton( + key: const Key(kAnimatedAdvancedBlend), + child: const Text('Animated Advanced Blend'), + onPressed: () { + Navigator.pushNamed(context, kAnimatedAdvancedBlend); + }, + ), ], ), ); diff --git a/dev/benchmarks/macrobenchmarks/lib/src/animated_advanced_blend.dart b/dev/benchmarks/macrobenchmarks/lib/src/animated_advanced_blend.dart new file mode 100644 index 0000000000000..c3ea0f82171db --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/animated_advanced_blend.dart @@ -0,0 +1,83 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +class _MultiplyPainter extends CustomPainter { + _MultiplyPainter(this._color); + + final Color _color; + + @override + void paint(Canvas canvas, Size size) { + const int xDenominator = 2; + const int yDenominator = 10; + final double width = size.width / xDenominator; + final double height = size.height / yDenominator; + + for (int y = 0; y < yDenominator; y++) { + for (int x = 0; x < xDenominator; x++) { + final Rect rect = Offset(x * width, y * height) & Size(width, height); + final Paint basePaint = Paint() + ..color = Color.fromARGB( + (((x + 1) * width) / size.width * 255.0).floor(), + (((y + 1) * height) / size.height * 255.0).floor(), + 255, + 127); + canvas.drawRect(rect, basePaint); + + final Paint multiplyPaint = Paint() + ..color = _color + ..blendMode = BlendMode.multiply; + canvas.drawRect(rect, multiplyPaint); + } + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} + +class AnimatedAdvancedBlend extends StatefulWidget { + const AnimatedAdvancedBlend({super.key}); + + @override + State createState() => _AnimatedAdvancedBlendState(); +} + +class _AnimatedAdvancedBlendState extends State with SingleTickerProviderStateMixin { + late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000)); + late final Animation animation = controller.drive(Tween(begin: 0.0, end: 1.0)); + Color _color = const Color.fromARGB(255, 255, 0, 255); + + @override + void initState() { + super.initState(); + controller.repeat(); + animation.addListener(() { + setState(() { + _color = Color.fromARGB((animation.value * 255).floor(), 255, 0, 255); + }); + }); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + body: CustomPaint( + painter: _MultiplyPainter(_color), + child: Container(), + ), + )); + } +} diff --git a/dev/benchmarks/macrobenchmarks/test_driver/animated_advanced_blend_perf_test.dart b/dev/benchmarks/macrobenchmarks/test_driver/animated_advanced_blend_perf_test.dart new file mode 100644 index 0000000000000..9a7ad83cfb3cb --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test_driver/animated_advanced_blend_perf_test.dart @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTest( + 'animated_advanced_blend_perf', + kAnimatedAdvancedBlend, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 10), + ); +} diff --git a/dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart new file mode 100644 index 0000000000000..9bca1dc045592 --- /dev/null +++ b/dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createAnimatedAdvancedBlendPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/animated_advanced_blend_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/animated_advanced_blend_perf_ios__timeline_summary.dart new file mode 100644 index 0000000000000..5d09c1787022f --- /dev/null +++ b/dev/devicelab/bin/tasks/animated_advanced_blend_perf_ios__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createAnimatedAdvancedBlendPerfTest(enableImpeller: true)); +} diff --git a/dev/devicelab/bin/tasks/animated_advanced_blend_perf_opengles__timeline_summary.dart b/dev/devicelab/bin/tasks/animated_advanced_blend_perf_opengles__timeline_summary.dart new file mode 100644 index 0000000000000..113a496ac5777 --- /dev/null +++ b/dev/devicelab/bin/tasks/animated_advanced_blend_perf_opengles__timeline_summary.dart @@ -0,0 +1,15 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createAnimatedAdvancedBlendPerfTest( + enableImpeller: true, forceOpenGLES: true)); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 680dfc2fb394f..ca408a694c765 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -628,6 +628,21 @@ TaskFunction createGradientStaticPerfE2ETest() { ).run; } +TaskFunction createAnimatedAdvancedBlendPerfTest({ + bool? enableImpeller, + bool? forceOpenGLES, +}) { + return PerfTest( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test_driver/run_app.dart', + 'animated_advanced_blend_perf', + enableImpeller: enableImpeller, + forceOpenGLES: forceOpenGLES, + testDriver: 'test_driver/animated_advanced_blend_perf_test.dart', + saveTraceFile: true, + ).run; +} + TaskFunction createAnimatedBlurBackropFilterPerfTest({ bool? enableImpeller, bool? forceOpenGLES, From 88ed9bd9d2017be2f1a42711382d8ba974989eb6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 9 Aug 2023 14:05:56 -0400 Subject: [PATCH 0618/1547] Roll Flutter Engine from 30e7780efacc to b5b41ff66dae (2 revisions) (#132238) https://github.com/flutter/engine/compare/30e7780efacc...b5b41ff66dae 2023-08-09 ftsui@google.com Request GLES version 2 interface. (flutter/engine#44504) 2023-08-09 jonahwilliams@google.com [Impeller] Don't perform final layout transition on worker thread. (flutter/engine#44510) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ab4951db231f2..9ab1888b007aa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -30e7780efaccc4c3af6a474bdb758056c2ff8b08 +b5b41ff66dae3e0bf4a849e0bd9d44343db16dfb From d631b26285616c89b6f2eef660ca8f11ac86b17d Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Wed, 9 Aug 2023 14:25:12 -0500 Subject: [PATCH 0619/1547] New tooling for iOS 17 physical devices (#131865) This PR includes the following changes. These changes only apply to iOS 17 physical devices. | Command | Change Description | Changes to User Experience | | ------------- | ------------- | ------------- | | `flutter run --release` | Uses `devicectl` to install and launch application in release mode. | No change. | | `flutter run` | Uses Xcode via automation scripting to run application in debug and profile mode. | Xcode will be opened in the background. Errors/crashes may be caught in Xcode and therefore may not show in terminal. | | `flutter run --use-application-binary=xxxx` | Creates temporary empty Xcode project and use Xcode to run via automation scripting in debug and profile. | Xcode will be opened in the background. Errors/crashes may be caught in Xcode and therefore may not show in terminal. | | `flutter install` | Uses `devicectl` to check installed apps, install app, uninstall app. | No change. | | `flutter screenshot` | Will return error. | Will return error. | Other changes include: * Using `devicectl` to get information about the device * Using `idevicesyslog` and Dart VM logging for device logs Note: Xcode automation scripting (used in `flutter run` for debug and profile) does not work in a headless (without a UI) interface. No known workaround. Fixes https://github.com/flutter/flutter/issues/128827, https://github.com/flutter/flutter/issues/128531. --- .ci.yaml | 20 + TESTOWNERS | 2 + ...ter_gallery_ios__start_up_xcode_debug.dart | 21 + ...integration_ui_ios_driver_xcode_debug.dart | 21 + .../lib/tasks/integration_tests.dart | 7 +- dev/devicelab/lib/tasks/perf_tests.dart | 46 +- packages/flutter_tools/bin/xcode_debug.js | 530 +++++ .../flutter_tools/lib/src/context_runner.dart | 2 + packages/flutter_tools/lib/src/device.dart | 6 +- .../lib/src/ios/core_devices.dart | 854 ++++++++ .../flutter_tools/lib/src/ios/devices.dart | 485 +++- packages/flutter_tools/lib/src/ios/mac.dart | 2 + .../lib/src/ios/xcode_build_settings.dart | 9 + .../lib/src/ios/xcode_debug.dart | 479 ++++ .../flutter_tools/lib/src/macos/xcdevice.dart | 53 +- .../flutter_tools/lib/src/macos/xcode.dart | 65 + .../flutter_tools/lib/src/mdns_discovery.dart | 47 +- .../templates/template_manifest.json | 11 +- .../ios/custom_application_bundle/README.md | 5 + .../Runner.xcodeproj.tmpl/project.pbxproj | 297 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcschemes/Runner.xcscheme.tmpl | 82 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../test/general.shard/device_test.dart | 20 + .../general.shard/ios/core_devices_test.dart | 1949 +++++++++++++++++ .../test/general.shard/ios/devices_test.dart | 81 + .../ios/ios_device_install_test.dart | 105 + .../ios/ios_device_logger_test.dart | 179 +- .../ios/ios_device_project_test.dart | 10 + .../ios_device_start_nonprebuilt_test.dart | 433 +++- .../ios/ios_device_start_prebuilt_test.dart | 297 ++- .../general.shard/ios/xcode_debug_test.dart | 1033 +++++++++ .../general.shard/ios/xcodeproj_test.dart | 70 + .../test/general.shard/macos/xcode_test.dart | 376 +++- .../general.shard/mdns_discovery_test.dart | 104 + 39 files changed, 7587 insertions(+), 160 deletions(-) create mode 100644 dev/devicelab/bin/tasks/flutter_gallery_ios__start_up_xcode_debug.dart create mode 100644 dev/devicelab/bin/tasks/integration_ui_ios_driver_xcode_debug.dart create mode 100644 packages/flutter_tools/bin/xcode_debug.js create mode 100644 packages/flutter_tools/lib/src/ios/core_devices.dart create mode 100644 packages/flutter_tools/lib/src/ios/xcode_debug.dart create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/README.md create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.pbxproj create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/contents.xcworkspacedata create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 packages/flutter_tools/test/general.shard/ios/core_devices_test.dart create mode 100644 packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart diff --git a/.ci.yaml b/.ci.yaml index 65067287e2ea3..2ca4af28d2af1 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3685,6 +3685,16 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery_ios__start_up + - name: Mac_ios flutter_gallery_ios__start_up_xcode_debug + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: flutter_gallery_ios__start_up_xcode_debug + bringup: true + - name: Mac_ios flutter_view_ios__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -3752,6 +3762,16 @@ targets: ["devicelab", "ios", "mac"] task_name: integration_ui_ios_driver + - name: Mac_ios integration_ui_ios_driver_xcode_debug + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: integration_ui_ios_driver_xcode_debug + bringup: true + - name: Mac_ios integration_ui_ios_frame_number recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index 11a3dc6eb9a27..dfd325dd4772e 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -168,6 +168,7 @@ /dev/devicelab/bin/tasks/flutter_gallery__transition_perf_e2e_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery_ios__compile.dart @vashworth @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery_ios__start_up.dart @vashworth @flutter/engine +/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up_xcode_debug.dart @vashworth @flutter/engine /dev/devicelab/bin/tasks/flutter_gallery_ios_sksl_warmup__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/flutter_view_ios__start_up.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/fullscreen_textfield_perf_ios__e2e_summary.dart @cyanglaz @flutter/engine @@ -178,6 +179,7 @@ /dev/devicelab/bin/tasks/imagefiltered_transform_animation_perf_ios__timeline_summary.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/integration_test_test_ios.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/integration_ui_ios_driver.dart @cyanglaz @flutter/tool +/dev/devicelab/bin/tasks/integration_ui_ios_driver_xcode_debug.dart @vashworth @flutter/tool /dev/devicelab/bin/tasks/integration_ui_ios_frame_number.dart @iskakaushik @flutter/engine /dev/devicelab/bin/tasks/integration_ui_ios_keyboard_resize.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/integration_ui_ios_screenshot.dart @cyanglaz @flutter/tool diff --git a/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up_xcode_debug.dart b/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up_xcode_debug.dart new file mode 100644 index 0000000000000..a17c45d2d8678 --- /dev/null +++ b/dev/devicelab/bin/tasks/flutter_gallery_ios__start_up_xcode_debug.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + // TODO(vashworth): Remove after Xcode 15 and iOS 17 are in CI (https://github.com/flutter/flutter/issues/132128) + // XcodeDebug workflow is used for CoreDevices (iOS 17+ and Xcode 15+). Use + // FORCE_XCODE_DEBUG environment variable to force the use of XcodeDebug + // workflow in CI to test from older versions since devicelab has not yet been + // updated to iOS 17 and Xcode 15. + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createFlutterGalleryStartupTest( + runEnvironment: { + 'FORCE_XCODE_DEBUG': 'true', + }, + )); +} diff --git a/dev/devicelab/bin/tasks/integration_ui_ios_driver_xcode_debug.dart b/dev/devicelab/bin/tasks/integration_ui_ios_driver_xcode_debug.dart new file mode 100644 index 0000000000000..f51b231d2953f --- /dev/null +++ b/dev/devicelab/bin/tasks/integration_ui_ios_driver_xcode_debug.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/integration_tests.dart'; + +Future main() async { + // TODO(vashworth): Remove after Xcode 15 and iOS 17 are in CI (https://github.com/flutter/flutter/issues/132128) + // XcodeDebug workflow is used for CoreDevices (iOS 17+ and Xcode 15+). Use + // FORCE_XCODE_DEBUG environment variable to force the use of XcodeDebug + // workflow in CI to test from older versions since devicelab has not yet been + // updated to iOS 17 and Xcode 15. + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createEndToEndDriverTest( + environment: { + 'FORCE_XCODE_DEBUG': 'true', + }, + )); +} diff --git a/dev/devicelab/lib/tasks/integration_tests.dart b/dev/devicelab/lib/tasks/integration_tests.dart index 0172d576fe417..c06e717874d17 100644 --- a/dev/devicelab/lib/tasks/integration_tests.dart +++ b/dev/devicelab/lib/tasks/integration_tests.dart @@ -106,10 +106,11 @@ TaskFunction createEndToEndFrameNumberTest() { ).call; } -TaskFunction createEndToEndDriverTest() { +TaskFunction createEndToEndDriverTest({Map? environment}) { return DriverTest( '${flutterDirectory.path}/dev/integration_tests/ui', 'lib/driver.dart', + environment: environment, ).call; } @@ -173,6 +174,7 @@ class DriverTest { this.testTarget, { this.extraOptions = const [], this.deviceIdOverride, + this.environment, } ); @@ -180,6 +182,7 @@ class DriverTest { final String testTarget; final List extraOptions; final String? deviceIdOverride; + final Map? environment; Future call() { return inDirectory(testDirectory, () async { @@ -202,7 +205,7 @@ class DriverTest { deviceId, ...extraOptions, ]; - await flutter('drive', options: options); + await flutter('drive', options: options, environment: environment); return TaskResult.success(null); }); diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index ca408a694c765..9416e505b2d1c 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -233,10 +233,11 @@ TaskFunction createOpenPayScrollPerfTest({bool measureCpuGpu = true}) { ).run; } -TaskFunction createFlutterGalleryStartupTest({String target = 'lib/main.dart'}) { +TaskFunction createFlutterGalleryStartupTest({String target = 'lib/main.dart', Map? runEnvironment}) { return StartupTest( '${flutterDirectory.path}/dev/integration_tests/flutter_gallery', target: target, + runEnvironment: runEnvironment, ).run; } @@ -768,11 +769,17 @@ Future _resetManifest(String testDirectory) async { /// Measure application startup performance. class StartupTest { - const StartupTest(this.testDirectory, { this.reportMetrics = true, this.target = 'lib/main.dart' }); + const StartupTest( + this.testDirectory, { + this.reportMetrics = true, + this.target = 'lib/main.dart', + this.runEnvironment, + }); final String testDirectory; final bool reportMetrics; final String target; + final Map? runEnvironment; Future run() async { return inDirectory(testDirectory, () async { @@ -855,21 +862,26 @@ class StartupTest { 'screenshot_startup_${DateTime.now().toLocal().toIso8601String()}.png', ); }); - final int result = await flutter('run', options: [ - '--no-android-gradle-daemon', - '--no-publish-port', - '--verbose', - '--profile', - '--trace-startup', - // TODO(vashworth): Remove once done debugging https://github.com/flutter/flutter/issues/129836 - if (device is IosDevice) - '--verbose-system-logs', - '--target=$target', - '-d', - device.deviceId, - if (applicationBinaryPath != null) - '--use-application-binary=$applicationBinaryPath', - ], canFail: true); + final int result = await flutter( + 'run', + options: [ + '--no-android-gradle-daemon', + '--no-publish-port', + '--verbose', + '--profile', + '--trace-startup', + // TODO(vashworth): Remove once done debugging https://github.com/flutter/flutter/issues/129836 + if (device is IosDevice) + '--verbose-system-logs', + '--target=$target', + '-d', + device.deviceId, + if (applicationBinaryPath != null) + '--use-application-binary=$applicationBinaryPath', + ], + environment: runEnvironment, + canFail: true, + ); timer.cancel(); if (result == 0) { final Map data = json.decode( diff --git a/packages/flutter_tools/bin/xcode_debug.js b/packages/flutter_tools/bin/xcode_debug.js new file mode 100644 index 0000000000000..25f16a27298aa --- /dev/null +++ b/packages/flutter_tools/bin/xcode_debug.js @@ -0,0 +1,530 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview OSA Script to interact with Xcode. Functionality includes + * checking if a given project is open in Xcode, starting a debug session for + * a given project, and stopping a debug session for a given project. + */ + +'use strict'; + +/** + * OSA Script `run` handler that is called when the script is run. When ran + * with `osascript`, arguments are passed from the command line to the direct + * parameter of the `run` handler as a list of strings. + * + * @param {?Array=} args_array + * @returns {!RunJsonResponse} The validated command. + */ +function run(args_array = []) { + let args; + try { + args = new CommandArguments(args_array); + } catch (e) { + return new RunJsonResponse(false, `Failed to parse arguments: ${e}`).stringify(); + } + + const xcodeResult = getXcode(args); + if (xcodeResult.error != null) { + return new RunJsonResponse(false, xcodeResult.error).stringify(); + } + const xcode = xcodeResult.result; + + if (args.command === 'check-workspace-opened') { + const result = getWorkspaceDocument(xcode, args); + return new RunJsonResponse(result.error == null, result.error).stringify(); + } else if (args.command === 'debug') { + const result = debugApp(xcode, args); + return new RunJsonResponse(result.error == null, result.error, result.result).stringify(); + } else if (args.command === 'stop') { + const result = stopApp(xcode, args); + return new RunJsonResponse(result.error == null, result.error).stringify(); + } else { + return new RunJsonResponse(false, 'Unknown command').stringify(); + } +} + +/** + * Parsed and validated arguments passed from the command line. + */ +class CommandArguments { + /** + * + * @param {!Array} args List of arguments passed from the command line. + */ + constructor(args) { + this.command = this.validatedCommand(args[0]); + + const parsedArguments = this.parseArguments(args); + + this.xcodePath = this.validatedStringArgument('--xcode-path', parsedArguments['--xcode-path']); + this.projectPath = this.validatedStringArgument('--project-path', parsedArguments['--project-path']); + this.workspacePath = this.validatedStringArgument('--workspace-path', parsedArguments['--workspace-path']); + this.targetDestinationId = this.validatedStringArgument('--device-id', parsedArguments['--device-id']); + this.targetSchemeName = this.validatedStringArgument('--scheme', parsedArguments['--scheme']); + this.skipBuilding = this.validatedBoolArgument('--skip-building', parsedArguments['--skip-building']); + this.launchArguments = this.validatedJsonArgument('--launch-args', parsedArguments['--launch-args']); + this.closeWindowOnStop = this.validatedBoolArgument('--close-window', parsedArguments['--close-window']); + this.promptToSaveBeforeClose = this.validatedBoolArgument('--prompt-to-save', parsedArguments['--prompt-to-save']); + this.verbose = this.validatedBoolArgument('--verbose', parsedArguments['--verbose']); + + if (this.verbose === true) { + console.log(JSON.stringify(this)); + } + } + + /** + * Validates the command is available. + * + * @param {?string} command + * @returns {!string} The validated command. + * @throws Will throw an error if command is not recognized. + */ + validatedCommand(command) { + const allowedCommands = ['check-workspace-opened', 'debug', 'stop']; + if (allowedCommands.includes(command) === false) { + throw `Unrecognized Command: ${command}`; + } + + return command; + } + + /** + * Validates the flag is allowed for the current command. + * + * @param {!string} flag + * @param {?string} value + * @returns {!bool} + * @throws Will throw an error if the flag is not allowed for the current + * command and the value is not null, undefined, or empty. + */ + isArgumentAllowed(flag, value) { + const allowedArguments = { + 'common': { + '--xcode-path': true, + '--project-path': true, + '--workspace-path': true, + '--verbose': true, + }, + 'check-workspace-opened': {}, + 'debug': { + '--device-id': true, + '--scheme': true, + '--skip-building': true, + '--launch-args': true, + }, + 'stop': { + '--close-window': true, + '--prompt-to-save': true, + }, + } + + const isAllowed = allowedArguments['common'][flag] === true || allowedArguments[this.command][flag] === true; + if (isAllowed === false && (value != null && value !== '')) { + throw `The flag ${flag} is not allowed for the command ${this.command}.`; + } + return isAllowed; + } + + /** + * Parses the command line arguments into an object. + * + * @param {!Array} args List of arguments passed from the command line. + * @returns {!Object.} Object mapping flag to value. + * @throws Will throw an error if flag does not begin with '--'. + */ + parseArguments(args) { + const valuesPerFlag = {}; + for (let index = 1; index < args.length; index++) { + const entry = args[index]; + let flag; + let value; + const splitIndex = entry.indexOf('='); + if (splitIndex === -1) { + flag = entry; + value = args[index + 1]; + + // If the flag is allowed for the command, and the next value in the + // array is null/undefined or also a flag, treat the flag like a boolean + // flag and set the value to 'true'. + if (this.isArgumentAllowed(flag) && (value == null || value.startsWith('--'))) { + value = 'true'; + } else { + index++; + } + } else { + flag = entry.substring(0, splitIndex); + value = entry.substring(splitIndex + 1, entry.length + 1); + } + if (flag.startsWith('--') === false) { + throw `Unrecognized Flag: ${flag}`; + } + + valuesPerFlag[flag] = value; + } + return valuesPerFlag; + } + + + /** + * Validates the flag is allowed and `value` is valid. If the flag is not + * allowed for the current command, return `null`. + * + * @param {!string} flag + * @param {?string} value + * @returns {!string} + * @throws Will throw an error if the flag is allowed and `value` is null, + * undefined, or empty. + */ + validatedStringArgument(flag, value) { + if (this.isArgumentAllowed(flag, value) === false) { + return null; + } + if (value == null || value === '') { + throw `Missing value for ${flag}`; + } + return value; + } + + /** + * Validates the flag is allowed, validates `value` is valid, and converts + * `value` to a boolean. A `value` of null, undefined, or empty, it will + * return true. If the flag is not allowed for the current command, will + * return `null`. + * + * @param {?string} value + * @returns {?boolean} + * @throws Will throw an error if the flag is allowed and `value` is not + * null, undefined, empty, 'true', or 'false'. + */ + validatedBoolArgument(flag, value) { + if (this.isArgumentAllowed(flag, value) === false) { + return null; + } + if (value == null || value === '') { + return false; + } + if (value !== 'true' && value !== 'false') { + throw `Invalid value for ${flag}`; + } + return value === 'true'; + } + + /** + * Validates the flag is allowed, `value` is valid, and parses `value` as JSON. + * If the flag is not allowed for the current command, will return `null`. + * + * @param {!string} flag + * @param {?string} value + * @returns {!Object} + * @throws Will throw an error if the flag is allowed and the value is + * null, undefined, or empty. Will also throw an error if parsing fails. + */ + validatedJsonArgument(flag, value) { + if (this.isArgumentAllowed(flag, value) === false) { + return null; + } + if (value == null || value === '') { + throw `Missing value for ${flag}`; + } + try { + return JSON.parse(value); + } catch (e) { + throw `Error parsing ${flag}: ${e}`; + } + } +} + +/** + * Response to return in `run` function. + */ +class RunJsonResponse { + /** + * + * @param {!bool} success Whether the command was successful. + * @param {?string=} errorMessage Defaults to null. + * @param {?DebugResult=} debugResult Curated results from Xcode's debug + * function. Defaults to null. + */ + constructor(success, errorMessage = null, debugResult = null) { + this.status = success; + this.errorMessage = errorMessage; + this.debugResult = debugResult; + } + + /** + * Converts this object to a JSON string. + * + * @returns {!string} + * @throws Throws an error if conversion fails. + */ + stringify() { + return JSON.stringify(this); + } +} + +/** + * Utility class to return a result along with a potential error. + */ +class FunctionResult { + /** + * + * @param {?Object} result + * @param {?string=} error Defaults to null. + */ + constructor(result, error = null) { + this.result = result; + this.error = error; + } +} + +/** + * Curated results from Xcode's debug function. Mirrors parts of + * `scheme action result` from Xcode's Script Editor dictionary. + */ +class DebugResult { + /** + * + * @param {!Object} result + */ + constructor(result) { + this.completed = result.completed(); + this.status = result.status(); + this.errorMessage = result.errorMessage(); + } +} + +/** + * Get the Xcode application from the given path. Since macs can have multiple + * Xcode version, we use the path to target the specific Xcode application. + * If the Xcode app is not running, return null with an error. + * + * @param {!CommandArguments} args + * @returns {!FunctionResult} Return either an `Application` (Mac Scripting class) + * or null as the `result`. + */ +function getXcode(args) { + try { + const xcode = Application(args.xcodePath); + const isXcodeRunning = xcode.running(); + + if (isXcodeRunning === false) { + return new FunctionResult(null, 'Xcode is not running'); + } + + return new FunctionResult(xcode); + } catch (e) { + return new FunctionResult(null, `Failed to get Xcode application: ${e}`); + } +} + +/** + * After setting the active run destination to the targeted device, uses Xcode + * debug function from Mac Scripting for Xcode to install the app on the device + * and start a debugging session using the 'run' or 'run without building' scheme + * action (depending on `args.skipBuilding`). Waits for the debugging session + * to start running. + * + * @param {!Application} xcode An `Application` (Mac Scripting class) for Xcode. + * @param {!CommandArguments} args + * @returns {!FunctionResult} Return either a `DebugResult` or null as the `result`. + */ +function debugApp(xcode, args) { + const workspaceResult = waitForWorkspaceToLoad(xcode, args); + if (workspaceResult.error != null) { + return new FunctionResult(null, workspaceResult.error); + } + const targetWorkspace = workspaceResult.result; + + const destinationResult = getTargetDestination( + targetWorkspace, + args.targetDestinationId, + args.verbose, + ); + if (destinationResult.error != null) { + return new FunctionResult(null, destinationResult.error) + } + + try { + // Documentation from the Xcode Script Editor dictionary indicates that the + // `debug` function has a parameter called `runDestinationSpecifier` which + // is used to specify which device to debug the app on. It also states that + // it should be the same as the xcodebuild -destination specifier. It also + // states that if not specified, the `activeRunDestination` is used instead. + // + // Experimentation has shown that the `runDestinationSpecifier` does not work. + // It will always use the `activeRunDestination`. To mitigate this, we set + // the `activeRunDestination` to the targeted device prior to starting the debug. + targetWorkspace.activeRunDestination = destinationResult.result; + + const actionResult = targetWorkspace.debug({ + scheme: args.targetSchemeName, + skipBuilding: args.skipBuilding, + commandLineArguments: args.launchArguments, + }); + + // Wait until scheme action has started up to a max of 10 minutes. + // This does not wait for app to install, launch, or start debug session. + // Potential statuses include: not yet started/‌running/‌cancelled/‌failed/‌error occurred/‌succeeded. + const checkFrequencyInSeconds = 0.5; + const maxWaitInSeconds = 10 * 60; // 10 minutes + const iterations = maxWaitInSeconds * (1 / checkFrequencyInSeconds); + const verboseLogInterval = 10 * (1 / checkFrequencyInSeconds); + for (let i = 0; i < iterations; i++) { + if (actionResult.status() !== 'not yet started') { + break; + } + if (args.verbose === true && i % verboseLogInterval === 0) { + console.log(`Action result status: ${actionResult.status()}`); + } + delay(checkFrequencyInSeconds); + } + + return new FunctionResult(new DebugResult(actionResult)); + } catch (e) { + return new FunctionResult(null, `Failed to start debugging session: ${e}`); + } +} + +/** + * Iterates through available run destinations looking for one with a matching + * `deviceId`. If device is not found, return null with an error. + * + * @param {!WorkspaceDocument} targetWorkspace A `WorkspaceDocument` (Xcode Mac + * Scripting class). + * @param {!string} deviceId + * @param {?bool=} verbose Defaults to false. + * @returns {!FunctionResult} Return either a `RunDestination` (Xcode Mac + * Scripting class) or null as the `result`. + */ +function getTargetDestination(targetWorkspace, deviceId, verbose = false) { + try { + for (let destination of targetWorkspace.runDestinations()) { + const device = destination.device(); + if (verbose === true && device != null) { + console.log(`Device: ${device.name()} (${device.deviceIdentifier()})`); + } + if (device != null && device.deviceIdentifier() === deviceId) { + return new FunctionResult(destination); + } + } + return new FunctionResult( + null, + 'Unable to find target device. Ensure that the device is paired, ' + + 'unlocked, connected, and has an iOS version at least as high as the ' + + 'Minimum Deployment.', + ); + } catch (e) { + return new FunctionResult(null, `Failed to get target destination: ${e}`); + } +} + +/** + * Waits for the workspace to load. If the workspace is not loaded or in the + * process of opening, it will wait up to 10 minutes. + * + * @param {!Application} xcode An `Application` (Mac Scripting class) for Xcode. + * @param {!CommandArguments} args + * @returns {!FunctionResult} Return either a `WorkspaceDocument` (Xcode Mac + * Scripting class) or null as the `result`. + */ +function waitForWorkspaceToLoad(xcode, args) { + try { + const checkFrequencyInSeconds = 0.5; + const maxWaitInSeconds = 10 * 60; // 10 minutes + const verboseLogInterval = 10 * (1 / checkFrequencyInSeconds); + const iterations = maxWaitInSeconds * (1 / checkFrequencyInSeconds); + for (let i = 0; i < iterations; i++) { + // Every 10 seconds, print the list of workspaces if verbose + const verbose = args.verbose && i % verboseLogInterval === 0; + + const workspaceResult = getWorkspaceDocument(xcode, args, verbose); + if (workspaceResult.error == null) { + const document = workspaceResult.result; + if (document.loaded() === true) { + return new FunctionResult(document, null); + } + } else if (verbose === true) { + console.log(workspaceResult.error); + } + delay(checkFrequencyInSeconds); + } + return new FunctionResult(null, 'Timed out waiting for workspace to load'); + } catch (e) { + return new FunctionResult(null, `Failed to wait for workspace to load: ${e}`); + } +} + +/** + * Gets workspace opened in Xcode matching the projectPath or workspacePath + * from the command line arguments. If workspace is not found, return null with + * an error. + * + * @param {!Application} xcode An `Application` (Mac Scripting class) for Xcode. + * @param {!CommandArguments} args + * @param {?bool=} verbose Defaults to false. + * @returns {!FunctionResult} Return either a `WorkspaceDocument` (Xcode Mac + * Scripting class) or null as the `result`. + */ +function getWorkspaceDocument(xcode, args, verbose = false) { + const privatePrefix = '/private'; + + try { + const documents = xcode.workspaceDocuments(); + for (let document of documents) { + const filePath = document.file().toString(); + if (verbose === true) { + console.log(`Workspace: ${filePath}`); + } + if (filePath === args.projectPath || filePath === args.workspacePath) { + return new FunctionResult(document); + } + // Sometimes when the project is in a temporary directory, it'll be + // prefixed with `/private` but the args will not. Remove the + // prefix before matching. + if (filePath.startsWith(privatePrefix) === true) { + const filePathWithoutPrefix = filePath.slice(privatePrefix.length); + if (filePathWithoutPrefix === args.projectPath || filePathWithoutPrefix === args.workspacePath) { + return new FunctionResult(document); + } + } + } + } catch (e) { + return new FunctionResult(null, `Failed to get workspace: ${e}`); + } + return new FunctionResult(null, `Failed to get workspace.`); +} + +/** + * Stops all debug sessions in the target workspace. + * + * @param {!Application} xcode An `Application` (Mac Scripting class) for Xcode. + * @param {!CommandArguments} args + * @returns {!FunctionResult} Always returns null as the `result`. + */ +function stopApp(xcode, args) { + const workspaceResult = getWorkspaceDocument(xcode, args); + if (workspaceResult.error != null) { + return new FunctionResult(null, workspaceResult.error); + } + const targetDocument = workspaceResult.result; + + try { + targetDocument.stop(); + + if (args.closeWindowOnStop === true) { + // Wait a couple seconds before closing Xcode, otherwise it'll prompt the + // user to stop the app. + delay(2); + + targetDocument.close({ + saving: args.promptToSaveBeforeClose === true ? 'ask' : 'no', + }); + } + } catch (e) { + return new FunctionResult(null, `Failed to stop app: ${e}`); + } + return new FunctionResult(null, null); +} diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index 08cefe5169c7d..a5a4f92c25048 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -359,6 +359,7 @@ Future runInContext( platform: globals.platform, fileSystem: globals.fs, xcodeProjectInterpreter: globals.xcodeProjectInterpreter!, + userMessages: globals.userMessages, ), XCDevice: () => XCDevice( processManager: globals.processManager, @@ -375,6 +376,7 @@ Future runInContext( processManager: globals.processManager, dyLdLibEntry: globals.cache.dyLdLibEntry, ), + fileSystem: globals.fs, ), XcodeProjectInterpreter: () => XcodeProjectInterpreter( logger: globals.logger, diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index c789e31652ae9..4f209b09e9226 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -1159,6 +1159,7 @@ class DebuggingOptions { Map platformArgs, { bool ipv6 = false, DeviceConnectionInterface interfaceType = DeviceConnectionInterface.attached, + bool isCoreDevice = false, }) { final String dartVmFlags = computeDartVmFlags(this); return [ @@ -1172,7 +1173,10 @@ class DebuggingOptions { if (environmentType == EnvironmentType.simulator && dartVmFlags.isNotEmpty) '--dart-flags=$dartVmFlags', if (useTestFonts) '--use-test-fonts', - if (debuggingEnabled) ...[ + // Core Devices (iOS 17 devices) are debugged through Xcode so don't + // include these flags, which are used to check if the app was launched + // via Flutter CLI and `ios-deploy`. + if (debuggingEnabled && !isCoreDevice) ...[ '--enable-checked-mode', '--verify-entry-points', ], diff --git a/packages/flutter_tools/lib/src/ios/core_devices.dart b/packages/flutter_tools/lib/src/ios/core_devices.dart new file mode 100644 index 0000000000000..aa39adbf66cb3 --- /dev/null +++ b/packages/flutter_tools/lib/src/ios/core_devices.dart @@ -0,0 +1,854 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; +import 'package:process/process.dart'; + +import '../base/file_system.dart'; +import '../base/io.dart'; +import '../base/logger.dart'; +import '../base/process.dart'; +import '../convert.dart'; +import '../device.dart'; +import '../macos/xcode.dart'; + +/// A wrapper around the `devicectl` command line tool. +/// +/// CoreDevice is a device connectivity stack introduced in Xcode 15. Devices +/// with iOS 17 or greater are CoreDevices. +/// +/// `devicectl` (CoreDevice Device Control) is an Xcode CLI tool used for +/// interacting with CoreDevices. +class IOSCoreDeviceControl { + IOSCoreDeviceControl({ + required Logger logger, + required ProcessManager processManager, + required Xcode xcode, + required FileSystem fileSystem, + }) : _logger = logger, + _processUtils = ProcessUtils(logger: logger, processManager: processManager), + _xcode = xcode, + _fileSystem = fileSystem; + + final Logger _logger; + final ProcessUtils _processUtils; + final Xcode _xcode; + final FileSystem _fileSystem; + + /// When the `--timeout` flag is used with `devicectl`, it must be at + /// least 5 seconds. If lower than 5 seconds, `devicectl` will error and not + /// run the command. + static const int _minimumTimeoutInSeconds = 5; + + /// Executes `devicectl` command to get list of devices. The command will + /// likely complete before [timeout] is reached. If [timeout] is reached, + /// the command will be stopped as a failure. + Future> _listCoreDevices({ + Duration timeout = const Duration(seconds: _minimumTimeoutInSeconds), + }) async { + if (!_xcode.isDevicectlInstalled) { + _logger.printError('devicectl is not installed.'); + return []; + } + + // Default to minimum timeout if needed to prevent error. + Duration validTimeout = timeout; + if (timeout.inSeconds < _minimumTimeoutInSeconds) { + _logger.printError( + 'Timeout of ${timeout.inSeconds} seconds is below the minimum timeout value ' + 'for devicectl. Changing the timeout to the minimum value of $_minimumTimeoutInSeconds.'); + validTimeout = const Duration(seconds: _minimumTimeoutInSeconds); + } + + final Directory tempDirectory = _fileSystem.systemTempDirectory.createTempSync('core_devices.'); + final File output = tempDirectory.childFile('core_device_list.json'); + output.createSync(); + + final List command = [ + ..._xcode.xcrunCommand(), + 'devicectl', + 'list', + 'devices', + '--timeout', + validTimeout.inSeconds.toString(), + '--json-output', + output.path, + ]; + + try { + await _processUtils.run(command, throwOnError: true); + + final String stringOutput = output.readAsStringSync(); + _logger.printTrace(stringOutput); + + try { + final Object? decodeResult = (json.decode(stringOutput) as Map)['result']; + if (decodeResult is Map) { + final Object? decodeDevices = decodeResult['devices']; + if (decodeDevices is List) { + return decodeDevices; + } + } + _logger.printError('devicectl returned unexpected JSON response: $stringOutput'); + return []; + } on FormatException { + // We failed to parse the devicectl output, or it returned junk. + _logger.printError('devicectl returned non-JSON response: $stringOutput'); + return []; + } + } on ProcessException catch (err) { + _logger.printError('Error executing devicectl: $err'); + return []; + } finally { + tempDirectory.deleteSync(recursive: true); + } + } + + Future> getCoreDevices({ + Duration timeout = const Duration(seconds: _minimumTimeoutInSeconds), + }) async { + final List devices = []; + + final List devicesSection = await _listCoreDevices(timeout: timeout); + for (final Object? deviceObject in devicesSection) { + if (deviceObject is Map) { + devices.add(IOSCoreDevice.fromBetaJson(deviceObject, logger: _logger)); + } + } + return devices; + } + + /// Executes `devicectl` command to get list of apps installed on the device. + /// If [bundleId] is provided, it will only return apps matching the bundle + /// identifier exactly. + Future> _listInstalledApps({ + required String deviceId, + String? bundleId, + }) async { + if (!_xcode.isDevicectlInstalled) { + _logger.printError('devicectl is not installed.'); + return []; + } + + final Directory tempDirectory = _fileSystem.systemTempDirectory.createTempSync('core_devices.'); + final File output = tempDirectory.childFile('core_device_app_list.json'); + output.createSync(); + + final List command = [ + ..._xcode.xcrunCommand(), + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + if (bundleId != null) + '--bundle-id', + bundleId!, + '--json-output', + output.path, + ]; + + try { + await _processUtils.run(command, throwOnError: true); + + final String stringOutput = output.readAsStringSync(); + + try { + final Object? decodeResult = (json.decode(stringOutput) as Map)['result']; + if (decodeResult is Map) { + final Object? decodeApps = decodeResult['apps']; + if (decodeApps is List) { + return decodeApps; + } + } + _logger.printError('devicectl returned unexpected JSON response: $stringOutput'); + return []; + } on FormatException { + // We failed to parse the devicectl output, or it returned junk. + _logger.printError('devicectl returned non-JSON response: $stringOutput'); + return []; + } + } on ProcessException catch (err) { + _logger.printError('Error executing devicectl: $err'); + return []; + } finally { + tempDirectory.deleteSync(recursive: true); + } + } + + @visibleForTesting + Future> getInstalledApps({ + required String deviceId, + String? bundleId, + }) async { + final List apps = []; + + final List appsData = await _listInstalledApps(deviceId: deviceId, bundleId: bundleId); + for (final Object? appObject in appsData) { + if (appObject is Map) { + apps.add(IOSCoreDeviceInstalledApp.fromBetaJson(appObject)); + } + } + return apps; + } + + Future isAppInstalled({ + required String deviceId, + required String bundleId, + }) async { + final List apps = await getInstalledApps( + deviceId: deviceId, + bundleId: bundleId, + ); + if (apps.isNotEmpty) { + return true; + } + return false; + } + + Future installApp({ + required String deviceId, + required String bundlePath, + }) async { + if (!_xcode.isDevicectlInstalled) { + _logger.printError('devicectl is not installed.'); + return false; + } + + final Directory tempDirectory = _fileSystem.systemTempDirectory.createTempSync('core_devices.'); + final File output = tempDirectory.childFile('install_results.json'); + output.createSync(); + + final List command = [ + ..._xcode.xcrunCommand(), + 'devicectl', + 'device', + 'install', + 'app', + '--device', + deviceId, + bundlePath, + '--json-output', + output.path, + ]; + + try { + await _processUtils.run(command, throwOnError: true); + final String stringOutput = output.readAsStringSync(); + + try { + final Object? decodeResult = (json.decode(stringOutput) as Map)['info']; + if (decodeResult is Map && decodeResult['outcome'] == 'success') { + return true; + } + _logger.printError('devicectl returned unexpected JSON response: $stringOutput'); + return false; + } on FormatException { + // We failed to parse the devicectl output, or it returned junk. + _logger.printError('devicectl returned non-JSON response: $stringOutput'); + return false; + } + } on ProcessException catch (err) { + _logger.printError('Error executing devicectl: $err'); + return false; + } finally { + tempDirectory.deleteSync(recursive: true); + } + } + + /// Uninstalls the app from the device. Will succeed even if the app is not + /// currently installed on the device. + Future uninstallApp({ + required String deviceId, + required String bundleId, + }) async { + if (!_xcode.isDevicectlInstalled) { + _logger.printError('devicectl is not installed.'); + return false; + } + + final Directory tempDirectory = _fileSystem.systemTempDirectory.createTempSync('core_devices.'); + final File output = tempDirectory.childFile('uninstall_results.json'); + output.createSync(); + + final List command = [ + ..._xcode.xcrunCommand(), + 'devicectl', + 'device', + 'uninstall', + 'app', + '--device', + deviceId, + bundleId, + '--json-output', + output.path, + ]; + + try { + await _processUtils.run(command, throwOnError: true); + final String stringOutput = output.readAsStringSync(); + + try { + final Object? decodeResult = (json.decode(stringOutput) as Map)['info']; + if (decodeResult is Map && decodeResult['outcome'] == 'success') { + return true; + } + _logger.printError('devicectl returned unexpected JSON response: $stringOutput'); + return false; + } on FormatException { + // We failed to parse the devicectl output, or it returned junk. + _logger.printError('devicectl returned non-JSON response: $stringOutput'); + return false; + } + } on ProcessException catch (err) { + _logger.printError('Error executing devicectl: $err'); + return false; + } finally { + tempDirectory.deleteSync(recursive: true); + } + } + + Future launchApp({ + required String deviceId, + required String bundleId, + List launchArguments = const [], + }) async { + if (!_xcode.isDevicectlInstalled) { + _logger.printError('devicectl is not installed.'); + return false; + } + + final Directory tempDirectory = _fileSystem.systemTempDirectory.createTempSync('core_devices.'); + final File output = tempDirectory.childFile('launch_results.json'); + output.createSync(); + + final List command = [ + ..._xcode.xcrunCommand(), + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + bundleId, + if (launchArguments.isNotEmpty) ...launchArguments, + '--json-output', + output.path, + ]; + + try { + await _processUtils.run(command, throwOnError: true); + final String stringOutput = output.readAsStringSync(); + + try { + final Object? decodeResult = (json.decode(stringOutput) as Map)['info']; + if (decodeResult is Map && decodeResult['outcome'] == 'success') { + return true; + } + _logger.printError('devicectl returned unexpected JSON response: $stringOutput'); + return false; + } on FormatException { + // We failed to parse the devicectl output, or it returned junk. + _logger.printError('devicectl returned non-JSON response: $stringOutput'); + return false; + } + } on ProcessException catch (err) { + _logger.printError('Error executing devicectl: $err'); + return false; + } finally { + tempDirectory.deleteSync(recursive: true); + } + } +} + +class IOSCoreDevice { + IOSCoreDevice._({ + required this.capabilities, + required this.connectionProperties, + required this.deviceProperties, + required this.hardwareProperties, + required this.coreDeviceIdentifer, + required this.visibilityClass, + }); + + /// Parse JSON from `devicectl list devices --json-output` while it's in beta preview mode. + /// + /// Example: + /// { + /// "capabilities" : [ + /// ], + /// "connectionProperties" : { + /// }, + /// "deviceProperties" : { + /// }, + /// "hardwareProperties" : { + /// }, + /// "identifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + /// "visibilityClass" : "default" + /// } + factory IOSCoreDevice.fromBetaJson( + Map data, { + required Logger logger, + }) { + final List<_IOSCoreDeviceCapability> capabilitiesList = <_IOSCoreDeviceCapability>[]; + if (data['capabilities'] is List) { + final List capabilitiesData = data['capabilities']! as List; + for (final Object? capabilityData in capabilitiesData) { + if (capabilityData != null && capabilityData is Map) { + capabilitiesList.add(_IOSCoreDeviceCapability.fromBetaJson(capabilityData)); + } + } + } + + _IOSCoreDeviceConnectionProperties? connectionProperties; + if (data['connectionProperties'] is Map) { + final Map connectionPropertiesData = data['connectionProperties']! as Map; + connectionProperties = _IOSCoreDeviceConnectionProperties.fromBetaJson( + connectionPropertiesData, + logger: logger, + ); + } + + IOSCoreDeviceProperties? deviceProperties; + if (data['deviceProperties'] is Map) { + final Map devicePropertiesData = data['deviceProperties']! as Map; + deviceProperties = IOSCoreDeviceProperties.fromBetaJson(devicePropertiesData); + } + + _IOSCoreDeviceHardwareProperties? hardwareProperties; + if (data['hardwareProperties'] is Map) { + final Map hardwarePropertiesData = data['hardwareProperties']! as Map; + hardwareProperties = _IOSCoreDeviceHardwareProperties.fromBetaJson( + hardwarePropertiesData, + logger: logger, + ); + } + + return IOSCoreDevice._( + capabilities: capabilitiesList, + connectionProperties: connectionProperties, + deviceProperties: deviceProperties, + hardwareProperties: hardwareProperties, + coreDeviceIdentifer: data['identifier']?.toString(), + visibilityClass: data['visibilityClass']?.toString(), + ); + } + + String? get udid => hardwareProperties?.udid; + + DeviceConnectionInterface? get connectionInterface { + final String? transportType = connectionProperties?.transportType; + if (transportType != null) { + if (transportType.toLowerCase() == 'localnetwork') { + return DeviceConnectionInterface.wireless; + } else if (transportType.toLowerCase() == 'wired') { + return DeviceConnectionInterface.attached; + } + } + return null; + } + + @visibleForTesting + final List<_IOSCoreDeviceCapability> capabilities; + + @visibleForTesting + final _IOSCoreDeviceConnectionProperties? connectionProperties; + + final IOSCoreDeviceProperties? deviceProperties; + + @visibleForTesting + final _IOSCoreDeviceHardwareProperties? hardwareProperties; + + final String? coreDeviceIdentifer; + final String? visibilityClass; +} + + +class _IOSCoreDeviceCapability { + _IOSCoreDeviceCapability._({ + required this.featureIdentifier, + required this.name, + }); + + /// Parse `capabilities` section of JSON from `devicectl list devices --json-output` + /// while it's in beta preview mode. + /// + /// Example: + /// "capabilities" : [ + /// { + /// "featureIdentifier" : "com.apple.coredevice.feature.spawnexecutable", + /// "name" : "Spawn Executable" + /// }, + /// { + /// "featureIdentifier" : "com.apple.coredevice.feature.launchapplication", + /// "name" : "Launch Application" + /// } + /// ] + factory _IOSCoreDeviceCapability.fromBetaJson(Map data) { + return _IOSCoreDeviceCapability._( + featureIdentifier: data['featureIdentifier']?.toString(), + name: data['name']?.toString(), + ); + } + + final String? featureIdentifier; + final String? name; +} + +class _IOSCoreDeviceConnectionProperties { + _IOSCoreDeviceConnectionProperties._({ + required this.authenticationType, + required this.isMobileDeviceOnly, + required this.lastConnectionDate, + required this.localHostnames, + required this.pairingState, + required this.potentialHostnames, + required this.transportType, + required this.tunnelIPAddress, + required this.tunnelState, + required this.tunnelTransportProtocol, + }); + + /// Parse `connectionProperties` section of JSON from `devicectl list devices --json-output` + /// while it's in beta preview mode. + /// + /// Example: + /// "connectionProperties" : { + /// "authenticationType" : "manualPairing", + /// "isMobileDeviceOnly" : false, + /// "lastConnectionDate" : "2023-06-15T15:29:00.082Z", + /// "localHostnames" : [ + /// "iPadName.coredevice.local", + /// "00001234-0001234A3C03401E.coredevice.local", + /// "12345BB5-AEDE-4A22-B653-6037262550DD.coredevice.local" + /// ], + /// "pairingState" : "paired", + /// "potentialHostnames" : [ + /// "00001234-0001234A3C03401E.coredevice.local", + /// "12345BB5-AEDE-4A22-B653-6037262550DD.coredevice.local" + /// ], + /// "transportType" : "wired", + /// "tunnelIPAddress" : "fdf1:23c4:cd56::1", + /// "tunnelState" : "connected", + /// "tunnelTransportProtocol" : "tcp" + /// } + factory _IOSCoreDeviceConnectionProperties.fromBetaJson( + Map data, { + required Logger logger, + }) { + List? localHostnames; + if (data['localHostnames'] is List) { + final List values = data['localHostnames']! as List; + try { + localHostnames = List.from(values); + } on TypeError { + logger.printTrace('Error parsing localHostnames value: $values'); + } + } + + List? potentialHostnames; + if (data['potentialHostnames'] is List) { + final List values = data['potentialHostnames']! as List; + try { + potentialHostnames = List.from(values); + } on TypeError { + logger.printTrace('Error parsing potentialHostnames value: $values'); + } + } + return _IOSCoreDeviceConnectionProperties._( + authenticationType: data['authenticationType']?.toString(), + isMobileDeviceOnly: data['isMobileDeviceOnly'] is bool? ? data['isMobileDeviceOnly'] as bool? : null, + lastConnectionDate: data['lastConnectionDate']?.toString(), + localHostnames: localHostnames, + pairingState: data['pairingState']?.toString(), + potentialHostnames: potentialHostnames, + transportType: data['transportType']?.toString(), + tunnelIPAddress: data['tunnelIPAddress']?.toString(), + tunnelState: data['tunnelState']?.toString(), + tunnelTransportProtocol: data['tunnelTransportProtocol']?.toString(), + ); + } + + final String? authenticationType; + final bool? isMobileDeviceOnly; + final String? lastConnectionDate; + final List? localHostnames; + final String? pairingState; + final List? potentialHostnames; + final String? transportType; + final String? tunnelIPAddress; + final String? tunnelState; + final String? tunnelTransportProtocol; +} + +@visibleForTesting +class IOSCoreDeviceProperties { + IOSCoreDeviceProperties._({ + required this.bootedFromSnapshot, + required this.bootedSnapshotName, + required this.bootState, + required this.ddiServicesAvailable, + required this.developerModeStatus, + required this.hasInternalOSBuild, + required this.name, + required this.osBuildUpdate, + required this.osVersionNumber, + required this.rootFileSystemIsWritable, + required this.screenViewingURL, + }); + + /// Parse `deviceProperties` section of JSON from `devicectl list devices --json-output` + /// while it's in beta preview mode. + /// + /// Example: + /// "deviceProperties" : { + /// "bootedFromSnapshot" : true, + /// "bootedSnapshotName" : "com.apple.os.update-B5336980824124F599FD39FE91016493A74331B09F475250BB010B276FE2439E3DE3537349A3A957D3FF2A4B623B4ECC", + /// "bootState" : "booted", + /// "ddiServicesAvailable" : true, + /// "developerModeStatus" : "enabled", + /// "hasInternalOSBuild" : false, + /// "name" : "iPadName", + /// "osBuildUpdate" : "21A5248v", + /// "osVersionNumber" : "17.0", + /// "rootFileSystemIsWritable" : false, + /// "screenViewingURL" : "coredevice-devices:/viewDeviceByUUID?uuid=123456BB5-AEDE-7A22-B890-1234567890DD" + /// } + factory IOSCoreDeviceProperties.fromBetaJson(Map data) { + return IOSCoreDeviceProperties._( + bootedFromSnapshot: data['bootedFromSnapshot'] is bool? ? data['bootedFromSnapshot'] as bool? : null, + bootedSnapshotName: data['bootedSnapshotName']?.toString(), + bootState: data['bootState']?.toString(), + ddiServicesAvailable: data['ddiServicesAvailable'] is bool? ? data['ddiServicesAvailable'] as bool? : null, + developerModeStatus: data['developerModeStatus']?.toString(), + hasInternalOSBuild: data['hasInternalOSBuild'] is bool? ? data['hasInternalOSBuild'] as bool? : null, + name: data['name']?.toString(), + osBuildUpdate: data['osBuildUpdate']?.toString(), + osVersionNumber: data['osVersionNumber']?.toString(), + rootFileSystemIsWritable: data['rootFileSystemIsWritable'] is bool? ? data['rootFileSystemIsWritable'] as bool? : null, + screenViewingURL: data['screenViewingURL']?.toString(), + ); + } + + final bool? bootedFromSnapshot; + final String? bootedSnapshotName; + final String? bootState; + final bool? ddiServicesAvailable; + final String? developerModeStatus; + final bool? hasInternalOSBuild; + final String? name; + final String? osBuildUpdate; + final String? osVersionNumber; + final bool? rootFileSystemIsWritable; + final String? screenViewingURL; +} + +class _IOSCoreDeviceHardwareProperties { + _IOSCoreDeviceHardwareProperties._({ + required this.cpuType, + required this.deviceType, + required this.ecid, + required this.hardwareModel, + required this.internalStorageCapacity, + required this.marketingName, + required this.platform, + required this.productType, + required this.serialNumber, + required this.supportedCPUTypes, + required this.supportedDeviceFamilies, + required this.thinningProductType, + required this.udid, + }); + + /// Parse `hardwareProperties` section of JSON from `devicectl list devices --json-output` + /// while it's in beta preview mode. + /// + /// Example: + /// "hardwareProperties" : { + /// "cpuType" : { + /// "name" : "arm64e", + /// "subType" : 2, + /// "type" : 16777228 + /// }, + /// "deviceType" : "iPad", + /// "ecid" : 12345678903408542, + /// "hardwareModel" : "J617AP", + /// "internalStorageCapacity" : 128000000000, + /// "marketingName" : "iPad Pro (11-inch) (4th generation)\"", + /// "platform" : "iOS", + /// "productType" : "iPad14,3", + /// "serialNumber" : "HC123DHCQV", + /// "supportedCPUTypes" : [ + /// { + /// "name" : "arm64e", + /// "subType" : 2, + /// "type" : 16777228 + /// }, + /// { + /// "name" : "arm64", + /// "subType" : 0, + /// "type" : 16777228 + /// } + /// ], + /// "supportedDeviceFamilies" : [ + /// 1, + /// 2 + /// ], + /// "thinningProductType" : "iPad14,3-A", + /// "udid" : "00001234-0001234A3C03401E" + /// } + factory _IOSCoreDeviceHardwareProperties.fromBetaJson( + Map data, { + required Logger logger, + }) { + _IOSCoreDeviceCPUType? cpuType; + if (data['cpuType'] is Map) { + cpuType = _IOSCoreDeviceCPUType.fromBetaJson(data['cpuType']! as Map); + } + + List<_IOSCoreDeviceCPUType>? supportedCPUTypes; + if (data['supportedCPUTypes'] is List) { + final List values = data['supportedCPUTypes']! as List; + final List<_IOSCoreDeviceCPUType> cpuTypes = <_IOSCoreDeviceCPUType>[]; + for (final Object? cpuTypeData in values) { + if (cpuTypeData is Map) { + cpuTypes.add(_IOSCoreDeviceCPUType.fromBetaJson(cpuTypeData)); + } + } + supportedCPUTypes = cpuTypes; + } + + List? supportedDeviceFamilies; + if (data['supportedDeviceFamilies'] is List) { + final List values = data['supportedDeviceFamilies']! as List; + try { + supportedDeviceFamilies = List.from(values); + } on TypeError { + logger.printTrace('Error parsing supportedDeviceFamilies value: $values'); + } + } + + return _IOSCoreDeviceHardwareProperties._( + cpuType: cpuType, + deviceType: data['deviceType']?.toString(), + ecid: data['ecid'] is int? ? data['ecid'] as int? : null, + hardwareModel: data['hardwareModel']?.toString(), + internalStorageCapacity: data['internalStorageCapacity'] is int? ? data['internalStorageCapacity'] as int? : null, + marketingName: data['marketingName']?.toString(), + platform: data['platform']?.toString(), + productType: data['productType']?.toString(), + serialNumber: data['serialNumber']?.toString(), + supportedCPUTypes: supportedCPUTypes, + supportedDeviceFamilies: supportedDeviceFamilies, + thinningProductType: data['thinningProductType']?.toString(), + udid: data['udid']?.toString(), + ); + } + + final _IOSCoreDeviceCPUType? cpuType; + final String? deviceType; + final int? ecid; + final String? hardwareModel; + final int? internalStorageCapacity; + final String? marketingName; + final String? platform; + final String? productType; + final String? serialNumber; + final List<_IOSCoreDeviceCPUType>? supportedCPUTypes; + final List? supportedDeviceFamilies; + final String? thinningProductType; + final String? udid; +} + +class _IOSCoreDeviceCPUType { + _IOSCoreDeviceCPUType._({ + this.name, + this.subType, + this.cpuType, + }); + + /// Parse `hardwareProperties.cpuType` and `hardwareProperties.supportedCPUTypes` + /// sections of JSON from `devicectl list devices --json-output` while it's in beta preview mode. + /// + /// Example: + /// "cpuType" : { + /// "name" : "arm64e", + /// "subType" : 2, + /// "type" : 16777228 + /// } + factory _IOSCoreDeviceCPUType.fromBetaJson(Map data) { + return _IOSCoreDeviceCPUType._( + name: data['name']?.toString(), + subType: data['subType'] is int? ? data['subType'] as int? : null, + cpuType: data['type'] is int? ? data['type'] as int? : null, + ); + } + + final String? name; + final int? subType; + final int? cpuType; +} + +@visibleForTesting +class IOSCoreDeviceInstalledApp { + IOSCoreDeviceInstalledApp._({ + required this.appClip, + required this.builtByDeveloper, + required this.bundleIdentifier, + required this.bundleVersion, + required this.defaultApp, + required this.hidden, + required this.internalApp, + required this.name, + required this.removable, + required this.url, + required this.version, + }); + + /// Parse JSON from `devicectl device info apps --json-output` while it's in + /// beta preview mode. + /// + /// Example: + /// { + /// "appClip" : false, + /// "builtByDeveloper" : true, + /// "bundleIdentifier" : "com.example.flutterApp", + /// "bundleVersion" : "1", + /// "defaultApp" : false, + /// "hidden" : false, + /// "internalApp" : false, + /// "name" : "Flutter App", + /// "removable" : true, + /// "url" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/", + /// "version" : "1.0.0" + /// } + factory IOSCoreDeviceInstalledApp.fromBetaJson(Map data) { + return IOSCoreDeviceInstalledApp._( + appClip: data['appClip'] is bool? ? data['appClip'] as bool? : null, + builtByDeveloper: data['builtByDeveloper'] is bool? ? data['builtByDeveloper'] as bool? : null, + bundleIdentifier: data['bundleIdentifier']?.toString(), + bundleVersion: data['bundleVersion']?.toString(), + defaultApp: data['defaultApp'] is bool? ? data['defaultApp'] as bool? : null, + hidden: data['hidden'] is bool? ? data['hidden'] as bool? : null, + internalApp: data['internalApp'] is bool? ? data['internalApp'] as bool? : null, + name: data['name']?.toString(), + removable: data['removable'] is bool? ? data['removable'] as bool? : null, + url: data['url']?.toString(), + version: data['version']?.toString(), + ); + } + + final bool? appClip; + final bool? builtByDeveloper; + final String? bundleIdentifier; + final String? bundleVersion; + final bool? defaultApp; + final bool? hidden; + final bool? internalApp; + final String? name; + final bool? removable; + final String? url; + final String? version; +} diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 000529dad532b..b9a02e8660f66 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -15,6 +15,7 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/os.dart'; import '../base/platform.dart'; +import '../base/process.dart'; import '../base/utils.dart'; import '../base/version.dart'; import '../build_info.dart'; @@ -28,10 +29,13 @@ import '../project.dart'; import '../protocol_discovery.dart'; import '../vmservice.dart'; import 'application_package.dart'; +import 'core_devices.dart'; import 'ios_deploy.dart'; import 'ios_workflow.dart'; import 'iproxy.dart'; import 'mac.dart'; +import 'xcode_debug.dart'; +import 'xcodeproj.dart'; class IOSDevices extends PollingDeviceDiscovery { IOSDevices({ @@ -263,16 +267,21 @@ class IOSDevice extends Device { required this.connectionInterface, required this.isConnected, required this.devModeEnabled, + required this.isCoreDevice, String? sdkVersion, required Platform platform, required IOSDeploy iosDeploy, required IMobileDevice iMobileDevice, + required IOSCoreDeviceControl coreDeviceControl, + required XcodeDebug xcodeDebug, required IProxy iProxy, required Logger logger, }) : _sdkVersion = sdkVersion, _iosDeploy = iosDeploy, _iMobileDevice = iMobileDevice, + _coreDeviceControl = coreDeviceControl, + _xcodeDebug = xcodeDebug, _iproxy = iProxy, _fileSystem = fileSystem, _logger = logger, @@ -294,6 +303,8 @@ class IOSDevice extends Device { final Logger _logger; final Platform _platform; final IMobileDevice _iMobileDevice; + final IOSCoreDeviceControl _coreDeviceControl; + final XcodeDebug _xcodeDebug; final IProxy _iproxy; Version? get sdkVersion { @@ -324,6 +335,10 @@ class IOSDevice extends Device { @override bool isConnected; + /// CoreDevice is a device connectivity stack introduced in Xcode 15. Devices + /// with iOS 17 or greater are CoreDevices. + final bool isCoreDevice; + final Map _logReaders = {}; DevicePortForwarder? _portForwarder; @@ -349,10 +364,17 @@ class IOSDevice extends Device { }) async { bool result; try { - result = await _iosDeploy.isAppInstalled( - bundleId: app.id, - deviceId: id, - ); + if (isCoreDevice) { + result = await _coreDeviceControl.isAppInstalled( + bundleId: app.id, + deviceId: id, + ); + } else { + result = await _iosDeploy.isAppInstalled( + bundleId: app.id, + deviceId: id, + ); + } } on ProcessException catch (e) { _logger.printError(e.message); return false; @@ -376,13 +398,20 @@ class IOSDevice extends Device { int installationResult; try { - installationResult = await _iosDeploy.installApp( - deviceId: id, - bundlePath: bundle.path, - appDeltaDirectory: app.appDeltaDirectory, - launchArguments: [], - interfaceType: connectionInterface, - ); + if (isCoreDevice) { + installationResult = await _coreDeviceControl.installApp( + deviceId: id, + bundlePath: bundle.path, + ) ? 0 : 1; + } else { + installationResult = await _iosDeploy.installApp( + deviceId: id, + bundlePath: bundle.path, + appDeltaDirectory: app.appDeltaDirectory, + launchArguments: [], + interfaceType: connectionInterface, + ); + } } on ProcessException catch (e) { _logger.printError(e.message); return false; @@ -404,10 +433,17 @@ class IOSDevice extends Device { }) async { int uninstallationResult; try { - uninstallationResult = await _iosDeploy.uninstallApp( - deviceId: id, - bundleId: app.id, - ); + if (isCoreDevice) { + uninstallationResult = await _coreDeviceControl.uninstallApp( + deviceId: id, + bundleId: app.id, + ) ? 0 : 1; + } else { + uninstallationResult = await _iosDeploy.uninstallApp( + deviceId: id, + bundleId: app.id, + ); + } } on ProcessException catch (e) { _logger.printError(e.message); return false; @@ -434,6 +470,7 @@ class IOSDevice extends Device { bool ipv6 = false, String? userIdentifier, @visibleForTesting Duration? discoveryTimeout, + @visibleForTesting ShutdownHooks? shutdownHooks, }) async { String? packageId; if (isWirelesslyConnected && @@ -441,6 +478,18 @@ class IOSDevice extends Device { debuggingOptions.disablePortPublication) { throwToolExit('Cannot start app on wirelessly tethered iOS device. Try running again with the --publish-port flag'); } + + // TODO(vashworth): Remove after Xcode 15 and iOS 17 are in CI (https://github.com/flutter/flutter/issues/132128) + // XcodeDebug workflow is used for CoreDevices (iOS 17+ and Xcode 15+). + // Force the use of XcodeDebug workflow in CI to test from older versions + // since devicelab has not yet been updated to iOS 17 and Xcode 15. + bool forceXcodeDebugWorkflow = false; + if (debuggingOptions.usingCISystem && + debuggingOptions.debuggingEnabled && + _platform.environment['FORCE_XCODE_DEBUG']?.toLowerCase() == 'true') { + forceXcodeDebugWorkflow = true; + } + if (!prebuiltApplication) { _logger.printTrace('Building ${package.name} for $id'); @@ -451,6 +500,7 @@ class IOSDevice extends Device { targetOverride: mainPath, activeArch: cpuArchitecture, deviceID: id, + isCoreDevice: isCoreDevice || forceXcodeDebugWorkflow, ); if (!buildResult.success) { _logger.printError('Could not build the precompiled application for the device.'); @@ -477,6 +527,7 @@ class IOSDevice extends Device { platformArgs, ipv6: ipv6, interfaceType: connectionInterface, + isCoreDevice: isCoreDevice, ); Status startAppStatus = _logger.startProgress( 'Installing and launching...', @@ -516,7 +567,16 @@ class IOSDevice extends Device { logger: _logger, ); } - if (iosDeployDebugger == null) { + + if (isCoreDevice || forceXcodeDebugWorkflow) { + installationResult = await _startAppOnCoreDevice( + debuggingOptions: debuggingOptions, + package: package, + launchArguments: launchArguments, + discoveryTimeout: discoveryTimeout, + shutdownHooks: shutdownHooks ?? globals.shutdownHooks, + ) ? 0 : 1; + } else if (iosDeployDebugger == null) { installationResult = await _iosDeploy.launchApp( deviceId: id, bundlePath: bundle.path, @@ -543,10 +603,26 @@ class IOSDevice extends Device { _logger.printTrace('Application launched on the device. Waiting for Dart VM Service url.'); - final int defaultTimeout = isWirelesslyConnected ? 45 : 30; + final int defaultTimeout; + if ((isCoreDevice || forceXcodeDebugWorkflow) && debuggingOptions.debuggingEnabled) { + // Core devices with debugging enabled takes longer because this + // includes time to install and launch the app on the device. + defaultTimeout = isWirelesslyConnected ? 75 : 60; + } else if (isWirelesslyConnected) { + defaultTimeout = 45; + } else { + defaultTimeout = 30; + } + final Timer timer = Timer(discoveryTimeout ?? Duration(seconds: defaultTimeout), () { _logger.printError('The Dart VM Service was not discovered after $defaultTimeout seconds. This is taking much longer than expected...'); - + if (isCoreDevice && debuggingOptions.debuggingEnabled) { + _logger.printError( + 'Open the Xcode window the project is opened in to ensure the app ' + 'is running. If the app is not running, try selecting "Product > Run" ' + 'to fix the problem.', + ); + } // If debugging with a wireless device and the timeout is reached, remind the // user to allow local network permissions. if (isWirelesslyConnected) { @@ -564,37 +640,71 @@ class IOSDevice extends Device { Uri? localUri; if (isWirelesslyConnected) { - // Wait for Dart VM Service to start up. - final Uri? serviceURL = await vmServiceDiscovery?.uri; - if (serviceURL == null) { - await iosDeployDebugger?.stopAndDumpBacktrace(); - await dispose(); - return LaunchResult.failed(); - } + // When using a CoreDevice, device logs are unavailable and therefore + // cannot be used to get the Dart VM url. Instead, get the Dart VM + // Service by finding services matching the app bundle id and the + // device name. + // + // If not using a CoreDevice, wait for the Dart VM url to be discovered + // via logs and then get the Dart VM Service by finding services matching + // the app bundle id and the Dart VM port. + // + // Then in both cases, get the device IP from the Dart VM Service to + // construct the Dart VM url using the device IP as the host. + if (isCoreDevice) { + localUri = await MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( + packageId, + this, + usesIpv6: ipv6, + useDeviceIPAsHost: true, + ); + } else { + // Wait for Dart VM Service to start up. + final Uri? serviceURL = await vmServiceDiscovery?.uri; + if (serviceURL == null) { + await iosDeployDebugger?.stopAndDumpBacktrace(); + await dispose(); + return LaunchResult.failed(); + } - // If Dart VM Service URL with the device IP is not found within 5 seconds, - // change the status message to prompt users to click Allow. Wait 5 seconds because it - // should only show this message if they have not already approved the permissions. - // MDnsVmServiceDiscovery usually takes less than 5 seconds to find it. - final Timer mDNSLookupTimer = Timer(const Duration(seconds: 5), () { - startAppStatus.stop(); - startAppStatus = _logger.startProgress( - 'Waiting for approval of local network permissions...', + // If Dart VM Service URL with the device IP is not found within 5 seconds, + // change the status message to prompt users to click Allow. Wait 5 seconds because it + // should only show this message if they have not already approved the permissions. + // MDnsVmServiceDiscovery usually takes less than 5 seconds to find it. + final Timer mDNSLookupTimer = Timer(const Duration(seconds: 5), () { + startAppStatus.stop(); + startAppStatus = _logger.startProgress( + 'Waiting for approval of local network permissions...', + ); + }); + + // Get Dart VM Service URL with the device IP as the host. + localUri = await MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( + packageId, + this, + usesIpv6: ipv6, + deviceVmservicePort: serviceURL.port, + useDeviceIPAsHost: true, ); - }); - - // Get Dart VM Service URL with the device IP as the host. - localUri = await MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( - packageId, - this, - usesIpv6: ipv6, - deviceVmservicePort: serviceURL.port, - useDeviceIPAsHost: true, - ); - mDNSLookupTimer.cancel(); + mDNSLookupTimer.cancel(); + } } else { - localUri = await vmServiceDiscovery?.uri; + if (isCoreDevice && vmServiceDiscovery != null) { + // When searching for the Dart VM url, search for it via ProtocolDiscovery + // (device logs) and mDNS simultaneously, since both can be flaky at times. + final Future vmUrlFromMDns = MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( + packageId, + this, + usesIpv6: ipv6, + ); + final Future vmUrlFromLogs = vmServiceDiscovery.uri; + localUri = await Future.any( + >[vmUrlFromMDns, vmUrlFromLogs] + ); + } else { + localUri = await vmServiceDiscovery?.uri; + } } timer.cancel(); if (localUri == null) { @@ -613,6 +723,110 @@ class IOSDevice extends Device { } } + /// Starting with Xcode 15 and iOS 17, `ios-deploy` stopped working due to + /// the new CoreDevice connectivity stack. Previously, `ios-deploy` was used + /// to install the app, launch the app, and start `debugserver`. + /// Xcode 15 introduced a new command line tool called `devicectl` that + /// includes much of the functionality supplied by `ios-deploy`. However, + /// `devicectl` lacks the ability to start a `debugserver` and therefore `ptrace`, which are needed + /// for debug mode due to using a JIT Dart VM. + /// + /// Therefore, when starting an app on a CoreDevice, use `devicectl` when + /// debugging is not enabled. Otherwise, use Xcode automation. + Future _startAppOnCoreDevice({ + required DebuggingOptions debuggingOptions, + required IOSApp package, + required List launchArguments, + required ShutdownHooks shutdownHooks, + @visibleForTesting Duration? discoveryTimeout, + }) async { + if (!debuggingOptions.debuggingEnabled) { + // Release mode + + // Install app to device + final bool installSuccess = await _coreDeviceControl.installApp( + deviceId: id, + bundlePath: package.deviceBundlePath, + ); + if (!installSuccess) { + return installSuccess; + } + + // Launch app to device + final bool launchSuccess = await _coreDeviceControl.launchApp( + deviceId: id, + bundleId: package.id, + launchArguments: launchArguments, + ); + + return launchSuccess; + } else { + _logger.printStatus( + 'You may be prompted to give access to control Xcode. Flutter uses Xcode ' + 'to run your app. If access is not allowed, you can change this through ' + 'your Settings > Privacy & Security > Automation.', + ); + final int launchTimeout = isWirelesslyConnected ? 45 : 30; + final Timer timer = Timer(discoveryTimeout ?? Duration(seconds: launchTimeout), () { + _logger.printError( + 'Xcode is taking longer than expected to start debugging the app. ' + 'Ensure the project is opened in Xcode.', + ); + }); + + XcodeDebugProject debugProject; + + if (package is PrebuiltIOSApp) { + debugProject = await _xcodeDebug.createXcodeProjectWithCustomBundle( + package.deviceBundlePath, + templateRenderer: globals.templateRenderer, + verboseLogging: _logger.isVerbose, + ); + } else if (package is BuildableIOSApp) { + final IosProject project = package.project; + final XcodeProjectInfo? projectInfo = await project.projectInfo(); + if (projectInfo == null) { + globals.printError('Xcode project not found.'); + return false; + } + if (project.xcodeWorkspace == null) { + globals.printError('Unable to get Xcode workspace.'); + return false; + } + final String? scheme = projectInfo.schemeFor(debuggingOptions.buildInfo); + if (scheme == null) { + projectInfo.reportFlavorNotFoundAndExit(); + } + + debugProject = XcodeDebugProject( + scheme: scheme, + xcodeProject: project.xcodeProject, + xcodeWorkspace: project.xcodeWorkspace!, + verboseLogging: _logger.isVerbose, + ); + } else { + // This should not happen. Currently, only PrebuiltIOSApp and + // BuildableIOSApp extend from IOSApp. + _logger.printError('IOSApp type ${package.runtimeType} is not recognized.'); + return false; + } + + final bool debugSuccess = await _xcodeDebug.debugApp( + project: debugProject, + deviceId: id, + launchArguments:launchArguments, + ); + timer.cancel(); + + // Kill Xcode on shutdown when running from CI + if (debuggingOptions.usingCISystem) { + shutdownHooks.addShutdownHook(() => _xcodeDebug.exit(force: true)); + } + + return debugSuccess; + } + } + @override Future stopApp( ApplicationPackage? app, { @@ -623,6 +837,9 @@ class IOSDevice extends Device { if (deployDebugger != null && deployDebugger.debuggerAttached) { return deployDebugger.exit(); } + if (_xcodeDebug.debugStarted) { + return _xcodeDebug.exit(); + } return false; } @@ -669,7 +886,14 @@ class IOSDevice extends Device { void clearLogs() { } @override - bool get supportsScreenshot => _iMobileDevice.isInstalled; + bool get supportsScreenshot { + if (isCoreDevice) { + // `idevicescreenshot` stopped working with iOS 17 / Xcode 15 + // (https://github.com/flutter/flutter/issues/128598). + return false; + } + return _iMobileDevice.isInstalled; + } @override Future takeScreenshot(File outputFile) async { @@ -757,14 +981,18 @@ class IOSDeviceLogReader extends DeviceLogReader { this._majorSdkVersion, this._deviceId, this.name, + this._isWirelesslyConnected, + this._isCoreDevice, String appName, - bool usingCISystem, - ) : // Match for lines for the runner in syslog. + bool usingCISystem, { + bool forceXcodeDebug = false, + }) : // Match for lines for the runner in syslog. // // iOS 9 format: Runner[297] : // iOS 10 format: Runner(Flutter)[297] : _runnerLineRegex = RegExp(appName + r'(\(Flutter\))?\[[\d]+\] <[A-Za-z]+>: '), - _usingCISystem = usingCISystem; + _usingCISystem = usingCISystem, + _forceXcodeDebug = forceXcodeDebug; /// Create a new [IOSDeviceLogReader]. factory IOSDeviceLogReader.create({ @@ -779,8 +1007,11 @@ class IOSDeviceLogReader extends DeviceLogReader { device.majorSdkVersion, device.id, device.name, + device.isWirelesslyConnected, + device.isCoreDevice, appName, usingCISystem, + forceXcodeDebug: device._platform.environment['FORCE_XCODE_DEBUG']?.toLowerCase() == 'true', ); } @@ -790,6 +1021,8 @@ class IOSDeviceLogReader extends DeviceLogReader { bool useSyslog = true, bool usingCISystem = false, int? majorSdkVersion, + bool isWirelesslyConnected = false, + bool isCoreDevice = false, }) { final int sdkVersion; if (majorSdkVersion != null) { @@ -798,16 +1031,22 @@ class IOSDeviceLogReader extends DeviceLogReader { sdkVersion = useSyslog ? 12 : 13; } return IOSDeviceLogReader._( - iMobileDevice, sdkVersion, '1234', 'test', 'Runner', usingCISystem); + iMobileDevice, sdkVersion, '1234', 'test', isWirelesslyConnected, isCoreDevice, 'Runner', usingCISystem); } @override final String name; final int _majorSdkVersion; final String _deviceId; + final bool _isWirelesslyConnected; + final bool _isCoreDevice; final IMobileDevice _iMobileDevice; final bool _usingCISystem; + // TODO(vashworth): Remove after Xcode 15 and iOS 17 are in CI (https://github.com/flutter/flutter/issues/132128) + /// Whether XcodeDebug workflow is being forced. + final bool _forceXcodeDebug; + // Matches a syslog line from the runner. RegExp _runnerLineRegex; @@ -845,16 +1084,13 @@ class IOSDeviceLogReader extends DeviceLogReader { /// is true. final List _streamFlutterMessages = []; - /// When using both `idevicesyslog` and `ios-deploy`, exclude logs with the - /// "flutter:" prefix if they have already been added to the stream. This is - /// to prevent duplicates from being printed. - /// - /// If a message does not have the prefix, exclude it if the message's - /// source is `idevicesyslog`. This is done because `ios-deploy` and - /// `idevicesyslog` often have different prefixes on non-flutter messages - /// and are often not critical for CI tests. + /// There are three potential logging sources: `idevicesyslog`, `ios-deploy`, + /// and Unified Logging (Dart VM). When using more than one of these logging + /// sources at a time, exclude logs with a `flutter:` prefix if they have + /// already been added to the stream. This is to prevent duplicates from + /// being printed. bool _excludeLog(String message, IOSDeviceLogSource source) { - if (!useBothLogDeviceReaders) { + if (!usingMultipleLoggingSources) { return false; } if (message.startsWith('flutter:')) { @@ -862,7 +1098,12 @@ class IOSDeviceLogReader extends DeviceLogReader { return true; } _streamFlutterMessages.add(message); - } else if (source == IOSDeviceLogSource.idevicesyslog) { + } else if (useIOSDeployLogging && source == IOSDeviceLogSource.idevicesyslog) { + // If using both `ios-deploy` and `idevicesyslog` simultaneously, exclude + // the message if its source is `idevicesyslog`. This is done because + //`ios-deploy` and `idevicesyslog` often have different prefixes, which + // makes duplicate matching difficult. Instead, exclude any non-flutter-prefixed + // `idevicesyslog` messages, which are not critical for CI tests. return true; } return false; @@ -887,12 +1128,114 @@ class IOSDeviceLogReader extends DeviceLogReader { static const int minimumUniversalLoggingSdkVersion = 13; + /// Use `idevicesyslog` to stream logs from the device when one of the + /// following criteria is met: + /// + /// 1) The device is a physically attached CoreDevice. + /// 2) The device has iOS 16 or greater and it's being debugged from CI. + /// 3) The device has iOS 12 or lower. + /// + /// Syslog stopped working on iOS 13 (https://github.com/flutter/flutter/issues/41133). + /// However, from at least iOS 16, it has began working again. It's unclear + /// why it started working again. + @visibleForTesting + bool get useSyslogLogging { + // When forcing XcodeDebug workflow, use `idevicesyslog`. + if (_forceXcodeDebug) { + return true; + } + + // `ios-deploy` stopped working with iOS 17 / Xcode 15, so use `idevicesyslog` instead. + // However, `idevicesyslog` does not work with iOS 17 wireless devices. + if (_isCoreDevice && !_isWirelesslyConnected) { + return true; + } + + // Use both logs from `idevicesyslog` and `ios-deploy` when debugging from CI system + // since sometimes `ios-deploy` does not return the device logs: + // https://github.com/flutter/flutter/issues/121231 + if (_usingCISystem && _majorSdkVersion >= 16) { + return true; + } + if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) { + return true; + } + return false; + } + + /// Use the Dart VM to stream logs from the device when one of the following + /// criteria is met: + /// + /// 1) The device is a CoreDevice and wirelessly connected. + /// 2) The device has iOS 13 or greater and [_iosDeployDebugger] is null or + /// the [_iosDeployDebugger] debugger is not attached. + /// + /// This value may change if [_iosDeployDebugger] changes. + @visibleForTesting + bool get useUnifiedLogging { + // Can't use Unified Logging if it's not going to listen to the Dart VM. + if (!_shouldListenForUnifiedLoggingEvents) { + return false; + } + + // `idevicesyslog` doesn't work on wireless devices, so use logs from Dart VM instead. + if (_isCoreDevice) { + return true; + } + + // Prefer the more complete logs from the attached debugger, if they are available. + if (_majorSdkVersion >= minimumUniversalLoggingSdkVersion && (_iosDeployDebugger == null || !_iosDeployDebugger!.debuggerAttached)) { + return true; + } + + return false; + } + + /// Determine whether to listen to the Dart VM for logging events. Returns + /// true when one of the following criteria is met: + /// + /// 1) The device is a CoreDevice and wirelessly connected. + /// 2) The device has iOS 13 or greater. + bool get _shouldListenForUnifiedLoggingEvents { + // `idevicesyslog` doesn't work on wireless devices, so use logs from Dart VM instead. + if (_isCoreDevice) { + return true; + } + + if (_majorSdkVersion >= minimumUniversalLoggingSdkVersion) { + return true; + } + + return false; + } + + + /// Use `ios-deploy` to stream logs from the device when the device is not a + /// CoreDevice and has iOS 13 or greater. + @visibleForTesting + bool get useIOSDeployLogging { + if (_majorSdkVersion < minimumUniversalLoggingSdkVersion || _isCoreDevice) { + return false; + } + return true; + } + + @visibleForTesting + /// Returns true when using multiple sources for streaming the device logs. + bool get usingMultipleLoggingSources { + final int numberOfSources = (useIOSDeployLogging ? 1 : 0) + (useSyslogLogging ? 1 : 0) + (useUnifiedLogging ? 1 : 0); + if (numberOfSources > 1) { + return true; + } + return false; + } + /// Listen to Dart VM for logs on iOS 13 or greater. /// /// Only send logs to stream if [_iosDeployDebugger] is null or /// the [_iosDeployDebugger] debugger is not attached. Future _listenToUnifiedLoggingEvents(FlutterVmService connectedVmService) async { - if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) { + if (!_shouldListenForUnifiedLoggingEvents) { return; } try { @@ -909,7 +1252,7 @@ class IOSDeviceLogReader extends DeviceLogReader { } void logMessage(vm_service.Event event) { - if (_iosDeployDebugger != null && _iosDeployDebugger!.debuggerAttached) { + if (!useUnifiedLogging) { // Prefer the more complete logs from the attached debugger. return; } @@ -931,7 +1274,7 @@ class IOSDeviceLogReader extends DeviceLogReader { /// Send messages from ios-deploy debugger stream to device log reader stream. set debuggerStream(IOSDeployDebugger? debugger) { // Logging is gathered from syslog on iOS earlier than 13. - if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) { + if (!useIOSDeployLogging) { return; } _iosDeployDebugger = debugger; @@ -954,22 +1297,10 @@ class IOSDeviceLogReader extends DeviceLogReader { // Strip off the logging metadata (leave the category), or just echo the line. String _debuggerLineHandler(String line) => _debuggerLoggingRegex.firstMatch(line)?.group(1) ?? line; - /// Use both logs from `idevicesyslog` and `ios-deploy` when debugging from CI system - /// since sometimes `ios-deploy` does not return the device logs: - /// https://github.com/flutter/flutter/issues/121231 - @visibleForTesting - bool get useBothLogDeviceReaders { - return _usingCISystem && _majorSdkVersion >= 16; - } - /// Start and listen to idevicesyslog to get device logs for iOS versions /// prior to 13 or if [useBothLogDeviceReaders] is true. void _listenToSysLog() { - // Syslog stopped working on iOS 13 (https://github.com/flutter/flutter/issues/41133). - // However, from at least iOS 16, it has began working again. It's unclear - // why it started working again so only use syslogs for iOS versions prior - // to 13 unless [useBothLogDeviceReaders] is true. - if (!useBothLogDeviceReaders && _majorSdkVersion >= minimumUniversalLoggingSdkVersion) { + if (!useSyslogLogging) { return; } _iMobileDevice.startLogger(_deviceId).then((Process process) { @@ -982,7 +1313,7 @@ class IOSDeviceLogReader extends DeviceLogReader { // When using both log readers, do not close the stream on exit. // This is to allow ios-deploy to be the source of authority to close // the stream. - if (useBothLogDeviceReaders && debuggerStream != null) { + if (useSyslogLogging && useIOSDeployLogging && debuggerStream != null) { return; } linesController.close(); diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 6a088c705cde3..34c487e7ff652 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -132,6 +132,7 @@ Future buildXcodeProject({ DarwinArch? activeArch, bool codesign = true, String? deviceID, + bool isCoreDevice = false, bool configOnly = false, XcodeBuildAction buildAction = XcodeBuildAction.build, }) async { @@ -240,6 +241,7 @@ Future buildXcodeProject({ project: project, targetOverride: targetOverride, buildInfo: buildInfo, + usingCoreDevice: isCoreDevice, ); await processPodsIfNeeded(project.ios, getIosBuildDirectory(), buildInfo.mode); if (configOnly) { diff --git a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart index 2ef75a209de2a..0e7c42b9f34d2 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -35,6 +35,7 @@ Future updateGeneratedXcodeProperties({ String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, + bool usingCoreDevice = false, }) async { final List xcodeBuildSettings = await _xcodeBuildSettingsLines( project: project, @@ -42,6 +43,7 @@ Future updateGeneratedXcodeProperties({ targetOverride: targetOverride, useMacOSConfig: useMacOSConfig, buildDirOverride: buildDirOverride, + usingCoreDevice: usingCoreDevice, ); _updateGeneratedXcodePropertiesFile( @@ -143,6 +145,7 @@ Future> _xcodeBuildSettingsLines({ String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, + bool usingCoreDevice = false, }) async { final List xcodeBuildSettings = []; @@ -170,6 +173,12 @@ Future> _xcodeBuildSettingsLines({ final String buildNumber = parsedBuildNumber(manifest: project.manifest, buildInfo: buildInfo) ?? '1'; xcodeBuildSettings.add('FLUTTER_BUILD_NUMBER=$buildNumber'); + // CoreDevices in debug and profile mode are launched, but not built, via Xcode. + // Set the BUILD_DIR so Xcode knows where to find the app bundle to launch. + if (usingCoreDevice && !buildInfo.isRelease) { + xcodeBuildSettings.add('BUILD_DIR=${globals.fs.path.absolute(getIosBuildDirectory())}'); + } + final LocalEngineInfo? localEngineInfo = globals.artifacts?.localEngineInfo; if (localEngineInfo != null) { final String engineOutPath = localEngineInfo.engineOutPath; diff --git a/packages/flutter_tools/lib/src/ios/xcode_debug.dart b/packages/flutter_tools/lib/src/ios/xcode_debug.dart new file mode 100644 index 0000000000000..2708add258def --- /dev/null +++ b/packages/flutter_tools/lib/src/ios/xcode_debug.dart @@ -0,0 +1,479 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:meta/meta.dart'; +import 'package:process/process.dart'; + +import '../base/file_system.dart'; +import '../base/io.dart'; +import '../base/logger.dart'; +import '../base/process.dart'; +import '../base/template.dart'; +import '../convert.dart'; +import '../macos/xcode.dart'; +import '../template.dart'; + +/// A class to handle interacting with Xcode via OSA (Open Scripting Architecture) +/// Scripting to debug Flutter applications. +class XcodeDebug { + XcodeDebug({ + required Logger logger, + required ProcessManager processManager, + required Xcode xcode, + required FileSystem fileSystem, + }) : _logger = logger, + _processUtils = ProcessUtils(logger: logger, processManager: processManager), + _xcode = xcode, + _fileSystem = fileSystem; + + final ProcessUtils _processUtils; + final Logger _logger; + final Xcode _xcode; + final FileSystem _fileSystem; + + /// Process to start Xcode's debug action. + @visibleForTesting + Process? startDebugActionProcess; + + /// Information about the project that is currently being debugged. + @visibleForTesting + XcodeDebugProject? currentDebuggingProject; + + /// Whether the debug action has been started. + bool get debugStarted => currentDebuggingProject != null; + + /// Install, launch, and start a debug session for app through Xcode interface, + /// automated by OSA scripting. First checks if the project is opened in + /// Xcode. If it isn't, open it with the `open` command. + /// + /// The OSA script waits until the project is opened and the debug action + /// has started. It does not wait for the app to install, launch, or start + /// the debug session. + Future debugApp({ + required XcodeDebugProject project, + required String deviceId, + required List launchArguments, + }) async { + + // If project is not already opened in Xcode, open it. + if (!await _isProjectOpenInXcode(project: project)) { + final bool openResult = await _openProjectInXcode(xcodeWorkspace: project.xcodeWorkspace); + if (!openResult) { + return openResult; + } + } + + currentDebuggingProject = project; + StreamSubscription? stdoutSubscription; + StreamSubscription? stderrSubscription; + try { + startDebugActionProcess = await _processUtils.start( + [ + ..._xcode.xcrunCommand(), + 'osascript', + '-l', + 'JavaScript', + _xcode.xcodeAutomationScriptPath, + 'debug', + '--xcode-path', + _xcode.xcodeAppPath, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + json.encode(launchArguments), + if (project.verboseLogging) '--verbose', + ], + ); + + final StringBuffer stdoutBuffer = StringBuffer(); + stdoutSubscription = startDebugActionProcess!.stdout + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + _logger.printTrace(line); + stdoutBuffer.write(line); + }); + + final StringBuffer stderrBuffer = StringBuffer(); + bool permissionWarningPrinted = false; + // console.log from the script are found in the stderr + stderrSubscription = startDebugActionProcess!.stderr + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + _logger.printTrace('stderr: $line'); + stderrBuffer.write(line); + + // This error may occur if Xcode automation has not been allowed. + // Example: Failed to get workspace: Error: An error occurred. + if (!permissionWarningPrinted && line.contains('Failed to get workspace') && line.contains('An error occurred')) { + _logger.printError( + 'There was an error finding the project in Xcode. Ensure permission ' + 'has been given to control Xcode in Settings > Privacy & Security > Automation.', + ); + permissionWarningPrinted = true; + } + }); + + final int exitCode = await startDebugActionProcess!.exitCode.whenComplete(() async { + await stdoutSubscription?.cancel(); + await stderrSubscription?.cancel(); + startDebugActionProcess = null; + }); + + if (exitCode != 0) { + _logger.printError('Error executing osascript: $exitCode\n$stderrBuffer'); + return false; + } + + final XcodeAutomationScriptResponse? response = parseScriptResponse( + stdoutBuffer.toString(), + ); + if (response == null) { + return false; + } + if (response.status == false) { + _logger.printError('Error starting debug session in Xcode: ${response.errorMessage}'); + return false; + } + if (response.debugResult == null) { + _logger.printError('Unable to get debug results from response: $stdoutBuffer'); + return false; + } + if (response.debugResult?.status != 'running') { + _logger.printError( + 'Unexpected debug results: \n' + ' Status: ${response.debugResult?.status}\n' + ' Completed: ${response.debugResult?.completed}\n' + ' Error Message: ${response.debugResult?.errorMessage}\n' + ); + return false; + } + return true; + } on ProcessException catch (exception) { + _logger.printError('Error executing osascript: $exitCode\n$exception'); + await stdoutSubscription?.cancel(); + await stderrSubscription?.cancel(); + startDebugActionProcess = null; + + return false; + } + } + + /// Kills [startDebugActionProcess] if it's still running. If [force] is true, it + /// will kill all Xcode app processes. Otherwise, it will stop the debug + /// session in Xcode. If the project is temporary, it will close the Xcode + /// window of the project and then delete the project. + Future exit({ + bool force = false, + @visibleForTesting + bool skipDelay = false, + }) async { + final bool success = (startDebugActionProcess == null) || startDebugActionProcess!.kill(); + + if (force) { + await _forceExitXcode(); + if (currentDebuggingProject != null) { + final XcodeDebugProject project = currentDebuggingProject!; + if (project.isTemporaryProject) { + project.xcodeProject.parent.deleteSync(recursive: true); + } + currentDebuggingProject = null; + } + } + + if (currentDebuggingProject != null) { + final XcodeDebugProject project = currentDebuggingProject!; + await stopDebuggingApp( + project: project, + closeXcode: project.isTemporaryProject, + ); + + if (project.isTemporaryProject) { + // Wait a couple seconds before deleting the project. If project is + // still opened in Xcode and it's deleted, it will prompt the user to + // restore it. + if (!skipDelay) { + await Future.delayed(const Duration(seconds: 2)); + } + + try { + project.xcodeProject.parent.deleteSync(recursive: true); + } on FileSystemException { + _logger.printError('Failed to delete temporary Xcode project: ${project.xcodeProject.parent.path}'); + } + } + currentDebuggingProject = null; + } + + return success; + } + + /// Kill all opened Xcode applications. + Future _forceExitXcode() async { + final RunResult result = await _processUtils.run( + [ + 'killall', + '-9', + 'Xcode', + ], + ); + + if (result.exitCode != 0) { + _logger.printError('Error killing Xcode: ${result.exitCode}\n${result.stderr}'); + return false; + } + return true; + } + + Future _isProjectOpenInXcode({ + required XcodeDebugProject project, + }) async { + + final RunResult result = await _processUtils.run( + [ + ..._xcode.xcrunCommand(), + 'osascript', + '-l', + 'JavaScript', + _xcode.xcodeAutomationScriptPath, + 'check-workspace-opened', + '--xcode-path', + _xcode.xcodeAppPath, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + if (project.verboseLogging) '--verbose', + ], + ); + + if (result.exitCode != 0) { + _logger.printError('Error executing osascript: ${result.exitCode}\n${result.stderr}'); + return false; + } + + final XcodeAutomationScriptResponse? response = parseScriptResponse(result.stdout); + if (response == null) { + return false; + } + if (response.status == false) { + _logger.printTrace('Error checking if project opened in Xcode: ${response.errorMessage}'); + return false; + } + return true; + } + + @visibleForTesting + XcodeAutomationScriptResponse? parseScriptResponse(String results) { + try { + final Object decodeResult = json.decode(results) as Object; + if (decodeResult is Map) { + final XcodeAutomationScriptResponse response = XcodeAutomationScriptResponse.fromJson(decodeResult); + // Status should always be found + if (response.status != null) { + return response; + } + } + _logger.printError('osascript returned unexpected JSON response: $results'); + return null; + } on FormatException { + _logger.printError('osascript returned non-JSON response: $results'); + return null; + } + } + + Future _openProjectInXcode({ + required Directory xcodeWorkspace, + }) async { + try { + await _processUtils.run( + [ + 'open', + '-a', + _xcode.xcodeAppPath, + '-g', // Do not bring the application to the foreground. + '-j', // Launches the app hidden. + xcodeWorkspace.path + ], + throwOnError: true, + ); + return true; + } on ProcessException catch (error, stackTrace) { + _logger.printError('$error', stackTrace: stackTrace); + } + return false; + } + + /// Using OSA Scripting, stop the debug session in Xcode. + /// + /// If [closeXcode] is true, it will close the Xcode window that has the + /// project opened. If [promptToSaveOnClose] is true, it will ask the user if + /// they want to save any changes before it closes. + Future stopDebuggingApp({ + required XcodeDebugProject project, + bool closeXcode = false, + bool promptToSaveOnClose = false, + }) async { + final RunResult result = await _processUtils.run( + [ + ..._xcode.xcrunCommand(), + 'osascript', + '-l', + 'JavaScript', + _xcode.xcodeAutomationScriptPath, + 'stop', + '--xcode-path', + _xcode.xcodeAppPath, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + if (closeXcode) '--close-window', + if (promptToSaveOnClose) '--prompt-to-save', + if (project.verboseLogging) '--verbose', + ], + ); + + if (result.exitCode != 0) { + _logger.printError('Error executing osascript: ${result.exitCode}\n${result.stderr}'); + return false; + } + + final XcodeAutomationScriptResponse? response = parseScriptResponse(result.stdout); + if (response == null) { + return false; + } + if (response.status == false) { + _logger.printError('Error stopping app in Xcode: ${response.errorMessage}'); + return false; + } + return true; + } + + /// Create a temporary empty Xcode project with the application bundle + /// location explicitly set. + Future createXcodeProjectWithCustomBundle( + String deviceBundlePath, { + required TemplateRenderer templateRenderer, + @visibleForTesting + Directory? projectDestination, + bool verboseLogging = false, + }) async { + final Directory tempXcodeProject = projectDestination ?? _fileSystem.systemTempDirectory.createTempSync('flutter_empty_xcode.'); + + final Template template = await Template.fromName( + _fileSystem.path.join('xcode', 'ios', 'custom_application_bundle'), + fileSystem: _fileSystem, + templateManifest: null, + logger: _logger, + templateRenderer: templateRenderer, + ); + + template.render( + tempXcodeProject, + { + 'applicationBundlePath': deviceBundlePath + }, + printStatusWhenWriting: false, + ); + + return XcodeDebugProject( + scheme: 'Runner', + xcodeProject: tempXcodeProject.childDirectory('Runner.xcodeproj'), + xcodeWorkspace: tempXcodeProject.childDirectory('Runner.xcworkspace'), + isTemporaryProject: true, + verboseLogging: verboseLogging, + ); + } +} + +@visibleForTesting +class XcodeAutomationScriptResponse { + XcodeAutomationScriptResponse._({ + this.status, + this.errorMessage, + this.debugResult, + }); + + factory XcodeAutomationScriptResponse.fromJson(Map data) { + XcodeAutomationScriptDebugResult? debugResult; + if (data['debugResult'] != null && data['debugResult'] is Map) { + debugResult = XcodeAutomationScriptDebugResult.fromJson( + data['debugResult']! as Map, + ); + } + return XcodeAutomationScriptResponse._( + status: data['status'] is bool? ? data['status'] as bool? : null, + errorMessage: data['errorMessage']?.toString(), + debugResult: debugResult, + ); + } + + final bool? status; + final String? errorMessage; + final XcodeAutomationScriptDebugResult? debugResult; +} + +@visibleForTesting +class XcodeAutomationScriptDebugResult { + XcodeAutomationScriptDebugResult._({ + required this.completed, + required this.status, + required this.errorMessage, + }); + + factory XcodeAutomationScriptDebugResult.fromJson(Map data) { + return XcodeAutomationScriptDebugResult._( + completed: data['completed'] is bool? ? data['completed'] as bool? : null, + status: data['status']?.toString(), + errorMessage: data['errorMessage']?.toString(), + ); + } + + /// Whether this scheme action has completed (sucessfully or otherwise). Will + /// be false if still running. + final bool? completed; + + /// The status of the debug action. Potential statuses include: + /// `not yet started`, `‌running`, `‌cancelled`, `‌failed`, `‌error occurred`, + /// and `‌succeeded`. + /// + /// Only the status of `‌running` indicates the debug action has started successfully. + /// For example, `‌succeeded` often does not indicate success as if the action fails, + /// it will sometimes return `‌succeeded`. + final String? status; + + /// When [status] is `‌error occurred`, an error message is provided. + /// Otherwise, this will be null. + final String? errorMessage; +} + +class XcodeDebugProject { + XcodeDebugProject({ + required this.scheme, + required this.xcodeWorkspace, + required this.xcodeProject, + this.isTemporaryProject = false, + this.verboseLogging = false, + }); + + final String scheme; + final Directory xcodeWorkspace; + final Directory xcodeProject; + final bool isTemporaryProject; + + /// When [verboseLogging] is true, the xcode_debug.js script will log + /// additional information via console.log, which is sent to stderr. + final bool verboseLogging; +} diff --git a/packages/flutter_tools/lib/src/macos/xcdevice.dart b/packages/flutter_tools/lib/src/macos/xcdevice.dart index c53fdcaf9260b..a2c66eea776d1 100644 --- a/packages/flutter_tools/lib/src/macos/xcdevice.dart +++ b/packages/flutter_tools/lib/src/macos/xcdevice.dart @@ -8,6 +8,7 @@ import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../artifacts.dart'; +import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; @@ -18,10 +19,12 @@ import '../cache.dart'; import '../convert.dart'; import '../device.dart'; import '../globals.dart' as globals; +import '../ios/core_devices.dart'; import '../ios/devices.dart'; import '../ios/ios_deploy.dart'; import '../ios/iproxy.dart'; import '../ios/mac.dart'; +import '../ios/xcode_debug.dart'; import '../reporting/reporting.dart'; import 'xcode.dart'; @@ -65,6 +68,10 @@ class XCDevice { required Xcode xcode, required Platform platform, required IProxy iproxy, + required FileSystem fileSystem, + @visibleForTesting + IOSCoreDeviceControl? coreDeviceControl, + XcodeDebug? xcodeDebug, }) : _processUtils = ProcessUtils(logger: logger, processManager: processManager), _logger = logger, _iMobileDevice = IMobileDevice( @@ -80,6 +87,18 @@ class XCDevice { platform: platform, processManager: processManager, ), + _coreDeviceControl = coreDeviceControl ?? IOSCoreDeviceControl( + logger: logger, + processManager: processManager, + xcode: xcode, + fileSystem: fileSystem, + ), + _xcodeDebug = xcodeDebug ?? XcodeDebug( + logger: logger, + processManager: processManager, + xcode: xcode, + fileSystem: fileSystem, + ), _iProxy = iproxy, _xcode = xcode { @@ -99,6 +118,8 @@ class XCDevice { final IOSDeploy _iosDeploy; final Xcode _xcode; final IProxy _iProxy; + final IOSCoreDeviceControl _coreDeviceControl; + final XcodeDebug _xcodeDebug; List? _cachedListResults; @@ -457,6 +478,17 @@ class XCDevice { return const []; } + final Map coreDeviceMap = {}; + if (_xcode.isDevicectlInstalled) { + final List coreDevices = await _coreDeviceControl.getCoreDevices(); + for (final IOSCoreDevice device in coreDevices) { + if (device.udid == null) { + continue; + } + coreDeviceMap[device.udid!] = device; + } + } + // [ // { // "simulator" : true, @@ -565,11 +597,27 @@ class XCDevice { } } + DeviceConnectionInterface connectionInterface = _interfaceType(device); + + // CoreDevices (devices with iOS 17 and greater) no longer reflect the + // correct connection interface or developer mode status in `xcdevice`. + // Use `devicectl` to get that information for CoreDevices. + final IOSCoreDevice? coreDevice = coreDeviceMap[identifier]; + if (coreDevice != null) { + if (coreDevice.connectionInterface != null) { + connectionInterface = coreDevice.connectionInterface!; + } + + if (coreDevice.deviceProperties?.developerModeStatus != 'enabled') { + devModeEnabled = false; + } + } + deviceMap[identifier] = IOSDevice( identifier, name: name, cpuArchitecture: _cpuArchitecture(device), - connectionInterface: _interfaceType(device), + connectionInterface: connectionInterface, isConnected: isConnected, sdkVersion: sdkVersionString, iProxy: _iProxy, @@ -577,8 +625,11 @@ class XCDevice { logger: _logger, iosDeploy: _iosDeploy, iMobileDevice: _iMobileDevice, + coreDeviceControl: _coreDeviceControl, + xcodeDebug: _xcodeDebug, platform: globals.platform, devModeEnabled: devModeEnabled, + isCoreDevice: coreDevice != null, ); } } diff --git a/packages/flutter_tools/lib/src/macos/xcode.dart b/packages/flutter_tools/lib/src/macos/xcode.dart index 4784013da8e70..540f08d5f3b38 100644 --- a/packages/flutter_tools/lib/src/macos/xcode.dart +++ b/packages/flutter_tools/lib/src/macos/xcode.dart @@ -14,8 +14,10 @@ import '../base/io.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/process.dart'; +import '../base/user_messages.dart'; import '../base/version.dart'; import '../build_info.dart'; +import '../cache.dart'; import '../ios/xcodeproj.dart'; Version get xcodeRequiredVersion => Version(14, null, null); @@ -44,9 +46,13 @@ class Xcode { required Logger logger, required FileSystem fileSystem, required XcodeProjectInterpreter xcodeProjectInterpreter, + required UserMessages userMessages, + String? flutterRoot, }) : _platform = platform, _fileSystem = fileSystem, _xcodeProjectInterpreter = xcodeProjectInterpreter, + _userMessage = userMessages, + _flutterRoot = flutterRoot, _processUtils = ProcessUtils(logger: logger, processManager: processManager), _logger = logger; @@ -61,6 +67,7 @@ class Xcode { XcodeProjectInterpreter? xcodeProjectInterpreter, Platform? platform, FileSystem? fileSystem, + String? flutterRoot, Logger? logger, }) { platform ??= FakePlatform( @@ -72,6 +79,8 @@ class Xcode { platform: platform, processManager: processManager, fileSystem: fileSystem ?? MemoryFileSystem.test(), + userMessages: UserMessages(), + flutterRoot: flutterRoot, logger: logger, xcodeProjectInterpreter: xcodeProjectInterpreter ?? XcodeProjectInterpreter.test(processManager: processManager), ); @@ -81,6 +90,8 @@ class Xcode { final ProcessUtils _processUtils; final FileSystem _fileSystem; final XcodeProjectInterpreter _xcodeProjectInterpreter; + final UserMessages _userMessage; + final String? _flutterRoot; final Logger _logger; bool get isInstalledAndMeetsVersionCheck => _platform.isMacOS && isInstalled && isRequiredVersionSatisfactory; @@ -101,6 +112,38 @@ class Xcode { return _xcodeSelectPath; } + String get xcodeAppPath { + // If the Xcode Select Path is /Applications/Xcode.app/Contents/Developer, + // the path to Xcode App is /Applications/Xcode.app + + final String? pathToXcode = xcodeSelectPath; + if (pathToXcode == null || pathToXcode.isEmpty) { + throwToolExit(_userMessage.xcodeMissing); + } + final int index = pathToXcode.indexOf('.app'); + if (index == -1) { + throwToolExit(_userMessage.xcodeMissing); + } + return pathToXcode.substring(0, index + 4); + } + + /// Path to script to automate debugging through Xcode. Used in xcode_debug.dart. + /// Located in this file to make it easily overrideable in google3. + String get xcodeAutomationScriptPath { + final String flutterRoot = _flutterRoot ?? Cache.flutterRoot!; + final String flutterToolsAbsolutePath = _fileSystem.path.join( + flutterRoot, + 'packages', + 'flutter_tools', + ); + + final String filePath = '$flutterToolsAbsolutePath/bin/xcode_debug.js'; + if (!_fileSystem.file(filePath).existsSync()) { + throwToolExit('Unable to find Xcode automation script at $filePath'); + } + return filePath; + } + bool get isInstalled => _xcodeProjectInterpreter.isInstalled; Version? get currentVersion => _xcodeProjectInterpreter.version; @@ -150,6 +193,28 @@ class Xcode { return _isSimctlInstalled ?? false; } + bool? _isDevicectlInstalled; + + /// Verifies that `devicectl` is installed by checking Xcode version and trying + /// to run it. `devicectl` is made available in Xcode 15. + bool get isDevicectlInstalled { + if (_isDevicectlInstalled == null) { + try { + if (currentVersion == null || currentVersion!.major < 15) { + _isDevicectlInstalled = false; + return _isDevicectlInstalled!; + } + final RunResult result = _processUtils.runSync( + [...xcrunCommand(), 'devicectl', '--version'], + ); + _isDevicectlInstalled = result.exitCode == 0; + } on ProcessException { + _isDevicectlInstalled = false; + } + } + return _isDevicectlInstalled ?? false; + } + bool get isRequiredVersionSatisfactory { final Version? version = currentVersion; if (version == null) { diff --git a/packages/flutter_tools/lib/src/mdns_discovery.dart b/packages/flutter_tools/lib/src/mdns_discovery.dart index 82196118afc00..da6527596caa3 100644 --- a/packages/flutter_tools/lib/src/mdns_discovery.dart +++ b/packages/flutter_tools/lib/src/mdns_discovery.dart @@ -130,9 +130,9 @@ class MDnsVmServiceDiscovery { /// The [deviceVmservicePort] parameter must be set to specify which port /// to find. /// - /// [applicationId] and [deviceVmservicePort] are required for launch so that - /// if multiple flutter apps are running on different devices, it will - /// only match with the device running the desired app. + /// [applicationId] and either [deviceVmservicePort] or [deviceName] are + /// required for launch so that if multiple flutter apps are running on + /// different devices, it will only match with the device running the desired app. /// /// The [useDeviceIPAsHost] parameter flags whether to get the device IP /// and the [ipv6] parameter flags whether to get an iPv6 address @@ -141,21 +141,27 @@ class MDnsVmServiceDiscovery { /// The [timeout] parameter determines how long to continue to wait for /// services to become active. /// - /// If a Dart VM Service matching the [applicationId] and [deviceVmservicePort] - /// cannot be found after the [timeout], it will call [throwToolExit]. + /// If a Dart VM Service matching the [applicationId] and + /// [deviceVmservicePort]/[deviceName] cannot be found before the [timeout] + /// is reached, it will call [throwToolExit]. @visibleForTesting Future queryForLaunch({ required String applicationId, - required int deviceVmservicePort, + int? deviceVmservicePort, + String? deviceName, bool ipv6 = false, bool useDeviceIPAsHost = false, Duration timeout = const Duration(minutes: 10), }) async { - // Query for a specific application and device port. + // Either the device port or the device name must be provided. + assert(deviceVmservicePort != null || deviceName != null); + + // Query for a specific application matching on either device port or device name. return firstMatchingVmService( _client, applicationId: applicationId, deviceVmservicePort: deviceVmservicePort, + deviceName: deviceName, ipv6: ipv6, useDeviceIPAsHost: useDeviceIPAsHost, timeout: timeout, @@ -170,6 +176,7 @@ class MDnsVmServiceDiscovery { MDnsClient client, { String? applicationId, int? deviceVmservicePort, + String? deviceName, bool ipv6 = false, bool useDeviceIPAsHost = false, Duration timeout = const Duration(minutes: 10), @@ -178,6 +185,7 @@ class MDnsVmServiceDiscovery { client, applicationId: applicationId, deviceVmservicePort: deviceVmservicePort, + deviceName: deviceName, ipv6: ipv6, useDeviceIPAsHost: useDeviceIPAsHost, timeout: timeout, @@ -193,6 +201,7 @@ class MDnsVmServiceDiscovery { MDnsClient client, { String? applicationId, int? deviceVmservicePort, + String? deviceName, bool ipv6 = false, bool useDeviceIPAsHost = false, required Duration timeout, @@ -263,6 +272,11 @@ class MDnsVmServiceDiscovery { continue; } + // If deviceName is set, only use records that match it + if (deviceName != null && !deviceNameMatchesTargetName(deviceName, srvRecord.target)) { + continue; + } + // Get the IP address of the device if using the IP as the host. InternetAddress? ipAddress; if (useDeviceIPAsHost) { @@ -332,6 +346,15 @@ class MDnsVmServiceDiscovery { } } + @visibleForTesting + bool deviceNameMatchesTargetName(String deviceName, String targetName) { + // Remove `.local` from the name along with any non-word, non-digit characters. + final RegExp cleanedNameRegex = RegExp(r'\.local|\W'); + final String cleanedDeviceName = deviceName.trim().toLowerCase().replaceAll(cleanedNameRegex, ''); + final String cleanedTargetName = targetName.toLowerCase().replaceAll(cleanedNameRegex, ''); + return cleanedDeviceName == cleanedTargetName; + } + String _getAuthCode(String txtRecord) { const String authCodePrefix = 'authCode='; final Iterable matchingRecords = @@ -354,7 +377,7 @@ class MDnsVmServiceDiscovery { /// When [useDeviceIPAsHost] is true, it will use the device's IP as the /// host and will not forward the port. /// - /// Differs from `getVMServiceUriForLaunch` because it can search for any available Dart VM Service. + /// Differs from [getVMServiceUriForLaunch] because it can search for any available Dart VM Service. /// Since [applicationId] and [deviceVmservicePort] are optional, it can either look for any service /// or a specific service matching [applicationId]/[deviceVmservicePort]. /// It may find more than one service, which will throw an error listing the found services. @@ -391,20 +414,22 @@ class MDnsVmServiceDiscovery { /// When [useDeviceIPAsHost] is true, it will use the device's IP as the /// host and will not forward the port. /// - /// Differs from `getVMServiceUriForAttach` because it only searches for a specific service. - /// This is enforced by [applicationId] and [deviceVmservicePort] being required. + /// Differs from [getVMServiceUriForAttach] because it only searches for a specific service. + /// This is enforced by [applicationId] being required and using either the + /// [deviceVmservicePort] or the [device]'s name to query. Future getVMServiceUriForLaunch( String applicationId, Device device, { bool usesIpv6 = false, int? hostVmservicePort, - required int deviceVmservicePort, + int? deviceVmservicePort, bool useDeviceIPAsHost = false, Duration timeout = const Duration(minutes: 10), }) async { final MDnsVmServiceDiscoveryResult? result = await queryForLaunch( applicationId: applicationId, deviceVmservicePort: deviceVmservicePort, + deviceName: deviceVmservicePort == null ? device.name : null, ipv6: usesIpv6, useDeviceIPAsHost: useDeviceIPAsHost, timeout: timeout, diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json index d0902d5edc286..3729d8909fa75 100644 --- a/packages/flutter_tools/templates/template_manifest.json +++ b/packages/flutter_tools/templates/template_manifest.json @@ -339,6 +339,15 @@ "templates/skeleton/README.md.tmpl", "templates/skeleton/test/implementation_test.dart.test.tmpl", "templates/skeleton/test/unit_test.dart.tmpl", - "templates/skeleton/test/widget_test.dart.tmpl" + "templates/skeleton/test/widget_test.dart.tmpl", + + "templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/contents.xcworkspacedata", + "templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist", + "templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings", + "templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.pbxproj", + "templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata", + "templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist", + "templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", + "templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl" ] } diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/README.md b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/README.md new file mode 100644 index 0000000000000..2b2b69707db5d --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/README.md @@ -0,0 +1,5 @@ +# Template Xcode project with a custom application bundle + +This template is an empty Xcode project with a settable application bundle path +within the `xcscheme`. It is used when debugging a project on a physical iOS 17+ +device via Xcode 15+ when `--use-application-binary` is used. \ No newline at end of file diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.pbxproj b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.pbxproj new file mode 100644 index 0000000000000..8f544ef77eb2b --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.pbxproj @@ -0,0 +1,297 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXFileReference section */ + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000000..919434a6254f0 --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000000..f9b0d7c5ea15f --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl new file mode 100644 index 0000000000000..bcca935dea1c6 --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcodeproj.tmpl/xcshareddata/xcschemes/Runner.xcscheme.tmpl @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/contents.xcworkspacedata b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/contents.xcworkspacedata new file mode 100644 index 0000000000000..1d526a16ed0f1 --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000000..18d981003d68d --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000000..f9b0d7c5ea15f --- /dev/null +++ b/packages/flutter_tools/templates/xcode/ios/custom_application_bundle/Runner.xcworkspace.tmpl/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/packages/flutter_tools/test/general.shard/device_test.dart b/packages/flutter_tools/test/general.shard/device_test.dart index fab87b8f71090..14e3dbb6bfeab 100644 --- a/packages/flutter_tools/test/general.shard/device_test.dart +++ b/packages/flutter_tools/test/general.shard/device_test.dart @@ -884,6 +884,26 @@ void main() { ); }); + testWithoutContext('Get launch arguments for physical CoreDevice with debugging enabled with no launch arguments', () { + final DebuggingOptions original = DebuggingOptions.enabled( + BuildInfo.debug, + ); + + final List launchArguments = original.getIOSLaunchArguments( + EnvironmentType.physical, + null, + {}, + isCoreDevice: true, + ); + + expect( + launchArguments.join(' '), + [ + '--enable-dart-profiling', + ].join(' '), + ); + }); + testWithoutContext('Get launch arguments for physical device with iPv4 network connection', () { final DebuggingOptions original = DebuggingOptions.enabled( BuildInfo.debug, diff --git a/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart b/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart new file mode 100644 index 0000000000000..d820e1a13bcb2 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/ios/core_devices_test.dart @@ -0,0 +1,1949 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/version.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; +import 'package:flutter_tools/src/ios/xcodeproj.dart'; +import 'package:flutter_tools/src/macos/xcode.dart'; + +import '../../src/common.dart'; +import '../../src/fake_process_manager.dart'; + +void main() { + late MemoryFileSystem fileSystem; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + }); + + group('Xcode prior to Core Device Control/Xcode 15', () { + late BufferLogger logger; + late FakeProcessManager fakeProcessManager; + late Xcode xcode; + late IOSCoreDeviceControl deviceControl; + + setUp(() { + logger = BufferLogger.test(); + fakeProcessManager = FakeProcessManager.empty(); + final XcodeProjectInterpreter xcodeProjectInterpreter = XcodeProjectInterpreter.test( + processManager: fakeProcessManager, + version: Version(14, 0, 0), + ); + xcode = Xcode.test( + processManager: FakeProcessManager.any(), + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + deviceControl = IOSCoreDeviceControl( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + }); + + group('devicectl is not installed', () { + testWithoutContext('fails to get device list', () async { + final List devices = await deviceControl.getCoreDevices(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl is not installed.')); + expect(devices.isEmpty, isTrue); + }); + + testWithoutContext('fails to install app', () async { + final bool status = await deviceControl.installApp(deviceId: 'device-id', bundlePath: '/path/to/bundle'); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl is not installed.')); + expect(status, isFalse); + }); + + testWithoutContext('fails to launch app', () async { + final bool status = await deviceControl.launchApp(deviceId: 'device-id', bundleId: 'com.example.flutterApp'); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl is not installed.')); + expect(status, isFalse); + }); + + testWithoutContext('fails to check if app is installed', () async { + final bool status = await deviceControl.isAppInstalled(deviceId: 'device-id', bundleId: 'com.example.flutterApp'); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl is not installed.')); + expect(status, isFalse); + }); + }); + }); + + group('Core Device Control', () { + late BufferLogger logger; + late FakeProcessManager fakeProcessManager; + late Xcode xcode; + late IOSCoreDeviceControl deviceControl; + + setUp(() { + logger = BufferLogger.test(); + fakeProcessManager = FakeProcessManager.empty(); + xcode = Xcode.test(processManager: FakeProcessManager.any()); + deviceControl = IOSCoreDeviceControl( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + }); + + group('install app', () { + const String deviceId = 'device-id'; + const String bundlePath = '/path/to/com.example.flutterApp'; + + testWithoutContext('Successful install', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "install", + "app", + "--device", + "00001234-0001234A3C03401E", + "build/ios/iphoneos/Runner.app", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/install_results.json" + ], + "commandType" : "devicectl.device.install.app", + "environment" : { + + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "installedApplications" : [ + { + "bundleID" : "com.example.bundle", + "databaseSequenceNumber" : 1230, + "databaseUUID" : "1234A567-D890-1B23-BCF4-D5D67A8D901E", + "installationURL" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/", + "launchServicesIdentifier" : "unknown", + "options" : { + + } + } + ] + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('install_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'install', + 'app', + '--device', + deviceId, + bundlePath, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.installApp( + deviceId: deviceId, + bundlePath: bundlePath, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(status, true); + }); + + testWithoutContext('devicectl fails install', () async { + const String deviceControlOutput = ''' +{ + "error" : { + "code" : 1005, + "domain" : "com.apple.dt.CoreDeviceError", + "userInfo" : { + "NSLocalizedDescription" : { + "string" : "Could not obtain access to one or more requested file system resources because CoreDevice was unable to create bookmark data." + }, + "NSUnderlyingError" : { + "error" : { + "code" : 260, + "domain" : "NSCocoaErrorDomain", + "userInfo" : { + + } + } + } + } + }, + "info" : { + "arguments" : [ + "devicectl", + "device", + "install", + "app", + "--device", + "00001234-0001234A3C03401E", + "/path/to/app", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/install_results.json" + ], + "commandType" : "devicectl.device.install.app", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "failed", + "version" : "341" + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('install_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'install', + 'app', + '--device', + deviceId, + bundlePath, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + exitCode: 1, + stderr: ''' +ERROR: Could not obtain access to one or more requested file system resources because CoreDevice was unable to create bookmark data. (com.apple.dt.CoreDeviceError error 1005.) + NSURL = file:///path/to/app +-------------------------------------------------------------------------------- +ERROR: The file couldn’t be opened because it doesn’t exist. (NSCocoaErrorDomain error 260.) +''' + )); + + final bool status = await deviceControl.installApp( + deviceId: deviceId, + bundlePath: bundlePath, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('ERROR: Could not obtain access to one or more requested file system')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails install because of unexpected JSON', () async { + const String deviceControlOutput = ''' +{ + "valid_unexpected_json": true +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('install_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'install', + 'app', + '--device', + deviceId, + bundlePath, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.installApp( + deviceId: deviceId, + bundlePath: bundlePath, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned unexpected JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails install because of invalid JSON', () async { + const String deviceControlOutput = ''' +invalid JSON +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('install_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'install', + 'app', + '--device', + deviceId, + bundlePath, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.installApp( + deviceId: deviceId, + bundlePath: bundlePath, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned non-JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + }); + + group('uninstall app', () { + const String deviceId = 'device-id'; + const String bundleId = 'com.example.flutterApp'; + + testWithoutContext('Successful uninstall', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "uninstall", + "app", + "--device", + "00001234-0001234A3C03401E", + "build/ios/iphoneos/Runner.app", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/uninstall_results.json" + ], + "commandType" : "devicectl.device.uninstall.app", + "environment" : { + + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "uninstalledApplications" : [ + { + "bundleID" : "com.example.bundle" + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('uninstall_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'uninstall', + 'app', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.uninstallApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(status, true); + }); + + testWithoutContext('devicectl fails uninstall', () async { + const String deviceControlOutput = ''' +{ + "error" : { + "code" : 1005, + "domain" : "com.apple.dt.CoreDeviceError", + "userInfo" : { + "NSLocalizedDescription" : { + "string" : "Could not obtain access to one or more requested file system resources because CoreDevice was unable to create bookmark data." + }, + "NSUnderlyingError" : { + "error" : { + "code" : 260, + "domain" : "NSCocoaErrorDomain", + "userInfo" : { + + } + } + } + } + }, + "info" : { + "arguments" : [ + "devicectl", + "device", + "uninstall", + "app", + "--device", + "00001234-0001234A3C03401E", + "com.example.flutterApp", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/uninstall_results.json" + ], + "commandType" : "devicectl.device.uninstall.app", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "failed", + "version" : "341" + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('uninstall_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'uninstall', + 'app', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + exitCode: 1, + stderr: ''' +ERROR: Could not obtain access to one or more requested file system resources because CoreDevice was unable to create bookmark data. (com.apple.dt.CoreDeviceError error 1005.) + NSURL = file:///path/to/app +-------------------------------------------------------------------------------- +ERROR: The file couldn’t be opened because it doesn’t exist. (NSCocoaErrorDomain error 260.) +''' + )); + + final bool status = await deviceControl.uninstallApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('ERROR: Could not obtain access to one or more requested file system')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails uninstall because of unexpected JSON', () async { + const String deviceControlOutput = ''' +{ + "valid_unexpected_json": true +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('uninstall_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'uninstall', + 'app', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.uninstallApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned unexpected JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails uninstall because of invalid JSON', () async { + const String deviceControlOutput = ''' +invalid JSON +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('uninstall_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'uninstall', + 'app', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.uninstallApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned non-JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + }); + + group('launch app', () { + const String deviceId = 'device-id'; + const String bundleId = 'com.example.flutterApp'; + + testWithoutContext('Successful launch without launch args', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "process", + "launch", + "--device", + "00001234-0001234A3C03401E", + "com.example.flutterApp", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/install_results.json" + ], + "commandType" : "devicectl.device.process.launch", + "environment" : { + + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "launchOptions" : { + "activatedWhenStarted" : true, + "arguments" : [ + + ], + "environmentVariables" : { + "TERM" : "vt100" + }, + "platformSpecificOptions" : { + + }, + "startStopped" : false, + "terminateExistingInstances" : false, + "user" : { + "active" : true + } + }, + "process" : { + "auditToken" : [ + 12345, + 678 + ], + "executable" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/Runner", + "processIdentifier" : 1234 + } + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('launch_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.launchApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(status, true); + }); + + testWithoutContext('Successful launch with launch args', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "process", + "launch", + "--device", + "00001234-0001234A3C03401E", + "com.example.flutterApp", + "--arg1", + "--arg2", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/install_results.json" + ], + "commandType" : "devicectl.device.process.launch", + "environment" : { + + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "launchOptions" : { + "activatedWhenStarted" : true, + "arguments" : [ + + ], + "environmentVariables" : { + "TERM" : "vt100" + }, + "platformSpecificOptions" : { + + }, + "startStopped" : false, + "terminateExistingInstances" : false, + "user" : { + "active" : true + } + }, + "process" : { + "auditToken" : [ + 12345, + 678 + ], + "executable" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/Runner", + "processIdentifier" : 1234 + } + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('launch_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + bundleId, + '--arg1', + '--arg2', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.launchApp( + deviceId: deviceId, + bundleId: bundleId, + launchArguments: ['--arg1', '--arg2'], + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(status, true); + }); + + testWithoutContext('devicectl fails install', () async { + const String deviceControlOutput = ''' +{ + "error" : { + "code" : -10814, + "domain" : "NSOSStatusErrorDomain", + "userInfo" : { + "_LSFunction" : { + "string" : "runEvaluator" + }, + "_LSLine" : { + "int" : 1608 + } + } + }, + "info" : { + "arguments" : [ + "devicectl", + "device", + "process", + "launch", + "--device", + "00001234-0001234A3C03401E", + "com.example.flutterApp", + "--json-output", + "/var/folders/wq/randompath/T/flutter_tools.rand0/core_devices.rand0/install_results.json" + ], + "commandType" : "devicectl.device.process.launch", + "environment" : { + + }, + "outcome" : "failed", + "version" : "341" + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('launch_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + exitCode: 1, + stderr: ''' +ERROR: The operation couldn?t be completed. (OSStatus error -10814.) (NSOSStatusErrorDomain error -10814.) + _LSFunction = runEvaluator + _LSLine = 1608 +''' + )); + + final bool status = await deviceControl.launchApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('ERROR: The operation couldn?t be completed.')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails launch because of unexpected JSON', () async { + const String deviceControlOutput = ''' +{ + "valid_unexpected_json": true +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('launch_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + + final bool status = await deviceControl.launchApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned unexpected JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails launch because of invalid JSON', () async { + const String deviceControlOutput = ''' +invalid JSON +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('launch_results.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'process', + 'launch', + '--device', + deviceId, + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.launchApp( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned non-JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + }); + + group('list apps', () { + const String deviceId = 'device-id'; + const String bundleId = 'com.example.flutterApp'; + + testWithoutContext('Successfully parses apps', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "info", + "apps", + "--device", + "00001234-0001234A3C03401E", + "--bundle-id", + "com.example.flutterApp", + "--json-output", + "apps.txt" + ], + "commandType" : "devicectl.device.info.apps", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "apps" : [ + { + "appClip" : false, + "builtByDeveloper" : true, + "bundleIdentifier" : "com.example.flutterApp", + "bundleVersion" : "1", + "defaultApp" : false, + "hidden" : false, + "internalApp" : false, + "name" : "Bundle", + "removable" : true, + "url" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/", + "version" : "1.0.0" + }, + { + "appClip" : true, + "builtByDeveloper" : false, + "bundleIdentifier" : "com.example.flutterApp2", + "bundleVersion" : "2", + "defaultApp" : true, + "hidden" : true, + "internalApp" : true, + "name" : "Bundle 2", + "removable" : false, + "url" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/", + "version" : "1.0.0" + } + ], + "defaultAppsIncluded" : false, + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "hiddenAppsIncluded" : false, + "internalAppsIncluded" : false, + "matchingBundleIdentifier" : "com.example.flutterApp", + "removableAppsIncluded" : true + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_app_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + '--bundle-id', + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List apps = await deviceControl.getInstalledApps( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(apps.length, 2); + + expect(apps[0].appClip, isFalse); + expect(apps[0].builtByDeveloper, isTrue); + expect(apps[0].bundleIdentifier, 'com.example.flutterApp'); + expect(apps[0].bundleVersion, '1'); + expect(apps[0].defaultApp, isFalse); + expect(apps[0].hidden, isFalse); + expect(apps[0].internalApp, isFalse); + expect(apps[0].name, 'Bundle'); + expect(apps[0].removable, isTrue); + expect(apps[0].url, 'file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/'); + expect(apps[0].version, '1.0.0'); + + expect(apps[1].appClip, isTrue); + expect(apps[1].builtByDeveloper, isFalse); + expect(apps[1].bundleIdentifier, 'com.example.flutterApp2'); + expect(apps[1].bundleVersion, '2'); + expect(apps[1].defaultApp, isTrue); + expect(apps[1].hidden, isTrue); + expect(apps[1].internalApp, isTrue); + expect(apps[1].name, 'Bundle 2'); + expect(apps[1].removable, isFalse); + expect(apps[1].url, 'file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/'); + expect(apps[1].version, '1.0.0'); + }); + + + testWithoutContext('Successfully find installed app', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "info", + "apps", + "--device", + "00001234-0001234A3C03401E", + "--bundle-id", + "com.example.flutterApp", + "--json-output", + "apps.txt" + ], + "commandType" : "devicectl.device.info.apps", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "apps" : [ + { + "appClip" : false, + "builtByDeveloper" : true, + "bundleIdentifier" : "com.example.flutterApp", + "bundleVersion" : "1", + "defaultApp" : false, + "hidden" : false, + "internalApp" : false, + "name" : "Bundle", + "removable" : true, + "url" : "file:///private/var/containers/Bundle/Application/12345E6A-7F89-0C12-345E-F6A7E890CFF1/Runner.app/", + "version" : "1.0.0" + } + ], + "defaultAppsIncluded" : false, + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "hiddenAppsIncluded" : false, + "internalAppsIncluded" : false, + "matchingBundleIdentifier" : "com.example.flutterApp", + "removableAppsIncluded" : true + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_app_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + '--bundle-id', + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.isAppInstalled( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(status, true); + }); + + testWithoutContext('Succeeds but does not find app', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "device", + "info", + "apps", + "--device", + "00001234-0001234A3C03401E", + "--bundle-id", + "com.example.flutterApp", + "--json-output", + "apps.txt" + ], + "commandType" : "devicectl.device.info.apps", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "341" + }, + "result" : { + "apps" : [ + ], + "defaultAppsIncluded" : false, + "deviceIdentifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "hiddenAppsIncluded" : false, + "internalAppsIncluded" : false, + "matchingBundleIdentifier" : "com.example.flutterApp", + "removableAppsIncluded" : true + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_app_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + '--bundle-id', + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.isAppInstalled( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, isEmpty); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('devicectl fails to get apps', () async { + const String deviceControlOutput = ''' +{ + "error" : { + "code" : 1000, + "domain" : "com.apple.dt.CoreDeviceError", + "userInfo" : { + "NSLocalizedDescription" : { + "string" : "The specified device was not found." + } + } + }, + "info" : { + "arguments" : [ + "devicectl", + "device", + "info", + "apps", + "--device", + "00001234-0001234A3C03401E", + "--bundle-id", + "com.example.flutterApp", + "--json-output", + "apps.txt" + ], + "commandType" : "devicectl.device.info.apps", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "failed", + "version" : "341" + } +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_app_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + '--bundle-id', + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + exitCode: 1, + stderr: ''' +ERROR: The specified device was not found. (com.apple.dt.CoreDeviceError error 1000.) +''' + )); + + final bool status = await deviceControl.isAppInstalled( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('ERROR: The specified device was not found.')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails launch because of unexpected JSON', () async { + const String deviceControlOutput = ''' +{ + "valid_unexpected_json": true +} +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_app_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + '--bundle-id', + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + + final bool status = await deviceControl.isAppInstalled( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned unexpected JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + + testWithoutContext('fails launch because of invalid JSON', () async { + const String deviceControlOutput = ''' +invalid JSON +'''; + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_app_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'device', + 'info', + 'apps', + '--device', + deviceId, + '--bundle-id', + bundleId, + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final bool status = await deviceControl.isAppInstalled( + deviceId: deviceId, + bundleId: bundleId, + ); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned non-JSON response')); + expect(tempFile, isNot(exists)); + expect(status, false); + }); + }); + + group('list devices', () { + testWithoutContext('No devices', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "list", + "devices", + "--json-output", + "core_device_list.json" + ], + "commandType" : "devicectl.list.devices", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "325.3" + }, + "result" : { + "devices" : [ + + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(devices.isEmpty, isTrue); + }); + + testWithoutContext('All sections parsed', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "list", + "devices", + "--json-output", + "core_device_list.json" + ], + "commandType" : "devicectl.list.devices", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "325.3" + }, + "result" : { + "devices" : [ + { + "capabilities" : [ + ], + "connectionProperties" : { + }, + "deviceProperties" : { + }, + "hardwareProperties" : { + }, + "identifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "visibilityClass" : "default" + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.length, 1); + + expect(devices[0].capabilities, isNotNull); + expect(devices[0].connectionProperties, isNotNull); + expect(devices[0].deviceProperties, isNotNull); + expect(devices[0].hardwareProperties, isNotNull); + expect(devices[0].coreDeviceIdentifer, '123456BB5-AEDE-7A22-B890-1234567890DD'); + expect(devices[0].visibilityClass, 'default'); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(tempFile, isNot(exists)); + }); + + testWithoutContext('All sections parsed, device missing sections', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "list", + "devices", + "--json-output", + "core_device_list.json" + ], + "commandType" : "devicectl.list.devices", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "325.3" + }, + "result" : { + "devices" : [ + { + "identifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "visibilityClass" : "default" + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.length, 1); + + expect(devices[0].capabilities, isEmpty); + expect(devices[0].connectionProperties, isNull); + expect(devices[0].deviceProperties, isNull); + expect(devices[0].hardwareProperties, isNull); + expect(devices[0].coreDeviceIdentifer, '123456BB5-AEDE-7A22-B890-1234567890DD'); + expect(devices[0].visibilityClass, 'default'); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(tempFile, isNot(exists)); + }); + + testWithoutContext('capabilities parsed', () async { + const String deviceControlOutput = ''' +{ + "result" : { + "devices" : [ + { + "capabilities" : [ + { + "featureIdentifier" : "com.apple.coredevice.feature.spawnexecutable", + "name" : "Spawn Executable" + }, + { + "featureIdentifier" : "com.apple.coredevice.feature.launchapplication", + "name" : "Launch Application" + } + ] + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.length, 1); + + expect(devices[0].capabilities.length, 2); + expect(devices[0].capabilities[0].featureIdentifier, 'com.apple.coredevice.feature.spawnexecutable'); + expect(devices[0].capabilities[0].name, 'Spawn Executable'); + expect(devices[0].capabilities[1].featureIdentifier, 'com.apple.coredevice.feature.launchapplication'); + expect(devices[0].capabilities[1].name, 'Launch Application'); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(tempFile, isNot(exists)); + }); + + testWithoutContext('connectionProperties parsed', () async { + const String deviceControlOutput = ''' +{ + "result" : { + "devices" : [ + { + "connectionProperties" : { + "authenticationType" : "manualPairing", + "isMobileDeviceOnly" : false, + "lastConnectionDate" : "2023-06-15T15:29:00.082Z", + "localHostnames" : [ + "Victorias-iPad.coredevice.local", + "00001234-0001234A3C03401E.coredevice.local", + "123456BB5-AEDE-7A22-B890-1234567890DD.coredevice.local" + ], + "pairingState" : "paired", + "potentialHostnames" : [ + "00001234-0001234A3C03401E.coredevice.local", + "123456BB5-AEDE-7A22-B890-1234567890DD.coredevice.local" + ], + "transportType" : "wired", + "tunnelIPAddress" : "fdf1:23c4:cd56::1", + "tunnelState" : "connected", + "tunnelTransportProtocol" : "tcp" + } + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.length, 1); + + expect(devices[0].connectionProperties?.authenticationType, 'manualPairing'); + expect(devices[0].connectionProperties?.isMobileDeviceOnly, false); + expect(devices[0].connectionProperties?.lastConnectionDate, '2023-06-15T15:29:00.082Z'); + expect( + devices[0].connectionProperties?.localHostnames, + [ + 'Victorias-iPad.coredevice.local', + '00001234-0001234A3C03401E.coredevice.local', + '123456BB5-AEDE-7A22-B890-1234567890DD.coredevice.local', + ], + ); + expect(devices[0].connectionProperties?.pairingState, 'paired'); + expect(devices[0].connectionProperties?.potentialHostnames, [ + '00001234-0001234A3C03401E.coredevice.local', + '123456BB5-AEDE-7A22-B890-1234567890DD.coredevice.local', + ]); + expect(devices[0].connectionProperties?.transportType, 'wired'); + expect(devices[0].connectionProperties?.tunnelIPAddress, 'fdf1:23c4:cd56::1'); + expect(devices[0].connectionProperties?.tunnelState, 'connected'); + expect(devices[0].connectionProperties?.tunnelTransportProtocol, 'tcp'); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(tempFile, isNot(exists)); + }); + + testWithoutContext('deviceProperties parsed', () async { + const String deviceControlOutput = ''' +{ + "result" : { + "devices" : [ + { + "deviceProperties" : { + "bootedFromSnapshot" : true, + "bootedSnapshotName" : "com.apple.os.update-123456", + "bootState" : "booted", + "ddiServicesAvailable" : true, + "developerModeStatus" : "enabled", + "hasInternalOSBuild" : false, + "name" : "iPadName", + "osBuildUpdate" : "21A5248v", + "osVersionNumber" : "17.0", + "rootFileSystemIsWritable" : false, + "screenViewingURL" : "coredevice-devices:/viewDeviceByUUID?uuid=123456BB5-AEDE-7A22-B890-1234567890DD" + } + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.length, 1); + + expect(devices[0].deviceProperties?.bootedFromSnapshot, true); + expect(devices[0].deviceProperties?.bootedSnapshotName, 'com.apple.os.update-123456'); + expect(devices[0].deviceProperties?.bootState, 'booted'); + expect(devices[0].deviceProperties?.ddiServicesAvailable, true); + expect(devices[0].deviceProperties?.developerModeStatus, 'enabled'); + expect(devices[0].deviceProperties?.hasInternalOSBuild, false); + expect(devices[0].deviceProperties?.name, 'iPadName'); + expect(devices[0].deviceProperties?.osBuildUpdate, '21A5248v'); + expect(devices[0].deviceProperties?.osVersionNumber, '17.0'); + expect(devices[0].deviceProperties?.rootFileSystemIsWritable, false); + expect(devices[0].deviceProperties?.screenViewingURL, 'coredevice-devices:/viewDeviceByUUID?uuid=123456BB5-AEDE-7A22-B890-1234567890DD'); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(tempFile, isNot(exists)); + }); + + testWithoutContext('hardwareProperties parsed', () async { + const String deviceControlOutput = r''' +{ + "result" : { + "devices" : [ + { + "hardwareProperties" : { + "cpuType" : { + "name" : "arm64e", + "subType" : 2, + "type" : 16777228 + }, + "deviceType" : "iPad", + "ecid" : 12345678903408542, + "hardwareModel" : "J617AP", + "internalStorageCapacity" : 128000000000, + "marketingName" : "iPad Pro (11-inch) (4th generation)\"", + "platform" : "iOS", + "productType" : "iPad14,3", + "serialNumber" : "HC123DHCQV", + "supportedCPUTypes" : [ + { + "name" : "arm64e", + "subType" : 2, + "type" : 16777228 + }, + { + "name" : "arm64", + "subType" : 0, + "type" : 16777228 + } + ], + "supportedDeviceFamilies" : [ + 1, + 2 + ], + "thinningProductType" : "iPad14,3-A", + "udid" : "00001234-0001234A3C03401E" + } + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.length, 1); + + expect(devices[0].hardwareProperties?.cpuType, isNotNull); + expect(devices[0].hardwareProperties?.cpuType?.name, 'arm64e'); + expect(devices[0].hardwareProperties?.cpuType?.subType, 2); + expect(devices[0].hardwareProperties?.cpuType?.cpuType, 16777228); + expect(devices[0].hardwareProperties?.deviceType, 'iPad'); + expect(devices[0].hardwareProperties?.ecid, 12345678903408542); + expect(devices[0].hardwareProperties?.hardwareModel, 'J617AP'); + expect(devices[0].hardwareProperties?.internalStorageCapacity, 128000000000); + expect(devices[0].hardwareProperties?.marketingName, 'iPad Pro (11-inch) (4th generation)"'); + expect(devices[0].hardwareProperties?.platform, 'iOS'); + expect(devices[0].hardwareProperties?.productType, 'iPad14,3'); + expect(devices[0].hardwareProperties?.serialNumber, 'HC123DHCQV'); + expect(devices[0].hardwareProperties?.supportedCPUTypes, isNotNull); + expect(devices[0].hardwareProperties?.supportedCPUTypes?[0].name, 'arm64e'); + expect(devices[0].hardwareProperties?.supportedCPUTypes?[0].subType, 2); + expect(devices[0].hardwareProperties?.supportedCPUTypes?[0].cpuType, 16777228); + expect(devices[0].hardwareProperties?.supportedCPUTypes?[1].name, 'arm64'); + expect(devices[0].hardwareProperties?.supportedCPUTypes?[1].subType, 0); + expect(devices[0].hardwareProperties?.supportedCPUTypes?[1].cpuType, 16777228); + expect(devices[0].hardwareProperties?.supportedDeviceFamilies, [1, 2]); + expect(devices[0].hardwareProperties?.thinningProductType, 'iPad14,3-A'); + + expect(devices[0].hardwareProperties?.udid, '00001234-0001234A3C03401E'); + + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(tempFile, isNot(exists)); + }); + + group('Handles errors', () { + testWithoutContext('invalid json', () async { + const String deviceControlOutput = '''Invalid JSON'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.isEmpty, isTrue); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned non-JSON response: Invalid JSON')); + }); + + testWithoutContext('unexpected json', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "list", + "devices", + "--json-output", + "device_list.json" + ], + "commandType" : "devicectl.list.devices", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "325.3" + }, + "result" : [ + + ] +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices(); + expect(devices.isEmpty, isTrue); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(logger.errorText, contains('devicectl returned unexpected JSON response:')); + }); + + testWithoutContext('When timeout is below minimum, default to minimum', () async { + const String deviceControlOutput = ''' +{ + "info" : { + "arguments" : [ + "devicectl", + "list", + "devices", + "--json-output", + "core_device_list.json" + ], + "commandType" : "devicectl.list.devices", + "environment" : { + "TERM" : "xterm-256color" + }, + "outcome" : "success", + "version" : "325.3" + }, + "result" : { + "devices" : [ + { + "identifier" : "123456BB5-AEDE-7A22-B890-1234567890DD", + "visibilityClass" : "default" + } + ] + } +} +'''; + + final File tempFile = fileSystem.systemTempDirectory + .childDirectory('core_devices.rand0') + .childFile('core_device_list.json'); + fakeProcessManager.addCommand(FakeCommand( + command: [ + 'xcrun', + 'devicectl', + 'list', + 'devices', + '--timeout', + '5', + '--json-output', + tempFile.path, + ], + onRun: () { + expect(tempFile, exists); + tempFile.writeAsStringSync(deviceControlOutput); + }, + )); + + final List devices = await deviceControl.getCoreDevices( + timeout: const Duration(seconds: 2), + ); + expect(devices.isNotEmpty, isTrue); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect( + logger.errorText, + contains('Timeout of 2 seconds is below the minimum timeout value ' + 'for devicectl. Changing the timeout to the minimum value of 5.'), + ); + }); + }); + }); + + + }); +} diff --git a/packages/flutter_tools/test/general.shard/ios/devices_test.dart b/packages/flutter_tools/test/general.shard/ios/devices_test.dart index cb222d9e3fe5b..146e05b2b70b7 100644 --- a/packages/flutter_tools/test/general.shard/ios/devices_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/devices_test.dart @@ -19,11 +19,13 @@ import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/ios/application_package.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/ios_deploy.dart'; import 'package:flutter_tools/src/ios/ios_workflow.dart'; import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/mac.dart'; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; import 'package:flutter_tools/src/macos/xcdevice.dart'; import 'package:test/fake.dart'; @@ -42,6 +44,8 @@ void main() { late IOSDeploy iosDeploy; late IMobileDevice iMobileDevice; late FileSystem fileSystem; + late IOSCoreDeviceControl coreDeviceControl; + late XcodeDebug xcodeDebug; setUp(() { final Artifacts artifacts = Artifacts.test(); @@ -61,6 +65,8 @@ void main() { logger: logger, processManager: FakeProcessManager.any(), ); + coreDeviceControl = FakeIOSCoreDeviceControl(); + xcodeDebug = FakeXcodeDebug(); }); testWithoutContext('successfully instantiates on Mac OS', () { @@ -72,12 +78,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', sdkVersion: '13.3', cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); expect(device.isSupported(), isTrue); }); @@ -91,11 +100,14 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.armv7, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); expect(device.isSupported(), isFalse); }); @@ -109,12 +121,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '1.0.0', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).majorSdkVersion, 1); expect(IOSDevice( 'device-123', @@ -124,12 +139,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '13.1.1', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).majorSdkVersion, 13); expect(IOSDevice( 'device-123', @@ -139,12 +157,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '10', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).majorSdkVersion, 10); expect(IOSDevice( 'device-123', @@ -154,12 +175,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '0', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).majorSdkVersion, 0); expect(IOSDevice( 'device-123', @@ -169,12 +193,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: 'bogus', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).majorSdkVersion, 0); }); @@ -187,12 +214,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '13.3.1', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).sdkVersion; Version expectedVersion = Version(13, 3, 1, text: '13.3.1'); expect(sdkVersion, isNotNull); @@ -207,12 +237,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '13.3.1 (20ADBC)', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).sdkVersion; expectedVersion = Version(13, 3, 1, text: '13.3.1 (20ADBC)'); expect(sdkVersion, isNotNull); @@ -227,12 +260,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '16.4.1(a) (20ADBC)', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).sdkVersion; expectedVersion = Version(16, 4, 1, text: '16.4.1(a) (20ADBC)'); expect(sdkVersion, isNotNull); @@ -247,12 +283,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: '0', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).sdkVersion; expectedVersion = Version(0, 0, 0, text: '0'); expect(sdkVersion, isNotNull); @@ -267,11 +306,14 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).sdkVersion; expect(sdkVersion, isNull); @@ -283,12 +325,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', cpuArchitecture: DarwinArch.arm64, sdkVersion: 'bogus', connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ).sdkVersion; expect(sdkVersion, isNull); }); @@ -302,12 +347,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', sdkVersion: '13.3 17C54', cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); expect(await device.sdkNameAndVersion,'iOS 13.3 17C54'); @@ -322,12 +370,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', sdkVersion: '13.3', cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); expect(device.supportsRuntimeMode(BuildMode.debug), true); @@ -348,12 +399,15 @@ void main() { platform: platform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', sdkVersion: '13.3', cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); }, throwsAssertionError, @@ -440,12 +494,15 @@ void main() { platform: macPlatform, iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, name: 'iPhone 1', sdkVersion: '13.3', cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); logReader1 = createLogReader(device, appPackage1, process1); logReader2 = createLogReader(device, appPackage2, process2); @@ -471,6 +528,8 @@ void main() { late IOSDeploy iosDeploy; late IMobileDevice iMobileDevice; late IOSWorkflow iosWorkflow; + late IOSCoreDeviceControl coreDeviceControl; + late XcodeDebug xcodeDebug; late IOSDevice device1; late IOSDevice device2; @@ -494,6 +553,8 @@ void main() { processManager: fakeProcessManager, logger: logger, ); + coreDeviceControl = FakeIOSCoreDeviceControl(); + xcodeDebug = FakeXcodeDebug(); device1 = IOSDevice( 'd83d5bc53967baa0ee18626ba87b6254b2ab5418', @@ -503,12 +564,15 @@ void main() { iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()), iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, logger: logger, platform: macPlatform, fileSystem: MemoryFileSystem.test(), connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); device2 = IOSDevice( @@ -519,12 +583,15 @@ void main() { iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()), iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, logger: logger, platform: macPlatform, fileSystem: MemoryFileSystem.test(), connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); }); @@ -781,6 +848,8 @@ void main() { late IOSDeploy iosDeploy; late IMobileDevice iMobileDevice; late IOSWorkflow iosWorkflow; + late IOSCoreDeviceControl coreDeviceControl; + late XcodeDebug xcodeDebug; late IOSDevice notConnected1; setUp(() { @@ -803,6 +872,8 @@ void main() { processManager: fakeProcessManager, logger: logger, ); + coreDeviceControl = FakeIOSCoreDeviceControl(); + xcodeDebug = FakeXcodeDebug(); notConnected1 = IOSDevice( '00000001-0000000000000000', name: 'iPad', @@ -811,12 +882,15 @@ void main() { iProxy: IProxy.test(logger: logger, processManager: FakeProcessManager.any()), iosDeploy: iosDeploy, iMobileDevice: iMobileDevice, + coreDeviceControl: coreDeviceControl, + xcodeDebug: xcodeDebug, logger: logger, platform: macPlatform, fileSystem: MemoryFileSystem.test(), connectionInterface: DeviceConnectionInterface.attached, isConnected: false, devModeEnabled: true, + isCoreDevice: false, ); }); @@ -965,3 +1039,10 @@ class FakeProcess extends Fake implements Process { return true; } } + +class FakeXcodeDebug extends Fake implements XcodeDebug { + @override + bool get debugStarted => false; +} + +class FakeIOSCoreDeviceControl extends Fake implements IOSCoreDeviceControl {} diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart index 8c93d8fb4f81d..6a5f5226fdba9 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_install_test.dart @@ -12,10 +12,13 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/ios/application_package.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/ios_deploy.dart'; import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/mac.dart'; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/fake_process_manager.dart'; @@ -105,6 +108,28 @@ void main() { expect(processManager, hasNoRemainingExpectations); }); + testWithoutContext('IOSDevice.installApp uses devicectl for CoreDevices', () async { + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + uncompressedBundle: fileSystem.currentDirectory, + applicationPackage: bundleDirectory, + ); + + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + interfaceType: DeviceConnectionInterface.attached, + artifacts: artifacts, + isCoreDevice: true, + ); + final bool wasInstalled = await device.installApp(iosApp); + + expect(wasInstalled, true); + expect(processManager, hasNoRemainingExpectations); + }); + testWithoutContext('IOSDevice.uninstallApp calls ios-deploy correctly', () async { final IOSApp iosApp = PrebuiltIOSApp( projectBundleId: 'app', @@ -134,6 +159,28 @@ void main() { expect(processManager, hasNoRemainingExpectations); }); + testWithoutContext('IOSDevice.uninstallApp uses devicectl for CoreDevices', () async { + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + uncompressedBundle: fileSystem.currentDirectory, + applicationPackage: bundleDirectory, + ); + + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + interfaceType: DeviceConnectionInterface.attached, + artifacts: artifacts, + isCoreDevice: true, + ); + final bool wasUninstalled = await device.uninstallApp(iosApp); + + expect(wasUninstalled, true); + expect(processManager, hasNoRemainingExpectations); + }); + group('isAppInstalled', () { testWithoutContext('catches ProcessException from ios-deploy', () async { final IOSApp iosApp = PrebuiltIOSApp( @@ -263,6 +310,28 @@ void main() { expect(processManager, hasNoRemainingExpectations); expect(logger.traceText, contains(stderr)); }); + + testWithoutContext('uses devicectl for CoreDevices', () async { + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + uncompressedBundle: fileSystem.currentDirectory, + applicationPackage: bundleDirectory, + ); + + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + interfaceType: DeviceConnectionInterface.attached, + artifacts: artifacts, + isCoreDevice: true, + ); + final bool wasInstalled = await device.isAppInstalled(iosApp); + + expect(wasInstalled, true); + expect(processManager, hasNoRemainingExpectations); + }); }); testWithoutContext('IOSDevice.installApp catches ProcessException from ios-deploy', () async { @@ -314,6 +383,8 @@ void main() { expect(wasAppUninstalled, false); }); + + } IOSDevice setUpIOSDevice({ @@ -322,6 +393,7 @@ IOSDevice setUpIOSDevice({ Logger? logger, DeviceConnectionInterface? interfaceType, Artifacts? artifacts, + bool isCoreDevice = false, }) { logger ??= BufferLogger.test(); final FakePlatform platform = FakePlatform( @@ -357,9 +429,42 @@ IOSDevice setUpIOSDevice({ artifacts: artifacts, cache: cache, ), + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug(), iProxy: IProxy.test(logger: logger, processManager: processManager), connectionInterface: interfaceType ?? DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: isCoreDevice, ); } + +class FakeXcodeDebug extends Fake implements XcodeDebug {} + +class FakeIOSCoreDeviceControl extends Fake implements IOSCoreDeviceControl { + @override + Future installApp({ + required String deviceId, + required String bundlePath, + }) async { + + return true; + } + + @override + Future uninstallApp({ + required String deviceId, + required String bundleId, + }) async { + + return true; + } + + @override + Future isAppInstalled({ + required String deviceId, + required String bundleId, + }) async { + return true; + } +} diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart index 9f65a67072a15..8b25f528ab132 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart @@ -349,9 +349,26 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt }); }); - group('both syslog and debugger stream', () { + group('Determine which loggers to use', () { + testWithoutContext('for physically attached CoreDevice', () { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 17, + isCoreDevice: true, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useUnifiedLogging, isTrue); + expect(logReader.useIOSDeployLogging, isFalse); + expect(logReader.usingMultipleLoggingSources, isTrue); + }); - testWithoutContext('useBothLogDeviceReaders is true when CI option is true and sdk is at least 16', () { + testWithoutContext('for wirelessly attached CoreDevice', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -359,14 +376,18 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt cache: fakeCache, logger: logger, ), - usingCISystem: true, - majorSdkVersion: 16, + majorSdkVersion: 17, + isCoreDevice: true, + isWirelesslyConnected: true, ); - expect(logReader.useBothLogDeviceReaders, isTrue); + expect(logReader.useSyslogLogging, isFalse); + expect(logReader.useUnifiedLogging, isTrue); + expect(logReader.useIOSDeployLogging, isFalse); + expect(logReader.usingMultipleLoggingSources, isFalse); }); - testWithoutContext('useBothLogDeviceReaders is false when sdk is less than 16', () { + testWithoutContext('for iOS 12 or less device', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -374,14 +395,54 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt cache: fakeCache, logger: logger, ), - usingCISystem: true, - majorSdkVersion: 15, + majorSdkVersion: 12, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useUnifiedLogging, isFalse); + expect(logReader.useIOSDeployLogging, isFalse); + expect(logReader.usingMultipleLoggingSources, isFalse); + }); + + testWithoutContext('for iOS 13 or greater non-CoreDevice', () { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 13, ); - expect(logReader.useBothLogDeviceReaders, isFalse); + expect(logReader.useSyslogLogging, isFalse); + expect(logReader.useUnifiedLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.usingMultipleLoggingSources, isTrue); }); - testWithoutContext('useBothLogDeviceReaders is false when CI option is false', () { + testWithoutContext('for iOS 13 or greater non-CoreDevice and _iosDeployDebugger is attached', () { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 13, + ); + + final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + iosDeployDebugger.debuggerAttached = true; + logReader.debuggerStream = iosDeployDebugger; + + expect(logReader.useSyslogLogging, isFalse); + expect(logReader.useUnifiedLogging, isFalse); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.usingMultipleLoggingSources, isFalse); + }); + + testWithoutContext('for iOS 16 or greater non-CoreDevice', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -392,10 +453,31 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt majorSdkVersion: 16, ); - expect(logReader.useBothLogDeviceReaders, isFalse); + expect(logReader.useSyslogLogging, isFalse); + expect(logReader.useUnifiedLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.usingMultipleLoggingSources, isTrue); }); - testWithoutContext('syslog only sends flutter messages to stream when useBothLogDeviceReaders is true', () async { + testWithoutContext('for iOS 16 or greater non-CoreDevice in CI', () { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + usingCISystem: true, + majorSdkVersion: 16, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useUnifiedLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.usingMultipleLoggingSources, isTrue); + }); + + testWithoutContext('syslog sends flutter messages to stream when useSyslogLogging is true', () async { processManager.addCommand( FakeCommand( command: [ @@ -422,7 +504,7 @@ May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextM ); final List lines = await logReader.logLines.toList(); - expect(logReader.useBothLogDeviceReaders, isTrue); + expect(logReader.useSyslogLogging, isTrue); expect(processManager, hasNoRemainingExpectations); expect(lines, [ 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', @@ -430,23 +512,10 @@ May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextM ]); }); - testWithoutContext('IOSDeviceLogReader uses both syslog and ios-deploy debugger', () async { - processManager.addCommand( - FakeCommand( - command: [ - ideviceSyslogPath, '-u', '1234', - ], - stdout: ''' -May 30 13:56:28 Runner(Flutter)[2037] : flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/ -May 30 13:56:28 Runner(Flutter)[2037] : flutter: Check for duplicate -May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend. -''' - ), - ); - + testWithoutContext('IOSDeviceLogReader only uses ios-deploy debugger when attached and not in CI', () async { final Stream debuggingLogs = Stream.fromIterable([ - '2023-06-01 12:49:01.445093-0500 Runner[2225:533240] flutter: Check for duplicate', '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', + '', ]); final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( @@ -456,30 +525,45 @@ May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextM cache: fakeCache, logger: logger, ), - usingCISystem: true, majorSdkVersion: 16, ); final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + iosDeployDebugger.debuggerAttached = true; iosDeployDebugger.logLines = debuggingLogs; logReader.debuggerStream = iosDeployDebugger; final Future> logLines = logReader.logLines.toList(); final List lines = await logLines; - expect(logReader.useBothLogDeviceReaders, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.useSyslogLogging, isFalse); + expect(logReader.useUnifiedLogging, isFalse); + expect(logReader.usingMultipleLoggingSources, isFalse); expect(processManager, hasNoRemainingExpectations); - expect(lines.length, 3); - expect(lines, containsAll([ - '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', - 'flutter: Check for duplicate', - ])); - + expect( + lines.contains( + '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', + ), + isTrue, + ); }); - testWithoutContext('IOSDeviceLogReader only uses ios-deploy debugger when useBothLogDeviceReaders is false', () async { + testWithoutContext('IOSDeviceLogReader uses both syslog and ios-deploy debugger for CI and filters duplicate messages', () async { + processManager.addCommand( + FakeCommand( + command: [ + ideviceSyslogPath, '-u', '1234', + ], + stdout: ''' +May 30 13:56:28 Runner(Flutter)[2037] : flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/ +May 30 13:56:28 Runner(Flutter)[2037] : flutter: Check for duplicate +May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend. +''' + ), + ); + final Stream debuggingLogs = Stream.fromIterable([ + '2023-06-01 12:49:01.445093-0500 Runner[2225:533240] flutter: Check for duplicate', '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - '', ]); final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( @@ -489,6 +573,7 @@ May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextM cache: fakeCache, logger: logger, ), + usingCISystem: true, majorSdkVersion: 16, ); final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); @@ -497,14 +582,16 @@ May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextM final Future> logLines = logReader.logLines.toList(); final List lines = await logLines; - expect(logReader.useBothLogDeviceReaders, isFalse); + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.usingMultipleLoggingSources, isTrue); expect(processManager, hasNoRemainingExpectations); - expect( - lines.contains( - '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - ), - isTrue, - ); + expect(lines.length, 3); + expect(lines, containsAll([ + '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + 'flutter: Check for duplicate', + ])); }); }); } diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_project_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_project_test.dart index 082d70b77beee..abe1e850a4a1a 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_project_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_project_test.dart @@ -10,11 +10,14 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/ios_deploy.dart'; import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/mac.dart'; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; import 'package:flutter_tools/src/project.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -94,6 +97,8 @@ IOSDevice setUpIOSDevice(FileSystem fileSystem) { cache: Cache.test(processManager: processManager), ), iMobileDevice: IMobileDevice.test(processManager: processManager), + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug(), platform: platform, name: 'iPhone 1', sdkVersion: '13.3', @@ -102,5 +107,10 @@ IOSDevice setUpIOSDevice(FileSystem fileSystem) { connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: false, ); } + +class FakeXcodeDebug extends Fake implements XcodeDebug {} + +class FakeIOSCoreDeviceControl extends Fake implements IOSCoreDeviceControl {} diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart index be0d51a3438ad..d7f354cd6148a 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:fake_async/fake_async.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; @@ -13,11 +15,14 @@ import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/ios/application_package.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/ios_deploy.dart'; import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/mac.dart'; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/project.dart'; @@ -25,6 +30,7 @@ import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/context.dart' hide FakeXcodeProjectInterpreter; +import '../../src/fake_devices.dart'; import '../../src/fake_process_manager.dart'; import '../../src/fakes.dart'; @@ -287,13 +293,363 @@ void main() { Xcode: () => xcode, }, skip: true); // TODO(zanderso): clean up with https://github.com/flutter/flutter/issues/60675 }); + + group('IOSDevice.startApp for CoreDevice', () { + late FileSystem fileSystem; + late FakeProcessManager processManager; + late BufferLogger logger; + late Xcode xcode; + late FakeXcodeProjectInterpreter fakeXcodeProjectInterpreter; + late XcodeProjectInfo projectInfo; + + setUp(() { + logger = BufferLogger.test(); + fileSystem = MemoryFileSystem.test(); + processManager = FakeProcessManager.empty(); + projectInfo = XcodeProjectInfo( + ['Runner'], + ['Debug', 'Release'], + ['Runner'], + logger, + ); + fakeXcodeProjectInterpreter = FakeXcodeProjectInterpreter(projectInfo: projectInfo); + xcode = Xcode.test(processManager: FakeProcessManager.any(), xcodeProjectInterpreter: fakeXcodeProjectInterpreter); + fileSystem.file('foo/.packages') + ..createSync(recursive: true) + ..writeAsStringSync('\n'); + }); + + group('in release mode', () { + testUsingContext('suceeds when install and launch succeed', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + ); + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), + platformArgs: {}, + ); + + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, true); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + + testUsingContext('fails when install fails', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl( + installSuccess: false, + ), + ); + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), + platformArgs: {}, + ); + + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, false); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + + testUsingContext('fails when launch fails', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl( + launchSuccess: false, + ), + ); + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), + platformArgs: {}, + ); + + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, false); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + + testUsingContext('ensure arguments passed to launch', () async { + final FakeIOSCoreDeviceControl coreDeviceControl = FakeIOSCoreDeviceControl(); + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: coreDeviceControl, + ); + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), + platformArgs: {}, + ); + + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, true); + expect(processManager, hasNoRemainingExpectations); + expect(coreDeviceControl.argumentsUsedForLaunch, isNotNull); + expect(coreDeviceControl.argumentsUsedForLaunch, contains('--enable-dart-profiling')); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + + }); + + group('in debug mode', () { + + testUsingContext('succeeds', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: fileSystem.directory('/ios/Runner.xcworkspace'), + xcodeProject: fileSystem.directory('/ios/Runner.xcodeproj'), + ), + expectedDeviceId: '123', + expectedLaunchArguments: ['--enable-dart-profiling'], + ), + ); + + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + iosDevice.portForwarder = const NoOpDevicePortForwarder(); + iosDevice.setLogReader(buildableIOSApp, deviceLogReader); + + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + null, + buildName: '1.2.3', + buildNumber: '4', + treeShakeIcons: false, + )), + platformArgs: {}, + ); + + expect(logger.errorText, isEmpty); + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, true); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + + testUsingContext('fails when Xcode project is not found', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl() + ); + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + null, + buildName: '1.2.3', + buildNumber: '4', + treeShakeIcons: false, + )), + platformArgs: {}, + ); + expect(logger.errorText, contains('Xcode project not found')); + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, false); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreter(), + Xcode: () => xcode, + }); + + testUsingContext('fails when Xcode workspace is not found', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl() + ); + setUpIOSProject(fileSystem, createWorkspace: false); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final LaunchResult launchResult = await iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + null, + buildName: '1.2.3', + buildNumber: '4', + treeShakeIcons: false, + )), + platformArgs: {}, + ); + expect(logger.errorText, contains('Unable to get Xcode workspace')); + expect(fileSystem.directory('build/ios/iphoneos'), exists); + expect(launchResult.started, false); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + + testUsingContext('fails when scheme is not found', () async { + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl() + ); + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + iosDevice.portForwarder = const NoOpDevicePortForwarder(); + iosDevice.setLogReader(buildableIOSApp, deviceLogReader); + + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + + expect(() async => iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + 'Flavor', + buildName: '1.2.3', + buildNumber: '4', + treeShakeIcons: false, + )), + platformArgs: {}, + ), throwsToolExit()); + }, overrides: { + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + }); + }); } -void setUpIOSProject(FileSystem fileSystem) { +void setUpIOSProject(FileSystem fileSystem, {bool createWorkspace = true}) { fileSystem.file('pubspec.yaml').createSync(); fileSystem.file('.packages').writeAsStringSync('\n'); fileSystem.directory('ios').createSync(); - fileSystem.directory('ios/Runner.xcworkspace').createSync(); + if (createWorkspace) { + fileSystem.directory('ios/Runner.xcworkspace').createSync(); + } fileSystem.file('ios/Runner.xcodeproj/project.pbxproj').createSync(recursive: true); // This is the expected output directory. fileSystem.directory('build/ios/iphoneos/My Super Awesome App.app').createSync(recursive: true); @@ -305,6 +661,9 @@ IOSDevice setUpIOSDevice({ Logger? logger, ProcessManager? processManager, Artifacts? artifacts, + bool isCoreDevice = false, + IOSCoreDeviceControl? coreDeviceControl, + FakeXcodeDebug? xcodeDebug, }) { artifacts ??= Artifacts.test(); final Cache cache = Cache.test( @@ -336,10 +695,13 @@ IOSDevice setUpIOSDevice({ artifacts: artifacts, cache: cache, ), + coreDeviceControl: coreDeviceControl ?? FakeIOSCoreDeviceControl(), + xcodeDebug: xcodeDebug ?? FakeXcodeDebug(), cpuArchitecture: DarwinArch.arm64, connectionInterface: DeviceConnectionInterface.attached, isConnected: true, devModeEnabled: true, + isCoreDevice: isCoreDevice, ); } @@ -381,3 +743,70 @@ class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterprete Duration timeout = const Duration(minutes: 1), }) async => buildSettings; } + +class FakeXcodeDebug extends Fake implements XcodeDebug { + FakeXcodeDebug({ + this.debugSuccess = true, + this.expectedProject, + this.expectedDeviceId, + this.expectedLaunchArguments, + }); + + final bool debugSuccess; + + final XcodeDebugProject? expectedProject; + final String? expectedDeviceId; + final List? expectedLaunchArguments; + + @override + Future debugApp({ + required XcodeDebugProject project, + required String deviceId, + required List launchArguments, + }) async { + if (expectedProject != null) { + expect(project.scheme, expectedProject!.scheme); + expect(project.xcodeWorkspace.path, expectedProject!.xcodeWorkspace.path); + expect(project.xcodeProject.path, expectedProject!.xcodeProject.path); + expect(project.isTemporaryProject, expectedProject!.isTemporaryProject); + } + if (expectedDeviceId != null) { + expect(deviceId, expectedDeviceId); + } + if (expectedLaunchArguments != null) { + expect(expectedLaunchArguments, launchArguments); + } + return debugSuccess; + } +} + +class FakeIOSCoreDeviceControl extends Fake implements IOSCoreDeviceControl { + FakeIOSCoreDeviceControl({ + this.installSuccess = true, + this.launchSuccess = true + }); + + final bool installSuccess; + final bool launchSuccess; + List? _launchArguments; + + List? get argumentsUsedForLaunch => _launchArguments; + + @override + Future installApp({ + required String deviceId, + required String bundlePath, + }) async { + return installSuccess; + } + + @override + Future launchApp({ + required String deviceId, + required String bundleId, + List launchArguments = const [], + }) async { + _launchArguments = launchArguments; + return launchSuccess; + } +} diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 5d01888b0c471..8e8e2235a6bcf 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -5,20 +5,25 @@ import 'dart:async'; import 'dart:convert'; +import 'package:fake_async/fake_async.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/process.dart'; +import 'package:flutter_tools/src/base/template.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/ios/application_package.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/ios_deploy.dart'; import 'package:flutter_tools/src/ios/iproxy.dart'; import 'package:flutter_tools/src/ios/mac.dart'; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; import 'package:flutter_tools/src/mdns_discovery.dart'; import 'package:test/fake.dart'; @@ -601,6 +606,212 @@ void main() { expect(await device.stopApp(iosApp), false); expect(processManager, hasNoRemainingExpectations); }); + + group('IOSDevice.startApp for CoreDevice', () { + group('in debug mode', () { + testUsingContext('succeeds', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0'); + final Directory bundleLocation = fileSystem.currentDirectory; + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), + xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + ), + expectedDeviceId: '123', + expectedLaunchArguments: ['--enable-dart-profiling'], + expectedBundlePath: bundleLocation.path, + ) + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: bundleLocation, + applicationPackage: bundleLocation, + ); + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + device.portForwarder = const NoOpDevicePortForwarder(); + device.setLogReader(iosApp, deviceLogReader); + + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + + final LaunchResult launchResult = await device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + platformArgs: {}, + ); + + expect(launchResult.started, true); + }); + + testUsingContext('prints warning message if it takes too long to start debugging', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); + final BufferLogger logger = BufferLogger.test(); + final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0'); + final Directory bundleLocation = fileSystem.currentDirectory; + final Completer completer = Completer(); + final FakeXcodeDebug xcodeDebug = FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), + xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + ), + expectedDeviceId: '123', + expectedLaunchArguments: ['--enable-dart-profiling'], + expectedBundlePath: bundleLocation.path, + completer: completer, + ); + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: xcodeDebug, + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: bundleLocation, + applicationPackage: bundleLocation, + ); + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + device.portForwarder = const NoOpDevicePortForwarder(); + device.setLogReader(iosApp, deviceLogReader); + + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + + FakeAsync().run((FakeAsync fakeAsync) { + device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + platformArgs: {}, + ); + + fakeAsync.flushTimers(); + expect(logger.errorText, contains('Xcode is taking longer than expected to start debugging the app. Ensure the project is opened in Xcode.')); + completer.complete(); + }); + }); + + testUsingContext('succeeds with shutdown hook added when running from CI', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0'); + final Directory bundleLocation = fileSystem.currentDirectory; + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), + xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + ), + expectedDeviceId: '123', + expectedLaunchArguments: ['--enable-dart-profiling'], + expectedBundlePath: bundleLocation.path, + ) + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: bundleLocation, + applicationPackage: bundleLocation, + ); + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + device.portForwarder = const NoOpDevicePortForwarder(); + device.setLogReader(iosApp, deviceLogReader); + + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + + final FakeShutDownHooks shutDownHooks = FakeShutDownHooks(); + + final LaunchResult launchResult = await device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, usingCISystem: true), + platformArgs: {}, + shutdownHooks: shutDownHooks, + ); + + expect(launchResult.started, true); + expect(shutDownHooks.hooks.length, 1); + }); + + testUsingContext('IOSDevice.startApp attaches in debug mode via mDNS when device logging fails', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final Directory temporaryXcodeProjectDirectory = fileSystem.systemTempDirectory.childDirectory('flutter_empty_xcode.rand0'); + final Directory bundleLocation = fileSystem.currentDirectory; + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), + xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + ), + expectedDeviceId: '123', + expectedLaunchArguments: ['--enable-dart-profiling'], + expectedBundlePath: bundleLocation.path, + ) + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: bundleLocation, + applicationPackage: bundleLocation, + ); + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + device.portForwarder = const NoOpDevicePortForwarder(); + device.setLogReader(iosApp, deviceLogReader); + + final LaunchResult launchResult = await device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), + platformArgs: {}, + ); + + expect(launchResult.started, true); + expect(launchResult.hasVmService, true); + expect(await device.stopApp(iosApp), true); + }, overrides: { + MDnsVmServiceDiscovery: () => FakeMDnsVmServiceDiscovery(), + }); + }); + }); } IOSDevice setUpIOSDevice({ @@ -610,6 +821,9 @@ IOSDevice setUpIOSDevice({ ProcessManager? processManager, IOSDeploy? iosDeploy, DeviceConnectionInterface interfaceType = DeviceConnectionInterface.attached, + bool isCoreDevice = false, + IOSCoreDeviceControl? coreDeviceControl, + FakeXcodeDebug? xcodeDebug, }) { final Artifacts artifacts = Artifacts.test(); final FakePlatform macPlatform = FakePlatform( @@ -646,10 +860,13 @@ IOSDevice setUpIOSDevice({ artifacts: artifacts, cache: cache, ), + coreDeviceControl: coreDeviceControl ?? FakeIOSCoreDeviceControl(), + xcodeDebug: xcodeDebug ?? FakeXcodeDebug(), cpuArchitecture: DarwinArch.arm64, connectionInterface: interfaceType, isConnected: true, devModeEnabled: true, + isCoreDevice: isCoreDevice, ); } @@ -669,10 +886,88 @@ class FakeMDnsVmServiceDiscovery extends Fake implements MDnsVmServiceDiscovery Device device, { bool usesIpv6 = false, int? hostVmservicePort, - required int deviceVmservicePort, + int? deviceVmservicePort, bool useDeviceIPAsHost = false, Duration timeout = Duration.zero, }) async { return Uri.tryParse('http://0.0.0.0:1234'); } } + +class FakeXcodeDebug extends Fake implements XcodeDebug { + FakeXcodeDebug({ + this.debugSuccess = true, + this.expectedProject, + this.expectedDeviceId, + this.expectedLaunchArguments, + this.expectedBundlePath, + this.completer, + }); + + final bool debugSuccess; + final XcodeDebugProject? expectedProject; + final String? expectedDeviceId; + final List? expectedLaunchArguments; + final String? expectedBundlePath; + final Completer? completer; + + @override + bool debugStarted = false; + + @override + Future createXcodeProjectWithCustomBundle( + String deviceBundlePath, { + required TemplateRenderer templateRenderer, + Directory? projectDestination, + bool verboseLogging = false, + }) async { + if (expectedBundlePath != null) { + expect(expectedBundlePath, deviceBundlePath); + } + return expectedProject!; + } + + @override + Future debugApp({ + required XcodeDebugProject project, + required String deviceId, + required List launchArguments, + }) async { + if (expectedProject != null) { + expect(project.scheme, expectedProject!.scheme); + expect(project.xcodeWorkspace.path, expectedProject!.xcodeWorkspace.path); + expect(project.xcodeProject.path, expectedProject!.xcodeProject.path); + expect(project.isTemporaryProject, expectedProject!.isTemporaryProject); + } + if (expectedDeviceId != null) { + expect(deviceId, expectedDeviceId); + } + if (expectedLaunchArguments != null) { + expect(expectedLaunchArguments, launchArguments); + } + debugStarted = debugSuccess; + + if (completer != null) { + await completer!.future; + } + return debugSuccess; + } + + @override + Future exit({ + bool force = false, + bool skipDelay = false, + }) async { + return true; + } +} + +class FakeIOSCoreDeviceControl extends Fake implements IOSCoreDeviceControl {} + +class FakeShutDownHooks extends Fake implements ShutdownHooks { + List hooks = []; + @override + void addShutdownHook(ShutdownHook shutdownHook) { + hooks.add(shutdownHook); + } +} diff --git a/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart b/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart new file mode 100644 index 0000000000000..67aa5838afcda --- /dev/null +++ b/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart @@ -0,0 +1,1033 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io' as io; + +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/version.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; +import 'package:flutter_tools/src/ios/xcodeproj.dart'; +import 'package:flutter_tools/src/macos/xcode.dart'; +import 'package:test/fake.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fake_process_manager.dart'; + +void main() { + group('Debug project through Xcode', () { + late MemoryFileSystem fileSystem; + late BufferLogger logger; + late FakeProcessManager fakeProcessManager; + + const String flutterRoot = '/path/to/flutter'; + const String pathToXcodeAutomationScript = '$flutterRoot/packages/flutter_tools/bin/xcode_debug.js'; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + logger = BufferLogger.test(); + fakeProcessManager = FakeProcessManager.empty(); + }); + + group('debugApp', () { + const String pathToXcodeApp = '/Applications/Xcode.app'; + const String deviceId = '0000001234'; + + late Xcode xcode; + late Directory xcodeproj; + late Directory xcworkspace; + late XcodeDebugProject project; + + setUp(() { + xcode = setupXcode( + fakeProcessManager: fakeProcessManager, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + + xcodeproj = fileSystem.directory('Runner.xcodeproj'); + xcworkspace = fileSystem.directory('Runner.xcworkspace'); + project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + ); + }); + + testWithoutContext('succeeds in opening and debugging with launch options and verbose logging', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--verbose', + ], + stdout: ''' + {"status":false,"errorMessage":"Xcode is not running","debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'open', + '-a', + pathToXcodeApp, + '-g', + '-j', + xcworkspace.path + ], + ), + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'debug', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + r'["--enable-dart-profiling","--trace-allowlist=\"foo,bar\""]', + '--verbose', + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":{"completed":false,"status":"running","errorMessage":null}} + ''', + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + verboseLogging: true, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [ + '--enable-dart-profiling', + '--trace-allowlist="foo,bar"' + ], + ); + + expect(logger.errorText, isEmpty); + expect(logger.traceText, contains('Error checking if project opened in Xcode')); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(xcodeDebug.startDebugActionProcess, isNull); + expect(status, true); + }); + + testWithoutContext('succeeds in opening and debugging without launch options and verbose logging', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":false,"errorMessage":"Xcode is not running","debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'open', + '-a', + pathToXcodeApp, + '-g', + '-j', + xcworkspace.path + ], + ), + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'debug', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + '[]' + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":{"completed":false,"status":"running","errorMessage":null}} + ''', + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [], + ); + + expect(logger.errorText, isEmpty); + expect(logger.traceText, contains('Error checking if project opened in Xcode')); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(xcodeDebug.startDebugActionProcess, isNull); + expect(status, true); + }); + + testWithoutContext('fails if project fails to open', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":false,"errorMessage":"Xcode is not running","debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'open', + '-a', + pathToXcodeApp, + '-g', + '-j', + xcworkspace.path + ], + exception: ProcessException( + 'open', + [ + '-a', + '/non_existant_path', + '-g', + '-j', + xcworkspace.path, + ], + 'The application /non_existant_path cannot be opened for an unexpected reason', + ), + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [ + '--enable-dart-profiling', + '--trace-allowlist="foo,bar"', + ], + ); + + expect( + logger.errorText, + contains('The application /non_existant_path cannot be opened for an unexpected reason'), + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, false); + }); + + testWithoutContext('fails if osascript errors', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":true,"errorMessage":"","debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'debug', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + r'["--enable-dart-profiling","--trace-allowlist=\"foo,bar\""]' + ], + exitCode: 1, + stderr: "/flutter/packages/flutter_tools/bin/xcode_debug.js: execution error: Error: ReferenceError: Can't find variable: y (-2700)", + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [ + '--enable-dart-profiling', + '--trace-allowlist="foo,bar"', + ], + ); + + expect(logger.errorText, contains('Error executing osascript')); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, false); + }); + + testWithoutContext('fails if osascript output returns false status', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'debug', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + r'["--enable-dart-profiling","--trace-allowlist=\"foo,bar\""]' + ], + stdout: ''' + {"status":false,"errorMessage":"Unable to find target device.","debugResult":null} + ''', + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [ + '--enable-dart-profiling', + '--trace-allowlist="foo,bar"', + ], + ); + + expect( + logger.errorText, + contains('Error starting debug session in Xcode'), + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, false); + }); + + testWithoutContext('fails if missing debug results', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'debug', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + r'["--enable-dart-profiling","--trace-allowlist=\"foo,bar\""]' + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [ + '--enable-dart-profiling', + '--trace-allowlist="foo,bar"' + ], + ); + + expect( + logger.errorText, + contains('Unable to get debug results from response'), + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, false); + }); + + testWithoutContext('fails if debug results status is not running', () async { + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'check-workspace-opened', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'debug', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--device-id', + deviceId, + '--scheme', + project.scheme, + '--skip-building', + '--launch-args', + r'["--enable-dart-profiling","--trace-allowlist=\"foo,bar\""]' + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":{"completed":false,"status":"not yet started","errorMessage":null}} + ''', + ), + ]); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final bool status = await xcodeDebug.debugApp( + project: project, + deviceId: deviceId, + launchArguments: [ + '--enable-dart-profiling', + '--trace-allowlist="foo,bar"', + ], + ); + + expect(logger.errorText, contains('Unexpected debug results')); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, false); + }); + }); + + group('parse script response', () { + testWithoutContext('fails if osascript output returns non-json output', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: FakeProcessManager.any(), + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final XcodeAutomationScriptResponse? response = xcodeDebug.parseScriptResponse('not json'); + + expect( + logger.errorText, + contains('osascript returned non-JSON response'), + ); + expect(response, isNull); + }); + + testWithoutContext('fails if osascript output returns unexpected json', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: FakeProcessManager.any(), + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final XcodeAutomationScriptResponse? response = xcodeDebug.parseScriptResponse('[]'); + + expect( + logger.errorText, + contains('osascript returned unexpected JSON response'), + ); + expect(response, isNull); + }); + + testWithoutContext('fails if osascript output is missing status field', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: FakeProcessManager.any(), + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + final XcodeAutomationScriptResponse? response = xcodeDebug.parseScriptResponse('{}'); + + expect( + logger.errorText, + contains('osascript returned unexpected JSON response'), + ); + expect(response, isNull); + }); + }); + + group('exit', () { + const String pathToXcodeApp = '/Applications/Xcode.app'; + + late Directory projectDirectory; + late Directory xcodeproj; + late Directory xcworkspace; + + setUp(() { + projectDirectory = fileSystem.directory('FlutterApp'); + xcodeproj = projectDirectory.childDirectory('Runner.xcodeproj'); + xcworkspace = projectDirectory.childDirectory('Runner.xcworkspace'); + }); + + testWithoutContext('exits when waiting for debug session to start', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: fakeProcessManager, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebugProject project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'stop', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + ]); + + xcodeDebug.startDebugActionProcess = FakeProcess(); + xcodeDebug.currentDebuggingProject = project; + + expect(xcodeDebug.startDebugActionProcess, isNotNull); + expect(xcodeDebug.currentDebuggingProject, isNotNull); + + final bool exitStatus = await xcodeDebug.exit(); + + expect((xcodeDebug.startDebugActionProcess! as FakeProcess).killed, isTrue); + expect(xcodeDebug.currentDebuggingProject, isNull); + expect(logger.errorText, isEmpty); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(exitStatus, isTrue); + }); + + testWithoutContext('exits and deletes temporary directory', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: fakeProcessManager, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + xcodeproj.createSync(recursive: true); + xcworkspace.createSync(recursive: true); + + final XcodeDebugProject project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + isTemporaryProject: true, + ); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'stop', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--close-window' + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + ]); + + xcodeDebug.startDebugActionProcess = FakeProcess(); + xcodeDebug.currentDebuggingProject = project; + + expect(xcodeDebug.startDebugActionProcess, isNotNull); + expect(xcodeDebug.currentDebuggingProject, isNotNull); + expect(projectDirectory.existsSync(), isTrue); + expect(xcodeproj.existsSync(), isTrue); + expect(xcworkspace.existsSync(), isTrue); + + final bool status = await xcodeDebug.exit(skipDelay: true); + + expect((xcodeDebug.startDebugActionProcess! as FakeProcess).killed, isTrue); + expect(xcodeDebug.currentDebuggingProject, isNull); + expect(projectDirectory.existsSync(), isFalse); + expect(xcodeproj.existsSync(), isFalse); + expect(xcworkspace.existsSync(), isFalse); + expect(logger.errorText, isEmpty); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, isTrue); + }); + + testWithoutContext('kill Xcode when force exit', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: FakeProcessManager.any(), + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebugProject project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + fakeProcessManager.addCommands([ + const FakeCommand( + command: [ + 'killall', + '-9', + 'Xcode', + ], + ), + ]); + + xcodeDebug.startDebugActionProcess = FakeProcess(); + xcodeDebug.currentDebuggingProject = project; + + expect(xcodeDebug.startDebugActionProcess, isNotNull); + expect(xcodeDebug.currentDebuggingProject, isNotNull); + + final bool exitStatus = await xcodeDebug.exit(force: true); + + expect((xcodeDebug.startDebugActionProcess! as FakeProcess).killed, isTrue); + expect(xcodeDebug.currentDebuggingProject, isNull); + expect(logger.errorText, isEmpty); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(exitStatus, isTrue); + }); + }); + + group('stop app', () { + const String pathToXcodeApp = '/Applications/Xcode.app'; + + late Xcode xcode; + late Directory xcodeproj; + late Directory xcworkspace; + late XcodeDebugProject project; + + setUp(() { + xcode = setupXcode( + fakeProcessManager: fakeProcessManager, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + xcodeproj = fileSystem.directory('Runner.xcodeproj'); + xcworkspace = fileSystem.directory('Runner.xcworkspace'); + project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + ); + }); + + testWithoutContext('succeeds with all optional flags', () async { + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'stop', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--close-window', + '--prompt-to-save' + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + ]); + + final bool status = await xcodeDebug.stopDebuggingApp( + project: project, + closeXcode: true, + promptToSaveOnClose: true, + ); + + expect(logger.errorText, isEmpty); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, isTrue); + }); + + testWithoutContext('fails if osascript output returns false status', () async { + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'stop', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--close-window', + '--prompt-to-save' + ], + stdout: ''' + {"status":false,"errorMessage":"Failed to stop app","debugResult":null} + ''', + ), + ]); + + final bool status = await xcodeDebug.stopDebuggingApp( + project: project, + closeXcode: true, + promptToSaveOnClose: true, + ); + + expect(logger.errorText, contains('Error stopping app in Xcode')); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, isFalse); + }); + }); + }); + + group('Debug project through Xcode with app bundle', () { + late BufferLogger logger; + late FakeProcessManager fakeProcessManager; + late MemoryFileSystem fileSystem; + + const String flutterRoot = '/path/to/flutter'; + + setUp(() { + logger = BufferLogger.test(); + fakeProcessManager = FakeProcessManager.empty(); + fileSystem = MemoryFileSystem.test(); + }); + + testUsingContext('creates temporary xcode project', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: fakeProcessManager, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: globals.fs, + ); + + final Directory projectDirectory = globals.fs.systemTempDirectory.createTempSync('flutter_empty_xcode.'); + + try { + final XcodeDebugProject project = await xcodeDebug.createXcodeProjectWithCustomBundle( + '/path/to/bundle', + templateRenderer: globals.templateRenderer, + projectDestination: projectDirectory, + ); + + final File schemeFile = projectDirectory + .childDirectory('Runner.xcodeproj') + .childDirectory('xcshareddata') + .childDirectory('xcschemes') + .childFile('Runner.xcscheme'); + + expect(project.scheme, 'Runner'); + expect(project.xcodeProject.existsSync(), isTrue); + expect(project.xcodeWorkspace.existsSync(), isTrue); + expect(project.isTemporaryProject, isTrue); + expect(projectDirectory.childDirectory('Runner.xcodeproj').existsSync(), isTrue); + expect(projectDirectory.childDirectory('Runner.xcworkspace').existsSync(), isTrue); + expect(schemeFile.existsSync(), isTrue); + expect(schemeFile.readAsStringSync(), contains('FilePath = "/path/to/bundle"')); + + } catch (err) { // ignore: avoid_catches_without_on_clauses + fail(err.toString()); + } finally { + projectDirectory.deleteSync(recursive: true); + } + }); + }); +} + +Xcode setupXcode({ + required FakeProcessManager fakeProcessManager, + required FileSystem fileSystem, + required String flutterRoot, + bool xcodeSelect = true, +}) { + fakeProcessManager.addCommand(const FakeCommand( + command: ['/usr/bin/xcode-select', '--print-path'], + stdout: '/Applications/Xcode.app/Contents/Developer', + )); + + fileSystem.file('$flutterRoot/packages/flutter_tools/bin/xcode_debug.js').createSync(recursive: true); + + final XcodeProjectInterpreter xcodeProjectInterpreter = XcodeProjectInterpreter.test( + processManager: FakeProcessManager.any(), + version: Version(14, 0, 0), + ); + + return Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); +} + +class FakeProcess extends Fake implements Process { + bool killed = false; + + @override + bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) { + killed = true; + return true; + } +} diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart index 90210c3255604..3dfe9157d5189 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart @@ -1306,5 +1306,75 @@ flutter: expectedBuildNumber: '1', ); }); + + group('CoreDevice', () { + testUsingContext('sets BUILD_DIR for core devices in debug mode', () async { + const BuildInfo buildInfo = BuildInfo.debug; + final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); + await updateGeneratedXcodeProperties( + project: project, + buildInfo: buildInfo, + useMacOSConfig: true, + usingCoreDevice: true, + ); + + final File config = fs.file('path/to/project/macos/Flutter/ephemeral/Flutter-Generated.xcconfig'); + expect(config.existsSync(), isTrue); + + final String contents = config.readAsStringSync(); + expect(contents, contains('\nBUILD_DIR=/build/ios\n')); + }, overrides: { + Artifacts: () => localIosArtifacts, + Platform: () => macOS, + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + XcodeProjectInterpreter: () => xcodeProjectInterpreter, + }); + + testUsingContext('does not set BUILD_DIR for core devices in release mode', () async { + const BuildInfo buildInfo = BuildInfo.release; + final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); + await updateGeneratedXcodeProperties( + project: project, + buildInfo: buildInfo, + useMacOSConfig: true, + usingCoreDevice: true, + ); + + final File config = fs.file('path/to/project/macos/Flutter/ephemeral/Flutter-Generated.xcconfig'); + expect(config.existsSync(), isTrue); + + final String contents = config.readAsStringSync(); + expect(contents.contains('\nBUILD_DIR'), isFalse); + }, overrides: { + Artifacts: () => localIosArtifacts, + Platform: () => macOS, + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + XcodeProjectInterpreter: () => xcodeProjectInterpreter, + }); + + testUsingContext('does not set BUILD_DIR for non core devices', () async { + const BuildInfo buildInfo = BuildInfo.debug; + final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); + await updateGeneratedXcodeProperties( + project: project, + buildInfo: buildInfo, + useMacOSConfig: true, + ); + + final File config = fs.file('path/to/project/macos/Flutter/ephemeral/Flutter-Generated.xcconfig'); + expect(config.existsSync(), isTrue); + + final String contents = config.readAsStringSync(); + expect(contents.contains('\nBUILD_DIR'), isFalse); + }, overrides: { + Artifacts: () => localIosArtifacts, + Platform: () => macOS, + FileSystem: () => fs, + ProcessManager: () => FakeProcessManager.any(), + XcodeProjectInterpreter: () => xcodeProjectInterpreter, + }); + }); }); } diff --git a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart index 887712ad2e5c3..6df6b82b6d751 100644 --- a/packages/flutter_tools/test/general.shard/macos/xcode_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/xcode_test.dart @@ -4,16 +4,20 @@ import 'dart:async'; +import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/io.dart' show ProcessException; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/ios/core_devices.dart'; import 'package:flutter_tools/src/ios/devices.dart'; import 'package:flutter_tools/src/ios/iproxy.dart'; +import 'package:flutter_tools/src/ios/xcode_debug.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/macos/xcdevice.dart'; import 'package:flutter_tools/src/macos/xcode.dart'; @@ -75,7 +79,7 @@ void main() { expect(fakeProcessManager, hasNoRemainingExpectations); }); - testWithoutContext('isSimctlInstalled is true when simctl list fails', () { + testWithoutContext('isSimctlInstalled is false when simctl list fails', () { fakeProcessManager.addCommand( const FakeCommand( command: [ @@ -97,6 +101,156 @@ void main() { expect(fakeProcessManager, hasNoRemainingExpectations); }); + group('isDevicectlInstalled', () { + testWithoutContext('is true when Xcode is 15+ and devicectl succeeds', () { + fakeProcessManager.addCommand( + const FakeCommand( + command: [ + 'xcrun', + 'devicectl', + '--version', + ], + ), + ); + xcodeProjectInterpreter.version = Version(15, 0, 0); + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + + expect(xcode.isDevicectlInstalled, isTrue); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('is false when devicectl fails', () { + fakeProcessManager.addCommand( + const FakeCommand( + command: [ + 'xcrun', + 'devicectl', + '--version', + ], + exitCode: 1, + ), + ); + xcodeProjectInterpreter.version = Version(15, 0, 0); + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + + expect(xcode.isDevicectlInstalled, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('is false when Xcode is less than 15', () { + xcodeProjectInterpreter.version = Version(14, 0, 0); + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + + expect(xcode.isDevicectlInstalled, isFalse); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + }); + + group('pathToXcodeApp', () { + late UserMessages userMessages; + + setUp(() { + userMessages = UserMessages(); + }); + + testWithoutContext('parses correctly', () { + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + + fakeProcessManager.addCommand(const FakeCommand( + command: ['/usr/bin/xcode-select', '--print-path'], + stdout: '/Applications/Xcode.app/Contents/Developer', + )); + + expect(xcode.xcodeAppPath, '/Applications/Xcode.app'); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + testWithoutContext('throws error if not found', () { + final Xcode xcode = Xcode.test( + processManager: FakeProcessManager.any(), + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + + expect( + () => xcode.xcodeAppPath, + throwsToolExit(message: userMessages.xcodeMissing), + ); + }); + + testWithoutContext('throws error with unexpected outcome', () { + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + ); + + fakeProcessManager.addCommand(const FakeCommand( + command: [ + '/usr/bin/xcode-select', + '--print-path', + ], + stdout: '/Library/Developer/CommandLineTools', + )); + + expect( + () => xcode.xcodeAppPath, + throwsToolExit(message: userMessages.xcodeMissing), + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + }); + + group('pathToXcodeAutomationScript', () { + const String flutterRoot = '/path/to/flutter'; + + late MemoryFileSystem fileSystem; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + }); + + testWithoutContext('returns path when file is found', () { + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + + fileSystem.file('$flutterRoot/packages/flutter_tools/bin/xcode_debug.js').createSync(recursive: true); + + expect( + xcode.xcodeAutomationScriptPath, + '$flutterRoot/packages/flutter_tools/bin/xcode_debug.js', + ); + }); + + testWithoutContext('throws error when not found', () { + final Xcode xcode = Xcode.test( + processManager: fakeProcessManager, + xcodeProjectInterpreter: xcodeProjectInterpreter, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + + expect(() => + xcode.xcodeAutomationScriptPath, + throwsToolExit() + ); + }); + }); + group('macOS', () { late Xcode xcode; late BufferLogger logger; @@ -339,6 +493,7 @@ void main() { group('xcdevice not installed', () { late XCDevice xcdevice; late Xcode xcode; + late MemoryFileSystem fileSystem; setUp(() { xcode = Xcode.test( @@ -348,6 +503,7 @@ void main() { version: null, // Not installed. ), ); + fileSystem = MemoryFileSystem.test(); xcdevice = XCDevice( processManager: fakeProcessManager, logger: logger, @@ -356,6 +512,9 @@ void main() { artifacts: Artifacts.test(), cache: Cache.test(processManager: FakeProcessManager.any()), iproxy: IProxy.test(logger: logger, processManager: fakeProcessManager), + fileSystem: fileSystem, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug(), ); }); @@ -373,9 +532,13 @@ void main() { group('xcdevice', () { late XCDevice xcdevice; late Xcode xcode; + late MemoryFileSystem fileSystem; + late FakeIOSCoreDeviceControl coreDeviceControl; setUp(() { xcode = Xcode.test(processManager: FakeProcessManager.any()); + fileSystem = MemoryFileSystem.test(); + coreDeviceControl = FakeIOSCoreDeviceControl(); xcdevice = XCDevice( processManager: fakeProcessManager, logger: logger, @@ -384,6 +547,9 @@ void main() { artifacts: Artifacts.test(), cache: Cache.test(processManager: FakeProcessManager.any()), iproxy: IProxy.test(logger: logger, processManager: fakeProcessManager), + fileSystem: fileSystem, + coreDeviceControl: coreDeviceControl, + xcodeDebug: FakeXcodeDebug(), ); }); @@ -1117,6 +1283,176 @@ void main() { }, overrides: { Platform: () => macPlatform, }); + + group('with CoreDevices', () { + testUsingContext('returns devices with corresponding CoreDevices', () async { + const String devicesOutput = ''' +[ + { + "simulator" : true, + "operatingSystemVersion" : "13.3 (17K446)", + "available" : true, + "platform" : "com.apple.platform.appletvsimulator", + "modelCode" : "AppleTV5,3", + "identifier" : "CBB5E1ED-2172-446E-B4E7-F2B5823DBBA6", + "architecture" : "x86_64", + "modelName" : "Apple TV", + "name" : "Apple TV" + }, + { + "simulator" : false, + "operatingSystemVersion" : "13.3 (17C54)", + "interface" : "usb", + "available" : true, + "platform" : "com.apple.platform.iphoneos", + "modelCode" : "iPhone8,1", + "identifier" : "00008027-00192736010F802E", + "architecture" : "arm64", + "modelName" : "iPhone 6s", + "name" : "An iPhone (Space Gray)" + }, + { + "simulator" : false, + "operatingSystemVersion" : "10.1 (14C54)", + "interface" : "usb", + "available" : true, + "platform" : "com.apple.platform.iphoneos", + "modelCode" : "iPad11,4", + "identifier" : "98206e7a4afd4aedaff06e687594e089dede3c44", + "architecture" : "armv7", + "modelName" : "iPad Air 3rd Gen", + "name" : "iPad 1" + }, + { + "simulator" : false, + "operatingSystemVersion" : "10.1 (14C54)", + "interface" : "network", + "available" : true, + "platform" : "com.apple.platform.iphoneos", + "modelCode" : "iPad11,4", + "identifier" : "234234234234234234345445687594e089dede3c44", + "architecture" : "arm64", + "modelName" : "iPad Air 3rd Gen", + "name" : "A networked iPad" + }, + { + "simulator" : false, + "operatingSystemVersion" : "10.1 (14C54)", + "interface" : "usb", + "available" : true, + "platform" : "com.apple.platform.iphoneos", + "modelCode" : "iPad11,4", + "identifier" : "f577a7903cc54959be2e34bc4f7f80b7009efcf4", + "architecture" : "BOGUS", + "modelName" : "iPad Air 3rd Gen", + "name" : "iPad 2" + }, + { + "simulator" : true, + "operatingSystemVersion" : "6.1.1 (17S445)", + "available" : true, + "platform" : "com.apple.platform.watchsimulator", + "modelCode" : "Watch5,4", + "identifier" : "2D74FB11-88A0-44D0-B81E-C0C142B1C94A", + "architecture" : "i386", + "modelName" : "Apple Watch Series 5 - 44mm", + "name" : "Apple Watch Series 5 - 44mm" + }, + { + "simulator" : false, + "operatingSystemVersion" : "13.3 (17C54)", + "interface" : "usb", + "available" : false, + "platform" : "com.apple.platform.iphoneos", + "modelCode" : "iPhone8,1", + "identifier" : "c4ca6f7a53027d1b7e4972e28478e7a28e2faee2", + "architecture" : "arm64", + "modelName" : "iPhone 6s", + "name" : "iPhone", + "error" : { + "code" : -9, + "failureReason" : "", + "description" : "iPhone is not paired with your computer.", + "domain" : "com.apple.platform.iphoneos" + } + } +] +'''; + coreDeviceControl.devices.addAll([ + FakeIOSCoreDevice( + udid: '00008027-00192736010F802E', + connectionInterface: DeviceConnectionInterface.wireless, + developerModeStatus: 'enabled', + ), + FakeIOSCoreDevice( + connectionInterface: DeviceConnectionInterface.wireless, + developerModeStatus: 'enabled', + ), + FakeIOSCoreDevice( + udid: '234234234234234234345445687594e089dede3c44', + connectionInterface: DeviceConnectionInterface.attached, + ), + FakeIOSCoreDevice( + udid: 'f577a7903cc54959be2e34bc4f7f80b7009efcf4', + connectionInterface: DeviceConnectionInterface.attached, + developerModeStatus: 'disabled', + ), + ]); + + fakeProcessManager.addCommand(const FakeCommand( + command: ['xcrun', 'xcdevice', 'list', '--timeout', '2'], + stdout: devicesOutput, + )); + + final List devices = await xcdevice.getAvailableIOSDevices(); + expect(devices, hasLength(5)); + expect(devices[0].id, '00008027-00192736010F802E'); + expect(devices[0].name, 'An iPhone (Space Gray)'); + expect(await devices[0].sdkNameAndVersion, 'iOS 13.3 17C54'); + expect(devices[0].cpuArchitecture, DarwinArch.arm64); + expect(devices[0].connectionInterface, DeviceConnectionInterface.wireless); + expect(devices[0].isConnected, true); + expect(devices[0].devModeEnabled, true); + + expect(devices[1].id, '98206e7a4afd4aedaff06e687594e089dede3c44'); + expect(devices[1].name, 'iPad 1'); + expect(await devices[1].sdkNameAndVersion, 'iOS 10.1 14C54'); + expect(devices[1].cpuArchitecture, DarwinArch.armv7); + expect(devices[1].connectionInterface, DeviceConnectionInterface.attached); + expect(devices[1].isConnected, true); + expect(devices[1].devModeEnabled, true); + + expect(devices[2].id, '234234234234234234345445687594e089dede3c44'); + expect(devices[2].name, 'A networked iPad'); + expect(await devices[2].sdkNameAndVersion, 'iOS 10.1 14C54'); + expect(devices[2].cpuArchitecture, DarwinArch.arm64); // Defaults to arm64 for unknown architecture. + expect(devices[2].connectionInterface, DeviceConnectionInterface.attached); + expect(devices[2].isConnected, true); + expect(devices[2].devModeEnabled, false); + + expect(devices[3].id, 'f577a7903cc54959be2e34bc4f7f80b7009efcf4'); + expect(devices[3].name, 'iPad 2'); + expect(await devices[3].sdkNameAndVersion, 'iOS 10.1 14C54'); + expect(devices[3].cpuArchitecture, DarwinArch.arm64); // Defaults to arm64 for unknown architecture. + expect(devices[3].connectionInterface, DeviceConnectionInterface.attached); + expect(devices[3].isConnected, true); + expect(devices[3].devModeEnabled, false); + + expect(devices[4].id, 'c4ca6f7a53027d1b7e4972e28478e7a28e2faee2'); + expect(devices[4].name, 'iPhone'); + expect(await devices[4].sdkNameAndVersion, 'iOS 13.3 17C54'); + expect(devices[4].cpuArchitecture, DarwinArch.arm64); + expect(devices[4].connectionInterface, DeviceConnectionInterface.attached); + expect(devices[4].isConnected, false); + expect(devices[4].devModeEnabled, true); + + expect(fakeProcessManager, hasNoRemainingExpectations); + }, overrides: { + Platform: () => macPlatform, + Artifacts: () => Artifacts.test(), + }); + + }); }); group('diagnostics', () { @@ -1312,3 +1648,41 @@ class FakeXcodeProjectInterpreter extends Fake implements XcodeProjectInterprete @override List xcrunCommand() => ['xcrun']; } + +class FakeXcodeDebug extends Fake implements XcodeDebug {} + +class FakeIOSCoreDeviceControl extends Fake implements IOSCoreDeviceControl { + + List devices = []; + + @override + Future> getCoreDevices({Duration timeout = Duration.zero}) async { + return devices; + } +} + +class FakeIOSCoreDevice extends Fake implements IOSCoreDevice { + FakeIOSCoreDevice({ + this.udid, + this.connectionInterface, + this.developerModeStatus, + }); + + final String? developerModeStatus; + + @override + final String? udid; + + @override + final DeviceConnectionInterface? connectionInterface; + + @override + IOSCoreDeviceProperties? get deviceProperties => FakeIOSCoreDeviceProperties(developerModeStatus: developerModeStatus); +} + +class FakeIOSCoreDeviceProperties extends Fake implements IOSCoreDeviceProperties { + FakeIOSCoreDeviceProperties({required this.developerModeStatus}); + + @override + final String? developerModeStatus; +} diff --git a/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart b/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart index b0f608538753e..8c6868512138d 100644 --- a/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart +++ b/packages/flutter_tools/test/general.shard/mdns_discovery_test.dart @@ -478,6 +478,18 @@ void main() { }); group('for launch', () { + testWithoutContext('Ensure either port or device name are provided', () async { + final MDnsClient client = FakeMDnsClient([], >{}); + + final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( + mdnsClient: client, + logger: BufferLogger.test(), + flutterUsage: TestUsage(), + ); + + expect(() async => portDiscovery.queryForLaunch(applicationId: 'app-id'), throwsAssertionError); + }); + testWithoutContext('No ports available', () async { final MDnsClient client = FakeMDnsClient([], >{}); @@ -666,6 +678,93 @@ void main() { message:'Did not find a Dart VM Service advertised for srv-bar on port 321.'), ); }); + + testWithoutContext('Matches on application id and device name', () async { + final MDnsClient client = FakeMDnsClient( + [ + PtrResourceRecord('foo', future, domainName: 'srv-foo'), + PtrResourceRecord('bar', future, domainName: 'srv-bar'), + PtrResourceRecord('baz', future, domainName: 'srv-boo'), + ], + >{ + 'srv-bar': [ + SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'My-Phone.local'), + ], + }, + ); + final FakeIOSDevice device = FakeIOSDevice( + name: 'My Phone', + ); + final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( + mdnsClient: client, + logger: BufferLogger.test(), + flutterUsage: TestUsage(), + ); + + final Uri? uri = await portDiscovery.getVMServiceUriForLaunch( + 'srv-bar', + device, + ); + expect(uri.toString(), 'http://127.0.0.1:123/'); + }); + + testWithoutContext('Throw error if unable to find VM Service with app id and device name', () async { + final MDnsClient client = FakeMDnsClient( + [ + PtrResourceRecord('foo', future, domainName: 'srv-foo'), + PtrResourceRecord('bar', future, domainName: 'srv-bar'), + PtrResourceRecord('baz', future, domainName: 'srv-boo'), + ], + >{ + 'srv-foo': [ + SrvResourceRecord('srv-foo', future, port: 123, weight: 1, priority: 1, target: 'target-foo'), + ], + }, + ); + final FakeIOSDevice device = FakeIOSDevice( + name: 'My Phone', + ); + final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( + mdnsClient: client, + logger: BufferLogger.test(), + flutterUsage: TestUsage(), + ); + expect( + portDiscovery.getVMServiceUriForLaunch( + 'srv-bar', + device, + ), + throwsToolExit( + message:'Did not find a Dart VM Service advertised for srv-bar'), + ); + }); + }); + + group('deviceNameMatchesTargetName', () { + testWithoutContext('compares case insensitive and without spaces, hypthens, .local', () { + final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( + mdnsClient: FakeMDnsClient( + [], + >{}, + ), + logger: BufferLogger.test(), + flutterUsage: TestUsage(), + ); + + expect(portDiscovery.deviceNameMatchesTargetName('My phone', 'My-Phone.local'), isTrue); + }); + + testWithoutContext('includes numbers in comparison', () { + final MDnsVmServiceDiscovery portDiscovery = MDnsVmServiceDiscovery( + mdnsClient: FakeMDnsClient( + [], + >{}, + ), + logger: BufferLogger.test(), + flutterUsage: TestUsage(), + ); + expect(portDiscovery.deviceNameMatchesTargetName('My phone', 'My-Phone-2.local'), isFalse); + }); }); testWithoutContext('Find firstMatchingVmService with many available and no application id', () async { @@ -895,6 +994,11 @@ class FakeMDnsClient extends Fake implements MDnsClient { // Until we fix that, we have to also ignore related lints here. // ignore: avoid_implementing_value_types class FakeIOSDevice extends Fake implements IOSDevice { + FakeIOSDevice({this.name = 'iPhone'}); + + @override + final String name; + @override Future get targetPlatform async => TargetPlatform.ios; From 632681da9973a9352cbf03db9cdd29638bafbe1d Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 9 Aug 2023 15:41:45 -0400 Subject: [PATCH 0620/1547] Reland "[web] Migrate framework to fully use package:web (#128901)" (#132092) Relanding https://github.com/flutter/flutter/pull/128901 Part of https://github.com/flutter/flutter/issues/113402 Part of https://github.com/flutter/flutter/issues/127030 --- .../lib/src/foundation/_platform_web.dart | 6 +- .../lib/src/painting/_network_image_web.dart | 29 +- packages/flutter/lib/src/services/dom.dart | 416 ------------------ ...rm_selectable_region_context_menu_web.dart | 27 +- .../painting/_network_image_test_web.dart | 10 +- .../test/painting/_test_http_request.dart | 26 +- 6 files changed, 50 insertions(+), 464 deletions(-) delete mode 100644 packages/flutter/lib/src/services/dom.dart diff --git a/packages/flutter/lib/src/foundation/_platform_web.dart b/packages/flutter/lib/src/foundation/_platform_web.dart index babeee421a23f..30f757012e18a 100644 --- a/packages/flutter/lib/src/foundation/_platform_web.dart +++ b/packages/flutter/lib/src/foundation/_platform_web.dart @@ -4,7 +4,7 @@ import 'dart:ui_web' as ui_web; -import '../services/dom.dart'; +import 'package:web/web.dart' as web; import 'platform.dart' as platform; @@ -38,7 +38,7 @@ final platform.TargetPlatform? _testPlatform = () { // 0.20ms. As `defaultTargetPlatform` is routinely called dozens of times per // frame this value should be cached. final platform.TargetPlatform _browserPlatform = () { - final String navigatorPlatform = domWindow.navigator.platform?.toLowerCase() ?? ''; + final String navigatorPlatform = web.window.navigator.platform.toLowerCase(); if (navigatorPlatform.startsWith('mac')) { return platform.TargetPlatform.macOS; } @@ -58,7 +58,7 @@ final platform.TargetPlatform _browserPlatform = () { // indicates that a device has a "fine pointer" (mouse) as the primary // pointing device, then we'll assume desktop linux, and otherwise we'll // assume Android. - if (domWindow.matchMedia('only screen and (pointer: fine)').matches) { + if (web.window.matchMedia('only screen and (pointer: fine)').matches) { return platform.TargetPlatform.linux; } return platform.TargetPlatform.android; diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index 95e97e0c2853f..af45a0eb33e5a 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -7,17 +7,17 @@ import 'dart:js_interop'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; +import 'package:web/web.dart' as web; -import '../services/dom.dart'; import 'image_provider.dart' as image_provider; import 'image_stream.dart'; /// Creates a type for an overridable factory function for testing purposes. -typedef HttpRequestFactory = DomXMLHttpRequest Function(); +typedef HttpRequestFactory = web.XMLHttpRequest Function(); /// Default HTTP client. -DomXMLHttpRequest _httpClient() { - return DomXMLHttpRequest(); +web.XMLHttpRequest _httpClient() { + return web.XMLHttpRequest(); } /// Creates an overridable factory function. @@ -135,9 +135,9 @@ class NetworkImage // We use a different method when headers are set because the // `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers. if (isCanvasKit || containsNetworkImageHeaders) { - final Completer completer = - Completer(); - final DomXMLHttpRequest request = httpRequestFactory(); + final Completer completer = + Completer(); + final web.XMLHttpRequest request = httpRequestFactory(); request.open('GET', key.url, true); request.responseType = 'arraybuffer'; @@ -147,9 +147,9 @@ class NetworkImage }); } - request.addEventListener('load', createDomEventListener((DomEvent e) { - final int? status = request.status; - final bool accepted = status! >= 200 && status < 300; + request.addEventListener('load', (web.Event e) { + final int status = request.status; + final bool accepted = status >= 200 && status < 300; final bool fileUri = status == 0; // file:// URIs have status of 0. final bool notModified = status == 304; final bool unknownRedirect = status > 307 && status < 400; @@ -161,12 +161,11 @@ class NetworkImage } else { completer.completeError(e); throw image_provider.NetworkImageLoadException( - statusCode: request.status ?? 400, uri: resolved); + statusCode: status, uri: resolved); } - })); + }.toJS); - request.addEventListener('error', - createDomEventListener(completer.completeError)); + request.addEventListener('error', completer.completeError.toJS); request.send(); @@ -176,7 +175,7 @@ class NetworkImage if (bytes.lengthInBytes == 0) { throw image_provider.NetworkImageLoadException( - statusCode: request.status!, uri: resolved); + statusCode: request.status, uri: resolved); } if (decode != null) { diff --git a/packages/flutter/lib/src/services/dom.dart b/packages/flutter/lib/src/services/dom.dart deleted file mode 100644 index 42235a84cf505..0000000000000 --- a/packages/flutter/lib/src/services/dom.dart +++ /dev/null @@ -1,416 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:js_interop'; - -/// This file includes static interop helpers for Flutter Web. -// TODO(joshualitt): This file will eventually be removed, -// https://github.com/flutter/flutter/issues/113402. - -/// [DomWindow] interop object. -@JS() -@staticInterop -class DomWindow {} - -/// [DomWindow] required extension. -extension DomWindowExtension on DomWindow { - @JS('matchMedia') - external DomMediaQueryList _matchMedia(JSString? query); - - /// Returns a [DomMediaQueryList] of the media that matches [query]. - DomMediaQueryList matchMedia(String? query) => _matchMedia(query?.toJS); - - /// Returns the [DomNavigator] associated with this window. - external DomNavigator get navigator; - - /// Gets the current selection. - external DomSelection? getSelection(); -} - -/// The underyling window. -@JS('window') -external DomWindow get domWindow; - -/// [DomMediaQueryList] interop object. -@JS() -@staticInterop -class DomMediaQueryList {} - -/// [DomMediaQueryList] required extension. -extension DomMediaQueryListExtension on DomMediaQueryList { - @JS('matches') - external JSBoolean get _matches; - - /// Whether or not the query matched. - bool get matches => _matches.toDart; -} - -/// [DomNavigator] interop object. -@JS() -@staticInterop -class DomNavigator {} - -/// [DomNavigator] required extension. -extension DomNavigatorExtension on DomNavigator { - @JS('platform') - external JSString? get _platform; - - /// The underyling platform string. - String? get platform => _platform?.toDart; -} - -/// A DOM event target. -@JS() -@staticInterop -class DomEventTarget {} - -/// [DomEventTarget]'s required extension. -extension DomEventTargetExtension on DomEventTarget { - @JS('addEventListener') - external JSVoid _addEventListener1(JSString type, DomEventListener? listener); - - @JS('addEventListener') - external JSVoid _addEventListener2( - JSString type, DomEventListener? listener, JSBoolean useCapture); - - /// Adds an event listener to this event target. - @JS('addEventListener') - void addEventListener(String type, DomEventListener? listener, - [bool? useCapture]) { - if (listener != null) { - if (useCapture == null) { - _addEventListener1(type.toJS, listener); - } else { - _addEventListener2(type.toJS, listener, useCapture.toJS); - } - } - } -} - -/// [DomXMLHttpRequest] interop class. -@JS('XMLHttpRequest') -@staticInterop -class DomXMLHttpRequest extends DomEventTarget { - /// Constructor for [DomXMLHttpRequest]. - external factory DomXMLHttpRequest(); -} - -/// [DomXMLHttpRequest] extension. -extension DomXMLHttpRequestExtension on DomXMLHttpRequest { - /// Gets the response. - external JSAny? get response; - - @JS('responseText') - external JSString? get _responseText; - - /// Gets the response text. - String? get responseText => _responseText?.toDart; - - @JS('responseType') - external JSString get _responseType; - - /// Gets the response type. - String get responseType => _responseType.toDart; - - @JS('status') - external JSNumber? get _status; - - /// Gets the status. - int? get status => _status?.toDartInt; - - @JS('responseType') - external set _responseType(JSString value); - - /// Set the response type. - set responseType(String value) => _responseType = value.toJS; - - @JS('setRequestHeader') - external void _setRequestHeader(JSString header, JSString value); - - /// Set the request header. - void setRequestHeader(String header, String value) => - _setRequestHeader(header.toJS, value.toJS); - - @JS('open') - external JSVoid _open(JSString method, JSString url, JSBoolean isAsync); - - /// Open the request. - void open(String method, String url, bool isAsync) => - _open(method.toJS, url.toJS, isAsync.toJS); - - /// Send the request. - external JSVoid send(); -} - -/// Type for event listener. -typedef DartDomEventListener = JSVoid Function(DomEvent event); - -/// The type of [JSFunction] expected as an `EventListener`. -@JS() -@staticInterop -class DomEventListener {} - -/// Creates a [DomEventListener] from a [DartDomEventListener]. -DomEventListener createDomEventListener(DartDomEventListener listener) => - listener.toJS as DomEventListener; - -/// [DomEvent] interop object. -@JS() -@staticInterop -class DomEvent {} - -/// [DomEvent] required extension. -extension DomEventExtension on DomEvent { - @JS('type') - external JSString get _type; - - /// Get the event type. - String get type => _type.toDart; - - /// Initialize an event. - external JSVoid initEvent( - JSString type, JSBoolean bubbles, JSBoolean cancelable); -} - -/// [DomProgressEvent] interop object. -@JS() -@staticInterop -class DomProgressEvent extends DomEvent {} - -/// [DomProgressEvent] required extension. -extension DomProgressEventExtension on DomProgressEvent { - @JS('loaded') - external JSNumber? get _loaded; - - /// Amount of work done. - int? get loaded => _loaded?.toDartInt; - - @JS('total') - external JSNumber? get _total; - - /// Total amount of work. - int? get total => _total?.toDartInt; -} - -/// The underlying DOM document. -@JS() -@staticInterop -class DomDocument {} - -/// [DomDocument]'s required extension. -extension DomDocumentExtension on DomDocument { - @JS('createEvent') - external DomEvent _createEvent(JSString eventType); - - /// Creates an event. - DomEvent createEvent(String eventType) => _createEvent(eventType.toJS); - - /// Creates a range. - external DomRange createRange(); - - /// Gets the head element. - external DomHTMLHeadElement? get head; - - /// Creates a [DomElement]. - @JS('createElement') - external DomElement createElement(JSString name); -} - -/// Returns the top level document. -@JS('window.document') -external DomDocument get domDocument; - -/// Creates a new DOM event. -DomEvent createDomEvent(String type, String name) { - final DomEvent event = domDocument.createEvent(type); - event.initEvent(name.toJS, true.toJS, true.toJS); - return event; -} - -/// A Range object. -@JS() -@staticInterop -class DomRange {} - -/// [DomRange]'s required extension. -extension DomRangeExtension on DomRange { - /// Selects the provided node. - external JSVoid selectNode(DomNode node); -} - -/// A node in the DOM. -@JS() -@staticInterop -class DomNode extends DomEventTarget {} - -/// [DomNode]'s required extension. -extension DomNodeExtension on DomNode { - @JS('innerText') - external set _innerText(JSString text); - - /// Sets the innerText of this node. - set innerText(String text) => _innerText = text.toJS; - - /// Appends a node this node. - external JSVoid append(DomNode node); -} - -/// An element in the DOM. -@JS() -@staticInterop -class DomElement extends DomNode {} - -/// [DomElement]'s required extension. -extension DomElementExtension on DomElement { - /// Returns the style of this element. - external DomCSSStyleDeclaration get style; - - /// Returns the class list of this element. - external DomTokenList get classList; -} - -/// An HTML element in the DOM. -@JS() -@staticInterop -class DomHTMLElement extends DomElement {} - -/// A UI event. -@JS() -@staticInterop -class DomUIEvent extends DomEvent {} - -/// A mouse event. -@JS() -@staticInterop -class DomMouseEvent extends DomUIEvent {} - -/// [DomMouseEvent]'s required extension. -extension DomMouseEventExtension on DomMouseEvent { - @JS('offsetX') - external JSNumber get _offsetX; - - /// Returns the current x offset. - num get offsetX => _offsetX.toDartDouble; - - @JS('offsetY') - external JSNumber get _offsetY; - - /// Returns the current y offset. - num get offsetY => _offsetY.toDartDouble; - - @JS('button') - external JSNumber get _button; - - /// Returns the current button. - int get button => _button.toDartInt; -} - -/// A DOM selection. -@JS() -@staticInterop -class DomSelection {} - -/// [DomSelection]'s required extension. -extension DomSelectionExtension on DomSelection { - /// Removes all ranges from this selection. - external JSVoid removeAllRanges(); - - /// Adds a range to this selection. - external JSVoid addRange(DomRange range); -} - -/// A DOM html div element. -@JS() -@staticInterop -class DomHTMLDivElement extends DomHTMLElement {} - -/// Factory constructor for [DomHTMLDivElement]. -DomHTMLDivElement createDomHTMLDivElement() => - domDocument.createElement('div'.toJS) as DomHTMLDivElement; - -/// An html style element. -@JS() -@staticInterop -class DomHTMLStyleElement extends DomHTMLElement {} - -/// [DomHTMLStyleElement]'s required extension. -extension DomHTMLStyleElementExtension on DomHTMLStyleElement { - /// Get's the style sheet of this element. - external DomStyleSheet? get sheet; -} - -/// Factory constructor for [DomHTMLStyleElement]. -DomHTMLStyleElement createDomHTMLStyleElement() => - domDocument.createElement('style'.toJS) as DomHTMLStyleElement; - -/// CSS styles. -@JS() -@staticInterop -class DomCSSStyleDeclaration {} - -/// [DomCSSStyleDeclaration]'s required extension. -extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration { - /// Sets the width. - set width(String value) => setProperty('width', value); - - /// Sets the height. - set height(String value) => setProperty('height', value); - - @JS('setProperty') - external JSVoid _setProperty( - JSString propertyName, JSString value, JSString priority); - - /// Sets a CSS property by name. - void setProperty(String propertyName, String value, [String? priority]) { - priority ??= ''; - _setProperty(propertyName.toJS, value.toJS, priority.toJS); - } -} - -/// The HTML head element. -@JS() -@staticInterop -class DomHTMLHeadElement extends DomHTMLElement {} - -/// A DOM style sheet. -@JS() -@staticInterop -class DomStyleSheet {} - -/// A DOM CSS style sheet. -@JS() -@staticInterop -class DomCSSStyleSheet extends DomStyleSheet {} - -/// [DomCSSStyleSheet]'s required extension. -extension DomCSSStyleSheetExtension on DomCSSStyleSheet { - @JS('insertRule') - external JSNumber _insertRule1(JSString rule); - - @JS('insertRule') - external JSNumber _insertRule2(JSString rule, JSNumber index); - - /// Inserts a rule into this style sheet. - int insertRule(String rule, [int? index]) { - if (index == null) { - return _insertRule1(rule.toJS).toDartInt; - } else { - return _insertRule2(rule.toJS, index.toJS).toDartInt; - } - } -} - -/// A list of token. -@JS() -@staticInterop -class DomTokenList {} - -/// [DomTokenList]'s required extension. -extension DomTokenListExtension on DomTokenList { - @JS('add') - external JSVoid _add(JSString value); - - /// Adds a token to this token list. - void add(String value) => _add(value.toJS); -} diff --git a/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart b/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart index 2a5fa323b81ee..9e29598855d08 100644 --- a/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart +++ b/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:js_interop'; import 'dart:ui_web' as ui_web; import 'package:flutter/rendering.dart'; +import 'package:web/web.dart' as web; -import '../services/dom.dart'; import 'basic.dart'; import 'framework.dart'; import 'platform_view.dart'; @@ -27,7 +28,7 @@ const String _kClassRule = ''' '''; const int _kRightClickButton = 2; -typedef _WebSelectionCallBack = void Function(DomHTMLElement, DomMouseEvent); +typedef _WebSelectionCallBack = void Function(web.HTMLElement, web.MouseEvent); /// Function signature for `ui_web.platformViewRegistry.registerViewFactory`. @visibleForTesting @@ -80,11 +81,11 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { // Registers the view factories for the interceptor widgets. static void _register() { assert(_registeredViewType == null); - _registeredViewType = _registerWebSelectionCallback((DomHTMLElement element, DomMouseEvent event) { + _registeredViewType = _registerWebSelectionCallback((web.HTMLElement element, web.MouseEvent event) { final SelectionContainerDelegate? client = _activeClient; if (client != null) { // Converts the html right click event to flutter coordinate. - final Offset localOffset = Offset(event.offsetX.toDouble(), event.offsetY.toDouble()); + final Offset localOffset = Offset(event.offsetX, event.offsetY); final Matrix4 transform = client.getTransformTo(null); final Offset globalOffset = MatrixUtils.transformPoint(transform, localOffset); client.dispatchSelectionEvent(SelectWordSelectionEvent(globalPosition: globalOffset)); @@ -93,9 +94,9 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { element.innerText = client.getSelectedContent()?.plainText ?? ''; // Programmatically select the dom element in browser. - final DomRange range = domDocument.createRange(); + final web.Range range = web.document.createRange(); range.selectNode(element); - final DomSelection? selection = domWindow.getSelection(); + final web.Selection? selection = web.window.getSelection(); if (selection != null) { selection.removeAllRanges(); selection.addRange(range); @@ -106,26 +107,26 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { static String _registerWebSelectionCallback(_WebSelectionCallBack callback) { _registerViewFactory(_viewType, (int viewId) { - final DomHTMLElement htmlElement = createDomHTMLDivElement(); + final web.HTMLElement htmlElement = web.document.createElement('div') as web.HTMLElement; htmlElement ..style.width = '100%' ..style.height = '100%' ..classList.add(_kClassName); // Create css style for _kClassName. - final DomHTMLStyleElement styleElement = createDomHTMLStyleElement(); - domDocument.head!.append(styleElement); - final DomCSSStyleSheet sheet = styleElement.sheet! as DomCSSStyleSheet; + final web.HTMLStyleElement styleElement = web.document.createElement('style') as web.HTMLStyleElement; + web.document.head!.append(styleElement); + final web.CSSStyleSheet sheet = styleElement.sheet!; sheet.insertRule(_kClassRule, 0); sheet.insertRule(_kClassSelectionRule, 1); - htmlElement.addEventListener('mousedown', createDomEventListener((DomEvent event) { - final DomMouseEvent mouseEvent = event as DomMouseEvent; + htmlElement.addEventListener('mousedown', (web.Event event) { + final web.MouseEvent mouseEvent = event as web.MouseEvent; if (mouseEvent.button != _kRightClickButton) { return; } callback(htmlElement, mouseEvent); - })); + }.toJS); return htmlElement; }, isVisible: false); return _viewType; diff --git a/packages/flutter/test/painting/_network_image_test_web.dart b/packages/flutter/test/painting/_network_image_test_web.dart index f82a6e16103dc..307d6f910841f 100644 --- a/packages/flutter/test/painting/_network_image_test_web.dart +++ b/packages/flutter/test/painting/_network_image_test_web.dart @@ -5,8 +5,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/painting/_network_image_web.dart'; -import 'package:flutter/src/services/dom.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:web/web.dart' as web; import '../image_data.dart'; import '_test_http_request.dart'; @@ -20,7 +20,7 @@ void runTests() { (WidgetTester tester) async { final TestHttpRequest testHttpRequest = TestHttpRequest() ..status = 200 - ..mockEvent = MockEvent('load', createDomEvent('Event', 'test error')) + ..mockEvent = MockEvent('load', web.Event('test error')) ..response = (Uint8List.fromList(kTransparentImage)).buffer; httpRequestFactory = () { @@ -46,7 +46,7 @@ void runTests() { (WidgetTester tester) async { final TestHttpRequest testHttpRequest = TestHttpRequest() ..status = 404 - ..mockEvent = MockEvent('error', createDomEvent('Event', 'test error')); + ..mockEvent = MockEvent('error', web.Event('test error')); httpRequestFactory = () { @@ -64,14 +64,14 @@ void runTests() { ); await tester.pumpWidget(image); - expect((tester.takeException() as DomProgressEvent).type, 'test error'); + expect((tester.takeException() as web.ProgressEvent).type, 'test error'); }); testWidgets('loads an image from the network with empty response', (WidgetTester tester) async { final TestHttpRequest testHttpRequest = TestHttpRequest() ..status = 200 - ..mockEvent = MockEvent('load', createDomEvent('Event', 'test error')) + ..mockEvent = MockEvent('load', web.Event('test error')) ..response = (Uint8List.fromList([])).buffer; httpRequestFactory = () { diff --git a/packages/flutter/test/painting/_test_http_request.dart b/packages/flutter/test/painting/_test_http_request.dart index ccfbf1d752af9..86e03ae80c1c1 100644 --- a/packages/flutter/test/painting/_test_http_request.dart +++ b/packages/flutter/test/painting/_test_http_request.dart @@ -4,16 +4,16 @@ import 'dart:js_interop'; -import 'package:flutter/src/services/dom.dart'; +import 'package:web/web.dart' as web; /// Defines a new property on an Object. @JS('Object.defineProperty') -external JSVoid objectDefineProperty(JSAny o, JSString symbol, JSAny desc); +external void objectDefineProperty(JSAny o, String symbol, JSAny desc); void createGetter(JSAny mock, String key, JSAny? Function() get) { objectDefineProperty( mock, - key.toJS, + key, { 'get': (() => get()).toJS, }.jsify()!, @@ -35,6 +35,8 @@ class DomXMLHttpRequestMock { }); } +typedef _DartDomEventListener = JSVoid Function(web.Event event); + class TestHttpRequest { TestHttpRequest() { _mock = DomXMLHttpRequestMock( @@ -58,26 +60,26 @@ class TestHttpRequest { Object? response; Map get responseHeaders => headers; - JSVoid open(JSString method, JSString url, JSBoolean async) {} + JSVoid open(String method, String url, bool async) {} JSVoid send() {} - JSVoid setRequestHeader(JSString name, JSString value) { - headers[name.toDart] = value.toDart; + JSVoid setRequestHeader(String name, String value) { + headers[name] = value; } - JSVoid addEventListener(JSString type, DomEventListener listener) { - if (type.toDart == mockEvent?.type) { - final DartDomEventListener dartListener = - (listener as JSExportedDartFunction).toDart as DartDomEventListener; + JSVoid addEventListener(String type, web.EventListener listener) { + if (type == mockEvent?.type) { + final _DartDomEventListener dartListener = + (listener as JSExportedDartFunction).toDart as _DartDomEventListener; dartListener(mockEvent!.event); } } - DomXMLHttpRequest getMock() => _mock as DomXMLHttpRequest; + web.XMLHttpRequest getMock() => _mock as web.XMLHttpRequest; } class MockEvent { MockEvent(this.type, this.event); final String type; - final DomEvent event; + final web.Event event; } From 6ac161f90941cb16d9db40961432b6755d4cb255 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Wed, 9 Aug 2023 12:59:03 -0700 Subject: [PATCH 0621/1547] Add an example for `TapAndPanGestureRecognizer` (#131873) This adds an example for `TapAndPanGestureRecognizer` that demonstrates how to scale a widget using a double tap + vertical drag gesture. https://github.com/flutter/flutter/assets/948037/4c6c5467-2157-4b6a-bc52-264a3b6303de --- .../gestures/tap_and_drag/tap_and_drag.0.dart | 138 ++++++++++++++++++ .../tap_and_drag/tap_and_drag.0_test.dart | 88 +++++++++++ .../lib/src/gestures/tap_and_drag.dart | 7 + 3 files changed, 233 insertions(+) create mode 100644 examples/api/lib/gestures/tap_and_drag/tap_and_drag.0.dart create mode 100644 examples/api/test/gestures/tap_and_drag/tap_and_drag.0_test.dart diff --git a/examples/api/lib/gestures/tap_and_drag/tap_and_drag.0.dart b/examples/api/lib/gestures/tap_and_drag/tap_and_drag.0.dart new file mode 100644 index 0000000000000..ec1229572be53 --- /dev/null +++ b/examples/api/lib/gestures/tap_and_drag/tap_and_drag.0.dart @@ -0,0 +1,138 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +/// Flutter code sample for [TapAndPanGestureRecognizer]. + +void main() { + runApp(const TapAndDragToZoomApp()); +} + +class TapAndDragToZoomApp extends StatelessWidget { + const TapAndDragToZoomApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: Scaffold( + body: Center( + child: TapAndDragToZoomWidget( + child: MyBoxWidget(), + ), + ), + ), + ); + } +} + +class MyBoxWidget extends StatelessWidget { + const MyBoxWidget({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.blueAccent, + height: 100.0, + width: 100.0, + ); + } +} + +// This widget will scale its child up when it detects a drag up, after a +// double tap/click. It will scale the widget down when it detects a drag down, +// after a double tap. Dragging down and then up after a double tap/click will +// zoom the child in/out. The scale of the child will be reset when the drag ends. +class TapAndDragToZoomWidget extends StatefulWidget { + const TapAndDragToZoomWidget({super.key, required this.child}); + + final Widget child; + + @override + State createState() => _TapAndDragToZoomWidgetState(); +} + +class _TapAndDragToZoomWidgetState extends State { + final double scaleMultiplier = -0.0001; + double _currentScale = 1.0; + Offset? _previousDragPosition; + + static double _keepScaleWithinBounds(double scale) { + const double minScale = 0.1; + const double maxScale = 30; + if (scale <= 0) { + return minScale; + } + if (scale >= 30) { + return maxScale; + } + return scale; + } + + void _zoomLogic(Offset currentDragPosition) { + final double dx = (_previousDragPosition!.dx - currentDragPosition.dx).abs(); + final double dy = (_previousDragPosition!.dy - currentDragPosition.dy).abs(); + + if (dx > dy) { + // Ignore horizontal drags. + _previousDragPosition = currentDragPosition; + return; + } + + if (currentDragPosition.dy < _previousDragPosition!.dy) { + // Zoom out on drag up. + setState(() { + _currentScale += currentDragPosition.dy * scaleMultiplier; + _currentScale = _keepScaleWithinBounds(_currentScale); + }); + } else { + // Zoom in on drag down. + setState(() { + _currentScale -= currentDragPosition.dy * scaleMultiplier; + _currentScale = _keepScaleWithinBounds(_currentScale); + }); + } + _previousDragPosition = currentDragPosition; + } + + @override + Widget build(BuildContext context) { + return RawGestureDetector( + gestures: { + TapAndPanGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => TapAndPanGestureRecognizer(), + (TapAndPanGestureRecognizer instance) { + instance + ..onTapDown = (TapDragDownDetails details) { + _previousDragPosition = details.globalPosition; + } + ..onDragStart = (TapDragStartDetails details) { + if (details.consecutiveTapCount == 2) { + _zoomLogic(details.globalPosition); + } + } + ..onDragUpdate = (TapDragUpdateDetails details) { + if (details.consecutiveTapCount == 2) { + _zoomLogic(details.globalPosition); + } + } + ..onDragEnd = (TapDragEndDetails details) { + if (details.consecutiveTapCount == 2) { + setState(() { + _currentScale = 1.0; + }); + _previousDragPosition = null; + } + }; + } + ), + }, + child: Transform.scale( + scale: _currentScale, + child: widget.child, + ), + ); + } +} diff --git a/examples/api/test/gestures/tap_and_drag/tap_and_drag.0_test.dart b/examples/api/test/gestures/tap_and_drag/tap_and_drag.0_test.dart new file mode 100644 index 0000000000000..991d8ef493795 --- /dev/null +++ b/examples/api/test/gestures/tap_and_drag/tap_and_drag.0_test.dart @@ -0,0 +1,88 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/gestures/tap_and_drag/tap_and_drag.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Single tap + drag should not change the scale of child', (WidgetTester tester) async { + await tester.pumpWidget( + const example.TapAndDragToZoomApp(), + ); + + double getScale() { + final RenderBox box = tester.renderObject(find.byType(Container).first); + return box.getTransformTo(null)[0]; + } + + final Finder containerFinder = find.byType(Container).first; + final Offset centerOfChild = tester.getCenter(containerFinder); + + expect(getScale(), 1.0); + + // Single tap + drag down. + final TestGesture gesture = await tester.startGesture(centerOfChild); + await tester.pump(); + await gesture.moveTo(centerOfChild + const Offset(0, 100.0)); + await tester.pump(); + expect(getScale(), 1.0); + + // Single tap + drag up. + await gesture.moveTo(centerOfChild); + await tester.pump(); + expect(getScale(), 1.0); + }); + + testWidgets('Double tap + drag should change the scale of the child', (WidgetTester tester) async { + await tester.pumpWidget( + const example.TapAndDragToZoomApp(), + ); + + double getScale() { + final RenderBox box = tester.renderObject(find.byType(Container).first); + return box.getTransformTo(null)[0]; + } + + final Finder containerFinder = find.byType(Container).first; + final Offset centerOfChild = tester.getCenter(containerFinder); + + expect(getScale(), 1.0); + + // Double tap + drag down to scale up. + final TestGesture gesture = await tester.startGesture(centerOfChild); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(centerOfChild); + await tester.pump(); + await gesture.moveTo(centerOfChild + const Offset(0, 100.0)); + await tester.pump(); + expect(getScale(), greaterThan(1.0)); + + // Scale is reset on drag end. + await gesture.up(); + await tester.pumpAndSettle(); + expect(getScale(), 1.0); + + // Double tap + drag up to scale down. + await gesture.down(centerOfChild); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(centerOfChild); + await tester.pump(); + await gesture.moveTo(centerOfChild + const Offset(0, -100.0)); + await tester.pump(); + expect(getScale(), lessThan(1.0)); + + // Scale is reset on drag end. + await gesture.up(); + await tester.pumpAndSettle(); + expect(getScale(), 1.0); + }); +} diff --git a/packages/flutter/lib/src/gestures/tap_and_drag.dart b/packages/flutter/lib/src/gestures/tap_and_drag.dart index 907173c5d79c2..31aa233c80434 100644 --- a/packages/flutter/lib/src/gestures/tap_and_drag.dart +++ b/packages/flutter/lib/src/gestures/tap_and_drag.dart @@ -684,6 +684,13 @@ mixin _TapStatusTrackerMixin on OneSequenceGestureRecognizer { /// pointer does travel enough distance then the recognizer that entered the arena /// first will win. The gesture detected in this case is a drag. /// +/// {@tool dartpad} +/// This example shows how to use the [TapAndPanGestureRecognizer] along with a +/// [RawGestureDetector] to scale a Widget. +/// +/// ** See code in examples/api/lib/gestures/tap_and_drag/tap_and_drag.0.dart ** +/// {@end-tool} +/// /// {@tool snippet} /// /// This example shows how to hook up [TapAndPanGestureRecognizer]s' to nested From f5ceaf9810847885c86b0a4e8bfa22c30c592093 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Wed, 9 Aug 2023 13:36:45 -0700 Subject: [PATCH 0622/1547] Handle hasStrings on web (#132093) By default, Flutter web uses the browser's built-in context menu. As of [recently](https://github.com/flutter/engine/pull/38682), it's possible to use a Flutter-rendered context menu like the other platforms. ```dart void main() { runApp(const MyApp()); BrowserContextMenu.disableContextMenu(); } ``` But there is a bug (https://github.com/flutter/flutter/issues/129692) that the Paste button is missing and never shows up. Screenshot 2023-08-07 at 2 39 03 PM The reason why it's missing is that Flutter first checks if there is any pasteable text on the clipboard before deciding to show the Paste button using the `hasStrings` platform channel method, but that was never implemented for web ([original hasStrings PR](https://github.com/flutter/flutter/pull/87678)). So let's just implement hasStrings for web? No, because Chrome shows a permissions prompt when the clipboard is accessed, and there is [no browser clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) to avoid it. The prompt will show immediately when the EditableText is built, not just when the Paste button is pressed. ### This PR's solution Instead, before implementing hasStrings for web, this PR disables the hasStrings check for web. The result is that users will always see a paste button, even in the (unlikely) case that they have nothing pasteable on the clipboard. However, they will not see a permissions dialog until they actually click the Paste button. Subsequent pastes don't show the permission dialog.
Video of final behavior with this PR https://github.com/flutter/flutter/assets/389558/ed16c925-8111-44a7-99e8-35a09d682748
I think this will be the desired behavior for the vast majority of app developers. Those that want different behavior can use hasStrings themselves, which will be implemented in https://github.com/flutter/engine/pull/43360. ### References Fixes https://github.com/flutter/flutter/issues/129692 Engine PR to be merged after this: https://github.com/flutter/engine/pull/43360 --- .../lib/src/widgets/editable_text.dart | 23 ++++++- .../test/material/text_field_test.dart | 4 +- .../test/widgets/editable_text_test.dart | 63 +++++++++++++++++-- 3 files changed, 83 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index f371290e7508d..9f857021fdf3e 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2102,7 +2102,13 @@ class EditableTextState extends State with AutomaticKeepAliveClien final GlobalKey _editableKey = GlobalKey(); /// Detects whether the clipboard can paste. - final ClipboardStatusNotifier clipboardStatus = ClipboardStatusNotifier(); + final ClipboardStatusNotifier clipboardStatus = kIsWeb + // Web browsers will show a permission dialog when Clipboard.hasStrings is + // called. In an EditableText, this will happen before the paste button is + // clicked, often before the context menu is even shown. To avoid this + // poor user experience, always show the paste button on web. + ? _WebClipboardStatusNotifier() + : ClipboardStatusNotifier(); /// Detects whether the Live Text input is enabled. /// @@ -5561,3 +5567,18 @@ class _GlyphHeights { /// The glyph height of the last line. final double end; } + +/// A [ClipboardStatusNotifier] whose [value] is hardcoded to +/// [ClipboardStatus.pasteable]. +/// +/// Useful to avoid showing a permission dialog on web, which happens when +/// [Clipboard.hasStrings] is called. +class _WebClipboardStatusNotifier extends ClipboardStatusNotifier { + @override + ClipboardStatus value = ClipboardStatus.pasteable; + + @override + Future update() { + return Future.value(); + } +} diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 966ff68b0dcfe..3697dbc37a380 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -14154,7 +14154,9 @@ void main() { expect(calledGetData, false); // hasStrings is checked in order to decide if the content can be pasted. expect(calledHasStrings, true); - }); + }, + skip: kIsWeb, // [intended] web doesn't call hasStrings. + ); testWidgets('TextField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 6d008132e8591..461085d7f2c47 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -63,11 +63,10 @@ TextEditingValue collapsedAtEnd(String text) { } void main() { - final MockClipboard mockClipboard = MockClipboard(); - TestWidgetsFlutterBinding.ensureInitialized() - .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall); - setUp(() async { + final MockClipboard mockClipboard = MockClipboard(); + TestWidgetsFlutterBinding.ensureInitialized() + .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall); debugResetSemanticsIdCounter(); controller = TextEditingController(); // Fill the clipboard so that the Paste option is available in the text @@ -76,6 +75,8 @@ void main() { }); tearDown(() { + TestWidgetsFlutterBinding.ensureInitialized() + .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null); controller.dispose(); }); @@ -2145,7 +2146,7 @@ void main() { ); final EditableTextState state = - tester.state(find.byType(EditableText)); + tester.state(find.byType(EditableText)); // Show the toolbar. state.renderEditable.selectWordsInRange( @@ -2156,9 +2157,11 @@ void main() { final TextSelection copySelectionRange = localController.selection; + expect(find.byType(TextSelectionToolbar), findsNothing); state.showToolbar(); await tester.pumpAndSettle(); + expect(find.byType(TextSelectionToolbar), findsOneWidget); expect(find.text('Copy'), findsOneWidget); await tester.tap(find.text('Copy')); @@ -16603,6 +16606,56 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, skip: kIsWeb, // [intended] ); + + group('hasStrings', () { + late int calls; + setUp(() { + calls = 0; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) { + if (methodCall.method == 'Clipboard.hasStrings') { + calls += 1; + } + return Future.value(); + }); + }); + tearDown(() { + TestWidgetsFlutterBinding.ensureInitialized() + .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null); + }); + + testWidgets('web avoids the paste permissions prompt by not calling hasStrings', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: EditableText( + backgroundCursorColor: Colors.grey, + controller: TextEditingController(), + focusNode: focusNode, + obscureText: true, + toolbarOptions: const ToolbarOptions( + copy: true, + cut: true, + paste: true, + selectAll: true, + ), + style: textStyle, + cursorColor: cursorColor, + selectionControls: materialTextSelectionControls, + ), + ), + ); + + expect(calls, equals(kIsWeb ? 0 : 1)); + + // Long-press to bring up the context menu. + final Finder textFinder = find.byType(EditableText); + await tester.longPress(textFinder); + tester.state(textFinder).showToolbar(); + await tester.pumpAndSettle(); + + expect(calls, equals(kIsWeb ? 0 : 2)); + }); + }); } class UnsettableController extends TextEditingController { From 6da6fbf5a8f18f84d7888d0e5f60808bd77decaf Mon Sep 17 00:00:00 2001 From: Bernardo Ferrari Date: Wed, 9 Aug 2023 18:58:52 -0300 Subject: [PATCH 0623/1547] Deprecate `describeEnum`. (#125016) Final part of https://github.com/flutter/flutter/issues/123346. --- .../flutter/lib/src/foundation/diagnostics.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index e5c1345ade8cc..b2ecd9a903d28 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -2262,14 +2262,12 @@ class IterableProperty extends DiagnosticsProperty> { } } -/// An property than displays enum values tersely. +/// [DiagnosticsProperty] that has an [Enum] as value. /// -/// The enum value is displayed with the class name stripped. For example: +/// The enum value is displayed with the enum name stripped. For example: /// [HitTestBehavior.deferToChild] is shown as `deferToChild`. /// -/// This class can be used with classes that appear like enums but are not -/// "real" enums, so long as their `toString` implementation, in debug mode, -/// returns a string consisting of the class name followed by the value name. It +/// This class can be used with enums and returns the enum's name getter. It /// can also be used with nullable properties; the null value is represented as /// `null`. /// @@ -2277,7 +2275,7 @@ class IterableProperty extends DiagnosticsProperty> { /// /// * [DiagnosticsProperty] which documents named parameters common to all /// [DiagnosticsProperty]. -class EnumProperty extends DiagnosticsProperty { +class EnumProperty extends DiagnosticsProperty { /// Create a diagnostics property that displays an enum. /// /// The [level] argument must also not be null. @@ -2293,7 +2291,7 @@ class EnumProperty extends DiagnosticsProperty { if (value == null) { return value.toString(); } - return describeEnum(value!); + return value!.name; } } @@ -2975,11 +2973,16 @@ String describeIdentity(Object? object) => '${objectRuntimeType(object, ' Date: Wed, 9 Aug 2023 22:29:58 +0000 Subject: [PATCH 0624/1547] Remove shrinkWrap from flexible_space_bar_test.dart (#132173) See title. --- .../material/flexible_space_bar_test.dart | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index 1de3f896b7cc7..b20624e04bb06 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -910,21 +910,17 @@ class _SubCategoryScreenViewState extends State ), ), const SliverToBoxAdapter(child: SizedBox(height: 12)), - SliverToBoxAdapter( - child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 3, - ), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: 300, - itemBuilder: (BuildContext context, int index) { - return Card( - color: Colors.amber, - child: Center(child: Text('$index')), - ); - }, + SliverGrid.builder( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, ), + itemCount: 300, + itemBuilder: (BuildContext context, int index) { + return Card( + color: Colors.amber, + child: Center(child: Text('$index')), + ); + }, ), const SliverToBoxAdapter(child: SizedBox(height: 12)), ], From 9c8f3950e3b9bf33d527b69f14f7f785134f8a8f Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 9 Aug 2023 15:58:26 -0700 Subject: [PATCH 0625/1547] Sample code for ImageProvider (#131952) Also: - minor improvements to documentation - wrap one of our test error messages in a manner more consistent with other messages --- dev/bots/test.dart | 13 +-- .../image_provider/image_provider.0.dart | 104 ++++++++++++++++++ .../image_provider/image_provider.0_test.dart | 20 ++++ .../flutter/lib/src/foundation/print.dart | 6 + .../lib/src/painting/image_provider.dart | 25 ++++- packages/flutter/lib/src/widgets/image.dart | 14 ++- .../flutter_test/lib/src/_binding_io.dart | 20 ++-- 7 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 examples/api/lib/painting/image_provider/image_provider.0.dart create mode 100644 examples/api/test/painting/image_provider/image_provider.0_test.dart diff --git a/dev/bots/test.dart b/dev/bots/test.dart index be3405c79e9f9..26fa9c6cdbc55 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1006,14 +1006,11 @@ Future _runFrameworkTests() async { await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol')); await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable')); const String httpClientWarning = - 'Warning: At least one test in this suite creates an HttpClient. When\n' - 'running a test suite that uses TestWidgetsFlutterBinding, all HTTP\n' - 'requests will return status code 400, and no network request will\n' - 'actually be made. Any test expecting a real network connection and\n' - 'status code will fail.\n' - 'To test code that needs an HttpClient, provide your own HttpClient\n' - 'implementation to the code under test, so that your test can\n' - 'consistently provide a testable response to the code under test.'; + 'Warning: At least one test in this suite creates an HttpClient. When running a test suite that uses\n' + 'TestWidgetsFlutterBinding, all HTTP requests will return status code 400, and no network request\n' + 'will actually be made. Any test expecting a real network connection and status code will fail.\n' + 'To test code that needs an HttpClient, provide your own HttpClient implementation to the code under\n' + 'test, so that your test can consistently provide a testable response to the code under test.'; await _runFlutterTest( path.join(flutterRoot, 'packages', 'flutter_test'), script: path.join('test', 'bindings_test_failure.dart'), diff --git a/examples/api/lib/painting/image_provider/image_provider.0.dart b/examples/api/lib/painting/image_provider/image_provider.0.dart new file mode 100644 index 0000000000000..86349f15c0d0f --- /dev/null +++ b/examples/api/lib/painting/image_provider/image_provider.0.dart @@ -0,0 +1,104 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:io'; +import 'dart:ui' as ui; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +@immutable +class CustomNetworkImage extends ImageProvider { + const CustomNetworkImage(this.url); + + final String url; + + @override + Future obtainKey(ImageConfiguration configuration) { + final Uri result = Uri.parse(url).replace( + queryParameters: { + 'dpr': '${configuration.devicePixelRatio}', + 'locale': '${configuration.locale?.toLanguageTag()}', + 'platform': '${configuration.platform?.name}', + 'width': '${configuration.size?.width}', + 'height': '${configuration.size?.height}', + 'bidi': '${configuration.textDirection?.name}', + }, + ); + return SynchronousFuture(result); + } + + static HttpClient get _httpClient { + HttpClient? client; + assert(() { + if (debugNetworkImageHttpClientProvider != null) { + client = debugNetworkImageHttpClientProvider!(); + } + return true; + }()); + return client ?? HttpClient()..autoUncompress = false; + } + + @override + ImageStreamCompleter loadImage(Uri key, ImageDecoderCallback decode) { + final StreamController chunkEvents = StreamController(); + debugPrint('Fetching "$key"...'); + return MultiFrameImageStreamCompleter( + codec: _httpClient.getUrl(key) + .then((HttpClientRequest request) => request.close()) + .then((HttpClientResponse response) { + return consolidateHttpClientResponseBytes( + response, + onBytesReceived: (int cumulative, int? total) { + chunkEvents.add(ImageChunkEvent( + cumulativeBytesLoaded: cumulative, + expectedTotalBytes: total, + )); + }, + ); + }) + .catchError((Object e, StackTrace stack) { + scheduleMicrotask(() { + PaintingBinding.instance.imageCache.evict(key); + }); + return Future.error(e, stack); + }) + .whenComplete(chunkEvents.close) + .then(ui.ImmutableBuffer.fromUint8List) + .then(decode), + chunkEvents: chunkEvents.stream, + scale: 1.0, + debugLabel: '"key"', + informationCollector: () => [ + DiagnosticsProperty('Image provider', this), + DiagnosticsProperty('URL', key), + ], + ); + } + + @override + String toString() => '${objectRuntimeType(this, 'CustomNetworkImage')}("$url")'; +} + +void main() => runApp(const ExampleApp()); + +class ExampleApp extends StatelessWidget { + const ExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Image( + image: const CustomNetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/flamingos.jpg'), + width: constraints.hasBoundedWidth ? constraints.maxWidth : null, + height: constraints.hasBoundedHeight ? constraints.maxHeight : null, + ); + }, + ), + ); + } +} diff --git a/examples/api/test/painting/image_provider/image_provider.0_test.dart b/examples/api/test/painting/image_provider/image_provider.0_test.dart new file mode 100644 index 0000000000000..0b1ce43c0aee6 --- /dev/null +++ b/examples/api/test/painting/image_provider/image_provider.0_test.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter_api_samples/painting/image_provider/image_provider.0.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('$CustomNetworkImage', (WidgetTester tester) async { + const String expectedUrl = 'https://flutter.github.io/assets-for-api-docs/assets/widgets/flamingos.jpg?dpr=3.0&locale=en-US&platform=android&width=800.0&height=600.0&bidi=ltr'; + final List log = []; + final DebugPrintCallback originalDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { log.add('$message'); }; + await tester.pumpWidget(const ExampleApp()); + expect(tester.takeException().toString(), 'Exception: Invalid image data'); + expect(log, ['Fetching "$expectedUrl"...']); + debugPrint = originalDebugPrint; + }); +} diff --git a/packages/flutter/lib/src/foundation/print.dart b/packages/flutter/lib/src/foundation/print.dart index 7f60da7bb6cb9..123e591649a66 100644 --- a/packages/flutter/lib/src/foundation/print.dart +++ b/packages/flutter/lib/src/foundation/print.dart @@ -34,6 +34,7 @@ typedef DebugPrintCallback = void Function(String? message, { int? wrapWidth }); /// See also: /// /// * [DebugPrintCallback], for function parameters and usage details. +/// * [debugPrintThrottled], the default implementation. DebugPrintCallback debugPrint = debugPrintThrottled; /// Alternative implementation of [debugPrint] that does not throttle. @@ -48,6 +49,8 @@ void debugPrintSynchronously(String? message, { int? wrapWidth }) { /// Implementation of [debugPrint] that throttles messages. This avoids dropping /// messages on platforms that rate-limit their logging (for example, Android). +/// +/// If `wrapWidth` is not null, the message is wrapped using [debugWordWrap]. void debugPrintThrottled(String? message, { int? wrapWidth }) { final List messageLines = message?.split('\n') ?? ['null']; if (wrapWidth != null) { @@ -100,6 +103,9 @@ enum _WordWrapParseMode { inSpace, inWord, atBreak } /// Wraps the given string at the given width. /// +/// The `message` should not contain newlines (`\n`, U+000A). Strings that may +/// contain newlines should be [String.split] before being wrapped. +/// /// Wrapping occurs at space characters (U+0020). Lines that start with an /// octothorpe ("#", U+0023) are not wrapped (so for example, Dart stack traces /// won't be wrapped). diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index 728ccbff0e44d..0689ad192d423 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -344,6 +344,16 @@ typedef ImageDecoderCallback = Future Function( /// } /// ``` /// {@end-tool} +/// +/// ## Creating an [ImageProvider] +/// +/// {@tool dartpad} +/// In this example, a variant of [NetworkImage] is created that passes all the +/// [ImageConfiguration] information (locale, platform, size, etc) to the server +/// using query arguments in the image URL. +/// +/// ** See code in examples/api/lib/painting/image_provider/image_provider.0.dart ** +/// {@end-tool} @optionalTypeArgs abstract class ImageProvider { /// Abstract const constructor. This constructor enables subclasses to provide @@ -596,7 +606,7 @@ abstract class ImageProvider { return cache.evict(key); } - /// Converts an ImageProvider's settings plus an ImageConfiguration to a key + /// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key /// that describes the precise image to load. /// /// The type of the key is determined by the subclass. It is a value that @@ -605,6 +615,10 @@ abstract class ImageProvider { /// arguments and [ImageConfiguration] objects should return keys that are /// '==' to each other (possibly by using a class for the key that itself /// implements [==]). + /// + /// If the result can be determined synchronously, this function should return + /// a [SynchronousFuture]. This allows image resolution to progress + /// synchronously during a frame rather than delaying image loading. Future obtainKey(ImageConfiguration configuration); /// Converts a key into an [ImageStreamCompleter], and begins fetching the @@ -632,10 +646,7 @@ abstract class ImageProvider { /// Converts a key into an [ImageStreamCompleter], and begins fetching the /// image. /// - /// For backwards-compatibility the default implementation of this method returns - /// an object that will cause [resolveStreamForKey] to consult [load]. However, - /// implementors of this interface should only override this method and not - /// [load], which is deprecated. + /// This method is deprecated. Implement [loadImage] instead. /// /// The [decode] callback provides the logic to obtain the codec for the /// image. @@ -1477,6 +1488,8 @@ class ResizeImage extends ImageProvider { /// See also: /// /// * [Image.network] for a shorthand of an [Image] widget backed by [NetworkImage]. +/// * The example at [ImageProvider], which shows a custom variant of this class +/// that applies different logic for fetching the image. // TODO(ianh): Find some way to honor cache headers to the extent that when the // last reference to an image is released, we proactively evict the image from // our cache if the headers describe the image as having expired at that point. @@ -1494,7 +1507,7 @@ abstract class NetworkImage extends ImageProvider { /// The HTTP headers that will be used with [HttpClient.get] to fetch image from network. /// - /// When running flutter on the web, headers are not used. + /// When running Flutter on the web, headers are not used. Map? get headers; @override diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 4c1ec7321aed6..1e0776cd78047 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart @@ -309,6 +309,16 @@ typedef ImageErrorWidgetBuilder = Widget Function( /// using the HTML renderer, the web engine delegates image decoding of network /// images to the Web, which does not support custom decode sizes. /// +/// ## Custom image providers +/// +/// {@tool dartpad} +/// In this example, a variant of [NetworkImage] is created that passes all the +/// [ImageConfiguration] information (locale, platform, size, etc) to the server +/// using query arguments in the image URL. +/// +/// ** See code in examples/api/lib/painting/image_provider/image_provider.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [Icon], which shows an image from a font. @@ -819,7 +829,7 @@ class Image extends StatefulWidget { /// {@end-tool} final ImageErrorWidgetBuilder? errorBuilder; - /// If non-null, require the image to have this width. + /// If non-null, require the image to have this width (in logical pixels). /// /// If null, the image will pick a size that best preserves its intrinsic /// aspect ratio. @@ -831,7 +841,7 @@ class Image extends StatefulWidget { /// and height if the exact image dimensions are not known in advance. final double? width; - /// If non-null, require the image to have this height. + /// If non-null, require the image to have this height (in logical pixels). /// /// If null, the image will pick a size that best preserves its intrinsic /// aspect ratio. diff --git a/packages/flutter_test/lib/src/_binding_io.dart b/packages/flutter_test/lib/src/_binding_io.dart index 710823682ffae..2123956cef468 100644 --- a/packages/flutter_test/lib/src/_binding_io.dart +++ b/packages/flutter_test/lib/src/_binding_io.dart @@ -71,17 +71,21 @@ void mockFlutterAssets() { class _MockHttpOverrides extends HttpOverrides { bool warningPrinted = false; @override - HttpClient createHttpClient(SecurityContext? _) { + HttpClient createHttpClient(SecurityContext? context) { if (!warningPrinted) { test_package.printOnFailure( - 'Warning: At least one test in this suite creates an HttpClient. When\n' - 'running a test suite that uses TestWidgetsFlutterBinding, all HTTP\n' - 'requests will return status code 400, and no network request will\n' - 'actually be made. Any test expecting a real network connection and\n' + 'Warning: At least one test in this suite creates an HttpClient. When ' + 'running a test suite that uses TestWidgetsFlutterBinding, all HTTP ' + 'requests will return status code 400, and no network request will ' + 'actually be made. Any test expecting a real network connection and ' 'status code will fail.\n' - 'To test code that needs an HttpClient, provide your own HttpClient\n' - 'implementation to the code under test, so that your test can\n' - 'consistently provide a testable response to the code under test.'); + 'To test code that needs an HttpClient, provide your own HttpClient ' + 'implementation to the code under test, so that your test can ' + 'consistently provide a testable response to the code under test.' + .split('\n') + .expand((String line) => debugWordWrap(line, FlutterError.wrapWidth)) + .join('\n'), + ); warningPrinted = true; } return _MockHttpClient(); From 118c2df7764dbac21268ad7d6239de9a0ccefd7d Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 9 Aug 2023 16:26:05 -0700 Subject: [PATCH 0626/1547] Allows adding a storage 'realm' to the storage base URL (#131951) Context: https://github.com/flutter/flutter/issues/131862 This PR injects a "realm" component to the storage base URL when the contents of the file `bin/internal/engine.realm` is non-empty. As documented in the PR, when the realm is `flutter_archives_v2`, and `bin/internal/engine.version` contains the commit hash for a commit in a `flutter/engine` PR, then the artifacts pulled by the tool will be the artifacts built by the presubmit checks for the PR. This works for everything but the following two cases: 1. Fuchsia artifacts are not uploaded to CIPD by the Fuchsia presubmit builds. 2. Web artifacts are not uploaded to gstatic by the web engine presubmit builds. For (1), the flutter/flutter presubmit `fuchsia_precache` is driven by a shell script outside of the repo. It will fail when the `engine.version` and `engine.realm` don't point to a post-submit engine commit. For (2), the flutter/flutter web presubmit tests that refer to artifacts in gstatic hang when the artifacts aren't found, so this PR skips them. --- bin/internal/engine.realm | 0 bin/internal/update_dart_sdk.ps1 | 4 ++ bin/internal/update_dart_sdk.sh | 3 +- dev/bots/test.dart | 5 +++ dev/conductor/core/lib/src/codesign.dart | 10 ++++- .../tasks/engine_dependency_proxy_test.dart | 44 ++++++++++++------- dev/tools/java_and_objc_doc.dart | 8 +++- .../gradle/aar_init_script.gradle | 9 +++- .../gradle/resolve_dependencies.gradle | 8 +++- .../gradle/src/main/groovy/flutter.groovy | 34 ++++++++------ packages/flutter_tools/lib/src/cache.dart | 40 ++++++++++++++++- .../flutter_tools/lib/src/flutter_cache.dart | 6 ++- .../test/general.shard/cache_test.dart | 31 +++++++++++++ 13 files changed, 163 insertions(+), 39 deletions(-) create mode 100644 bin/internal/engine.realm diff --git a/bin/internal/engine.realm b/bin/internal/engine.realm new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index f4e2e77a55886..6af62a54f73b7 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -20,6 +20,7 @@ $cachePath = "$flutterRoot\bin\cache" $dartSdkPath = "$cachePath\dart-sdk" $engineStamp = "$cachePath\engine-dart-sdk.stamp" $engineVersion = (Get-Content "$flutterRoot\bin\internal\engine.version") +$engineRealm = (Get-Content "$flutterRoot\bin\internal\engine.realm") $oldDartSdkPrefix = "dart-sdk.old" @@ -42,6 +43,9 @@ $dartSdkBaseUrl = $Env:FLUTTER_STORAGE_BASE_URL if (-not $dartSdkBaseUrl) { $dartSdkBaseUrl = "https://storage.googleapis.com" } +if ($engineRealm) { + $dartSdkBaseUrl = "$dartSdkBaseUrl/$engineRealm" +} $dartZipName = "dart-sdk-windows-x64.zip" $dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName" diff --git a/bin/internal/update_dart_sdk.sh b/bin/internal/update_dart_sdk.sh index 0f1a238048886..8aed2f47861d7 100755 --- a/bin/internal/update_dart_sdk.sh +++ b/bin/internal/update_dart_sdk.sh @@ -20,6 +20,7 @@ DART_SDK_PATH="$FLUTTER_ROOT/bin/cache/dart-sdk" DART_SDK_PATH_OLD="$DART_SDK_PATH.old" ENGINE_STAMP="$FLUTTER_ROOT/bin/cache/engine-dart-sdk.stamp" ENGINE_VERSION=`cat "$FLUTTER_ROOT/bin/internal/engine.version"` +ENGINE_REALM=`cat "$FLUTTER_ROOT/bin/internal/engine.realm"` OS="$(uname -s)" if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; then @@ -121,7 +122,7 @@ if [ ! -f "$ENGINE_STAMP" ] || [ "$ENGINE_VERSION" != `cat "$ENGINE_STAMP"` ]; t FIND=find fi - DART_SDK_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.googleapis.com}" + DART_SDK_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.googleapis.com}${ENGINE_REALM:+/$ENGINE_REALM}" DART_SDK_URL="$DART_SDK_BASE_URL/flutter_infra_release/flutter/$ENGINE_VERSION/$DART_ZIP_NAME" # if the sdk path exists, copy it to a temporary location diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 26fa9c6cdbc55..2b48df03287e4 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -83,6 +83,7 @@ final String flutter = path.join(flutterRoot, 'bin', 'flutter$bat'); final String dart = path.join(flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', 'dart$exe'); final String pubCache = path.join(flutterRoot, '.pub-cache'); final String engineVersionFile = path.join(flutterRoot, 'bin', 'internal', 'engine.version'); +final String engineRealmFile = path.join(flutterRoot, 'bin', 'internal', 'engine.realm'); final String flutterPackagesVersionFile = path.join(flutterRoot, 'bin', 'internal', 'flutter_packages.version'); String get platformFolderName { @@ -1138,6 +1139,10 @@ Future _runWebUnitTests(String webRenderer) async { /// Coarse-grained integration tests running on the Web. Future _runWebLongRunningTests() async { final String engineVersion = File(engineVersionFile).readAsStringSync().trim(); + final String engineRealm = File(engineRealmFile).readAsStringSync().trim(); + if (engineRealm.isNotEmpty) { + return; + } final List tests = [ for (final String buildMode in _kAllBuildModes) ...[ () => _runFlutterDriverWebTest( diff --git a/dev/conductor/core/lib/src/codesign.dart b/dev/conductor/core/lib/src/codesign.dart index c5cf2038a6c6c..5691aefe07ea7 100644 --- a/dev/conductor/core/lib/src/codesign.dart +++ b/dev/conductor/core/lib/src/codesign.dart @@ -125,7 +125,15 @@ class CodesignCommand extends Command { await framework.checkout(revision); // Ensure artifacts present - await framework.runFlutter(['precache', '--android', '--ios', '--macos']); + final io.ProcessResult result = await framework.runFlutter( + ['precache', '--android', '--ios', '--macos'], + ); + if (result.exitCode != 0) { + stdio.printError( + 'flutter precache: exitCode: ${result.exitCode}\n' + 'stdout:\n${result.stdout}\nstderr:\n${result.stderr}', + ); + } await verifyExist(); if (argResults![kSignatures] as bool) { diff --git a/dev/devicelab/bin/tasks/engine_dependency_proxy_test.dart b/dev/devicelab/bin/tasks/engine_dependency_proxy_test.dart index 43cad17440688..9443a29bb257a 100644 --- a/dev/devicelab/bin/tasks/engine_dependency_proxy_test.dart +++ b/dev/devicelab/bin/tasks/engine_dependency_proxy_test.dart @@ -30,7 +30,8 @@ Future main() async { await inDirectory(path.join(flutterProject.rootPath, 'android'), () async { section('Insert gradle testing script'); final File build = File(path.join( - flutterProject.rootPath, 'android', 'app', 'build.gradle')); + flutterProject.rootPath, 'android', 'app', 'build.gradle', + )); build.writeAsStringSync( ''' task printEngineMavenUrl() { @@ -44,6 +45,7 @@ task printEngineMavenUrl() { ); section('Checking default maven URL'); + String gradleOutput = await eval( gradlewExecutable, ['printEngineMavenUrl', '-q'], @@ -53,29 +55,39 @@ task printEngineMavenUrl() { String mavenUrl = outputLines.last; print('Returned maven url: $mavenUrl'); - if (mavenUrl != 'https://storage.googleapis.com/download.flutter.io') { - throw TaskResult.failure('Expected Android engine maven dependency URL to ' - 'resolve to https://storage.googleapis.com/download.flutter.io. Got ' - '$mavenUrl instead'); + String realm = File( + path.join(flutterDirectory.path, 'bin', 'internal', 'engine.realm'), + ).readAsStringSync().trim(); + if (realm.isNotEmpty) { + realm = '$realm/'; + } + + if (mavenUrl != 'https://storage.googleapis.com/${realm}download.flutter.io') { + throw TaskResult.failure( + 'Expected Android engine maven dependency URL to ' + 'resolve to https://storage.googleapis.com/${realm}download.flutter.io. Got ' + '$mavenUrl instead', + ); } section('Checking overridden maven URL'); gradleOutput = await eval( - gradlewExecutable, - ['printEngineMavenUrl','-q'], - environment: { - 'FLUTTER_STORAGE_BASE_URL': 'https://my.special.proxy', - } - ); + gradlewExecutable, + ['printEngineMavenUrl','-q'], + environment: { + 'FLUTTER_STORAGE_BASE_URL': 'https://my.special.proxy', + }, + ); outputLines = splitter.convert(gradleOutput); mavenUrl = outputLines.last; - if (mavenUrl != 'https://my.special.proxy/download.flutter.io') { + if (mavenUrl != 'https://my.special.proxy/${realm}download.flutter.io') { throw TaskResult.failure( - 'Expected overridden Android engine maven ' - 'dependency URL to resolve to proxy location ' - 'https://my.special.proxy/download.flutter.io. Got ' - '$mavenUrl instead'); + 'Expected overridden Android engine maven ' + 'dependency URL to resolve to proxy location ' + 'https://my.special.proxy/${realm}download.flutter.io. Got ' + '$mavenUrl instead', + ); } }); }); diff --git a/dev/tools/java_and_objc_doc.dart b/dev/tools/java_and_objc_doc.dart index af8b745baadbe..260cdc7b6094f 100644 --- a/dev/tools/java_and_objc_doc.dart +++ b/dev/tools/java_and_objc_doc.dart @@ -15,11 +15,15 @@ const String kDocRoot = 'dev/docs/doc'; /// the artifact store and extracts them to the location used for Dartdoc. Future main(List args) async { final String engineVersion = File('bin/internal/engine.version').readAsStringSync().trim(); + String engineRealm = File('bin/internal/engine.realm').readAsStringSync().trim(); + if (engineRealm.isNotEmpty) { + engineRealm = '$engineRealm/'; + } - final String javadocUrl = 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineVersion/android-javadoc.zip'; + final String javadocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/android-javadoc.zip'; generateDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html'); - final String objcdocUrl = 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip'; + final String objcdocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip'; generateDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html'); } diff --git a/packages/flutter_tools/gradle/aar_init_script.gradle b/packages/flutter_tools/gradle/aar_init_script.gradle index 07f8f552993f7..e6fa84cc17fd8 100644 --- a/packages/flutter_tools/gradle/aar_init_script.gradle +++ b/packages/flutter_tools/gradle/aar_init_script.gradle @@ -45,11 +45,18 @@ void configureProject(Project project, String outputDir) { } String storageUrl = System.getenv('FLUTTER_STORAGE_BASE_URL') ?: "https://storage.googleapis.com" + + String engineRealm = Paths.get(getFlutterRoot(project), "bin", "internal", "engine.realm") + .toFile().text.trim() + if (engineRealm) { + engineRealm = engineRealm + "/" + } + // This is a Flutter plugin project. Plugin projects don't apply the Flutter Gradle plugin, // as a result, add the dependency on the embedding. project.repositories { maven { - url "$storageUrl/download.flutter.io" + url "$storageUrl/${engineRealm}download.flutter.io" } } String engineVersion = Paths.get(getFlutterRoot(project), "bin", "internal", "engine.version") diff --git a/packages/flutter_tools/gradle/resolve_dependencies.gradle b/packages/flutter_tools/gradle/resolve_dependencies.gradle index 817b730613141..6355654f2edfb 100644 --- a/packages/flutter_tools/gradle/resolve_dependencies.gradle +++ b/packages/flutter_tools/gradle/resolve_dependencies.gradle @@ -16,11 +16,17 @@ import java.nio.file.Paths String storageUrl = System.getenv('FLUTTER_STORAGE_BASE_URL') ?: "https://storage.googleapis.com" +String engineRealm = Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.realm") + .toFile().text.trim() +if (engineRealm) { + engineRealm = engineRealm + "/" +} + repositories { google() mavenCentral() maven { - url "$storageUrl/download.flutter.io" + url "$storageUrl/${engineRealm}download.flutter.io" } } diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index c0102b4ff2199..95a750e6ef9e1 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -167,6 +167,7 @@ class FlutterPlugin implements Plugin { private String localEngineSrcPath private Properties localProperties private String engineVersion + private String engineRealm /** * Flutter Docs Website URLs for help messages. @@ -192,11 +193,29 @@ class FlutterPlugin implements Plugin { } } + String flutterRootPath = resolveProperty("flutter.sdk", System.env.FLUTTER_ROOT) + if (flutterRootPath == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable.") + } + flutterRoot = project.file(flutterRootPath) + if (!flutterRoot.isDirectory()) { + throw new GradleException("flutter.sdk must point to the Flutter SDK directory") + } + + engineVersion = useLocalEngine() + ? "+" // Match any version since there's only one. + : "1.0.0-" + Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.version").toFile().text.trim() + + engineRealm = Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.realm").toFile().text.trim() + if (engineRealm) { + engineRealm = engineRealm + "/" + } + // Configure the Maven repository. String hostedRepository = System.env.FLUTTER_STORAGE_BASE_URL ?: DEFAULT_MAVEN_HOST String repository = useLocalEngine() ? project.property('local-engine-repo') - : "$hostedRepository/download.flutter.io" + : "$hostedRepository/${engineRealm}download.flutter.io" rootProject.allprojects { repositories { maven { @@ -246,19 +265,6 @@ class FlutterPlugin implements Plugin { } } - String flutterRootPath = resolveProperty("flutter.sdk", System.env.FLUTTER_ROOT) - if (flutterRootPath == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable.") - } - flutterRoot = project.file(flutterRootPath) - if (!flutterRoot.isDirectory()) { - throw new GradleException("flutter.sdk must point to the Flutter SDK directory") - } - - engineVersion = useLocalEngine() - ? "+" // Match any version since there's only one. - : "1.0.0-" + Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.version").toFile().text.trim() - String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter" flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile(); diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 13efbde879dde..7cfa8ce22fec2 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -190,6 +190,7 @@ class Cache { httpClient: HttpClient(), allowedBaseUrls: [ storageBaseUrl, + realmlessStorageBaseUrl, cipdBaseUrl, ], ); @@ -447,6 +448,22 @@ class Cache { } String? _engineRevision; + /// The "realm" for the storage URL. + /// + /// For production artifacts from Engine post-submit and release builds, + /// this string will be empty, and the `storageBaseUrl` will be unmodified. + /// When non-empty, this string will be appended to the `storageBaseUrl` after + /// a '/'. For artifacts generated by Engine presubmits, the realm should be + /// "flutter_archives_v2". + String get storageRealm { + _storageRealm ??= getRealmFor('engine'); + if (_storageRealm == null) { + throwToolExit('Could not determine engine realm.'); + } + return _storageRealm!; + } + String? _storageRealm; + /// The base for URLs that store Flutter engine artifacts that are fetched /// during the installation of the Flutter SDK. /// @@ -459,11 +476,14 @@ class Cache { /// * [cipdBaseUrl], which determines how CIPD artifacts are fetched. /// * [Cache] class-level dartdocs that explain how artifact mirrors work. String get storageBaseUrl { - final String? overrideUrl = _platform.environment[kFlutterStorageBaseUrl]; + String? overrideUrl = _platform.environment[kFlutterStorageBaseUrl]; if (overrideUrl == null) { - return 'https://storage.googleapis.com'; + return storageRealm.isEmpty + ? 'https://storage.googleapis.com' + : 'https://storage.googleapis.com/$storageRealm'; } // verify that this is a valid URI. + overrideUrl = storageRealm.isEmpty ? overrideUrl : '$overrideUrl/$storageRealm'; try { Uri.parse(overrideUrl); } on FormatException catch (err) { @@ -473,6 +493,12 @@ class Cache { return overrideUrl; } + String get realmlessStorageBaseUrl { + return storageRealm.isEmpty + ? storageBaseUrl + : storageBaseUrl.replaceAll('/$storageRealm', ''); + } + /// The base for URLs that store Flutter engine artifacts in CIPD. /// /// For some platforms, such as Web and Fuchsia, CIPD artifacts are fetched @@ -607,6 +633,16 @@ class Cache { return versionFile.existsSync() ? versionFile.readAsStringSync().trim() : null; } + String? getRealmFor(String artifactName) { + final File realmFile = _fileSystem.file(_fileSystem.path.join( + _rootOverride?.path ?? flutterRoot!, + 'bin', + 'internal', + '$artifactName.realm', + )); + return realmFile.existsSync() ? realmFile.readAsStringSync().trim() : ''; + } + /// Delete all stamp files maintained by the cache. void clearStampFiles() { try { diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart index 252021cf78e89..dcba2c6da5443 100644 --- a/packages/flutter_tools/lib/src/flutter_cache.dart +++ b/packages/flutter_tools/lib/src/flutter_cache.dart @@ -836,7 +836,11 @@ class IosUsbArtifacts extends CachedArtifact { } @visibleForTesting - Uri get archiveUri => Uri.parse('${cache.storageBaseUrl}/flutter_infra_release/ios-usb-dependencies${cache.useUnsignedMacBinaries ? '/unsigned' : ''}/$name/$version/$name.zip'); + Uri get archiveUri => Uri.parse( + '${cache.realmlessStorageBaseUrl}/flutter_infra_release/' + 'ios-usb-dependencies${cache.useUnsignedMacBinaries ? '/unsigned' : ''}' + '/$name/$version/$name.zip', + ); } // TODO(zanderso): upload debug desktop artifacts to host-debug and diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index da9f6e10c8a9e..f5b7b6a6454bb 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -334,6 +334,37 @@ void main() { expect(logger.warningText, contains('Flutter assets will be downloaded from $baseUrl')); expect(logger.statusText, isEmpty); }); + + testWithoutContext('a non-empty realm is included in the storage url', () async { + final MemoryFileSystem fileSystem = MemoryFileSystem.test(); + final Directory internalDir = fileSystem.currentDirectory + .childDirectory('cache') + .childDirectory('bin') + .childDirectory('internal'); + final File engineVersionFile = internalDir.childFile('engine.version'); + engineVersionFile.createSync(recursive: true); + engineVersionFile.writeAsStringSync('abcdef'); + + final File engineRealmFile = internalDir.childFile('engine.realm'); + engineRealmFile.createSync(recursive: true); + engineRealmFile.writeAsStringSync('flutter_archives_v2'); + + final Cache cache = Cache.test( + processManager: FakeProcessManager.any(), + fileSystem: fileSystem, + ); + + expect(cache.storageBaseUrl, contains('flutter_archives_v2')); + }); + + test('bin/internal/engine.realm is empty', () async { + final FileSystem fileSystem = globals.fs; + final String realmFilePath = fileSystem.path.join( + getFlutterRoot(), 'bin', 'internal', 'engine.realm'); + final String realm = fileSystem.file(realmFilePath).readAsStringSync().trim(); + expect(realm, isEmpty, + reason: 'The checked-in engine.realm file must be empty.'); + }); }); testWithoutContext('flattenNameSubdirs', () { From 3f831b694ff30a17ef77d900ff719a6da40c1455 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:30:52 -0700 Subject: [PATCH 0627/1547] Making TextPainter rounding hack disabled by default (#132094) Migrate tests in flutter/flutter. Once the tests here and in `*_customer_testing` are migrated, the default value of the migration flag will be changed from false to true, making the rounding hack disabled by default. --- dev/bots/test.dart | 8 +- .../flutter_gallery/test/drawer_test.dart | 2 +- .../floating_action_button.1_test.dart | 2 +- .../menu_accelerator_label.0_test.dart | 2 +- .../lib/src/painting/text_painter.dart | 8 +- .../flutter/test/cupertino/dialog_test.dart | 8 +- .../cupertino/nav_bar_transition_test.dart | 144 ++++---- .../flutter/test/material/about_test.dart | 10 +- .../test/material/action_chip_test.dart | 10 +- .../flutter/test/material/app_bar_test.dart | 19 +- .../flutter/test/material/badge_test.dart | 27 +- .../flutter/test/material/banner_test.dart | 4 +- packages/flutter/test/material/chip_test.dart | 2 +- .../test/material/choice_chip_test.dart | 10 +- .../test/material/date_picker_test.dart | 30 +- .../test/material/date_range_picker_test.dart | 21 +- .../test/material/dialog_theme_test.dart | 5 +- .../test/material/dropdown_menu_test.dart | 33 +- .../flutter/test/material/dropdown_test.dart | 6 +- .../test/material/filter_chip_test.dart | 10 +- .../material/flexible_space_bar_test.dart | 10 +- .../test/material/input_decorator_test.dart | 5 +- .../flutter/test/material/list_tile_test.dart | 30 +- .../test/material/navigation_bar_test.dart | 14 +- .../test/material/navigation_rail_test.dart | 340 ++++++++++-------- .../test/material/outlined_button_test.dart | 7 +- .../flutter/test/material/snack_bar_test.dart | 8 +- .../flutter/test/material/stepper_test.dart | 24 +- .../test/material/tab_bar_theme_test.dart | 6 +- packages/flutter/test/material/tabs_test.dart | 66 ++-- .../test/material/text_button_test.dart | 10 +- .../test/material/time_picker_test.dart | 29 +- .../test/painting/text_painter_test.dart | 3 - .../flutter_localizations/test/text_test.dart | 44 +-- 34 files changed, 486 insertions(+), 471 deletions(-) diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 2b48df03287e4..fd91ada4f66b3 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -102,7 +102,7 @@ final String flutterTester = path.join(flutterRoot, 'bin', 'cache', 'artifacts', /// The arguments to pass to `flutter test` (typically the local engine /// configuration) -- prefilled with the arguments passed to test.dart. -final List flutterTestArgs = []; +final List flutterTestArgs = ['--dart-define=SKPARAGRAPH_REMOVE_ROUNDING_HACK=true']; /// Environment variables to override the local engine when running `pub test`, /// if such flags are provided to `test.dart`. @@ -1309,8 +1309,8 @@ Future _runFlutterDriverWebTest({ await runCommand( flutter, [ - ...flutterTestArgs, 'drive', + ...flutterTestArgs, if (driver != null) '--driver=$driver', '--target=$target', '--browser-name=chrome', @@ -1584,8 +1584,8 @@ Future _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false }) await runCommand( flutter, [ - ...flutterTestArgs, 'drive', + ...flutterTestArgs, if (canvasKit) '--dart-define=FLUTTER_WEB_USE_SKIA=true', if (!canvasKit) @@ -1665,10 +1665,10 @@ Future _runWebReleaseTest(String target, { await runCommand( flutter, [ - ...flutterTestArgs, 'build', 'web', '--release', + ...flutterTestArgs, ...additionalArguments, '-t', target, diff --git a/dev/integration_tests/flutter_gallery/test/drawer_test.dart b/dev/integration_tests/flutter_gallery/test/drawer_test.dart index 3dc6e93675ab5..2341180fb64c3 100644 --- a/dev/integration_tests/flutter_gallery/test/drawer_test.dart +++ b/dev/integration_tests/flutter_gallery/test/drawer_test.dart @@ -105,7 +105,7 @@ void main() { await tester.tap(find.text('Small')); await tester.pumpAndSettle(); Size textSize = tester.getSize(find.text('Text size')); - expect(textSize, equals(const Size(116.0, 13.0))); + expect(textSize, equals(within(distance: 0.05, from: const Size(115.2, 13.0)))); // Set font scale back to the default. await tester.tap(find.byIcon(Icons.arrow_drop_down).at(1)); diff --git a/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart b/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart index eb6ba0e8e7c0c..d618defc169a3 100644 --- a/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart +++ b/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart @@ -42,7 +42,7 @@ void main() { final Finder extendedFABMaterialButton = find.byType(RawMaterialButton).at(3); final RenderBox extendedFABRenderBox = tester.renderObject(extendedFABMaterialButton); - expect(extendedFABRenderBox.size, const Size(111.0, 56.0)); + expect(extendedFABRenderBox.size, within(distance: 0.01, from: const Size(110.3, 56.0))); expect(getRawMaterialButtonWidget(extendedFABMaterialButton).fillColor, theme.colorScheme.primaryContainer); expect(getRawMaterialButtonWidget(extendedFABMaterialButton).shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.0))); }); diff --git a/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart b/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart index 0268dcab84ee0..9cf332dd6966a 100644 --- a/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart @@ -29,7 +29,7 @@ void main() { expect(find.text('About', findRichText: true), findsOneWidget); expect( tester.getRect(findMenu('About')), - equals(const Rect.fromLTRB(4.0, 48.0, 111.0, 208.0)), + equals(const Rect.fromLTRB(4.0, 48.0, 110.5, 208.0)), ); expect(find.text('Save', findRichText: true), findsOneWidget); expect(find.text('Quit', findRichText: true), findsOneWidget); diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 07a26d79e3bae..210b93d3ba4e5 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -513,7 +513,13 @@ class TextPainter { _locale = locale, _strutStyle = strutStyle, _textWidthBasis = textWidthBasis, - _textHeightBehavior = textHeightBehavior; + _textHeightBehavior = textHeightBehavior, + assert(() { + if (const bool.fromEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')) { + ui.ParagraphBuilder.setDisableRoundingHack(true); + } + return true; + }()); /// Computes the width of a configured [TextPainter]. /// diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart index 388c1097ec55f..7ae06059ca5dd 100644 --- a/packages/flutter/test/cupertino/dialog_test.dart +++ b/packages/flutter/test/cupertino/dialog_test.dart @@ -344,11 +344,9 @@ void main() { // regular font. However, when using the test font, "Cancel" becomes 2 lines which // is why the height we're verifying for "Cancel" is larger than "OK". - // TODO(yjbanov): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - expect(tester.getSize(find.text('The Title')), equals(const Size(270.0, hasIssue99933 ? 133 : 132.0))); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(tester.getSize(find.text('The Title')), equals(const Size(270.0, 132.0))); + } expect(tester.getTopLeft(find.text('The Title')), equals(const Offset(265.0, 80.0 + 24.0))); expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Cancel')), equals(const Size(310.0, 148.0))); expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'OK')), equals(const Size(310.0, 98.0))); diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index abfbf7bc31f1b..662fcb5300c6c 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -145,15 +145,15 @@ void main() { // place. expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, + const Offset( + 342.547737105096302912, 13.5, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, + const Offset( + 342.547737105096302912, 13.5, ), ); @@ -172,15 +172,15 @@ void main() { // Same as LTR but more to the right now. expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, + const Offset( + 357.912261979376353338, 13.5, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, + const Offset( + 357.912261979376353338, 13.5, ), ); @@ -371,8 +371,8 @@ void main() { expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, + const Offset( + 342.547737105096302912, 13.5, ), ); @@ -384,8 +384,8 @@ void main() { expect(topBackLabel.text.style!.color, const Color(0xff000306)); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 342.547737105096302912 : 342.33420100808144, + const Offset( + 342.547737105096302912, 13.5, ), ); @@ -422,8 +422,8 @@ void main() { expect(bottomMiddle.text.style!.color, const Color(0xff000306)); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, + const Offset( + 357.912261979376353338, 13.5, ), ); @@ -435,8 +435,8 @@ void main() { expect(topBackLabel.text.style!.color, const Color(0xff000306)); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 357.912261979376353338 : 357.66579899191856, + const Offset( + 357.912261979376353338, 13.5, ), ); @@ -736,15 +736,15 @@ void main() { ); // Come in from the right and fade in. checkOpacity(tester, backChevron, 0.0); - expect(tester.getTopLeft(backChevron), Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 87.2460581221158690823 : 88.04496401548386, + expect(tester.getTopLeft(backChevron), const Offset( + 87.2460581221158690823, 7.0, )); await tester.pump(const Duration(milliseconds: 200)); checkOpacity(tester, backChevron, 0.09497911669313908); - expect(tester.getTopLeft(backChevron), Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 30.8718595298545324113 : 31.055883467197418, + expect(tester.getTopLeft(backChevron), const Offset( + 30.8718595298545324113, 7.0, )); }); @@ -784,8 +784,8 @@ void main() { checkOpacity(tester, backChevron, 0.0); expect( tester.getTopRight(backChevron), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 687.163941725296126606 : 685.9550359845161, + const Offset( + 687.163941725296126606, 7.0, ), ); @@ -794,8 +794,8 @@ void main() { checkOpacity(tester, backChevron, 0.09497911669313908); expect( tester.getTopRight(backChevron), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 743.538140317557690651 : 742.9441165328026, + const Offset( + 743.538140317557690651, 7.0, ), ); @@ -899,8 +899,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('custom')), 0.9280824661254883); expect( tester.getTopLeft(flying(tester, find.text('custom'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 684.459999084472656250 : 684.0, + const Offset( + 684.459999084472656250, 13.5, ), ); @@ -909,8 +909,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('custom')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('custom'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 684.459999084472656250 : 684.0, + const Offset( + 684.459999084472656250, 13.5, ), ); @@ -941,8 +941,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 1')), 0.7952219992876053); expect( tester.getTopLeft(flying(tester, find.text('Page 1'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 41.3003370761871337891 : 41.71033692359924, + const Offset( + 41.3003370761871337891, 13.5, ), ); @@ -951,8 +951,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 1')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('Page 1'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? -258.642192125320434570 : -258.2321922779083, + const Offset( + -258.642192125320434570, 13.5, ), ); @@ -984,8 +984,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 1')), 0.7952219992876053); expect( tester.getTopRight(flying(tester, find.text('Page 1'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 758.699662923812866211 : 758.2896630764008, + const Offset( + 758.699662923812866211, 13.5, ), ); @@ -995,8 +995,8 @@ void main() { expect( tester.getTopRight(flying(tester, find.text('Page 1'))), // >1000. It's now off the screen. - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 1058.64219212532043457 : 1058.2321922779083, + const Offset( + 1058.64219212532043457, 13.5, ), ); @@ -1021,15 +1021,15 @@ void main() { expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, + const Offset( + 16.9155227761479522997, 52.73951627314091, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, + const Offset( + 16.9155227761479522997, 52.73951627314091, ), ); @@ -1040,15 +1040,15 @@ void main() { expect( tester.getTopLeft(flying(tester, find.text('Page 1')).first), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, + const Offset( + 43.6029094262710827934, 22.49655644595623, ), ); expect( tester.getTopLeft(flying(tester, find.text('Page 1')).last), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, + const Offset( + 43.6029094262710827934, 22.49655644595623, ), ); @@ -1072,15 +1072,15 @@ void main() { checkOpacity(tester, flying(tester, find.text('Back')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('A title too long to fit'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, + const Offset( + 16.9155227761479522997, 52.73951627314091, ), ); expect( tester.getTopLeft(flying(tester, find.text('Back'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 16.9155227761479522997 : 16.926069676876068, + const Offset( + 16.9155227761479522997, 52.73951627314091, ), ); @@ -1090,15 +1090,15 @@ void main() { checkOpacity(tester, flying(tester, find.text('Back')), 0.4604858811944723); expect( tester.getTopLeft(flying(tester, find.text('A title too long to fit'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, + const Offset( + 43.6029094262710827934, 22.49655644595623, ), ); expect( tester.getTopLeft(flying(tester, find.text('Back'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 43.6029094262710827934 : 43.92089730501175, + const Offset( + 43.6029094262710827934, 22.49655644595623, ), ); @@ -1156,8 +1156,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.0); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 739.940336465835571289 : 739.7103369235992, + const Offset( + 739.940336465835571289, 13.5, ), ); @@ -1167,8 +1167,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.29867843724787235); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 504.880443334579467773 : 504.65044379234314, + const Offset( + 504.880443334579467773, 13.5, ), ); @@ -1212,8 +1212,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.0); expect( tester.getTopRight(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 60.0596635341644287109 : 60.28966307640076, + const Offset( + 60.0596635341644287109, 13.5, ), ); @@ -1223,8 +1223,8 @@ void main() { checkOpacity(tester, flying(tester, find.text('Page 2')), 0.29867843724787235); expect( tester.getTopRight(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 295.119556665420532227 : 295.34955620765686, + const Offset( + 295.119556665420532227, 13.5, ), ); @@ -1350,8 +1350,8 @@ void main() { // Page 2, which is the middle of the top route, start to fly back to the right. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 353.810205429792404175 : 353.5802058875561, + const Offset( + 353.810205429792404175, 13.5, ), ); @@ -1368,16 +1368,16 @@ void main() { // Transition continues. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 655.435583114624023438 : 655.2055835723877, + const Offset( + 655.435583114624023438, 13.5, ), ); await tester.pump(const Duration(milliseconds: 50)); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 749.863556146621704102 : 749.6335566043854, + const Offset( + 749.863556146621704102, 13.5, ), ); @@ -1421,8 +1421,8 @@ void main() { // Page 2, which is the middle of the top route, start to fly back to the right. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 353.810205429792404175 : 353.5802058875561, + const Offset( + 353.810205429792404175, 13.5, ), ); @@ -1433,16 +1433,16 @@ void main() { // Transition continues from the point we let off. expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 353.810205429792404175 : 353.5802058875561, + const Offset( + 353.810205429792404175, 13.5, ), ); await tester.pump(const Duration(milliseconds: 50)); expect( tester.getTopLeft(flying(tester, find.text('Page 2'))), - Offset( - ParagraphBuilder.shouldDisableRoundingHack ? 350.231143206357955933 : 350.0011436641216, + const Offset( + 350.231143206357955933, 13.5, ), ); diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 7e38905b8dbe1..0199deb48f5c1 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -583,7 +583,7 @@ void main() { tester.getTopLeft(find.text('Licenses')), const Offset(16.0 + safeareaPadding, 14.0 + safeareaPadding), ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('LicensePage returns early if unmounted', (WidgetTester tester) async { final Completer licenseCompleter = Completer(); @@ -1578,7 +1578,9 @@ void main() { // If the layout width is less than 840.0 pixels, nested layout is // used which positions license page title at the top center. Offset titleOffset = tester.getCenter(find.text(title)); - expect(titleOffset, Offset(defaultSize.width / 2, 96.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(titleOffset, Offset(defaultSize.width / 2, 96.0)); + } expect(tester.getCenter(find.byType(ListView)), Offset(defaultSize.width / 2, 328.0)); // Configure a wide window to show the lateral UI. @@ -1708,7 +1710,9 @@ void main() { // If the layout width is less than 840.0 pixels, nested layout is // used which positions license page title at the top center. Offset titleOffset = tester.getCenter(find.text(title)); - expect(titleOffset, Offset(defaultSize.width / 2, 96.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(titleOffset, Offset(defaultSize.width / 2, 96.0)); + } expect(tester.getCenter(find.byType(ListView)), Offset(defaultSize.width / 2, 328.0)); // Configure a wide window to show the lateral UI. diff --git a/packages/flutter/test/material/action_chip_test.dart b/packages/flutter/test/material/action_chip_test.dart index f1fa44830cc63..879c6fb5bd5ae 100644 --- a/packages/flutter/test/material/action_chip_test.dart +++ b/packages/flutter/test/material/action_chip_test.dart @@ -84,7 +84,10 @@ void main() { ); // Test default chip size. - expect(tester.getSize(find.byType(ActionChip)), const Size(190.0, 48.0)); + expect( + tester.getSize(find.byType(ActionChip)), + within(distance: 0.01, from: const Size(189.1, 48.0)), + ); // Test default label style. expect( getLabelStyle(tester, label).style.color!.value, @@ -155,7 +158,10 @@ void main() { ); // Test default chip size. - expect(tester.getSize(find.byType(ActionChip)), const Size(190.0, 48.0)); + expect( + tester.getSize(find.byType(ActionChip)), + within(distance: 0.01, from: const Size(189.1, 48.0)), + ); // Test default label style. expect( getLabelStyle(tester, label).style.color!.value, diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 1d748fc5786b4..af1ee49ad6411 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -1280,7 +1280,9 @@ void main() { // Test the expanded title is positioned correctly. final Offset titleOffset = tester.getBottomLeft(expandedTitle); expect(titleOffset.dx, 16.0); - expect(titleOffset.dy, 96.0); + if (!kIsWeb || isCanvasKit) { + expect(titleOffset.dy, 96.0); + } _verifyTextNotClipped(expandedTitle, tester); @@ -5191,7 +5193,7 @@ void main() { await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0)); expect(tester.getRect(expandedTitle).height, 43.0); _verifyTextNotClipped(expandedTitle, tester); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgets('SliverAppBar.large expanded title has upper limit on text scaling', (WidgetTester tester) async { const String title = 'Large AppBar'; @@ -5221,22 +5223,15 @@ void main() { await tester.pumpWidget(buildAppBar()); - // TODO(tahatesser): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); final Finder expandedTitle = find.text(title).first; - expect( - tester.getRect(expandedTitle).height, - closeTo( hasIssue99933 ? 37.0 : 36.0, 0.1), - ); + expect(tester.getRect(expandedTitle).height, 36.0); await tester.pumpWidget(buildAppBar(textScaleFactor: 2.0)); expect(tester.getRect(expandedTitle).height, closeTo(48.0, 0.1)); await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0)); expect(tester.getRect(expandedTitle).height, closeTo(48.0, 0.1)); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgets('SliverAppBar.medium expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async { const String title = 'Medium AppBar'; @@ -5277,7 +5272,7 @@ void main() { await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0)); expect(tester.getBottomLeft(expandedTitle).dy, 107.0); _verifyTextNotClipped(expandedTitle, tester); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgets('SliverAppBar.large expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async { const String title = 'Large AppBar'; diff --git a/packages/flutter/test/material/badge_test.dart b/packages/flutter/test/material/badge_test.dart index 6fe8c70fb4312..d51adf08bc30a 100644 --- a/packages/flutter/test/material/badge_test.dart +++ b/packages/flutter/test/material/badge_test.dart @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show ParagraphBuilder; - +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -49,12 +48,12 @@ void main() { expect(tester.getSize(find.byType(Badge)), const Size(24, 24)); // default Icon size expect(tester.getTopLeft(find.byType(Badge)), Offset.zero); - expect(tester.getTopLeft(find.text('0')), const Offset(16, -4)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(tester.getTopLeft(find.text('0')), const Offset(16, -4)); + } final RenderBox box = tester.renderObject(find.byType(Badge)); - final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack - ? RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8)) - : RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)); + final RRect rrect = RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8)); expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); }); @@ -91,12 +90,12 @@ void main() { expect(tester.getSize(find.byType(Badge)), const Size(24, 24)); // default Icon size expect(tester.getTopLeft(find.byType(Badge)), Offset.zero); - expect(tester.getTopLeft(find.text('0')), const Offset(0, -4)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(tester.getTopLeft(find.text('0')), const Offset(0, -4)); + } final RenderBox box = tester.renderObject(find.byType(Badge)); - final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack - ? RRect.fromLTRBR(-4, -4, 15.5, 12, const Radius.circular(8)) - : RRect.fromLTRBR(-4, -4, 16, 12, const Radius.circular(8)); + final RRect rrect = RRect.fromLTRBR(-4, -4, 15.5, 12, const Radius.circular(8)); expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); }); @@ -143,7 +142,9 @@ void main() { // x = alignment.start + padding.left // y = alignment.top - expect(tester.getTopLeft(find.text('0')), const Offset(16, -4)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(tester.getTopLeft(find.text('0')), const Offset(16, -4)); + } final RenderBox box = tester.renderObject(find.byType(Badge)); // '0'.width = 12 @@ -151,9 +152,7 @@ void main() { // T = alignment.top // R = L + '0'.width + padding.width // B = T + largeSize, R = largeSize/2 - final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack - ? RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8)) - : RRect.fromLTRBR(12, -4, 32, 12, const Radius.circular(8)); + final RRect rrect = RRect.fromLTRBR(12, -4, 31.5, 12, const Radius.circular(8)); expect(box, paints..rrect(rrect: rrect, color: theme.colorScheme.error)); await tester.pumpWidget(buildFrame(1000)); diff --git a/packages/flutter/test/material/banner_test.dart b/packages/flutter/test/material/banner_test.dart index 58e51ab256f9a..332cab51ed3f4 100644 --- a/packages/flutter/test/material/banner_test.dart +++ b/packages/flutter/test/material/banner_test.dart @@ -600,7 +600,7 @@ void main() { final Offset actionsTopLeft = tester.getTopLeft(find.byType(OverflowBar)); final Offset bannerTopLeft = tester.getTopLeft(find.byType(MaterialBanner)); - expect(actionsTopLeft.dx - 8, bannerTopLeft.dx); // actions OverflowBar is padded by 8 + expect(actionsTopLeft.dx - 8, moreOrLessEquals(bannerTopLeft.dx)); // actions OverflowBar is padded by 8 }); testWidgetsWithLeakTracking('Single action laid out beside content but aligned to the trailing edge when presented by ScaffoldMessenger - RTL', (WidgetTester tester) async { @@ -640,7 +640,7 @@ void main() { final Offset actionsTopLeft = tester.getTopLeft(find.byType(OverflowBar)); final Offset bannerTopLeft = tester.getTopLeft(find.byType(MaterialBanner)); - expect(actionsTopLeft.dx - 8, bannerTopLeft.dx); // actions OverflowBar is padded by 8 + expect(actionsTopLeft.dx - 8, moreOrLessEquals(bannerTopLeft.dx)); // actions OverflowBar is padded by 8 }); testWidgetsWithLeakTracking('Actions laid out below content if forced override', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index a8cba15354e4a..24a5943490d85 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -3499,7 +3499,7 @@ void main() { expect(calledDelete, isFalse); // Tap after end of the label. - await tester.tapAt(Offset(labelCenter.dx + (labelSize.width / 2), labelCenter.dy)); + await tester.tapAt(Offset(labelCenter.dx + (labelSize.width / 2) + 0.01, labelCenter.dy)); await tester.pump(); expect(calledDelete, isTrue); }); diff --git a/packages/flutter/test/material/choice_chip_test.dart b/packages/flutter/test/material/choice_chip_test.dart index fcf584c2ceccd..1fcf539520ada 100644 --- a/packages/flutter/test/material/choice_chip_test.dart +++ b/packages/flutter/test/material/choice_chip_test.dart @@ -85,7 +85,10 @@ void main() { ); // Test default chip size. - expect(tester.getSize(find.byType(ChoiceChip)), const Size(190.0, 48.0)); + expect( + tester.getSize(find.byType(ChoiceChip)), + within(distance: 0.01, from: const Size(189.1, 48.0)), + ); // Test default label style. expect( getLabelStyle(tester, label).style.color!.value, @@ -217,7 +220,10 @@ void main() { ); // Test default chip size. - expect(tester.getSize(find.byType(ChoiceChip)), const Size(190.0, 48.0)); + expect( + tester.getSize(find.byType(ChoiceChip)), + within(distance: 0.01, from: const Size(189.1, 48.0)), + ); // Test default label style. expect( getLabelStyle(tester, label).style.color!.value, diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index e91af3ac65f4b..de670d7131512 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -330,7 +330,7 @@ void main() { // We expect the left edge of the 'OK' button in the RTL // layout to match the gap between right edge of the 'OK' // button and the right edge of the 800 wide view. - expect(tester.getBottomLeft(find.text('OK')).dx, 800 - ltrOkRight); + expect(tester.getBottomLeft(find.text('OK')).dx, moreOrLessEquals(800 - ltrOkRight)); }); group('Barrier dismissible', () { @@ -876,11 +876,9 @@ void main() { final Offset subHeaderTextTopLeft = tester.getTopLeft(subHeaderText); final Offset dividerTopRight = tester.getTopRight(divider); expect(subHeaderTextTopLeft.dx, dividerTopRight.dx + 24.0); - // TODO(tahatesser): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - expect(subHeaderTextTopLeft.dy, dialogTopLeft.dy + 16.0 - (hasIssue99933 ? 0.5 : 0.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(subHeaderTextTopLeft.dy, dialogTopLeft.dy + 16.0); + } // Test sub header icon position. final Finder subHeaderIcon = find.byIcon(Icons.arrow_drop_down); @@ -894,7 +892,9 @@ void main() { final Offset calendarPageViewTopLeft = tester.getTopLeft(calendarPageView); final Offset subHeaderTextBottomLeft = tester.getBottomLeft(subHeaderText); expect(calendarPageViewTopLeft.dx, dividerTopRight.dx); - expect(calendarPageViewTopLeft.dy, subHeaderTextBottomLeft.dy + 16.0 - (hasIssue99933 ? 0.5 : 0.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(calendarPageViewTopLeft.dy, subHeaderTextBottomLeft.dy + 16.0); + } // Test month navigation icons position. final Finder previousMonthButton = find.widgetWithIcon(IconButton, Icons.chevron_left); @@ -954,11 +954,9 @@ void main() { final Offset headerTextTextTopLeft = tester.getTopLeft(headerText); final Offset helpTextBottomLeft = tester.getBottomLeft(helpText); expect(headerTextTextTopLeft.dx, dialogTopLeft.dx + 24.0); - // TODO(tahatesser): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - expect(headerTextTextTopLeft.dy, helpTextBottomLeft.dy + 28.0 - (hasIssue99933 ? 1.0 : 0.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(headerTextTextTopLeft.dy, helpTextBottomLeft.dy + 28.0); + } // Test switch button position. final Finder switchButtonM3 = find.widgetWithIcon(IconButton, Icons.edit_outlined); @@ -978,7 +976,9 @@ void main() { final Offset subHeaderTextTopLeft = tester.getTopLeft(subHeaderText); final Offset dividerBottomLeft = tester.getBottomLeft(divider); expect(subHeaderTextTopLeft.dx, dialogTopLeft.dx + 24.0); - expect(subHeaderTextTopLeft.dy, dividerBottomLeft.dy + 16.0 - (hasIssue99933 ? 0.5 : 0.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(subHeaderTextTopLeft.dy, dividerBottomLeft.dy + 16.0); + } // Test sub header icon position. final Finder subHeaderIcon = find.byIcon(Icons.arrow_drop_down); @@ -1001,7 +1001,9 @@ void main() { final Offset calendarPageViewTopLeft = tester.getTopLeft(calendarPageView); final Offset subHeaderTextBottomLeft = tester.getBottomLeft(subHeaderText); expect(calendarPageViewTopLeft.dx, dialogTopLeft.dx); - expect(calendarPageViewTopLeft.dy, subHeaderTextBottomLeft.dy + 16.0 - (hasIssue99933 ? 0.5 : 0.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(calendarPageViewTopLeft.dy, subHeaderTextBottomLeft.dy + 16.0); + } // Test action buttons position. final Offset dialogBottomRight = tester.getBottomRight(find.byType(AnimatedContainer)); diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index baf135666ab9d..c9e5c544c26a0 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -133,22 +133,21 @@ void main() { final Offset entryButtonBottomLeft = tester.getBottomLeft( find.widgetWithIcon(IconButton, Icons.edit_outlined), ); - expect( - saveButtonBottomLeft.dx, - ParagraphBuilder.shouldDisableRoundingHack ? moreOrLessEquals(711.6, epsilon: 1e-5) : (800 - 89.0), - ); - expect(saveButtonBottomLeft.dy, helpTextTopLeft.dy); + expect(saveButtonBottomLeft.dx, moreOrLessEquals(711.6, epsilon: 1e-5)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(saveButtonBottomLeft.dy, helpTextTopLeft.dy); + } expect(entryButtonBottomLeft.dx, saveButtonBottomLeft.dx - 48.0); - expect(entryButtonBottomLeft.dy, helpTextTopLeft.dy); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(entryButtonBottomLeft.dy, helpTextTopLeft.dy); + } // Test help text position. final Offset helpTextBottomLeft = tester.getBottomLeft(helpText); expect(helpTextBottomLeft.dx, 72.0); - // TODO(tahatesser): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - expect(helpTextBottomLeft.dy, closeButtonBottomRight.dy + 20.0 + (hasIssue99933 ? 1.0 : 0.0)); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(helpTextBottomLeft.dy, closeButtonBottomRight.dy + 20.0); + } // Test the header position. final Offset firstDateHeaderTopLeft = tester.getTopLeft(firstDateHeaderText); diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index 22c78e3a817e4..0d41077d0c87b 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -7,6 +7,7 @@ @Tags(['reduced-test-set']) library; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -186,7 +187,9 @@ void main() { find.descendant(of: find.byType(Dialog), matching: find.byType(Material)), ); expect(bottomLeft.dx, 480.0); - expect(bottomLeft.dy, 124.0); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(bottomLeft.dy, 124.0); + } }); testWidgets('Material2 - Dialog alignment takes priority over theme', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index a721cfdb87a2b..45802fdb91a75 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -5,7 +5,6 @@ import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -146,8 +145,8 @@ void main() { await tester.pumpWidget(buildTest(themeData, menuChildren, width: 200.0)); final Finder anchor = find.byType(TextField); - final Size size = tester.getSize(anchor); - expect(size, const Size(200.0, 56.0)); + final double width = tester.getSize(anchor).width; + expect(width, 200.0); await tester.tap(anchor); await tester.pumpAndSettle(); @@ -156,8 +155,8 @@ void main() { of: find.byType(SingleChildScrollView), matching: find.byType(Material), ); - final Size updatedMenuSize = tester.getSize(updatedMenu); - expect(updatedMenuSize, const Size(200.0, 304.0)); + final double updatedMenuWidth = tester.getSize(updatedMenu).width; + expect(updatedMenuWidth, 200.0); }); testWidgets('Material3 - The width of the text field should always be the same as the menu view', @@ -177,12 +176,8 @@ void main() { ); final Finder textField = find.byType(TextField); - final Size anchorSize = tester.getSize(textField); - if (kIsWeb && !isCanvasKit) { - expect(anchorSize, const Size(195.0, 61.0)); - } else { - expect(anchorSize, const Size(195.0, 60.0)); - } + final double anchorWidth = tester.getSize(textField).width; + expect(anchorWidth, 195.0); await tester.tap(find.byType(DropdownMenu)); await tester.pumpAndSettle(); @@ -191,20 +186,16 @@ void main() { of: find.byType(SingleChildScrollView), matching: find.byType(Material), ); - final Size menuSize = tester.getSize(menuMaterial); - expect(menuSize, const Size(195.0, 304.0)); + final double menuWidth = tester.getSize(menuMaterial).width; + expect(menuWidth, 195.0); // The text field should have same width as the menu // when the width property is not null. await tester.pumpWidget(buildTest(themeData, menuChildren, width: 200.0)); final Finder anchor = find.byType(TextField); - final Size size = tester.getSize(anchor); - if (kIsWeb && !isCanvasKit) { - expect(size, const Size(200.0, 61.0)); - } else { - expect(size, const Size(200.0, 60.0)); - } + final double width = tester.getSize(anchor).width; + expect(width, 200.0); await tester.tap(anchor); await tester.pumpAndSettle(); @@ -213,8 +204,8 @@ void main() { of: find.byType(SingleChildScrollView), matching: find.byType(Material), ); - final Size updatedMenuSize = tester.getSize(updatedMenu); - expect(updatedMenuSize, const Size(200.0, 304.0)); + final double updatedMenuWidth = tester.getSize(updatedMenu).width; + expect(updatedMenuWidth, 200.0); }); testWidgets('The width property can customize the width of the dropdown menu', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart index af49dca265ebe..8db8c6fbdee10 100644 --- a/packages/flutter/test/material/dropdown_test.dart +++ b/packages/flutter/test/material/dropdown_test.dart @@ -3346,7 +3346,7 @@ void main() { // Should be center-center aligned, the icon size is 24.0 pixels. expect( buttonBox.localToGlobal(Offset((buttonBox.size.width -24.0) / 2.0, buttonBox.size.height / 2.0)), - selectedItemBox.localToGlobal(Offset(selectedItemBox.size.width / 2.0, selectedItemBox.size.height / 2.0)), + offsetMoreOrLessEquals(selectedItemBox.localToGlobal(Offset(selectedItemBox.size.width / 2.0, selectedItemBox.size.height / 2.0))), ); // Open dropdown. @@ -3362,10 +3362,10 @@ void main() { Offset(selectedItemBoxInMenu.size.width / 2.0, selectedItemBoxInMenu.size.height / 2.0) ); - expect(center.dx, menuRect.topCenter.dx,); + expect(center.dx, moreOrLessEquals(menuRect.topCenter.dx)); expect( center.dy, - selectedItemBox.localToGlobal(Offset(selectedItemBox.size.width / 2.0, selectedItemBox.size.height / 2.0)).dy, + moreOrLessEquals(selectedItemBox.localToGlobal(Offset(selectedItemBox.size.width / 2.0, selectedItemBox.size.height / 2.0)).dy), ); }); diff --git a/packages/flutter/test/material/filter_chip_test.dart b/packages/flutter/test/material/filter_chip_test.dart index 68a94dd1178b5..30dbbfed3b28a 100644 --- a/packages/flutter/test/material/filter_chip_test.dart +++ b/packages/flutter/test/material/filter_chip_test.dart @@ -135,7 +135,10 @@ void main() { ); // Test default chip size. - expect(tester.getSize(find.byType(FilterChip)), const Size(190.0, 48.0)); + expect( + tester.getSize(find.byType(FilterChip)), + within(distance: 0.001, from: const Size(189.1, 48.0)), + ); // Test default label style. expect( getLabelStyle(tester, label).style.color!.value, @@ -267,7 +270,10 @@ void main() { ); // Test default chip size. - expect(tester.getSize(find.byType(FilterChip)), const Size(190.0, 48.0)); + expect( + tester.getSize(find.byType(FilterChip)), + within(distance: 0.001, from: const Size(189.1, 48.0)), + ); // Test default label style. expect( getLabelStyle(tester, 'filter chip').style.color!.value, diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index b20624e04bb06..4f37ab2db26d8 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -7,8 +7,6 @@ @Tags(['reduced-test-set']) library; -import 'dart:ui' as ui show ParagraphBuilder; - import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -473,9 +471,7 @@ void main() { ), ); - final double textWidth = ui.ParagraphBuilder.shouldDisableRoundingHack - ? width - : (width / 1.5).floorToDouble() * 1.5; + final double textWidth = width; // The title is scaled and transformed to be 1.5 times bigger, when the // FlexibleSpaceBar is fully expanded, thus we expect the width to be // 1.5 times smaller than the full width. The height of the text is the same @@ -544,9 +540,7 @@ void main() { // bottom edge. const double bottomMargin = titleFontSize * (expandedTitleScale - 1); - final double textWidth = ui.ParagraphBuilder.shouldDisableRoundingHack - ? collapsedWidth - : (collapsedWidth / 3).floorToDouble() * 3; + final double textWidth = collapsedWidth; // The title is scaled and transformed to be 3 times bigger, when the // FlexibleSpaceBar is fully expanded, thus we expect the width to be // 3 times smaller than the full width. The height of the text is the same diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 28b44c614ea07..8647713698eee 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -5930,10 +5930,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular } final Rect clipRect = arguments[0] as Rect; // _kFinalLabelScale = 0.75 - final double width = ParagraphBuilder.shouldDisableRoundingHack - ? 100 / 0.75 - : 133.0; - expect(clipRect, rectMoreOrLessEquals(Rect.fromLTWH(0, 0, width, 16.0), epsilon: 1e-5)); + expect(clipRect, rectMoreOrLessEquals(const Rect.fromLTWH(0, 0, 100 / 0.75, 16.0), epsilon: 1e-5)); return true; }), ); diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index 962e31854cdfe..c80d641bd630e 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -156,22 +156,24 @@ void main() { await tester.pumpWidget(buildFrame(isTwoLine: true, textScaleFactor: 4.0)); testChildren(); testHorizontalGeometry(); - // TODO(tahatesser): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - testVerticalGeometry(hasIssue99933 ? 193 : 192.0); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + testVerticalGeometry(192.0); + } // Make sure that the height of a large subtitle is taken into account. await tester.pumpWidget(buildFrame(isTwoLine: true, textScaleFactor: 0.5, subtitleScaleFactor: 4.0)); testChildren(); testHorizontalGeometry(); - testVerticalGeometry(hasIssue99933 ? 109 : 108.0); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + testVerticalGeometry(108.0); + } await tester.pumpWidget(buildFrame(isThreeLine: true, textScaleFactor: 4.0)); testChildren(); testHorizontalGeometry(); - testVerticalGeometry(hasIssue99933 ? 193 : 192.0); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + testVerticalGeometry(192.0); + } }); testWidgetsWithLeakTracking('ListTile geometry (RTL)', (WidgetTester tester) async { @@ -504,13 +506,13 @@ void main() { ), ), ); - // TODO(tahatesser): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - const double height = hasIssue99933 ? 301.0 : 300; - const double avatarTop = hasIssue99933 ? 130.5 : 130.0; - const double placeholderTop = hasIssue99933 ? 138.5 : 138.0; + + if (kIsWeb && !isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + return; + } + const double height = 300; + const double avatarTop = 130.0; + const double placeholderTop = 138.0; // LEFT TOP WIDTH HEIGHT expect(tester.getRect(find.byType(ListTile).at(0)), const Rect.fromLTWH( 0.0, 0.0, 800.0, height)); expect(tester.getRect(find.byType(CircleAvatar).at(0)), const Rect.fromLTWH( 16.0, avatarTop, 40.0, 40.0)); diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index 63019b9a68f36..1736729c911db 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -411,10 +411,8 @@ void main() { await tester.longPress(find.text(label)); expect(find.text(label), findsNWidgets(2)); - if (kIsWeb && !isCanvasKit) { - expect(tester.getSize(find.text(label).last), const Size(15.0, 21.0)); - } else { - expect(tester.getSize(find.text(label).last), const Size(15.0, 20.0)); + if (!kIsWeb || isCanvasKit) { + expect(tester.getSize(find.text(label).last), const Size(14.25, 20.0)); } // The duration is needed to ensure the tooltip disappears. await tester.pumpAndSettle(const Duration(seconds: 2)); @@ -423,10 +421,8 @@ void main() { expect(find.text(label), findsOneWidget); await tester.longPress(find.text(label)); - if (kIsWeb && !isCanvasKit) { - expect(tester.getSize(find.text(label).last), const Size(57.0, 81.0)); - } else { - expect(tester.getSize(find.text(label).last), const Size(57.0, 80.0)); + if (!kIsWeb || isCanvasKit) { + expect(tester.getSize(find.text(label).last), const Size(56.25, 80.0)); } }); @@ -831,7 +827,7 @@ void main() { color: const Color(0x0a000000), ) ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('Material3 - Navigation indicator ripple golden test', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117420. diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index ec1159c8a3e2e..d2872221da20c 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show ParagraphBuilder; - import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -544,48 +542,54 @@ void main() { // The second destination is below the first with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox secondIconRenderBox = _iconRenderBox(tester, Icons.bookmark_border); - expect( - secondIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - secondIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + secondIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - secondIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The third destination is below the second with some spacing. nextDestinationY += destinationHeight + destinationSpacing; final RenderBox thirdIconRenderBox = _iconRenderBox(tester, Icons.star_border); - expect( - thirdIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - thirdIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + thirdIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - thirdIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The fourth destination is below the third with some spacing. nextDestinationY += destinationHeight + destinationSpacing; final RenderBox fourthIconRenderBox = _iconRenderBox(tester, Icons.hotel); - expect( - fourthIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - fourthIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + fourthIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - fourthIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } }); testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=3.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. - final double destinationWidth = ui.ParagraphBuilder.shouldDisableRoundingHack ? 125.5 : 126.0; + const double destinationWidth = 125.5; // Height of a destination indicator with icon. const double destinationHeight = 32.0; // Space between the indicator and label. @@ -636,41 +640,47 @@ void main() { // The second destination is below the first with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox secondIconRenderBox = _iconRenderBox(tester, Icons.bookmark_border); - expect( - secondIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - secondIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + secondIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - secondIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The third destination is below the second with some spacing. nextDestinationY += destinationHeight + destinationSpacing; final RenderBox thirdIconRenderBox = _iconRenderBox(tester, Icons.star_border); - expect( - thirdIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - thirdIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + thirdIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - thirdIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The fourth destination is below the third with some spacing. nextDestinationY += destinationHeight + destinationSpacing; final RenderBox fourthIconRenderBox = _iconRenderBox(tester, Icons.hotel); - expect( - fourthIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - fourthIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + fourthIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - fourthIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } }); testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=0.75', (WidgetTester tester) async { @@ -728,41 +738,47 @@ void main() { // The second destination is below the first with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox secondIconRenderBox = _iconRenderBox(tester, Icons.bookmark_border); - expect( - secondIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - secondIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + secondIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - secondIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The third destination is below the second with some spacing. nextDestinationY += destinationHeight + destinationSpacing; final RenderBox thirdIconRenderBox = _iconRenderBox(tester, Icons.star_border); - expect( - thirdIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - thirdIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + thirdIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - thirdIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The fourth destination is below the third with some spacing. nextDestinationY += destinationHeight + destinationSpacing; final RenderBox fourthIconRenderBox = _iconRenderBox(tester, Icons.hotel); - expect( - fourthIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - fourthIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + fourthIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - fourthIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } }); testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { @@ -819,48 +835,54 @@ void main() { // The second destination is below the first with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox secondIconRenderBox = _iconRenderBox(tester, Icons.bookmark_border); - expect( - secondIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - secondIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + secondIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - secondIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The third destination is below the second with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox thirdIconRenderBox = _iconRenderBox(tester, Icons.star_border); - expect( - thirdIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - thirdIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + thirdIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - thirdIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The fourth destination is below the third with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox fourthIconRenderBox = _iconRenderBox(tester, Icons.hotel); - expect( - fourthIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - fourthIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + fourthIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - fourthIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } }); testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=3.0', (WidgetTester tester) async { // Padding at the top of the rail. const double topPadding = 8.0; // Width of a destination. - final double destinationWidth = ui.ParagraphBuilder.shouldDisableRoundingHack ? 125.5 : 126.0; + const double destinationWidth = 125.5; // Height of a destination indicator with icon. const double destinationHeight = 32.0; // Space between the indicator and label. @@ -911,41 +933,47 @@ void main() { // The second destination is below the first with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox secondIconRenderBox = _iconRenderBox(tester, Icons.bookmark_border); - expect( - secondIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - secondIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + secondIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - secondIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The third destination is below the second with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox thirdIconRenderBox = _iconRenderBox(tester, Icons.star_border); - expect( - thirdIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - thirdIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + thirdIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - thirdIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The fourth destination is below the third with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox fourthIconRenderBox = _iconRenderBox(tester, Icons.hotel); - expect( - fourthIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - fourthIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + fourthIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - fourthIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } }); testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=all, [textScaleFactor]=0.75', (WidgetTester tester) async { @@ -1003,41 +1031,47 @@ void main() { // The second destination is below the first with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox secondIconRenderBox = _iconRenderBox(tester, Icons.bookmark_border); - expect( - secondIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - secondIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + secondIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - secondIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - secondIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The third destination is below the second with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox thirdIconRenderBox = _iconRenderBox(tester, Icons.star_border); - expect( - thirdIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - thirdIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + thirdIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - thirdIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - thirdIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } // The fourth destination is below the third with some spacing. nextDestinationY += destinationHeightWithLabel + destinationSpacing; final RenderBox fourthIconRenderBox = _iconRenderBox(tester, Icons.hotel); - expect( - fourthIconRenderBox.localToGlobal(Offset.zero), - equals( - Offset( - (destinationWidth - fourthIconRenderBox.size.width) / 2.0, - nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect( + fourthIconRenderBox.localToGlobal(Offset.zero), + equals( + Offset( + (destinationWidth - fourthIconRenderBox.size.width) / 2.0, + nextDestinationY + (destinationHeight - fourthIconRenderBox.size.height) / 2.0, + ), ), - ), - ); + ); + } }); testWidgetsWithLeakTracking('Destination spacing is correct for a compact rail - [preferredWidth]=56, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { @@ -2790,7 +2824,7 @@ void main() { color: const Color(0xffe8def8), ), ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('NavigationRail indicator renders ripple - extended', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/117126 @@ -3123,7 +3157,7 @@ void main() { color: const Color(0xffe8def8), ), ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('NavigationRail indicator scale transform', (WidgetTester tester) async { int selectedIndex = 0; @@ -3371,7 +3405,7 @@ void main() { ), ), ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=3.0', (WidgetTester tester) async { // Since the rail is icon only, its destinations should not be affected by @@ -3441,7 +3475,7 @@ void main() { ), ), ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=none (default), [textScaleFactor]=0.75', (WidgetTester tester) async { // Since the rail is icon only, its destinations should not be affected by @@ -3511,7 +3545,7 @@ void main() { ), ), ); - }); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 testWidgetsWithLeakTracking('Destination spacing is correct - [labelType]=selected, [textScaleFactor]=1.0 (default)', (WidgetTester tester) async { await _pumpNavigationRail( diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 1bc1fe8b29602..61a14a6b968cc 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show ParagraphBuilder; - import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -1068,10 +1066,7 @@ void main() { ); expect(tester.getSize(find.byType(OutlinedButton)), equals(const Size(88.0, 48.0))); - expect(tester.getSize(find.byType(Text)), Size( - ui.ParagraphBuilder.shouldDisableRoundingHack ? 52.5 : 53.0, - 18.0, - )); + expect(tester.getSize(find.byType(Text)), const Size(52.5, 18.0)); // Set text scale large enough to expand text and button. await tester.pumpWidget( diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index 9720578de9117..667f482978916 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -2788,11 +2788,9 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.scaffold.nested.png')); final Offset snackBarTopRight = tester.getTopRight(find.byType(SnackBar)); - // TODO(bleroux): https://github.com/flutter/flutter/issues/99933 - // A bug in the HTML renderer and/or Chrome 96+ causes a - // discrepancy in the paragraph height. - const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA'); - expect(snackBarTopRight.dy, hasIssue99933 ? 464.0 : 465.0); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(snackBarTopRight.dy, 465.0); + } }); diff --git a/packages/flutter/test/material/stepper_test.dart b/packages/flutter/test/material/stepper_test.dart index e89a8efec1c18..2d3f0106d4033 100644 --- a/packages/flutter/test/material/stepper_test.dart +++ b/packages/flutter/test/material/stepper_test.dart @@ -968,17 +968,23 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async const String continueStr = 'Continue'; const String cancelStr = 'Cancel'; - const Rect continueButtonRect = Rect.fromLTRB(24.0, 212.0, 169.0, 260.0); - const Rect cancelButtonRect = Rect.fromLTRB(177.0, 212.0, 294.0, 260.0); + const Rect continueButtonRect = Rect.fromLTRB(24.0, 212.0, 168.8, 260.0); + const Rect cancelButtonRect = Rect.fromLTRB(176.8, 212.0, 293.4, 260.0); expect(buttonMaterial(continueStr).color!.value, themeLight.colorScheme.primary.value); expect(buttonMaterial(continueStr).textStyle!.color!.value, 0xffffffff); expect(buttonMaterial(continueStr).shape, buttonShape); - expect(tester.getRect(find.widgetWithText(TextButton, continueStr)), continueButtonRect); + expect( + tester.getRect(find.widgetWithText(TextButton, continueStr)), + rectMoreOrLessEquals(continueButtonRect, epsilon: 0.001), + ); expect(buttonMaterial(cancelStr).color!.value, 0); expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0x8a000000); expect(buttonMaterial(cancelStr).shape, buttonShape); - expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); + expect( + tester.getRect(find.widgetWithText(TextButton, cancelStr)), + rectMoreOrLessEquals(cancelButtonRect, epsilon: 0.001), + ); final ThemeData themeDark = ThemeData.dark(useMaterial3: true); await tester.pumpWidget(buildFrame(themeDark)); @@ -987,12 +993,18 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(buttonMaterial(continueStr).color!.value, 0); expect(buttonMaterial(continueStr).textStyle!.color!.value, themeDark.colorScheme.onSurface.value); expect(buttonMaterial(continueStr).shape, buttonShape); - expect(tester.getRect(find.widgetWithText(TextButton, continueStr)), continueButtonRect); + expect( + tester.getRect(find.widgetWithText(TextButton, continueStr)), + rectMoreOrLessEquals(continueButtonRect, epsilon: 0.001), + ); expect(buttonMaterial(cancelStr).color!.value, 0); expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0xb3ffffff); expect(buttonMaterial(cancelStr).shape, buttonShape); - expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); + expect( + tester.getRect(find.widgetWithText(TextButton, cancelStr)), + rectMoreOrLessEquals(cancelButtonRect, epsilon: 0.001), + ); }); testWidgets('Material2 - Stepper disabled button styles', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index e137c541ad963..0db83f44abc88 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -7,8 +7,6 @@ @Tags(['reduced-test-set']) library; -import 'dart:ui' as ui show ParagraphBuilder; - import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -675,8 +673,8 @@ void main() { ..line( color: theme.colorScheme.primary, strokeWidth: indicatorWeight, - p1: Offset(ui.ParagraphBuilder.shouldDisableRoundingHack ? 65.75 : 65.5, indicatorY), - p2: Offset(ui.ParagraphBuilder.shouldDisableRoundingHack ? 134.25 : 134.5, indicatorY), + p1: const Offset(65.75, indicatorY), + p2: const Offset(134.25, indicatorY), ), ); }); diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 1dc8234f5c562..461393d7ab557 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show ParagraphBuilder; - import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -328,7 +326,10 @@ void main() { MaterialApp(theme: theme, home: const Center(child: Material(child: Tab(text: 'x')))), ); expect(tester.renderObject(find.byType(RichText)).text.style!.fontFamily, 'FlutterTest'); - expect(tester.getSize(find.byType(Tab)), material3 ? const Size(15.0, 46.0) : const Size(14.0, 46.0)); + expect( + tester.getSize(find.byType(Tab)), + material3 ? const Size(14.25, 46.0) : const Size(14.0, 46.0), + ); }); testWidgets('Tab sizing - icon and text', (WidgetTester tester) async { @@ -338,7 +339,9 @@ void main() { MaterialApp(theme: theme, home: const Center(child: Material(child: Tab(icon: SizedBox(width: 10.0, height: 10.0), text: 'x')))), ); expect(tester.renderObject(find.byType(RichText)).text.style!.fontFamily, 'FlutterTest'); - expect(tester.getSize(find.byType(Tab)), material3 ? const Size(15.0, 72.0) : const Size(14.0, 72.0)); + expect( + tester.getSize(find.byType(Tab)), + material3 ? const Size(14.25, 72.0) : const Size(14.0, 72.0)); }); testWidgets('Tab sizing - icon, iconMargin and text', (WidgetTester tester) async { @@ -372,7 +375,9 @@ void main() { MaterialApp(theme: theme, home: const Center(child: Material(child: Tab(icon: SizedBox(width: 10.0, height: 10.0), child: Text('x'))))), ); expect(tester.renderObject(find.byType(RichText)).text.style!.fontFamily, 'FlutterTest'); - expect(tester.getSize(find.byType(Tab)), material3 ? const Size(15.0, 72.0) : const Size(14.0, 72.0)); + expect( + tester.getSize(find.byType(Tab)), + material3 ? const Size(14.25, 72.0) : const Size(14.0, 72.0)); }); testWidgets('Tab color - normal', (WidgetTester tester) async { @@ -488,23 +493,14 @@ void main() { const double indicatorWeight = 3.0; - final RRect rrect = ui.ParagraphBuilder.shouldDisableRoundingHack - ? RRect.fromLTRBAndCorners( - 64.75, - tabBarBox.size.height - indicatorWeight, - 135.25, - tabBarBox.size.height, - topLeft: const Radius.circular(3.0), - topRight: const Radius.circular(3.0), - ) - : RRect.fromLTRBAndCorners( - 64.5, - tabBarBox.size.height - indicatorWeight, - 135.5, - tabBarBox.size.height, - topLeft: const Radius.circular(3.0), - topRight: const Radius.circular(3.0), - ); + final RRect rrect = RRect.fromLTRBAndCorners( + 64.75, + tabBarBox.size.height - indicatorWeight, + 135.25, + tabBarBox.size.height, + topLeft: const Radius.circular(3.0), + topRight: const Radius.circular(3.0), + ); expect( tabBarBox, @@ -2416,7 +2412,7 @@ void main() { // that. Tabs are padded horizontally with kTabLabelPadding. final double tabRight = 800.0 - kTabLabelPadding.right; - expect(tester.getTopRight(find.widgetWithText(Tab, 'TAB #19')).dx, tabRight); + expect(tester.getTopRight(find.widgetWithText(Tab, 'TAB #19')).dx, moreOrLessEquals(tabRight)); }); testWidgets('TabBar with indicatorWeight, indicatorPadding (LTR)', (WidgetTester tester) async { @@ -6089,9 +6085,9 @@ void main() { // Tabs should fill the width of the TabBar. double tabOneLeft = ((tabBar.width / 2) - tabOneRect.width) / 2; - expect(tabOneRect.left, equals(tabOneLeft)); + expect(tabOneRect.left, moreOrLessEquals(tabOneLeft)); double tabTwoRight = tabBar.width - ((tabBar.width / 2) - tabTwoRect.width) / 2; - expect(tabTwoRect.right, equals(tabTwoRight)); + expect(tabTwoRect.right, moreOrLessEquals(tabTwoRight)); // Test default TabAlignment when isScrollable is true. await tester.pumpWidget(buildFrame( @@ -6106,9 +6102,9 @@ void main() { // Tabs should be aligned to the start of the TabBar. tabOneLeft = kTabLabelPadding.left + tabStartOffset; - expect(tabOneRect.left, equals(tabOneLeft)); + expect(tabOneRect.left, moreOrLessEquals(tabOneLeft)); tabTwoRight = kTabLabelPadding.horizontal + tabStartOffset + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; - expect(tabTwoRect.right, equals(tabTwoRight)); + expect(tabTwoRect.right, moreOrLessEquals(tabTwoRight)); }); testWidgets('TabAlignment.fill only supports non-scrollable tab bar', (WidgetTester tester) async { @@ -6181,9 +6177,9 @@ void main() { // By defaults tabs should fill the width of the TabBar. double tabOneLeft = ((availableWidth / 2) - tabOneRect.width) / 2; - expect(tabOneRect.left, equals(tabOneLeft)); + expect(tabOneRect.left, moreOrLessEquals(tabOneLeft)); double tabTwoRight = availableWidth - ((availableWidth / 2) - tabTwoRect.width) / 2; - expect(tabTwoRect.right, equals(tabTwoRight)); + expect(tabTwoRect.right, moreOrLessEquals(tabTwoRight)); // Test TabAlignment.center when isScrollable is false. await tester.pumpWidget(buildFrame( @@ -6199,9 +6195,9 @@ void main() { // Tabs should not fill the width of the TabBar. tabOneLeft = kTabLabelPadding.left; - expect(tabOneRect.left, equals(tabOneLeft)); + expect(tabOneRect.left, moreOrLessEquals(tabOneLeft)); tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; - expect(tabTwoRect.right, equals(tabTwoRight)); + expect(tabTwoRect.right, moreOrLessEquals(tabTwoRight)); }); testWidgets('Material3 - TabAlignment updates tabs alignment (scrollable TabBar)', (WidgetTester tester) async { @@ -6690,9 +6686,9 @@ void main() { // By default tabs should fill the width of the TabBar. double tabOneLeft = ((tabBar.width / 2) - tabOneRect.width) / 2; - expect(tabOneRect.left, equals(tabOneLeft)); + expect(tabOneRect.left, moreOrLessEquals(tabOneLeft)); double tabTwoRight = tabBar.width - ((tabBar.width / 2) - tabTwoRect.width) / 2; - expect(tabTwoRect.right, equals(tabTwoRight)); + expect(tabTwoRect.right, moreOrLessEquals(tabTwoRight)); // Test TabAlignment.center when isScrollable is false. await tester.pumpWidget(MaterialApp( @@ -6706,9 +6702,9 @@ void main() { // Tabs should not fill the width of the TabBar. tabOneLeft = kTabLabelPadding.left; - expect(tabOneRect.left, equals(tabOneLeft)); + expect(tabOneRect.left, moreOrLessEquals(tabOneLeft)); tabTwoRight = kTabLabelPadding.horizontal + tabOneRect.width + kTabLabelPadding.left + tabTwoRect.width; - expect(tabTwoRect.right, equals(tabTwoRight)); + expect(tabTwoRect.right, moreOrLessEquals(tabTwoRight)); }); }); } diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 1c3b757d2fa24..784ffb3a3c1ae 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show ParagraphBuilder; - import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -620,12 +618,8 @@ void main() { ), ); - final Size textButtonSize = ui.ParagraphBuilder.shouldDisableRoundingHack - ? const Size(68.5, 48.0) - : const Size(69.0, 48.0); - final Size textSize = ui.ParagraphBuilder.shouldDisableRoundingHack - ? const Size(52.5, 18.0) - : const Size(53.0, 18.0); + const Size textButtonSize = Size(68.5, 48.0); + const Size textSize = Size(52.5, 18.0); expect(tester.getSize(find.byType(TextButton)), textButtonSize); expect(tester.getSize(find.byType(Text)), textSize); diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index fca0bc614b0e4..2d5b880fa5ba0 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -969,7 +969,7 @@ void main() { expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155))); expect(tester.getBottomRight(find.text(selectTimeString)), equals( - ParagraphBuilder.shouldDisableRoundingHack ? const Offset(280.5, 165) : const Offset(281, 165), + const Offset(280.5, 165), )); expect(tester.getBottomRight(find.text(okString)).dx, 644); expect(tester.getBottomLeft(find.text(okString)).dx, 616); @@ -983,7 +983,7 @@ void main() { await tester.pumpAndSettle(); expect(tester.getTopLeft(find.text(selectTimeString)), equals( - ParagraphBuilder.shouldDisableRoundingHack ? const Offset(519.5, 155) : const Offset(519, 155), + const Offset(519.5, 155), )); expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165))); expect(tester.getBottomLeft(find.text(okString)).dx, 156); @@ -1031,8 +1031,14 @@ void main() { await tester.pumpAndSettle(); expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(138, 129))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(295.0, 149.0))); - expect(tester.getBottomLeft(find.text(okString)).dx, 615.5); + expect( + tester.getBottomRight(find.text(selectTimeString)), + const Offset(294.75, 149.0), + ); + expect( + tester.getBottomLeft(find.text(okString)).dx, + moreOrLessEquals(615.9, epsilon: 0.001), + ); expect(tester.getBottomRight(find.text(cancelString)).dx, 578); await tester.tap(find.text(okString)); @@ -1042,10 +1048,19 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(); - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(505.0, 129.0))); + expect( + tester.getTopLeft(find.text(selectTimeString)), + equals(const Offset(505.25, 129.0)), + ); expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(662, 149))); - expect(tester.getBottomLeft(find.text(okString)).dx, 155.5); - expect(tester.getBottomRight(find.text(okString)).dx, 184.5); + expect( + tester.getBottomLeft(find.text(okString)).dx, + moreOrLessEquals(155.9, epsilon: 0.001), + ); + expect( + tester.getBottomRight(find.text(okString)).dx, + moreOrLessEquals(184.1, epsilon: 0.001), + ); expect(tester.getBottomLeft(find.text(cancelString)).dx, 222); await tester.tap(find.text(okString)); diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index 55c7ec50e09e2..8dec06994531b 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -1509,9 +1509,6 @@ void main() { }); test('TextPainter line breaking does not round to integers', () { - if (!ui.ParagraphBuilder.shouldDisableRoundingHack) { - return; - } const double fontSize = 1.25; const String text = '12345'; assert((fontSize * text.length).truncate() != fontSize * text.length); diff --git a/packages/flutter_localizations/test/text_test.dart b/packages/flutter_localizations/test/text_test.dart index 310cdf0ea2d86..bd3528a53f721 100644 --- a/packages/flutter_localizations/test/text_test.dart +++ b/packages/flutter_localizations/test/text_test.dart @@ -71,25 +71,11 @@ void main() { expect(find.text('hello, world'), findsOneWidget); expect(find.text('你好,世界'), findsOneWidget); - Offset topLeft = tester.getTopLeft(find.text('hello, world')); - Offset topRight = tester.getTopRight(find.text('hello, world')); - Offset bottomLeft = tester.getBottomLeft(find.text('hello, world')); - Offset bottomRight = tester.getBottomRight(find.text('hello, world')); + expect(tester.getTopLeft(find.text('hello, world')).dy, 298.0); + expect(tester.getBottomLeft(find.text('hello, world')).dy, 318.0); - expect(topLeft, const Offset(392.0, 298.0)); - expect(topRight, const Offset(562.0, 298.0)); - expect(bottomLeft, const Offset(392.0, 318.0)); - expect(bottomRight, const Offset(562.0, 318.0)); - - topLeft = tester.getTopLeft(find.text('你好,世界')); - topRight = tester.getTopRight(find.text('你好,世界')); - bottomLeft = tester.getBottomLeft(find.text('你好,世界')); - bottomRight = tester.getBottomRight(find.text('你好,世界')); - - expect(topLeft, const Offset(392.0, 346.0)); - expect(topRight, const Offset(463.0, 346.0)); - expect(bottomLeft, const Offset(392.0, 366.0)); - expect(bottomRight, const Offset(463.0, 366.0)); + expect(tester.getTopLeft(find.text('你好,世界')).dy, 346.0); + expect(tester.getBottomLeft(find.text('你好,世界')).dy, 366.0); }); testWidgets('Text baseline with EN locale', (WidgetTester tester) async { @@ -156,24 +142,10 @@ void main() { expect(find.text('hello, world'), findsOneWidget); expect(find.text('你好,世界'), findsOneWidget); - Offset topLeft = tester.getTopLeft(find.text('hello, world')); - Offset topRight = tester.getTopRight(find.text('hello, world')); - Offset bottomLeft = tester.getBottomLeft(find.text('hello, world')); - Offset bottomRight = tester.getBottomRight(find.text('hello, world')); - - expect(topLeft, const Offset(392.0, 298.0)); - expect(topRight, const Offset(562.0, 298.0)); - expect(bottomLeft, const Offset(392.0, 318.0)); - expect(bottomRight, const Offset(562.0, 318.0)); - - topLeft = tester.getTopLeft(find.text('你好,世界')); - topRight = tester.getTopRight(find.text('你好,世界')); - bottomLeft = tester.getBottomLeft(find.text('你好,世界')); - bottomRight = tester.getBottomRight(find.text('你好,世界')); + expect(tester.getTopLeft(find.text('hello, world')).dy, 298.0); + expect(tester.getBottomLeft(find.text('hello, world')).dy, 318.0); - expect(topLeft, const Offset(392.0, 346.0)); - expect(topRight, const Offset(463.0, 346.0)); - expect(bottomLeft, const Offset(392.0, 366.0)); - expect(bottomRight, const Offset(463.0, 366.0)); + expect(tester.getTopLeft(find.text('你好,世界')).dy, 346.0); + expect(tester.getBottomLeft(find.text('你好,世界')).dy, 366.0); }); } From 9a32f24a3441fa25336e8fb7ecb582682cf69177 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Wed, 9 Aug 2023 17:08:11 -1000 Subject: [PATCH 0628/1547] Fix prefer_null_aware_operators violation (#132242) Use a null-aware `?.` operator instead of a conditional operator. This complies with the `prefer_null_aware_operators` rule. Fixes https://github.com/flutter/flutter/issues/132241 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- packages/flutter/lib/src/painting/gradient.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/painting/gradient.dart b/packages/flutter/lib/src/painting/gradient.dart index f740eab9797d7..106d694068f0c 100644 --- a/packages/flutter/lib/src/painting/gradient.dart +++ b/packages/flutter/lib/src/painting/gradient.dart @@ -707,7 +707,7 @@ class RadialGradient extends Gradient { radius * rect.shortestSide, colors, _impliedStops(), tileMode, _resolveTransform(rect, textDirection), - focal == null ? null : focal!.resolve(textDirection).withinRect(rect), + focal?.resolve(textDirection).withinRect(rect), focalRadius * rect.shortestSide, ); } From 2efda23a45124469d4d4a243632c7aaf999637be Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 9 Aug 2023 20:25:06 -0700 Subject: [PATCH 0629/1547] Pin leak_tracker. (#132261) --- packages/flutter_tools/lib/src/commands/update_packages.dart | 4 ++++ .../test/general.shard/update_packages_test.dart | 2 ++ 2 files changed, 6 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 5d240051fba88..92e6a81a2ced3 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -38,6 +38,10 @@ const Map kManuallyPinnedDependencies = { 'url_launcher_android': '6.0.17', // https://github.com/flutter/flutter/issues/115660 'archive': '3.3.2', + // https://github.com/flutter/flutter/issues/132222 + 'leak_tracker': '8.0.3', + // https://github.com/flutter/flutter/issues/132222 + 'leak_tracker_testing': '1.0.2', }; class UpdatePackagesCommand extends FlutterCommand { diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index b92fe6b15a40e..34b24592e2178 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -108,6 +108,8 @@ void main() { 'material_color_utilities', 'url_launcher_android', 'archive', + 'leak_tracker', + 'leak_tracker_testing', ]), ); }); From 9156f6b5f3aee463400a50eb5b734f18332db7d4 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 9 Aug 2023 22:00:05 -0700 Subject: [PATCH 0630/1547] Add missing `ignore: deprecated_member_use` to unblock the engine roller (#132280) ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- packages/flutter/lib/src/painting/text_painter.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 210b93d3ba4e5..c1e01cb36a1fd 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -282,6 +282,7 @@ class _TextLayout { // TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/31707 // remove this hack as well as the flooring in `layout`. @pragma('vm:prefer-inline') + // ignore: deprecated_member_use static double _applyFloatingPointHack(double layoutValue) => ui.ParagraphBuilder.shouldDisableRoundingHack ? layoutValue : layoutValue.ceilToDouble(); /// Whether this layout has been invalidated and disposed. @@ -360,6 +361,7 @@ class _TextPainterLayoutCacheWithOffset { static double _contentWidthFor(double minWidth, double maxWidth, TextWidthBasis widthBasis, _TextLayout layout) { // TODO(LongCatIsLooong): remove the rounding when _applyFloatingPointHack // is removed. + // ignore: deprecated_member_use if (!ui.ParagraphBuilder.shouldDisableRoundingHack) { minWidth = minWidth.floorToDouble(); maxWidth = maxWidth.floorToDouble(); From 0c80ed6d1238efabe47618e97f2a19bb0aba2818 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 10 Aug 2023 00:46:05 -0500 Subject: [PATCH 0631/1547] Keep alive support for 2D scrolling (#131641) Fixes https://github.com/flutter/flutter/issues/126297 This adds support for keep alive to the 2D scrolling foundation. The TwoDimensionalChildBuilderDelegate and TwoDimensionalChildListDelegate will both add automatic keep alives to their children, matching the convention from SliverChildDelegates. The TwoDimensionalViewportParentData now incorporates keep alive and which is managed by the RenderTwoDimensionalViewport. --- .../lib/src/widgets/scroll_delegate.dart | 22 +- .../src/widgets/two_dimensional_viewport.dart | 130 ++++++- .../test/widgets/two_dimensional_utils.dart | 56 ++- .../two_dimensional_viewport_test.dart | 336 +++++++++++++++++- 4 files changed, 514 insertions(+), 30 deletions(-) diff --git a/packages/flutter/lib/src/widgets/scroll_delegate.dart b/packages/flutter/lib/src/widgets/scroll_delegate.dart index 765bf31d8a1a7..b81b9b069ecf9 100644 --- a/packages/flutter/lib/src/widgets/scroll_delegate.dart +++ b/packages/flutter/lib/src/widgets/scroll_delegate.dart @@ -395,8 +395,8 @@ class SliverChildBuilderDelegate extends SliverChildDelegate { /// {@template flutter.widgets.SliverChildBuilderDelegate.addAutomaticKeepAlives} /// Whether to wrap each child in an [AutomaticKeepAlive]. /// - /// Typically, children in lazy list are wrapped in [AutomaticKeepAlive] - /// widgets so that children can use [KeepAliveNotification]s to preserve + /// Typically, lazily laid out children are wrapped in [AutomaticKeepAlive] + /// widgets so that the children can use [KeepAliveNotification]s to preserve /// their state when they would otherwise be garbage collected off-screen. /// /// This feature (and [addRepaintBoundaries]) must be disabled if the children @@ -863,7 +863,6 @@ Widget _createErrorWidget(Object exception, StackTrace stackTrace) { return ErrorWidget.builder(details); } -// TODO(Piinks): Come back and add keep alive support, https://github.com/flutter/flutter/issues/126297 /// A delegate that supplies children for scrolling in two dimensions. /// /// A [TwoDimensionalScrollView] lazily constructs its box children to avoid @@ -929,10 +928,11 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { /// Creates a delegate that supplies children for a [TwoDimensionalScrollView] /// using the given builder callback. TwoDimensionalChildBuilderDelegate({ - this.addRepaintBoundaries = true, required this.builder, int? maxXIndex, int? maxYIndex, + this.addRepaintBoundaries = true, + this.addAutomaticKeepAlives = true, }) : assert(maxYIndex == null || maxYIndex >= 0), assert(maxXIndex == null || maxXIndex >= 0), _maxYIndex = maxYIndex, @@ -1028,6 +1028,9 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { /// {@macro flutter.widgets.SliverChildBuilderDelegate.addRepaintBoundaries} final bool addRepaintBoundaries; + /// {@macro flutter.widgets.SliverChildBuilderDelegate.addAutomaticKeepAlives} + final bool addAutomaticKeepAlives; + @override Widget? build(BuildContext context, ChildVicinity vicinity) { // If we have exceeded explicit upper bounds, return null. @@ -1050,6 +1053,9 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { if (addRepaintBoundaries) { child = RepaintBoundary(child: child); } + if (addAutomaticKeepAlives) { + child = AutomaticKeepAlive(child: _SelectionKeepAlive(child: child)); + } return child; } @@ -1095,6 +1101,7 @@ class TwoDimensionalChildListDelegate extends TwoDimensionalChildDelegate { /// null. TwoDimensionalChildListDelegate({ this.addRepaintBoundaries = true, + this.addAutomaticKeepAlives = true, required this.children, }); @@ -1114,6 +1121,9 @@ class TwoDimensionalChildListDelegate extends TwoDimensionalChildDelegate { /// {@macro flutter.widgets.SliverChildBuilderDelegate.addRepaintBoundaries} final bool addRepaintBoundaries; + /// {@macro flutter.widgets.SliverChildBuilderDelegate.addAutomaticKeepAlives} + final bool addAutomaticKeepAlives; + @override Widget? build(BuildContext context, ChildVicinity vicinity) { // If we have exceeded explicit upper bounds, return null. @@ -1128,7 +1138,9 @@ class TwoDimensionalChildListDelegate extends TwoDimensionalChildDelegate { if (addRepaintBoundaries) { child = RepaintBoundary(child: child); } - + if (addAutomaticKeepAlives) { + child = AutomaticKeepAlive(child: _SelectionKeepAlive(child: child)); + } return child; } diff --git a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart index 82befbce08432..282ef44490874 100644 --- a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart +++ b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart @@ -391,7 +391,7 @@ class _TwoDimensionalViewportElement extends RenderObjectElement /// RenderTwoDimensionalViewport override the paint method, the [paintOffset] /// should be used to position the child in the viewport in order to account for /// a reversed [AxisDirection] in one or both dimensions. -class TwoDimensionalViewportParentData extends ParentData { +class TwoDimensionalViewportParentData extends ParentData with KeepAliveParentDataMixin { /// The offset at which to paint the child in the parent's coordinate system. /// /// This [Offset] represents the top left corner of the child of the @@ -472,14 +472,18 @@ class TwoDimensionalViewportParentData extends ParentData { /// position the children instead of [layoutOffset]. Offset? paintOffset; + @override + bool get keptAlive => keepAlive && !isVisible; + @override String toString() { return 'vicinity=$vicinity; ' 'layoutOffset=$layoutOffset; ' 'paintOffset=$paintOffset; ' '${_paintExtent == null - ? 'not visible ' - : '${!isVisible ? 'not ' : ''}visible - paintExtent=$_paintExtent'}'; + ? 'not visible; ' + : '${!isVisible ? 'not ' : ''}visible - paintExtent=$_paintExtent; '}' + '${keepAlive ? "keepAlive; " : ""}'; } } @@ -493,9 +497,7 @@ class TwoDimensionalViewportParentData extends ParentData { /// /// Subclasses should not override [performLayout], as it handles housekeeping /// on either side of the call to [layoutChildSequence]. -// TODO(Piinks): Two follow up changes: -// - Keep alive https://github.com/flutter/flutter/issues/126297 -// - ensureVisible https://github.com/flutter/flutter/issues/126299 +// TODO(Piinks): ensureVisible https://github.com/flutter/flutter/issues/126299 abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderAbstractViewport { /// Initializes fields for subclasses. /// @@ -527,7 +529,12 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA _delegate = delegate, _mainAxis = mainAxis, _cacheExtent = cacheExtent ?? RenderAbstractViewport.defaultCacheExtent, - _clipBehavior = clipBehavior; + _clipBehavior = clipBehavior { + assert(() { + _debugDanglingKeepAlives = []; + return true; + }()); + } /// Which part of the content inside the viewport should be visible in the /// horizontal axis. @@ -674,6 +681,16 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA } final TwoDimensionalChildManager _childManager; + final Map _children = {}; + /// Children that have been laid out (or re-used) during the course of + /// performLayout, used to update the keep alive bucket at the end of + /// performLayout. + final Map _activeChildrenForLayoutPass = {}; + /// The nodes being kept alive despite not being visible. + final Map _keepAliveBucket = {}; + + late List _debugDanglingKeepAlives; + bool _hasVisualOverflow = false; final LayerHandle _clipRectLayer = LayerHandle(); @@ -683,7 +700,6 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA @override bool get sizedByParent => true; - final Map _children = {}; // Keeps track of the upper and lower bounds of ChildVicinity indices when // subclasses call buildOrObtainChildFor during layoutChildSequence. These // values are used to sort children in accordance with the mainAxis for @@ -788,6 +804,9 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA for (final RenderBox child in _children.values) { child.attach(owner); } + for (final RenderBox child in _keepAliveBucket.values) { + child.attach(owner); + } } @override @@ -799,6 +818,9 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA for (final RenderBox child in _children.values) { child.detach(); } + for (final RenderBox child in _keepAliveBucket.values) { + child.detach(); + } } @override @@ -806,6 +828,7 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA for (final RenderBox child in _children.values) { child.redepthChildren(); } + _keepAliveBucket.values.forEach(redepthChild); } @override @@ -815,6 +838,7 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA visitor(child); child = parentDataOf(child)._nextSibling; } + _keepAliveBucket.values.forEach(visitor); } @override @@ -824,11 +848,14 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA RenderBox? child = _firstChild; while (child != null) { final TwoDimensionalViewportParentData childParentData = parentDataOf(child); + // TODO(Piinks): When ensure visible is supported, remove this isVisible + // condition. if (childParentData.isVisible) { visitor(child); } child = childParentData._nextSibling; } + // Do not visit children in [_keepAliveBucket]. } @override @@ -959,6 +986,7 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA void performLayout() { _firstChild = null; _lastChild = null; + _activeChildrenForLayoutPass.clear(); _childManager._startLayout(); // Subclass lays out children. @@ -967,15 +995,35 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA assert(_debugCheckContentDimensions()); _didResize = false; _needsDelegateRebuild = false; + _cacheKeepAlives(); invokeLayoutCallback((BoxConstraints _) { _childManager._endLayout(); assert(_debugOrphans?.isEmpty ?? true); + assert(_debugDanglingKeepAlives.isEmpty); + // Ensure we are not keeping anything alive that should not be any longer. + assert(_keepAliveBucket.values.where((RenderBox child) { + return !parentDataOf(child).keepAlive; + }).isEmpty); // Organize children in paint order and complete parent data after // un-used children are disposed of by the childManager. _reifyChildren(); }); } + void _cacheKeepAlives() { + final List remainingChildren = _children.values.toSet().difference( + _activeChildrenForLayoutPass.values.toSet() + ).toList(); + for (final RenderBox child in remainingChildren) { + final TwoDimensionalViewportParentData childParentData = parentDataOf(child); + if (childParentData.keepAlive) { + _keepAliveBucket[childParentData.vicinity] = child; + // Let the child manager know we intend to keep this. + _childManager._reuseChild(childParentData.vicinity); + } + } + } + // Ensures all children have a layoutOffset, sets paintExtent & paintOffset, // and arranges children in paint order. void _reifyChildren() { @@ -1082,12 +1130,20 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA return true; } - /// Returns the child for a given [ChildVicinity]. + /// Returns the child for a given [ChildVicinity], should be called during + /// [layoutChildSequence] in order to instantiate or retrieve children. /// /// This method will build the child if it has not been already, or will reuse - /// it if it already exists. + /// it if it already exists, whether it was part of the previous frame or kept + /// alive. + /// + /// Children for the given [ChildVicinity] will be inserted into the active + /// children list, and so should be visible, or contained within the + /// [cacheExtent]. RenderBox? buildOrObtainChildFor(ChildVicinity vicinity) { assert(vicinity != ChildVicinity.invalid); + // This should only be called during layout. + assert(debugDoingThisLayout); if (_leadingXIndex == null || _trailingXIndex == null || _leadingXIndex == null || _trailingYIndex == null) { // First child of this layout pass. Set leading and trailing trackers. _leadingXIndex = vicinity.xIndex; @@ -1107,11 +1163,12 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA _leadingYIndex = math.min(vicinity.yIndex, _leadingYIndex!); _trailingYIndex = math.max(vicinity.yIndex, _trailingYIndex!); } - if (_needsDelegateRebuild || !_children.containsKey(vicinity)) { + if (_needsDelegateRebuild || (!_children.containsKey(vicinity) && !_keepAliveBucket.containsKey(vicinity))) { invokeLayoutCallback((BoxConstraints _) { _childManager._buildChild(vicinity); }); } else { + _keepAliveBucket.remove(vicinity); _childManager._reuseChild(vicinity); } if (!_children.containsKey(vicinity)) { @@ -1122,6 +1179,7 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA assert(_children.containsKey(vicinity)); final RenderBox child = _children[vicinity]!; + _activeChildrenForLayoutPass[vicinity] = child; parentDataOf(child).vicinity = vicinity; return child; } @@ -1304,23 +1362,59 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA void _insertChild(RenderBox child, ChildVicinity slot) { assert(_debugTrackOrphans(newOrphan: _children[slot])); + assert(!_keepAliveBucket.containsValue(child)); _children[slot] = child; adoptChild(child); } void _moveChild(RenderBox child, {required ChildVicinity from, required ChildVicinity to}) { - if (_children[from] == child) { - _children.remove(from); + final TwoDimensionalViewportParentData childParentData = parentDataOf(child); + if (!childParentData.keptAlive) { + if (_children[from] == child) { + _children.remove(from); + } + assert(_debugTrackOrphans(newOrphan: _children[to], noLongerOrphan: child)); + _children[to] = child; + return; + } + // If the child in the bucket is not current child, that means someone has + // already moved and replaced current child, and we cannot remove this + // child. + if (_keepAliveBucket[childParentData.vicinity] == child) { + _keepAliveBucket.remove(childParentData.vicinity); } - assert(_debugTrackOrphans(newOrphan: _children[to], noLongerOrphan: child)); - _children[to] = child; + assert(() { + _debugDanglingKeepAlives.remove(child); + return true; + }()); + // If there is an existing child in the new slot, that mean that child + // will be moved to other index. In other cases, the existing child should + // have been removed by _removeChild. Thus, it is ok to overwrite it. + assert(() { + if (_keepAliveBucket.containsKey(childParentData.vicinity)) { + _debugDanglingKeepAlives.add(_keepAliveBucket[childParentData.vicinity]!); + } + return true; + }()); + _keepAliveBucket[childParentData.vicinity] = child; } void _removeChild(RenderBox child, ChildVicinity slot) { - if (_children[slot] == child) { - _children.remove(slot); + final TwoDimensionalViewportParentData childParentData = parentDataOf(child); + if (!childParentData.keptAlive) { + if (_children[slot] == child) { + _children.remove(slot); + } + assert(_debugTrackOrphans(noLongerOrphan: child)); + dropChild(child); + return; } - assert(_debugTrackOrphans(noLongerOrphan: child)); + assert(_keepAliveBucket[childParentData.vicinity] == child); + assert(() { + _debugDanglingKeepAlives.remove(child); + return true; + }()); + _keepAliveBucket.remove(childParentData.vicinity); dropChild(child); } diff --git a/packages/flutter/test/widgets/two_dimensional_utils.dart b/packages/flutter/test/widgets/two_dimensional_utils.dart index 5eb3bf2602082..017897bcae56b 100644 --- a/packages/flutter/test/widgets/two_dimensional_utils.dart +++ b/packages/flutter/test/widgets/two_dimensional_utils.dart @@ -393,18 +393,18 @@ class RenderSimpleListTableViewport extends RenderTwoDimensionalViewport { final TwoDimensionalChildListDelegate listDelegate = delegate as TwoDimensionalChildListDelegate; final int rowCount; final int columnCount; - rowCount = listDelegate.children.length - 1; - columnCount = listDelegate.children[0].length - 1; + rowCount = listDelegate.children.length; + columnCount = listDelegate.children[0].length; final int leadingColumn = math.max((horizontalPixels / 200).floor(), 0); final int leadingRow = math.max((verticalPixels / 200).floor(), 0); final int trailingColumn = math.min( ((horizontalPixels + viewportDimension.width) / 200).ceil(), - columnCount, + columnCount - 1, ); final int trailingRow = math.min( ((verticalPixels + viewportDimension.height) / 200).ceil(), - rowCount, + rowCount - 1, ); double xLayoutOffset = (leadingColumn * 200) - horizontalOffset.pixels; @@ -420,7 +420,51 @@ class RenderSimpleListTableViewport extends RenderTwoDimensionalViewport { } xLayoutOffset += 200; } - verticalOffset.applyContentDimensions(0, 200 * 100 - viewportDimension.height); - horizontalOffset.applyContentDimensions(0, 200 * 100 - viewportDimension.width); + + verticalOffset.applyContentDimensions( + 0.0, + math.max(200 * rowCount - viewportDimension.height, 0.0), + ); + horizontalOffset.applyContentDimensions( + 0, + math.max(200 * columnCount - viewportDimension.width, 0.0), + ); + } +} + +class KeepAliveCheckBox extends StatefulWidget { + const KeepAliveCheckBox({ super.key }); + + @override + KeepAliveCheckBoxState createState() => KeepAliveCheckBoxState(); +} + +class KeepAliveCheckBoxState extends State with AutomaticKeepAliveClientMixin { + bool checkValue = false; + + @override + bool get wantKeepAlive => _wantKeepAlive; + bool _wantKeepAlive = false; + set wantKeepAlive(bool value) { + if (_wantKeepAlive != value) { + _wantKeepAlive = value; + updateKeepAlive(); + } + } + + @override + Widget build(BuildContext context) { + super.build(context); + return Checkbox( + value: checkValue, + onChanged: (bool? value) { + if (checkValue != value) { + setState(() { + checkValue = value!; + wantKeepAlive = value; + }); + } + }, + ); } } diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index a445d3412c97b..6cb6d025dd35f 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -212,6 +212,172 @@ void main() { testWidgets('shouldRebuild', (WidgetTester tester) async { expect(builderDelegate.shouldRebuild(builderDelegate), isTrue); }, variant: TargetPlatformVariant.all()); + + testWidgets('builder delegate supports automatic keep alive - default true', (WidgetTester tester) async { + const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); + final ScrollController verticalController = ScrollController(); + final UniqueKey checkBoxKey = UniqueKey(); + final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( + maxXIndex: 5, + maxYIndex: 5, + builder: (BuildContext context, ChildVicinity vicinity) { + return SizedBox.square( + dimension: 200, + child: Center(child: vicinity == firstCell + ? KeepAliveCheckBox(key: checkBoxKey) + : Text('R${vicinity.xIndex}:C${vicinity.yIndex}') + ), + ); + } + ); + + await tester.pumpWidget(simpleBuilderTest( + delegate: builderDelegate, + verticalDetails: ScrollableDetails.vertical(controller: verticalController), + )); + await tester.pumpAndSettle(); + + expect(verticalController.hasClients, isTrue); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + // Scroll away, disposing of the checkbox. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 600.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, still unchecked, not kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + await tester.tap(find.byKey(checkBoxKey)); + await tester.pumpAndSettle(); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + + // Scroll away again, checkbox should be kept alive now. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 600.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + + // Bring back into view, still checked, after being kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + }); + + testWidgets('builder delegate will not add automatic keep alives', (WidgetTester tester) async { + const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); + final ScrollController verticalController = ScrollController(); + final UniqueKey checkBoxKey = UniqueKey(); + final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( + maxXIndex: 5, + maxYIndex: 5, + addAutomaticKeepAlives: false, // No keeping alive this time + builder: (BuildContext context, ChildVicinity vicinity) { + return SizedBox.square( + dimension: 200, + child: Center(child: vicinity == firstCell + ? KeepAliveCheckBox(key: checkBoxKey) + : Text('R${vicinity.xIndex}:C${vicinity.yIndex}') + ), + ); + } + ); + + await tester.pumpWidget(simpleBuilderTest( + delegate: builderDelegate, + verticalDetails: ScrollableDetails.vertical(controller: verticalController), + )); + await tester.pumpAndSettle(); + + expect(verticalController.hasClients, isTrue); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + // Scroll away, disposing of the checkbox. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 600.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, still unchecked, not kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + await tester.tap(find.byKey(checkBoxKey)); + await tester.pumpAndSettle(); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + + // Scroll away again, checkbox should not be kept alive since the + // delegate did not add automatic keep alive. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 600.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, not checked, having not been kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + }); }); group('TwoDimensionalChildListDelegate', () { @@ -338,6 +504,174 @@ void main() { expect(delegate.shouldRebuild(oldDelegate), isTrue); }, variant: TargetPlatformVariant.all()); }); + + testWidgets('list delegate supports automatic keep alive - default true', (WidgetTester tester) async { + final UniqueKey checkBoxKey = UniqueKey(); + final Widget originCell = SizedBox.square( + dimension: 200, + child: Center(child: KeepAliveCheckBox(key: checkBoxKey) + ), + ); + const Widget otherCell = SizedBox.square(dimension: 200); + final ScrollController verticalController = ScrollController(); + final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate( + children: >[ + [originCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + ], + ); + + await tester.pumpWidget(simpleListTest( + delegate: listDelegate, + verticalDetails: ScrollableDetails.vertical(controller: verticalController), + )); + await tester.pumpAndSettle(); + + expect(verticalController.hasClients, isTrue); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + // Scroll away, disposing of the checkbox. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 400.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, still unchecked, not kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + await tester.tap(find.byKey(checkBoxKey)); + await tester.pumpAndSettle(); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + + // Scroll away again, checkbox should be kept alive now. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 400.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + + // Bring back into view, still checked, after being kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + }); + + testWidgets('list delegate will not add automatic keep alives', (WidgetTester tester) async { + final UniqueKey checkBoxKey = UniqueKey(); + final Widget originCell = SizedBox.square( + dimension: 200, + child: Center(child: KeepAliveCheckBox(key: checkBoxKey) + ), + ); + const Widget otherCell = SizedBox.square(dimension: 200); + final ScrollController verticalController = ScrollController(); + final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate( + addAutomaticKeepAlives: false, + children: >[ + [originCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + [otherCell, otherCell, otherCell, otherCell, otherCell], + ], + ); + + await tester.pumpWidget(simpleListTest( + delegate: listDelegate, + verticalDetails: ScrollableDetails.vertical(controller: verticalController), + )); + await tester.pumpAndSettle(); + + expect(verticalController.hasClients, isTrue); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + // Scroll away, disposing of the checkbox. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 400.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, still unchecked, not kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + await tester.tap(find.byKey(checkBoxKey)); + await tester.pumpAndSettle(); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + + // Scroll away again, checkbox should not be kept alive since the + // delegate did not add automatic keep alive. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 400.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, not checked, having not been kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + }); }); group('TwoDimensionalScrollable', () { @@ -1025,7 +1359,7 @@ void main() { expect( parentData.toString(), 'vicinity=(xIndex: 10, yIndex: 10); layoutOffset=Offset(20.0, 20.0); ' - 'paintOffset=Offset(20.0, 20.0); not visible ', + 'paintOffset=Offset(20.0, 20.0); not visible; ', ); }); From a50776e5b8ed8d9cc67f12c2d496c2861b246482 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 02:29:24 -0400 Subject: [PATCH 0632/1547] Roll Flutter Engine from b5b41ff66dae to 9117ff27d9c9 (16 revisions) (#132284) https://github.com/flutter/engine/compare/b5b41ff66dae...9117ff27d9c9 2023-08-10 zanderso@users.noreply.github.com Revert "Android a11y bridge sets importantness" (flutter/engine#44569) 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from 491f67637e6e to 7c5f6b17a998 (2 revisions) (flutter/engine#44568) 2023-08-10 matanlurey@users.noreply.github.com [Impeller] Replace Vulkan rotation checks with polling (flutter/engine#44361) 2023-08-10 31859944+LongCatIsLooong@users.noreply.github.com Disable text rounding hack by default (flutter/engine#44544) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from 3d5a6138b7e5 to 491f67637e6e (4 revisions) (flutter/engine#44563) 2023-08-09 skia-flutter-autoroll@skia.org Manual roll Dart SDK from f664f4b9c50d to d89e4ead966d (11 revisions) (flutter/engine#44560) 2023-08-09 58529443+srujzs@users.noreply.github.com Make toJS'd function use JS types (flutter/engine#44469) 2023-08-09 xty50337@hotmail.com [web] Fix rendering of gradients in html mode (flutter/engine#40345) 2023-08-09 55360120+Matt2D@users.noreply.github.com Flutter iOS Interactive Keyboard: Fixing Animation Issue (flutter/engine#44514) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from 8c9a8d3e073c to 3d5a6138b7e5 (4 revisions) (flutter/engine#44557) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from d210bab77137 to 8c9a8d3e073c (1 revision) (flutter/engine#44555) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from 25aedb939915 to d210bab77137 (2 revisions) (flutter/engine#44550) 2023-08-09 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from e7bMhkfY-RPMrSMhB... to zoCGnScKZWbm5s9Hy... (flutter/engine#44548) 2023-08-09 skia-flutter-autoroll@skia.org Roll Skia from 17ba2122707b to 25aedb939915 (3 revisions) (flutter/engine#44547) 2023-08-09 47866232+chunhtai@users.noreply.github.com Android a11y bridge sets importantness (flutter/engine#44452) 2023-08-09 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from tO6r8iQqnmsYkLcvZ... to ZCP8LDbKF4LTBFz_W... (flutter/engine#44545) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from tO6r8iQqnmsY to ZCP8LDbKF4LT fuchsia/sdk/core/mac-amd64 from e7bMhkfY-RPM to zoCGnScKZWbm If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9ab1888b007aa..b1af1a1bee6a6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b5b41ff66dae3e0bf4a849e0bd9d44343db16dfb +9117ff27d9c9db8d78d487a0611d6a81ebe19fce diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 4a09256afc848..e2b329e1489a9 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -tO6r8iQqnmsYkLcvZA4V78wIgYbJaaz3RO_wyttfBLgC +ZCP8LDbKF4LTBFz_W5JeK5PEaIsrWaGGiH9iKZoHTJkC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 0f9e018d963c0..897d7691c8b22 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -e7bMhkfY-RPMrSMhBlm8WZT3x0sZhGnCxtkXrrLWuyYC +zoCGnScKZWbm5s9HyAjx76EBVB8sGlXfVdo-mqVQ5PMC From 35a3ef7eb5d5cffba4ff5a0b79acc68dfc41e970 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 03:23:24 -0400 Subject: [PATCH 0633/1547] Roll Flutter Engine from 9117ff27d9c9 to 02ac5e84097b (2 revisions) (#132288) https://github.com/flutter/engine/compare/9117ff27d9c9...02ac5e84097b 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from 7c5f6b17a998 to d9e9b7073171 (1 revision) (flutter/engine#44573) 2023-08-10 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ZCP8LDbKF4LTBFz_W... to 961_tJawsbLMdy5i0... (flutter/engine#44572) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ZCP8LDbKF4LT to 961_tJawsbLM If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b1af1a1bee6a6..f39ef7aff5656 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9117ff27d9c9db8d78d487a0611d6a81ebe19fce +02ac5e84097b69331855ab2d41174cc1fd533172 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index e2b329e1489a9..cb7517e421e6d 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ZCP8LDbKF4LTBFz_W5JeK5PEaIsrWaGGiH9iKZoHTJkC +961_tJawsbLMdy5i09FvefiD-ckFh6S_8yhK0SdtgW8C From bb6b72d6c66f62e2a13569241f4c7c711b5c5e9c Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 10 Aug 2023 11:36:17 +0300 Subject: [PATCH 0634/1547] Fix `DropdownButtonFormField` input border clipping (#131481) fixes [BUG: DropdownButtonFormField input decorator focus/hover is not clipped ](https://github.com/flutter/flutter/issues/131282) ### Description This fixes an issue where `DropdownButtonFormField`'s input border isn't used for clipping with `InkWell`. ### Before ![Screenshot 2023-07-28 at 17 06 20](https://github.com/flutter/flutter/assets/48603081/8fe1ee1f-5cea-4297-b4f6-e672d74bb583) ### After ![Screenshot 2023-07-28 at 17 06 38](https://github.com/flutter/flutter/assets/48603081/a0091459-67dc-45ca-96b1-95d7093d475f) --- .../flutter/lib/src/material/dropdown.dart | 33 ++++++- .../material/dropdown_form_field_test.dart | 97 +++++++++++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index 17bc7ec6d11bd..48adf8ebeaed6 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -15,6 +15,7 @@ import 'constants.dart'; import 'debug.dart'; import 'icons.dart'; import 'ink_well.dart'; +import 'input_border.dart'; import 'input_decorator.dart'; import 'material.dart'; import 'material_localizations.dart'; @@ -1633,6 +1634,7 @@ class DropdownButtonFormField extends FormField { } } final bool isEmpty = !showSelectedItem && !isHintOrDisabledHintAvailable(); + final bool hasError = effectiveDecoration.errorText != null; // An unfocusable Focus widget so that this widget can detect if its // descendants have focus or not. @@ -1640,6 +1642,33 @@ class DropdownButtonFormField extends FormField { canRequestFocus: false, skipTraversal: true, child: Builder(builder: (BuildContext context) { + final bool isFocused = Focus.of(context).hasFocus; + InputBorder? resolveInputBorder() { + if (hasError) { + if (isFocused) { + return effectiveDecoration.focusedErrorBorder; + } + return effectiveDecoration.errorBorder; + } + if (isFocused) { + return effectiveDecoration.focusedBorder; + } + if (effectiveDecoration.enabled) { + return effectiveDecoration.enabledBorder; + } + return effectiveDecoration.border; + } + BorderRadius? effectiveBorderRadius() { + final InputBorder? inputBorder = resolveInputBorder(); + if (inputBorder is OutlineInputBorder) { + return inputBorder.borderRadius; + } + if (inputBorder is UnderlineInputBorder) { + return inputBorder.borderRadius; + } + return null; + } + return DropdownButtonHideUnderline( child: DropdownButton._formField( items: items, @@ -1665,10 +1694,10 @@ class DropdownButtonFormField extends FormField { menuMaxHeight: menuMaxHeight, enableFeedback: enableFeedback, alignment: alignment, - borderRadius: borderRadius, + borderRadius: borderRadius ?? effectiveBorderRadius(), inputDecoration: effectiveDecoration.copyWith(errorText: field.errorText), isEmpty: isEmpty, - isFocused: Focus.of(context).hasFocus, + isFocused: isFocused, padding: padding, ), ); diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index 149733508f81a..6b13161d31c77 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -1134,4 +1135,100 @@ void main() { selectedItemBox.localToGlobal(Offset(selectedItemBox.size.width / 2.0, selectedItemBox.size.height / 2.0)), ); }); + + testWidgets('InputDecoration borders are used for clipping', (WidgetTester tester) async { + const BorderRadius errorBorderRadius = BorderRadius.all(Radius.circular(5.0)); + const BorderRadius focusedErrorBorderRadius = BorderRadius.all(Radius.circular(6.0)); + const BorderRadius focusedBorder = BorderRadius.all(Radius.circular(7.0)); + const BorderRadius enabledBorder = BorderRadius.all(Radius.circular(9.0)); + + final FocusNode focusNode = FocusNode(); + + const String errorText = 'This is an error'; + bool showError = false; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + inputDecorationTheme: const InputDecorationTheme( + errorBorder: OutlineInputBorder( + borderRadius: errorBorderRadius, + ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: focusedErrorBorderRadius, + ), + focusedBorder: OutlineInputBorder( + borderRadius: focusedBorder, + ), + enabledBorder: OutlineInputBorder( + borderRadius: enabledBorder, + ), + ), + ), + home: Material( + child: Center( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return DropdownButtonFormField( + value: 'two', + onChanged:(String? value) { + setState(() { + if (value == 'three') { + showError = true; + } else { + showError = false; + } + }); + }, + decoration: InputDecoration( + errorText: showError ? errorText : null, + ), + focusNode: focusNode, + items: menuItems.map>((String item) { + return DropdownMenuItem( + key: ValueKey(item), + value: item, + child: Text(item, key: ValueKey('${item}Text')), + ); + }).toList(), + ); + } + ), + ), + ), + ), + ); + + // Test enabled border. + InkWell inkWell = tester.widget(find.byType(InkWell)); + expect(inkWell.borderRadius, enabledBorder); + + // Test focused border. + focusNode.requestFocus(); + await tester.pump(); + + inkWell = tester.widget(find.byType(InkWell)); + expect(inkWell.borderRadius, focusedBorder); + + // Test focused error border. + await tester.tap(find.text('two'), warnIfMissed: false); + await tester.pumpAndSettle(); + await tester.tap(find.text('three').last); + await tester.pumpAndSettle(); + + inkWell = tester.widget(find.byType(InkWell)); + expect(inkWell.borderRadius, focusedErrorBorderRadius); + + // Test error border with no focus. + focusNode.unfocus(); + await tester.pump(); + + // Hovering over the widget should show the error border. + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.moveTo(tester.getCenter(find.text('three').last)); + await tester.pumpAndSettle(); + + inkWell = tester.widget(find.byType(InkWell)); + expect(inkWell.borderRadius, errorBorderRadius); + }); } From 7c59dfebb957fd8fe3fc0246ee366c8d1da0c817 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 06:52:01 -0400 Subject: [PATCH 0635/1547] Roll Flutter Engine from 02ac5e84097b to 2fe84892b90a (2 revisions) (#132294) https://github.com/flutter/engine/compare/02ac5e84097b...2fe84892b90a 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from d9e9b7073171 to a3975f2a9e79 (2 revisions) (flutter/engine#44577) 2023-08-10 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from zoCGnScKZWbm5s9Hy... to SoKcmsZ5H8uHJXV1S... (flutter/engine#44576) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from zoCGnScKZWbm to SoKcmsZ5H8uH If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f39ef7aff5656..697fa329b3d8b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -02ac5e84097b69331855ab2d41174cc1fd533172 +2fe84892b90abf9973cc10ae9f982ba9cb3cdad8 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 897d7691c8b22..02e28e469b838 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -zoCGnScKZWbm5s9HyAjx76EBVB8sGlXfVdo-mqVQ5PMC +SoKcmsZ5H8uHJXV1S-usFW2d9gflCTQCiZ7pJIgc7FcC From c428d9154859e21948f4214c86fff3c3dcd758b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 12:01:06 -0400 Subject: [PATCH 0636/1547] Roll Flutter Engine from 2fe84892b90a to 3359d6696da4 (1 revision) (#132305) https://github.com/flutter/engine/compare/2fe84892b90a...3359d6696da4 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from a3975f2a9e79 to 7a1fec6b197f (1 revision) (flutter/engine#44580) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 697fa329b3d8b..2224998f5aaf9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2fe84892b90abf9973cc10ae9f982ba9cb3cdad8 +3359d6696da41b64f8e923d59eb23c9ef183aa51 From 96e02c61dcc318e7062770f5db6d760b85a1e075 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 10 Aug 2023 19:05:03 +0300 Subject: [PATCH 0637/1547] Fix `PopupMenuItem` & `CheckedPopupMenuItem` has redundant `ListTile` padding and update default horizontal padding for Material 3 (#131609) fixes [`PopupMenuItem` adds redundant padding when using `ListItem`](https://github.com/flutter/flutter/issues/128553) ### Description - Fixed redundant `ListTile` padding when using `CheckedPopupMenuItem` or `PopupMenuItem` with the `ListTile` child for complex popup menu items as suggested in the docs. - Updated default horizontal padding for popup menu items. ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [PopupMenuButton]. // This is the type used by the popup menu below. enum SampleItem { itemOne, itemTwo, itemThree } void main() => runApp(const PopupMenuApp()); class PopupMenuApp extends StatelessWidget { const PopupMenuApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData(useMaterial3: true), home: const PopupMenuExample(), ); } } class PopupMenuExample extends StatefulWidget { const PopupMenuExample({super.key}); @override State createState() => _PopupMenuExampleState(); } class _PopupMenuExampleState extends State { SampleItem? selectedMenu; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('PopupMenuButton')), body: Center( child: SizedBox( width: 150, height: 100, child: Align( alignment: Alignment.topLeft, child: PopupMenuButton( initialValue: selectedMenu, // Callback that sets the selected popup menu item. onSelected: (SampleItem item) { setState(() { selectedMenu = item; }); }, itemBuilder: (BuildContext context) => >[ const PopupMenuItem( value: SampleItem.itemOne, child: Text('PopupMenuItem'), ), const CheckedPopupMenuItem( checked: true, value: SampleItem.itemTwo, child: Text('CheckedPopupMenuItem'), ), const PopupMenuItem( value: SampleItem.itemOne, child: ListTile( leading: Icon(Icons.cloud), title: Text('ListTile'), contentPadding: EdgeInsets.zero, trailing: Icon(Icons.arrow_right_rounded), ), ), ], ), ), ), ), ); } } ```
### Before ![image](https://github.com/flutter/flutter/assets/48603081/aad15ffb-ca11-4997-81d1-b46288161a4e) - Default horizontal padding is the same as M2 (16.0), while the specs use a smaller value (12.0) - `ListTile` nested by default in `CheckedPopupMenuItem` has redundant padding - `PopupMenuItem` using `ListTile` as a child for complex menu items contains redundant padding. ![Screenshot 2023-07-31 at 17 17 08](https://github.com/flutter/flutter/assets/48603081/75ad1fe5-e051-42ba-badf-e20c799dee96) ### After - Default horizontal padding is updated for Material 3. - `PopupMenuItem` & `CheckedPopupMenuItem` override `ListTile` padding (similar to how `ExpansionTile` overrides `ListTile` text and icon color. ![Screenshot 2023-07-31 at 17 17 25](https://github.com/flutter/flutter/assets/48603081/288cf892-5b51-4365-9855-5ef0ed2928e9) --- .../gen_defaults/lib/popup_menu_template.dart | 4 + .../flutter/lib/src/material/popup_menu.dart | 38 ++-- .../test/material/popup_menu_test.dart | 166 ++++++++++++++++++ 3 files changed, 197 insertions(+), 11 deletions(-) diff --git a/dev/tools/gen_defaults/lib/popup_menu_template.dart b/dev/tools/gen_defaults/lib/popup_menu_template.dart index f11b89c9500e9..bed11d0b8b09a 100644 --- a/dev/tools/gen_defaults/lib/popup_menu_template.dart +++ b/dev/tools/gen_defaults/lib/popup_menu_template.dart @@ -42,5 +42,9 @@ class _${blockName}DefaultsM3 extends PopupMenuThemeData { @override ShapeBorder? get shape => ${shape("md.comp.menu.container")}; + + // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs + // Update this when the token is available. + static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); }'''; } diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index ef8f4367c6b43..7a3f7a5249bff 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -14,6 +14,7 @@ import 'icon_button.dart'; import 'icons.dart'; import 'ink_well.dart'; import 'list_tile.dart'; +import 'list_tile_theme.dart'; import 'material.dart'; import 'material_localizations.dart'; import 'material_state.dart'; @@ -32,7 +33,6 @@ import 'tooltip.dart'; const Duration _kMenuDuration = Duration(milliseconds: 300); const double _kMenuCloseIntervalEnd = 2.0 / 3.0; -const double _kMenuHorizontalPadding = 16.0; const double _kMenuDividerHeight = 16.0; const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; @@ -255,7 +255,11 @@ class PopupMenuItem extends PopupMenuEntry { /// If a [height] greater than the height of the sum of the padding and [child] /// is provided, then the padding's effect will not be visible. /// - /// When null, the horizontal padding defaults to 16.0 on both sides. + /// If this is null and [ThemeData.useMaterial3] is true, the horizontal padding + /// defaults to 12.0 on both sides. + /// + /// If this is null and [ThemeData.useMaterial3] is false, the horizontal padding + /// defaults to 16.0 on both sides. final EdgeInsets? padding; /// The text style of the popup menu item. @@ -372,7 +376,7 @@ class PopupMenuItemState> extends State { child: Container( alignment: AlignmentDirectional.centerStart, constraints: BoxConstraints(minHeight: widget.height), - padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: _kMenuHorizontalPadding), + padding: widget.padding ?? (theme.useMaterial3 ? _PopupMenuDefaultsM3.menuHorizontalPadding : _PopupMenuDefaultsM2.menuHorizontalPadding), child: buildChild(), ), ); @@ -393,7 +397,10 @@ class PopupMenuItemState> extends State { onTap: widget.enabled ? handleTap : null, canRequestFocus: widget.enabled, mouseCursor: _EffectiveMouseCursor(widget.mouseCursor, popupMenuTheme.mouseCursor), - child: item, + child: ListTileTheme.merge( + contentPadding: EdgeInsets.zero, + child: item, + ), ), ), ); @@ -540,14 +547,17 @@ class _CheckedPopupMenuItemState extends PopupMenuItemState _textTheme.subtitle1; + + static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 16.0); } // BEGIN GENERATED TOKEN PROPERTIES - PopupMenu @@ -1465,5 +1477,9 @@ class _PopupMenuDefaultsM3 extends PopupMenuThemeData { @override ShapeBorder? get shape => const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))); + + // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs + // Update this when the token is available. + static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); } // END GENERATED TOKEN PROPERTIES - PopupMenu diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index f26ed5a03adc7..60c576797dcd8 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1553,6 +1553,82 @@ void main() { ); }); + testWidgets('Material3 - PopupMenuItem default padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + value: '0', + enabled: false, + child: Text('Item 0'), + ), + const PopupMenuItem( + value: '1', + child: Text('Item 1'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + expect(tester.widget(find.widgetWithText(Container, 'Item 0')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); + expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); + }); + + testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + value: '0', + enabled: false, + child: Text('Item 0'), + ), + const PopupMenuItem( + value: '1', + child: Text('Item 1'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + expect(tester.widget(find.widgetWithText(Container, 'Item 0')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); + expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); + }); + testWidgets('PopupMenuItem custom padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -3415,6 +3491,96 @@ void main() { labelTextStyle.resolve({MaterialState.selected}) ); }); + + testWidgets('CheckedPopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const CheckedPopupMenuItem( + value: '0', + child: Text('Item 0'), + ), + const CheckedPopupMenuItem( + value: '1', + checked: true, + child: Text('Item 1'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + SafeArea getItemSafeArea(String label) { + return tester.widget(find.ancestor( + of: find.text(label), + matching: find.byType(SafeArea), + )); + } + + expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); + expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); + }); + + testWidgets('PopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + value: '0', + enabled: false, + child: ListTile(title: Text('Item 0')), + ), + const PopupMenuItem( + value: '1', + child: ListTile(title: Text('Item 1')), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + SafeArea getItemSafeArea(String label) { + return tester.widget(find.ancestor( + of: find.text(label), + matching: find.byType(SafeArea), + )); + } + + expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); + expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); + }); } class TestApp extends StatelessWidget { From bd1bb675b3dff2f782952e5681ea9542fad7733d Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 10 Aug 2023 09:25:02 -0700 Subject: [PATCH 0638/1547] Remove bringup from Windows build_tests shards (#132306) Context: https://github.com/flutter/flutter/commit/aff8ef13d428395725ce8f836ca771b8bf2d87db --- .ci.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 2ca4af28d2af1..7f123a728d599 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4187,7 +4187,6 @@ targets: - .ci.yaml - name: Windows build_tests_1_5 - bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4206,7 +4205,6 @@ targets: ["framework", "hostonly", "shard", "windows"] - name: Windows build_tests_2_5 - bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4225,7 +4223,6 @@ targets: ["framework", "hostonly", "shard", "windows"] - name: Windows build_tests_3_5 - bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4244,7 +4241,6 @@ targets: ["framework", "hostonly", "shard", "windows"] - name: Windows build_tests_4_5 - bringup: true recipe: flutter/flutter_drone timeout: 60 properties: @@ -4263,7 +4259,6 @@ targets: ["framework", "hostonly", "shard", "windows"] - name: Windows build_tests_5_5 - bringup: true recipe: flutter/flutter_drone timeout: 60 properties: From 52a6de255871bc4b13b0e4b35402745b425dd26e Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 10 Aug 2023 09:38:38 -0700 Subject: [PATCH 0639/1547] Add `--local-engine-host`, which if specified, is used instead of being inferred (#132180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/flutter/flutter/issues/132162. I did a tiny bit of minor cleanup but didn't want to go 🍔 beyond the scope of this change. After it lands I'll update the Wiki. ## Before ```bash $ fl run \ --local-engine-src-path=$ENGINE \ --local-engine=android_debug_unopt_arm64 ``` ... would try to use `host_debug_unopt` (i.e. Rosetta). ## After ```bash $ fl run \ --local-engine-src-path=$ENGINE \ --local-engine=android_debug_unopt_arm64 \ --local-engine-host=host_debug_unopt_arm64 ``` ... uses `host_debug_unopt_arm64`, as specified. --- /cc @jonahwilliams @gaaclarke @zanderso --- .../flutter_gallery/macos/Podfile.lock | 4 +- .../lib/src/base/user_messages.dart | 6 +++ .../src/runner/flutter_command_runner.dart | 9 ++++ .../lib/src/runner/local_engine.dart | 36 ++++++++++--- .../runner/local_engine_test.dart | 52 +++++++++++++++++++ 5 files changed, 97 insertions(+), 10 deletions(-) diff --git a/dev/integration_tests/flutter_gallery/macos/Podfile.lock b/dev/integration_tests/flutter_gallery/macos/Podfile.lock index 7fc925bb07325..04d3145211d20 100644 --- a/dev/integration_tests/flutter_gallery/macos/Podfile.lock +++ b/dev/integration_tests/flutter_gallery/macos/Podfile.lock @@ -28,8 +28,8 @@ SPEC CHECKSUMS: connectivity_macos: 5dae6ee11d320fac7c05f0d08bd08fc32b5514d9 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 - url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451 + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 PODFILE CHECKSUM: 2e6060c123c393d6beb3ee5b7beaf789de4d2e47 -COCOAPODS: 1.12.0 +COCOAPODS: 1.12.1 diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 1c13db18f95e6..780561311efb3 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -308,6 +308,12 @@ class UserMessages { "you have compiled the engine in that directory, which should produce an 'out' directory"; String get runnerLocalEngineOrWebSdkRequired => 'You must specify --local-engine or --local-web-sdk if you are using a locally built engine or web sdk.'; + // TODO(matanlurey): Make this an error, https://github.com/flutter/flutter/issues/132245. + String get runnerLocalEngineRequiresHostEngine => + 'Warning! You are using a locally built engine (--local-engine) but have not specified --local-host-engine.\n' + 'You may be building with a different engine than the one you are running with. ' + 'See https://github.com/flutter/flutter/issues/132245 for details (in the future this will become ' + 'an error).'; String runnerNoEngineBuild(String engineBuildPath) => 'No Flutter engine build found at $engineBuildPath.'; String runnerNoWebSdk(String webSdkPath) => diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index 5d6d78639fb66..0f752bc98b625 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -30,6 +30,7 @@ abstract final class FlutterGlobalOptions { static const String kEnableTelemetryFlag = 'enable-telemetry'; static const String kLocalEngineOption = 'local-engine'; static const String kLocalEngineSrcPathOption = 'local-engine-src-path'; + static const String kLocalEngineHostOption = 'local-engine-host'; static const String kLocalWebSDKOption = 'local-web-sdk'; static const String kMachineFlag = 'machine'; static const String kPackagesOption = 'packages'; @@ -131,6 +132,13 @@ class FlutterCommandRunner extends CommandRunner { 'Use this to select a specific version of the engine if you have built multiple engine targets.\n' 'This path is relative to "--local-engine-src-path" (see above).'); + argParser.addOption(FlutterGlobalOptions.kLocalEngineHostOption, + hide: !verboseHelp, + help: 'The host operating system for which engine artifacts should be selected, if you are building Flutter locally.\n' + 'This is only used when "--local-engine" is also specified.\n' + 'By default, the host is determined automatically, but you may need to specify this if you are building on one ' + 'platform (e.g. MacOS ARM64) but intend to run Flutter on another (e.g. Android).'); + argParser.addOption(FlutterGlobalOptions.kLocalWebSDKOption, hide: !verboseHelp, help: 'Name of a build output within the engine out directory, if you are building Flutter locally.\n' @@ -273,6 +281,7 @@ class FlutterCommandRunner extends CommandRunner { final EngineBuildPaths? engineBuildPaths = await globals.localEngineLocator?.findEnginePath( engineSourcePath: topLevelResults[FlutterGlobalOptions.kLocalEngineSrcPathOption] as String?, localEngine: topLevelResults[FlutterGlobalOptions.kLocalEngineOption] as String?, + localHostEngine: topLevelResults[FlutterGlobalOptions.kLocalEngineHostOption] as String?, localWebSdk: topLevelResults[FlutterGlobalOptions.kLocalWebSDKOption] as String?, packagePath: topLevelResults[FlutterGlobalOptions.kPackagesOption] as String?, ); diff --git a/packages/flutter_tools/lib/src/runner/local_engine.dart b/packages/flutter_tools/lib/src/runner/local_engine.dart index e5911f2c2df0a..57c9c19a8b73d 100644 --- a/packages/flutter_tools/lib/src/runner/local_engine.dart +++ b/packages/flutter_tools/lib/src/runner/local_engine.dart @@ -13,7 +13,7 @@ import '../base/user_messages.dart' hide userMessages; import '../cache.dart'; import '../dart/package_map.dart'; -/// A strategy for locating the out/ directory of a local engine build. +/// A strategy for locating the `out/` directory of a local engine build. /// /// The flutter tool can be run with the output files of one or more engine builds /// replacing the cached artifacts. Typically this is done by setting the @@ -25,7 +25,7 @@ import '../dart/package_map.dart'; /// For scenarios where the engine is not adjacent to flutter, the /// `--local-engine-src-path` can be provided to give an exact path. /// -/// For more information on local engines, see CONTRIBUTING.md. +/// For more information on local engines, see README.md. class LocalEngineLocator { LocalEngineLocator({ required Platform platform, @@ -46,7 +46,13 @@ class LocalEngineLocator { final UserMessages _userMessages; /// Returns the engine build path of a local engine if one is located, otherwise `null`. - Future findEnginePath({String? engineSourcePath, String? localEngine, String? localWebSdk, String? packagePath}) async { + Future findEnginePath({ + String? engineSourcePath, + String? localEngine, + String? localHostEngine, + String? localWebSdk, + String? packagePath, + }) async { engineSourcePath ??= _platform.environment[kFlutterEngineEnvironmentVariableName]; if (engineSourcePath == null && localEngine == null && localWebSdk == null && packagePath == null) { return null; @@ -81,7 +87,12 @@ class LocalEngineLocator { if (engineSourcePath != null) { _logger.printTrace('Local engine source at $engineSourcePath'); - return _findEngineBuildPath(localEngine, localWebSdk, engineSourcePath); + return _findEngineBuildPath( + engineSourcePath: engineSourcePath, + localEngine: localEngine, + localWebSdk: localWebSdk, + localHostEngine: localHostEngine, + ); } if (localEngine != null || localWebSdk != null) { throwToolExit( @@ -176,7 +187,12 @@ class LocalEngineLocator { return 'host_$tmpBasename'; } - EngineBuildPaths _findEngineBuildPath(String? localEngine, String? localWebSdk, String enginePath) { + EngineBuildPaths _findEngineBuildPath({ + required String engineSourcePath, + String? localEngine, + String? localWebSdk, + String? localHostEngine, + }) { if (localEngine == null && localWebSdk == null) { throwToolExit(_userMessages.runnerLocalEngineOrWebSdkRequired, exitCode: 2); } @@ -184,12 +200,16 @@ class LocalEngineLocator { String? engineBuildPath; String? engineHostBuildPath; if (localEngine != null) { - engineBuildPath = _fileSystem.path.normalize(_fileSystem.path.join(enginePath, 'out', localEngine)); + engineBuildPath = _fileSystem.path.normalize(_fileSystem.path.join(engineSourcePath, 'out', localEngine)); if (!_fileSystem.isDirectorySync(engineBuildPath)) { throwToolExit(_userMessages.runnerNoEngineBuild(engineBuildPath), exitCode: 2); } - final String basename = _fileSystem.path.basename(engineBuildPath); + if (localHostEngine == null) { + // TODO(matanlurey): https://github.com/flutter/flutter/issues/132245, change to throwToolExit. + _logger.printStatus(_userMessages.runnerLocalEngineRequiresHostEngine); + } + final String basename = localHostEngine ?? _fileSystem.path.basename(engineBuildPath); final String hostBasename = _getHostEngineBasename(basename); engineHostBuildPath = _fileSystem.path.normalize( _fileSystem.path.join(_fileSystem.path.dirname(engineBuildPath), hostBasename), @@ -201,7 +221,7 @@ class LocalEngineLocator { String? webSdkPath; if (localWebSdk != null) { - webSdkPath = _fileSystem.path.normalize(_fileSystem.path.join(enginePath, 'out', localWebSdk)); + webSdkPath = _fileSystem.path.normalize(_fileSystem.path.join(engineSourcePath, 'out', localWebSdk)); if (!_fileSystem.isDirectorySync(webSdkPath)) { throwToolExit(_userMessages.runnerNoWebSdk(webSdkPath), exitCode: 2); } diff --git a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart index 2845922dcf44f..f2f3aedcbf315 100644 --- a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart @@ -93,6 +93,58 @@ void main() { expect(logger.traceText, contains('Local engine source at /arbitrary/engine/src')); }); + testWithoutContext('works if --local-engine is specified and --local-engine-host is specified', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final Directory localEngine = fileSystem + .directory('$kArbitraryEngineRoot/src/out/android_debug_unopt_arm64/') + ..createSync(recursive: true); + fileSystem.directory('$kArbitraryEngineRoot/src/out/host_debug_unopt_arm64/').createSync(recursive: true); + + final BufferLogger logger = BufferLogger.test(); + final LocalEngineLocator localEngineLocator = LocalEngineLocator( + fileSystem: fileSystem, + flutterRoot: 'flutter/flutter', + logger: logger, + userMessages: UserMessages(), + platform: FakePlatform(environment: {}), + ); + + expect( + await localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: 'host_debug_unopt_arm64'), + matchesEngineBuildPaths( + hostEngine: '/arbitrary/engine/src/out/host_debug_unopt_arm64', + targetEngine: '/arbitrary/engine/src/out/android_debug_unopt_arm64', + ), + ); + expect(logger.traceText, contains('Local engine source at /arbitrary/engine/src')); + }); + + testWithoutContext('works but produces a warning if --local-engine is specified but not --local-host-engine', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final Directory localEngine = fileSystem + .directory('$kArbitraryEngineRoot/src/out/android_debug_unopt_arm64/') + ..createSync(recursive: true); + fileSystem.directory('$kArbitraryEngineRoot/src/out/host_debug_unopt/').createSync(recursive: true); + + final BufferLogger logger = BufferLogger.test(); + final LocalEngineLocator localEngineLocator = LocalEngineLocator( + fileSystem: fileSystem, + flutterRoot: 'flutter/flutter', + logger: logger, + userMessages: UserMessages(), + platform: FakePlatform(environment: {}), + ); + + expect( + await localEngineLocator.findEnginePath(localEngine: localEngine.path), + matchesEngineBuildPaths( + hostEngine: '/arbitrary/engine/src/out/host_debug_unopt', + targetEngine: '/arbitrary/engine/src/out/android_debug_unopt_arm64', + ), + ); + expect(logger.statusText, contains('Warning! You are using a locally built engine (--local-engine) but have not specified --local-host-engine')); + }); + testWithoutContext('works if --local-engine is specified and --local-engine-src-path ' 'is determined by --local-engine', () async { final FileSystem fileSystem = MemoryFileSystem.test(); From e11cc3507608d145154076482002b7953a984692 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 13:04:32 -0400 Subject: [PATCH 0640/1547] Roll Flutter Engine from 3359d6696da4 to e2ed1bebf31d (1 revision) (#132311) https://github.com/flutter/engine/compare/3359d6696da4...e2ed1bebf31d 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from 7a1fec6b197f to aac2d55d35eb (1 revision) (flutter/engine#44582) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2224998f5aaf9..ddfa21b8a5d6f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3359d6696da41b64f8e923d59eb23c9ef183aa51 +e2ed1bebf31d9e6fccf78d0fa5f27743fff1f246 From 64a0683b4197621082556edb9f16c6f987904230 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Thu, 10 Aug 2023 10:18:12 -0700 Subject: [PATCH 0641/1547] Analyze code snippets in flutter_test docs (#132246) Fixes https://github.com/flutter/flutter/issues/132274. --- dev/bots/analyze_snippet_code.dart | 32 ++++---- packages/flutter_test/lib/flutter_test.dart | 2 +- .../flutter_test/lib/src/accessibility.dart | 3 + .../flutter_test/lib/src/animation_sheet.dart | 4 +- packages/flutter_test/lib/src/binding.dart | 6 +- .../flutter_test/lib/src/buffer_matcher.dart | 74 ------------------- packages/flutter_test/lib/src/controller.dart | 9 ++- packages/flutter_test/lib/src/finders.dart | 24 +++--- packages/flutter_test/lib/src/matchers.dart | 74 ++++++++++++------- .../flutter_test/lib/src/mock_canvas.dart | 12 ++- packages/flutter_test/lib/src/nonconst.dart | 6 +- .../lib/src/recording_canvas.dart | 3 + .../lib/src/test_async_utils.dart | 3 + .../flutter_test/lib/src/widget_tester.dart | 20 +++-- packages/flutter_test/lib/src/window.dart | 2 +- 15 files changed, 128 insertions(+), 146 deletions(-) delete mode 100644 packages/flutter_test/lib/src/buffer_matcher.dart diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index edcbd88cb00f2..b98b6ae0bc7c2 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -70,7 +70,8 @@ import 'package:path/path.dart' as path; import 'package:watcher/watcher.dart'; final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); -final String _defaultFlutterPackage = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); +final String _packageFlutter = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); +final String _packageFlutterTest = path.join(_flutterRoot, 'packages', 'flutter_test', 'lib'); final String _defaultDartUiLocation = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui'); final String _flutter = path.join(_flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); @@ -142,12 +143,16 @@ Future main(List arguments) async { exit(0); } - Directory flutterPackage; + List flutterPackages; if (parsedArguments.rest.length == 1) { // Used for testing. - flutterPackage = Directory(parsedArguments.rest.single); + flutterPackages = [Directory(parsedArguments.rest.single)]; } else { - flutterPackage = Directory(_defaultFlutterPackage); + flutterPackages = [ + Directory(_packageFlutter), + Directory(_packageFlutterTest), + // TODO(goderbauer): Add all other packages. + ]; } final bool includeDartUi = parsedArguments.wasParsed('dart-ui-location') || parsedArguments['include-dart-ui'] as bool; @@ -165,14 +170,14 @@ Future main(List arguments) async { if (parsedArguments['interactive'] != null) { await _runInteractive( - flutterPackage: flutterPackage, + flutterPackages: flutterPackages, tempDirectory: parsedArguments['temp'] as String?, filePath: parsedArguments['interactive'] as String, dartUiLocation: includeDartUi ? dartUiLocation : null, ); } else { if (await _SnippetChecker( - flutterPackage, + flutterPackages, tempDirectory: parsedArguments['temp'] as String?, verbose: parsedArguments['verbose'] as bool, dartUiLocation: includeDartUi ? dartUiLocation : null, @@ -360,7 +365,7 @@ class _SnippetChecker { /// supplied, the default location of the `dart:ui` code in the Flutter /// repository is used (i.e. "/bin/cache/pkg/sky_engine/lib/ui"). _SnippetChecker( - this._flutterPackage, { + this._flutterPackages, { String? tempDirectory, this.verbose = false, Directory? dartUiLocation, @@ -438,8 +443,8 @@ class _SnippetChecker { /// automatically if there are no errors unless _keepTmp is true. final Directory _tempDirectory; - /// The package directory for the flutter package within the flutter root dir. - final Directory _flutterPackage; + /// The package directories within the flutter root dir that will be checked. + final List _flutterPackages; /// The directory for the dart:ui code to be analyzed with the flutter code. /// @@ -481,7 +486,7 @@ class _SnippetChecker { "import 'dart:typed_data';", "import 'dart:ui' as ui;", "import 'package:flutter_test/flutter_test.dart';", - for (final File file in _listDartFiles(Directory(_defaultFlutterPackage))) + for (final File file in _listDartFiles(Directory(_packageFlutter))) "import 'package:flutter/${path.basename(file.path)}';", ].map<_Line>((String code) => _Line.generated(code: code)).toList(); } @@ -495,7 +500,8 @@ class _SnippetChecker { stderr.writeln('Unable to analyze engine dart snippets at ${_dartUiLocation!.path}.'); } final List filesToAnalyze = [ - ..._listDartFiles(_flutterPackage, recursive: true), + for (final Directory flutterPackage in _flutterPackages) + ..._listDartFiles(flutterPackage, recursive: true), if (_dartUiLocation != null && _dartUiLocation!.existsSync()) ..._listDartFiles(_dartUiLocation!, recursive: true), ]; @@ -1084,7 +1090,7 @@ class _SnippetFile { Future _runInteractive({ required String? tempDirectory, - required Directory flutterPackage, + required List flutterPackages, required String filePath, required Directory? dartUiLocation, }) async { @@ -1106,7 +1112,7 @@ Future _runInteractive({ print('Starting up in interactive mode on ${path.relative(filePath, from: _flutterRoot)} ...'); print('Type "q" to quit, or "r" to force a reload.'); - final _SnippetChecker checker = _SnippetChecker(flutterPackage, tempDirectory: tempDirectory) + final _SnippetChecker checker = _SnippetChecker(flutterPackages, tempDirectory: tempDirectory) .._createConfigurationFiles(); ProcessSignal.sigint.watch().listen((_) { diff --git a/packages/flutter_test/lib/flutter_test.dart b/packages/flutter_test/lib/flutter_test.dart index 74483c1561bf4..642f6973114b1 100644 --- a/packages/flutter_test/lib/flutter_test.dart +++ b/packages/flutter_test/lib/flutter_test.dart @@ -27,7 +27,7 @@ /// with the following signature: /// /// ```dart -/// Future testExecutable(FutureOr Function() testMain); +/// Future testExecutable(FutureOr Function() testMain) async { } /// ``` /// /// The test framework will execute that method and pass it the `main()` method diff --git a/packages/flutter_test/lib/src/accessibility.dart b/packages/flutter_test/lib/src/accessibility.dart index 7faeb4a386259..17d711d2500f5 100644 --- a/packages/flutter_test/lib/src/accessibility.dart +++ b/packages/flutter_test/lib/src/accessibility.dart @@ -57,6 +57,9 @@ class Evaluation { } } +// Examples can assume: +// typedef HomePage = Placeholder; + /// An accessibility guideline describes a recommendation an application should /// meet to be considered accessible. /// diff --git a/packages/flutter_test/lib/src/animation_sheet.dart b/packages/flutter_test/lib/src/animation_sheet.dart index 22973287e9fee..aa69e50970908 100644 --- a/packages/flutter_test/lib/src/animation_sheet.dart +++ b/packages/flutter_test/lib/src/animation_sheet.dart @@ -55,14 +55,14 @@ import 'package:flutter/widgets.dart'; /// // Start recording (`recording` is true) /// await tester.pumpFrames(animationSheet.record( /// target, -/// recording: true, +/// recording: true, // ignore: avoid_redundant_argument_values /// ), const Duration(seconds: 1)); /// /// await gesture.up(); /// /// await tester.pumpFrames(animationSheet.record( /// target, -/// recording: true, +/// recording: true, // ignore: avoid_redundant_argument_values /// ), const Duration(seconds: 1)); /// /// // Compare against golden file diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index c3c289b016ed1..466bf05ce4dd3 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -143,6 +143,10 @@ class CapturedAccessibilityAnnouncement { final Assertiveness assertiveness; } +// Examples can assume: +// late TestWidgetsFlutterBinding binding; +// late Size someSize; + /// Base class for bindings used by widgets library tests. /// /// The [ensureInitialized] method creates (if necessary) and returns an @@ -1548,7 +1552,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { /// ```dart /// TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); /// if (binding is LiveTestWidgetsFlutterBinding) { -/// binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.[thePolicy]; +/// binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.onlyPumps; /// } /// ``` /// {@endtemplate} diff --git a/packages/flutter_test/lib/src/buffer_matcher.dart b/packages/flutter_test/lib/src/buffer_matcher.dart deleted file mode 100644 index 6c621e6c27ac7..0000000000000 --- a/packages/flutter_test/lib/src/buffer_matcher.dart +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:typed_data'; - -import 'package:matcher/expect.dart' show Description; -import 'package:matcher/src/expect/async_matcher.dart'; // ignore: implementation_imports -import 'package:test_api/hooks.dart' show TestFailure; - -import 'goldens.dart'; - -/// Matcher created by [bufferMatchesGoldenFile]. -class _BufferGoldenMatcher extends AsyncMatcher { - /// Creates an instance of [BufferGoldenMatcher]. Called by [bufferMatchesGoldenFile]. - const _BufferGoldenMatcher(this.key, this.version); - - /// The [key] to the golden image. - final Uri key; - - /// The [version] of the golden image. - final int? version; - - @override - Future matchAsync(dynamic item) async { - Uint8List buffer; - if (item is List) { - buffer = Uint8List.fromList(item); - } else if (item is Future>) { - buffer = Uint8List.fromList(await item); - } else { - throw AssertionError('Expected `List` or `Future>`, instead found: ${item.runtimeType}'); - } - final Uri testNameUri = goldenFileComparator.getTestUri(key, version); - if (autoUpdateGoldenFiles) { - await goldenFileComparator.update(testNameUri, buffer); - return null; - } - try { - final bool success = await goldenFileComparator.compare(buffer, testNameUri); - return success ? null : 'does not match'; - } on TestFailure catch (ex) { - return ex.message; - } - } - - @override - Description describe(Description description) { - final Uri testNameUri = goldenFileComparator.getTestUri(key, version); - return description.add('Byte buffer matches golden image "$testNameUri"'); - } -} - -/// Asserts that a [Future>], or [List[ /* bytes... */ ], -/// bufferMatchesGoldenFile('sample.png'), -/// ); -/// ``` -/// {@end-tool} -AsyncMatcher bufferMatchesGoldenFile(String key, {int? version}) { - return _BufferGoldenMatcher(Uri.parse(key), version); -} diff --git a/packages/flutter_test/lib/src/controller.dart b/packages/flutter_test/lib/src/controller.dart index 9443e36ec97a7..3a89d3cdaf91a 100644 --- a/packages/flutter_test/lib/src/controller.dart +++ b/packages/flutter_test/lib/src/controller.dart @@ -24,6 +24,9 @@ const double kDragSlopDefault = 20.0; const String _defaultPlatform = kIsWeb ? 'web' : 'android'; +// Examples can assume: +// typedef MyWidget = Placeholder; + /// Class that programmatically interacts with the [Semantics] tree. /// /// Allows for testing of the [Semantics] tree, which is used by assistive @@ -123,13 +126,13 @@ class SemanticsController { /// /// ## Sample Code /// - /// ``` + /// ```dart /// testWidgets('MyWidget', (WidgetTester tester) async { - /// await tester.pumpWidget(MyWidget()); + /// await tester.pumpWidget(const MyWidget()); /// /// expect( /// tester.semantics.simulatedAccessibilityTraversal(), - /// containsAllInOrder([ + /// containsAllInOrder([ /// containsSemantics(label: 'My Widget'), /// containsSemantics(label: 'is awesome!', isChecked: true), /// ]), diff --git a/packages/flutter_test/lib/src/finders.dart b/packages/flutter_test/lib/src/finders.dart index e1afcc8fa8cc0..a79a5575c2595 100644 --- a/packages/flutter_test/lib/src/finders.dart +++ b/packages/flutter_test/lib/src/finders.dart @@ -17,6 +17,12 @@ typedef ElementPredicate = bool Function(Element element); /// Some frequently used widget [Finder]s. const CommonFinders find = CommonFinders._(); +// Examples can assume: +// typedef Button = Placeholder; +// late WidgetTester tester; +// late String filePath; +// late Key backKey; + /// Provides lightweight syntax for getting frequently used widget [Finder]s. /// /// This class is instantiated once, as [find]. @@ -116,9 +122,9 @@ class CommonFinders { /// /// ```dart /// // Suppose you have a button with text 'Update' in it: - /// Button( + /// const Button( /// child: Text('Update') - /// ) + /// ); /// /// // You can find and tap on it like this: /// tester.tap(find.widgetWithText(Button, 'Update')); @@ -217,9 +223,9 @@ class CommonFinders { /// /// ```dart /// // Suppose you have a button with icon 'arrow_forward' in it: - /// Button( + /// const Button( /// child: Icon(Icons.arrow_forward) - /// ) + /// ); /// /// // You can find and tap on it like this: /// tester.tap(find.widgetWithIcon(Button, Icons.arrow_forward)); @@ -242,11 +248,11 @@ class CommonFinders { /// ```dart /// // Suppose you have a button with image in it: /// Button( - /// child: Image.file(filePath) - /// ) + /// child: Image.file(File(filePath)) + /// ); /// /// // You can find and tap on it like this: - /// tester.tap(find.widgetWithImage(Button, FileImage(filePath))); + /// tester.tap(find.widgetWithImage(Button, FileImage(File(filePath)))); /// ``` /// /// If the `skipOffstage` argument is true (the default), then this skips @@ -283,7 +289,7 @@ class CommonFinders { /// /// ```dart /// // Suppose you have a button created like this: - /// Widget myButton = Button( + /// Widget myButton = const Button( /// child: Text('Update') /// ); /// @@ -396,7 +402,7 @@ class CommonFinders { /// tester.widget( /// find.ancestor( /// of: find.text('faded'), - /// matching: find.byType('Opacity'), + /// matching: find.byType(Opacity), /// ) /// ).opacity, /// 0.5 diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index 7da2de31aa4f7..1e97df7cdfeca 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -331,6 +331,13 @@ Matcher isMethodCall(String name, { required dynamic arguments }) { Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int sampleSize = 20 }) => _CoversSameAreaAs(expectedPath, areaToCompare: areaToCompare, sampleSize: sampleSize); +// Examples can assume: +// late Image image; +// late Future imageFuture; +// typedef MyWidget = Placeholder; +// late Future someFont; +// late WidgetTester tester; + /// Asserts that a [Finder], [Future], or [ui.Image] matches the /// golden image file identified by [key], with an optional [version] number. /// @@ -404,18 +411,18 @@ Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int s /// {@tool snippet} /// How to load a custom font for golden images. /// ```dart -/// testWidgets('Creating a golden image with a custom font', (tester) async { +/// testWidgets('Creating a golden image with a custom font', (WidgetTester tester) async { /// // Assuming the 'Roboto.ttf' file is declared in the pubspec.yaml file -/// final font = rootBundle.load('path/to/font-file/Roboto.ttf'); +/// final Future font = rootBundle.load('path/to/font-file/Roboto.ttf'); /// -/// final fontLoader = FontLoader('Roboto')..addFont(font); +/// final FontLoader fontLoader = FontLoader('Roboto')..addFont(font); /// await fontLoader.load(); /// -/// await tester.pumpWidget(const SomeWidget()); +/// await tester.pumpWidget(const MyWidget()); /// /// await expectLater( -/// find.byType(SomeWidget), -/// matchesGoldenFile('someWidget.png'), +/// find.byType(MyWidget), +/// matchesGoldenFile('myWidget.png'), /// ); /// }); /// ``` @@ -431,7 +438,7 @@ Matcher coversSameAreaAs(Path expectedPath, { required Rect areaToCompare, int s /// ```dart /// Future testExecutable(FutureOr Function() testMain) async { /// setUpAll(() async { -/// final fontLoader = FontLoader('SomeFont')..addFont(someFont); +/// final FontLoader fontLoader = FontLoader('SomeFont')..addFont(someFont); /// await fontLoader.load(); /// }); /// @@ -473,18 +480,20 @@ AsyncMatcher matchesGoldenFile(Object key, {int? version}) { /// ## Sample code /// /// ```dart -/// final ui.Paint paint = ui.Paint() -/// ..style = ui.PaintingStyle.stroke -/// ..strokeWidth = 1.0; -/// final ui.PictureRecorder recorder = ui.PictureRecorder(); -/// final ui.Canvas pictureCanvas = ui.Canvas(recorder); -/// pictureCanvas.drawCircle(Offset.zero, 20.0, paint); -/// final ui.Picture picture = recorder.endRecording(); -/// ui.Image referenceImage = picture.toImage(50, 50); -/// -/// await expectLater(find.text('Save'), matchesReferenceImage(referenceImage)); -/// await expectLater(image, matchesReferenceImage(referenceImage); -/// await expectLater(imageFuture, matchesReferenceImage(referenceImage)); +/// testWidgets('matchesReferenceImage', (WidgetTester tester) async { +/// final ui.Paint paint = ui.Paint() +/// ..style = ui.PaintingStyle.stroke +/// ..strokeWidth = 1.0; +/// final ui.PictureRecorder recorder = ui.PictureRecorder(); +/// final ui.Canvas pictureCanvas = ui.Canvas(recorder); +/// pictureCanvas.drawCircle(Offset.zero, 20.0, paint); +/// final ui.Picture picture = recorder.endRecording(); +/// ui.Image referenceImage = await picture.toImage(50, 50); +/// +/// await expectLater(find.text('Save'), matchesReferenceImage(referenceImage)); +/// await expectLater(image, matchesReferenceImage(referenceImage)); +/// await expectLater(imageFuture, matchesReferenceImage(referenceImage)); +/// }); /// ``` /// /// See also: @@ -508,9 +517,12 @@ AsyncMatcher matchesReferenceImage(ui.Image image) { /// ## Sample code /// /// ```dart -/// final SemanticsHandle handle = tester.ensureSemantics(); -/// expect(tester.getSemantics(find.text('hello')), matchesSemantics(label: 'hello')); -/// handle.dispose(); +/// testWidgets('matchesSemantics', (WidgetTester tester) async { +/// final SemanticsHandle handle = tester.ensureSemantics(); +/// // ... +/// expect(tester.getSemantics(find.text('hello')), matchesSemantics(label: 'hello')); +/// handle.dispose(); +/// }); /// ``` /// /// See also: @@ -685,9 +697,12 @@ Matcher matchesSemantics({ /// ## Sample code /// /// ```dart -/// final SemanticsHandle handle = tester.ensureSemantics(); -/// expect(tester.getSemantics(find.text('hello')), hasSemantics(label: 'hello')); -/// handle.dispose(); +/// testWidgets('containsSemantics', (WidgetTester tester) async { +/// final SemanticsHandle handle = tester.ensureSemantics(); +/// // ... +/// expect(tester.getSemantics(find.text('hello')), containsSemantics(label: 'hello')); +/// handle.dispose(); +/// }); /// ``` /// /// See also: @@ -859,9 +874,12 @@ Matcher containsSemantics({ /// ## Sample code /// /// ```dart -/// final SemanticsHandle handle = tester.ensureSemantics(); -/// await expectLater(tester, meetsGuideline(textContrastGuideline)); -/// handle.dispose(); +/// testWidgets('containsSemantics', (WidgetTester tester) async { +/// final SemanticsHandle handle = tester.ensureSemantics(); +/// // ... +/// await expectLater(tester, meetsGuideline(textContrastGuideline)); +/// handle.dispose(); +/// }); /// ``` /// /// Supported accessibility guidelines: diff --git a/packages/flutter_test/lib/src/mock_canvas.dart b/packages/flutter_test/lib/src/mock_canvas.dart index f448aef1accef..48aab5a23fd31 100644 --- a/packages/flutter_test/lib/src/mock_canvas.dart +++ b/packages/flutter_test/lib/src/mock_canvas.dart @@ -12,6 +12,10 @@ import 'finders.dart'; import 'recording_canvas.dart'; import 'test_async_utils.dart'; +// Examples can assume: +// late RenderObject myRenderObject; +// late Symbol methodName; + /// Matches objects or functions that paint a display list that matches the /// canvas calls described by the pattern. /// @@ -20,8 +24,8 @@ import 'test_async_utils.dart'; /// following signatures: /// /// ```dart -/// void function(PaintingContext context, Offset offset); -/// void function(Canvas canvas); +/// void exampleOne(PaintingContext context, Offset offset) { } +/// void exampleTwo(Canvas canvas) { } /// ``` /// /// In the case of functions that take a [PaintingContext] and an [Offset], the @@ -65,7 +69,9 @@ Matcher paintsExactlyCountTimes(Symbol methodName, int count) { /// literal syntax, for example: /// /// ```dart -/// if (methodName == #drawCircle) { ... } +/// if (methodName == #drawCircle) { +/// // ... +/// } /// ``` typedef PaintPatternPredicate = bool Function(Symbol methodName, List arguments); diff --git a/packages/flutter_test/lib/src/nonconst.dart b/packages/flutter_test/lib/src/nonconst.dart index c3b9d34660fd2..561f933f5fb91 100644 --- a/packages/flutter_test/lib/src/nonconst.dart +++ b/packages/flutter_test/lib/src/nonconst.dart @@ -8,15 +8,15 @@ /// ```dart /// class A { /// const A(this.i); -/// int i; +/// final int? i; /// } /// -/// main () { +/// void main () { /// // prevent prefer_const_constructors lint /// A(nonconst(null)); /// /// // prevent prefer_const_declarations lint -/// final int $null = nonconst(null); +/// final int? $null = nonconst(null); /// final A a = nonconst(const A(null)); /// } /// ``` diff --git a/packages/flutter_test/lib/src/recording_canvas.dart b/packages/flutter_test/lib/src/recording_canvas.dart index 04bda6f451e30..47f3478c1a856 100644 --- a/packages/flutter_test/lib/src/recording_canvas.dart +++ b/packages/flutter_test/lib/src/recording_canvas.dart @@ -35,6 +35,9 @@ class RecordedInvocation { } } +// Examples can assume: +// late WidgetTester tester; + /// A [Canvas] for tests that records its method calls. /// /// This class can be used in conjunction with [TestRecordingPaintingContext] diff --git a/packages/flutter_test/lib/src/test_async_utils.dart b/packages/flutter_test/lib/src/test_async_utils.dart index 9bdeebe110e01..3d915af565af2 100644 --- a/packages/flutter_test/lib/src/test_async_utils.dart +++ b/packages/flutter_test/lib/src/test_async_utils.dart @@ -12,6 +12,9 @@ class _AsyncScope { final Zone zone; } +// Examples can assume: +// late WidgetTester tester; + /// Utility class for all the async APIs in the `flutter_test` library. /// /// This class provides checking for asynchronous APIs, allowing the library to diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart index f63f79d0a4491..b4d65a1cb511a 100644 --- a/packages/flutter_test/lib/src/widget_tester.dart +++ b/packages/flutter_test/lib/src/widget_tester.dart @@ -81,6 +81,9 @@ E? _lastWhereOrNull(Iterable list, bool Function(E) test) { return null; } +// Examples can assume: +// typedef MyWidget = Placeholder; + /// Runs the [callback] inside the Flutter test environment. /// /// Use this function for testing custom [StatelessWidget]s and @@ -117,7 +120,7 @@ E? _lastWhereOrNull(Iterable list, bool Function(E) test) { /// /// ```dart /// testWidgets('MyWidget', (WidgetTester tester) async { -/// await tester.pumpWidget(MyWidget()); +/// await tester.pumpWidget(const MyWidget()); /// await tester.tap(find.text('Save')); /// expect(find.text('Success'), findsOneWidget); /// }); @@ -319,12 +322,13 @@ class TargetPlatformVariant extends TestVariant { /// } /// /// final ValueVariant variants = ValueVariant( -/// {value1, value2}, +/// {TestScenario.value1, TestScenario.value2}, /// ); -/// -/// testWidgets('Test handling of TestScenario', (WidgetTester tester) { -/// expect(variants.currentValue, equals(value1)); -/// }, variant: variants); +/// void main() { +/// testWidgets('Test handling of TestScenario', (WidgetTester tester) async { +/// expect(variants.currentValue, equals(TestScenario.value1)); +/// }, variant: variants); +/// } /// ``` /// {@end-tool} class ValueVariant extends TestVariant { @@ -507,7 +511,7 @@ Future expectLater( /// /// ```dart /// testWidgets('MyWidget', (WidgetTester tester) async { -/// await tester.pumpWidget(MyWidget()); +/// await tester.pumpWidget(const MyWidget()); /// await tester.tap(find.text('Save')); /// await tester.pump(); // allow the application to handle /// await tester.pump(const Duration(seconds: 1)); // skip past the animation @@ -555,7 +559,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker /// {@tool snippet} /// ```dart /// testWidgets('MyWidget asserts invalid bounds', (WidgetTester tester) async { - /// await tester.pumpWidget(MyWidget(-1)); + /// await tester.pumpWidget(const MyWidget()); /// expect(tester.takeException(), isAssertionError); // or isNull, as appropriate. /// }); /// ``` diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index 9c379003e7d9f..50d6b2bac7dde 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -1173,7 +1173,7 @@ class _UnsupportedDisplay implements TestDisplay { /// // Fake the desired properties of the TestWindow. All code running /// // within this test will perceive the following fake text scale /// // factor as the real text scale factor of the window. -/// testBinding.window.textScaleFactorFakeValue = 2.5; +/// testBinding.window.textScaleFactorTestValue = 2.5; // ignore: deprecated_member_use /// /// // Test code that depends on text scale factor here. /// }); From a6118612ac4d0f83fd129ad910c7b16b76879076 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Thu, 10 Aug 2023 10:51:05 -0700 Subject: [PATCH 0642/1547] Fix flutter attach local engine (#131825) Fixes: https://github.com/flutter/flutter/issues/124970 Part of https://github.com/flutter/flutter/issues/47161 Before this change, there were two places we overrode the `Artifacts` in a Zone: 1. if/when we parse local-engine CLI options: https://github.com/flutter/flutter/blob/1cf3907407cbc91be7cec2c38b348a2d66041dd5/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart#L281 2. an additional override for fuchsia platform dill (no longer used, deleted in this PR): https://github.com/flutter/flutter/blob/1cf3907407cbc91be7cec2c38b348a2d66041dd5/packages/flutter_tools/lib/src/commands/attach.dart#L274 Note 1 above creates a new instance of `Artifacts.getLocalEngine()`. In this flow, there exist two instances of `Artifacts`: 1. The default fallback instance of `CachedArtifacts` (which gets all artifacts from flutter/bin/cache), instantiated in context_runner.dart: https://github.com/flutter/flutter/blob/1cf3907407cbc91be7cec2c38b348a2d66041dd5/packages/flutter_tools/lib/src/context_runner.dart#L137 2. An instance of `CachedLocalEngineArtifacts` created in the command runner once the CLI options have been parsed: https://github.com/flutter/flutter/blob/1cf3907407cbc91be7cec2c38b348a2d66041dd5/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart#L281 The regression happened when we direct injected the Artifacts 1 from above BEFORE we parsed the local-engine flag, and then used this in the second zone override, and then when creating the `FlutterDevice` there are multiple calls to `globals.artifacts` returned it when it should have returned Artifacts 2: https://github.com/flutter/flutter/blob/1cf3907407cbc91be7cec2c38b348a2d66041dd5/packages/flutter_tools/lib/src/resident_runner.dart#L80 Device.artifactOverrides was originally introduced in https://github.com/flutter/flutter/pull/32071, but is no longer used, so I deleted it. I also removed direct injection of `Artifacts` to the attach sub-command, because that class now no longer references artifacts. I believe the ideal true fix for this would be to: 1. Migrate all leaf calls to `globals.artifacts` to use direct injection (in this case, the offending invocations were in [`FlutterDevice.create()`](https://github.com/flutter/flutter/blob/1cf3907407cbc91be7cec2c38b348a2d66041dd5/packages/flutter_tools/lib/src/resident_runner.dart#L80-L218), but I'm not sure that something else would not have broken later) 2. Ensure we are always direct injecting the desired instance of `Artifacts`--that is, if the user desires local engine artifacts, that we are passing an instance of `CachedLocalEngineArtifacts`. a. Alternatively, and probably simpler, teach `CachedArtifacts` to know about the local engine. This would mean parsing the global CLI options BEFORE we ever construct any instance of `Artifacts`. As an overall recommendation for implementing https://github.com/flutter/flutter/issues/47161, in the overall tree of tool function calls, we should probably migrate the leaves first (that is, migrate the sub-commands last). We should also audit and reconsider any usage of `runZoned()` or `context.run()` for the purpose overriding zoneValues. --- packages/flutter_tools/lib/executable.dart | 1 - .../lib/src/commands/attach.dart | 29 ++--- packages/flutter_tools/lib/src/compile.dart | 9 +- packages/flutter_tools/lib/src/device.dart | 4 - .../commands.shard/hermetic/attach_test.dart | 107 +++++++++++++----- .../general.shard/commands/build_test.dart | 2 - 6 files changed, 91 insertions(+), 61 deletions(-) diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index 2fb826f17d10f..b5ecf5a3bcb0d 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -156,7 +156,6 @@ List generateCommands({ AssembleCommand(verboseHelp: verboseHelp, buildSystem: globals.buildSystem), AttachCommand( verboseHelp: verboseHelp, - artifacts: globals.artifacts, stdio: globals.stdio, logger: globals.logger, terminal: globals.terminal, diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 9093a2c569071..303f6e6676b94 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -7,9 +7,7 @@ import 'dart:async'; import 'package:vm_service/vm_service.dart'; import '../android/android_device.dart'; -import '../artifacts.dart'; import '../base/common.dart'; -import '../base/context.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; @@ -65,7 +63,6 @@ class AttachCommand extends FlutterCommand { AttachCommand({ bool verboseHelp = false, HotRunnerFactory? hotRunnerFactory, - required Artifacts? artifacts, required Stdio stdio, required Logger logger, required Terminal terminal, @@ -73,15 +70,14 @@ class AttachCommand extends FlutterCommand { required Platform platform, required ProcessInfo processInfo, required FileSystem fileSystem, - }): _artifacts = artifacts, - _hotRunnerFactory = hotRunnerFactory ?? HotRunnerFactory(), - _stdio = stdio, - _logger = logger, - _terminal = terminal, - _signals = signals, - _platform = platform, - _processInfo = processInfo, - _fileSystem = fileSystem { + }) : _hotRunnerFactory = hotRunnerFactory ?? HotRunnerFactory(), + _stdio = stdio, + _logger = logger, + _terminal = terminal, + _signals = signals, + _platform = platform, + _processInfo = processInfo, + _fileSystem = fileSystem { addBuildModeFlags(verboseHelp: verboseHelp, defaultToRelease: false, excludeRelease: true); usesTargetOption(); usesPortOptions(verboseHelp: verboseHelp); @@ -145,7 +141,6 @@ class AttachCommand extends FlutterCommand { } final HotRunnerFactory _hotRunnerFactory; - final Artifacts? _artifacts; final Stdio _stdio; final Logger _logger; final Terminal _terminal; @@ -267,13 +262,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. throwToolExit('Did not find any valid target devices.'); } - final Artifacts? overrideArtifacts = device.artifactOverrides ?? _artifacts; - await context.run( - body: () => _attachToDevice(device), - overrides: { - Artifacts: () => overrideArtifacts, - }, - ); + await _attachToDevice(device); return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index 6774080a54586..1329c9fcd1a18 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -585,7 +585,7 @@ class DefaultResidentCompiler implements ResidentCompiler { required this.buildMode, required Logger logger, required ProcessManager processManager, - required Artifacts artifacts, + required this.artifacts, required Platform platform, required FileSystem fileSystem, this.testCompilation = false, @@ -604,7 +604,6 @@ class DefaultResidentCompiler implements ResidentCompiler { @visibleForTesting StdoutHandler? stdoutHandler, }) : _logger = logger, _processManager = processManager, - _artifacts = artifacts, _stdoutHandler = stdoutHandler ?? StdoutHandler(logger: logger, fileSystem: fileSystem), _platform = platform, dartDefines = dartDefines ?? const [], @@ -615,7 +614,7 @@ class DefaultResidentCompiler implements ResidentCompiler { final Logger _logger; final ProcessManager _processManager; - final Artifacts _artifacts; + final Artifacts artifacts; final Platform _platform; final bool testCompilation; @@ -751,12 +750,12 @@ class DefaultResidentCompiler implements ResidentCompiler { {String? additionalSourceUri} ) async { final TargetPlatform? platform = (targetModel == TargetModel.dartdevc) ? TargetPlatform.web_javascript : null; - final String frontendServer = _artifacts.getArtifactPath( + final String frontendServer = artifacts.getArtifactPath( Artifact.frontendServerSnapshotForEngineDartSdk, platform: platform, ); final List command = [ - _artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), + artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), '--disable-dart-dev', frontendServer, '--sdk-root', diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 4f209b09e9226..c601c543d0329 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -8,7 +8,6 @@ import 'dart:math' as math; import 'package:meta/meta.dart'; import 'application_package.dart'; -import 'artifacts.dart'; import 'base/context.dart'; import 'base/dds.dart'; import 'base/file_system.dart'; @@ -741,9 +740,6 @@ abstract class Device { /// Clear the device's logs. void clearLogs(); - /// Optional device-specific artifact overrides. - OverrideArtifacts? get artifactOverrides => null; - /// Start an app package on the current device. /// /// [platformArgs] allows callers to pass platform-specific arguments to the diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index 2f0d9d0f667ec..5740b20c93cf5 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -19,6 +19,7 @@ import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/attach.dart'; +import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; import 'package:flutter_tools/src/ios/application_package.dart'; @@ -72,12 +73,12 @@ void main() { testFileSystem = MemoryFileSystem.test(); testFileSystem.directory('lib').createSync(); testFileSystem.file(testFileSystem.path.join('lib', 'main.dart')).createSync(); - artifacts = Artifacts.test(); + artifacts = Artifacts.test(fileSystem: testFileSystem); stdio = FakeStdio(); terminal = FakeTerminal(); signals = Signals.test(); processInfo = FakeProcessInfo(); - testDeviceManager = TestDeviceManager(logger: BufferLogger.test()); + testDeviceManager = TestDeviceManager(logger: logger); }); group('with one device and no specified target file', () { @@ -135,7 +136,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -199,7 +199,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -229,6 +228,75 @@ void main() { Signals: () => FakeSignals(), }); + testUsingContext('local engine artifacts are passed to runner', () async { + const String localEngineSrc = '/path/to/local/engine/src'; + const String localEngineDir = 'host_debug_unopt'; + testFileSystem.directory('$localEngineSrc/out/$localEngineDir').createSync(recursive: true); + final FakeIOSDevice device = FakeIOSDevice( + portForwarder: portForwarder, + majorSdkVersion: 12, + onGetLogReader: () { + fakeLogReader.addLine('Foo'); + fakeLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:$devicePort'); + return fakeLogReader; + }, + ); + testDeviceManager.devices = [device]; + final Completer completer = Completer(); + final StreamSubscription loggerSubscription = logger.stream.listen((String message) { + if (message == '[verbose] VM Service URL on device: http://127.0.0.1:$devicePort') { + // The "VM Service URL on device" message is output by the ProtocolDiscovery when it found the VM Service. + completer.complete(); + } + }); + final FakeHotRunner hotRunner = FakeHotRunner(); + hotRunner.onAttach = ( + Completer? connectionInfoCompleter, + Completer? appStartedCompleter, + bool allowExistingDdsInstance, + bool enableDevTools, + ) async => 0; + hotRunner.exited = false; + hotRunner.isWaitingForVmService = false; + bool passedArtifactTest = false; + final FakeHotRunnerFactory hotRunnerFactory = FakeHotRunnerFactory() + ..hotRunner = hotRunner + .._artifactTester = (Artifacts artifacts) { + expect(artifacts, isA()); + // expecting this to be true ensures this test ran + passedArtifactTest = true; + }; + + await createTestCommandRunner(AttachCommand( + hotRunnerFactory: hotRunnerFactory, + stdio: stdio, + logger: logger, + terminal: terminal, + signals: signals, + platform: platform, + processInfo: processInfo, + fileSystem: testFileSystem, + )).run(['attach', '--local-engine-src-path=$localEngineSrc', '--local-engine=$localEngineDir']); + await Future.wait(>[ + completer.future, + fakeLogReader.dispose(), + loggerSubscription.cancel(), + ]); + expect(passedArtifactTest, isTrue); + }, overrides: { + Artifacts: () => artifacts, + DeviceManager: () => testDeviceManager, + FileSystem: () => testFileSystem, + Logger: () => logger, + MDnsVmServiceDiscovery: () => MDnsVmServiceDiscovery( + mdnsClient: FakeMDnsClient([], >{}), + preliminaryMDnsClient: FakeMDnsClient([], >{}), + logger: logger, + flutterUsage: TestUsage(), + ), + ProcessManager: () => FakeProcessManager.empty(), + }); + testUsingContext('succeeds with iOS device with mDNS', () async { final FakeIOSDevice device = FakeIOSDevice( portForwarder: portForwarder, @@ -254,7 +322,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -319,7 +386,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -390,7 +456,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -465,7 +530,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -534,7 +598,6 @@ void main() { } }); final Future task = createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -567,7 +630,6 @@ void main() { }; testDeviceManager.devices = [device]; expect(() => createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -611,7 +673,6 @@ void main() { final AttachCommand command = AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -655,7 +716,6 @@ void main() { testDeviceManager.devices = [device]; final AttachCommand command = AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -709,7 +769,6 @@ void main() { await createTestCommandRunner(AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -741,7 +800,6 @@ void main() { testDeviceManager.devices = [device]; final AttachCommand command = AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -790,7 +848,6 @@ void main() { } }); final Future task = createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -825,7 +882,6 @@ void main() { } }); final Future task = createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -861,7 +917,6 @@ void main() { } }); final Future task = createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -906,7 +961,6 @@ void main() { } }); final Future task = createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -943,7 +997,6 @@ void main() { testUsingContext('exits when no device connected', () async { final AttachCommand command = AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -967,7 +1020,6 @@ void main() { final FakeIOSDevice device = FakeIOSDevice(); testDeviceManager.devices = [device]; expect(createTestCommandRunner(AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -988,7 +1040,6 @@ void main() { testUsingContext('exits when multiple devices connected', () async { final AttachCommand command = AttachCommand( - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -1038,7 +1089,6 @@ void main() { final AttachCommand command = AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -1079,7 +1129,6 @@ void main() { final AttachCommand command = AttachCommand( hotRunnerFactory: hotRunnerFactory, - artifacts: artifacts, stdio: stdio, logger: logger, terminal: terminal, @@ -1134,6 +1183,7 @@ class FakeHotRunnerFactory extends Fake implements HotRunnerFactory { String? dillOutputPath; String? projectRootPath; late List devices; + void Function(Artifacts artifacts)? _artifactTester; @override HotRunner build( @@ -1150,6 +1200,11 @@ class FakeHotRunnerFactory extends Fake implements HotRunnerFactory { bool ipv6 = false, FlutterProject? flutterProject, }) { + if (_artifactTester != null) { + for (final FlutterDevice device in devices) { + _artifactTester!((device.generator! as DefaultResidentCompiler).artifacts); + } + } this.devices = devices; this.dillOutputPath = dillOutputPath; this.projectRootPath = projectRootPath; @@ -1399,9 +1454,6 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { return onGetLogReader!(); } - @override - OverrideArtifacts? get artifactOverrides => null; - @override final PlatformType platformType = PlatformType.android; @@ -1456,9 +1508,6 @@ class FakeIOSDevice extends Fake implements IOSDevice { return onGetLogReader!(); } - @override - OverrideArtifacts? get artifactOverrides => null; - @override final String name = 'name'; diff --git a/packages/flutter_tools/test/general.shard/commands/build_test.dart b/packages/flutter_tools/test/general.shard/commands/build_test.dart index 33e6a5e78da7c..9663a387cb848 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_test.dart @@ -5,7 +5,6 @@ import 'package:args/args.dart'; import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; -import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; @@ -75,7 +74,6 @@ void main() { ), ), AttachCommand( - artifacts: Artifacts.test(), stdio: FakeStdio(), logger: logger, terminal: FakeTerminal(), From 685141bf3b5ff4a90589fd77784776e011dd5fcc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 14:21:46 -0400 Subject: [PATCH 0643/1547] Roll Flutter Engine from e2ed1bebf31d to ea7730c16301 (3 revisions) (#132313) https://github.com/flutter/engine/compare/e2ed1bebf31d...ea7730c16301 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from 67bad75b41c2 to f39fd2de8f10 (1 revision) (flutter/engine#44588) 2023-08-10 skia-flutter-autoroll@skia.org Roll Dart SDK from d89e4ead966d to 46da53e7abe2 (4 revisions) (flutter/engine#44584) 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from aac2d55d35eb to 67bad75b41c2 (1 revision) (flutter/engine#44583) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ddfa21b8a5d6f..a10b3e1f9deae 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e2ed1bebf31d9e6fccf78d0fa5f27743fff1f246 +ea7730c16301a7c40a511363de73ca852289ce88 From e972d5a3f6469d2391e2851531e04ba154584d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9=20Dumazy?= Date: Thu, 10 Aug 2023 20:53:56 +0200 Subject: [PATCH 0644/1547] Add hasInteractedByUser getter in FormField (#131539) Adds a getter to access the value of the private `RestorableBool _hasInteractedByUser`. *List which issues are fixed by this PR. You must list at least one issue.* Fixes #131538 --- packages/flutter/lib/src/widgets/form.dart | 6 ++ packages/flutter/test/widgets/form_test.dart | 86 ++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 76e8521ab9196..0860532a78fb0 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -423,6 +423,12 @@ class FormFieldState extends State> with RestorationMixin { /// True if this field has any validation errors. bool get hasError => _errorText.value != null; + /// Returns true if the user has modified the value of this field. + /// + /// This only updates to true once [didChange] has been called and resets to + /// false when [reset] is called. + bool get hasInteractedByUser => _hasInteractedByUser.value; + /// True if the current value is valid. /// /// This will not set [errorText] or [hasError] and it will not update diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart index 98d10c636afd5..6fa4bbd42acd6 100644 --- a/packages/flutter/test/widgets/form_test.dart +++ b/packages/flutter/test/widgets/form_test.dart @@ -854,4 +854,90 @@ void main() { expect(fieldValue, '123456'); expect(formKey.currentState!.validate(), isFalse); }); + + testWidgets('hasInteractedByUser returns false when the input has not changed', (WidgetTester tester) async { + final GlobalKey> fieldKey = GlobalKey>(); + + final Widget widget = MaterialApp( + home: MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Material( + child: TextFormField( + key: fieldKey, + ), + ), + ), + ), + ), + ); + + await tester.pumpWidget(widget); + + expect(fieldKey.currentState!.hasInteractedByUser, isFalse); + }); + + testWidgets('hasInteractedByUser returns true after the input has changed', (WidgetTester tester) async { + final GlobalKey> fieldKey = GlobalKey>(); + + final Widget widget = MaterialApp( + home: MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Material( + child: TextFormField( + key: fieldKey, + ), + ), + ), + ), + ), + ); + + await tester.pumpWidget(widget); + + // initially, the field has not been interacted with + expect(fieldKey.currentState!.hasInteractedByUser, isFalse); + + // after entering text, the field has been interacted with + await tester.enterText(find.byType(TextFormField), 'foo'); + expect(fieldKey.currentState!.hasInteractedByUser, isTrue); + }); + + testWidgets('hasInteractedByUser returns false after the field is reset', (WidgetTester tester) async { + final GlobalKey> fieldKey = GlobalKey>(); + + final Widget widget = MaterialApp( + home: MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Material( + child: TextFormField( + key: fieldKey, + ), + ), + ), + ), + ), + ); + + await tester.pumpWidget(widget); + + // initially, the field has not been interacted with + expect(fieldKey.currentState!.hasInteractedByUser, isFalse); + + // after entering text, the field has been interacted with + await tester.enterText(find.byType(TextFormField), 'foo'); + expect(fieldKey.currentState!.hasInteractedByUser, isTrue); + + // after resetting the field, it has not been interacted with again + fieldKey.currentState!.reset(); + expect(fieldKey.currentState!.hasInteractedByUser, isFalse); + }); } From f9a578dd82b2565a4cc13039256e09cbd3679ccc Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 10 Aug 2023 12:40:06 -0700 Subject: [PATCH 0645/1547] An example of parentData usage. (#131818) --- .../api/lib/rendering/box/parent_data.0.dart | 394 ++++++++++++++++++ .../rendering/box/parent_data.0_test.dart | 17 + packages/flutter/lib/src/rendering/box.dart | 9 + .../flutter/lib/src/widgets/framework.dart | 45 +- 4 files changed, 447 insertions(+), 18 deletions(-) create mode 100644 examples/api/lib/rendering/box/parent_data.0.dart create mode 100644 examples/api/test/rendering/box/parent_data.0_test.dart diff --git a/examples/api/lib/rendering/box/parent_data.0.dart b/examples/api/lib/rendering/box/parent_data.0.dart new file mode 100644 index 0000000000000..0063f0e54427d --- /dev/null +++ b/examples/api/lib/rendering/box/parent_data.0.dart @@ -0,0 +1,394 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +void main() => runApp(const SampleApp()); + +class SampleApp extends StatefulWidget { + const SampleApp({super.key}); + + @override + State createState() => _SampleAppState(); +} + +class _SampleAppState extends State { + // This can be toggled using buttons in the UI to change which layout render object is used. + bool _compact = false; + + // This is the content we show in the rendering. + // + // Headline and Paragraph are simple custom widgets defined below. + // + // Any widget _could_ be specified here, and would render fine. + // The Headline and Paragraph widgets are used so that the renderer + // can distinguish between the kinds of content and use different + // spacing between different children. + static const List body = [ + Headline('Bugs that improve T for future bugs'), + Paragraph( + 'The best bugs to fix are those that make us more productive ' + 'in the future. Reducing test flakiness, reducing technical ' + 'debt, increasing the number of team members who are able to ' + 'review code confidently and well: this all makes future bugs ' + 'easier to fix, which is a huge multiplier to our overall ' + 'effectiveness and thus to developer happiness.', + ), + Headline('Bugs affecting more people are more valuable (maximize N)'), + Paragraph( + 'We will make more people happier if we fix a bug experienced by more people.' + ), + Paragraph( + 'One thing to be careful about is to think about the number of ' + 'people we are ignoring in our metrics. For example, if we had ' + 'a bug that prevented our product from working on Windows, we ' + 'would have no Windows users, so the bug would affect nobody. ' + 'However, fixing the bug would enable millions of developers ' + "to use our product, and that's the number that counts." + ), + Headline('Bugs with greater impact on developers are more valuable (maximize ΔH)'), + Paragraph( + 'A slight improvement to the user experience is less valuable ' + 'than a greater improvement. For example, if our application, ' + 'under certain conditions, shows a message with a typo, and ' + 'then crashes because of an off-by-one error in the code, ' + 'fixing the crash is a higher priority than fixing the typo.' + ), + ]; + + // This is the description of the demo's interface. + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Custom Render Boxes'), + // There are two buttons over to the top right of the demo that let you + // toggle between the two rendering modes. + actions: [ + IconButton( + icon: const Icon(Icons.density_small), + isSelected: _compact, + onPressed: () { + setState(() { _compact = true; }); + }, + ), + IconButton( + icon: const Icon(Icons.density_large), + isSelected: !_compact, + onPressed: () { + setState(() { _compact = false; }); + }, + ), + ], + ), + body: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 20.0), + // CompactLayout and OpenLayout are the two rendering widgets defined below. + child: _compact ? const CompactLayout(children: body) : const OpenLayout(children: body), + ), + ), + ); + } +} + +// Headline and Paragraph are just wrappers around the Text widget, but they +// also introduce a TextCategory widget that the CompactLayout and OpenLayout +// widgets can read to determine what kind of child is being rendered. + +class Headline extends StatelessWidget { + const Headline(this.text, { super.key }); + + final String text; + + @override + Widget build(BuildContext context) { + return TextCategory( + category: 'headline', + child: Text(text, style: Theme.of(context).textTheme.titleLarge), + ); + } +} + +class Paragraph extends StatelessWidget { + const Paragraph(this.text, { super.key }); + + final String text; + + @override + Widget build(BuildContext context) { + return TextCategory( + category: 'paragraph', + child: Text(text, style: Theme.of(context).textTheme.bodyLarge), + ); + } +} + +// This is the ParentDataWidget that allows us to specify what kind of child +// is being rendered. It allows information to be shared with the render object +// without violating the principle of agnostic composition (wherein parents should +// work with any child, not only support a fixed set of children). +class TextCategory extends ParentDataWidget { + const TextCategory({ super.key, required this.category, required super.child }); + + final String category; + + @override + void applyParentData(RenderObject renderObject) { + final TextFlowParentData parentData = renderObject.parentData! as TextFlowParentData; + if (parentData.category != category) { + parentData.category = category; + renderObject.parent!.markNeedsLayout(); + } + } + + @override + Type get debugTypicalAncestorWidgetClass => OpenLayout; +} + +// This is one of the two layout variants. It is a widget that defers to +// a render object defined below (RenderCompactLayout). +class CompactLayout extends MultiChildRenderObjectWidget { + const CompactLayout({ super.key, super.children }); + + @override + RenderCompactLayout createRenderObject(BuildContext context) { + return RenderCompactLayout(); + } + + @override + void updateRenderObject(BuildContext context, RenderCompactLayout renderObject) { + // nothing to update + } +} + +// This is the other of the two layout variants. It is a widget that defers to a +// render object defined below (RenderOpenLayout). +class OpenLayout extends MultiChildRenderObjectWidget { + const OpenLayout({ super.key, super.children }); + + @override + RenderOpenLayout createRenderObject(BuildContext context) { + return RenderOpenLayout(); + } + + @override + void updateRenderObject(BuildContext context, RenderOpenLayout renderObject) { + // nothing to update + } +} + +// This is the data structure that contains the kind of data that can be +// passed to the parent to label the child. It is literally stored on +// the RenderObject child, in its "parentData" field. +class TextFlowParentData extends ContainerBoxParentData { + String category = ''; +} + +// This is the bulk of the layout logic. (It's similar to RenderListBody, +// but only supports vertical layout.) It has no properties. +// +// This is an abstract class that is then extended by RenderCompactLayout and +// RenderOpenLayout to get different layouts based on the children's categories, +// as stored in the ParentData structure defined above. +// +// The documentation for the RenderBox class and its members provides much +// more detail on how to implement each of the methods below. +abstract class RenderTextFlow extends RenderBox + with ContainerRenderObjectMixin, + RenderBoxContainerDefaultsMixin { + RenderTextFlow({ List? children }) { + addAll(children); + } + + @override + void setupParentData(RenderBox child) { + if (child.parentData is! TextFlowParentData) { + child.parentData = TextFlowParentData(); + } + } + + // This is the function that is overridden by the subclasses to do the + // actual decision about the space to use between children. + double spacingBetween(String before, String after); + + // The next few functions are the layout functions. In each case we walk the + // children, calling each one to determine the geometry of the child, and use + // that to determine the layout. + + // The first two functions compute the intrinsic width of the render object, + // as seen when using the IntrinsicWidth widget. + // + // They essentially defer to the widest child. + + @override + double computeMinIntrinsicWidth(double height) { + double width = 0.0; + RenderBox? child = firstChild; + while (child != null) { + final double childWidth = child.getMinIntrinsicWidth(height); + if (childWidth > width) { + width = childWidth; + } + child = childAfter(child); + } + return width; + } + + @override + double computeMaxIntrinsicWidth(double height) { + double width = 0.0; + RenderBox? child = firstChild; + while (child != null) { + final double childWidth = child.getMaxIntrinsicWidth(height); + if (childWidth > width) { + width = childWidth; + } + child = childAfter(child); + } + return width; + } + + // The next two functions compute the intrinsic height of the render object, + // as seen when using the IntrinsicHeight widget. + // + // They add up the height contributed by each child. + // + // They have to take into account the categories of the children and the + // spacing that will be added, hence the slightly more elaborate logic. + + @override + double computeMinIntrinsicHeight(double width) { + String? previousCategory; + double height = 0.0; + RenderBox? child = firstChild; + while (child != null) { + final String category = (child.parentData! as TextFlowParentData).category; + if (previousCategory != null) { + height += spacingBetween(previousCategory, category); + } + height += child.getMinIntrinsicHeight(width); + previousCategory = category; + child = childAfter(child); + } + return height; + } + + @override + double computeMaxIntrinsicHeight(double width) { + String? previousCategory; + double height = 0.0; + RenderBox? child = firstChild; + while (child != null) { + final String category = (child.parentData! as TextFlowParentData).category; + if (previousCategory != null) { + height += spacingBetween(previousCategory, category); + } + height += child.getMaxIntrinsicHeight(width); + previousCategory = category; + child = childAfter(child); + } + return height; + } + + // This function implements the baseline logic. Because this class does + // nothing special, we just defer to the default implementation in the + // RenderBoxContainerDefaultsMixin utility class. + + @override + double? computeDistanceToActualBaseline(TextBaseline baseline) { + return defaultComputeDistanceToFirstActualBaseline(baseline); + } + + // Next we have a function similar to the intrinsic methods, but for both axes + // at the same time. + + @override + Size computeDryLayout(BoxConstraints constraints) { + final BoxConstraints innerConstraints = BoxConstraints.tightFor(width: constraints.maxWidth); + String? previousCategory; + double y = 0.0; + RenderBox? child = firstChild; + while (child != null) { + final String category = (child.parentData! as TextFlowParentData).category; + if (previousCategory != null) { + y += spacingBetween(previousCategory, category); + } + final Size childSize = child.getDryLayout(innerConstraints); + y += childSize.height; + previousCategory = category; + child = childAfter(child); + } + return constraints.constrain(Size(constraints.maxWidth, y)); + } + + // This is the core of the layout logic. Most of the time, this is the only + // function that will be called. It computes the size and position of each + // child, and stores it (in the parent data, as it happens!) for use during + // the paint phase. + + @override + void performLayout() { + final BoxConstraints innerConstraints = BoxConstraints.tightFor(width: constraints.maxWidth); + String? previousCategory; + double y = 0.0; + RenderBox? child = firstChild; + while (child != null) { + final String category = (child.parentData! as TextFlowParentData).category; + if (previousCategory != null) { + // This is where we call the function that computes the spacing between + // the different children. The arguments are the categories, obtained + // from the parentData property of each child. + y += spacingBetween(previousCategory, category); + } + child.layout(innerConstraints, parentUsesSize: true); + (child.parentData! as TextFlowParentData).offset = Offset(0.0, y); + y += child.size.height; + previousCategory = category; + child = childAfter(child); + } + size = constraints.constrain(Size(constraints.maxWidth, y)); + } + + // Hit testing is normal for this widget, so we defer to the default implementation. + @override + bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { + return defaultHitTestChildren(result, position: position); + } + + // Painting is normal for this widget, so we defer to the default + // implementation. The default implementation expects to find the positions + // configured in the parentData property of each child, which is why we + // configure it that way in performLayout above. + @override + void paint(PaintingContext context, Offset offset) { + defaultPaint(context, offset); + } +} + +// Finally we have the two render objects that implement the two layouts in this demo. + +class RenderOpenLayout extends RenderTextFlow { + @override + double spacingBetween(String before, String after) { + if (after == 'headline') { + return 20.0; + } + if (before == 'headline') { + return 5.0; + } + return 10.0; + } +} + +class RenderCompactLayout extends RenderTextFlow { + @override + double spacingBetween(String before, String after) { + if (after == 'headline') { + return 4.0; + } + return 2.0; + } +} diff --git a/examples/api/test/rendering/box/parent_data.0_test.dart b/examples/api/test/rendering/box/parent_data.0_test.dart new file mode 100644 index 0000000000000..91c4a1beb4274 --- /dev/null +++ b/examples/api/test/rendering/box/parent_data.0_test.dart @@ -0,0 +1,17 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/rendering/box/parent_data.0.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('parent data example', (WidgetTester tester) async { + await tester.pumpWidget(const SampleApp()); + expect(tester.getTopLeft(find.byType(Headline).at(2)), const Offset(30.0, 728.0)); + await tester.tap(find.byIcon(Icons.density_small)); + await tester.pump(); + expect(tester.getTopLeft(find.byType(Headline).at(2)), const Offset(30.0, 682.0)); + }); +} diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index 6a9a00791ef15..68cb816d26a79 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -911,6 +911,15 @@ class BoxHitTestEntry extends HitTestEntry { } /// Parent data used by [RenderBox] and its subclasses. +/// +/// {@tool dartpad} +/// Parent data is used to communicate to a render object about its +/// children. In this example, there are two render objects that perform +/// text layout. They use parent data to identify the kind of child they +/// are laying out, and space the children accordingly. +/// +/// ** See code in examples/api/lib/rendering/box/parent_data.0.dart ** +/// {@end-tool} class BoxParentData extends ParentData { /// The offset at which to paint the child in the parent's coordinate system. Offset offset = Offset.zero; diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index abd202dd943ba..3a432ee3a9402 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1778,16 +1778,20 @@ abstract class InheritedWidget extends ProxyWidget { bool updateShouldNotify(covariant InheritedWidget oldWidget); } -/// RenderObjectWidgets provide the configuration for [RenderObjectElement]s, +/// [RenderObjectWidget]s provide the configuration for [RenderObjectElement]s, /// which wrap [RenderObject]s, which provide the actual rendering of the /// application. /// -/// See also: +/// Usually, rather than subclassing [RenderObjectWidget] directly, render +/// object widgets subclass one of: /// -/// * [MultiChildRenderObjectWidget], which configures a [RenderObject] with -/// a single list of children. -/// * [SlottedMultiChildRenderObjectWidget], which configures a -/// [RenderObject] that organizes its children in different named slots. +/// * [LeafRenderObjectWidget], if the widget has no children. +/// * [SingleChildRenderObjectElement], if the widget has exactly one child. +/// * [MultiChildRenderObjectWidget], if the widget takes a list of children. +/// * [SlottedMultiChildRenderObjectWidget], if the widget organizes its +/// children in different named slots. +/// +/// Subclasses must implement [createRenderObject] and [updateRenderObject]. abstract class RenderObjectWidget extends Widget { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1830,8 +1834,10 @@ abstract class RenderObjectWidget extends Widget { void didUnmountRenderObject(covariant RenderObject renderObject) { } } -/// A superclass for RenderObjectWidgets that configure RenderObject subclasses +/// A superclass for [RenderObjectWidget]s that configure [RenderObject] subclasses /// that have no children. +/// +/// Subclasses must implement [createRenderObject] and [updateRenderObject]. abstract class LeafRenderObjectWidget extends RenderObjectWidget { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1842,13 +1848,14 @@ abstract class LeafRenderObjectWidget extends RenderObjectWidget { } /// A superclass for [RenderObjectWidget]s that configure [RenderObject] subclasses -/// that have a single child slot. (This superclass only provides the storage -/// for that child, it doesn't actually provide the updating logic.) +/// that have a single child slot. /// -/// Typically, the render object assigned to this widget will make use of +/// The render object assigned to this widget should make use of /// [RenderObjectWithChildMixin] to implement a single-child model. The mixin -/// exposes a [RenderObjectWithChildMixin.child] property that allows -/// retrieving the render object belonging to the [child] widget. +/// exposes a [RenderObjectWithChildMixin.child] property that allows retrieving +/// the render object belonging to the [child] widget. +/// +/// Subclasses must implement [createRenderObject] and [updateRenderObject]. abstract class SingleChildRenderObjectWidget extends RenderObjectWidget { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. @@ -1868,13 +1875,15 @@ abstract class SingleChildRenderObjectWidget extends RenderObjectWidget { /// storage for that child list, it doesn't actually provide the updating /// logic.) /// -/// Subclasses must return a [RenderObject] that mixes in +/// Subclasses must use a [RenderObject] that mixes in /// [ContainerRenderObjectMixin], which provides the necessary functionality to /// visit the children of the container render object (the render object -/// belonging to the [children] widgets). Typically, subclasses will return a +/// belonging to the [children] widgets). Typically, subclasses will use a /// [RenderBox] that mixes in both [ContainerRenderObjectMixin] and /// [RenderBoxContainerDefaultsMixin]. /// +/// Subclasses must implement [createRenderObject] and [updateRenderObject]. +/// /// See also: /// /// * [Stack], which uses [MultiChildRenderObjectWidget]. @@ -6538,8 +6547,8 @@ class LeafRenderObjectElement extends RenderObjectElement { /// /// The child is optional. /// -/// This element subclass can be used for RenderObjectWidgets whose -/// RenderObjects use the [RenderObjectWithChildMixin] mixin. Such widgets are +/// This element subclass can be used for [RenderObjectWidget]s whose +/// [RenderObject]s use the [RenderObjectWithChildMixin] mixin. Such widgets are /// expected to inherit from [SingleChildRenderObjectWidget]. class SingleChildRenderObjectElement extends RenderObjectElement { /// Creates an element that uses the given widget as its configuration. @@ -6600,8 +6609,8 @@ class SingleChildRenderObjectElement extends RenderObjectElement { /// An [Element] that uses a [MultiChildRenderObjectWidget] as its configuration. /// -/// This element subclass can be used for RenderObjectWidgets whose -/// RenderObjects use the [ContainerRenderObjectMixin] mixin with a parent data +/// This element subclass can be used for [RenderObjectWidget]s whose +/// [RenderObject]s use the [ContainerRenderObjectMixin] mixin with a parent data /// type that implements [ContainerParentDataMixin]. Such widgets /// are expected to inherit from [MultiChildRenderObjectWidget]. /// From e1fd2ace92f730179612b5714e5e6730c6f56676 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 10 Aug 2023 13:18:51 -0700 Subject: [PATCH 0646/1547] TextPainter migration cleanup (#132317) Undo temporary changes made in #132094 --- dev/bots/test.dart | 8 ++++---- packages/flutter/lib/src/painting/text_painter.dart | 8 +------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/dev/bots/test.dart b/dev/bots/test.dart index fd91ada4f66b3..2b48df03287e4 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -102,7 +102,7 @@ final String flutterTester = path.join(flutterRoot, 'bin', 'cache', 'artifacts', /// The arguments to pass to `flutter test` (typically the local engine /// configuration) -- prefilled with the arguments passed to test.dart. -final List flutterTestArgs = ['--dart-define=SKPARAGRAPH_REMOVE_ROUNDING_HACK=true']; +final List flutterTestArgs = []; /// Environment variables to override the local engine when running `pub test`, /// if such flags are provided to `test.dart`. @@ -1309,8 +1309,8 @@ Future _runFlutterDriverWebTest({ await runCommand( flutter, [ - 'drive', ...flutterTestArgs, + 'drive', if (driver != null) '--driver=$driver', '--target=$target', '--browser-name=chrome', @@ -1584,8 +1584,8 @@ Future _runGalleryE2eWebTest(String buildMode, { bool canvasKit = false }) await runCommand( flutter, [ - 'drive', ...flutterTestArgs, + 'drive', if (canvasKit) '--dart-define=FLUTTER_WEB_USE_SKIA=true', if (!canvasKit) @@ -1665,10 +1665,10 @@ Future _runWebReleaseTest(String target, { await runCommand( flutter, [ + ...flutterTestArgs, 'build', 'web', '--release', - ...flutterTestArgs, ...additionalArguments, '-t', target, diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index c1e01cb36a1fd..6457e7cd37f46 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -515,13 +515,7 @@ class TextPainter { _locale = locale, _strutStyle = strutStyle, _textWidthBasis = textWidthBasis, - _textHeightBehavior = textHeightBehavior, - assert(() { - if (const bool.fromEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK')) { - ui.ParagraphBuilder.setDisableRoundingHack(true); - } - return true; - }()); + _textHeightBehavior = textHeightBehavior; /// Computes the width of a configured [TextPainter]. /// From 60634c65b222b1e29e55e87e5fead2277e214c7d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 10 Aug 2023 13:44:05 -0700 Subject: [PATCH 0647/1547] Upgrade flutter packages. (#132326) --- dev/automated_tests/pubspec.yaml | 11 +++++------ dev/benchmarks/complex_layout/pubspec.yaml | 11 +++++------ dev/benchmarks/macrobenchmarks/pubspec.yaml | 11 +++++------ dev/benchmarks/microbenchmarks/pubspec.yaml | 11 +++++------ .../multiple_flutters/module/pubspec.yaml | 8 ++++---- .../platform_channels_benchmarks/pubspec.yaml | 11 +++++------ .../platform_views_layout/pubspec.yaml | 11 +++++------ .../pubspec.yaml | 11 +++++------ dev/benchmarks/test_apps/stocks/pubspec.yaml | 11 +++++------ dev/bots/pubspec.yaml | 13 ++++++------- dev/conductor/core/pubspec.yaml | 11 +++++------ dev/customer_testing/pubspec.yaml | 11 +++++------ dev/devicelab/pubspec.yaml | 13 ++++++------- .../android_semantics_testing/pubspec.yaml | 11 +++++------ .../android_views/pubspec.yaml | 17 ++++++++--------- .../deferred_components_test/pubspec.yaml | 11 +++++------ dev/integration_tests/external_ui/pubspec.yaml | 11 +++++------ dev/integration_tests/flavors/pubspec.yaml | 11 +++++------ .../flutter_gallery/pubspec.yaml | 11 +++++------ .../gradle_deprecated_settings/pubspec.yaml | 10 +++++----- .../hybrid_android_views/pubspec.yaml | 17 ++++++++--------- .../ios_platform_view_tests/pubspec.yaml | 11 +++++------ .../platform_interaction/pubspec.yaml | 11 +++++------ dev/integration_tests/ui/pubspec.yaml | 11 +++++------ .../web_e2e_tests/pubspec.yaml | 11 +++++------ .../windows_startup_test/pubspec.yaml | 11 +++++------ dev/tools/gen_defaults/pubspec.yaml | 11 +++++------ dev/tools/gen_keycodes/pubspec.yaml | 11 +++++------ dev/tools/pubspec.yaml | 11 +++++------ examples/api/pubspec.yaml | 11 +++++------ examples/hello_world/pubspec.yaml | 11 +++++------ examples/platform_channel/pubspec.yaml | 11 +++++------ examples/platform_channel_swift/pubspec.yaml | 11 +++++------ examples/texture/pubspec.yaml | 11 +++++------ packages/flutter/pubspec.yaml | 11 +++++------ packages/flutter_driver/pubspec.yaml | 11 +++++------ packages/flutter_tools/pubspec.yaml | 11 +++++------ .../fuchsia_remote_debug_protocol/pubspec.yaml | 11 +++++------ packages/integration_test/example/pubspec.yaml | 11 +++++------ 39 files changed, 202 insertions(+), 239 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 3af15f456dfb0..69b4b79ea8b7b 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -13,10 +13,10 @@ dependencies: integration_test: sdk: flutter platform: 3.1.0 - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,7 +26,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,7 +57,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 90e3 +# PUBSPEC CHECKSUM: 4a29 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 0add398c2f9d8..0f7dee37a1c04 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -40,18 +40,17 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 integration_test: sdk: flutter - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,7 +70,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 1b02 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 60e156a59bc06..9a9ad7316db07 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -43,17 +43,16 @@ dependencies: webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 integration_test: sdk: flutter - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,7 +71,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -211,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 1b02 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 02c8cee8cb2ee..12e1fcf70fcb2 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -12,11 +12,11 @@ dependencies: sdk: flutter stocks: path: ../test_apps/stocks - test: 1.24.5 + test: 1.24.6 flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -26,7 +26,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,7 +58,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -138,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 8334 +# PUBSPEC CHECKSUM: 3579 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 2817865c68728..d16df86ae4d15 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -17,13 +17,13 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + ffi: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http: 0.13.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_android: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -38,7 +38,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 91fe +# PUBSPEC CHECKSUM: 46c9 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index bbc27ebff51c2..b8c158bb8b604 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../microbenchmarks cupertino_icons: 1.0.5 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,7 +27,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_gallery_assets: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,9 +57,9 @@ dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 071f +# PUBSPEC CHECKSUM: e664 diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index cd3b965385088..fada1d5bffcdf 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -40,16 +40,15 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,7 +68,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 1b02 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index c9519591cc9e2..3ede5ac0e5a01 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -40,16 +40,15 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,7 +68,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -82,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 50bc +# PUBSPEC CHECKSUM: 1b02 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 49f2cdc6d5a59..a5ca26cd66751 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -32,16 +32,15 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,7 +65,7 @@ dev_dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: d5de +# PUBSPEC CHECKSUM: 5b24 diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index aa7f54ee036a6..a6d9d9a00d994 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -16,11 +16,11 @@ dependencies: path: 1.8.3 platform: 3.1.0 process: 4.2.4 - test: 1.24.5 + test: 1.24.6 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -29,9 +29,8 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,7 +61,7 @@ dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +74,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 5232 +# PUBSPEC CHECKSUM: 0d78 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 0d9f0d93585ef..5d8fa01f7575c 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -30,15 +30,14 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 test_api: 0.6.1 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,11 +58,11 @@ dev_dependencies: source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 98bf +# PUBSPEC CHECKSUM: c505 diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 8165b2ecf7351..17a2f6a3f1dd0 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -18,15 +18,14 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,7 +47,7 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +55,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3e0d +# PUBSPEC CHECKSUM: 6852 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 4a0f12ca8a78e..5dfb48f93db9e 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - gcloud: 0.8.10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + gcloud: 0.8.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis: 3.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" googleapis_auth: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,13 +49,12 @@ dependencies: yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,8 +68,8 @@ dev_dependencies: source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 069f +# PUBSPEC CHECKSUM: f7e5 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 4bb0c77fd3db9..665fa107273ad 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: flutter_test: sdk: flutter pub_semver: 2.1.4 - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -24,7 +24,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,7 +53,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a7dc +# PUBSPEC CHECKSUM: 2422 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 7d269f49cd637..83565f0a4651f 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - path_provider: 2.0.15 + path_provider: 2.1.0 # This made non-transitive to allow exact pinning # https://github.com/flutter/flutter/issues/116376 path_provider_android: 2.1.0 @@ -25,7 +25,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + ffi: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,21 +49,20 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,7 +82,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -93,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7544 +# PUBSPEC CHECKSUM: 9c54 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 815f51e13395d..ad385517eec8d 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -35,16 +35,15 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,7 +63,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index a98b678a049dd..84cdc27130dc1 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,7 +21,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +51,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 6eaa diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index b58bd6965a1df..330456ad0dc35 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,7 +23,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,7 +53,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index beadeb0f2bd9a..de5f30817bfd5 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -58,19 +58,18 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter - test: 1.24.5 + test: 1.24.6 integration_test: sdk: flutter - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -98,7 +97,7 @@ dev_dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -277,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 2d08 +# PUBSPEC CHECKSUM: 554d diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index bc2faa5edf60e..f17db6ddf175e 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -7,14 +7,14 @@ environment: dependencies: flutter: sdk: flutter - camera: 0.10.5+2 + camera: 0.10.5+3 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_avfoundation: 0.9.13+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_avfoundation: 0.9.13+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_web: 0.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_web: 0.3.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.3+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: f4a6 +# PUBSPEC CHECKSUM: 9f06 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index fdcce7bc03c39..1a4e24836f093 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - path_provider: 2.0.15 + path_provider: 2.1.0 collection: 1.18.0 assets_for_android_views: git: @@ -22,7 +22,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - ffi: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + ffi: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,21 +47,20 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,7 +80,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 7544 +# PUBSPEC CHECKSUM: 9c54 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index ca8b8b2c4529c..47a9bea4ac4d1 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -35,16 +35,15 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,7 +63,7 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 1ca2802ac64f4..91ecf03b66b4f 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,7 +21,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +51,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 6eaa diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index e01cef777b9f3..a76ac73629c31 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: sdk: flutter integration_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -23,7 +23,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,7 +52,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 50782ae127044..68e3c3f3d6274 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -49,15 +49,14 @@ dev_dependencies: flutter_goldens: sdk: flutter http: 0.13.6 - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,11 +77,11 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 9207 +# PUBSPEC CHECKSUM: e84c diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 5ad79e827bd63..3e726bd34869d 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -9,10 +9,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,7 +21,6 @@ dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +51,7 @@ dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +62,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 6eaa diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 4fd3370b262d9..ad687f84177cc 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -10,17 +10,16 @@ dependencies: dev_dependencies: path: 1.8.3 - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,7 +47,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -56,4 +55,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3e0d +# PUBSPEC CHECKSUM: 6852 diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 1c543406e9959..0abcd5474df37 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -20,16 +20,15 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 test_api: 0.6.1 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -51,11 +50,11 @@ dev_dependencies: source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2004 +# PUBSPEC CHECKSUM: 7a49 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 71bb08f68b1e4..1dce1e953d8af 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -26,15 +26,14 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 test_api: 0.6.1 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,11 +54,11 @@ dev_dependencies: source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b61e +# PUBSPEC CHECKSUM: 2d63 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 94019eda081f4..882900961821a 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -31,10 +31,10 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,7 +42,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,7 +73,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -86,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a4d0 +# PUBSPEC CHECKSUM: 9516 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 658b6ebb2f29e..fddff49557526 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -19,10 +19,10 @@ dev_dependencies: sdk: flutter flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +59,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,4 +68,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 771b425a71c3c..6735bf56b6b8c 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -19,10 +19,10 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +59,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index b0174fe733b92..f4554126bd036 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -19,10 +19,10 @@ dev_dependencies: sdk: flutter flutter_driver: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -30,7 +30,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +59,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2d22 +# PUBSPEC CHECKSUM: ba67 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 0c7254667ccf2..fad02fa1db029 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -17,10 +17,10 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -28,7 +28,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,7 +56,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +64,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a7dc +# PUBSPEC CHECKSUM: 2422 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 4397753e04a96..dd753c75e994d 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -25,8 +25,8 @@ dev_dependencies: leak_tracker: 8.0.3 leak_tracker_testing: 1.0.2 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,7 +34,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,9 +63,9 @@ dev_dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +73,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 10f4 +# PUBSPEC CHECKSUM: 443a diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index e51fc3f4fd7f9..77e05775ddadc 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -39,15 +39,14 @@ dependencies: dev_dependencies: fake_async: 1.3.1 - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,11 +65,11 @@ dev_dependencies: shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d729 +# PUBSPEC CHECKSUM: a26e diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 4fa470fb15965..db71a194d144d 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -54,21 +54,20 @@ dependencies: # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. test_api: 0.6.1 - test_core: 0.5.5 + test_core: 0.5.6 vm_service: 11.9.0 standard_message_codec: 0.0.1+3 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_value: 8.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dds_service_extensions: 1.6.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" devtools_shared: 2.26.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -102,10 +101,10 @@ dev_dependencies: checked_yaml: 2.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test: 1.24.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 6b41 +# PUBSPEC CHECKSUM: 1a86 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 1b9eec759ca1d..7ee7ff7241109 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -16,10 +16,10 @@ dependencies: platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: - test: 1.24.5 + test: 1.24.6 - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -27,7 +27,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -53,7 +52,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +63,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: f314 +# PUBSPEC CHECKSUM: 5b59 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index aff039587fdef..b84a3410fb4d7 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -28,14 +28,14 @@ dev_dependencies: sdk: flutter integration_test_macos: path: ../integration_test_macos - test: 1.24.5 + test: 1.24.6 pedantic: 1.11.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 62.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,7 +43,6 @@ dev_dependencies: convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - dart_internal: 0.2.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fake_async: 1.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,7 +72,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - test_core: 0.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +84,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 5290 +# PUBSPEC CHECKSUM: 6ed5 From 4d42f1a8524e66308136e74c73414a182e607166 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 10 Aug 2023 13:53:05 -0700 Subject: [PATCH 0648/1547] GridView sample code (#131900) --- .../lib/widgets/scroll_view/grid_view.0.dart | 190 ++++++++++++++++++ .../widgets/scroll_view/grid_view.0_test.dart | 32 +++ .../lib/src/rendering/sliver_grid.dart | 40 +++- .../flutter/lib/src/widgets/scroll_view.dart | 32 ++- 4 files changed, 278 insertions(+), 16 deletions(-) create mode 100644 examples/api/lib/widgets/scroll_view/grid_view.0.dart create mode 100644 examples/api/test/widgets/scroll_view/grid_view.0_test.dart diff --git a/examples/api/lib/widgets/scroll_view/grid_view.0.dart b/examples/api/lib/widgets/scroll_view/grid_view.0.dart new file mode 100644 index 0000000000000..218429fde5ef2 --- /dev/null +++ b/examples/api/lib/widgets/scroll_view/grid_view.0.dart @@ -0,0 +1,190 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +void main() => runApp(const GridViewExampleApp()); + +class GridViewExampleApp extends StatelessWidget { + const GridViewExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Padding( + padding: const EdgeInsets.all(20.0), + child: Card( + elevation: 8.0, + child: GridView.builder( + padding: const EdgeInsets.all(12.0), + gridDelegate: CustomGridDelegate(dimension: 240.0), + // Try uncommenting some of these properties to see the effect on the grid: + // itemCount: 20, // The default is that the number of grid tiles is infinite. + // scrollDirection: Axis.horizontal, // The default is vertical. + // reverse: true, // The default is false, going down (or left to right). + itemBuilder: (BuildContext context, int index) { + final math.Random random = math.Random(index); + return GridTile( + header: GridTileBar( + title: Text('$index', style: const TextStyle(color: Colors.black)), + ), + child: Container( + margin: const EdgeInsets.all(12.0), + decoration: ShapeDecoration( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), + ), + gradient: const RadialGradient( + colors: [ Color(0x0F88EEFF), Color(0x2F0099BB) ], + ), + ), + child: FlutterLogo( + style: FlutterLogoStyle.values[random.nextInt(FlutterLogoStyle.values.length)], + ), + ), + ); + }, + ), + ), + ), + ); + } +} + +class CustomGridDelegate extends SliverGridDelegate { + CustomGridDelegate({ required this.dimension }); + + // This is the desired height of each row (and width of each square). + // When there is not enough room, we shrink this to the width of the scroll view. + final double dimension; + + // The layout is two rows of squares, then one very wide cell, repeat. + + @override + SliverGridLayout getLayout(SliverConstraints constraints) { + // Determine how many squares we can fit per row. + int count = constraints.crossAxisExtent ~/ dimension; + if (count < 1) { + count = 1; // Always fit at least one regardless. + } + final double squareDimension = constraints.crossAxisExtent / count; + return CustomGridLayout( + crossAxisCount: count, + fullRowPeriod: 3, // Number of rows per block (one of which is the full row). + dimension: squareDimension, + ); + } + + @override + bool shouldRelayout(CustomGridDelegate oldDelegate) { + return dimension != oldDelegate.dimension; + } +} + +class CustomGridLayout extends SliverGridLayout { + const CustomGridLayout({ + required this.crossAxisCount, + required this.dimension, + required this.fullRowPeriod, + }) : assert(crossAxisCount > 0), + assert(fullRowPeriod > 1), + loopLength = crossAxisCount * (fullRowPeriod - 1) + 1, + loopHeight = fullRowPeriod * dimension; + + final int crossAxisCount; + final double dimension; + final int fullRowPeriod; + + // Computed values. + final int loopLength; + final double loopHeight; + + @override + double computeMaxScrollOffset(int childCount) { + // This returns the scroll offset of the end side of the childCount'th child. + // In the case of this example, this method is not used, since the grid is + // infinite. However, if one set an itemCount on the GridView above, this + // function would be used to determine how far to allow the user to scroll. + if (childCount == 0 || dimension == 0) { + return 0; + } + return (childCount ~/ loopLength) * loopHeight + + ((childCount % loopLength) ~/ crossAxisCount) * dimension; + } + + @override + SliverGridGeometry getGeometryForChildIndex(int index) { + // This returns the position of the index'th tile. + // + // The SliverGridGeometry object returned from this method has four + // properties. For a grid that scrolls down, as in this example, the four + // properties are equivalent to x,y,width,height. However, since the + // GridView is direction agnostic, the names used for SliverGridGeometry are + // also direction-agnostic. + // + // Try changing the scrollDirection and reverse properties on the GridView + // to see how this algorithm works in any direction (and why, therefore, the + // names are direction-agnostic). + final int loop = index ~/ loopLength; + final int loopIndex = index % loopLength; + if (loopIndex == loopLength - 1) { + // Full width case. + return SliverGridGeometry( + scrollOffset: (loop + 1) * loopHeight - dimension, // "y" + crossAxisOffset: 0, // "x" + mainAxisExtent: dimension, // "height" + crossAxisExtent: crossAxisCount * dimension, // "width" + ); + } + // Square case. + final int rowIndex = loopIndex ~/ crossAxisCount; + final int columnIndex = loopIndex % crossAxisCount; + return SliverGridGeometry( + scrollOffset: (loop * loopHeight) + (rowIndex * dimension), // "y" + crossAxisOffset: columnIndex * dimension, // "x" + mainAxisExtent: dimension, // "height" + crossAxisExtent: dimension, // "width" + ); + } + + @override + int getMinChildIndexForScrollOffset(double scrollOffset) { + // This returns the first index that is visible for a given scrollOffset. + // + // The GridView only asks for the geometry of children that are visible + // between the scroll offset passed to getMinChildIndexForScrollOffset and + // the scroll offset passed to getMaxChildIndexForScrollOffset. + // + // It is the responsibility of the SliverGridLayout to ensure that + // getGeometryForChildIndex is consistent with getMinChildIndexForScrollOffset + // and getMaxChildIndexForScrollOffset. + // + // Not every child between the minimum child index and the maximum child + // index need be visible (some may have scroll offsets that are outside the + // view; this happens commonly when the grid view places tiles out of + // order). However, doing this means the grid view is less efficient, as it + // will do work for children that are not visible. It is preferred that the + // children are returned in the order that they are laid out. + final int rows = scrollOffset ~/ dimension; + final int loops = rows ~/ fullRowPeriod; + final int extra = rows % fullRowPeriod; + return loops * loopLength + extra * crossAxisCount; + } + + @override + int getMaxChildIndexForScrollOffset(double scrollOffset) { + // (See commentary above.) + final int rows = scrollOffset ~/ dimension; + final int loops = rows ~/ fullRowPeriod; + final int extra = rows % fullRowPeriod; + final int count = loops * loopLength + extra * crossAxisCount; + if (extra == fullRowPeriod - 1) { + return count; + } + return count + crossAxisCount - 1; + } +} diff --git a/examples/api/test/widgets/scroll_view/grid_view.0_test.dart b/examples/api/test/widgets/scroll_view/grid_view.0_test.dart new file mode 100644 index 0000000000000..9368a091d3b38 --- /dev/null +++ b/examples/api/test/widgets/scroll_view/grid_view.0_test.dart @@ -0,0 +1,32 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/rendering.dart'; +import 'package:flutter_api_samples/widgets/scroll_view/grid_view.0.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('$CustomGridLayout', (WidgetTester tester) async { + const CustomGridLayout layout = CustomGridLayout( + crossAxisCount: 2, + fullRowPeriod: 3, + dimension: 100, + ); + final List scrollOffsets = List.generate(10, (int i) => layout.computeMaxScrollOffset(i)); + expect(scrollOffsets, [0.0, 0.0, 100.0, 100.0, 200.0, 300.0, 300.0, 400.0, 400.0, 500.0]); + final List minOffsets = List.generate(10, (int i) => layout.getMinChildIndexForScrollOffset(i * 80.0)); + expect(minOffsets, [0, 0, 2, 4, 5, 7, 7, 9, 10, 12]); + final List maxOffsets = List.generate(10, (int i) => layout.getMaxChildIndexForScrollOffset(i * 80.0)); + expect(maxOffsets, [1, 1, 3, 4, 6, 8, 8, 9, 11, 13]); + final List offsets = List.generate(20, (int i) => layout.getGeometryForChildIndex(i)); + offsets.reduce((SliverGridGeometry a, SliverGridGeometry b) { + if (a.scrollOffset == b.scrollOffset) { + expect(a.crossAxisOffset, lessThan(b.crossAxisOffset)); + } else { + expect(a.scrollOffset, lessThan(b.scrollOffset)); + } + return b; + }); + }); +} diff --git a/packages/flutter/lib/src/rendering/sliver_grid.dart b/packages/flutter/lib/src/rendering/sliver_grid.dart index 78d412edf4118..d09aae2aa4136 100644 --- a/packages/flutter/lib/src/rendering/sliver_grid.dart +++ b/packages/flutter/lib/src/rendering/sliver_grid.dart @@ -13,6 +13,16 @@ import 'sliver_multi_box_adaptor.dart'; /// Describes the placement of a child in a [RenderSliverGrid]. /// +/// This class is similar to [Rect], in that it gives a two-dimensional position +/// and a two-dimensional dimension, but is direction-agnostic. +/// +/// {@tool dartpad} +/// This example shows how a custom [SliverGridLayout] uses [SliverGridGeometry] +/// to lay out the children. +/// +/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [SliverGridLayout], which represents the geometry of all the tiles in a @@ -60,7 +70,7 @@ class SliverGridGeometry { double get trailingScrollOffset => scrollOffset + mainAxisExtent; /// Returns a tight [BoxConstraints] that forces the child to have the - /// required size. + /// required size, given a [SliverConstraints]. BoxConstraints getBoxConstraints(SliverConstraints constraints) { return constraints.asBoxConstraints( minExtent: mainAxisExtent, @@ -83,13 +93,22 @@ class SliverGridGeometry { /// The size and position of all the tiles in a [RenderSliverGrid]. /// -/// Rather that providing a grid with a [SliverGridLayout] directly, you instead -/// provide the grid a [SliverGridDelegate], which can compute a -/// [SliverGridLayout] given the current [SliverConstraints]. +/// Rather that providing a grid with a [SliverGridLayout] directly, the grid is +/// provided a [SliverGridDelegate], which computes a [SliverGridLayout] given a +/// set of [SliverConstraints]. This allows the algorithm to dynamically respond +/// to changes in the environment (e.g. the user rotating the device). /// /// The tiles can be placed arbitrarily, but it is more efficient to place tiles -/// in roughly in order by scroll offset because grids reify a contiguous -/// sequence of children. +/// roughly in order by scroll offset because grids reify a contiguous sequence +/// of children. +/// +/// {@tool dartpad} +/// This example shows how to construct a custom [SliverGridLayout] to lay tiles +/// in a grid form with some cells stretched to fit the entire width of the +/// grid (sometimes called "hero tiles"). +/// +/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart ** +/// {@end-tool} /// /// See also: /// @@ -240,9 +259,16 @@ class SliverGridRegularTileLayout extends SliverGridLayout { /// /// Given the current constraints on the grid, a [SliverGridDelegate] computes /// the layout for the tiles in the grid. The tiles can be placed arbitrarily, -/// but it is more efficient to place tiles in roughly in order by scroll offset +/// but it is more efficient to place tiles roughly in order by scroll offset /// because grids reify a contiguous sequence of children. /// +/// {@tool dartpad} +/// This example shows how a [SliverGridDelegate] returns a [SliverGridLayout] +/// configured based on the provided [SliverConstraints] in [getLayout]. +/// +/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [SliverGridDelegateWithFixedCrossAxisCount], which creates a layout with diff --git a/packages/flutter/lib/src/widgets/scroll_view.dart b/packages/flutter/lib/src/widgets/scroll_view.dart index 47a1bddc3ab08..c097a1b785756 100644 --- a/packages/flutter/lib/src/widgets/scroll_view.dart +++ b/packages/flutter/lib/src/widgets/scroll_view.dart @@ -1681,6 +1681,10 @@ class ListView extends BoxScrollView { /// [SliverList] or [SliverAppBar], can be put in the [CustomScrollView.slivers] /// list. /// +/// {@macro flutter.widgets.ScrollView.PageStorage} +/// +/// ## Examples +/// /// {@tool snippet} /// This example demonstrates how to create a [GridView] with two columns. The /// children are spaced apart using the `crossAxisSpacing` and `mainAxisSpacing` @@ -1786,6 +1790,25 @@ class ListView extends BoxScrollView { /// ``` /// {@end-tool} /// +/// {@tool dartpad} +/// This example shows a custom implementation of selection in list and grid views. +/// Use the button in the top right (possibly hidden under the DEBUG banner) to toggle between +/// [ListView] and [GridView]. +/// Long press any [ListTile] or [GridTile] to enable selection mode. +/// +/// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This example shows a custom [SliverGridDelegate]. +/// +/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart ** +/// {@end-tool} +/// +/// ## Troubleshooting +/// +/// ### Padding +/// /// By default, [GridView] will automatically pad the limits of the /// grid's scrollable to avoid partial obstructions indicated by /// [MediaQuery]'s padding. To avoid this behavior, override with a @@ -1817,15 +1840,6 @@ class ListView extends BoxScrollView { /// ``` /// {@end-tool} /// -/// {@tool dartpad} -/// This example shows a custom implementation of [ListTile] selection in a [GridView] or [ListView]. -/// Long press any ListTile to enable selection mode. -/// -/// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart ** -/// {@end-tool} -/// -/// {@macro flutter.widgets.ScrollView.PageStorage} -/// /// See also: /// /// * [SingleChildScrollView], which is a scrollable widget that has a single From 82e2de0650b5f85914fd5fee0ef19c4a861fe0dd Mon Sep 17 00:00:00 2001 From: Danny Eldering <75845003+deldering-momo@users.noreply.github.com> Date: Thu, 10 Aug 2023 22:53:08 +0200 Subject: [PATCH 0649/1547] Fix: use --web-launch-url and --web-hostname arguments in flutter drive (#131763) Implement expected functionalities when supplying `--web-launch-url` and/or `--web-hostname` arguments to `flutter drive`. - `--web-launch-url` now sets the starting url for the (headless) browser - Which for example means you can start at a certain part of the app at the start of your integration test - `--web-hostname` now sets the hostname where the target of flutter drive will be hosted - Which allows you to set something other than localhost (allowing access via a reverse-proxy for example) Fixes #118028 --- .../flutter_gallery/.gitignore | 1 - .../lib/src/drive/web_driver_service.dart | 16 ++++++++++--- .../drive/web_driver_service_test.dart | 23 +++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/dev/integration_tests/flutter_gallery/.gitignore b/dev/integration_tests/flutter_gallery/.gitignore index a61bb46ed60fe..d8571249c6b57 100644 --- a/dev/integration_tests/flutter_gallery/.gitignore +++ b/dev/integration_tests/flutter_gallery/.gitignore @@ -1,3 +1,2 @@ -lib/generated_plugin_registrant.dart vmservice.out *.sksl.json diff --git a/packages/flutter_tools/lib/src/drive/web_driver_service.dart b/packages/flutter_tools/lib/src/drive/web_driver_service.dart index 445716b8712f5..ffd4a990dcf3e 100644 --- a/packages/flutter_tools/lib/src/drive/web_driver_service.dart +++ b/packages/flutter_tools/lib/src/drive/web_driver_service.dart @@ -41,6 +41,9 @@ class WebDriverService extends DriverService { late ResidentRunner _residentRunner; Uri? _webUri; + @visibleForTesting + Uri? get webUri => _webUri; + /// The result of [ResidentRunner.run]. /// /// This is expected to stay `null` throughout the test, as the application @@ -74,10 +77,12 @@ class WebDriverService extends DriverService { DebuggingOptions.disabled( buildInfo, port: debuggingOptions.port, + hostname: debuggingOptions.hostname, ) : DebuggingOptions.enabled( buildInfo, port: debuggingOptions.port, + hostname: debuggingOptions.hostname, disablePortPublication: debuggingOptions.disablePortPublication, ), stayResident: true, @@ -116,11 +121,16 @@ class WebDriverService extends DriverService { throw ToolExit('Failed to start application'); } - _webUri = _residentRunner.uri; - - if (_webUri == null) { + if (_residentRunner.uri == null) { throw ToolExit('Unable to connect to the app. URL not available.'); } + + if (debuggingOptions.webLaunchUrl != null) { + // It should thow an error if the provided url is invalid so no tryParse + _webUri = Uri.parse(debuggingOptions.webLaunchUrl!); + } else { + _webUri = _residentRunner.uri; + } } @override diff --git a/packages/flutter_tools/test/general.shard/drive/web_driver_service_test.dart b/packages/flutter_tools/test/general.shard/drive/web_driver_service_test.dart index bab05c5169cdb..28f66f2cc2fd6 100644 --- a/packages/flutter_tools/test/general.shard/drive/web_driver_service_test.dart +++ b/packages/flutter_tools/test/general.shard/drive/web_driver_service_test.dart @@ -258,6 +258,29 @@ void main() { WebRunnerFactory: () => FakeWebRunnerFactory(), }); + testUsingContext('WebDriverService can start an app with a launch url provided', () async { + final WebDriverService service = setUpDriverService(); + final FakeDevice device = FakeDevice(); + const String testUrl = 'http://localhost:1234/test'; + await service.start(BuildInfo.profile, device, DebuggingOptions.enabled(BuildInfo.profile, webLaunchUrl: testUrl), true); + await service.stop(); + expect(service.webUri, Uri.parse(testUrl)); + }, overrides: { + WebRunnerFactory: () => FakeWebRunnerFactory(), + }); + + testUsingContext('WebDriverService will throw when an invalid launch url is provided', () async { + final WebDriverService service = setUpDriverService(); + final FakeDevice device = FakeDevice(); + const String invalidTestUrl = '::INVALID_URL::'; + await expectLater( + service.start(BuildInfo.profile, device, DebuggingOptions.enabled(BuildInfo.profile, webLaunchUrl: invalidTestUrl), true), + throwsA(isA()), + ); + }, overrides: { + WebRunnerFactory: () => FakeWebRunnerFactory(), + }); + testUsingContext('WebDriverService forwards exception when run future fails before app starts', () async { final WebDriverService service = setUpDriverService(); final Device device = FakeDevice(); From eb126ccfc791f5e82f32fcfb7c003de7c6faf144 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 16:55:06 -0400 Subject: [PATCH 0650/1547] Roll Flutter Engine from ea7730c16301 to a9be77e6f475 (6 revisions) (#132328) https://github.com/flutter/engine/compare/ea7730c16301...a9be77e6f475 2023-08-10 55360120+Matt2D@users.noreply.github.com Flutter iOS Interactive Keyboard: Fixing Behavior Issue (flutter/engine#44586) 2023-08-10 bdero@google.com [Impeller] Flutter GPU: Add context override. (flutter/engine#44566) 2023-08-10 bdero@google.com [Impeller] External OpenGLES texture sampling. (flutter/engine#44559) 2023-08-10 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 961_tJawsbLMdy5i0... to konJQZKk2qXc276iA... (flutter/engine#44593) 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from 364900538771 to 92e6f52b0fa8 (1 revision) (flutter/engine#44592) 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from f39fd2de8f10 to 364900538771 (1 revision) (flutter/engine#44590) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 961_tJawsbLM to konJQZKk2qXc If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a10b3e1f9deae..f41099087f77c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ea7730c16301a7c40a511363de73ca852289ce88 +a9be77e6f47552cfcd5252112218d273d472e19b diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index cb7517e421e6d..fa9bf09790b32 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -961_tJawsbLMdy5i09FvefiD-ckFh6S_8yhK0SdtgW8C +konJQZKk2qXc276iAIxQgmZOqP26ZATMf3alFxYkhDIC From 1e35d3a6b702b9c804edc01fc4992567f7847f73 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 10 Aug 2023 14:14:06 -0700 Subject: [PATCH 0651/1547] setState documentation (#132090) Fixes https://github.com/flutter/flutter/issues/12296 --- dev/bots/analyze_snippet_code.dart | 3 +- .../flutter/lib/src/widgets/framework.dart | 67 ++++++++++++++++++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index b98b6ae0bc7c2..d29d6d251e558 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -458,8 +458,9 @@ class _SnippetChecker { } static const List ignoresDirectives = [ - '// ignore_for_file: duplicate_ignore', '// ignore_for_file: directives_ordering', + '// ignore_for_file: duplicate_ignore', + '// ignore_for_file: no_leading_underscores_for_local_identifiers', '// ignore_for_file: prefer_final_locals', '// ignore_for_file: unnecessary_import', '// ignore_for_file: unreachable_from_main', diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 3a432ee3a9402..6c5c231a34830 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -45,6 +45,7 @@ export 'package:flutter/rendering.dart' show RenderBox, RenderObject, debugDumpL // late Object? _myState, newValue; // int _counter = 0; // Future getApplicationDocumentsDirectory() async => Directory(''); +// late AnimationController animation; // An annotation used by test_analysis package to verify patterns are followed // that allow for tree-shaking of both fields and their initializers. This @@ -1092,9 +1093,73 @@ abstract class State with Diagnosticable { /// } /// ``` /// + /// Sometimes, the changed state is in some other object not owned by the + /// widget [State], but the widget nonetheless needs to be updated to react to + /// the new state. This is especially common with [Listenable]s, such as + /// [AnimationController]s. + /// + /// In such cases, it is good practice to leave a comment in the callback + /// passed to [setState] that explains what state changed: + /// + /// ```dart + /// void _update() { + /// setState(() { /* The animation changed. */ }); + /// } + /// //... + /// animation.addListener(_update); + /// ``` + /// /// It is an error to call this method after the framework calls [dispose]. /// You can determine whether it is legal to call this method by checking - /// whether the [mounted] property is true. + /// whether the [mounted] property is true. That said, it is better practice + /// to cancel whatever work might trigger the [setState] rather than merely + /// checking for [mounted] before calling [setState], as otherwise CPU cycles + /// will be wasted. + /// + /// ## Design discussion + /// + /// The original version of this API was a method called `markNeedsBuild`, for + /// consistency with [RenderObject.markNeedsLayout], + /// [RenderObject.markNeedsPaint], _et al_. + /// + /// However, early user testing of the Flutter framework revealed that people + /// would call `markNeedsBuild()` much more often than necessary. Essentially, + /// people used it like a good luck charm, any time they weren't sure if they + /// needed to call it, they would call it, just in case. + /// + /// Naturally, this led to performance issues in applications. + /// + /// When the API was changed to take a callback instead, this practice was + /// greatly reduced. One hypothesis is that prompting developers to actually + /// update their state in a callback caused developers to think more carefully + /// about what exactly was being updated, and thus improved their understanding + /// of the appropriate times to call the method. + /// + /// In practice, the [setState] method's implementation is trivial: it calls + /// the provided callback synchronously, then calls [Element.markNeedsBuild]. + /// + /// ## Performance considerations + /// + /// There is minimal _direct_ overhead to calling this function, and as it is + /// expected to be called at most once per frame, the overhead is irrelevant + /// anyway. Nonetheless, it is best to avoid calling this function redundantly + /// (e.g. in a tight loop), as it does involve creating a closure and calling + /// it. The method is idempotent, there is no benefit to calling it more than + /// once per [State] per frame. + /// + /// The _indirect_ cost of causing this function, however, is high: it causes + /// the widget to rebuild, possibly triggering rebuilds for the entire subtree + /// rooted at this widget, and further triggering a relayout and repaint of + /// the entire corresponding [RenderObject] subtree. + /// + /// For this reason, this method should only be called when the [build] method + /// will, as a result of whatever state change was detected, change its result + /// meaningfully. + /// + /// See also: + /// + /// * [StatefulWidget], the API documentation for which has a section on + /// performance considerations that are relevant here. @protected void setState(VoidCallback fn) { assert(() { From 73e0dbf5f40f343cf0e787d9a59302058f8938f9 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Thu, 10 Aug 2023 14:25:05 -0700 Subject: [PATCH 0652/1547] TextField should correctly resolve provided style for material states (#132330) This change makes sure the style provided through the `TextField`s `style` parameter is resolved for material states before merging it with defaults. Fixes #132212 --- .../flutter/lib/src/material/text_field.dart | 3 +- .../test/material/text_field_test.dart | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index aa8f715bf905b..3e0cfe9f90ca4 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -1248,7 +1248,8 @@ class _TextFieldState extends State with RestorationMixin implements final ThemeData theme = Theme.of(context); final DefaultSelectionStyle selectionStyle = DefaultSelectionStyle.of(context); - final TextStyle style = _getInputStyleForState(theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.titleMedium!).merge(widget.style); + final TextStyle? providedStyle = MaterialStateProperty.resolveAs(widget.style, _materialState); + final TextStyle style = _getInputStyleForState(theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.titleMedium!).merge(providedStyle); final Brightness keyboardAppearance = widget.keyboardAppearance ?? theme.brightness; final TextEditingController controller = _effectiveController; final FocusNode focusNode = _effectiveFocusNode; diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 3697dbc37a380..68fc1b87c8b08 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -6592,6 +6592,41 @@ void main() { expect(editableText.style.color, theme.textTheme.bodyLarge!.color!.withOpacity(0.38)); }); + testWidgets('Provided style correctly resolves for material states', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController( + text: 'Atwater Peel Sherbrooke Bonaventure', + ); + + final ThemeData theme = ThemeData.light(useMaterial3: true); + + Widget buildFrame(bool enabled) { + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: TextField( + controller: controller, + enabled: enabled, + style: MaterialStateTextStyle.resolveWith((Set states) { + if (states.contains(MaterialState.disabled)) { + return const TextStyle(color: Colors.red); + } + return const TextStyle(color: Colors.blue); + }), + ), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame(false)); + EditableText editableText = tester.widget(find.byType(EditableText)); + expect(editableText.style.color, Colors.red); + await tester.pumpWidget(buildFrame(true)); + editableText = tester.widget(find.byType(EditableText)); + expect(editableText.style.color, Colors.blue); + }); + testWidgets('currentValueLength/maxValueLength are in the tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final TextEditingController controller = TextEditingController(); From 5df1c996add0ca8cff503ca084dc103b04142ba7 Mon Sep 17 00:00:00 2001 From: pdblasi-google <109253501+pdblasi-google@users.noreply.github.com> Date: Thu, 10 Aug 2023 14:31:06 -0700 Subject: [PATCH 0653/1547] Adds SemanticsNode Finders for searching the semantics tree (#127137) * Pulled `FinderBase` out of `Finder` * `FinderBase` can be used for any object, not just elements * Terminology was updated to be more "find" related * Re-implemented `Finder` using `FinderBase` * Backwards compatibility maintained with `_LegacyFinderMixin` * Introduced base classes for SemanticsNode finders * Introduced basic SemanticsNode finders through `find.semantics` * Updated some relevant matchers to make use of the more generic `FinderBase` Closes #123634 Closes #115874 --- .../flutter_gallery/test/live_smoketest.dart | 10 +- .../test_memory/image_cache_memory.dart | 2 +- .../test_memory/memory_nav.dart | 2 +- .../flutter/test/widgets/list_body_test.dart | 13 +- packages/flutter_test/lib/flutter_test.dart | 2 +- .../flutter_test/lib/src/all_elements.dart | 91 -- packages/flutter_test/lib/src/controller.dart | 96 +- packages/flutter_test/lib/src/finders.dart | 1053 +++++++++++++---- packages/flutter_test/lib/src/matchers.dart | 151 ++- .../flutter_test/lib/src/tree_traversal.dart | 156 +++ .../flutter_test/lib/src/widget_tester.dart | 12 +- packages/flutter_test/test/finders_test.dart | 805 +++++++++++++ packages/flutter_test/test/matchers_test.dart | 66 ++ .../flutter_test/test/widget_tester_test.dart | 287 ----- 14 files changed, 2037 insertions(+), 709 deletions(-) delete mode 100644 packages/flutter_test/lib/src/all_elements.dart create mode 100644 packages/flutter_test/lib/src/tree_traversal.dart diff --git a/dev/integration_tests/flutter_gallery/test/live_smoketest.dart b/dev/integration_tests/flutter_gallery/test/live_smoketest.dart index 26aae16dec966..44afcc9b0d0f2 100644 --- a/dev/integration_tests/flutter_gallery/test/live_smoketest.dart +++ b/dev/integration_tests/flutter_gallery/test/live_smoketest.dart @@ -126,11 +126,11 @@ class _LiveWidgetController extends LiveWidgetController { } /// Runs `finder` repeatedly until it finds one or more [Element]s. - Future _waitForElement(Finder finder) async { + Future> _waitForElement(FinderBase finder) async { if (frameSync) { await _waitUntilFrame(() => binding.transientCallbackCount == 0); } - await _waitUntilFrame(() => finder.precache()); + await _waitUntilFrame(() => finder.tryEvaluate()); if (frameSync) { await _waitUntilFrame(() => binding.transientCallbackCount == 0); } @@ -138,12 +138,12 @@ class _LiveWidgetController extends LiveWidgetController { } @override - Future tap(Finder finder, { int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true }) async { + Future tap(FinderBase finder, { int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true }) async { await super.tap(await _waitForElement(finder), pointer: pointer, buttons: buttons, warnIfMissed: warnIfMissed); } - Future scrollIntoView(Finder finder, {required double alignment}) async { - final Finder target = await _waitForElement(finder); + Future scrollIntoView(FinderBase finder, {required double alignment}) async { + final FinderBase target = await _waitForElement(finder); await Scrollable.ensureVisible(target.evaluate().single, duration: const Duration(milliseconds: 100), alignment: alignment); } } diff --git a/dev/integration_tests/flutter_gallery/test_memory/image_cache_memory.dart b/dev/integration_tests/flutter_gallery/test_memory/image_cache_memory.dart index 0533a5fca342c..ccac85a2ce1ba 100644 --- a/dev/integration_tests/flutter_gallery/test_memory/image_cache_memory.dart +++ b/dev/integration_tests/flutter_gallery/test_memory/image_cache_memory.dart @@ -56,7 +56,7 @@ Future main() async { do { await controller.drag(list, const Offset(0.0, -30.0)); await Future.delayed(const Duration(milliseconds: 20)); - } while (!lastItem.precache()); + } while (!lastItem.tryEvaluate()); debugPrint('==== MEMORY BENCHMARK ==== DONE ===='); } diff --git a/dev/integration_tests/flutter_gallery/test_memory/memory_nav.dart b/dev/integration_tests/flutter_gallery/test_memory/memory_nav.dart index d83f61f9d3dd1..5992b64b1aa60 100644 --- a/dev/integration_tests/flutter_gallery/test_memory/memory_nav.dart +++ b/dev/integration_tests/flutter_gallery/test_memory/memory_nav.dart @@ -60,7 +60,7 @@ Future main() async { do { await controller.drag(demoList, const Offset(0.0, -300.0)); await Future.delayed(const Duration(milliseconds: 20)); - } while (!demoItem.precache()); + } while (!demoItem.tryEvaluate()); // Ensure that the center of the "Text fields" item is visible // because that's where we're going to tap diff --git a/packages/flutter/test/widgets/list_body_test.dart b/packages/flutter/test/widgets/list_body_test.dart index 6fcc17e1b2c55..6ac39df8d32d5 100644 --- a/packages/flutter/test/widgets/list_body_test.dart +++ b/packages/flutter/test/widgets/list_body_test.dart @@ -15,13 +15,14 @@ const List children = [ void expectRects(WidgetTester tester, List expected) { final Finder finder = find.byType(SizedBox); - finder.precache(); final List actual = []; - for (int i = 0; i < expected.length; ++i) { - final Finder current = finder.at(i); - expect(current, findsOneWidget); - actual.add(tester.getRect(finder.at(i))); - } + finder.runCached(() { + for (int i = 0; i < expected.length; ++i) { + final Finder current = finder.at(i); + expect(current, findsOneWidget); + actual.add(tester.getRect(finder.at(i))); + } + }); expect(() => finder.at(expected.length), throwsRangeError); expect(actual, equals(expected)); } diff --git a/packages/flutter_test/lib/flutter_test.dart b/packages/flutter_test/lib/flutter_test.dart index 642f6973114b1..9d76239f03742 100644 --- a/packages/flutter_test/lib/flutter_test.dart +++ b/packages/flutter_test/lib/flutter_test.dart @@ -58,7 +58,6 @@ export 'dart:async' show Future; export 'src/_goldens_io.dart' if (dart.library.html) 'src/_goldens_web.dart'; export 'src/_matchers_io.dart' if (dart.library.html) 'src/_matchers_web.dart'; export 'src/accessibility.dart'; -export 'src/all_elements.dart'; export 'src/animation_sheet.dart'; export 'src/binding.dart'; export 'src/controller.dart'; @@ -83,5 +82,6 @@ export 'src/test_exception_reporter.dart'; export 'src/test_pointer.dart'; export 'src/test_text_input.dart'; export 'src/test_vsync.dart'; +export 'src/tree_traversal.dart'; export 'src/widget_tester.dart'; export 'src/window.dart'; diff --git a/packages/flutter_test/lib/src/all_elements.dart b/packages/flutter_test/lib/src/all_elements.dart deleted file mode 100644 index 76e62eb94b0a9..0000000000000 --- a/packages/flutter_test/lib/src/all_elements.dart +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; - -/// Provides an iterable that efficiently returns all the elements -/// rooted at the given element. See [CachingIterable] for details. -/// -/// This method must be called again if the tree changes. You cannot -/// call this function once, then reuse the iterable after having -/// changed the state of the tree, because the iterable returned by -/// this function caches the results and only walks the tree once. -/// -/// The same applies to any iterable obtained indirectly through this -/// one, for example the results of calling `where` on this iterable -/// are also cached. -Iterable collectAllElementsFrom( - Element rootElement, { - required bool skipOffstage, -}) { - return CachingIterable(_DepthFirstChildIterator(rootElement, skipOffstage)); -} - -/// Provides a recursive, efficient, depth first search of an element tree. -/// -/// [Element.visitChildren] does not guarantee order, but does guarantee stable -/// order. This iterator also guarantees stable order, and iterates in a left -/// to right order: -/// -/// 1 -/// / \ -/// 2 3 -/// / \ / \ -/// 4 5 6 7 -/// -/// Will iterate in order 2, 4, 5, 3, 6, 7. -/// -/// Performance is important here because this method is on the critical path -/// for flutter_driver and package:integration_test performance tests. -/// Performance is measured in the all_elements_bench microbenchmark. -/// Any changes to this implementation should check the before and after numbers -/// on that benchmark to avoid regressions in general performance test overhead. -/// -/// If we could use RTL order, we could save on performance, but numerous tests -/// have been written (and developers clearly expect) that LTR order will be -/// respected. -class _DepthFirstChildIterator implements Iterator { - _DepthFirstChildIterator(Element rootElement, this.skipOffstage) { - _fillChildren(rootElement); - } - - final bool skipOffstage; - - late Element _current; - - final List _stack = []; - - @override - Element get current => _current; - - @override - bool moveNext() { - if (_stack.isEmpty) { - return false; - } - - _current = _stack.removeLast(); - _fillChildren(_current); - - return true; - } - - void _fillChildren(Element element) { - // If we did not have to follow LTR order and could instead use RTL, - // we could avoid reversing this and the operation would be measurably - // faster. Unfortunately, a lot of tests depend on LTR order. - final List reversed = []; - if (skipOffstage) { - element.debugVisitOnstageChildren(reversed.add); - } else { - element.visitChildren(reversed.add); - } - // This is faster than _stack.addAll(reversed.reversed), presumably since - // we don't actually care about maintaining an iteration pointer. - while (reversed.isNotEmpty) { - _stack.add(reversed.removeLast()); - } - } -} diff --git a/packages/flutter_test/lib/src/controller.dart b/packages/flutter_test/lib/src/controller.dart index 3a89d3cdaf91a..e1f668de2451a 100644 --- a/packages/flutter_test/lib/src/controller.dart +++ b/packages/flutter_test/lib/src/controller.dart @@ -9,11 +9,11 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; -import 'all_elements.dart'; import 'event_simulation.dart'; import 'finders.dart'; import 'test_async_utils.dart'; import 'test_pointer.dart'; +import 'tree_traversal.dart'; import 'window.dart'; /// The default drag touch slop used to break up a large drag into multiple @@ -74,7 +74,7 @@ class SemanticsController { /// /// Will throw a [StateError] if the finder returns more than one element or /// if no semantics are found or are not enabled. - SemanticsNode find(Finder finder) { + SemanticsNode find(FinderBase finder) { TestAsyncUtils.guardSync(); if (!_controller.binding.semanticsEnabled) { throw StateError('Semantics are not enabled.'); @@ -149,7 +149,7 @@ class SemanticsController { /// parts of the traversal. /// * [orderedEquals], which can be given an [Iterable] to exactly /// match the order of the traversal. - Iterable simulatedAccessibilityTraversal({Finder? start, Finder? end, FlutterView? view}) { + Iterable simulatedAccessibilityTraversal({FinderBase? start, FinderBase? end, FlutterView? view}) { TestAsyncUtils.guardSync(); FlutterView? startView; FlutterView? endView; @@ -158,7 +158,7 @@ class SemanticsController { if (view != null && startView != view) { throw StateError( 'The start node is not part of the provided view.\n' - 'Finder: ${start.description}\n' + 'Finder: ${start.toString(describeSelf: true)}\n' 'View of start node: $startView\n' 'Specified view: $view' ); @@ -169,7 +169,7 @@ class SemanticsController { if (view != null && endView != view) { throw StateError( 'The end node is not part of the provided view.\n' - 'Finder: ${end.description}\n' + 'Finder: ${end.toString(describeSelf: true)}\n' 'View of end node: $endView\n' 'Specified view: $view' ); @@ -178,8 +178,8 @@ class SemanticsController { if (endView != null && startView != null && endView != startView) { throw StateError( 'The start and end node are in different views.\n' - 'Start finder: ${start!.description}\n' - 'End finder: ${end!.description}\n' + 'Start finder: ${start!.toString(describeSelf: true)}\n' + 'End finder: ${end!.toString(describeSelf: true)}\n' 'View of start node: $startView\n' 'View of end node: $endView' ); @@ -200,7 +200,7 @@ class SemanticsController { if (startIndex == -1) { throw StateError( 'The expected starting node was not found.\n' - 'Finder: ${start.description}\n\n' + 'Finder: ${start.toString(describeSelf: true)}\n\n' 'Expected Start Node: $startNode\n\n' 'Traversal: [\n ${traversal.join('\n ')}\n]'); } @@ -212,7 +212,7 @@ class SemanticsController { if (endIndex == -1) { throw StateError( 'The expected ending node was not found.\n' - 'Finder: ${end.description}\n\n' + 'Finder: ${end.toString(describeSelf: true)}\n\n' 'Expected End Node: $endNode\n\n' 'Traversal: [\n ${traversal.join('\n ')}\n]'); } @@ -342,11 +342,11 @@ abstract class WidgetController { /// /// * [view] which returns the [TestFlutterView] used when only a single /// view is being used. - TestFlutterView viewOf(Finder finder) { + TestFlutterView viewOf(FinderBase finder) { return _viewOf(finder) as TestFlutterView; } - FlutterView _viewOf(Finder finder) { + FlutterView _viewOf(FinderBase finder) { return firstWidget( find.ancestor( of: finder, @@ -356,7 +356,7 @@ abstract class WidgetController { } /// Checks if `finder` exists in the tree. - bool any(Finder finder) { + bool any(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().isNotEmpty; } @@ -377,7 +377,7 @@ abstract class WidgetController { /// /// * Use [firstWidget] if you expect to match several widgets but only want the first. /// * Use [widgetList] if you expect to match several widgets and want all of them. - T widget(Finder finder) { + T widget(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().single.widget as T; } @@ -388,7 +388,7 @@ abstract class WidgetController { /// Throws a [StateError] if `finder` is empty. /// /// * Use [widget] if you only expect to match one widget. - T firstWidget(Finder finder) { + T firstWidget(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().first.widget as T; } @@ -397,7 +397,7 @@ abstract class WidgetController { /// /// * Use [widget] if you only expect to match one widget. /// * Use [firstWidget] if you expect to match several but only want the first. - Iterable widgetList(Finder finder) { + Iterable widgetList(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().map((Element element) { final T result = element.widget as T; @@ -408,7 +408,7 @@ abstract class WidgetController { /// Find all layers that are children of the provided [finder]. /// /// The [finder] must match exactly one element. - Iterable layerListOf(Finder finder) { + Iterable layerListOf(FinderBase finder) { TestAsyncUtils.guardSync(); final Element element = finder.evaluate().single; final RenderObject object = element.renderObject!; @@ -437,7 +437,7 @@ abstract class WidgetController { /// /// * Use [firstElement] if you expect to match several elements but only want the first. /// * Use [elementList] if you expect to match several elements and want all of them. - T element(Finder finder) { + T element(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().single as T; } @@ -448,7 +448,7 @@ abstract class WidgetController { /// Throws a [StateError] if `finder` is empty. /// /// * Use [element] if you only expect to match one element. - T firstElement(Finder finder) { + T firstElement(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().first as T; } @@ -457,7 +457,7 @@ abstract class WidgetController { /// /// * Use [element] if you only expect to match one element. /// * Use [firstElement] if you expect to match several but only want the first. - Iterable elementList(Finder finder) { + Iterable elementList(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().cast(); } @@ -479,7 +479,7 @@ abstract class WidgetController { /// /// * Use [firstState] if you expect to match several states but only want the first. /// * Use [stateList] if you expect to match several states and want all of them. - T state(Finder finder) { + T state(FinderBase finder) { TestAsyncUtils.guardSync(); return _stateOf(finder.evaluate().single, finder); } @@ -491,7 +491,7 @@ abstract class WidgetController { /// matching widget has no state. /// /// * Use [state] if you only expect to match one state. - T firstState(Finder finder) { + T firstState(FinderBase finder) { TestAsyncUtils.guardSync(); return _stateOf(finder.evaluate().first, finder); } @@ -503,17 +503,17 @@ abstract class WidgetController { /// /// * Use [state] if you only expect to match one state. /// * Use [firstState] if you expect to match several but only want the first. - Iterable stateList(Finder finder) { + Iterable stateList(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().map((Element element) => _stateOf(element, finder)); } - T _stateOf(Element element, Finder finder) { + T _stateOf(Element element, FinderBase finder) { TestAsyncUtils.guardSync(); if (element is StatefulElement) { return element.state as T; } - throw StateError('Widget of type ${element.widget.runtimeType}, with ${finder.description}, is not a StatefulWidget.'); + throw StateError('Widget of type ${element.widget.runtimeType}, with ${finder.describeMatch(Plurality.many)}, is not a StatefulWidget.'); } /// Render objects of all the widgets currently in the widget tree @@ -535,7 +535,7 @@ abstract class WidgetController { /// /// * Use [firstRenderObject] if you expect to match several render objects but only want the first. /// * Use [renderObjectList] if you expect to match several render objects and want all of them. - T renderObject(Finder finder) { + T renderObject(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().single.renderObject! as T; } @@ -546,7 +546,7 @@ abstract class WidgetController { /// Throws a [StateError] if `finder` is empty. /// /// * Use [renderObject] if you only expect to match one render object. - T firstRenderObject(Finder finder) { + T firstRenderObject(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().first.renderObject! as T; } @@ -555,7 +555,7 @@ abstract class WidgetController { /// /// * Use [renderObject] if you only expect to match one render object. /// * Use [firstRenderObject] if you expect to match several but only want the first. - Iterable renderObjectList(Finder finder) { + Iterable renderObjectList(FinderBase finder) { TestAsyncUtils.guardSync(); return finder.evaluate().map((Element element) { final T result = element.renderObject! as T; @@ -603,7 +603,7 @@ abstract class WidgetController { /// For example, a test that verifies that tapping a disabled button does not /// trigger the button would set `warnIfMissed` to false, because the button /// would ignore the tap. - Future tap(Finder finder, {int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true}) { + Future tap(FinderBase finder, {int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true}) { return tapAt(getCenter(finder, warnIfMissed: warnIfMissed, callee: 'tap'), pointer: pointer, buttons: buttons); } @@ -628,7 +628,7 @@ abstract class WidgetController { /// * [tap], which presses and releases a pointer at the given location. /// * [longPress], which presses and releases a pointer with a gap in /// between long enough to trigger the long-press gesture. - Future press(Finder finder, {int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true}) { + Future press(FinderBase finder, {int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true}) { return TestAsyncUtils.guard(() { return startGesture(getCenter(finder, warnIfMissed: warnIfMissed, callee: 'press'), pointer: pointer, buttons: buttons); }); @@ -646,7 +646,7 @@ abstract class WidgetController { /// later verify that long-pressing the same location (using the same finder) /// has no effect (since the widget is now obscured), setting `warnIfMissed` /// to false on that second call. - Future longPress(Finder finder, {int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true}) { + Future longPress(FinderBase finder, {int? pointer, int buttons = kPrimaryButton, bool warnIfMissed = true}) { return longPressAt(getCenter(finder, warnIfMissed: warnIfMissed, callee: 'longPress'), pointer: pointer, buttons: buttons); } @@ -707,7 +707,7 @@ abstract class WidgetController { /// A fling is essentially a drag that ends at a particular speed. If you /// just want to drag and end without a fling, use [drag]. Future fling( - Finder finder, + FinderBase finder, Offset offset, double speed, { int? pointer, @@ -787,7 +787,7 @@ abstract class WidgetController { /// A fling is essentially a drag that ends at a particular speed. If you /// just want to drag and end without a fling, use [drag]. Future trackpadFling( - Finder finder, + FinderBase finder, Offset offset, double speed, { int? pointer, @@ -952,7 +952,7 @@ abstract class WidgetController { /// should be left to their default values. /// {@endtemplate} Future drag( - Finder finder, + FinderBase finder, Offset offset, { int? pointer, int buttons = kPrimaryButton, @@ -1085,7 +1085,7 @@ abstract class WidgetController { /// more accurate time control. /// {@endtemplate} Future timedDrag( - Finder finder, + FinderBase finder, Offset offset, Duration duration, { int? pointer, @@ -1282,14 +1282,14 @@ abstract class WidgetController { /// this method is being called from another that is forwarding its own /// `warnIfMissed` parameter (see e.g. the implementation of [tap]). /// {@endtemplate} - Offset getCenter(Finder finder, { bool warnIfMissed = false, String callee = 'getCenter' }) { + Offset getCenter(FinderBase finder, { bool warnIfMissed = false, String callee = 'getCenter' }) { return _getElementPoint(finder, (Size size) => size.center(Offset.zero), warnIfMissed: warnIfMissed, callee: callee); } /// Returns the point at the top left of the given widget. /// /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed} - Offset getTopLeft(Finder finder, { bool warnIfMissed = false, String callee = 'getTopLeft' }) { + Offset getTopLeft(FinderBase finder, { bool warnIfMissed = false, String callee = 'getTopLeft' }) { return _getElementPoint(finder, (Size size) => Offset.zero, warnIfMissed: warnIfMissed, callee: callee); } @@ -1297,7 +1297,7 @@ abstract class WidgetController { /// point is not inside the object's hit test area. /// /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed} - Offset getTopRight(Finder finder, { bool warnIfMissed = false, String callee = 'getTopRight' }) { + Offset getTopRight(FinderBase finder, { bool warnIfMissed = false, String callee = 'getTopRight' }) { return _getElementPoint(finder, (Size size) => size.topRight(Offset.zero), warnIfMissed: warnIfMissed, callee: callee); } @@ -1305,7 +1305,7 @@ abstract class WidgetController { /// point is not inside the object's hit test area. /// /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed} - Offset getBottomLeft(Finder finder, { bool warnIfMissed = false, String callee = 'getBottomLeft' }) { + Offset getBottomLeft(FinderBase finder, { bool warnIfMissed = false, String callee = 'getBottomLeft' }) { return _getElementPoint(finder, (Size size) => size.bottomLeft(Offset.zero), warnIfMissed: warnIfMissed, callee: callee); } @@ -1313,7 +1313,7 @@ abstract class WidgetController { /// point is not inside the object's hit test area. /// /// {@macro flutter.flutter_test.WidgetController.getCenter.warnIfMissed} - Offset getBottomRight(Finder finder, { bool warnIfMissed = false, String callee = 'getBottomRight' }) { + Offset getBottomRight(FinderBase finder, { bool warnIfMissed = false, String callee = 'getBottomRight' }) { return _getElementPoint(finder, (Size size) => size.bottomRight(Offset.zero), warnIfMissed: warnIfMissed, callee: callee); } @@ -1340,7 +1340,7 @@ abstract class WidgetController { /// in the documentation for the [flutter_test] library. static bool hitTestWarningShouldBeFatal = false; - Offset _getElementPoint(Finder finder, Offset Function(Size size) sizeToPoint, { required bool warnIfMissed, required String callee }) { + Offset _getElementPoint(FinderBase finder, Offset Function(Size size) sizeToPoint, { required bool warnIfMissed, required String callee }) { TestAsyncUtils.guardSync(); final Iterable elements = finder.evaluate(); if (elements.isEmpty) { @@ -1411,7 +1411,7 @@ abstract class WidgetController { /// Returns the size of the given widget. This is only valid once /// the widget's render object has been laid out at least once. - Size getSize(Finder finder) { + Size getSize(FinderBase finder) { TestAsyncUtils.guardSync(); final Element element = finder.evaluate().single; final RenderBox box = element.renderObject! as RenderBox; @@ -1579,7 +1579,7 @@ abstract class WidgetController { /// Returns the rect of the given widget. This is only valid once /// the widget's render object has been laid out at least once. - Rect getRect(Finder finder) => Rect.fromPoints(getTopLeft(finder), getBottomRight(finder)); + Rect getRect(FinderBase finder) => Rect.fromPoints(getTopLeft(finder), getBottomRight(finder)); /// Attempts to find the [SemanticsNode] of first result from `finder`. /// @@ -1596,7 +1596,7 @@ abstract class WidgetController { /// Will throw a [StateError] if the finder returns more than one element or /// if no semantics are found or are not enabled. // TODO(pdblasi-google): Deprecate this and point references to semantics.find. See https://github.com/flutter/flutter/issues/112670. - SemanticsNode getSemantics(Finder finder) => semantics.find(finder); + SemanticsNode getSemantics(FinderBase finder) => semantics.find(finder); /// Enable semantics in a test by creating a [SemanticsHandle]. /// @@ -1620,7 +1620,7 @@ abstract class WidgetController { /// /// * [Scrollable.ensureVisible], which is the production API used to /// implement this method. - Future ensureVisible(Finder finder) => Scrollable.ensureVisible(element(finder)); + Future ensureVisible(FinderBase finder) => Scrollable.ensureVisible(element(finder)); /// Repeatedly scrolls a [Scrollable] by `delta` in the /// [Scrollable.axisDirection] direction until a widget matching `finder` is @@ -1645,9 +1645,9 @@ abstract class WidgetController { /// /// * [dragUntilVisible], which implements the body of this method. Future scrollUntilVisible( - Finder finder, + FinderBase finder, double delta, { - Finder? scrollable, + FinderBase? scrollable, int maxScrolls = 50, Duration duration = const Duration(milliseconds: 50), } @@ -1688,8 +1688,8 @@ abstract class WidgetController { /// * [scrollUntilVisible], which wraps this method with an API that is more /// convenient when dealing with a [Scrollable]. Future dragUntilVisible( - Finder finder, - Finder view, + FinderBase finder, + FinderBase view, Offset moveStep, { int maxIteration = 50, Duration duration = const Duration(milliseconds: 50), diff --git a/packages/flutter_test/lib/src/finders.dart b/packages/flutter_test/lib/src/finders.dart index a79a5575c2595..4cff6b0d6e947 100644 --- a/packages/flutter_test/lib/src/finders.dart +++ b/packages/flutter_test/lib/src/finders.dart @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ui'; + import 'package:flutter/material.dart' show Tooltip; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; -import 'all_elements.dart'; +import 'binding.dart'; +import 'tree_traversal.dart'; /// Signature for [CommonFinders.byWidgetPredicate]. typedef WidgetPredicate = bool Function(Widget widget); @@ -14,7 +17,13 @@ typedef WidgetPredicate = bool Function(Widget widget); /// Signature for [CommonFinders.byElementPredicate]. typedef ElementPredicate = bool Function(Element element); -/// Some frequently used widget [Finder]s. +/// Signature for [CommonSemanticsFinders.byPredicate]. +typedef SemanticsNodePredicate = bool Function(SemanticsNode node); + +/// Signature for [FinderBase.describeMatch]. +typedef DescribeMatchCallback = String Function(Plurality plurality); + +/// Some frequently used [Finder]s and [SemanticsFinder]s. const CommonFinders find = CommonFinders._(); // Examples can assume: @@ -23,12 +32,16 @@ const CommonFinders find = CommonFinders._(); // late String filePath; // late Key backKey; -/// Provides lightweight syntax for getting frequently used widget [Finder]s. +/// Provides lightweight syntax for getting frequently used [Finder]s and +/// [SemanticsFinder]s through [semantics]. /// /// This class is instantiated once, as [find]. class CommonFinders { const CommonFinders._(); + /// Some frequently used semantics finders. + CommonSemanticsFinders get semantics => const CommonSemanticsFinders._(); + /// Finds [Text], [EditableText], and optionally [RichText] widgets /// containing string equal to the `text` argument. /// @@ -64,7 +77,7 @@ class CommonFinders { bool findRichText = false, bool skipOffstage = true, }) { - return _TextFinder( + return _TextWidgetFinder( text, findRichText: findRichText, skipOffstage: skipOffstage, @@ -108,7 +121,7 @@ class CommonFinders { bool findRichText = false, bool skipOffstage = true, }) { - return _TextContainingFinder( + return _TextContainingWidgetFinder( pattern, findRichText: findRichText, skipOffstage: skipOffstage @@ -121,12 +134,12 @@ class CommonFinders { /// ## Sample code /// /// ```dart - /// // Suppose you have a button with text 'Update' in it: + /// // Suppose there is a button with text 'Update' in it: /// const Button( /// child: Text('Update') /// ); /// - /// // You can find and tap on it like this: + /// // It can be found and tapped like this: /// tester.tap(find.widgetWithText(Button, 'Update')); /// ``` /// @@ -150,9 +163,9 @@ class CommonFinders { /// /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. - Finder image(ImageProvider image, { bool skipOffstage = true }) => _WidgetImageFinder(image, skipOffstage: skipOffstage); + Finder image(ImageProvider image, { bool skipOffstage = true }) => _ImageWidgetFinder(image, skipOffstage: skipOffstage); - /// Finds widgets by searching for one with a particular [Key]. + /// Finds widgets by searching for one with the given `key`. /// /// ## Sample code /// @@ -162,7 +175,7 @@ class CommonFinders { /// /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. - Finder byKey(Key key, { bool skipOffstage = true }) => _KeyFinder(key, skipOffstage: skipOffstage); + Finder byKey(Key key, { bool skipOffstage = true }) => _KeyWidgetFinder(key, skipOffstage: skipOffstage); /// Finds widgets by searching for widgets implementing a particular type. /// @@ -180,13 +193,13 @@ class CommonFinders { /// /// See also: /// * [byType], which does not do subtype tests. - Finder bySubtype({ bool skipOffstage = true }) => _WidgetSubtypeFinder(skipOffstage: skipOffstage); + Finder bySubtype({ bool skipOffstage = true }) => _SubtypeWidgetFinder(skipOffstage: skipOffstage); /// Finds widgets by searching for widgets with a particular type. /// /// This does not do subclass tests, so for example - /// `byType(StatefulWidget)` will never find anything since that's - /// an abstract class. + /// `byType(StatefulWidget)` will never find anything since [StatefulWidget] + /// is an abstract class. /// /// The `type` argument must be a subclass of [Widget]. /// @@ -201,7 +214,7 @@ class CommonFinders { /// /// See also: /// * [bySubtype], which allows subtype tests. - Finder byType(Type type, { bool skipOffstage = true }) => _WidgetTypeFinder(type, skipOffstage: skipOffstage); + Finder byType(Type type, { bool skipOffstage = true }) => _TypeWidgetFinder(type, skipOffstage: skipOffstage); /// Finds [Icon] widgets containing icon data equal to the `icon` /// argument. @@ -214,7 +227,7 @@ class CommonFinders { /// /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. - Finder byIcon(IconData icon, { bool skipOffstage = true }) => _WidgetIconFinder(icon, skipOffstage: skipOffstage); + Finder byIcon(IconData icon, { bool skipOffstage = true }) => _IconWidgetFinder(icon, skipOffstage: skipOffstage); /// Looks for widgets that contain an [Icon] descendant displaying [IconData] /// `icon` in it. @@ -222,12 +235,12 @@ class CommonFinders { /// ## Sample code /// /// ```dart - /// // Suppose you have a button with icon 'arrow_forward' in it: + /// // Suppose there is a button with icon 'arrow_forward' in it: /// const Button( /// child: Icon(Icons.arrow_forward) /// ); /// - /// // You can find and tap on it like this: + /// // It can be found and tapped like this: /// tester.tap(find.widgetWithIcon(Button, Icons.arrow_forward)); /// ``` /// @@ -240,18 +253,18 @@ class CommonFinders { ); } - /// Looks for widgets that contain an [Image] descendant displaying [ImageProvider] - /// `image` in it. + /// Looks for widgets that contain an [Image] descendant displaying + /// [ImageProvider] `image` in it. /// /// ## Sample code /// /// ```dart - /// // Suppose you have a button with image in it: + /// // Suppose there is a button with an image in it: /// Button( /// child: Image.file(File(filePath)) /// ); /// - /// // You can find and tap on it like this: + /// // It can be found and tapped like this: /// tester.tap(find.widgetWithImage(Button, FileImage(File(filePath)))); /// ``` /// @@ -268,7 +281,7 @@ class CommonFinders { /// /// This does not do subclass tests, so for example /// `byElementType(VirtualViewportElement)` will never find anything - /// since that's an abstract class. + /// since [RenderObjectElement] is an abstract class. /// /// The `type` argument must be a subclass of [Element]. /// @@ -280,39 +293,39 @@ class CommonFinders { /// /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. - Finder byElementType(Type type, { bool skipOffstage = true }) => _ElementTypeFinder(type, skipOffstage: skipOffstage); + Finder byElementType(Type type, { bool skipOffstage = true }) => _ElementTypeWidgetFinder(type, skipOffstage: skipOffstage); - /// Finds widgets whose current widget is the instance given by the + /// Finds widgets whose current widget is the instance given by the `widget` /// argument. /// /// ## Sample code /// /// ```dart - /// // Suppose you have a button created like this: + /// // Suppose there is a button created like this: /// Widget myButton = const Button( /// child: Text('Update') /// ); /// - /// // You can find and tap on it like this: + /// // It can be found and tapped like this: /// tester.tap(find.byWidget(myButton)); /// ``` /// /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. - Finder byWidget(Widget widget, { bool skipOffstage = true }) => _WidgetFinder(widget, skipOffstage: skipOffstage); + Finder byWidget(Widget widget, { bool skipOffstage = true }) => _ExactWidgetFinder(widget, skipOffstage: skipOffstage); - /// Finds widgets using a widget [predicate]. + /// Finds widgets using a widget `predicate`. /// /// ## Sample code /// /// ```dart /// expect(find.byWidgetPredicate( /// (Widget widget) => widget is Tooltip && widget.message == 'Back', - /// description: 'widget with tooltip "Back"', + /// description: 'with tooltip "Back"', /// ), findsOneWidget); /// ``` /// - /// If [description] is provided, then this uses it as the description of the + /// If `description` is provided, then this uses it as the description of the /// [Finder] and appears, for example, in the error message when the finder /// fails to locate the desired widget. Otherwise, the description prints the /// signature of the predicate function. @@ -320,10 +333,10 @@ class CommonFinders { /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. Finder byWidgetPredicate(WidgetPredicate predicate, { String? description, bool skipOffstage = true }) { - return _WidgetPredicateFinder(predicate, description: description, skipOffstage: skipOffstage); + return _WidgetPredicateWidgetFinder(predicate, description: description, skipOffstage: skipOffstage); } - /// Finds Tooltip widgets with the given message. + /// Finds [Tooltip] widgets with the given `message`. /// /// ## Sample code /// @@ -340,13 +353,13 @@ class CommonFinders { ); } - /// Finds widgets using an element [predicate]. + /// Finds widgets using an element `predicate`. /// /// ## Sample code /// /// ```dart /// expect(find.byElementPredicate( - /// // finds elements of type SingleChildRenderObjectElement, including + /// // Finds elements of type SingleChildRenderObjectElement, including /// // those that are actually subclasses of that type. /// // (contrast with byElementType, which only returns exact matches) /// (Element element) => element is SingleChildRenderObjectElement, @@ -354,7 +367,7 @@ class CommonFinders { /// ), findsOneWidget); /// ``` /// - /// If [description] is provided, then this uses it as the description of the + /// If `description` is provided, then this uses it as the description of the /// [Finder] and appears, for example, in the error message when the finder /// fails to locate the desired widget. Otherwise, the description prints the /// signature of the predicate function. @@ -362,36 +375,37 @@ class CommonFinders { /// If the `skipOffstage` argument is true (the default), then this skips /// nodes that are [Offstage] or that are from inactive [Route]s. Finder byElementPredicate(ElementPredicate predicate, { String? description, bool skipOffstage = true }) { - return _ElementPredicateFinder(predicate, description: description, skipOffstage: skipOffstage); + return _ElementPredicateWidgetFinder(predicate, description: description, skipOffstage: skipOffstage); } - /// Finds widgets that are descendants of the [of] parameter and that match - /// the [matching] parameter. + /// Finds widgets that are descendants of the `of` parameter and that match + /// the `matching` parameter. /// /// ## Sample code /// /// ```dart /// expect(find.descendant( - /// of: find.widgetWithText(Row, 'label_1'), matching: find.text('value_1') + /// of: find.widgetWithText(Row, 'label_1'), + /// matching: find.text('value_1'), /// ), findsOneWidget); /// ``` /// - /// If the [matchRoot] argument is true then the widget(s) specified by [of] + /// If the `matchRoot` argument is true then the widget(s) specified by `of` /// will be matched along with the descendants. /// - /// If the [skipOffstage] argument is true (the default), then nodes that are + /// If the `skipOffstage` argument is true (the default), then nodes that are /// [Offstage] or that are from inactive [Route]s are skipped. Finder descendant({ - required Finder of, - required Finder matching, + required FinderBase of, + required FinderBase matching, bool matchRoot = false, bool skipOffstage = true, }) { - return _DescendantFinder(of, matching, matchRoot: matchRoot, skipOffstage: skipOffstage); + return _DescendantWidgetFinder(of, matching, matchRoot: matchRoot, skipOffstage: skipOffstage); } - /// Finds widgets that are ancestors of the [of] parameter and that match - /// the [matching] parameter. + /// Finds widgets that are ancestors of the `of` parameter and that match + /// the `matching` parameter. /// /// ## Sample code /// @@ -409,14 +423,14 @@ class CommonFinders { /// ); /// ``` /// - /// If the [matchRoot] argument is true then the widget(s) specified by [of] + /// If the `matchRoot` argument is true then the widget(s) specified by `of` /// will be matched along with the ancestors. Finder ancestor({ - required Finder of, - required Finder matching, + required FinderBase of, + required FinderBase matching, bool matchRoot = false, }) { - return _AncestorFinder(of, matching, matchRoot: matchRoot); + return _AncestorWidgetFinder(of, matching, matchLeaves: matchRoot); } /// Finds [Semantics] widgets matching the given `label`, either by @@ -466,58 +480,441 @@ class CommonFinders { } } -/// Searches a widget tree and returns nodes that match a particular -/// pattern. -abstract class Finder { - /// Initializes a Finder. Used by subclasses to initialize the [skipOffstage] - /// property. - Finder({ this.skipOffstage = true }); - /// Describes what the finder is looking for. The description should be - /// a brief English noun phrase describing the finder's pattern. - String get description; +/// Provides lightweight syntax for getting frequently used semantics finders. +/// +/// This class is instantiated once, as [CommonFinders.semantics], under [find]. +class CommonSemanticsFinders { + const CommonSemanticsFinders._(); - /// Returns all the elements in the given list that match this - /// finder's pattern. + /// Finds an ancestor of `of` that matches `matching`. /// - /// When implementing your own Finders that inherit directly from - /// [Finder], this is the main method to override. If your finder - /// can efficiently be described just in terms of a predicate - /// function, consider extending [MatchFinder] instead. - Iterable apply(Iterable candidates); + /// If `matchRoot` is true, then the results of `of` are included in the + /// search and results. + FinderBase ancestor({ + required FinderBase of, + required FinderBase matching, + bool matchRoot = false, + }) { + return _AncestorSemanticsFinder(of, matching, matchRoot); + } - /// Whether this finder skips nodes that are offstage. + /// Finds a descendant of `of` that matches `matching`. /// - /// If this is true, then the elements are walked using - /// [Element.debugVisitOnstageChildren]. This skips offstage children of - /// [Offstage] widgets, as well as children of inactive [Route]s. - final bool skipOffstage; + /// If `matchRoot` is true, then the results of `of` are included in the + /// search and results. + FinderBase descendant({ + required FinderBase of, + required FinderBase matching, + bool matchRoot = false, + }) { + return _DescendantSemanticsFinder(of, matching, matchRoot: matchRoot); + } + + /// Finds any [SemanticsNode]s matching the given `predicate`. + /// + /// If `describeMatch` is provided, it will be used to describe the + /// [FinderBase] and [FinderResult]s. + /// {@macro flutter_test.finders.FinderBase.describeMatch} + /// + /// {@template flutter_test.finders.CommonSemanticsFinders.viewParameter} + /// The `view` provided will be used to determine the semantics tree where + /// the search will be evaluated. If not provided, the search will be + /// evaluated against the semantics tree of [WidgetTester.view]. + /// {@endtemplate} + SemanticsFinder byPredicate( + SemanticsNodePredicate predicate, { + DescribeMatchCallback? describeMatch, + FlutterView? view, + }) { + return _PredicateSemanticsFinder( + predicate, + describeMatch, + _rootFromView(view), + ); + } + + /// Finds any [SemanticsNode]s that has a [SemanticsNode.label] that matches + /// the given `label`. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byLabel(Pattern label, {FlutterView? view}) { + return byPredicate( + (SemanticsNode node) => _matchesPattern(node.label, label), + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with label "$label"', + view: view, + ); + } + + /// Finds any [SemanticsNode]s that has a [SemanticsNode.value] that matches + /// the given `value`. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byValue(Pattern value, {FlutterView? view}) { + return byPredicate( + (SemanticsNode node) => _matchesPattern(node.value, value), + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with value "$value"', + view: view, + ); + } + + /// Finds any [SemanticsNode]s that has a [SemanticsNode.hint] that matches + /// the given `hint`. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byHint(Pattern hint, {FlutterView? view}) { + return byPredicate( + (SemanticsNode node) => _matchesPattern(node.hint, hint), + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with hint "$hint"', + view: view, + ); + } + + /// Finds any [SemanticsNode]s that has the given [SemanticsAction]. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byAction(SemanticsAction action, {FlutterView? view}) { + return byPredicate( + (SemanticsNode node) => node.getSemanticsData().hasAction(action), + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with action "$action"', + view: view, + ); + } - /// Returns all the [Element]s that will be considered by this finder. + /// Finds any [SemanticsNode]s that has at least one of the given + /// [SemanticsAction]s. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byAnyAction(List actions, {FlutterView? view}) { + final int actionsInt = actions.fold(0, (int value, SemanticsAction action) => value | action.index); + return byPredicate( + (SemanticsNode node) => node.getSemanticsData().actions & actionsInt != 0, + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with any of the following actions: $actions', + view: view, + ); + } + + /// Finds any [SemanticsNode]s that has the given [SemanticsFlag]. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byFlag(SemanticsFlag flag, {FlutterView? view}) { + return byPredicate( + (SemanticsNode node) => node.hasFlag(flag), + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with flag "$flag"', + view: view, + ); + } + + /// Finds any [SemanticsNode]s that has at least one of the given + /// [SemanticsFlag]s. + /// + /// {@macro flutter_test.finders.CommonSemanticsFinders.viewParameter} + SemanticsFinder byAnyFlag(List flags, {FlutterView? view}) { + final int flagsInt = flags.fold(0, (int value, SemanticsFlag flag) => value | flag.index); + return byPredicate( + (SemanticsNode node) => node.getSemanticsData().flags & flagsInt != 0, + describeMatch: (Plurality plurality) => '${switch (plurality) { + Plurality.one => 'SemanticsNode', + Plurality.zero || Plurality.many => 'SemanticsNodes', + }} with any of the following flags: $flags', + view: view, + ); + } + + bool _matchesPattern(String target, Pattern pattern) { + if (pattern is RegExp) { + return pattern.hasMatch(target); + } else { + return pattern == target; + } + } + + SemanticsNode _rootFromView(FlutterView? view) { + view ??= TestWidgetsFlutterBinding.instance.platformDispatcher.implicitView; + assert(view != null, 'The given view was not available. Ensure WidgetTester.view is available or pass in a specific view using WidgetTester.viewOf.'); + final RenderView renderView = TestWidgetsFlutterBinding.instance.renderViews + .firstWhere((RenderView r) => r.flutterView == view); + + return renderView.owner!.semanticsOwner!.rootSemanticsNode!; + } +} + +/// Describes how a string of text should be pluralized. +enum Plurality { + /// Text should be pluralized to describe zero items. + zero, + /// Text should be pluralized to describe a single item. + one, + /// Text should be pluralized to describe more than one item. + many; + + static Plurality _fromNum(num source) { + assert(source >= 0, 'A Plurality can only be created with a positive number.'); + return switch (source) { + 0 => Plurality.zero, + 1 => Plurality.one, + _ => Plurality.many, + }; + } +} + +/// Encapsulates the logic for searching a list of candidates and filtering the +/// candidates to only those that meet the requirements defined by the finder. +/// +/// Implementations will need to implement [allCandidates] to define the total +/// possible search space and [findInCandidates] to define the requirements of +/// the finder. +/// +/// This library contains [Finder] and [SemanticsFinder] for searching +/// Flutter's element and semantics trees respectively. +/// +/// If the search can be represented as a predicate, then consider using +/// [MatchFinderMixin] along with the [Finder] or [SemanticsFinder] base class. +/// +/// If the search further filters the results from another finder, consider using +/// [ChainedFinderMixin] along with the [Finder] or [SemanticsFinder] base class. +abstract class FinderBase { + bool _cached = false; + + /// The results of the latest [evaluate] or [tryEvaluate] call. + /// + /// Unlike [evaluate] and [tryEvaluate], [found] will not re-execute the + /// search for this finder. Either [evaluate] or [tryEvaluate] must be called + /// before accessing [found]. + FinderResult get found { + assert( + _found != null, + 'No results have been found yet. ' + 'Either `evaluate` or `tryEvaluate` must be called before accessing `found`', + ); + return _found!; + } + FinderResult? _found; + + /// Whether or not this finder has any results in [found]. + bool get hasFound => _found != null; + + /// Describes zero, one, or more candidates that match the requirements of a + /// finder. /// - /// This is the internal API for the [Finder]. To obtain the elements from - /// a [Finder] in a test, consider [WidgetTester.elementList]. + /// {@template flutter_test.finders.FinderBase.describeMatch} + /// The description returned should be a brief English phrase describing a + /// matching candidate with the proper plural form. As an example for a string + /// finder that is looking for strings starting with "hello": /// - /// See [collectAllElementsFrom]. + /// ```dart + /// String describeMatch(Plurality plurality) { + /// return switch (plurality) { + /// Plurality.zero || Plurality.many => 'strings starting with "hello"', + /// Plurality.one => 'string starting with "hello"', + /// }; + /// } + /// ``` + /// {@endtemplate} + /// + /// This will be used both to describe a finder and the results of searching + /// with that finder. + /// + /// See also: + /// + /// * [FinderBase.toString] where this is used to fully describe the finder + /// * [FinderResult.toString] where this is used to provide context to the + /// results of a search + String describeMatch(Plurality plurality); + + /// Returns all of the items that will be considered by this finder. @protected - Iterable get allCandidates { - return collectAllElementsFrom( - WidgetsBinding.instance.rootElement!, - skipOffstage: skipOffstage, + Iterable get allCandidates; + + /// Returns a variant of this finder that only matches the first item + /// found by this finder. + FinderBase get first => _FirstFinder(this); + + /// Returns a variant of this finder that only matches the last item + /// found by this finder. + FinderBase get last => _LastFinder(this); + + /// Returns a variant of this finder that only matches the item at the + /// given index found by this finder. + FinderBase at(int index) => _IndexFinder(this, index); + + /// Returns all the items in the given list that match this + /// finder's requirements. + /// + /// This is overridden to define the requirements of the finder when + /// implementing finders that directly extend [FinderBase]. If a finder can + /// be efficiently described just in terms of a predicate function, consider + /// mixing in [MatchFinderMixin] and implementing [MatchFinderMixin.matches] + /// instead. + @protected + Iterable findInCandidates(Iterable candidates); + + /// Searches a set of candidates for those that meet the requirements set by + /// this finder and returns the result of that search. + /// + /// See also: + /// + /// * [found] which will return the latest results without re-executing the + /// search. + /// * [tryEvaluate] which will indicate whether any results were found rather + /// than directly returning results. + FinderResult evaluate() { + if (!_cached || _found == null) { + _found = FinderResult(describeMatch, findInCandidates(allCandidates)); + } + return found; + } + + /// Searches a set of candidates for those that meet the requirements set by + /// this finder and returns whether the search found any matching candidates. + /// + /// This is useful in cases where an action needs to be repeated while or + /// until a finder has results. The results from the search can be accessed + /// using the [found] property without re-executing the search. + /// + /// ## Sample code + /// + /// ```dart + /// testWidgets('Top text loads first', (WidgetTester tester) async { + /// // Assume a widget is pumped with a top and bottom loading area, with + /// // the texts "Top loaded" and "Bottom loaded" when loading is complete. + /// // await tester.pumpWidget(...) + /// + /// // Wait until at least one loaded widget is available + /// Finder loadedFinder = find.textContaining('loaded'); + /// while (!loadedFinder.tryEvaluate()) { + /// await tester.pump(const Duration(milliseconds: 100)); + /// } + /// + /// expect(loadedFinder.found, hasLength(1)); + /// expect(tester.widget(loadedFinder).data, contains('Top')); + /// }); + /// ``` + bool tryEvaluate() { + evaluate(); + return found.isNotEmpty; + } + + /// Runs the given callback using cached results. + /// + /// While in this callback, this [FinderBase] will cache the results from the + /// next call to [evaluate] or [tryEvaluate] and then no longer evaluate new results + /// until the callback completes. After the first call, all calls to [evaluate], + /// [tryEvaluate] or [found] will return the same results without evaluating. + void runCached(VoidCallback run) { + reset(); + _cached = true; + try { + run(); + } finally { + reset(); + _cached = false; + } + } + + /// Resets all state of this [FinderBase]. + /// + /// Generally used between tests to reset the state of [found] if a finder is + /// used across multiple tests. + void reset() { + _found = null; + } + + /// A string representation of this finder or its results. + /// + /// By default, this describes the results of the search in order to play + /// nicely with [expect] and its output when a failure occurs. If you wish + /// to get a string representation of the finder itself, pass [describeSelf] + /// as `true`. + @override + String toString({bool describeSelf = false}) { + if (describeSelf) { + return 'A finder that searches for ${describeMatch(Plurality.many)}.'; + } else { + if (!hasFound) { + evaluate(); + } + return found.toString(); + } + } +} + +/// The results of searching with a [FinderBase]. +class FinderResult extends Iterable { + /// Creates a new [FinderResult] that describes the `values` using the given + /// `describeMatch` callback. + /// + /// {@macro flutter_test.finders.FinderBase.describeMatch} + FinderResult(DescribeMatchCallback describeMatch, Iterable values) + : _describeMatch = describeMatch, _values = values; + + final DescribeMatchCallback _describeMatch; + final Iterable _values; + + @override + Iterator get iterator => _values.iterator; + + @override + String toString() { + final List valuesList = _values.toList(); + // This will put each value on its own line with a comma and indentation + final String valuesString = valuesList.fold( + '', + (String current, CandidateType candidate) => '$current\n $candidate,', ); + return 'Found ${valuesList.length} ${_describeMatch(Plurality._fromNum(valuesList.length))}: [' + '${valuesString.isNotEmpty ? '$valuesString\n' : ''}' + ']'; } +} + +/// Provides backwards compatibility with the original [Finder] API. +mixin _LegacyFinderMixin on FinderBase { + Iterable? _precacheResults; - Iterable? _cachedResult; + /// Describes what the finder is looking for. The description should be + /// a brief English noun phrase describing the finder's requirements. + @Deprecated( + 'Use FinderBase.describeMatch instead. ' + 'FinderBase.describeMatch allows for more readable descriptions and removes ambiguity about pluralization. ' + 'This feature was deprecated after v3.13.0-0.2.pre.' + ) + String get description; - /// Returns the current result. If [precache] was called and returned true, this will - /// cheaply return the result that was computed then. Otherwise, it creates a new - /// iterable to compute the answer. + /// Returns all the elements in the given list that match this + /// finder's pattern. /// - /// Calling this clears the cache from [precache]. - Iterable evaluate() { - final Iterable result = _cachedResult ?? apply(allCandidates); - _cachedResult = null; - return result; + /// When implementing Finders that inherit directly from + /// [Finder], [findInCandidates] is the main method to override. This method + /// is maintained for backwards compatibility and will be removed in a future + /// version of Flutter. If the finder can efficiently be described just in + /// terms of a predicate function, consider mixing in [MatchFinderMixin] + /// instead. + @Deprecated( + 'Override FinderBase.findInCandidates instead. ' + 'Using the FinderBase API allows for more consistent caching behavior and cleaner options for interacting with the widget tree. ' + 'This feature was deprecated after v3.13.0-0.2.pre.' + ) + Iterable apply(Iterable candidates) { + return findInCandidates(candidates); } /// Attempts to evaluate the finder. Returns whether any elements in the tree @@ -525,122 +922,221 @@ abstract class Finder { /// from [evaluate]. /// /// If this returns true, you must call [evaluate] before you call [precache] again. + @Deprecated( + 'Use FinderBase.tryFind or FinderBase.runCached instead. ' + 'Using the FinderBase API allows for more consistent caching behavior and cleaner options for interacting with the widget tree. ' + 'This feature was deprecated after v3.13.0-0.2.pre.' + ) bool precache() { - assert(_cachedResult == null); - final Iterable result = apply(allCandidates); - if (result.isNotEmpty) { - _cachedResult = result; + assert(_precacheResults == null); + if (tryEvaluate()) { return true; } - _cachedResult = null; + _precacheResults = null; return false; } - /// Returns a variant of this finder that only matches the first element - /// matched by this finder. - Finder get first => _FirstFinder(this); + @override + Iterable findInCandidates(Iterable candidates) { + return apply(candidates); + } +} - /// Returns a variant of this finder that only matches the last element - /// matched by this finder. - Finder get last => _LastFinder(this); +/// A base class for creating finders that search the [Element] tree for +/// [Widget]s. +/// +/// The [findInCandidates] method must be overriden and will be enforced at +/// compilation after [apply] is removed. +abstract class Finder extends FinderBase with _LegacyFinderMixin { + /// Creates a new [Finder] with the given `skipOffstage` value. + Finder({this.skipOffstage = true}); - /// Returns a variant of this finder that only matches the element at the - /// given index matched by this finder. - Finder at(int index) => _IndexFinder(this, index); + /// Whether this finder skips nodes that are offstage. + /// + /// If this is true, then the elements are walked using + /// [Element.debugVisitOnstageChildren]. This skips offstage children of + /// [Offstage] widgets, as well as children of inactive [Route]s. + final bool skipOffstage; + + @override + Finder get first => _FirstWidgetFinder(this); + + @override + Finder get last => _LastWidgetFinder(this); + + @override + Finder at(int index) => _IndexWidgetFinder(this, index); + + @override + Iterable get allCandidates { + return collectAllElementsFrom( + WidgetsBinding.instance.rootElement!, + skipOffstage: skipOffstage, + ); + } + + @override + String describeMatch(Plurality plurality) { + return switch (plurality) { + Plurality.zero ||Plurality.many => 'widgets with $description', + Plurality.one => 'widget with $description', + }; + } /// Returns a variant of this finder that only matches elements reachable by /// a hit test. /// - /// The [at] parameter specifies the location relative to the size of the + /// The `at` parameter specifies the location relative to the size of the /// target element where the hit test is performed. - Finder hitTestable({ Alignment at = Alignment.center }) => _HitTestableFinder(this, at); + Finder hitTestable({ Alignment at = Alignment.center }) => _HitTestableWidgetFinder(this, at); +} + +/// A base class for creating finders that search the semantics tree. +abstract class SemanticsFinder extends FinderBase { + /// Creates a new [SemanticsFinder] that will search starting at the given + /// `root`. + SemanticsFinder(this.root); + + /// The root of the semantics tree that this finder will search. + final SemanticsNode root; @override - String toString() { - final String additional = skipOffstage ? ' (ignoring offstage widgets)' : ''; - final List widgets = evaluate().toList(); - final int count = widgets.length; - if (count == 0) { - return 'zero widgets with $description$additional'; - } - if (count == 1) { - return 'exactly one widget with $description$additional: ${widgets.single}'; - } - if (count < 4) { - return '$count widgets with $description$additional: $widgets'; - } - return '$count widgets with $description$additional: ${widgets[0]}, ${widgets[1]}, ${widgets[2]}, ...'; + Iterable get allCandidates { + return collectAllSemanticsNodesFrom(root); } } -/// Applies additional filtering against a [parent] [Finder]. -abstract class ChainedFinder extends Finder { - /// Create a Finder chained against the candidates of another [Finder]. - ChainedFinder(this.parent); +/// A mixin that applies additional filtering to the results of a parent [Finder]. + mixin ChainedFinderMixin on FinderBase { - /// Another [Finder] that will run first. - final Finder parent; + /// Another finder whose results will be further filtered. + FinderBase get parent; /// Return another [Iterable] when given an [Iterable] of candidates from a - /// parent [Finder]. + /// parent [FinderBase]. /// - /// This is the method to implement when subclassing [ChainedFinder]. - Iterable filter(Iterable parentCandidates); + /// This is the main method to implement when mixing in [ChainedFinderMixin]. + Iterable filter(Iterable parentCandidates); @override - Iterable apply(Iterable candidates) { - return filter(parent.apply(candidates)); + Iterable findInCandidates(Iterable candidates) { + return filter(parent.findInCandidates(candidates)); } @override - Iterable get allCandidates => parent.allCandidates; + Iterable get allCandidates => parent.allCandidates; } -class _FirstFinder extends ChainedFinder { - _FirstFinder(super.parent); +/// Applies additional filtering against a [parent] widget finder. +abstract class ChainedFinder extends Finder with ChainedFinderMixin { + /// Create a Finder chained against the candidates of another `parent` [Finder]. + ChainedFinder(this.parent); @override - String get description => '${parent.description} (ignoring all but first)'; + final FinderBase parent; +} +mixin _FirstFinderMixin on ChainedFinderMixin{ @override - Iterable filter(Iterable parentCandidates) sync* { + String describeMatch(Plurality plurality) { + return '${parent.describeMatch(plurality)} (ignoring all but first)'; + } + + @override + Iterable filter(Iterable parentCandidates) sync* { yield parentCandidates.first; } } -class _LastFinder extends ChainedFinder { - _LastFinder(super.parent); +class _FirstFinder extends FinderBase + with ChainedFinderMixin, _FirstFinderMixin { + _FirstFinder(this.parent); @override - String get description => '${parent.description} (ignoring all but last)'; + final FinderBase parent; +} + +class _FirstWidgetFinder extends ChainedFinder with _FirstFinderMixin { + _FirstWidgetFinder(super.parent); @override - Iterable filter(Iterable parentCandidates) sync* { + String get description => describeMatch(Plurality.many); +} + +mixin _LastFinderMixin on ChainedFinderMixin { + @override + String describeMatch(Plurality plurality) { + return '${parent.describeMatch(plurality)} (ignoring all but first)'; + } + + @override + Iterable filter(Iterable parentCandidates) sync* { yield parentCandidates.last; } } -class _IndexFinder extends ChainedFinder { - _IndexFinder(super.parent, this.index); +class _LastFinder extends FinderBase + with ChainedFinderMixin, _LastFinderMixin{ + _LastFinder(this.parent); - final int index; + @override + final FinderBase parent; +} + +class _LastWidgetFinder extends ChainedFinder with _LastFinderMixin { + _LastWidgetFinder(super.parent); @override - String get description => '${parent.description} (ignoring all but index $index)'; + String get description => describeMatch(Plurality.many); +} + +mixin _IndexFinderMixin on ChainedFinderMixin { + int get index; @override - Iterable filter(Iterable parentCandidates) sync* { + String describeMatch(Plurality plurality) { + return '${parent.describeMatch(plurality)} (ignoring all but index $index)'; + } + + @override + Iterable filter(Iterable parentCandidates) sync* { yield parentCandidates.elementAt(index); } } -class _HitTestableFinder extends ChainedFinder { - _HitTestableFinder(super.parent, this.alignment); +class _IndexFinder extends FinderBase + with ChainedFinderMixin, _IndexFinderMixin { + _IndexFinder(this.parent, this.index); + + @override + final int index; + + @override + final FinderBase parent; +} + +class _IndexWidgetFinder extends ChainedFinder with _IndexFinderMixin { + _IndexWidgetFinder(super.parent, this.index); + + @override + final int index; + + @override + String get description => describeMatch(Plurality.many); +} + +class _HitTestableWidgetFinder extends ChainedFinder { + _HitTestableWidgetFinder(super.parent, this.alignment); final Alignment alignment; @override - String get description => '${parent.description} (considering only hit-testable ones)'; + String describeMatch(Plurality plurality) { + return '${parent.describeMatch(plurality)} (considering only hit-testable ones)'; + } + + @override + String get description => describeMatch(Plurality.many); @override Iterable filter(Iterable parentCandidates) sync* { @@ -660,24 +1156,27 @@ class _HitTestableFinder extends ChainedFinder { } } -/// Searches a widget tree and returns nodes that match a particular -/// pattern. -abstract class MatchFinder extends Finder { - /// Initializes a predicate-based Finder. Used by subclasses to initialize the - /// [skipOffstage] property. - MatchFinder({ super.skipOffstage }); - +/// A mixin for creating finders that search candidates for those that match +/// a given pattern. +mixin MatchFinderMixin on FinderBase { /// Returns true if the given element matches the pattern. /// - /// When implementing your own MatchFinder, this is the main method to override. - bool matches(Element candidate); + /// When implementing a MatchFinder, this is the main method to override. + bool matches(CandidateType candidate); @override - Iterable apply(Iterable candidates) { + Iterable findInCandidates(Iterable candidates) { return candidates.where(matches); } } +/// Searches candidates for any that match a particular pattern. +abstract class MatchFinder extends Finder with MatchFinderMixin { + /// Initializes a predicate-based Finder. Used by subclasses to initialize the + /// `skipOffstage` property. + MatchFinder({ super.skipOffstage }); +} + abstract class _MatchTextFinder extends MatchFinder { _MatchTextFinder({ this.findRichText = false, @@ -740,8 +1239,8 @@ abstract class _MatchTextFinder extends MatchFinder { } } -class _TextFinder extends _MatchTextFinder { - _TextFinder( +class _TextWidgetFinder extends _MatchTextFinder { + _TextWidgetFinder( this.text, { super.findRichText, super.skipOffstage, @@ -758,8 +1257,8 @@ class _TextFinder extends _MatchTextFinder { } } -class _TextContainingFinder extends _MatchTextFinder { - _TextContainingFinder( +class _TextContainingWidgetFinder extends _MatchTextFinder { + _TextContainingWidgetFinder( this.pattern, { super.findRichText, super.skipOffstage, @@ -776,8 +1275,8 @@ class _TextContainingFinder extends _MatchTextFinder { } } -class _KeyFinder extends MatchFinder { - _KeyFinder(this.key, { super.skipOffstage }); +class _KeyWidgetFinder extends MatchFinder { + _KeyWidgetFinder(this.key, { super.skipOffstage }); final Key key; @@ -790,8 +1289,8 @@ class _KeyFinder extends MatchFinder { } } -class _WidgetSubtypeFinder extends MatchFinder { - _WidgetSubtypeFinder({ super.skipOffstage }); +class _SubtypeWidgetFinder extends MatchFinder { + _SubtypeWidgetFinder({ super.skipOffstage }); @override String get description => 'is "$T"'; @@ -802,8 +1301,8 @@ class _WidgetSubtypeFinder extends MatchFinder { } } -class _WidgetTypeFinder extends MatchFinder { - _WidgetTypeFinder(this.widgetType, { super.skipOffstage }); +class _TypeWidgetFinder extends MatchFinder { + _TypeWidgetFinder(this.widgetType, { super.skipOffstage }); final Type widgetType; @@ -816,8 +1315,8 @@ class _WidgetTypeFinder extends MatchFinder { } } -class _WidgetImageFinder extends MatchFinder { - _WidgetImageFinder(this.image, { super.skipOffstage }); +class _ImageWidgetFinder extends MatchFinder { + _ImageWidgetFinder(this.image, { super.skipOffstage }); final ImageProvider image; @@ -836,8 +1335,8 @@ class _WidgetImageFinder extends MatchFinder { } } -class _WidgetIconFinder extends MatchFinder { - _WidgetIconFinder(this.icon, { super.skipOffstage }); +class _IconWidgetFinder extends MatchFinder { + _IconWidgetFinder(this.icon, { super.skipOffstage }); final IconData icon; @@ -851,8 +1350,8 @@ class _WidgetIconFinder extends MatchFinder { } } -class _ElementTypeFinder extends MatchFinder { - _ElementTypeFinder(this.elementType, { super.skipOffstage }); +class _ElementTypeWidgetFinder extends MatchFinder { + _ElementTypeWidgetFinder(this.elementType, { super.skipOffstage }); final Type elementType; @@ -865,8 +1364,8 @@ class _ElementTypeFinder extends MatchFinder { } } -class _WidgetFinder extends MatchFinder { - _WidgetFinder(this.widget, { super.skipOffstage }); +class _ExactWidgetFinder extends MatchFinder { + _ExactWidgetFinder(this.widget, { super.skipOffstage }); final Widget widget; @@ -879,15 +1378,15 @@ class _WidgetFinder extends MatchFinder { } } -class _WidgetPredicateFinder extends MatchFinder { - _WidgetPredicateFinder(this.predicate, { String? description, super.skipOffstage }) +class _WidgetPredicateWidgetFinder extends MatchFinder { + _WidgetPredicateWidgetFinder(this.predicate, { String? description, super.skipOffstage }) : _description = description; final WidgetPredicate predicate; final String? _description; @override - String get description => _description ?? 'widget matching predicate ($predicate)'; + String get description => _description ?? 'widget matching predicate'; @override bool matches(Element candidate) { @@ -895,15 +1394,15 @@ class _WidgetPredicateFinder extends MatchFinder { } } -class _ElementPredicateFinder extends MatchFinder { - _ElementPredicateFinder(this.predicate, { String? description, super.skipOffstage }) +class _ElementPredicateWidgetFinder extends MatchFinder { + _ElementPredicateWidgetFinder(this.predicate, { String? description, super.skipOffstage }) : _description = description; final ElementPredicate predicate; final String? _description; @override - String get description => _description ?? 'element matching predicate ($predicate)'; + String get description => _description ?? 'element matching predicate'; @override bool matches(Element candidate) { @@ -911,80 +1410,182 @@ class _ElementPredicateFinder extends MatchFinder { } } -class _DescendantFinder extends Finder { - _DescendantFinder( - this.ancestor, - this.descendant, { - this.matchRoot = false, - super.skipOffstage, - }); +class _PredicateSemanticsFinder extends SemanticsFinder + with MatchFinderMixin { + _PredicateSemanticsFinder(this.predicate, DescribeMatchCallback? describeMatch, super.root) + : _describeMatch = describeMatch; - final Finder ancestor; - final Finder descendant; - final bool matchRoot; + final SemanticsNodePredicate predicate; + final DescribeMatchCallback? _describeMatch; @override - String get description { - if (matchRoot) { - return '${descendant.description} in the subtree(s) beginning with ${ancestor.description}'; - } - return '${descendant.description} that has ancestor(s) with ${ancestor.description}'; + String describeMatch(Plurality plurality) { + return _describeMatch?.call(plurality) ?? + 'matching semantics predicate'; } @override - Iterable apply(Iterable candidates) { - final Iterable descendants = descendant.evaluate(); - return candidates.where((Element element) => descendants.contains(element)); + bool matches(SemanticsNode candidate) { + return predicate(candidate); } +} + +mixin _DescendantFinderMixin on FinderBase { + + FinderBase get ancestor; + FinderBase get descendant; + bool get matchRoot; @override - Iterable get allCandidates { - final Iterable ancestorElements = ancestor.evaluate(); - final List candidates = ancestorElements.expand( - (Element element) => collectAllElementsFrom(element, skipOffstage: skipOffstage) + String describeMatch(Plurality plurality) { + return '${descendant.describeMatch(plurality)} descending from ' + '${ancestor.describeMatch(plurality)}' + '${matchRoot ? ' inclusive' : ''}'; + } + + @override + Iterable findInCandidates(Iterable candidates) { + final Iterable descendants = descendant.evaluate(); + return candidates.where((CandidateType candidate) => descendants.contains(candidate)); + } + + @override + Iterable get allCandidates { + final Iterable ancestors = ancestor.evaluate(); + final List candidates = ancestors.expand( + (CandidateType ancestor) => _collectDescendants(ancestor) ).toSet().toList(); if (matchRoot) { - candidates.insertAll(0, ancestorElements); + candidates.insertAll(0, ancestors); } return candidates; } + + Iterable _collectDescendants(CandidateType root); } -class _AncestorFinder extends Finder { - _AncestorFinder(this.descendant, this.ancestor, { this.matchRoot = false }) : super(skipOffstage: false); +class _DescendantWidgetFinder extends Finder + with _DescendantFinderMixin { + _DescendantWidgetFinder( + this.ancestor, + this.descendant, { + this.matchRoot = false, + super.skipOffstage, + }); - final Finder ancestor; - final Finder descendant; + @override + final FinderBase ancestor; + @override + final FinderBase descendant; + @override final bool matchRoot; @override - String get description { - if (matchRoot) { - return 'ancestor ${ancestor.description} beginning with ${descendant.description}'; - } - return '${ancestor.description} which is an ancestor of ${descendant.description}'; + String get description => describeMatch(Plurality.many); + + @override + Iterable _collectDescendants(Element root) { + return collectAllElementsFrom(root, skipOffstage: skipOffstage); } +} + +class _DescendantSemanticsFinder extends FinderBase + with _DescendantFinderMixin { + _DescendantSemanticsFinder(this.ancestor, this.descendant, {this.matchRoot = false}); @override - Iterable apply(Iterable candidates) { - final Iterable ancestors = ancestor.evaluate(); - return candidates.where((Element element) => ancestors.contains(element)); + final FinderBase ancestor; + + @override + final FinderBase descendant; + + @override + final bool matchRoot; + + @override + Iterable _collectDescendants(SemanticsNode root) { + return collectAllSemanticsNodesFrom(root); } +} + +mixin _AncestorFinderMixin on FinderBase { + FinderBase get ancestor; + FinderBase get descendant; + bool get matchLeaves; @override - Iterable get allCandidates { - final List candidates = []; - for (final Element root in descendant.evaluate()) { - final List ancestors = []; - if (matchRoot) { - ancestors.add(root); + String describeMatch(Plurality plurality) { + return '${ancestor.describeMatch(plurality)} that are ancestors of ' + '${descendant.describeMatch(plurality)}' + '${matchLeaves ? ' inclusive' : ''}'; + } + + @override + Iterable findInCandidates(Iterable candidates) { + final Iterable ancestors = ancestor.evaluate(); + return candidates.where((CandidateType element) => ancestors.contains(element)); + } + + @override + Iterable get allCandidates { + final List candidates = []; + for (final CandidateType leaf in descendant.evaluate()) { + if (matchLeaves) { + candidates.add(leaf); } - root.visitAncestorElements((Element element) { - ancestors.add(element); - return true; - }); - candidates.addAll(ancestors); + candidates.addAll(_collectAncestors(leaf)); } return candidates; } + + Iterable _collectAncestors(CandidateType child); +} + +class _AncestorWidgetFinder extends Finder + with _AncestorFinderMixin { + _AncestorWidgetFinder(this.descendant, this.ancestor, { this.matchLeaves = false }) : super(skipOffstage: false); + + @override + final FinderBase ancestor; + @override + final FinderBase descendant; + @override + final bool matchLeaves; + + @override + String get description => describeMatch(Plurality.many); + + @override + Iterable _collectAncestors(Element child) { + final List ancestors = []; + child.visitAncestorElements((Element element) { + ancestors.add(element); + return true; + }); + return ancestors; + } +} + +class _AncestorSemanticsFinder extends FinderBase + with _AncestorFinderMixin { + _AncestorSemanticsFinder(this.descendant, this.ancestor, this.matchLeaves); + + @override + final FinderBase ancestor; + + @override + final FinderBase descendant; + + @override + final bool matchLeaves; + + @override + Iterable _collectAncestors(SemanticsNode child) { + final List ancestors = []; + while (child.parent != null) { + ancestors.add(child.parent!); + child = child.parent!; + } + return ancestors; + } } diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index 1e97df7cdfeca..54d02bf540432 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -16,11 +16,12 @@ import 'package:matcher/src/expect/async_matcher.dart'; // ignore: implementatio import '_matchers_io.dart' if (dart.library.html) '_matchers_web.dart' show MatchesGoldenFile, captureImage; import 'accessibility.dart'; import 'binding.dart'; +import 'controller.dart'; import 'finders.dart'; import 'goldens.dart'; import 'widget_tester.dart' show WidgetTester; -/// Asserts that the [Finder] matches no widgets in the widget tree. +/// Asserts that the [FinderBase] matches nothing in the available candidates. /// /// ## Sample code /// @@ -30,14 +31,16 @@ import 'widget_tester.dart' show WidgetTester; /// /// See also: /// -/// * [findsWidgets], when you want the finder to find one or more widgets. -/// * [findsOneWidget], when you want the finder to find exactly one widget. -/// * [findsNWidgets], when you want the finder to find a specific number of widgets. -/// * [findsAtLeastNWidgets], when you want the finder to find at least a specific number of widgets. -const Matcher findsNothing = _FindsWidgetMatcher(null, 0); +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsOne], when you want the finder to find exactly one candidate. +/// * [findsExactly], when you want the finder to find a specific number of candidates. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +const Matcher findsNothing = _FindsCountMatcher(null, 0); /// Asserts that the [Finder] locates at least one widget in the widget tree. /// +/// This is equivalent to the preferred [findsAny] method. +/// /// ## Sample code /// /// ```dart @@ -47,13 +50,31 @@ const Matcher findsNothing = _FindsWidgetMatcher(null, 0); /// See also: /// /// * [findsNothing], when you want the finder to not find anything. -/// * [findsOneWidget], when you want the finder to find exactly one widget. -/// * [findsNWidgets], when you want the finder to find a specific number of widgets. -/// * [findsAtLeastNWidgets], when you want the finder to find at least a specific number of widgets. -const Matcher findsWidgets = _FindsWidgetMatcher(1, null); +/// * [findsOne], when you want the finder to find exactly one candidate. +/// * [findsExactly], when you want the finder to find a specific number of candidates. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +const Matcher findsWidgets = _FindsCountMatcher(1, null); + +/// Asserts that the [FinderBase] locates at least one matching candidate. +/// +/// ## Sample code +/// +/// ```dart +/// expect(find.text('Save'), findsAny); +/// ``` +/// +/// See also: +/// +/// * [findsNothing], when you want the finder to not find anything. +/// * [findsOne], when you want the finder to find exactly one candidate. +/// * [findsExactly], when you want the finder to find a specific number of candidates. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +const Matcher findsAny = _FindsCountMatcher(1, null); /// Asserts that the [Finder] locates at exactly one widget in the widget tree. /// +/// This is equivalent to the preferred [findsOne] method. +/// /// ## Sample code /// /// ```dart @@ -63,13 +84,31 @@ const Matcher findsWidgets = _FindsWidgetMatcher(1, null); /// See also: /// /// * [findsNothing], when you want the finder to not find anything. -/// * [findsWidgets], when you want the finder to find one or more widgets. -/// * [findsNWidgets], when you want the finder to find a specific number of widgets. -/// * [findsAtLeastNWidgets], when you want the finder to find at least a specific number of widgets. -const Matcher findsOneWidget = _FindsWidgetMatcher(1, 1); +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsExactly], when you want the finder to find a specific number of candidates. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +const Matcher findsOneWidget = _FindsCountMatcher(1, 1); + +/// Asserts that the [FinderBase] finds exactly one matching candidate. +/// +/// ## Sample code +/// +/// ```dart +/// expect(find.text('Save'), findsOne); +/// ``` +/// +/// See also: +/// +/// * [findsNothing], when you want the finder to not find anything. +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsExactly], when you want the finder to find a specific number candidates. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +const Matcher findsOne = _FindsCountMatcher(1, 1); /// Asserts that the [Finder] locates the specified number of widgets in the widget tree. /// +/// This is equivalent to the preferred [findsExactly] method. +/// /// ## Sample code /// /// ```dart @@ -79,13 +118,31 @@ const Matcher findsOneWidget = _FindsWidgetMatcher(1, 1); /// See also: /// /// * [findsNothing], when you want the finder to not find anything. -/// * [findsWidgets], when you want the finder to find one or more widgets. -/// * [findsOneWidget], when you want the finder to find exactly one widget. -/// * [findsAtLeastNWidgets], when you want the finder to find at least a specific number of widgets. -Matcher findsNWidgets(int n) => _FindsWidgetMatcher(n, n); +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsOne], when you want the finder to find exactly one candidate. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +Matcher findsNWidgets(int n) => _FindsCountMatcher(n, n); + +/// Asserts that the [FinderBase] locates the specified number of candidates. +/// +/// ## Sample code +/// +/// ```dart +/// expect(find.text('Save'), findsExactly(2)); +/// ``` +/// +/// See also: +/// +/// * [findsNothing], when you want the finder to not find anything. +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsOne], when you want the finder to find exactly one candidates. +/// * [findsAtLeast], when you want the finder to find at least a specific number of candidates. +Matcher findsExactly(int n) => _FindsCountMatcher(n, n); /// Asserts that the [Finder] locates at least a number of widgets in the widget tree. /// +/// This is equivalent to the preferred [findsAtLeast] method. +/// /// ## Sample code /// /// ```dart @@ -95,10 +152,26 @@ Matcher findsNWidgets(int n) => _FindsWidgetMatcher(n, n); /// See also: /// /// * [findsNothing], when you want the finder to not find anything. -/// * [findsWidgets], when you want the finder to find one or more widgets. -/// * [findsOneWidget], when you want the finder to find exactly one widget. -/// * [findsNWidgets], when you want the finder to find a specific number of widgets. -Matcher findsAtLeastNWidgets(int n) => _FindsWidgetMatcher(n, null); +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsOne], when you want the finder to find exactly one candidate. +/// * [findsExactly], when you want the finder to find a specific number of candidates. +Matcher findsAtLeastNWidgets(int n) => _FindsCountMatcher(n, null); + +/// Asserts that the [FinderBase] locates at least the given number of candidates. +/// +/// ## Sample code +/// +/// ```dart +/// expect(find.text('Save'), findsAtLeast(2)); +/// ``` +/// +/// See also: +/// +/// * [findsNothing], when you want the finder to not find anything. +/// * [findsAny], when you want the finder to find one or more candidates. +/// * [findsOne], when you want the finder to find exactly one candidates. +/// * [findsExactly], when you want the finder to find a specific number of candidates. +Matcher findsAtLeast(int n) => _FindsCountMatcher(n, null); /// Asserts that the [Finder] locates a single widget that has at /// least one [Offstage] widget ancestor. @@ -527,7 +600,7 @@ AsyncMatcher matchesReferenceImage(ui.Image image) { /// /// See also: /// -/// * [WidgetTester.getSemantics], the tester method which retrieves semantics. +/// * [SemanticsController.find] under [WidgetTester.semantics], the tester method which retrieves semantics. /// * [containsSemantics], a similar matcher without default values for flags or actions. Matcher matchesSemantics({ String? label, @@ -707,7 +780,7 @@ Matcher matchesSemantics({ /// /// See also: /// -/// * [WidgetTester.getSemantics], the tester method which retrieves semantics. +/// * [SemanticsController.find] under [WidgetTester.semantics], the tester method which retrieves semantics. /// * [matchesSemantics], a similar matcher with default values for flags and actions. Matcher containsSemantics({ String? label, @@ -900,19 +973,19 @@ AsyncMatcher doesNotMeetGuideline(AccessibilityGuideline guideline) { return _DoesNotMatchAccessibilityGuideline(guideline); } -class _FindsWidgetMatcher extends Matcher { - const _FindsWidgetMatcher(this.min, this.max); +class _FindsCountMatcher extends Matcher { + const _FindsCountMatcher(this.min, this.max); final int? min; final int? max; @override - bool matches(covariant Finder finder, Map matchState) { + bool matches(covariant FinderBase finder, Map matchState) { assert(min != null || max != null); assert(min == null || max == null || min! <= max!); - matchState[Finder] = finder; + matchState[FinderBase] = finder; int count = 0; - final Iterator iterator = finder.evaluate().iterator; + final Iterator iterator = finder.evaluate().iterator; if (min != null) { while (count < min! && iterator.moveNext()) { count += 1; @@ -937,26 +1010,26 @@ class _FindsWidgetMatcher extends Matcher { assert(min != null || max != null); if (min == max) { if (min == 1) { - return description.add('exactly one matching node in the widget tree'); + return description.add('exactly one matching candidate'); } - return description.add('exactly $min matching nodes in the widget tree'); + return description.add('exactly $min matching candidates'); } if (min == null) { if (max == 0) { - return description.add('no matching nodes in the widget tree'); + return description.add('no matching candidates'); } if (max == 1) { - return description.add('at most one matching node in the widget tree'); + return description.add('at most one matching candidate'); } - return description.add('at most $max matching nodes in the widget tree'); + return description.add('at most $max matching candidates'); } if (max == null) { if (min == 1) { - return description.add('at least one matching node in the widget tree'); + return description.add('at least one matching candidate'); } - return description.add('at least $min matching nodes in the widget tree'); + return description.add('at least $min matching candidates'); } - return description.add('between $min and $max matching nodes in the widget tree (inclusive)'); + return description.add('between $min and $max matching candidates (inclusive)'); } @override @@ -966,8 +1039,8 @@ class _FindsWidgetMatcher extends Matcher { Map matchState, bool verbose, ) { - final Finder finder = matchState[Finder] as Finder; - final int count = finder.evaluate().length; + final FinderBase finder = matchState[FinderBase] as FinderBase; + final int count = finder.found.length; if (count == 0) { assert(min != null && min! > 0); if (min == 1 && max == 1) { diff --git a/packages/flutter_test/lib/src/tree_traversal.dart b/packages/flutter_test/lib/src/tree_traversal.dart new file mode 100644 index 0000000000000..5ae34e797c713 --- /dev/null +++ b/packages/flutter_test/lib/src/tree_traversal.dart @@ -0,0 +1,156 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/semantics.dart'; +import 'package:flutter/widgets.dart'; + +/// Provides an iterable that efficiently returns all the [Element]s +/// rooted at the given [Element]. See [CachingIterable] for details. +/// +/// This function must be called again if the tree changes. You cannot +/// call this function once, then reuse the iterable after having +/// changed the state of the tree, because the iterable returned by +/// this function caches the results and only walks the tree once. +/// +/// The same applies to any iterable obtained indirectly through this +/// one, for example the results of calling `where` on this iterable +/// are also cached. +Iterable collectAllElementsFrom( + Element rootElement, { + required bool skipOffstage, +}) { + return CachingIterable(_DepthFirstElementTreeIterator(rootElement, !skipOffstage)); +} + +/// Provides an iterable that efficiently returns all the [SemanticsNode]s +/// rooted at the given [SemanticsNode]. See [CachingIterable] for details. +/// +/// By default, this will traverse the semantics tree in semantic traversal +/// order, but the traversal order can be changed by passing in a different +/// value to `order`. +/// +/// This function must be called again if the semantics change. You cannot call +/// this function once, then reuse the iterable after having changed the state +/// of the tree, because the iterable returned by this function caches the +/// results and only walks the tree once. +/// +/// The same applies to any iterable obtained indirectly through this +/// one, for example the results of calling `where` on this iterable +/// are also cached. +Iterable collectAllSemanticsNodesFrom( + SemanticsNode root, { + DebugSemanticsDumpOrder order = DebugSemanticsDumpOrder.traversalOrder, + }) { + return CachingIterable(_DepthFirstSemanticsTreeIterator(root, order)); +} + +/// Provides a recursive, efficient, depth first search of a tree. +/// +/// This iterator executes a depth first search as an iterable, and iterates in +/// a left to right order: +/// +/// 1 +/// / \ +/// 2 3 +/// / \ / \ +/// 4 5 6 7 +/// +/// Will iterate in order 2, 4, 5, 3, 6, 7. The given root element is not +/// included in the traversal. +abstract class _DepthFirstTreeIterator implements Iterator { + _DepthFirstTreeIterator(ItemType root) { + _fillStack(_collectChildren(root)); + } + + @override + ItemType get current => _current!; + late ItemType _current; + + final List _stack = []; + + @override + bool moveNext() { + if (_stack.isEmpty) { + return false; + } + + _current = _stack.removeLast(); + _fillStack(_collectChildren(_current)); + return true; + } + + /// Fills the stack in such a way that the next element of a depth first + /// traversal is easily and efficiently accessible when calling `moveNext`. + void _fillStack(List children) { + // We reverse the list of children so we don't have to do use expensive + // `insert` or `remove` operations, and so the order of the traversal + // is depth first when built lazily through the iterator. + // + // This is faster than `_stack.addAll(children.reversed)`, presumably since + // we don't actually care about maintaining an iteration pointer. + while (children.isNotEmpty) { + _stack.add(children.removeLast()); + } + } + + /// Collect the children from [root] in the order they are expected to traverse. + List _collectChildren(ItemType root); +} + +/// [Element.visitChildren] does not guarantee order, but does guarantee stable +/// order. This iterator also guarantees stable order, and iterates in a left +/// to right order: +/// +/// 1 +/// / \ +/// 2 3 +/// / \ / \ +/// 4 5 6 7 +/// +/// Will iterate in order 2, 4, 5, 3, 6, 7. +/// +/// Performance is important here because this class is on the critical path +/// for flutter_driver and package:integration_test performance tests. +/// Performance is measured in the all_elements_bench microbenchmark. +/// Any changes to this implementation should check the before and after numbers +/// on that benchmark to avoid regressions in general performance test overhead. +/// +/// If we could use RTL order, we could save on performance, but numerous tests +/// have been written (and developers clearly expect) that LTR order will be +/// respected. +class _DepthFirstElementTreeIterator extends _DepthFirstTreeIterator { + _DepthFirstElementTreeIterator(super.root, this.includeOffstage); + + final bool includeOffstage; + + @override + List _collectChildren(Element root) { + final List children = []; + if (includeOffstage) { + root.visitChildren(children.add); + } else { + root.debugVisitOnstageChildren(children.add); + } + + return children; + } +} + +/// Iterates the semantics tree starting at the given `root`. +/// +/// This will iterate in the same order expected from accessibility services, +/// so the results can be used to simulate the same traversal the engine will +/// make. The results are not filtered based on flags or visibility, so they +/// will need to be further filtered to fully simulate an accessiblity service. +class _DepthFirstSemanticsTreeIterator extends _DepthFirstTreeIterator { + _DepthFirstSemanticsTreeIterator(super.root, this.order); + + final DebugSemanticsDumpOrder order; + + @override + List _collectChildren(SemanticsNode root) { + return root.debugListChildrenInOrder(order); + } +} diff --git a/packages/flutter_test/lib/src/widget_tester.dart b/packages/flutter_test/lib/src/widget_tester.dart index b4d65a1cb511a..2a8c36dcc7830 100644 --- a/packages/flutter_test/lib/src/widget_tester.dart +++ b/packages/flutter_test/lib/src/widget_tester.dart @@ -13,7 +13,6 @@ import 'package:matcher/expect.dart' as matcher_expect; import 'package:meta/meta.dart'; import 'package:test_api/scaffolding.dart' as test_package; -import 'all_elements.dart'; import 'binding.dart'; import 'controller.dart'; import 'finders.dart'; @@ -23,6 +22,7 @@ import 'test_async_utils.dart'; import 'test_compat.dart'; import 'test_pointer.dart'; import 'test_text_input.dart'; +import 'tree_traversal.dart'; // Keep users from needing multiple imports to test semantics. export 'package:flutter/rendering.dart' show SemanticsHandle; @@ -1089,12 +1089,16 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker /// /// Tests that just need to add text to widgets like [TextField] /// or [TextFormField] only need to call [enterText]. - Future showKeyboard(Finder finder) async { + Future showKeyboard(FinderBase finder) async { + bool skipOffstage = true; + if (finder is Finder) { + skipOffstage = finder.skipOffstage; + } return TestAsyncUtils.guard(() async { final EditableTextState editable = state( find.descendant( of: finder, - matching: find.byType(EditableText, skipOffstage: finder.skipOffstage), + matching: find.byType(EditableText, skipOffstage: skipOffstage), matchRoot: true, ), ); @@ -1124,7 +1128,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker /// that widget has an open connection (e.g. by using [tap] to focus it), /// then call `testTextInput.enterText` directly (see /// [TestTextInput.enterText]). - Future enterText(Finder finder, String text) async { + Future enterText(FinderBase finder, String text) async { return TestAsyncUtils.guard(() async { await showKeyboard(finder); testTextInput.enterText(text); diff --git a/packages/flutter_test/test/finders_test.dart b/packages/flutter_test/test/finders_test.dart index 09a482bc29e3e..68ac80a0184e2 100644 --- a/packages/flutter_test/test/finders_test.dart +++ b/packages/flutter_test/test/finders_test.dart @@ -8,6 +8,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +const List fooBarTexts = [ + Text('foo', textDirection: TextDirection.ltr), + Text('bar', textDirection: TextDirection.ltr), +]; + void main() { group('image', () { testWidgets('finds Image widgets', (WidgetTester tester) async { @@ -390,6 +395,764 @@ void main() { find.byWidgetPredicate((_) => true).evaluate().length; expect(find.bySubtype(), findsNWidgets(totalWidgetCount)); }); + + group('find.byElementPredicate', () { + testWidgets('fails with a custom description in the message', (WidgetTester tester) async { + await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); + + const String customDescription = 'custom description'; + late TestFailure failure; + try { + expect(find.byElementPredicate((_) => false, description: customDescription), findsOneWidget); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure, isNotNull); + expect(failure.message, contains('Actual: _ElementPredicateWidgetFinder: false, description: customDescription), findsOneWidget); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure, isNotNull); + expect(failure.message, contains('Actual: _WidgetPredicateWidgetFinder:[ + Column(children: fooBarTexts), + ], + )); + + expect(find.descendant( + of: find.widgetWithText(Row, 'foo'), + matching: find.text('bar'), + ), findsOneWidget); + }); + + testWidgets('finds two descendants with different ancestors', (WidgetTester tester) async { + await tester.pumpWidget(const Row( + textDirection: TextDirection.ltr, + children: [ + Column(children: fooBarTexts), + Column(children: fooBarTexts), + ], + )); + + expect(find.descendant( + of: find.widgetWithText(Column, 'foo'), + matching: find.text('bar'), + ), findsNWidgets(2)); + }); + + testWidgets('fails with a descriptive message', (WidgetTester tester) async { + await tester.pumpWidget(const Row( + textDirection: TextDirection.ltr, + children: [ + Column(children: [Text('foo', textDirection: TextDirection.ltr)]), + Text('bar', textDirection: TextDirection.ltr), + ], + )); + + late TestFailure failure; + try { + expect(find.descendant( + of: find.widgetWithText(Column, 'foo'), + matching: find.text('bar'), + ), findsOneWidget); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure, isNotNull); + expect( + failure.message, + contains( + 'Actual: _DescendantWidgetFinder:[ + Column(children: fooBarTexts), + ], + )); + + expect(find.ancestor( + of: find.text('bar'), + matching: find.widgetWithText(Row, 'foo'), + ), findsOneWidget); + }); + + testWidgets('finds two matching ancestors, one descendant', (WidgetTester tester) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Row( + children: [ + Row(children: fooBarTexts), + ], + ), + ), + ); + + expect(find.ancestor( + of: find.text('bar'), + matching: find.byType(Row), + ), findsNWidgets(2)); + }); + + testWidgets('fails with a descriptive message', (WidgetTester tester) async { + await tester.pumpWidget(const Row( + textDirection: TextDirection.ltr, + children: [ + Column(children: [Text('foo', textDirection: TextDirection.ltr)]), + Text('bar', textDirection: TextDirection.ltr), + ], + )); + + late TestFailure failure; + try { + expect(find.ancestor( + of: find.text('bar'), + matching: find.widgetWithText(Column, 'foo'), + ), findsOneWidget); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure, isNotNull); + expect( + failure.message, + contains( + 'Actual: _AncestorWidgetFinder:[ + Column(children: fooBarTexts), + ], + )); + + expect(find.ancestor( + of: find.byType(Column), + matching: find.widgetWithText(Column, 'foo'), + ), findsNothing); + }); + + testWidgets('Match the root', (WidgetTester tester) async { + await tester.pumpWidget(const Row( + textDirection: TextDirection.ltr, + children: [ + Column(children: fooBarTexts), + ], + )); + + expect(find.descendant( + of: find.byType(Column), + matching: find.widgetWithText(Column, 'foo'), + matchRoot: true, + ), findsOneWidget); + }); + + testWidgets('is fast in deep tree', (WidgetTester tester) async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: _deepWidgetTree( + depth: 1000, + child: Row( + children: [ + _deepWidgetTree( + depth: 1000, + child: const Column(children: fooBarTexts), + ), + ], + ), + ), + ), + ); + + expect(find.ancestor( + of: find.text('bar'), + matching: find.byType(Row), + ), findsOneWidget); + }); + }); + + group('CommonSemanticsFinders', () { + final Widget semanticsTree = _boilerplate( + Semantics( + container: true, + header: true, + readOnly: true, + onCopy: () {}, + onLongPress: () {}, + value: 'value1', + hint: 'hint1', + label: 'label1', + child: Semantics( + container: true, + textField: true, + onSetText: (_) { }, + onPaste: () { }, + onLongPress: () { }, + value: 'value2', + hint: 'hint2', + label: 'label2', + child: Semantics( + container: true, + readOnly: true, + onCopy: () {}, + value: 'value3', + hint: 'hint3', + label: 'label3', + child: Semantics( + container: true, + readOnly: true, + onLongPress: () { }, + value: 'value4', + hint: 'hint4', + label: 'label4', + child: Semantics( + container: true, + onLongPress: () { }, + onCopy: () {}, + value: 'value5', + hint: 'hint5', + label: 'label5' + ), + ), + ) + ), + ), + ); + + group('ancestor', () { + testWidgets('finds matching ancestor nodes', (WidgetTester tester) async { + await tester.pumpWidget(semanticsTree); + + final FinderBase finder = find.semantics.ancestor( + of: find.semantics.byLabel('label4'), + matching: find.semantics.byAction(SemanticsAction.copy), + ); + + expect(finder, findsExactly(2)); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final FinderBase finder = find.semantics.ancestor( + of: find.semantics.byLabel('label4'), + matching: find.semantics.byAction(SemanticsAction.copy), + ); + + try { + expect(finder, findsExactly(3)); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _AncestorSemanticsFinder: finder = find.semantics.descendant( + of: find.semantics.byLabel('label4'), + matching: find.semantics.byAction(SemanticsAction.copy), + ); + + expect(finder, findsOne); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final FinderBase finder = find.semantics.descendant( + of: find.semantics.byLabel('label4'), + matching: find.semantics.byAction(SemanticsAction.copy), + ); + + try { + expect(finder, findsNothing); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _DescendantSemanticsFinder: 1; + }, + ); + + expect(finder, findsExactly(4)); + }); + + testWidgets('fails with default message', (WidgetTester tester) async { + late TestFailure failure; + final RegExp replaceRegExp = RegExp(r'^[^\d]+'); + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byPredicate( + (SemanticsNode node) { + final int labelNum = int.tryParse(node.label.replaceAll(replaceRegExp, '')) ?? -1; + return labelNum > 1; + }, + ); + try { + expect(finder, findsExactly(5)); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _PredicateSemanticsFinder: 1; + }, + describeMatch: (_) => expected, + ); + try { + expect(finder, findsExactly(5)); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains(expected)); + }); + }); + + group('byLabel', () { + testWidgets('finds nodes with matching label using String', (WidgetTester tester) async { + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byLabel('label3'); + + expect(finder, findsOne); + expect(finder.found.first.label, 'label3'); + }); + + testWidgets('finds nodes with matching label using RegEx', (WidgetTester tester) async { + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byLabel(RegExp('^label.*')); + + expect(finder, findsExactly(5)); + expect(finder.found.every((SemanticsNode node) => node.label.startsWith('label')), isTrue); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byLabel('label3'); + + try { + expect(finder, findsNothing); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _PredicateSemanticsFinder: node.value.startsWith('value')), isTrue); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byValue('value3'); + + try { + expect(finder, findsNothing); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _PredicateSemanticsFinder: node.hint.startsWith('hint')), isTrue); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byHint('hint3'); + + try { + expect(finder, findsNothing); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _PredicateSemanticsFinder:[ + SemanticsAction.paste, + SemanticsAction.longPress, + ]); + + expect(finder, findsExactly(4)); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byAnyAction([ + SemanticsAction.paste, + SemanticsAction.longPress, + ]); + + try { + expect(finder, findsExactly(5)); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _PredicateSemanticsFinder:[ + SemanticsFlag.isHeader, + SemanticsFlag.isTextField, + ]); + + expect(finder, findsExactly(2)); + }); + + testWidgets('fails with descriptive message', (WidgetTester tester) async { + late TestFailure failure; + await tester.pumpWidget(semanticsTree); + + final SemanticsFinder finder = find.semantics.byAnyFlag([ + SemanticsFlag.isHeader, + SemanticsFlag.isTextField, + ]); + + try { + expect(finder, findsExactly(3)); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure.message, contains('Actual: _PredicateSemanticsFinder: Plurality.zero, + 1 => Plurality.one, + _ => Plurality.many, + }; + late final Plurality actual; + final _FakeFinder finder = _FakeFinder( + describeMatchCallback: (Plurality plurality) { + actual = plurality; + return 'Fake description'; + }, + findInCandidatesCallback: (_) => Iterable.generate(i, (int index) => index.toString()), + ); + finder.evaluate().toString(); + + expect(actual, expected); + }); + + test('gets expected plurality for $i when reporting results from toString', () { + final Plurality expected = switch (i) { + 0 => Plurality.zero, + 1 => Plurality.one, + _ => Plurality.many, + }; + late final Plurality actual; + final _FakeFinder finder = _FakeFinder( + describeMatchCallback: (Plurality plurality) { + actual = plurality; + return 'Fake description'; + }, + findInCandidatesCallback: (_) => Iterable.generate(i, (int index) => index.toString()), + ); + finder.toString(); + + expect(actual, expected); + }); + + test('always gets many when describing finder', () { + const Plurality expected = Plurality.many; + late final Plurality actual; + final _FakeFinder finder = _FakeFinder( + describeMatchCallback: (Plurality plurality) { + actual = plurality; + return 'Fake description'; + }, + findInCandidatesCallback: (_) => Iterable.generate(i, (int index) => index.toString()), + ); + finder.toString(describeSelf: true); + + expect(actual, expected); + }); + } + }); + + test('findInCandidates gets allCandidates', () { + final List expected = ['Test1', 'Test2', 'Test3', 'Test4']; + late final List actual; + final _FakeFinder finder = _FakeFinder( + allCandidatesCallback: () => expected, + findInCandidatesCallback: (Iterable candidates) { + actual = candidates.toList(); + return candidates; + }, + ); + finder.evaluate(); + + expect(actual, expected); + }); + + test('allCandidates calculated for each find', () { + const int expectedCallCount = 3; + int actualCallCount = 0; + final _FakeFinder finder = _FakeFinder( + allCandidatesCallback: () { + actualCallCount++; + return ['test']; + }, + ); + for (int i = 0; i < expectedCallCount; i++) { + finder.evaluate(); + } + + expect(actualCallCount, expectedCallCount); + }); + + test('allCandidates only called once while caching', () { + int actualCallCount = 0; + final _FakeFinder finder = _FakeFinder( + allCandidatesCallback: () { + actualCallCount++; + return ['test']; + }, + ); + finder.runCached(() { + for (int i = 0; i < 5; i++) { + finder.evaluate(); + finder.tryEvaluate(); + final FinderResult _ = finder.found; + } + }); + + expect(actualCallCount, 1); + }); + + group('tryFind', () { + test('returns false if no results', () { + final _FakeFinder finder = _FakeFinder( + findInCandidatesCallback: (_) => [], + ); + + expect(finder.tryEvaluate(), false); + }); + + test('returns true if results are available', () { + final _FakeFinder finder = _FakeFinder( + findInCandidatesCallback: (_) => ['Results'], + ); + + expect(finder.tryEvaluate(), true); + }); + }); + + group('found', () { + test('throws before any calls to evaluate or tryEvaluate', () { + final _FakeFinder finder = _FakeFinder(); + + expect(finder.hasFound, false); + expect(() => finder.found, throwsAssertionError); + }); + + test('has same results as evaluate after call to evaluate', () { + final _FakeFinder finder = _FakeFinder(); + final FinderResult expected = finder.evaluate(); + + expect(finder.hasFound, true); + expect(finder.found, expected); + }); + + test('has expected results after call to tryFind', () { + final Iterable expected = Iterable.generate(10, (int i) => i.toString()); + final _FakeFinder finder = _FakeFinder(findInCandidatesCallback: (_) => expected); + finder.tryEvaluate(); + + + expect(finder.hasFound, true); + expect(finder.found, orderedEquals(expected)); + }); + }); + }); } Widget _boilerplate(Widget child) { @@ -442,3 +1205,45 @@ class SimpleGenericWidget extends StatelessWidget { return _child; } } + +/// Wraps [child] in [depth] layers of [SizedBox] +Widget _deepWidgetTree({required int depth, required Widget child}) { + Widget tree = child; + for (int i = 0; i < depth; i += 1) { + tree = SizedBox(child: tree); + } + return tree; +} + +class _FakeFinder extends FinderBase { + _FakeFinder({ + this.allCandidatesCallback, + this.describeMatchCallback, + this.findInCandidatesCallback, + }); + + final Iterable Function()? allCandidatesCallback; + final DescribeMatchCallback? describeMatchCallback; + final Iterable Function(Iterable candidates)? findInCandidatesCallback; + + + @override + Iterable get allCandidates { + return allCandidatesCallback?.call() ?? [ + 'String 1', 'String 2', 'String 3', + ]; + } + + @override + String describeMatch(Plurality plurality) { + return describeMatchCallback?.call(plurality) ?? switch (plurality) { + Plurality.one => 'String', + Plurality.many || Plurality.zero => 'Strings', + }; + } + + @override + Iterable findInCandidates(Iterable candidates) { + return findInCandidatesCallback?.call(candidates) ?? candidates; + } +} diff --git a/packages/flutter_test/test/matchers_test.dart b/packages/flutter_test/test/matchers_test.dart index 87d5fffa40ab7..7a5aa13fa5f94 100644 --- a/packages/flutter_test/test/matchers_test.dart +++ b/packages/flutter_test/test/matchers_test.dart @@ -1330,6 +1330,72 @@ void main() { expect(find.byType(Text), isNot(findsAtLeastNWidgets(3))); }); }); + + group('findsOneWidget', () { + testWidgets('finds exactly one widget', (WidgetTester tester) async { + await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); + expect(find.text('foo'), findsOneWidget); + }); + + testWidgets('fails with a descriptive message', (WidgetTester tester) async { + late TestFailure failure; + try { + expect(find.text('foo', skipOffstage: false), findsOneWidget); + } on TestFailure catch (e) { + failure = e; + } + + expect(failure, isNotNull); + final String? message = failure.message; + expect(message, contains('Expected: exactly one matching candidate\n')); + expect(message, contains('Actual: _TextWidgetFinder: fooBarTexts = [ - Text('foo', textDirection: TextDirection.ltr), - Text('bar', textDirection: TextDirection.ltr), -]; - void main() { group('expectLater', () { testWidgets('completes when matcher completes', (WidgetTester tester) async { @@ -75,70 +70,6 @@ void main() { }); }, skip: true); // [intended] API testing - group('findsOneWidget', () { - testWidgets('finds exactly one widget', (WidgetTester tester) async { - await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); - expect(find.text('foo'), findsOneWidget); - }); - - testWidgets('fails with a descriptive message', (WidgetTester tester) async { - late TestFailure failure; - try { - expect(find.text('foo', skipOffstage: false), findsOneWidget); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - final String? message = failure.message; - expect(message, contains('Expected: exactly one matching node in the widget tree\n')); - expect(message, contains('Actual: _TextFinder:\n')); - expect(message, contains('Which: means none were found but one was expected\n')); - }); - }); - - group('findsNothing', () { - testWidgets('finds no widgets', (WidgetTester tester) async { - expect(find.text('foo'), findsNothing); - }); - - testWidgets('fails with a descriptive message', (WidgetTester tester) async { - await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); - - late TestFailure failure; - try { - expect(find.text('foo', skipOffstage: false), findsNothing); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - final String? message = failure.message; - - expect(message, contains('Expected: no matching nodes in the widget tree\n')); - expect(message, contains('Actual: _TextFinder:\n')); - expect(message, contains('Which: means one was found but none were expected\n')); - }); - - testWidgets('fails with a descriptive message when skipping', (WidgetTester tester) async { - await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); - - late TestFailure failure; - try { - expect(find.text('foo'), findsNothing); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - final String? message = failure.message; - - expect(message, contains('Expected: no matching nodes in the widget tree\n')); - expect(message, contains('Actual: _TextFinder:\n')); - expect(message, contains('Which: means one was found but none were expected\n')); - }); - }); - group('pumping', () { testWidgets('pumping', (WidgetTester tester) async { await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); @@ -196,215 +127,6 @@ void main() { expect(logPaints, [60000, 70000, 80000]); }); }); - - group('find.byElementPredicate', () { - testWidgets('fails with a custom description in the message', (WidgetTester tester) async { - await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr)); - - const String customDescription = 'custom description'; - late TestFailure failure; - try { - expect(find.byElementPredicate((_) => false, description: customDescription), findsOneWidget); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - expect(failure.message, contains('Actual: _ElementPredicateFinder: false, description: customDescription), findsOneWidget); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - expect(failure.message, contains('Actual: _WidgetPredicateFinder:[ - Column(children: fooBarTexts), - ], - )); - - expect(find.descendant( - of: find.widgetWithText(Row, 'foo'), - matching: find.text('bar'), - ), findsOneWidget); - }); - - testWidgets('finds two descendants with different ancestors', (WidgetTester tester) async { - await tester.pumpWidget(const Row( - textDirection: TextDirection.ltr, - children: [ - Column(children: fooBarTexts), - Column(children: fooBarTexts), - ], - )); - - expect(find.descendant( - of: find.widgetWithText(Column, 'foo'), - matching: find.text('bar'), - ), findsNWidgets(2)); - }); - - testWidgets('fails with a descriptive message', (WidgetTester tester) async { - await tester.pumpWidget(const Row( - textDirection: TextDirection.ltr, - children: [ - Column(children: [Text('foo', textDirection: TextDirection.ltr)]), - Text('bar', textDirection: TextDirection.ltr), - ], - )); - - late TestFailure failure; - try { - expect(find.descendant( - of: find.widgetWithText(Column, 'foo'), - matching: find.text('bar'), - ), findsOneWidget); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - expect( - failure.message, - contains( - 'Actual: _DescendantFinder:[ - Column(children: fooBarTexts), - ], - )); - - expect(find.ancestor( - of: find.text('bar'), - matching: find.widgetWithText(Row, 'foo'), - ), findsOneWidget); - }); - - testWidgets('finds two matching ancestors, one descendant', (WidgetTester tester) async { - await tester.pumpWidget( - const Directionality( - textDirection: TextDirection.ltr, - child: Row( - children: [ - Row(children: fooBarTexts), - ], - ), - ), - ); - - expect(find.ancestor( - of: find.text('bar'), - matching: find.byType(Row), - ), findsNWidgets(2)); - }); - - testWidgets('fails with a descriptive message', (WidgetTester tester) async { - await tester.pumpWidget(const Row( - textDirection: TextDirection.ltr, - children: [ - Column(children: [Text('foo', textDirection: TextDirection.ltr)]), - Text('bar', textDirection: TextDirection.ltr), - ], - )); - - late TestFailure failure; - try { - expect(find.ancestor( - of: find.text('bar'), - matching: find.widgetWithText(Column, 'foo'), - ), findsOneWidget); - } on TestFailure catch (e) { - failure = e; - } - - expect(failure, isNotNull); - expect( - failure.message, - contains( - 'Actual: _AncestorFinder:[ - Column(children: fooBarTexts), - ], - )); - - expect(find.ancestor( - of: find.byType(Column), - matching: find.widgetWithText(Column, 'foo'), - ), findsNothing); - }); - - testWidgets('Match the root', (WidgetTester tester) async { - await tester.pumpWidget(const Row( - textDirection: TextDirection.ltr, - children: [ - Column(children: fooBarTexts), - ], - )); - - expect(find.descendant( - of: find.byType(Column), - matching: find.widgetWithText(Column, 'foo'), - matchRoot: true, - ), findsOneWidget); - }); - - testWidgets('is fast in deep tree', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: _deepWidgetTree( - depth: 1000, - child: Row( - children: [ - _deepWidgetTree( - depth: 1000, - child: const Column(children: fooBarTexts), - ), - ], - ), - ), - ), - ); - - expect(find.ancestor( - of: find.text('bar'), - matching: find.byType(Row), - ), findsOneWidget); - }); - }); - group('pageBack', () { testWidgets('fails when there are no back buttons', (WidgetTester tester) async { await tester.pumpWidget(Container()); @@ -985,12 +707,3 @@ class _AlwaysRepaint extends CustomPainter { onPaint(); } } - -/// Wraps [child] in [depth] layers of [SizedBox] -Widget _deepWidgetTree({required int depth, required Widget child}) { - Widget tree = child; - for (int i = 0; i < depth; i += 1) { - tree = SizedBox(child: tree); - } - return tree; -} From 6cf5dbe37151515a8b6f4bccd0b69ab10f5a5aa7 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Thu, 10 Aug 2023 14:34:49 -0700 Subject: [PATCH 0654/1547] Analyze code snippets in integration_test docs (#132314) --- dev/bots/analyze_snippet_code.dart | 2 ++ packages/integration_test/lib/integration_test.dart | 4 ++-- .../lib/integration_test_driver_extended.dart | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index d29d6d251e558..e6de1e4cf592d 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -72,6 +72,7 @@ import 'package:watcher/watcher.dart'; final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String _packageFlutter = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); final String _packageFlutterTest = path.join(_flutterRoot, 'packages', 'flutter_test', 'lib'); +final String _packageIntegrationTest = path.join(_flutterRoot, 'packages', 'integration_test', 'lib'); final String _defaultDartUiLocation = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui'); final String _flutter = path.join(_flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); @@ -151,6 +152,7 @@ Future main(List arguments) async { flutterPackages = [ Directory(_packageFlutter), Directory(_packageFlutterTest), + Directory(_packageIntegrationTest), // TODO(goderbauer): Add all other packages. ]; } diff --git a/packages/integration_test/lib/integration_test.dart b/packages/integration_test/lib/integration_test.dart index 14542e6637e09..811f1c244e3d0 100644 --- a/packages/integration_test/lib/integration_test.dart +++ b/packages/integration_test/lib/integration_test.dart @@ -326,9 +326,9 @@ https://flutter.dev/docs/testing/integration-tests#testing-on-firebase-test-lab /// /// Future main() { /// return integrationDriver( - /// responseDataCallback: (data) async { + /// responseDataCallback: (Map? data) async { /// if (data != null) { - /// for (var entry in data.entries) { + /// for (final MapEntry entry in data.entries) { /// print('Writing ${entry.key} to the disk.'); /// await writeResponseData( /// entry.value as Map, diff --git a/packages/integration_test/lib/integration_test_driver_extended.dart b/packages/integration_test/lib/integration_test_driver_extended.dart index d449d7df98936..d4226f4ecb261 100644 --- a/packages/integration_test/lib/integration_test_driver_extended.dart +++ b/packages/integration_test/lib/integration_test_driver_extended.dart @@ -20,13 +20,14 @@ import 'common.dart'; /// ```dart /// import 'dart:async'; /// +/// import 'package:flutter_driver/flutter_driver.dart'; /// import 'package:integration_test/integration_test_driver_extended.dart'; /// /// Future main() async { /// final FlutterDriver driver = await FlutterDriver.connect(); /// await integrationDriver( /// driver: driver, -/// onScreenshot: (String screenshotName, List screenshotBytes) async { +/// onScreenshot: (String name, List image, [Map? args]) async { /// return true; /// }, /// ); From a2e2574941982e3de3eb746f0a00ca90f6d28f04 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 10 Aug 2023 14:48:06 -0700 Subject: [PATCH 0655/1547] Remove the fast reassemble / single widget reload feature (#132255) Fixes https://github.com/flutter/flutter/issues/132157 --- .../flutter/lib/src/foundation/binding.dart | 27 ---- .../flutter/lib/src/rendering/binding.dart | 20 ++- packages/flutter/lib/src/widgets/binding.dart | 21 +-- .../flutter/lib/src/widgets/framework.dart | 21 +-- .../lib/src/widgets/widget_inspector.dart | 2 +- .../foundation/service_extensions_test.dart | 73 +++++++++- .../test/widgets/fast_reassemble_test.dart | 123 ----------------- .../widgets/widget_inspector_test_utils.dart | 2 +- packages/flutter_tools/lib/src/bundle.dart | 2 +- packages/flutter_tools/lib/src/devfs.dart | 22 --- packages/flutter_tools/lib/src/features.dart | 18 --- .../lib/src/flutter_features.dart | 3 - .../lib/src/isolated/resident_web_runner.dart | 1 - .../lib/src/reporting/custom_dimensions.dart | 24 ++-- .../lib/src/reporting/events.dart | 3 - .../lib/src/resident_runner.dart | 4 - packages/flutter_tools/lib/src/run_hot.dart | 25 +--- packages/flutter_tools/lib/src/vmservice.dart | 13 -- .../general.shard/bundle_builder_test.dart | 10 +- .../test/general.shard/hot_test.dart | 4 - .../general.shard/resident_runner_test.dart | 128 +----------------- .../single_widget_reload_test.dart | 63 --------- .../single_widget_reload_project.dart | 94 ------------- .../test/integration.shard/test_driver.dart | 11 -- packages/flutter_tools/test/src/fakes.dart | 6 - 25 files changed, 105 insertions(+), 615 deletions(-) delete mode 100644 packages/flutter/test/widgets/fast_reassemble_test.dart delete mode 100644 packages/flutter_tools/test/integration.shard/single_widget_reload_test.dart delete mode 100644 packages/flutter_tools/test/integration.shard/test_data/single_widget_reload_project.dart diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index 83204bd57b227..e898b808e5f1a 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -168,13 +168,6 @@ abstract class BindingBase { static Type? _debugInitializedType; static bool _debugServiceExtensionsRegistered = false; - /// Additional configuration used by the framework during hot reload. - /// - /// See also: - /// - /// * [DebugReassembleConfig], which describes the configuration. - static DebugReassembleConfig? debugReassembleConfig; - /// Deprecated. Will be removed in a future version of Flutter. /// /// This property has been deprecated to prepare for Flutter's upcoming @@ -989,23 +982,3 @@ abstract class BindingBase { Future _exitApplication() async { exit(0); } - -/// Additional configuration used for hot reload reassemble optimizations. -/// -/// Do not extend, implement, or mixin this class. This may only be instantiated -/// in debug mode. -class DebugReassembleConfig { - /// Create a new [DebugReassembleConfig]. - /// - /// Throws a [FlutterError] if this is called in profile or release mode. - DebugReassembleConfig({ - this.widgetName, - }) { - if (!kDebugMode) { - throw FlutterError('Cannot instantiate DebugReassembleConfig in profile or release mode.'); - } - } - - /// The name of the widget that was modified, or `null` if the change was elsewhere. - final String? widgetName; -} diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 8b14588b78db1..5d1552ec3cb54 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -603,18 +603,16 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture @override Future performReassemble() async { await super.performReassemble(); - if (BindingBase.debugReassembleConfig?.widgetName == null) { - if (!kReleaseMode) { - FlutterTimeline.startSync('Preparing Hot Reload (layout)'); + if (!kReleaseMode) { + FlutterTimeline.startSync('Preparing Hot Reload (layout)'); + } + try { + for (final RenderView renderView in renderViews) { + renderView.reassemble(); } - try { - for (final RenderView renderView in renderViews) { - renderView.reassemble(); - } - } finally { - if (!kReleaseMode) { - FlutterTimeline.finishSync(); - } + } finally { + if (!kReleaseMode) { + FlutterTimeline.finishSync(); } } scheduleWarmUpFrame(); diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index 900d34fe77232..ca8347edbe485 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -505,23 +505,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB }, ); - registerServiceExtension( - name: WidgetsServiceExtensions.fastReassemble.name, - callback: (Map params) async { - // This mirrors the implementation of the 'reassemble' callback registration - // in lib/src/foundation/binding.dart, but with the extra binding config used - // to skip some reassemble work. - final String? className = params['className'] as String?; - BindingBase.debugReassembleConfig = DebugReassembleConfig(widgetName: className); - try { - await reassembleApplication(); - } finally { - BindingBase.debugReassembleConfig = null; - } - return {'type': 'Success'}; - }, - ); - // Expose the ability to send Widget rebuilds as [Timeline] events. registerBoolServiceExtension( name: WidgetsServiceExtensions.profileWidgetBuilds.name, @@ -560,7 +543,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB Future _forceRebuild() { if (rootElement != null) { - buildOwner!.reassemble(rootElement!, null); + buildOwner!.reassemble(rootElement!); return endOfFrame; } return Future.value(); @@ -1090,7 +1073,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB }()); if (rootElement != null) { - buildOwner!.reassemble(rootElement!, BindingBase.debugReassembleConfig); + buildOwner!.reassemble(rootElement!); } return super.performReassemble(); } diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 6c5c231a34830..c1c45fcbfa097 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -3252,14 +3252,13 @@ class BuildOwner { /// changed implementations. /// /// This is expensive and should not be called except during development. - void reassemble(Element root, DebugReassembleConfig? reassembleConfig) { + void reassemble(Element root) { if (!kReleaseMode) { FlutterTimeline.startSync('Preparing Hot Reload (widgets)'); } try { assert(root._parent == null); assert(root.owner == this); - root._debugReassembleConfig = reassembleConfig; root.reassemble(); } finally { if (!kReleaseMode) { @@ -3374,7 +3373,6 @@ abstract class Element extends DiagnosticableTree implements BuildContext { } Element? _parent; - DebugReassembleConfig? _debugReassembleConfig; _NotificationNode? _notificationTree; /// Compare two widgets for equality. @@ -3526,15 +3524,10 @@ abstract class Element extends DiagnosticableTree implements BuildContext { @mustCallSuper @protected void reassemble() { - if (_debugShouldReassemble(_debugReassembleConfig, _widget)) { - markNeedsBuild(); - _debugReassembleConfig = null; - } + markNeedsBuild(); visitChildren((Element child) { - child._debugReassembleConfig = _debugReassembleConfig; child.reassemble(); }); - _debugReassembleConfig = null; } bool _debugIsInScope(Element target) { @@ -5585,9 +5578,7 @@ class StatefulElement extends ComponentElement { @override void reassemble() { - if (_debugShouldReassemble(_debugReassembleConfig, _widget)) { - state.reassemble(); - } + state.reassemble(); super.reassemble(); } @@ -6952,9 +6943,3 @@ class _NullWidget extends Widget { @override Element createElement() => throw UnimplementedError(); } - -// Whether a [DebugReassembleConfig] indicates that an element holding [widget] can skip -// a reassemble. -bool _debugShouldReassemble(DebugReassembleConfig? config, Widget? widget) { - return config == null || config.widgetName == null || widget?.runtimeType.toString() == config.widgetName; -} diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 7c56bed8ec91f..5873aaab7eda3 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -970,7 +970,7 @@ mixin WidgetInspectorService { Future forceRebuild() { final WidgetsBinding binding = WidgetsBinding.instance; if (binding.rootElement != null) { - binding.buildOwner!.reassemble(binding.rootElement!, null); + binding.buildOwner!.reassemble(binding.rootElement!); return binding.endOfFrame; } return Future.value(); diff --git a/packages/flutter/test/foundation/service_extensions_test.dart b/packages/flutter/test/foundation/service_extensions_test.dart index b97a70a74a6a5..7b6d36a8358dc 100644 --- a/packages/flutter/test/foundation/service_extensions_test.dart +++ b/packages/flutter/test/foundation/service_extensions_test.dart @@ -116,6 +116,7 @@ Future> hasReassemble(Future> pendingR } void main() { + final Set testedExtensions = {}; // Add the name of an extension to this set in the test where it is tested. final List console = []; late PipelineOwner owner; @@ -153,6 +154,9 @@ void main() { expect(binding.frameScheduled, isFalse); + testedExtensions.add(WidgetsServiceExtensions.didSendFirstFrameEvent.name); + testedExtensions.add(WidgetsServiceExtensions.didSendFirstFrameRasterizedEvent.name); + expect(debugPrint, equals(debugPrintThrottled)); debugPrint = (String? message, { int? wrapWidth }) { console.add(message); @@ -162,12 +166,13 @@ void main() { tearDownAll(() async { // See widget_inspector_test.dart for tests of the ext.flutter.inspector // service extensions included in this count. - int widgetInspectorExtensionCount = 20; + int widgetInspectorExtensionCount = 28; if (WidgetInspectorService.instance.isWidgetCreationTracked()) { // Some inspector extensions are only exposed if widget creation locations // are tracked. widgetInspectorExtensionCount += 2; } + expect(binding.extensions.keys.where((String name) => name.startsWith('inspector.')), hasLength(widgetInspectorExtensionCount)); // The following service extensions are disabled in web: // 1. exit @@ -175,12 +180,13 @@ void main() { const int disabledExtensions = kIsWeb ? 2 : 0; // The expected number of registered service extensions in the Flutter - // framework, excluding any that are for the widget inspector - // (see widget_inspector_test.dart for tests of the ext.flutter.inspector - // service extensions). - const int serviceExtensionCount = 38; + // framework, excluding any that are for the widget inspector (see + // widget_inspector_test.dart for tests of the ext.flutter.inspector service + // extensions). Any test counted here must be tested in this file! + const int serviceExtensionCount = 29; expect(binding.extensions.length, serviceExtensionCount + widgetInspectorExtensionCount - disabledExtensions); + expect(testedExtensions, hasLength(serviceExtensionCount)); expect(console, isEmpty); debugPrint = debugPrintThrottled; @@ -213,6 +219,8 @@ void main() { expect(result, {'enabled': 'true'}); expect(WidgetsApp.debugAllowBannerOverride, true); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(WidgetsServiceExtensions.debugAllowBanner.name); }); test('Service extensions - debugDumpApp', () async { @@ -221,6 +229,8 @@ void main() { expect(result, { 'data': matches('TestServiceExtensionsBinding - DEBUG MODE\n'), }); + + testedExtensions.add(WidgetsServiceExtensions.debugDumpApp.name); }); test('Service extensions - debugDumpFocusTree', () async { @@ -234,6 +244,8 @@ void main() { r'$', ), }); + + testedExtensions.add(WidgetsServiceExtensions.debugDumpFocusTree.name); }); test('Service extensions - debugDumpRenderTree', () async { @@ -251,6 +263,8 @@ void main() { r'$', ), }); + + testedExtensions.add(RenderingServiceExtensions.debugDumpRenderTree.name); }); test('Service extensions - debugDumpLayerTree', () async { @@ -274,6 +288,8 @@ void main() { r'$', ), }); + + testedExtensions.add(RenderingServiceExtensions.debugDumpLayerTree.name); }); test('Service extensions - debugDumpSemanticsTreeInTraversalOrder', () async { @@ -288,6 +304,8 @@ void main() { r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.' ) }); + + testedExtensions.add(RenderingServiceExtensions.debugDumpSemanticsTreeInTraversalOrder.name); }); test('Service extensions - debugDumpSemanticsTreeInInverseHitTestOrder', () async { @@ -302,10 +320,12 @@ void main() { r'To generate semantics, try turning on an assistive technology \(like VoiceOver or TalkBack\) on your device.' ) }); + + testedExtensions.add(RenderingServiceExtensions.debugDumpSemanticsTreeInInverseHitTestOrder.name); }); test('Service extensions - debugPaint', () async { - final Iterable> extensionChangedEvents = binding.getServiceExtensionStateChangedEvents('ext.flutter.debugPaint'); + final Iterable> extensionChangedEvents = binding.getServiceExtensionStateChangedEvents('ext.flutter.${RenderingServiceExtensions.debugPaint.name}'); Map extensionChangedEvent; Map result; Future> pendingResult; @@ -357,6 +377,8 @@ void main() { expect(debugPaintSizeEnabled, false); expect(extensionChangedEvents.length, 2); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.debugPaint.name); }); test('Service extensions - debugPaintBaselinesEnabled', () async { @@ -399,6 +421,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(debugPaintBaselinesEnabled, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.debugPaintBaselinesEnabled.name); }); test('Service extensions - invertOversizedImages', () async { @@ -445,6 +469,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(debugInvertOversizedImages, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.invertOversizedImages.name); }); test('Service extensions - profileWidgetBuilds', () async { @@ -474,6 +500,8 @@ void main() { expect(debugProfileBuildsEnabled, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(WidgetsServiceExtensions.profileWidgetBuilds.name); }); test('Service extensions - profileUserWidgetBuilds', () async { @@ -503,6 +531,8 @@ void main() { expect(debugProfileBuildsEnabledUserWidgets, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(WidgetsServiceExtensions.profileUserWidgetBuilds.name); }); test('Service extensions - profileRenderObjectPaints', () async { @@ -532,6 +562,8 @@ void main() { expect(debugProfilePaintsEnabled, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.profileRenderObjectPaints.name); }); test('Service extensions - profileRenderObjectLayouts', () async { @@ -561,6 +593,8 @@ void main() { expect(debugProfileLayoutsEnabled, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.profileRenderObjectLayouts.name); }); test('Service extensions - evict', () async { @@ -596,12 +630,16 @@ void main() { expect(data, isFalse); expect(completed, isTrue); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', null); + + testedExtensions.add(ServicesServiceExtensions.evict.name); }); test('Service extensions - exit', () async { // no test for _calling_ 'exit', because that should terminate the process! // Not expecting extension to be available for web platform. expect(binding.extensions.containsKey(FoundationServiceExtensions.exit.name), !isBrowser); + + testedExtensions.add(FoundationServiceExtensions.exit.name); }); test('Service extensions - platformOverride', () async { @@ -688,6 +726,8 @@ void main() { expect(extensionChangedEvent['extension'], 'ext.flutter.platformOverride'); expect(extensionChangedEvent['value'], 'android'); binding.reassembled = 0; + + testedExtensions.add(FoundationServiceExtensions.platformOverride.name); }); test('Service extensions - repaintRainbow', () async { @@ -731,6 +771,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(debugRepaintRainbowEnabled, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.repaintRainbow.name); }); test('Service extensions - debugDisableClipLayers', () async { @@ -773,6 +815,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(debugDisableClipLayers, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.debugDisableClipLayers.name); }); test('Service extensions - debugDisablePhysicalShapeLayers', () async { @@ -815,6 +859,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(debugDisablePhysicalShapeLayers, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.debugDisablePhysicalShapeLayers.name); }); test('Service extensions - debugDisableOpacityLayers', () async { @@ -857,6 +903,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(debugDisableOpacityLayers, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(RenderingServiceExtensions.debugDisableOpacityLayers.name); }); test('Service extensions - reassemble', () async { @@ -880,6 +928,8 @@ void main() { expect(result, {}); expect(binding.reassembled, 1); binding.reassembled = 0; + + testedExtensions.add(FoundationServiceExtensions.reassemble.name); }); test('Service extensions - showPerformanceOverlay', () async { @@ -888,6 +938,7 @@ void main() { // The performance overlay service extension is disabled on the web. if (kIsWeb) { expect(binding.extensions.containsKey(WidgetsServiceExtensions.showPerformanceOverlay.name), isFalse); + testedExtensions.add(WidgetsServiceExtensions.showPerformanceOverlay.name); return; } @@ -909,6 +960,8 @@ void main() { expect(result, {'enabled': 'false'}); expect(WidgetsApp.showPerformanceOverlayOverride, false); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(WidgetsServiceExtensions.showPerformanceOverlay.name); }); test('Service extensions - timeDilation', () async { @@ -945,6 +998,8 @@ void main() { expect(timeDilation, 1.0); expect(extensionChangedEvents.length, 2); expect(binding.frameScheduled, isFalse); + + testedExtensions.add(SchedulerServiceExtensions.timeDilation.name); }); test('Service extensions - brightnessOverride', () async { @@ -953,6 +1008,8 @@ void main() { final String brightnessValue = result['value'] as String; expect(brightnessValue, 'Brightness.light'); + + testedExtensions.add(FoundationServiceExtensions.brightnessOverride.name); }); test('Service extensions - activeDevToolsServerAddress', () async { @@ -966,6 +1023,8 @@ void main() { result = await binding.testExtension(FoundationServiceExtensions.activeDevToolsServerAddress.name, {'value': 'http://127.0.0.1:9102'}); serverAddress = result['value'] as String; expect(serverAddress, 'http://127.0.0.1:9102'); + + testedExtensions.add(FoundationServiceExtensions.activeDevToolsServerAddress.name); }); test('Service extensions - connectedVmServiceUri', () async { @@ -979,5 +1038,7 @@ void main() { result = await binding.testExtension(FoundationServiceExtensions.connectedVmServiceUri.name, {'value': 'http://127.0.0.1:54000/kMUMseKAnog=/'}); serverAddress = result['value'] as String; expect(serverAddress, 'http://127.0.0.1:54000/kMUMseKAnog=/'); + + testedExtensions.add(FoundationServiceExtensions.connectedVmServiceUri.name); }); } diff --git a/packages/flutter/test/widgets/fast_reassemble_test.dart b/packages/flutter/test/widgets/fast_reassemble_test.dart deleted file mode 100644 index 1269992c113ce..0000000000000 --- a/packages/flutter/test/widgets/fast_reassemble_test.dart +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('reassemble with a className only marks subtrees from the first matching element as dirty', (WidgetTester tester) async { - await tester.pumpWidget( - const Foo(Bar(Fizz(SizedBox()))) - ); - - expect(Foo.count, 0); - expect(Bar.count, 0); - expect(Fizz.count, 0); - - DebugReassembleConfig config = DebugReassembleConfig(widgetName: 'Bar'); - WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config); - - expect(Foo.count, 0); - expect(Bar.count, 1); - expect(Fizz.count, 1); - - config = DebugReassembleConfig(widgetName: 'Fizz'); - WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config); - - expect(Foo.count, 0); - expect(Bar.count, 1); - expect(Fizz.count, 2); - - config = DebugReassembleConfig(widgetName: 'NoMatch'); - WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config); - - expect(Foo.count, 0); - expect(Bar.count, 1); - expect(Fizz.count, 2); - - config = DebugReassembleConfig(); - WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config); - - expect(Foo.count, 1); - expect(Bar.count, 2); - expect(Fizz.count, 3); - - WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, null); - - expect(Foo.count, 2); - expect(Bar.count, 3); - expect(Fizz.count, 4); - }); -} - -class Foo extends StatefulWidget { - const Foo(this.child, {super.key}); - - final Widget child; - static int count = 0; - - @override - State createState() => _FooState(); -} - -class _FooState extends State { - @override - void reassemble() { - Foo.count += 1; - super.reassemble(); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } -} - - -class Bar extends StatefulWidget { - const Bar(this.child, {super.key}); - - final Widget child; - static int count = 0; - - @override - State createState() => _BarState(); -} - -class _BarState extends State { - @override - void reassemble() { - Bar.count += 1; - super.reassemble(); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } -} - -class Fizz extends StatefulWidget { - const Fizz(this.child, {super.key}); - - final Widget child; - static int count = 0; - - @override - State createState() => _FizzState(); -} - -class _FizzState extends State { - @override - void reassemble() { - Fizz.count += 1; - super.reassemble(); - } - - @override - Widget build(BuildContext context) { - return widget.child; - } -} diff --git a/packages/flutter/test/widgets/widget_inspector_test_utils.dart b/packages/flutter/test/widgets/widget_inspector_test_utils.dart index 843b76e3e8522..19370bfa778b9 100644 --- a/packages/flutter/test/widgets/widget_inspector_test_utils.dart +++ b/packages/flutter/test/widgets/widget_inspector_test_utils.dart @@ -115,7 +115,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { final WidgetsBinding binding = WidgetsBinding.instance; if (binding.rootElement != null) { - binding.buildOwner!.reassemble(binding.rootElement!, null); + binding.buildOwner!.reassemble(binding.rootElement!); } } diff --git a/packages/flutter_tools/lib/src/bundle.dart b/packages/flutter_tools/lib/src/bundle.dart index 6eed94ee93a88..ef7bfdbddb095 100644 --- a/packages/flutter_tools/lib/src/bundle.dart +++ b/packages/flutter_tools/lib/src/bundle.dart @@ -33,7 +33,7 @@ String getDefaultCachedKernelPath({ }) { final StringBuffer buffer = StringBuffer(); final List cacheFrontEndOptions = extraFrontEndOptions.toList() - ..removeWhere((String arg) => arg.startsWith('--enable-experiment=') || arg == '--flutter-widget-cache'); + ..removeWhere((String arg) => arg.startsWith('--enable-experiment=')); buffer.writeAll(dartDefines); buffer.writeAll(cacheFrontEndOptions); String buildPrefix = ''; diff --git a/packages/flutter_tools/lib/src/devfs.dart b/packages/flutter_tools/lib/src/devfs.dart index 4136071ee2723..93e0f3a363ade 100644 --- a/packages/flutter_tools/lib/src/devfs.dart +++ b/packages/flutter_tools/lib/src/devfs.dart @@ -401,7 +401,6 @@ class UpdateFSReport { bool success = false, int invalidatedSourcesCount = 0, int syncedBytes = 0, - this.fastReassembleClassName, int scannedSourcesCount = 0, Duration compileDuration = Duration.zero, Duration transferDuration = Duration.zero, @@ -423,7 +422,6 @@ class UpdateFSReport { Duration get findInvalidatedDuration => _findInvalidatedDuration; bool _success; - String? fastReassembleClassName; int _invalidatedSourcesCount; int _syncedBytes; int _scannedSourcesCount; @@ -435,7 +433,6 @@ class UpdateFSReport { if (!report._success) { _success = false; } - fastReassembleClassName ??= report.fastReassembleClassName; _invalidatedSourcesCount += report._invalidatedSourcesCount; _syncedBytes += report._syncedBytes; _scannedSourcesCount += report._scannedSourcesCount; @@ -495,7 +492,6 @@ class DevFS { DateTime? lastCompiled; DateTime? _previousCompiled; PackageConfig? lastPackageConfig; - File? _widgetCacheOutputFile; Uri? _baseUri; Uri? get baseUri => _baseUri; @@ -555,22 +551,6 @@ class DevFS { lastCompiled = _previousCompiled; } - - /// If the build method of a single widget was modified, return the widget name. - /// - /// If any other changes were made, or there is an error scanning the file, - /// return `null`. - String? _checkIfSingleWidgetReloadApplied() { - final File? widgetCacheOutputFile = _widgetCacheOutputFile; - if (widgetCacheOutputFile != null && widgetCacheOutputFile.existsSync()) { - final String widget = widgetCacheOutputFile.readAsStringSync().trim(); - if (widget.isNotEmpty) { - return widget; - } - } - return null; - } - /// Updates files on the device. /// /// Returns the number of bytes synced. @@ -596,7 +576,6 @@ class DevFS { final DateTime candidateCompileTime = DateTime.now(); didUpdateFontManifest = false; lastPackageConfig = packageConfig; - _widgetCacheOutputFile = _fileSystem.file('$dillOutputPath.incremental.dill.widget_cache'); // Update modified files final Map dirtyEntries = {}; @@ -741,7 +720,6 @@ class DevFS { success: true, syncedBytes: syncedBytes, invalidatedSourcesCount: invalidatedFiles.length, - fastReassembleClassName: _checkIfSingleWidgetReloadApplied(), compileDuration: compileTimer.elapsed, transferDuration: transferTimer.elapsed, ); diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index 97be411a541fa..2c5a1b3c10fee 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -44,9 +44,6 @@ abstract class FeatureFlags { /// Whether custom devices are enabled. bool get areCustomDevicesEnabled => false; - /// Whether fast single widget reloads are enabled. - bool get isSingleWidgetReloadEnabled => false; - /// Whether WebAssembly compilation for Flutter Web is enabled. bool get isFlutterWebWasmEnabled => false; @@ -62,7 +59,6 @@ const List allFeatures = [ flutterLinuxDesktopFeature, flutterMacOSDesktopFeature, flutterWindowsDesktopFeature, - singleWidgetReload, flutterAndroidFeature, flutterIOSFeature, flutterFuchsiaFeature, @@ -140,20 +136,6 @@ const Feature flutterCustomDevicesFeature = Feature( ), ); -/// The fast hot reload feature for https://github.com/flutter/flutter/issues/61407. -const Feature singleWidgetReload = Feature( - name: 'Hot reload optimization for changes to class body of a single widget', - configSetting: 'single-widget-reload-optimization', - environmentOverride: 'FLUTTER_SINGLE_WIDGET_RELOAD', - master: FeatureChannelSetting( - available: true, - enabledByDefault: true, - ), - beta: FeatureChannelSetting( - available: true, - ), -); - /// Enabling WebAssembly compilation from `flutter build web` const Feature flutterWebWasm = Feature( name: 'WebAssembly compilation from flutter build web', diff --git a/packages/flutter_tools/lib/src/flutter_features.dart b/packages/flutter_tools/lib/src/flutter_features.dart index 672a81855d4bc..e4102bdfe8b95 100644 --- a/packages/flutter_tools/lib/src/flutter_features.dart +++ b/packages/flutter_tools/lib/src/flutter_features.dart @@ -44,9 +44,6 @@ class FlutterFeatureFlags implements FeatureFlags { @override bool get areCustomDevicesEnabled => isEnabled(flutterCustomDevicesFeature); - @override - bool get isSingleWidgetReloadEnabled => isEnabled(singleWidgetReload); - @override bool get isFlutterWebWasmEnabled => isEnabled(flutterWebWasm); diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index a44b803320a01..2c81eb2c91817 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -446,7 +446,6 @@ Please provide a valid TCP port (an integer between 0 and 65535, inclusive). fullRestart: true, reason: reason, overallTimeInMs: elapsed.inMilliseconds, - fastReassemble: false, ).send(); } return OperationResult.ok; diff --git a/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart b/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart index 9a31fcd57562d..4ee8c9e3429d1 100644 --- a/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart +++ b/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart @@ -58,7 +58,6 @@ class CustomDimensions { this.commandRunAndroidEmbeddingVersion, this.commandPackagesAndroidEmbeddingVersion, this.nullSafety, - this.fastReassemble, this.nullSafeMigratedLibraries, this.nullSafeTotalLibraries, this.hotEventCompileTimeInMs, @@ -118,17 +117,17 @@ class CustomDimensions { final String? commandRunAndroidEmbeddingVersion; // cd45 final String? commandPackagesAndroidEmbeddingVersion; // cd46 final bool? nullSafety; // cd47 - final bool? fastReassemble; // cd48 + // cd48 was fastReassemble but that feature was removed final int? nullSafeMigratedLibraries; // cd49 final int? nullSafeTotalLibraries; // cd50 - final int? hotEventCompileTimeInMs; // cd 51 - final int? hotEventFindInvalidatedTimeInMs; // cd 52 - final int? hotEventScannedSourcesCount; // cd 53 - final int? hotEventReassembleTimeInMs; // cd 54 - final int? hotEventReloadVMTimeInMs; // cd 55 - final bool? commandRunEnableImpeller; // cd 56 - final String? commandRunIOSInterfaceType; // cd 57 - final bool? commandRunIsTest; // cd 58 + final int? hotEventCompileTimeInMs; // cd51 + final int? hotEventFindInvalidatedTimeInMs; // cd52 + final int? hotEventScannedSourcesCount; // cd53 + final int? hotEventReassembleTimeInMs; // cd54 + final int? hotEventReloadVMTimeInMs; // cd55 + final bool? commandRunEnableImpeller; // cd56 + final String? commandRunIOSInterfaceType; // cd57 + final bool? commandRunIsTest; // cd58 /// Convert to a map that will be used to upload to the analytics backend. Map toMap() => { @@ -179,7 +178,6 @@ class CustomDimensions { if (commandRunAndroidEmbeddingVersion != null) CustomDimensionsEnum.commandRunAndroidEmbeddingVersion.cdKey: commandRunAndroidEmbeddingVersion.toString(), if (commandPackagesAndroidEmbeddingVersion != null) CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion.cdKey: commandPackagesAndroidEmbeddingVersion.toString(), if (nullSafety != null) CustomDimensionsEnum.nullSafety.cdKey: nullSafety.toString(), - if (fastReassemble != null) CustomDimensionsEnum.fastReassemble.cdKey: fastReassemble.toString(), if (nullSafeMigratedLibraries != null) CustomDimensionsEnum.nullSafeMigratedLibraries.cdKey: nullSafeMigratedLibraries.toString(), if (nullSafeTotalLibraries != null) CustomDimensionsEnum.nullSafeTotalLibraries.cdKey: nullSafeTotalLibraries.toString(), if (hotEventCompileTimeInMs != null) CustomDimensionsEnum.hotEventCompileTimeInMs.cdKey: hotEventCompileTimeInMs.toString(), @@ -247,7 +245,6 @@ class CustomDimensions { commandRunAndroidEmbeddingVersion: other.commandRunAndroidEmbeddingVersion ?? commandRunAndroidEmbeddingVersion, commandPackagesAndroidEmbeddingVersion: other.commandPackagesAndroidEmbeddingVersion ?? commandPackagesAndroidEmbeddingVersion, nullSafety: other.nullSafety ?? nullSafety, - fastReassemble: other.fastReassemble ?? fastReassemble, nullSafeMigratedLibraries: other.nullSafeMigratedLibraries ?? nullSafeMigratedLibraries, nullSafeTotalLibraries: other.nullSafeTotalLibraries ?? nullSafeTotalLibraries, hotEventCompileTimeInMs: other.hotEventCompileTimeInMs ?? hotEventCompileTimeInMs, @@ -309,7 +306,6 @@ class CustomDimensions { commandRunAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandRunAndroidEmbeddingVersion), commandPackagesAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion), nullSafety: _extractBool(map, CustomDimensionsEnum.nullSafety), - fastReassemble: _extractBool(map, CustomDimensionsEnum.fastReassemble), nullSafeMigratedLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeMigratedLibraries), nullSafeTotalLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeTotalLibraries), hotEventCompileTimeInMs: _extractInt(map, CustomDimensionsEnum.hotEventCompileTimeInMs), @@ -397,7 +393,7 @@ enum CustomDimensionsEnum { commandRunAndroidEmbeddingVersion, // cd45 commandPackagesAndroidEmbeddingVersion, // cd46 nullSafety, // cd47 - fastReassemble, // cd48 + obsolete1, // cd48 (was fastReassemble) nullSafeMigratedLibraries, // cd49 nullSafeTotalLibraries, // cd50 hotEventCompileTimeInMs, // cd51 diff --git a/packages/flutter_tools/lib/src/reporting/events.dart b/packages/flutter_tools/lib/src/reporting/events.dart index ae0028f214f93..ec3933ed5d48f 100644 --- a/packages/flutter_tools/lib/src/reporting/events.dart +++ b/packages/flutter_tools/lib/src/reporting/events.dart @@ -39,7 +39,6 @@ class HotEvent extends UsageEvent { required this.sdkName, required this.emulator, required this.fullRestart, - required this.fastReassemble, this.reason, this.finalLibraryCount, this.syncedLibraryCount, @@ -63,7 +62,6 @@ class HotEvent extends UsageEvent { final String sdkName; final bool emulator; final bool fullRestart; - final bool fastReassemble; final int? finalLibraryCount; final int? syncedLibraryCount; final int? syncedClassesCount; @@ -94,7 +92,6 @@ class HotEvent extends UsageEvent { hotEventInvalidatedSourcesCount: invalidatedSourcesCount, hotEventTransferTimeInMs: transferTimeInMs, hotEventOverallTimeInMs: overallTimeInMs, - fastReassemble: fastReassemble, hotEventCompileTimeInMs: compileTimeInMs, hotEventFindInvalidatedTimeInMs: findInvalidatedTimeInMs, hotEventScannedSourcesCount: scannedSourcesCount, diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 1d55e0d5673dc..a3de310f5a612 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -34,7 +34,6 @@ import 'compile.dart'; import 'convert.dart'; import 'devfs.dart'; import 'device.dart'; -import 'features.dart'; import 'globals.dart' as globals; import 'ios/application_package.dart'; import 'ios/devices.dart'; @@ -169,11 +168,8 @@ class FlutterDevice { platform: platform, ); } else { - // The flutter-widget-cache feature only applies to run mode. List extraFrontEndOptions = buildInfo.extraFrontEndOptions; extraFrontEndOptions = [ - if (featureFlags.isSingleWidgetReloadEnabled) - '--flutter-widget-cache', '--enable-experiment=alternative-invalidation-strategy', ...extraFrontEndOptions, ]; diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index d687012fdeab0..fdebdcab7314c 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -20,7 +20,6 @@ import 'convert.dart'; import 'dart/package_map.dart'; import 'devfs.dart'; import 'device.dart'; -import 'features.dart'; import 'globals.dart' as globals; import 'project.dart'; import 'reporting/reporting.dart'; @@ -415,7 +414,6 @@ class HotRunner extends ResidentRunner { sdkName: _sdkName!, emulator: _emulator!, fullRestart: false, - fastReassemble: false, overallTimeInMs: appStartedTimer.elapsed.inMilliseconds, compileTimeInMs: totalCompileTime.inMilliseconds, transferTimeInMs: totalLaunchAppTime.inMilliseconds, @@ -802,7 +800,6 @@ class HotRunner extends ResidentRunner { emulator: emulator!, fullRestart: true, reason: reason, - fastReassemble: false, overallTimeInMs: restartTimer.elapsed.inMilliseconds, syncedBytes: result.updateFSReport?.syncedBytes, invalidatedSourcesCount: result.updateFSReport?.invalidatedSourcesCount, @@ -828,7 +825,6 @@ class HotRunner extends ResidentRunner { emulator: emulator!, fullRestart: true, reason: reason, - fastReassemble: false, ).send(); } status?.cancel(); @@ -878,7 +874,6 @@ class HotRunner extends ResidentRunner { emulator: emulator!, fullRestart: false, reason: reason, - fastReassemble: false, ).send(); } else { HotEvent('exception', @@ -887,7 +882,6 @@ class HotRunner extends ResidentRunner { emulator: emulator!, fullRestart: false, reason: reason, - fastReassemble: false, ).send(); } return OperationResult(errorCode, errorMessage, fatal: true); @@ -971,7 +965,6 @@ class HotRunner extends ResidentRunner { viewCache, onSlow, reloadMessage, - updatedDevFS.fastReassembleClassName, ); shouldReportReloadTime = reassembleResult.shouldReportReloadTime; if (reassembleResult.reassembleViews.isEmpty) { @@ -1005,7 +998,6 @@ class HotRunner extends ResidentRunner { syncedBytes: updatedDevFS.syncedBytes, invalidatedSourcesCount: updatedDevFS.invalidatedSourcesCount, transferTimeInMs: updatedDevFS.transferDuration.inMilliseconds, - fastReassemble: featureFlags.isSingleWidgetReloadEnabled && updatedDevFS.fastReassembleClassName != null, compileTimeInMs: updatedDevFS.compileDuration.inMilliseconds, findInvalidatedTimeInMs: updatedDevFS.findInvalidatedDuration.inMilliseconds, scannedSourcesCount: updatedDevFS.scannedSourcesCount, @@ -1225,7 +1217,6 @@ Future defaultReloadSourcesHelper( emulator: emulator!, fullRestart: false, reason: reason, - fastReassemble: false, usage: usage, ).send(); // Reset devFS lastCompileTime to ensure the file will still be marked @@ -1288,7 +1279,6 @@ typedef ReassembleHelper = Future Function( Map> viewCache, void Function(String message)? onSlow, String reloadMessage, - String? fastReassembleClassName, ); Future _defaultReassembleHelper( @@ -1296,7 +1286,6 @@ Future _defaultReassembleHelper( Map> viewCache, void Function(String message)? onSlow, String reloadMessage, - String? fastReassembleClassName, ) async { // Check if any isolates are paused and reassemble those that aren't. final Map reassembleViews = {}; @@ -1325,17 +1314,9 @@ Future _defaultReassembleHelper( reassembleViews[view] = device.vmService; // If the tool identified a change in a single widget, do a fast instead // of a full reassemble. - Future reassembleWork; - if (fastReassembleClassName != null) { - reassembleWork = device.vmService!.flutterFastReassemble( - isolateId: view.uiIsolate!.id!, - className: fastReassembleClassName, - ); - } else { - reassembleWork = device.vmService!.flutterReassemble( - isolateId: view.uiIsolate!.id!, - ); - } + final Future reassembleWork = device.vmService!.flutterReassemble( + isolateId: view.uiIsolate!.id!, + ); reassembleFutures.add(reassembleWork.then( (Object? obj) => obj, onError: (Object error, StackTrace stackTrace) { diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 6da8494d24de6..57228a9bdf75d 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -809,19 +809,6 @@ class FlutterVmService { ); } - Future?> flutterFastReassemble({ - required String isolateId, - required String className, - }) { - return invokeFlutterExtensionRpcRaw( - 'ext.flutter.fastReassemble', - isolateId: isolateId, - args: { - 'className': className, - }, - ); - } - Future flutterAlreadyPaintedFirstUsefulFrame({ required String isolateId, }) async { diff --git a/packages/flutter_tools/test/general.shard/bundle_builder_test.dart b/packages/flutter_tools/test/general.shard/bundle_builder_test.dart index 190400acb5800..335354026fb27 100644 --- a/packages/flutter_tools/test/general.shard/bundle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/bundle_builder_test.dart @@ -118,14 +118,14 @@ void main() { ProcessManager: () => FakeProcessManager.any(), }); - testWithoutContext('--flutter-widget-cache and --enable-experiment are removed from getDefaultCachedKernelPath hash', () { + testWithoutContext('--enable-experiment is removed from getDefaultCachedKernelPath hash', () { final FileSystem fileSystem = MemoryFileSystem.test(); final Config config = Config.test(); expect(getDefaultCachedKernelPath( trackWidgetCreation: true, dartDefines: [], - extraFrontEndOptions: ['--enable-experiment=foo', '--flutter-widget-cache'], + extraFrontEndOptions: ['--enable-experiment=foo'], fileSystem: fileSystem, config: config, ), 'build/cache.dill.track.dill'); @@ -133,7 +133,7 @@ void main() { expect(getDefaultCachedKernelPath( trackWidgetCreation: true, dartDefines: ['foo=bar'], - extraFrontEndOptions: ['--enable-experiment=foo', '--flutter-widget-cache'], + extraFrontEndOptions: ['--enable-experiment=foo'], fileSystem: fileSystem, config: config, ), 'build/06ad47d8e64bd28de537b62ff85357c4.cache.dill.track.dill'); @@ -141,7 +141,7 @@ void main() { expect(getDefaultCachedKernelPath( trackWidgetCreation: false, dartDefines: [], - extraFrontEndOptions: ['--enable-experiment=foo', '--flutter-widget-cache'], + extraFrontEndOptions: ['--enable-experiment=foo'], fileSystem: fileSystem, config: config, ), 'build/cache.dill'); @@ -149,7 +149,7 @@ void main() { expect(getDefaultCachedKernelPath( trackWidgetCreation: true, dartDefines: [], - extraFrontEndOptions: ['--enable-experiment=foo', '--flutter-widget-cache', '--foo=bar'], + extraFrontEndOptions: ['--enable-experiment=foo', '--foo=bar'], fileSystem: fileSystem, config: config, ), 'build/95b595cca01caa5f0ca0a690339dd7f6.cache.dill.track.dill'); diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index 110b59a08cd09..b8be90ff0b46a 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -178,7 +178,6 @@ void main() { Map> viewCache, void Function(String message)? onSlow, String reloadMessage, - String? fastReassembleClassName, ) async => ReassembleResult( {null: null}, false, @@ -296,7 +295,6 @@ void main() { hotEventSdkName: 'Tester', hotEventEmulator: false, hotEventFullRestart: true, - fastReassemble: false, hotEventOverallTimeInMs: 64000, hotEventSyncedBytes: 4, hotEventInvalidatedSourcesCount: 2, @@ -379,7 +377,6 @@ void main() { Map> viewCache, void Function(String message)? onSlow, String reloadMessage, - String? fastReassembleClassName, ) async => ReassembleResult( {null: null}, false, @@ -402,7 +399,6 @@ void main() { hotEventSdkName: 'Tester', hotEventEmulator: false, hotEventFullRestart: false, - fastReassemble: false, hotEventCompileTimeInMs: 16000, hotEventFindInvalidatedTimeInMs: 64000, hotEventScannedSourcesCount: 16, diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 35970ba5c196c..6723487850953 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -25,7 +25,6 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; -import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; @@ -424,7 +423,6 @@ void main() { hotEventSdkName: 'Android', hotEventEmulator: false, hotEventFullRestart: false, - fastReassemble: false, )), )); expect(fakeVmServiceHost?.hasRemainingExpectations, false); @@ -480,7 +478,6 @@ void main() { hotEventSdkName: 'Android', hotEventEmulator: false, hotEventFullRestart: false, - fastReassemble: false, )), )); expect(fakeVmServiceHost?.hasRemainingExpectations, false); @@ -527,7 +524,6 @@ void main() { hotEventSdkName: 'Android', hotEventEmulator: false, hotEventFullRestart: false, - fastReassemble: false, )), )); expect(fakeVmServiceHost?.hasRemainingExpectations, false); @@ -766,96 +762,6 @@ void main() { Usage: () => TestUsage(), })); - testUsingContext('ResidentRunner can perform fast reassemble', () => testbed.run(() async { - fakeVmServiceHost = FakeVmServiceHost(requests: [ - listViews, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), - listViews, - listViews, - FakeVmServiceRequest( - method: 'getVM', - jsonResponse: fakeVM.toJson(), - ), - const FakeVmServiceRequest( - method: kReloadSourcesServiceName, - args: { - 'isolateId': '1', - 'pause': false, - 'rootLibUri': 'main.dart.incremental.dill', - }, - jsonResponse: { - 'type': 'ReloadReport', - 'success': true, - 'details': { - 'loadedLibraryCount': 1, - }, - }, - ), - FakeVmServiceRequest( - method: 'getIsolatePauseEvent', - args: { - 'isolateId': '1', - }, - jsonResponse: fakeUnpausedEvent.toJson(), - ), - FakeVmServiceRequest( - method: 'ext.flutter.fastReassemble', - args: { - 'isolateId': fakeUnpausedIsolate.id, - 'className': 'FOO', - }, - ), - ]); - final FakeDelegateFlutterDevice flutterDevice = FakeDelegateFlutterDevice( - device, - BuildInfo.debug, - FakeResidentCompiler(), - devFS, - )..vmService = fakeVmServiceHost!.vmService; - residentRunner = HotRunner( - [ - flutterDevice, - ], - stayResident: false, - debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), - target: 'main.dart', - devtoolsHandler: createNoOpHandler, - ); - devFS.nextUpdateReport = UpdateFSReport( - success: true, - fastReassembleClassName: 'FOO', - invalidatedSourcesCount: 1, - ); - - final Completer futureConnectionInfo = Completer.sync(); - final Completer futureAppStart = Completer.sync(); - unawaited(residentRunner.attach( - appStartedCompleter: futureAppStart, - connectionInfoCompleter: futureConnectionInfo, - enableDevTools: true, - )); - - await futureAppStart.future; - final OperationResult result = await residentRunner.restart(); - - expect(result.fatal, false); - expect(result.code, 0); - - final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; - expect(event.category, 'hot'); - expect(event.parameter, 'reload'); - expect(event.parameters?.fastReassemble, true); - }, overrides: { - FileSystem: () => MemoryFileSystem.test(), - Platform: () => FakePlatform(), - ProjectFileInvalidator: () => FakeProjectFileInvalidator(), - Usage: () => TestUsage(), - FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true), - })); - testUsingContext('ResidentRunner reports hot reload time details', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: [ listViews, @@ -893,10 +799,9 @@ void main() { jsonResponse: fakeUnpausedEvent.toJson(), ), FakeVmServiceRequest( - method: 'ext.flutter.fastReassemble', + method: 'ext.flutter.reassemble', args: { 'isolateId': fakeUnpausedIsolate.id, - 'className': 'FOO', }, ), ]); @@ -917,7 +822,6 @@ void main() { ); devFS.nextUpdateReport = UpdateFSReport( success: true, - fastReassembleClassName: 'FOO', invalidatedSourcesCount: 1, ); @@ -942,7 +846,6 @@ void main() { Platform: () => FakePlatform(), ProjectFileInvalidator: () => FakeProjectFileInvalidator(), Usage: () => TestUsage(), - FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true), })); testUsingContext('ResidentRunner can send target platform to analytics from full restart', () => testbed.run(() async { @@ -1225,7 +1128,6 @@ void main() { hotEventSdkName: 'Android', hotEventEmulator: false, hotEventFullRestart: true, - fastReassemble: false, )), )); expect(fakeVmServiceHost?.hasRemainingExpectations, false); @@ -1984,31 +1886,7 @@ flutter: ProcessManager: () => FakeProcessManager.any(), }); - testUsingContext('FlutterDevice passes flutter-widget-cache flag when feature is enabled', () async { - fakeVmServiceHost = FakeVmServiceHost(requests: []); - final FakeDevice device = FakeDevice(); - - final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( - device, - buildInfo: const BuildInfo( - BuildMode.debug, - '', - treeShakeIcons: false, - extraFrontEndOptions: [], - ), - target: null, platform: FakePlatform(), - )).generator as DefaultResidentCompiler?; - - expect(residentCompiler!.extraFrontEndOptions, - contains('--flutter-widget-cache')); - }, overrides: { - Artifacts: () => Artifacts.test(), - FileSystem: () => MemoryFileSystem.test(), - ProcessManager: () => FakeProcessManager.any(), - FeatureFlags: () => TestFeatureFlags(isSingleWidgetReloadEnabled: true), - }); - - testUsingContext('FlutterDevice passes alternative-invalidation-strategy flag', () async { + testUsingContext('FlutterDevice passes alternative-invalidation-strategy flag', () async { fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(); @@ -2032,7 +1910,7 @@ flutter: ProcessManager: () => FakeProcessManager.any(), }); - testUsingContext('FlutterDevice passes initializeFromDill parameter if specified', () async { + testUsingContext('FlutterDevice passes initializeFromDill parameter if specified', () async { fakeVmServiceHost = FakeVmServiceHost(requests: []); final FakeDevice device = FakeDevice(); diff --git a/packages/flutter_tools/test/integration.shard/single_widget_reload_test.dart b/packages/flutter_tools/test/integration.shard/single_widget_reload_test.dart deleted file mode 100644 index 85ec32c59e08e..0000000000000 --- a/packages/flutter_tools/test/integration.shard/single_widget_reload_test.dart +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; - -import 'package:flutter_tools/src/base/file_system.dart'; - -import '../src/common.dart'; -import 'test_data/single_widget_reload_project.dart'; -import 'test_driver.dart'; -import 'test_utils.dart'; - -void main() { - late Directory tempDir; - final SingleWidgetReloadProject project = SingleWidgetReloadProject(); - late FlutterRunTestDriver flutter; - - setUp(() async { - tempDir = createResolvedTempDirectorySync('hot_reload_test.'); - await project.setUpIn(tempDir); - flutter = FlutterRunTestDriver(tempDir); - }); - - tearDown(() async { - await flutter.stop(); - tryToDelete(tempDir); - }); - - testWithoutContext('newly added code executes during hot reload with single widget reloads, but only invalidated widget', () async { - final StringBuffer stdout = StringBuffer(); - final StreamSubscription subscription = flutter.stdout.listen(stdout.writeln); - await flutter.run(singleWidgetReloads: true); - project.uncommentHotReloadPrint(); - try { - await flutter.hotReload(); - expect(stdout.toString(), allOf( - contains('(((TICK 1)))'), - contains('(((((RELOAD WORKED)))))'), - // Does not invalidate parent widget, so second tick is not output. - isNot(contains('(((TICK 2)))'), - ))); - } finally { - await subscription.cancel(); - } - }); - - testWithoutContext('changes outside of the class body triggers a full reload', () async { - final StringBuffer stdout = StringBuffer(); - final StreamSubscription subscription = flutter.stdout.listen(stdout.writeln); - await flutter.run(singleWidgetReloads: true); - project.modifyFunction(); - try { - await flutter.hotReload(); - expect(stdout.toString(), allOf( - contains('(((TICK 1)))'), - contains('(((TICK 2)))'), - )); - } finally { - await subscription.cancel(); - } - }); -} diff --git a/packages/flutter_tools/test/integration.shard/test_data/single_widget_reload_project.dart b/packages/flutter_tools/test/integration.shard/test_data/single_widget_reload_project.dart deleted file mode 100644 index 2a48a090ea084..0000000000000 --- a/packages/flutter_tools/test/integration.shard/test_data/single_widget_reload_project.dart +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '../test_utils.dart'; -import 'project.dart'; - -class SingleWidgetReloadProject extends Project { - @override - final String pubspec = ''' - name: test - environment: - sdk: '>=3.0.0-0 <4.0.0' - - dependencies: - flutter: - sdk: flutter - '''; - - @override - final String main = r''' - import 'package:flutter/material.dart'; - import 'package:flutter/scheduler.dart'; - import 'package:flutter/services.dart'; - import 'package:flutter/widgets.dart'; - - void main() async { - WidgetsFlutterBinding.ensureInitialized(); - final ByteData message = const StringCodec().encodeMessage('AppLifecycleState.resumed')!; - await ServicesBinding.instance!.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) { }); - runApp(MyApp()); - } - - int count = 1; - - class MyApp extends StatelessWidget { - @override - Widget build(BuildContext context) { - // PARENT WIDGET - - print('((((TICK $count))))'); - count += 1; - - return MaterialApp( - title: 'Flutter Demo', - home: SecondWidget(), - ); - } - } - - class SecondWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - // Do not remove the next line, it's uncommented by a test to verify that - // hot reloading worked: - // printHotReloadWorked(); - return Container(); - } - } - - void printHotReloadWorked() { - // The call to this function is uncommented by a test to verify that hot - // reloading worked. - print('(((((RELOAD WORKED)))))'); - } - '''; - - Uri get parentWidgetUri => mainDart; - int get parentWidgetLine => lineContaining(main, '// PARENT WIDGET'); - - void uncommentHotReloadPrint() { - final String newMainContents = main.replaceAll( - '// printHotReloadWorked();', - 'printHotReloadWorked();', - ); - writeFile( - fileSystem.path.join(dir.path, 'lib', 'main.dart'), - newMainContents, - writeFutureModifiedDate: true, - ); - } - - void modifyFunction() { - final String newMainContents = main.replaceAll( - '(((((RELOAD WORKED)))))', - '(((((RELOAD WORKED 2)))))', - ); - writeFile( - fileSystem.path.join(dir.path, 'lib', 'main.dart'), - newMainContents, - writeFutureModifiedDate: true, - ); - } -} diff --git a/packages/flutter_tools/test/integration.shard/test_driver.dart b/packages/flutter_tools/test/integration.shard/test_driver.dart index 24a8e59575a09..6be229d2d5e91 100644 --- a/packages/flutter_tools/test/integration.shard/test_driver.dart +++ b/packages/flutter_tools/test/integration.shard/test_driver.dart @@ -90,7 +90,6 @@ abstract class FlutterTestDriver { List arguments, { String? script, bool withDebugger = false, - bool singleWidgetReloads = false, }) async { final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); if (withDebugger) { @@ -114,8 +113,6 @@ abstract class FlutterTestDriver { environment: { 'FLUTTER_TEST': 'true', 'FLUTTER_WEB': 'true', - if (singleWidgetReloads) - 'FLUTTER_SINGLE_WIDGET_RELOAD': 'true', }, ); @@ -511,7 +508,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { bool chrome = false, bool expressionEvaluation = true, bool structuredErrors = false, - bool singleWidgetReloads = false, bool serveObservatory = false, String? script, List? additionalCommandArgs, @@ -542,7 +538,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { startPaused: startPaused, pauseOnExceptions: pauseOnExceptions, script: script, - singleWidgetReloads: singleWidgetReloads, ); } @@ -551,7 +546,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { bool withDebugger = false, bool startPaused = false, bool pauseOnExceptions = false, - bool singleWidgetReloads = false, bool serveObservatory = false, List? additionalCommandArgs, }) async { @@ -573,7 +567,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { withDebugger: withDebugger, startPaused: startPaused, pauseOnExceptions: pauseOnExceptions, - singleWidgetReloads: singleWidgetReloads, attachPort: port, ); } @@ -585,7 +578,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { bool withDebugger = false, bool startPaused = false, bool pauseOnExceptions = false, - bool singleWidgetReloads = false, int? attachPort, }) async { assert(!startPaused || withDebugger); @@ -593,7 +585,6 @@ class FlutterRunTestDriver extends FlutterTestDriver { args, script: script, withDebugger: withDebugger, - singleWidgetReloads: singleWidgetReloads, ); final Completer prematureExitGuard = Completer(); @@ -806,13 +797,11 @@ class FlutterTestTestDriver extends FlutterTestDriver { bool withDebugger = false, bool pauseOnExceptions = false, Future Function()? beforeStart, - bool singleWidgetReloads = false, }) async { await super._setupProcess( args, script: script, withDebugger: withDebugger, - singleWidgetReloads: singleWidgetReloads, ); // Stash the PID so that we can terminate the VM more reliably than using diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index 65fb5578cf185..d51ec236dcaac 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -443,7 +443,6 @@ class TestFeatureFlags implements FeatureFlags { this.isMacOSEnabled = false, this.isWebEnabled = false, this.isWindowsEnabled = false, - this.isSingleWidgetReloadEnabled = false, this.isAndroidEnabled = true, this.isIOSEnabled = true, this.isFuchsiaEnabled = false, @@ -463,9 +462,6 @@ class TestFeatureFlags implements FeatureFlags { @override final bool isWindowsEnabled; - @override - final bool isSingleWidgetReloadEnabled; - @override final bool isAndroidEnabled; @@ -492,8 +488,6 @@ class TestFeatureFlags implements FeatureFlags { return isMacOSEnabled; case flutterWindowsDesktopFeature: return isWindowsEnabled; - case singleWidgetReload: - return isSingleWidgetReloadEnabled; case flutterAndroidFeature: return isAndroidEnabled; case flutterIOSFeature: From 2bb91a2692e1ec369ff11b56c33d11cb06f0796e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 17:58:07 -0400 Subject: [PATCH 0656/1547] Roll Flutter Engine from a9be77e6f475 to 16b01b98af20 (6 revisions) (#132332) https://github.com/flutter/engine/compare/a9be77e6f475...16b01b98af20 2023-08-10 skia-flutter-autoroll@skia.org Roll Dart SDK from 46da53e7abe2 to a2eac00da6b8 (1 revision) (flutter/engine#44601) 2023-08-10 huxiaohu2007@gmail.com Fix unexpected pointer change issue and Add test case (flutter/engine#43949) 2023-08-10 47866232+chunhtai@users.noreply.github.com Reland "Android a11y bridge sets importantness" (flutter/engine#44589) 2023-08-10 john@johnmccutchan.com Support for Android Platform Views under Impeller/Vulkan (flutter/engine#44571) 2023-08-10 109111084+yaakovschectman@users.noreply.github.com Reintroduce Windows lifecycle with guard for posthumous `OnWindowStateEvent` (flutter/engine#44344) 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from 92e6f52b0fa8 to b6492f5ce8c3 (1 revision) (flutter/engine#44597) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f41099087f77c..5c60fc5828fbb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a9be77e6f47552cfcd5252112218d273d472e19b +16b01b98af20a8b169d00dd05e828071416139b0 From 7dff527be524e4371245419683fe31c4f306c414 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 10 Aug 2023 15:15:26 -0700 Subject: [PATCH 0657/1547] Update application id and bundle id of a11y assessment app (#132334) The skeleton id needed to be updated to be sent to app store or play store --- dev/a11y_assessments/android/app/build.gradle | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 32 ++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/dev/a11y_assessments/android/app/build.gradle b/dev/a11y_assessments/android/app/build.gradle index dcf73d660939c..c60f9f431e37e 100644 --- a/dev/a11y_assessments/android/app/build.gradle +++ b/dev/a11y_assessments/android/app/build.gradle @@ -46,7 +46,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.a11y_assessments" + applicationId "dev.flutter.a11yassessments" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdkVersion flutter.minSdkVersion diff --git a/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj b/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj index 9711fbb0f3ef8..142bb384b0dd1 100644 --- a/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj +++ b/dev/a11y_assessments/ios/Runner.xcodeproj/project.pbxproj @@ -8,12 +8,12 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,6 +42,8 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -53,8 +55,6 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -68,6 +68,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -79,14 +87,6 @@ name = Flutter; sourceTree = ""; }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( @@ -129,7 +129,6 @@ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( 331C807D294A63A400263BE5 /* Sources */, - 331C807E294A63A400263BE5 /* Frameworks */, 331C807F294A63A400263BE5 /* Resources */, ); buildRules = ( @@ -368,7 +367,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.a11yAssessments; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; @@ -378,7 +377,6 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,7 +394,6 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -412,7 +409,6 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -547,7 +543,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.a11yAssessments; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; @@ -570,7 +566,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.a11yAssessments; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.a11yAssessments; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; From b4d5c8f4254edb8ade076679b4db0673c5208d8a Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 10 Aug 2023 15:25:57 -0700 Subject: [PATCH 0658/1547] Update `flutter_tools/bin/*.(dart|sh)` to provide, if set, --local-engine-host. (#132336) Partial work towards https://github.com/flutter/flutter/issues/132245. Other than updating error messages, and passing `$LOCAL_ENGINE_HOST` downwards, this PR should not change the behavior of any existing workflows or code (i.e. it's purely additive). --- packages/flutter_tools/bin/macos_assemble.sh | 21 +++++++++++++++++-- packages/flutter_tools/bin/tool_backend.dart | 19 +++++++++++++++-- packages/flutter_tools/bin/xcode_backend.dart | 4 ++++ .../integration.shard/tool_backend_test.dart | 21 +++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/bin/macos_assemble.sh b/packages/flutter_tools/bin/macos_assemble.sh index f4df20b9bf658..50f85fd227c4e 100755 --- a/packages/flutter_tools/bin/macos_assemble.sh +++ b/packages/flutter_tools/bin/macos_assemble.sh @@ -66,9 +66,23 @@ BuildApp() { EchoError "This engine is not compatible with FLUTTER_BUILD_MODE: '${build_mode}'." EchoError "You can fix this by updating the LOCAL_ENGINE environment variable, or" EchoError "by running:" - EchoError " flutter build macos --local-engine=host_${build_mode}" + EchoError " flutter build macos --local-engine=host_${build_mode} --local-engine-host=host_${build_mode}" EchoError "or" - EchoError " flutter build macos --local-engine=host_${build_mode}_unopt" + EchoError " flutter build macos --local-engine=host_${build_mode}_unopt --local-engine-host=host_${build_mode}_unopt" + EchoError "========================================================================" + exit -1 + fi + fi + if [[ -n "$LOCAL_ENGINE_HOST" ]]; then + if [[ $(echo "$LOCAL_ENGINE_HOST" | tr "[:upper:]" "[:lower:]") != *"$build_mode"* ]]; then + EchoError "========================================================================" + EchoError "ERROR: Requested build with Flutter local engine at '${LOCAL_ENGINE_HOST}'" + EchoError "This engine is not compatible with FLUTTER_BUILD_MODE: '${build_mode}'." + EchoError "You can fix this by updating the LOCAL_ENGINE_HOST environment variable, or" + EchoError "by running:" + EchoError " flutter build macos --local-engine=host_${build_mode} --local-engine-host=host_${build_mode}" + EchoError "or" + EchoError " flutter build macos --local-engine=host_${build_mode}_unopt --local-engine-host=host_${build_mode}_unopt" EchoError "========================================================================" exit -1 fi @@ -94,6 +108,9 @@ BuildApp() { if [[ -n "$LOCAL_ENGINE" ]]; then flutter_args+=("--local-engine=${LOCAL_ENGINE}") fi + if [[ -n "$LOCAL_ENGINE_HOST" ]]; then + flutter_args+=("--local-engine-host=${LOCAL_ENGINE_HOST}") + fi flutter_args+=( "assemble" "--no-version-check" diff --git a/packages/flutter_tools/bin/tool_backend.dart b/packages/flutter_tools/bin/tool_backend.dart index 411d53e962e53..7b67f56757638 100644 --- a/packages/flutter_tools/bin/tool_backend.dart +++ b/packages/flutter_tools/bin/tool_backend.dart @@ -21,6 +21,7 @@ Future main(List arguments) async { ?? pathJoin(['lib', 'main.dart']); final String? codeSizeDirectory = Platform.environment['CODE_SIZE_DIRECTORY']; final String? localEngine = Platform.environment['LOCAL_ENGINE']; + final String? localEngineHost = Platform.environment['LOCAL_ENGINE_HOST']; final String? projectDirectory = Platform.environment['PROJECT_DIR']; final String? splitDebugInfo = Platform.environment['SPLIT_DEBUG_INFO']; final String? bundleSkSLPath = Platform.environment['BUNDLE_SKSL_PATH']; @@ -46,9 +47,22 @@ ERROR: Requested build with Flutter local engine at '$localEngine' This engine is not compatible with FLUTTER_BUILD_MODE: '$buildMode'. You can fix this by updating the LOCAL_ENGINE environment variable, or by running: - flutter build --local-engine=host_$buildMode + flutter build --local-engine=_$buildMode --local-engine-host=host_$buildMode or - flutter build --local-engine=host_${buildMode}_unopt + flutter build --local-engine=_${buildMode}_unopt --local-engine-host=host_${buildMode}_unopt +======================================================================== +'''); + exit(1); + } + if (localEngineHost != null && !localEngineHost.contains(buildMode)) { + stderr.write(''' +ERROR: Requested build with Flutter local engine host at '$localEngineHost' +This engine is not compatible with FLUTTER_BUILD_MODE: '$buildMode'. +You can fix this by updating the LOCAL_ENGINE_HOST environment variable, or +by running: + flutter build --local-engine=_$buildMode --local-engine-host=host_$buildMode +or + flutter build --local-engine=_$buildMode --local-engine-host=host_${buildMode}_unopt ======================================================================== '''); exit(1); @@ -72,6 +86,7 @@ or '--prefixed-errors', if (flutterEngine != null) '--local-engine-src-path=$flutterEngine', if (localEngine != null) '--local-engine=$localEngine', + if (localEngineHost != null) '--local-engine-host=$localEngineHost', 'assemble', '--no-version-check', '--output=build', diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index 0486a8741c3dc..15da6b525ed47 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -345,6 +345,10 @@ class Context { flutterArgs.add('--local-engine=${environment['LOCAL_ENGINE']}'); } + if (environment['LOCAL_ENGINE_HOST'] != null && environment['LOCAL_ENGINE_HOST']!.isNotEmpty) { + flutterArgs.add('--local-engine-host=${environment['LOCAL_ENGINE_HOST']}'); + } + flutterArgs.addAll([ 'assemble', '--no-version-check', diff --git a/packages/flutter_tools/test/integration.shard/tool_backend_test.dart b/packages/flutter_tools/test/integration.shard/tool_backend_test.dart index 1beb8916aad40..7353bf9d617d8 100644 --- a/packages/flutter_tools/test/integration.shard/tool_backend_test.dart +++ b/packages/flutter_tools/test/integration.shard/tool_backend_test.dart @@ -70,4 +70,25 @@ void main() { ), ); }); + + testWithoutContext('tool_backend.dart exits if local engine host does not match build mode', () async { + final ProcessResult result = await processManager.run([ + dart, + toolBackend, + 'linux-x64', + 'debug', + ], environment: { + 'PROJECT_DIR': examplePath, + 'LOCAL_ENGINE': 'debug_foo_bar', // OK + 'LOCAL_ENGINE_HOST': 'release_foo_bar', // Does not contain "debug", + }); + + expect( + result, + const ProcessResultMatcher( + exitCode: 1, + stderrPattern: "ERROR: Requested build with Flutter local engine host at 'release_foo_bar'", + ), + ); + }); } From 67ded4b0802b47a1911768bab4d9f4117a651eab Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 18:51:23 -0400 Subject: [PATCH 0659/1547] Roll Flutter Engine from 16b01b98af20 to b019ac62f21f (1 revision) (#132341) https://github.com/flutter/engine/compare/16b01b98af20...b019ac62f21f 2023-08-10 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from SoKcmsZ5H8uHJXV1S... to hdjihTvRxbNprHI9x... (flutter/engine#44600) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from SoKcmsZ5H8uH to hdjihTvRxbNp If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5c60fc5828fbb..a66a99469afa2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -16b01b98af20a8b169d00dd05e828071416139b0 +b019ac62f21ffa15303ee8eb62e6140d38729295 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 02e28e469b838..779baf766ab54 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -SoKcmsZ5H8uHJXV1S-usFW2d9gflCTQCiZ7pJIgc7FcC +hdjihTvRxbNprHI9xGvPV7rtu-TXd1KORZXTW_2t8T4C From 978461c54e736b4d0481fdf4c9a75beafea19a31 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 19:50:09 -0400 Subject: [PATCH 0660/1547] Roll Flutter Engine from b019ac62f21f to 18a71c031f5f (2 revisions) (#132347) https://github.com/flutter/engine/compare/b019ac62f21f...18a71c031f5f 2023-08-10 chris@bracken.jp [shell] Add references to VsyncWaiter docs (flutter/engine#44607) 2023-08-10 skia-flutter-autoroll@skia.org Roll Skia from b6492f5ce8c3 to b001e0a5e46f (1 revision) (flutter/engine#44606) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a66a99469afa2..61bb355ebb406 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b019ac62f21ffa15303ee8eb62e6140d38729295 +18a71c031f5ffd65ebac93228c141ee0ea735d41 From a7997f606e32bc7e54778df50e003f975b85a536 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Thu, 10 Aug 2023 17:25:30 -0700 Subject: [PATCH 0661/1547] Update `dev/devicelab/**` to provide `--local-engine-host`. (#132342) Partial work towards https://github.com/flutter/flutter/issues/132245. I have to admit I don't totally understand what I've updated, or whether there are more integration points needed. --- dev/devicelab/README.md | 11 ++++++--- dev/devicelab/bin/run.dart | 27 +++++++++++++++++++++- dev/devicelab/lib/command/test.dart | 10 ++++++++ dev/devicelab/lib/framework/ab.dart | 6 ++++- dev/devicelab/lib/framework/framework.dart | 4 ++++ dev/devicelab/lib/framework/runner.dart | 6 +++++ dev/devicelab/lib/framework/utils.dart | 10 ++++++++ dev/devicelab/lib/tasks/perf_tests.dart | 5 ++++ dev/devicelab/test/ab_test.dart | 2 +- dev/devicelab/test/run_test.dart | 2 +- dev/devicelab/test/utils_test.dart | 1 + 11 files changed, 77 insertions(+), 7 deletions(-) diff --git a/dev/devicelab/README.md b/dev/devicelab/README.md index afa8300f1534c..69ba2d61ea168 100644 --- a/dev/devicelab/README.md +++ b/dev/devicelab/README.md @@ -91,10 +91,12 @@ flags to `bin/run.dart`: ```sh ../../bin/cache/dart-sdk/bin/dart bin/run.dart --task=[some_task] \ --local-engine-src-path=[path_to_local]/engine/src \ - --local-engine=[local_engine_architecture] + --local-engine=[local_engine_architecture] \ + --local-engine-host=[local_engine_host_architecture] ``` -An example of a local engine architecture is `android_debug_unopt_x86`. +An example of a local engine architecture is `android_debug_unopt_x86` and +an example of a local engine host architecture is `host_debug_unopt`. ### Running an A/B test for engine changes @@ -111,13 +113,16 @@ Example: ```sh ../../bin/cache/dart-sdk/bin/dart bin/run.dart --ab=10 \ --local-engine=host_debug_unopt \ + --local-engine-host=host_debug_unopt \ -t bin/tasks/web_benchmarks_canvaskit.dart ``` The `--ab=10` tells the runner to run an A/B test 10 times. `--local-engine=host_debug_unopt` tells the A/B test to use the -`host_debug_unopt` engine build. `--local-engine` is required for A/B test. +`host_debug_unopt` engine build. `--local-engine-host=host_debug_unopt` uses +the same engine build to run the `frontend_server` (in this example). +`--local-engine` is required for A/B test. `--ab-result-file=filename` can be used to provide an alternate location to output the JSON results file (defaults to `ABresults#.json`). A single `#` diff --git a/dev/devicelab/bin/run.dart b/dev/devicelab/bin/run.dart index cc0cb1bb29fbf..28da34ad507c8 100644 --- a/dev/devicelab/bin/run.dart +++ b/dev/devicelab/bin/run.dart @@ -38,6 +38,11 @@ Future main(List rawArgs) async { /// Required for A/B test mode. final String? localEngine = args['local-engine'] as String?; + /// The build of the local engine to use as the host platform. + /// + /// Required if [localEngine] is set. + final String? localEngineHost = args['local-engine-host'] as String?; + /// The build of the local Web SDK to use. /// /// Required for A/B test mode. @@ -95,10 +100,16 @@ Future main(List rawArgs) async { stderr.writeln(argParser.usage); exit(1); } + if (localEngineHost == null) { + stderr.writeln('When running in A/B test mode --local-engine-host is required.\n'); + stderr.writeln(argParser.usage); + exit(1); + } await _runABTest( runsPerTest: runsPerTest, silent: silent, localEngine: localEngine, + localEngineHost: localEngineHost, localWebSdk: localWebSdk, localEngineSrcPath: localEngineSrcPath, deviceId: deviceId, @@ -125,6 +136,7 @@ Future _runABTest({ required int runsPerTest, required bool silent, required String? localEngine, + required String localEngineHost, required String? localWebSdk, required String? localEngineSrcPath, required String? deviceId, @@ -135,7 +147,11 @@ Future _runABTest({ assert(localEngine != null || localWebSdk != null); - final ABTest abTest = ABTest((localEngine ?? localWebSdk)!, taskName); + final ABTest abTest = ABTest( + localEngine: (localEngine ?? localWebSdk)!, + localEngineHost: localEngineHost, + taskName: taskName, + ); for (int i = 1; i <= runsPerTest; i++) { section('Run #$i'); @@ -292,6 +308,15 @@ ArgParser createArgParser(List taskNames) { 'This path is relative to --local-engine-src-path/out. This option\n' 'is required when running an A/B test (see the --ab option).', ) + ..addOption( + 'local-engine-host', + help: 'Name of a build output within the engine out directory, if you\n' + 'are building Flutter locally. Use this to select a specific\n' + 'version of the engine to use as the host platform if you have built ' + 'multiple engine targets.\n' + 'This path is relative to --local-engine-src-path/out. This option\n' + 'is required when running an A/B test (see the --ab option).', + ) ..addOption( 'local-web-sdk', help: 'Name of a build output within the engine out directory, if you\n' diff --git a/dev/devicelab/lib/command/test.dart b/dev/devicelab/lib/command/test.dart index a98d2b3ecebee..186999403fe3f 100644 --- a/dev/devicelab/lib/command/test.dart +++ b/dev/devicelab/lib/command/test.dart @@ -37,6 +37,15 @@ class TestCommand extends Command { 'This path is relative to --local-engine-src-path/out. This option\n' 'is required when running an A/B test (see the --ab option).', ); + argParser.addOption( + 'local-engine-host', + help: 'Name of a build output within the engine out directory, if you\n' + 'are building Flutter locally. Use this to select a specific\n' + 'version of the engine to use as the host platform if you have built ' + 'multiple engine targets.\n' + 'This path is relative to --local-engine-src-path/out. This option\n' + 'is required when running an A/B test (see the --ab option).', + ); argParser.addOption( 'local-engine-src-path', help: 'Path to your engine src directory, if you are building Flutter\n' @@ -74,6 +83,7 @@ class TestCommand extends Command { deviceId: argResults!['device-id'] as String?, gitBranch: argResults!['git-branch'] as String?, localEngine: argResults!['local-engine'] as String?, + localEngineHost: argResults!['local-engine-host'] as String?, localEngineSrcPath: argResults!['local-engine-src-path'] as String?, luciBuilder: argResults!['luci-builder'] as String?, resultsPath: argResults!['results-file'] as String?, diff --git a/dev/devicelab/lib/framework/ab.dart b/dev/devicelab/lib/framework/ab.dart index e7da55855006e..0e05a130bfbc4 100644 --- a/dev/devicelab/lib/framework/ab.dart +++ b/dev/devicelab/lib/framework/ab.dart @@ -9,6 +9,7 @@ import 'task_result.dart'; const String kBenchmarkTypeKeyName = 'benchmark_type'; const String kBenchmarkVersionKeyName = 'version'; const String kLocalEngineKeyName = 'local_engine'; +const String kLocalEngineHostKeyName = 'local_engine_host'; const String kTaskNameKeyName = 'task_name'; const String kRunStartKeyName = 'run_start'; const String kRunEndKeyName = 'run_end'; @@ -24,13 +25,14 @@ enum FieldJustification { LEFT, RIGHT, CENTER } /// /// See [printSummary] for more. class ABTest { - ABTest(this.localEngine, this.taskName) + ABTest({required this.localEngine, required this.localEngineHost, required this.taskName}) : runStart = DateTime.now(), _aResults = >{}, _bResults = >{}; ABTest.fromJsonMap(Map jsonResults) : localEngine = jsonResults[kLocalEngineKeyName] as String, + localEngineHost = jsonResults[kLocalEngineHostKeyName] as String, taskName = jsonResults[kTaskNameKeyName] as String, runStart = DateTime.parse(jsonResults[kRunStartKeyName] as String), _runEnd = DateTime.parse(jsonResults[kRunEndKeyName] as String), @@ -38,6 +40,7 @@ class ABTest { _bResults = _convertFrom(jsonResults[kBResultsKeyName] as Map); final String localEngine; + final String localEngineHost; final String taskName; final DateTime runStart; DateTime? _runEnd; @@ -86,6 +89,7 @@ class ABTest { kBenchmarkTypeKeyName: kBenchmarkResultsType, kBenchmarkVersionKeyName: kBenchmarkABVersion, kLocalEngineKeyName: localEngine, + kLocalEngineHostKeyName: localEngineHost, kTaskNameKeyName: taskName, kRunStartKeyName: runStart.toIso8601String(), kRunEndKeyName: runEnd!.toIso8601String(), diff --git a/dev/devicelab/lib/framework/framework.dart b/dev/devicelab/lib/framework/framework.dart index 2282907aaf8de..d64fe2e15023e 100644 --- a/dev/devicelab/lib/framework/framework.dart +++ b/dev/devicelab/lib/framework/framework.dart @@ -74,11 +74,13 @@ class _TaskRunner { final bool runFlutterConfig = parameters['runFlutterConfig'] != 'false'; // used by tests to avoid changing the configuration final bool runProcessCleanup = parameters['runProcessCleanup'] != 'false'; final String? localEngine = parameters['localEngine']; + final String? localEngineHost = parameters['localEngineHost']; final TaskResult result = await run( taskTimeout, runProcessCleanup: runProcessCleanup, runFlutterConfig: runFlutterConfig, localEngine: localEngine, + localEngineHost: localEngineHost, ); return ServiceExtensionResponse.result(json.encode(result.toJson())); }); @@ -115,6 +117,7 @@ class _TaskRunner { bool runFlutterConfig = true, bool runProcessCleanup = true, required String? localEngine, + required String? localEngineHost, }) async { try { _taskStarted = true; @@ -144,6 +147,7 @@ class _TaskRunner { '--enable-macos-desktop', '--enable-linux-desktop', if (localEngine != null) ...['--local-engine', localEngine], + if (localEngineHost != null) ...['--local-engine-host', localEngineHost], ], canFail: true); if (configResult != 0) { print('Failed to enable configuration, tasks may not run.'); diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index 88a81d81ba934..5f11b4ffc7684 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -35,6 +35,7 @@ Future runTasks( String? deviceId, String? gitBranch, String? localEngine, + String? localEngineHost, String? localEngineSrcPath, String? luciBuilder, String? resultsPath, @@ -52,6 +53,7 @@ Future runTasks( taskName, deviceId: deviceId, localEngine: localEngine, + localEngineHost: localEngineHost, localEngineSrcPath: localEngineSrcPath, terminateStrayDartProcesses: terminateStrayDartProcesses, silent: silent, @@ -99,6 +101,7 @@ Future rerunTask( String taskName, { String? deviceId, String? localEngine, + String? localEngineHost, String? localEngineSrcPath, bool terminateStrayDartProcesses = false, bool silent = false, @@ -114,6 +117,7 @@ Future rerunTask( taskName, deviceId: deviceId, localEngine: localEngine, + localEngineHost: localEngineHost, localEngineSrcPath: localEngineSrcPath, terminateStrayDartProcesses: terminateStrayDartProcesses, silent: silent, @@ -153,6 +157,7 @@ Future runTask( bool terminateStrayDartProcesses = false, bool silent = false, String? localEngine, + String? localEngineHost, String? localWebSdk, String? localEngineSrcPath, String? deviceId, @@ -182,6 +187,7 @@ Future runTask( '--enable-vm-service=0', // zero causes the system to choose a free port '--no-pause-isolates-on-exit', if (localEngine != null) '-DlocalEngine=$localEngine', + if (localEngineHost != null) '-DlocalEngineHost=$localEngineHost', if (localWebSdk != null) '-DlocalWebSdk=$localWebSdk', if (localEngineSrcPath != null) '-DlocalEngineSrcPath=$localEngineSrcPath', taskExecutable, diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart index 20301e51eebd0..8b97890ac2cab 100644 --- a/dev/devicelab/lib/framework/utils.dart +++ b/dev/devicelab/lib/framework/utils.dart @@ -26,6 +26,14 @@ String? get localEngineFromEnv { return isDefined ? const String.fromEnvironment('localEngine') : null; } +/// The local engine host to use for [flutter] and [evalFlutter], if any. +/// +/// This is set as an environment variable when running the task, see runTask in runner.dart. +String? get localEngineHostFromEnv { + const bool isDefined = bool.hasEnvironment('localEngineHost'); + return isDefined ? const String.fromEnvironment('localEngineHost') : null; +} + /// The local engine source path to use if a local engine is used for [flutter] /// and [evalFlutter]. /// @@ -453,6 +461,7 @@ List _flutterCommandArgs(String command, List options) { 'screenshot', }; final String? localEngine = localEngineFromEnv; + final String? localEngineHost = localEngineHostFromEnv; final String? localEngineSrcPath = localEngineSrcPathFromEnv; final String? localWebSdk = localWebSdkFromEnv; return [ @@ -468,6 +477,7 @@ List _flutterCommandArgs(String command, List options) { hostAgent.dumpDirectory!.path, ], if (localEngine != null) ...['--local-engine', localEngine], + if (localEngineHost != null) ...['--local-engine-host', localEngineHost], if (localEngineSrcPath != null) ...['--local-engine-src-path', localEngineSrcPath], if (localWebSdk != null) ...['--local-web-sdk', localWebSdk], ...options, diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 9416e505b2d1c..989b5dcc00e60 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -1169,6 +1169,7 @@ class PerfTest { await selectedDevice.unlock(); final String deviceId = selectedDevice.deviceId; final String? localEngine = localEngineFromEnv; + final String? localEngineHost = localEngineHostFromEnv; final String? localEngineSrcPath = localEngineSrcPathFromEnv; Future Function()? manifestReset; @@ -1181,6 +1182,10 @@ class PerfTest { try { final List options = [ if (localEngine != null) ...['--local-engine', localEngine], + if (localEngineHost != null) ...[ + '--local-engine-host', + localEngineHost + ], if (localEngineSrcPath != null) ...[ '--local-engine-src-path', localEngineSrcPath diff --git a/dev/devicelab/test/ab_test.dart b/dev/devicelab/test/ab_test.dart index 27e92fd687662..b6ff15b1c2269 100644 --- a/dev/devicelab/test/ab_test.dart +++ b/dev/devicelab/test/ab_test.dart @@ -9,7 +9,7 @@ import 'common.dart'; void main() { test('ABTest', () { - final ABTest ab = ABTest('engine', 'test'); + final ABTest ab = ABTest(localEngine: 'engine', localEngineHost: 'engine', taskName: 'test'); for (int i = 0; i < 5; i++) { final TaskResult aResult = TaskResult.fromJson({ diff --git a/dev/devicelab/test/run_test.dart b/dev/devicelab/test/run_test.dart index a5332dd53c7ad..933c7391a32dd 100644 --- a/dev/devicelab/test/run_test.dart +++ b/dev/devicelab/test/run_test.dart @@ -96,7 +96,7 @@ void main() { final ProcessResult result = await runScript( ['smoke_test_success'], - ['--ab=2', '--local-engine=host_debug_unopt', '--ab-result-file', abResultsFile.path], + ['--ab=2', '--local-engine=host_debug_unopt', '--local-engine-host=host_debug_unopt', '--ab-result-file', abResultsFile.path], ); expect(result.exitCode, 0); diff --git a/dev/devicelab/test/utils_test.dart b/dev/devicelab/test/utils_test.dart index c51ac5afa99dc..f137140abed4b 100644 --- a/dev/devicelab/test/utils_test.dart +++ b/dev/devicelab/test/utils_test.dart @@ -37,6 +37,7 @@ void main() { group('engine environment declarations', () { test('localEngine', () { expect(localEngineFromEnv, null); + expect(localEngineHostFromEnv, null); expect(localEngineSrcPathFromEnv, null); }); }); From 653187668a944f18200c4918ac535476f6f42f11 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 22:12:34 -0400 Subject: [PATCH 0662/1547] Roll Flutter Engine from 18a71c031f5f to 578a8e8aabf6 (1 revision) (#132364) https://github.com/flutter/engine/compare/18a71c031f5f...578a8e8aabf6 2023-08-11 matanlurey@users.noreply.github.com Update `examples/**` to provide `--local-engine-host`. (flutter/engine#44610) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 61bb355ebb406..497a51d8b050e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -18a71c031f5ffd65ebac93228c141ee0ea735d41 +578a8e8aabf65ae52f245dc005671ff34bec8086 From dd4c8d9f099e9b373b876f780a23e3e5ad4c8c17 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 10 Aug 2023 23:33:30 -0400 Subject: [PATCH 0663/1547] Roll Flutter Engine from 578a8e8aabf6 to acd1bc5536ef (1 revision) (#132365) https://github.com/flutter/engine/compare/578a8e8aabf6...acd1bc5536ef 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from b001e0a5e46f to b669a6cd29f7 (1 revision) (flutter/engine#44615) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 497a51d8b050e..85aa8aa78e89c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -578a8e8aabf65ae52f245dc005671ff34bec8086 +acd1bc5536ef6e8d22d98c1d3b8bcb3fdb726a15 From 9d3268b891397c14293d382f58ea142f4630fb83 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 00:55:49 -0400 Subject: [PATCH 0664/1547] Roll Flutter Engine from acd1bc5536ef to da23fb0d9a1d (2 revisions) (#132367) https://github.com/flutter/engine/compare/acd1bc5536ef...da23fb0d9a1d 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from b669a6cd29f7 to 88d5e1daa3ba (1 revision) (flutter/engine#44620) 2023-08-11 skia-flutter-autoroll@skia.org Roll Dart SDK from a2eac00da6b8 to 13317278a6fa (2 revisions) (flutter/engine#44618) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 85aa8aa78e89c..d8567fea46fe6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -acd1bc5536ef6e8d22d98c1d3b8bcb3fdb726a15 +da23fb0d9a1d1aa91e2e4e954b0880aad54b3334 From a491089accd5a0adbf0aa34086144769719dbbec Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 02:37:32 -0400 Subject: [PATCH 0665/1547] Roll Flutter Engine from da23fb0d9a1d to 25afdb9b696d (1 revision) (#132370) https://github.com/flutter/engine/compare/da23fb0d9a1d...25afdb9b696d 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 88d5e1daa3ba to f4080803ee69 (1 revision) (flutter/engine#44622) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d8567fea46fe6..db46dbd5ce8b5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -da23fb0d9a1d1aa91e2e4e954b0880aad54b3334 +25afdb9b696d45cd95aef838b67aa6a15fcc7334 From 496144de94a02f9347b8df74fec4dce77bf38fd7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 05:33:20 -0400 Subject: [PATCH 0666/1547] Roll Flutter Engine from 25afdb9b696d to 4e532b957225 (4 revisions) (#132376) https://github.com/flutter/engine/compare/25afdb9b696d...4e532b957225 2023-08-11 john@johnmccutchan.com Add support for HardwareBuffer backed Android Platform Views under Impeller/GLES (flutter/engine#44617) 2023-08-11 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from konJQZKk2qXc276iA... to v33NyNdr6Y1sKZDze... (flutter/engine#44627) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 41d099099095 to 723df2275d7b (1 revision) (flutter/engine#44626) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from f4080803ee69 to 41d099099095 (2 revisions) (flutter/engine#44624) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from konJQZKk2qXc to v33NyNdr6Y1s If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index db46dbd5ce8b5..358051598d267 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -25afdb9b696d45cd95aef838b67aa6a15fcc7334 +4e532b957225c786ee31128a41ffdb86e31f3ee4 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index fa9bf09790b32..403fe002f3319 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -konJQZKk2qXc276iAIxQgmZOqP26ZATMf3alFxYkhDIC +v33NyNdr6Y1sKZDze0sHWQP_VGO-Qi5XMe2Za3-mg0AC From b062b81b5ba84110610da98eee217ba9e6e78941 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 06:31:40 -0400 Subject: [PATCH 0667/1547] Roll Flutter Engine from 4e532b957225 to 93e8901490e7 (1 revision) (#132381) https://github.com/flutter/engine/compare/4e532b957225...93e8901490e7 2023-08-11 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from hdjihTvRxbNprHI9x... to 7DmdwgtGmIxyejFDl... (flutter/engine#44630) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from hdjihTvRxbNp to 7DmdwgtGmIxy If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 358051598d267..c481e1b122360 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4e532b957225c786ee31128a41ffdb86e31f3ee4 +93e8901490e78c7ba7e319cce4470d9c6478c6dc diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 779baf766ab54..e996b6a24c099 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -hdjihTvRxbNprHI9xGvPV7rtu-TXd1KORZXTW_2t8T4C +7DmdwgtGmIxyejFDlL7-HuTsOjxOTSn_eTIb6vNsAU4C From 9b6945b465a104c7dea41f3042a70781abc39718 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 10:24:25 -0400 Subject: [PATCH 0668/1547] Roll Flutter Engine from 93e8901490e7 to 77dfeea40e10 (1 revision) (#132389) https://github.com/flutter/engine/compare/93e8901490e7...77dfeea40e10 2023-08-11 skia-flutter-autoroll@skia.org Roll Dart SDK from 13317278a6fa to 83f96a990792 (1 revision) (flutter/engine#44633) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c481e1b122360..d0e977c325dbb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -93e8901490e78c7ba7e319cce4470d9c6478c6dc +77dfeea40e10d2d091195419b0d0a83d0ba907e3 From 2605e03b55d1d1f671d8b48679fd4e73789fd30c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 12:38:48 -0400 Subject: [PATCH 0669/1547] Roll Packages from 881c1f552d0f to 9b15c2e6ab30 (4 revisions) (#132391) https://github.com/flutter/packages/compare/881c1f552d0f...9b15c2e6ab30 2023-08-10 tarrinneal@gmail.com [dynamic_layouts] relax layout test to fix tree (flutter/packages#4677) 2023-08-10 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.2 to 2.21.3 (flutter/packages#4664) 2023-08-09 jhy03261997@gmail.com go_router should allow setting requestFocus (flutter/packages#4636) 2023-08-09 10687576+bparrishMines@users.noreply.github.com [webview_flutter_android][webview_flutter_wkwebview] Fixes widget rebuild bug caused by key type (flutter/packages#4667) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index ede5fd9daadee..aee68635d47e9 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -881c1f552d0fbc335e419d95565e16f667d343b7 +9b15c2e6ab30cb259dd42334a95caa1b0e3b7267 From fff08248b37c2cbc47341f32550bdb74efeb22d3 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 11 Aug 2023 13:24:23 -0500 Subject: [PATCH 0670/1547] Disable Xcode Debug tests (#132398) Temporarily removes Xcode debug tests. Xcode tests are currently failing in CI for some infra-related issues. I have a fix for it (https://github.com/flutter/flutter/pull/132318) that I confirmed worked in presubmit, but I think the logic is better suited to live in recipes. However, it's going to be a bit of a learning curve to update recipes and might take me a couple days so disabling them in the meantime. Tracking issue to readd when ready: https://github.com/flutter/flutter/issues/132309 --- .ci.yaml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 7f123a728d599..d01625198394f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3685,16 +3685,6 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery_ios__start_up - - name: Mac_ios flutter_gallery_ios__start_up_xcode_debug - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "ios", "mac"] - task_name: flutter_gallery_ios__start_up_xcode_debug - bringup: true - - name: Mac_ios flutter_view_ios__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -3762,16 +3752,6 @@ targets: ["devicelab", "ios", "mac"] task_name: integration_ui_ios_driver - - name: Mac_ios integration_ui_ios_driver_xcode_debug - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "ios", "mac"] - task_name: integration_ui_ios_driver_xcode_debug - bringup: true - - name: Mac_ios integration_ui_ios_frame_number recipe: devicelab/devicelab_drone presubmit: false From d23fb23df822e882bdf0f25468359a3f2cae2b02 Mon Sep 17 00:00:00 2001 From: Nate Bosch Date: Fri, 11 Aug 2023 12:46:53 -0700 Subject: [PATCH 0671/1547] Send test message channel from the test frame (#131881) Towards https://github.com/dart-lang/test/issues/2065 The flutter test runner uses the copy of `host.dart.js` from the copy of `package:test` that surfaces in the pub solve for `flutter_tool`. This copy has been updated to allow either the old pattern of communication, or this new pattern. The new pattern removes an extra hop and use of the frame `window.onMessage` messages. --- .../flutter_tools/lib/src/web/bootstrap.dart | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/packages/flutter_tools/lib/src/web/bootstrap.dart b/packages/flutter_tools/lib/src/web/bootstrap.dart index 814a9a680902a..7b44bec7494a3 100644 --- a/packages/flutter_tools/lib/src/web/bootstrap.dart +++ b/packages/flutter_tools/lib/src/web/bootstrap.dart @@ -247,25 +247,16 @@ String generateTestEntrypoint({ StreamChannel serializeSuite(Function getMain(), {bool hidePrints = true}) => RemoteListener.start(getMain, hidePrints: hidePrints); StreamChannel postMessageChannel() { - var controller = StreamChannelController(sync: true); - window.onMessage.firstWhere((message) { - return message.origin == window.location.origin && message.data == "port"; - }).then((message) { - var port = message.ports.first; - var portSubscription = port.onMessage.listen((message) { - controller.local.sink.add(message.data); - }); - controller.local.stream.listen((data) { - port.postMessage({"data": data}); - }, onDone: () { - port.postMessage({"event": "done"}); - portSubscription.cancel(); - }); + var controller = StreamChannelController(sync: true); + var channel = MessageChannel(); + window.parent!.postMessage('port', window.location.origin, [channel.port2]); + + var portSubscription = channel.port1.onMessage.listen((message) { + controller.local.sink.add(message.data); }); - context['parent'].callMethod('postMessage', [ - JsObject.jsify({"href": window.location.href, "ready": true}), - window.location.origin, - ]); + controller.local.stream + .listen(channel.port1.postMessage, onDone: portSubscription.cancel); + return controller.foreign; } '''; From b3096225e0ebc005ed678fa7a9f03164caba1d73 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 16:57:39 -0400 Subject: [PATCH 0672/1547] Roll Flutter Engine from 77dfeea40e10 to 622ded929968 (2 revisions) (#132397) https://github.com/flutter/engine/compare/77dfeea40e10...622ded929968 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 416789a5e761 to cfb9844091fa (1 revision) (flutter/engine#44638) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 723df2275d7b to 416789a5e761 (1 revision) (flutter/engine#44637) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d0e977c325dbb..4e001e4b8456e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -77dfeea40e10d2d091195419b0d0a83d0ba907e3 +622ded92996879c7d5cf7c8a40a5a68a9f843e80 From 457d00449dd76e1166d1295b027487773236bb04 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Fri, 11 Aug 2023 14:08:39 -0700 Subject: [PATCH 0673/1547] Add double click and double click + drag gestures to SelectionArea (#124817) Adds double click to select a word. Adds double click + drag to select word by word. https://user-images.githubusercontent.com/948037/234363577-941c36bc-ac42-4b7f-84aa-26b106c9ff05.mov Partially fixes #104552 --- .../flutter/lib/src/rendering/paragraph.dart | 234 +++++++++++++++- .../flutter/lib/src/rendering/selection.dart | 38 ++- .../flutter/lib/src/widgets/scrollable.dart | 10 +- .../lib/src/widgets/selectable_region.dart | 116 +++++--- .../test/material/selection_area_test.dart | 1 + .../widgets/scrollable_selection_test.dart | 84 ++++++ .../test/widgets/selectable_region_test.dart | 252 +++++++++++++++++- 7 files changed, 685 insertions(+), 50 deletions(-) diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 345bc75c340ca..f1b252b032c0d 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -18,6 +18,9 @@ import 'layout_helper.dart'; import 'object.dart'; import 'selection.dart'; +/// The start and end positions for a word. +typedef _WordBoundaryRecord = ({TextPosition wordStart, TextPosition wordEnd}); + const String _kEllipsis = '\u2026'; /// Used by the [RenderParagraph] to map its rendering children to their @@ -1329,6 +1332,8 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM TextPosition? _textSelectionStart; TextPosition? _textSelectionEnd; + bool _selectableContainsOriginWord = false; + LayerLink? _startHandleLayerLink; LayerLink? _endHandleLayerLink; @@ -1397,7 +1402,17 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM case SelectionEventType.startEdgeUpdate: case SelectionEventType.endEdgeUpdate: final SelectionEdgeUpdateEvent edgeUpdate = event as SelectionEdgeUpdateEvent; - result = _updateSelectionEdge(edgeUpdate.globalPosition, isEnd: edgeUpdate.type == SelectionEventType.endEdgeUpdate); + final TextGranularity granularity = event.granularity; + + switch (granularity) { + case TextGranularity.character: + result = _updateSelectionEdge(edgeUpdate.globalPosition, isEnd: edgeUpdate.type == SelectionEventType.endEdgeUpdate); + case TextGranularity.word: + result = _updateSelectionEdgeByWord(edgeUpdate.globalPosition, isEnd: edgeUpdate.type == SelectionEventType.endEdgeUpdate); + case TextGranularity.document: + case TextGranularity.line: + assert(false, 'Moving the selection edge by line or document is not supported.'); + } case SelectionEventType.clear: result = _handleClearSelection(); case SelectionEventType.selectAll: @@ -1474,6 +1489,199 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM return SelectionUtils.getResultBasedOnRect(_rect, localPosition); } + TextPosition _closestWordBoundary( + _WordBoundaryRecord wordBoundary, + TextPosition position, + ) { + final int differenceA = (position.offset - wordBoundary.wordStart.offset).abs(); + final int differenceB = (position.offset - wordBoundary.wordEnd.offset).abs(); + return differenceA < differenceB ? wordBoundary.wordStart : wordBoundary.wordEnd; + } + + TextPosition _updateSelectionStartEdgeByWord( + _WordBoundaryRecord? wordBoundary, + TextPosition position, + TextPosition? existingSelectionStart, + TextPosition? existingSelectionEnd, + ) { + TextPosition? targetPosition; + if (wordBoundary != null) { + assert(wordBoundary.wordStart.offset >= range.start && wordBoundary.wordEnd.offset <= range.end); + if (_selectableContainsOriginWord && existingSelectionStart != null && existingSelectionEnd != null) { + final bool isSamePosition = position.offset == existingSelectionEnd.offset; + final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; + final bool shouldSwapEdges = !isSamePosition && (isSelectionInverted != (position.offset > existingSelectionEnd.offset)); + if (shouldSwapEdges) { + if (position.offset < existingSelectionEnd.offset) { + targetPosition = wordBoundary.wordStart; + } else { + targetPosition = wordBoundary.wordEnd; + } + // When the selection is inverted by the new position it is necessary to + // swap the start edge (moving edge) with the end edge (static edge) to + // maintain the origin word within the selection. + final _WordBoundaryRecord localWordBoundary = _getWordBoundaryAtPosition(existingSelectionEnd); + assert(localWordBoundary.wordStart.offset >= range.start && localWordBoundary.wordEnd.offset <= range.end); + _setSelectionPosition(existingSelectionEnd.offset == localWordBoundary.wordStart.offset ? localWordBoundary.wordEnd : localWordBoundary.wordStart, isEnd: true); + } else { + if (position.offset < existingSelectionEnd.offset) { + targetPosition = wordBoundary.wordStart; + } else if (position.offset > existingSelectionEnd.offset) { + targetPosition = wordBoundary.wordEnd; + } else { + // Keep the origin word in bounds when position is at the static edge. + targetPosition = existingSelectionStart; + } + } + } else { + if (existingSelectionEnd != null) { + // If the end edge exists and the start edge is being moved, then the + // start edge is moved to encompass the entire word at the new position. + if (position.offset < existingSelectionEnd.offset) { + targetPosition = wordBoundary.wordStart; + } else { + targetPosition = wordBoundary.wordEnd; + } + } else { + // Move the start edge to the closest word boundary. + targetPosition = _closestWordBoundary(wordBoundary, position); + } + } + } else { + // The position is not contained within the current rect. The targetPosition + // will either be at the end or beginning of the current rect. See [SelectionUtils.adjustDragOffset] + // for a more in depth explanation on this adjustment. + if (_selectableContainsOriginWord && existingSelectionStart != null && existingSelectionEnd != null) { + // When the selection is inverted by the new position it is necessary to + // swap the start edge (moving edge) with the end edge (static edge) to + // maintain the origin word within the selection. + final bool isSamePosition = position.offset == existingSelectionEnd.offset; + final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; + final bool shouldSwapEdges = !isSamePosition && (isSelectionInverted != (position.offset > existingSelectionEnd.offset)); + + if (shouldSwapEdges) { + final _WordBoundaryRecord localWordBoundary = _getWordBoundaryAtPosition(existingSelectionEnd); + assert(localWordBoundary.wordStart.offset >= range.start && localWordBoundary.wordEnd.offset <= range.end); + _setSelectionPosition(isSelectionInverted ? localWordBoundary.wordEnd : localWordBoundary.wordStart, isEnd: true); + } + } + } + return targetPosition ?? position; + } + + TextPosition _updateSelectionEndEdgeByWord( + _WordBoundaryRecord? wordBoundary, + TextPosition position, + TextPosition? existingSelectionStart, + TextPosition? existingSelectionEnd, + ) { + TextPosition? targetPosition; + if (wordBoundary != null) { + assert(wordBoundary.wordStart.offset >= range.start && wordBoundary.wordEnd.offset <= range.end); + if (_selectableContainsOriginWord && existingSelectionStart != null && existingSelectionEnd != null) { + final bool isSamePosition = position.offset == existingSelectionStart.offset; + final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; + final bool shouldSwapEdges = !isSamePosition && (isSelectionInverted != (position.offset < existingSelectionStart.offset)); + if (shouldSwapEdges) { + if (position.offset < existingSelectionStart.offset) { + targetPosition = wordBoundary.wordStart; + } else { + targetPosition = wordBoundary.wordEnd; + } + // When the selection is inverted by the new position it is necessary to + // swap the end edge (moving edge) with the start edge (static edge) to + // maintain the origin word within the selection. + final _WordBoundaryRecord localWordBoundary = _getWordBoundaryAtPosition(existingSelectionStart); + assert(localWordBoundary.wordStart.offset >= range.start && localWordBoundary.wordEnd.offset <= range.end); + _setSelectionPosition(existingSelectionStart.offset == localWordBoundary.wordStart.offset ? localWordBoundary.wordEnd : localWordBoundary.wordStart, isEnd: false); + } else { + if (position.offset < existingSelectionStart.offset) { + targetPosition = wordBoundary.wordStart; + } else if (position.offset > existingSelectionStart.offset) { + targetPosition = wordBoundary.wordEnd; + } else { + // Keep the origin word in bounds when position is at the static edge. + targetPosition = existingSelectionEnd; + } + } + } else { + if (existingSelectionStart != null) { + // If the start edge exists and the end edge is being moved, then the + // end edge is moved to encompass the entire word at the new position. + if (position.offset < existingSelectionStart.offset) { + targetPosition = wordBoundary.wordStart; + } else { + targetPosition = wordBoundary.wordEnd; + } + } else { + // Move the end edge to the closest word boundary. + targetPosition = _closestWordBoundary(wordBoundary, position); + } + } + } else { + // The position is not contained within the current rect. The targetPosition + // will either be at the end or beginning of the current rect. See [SelectionUtils.adjustDragOffset] + // for a more in depth explanation on this adjustment. + if (_selectableContainsOriginWord && existingSelectionStart != null && existingSelectionEnd != null) { + // When the selection is inverted by the new position it is necessary to + // swap the end edge (moving edge) with the start edge (static edge) to + // maintain the origin word within the selection. + final bool isSamePosition = position.offset == existingSelectionStart.offset; + final bool isSelectionInverted = existingSelectionStart.offset > existingSelectionEnd.offset; + final bool shouldSwapEdges = isSelectionInverted != (position.offset < existingSelectionStart.offset) || isSamePosition; + if (shouldSwapEdges) { + final _WordBoundaryRecord localWordBoundary = _getWordBoundaryAtPosition(existingSelectionStart); + assert(localWordBoundary.wordStart.offset >= range.start && localWordBoundary.wordEnd.offset <= range.end); + _setSelectionPosition(isSelectionInverted ? localWordBoundary.wordStart : localWordBoundary.wordEnd, isEnd: false); + } + } + } + return targetPosition ?? position; + } + + SelectionResult _updateSelectionEdgeByWord(Offset globalPosition, {required bool isEnd}) { + // When the start/end edges are swapped, i.e. the start is after the end, and + // the scrollable synthesizes an event for the opposite edge, this will potentially + // move the opposite edge outside of the origin word boundary and we are unable to recover. + final TextPosition? existingSelectionStart = _textSelectionStart; + final TextPosition? existingSelectionEnd = _textSelectionEnd; + + _setSelectionPosition(null, isEnd: isEnd); + final Matrix4 transform = paragraph.getTransformTo(null); + transform.invert(); + final Offset localPosition = MatrixUtils.transformPoint(transform, globalPosition); + if (_rect.isEmpty) { + return SelectionUtils.getResultBasedOnRect(_rect, localPosition); + } + final Offset adjustedOffset = SelectionUtils.adjustDragOffset( + _rect, + localPosition, + direction: paragraph.textDirection, + ); + + final TextPosition position = paragraph.getPositionForOffset(adjustedOffset); + // Check if the original local position is within the rect, if it is not then + // we do not need to look up the word boundary for that position. This is to + // maintain a selectables selection collapsed at 0 when the local position is + // not located inside its rect. + final _WordBoundaryRecord? wordBoundary = !_rect.contains(localPosition) ? null : _getWordBoundaryAtPosition(position); + final TextPosition targetPosition = _clampTextPosition(isEnd ? _updateSelectionEndEdgeByWord(wordBoundary, position, existingSelectionStart, existingSelectionEnd) : _updateSelectionStartEdgeByWord(wordBoundary, position, existingSelectionStart, existingSelectionEnd)); + + _setSelectionPosition(targetPosition, isEnd: isEnd); + if (targetPosition.offset == range.end) { + return SelectionResult.next; + } + + if (targetPosition.offset == range.start) { + return SelectionResult.previous; + } + // TODO(chunhtai): The geometry information should not be used to determine + // selection result. This is a workaround to RenderParagraph, where it does + // not have a way to get accurate text length if its text is truncated due to + // layout constraint. + return SelectionUtils.getResultBasedOnRect(_rect, localPosition); + } + TextPosition _clampTextPosition(TextPosition position) { // Affinity of range.end is upstream. if (position.offset > range.end || @@ -1497,6 +1705,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM SelectionResult _handleClearSelection() { _textSelectionStart = null; _textSelectionEnd = null; + _selectableContainsOriginWord = false; return SelectionResult.none; } @@ -1507,20 +1716,29 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM } SelectionResult _handleSelectWord(Offset globalPosition) { + _selectableContainsOriginWord = true; + final TextPosition position = paragraph.getPositionForOffset(paragraph.globalToLocal(globalPosition)); if (_positionIsWithinCurrentSelection(position)) { return SelectionResult.end; } - final TextRange word = paragraph.getWordBoundary(position); - assert(word.isNormalized); - if (word.start < range.start && word.end < range.start) { + final _WordBoundaryRecord wordBoundary = _getWordBoundaryAtPosition(position); + if (wordBoundary.wordStart.offset < range.start && wordBoundary.wordEnd.offset < range.start) { return SelectionResult.previous; - } else if (word.start > range.end && word.end > range.end) { + } else if (wordBoundary.wordStart.offset > range.end && wordBoundary.wordEnd.offset > range.end) { return SelectionResult.next; } // Fragments are separated by placeholder span, the word boundary shouldn't // expand across fragments. - assert(word.start >= range.start && word.end <= range.end); + assert(wordBoundary.wordStart.offset >= range.start && wordBoundary.wordEnd.offset <= range.end); + _textSelectionStart = wordBoundary.wordStart; + _textSelectionEnd = wordBoundary.wordEnd; + return SelectionResult.end; + } + + _WordBoundaryRecord _getWordBoundaryAtPosition(TextPosition position) { + final TextRange word = paragraph.getWordBoundary(position); + assert(word.isNormalized); late TextPosition start; late TextPosition end; if (position.offset > word.end) { @@ -1529,9 +1747,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM start = TextPosition(offset: word.start); end = TextPosition(offset: word.end, affinity: TextAffinity.upstream); } - _textSelectionStart = start; - _textSelectionEnd = end; - return SelectionResult.end; + return (wordStart: start, wordEnd: end); } SelectionResult _handleDirectionallyExtendSelection(double horizontalBaseline, bool isExtent, SelectionExtendDirection movement) { diff --git a/packages/flutter/lib/src/rendering/selection.dart b/packages/flutter/lib/src/rendering/selection.dart index beaf5a02700cf..303a5d71654b1 100644 --- a/packages/flutter/lib/src/rendering/selection.dart +++ b/packages/flutter/lib/src/rendering/selection.dart @@ -375,26 +375,44 @@ class SelectWordSelectionEvent extends SelectionEvent { /// /// The [globalPosition] contains the new offset of the edge. /// -/// This event is dispatched when the framework detects [DragStartDetails] in +/// The [granularity] contains the granularity that the selection edge should move by. +/// Only [TextGranularity.character] and [TextGranularity.word] are currently supported. +/// +/// This event is dispatched when the framework detects [TapDragStartDetails] in /// [SelectionArea]'s gesture recognizers for mouse devices, or the selection /// handles have been dragged to new locations. class SelectionEdgeUpdateEvent extends SelectionEvent { /// Creates a selection start edge update event. /// /// The [globalPosition] contains the location of the selection start edge. + /// + /// The [granularity] contains the granularity which the selection edge should move by. + /// This value defaults to [TextGranularity.character]. const SelectionEdgeUpdateEvent.forStart({ - required this.globalPosition - }) : super._(SelectionEventType.startEdgeUpdate); + required this.globalPosition, + TextGranularity? granularity + }) : granularity = granularity ?? TextGranularity.character, super._(SelectionEventType.startEdgeUpdate); /// Creates a selection end edge update event. /// /// The [globalPosition] contains the new location of the selection end edge. + /// + /// The [granularity] contains the granularity which the selection edge should move by. + /// This value defaults to [TextGranularity.character]. const SelectionEdgeUpdateEvent.forEnd({ - required this.globalPosition - }) : super._(SelectionEventType.endEdgeUpdate); + required this.globalPosition, + TextGranularity? granularity + }) : granularity = granularity ?? TextGranularity.character, super._(SelectionEventType.endEdgeUpdate); /// The new location of the selection edge. final Offset globalPosition; + + /// The granularity for which the selection moves. + /// + /// Only [TextGranularity.character] and [TextGranularity.word] are currently supported. + /// + /// Defaults to [TextGranularity.character]. + final TextGranularity granularity; } /// Extends the start or end of the selection by a given [TextGranularity]. @@ -686,7 +704,7 @@ class SelectionGeometry { /// The geometry information of a selection point. @immutable -class SelectionPoint { +class SelectionPoint with Diagnosticable { /// Creates a selection point object. /// /// All properties must not be null. @@ -730,6 +748,14 @@ class SelectionPoint { handleType, ); } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('localPosition', localPosition)); + properties.add(DoubleProperty('lineHeight', lineHeight)); + properties.add(EnumProperty('handleType', handleType)); + } } /// The type of selection handle to be displayed. diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index 1331de1d57de0..dfd3a80a6781f 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -1177,11 +1177,11 @@ class _ScrollableSelectionContainerDelegate extends MultiSelectableSelectionCont if (event.type == SelectionEventType.endEdgeUpdate) { _currentDragEndRelatedToOrigin = _inferPositionRelatedToOrigin(event.globalPosition); final Offset endOffset = _currentDragEndRelatedToOrigin!.translate(-deltaToOrigin.dx, -deltaToOrigin.dy); - event = SelectionEdgeUpdateEvent.forEnd(globalPosition: endOffset); + event = SelectionEdgeUpdateEvent.forEnd(globalPosition: endOffset, granularity: event.granularity); } else { _currentDragStartRelatedToOrigin = _inferPositionRelatedToOrigin(event.globalPosition); final Offset startOffset = _currentDragStartRelatedToOrigin!.translate(-deltaToOrigin.dx, -deltaToOrigin.dy); - event = SelectionEdgeUpdateEvent.forStart(globalPosition: startOffset); + event = SelectionEdgeUpdateEvent.forStart(globalPosition: startOffset, granularity: event.granularity); } final SelectionResult result = super.handleSelectionEdgeUpdate(event); @@ -1430,6 +1430,9 @@ class _ScrollableSelectionContainerDelegate extends MultiSelectableSelectionCont final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); final Offset startOffset = _currentDragStartRelatedToOrigin!.translate(-deltaToOrigin.dx, -deltaToOrigin.dy); selectable.dispatchSelectionEvent(SelectionEdgeUpdateEvent.forStart(globalPosition: startOffset)); + // Make sure we track that we have synthesized a start event for this selectable, + // so we don't synthesize events unnecessarily. + _selectableStartEdgeUpdateRecords[selectable] = state.position.pixels; } final double? previousEndRecord = _selectableEndEdgeUpdateRecords[selectable]; if (_currentDragEndRelatedToOrigin != null && @@ -1438,6 +1441,9 @@ class _ScrollableSelectionContainerDelegate extends MultiSelectableSelectionCont final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); final Offset endOffset = _currentDragEndRelatedToOrigin!.translate(-deltaToOrigin.dx, -deltaToOrigin.dy); selectable.dispatchSelectionEvent(SelectionEdgeUpdateEvent.forEnd(globalPosition: endOffset)); + // Make sure we track that we have synthesized an end event for this selectable, + // so we don't synthesize events unnecessarily. + _selectableEndEdgeUpdateRecords[selectable] = state.position.pixels; } } diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 568cb645073eb..33ca404dceb32 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -422,15 +422,46 @@ class SelectableRegionState extends State with TextSelectionDe // gestures. + // Converts the details.consecutiveTapCount from a TapAndDrag*Details object, + // which can grow to be infinitely large, to a value between 1 and the supported + // max consecutive tap count. The value that the raw count is converted to is + // based on the default observed behavior on the native platforms. + // + // This method should be used in all instances when details.consecutiveTapCount + // would be used. + static int _getEffectiveConsecutiveTapCount(int rawCount) { + const int maxConsecutiveTap = 2; + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + // From observation, these platforms reset their tap count to 0 when + // the number of consecutive taps exceeds the max consecutive tap supported. + // For example on Debian Linux with GTK, when going past a triple click, + // on the fourth click the selection is moved to the precise click + // position, on the fifth click the word at the position is selected, and + // on the sixth click the paragraph at the position is selected. + return rawCount <= maxConsecutiveTap ? rawCount : (rawCount % maxConsecutiveTap == 0 ? maxConsecutiveTap : rawCount % maxConsecutiveTap); + case TargetPlatform.iOS: + case TargetPlatform.macOS: + case TargetPlatform.windows: + // From observation, these platforms either hold their tap count at the max + // consecutive tap supported. For example on macOS, when going past a triple + // click, the selection should be retained at the paragraph that was first + // selected on triple click. + return min(rawCount, maxConsecutiveTap); + } + } + void _initMouseGestureRecognizer() { - _gestureRecognizers[PanGestureRecognizer] = GestureRecognizerFactoryWithHandlers( - () => PanGestureRecognizer(debugOwner:this, supportedDevices: { PointerDeviceKind.mouse }), - (PanGestureRecognizer instance) { + _gestureRecognizers[TapAndPanGestureRecognizer] = GestureRecognizerFactoryWithHandlers( + () => TapAndPanGestureRecognizer(debugOwner:this, supportedDevices: { PointerDeviceKind.mouse }), + (TapAndPanGestureRecognizer instance) { instance - ..onDown = _startNewMouseSelectionGesture - ..onStart = _handleMouseDragStart - ..onUpdate = _handleMouseDragUpdate - ..onEnd = _handleMouseDragEnd + ..onTapDown = _startNewMouseSelectionGesture + ..onDragStart = _handleMouseDragStart + ..onDragUpdate = _handleMouseDragUpdate + ..onDragEnd = _handleMouseDragEnd ..onCancel = _clearSelection ..dragStartBehavior = DragStartBehavior.down; }, @@ -449,18 +480,36 @@ class SelectableRegionState extends State with TextSelectionDe ); } - void _startNewMouseSelectionGesture(DragDownDetails details) { - widget.focusNode.requestFocus(); - hideToolbar(); - _clearSelection(); + void _startNewMouseSelectionGesture(TapDragDownDetails details) { + switch (_getEffectiveConsecutiveTapCount(details.consecutiveTapCount)) { + case 1: + widget.focusNode.requestFocus(); + hideToolbar(); + _clearSelection(); + case 2: + _selectWordAt(offset: details.globalPosition); + } } - void _handleMouseDragStart(DragStartDetails details) { - _selectStartTo(offset: details.globalPosition); + void _handleMouseDragStart(TapDragStartDetails details) { + switch (_getEffectiveConsecutiveTapCount(details.consecutiveTapCount)) { + case 1: + _selectStartTo(offset: details.globalPosition); + } } - void _handleMouseDragUpdate(DragUpdateDetails details) { - _selectEndTo(offset: details.globalPosition, continuous: true); + void _handleMouseDragUpdate(TapDragUpdateDetails details) { + switch (_getEffectiveConsecutiveTapCount(details.consecutiveTapCount)) { + case 1: + _selectEndTo(offset: details.globalPosition, continuous: true); + case 2: + _selectEndTo(offset: details.globalPosition, continuous: true, textGranularity: TextGranularity.word); + } + } + + void _handleMouseDragEnd(TapDragEndDetails details) { + _finalizeSelection(); + _updateSelectedContentIfNeeded(); } void _updateSelectedContentIfNeeded() { @@ -470,11 +519,6 @@ class SelectableRegionState extends State with TextSelectionDe } } - void _handleMouseDragEnd(DragEndDetails details) { - _finalizeSelection(); - _updateSelectedContentIfNeeded(); - } - void _handleTouchLongPressStart(LongPressStartDetails details) { HapticFeedback.selectionClick(); widget.focusNode.requestFocus(); @@ -563,7 +607,7 @@ class SelectableRegionState extends State with TextSelectionDe /// If the selectable subtree returns a [SelectionResult.pending], this method /// continues to send [SelectionEdgeUpdateEvent]s every frame until the result /// is not pending or users end their gestures. - void _triggerSelectionEndEdgeUpdate() { + void _triggerSelectionEndEdgeUpdate({TextGranularity? textGranularity}) { // This method can be called when the drag is not in progress. This can // happen if the child scrollable returns SelectionResult.pending, and // the selection area scheduled a selection update for the next frame, but @@ -572,14 +616,14 @@ class SelectableRegionState extends State with TextSelectionDe return; } if (_selectable?.dispatchSelectionEvent( - SelectionEdgeUpdateEvent.forEnd(globalPosition: _selectionEndPosition!)) == SelectionResult.pending) { + SelectionEdgeUpdateEvent.forEnd(globalPosition: _selectionEndPosition!, granularity: textGranularity)) == SelectionResult.pending) { _scheduledSelectionEndEdgeUpdate = true; SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { if (!_scheduledSelectionEndEdgeUpdate) { return; } _scheduledSelectionEndEdgeUpdate = false; - _triggerSelectionEndEdgeUpdate(); + _triggerSelectionEndEdgeUpdate(textGranularity: textGranularity); }); return; } @@ -617,7 +661,7 @@ class SelectableRegionState extends State with TextSelectionDe /// If the selectable subtree returns a [SelectionResult.pending], this method /// continues to send [SelectionEdgeUpdateEvent]s every frame until the result /// is not pending or users end their gestures. - void _triggerSelectionStartEdgeUpdate() { + void _triggerSelectionStartEdgeUpdate({TextGranularity? textGranularity}) { // This method can be called when the drag is not in progress. This can // happen if the child scrollable returns SelectionResult.pending, and // the selection area scheduled a selection update for the next frame, but @@ -626,14 +670,14 @@ class SelectableRegionState extends State with TextSelectionDe return; } if (_selectable?.dispatchSelectionEvent( - SelectionEdgeUpdateEvent.forStart(globalPosition: _selectionStartPosition!)) == SelectionResult.pending) { + SelectionEdgeUpdateEvent.forStart(globalPosition: _selectionStartPosition!, granularity: textGranularity)) == SelectionResult.pending) { _scheduledSelectionStartEdgeUpdate = true; SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { if (!_scheduledSelectionStartEdgeUpdate) { return; } _scheduledSelectionStartEdgeUpdate = false; - _triggerSelectionStartEdgeUpdate(); + _triggerSelectionStartEdgeUpdate(textGranularity: textGranularity); }); return; } @@ -845,20 +889,24 @@ class SelectableRegionState extends State with TextSelectionDe /// /// The `offset` is in global coordinates. /// + /// Provide the `textGranularity` if the selection should not move by the default + /// [TextGranularity.character]. Only [TextGranularity.character] and + /// [TextGranularity.word] are currently supported. + /// /// See also: /// * [_selectStartTo], which sets or updates selection start edge. /// * [_finalizeSelection], which stops the `continuous` updates. /// * [_clearSelection], which clear the ongoing selection. /// * [_selectWordAt], which selects a whole word at the location. /// * [selectAll], which selects the entire content. - void _selectEndTo({required Offset offset, bool continuous = false}) { + void _selectEndTo({required Offset offset, bool continuous = false, TextGranularity? textGranularity}) { if (!continuous) { - _selectable?.dispatchSelectionEvent(SelectionEdgeUpdateEvent.forEnd(globalPosition: offset)); + _selectable?.dispatchSelectionEvent(SelectionEdgeUpdateEvent.forEnd(globalPosition: offset, granularity: textGranularity)); return; } if (_selectionEndPosition != offset) { _selectionEndPosition = offset; - _triggerSelectionEndEdgeUpdate(); + _triggerSelectionEndEdgeUpdate(textGranularity: textGranularity); } } @@ -880,20 +928,24 @@ class SelectableRegionState extends State with TextSelectionDe /// /// The `offset` is in global coordinates. /// + /// Provide the `textGranularity` if the selection should not move by the default + /// [TextGranularity.character]. Only [TextGranularity.character] and + /// [TextGranularity.word] are currently supported. + /// /// See also: /// * [_selectEndTo], which sets or updates selection end edge. /// * [_finalizeSelection], which stops the `continuous` updates. /// * [_clearSelection], which clear the ongoing selection. /// * [_selectWordAt], which selects a whole word at the location. /// * [selectAll], which selects the entire content. - void _selectStartTo({required Offset offset, bool continuous = false}) { + void _selectStartTo({required Offset offset, bool continuous = false, TextGranularity? textGranularity}) { if (!continuous) { - _selectable?.dispatchSelectionEvent(SelectionEdgeUpdateEvent.forStart(globalPosition: offset)); + _selectable?.dispatchSelectionEvent(SelectionEdgeUpdateEvent.forStart(globalPosition: offset, granularity: textGranularity)); return; } if (_selectionStartPosition != offset) { _selectionStartPosition = offset; - _triggerSelectionStartEdgeUpdate(); + _triggerSelectionStartEdgeUpdate(textGranularity: textGranularity); } } diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index c5d110b1ad9a8..00211f70f5de6 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -157,6 +157,7 @@ void main() { // Backwards selection. await gesture.down(textOffsetToPosition(paragraph, 3)); + await tester.pumpAndSettle(); expect(content, isNull); await gesture.moveTo(textOffsetToPosition(paragraph, 0)); await gesture.up(); diff --git a/packages/flutter/test/widgets/scrollable_selection_test.dart b/packages/flutter/test/widgets/scrollable_selection_test.dart index 54a07e2f487e2..ea3fa2843a3e0 100644 --- a/packages/flutter/test/widgets/scrollable_selection_test.dart +++ b/packages/flutter/test/widgets/scrollable_selection_test.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; @@ -106,6 +107,89 @@ void main() { await gesture.up(); }); + testWidgets('mouse can select multiple widgets on double-click drag', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: SelectionArea( + selectionControls: materialTextSelectionControls, + child: ListView.builder( + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + return Text('Item $index'); + }, + ), + ), + )); + await tester.pumpAndSettle(); + + final RenderParagraph paragraph1 = tester.renderObject(find.descendant(of: find.text('Item 0'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 2), kind: ui.PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.up(); + await tester.pump(); + await gesture.down(textOffsetToPosition(paragraph1, 2)); + await tester.pumpAndSettle(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); + + await gesture.moveTo(textOffsetToPosition(paragraph1, 4)); + await tester.pump(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 5)); + + final RenderParagraph paragraph2 = tester.renderObject(find.descendant(of: find.text('Item 1'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph2, 4)); + // Should select the rest of paragraph 1. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 5)); + + final RenderParagraph paragraph3 = tester.renderObject(find.descendant(of: find.text('Item 3'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph3, 3)); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); + + await gesture.up(); + }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + + testWidgets('mouse can select multiple widgets on double-click drag - horizontal', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: SelectionArea( + selectionControls: materialTextSelectionControls, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: 100, + itemBuilder: (BuildContext context, int index) { + return Text('Item $index'); + }, + ), + ), + )); + await tester.pumpAndSettle(); + + final RenderParagraph paragraph1 = tester.renderObject(find.descendant(of: find.text('Item 0'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 2), kind: ui.PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(textOffsetToPosition(paragraph1, 2)); + await tester.pumpAndSettle(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); + + await gesture.moveTo(textOffsetToPosition(paragraph1, 4)); + await tester.pump(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 5)); + + final RenderParagraph paragraph2 = tester.renderObject(find.descendant(of: find.text('Item 1'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph2, 5) + const Offset(0, 5)); + // Should select the rest of paragraph 1. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + + await gesture.up(); + }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + testWidgets('select to scroll forward', (WidgetTester tester) async { final ScrollController controller = ScrollController(); await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 7d9fbd174c9fc..f70a046a5c7dd 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -37,7 +37,7 @@ void main() { }); group('SelectableRegion', () { - testWidgets('mouse selection sends correct events', (WidgetTester tester) async { + testWidgets('mouse selection single click sends correct events', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -53,6 +53,7 @@ void main() { final RenderSelectionSpy renderSelectionSpy = tester.renderObject(find.byKey(spy)); final TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0), kind: PointerDeviceKind.mouse); addTearDown(gesture.removePointer); + await tester.pumpAndSettle(); renderSelectionSpy.events.clear(); await gesture.moveTo(const Offset(200.0, 100.0)); @@ -74,6 +75,34 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/102410. + testWidgets('mouse double click sends select-word event', (WidgetTester tester) async { + final UniqueKey spy = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: SelectionSpy(key: spy), + ), + ) + ); + + final RenderSelectionSpy renderSelectionSpy = tester.renderObject(find.byKey(spy)); + final TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + renderSelectionSpy.events.clear(); + await gesture.down(const Offset(200.0, 200.0)); + await tester.pump(); + await gesture.up(); + expect(renderSelectionSpy.events.length, 1); + expect(renderSelectionSpy.events[0], isA()); + final SelectWordSelectionEvent selectionEvent = renderSelectionSpy.events[0] as SelectWordSelectionEvent; + expect(selectionEvent.globalPosition, const Offset(200.0, 200.0)); + }); + testWidgets('Does not crash when using Navigator pages', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/119776 await tester.pumpWidget( @@ -249,6 +278,7 @@ void main() { final RenderSelectionSpy renderSelectionSpy = tester.renderObject(find.byKey(spy)); final TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0), kind: PointerDeviceKind.mouse); addTearDown(gesture.removePointer); + await tester.pumpAndSettle(); expect(renderSelectionSpy.events.length, 1); expect(renderSelectionSpy.events[0], isA()); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/102410. @@ -506,6 +536,7 @@ void main() { // Start a new drag. await gesture.up(); await gesture.down(textOffsetToPosition(paragraph, 5)); + await tester.pumpAndSettle(); expect(paragraph.selections.isEmpty, isTrue); // Selecting across line should select to the end. @@ -516,6 +547,224 @@ void main() { await gesture.up(); }); + testWidgets('mouse can select word-by-word on double click drag', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: const Center( + child: Text('How are you'), + ), + ), + ), + ); + final RenderParagraph paragraph = tester.renderObject(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(textOffsetToPosition(paragraph, 2)); + await tester.pumpAndSettle(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + + await gesture.moveTo(textOffsetToPosition(paragraph, 3)); + await tester.pumpAndSettle(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); + + await gesture.moveTo(textOffsetToPosition(paragraph, 4)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 7)); + + await gesture.moveTo(textOffsetToPosition(paragraph, 7)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 8)); + + await gesture.moveTo(textOffsetToPosition(paragraph, 8)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 11)); + + // Check backward selection. + await gesture.moveTo(textOffsetToPosition(paragraph, 1)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + + // Start a new double-click drag. + await gesture.up(); + await tester.pump(); + await gesture.down(textOffsetToPosition(paragraph, 5)); + await tester.pump(); + await gesture.up(); + expect(paragraph.selections.isEmpty, isTrue); + await tester.pump(kDoubleTapTimeout); + + // Double-click. + await gesture.down(textOffsetToPosition(paragraph, 5)); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await gesture.down(textOffsetToPosition(paragraph, 5)); + await tester.pumpAndSettle(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); + + // Selecting across line should select to the end. + await gesture.moveTo(textOffsetToPosition(paragraph, 5) + const Offset(0.0, 200.0)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 4, extentOffset: 11)); + await gesture.up(); + }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + + testWidgets('mouse can select multiple widgets on double click drag', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: const Column( + children: [ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + final RenderParagraph paragraph1 = tester.renderObject(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 2), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(textOffsetToPosition(paragraph1, 2)); + await tester.pumpAndSettle(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + + await gesture.moveTo(textOffsetToPosition(paragraph1, 4)); + await tester.pump(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 7)); + + final RenderParagraph paragraph2 = tester.renderObject(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph2, 5)); + // Should select the rest of paragraph 1. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + + final RenderParagraph paragraph3 = tester.renderObject(find.descendant(of: find.text('Fine, thank you.'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph3, 6)); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 14)); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 11)); + + await gesture.up(); + }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + + testWidgets('mouse can select multiple widgets on double click drag and return to origin word', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: const Column( + children: [ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + final RenderParagraph paragraph1 = tester.renderObject(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 2), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(textOffsetToPosition(paragraph1, 2)); + await tester.pumpAndSettle(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + + await gesture.moveTo(textOffsetToPosition(paragraph1, 4)); + await tester.pump(); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 7)); + + final RenderParagraph paragraph2 = tester.renderObject(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph2, 5)); + // Should select the rest of paragraph 1. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + + final RenderParagraph paragraph3 = tester.renderObject(find.descendant(of: find.text('Fine, thank you.'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph3, 6)); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 14)); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 0, extentOffset: 11)); + + await gesture.moveTo(textOffsetToPosition(paragraph2, 5)); + // Should clear the selection on paragraph 3. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); + expect(paragraph3.selections.isEmpty, true); + + await gesture.moveTo(textOffsetToPosition(paragraph1, 4)); + // Should clear the selection on paragraph 2. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 7)); + expect(paragraph2.selections.isEmpty, true); + expect(paragraph3.selections.isEmpty, true); + + await gesture.up(); + }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + + testWidgets('mouse can reverse selection across multiple widgets on double click drag', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: const Column( + children: [ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + final RenderParagraph paragraph3 = tester.renderObject(find.descendant(of: find.text('Fine, thank you.'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph3, 10), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + await gesture.down(textOffsetToPosition(paragraph3, 10)); + await tester.pumpAndSettle(); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 6, extentOffset: 11)); + + await gesture.moveTo(textOffsetToPosition(paragraph3, 4)); + await tester.pump(); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 11, extentOffset: 4)); + + final RenderParagraph paragraph2 = tester.renderObject(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph2, 5)); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 11, extentOffset: 0)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 14, extentOffset: 5)); + + final RenderParagraph paragraph1 = tester.renderObject(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + await gesture.moveTo(textOffsetToPosition(paragraph1, 6)); + expect(paragraph3.selections[0], const TextSelection(baseOffset: 11, extentOffset: 0)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 14, extentOffset: 0)); + expect(paragraph1.selections[0], const TextSelection(baseOffset: 12, extentOffset: 4)); + + await gesture.up(); + }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. + testWidgets('mouse can select multiple widgets', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( @@ -2416,6 +2665,7 @@ void main() { // Backwards selection. await gesture.down(textOffsetToPosition(paragraph, 3)); + await tester.pumpAndSettle(); expect(content, isNull); await gesture.moveTo(textOffsetToPosition(paragraph, 0)); await gesture.up(); From 83f56ee77f7cd54baffc4bbe8fea73c441094a38 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 17:53:54 -0400 Subject: [PATCH 0674/1547] Roll Flutter Engine from 622ded929968 to 832e7803b758 (7 revisions) (#132407) https://github.com/flutter/engine/compare/622ded929968...832e7803b758 2023-08-11 stuartmorgan@google.com Allow macOS plugins to register as app delegates (flutter/engine#44587) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 68ea92de8f29 to 7dd695d828cf (1 revision) (flutter/engine#44643) 2023-08-11 skia-flutter-autoroll@skia.org Roll Dart SDK from 83f96a990792 to ade04f1beb2c (1 revision) (flutter/engine#44642) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from fa30af9c2b80 to 68ea92de8f29 (2 revisions) (flutter/engine#44641) 2023-08-11 30870216+gaaclarke@users.noreply.github.com [Impeller] Added benchmark for advanced blend. (flutter/engine#44450) 2023-08-11 737941+loic-sharma@users.noreply.github.com [Embedder] Refactor how semantic updates are mapped (flutter/engine#44553) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from cfb9844091fa to fa30af9c2b80 (1 revision) (flutter/engine#44639) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4e001e4b8456e..47c2037dc1b17 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -622ded92996879c7d5cf7c8a40a5a68a9f843e80 +832e7803b7588d262397cc296d6c4e7c62fe1267 From 36c40e4972602c73fc6ee8ac698c1bd94b141ca4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 11 Aug 2023 18:48:13 -0400 Subject: [PATCH 0675/1547] Roll Flutter Engine from 832e7803b758 to 5669544866f3 (3 revisions) (#132413) https://github.com/flutter/engine/compare/832e7803b758...5669544866f3 2023-08-11 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from v33NyNdr6Y1sKZDze... to wSdqhvS1srhptT4ij... (flutter/engine#44648) 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 7dd695d828cf to 0f0ff37af487 (6 revisions) (flutter/engine#44649) 2023-08-11 john@johnmccutchan.com Rename impeller::TextureIntent to impeller::TextureCoordinateSystem (flutter/engine#44628) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from v33NyNdr6Y1s to wSdqhvS1srhp If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 47c2037dc1b17..a6c9e275cedc5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -832e7803b7588d262397cc296d6c4e7c62fe1267 +5669544866f3a0a0fd6e1eb50b2d8506ca88923c diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 403fe002f3319..40d9f457a6ada 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -v33NyNdr6Y1sKZDze0sHWQP_VGO-Qi5XMe2Za3-mg0AC +wSdqhvS1srhptT4ijfNMp8UkOOk3KdUXHfuXSn4i2e8C From 118544972a05fa8270c196a1c8cd9683868bf09a Mon Sep 17 00:00:00 2001 From: Elliott Brooks <21270878+elliette@users.noreply.github.com> Date: Fri, 11 Aug 2023 16:09:07 -0700 Subject: [PATCH 0676/1547] Update DWDS to `20.0.1` in `flutter_tools` (#132350) - Updates DWDS from `19.0.2` to `20.0.1` - Makes the required changes for the breaking changes to the `AssetReader` class --- packages/flutter_tools/lib/src/isolated/devfs_web.dart | 2 +- packages/flutter_tools/pubspec.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/flutter_tools/lib/src/isolated/devfs_web.dart b/packages/flutter_tools/lib/src/isolated/devfs_web.dart index 903eae94f6bfc..e9539482ab6db 100644 --- a/packages/flutter_tools/lib/src/isolated/devfs_web.dart +++ b/packages/flutter_tools/lib/src/isolated/devfs_web.dart @@ -295,7 +295,6 @@ class WebAssetServer implements AssetReader { server, PackageUriMapper(packageConfig), digestProvider, - server.basePath, packageConfig.toPackageUri( globals.fs.file(entrypoint).absolute.uri, ), @@ -347,6 +346,7 @@ class WebAssetServer implements AssetReader { /// /// It should have no leading or trailing slashes. @visibleForTesting + @override String basePath; // handle requests for JavaScript source, dart sources maps, or asset files. diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index db71a194d144d..4307ba5334ed9 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: args: 2.4.2 browser_launcher: 1.1.1 dds: 2.9.4 - dwds: 19.0.2 + dwds: 20.0.1 completion: 1.0.1 coverage: 1.6.3 crypto: 3.0.3 @@ -107,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 1a86 +# PUBSPEC CHECKSUM: f97d From 881945ddb862761c9c4f04607dfcf0bac4c718ab Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 11 Aug 2023 18:56:22 -0700 Subject: [PATCH 0677/1547] Read `--dart-define` in `RendererBinding.initInstances()` (#132408) Move `SKPARAGRAPH_REMOVE_ROUNDING_HACK` reading to the framework from `dart:ui` so `flutter run --dart-define="SKPARAGRAPH_REMOVE_ROUNDING_HACK=false"` works --- packages/flutter/lib/src/rendering/binding.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 5d1552ec3cb54..bb9bd4fe77610 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show SemanticsUpdate; +import 'dart:ui' as ui show ParagraphBuilder, SemanticsUpdate; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -49,6 +49,11 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture addPostFrameCallback(_handleWebFirstFrame); } rootPipelineOwner.attach(_manifold); + // TODO(LongCatIsLooong): clean up after + // https://github.com/flutter/flutter/issues/31707 is fully migrated. + if (!const bool.fromEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK', defaultValue: true)) { + ui.ParagraphBuilder.setDisableRoundingHack(false); + } } /// The current [RendererBinding], if one has been created. From 5d03cf9c2de5450472af9d17f7bf7b545ed18ab4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 00:42:23 -0400 Subject: [PATCH 0678/1547] Roll Flutter Engine from 5669544866f3 to e59ea1641b75 (2 revisions) (#132420) https://github.com/flutter/engine/compare/5669544866f3...e59ea1641b75 2023-08-11 skia-flutter-autoroll@skia.org Roll Skia from 0f0ff37af487 to dc71a424d870 (3 revisions) (flutter/engine#44654) 2023-08-11 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 7DmdwgtGmIxyejFDl... to UdQpH1Y2NyVf3vt3R... (flutter/engine#44653) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 7DmdwgtGmIxy to UdQpH1Y2NyVf If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a6c9e275cedc5..83d5a9ccf6d39 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5669544866f3a0a0fd6e1eb50b2d8506ca88923c +e59ea1641b75de55f34e61d5ac425feb6ecf6121 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index e996b6a24c099..57cd6149900f6 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -7DmdwgtGmIxyejFDlL7-HuTsOjxOTSn_eTIb6vNsAU4C +UdQpH1Y2NyVf3vt3Rz4gLxgRubjiHql2VtJUTw5IcZ8C From 7cca58819411fe8df391c31c8a92373e2588d6ad Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 01:36:15 -0400 Subject: [PATCH 0679/1547] Roll Flutter Engine from e59ea1641b75 to f6ad8d574dee (4 revisions) (#132427) https://github.com/flutter/engine/compare/e59ea1641b75...f6ad8d574dee 2023-08-12 skia-flutter-autoroll@skia.org Roll Dart SDK from ade04f1beb2c to e23931233ff2 (1 revision) (flutter/engine#44657) 2023-08-12 ypomortsev@google.com Remove dependencies on fuchsia.sys.* FIDL protocols (flutter/engine#44614) 2023-08-12 skia-flutter-autoroll@skia.org Roll Skia from dc71a424d870 to e0f07834d736 (1 revision) (flutter/engine#44655) 2023-08-11 31859944+LongCatIsLooong@users.noreply.github.com allow `ParagraphBuilder.shouldDisableRoundingHack` to actually be set to false in tests (flutter/engine#44647) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 83d5a9ccf6d39..4b7a98bf699c9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e59ea1641b75de55f34e61d5ac425feb6ecf6121 +f6ad8d574deee7ff597ad95767f7139e794189dc From 0fefd9d6ff9da112e38c7f10a7c56a73ddbc85b0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 05:07:24 -0400 Subject: [PATCH 0680/1547] Roll Flutter Engine from f6ad8d574dee to 8435d7d344a4 (2 revisions) (#132431) https://github.com/flutter/engine/compare/f6ad8d574dee...8435d7d344a4 2023-08-12 skia-flutter-autoroll@skia.org Roll Skia from e0f07834d736 to 52eef2a16dfe (1 revision) (flutter/engine#44659) 2023-08-12 skia-flutter-autoroll@skia.org Roll Dart SDK from e23931233ff2 to 6118ce565dc2 (1 revision) (flutter/engine#44658) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4b7a98bf699c9..26edf1d557bd2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f6ad8d574deee7ff597ad95767f7139e794189dc +8435d7d344a4787dbef789717142d68eac0e6a23 From 7d83e9eebb77f91d36dc1c79c565dce0b5ec852b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 06:15:22 -0400 Subject: [PATCH 0681/1547] Roll Flutter Engine from 8435d7d344a4 to a0d550756800 (1 revision) (#132434) https://github.com/flutter/engine/compare/8435d7d344a4...a0d550756800 2023-08-12 skia-flutter-autoroll@skia.org Roll Dart SDK from 6118ce565dc2 to 55d7c1b35902 (1 revision) (flutter/engine#44660) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 26edf1d557bd2..8a4b510a49f24 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8435d7d344a4787dbef789717142d68eac0e6a23 +a0d55075680048c3a19850e89c6748bb42a0e4e8 From dc8ec01f9dcfcc9a1bc47b90da38471b6c9a5f89 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 07:13:35 -0400 Subject: [PATCH 0682/1547] Roll Flutter Engine from a0d550756800 to f4db669cf4e6 (1 revision) (#132435) https://github.com/flutter/engine/compare/a0d550756800...f4db669cf4e6 2023-08-12 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from wSdqhvS1srhptT4ij... to 1-uqfjivXAYe2ue-4... (flutter/engine#44661) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from wSdqhvS1srhp to 1-uqfjivXAYe If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8a4b510a49f24..78a76237bc73d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a0d55075680048c3a19850e89c6748bb42a0e4e8 +f4db669cf4e69c84c81e3c417563dc3958e30b83 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 40d9f457a6ada..d3a5f8c2b2abb 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -wSdqhvS1srhptT4ijfNMp8UkOOk3KdUXHfuXSn4i2e8C +1-uqfjivXAYe2ue-4gj_jceMWxWZ9jVpTTsVr4UbYHQC From b8c1f8e2fc7300d83e00e72f579355bbac5ce024 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 11:48:37 -0400 Subject: [PATCH 0683/1547] Roll Flutter Engine from f4db669cf4e6 to 2107c6f6971f (1 revision) (#132441) https://github.com/flutter/engine/compare/f4db669cf4e6...2107c6f6971f 2023-08-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from UdQpH1Y2NyVf3vt3R... to NepG1SFiAP-GMJS7R... (flutter/engine#44662) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from UdQpH1Y2NyVf to NepG1SFiAP-G If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 78a76237bc73d..c6dd6fca1a258 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f4db669cf4e69c84c81e3c417563dc3958e30b83 +2107c6f6971fb13008e0616bf1c5b2087dde5e50 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 57cd6149900f6..1c8c6f0910d2a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -UdQpH1Y2NyVf3vt3Rz4gLxgRubjiHql2VtJUTw5IcZ8C +NepG1SFiAP-GMJS7RpjI00ndIqhslNYAv-MqFXGWwS4C From 156c12c45249155ff96672e256197463be65f512 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 21:46:27 -0400 Subject: [PATCH 0684/1547] Roll Flutter Engine from 2107c6f6971f to 86a1e6582c71 (1 revision) (#132446) https://github.com/flutter/engine/compare/2107c6f6971f...86a1e6582c71 2023-08-13 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from NepG1SFiAP-GMJS7R... to vHvU_OjTM5PQkRx1Y... (flutter/engine#44664) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from NepG1SFiAP-G to vHvU_OjTM5PQ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c6dd6fca1a258..ac3e566cb8123 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2107c6f6971fb13008e0616bf1c5b2087dde5e50 +86a1e6582c710bba332b228a7e3dc8cf8e39bf4d diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 1c8c6f0910d2a..3223330b4c2a6 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -NepG1SFiAP-GMJS7RpjI00ndIqhslNYAv-MqFXGWwS4C +vHvU_OjTM5PQkRx1Y7Ay-b-A_waBt8FGKlvOavsU7C4C From 28400daf2d36d22c3f756a9c7f177acaa512fbeb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 12 Aug 2023 23:20:24 -0400 Subject: [PATCH 0685/1547] Roll Flutter Engine from 86a1e6582c71 to 6e0804f8aff3 (1 revision) (#132447) https://github.com/flutter/engine/compare/86a1e6582c71...6e0804f8aff3 2023-08-13 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 1-uqfjivXAYe2ue-4... to tfgOFdhH6PlJyMv3V... (flutter/engine#44665) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 1-uqfjivXAYe to tfgOFdhH6PlJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ac3e566cb8123..7bc73013fff65 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -86a1e6582c710bba332b228a7e3dc8cf8e39bf4d +6e0804f8aff32cc1214659e216147ad1b6b78111 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index d3a5f8c2b2abb..e151a75f7d807 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -1-uqfjivXAYe2ue-4gj_jceMWxWZ9jVpTTsVr4UbYHQC +tfgOFdhH6PlJyMv3VUl3UccrvFsHmdzKd0bEc8KNT7UC From e6797126a879f7911230551ac4b9d9587678aa13 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 13 Aug 2023 11:49:17 -0400 Subject: [PATCH 0686/1547] Roll Flutter Engine from 6e0804f8aff3 to 7c9d71a464c4 (2 revisions) (#132458) https://github.com/flutter/engine/compare/6e0804f8aff3...7c9d71a464c4 2023-08-13 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from tfgOFdhH6PlJyMv3V... to UN2vSCJekPhDnlCRd... (flutter/engine#44668) 2023-08-13 skia-flutter-autoroll@skia.org Roll Skia from 52eef2a16dfe to 9bb236d03e63 (1 revision) (flutter/engine#44667) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from tfgOFdhH6PlJ to UN2vSCJekPhD If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7bc73013fff65..33be314821d5d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6e0804f8aff32cc1214659e216147ad1b6b78111 +7c9d71a464c4cb7d3ec2112fd930b9fc26783f65 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index e151a75f7d807..4020d50376757 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -tfgOFdhH6PlJyMv3VUl3UccrvFsHmdzKd0bEc8KNT7UC +UN2vSCJekPhDnlCRd9RqqMKCawxo7Qr2wUA8uwDNMhoC From 6b3eefc2868b8cda1728a9784acdf0b8336ac5ae Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 13 Aug 2023 13:03:16 -0400 Subject: [PATCH 0687/1547] Roll Flutter Engine from 7c9d71a464c4 to f47e864f2dcb (1 revision) (#132459) https://github.com/flutter/engine/compare/7c9d71a464c4...f47e864f2dcb 2023-08-13 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from vHvU_OjTM5PQkRx1Y... to yfMzjtavZwtK0QM4C... (flutter/engine#44669) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from vHvU_OjTM5PQ to yfMzjtavZwtK If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 33be314821d5d..2eff4e5d6e474 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7c9d71a464c4cb7d3ec2112fd930b9fc26783f65 +f47e864f2dcb9c299a3a3ed22300a1dcacbdf1fe diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 3223330b4c2a6..6b544bb235927 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -vHvU_OjTM5PQkRx1Y7Ay-b-A_waBt8FGKlvOavsU7C4C +yfMzjtavZwtK0QM4CqywKUps3zcuDiCADTANuCw749AC From 7ce2d83b848fb2081855ec47deddedb554348cd4 Mon Sep 17 00:00:00 2001 From: Casey Hillers Date: Sun, 13 Aug 2023 14:27:01 -0700 Subject: [PATCH 0688/1547] Revert "Fix `PopupMenuItem` & `CheckedPopupMenuItem` has redundant `ListTile` padding and update default horizontal padding for Material 3" (#132457) Reverts flutter/flutter#131609 b/295497265 - This broke Google Testing. We'll need the internal patch before landing as there's a large number of customer codebases impacted. --- .../gen_defaults/lib/popup_menu_template.dart | 4 - .../flutter/lib/src/material/popup_menu.dart | 38 ++-- .../test/material/popup_menu_test.dart | 166 ------------------ 3 files changed, 11 insertions(+), 197 deletions(-) diff --git a/dev/tools/gen_defaults/lib/popup_menu_template.dart b/dev/tools/gen_defaults/lib/popup_menu_template.dart index bed11d0b8b09a..f11b89c9500e9 100644 --- a/dev/tools/gen_defaults/lib/popup_menu_template.dart +++ b/dev/tools/gen_defaults/lib/popup_menu_template.dart @@ -42,9 +42,5 @@ class _${blockName}DefaultsM3 extends PopupMenuThemeData { @override ShapeBorder? get shape => ${shape("md.comp.menu.container")}; - - // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs - // Update this when the token is available. - static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); }'''; } diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 7a3f7a5249bff..ef8f4367c6b43 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -14,7 +14,6 @@ import 'icon_button.dart'; import 'icons.dart'; import 'ink_well.dart'; import 'list_tile.dart'; -import 'list_tile_theme.dart'; import 'material.dart'; import 'material_localizations.dart'; import 'material_state.dart'; @@ -33,6 +32,7 @@ import 'tooltip.dart'; const Duration _kMenuDuration = Duration(milliseconds: 300); const double _kMenuCloseIntervalEnd = 2.0 / 3.0; +const double _kMenuHorizontalPadding = 16.0; const double _kMenuDividerHeight = 16.0; const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; @@ -255,11 +255,7 @@ class PopupMenuItem extends PopupMenuEntry { /// If a [height] greater than the height of the sum of the padding and [child] /// is provided, then the padding's effect will not be visible. /// - /// If this is null and [ThemeData.useMaterial3] is true, the horizontal padding - /// defaults to 12.0 on both sides. - /// - /// If this is null and [ThemeData.useMaterial3] is false, the horizontal padding - /// defaults to 16.0 on both sides. + /// When null, the horizontal padding defaults to 16.0 on both sides. final EdgeInsets? padding; /// The text style of the popup menu item. @@ -376,7 +372,7 @@ class PopupMenuItemState> extends State { child: Container( alignment: AlignmentDirectional.centerStart, constraints: BoxConstraints(minHeight: widget.height), - padding: widget.padding ?? (theme.useMaterial3 ? _PopupMenuDefaultsM3.menuHorizontalPadding : _PopupMenuDefaultsM2.menuHorizontalPadding), + padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: _kMenuHorizontalPadding), child: buildChild(), ), ); @@ -397,10 +393,7 @@ class PopupMenuItemState> extends State { onTap: widget.enabled ? handleTap : null, canRequestFocus: widget.enabled, mouseCursor: _EffectiveMouseCursor(widget.mouseCursor, popupMenuTheme.mouseCursor), - child: ListTileTheme.merge( - contentPadding: EdgeInsets.zero, - child: item, - ), + child: item, ), ), ); @@ -547,17 +540,14 @@ class _CheckedPopupMenuItemState extends PopupMenuItemState _textTheme.subtitle1; - - static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 16.0); } // BEGIN GENERATED TOKEN PROPERTIES - PopupMenu @@ -1477,9 +1465,5 @@ class _PopupMenuDefaultsM3 extends PopupMenuThemeData { @override ShapeBorder? get shape => const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))); - - // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs - // Update this when the token is available. - static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); } // END GENERATED TOKEN PROPERTIES - PopupMenu diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 60c576797dcd8..f26ed5a03adc7 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1553,82 +1553,6 @@ void main() { ); }); - testWidgets('Material3 - PopupMenuItem default padding', (WidgetTester tester) async { - final Key popupMenuButtonKey = UniqueKey(); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData(useMaterial3: true), - home: Scaffold( - body: Center( - child: PopupMenuButton( - key: popupMenuButtonKey, - child: const Text('button'), - onSelected: (String result) { }, - itemBuilder: (BuildContext context) { - return >[ - const PopupMenuItem( - value: '0', - enabled: false, - child: Text('Item 0'), - ), - const PopupMenuItem( - value: '1', - child: Text('Item 1'), - ), - ]; - }, - ), - ), - ), - ), - ); - - // Show the menu. - await tester.tap(find.byKey(popupMenuButtonKey)); - await tester.pumpAndSettle(); - - expect(tester.widget(find.widgetWithText(Container, 'Item 0')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); - expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); - }); - - testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async { - final Key popupMenuButtonKey = UniqueKey(); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData(useMaterial3: false), - home: Scaffold( - body: Center( - child: PopupMenuButton( - key: popupMenuButtonKey, - child: const Text('button'), - onSelected: (String result) { }, - itemBuilder: (BuildContext context) { - return >[ - const PopupMenuItem( - value: '0', - enabled: false, - child: Text('Item 0'), - ), - const PopupMenuItem( - value: '1', - child: Text('Item 1'), - ), - ]; - }, - ), - ), - ), - ), - ); - - // Show the menu. - await tester.tap(find.byKey(popupMenuButtonKey)); - await tester.pumpAndSettle(); - - expect(tester.widget(find.widgetWithText(Container, 'Item 0')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); - expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); - }); - testWidgets('PopupMenuItem custom padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -3491,96 +3415,6 @@ void main() { labelTextStyle.resolve({MaterialState.selected}) ); }); - - testWidgets('CheckedPopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { - final Key popupMenuButtonKey = UniqueKey(); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData(useMaterial3: false), - home: Scaffold( - body: Center( - child: PopupMenuButton( - key: popupMenuButtonKey, - child: const Text('button'), - onSelected: (String result) { }, - itemBuilder: (BuildContext context) { - return >[ - const CheckedPopupMenuItem( - value: '0', - child: Text('Item 0'), - ), - const CheckedPopupMenuItem( - value: '1', - checked: true, - child: Text('Item 1'), - ), - ]; - }, - ), - ), - ), - ), - ); - - // Show the menu. - await tester.tap(find.byKey(popupMenuButtonKey)); - await tester.pumpAndSettle(); - - SafeArea getItemSafeArea(String label) { - return tester.widget(find.ancestor( - of: find.text(label), - matching: find.byType(SafeArea), - )); - } - - expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); - expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); - }); - - testWidgets('PopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { - final Key popupMenuButtonKey = UniqueKey(); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData(useMaterial3: false), - home: Scaffold( - body: Center( - child: PopupMenuButton( - key: popupMenuButtonKey, - child: const Text('button'), - onSelected: (String result) { }, - itemBuilder: (BuildContext context) { - return >[ - const PopupMenuItem( - value: '0', - enabled: false, - child: ListTile(title: Text('Item 0')), - ), - const PopupMenuItem( - value: '1', - child: ListTile(title: Text('Item 1')), - ), - ]; - }, - ), - ), - ), - ), - ); - - // Show the menu. - await tester.tap(find.byKey(popupMenuButtonKey)); - await tester.pumpAndSettle(); - - SafeArea getItemSafeArea(String label) { - return tester.widget(find.ancestor( - of: find.text(label), - matching: find.byType(SafeArea), - )); - } - - expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); - expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); - }); } class TestApp extends StatelessWidget { From d4c5e90e268db7c5ad3529c42f70029eb2cc8e91 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 13 Aug 2023 23:33:11 -0400 Subject: [PATCH 0689/1547] Roll Flutter Engine from f47e864f2dcb to 7915c049a1fd (1 revision) (#132466) https://github.com/flutter/engine/compare/f47e864f2dcb...7915c049a1fd 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from 9bb236d03e63 to a8715028bba1 (1 revision) (flutter/engine#44671) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2eff4e5d6e474..6c31487267645 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f47e864f2dcb9c299a3a3ed22300a1dcacbdf1fe +7915c049a1fdf83a734c48ab07941e1fdf8946d2 From 427bfc66095dcc44acb6d43ac8f230823a2fc6d0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 00:57:40 -0400 Subject: [PATCH 0690/1547] Roll Flutter Engine from 7915c049a1fd to bcaaa0e125fe (1 revision) (#132473) https://github.com/flutter/engine/compare/7915c049a1fd...bcaaa0e125fe 2023-08-14 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from UN2vSCJekPhDnlCRd... to yr5wa34bzOBfEgzDH... (flutter/engine#44672) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from UN2vSCJekPhD to yr5wa34bzOBf If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6c31487267645..55d0e82ca0eed 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7915c049a1fdf83a734c48ab07941e1fdf8946d2 +bcaaa0e125fe1fa0d7b58426aa208829e08290b0 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 4020d50376757..16b67afdc8ba5 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -UN2vSCJekPhDnlCRd9RqqMKCawxo7Qr2wUA8uwDNMhoC +yr5wa34bzOBfEgzDH0dAgw9hz2auaQ7qLNdAEEyKD4IC From de84eec63a77177326fc59790d5d5978bbd97d0b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 03:16:34 -0400 Subject: [PATCH 0691/1547] Roll Flutter Engine from bcaaa0e125fe to 9cebd2015688 (2 revisions) (#132477) https://github.com/flutter/engine/compare/bcaaa0e125fe...9cebd2015688 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from a8715028bba1 to afec82ee6a10 (1 revision) (flutter/engine#44674) 2023-08-14 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from yfMzjtavZwtK0QM4C... to JKTVoxVrHjZjBaxG4... (flutter/engine#44673) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from yfMzjtavZwtK to JKTVoxVrHjZj If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 55d0e82ca0eed..1df72b3006af8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bcaaa0e125fe1fa0d7b58426aa208829e08290b0 +9cebd20156883b59fa34cad023478cc88d20b9a0 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 6b544bb235927..104400eccfb64 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -yfMzjtavZwtK0QM4CqywKUps3zcuDiCADTANuCw749AC +JKTVoxVrHjZjBaxG4cdtYRkXlgD-QKknAFLrCcS91nQC From 9c214034714a91197f6750467a0e4c86be9f0551 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 04:47:23 -0400 Subject: [PATCH 0692/1547] Roll Flutter Engine from 9cebd2015688 to f50ad637de75 (3 revisions) (#132480) https://github.com/flutter/engine/compare/9cebd2015688...f50ad637de75 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from efb8daa0503b to f3b22eaf86bd (1 revision) (flutter/engine#44677) 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from afec82ee6a10 to efb8daa0503b (1 revision) (flutter/engine#44676) 2023-08-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 55d7c1b35902 to 452c6617ee36 (1 revision) (flutter/engine#44675) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1df72b3006af8..faa772ce8cf1f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9cebd20156883b59fa34cad023478cc88d20b9a0 +f50ad637de7540a37f0b86fd00efa64c01361c76 From 8b132c0f3d7c7687d1319c101efac36e1425a386 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 10:30:15 -0400 Subject: [PATCH 0693/1547] Roll Flutter Engine from f50ad637de75 to 62a392f29aa5 (1 revision) (#132487) https://github.com/flutter/engine/compare/f50ad637de75...62a392f29aa5 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from f3b22eaf86bd to a4aa96331dd5 (1 revision) (flutter/engine#44678) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index faa772ce8cf1f..c371dc4740c7d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f50ad637de7540a37f0b86fd00efa64c01361c76 +62a392f29aa5e59737510d3898ae261a6df131f1 From 87de2c5e609a5988efcb70cb2a14e738fca27f8e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 12:17:09 -0400 Subject: [PATCH 0694/1547] Roll Flutter Engine from 62a392f29aa5 to 4e8b2b61f648 (2 revisions) (#132490) https://github.com/flutter/engine/compare/62a392f29aa5...4e8b2b61f648 2023-08-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 452c6617ee36 to 3295a353980a (1 revision) (flutter/engine#44681) 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from a4aa96331dd5 to 8b051126be8a (2 revisions) (flutter/engine#44680) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c371dc4740c7d..42717a4f37385 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -62a392f29aa5e59737510d3898ae261a6df131f1 +4e8b2b61f64856bc11df6a569472c279dc1eef6d From a7b69b069f253e255cf22ce07010bffc3ab71448 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 14 Aug 2023 10:05:20 -0700 Subject: [PATCH 0695/1547] Unpin leak_tracker and handle breaking changes in API. (#132352) --- packages/flutter/pubspec.yaml | 7 +- .../test/animation/animation_sheet_test.dart | 5 +- .../flutter/test/animation/futures_test.dart | 3 +- .../animation/iteration_patterns_test.dart | 3 +- .../test/animation/live_binding_test.dart | 5 +- .../flutter/test/flutter_test_config.dart | 6 +- .../test/foundation/change_notifier_test.dart | 3 +- .../test/foundation/leak_tracking.dart | 206 --------------- .../test/foundation/leak_tracking_test.dart | 235 ------------------ .../flutter/test/gestures/debug_test.dart | 3 +- ...binding_resample_event_on_widget_test.dart | 3 +- .../gesture_config_regression_test.dart | 3 +- .../gestures/transformed_double_tap_test.dart | 3 +- .../gestures/transformed_long_press_test.dart | 3 +- .../gestures/transformed_monodrag_test.dart | 5 +- .../test/gestures/transformed_scale_test.dart | 4 +- .../test/gestures/transformed_tap_test.dart | 3 +- .../flutter/test/material/about_test.dart | 17 +- .../test/material/action_chip_test.dart | 3 +- .../material/action_icons_theme_test.dart | 3 +- .../adaptive_text_selection_toolbar_test.dart | 9 +- .../test/material/animated_icons_test.dart | 3 +- .../test/material/app_builder_test.dart | 3 +- .../test/material/back_button_test.dart | 3 +- .../flutter/test/material/badge_test.dart | 3 +- .../test/material/badge_theme_test.dart | 3 +- .../flutter/test/material/banner_test.dart | 3 +- .../test/material/banner_theme_test.dart | 3 +- .../test/material/bottom_app_bar_test.dart | 3 +- .../material/bottom_app_bar_theme_test.dart | 3 +- .../material/bottom_navigation_bar_test.dart | 2 +- .../bottom_navigation_bar_theme_test.dart | 3 +- .../material/bottom_sheet_theme_test.dart | 7 +- .../test/material/button_bar_test.dart | 7 +- .../test/material/button_bar_theme_test.dart | 3 +- .../test/material/button_style_test.dart | 3 +- packages/flutter/test/material/card_test.dart | 3 +- .../material/checkbox_list_tile_test.dart | 5 +- .../test/material/checkbox_theme_test.dart | 5 +- packages/flutter/test/material/chip_test.dart | 21 +- .../test/material/chip_theme_test.dart | 5 +- .../test/material/choice_chip_test.dart | 3 +- .../test/material/circle_avatar_test.dart | 3 +- .../test/material/data_table_test.dart | 2 +- .../test/material/data_table_theme_test.dart | 3 +- .../test/material/date_range_picker_test.dart | 4 +- .../flutter/test/material/debug_test.dart | 3 +- ...op_text_selection_toolbar_button_test.dart | 3 +- .../desktop_text_selection_toolbar_test.dart | 3 +- .../flutter/test/material/dialog_test.dart | 14 +- .../test/material/drawer_button_test.dart | 7 +- .../material/dropdown_form_field_test.dart | 48 ++-- .../material/dropdown_menu_theme_test.dart | 11 +- .../test/material/elevated_button_test.dart | 29 ++- .../material/elevated_button_theme_test.dart | 3 +- .../test/material/expand_icon_test.dart | 3 +- .../test/material/expansion_panel_test.dart | 3 +- .../test/material/expansion_tile_test.dart | 3 +- .../material/expansion_tile_theme_test.dart | 3 +- .../flutter/test/material/feedback_test.dart | 3 +- .../test/material/filled_button_test.dart | 20 +- .../material/filled_button_theme_test.dart | 3 +- .../test/material/filter_chip_test.dart | 3 +- ...flexible_space_bar_collapse_mode_test.dart | 7 +- .../flexible_space_bar_stretch_mode_test.dart | 7 +- .../material/flexible_space_bar_test.dart | 3 +- .../floating_action_button_location_test.dart | 9 +- .../material/floating_action_button_test.dart | 17 +- .../floating_action_button_theme_test.dart | 3 +- .../test/material/flutter_logo_test.dart | 3 +- .../test/material/grid_title_test.dart | 3 +- .../test/material/icon_button_test.dart | 27 +- .../test/material/icon_button_theme_test.dart | 3 +- .../flutter/test/material/icons_test.dart | 3 +- .../flutter/test/material/ink_paint_test.dart | 7 +- .../test/material/ink_sparkle_test.dart | 3 +- .../test/material/ink_splash_test.dart | 3 +- .../flutter/test/material/ink_well_test.dart | 23 +- .../test/material/input_chip_test.dart | 8 +- .../input_date_picker_form_field_test.dart | 27 +- .../flutter/test/material/list_tile_test.dart | 7 +- .../test/material/list_tile_theme_test.dart | 5 +- .../test/material/localizations_test.dart | 3 +- .../flutter/test/material/magnifier_test.dart | 24 +- .../test/material/material_button_test.dart | 9 +- .../material/material_state_mixin_test.dart | 3 +- .../flutter/test/material/material_test.dart | 3 +- .../test/material/menu_bar_theme_test.dart | 5 +- .../test/material/menu_style_test.dart | 11 +- .../test/material/menu_theme_test.dart | 7 +- .../material/mergeable_material_test.dart | 11 +- .../test/material/navigation_bar_test.dart | 3 +- .../material/navigation_bar_theme_test.dart | 3 +- .../test/material/navigation_drawer_test.dart | 20 +- .../test/material/navigation_rail_test.dart | 3 +- .../test/material/outlined_button_test.dart | 33 ++- .../material/outlined_button_theme_test.dart | 3 +- .../test/material/page_selector_test.dart | 5 +- .../material/page_transitions_theme_test.dart | 3 +- .../persistent_bottom_sheet_test.dart | 13 +- .../test/material/popup_menu_theme_test.dart | 3 +- .../material/progress_indicator_test.dart | 3 +- .../flutter/test/material/radio_test.dart | 19 +- .../test/material/radio_theme_test.dart | 3 +- .../test/material/range_slider_test.dart | 90 ++++--- .../material/raw_material_button_test.dart | 9 +- .../test/material/refresh_indicator_test.dart | 3 +- .../test/material/scrollbar_paint_test.dart | 7 +- .../flutter/test/material/scrollbar_test.dart | 3 +- .../test/material/scrollbar_theme_test.dart | 3 +- .../test/material/search_bar_theme_test.dart | 15 +- .../test/material/search_view_theme_test.dart | 15 +- .../test/material/segmented_button_test.dart | 13 +- .../material/segmented_button_theme_test.dart | 11 +- .../test/material/selection_area_test.dart | 11 +- .../test/material/slider_theme_test.dart | 78 +++--- ...gestions_toolbar_layout_delegate_test.dart | 3 +- .../spell_check_suggestions_toolbar_test.dart | 3 +- .../test/material/switch_list_tile_test.dart | 6 +- .../flutter/test/material/switch_test.dart | 29 ++- .../test/material/switch_theme_test.dart | 3 +- .../material/tabbed_scrollview_warp_test.dart | 3 +- .../test/material/text_button_test.dart | 29 ++- .../test/material/text_button_theme_test.dart | 3 +- .../material/text_field_helper_text_test.dart | 4 +- .../test/material/text_field_splash_test.dart | 4 +- .../test/material/text_form_field_test.dart | 83 +++---- .../material/text_selection_theme_test.dart | 9 +- .../material/text_selection_toolbar_test.dart | 5 +- ...xt_selection_toolbar_text_button_test.dart | 3 +- .../test/material/theme_data_test.dart | 3 +- packages/flutter/test/material/time_test.dart | 9 +- .../test/material/toggle_buttons_test.dart | 13 +- .../material/toggle_buttons_theme_test.dart | 5 +- .../flutter/test/material/tooltip_test.dart | 29 ++- .../test/material/tooltip_theme_test.dart | 27 +- .../material/tooltip_visibility_test.dart | 3 +- .../test/material/typography_test.dart | 3 +- .../user_accounts_drawer_header_test.dart | 3 +- .../value_indicating_slider_test.dart | 10 +- .../lib/src/commands/update_packages.dart | 4 - .../general.shard/update_packages_test.dart | 2 - 142 files changed, 666 insertions(+), 1048 deletions(-) delete mode 100644 packages/flutter/test/foundation/leak_tracking.dart delete mode 100644 packages/flutter/test/foundation/leak_tracking_test.dart diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index dd753c75e994d..7975cf6bf2777 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,8 +22,8 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 8.0.3 - leak_tracker_testing: 1.0.2 + leak_tracker: 9.0.4 + leak_tracker_flutter_testing: 1.0.1 _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,6 +42,7 @@ dev_dependencies: intl: 0.18.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + leak_tracker_testing: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -73,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 443a +# PUBSPEC CHECKSUM: a63c diff --git a/packages/flutter/test/animation/animation_sheet_test.dart b/packages/flutter/test/animation/animation_sheet_test.dart index 4c26669abec4f..0d60746c45dfb 100644 --- a/packages/flutter/test/animation/animation_sheet_test.dart +++ b/packages/flutter/test/animation/animation_sheet_test.dart @@ -12,7 +12,6 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; void main() { /* @@ -20,7 +19,7 @@ void main() { * because [matchesGoldenFile] does not use Skia Gold in its native package. */ - testWidgetsWithLeakTracking('correctly records frames using collate', (WidgetTester tester) async { + testWidgets('correctly records frames using collate', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); await tester.pumpFrames( @@ -57,7 +56,7 @@ void main() { image.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgetsWithLeakTracking('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { + testWidgets('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder( frameSize: const Size(8, 2), allLayers: true, diff --git a/packages/flutter/test/animation/futures_test.dart b/packages/flutter/test/animation/futures_test.dart index 5a33543024d29..6ffee8e16445a 100644 --- a/packages/flutter/test/animation/futures_test.dart +++ b/packages/flutter/test/animation/futures_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/animation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('awaiting animation controllers - using direct future', (WidgetTester tester) async { diff --git a/packages/flutter/test/animation/iteration_patterns_test.dart b/packages/flutter/test/animation/iteration_patterns_test.dart index 42b4e916da476..0705333d3f99a 100644 --- a/packages/flutter/test/animation/iteration_patterns_test.dart +++ b/packages/flutter/test/animation/iteration_patterns_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { setUp(() { diff --git a/packages/flutter/test/animation/live_binding_test.dart b/packages/flutter/test/animation/live_binding_test.dart index 4928e6a6762f0..e0d523fb22ab4 100644 --- a/packages/flutter/test/animation/live_binding_test.dart +++ b/packages/flutter/test/animation/live_binding_test.dart @@ -11,8 +11,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { /* @@ -80,7 +79,7 @@ void main() { // Currently skipped due to daily flake: https://github.com/flutter/flutter/issues/87588 }, skip: true); // Typically skip: isBrowser https://github.com/flutter/flutter/issues/42767 - testWidgetsWithLeakTracking('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { + testWidgets('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(200, 200), allLayers: true); final List taps = []; Widget target({bool recording = true}) => Container( diff --git a/packages/flutter/test/flutter_test_config.dart b/packages/flutter/test/flutter_test_config.dart index e8d488aff5fe2..5600ab04609d6 100644 --- a/packages/flutter/test/flutter_test_config.dart +++ b/packages/flutter/test/flutter_test_config.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker/leak_tracker.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as flutter_goldens; @@ -23,7 +24,10 @@ Future testExecutable(FutureOr Function() testMain) { // receive the event. WidgetController.hitTestWarningShouldBeFatal = true; - LeakTrackerGlobalSettings.warnForNonSupportedPlatforms = false; + LeakTracking.warnForUnsupportedPlatforms = false; + setLeakTrackingTestSettings( + LeakTrackingTestSettings(switches: const Switches(disableNotGCed: true)) + ); // Enable golden file testing using Skia Gold. return flutter_goldens.testExecutable(testMain); diff --git a/packages/flutter/test/foundation/change_notifier_test.dart b/packages/flutter/test/foundation/change_notifier_test.dart index 661431e6c4a97..a7adb3df3163f 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; - -import 'leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestNotifier extends ChangeNotifier { void notify() { diff --git a/packages/flutter/test/foundation/leak_tracking.dart b/packages/flutter/test/foundation/leak_tracking.dart deleted file mode 100644 index 1ed364c9fa469..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking.dart +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:core'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; -import 'package:leak_tracker_testing/leak_tracker_testing.dart'; -import 'package:meta/meta.dart'; - -export 'package:leak_tracker/leak_tracker.dart' show LeakDiagnosticConfig, LeakTrackingTestConfig; - -/// Set of objects, that does not hold the objects from garbage collection. -/// -/// The objects are referenced by hash codes and can duplicate with low probability. -@visibleForTesting -class WeakSet { - final Set _objectCodes = {}; - - String _toCode(int hashCode, String type) => '$type-$hashCode'; - - void add(Object object) { - _objectCodes.add(_toCode(identityHashCode(object), object.runtimeType.toString())); - } - - void addByCode(int hashCode, String type) { - _objectCodes.add(_toCode(hashCode, type)); - } - - bool contains(int hashCode, String type) { - final bool result = _objectCodes.contains(_toCode(hashCode, type)); - return result; - } -} - -/// Wrapper for [testWidgets] with memory leak tracking. -/// -/// The method will fail if instrumented objects in [callback] are -/// garbage collected without being disposed. -/// -/// More about leak tracking: -/// https://github.com/dart-lang/leak_tracker. -/// -/// See https://github.com/flutter/devtools/issues/3951 for plans -/// on leak tracking. -@isTest -void testWidgetsWithLeakTracking( - String description, - WidgetTesterCallback callback, { - bool? skip, - Timeout? timeout, - bool semanticsEnabled = true, - TestVariant variant = const DefaultTestVariant(), - dynamic tags, - LeakTrackingTestConfig leakTrackingTestConfig = const LeakTrackingTestConfig(), -}) { - Future wrappedCallback(WidgetTester tester) async { - await _withFlutterLeakTracking( - () async => callback(tester), - tester, - leakTrackingTestConfig, - ); - } - - testWidgets( - description, - wrappedCallback, - skip: skip, - timeout: timeout, - semanticsEnabled: semanticsEnabled, - variant: variant, - tags: tags, - ); -} - -bool _webWarningPrinted = false; - -/// Runs [callback] with leak tracking. -/// -/// Wrapper for [withLeakTracking] with Flutter specific functionality. -/// -/// The method will fail if wrapped code contains memory leaks. -/// -/// See details in documentation for `withLeakTracking` at -/// https://github.com/dart-lang/leak_tracker/blob/main/lib/src/leak_tracking/orchestration.dart -/// -/// The Flutter related enhancements are: -/// 1. Listens to [MemoryAllocations] events. -/// 2. Uses `tester.runAsync` for leak detection if [tester] is provided. -/// -/// Pass [config] to troubleshoot or exempt leaks. See [LeakTrackingTestConfig] -/// for details. -Future _withFlutterLeakTracking( - DartAsyncCallback callback, - WidgetTester tester, - LeakTrackingTestConfig config, -) async { - // Leak tracker does not work for web platform. - if (kIsWeb) { - final bool shouldPrintWarning = !_webWarningPrinted && LeakTrackerGlobalSettings.warnForNonSupportedPlatforms; - if (shouldPrintWarning) { - _webWarningPrinted = true; - debugPrint('Leak tracking is not supported on web platform.\nTo turn off this message, set `LeakTrackingTestConfig.warnForNonSupportedPlatforms` to false.'); - } - await callback(); - return; - } - - void flutterEventToLeakTracker(ObjectEvent event) { - return dispatchObjectEvent(event.toMap()); - } - - return TestAsyncUtils.guard(() async { - MemoryAllocations.instance.addListener(flutterEventToLeakTracker); - Future asyncCodeRunner(DartAsyncCallback action) async => tester.runAsync(action); - - try { - Leaks leaks = await withLeakTracking( - callback, - asyncCodeRunner: asyncCodeRunner, - leakDiagnosticConfig: config.leakDiagnosticConfig, - shouldThrowOnLeaks: false, - ); - - leaks = LeakCleaner(config).clean(leaks); - - if (leaks.total > 0) { - config.onLeaks?.call(leaks); - if (config.failTestOnLeaks) { - expect(leaks, isLeakFree); - } - } - } finally { - MemoryAllocations.instance.removeListener(flutterEventToLeakTracker); - } - }); -} - -/// Cleans leaks that are allowed by [config]. -@visibleForTesting -class LeakCleaner { - LeakCleaner(this.config); - - final LeakTrackingTestConfig config; - - static Map<(String, LeakType), int> _countByClassAndType(Leaks leaks) { - final Map<(String, LeakType), int> result = <(String, LeakType), int>{}; - - for (final MapEntry> entry in leaks.byType.entries) { - for (final LeakReport leak in entry.value) { - final (String, LeakType) classAndType = (leak.type, entry.key); - result[classAndType] = (result[classAndType] ?? 0) + 1; - } - } - return result; - } - - Leaks clean(Leaks leaks) { - final Map<(String, LeakType), int> countByClassAndType = _countByClassAndType(leaks); - - final Leaks result = Leaks(>{ - for (final LeakType leakType in leaks.byType.keys) - leakType: leaks.byType[leakType]!.where((LeakReport leak) => _shouldReportLeak(leakType, leak, countByClassAndType)).toList() - }); - return result; - } - - /// Returns true if [leak] should be reported as failure. - bool _shouldReportLeak(LeakType leakType, LeakReport leak, Map<(String, LeakType), int> countByClassAndType) { - switch (leakType) { - case LeakType.notDisposed: - if (config.allowAllNotDisposed) { - return false; - } - case LeakType.notGCed: - case LeakType.gcedLate: - if (config.allowAllNotGCed) { - return false; - } - } - - final String leakingClass = leak.type; - final (String, LeakType) classAndType = (leakingClass, leakType); - - bool isAllowedForClass(Map allowList) { - if (!allowList.containsKey(leakingClass)) { - return false; - } - final int? allowedCount = allowList[leakingClass]; - if (allowedCount == null) { - return true; - } - return allowedCount >= countByClassAndType[classAndType]!; - } - - switch (leakType) { - case LeakType.notDisposed: - return !isAllowedForClass(config.notDisposedAllowList); - case LeakType.notGCed: - case LeakType.gcedLate: - return !isAllowedForClass(config.notGCedAllowList); - } - } -} diff --git a/packages/flutter/test/foundation/leak_tracking_test.dart b/packages/flutter/test/foundation/leak_tracking_test.dart deleted file mode 100644 index bd02bd2c781dd..0000000000000 --- a/packages/flutter/test/foundation/leak_tracking_test.dart +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/widgets.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker/leak_tracker.dart'; -import 'package:leak_tracker_testing/leak_tracker_testing.dart'; - -import 'leak_tracking.dart'; - -final String _leakTrackedClassName = '$_LeakTrackedClass'; - -Leaks _leaksOfAllTypes() => Leaks(> { - LeakType.notDisposed: [LeakReport(code: 1, context: {}, type:'myNotDisposedClass', trackedClass: 'myTrackedClass')], - LeakType.notGCed: [LeakReport(code: 2, context: {}, type:'myNotGCedClass', trackedClass: 'myTrackedClass')], - LeakType.gcedLate: [LeakReport(code: 3, context: {}, type:'myGCedLateClass', trackedClass: 'myTrackedClass')], -}); - -Future main() async { - test('Trivial $LeakCleaner returns all leaks.', () { - final LeakCleaner leakCleaner = LeakCleaner(const LeakTrackingTestConfig()); - final Leaks leaks = _leaksOfAllTypes(); - final int leakTotal = leaks.total; - - final Leaks cleanedLeaks = leakCleaner.clean(leaks); - - expect(leaks.total, leakTotal); - expect(cleanedLeaks.total, 3); - }); - - test('$LeakCleaner catches extra leaks', () { - Leaks leaks = _leaksOfAllTypes(); - final LeakReport leak = leaks.notDisposed.first; - leaks.notDisposed.add(leak); - - final LeakTrackingTestConfig config = LeakTrackingTestConfig( - notDisposedAllowList: {leak.type: 1}, - ); - leaks = LeakCleaner(config).clean(leaks); - - expect(leaks.notDisposed, hasLength(2)); - }); - - group('Leak tracking works for non-web, and', () { - testWidgetsWithLeakTracking( - 'respects all allow lists', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - notDisposedAllowList: {_leakTrackedClassName: null}, - notGCedAllowList: {_leakTrackedClassName: null}, - ), - ); - - testWidgetsWithLeakTracking( - 'respects allowAllNotDisposed', - (WidgetTester tester) async { - // ignore: avoid_redundant_argument_values, for readability. - await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: true, notGCed: false)); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - allowAllNotDisposed: true, - ), - ); - - testWidgetsWithLeakTracking( - 'respects allowAllNotGCed', - (WidgetTester tester) async { - // ignore: avoid_redundant_argument_values, for readability. - await tester.pumpWidget(_StatelessLeakingWidget(notDisposed: false, notGCed: true)); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - allowAllNotGCed: true, - ), - ); - - testWidgetsWithLeakTracking( - 'respects count in allow lists', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - notDisposedAllowList: {_leakTrackedClassName: 1}, - notGCedAllowList: {_leakTrackedClassName: 1}, - ), - ); - - group('fails if number or leaks is more than allowed', () { - // This test cannot run inside other tests because test nesting is forbidden. - // So, `expect` happens outside the tests, in `tearDown`. - late Leaks leaks; - - testWidgetsWithLeakTracking( - 'for $_StatelessLeakingWidget', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - onLeaks: (Leaks theLeaks) { - leaks = theLeaks; - }, - failTestOnLeaks: false, - notDisposedAllowList: {_leakTrackedClassName: 1}, - ), - ); - - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 2, expectedNotGCed: 2, shouldContainDebugInfo: false)); - }); - - group('respects notGCed allow lists', () { - // These tests cannot run inside other tests because test nesting is forbidden. - // So, `expect` happens outside the tests, in `tearDown`. - late Leaks leaks; - - testWidgetsWithLeakTracking( - 'when $_StatelessLeakingWidget leaks', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - onLeaks: (Leaks theLeaks) { - leaks = theLeaks; - }, - failTestOnLeaks: false, - notGCedAllowList: {_leakTrackedClassName: null}, - ), - ); - - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, shouldContainDebugInfo: false)); - }); - - group('catches that', () { - // These test cannot run inside other tests because test nesting is forbidden. - // So, `expect` happens outside the tests, in `tearDown`. - late Leaks leaks; - - testWidgetsWithLeakTracking( - '$_StatelessLeakingWidget leaks', - (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - leakTrackingTestConfig: LeakTrackingTestConfig( - onLeaks: (Leaks theLeaks) { - leaks = theLeaks; - }, - failTestOnLeaks: false, - ), - ); - - tearDown(() => _verifyLeaks(leaks, expectedNotDisposed: 1, expectedNotGCed: 1, shouldContainDebugInfo: false)); - }); - }, - skip: isBrowser); // [intended] Leak detection is off for web. - - testWidgetsWithLeakTracking('Leak tracking is no-op for web', (WidgetTester tester) async { - await tester.pumpWidget(_StatelessLeakingWidget()); - }, - skip: !isBrowser); // [intended] Leaks detection is off for web. -} - -/// Verifies [leaks] contains expected number of leaks for [_LeakTrackedClass]. -void _verifyLeaks( - Leaks leaks, { - int expectedNotDisposed = 0, - int expectedNotGCed = 0, - required bool shouldContainDebugInfo, -}) { - const String linkToLeakTracker = 'https://github.com/dart-lang/leak_tracker'; - - expect( - () => expect(leaks, isLeakFree), - throwsA( - predicate((Object? e) { - return e is TestFailure && e.toString().contains(linkToLeakTracker); - }), - ), - ); - - _verifyLeakList(leaks.notDisposed, expectedNotDisposed, shouldContainDebugInfo); - _verifyLeakList(leaks.notGCed, expectedNotGCed, shouldContainDebugInfo); -} - -void _verifyLeakList(List list, int expectedCount, bool shouldContainDebugInfo){ - expect(list.length, expectedCount); - - for (final LeakReport leak in list) { - if (shouldContainDebugInfo) { - expect(leak.context, isNotEmpty); - } else { - expect(leak.context ?? {}, isEmpty); - } - - expect(leak.trackedClass, contains(_LeakTrackedClass.library)); - expect(leak.trackedClass, contains(_leakTrackedClassName)); - } -} - -/// Storage to keep disposed objects, to generate not-gced leaks. -final List<_LeakTrackedClass> _notGcedStorage = <_LeakTrackedClass>[]; - -class _StatelessLeakingWidget extends StatelessWidget { - _StatelessLeakingWidget({bool notDisposed = true, bool notGCed = true}) { - if (notDisposed) { - // ignore: unused_local_variable, the variable is used to create non disposed leak - final _LeakTrackedClass notDisposed = _LeakTrackedClass(); - } - if (notGCed) { - _notGcedStorage.add(_LeakTrackedClass()..dispose()); - } - } - - @override - Widget build(BuildContext context) { - return const Placeholder(); - } -} - -class _LeakTrackedClass { - _LeakTrackedClass() { - dispatchObjectCreated( - library: library, - className: '$_LeakTrackedClass', - object: this, - ); - } - - static const String library = 'package:my_package/lib/src/my_lib.dart'; - - void dispose() { - dispatchObjectDisposed(object: this); - } -} diff --git a/packages/flutter/test/gestures/debug_test.dart b/packages/flutter/test/gestures/debug_test.dart index f3f812ccf9c08..6a17b90642978 100644 --- a/packages/flutter/test/gestures/debug_test.dart +++ b/packages/flutter/test/gestures/debug_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('debugPrintGestureArenaDiagnostics', (WidgetTester tester) async { diff --git a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart index 26c2f8ffe3bd0..76d0d82be2498 100644 --- a/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart +++ b/packages/flutter/test/gestures/gesture_binding_resample_event_on_widget_test.dart @@ -9,8 +9,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestResampleEventFlutterBinding extends AutomatedTestWidgetsFlutterBinding { @override diff --git a/packages/flutter/test/gestures/gesture_config_regression_test.dart b/packages/flutter/test/gestures/gesture_config_regression_test.dart index 7fcda721bbf09..b238b5b1033c3 100644 --- a/packages/flutter/test/gestures/gesture_config_regression_test.dart +++ b/packages/flutter/test/gestures/gesture_config_regression_test.dart @@ -6,8 +6,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestResult { bool dragStarted = false; diff --git a/packages/flutter/test/gestures/transformed_double_tap_test.dart b/packages/flutter/test/gestures/transformed_double_tap_test.dart index 38056a658e633..b550ad0f3f966 100644 --- a/packages/flutter/test/gestures/transformed_double_tap_test.dart +++ b/packages/flutter/test/gestures/transformed_double_tap_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('kTouchSlop is evaluated in the global coordinate space when scaled up', (WidgetTester tester) async { diff --git a/packages/flutter/test/gestures/transformed_long_press_test.dart b/packages/flutter/test/gestures/transformed_long_press_test.dart index fcbd38c69a4c8..9e222ca41d56f 100644 --- a/packages/flutter/test/gestures/transformed_long_press_test.dart +++ b/packages/flutter/test/gestures/transformed_long_press_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { diff --git a/packages/flutter/test/gestures/transformed_monodrag_test.dart b/packages/flutter/test/gestures/transformed_monodrag_test.dart index c85bf24cd0c86..1a7c39b6823d0 100644 --- a/packages/flutter/test/gestures/transformed_monodrag_test.dart +++ b/packages/flutter/test/gestures/transformed_monodrag_test.dart @@ -7,12 +7,11 @@ import 'dart:math' as math; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('Horizontal', () { - testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { + testWidgets('gets local coordinates', (WidgetTester tester) async { int dragCancelCount = 0; final List downDetails = []; final List endDetails = []; diff --git a/packages/flutter/test/gestures/transformed_scale_test.dart b/packages/flutter/test/gestures/transformed_scale_test.dart index c01c6548ad3e4..f48b5e8a14d05 100644 --- a/packages/flutter/test/gestures/transformed_scale_test.dart +++ b/packages/flutter/test/gestures/transformed_scale_test.dart @@ -5,10 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { - testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { + testWidgets('gets local coordinates', (WidgetTester tester) async { final List startDetails = []; final List updateDetails = []; diff --git a/packages/flutter/test/gestures/transformed_tap_test.dart b/packages/flutter/test/gestures/transformed_tap_test.dart index 2d3dd3cd48bf0..54868059930c0 100644 --- a/packages/flutter/test/gestures/transformed_tap_test.dart +++ b/packages/flutter/test/gestures/transformed_tap_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('gets local coordinates', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 0199deb48f5c1..7585853dc459b 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -10,8 +10,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { tearDown(() { @@ -58,7 +57,7 @@ void main() { expect(find.text('View licenses'), findsOneWidget); }); - testWidgetsWithLeakTracking('Material2 - AboutListTile control test', (WidgetTester tester) async { + testWidgets('Material2 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -141,7 +140,7 @@ void main() { expect(find.text('Pirate license'), findsOneWidget); }); - testWidgetsWithLeakTracking('Material3 - AboutListTile control test', (WidgetTester tester) async { + testWidgets('Material3 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -1477,7 +1476,7 @@ void main() { expect(find.text('Exception: Injected failure'), findsOneWidget); }); - testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgets('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1542,7 +1541,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgets('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1609,7 +1608,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgets('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1674,7 +1673,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgets('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1741,7 +1740,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgetsWithLeakTracking('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { + testWidgets('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/108991 final ThemeData theme = ThemeData( appBarTheme: const AppBarTheme(foregroundColor: Color(0xFFFFFFFF)), diff --git a/packages/flutter/test/material/action_chip_test.dart b/packages/flutter/test/material/action_chip_test.dart index 879c6fb5bd5ae..310db84c5c4ed 100644 --- a/packages/flutter/test/material/action_chip_test.dart +++ b/packages/flutter/test/material/action_chip_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; /// Adds the basic requirements for a Chip. Widget wrapForChip({ diff --git a/packages/flutter/test/material/action_icons_theme_test.dart b/packages/flutter/test/material/action_icons_theme_test.dart index f69ce2ac7e2ae..37ad357c9dd22 100644 --- a/packages/flutter/test/material/action_icons_theme_test.dart +++ b/packages/flutter/test/material/action_icons_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('ActionIconThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index 41ad77aec6a21..067ced62292ac 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart'; import '../widgets/live_text_utils.dart'; @@ -112,7 +111,7 @@ void main() { expect(find.byKey(key), findsOneWidget); }); - testWidgetsWithLeakTracking('Can build from EditableTextState', (WidgetTester tester) async { + testWidgets('Can build from EditableTextState', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -233,7 +232,7 @@ void main() { ); group('buttonItems', () { - testWidgetsWithLeakTracking('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { + testWidgets('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { // Fill the clipboard so that the Paste option is available in the text // selection menu. await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); @@ -328,7 +327,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgetsWithLeakTracking('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { + testWidgets('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { const String buttonText = 'Click me'; await tester.pumpWidget( diff --git a/packages/flutter/test/material/animated_icons_test.dart b/packages/flutter/test/material/animated_icons_test.dart index b245000b02806..b81df83618104 100644 --- a/packages/flutter/test/material/animated_icons_test.dart +++ b/packages/flutter/test/material/animated_icons_test.dart @@ -9,8 +9,7 @@ import 'dart:math' as math show pi; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; class MockCanvas extends Fake implements Canvas { diff --git a/packages/flutter/test/material/app_builder_test.dart b/packages/flutter/test/material/app_builder_test.dart index aedf2b14f4962..f5b6500ac569a 100644 --- a/packages/flutter/test/material/app_builder_test.dart +++ b/packages/flutter/test/material/app_builder_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking("builder doesn't get called if app doesn't change", (WidgetTester tester) async { diff --git a/packages/flutter/test/material/back_button_test.dart b/packages/flutter/test/material/back_button_test.dart index ef0eb7d112251..9ba330182c168 100644 --- a/packages/flutter/test/material/back_button_test.dart +++ b/packages/flutter/test/material/back_button_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgets('BackButton control test', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/badge_test.dart b/packages/flutter/test/material/badge_test.dart index d51adf08bc30a..b5b5b3c658102 100644 --- a/packages/flutter/test/material/badge_test.dart +++ b/packages/flutter/test/material/badge_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { diff --git a/packages/flutter/test/material/badge_theme_test.dart b/packages/flutter/test/material/badge_theme_test.dart index 9786e5639f1e1..9ab250eaab492 100644 --- a/packages/flutter/test/material/badge_theme_test.dart +++ b/packages/flutter/test/material/badge_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('BadgeThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/banner_test.dart b/packages/flutter/test/material/banner_test.dart index 332cab51ed3f4..4d766fbfc188b 100644 --- a/packages/flutter/test/material/banner_test.dart +++ b/packages/flutter/test/material/banner_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('MaterialBanner properties are respected', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/banner_theme_test.dart b/packages/flutter/test/material/banner_theme_test.dart index 04db7bba26b92..1287699d39cd2 100644 --- a/packages/flutter/test/material/banner_theme_test.dart +++ b/packages/flutter/test/material/banner_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('MaterialBannerThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/bottom_app_bar_test.dart b/packages/flutter/test/material/bottom_app_bar_test.dart index 2c26051617d7b..05f7da0b696d8 100644 --- a/packages/flutter/test/material/bottom_app_bar_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_test.dart @@ -10,8 +10,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('Material3 - Shadow effect is not doubled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123064 diff --git a/packages/flutter/test/material/bottom_app_bar_theme_test.dart b/packages/flutter/test/material/bottom_app_bar_theme_test.dart index eed8f3e01bad9..e3358d1af875f 100644 --- a/packages/flutter/test/material/bottom_app_bar_theme_test.dart +++ b/packages/flutter/test/material/bottom_app_bar_theme_test.dart @@ -9,8 +9,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('BottomAppBarTheme lerp special cases', () { diff --git a/packages/flutter/test/material/bottom_navigation_bar_test.dart b/packages/flutter/test/material/bottom_navigation_bar_test.dart index 92a1ec9af20e1..88f772474a7e4 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_test.dart @@ -12,9 +12,9 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'package:vector_math/vector_math_64.dart' show Vector3; -import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart b/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart index 59b93e01b8092..70ae2b6833771 100644 --- a/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/bottom_navigation_bar_theme_test.dart @@ -6,10 +6,9 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'package:vector_math/vector_math_64.dart' show Vector3; -import '../foundation/leak_tracking.dart'; - void main() { test('BottomNavigationBarThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/bottom_sheet_theme_test.dart b/packages/flutter/test/material/bottom_sheet_theme_test.dart index 0e3593d04aca5..9d203e5ceff77 100644 --- a/packages/flutter/test/material/bottom_sheet_theme_test.dart +++ b/packages/flutter/test/material/bottom_sheet_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('BottomSheetThemeData copyWith, ==, hashCode basics', () { @@ -171,7 +170,7 @@ void main() { expect(material.clipBehavior, clipBehavior); }); - testWidgetsWithLeakTracking('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { + testWidgets('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { const double modalElevation = 5.0; const double persistentElevation = 7.0; const Color modalBackgroundColor = Colors.yellow; @@ -250,7 +249,7 @@ void main() { expect(material.color, null); }); - testWidgetsWithLeakTracking('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { + testWidgets('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { const double lightElevation = 5.0; const double darkElevation = 3.0; const Color lightBackgroundColor = Colors.green; diff --git a/packages/flutter/test/material/button_bar_test.dart b/packages/flutter/test/material/button_bar_test.dart index 16d4e84f0efeb..f7bb7768b3d6e 100644 --- a/packages/flutter/test/material/button_bar_test.dart +++ b/packages/flutter/test/material/button_bar_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('ButtonBar default control smoketest', (WidgetTester tester) async { @@ -341,7 +340,7 @@ void main() { group('layoutBehavior', () { - testWidgetsWithLeakTracking('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { + testWidgets('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( @@ -364,7 +363,7 @@ void main() { expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 52.0); }); - testWidgetsWithLeakTracking('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { + testWidgets('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( diff --git a/packages/flutter/test/material/button_bar_theme_test.dart b/packages/flutter/test/material/button_bar_theme_test.dart index 7e25d30493b21..158c9dbb5176f 100644 --- a/packages/flutter/test/material/button_bar_theme_test.dart +++ b/packages/flutter/test/material/button_bar_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { diff --git a/packages/flutter/test/material/button_style_test.dart b/packages/flutter/test/material/button_style_test.dart index 6ccc97ece5319..f6b096abd5dbe 100644 --- a/packages/flutter/test/material/button_style_test.dart +++ b/packages/flutter/test/material/button_style_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('ButtonStyle copyWith, merge, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/card_test.dart b/packages/flutter/test/material/card_test.dart index 7c9f2658543c2..1f08017a13257 100644 --- a/packages/flutter/test/material/card_test.dart +++ b/packages/flutter/test/material/card_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index 4732591978bdd..ef5f4971ae739 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -8,8 +8,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'feedback_tester.dart'; Widget wrap({ required Widget child }) { @@ -496,6 +495,8 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('CheckboxListTile can be disabled', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index 5beec65073f31..36e23779fac99 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('CheckboxThemeData copyWith, ==, hashCode basics', () { @@ -302,7 +301,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)); }); - testWidgetsWithLeakTracking('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgets('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 24a5943490d85..d098936aa14e3 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -701,7 +700,7 @@ void main() { expect(calledDelete, isFalse); }); - testWidgetsWithLeakTracking('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { + testWidgets('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { final UniqueKey iconKey = UniqueKey(); final Widget test = Overlay( initialEntries: [ @@ -877,7 +876,7 @@ void main() { expect(tester.getSize(find.byKey(keyA)), equals(const Size(20.0, 20.0))); }); - testWidgetsWithLeakTracking('Chip padding - LTR', (WidgetTester tester) async { + testWidgets('Chip padding - LTR', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -913,7 +912,7 @@ void main() { expect(tester.getBottomRight(find.byType(Icon)), const Offset(457.0, 309.0)); }); - testWidgetsWithLeakTracking('Chip padding - RTL', (WidgetTester tester) async { + testWidgets('Chip padding - RTL', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); await tester.pumpWidget( @@ -2633,7 +2632,7 @@ void main() { expect(find.byType(InkWell), findsOneWidget); }); - testWidgetsWithLeakTracking('Chip uses stateful color for text color in different states', (WidgetTester tester) async { + testWidgets('Chip uses stateful color for text color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2721,7 +2720,7 @@ void main() { expect(textColor(), disabledColor); }); - testWidgetsWithLeakTracking('Chip uses stateful border side color in different states', (WidgetTester tester) async { + testWidgets('Chip uses stateful border side color in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2801,7 +2800,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgetsWithLeakTracking('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { + testWidgets('Chip uses stateful border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2882,7 +2881,7 @@ void main() { }); - testWidgetsWithLeakTracking('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { + testWidgets('Chip uses stateful nullable border side color from resolveWith', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); const Color pressedColor = Color(0x00000001); @@ -2971,7 +2970,7 @@ void main() { expect(find.byType(RawChip), paints..rrect()..rrect(color: disabledColor)); }); - testWidgetsWithLeakTracking('Chip uses stateful shape in different states', (WidgetTester tester) async { + testWidgets('Chip uses stateful shape in different states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); OutlinedBorder? getShape(Set states) { @@ -3339,7 +3338,7 @@ void main() { expect(decoration.shape, shape); }); - testWidgetsWithLeakTracking('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { + testWidgets('Chip highlight color is drawn on top of the backgroundColor', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'RawChip'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color backgroundColor = Color(0xff00ff00); diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 13fa9dbf02900..2303b56478cd3 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; RenderBox getMaterialBox(WidgetTester tester) { return tester.firstRenderObject( @@ -641,6 +640,8 @@ void main() { await tester.pumpWidget(chipWidget(enabled: false)); await tester.pumpAndSettle(); expect(textColor(), disabledColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Chip uses stateful border side from resolveWith pattern', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/choice_chip_test.dart b/packages/flutter/test/material/choice_chip_test.dart index 1fcf539520ada..2f97610fd203c 100644 --- a/packages/flutter/test/material/choice_chip_test.dart +++ b/packages/flutter/test/material/choice_chip_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; RenderBox getMaterialBox(WidgetTester tester, Finder type) { return tester.firstRenderObject( diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart index 93ede89c0c7a6..8487f124cf343 100644 --- a/packages/flutter/test/material/circle_avatar_test.dart +++ b/packages/flutter/test/material/circle_avatar_test.dart @@ -12,8 +12,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; import '../painting/mocks_for_image_cache.dart'; diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 356301629fdfa..8b71d9eca43da 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -11,9 +11,9 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'package:vector_math/vector_math_64.dart' show Matrix3; -import '../foundation/leak_tracking.dart'; import 'data_table_test_utils.dart'; void main() { diff --git a/packages/flutter/test/material/data_table_theme_test.dart b/packages/flutter/test/material/data_table_theme_test.dart index 0f922cb0a4801..ea5d19235ce5b 100644 --- a/packages/flutter/test/material/data_table_theme_test.dart +++ b/packages/flutter/test/material/data_table_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('DataTableThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index c9e5c544c26a0..021a85b5db95e 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -8,8 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'feedback_tester.dart'; void main() { @@ -260,6 +259,7 @@ void main() { // https://github.com/flutter/flutter/issues/130354 leakTrackingTestConfig: const LeakTrackingTestConfig( allowAllNotGCed: true, + allowAllNotDisposed: true, )); }); diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index d3d01556d4bae..4ff2481973ef7 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('debugCheckHasMaterial control test', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart b/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart index d42cbc638cffe..e025948ea09d0 100644 --- a/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart +++ b/packages/flutter/test/material/desktop_text_selection_toolbar_button_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart b/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart index 5eb0c67c549b8..3a0652b7b33cd 100644 --- a/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/desktop_text_selection_toolbar_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 4ba0c9b5e0cdb..d26707e98629b 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -9,8 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; MaterialApp _buildAppWithDialog( @@ -2338,7 +2337,7 @@ void main() { }); group('AlertDialog.scrollable: ', () { - testWidgetsWithLeakTracking('Title is scrollable', (WidgetTester tester) async { + testWidgets('Title is scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final AlertDialog dialog = AlertDialog( title: Container( @@ -2378,7 +2377,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0))); }); - testWidgetsWithLeakTracking('Title and content are scrollable', (WidgetTester tester) async { + testWidgets('Title and content are scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final Key contentKey = UniqueKey(); final AlertDialog dialog = AlertDialog( @@ -2511,7 +2510,7 @@ void main() { semantics.dispose(); }); - testWidgetsWithLeakTracking('DialogRoute is state restorable', (WidgetTester tester) async { + testWidgets('DialogRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -2660,6 +2659,9 @@ void main() { expect(await previousFocus(), true); expect(okNode.hasFocus, true); expect(cancelNode.hasFocus, false); + + cancelNode.dispose(); + okNode.dispose(); }); testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { @@ -2764,7 +2766,7 @@ void main() { expect(find.text('Dialog2'), findsOneWidget); }); - testWidgetsWithLeakTracking('Uses open focus traversal when overridden', (WidgetTester tester) async { + testWidgets('Uses open focus traversal when overridden', (WidgetTester tester) async { final FocusNode okNode = FocusNode(); final FocusNode cancelNode = FocusNode(); diff --git a/packages/flutter/test/material/drawer_button_test.dart b/packages/flutter/test/material/drawer_button_test.dart index 872e633e7b1e6..4e42ba7dcd993 100644 --- a/packages/flutter/test/material/drawer_button_test.dart +++ b/packages/flutter/test/material/drawer_button_test.dart @@ -5,11 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('DrawerButton control test', (WidgetTester tester) async { + testWidgets('DrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -171,7 +170,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgetsWithLeakTracking('EndDrawerButton control test', (WidgetTester tester) async { + testWidgets('EndDrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index 6b13161d31c77..582f0e88882cf 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -8,8 +8,6 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - const List menuItems = ['one', 'two', 'three', 'four']; void onChanged(T _) { } final Type dropdownButtonType = DropdownButton( @@ -201,7 +199,7 @@ void main() { expect(hintEmptyLabel, oneValueLabel); }); - testWidgetsWithLeakTracking('label position test - show disabledHint: disable', (WidgetTester tester) async { + testWidgets('label position test - show disabledHint: disable', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -239,7 +237,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgetsWithLeakTracking('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { + testWidgets('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -264,7 +262,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgetsWithLeakTracking('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { + testWidgets('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -314,7 +312,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgetsWithLeakTracking('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { + testWidgets('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -352,7 +350,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 24.0)); }); - testWidgetsWithLeakTracking('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { + testWidgets('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { const int value = 1; await tester.pumpWidget( @@ -392,7 +390,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/82910 - testWidgetsWithLeakTracking('null value test', (WidgetTester tester) async { + testWidgets('null value test', (WidgetTester tester) async { int? value = 1; await tester.pumpWidget( @@ -493,7 +491,7 @@ void main() { expect(value, equals('three')); }); - testWidgetsWithLeakTracking('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); // There shouldn't be overflow when expanded although list contains longer items. @@ -528,7 +526,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -568,7 +566,7 @@ void main() { } }); - testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true does not clip large scale text', + testWidgets('DropdownButtonFormField with isDense:true does not clip large scale text', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -607,7 +605,7 @@ void main() { expect(box.size.height, 72.0); }); - testWidgetsWithLeakTracking('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46844 final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -638,7 +636,7 @@ void main() { expect(box.size.height, 48.0); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - custom text style', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - custom text style', (WidgetTester tester) async { const String value = 'foo'; final UniqueKey itemKey = UniqueKey(); @@ -676,7 +674,7 @@ void main() { expect(richText.text.style!.fontSize, 20.0); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -699,7 +697,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking( + testWidgets( 'DropdownButtonFormField - hint displays when the items list is ' 'empty, items is null, and disabledHint is null', (WidgetTester tester) async { @@ -723,7 +721,7 @@ void main() { }, ); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -743,7 +741,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items }) { @@ -763,7 +761,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items, ValueChanged? onChanged }) { @@ -781,7 +779,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List? items}) { @@ -806,7 +804,7 @@ void main() { expect(enabledHintBox.size, equals(disabledHintBox.size)); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { final Key iconKey = UniqueKey(); final Icon customIcon = Icon(Icons.assessment, key: iconKey); @@ -839,7 +837,7 @@ void main() { expect(disabledRichText.text.style!.color, Colors.orange); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - default elevation', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - default elevation', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); debugDisableShadows = false; await tester.pumpWidget(buildFormFrame( @@ -896,7 +894,7 @@ void main() { debugDisableShadows = true; }); - testWidgetsWithLeakTracking('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'c'] .map>((String value) { return DropdownMenuItem( @@ -925,7 +923,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { final List> itemsWithDuplicateValues = ['a', 'b', 'c', 'd'] .map>((String value) { return DropdownMenuItem( @@ -1090,7 +1088,7 @@ void main() { expect(find.text(currentValue), findsOneWidget); }); - testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -1119,7 +1117,7 @@ void main() { expect(validateCalled, 1); }); - testWidgetsWithLeakTracking('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { + testWidgets('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { await tester.pumpWidget(buildFormFrame( buttonAlignment: AlignmentDirectional.center, items: ['one'], diff --git a/packages/flutter/test/material/dropdown_menu_theme_test.dart b/packages/flutter/test/material/dropdown_menu_theme_test.dart index dcfd4ff75e45f..dabb572db8295 100644 --- a/packages/flutter/test/material/dropdown_menu_theme_test.dart +++ b/packages/flutter/test/material/dropdown_menu_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('DropdownMenuThemeData copyWith, ==, hashCode basics', () { @@ -44,7 +43,7 @@ void main() { expect(description, []); }); - testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -101,7 +100,7 @@ void main() { expect(material.textStyle?.color, themeData.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { + testWidgets('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( dropdownMenuTheme: DropdownMenuThemeData( textStyle: TextStyle( @@ -180,7 +179,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgets('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, @@ -283,7 +282,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgets('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index 0f504b52838c2..34db08eca1982 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -196,6 +195,7 @@ void main() { await gesture.moveTo(center); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -259,6 +259,8 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 1.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('ElevatedButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -334,6 +336,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + + focusNode.dispose(); }); @@ -410,6 +414,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('ElevatedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -534,6 +540,8 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered ElevatedButton responds to mouse-exit', (WidgetTester tester) async { @@ -625,6 +633,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('When ElevatedButton disable, Can not set ElevatedButton focus.', (WidgetTester tester) async { @@ -648,6 +658,9 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + + node.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton work with hover', (WidgetTester tester) async { @@ -703,6 +716,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton work with autofocus', (WidgetTester tester) async { @@ -733,6 +748,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does ElevatedButton contribute semantics', (WidgetTester tester) async { @@ -1667,7 +1684,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('ElevatedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1865,15 +1882,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('ElevatedButton statesController', (WidgetTester tester) async { + testWidgets('ElevatedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('ElevatedButton.icon statesController', (WidgetTester tester) async { + testWidgets('ElevatedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled ElevatedButton statesController', (WidgetTester tester) async { + testWidgets('Disabled ElevatedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/elevated_button_theme_test.dart b/packages/flutter/test/material/elevated_button_theme_test.dart index 449da915d49a1..aa713c23696a2 100644 --- a/packages/flutter/test/material/elevated_button_theme_test.dart +++ b/packages/flutter/test/material/elevated_button_theme_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('ElevatedButtonThemeData lerp special cases', () { diff --git a/packages/flutter/test/material/expand_icon_test.dart b/packages/flutter/test/material/expand_icon_test.dart index 5908befe00f68..b6998cc58f651 100644 --- a/packages/flutter/test/material/expand_icon_test.dart +++ b/packages/flutter/test/material/expand_icon_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Widget wrap({ required Widget child, ThemeData? theme }) { return MaterialApp( diff --git a/packages/flutter/test/material/expansion_panel_test.dart b/packages/flutter/test/material/expansion_panel_test.dart index 0f3c1e6e14496..c60cd9a0cc1d8 100644 --- a/packages/flutter/test/material/expansion_panel_test.dart +++ b/packages/flutter/test/material/expansion_panel_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class SimpleExpansionPanelListTestWidget extends StatefulWidget { const SimpleExpansionPanelListTestWidget({ diff --git a/packages/flutter/test/material/expansion_tile_test.dart b/packages/flutter/test/material/expansion_tile_test.dart index 67634911786ec..3c6d9640a52f1 100644 --- a/packages/flutter/test/material/expansion_tile_test.dart +++ b/packages/flutter/test/material/expansion_tile_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestIcon extends StatefulWidget { const TestIcon({super.key}); diff --git a/packages/flutter/test/material/expansion_tile_theme_test.dart b/packages/flutter/test/material/expansion_tile_theme_test.dart index 582d2486e4400..f21b095156443 100644 --- a/packages/flutter/test/material/expansion_tile_theme_test.dart +++ b/packages/flutter/test/material/expansion_tile_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestIcon extends StatefulWidget { const TestIcon({super.key}); diff --git a/packages/flutter/test/material/feedback_test.dart b/packages/flutter/test/material/feedback_test.dart index 1a1a4ef2a1b29..95cc70b7cb4a6 100644 --- a/packages/flutter/test/material/feedback_test.dart +++ b/packages/flutter/test/material/feedback_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index b2d29c7142cac..2940dac61076e 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -340,6 +339,7 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 0.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton.tonal default overlayColor and elevation resolve pressed state', (WidgetTester tester) async { @@ -405,6 +405,7 @@ void main() { await tester.pumpAndSettle(); expect(elevation(), 0.0); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -480,6 +481,7 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + focusNode.dispose(); }); @@ -556,6 +558,7 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + focusNode.dispose(); }); testWidgetsWithLeakTracking('FilledButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -680,6 +683,7 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered FilledButton responds to mouse-exit', (WidgetTester tester) async { @@ -771,6 +775,7 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); testWidgetsWithLeakTracking('When FilledButton disable, Can not set FilledButton focus.', (WidgetTester tester) async { @@ -794,6 +799,7 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton work with hover', (WidgetTester tester) async { @@ -849,6 +855,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton work with autofocus', (WidgetTester tester) async { @@ -879,6 +886,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does FilledButton contribute semantics', (WidgetTester tester) async { @@ -1741,7 +1749,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1937,15 +1945,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('FilledButton statesController', (WidgetTester tester) async { + testWidgets('FilledButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('FilledButton.icon statesController', (WidgetTester tester) async { + testWidgets('FilledButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled FilledButton statesController', (WidgetTester tester) async { + testWidgets('Disabled FilledButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/filled_button_theme_test.dart b/packages/flutter/test/material/filled_button_theme_test.dart index ab30f3c60e305..2b0ff185dd5a2 100644 --- a/packages/flutter/test/material/filled_button_theme_test.dart +++ b/packages/flutter/test/material/filled_button_theme_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('FilledButtonThemeData lerp special cases', () { diff --git a/packages/flutter/test/material/filter_chip_test.dart b/packages/flutter/test/material/filter_chip_test.dart index 30dbbfed3b28a..3d46afa83fd1b 100644 --- a/packages/flutter/test/material/filter_chip_test.dart +++ b/packages/flutter/test/material/filter_chip_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; /// Adds the basic requirements for a Chip. Widget wrapForChip({ diff --git a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart index 4d481b87b75f7..f66f471b56196 100644 --- a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; final Key blockKey = UniqueKey(); const double expandedAppbarHeight = 250.0; @@ -51,7 +50,7 @@ void main() { expect(topAfterScroll.dy, equals(0.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), @@ -89,7 +88,7 @@ void main() { expect(topAfterScroll.dy, equals(-100.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), diff --git a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart index 4fa49ea9344be..f515061f0c3e4 100644 --- a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart @@ -9,8 +9,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; final Key blockKey = UniqueKey(); const double expandedAppbarHeight = 250.0; @@ -92,7 +91,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -136,7 +135,7 @@ void main() { expect(opacityWidget.opacity, equals(0.0)); }); - testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { + testWidgets('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index 4f37ab2db26d8..b1f34bebd914e 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -10,8 +10,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 932b632617a7f..5b87324bc5a73 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -7,8 +7,7 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('Basic floating action button locations', () { @@ -185,7 +184,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('interrupting motion towards the StartTop location.', (WidgetTester tester) async { + testWidgets('interrupting motion towards the StartTop location.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -198,7 +197,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('interrupting entrance to remove the fab.', (WidgetTester tester) async { + testWidgets('interrupting entrance to remove the fab.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(fab: null, location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -217,7 +216,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('interrupting entrance of a new fab.', (WidgetTester tester) async { + testWidgets('interrupting entrance of a new fab.', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( fab: null, diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 189573dfc0ccf..7cda152c9e057 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -13,8 +13,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -326,7 +325,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -368,6 +367,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(getFABWidget(fabFinder).elevation, 6); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('FlatActionButton mini size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { @@ -785,7 +786,7 @@ void main() { }); // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -909,6 +910,8 @@ void main() { tester.renderObject(find.byType(FloatingActionButton)), paintsExactlyCountTimes(#clipPath, 0), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Can find FloatingActionButton semantics', (WidgetTester tester) async { @@ -1164,7 +1167,7 @@ void main() { expect(tester.widget(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -1206,6 +1209,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(getFABWidget(fabFinder).elevation, 12); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('FloatingActionButton.isExtended', (WidgetTester tester) async { @@ -1327,7 +1332,7 @@ void main() { // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/floating_action_button_theme_test.dart b/packages/flutter/test/material/floating_action_button_theme_test.dart index dcc68ce96cdb8..1c282d714fa32 100644 --- a/packages/flutter/test/material/floating_action_button_theme_test.dart +++ b/packages/flutter/test/material/floating_action_button_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('FloatingActionButtonThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/flutter_logo_test.dart b/packages/flutter/test/material/flutter_logo_test.dart index 284a965c039f2..66d9d2484ebe5 100644 --- a/packages/flutter/test/material/flutter_logo_test.dart +++ b/packages/flutter/test/material/flutter_logo_test.dart @@ -9,8 +9,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('Flutter Logo golden test', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/grid_title_test.dart b/packages/flutter/test/material/grid_title_test.dart index bd4f17297bee3..ff5bd5bd5f7ad 100644 --- a/packages/flutter/test/material/grid_title_test.dart +++ b/packages/flutter/test/material/grid_title_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('GridTile control test', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 19ea27f0ad222..fce7855170a55 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -7,8 +7,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -100,13 +99,14 @@ void main() { testWidgetsWithLeakTracking('when both iconSize and IconTheme.of(context).size are null, size falls back to 24.0', (WidgetTester tester) async { final bool material3 = theme.useMaterial3; + final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget( wrap( useMaterial3: material3, child: IconTheme( data: const IconThemeData(), child: IconButton( - focusNode: FocusNode(debugLabel: 'Ink Focus'), + focusNode: focusNode, onPressed: mockOnPressedFunction.handler, icon: const Icon(Icons.link), ), @@ -116,6 +116,8 @@ void main() { final RenderBox icon = tester.renderObject(find.byType(Icon)); expect(icon.size, const Size(24.0, 24.0)); + + focusNode.dispose(); }); testWidgets('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async { @@ -739,6 +741,8 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('IconButton keeps focus when disabled in directional navigation mode.', (WidgetTester tester) async { @@ -781,6 +785,8 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isTrue); + + focusNode.dispose(); }); testWidgetsWithLeakTracking("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { @@ -817,6 +823,9 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); group('feedback', () { @@ -1240,6 +1249,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('IconButton.fill defaults - M3', (WidgetTester tester) async { @@ -1379,6 +1390,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onPrimary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.fill defaults - M3', (WidgetTester tester) async { @@ -1633,6 +1646,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSecondaryContainer.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.filledTonal defaults - M3', (WidgetTester tester) async { @@ -1887,6 +1902,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.onSurfaceVariant.withOpacity(0.08))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Toggleable IconButton.outlined defaults - M3', (WidgetTester tester) async { @@ -2047,6 +2064,8 @@ void main() { await expectLater(tester, meetsGuideline(textContrastGuideline)); await gesture.removePointer(); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -2135,6 +2154,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does IconButton contribute semantics - M3', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/icon_button_theme_test.dart b/packages/flutter/test/material/icon_button_theme_test.dart index 20b2889b85d30..f0f3c8cd89fb5 100644 --- a/packages/flutter/test/material/icon_button_theme_test.dart +++ b/packages/flutter/test/material/icon_button_theme_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('IconButtonThemeData lerp special cases', () { diff --git a/packages/flutter/test/material/icons_test.dart b/packages/flutter/test/material/icons_test.dart index 01bd6c4cd19b4..adc51f4d32fd3 100644 --- a/packages/flutter/test/material/icons_test.dart +++ b/packages/flutter/test/material/icons_test.dart @@ -12,10 +12,9 @@ import 'package:file/local.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'package:platform/platform.dart'; -import '../foundation/leak_tracking.dart'; - void main() { testWidgetsWithLeakTracking('IconData object test', (WidgetTester tester) async { expect(Icons.account_balance, isNot(equals(Icons.account_box))); diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index 5dc4710697c9c..082e1a42efd32 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('The Ink widget expands when no dimensions are set', (WidgetTester tester) async { @@ -271,7 +270,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { + testWidgets('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); @@ -454,7 +453,7 @@ void main() { })); }); - testWidgetsWithLeakTracking('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { + testWidgets('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { final OverlayPortalController controller = OverlayPortalController(); controller.show(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/ink_sparkle_test.dart b/packages/flutter/test/material/ink_sparkle_test.dart index 707c0d934d6af..40b47d7625173 100644 --- a/packages/flutter/test/material/ink_sparkle_test.dart +++ b/packages/flutter/test/material/ink_sparkle_test.dart @@ -10,8 +10,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/src/foundation/constants.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('InkSparkle in a Button compiles and does not crash', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/ink_splash_test.dart b/packages/flutter/test/material/ink_splash_test.dart index aee79794695ad..ceb1c4b114f49 100644 --- a/packages/flutter/test/material/ink_splash_test.dart +++ b/packages/flutter/test/material/ink_splash_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/21506. diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index 1019d9bf4cab6..ed2a5411f3d8b 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/src/services/keyboard_key.g.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -250,6 +249,7 @@ void main() { inkFeatures, paints ..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response changes color on focus with overlayColor', (WidgetTester tester) async { @@ -298,6 +298,7 @@ void main() { inkFeatures, paints..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink well changes color on pressed with overlayColor', (WidgetTester tester) async { @@ -370,6 +371,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..circle(x: 50, y: 50, color: splashColor)); await gesture.up(); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response splashColor matches resolved overlayColor for MaterialState.pressed', (WidgetTester tester) async { @@ -419,6 +421,7 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..circle(x: 50, y: 50, color: splashColor)); await gesture.up(); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response uses radius for focus highlight', (WidgetTester tester) async { @@ -449,6 +452,7 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell uses borderRadius for focus highlight', (WidgetTester tester) async { @@ -485,6 +489,7 @@ void main() { rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(10)), color: const Color(0xff0000ff), )); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell uses borderRadius for hover highlight', (WidgetTester tester) async { @@ -576,6 +581,7 @@ void main() { sampleSize: 100, )), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell customBorder clips for hover highlight', (WidgetTester tester) async { @@ -667,6 +673,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 1)); expect(inkFeatures, paints..circle(radius: 20, color: const Color(0xff0000ff))); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkResponse highlightShape can be updated', (WidgetTester tester) async { @@ -708,6 +715,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); expect(inkFeatures, paintsExactlyCountTimes(#drawRRect, 1)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell borderRadius can be updated', (WidgetTester tester) async { @@ -753,6 +761,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t rrect: RRect.fromLTRBR(350.0, 250.0, 450.0, 350.0, const Radius.circular(30)), color: const Color(0xff0000ff), )); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell customBorder can be updated', (WidgetTester tester) async { @@ -820,6 +829,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t sampleSize: 100, )), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell splash customBorder can be updated', (WidgetTester tester) async { @@ -908,6 +918,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await gesture.up(); + focusNode.dispose(); }); testWidgetsWithLeakTracking("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async { @@ -940,6 +951,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t focusNode.requestFocus(); await tester.pumpAndSettle(); expect(inkFeatures, paintsExactlyCountTimes(#drawRect, 0)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('InkWell.mouseCursor changes cursor on hover', (WidgetTester tester) async { @@ -1029,7 +1041,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1218,6 +1230,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking('ink response accepts focus when disabled in directional navigation mode', (WidgetTester tester) async { @@ -1264,6 +1277,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t ); await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isTrue); + focusNode.dispose(); }); testWidgetsWithLeakTracking("ink response doesn't hover when disabled", (WidgetTester tester) async { @@ -1317,6 +1331,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking('When ink wells are nested, only the inner one is triggered by tap splash', (WidgetTester tester) async { @@ -2071,7 +2086,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); }); - testWidgetsWithLeakTracking('InkWell dispose statesController', (WidgetTester tester) async { + testWidgets('InkWell disposes statesController', (WidgetTester tester) async { int tapCount = 0; Widget buildFrame(MaterialStatesController? statesController) { return MaterialApp( diff --git a/packages/flutter/test/material/input_chip_test.dart b/packages/flutter/test/material/input_chip_test.dart index a7f341072de94..bb43b64cf4661 100644 --- a/packages/flutter/test/material/input_chip_test.dart +++ b/packages/flutter/test/material/input_chip_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; /// Adds the basic requirements for a Chip. Widget wrapForChip({ @@ -241,6 +240,8 @@ void main() { ); await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('cannot be traversed to when disabled', (WidgetTester tester) async { @@ -276,6 +277,9 @@ void main() { await tester.pump(); expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); testWidgetsWithLeakTracking('Input chip check mark color is determined by platform brightness when light', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/input_date_picker_form_field_test.dart b/packages/flutter/test/material/input_date_picker_form_field_test.dart index 50275ffe79cca..076b3978f41a0 100644 --- a/packages/flutter/test/material/input_date_picker_form_field_test.dart +++ b/packages/flutter/test/material/input_date_picker_form_field_test.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; import '../widgets/clipboard_utils.dart'; class TestMaterialLocalizations extends DefaultMaterialLocalizations { @@ -98,7 +97,7 @@ void main() { group('InputDatePickerFormField', () { - testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { + testWidgets('Initial date is the default', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); final DateTime initialDate = DateTime(2016, DateTime.february, 21); DateTime? inputDate; @@ -112,7 +111,7 @@ void main() { expect(inputDate, equals(initialDate)); }); - testWidgetsWithLeakTracking('Changing initial date is reflected in text value', (WidgetTester tester) async { + testWidgets('Changing initial date is reflected in text value', (WidgetTester tester) async { final DateTime initialDate = DateTime(2016, DateTime.february, 21); final DateTime updatedInitialDate = DateTime(2016, DateTime.february, 23); await tester.pumpWidget(inputDatePickerField( @@ -127,7 +126,7 @@ void main() { expect(textFieldController(tester).value.text, equals('02/23/2016')); }); - testWidgetsWithLeakTracking('Valid date entry', (WidgetTester tester) async { + testWidgets('Valid date entry', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -140,7 +139,7 @@ void main() { expect(inputDate, equals(DateTime(2016, DateTime.february, 21))); }); - testWidgetsWithLeakTracking('Invalid text entry shows errorFormat text', (WidgetTester tester) async { + testWidgets('Invalid text entry shows errorFormat text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -167,7 +166,7 @@ void main() { expect(find.text('That is not a date.'), findsOneWidget); }); - testWidgetsWithLeakTracking('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { + testWidgets('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -202,7 +201,7 @@ void main() { expect(find.text('Not in given range.'), findsOneWidget); }); - testWidgetsWithLeakTracking('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { + testWidgets('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -228,7 +227,7 @@ void main() { expect(find.text('Out of range.'), findsNothing); }); - testWidgetsWithLeakTracking('Empty field shows hint text when focused', (WidgetTester tester) async { + testWidgets('Empty field shows hint text when focused', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Focus on it await tester.tap(find.byType(TextField)); @@ -251,7 +250,7 @@ void main() { expect(textOpacity(tester, 'Enter some date'), equals(0.0)); }); - testWidgetsWithLeakTracking('Label text', (WidgetTester tester) async { + testWidgets('Label text', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Default label expect(find.text('Enter Date'), findsOneWidget); @@ -263,7 +262,7 @@ void main() { expect(find.text('Give me a date!'), findsOneWidget); }); - testWidgetsWithLeakTracking('Semantics', (WidgetTester tester) async { + testWidgets('Semantics', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); // Fill the clipboard so that the Paste option is available in the text @@ -292,7 +291,7 @@ void main() { semantics.dispose(); }); - testWidgetsWithLeakTracking('InputDecorationTheme is honored', (WidgetTester tester) async { + testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async { const InputBorder border = InputBorder.none; await tester.pumpWidget(inputDatePickerField( theme: ThemeData.from(colorScheme: const ColorScheme.light()).copyWith( @@ -326,7 +325,7 @@ void main() { expect(containerColor, equals(Colors.transparent)); }); - testWidgetsWithLeakTracking('Date text localization', (WidgetTester tester) async { + testWidgets('Date text localization', (WidgetTester tester) async { final Iterable> delegates = >[ TestMaterialLocalizationsDelegate(), DefaultWidgetsLocalizations.delegate, @@ -349,7 +348,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { + testWidgets('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( @@ -364,7 +363,7 @@ void main() { expect(find.text(errorFormatText), findsNothing); }); - testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { + testWidgets('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index c80d641bd630e..8e491d7193b26 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -10,8 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -906,6 +905,8 @@ void main() { rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), ), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('ListTile can be hovered and has correct hover color', (WidgetTester tester) async { @@ -1236,6 +1237,8 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('ListTile respects tileColor & selectedTileColor', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index f07f79528b6a3..8b92ae3ab60ee 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestIcon extends StatefulWidget { const TestIcon({ super.key }); @@ -568,7 +567,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgetsWithLeakTracking('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { + testWidgets('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/106303 final GlobalKey scaffoldKey = GlobalKey(); diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart index 83b3738f0577e..7382be5ac2b9c 100644 --- a/packages/flutter/test/material/localizations_test.dart +++ b/packages/flutter/test/material/localizations_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('English translations exist for all MaterialLocalizations properties', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/magnifier_test.dart b/packages/flutter/test/material/magnifier_test.dart index f700ca40c95ae..9abf8906b2fcd 100644 --- a/packages/flutter/test/material/magnifier_test.dart +++ b/packages/flutter/test/material/magnifier_test.dart @@ -9,8 +9,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { final MagnifierController magnifierController = MagnifierController(); const Rect reasonableTextField = Rect.fromLTRB(50, 100, 200, 100); @@ -112,7 +110,7 @@ void main() { group('magnifier', () { group('position', () { - testWidgetsWithLeakTracking( + testWidgets( 'should be at gesture position if does not violate any positioning rules', (WidgetTester tester) async { final Key textField = UniqueKey(); @@ -168,7 +166,7 @@ void main() { ); }); - testWidgetsWithLeakTracking( + testWidgets( 'should never move outside the right bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -201,7 +199,7 @@ void main() { lessThanOrEqualTo(reasonableTextField.right)); }); - testWidgetsWithLeakTracking( + testWidgets( 'should never move outside the left bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -233,7 +231,7 @@ void main() { greaterThanOrEqualTo(reasonableTextField.left)); }); - testWidgetsWithLeakTracking('should position vertically at the center of the line', (WidgetTester tester) async { + testWidgets('should position vertically at the center of the line', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), )); @@ -256,7 +254,7 @@ void main() { reasonableTextField.center.dy - basicOffset.dy); }); - testWidgetsWithLeakTracking('should reposition vertically if mashed against the ceiling', + testWidgets('should reposition vertically if mashed against the ceiling', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = Rect.fromPoints(Offset.zero, const Offset(200, 0)); @@ -291,7 +289,7 @@ void main() { return magnifier.additionalFocalPointOffset; } - testWidgetsWithLeakTracking( + testWidgets( 'should shift focal point so that the lens sees nothing out of bounds', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( @@ -319,7 +317,7 @@ void main() { lessThan(reasonableTextField.left)); }); - testWidgetsWithLeakTracking( + testWidgets( 'focal point should shift if mashed against the top to always point to text', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = @@ -356,7 +354,7 @@ void main() { return animatedPositioned.duration.compareTo(Duration.zero) != 0; } - testWidgetsWithLeakTracking('should not be animated on the initial state', + testWidgets('should not be animated on the initial state', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -381,7 +379,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgetsWithLeakTracking('should not be animated on horizontal shifts', + testWidgets('should not be animated on horizontal shifts', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -415,7 +413,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgetsWithLeakTracking('should be animated on vertical shifts', + testWidgets('should be animated on vertical shifts', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); @@ -451,7 +449,7 @@ void main() { expect(getIsAnimated(tester), true); }); - testWidgetsWithLeakTracking('should stop being animated when timer is up', + testWidgets('should stop being animated when timer is up', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); diff --git a/packages/flutter/test/material/material_button_test.dart b/packages/flutter/test/material/material_button_test.dart index 1e79a48320e01..3ef6687f05f98 100644 --- a/packages/flutter/test/material/material_button_test.dart +++ b/packages/flutter/test/material/material_button_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -143,6 +142,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('MaterialButton elevation and colors have proper precedence', (WidgetTester tester) async { @@ -215,6 +216,8 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)..rect(color: highlightColor)); expect(material.elevation, equals(highlightElevation)); await gesture2.up(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking("MaterialButton's disabledColor takes precedence over its default disabled color.", (WidgetTester tester) async { @@ -299,6 +302,8 @@ void main() { await tester.pump(); expect(focusNode.hasPrimaryFocus, isTrue); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('MaterialButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/material_state_mixin_test.dart b/packages/flutter/test/material/material_state_mixin_test.dart index 684fe32e34fc7..f45afb6539ff1 100644 --- a/packages/flutter/test/material/material_state_mixin_test.dart +++ b/packages/flutter/test/material/material_state_mixin_test.dart @@ -6,8 +6,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Key key = Key('testContainer'); const Color trueColor = Colors.red; diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index e717fb242eafc..cbf76ec4de523 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -10,8 +10,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/test_border.dart' show TestBorder; class NotifyMaterial extends StatelessWidget { diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index e5a8536754946..2b9dabe7f403d 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { void onPressed(TestMenu item) {} @@ -54,7 +53,7 @@ void main() { expect(identical(MenuBarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { + testWidgets('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_style_test.dart b/packages/flutter/test/material/menu_style_test.dart index acc6d2079761f..dc501b68bc386 100644 --- a/packages/flutter/test/material/menu_style_test.dart +++ b/packages/flutter/test/material/menu_style_test.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; void main() { Finder findMenuPanels() { @@ -43,7 +42,7 @@ void main() { expect(identical(MenuStyle.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('fixedSize affects geometry', (WidgetTester tester) async { + testWidgets('fixedSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -86,7 +85,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgetsWithLeakTracking('maximumSize affects geometry', (WidgetTester tester) async { + testWidgets('maximumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -129,7 +128,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgetsWithLeakTracking('minimumSize affects geometry', (WidgetTester tester) async { + testWidgets('minimumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -172,7 +171,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(300.0, 300.0))); }); - testWidgetsWithLeakTracking('Material parameters are honored', (WidgetTester tester) async { + testWidgets('Material parameters are honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -238,7 +237,7 @@ void main() { expect(panelPadding.padding, equals(const EdgeInsets.all(20))); }); - testWidgetsWithLeakTracking('visual density', (WidgetTester tester) async { + testWidgets('visual density', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index 868d4eb7f93de..bb4c0cd3ce973 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -4,8 +4,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; -import '../foundation/leak_tracking.dart'; void main() { void onPressed(TestMenu item) {} @@ -54,7 +54,7 @@ void main() { expect(identical(MenuThemeData.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { + testWidgets('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -107,7 +107,8 @@ void main() { expect(subMenuMaterial.color, equals(Colors.red)); }); - testWidgetsWithLeakTracking('Constructor parameters override theme parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Constructor parameters override theme parameters', + (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/mergeable_material_test.dart b/packages/flutter/test/material/mergeable_material_test.dart index 1d184edb0f5eb..7598403270286 100644 --- a/packages/flutter/test/material/mergeable_material_test.dart +++ b/packages/flutter/test/material/mergeable_material_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; enum RadiusType { Sharp, @@ -80,7 +79,7 @@ void main() { expect(box.size.height, equals(0)); }); - testWidgetsWithLeakTracking('MergeableMaterial update slice', (WidgetTester tester) async { + testWidgets('MergeableMaterial update slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -234,7 +233,7 @@ void main() { debugDisableShadows = true; }); - testWidgetsWithLeakTracking('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { + testWidgets('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( const MaterialApp( @@ -1168,7 +1167,7 @@ void main() { ); } - testWidgetsWithLeakTracking('MergeableMaterial dividers', (WidgetTester tester) async { + testWidgets('MergeableMaterial dividers', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1330,7 +1329,7 @@ void main() { expect(decoration.border!.top.color, dividerColor); }); - testWidgetsWithLeakTracking('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { + testWidgets('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { const Color themeCardColor = Colors.red; const Color materialSliceColor = Colors.green; diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index 1736729c911db..f38a4830f6617 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -13,8 +13,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('Navigation bar updates destinations when tapped', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index 0e1ce6dafb091..71d27bafc23d1 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -11,8 +11,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index 2e8befad6de7f..cde4e4eb0eace 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -5,10 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { - testWidgetsWithLeakTracking('Navigation drawer updates destinations when tapped', + testWidgets('Navigation drawer updates destinations when tapped', (WidgetTester tester) async { int mutatedIndex = -1; final GlobalKey scaffoldKey = GlobalKey(); @@ -51,7 +49,7 @@ void main() { expect(mutatedIndex, 0); }); - testWidgetsWithLeakTracking('NavigationDrawer can update background color', + testWidgets('NavigationDrawer can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; final GlobalKey scaffoldKey = GlobalKey(); @@ -84,7 +82,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgetsWithLeakTracking('NavigationDrawer can update elevation', + testWidgets('NavigationDrawer can update elevation', (WidgetTester tester) async { const double elevation = 42.0; final GlobalKey scaffoldKey = GlobalKey(); @@ -116,7 +114,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(elevation)); }); - testWidgetsWithLeakTracking( + testWidgets( 'NavigationDrawer uses proper defaults when no parameters are given', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -165,7 +163,7 @@ void main() { expect(iconBox.size, const Size(24.0, 24.0)); }); - testWidgetsWithLeakTracking('Navigation drawer is scrollable', (WidgetTester tester) async { + testWidgets('Navigation drawer is scrollable', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 500, viewHeight: 300); await tester.pumpWidget( @@ -212,7 +210,7 @@ void main() { expect(find.text('Label10'), findsNothing); }); - testWidgetsWithLeakTracking('Safe Area test', (WidgetTester tester) async { + testWidgets('Safe Area test', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const double viewHeight = 300; widgetSetup(tester, 500, viewHeight: viewHeight); @@ -253,7 +251,7 @@ void main() { expect(tester.getBottomRight(find.widgetWithText(NavigationDrawerDestination,'Label4')).dy, viewHeight); }); - testWidgetsWithLeakTracking('Navigation drawer semantics', (WidgetTester tester) async { + testWidgets('Navigation drawer semantics', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme= ThemeData.from(colorScheme: const ColorScheme.light()); Widget widget({int selectedIndex = 0}) { @@ -323,7 +321,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); @@ -374,7 +372,7 @@ void main() { expect(_getInkWell(tester)?.customBorder, shape); }); - testWidgetsWithLeakTracking('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { + testWidgets('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 3000, viewHeight: 3000); final Widget widget = _buildWidget( diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index d2872221da20c..b94dc65194656 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 61a14a6b968cc..a147a4651e65c 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -227,6 +226,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does OutlinedButton work with hover', (WidgetTester tester) async { @@ -285,6 +286,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does OutlinedButton work with autofocus', (WidgetTester tester) async { @@ -315,6 +318,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgets('Default OutlinedButton meets a11y contrast guidelines', (WidgetTester tester) async { @@ -360,6 +365,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -429,6 +436,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -498,6 +507,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton uses stateful color for icon color in different states', (WidgetTester tester) async { @@ -565,6 +576,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton uses stateful color for border color in different states', (WidgetTester tester) async { @@ -633,6 +646,8 @@ void main() { await gesture.down(center); await tester.pumpAndSettle(); expect(outlinedButton, paints..drrect(color: pressedColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('OutlinedButton onPressed and onLongPress callbacks are correctly called when non-null', (WidgetTester tester) async { @@ -727,6 +742,8 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered OutlinedButton responds to mouse-exit', (WidgetTester tester) async { @@ -818,6 +835,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('When OutlinedButton disable, Can not set OutlinedButton focus.', (WidgetTester tester) async { @@ -841,6 +860,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking("Outline button doesn't crash if disabled during a gesture", (WidgetTester tester) async { @@ -1816,7 +1837,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1969,15 +1990,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('OutlinedButton statesController', (WidgetTester tester) async { + testWidgets('OutlinedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('OutlinedButton.icon statesController', (WidgetTester tester) async { + testWidgets('OutlinedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled OutlinedButton statesController', (WidgetTester tester) async { + testWidgets('Disabled OutlinedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/outlined_button_theme_test.dart b/packages/flutter/test/material/outlined_button_theme_test.dart index 57a57f4e7bf4b..d29697eaa896f 100644 --- a/packages/flutter/test/material/outlined_button_theme_test.dart +++ b/packages/flutter/test/material/outlined_button_theme_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('OutlinedButtonThemeData lerp special cases', () { diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 2a46455781e12..3d2d0fed6193e 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Color kSelectedColor = Color(0xFF00FF00); const Color kUnselectedColor = Colors.transparent; @@ -208,7 +207,7 @@ void main() { expect(indicatorColors(tester), const [kBlue, kRed, kRed]); }); - testWidgetsWithLeakTracking('PageSelector indicatorSize', (WidgetTester tester) async { + testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart index d43fdc737c424..210bc065c5785 100644 --- a/packages/flutter/test/material/page_transitions_theme_test.dart +++ b/packages/flutter/test/material/page_transitions_theme_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('Default PageTransitionsTheme platform', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/persistent_bottom_sheet_test.dart b/packages/flutter/test/material/persistent_bottom_sheet_test.dart index eb7c6eec93f7d..cb8025e14f91c 100644 --- a/packages/flutter/test/material/persistent_bottom_sheet_test.dart +++ b/packages/flutter/test/material/persistent_bottom_sheet_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Pumps and ensures that the BottomSheet animates non-linearly. @@ -124,7 +123,7 @@ void main() { expect(buildCount, equals(2)); }); - testWidgetsWithLeakTracking('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { + testWidgets('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: const Center(child: Text('body')), @@ -187,7 +186,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgetsWithLeakTracking('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { + testWidgets('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -299,7 +298,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgetsWithLeakTracking('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { + testWidgets('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -410,7 +409,7 @@ void main() { expect(find.text('Item 22'), findsNothing); }); - testWidgetsWithLeakTracking('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { + testWidgets('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( @@ -590,7 +589,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/71435 - testWidgetsWithLeakTracking( + testWidgets( 'Scaffold.bottomSheet should be updated without creating a new RO' ' when the new widget has the same key and type.', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index 4096d698f8e5f..f17caec690199 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; PopupMenuThemeData _popupMenuThemeM2() { return PopupMenuThemeData( diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 21545cb3f83b2..2c1a72ce88fa6 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -17,8 +17,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { final ThemeData theme = ThemeData(); diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index 4ad6e7e9cbdcd..f3605238b43c4 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -16,8 +16,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -584,6 +583,7 @@ void main() { ..circle(color: const Color(0x61000000)) ..circle(color: const Color(0x61000000)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio is focusable and has correct focus color', (WidgetTester tester) async { @@ -662,6 +662,7 @@ void main() { ..circle(color: theme.colorScheme.onSurface.withOpacity(0.38)) ..circle(color: theme.colorScheme.onSurface.withOpacity(0.38)), ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Radio can be hovered and has correct hover color', (WidgetTester tester) async { @@ -908,6 +909,8 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.space); await tester.pumpAndSettle(); expect(groupValue, equals(2)); + + focusNode2.dispose(); }); testWidgetsWithLeakTracking('Radio responds to density changes.', (WidgetTester tester) async { @@ -1224,6 +1227,8 @@ void main() { ..circle(color: theme.hoverColor) ..circle(color: hoveredFillColor), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio fill color resolves in hovered/focused states', (WidgetTester tester) async { @@ -1302,6 +1307,8 @@ void main() { ..circle(color: theme.colorScheme.primary.withOpacity(0.08)) ..circle(color: hoveredFillColor), ); + + focusNode.dispose(); }); testWidgets('Radio overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { @@ -1447,6 +1454,8 @@ void main() { ), reason: 'Hovered Radio should use overlay color $hoverOverlayColor over $hoverColor', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { @@ -1710,6 +1719,8 @@ void main() { Material.of(tester.element(find.byType(Radio))), paints..circle(color: theme.hoverColor)..circle(color: colors.secondary) ); + + focusNode.dispose(); }); testWidgets('Material3 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { @@ -1796,6 +1807,8 @@ void main() { Material.of(tester.element(find.byType(Radio))), paints..circle(color: colors.primary.withOpacity(0.08))..circle(color: colors.primary.withOpacity(1)) ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Radio.adaptive shows the correct platform widget', (WidgetTester tester) async { @@ -1892,6 +1905,7 @@ void main() { ..circle(color: theme.focusColor) ..circle(color: theme.colorScheme.secondary) ); + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Radio default overlayColor and fillColor resolves pressed state', (WidgetTester tester) async { @@ -1957,5 +1971,6 @@ void main() { ..circle(color: theme.colorScheme.primary.withOpacity(0.12)) ..circle(color: theme.colorScheme.primary) ); + focusNode.dispose(); }); } diff --git a/packages/flutter/test/material/radio_theme_test.dart b/packages/flutter/test/material/radio_theme_test.dart index d763972842ae5..5c8c186121629 100644 --- a/packages/flutter/test/material/radio_theme_test.dart +++ b/packages/flutter/test/material/radio_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('RadioThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index 0f4f2270469f9..f89cfe9957337 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -9,11 +9,9 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { // Regression test for https://github.com/flutter/flutter/issues/105833 - testWidgetsWithLeakTracking('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { RangeValues values = const RangeValues(0.1, 0.5); bool dragStarted = false; final Key sliderKey = UniqueKey(); @@ -119,7 +117,7 @@ void main() { expect(dragStarted, false); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -173,7 +171,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -227,7 +225,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -285,7 +283,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -343,7 +341,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -387,7 +385,7 @@ void main() { expect(values.end, equals(1)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -431,7 +429,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -477,7 +475,7 @@ void main() { expect(values.end, equals(100)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -523,7 +521,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -573,7 +571,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -623,7 +621,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -675,7 +673,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -727,7 +725,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -777,7 +775,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -827,7 +825,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -879,7 +877,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -931,7 +929,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { + testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); RangeValues? startValues; RangeValues? endValues; @@ -985,7 +983,7 @@ void main() { expect(endValues!.end, moreOrLessEquals(70, epsilon: 1)); }); - testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { + testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); late RangeValues startValues; late RangeValues endValues; @@ -1100,7 +1098,7 @@ void main() { ); } - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1129,7 +1127,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1157,7 +1155,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1184,7 +1182,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1217,7 +1215,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1247,7 +1245,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1288,7 +1286,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1308,7 +1306,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { + testWidgets('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1497,7 +1495,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1564,7 +1562,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1638,7 +1636,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { + testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1715,7 +1713,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgets('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1796,7 +1794,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101868 - testWidgetsWithLeakTracking('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { + testWidgets('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1854,7 +1852,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Range Slider Semantics - ltr', (WidgetTester tester) async { + testWidgets('Range Slider Semantics - ltr', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1938,7 +1936,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Range Slider Semantics - rtl', (WidgetTester tester) async { + testWidgets('Range Slider Semantics - rtl', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -2020,7 +2018,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Range Slider implements debugFillProperties', (WidgetTester tester) async { + testWidgets('Range Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); RangeSlider( @@ -2051,7 +2049,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { + testWidgets('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -2090,7 +2088,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { + testWidgets('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -2135,7 +2133,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { + testWidgets('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { // Regress test for https://github.com/flutter/flutter/issues/65943 Widget buildFrame(double maxValue) { return MaterialApp( @@ -2179,7 +2177,7 @@ void main() { expect(nearEqual(activeTrackRect.right, (800.0 - 24.0 - 24.0) * (8 / 15) + 24.0, 0.01), true); }); - testWidgetsWithLeakTracking('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { const RangeValues values = RangeValues(50, 70); // Test default cursor. @@ -2234,7 +2232,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgetsWithLeakTracking('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { + testWidgets('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { RangeValues values = const RangeValues(50, 70); const MouseCursor disabledCursor = SystemMouseCursors.basic; const MouseCursor hoveredCursor = SystemMouseCursors.grab; @@ -2308,7 +2306,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), draggedCursor); }); - testWidgetsWithLeakTracking('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgets('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2371,7 +2369,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgets('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2427,7 +2425,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { + testWidgets('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); const Color hoverColor = Color(0xffff0000); @@ -2542,7 +2540,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgets('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128433 int startFired = 0; diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index 2306e083df160..3736ab1a31c3f 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -8,8 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/src/services/keyboard_key.g.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -108,6 +107,7 @@ void main() { await tester.pumpAndSettle(); expect(pressed, isTrue); + focusNode.dispose(); }); testWidgetsWithLeakTracking('materialTapTargetSize.padded expands hit test area', (WidgetTester tester) async { @@ -345,6 +345,7 @@ void main() { await tester.pumpAndSettle(const Duration(seconds: 1)); expect(box, paints..rect(color: focusColor)); + focusNode.dispose(); }); testWidgetsWithLeakTracking('RawMaterialButton loses focus when disabled.', (WidgetTester tester) async { @@ -379,6 +380,7 @@ void main() { await tester.pump(); expect(focusNode.hasPrimaryFocus, isFalse); + focusNode.dispose(); }); testWidgetsWithLeakTracking("Disabled RawMaterialButton can't be traversed to.", (WidgetTester tester) async { @@ -419,6 +421,9 @@ void main() { expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); testWidgetsWithLeakTracking('RawMaterialButton handles hover', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/refresh_indicator_test.dart b/packages/flutter/test/material/refresh_indicator_test.dart index 4378ff8cd8e0f..23af4664430af 100644 --- a/packages/flutter/test/material/refresh_indicator_test.dart +++ b/packages/flutter/test/material/refresh_indicator_test.dart @@ -8,8 +8,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; bool refreshCalled = false; diff --git a/packages/flutter/test/material/scrollbar_paint_test.dart b/packages/flutter/test/material/scrollbar_paint_test.dart index 1686ff52e495d..8c3ac02dd9127 100644 --- a/packages/flutter/test/material/scrollbar_paint_test.dart +++ b/packages/flutter/test/material/scrollbar_paint_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Color _kAndroidThumbIdleColor = Color(0xffbcbcbc); @@ -79,7 +78,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('works with MaterialApp and Scaffold', (WidgetTester tester) async { + testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -123,7 +122,7 @@ void main() { ); }); - testWidgetsWithLeakTracking("should not paint when there isn't enough space", (WidgetTester tester) async { + testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index ffbaafea47512..741adf448c6a5 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -16,8 +16,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300); const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600); diff --git a/packages/flutter/test/material/scrollbar_theme_test.dart b/packages/flutter/test/material/scrollbar_theme_test.dart index 15bb54f9f7d96..de07fda289cc9 100644 --- a/packages/flutter/test/material/scrollbar_theme_test.dart +++ b/packages/flutter/test/material/scrollbar_theme_test.dart @@ -8,8 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // The const represents the starting position of the scrollbar thumb for // the below tests. The thumb is 90 pixels long, and 8 pixels wide, with a 2 diff --git a/packages/flutter/test/material/search_bar_theme_test.dart b/packages/flutter/test/material/search_bar_theme_test.dart index ce85e73e3c932..cfa506499784e 100644 --- a/packages/flutter/test/material/search_bar_theme_test.dart +++ b/packages/flutter/test/material/search_bar_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('SearchBarThemeData copyWith, ==, hashCode basics', () { @@ -243,19 +242,19 @@ void main() { expect(trailingRect.right, barRect.right - 16.0); } - testWidgetsWithLeakTracking('SearchBar properties overrides defaults', (WidgetTester tester) async { + testWidgets('SearchBar properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgetsWithLeakTracking('SearchBar theme data overrides defaults', (WidgetTester tester) async { + testWidgets('SearchBar theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { + testWidgets('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); @@ -263,7 +262,7 @@ void main() { // Same as the previous tests with empty SearchBarThemeData's instead of null. - testWidgetsWithLeakTracking('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgets('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true, searchBarThemeData: const SearchBarThemeData(), overallTheme: const SearchBarThemeData())); @@ -271,14 +270,14 @@ void main() { checkSearchBar(tester); }); - testWidgetsWithLeakTracking('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgets('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme, overallTheme: const SearchBarThemeData())); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgets('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); diff --git a/packages/flutter/test/material/search_view_theme_test.dart b/packages/flutter/test/material/search_view_theme_test.dart index 98e8e379cc6dd..647012c09f458 100644 --- a/packages/flutter/test/material/search_view_theme_test.dart +++ b/packages/flutter/test/material/search_view_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('SearchViewThemeData copyWith, ==, hashCode basics', () { @@ -197,21 +196,21 @@ void main() { expect(inputText.style.fontSize, headerTextStyle.fontSize); } - testWidgetsWithLeakTracking('SearchView properties overrides defaults', (WidgetTester tester) async { + testWidgets('SearchView properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchView(tester); }); - testWidgetsWithLeakTracking('SearchView theme data overrides defaults', (WidgetTester tester) async { + testWidgets('SearchView theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); checkSearchView(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { + testWidgets('Overall Theme SearchView theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); @@ -220,7 +219,7 @@ void main() { // Same as the previous tests with empty SearchViewThemeData's instead of null. - testWidgetsWithLeakTracking('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgets('SearchView properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchViewProperties: true, searchViewThemeData: const SearchViewThemeData(), overallTheme: const SearchViewThemeData())); @@ -229,7 +228,7 @@ void main() { checkSearchView(tester); }); - testWidgetsWithLeakTracking('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgets('SearchView theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchViewThemeData: searchViewTheme, overallTheme: const SearchViewThemeData())); await tester.tap(find.byIcon(Icons.search)); @@ -237,7 +236,7 @@ void main() { checkSearchView(tester); }); - testWidgetsWithLeakTracking('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgets('Overall Theme SearchView theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchViewTheme)); await tester.tap(find.byIcon(Icons.search)); await tester.pumpAndSettle(); // allow the animations to finish diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index bc0caa645fb1b..57b31588e8862 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -10,7 +10,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; import '../widgets/semantics_tester.dart'; Widget boilerplate({required Widget child}) { @@ -22,7 +21,7 @@ Widget boilerplate({required Widget child}) { void main() { - testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { + testWidgets('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -330,7 +329,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgetsWithLeakTracking('SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgets('SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -409,7 +408,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgetsWithLeakTracking('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgets('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -486,7 +485,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes semantics.dispose(); }); - testWidgetsWithLeakTracking('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { + testWidgets('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -534,7 +533,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgetsWithLeakTracking('SegmentedButton has no tooltips by default', (WidgetTester tester) async { + testWidgets('SegmentedButton has no tooltips by default', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -558,7 +557,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byType(Tooltip), findsNothing); }); - testWidgetsWithLeakTracking('SegmentedButton has correct tooltips', (WidgetTester tester) async { + testWidgets('SegmentedButton has correct tooltips', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/segmented_button_theme_test.dart b/packages/flutter/test/material/segmented_button_theme_test.dart index 6c2cf45a0df6b..a273f3633e8ad 100644 --- a/packages/flutter/test/material/segmented_button_theme_test.dart +++ b/packages/flutter/test/material/segmented_button_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { @@ -43,7 +42,7 @@ void main() { expect(description, []); }); - testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -110,7 +109,7 @@ void main() { } }); - testWidgetsWithLeakTracking('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { + testWidgets('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: true, segmentedButtonTheme: SegmentedButtonThemeData( @@ -203,7 +202,7 @@ void main() { } }); - testWidgetsWithLeakTracking('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgets('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { @@ -330,7 +329,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgets('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set states) { diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index 00211f70f5de6..8e19b78f6f7d2 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -9,7 +9,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0); @@ -18,7 +17,7 @@ Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { } void main() { - testWidgetsWithLeakTracking('SelectionArea uses correct selection controls', (WidgetTester tester) async { + testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('abc'), @@ -40,7 +39,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgetsWithLeakTracking('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { + testWidgets('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123378 await tester.pumpWidget( const MaterialApp( @@ -71,7 +70,7 @@ void main() { }); - testWidgetsWithLeakTracking('builds the default context menu by default', (WidgetTester tester) async { + testWidgets('builds the default context menu by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SelectionArea( @@ -98,7 +97,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgetsWithLeakTracking('builds a custom context menu if provided', (WidgetTester tester) async { + testWidgets('builds a custom context menu if provided', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -134,7 +133,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { SelectedContent? content; await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 935e959afff4d..383dc49d4f9b8 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -7,8 +7,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { test('SliderThemeData copyWith, ==, hashCode basics', () { expect(const SliderThemeData(), const SliderThemeData().copyWith()); @@ -20,7 +18,7 @@ void main() { expect(identical(SliderThemeData.lerp(data, data, 0.5), data), true); }); - testWidgetsWithLeakTracking('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { + testWidgets('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData().debugFillProperties(builder); @@ -32,7 +30,7 @@ void main() { expect(description, []); }); - testWidgetsWithLeakTracking('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgets('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData( trackHeight: 7.0, @@ -502,7 +500,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Slider parameters overrides theme properties', (WidgetTester tester) async { + testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async { debugDisableShadows = false; const Color activeTrackColor = Color(0xffff0001); const Color inactiveTrackColor = Color(0xffff0002); @@ -556,7 +554,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { + testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -580,7 +578,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { + testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -604,7 +602,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { + testWidgets('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -634,7 +632,7 @@ void main() { expect(sliderTheme.valueIndicatorTextStyle!.color, equals(customColor4)); }); - testWidgetsWithLeakTracking('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { + testWidgets('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -658,7 +656,7 @@ void main() { expect(sliderTheme.rangeValueIndicatorShape, const PaddleRangeSliderValueIndicatorShape()); }); - testWidgetsWithLeakTracking('SliderThemeData lerps correctly', (WidgetTester tester) async { + testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async { final SliderThemeData sliderThemeBlack = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -692,7 +690,7 @@ void main() { expect(lerp.valueIndicatorTextStyle!.color, equals(middleGrey.withAlpha(0xff))); }); - testWidgetsWithLeakTracking('Default slider track draws correctly', (WidgetTester tester) async { + testWidgets('Default slider track draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -728,7 +726,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Default slider overlay draws correctly', (WidgetTester tester) async { + testWidgets('Default slider overlay draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -789,7 +787,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider can use theme overlay with material states', (WidgetTester tester) async { + testWidgets('Slider can use theme overlay with material states', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -848,7 +846,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { + testWidgets('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -892,7 +890,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1076,7 +1074,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1260,7 +1258,7 @@ void main() { } }); - testWidgetsWithLeakTracking('The slider track height can be overridden', (WidgetTester tester) async { + testWidgets('The slider track height can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(trackHeight: 16); const Radius radius = Radius.circular(8); const Radius activatedRadius = Radius.circular(9); @@ -1290,7 +1288,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { + testWidgets('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 7, @@ -1315,7 +1313,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { + testWidgets('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 9, @@ -1338,7 +1336,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { + testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5), activeTickMarkColor: const Color(0xfadedead), @@ -1371,7 +1369,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The default slider overlay shape size can be overridden', (WidgetTester tester) async { + testWidgets('The default slider overlay shape size can be overridden', (WidgetTester tester) async { const double uniqueOverlayRadius = 23; final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: const RoundSliderOverlayShape( @@ -1398,7 +1396,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/74503 - testWidgetsWithLeakTracking('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgets('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1439,7 +1437,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/125467 - testWidgetsWithLeakTracking('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgets('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1490,7 +1488,7 @@ void main() { // // The value indicator can be skipped by passing the appropriate // [ShowValueIndicator]. - testWidgetsWithLeakTracking('The slider can skip all of its component painting', (WidgetTester tester) async { + testWidgets('The slider can skip all of its component painting', (WidgetTester tester) async { // Pump a slider with all shapes skipped. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1511,7 +1509,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the track', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the track', (WidgetTester tester) async { // Pump a slider with just a track. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1532,7 +1530,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { // Pump a slider with just tick marks. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1556,7 +1554,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the thumb', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a thumb. @@ -1582,7 +1580,7 @@ void main() { } }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the overlay', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async { // Pump a slider with just an overlay. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1610,7 +1608,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { + testWidgets('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1640,7 +1638,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1675,7 +1673,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1707,7 +1705,7 @@ void main() { }); - testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgets('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1757,7 +1755,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { + testWidgets('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { debugDisableShadows = true; final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -1803,7 +1801,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1837,7 +1835,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgets('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1873,7 +1871,7 @@ void main() { } }); - testWidgetsWithLeakTracking('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { + testWidgets('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( trackShape: const RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight( @@ -1900,7 +1898,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('The mouse cursor is themeable', (WidgetTester tester) async { + testWidgets('The mouse cursor is themeable', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( mouseCursor: const MaterialStatePropertyAll(SystemMouseCursors.text), @@ -1915,7 +1913,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgetsWithLeakTracking('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { + testWidgets('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { double value = 0.0; Widget buildApp({ @@ -2022,7 +2020,7 @@ void main() { await gesture.up(); }); - testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { + testWidgets('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -2235,7 +2233,7 @@ void main() { } }); - testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { + testWidgets('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( diff --git a/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart b/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart index 002aba3fecc26..494dbe7308aca 100644 --- a/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart +++ b/packages/flutter/test/material/spell_check_suggestions_toolbar_layout_delegate_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgetsWithLeakTracking('positions itself at anchorAbove if it fits and shifts up when not', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart b/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart index 6a97355d0b107..e9bbc4950eae7 100644 --- a/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart +++ b/packages/flutter/test/material/spell_check_suggestions_toolbar_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // Vertical position at which to anchor the toolbar for testing. const double _kAnchor = 200; diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index c3801a8fcbb4d..f3ee1be963477 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -7,7 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -560,6 +560,7 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); testWidgetsWithLeakTracking('SwitchListTile.adaptive onFocusChange Callback', (WidgetTester tester) async { @@ -589,6 +590,7 @@ void main() { await tester.pump(); expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + node.dispose(); }); group('feedback', () { @@ -863,7 +865,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { + testWidgets('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF4caf50); const Color pressedThumbColor = Color(0xFFF44336); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index fa89e561f7fc6..9fbf97f7ac878 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -17,8 +17,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -701,6 +700,8 @@ void main() { expect(getSwitchMaterial(tester), paints..circle(color: theme.hoverColor) ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch default overlayColor resolves hovered/focused state', (WidgetTester tester) async { @@ -746,6 +747,8 @@ void main() { expect(getSwitchMaterial(tester), paints..circle(color: theme.colorScheme.primary.withOpacity(0.08)) ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Switch can be set color', (WidgetTester tester) async { @@ -1238,6 +1241,8 @@ void main() { ..rrect(color: const Color(0x1f000000)) ..rrect(color: const Color(0xffbdbdbd)), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch is focusable and has correct focus color', (WidgetTester tester) async { @@ -1325,6 +1330,8 @@ void main() { ) ..rrect(color: Color.alphaBlend(colors.onSurface.withOpacity(0.38), colors.surface)), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch with splash radius set', (WidgetTester tester) async { @@ -1985,6 +1992,8 @@ void main() { ..rrect(color: hoveredThumbColor), reason: 'Inactive disabled switch should default track and custom thumb color', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch thumb color resolves in hovered/focused states', (WidgetTester tester) async { @@ -2061,6 +2070,8 @@ void main() { ..rrect(color: hoveredThumbColor), reason: 'active enabled switch should default track and custom thumb color', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Track color resolves in active/enabled states', (WidgetTester tester) async { @@ -2312,6 +2323,8 @@ void main() { ), reason: 'Inactive enabled switch should match these colors', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material3 - Switch track color resolves in hovered/focused states', (WidgetTester tester) async { @@ -2382,6 +2395,8 @@ void main() { ), reason: 'Active enabled switch should match these colors', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Material2 - Switch thumb color is blended against surface color', (WidgetTester tester) async { @@ -2634,6 +2649,8 @@ void main() { ), reason: 'Hovered Switch should use overlay color $hoverOverlayColor over $hoverColor', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { @@ -3187,6 +3204,8 @@ void main() { ..rrect(color: hoveredTrackOutlineColor, style: PaintingStyle.stroke), reason: 'Active enabled switch track outline should match this color', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Track outline width resolves in active/enabled states', (WidgetTester tester) async { @@ -3322,6 +3341,8 @@ void main() { ..rrect(strokeWidth: hoveredTrackOutlineWidth, style: PaintingStyle.stroke), reason: 'Active enabled switch track outline width should be 4.0', ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch can set icon - M3', (WidgetTester tester) async { @@ -3486,6 +3507,8 @@ void main() { ..rrect(color: const Color(0x0a000000)) ..rrect(color: const Color(0xffffffff)), ); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Switch.onFocusChange callback', (WidgetTester tester) async { @@ -3515,6 +3538,8 @@ void main() { await tester.pump(); expect(focused, isFalse); expect(focusNode.hasFocus, isFalse); + + focusNode.dispose(); }); } diff --git a/packages/flutter/test/material/switch_theme_test.dart b/packages/flutter/test/material/switch_theme_test.dart index 900e0bc06a665..720c103da491b 100644 --- a/packages/flutter/test/material/switch_theme_test.dart +++ b/packages/flutter/test/material/switch_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('SwitchThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart index 6f495bf9a3824..98e1dd8280b40 100644 --- a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart +++ b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // This is a regression test for https://github.com/flutter/flutter/issues/10549 // which was failing because _SliverPersistentHeaderElement.visitChildren() diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 784ffb3a3c1ae..862eadb1bbd41 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { @@ -198,6 +197,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -265,6 +266,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. await expectLater(tester, meetsGuideline(textContrastGuideline)); + + focusNode.dispose(); }, skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); @@ -320,6 +323,8 @@ void main() { focusNode.requestFocus(); await tester.pumpAndSettle(); expect(overlayColor(), paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton uses stateful color for text color in different states', (WidgetTester tester) async { @@ -387,6 +392,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(textColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton uses stateful color for icon color in different states', (WidgetTester tester) async { @@ -454,6 +461,8 @@ void main() { await tester.pump(); // Start the splash and highlight animations. await tester.pump(const Duration(milliseconds: 800)); // Wait for splash and highlight to be well under way. expect(iconColor(), pressedColor); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('TextButton has no clip by default', (WidgetTester tester) async { @@ -530,6 +539,8 @@ void main() { final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); expect(inkFeatures, paints..rect(color: focusColor)); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Does TextButton contribute semantics', (WidgetTester tester) async { @@ -795,6 +806,8 @@ void main() { await tester.pumpAndSettle(); expect(focusNode.hasPrimaryFocus, isFalse); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('disabled and hovered TextButton responds to mouse-exit', (WidgetTester tester) async { @@ -886,6 +899,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('When TextButton disable, Can not set TextButton focus.', (WidgetTester tester) async { @@ -909,6 +924,8 @@ void main() { expect(gotFocus, isFalse); expect(node.hasFocus, isFalse); + + node.dispose(); }); testWidgetsWithLeakTracking('TextButton responds to density changes.', (WidgetTester tester) async { @@ -1619,7 +1636,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgetsWithLeakTracking('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1772,15 +1789,15 @@ void main() { await gesture.removePointer(); } - testWidgetsWithLeakTracking('TextButton statesController', (WidgetTester tester) async { + testWidgets('TextButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgetsWithLeakTracking('TextButton.icon statesController', (WidgetTester tester) async { + testWidgets('TextButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgetsWithLeakTracking('Disabled TextButton statesController', (WidgetTester tester) async { + testWidgets('Disabled TextButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; diff --git a/packages/flutter/test/material/text_button_theme_test.dart b/packages/flutter/test/material/text_button_theme_test.dart index fc0d023cc177b..b9326fdcf10c4 100644 --- a/packages/flutter/test/material/text_button_theme_test.dart +++ b/packages/flutter/test/material/text_button_theme_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('TextButtonTheme lerp special cases', () { diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart index 21934175279ed..a5b4a06a421fd 100644 --- a/packages/flutter/test/material/text_field_helper_text_test.dart +++ b/packages/flutter/test/material/text_field_helper_text_test.dart @@ -5,10 +5,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - void main() { - testWidgetsWithLeakTracking('TextField works correctly when changing helperText', (WidgetTester tester) async { + testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(1)); await tester.pump(const Duration(milliseconds: 100)); diff --git a/packages/flutter/test/material/text_field_splash_test.dart b/packages/flutter/test/material/text_field_splash_test.dart index ab26df41cbe0d..b16f0ced9b951 100644 --- a/packages/flutter/test/material/text_field_splash_test.dart +++ b/packages/flutter/test/material/text_field_splash_test.dart @@ -6,8 +6,6 @@ import 'package:flutter/gestures.dart' show kPressTimeout; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import '../foundation/leak_tracking.dart'; - bool confirmCalled = false; bool cancelCalled = false; @@ -137,7 +135,7 @@ void main() { expect(cancelCalled, isFalse); }); - testWidgetsWithLeakTracking('Splash should never be created or canceled', (WidgetTester tester) async { + testWidgets('Splash should never be created or canceled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 36373fec387cf..97323bf4e73f1 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -11,8 +11,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart'; @@ -249,10 +248,10 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. // TODO(polina-c): remove after fixing // https://github.com/flutter/flutter/issues/130467 - leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: {'ValueNotifier<_OverlayEntryWidgetState?>': 16}), + leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true, allowAllNotGCed: true), ); - testWidgetsWithLeakTracking('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { + testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); @@ -347,7 +346,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgetsWithLeakTracking('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { + testWidgets('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { bool asserted; try { TextFormField( @@ -360,7 +359,7 @@ void main() { expect(asserted, false); }); - testWidgetsWithLeakTracking('Passes textAlign to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes textAlign to underlying TextField', (WidgetTester tester) async { const TextAlign alignment = TextAlign.center; await tester.pumpWidget( @@ -382,7 +381,7 @@ void main() { expect(textFieldWidget.textAlign, alignment); }); - testWidgetsWithLeakTracking('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { const ScrollPhysics scrollPhysics = ScrollPhysics(); await tester.pumpWidget( @@ -404,7 +403,7 @@ void main() { expect(textFieldWidget.scrollPhysics, scrollPhysics); }); - testWidgetsWithLeakTracking('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { const TextAlignVertical textAlignVertical = TextAlignVertical.bottom; await tester.pumpWidget( @@ -426,7 +425,7 @@ void main() { expect(textFieldWidget.textAlignVertical, textAlignVertical); }); - testWidgetsWithLeakTracking('Passes textInputAction to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes textInputAction to underlying TextField', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -446,7 +445,7 @@ void main() { expect(textFieldWidget.textInputAction, TextInputAction.next); }); - testWidgetsWithLeakTracking('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { void onEditingComplete() { } await tester.pumpWidget( @@ -468,7 +467,7 @@ void main() { expect(textFieldWidget.onEditingComplete, onEditingComplete); }); - testWidgetsWithLeakTracking('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { const double cursorWidth = 3.14; const double cursorHeight = 6.28; const Radius cursorRadius = Radius.circular(4); @@ -520,7 +519,7 @@ void main() { expect(called, true); }); - testWidgetsWithLeakTracking('onChanged callbacks are called', (WidgetTester tester) async { + testWidgets('onChanged callbacks are called', (WidgetTester tester) async { late String value; await tester.pumpWidget( @@ -542,7 +541,7 @@ void main() { expect(value, 'Soup'); }); - testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -567,7 +566,7 @@ void main() { expect(validateCalled, 2); }); - testWidgetsWithLeakTracking('validate is called if widget is enabled', (WidgetTester tester) async { + testWidgets('validate is called if widget is enabled', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -594,7 +593,7 @@ void main() { }); - testWidgetsWithLeakTracking('Disabled field hides helper and counter in M2', (WidgetTester tester) async { + testWidgets('Disabled field hides helper and counter in M2', (WidgetTester tester) async { const String helperText = 'helper text'; const String counterText = 'counter text'; const String errorText = 'error text'; @@ -642,7 +641,7 @@ void main() { expect(errorWidget.style!.color, equals(Colors.transparent)); }); - testWidgetsWithLeakTracking('passing a buildCounter shows returned widget', (WidgetTester tester) async { + testWidgets('passing a buildCounter shows returned widget', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -707,7 +706,7 @@ void main() { expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); }, skip: isBrowser); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { + testWidgets('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( MaterialApp( @@ -734,7 +733,7 @@ void main() { expect(tapCount, 3); }); - testWidgetsWithLeakTracking('onTapOutside is called upon tap outside', (WidgetTester tester) async { + testWidgets('onTapOutside is called upon tap outside', (WidgetTester tester) async { int tapOutsideCount = 0; await tester.pumpWidget( MaterialApp( @@ -765,7 +764,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgetsWithLeakTracking('reset resets the text fields value to the initialValue', (WidgetTester tester) async { + testWidgets('reset resets the text fields value to the initialValue', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -788,7 +787,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgetsWithLeakTracking("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { + testWidgets("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -811,7 +810,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgetsWithLeakTracking("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { + testWidgets("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -834,7 +833,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgetsWithLeakTracking('didChange changes text fields value', (WidgetTester tester) async { + testWidgets('didChange changes text fields value', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -856,7 +855,7 @@ void main() { expect(find.text('changedValue'), findsOneWidget); }); - testWidgetsWithLeakTracking('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { + testWidgets('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { bool called = false; late FormFieldState state; @@ -883,7 +882,7 @@ void main() { expect(called, true); }); - testWidgetsWithLeakTracking('autofillHints is passed to super', (WidgetTester tester) async { + testWidgets('autofillHints is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -900,7 +899,7 @@ void main() { expect(widget.autofillHints, equals(const [AutofillHints.countryName])); }); - testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -925,7 +924,7 @@ void main() { expect(validateCalled, 1); }); - testWidgetsWithLeakTracking('textSelectionControls is passed to super', (WidgetTester tester) async { + testWidgets('textSelectionControls is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -942,7 +941,7 @@ void main() { expect(widget.selectionControls, equals(materialTextSelectionControls)); }); - testWidgetsWithLeakTracking('TextFormField respects hintTextDirection', (WidgetTester tester) async { + testWidgets('TextFormField respects hintTextDirection', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Directionality( @@ -984,7 +983,7 @@ void main() { expect(textDirection, TextDirection.rtl); }); - testWidgetsWithLeakTracking('Passes scrollController to underlying TextField', (WidgetTester tester) async { + testWidgets('Passes scrollController to underlying TextField', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); await tester.pumpWidget( @@ -1006,7 +1005,7 @@ void main() { expect(textFieldWidget.scrollController, scrollController); }); - testWidgetsWithLeakTracking('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1151,7 +1150,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgetsWithLeakTracking('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgets('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { final SpellCheckConfiguration mySpellCheckConfiguration = SpellCheckConfiguration( spellCheckService: DefaultSpellCheckService(), misspelledTextStyle: TextField.materialMisspelledTextStyle, @@ -1181,7 +1180,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgets('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { final TextMagnifierConfiguration myTextMagnifierConfiguration = TextMagnifierConfiguration( magnifierBuilder: (BuildContext context, MagnifierController controller, ValueNotifier notifier) { return const Placeholder(); @@ -1202,7 +1201,7 @@ void main() { expect(editableText.magnifierConfiguration, equals(myTextMagnifierConfiguration)); }); - testWidgetsWithLeakTracking('Passes undoController to undoController TextField', (WidgetTester tester) async { + testWidgets('Passes undoController to undoController TextField', (WidgetTester tester) async { final UndoHistoryController undoController = UndoHistoryController(value: UndoHistoryValue.empty); await tester.pumpWidget( @@ -1224,7 +1223,7 @@ void main() { expect(textFieldWidget.undoController, undoController); }); - testWidgetsWithLeakTracking('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { + testWidgets('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { const bool cursorOpacityAnimates = true; await tester.pumpWidget( @@ -1246,7 +1245,7 @@ void main() { expect(textFieldWidget.cursorOpacityAnimates, cursorOpacityAnimates); }); - testWidgetsWithLeakTracking('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { + testWidgets('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { final ContentInsertionConfiguration contentInsertionConfiguration = ContentInsertionConfiguration(onContentInserted: (KeyboardInsertedContent value) {}); @@ -1269,7 +1268,7 @@ void main() { expect(textFieldWidget.contentInsertionConfiguration, contentInsertionConfiguration); }); - testWidgetsWithLeakTracking('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { + testWidgets('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { const Clip clipBehavior = Clip.antiAlias; await tester.pumpWidget( @@ -1291,7 +1290,7 @@ void main() { expect(textFieldWidget.clipBehavior, clipBehavior); }); - testWidgetsWithLeakTracking('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { + testWidgets('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { const bool scribbleEnabled = false; await tester.pumpWidget( @@ -1313,7 +1312,7 @@ void main() { expect(textFieldWidget.scribbleEnabled, scribbleEnabled); }); - testWidgetsWithLeakTracking('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { + testWidgets('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { const bool canRequestFocus = false; await tester.pumpWidget( @@ -1335,7 +1334,7 @@ void main() { expect(textFieldWidget.canRequestFocus, canRequestFocus); }); - testWidgetsWithLeakTracking('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { + testWidgets('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { void onAppPrivateCommand(String p0, Map p1) {} await tester.pumpWidget( @@ -1357,7 +1356,7 @@ void main() { expect(textFieldWidget.onAppPrivateCommand, onAppPrivateCommand); }); - testWidgetsWithLeakTracking('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { + testWidgets('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { const BoxHeightStyle selectionHeightStyle = BoxHeightStyle.max; await tester.pumpWidget( @@ -1379,7 +1378,7 @@ void main() { expect(textFieldWidget.selectionHeightStyle, selectionHeightStyle); }); - testWidgetsWithLeakTracking('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { + testWidgets('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { const BoxWidthStyle selectionWidthStyle = BoxWidthStyle.max; await tester.pumpWidget( @@ -1401,7 +1400,7 @@ void main() { expect(textFieldWidget.selectionWidthStyle, selectionWidthStyle); }); - testWidgetsWithLeakTracking('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { + testWidgets('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { const DragStartBehavior dragStartBehavior = DragStartBehavior.down; await tester.pumpWidget( @@ -1423,7 +1422,7 @@ void main() { expect(textFieldWidget.dragStartBehavior, dragStartBehavior); }); - testWidgetsWithLeakTracking('Error color for cursor while validating', (WidgetTester tester) async { + testWidgets('Error color for cursor while validating', (WidgetTester tester) async { const Color errorColor = Color(0xff123456); await tester.pumpWidget(MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 1e7ba83ced5b5..ecd0850d8069d 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('TextSelectionThemeData copyWith, ==, hashCode basics', () { @@ -113,7 +112,8 @@ void main() { notDisposedAllowList: { 'ValueNotifier': 1, 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 1, + 'ValueNotifier': 2, + '_InputBorderGap': 1, }, // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. allowAllNotGCed: true, @@ -173,7 +173,8 @@ void main() { notDisposedAllowList: { 'ValueNotifier': 1, 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 1, + 'ValueNotifier': 2, + '_InputBorderGap': 1, }, // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. allowAllNotGCed: true, diff --git a/packages/flutter/test/material/text_selection_toolbar_test.dart b/packages/flutter/test/material/text_selection_toolbar_test.dart index f37714db21c24..f3317c109c98f 100644 --- a/packages/flutter/test/material/text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/editable_text_utils.dart' show textOffsetToPosition; const double _kToolbarContentDistance = 8.0; @@ -173,7 +172,7 @@ void main() { expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); }); - testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { + testWidgets('can create and use a custom toolbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart index a6d6faaa82df4..f2f6cbd10cf22 100644 --- a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index b5b67bd6c9bac..0ec084f255d56 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('Theme data control test', () { diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index 7c6d42c2fa396..6c71fef4565f5 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -4,8 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('TimeOfDay.format', () { @@ -62,7 +61,7 @@ void main() { expect(() => RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)).value, throwsAssertionError); }); - testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { + testWidgets('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); final _RestorableWidgetState state = tester.state(find.byType(_RestorableWidget)); @@ -107,7 +106,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 2, minute: 2)); }); - testWidgetsWithLeakTracking('restore to older state', (WidgetTester tester) async { + testWidgets('restore to older state', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -138,7 +137,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 10, minute: 5)); }); - testWidgetsWithLeakTracking('call notifiers when value changes', (WidgetTester tester) async { + testWidgets('call notifiers when value changes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), diff --git a/packages/flutter/test/material/toggle_buttons_test.dart b/packages/flutter/test/material/toggle_buttons_test.dart index a14363033b86e..0a31859bd8f29 100644 --- a/packages/flutter/test/material/toggle_buttons_test.dart +++ b/packages/flutter/test/material/toggle_buttons_test.dart @@ -11,8 +11,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; const double _defaultBorderWidth = 1.0; @@ -817,6 +816,8 @@ void main() { expect(inkFeatures, paints..rect(color: theme.colorScheme.onSurface.withOpacity(0.12))); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Default InkWell colors - selected', (WidgetTester tester) async { @@ -882,6 +883,8 @@ void main() { expect(inkFeatures, paints..rect(color: theme.colorScheme.primary.withOpacity(0.12))); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking('Custom InkWell colors', (WidgetTester tester) async { @@ -951,6 +954,8 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking( @@ -1863,6 +1868,10 @@ void main() { expect(toggleButtonElevation('two'), 0); await hoverGesture.removePointer(); + + for (final FocusNode n in focusNodes) { + n.dispose(); + } }); testWidgetsWithLeakTracking('Toggle buttons height matches MaterialTapTargetSize.padded height', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/toggle_buttons_theme_test.dart b/packages/flutter/test/material/toggle_buttons_theme_test.dart index 7b67cbe901edc..a041f1d7679ec 100644 --- a/packages/flutter/test/material/toggle_buttons_theme_test.dart +++ b/packages/flutter/test/material/toggle_buttons_theme_test.dart @@ -6,8 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Widget boilerplate({required Widget child}) { return Directionality( @@ -512,6 +511,8 @@ void main() { expect(inkFeatures, paints..rect(color: focusColor)); await hoverGesture.removePointer(); + + focusNode.dispose(); }); testWidgetsWithLeakTracking( diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 8b68be4cbdf5f..94fcde0662911 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -10,8 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -25,7 +24,7 @@ Finder _findTooltipContainer(String tooltipText) { } void main() { - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -79,7 +78,7 @@ void main() { expect(tipInGlobal.dy, 20.0); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -138,7 +137,7 @@ void main() { expect(tipInGlobal.dy, 40.0); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - top left', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -192,7 +191,7 @@ void main() { expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0))); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -245,7 +244,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -309,7 +308,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Directionality( @@ -361,7 +360,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -418,7 +417,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgetsWithLeakTracking('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { + testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -475,7 +474,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgetsWithLeakTracking('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { + testWidgets('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23666 Widget materialAppWithViewInsets(double viewInsetsHeight) { final Widget scaffold = Scaffold( @@ -530,7 +529,7 @@ void main() { expect(tooltipTopRight.dy, lessThan(fabTopRight.dy)); }); - testWidgetsWithLeakTracking('Custom tooltip margin', (WidgetTester tester) async { + testWidgets('Custom tooltip margin', (WidgetTester tester) async { const double customMarginValue = 10.0; final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( @@ -767,7 +766,7 @@ void main() { expect(textStyle.decorationStyle, isNot(TextDecorationStyle.double)); }); - testWidgetsWithLeakTracking('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { + testWidgets('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); await tester.pumpWidget( Theme( @@ -835,7 +834,7 @@ void main() { expect(tooltipContainer.padding, const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0)); }, variant: const TargetPlatformVariant({TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows})); - testWidgetsWithLeakTracking('Can tooltip decoration be customized', (WidgetTester tester) async { + testWidgets('Can tooltip decoration be customized', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -1393,7 +1392,7 @@ void main() { await tester.pump(waitDuration); }); - testWidgetsWithLeakTracking('Does tooltip contribute semantics', (WidgetTester tester) async { + testWidgets('Does tooltip contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey tooltipKey = GlobalKey(); diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index 75d623b1f0ed5..1c328e6b259d2 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -7,8 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; const String tooltipText = 'TIP'; @@ -113,7 +112,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -170,7 +169,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -225,7 +224,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -293,7 +292,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -359,7 +358,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -415,7 +414,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -469,7 +468,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgetsWithLeakTracking('Tooltip margin - ThemeData', (WidgetTester tester) async { + testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -524,7 +523,7 @@ void main() { expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); }); - testWidgetsWithLeakTracking('Tooltip margin - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( Directionality( @@ -675,7 +674,7 @@ void main() { expect(textAlign, TextAlign.end); }); - testWidgetsWithLeakTracking('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -717,7 +716,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgetsWithLeakTracking('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), @@ -757,7 +756,7 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgetsWithLeakTracking('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingVal = 20.0; @@ -804,7 +803,7 @@ void main() { expect(content.size.width, equals(tip.size.width - 2 * customPaddingVal)); }); - testWidgetsWithLeakTracking('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { + testWidgets('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingValue = 20.0; diff --git a/packages/flutter/test/material/tooltip_visibility_test.dart b/packages/flutter/test/material/tooltip_visibility_test.dart index c1f88e5e4691e..e607bd9f7e11c 100644 --- a/packages/flutter/test/material/tooltip_visibility_test.dart +++ b/packages/flutter/test/material/tooltip_visibility_test.dart @@ -7,8 +7,7 @@ import 'dart:ui'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const String tooltipText = 'TIP'; diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart index 515c90e76be03..a7e91eb6f5821 100644 --- a/packages/flutter/test/material/typography_test.dart +++ b/packages/flutter/test/material/typography_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('Typography is defined for all target platforms', () { diff --git a/packages/flutter/test/material/user_accounts_drawer_header_test.dart b/packages/flutter/test/material/user_accounts_drawer_header_test.dart index 65dac36e4cdee..004c801d0b457 100644 --- a/packages/flutter/test/material/user_accounts_drawer_header_test.dart +++ b/packages/flutter/test/material/user_accounts_drawer_header_test.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; - -import '../foundation/leak_tracking.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; const Key avatarA = Key('A'); diff --git a/packages/flutter/test/material/value_indicating_slider_test.dart b/packages/flutter/test/material/value_indicating_slider_test.dart index fb8029b935ab7..c0c255badddd0 100644 --- a/packages/flutter/test/material/value_indicating_slider_test.dart +++ b/packages/flutter/test/material/value_indicating_slider_test.dart @@ -9,11 +9,11 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; -import '../foundation/leak_tracking.dart'; void main() { - testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { + testWidgets('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -54,7 +54,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { + testWidgets('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -195,7 +195,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { + testWidgets('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -233,7 +233,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { + testWidgets('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 92e6a81a2ced3..5d240051fba88 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -38,10 +38,6 @@ const Map kManuallyPinnedDependencies = { 'url_launcher_android': '6.0.17', // https://github.com/flutter/flutter/issues/115660 'archive': '3.3.2', - // https://github.com/flutter/flutter/issues/132222 - 'leak_tracker': '8.0.3', - // https://github.com/flutter/flutter/issues/132222 - 'leak_tracker_testing': '1.0.2', }; class UpdatePackagesCommand extends FlutterCommand { diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index 34b24592e2178..b92fe6b15a40e 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -108,8 +108,6 @@ void main() { 'material_color_utilities', 'url_launcher_android', 'archive', - 'leak_tracker', - 'leak_tracker_testing', ]), ); }); From 8b8f262d4ddc96025585abe109cbebe0d521b459 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 13:14:18 -0400 Subject: [PATCH 0696/1547] Roll Flutter Engine from 4e8b2b61f648 to c125e1e23d4b (1 revision) (#132496) https://github.com/flutter/engine/compare/4e8b2b61f648...c125e1e23d4b 2023-08-14 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from yr5wa34bzOBfEgzDH... to AvjxPvh-niiyQpYoD... (flutter/engine#44683) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from yr5wa34bzOBf to AvjxPvh-niiy If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 42717a4f37385..bda5815512976 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4e8b2b61f64856bc11df6a569472c279dc1eef6d +c125e1e23d4b3ee3f2d6dd4fb57657264b23d8d8 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 16b67afdc8ba5..9d8675692a14b 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -yr5wa34bzOBfEgzDH0dAgw9hz2auaQ7qLNdAEEyKD4IC +AvjxPvh-niiyQpYoDshRJNeONXoN7kFYhUeQ26-eTX8C From ec0b7443c42691df6b86cf9bd5d84e3b63cadefe Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 14 Aug 2023 12:30:55 -0500 Subject: [PATCH 0697/1547] Fix log filtering and CI tests for iOS 17 physical devices (#132491) Fixes a couple of issues introduced in new iOS 17 physical device tooling: https://github.com/flutter/flutter/pull/131865. 1) Duplicate messages were being filtered out too aggressively. For example, if on the counter app, you printed "Increment!" on button click, it would only print once no matter how many times you clicked. Sometimes more than one log source is used at a time and the original intention was to filter duplicates between two log sources, so it wouldn't print the same message from both logs. However, it would also filter when the same message was added more than once via the same log. The new solution distinguishes a "primary" and a "fallback" log source and prefers to use the primary source unless it's not working, in which it'll use the fallback. If the fallback is faster than the primary, the primary will exclude the logs received by the fallback in a 1-to-1 fashion to prevent too-aggressive filtering. Once a flutter-message has been received by the primary source, fallback messages will be ignored. Note: iOS < 17 did not regress. 2) There was a race condition between the shutdown hooks and exiting XcodeDebug that was causing a crash when deleting a file that doesn't exist. This only affects CI - for the new integration tests and when testing with iOS 17 physical devices. --- .../flutter_tools/lib/src/ios/devices.dart | 223 ++++--- .../lib/src/ios/xcode_debug.dart | 8 +- .../ios/ios_device_logger_test.dart | 631 ++++++++++++++---- .../general.shard/ios/xcode_debug_test.dart | 103 +++ 4 files changed, 737 insertions(+), 228 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index b9a02e8660f66..85d89aceeb274 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -690,7 +690,7 @@ class IOSDevice extends Device { mDNSLookupTimer.cancel(); } } else { - if (isCoreDevice && vmServiceDiscovery != null) { + if ((isCoreDevice || forceXcodeDebugWorkflow) && vmServiceDiscovery != null) { // When searching for the Dart VM url, search for it via ProtocolDiscovery // (device logs) and mDNS simultaneously, since both can be flaky at times. final Future vmUrlFromMDns = MDnsVmServiceDiscovery.instance!.getVMServiceUriForLaunch( @@ -1071,7 +1071,8 @@ class IOSDeviceLogReader extends DeviceLogReader { // Sometimes (race condition?) we try to send a log after the controller has // been closed. See https://github.com/flutter/flutter/issues/99021 for more // context. - void _addToLinesController(String message, IOSDeviceLogSource source) { + @visibleForTesting + void addToLinesController(String message, IOSDeviceLogSource source) { if (!linesController.isClosed) { if (_excludeLog(message, source)) { return; @@ -1080,32 +1081,53 @@ class IOSDeviceLogReader extends DeviceLogReader { } } - /// Used to track messages prefixed with "flutter:" when [useBothLogDeviceReaders] - /// is true. - final List _streamFlutterMessages = []; + /// Used to track messages prefixed with "flutter:" from the fallback log source. + final List _fallbackStreamFlutterMessages = []; + + /// Used to track if a message prefixed with "flutter:" has been received from the primary log. + bool primarySourceFlutterLogReceived = false; /// There are three potential logging sources: `idevicesyslog`, `ios-deploy`, /// and Unified Logging (Dart VM). When using more than one of these logging - /// sources at a time, exclude logs with a `flutter:` prefix if they have - /// already been added to the stream. This is to prevent duplicates from - /// being printed. + /// sources at a time, prefer to use the primary source. However, if the + /// primary source is not working, use the fallback. bool _excludeLog(String message, IOSDeviceLogSource source) { - if (!usingMultipleLoggingSources) { + // If no fallback, don't exclude any logs. + if (logSources.fallbackSource == null) { return false; } - if (message.startsWith('flutter:')) { - if (_streamFlutterMessages.contains(message)) { + + // If log is from primary source, don't exclude it unless the fallback was + // quicker and added the message first. + if (source == logSources.primarySource) { + if (!primarySourceFlutterLogReceived && message.startsWith('flutter:')) { + primarySourceFlutterLogReceived = true; + } + + // If the message was already added by the fallback, exclude it to + // prevent duplicates. + final bool foundAndRemoved = _fallbackStreamFlutterMessages.remove(message); + if (foundAndRemoved) { return true; } - _streamFlutterMessages.add(message); - } else if (useIOSDeployLogging && source == IOSDeviceLogSource.idevicesyslog) { - // If using both `ios-deploy` and `idevicesyslog` simultaneously, exclude - // the message if its source is `idevicesyslog`. This is done because - //`ios-deploy` and `idevicesyslog` often have different prefixes, which - // makes duplicate matching difficult. Instead, exclude any non-flutter-prefixed - // `idevicesyslog` messages, which are not critical for CI tests. + return false; + } + + // If a flutter log was received from the primary source, that means it's + // working so don't use any messages from the fallback. + if (primarySourceFlutterLogReceived) { + return true; + } + + // When using logs from fallbacks, skip any logs not prefixed with "flutter:". + // This is done because different sources often have different prefixes for + // non-flutter messages, which makes duplicate matching difficult. Also, + // non-flutter messages are not critical for CI tests. + if (!message.startsWith('flutter:')) { return true; } + + _fallbackStreamFlutterMessages.add(message); return false; } @@ -1128,114 +1150,91 @@ class IOSDeviceLogReader extends DeviceLogReader { static const int minimumUniversalLoggingSdkVersion = 13; - /// Use `idevicesyslog` to stream logs from the device when one of the - /// following criteria is met: + /// Determine the primary and fallback source for device logs. /// - /// 1) The device is a physically attached CoreDevice. - /// 2) The device has iOS 16 or greater and it's being debugged from CI. - /// 3) The device has iOS 12 or lower. - /// - /// Syslog stopped working on iOS 13 (https://github.com/flutter/flutter/issues/41133). - /// However, from at least iOS 16, it has began working again. It's unclear - /// why it started working again. + /// There are three potential logging sources: `idevicesyslog`, `ios-deploy`, + /// and Unified Logging (Dart VM). @visibleForTesting - bool get useSyslogLogging { - // When forcing XcodeDebug workflow, use `idevicesyslog`. - if (_forceXcodeDebug) { - return true; + _IOSDeviceLogSources get logSources { + // `ios-deploy` stopped working with iOS 17 / Xcode 15, so use `idevicesyslog` instead. + // However, `idevicesyslog` is sometimes unreliable so use Dart VM as a fallback. + // Also, `idevicesyslog` does not work with iOS 17 wireless devices, so use the + // Dart VM for wireless devices. + if (_isCoreDevice || _forceXcodeDebug) { + if (_isWirelesslyConnected) { + return _IOSDeviceLogSources( + primarySource: IOSDeviceLogSource.unifiedLogging, + ); + } + return _IOSDeviceLogSources( + primarySource: IOSDeviceLogSource.idevicesyslog, + fallbackSource: IOSDeviceLogSource.unifiedLogging, + ); } - // `ios-deploy` stopped working with iOS 17 / Xcode 15, so use `idevicesyslog` instead. - // However, `idevicesyslog` does not work with iOS 17 wireless devices. - if (_isCoreDevice && !_isWirelesslyConnected) { - return true; + // Use `idevicesyslog` for iOS 12 or less. + // Syslog stopped working on iOS 13 (https://github.com/flutter/flutter/issues/41133). + // However, from at least iOS 16, it has began working again. It's unclear + // why it started working again. + if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) { + return _IOSDeviceLogSources( + primarySource: IOSDeviceLogSource.idevicesyslog, + ); } - // Use both logs from `idevicesyslog` and `ios-deploy` when debugging from CI system - // since sometimes `ios-deploy` does not return the device logs: + // Use `idevicesyslog` as a fallback to `ios-deploy` when debugging from + // CI system since sometimes `ios-deploy` does not return the device logs: // https://github.com/flutter/flutter/issues/121231 if (_usingCISystem && _majorSdkVersion >= 16) { - return true; + return _IOSDeviceLogSources( + primarySource: IOSDeviceLogSource.iosDeploy, + fallbackSource: IOSDeviceLogSource.idevicesyslog, + ); } - if (_majorSdkVersion < minimumUniversalLoggingSdkVersion) { - return true; + + // Use `ios-deploy` to stream logs from the device when the device is not a + // CoreDevice and has iOS 13 or greater. + // When using `ios-deploy` and the Dart VM, prefer the more complete logs + // from the attached debugger, if available. + if (connectedVMService != null && (_iosDeployDebugger == null || !_iosDeployDebugger!.debuggerAttached)) { + return _IOSDeviceLogSources( + primarySource: IOSDeviceLogSource.unifiedLogging, + fallbackSource: IOSDeviceLogSource.iosDeploy, + ); } - return false; + return _IOSDeviceLogSources( + primarySource: IOSDeviceLogSource.iosDeploy, + fallbackSource: IOSDeviceLogSource.unifiedLogging, + ); } - /// Use the Dart VM to stream logs from the device when one of the following - /// criteria is met: - /// - /// 1) The device is a CoreDevice and wirelessly connected. - /// 2) The device has iOS 13 or greater and [_iosDeployDebugger] is null or - /// the [_iosDeployDebugger] debugger is not attached. - /// - /// This value may change if [_iosDeployDebugger] changes. + /// Whether `idevicesyslog` is used as either the primary or fallback source for device logs. @visibleForTesting - bool get useUnifiedLogging { - // Can't use Unified Logging if it's not going to listen to the Dart VM. - if (!_shouldListenForUnifiedLoggingEvents) { - return false; - } - - // `idevicesyslog` doesn't work on wireless devices, so use logs from Dart VM instead. - if (_isCoreDevice) { - return true; - } - - // Prefer the more complete logs from the attached debugger, if they are available. - if (_majorSdkVersion >= minimumUniversalLoggingSdkVersion && (_iosDeployDebugger == null || !_iosDeployDebugger!.debuggerAttached)) { - return true; - } - - return false; + bool get useSyslogLogging { + return logSources.primarySource == IOSDeviceLogSource.idevicesyslog || + logSources.fallbackSource == IOSDeviceLogSource.idevicesyslog; } - /// Determine whether to listen to the Dart VM for logging events. Returns - /// true when one of the following criteria is met: + /// Whether the Dart VM is used as either the primary or fallback source for device logs. /// - /// 1) The device is a CoreDevice and wirelessly connected. - /// 2) The device has iOS 13 or greater. - bool get _shouldListenForUnifiedLoggingEvents { - // `idevicesyslog` doesn't work on wireless devices, so use logs from Dart VM instead. - if (_isCoreDevice) { - return true; - } - - if (_majorSdkVersion >= minimumUniversalLoggingSdkVersion) { - return true; - } - - return false; + /// Unified Logging only works after the Dart VM has been connected to. + @visibleForTesting + bool get useUnifiedLogging { + return logSources.primarySource == IOSDeviceLogSource.unifiedLogging || + logSources.fallbackSource == IOSDeviceLogSource.unifiedLogging; } - /// Use `ios-deploy` to stream logs from the device when the device is not a - /// CoreDevice and has iOS 13 or greater. + /// Whether `ios-deploy` is used as either the primary or fallback source for device logs. @visibleForTesting bool get useIOSDeployLogging { - if (_majorSdkVersion < minimumUniversalLoggingSdkVersion || _isCoreDevice) { - return false; - } - return true; - } - - @visibleForTesting - /// Returns true when using multiple sources for streaming the device logs. - bool get usingMultipleLoggingSources { - final int numberOfSources = (useIOSDeployLogging ? 1 : 0) + (useSyslogLogging ? 1 : 0) + (useUnifiedLogging ? 1 : 0); - if (numberOfSources > 1) { - return true; - } - return false; + return logSources.primarySource == IOSDeviceLogSource.iosDeploy || + logSources.fallbackSource == IOSDeviceLogSource.iosDeploy; } /// Listen to Dart VM for logs on iOS 13 or greater. - /// - /// Only send logs to stream if [_iosDeployDebugger] is null or - /// the [_iosDeployDebugger] debugger is not attached. Future _listenToUnifiedLoggingEvents(FlutterVmService connectedVmService) async { - if (!_shouldListenForUnifiedLoggingEvents) { + if (!useUnifiedLogging) { return; } try { @@ -1252,13 +1251,9 @@ class IOSDeviceLogReader extends DeviceLogReader { } void logMessage(vm_service.Event event) { - if (!useUnifiedLogging) { - // Prefer the more complete logs from the attached debugger. - return; - } final String message = processVmServiceMessage(event); if (message.isNotEmpty) { - _addToLinesController(message, IOSDeviceLogSource.unifiedLogging); + addToLinesController(message, IOSDeviceLogSource.unifiedLogging); } } @@ -1283,7 +1278,7 @@ class IOSDeviceLogReader extends DeviceLogReader { } // Add the debugger logs to the controller created on initialization. _loggingSubscriptions.add(debugger.logLines.listen( - (String line) => _addToLinesController( + (String line) => addToLinesController( _debuggerLineHandler(line), IOSDeviceLogSource.iosDeploy, ), @@ -1338,7 +1333,7 @@ class IOSDeviceLogReader extends DeviceLogReader { return (String line) { if (printing) { if (!_anyLineRegex.hasMatch(line)) { - _addToLinesController(decodeSyslog(line), IOSDeviceLogSource.idevicesyslog); + addToLinesController(decodeSyslog(line), IOSDeviceLogSource.idevicesyslog); return; } @@ -1350,7 +1345,7 @@ class IOSDeviceLogReader extends DeviceLogReader { if (match != null) { final String logLine = line.substring(match.end); // Only display the log line after the initial device and executable information. - _addToLinesController(decodeSyslog(logLine), IOSDeviceLogSource.idevicesyslog); + addToLinesController(decodeSyslog(logLine), IOSDeviceLogSource.idevicesyslog); printing = true; } }; @@ -1375,6 +1370,16 @@ enum IOSDeviceLogSource { unifiedLogging, } +class _IOSDeviceLogSources { + _IOSDeviceLogSources({ + required this.primarySource, + this.fallbackSource, + }); + + final IOSDeviceLogSource primarySource; + final IOSDeviceLogSource? fallbackSource; +} + /// A [DevicePortForwarder] specialized for iOS usage with iproxy. class IOSDevicePortForwarder extends DevicePortForwarder { diff --git a/packages/flutter_tools/lib/src/ios/xcode_debug.dart b/packages/flutter_tools/lib/src/ios/xcode_debug.dart index 2708add258def..e1b503643573c 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_debug.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_debug.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:meta/meta.dart'; import 'package:process/process.dart'; +import '../base/error_handling_io.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; @@ -186,7 +187,12 @@ class XcodeDebug { if (currentDebuggingProject != null) { final XcodeDebugProject project = currentDebuggingProject!; if (project.isTemporaryProject) { - project.xcodeProject.parent.deleteSync(recursive: true); + // Only delete if it exists. This is to prevent crashes when racing + // with shutdown hooks to delete temporary files. + ErrorHandlingFileSystem.deleteIfExists( + project.xcodeProject.parent, + recursive: true, + ); } currentDebuggingProject = null; } diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart index 8b25f528ab132..01506cd99dfca 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_logger_test.dart @@ -190,7 +190,7 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt ])); }); - testWithoutContext('IOSDeviceLogReader ignores VM Service logs when attached to debugger', () async { + testWithoutContext('IOSDeviceLogReader ignores VM Service logs when attached to and received flutter logs from debugger', () async { final Event stdoutEvent = Event( kind: 'Stdout', timestamp: 0, @@ -229,14 +229,14 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt iosDeployDebugger.debuggerAttached = true; final Stream debuggingLogs = Stream.fromIterable([ - 'Message from debugger', + 'flutter: Message from debugger', ]); iosDeployDebugger.logLines = debuggingLogs; logReader.debuggerStream = iosDeployDebugger; // Wait for stream listeners to fire. await expectLater(logReader.logLines, emitsInAnyOrder([ - equals('Message from debugger'), + equals('flutter: Message from debugger'), ])); }); }); @@ -365,7 +365,8 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt expect(logReader.useSyslogLogging, isTrue); expect(logReader.useUnifiedLogging, isTrue); expect(logReader.useIOSDeployLogging, isFalse); - expect(logReader.usingMultipleLoggingSources, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.idevicesyslog); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.unifiedLogging); }); testWithoutContext('for wirelessly attached CoreDevice', () { @@ -384,7 +385,8 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt expect(logReader.useSyslogLogging, isFalse); expect(logReader.useUnifiedLogging, isTrue); expect(logReader.useIOSDeployLogging, isFalse); - expect(logReader.usingMultipleLoggingSources, isFalse); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.unifiedLogging); + expect(logReader.logSources.fallbackSource, isNull); }); testWithoutContext('for iOS 12 or less device', () { @@ -401,10 +403,11 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt expect(logReader.useSyslogLogging, isTrue); expect(logReader.useUnifiedLogging, isFalse); expect(logReader.useIOSDeployLogging, isFalse); - expect(logReader.usingMultipleLoggingSources, isFalse); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.idevicesyslog); + expect(logReader.logSources.fallbackSource, isNull); }); - testWithoutContext('for iOS 13 or greater non-CoreDevice', () { + testWithoutContext('for iOS 13 or greater non-CoreDevice and _iosDeployDebugger not attached', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -418,10 +421,11 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt expect(logReader.useSyslogLogging, isFalse); expect(logReader.useUnifiedLogging, isTrue); expect(logReader.useIOSDeployLogging, isTrue); - expect(logReader.usingMultipleLoggingSources, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.unifiedLogging); }); - testWithoutContext('for iOS 13 or greater non-CoreDevice and _iosDeployDebugger is attached', () { + testWithoutContext('for iOS 13 or greater non-CoreDevice, _iosDeployDebugger not attached, and VM is connected', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -432,17 +436,28 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt majorSdkVersion: 13, ); - final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); - iosDeployDebugger.debuggerAttached = true; - logReader.debuggerStream = iosDeployDebugger; + final FlutterVmService vmService = FakeVmServiceHost(requests: [ + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Debug', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stdout', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stderr', + }), + ]).vmService; + + logReader.connectedVMService = vmService; expect(logReader.useSyslogLogging, isFalse); - expect(logReader.useUnifiedLogging, isFalse); + expect(logReader.useUnifiedLogging, isTrue); expect(logReader.useIOSDeployLogging, isTrue); - expect(logReader.usingMultipleLoggingSources, isFalse); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.unifiedLogging); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.iosDeploy); }); - testWithoutContext('for iOS 16 or greater non-CoreDevice', () { + testWithoutContext('for iOS 13 or greater non-CoreDevice and _iosDeployDebugger is attached', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -450,16 +465,35 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt cache: fakeCache, logger: logger, ), - majorSdkVersion: 16, + majorSdkVersion: 13, ); + final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + iosDeployDebugger.debuggerAttached = true; + logReader.debuggerStream = iosDeployDebugger; + + final FlutterVmService vmService = FakeVmServiceHost(requests: [ + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Debug', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stdout', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stderr', + }), + ]).vmService; + + logReader.connectedVMService = vmService; + expect(logReader.useSyslogLogging, isFalse); expect(logReader.useUnifiedLogging, isTrue); expect(logReader.useIOSDeployLogging, isTrue); - expect(logReader.usingMultipleLoggingSources, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.unifiedLogging); }); - testWithoutContext('for iOS 16 or greater non-CoreDevice in CI', () { + testWithoutContext('for iOS 16 or greater non-CoreDevice', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -467,31 +501,21 @@ Runner(libsystem_asl.dylib)[297] : libMobileGestalt cache: fakeCache, logger: logger, ), - usingCISystem: true, majorSdkVersion: 16, ); - expect(logReader.useSyslogLogging, isTrue); + final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + iosDeployDebugger.debuggerAttached = true; + logReader.debuggerStream = iosDeployDebugger; + + expect(logReader.useSyslogLogging, isFalse); expect(logReader.useUnifiedLogging, isTrue); expect(logReader.useIOSDeployLogging, isTrue); - expect(logReader.usingMultipleLoggingSources, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.unifiedLogging); }); - testWithoutContext('syslog sends flutter messages to stream when useSyslogLogging is true', () async { - processManager.addCommand( - FakeCommand( - command: [ - ideviceSyslogPath, '-u', '1234', - ], - stdout: ''' -Runner(Flutter)[297] : A is for ari -Runner(Flutter)[297] : I is for ichigo -May 30 13:56:28 Runner(Flutter)[2037] : flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/ -May 30 13:56:28 Runner(Flutter)[2037] : flutter: This is a test -May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend. -''' - ), - ); + testWithoutContext('for iOS 16 or greater non-CoreDevice in CI', () { final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( iMobileDevice: IMobileDevice( artifacts: artifacts, @@ -502,96 +526,467 @@ May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextM usingCISystem: true, majorSdkVersion: 16, ); - final List lines = await logReader.logLines.toList(); expect(logReader.useSyslogLogging, isTrue); - expect(processManager, hasNoRemainingExpectations); - expect(lines, [ - 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', - 'flutter: This is a test' - ]); - }); - - testWithoutContext('IOSDeviceLogReader only uses ios-deploy debugger when attached and not in CI', () async { - final Stream debuggingLogs = Stream.fromIterable([ - '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - '', - ]); - - final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( - iMobileDevice: IMobileDevice( - artifacts: artifacts, - processManager: processManager, - cache: fakeCache, - logger: logger, - ), - majorSdkVersion: 16, - ); - final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); - iosDeployDebugger.debuggerAttached = true; - iosDeployDebugger.logLines = debuggingLogs; - logReader.debuggerStream = iosDeployDebugger; - final Future> logLines = logReader.logLines.toList(); - final List lines = await logLines; - - expect(logReader.useIOSDeployLogging, isTrue); - expect(logReader.useSyslogLogging, isFalse); expect(logReader.useUnifiedLogging, isFalse); - expect(logReader.usingMultipleLoggingSources, isFalse); - expect(processManager, hasNoRemainingExpectations); - expect( - lines.contains( - '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - ), - isTrue, - ); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.idevicesyslog); }); - testWithoutContext('IOSDeviceLogReader uses both syslog and ios-deploy debugger for CI and filters duplicate messages', () async { - processManager.addCommand( - FakeCommand( - command: [ - ideviceSyslogPath, '-u', '1234', - ], - stdout: ''' -May 30 13:56:28 Runner(Flutter)[2037] : flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/ -May 30 13:56:28 Runner(Flutter)[2037] : flutter: Check for duplicate -May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend. -''' - ), - ); + group('when useSyslogLogging', () { + + testWithoutContext('is true syslog sends flutter messages to stream', () async { + processManager.addCommand( + FakeCommand( + command: [ + ideviceSyslogPath, '-u', '1234', + ], + stdout: ''' + Runner(Flutter)[297] : A is for ari + Runner(Flutter)[297] : I is for ichigo + May 30 13:56:28 Runner(Flutter)[2037] : flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/ + May 30 13:56:28 Runner(Flutter)[2037] : flutter: This is a test + May 30 13:56:28 Runner(Flutter)[2037] : [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend. + ''' + ), + ); + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + usingCISystem: true, + majorSdkVersion: 16, + ); + final List lines = await logReader.logLines.toList(); + + expect(logReader.useSyslogLogging, isTrue); + expect(processManager, hasNoRemainingExpectations); + expect(lines, [ + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + 'flutter: This is a test' + ]); + }); + + testWithoutContext('is false syslog does not send flutter messages to stream', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 16, + ); + + final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + iosDeployDebugger.logLines = Stream.fromIterable([]); + logReader.debuggerStream = iosDeployDebugger; + + final List lines = await logReader.logLines.toList(); + + expect(logReader.useSyslogLogging, isFalse); + expect(processManager, hasNoRemainingExpectations); + expect(lines, isEmpty); + }); + }); - final Stream debuggingLogs = Stream.fromIterable([ - '2023-06-01 12:49:01.445093-0500 Runner[2225:533240] flutter: Check for duplicate', - '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - ]); + group('when useIOSDeployLogging', () { + + testWithoutContext('is true ios-deploy sends flutter messages to stream', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 16, + ); + + final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + final Stream debuggingLogs = Stream.fromIterable([ + 'flutter: Message from debugger', + ]); + iosDeployDebugger.logLines = debuggingLogs; + logReader.debuggerStream = iosDeployDebugger; + + final List lines = await logReader.logLines.toList(); + + expect(logReader.useIOSDeployLogging, isTrue); + expect(processManager, hasNoRemainingExpectations); + expect(lines, [ + 'flutter: Message from debugger', + ]); + }); + + testWithoutContext('is false ios-deploy does not send flutter messages to stream', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 12, + ); + + final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); + final Stream debuggingLogs = Stream.fromIterable([ + 'flutter: Message from debugger', + ]); + iosDeployDebugger.logLines = debuggingLogs; + logReader.debuggerStream = iosDeployDebugger; + + final List lines = await logReader.logLines.toList(); + + expect(logReader.useIOSDeployLogging, isFalse); + expect(processManager, hasNoRemainingExpectations); + expect(lines, isEmpty); + }); + }); - final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( - iMobileDevice: IMobileDevice( - artifacts: artifacts, - processManager: processManager, - cache: fakeCache, - logger: logger, - ), - usingCISystem: true, - majorSdkVersion: 16, - ); - final FakeIOSDeployDebugger iosDeployDebugger = FakeIOSDeployDebugger(); - iosDeployDebugger.logLines = debuggingLogs; - logReader.debuggerStream = iosDeployDebugger; - final Future> logLines = logReader.logLines.toList(); - final List lines = await logLines; + group('when useUnifiedLogging', () { + + + testWithoutContext('is true Dart VM sends flutter messages to stream', () async { + final Event stdoutEvent = Event( + kind: 'Stdout', + timestamp: 0, + bytes: base64.encode(utf8.encode('flutter: A flutter message')), + ); + final Event stderrEvent = Event( + kind: 'Stderr', + timestamp: 0, + bytes: base64.encode(utf8.encode('flutter: A second flutter message')), + ); + final FlutterVmService vmService = FakeVmServiceHost(requests: [ + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Debug', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stdout', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stderr', + }), + FakeVmServiceStreamResponse(event: stdoutEvent, streamId: 'Stdout'), + FakeVmServiceStreamResponse(event: stderrEvent, streamId: 'Stderr'), + ]).vmService; + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + useSyslog: false, + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: processManager, + cache: fakeCache, + logger: logger, + ), + ); + logReader.connectedVMService = vmService; + + // Wait for stream listeners to fire. + expect(logReader.useUnifiedLogging, isTrue); + expect(processManager, hasNoRemainingExpectations); + await expectLater(logReader.logLines, emitsInAnyOrder([ + equals('flutter: A flutter message'), + equals('flutter: A second flutter message'), + ])); + }); + + testWithoutContext('is false Dart VM does not send flutter messages to stream', () async { + final Event stdoutEvent = Event( + kind: 'Stdout', + timestamp: 0, + bytes: base64.encode(utf8.encode('flutter: A flutter message')), + ); + final Event stderrEvent = Event( + kind: 'Stderr', + timestamp: 0, + bytes: base64.encode(utf8.encode('flutter: A second flutter message')), + ); + final FlutterVmService vmService = FakeVmServiceHost(requests: [ + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Debug', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stdout', + }), + const FakeVmServiceRequest(method: 'streamListen', args: { + 'streamId': 'Stderr', + }), + FakeVmServiceStreamResponse(event: stdoutEvent, streamId: 'Stdout'), + FakeVmServiceStreamResponse(event: stderrEvent, streamId: 'Stderr'), + ]).vmService; + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 12, + ); + logReader.connectedVMService = vmService; + + final List lines = await logReader.logLines.toList(); + + // Wait for stream listeners to fire. + expect(logReader.useUnifiedLogging, isFalse); + expect(processManager, hasNoRemainingExpectations); + expect(lines, isEmpty); + }); + }); - expect(logReader.useSyslogLogging, isTrue); - expect(logReader.useIOSDeployLogging, isTrue); - expect(logReader.usingMultipleLoggingSources, isTrue); - expect(processManager, hasNoRemainingExpectations); - expect(lines.length, 3); - expect(lines, containsAll([ - '(lldb) 2023-05-30 13:48:52.461894-0500 Runner[2019:1101495] [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(39)] Using the Impeller rendering backend.', - 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', - 'flutter: Check for duplicate', - ])); + group('and when to exclude logs:', () { + + testWithoutContext('all primary messages are included except if fallback sent flutter message first', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + usingCISystem: true, + majorSdkVersion: 16, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.idevicesyslog); + + final Future> logLines = logReader.logLines.toList(); + + logReader.addToLinesController( + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + IOSDeviceLogSource.idevicesyslog, + ); + // Will be excluded because was already added by fallback. + logReader.addToLinesController( + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + IOSDeviceLogSource.iosDeploy, + ); + logReader.addToLinesController( + 'A second non-flutter message', + IOSDeviceLogSource.iosDeploy, + ); + logReader.addToLinesController( + 'flutter: Another flutter message', + IOSDeviceLogSource.iosDeploy, + ); + final List lines = await logLines; + + expect(lines, containsAllInOrder([ + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', // from idevicesyslog + 'A second non-flutter message', // from iosDeploy + 'flutter: Another flutter message', // from iosDeploy + ])); + }); + + testWithoutContext('all primary messages are included when there is no fallback', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + majorSdkVersion: 12, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.idevicesyslog); + expect(logReader.logSources.fallbackSource, isNull); + + final Future> logLines = logReader.logLines.toList(); + + logReader.addToLinesController( + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'A non-flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'A non-flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + final List lines = await logLines; + + expect(lines, containsAllInOrder([ + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + 'A non-flutter message', + 'A non-flutter message', + 'flutter: A flutter message', + 'flutter: A flutter message', + ])); + }); + + testWithoutContext('primary messages are not added if fallback already added them, otherwise duplicates are allowed', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + usingCISystem: true, + majorSdkVersion: 16, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.idevicesyslog); + + final Future> logLines = logReader.logLines.toList(); + + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'A non-flutter message', + IOSDeviceLogSource.iosDeploy, + ); + logReader.addToLinesController( + 'A non-flutter message', + IOSDeviceLogSource.iosDeploy, + ); + // Will be excluded because was already added by fallback. + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.iosDeploy, + ); + // Will be excluded because was already added by fallback. + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.iosDeploy, + ); + // Will be included because, although the message is the same, the + // fallback only added it twice so this third one is considered new. + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.iosDeploy, + ); + + final List lines = await logLines; + + expect(lines, containsAllInOrder([ + 'flutter: A flutter message', // from idevicesyslog + 'flutter: A flutter message', // from idevicesyslog + 'A non-flutter message', // from iosDeploy + 'A non-flutter message', // from iosDeploy + 'flutter: A flutter message', // from iosDeploy + ])); + }); + + testWithoutContext('flutter fallback messages are included until a primary flutter message is received', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + usingCISystem: true, + majorSdkVersion: 16, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.idevicesyslog); + + final Future> logLines = logReader.logLines.toList(); + + logReader.addToLinesController( + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + IOSDeviceLogSource.idevicesyslog, + ); + logReader.addToLinesController( + 'A second non-flutter message', + IOSDeviceLogSource.iosDeploy, + ); + // Will be included because the first log from primary source wasn't a + // flutter log. + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + // Will be excluded because was already added by fallback, however, it + // will be used to determine a flutter log was received by the primary source. + logReader.addToLinesController( + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', + IOSDeviceLogSource.iosDeploy, + ); + // Will be excluded because flutter log from primary was received. + logReader.addToLinesController( + 'flutter: A third flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + + final List lines = await logLines; + + expect(lines, containsAllInOrder([ + 'flutter: The Dart VM service is listening on http://127.0.0.1:63098/35ZezGIQLnw=/', // from idevicesyslog + 'A second non-flutter message', // from iosDeploy + 'flutter: A flutter message', // from idevicesyslog + ])); + }); + + testWithoutContext('non-flutter fallback messages are not included', () async { + final IOSDeviceLogReader logReader = IOSDeviceLogReader.test( + iMobileDevice: IMobileDevice( + artifacts: artifacts, + processManager: FakeProcessManager.any(), + cache: fakeCache, + logger: logger, + ), + usingCISystem: true, + majorSdkVersion: 16, + ); + + expect(logReader.useSyslogLogging, isTrue); + expect(logReader.useIOSDeployLogging, isTrue); + expect(logReader.logSources.primarySource, IOSDeviceLogSource.iosDeploy); + expect(logReader.logSources.fallbackSource, IOSDeviceLogSource.idevicesyslog); + + final Future> logLines = logReader.logLines.toList(); + + logReader.addToLinesController( + 'flutter: A flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + // Will be excluded because it's from fallback and not a flutter message. + logReader.addToLinesController( + 'A non-flutter message', + IOSDeviceLogSource.idevicesyslog, + ); + + final List lines = await logLines; + + expect(lines, containsAllInOrder([ + 'flutter: A flutter message', + ])); + }); }); }); } diff --git a/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart b/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart index 67aa5838afcda..cbd2416c2d9c2 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart @@ -784,6 +784,69 @@ void main() { expect(status, isTrue); }); + testWithoutContext('prints error message when deleting temporary directory that is nonexistant', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: fakeProcessManager, + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebugProject project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + isTemporaryProject: true, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager: fakeProcessManager, + xcode: xcode, + fileSystem: fileSystem, + ); + + fakeProcessManager.addCommands([ + FakeCommand( + command: [ + 'xcrun', + 'osascript', + '-l', + 'JavaScript', + pathToXcodeAutomationScript, + 'stop', + '--xcode-path', + pathToXcodeApp, + '--project-path', + project.xcodeProject.path, + '--workspace-path', + project.xcodeWorkspace.path, + '--close-window' + ], + stdout: ''' + {"status":true,"errorMessage":null,"debugResult":null} + ''', + ), + ]); + + xcodeDebug.startDebugActionProcess = FakeProcess(); + xcodeDebug.currentDebuggingProject = project; + + expect(xcodeDebug.startDebugActionProcess, isNotNull); + expect(xcodeDebug.currentDebuggingProject, isNotNull); + expect(projectDirectory.existsSync(), isFalse); + expect(xcodeproj.existsSync(), isFalse); + expect(xcworkspace.existsSync(), isFalse); + + final bool status = await xcodeDebug.exit(skipDelay: true); + + expect((xcodeDebug.startDebugActionProcess! as FakeProcess).killed, isTrue); + expect(xcodeDebug.currentDebuggingProject, isNull); + expect(projectDirectory.existsSync(), isFalse); + expect(xcodeproj.existsSync(), isFalse); + expect(xcworkspace.existsSync(), isFalse); + expect(logger.errorText, contains('Failed to delete temporary Xcode project')); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, isTrue); + }); + testWithoutContext('kill Xcode when force exit', () async { final Xcode xcode = setupXcode( fakeProcessManager: FakeProcessManager.any(), @@ -825,6 +888,46 @@ void main() { expect(fakeProcessManager, hasNoRemainingExpectations); expect(exitStatus, isTrue); }); + + testWithoutContext('does not crash when deleting temporary directory that is nonexistant when force exiting', () async { + final Xcode xcode = setupXcode( + fakeProcessManager: FakeProcessManager.any(), + fileSystem: fileSystem, + flutterRoot: flutterRoot, + ); + final XcodeDebugProject project = XcodeDebugProject( + scheme: 'Runner', + xcodeProject: xcodeproj, + xcodeWorkspace: xcworkspace, + isTemporaryProject: true, + ); + final XcodeDebug xcodeDebug = XcodeDebug( + logger: logger, + processManager:FakeProcessManager.any(), + xcode: xcode, + fileSystem: fileSystem, + ); + + xcodeDebug.startDebugActionProcess = FakeProcess(); + xcodeDebug.currentDebuggingProject = project; + + expect(xcodeDebug.startDebugActionProcess, isNotNull); + expect(xcodeDebug.currentDebuggingProject, isNotNull); + expect(projectDirectory.existsSync(), isFalse); + expect(xcodeproj.existsSync(), isFalse); + expect(xcworkspace.existsSync(), isFalse); + + final bool status = await xcodeDebug.exit(force: true); + + expect((xcodeDebug.startDebugActionProcess! as FakeProcess).killed, isTrue); + expect(xcodeDebug.currentDebuggingProject, isNull); + expect(projectDirectory.existsSync(), isFalse); + expect(xcodeproj.existsSync(), isFalse); + expect(xcworkspace.existsSync(), isFalse); + expect(logger.errorText, isEmpty); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(status, isTrue); + }); }); group('stop app', () { From 7f12bbc689795c16a539445b38c767e282a73537 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 14:00:00 -0400 Subject: [PATCH 0698/1547] Roll Flutter Engine from c125e1e23d4b to 46c11916f8d2 (1 revision) (#132502) https://github.com/flutter/engine/compare/c125e1e23d4b...46c11916f8d2 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from 8b051126be8a to a690bd1fb8b8 (1 revision) (flutter/engine#44684) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bda5815512976..ea3c9a2519278 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c125e1e23d4b3ee3f2d6dd4fb57657264b23d8d8 +46c11916f8d2595e776faa9c11354e5d4b1999c0 From 6d87a23b3722e4fb2e2db993322d5be4adf04fb5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 14:36:04 -0400 Subject: [PATCH 0699/1547] Roll Packages from 9b15c2e6ab30 to 08080abd9cbb (5 revisions) (#132505) https://github.com/flutter/packages/compare/9b15c2e6ab30...08080abd9cbb 2023-08-12 66741910+mishapark@users.noreply.github.com [google_maps_flutter] removed old overrides (flutter/packages#4679) 2023-08-11 katelovett@google.com [dynamic_layouts] Refactor flaky test (flutter/packages#4681) 2023-08-11 stuartmorgan@google.com [shared_preferences] Update iOS/macOS Pigeon (flutter/packages#4668) 2023-08-11 tarrinneal@gmail.com [pigeon] skipGen (flutter/packages#4682) 2023-08-11 engine-flutter-autoroll@skia.org Roll Flutter from 685141bf3b5f to 9b6945b465a1 (25 revisions) (flutter/packages#4680) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index aee68635d47e9..4f7a79cdafe89 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -9b15c2e6ab30cb259dd42334a95caa1b0e3b7267 +08080abd9cbb291cc3b4aec4f03454c9c8a88814 From f7bd03202f0788bf3c7aee748b38ba5e5eff8761 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 14 Aug 2023 11:47:08 -0700 Subject: [PATCH 0700/1547] [devicelab] boot up benchmarks. (#132148) Enable Impeller benchmarks for drawAtlas/drawVertices on iOS/Metal, Android/GLES, and Android/Vulkan. Enable impeller tessellation benchmarks on iOS/Metal and Android/Vulkan - not GLES as this is measuring backend agnostic performance. --- .ci.yaml | 107 ++++++++++++++++++ TESTOWNERS | 10 ++ .../draw_atlas_perf__timeline_summary.dart | 14 +++ ...draw_atlas_perf_ios__timeline_summary.dart | 14 +++ ...atlas_perf_opengles__timeline_summary.dart | 14 +++ .../draw_vertices_perf__timeline_summary.dart | 14 +++ ...w_vertices_perf_ios__timeline_summary.dart | 14 +++ ...tices_perf_opengles__timeline_summary.dart | 14 +++ ...h_tessellation_perf__timeline_summary.dart | 14 +++ ...ssellation_perf_ios__timeline_summary.dart | 14 +++ ...h_tessellation_perf__timeline_summary.dart | 14 +++ ...ssellation_perf_ios__timeline_summary.dart | 14 +++ dev/devicelab/lib/tasks/perf_tests.dart | 50 ++++++++ 13 files changed, 307 insertions(+) create mode 100644 dev/devicelab/bin/tasks/draw_atlas_perf__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/draw_atlas_perf_ios__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/draw_atlas_perf_opengles__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/draw_vertices_perf__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/draw_vertices_perf_opengles__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/dynamic_path_tessellation_perf__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/dynamic_path_tessellation_perf_ios__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/static_path_tessellation_perf__timeline_summary.dart create mode 100644 dev/devicelab/bin/tasks/static_path_tessellation_perf_ios__timeline_summary.dart diff --git a/.ci.yaml b/.ci.yaml index d01625198394f..c2a797eddefdf 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1664,6 +1664,51 @@ targets: ["devicelab", "android", "linux", "samsung", "s10"] task_name: backdrop_filter_perf__timeline_summary + + - name: Linux_samsung_s10 draw_atlas_perf_opengles__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: draw_atlas_perf_opengles__timeline_summary + + - name: Linux_samsung_s10 draw_atlas_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: draw_atlas_perf__timeline_summary + + - name: Linux_samsung_s10 dynamic_path_tessellation_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: dynamic_path_tessellation_perf__timeline_summary + + - name: Linux_samsung_s10 static_path_tessellation_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: static_path_tessellation_perf__timeline_summary + - name: Linux_android basic_material_app_android__compile recipe: devicelab/devicelab_drone presubmit: false @@ -2656,6 +2701,68 @@ targets: ["devicelab", "android", "linux", "samsung", "s10"] task_name: animated_blur_backdrop_filter_perf_opengles__timeline_summary + - name: Linux_samsung_s10 draw_vertices_perf_opengles__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: draw_vertices_perf_opengles__timeline_summary + + - name: Linux_samsung_s10 draw_vertices_perf__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "s10"] + task_name: draw_vertices_perf__timeline_summary + + - name: Mac_ios draw_vertices_perf_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + bringup: true + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: draw_vertices_perf_ios__timeline_summary + + - name: Mac_ios draw_atlas_perf_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + bringup: true + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: draw_atlas_perf_ios__timeline_summary + + - name: Mac_ios static_path_tessellation_perf_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + bringup: true + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: static_path_tessellation_perf_ios__timeline_summary + + - name: Mac_ios dynamic_path_tessellation_perf_ios__timeline_summary + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + bringup: true + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: dynamic_path_tessellation_perf_ios__timeline_summary + - name: Staging_build_linux analyze presubmit: false bringup: true diff --git a/TESTOWNERS b/TESTOWNERS index dfd325dd4772e..ed1c75770836c 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -97,6 +97,12 @@ /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf__timeline_summary.dart @jonahwilliams @flutter/engine /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_opengles__timeline_summary.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/slider_perf_android.dart @tahatesser @flutter/framework +/dev/devicelab/bin/tasks/draw_vertices_perf_opengles__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/draw_atlas_perf_opengles__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/draw_vertices_perf__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/draw_atlas_perf__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/static_path_tessellation_perf__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf__timeline_summary.dart @jonahwilliams @flutter/engine ## Windows Android DeviceLab tests /dev/devicelab/bin/tasks/basic_material_app_win__compile.dart @zanderso @flutter/tool @@ -208,6 +214,10 @@ /dev/devicelab/bin/tasks/tiles_scroll_perf_ios__timeline_summary.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine /dev/devicelab/bin/tasks/draw_points_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/draw_atlas_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/static_path_tessellation_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine +/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine ## Host only DeviceLab tests /dev/devicelab/bin/tasks/animated_complex_opacity_perf_macos__e2e_summary.dart @cbracken @flutter/desktop diff --git a/dev/devicelab/bin/tasks/draw_atlas_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/draw_atlas_perf__timeline_summary.dart new file mode 100644 index 0000000000000..9386d64d3b8bd --- /dev/null +++ b/dev/devicelab/bin/tasks/draw_atlas_perf__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createDrawAtlasPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/draw_atlas_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/draw_atlas_perf_ios__timeline_summary.dart new file mode 100644 index 0000000000000..374e5105a8341 --- /dev/null +++ b/dev/devicelab/bin/tasks/draw_atlas_perf_ios__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createDrawAtlasPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/draw_atlas_perf_opengles__timeline_summary.dart b/dev/devicelab/bin/tasks/draw_atlas_perf_opengles__timeline_summary.dart new file mode 100644 index 0000000000000..bbdb935fd6a99 --- /dev/null +++ b/dev/devicelab/bin/tasks/draw_atlas_perf_opengles__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createDrawAtlasPerfTest(forceOpenGLES: true)); +} diff --git a/dev/devicelab/bin/tasks/draw_vertices_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/draw_vertices_perf__timeline_summary.dart new file mode 100644 index 0000000000000..635e4296d285b --- /dev/null +++ b/dev/devicelab/bin/tasks/draw_vertices_perf__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createDrawVerticesPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart new file mode 100644 index 0000000000000..96c02f1409a77 --- /dev/null +++ b/dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createDrawVerticesPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/draw_vertices_perf_opengles__timeline_summary.dart b/dev/devicelab/bin/tasks/draw_vertices_perf_opengles__timeline_summary.dart new file mode 100644 index 0000000000000..d1163ce2baba6 --- /dev/null +++ b/dev/devicelab/bin/tasks/draw_vertices_perf_opengles__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createDrawVerticesPerfTest(forceOpenGLES: true)); +} diff --git a/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf__timeline_summary.dart new file mode 100644 index 0000000000000..47ae2d1ff2817 --- /dev/null +++ b/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createPathTessellationDynamicPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf_ios__timeline_summary.dart new file mode 100644 index 0000000000000..79509a3b36d2b --- /dev/null +++ b/dev/devicelab/bin/tasks/dynamic_path_tessellation_perf_ios__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createPathTessellationDynamicPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/static_path_tessellation_perf__timeline_summary.dart b/dev/devicelab/bin/tasks/static_path_tessellation_perf__timeline_summary.dart new file mode 100644 index 0000000000000..10285bf9e07f3 --- /dev/null +++ b/dev/devicelab/bin/tasks/static_path_tessellation_perf__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createPathTessellationStaticPerfTest()); +} diff --git a/dev/devicelab/bin/tasks/static_path_tessellation_perf_ios__timeline_summary.dart b/dev/devicelab/bin/tasks/static_path_tessellation_perf_ios__timeline_summary.dart new file mode 100644 index 0000000000000..5278dfbb2d740 --- /dev/null +++ b/dev/devicelab/bin/tasks/static_path_tessellation_perf_ios__timeline_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createPathTessellationStaticPerfTest()); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 989b5dcc00e60..0b890f84d803e 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -672,6 +672,56 @@ TaskFunction createDrawPointsPerfTest({ ).run; } +TaskFunction createDrawAtlasPerfTest({ + bool? forceOpenGLES, +}) { + return PerfTest( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test_driver/run_app.dart', + 'draw_atlas_perf', + enableImpeller: true, + testDriver: 'test_driver/draw_atlas_perf.dart', + saveTraceFile: true, + forceOpenGLES: forceOpenGLES, + ).run; +} + +TaskFunction createDrawVerticesPerfTest({ + bool? forceOpenGLES, +}) { + return PerfTest( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test_driver/run_app.dart', + 'draw_vertices_perf', + enableImpeller: true, + testDriver: 'test_driver/draw_vertices_perf_test.dart', + saveTraceFile: true, + forceOpenGLES: forceOpenGLES, + ).run; +} + +TaskFunction createPathTessellationStaticPerfTest() { + return PerfTest( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test_driver/run_app.dart', + 'tessellation_perf_static', + enableImpeller: true, + testDriver: 'test_driver/path_tessellation_static_perf_test.dart', + saveTraceFile: true, + ).run; +} + +TaskFunction createPathTessellationDynamicPerfTest() { + return PerfTest( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test_driver/run_app.dart', + 'tessellation_perf_dynamic', + enableImpeller: true, + testDriver: 'test_driver/path_tessellation_dynamic_perf_test.dart', + saveTraceFile: true, + ).run; +} + TaskFunction createAnimatedComplexOpacityPerfE2ETest({ bool? enableImpeller, }) { From 5b0c7ea2c7747b7c4ae8bfd43ac2fa79275f8c32 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 14:50:56 -0400 Subject: [PATCH 0701/1547] Roll Flutter Engine from 46c11916f8d2 to 56a0e2715dca (2 revisions) (#132508) https://github.com/flutter/engine/compare/46c11916f8d2...56a0e2715dca 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from a690bd1fb8b8 to 1cf6f71c8120 (1 revision) (flutter/engine#44685) 2023-08-14 jmccandless@google.com hasStrings for web (flutter/engine#43360) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ea3c9a2519278..5b03c85609c8a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -46c11916f8d2595e776faa9c11354e5d4b1999c0 +56a0e2715dca989aba14e498342192fed2638d4d From 491ba2307fba0762b9f5541a0e34a8667f13b574 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 14 Aug 2023 13:21:14 -0700 Subject: [PATCH 0702/1547] Update `dev/bots/test.dart` (and friends) to provide `--local-engine-host`. (#132354) Partial work towards https://github.com/flutter/flutter/issues/132245. As far as I can tell, this just plumbs flags downwards and has no semantic changes. --- dev/bots/test.dart | 5 ++++- packages/flutter_tools/README.md | 12 +++++++----- .../test/integration.shard/test_utils.dart | 3 +++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 2b48df03287e4..8408e452d4970 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -213,7 +213,7 @@ String get shuffleSeed { /// /// Examples: /// SHARD=tool_tests bin/cache/dart-sdk/bin/dart dev/bots/test.dart -/// bin/cache/dart-sdk/bin/dart dev/bots/test.dart --local-engine=host_debug_unopt +/// bin/cache/dart-sdk/bin/dart dev/bots/test.dart --local-engine=host_debug_unopt --local-engine-host=host_debug_unopt Future main(List args) async { try { printProgress('STARTING ANALYSIS'); @@ -221,6 +221,9 @@ Future main(List args) async { if (arg.startsWith('--local-engine=')) { localEngineEnv['FLUTTER_LOCAL_ENGINE'] = arg.substring('--local-engine='.length); flutterTestArgs.add(arg); + } else if (arg.startsWith('--local-engine-host=')) { + localEngineEnv['FLUTTER_LOCAL_ENGINE_HOST'] = arg.substring('--local-engine-host='.length); + flutterTestArgs.add(arg); } else if (arg.startsWith('--local-engine-src-path=')) { localEngineEnv['FLUTTER_LOCAL_ENGINE_SRC_PATH'] = arg.substring('--local-engine-src-path='.length); flutterTestArgs.add(arg); diff --git a/packages/flutter_tools/README.md b/packages/flutter_tools/README.md index c52201c29cb7e..606eacfb3ad5b 100644 --- a/packages/flutter_tools/README.md +++ b/packages/flutter_tools/README.md @@ -67,14 +67,16 @@ Please avoid setting any other timeouts. #### Using local engine builds in integration tests The integration tests can be configured to use a specific local engine -variant by setting the `FLUTTER_LOCAL_ENGINE` environment variable to the -name of the local engine (e.g. "android_debug_unopt"). If the local engine build -requires a source path, this can be provided by setting the `FLUTTER_LOCAL_ENGINE_SRC_PATH` -environment variable. This second variable is not necessary if the `flutter` and -`engine` checkouts are in adjacent directories. +variant by setting the `FLUTTER_LOCAL_ENGINE` and `FLUTTER_LOCAL_ENGINE_HOST` +environment svariable to the name of the local engines (e.g. `android_debug_unopt` +and `host_debug_unopt`). If the local engine build requires a source path, this +can be provided by setting the `FLUTTER_LOCAL_ENGINE_SRC_PATH` environment +variable. This second variable is not necessary if the `flutter` and `engine` +checkouts are in adjacent directories. ```shell export FLUTTER_LOCAL_ENGINE=android_debug_unopt +export FLUTTER_LOCAL_ENGINE_HOST=host_debug_unopt flutter test test/integration.shard/some_test_case ``` diff --git a/packages/flutter_tools/test/integration.shard/test_utils.dart b/packages/flutter_tools/test/integration.shard/test_utils.dart index 101828206776f..b13452209a059 100644 --- a/packages/flutter_tools/test/integration.shard/test_utils.dart +++ b/packages/flutter_tools/test/integration.shard/test_utils.dart @@ -67,6 +67,7 @@ Future getPackages(String folder) async { } const String kLocalEngineEnvironment = 'FLUTTER_LOCAL_ENGINE'; +const String kLocalEngineHostEnvironment = 'FLUTTER_LOCAL_ENGINE_HOST'; const String kLocalEngineLocation = 'FLUTTER_LOCAL_ENGINE_SRC_PATH'; List getLocalEngineArguments() { @@ -75,6 +76,8 @@ List getLocalEngineArguments() { '--local-engine=${platform.environment[kLocalEngineEnvironment]}', if (platform.environment.containsKey(kLocalEngineLocation)) '--local-engine-src-path=${platform.environment[kLocalEngineLocation]}', + if (platform.environment.containsKey(kLocalEngineHostEnvironment)) + '--local-engine-host=${platform.environment[kLocalEngineHostEnvironment]}', ]; } From 5c96642fa0598195237d67cae6e282db82576e2a Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 14 Aug 2023 23:30:01 +0300 Subject: [PATCH 0703/1547] Update menu examples for `SafeArea` (#132390) fixes [Some of the menu examples don't contain `SafeArea`](https://github.com/flutter/flutter/issues/132388) ### Description This fixes the menu examples for running on mobile with a safe area. ![Group 2](https://github.com/flutter/flutter/assets/48603081/0d460c00-60f5-45e0-87ee-c010ede9ee42) --- .../menu_anchor/checkbox_menu_button.0.dart | 5 +++-- .../menu_anchor/menu_accelerator_label.0.dart | 2 +- .../lib/material/menu_anchor/menu_anchor.0.dart | 2 +- .../api/lib/material/menu_anchor/menu_bar.0.dart | 2 +- .../material/menu_anchor/radio_menu_button.0.dart | 5 +++-- .../menu_anchor/checkbox_menu_button.0_test.dart | 14 ++++++++++++++ .../menu_anchor/menu_accelerator_label.0_test.dart | 14 ++++++++++++++ .../material/menu_anchor/menu_anchor.0_test.dart | 14 ++++++++++++++ .../test/material/menu_anchor/menu_bar.0_test.dart | 14 ++++++++++++++ .../menu_anchor/radio_menu_button.0_test.dart | 14 ++++++++++++++ 10 files changed, 79 insertions(+), 7 deletions(-) diff --git a/examples/api/lib/material/menu_anchor/checkbox_menu_button.0.dart b/examples/api/lib/material/menu_anchor/checkbox_menu_button.0.dart index 6279b6e2227cf..8a6066f7ce850 100644 --- a/examples/api/lib/material/menu_anchor/checkbox_menu_button.0.dart +++ b/examples/api/lib/material/menu_anchor/checkbox_menu_button.0.dart @@ -101,8 +101,9 @@ class MenuApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold(body: MyCheckboxMenu(message: kMessage)), + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold(body: SafeArea(child: MyCheckboxMenu(message: kMessage))), ); } } diff --git a/examples/api/lib/material/menu_anchor/menu_accelerator_label.0.dart b/examples/api/lib/material/menu_anchor/menu_accelerator_label.0.dart index 802cb9c66d07e..5e09ef9328486 100644 --- a/examples/api/lib/material/menu_anchor/menu_accelerator_label.0.dart +++ b/examples/api/lib/material/menu_anchor/menu_accelerator_label.0.dart @@ -110,7 +110,7 @@ class MenuAcceleratorApp extends StatelessWidget { debugDumpApp(); }), }, - child: const Scaffold(body: MyMenuBar()), + child: const Scaffold(body: SafeArea(child: MyMenuBar())), ), ); } diff --git a/examples/api/lib/material/menu_anchor/menu_anchor.0.dart b/examples/api/lib/material/menu_anchor/menu_anchor.0.dart index 413879d665d30..d4a3de7dece2b 100644 --- a/examples/api/lib/material/menu_anchor/menu_anchor.0.dart +++ b/examples/api/lib/material/menu_anchor/menu_anchor.0.dart @@ -204,7 +204,7 @@ class MenuApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( theme: ThemeData(useMaterial3: true), - home: const Scaffold(body: MyCascadingMenu(message: kMessage)), + home: const Scaffold(body: SafeArea(child: MyCascadingMenu(message: kMessage))), ); } } diff --git a/examples/api/lib/material/menu_anchor/menu_bar.0.dart b/examples/api/lib/material/menu_anchor/menu_bar.0.dart index 23ccec10999ca..b769630027a38 100644 --- a/examples/api/lib/material/menu_anchor/menu_bar.0.dart +++ b/examples/api/lib/material/menu_anchor/menu_bar.0.dart @@ -230,7 +230,7 @@ class MenuBarApp extends StatelessWidget { @override Widget build(BuildContext context) { return const MaterialApp( - home: Scaffold(body: MyMenuBar(message: kMessage)), + home: Scaffold(body: SafeArea(child: MyMenuBar(message: kMessage))), ); } } diff --git a/examples/api/lib/material/menu_anchor/radio_menu_button.0.dart b/examples/api/lib/material/menu_anchor/radio_menu_button.0.dart index 20448926d3e45..3976c88d3745e 100644 --- a/examples/api/lib/material/menu_anchor/radio_menu_button.0.dart +++ b/examples/api/lib/material/menu_anchor/radio_menu_button.0.dart @@ -107,8 +107,9 @@ class MenuApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( - home: Scaffold(body: MyRadioMenu()), + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Scaffold(body: SafeArea(child: MyRadioMenu())), ); } } diff --git a/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart b/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart index 76d27b5693504..5251505868429 100644 --- a/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart +++ b/examples/api/test/material/menu_anchor/checkbox_menu_button.0_test.dart @@ -24,4 +24,18 @@ void main() { expect(find.text('Show Message'), findsNothing); expect(find.text(example.MenuApp.kMessage), findsOneWidget); }); + + testWidgets('MenuAnchor is wrapped in a SafeArea', (WidgetTester tester) async { + const double safeAreaPadding = 100.0; + await tester.pumpWidget( + const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.symmetric(vertical: safeAreaPadding), + ), + child: example.MenuApp(), + ), + ); + + expect(tester.getTopLeft(find.byType(MenuAnchor)), const Offset(0.0, safeAreaPadding)); + }); } diff --git a/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart b/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart index 9cf332dd6966a..89cadb7db30d0 100644 --- a/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart @@ -51,4 +51,18 @@ void main() { await tester.pumpAndSettle(); expect(find.text('Close'), findsNothing); }); + + testWidgets('MenuBar is wrapped in a SafeArea', (WidgetTester tester) async { + const double safeAreaPadding = 100.0; + await tester.pumpWidget( + const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.symmetric(vertical: safeAreaPadding), + ), + child: example.MenuAcceleratorApp(), + ), + ); + + expect(tester.getTopLeft(find.byType(MenuBar)), const Offset(0.0, safeAreaPadding)); + }); } diff --git a/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart b/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart index dcbabb2cba249..11a6becc68004 100644 --- a/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_anchor.0_test.dart @@ -104,4 +104,18 @@ void main() { expect(find.text('Last Selected: ${example.MenuEntry.colorBlue.label}'), findsOneWidget); }); + + testWidgets('MenuAnchor is wrapped in a SafeArea', (WidgetTester tester) async { + const double safeAreaPadding = 100.0; + await tester.pumpWidget( + const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.symmetric(vertical: safeAreaPadding), + ), + child: example.MenuApp(), + ), + ); + + expect(tester.getTopLeft(find.byType(MenuAnchor)), const Offset(0.0, safeAreaPadding)); + }); } diff --git a/examples/api/test/material/menu_anchor/menu_bar.0_test.dart b/examples/api/test/material/menu_anchor/menu_bar.0_test.dart index ccfe4c93577fa..1ba69519c1b07 100644 --- a/examples/api/test/material/menu_anchor/menu_bar.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_bar.0_test.dart @@ -91,4 +91,18 @@ void main() { expect(find.text('Last Selected: Blue Background'), findsOneWidget); }); + + testWidgets('MenuBar is wrapped in a SafeArea', (WidgetTester tester) async { + const double safeAreaPadding = 100.0; + await tester.pumpWidget( + const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.symmetric(vertical: safeAreaPadding), + ), + child: example.MenuBarApp(), + ), + ); + + expect(tester.getTopLeft(find.byType(MenuBar)), const Offset(0.0, safeAreaPadding)); + }); } diff --git a/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart b/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart index 2b88a77522dac..bbc91423e8b5b 100644 --- a/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart +++ b/examples/api/test/material/menu_anchor/radio_menu_button.0_test.dart @@ -74,4 +74,18 @@ void main() { expect(tester.widget>(find.descendant(of: find.byType(RadioMenuButton).at(2), matching: find.byType(Radio))).groupValue, equals(Colors.blue)); expect(tester.widget(find.byType(Container)).color, equals(Colors.blue)); }); + + testWidgets('MenuAnchor is wrapped in a SafeArea', (WidgetTester tester) async { + const double safeAreaPadding = 100.0; + await tester.pumpWidget( + const MediaQuery( + data: MediaQueryData( + padding: EdgeInsets.symmetric(vertical: safeAreaPadding), + ), + child: example.MenuApp(), + ), + ); + + expect(tester.getTopLeft(find.byType(MenuAnchor)), const Offset(0.0, safeAreaPadding)); + }); } From 5de43e2017b28406fac946a727eb1bc3b773b801 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 14 Aug 2023 13:54:15 -0700 Subject: [PATCH 0704/1547] [flutter_tools] hide Skia specific rendering options. (#132509) At some point in the near future, we'll start an Impeller on Android preivew - and later make it the default. Unlike Skia, Impeller does not have a fallback software rendering mode. We'd like to stop suggesting this as an option now, and in the future remove the option to force software rendering. Once impeller is the default, asking for software rendering on Android will result in either an error or falling back to Skia. --- .../flutter_tools/lib/src/commands/run.dart | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 61829b16ebbe2..67b5c0aece89e 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -145,16 +145,20 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment ) ..addFlag('enable-software-rendering', negatable: false, - help: 'Enable rendering using the Skia software backend. ' + help: '(deprecated) Enable rendering using the Skia software backend. ' 'This is useful when testing Flutter on emulators. By default, ' 'Flutter will attempt to either use OpenGL or Vulkan and fall back ' - 'to software when neither is available.', + 'to software when neither is available. This option is not supported ' + 'when using the Impeller rendering engine.', + hide: !verboseHelp, ) ..addFlag('skia-deterministic-rendering', negatable: false, - help: 'When combined with "--enable-software-rendering", this should provide completely ' + help: '(deprecated) When combined with "--enable-software-rendering", this should provide completely ' 'deterministic (i.e. reproducible) Skia rendering. This is useful for testing purposes ' - '(e.g. when comparing screenshots).', + '(e.g. when comparing screenshots). This option is not supported ' + 'when using the Impeller rendering engine.', + hide: !verboseHelp, ) ..addMultiOption('dart-entrypoint-args', abbr: 'a', @@ -682,19 +686,6 @@ class RunCommand extends RunCommandBase { throwToolExit('Hot reload is not supported by ${device.name}. Run with "--no-hot".'); } } - if (await device.isLocalEmulator && await device.supportsHardwareRendering) { - if (boolArg('enable-software-rendering')) { - globals.printStatus( - 'Using software rendering with device ${device.name}. You may get better performance ' - 'with hardware mode by configuring hardware rendering for your device.' - ); - } else { - globals.printStatus( - 'Using hardware rendering with device ${device.name}. If you notice graphics artifacts, ' - 'consider enabling software rendering with "--enable-software-rendering".' - ); - } - } } List? expFlags; From 0a10359f6a20a1807d0299080d1960ad2097d370 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 17:49:05 -0400 Subject: [PATCH 0705/1547] Roll Flutter Engine from 56a0e2715dca to 785b24900a36 (10 revisions) (#132522) https://github.com/flutter/engine/compare/56a0e2715dca...785b24900a36 2023-08-14 amirpanahandeh@yahoo.com Update CompositionAwareMixin to correctly compute composingBase in Web engine (flutter/engine#44139) 2023-08-14 stuartmorgan@google.com Add application:openURLs: forwarding on macOS (flutter/engine#44689) 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from a4377099b25a to 69ea58157190 (1 revision) (flutter/engine#44692) 2023-08-14 chillers@google.com Update embedder_semantics_update.h imports to include flutter namespace (flutter/engine#44670) 2023-08-14 skia-flutter-autoroll@skia.org Roll Dart SDK from 3295a353980a to d445f5a18876 (1 revision) (flutter/engine#44691) 2023-08-14 dnfield@google.com Revert "Make run_tests.py assert that the ios test dylib is at least as new as libFlutter.dylib" (flutter/engine#44690) 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from 1cf6f71c8120 to a4377099b25a (1 revision) (flutter/engine#44688) 2023-08-14 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from JKTVoxVrHjZjBaxG4... to uIGMbDkXoIcpqWjgR... (flutter/engine#44687) 2023-08-14 jonahwilliams@google.com [Impeller] Conditionally set command debug info. (flutter/engine#44274) 2023-08-14 kjlubick@users.noreply.github.com Migrate more GL calls of GrBackend* (flutter/engine#44682) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from JKTVoxVrHjZj to uIGMbDkXoIcp If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5b03c85609c8a..8a941cdf63e09 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -56a0e2715dca989aba14e498342192fed2638d4d +785b24900a360ed872d1f779a65d6c062ce69448 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 104400eccfb64..caae64c0cd817 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -JKTVoxVrHjZjBaxG4cdtYRkXlgD-QKknAFLrCcS91nQC +uIGMbDkXoIcpqWjgR5qZBJ4xzPDq2aHVlM8NWImJbXoC From 9a39a5d69795448e4ad939166080e8e921e435af Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Mon, 14 Aug 2023 15:51:05 -0700 Subject: [PATCH 0706/1547] Selection area should move selection word by word on a long press drag (#132518) On native iOS and Android when long pressing and then dragging the selection expands word by word. Before this change `SelectionArea` expanded the selection character by character on a long press drag. Fixes #104603 --- packages/flutter/lib/src/widgets/selectable_region.dart | 2 +- packages/flutter/test/widgets/selectable_region_test.dart | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 33ca404dceb32..4b3d6e3730a15 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -529,7 +529,7 @@ class SelectableRegionState extends State with TextSelectionDe } void _handleTouchLongPressMoveUpdate(LongPressMoveUpdateDetails details) { - _selectEndTo(offset: details.globalPosition); + _selectEndTo(offset: details.globalPosition, textGranularity: TextGranularity.word); } void _handleTouchLongPressEnd(LongPressEndDetails details) { diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index f70a046a5c7dd..2f70f266f9d58 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -338,6 +338,7 @@ void main() { expect(renderSelectionSpy.events[0].type, SelectionEventType.endEdgeUpdate); final SelectionEdgeUpdateEvent edgeEvent = renderSelectionSpy.events[0] as SelectionEdgeUpdateEvent; expect(edgeEvent.globalPosition, const Offset(200.0, 50.0)); + expect(edgeEvent.granularity, TextGranularity.word); }); testWidgets( @@ -1656,7 +1657,7 @@ void main() { await gesture.up(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61020 - testWidgets('long press and drag touch selection', (WidgetTester tester) async { + testWidgets('long press and drag touch moves selection word by word', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SelectableRegion( @@ -1681,9 +1682,9 @@ void main() { expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); final RenderParagraph paragraph2 = tester.renderObject(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText))); - await gesture.moveTo(textOffsetToPosition(paragraph2, 5)); + await gesture.moveTo(textOffsetToPosition(paragraph2, 7)); expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 12)); - expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 5)); + expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 9)); await gesture.up(); }); From a077189581f052872fa65aa30d04a2a9fdd3c768 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 14 Aug 2023 15:57:58 -0700 Subject: [PATCH 0707/1547] [devicelab] fix NAN/Inf in drawPoints benchmark. (#132526) This is causing the benchmark to not render with Skia. We probably need to CHECK this somewhere in the backend.. --- dev/benchmarks/macrobenchmarks/lib/src/draw_points.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/benchmarks/macrobenchmarks/lib/src/draw_points.dart b/dev/benchmarks/macrobenchmarks/lib/src/draw_points.dart index a3ca792cb50d5..09989f7c695df 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/draw_points.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/draw_points.dart @@ -72,10 +72,10 @@ class PointsPainter extends CustomPainter { } canvas.drawPaint(Paint()..color = Colors.white); for (int i = 0; i < 8; i++) { - final double x = ((size.width / i) + tick) % size.width; + final double x = ((size.width / (i + 1)) + tick) % size.width; for (int j = 0; j < data.length; j += 2) { data[j] = x; - data[j + 1] = (size.height / j) + 200; + data[j + 1] = (size.height / (j + 1)) + 200; } final Paint paint = Paint() ..color = kColors[i] From 99dd6b49722ebad82937cb2ea3566d7948180596 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 23:04:10 +0000 Subject: [PATCH 0708/1547] Bump github/codeql-action from 2.21.3 to 2.21.4 (#132525) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.3 to 2.21.4.
Changelog

Sourced from github/codeql-action's changelog.

CodeQL Action Changelog

See the releases page for the relevant changes to the CodeQL CLI and language packs.

[UNRELEASED]

No user facing changes.

2.21.4 - 14 Aug 2023

  • Update default CodeQL bundle version to 2.14.2. #1831
  • Log a warning if the amount of available disk space runs low during a code scanning run. #1825
  • When downloading CodeQL bundle version 2.13.4 and later, cache these bundles in the Actions tool cache using a simpler version number. #1832
  • Fix an issue that first appeared in CodeQL Action v2.21.2 that prevented CodeQL invocations from being logged. #1833
  • We are rolling out a feature in August 2023 that will improve the quality of file coverage information. #1835

2.21.3 - 08 Aug 2023

  • We are rolling out a feature in August 2023 that will improve multi-threaded performance on larger runners. #1817
  • We are rolling out a feature in August 2023 that adds beta support for Project Lombok when analyzing Java. #1809
  • Reduce disk space usage when downloading the CodeQL bundle. #1820

2.21.2 - 28 Jul 2023

  • Update default CodeQL bundle version to 2.14.1. #1797
  • Avoid duplicating the analysis summary within the logs. #1811

2.21.1 - 26 Jul 2023

  • Improve the handling of fatal errors from the CodeQL CLI. #1795
  • Add the sarif-output output to the analyze action that contains the path to the directory of the generated SARIF. #1799

2.21.0 - 19 Jul 2023

  • CodeQL Action now requires CodeQL CLI 2.9.4 or later. For more information, see the corresponding changelog entry for CodeQL Action version 2.20.4. #1724

2.20.4 - 14 Jul 2023

  • This is the last release of the Action that supports CodeQL CLI versions 2.8.5 to 2.9.3. These versions of the CodeQL CLI were deprecated on June 20, 2023 alongside GitHub Enterprise Server 3.5 and will not be supported by the next release of the CodeQL Action (2.21.0).
    • If you are using one of these versions, please update to CodeQL CLI version 2.9.4 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
    • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.8.5 and 2.9.3, you can replace 'github/codeql-action/@​v2' by 'github/codeql-action/@​v2.20.4' in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
  • We are rolling out a feature in July 2023 that will slightly reduce the default amount of RAM used for query execution, in proportion to the runner's total memory. This will help to avoid out-of-memory failures on larger runners. #1760
  • Update default CodeQL bundle version to 2.14.0. #1762

2.20.3 - 06 Jul 2023

  • Update default CodeQL bundle version to 2.13.5. #1743

2.20.2 - 03 Jul 2023

... (truncated)

Commits
  • a09933a Merge pull request #1838 from github/update-v2.21.4-492a68c32
  • 37116fb Fix positioning of bundle update changelog note
  • c613917 Update changelog for v2.21.4
  • 492a68c Merge pull request #1836 from github/henrymercer/analysis-summary-v2-ff
  • ac49314 Merge pull request #1834 from github/henrymercer/analysis-summary-v2-ff
  • ac35d7a Merge pull request #1835 from github/henrymercer/language-baseline-config
  • d03c744 Don't pass --no- flag as it doesn't exist yet
  • a0407a8 Add changelog note for rollout
  • 8a7b2e9 Enable language specific baselines via feature flag
  • 9a510d9 Rename new analysis summary feature flag
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.21.3&new-version=2.21.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 91d4aa072ae3e..1f96e564eff4e 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@5b6282e01c62d02e720b81eb8a51204f527c3624 + uses: github/codeql-action/upload-sarif@a09933a12a80f87b87005513f0abb1494c27a716 with: sarif_file: results.sarif From 36df9560562bb8964a77588bafdfd9b6c4245a52 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 19:04:13 -0400 Subject: [PATCH 0709/1547] Roll Flutter Engine from 785b24900a36 to 3c8852827646 (2 revisions) (#132530) https://github.com/flutter/engine/compare/785b24900a36...3c8852827646 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from 69ea58157190 to 58397bfd9ab6 (8 revisions) (flutter/engine#44698) 2023-08-14 matanlurey@users.noreply.github.com Update `web_ui/**` to explicitly pass `--local-engine-host` to the `flutter` tool. (flutter/engine#44613) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8a941cdf63e09..a1dd24dd446c7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -785b24900a360ed872d1f779a65d6c062ce69448 +3c8852827646e1740f930bc4d3cae62875b2b605 From e1ec3581bd21ed7d7442634206257c99e2846e0f Mon Sep 17 00:00:00 2001 From: pdblasi-google <109253501+pdblasi-google@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:24:47 -0700 Subject: [PATCH 0710/1547] Updates `AutomatedTestWidgetsFlutterBinding.pump` to support microsecond precision (#132401) * Updated `AutomatedTestWidgetsFlutterBinding.pump` to use microseconds instead of milliseconds * Added a test to prevent regression of the microsecond precision * Fixed a test that incorrectly assumed millisecond precision Closes #112610 --- packages/flutter_test/lib/src/binding.dart | 2 +- packages/flutter_test/test/bindings_test.dart | 14 +++++++++++++- packages/flutter_test/test/widget_tester_test.dart | 9 +++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index 466bf05ce4dd3..f3398fe47d100 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -1257,7 +1257,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding { if (hasScheduledFrame) { _currentFakeAsync!.flushMicrotasks(); handleBeginFrame(Duration( - milliseconds: _clock!.now().millisecondsSinceEpoch, + microseconds: _clock!.now().microsecondsSinceEpoch, )); _currentFakeAsync!.flushMicrotasks(); handleDrawFrame(); diff --git a/packages/flutter_test/test/bindings_test.dart b/packages/flutter_test/test/bindings_test.dart index ef4a1658c2deb..f2ed74c6e3762 100644 --- a/packages/flutter_test/test/bindings_test.dart +++ b/packages/flutter_test/test/bindings_test.dart @@ -12,8 +12,8 @@ library; import 'dart:async'; import 'dart:io'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -57,6 +57,18 @@ void main() { order += 1; }); + testWidgets('timeStamp should be accurate to microsecond precision', (WidgetTester tester) async { + final WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); + + await tester.pumpWidget(const CircularProgressIndicator()); + + final Duration timeStampBefore = widgetsBinding.currentSystemFrameTimeStamp; + await tester.pump(const Duration(microseconds: 12345)); + final Duration timeStampAfter = widgetsBinding.currentSystemFrameTimeStamp; + + expect(timeStampAfter - timeStampBefore, const Duration(microseconds: 12345)); + }); + group('elapseBlocking', () { testWidgets('timer is not called', (WidgetTester tester) async { bool timerCalled = false; diff --git a/packages/flutter_test/test/widget_tester_test.dart b/packages/flutter_test/test/widget_tester_test.dart index 03af510d78a86..e8944bee55da2 100644 --- a/packages/flutter_test/test/widget_tester_test.dart +++ b/packages/flutter_test/test/widget_tester_test.dart @@ -119,12 +119,17 @@ void main() { await tester.pumpFrames(target, const Duration(milliseconds: 55)); - expect(logPaints, [0, 17000, 34000, 50000]); + // `pumpframes` defaults to 16 milliseconds and 683 microseconds per pump, + // so we expect 4 pumps of 16683 microseconds each in the 55ms duration. + expect(logPaints, [0, 16683, 33366, 50049]); logPaints.clear(); await tester.pumpFrames(target, const Duration(milliseconds: 30), const Duration(milliseconds: 10)); - expect(logPaints, [60000, 70000, 80000]); + // Since `pumpFrames` was given a 10ms interval per pump, we expect the + // results to continue from 50049 with 10000 microseconds per pump over + // the 30ms duration. + expect(logPaints, [60049, 70049, 80049]); }); }); group('pageBack', () { From ef528f8939c36646d8c8b089b89269ea21aba5de Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 19:50:23 -0400 Subject: [PATCH 0711/1547] Roll Flutter Engine from 3c8852827646 to 1d63eece6c37 (1 revision) (#132534) https://github.com/flutter/engine/compare/3c8852827646...1d63eece6c37 2023-08-14 zanderso@users.noreply.github.com Update android_embedding_bundle CIPD instructions (flutter/engine#44644) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a1dd24dd446c7..6c1fc8a66e6b6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3c8852827646e1740f930bc4d3cae62875b2b605 +1d63eece6c37aa467b1d4e1e1d564c9e84411417 From 51a0ec006fbac207ad976dd5423bbb87ec3929de Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 14 Aug 2023 17:03:48 -0700 Subject: [PATCH 0712/1547] [devicelab] fix name of flutter driver benchmark. (#132527) Missing the _test.dart --- dev/devicelab/lib/tasks/perf_tests.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 0b890f84d803e..792cb51f352c8 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -680,7 +680,7 @@ TaskFunction createDrawAtlasPerfTest({ 'test_driver/run_app.dart', 'draw_atlas_perf', enableImpeller: true, - testDriver: 'test_driver/draw_atlas_perf.dart', + testDriver: 'test_driver/draw_atlas_perf_test.dart', saveTraceFile: true, forceOpenGLES: forceOpenGLES, ).run; From 668a00228064434fb6fbd01f2870b33cb8e76b90 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 20:43:08 -0400 Subject: [PATCH 0713/1547] Roll Flutter Engine from 1d63eece6c37 to f1f912c0c7c7 (2 revisions) (#132538) https://github.com/flutter/engine/compare/1d63eece6c37...f1f912c0c7c7 2023-08-14 skia-flutter-autoroll@skia.org Roll Skia from 58397bfd9ab6 to f636188df4e2 (1 revision) (flutter/engine#44700) 2023-08-14 skia-flutter-autoroll@skia.org Roll Dart SDK from d445f5a18876 to 8731e9796eb3 (1 revision) (flutter/engine#44699) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6c1fc8a66e6b6..b6450f0119211 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1d63eece6c37aa467b1d4e1e1d564c9e84411417 +f1f912c0c7c78a42248862396b06f796e457310f From ccdf82646620da3e84788826adf8d7c36cb68760 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Mon, 14 Aug 2023 17:55:07 -0700 Subject: [PATCH 0714/1547] PaginatedDataTable improvements (#131374) - slightly improved assert message when row cell counts don't match column count. - more breadcrumbs in API documentation. more documentation in general. - added more documentation for the direction of the "ascending" arrow. - two samples for PaginatedDataTable. - make PaginatedDataTable support hot reloading across changes to the number of columns. - introduce matrix3MoreOrLessEquals. An earlier version of this PR used it in tests, but eventually it was not needed. The function seems useful to keep though. --- .../paginated_data_table.0.dart | 86 +++++ .../paginated_data_table.1.dart | 307 ++++++++++++++++++ .../paginated_data_table.0_test.dart | 13 + .../paginated_data_table.1_test.dart | 23 ++ .../flutter/lib/src/material/data_table.dart | 6 +- .../lib/src/material/data_table_source.dart | 23 +- .../src/material/paginated_data_table.dart | 56 +++- .../test/material/data_table_test.dart | 6 +- packages/flutter_test/lib/src/matchers.dart | 23 ++ packages/flutter_test/test/matchers_test.dart | 30 ++ 10 files changed, 555 insertions(+), 18 deletions(-) create mode 100644 examples/api/lib/material/paginated_data_table/paginated_data_table.0.dart create mode 100644 examples/api/lib/material/paginated_data_table/paginated_data_table.1.dart create mode 100644 examples/api/test/material/paginated_data_table/paginated_data_table.0_test.dart create mode 100644 examples/api/test/material/paginated_data_table/paginated_data_table.1_test.dart diff --git a/examples/api/lib/material/paginated_data_table/paginated_data_table.0.dart b/examples/api/lib/material/paginated_data_table/paginated_data_table.0.dart new file mode 100644 index 0000000000000..8249d5e62fff9 --- /dev/null +++ b/examples/api/lib/material/paginated_data_table/paginated_data_table.0.dart @@ -0,0 +1,86 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [PaginatedDataTable]. + +class MyDataSource extends DataTableSource { + @override + int get rowCount => 3; + + @override + DataRow? getRow(int index) { + switch (index) { + case 0: return const DataRow( + cells: [ + DataCell(Text('Sarah')), + DataCell(Text('19')), + DataCell(Text('Student')), + ], + ); + case 1: return const DataRow( + cells: [ + DataCell(Text('Janine')), + DataCell(Text('43')), + DataCell(Text('Professor')), + ], + ); + case 2: return const DataRow( + cells: [ + DataCell(Text('William')), + DataCell(Text('27')), + DataCell(Text('Associate Professor')), + ], + ); + default: return null; + } + } + + @override + bool get isRowCountApproximate => false; + + @override + int get selectedRowCount => 0; +} + +final DataTableSource dataSource = MyDataSource(); + +void main() => runApp(const DataTableExampleApp()); + +class DataTableExampleApp extends StatelessWidget { + const DataTableExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: SingleChildScrollView( + padding: EdgeInsets.all(12.0), + child: DataTableExample(), + ), + ); + } +} + +class DataTableExample extends StatelessWidget { + const DataTableExample({super.key}); + + @override + Widget build(BuildContext context) { + return PaginatedDataTable( + columns: const [ + DataColumn( + label: Text('Name'), + ), + DataColumn( + label: Text('Age'), + ), + DataColumn( + label: Text('Role'), + ), + ], + source: dataSource, + ); + } +} diff --git a/examples/api/lib/material/paginated_data_table/paginated_data_table.1.dart b/examples/api/lib/material/paginated_data_table/paginated_data_table.1.dart new file mode 100644 index 0000000000000..bc4eff6a93ac4 --- /dev/null +++ b/examples/api/lib/material/paginated_data_table/paginated_data_table.1.dart @@ -0,0 +1,307 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [PaginatedDataTable]. + +class MyDataSource extends DataTableSource { + static const List _displayIndexToRawIndex = [ 0, 3, 4, 5, 6 ]; + + late List>> sortedData; + void setData(List>> rawData, int sortColumn, bool sortAscending) { + sortedData = rawData.toList()..sort((List> a, List> b) { + final Comparable cellA = a[_displayIndexToRawIndex[sortColumn]]; + final Comparable cellB = b[_displayIndexToRawIndex[sortColumn]]; + return cellA.compareTo(cellB) * (sortAscending ? 1 : -1); + }); + notifyListeners(); + } + + @override + int get rowCount => sortedData.length; + + static DataCell cellFor(Object data) { + String value; + if (data is DateTime) { + value = '${data.year}-${data.month.toString().padLeft(2, '0')}-${data.day.toString().padLeft(2, '0')}'; + } else { + value = data.toString(); + } + return DataCell(Text(value)); + } + + @override + DataRow? getRow(int index) { + return DataRow.byIndex( + index: sortedData[index][0] as int, + cells: [ + cellFor('S${sortedData[index][1]}E${sortedData[index][2].toString().padLeft(2, '0')}'), + cellFor(sortedData[index][3]), + cellFor(sortedData[index][4]), + cellFor(sortedData[index][5]), + cellFor(sortedData[index][6]), + ], + ); + } + + @override + bool get isRowCountApproximate => false; + + @override + int get selectedRowCount => 0; +} + +void main() => runApp(const DataTableExampleApp()); + +class DataTableExampleApp extends StatelessWidget { + const DataTableExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: SingleChildScrollView( + padding: EdgeInsets.all(12.0), + child: DataTableExample(), + ), + ); + } +} + +class DataTableExample extends StatefulWidget { + const DataTableExample({super.key}); + + @override + State createState() => _DataTableExampleState(); +} + +class _DataTableExampleState extends State { + final MyDataSource dataSource = MyDataSource() + ..setData(episodes, 0, true); + + int _columnIndex = 0; + bool _columnAscending = true; + + void _sort(int columnIndex, bool ascending) { + setState(() { + _columnIndex = columnIndex; + _columnAscending = ascending; + dataSource.setData(episodes, _columnIndex, _columnAscending); + }); + } + + @override + Widget build(BuildContext context) { + return PaginatedDataTable( + sortColumnIndex: _columnIndex, + sortAscending: _columnAscending, + columns: [ + DataColumn( + label: const Text('Episode'), + onSort: _sort, + ), + DataColumn( + label: const Text('Title'), + onSort: _sort, + ), + DataColumn( + label: const Text('Director'), + onSort: _sort, + ), + DataColumn( + label: const Text('Writer(s)'), + onSort: _sort, + ), + DataColumn( + label: const Text('Air Date'), + onSort: _sort, + ), + ], + source: dataSource, + ); + } +} + +final List>> episodes = >>[ + >[ + 1, + 1, + 1, + 'Strange New Worlds', + 'Akiva Goldsman', + 'Akiva Goldsman, Alex Kurtzman, Jenny Lumet', + DateTime(2022, 5, 5), + ], + >[ + 2, + 1, + 2, + 'Children of the Comet', + 'Maja Vrvilo', + 'Henry Alonso Myers, Sarah Tarkoff', + DateTime(2022, 5, 12), + ], + >[ + 3, + 1, + 3, + 'Ghosts of Illyria', + 'Leslie Hope', + 'Akela Cooper, Bill Wolkoff', + DateTime(2022, 5, 19), + ], + >[ + 4, + 1, + 4, + 'Memento Mori', + 'Dan Liu', + 'Davy Perez, Beau DeMayo', + DateTime(2022, 5, 26), + ], + >[ + 5, + 1, + 5, + 'Spock Amok', + 'Rachel Leiterman', + 'Henry Alonso Myers, Robin Wasserman', + DateTime(2022, 6, 2), + ], + >[ + 6, + 1, + 6, + 'Lift Us Where Suffering Cannot Reach', + 'Andi Armaganian', + 'Robin Wasserman, Bill Wolkoff', + DateTime(2022, 6, 9), + ], + >[ + 7, + 1, + 7, + 'The Serene Squall', + 'Sydney Freeland', + 'Beau DeMayo, Sarah Tarkoff', + DateTime(2022, 6, 16), + ], + >[ + 8, + 1, + 8, + 'The Elysian Kingdom', + 'Amanda Row', + 'Akela Cooper, Onitra Johnson', + DateTime(2022, 6, 23), + ], + >[ + 9, + 1, + 9, + 'All Those Who Wander', + 'Christopher J. Byrne', + 'Davy Perez', + DateTime(2022, 6, 30), + ], + >[ + 10, + 2, + 10, + 'A Quality of Mercy', + 'Chris Fisher', + 'Henry Alonso Myers, Akiva Goldsman', + DateTime(2022, 7, 7), + ], + >[ + 11, + 2, + 1, + 'The Broken Circle', + 'Chris Fisher', + 'Henry Alonso Myers, Akiva Goldsman', + DateTime(2023, 6, 15), + ], + >[ + 12, + 2, + 2, + 'Ad Astra per Aspera', + 'Valerie Weiss', + 'Dana Horgan', + DateTime(2023, 6, 22), + ], + >[ + 13, + 2, + 3, + 'Tomorrow and Tomorrow and Tomorrow', + 'Amanda Row', + 'David Reed', + DateTime(2023, 6, 29), + ], + >[ + 14, + 2, + 4, + 'Among the Lotus Eaters', + 'Eduardo Sánchez', + 'Kirsten Beyer, Davy Perez', + DateTime(2023, 7, 6), + ], + >[ + 15, + 2, + 5, + 'Charades', + 'Jordan Canning', + 'Kathryn Lyn, Henry Alonso Myers', + DateTime(2023, 7, 13), + ], + >[ + 16, + 2, + 6, + 'Lost in Translation', + 'Dan Liu', + 'Onitra Johnson, David Reed', + DateTime(2023, 7, 20), + ], + >[ + 17, + 2, + 7, + 'Those Old Scientists', + 'Jonathan Frakes', + 'Kathryn Lyn, Bill Wolkoff', + DateTime(2023, 7, 22), + ], + >[ + 18, + 2, + 8, + 'Under the Cloak of War', + '', + 'Davy Perez', + DateTime(2023, 7, 27), + ], + >[ + 19, + 2, + 9, + 'Subspace Rhapsody', + '', + 'Dana Horgan, Bill Wolkoff', + DateTime(2023, 8, 3), + ], + >[ + 20, + 2, + 10, + 'Hegemony', + '', + 'Henry Alonso Myers', + DateTime(2023, 8, 10), + ], +]; diff --git a/examples/api/test/material/paginated_data_table/paginated_data_table.0_test.dart b/examples/api/test/material/paginated_data_table/paginated_data_table.0_test.dart new file mode 100644 index 0000000000000..31084fc2634e8 --- /dev/null +++ b/examples/api/test/material/paginated_data_table/paginated_data_table.0_test.dart @@ -0,0 +1,13 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/material/paginated_data_table/paginated_data_table.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('PaginatedDataTable 0', (WidgetTester tester) async { + await tester.pumpWidget(const example.DataTableExampleApp()); + expect(find.text('Associate Professor'), findsOneWidget); + }); +} diff --git a/examples/api/test/material/paginated_data_table/paginated_data_table.1_test.dart b/examples/api/test/material/paginated_data_table/paginated_data_table.1_test.dart new file mode 100644 index 0000000000000..7a3bb9168586a --- /dev/null +++ b/examples/api/test/material/paginated_data_table/paginated_data_table.1_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/paginated_data_table/paginated_data_table.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('PaginatedDataTable 1', (WidgetTester tester) async { + await tester.pumpWidget(const example.DataTableExampleApp()); + expect(find.text('Strange New Worlds'), findsOneWidget); + await tester.tap(find.byIcon(Icons.arrow_upward).at(1)); + await tester.pump(); + expect(find.text('Strange New Worlds'), findsNothing); + await tester.tap(find.byIcon(Icons.chevron_right)); + await tester.pump(); + expect(find.text('Strange New Worlds'), findsOneWidget); + await tester.tap(find.byIcon(Icons.arrow_upward).at(1)); + await tester.pump(); + expect(find.text('Strange New Worlds'), findsNothing); + }); +} diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index b1c01ce207994..a7ed565f3a159 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -444,7 +444,7 @@ class DataTable extends StatelessWidget { this.clipBehavior = Clip.none, }) : assert(columns.isNotEmpty), assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)), - assert(!rows.any((DataRow row) => row.cells.length != columns.length)), + assert(!rows.any((DataRow row) => row.cells.length != columns.length), 'All rows must have the same number of cells as there are header cells (${columns.length})'), assert(dividerThickness == null || dividerThickness >= 0), assert(dataRowMinHeight == null || dataRowMaxHeight == null || dataRowMaxHeight >= dataRowMinHeight), assert(dataRowHeight == null || (dataRowMinHeight == null && dataRowMaxHeight == null), @@ -467,6 +467,8 @@ class DataTable extends StatelessWidget { /// /// When this is null, it implies that the table's sort order does /// not correspond to any of the columns. + /// + /// The direction of the sort is specified using [sortAscending]. final int? sortColumnIndex; /// Whether the column mentioned in [sortColumnIndex], if any, is sorted @@ -479,6 +481,8 @@ class DataTable extends StatelessWidget { /// If false, the order is descending (meaning the rows with the /// smallest values for the current sort column are last in the /// table). + /// + /// Ascending order is represented by an upwards-facing arrow. final bool sortAscending; /// Invoked when the user selects or unselects every row, using the diff --git a/packages/flutter/lib/src/material/data_table_source.dart b/packages/flutter/lib/src/material/data_table_source.dart index dd7e8b9febc05..7b51441f96f27 100644 --- a/packages/flutter/lib/src/material/data_table_source.dart +++ b/packages/flutter/lib/src/material/data_table_source.dart @@ -18,21 +18,32 @@ import 'data_table.dart'; /// /// DataTableSource objects are expected to be long-lived, not recreated with /// each build. +/// +/// If a [DataTableSource] is used with a [PaginatedDataTable] that supports +/// sortable columns (see [DataColumn.onSort] and +/// [PaginatedDataTable.sortColumnIndex]), the rows reported by the data source +/// must be reported in the sorted order. abstract class DataTableSource extends ChangeNotifier { /// Called to obtain the data about a particular row. /// + /// Rows should be keyed so that state can be maintained when the data source + /// is sorted (e.g. in response to [DataColumn.onSort]). Keys should be + /// consistent for a given [DataRow] regardless of the sort order (i.e. the + /// key represents the data's identity, not the row position). + /// /// The [DataRow.byIndex] constructor provides a convenient way to construct - /// [DataRow] objects for this callback's purposes without having to worry about - /// independently keying each row. + /// [DataRow] objects for this method's purposes without having to worry about + /// independently keying each row. The index passed to that constructor is the + /// index of the underlying data, which is different than the `index` + /// parameter for [getRow], which represents the _sorted_ position. /// /// If the given index does not correspond to a row, or if no data is yet /// available for a row, then return null. The row will be left blank and a /// loading indicator will be displayed over the table. Once data is available /// or once it is firmly established that the row index in question is beyond - /// the end of the table, call [notifyListeners]. + /// the end of the table, call [notifyListeners]. (See [rowCount].) /// - /// Data returned from this method must be consistent for the lifetime of the - /// object. If the row count changes, then a new delegate must be provided. + /// If the underlying data changes, call [notifyListeners]. DataRow? getRow(int index); /// Called to obtain the number of rows to tell the user are available. @@ -58,5 +69,7 @@ abstract class DataTableSource extends ChangeNotifier { /// Called to obtain the number of rows that are currently selected. /// /// If the selected row count changes, call [notifyListeners]. + /// + /// Selected rows are those whose [DataRow.selected] property is set to true. int get selectedRowCount; } diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index ef85796455910..f30cff990356e 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -31,6 +31,23 @@ import 'theme.dart'; /// If the [key] is a [PageStorageKey], the [initialFirstRowIndex] is persisted /// to [PageStorage]. /// +/// {@tool dartpad} +/// +/// This sample shows how to display a [DataTable] with three columns: name, +/// age, and role. The columns are defined by three [DataColumn] objects. The +/// table contains three rows of data for three example users, the data for +/// which is defined by three [DataRow] objects. +/// +/// ** See code in examples/api/lib/material/paginated_data_table/paginated_data_table.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// +/// This example shows how paginated data tables can supported sorted data. +/// +/// ** See code in examples/api/lib/material/paginated_data_table/paginated_data_table.1.dart ** +/// {@end-tool} +/// /// See also: /// /// * [DataTable], which is not paginated. @@ -142,13 +159,15 @@ class PaginatedDataTable extends StatefulWidget { /// The current primary sort key's column. /// - /// See [DataTable.sortColumnIndex]. + /// See [DataTable.sortColumnIndex] for details. + /// + /// The direction of the sort is specified using [sortAscending]. final int? sortColumnIndex; /// Whether the column mentioned in [sortColumnIndex], if any, is sorted /// in ascending order. /// - /// See [DataTable.sortAscending]. + /// See [DataTable.sortAscending] for details. final bool sortAscending; /// Invoked when the user selects or unselects every row, using the @@ -297,10 +316,27 @@ class PaginatedDataTableState extends State { if (oldWidget.source != widget.source) { oldWidget.source.removeListener(_handleDataSourceChanged); widget.source.addListener(_handleDataSourceChanged); - _handleDataSourceChanged(); + _updateCaches(); } } + @override + void reassemble() { + super.reassemble(); + // This function is called during hot reload. + // + // Normally, if the data source changes, it would notify its listeners and + // thus trigger _handleDataSourceChanged(), which clears the row cache and + // causes the widget to rebuild. + // + // During a hot reload, though, a data source can change in ways that will + // invalidate the row cache (e.g. adding or removing columns) without ever + // triggering a notification, leaving the PaginatedDataTable in an invalid + // state. This method handles this case by clearing the cache any time the + // widget is involved in a hot reload. + _updateCaches(); + } + @override void dispose() { widget.source.removeListener(_handleDataSourceChanged); @@ -308,12 +344,14 @@ class PaginatedDataTableState extends State { } void _handleDataSourceChanged() { - setState(() { - _rowCount = widget.source.rowCount; - _rowCountApproximate = widget.source.isRowCountApproximate; - _selectedRowCount = widget.source.selectedRowCount; - _rows.clear(); - }); + setState(_updateCaches); + } + + void _updateCaches() { + _rowCount = widget.source.rowCount; + _rowCountApproximate = widget.source.isRowCountApproximate; + _selectedRowCount = widget.source.selectedRowCount; + _rows.clear(); } /// Ensures that the given row is visible. diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 8b71d9eca43da..2863d8a606ec3 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -469,11 +469,11 @@ void main() { await tester.pumpWidget(MaterialApp( home: Material(child: buildTable()), )); - // The `tester.widget` ensures that there is exactly one upward arrow. final Finder iconFinder = find.descendant( of: find.byType(DataTable), matching: find.widgetWithIcon(Transform, Icons.arrow_upward), ); + // The `tester.widget` ensures that there is exactly one upward arrow. Transform transformOfArrow = tester.widget(iconFinder); expect( transformOfArrow.transform.getRotation(), @@ -521,11 +521,11 @@ void main() { await tester.pumpWidget(MaterialApp( home: Material(child: buildTable()), )); - // The `tester.widget` ensures that there is exactly one upward arrow. final Finder iconFinder = find.descendant( of: find.byType(DataTable), matching: find.widgetWithIcon(Transform, Icons.arrow_upward), ); + // The `tester.widget` ensures that there is exactly one upward arrow. Transform transformOfArrow = tester.widget(iconFinder); expect( transformOfArrow.transform.getRotation(), @@ -574,11 +574,11 @@ void main() { await tester.pumpWidget(MaterialApp( home: Material(child: buildTable()), )); - // The `tester.widget` ensures that there is exactly one upward arrow. final Finder iconFinder = find.descendant( of: find.byType(DataTable), matching: find.widgetWithIcon(Transform, Icons.arrow_upward), ); + // The `tester.widget` ensures that there is exactly one upward arrow. Transform transformOfArrow = tester.widget(iconFinder); expect( transformOfArrow.transform.getRotation(), diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index 54d02bf540432..9742411bee12e 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -12,6 +12,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:matcher/expect.dart'; import 'package:matcher/src/expect/async_matcher.dart'; // ignore: implementation_imports +import 'package:vector_math/vector_math_64.dart' show Matrix3; import '_matchers_io.dart' if (dart.library.html) '_matchers_web.dart' show MatchesGoldenFile, captureImage; import 'accessibility.dart'; @@ -345,10 +346,24 @@ Matcher rectMoreOrLessEquals(Rect value, { double epsilon = precisionErrorTolera /// /// * [moreOrLessEquals], which is for [double]s. /// * [offsetMoreOrLessEquals], which is for [Offset]s. +/// * [matrix3MoreOrLessEquals], which is for [Matrix3]s. Matcher matrixMoreOrLessEquals(Matrix4 value, { double epsilon = precisionErrorTolerance }) { return _IsWithinDistance(_matrixDistance, value, epsilon); } +/// Asserts that two [Matrix3]s are equal, within some tolerated error. +/// +/// {@macro flutter.flutter_test.moreOrLessEquals} +/// +/// See also: +/// +/// * [moreOrLessEquals], which is for [double]s. +/// * [offsetMoreOrLessEquals], which is for [Offset]s. +/// * [matrixMoreOrLessEquals], which is for [Matrix4]s. +Matcher matrix3MoreOrLessEquals(Matrix3 value, { double epsilon = precisionErrorTolerance }) { + return _IsWithinDistance(_matrix3Distance, value, epsilon); +} + /// Asserts that two [Offset]s are equal, within some tolerated error. /// /// {@macro flutter.flutter_test.moreOrLessEquals} @@ -1443,6 +1458,14 @@ double _matrixDistance(Matrix4 a, Matrix4 b) { return delta; } +double _matrix3Distance(Matrix3 a, Matrix3 b) { + double delta = 0.0; + for (int i = 0; i < 9; i += 1) { + delta = math.max((a[i] - b[i]).abs(), delta); + } + return delta; +} + double _sizeDistance(Size a, Size b) { // TODO(a14n): remove ignore when lint is updated, https://github.com/dart-lang/linter/issues/1843 // ignore: unnecessary_parenthesis diff --git a/packages/flutter_test/test/matchers_test.dart b/packages/flutter_test/test/matchers_test.dart index 7a5aa13fa5f94..7e37125c808bd 100644 --- a/packages/flutter_test/test/matchers_test.dart +++ b/packages/flutter_test/test/matchers_test.dart @@ -10,6 +10,7 @@ import 'dart:typed_data'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:vector_math/vector_math_64.dart' show Matrix3; /// Class that makes it easy to mock common toStringDeep behavior. class _MockToStringDeep { @@ -251,6 +252,35 @@ void main() { ); }); + test('matrix3MoreOrLessEquals', () { + expect( + Matrix3.rotationZ(math.pi), + matrix3MoreOrLessEquals(Matrix3.fromList([ + -1, 0, 0, + 0, -1, 0, + 0, 0, 1, + ])) + ); + + expect( + Matrix3.rotationZ(math.pi), + matrix3MoreOrLessEquals(Matrix3.fromList([ + -2, 0, 0, + 0, -2, 0, + 0, 0, 1, + ]), epsilon: 2) + ); + + expect( + Matrix3.rotationZ(math.pi), + isNot(matrix3MoreOrLessEquals(Matrix3.fromList([ + -2, 0, 0, + 0, -2, 0, + 0, 0, 1, + ]))) + ); + }); + test('rectMoreOrLessEquals', () { expect( const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), From 2f54ff6c99dc5c8dc54f0178f1890e3b9db6607e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 21:27:31 -0400 Subject: [PATCH 0715/1547] Roll Flutter Engine from f1f912c0c7c7 to 21aed05ad751 (1 revision) (#132540) https://github.com/flutter/engine/compare/f1f912c0c7c7...21aed05ad751 2023-08-14 10456171+caroqliu@users.noreply.github.com [fuchsia] Delete obsolete GFX-specific source files (flutter/engine#44594) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b6450f0119211..6980af65dfbcd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f1f912c0c7c78a42248862396b06f796e457310f +21aed05ad75150ff1420893a28b2f45326103351 From 29924c7ccdfa480de8e0e99f89ad967b9a8cf556 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Mon, 14 Aug 2023 18:27:32 -0700 Subject: [PATCH 0716/1547] Manual roll of docker focal version. (#132536) This manual roll is needed to update the jdk apt package. Bug: https://github.com/flutter/flutter/issues/132531 --- dev/ci/docker_linux/Dockerfile | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/dev/ci/docker_linux/Dockerfile b/dev/ci/docker_linux/Dockerfile index 9cba6dcdbf1de..caec75d6535b2 100644 --- a/dev/ci/docker_linux/Dockerfile +++ b/dev/ci/docker_linux/Dockerfile @@ -12,7 +12,7 @@ # Last manual update 2021-09-24 (changing this comment will re-build image) -FROM ubuntu:focal@sha256:c9820a44b950956a790c354700c1166a7ec648bc0d215fa438d3a339812f1d01 +FROM ubuntu:focal@sha256:33a5cc25d22c45900796a1aca487ad7a7cb09f09ea00b779e3b2026b4fc2faba MAINTAINER Flutter Developers ENV TZ=America/Los_Angeles @@ -48,14 +48,9 @@ RUN apt-get update && apt-get install -y google-cloud-sdk && \ gcloud config set core/disable_usage_reporting true && \ gcloud config set component_manager/disable_update_check true -# Add repo for OpenJDK from JFrog.io -RUN wget -q -O - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add - -RUN echo 'deb [arch=amd64] https://adoptopenjdk.jfrog.io/adoptopenjdk/deb bullseye main' | \ - tee /etc/apt/sources.list.d/adoptopenjdk.list - # Install the dependencies needed for the rest of the build. RUN apt-get update && apt-get install -y --no-install-recommends \ - adoptopenjdk-11-hotspot \ + openjdk-17-jdk \ build-essential \ default-jdk-headless \ gcc \ @@ -70,7 +65,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ruby-dev && \ apt-get clean -ENV JAVA_HOME="/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64" +ENV JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64" # Install the Android SDK Dependency. # In the event of an update you can visit this page: https://developer.android.com/studio and scroll to the bottom to find From 25318599c136edcc2109d536646c4ae3d4aaa5ee Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 14 Aug 2023 23:55:06 -0400 Subject: [PATCH 0717/1547] Roll Flutter Engine from 21aed05ad751 to 6975ee1b6de7 (1 revision) (#132543) https://github.com/flutter/engine/compare/21aed05ad751...6975ee1b6de7 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from f636188df4e2 to 022415d74e73 (2 revisions) (flutter/engine#44706) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6980af65dfbcd..5a7d6fdba7bc9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -21aed05ad75150ff1420893a28b2f45326103351 +6975ee1b6de7afc31d713b0b073ace129eb89b56 From b4842cfade2b429df6fc563b0d1e56460191454b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 03:00:39 -0400 Subject: [PATCH 0718/1547] Roll Flutter Engine from 6975ee1b6de7 to a17130ac4d49 (5 revisions) (#132550) https://github.com/flutter/engine/compare/6975ee1b6de7...a17130ac4d49 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from d8d880c560f8 to e137aad081a3 (1 revision) (flutter/engine#44712) 2023-08-15 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from AvjxPvh-niiyQpYoD... to -16K9GvYE3a4Bqs0G... (flutter/engine#44710) 2023-08-15 brianosman@google.com Stop using deprecated GrBackendRenderTarget constructor (flutter/engine#44694) 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from 022415d74e73 to d8d880c560f8 (1 revision) (flutter/engine#44708) 2023-08-15 skia-flutter-autoroll@skia.org Roll Dart SDK from 8731e9796eb3 to d240bef060ed (1 revision) (flutter/engine#44707) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from AvjxPvh-niiy to -16K9GvYE3a4 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5a7d6fdba7bc9..3263f62b5607f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6975ee1b6de7afc31d713b0b073ace129eb89b56 +a17130ac4d49783bb66221fcfc0aa1289da3319b diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 9d8675692a14b..508eb674e196c 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -AvjxPvh-niiyQpYoDshRJNeONXoN7kFYhUeQ26-eTX8C +-16K9GvYE3a4Bqs0G5fv6KEFKdFMm24GuNOMcS0-MQsC From 69b0c03416dae7e57d0986603bc2d1e931f1d76b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 03:38:25 -0400 Subject: [PATCH 0719/1547] Roll Flutter Engine from a17130ac4d49 to 9091107e594d (2 revisions) (#132553) https://github.com/flutter/engine/compare/a17130ac4d49...9091107e594d 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from e137aad081a3 to 4beb6fd05f4f (3 revisions) (flutter/engine#44713) 2023-08-15 jiahaog@users.noreply.github.com Namespace imports with flutter (flutter/engine#44709) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC chinmaygarde@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3263f62b5607f..dd405c96c37ef 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a17130ac4d49783bb66221fcfc0aa1289da3319b +9091107e594dabf90d088e1af77e230db200fcc5 From c7fb28034fb567fdcd80f9fc8a45edf5a3520e6f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 07:06:28 -0400 Subject: [PATCH 0720/1547] Roll Flutter Engine from 9091107e594d to 6bd7b717e110 (1 revision) (#132561) https://github.com/flutter/engine/compare/9091107e594d...6bd7b717e110 2023-08-15 skia-flutter-autoroll@skia.org Roll Dart SDK from d240bef060ed to d1c68769eba0 (1 revision) (flutter/engine#44715) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index dd405c96c37ef..a8837660fe907 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9091107e594dabf90d088e1af77e230db200fcc5 +6bd7b717e11059d66a3430873a4e312534be00d3 From 9526142cadc0e7700f7bc7a4d5ab50e686f3fac3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 08:33:36 -0400 Subject: [PATCH 0721/1547] Roll Flutter Engine from 6bd7b717e110 to 2c90670171a7 (2 revisions) (#132566) https://github.com/flutter/engine/compare/6bd7b717e110...2c90670171a7 2023-08-15 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from uIGMbDkXoIcpqWjgR... to 7iuIq3PsSkuCmuEMr... (flutter/engine#44721) 2023-08-15 skia-flutter-autoroll@skia.org Roll Dart SDK from d1c68769eba0 to 19c87486f0a9 (1 revision) (flutter/engine#44719) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from uIGMbDkXoIcp to 7iuIq3PsSkuC If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a8837660fe907..a5dd726ffe09d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6bd7b717e11059d66a3430873a4e312534be00d3 +2c90670171a7983cc779e0a0a8e7349585b5cde9 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index caae64c0cd817..833b5a5e9b655 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -uIGMbDkXoIcpqWjgR5qZBJ4xzPDq2aHVlM8NWImJbXoC +7iuIq3PsSkuCmuEMr29sQ3wjRe8GTExLe-cHjITyxcEC From 6579844528dc1b487f0bf61c8cbd86e8d4d78d19 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Tue, 15 Aug 2023 07:28:18 -0700 Subject: [PATCH 0722/1547] Update `flutter_tools` internals related to Gradle/XCode to set `--local-engine-host`. (#132346) Partial work towards https://github.com/flutter/flutter/issues/132245. I made a minor refactor to test-only code because it was too confusing to have 2 optional parameters that are technically required together, but otherwise all other changes *should* be pass throughs. That being said, I can't say I totally understand the Gradle stuff so I could use a hand double checking that. --- .../gradle/src/main/groovy/flutter.groovy | 14 +++++++ .../flutter_tools/lib/src/android/gradle.dart | 2 + packages/flutter_tools/lib/src/artifacts.dart | 39 +++++++++++++------ packages/flutter_tools/lib/src/ios/mac.dart | 1 + .../hermetic/assemble_test.dart | 2 +- .../android/android_gradle_builder_test.dart | 24 ++++++++---- .../general.shard/android/gradle_test.dart | 2 +- .../test/general.shard/build_info_test.dart | 10 ++--- .../general.shard/ios/xcodeproj_test.dart | 12 +++--- 9 files changed, 73 insertions(+), 33 deletions(-) diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index 95a750e6ef9e1..657ef144bf483 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -164,6 +164,7 @@ class FlutterPlugin implements Plugin { private File flutterRoot private File flutterExecutable private String localEngine + private String localEngineHost private String localEngineSrcPath private Properties localProperties private String engineVersion @@ -324,6 +325,13 @@ class FlutterPlugin implements Plugin { } localEngine = engineOut.name localEngineSrcPath = engineOut.parentFile.parent + + String engineHostOutPath = project.property('local-engine-host-out') + File engineHostOut = project.file(engineHostOutPath) + if (!engineHostOut.isDirectory()) { + throw new GradleException('local-engine-host-out must point to a local engine host build') + } + localEngineHostOut = engineHostOut.name } project.android.buildTypes.all this.&addFlutterDependencies } @@ -1027,6 +1035,7 @@ class FlutterPlugin implements Plugin { flutterExecutable this.flutterExecutable buildMode variantBuildMode localEngine this.localEngine + localEngineHost this.localEngineHost localEngineSrcPath this.localEngineSrcPath targetPath getFlutterTarget() verbose this.isVerbose() @@ -1235,6 +1244,8 @@ abstract class BaseFlutterTask extends DefaultTask { @Optional @Input String localEngine @Optional @Input + String localEngineHost + @Optional @Input String localEngineSrcPath @Optional @Input Boolean fastStart @@ -1313,6 +1324,9 @@ abstract class BaseFlutterTask extends DefaultTask { args "--local-engine", localEngine args "--local-engine-src-path", localEngineSrcPath } + if (localEngineHost != null) { + args "--local-engine-host", localEngineHost + } if (verbose) { args "--verbose" } else { diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index d90431dd49486..3a456dc48fcd2 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -401,6 +401,7 @@ class AndroidGradleBuilder implements AndroidBuilder { command.add('-Plocal-engine-repo=${localEngineRepo.path}'); command.add('-Plocal-engine-build-mode=${buildInfo.modeName}'); command.add('-Plocal-engine-out=${localEngineInfo.engineOutPath}'); + command.add('-Plocal-engine-host-out=${localEngineInfo.engineHostOutPath}'); command.add('-Ptarget-platform=${_getTargetPlatformByLocalEnginePath( localEngineInfo.engineOutPath)}'); } else if (androidBuildInfo.targetArchs.isNotEmpty) { @@ -726,6 +727,7 @@ class AndroidGradleBuilder implements AndroidBuilder { command.add('-Plocal-engine-repo=${localEngineRepo.path}'); command.add('-Plocal-engine-build-mode=${buildInfo.modeName}'); command.add('-Plocal-engine-out=${localEngineInfo.engineOutPath}'); + command.add('-Plocal-engine-host-out=${localEngineInfo.engineHostOutPath}'); // Copy the local engine repo in the output directory. try { diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index f226d139d2396..97e6e1da9f6b8 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:file/memory.dart'; +import 'package:meta/meta.dart'; import 'package:process/process.dart'; import 'base/common.dart'; @@ -287,10 +288,12 @@ class EngineBuildPaths { class LocalEngineInfo { const LocalEngineInfo({ required this.engineOutPath, + required this.engineHostOutPath, required this.localEngineName, }); final String engineOutPath; + final String engineHostOutPath; final String localEngineName; } @@ -302,12 +305,23 @@ abstract class Artifacts { /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance. /// /// Creates a [LocalEngineArtifacts] if `localEngine` is non-null - factory Artifacts.test({String? localEngine, FileSystem? fileSystem}) { - fileSystem ??= MemoryFileSystem.test(); - if (localEngine != null) { - return _TestLocalEngine(localEngine, fileSystem); - } - return _TestArtifacts(fileSystem); + @visibleForTesting + factory Artifacts.test({FileSystem? fileSystem}) { + return _TestArtifacts(fileSystem ?? MemoryFileSystem.test()); + } + + /// A test-specific implementation of artifacts that returns stable paths for + /// all artifacts, and uses a local engine. + /// + /// If a [fileSystem] is not provided, creates a new [MemoryFileSystem] instance. + @visibleForTesting + factory Artifacts.testLocalEngine({ + required String localEngine, + required String localEngineHost, + FileSystem? fileSystem, + }) { + return _TestLocalEngine( + localEngine, localEngineHost, fileSystem ?? MemoryFileSystem.test()); } static Artifacts getLocalEngine(EngineBuildPaths engineBuildPaths) { @@ -811,6 +825,7 @@ class CachedLocalEngineArtifacts implements Artifacts { localEngineInfo = LocalEngineInfo( engineOutPath: engineOutPath, + engineHostOutPath: _hostEngineOutPath, localEngineName: fileSystem.path.basename(engineOutPath) ), _cache = cache, @@ -1365,12 +1380,12 @@ class _TestArtifacts implements Artifacts { } class _TestLocalEngine extends _TestArtifacts { - _TestLocalEngine(String engineOutPath, super.fileSystem) : - localEngineInfo = - LocalEngineInfo( - engineOutPath: engineOutPath, - localEngineName: fileSystem.path.basename(engineOutPath) - ); + _TestLocalEngine( + String engineOutPath, String engineHostOutPath, super.fileSystem) + : localEngineInfo = LocalEngineInfo( + engineOutPath: engineOutPath, + engineHostOutPath: engineHostOutPath, + localEngineName: fileSystem.path.basename(engineOutPath)); @override bool get isLocalEngine => true; diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index 34c487e7ff652..f51d436b971e2 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -72,6 +72,7 @@ class IMobileDevice { /// Create an [IMobileDevice] for testing. factory IMobileDevice.test({ required ProcessManager processManager }) { return IMobileDevice( + // ignore: invalid_use_of_visible_for_testing_member artifacts: Artifacts.test(), cache: Cache.test(processManager: processManager), processManager: processManager, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart index 09f2c56444f46..4e302df9b8033 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart @@ -192,7 +192,7 @@ void main() { )); await commandRunner.run(['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']); }, overrides: { - Artifacts: () => Artifacts.test(localEngine: 'out/host_release'), + Artifacts: () => Artifacts.testLocalEngine(localEngine: 'out/host_release', localEngineHost: 'out/host_release'), Cache: () => Cache.test(processManager: FakeProcessManager.any()), FileSystem: () => MemoryFileSystem.test(), ProcessManager: () => FakeProcessManager.any(), diff --git a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart index b989d371f4615..217a6911b0369 100644 --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart @@ -1187,7 +1187,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_arm'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_arm', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1200,6 +1200,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_arm', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-arm', '-Ptarget=lib/main.dart', '-Pbase-application-name=io.flutter.app.FlutterApplication', @@ -1266,7 +1267,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_arm64'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_arm64', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1279,6 +1280,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_arm64', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-arm64', '-Ptarget=lib/main.dart', '-Pbase-application-name=io.flutter.app.FlutterApplication', @@ -1345,7 +1347,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_x86'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_x86', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1358,6 +1360,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_x86', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-x86', '-Ptarget=lib/main.dart', '-Pbase-application-name=io.flutter.app.FlutterApplication', @@ -1424,7 +1427,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_x64'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_x64', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1437,6 +1440,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_x64', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-x64', '-Ptarget=lib/main.dart', '-Pbase-application-name=io.flutter.app.FlutterApplication', @@ -1565,7 +1569,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_arm'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_arm', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1586,6 +1590,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_arm', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-arm', 'assembleAarRelease', ], @@ -1653,7 +1658,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_arm64'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_arm64', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1674,6 +1679,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_arm64', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-arm64', 'assembleAarRelease', ], @@ -1741,7 +1747,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_x86'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_x86', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1762,6 +1768,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_x86', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-x86', 'assembleAarRelease', ], @@ -1829,7 +1836,7 @@ unknown crash logger: logger, processManager: processManager, fileSystem: fileSystem, - artifacts: Artifacts.test(localEngine: 'out/android_x64'), + artifacts: Artifacts.testLocalEngine(localEngine: 'out/android_x64', localEngineHost: 'out/host_release'), usage: testUsage, gradleUtils: FakeGradleUtils(), platform: FakePlatform(), @@ -1850,6 +1857,7 @@ unknown crash '-Plocal-engine-repo=/.tmp_rand0/flutter_tool_local_engine_repo.rand0', '-Plocal-engine-build-mode=release', '-Plocal-engine-out=out/android_x64', + '-Plocal-engine-host-out=out/host_release', '-Ptarget-platform=android-x64', 'assembleAarRelease', ], diff --git a/packages/flutter_tools/test/general.shard/android/gradle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_test.dart index 5b32f927997f0..493d76cb3826e 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_test.dart @@ -211,7 +211,7 @@ void main() { setUp(() { fs = MemoryFileSystem.test(); - localEngineArtifacts = Artifacts.test(localEngine: 'out/android_arm'); + localEngineArtifacts = Artifacts.testLocalEngine(localEngine: 'out/android_arm', localEngineHost: 'out/host_release'); }); void testUsingAndroidContext(String description, dynamic Function() testMethod) { diff --git a/packages/flutter_tools/test/general.shard/build_info_test.dart b/packages/flutter_tools/test/general.shard/build_info_test.dart index af04ee243a2c1..eef8e9c10f42c 100644 --- a/packages/flutter_tools/test/general.shard/build_info_test.dart +++ b/packages/flutter_tools/test/general.shard/build_info_test.dart @@ -104,17 +104,17 @@ void main() { testWithoutContext('defaultIOSArchsForEnvironment', () { expect(defaultIOSArchsForEnvironment( EnvironmentType.physical, - Artifacts.test(localEngine: 'ios_debug_unopt'), + Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_unopt'), ).single, DarwinArch.arm64); expect(defaultIOSArchsForEnvironment( EnvironmentType.simulator, - Artifacts.test(localEngine: 'ios_debug_sim_unopt'), + Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_sim_unopt'), ).single, DarwinArch.x86_64); expect(defaultIOSArchsForEnvironment( EnvironmentType.simulator, - Artifacts.test(localEngine: 'ios_debug_sim_unopt_arm64'), + Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_sim_unopt_arm64'), ).single, DarwinArch.arm64); expect(defaultIOSArchsForEnvironment( @@ -128,11 +128,11 @@ void main() { testWithoutContext('defaultMacOSArchsForEnvironment', () { expect(defaultMacOSArchsForEnvironment( - Artifacts.test(localEngine: 'host_debug_unopt'), + Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'host_debug_unopt'), ).single, DarwinArch.x86_64); expect(defaultMacOSArchsForEnvironment( - Artifacts.test(localEngine: 'host_debug_unopt_arm64'), + Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'host_debug_unopt_arm64'), ).single, DarwinArch.arm64); expect(defaultMacOSArchsForEnvironment( diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart index 3dfe9157d5189..4dacb94625ae9 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart @@ -754,7 +754,7 @@ Information about project "Runner": setUp(() { fs = MemoryFileSystem.test(); - localIosArtifacts = Artifacts.test(localEngine: 'out/ios_profile_arm64'); + localIosArtifacts = Artifacts.testLocalEngine(localEngine: 'out/ios_profile_arm64', localEngineHost: 'out/host_release'); macOS = FakePlatform(operatingSystem: 'macos'); fs.file(xcodebuild).createSync(recursive: true); }); @@ -938,7 +938,7 @@ Build settings for action build and target plugin2: } testUsingOsxContext('exits when armv7 local engine is set', () async { - localIosArtifacts = Artifacts.test(localEngine: 'out/ios_profile_arm'); + localIosArtifacts = Artifacts.testLocalEngine(localEngine: 'out/ios_profile_arm', localEngineHost: 'out/host_release'); const BuildInfo buildInfo = BuildInfo.debug; final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); await expectLater(() => @@ -971,7 +971,7 @@ Build settings for action build and target plugin2: final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync(); expect(buildPhaseScriptContents.contains('export "ARCHS=arm64"'), isTrue); }, overrides: { - Artifacts: () => Artifacts.test(localEngine: 'out/host_profile_arm64'), + Artifacts: () => Artifacts.testLocalEngine(localEngine: 'out/host_profile_arm64', localEngineHost: 'out/host_release'), Platform: () => macOS, FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -998,7 +998,7 @@ Build settings for action build and target plugin2: final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync(); expect(buildPhaseScriptContents.contains('export "ARCHS=x86_64"'), isTrue); }, overrides: { - Artifacts: () => Artifacts.test(localEngine: 'out/host_profile'), + Artifacts: () => Artifacts.testLocalEngine(localEngine: 'out/host_profile', localEngineHost: 'out/host_release'), Platform: () => macOS, FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -1083,7 +1083,7 @@ Build settings for action build and target plugin2: final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync(); expect(buildPhaseScriptContents.contains('ARCHS=x86_64'), isTrue); }, overrides: { - Artifacts: () => Artifacts.test(localEngine: 'out/ios_debug_sim_unopt'), + Artifacts: () => Artifacts.testLocalEngine(localEngine: 'out/ios_debug_sim_unopt', localEngineHost: 'out/host_debug_unopt'), Platform: () => macOS, FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), @@ -1109,7 +1109,7 @@ Build settings for action build and target plugin2: final String buildPhaseScriptContents = buildPhaseScript.readAsStringSync(); expect(buildPhaseScriptContents.contains('ARCHS=arm64'), isTrue); }, overrides: { - Artifacts: () => Artifacts.test(localEngine: 'out/ios_debug_sim_arm64'), + Artifacts: () => Artifacts.testLocalEngine(localEngine: 'out/ios_debug_sim_arm64', localEngineHost: 'out/host_debug_unopt'), Platform: () => macOS, FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), From 30f228d894ac7f21d619c9d33b1598973741b1fb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 11:26:31 -0400 Subject: [PATCH 0723/1547] Roll Flutter Engine from 2c90670171a7 to 0760b5589c71 (1 revision) (#132570) https://github.com/flutter/engine/compare/2c90670171a7...0760b5589c71 2023-08-15 matej.knopp@gmail.com Reset editing delta state when replacing editing state (flutter/engine#44595) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a5dd726ffe09d..1462ebd1acbff 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2c90670171a7983cc779e0a0a8e7349585b5cde9 +0760b5589c71acf63dce1ba99b5b186207a92e70 From efdfd96c4aaf8b14174d81f14a835656da412443 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 11:43:11 -0400 Subject: [PATCH 0724/1547] Roll Packages from 08080abd9cbb to 84218b9d834c (1 revision) (#132572) https://github.com/flutter/packages/compare/08080abd9cbb...84218b9d834c 2023-08-14 stuartmorgan@google.com [file_selector] Fix default accept types on iOS (flutter/packages#4691) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 4f7a79cdafe89..57754f9bd92b1 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -08080abd9cbb291cc3b4aec4f03454c9c8a88814 +84218b9d834cd1d19d41a0b2079c9cdd1db67bd4 From cc0d63ea6638131299092a7089c53fff550ce825 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 15 Aug 2023 09:37:16 -0700 Subject: [PATCH 0725/1547] Further clarification of the TextSelectionControls migration (#132539) Further follow-up for https://github.com/flutter/flutter/issues/122421. --- .../lib/src/widgets/editable_text.dart | 17 +++++++--- .../lib/src/widgets/text_selection.dart | 33 +++++++++++-------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 9f857021fdf3e..b8effd5a2fa91 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1255,11 +1255,14 @@ class EditableText extends StatefulWidget { final Color? selectionColor; /// {@template flutter.widgets.editableText.selectionControls} - /// Optional delegate for building the text selection handles and toolbar. + /// Optional delegate for building the text selection handles. /// - /// The [EditableText] widget used on its own will not trigger the display - /// of the selection toolbar by itself. The toolbar is shown by calling - /// [EditableTextState.showToolbar] in response to an appropriate user event. + /// Historically, this field also controlled the toolbar. This is now handled + /// by [contextMenuBuilder] instead. However, for backwards compatibility, when + /// [selectionControls] is set to an object that does not mix in + /// [TextSelectionHandleControls], [contextMenuBuilder] is ignored and the + /// [TextSelectionControls.buildToolbar] method is used instead. + /// {@endtemplate} /// /// See also: /// @@ -1269,7 +1272,6 @@ class EditableText extends StatefulWidget { /// * [TextField], a Material Design themed wrapper of [EditableText], which /// shows the selection toolbar upon appropriate user events based on the /// user's platform set in [ThemeData.platform]. - /// {@endtemplate} final TextSelectionControls? selectionControls; /// {@template flutter.widgets.editableText.keyboardType} @@ -1778,6 +1780,11 @@ class EditableText extends StatefulWidget { /// `buttonItems` represents the buttons that would be built by default for /// this widget. /// + /// For backwards compatibility, when [selectionControls] is set to an object + /// that does not mix in [TextSelectionHandleControls], [contextMenuBuilder] + /// is ignored and the [TextSelectionControls.buildToolbar] method is used + /// instead. + /// /// {@tool dartpad} /// This example shows how to customize the menu, in this case by keeping the /// default buttons for the platform but modifying their appearance. diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 8d45921727578..177c32f7c6315 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -61,23 +61,28 @@ class ToolbarItemsParentData extends ContainerBoxParentData { /// An interface for building the selection UI, to be provided by the /// implementer of the toolbar widget. /// -/// Override text operations such as [handleCut] if needed. +/// Parts of this class, including [buildToolbar], have been deprecated in favor +/// of [EditableText.contextMenuBuilder], which is now the preferred way to +/// customize the context menus. /// /// ## Use with [EditableText.contextMenuBuilder] -/// [buildToolbar] has been deprecated in favor of -/// [EditableText.contextMenuBuilder], and that is the preferred way to -/// customize the context menus now. However, both ways will continue to work -/// during the deprecation period. /// -/// To use both [EditableText.contextMenuBuilder] and [buildHandle], a two-step -/// migration is necessary. First, migrate to [TextSelectionHandleControls], -/// using its [TextSelectionHandleControls.buildHandle] method and moving -/// toolbar code to [EditableText.contextMenuBuilder]. Later, the deprecation -/// period will expire, [buildToolbar] will be removed, and -/// [TextSelectionHandleControls] will be deprecated. Migrate back to -/// [TextSelectionControls.buildHandle], so that the final state is to use -/// [EditableText.contextMenuBuilder] for the toolbar and -/// [TextSelectionControls] for the handles. +/// For backwards compatibility during the deprecation period, when +/// [EditableText.selectionControls] is set to an object that does not mix in +/// [TextSelectionHandleControls], [EditableText.contextMenuBuilder] is ignored +/// in favor of the deprecated [buildToolbar]. +/// +/// To migrate code from [buildToolbar] to the preferred +/// [EditableText.contextMenuBuilder], while still using [buildHandle], mix in +/// [TextSelectionHandleControls] into the [TextSelectionControls] subclass when +/// moving any toolbar code to a callback passed to +/// [EditableText.contextMenuBuilder]. +/// +/// In due course, [buildToolbar] will be removed, and the mixin will no longer +/// be necessary as a way to flag to the framework that the code has been +/// migrated and does not expect [buildToolbar] to be called. +/// +/// For more information, see . /// /// See also: /// From 33b66f6436c5746e99a30060885a0cfb24fa79cc Mon Sep 17 00:00:00 2001 From: keyonghan <54558023+keyonghan@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:53:17 -0700 Subject: [PATCH 0726/1547] Skip backfiller for docs_publish (#132510) This is to avoid old docs published by backfilling. --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index c2a797eddefdf..85754964c7ced 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -363,6 +363,7 @@ targets: ] tags: > ["framework", "hostonly", "linux"] + backfill: "false" validation: docs validation_name: Docs firebase_project: master-docs-flutter-dev From 32aa3128eea9e37ba4fa56bcbe593b8c29b82468 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Tue, 15 Aug 2023 11:02:30 -0700 Subject: [PATCH 0727/1547] Analyze code snippets in flutter_driver docs (#132337) --- dev/bots/analyze_snippet_code.dart | 49 ++++-- .../custom_imports_broken.dart | 21 +++ dev/bots/test/analyze_snippet_code_test.dart | 5 +- .../flutter_driver/lib/src/driver/driver.dart | 9 +- .../lib/src/driver/gc_summarizer.dart | 2 +- .../lib/src/driver/profiling_summarizer.dart | 2 +- .../src/driver/raster_cache_summarizer.dart | 2 +- .../driver/scene_display_lag_summarizer.dart | 2 +- .../lib/src/extension/extension.dart | 154 +++++++++--------- 9 files changed, 144 insertions(+), 102 deletions(-) create mode 100644 dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index e6de1e4cf592d..4b635c90586eb 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -55,10 +55,12 @@ // // At the top of a file you can say `// Examples can assume:` and then list some // commented-out declarations that will be included in the analysis for snippets -// in that file. +// in that file. This section may also contain explicit import statements. // -// Snippets generally import all the main Flutter packages (including material -// and flutter_test), as well as most core Dart packages with the usual prefixes. +// For files without an `// Examples can assume:` section or if that section +// contains no explicit imports, the snippets will implicitly import all the +// main Flutter packages (including material and flutter_test), as well as most +// core Dart packages with the usual prefixes. import 'dart:async'; import 'dart:convert'; @@ -72,6 +74,7 @@ import 'package:watcher/watcher.dart'; final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String _packageFlutter = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); final String _packageFlutterTest = path.join(_flutterRoot, 'packages', 'flutter_test', 'lib'); +final String _packageFlutterDriver = path.join(_flutterRoot, 'packages', 'flutter_driver', 'lib'); final String _packageIntegrationTest = path.join(_flutterRoot, 'packages', 'integration_test', 'lib'); final String _defaultDartUiLocation = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui'); final String _flutter = path.join(_flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); @@ -153,7 +156,8 @@ Future main(List arguments) async { Directory(_packageFlutter), Directory(_packageFlutterTest), Directory(_packageIntegrationTest), - // TODO(goderbauer): Add all other packages. + Directory(_packageFlutterDriver), + // TODO(goderbauer): Add all other packages for which we publish docs. ]; } @@ -574,6 +578,7 @@ class _SnippetChecker { final List fileLines = file.readAsLinesSync(); final List<_Line> ignorePreambleLinesOnly = <_Line>[]; final List<_Line> preambleLines = <_Line>[]; + final List<_Line> customImports = <_Line>[]; bool inExamplesCanAssumePreamble = false; // Whether or not we're in the file-wide preamble section ("Examples can assume"). bool inToolSection = false; // Whether or not we're in a code snippet bool inDartSection = false; // Whether or not we're in a '```dart' segment. @@ -592,7 +597,11 @@ class _SnippetChecker { throw _SnippetCheckerException('Unexpected content in snippet code preamble.', file: relativeFilePath, line: lineNumber); } else { final _Line newLine = _Line(line: lineNumber, indent: 3, code: line.substring(3)); - preambleLines.add(newLine); + if (newLine.code.startsWith('import ')) { + customImports.add(newLine); + } else { + preambleLines.add(newLine); + } if (line.startsWith('// // ignore_for_file: ')) { ignorePreambleLinesOnly.add(newLine); } @@ -612,7 +621,7 @@ class _SnippetChecker { } if (trimmedLine.startsWith(_codeBlockEndRegex)) { inDartSection = false; - final _SnippetFile snippet = _processBlock(startLine, block, preambleLines, ignorePreambleLinesOnly, relativeFilePath, lastExample); + final _SnippetFile snippet = _processBlock(startLine, block, preambleLines, ignorePreambleLinesOnly, relativeFilePath, lastExample, customImports); final String path = _writeSnippetFile(snippet).path; assert(!snippetMap.containsKey(path)); snippetMap[path] = snippet; @@ -655,6 +664,7 @@ class _SnippetChecker { line.contains('```kotlin') || line.contains('```swift') || line.contains('```glsl') || + line.contains('```json') || line.contains('```csv')) { inOtherBlock = true; } else if (line.startsWith(_uncheckedCodeBlockStartRegex)) { @@ -694,7 +704,7 @@ class _SnippetChecker { /// a primitive heuristic to make snippet blocks into valid Dart code. /// /// `block` argument will get mutated, but is copied before this function returns. - _SnippetFile _processBlock(_Line startingLine, List block, List<_Line> assumptions, List<_Line> ignoreAssumptionsOnly, String filename, _SnippetFile? lastExample) { + _SnippetFile _processBlock(_Line startingLine, List block, List<_Line> assumptions, List<_Line> ignoreAssumptionsOnly, String filename, _SnippetFile? lastExample, List<_Line> customImports) { if (block.isEmpty) { throw _SnippetCheckerException('${startingLine.asLocation(filename, 0)}: Empty ```dart block in snippet code.'); } @@ -755,7 +765,7 @@ class _SnippetChecker { return _SnippetFile.fromStrings( startingLine, block.toList(), - importPreviousExample ? <_Line>[] : headersWithoutImports, + headersWithoutImports, <_Line>[ ...ignoreAssumptionsOnly, if (hasEllipsis) @@ -764,13 +774,24 @@ class _SnippetChecker { 'self-contained program', filename, ); - } else if (hasStatefulWidgetComment) { + } + + final List<_Line> headers = switch ((importPreviousExample, customImports.length)) { + (true, _) => <_Line>[], + (false, 0) => headersWithImports, + (false, _) => <_Line>[ + ...headersWithoutImports, + const _Line.generated(code: '// ignore_for_file: unused_import'), + ...customImports, + ] + }; + if (hasStatefulWidgetComment) { return _SnippetFile.fromStrings( startingLine, prefix: 'class _State extends State {', block.toList(), postfix: '}', - importPreviousExample ? <_Line>[] : headersWithImports, + headers, preamble, 'stateful widget', filename, @@ -782,7 +803,7 @@ class _SnippetChecker { return _SnippetFile.fromStrings( startingLine, block.toList(), - importPreviousExample ? <_Line>[] : headersWithImports, + headers, preamble, 'top-level declaration', filename, @@ -795,7 +816,7 @@ class _SnippetChecker { prefix: 'Future function() async {', block.toList(), postfix: '}', - importPreviousExample ? <_Line>[] : headersWithImports, + headers, preamble, 'statement', filename, @@ -807,7 +828,7 @@ class _SnippetChecker { prefix: 'class Class {', block.toList(), postfix: '}', - importPreviousExample ? <_Line>[] : headersWithImports, + headers, <_Line>[ ...preamble, const _Line.generated(code: '// ignore_for_file: avoid_classes_with_only_static_members'), @@ -849,7 +870,7 @@ class _SnippetChecker { prefix: 'dynamic expression = ', block.toList(), postfix: ';', - importPreviousExample ? <_Line>[] : headersWithImports, + headers, preamble, 'expression', filename, diff --git a/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart b/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart new file mode 100644 index 0000000000000..cdf466efe2631 --- /dev/null +++ b/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file is used by ../analyze_snippet_code_test.dart, which depends on the +// precise contents (including especially the comments) of this file. + +// Examples can assume: +// import 'package:flutter/rendering.dart'; + +/// no error: rendering library was imported. +/// ```dart +/// print(RenderObject); +/// ``` +String? bar; + +/// error: widgets library was not imported (not even implicitly). +/// ```dart +/// print(Widget); +/// ``` +String? foo; diff --git a/dev/bots/test/analyze_snippet_code_test.dart b/dev/bots/test/analyze_snippet_code_test.dart index 712052faf6eca..90b6366cb93ab 100644 --- a/dev/bots/test/analyze_snippet_code_test.dart +++ b/dev/bots/test/analyze_snippet_code_test.dart @@ -11,6 +11,7 @@ import 'dart:io'; import 'common.dart'; const List expectedMainErrors = [ + 'dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart:19:11: (statement) (undefined_identifier)', 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:30:5: (expression) (unnecessary_new)', 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:103:5: (statement) (always_specify_types)', 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:111:5: (top-level declaration) (prefer_const_declarations)', @@ -68,7 +69,7 @@ void main() { final List stderrNoDescriptions = stderrLines.map(removeLintDescriptions).toList(); expect(stderrNoDescriptions, [ ...expectedMainErrors, - 'Found 15 snippet code errors.', + 'Found 16 snippet code errors.', 'See the documentation at the top of dev/bots/analyze_snippet_code.dart for details.', '', // because we end with a newline, split gives us an extra blank line ]); @@ -92,7 +93,7 @@ void main() { expect(stderrNoDescriptions, [ ...expectedUiErrors, ...expectedMainErrors, - 'Found 19 snippet code errors.', + 'Found 20 snippet code errors.', 'See the documentation at the top of dev/bots/analyze_snippet_code.dart for details.', '', // because we end with a newline, split gives us an extra blank line ]); diff --git a/packages/flutter_driver/lib/src/driver/driver.dart b/packages/flutter_driver/lib/src/driver/driver.dart index b29becca68ef4..bedb7f4ffaec0 100644 --- a/packages/flutter_driver/lib/src/driver/driver.dart +++ b/packages/flutter_driver/lib/src/driver/driver.dart @@ -83,6 +83,11 @@ const CommonFinders find = CommonFinders._(); /// See also [FlutterDriver.waitFor]. typedef EvaluatorFunction = dynamic Function(); +// Examples can assume: +// import 'package:flutter_driver/flutter_driver.dart'; +// import 'package:test/test.dart'; +// late FlutterDriver driver; + /// Drives a Flutter Application running in another process. abstract class FlutterDriver { /// Default constructor. @@ -478,7 +483,7 @@ abstract class FlutterDriver { /// /// ```dart /// test('enters text in a text field', () async { - /// var textField = find.byValueKey('enter-text-field'); + /// final SerializableFinder textField = find.byValueKey('enter-text-field'); /// await driver.tap(textField); // acquire focus /// await driver.enterText('Hello!'); // enter text /// await driver.waitFor(find.text('Hello!')); // verify text appears on UI @@ -520,7 +525,7 @@ abstract class FlutterDriver { /// /// ```dart /// test('submit text in a text field', () async { - /// var textField = find.byValueKey('enter-text-field'); + /// final SerializableFinder textField = find.byValueKey('enter-text-field'); /// await driver.tap(textField); // acquire focus /// await driver.enterText('Hello!'); // enter text /// await driver.waitFor(find.text('Hello!')); // verify text appears on UI diff --git a/packages/flutter_driver/lib/src/driver/gc_summarizer.dart b/packages/flutter_driver/lib/src/driver/gc_summarizer.dart index 2779e782fc79b..36abab586c991 100644 --- a/packages/flutter_driver/lib/src/driver/gc_summarizer.dart +++ b/packages/flutter_driver/lib/src/driver/gc_summarizer.dart @@ -17,7 +17,7 @@ const Set kGCRootEvents = { /// Summarizes [TimelineEvents]s corresponding to [kGCRootEvents] category. /// /// A sample event (some fields have been omitted for brevity): -/// ``` +/// ```json /// { /// "name": "StartConcurrentMarking", /// "cat": "GC", diff --git a/packages/flutter_driver/lib/src/driver/profiling_summarizer.dart b/packages/flutter_driver/lib/src/driver/profiling_summarizer.dart index b3e708a6b886f..e70e86679756c 100644 --- a/packages/flutter_driver/lib/src/driver/profiling_summarizer.dart +++ b/packages/flutter_driver/lib/src/driver/profiling_summarizer.dart @@ -36,7 +36,7 @@ enum ProfileType { /// Summarizes [TimelineEvents]s corresponding to [kProfilingEvents] category. /// /// A sample event (some fields have been omitted for brevity): -/// ``` +/// ```json /// { /// "category": "embedder", /// "name": "CpuUsage", diff --git a/packages/flutter_driver/lib/src/driver/raster_cache_summarizer.dart b/packages/flutter_driver/lib/src/driver/raster_cache_summarizer.dart index 2b750116a8e42..3ae673d270a3d 100644 --- a/packages/flutter_driver/lib/src/driver/raster_cache_summarizer.dart +++ b/packages/flutter_driver/lib/src/driver/raster_cache_summarizer.dart @@ -16,7 +16,7 @@ const String _kPictureMemory = 'PictureMBytes'; /// Summarizes [TimelineEvents]s corresponding to [kRasterCacheEvent] events. /// /// A sample event (some fields have been omitted for brevity): -/// ``` +/// ```json /// { /// "name": "RasterCache", /// "ts": 75598996256, diff --git a/packages/flutter_driver/lib/src/driver/scene_display_lag_summarizer.dart b/packages/flutter_driver/lib/src/driver/scene_display_lag_summarizer.dart index d6eaec031b26f..6dd2023e84570 100644 --- a/packages/flutter_driver/lib/src/driver/scene_display_lag_summarizer.dart +++ b/packages/flutter_driver/lib/src/driver/scene_display_lag_summarizer.dart @@ -13,7 +13,7 @@ const String _kVsyncTransitionsMissed = 'vsync_transitions_missed'; /// Summarizes [TimelineEvents]s corresponding to [kSceneDisplayLagEvent] events. /// /// A sample event (some fields have been omitted for brevity): -/// ``` +/// ```json /// { /// "name": "SceneDisplayLag", /// "ts": 408920509340, diff --git a/packages/flutter_driver/lib/src/extension/extension.dart b/packages/flutter_driver/lib/src/extension/extension.dart index 2bb6705dd25b4..6e29825d32523 100644 --- a/packages/flutter_driver/lib/src/extension/extension.dart +++ b/packages/flutter_driver/lib/src/extension/extension.dart @@ -58,6 +58,19 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, } } +// Examples can assume: +// import 'package:flutter_driver/flutter_driver.dart'; +// import 'package:flutter/widgets.dart'; +// import 'package:flutter_driver/driver_extension.dart'; +// import 'package:flutter_test/flutter_test.dart' hide find; +// import 'package:flutter_test/flutter_test.dart' as flutter_test; +// typedef MyHomeWidget = Placeholder; +// abstract class SomeWidget extends StatelessWidget { const SomeWidget({super.key, required this.title}); final String title; } +// late FlutterDriver driver; +// abstract class StubNestedCommand { int get times; SerializableFinder get finder; } +// class StubCommandResult extends Result { const StubCommandResult(this.arg); final String arg; @override Map toJson() => {}; } +// abstract class StubProberCommand { int get times; SerializableFinder get finder; } + /// Enables Flutter Driver VM service extension. /// /// This extension is required for tests that use `package:flutter_driver` to @@ -87,26 +100,40 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, /// The `finders` and `commands` parameters are optional and used to add custom /// finders or commands, as in the following example. /// -/// ```dart main +/// ```dart /// void main() { /// enableFlutterDriverExtension( /// finders: [ SomeFinderExtension() ], /// commands: [ SomeCommandExtension() ], /// ); /// -/// app.main(); +/// runApp(const MyHomeWidget()); /// } -/// ``` /// -/// ```dart -/// driver.sendCommand(SomeCommand(ByValueKey('Button'), 7)); -/// ``` +/// class SomeFinderExtension extends FinderExtension { +/// @override +/// String get finderType => 'SomeFinder'; /// -/// `SomeFinder` and `SomeFinderExtension` must be placed in different files -/// to avoid `dart:ui` import issue. Imports relative to `dart:ui` can't be -/// accessed from host runner, where flutter runtime is not accessible. +/// @override +/// SerializableFinder deserialize(Map params, DeserializeFinderFactory finderFactory) { +/// return SomeFinder(params['title']!); +/// } /// -/// ```dart +/// @override +/// Finder createFinder(SerializableFinder finder, CreateFinderFactory finderFactory) { +/// final SomeFinder someFinder = finder as SomeFinder; +/// +/// return flutter_test.find.byElementPredicate((Element element) { +/// final Widget widget = element.widget; +/// if (widget is SomeWidget) { +/// return widget.title == someFinder.title; +/// } +/// return false; +/// }); +/// } +/// } +/// +/// // Use this class in a test anywhere where a SerializableFinder is expected. /// class SomeFinder extends SerializableFinder { /// const SomeFinder(this.title); /// @@ -120,43 +147,51 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, /// 'title': title, /// }); /// } -/// ``` /// -/// ```dart -/// class SomeFinderExtension extends FinderExtension { +/// class SomeCommandExtension extends CommandExtension { +/// @override +/// String get commandKind => 'SomeCommand'; /// -/// String get finderType => 'SomeFinder'; +/// @override +/// Future call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async { +/// final SomeCommand someCommand = command as SomeCommand; /// -/// SerializableFinder deserialize(Map params, DeserializeFinderFactory finderFactory) { -/// return SomeFinder(json['title']); -/// } +/// // Deserialize [Finder]: +/// final Finder finder = finderFactory.createFinder(someCommand.finder); /// -/// Finder createFinder(SerializableFinder finder, CreateFinderFactory finderFactory) { -/// Some someFinder = finder as SomeFinder; +/// // Wait for [Element]: +/// handlerFactory.waitForElement(finder); /// -/// return find.byElementPredicate((Element element) { -/// final Widget widget = element.widget; -/// if (element.widget is SomeWidget) { -/// return element.widget.title == someFinder.title; -/// } -/// return false; -/// }); -/// } -/// } -/// ``` +/// // Alternatively, wait for [Element] absence: +/// handlerFactory.waitForAbsentElement(finder); /// -/// `SomeCommand`, `SomeResult` and `SomeCommandExtension` must be placed in -/// different files to avoid `dart:ui` import issue. Imports relative to `dart:ui` -/// can't be accessed from host runner, where flutter runtime is not accessible. +/// // Submit known [Command]s: +/// for (int i = 0; i < someCommand.times; i++) { +/// await handlerFactory.handleCommand(Tap(someCommand.finder), prober, finderFactory); +/// } /// -/// ```dart +/// // Alternatively, use [WidgetController]: +/// for (int i = 0; i < someCommand.times; i++) { +/// await prober.tap(finder); +/// } +/// +/// return const SomeCommandResult('foo bar'); +/// } +/// +/// @override +/// Command deserialize(Map params, DeserializeFinderFactory finderFactory, DeserializeCommandFactory commandFactory) { +/// return SomeCommand.deserialize(params, finderFactory); +/// } +/// } +/// +/// // Pass an instance of this class to `FlutterDriver.sendCommand` to invoke +/// // the custom command during a test. /// class SomeCommand extends CommandWithTarget { -/// SomeCommand(SerializableFinder finder, this.times, {Duration? timeout}) -/// : super(finder, timeout: timeout); +/// SomeCommand(super.finder, this.times, {super.timeout}); /// -/// SomeCommand.deserialize(Map json, DeserializeFinderFactory finderFactory) +/// SomeCommand.deserialize(super.json, super.finderFactory) /// : times = int.parse(json['times']!), -/// super.deserialize(json, finderFactory); +/// super.deserialize(); /// /// @override /// Map serialize() { @@ -168,9 +203,7 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, /// /// final int times; /// } -/// ``` /// -/// ```dart /// class SomeCommandResult extends Result { /// const SomeCommandResult(this.resultParam); /// @@ -184,45 +217,6 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, /// } /// } /// ``` -/// -/// ```dart -/// class SomeCommandExtension extends CommandExtension { -/// @override -/// String get commandKind => 'SomeCommand'; -/// -/// @override -/// Future call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async { -/// final SomeCommand someCommand = command as SomeCommand; -/// -/// // Deserialize [Finder]: -/// final Finder finder = finderFactory.createFinder(stubCommand.finder); -/// -/// // Wait for [Element]: -/// handlerFactory.waitForElement(finder); -/// -/// // Alternatively, wait for [Element] absence: -/// handlerFactory.waitForAbsentElement(finder); -/// -/// // Submit known [Command]s: -/// for (int index = 0; i < someCommand.times; index++) { -/// await handlerFactory.handleCommand(Tap(someCommand.finder), prober, finderFactory); -/// } -/// -/// // Alternatively, use [WidgetController]: -/// for (int index = 0; i < stubCommand.times; index++) { -/// await prober.tap(finder); -/// } -/// -/// return const SomeCommandResult('foo bar'); -/// } -/// -/// @override -/// Command deserialize(Map params, DeserializeFinderFactory finderFactory, DeserializeCommandFactory commandFactory) { -/// return SomeCommand.deserialize(params, finderFactory); -/// } -/// } -/// ``` -/// void enableFlutterDriverExtension({ DataHandler? handler, bool silenceErrors = false, bool enableTextEntryEmulation = true, List? finders, List? commands}) { _DriverBinding(handler, silenceErrors, enableTextEntryEmulation, finders ?? [], commands ?? []); assert(WidgetsBinding.instance is _DriverBinding); @@ -287,7 +281,7 @@ abstract class CommandExtension { /// @override /// Future call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async { /// final StubNestedCommand stubCommand = command as StubNestedCommand; - /// for (int index = 0; i < stubCommand.times; index++) { + /// for (int i = 0; i < stubCommand.times; i++) { /// await handlerFactory.handleCommand(Tap(stubCommand.finder), prober, finderFactory); /// } /// return const StubCommandResult('stub response'); @@ -300,7 +294,7 @@ abstract class CommandExtension { /// @override /// Future call(Command command, WidgetController prober, CreateFinderFactory finderFactory, CommandHandlerFactory handlerFactory) async { /// final StubProberCommand stubCommand = command as StubProberCommand; - /// for (int index = 0; i < stubCommand.times; index++) { + /// for (int i = 0; i < stubCommand.times; i++) { /// await prober.tap(finderFactory.createFinder(stubCommand.finder)); /// } /// return const StubCommandResult('stub response'); From 03b9911a07bab13decdd6d3731e5b575599b3790 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam <58529443+srujzs@users.noreply.github.com> Date: Tue, 15 Aug 2023 11:50:31 -0700 Subject: [PATCH 0728/1547] Make completeError be a proper JS function (#132492) Function.toJS will start requiring that the function accept and return JS types only. Allows https://dart-review.googlesource.com/c/sdk/+/316867 to land. --- packages/flutter/lib/src/painting/_network_image_web.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index af45a0eb33e5a..667f08f1e1b0d 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -165,7 +165,8 @@ class NetworkImage } }.toJS); - request.addEventListener('error', completer.completeError.toJS); + request.addEventListener('error', + ((JSObject e) => completer.completeError(e)).toJS); request.send(); From 0c10e1ca54ae74043909059e2ff56bf5dd0c3d23 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 15:01:59 -0400 Subject: [PATCH 0729/1547] Roll Flutter Engine from 0760b5589c71 to 22f03ffdc290 (1 revision) (#132580) https://github.com/flutter/engine/compare/0760b5589c71...22f03ffdc290 2023-08-15 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -16K9GvYE3a4Bqs0G... to orVLXMF7ak2qfFkGs... (flutter/engine#44726) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from -16K9GvYE3a4 to orVLXMF7ak2q If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1462ebd1acbff..ac11dcac51b35 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0760b5589c71acf63dce1ba99b5b186207a92e70 +22f03ffdc290081f6a0a1ed11ba19fd24ad83109 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 508eb674e196c..929cf1bdadf39 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ --16K9GvYE3a4Bqs0G5fv6KEFKdFMm24GuNOMcS0-MQsC +orVLXMF7ak2qfFkGs7OLUQNik6GqDB0aUMScuWBMeLwC From 6b70dc18f5403b1b783afcc44fe881ca3ab24766 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Tue, 15 Aug 2023 13:46:37 -0700 Subject: [PATCH 0730/1547] [integration_test] Update outdated onScreenshot signature in README code snippet (#132409) Fixes https://github.com/flutter/flutter/issues/126690. Encountered while testing https://github.com/flutter/flutter/pull/132406. Updates the signature to be in line with the [current typedef](https://github.com/flutter/flutter/blob/b3096225e0ebc005ed678fa7a9f03164caba1d73/packages/integration_test/lib/common.dart#L26). --- packages/integration_test/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integration_test/README.md b/packages/integration_test/README.md index 7ba3a031c3fed..305fad32417f4 100644 --- a/packages/integration_test/README.md +++ b/packages/integration_test/README.md @@ -140,7 +140,7 @@ import 'package:integration_test/integration_test_driver_extended.dart'; Future main() async { await integrationDriver( - onScreenshot: (String screenshotName, List screenshotBytes) async { + onScreenshot: (String screenshotName, List screenshotBytes, [Map? args]) async { final File image = File('$screenshotName.png'); image.writeAsBytesSync(screenshotBytes); // Return false if the screenshot is invalid. From f0e7c518164167638d55ec848365f1aa8a7cb6b2 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 15 Aug 2023 13:50:17 -0700 Subject: [PATCH 0731/1547] Upgrade flutter packages. (#132585) --- dev/automated_tests/pubspec.yaml | 6 +++--- dev/benchmarks/complex_layout/pubspec.yaml | 6 +++--- dev/benchmarks/macrobenchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/microbenchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 6 +++--- dev/benchmarks/platform_views_layout/pubspec.yaml | 6 +++--- .../platform_views_layout_hybrid_composition/pubspec.yaml | 6 +++--- dev/benchmarks/test_apps/stocks/pubspec.yaml | 6 +++--- dev/bots/pubspec.yaml | 6 +++--- dev/conductor/core/pubspec.yaml | 8 ++++---- dev/customer_testing/pubspec.yaml | 6 +++--- dev/devicelab/pubspec.yaml | 6 +++--- .../android_semantics_testing/pubspec.yaml | 6 +++--- dev/integration_tests/android_views/pubspec.yaml | 6 +++--- .../deferred_components_test/pubspec.yaml | 6 +++--- dev/integration_tests/external_ui/pubspec.yaml | 6 +++--- dev/integration_tests/flavors/pubspec.yaml | 6 +++--- dev/integration_tests/flutter_gallery/pubspec.yaml | 6 +++--- dev/integration_tests/hybrid_android_views/pubspec.yaml | 6 +++--- .../ios_platform_view_tests/pubspec.yaml | 6 +++--- dev/integration_tests/platform_interaction/pubspec.yaml | 6 +++--- dev/integration_tests/ui/pubspec.yaml | 6 +++--- dev/integration_tests/web_e2e_tests/pubspec.yaml | 6 +++--- dev/integration_tests/windows_startup_test/pubspec.yaml | 6 +++--- dev/tools/gen_defaults/pubspec.yaml | 6 +++--- dev/tools/gen_keycodes/pubspec.yaml | 6 +++--- dev/tools/pubspec.yaml | 6 +++--- examples/api/pubspec.yaml | 6 +++--- examples/hello_world/pubspec.yaml | 6 +++--- examples/platform_channel/pubspec.yaml | 6 +++--- examples/platform_channel_swift/pubspec.yaml | 6 +++--- examples/texture/pubspec.yaml | 6 +++--- packages/flutter/pubspec.yaml | 8 ++++---- packages/flutter_driver/pubspec.yaml | 6 +++--- packages/flutter_tools/pubspec.yaml | 6 +++--- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 6 +++--- packages/integration_test/example/pubspec.yaml | 6 +++--- 37 files changed, 113 insertions(+), 113 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 69b4b79ea8b7b..340c2ab3c3a02 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: platform: 3.1.0 test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 4a29 +# PUBSPEC CHECKSUM: 402b diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 0f7dee37a1c04..e3c9e2c19b4a5 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -44,8 +44,8 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 1b02 +# PUBSPEC CHECKSUM: 9104 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 9a9ad7316db07..c0d17d2e970e9 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -47,8 +47,8 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -210,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 1b02 +# PUBSPEC CHECKSUM: 9104 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 12e1fcf70fcb2..031e6d636d415 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -15,8 +15,8 @@ dependencies: test: 1.24.6 flutter_gallery_assets: 1.0.2 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -137,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 3579 +# PUBSPEC CHECKSUM: c37b diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index b8c158bb8b604..03139bc65b7ca 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -16,8 +16,8 @@ dependencies: path: ../microbenchmarks cupertino_icons: 1.0.5 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e664 +# PUBSPEC CHECKSUM: 3566 diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index fada1d5bffcdf..046b61d52ac9c 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -42,8 +42,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 1b02 +# PUBSPEC CHECKSUM: 9104 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 3ede5ac0e5a01..f9b4c2e42ce01 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -42,8 +42,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 1b02 +# PUBSPEC CHECKSUM: 9104 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index a5ca26cd66751..4e9d5a2512a84 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -34,8 +34,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 5b24 +# PUBSPEC CHECKSUM: f526 diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index a6d9d9a00d994..4cc62550c3b50 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -19,8 +19,8 @@ dependencies: test: 1.24.6 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" archive: 3.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 0d78 +# PUBSPEC CHECKSUM: 117a diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 5d8fa01f7575c..483c5eb4a0ef3 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: meta: 1.9.1 path: 1.8.3 process: 4.2.4 - protobuf: 3.0.0 + protobuf: 3.1.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -33,8 +33,8 @@ dev_dependencies: test: 1.24.6 test_api: 0.6.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c505 +# PUBSPEC CHECKSUM: 7108 diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 17a2f6a3f1dd0..62fdfeba11634 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -20,8 +20,8 @@ dependencies: dev_dependencies: test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,4 +55,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6852 +# PUBSPEC CHECKSUM: 3054 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 5dfb48f93db9e..6fb98320dce28 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -51,8 +51,8 @@ dependencies: dev_dependencies: test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f7e5 +# PUBSPEC CHECKSUM: 9be7 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 665fa107273ad..a33cce9dd52cb 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: pub_semver: 2.1.4 test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2422 +# PUBSPEC CHECKSUM: a524 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 83565f0a4651f..91f816f798639 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -56,8 +56,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -92,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9c54 +# PUBSPEC CHECKSUM: be56 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index ad385517eec8d..3fb22a40146c5 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -37,8 +37,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -80,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index 84cdc27130dc1..ea600c3115324 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6eaa +# PUBSPEC CHECKSUM: fbac diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 330456ad0dc35..a2f6671b021c8 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index de5f30817bfd5..6a829699e17ea 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -62,8 +62,8 @@ dev_dependencies: integration_test: sdk: flutter - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 554d +# PUBSPEC CHECKSUM: e44f diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 1a4e24836f093..2410ef8a309ce 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -54,8 +54,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9c54 +# PUBSPEC CHECKSUM: be56 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 47a9bea4ac4d1..e83292fa8a448 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -37,8 +37,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 91ecf03b66b4f..f8cf9d1c4890f 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6eaa +# PUBSPEC CHECKSUM: fbac diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index a76ac73629c31..aaab446f158e8 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -13,8 +13,8 @@ dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 68e3c3f3d6274..6c7bc1f132c19 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -51,8 +51,8 @@ dev_dependencies: http: 0.13.6 test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: e84c +# PUBSPEC CHECKSUM: 044e diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 3e726bd34869d..64094a0fa4848 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -11,8 +11,8 @@ dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,4 +62,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6eaa +# PUBSPEC CHECKSUM: fbac diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index ad687f84177cc..6c93e29f00460 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -12,8 +12,8 @@ dev_dependencies: path: 1.8.3 test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -55,4 +55,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6852 +# PUBSPEC CHECKSUM: 3054 diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 0abcd5474df37..784907286b6ee 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -23,8 +23,8 @@ dev_dependencies: test: 1.24.6 test_api: 0.6.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,4 +57,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7a49 +# PUBSPEC CHECKSUM: ae4b diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 1dce1e953d8af..82ad7215a6c85 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -29,8 +29,8 @@ dev_dependencies: test: 1.24.6 test_api: 0.6.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,4 +61,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2d63 +# PUBSPEC CHECKSUM: 3265 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 882900961821a..ccfd967cf3f2d 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -33,8 +33,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -85,4 +85,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9516 +# PUBSPEC CHECKSUM: 6418 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index fddff49557526..dc4cef6891dfd 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -68,4 +68,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 6735bf56b6b8c..e1a69b943bede 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index f4554126bd036..c270c209a2c28 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -21,8 +21,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ba67 +# PUBSPEC CHECKSUM: bc69 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index fad02fa1db029..a42535013bebc 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -19,8 +19,8 @@ dev_dependencies: sdk: flutter test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,4 +64,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2422 +# PUBSPEC CHECKSUM: a524 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 7975cf6bf2777..35684cf52978b 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,11 +22,11 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 9.0.4 + leak_tracker: 9.0.5 leak_tracker_flutter_testing: 1.0.1 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a63c +# PUBSPEC CHECKSUM: 623f diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 77e05775ddadc..754474f9644b0 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -41,8 +41,8 @@ dev_dependencies: fake_async: 1.3.1 test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a26e +# PUBSPEC CHECKSUM: 1970 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 4307ba5334ed9..70afa9c91a147 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -60,8 +60,8 @@ dependencies: standard_message_codec: 0.0.1+3 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_value: 8.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -107,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: f97d +# PUBSPEC CHECKSUM: d87f diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 7ee7ff7241109..9412af17cb4a0 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -18,8 +18,8 @@ dependencies: dev_dependencies: test: 1.24.6 - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +63,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 5b59 +# PUBSPEC CHECKSUM: 975b diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index b84a3410fb4d7..a6c80890b20a6 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -34,8 +34,8 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - _fe_analyzer_shared: 63.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - analyzer: 6.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6ed5 +# PUBSPEC CHECKSUM: 09d7 From 301577a34f3f9614e5e866fb2d41372158dc0e89 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 15 Aug 2023 14:58:21 -0700 Subject: [PATCH 0732/1547] Fixing a memory leak in About box/dialog overlays (#130842) ## Description Fix three memory leaks detected by `about_test.dart`, but were really in the `Route` and `OverlayEntry` classes. ## Related Issues - Fixes https://github.com/flutter/flutter/issues/130354 ## Tests - Updates about_test.dart to not ignore the leaks anymore. --- .../flutter/lib/src/widgets/navigator.dart | 8 +++--- packages/flutter/lib/src/widgets/overlay.dart | 27 +++++++++++-------- .../gesture_config_regression_test.dart | 6 ++++- .../flutter/test/material/about_test.dart | 20 ++------------ 4 files changed, 27 insertions(+), 34 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 43156aa44e26e..82c4090037c18 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -2861,11 +2861,11 @@ class _RouteEntry extends RouteTransitionRecord { final _RestorationInformation? restorationInformation; final bool pageBased; - static Route notAnnounced = _NotAnnounced(); + static final Route notAnnounced = _NotAnnounced(); _RouteLifecycle currentState; Route? lastAnnouncedPreviousRoute = notAnnounced; // last argument to Route.didChangePrevious - Route lastAnnouncedPoppedNextRoute = notAnnounced; // last argument to Route.didPopNext + WeakReference> lastAnnouncedPoppedNextRoute = WeakReference>(notAnnounced); // last argument to Route.didPopNext Route? lastAnnouncedNextRoute = notAnnounced; // last argument to Route.didChangeNext /// Restoration ID to be used for the encapsulating route when restoration is @@ -2954,7 +2954,7 @@ class _RouteEntry extends RouteTransitionRecord { void handleDidPopNext(Route poppedRoute) { route.didPopNext(poppedRoute); - lastAnnouncedPoppedNextRoute = poppedRoute; + lastAnnouncedPoppedNextRoute = WeakReference>(poppedRoute); } /// Process the to-be-popped route. @@ -3153,7 +3153,7 @@ class _RouteEntry extends RouteTransitionRecord { // already announced this change by calling didPopNext. return !( nextRoute == null && - lastAnnouncedPoppedNextRoute == lastAnnouncedNextRoute + lastAnnouncedPoppedNextRoute.target == lastAnnouncedNextRoute ); } diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index f62b5fddc169f..e88aafad20b6e 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -135,20 +135,20 @@ class OverlayEntry implements Listenable { /// Whether the [OverlayEntry] is currently mounted in the widget tree. /// /// The [OverlayEntry] notifies its listeners when this value changes. - bool get mounted => _overlayEntryStateNotifier.value != null; + bool get mounted => _overlayEntryStateNotifier?.value != null; /// The currently mounted `_OverlayEntryWidgetState` built using this [OverlayEntry]. - final ValueNotifier<_OverlayEntryWidgetState?> _overlayEntryStateNotifier = ValueNotifier<_OverlayEntryWidgetState?>(null); + ValueNotifier<_OverlayEntryWidgetState?>? _overlayEntryStateNotifier = ValueNotifier<_OverlayEntryWidgetState?>(null); @override void addListener(VoidCallback listener) { assert(!_disposedByOwner); - _overlayEntryStateNotifier.addListener(listener); + _overlayEntryStateNotifier?.addListener(listener); } @override void removeListener(VoidCallback listener) { - _overlayEntryStateNotifier.removeListener(listener); + _overlayEntryStateNotifier?.removeListener(listener); } OverlayState? _overlay; @@ -194,7 +194,8 @@ class OverlayEntry implements Listenable { void _didUnmount() { assert(!mounted); if (_disposedByOwner) { - _overlayEntryStateNotifier.dispose(); + _overlayEntryStateNotifier?.dispose(); + _overlayEntryStateNotifier = null; } } @@ -217,7 +218,11 @@ class OverlayEntry implements Listenable { assert(_overlay == null, 'An OverlayEntry must first be removed from the Overlay before dispose is called.'); _disposedByOwner = true; if (!mounted) { - _overlayEntryStateNotifier.dispose(); + // If we're still mounted when disposed, then this will be disposed in + // _didUnmount, to allow notifications to occur until the entry is + // unmounted. + _overlayEntryStateNotifier?.dispose(); + _overlayEntryStateNotifier = null; } } @@ -315,7 +320,7 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> { @override void initState() { super.initState(); - widget.entry._overlayEntryStateNotifier.value = this; + widget.entry._overlayEntryStateNotifier!.value = this; _theater = context.findAncestorRenderObjectOfType<_RenderTheater>()!; assert(_sortedTheaterSiblings == null); } @@ -335,7 +340,7 @@ class _OverlayEntryWidgetState extends State<_OverlayEntryWidget> { @override void dispose() { - widget.entry._overlayEntryStateNotifier.value = null; + widget.entry._overlayEntryStateNotifier?.value = null; widget.entry._didUnmount(); _sortedTheaterSiblings = null; super.dispose(); @@ -917,9 +922,9 @@ class _TheaterParentData extends StackParentData { // _overlayStateMounted is set to null in _OverlayEntryWidgetState's dispose // method. This property is only accessed during layout, paint and hit-test so // the `value!` should be safe. - Iterator? get paintOrderIterator => overlayEntry?._overlayEntryStateNotifier.value!._paintOrderIterable.iterator; - Iterator? get hitTestOrderIterator => overlayEntry?._overlayEntryStateNotifier.value!._hitTestOrderIterable.iterator; - void visitChildrenOfOverlayEntry(RenderObjectVisitor visitor) => overlayEntry?._overlayEntryStateNotifier.value!._paintOrderIterable.forEach(visitor); + Iterator? get paintOrderIterator => overlayEntry?._overlayEntryStateNotifier?.value!._paintOrderIterable.iterator; + Iterator? get hitTestOrderIterator => overlayEntry?._overlayEntryStateNotifier?.value!._hitTestOrderIterable.iterator; + void visitChildrenOfOverlayEntry(RenderObjectVisitor visitor) => overlayEntry?._overlayEntryStateNotifier?.value!._paintOrderIterable.forEach(visitor); } class _RenderTheater extends RenderBox with ContainerRenderObjectMixin, _RenderTheaterMixin { diff --git a/packages/flutter/test/gestures/gesture_config_regression_test.dart b/packages/flutter/test/gestures/gesture_config_regression_test.dart index b238b5b1033c3..fd7569c2e5488 100644 --- a/packages/flutter/test/gestures/gesture_config_regression_test.dart +++ b/packages/flutter/test/gestures/gesture_config_regression_test.dart @@ -11,6 +11,7 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestResult { bool dragStarted = false; bool dragUpdate = false; + bool dragEnd = false; } class NestedScrollableCase extends StatelessWidget { @@ -77,7 +78,9 @@ class NestedDraggableCase extends StatelessWidget { onDragUpdate: (DragUpdateDetails details){ testResult.dragUpdate = true; }, - onDragEnd: (_) {}, + onDragEnd: (_) { + testResult.dragEnd = true; + }, ), ); }, @@ -134,5 +137,6 @@ void main() { expect(result.dragStarted, true); expect(result.dragUpdate, true); + expect(result.dragEnd, true); }); } diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 7585853dc459b..ddc3c2fd254f2 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -282,15 +282,7 @@ void main() { await tester.tap(find.text('Another package')); await tester.pumpAndSettle(); expect(find.text('Another license'), findsOneWidget); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130354 - notGCedAllowList: { - 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 1, - }, - )); + }); testWidgetsWithLeakTracking('LicensePage control test with all properties', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); @@ -366,15 +358,7 @@ void main() { await tester.tap(find.text('Another package')); await tester.pumpAndSettle(); expect(find.text('Another license'), findsOneWidget); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130354 - notGCedAllowList: { - 'ValueNotifier<_OverlayEntryWidgetState?>':2, - 'ValueNotifier': 1, - }, - )); + }); testWidgetsWithLeakTracking('Material2 - _PackageLicensePage title style without AppBarTheme', (WidgetTester tester) async { LicenseRegistry.addLicense(() { From 899a29f8301e7effb1e8e4d9fd030d421a3adcc3 Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 15 Aug 2023 15:12:16 -0700 Subject: [PATCH 0733/1547] Reorganize and clarify API doc generator (#132353) ## Description This cleans up a lot of issues with the API doc generation. Here are the main changes: - Rename `dartdoc.dart` to `create_api_docs.dart` - Move the bulk of the operations out of `dev/bots/docs.sh` into `create_api_docs.dart`. - Delete `dashing_postprocess.dart` and `java_and_objc.dart` and incorporate those operations into `create_api_docs.dart`. - Refactor the doc generation into more understandable classes - Bump the snippets tool version to 0.4.0 (the latest one) - Centralize the information gathering about the Flutter repo into the new `FlutterInformation` class. - Clean up the directory handling, and convert to using the `file` package for all file and directory paths. - Add an `--output` option to docs.sh that specifies the location of the output ZIP file containing the docs. - Defaults to placing the output in `dev/docs/api_docs.zip` (i.e. where the previous code generates the file). - Moved all document generation into a temporary folder that is removed once the documents are generated, to avoid VSCode and other IDEs trying to index the thousands of HTML and JS files in the docs output. - Updated pubspec dependencies. ## Tests - Added tests for doc generation. --- dev/bots/docs.sh | 200 ++-- dev/docs/dashing_postprocess.dart | 29 - dev/tools/create_api_docs.dart | 1095 ++++++++++++++++++++++ dev/tools/dartdoc.dart | 606 ------------ dev/tools/java_and_objc_doc.dart | 97 -- dev/tools/pubspec.yaml | 2 +- dev/tools/test/create_api_docs_test.dart | 195 ++++ dev/tools/test/dartdoc_test.dart | 98 -- 8 files changed, 1384 insertions(+), 938 deletions(-) delete mode 100644 dev/docs/dashing_postprocess.dart create mode 100644 dev/tools/create_api_docs.dart delete mode 100644 dev/tools/dartdoc.dart delete mode 100644 dev/tools/java_and_objc_doc.dart create mode 100644 dev/tools/test/create_api_docs_test.dart delete mode 100644 dev/tools/test/dartdoc_test.dart diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh index 6a0cec83c97d8..64cd279c494f1 100755 --- a/dev/bots/docs.sh +++ b/dev/bots/docs.sh @@ -16,102 +16,13 @@ function script_location() { cd -P "$(dirname "$script_location")" >/dev/null && pwd } -function generate_docs() { - # Install and activate dartdoc. - # When updating to a new dartdoc version, please also update - # `dartdoc_options.yaml` to include newly introduced error and warning types. - "$DART" pub global activate dartdoc 6.3.0 - - # Install and activate the snippets tool, which resides in the - # assets-for-api-docs repo: - # https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets - "$DART" pub global activate snippets 0.3.1 - - # This script generates a unified doc set, and creates - # a custom index.html, placing everything into dev/docs/doc. - (cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get) - (cd "$FLUTTER_ROOT/dev/tools" && "$DART" pub get) - (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/dartdoc.dart") - (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/java_and_objc_doc.dart") -} - -# Zip up the docs so people can download them for offline usage. -function create_offline_zip() { - # Must be run from "$FLUTTER_ROOT/dev/docs" - echo "$(date): Zipping Flutter offline docs archive." - rm -rf flutter.docs.zip doc/offline - (cd ./doc; zip -r -9 -q ../flutter.docs.zip .) -} - -# Generate the docset for Flutter docs for use with Dash, Zeal, and Velocity. -function create_docset() { - # Must be run from "$FLUTTER_ROOT/dev/docs" - # Must have dashing installed: go get -u github.com/technosophos/dashing - # Dashing produces a LOT of log output (~30MB), so we redirect it, and just - # show the end of it if there was a problem. - echo "$(date): Building Flutter docset." - rm -rf flutter.docset - # If dashing gets stuck, Cirrus will time out the build after an hour, and we - # never get to see the logs. Thus, we run it in the background and tail the logs - # while we wait for it to complete. - dashing_log=/tmp/dashing.log - dashing build --source ./doc --config ./dashing.json > $dashing_log 2>&1 & - dashing_pid=$! - wait $dashing_pid && \ - cp ./doc/flutter/static-assets/favicon.png ./flutter.docset/icon.png && \ - "$DART" --disable-dart-dev --enable-asserts ./dashing_postprocess.dart && \ - tar cf flutter.docset.tar.gz --use-compress-program="gzip --best" flutter.docset - if [[ $? -ne 0 ]]; then - >&2 echo "Dashing docset generation failed" - tail -200 $dashing_log - exit 1 - fi -} - -function deploy_docs() { - case "$LUCI_BRANCH" in - master) - echo "$(date): Updating $LUCI_BRANCH docs: https://master-api.flutter.dev/" - # Disable search indexing on the master staging site so searches get only - # the stable site. - echo -e "User-agent: *\nDisallow: /" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt" - ;; - stable) - echo "$(date): Updating $LUCI_BRANCH docs: https://api.flutter.dev/" - # Enable search indexing on the master staging site so searches get only - # the stable site. - echo -e "# All robots welcome!" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt" - ;; - *) - >&2 echo "Docs deployment cannot be run on the $LUCI_BRANCH branch." - exit 0 - esac -} - -# Move the offline archives into place, after all the processing of the doc -# directory is done. This avoids the tools recursively processing the archives -# as part of their process. -function move_offline_into_place() { - # Must be run from "$FLUTTER_ROOT/dev/docs" - echo "$(date): Moving offline data into place." - mkdir -p doc/offline - mv flutter.docs.zip doc/offline/flutter.docs.zip - du -sh doc/offline/flutter.docs.zip - if [[ "$LUCI_BRANCH" == "stable" ]]; then - echo -e "\n ${FLUTTER_VERSION_STRING}\n https://api.flutter.dev/offline/flutter.docset.tar.gz\n" > doc/offline/flutter.xml - else - echo -e "\n ${FLUTTER_VERSION_STRING}\n https://master-api.flutter.dev/offline/flutter.docset.tar.gz\n" > doc/offline/flutter.xml - fi - mv flutter.docset.tar.gz doc/offline/flutter.docset.tar.gz - du -sh doc/offline/flutter.docset.tar.gz -} - # So that users can run this script from anywhere and it will work as expected. SCRIPT_LOCATION="$(script_location)" # Sets the Flutter root to be "$(script_location)/../..": This script assumes # that it resides two directory levels down from the root, so if that changes, # then this line will need to as well. FLUTTER_ROOT="$(dirname "$(dirname "$SCRIPT_LOCATION")")" +export FLUTTER_ROOT echo "$(date): Running docs.sh" @@ -124,31 +35,106 @@ FLUTTER_BIN="$FLUTTER_ROOT/bin" DART_BIN="$FLUTTER_ROOT/bin/cache/dart-sdk/bin" FLUTTER="$FLUTTER_BIN/flutter" DART="$DART_BIN/dart" -export PATH="$FLUTTER_BIN:$DART_BIN:$PATH" +PATH="$FLUTTER_BIN:$DART_BIN:$PATH" -# Make sure dart is installed by invoking Flutter to download it. -# This also creates the 'version' file. -FLUTTER_VERSION=$("$FLUTTER" --version --machine) +# Make sure dart is installed by invoking Flutter to download it if it is missing. +# Also make sure the flutter command is ready to run before capturing output from +# it: if it has to rebuild itself or something, it'll spoil our JSON output. +"$FLUTTER" > /dev/null 2>&1 +FLUTTER_VERSION="$("$FLUTTER" --version --machine)" export FLUTTER_VERSION -FLUTTER_VERSION_STRING=$(cat "$FLUTTER_ROOT/version") # If the pub cache directory exists in the root, then use that. FLUTTER_PUB_CACHE="$FLUTTER_ROOT/.pub-cache" if [[ -d "$FLUTTER_PUB_CACHE" ]]; then # This has to be exported, because pub interprets setting it to the empty # string in the same way as setting it to ".". - export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}" + PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}" + export PUB_CACHE fi -generate_docs -# Skip publishing docs for PRs and release candidate branches -if [[ -n "$LUCI_CI" && -z "$LUCI_PR" ]]; then - (cd "$FLUTTER_ROOT/dev/docs"; create_offline_zip) - (cd "$FLUTTER_ROOT/dev/docs"; create_docset) - (cd "$FLUTTER_ROOT/dev/docs"; move_offline_into_place) - deploy_docs -fi +OUTPUT_DIR=$(mktemp -d /tmp/dartdoc.XXXXX) +DOC_DIR="$OUTPUT_DIR/doc" + +function usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") [--keep-temp] [--output ]" + echo "" + echo " --keep-temp Do not delete the temporary output directory created while generating docs." + echo " Normally the script deletes the temporary directory after generating the" + echo " output ZIP file." + echo " --output specifies where the output ZIP file containing the documentation data" + echo " will be written." + echo "" +} + +function parse_args() { + local arg + local args=() + KEEP_TEMP=0 + DESTINATION="$FLUTTER_ROOT/dev/docs/api_docs.zip" + while (( "$#" )); do + case "$1" in + --help) + usage + exit 0 + ;; + --keep-temp) + KEEP_TEMP=1 + ;; + --output) + DESTINATION="$2" + shift + ;; + *) + args=("${args[@]}" "$1") + ;; + esac + shift + done + if [[ ${#args[@]} != 0 ]]; then + >&2 echo "ERROR: Unknown arguments: ${args[@]}" + usage + exit 1 + fi +} + +function generate_docs() { + # Install and activate dartdoc. + # When updating to a new dartdoc version, please also update + # `dartdoc_options.yaml` to include newly introduced error and warning types. + "$DART" pub global activate dartdoc 6.3.0 + + # Install and activate the snippets tool, which resides in the + # assets-for-api-docs repo: + # https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets + "$DART" pub global activate snippets 0.4.0 + + # This script generates a unified doc set, and creates + # a custom index.html, placing everything into DOC_DIR. + + # Make sure that create_api_docs.dart has all the dependencies it needs. + (cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get) + (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/create_api_docs.dart" --output-dir="$DOC_DIR") +} + +function main() { + echo "Writing docs build temporary output to $DOC_DIR" + mkdir -p "$DOC_DIR" + generate_docs + # If the destination isn't an absolute path, make it into one. + if ! [[ "$DESTINATION" =~ ^/ ]]; then + DESTINATION="$PWD/$DESTINATION" + fi + # Zip up doc directory and write the output to the destination. + (cd "$OUTPUT_DIR"; zip -r -9 -q "$DESTINATION" ./doc) + if [[ $KEEP_TMP == 1 ]]; then + echo "Temporary document generation output left in $OUTPUT_DIR" + else + echo "Removing Temporary document generation output from $OUTPUT_DIR" + rm -rf "$OUTPUT_DIR" + fi + echo "Wrote docs ZIP file to $DESTINATION" +} -# Zip docs -cd "$FLUTTER_ROOT/dev/docs" -zip -r api_docs.zip doc +parse_args "$@" +main diff --git a/dev/docs/dashing_postprocess.dart b/dev/docs/dashing_postprocess.dart deleted file mode 100644 index 9f186e4f2c315..0000000000000 --- a/dev/docs/dashing_postprocess.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:io'; - -/// This changes the DocSetPlatformFamily key to be "dartlang" instead of the -/// name of the package (usually "flutter"). -/// -/// This is so that the IntelliJ plugin for Dash will be able to go directly to -/// the docs for a symbol from a keystroke. Without this, flutter isn't part -/// of the list of package names it searches. After this, it finds the flutter -/// docs because they're declared here to be part of the "dartlang" family of -/// docs. -/// -/// Dashing doesn't have a way to configure this, so we modify the Info.plist -/// directly to make the change. -void main(List args) { - final File infoPlist = File('flutter.docset/Contents/Info.plist'); - String contents = infoPlist.readAsStringSync(); - - // Since I didn't want to add the XML package as a dependency just for this, - // I just used a regular expression to make this simple change. - final RegExp findRe = RegExp(r'(\s*DocSetPlatformFamily\s*)[^<]+()', multiLine: true); - contents = contents.replaceAllMapped(findRe, (Match match) { - return '${match.group(1)}dartlang${match.group(2)}'; - }); - infoPlist.writeAsStringSync(contents); -} diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart new file mode 100644 index 0000000000000..924e34a34e826 --- /dev/null +++ b/dev/tools/create_api_docs.dart @@ -0,0 +1,1095 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; +import 'dart:math' as math; + +import 'package:archive/archive_io.dart'; +import 'package:args/args.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; +import 'package:platform/platform.dart'; +import 'package:process/process.dart'; +import 'package:pub_semver/pub_semver.dart'; + +import 'dartdoc_checker.dart'; +import 'examples_smoke_test.dart'; + +FileSystem filesystem = const LocalFileSystem(); + +const String kDummyPackageName = 'Flutter'; +const String kPlatformIntegrationPackageName = 'platform_integration'; + +/// This script will generate documentation for the packages in `packages/` and +/// write the documentation to the output directory specified on the command +/// line. +/// +/// This script also updates the index.html file so that it can be placed at the +/// root of api.flutter.dev. The files are kept inside of +/// api.flutter.dev/flutter, so we need to manipulate paths a bit. See +/// https://github.com/flutter/flutter/issues/3900 for more info. +/// +/// This will only work on UNIX systems, not Windows. It requires that 'git', +/// 'zip', and 'tar' be in the PATH. It requires that 'flutter' has been run +/// previously. It uses the version of Dart downloaded by the 'flutter' tool in +/// this repository and will fail if that is absent. +Future main(List arguments) async { + // The place to find customization files and configuration files for docs + // generation. + final Directory docsRoot = filesystem + .directory(FlutterInformation.instance.getFlutterRoot().childDirectory('dev').childDirectory('docs')) + .absolute; + final ArgParser argParser = _createArgsParser( + publishDefault: docsRoot.childDirectory('doc').path, + ); + final ArgResults args = argParser.parse(arguments); + if (args['help'] as bool) { + print('Usage:'); + print(argParser.usage); + exit(0); + } + + final Directory publishRoot = filesystem.directory(args['output-dir']! as String); + final Directory packageRoot = publishRoot.parent; + if (!filesystem.directory(packageRoot).existsSync()) { + filesystem.directory(packageRoot).createSync(recursive: true); + } + + if (!filesystem.directory(publishRoot).existsSync()) { + filesystem.directory(publishRoot).createSync(recursive: true); + } + + final Configurator configurator = Configurator( + publishRoot: publishRoot, + packageRoot: packageRoot, + docsRoot: docsRoot, + ); + configurator.generateConfiguration(); + + final PlatformDocGenerator platformGenerator = PlatformDocGenerator(outputDir: publishRoot); + platformGenerator.generatePlatformDocs(); + + final DartdocGenerator dartdocGenerator = DartdocGenerator( + publishRoot: publishRoot, + packageRoot: packageRoot, + docsRoot: docsRoot, + useJson: args['json'] as bool? ?? true, + validateLinks: args['validate-links']! as bool, + verbose: args['verbose'] as bool? ?? false, + ); + + await dartdocGenerator.generateDartdoc(); + await configurator.generateOfflineAssetsIfNeeded(); +} + +ArgParser _createArgsParser({required String publishDefault}) { + final ArgParser parser = ArgParser(); + parser.addFlag('help', abbr: 'h', negatable: false, help: 'Show command help.'); + parser.addFlag('verbose', + defaultsTo: true, + help: 'Whether to report all error messages (on) or attempt to ' + 'filter out some known false positives (off). Shut this off ' + 'locally if you want to address Flutter-specific issues.'); + parser.addFlag('json', help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); + parser.addFlag('validate-links', help: 'Display warnings for broken links generated by dartdoc (slow)'); + parser.addOption('output-dir', defaultsTo: publishDefault, help: 'Sets the output directory for the documentation.'); + return parser; +} + +/// A class used to configure the staging area for building the docs in. +/// +/// The [generateConfiguration] function generates a dummy package with a +/// pubspec. It copies any assets and customization files from the framework +/// repo. It creates a metadata file for searches. +/// +/// Once the docs have been generated, [generateOfflineAssetsIfNeeded] will +/// create offline assets like Dash/Zeal docsets and an offline ZIP file of the +/// site if the build is a CI build that is not a presubmit build. +class Configurator { + Configurator({ + required this.docsRoot, + required this.publishRoot, + required this.packageRoot, + this.filesystem = const LocalFileSystem(), + }); + + /// The root of the directory in the Flutter repo where configuration data is + /// stored. + final Directory docsRoot; + + /// The root of the output area for the dartdoc docs. + /// + /// Typically this is a "doc" subdirectory under the [packageRoot]. + final Directory publishRoot; + + /// The root of the staging area for creating docs. + final Directory packageRoot; + + /// The [FileSystem] object used to create [File] and [Directory] objects. + final FileSystem filesystem; + + void generateConfiguration() { + final Version version = FlutterInformation.instance.getFlutterVersion(); + _createDummyPubspec(); + _createDummyLibrary(); + _createPageFooter(packageRoot, version); + _copyCustomizations(); + _createSearchMetadata( + docsRoot.childDirectory('lib').childFile('opensearch.xml'), publishRoot.childFile('opensearch.xml')); + } + + Future generateOfflineAssetsIfNeeded() async { + // Only create the offline docs if we're running in a non-presubmit build: + // it takes too long otherwise. + if (platform.environment.containsKey('LUCI_CI') && (platform.environment['LUCI_PR'] ?? '').isEmpty) { + _createOfflineZipFile(); + await _createDocset(); + _moveOfflineIntoPlace(); + _createRobotsTxt(); + } + } + + /// Returns import or on-disk paths for all libraries in the Flutter SDK. + Iterable _libraryRefs() sync* { + for (final Directory dir in findPackages()) { + final String dirName = dir.basename; + for (final FileSystemEntity file in dir.childDirectory('lib').listSync()) { + if (file is File && file.path.endsWith('.dart')) { + yield '$dirName/${file.basename}'; + } + } + } + + // Add a fake package for platform integration APIs. + yield '$kPlatformIntegrationPackageName/android.dart'; + yield '$kPlatformIntegrationPackageName/ios.dart'; + } + + void _createDummyPubspec() { + // Create the pubspec.yaml file. + final List pubspec = [ + 'name: $kDummyPackageName', + 'homepage: https://flutter.dev', + 'version: 0.0.0', + 'environment:', + " sdk: '>=3.0.0-0 <4.0.0'", + 'dependencies:', + for (final String package in findPackageNames()) ' $package:\n sdk: flutter', + ' $kPlatformIntegrationPackageName: 0.0.1', + 'dependency_overrides:', + ' $kPlatformIntegrationPackageName:', + ' path: ${docsRoot.childDirectory(kPlatformIntegrationPackageName).path}', + ]; + + packageRoot.childFile('pubspec.yaml').writeAsStringSync(pubspec.join('\n')); + } + + void _createDummyLibrary() { + final Directory libDir = packageRoot.childDirectory('lib'); + libDir.createSync(); + + final StringBuffer contents = StringBuffer('library temp_doc;\n\n'); + for (final String libraryRef in _libraryRefs()) { + contents.writeln("import 'package:$libraryRef';"); + } + packageRoot.childDirectory('lib') + ..createSync(recursive: true) + ..childFile('temp_doc.dart').writeAsStringSync(contents.toString()); + } + + void _createPageFooter(Directory footerPath, Version version) { + final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now()); + final String gitBranch = FlutterInformation.instance.getBranchName(); + final String gitRevision = FlutterInformation.instance.getFlutterRevision(); + final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch'; + footerPath.childFile('footer.html').writeAsStringSync(''); + publishRoot.childDirectory('flutter').childFile('footer.js') + ..createSync(recursive: true) + ..writeAsStringSync(''' +(function() { + var span = document.querySelector('footer>span'); + if (span) { + span.innerText = 'Flutter $version • $timestamp • $gitRevision $gitBranchOut'; + } + var sourceLink = document.querySelector('a.source-link'); + if (sourceLink) { + sourceLink.href = sourceLink.href.replace('/master/', '/$gitRevision/'); + } +})(); +'''); + } + + void _copyCustomizations() { + final List files = [ + 'README.md', + 'analysis_options.yaml', + 'dartdoc_options.yaml', + ]; + for (final String file in files) { + filesystem.file(docsRoot.childFile(file)).copySync(packageRoot.childFile(file).path); + } + final Directory assetsDir = filesystem.directory(publishRoot.childDirectory('assets')); + if (assetsDir.existsSync()) { + assetsDir.deleteSync(recursive: true); + } + copyDirectorySync(docsRoot.childDirectory('assets'), assetsDir, + (File src, File dest) => print('Copied ${src.path} to ${dest.path}')); + } + + /// Generates an OpenSearch XML description that can be used to add a custom + /// search for Flutter API docs to the browser. Unfortunately, it has to know + /// the URL to which site to search, so we customize it here based upon the + /// branch name. + void _createSearchMetadata(File templatePath, File metadataPath) { + final String template = templatePath.readAsStringSync(); + final String branch = FlutterInformation.instance.getBranchName(); + final String metadata = template.replaceAll( + '{SITE_URL}', + branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/', + ); + metadataPath.parent.create(recursive: true); + metadataPath.writeAsStringSync(metadata); + } + + Future _createDocset() async { + // Must have dashing installed: go get -u github.com/technosophos/dashing + // Dashing produces a LOT of log output (~30MB), so we collect it, and just + // show the end of it if there was a problem. + print('${DateTime.now().toUtc()}: Building Flutter docset.'); + + // If dashing gets stuck, Cirrus will time out the build after an hour, and we + // never get to see the logs. Thus, we run it in the background and tail the + // logs only if it fails. + final ProcessWrapper result = ProcessWrapper( + await processManager.start( + [ + 'dashing', + 'build', + '--source', + publishRoot.path, + '--config', + docsRoot.childFile('dashing.json').path, + ], + workingDirectory: packageRoot.path, + ), + ); + final List buffer = []; + result.stdout.listen(buffer.addAll); + result.stderr.listen(buffer.addAll); + // If the dashing process exited with an error, print the last 200 lines of stderr and exit. + final int exitCode = await result.done; + if (exitCode != 0) { + print('Dashing docset generation failed with code $exitCode'); + final List output = systemEncoding.decode(buffer).split('\n'); + print(output.sublist(math.max(output.length - 200, 0)).join('\n')); + exit(exitCode); + } + buffer.clear(); + + // Copy the favicon file to the output directory. + final File faviconFile = + publishRoot.childDirectory('flutter').childDirectory('static-assets').childFile('favicon.png'); + final File iconFile = packageRoot.childDirectory('flutter.docset').childFile('icon.png'); + faviconFile..createSync(recursive: true)..copySync(iconFile.path); + + // Post-process the dashing output. + final File infoPlist = + packageRoot.childDirectory('flutter.docset').childDirectory('Contents').childFile('Info.plist'); + String contents = infoPlist.readAsStringSync(); + + // Since I didn't want to add the XML package as a dependency just for this, + // I just used a regular expression to make this simple change. + final RegExp findRe = RegExp(r'(\s*DocSetPlatformFamily\s*)[^<]+()', multiLine: true); + contents = contents.replaceAllMapped(findRe, (Match match) { + return '${match.group(1)}dartlang${match.group(2)}'; + }); + infoPlist.writeAsStringSync(contents); + final Directory offlineDir = publishRoot.childDirectory('offline'); + if (!offlineDir.existsSync()) { + offlineDir.createSync(recursive: true); + } + tarDirectory(packageRoot, offlineDir.childFile('flutter.docset.tar.gz')); + + // Write the Dash/Zeal XML feed file. + final bool isStable = platform.environment['LUCI_BRANCH'] == 'stable'; + offlineDir.childFile('flutter.xml').writeAsStringSync('\n' + ' ${FlutterInformation.instance.getFlutterVersion()}\n' + ' https://${isStable ? '' : 'master-'}api.flutter.dev/offline/flutter.docset.tar.gz\n' + '\n'); + } + + // Creates the offline ZIP file containing all of the website HTML files. + void _createOfflineZipFile() { + print('${DateTime.now().toLocal()}: Creating offline docs archive.'); + zipDirectory(publishRoot, packageRoot.childFile('flutter.docs.zip')); + } + + // Moves the generated offline archives into the publish directory so that + // they can be included in the output ZIP file. + void _moveOfflineIntoPlace() { + print('${DateTime.now().toUtc()}: Moving offline docs into place.'); + final Directory offlineDir = publishRoot.childDirectory('offline')..createSync(recursive: true); + packageRoot.childFile('flutter.docs.zip').renameSync(offlineDir.childFile('flutter.docs.zip').path); + } + + // Creates a robots.txt file that disallows indexing unless the branch is the + // stable branch. + void _createRobotsTxt() { + final File robotsTxt = publishRoot.childFile('robots.txt'); + if (FlutterInformation.instance.getBranchName() == 'stable') { + robotsTxt.writeAsStringSync('# All robots welcome!'); + } else { + robotsTxt.writeAsStringSync('User-agent: *\nDisallow: /'); + } + } +} + +/// Runs Dartdoc inside of the given pre-prepared staging area, prepared by +/// [Configurator.generateConfiguration]. +/// +/// Performs a sanity check of the output once the generation is complete. +class DartdocGenerator { + DartdocGenerator({ + required this.docsRoot, + required this.publishRoot, + required this.packageRoot, + this.filesystem = const LocalFileSystem(), + this.useJson = true, + this.validateLinks = true, + this.verbose = false, + }); + + /// The root of the directory in the Flutter repo where configuration data is + /// stored. + final Directory docsRoot; + + /// The root of the output area for the dartdoc docs. + /// + /// Typically this is a "doc" subdirectory under the [packageRoot]. + final Directory publishRoot; + + /// The root of the staging area for creating docs. + final Directory packageRoot; + + /// The [FileSystem] object used to create [File] and [Directory] objects. + final FileSystem filesystem; + + /// Whether or not dartdoc should output an index.json file of the + /// documentation. + final bool useJson; + + // Whether or not to have dartdoc validate its own links. + final bool validateLinks; + + /// Whether or not to filter overly verbose log output from dartdoc. + final bool verbose; + + Future generateDartdoc() async { + final Directory flutterRoot = FlutterInformation.instance.getFlutterRoot(); + final Map pubEnvironment = { + 'FLUTTER_ROOT': flutterRoot.absolute.path, + }; + + // If there's a .pub-cache dir in the Flutter root, use that. + final File pubCache = flutterRoot.childFile('.pub-cache'); + if (pubCache.existsSync()) { + pubEnvironment['PUB_CACHE'] = pubCache.path; + } + + // Run pub. + ProcessWrapper process = ProcessWrapper(await runPubProcess( + arguments: ['get'], + workingDirectory: packageRoot, + environment: pubEnvironment, + )); + printStream(process.stdout, prefix: 'pub:stdout: '); + printStream(process.stderr, prefix: 'pub:stderr: '); + final int code = await process.done; + if (code != 0) { + exit(code); + } + + final Version version = FlutterInformation.instance.getFlutterVersion(); + + // Verify which version of snippets and dartdoc we're using. + final ProcessResult snippetsResult = Process.runSync( + FlutterInformation.instance.getDartBinaryPath().path, + [ + 'pub', + 'global', + 'list', + ], + workingDirectory: packageRoot.path, + environment: pubEnvironment, + stdoutEncoding: utf8, + ); + print(''); + final Iterable versionMatches = + RegExp(r'^(?snippets|dartdoc) (?[^\s]+)', multiLine: true) + .allMatches(snippetsResult.stdout as String); + for (final RegExpMatch match in versionMatches) { + print('${match.namedGroup('name')} version: ${match.namedGroup('version')}'); + } + + print('flutter version: $version\n'); + + // Dartdoc warnings and errors in these packages are considered fatal. + // All packages owned by flutter should be in the list. + final List flutterPackages = [ + kDummyPackageName, + kPlatformIntegrationPackageName, + ...findPackageNames(), + // TODO(goderbauer): Figure out how to only include `dart:ui` of + // `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278. + // 'sky_engine', + ]; + + // Generate the documentation. We don't need to exclude flutter_tools in + // this list because it's not in the recursive dependencies of the package + // defined at packageRoot + final List dartdocArgs = [ + 'global', + 'run', + '--enable-asserts', + 'dartdoc', + '--output', + publishRoot.childDirectory('flutter').path, + '--allow-tools', + if (useJson) '--json', + if (validateLinks) '--validate-links' else '--no-validate-links', + '--link-to-source-excludes', + flutterRoot.childDirectory('bin').childDirectory('cache').path, + '--link-to-source-root', + flutterRoot.path, + '--link-to-source-uri-template', + 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', + '--inject-html', + '--use-base-href', + '--header', + docsRoot.childFile('styles.html').path, + '--header', + docsRoot.childFile('analytics.html').path, + '--header', + docsRoot.childFile('survey.html').path, + '--header', + docsRoot.childFile('snippets.html').path, + '--header', + docsRoot.childFile('opensearch.html').path, + '--footer-text', + packageRoot.childFile('footer.html').path, + '--allow-warnings-in-packages', + flutterPackages.join(','), + '--exclude-packages', + [ + 'analyzer', + 'args', + 'barback', + 'csslib', + 'flutter_goldens', + 'flutter_goldens_client', + 'front_end', + 'fuchsia_remote_debug_protocol', + 'glob', + 'html', + 'http_multi_server', + 'io', + 'isolate', + 'js', + 'kernel', + 'logging', + 'mime', + 'mockito', + 'node_preamble', + 'plugin', + 'shelf', + 'shelf_packages_handler', + 'shelf_static', + 'shelf_web_socket', + 'utf', + 'watcher', + 'yaml', + ].join(','), + '--exclude', + [ + 'dart:io/network_policy.dart', // dart-lang/dartdoc#2437 + 'package:Flutter/temp_doc.dart', + 'package:http/browser_client.dart', + 'package:intl/intl_browser.dart', + 'package:matcher/mirror_matchers.dart', + 'package:quiver/io.dart', + 'package:quiver/mirrors.dart', + 'package:vm_service_client/vm_service_client.dart', + 'package:web_socket_channel/html.dart', + ].join(','), + '--favicon', + docsRoot.childFile('favicon.ico').absolute.path, + '--package-order', + 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver', + '--auto-include-dependencies', + ]; + + String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg; + print('Executing: (cd "${packageRoot.path}" ; ' + '${FlutterInformation.instance.getDartBinaryPath().path} ' + '${dartdocArgs.map(quote).join(' ')})'); + + process = ProcessWrapper(await runPubProcess( + arguments: dartdocArgs, + workingDirectory: packageRoot, + environment: pubEnvironment, + )); + printStream( + process.stdout, + prefix: useJson ? '' : 'dartdoc:stdout: ', + filter: [ + if (!verbose) RegExp(r'^Generating docs for library '), // Unnecessary verbosity + ], + ); + printStream( + process.stderr, + prefix: useJson ? '' : 'dartdoc:stderr: ', + filter: [ + if (!verbose) + RegExp( + // Remove warnings from packages outside our control + r'^ warning: .+: \(.+[\\/]\.pub-cache[\\/]hosted[\\/]pub.dartlang.org[\\/].+\)', + ), + ], + ); + final int exitCode = await process.done; + + if (exitCode != 0) { + exit(exitCode); + } + + _sanityCheckDocs(); + checkForUnresolvedDirectives(publishRoot.childDirectory('flutter').path); + + _createIndexAndCleanup(); + + print('Documentation written to ${publishRoot.path}'); + } + + void _sanityCheckExample(String fileString, String regExpString) { + final File file = filesystem.file(fileString); + if (file.existsSync()) { + final RegExp regExp = RegExp(regExpString, dotAll: true); + final String contents = file.readAsStringSync(); + if (!regExp.hasMatch(contents)) { + throw Exception("Missing example code matching '$regExpString' in ${file.path}."); + } + } else { + throw Exception( + "Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file."); + } + } + + /// Runs a sanity check by running a test. + void _sanityCheckDocs([Platform platform = const LocalPlatform()]) { + final Directory flutterDirectory = publishRoot.childDirectory('flutter'); + final Directory widgetsDirectory = flutterDirectory.childDirectory('widgets'); + + final List canaries = [ + publishRoot.childDirectory('assets').childFile('overrides.css'), + flutterDirectory.childDirectory('dart-io').childFile('File-class.html'), + flutterDirectory.childDirectory('dart-ui').childFile('Canvas-class.html'), + flutterDirectory.childDirectory('dart-ui').childDirectory('Canvas').childFile('drawRect.html'), + flutterDirectory + .childDirectory('flutter_driver') + .childDirectory('FlutterDriver') + .childFile('FlutterDriver.connectedTo.html'), + flutterDirectory.childDirectory('flutter_test').childDirectory('WidgetTester').childFile('pumpWidget.html'), + flutterDirectory.childDirectory('material').childFile('Material-class.html'), + flutterDirectory.childDirectory('material').childFile('Tooltip-class.html'), + widgetsDirectory.childFile('Widget-class.html'), + widgetsDirectory.childFile('Listener-class.html'), + ]; + for (final File canary in canaries) { + if (!canary.existsSync()) { + throw Exception('Missing "${canary.path}", which probably means the documentation failed to build correctly.'); + } + } + // Make sure at least one example of each kind includes source code. + + // Check a "sample" example, any one will do. + _sanityCheckExample( + widgetsDirectory.childFile('showGeneralDialog.html').path, + r'\s*\s*import 'package:flutter/material.dart';', + ); + + // Check a "snippet" example, any one will do. + _sanityCheckExample( + widgetsDirectory.childDirectory('ModalRoute').childFile('barrierColor.html').path, + r'\s*.*Color\s+get\s+barrierColor.*', + ); + + // Check a "dartpad" example, any one will do, and check for the correct URL + // arguments. + // Just use "master" for any branch other than the LUCI_BRANCH. + final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim(); + final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master'; + final List argumentRegExps = [ + r'split=\d+', + r'run=true', + r'sample_id=widgets\.Listener\.\d+', + 'sample_channel=$expectedBranch', + 'channel=$expectedBranch', + ]; + for (final String argumentRegExp in argumentRegExps) { + _sanityCheckExample( + widgetsDirectory.childFile('Listener-class.html').path, + r'\s*\s*<\/iframe>', + ); + } + } + + /// Creates a custom index.html because we try to maintain old + /// paths. Cleanup unused index.html files no longer needed. + void _createIndexAndCleanup() { + print('\nCreating a custom index.html in ${publishRoot.childFile('index.html').path}'); + _copyIndexToRootOfDocs(); + _addHtmlBaseToIndex(); + _changePackageToSdkInTitlebar(); + _putRedirectInOldIndexLocation(); + _writeSnippetsIndexFile(); + print('\nDocs ready to go!'); + } + + void _copyIndexToRootOfDocs() { + publishRoot.childDirectory('flutter').childFile('index.html').copySync(publishRoot.childFile('index.html').path); + } + + void _changePackageToSdkInTitlebar() { + final File indexFile = publishRoot.childFile('index.html'); + String indexContents = indexFile.readAsStringSync(); + indexContents = indexContents.replaceFirst( + '
  • Flutter package
  • ', + '
  • Flutter SDK
  • ', + ); + + indexFile.writeAsStringSync(indexContents); + } + + void _addHtmlBaseToIndex() { + final File indexFile = publishRoot.childFile('index.html'); + String indexContents = indexFile.readAsStringSync(); + indexContents = indexContents.replaceFirst( + '\n', + '\n \n', + ); + indexContents = indexContents.replaceAll( + 'href="Android/Android-library.html"', + 'href="/javadoc/"', + ); + indexContents = indexContents.replaceAll( + 'href="iOS/iOS-library.html"', + 'href="/objcdoc/"', + ); + + indexFile.writeAsStringSync(indexContents); + } + + void _putRedirectInOldIndexLocation() { + const String metaTag = ''; + publishRoot.childDirectory('flutter').childFile('index.html').writeAsStringSync(metaTag); + } + + void _writeSnippetsIndexFile() { + final Directory snippetsDir = publishRoot.childDirectory('snippets'); + if (snippetsDir.existsSync()) { + const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' '); + final Iterable files = + snippetsDir.listSync().whereType().where((File file) => path.extension(file.path) == '.json'); + // Combine all the metadata into a single JSON array. + final Iterable fileContents = files.map((File file) => file.readAsStringSync()); + final List metadataObjects = fileContents.map(json.decode).toList(); + final String jsonArray = jsonEncoder.convert(metadataObjects); + snippetsDir.childFile('index.json').writeAsStringSync(jsonArray); + } + } +} + +/// Downloads and unpacks the platform specific documentation generated by the +/// engine build. +/// +/// Unpacks and massages the data so that it can be properly included in the +/// output archive. +class PlatformDocGenerator { + PlatformDocGenerator({required this.outputDir, this.filesystem = const LocalFileSystem()}); + + final FileSystem filesystem; + final Directory outputDir; + final String engineRevision = FlutterInformation.instance.getEngineRevision(); + + /// This downloads an archive of platform docs for the engine from the artifact + /// store and extracts them to the location used for Dartdoc. + void generatePlatformDocs() { + final String javadocUrl = + 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; + _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); + + final String objcdocUrl = + 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; + _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); + } + + /// Fetches the zip archive at the specified url. + /// + /// Returns null if the archive fails to download after [maxTries] attempts. + Future _fetchArchive(String url, int maxTries) async { + List? responseBytes; + for (int i = 0; i < maxTries; i++) { + final http.Response response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + responseBytes = response.bodyBytes; + break; + } + stderr.writeln('Failed attempt ${i + 1} to fetch $url.'); + + // On failure print a short snipped from the body in case it's helpful. + final int bodyLength = math.min(1024, response.body.length); + stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}'); + sleep(const Duration(seconds: 1)); + } + return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); + } + + Future _extractDocs(String url, String docName, String checkFile, Directory outputDir) async { + const int maxTries = 5; + final Archive? archive = await _fetchArchive(url, maxTries); + if (archive == null) { + stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.'); + exit(1); + } + + final Directory output = outputDir.childDirectory(docName); + print('Extracting $docName to ${output.path}'); + output.createSync(recursive: true); + + for (final ArchiveFile af in archive) { + if (!af.name.endsWith('/')) { + final File file = filesystem.file('${output.path}/${af.name}'); + file.createSync(recursive: true); + file.writeAsBytesSync(af.content as List); + } + } + + /// If object then copy files to old location if the archive is using the new location. + final Directory objcDocsDir = output.childDirectory('objectc_docs'); + if (objcDocsDir.existsSync()) { + copyDirectorySync(objcDocsDir, output); + } + + final File testFile = output.childFile(checkFile); + if (!testFile.existsSync()) { + print('Expected file ${testFile.path} not found'); + exit(1); + } + print('$docName ready to go!'); + } +} + +/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if +/// specified, for each source/destination file pair. +/// +/// Creates `destDir` if needed. +void copyDirectorySync(Directory srcDir, Directory destDir, + [void Function(File srcFile, File destFile)? onFileCopied]) { + if (!srcDir.existsSync()) { + throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); + } + + if (!destDir.existsSync()) { + destDir.createSync(recursive: true); + } + + for (final FileSystemEntity entity in srcDir.listSync()) { + final String newPath = path.join(destDir.path, path.basename(entity.path)); + if (entity is File) { + final File newFile = filesystem.file(newPath); + entity.copySync(newPath); + onFileCopied?.call(entity, newFile); + } else if (entity is Directory) { + copyDirectorySync(entity, filesystem.directory(newPath)); + } else { + throw Exception('${entity.path} is neither File nor Directory'); + } + } +} + +void printStream(Stream> stream, {String prefix = '', List filter = const []}) { + stream.transform(utf8.decoder).transform(const LineSplitter()).listen((String line) { + if (!filter.any((Pattern pattern) => line.contains(pattern))) { + print('$prefix$line'.trim()); + } + }); +} + +void zipDirectory(Directory src, File output) { + // We would use the archive package to do this in one line, but it + // is a lot slower, and doesn't do compression nearly as well. + final ProcessResult zipProcess = processManager.runSync( + [ + 'zip', + '-r', + '-9', + '-q', + output.path, + '.', + ], + workingDirectory: src.path, + ); + + if (zipProcess.exitCode != 0) { + print('Creating offline ZIP archive ${output.path} failed:'); + print(zipProcess.stderr); + exit(1); + } +} + +void tarDirectory(Directory src, File output) { + // We would use the archive package to do this in one line, but it + // is a lot slower, and doesn't do compression nearly as well. + final ProcessResult tarProcess = processManager.runSync( + [ + 'tar', + 'cf', + output.path, + '--use-compress-program', + 'gzip --best', + 'flutter.docset', + ], + workingDirectory: src.path, + ); + + if (tarProcess.exitCode != 0) { + print('Creating a tarball ${output.path} failed:'); + print(tarProcess.stderr); + exit(1); + } +} + +Future runPubProcess({ + required List arguments, + Directory? workingDirectory, + Map? environment, + @visibleForTesting ProcessManager processManager = const LocalProcessManager(), + @visibleForTesting FileSystem filesystem = const LocalFileSystem(), +}) { + return processManager.start( + [FlutterInformation.instance.getDartBinaryPath().path, 'pub', ...arguments], + workingDirectory: (workingDirectory ?? filesystem.currentDirectory).path, + environment: environment, + ); +} + +List findPackageNames() { + return findPackages().map((FileSystemEntity file) => path.basename(file.path)).toList(); +} + +/// Finds all packages in the Flutter SDK +List findPackages() { + return FlutterInformation.instance + .getFlutterRoot() + .childDirectory('packages') + .listSync() + .where((FileSystemEntity entity) { + if (entity is! Directory) { + return false; + } + final File pubspec = filesystem.file('${entity.path}/pubspec.yaml'); + if (!pubspec.existsSync()) { + print("Unexpected package '${entity.path}' found in packages directory"); + return false; + } + // TODO(ianh): Use a real YAML parser here + return !pubspec.readAsStringSync().contains('nodoc: true'); + }) + .cast() + .toList(); +} + +/// An exception class used to indicate problems when collecting information. +class DartdocException implements Exception { + DartdocException(this.message, {this.file, this.line}); + final String message; + final String? file; + final int? line; + + @override + String toString() { + if (file != null || line != null) { + final String fileStr = file == null ? '' : '$file:'; + final String lineStr = line == null ? '' : '$line:'; + return '$runtimeType: $fileStr$lineStr: $message'; + } else { + return '$runtimeType: $message'; + } + } +} + +/// A singleton used to consolidate the way in which information about the +/// Flutter repo and environment is collected. +/// +/// Collects the information once, and caches it for any later access. +/// +/// The singleton instance can be overridden by tests by setting [instance]. +class FlutterInformation { + FlutterInformation({ + this.platform = const LocalPlatform(), + this.processManager = const LocalProcessManager(), + this.filesystem = const LocalFileSystem(), + }); + + final Platform platform; + final ProcessManager processManager; + final FileSystem filesystem; + + static FlutterInformation? _instance; + + static FlutterInformation get instance => _instance ??= FlutterInformation(); + + @visibleForTesting + static set instance(FlutterInformation? value) => _instance = value; + + /// The path to the Dart binary in the Flutter repo. + /// + /// This is probably a shell script. + File getDartBinaryPath() { + return getFlutterRoot().childDirectory('bin').childFile('dart'); + } + + /// The path to the Flutter repo root directory. + /// + /// If the environment variable `FLUTTER_ROOT` is set, will use that instead + /// of looking for it. + /// + /// Otherwise, uses the output of `flutter --version --machine` to find the + /// Flutter root. + Directory getFlutterRoot() { + if (platform.environment['FLUTTER_ROOT'] != null) { + return filesystem.directory(platform.environment['FLUTTER_ROOT']); + } + return getFlutterInformation()['flutterRoot']! as Directory; + } + + /// Gets the semver version of the Flutter framework in the repo. + Version getFlutterVersion() => getFlutterInformation()['frameworkVersion']! as Version; + + /// Gets the git hash of the engine used by the Flutter framework in the repo. + String getEngineRevision() => getFlutterInformation()['engineRevision']! as String; + + /// Gets the git hash of the Flutter framework in the repo. + String getFlutterRevision() => getFlutterInformation()['flutterGitRevision']! as String; + + /// Gets the name of the current branch in the Flutter framework in the repo. + String getBranchName() => getFlutterInformation()['branchName']! as String; + + Map? _cachedFlutterInformation; + + /// Gets a Map of various kinds of information about the Flutter repo. + Map getFlutterInformation() { + if (_cachedFlutterInformation != null) { + return _cachedFlutterInformation!; + } + + String flutterVersionJson; + if (platform.environment['FLUTTER_VERSION'] != null) { + flutterVersionJson = platform.environment['FLUTTER_VERSION']!; + } else { + String flutterCommand; + if (platform.environment['FLUTTER_ROOT'] != null) { + flutterCommand = filesystem + .directory(platform.environment['FLUTTER_ROOT']) + .childDirectory('bin') + .childFile('flutter') + .absolute + .path; + } else { + flutterCommand = 'flutter'; + } + ProcessResult result; + try { + result = processManager.runSync([flutterCommand, '--version', '--machine'], stdoutEncoding: utf8); + } on ProcessException catch (e) { + throw DartdocException( + 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e'); + } + if (result.exitCode != 0) { + throw DartdocException('Unable to determine Flutter information, because of abnormal exit to flutter command.'); + } + flutterVersionJson = (result.stdout as String) + .replaceAll('Waiting for another flutter command to release the startup lock...', ''); + } + + final Map flutterVersion = json.decode(flutterVersionJson) as Map; + if (flutterVersion['flutterRoot'] == null || + flutterVersion['frameworkVersion'] == null || + flutterVersion['dartSdkVersion'] == null) { + throw DartdocException( + 'Flutter command output has unexpected format, unable to determine flutter root location.'); + } + + final Map info = {}; + final Directory flutterRoot = filesystem.directory(flutterVersion['flutterRoot']! as String); + info['flutterRoot'] = flutterRoot; + info['frameworkVersion'] = Version.parse(flutterVersion['frameworkVersion'] as String); + info['engineRevision'] = flutterVersion['engineRevision'] as String; + + final RegExpMatch? dartVersionRegex = RegExp(r'(?[\d.]+)(?:\s+\(build (?[-.\w]+)\))?') + .firstMatch(flutterVersion['dartSdkVersion'] as String); + if (dartVersionRegex == null) { + throw DartdocException( + 'Flutter command output has unexpected format, unable to parse dart SDK version ${flutterVersion['dartSdkVersion']}.'); + } + info['dartSdkVersion'] = + Version.parse(dartVersionRegex.namedGroup('detail') ?? dartVersionRegex.namedGroup('base')!); + + info['branchName'] = _getBranchName(); + info['flutterGitRevision'] = _getFlutterGitRevision(); + _cachedFlutterInformation = info; + + return info; + } + + // Get the name of the release branch. + // + // On LUCI builds, the git HEAD is detached, so first check for the env + // variable "LUCI_BRANCH"; if it is not set, fall back to calling git. + String _getBranchName() { + final String? luciBranch = platform.environment['LUCI_BRANCH']; + if (luciBranch != null && luciBranch.trim().isNotEmpty) { + return luciBranch.trim(); + } + final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain']); + if (gitResult.exitCode != 0) { + throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; + } + final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); + final RegExpMatch? gitBranchMatch = + gitBranchRegexp.firstMatch((gitResult.stdout as String).trim().split('\n').first); + return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first; + } + + // Get the git revision for the repo. + String _getFlutterGitRevision() { + const int kGitRevisionLength = 10; + + final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); + if (gitResult.exitCode != 0) { + throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; + } + final String gitRevision = (gitResult.stdout as String).trim(); + + return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision; + } +} diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart deleted file mode 100644 index 8bd8b39d73ac2..0000000000000 --- a/dev/tools/dartdoc.dart +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:args/args.dart'; -import 'package:intl/intl.dart'; -import 'package:meta/meta.dart'; -import 'package:path/path.dart' as path; -import 'package:platform/platform.dart'; -import 'package:process/process.dart'; - -import 'dartdoc_checker.dart'; - -const String kDocsRoot = 'dev/docs'; -const String kPublishRoot = '$kDocsRoot/doc'; - -const String kDummyPackageName = 'Flutter'; -const String kPlatformIntegrationPackageName = 'platform_integration'; - -/// This script expects to run with the cwd as the root of the flutter repo. It -/// will generate documentation for the packages in `//packages/` and write the -/// documentation to `//dev/docs/doc/api/`. -/// -/// This script also updates the index.html file so that it can be placed -/// at the root of api.flutter.dev. We are keeping the files inside of -/// api.flutter.dev/flutter for now, so we need to manipulate paths -/// a bit. See https://github.com/flutter/flutter/issues/3900 for more info. -/// -/// This will only work on UNIX systems, not Windows. It requires that 'git' be -/// in your path. It requires that 'flutter' has been run previously. It uses -/// the version of Dart downloaded by the 'flutter' tool in this repository and -/// will crash if that is absent. -Future main(List arguments) async { - final ArgParser argParser = _createArgsParser(); - final ArgResults args = argParser.parse(arguments); - if (args['help'] as bool) { - print ('Usage:'); - print (argParser.usage); - exit(0); - } - // If we're run from the `tools` dir, set the cwd to the repo root. - if (path.basename(Directory.current.path) == 'tools') { - Directory.current = Directory.current.parent.parent; - } - - final ProcessResult flutter = Process.runSync('flutter', []); - final File versionFile = File('version'); - if (flutter.exitCode != 0 || !versionFile.existsSync()) { - throw Exception('Failed to determine Flutter version.'); - } - final String version = versionFile.readAsStringSync(); - - // Create the pubspec.yaml file. - final StringBuffer buf = StringBuffer(); - buf.writeln('name: $kDummyPackageName'); - buf.writeln('homepage: https://flutter.dev'); - buf.writeln('version: 0.0.0'); - buf.writeln('environment:'); - buf.writeln(" sdk: '>=3.0.0-0 <4.0.0'"); - buf.writeln('dependencies:'); - for (final String package in findPackageNames()) { - buf.writeln(' $package:'); - buf.writeln(' sdk: flutter'); - } - buf.writeln(' $kPlatformIntegrationPackageName: 0.0.1'); - buf.writeln('dependency_overrides:'); - buf.writeln(' $kPlatformIntegrationPackageName:'); - buf.writeln(' path: $kPlatformIntegrationPackageName'); - File('$kDocsRoot/pubspec.yaml').writeAsStringSync(buf.toString()); - - // Create the library file. - final Directory libDir = Directory('$kDocsRoot/lib'); - libDir.createSync(); - - final StringBuffer contents = StringBuffer('library temp_doc;\n\n'); - for (final String libraryRef in libraryRefs()) { - contents.writeln("import 'package:$libraryRef';"); - } - File('$kDocsRoot/lib/temp_doc.dart').writeAsStringSync(contents.toString()); - - final String flutterRoot = Directory.current.path; - final Map pubEnvironment = { - 'FLUTTER_ROOT': flutterRoot, - }; - - // If there's a .pub-cache dir in the flutter root, use that. - final String pubCachePath = '$flutterRoot/.pub-cache'; - if (Directory(pubCachePath).existsSync()) { - pubEnvironment['PUB_CACHE'] = pubCachePath; - } - - final String dartExecutable = '$flutterRoot/bin/cache/dart-sdk/bin/dart'; - - // Run pub. - ProcessWrapper process = ProcessWrapper(await runPubProcess( - dartBinaryPath: dartExecutable, - arguments: ['get'], - workingDirectory: kDocsRoot, - environment: pubEnvironment, - )); - printStream(process.stdout, prefix: 'pub:stdout: '); - printStream(process.stderr, prefix: 'pub:stderr: '); - final int code = await process.done; - if (code != 0) { - exit(code); - } - - createFooter('$kDocsRoot/lib/', version); - copyAssets(); - createSearchMetadata('$kDocsRoot/lib/opensearch.xml', '$kDocsRoot/doc/opensearch.xml'); - cleanOutSnippets(); - - final List dartdocBaseArgs = [ - 'global', - 'run', - if (args['checked'] as bool) '--enable-asserts', - 'dartdoc', - ]; - - // Verify which version of snippets and dartdoc we're using. - final ProcessResult snippetsResult = Process.runSync( - dartExecutable, - [ - 'pub', - 'global', - 'list', - ], - workingDirectory: kDocsRoot, - environment: pubEnvironment, - stdoutEncoding: utf8, - ); - print(''); - final Iterable versionMatches = RegExp(r'^(?snippets|dartdoc) (?[^\s]+)', multiLine: true) - .allMatches(snippetsResult.stdout as String); - for (final RegExpMatch match in versionMatches) { - print('${match.namedGroup('name')} version: ${match.namedGroup('version')}'); - } - - print('flutter version: $version\n'); - - // Dartdoc warnings and errors in these packages are considered fatal. - // All packages owned by flutter should be in the list. - final List flutterPackages = [ - kDummyPackageName, - kPlatformIntegrationPackageName, - ...findPackageNames(), - // TODO(goderbauer): Figure out how to only include `dart:ui` of `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278. - // 'sky_engine', - ]; - - // Generate the documentation. - // We don't need to exclude flutter_tools in this list because it's not in the - // recursive dependencies of the package defined at dev/docs/pubspec.yaml - final List dartdocArgs = [ - ...dartdocBaseArgs, - '--allow-tools', - if (args['json'] as bool) '--json', - if (args['validate-links'] as bool) '--validate-links' else '--no-validate-links', - '--link-to-source-excludes', '../../bin/cache', - '--link-to-source-root', '../..', - '--link-to-source-uri-template', 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', - '--inject-html', - '--use-base-href', - '--header', 'styles.html', - '--header', 'analytics.html', - '--header', 'survey.html', - '--header', 'snippets.html', - '--header', 'opensearch.html', - '--footer-text', 'lib/footer.html', - '--allow-warnings-in-packages', flutterPackages.join(','), - '--exclude-packages', - [ - 'analyzer', - 'args', - 'barback', - 'csslib', - 'flutter_goldens', - 'flutter_goldens_client', - 'front_end', - 'fuchsia_remote_debug_protocol', - 'glob', - 'html', - 'http_multi_server', - 'io', - 'isolate', - 'js', - 'kernel', - 'logging', - 'mime', - 'mockito', - 'node_preamble', - 'plugin', - 'shelf', - 'shelf_packages_handler', - 'shelf_static', - 'shelf_web_socket', - 'utf', - 'watcher', - 'yaml', - ].join(','), - '--exclude', - [ - 'dart:io/network_policy.dart', // dart-lang/dartdoc#2437 - 'package:Flutter/temp_doc.dart', - 'package:http/browser_client.dart', - 'package:intl/intl_browser.dart', - 'package:matcher/mirror_matchers.dart', - 'package:quiver/io.dart', - 'package:quiver/mirrors.dart', - 'package:vm_service_client/vm_service_client.dart', - 'package:web_socket_channel/html.dart', - ].join(','), - '--favicon=favicon.ico', - '--package-order', 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver', - '--auto-include-dependencies', - ]; - - String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg; - print('Executing: (cd $kDocsRoot ; $dartExecutable ${dartdocArgs.map(quote).join(' ')})'); - - process = ProcessWrapper(await runPubProcess( - dartBinaryPath: dartExecutable, - arguments: dartdocArgs, - workingDirectory: kDocsRoot, - environment: pubEnvironment, - )); - printStream(process.stdout, prefix: args['json'] as bool ? '' : 'dartdoc:stdout: ', - filter: args['verbose'] as bool ? const [] : [ - RegExp(r'^Generating docs for library '), // unnecessary verbosity - ], - ); - printStream(process.stderr, prefix: args['json'] as bool ? '' : 'dartdoc:stderr: ', - filter: args['verbose'] as bool ? const [] : [ - RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control - ], - ); - final int exitCode = await process.done; - - if (exitCode != 0) { - exit(exitCode); - } - - sanityCheckDocs(); - checkForUnresolvedDirectives('$kPublishRoot/api'); - - createIndexAndCleanup(); -} - -ArgParser _createArgsParser() { - final ArgParser parser = ArgParser(); - parser.addFlag('help', abbr: 'h', negatable: false, - help: 'Show command help.'); - parser.addFlag('verbose', defaultsTo: true, - help: 'Whether to report all error messages (on) or attempt to ' - 'filter out some known false positives (off). Shut this off ' - 'locally if you want to address Flutter-specific issues.'); - parser.addFlag('checked', abbr: 'c', - help: 'Run dartdoc with asserts enabled.'); - parser.addFlag('json', - help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); - parser.addFlag('validate-links', - help: 'Display warnings for broken links generated by dartdoc (slow)'); - return parser; -} - -final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); - -/// Get the name of the release branch. -/// -/// On LUCI builds, the git HEAD is detached, so first check for the env -/// variable "LUCI_BRANCH"; if it is not set, fall back to calling git. -String getBranchName({ - @visibleForTesting - Platform platform = const LocalPlatform(), - @visibleForTesting - ProcessManager processManager = const LocalProcessManager(), -}) { - final String? luciBranch = platform.environment['LUCI_BRANCH']; - if (luciBranch != null && luciBranch.trim().isNotEmpty) { - return luciBranch.trim(); - } - final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain']); - if (gitResult.exitCode != 0) { - throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; - } - final RegExpMatch? gitBranchMatch = gitBranchRegexp.firstMatch( - (gitResult.stdout as String).trim().split('\n').first); - return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first; -} - -String gitRevision() { - const int kGitRevisionLength = 10; - - final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); - if (gitResult.exitCode != 0) { - throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; - } - final String gitRevision = (gitResult.stdout as String).trim(); - - return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision; -} - -void createFooter(String footerPath, String version) { - final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now()); - final String gitBranch = getBranchName(); - final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch'; - File('${footerPath}footer.html').writeAsStringSync(''); - File('$kPublishRoot/api/footer.js') - ..createSync(recursive: true) - ..writeAsStringSync(''' -(function() { - var span = document.querySelector('footer>span'); - if (span) { - span.innerText = 'Flutter $version • $timestamp • ${gitRevision()} $gitBranchOut'; - } - var sourceLink = document.querySelector('a.source-link'); - if (sourceLink) { - sourceLink.href = sourceLink.href.replace('/master/', '/${gitRevision()}/'); - } -})(); -'''); -} - -/// Generates an OpenSearch XML description that can be used to add a custom -/// search for Flutter API docs to the browser. Unfortunately, it has to know -/// the URL to which site to search, so we customize it here based upon the -/// branch name. -void createSearchMetadata(String templatePath, String metadataPath) { - final String template = File(templatePath).readAsStringSync(); - final String branch = getBranchName(); - final String metadata = template.replaceAll( - '{SITE_URL}', - branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/', - ); - Directory(path.dirname(metadataPath)).create(recursive: true); - File(metadataPath).writeAsStringSync(metadata); -} - -/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if -/// specified, for each source/destination file pair. -/// -/// Creates `destDir` if needed. -void copyDirectorySync(Directory srcDir, Directory destDir, [void Function(File srcFile, File destFile)? onFileCopied]) { - if (!srcDir.existsSync()) { - throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); - } - - if (!destDir.existsSync()) { - destDir.createSync(recursive: true); - } - - for (final FileSystemEntity entity in srcDir.listSync()) { - final String newPath = path.join(destDir.path, path.basename(entity.path)); - if (entity is File) { - final File newFile = File(newPath); - entity.copySync(newPath); - onFileCopied?.call(entity, newFile); - } else if (entity is Directory) { - copyDirectorySync(entity, Directory(newPath)); - } else { - throw Exception('${entity.path} is neither File nor Directory'); - } - } -} - -void copyAssets() { - final Directory assetsDir = Directory(path.join(kPublishRoot, 'assets')); - if (assetsDir.existsSync()) { - assetsDir.deleteSync(recursive: true); - } - copyDirectorySync( - Directory(path.join(kDocsRoot, 'assets')), - Directory(path.join(kPublishRoot, 'assets')), - (File src, File dest) => print('Copied ${src.path} to ${dest.path}')); -} - -/// Clean out any existing snippets so that we don't publish old files from -/// previous runs accidentally. -void cleanOutSnippets() { - final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets')); - if (snippetsDir.existsSync()) { - snippetsDir - ..deleteSync(recursive: true) - ..createSync(recursive: true); - } -} - -void _sanityCheckExample(String fileString, String regExpString) { - final File file = File(fileString); - if (file.existsSync()) { - final RegExp regExp = RegExp(regExpString, dotAll: true); - final String contents = file.readAsStringSync(); - if (!regExp.hasMatch(contents)) { - throw Exception("Missing example code matching '$regExpString' in ${file.path}."); - } - } else { - throw Exception( - "Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file."); - } -} - -/// Runs a sanity check by running a test. -void sanityCheckDocs([Platform platform = const LocalPlatform()]) { - final List canaries = [ - '$kPublishRoot/assets/overrides.css', - '$kPublishRoot/api/dart-io/File-class.html', - '$kPublishRoot/api/dart-ui/Canvas-class.html', - '$kPublishRoot/api/dart-ui/Canvas/drawRect.html', - '$kPublishRoot/api/flutter_driver/FlutterDriver/FlutterDriver.connectedTo.html', - '$kPublishRoot/api/flutter_test/WidgetTester/pumpWidget.html', - '$kPublishRoot/api/material/Material-class.html', - '$kPublishRoot/api/material/Tooltip-class.html', - '$kPublishRoot/api/widgets/Widget-class.html', - '$kPublishRoot/api/widgets/Listener-class.html', - ]; - for (final String canary in canaries) { - if (!File(canary).existsSync()) { - throw Exception('Missing "$canary", which probably means the documentation failed to build correctly.'); - } - } - // Make sure at least one example of each kind includes source code. - - // Check a "sample" example, any one will do. - _sanityCheckExample( - '$kPublishRoot/api/widgets/showGeneralDialog.html', - r'\s*\s*import 'package:flutter/material.dart';', - ); - - // Check a "snippet" example, any one will do. - _sanityCheckExample( - '$kPublishRoot/api/widgets/ModalRoute/barrierColor.html', - r'\s*.*Color\s+get\s+barrierColor.*', - ); - - // Check a "dartpad" example, any one will do, and check for the correct URL - // arguments. - // Just use "master" for any branch other than the LUCI_BRANCH. - final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim(); - final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master'; - final List argumentRegExps = [ - r'split=\d+', - r'run=true', - r'sample_id=widgets\.Listener\.\d+', - 'sample_channel=$expectedBranch', - 'channel=$expectedBranch', - ]; - for (final String argumentRegExp in argumentRegExps) { - _sanityCheckExample( - '$kPublishRoot/api/widgets/Listener-class.html', - r'\s*\s*<\/iframe>', - ); - } -} - -/// Creates a custom index.html because we try to maintain old -/// paths. Cleanup unused index.html files no longer needed. -void createIndexAndCleanup() { - print('\nCreating a custom index.html in $kPublishRoot/index.html'); - removeOldFlutterDocsDir(); - renameApiDir(); - copyIndexToRootOfDocs(); - addHtmlBaseToIndex(); - changePackageToSdkInTitlebar(); - putRedirectInOldIndexLocation(); - writeSnippetsIndexFile(); - print('\nDocs ready to go!'); -} - -void removeOldFlutterDocsDir() { - try { - Directory('$kPublishRoot/flutter').deleteSync(recursive: true); - } on FileSystemException { - // If the directory does not exist, that's OK. - } -} - -void renameApiDir() { - Directory('$kPublishRoot/api').renameSync('$kPublishRoot/flutter'); -} - -void copyIndexToRootOfDocs() { - File('$kPublishRoot/flutter/index.html').copySync('$kPublishRoot/index.html'); -} - -void changePackageToSdkInTitlebar() { - final File indexFile = File('$kPublishRoot/index.html'); - String indexContents = indexFile.readAsStringSync(); - indexContents = indexContents.replaceFirst( - '
  • Flutter package
  • ', - '
  • Flutter SDK
  • ', - ); - - indexFile.writeAsStringSync(indexContents); -} - -void addHtmlBaseToIndex() { - final File indexFile = File('$kPublishRoot/index.html'); - String indexContents = indexFile.readAsStringSync(); - indexContents = indexContents.replaceFirst( - '\n', - '\n \n', - ); - indexContents = indexContents.replaceAll( - 'href="Android/Android-library.html"', - 'href="/javadoc/"', - ); - indexContents = indexContents.replaceAll( - 'href="iOS/iOS-library.html"', - 'href="/objcdoc/"', - ); - - indexFile.writeAsStringSync(indexContents); -} - -void putRedirectInOldIndexLocation() { - const String metaTag = ''; - File('$kPublishRoot/flutter/index.html').writeAsStringSync(metaTag); -} - -void writeSnippetsIndexFile() { - final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets')); - if (snippetsDir.existsSync()) { - const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' '); - final Iterable files = snippetsDir - .listSync() - .whereType() - .where((File file) => path.extension(file.path) == '.json'); - // Combine all the metadata into a single JSON array. - final Iterable fileContents = files.map((File file) => file.readAsStringSync()); - final List metadataObjects = fileContents.map(json.decode).toList(); - final String jsonArray = jsonEncoder.convert(metadataObjects); - File('$kPublishRoot/snippets/index.json').writeAsStringSync(jsonArray); - } -} - -List findPackageNames() { - return findPackages().map((FileSystemEntity file) => path.basename(file.path)).toList(); -} - -/// Finds all packages in the Flutter SDK -List findPackages() { - return Directory('packages') - .listSync() - .where((FileSystemEntity entity) { - if (entity is! Directory) { - return false; - } - final File pubspec = File('${entity.path}/pubspec.yaml'); - if (!pubspec.existsSync()) { - print("Unexpected package '${entity.path}' found in packages directory"); - return false; - } - // TODO(ianh): Use a real YAML parser here - return !pubspec.readAsStringSync().contains('nodoc: true'); - }) - .cast() - .toList(); -} - -/// Returns import or on-disk paths for all libraries in the Flutter SDK. -Iterable libraryRefs() sync* { - for (final Directory dir in findPackages()) { - final String dirName = path.basename(dir.path); - for (final FileSystemEntity file in Directory('${dir.path}/lib').listSync()) { - if (file is File && file.path.endsWith('.dart')) { - yield '$dirName/${path.basename(file.path)}'; - } - } - } - - // Add a fake package for platform integration APIs. - yield '$kPlatformIntegrationPackageName/android.dart'; - yield '$kPlatformIntegrationPackageName/ios.dart'; -} - -void printStream(Stream> stream, { String prefix = '', List filter = const [] }) { - stream - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - if (!filter.any((Pattern pattern) => line.contains(pattern))) { - print('$prefix$line'.trim()); - } - }); -} - -Future runPubProcess({ - required String dartBinaryPath, - required List arguments, - String? workingDirectory, - Map? environment, - @visibleForTesting - ProcessManager processManager = const LocalProcessManager(), -}) { - return processManager.start( - [dartBinaryPath, 'pub', ...arguments], - workingDirectory: workingDirectory, - environment: environment, - ); -} diff --git a/dev/tools/java_and_objc_doc.dart b/dev/tools/java_and_objc_doc.dart deleted file mode 100644 index 260cdc7b6094f..0000000000000 --- a/dev/tools/java_and_objc_doc.dart +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:io'; -import 'dart:math'; - -import 'package:archive/archive.dart'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart' as path; - -const String kDocRoot = 'dev/docs/doc'; - -/// This script downloads an archive of Javadoc and objc doc for the engine from -/// the artifact store and extracts them to the location used for Dartdoc. -Future main(List args) async { - final String engineVersion = File('bin/internal/engine.version').readAsStringSync().trim(); - String engineRealm = File('bin/internal/engine.realm').readAsStringSync().trim(); - if (engineRealm.isNotEmpty) { - engineRealm = '$engineRealm/'; - } - - final String javadocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/android-javadoc.zip'; - generateDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html'); - - final String objcdocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip'; - generateDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html'); -} - -/// Fetches the zip archive at the specified url. -/// -/// Returns null if the archive fails to download after [maxTries] attempts. -Future fetchArchive(String url, int maxTries) async { - List? responseBytes; - for (int i = 0; i < maxTries; i++) { - final http.Response response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - responseBytes = response.bodyBytes; - break; - } - stderr.writeln('Failed attempt ${i+1} to fetch $url.'); - - // On failure print a short snipped from the body in case it's helpful. - final int bodyLength = min(1024, response.body.length); - stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}'); - sleep(const Duration(seconds: 1)); - } - return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); -} - -Future generateDocs(String url, String docName, String checkFile) async { - const int maxTries = 5; - final Archive? archive = await fetchArchive(url, maxTries); - if (archive == null) { - stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.'); - exit(1); - } - - final Directory output = Directory('$kDocRoot/$docName'); - print('Extracting $docName to ${output.path}'); - output.createSync(recursive: true); - - for (final ArchiveFile af in archive) { - if (!af.name.endsWith('/')) { - final File file = File('${output.path}/${af.name}'); - file.createSync(recursive: true); - file.writeAsBytesSync(af.content as List); - } - } - - /// If object then copy files to old location if the archive is using the new location. - final bool exists = Directory('$kDocRoot/$docName/objectc_docs').existsSync(); - if (exists) { - copyFolder(Directory('$kDocRoot/$docName/objectc_docs'), Directory('$kDocRoot/$docName/')); - } - - final File testFile = File('${output.path}/$checkFile'); - if (!testFile.existsSync()) { - print('Expected file ${testFile.path} not found'); - exit(1); - } - print('$docName ready to go!'); -} - -/// Copies the files in a directory recursively to a new location. -void copyFolder(Directory source, Directory destination) { - source.listSync() - .forEach((FileSystemEntity entity) { - if (entity is Directory) { - final Directory newDirectory = Directory(path.join(destination.absolute.path, path.basename(entity.path))); - newDirectory.createSync(); - copyFolder(entity.absolute, newDirectory); - } else if (entity is File) { - entity.copySync(path.join(destination.path, path.basename(entity.path))); - } - }); -} diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 82ad7215a6c85..fdf94b40dd17b 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: meta: 1.9.1 path: 1.8.3 process: 4.2.4 + pub_semver: 2.1.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,7 +46,6 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart new file mode 100644 index 0000000000000..a12edbbfdf428 --- /dev/null +++ b/dev/tools/test/create_api_docs_test.dart @@ -0,0 +1,195 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:platform/platform.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:test/test.dart'; + +import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; +import '../create_api_docs.dart' as apidocs; + +void main() { + test('getBranchName does not call git if env LUCI_BRANCH provided', () { + final Platform platform = FakePlatform( + environment: { + 'LUCI_BRANCH': branchName, + }, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + ], + ); + + expect( + apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH not provided', () { + final Platform platform = FakePlatform( + environment: {}, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + ], + ); + + expect( + apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH is empty', () { + final Platform platform = FakePlatform( + environment: { + 'LUCI_BRANCH': '', + }, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + ], + ); + + expect( + apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test("runPubProcess doesn't use the pub binary", () { + final Platform platform = FakePlatform( + environment: { + 'FLUTTER_ROOT': '/flutter', + }, + ); + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['/flutter/bin/dart', 'pub', '--one', '--two'], + ), + ], + ); + apidocs.FlutterInformation.instance = + apidocs.FlutterInformation(platform: platform, processManager: processManager); + + apidocs.runPubProcess( + arguments: ['--one', '--two'], + processManager: processManager, + ); + + expect(processManager, hasNoRemainingExpectations); + }); + + group('FlutterInformation', () { + late FakeProcessManager fakeProcessManager; + late FakePlatform fakePlatform; + late MemoryFileSystem memoryFileSystem; + late apidocs.FlutterInformation flutterInformation; + + void setUpWithEnvironment(Map environment) { + fakePlatform = FakePlatform(environment: environment); + flutterInformation = apidocs.FlutterInformation( + filesystem: memoryFileSystem, + processManager: fakeProcessManager, + platform: fakePlatform, + ); + apidocs.FlutterInformation.instance = flutterInformation; + } + + setUp(() { + fakeProcessManager = FakeProcessManager.empty(); + memoryFileSystem = MemoryFileSystem(); + setUpWithEnvironment({}); + }); + + test('calls out to flutter if FLUTTER_VERSION is not set', () async { + fakeProcessManager.addCommand( + const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Map info = flutterInformation.getFlutterInformation(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); + }); + test("doesn't call out to flutter if FLUTTER_VERSION is set", () async { + setUpWithEnvironment({ + 'FLUTTER_VERSION': testVersionInfo, + }); + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Map info = flutterInformation.getFlutterInformation(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); + }); + test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set', () async { + fakeProcessManager.addCommand( + const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Directory root = flutterInformation.getFlutterRoot(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(root.path, equals('/home/user/flutter')); + }); + test("getFlutterRoot doesn't call out to flutter if FLUTTER_ROOT is set", () async { + setUpWithEnvironment({'FLUTTER_ROOT': '/home/user/flutter'}); + final Directory root = flutterInformation.getFlutterRoot(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(root.path, equals('/home/user/flutter')); + }); + test('parses version properly', () async { + fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo; + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Map info = flutterInformation.getFlutterInformation(); + expect(info['frameworkVersion'], isNotNull); + expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); + expect(info['dartSdkVersion'], isNotNull); + expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev'))); + }); + }); +} + +const String branchName = 'stable'; +const String testVersionInfo = ''' +{ + "frameworkVersion": "2.5.0", + "channel": "$branchName", + "repositoryUrl": "git@github.com:flutter/flutter.git", + "frameworkRevision": "0000000000000000000000000000000000000000", + "frameworkCommitDate": "2021-07-28 13:03:40 -0700", + "engineRevision": "0000000000000000000000000000000000000001", + "dartSdkVersion": "2.14.0 (build 2.14.0-360.0.dev)", + "flutterRoot": "/home/user/flutter" +} +'''; diff --git a/dev/tools/test/dartdoc_test.dart b/dev/tools/test/dartdoc_test.dart deleted file mode 100644 index 5744650ee3fa8..0000000000000 --- a/dev/tools/test/dartdoc_test.dart +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:platform/platform.dart'; -import 'package:test/test.dart'; - -import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; -import '../dartdoc.dart' show getBranchName, runPubProcess; - -void main() { - const String branchName = 'stable'; - test('getBranchName does not call git if env LUCI_BRANCH provided', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': branchName, - }, - ); - - final ProcessManager processManager = FakeProcessManager.empty(); - - expect( - getBranchName( - platform: platform, - processManager: processManager, - ), - branchName, - ); - }); - - test('getBranchName calls git if env LUCI_BRANCH not provided', () { - final Platform platform = FakePlatform( - environment: {}, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - getBranchName( - platform: platform, - processManager: processManager, - ), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH is empty', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': '', - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - getBranchName( - platform: platform, - processManager: processManager, - ), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test("runPubProcess doesn't use the pub binary", () { - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['dart', 'pub', '--one', '--two'], - ), - ], - ); - - runPubProcess( - dartBinaryPath: 'dart', - arguments: ['--one', '--two'], - processManager: processManager, - ); - - expect(processManager, hasNoRemainingExpectations); - }); -} From 9d9427923f4b6a4afe7c64ec46ba8d4f333731ad Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Tue, 15 Aug 2023 17:56:09 -0500 Subject: [PATCH 0734/1547] Fix extent for null returning builder in GridView (#132511) Fixes https://github.com/flutter/flutter/issues/130685 This fixes an issue where a GridView/SliverGrid with a SliverChildBuilderDelegate would still reflect a max scroll extent of infinity after returning null from the builder. This change incorporates the same way we handle this case in SliverList: https://github.com/flutter/flutter/blob/6d87a23b3722e4fb2e2db993322d5be4adf04fb5/packages/flutter/lib/src/rendering/sliver_list.dart#L305-L307 --- .../lib/src/rendering/sliver_grid.dart | 18 +++++---- .../flutter/test/widgets/grid_view_test.dart | 37 +++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/rendering/sliver_grid.dart b/packages/flutter/lib/src/rendering/sliver_grid.dart index d09aae2aa4136..22fddd2178293 100644 --- a/packages/flutter/lib/src/rendering/sliver_grid.dart +++ b/packages/flutter/lib/src/rendering/sliver_grid.dart @@ -631,6 +631,7 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor { final double leadingScrollOffset = firstChildGridGeometry.scrollOffset; double trailingScrollOffset = firstChildGridGeometry.trailingScrollOffset; RenderBox? trailingChildWithLayout; + bool reachedEnd = false; for (int index = indexOf(firstChild!) - 1; index >= firstIndex; --index) { final SliverGridGeometry gridGeometry = layout.getGeometryForChildIndex(index); @@ -660,6 +661,7 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor { if (child == null || indexOf(child) != index) { child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout); if (child == null) { + reachedEnd = true; // We have run out of children. break; } @@ -680,13 +682,15 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor { assert(indexOf(firstChild!) == firstIndex); assert(targetLastIndex == null || lastIndex <= targetLastIndex); - final double estimatedTotalExtent = childManager.estimateMaxScrollOffset( - constraints, - firstIndex: firstIndex, - lastIndex: lastIndex, - leadingScrollOffset: leadingScrollOffset, - trailingScrollOffset: trailingScrollOffset, - ); + final double estimatedTotalExtent = reachedEnd + ? trailingScrollOffset + : childManager.estimateMaxScrollOffset( + constraints, + firstIndex: firstIndex, + lastIndex: lastIndex, + leadingScrollOffset: leadingScrollOffset, + trailingScrollOffset: trailingScrollOffset, + ); final double paintExtent = calculatePaintOffset( constraints, from: math.min(constraints.scrollOffset, leadingScrollOffset), diff --git a/packages/flutter/test/widgets/grid_view_test.dart b/packages/flutter/test/widgets/grid_view_test.dart index 90b9a945eb1fa..f1abdebe6fc13 100644 --- a/packages/flutter/test/widgets/grid_view_test.dart +++ b/packages/flutter/test/widgets/grid_view_test.dart @@ -856,6 +856,43 @@ void main() { maxCrossAxisExtent: maxCrossAxisExtent, ), ), throwsAssertionError); + }); + + testWidgets('SliverGrid sets correct extent for null returning builder delegate', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/130685 + final ScrollController controller = ScrollController(); + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: GridView.builder( + controller: controller, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + ), + itemBuilder: (BuildContext context, int index) { + if (index == 12) { + return null; + } + return Container( + height: 100, + width: 100, + color: const Color(0xFFFF8A80), + alignment: Alignment.center, + child: Text('item ${index+1}'), + ); + }, + ), + )); + await tester.pumpAndSettle(); + expect(controller.position.maxScrollExtent, double.infinity); + expect(controller.position.pixels, 0.0); + await tester.fling(find.byType(GridView), const Offset(0.0, -1300.0), 100.0); + await tester.pumpAndSettle(); + // The actual extent of the children is 472.0. This should be reflected when + // the builder returns null (meaning we have reached the end). + expect(controller.position.maxScrollExtent, 472.0); + expect(controller.position.pixels, 472.0); }); } From 6971dcb7056f573fc10482d7e3d88359fc18c361 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 15 Aug 2023 16:06:58 -0700 Subject: [PATCH 0735/1547] Explain the keyboard manager protocol (#132533) Fixes https://github.com/flutter/flutter/issues/132433 --- .../lib/src/services/hardware_keyboard.dart | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/services/hardware_keyboard.dart b/packages/flutter/lib/src/services/hardware_keyboard.dart index 9f12f723c6d38..7c2af2bd843b6 100644 --- a/packages/flutter/lib/src/services/hardware_keyboard.dart +++ b/packages/flutter/lib/src/services/hardware_keyboard.dart @@ -788,14 +788,42 @@ typedef KeyMessageHandler = bool Function(KeyMessage message); /// and [RawKeyboard] for recording keeping, and then dispatches the [KeyMessage] /// to [keyMessageHandler], the global message handler. /// -/// [KeyEventManager] also resolves cross-platform compatibility of keyboard -/// implementations. Legacy platforms might have not implemented the new key -/// data API and only send raw key data on each key message. [KeyEventManager] -/// recognize platform types as [KeyDataTransitMode] and dispatches events in -/// different ways accordingly. -/// /// [KeyEventManager] is typically created, owned, and invoked by /// [ServicesBinding]. +/// +/// ## On embedder implementation +/// +/// Currently, Flutter has two sets of key event APIs running in parallel. +/// +/// * The legacy "raw key event" route receives messages from the +/// "flutter/keyevent" message channel ([SystemChannels.keyEvent]) and +/// dispatches [RawKeyEvent] to [RawKeyboard] and [Focus.onKey] as well as +/// similar methods. +/// * The newer "hardware key event" route receives messages from the +/// "flutter/keydata" message channel (embedder API +/// `FlutterEngineSendKeyEvent`) and dispatches [KeyEvent] to +/// [HardwareKeyboard] and some methods such as [Focus.onKeyEvent]. +/// +/// [KeyEventManager] resolves cross-platform compatibility of keyboard +/// implementations, since legacy platforms might have not implemented the new +/// key data API and only send raw key data on each key message. +/// [KeyEventManager] recognizes the platform support by detecting whether a +/// message comes from platform channel "flutter/keyevent" before one from +/// "flutter/keydata", or vice versa, at the beginning of the app. +/// +/// * If a "flutter/keyevent" message is received first, then this platform is +/// considered a legacy platform. The raw key event is transformed into a +/// hardware key event at best effort. No messages from "flutter/keydata" are +/// expected. +/// * If a "flutter/keydata" message is received first, then this platform is +/// considered a newer platform. The hardware key events are stored, and +/// dispatched only when a raw key message is received. +/// +/// Therefore, to correctly implement a platform that supports +/// `FlutterEngineSendKeyEvent`, the platform must ensure that +/// `FlutterEngineSendKeyEvent` is called before sending a message to +/// "flutter/keyevent" at the beginning of the app, and every physical key event +/// is ended with a "flutter/keyevent" message. class KeyEventManager { /// Create an instance. /// From 23315f1b574e322bf8f5c25e879087cc91c43020 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 16 Aug 2023 03:44:06 +0300 Subject: [PATCH 0736/1547] [Reland] #131609 (#132555) This relands https://github.com/flutter/flutter/pull/131609 --- fixes [`PopupMenuItem` adds redundant padding when using `ListItem`](https://github.com/flutter/flutter/issues/128553) --- .../gen_defaults/lib/popup_menu_template.dart | 4 + .../flutter/lib/src/material/popup_menu.dart | 38 ++-- .../test/material/popup_menu_test.dart | 166 ++++++++++++++++++ 3 files changed, 197 insertions(+), 11 deletions(-) diff --git a/dev/tools/gen_defaults/lib/popup_menu_template.dart b/dev/tools/gen_defaults/lib/popup_menu_template.dart index f11b89c9500e9..bed11d0b8b09a 100644 --- a/dev/tools/gen_defaults/lib/popup_menu_template.dart +++ b/dev/tools/gen_defaults/lib/popup_menu_template.dart @@ -42,5 +42,9 @@ class _${blockName}DefaultsM3 extends PopupMenuThemeData { @override ShapeBorder? get shape => ${shape("md.comp.menu.container")}; + + // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs + // Update this when the token is available. + static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); }'''; } diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index ef8f4367c6b43..7a3f7a5249bff 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -14,6 +14,7 @@ import 'icon_button.dart'; import 'icons.dart'; import 'ink_well.dart'; import 'list_tile.dart'; +import 'list_tile_theme.dart'; import 'material.dart'; import 'material_localizations.dart'; import 'material_state.dart'; @@ -32,7 +33,6 @@ import 'tooltip.dart'; const Duration _kMenuDuration = Duration(milliseconds: 300); const double _kMenuCloseIntervalEnd = 2.0 / 3.0; -const double _kMenuHorizontalPadding = 16.0; const double _kMenuDividerHeight = 16.0; const double _kMenuMaxWidth = 5.0 * _kMenuWidthStep; const double _kMenuMinWidth = 2.0 * _kMenuWidthStep; @@ -255,7 +255,11 @@ class PopupMenuItem extends PopupMenuEntry { /// If a [height] greater than the height of the sum of the padding and [child] /// is provided, then the padding's effect will not be visible. /// - /// When null, the horizontal padding defaults to 16.0 on both sides. + /// If this is null and [ThemeData.useMaterial3] is true, the horizontal padding + /// defaults to 12.0 on both sides. + /// + /// If this is null and [ThemeData.useMaterial3] is false, the horizontal padding + /// defaults to 16.0 on both sides. final EdgeInsets? padding; /// The text style of the popup menu item. @@ -372,7 +376,7 @@ class PopupMenuItemState> extends State { child: Container( alignment: AlignmentDirectional.centerStart, constraints: BoxConstraints(minHeight: widget.height), - padding: widget.padding ?? const EdgeInsets.symmetric(horizontal: _kMenuHorizontalPadding), + padding: widget.padding ?? (theme.useMaterial3 ? _PopupMenuDefaultsM3.menuHorizontalPadding : _PopupMenuDefaultsM2.menuHorizontalPadding), child: buildChild(), ), ); @@ -393,7 +397,10 @@ class PopupMenuItemState> extends State { onTap: widget.enabled ? handleTap : null, canRequestFocus: widget.enabled, mouseCursor: _EffectiveMouseCursor(widget.mouseCursor, popupMenuTheme.mouseCursor), - child: item, + child: ListTileTheme.merge( + contentPadding: EdgeInsets.zero, + child: item, + ), ), ), ); @@ -540,14 +547,17 @@ class _CheckedPopupMenuItemState extends PopupMenuItemState _textTheme.subtitle1; + + static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 16.0); } // BEGIN GENERATED TOKEN PROPERTIES - PopupMenu @@ -1465,5 +1477,9 @@ class _PopupMenuDefaultsM3 extends PopupMenuThemeData { @override ShapeBorder? get shape => const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))); + + // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs + // Update this when the token is available. + static EdgeInsets menuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 12.0); } // END GENERATED TOKEN PROPERTIES - PopupMenu diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index f26ed5a03adc7..60c576797dcd8 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -1553,6 +1553,82 @@ void main() { ); }); + testWidgets('Material3 - PopupMenuItem default padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + value: '0', + enabled: false, + child: Text('Item 0'), + ), + const PopupMenuItem( + value: '1', + child: Text('Item 1'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + expect(tester.widget(find.widgetWithText(Container, 'Item 0')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); + expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); + }); + + testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + value: '0', + enabled: false, + child: Text('Item 0'), + ), + const PopupMenuItem( + value: '1', + child: Text('Item 1'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + expect(tester.widget(find.widgetWithText(Container, 'Item 0')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); + expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); + }); + testWidgets('PopupMenuItem custom padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -3415,6 +3491,96 @@ void main() { labelTextStyle.resolve({MaterialState.selected}) ); }); + + testWidgets('CheckedPopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const CheckedPopupMenuItem( + value: '0', + child: Text('Item 0'), + ), + const CheckedPopupMenuItem( + value: '1', + checked: true, + child: Text('Item 1'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + SafeArea getItemSafeArea(String label) { + return tester.widget(find.ancestor( + of: find.text(label), + matching: find.byType(SafeArea), + )); + } + + expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); + expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); + }); + + testWidgets('PopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + const PopupMenuItem( + value: '0', + enabled: false, + child: ListTile(title: Text('Item 0')), + ), + const PopupMenuItem( + value: '1', + child: ListTile(title: Text('Item 1')), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + SafeArea getItemSafeArea(String label) { + return tester.widget(find.ancestor( + of: find.text(label), + matching: find.byType(SafeArea), + )); + } + + expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); + expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); + }); } class TestApp extends StatelessWidget { From 0dd73932787f50db699a84c50106fb56cf828bf3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 20:45:54 -0400 Subject: [PATCH 0737/1547] Roll Flutter Engine from 22f03ffdc290 to a9da7212eacf (4 revisions) (#132608) https://github.com/flutter/engine/compare/22f03ffdc290...a9da7212eacf 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from c7c9e85a8657 to b07a6964a1cf (2 revisions) (flutter/engine#44733) 2023-08-15 jonahwilliams@google.com [Impeller] Make porter duff blended atlas calls faster. (flutter/engine#44059) 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from 4beb6fd05f4f to c7c9e85a8657 (7 revisions) (flutter/engine#44729) 2023-08-15 skia-flutter-autoroll@skia.org Roll Dart SDK from 19c87486f0a9 to b36934aae968 (1 revision) (flutter/engine#44728) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ac11dcac51b35..2ea4205b17c62 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -22f03ffdc290081f6a0a1ed11ba19fd24ad83109 +a9da7212eacf1bf47d12993f6cc812cffbbad689 From 375538873dbeda3c71c10932cc403370cb7155f6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 21:39:27 -0400 Subject: [PATCH 0738/1547] Roll Flutter Engine from a9da7212eacf to 7409ce4ba0a8 (5 revisions) (#132609) https://github.com/flutter/engine/compare/a9da7212eacf...7409ce4ba0a8 2023-08-16 amirpanahandeh@yahoo.com Add more tests for CompositionAwareMixin (flutter/engine#44717) 2023-08-15 john@johnmccutchan.com Fix clang_tidy lints (flutter/engine#44740) 2023-08-15 skia-flutter-autoroll@skia.org Roll Skia from b07a6964a1cf to 9fc1c628456a (5 revisions) (flutter/engine#44737) 2023-08-15 godofredoc@google.com Add SLSA L1 badge (flutter/engine#44731) 2023-08-15 john@johnmccutchan.com Add support for SurfaceTexture based external textures on Android under Impeller/GLES. (flutter/engine#44734) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2ea4205b17c62..71fc835ed2656 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a9da7212eacf1bf47d12993f6cc812cffbbad689 +7409ce4ba0a8f18c0c3d7081a39d9b41c0b6ce8b From 909400dc4d031c9d0a92df93d360e335073da928 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 15 Aug 2023 19:47:26 -0700 Subject: [PATCH 0739/1547] Revert "Reorganize and clarify API doc generator" (#132613) Reverts flutter/flutter#132353 Educated guess that this is causing the docs failures: https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8772644466113801713/+/u/Docs/Deploy_docs/Firebase_deploy/stdout --- dev/bots/docs.sh | 200 ++-- dev/docs/dashing_postprocess.dart | 29 + dev/tools/create_api_docs.dart | 1095 ---------------------- dev/tools/dartdoc.dart | 606 ++++++++++++ dev/tools/java_and_objc_doc.dart | 97 ++ dev/tools/pubspec.yaml | 2 +- dev/tools/test/create_api_docs_test.dart | 195 ---- dev/tools/test/dartdoc_test.dart | 98 ++ 8 files changed, 938 insertions(+), 1384 deletions(-) create mode 100644 dev/docs/dashing_postprocess.dart delete mode 100644 dev/tools/create_api_docs.dart create mode 100644 dev/tools/dartdoc.dart create mode 100644 dev/tools/java_and_objc_doc.dart delete mode 100644 dev/tools/test/create_api_docs_test.dart create mode 100644 dev/tools/test/dartdoc_test.dart diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh index 64cd279c494f1..6a0cec83c97d8 100755 --- a/dev/bots/docs.sh +++ b/dev/bots/docs.sh @@ -16,13 +16,102 @@ function script_location() { cd -P "$(dirname "$script_location")" >/dev/null && pwd } +function generate_docs() { + # Install and activate dartdoc. + # When updating to a new dartdoc version, please also update + # `dartdoc_options.yaml` to include newly introduced error and warning types. + "$DART" pub global activate dartdoc 6.3.0 + + # Install and activate the snippets tool, which resides in the + # assets-for-api-docs repo: + # https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets + "$DART" pub global activate snippets 0.3.1 + + # This script generates a unified doc set, and creates + # a custom index.html, placing everything into dev/docs/doc. + (cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get) + (cd "$FLUTTER_ROOT/dev/tools" && "$DART" pub get) + (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/dartdoc.dart") + (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/java_and_objc_doc.dart") +} + +# Zip up the docs so people can download them for offline usage. +function create_offline_zip() { + # Must be run from "$FLUTTER_ROOT/dev/docs" + echo "$(date): Zipping Flutter offline docs archive." + rm -rf flutter.docs.zip doc/offline + (cd ./doc; zip -r -9 -q ../flutter.docs.zip .) +} + +# Generate the docset for Flutter docs for use with Dash, Zeal, and Velocity. +function create_docset() { + # Must be run from "$FLUTTER_ROOT/dev/docs" + # Must have dashing installed: go get -u github.com/technosophos/dashing + # Dashing produces a LOT of log output (~30MB), so we redirect it, and just + # show the end of it if there was a problem. + echo "$(date): Building Flutter docset." + rm -rf flutter.docset + # If dashing gets stuck, Cirrus will time out the build after an hour, and we + # never get to see the logs. Thus, we run it in the background and tail the logs + # while we wait for it to complete. + dashing_log=/tmp/dashing.log + dashing build --source ./doc --config ./dashing.json > $dashing_log 2>&1 & + dashing_pid=$! + wait $dashing_pid && \ + cp ./doc/flutter/static-assets/favicon.png ./flutter.docset/icon.png && \ + "$DART" --disable-dart-dev --enable-asserts ./dashing_postprocess.dart && \ + tar cf flutter.docset.tar.gz --use-compress-program="gzip --best" flutter.docset + if [[ $? -ne 0 ]]; then + >&2 echo "Dashing docset generation failed" + tail -200 $dashing_log + exit 1 + fi +} + +function deploy_docs() { + case "$LUCI_BRANCH" in + master) + echo "$(date): Updating $LUCI_BRANCH docs: https://master-api.flutter.dev/" + # Disable search indexing on the master staging site so searches get only + # the stable site. + echo -e "User-agent: *\nDisallow: /" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt" + ;; + stable) + echo "$(date): Updating $LUCI_BRANCH docs: https://api.flutter.dev/" + # Enable search indexing on the master staging site so searches get only + # the stable site. + echo -e "# All robots welcome!" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt" + ;; + *) + >&2 echo "Docs deployment cannot be run on the $LUCI_BRANCH branch." + exit 0 + esac +} + +# Move the offline archives into place, after all the processing of the doc +# directory is done. This avoids the tools recursively processing the archives +# as part of their process. +function move_offline_into_place() { + # Must be run from "$FLUTTER_ROOT/dev/docs" + echo "$(date): Moving offline data into place." + mkdir -p doc/offline + mv flutter.docs.zip doc/offline/flutter.docs.zip + du -sh doc/offline/flutter.docs.zip + if [[ "$LUCI_BRANCH" == "stable" ]]; then + echo -e "\n ${FLUTTER_VERSION_STRING}\n https://api.flutter.dev/offline/flutter.docset.tar.gz\n" > doc/offline/flutter.xml + else + echo -e "\n ${FLUTTER_VERSION_STRING}\n https://master-api.flutter.dev/offline/flutter.docset.tar.gz\n" > doc/offline/flutter.xml + fi + mv flutter.docset.tar.gz doc/offline/flutter.docset.tar.gz + du -sh doc/offline/flutter.docset.tar.gz +} + # So that users can run this script from anywhere and it will work as expected. SCRIPT_LOCATION="$(script_location)" # Sets the Flutter root to be "$(script_location)/../..": This script assumes # that it resides two directory levels down from the root, so if that changes, # then this line will need to as well. FLUTTER_ROOT="$(dirname "$(dirname "$SCRIPT_LOCATION")")" -export FLUTTER_ROOT echo "$(date): Running docs.sh" @@ -35,106 +124,31 @@ FLUTTER_BIN="$FLUTTER_ROOT/bin" DART_BIN="$FLUTTER_ROOT/bin/cache/dart-sdk/bin" FLUTTER="$FLUTTER_BIN/flutter" DART="$DART_BIN/dart" -PATH="$FLUTTER_BIN:$DART_BIN:$PATH" +export PATH="$FLUTTER_BIN:$DART_BIN:$PATH" -# Make sure dart is installed by invoking Flutter to download it if it is missing. -# Also make sure the flutter command is ready to run before capturing output from -# it: if it has to rebuild itself or something, it'll spoil our JSON output. -"$FLUTTER" > /dev/null 2>&1 -FLUTTER_VERSION="$("$FLUTTER" --version --machine)" +# Make sure dart is installed by invoking Flutter to download it. +# This also creates the 'version' file. +FLUTTER_VERSION=$("$FLUTTER" --version --machine) export FLUTTER_VERSION +FLUTTER_VERSION_STRING=$(cat "$FLUTTER_ROOT/version") # If the pub cache directory exists in the root, then use that. FLUTTER_PUB_CACHE="$FLUTTER_ROOT/.pub-cache" if [[ -d "$FLUTTER_PUB_CACHE" ]]; then # This has to be exported, because pub interprets setting it to the empty # string in the same way as setting it to ".". - PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}" - export PUB_CACHE + export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}" fi -OUTPUT_DIR=$(mktemp -d /tmp/dartdoc.XXXXX) -DOC_DIR="$OUTPUT_DIR/doc" - -function usage() { - echo "Usage: $(basename "${BASH_SOURCE[0]}") [--keep-temp] [--output ]" - echo "" - echo " --keep-temp Do not delete the temporary output directory created while generating docs." - echo " Normally the script deletes the temporary directory after generating the" - echo " output ZIP file." - echo " --output specifies where the output ZIP file containing the documentation data" - echo " will be written." - echo "" -} - -function parse_args() { - local arg - local args=() - KEEP_TEMP=0 - DESTINATION="$FLUTTER_ROOT/dev/docs/api_docs.zip" - while (( "$#" )); do - case "$1" in - --help) - usage - exit 0 - ;; - --keep-temp) - KEEP_TEMP=1 - ;; - --output) - DESTINATION="$2" - shift - ;; - *) - args=("${args[@]}" "$1") - ;; - esac - shift - done - if [[ ${#args[@]} != 0 ]]; then - >&2 echo "ERROR: Unknown arguments: ${args[@]}" - usage - exit 1 - fi -} - -function generate_docs() { - # Install and activate dartdoc. - # When updating to a new dartdoc version, please also update - # `dartdoc_options.yaml` to include newly introduced error and warning types. - "$DART" pub global activate dartdoc 6.3.0 - - # Install and activate the snippets tool, which resides in the - # assets-for-api-docs repo: - # https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets - "$DART" pub global activate snippets 0.4.0 - - # This script generates a unified doc set, and creates - # a custom index.html, placing everything into DOC_DIR. - - # Make sure that create_api_docs.dart has all the dependencies it needs. - (cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get) - (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/create_api_docs.dart" --output-dir="$DOC_DIR") -} - -function main() { - echo "Writing docs build temporary output to $DOC_DIR" - mkdir -p "$DOC_DIR" - generate_docs - # If the destination isn't an absolute path, make it into one. - if ! [[ "$DESTINATION" =~ ^/ ]]; then - DESTINATION="$PWD/$DESTINATION" - fi - # Zip up doc directory and write the output to the destination. - (cd "$OUTPUT_DIR"; zip -r -9 -q "$DESTINATION" ./doc) - if [[ $KEEP_TMP == 1 ]]; then - echo "Temporary document generation output left in $OUTPUT_DIR" - else - echo "Removing Temporary document generation output from $OUTPUT_DIR" - rm -rf "$OUTPUT_DIR" - fi - echo "Wrote docs ZIP file to $DESTINATION" -} +generate_docs +# Skip publishing docs for PRs and release candidate branches +if [[ -n "$LUCI_CI" && -z "$LUCI_PR" ]]; then + (cd "$FLUTTER_ROOT/dev/docs"; create_offline_zip) + (cd "$FLUTTER_ROOT/dev/docs"; create_docset) + (cd "$FLUTTER_ROOT/dev/docs"; move_offline_into_place) + deploy_docs +fi -parse_args "$@" -main +# Zip docs +cd "$FLUTTER_ROOT/dev/docs" +zip -r api_docs.zip doc diff --git a/dev/docs/dashing_postprocess.dart b/dev/docs/dashing_postprocess.dart new file mode 100644 index 0000000000000..9f186e4f2c315 --- /dev/null +++ b/dev/docs/dashing_postprocess.dart @@ -0,0 +1,29 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +/// This changes the DocSetPlatformFamily key to be "dartlang" instead of the +/// name of the package (usually "flutter"). +/// +/// This is so that the IntelliJ plugin for Dash will be able to go directly to +/// the docs for a symbol from a keystroke. Without this, flutter isn't part +/// of the list of package names it searches. After this, it finds the flutter +/// docs because they're declared here to be part of the "dartlang" family of +/// docs. +/// +/// Dashing doesn't have a way to configure this, so we modify the Info.plist +/// directly to make the change. +void main(List args) { + final File infoPlist = File('flutter.docset/Contents/Info.plist'); + String contents = infoPlist.readAsStringSync(); + + // Since I didn't want to add the XML package as a dependency just for this, + // I just used a regular expression to make this simple change. + final RegExp findRe = RegExp(r'(\s*DocSetPlatformFamily\s*)[^<]+()', multiLine: true); + contents = contents.replaceAllMapped(findRe, (Match match) { + return '${match.group(1)}dartlang${match.group(2)}'; + }); + infoPlist.writeAsStringSync(contents); +} diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart deleted file mode 100644 index 924e34a34e826..0000000000000 --- a/dev/tools/create_api_docs.dart +++ /dev/null @@ -1,1095 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; -import 'dart:math' as math; - -import 'package:archive/archive_io.dart'; -import 'package:args/args.dart'; -import 'package:file/file.dart'; -import 'package:file/local.dart'; -import 'package:http/http.dart' as http; -import 'package:intl/intl.dart'; -import 'package:meta/meta.dart'; -import 'package:path/path.dart' as path; -import 'package:platform/platform.dart'; -import 'package:process/process.dart'; -import 'package:pub_semver/pub_semver.dart'; - -import 'dartdoc_checker.dart'; -import 'examples_smoke_test.dart'; - -FileSystem filesystem = const LocalFileSystem(); - -const String kDummyPackageName = 'Flutter'; -const String kPlatformIntegrationPackageName = 'platform_integration'; - -/// This script will generate documentation for the packages in `packages/` and -/// write the documentation to the output directory specified on the command -/// line. -/// -/// This script also updates the index.html file so that it can be placed at the -/// root of api.flutter.dev. The files are kept inside of -/// api.flutter.dev/flutter, so we need to manipulate paths a bit. See -/// https://github.com/flutter/flutter/issues/3900 for more info. -/// -/// This will only work on UNIX systems, not Windows. It requires that 'git', -/// 'zip', and 'tar' be in the PATH. It requires that 'flutter' has been run -/// previously. It uses the version of Dart downloaded by the 'flutter' tool in -/// this repository and will fail if that is absent. -Future main(List arguments) async { - // The place to find customization files and configuration files for docs - // generation. - final Directory docsRoot = filesystem - .directory(FlutterInformation.instance.getFlutterRoot().childDirectory('dev').childDirectory('docs')) - .absolute; - final ArgParser argParser = _createArgsParser( - publishDefault: docsRoot.childDirectory('doc').path, - ); - final ArgResults args = argParser.parse(arguments); - if (args['help'] as bool) { - print('Usage:'); - print(argParser.usage); - exit(0); - } - - final Directory publishRoot = filesystem.directory(args['output-dir']! as String); - final Directory packageRoot = publishRoot.parent; - if (!filesystem.directory(packageRoot).existsSync()) { - filesystem.directory(packageRoot).createSync(recursive: true); - } - - if (!filesystem.directory(publishRoot).existsSync()) { - filesystem.directory(publishRoot).createSync(recursive: true); - } - - final Configurator configurator = Configurator( - publishRoot: publishRoot, - packageRoot: packageRoot, - docsRoot: docsRoot, - ); - configurator.generateConfiguration(); - - final PlatformDocGenerator platformGenerator = PlatformDocGenerator(outputDir: publishRoot); - platformGenerator.generatePlatformDocs(); - - final DartdocGenerator dartdocGenerator = DartdocGenerator( - publishRoot: publishRoot, - packageRoot: packageRoot, - docsRoot: docsRoot, - useJson: args['json'] as bool? ?? true, - validateLinks: args['validate-links']! as bool, - verbose: args['verbose'] as bool? ?? false, - ); - - await dartdocGenerator.generateDartdoc(); - await configurator.generateOfflineAssetsIfNeeded(); -} - -ArgParser _createArgsParser({required String publishDefault}) { - final ArgParser parser = ArgParser(); - parser.addFlag('help', abbr: 'h', negatable: false, help: 'Show command help.'); - parser.addFlag('verbose', - defaultsTo: true, - help: 'Whether to report all error messages (on) or attempt to ' - 'filter out some known false positives (off). Shut this off ' - 'locally if you want to address Flutter-specific issues.'); - parser.addFlag('json', help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); - parser.addFlag('validate-links', help: 'Display warnings for broken links generated by dartdoc (slow)'); - parser.addOption('output-dir', defaultsTo: publishDefault, help: 'Sets the output directory for the documentation.'); - return parser; -} - -/// A class used to configure the staging area for building the docs in. -/// -/// The [generateConfiguration] function generates a dummy package with a -/// pubspec. It copies any assets and customization files from the framework -/// repo. It creates a metadata file for searches. -/// -/// Once the docs have been generated, [generateOfflineAssetsIfNeeded] will -/// create offline assets like Dash/Zeal docsets and an offline ZIP file of the -/// site if the build is a CI build that is not a presubmit build. -class Configurator { - Configurator({ - required this.docsRoot, - required this.publishRoot, - required this.packageRoot, - this.filesystem = const LocalFileSystem(), - }); - - /// The root of the directory in the Flutter repo where configuration data is - /// stored. - final Directory docsRoot; - - /// The root of the output area for the dartdoc docs. - /// - /// Typically this is a "doc" subdirectory under the [packageRoot]. - final Directory publishRoot; - - /// The root of the staging area for creating docs. - final Directory packageRoot; - - /// The [FileSystem] object used to create [File] and [Directory] objects. - final FileSystem filesystem; - - void generateConfiguration() { - final Version version = FlutterInformation.instance.getFlutterVersion(); - _createDummyPubspec(); - _createDummyLibrary(); - _createPageFooter(packageRoot, version); - _copyCustomizations(); - _createSearchMetadata( - docsRoot.childDirectory('lib').childFile('opensearch.xml'), publishRoot.childFile('opensearch.xml')); - } - - Future generateOfflineAssetsIfNeeded() async { - // Only create the offline docs if we're running in a non-presubmit build: - // it takes too long otherwise. - if (platform.environment.containsKey('LUCI_CI') && (platform.environment['LUCI_PR'] ?? '').isEmpty) { - _createOfflineZipFile(); - await _createDocset(); - _moveOfflineIntoPlace(); - _createRobotsTxt(); - } - } - - /// Returns import or on-disk paths for all libraries in the Flutter SDK. - Iterable _libraryRefs() sync* { - for (final Directory dir in findPackages()) { - final String dirName = dir.basename; - for (final FileSystemEntity file in dir.childDirectory('lib').listSync()) { - if (file is File && file.path.endsWith('.dart')) { - yield '$dirName/${file.basename}'; - } - } - } - - // Add a fake package for platform integration APIs. - yield '$kPlatformIntegrationPackageName/android.dart'; - yield '$kPlatformIntegrationPackageName/ios.dart'; - } - - void _createDummyPubspec() { - // Create the pubspec.yaml file. - final List pubspec = [ - 'name: $kDummyPackageName', - 'homepage: https://flutter.dev', - 'version: 0.0.0', - 'environment:', - " sdk: '>=3.0.0-0 <4.0.0'", - 'dependencies:', - for (final String package in findPackageNames()) ' $package:\n sdk: flutter', - ' $kPlatformIntegrationPackageName: 0.0.1', - 'dependency_overrides:', - ' $kPlatformIntegrationPackageName:', - ' path: ${docsRoot.childDirectory(kPlatformIntegrationPackageName).path}', - ]; - - packageRoot.childFile('pubspec.yaml').writeAsStringSync(pubspec.join('\n')); - } - - void _createDummyLibrary() { - final Directory libDir = packageRoot.childDirectory('lib'); - libDir.createSync(); - - final StringBuffer contents = StringBuffer('library temp_doc;\n\n'); - for (final String libraryRef in _libraryRefs()) { - contents.writeln("import 'package:$libraryRef';"); - } - packageRoot.childDirectory('lib') - ..createSync(recursive: true) - ..childFile('temp_doc.dart').writeAsStringSync(contents.toString()); - } - - void _createPageFooter(Directory footerPath, Version version) { - final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now()); - final String gitBranch = FlutterInformation.instance.getBranchName(); - final String gitRevision = FlutterInformation.instance.getFlutterRevision(); - final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch'; - footerPath.childFile('footer.html').writeAsStringSync(''); - publishRoot.childDirectory('flutter').childFile('footer.js') - ..createSync(recursive: true) - ..writeAsStringSync(''' -(function() { - var span = document.querySelector('footer>span'); - if (span) { - span.innerText = 'Flutter $version • $timestamp • $gitRevision $gitBranchOut'; - } - var sourceLink = document.querySelector('a.source-link'); - if (sourceLink) { - sourceLink.href = sourceLink.href.replace('/master/', '/$gitRevision/'); - } -})(); -'''); - } - - void _copyCustomizations() { - final List files = [ - 'README.md', - 'analysis_options.yaml', - 'dartdoc_options.yaml', - ]; - for (final String file in files) { - filesystem.file(docsRoot.childFile(file)).copySync(packageRoot.childFile(file).path); - } - final Directory assetsDir = filesystem.directory(publishRoot.childDirectory('assets')); - if (assetsDir.existsSync()) { - assetsDir.deleteSync(recursive: true); - } - copyDirectorySync(docsRoot.childDirectory('assets'), assetsDir, - (File src, File dest) => print('Copied ${src.path} to ${dest.path}')); - } - - /// Generates an OpenSearch XML description that can be used to add a custom - /// search for Flutter API docs to the browser. Unfortunately, it has to know - /// the URL to which site to search, so we customize it here based upon the - /// branch name. - void _createSearchMetadata(File templatePath, File metadataPath) { - final String template = templatePath.readAsStringSync(); - final String branch = FlutterInformation.instance.getBranchName(); - final String metadata = template.replaceAll( - '{SITE_URL}', - branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/', - ); - metadataPath.parent.create(recursive: true); - metadataPath.writeAsStringSync(metadata); - } - - Future _createDocset() async { - // Must have dashing installed: go get -u github.com/technosophos/dashing - // Dashing produces a LOT of log output (~30MB), so we collect it, and just - // show the end of it if there was a problem. - print('${DateTime.now().toUtc()}: Building Flutter docset.'); - - // If dashing gets stuck, Cirrus will time out the build after an hour, and we - // never get to see the logs. Thus, we run it in the background and tail the - // logs only if it fails. - final ProcessWrapper result = ProcessWrapper( - await processManager.start( - [ - 'dashing', - 'build', - '--source', - publishRoot.path, - '--config', - docsRoot.childFile('dashing.json').path, - ], - workingDirectory: packageRoot.path, - ), - ); - final List buffer = []; - result.stdout.listen(buffer.addAll); - result.stderr.listen(buffer.addAll); - // If the dashing process exited with an error, print the last 200 lines of stderr and exit. - final int exitCode = await result.done; - if (exitCode != 0) { - print('Dashing docset generation failed with code $exitCode'); - final List output = systemEncoding.decode(buffer).split('\n'); - print(output.sublist(math.max(output.length - 200, 0)).join('\n')); - exit(exitCode); - } - buffer.clear(); - - // Copy the favicon file to the output directory. - final File faviconFile = - publishRoot.childDirectory('flutter').childDirectory('static-assets').childFile('favicon.png'); - final File iconFile = packageRoot.childDirectory('flutter.docset').childFile('icon.png'); - faviconFile..createSync(recursive: true)..copySync(iconFile.path); - - // Post-process the dashing output. - final File infoPlist = - packageRoot.childDirectory('flutter.docset').childDirectory('Contents').childFile('Info.plist'); - String contents = infoPlist.readAsStringSync(); - - // Since I didn't want to add the XML package as a dependency just for this, - // I just used a regular expression to make this simple change. - final RegExp findRe = RegExp(r'(\s*DocSetPlatformFamily\s*)[^<]+()', multiLine: true); - contents = contents.replaceAllMapped(findRe, (Match match) { - return '${match.group(1)}dartlang${match.group(2)}'; - }); - infoPlist.writeAsStringSync(contents); - final Directory offlineDir = publishRoot.childDirectory('offline'); - if (!offlineDir.existsSync()) { - offlineDir.createSync(recursive: true); - } - tarDirectory(packageRoot, offlineDir.childFile('flutter.docset.tar.gz')); - - // Write the Dash/Zeal XML feed file. - final bool isStable = platform.environment['LUCI_BRANCH'] == 'stable'; - offlineDir.childFile('flutter.xml').writeAsStringSync('\n' - ' ${FlutterInformation.instance.getFlutterVersion()}\n' - ' https://${isStable ? '' : 'master-'}api.flutter.dev/offline/flutter.docset.tar.gz\n' - '\n'); - } - - // Creates the offline ZIP file containing all of the website HTML files. - void _createOfflineZipFile() { - print('${DateTime.now().toLocal()}: Creating offline docs archive.'); - zipDirectory(publishRoot, packageRoot.childFile('flutter.docs.zip')); - } - - // Moves the generated offline archives into the publish directory so that - // they can be included in the output ZIP file. - void _moveOfflineIntoPlace() { - print('${DateTime.now().toUtc()}: Moving offline docs into place.'); - final Directory offlineDir = publishRoot.childDirectory('offline')..createSync(recursive: true); - packageRoot.childFile('flutter.docs.zip').renameSync(offlineDir.childFile('flutter.docs.zip').path); - } - - // Creates a robots.txt file that disallows indexing unless the branch is the - // stable branch. - void _createRobotsTxt() { - final File robotsTxt = publishRoot.childFile('robots.txt'); - if (FlutterInformation.instance.getBranchName() == 'stable') { - robotsTxt.writeAsStringSync('# All robots welcome!'); - } else { - robotsTxt.writeAsStringSync('User-agent: *\nDisallow: /'); - } - } -} - -/// Runs Dartdoc inside of the given pre-prepared staging area, prepared by -/// [Configurator.generateConfiguration]. -/// -/// Performs a sanity check of the output once the generation is complete. -class DartdocGenerator { - DartdocGenerator({ - required this.docsRoot, - required this.publishRoot, - required this.packageRoot, - this.filesystem = const LocalFileSystem(), - this.useJson = true, - this.validateLinks = true, - this.verbose = false, - }); - - /// The root of the directory in the Flutter repo where configuration data is - /// stored. - final Directory docsRoot; - - /// The root of the output area for the dartdoc docs. - /// - /// Typically this is a "doc" subdirectory under the [packageRoot]. - final Directory publishRoot; - - /// The root of the staging area for creating docs. - final Directory packageRoot; - - /// The [FileSystem] object used to create [File] and [Directory] objects. - final FileSystem filesystem; - - /// Whether or not dartdoc should output an index.json file of the - /// documentation. - final bool useJson; - - // Whether or not to have dartdoc validate its own links. - final bool validateLinks; - - /// Whether or not to filter overly verbose log output from dartdoc. - final bool verbose; - - Future generateDartdoc() async { - final Directory flutterRoot = FlutterInformation.instance.getFlutterRoot(); - final Map pubEnvironment = { - 'FLUTTER_ROOT': flutterRoot.absolute.path, - }; - - // If there's a .pub-cache dir in the Flutter root, use that. - final File pubCache = flutterRoot.childFile('.pub-cache'); - if (pubCache.existsSync()) { - pubEnvironment['PUB_CACHE'] = pubCache.path; - } - - // Run pub. - ProcessWrapper process = ProcessWrapper(await runPubProcess( - arguments: ['get'], - workingDirectory: packageRoot, - environment: pubEnvironment, - )); - printStream(process.stdout, prefix: 'pub:stdout: '); - printStream(process.stderr, prefix: 'pub:stderr: '); - final int code = await process.done; - if (code != 0) { - exit(code); - } - - final Version version = FlutterInformation.instance.getFlutterVersion(); - - // Verify which version of snippets and dartdoc we're using. - final ProcessResult snippetsResult = Process.runSync( - FlutterInformation.instance.getDartBinaryPath().path, - [ - 'pub', - 'global', - 'list', - ], - workingDirectory: packageRoot.path, - environment: pubEnvironment, - stdoutEncoding: utf8, - ); - print(''); - final Iterable versionMatches = - RegExp(r'^(?snippets|dartdoc) (?[^\s]+)', multiLine: true) - .allMatches(snippetsResult.stdout as String); - for (final RegExpMatch match in versionMatches) { - print('${match.namedGroup('name')} version: ${match.namedGroup('version')}'); - } - - print('flutter version: $version\n'); - - // Dartdoc warnings and errors in these packages are considered fatal. - // All packages owned by flutter should be in the list. - final List flutterPackages = [ - kDummyPackageName, - kPlatformIntegrationPackageName, - ...findPackageNames(), - // TODO(goderbauer): Figure out how to only include `dart:ui` of - // `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278. - // 'sky_engine', - ]; - - // Generate the documentation. We don't need to exclude flutter_tools in - // this list because it's not in the recursive dependencies of the package - // defined at packageRoot - final List dartdocArgs = [ - 'global', - 'run', - '--enable-asserts', - 'dartdoc', - '--output', - publishRoot.childDirectory('flutter').path, - '--allow-tools', - if (useJson) '--json', - if (validateLinks) '--validate-links' else '--no-validate-links', - '--link-to-source-excludes', - flutterRoot.childDirectory('bin').childDirectory('cache').path, - '--link-to-source-root', - flutterRoot.path, - '--link-to-source-uri-template', - 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', - '--inject-html', - '--use-base-href', - '--header', - docsRoot.childFile('styles.html').path, - '--header', - docsRoot.childFile('analytics.html').path, - '--header', - docsRoot.childFile('survey.html').path, - '--header', - docsRoot.childFile('snippets.html').path, - '--header', - docsRoot.childFile('opensearch.html').path, - '--footer-text', - packageRoot.childFile('footer.html').path, - '--allow-warnings-in-packages', - flutterPackages.join(','), - '--exclude-packages', - [ - 'analyzer', - 'args', - 'barback', - 'csslib', - 'flutter_goldens', - 'flutter_goldens_client', - 'front_end', - 'fuchsia_remote_debug_protocol', - 'glob', - 'html', - 'http_multi_server', - 'io', - 'isolate', - 'js', - 'kernel', - 'logging', - 'mime', - 'mockito', - 'node_preamble', - 'plugin', - 'shelf', - 'shelf_packages_handler', - 'shelf_static', - 'shelf_web_socket', - 'utf', - 'watcher', - 'yaml', - ].join(','), - '--exclude', - [ - 'dart:io/network_policy.dart', // dart-lang/dartdoc#2437 - 'package:Flutter/temp_doc.dart', - 'package:http/browser_client.dart', - 'package:intl/intl_browser.dart', - 'package:matcher/mirror_matchers.dart', - 'package:quiver/io.dart', - 'package:quiver/mirrors.dart', - 'package:vm_service_client/vm_service_client.dart', - 'package:web_socket_channel/html.dart', - ].join(','), - '--favicon', - docsRoot.childFile('favicon.ico').absolute.path, - '--package-order', - 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver', - '--auto-include-dependencies', - ]; - - String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg; - print('Executing: (cd "${packageRoot.path}" ; ' - '${FlutterInformation.instance.getDartBinaryPath().path} ' - '${dartdocArgs.map(quote).join(' ')})'); - - process = ProcessWrapper(await runPubProcess( - arguments: dartdocArgs, - workingDirectory: packageRoot, - environment: pubEnvironment, - )); - printStream( - process.stdout, - prefix: useJson ? '' : 'dartdoc:stdout: ', - filter: [ - if (!verbose) RegExp(r'^Generating docs for library '), // Unnecessary verbosity - ], - ); - printStream( - process.stderr, - prefix: useJson ? '' : 'dartdoc:stderr: ', - filter: [ - if (!verbose) - RegExp( - // Remove warnings from packages outside our control - r'^ warning: .+: \(.+[\\/]\.pub-cache[\\/]hosted[\\/]pub.dartlang.org[\\/].+\)', - ), - ], - ); - final int exitCode = await process.done; - - if (exitCode != 0) { - exit(exitCode); - } - - _sanityCheckDocs(); - checkForUnresolvedDirectives(publishRoot.childDirectory('flutter').path); - - _createIndexAndCleanup(); - - print('Documentation written to ${publishRoot.path}'); - } - - void _sanityCheckExample(String fileString, String regExpString) { - final File file = filesystem.file(fileString); - if (file.existsSync()) { - final RegExp regExp = RegExp(regExpString, dotAll: true); - final String contents = file.readAsStringSync(); - if (!regExp.hasMatch(contents)) { - throw Exception("Missing example code matching '$regExpString' in ${file.path}."); - } - } else { - throw Exception( - "Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file."); - } - } - - /// Runs a sanity check by running a test. - void _sanityCheckDocs([Platform platform = const LocalPlatform()]) { - final Directory flutterDirectory = publishRoot.childDirectory('flutter'); - final Directory widgetsDirectory = flutterDirectory.childDirectory('widgets'); - - final List canaries = [ - publishRoot.childDirectory('assets').childFile('overrides.css'), - flutterDirectory.childDirectory('dart-io').childFile('File-class.html'), - flutterDirectory.childDirectory('dart-ui').childFile('Canvas-class.html'), - flutterDirectory.childDirectory('dart-ui').childDirectory('Canvas').childFile('drawRect.html'), - flutterDirectory - .childDirectory('flutter_driver') - .childDirectory('FlutterDriver') - .childFile('FlutterDriver.connectedTo.html'), - flutterDirectory.childDirectory('flutter_test').childDirectory('WidgetTester').childFile('pumpWidget.html'), - flutterDirectory.childDirectory('material').childFile('Material-class.html'), - flutterDirectory.childDirectory('material').childFile('Tooltip-class.html'), - widgetsDirectory.childFile('Widget-class.html'), - widgetsDirectory.childFile('Listener-class.html'), - ]; - for (final File canary in canaries) { - if (!canary.existsSync()) { - throw Exception('Missing "${canary.path}", which probably means the documentation failed to build correctly.'); - } - } - // Make sure at least one example of each kind includes source code. - - // Check a "sample" example, any one will do. - _sanityCheckExample( - widgetsDirectory.childFile('showGeneralDialog.html').path, - r'\s*\s*import 'package:flutter/material.dart';', - ); - - // Check a "snippet" example, any one will do. - _sanityCheckExample( - widgetsDirectory.childDirectory('ModalRoute').childFile('barrierColor.html').path, - r'\s*.*Color\s+get\s+barrierColor.*', - ); - - // Check a "dartpad" example, any one will do, and check for the correct URL - // arguments. - // Just use "master" for any branch other than the LUCI_BRANCH. - final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim(); - final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master'; - final List argumentRegExps = [ - r'split=\d+', - r'run=true', - r'sample_id=widgets\.Listener\.\d+', - 'sample_channel=$expectedBranch', - 'channel=$expectedBranch', - ]; - for (final String argumentRegExp in argumentRegExps) { - _sanityCheckExample( - widgetsDirectory.childFile('Listener-class.html').path, - r'\s*\s*<\/iframe>', - ); - } - } - - /// Creates a custom index.html because we try to maintain old - /// paths. Cleanup unused index.html files no longer needed. - void _createIndexAndCleanup() { - print('\nCreating a custom index.html in ${publishRoot.childFile('index.html').path}'); - _copyIndexToRootOfDocs(); - _addHtmlBaseToIndex(); - _changePackageToSdkInTitlebar(); - _putRedirectInOldIndexLocation(); - _writeSnippetsIndexFile(); - print('\nDocs ready to go!'); - } - - void _copyIndexToRootOfDocs() { - publishRoot.childDirectory('flutter').childFile('index.html').copySync(publishRoot.childFile('index.html').path); - } - - void _changePackageToSdkInTitlebar() { - final File indexFile = publishRoot.childFile('index.html'); - String indexContents = indexFile.readAsStringSync(); - indexContents = indexContents.replaceFirst( - '
  • Flutter package
  • ', - '
  • Flutter SDK
  • ', - ); - - indexFile.writeAsStringSync(indexContents); - } - - void _addHtmlBaseToIndex() { - final File indexFile = publishRoot.childFile('index.html'); - String indexContents = indexFile.readAsStringSync(); - indexContents = indexContents.replaceFirst( - '\n', - '\n \n', - ); - indexContents = indexContents.replaceAll( - 'href="Android/Android-library.html"', - 'href="/javadoc/"', - ); - indexContents = indexContents.replaceAll( - 'href="iOS/iOS-library.html"', - 'href="/objcdoc/"', - ); - - indexFile.writeAsStringSync(indexContents); - } - - void _putRedirectInOldIndexLocation() { - const String metaTag = ''; - publishRoot.childDirectory('flutter').childFile('index.html').writeAsStringSync(metaTag); - } - - void _writeSnippetsIndexFile() { - final Directory snippetsDir = publishRoot.childDirectory('snippets'); - if (snippetsDir.existsSync()) { - const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' '); - final Iterable files = - snippetsDir.listSync().whereType().where((File file) => path.extension(file.path) == '.json'); - // Combine all the metadata into a single JSON array. - final Iterable fileContents = files.map((File file) => file.readAsStringSync()); - final List metadataObjects = fileContents.map(json.decode).toList(); - final String jsonArray = jsonEncoder.convert(metadataObjects); - snippetsDir.childFile('index.json').writeAsStringSync(jsonArray); - } - } -} - -/// Downloads and unpacks the platform specific documentation generated by the -/// engine build. -/// -/// Unpacks and massages the data so that it can be properly included in the -/// output archive. -class PlatformDocGenerator { - PlatformDocGenerator({required this.outputDir, this.filesystem = const LocalFileSystem()}); - - final FileSystem filesystem; - final Directory outputDir; - final String engineRevision = FlutterInformation.instance.getEngineRevision(); - - /// This downloads an archive of platform docs for the engine from the artifact - /// store and extracts them to the location used for Dartdoc. - void generatePlatformDocs() { - final String javadocUrl = - 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; - _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); - - final String objcdocUrl = - 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; - _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); - } - - /// Fetches the zip archive at the specified url. - /// - /// Returns null if the archive fails to download after [maxTries] attempts. - Future _fetchArchive(String url, int maxTries) async { - List? responseBytes; - for (int i = 0; i < maxTries; i++) { - final http.Response response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - responseBytes = response.bodyBytes; - break; - } - stderr.writeln('Failed attempt ${i + 1} to fetch $url.'); - - // On failure print a short snipped from the body in case it's helpful. - final int bodyLength = math.min(1024, response.body.length); - stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}'); - sleep(const Duration(seconds: 1)); - } - return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); - } - - Future _extractDocs(String url, String docName, String checkFile, Directory outputDir) async { - const int maxTries = 5; - final Archive? archive = await _fetchArchive(url, maxTries); - if (archive == null) { - stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.'); - exit(1); - } - - final Directory output = outputDir.childDirectory(docName); - print('Extracting $docName to ${output.path}'); - output.createSync(recursive: true); - - for (final ArchiveFile af in archive) { - if (!af.name.endsWith('/')) { - final File file = filesystem.file('${output.path}/${af.name}'); - file.createSync(recursive: true); - file.writeAsBytesSync(af.content as List); - } - } - - /// If object then copy files to old location if the archive is using the new location. - final Directory objcDocsDir = output.childDirectory('objectc_docs'); - if (objcDocsDir.existsSync()) { - copyDirectorySync(objcDocsDir, output); - } - - final File testFile = output.childFile(checkFile); - if (!testFile.existsSync()) { - print('Expected file ${testFile.path} not found'); - exit(1); - } - print('$docName ready to go!'); - } -} - -/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if -/// specified, for each source/destination file pair. -/// -/// Creates `destDir` if needed. -void copyDirectorySync(Directory srcDir, Directory destDir, - [void Function(File srcFile, File destFile)? onFileCopied]) { - if (!srcDir.existsSync()) { - throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); - } - - if (!destDir.existsSync()) { - destDir.createSync(recursive: true); - } - - for (final FileSystemEntity entity in srcDir.listSync()) { - final String newPath = path.join(destDir.path, path.basename(entity.path)); - if (entity is File) { - final File newFile = filesystem.file(newPath); - entity.copySync(newPath); - onFileCopied?.call(entity, newFile); - } else if (entity is Directory) { - copyDirectorySync(entity, filesystem.directory(newPath)); - } else { - throw Exception('${entity.path} is neither File nor Directory'); - } - } -} - -void printStream(Stream> stream, {String prefix = '', List filter = const []}) { - stream.transform(utf8.decoder).transform(const LineSplitter()).listen((String line) { - if (!filter.any((Pattern pattern) => line.contains(pattern))) { - print('$prefix$line'.trim()); - } - }); -} - -void zipDirectory(Directory src, File output) { - // We would use the archive package to do this in one line, but it - // is a lot slower, and doesn't do compression nearly as well. - final ProcessResult zipProcess = processManager.runSync( - [ - 'zip', - '-r', - '-9', - '-q', - output.path, - '.', - ], - workingDirectory: src.path, - ); - - if (zipProcess.exitCode != 0) { - print('Creating offline ZIP archive ${output.path} failed:'); - print(zipProcess.stderr); - exit(1); - } -} - -void tarDirectory(Directory src, File output) { - // We would use the archive package to do this in one line, but it - // is a lot slower, and doesn't do compression nearly as well. - final ProcessResult tarProcess = processManager.runSync( - [ - 'tar', - 'cf', - output.path, - '--use-compress-program', - 'gzip --best', - 'flutter.docset', - ], - workingDirectory: src.path, - ); - - if (tarProcess.exitCode != 0) { - print('Creating a tarball ${output.path} failed:'); - print(tarProcess.stderr); - exit(1); - } -} - -Future runPubProcess({ - required List arguments, - Directory? workingDirectory, - Map? environment, - @visibleForTesting ProcessManager processManager = const LocalProcessManager(), - @visibleForTesting FileSystem filesystem = const LocalFileSystem(), -}) { - return processManager.start( - [FlutterInformation.instance.getDartBinaryPath().path, 'pub', ...arguments], - workingDirectory: (workingDirectory ?? filesystem.currentDirectory).path, - environment: environment, - ); -} - -List findPackageNames() { - return findPackages().map((FileSystemEntity file) => path.basename(file.path)).toList(); -} - -/// Finds all packages in the Flutter SDK -List findPackages() { - return FlutterInformation.instance - .getFlutterRoot() - .childDirectory('packages') - .listSync() - .where((FileSystemEntity entity) { - if (entity is! Directory) { - return false; - } - final File pubspec = filesystem.file('${entity.path}/pubspec.yaml'); - if (!pubspec.existsSync()) { - print("Unexpected package '${entity.path}' found in packages directory"); - return false; - } - // TODO(ianh): Use a real YAML parser here - return !pubspec.readAsStringSync().contains('nodoc: true'); - }) - .cast() - .toList(); -} - -/// An exception class used to indicate problems when collecting information. -class DartdocException implements Exception { - DartdocException(this.message, {this.file, this.line}); - final String message; - final String? file; - final int? line; - - @override - String toString() { - if (file != null || line != null) { - final String fileStr = file == null ? '' : '$file:'; - final String lineStr = line == null ? '' : '$line:'; - return '$runtimeType: $fileStr$lineStr: $message'; - } else { - return '$runtimeType: $message'; - } - } -} - -/// A singleton used to consolidate the way in which information about the -/// Flutter repo and environment is collected. -/// -/// Collects the information once, and caches it for any later access. -/// -/// The singleton instance can be overridden by tests by setting [instance]. -class FlutterInformation { - FlutterInformation({ - this.platform = const LocalPlatform(), - this.processManager = const LocalProcessManager(), - this.filesystem = const LocalFileSystem(), - }); - - final Platform platform; - final ProcessManager processManager; - final FileSystem filesystem; - - static FlutterInformation? _instance; - - static FlutterInformation get instance => _instance ??= FlutterInformation(); - - @visibleForTesting - static set instance(FlutterInformation? value) => _instance = value; - - /// The path to the Dart binary in the Flutter repo. - /// - /// This is probably a shell script. - File getDartBinaryPath() { - return getFlutterRoot().childDirectory('bin').childFile('dart'); - } - - /// The path to the Flutter repo root directory. - /// - /// If the environment variable `FLUTTER_ROOT` is set, will use that instead - /// of looking for it. - /// - /// Otherwise, uses the output of `flutter --version --machine` to find the - /// Flutter root. - Directory getFlutterRoot() { - if (platform.environment['FLUTTER_ROOT'] != null) { - return filesystem.directory(platform.environment['FLUTTER_ROOT']); - } - return getFlutterInformation()['flutterRoot']! as Directory; - } - - /// Gets the semver version of the Flutter framework in the repo. - Version getFlutterVersion() => getFlutterInformation()['frameworkVersion']! as Version; - - /// Gets the git hash of the engine used by the Flutter framework in the repo. - String getEngineRevision() => getFlutterInformation()['engineRevision']! as String; - - /// Gets the git hash of the Flutter framework in the repo. - String getFlutterRevision() => getFlutterInformation()['flutterGitRevision']! as String; - - /// Gets the name of the current branch in the Flutter framework in the repo. - String getBranchName() => getFlutterInformation()['branchName']! as String; - - Map? _cachedFlutterInformation; - - /// Gets a Map of various kinds of information about the Flutter repo. - Map getFlutterInformation() { - if (_cachedFlutterInformation != null) { - return _cachedFlutterInformation!; - } - - String flutterVersionJson; - if (platform.environment['FLUTTER_VERSION'] != null) { - flutterVersionJson = platform.environment['FLUTTER_VERSION']!; - } else { - String flutterCommand; - if (platform.environment['FLUTTER_ROOT'] != null) { - flutterCommand = filesystem - .directory(platform.environment['FLUTTER_ROOT']) - .childDirectory('bin') - .childFile('flutter') - .absolute - .path; - } else { - flutterCommand = 'flutter'; - } - ProcessResult result; - try { - result = processManager.runSync([flutterCommand, '--version', '--machine'], stdoutEncoding: utf8); - } on ProcessException catch (e) { - throw DartdocException( - 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e'); - } - if (result.exitCode != 0) { - throw DartdocException('Unable to determine Flutter information, because of abnormal exit to flutter command.'); - } - flutterVersionJson = (result.stdout as String) - .replaceAll('Waiting for another flutter command to release the startup lock...', ''); - } - - final Map flutterVersion = json.decode(flutterVersionJson) as Map; - if (flutterVersion['flutterRoot'] == null || - flutterVersion['frameworkVersion'] == null || - flutterVersion['dartSdkVersion'] == null) { - throw DartdocException( - 'Flutter command output has unexpected format, unable to determine flutter root location.'); - } - - final Map info = {}; - final Directory flutterRoot = filesystem.directory(flutterVersion['flutterRoot']! as String); - info['flutterRoot'] = flutterRoot; - info['frameworkVersion'] = Version.parse(flutterVersion['frameworkVersion'] as String); - info['engineRevision'] = flutterVersion['engineRevision'] as String; - - final RegExpMatch? dartVersionRegex = RegExp(r'(?[\d.]+)(?:\s+\(build (?[-.\w]+)\))?') - .firstMatch(flutterVersion['dartSdkVersion'] as String); - if (dartVersionRegex == null) { - throw DartdocException( - 'Flutter command output has unexpected format, unable to parse dart SDK version ${flutterVersion['dartSdkVersion']}.'); - } - info['dartSdkVersion'] = - Version.parse(dartVersionRegex.namedGroup('detail') ?? dartVersionRegex.namedGroup('base')!); - - info['branchName'] = _getBranchName(); - info['flutterGitRevision'] = _getFlutterGitRevision(); - _cachedFlutterInformation = info; - - return info; - } - - // Get the name of the release branch. - // - // On LUCI builds, the git HEAD is detached, so first check for the env - // variable "LUCI_BRANCH"; if it is not set, fall back to calling git. - String _getBranchName() { - final String? luciBranch = platform.environment['LUCI_BRANCH']; - if (luciBranch != null && luciBranch.trim().isNotEmpty) { - return luciBranch.trim(); - } - final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain']); - if (gitResult.exitCode != 0) { - throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; - } - final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); - final RegExpMatch? gitBranchMatch = - gitBranchRegexp.firstMatch((gitResult.stdout as String).trim().split('\n').first); - return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first; - } - - // Get the git revision for the repo. - String _getFlutterGitRevision() { - const int kGitRevisionLength = 10; - - final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); - if (gitResult.exitCode != 0) { - throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; - } - final String gitRevision = (gitResult.stdout as String).trim(); - - return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision; - } -} diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart new file mode 100644 index 0000000000000..8bd8b39d73ac2 --- /dev/null +++ b/dev/tools/dartdoc.dart @@ -0,0 +1,606 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; +import 'package:platform/platform.dart'; +import 'package:process/process.dart'; + +import 'dartdoc_checker.dart'; + +const String kDocsRoot = 'dev/docs'; +const String kPublishRoot = '$kDocsRoot/doc'; + +const String kDummyPackageName = 'Flutter'; +const String kPlatformIntegrationPackageName = 'platform_integration'; + +/// This script expects to run with the cwd as the root of the flutter repo. It +/// will generate documentation for the packages in `//packages/` and write the +/// documentation to `//dev/docs/doc/api/`. +/// +/// This script also updates the index.html file so that it can be placed +/// at the root of api.flutter.dev. We are keeping the files inside of +/// api.flutter.dev/flutter for now, so we need to manipulate paths +/// a bit. See https://github.com/flutter/flutter/issues/3900 for more info. +/// +/// This will only work on UNIX systems, not Windows. It requires that 'git' be +/// in your path. It requires that 'flutter' has been run previously. It uses +/// the version of Dart downloaded by the 'flutter' tool in this repository and +/// will crash if that is absent. +Future main(List arguments) async { + final ArgParser argParser = _createArgsParser(); + final ArgResults args = argParser.parse(arguments); + if (args['help'] as bool) { + print ('Usage:'); + print (argParser.usage); + exit(0); + } + // If we're run from the `tools` dir, set the cwd to the repo root. + if (path.basename(Directory.current.path) == 'tools') { + Directory.current = Directory.current.parent.parent; + } + + final ProcessResult flutter = Process.runSync('flutter', []); + final File versionFile = File('version'); + if (flutter.exitCode != 0 || !versionFile.existsSync()) { + throw Exception('Failed to determine Flutter version.'); + } + final String version = versionFile.readAsStringSync(); + + // Create the pubspec.yaml file. + final StringBuffer buf = StringBuffer(); + buf.writeln('name: $kDummyPackageName'); + buf.writeln('homepage: https://flutter.dev'); + buf.writeln('version: 0.0.0'); + buf.writeln('environment:'); + buf.writeln(" sdk: '>=3.0.0-0 <4.0.0'"); + buf.writeln('dependencies:'); + for (final String package in findPackageNames()) { + buf.writeln(' $package:'); + buf.writeln(' sdk: flutter'); + } + buf.writeln(' $kPlatformIntegrationPackageName: 0.0.1'); + buf.writeln('dependency_overrides:'); + buf.writeln(' $kPlatformIntegrationPackageName:'); + buf.writeln(' path: $kPlatformIntegrationPackageName'); + File('$kDocsRoot/pubspec.yaml').writeAsStringSync(buf.toString()); + + // Create the library file. + final Directory libDir = Directory('$kDocsRoot/lib'); + libDir.createSync(); + + final StringBuffer contents = StringBuffer('library temp_doc;\n\n'); + for (final String libraryRef in libraryRefs()) { + contents.writeln("import 'package:$libraryRef';"); + } + File('$kDocsRoot/lib/temp_doc.dart').writeAsStringSync(contents.toString()); + + final String flutterRoot = Directory.current.path; + final Map pubEnvironment = { + 'FLUTTER_ROOT': flutterRoot, + }; + + // If there's a .pub-cache dir in the flutter root, use that. + final String pubCachePath = '$flutterRoot/.pub-cache'; + if (Directory(pubCachePath).existsSync()) { + pubEnvironment['PUB_CACHE'] = pubCachePath; + } + + final String dartExecutable = '$flutterRoot/bin/cache/dart-sdk/bin/dart'; + + // Run pub. + ProcessWrapper process = ProcessWrapper(await runPubProcess( + dartBinaryPath: dartExecutable, + arguments: ['get'], + workingDirectory: kDocsRoot, + environment: pubEnvironment, + )); + printStream(process.stdout, prefix: 'pub:stdout: '); + printStream(process.stderr, prefix: 'pub:stderr: '); + final int code = await process.done; + if (code != 0) { + exit(code); + } + + createFooter('$kDocsRoot/lib/', version); + copyAssets(); + createSearchMetadata('$kDocsRoot/lib/opensearch.xml', '$kDocsRoot/doc/opensearch.xml'); + cleanOutSnippets(); + + final List dartdocBaseArgs = [ + 'global', + 'run', + if (args['checked'] as bool) '--enable-asserts', + 'dartdoc', + ]; + + // Verify which version of snippets and dartdoc we're using. + final ProcessResult snippetsResult = Process.runSync( + dartExecutable, + [ + 'pub', + 'global', + 'list', + ], + workingDirectory: kDocsRoot, + environment: pubEnvironment, + stdoutEncoding: utf8, + ); + print(''); + final Iterable versionMatches = RegExp(r'^(?snippets|dartdoc) (?[^\s]+)', multiLine: true) + .allMatches(snippetsResult.stdout as String); + for (final RegExpMatch match in versionMatches) { + print('${match.namedGroup('name')} version: ${match.namedGroup('version')}'); + } + + print('flutter version: $version\n'); + + // Dartdoc warnings and errors in these packages are considered fatal. + // All packages owned by flutter should be in the list. + final List flutterPackages = [ + kDummyPackageName, + kPlatformIntegrationPackageName, + ...findPackageNames(), + // TODO(goderbauer): Figure out how to only include `dart:ui` of `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278. + // 'sky_engine', + ]; + + // Generate the documentation. + // We don't need to exclude flutter_tools in this list because it's not in the + // recursive dependencies of the package defined at dev/docs/pubspec.yaml + final List dartdocArgs = [ + ...dartdocBaseArgs, + '--allow-tools', + if (args['json'] as bool) '--json', + if (args['validate-links'] as bool) '--validate-links' else '--no-validate-links', + '--link-to-source-excludes', '../../bin/cache', + '--link-to-source-root', '../..', + '--link-to-source-uri-template', 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', + '--inject-html', + '--use-base-href', + '--header', 'styles.html', + '--header', 'analytics.html', + '--header', 'survey.html', + '--header', 'snippets.html', + '--header', 'opensearch.html', + '--footer-text', 'lib/footer.html', + '--allow-warnings-in-packages', flutterPackages.join(','), + '--exclude-packages', + [ + 'analyzer', + 'args', + 'barback', + 'csslib', + 'flutter_goldens', + 'flutter_goldens_client', + 'front_end', + 'fuchsia_remote_debug_protocol', + 'glob', + 'html', + 'http_multi_server', + 'io', + 'isolate', + 'js', + 'kernel', + 'logging', + 'mime', + 'mockito', + 'node_preamble', + 'plugin', + 'shelf', + 'shelf_packages_handler', + 'shelf_static', + 'shelf_web_socket', + 'utf', + 'watcher', + 'yaml', + ].join(','), + '--exclude', + [ + 'dart:io/network_policy.dart', // dart-lang/dartdoc#2437 + 'package:Flutter/temp_doc.dart', + 'package:http/browser_client.dart', + 'package:intl/intl_browser.dart', + 'package:matcher/mirror_matchers.dart', + 'package:quiver/io.dart', + 'package:quiver/mirrors.dart', + 'package:vm_service_client/vm_service_client.dart', + 'package:web_socket_channel/html.dart', + ].join(','), + '--favicon=favicon.ico', + '--package-order', 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver', + '--auto-include-dependencies', + ]; + + String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg; + print('Executing: (cd $kDocsRoot ; $dartExecutable ${dartdocArgs.map(quote).join(' ')})'); + + process = ProcessWrapper(await runPubProcess( + dartBinaryPath: dartExecutable, + arguments: dartdocArgs, + workingDirectory: kDocsRoot, + environment: pubEnvironment, + )); + printStream(process.stdout, prefix: args['json'] as bool ? '' : 'dartdoc:stdout: ', + filter: args['verbose'] as bool ? const [] : [ + RegExp(r'^Generating docs for library '), // unnecessary verbosity + ], + ); + printStream(process.stderr, prefix: args['json'] as bool ? '' : 'dartdoc:stderr: ', + filter: args['verbose'] as bool ? const [] : [ + RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control + ], + ); + final int exitCode = await process.done; + + if (exitCode != 0) { + exit(exitCode); + } + + sanityCheckDocs(); + checkForUnresolvedDirectives('$kPublishRoot/api'); + + createIndexAndCleanup(); +} + +ArgParser _createArgsParser() { + final ArgParser parser = ArgParser(); + parser.addFlag('help', abbr: 'h', negatable: false, + help: 'Show command help.'); + parser.addFlag('verbose', defaultsTo: true, + help: 'Whether to report all error messages (on) or attempt to ' + 'filter out some known false positives (off). Shut this off ' + 'locally if you want to address Flutter-specific issues.'); + parser.addFlag('checked', abbr: 'c', + help: 'Run dartdoc with asserts enabled.'); + parser.addFlag('json', + help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); + parser.addFlag('validate-links', + help: 'Display warnings for broken links generated by dartdoc (slow)'); + return parser; +} + +final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); + +/// Get the name of the release branch. +/// +/// On LUCI builds, the git HEAD is detached, so first check for the env +/// variable "LUCI_BRANCH"; if it is not set, fall back to calling git. +String getBranchName({ + @visibleForTesting + Platform platform = const LocalPlatform(), + @visibleForTesting + ProcessManager processManager = const LocalProcessManager(), +}) { + final String? luciBranch = platform.environment['LUCI_BRANCH']; + if (luciBranch != null && luciBranch.trim().isNotEmpty) { + return luciBranch.trim(); + } + final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain']); + if (gitResult.exitCode != 0) { + throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; + } + final RegExpMatch? gitBranchMatch = gitBranchRegexp.firstMatch( + (gitResult.stdout as String).trim().split('\n').first); + return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first; +} + +String gitRevision() { + const int kGitRevisionLength = 10; + + final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); + if (gitResult.exitCode != 0) { + throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; + } + final String gitRevision = (gitResult.stdout as String).trim(); + + return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision; +} + +void createFooter(String footerPath, String version) { + final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now()); + final String gitBranch = getBranchName(); + final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch'; + File('${footerPath}footer.html').writeAsStringSync(''); + File('$kPublishRoot/api/footer.js') + ..createSync(recursive: true) + ..writeAsStringSync(''' +(function() { + var span = document.querySelector('footer>span'); + if (span) { + span.innerText = 'Flutter $version • $timestamp • ${gitRevision()} $gitBranchOut'; + } + var sourceLink = document.querySelector('a.source-link'); + if (sourceLink) { + sourceLink.href = sourceLink.href.replace('/master/', '/${gitRevision()}/'); + } +})(); +'''); +} + +/// Generates an OpenSearch XML description that can be used to add a custom +/// search for Flutter API docs to the browser. Unfortunately, it has to know +/// the URL to which site to search, so we customize it here based upon the +/// branch name. +void createSearchMetadata(String templatePath, String metadataPath) { + final String template = File(templatePath).readAsStringSync(); + final String branch = getBranchName(); + final String metadata = template.replaceAll( + '{SITE_URL}', + branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/', + ); + Directory(path.dirname(metadataPath)).create(recursive: true); + File(metadataPath).writeAsStringSync(metadata); +} + +/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if +/// specified, for each source/destination file pair. +/// +/// Creates `destDir` if needed. +void copyDirectorySync(Directory srcDir, Directory destDir, [void Function(File srcFile, File destFile)? onFileCopied]) { + if (!srcDir.existsSync()) { + throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); + } + + if (!destDir.existsSync()) { + destDir.createSync(recursive: true); + } + + for (final FileSystemEntity entity in srcDir.listSync()) { + final String newPath = path.join(destDir.path, path.basename(entity.path)); + if (entity is File) { + final File newFile = File(newPath); + entity.copySync(newPath); + onFileCopied?.call(entity, newFile); + } else if (entity is Directory) { + copyDirectorySync(entity, Directory(newPath)); + } else { + throw Exception('${entity.path} is neither File nor Directory'); + } + } +} + +void copyAssets() { + final Directory assetsDir = Directory(path.join(kPublishRoot, 'assets')); + if (assetsDir.existsSync()) { + assetsDir.deleteSync(recursive: true); + } + copyDirectorySync( + Directory(path.join(kDocsRoot, 'assets')), + Directory(path.join(kPublishRoot, 'assets')), + (File src, File dest) => print('Copied ${src.path} to ${dest.path}')); +} + +/// Clean out any existing snippets so that we don't publish old files from +/// previous runs accidentally. +void cleanOutSnippets() { + final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets')); + if (snippetsDir.existsSync()) { + snippetsDir + ..deleteSync(recursive: true) + ..createSync(recursive: true); + } +} + +void _sanityCheckExample(String fileString, String regExpString) { + final File file = File(fileString); + if (file.existsSync()) { + final RegExp regExp = RegExp(regExpString, dotAll: true); + final String contents = file.readAsStringSync(); + if (!regExp.hasMatch(contents)) { + throw Exception("Missing example code matching '$regExpString' in ${file.path}."); + } + } else { + throw Exception( + "Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file."); + } +} + +/// Runs a sanity check by running a test. +void sanityCheckDocs([Platform platform = const LocalPlatform()]) { + final List canaries = [ + '$kPublishRoot/assets/overrides.css', + '$kPublishRoot/api/dart-io/File-class.html', + '$kPublishRoot/api/dart-ui/Canvas-class.html', + '$kPublishRoot/api/dart-ui/Canvas/drawRect.html', + '$kPublishRoot/api/flutter_driver/FlutterDriver/FlutterDriver.connectedTo.html', + '$kPublishRoot/api/flutter_test/WidgetTester/pumpWidget.html', + '$kPublishRoot/api/material/Material-class.html', + '$kPublishRoot/api/material/Tooltip-class.html', + '$kPublishRoot/api/widgets/Widget-class.html', + '$kPublishRoot/api/widgets/Listener-class.html', + ]; + for (final String canary in canaries) { + if (!File(canary).existsSync()) { + throw Exception('Missing "$canary", which probably means the documentation failed to build correctly.'); + } + } + // Make sure at least one example of each kind includes source code. + + // Check a "sample" example, any one will do. + _sanityCheckExample( + '$kPublishRoot/api/widgets/showGeneralDialog.html', + r'\s*\s*import 'package:flutter/material.dart';', + ); + + // Check a "snippet" example, any one will do. + _sanityCheckExample( + '$kPublishRoot/api/widgets/ModalRoute/barrierColor.html', + r'\s*.*Color\s+get\s+barrierColor.*', + ); + + // Check a "dartpad" example, any one will do, and check for the correct URL + // arguments. + // Just use "master" for any branch other than the LUCI_BRANCH. + final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim(); + final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master'; + final List argumentRegExps = [ + r'split=\d+', + r'run=true', + r'sample_id=widgets\.Listener\.\d+', + 'sample_channel=$expectedBranch', + 'channel=$expectedBranch', + ]; + for (final String argumentRegExp in argumentRegExps) { + _sanityCheckExample( + '$kPublishRoot/api/widgets/Listener-class.html', + r'\s*\s*<\/iframe>', + ); + } +} + +/// Creates a custom index.html because we try to maintain old +/// paths. Cleanup unused index.html files no longer needed. +void createIndexAndCleanup() { + print('\nCreating a custom index.html in $kPublishRoot/index.html'); + removeOldFlutterDocsDir(); + renameApiDir(); + copyIndexToRootOfDocs(); + addHtmlBaseToIndex(); + changePackageToSdkInTitlebar(); + putRedirectInOldIndexLocation(); + writeSnippetsIndexFile(); + print('\nDocs ready to go!'); +} + +void removeOldFlutterDocsDir() { + try { + Directory('$kPublishRoot/flutter').deleteSync(recursive: true); + } on FileSystemException { + // If the directory does not exist, that's OK. + } +} + +void renameApiDir() { + Directory('$kPublishRoot/api').renameSync('$kPublishRoot/flutter'); +} + +void copyIndexToRootOfDocs() { + File('$kPublishRoot/flutter/index.html').copySync('$kPublishRoot/index.html'); +} + +void changePackageToSdkInTitlebar() { + final File indexFile = File('$kPublishRoot/index.html'); + String indexContents = indexFile.readAsStringSync(); + indexContents = indexContents.replaceFirst( + '
  • Flutter package
  • ', + '
  • Flutter SDK
  • ', + ); + + indexFile.writeAsStringSync(indexContents); +} + +void addHtmlBaseToIndex() { + final File indexFile = File('$kPublishRoot/index.html'); + String indexContents = indexFile.readAsStringSync(); + indexContents = indexContents.replaceFirst( + '\n', + '\n \n', + ); + indexContents = indexContents.replaceAll( + 'href="Android/Android-library.html"', + 'href="/javadoc/"', + ); + indexContents = indexContents.replaceAll( + 'href="iOS/iOS-library.html"', + 'href="/objcdoc/"', + ); + + indexFile.writeAsStringSync(indexContents); +} + +void putRedirectInOldIndexLocation() { + const String metaTag = ''; + File('$kPublishRoot/flutter/index.html').writeAsStringSync(metaTag); +} + +void writeSnippetsIndexFile() { + final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets')); + if (snippetsDir.existsSync()) { + const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' '); + final Iterable files = snippetsDir + .listSync() + .whereType() + .where((File file) => path.extension(file.path) == '.json'); + // Combine all the metadata into a single JSON array. + final Iterable fileContents = files.map((File file) => file.readAsStringSync()); + final List metadataObjects = fileContents.map(json.decode).toList(); + final String jsonArray = jsonEncoder.convert(metadataObjects); + File('$kPublishRoot/snippets/index.json').writeAsStringSync(jsonArray); + } +} + +List findPackageNames() { + return findPackages().map((FileSystemEntity file) => path.basename(file.path)).toList(); +} + +/// Finds all packages in the Flutter SDK +List findPackages() { + return Directory('packages') + .listSync() + .where((FileSystemEntity entity) { + if (entity is! Directory) { + return false; + } + final File pubspec = File('${entity.path}/pubspec.yaml'); + if (!pubspec.existsSync()) { + print("Unexpected package '${entity.path}' found in packages directory"); + return false; + } + // TODO(ianh): Use a real YAML parser here + return !pubspec.readAsStringSync().contains('nodoc: true'); + }) + .cast() + .toList(); +} + +/// Returns import or on-disk paths for all libraries in the Flutter SDK. +Iterable libraryRefs() sync* { + for (final Directory dir in findPackages()) { + final String dirName = path.basename(dir.path); + for (final FileSystemEntity file in Directory('${dir.path}/lib').listSync()) { + if (file is File && file.path.endsWith('.dart')) { + yield '$dirName/${path.basename(file.path)}'; + } + } + } + + // Add a fake package for platform integration APIs. + yield '$kPlatformIntegrationPackageName/android.dart'; + yield '$kPlatformIntegrationPackageName/ios.dart'; +} + +void printStream(Stream> stream, { String prefix = '', List filter = const [] }) { + stream + .transform(utf8.decoder) + .transform(const LineSplitter()) + .listen((String line) { + if (!filter.any((Pattern pattern) => line.contains(pattern))) { + print('$prefix$line'.trim()); + } + }); +} + +Future runPubProcess({ + required String dartBinaryPath, + required List arguments, + String? workingDirectory, + Map? environment, + @visibleForTesting + ProcessManager processManager = const LocalProcessManager(), +}) { + return processManager.start( + [dartBinaryPath, 'pub', ...arguments], + workingDirectory: workingDirectory, + environment: environment, + ); +} diff --git a/dev/tools/java_and_objc_doc.dart b/dev/tools/java_and_objc_doc.dart new file mode 100644 index 0000000000000..260cdc7b6094f --- /dev/null +++ b/dev/tools/java_and_objc_doc.dart @@ -0,0 +1,97 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; +import 'dart:math'; + +import 'package:archive/archive.dart'; +import 'package:http/http.dart' as http; +import 'package:path/path.dart' as path; + +const String kDocRoot = 'dev/docs/doc'; + +/// This script downloads an archive of Javadoc and objc doc for the engine from +/// the artifact store and extracts them to the location used for Dartdoc. +Future main(List args) async { + final String engineVersion = File('bin/internal/engine.version').readAsStringSync().trim(); + String engineRealm = File('bin/internal/engine.realm').readAsStringSync().trim(); + if (engineRealm.isNotEmpty) { + engineRealm = '$engineRealm/'; + } + + final String javadocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/android-javadoc.zip'; + generateDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html'); + + final String objcdocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip'; + generateDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html'); +} + +/// Fetches the zip archive at the specified url. +/// +/// Returns null if the archive fails to download after [maxTries] attempts. +Future fetchArchive(String url, int maxTries) async { + List? responseBytes; + for (int i = 0; i < maxTries; i++) { + final http.Response response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + responseBytes = response.bodyBytes; + break; + } + stderr.writeln('Failed attempt ${i+1} to fetch $url.'); + + // On failure print a short snipped from the body in case it's helpful. + final int bodyLength = min(1024, response.body.length); + stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}'); + sleep(const Duration(seconds: 1)); + } + return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); +} + +Future generateDocs(String url, String docName, String checkFile) async { + const int maxTries = 5; + final Archive? archive = await fetchArchive(url, maxTries); + if (archive == null) { + stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.'); + exit(1); + } + + final Directory output = Directory('$kDocRoot/$docName'); + print('Extracting $docName to ${output.path}'); + output.createSync(recursive: true); + + for (final ArchiveFile af in archive) { + if (!af.name.endsWith('/')) { + final File file = File('${output.path}/${af.name}'); + file.createSync(recursive: true); + file.writeAsBytesSync(af.content as List); + } + } + + /// If object then copy files to old location if the archive is using the new location. + final bool exists = Directory('$kDocRoot/$docName/objectc_docs').existsSync(); + if (exists) { + copyFolder(Directory('$kDocRoot/$docName/objectc_docs'), Directory('$kDocRoot/$docName/')); + } + + final File testFile = File('${output.path}/$checkFile'); + if (!testFile.existsSync()) { + print('Expected file ${testFile.path} not found'); + exit(1); + } + print('$docName ready to go!'); +} + +/// Copies the files in a directory recursively to a new location. +void copyFolder(Directory source, Directory destination) { + source.listSync() + .forEach((FileSystemEntity entity) { + if (entity is Directory) { + final Directory newDirectory = Directory(path.join(destination.absolute.path, path.basename(entity.path))); + newDirectory.createSync(); + copyFolder(entity.absolute, newDirectory); + } else if (entity is File) { + entity.copySync(path.join(destination.path, path.basename(entity.path))); + } + }); +} diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index fdf94b40dd17b..82ad7215a6c85 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -12,7 +12,6 @@ dependencies: meta: 1.9.1 path: 1.8.3 process: 4.2.4 - pub_semver: 2.1.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -46,6 +45,7 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart deleted file mode 100644 index a12edbbfdf428..0000000000000 --- a/dev/tools/test/create_api_docs_test.dart +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:platform/platform.dart'; -import 'package:pub_semver/pub_semver.dart'; -import 'package:test/test.dart'; - -import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; -import '../create_api_docs.dart' as apidocs; - -void main() { - test('getBranchName does not call git if env LUCI_BRANCH provided', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': branchName, - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH not provided', () { - final Platform platform = FakePlatform( - environment: {}, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH is empty', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': '', - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test("runPubProcess doesn't use the pub binary", () { - final Platform platform = FakePlatform( - environment: { - 'FLUTTER_ROOT': '/flutter', - }, - ); - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['/flutter/bin/dart', 'pub', '--one', '--two'], - ), - ], - ); - apidocs.FlutterInformation.instance = - apidocs.FlutterInformation(platform: platform, processManager: processManager); - - apidocs.runPubProcess( - arguments: ['--one', '--two'], - processManager: processManager, - ); - - expect(processManager, hasNoRemainingExpectations); - }); - - group('FlutterInformation', () { - late FakeProcessManager fakeProcessManager; - late FakePlatform fakePlatform; - late MemoryFileSystem memoryFileSystem; - late apidocs.FlutterInformation flutterInformation; - - void setUpWithEnvironment(Map environment) { - fakePlatform = FakePlatform(environment: environment); - flutterInformation = apidocs.FlutterInformation( - filesystem: memoryFileSystem, - processManager: fakeProcessManager, - platform: fakePlatform, - ); - apidocs.FlutterInformation.instance = flutterInformation; - } - - setUp(() { - fakeProcessManager = FakeProcessManager.empty(); - memoryFileSystem = MemoryFileSystem(); - setUpWithEnvironment({}); - }); - - test('calls out to flutter if FLUTTER_VERSION is not set', () async { - fakeProcessManager.addCommand( - const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); - final Map info = flutterInformation.getFlutterInformation(); - expect(fakeProcessManager, hasNoRemainingExpectations); - expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); - }); - test("doesn't call out to flutter if FLUTTER_VERSION is set", () async { - setUpWithEnvironment({ - 'FLUTTER_VERSION': testVersionInfo, - }); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); - final Map info = flutterInformation.getFlutterInformation(); - expect(fakeProcessManager, hasNoRemainingExpectations); - expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); - }); - test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set', () async { - fakeProcessManager.addCommand( - const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); - final Directory root = flutterInformation.getFlutterRoot(); - expect(fakeProcessManager, hasNoRemainingExpectations); - expect(root.path, equals('/home/user/flutter')); - }); - test("getFlutterRoot doesn't call out to flutter if FLUTTER_ROOT is set", () async { - setUpWithEnvironment({'FLUTTER_ROOT': '/home/user/flutter'}); - final Directory root = flutterInformation.getFlutterRoot(); - expect(fakeProcessManager, hasNoRemainingExpectations); - expect(root.path, equals('/home/user/flutter')); - }); - test('parses version properly', () async { - fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo; - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); - final Map info = flutterInformation.getFlutterInformation(); - expect(info['frameworkVersion'], isNotNull); - expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); - expect(info['dartSdkVersion'], isNotNull); - expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev'))); - }); - }); -} - -const String branchName = 'stable'; -const String testVersionInfo = ''' -{ - "frameworkVersion": "2.5.0", - "channel": "$branchName", - "repositoryUrl": "git@github.com:flutter/flutter.git", - "frameworkRevision": "0000000000000000000000000000000000000000", - "frameworkCommitDate": "2021-07-28 13:03:40 -0700", - "engineRevision": "0000000000000000000000000000000000000001", - "dartSdkVersion": "2.14.0 (build 2.14.0-360.0.dev)", - "flutterRoot": "/home/user/flutter" -} -'''; diff --git a/dev/tools/test/dartdoc_test.dart b/dev/tools/test/dartdoc_test.dart new file mode 100644 index 0000000000000..5744650ee3fa8 --- /dev/null +++ b/dev/tools/test/dartdoc_test.dart @@ -0,0 +1,98 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:platform/platform.dart'; +import 'package:test/test.dart'; + +import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; +import '../dartdoc.dart' show getBranchName, runPubProcess; + +void main() { + const String branchName = 'stable'; + test('getBranchName does not call git if env LUCI_BRANCH provided', () { + final Platform platform = FakePlatform( + environment: { + 'LUCI_BRANCH': branchName, + }, + ); + + final ProcessManager processManager = FakeProcessManager.empty(); + + expect( + getBranchName( + platform: platform, + processManager: processManager, + ), + branchName, + ); + }); + + test('getBranchName calls git if env LUCI_BRANCH not provided', () { + final Platform platform = FakePlatform( + environment: {}, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + ], + ); + + expect( + getBranchName( + platform: platform, + processManager: processManager, + ), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH is empty', () { + final Platform platform = FakePlatform( + environment: { + 'LUCI_BRANCH': '', + }, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + ], + ); + + expect( + getBranchName( + platform: platform, + processManager: processManager, + ), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test("runPubProcess doesn't use the pub binary", () { + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['dart', 'pub', '--one', '--two'], + ), + ], + ); + + runPubProcess( + dartBinaryPath: 'dart', + arguments: ['--one', '--two'], + processManager: processManager, + ); + + expect(processManager, hasNoRemainingExpectations); + }); +} From e1880435650a17cf4b6f7e6ccb705c9562f17e59 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 15 Aug 2023 23:18:19 -0400 Subject: [PATCH 0740/1547] Roll Flutter Engine from 7409ce4ba0a8 to 659cdfc5a568 (1 revision) (#132612) https://github.com/flutter/engine/compare/7409ce4ba0a8...659cdfc5a568 2023-08-16 jonahwilliams@google.com [Impeller] Cache render target texture allocations across frames. (flutter/engine#44527) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 71fc835ed2656..78fe900386be5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7409ce4ba0a8f18c0c3d7081a39d9b41c0b6ce8b +659cdfc5a56840baed7f5481bbe4c22a173e851c From c70d1843aba2141718cdf947a8659cce747e9081 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 00:05:21 -0400 Subject: [PATCH 0741/1547] Roll Flutter Engine from 659cdfc5a568 to decaccfc421d (6 revisions) (#132618) https://github.com/flutter/engine/compare/659cdfc5a568...decaccfc421d 2023-08-16 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 7iuIq3PsSkuCmuEMr... to Zp9or9YwxZHHPeQbA... (flutter/engine#44747) 2023-08-16 godofredoc@google.com Move cache builders to prod. (flutter/engine#44739) 2023-08-16 26625149+0xZOne@users.noreply.github.com Enabling the host application to control the timing of attaching the |FlutterView| to the engine (flutter/engine#43595) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 9fc1c628456a to 3d2b84e28e79 (1 revision) (flutter/engine#44746) 2023-08-16 skia-flutter-autoroll@skia.org Roll Dart SDK from b36934aae968 to e6bf503b36fe (1 revision) (flutter/engine#44745) 2023-08-16 matanlurey@users.noreply.github.com [Skia] Only respect ui.Paint.dither when the colorSource is a gradient (flutter/engine#44730) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 7iuIq3PsSkuC to Zp9or9YwxZHH If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 78fe900386be5..2bd9920ad0774 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -659cdfc5a56840baed7f5481bbe4c22a173e851c +decaccfc421d90265bb9d0a42da0ad2e4de1eef1 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 833b5a5e9b655..1fa23fd64d673 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -7iuIq3PsSkuCmuEMr29sQ3wjRe8GTExLe-cHjITyxcEC +Zp9or9YwxZHHPeQbAnK1yZvyDefNEqdI8UQFALQsLH8C From 03aa95be67c2e17ef6723ec4018df8e9cb453d1b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 01:53:05 -0400 Subject: [PATCH 0742/1547] Roll Flutter Engine from decaccfc421d to 7cc6a5832a0e (1 revision) (#132621) https://github.com/flutter/engine/compare/decaccfc421d...7cc6a5832a0e 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 3d2b84e28e79 to 8f0238837ee4 (1 revision) (flutter/engine#44748) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2bd9920ad0774..9f601645056de 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -decaccfc421d90265bb9d0a42da0ad2e4de1eef1 +7cc6a5832a0eb1b2dbf457dcdfb3625753f65aeb From 5fd9fc174d31af5e01d59387be2ffe73d153e74b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 03:24:24 -0400 Subject: [PATCH 0743/1547] Roll Flutter Engine from 7cc6a5832a0e to e8670f03a9b1 (3 revisions) (#132623) https://github.com/flutter/engine/compare/7cc6a5832a0e...e8670f03a9b1 2023-08-16 skia-flutter-autoroll@skia.org Roll Dart SDK from e6bf503b36fe to 80b9a90ae563 (2 revisions) (flutter/engine#44753) 2023-08-16 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from orVLXMF7ak2qfFkGs... to GpKKtPGPMiRcY0kcz... (flutter/engine#44751) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 8f0238837ee4 to 586a6309e3a1 (2 revisions) (flutter/engine#44752) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from orVLXMF7ak2q to GpKKtPGPMiRc If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9f601645056de..d22d161f16d4f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7cc6a5832a0eb1b2dbf457dcdfb3625753f65aeb +e8670f03a9b163993d8162f5b7c0dbb8dc02bda7 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 929cf1bdadf39..bec69a7c685ea 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -orVLXMF7ak2qfFkGs7OLUQNik6GqDB0aUMScuWBMeLwC +GpKKtPGPMiRcY0kczUz9TMRl6fRE6e4PFlCkCfvzYuQC From 3423226958f65962a032af1a3ceaa68f6b48f8ee Mon Sep 17 00:00:00 2001 From: William Hesse Date: Wed, 16 Aug 2023 14:00:25 +0200 Subject: [PATCH 0744/1547] Fix flutter_tools use of --local-engine-host (#132648) PR #132346 added the use of --local-engine-host to flutter_tools internals, and had an error on one line. Fix that error, to use the correct field name. The error occurs when building plugins with the changed tools. --- packages/flutter_tools/gradle/src/main/groovy/flutter.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index 657ef144bf483..21368a4c9959f 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -331,7 +331,7 @@ class FlutterPlugin implements Plugin { if (!engineHostOut.isDirectory()) { throw new GradleException('local-engine-host-out must point to a local engine host build') } - localEngineHostOut = engineHostOut.name + localEngineHost = engineHostOut.name } project.android.buildTypes.all this.&addFlutterDependencies } From 9f46ed7449233d48b0468b6317ddbe004ccd57ed Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 08:14:41 -0400 Subject: [PATCH 0745/1547] Roll Flutter Engine from e8670f03a9b1 to f186f1e9dc88 (2 revisions) (#132649) https://github.com/flutter/engine/compare/e8670f03a9b1...f186f1e9dc88 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from cb3451491f11 to 3ab12f40c2a4 (1 revision) (flutter/engine#44756) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 586a6309e3a1 to cb3451491f11 (2 revisions) (flutter/engine#44755) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d22d161f16d4f..ee56a574cb1aa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e8670f03a9b163993d8162f5b7c0dbb8dc02bda7 +f186f1e9dc88429d657e9127a163dc99e2703ba7 From 2502b51f86c1dd3814420e117eee9786c7a8cbc9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 11:14:07 -0400 Subject: [PATCH 0746/1547] Roll Flutter Engine from f186f1e9dc88 to 70b5700b79f6 (1 revision) (#132655) https://github.com/flutter/engine/compare/f186f1e9dc88...70b5700b79f6 2023-08-16 skia-flutter-autoroll@skia.org Roll Dart SDK from 80b9a90ae563 to cc5eeac65f89 (1 revision) (flutter/engine#44758) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ee56a574cb1aa..e7c75508610d8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f186f1e9dc88429d657e9127a163dc99e2703ba7 +70b5700b79f6da03ecfb61f6d9135ca3eef51628 From 33ef5e413f53a6d1f73641683823154ab12845e2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 12:07:41 -0400 Subject: [PATCH 0747/1547] Roll Packages from 84218b9d834c to 9bf208f4beb6 (7 revisions) (#132659) https://github.com/flutter/packages/compare/84218b9d834c...9bf208f4beb6 2023-08-16 engine-flutter-autoroll@skia.org Manual roll Flutter from 9b6945b465a1 to f0e7c5181641 (63 revisions) (flutter/packages#4719) 2023-08-15 31859944+LongCatIsLooong@users.noreply.github.com Update palette_generator_test.dart (flutter/packages#4720) 2023-08-15 mit@google.com [pigeon] Fix typo in README.md (flutter/packages#4707) 2023-08-15 43054281+camsim99@users.noreply.github.com [camerax] Explicitly remove READ_EXTERNAL_STORAGE permission (flutter/packages#4716) 2023-08-15 10687576+bparrishMines@users.noreply.github.com [webview_flutter_platform_interface] Adds support for retrieving user agent (flutter/packages#4563) 2023-08-15 43054281+camsim99@users.noreply.github.com [camerax] Wrap classes to implement resolution configuration for video capture (flutter/packages#4620) 2023-08-15 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.3 to 2.21.4 (flutter/packages#4706) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 57754f9bd92b1..45e4e17a80cba 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -84218b9d834cd1d19d41a0b2079c9cdd1db67bd4 +9bf208f4beb6e4b8b26dd4df27871985f497cc5c From 99790cc8c044c40c698e92a568f1ae1246d88963 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Wed, 16 Aug 2023 09:44:11 -0700 Subject: [PATCH 0748/1547] Add more use cases to a11y assessments (#132325) see [go/flutter-gar-reporting-q3-2023](http://go/flutter-gar-reporting-q3-2023) --- .../lib/use_cases/date_picker.dart | 51 ++++++++++++++++ .../lib/use_cases/dialog.dart | 59 +++++++++++++++++++ .../lib/use_cases/slider.dart | 53 +++++++++++++++++ .../lib/use_cases/text_field.dart | 42 +++++++++++++ .../lib/use_cases/text_field_disabled.dart | 44 ++++++++++++++ .../lib/use_cases/text_field_password.dart | 42 +++++++++++++ .../lib/use_cases/use_cases.dart | 12 ++++ .../test/date_picker_test.dart | 20 +++++++ dev/a11y_assessments/test/dialog_test.dart | 23 ++++++++ dev/a11y_assessments/test/slider_test.dart | 22 +++++++ dev/a11y_assessments/test/test_utils.dart | 17 ++++++ .../test/text_field_disabled_test.dart | 23 ++++++++ .../test/text_field_password_test.dart | 22 +++++++ .../test/text_field_test.dart | 22 +++++++ 14 files changed, 452 insertions(+) create mode 100644 dev/a11y_assessments/lib/use_cases/date_picker.dart create mode 100644 dev/a11y_assessments/lib/use_cases/dialog.dart create mode 100644 dev/a11y_assessments/lib/use_cases/slider.dart create mode 100644 dev/a11y_assessments/lib/use_cases/text_field.dart create mode 100644 dev/a11y_assessments/lib/use_cases/text_field_disabled.dart create mode 100644 dev/a11y_assessments/lib/use_cases/text_field_password.dart create mode 100644 dev/a11y_assessments/test/date_picker_test.dart create mode 100644 dev/a11y_assessments/test/dialog_test.dart create mode 100644 dev/a11y_assessments/test/slider_test.dart create mode 100644 dev/a11y_assessments/test/test_utils.dart create mode 100644 dev/a11y_assessments/test/text_field_disabled_test.dart create mode 100644 dev/a11y_assessments/test/text_field_password_test.dart create mode 100644 dev/a11y_assessments/test/text_field_test.dart diff --git a/dev/a11y_assessments/lib/use_cases/date_picker.dart b/dev/a11y_assessments/lib/use_cases/date_picker.dart new file mode 100644 index 0000000000000..0a6b1e85563df --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/date_picker.dart @@ -0,0 +1,51 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class DatePickerUseCase extends UseCase { + + @override + String get name => 'DatePicker'; + + @override + String get route => '/date-picker'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatefulWidget { + const _MainWidget(); + + @override + State<_MainWidget> createState() => _MainWidgetState(); +} + +class _MainWidgetState extends State<_MainWidget> { + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('DatePicker'), + ), + body: Center( + child: TextButton( + onPressed: () => showDatePicker( + context: context, + initialEntryMode: DatePickerEntryMode.calendarOnly, + initialDate: DateTime.now(), + firstDate: DateTime.now().subtract(const Duration(days: 365)), + lastDate: DateTime.now().add(const Duration(days: 365)), + ), + child: const Text('Show Date Picker'), + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/dialog.dart b/dev/a11y_assessments/lib/use_cases/dialog.dart new file mode 100644 index 0000000000000..73ebddc5a97dd --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/dialog.dart @@ -0,0 +1,59 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class DialogUseCase extends UseCase { + + @override + String get name => 'Dialog'; + + @override + String get route => '/dialog'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('Dialog'), + ), + body: Center( + child: TextButton( + onPressed: () => showDialog( + context: context, + builder: (BuildContext context) => Dialog( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('This is a typical dialog.'), + const SizedBox(height: 15), + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('Close'), + ), + ], + ), + ), + ), + ), + child: const Text('Show Dialog'), + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/slider.dart b/dev/a11y_assessments/lib/use_cases/slider.dart new file mode 100644 index 0000000000000..a83261dbea3c5 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/slider.dart @@ -0,0 +1,53 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class SliderUseCase extends UseCase { + + @override + String get name => 'Slider'; + + @override + String get route => '/slider'; + + @override + Widget build(BuildContext context) => const MainWidget(); +} + +class MainWidget extends StatefulWidget { + const MainWidget({super.key}); + + @override + State createState() => MainWidgetState(); +} + +class MainWidgetState extends State { + double currentSliderValue = 20; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('Slider'), + ), + body: Center( + child: Slider( + value: currentSliderValue, + max: 100, + divisions: 5, + label: currentSliderValue.round().toString(), + onChanged: (double value) { + setState(() { + currentSliderValue = value; + }); + }, + ), + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/text_field.dart b/dev/a11y_assessments/lib/use_cases/text_field.dart new file mode 100644 index 0000000000000..3dd7e6eb16d8e --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/text_field.dart @@ -0,0 +1,42 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class TextFieldUseCase extends UseCase { + + @override + String get name => 'TextField'; + + @override + String get route => '/text-field'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('TextField'), + ), + body: const Center( + child: TextField( + decoration: InputDecoration( + labelText: 'Email', + suffixText: '@gmail.com', + hintText: 'Enter your email', + ), + ) + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart b/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart new file mode 100644 index 0000000000000..dcd20818001b3 --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart @@ -0,0 +1,44 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class TextFieldDisabledUseCase extends UseCase { + + @override + String get name => 'TextField disabled'; + + @override + String get route => '/text-field-disabled'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('TextField disabled'), + ), + body: Center( + child: TextField( + decoration: const InputDecoration( + labelText: 'Email', + suffixText: '@gmail.com', + hintText: 'Enter your email', + enabled: false, + ), + controller: TextEditingController(text: 'abc'), + ) + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/text_field_password.dart b/dev/a11y_assessments/lib/use_cases/text_field_password.dart new file mode 100644 index 0000000000000..5da9337cb6dfb --- /dev/null +++ b/dev/a11y_assessments/lib/use_cases/text_field_password.dart @@ -0,0 +1,42 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'use_cases.dart'; + +class TextFieldPasswordUseCase extends UseCase { + + @override + String get name => 'TextField password'; + + @override + String get route => '/text-field-password'; + + @override + Widget build(BuildContext context) => const _MainWidget(); +} + +class _MainWidget extends StatelessWidget { + const _MainWidget(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: const Text('TextField password'), + ), + body: const Center( + child: TextField( + decoration: InputDecoration( + labelText: 'Password', + hintText: 'Enter your password', + ), + obscureText: true, + ) + ), + ); + } +} diff --git a/dev/a11y_assessments/lib/use_cases/use_cases.dart b/dev/a11y_assessments/lib/use_cases/use_cases.dart index 139109fa64600..6099b87bc4931 100644 --- a/dev/a11y_assessments/lib/use_cases/use_cases.dart +++ b/dev/a11y_assessments/lib/use_cases/use_cases.dart @@ -6,6 +6,12 @@ import 'package:flutter/widgets.dart'; import 'check_box_list_tile.dart'; import 'check_box_list_tile_disabled.dart'; +import 'date_picker.dart'; +import 'dialog.dart'; +import 'slider.dart'; +import 'text_field.dart'; +import 'text_field_disabled.dart'; +import 'text_field_password.dart'; abstract class UseCase { String get name; @@ -16,4 +22,10 @@ abstract class UseCase { final List useCases = [ CheckBoxListTile(), CheckBoxListTileDisabled(), + DialogUseCase(), + SliderUseCase(), + TextFieldUseCase(), + TextFieldDisabledUseCase(), + TextFieldPasswordUseCase(), + DatePickerUseCase(), ]; diff --git a/dev/a11y_assessments/test/date_picker_test.dart b/dev/a11y_assessments/test/date_picker_test.dart new file mode 100644 index 0000000000000..a72c0ed7fd3aa --- /dev/null +++ b/dev/a11y_assessments/test/date_picker_test.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/date_picker.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('date picker can run', (WidgetTester tester) async { + await pumpsUseCase(tester, DatePickerUseCase()); + expect(find.text('Show Date Picker'), findsOneWidget); + + await tester.tap(find.text('Show Date Picker')); + await tester.pumpAndSettle(); + expect(find.byType(DatePickerDialog), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/dialog_test.dart b/dev/a11y_assessments/test/dialog_test.dart new file mode 100644 index 0000000000000..98d8c71bb7f91 --- /dev/null +++ b/dev/a11y_assessments/test/dialog_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/dialog.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('dialog can run', (WidgetTester tester) async { + await pumpsUseCase(tester, DialogUseCase()); + expect(find.text('Show Dialog'), findsOneWidget); + + await tester.tap(find.text('Show Dialog')); + await tester.pumpAndSettle(); + expect(find.text('This is a typical dialog.'), findsOneWidget); + + await tester.tap(find.text('Close')); + await tester.pumpAndSettle(); + expect(find.text('Show Dialog'), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/slider_test.dart b/dev/a11y_assessments/test/slider_test.dart new file mode 100644 index 0000000000000..a8769e844e03a --- /dev/null +++ b/dev/a11y_assessments/test/slider_test.dart @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/slider.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('slider can run', (WidgetTester tester) async { + await pumpsUseCase(tester, SliderUseCase()); + expect(find.byType(Slider), findsOneWidget); + + await tester.tapAt(tester.getCenter(find.byType(Slider))); + await tester.pumpAndSettle(); + + final MainWidgetState state = tester.state(find.byType(MainWidget)); + expect(state.currentSliderValue, 60); + }); +} diff --git a/dev/a11y_assessments/test/test_utils.dart b/dev/a11y_assessments/test/test_utils.dart new file mode 100644 index 0000000000000..8b2ae281dbeeb --- /dev/null +++ b/dev/a11y_assessments/test/test_utils.dart @@ -0,0 +1,17 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/use_cases.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +Future pumpsUseCase(WidgetTester tester, UseCase useCase) async { + await tester.pumpWidget(MaterialApp( + home: Builder( + builder: (BuildContext context) { + return useCase.build(context); + }, + ), + )); +} diff --git a/dev/a11y_assessments/test/text_field_disabled_test.dart b/dev/a11y_assessments/test/text_field_disabled_test.dart new file mode 100644 index 0000000000000..0a304b9ef5fec --- /dev/null +++ b/dev/a11y_assessments/test/text_field_disabled_test.dart @@ -0,0 +1,23 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/text_field_disabled.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('text field disabled can run', (WidgetTester tester) async { + await pumpsUseCase(tester, TextFieldDisabledUseCase()); + expect(find.byType(TextField), findsOneWidget); + expect(find.text('abc'), findsOneWidget); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextField), 'bde'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/text_field_password_test.dart b/dev/a11y_assessments/test/text_field_password_test.dart new file mode 100644 index 0000000000000..44a65a4e0023f --- /dev/null +++ b/dev/a11y_assessments/test/text_field_password_test.dart @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/text_field_password.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('text field password can run', (WidgetTester tester) async { + await pumpsUseCase(tester, TextFieldPasswordUseCase()); + expect(find.byType(TextField), findsOneWidget); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextField), 'abc'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + }); +} diff --git a/dev/a11y_assessments/test/text_field_test.dart b/dev/a11y_assessments/test/text_field_test.dart new file mode 100644 index 0000000000000..7623876edd6d5 --- /dev/null +++ b/dev/a11y_assessments/test/text_field_test.dart @@ -0,0 +1,22 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:a11y_assessments/use_cases/text_field.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'test_utils.dart'; + +void main() { + testWidgets('text field can run', (WidgetTester tester) async { + await pumpsUseCase(tester, TextFieldUseCase()); + expect(find.byType(TextField), findsOneWidget); + + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + await tester.enterText(find.byType(TextField), 'abc'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + }); +} From 371a9fc8359666fb86fdbf2ea200ed6b37e1e1b4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 13:33:44 -0400 Subject: [PATCH 0749/1547] Roll Flutter Engine from 70b5700b79f6 to 8f5f8b34c374 (2 revisions) (#132665) https://github.com/flutter/engine/compare/70b5700b79f6...8f5f8b34c374 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from f30893561924 to d029f149a806 (1 revision) (flutter/engine#44764) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 3ab12f40c2a4 to f30893561924 (1 revision) (flutter/engine#44761) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e7c75508610d8..171b20fde6673 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -70b5700b79f6da03ecfb61f6d9135ca3eef51628 +8f5f8b34c374ad8d5ae43d4af75b667d496e0e41 From 112f4293dc7239064bce8277fba18a923ecd61a6 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 16 Aug 2023 11:19:58 -0700 Subject: [PATCH 0750/1547] Fix some leaks and add test to test cover remaining in a simple way. (#131373) Contributes to https://github.com/flutter/flutter/issues/130467 Filed issue: https://github.com/flutter/flutter/issues/132620 --- .../src/widgets/context_menu_controller.dart | 1 + .../lib/src/widgets/text_selection.dart | 6 ++++ .../test/material/text_form_field_test.dart | 34 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/packages/flutter/lib/src/widgets/context_menu_controller.dart b/packages/flutter/lib/src/widgets/context_menu_controller.dart index df75571d46d44..6e29a2b0ad9bf 100644 --- a/packages/flutter/lib/src/widgets/context_menu_controller.dart +++ b/packages/flutter/lib/src/widgets/context_menu_controller.dart @@ -81,6 +81,7 @@ class ContextMenuController { /// * [remove], which removes only the current instance. static void removeAny() { _menuOverlayEntry?.remove(); + _menuOverlayEntry?.dispose(); _menuOverlayEntry = null; if (_shownInstance != null) { _shownInstance!.onRemove?.call(); diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 177c32f7c6315..adcba3a6ddea2 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -1371,7 +1371,9 @@ class SelectionOverlay { void hideHandles() { if (_handles != null) { _handles![0].remove(); + _handles![0].dispose(); _handles![1].remove(); + _handles![1].dispose(); _handles = null; } } @@ -1480,7 +1482,9 @@ class SelectionOverlay { _magnifierController.hide(); if (_handles != null) { _handles![0].remove(); + _handles![0].dispose(); _handles![1].remove(); + _handles![1].dispose(); _handles = null; } if (_toolbar != null || _contextMenuController.isShown || _spellCheckToolbarController.isShown) { @@ -1500,6 +1504,7 @@ class SelectionOverlay { return; } _toolbar?.remove(); + _toolbar?.dispose(); _toolbar = null; } @@ -1508,6 +1513,7 @@ class SelectionOverlay { /// {@endtemplate} void dispose() { hide(); + _magnifierInfo.dispose(); } Widget _buildStartHandle(BuildContext context) { diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 97323bf4e73f1..d830020fde290 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -251,6 +251,40 @@ void main() { leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true, allowAllNotGCed: true), ); + testWidgetsWithLeakTracking( + '$SelectionOverlay is not leaking', + (WidgetTester tester) async { + final TextEditingController controller = TextEditingController( + text: 'blah1 blah2', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: TextField( + controller: controller, + ), + ), + ), + ), + ); + + final Offset startBlah1 = textOffsetToPosition(tester, 0); + await tester.tapAt(startBlah1); + await tester.pump(const Duration(milliseconds: 100)); + await tester.tapAt(startBlah1); + await tester.pumpAndSettle(); + await tester.pump(); + controller.dispose(); + }, + skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/132620 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: {'_InputBorderGap' : 1}, + ), + ); + testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', From 06cb9a676a231cf18f490d7a632aac329edcec22 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 14:25:48 -0400 Subject: [PATCH 0751/1547] Roll Flutter Engine from 8f5f8b34c374 to dbfe71c898b6 (1 revision) (#132673) https://github.com/flutter/engine/compare/8f5f8b34c374...dbfe71c898b6 2023-08-16 zanderso@users.noreply.github.com Adds runIf to linux_clang_tidy (flutter/engine#44759) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 171b20fde6673..913b43c6f0592 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8f5f8b34c374ad8d5ae43d4af75b667d496e0e41 +dbfe71c898b6761af897574c297ce89623ce0d8c From 8617a18575a92db17129cdaec550cdd84a5cff18 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 15:36:49 -0400 Subject: [PATCH 0752/1547] Roll Flutter Engine from dbfe71c898b6 to 12cafaeb9e31 (1 revision) (#132677) https://github.com/flutter/engine/compare/dbfe71c898b6...12cafaeb9e31 2023-08-16 john@johnmccutchan.com Conditionally enable HardwareBuffer backed platform views (flutter/engine#44744) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 913b43c6f0592..6d72496699525 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -dbfe71c898b6761af897574c297ce89623ce0d8c +12cafaeb9e3113149e5d9fdfd136ee7cca9e91b2 From e52e8da303d25e70799068a54a4f813a26a07b5d Mon Sep 17 00:00:00 2001 From: yaakovschectman <109111084+yaakovschectman@users.noreply.github.com> Date: Wed, 16 Aug 2023 17:58:18 -0400 Subject: [PATCH 0753/1547] Revert "Roll Flutter Engine from dbfe71c898b6 to 12cafaeb9e31 (1 revision)" (#132698) Reverts flutter/flutter#132677 Causes failure for `Linux firebase_abstract_method_smoke_test` --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6d72496699525..913b43c6f0592 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -12cafaeb9e3113149e5d9fdfd136ee7cca9e91b2 +dbfe71c898b6761af897574c297ce89623ce0d8c From 14f9ed28d04c6b086f0b6d1289dc0248fc47a45f Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Wed, 16 Aug 2023 15:24:48 -0700 Subject: [PATCH 0754/1547] Analyze doc code snippets for all packages for which we publish docs (#132607) Fixes TODO in the analyzer script :) --- dev/bots/analyze_snippet_code.dart | 34 +++++++++++++------ examples/api/pubspec.yaml | 4 +++ .../lib/src/cupertino_localizations.dart | 20 ++++++----- .../lib/src/material_localizations.dart | 20 ++++++----- .../lib/src/navigation/url_strategy.dart | 6 ++-- .../src/navigation_non_web/url_strategy.dart | 12 ++++--- .../lib/src/plugin_registry.dart | 11 ++++++ 7 files changed, 74 insertions(+), 33 deletions(-) diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index 4b635c90586eb..b2bae35d7cdb3 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -61,6 +61,11 @@ // contains no explicit imports, the snippets will implicitly import all the // main Flutter packages (including material and flutter_test), as well as most // core Dart packages with the usual prefixes. +// +// When invoked without an additional path argument, the script will analyze +// the code snippets for all packages in the "packages" subdirectory that do +// not specify "nodoc: true" in their pubspec.yaml (i.e. all packages for which +// we publish docs will have their doc code snippets analyzed). import 'dart:async'; import 'dart:convert'; @@ -73,9 +78,6 @@ import 'package:watcher/watcher.dart'; final String _flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); final String _packageFlutter = path.join(_flutterRoot, 'packages', 'flutter', 'lib'); -final String _packageFlutterTest = path.join(_flutterRoot, 'packages', 'flutter_test', 'lib'); -final String _packageFlutterDriver = path.join(_flutterRoot, 'packages', 'flutter_driver', 'lib'); -final String _packageIntegrationTest = path.join(_flutterRoot, 'packages', 'integration_test', 'lib'); final String _defaultDartUiLocation = path.join(_flutterRoot, 'bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui'); final String _flutter = path.join(_flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); @@ -147,18 +149,28 @@ Future main(List arguments) async { exit(0); } - List flutterPackages; + final List flutterPackages; if (parsedArguments.rest.length == 1) { // Used for testing. flutterPackages = [Directory(parsedArguments.rest.single)]; } else { - flutterPackages = [ - Directory(_packageFlutter), - Directory(_packageFlutterTest), - Directory(_packageIntegrationTest), - Directory(_packageFlutterDriver), - // TODO(goderbauer): Add all other packages for which we publish docs. - ]; + // By default analyze snippets in all packages in the packages subdirectory + // that do not specify "nodoc: true" in their pubspec.yaml. + flutterPackages = []; + final String packagesRoot = path.join(_flutterRoot, 'packages'); + for (final FileSystemEntity entity in Directory(packagesRoot).listSync()) { + if (entity is! Directory) { + continue; + } + final File pubspec = File(path.join(entity.path, 'pubspec.yaml')); + if (!pubspec.existsSync()) { + throw StateError("Unexpected package '${entity.path}' found in packages directory"); + } + if (!pubspec.readAsStringSync().contains('nodoc: true')) { + flutterPackages.add(Directory(path.join(entity.path, 'lib'))); + } + } + assert(flutterPackages.length >= 4); } final bool includeDartUi = parsedArguments.wasParsed('dart-ui-location') || parsedArguments['include-dart-ui'] as bool; diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index ccfd967cf3f2d..bd46437270834 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -29,8 +29,12 @@ dev_dependencies: sdk: flutter flutter_goldens: sdk: flutter + flutter_localizations: + sdk: flutter flutter_test: sdk: flutter + flutter_web_plugins: + sdk: flutter test: 1.24.6 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" diff --git a/packages/flutter_localizations/lib/src/cupertino_localizations.dart b/packages/flutter_localizations/lib/src/cupertino_localizations.dart index 4efbfb671c651..68a5c0bc8b0bd 100644 --- a/packages/flutter_localizations/lib/src/cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/cupertino_localizations.dart @@ -10,6 +10,10 @@ import 'l10n/generated_cupertino_localizations.dart'; import 'utils/date_localizations.dart' as util; import 'widgets_localizations.dart'; +// Examples can assume: +// import 'package:flutter_localizations/flutter_localizations.dart'; +// import 'package:flutter/cupertino.dart'; + /// Implementation of localized strings for Cupertino widgets using the `intl` /// package for date and time formatting. /// @@ -32,11 +36,11 @@ import 'widgets_localizations.dart'; /// app supports with [CupertinoApp.supportedLocales]: /// /// ```dart -/// CupertinoApp( +/// const CupertinoApp( /// localizationsDelegates: GlobalCupertinoLocalizations.delegates, -/// supportedLocales: [ -/// const Locale('en', 'US'), // American English -/// const Locale('he', 'IL'), // Israeli Hebrew +/// supportedLocales: [ +/// Locale('en', 'US'), // American English +/// Locale('he', 'IL'), // Israeli Hebrew /// // ... /// ], /// // ... @@ -432,11 +436,11 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations { /// app supports with [CupertinoApp.supportedLocales]: /// /// ```dart - /// CupertinoApp( + /// const CupertinoApp( /// localizationsDelegates: GlobalCupertinoLocalizations.delegates, - /// supportedLocales: [ - /// const Locale('en', 'US'), // English - /// const Locale('he', 'IL'), // Hebrew + /// supportedLocales: [ + /// Locale('en', 'US'), // English + /// Locale('he', 'IL'), // Hebrew /// ], /// // ... /// ) diff --git a/packages/flutter_localizations/lib/src/material_localizations.dart b/packages/flutter_localizations/lib/src/material_localizations.dart index 477940e384972..e415db1726ba7 100644 --- a/packages/flutter_localizations/lib/src/material_localizations.dart +++ b/packages/flutter_localizations/lib/src/material_localizations.dart @@ -11,6 +11,10 @@ import 'l10n/generated_material_localizations.dart'; import 'utils/date_localizations.dart' as util; import 'widgets_localizations.dart'; +// Examples can assume: +// import 'package:flutter_localizations/flutter_localizations.dart'; +// import 'package:flutter/material.dart'; + /// Implementation of localized strings for the material widgets using the /// `intl` package for date and time formatting. /// @@ -30,11 +34,11 @@ import 'widgets_localizations.dart'; /// app supports with [MaterialApp.supportedLocales]: /// /// ```dart -/// MaterialApp( +/// const MaterialApp( /// localizationsDelegates: GlobalMaterialLocalizations.delegates, -/// supportedLocales: [ -/// const Locale('en', 'US'), // American English -/// const Locale('he', 'IL'), // Israeli Hebrew +/// supportedLocales: [ +/// Locale('en', 'US'), // American English +/// Locale('he', 'IL'), // Israeli Hebrew /// // ... /// ], /// // ... @@ -681,11 +685,11 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations { /// app supports with [MaterialApp.supportedLocales]: /// /// ```dart - /// MaterialApp( + /// const MaterialApp( /// localizationsDelegates: GlobalMaterialLocalizations.delegates, - /// supportedLocales: [ - /// const Locale('en', 'US'), // English - /// const Locale('he', 'IL'), // Hebrew + /// supportedLocales: [ + /// Locale('en', 'US'), // English + /// Locale('he', 'IL'), // Hebrew /// ], /// // ... /// ) diff --git a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart index 427942a4a8d32..e0f0dbeaa81b8 100644 --- a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart @@ -34,8 +34,10 @@ void usePathUrlStrategy() { /// ```dart /// import 'package:flutter_web_plugins/flutter_web_plugins.dart'; /// -/// // Somewhere before calling `runApp()` do: -/// setUrlStrategy(PathUrlStrategy()); +/// void main() { +/// // Somewhere before calling `runApp()` do: +/// setUrlStrategy(PathUrlStrategy()); +/// } /// ``` class PathUrlStrategy extends ui_web.HashUrlStrategy { /// Creates an instance of [PathUrlStrategy]. diff --git a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart index f9622608bdac5..0a4703b8120b7 100644 --- a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart @@ -99,8 +99,10 @@ void usePathUrlStrategy() { /// ```dart /// import 'package:flutter_web_plugins/flutter_web_plugins.dart'; /// -/// // Somewhere before calling `runApp()` do: -/// setUrlStrategy(const HashUrlStrategy()); +/// void main() { +/// // Somewhere before calling `runApp()` do: +/// setUrlStrategy(const HashUrlStrategy()); +/// } /// ``` class HashUrlStrategy extends UrlStrategy { /// Creates an instance of [HashUrlStrategy]. @@ -117,8 +119,10 @@ class HashUrlStrategy extends UrlStrategy { /// ```dart /// import 'package:flutter_web_plugins/flutter_web_plugins.dart'; /// -/// // Somewhere before calling `runApp()` do: -/// setUrlStrategy(PathUrlStrategy()); +/// void main() { +/// // Somewhere before calling `runApp()` do: +/// setUrlStrategy(PathUrlStrategy()); +/// } /// ``` class PathUrlStrategy extends HashUrlStrategy { /// Creates an instance of [PathUrlStrategy]. diff --git a/packages/flutter_web_plugins/lib/src/plugin_registry.dart b/packages/flutter_web_plugins/lib/src/plugin_registry.dart index 78108b9699c39..a6ff602a43220 100644 --- a/packages/flutter_web_plugins/lib/src/plugin_registry.dart +++ b/packages/flutter_web_plugins/lib/src/plugin_registry.dart @@ -9,6 +9,12 @@ import 'dart:ui_web' as ui_web; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +// Examples can assume: +// import 'package:flutter_web_plugins/flutter_web_plugins.dart'; +// import 'package:flutter/services.dart'; +// import 'dart:ui_web' as ui_web; +// void handleFrameworkMessage(String name, ByteData? data, PlatformMessageResponseCallback? callback) { } + /// A registrar for Flutter plugins implemented in Dart. /// /// Plugins for the web platform are implemented in Dart and are @@ -32,6 +38,11 @@ import 'package:flutter/services.dart'; /// final MyPlugin instance = MyPlugin(); /// channel.setMethodCallHandler(instance.handleMethodCall); /// } +/// +/// Future handleMethodCall(MethodCall call) async { +/// // ... +/// } +/// /// // ... /// } /// ``` From 223ae5d3acff1fd97d4dd0f5ea66b1bcf8b04c61 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 16 Aug 2023 15:24:51 -0700 Subject: [PATCH 0755/1547] Add support for LOCAL_ENGINE_HOST to Linux/Mac/Win builds. (#132579) Partial work towards https://github.com/flutter/flutter/issues/132245. I also couldn't help myself to do a very minor refactor and add some comments to `LocalEngineInfo` because I was getting confused myself implementing it. --- .../flutter_tools/lib/src/android/gradle.dart | 20 ++--- packages/flutter_tools/lib/src/artifacts.dart | 82 ++++++++++++------- .../flutter_tools/lib/src/build_info.dart | 4 +- .../lib/src/ios/xcode_build_settings.dart | 7 +- .../lib/src/linux/build_linux.dart | 8 +- .../lib/src/windows/build_windows.dart | 8 +- .../test/general.shard/artifacts_test.dart | 35 +++++++- .../test/general.shard/build_info_test.dart | 17 +++- 8 files changed, 127 insertions(+), 54 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 3a456dc48fcd2..6341cc173d752 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -390,20 +390,20 @@ class AndroidGradleBuilder implements AndroidBuilder { final LocalEngineInfo? localEngineInfo = _artifacts.localEngineInfo; if (localEngineInfo != null) { final Directory localEngineRepo = _getLocalEngineRepo( - engineOutPath: localEngineInfo.engineOutPath, + engineOutPath: localEngineInfo.targetOutPath, androidBuildInfo: androidBuildInfo, fileSystem: _fileSystem, ); _logger.printTrace( - 'Using local engine: ${localEngineInfo.engineOutPath}\n' + 'Using local engine: ${localEngineInfo.targetOutPath}\n' 'Local Maven repo: ${localEngineRepo.path}' ); command.add('-Plocal-engine-repo=${localEngineRepo.path}'); command.add('-Plocal-engine-build-mode=${buildInfo.modeName}'); - command.add('-Plocal-engine-out=${localEngineInfo.engineOutPath}'); - command.add('-Plocal-engine-host-out=${localEngineInfo.engineHostOutPath}'); + command.add('-Plocal-engine-out=${localEngineInfo.targetOutPath}'); + command.add('-Plocal-engine-host-out=${localEngineInfo.hostOutPath}'); command.add('-Ptarget-platform=${_getTargetPlatformByLocalEnginePath( - localEngineInfo.engineOutPath)}'); + localEngineInfo.targetOutPath)}'); } else if (androidBuildInfo.targetArchs.isNotEmpty) { final String targetPlatforms = androidBuildInfo .targetArchs @@ -716,18 +716,18 @@ class AndroidGradleBuilder implements AndroidBuilder { final LocalEngineInfo? localEngineInfo = _artifacts.localEngineInfo; if (localEngineInfo != null) { final Directory localEngineRepo = _getLocalEngineRepo( - engineOutPath: localEngineInfo.engineOutPath, + engineOutPath: localEngineInfo.targetOutPath, androidBuildInfo: androidBuildInfo, fileSystem: _fileSystem, ); _logger.printTrace( - 'Using local engine: ${localEngineInfo.engineOutPath}\n' + 'Using local engine: ${localEngineInfo.targetOutPath}\n' 'Local Maven repo: ${localEngineRepo.path}' ); command.add('-Plocal-engine-repo=${localEngineRepo.path}'); command.add('-Plocal-engine-build-mode=${buildInfo.modeName}'); - command.add('-Plocal-engine-out=${localEngineInfo.engineOutPath}'); - command.add('-Plocal-engine-host-out=${localEngineInfo.engineHostOutPath}'); + command.add('-Plocal-engine-out=${localEngineInfo.targetOutPath}'); + command.add('-Plocal-engine-host-out=${localEngineInfo.hostOutPath}'); // Copy the local engine repo in the output directory. try { @@ -742,7 +742,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ); } command.add('-Ptarget-platform=${_getTargetPlatformByLocalEnginePath( - localEngineInfo.engineOutPath)}'); + localEngineInfo.targetOutPath)}'); } else if (androidBuildInfo.targetArchs.isNotEmpty) { final String targetPlatforms = androidBuildInfo.targetArchs .map((AndroidArch e) => e.platformName).join(','); diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 97e6e1da9f6b8..8775db6fec1f1 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -284,17 +284,40 @@ class EngineBuildPaths { final String? webSdk; } -/// Information about a local engine build +/// Information about a local engine build (i.e. `--local-engine[-host]=...`). +/// +/// See https://github.com/flutter/flutter/wiki/The-flutter-tool#using-a-locally-built-engine-with-the-flutter-tool +/// for more information about local engine builds. class LocalEngineInfo { + /// Creates a reference to a local engine build. + /// + /// The [targetOutPath] and [hostOutPath] are assumed to be resolvable + /// paths to the built engine artifacts for the target (device) and host + /// (build) platforms, respectively. const LocalEngineInfo({ - required this.engineOutPath, - required this.engineHostOutPath, - required this.localEngineName, + required this.targetOutPath, + required this.hostOutPath, }); - final String engineOutPath; - final String engineHostOutPath; - final String localEngineName; + /// The path to the engine artifacts for the target (device) platform. + /// + /// For example, if the target platform is Android debug, this would be a path + /// like `/path/to/engine/src/out/android_debug_unopt`. To retrieve just the + /// name (platform), see [localTargetName]. + final String targetOutPath; + + /// The path to the engine artifacts for the host (build) platform. + /// + /// For example, if the host platform is debug, this would be a path like + /// `/path/to/engine/src/out/host_debug_unopt`. To retrieve just the name + /// (platform), see [localHostName]. + final String hostOutPath; + + /// The name of the target (device) platform, i.e. `android_debug_unopt`. + String get localTargetName => globals.fs.path.basename(targetOutPath); + + /// The name of the host (build) platform, e.g. `host_debug_unopt`. + String get localHostName => globals.fs.path.basename(hostOutPath); } // Manages the engine artifacts of Flutter. @@ -824,9 +847,8 @@ class CachedLocalEngineArtifacts implements Artifacts { }) : _fileSystem = fileSystem, localEngineInfo = LocalEngineInfo( - engineOutPath: engineOutPath, - engineHostOutPath: _hostEngineOutPath, - localEngineName: fileSystem.path.basename(engineOutPath) + targetOutPath: engineOutPath, + hostOutPath: _hostEngineOutPath, ), _cache = cache, _processManager = processManager, @@ -937,28 +959,28 @@ class CachedLocalEngineArtifacts implements Artifacts { return _flutterTesterPath(platform!); case Artifact.isolateSnapshotData: case Artifact.vmSnapshotData: - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', artifactFileName); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'gen', 'flutter', 'lib', 'snapshot', artifactFileName); case Artifact.icuData: case Artifact.flutterXcframework: case Artifact.flutterMacOSFramework: - return _fileSystem.path.join(localEngineInfo.engineOutPath, artifactFileName); + return _fileSystem.path.join(localEngineInfo.targetOutPath, artifactFileName); case Artifact.platformKernelDill: if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) { - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'flutter_runner_patched_sdk', artifactFileName); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_runner_patched_sdk', artifactFileName); } return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), artifactFileName); case Artifact.platformLibrariesJson: return _fileSystem.path.join(_getFlutterPatchedSdkPath(mode), 'lib', artifactFileName); case Artifact.flutterFramework: return _getIosEngineArtifactPath( - localEngineInfo.engineOutPath, environmentType, _fileSystem, _platform); + localEngineInfo.targetOutPath, environmentType, _fileSystem, _platform); case Artifact.flutterPatchedSdkPath: // When using local engine always use [BuildMode.debug] regardless of // what was specified in [mode] argument because local engine will // have only one flutter_patched_sdk in standard location, that // is happen to be what debug(non-release) mode is using. if (platform == TargetPlatform.fuchsia_x64 || platform == TargetPlatform.fuchsia_arm64) { - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'flutter_runner_patched_sdk'); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_runner_patched_sdk'); } return _getFlutterPatchedSdkPath(BuildMode.debug); case Artifact.skyEnginePath: @@ -967,11 +989,11 @@ class CachedLocalEngineArtifacts implements Artifacts { final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform()); final String modeName = mode!.isRelease ? 'release' : mode.toString(); final String dartBinaries = 'dart_binaries-$modeName-$hostPlatform'; - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot'); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot'); case Artifact.fuchsiaFlutterRunner: final String jitOrAot = mode!.isJit ? '_jit' : '_aot'; final String productOrNo = mode.isRelease ? '_product' : ''; - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far'); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far'); case Artifact.fontSubset: return _fileSystem.path.join(_hostEngineOutPath, artifactFileName); case Artifact.constFinder: @@ -999,11 +1021,11 @@ class CachedLocalEngineArtifacts implements Artifacts { @override String getEngineType(TargetPlatform platform, [ BuildMode? mode ]) { - return _fileSystem.path.basename(localEngineInfo.engineOutPath); + return _fileSystem.path.basename(localEngineInfo.targetOutPath); } String _getFlutterPatchedSdkPath(BuildMode? buildMode) { - return _fileSystem.path.join(localEngineInfo.engineOutPath, + return _fileSystem.path.join(localEngineInfo.targetOutPath, buildMode == BuildMode.release ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk'); } @@ -1053,14 +1075,14 @@ class CachedLocalEngineArtifacts implements Artifacts { } String _getFlutterWebSdkPath() { - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'flutter_web_sdk'); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_web_sdk'); } String _genSnapshotPath() { const List clangDirs = ['.', 'clang_x64', 'clang_x86', 'clang_i386', 'clang_arm64']; final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot, _platform)!; for (final String clangDir in clangDirs) { - final String genSnapshotPath = _fileSystem.path.join(localEngineInfo.engineOutPath, clangDir, genSnapshotName); + final String genSnapshotPath = _fileSystem.path.join(localEngineInfo.targetOutPath, clangDir, genSnapshotName); if (_processManager.canRun(genSnapshotPath)) { return genSnapshotPath; } @@ -1070,11 +1092,11 @@ class CachedLocalEngineArtifacts implements Artifacts { String _flutterTesterPath(TargetPlatform platform) { if (_platform.isLinux) { - return _fileSystem.path.join(localEngineInfo.engineOutPath, _artifactToFileName(Artifact.flutterTester, _platform)); + return _fileSystem.path.join(localEngineInfo.targetOutPath, _artifactToFileName(Artifact.flutterTester, _platform)); } else if (_platform.isMacOS) { - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'flutter_tester'); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_tester'); } else if (_platform.isWindows) { - return _fileSystem.path.join(localEngineInfo.engineOutPath, 'flutter_tester.exe'); + return _fileSystem.path.join(localEngineInfo.targetOutPath, 'flutter_tester.exe'); } throw Exception('Unsupported platform $platform.'); } @@ -1381,11 +1403,13 @@ class _TestArtifacts implements Artifacts { class _TestLocalEngine extends _TestArtifacts { _TestLocalEngine( - String engineOutPath, String engineHostOutPath, super.fileSystem) - : localEngineInfo = LocalEngineInfo( - engineOutPath: engineOutPath, - engineHostOutPath: engineHostOutPath, - localEngineName: fileSystem.path.basename(engineOutPath)); + String engineOutPath, + String engineHostOutPath, + super.fileSystem, + ) : localEngineInfo = LocalEngineInfo( + targetOutPath: engineOutPath, + hostOutPath: engineHostOutPath, + ); @override bool get isLocalEngine => true; diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 053197c8f1a17..5dcc2948b1688 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -647,7 +647,7 @@ List defaultIOSArchsForEnvironment( // Handle single-arch local engines. final LocalEngineInfo? localEngineInfo = artifacts.localEngineInfo; if (localEngineInfo != null) { - final String localEngineName = localEngineInfo.localEngineName; + final String localEngineName = localEngineInfo.localTargetName; if (localEngineName.contains('_arm64')) { return [ DarwinArch.arm64 ]; } @@ -670,7 +670,7 @@ List defaultMacOSArchsForEnvironment(Artifacts artifacts) { // Handle single-arch local engines. final LocalEngineInfo? localEngineInfo = artifacts.localEngineInfo; if (localEngineInfo != null) { - if (localEngineInfo.localEngineName.contains('_arm64')) { + if (localEngineInfo.localTargetName.contains('_arm64')) { return [ DarwinArch.arm64 ]; } return [ DarwinArch.x86_64 ]; diff --git a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart index 0e7c42b9f34d2..df53b38695671 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -181,12 +181,15 @@ Future> _xcodeBuildSettingsLines({ final LocalEngineInfo? localEngineInfo = globals.artifacts?.localEngineInfo; if (localEngineInfo != null) { - final String engineOutPath = localEngineInfo.engineOutPath; + final String engineOutPath = localEngineInfo.targetOutPath; xcodeBuildSettings.add('FLUTTER_ENGINE=${globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath))}'); - final String localEngineName = localEngineInfo.localEngineName; + final String localEngineName = localEngineInfo.localTargetName; xcodeBuildSettings.add('LOCAL_ENGINE=$localEngineName'); + final String localEngineHostName = localEngineInfo.localHostName; + xcodeBuildSettings.add('LOCAL_ENGINE_HOST=$localEngineHostName'); + // Tell Xcode not to build universal binaries for local engines, which are // single-architecture. // diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 81a8d775ddb63..410416aa63062 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -56,9 +56,11 @@ Future buildLinux( environmentConfig['FLUTTER_TARGET'] = target; final LocalEngineInfo? localEngineInfo = globals.artifacts?.localEngineInfo; if (localEngineInfo != null) { - final String engineOutPath = localEngineInfo.engineOutPath; - environmentConfig['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); - environmentConfig['LOCAL_ENGINE'] = localEngineInfo.localEngineName; + final String targetOutPath = localEngineInfo.targetOutPath; + // $ENGINE/src/out/foo_bar_baz -> $ENGINE/src + environmentConfig['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(targetOutPath)); + environmentConfig['LOCAL_ENGINE'] = localEngineInfo.localTargetName; + environmentConfig['LOCAL_ENGINE_HOST'] = localEngineInfo.localHostName; } writeGeneratedCmakeConfig(Cache.flutterRoot!, linuxProject, buildInfo, environmentConfig, logger); diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index c63b1dc3bc601..a665856d0cc45 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -247,9 +247,11 @@ void _writeGeneratedFlutterConfig( }; final LocalEngineInfo? localEngineInfo = globals.artifacts?.localEngineInfo; if (localEngineInfo != null) { - final String engineOutPath = localEngineInfo.engineOutPath; - environment['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(engineOutPath)); - environment['LOCAL_ENGINE'] = localEngineInfo.localEngineName; + final String targetOutPath = localEngineInfo.targetOutPath; + // Get the engine source root $ENGINE/src/out/foo_bar_baz -> $ENGINE/src + environment['FLUTTER_ENGINE'] = globals.fs.path.dirname(globals.fs.path.dirname(targetOutPath)); + environment['LOCAL_ENGINE'] = localEngineInfo.localTargetName; + environment['LOCAL_ENGINE_HOST'] = localEngineInfo.localHostName; } writeGeneratedCmakeConfig(Cache.flutterRoot!, windowsProject, buildInfo, environment, globals.logger); } diff --git a/packages/flutter_tools/test/general.shard/artifacts_test.dart b/packages/flutter_tools/test/general.shard/artifacts_test.dart index b6afa09955448..920980a23ba2f 100644 --- a/packages/flutter_tools/test/general.shard/artifacts_test.dart +++ b/packages/flutter_tools/test/general.shard/artifacts_test.dart @@ -11,7 +11,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import '../src/common.dart'; -import '../src/fake_process_manager.dart'; +import '../src/context.dart'; import '../src/fakes.dart'; void main() { @@ -545,4 +545,37 @@ void main() { ); }); }); + + group('LocalEngineInfo', () { + late FileSystem fileSystem; + late LocalEngineInfo localEngineInfo; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + }); + + testUsingContext('determines the target device name from the path', () { + localEngineInfo = LocalEngineInfo( + targetOutPath: fileSystem.path.join(fileSystem.currentDirectory.path, 'out', 'android_debug_unopt'), + hostOutPath: fileSystem.path.join(fileSystem.currentDirectory.path, 'out', 'host_debug_unopt'), + ); + + expect(localEngineInfo.localTargetName, 'android_debug_unopt'); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('determines the target device name from the path when using a custom engine path', () { + localEngineInfo = LocalEngineInfo( + targetOutPath: fileSystem.path.join(fileSystem.currentDirectory.path, 'out', 'android_debug_unopt'), + hostOutPath: fileSystem.path.join(fileSystem.currentDirectory.path, 'out', 'host_debug_unopt'), + ); + + expect(localEngineInfo.localHostName, 'host_debug_unopt'); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + }); } diff --git a/packages/flutter_tools/test/general.shard/build_info_test.dart b/packages/flutter_tools/test/general.shard/build_info_test.dart index eef8e9c10f42c..929ce64cd41c8 100644 --- a/packages/flutter_tools/test/general.shard/build_info_test.dart +++ b/packages/flutter_tools/test/general.shard/build_info_test.dart @@ -2,7 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:file/memory.dart'; + import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -101,7 +104,7 @@ void main() { expect(getNameForTargetPlatform(TargetPlatform.android), isNot(contains('ios'))); }); - testWithoutContext('defaultIOSArchsForEnvironment', () { + testUsingContext('defaultIOSArchsForEnvironment', () { expect(defaultIOSArchsForEnvironment( EnvironmentType.physical, Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'ios_debug_unopt'), @@ -124,9 +127,12 @@ void main() { expect(defaultIOSArchsForEnvironment( EnvironmentType.simulator, Artifacts.test(), ), [ DarwinArch.x86_64, DarwinArch.arm64 ]); - }); + }, overrides: { + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + }); - testWithoutContext('defaultMacOSArchsForEnvironment', () { + testUsingContext('defaultMacOSArchsForEnvironment', () { expect(defaultMacOSArchsForEnvironment( Artifacts.testLocalEngine(localEngineHost: 'host_debug_unopt', localEngine: 'host_debug_unopt'), ).single, DarwinArch.x86_64); @@ -138,7 +144,10 @@ void main() { expect(defaultMacOSArchsForEnvironment( Artifacts.test(), ), [ DarwinArch.x86_64, DarwinArch.arm64 ]); - }); + }, overrides: { + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + }); testWithoutContext('getIOSArchForName on Darwin arches', () { expect(getIOSArchForName('armv7'), DarwinArch.armv7); From 0ea523cf9318a33932d012b0355a24b8157d0a33 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 16 Aug 2023 15:38:59 -0700 Subject: [PATCH 0756/1547] Fix not-disposed _InputBorderGap. (#132694) Fixes: https://github.com/flutter/flutter/issues/132620 --- packages/flutter/lib/src/material/input_decorator.dart | 1 + packages/flutter/test/material/text_form_field_test.dart | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index ecfd98ab8568d..dd1e2bdf34dc5 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -1956,6 +1956,7 @@ class _InputDecoratorState extends State with TickerProviderStat void dispose() { _floatingLabelController.dispose(); _shakingLabelController.dispose(); + _borderGap.dispose(); super.dispose(); } diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index d830020fde290..f95f8bfaaa535 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -243,6 +243,7 @@ void main() { expect(controller.text, ' blah2blah1'); expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 0)); expect(find.byType(CupertinoButton), findsNothing); + controller.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.windows }), skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. @@ -278,11 +279,6 @@ void main() { controller.dispose(); }, skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/132620 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: {'_InputBorderGap' : 1}, - ), ); testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { From 2cb762d15407d0beaaf4b8141759df8017eb9a09 Mon Sep 17 00:00:00 2001 From: Faisal Ansari <61263149+faisalansari0367@users.noreply.github.com> Date: Thu, 17 Aug 2023 04:33:21 +0530 Subject: [PATCH 0757/1547] fixed documentation error input decorator (#132124) In the documentation of _Shaker in InputDecoration "Used to "shake" the floating label to the left and right" to the left was twice I have removed it. --- packages/flutter/lib/src/material/input_decorator.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index dd1e2bdf34dc5..c1dbc0988cf01 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -260,7 +260,7 @@ class _BorderContainerState extends State<_BorderContainer> with TickerProviderS } } -// Used to "shake" the floating label to the left to the left and right +// Used to "shake" the floating label to the left and right // when the errorText first appears. class _Shaker extends AnimatedWidget { const _Shaker({ From 0e15ab54d1b05e8f21153180a4719056127c0e8e Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Wed, 16 Aug 2023 16:05:16 -0700 Subject: [PATCH 0758/1547] Triple tap selection should not move beyond text boundary at the tapped location (#132357) This PR makes sure we do not select beyond the text boundary at the tapped position unless, we tap at the end of the text which in that case we should select the previous text boundary. ```dart // if x is a boundary defined by `textBoundary`, most textBoundaries (except // LineBreaker) guarantees `x == textBoundary.getLeadingTextBoundaryAt(x)`. // Use x - 1 here to make sure we don't get stuck at the fixed point x. final int start = textBoundary.getLeadingTextBoundaryAt(extent.offset - 1) ?? 0; ``` This was originally carried over from https://github.com/flutter/flutter/blob/f468f3366c26a5092eb964a230ce7892fda8f2f8/packages/flutter/lib/src/widgets/editable_text.dart#L4167-L4179 which used this `x - 1` to be able to move to the previous word boundary when navigating with a keyboard. When selecting by tapping/clicking we do not want to move past the text boundary at the tapped position so this adjustment is not needed. Fixes #132126 --- .../lib/src/widgets/text_selection.dart | 17 ++- .../test/cupertino/text_field_test.dart | 115 ++++++++++++++++++ .../test/material/text_field_test.dart | 111 +++++++++++++++++ 3 files changed, 234 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index adcba3a6ddea2..274150aa49de2 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -2567,14 +2567,13 @@ class TextSelectionGestureDetectorBuilder { _selectTextBoundariesInRange(boundary: lineBoundary, from: from, to: to, cause: cause); } - // Returns the closest boundary location to `extent` but not including `extent` - // itself. - TextRange _moveBeyondTextBoundary(TextPosition extent, TextBoundary textBoundary) { + // Returns the location of a text boundary at `extent`. When `extent` is at + // the end of the text, returns the previous text boundary's location. + TextRange _moveToTextBoundary(TextPosition extent, TextBoundary textBoundary) { assert(extent.offset >= 0); - // if x is a boundary defined by `textBoundary`, most textBoundaries (except - // LineBreaker) guarantees `x == textBoundary.getLeadingTextBoundaryAt(x)`. - // Use x - 1 here to make sure we don't get stuck at the fixed point x. - final int start = textBoundary.getLeadingTextBoundaryAt(extent.offset - 1) ?? 0; + // Use extent.offset - 1 when `extent` is at the end of the text to retrieve + // the previous text boundary's location. + final int start = textBoundary.getLeadingTextBoundaryAt(extent.offset == editableText.textEditingValue.text.length ? extent.offset - 1 : extent.offset) ?? 0; final int end = textBoundary.getTrailingTextBoundaryAt(extent.offset) ?? editableText.textEditingValue.text.length; return TextRange(start: start, end: end); } @@ -2589,13 +2588,13 @@ class TextSelectionGestureDetectorBuilder { // beginning and end of a text boundary respectively. void _selectTextBoundariesInRange({required TextBoundary boundary, required Offset from, Offset? to, SelectionChangedCause? cause}) { final TextPosition fromPosition = renderEditable.getPositionForPoint(from); - final TextRange fromRange = _moveBeyondTextBoundary(fromPosition, boundary); + final TextRange fromRange = _moveToTextBoundary(fromPosition, boundary); final TextPosition toPosition = to == null ? fromPosition : renderEditable.getPositionForPoint(to); final TextRange toRange = toPosition == fromPosition ? fromRange - : _moveBeyondTextBoundary(toPosition, boundary); + : _moveToTextBoundary(toPosition, boundary); final bool isFromBoundaryBeforeToBoundary = fromRange.start < toRange.end; final TextSelection newSelection = isFromBoundaryBeforeToBoundary diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index 2bc31a4dabeee..e9fc95e818357 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -3804,6 +3804,121 @@ void main() { variant: TargetPlatformVariant.mobile(), ); + testWidgets( + 'Triple click at the beginning of a line should not select the previous paragraph', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132126 + final TextEditingController controller = TextEditingController(); + + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + dragStartBehavior: DragStartBehavior.down, + controller: controller, + maxLines: null, + ), + ), + ), + ); + + await tester.enterText(find.byType(CupertinoTextField), testValueB); + // Skip past scrolling animation. + await tester.pump(); + await tester.pump(const Duration(milliseconds: 200)); + expect(controller.value.text, testValueB); + + final Offset thirdLinePos = textOffsetToPosition(tester, 38); + + // Click on text field to gain focus, and move the selection. + final TestGesture gesture = await tester.startGesture(thirdLinePos, kind: PointerDeviceKind.mouse); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + expect(controller.selection.isCollapsed, true); + expect(controller.selection.baseOffset, 38); + + // Here we click on same position again, to register a double click. This will select + // the word at the clicked position. + await gesture.down(thirdLinePos); + await gesture.up(); + + expect(controller.selection.baseOffset, 38); + expect(controller.selection.extentOffset, 40); + + // Here we click on same position again, to register a triple click. This will select + // the paragraph at the clicked position. + await gesture.down(thirdLinePos); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await tester.pumpAndSettle(); + + expect(controller.selection.baseOffset, 38); + expect(controller.selection.extentOffset, 57); + }, + variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), + ); + + testWidgets( + 'Triple click at the end of text should select the previous paragraph', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132126. + final TextEditingController controller = TextEditingController(); + + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: CupertinoTextField( + dragStartBehavior: DragStartBehavior.down, + controller: controller, + maxLines: null, + ), + ), + ), + ); + + await tester.enterText(find.byType(CupertinoTextField), testValueB); + // Skip past scrolling animation. + await tester.pump(); + await tester.pump(const Duration(milliseconds: 200)); + expect(controller.value.text, testValueB); + + final Offset endOfTextPos = textOffsetToPosition(tester, 74); + + // Click on text field to gain focus, and move the selection. + final TestGesture gesture = await tester.startGesture(endOfTextPos, kind: PointerDeviceKind.mouse); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + expect(controller.selection.isCollapsed, true); + expect(controller.selection.baseOffset, 74); + + // Here we click on same position again, to register a double click. + await gesture.down(endOfTextPos); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + expect(controller.selection.baseOffset, 74); + expect(controller.selection.extentOffset, 74); + + // Here we click on same position again, to register a triple click. This will select + // the paragraph at the clicked position. + await gesture.down(endOfTextPos); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await tester.pumpAndSettle(); + + expect(controller.selection.baseOffset, 57); + expect(controller.selection.extentOffset, 74); + }, + variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), + ); + testWidgets( 'triple tap chains work on Non-Apple mobile platforms', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 68fc1b87c8b08..0776562880dd9 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -9771,6 +9771,117 @@ void main() { variant: TargetPlatformVariant.mobile(), ); + testWidgets( + 'Triple click at the beginning of a line should not select the previous paragraph', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132126 + final TextEditingController controller = TextEditingController(); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + dragStartBehavior: DragStartBehavior.down, + controller: controller, + maxLines: null, + ), + ), + ), + ); + + await tester.enterText(find.byType(TextField), testValueB); + await skipPastScrollingAnimation(tester); + expect(controller.value.text, testValueB); + + final Offset thirdLinePos = textOffsetToPosition(tester, 38); + + // Click on text field to gain focus, and move the selection. + final TestGesture gesture = await tester.startGesture(thirdLinePos, kind: PointerDeviceKind.mouse); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + expect(controller.selection.isCollapsed, true); + expect(controller.selection.baseOffset, 38); + + // Here we click on same position again, to register a double click. This will select + // the word at the clicked position. + await gesture.down(thirdLinePos); + await gesture.up(); + + expect(controller.selection.baseOffset, 38); + expect(controller.selection.extentOffset, 40); + + // Here we click on same position again, to register a triple click. This will select + // the paragraph at the clicked position. + await gesture.down(thirdLinePos); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await tester.pumpAndSettle(); + + expect(controller.selection.baseOffset, 38); + expect(controller.selection.extentOffset, 57); + }, + variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), + ); + + testWidgets( + 'Triple click at the end of text should select the previous paragraph', + (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132126. + final TextEditingController controller = TextEditingController(); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + dragStartBehavior: DragStartBehavior.down, + controller: controller, + maxLines: null, + ), + ), + ), + ); + + await tester.enterText(find.byType(TextField), testValueB); + await skipPastScrollingAnimation(tester); + expect(controller.value.text, testValueB); + + final Offset endOfTextPos = textOffsetToPosition(tester, 74); + + // Click on text field to gain focus, and move the selection. + final TestGesture gesture = await tester.startGesture(endOfTextPos, kind: PointerDeviceKind.mouse); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + expect(controller.selection.isCollapsed, true); + expect(controller.selection.baseOffset, 74); + + // Here we click on same position again, to register a double click. + await gesture.down(endOfTextPos); + await tester.pump(); + await gesture.up(); + await tester.pump(); + + expect(controller.selection.baseOffset, 74); + expect(controller.selection.extentOffset, 74); + + // Here we click on same position again, to register a triple click. This will select + // the paragraph at the clicked position. + await gesture.down(endOfTextPos); + await tester.pump(); + await gesture.up(); + await tester.pump(); + await tester.pumpAndSettle(); + + expect(controller.selection.baseOffset, 57); + expect(controller.selection.extentOffset, 74); + }, + variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), + ); + testWidgets( 'triple tap chains work on Non-Apple mobile platforms', (WidgetTester tester) async { From 1a0077dc819369ba6e96da9b538e5cc37930bcc9 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 16 Aug 2023 16:26:58 -0700 Subject: [PATCH 0759/1547] Upgrade flutter packages. (#132697) --- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 4 ++-- dev/bots/pubspec.yaml | 4 ++-- dev/conductor/core/pubspec.yaml | 4 ++-- dev/devicelab/pubspec.yaml | 4 ++-- dev/forbidden_from_release_tests/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- dev/integration_tests/hybrid_android_views/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/tools/gen_keycodes/pubspec.yaml | 4 ++-- dev/tools/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 4 ++-- packages/flutter/pubspec.yaml | 6 +++--- packages/flutter/test_private/pubspec.yaml | 4 ++-- packages/flutter/test_private/test/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_goldens/pubspec.yaml | 4 ++-- packages/flutter_goldens_client/pubspec.yaml | 4 ++-- packages/flutter_tools/pubspec.yaml | 4 ++-- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 4 ++-- 21 files changed, 43 insertions(+), 43 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 340c2ab3c3a02..ead6706e5cebd 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter integration_test: sdk: flutter - platform: 3.1.0 + platform: 3.1.1 test: 1.24.6 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 402b +# PUBSPEC CHECKSUM: e62c diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index d16df86ae4d15..5fcb375ce1870 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 46c9 +# PUBSPEC CHECKSUM: a2ca diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 4cc62550c3b50..b832fcdb640ec 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: http_parser: 4.0.2 meta: 1.9.1 path: 1.8.3 - platform: 3.1.0 + platform: 3.1.1 process: 4.2.4 test: 1.24.6 @@ -74,4 +74,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 117a +# PUBSPEC CHECKSUM: e77b diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 483c5eb4a0ef3..9ce01ee17d988 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7108 +# PUBSPEC CHECKSUM: f309 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 6fb98320dce28..3b4a824cd0552 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: meta: 1.9.1 metrics_center: 1.0.11 path: 1.8.3 - platform: 3.1.0 + platform: 3.1.1 process: 4.2.4 pubspec_parse: 1.2.3 shelf: 1.4.1 @@ -72,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 9be7 +# PUBSPEC CHECKSUM: 72e8 diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index d94649f5b2173..f2b7c096d1816 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -14,6 +14,6 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 846a +# PUBSPEC CHECKSUM: d76b diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 91f816f798639..c0c531866db86 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -92,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: be56 +# PUBSPEC CHECKSUM: 0e57 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 6a829699e17ea..9a3fceb735b32 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -83,7 +83,7 @@ dev_dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: e44f +# PUBSPEC CHECKSUM: 5650 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index 2410ef8a309ce..b6cc4937f4f0a 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: be56 +# PUBSPEC CHECKSUM: 0e57 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 6c7bc1f132c19..7338b68209bc1 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -67,7 +67,7 @@ dev_dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 044e +# PUBSPEC CHECKSUM: ea4f diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 784907286b6ee..df82f1b4ba7b2 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: http: 0.13.6 meta: 1.9.1 path: 1.8.3 - platform: 3.1.0 + platform: 3.1.1 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -57,4 +57,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ae4b +# PUBSPEC CHECKSUM: f64c diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 82ad7215a6c85..5d6b2bffc086d 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,4 +61,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3265 +# PUBSPEC CHECKSUM: 9666 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index bd46437270834..be66089958428 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -60,7 +60,7 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -89,4 +89,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6418 +# PUBSPEC CHECKSUM: 4b19 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 35684cf52978b..d9c92283e4da7 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -23,7 +23,7 @@ dev_dependencies: sdk: flutter fake_async: 1.3.1 leak_tracker: 9.0.5 - leak_tracker_flutter_testing: 1.0.1 + leak_tracker_flutter_testing: 1.0.2 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,7 +49,7 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 623f +# PUBSPEC CHECKSUM: 1341 diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index 29ed2ec175574..270187916f3f5 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -15,6 +15,6 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 198f +# PUBSPEC CHECKSUM: 6090 diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 7a7e554f0a821..72510d5dc9705 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -36,7 +36,7 @@ dev_dependencies: fake_async: 1.3.1 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 183f +# PUBSPEC CHECKSUM: 5840 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 754474f9644b0..925526eaf0c42 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1970 +# PUBSPEC CHECKSUM: 0071 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index f4bb87e85f86c..399745f994670 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: path: ../flutter_goldens_client file: 6.1.4 meta: 1.9.1 - platform: 3.1.0 + platform: 3.1.1 process: 4.2.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,4 +36,4 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 40a0 +# PUBSPEC CHECKSUM: a2a1 diff --git a/packages/flutter_goldens_client/pubspec.yaml b/packages/flutter_goldens_client/pubspec.yaml index b676838563b61..c1bdb5bbe6bfa 100644 --- a/packages/flutter_goldens_client/pubspec.yaml +++ b/packages/flutter_goldens_client/pubspec.yaml @@ -7,7 +7,7 @@ dependencies: # To update these, use "flutter update-packages --force-upgrade". crypto: 3.0.3 file: 6.1.4 - platform: 3.1.0 + platform: 3.1.1 process: 4.2.4 collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -19,4 +19,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 120b +# PUBSPEC CHECKSUM: 510c diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 70afa9c91a147..beab68d169791 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -79,7 +79,7 @@ dependencies: json_rpc_2: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_proxy: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -107,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: d87f +# PUBSPEC CHECKSUM: e480 diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 9412af17cb4a0..3645af9d3181c 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: test: 1.24.6 @@ -63,4 +63,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 975b +# PUBSPEC CHECKSUM: fb5c From af0ca978426d9a3f50227dd4a0dcdb9abc6f9b53 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 16 Aug 2023 19:13:04 -0500 Subject: [PATCH 0760/1547] Fix bad pattern in 2D tests (#132709) Fixes some poor tests choices in the 2D tests that were identified in https://github.com/flutter/packages/pull/4536 --- .../widgets/two_dimensional_viewport_test.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index 6cb6d025dd35f..5d8f019f3f117 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -1514,7 +1514,7 @@ void main() { maxXIndex: 5, maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); @@ -1602,7 +1602,7 @@ void main() { maxXIndex: 5, maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); @@ -1731,7 +1731,7 @@ void main() { maxXIndex: 5, maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); @@ -1897,7 +1897,7 @@ void main() { maxXIndex: 19, maxYIndex: 19, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square( dimension: 200, child: Center( @@ -1965,7 +1965,7 @@ void main() { maxXIndex: 5, maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); @@ -2001,7 +2001,7 @@ void main() { maxXIndex: 5, maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); @@ -2119,7 +2119,7 @@ void main() { maxXIndex: 5, maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { - childKeys[vicinity] = UniqueKey(); + childKeys[vicinity] = childKeys[vicinity] ?? UniqueKey(); return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); From b66878a61e58642024da7b130371aa117059d2f6 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 16 Aug 2023 17:41:03 -0700 Subject: [PATCH 0761/1547] Treat missing --local-engine-host as fatal on CI-like systems. (#132707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partial work towards https://github.com/flutter/flutter/issues/132245. The goal here is to "sniff" out any missing pieces that would block engine builds, rolls, benchmarks and so on before requiring humans to provide the parameter. The implementation is based on a [short discussion with @christopherfujino](https://discord.com/channels/608014603317936148/608022056616853515/1141503921546875110): @matanlurey: > Not sure whether to post here or ⁠hackers-infra-🌡 , but is there a way to (and is it advisable to) detect whether the tool is running in a CI environment? I'd like to "soft enforce" --local-engine-host being provided strictly on CI, make sure that lands well, and then "upgrade" it to being non-CI invocations as well (re: https://github.com/flutter/flutter/issues/132245). > > Also happy to get talked out of this idea 🙂 @christopherfujino: > we have a check, lemme find it > whether or not it is advisable, idk > https://github.com/flutter/flutter/blob/flutter-3.14-candidate.0/packages/flutter_tools/lib/src/base/bot_detector.dart#L30 > > (...) > > is your desire to get early signal before enforcing t his for humans to prevent functionality churn of landing and reverting and re-landing? > > (yes) > > uhh, sure, that's advisable 🙂 --- .../lib/src/base/user_messages.dart | 4 ++-- .../flutter_tools/lib/src/context_runner.dart | 5 ++++ .../lib/src/runner/local_engine.dart | 12 +++++++--- .../commands.shard/hermetic/attach_test.dart | 2 +- .../runner/local_engine_test.dart | 23 +++++++++++++++++++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 780561311efb3..6ebaa13471ac1 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -309,8 +309,8 @@ class UserMessages { String get runnerLocalEngineOrWebSdkRequired => 'You must specify --local-engine or --local-web-sdk if you are using a locally built engine or web sdk.'; // TODO(matanlurey): Make this an error, https://github.com/flutter/flutter/issues/132245. - String get runnerLocalEngineRequiresHostEngine => - 'Warning! You are using a locally built engine (--local-engine) but have not specified --local-host-engine.\n' + String runnerLocalEngineRequiresHostEngine({bool warning = false}) => + '${warning ? 'Warning! ' : ''}You are using a locally built engine (--local-engine) but have not specified --local-host-engine.\n' 'You may be building with a different engine than the one you are running with. ' 'See https://github.com/flutter/flutter/issues/132245 for details (in the future this will become ' 'an error).'; diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index a5a4f92c25048..a3f0b268abe4a 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -276,6 +276,11 @@ Future runInContext( platform: globals.platform, fileSystem: globals.fs, flutterRoot: Cache.flutterRoot!, + // TODO(matanlurey): https://github.com/flutter/flutter/issues/132245. + // Even though we *think* this feature is stable, we'd like to verify + // that automated tests are all providing `--local-engine-host` before + // enforcing it for all users. + treatMissingLocalEngineHostAsFatal: runningOnBot, ), Logger: () => globals.platform.isWindows ? WindowsStdoutLogger( diff --git a/packages/flutter_tools/lib/src/runner/local_engine.dart b/packages/flutter_tools/lib/src/runner/local_engine.dart index 57c9c19a8b73d..5170bf59e2ce4 100644 --- a/packages/flutter_tools/lib/src/runner/local_engine.dart +++ b/packages/flutter_tools/lib/src/runner/local_engine.dart @@ -33,17 +33,20 @@ class LocalEngineLocator { required FileSystem fileSystem, required String flutterRoot, required UserMessages userMessages, + bool treatMissingLocalEngineHostAsFatal = false, }) : _platform = platform, _logger = logger, _fileSystem = fileSystem, _flutterRoot = flutterRoot, - _userMessages = userMessages; + _userMessages = userMessages, + _treatMissingLocalEngineHostAsFatal = treatMissingLocalEngineHostAsFatal; final Platform _platform; final Logger _logger; final FileSystem _fileSystem; final String _flutterRoot; final UserMessages _userMessages; + final bool _treatMissingLocalEngineHostAsFatal; /// Returns the engine build path of a local engine if one is located, otherwise `null`. Future findEnginePath({ @@ -206,8 +209,11 @@ class LocalEngineLocator { } if (localHostEngine == null) { - // TODO(matanlurey): https://github.com/flutter/flutter/issues/132245, change to throwToolExit. - _logger.printStatus(_userMessages.runnerLocalEngineRequiresHostEngine); + // TODO(matanlurey): https://github.com/flutter/flutter/issues/132245, always throwToolExit. + if (_treatMissingLocalEngineHostAsFatal) { + throwToolExit(_userMessages.runnerLocalEngineRequiresHostEngine()); + } + _logger.printStatus(_userMessages.runnerLocalEngineRequiresHostEngine(warning: true)); } final String basename = localHostEngine ?? _fileSystem.path.basename(engineBuildPath); final String hostBasename = _getHostEngineBasename(basename); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index 5740b20c93cf5..d334c8aa9dd87 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -276,7 +276,7 @@ void main() { platform: platform, processInfo: processInfo, fileSystem: testFileSystem, - )).run(['attach', '--local-engine-src-path=$localEngineSrc', '--local-engine=$localEngineDir']); + )).run(['attach', '--local-engine-src-path=$localEngineSrc', '--local-engine=$localEngineDir', '--local-engine-host=$localEngineDir']); await Future.wait(>[ completer.future, fakeLogReader.dispose(), diff --git a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart index f2f3aedcbf315..b18a3633a2842 100644 --- a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart @@ -145,6 +145,29 @@ void main() { expect(logger.statusText, contains('Warning! You are using a locally built engine (--local-engine) but have not specified --local-host-engine')); }); + testWithoutContext('fails if --local-engine-host is emitted and treatMissingLocalEngineHostAsFatal is set', () async { + final FileSystem fileSystem = MemoryFileSystem.test(); + final Directory localEngine = fileSystem + .directory('$kArbitraryEngineRoot/src/out/android_debug_unopt_arm64/') + ..createSync(recursive: true); + fileSystem.directory('$kArbitraryEngineRoot/src/out/host_debug_unopt/').createSync(recursive: true); + + final BufferLogger logger = BufferLogger.test(); + final LocalEngineLocator localEngineLocator = LocalEngineLocator( + fileSystem: fileSystem, + flutterRoot: 'flutter/flutter', + logger: logger, + userMessages: UserMessages(), + platform: FakePlatform(environment: {}), + treatMissingLocalEngineHostAsFatal: true, + ); + + await expectLater( + localEngineLocator.findEnginePath(localEngine: localEngine.path), + throwsToolExit(message: 'You are using a locally built engine (--local-engine) but have not specified --local-host-engine'), + ); + }); + testWithoutContext('works if --local-engine is specified and --local-engine-src-path ' 'is determined by --local-engine', () async { final FileSystem fileSystem = MemoryFileSystem.test(); From 8864395034e9d16937be3472957d69a2a7393bb8 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Wed, 16 Aug 2023 18:02:17 -0700 Subject: [PATCH 0762/1547] Improvements to EditableText documentation (#132532) --- .../flutter/lib/src/rendering/editable.dart | 16 +++-- .../lib/src/widgets/editable_text.dart | 61 +++++++++++-------- .../lib/src/widgets/text_selection.dart | 28 ++++++--- 3 files changed, 67 insertions(+), 38 deletions(-) diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 779e38371f3cf..2dd8671711aa4 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -878,7 +878,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// The color to use when painting the cursor aligned to the text while /// rendering the floating cursor. /// - /// The default is light grey. + /// Typically this would be set to [CupertinoColors.inactiveGray]. + /// + /// If this is null, the background cursor is not painted. Color? get backgroundCursorColor => _caretPainter.backgroundCursorColor; set backgroundCursorColor(Color? value) { _caretPainter.backgroundCursorColor = value; @@ -2645,8 +2647,8 @@ class _RenderEditableCustomPaint extends RenderBox { /// when only auxiliary content changes (e.g. a blinking cursor) are present. It /// will be scheduled to repaint when: /// -/// * It's assigned to a new [RenderEditable] and the [shouldRepaint] method -/// returns true. +/// * It's assigned to a new [RenderEditable] (replacing a prior +/// [RenderEditablePainter]) and the [shouldRepaint] method returns true. /// * Any of the [RenderEditable]s it is attached to repaints. /// * The [notifyListeners] method is called, which typically happens when the /// painter's attributes change. @@ -2657,9 +2659,8 @@ class _RenderEditableCustomPaint extends RenderBox { /// and sets it as the foreground painter of the [RenderEditable]. /// * [RenderEditable.painter], which takes a [RenderEditablePainter] /// and sets it as the background painter of the [RenderEditable]. -/// * [CustomPainter] a similar class which paints within a [RenderCustomPaint]. +/// * [CustomPainter], a similar class which paints within a [RenderCustomPaint]. abstract class RenderEditablePainter extends ChangeNotifier { - /// Determines whether repaint is needed when a new [RenderEditablePainter] /// is provided to a [RenderEditable]. /// @@ -2795,6 +2796,11 @@ class _CaretPainter extends RenderEditablePainter { notifyListeners(); } + // This is directly manipulated by the RenderEditable during + // setFloatingCursor. + // + // When changing this value, the caller is responsible for ensuring that + // listeners are notified. bool showRegularCaret = false; final Paint caretPaint = Paint(); diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index b8effd5a2fa91..da2014017544f 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -206,7 +206,7 @@ class TextEditingController extends ValueNotifier { value == null || !value.composing.isValid || value.isComposingRangeValid, 'New TextEditingValue $value has an invalid non-empty composing range ' '${value.composing}. It is recommended to use a valid composing range, ' - 'even for readonly text fields', + 'even for readonly text fields.', ), super(value ?? TextEditingValue.empty); @@ -235,7 +235,7 @@ class TextEditingController extends ValueNotifier { !newValue.composing.isValid || newValue.isComposingRangeValid, 'New TextEditingValue $newValue has an invalid non-empty composing range ' '${newValue.composing}. It is recommended to use a valid composing range, ' - 'even for readonly text fields', + 'even for readonly text fields.', ); super.value = newValue; } @@ -547,8 +547,11 @@ class _DiscreteKeyFrameSimulation extends Simulation { /// /// This widget interacts with the [TextInput] service to let the user edit the /// text it contains. It also provides scrolling, selection, and cursor -/// movement. This widget does not provide any focus management (e.g., -/// tap-to-focus). +/// movement. +/// +/// The [EditableText] widget is a low-level widget that is intended as a +/// building block for custom widget sets. For a complete user experience, +/// consider using a [TextField] or [CupertinoTextField]. /// /// ## Handling User Input /// @@ -662,13 +665,14 @@ class _DiscreteKeyFrameSimulation extends Simulation { /// /// ## Gesture Events Handling /// -/// This widget provides rudimentary, platform-agnostic gesture handling for -/// user actions such as tapping, long-pressing and scrolling when -/// [rendererIgnoresPointer] is false (false by default). To tightly conform -/// to the platform behavior with respect to input gestures in text fields, use -/// [TextField] or [CupertinoTextField]. For custom selection behavior, call -/// methods such as [RenderEditable.selectPosition], -/// [RenderEditable.selectWord], etc. programmatically. +/// When [rendererIgnoresPointer] is false (the default), this widget provides +/// rudimentary, platform-agnostic gesture handling for user actions such as +/// tapping, long-pressing, and scrolling. +/// +/// To provide more complete gesture handling, including double-click to select +/// a word, drag selection, and platform-specific handling of gestures such as +/// long presses, consider setting [rendererIgnoresPointer] to true and using +/// [TextSelectionGestureDetectorBuilder]. /// /// {@template flutter.widgets.editableText.showCaretOnScreen} /// ## Keep the caret visible when focused @@ -696,7 +700,7 @@ class _DiscreteKeyFrameSimulation extends Simulation { /// a currency value text field. The following example demonstrates how to /// suppress the default accessibility announcements by always announcing /// the content of the text field as a US currency value (the `\$` inserts -/// a dollar sign, the `$newText interpolates the `newText` variable): +/// a dollar sign, the `$newText` interpolates the `newText` variable): /// /// ```dart /// onChanged: (String newText) { @@ -726,14 +730,6 @@ class EditableText extends StatefulWidget { /// /// The text cursor is not shown if [showCursor] is false or if [showCursor] /// is null (the default) and [readOnly] is true. - /// - /// The [controller], [focusNode], [obscureText], [autocorrect], [autofocus], - /// [showSelectionHandles], [enableInteractiveSelection], [forceLine], - /// [style], [cursorColor], [cursorOpacityAnimates], [backgroundCursorColor], - /// [enableSuggestions], [paintCursorAboveText], [selectionHeightStyle], - /// [selectionWidthStyle], [textAlign], [dragStartBehavior], [scrollPadding], - /// [dragStartBehavior], [toolbarOptions], [rendererIgnoresPointer], - /// [readOnly], and [enableIMEPersonalizedLearning] arguments must not be null. EditableText({ super.key, required this.controller, @@ -1101,8 +1097,7 @@ class EditableText extends StatefulWidget { /// The color to use when painting the background cursor aligned with the text /// while rendering the floating cursor. /// - /// Cannot be null. By default it is the disabled grey color from - /// CupertinoColors. + /// Typically this would be set to [CupertinoColors.inactiveGray]. final Color backgroundCursorColor; /// {@template flutter.widgets.editableText.maxLines} @@ -1473,10 +1468,28 @@ class EditableText extends StatefulWidget { /// the editing position. final MouseCursor? mouseCursor; - /// If true, the [RenderEditable] created by this widget will not handle - /// pointer events, see [RenderEditable] and [RenderEditable.ignorePointer]. + /// Whether the caller will provide gesture handling (true), or if the + /// [EditableText] is expected to handle basic gestures (false). + /// + /// When this is false, the [EditableText] (or more specifically, the + /// [RenderEditable]) enables some rudimentary gestures (tap to position the + /// cursor, long-press to select all, and some scrolling behavior). + /// + /// These behaviors are sufficient for debugging purposes but are inadequate + /// for user-facing applications. To enable platform-specific behaviors, use a + /// [TextSelectionGestureDetectorBuilder] to wrap the [EditableText], and set + /// [rendererIgnoresPointer] to true. + /// + /// When [rendererIgnoresPointer] is true true, the [RenderEditable] created + /// by this widget will not handle pointer events. /// /// This property is false by default. + /// + /// See also: + /// + /// * [RenderEditable.ignorePointer], which implements this feature. + /// * [TextSelectionGestureDetectorBuilder], which implements platform-specific + /// gestures and behaviors. final bool rendererIgnoresPointer; /// {@template flutter.widgets.editableText.cursorWidth} diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 274150aa49de2..12d780ca72c60 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -1871,12 +1871,13 @@ class _SelectionHandleOverlayState extends State<_SelectionHandleOverlay> with S /// Delegate interface for the [TextSelectionGestureDetectorBuilder]. /// -/// The interface is usually implemented by text field implementations wrapping -/// [EditableText], that use a [TextSelectionGestureDetectorBuilder] to build a -/// [TextSelectionGestureDetector] for their [EditableText]. The delegate provides -/// the builder with information about the current state of the text field. -/// Based on these information, the builder adds the correct gesture handlers -/// to the gesture detector. +/// The interface is usually implemented by the [State] of text field +/// implementations wrapping [EditableText], so that they can use a +/// [TextSelectionGestureDetectorBuilder] to build a +/// [TextSelectionGestureDetector] for their [EditableText]. The delegate +/// provides the builder with information about the current state of the text +/// field. Based on that information, the builder adds the correct gesture +/// handlers to the gesture detector. /// /// See also: /// @@ -1907,6 +1908,12 @@ abstract class TextSelectionGestureDetectorBuilderDelegate { /// The resulting [TextSelectionGestureDetector] to wrap an [EditableText] is /// obtained by calling [buildGestureDetector]. /// +/// A [TextSelectionGestureDetectorBuilder] must be provided a +/// [TextSelectionGestureDetectorBuilderDelegate], from which information about +/// the [EditableText] may be obtained. Typically, the [State] of the widget +/// that builds the [EditableText] implements this interface, and then passes +/// itself as the [delegate]. +/// /// See also: /// /// * [TextField], which uses a subclass to implement the Material-specific @@ -1915,8 +1922,6 @@ abstract class TextSelectionGestureDetectorBuilderDelegate { /// Cupertino-specific gesture logic of an [EditableText]. class TextSelectionGestureDetectorBuilder { /// Creates a [TextSelectionGestureDetectorBuilder]. - /// - /// The [delegate] must not be null. TextSelectionGestureDetectorBuilder({ required this.delegate, }); @@ -1926,6 +1931,9 @@ class TextSelectionGestureDetectorBuilder { /// The delegate provides the builder with information about what actions can /// currently be performed on the text field. Based on this, the builder adds /// the correct gesture handlers to the gesture detector. + /// + /// Typically implemented by a [State] of a widget that builds an + /// [EditableText]. @protected final TextSelectionGestureDetectorBuilderDelegate delegate; @@ -2971,7 +2979,9 @@ class TextSelectionGestureDetectorBuilder { /// Returns a [TextSelectionGestureDetector] configured with the handlers /// provided by this builder. /// - /// The [child] or its subtree should contain [EditableText]. + /// The [child] or its subtree should contain an [EditableText] whose key is + /// the [GlobalKey] provided by the [delegate]'s + /// [TextSelectionGestureDetectorBuilderDelegate.editableTextKey]. Widget buildGestureDetector({ Key? key, HitTestBehavior? behavior, From ca319278bde5053a842456da5f8587b198174128 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 16 Aug 2023 21:05:06 -0500 Subject: [PATCH 0763/1547] Fix lower bound of children from TwoDimensionalChildBuilderDelegate (#132713) Found in https://github.com/flutter/packages/pull/4536 The max x and max y index should allow for a case where there are no children in the viewport. This should be CP'd into stable once it lands. --- .../lib/src/widgets/scroll_delegate.dart | 12 +++++++----- .../widgets/two_dimensional_viewport_test.dart | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/flutter/lib/src/widgets/scroll_delegate.dart b/packages/flutter/lib/src/widgets/scroll_delegate.dart index b81b9b069ecf9..6a816f153bd33 100644 --- a/packages/flutter/lib/src/widgets/scroll_delegate.dart +++ b/packages/flutter/lib/src/widgets/scroll_delegate.dart @@ -933,8 +933,8 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { int? maxYIndex, this.addRepaintBoundaries = true, this.addAutomaticKeepAlives = true, - }) : assert(maxYIndex == null || maxYIndex >= 0), - assert(maxXIndex == null || maxXIndex >= 0), + }) : assert(maxYIndex == null || maxYIndex >= -1), + assert(maxXIndex == null || maxXIndex >= -1), _maxYIndex = maxYIndex, _maxXIndex = maxXIndex; @@ -976,7 +976,9 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { /// [TwoDimensionalViewport] subclass to learn how this value is applied in /// the specific use case. /// - /// If not null, the value must be non-negative. + /// If not null, the value must be greater than or equal to -1, where -1 + /// indicates there will be no children at all provided to the + /// [TwoDimensionalViewport]. /// /// If the value changes, the delegate will call [notifyListeners]. This /// informs the [RenderTwoDimensionalViewport] that any cached information @@ -997,7 +999,7 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { if (value == maxXIndex) { return; } - assert(value == null || value >= 0); + assert(value == null || value >= -1); _maxXIndex = value; notifyListeners(); } @@ -1020,7 +1022,7 @@ class TwoDimensionalChildBuilderDelegate extends TwoDimensionalChildDelegate { if (maxYIndex == value) { return; } - assert(value == null || value >= 0); + assert(value == null || value >= -1); _maxYIndex = value; notifyListeners(); } diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index 5d8f019f3f117..e65f5319ba3aa 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -120,27 +120,29 @@ void main() { } ); // Update + delegate.maxXIndex = -1; // No exception. expect( () { - delegate.maxXIndex = -1; + delegate.maxXIndex = -2; }, throwsA( isA().having( (AssertionError error) => error.toString(), 'description', - contains('value == null || value >= 0'), + contains('value == null || value >= -1'), ), ), ); + delegate.maxYIndex = -1; // No exception expect( () { - delegate.maxYIndex = -1; + delegate.maxYIndex = -2; }, throwsA( isA().having( (AssertionError error) => error.toString(), 'description', - contains('value == null || value >= 0'), + contains('value == null || value >= -1'), ), ), ); @@ -148,7 +150,7 @@ void main() { expect( () { TwoDimensionalChildBuilderDelegate( - maxXIndex: -1, + maxXIndex: -2, maxYIndex: 0, builder: (BuildContext context, ChildVicinity vicinity) { return const SizedBox.shrink(); @@ -159,7 +161,7 @@ void main() { isA().having( (AssertionError error) => error.toString(), 'description', - contains('maxXIndex == null || maxXIndex >= 0'), + contains('maxXIndex == null || maxXIndex >= -1'), ), ), ); @@ -167,7 +169,7 @@ void main() { () { TwoDimensionalChildBuilderDelegate( maxXIndex: 0, - maxYIndex: -1, + maxYIndex: -2, builder: (BuildContext context, ChildVicinity vicinity) { return const SizedBox.shrink(); } @@ -177,7 +179,7 @@ void main() { isA().having( (AssertionError error) => error.toString(), 'description', - contains('maxYIndex == null || maxYIndex >= 0'), + contains('maxYIndex == null || maxYIndex >= -1'), ), ), ); From fe9c7f4fa7bfadaff4d4110313e0750eacc5d0e7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 16 Aug 2023 22:05:08 -0400 Subject: [PATCH 0764/1547] Roll Flutter Engine from dbfe71c898b6 to 533670269c99 (15 revisions) (#132717) https://github.com/flutter/engine/compare/dbfe71c898b6...533670269c99 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 233c4f26427a to 11cb8cdd37c1 (1 revision) (flutter/engine#44786) 2023-08-16 jason-simmons@users.noreply.github.com Revert "Conditionally enable HardwareBuffer backed platform views (#44744)" (flutter/engine#44785) 2023-08-16 dnfield@google.com [Impeller] Update docstring on layer.presentsWithTransaction (flutter/engine#44782) 2023-08-16 john@johnmccutchan.com Switch some ERROR logs to WARNING logs (flutter/engine#44784) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from 02870a1df818 to 233c4f26427a (1 revision) (flutter/engine#44780) 2023-08-16 skia-flutter-autoroll@skia.org Roll Dart SDK from cc5eeac65f89 to d6e1fca5dbdf (1 revision) (flutter/engine#44770) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from e65aabc26c86 to 02870a1df818 (7 revisions) (flutter/engine#44778) 2023-08-16 matanlurey@users.noreply.github.com Add an optional '--enable-check-profile' to 'tools/clang_tidy'. (flutter/engine#44773) 2023-08-16 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Zp9or9YwxZHHPeQbA... to VW7WAVPT3Cj5erlae... (flutter/engine#44777) 2023-08-16 louiseh0313@gmail.com Fix search web test (flutter/engine#44704) 2023-08-16 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from GpKKtPGPMiRcY0kcz... to cPncZK6z8HmuOmQr_... (flutter/engine#44769) 2023-08-16 godofredoc@google.com Remove duplicated v1 builds. (flutter/engine#44767) 2023-08-16 skia-flutter-autoroll@skia.org Roll Skia from d029f149a806 to e65aabc26c86 (4 revisions) (flutter/engine#44768) 2023-08-16 zanderso@users.noreply.github.com Split lint.sh into separate scripts for clang-tidy and pylint (flutter/engine#44763) 2023-08-16 john@johnmccutchan.com Conditionally enable HardwareBuffer backed platform views (flutter/engine#44744) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from GpKKtPGPMiRc to cPncZK6z8Hmu fuchsia/sdk/core/mac-amd64 from Zp9or9YwxZHH to VW7WAVPT3Cj5 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 913b43c6f0592..d5b50ea839eb8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -dbfe71c898b6761af897574c297ce89623ce0d8c +533670269c99a8f552edb1e5bf5a17b706e54e5b diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index bec69a7c685ea..2c965e97536c3 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -GpKKtPGPMiRcY0kczUz9TMRl6fRE6e4PFlCkCfvzYuQC +cPncZK6z8HmuOmQr_wP3MEXkUKsWRyPLc5j5W8aG4UUC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 1fa23fd64d673..96160304ec571 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Zp9or9YwxZHHPeQbAnK1yZvyDefNEqdI8UQFALQsLH8C +VW7WAVPT3Cj5erlaez7LYgmKffc3Tf5FIxhG2GxzyO0C From b7046b32dbad59f564f0a687f46e532f1b7de022 Mon Sep 17 00:00:00 2001 From: Bernardo Ferrari Date: Thu, 17 Aug 2023 01:04:23 -0300 Subject: [PATCH 0765/1547] Improve and optimize non-uniform Borders. (#124417) ~~Using the same priority order as a Border without borderRadius, it is possible to draw them on top of each other. This is better than the current behavior (crash!) and would work well for a "one color on top, another on bottom" scenario.~~ ~~With this, if approved, we move the current number of possible exceptions from 4 to 1 (`BoxShape.circle` + `borderRadius`).~~ ~~It is kind of odd how `borderRadius.zero` to `borderRadius != BorderRadius.zero` change, but I think it is better than crashing. Alternatively, we just remove the "original function" and see if any goldens are affected.~~ image Another one for @gspencergoog. If this works, we could make the paint method public and re-use in the InputBorder PR (if that's also approved). Single line fix. --- .../flutter/lib/src/painting/box_border.dart | 174 +++++++++++++----- .../test/material/data_table_test.dart | 2 +- .../flutter/test/material/divider_test.dart | 5 +- .../flutter/test/painting/border_test.dart | 30 ++- 4 files changed, 153 insertions(+), 58 deletions(-) diff --git a/packages/flutter/lib/src/painting/box_border.dart b/packages/flutter/lib/src/painting/box_border.dart index dfc9a606a556b..633be6a114017 100644 --- a/packages/flutter/lib/src/painting/box_border.dart +++ b/packages/flutter/lib/src/painting/box_border.dart @@ -242,16 +242,24 @@ abstract class BoxBorder extends ShapeBorder { } } - static void _paintNonUniformBorder( + /// Paints a Border with different widths, styles and strokeAligns, on any + /// borderRadius while using a single color. + /// + /// See also: + /// + /// * [paintBorder], which supports multiple colors but not borderRadius. + /// * [paint], which calls this method. + static void paintNonUniformBorder( Canvas canvas, Rect rect, { required BorderRadius? borderRadius, - required BoxShape shape, required TextDirection? textDirection, - required BorderSide left, - required BorderSide top, - required BorderSide right, - required BorderSide bottom, + BoxShape shape = BoxShape.rectangle, + BorderSide top = BorderSide.none, + BorderSide right = BorderSide.none, + BorderSide bottom = BorderSide.none, + BorderSide left = BorderSide.none, + required Color color, }) { final RRect borderRect; switch (shape) { @@ -266,7 +274,7 @@ abstract class BoxBorder extends ShapeBorder { Radius.circular(rect.width), ); } - final Paint paint = Paint()..color = top.color; + final Paint paint = Paint()..color = color; final RRect inner = _deflateRRect(borderRect, EdgeInsets.fromLTRB(left.strokeInset, top.strokeInset, right.strokeInset, bottom.strokeInset)); final RRect outer = _inflateRRect(borderRect, EdgeInsets.fromLTRB(left.strokeOutset, top.strokeOutset, right.strokeOutset, bottom.strokeOutset)); canvas.drawDRRect(outer, inner, paint); @@ -489,6 +497,32 @@ class Border extends BoxBorder { && right.strokeAlign == topStrokeAlign; } + Set _distinctVisibleColors() { + final Set distinctVisibleColors = {}; + if (top.style != BorderStyle.none) { + distinctVisibleColors.add(top.color); + } + if (right.style != BorderStyle.none) { + distinctVisibleColors.add(right.color); + } + if (bottom.style != BorderStyle.none) { + distinctVisibleColors.add(bottom.color); + } + if (left.style != BorderStyle.none) { + distinctVisibleColors.add(left.color); + } + return distinctVisibleColors; + } + + // [BoxBorder.paintNonUniformBorder] is about 20% faster than [paintBorder], + // but [paintBorder] is able to draw hairline borders when width is zero + // and style is [BorderStyle.solid]. + bool get _hasHairlineBorder => + (top.style == BorderStyle.solid && top.width == 0.0) || + (right.style == BorderStyle.solid && right.width == 0.0) || + (bottom.style == BorderStyle.solid && bottom.width == 0.0) || + (left.style == BorderStyle.solid && left.width == 0.0); + @override Border? add(ShapeBorder other, { bool reversed = false }) { if (other is Border && @@ -603,31 +637,41 @@ class Border extends BoxBorder { } } - // Allow painting non-uniform borders if the color and style are uniform. - if (_colorIsUniform && _styleIsUniform) { - switch (top.style) { - case BorderStyle.none: - return; - case BorderStyle.solid: - BoxBorder._paintNonUniformBorder(canvas, rect, - shape: shape, - borderRadius: borderRadius, - textDirection: textDirection, - left: left, - top: top, - right: right, - bottom: bottom); - return; - } + if (_styleIsUniform && top.style == BorderStyle.none) { + return; } - assert(() { - if (borderRadius != null) { + // Allow painting non-uniform borders if the visible colors are uniform. + final Set visibleColors = _distinctVisibleColors(); + final bool hasHairlineBorder = _hasHairlineBorder; + // Paint a non uniform border if a single color is visible + // and (borderRadius is present) or (border is visible and width != 0.0). + if (visibleColors.length == 1 && + !hasHairlineBorder && + (shape == BoxShape.circle || + (borderRadius != null && borderRadius != BorderRadius.zero))) { + BoxBorder.paintNonUniformBorder(canvas, rect, + shape: shape, + borderRadius: borderRadius, + textDirection: textDirection, + top: top.style == BorderStyle.none ? BorderSide.none : top, + right: right.style == BorderStyle.none ? BorderSide.none : right, + bottom: bottom.style == BorderStyle.none ? BorderSide.none : bottom, + left: left.style == BorderStyle.none ? BorderSide.none : left, + color: visibleColors.first); + return; + } + + assert(() { + if (hasHairlineBorder) { + assert(borderRadius == null || borderRadius == BorderRadius.zero, + 'A hairline border like `BorderSide(width: 0.0, style: BorderStyle.solid)` can only be drawn when BorderRadius is zero or null.'); + } + if (borderRadius != null && borderRadius != BorderRadius.zero) { throw FlutterError.fromParts([ - ErrorSummary('A borderRadius can only be given on borders with uniform colors and styles.'), + ErrorSummary('A borderRadius can only be given on borders with uniform colors.'), ErrorDescription('The following is not uniform:'), if (!_colorIsUniform) ErrorDescription('BorderSide.color'), - if (!_styleIsUniform) ErrorDescription('BorderSide.style'), ]); } return true; @@ -635,10 +679,9 @@ class Border extends BoxBorder { assert(() { if (shape != BoxShape.rectangle) { throw FlutterError.fromParts([ - ErrorSummary('A Border can only be drawn as a circle on borders with uniform colors and styles.'), + ErrorSummary('A Border can only be drawn as a circle on borders with uniform colors.'), ErrorDescription('The following is not uniform:'), if (!_colorIsUniform) ErrorDescription('BorderSide.color'), - if (!_styleIsUniform) ErrorDescription('BorderSide.style'), ]); } return true; @@ -646,7 +689,7 @@ class Border extends BoxBorder { assert(() { if (!_strokeAlignIsUniform || top.strokeAlign != BorderSide.strokeAlignInside) { throw FlutterError.fromParts([ - ErrorSummary('A Border can only draw strokeAlign different than BorderSide.strokeAlignInside on borders with uniform colors and styles.'), + ErrorSummary('A Border can only draw strokeAlign different than BorderSide.strokeAlignInside on borders with uniform colors.'), ]); } return true; @@ -806,6 +849,31 @@ class BorderDirectional extends BoxBorder { && end.strokeAlign == topStrokeAlign; } + Set _distinctVisibleColors() { + final Set distinctVisibleColors = {}; + if (top.style != BorderStyle.none) { + distinctVisibleColors.add(top.color); + } + if (end.style != BorderStyle.none) { + distinctVisibleColors.add(end.color); + } + if (bottom.style != BorderStyle.none) { + distinctVisibleColors.add(bottom.color); + } + if (start.style != BorderStyle.none) { + distinctVisibleColors.add(start.color); + } + + return distinctVisibleColors; + } + + + bool get _hasHairlineBorder => + (top.style == BorderStyle.solid && top.width == 0.0) || + (end.style == BorderStyle.solid && end.width == 0.0) || + (bottom.style == BorderStyle.solid && bottom.width == 0.0) || + (start.style == BorderStyle.solid && start.width == 0.0); + @override BoxBorder? add(ShapeBorder other, { bool reversed = false }) { if (other is BorderDirectional) { @@ -951,6 +1019,10 @@ class BorderDirectional extends BoxBorder { } } + if (_styleIsUniform && top.style == BorderStyle.none) { + return; + } + final BorderSide left, right; assert(textDirection != null, 'Non-uniform BorderDirectional objects require a TextDirection when painting.'); switch (textDirection!) { @@ -962,27 +1034,31 @@ class BorderDirectional extends BoxBorder { right = end; } - // Allow painting non-uniform borders if the color and style are uniform. - if (_colorIsUniform && _styleIsUniform) { - switch (top.style) { - case BorderStyle.none: - return; - case BorderStyle.solid: - BoxBorder._paintNonUniformBorder(canvas, rect, - shape: shape, - borderRadius: borderRadius, - textDirection: textDirection, - left: left, - top: top, - right: right, - bottom: bottom); - return; - } + // Allow painting non-uniform borders if the visible colors are uniform. + final Set visibleColors = _distinctVisibleColors(); + final bool hasHairlineBorder = _hasHairlineBorder; + if (visibleColors.length == 1 && + !hasHairlineBorder && + (shape == BoxShape.circle || + (borderRadius != null && borderRadius != BorderRadius.zero))) { + BoxBorder.paintNonUniformBorder(canvas, rect, + shape: shape, + borderRadius: borderRadius, + textDirection: textDirection, + top: top.style == BorderStyle.none ? BorderSide.none : top, + right: right.style == BorderStyle.none ? BorderSide.none : right, + bottom: bottom.style == BorderStyle.none ? BorderSide.none : bottom, + left: left.style == BorderStyle.none ? BorderSide.none : left, + color: visibleColors.first); + return; } - assert(borderRadius == null, 'A borderRadius can only be given for borders with uniform colors and styles.'); - assert(shape == BoxShape.rectangle, 'A Border can only be drawn as a circle on borders with uniform colors and styles.'); - assert(_strokeAlignIsUniform && top.strokeAlign == BorderSide.strokeAlignInside, 'A Border can only draw strokeAlign different than strokeAlignInside on borders with uniform colors and styles.'); + if (hasHairlineBorder) { + assert(borderRadius == null || borderRadius == BorderRadius.zero, 'A side like `BorderSide(width: 0.0, style: BorderStyle.solid)` can only be drawn when BorderRadius is zero or null.'); + } + assert(borderRadius == null, 'A borderRadius can only be given for borders with uniform colors.'); + assert(shape == BoxShape.rectangle, 'A Border can only be drawn as a circle on borders with uniform colors.'); + assert(_strokeAlignIsUniform && top.strokeAlign == BorderSide.strokeAlignInside, 'A Border can only draw strokeAlign different than strokeAlignInside on borders with uniform colors.'); paintBorder(canvas, rect, top: top, left: left, bottom: bottom, right: right); } diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 2863d8a606ec3..fed5e1a04dac7 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -1750,7 +1750,7 @@ void main() { ); expect( find.ancestor(of: find.byType(Table), matching: find.byType(Container)), - paints..drrect(color: borderColor), + paints..path(color: borderColor), ); expect( tester.getTopLeft(find.byType(Table)), diff --git a/packages/flutter/test/material/divider_test.dart b/packages/flutter/test/material/divider_test.dart index c3326e70ec02d..9249ea6112a39 100644 --- a/packages/flutter/test/material/divider_test.dart +++ b/packages/flutter/test/material/divider_test.dart @@ -136,8 +136,9 @@ void main() { testWidgets('Vertical Divider Test 2', (WidgetTester tester) async { await tester.pumpWidget( - const MaterialApp( - home: Material( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: const Material( child: SizedBox( height: 24.0, child: Row( diff --git a/packages/flutter/test/painting/border_test.dart b/packages/flutter/test/painting/border_test.dart index f2f2aebe5e1b1..e4298f8c5499d 100644 --- a/packages/flutter/test/painting/border_test.dart +++ b/packages/flutter/test/painting/border_test.dart @@ -273,7 +273,7 @@ void main() { expect(error.diagnostics.length, 1); expect( error.diagnostics[0].toStringDeep(), - 'A Border can only draw strokeAlign different than\nBorderSide.strokeAlignInside on borders with uniform colors and\nstyles.\n', + 'A Border can only draw strokeAlign different than\nBorderSide.strokeAlignInside on borders with uniform colors.\n', ); }); @@ -341,8 +341,8 @@ void main() { // This falls into non-uniform border because of strokeAlign. await tester.pumpWidget(buildWidget(border: allowedBorderVariations)); - expect(tester.takeException(), isNull, - reason: 'Border with non-uniform strokeAlign should not fail.'); + expect(tester.takeException(), isAssertionError, + reason: 'Border with non-uniform strokeAlign should fail.'); await tester.pumpWidget(buildWidget( border: allowedBorderVariations, @@ -364,8 +364,8 @@ void main() { borderRadius: BorderRadius.circular(25), ), ); - expect(tester.takeException(), isAssertionError, - reason: 'Border with non-uniform styles should fail with borderRadius.'); + expect(tester.takeException(), isNull, + reason: 'Border with non-uniform styles should work with borderRadius.'); await tester.pumpWidget( buildWidget( @@ -381,6 +381,24 @@ void main() { expect(tester.takeException(), isAssertionError, reason: 'Border with non-uniform colors should fail with borderRadius.'); + await tester.pumpWidget( + buildWidget( + border: const Border(bottom: BorderSide(width: 0)), + borderRadius: BorderRadius.zero, + ), + ); + expect(tester.takeException(), isNull, + reason: 'Border with a side.width == 0 should work without borderRadius (hairline border).'); + + await tester.pumpWidget( + buildWidget( + border: const Border(bottom: BorderSide(width: 0)), + borderRadius: BorderRadius.circular(40), + ), + ); + expect(tester.takeException(), isAssertionError, + reason: 'Border with width == 0 and borderRadius should fail (hairline border).'); + // Tests for BorderDirectional. const BorderDirectional allowedBorderDirectionalVariations = BorderDirectional( start: BorderSide(width: 5), @@ -390,7 +408,7 @@ void main() { ); await tester.pumpWidget(buildWidget(border: allowedBorderDirectionalVariations)); - expect(tester.takeException(), isNull); + expect(tester.takeException(), isAssertionError); await tester.pumpWidget(buildWidget( border: allowedBorderDirectionalVariations, From 7ee864ee37395f7ef13632cbc9663e24fcad248c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 17 Aug 2023 09:08:08 -0700 Subject: [PATCH 0766/1547] [Windows] Allow overwriting the cache's Dart SDK archive license file (#132669) https://github.com/flutter/engine/pull/43974 added a license file to the Dart SDK's ZIP archive. As a result, extracting the Dart SDK now needs to overwrite the cache's `LICENSE.dart_sdk_archive.md` file. This is a short-term solution that will be cherry-picked for the next [3.14 beta release](https://github.com/flutter/flutter/issues/132267). Addresses https://github.com/flutter/flutter/issues/132592. The long-term solution is tracked by https://github.com/flutter/flutter/issues/132702 --- bin/internal/update_dart_sdk.ps1 | 14 ++- .../batch_entrypoint_test.dart | 108 ++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index 6af62a54f73b7..2d0d0fc732d2f 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -18,6 +18,7 @@ $flutterRoot = (Get-Item $progName).parent.parent.FullName $cachePath = "$flutterRoot\bin\cache" $dartSdkPath = "$cachePath\dart-sdk" +$dartSdkLicense = "$cachePath\LICENSE.dart_sdk_archive.md" $engineStamp = "$cachePath\engine-dart-sdk.stamp" $engineVersion = (Get-Content "$flutterRoot\bin\internal\engine.version") $engineRealm = (Get-Content "$flutterRoot\bin\internal\engine.realm") @@ -49,11 +50,18 @@ if ($engineRealm) { $dartZipName = "dart-sdk-windows-x64.zip" $dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName" -if (Test-Path $dartSdkPath) { +if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) { # Move old SDK to a new location instead of deleting it in case it is still in use (e.g. by IntelliJ). $oldDartSdkSuffix = 1 while (Test-Path "$cachePath\$oldDartSdkPrefix$oldDartSdkSuffix") { $oldDartSdkSuffix++ } - Rename-Item $dartSdkPath "$oldDartSdkPrefix$oldDartSdkSuffix" + + if (Test-Path $dartSdkPath) { + Rename-Item $dartSdkPath "$oldDartSdkPrefix$oldDartSdkSuffix" + } + + if (Test-Path $dartSdkLicense) { + Rename-Item $dartSdkLicense "$oldDartSdkPrefix$oldDartSdkSuffix.LICENSE.md" + } } New-Item $dartSdkPath -force -type directory | Out-Null $dartSdkZip = "$cachePath\$dartZipName" @@ -98,5 +106,5 @@ If (Get-Command 7z -errorAction SilentlyContinue) { Remove-Item $dartSdkZip $engineVersion | Out-File $engineStamp -Encoding ASCII -# Try to delete all old SDKs. +# Try to delete all old SDKs and license files. Get-ChildItem -Path $cachePath | Where {$_.BaseName.StartsWith($oldDartSdkPrefix)} | Remove-Item -Recurse -ErrorAction SilentlyContinue diff --git a/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart new file mode 100644 index 0000000000000..e360aa9a8f5a0 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart @@ -0,0 +1,108 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; + +import 'package:file/file.dart'; +import 'package:flutter_tools/src/base/io.dart'; + +import '../src/common.dart'; +import 'test_utils.dart'; + +final String flutterRootPath = getFlutterRoot(); +final Directory flutterRoot = fileSystem.directory(flutterRootPath); + +Future main() async { + // Regression test for https://github.com/flutter/flutter/issues/132592 + test('flutter/bin/dart updates the Dart SDK without hanging', () async { + // Run the Dart entrypoint once to ensure the Dart SDK is downloaded. + await runDartBatch(); + + expect(dartSdkStamp.existsSync(), true); + + // Remove the Dart SDK stamp and run the Dart entrypoint again to trigger + // the Dart SDK update. + dartSdkStamp.deleteSync(); + final Future runFuture = runDartBatch(); + final Timer timer = Timer(const Duration(minutes: 5), () { + // This print is useful for people debugging this test. Normally we would + // avoid printing in a test but this is an exception because it's useful + // ambient information. + // ignore: avoid_print + print( + 'The Dart batch entrypoint did not complete after 5 minutes. ' + 'Historically this is a sign that 7-Zip zip extraction is waiting for ' + 'the user to confirm they would like to overwrite files. ' + "This likely means the test isn't a flake and will fail. " + 'See: https://github.com/flutter/flutter/issues/132592' + ); + }); + + final String output = await runFuture; + timer.cancel(); + + // Check the Dart SDK was re-downloaded and extracted. + // If 7-Zip is installed, unexpected overwrites causes this to hang. + // If 7-Zip is not installed, unexpected overwrites results in error messages. + // See: https://github.com/flutter/flutter/issues/132592 + expect(dartSdkStamp.existsSync(), true); + expect(output, contains('Downloading Dart SDK from Flutter engine ...')); + expect(output, contains('Expanding downloaded archive...')); + expect(output, isNot(contains('Use the -Force parameter' /* Luke */))); + }, + skip: !platform.isWindows); // [intended] Only Windows uses the batch entrypoint +} + +Future runDartBatch() async { + String output = ''; + final Process process = await processManager.start( + [ + dartBatch.path + ], + ); + final Future stdoutFuture = process.stdout + .transform(utf8.decoder) + .forEach((String str) { + output += str; + }); + final Future stderrFuture = process.stderr + .transform(utf8.decoder) + .forEach((String str) { + output += str; + }); + + // Wait for the output to complete + await Future.wait(>[stdoutFuture, stderrFuture]); + // Ensure child exited successfully + expect( + await process.exitCode, + 0, + reason: 'child process exited with code ${await process.exitCode}, and ' + 'output:\n$output', + ); + + // Check the Dart tool prints the expected output. + expect(output, contains('A command-line utility for Dart development.')); + expect(output, contains('Usage: dart [arguments]')); + + return output; +} + +// The executable batch entrypoint for the Dart binary. +File get dartBatch { + return flutterRoot + .childDirectory('bin') + .childFile('dart.bat') + .absolute; +} + +// The Dart SDK's stamp file. +File get dartSdkStamp { + return flutterRoot + .childDirectory('bin') + .childDirectory('cache') + .childFile('engine-dart-sdk.stamp') + .absolute; +} From e10d74b4d5ceea963c5f194df16098920c18c517 Mon Sep 17 00:00:00 2001 From: yaakovschectman <109111084+yaakovschectman@users.noreply.github.com> Date: Thu, 17 Aug 2023 13:26:17 -0400 Subject: [PATCH 0767/1547] Revert "[Windows] Allow overwriting the cache's Dart SDK archive license file" (#132773) Reverts flutter/flutter#132669 Introduced failure on `windows/mac/linux framework_library_tests`. ``` 05:41 +7318 ~22 -1: /b/s/w/ir/x/w/flutter/packages/flutter/test/material/menu_bar_theme_test.dart: (tearDownAll) [E] Expected: leak free Actual: Which: contains leaks: # The text is generated by leak_tracker. # For leak troubleshooting tips open: # https://github.com/dart-lang/leak_tracker/blob/main/doc/TROUBLESHOOT.md notDisposed: total: 3 objects: ValueNotifier<_OverlayEntryWidgetState?>: test: Constructor parameters override theme parameters identityHashCode: 407433615 FocusScopeNode: test: Constructor parameters override theme parameters identityHashCode: 513181650 FocusScopeNode: test: Constructor parameters override theme parameters identityHashCode: 704743556 package:matcher expect package:flutter_test/src/widget_tester.dart 458:18 expect package:leak_tracker_flutter_testing/src/leak_tracking_flutter_testing.dart 81:5 _tearDownTestingWithLeakTracking ===== asynchronous gap =========================== dart:async _CustomZone.registerBinaryCallback package:leak_tracker_flutter_testing/src/leak_tracking_flutter_testing.dart 59:9 configureLeakTrackingTearDown. ``` --- bin/internal/update_dart_sdk.ps1 | 14 +-- .../batch_entrypoint_test.dart | 108 ------------------ 2 files changed, 3 insertions(+), 119 deletions(-) delete mode 100644 packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index 2d0d0fc732d2f..6af62a54f73b7 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -18,7 +18,6 @@ $flutterRoot = (Get-Item $progName).parent.parent.FullName $cachePath = "$flutterRoot\bin\cache" $dartSdkPath = "$cachePath\dart-sdk" -$dartSdkLicense = "$cachePath\LICENSE.dart_sdk_archive.md" $engineStamp = "$cachePath\engine-dart-sdk.stamp" $engineVersion = (Get-Content "$flutterRoot\bin\internal\engine.version") $engineRealm = (Get-Content "$flutterRoot\bin\internal\engine.realm") @@ -50,18 +49,11 @@ if ($engineRealm) { $dartZipName = "dart-sdk-windows-x64.zip" $dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName" -if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) { +if (Test-Path $dartSdkPath) { # Move old SDK to a new location instead of deleting it in case it is still in use (e.g. by IntelliJ). $oldDartSdkSuffix = 1 while (Test-Path "$cachePath\$oldDartSdkPrefix$oldDartSdkSuffix") { $oldDartSdkSuffix++ } - - if (Test-Path $dartSdkPath) { - Rename-Item $dartSdkPath "$oldDartSdkPrefix$oldDartSdkSuffix" - } - - if (Test-Path $dartSdkLicense) { - Rename-Item $dartSdkLicense "$oldDartSdkPrefix$oldDartSdkSuffix.LICENSE.md" - } + Rename-Item $dartSdkPath "$oldDartSdkPrefix$oldDartSdkSuffix" } New-Item $dartSdkPath -force -type directory | Out-Null $dartSdkZip = "$cachePath\$dartZipName" @@ -106,5 +98,5 @@ If (Get-Command 7z -errorAction SilentlyContinue) { Remove-Item $dartSdkZip $engineVersion | Out-File $engineStamp -Encoding ASCII -# Try to delete all old SDKs and license files. +# Try to delete all old SDKs. Get-ChildItem -Path $cachePath | Where {$_.BaseName.StartsWith($oldDartSdkPrefix)} | Remove-Item -Recurse -ErrorAction SilentlyContinue diff --git a/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart deleted file mode 100644 index e360aa9a8f5a0..0000000000000 --- a/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; -import 'dart:convert'; - -import 'package:file/file.dart'; -import 'package:flutter_tools/src/base/io.dart'; - -import '../src/common.dart'; -import 'test_utils.dart'; - -final String flutterRootPath = getFlutterRoot(); -final Directory flutterRoot = fileSystem.directory(flutterRootPath); - -Future main() async { - // Regression test for https://github.com/flutter/flutter/issues/132592 - test('flutter/bin/dart updates the Dart SDK without hanging', () async { - // Run the Dart entrypoint once to ensure the Dart SDK is downloaded. - await runDartBatch(); - - expect(dartSdkStamp.existsSync(), true); - - // Remove the Dart SDK stamp and run the Dart entrypoint again to trigger - // the Dart SDK update. - dartSdkStamp.deleteSync(); - final Future runFuture = runDartBatch(); - final Timer timer = Timer(const Duration(minutes: 5), () { - // This print is useful for people debugging this test. Normally we would - // avoid printing in a test but this is an exception because it's useful - // ambient information. - // ignore: avoid_print - print( - 'The Dart batch entrypoint did not complete after 5 minutes. ' - 'Historically this is a sign that 7-Zip zip extraction is waiting for ' - 'the user to confirm they would like to overwrite files. ' - "This likely means the test isn't a flake and will fail. " - 'See: https://github.com/flutter/flutter/issues/132592' - ); - }); - - final String output = await runFuture; - timer.cancel(); - - // Check the Dart SDK was re-downloaded and extracted. - // If 7-Zip is installed, unexpected overwrites causes this to hang. - // If 7-Zip is not installed, unexpected overwrites results in error messages. - // See: https://github.com/flutter/flutter/issues/132592 - expect(dartSdkStamp.existsSync(), true); - expect(output, contains('Downloading Dart SDK from Flutter engine ...')); - expect(output, contains('Expanding downloaded archive...')); - expect(output, isNot(contains('Use the -Force parameter' /* Luke */))); - }, - skip: !platform.isWindows); // [intended] Only Windows uses the batch entrypoint -} - -Future runDartBatch() async { - String output = ''; - final Process process = await processManager.start( - [ - dartBatch.path - ], - ); - final Future stdoutFuture = process.stdout - .transform(utf8.decoder) - .forEach((String str) { - output += str; - }); - final Future stderrFuture = process.stderr - .transform(utf8.decoder) - .forEach((String str) { - output += str; - }); - - // Wait for the output to complete - await Future.wait(>[stdoutFuture, stderrFuture]); - // Ensure child exited successfully - expect( - await process.exitCode, - 0, - reason: 'child process exited with code ${await process.exitCode}, and ' - 'output:\n$output', - ); - - // Check the Dart tool prints the expected output. - expect(output, contains('A command-line utility for Dart development.')); - expect(output, contains('Usage: dart [arguments]')); - - return output; -} - -// The executable batch entrypoint for the Dart binary. -File get dartBatch { - return flutterRoot - .childDirectory('bin') - .childFile('dart.bat') - .absolute; -} - -// The Dart SDK's stamp file. -File get dartSdkStamp { - return flutterRoot - .childDirectory('bin') - .childDirectory('cache') - .childFile('engine-dart-sdk.stamp') - .absolute; -} From 609382a8c435f541bb94ceebe5f7d2f699a535f6 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 17 Aug 2023 10:40:05 -0700 Subject: [PATCH 0768/1547] Disable test order randomization on some leak tracker tests that are failing with today's seed (#132766) --- packages/flutter/test/material/menu_bar_theme_test.dart | 4 ++++ packages/flutter/test/material/menu_theme_test.dart | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index 2b9dabe7f403d..c4717282c3c75 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Fails with "flutter test --test-randomize-ordering-seed=20230817" +@Tags(['no-shuffle']) +library; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index bb4c0cd3ce973..b5437e386416b 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Fails with "flutter test --test-randomize-ordering-seed=20230817" +@Tags(['no-shuffle']) +library; + import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; From 6a02483044ab6a30fffb8ba575856b23d486c5ab Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 17 Aug 2023 11:42:57 -0700 Subject: [PATCH 0769/1547] Run new_gallery__transition_perf on Pixel 7 and Samsung A02 (#132772) --- .ci.yaml | 80 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 85754964c7ced..055e328f1c92a 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -50,6 +50,18 @@ platform_properties: ] os: Linux device_type: "msm8952" + + linux_pixel_7pro: + properties: + dependencies: >- + [ + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "curl", "version": "version:7.64.0"} + ] + os: Linux + device_type: "Pixel 7 Pro" + linux_samsung_s10: properties: dependencies: >- @@ -2272,15 +2284,6 @@ targets: ["devicelab", "android", "linux"] task_name: old_gallery__transition_perf - - name: Linux_android new_gallery__transition_perf - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "android", "linux"] - task_name: new_gallery__transition_perf - - name: Linux_build_test flutter_gallery__transition_perf recipe: devicelab/devicelab_drone_build_test presubmit: false @@ -2326,6 +2329,17 @@ targets: ["devicelab", "android", "linux"] task_name: flutter_gallery__transition_perf_with_semantics + # MotoG4, Skia + - name: Linux_android new_gallery__transition_perf + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux"] + task_name: new_gallery__transition_perf + + # Samsung S10, Skia - name: Linux_samsung_s10 new_gallery__transition_perf recipe: devicelab/devicelab_drone presubmit: false @@ -2335,6 +2349,29 @@ targets: ["devicelab", "android", "linux", "samsung", "s10"] task_name: new_gallery__transition_perf + # Pixel 7 Pro, Skia + - name: Linux_pixel_7pro new_gallery__transition_perf + recipe: devicelab/devicelab_drone + bringup: true + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux", "pixel", "7pro"] + task_name: new_gallery__transition_perf + + # Samsung A02, Skia + - name: Linux_samsung_a02 new_gallery__transition_perf + recipe: devicelab/devicelab_drone + bringup: true + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux", "samsung", "a02"] + task_name: new_gallery__transition_perf + + # Moto G4, Impeller (OpenGL) - name: Linux_android new_gallery_impeller__transition_perf recipe: devicelab/devicelab_drone presubmit: false @@ -2346,6 +2383,30 @@ targets: ["devicelab", "android", "linux"] task_name: new_gallery_impeller__transition_perf + # Pixel 7 Pro, Impeller (Vulkan) + - name: Linux_pixel_7pro new_gallery_impeller__transition_perf + recipe: devicelab/devicelab_drone + bringup: true + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux", "pixel", "7pro"] + task_name: new_gallery_impeller__transition_perf + + # Samsung A02, Impeller (OpenGL) + - name: Linux_samsung_a02 new_gallery_impeller__transition_perf + bringup: true + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + ignore_flakiness: "true" + tags: > + ["devicelab", "android", "linux", "samsung", "a02"] + task_name: new_gallery_impeller__transition_perf + + # Samsung S10, Impeller (Vulkan) - name: Linux_samsung_s10 new_gallery_impeller__transition_perf bringup: true # Flaky https://github.com/flutter/flutter/issues/124693 recipe: devicelab/devicelab_drone @@ -2357,6 +2418,7 @@ targets: ["devicelab", "android", "linux", "samsung", "s10"] task_name: new_gallery_impeller__transition_perf + # Samsung S10, Impeller (OpenGL) - name: Linux_samsung_s10 new_gallery_opengles_impeller__transition_perf bringup: true recipe: devicelab/devicelab_drone From 9e67e0e4a13b40de3ec843adf269a491ed60507e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 17 Aug 2023 11:45:18 -0700 Subject: [PATCH 0770/1547] =?UTF-8?q?[Windows]=20Allow=20overwriting=20the?= =?UTF-8?q?=20cache's=20Dart=20SDK=20archive=20license=20file=E2=80=A6=20(?= =?UTF-8?q?#132777)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relands https://github.com/flutter/flutter/pull/132669 after it was reverted by https://github.com/flutter/flutter/pull/132773. The test failures were fixed separately by https://github.com/flutter/flutter/pull/132766 Tracking issue: https://github.com/flutter/flutter/issues/132592 Cherrypick issue: https://github.com/flutter/flutter/issues/132718 --- bin/internal/update_dart_sdk.ps1 | 14 ++- .../batch_entrypoint_test.dart | 108 ++++++++++++++++++ 2 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index 6af62a54f73b7..2d0d0fc732d2f 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -18,6 +18,7 @@ $flutterRoot = (Get-Item $progName).parent.parent.FullName $cachePath = "$flutterRoot\bin\cache" $dartSdkPath = "$cachePath\dart-sdk" +$dartSdkLicense = "$cachePath\LICENSE.dart_sdk_archive.md" $engineStamp = "$cachePath\engine-dart-sdk.stamp" $engineVersion = (Get-Content "$flutterRoot\bin\internal\engine.version") $engineRealm = (Get-Content "$flutterRoot\bin\internal\engine.realm") @@ -49,11 +50,18 @@ if ($engineRealm) { $dartZipName = "dart-sdk-windows-x64.zip" $dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName" -if (Test-Path $dartSdkPath) { +if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) { # Move old SDK to a new location instead of deleting it in case it is still in use (e.g. by IntelliJ). $oldDartSdkSuffix = 1 while (Test-Path "$cachePath\$oldDartSdkPrefix$oldDartSdkSuffix") { $oldDartSdkSuffix++ } - Rename-Item $dartSdkPath "$oldDartSdkPrefix$oldDartSdkSuffix" + + if (Test-Path $dartSdkPath) { + Rename-Item $dartSdkPath "$oldDartSdkPrefix$oldDartSdkSuffix" + } + + if (Test-Path $dartSdkLicense) { + Rename-Item $dartSdkLicense "$oldDartSdkPrefix$oldDartSdkSuffix.LICENSE.md" + } } New-Item $dartSdkPath -force -type directory | Out-Null $dartSdkZip = "$cachePath\$dartZipName" @@ -98,5 +106,5 @@ If (Get-Command 7z -errorAction SilentlyContinue) { Remove-Item $dartSdkZip $engineVersion | Out-File $engineStamp -Encoding ASCII -# Try to delete all old SDKs. +# Try to delete all old SDKs and license files. Get-ChildItem -Path $cachePath | Where {$_.BaseName.StartsWith($oldDartSdkPrefix)} | Remove-Item -Recurse -ErrorAction SilentlyContinue diff --git a/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart new file mode 100644 index 0000000000000..e360aa9a8f5a0 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart @@ -0,0 +1,108 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; + +import 'package:file/file.dart'; +import 'package:flutter_tools/src/base/io.dart'; + +import '../src/common.dart'; +import 'test_utils.dart'; + +final String flutterRootPath = getFlutterRoot(); +final Directory flutterRoot = fileSystem.directory(flutterRootPath); + +Future main() async { + // Regression test for https://github.com/flutter/flutter/issues/132592 + test('flutter/bin/dart updates the Dart SDK without hanging', () async { + // Run the Dart entrypoint once to ensure the Dart SDK is downloaded. + await runDartBatch(); + + expect(dartSdkStamp.existsSync(), true); + + // Remove the Dart SDK stamp and run the Dart entrypoint again to trigger + // the Dart SDK update. + dartSdkStamp.deleteSync(); + final Future runFuture = runDartBatch(); + final Timer timer = Timer(const Duration(minutes: 5), () { + // This print is useful for people debugging this test. Normally we would + // avoid printing in a test but this is an exception because it's useful + // ambient information. + // ignore: avoid_print + print( + 'The Dart batch entrypoint did not complete after 5 minutes. ' + 'Historically this is a sign that 7-Zip zip extraction is waiting for ' + 'the user to confirm they would like to overwrite files. ' + "This likely means the test isn't a flake and will fail. " + 'See: https://github.com/flutter/flutter/issues/132592' + ); + }); + + final String output = await runFuture; + timer.cancel(); + + // Check the Dart SDK was re-downloaded and extracted. + // If 7-Zip is installed, unexpected overwrites causes this to hang. + // If 7-Zip is not installed, unexpected overwrites results in error messages. + // See: https://github.com/flutter/flutter/issues/132592 + expect(dartSdkStamp.existsSync(), true); + expect(output, contains('Downloading Dart SDK from Flutter engine ...')); + expect(output, contains('Expanding downloaded archive...')); + expect(output, isNot(contains('Use the -Force parameter' /* Luke */))); + }, + skip: !platform.isWindows); // [intended] Only Windows uses the batch entrypoint +} + +Future runDartBatch() async { + String output = ''; + final Process process = await processManager.start( + [ + dartBatch.path + ], + ); + final Future stdoutFuture = process.stdout + .transform(utf8.decoder) + .forEach((String str) { + output += str; + }); + final Future stderrFuture = process.stderr + .transform(utf8.decoder) + .forEach((String str) { + output += str; + }); + + // Wait for the output to complete + await Future.wait(>[stdoutFuture, stderrFuture]); + // Ensure child exited successfully + expect( + await process.exitCode, + 0, + reason: 'child process exited with code ${await process.exitCode}, and ' + 'output:\n$output', + ); + + // Check the Dart tool prints the expected output. + expect(output, contains('A command-line utility for Dart development.')); + expect(output, contains('Usage: dart [arguments]')); + + return output; +} + +// The executable batch entrypoint for the Dart binary. +File get dartBatch { + return flutterRoot + .childDirectory('bin') + .childFile('dart.bat') + .absolute; +} + +// The Dart SDK's stamp file. +File get dartSdkStamp { + return flutterRoot + .childDirectory('bin') + .childDirectory('cache') + .childFile('engine-dart-sdk.stamp') + .absolute; +} From f1d04a46cb31903383a26e82572bfdd57330c9fb Mon Sep 17 00:00:00 2001 From: Chinmoy Date: Fri, 18 Aug 2023 00:18:57 +0530 Subject: [PATCH 0771/1547] Update `Scrollable` on `ScrollBehaviour` change. (#131164) Fixes: #130793 --- .../flutter/lib/src/widgets/scrollable.dart | 6 + .../flutter/test/widgets/scrollable_test.dart | 107 ++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index dfd3a80a6781f..0d7a24a857753 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -632,6 +632,12 @@ class ScrollableState extends State with TickerProviderStateMixin, R } bool _shouldUpdatePosition(Scrollable oldWidget) { + if ((widget.scrollBehavior == null) != (oldWidget.scrollBehavior == null)) { + return true; + } + if (widget.scrollBehavior != null && oldWidget.scrollBehavior != null && widget.scrollBehavior!.shouldNotify(oldWidget.scrollBehavior!)) { + return true; + } ScrollPhysics? newPhysics = widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context); ScrollPhysics? oldPhysics = oldWidget.physics ?? oldWidget.scrollBehavior?.getScrollPhysics(context); do { diff --git a/packages/flutter/test/widgets/scrollable_test.dart b/packages/flutter/test/widgets/scrollable_test.dart index 01ba9bccef8d3..c5d5b5fd014df 100644 --- a/packages/flutter/test/widgets/scrollable_test.dart +++ b/packages/flutter/test/widgets/scrollable_test.dart @@ -1356,6 +1356,113 @@ void main() { 'AlwaysScrollableScrollPhysics ClampingScrollPhysics RangeMaintainingScrollPhysics', ); }); + + testWidgets('dragDevices change updates widget', (WidgetTester tester) async { + bool enable = false; + + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MaterialApp( + home: Scaffold( + body: Scrollable( + scrollBehavior: const MaterialScrollBehavior().copyWith(dragDevices: { + if (enable) ui.PointerDeviceKind.mouse, + }), + viewportBuilder: (BuildContext context, ViewportOffset position) => Viewport( + offset: position, + slivers: const [ + SliverToBoxAdapter(child: SizedBox(height: 2000.0)), + ], + ), + ), + floatingActionButton: FloatingActionButton(onPressed: () { + setState(() { + enable = !enable; + }); + }), + ), + ); + }, + ); + }, + ) + ); + + // Gesture should not work. + TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse); + expect(getScrollOffset(tester), 0.0); + await gesture.moveBy(const Offset(0.0, -200)); + await tester.pumpAndSettle(); + expect(getScrollOffset(tester), 0.0); + + // Change state to include mouse pointer device. + await tester.tap(find.byType(FloatingActionButton)); + await tester.pump(); + + // Gesture should work after state change. + gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse); + expect(getScrollOffset(tester), 0.0); + await gesture.moveBy(const Offset(0.0, -200)); + await tester.pumpAndSettle(); + expect(getScrollOffset(tester), 200); + }); + + testWidgets('dragDevices change updates widget when oldWidget scrollBehavior is null', (WidgetTester tester) async { + ScrollBehavior? scrollBehavior; + + await tester.pumpWidget( + Builder( + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MaterialApp( + home: Scaffold( + body: Scrollable( + physics: const ScrollPhysics(), + scrollBehavior: scrollBehavior, + viewportBuilder: (BuildContext context, ViewportOffset position) => Viewport( + offset: position, + slivers: const [ + SliverToBoxAdapter(child: SizedBox(height: 2000.0)), + ], + ), + ), + floatingActionButton: FloatingActionButton(onPressed: () { + setState(() { + scrollBehavior = const MaterialScrollBehavior().copyWith(dragDevices: { + ui.PointerDeviceKind.mouse + }); + }); + }), + ), + ); + }, + ); + }, + ) + ); + + // Gesture should not work. + TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse); + expect(getScrollOffset(tester), 0.0); + await gesture.moveBy(const Offset(0.0, -200)); + await tester.pumpAndSettle(); + expect(getScrollOffset(tester), 0.0); + + // Change state to include mouse pointer device. + await tester.tap(find.byType(FloatingActionButton)); + await tester.pump(); + + // Gesture should work after state change. + gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse); + expect(getScrollOffset(tester), 0.0); + await gesture.moveBy(const Offset(0.0, -200)); + await tester.pumpAndSettle(); + expect(getScrollOffset(tester), 200); + }); } // ignore: must_be_immutable From f1fa9e34c68555513bfa72fc065eecf6bf179dbe Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 17 Aug 2023 11:51:31 -0700 Subject: [PATCH 0772/1547] Update the tracing_tests Dart SDK version constraint to fix an analyzer error (#132753) --- dev/tracing_tests/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 1792a44f6d6d0..829f03ee2585b 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -2,7 +2,7 @@ name: tracing_tests description: Various tests for tracing in flutter/flutter environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: From f0bfd7d641ec650c929e62018b14b6027b813410 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Thu, 17 Aug 2023 11:56:57 -0700 Subject: [PATCH 0773/1547] Send `examples/api` PRs to the framework review queue (#132768) --- .github/labeler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/labeler.yml b/.github/labeler.yml index bda4edfa98d5e..543d4927e9712 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -77,6 +77,7 @@ framework: - packages/flutter_goldens_client/**/* - packages/flutter_test/**/* - packages/integration_test/**/* + - examples/api/**/* 'f: integration_test': - packages/integration_test/**/* From aa1bacb35a88fe464c636fde4cb8e7daea4de567 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 17 Aug 2023 12:11:24 -0700 Subject: [PATCH 0774/1547] Leaks fix. (#132778) Fixes https://github.com/flutter/flutter/issues/132769 --- packages/flutter/lib/src/material/menu_anchor.dart | 2 ++ packages/flutter/lib/src/widgets/focus_manager.dart | 1 + packages/flutter/test/material/menu_bar_theme_test.dart | 4 ---- packages/flutter/test/material/menu_theme_test.dart | 4 ---- 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index dd293e43405d2..f2dfeeea5ee49 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -303,6 +303,7 @@ class _MenuAnchorState extends State { _anchorChildren.clear(); _menuController._detach(this); _internalMenuController = null; + _menuScopeNode.dispose(); super.dispose(); } @@ -551,6 +552,7 @@ class _MenuAnchorState extends State { } _closeChildren(inDispose: inDispose); _overlayEntry?.remove(); + _overlayEntry?.dispose(); _overlayEntry = null; if (!inDispose) { // Notify that _childIsOpen changed state, but only if not diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index f534b992f7a8d..9a4576ea32a83 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -1480,6 +1480,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { @override void dispose() { _highlightManager.dispose(); + rootScope.dispose(); super.dispose(); } diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index c4717282c3c75..2b9dabe7f403d 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Fails with "flutter test --test-randomize-ordering-seed=20230817" -@Tags(['no-shuffle']) -library; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index b5437e386416b..bb4c0cd3ce973 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Fails with "flutter test --test-randomize-ordering-seed=20230817" -@Tags(['no-shuffle']) -library; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; From a70a852c66f97fdba03acaf10d51755d0ac13929 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Thu, 17 Aug 2023 16:09:44 -0700 Subject: [PATCH 0775/1547] Run gsutil with full python3 and full path. (#132805) This is to prevent failures when the gsutil.py is not executable. --- dev/bots/prepare_package.dart | 10 +--------- dev/bots/test/prepare_package_test.dart | 4 ++-- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/dev/bots/prepare_package.dart b/dev/bots/prepare_package.dart index 9f33a22cc3003..bf30ae38c4ccb 100644 --- a/dev/bots/prepare_package.dart +++ b/dev/bots/prepare_package.dart @@ -833,16 +833,8 @@ class ArchivePublisher { print('gsutil.py -- $args'); return ''; } - if (platform.isWindows) { - return _processRunner.runProcess( - ['python3', path.join(platform.environment['DEPOT_TOOLS']!, 'gsutil.py'), '--', ...args], - workingDirectory: workingDirectory, - failOk: failOk, - ); - } - return _processRunner.runProcess( - ['gsutil.py', '--', ...args], + ['python3', path.join(platform.environment['DEPOT_TOOLS']!, 'gsutil.py'), '--', ...args], workingDirectory: workingDirectory, failOk: failOk, ); diff --git a/dev/bots/test/prepare_package_test.dart b/dev/bots/test/prepare_package_test.dart index e8e5cac08f5c1..10ba341cc3078 100644 --- a/dev/bots/test/prepare_package_test.dart +++ b/dev/bots/test/prepare_package_test.dart @@ -38,7 +38,7 @@ void main() { final FakePlatform platform = FakePlatform( operatingSystem: platformName, environment: { - 'DEPOT_TOOLS': path.join('D:', 'depot_tools'), + 'DEPOT_TOOLS': platformName == Platform.windows ? path.join('D:', 'depot_tools'): '/depot_tools', }, ); group('ProcessRunner for $platform', () { @@ -378,7 +378,7 @@ void main() { late Directory tempDir; final String gsutilCall = platform.isWindows ? 'python3 ${path.join("D:", "depot_tools", "gsutil.py")}' - : 'gsutil.py'; + : 'python3 ${path.join("/", "depot_tools", "gsutil.py")}'; final String releasesName = 'releases_$platformName.json'; final String archiveName = platform.isLinux ? 'archive.tar.xz' : 'archive.zip'; final String archiveMime = platform.isLinux ? 'application/x-gtar' : 'application/zip'; From fb7baa9e027f8b04b9904471f70d4ee62a31f11a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 17 Aug 2023 19:30:12 -0400 Subject: [PATCH 0776/1547] Roll Flutter Engine from 533670269c99 to 5019d6da655c (15 revisions) (#132797) https://github.com/flutter/engine/compare/533670269c99...5019d6da655c 2023-08-17 dkwingsmt@users.noreply.github.com Basic view management for engine classes (flutter/engine#42991) 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from d0d390f9310d to bfd45173e5e3 (5 revisions) (flutter/engine#44820) 2023-08-17 matanlurey@users.noreply.github.com Implement 2 suggested Clang Tidy fixes we don't look for yet. (flutter/engine#44816) 2023-08-17 louiseh0313@gmail.com Add share to selection controls (flutter/engine#44554) 2023-08-17 zanderso@users.noreply.github.com Adds new builders for partial clang-tidy checks. (flutter/engine#44811) 2023-08-17 41930132+hellohuanlin@users.noreply.github.com [ios][ios17]fix auto correction highlight on top left corner (flutter/engine#44779) 2023-08-17 109111084+yaakovschectman@users.noreply.github.com [Windows] Delay enabling app lifecycle states until requested (flutter/engine#44238) 2023-08-17 dkwingsmt@users.noreply.github.com Move `viewConfiguration` parsing from `PlatformDispatcher` to `_hooks` (flutter/engine#44787) 2023-08-17 skia-flutter-autoroll@skia.org Roll Dart SDK from 92c32df13d31 to 7e4e5796ee99 (2 revisions) (flutter/engine#44810) 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from c4805a975ab3 to d0d390f9310d (2 revisions) (flutter/engine#44807) 2023-08-17 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from cPncZK6z8HmuOmQr_... to 7xOzci7fempFgHNk9... (flutter/engine#44809) 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from efb5a5e0b78b to c4805a975ab3 (2 revisions) (flutter/engine#44795) 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from 11cb8cdd37c1 to efb5a5e0b78b (1 revision) (flutter/engine#44792) 2023-08-17 matanlurey@users.noreply.github.com Passthrough stderr results of clang_tidy when --enable-check-profile. (flutter/engine#44789) 2023-08-17 skia-flutter-autoroll@skia.org Roll Dart SDK from d6e1fca5dbdf to 92c32df13d31 (1 revision) (flutter/engine#44788) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from cPncZK6z8Hmu to 7xOzci7fempF If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d5b50ea839eb8..d0d7105766e9a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -533670269c99a8f552edb1e5bf5a17b706e54e5b +5019d6da655ca9dd0b1b041042c4983baa6eec39 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 2c965e97536c3..b4b78338fbebb 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -cPncZK6z8HmuOmQr_wP3MEXkUKsWRyPLc5j5W8aG4UUC +7xOzci7fempFgHNk9DxPxpBKoI2onNU4Ye8ElQaNa_QC From ac66bdb7ece3c08fbb2cadcabf1510a82209ec92 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 17 Aug 2023 19:30:14 -0400 Subject: [PATCH 0777/1547] Roll Packages from 9bf208f4beb6 to 3b602e77e69a (3 revisions) (#132784) https://github.com/flutter/packages/compare/9bf208f4beb6...3b602e77e69a 2023-08-16 ian@hixie.ch Add advice on code review for this repo (flutter/packages#4698) 2023-08-16 stuartmorgan@google.com [platform] Import the `platform` package (flutter/packages#4613) 2023-08-16 engine-flutter-autoroll@skia.org Roll Flutter from f0e7c5181641 to 2502b51f86c1 (15 revisions) (flutter/packages#4722) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 45e4e17a80cba..f1007925ecde4 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -9bf208f4beb6e4b8b26dd4df27871985f497cc5c +3b602e77e69aac91dbbf2e18260fb70d3a42df23 From 3f34b480c8999466b6a3489e71a2359cbfd408f6 Mon Sep 17 00:00:00 2001 From: LouiseHsu Date: Thu, 17 Aug 2023 16:36:11 -0700 Subject: [PATCH 0778/1547] [Framework] Add Share to selection controls (#132599) In native iOS, users are able to select text and initiate a share menu, which provides several standard services, such as copy, sharing to social media, direct ability to send to various contacts through messaging apps, etc. https://github.com/flutter/engine/assets/36148254/d0af7034-31fd-412e-8636-a06bbff54765 This PR is the framework portion of the changes that will allow Share to be implemented. The corresponding merged engine PR is [here](https://github.com/flutter/engine/pull/44554) This PR addresses https://github.com/flutter/flutter/issues/107578 More details are available in this [design doc](https://github.com/flutter/engine/pull/flutter.dev/go/add-missing-features-to-selection-controls) --- .../adaptive_text_selection_toolbar.dart | 2 + .../lib/src/cupertino/localizations.dart | 7 + .../text_selection_toolbar_button.dart | 3 + .../adaptive_text_selection_toolbar.dart | 4 + .../src/material/material_localizations.dart | 6 + .../flutter/lib/src/services/text_input.dart | 15 +- .../src/widgets/context_menu_button_item.dart | 3 + .../lib/src/widgets/editable_text.dart | 50 +++- .../adaptive_text_selection_toolbar_test.dart | 3 +- .../test/cupertino/text_field_test.dart | 107 +++----- .../test/cupertino/text_selection_test.dart | 33 ++- .../adaptive_text_selection_toolbar_test.dart | 7 +- .../test/material/localizations_test.dart | 1 + .../test/material/text_field_test.dart | 183 ++++++++++++-- .../test/widgets/editable_text_test.dart | 1 + .../test/widgets/selectable_text_test.dart | 22 +- .../lib/src/l10n/cupertino_af.arb | 3 +- .../lib/src/l10n/cupertino_am.arb | 3 +- .../lib/src/l10n/cupertino_ar.arb | 3 +- .../lib/src/l10n/cupertino_as.arb | 3 +- .../lib/src/l10n/cupertino_az.arb | 3 +- .../lib/src/l10n/cupertino_be.arb | 3 +- .../lib/src/l10n/cupertino_bg.arb | 3 +- .../lib/src/l10n/cupertino_bn.arb | 3 +- .../lib/src/l10n/cupertino_bs.arb | 3 +- .../lib/src/l10n/cupertino_ca.arb | 3 +- .../lib/src/l10n/cupertino_cs.arb | 3 +- .../lib/src/l10n/cupertino_cy.arb | 3 +- .../lib/src/l10n/cupertino_da.arb | 3 +- .../lib/src/l10n/cupertino_de.arb | 3 +- .../lib/src/l10n/cupertino_el.arb | 3 +- .../lib/src/l10n/cupertino_en.arb | 5 + .../lib/src/l10n/cupertino_es.arb | 3 +- .../lib/src/l10n/cupertino_et.arb | 3 +- .../lib/src/l10n/cupertino_eu.arb | 3 +- .../lib/src/l10n/cupertino_fa.arb | 3 +- .../lib/src/l10n/cupertino_fi.arb | 3 +- .../lib/src/l10n/cupertino_fil.arb | 3 +- .../lib/src/l10n/cupertino_fr.arb | 3 +- .../lib/src/l10n/cupertino_gl.arb | 3 +- .../lib/src/l10n/cupertino_gsw.arb | 3 +- .../lib/src/l10n/cupertino_gu.arb | 3 +- .../lib/src/l10n/cupertino_he.arb | 3 +- .../lib/src/l10n/cupertino_hi.arb | 3 +- .../lib/src/l10n/cupertino_hr.arb | 3 +- .../lib/src/l10n/cupertino_hu.arb | 3 +- .../lib/src/l10n/cupertino_hy.arb | 3 +- .../lib/src/l10n/cupertino_id.arb | 3 +- .../lib/src/l10n/cupertino_is.arb | 3 +- .../lib/src/l10n/cupertino_it.arb | 3 +- .../lib/src/l10n/cupertino_ja.arb | 3 +- .../lib/src/l10n/cupertino_ka.arb | 3 +- .../lib/src/l10n/cupertino_kk.arb | 3 +- .../lib/src/l10n/cupertino_km.arb | 3 +- .../lib/src/l10n/cupertino_kn.arb | 3 +- .../lib/src/l10n/cupertino_ko.arb | 3 +- .../lib/src/l10n/cupertino_ky.arb | 3 +- .../lib/src/l10n/cupertino_lo.arb | 3 +- .../lib/src/l10n/cupertino_lt.arb | 3 +- .../lib/src/l10n/cupertino_lv.arb | 3 +- .../lib/src/l10n/cupertino_mk.arb | 3 +- .../lib/src/l10n/cupertino_ml.arb | 3 +- .../lib/src/l10n/cupertino_mn.arb | 3 +- .../lib/src/l10n/cupertino_mr.arb | 3 +- .../lib/src/l10n/cupertino_ms.arb | 3 +- .../lib/src/l10n/cupertino_my.arb | 3 +- .../lib/src/l10n/cupertino_nb.arb | 3 +- .../lib/src/l10n/cupertino_ne.arb | 3 +- .../lib/src/l10n/cupertino_nl.arb | 3 +- .../lib/src/l10n/cupertino_no.arb | 3 +- .../lib/src/l10n/cupertino_or.arb | 3 +- .../lib/src/l10n/cupertino_pa.arb | 3 +- .../lib/src/l10n/cupertino_pl.arb | 3 +- .../lib/src/l10n/cupertino_pt.arb | 3 +- .../lib/src/l10n/cupertino_ro.arb | 3 +- .../lib/src/l10n/cupertino_ru.arb | 3 +- .../lib/src/l10n/cupertino_si.arb | 3 +- .../lib/src/l10n/cupertino_sk.arb | 3 +- .../lib/src/l10n/cupertino_sl.arb | 3 +- .../lib/src/l10n/cupertino_sq.arb | 3 +- .../lib/src/l10n/cupertino_sr.arb | 3 +- .../lib/src/l10n/cupertino_sv.arb | 3 +- .../lib/src/l10n/cupertino_sw.arb | 3 +- .../lib/src/l10n/cupertino_ta.arb | 3 +- .../lib/src/l10n/cupertino_te.arb | 3 +- .../lib/src/l10n/cupertino_th.arb | 3 +- .../lib/src/l10n/cupertino_tl.arb | 3 +- .../lib/src/l10n/cupertino_tr.arb | 3 +- .../lib/src/l10n/cupertino_uk.arb | 3 +- .../lib/src/l10n/cupertino_ur.arb | 3 +- .../lib/src/l10n/cupertino_uz.arb | 3 +- .../lib/src/l10n/cupertino_vi.arb | 3 +- .../lib/src/l10n/cupertino_zh.arb | 3 +- .../lib/src/l10n/cupertino_zu.arb | 3 +- .../generated_cupertino_localizations.dart | 234 +++++++++++++++++ .../generated_material_localizations.dart | 237 ++++++++++++++++++ .../lib/src/l10n/material_af.arb | 3 +- .../lib/src/l10n/material_am.arb | 3 +- .../lib/src/l10n/material_ar.arb | 3 +- .../lib/src/l10n/material_as.arb | 3 +- .../lib/src/l10n/material_az.arb | 3 +- .../lib/src/l10n/material_be.arb | 3 +- .../lib/src/l10n/material_bg.arb | 3 +- .../lib/src/l10n/material_bn.arb | 3 +- .../lib/src/l10n/material_bs.arb | 3 +- .../lib/src/l10n/material_ca.arb | 3 +- .../lib/src/l10n/material_cs.arb | 3 +- .../lib/src/l10n/material_cy.arb | 3 +- .../lib/src/l10n/material_da.arb | 3 +- .../lib/src/l10n/material_de.arb | 3 +- .../lib/src/l10n/material_el.arb | 3 +- .../lib/src/l10n/material_en.arb | 5 + .../lib/src/l10n/material_es.arb | 3 +- .../lib/src/l10n/material_et.arb | 3 +- .../lib/src/l10n/material_eu.arb | 3 +- .../lib/src/l10n/material_fa.arb | 3 +- .../lib/src/l10n/material_fi.arb | 3 +- .../lib/src/l10n/material_fil.arb | 3 +- .../lib/src/l10n/material_fr.arb | 3 +- .../lib/src/l10n/material_gl.arb | 3 +- .../lib/src/l10n/material_gsw.arb | 3 +- .../lib/src/l10n/material_gu.arb | 3 +- .../lib/src/l10n/material_he.arb | 3 +- .../lib/src/l10n/material_hi.arb | 3 +- .../lib/src/l10n/material_hr.arb | 3 +- .../lib/src/l10n/material_hu.arb | 3 +- .../lib/src/l10n/material_hy.arb | 3 +- .../lib/src/l10n/material_id.arb | 3 +- .../lib/src/l10n/material_is.arb | 3 +- .../lib/src/l10n/material_it.arb | 3 +- .../lib/src/l10n/material_ja.arb | 3 +- .../lib/src/l10n/material_ka.arb | 3 +- .../lib/src/l10n/material_kk.arb | 3 +- .../lib/src/l10n/material_km.arb | 3 +- .../lib/src/l10n/material_kn.arb | 3 +- .../lib/src/l10n/material_ko.arb | 3 +- .../lib/src/l10n/material_ky.arb | 3 +- .../lib/src/l10n/material_lo.arb | 3 +- .../lib/src/l10n/material_lt.arb | 3 +- .../lib/src/l10n/material_lv.arb | 3 +- .../lib/src/l10n/material_mk.arb | 3 +- .../lib/src/l10n/material_ml.arb | 3 +- .../lib/src/l10n/material_mn.arb | 3 +- .../lib/src/l10n/material_mr.arb | 3 +- .../lib/src/l10n/material_ms.arb | 3 +- .../lib/src/l10n/material_my.arb | 3 +- .../lib/src/l10n/material_nb.arb | 3 +- .../lib/src/l10n/material_ne.arb | 3 +- .../lib/src/l10n/material_nl.arb | 3 +- .../lib/src/l10n/material_no.arb | 3 +- .../lib/src/l10n/material_or.arb | 3 +- .../lib/src/l10n/material_pa.arb | 3 +- .../lib/src/l10n/material_pl.arb | 3 +- .../lib/src/l10n/material_ps.arb | 3 +- .../lib/src/l10n/material_pt.arb | 3 +- .../lib/src/l10n/material_ro.arb | 3 +- .../lib/src/l10n/material_ru.arb | 3 +- .../lib/src/l10n/material_si.arb | 3 +- .../lib/src/l10n/material_sk.arb | 3 +- .../lib/src/l10n/material_sl.arb | 3 +- .../lib/src/l10n/material_sq.arb | 3 +- .../lib/src/l10n/material_sr.arb | 3 +- .../lib/src/l10n/material_sv.arb | 3 +- .../lib/src/l10n/material_sw.arb | 3 +- .../lib/src/l10n/material_ta.arb | 3 +- .../lib/src/l10n/material_te.arb | 3 +- .../lib/src/l10n/material_th.arb | 3 +- .../lib/src/l10n/material_tl.arb | 3 +- .../lib/src/l10n/material_tr.arb | 3 +- .../lib/src/l10n/material_uk.arb | 3 +- .../lib/src/l10n/material_ur.arb | 3 +- .../lib/src/l10n/material_uz.arb | 3 +- .../lib/src/l10n/material_vi.arb | 3 +- .../lib/src/l10n/material_zh.arb | 3 +- .../lib/src/l10n/material_zu.arb | 3 +- 175 files changed, 1108 insertions(+), 285 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart b/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart index 3db3f35f2e03e..da1c8bb08239b 100644 --- a/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart +++ b/packages/flutter/lib/src/cupertino/adaptive_text_selection_toolbar.dart @@ -96,6 +96,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { required VoidCallback? onSelectAll, required VoidCallback? onLookUp, required VoidCallback? onSearchWeb, + required VoidCallback? onShare, required VoidCallback? onLiveTextInput, required this.anchors, }) : children = null, @@ -107,6 +108,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { onSelectAll: onSelectAll, onLookUp: onLookUp, onSearchWeb: onSearchWeb, + onShare: onShare, onLiveTextInput: onLiveTextInput ); diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index ca00238129544..17bccd35b5859 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -253,6 +253,10 @@ abstract class CupertinoLocalizations { // The global version uses the translated string from the arb file. String get searchWebButtonLabel; + /// The term used for launching a web search on a selection. + // The global version uses the translated string from the arb file. + String get shareButtonLabel; + /// The default placeholder used in [CupertinoSearchTextField]. // The global version uses the translated string from the arb file. String get searchTextFieldPlaceholderLabel; @@ -469,6 +473,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { @override String get searchWebButtonLabel => 'Search Web'; + @override + String get shareButtonLabel => 'Share...'; + @override String get searchTextFieldPlaceholderLabel => 'Search'; diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart index 93ffd737e1296..140cd216135e1 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart @@ -109,6 +109,8 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget { return localizations.lookUpButtonLabel; case ContextMenuButtonType.searchWeb: return localizations.searchWebButtonLabel; + case ContextMenuButtonType.share: + return localizations.shareButtonLabel; case ContextMenuButtonType.liveTextInput: case ContextMenuButtonType.delete: case ContextMenuButtonType.custom: @@ -195,6 +197,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State 'Search Web'; + @override + String get shareButtonLabel => 'Share...'; + @override String get viewLicensesButtonLabel => 'View licenses'; diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index cad6abd56dd72..29684ccb8d88a 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -1038,24 +1038,27 @@ mixin TextSelectionDelegate { /// input. void bringIntoView(TextPosition position); - /// Whether cut is enabled, must not be null. + /// Whether cut is enabled. bool get cutEnabled => true; - /// Whether copy is enabled, must not be null. + /// Whether copy is enabled. bool get copyEnabled => true; - /// Whether paste is enabled, must not be null. + /// Whether paste is enabled. bool get pasteEnabled => true; - /// Whether select all is enabled, must not be null. + /// Whether select all is enabled. bool get selectAllEnabled => true; - /// Whether look up is enabled, must not be null. + /// Whether look up is enabled. bool get lookUpEnabled => true; - /// Whether search web is enabled, must not be null. + /// Whether search web is enabled. bool get searchWebEnabled => true; + /// Whether share is enabled. + bool get shareEnabled => true; + /// Whether Live Text input is enabled. /// /// See also: diff --git a/packages/flutter/lib/src/widgets/context_menu_button_item.dart b/packages/flutter/lib/src/widgets/context_menu_button_item.dart index 9c2bf132e3154..896cbab9d20ec 100644 --- a/packages/flutter/lib/src/widgets/context_menu_button_item.dart +++ b/packages/flutter/lib/src/widgets/context_menu_button_item.dart @@ -32,6 +32,9 @@ enum ContextMenuButtonType { /// A button that launches a web search for the current text selection. searchWeb, + /// A button that displays the share screen for the current text selection. + share, + /// A button for starting Live Text input. /// /// See also: diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index da2014017544f..246b9b7d71d2c 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1874,6 +1874,7 @@ class EditableText extends StatefulWidget { required final VoidCallback? onSelectAll, required final VoidCallback? onLookUp, required final VoidCallback? onSearchWeb, + required final VoidCallback? onShare, required final VoidCallback? onLiveTextInput, }) { final List resultButtonItem = []; @@ -1914,6 +1915,11 @@ class EditableText extends StatefulWidget { onPressed: onSearchWeb, type: ContextMenuButtonType.searchWeb, ), + if (onShare != null) + ContextMenuButtonItem( + onPressed: onShare, + type: ContextMenuButtonType.share, + ), ]); } @@ -2291,6 +2297,17 @@ class EditableTextState extends State with AutomaticKeepAliveClien && textEditingValue.selection.textInside(textEditingValue.text).trim() != ''; } + @override + bool get shareEnabled { + if (defaultTargetPlatform != TargetPlatform.iOS) { + return false; + } + + return !widget.obscureText + && !textEditingValue.selection.isCollapsed + && textEditingValue.selection.textInside(textEditingValue.text).trim() != ''; + } + @override bool get liveTextInputEnabled { return _liveTextInputStatus?.value == LiveTextInputStatus.enabled && @@ -2456,8 +2473,11 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } - /// Look up the current selection, as in the "Look Up" edit menu button on iOS. + /// Look up the current selection, + /// as in the "Look Up" edit menu button on iOS. + /// /// Currently this is only implemented for iOS. + /// /// Throws an error if the selection is empty or collapsed. Future lookUpSelection(SelectionChangedCause cause) async { assert(!widget.obscureText); @@ -2473,9 +2493,10 @@ class EditableTextState extends State with AutomaticKeepAliveClien } /// Launch a web search on the current selection, - /// as in the "Search Web" edit menu button on iOS. + /// as in the "Search Web" edit menu button on iOS. /// /// Currently this is only implemented for iOS. + /// /// When 'obscureText' is true or the selection is empty, /// this function will not do anything Future searchWebForSelection(SelectionChangedCause cause) async { @@ -2493,6 +2514,28 @@ class EditableTextState extends State with AutomaticKeepAliveClien } } + /// Launch the share interface for the current selection, + /// as in the "Share" edit menu button on iOS. + /// + /// Currently this is only implemented for iOS. + /// + /// When 'obscureText' is true or the selection is empty, + /// this function will not do anything + Future shareSelection(SelectionChangedCause cause) async { + assert(!widget.obscureText); + if (widget.obscureText) { + return; + } + + final String text = textEditingValue.selection.textInside(textEditingValue.text); + if (text.isNotEmpty) { + await SystemChannels.platform.invokeMethod( + 'Share.invoke', + text, + ); + } + } + void _startLiveTextInput(SelectionChangedCause cause) { if (!liveTextInputEnabled) { return; @@ -2725,6 +2768,9 @@ class EditableTextState extends State with AutomaticKeepAliveClien onSearchWeb: searchWebEnabled ? () => searchWebForSelection(SelectionChangedCause.toolbar) : null, + onShare: shareEnabled + ? () => shareSelection(SelectionChangedCause.toolbar) + : null, onLiveTextInput: liveTextInputEnabled ? () => _startLiveTextInput(SelectionChangedCause.toolbar) : null, diff --git a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart index 83c535c461472..70f4be6d4518b 100644 --- a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart @@ -177,6 +177,7 @@ void main() { onLiveTextInput: () {}, onLookUp: () {}, onSearchWeb: () {}, + onShare: () {}, ), ), )); @@ -202,7 +203,7 @@ void main() { case TargetPlatform.macOS: case TargetPlatform.linux: case TargetPlatform.windows: - expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(7)); + expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(8)); } }, skip: kIsWeb, // [intended] on web the browser handles the context menu. diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index e9fc95e818357..46c6262b1f669 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -250,7 +250,7 @@ void main() { }, ); - testWidgets('Look Up shows up on iOS only (CupertinoTextField)', (WidgetTester tester) async { + testWidgets('Look Up shows up on iOS only', (WidgetTester tester) async { String? lastLookUp; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -299,62 +299,13 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Look Up shows up on iOS only (TextField)', (WidgetTester tester) async { - String? lastLookUp; - TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { - if (methodCall.method == 'LookUp.invoke') { - expect(methodCall.arguments, isA()); - lastLookUp = methodCall.arguments as String; - } - return null; - }); - - final TextEditingController controller = TextEditingController( - text: 'Test ', - ); - await tester.pumpWidget( - MaterialApp( - home: Material( - child: TextField( - controller: controller, - ), - ), - ), - ); - - final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; - - // Long press to put the cursor after the "s". - const int index = 3; - await tester.longPressAt(textOffsetToPosition(tester, index)); - await tester.pump(); - - // Double tap on the same location to select the word around the cursor. - await tester.tapAt(textOffsetToPosition(tester, index)); - await tester.pump(const Duration(milliseconds: 50)); - await tester.tapAt(textOffsetToPosition(tester, index)); - await tester.pumpAndSettle(); - - expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); - expect(find.text('Look Up'), isTargetPlatformiOS? findsOneWidget : findsNothing); - - if (isTargetPlatformiOS) { - await tester.tap(find.text('Look Up')); - expect(lastLookUp, 'Test'); - } - }, - variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), - skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. - ); - - testWidgets('Search Web shows up on iOS only (CupertinoTextField)', (WidgetTester tester) async { - String? lastLookUp; + testWidgets('Search Web shows up on iOS only', (WidgetTester tester) async { + String? lastSearch; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { if (methodCall.method == 'SearchWeb.invoke') { expect(methodCall.arguments, isA()); - lastLookUp = methodCall.arguments as String; + lastSearch = methodCall.arguments as String; } return null; }); @@ -390,31 +341,31 @@ void main() { if (isTargetPlatformiOS) { await tester.tap(find.text('Search Web')); - expect(lastLookUp, 'Test'); + expect(lastSearch, 'Test'); } }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Search Web shows up on iOS only (TextField)', (WidgetTester tester) async { - String? lastLookUp; + testWidgets('Share shows up on iOS only', (WidgetTester tester) async { + String? lastShare; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { - if (methodCall.method == 'SearchWeb.invoke') { + if (methodCall.method == 'Share.invoke') { expect(methodCall.arguments, isA()); - lastLookUp = methodCall.arguments as String; + lastShare = methodCall.arguments as String; } return null; }); final TextEditingController controller = TextEditingController( - text: 'Test ', + text: 'Test', ); await tester.pumpWidget( - MaterialApp( - home: Material( - child: TextField( + CupertinoApp( + home: Center( + child: CupertinoTextField( controller: controller, ), ), @@ -435,11 +386,11 @@ void main() { await tester.pumpAndSettle(); expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); - expect(find.text('Search Web'), isTargetPlatformiOS? findsOneWidget : findsNothing); + expect(find.text('Share...'), isTargetPlatformiOS? findsOneWidget : findsNothing); if (isTargetPlatformiOS) { - await tester.tap(find.text('Search Web')); - expect(lastLookUp, 'Test'); + await tester.tap(find.text('Share...')); + expect(lastShare, 'Test'); } }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), @@ -2210,7 +2161,7 @@ void main() { ); // Selected text shows 5 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Tap the selected word to hide the toolbar and retain the selection. await tester.tapAt(vPos); @@ -2228,7 +2179,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 24, extentOffset: 35), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Tap past the selected word to move the cursor and hide the toolbar. await tester.tapAt(ePos); @@ -2347,7 +2298,7 @@ void main() { case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - expect(find.byType(CupertinoButton), findsNWidgets(5)); + expect(find.byType(CupertinoButton), findsNWidgets(6)); } } }, @@ -2559,7 +2510,7 @@ void main() { ); // Selected text shows 3 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -3604,7 +3555,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); // Shows toolbar. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgets( @@ -3638,7 +3589,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Double tap selecting the same word somewhere else is fine. await tester.tapAt(textFieldStart + const Offset(100.0, 5.0)); @@ -3658,7 +3609,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); await tester.tapAt(textFieldStart + const Offset(150.0, 5.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -3674,7 +3625,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); group('Triple tap/click', () { @@ -4042,7 +3993,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(kDoubleTapTimeout); @@ -4068,7 +4019,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); // Third tap shows the toolbar and selects the paragraph. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -4077,7 +4028,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 36), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); await tester.tapAt(textfieldStart + const Offset(150.0, 25.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -4095,7 +4046,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 44, extentOffset: 50), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); // Third tap selects the paragraph and shows the toolbar. await tester.tapAt(textfieldStart + const Offset(150.0, 25.0)); @@ -4104,7 +4055,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 36, extentOffset: 66), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3))); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : (isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3))); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart index f3ee78c2a9ab7..53be97f0d2486 100644 --- a/packages/flutter/test/cupertino/text_selection_test.dart +++ b/packages/flutter/test/cupertino/text_selection_test.dart @@ -336,7 +336,7 @@ void main() { expect(find.text('Look Up'), findsNothing); expect(find.text('Search Web'), findsOneWidget); expect(findOverflowBackButton(), findsOneWidget); - expect(findOverflowNextButton(), findsNothing); + expect(findOverflowNextButton(), findsOneWidget); // Tapping the back button thrice shows the first page again with the next button. await tapBackButton(); @@ -394,6 +394,7 @@ void main() { expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsNothing); @@ -412,6 +413,7 @@ void main() { expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); @@ -424,6 +426,7 @@ void main() { expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); @@ -436,6 +439,7 @@ void main() { expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); @@ -447,10 +451,11 @@ void main() { expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsOneWidget); expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); expect(findOverflowNextButton(), findsOneWidget); - // Tapping the next button again shows the last page. + // Tapping the next button again shows the Search Web Button. await tapNextButton(); expect(find.text('Cut'), findsNothing); expect(find.text('Copy'), findsNothing); @@ -458,23 +463,27 @@ void main() { expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); expect(find.text('Search Web'), findsOneWidget); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsOneWidget); - expect(findOverflowNextButton(), findsNothing); + expect(findOverflowNextButton(), findsOneWidget); - // Tapping the back button thrice shows the second page again with the next button. - await tapBackButton(); - await tapBackButton(); - await tapBackButton(); - expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(3)); + // Tapping the next button again shows the last page and the Share button + await tapNextButton(); expect(find.text('Cut'), findsNothing); - expect(find.text('Copy'), findsOneWidget); + expect(find.text('Copy'), findsNothing); expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsOneWidget); expect(findOverflowBackButton(), findsOneWidget); - expect(findOverflowNextButton(), findsOneWidget); + expect(findOverflowNextButton(), findsNothing); - // Tapping the back button again shows the first page again. + // Tapping the back button 5 times shows the first page again. + await tapBackButton(); + await tapBackButton(); + await tapBackButton(); + await tapBackButton(); await tapBackButton(); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(2)); expect(find.text('Cut'), findsOneWidget); @@ -482,6 +491,8 @@ void main() { expect(find.text('Paste'), findsNothing); expect(find.text('Select All'), findsNothing); expect(find.text('Look Up'), findsNothing); + expect(find.text('Search Web'), findsNothing); + expect(find.text('Share...'), findsNothing); expect(findOverflowBackButton(), findsNothing); expect(findOverflowNextButton(), findsOneWidget); }, diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index 067ced62292ac..6313af09cd11c 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -194,6 +194,7 @@ void main() { onLiveTextInput: () {}, onLookUp: () {}, onSearchWeb: () {}, + onShare: () {}, ), ), ), @@ -211,7 +212,7 @@ void main() { expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(6)); case TargetPlatform.fuchsia: expect(find.text('Select all'), findsOneWidget); - expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(7)); + expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(8)); case TargetPlatform.iOS: expect(find.text('Select All'), findsOneWidget); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(6)); @@ -221,10 +222,10 @@ void main() { case TargetPlatform.linux: case TargetPlatform.windows: expect(find.text('Select all'), findsOneWidget); - expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(7)); + expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(8)); case TargetPlatform.macOS: expect(find.text('Select All'), findsOneWidget); - expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(7)); + expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(8)); } }, skip: kIsWeb, // [intended] on web the browser handles the context menu. diff --git a/packages/flutter/test/material/localizations_test.dart b/packages/flutter/test/material/localizations_test.dart index 7382be5ac2b9c..e0fdaccbbba82 100644 --- a/packages/flutter/test/material/localizations_test.dart +++ b/packages/flutter/test/material/localizations_test.dart @@ -32,6 +32,7 @@ void main() { expect(localizations.scanTextButtonLabel, isNotNull); expect(localizations.lookUpButtonLabel, isNotNull); expect(localizations.searchWebButtonLabel, isNotNull); + expect(localizations.shareButtonLabel, isNotNull); expect(localizations.okButtonLabel, isNotNull); expect(localizations.pasteButtonLabel, isNotNull); expect(localizations.selectAllButtonLabel, isNotNull); diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index 0776562880dd9..c105dbb2179e2 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -605,6 +605,153 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); + testWidgets('Look Up shows up on iOS only', (WidgetTester tester) async { + String? lastLookUp; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'LookUp.invoke') { + expect(methodCall.arguments, isA()); + lastLookUp = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test ', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Look Up'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Look Up')); + expect(lastLookUp, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + + testWidgets('Search Web shows up on iOS only', (WidgetTester tester) async { + String? lastSearch; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SearchWeb.invoke') { + expect(methodCall.arguments, isA()); + lastSearch = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test ', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Search Web'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Search Web')); + expect(lastSearch, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + + testWidgets('Share shows up on iOS only', (WidgetTester tester) async { + String? lastShare; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'Share.invoke') { + expect(methodCall.arguments, isA()); + lastShare = methodCall.arguments as String; + } + return null; + }); + + final TextEditingController controller = TextEditingController( + text: 'Test ', + ); + await tester.pumpWidget( + MaterialApp( + home: Material( + child: TextField( + controller: controller, + ), + ), + ), + ); + + final bool isTargetPlatformiOS = defaultTargetPlatform == TargetPlatform.iOS; + + // Long press to put the cursor after the "s". + const int index = 3; + await tester.longPressAt(textOffsetToPosition(tester, index)); + await tester.pump(); + + // Double tap on the same location to select the word around the cursor. + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(textOffsetToPosition(tester, index)); + await tester.pumpAndSettle(); + + expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 4)); + expect(find.text('Share...'), isTargetPlatformiOS? findsOneWidget : findsNothing); + + if (isTargetPlatformiOS) { + await tester.tap(find.text('Share...')); + expect(lastShare, 'Test'); + } + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.android }), + skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. + ); + testWidgets('uses DefaultSelectionStyle for selection and cursor colors if provided', (WidgetTester tester) async { const Color selectionColor = Colors.orange; const Color cursorColor = Colors.red; @@ -9252,7 +9399,7 @@ void main() { ); // Selected text shows 4 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Tap the selected word to hide the toolbar and retain the selection. await tester.tapAt(vPos); @@ -9270,7 +9417,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 24, extentOffset: 35), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Tap past the selected word to move the cursor and hide the toolbar. await tester.tapAt(ePos); @@ -9325,7 +9472,7 @@ void main() { ); // Selected text shows 5 toolbar buttons. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -10005,7 +10152,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); await tester.tapAt(textfieldStart + const Offset(50.0, 9.0)); await tester.pumpAndSettle(kDoubleTapTimeout); @@ -10029,7 +10176,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Third tap shows the toolbar and selects the paragraph. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -10038,7 +10185,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 36), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); await tester.tapAt(textfieldStart + const Offset(150.0, 50.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -10055,7 +10202,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 44, extentOffset: 50), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Third tap selects the paragraph and shows the toolbar. await tester.tapAt(textfieldStart + const Offset(150.0, 50.0)); @@ -10064,7 +10211,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 36, extentOffset: 66), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -11271,7 +11418,7 @@ void main() { ); // Selected text shows 4 toolbar buttons on iOS, and 3 on macOS. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)); await gesture.up(); await tester.pump(); @@ -11283,7 +11430,7 @@ void main() { ); // The toolbar is still showing. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -11415,7 +11562,7 @@ void main() { // Collapsed toolbar shows 3 buttons. expect( find.byType(CupertinoButton), - isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3) + isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3) ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), @@ -11719,7 +11866,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 23), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -11885,7 +12032,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 66, affinity: TextAffinity.upstream), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)); lastCharEndpoint = renderEditable.getEndpointsForSelection( const TextSelection.collapsed(offset: 66), // Last character's position. @@ -12478,7 +12625,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformMobile ? findsNWidgets(6) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -12576,7 +12723,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); // Double tap selecting the same word somewhere else is fine. await tester.tapAt(textfieldStart + const Offset(100.0, 9.0)); @@ -12596,7 +12743,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)); await tester.tapAt(textfieldStart + const Offset(150.0, 9.0)); await tester.pump(const Duration(milliseconds: 50)); @@ -12612,7 +12759,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(5) : findsNWidgets(3)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : isTargetPlatformIOS ? findsNWidgets(6) : findsNWidgets(3)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -13039,7 +13186,7 @@ void main() { await gesture.up(); await tester.pumpAndSettle(); - expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(5)); + expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 461085d7f2c47..776793e9939f2 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -156,6 +156,7 @@ void main() { onSelectAll: null, onLookUp: null, onSearchWeb: null, + onShare: null, onLiveTextInput: () { invokedLiveTextInputSuccessfully = true; }, diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index d23761c672f0f..9591f09db5e17 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -2959,7 +2959,7 @@ void main() { ); // Selected text shows 1 toolbar buttons on MacOS, 2 on iOS. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3090,7 +3090,7 @@ void main() { ); // Selected text shows 2 toolbar buttons for iOS, 1 for macOS. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); await gesture.up(); await tester.pump(); @@ -3101,7 +3101,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); // The toolbar is still showing. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3218,7 +3218,7 @@ void main() { ); // Toolbar shows one button. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3554,7 +3554,7 @@ void main() { ), ); // The toolbar now shows up. - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -3782,7 +3782,7 @@ void main() { ); // Long press toolbar. - expect(find.byType(CupertinoButton), findsNWidgets(3)); + expect(find.byType(CupertinoButton), findsNWidgets(4)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); @@ -3876,7 +3876,7 @@ void main() { const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -3911,7 +3911,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); // Double tap selecting the same word somewhere else is fine. await tester.pumpAndSettle(kDoubleTapTimeout); @@ -3928,7 +3928,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 0, extentOffset: 7), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); // Hide the toolbar so it doesn't interfere with taps on the text. final EditableTextState editableTextState = @@ -3950,7 +3950,7 @@ void main() { controller.selection, const TextSelection(baseOffset: 8, extentOffset: 12), ); - expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(3) : findsNWidgets(1)); + expect(find.byType(CupertinoButton), isTargetPlatformIOS ? findsNWidgets(4) : findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); @@ -4029,7 +4029,7 @@ void main() { await gesture.up(); await tester.pump(); - expect(find.byType(CupertinoButton), findsNWidgets(3)); + expect(find.byType(CupertinoButton), findsNWidgets(4)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb index 63fdff3a35bb3..8a689cc1deee5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_af.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Geen plaasvervangers gevind nie", "menuDismissLabel": "Maak kieslys toe", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb index 8868f33d05943..e2075ff897e2b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_am.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "ምንም ተተኪዎች አልተገኙም", "menuDismissLabel": "ምናሌን አሰናብት", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb index 94f8b4f694a4f..dbe42013b85bc 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ar.arb @@ -45,5 +45,6 @@ "noSpellCheckReplacementsLabel": "لم يتم العثور على بدائل", "menuDismissLabel": "إغلاق القائمة", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb index 66e5a29399e8f..18770258b9084 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_as.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "এইটোৰ সলনি ব্যৱহাৰ কৰিব পৰা শব্দ পোৱা নগ’ল", "menuDismissLabel": "অগ্ৰাহ্য কৰাৰ মেনু", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb index 6cbbc9c80246a..bef3e1de9a87c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_az.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Əvəzləmə Tapılmadı", "menuDismissLabel": "Menyunu qapadın", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb index 1eea20f397934..da1534cf8dcfe 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_be.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Замен не знойдзена", "menuDismissLabel": "Закрыць меню", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb index 0612ebb1c26a8..8c727de43f2fb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bg.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Не бяха намерени замествания", "menuDismissLabel": "Отхвърляне на менюто", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb index 7dacc3e55ee8f..df1afd72b0462 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bn.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "কোনও বিকল্প বানান দেখানো হয়নি", "menuDismissLabel": "বাতিল করার মেনু", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb index 1f7f39829c9ae..12f25c219eb56 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_bs.arb @@ -30,5 +30,6 @@ "noSpellCheckReplacementsLabel": "Nije pronađena nijedna zamjena", "menuDismissLabel": "Odbacivanje menija", "lookUpButtonLabel": "Pogled prema gore", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb index 9e1ca020a3589..e11eb138abc82 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ca.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "No s'ha trobat cap substitució", "menuDismissLabel": "Ignora el menú", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb index 4ff2ecea1f904..de7c1b5d53456 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cs.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Žádná nahrazení nenalezena", "menuDismissLabel": "Zavřít nabídku", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb index e2fb99160786a..90a118f4298dd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_cy.arb @@ -45,5 +45,6 @@ "noSpellCheckReplacementsLabel": "Dim Ailosodiadau wedi'u Canfod", "menuDismissLabel": "Diystyru'r ddewislen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb index be0462ef5dc19..29b7d4a691cdb 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_da.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Der blev ikke fundet nogen erstatninger", "menuDismissLabel": "Luk menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb index e9e966833b674..5eeefca1c7857 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_de.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Keine Ersetzungen gefunden", "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb index b8760eb5fb2e5..af1ee5a8bf999 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_el.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Δεν βρέθηκαν αντικαταστάσεις", "menuDismissLabel": "Παράβλεψη μενού", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb index c3342e6c90ec6..6f52dc78ead20 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_en.arb @@ -175,6 +175,11 @@ "description": "The label for the Search Web button and menu items on iOS." }, + "shareButtonLabel": "Share...", + "@shareButtonLabel": { + "description": "The label for the Share button and menu items on iOS." + }, + "noSpellCheckReplacementsLabel": "No Replacements Found", "@noSpellCheckReplacementsLabel": { "description": "The label shown in the text selection context menu on iOS when a misspelled word is tapped but the spell checker found no reasonable fixes for it." diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb index 8e56f84da6486..aab7584291ddd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_es.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "No se ha encontrado ninguna sustitución", "menuDismissLabel": "Cerrar menú", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb index a9d95e26670a6..c4c6c6acdc0b7 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_et.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Asendusi ei leitud", "menuDismissLabel": "Sulge menüü", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb index 486038ec12388..6d72858ff3d96 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_eu.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Ez da aurkitu ordezteko hitzik", "menuDismissLabel": "Baztertu menua", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb index 9e7746e8e7ee8..a36c89ba40177 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fa.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "جایگزینی پیدا نشد", "menuDismissLabel": "بستن منو", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb index f60f9befe4ad0..0c56ce534f27b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fi.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Korvaavia sanoja ei löydy", "menuDismissLabel": "Hylkää valikko", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb index 5a3169db878f2..e983d4d1a58c9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fil.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Walang Nahanap na Kapalit", "menuDismissLabel": "I-dismiss ang menu", "lookUpButtonLabel": "Tumingin sa Itaas", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb index c2f57d3c634b4..57ae553ba1f46 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_fr.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Aucun remplacement trouvé", "menuDismissLabel": "Fermer le menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb index 4abf412a8b200..2949a2246b0ae 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gl.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Non se encontrou ningunha substitución", "menuDismissLabel": "Pechar menú", "lookUpButtonLabel": "Mirar cara arriba", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb index e9e966833b674..5eeefca1c7857 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gsw.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Keine Ersetzungen gefunden", "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb index b36d349787617..40f2602774898 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_gu.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "બદલવા માટે કોઈ શબ્દ મળ્યો નથી", "menuDismissLabel": "મેનૂ છોડી દો", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb index 1fc4c3fb38481..b2537b0af3836 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_he.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "לא נמצאו חלופות", "menuDismissLabel": "סגירת התפריט", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb index bf2c4efca730b..d7262f017c029 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hi.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "सही वर्तनी वाला कोई शब्द नहीं मिला", "menuDismissLabel": "मेन्यू खारिज करें", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb index fbacf98ca93c3..9d68b3e925967 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hr.arb @@ -30,5 +30,6 @@ "noSpellCheckReplacementsLabel": "Nema pronađenih zamjena", "menuDismissLabel": "Odbacivanje izbornika", "lookUpButtonLabel": "Pogled prema gore", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb index df30e15e3cc24..1d91e5b830bab 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hu.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Nem található javítás", "menuDismissLabel": "Menü bezárása", "lookUpButtonLabel": "Felfelé nézés", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb index 24717182f339d..011211fb5c853 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_hy.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Փոխարինումներ չեն գտնվել", "menuDismissLabel": "Փակել ընտրացանկը", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb index f0fa3b0184e67..99c0fec3d64be 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_id.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Penggantian Tidak Ditemukan", "menuDismissLabel": "Tutup menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb index 110a1f4c1bd7c..f71f0c3f59e92 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_is.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Engir staðgenglar fundust", "menuDismissLabel": "Loka valmynd", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb index d3279d1f8af06..15c1b1c810288 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_it.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Nessuna sostituzione trovata", "menuDismissLabel": "Ignora menu", "lookUpButtonLabel": "Cerca", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb index 8fe4d8254fcd5..3fbfe7d9e057e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ja.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "置き換えるものがありません", "menuDismissLabel": "メニューを閉じる", "lookUpButtonLabel": "調べる", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb index a0c5f673c93ba..825a5c44560e6 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ka.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "ჩანაცვლება არ მოიძებნა", "menuDismissLabel": "მენიუს უარყოფა", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb index 41ab324684ccd..8501fc704dd09 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kk.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Ауыстыратын ешнәрсе табылмады.", "menuDismissLabel": "Мәзірді жабу", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb index 3d5ab7f762f6e..37da3ecc0dc66 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_km.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "រកមិនឃើញ​ការជំនួសទេ", "menuDismissLabel": "ច្រានចោល​ម៉ឺនុយ", "lookUpButtonLabel": "រកមើល", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb index df58925efc06b..ea83d91ff3aed 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_kn.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "\u0caf\u0cbe\u0cb5\u0cc1\u0ca6\u0cc7\u0020\u0cac\u0ca6\u0cb2\u0cbe\u0cb5\u0ca3\u0cc6\u0c97\u0cb3\u0cc1\u0020\u0c95\u0c82\u0ca1\u0cc1\u0cac\u0c82\u0ca6\u0cbf\u0cb2\u0ccd\u0cb2", "menuDismissLabel": "\u0cae\u0cc6\u0ca8\u0cc1\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0cb5\u0c9c\u0cbe\u0c97\u0cc6\u0cc2\u0cb3\u0cbf\u0cb8\u0cbf", "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070", - "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062" + "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062", + "shareButtonLabel": "\u0053\u0068\u0061\u0072\u0065\u002e\u002e\u002e" } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb index e2675a47012f4..44e5c3461877b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ko.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "수정사항 없음", "menuDismissLabel": "메뉴 닫기", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb index c519944a5f6bb..ed73ad35ea05b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ky.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Алмаштыруу үчүн сөз табылган жок", "menuDismissLabel": "Менюну жабуу", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb index ec0da5f846749..8e4b6e0785358 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lo.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "ບໍ່ພົບການແທນທີ່", "menuDismissLabel": "ປິດເມນູ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb index 1d292f3af76af..b1939982d36e2 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lt.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Nerasta jokių pakeitimų", "menuDismissLabel": "Atsisakyti meniu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb index 032d59fc39e12..9a7943d06c150 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_lv.arb @@ -30,5 +30,6 @@ "noSpellCheckReplacementsLabel": "Netika atrasts neviens vārds aizstāšanai", "menuDismissLabel": "Nerādīt izvēlni", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb index 12221747737b3..ad88d5b9cec1c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mk.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Не се најдени заменски зборови", "menuDismissLabel": "Отфрлете го менито", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb index d08cabfcd6d53..da34cc0fe3922 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ml.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "റീപ്ലേസ്‌മെന്റുകളൊന്നും കണ്ടെത്തിയില്ല", "menuDismissLabel": "മെനു ഡിസ്മിസ് ചെയ്യുക", "lookUpButtonLabel": "മുകളിലേക്ക് നോക്കുക", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb index 165bfc7b780a5..b8e4f2872babd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mn.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Ямар ч орлуулалт олдсонгүй", "menuDismissLabel": "Цэсийг хаах", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb index 0f73502e156b1..fae07c75fbd43 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_mr.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "कोणतेही बदल आढळले नाहीत", "menuDismissLabel": "मेनू डिसमिस करा", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb index 46cfe286821f0..d38bc94049ea5 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ms.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Tiada Penggantian Ditemukan", "menuDismissLabel": "Ketepikan menu", "lookUpButtonLabel": "Lihat ke Atas", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb index da28217742deb..2f58733fea43b 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_my.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "အစားထိုးမှုများ မတွေ့ပါ", "menuDismissLabel": "မီနူးကိုပယ်ပါ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb index 042c9abb17524..5492d2cbe0e28 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nb.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Fant ingen erstatninger", "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb index cd5b3d0c5d209..5738d2472ddbd 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ne.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "बदल्नु पर्ने कुनै पनि कुरा भेटिएन", "menuDismissLabel": "मेनु खारेज गर्नुहोस्", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb index 90e2b9c098006..d101c83979bc9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_nl.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Geen vervangingen gevonden", "menuDismissLabel": "Menu sluiten", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb index 042c9abb17524..5492d2cbe0e28 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_no.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Fant ingen erstatninger", "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb index d978bab219ff5..72de165a9ecf1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_or.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "କୌଣସି ରିପ୍ଲେସମେଣ୍ଟ ମିଳିଲା ନାହିଁ", "menuDismissLabel": "ମେନୁ ଖାରଜ କରନ୍ତୁ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb index 9d7bc0bbf93a0..ad72fbfbf4427 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pa.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "ਕੋਈ ਸੁਝਾਅ ਨਹੀਂ ਮਿਲਿਆ", "menuDismissLabel": "ਮੀਨੂ ਖਾਰਜ ਕਰੋ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb index 8beef78c9007e..36c88c9ebf498 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pl.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Brak wyników zamieniania", "menuDismissLabel": "Zamknij menu", "lookUpButtonLabel": "Sprawdź", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb index 93dab0c53b3d3..29c1cf87062df 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_pt.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Nenhuma alternativa encontrada", "menuDismissLabel": "Dispensar menu", "lookUpButtonLabel": "Pesquisar", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb index ffd6a6015135c..e78637cf5ee65 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ro.arb @@ -30,5 +30,6 @@ "noSpellCheckReplacementsLabel": "Nu s-au găsit înlocuiri", "menuDismissLabel": "Respingeți meniul", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb index 6a5be8cd7af6c..c0e93bea0954e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ru.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Варианты замены не найдены", "menuDismissLabel": "Закрыть меню", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb index 6d36ab10c912c..35a98c19b7120 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_si.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "ප්‍රතිස්ථාපන හමු නොවිණි", "menuDismissLabel": "මෙනුව අස් කරන්න", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb index 677cf0000896e..6bce1b40316a1 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sk.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Nenašli sa žiadne náhrady", "menuDismissLabel": "Zavrieť ponuku", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb index 35ac090121100..466533c382c2c 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sl.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Ni zamenjav", "menuDismissLabel": "Opusti meni", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb index 60ac372323932..f7f2ba5de95ce 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sq.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Nuk u gjetën zëvendësime", "menuDismissLabel": "Hiqe menynë", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb index 9333954f5624c..da22e63e74863 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sr.arb @@ -30,5 +30,6 @@ "noSpellCheckReplacementsLabel": "Нису пронађене замене", "menuDismissLabel": "Одбаците мени", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb index 710d31c53154b..3fceee58ba699 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sv.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Inga ersättningar hittades", "menuDismissLabel": "Stäng menyn", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb index 9b6e6f46fdb31..3836a6c61d859 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_sw.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Hakuna Neno Mbadala Lilopatikana", "menuDismissLabel": "Ondoa menyu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb index f194d76ba4ced..fb43d1bc64700 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ta.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "மாற்று வார்த்தைகள் கிடைக்கவில்லை", "menuDismissLabel": "மெனுவை மூடும்", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb index ff56d35e2ff76..0e53a7e958255 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_te.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "రీప్లేస్‌మెంట్‌లు ఏవీ కనుగొనబడలేదు", "menuDismissLabel": "మెనూను తీసివేయండి", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb index fa71c08e8efa1..c6699874372f3 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_th.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "ไม่พบรายการแทนที่", "menuDismissLabel": "ปิดเมนู", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb index 5a3169db878f2..e983d4d1a58c9 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tl.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Walang Nahanap na Kapalit", "menuDismissLabel": "I-dismiss ang menu", "lookUpButtonLabel": "Tumingin sa Itaas", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb index e199c28f20064..59bfa3eccf53e 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_tr.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Yerine Kelime Bulunamadı", "menuDismissLabel": "Menüyü kapat", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb index 6e5197872f241..6f50ab997fb9d 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uk.arb @@ -35,5 +35,6 @@ "noSpellCheckReplacementsLabel": "Замін не знайдено", "menuDismissLabel": "Закрити меню", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb index bc46e9886c6c5..ca0282cc6d285 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_ur.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "کوئی تبدیلیاں نہیں ملیں", "menuDismissLabel": "مینو برخاست کریں", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb index b2f27001f6a9d..86fd969dab4f8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_uz.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Almashtirish uchun soʻz topilmadi", "menuDismissLabel": "Menyuni yopish", "lookUpButtonLabel": "Tepaga qarang", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb index 46d8e91db9aa7..4b8277007bfd0 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_vi.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Không tìm thấy phương án thay thế", "menuDismissLabel": "Đóng trình đơn", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb index d8ab8311f321d..98f18f4ab1237 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zh.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "找不到替换文字", "menuDismissLabel": "关闭菜单", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb index 89eda26ed6230..6e37c0fa0e0a8 100644 --- a/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/cupertino_zu.arb @@ -25,5 +25,6 @@ "noSpellCheckReplacementsLabel": "Akukho Okuzofakwa Esikhundleni Okutholakele", "menuDismissLabel": "Chitha imenyu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart index 912ff7165b7fa..4b584dcc61eb5 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart @@ -118,6 +118,9 @@ class CupertinoLocalizationAf extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Kies alles'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Oortjie $tabIndex van $tabCount'; @@ -277,6 +280,9 @@ class CupertinoLocalizationAm extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'ሁሉንም ምረጥ'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'ትር $tabIndex ከ$tabCount'; @@ -436,6 +442,9 @@ class CupertinoLocalizationAr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'اختيار الكل'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'علامة التبويب $tabIndex من $tabCount'; @@ -595,6 +604,9 @@ class CupertinoLocalizationAs extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'সকলো বাছনি কৰক'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount টা টেবৰ $tabIndex নম্বৰটো'; @@ -754,6 +766,9 @@ class CupertinoLocalizationAz extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Hamısını seçin'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex/$tabCount'; @@ -913,6 +928,9 @@ class CupertinoLocalizationBe extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Выбраць усе'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Укладка $tabIndex з $tabCount'; @@ -1072,6 +1090,9 @@ class CupertinoLocalizationBg extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Избиране на всички'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Раздел $tabIndex от $tabCount'; @@ -1231,6 +1252,9 @@ class CupertinoLocalizationBn extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'সব বেছে নিন'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount-এর মধ্যে $tabIndex নম্বর ট্যাব'; @@ -1390,6 +1414,9 @@ class CupertinoLocalizationBs extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Odaberi sve'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Kartica $tabIndex od $tabCount'; @@ -1549,6 +1576,9 @@ class CupertinoLocalizationCa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Selecciona-ho tot'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Pestanya $tabIndex de $tabCount'; @@ -1708,6 +1738,9 @@ class CupertinoLocalizationCs extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Vybrat vše'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Karta $tabIndex z $tabCount'; @@ -1867,6 +1900,9 @@ class CupertinoLocalizationCy extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Dewis y Cyfan'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex o $tabCount'; @@ -2026,6 +2062,9 @@ class CupertinoLocalizationDa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Vælg alle'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Fane $tabIndex af $tabCount'; @@ -2185,6 +2224,9 @@ class CupertinoLocalizationDe extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Alles auswählen'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex von $tabCount'; @@ -2365,6 +2407,9 @@ class CupertinoLocalizationEl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Επιλογή όλων'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Καρτέλα $tabIndex από $tabCount'; @@ -2524,6 +2569,9 @@ class CupertinoLocalizationEn extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Select All'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex of $tabCount'; @@ -2917,6 +2965,9 @@ class CupertinoLocalizationEs extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Seleccionar todo'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Pestaña $tabIndex de $tabCount'; @@ -3976,6 +4027,9 @@ class CupertinoLocalizationEt extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Vali kõik'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabIndex. vaheleht $tabCount-st'; @@ -4135,6 +4189,9 @@ class CupertinoLocalizationEu extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Hautatu dena'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabIndex/$tabCount fitxa'; @@ -4294,6 +4351,9 @@ class CupertinoLocalizationFa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'انتخاب همه'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'برگه $tabIndex از $tabCount'; @@ -4453,6 +4513,9 @@ class CupertinoLocalizationFi extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Valitse kaikki'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Välilehti $tabIndex kautta $tabCount'; @@ -4612,6 +4675,9 @@ class CupertinoLocalizationFil extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Piliin Lahat'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex ng $tabCount'; @@ -4771,6 +4837,9 @@ class CupertinoLocalizationFr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Tout sélect.'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Onglet $tabIndex sur $tabCount'; @@ -4975,6 +5044,9 @@ class CupertinoLocalizationGl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Seleccionar todo'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Pestana $tabIndex de $tabCount'; @@ -5134,6 +5206,9 @@ class CupertinoLocalizationGsw extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Alles auswählen'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex von $tabCount'; @@ -5293,6 +5368,9 @@ class CupertinoLocalizationGu extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'બધા પસંદ કરો'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCountમાંથી $tabIndex ટૅબ'; @@ -5452,6 +5530,9 @@ class CupertinoLocalizationHe extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'בחירת הכול'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'כרטיסייה $tabIndex מתוך $tabCount'; @@ -5611,6 +5692,9 @@ class CupertinoLocalizationHi extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'सभी चुनें'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount का टैब $tabIndex'; @@ -5770,6 +5854,9 @@ class CupertinoLocalizationHr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Odaberi sve'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Kartica $tabIndex od $tabCount'; @@ -5929,6 +6016,9 @@ class CupertinoLocalizationHu extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Összes kijelölése'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount/$tabIndex. lap'; @@ -6088,6 +6178,9 @@ class CupertinoLocalizationHy extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Նշել բոլորը'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Ներդիր $tabIndex՝ $tabCount-ից'; @@ -6247,6 +6340,9 @@ class CupertinoLocalizationId extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Pilih Semua'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex dari $tabCount'; @@ -6406,6 +6502,9 @@ class CupertinoLocalizationIs extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Velja allt'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Flipi $tabIndex af $tabCount'; @@ -6565,6 +6664,9 @@ class CupertinoLocalizationIt extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Seleziona tutto'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Scheda $tabIndex di $tabCount'; @@ -6724,6 +6826,9 @@ class CupertinoLocalizationJa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'すべて選択'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'タブ: $tabIndex/$tabCount'; @@ -6883,6 +6988,9 @@ class CupertinoLocalizationKa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'ყველას არჩევა'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'ჩანართი $tabIndex / $tabCount-დან'; @@ -7042,6 +7150,9 @@ class CupertinoLocalizationKk extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Барлығын таңдау'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Қойынды: $tabIndex/$tabCount'; @@ -7201,6 +7312,9 @@ class CupertinoLocalizationKm extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'ជ្រើសរើស​ទាំងអស់'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'ផ្ទាំងទី $tabIndex នៃ $tabCount'; @@ -7360,6 +7474,9 @@ class CupertinoLocalizationKn extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => '\u{c8e}\u{cb2}\u{ccd}\u{cb2}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc2}\u{20}\u{c86}\u{caf}\u{ccd}\u{c95}\u{cc6}\u{cae}\u{cbe}\u{ca1}\u{cbf}'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => '\u{24}\u{74}\u{61}\u{62}\u{43}\u{6f}\u{75}\u{6e}\u{74}\u{20}\u{cb0}\u{cb2}\u{ccd}\u{cb2}\u{cbf}\u{ca8}\u{20}\u{24}\u{74}\u{61}\u{62}\u{49}\u{6e}\u{64}\u{65}\u{78}\u{20}\u{c9f}\u{ccd}\u{caf}\u{cbe}\u{cac}\u{ccd}'; @@ -7519,6 +7636,9 @@ class CupertinoLocalizationKo extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => '전체 선택'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'탭 $tabCount개 중 $tabIndex번째'; @@ -7678,6 +7798,9 @@ class CupertinoLocalizationKy extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Баарын тандоо'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount ичинен $tabIndex-өтмөк'; @@ -7837,6 +7960,9 @@ class CupertinoLocalizationLo extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'ເລືອກທັງໝົດ'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'ແຖບທີ $tabIndex ຈາກທັງໝົດ $tabCount'; @@ -7996,6 +8122,9 @@ class CupertinoLocalizationLt extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Pasirinkti viską'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabIndex skirtukas iš $tabCount'; @@ -8155,6 +8284,9 @@ class CupertinoLocalizationLv extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Atlasīt visu'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabIndex. cilne no $tabCount'; @@ -8314,6 +8446,9 @@ class CupertinoLocalizationMk extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Избери ги сите'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Картичка $tabIndex од $tabCount'; @@ -8473,6 +8608,9 @@ class CupertinoLocalizationMl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'എല്ലാം തിരഞ്ഞെടുക്കുക'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount ടാബിൽ $tabIndex-ാമത്തേത്'; @@ -8632,6 +8770,9 @@ class CupertinoLocalizationMn extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Бүгдийг сонгох'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount-н $tabIndex-р таб'; @@ -8791,6 +8932,9 @@ class CupertinoLocalizationMr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'सर्व निवडा'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount पैकी $tabIndex टॅब'; @@ -8950,6 +9094,9 @@ class CupertinoLocalizationMs extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Pilih Semua'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex daripada $tabCount'; @@ -9109,6 +9256,9 @@ class CupertinoLocalizationMy extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'အားလုံး ရွေးရန်'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'တဘ် $tabCount ခုအနက် $tabIndex ခု'; @@ -9268,6 +9418,9 @@ class CupertinoLocalizationNb extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Velg alle'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Fane $tabIndex av $tabCount'; @@ -9427,6 +9580,9 @@ class CupertinoLocalizationNe extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'सबै चयन गर्नुहोस्'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount मध्ये $tabIndex ट्याब'; @@ -9586,6 +9742,9 @@ class CupertinoLocalizationNl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Alles selecteren'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tabblad $tabIndex van $tabCount'; @@ -9745,6 +9904,9 @@ class CupertinoLocalizationNo extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Velg alle'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Fane $tabIndex av $tabCount'; @@ -9904,6 +10066,9 @@ class CupertinoLocalizationOr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'ସମସ୍ତ ଚୟନ କରନ୍ତୁ'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCountର $tabIndex ଟାବ୍'; @@ -10063,6 +10228,9 @@ class CupertinoLocalizationPa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'ਸਭ ਚੁਣੋ'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount ਵਿੱਚੋਂ $tabIndex ਟੈਬ'; @@ -10222,6 +10390,9 @@ class CupertinoLocalizationPl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Wybierz wszystkie'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Karta $tabIndex z $tabCount'; @@ -10381,6 +10552,9 @@ class CupertinoLocalizationPt extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Selecionar Tudo'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Guia $tabIndex de $tabCount'; @@ -10588,6 +10762,9 @@ class CupertinoLocalizationRo extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Selectați-le pe toate'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Fila $tabIndex din $tabCount'; @@ -10747,6 +10924,9 @@ class CupertinoLocalizationRu extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Выбрать все'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Вкладка $tabIndex из $tabCount'; @@ -10906,6 +11086,9 @@ class CupertinoLocalizationSi extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'සියල්ල තෝරන්න'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'ටැබ $tabCount න් $tabIndex'; @@ -11065,6 +11248,9 @@ class CupertinoLocalizationSk extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Vybrať všetko'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Karta $tabIndex z $tabCount'; @@ -11224,6 +11410,9 @@ class CupertinoLocalizationSl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Izberi vse'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Zavihek $tabIndex od $tabCount'; @@ -11383,6 +11572,9 @@ class CupertinoLocalizationSq extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Zgjidhi të gjitha'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Skeda $tabIndex nga $tabCount'; @@ -11542,6 +11734,9 @@ class CupertinoLocalizationSr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Изабери све'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabIndex. картица од $tabCount'; @@ -11821,6 +12016,9 @@ class CupertinoLocalizationSv extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Markera alla'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Flik $tabIndex av $tabCount'; @@ -11980,6 +12178,9 @@ class CupertinoLocalizationSw extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Teua Zote'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Kichupo cha $tabIndex kati ya $tabCount'; @@ -12139,6 +12340,9 @@ class CupertinoLocalizationTa extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'எல்லாம் தேர்ந்தெடு'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'தாவல் $tabIndex / $tabCount'; @@ -12298,6 +12502,9 @@ class CupertinoLocalizationTe extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'అన్నింటినీ ఎంచుకోండి'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCountలో $tabIndexవ ట్యాబ్'; @@ -12457,6 +12664,9 @@ class CupertinoLocalizationTh extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'เลือกทั้งหมด'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'แท็บที่ $tabIndex จาก $tabCount'; @@ -12616,6 +12826,9 @@ class CupertinoLocalizationTl extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Piliin Lahat'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Tab $tabIndex ng $tabCount'; @@ -12775,6 +12988,9 @@ class CupertinoLocalizationTr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Tümünü Seç'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Sekme $tabIndex/$tabCount'; @@ -12934,6 +13150,9 @@ class CupertinoLocalizationUk extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Вибрати все'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Вкладка $tabIndex з $tabCount'; @@ -13093,6 +13312,9 @@ class CupertinoLocalizationUr extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'سبھی منتخب کریں'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount میں سے $tabIndex ٹیب'; @@ -13252,6 +13474,9 @@ class CupertinoLocalizationUz extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Barchasini tanlash'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'$tabCount varaqdan $tabIndex'; @@ -13411,6 +13636,9 @@ class CupertinoLocalizationVi extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Chọn tất cả'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Thẻ $tabIndex/$tabCount'; @@ -13570,6 +13798,9 @@ class CupertinoLocalizationZh extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => '全选'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'第 $tabIndex 个标签,共 $tabCount 个'; @@ -13891,6 +14122,9 @@ class CupertinoLocalizationZu extends GlobalCupertinoLocalizations { @override String get selectAllButtonLabel => 'Khetha konke'; + @override + String get shareButtonLabel => 'Share...'; + @override String get tabSemanticsLabelRaw => r'Ithebhu $tabIndex kwangu-$tabCount'; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart index 2bed33afb469c..f454b13b92810 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart @@ -464,6 +464,9 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Wys rekeninge'; @@ -951,6 +954,9 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'መለያዎችን አሳይ'; @@ -1438,6 +1444,9 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'لم يتم اختيار أي عنصر'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'إظهار الحسابات'; @@ -1925,6 +1934,9 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'একাউণ্টসমূহ দেখুৱাওক'; @@ -2412,6 +2424,9 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Hesabları göstərin'; @@ -2899,6 +2914,9 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Паказаць уліковыя запісы'; @@ -3386,6 +3404,9 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Показване на профилите'; @@ -3873,6 +3894,9 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'অ্যাকাউন্টগুলি দেখান'; @@ -4360,6 +4384,9 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Prikaži račune'; @@ -4847,6 +4874,9 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Mostra els comptes'; @@ -5334,6 +5364,9 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Zobrazit účty'; @@ -5821,6 +5854,9 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => "Nid oes unrhyw eitemau wedi'u dewis"; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Dangos cyfrifon'; @@ -6308,6 +6344,9 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Vis konti'; @@ -6795,6 +6834,9 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Keine Objekte ausgewählt'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Konten anzeigen'; @@ -7346,6 +7388,9 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Εμφάνιση λογαριασμών'; @@ -7833,6 +7878,9 @@ class MaterialLocalizationEn extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'No items selected'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Show accounts'; @@ -9117,6 +9165,9 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'No se han seleccionado elementos'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Mostrar cuentas'; @@ -13407,6 +13458,9 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Kuva kontod'; @@ -13894,6 +13948,9 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Erakutsi kontuak'; @@ -14381,6 +14438,9 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'نشان دادن حساب‌ها'; @@ -14868,6 +14928,9 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Näytä tilit'; @@ -15355,6 +15418,9 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Ipakita ang mga account'; @@ -15842,6 +15908,9 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Aucun élément sélectionné'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Afficher les comptes'; @@ -16486,6 +16555,9 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Non se seleccionaron elementos'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Mostrar contas'; @@ -16973,6 +17045,9 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Konten anzeigen'; @@ -17460,6 +17535,9 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'એકાઉન્ટ બતાવો'; @@ -17947,6 +18025,9 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'הצגת החשבונות'; @@ -18434,6 +18515,9 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'खाते दिखाएं'; @@ -18921,6 +19005,9 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Prikažite račune'; @@ -19408,6 +19495,9 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Fiókok megjelenítése'; @@ -19895,6 +19985,9 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Տողերը ընտրված չեն'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Ցույց տալ հաշիվները'; @@ -20382,6 +20475,9 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Tampilkan akun'; @@ -20869,6 +20965,9 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Sýna reikninga'; @@ -21356,6 +21455,9 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Mostra account'; @@ -21843,6 +21945,9 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'アカウントを表示'; @@ -22330,6 +22435,9 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'ანგარიშების ჩვენება'; @@ -22817,6 +22925,9 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Тармақ таңдалмаған'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Аккаунттарды көрсету'; @@ -23304,6 +23415,9 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'បង្ហាញគណនី'; @@ -23791,6 +23905,9 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => '\u{c96}\u{cbe}\u{ca4}\u{cc6}\u{c97}\u{cb3}\u{ca8}\u{ccd}\u{ca8}\u{cc1}\u{20}\u{ca4}\u{ccb}\u{cb0}\u{cbf}\u{cb8}\u{cbf}'; @@ -24278,6 +24395,9 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => '계정 표시'; @@ -24765,6 +24885,9 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Аккаунттарды көрсөтүү'; @@ -25252,6 +25375,9 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'ສະແດງບັນຊີ'; @@ -25739,6 +25865,9 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Rodyti paskyras'; @@ -26226,6 +26355,9 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Nav atlasītu vienumu'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Rādīt kontus'; @@ -26713,6 +26845,9 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Прикажи сметки'; @@ -27200,6 +27335,9 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'അക്കൗണ്ടുകൾ കാണിക്കുക'; @@ -27687,6 +27825,9 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Бичлэг сонгоогүй байна'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Бүртгэлүүдийг харуулах'; @@ -28174,6 +28315,9 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'कोणतेही आयटम निवडलेले नाहीत'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'खाती दर्शवा'; @@ -28661,6 +28805,9 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Tiada item dipilih'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Tunjukkan akaun'; @@ -29148,6 +29295,9 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'အကောင့်များကို ပြရန်'; @@ -29635,6 +29785,9 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Vis kontoer'; @@ -30122,6 +30275,9 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'खाताहरू देखाउनुहोस्'; @@ -30609,6 +30765,9 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Accounts tonen'; @@ -31096,6 +31255,9 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Vis kontoer'; @@ -31583,6 +31745,9 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'ଆକାଉଣ୍ଟ ଦେଖାନ୍ତୁ'; @@ -32070,6 +32235,9 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'ਖਾਤੇ ਦਿਖਾਓ'; @@ -32557,6 +32725,9 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Pokaż konta'; @@ -33044,6 +33215,9 @@ class MaterialLocalizationPs extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'حسابونه ښکاره کړئ'; @@ -33531,6 +33705,9 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Mostrar contas'; @@ -34193,6 +34370,9 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Nu există elemente selectate'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Afișați conturile'; @@ -34680,6 +34860,9 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Строки не выбраны'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Показать аккаунты'; @@ -35167,6 +35350,9 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'ගිණුම් පෙන්වන්න'; @@ -35654,6 +35840,9 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Zobraziť účty'; @@ -36141,6 +36330,9 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Prikaz računov'; @@ -36628,6 +36820,9 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Shfaq llogaritë'; @@ -37115,6 +37310,9 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Прикажи налоге'; @@ -37940,6 +38138,9 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Visa konton'; @@ -38427,6 +38628,9 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'Hamna kilicho chaguliwa'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Onyesha akaunti'; @@ -38914,6 +39118,9 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => 'எந்த வரிசையும் தேர்ந்தெடுக்கவில்லை'; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'கணக்குகளைக் காட்டும்'; @@ -39401,6 +39608,9 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'ఖాతాలను చూపు'; @@ -39888,6 +40098,9 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'แสดงบัญชี'; @@ -40375,6 +40588,9 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Ipakita ang mga account'; @@ -40862,6 +41078,9 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Hesapları göster'; @@ -41349,6 +41568,9 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Показати облікові записи'; @@ -41836,6 +42058,9 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'اکاؤنٹس دکھائیں'; @@ -42323,6 +42548,9 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Hisoblarni koʻrsatish'; @@ -42810,6 +43038,9 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Hiển thị tài khoản'; @@ -43297,6 +43528,9 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => '显示帐号'; @@ -44319,6 +44553,9 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations { @override String? get selectedRowCountTitleZero => null; + @override + String get shareButtonLabel => 'Share...'; + @override String get showAccountsLabel => 'Bonisa ama-akhawunti'; diff --git a/packages/flutter_localizations/lib/src/l10n/material_af.arb b/packages/flutter_localizations/lib/src/l10n/material_af.arb index 3e1e66d314473..654ccdf1eacba 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_af.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_af.arb @@ -143,5 +143,6 @@ "collapsedHint": "Uitgevou", "menuDismissLabel": "Maak kieslys toe", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_am.arb b/packages/flutter_localizations/lib/src/l10n/material_am.arb index 6caf83f4384aa..20158502e0817 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_am.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_am.arb @@ -143,5 +143,6 @@ "collapsedHint": "ተዘርግቷል", "menuDismissLabel": "ምናሌን አሰናብት", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ar.arb b/packages/flutter_localizations/lib/src/l10n/material_ar.arb index a5b7b99d7e6fa..18ee13a83e302 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ar.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ar.arb @@ -154,5 +154,6 @@ "collapsedHint": "موسَّع", "menuDismissLabel": "إغلاق القائمة", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_as.arb b/packages/flutter_localizations/lib/src/l10n/material_as.arb index 61c41c07cbdcc..79fb39ea71c1f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_as.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_as.arb @@ -143,5 +143,6 @@ "collapsedHint": "বিস্তাৰ কৰা আছে", "menuDismissLabel": "অগ্ৰাহ্য কৰাৰ মেনু", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_az.arb b/packages/flutter_localizations/lib/src/l10n/material_az.arb index 262f0d13d1e18..cc2a3321445bf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_az.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_az.arb @@ -143,5 +143,6 @@ "collapsedHint": "Genişləndirildi", "menuDismissLabel": "Menyunu qapadın", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_be.arb b/packages/flutter_localizations/lib/src/l10n/material_be.arb index f4d12ae8d02d5..2c6dbca5b316c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_be.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_be.arb @@ -149,5 +149,6 @@ "collapsedHint": "Разгорнута", "menuDismissLabel": "Закрыць меню", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bg.arb b/packages/flutter_localizations/lib/src/l10n/material_bg.arb index 24680a1248730..ad124c3a09e24 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bg.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bg.arb @@ -144,5 +144,6 @@ "collapsedHint": "Разгънато", "menuDismissLabel": "Отхвърляне на менюто", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bn.arb b/packages/flutter_localizations/lib/src/l10n/material_bn.arb index eafd2c5da81dc..77d039992b6a6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bn.arb @@ -143,5 +143,6 @@ "collapsedHint": "বড় করা হয়েছে", "menuDismissLabel": "বাতিল করার মেনু", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_bs.arb b/packages/flutter_localizations/lib/src/l10n/material_bs.arb index c60645b4a35a5..424b0e7f9079c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_bs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_bs.arb @@ -147,5 +147,6 @@ "collapsedHint": "Prošireno", "menuDismissLabel": "Odbacivanje menija", "lookUpButtonLabel": "Pogled prema gore", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ca.arb b/packages/flutter_localizations/lib/src/l10n/material_ca.arb index 77d9a9df476fb..3f2b74212aad9 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ca.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ca.arb @@ -144,5 +144,6 @@ "collapsedHint": "S'ha desplegat", "menuDismissLabel": "Ignora el menú", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cs.arb b/packages/flutter_localizations/lib/src/l10n/material_cs.arb index e2965db5da5ae..dccaa7511212c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cs.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cs.arb @@ -150,5 +150,6 @@ "collapsedHint": "Rozbaleno", "menuDismissLabel": "Zavřít nabídku", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_cy.arb b/packages/flutter_localizations/lib/src/l10n/material_cy.arb index e7de18926689a..61ce3f86520be 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_cy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_cy.arb @@ -154,5 +154,6 @@ "scanTextButtonLabel": "Sganio testun", "menuDismissLabel": "Diystyru'r ddewislen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_da.arb b/packages/flutter_localizations/lib/src/l10n/material_da.arb index 96784884cd051..582686b1da882 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_da.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_da.arb @@ -144,5 +144,6 @@ "collapsedHint": "Udvidet", "menuDismissLabel": "Luk menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_de.arb b/packages/flutter_localizations/lib/src/l10n/material_de.arb index a877c493bc7e3..7739ab93f08f0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_de.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_de.arb @@ -145,5 +145,6 @@ "collapsedHint": "Maximiert", "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_el.arb b/packages/flutter_localizations/lib/src/l10n/material_el.arb index ab3f8fc8f89d1..48a6551b2ad8b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_el.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_el.arb @@ -144,5 +144,6 @@ "collapsedHint": "Αναπτύχθηκε", "menuDismissLabel": "Παράβλεψη μενού", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb index 4a43629e0c8ef..de77ae0c163e1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb @@ -207,6 +207,11 @@ "description": "The label for the Search Web button and menu items on iOS." }, + "shareButtonLabel": "Share...", + "@shareButtonLabel": { + "description": "The label for the Share button and menu items on iOS." + }, + "okButtonLabel": "OK", "@okButtonLabel": { "description": "The label for OK buttons and menu items." diff --git a/packages/flutter_localizations/lib/src/l10n/material_es.arb b/packages/flutter_localizations/lib/src/l10n/material_es.arb index 581574c0e18c1..044c124f1867d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_es.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_es.arb @@ -145,5 +145,6 @@ "collapsedHint": "Desplegado", "menuDismissLabel": "Cerrar menú", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_et.arb b/packages/flutter_localizations/lib/src/l10n/material_et.arb index 88dfb1a62734c..6f207f1d4d3c4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_et.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_et.arb @@ -144,5 +144,6 @@ "collapsedHint": "Laiendatud", "menuDismissLabel": "Sulge menüü", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_eu.arb b/packages/flutter_localizations/lib/src/l10n/material_eu.arb index d3a312a150b79..741eacdd0ad4d 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_eu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_eu.arb @@ -143,5 +143,6 @@ "collapsedHint": "Zabalduta", "menuDismissLabel": "Baztertu menua", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fa.arb b/packages/flutter_localizations/lib/src/l10n/material_fa.arb index 0b574b15e080f..35d66dd050c81 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fa.arb @@ -144,5 +144,6 @@ "collapsedHint": "ازهم بازشده", "menuDismissLabel": "بستن منو", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fi.arb b/packages/flutter_localizations/lib/src/l10n/material_fi.arb index a121b4f5e93c1..283690abdd086 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fi.arb @@ -144,5 +144,6 @@ "collapsedHint": "Laajennettu", "menuDismissLabel": "Hylkää valikko", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fil.arb b/packages/flutter_localizations/lib/src/l10n/material_fil.arb index fe87826b1efab..81500d0ee0cb3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fil.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fil.arb @@ -144,5 +144,6 @@ "collapsedHint": "Naka-expand", "menuDismissLabel": "I-dismiss ang menu", "lookUpButtonLabel": "Tumingin sa Itaas", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_fr.arb b/packages/flutter_localizations/lib/src/l10n/material_fr.arb index c0852da9b94c3..73ca135a2b17f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_fr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_fr.arb @@ -145,5 +145,6 @@ "collapsedHint": "Développé", "menuDismissLabel": "Fermer le menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gl.arb b/packages/flutter_localizations/lib/src/l10n/material_gl.arb index 4e95b281bf9df..c4989e91aa616 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gl.arb @@ -145,5 +145,6 @@ "collapsedHint": "Despregado", "menuDismissLabel": "Pechar menú", "lookUpButtonLabel": "Mirar cara arriba", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb index b191f16cd703a..6e459e9d0c27c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gsw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gsw.arb @@ -144,5 +144,6 @@ "collapsedHint": "Maximiert", "menuDismissLabel": "Menü schließen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_gu.arb b/packages/flutter_localizations/lib/src/l10n/material_gu.arb index 39b25a6a23327..ce1c833d9babb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_gu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_gu.arb @@ -143,5 +143,6 @@ "collapsedHint": "મોટી કરી", "menuDismissLabel": "મેનૂ છોડી દો", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_he.arb b/packages/flutter_localizations/lib/src/l10n/material_he.arb index 7b3d765f40bf8..7e5ed5c95455b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_he.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_he.arb @@ -150,5 +150,6 @@ "collapsedHint": "מורחב", "menuDismissLabel": "סגירת התפריט", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hi.arb b/packages/flutter_localizations/lib/src/l10n/material_hi.arb index e8e20261a3765..38ac3fd0bdb9b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hi.arb @@ -144,5 +144,6 @@ "collapsedHint": "बड़ा किया गया", "menuDismissLabel": "मेन्यू खारिज करें", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hr.arb b/packages/flutter_localizations/lib/src/l10n/material_hr.arb index a9de4551a4605..59cf13db5ece5 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hr.arb @@ -147,5 +147,6 @@ "collapsedHint": "Prošireno", "menuDismissLabel": "Odbacivanje izbornika", "lookUpButtonLabel": "Pogled prema gore", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hu.arb b/packages/flutter_localizations/lib/src/l10n/material_hu.arb index 3ae117f266446..df2ba6d9ccda8 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hu.arb @@ -144,5 +144,6 @@ "collapsedHint": "Kibontva", "menuDismissLabel": "Menü bezárása", "lookUpButtonLabel": "Felfelé nézés", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_hy.arb b/packages/flutter_localizations/lib/src/l10n/material_hy.arb index 60b330e90e5b9..8a005fda07db1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_hy.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_hy.arb @@ -149,5 +149,6 @@ "collapsedHint": "Ծավալված է", "menuDismissLabel": "Փակել ընտրացանկը", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_id.arb b/packages/flutter_localizations/lib/src/l10n/material_id.arb index 0702678801668..c43af93ec3991 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_id.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_id.arb @@ -144,5 +144,6 @@ "collapsedHint": "Diluaskan", "menuDismissLabel": "Tutup menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_is.arb b/packages/flutter_localizations/lib/src/l10n/material_is.arb index d4a1d4d9c3ccf..8dbc6518dd4b3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_is.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_is.arb @@ -143,5 +143,6 @@ "collapsedHint": "Stækkað", "menuDismissLabel": "Loka valmynd", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_it.arb b/packages/flutter_localizations/lib/src/l10n/material_it.arb index 8315404a73ad4..f8094612375f7 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_it.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_it.arb @@ -144,5 +144,6 @@ "collapsedHint": "Espanso", "menuDismissLabel": "Ignora menu", "lookUpButtonLabel": "Cerca", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ja.arb b/packages/flutter_localizations/lib/src/l10n/material_ja.arb index 5aaef029ecfde..02700410405be 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ja.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ja.arb @@ -144,5 +144,6 @@ "collapsedHint": "開きました", "menuDismissLabel": "メニューを閉じる", "lookUpButtonLabel": "調べる", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ka.arb b/packages/flutter_localizations/lib/src/l10n/material_ka.arb index 3dda9b4d7c7cf..1fc8909e336c0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ka.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ka.arb @@ -143,5 +143,6 @@ "collapsedHint": "გაფართოებულია", "menuDismissLabel": "მენიუს უარყოფა", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kk.arb b/packages/flutter_localizations/lib/src/l10n/material_kk.arb index a858f1c95ca6e..efd070ee1b8d1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kk.arb @@ -145,5 +145,6 @@ "collapsedHint": "Жайылды", "menuDismissLabel": "Мәзірді жабу", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_km.arb b/packages/flutter_localizations/lib/src/l10n/material_km.arb index b73f086693a18..c14c56ae2c1cf 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_km.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_km.arb @@ -144,5 +144,6 @@ "collapsedHint": "បាន​ពង្រីក", "menuDismissLabel": "ច្រានចោល​ម៉ឺនុយ", "lookUpButtonLabel": "រកមើល", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_kn.arb b/packages/flutter_localizations/lib/src/l10n/material_kn.arb index 4dd80f0c0022d..21cef3bf69d8f 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_kn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_kn.arb @@ -143,5 +143,6 @@ "collapsedHint": "\u0cb5\u0cbf\u0cb8\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6", "menuDismissLabel": "\u0cae\u0cc6\u0ca8\u0cc1\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0cb5\u0c9c\u0cbe\u0c97\u0cc6\u0cc2\u0cb3\u0cbf\u0cb8\u0cbf", "lookUpButtonLabel": "\u004c\u006f\u006f\u006b\u0020\u0055\u0070", - "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062" + "searchWebButtonLabel": "\u0053\u0065\u0061\u0072\u0063\u0068\u0020\u0057\u0065\u0062", + "shareButtonLabel": "\u0053\u0068\u0061\u0072\u0065\u002e\u002e\u002e" } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ko.arb b/packages/flutter_localizations/lib/src/l10n/material_ko.arb index b4910e20b76cd..fa2856b05255b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ko.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ko.arb @@ -144,5 +144,6 @@ "collapsedHint": "펼침", "menuDismissLabel": "메뉴 닫기", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ky.arb b/packages/flutter_localizations/lib/src/l10n/material_ky.arb index c835a8a6063d6..d924c49546930 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ky.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ky.arb @@ -143,5 +143,6 @@ "collapsedHint": "Жайылып көрсөтүлдү", "menuDismissLabel": "Менюну жабуу", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lo.arb b/packages/flutter_localizations/lib/src/l10n/material_lo.arb index 552d3bb39cd22..69aefa7a22f7c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lo.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lo.arb @@ -143,5 +143,6 @@ "collapsedHint": "ຂະຫຍາຍແລ້ວ", "menuDismissLabel": "ປິດເມນູ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lt.arb b/packages/flutter_localizations/lib/src/l10n/material_lt.arb index 67f7266f7e094..79138cabaf381 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lt.arb @@ -150,5 +150,6 @@ "collapsedHint": "Išskleista", "menuDismissLabel": "Atsisakyti meniu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_lv.arb b/packages/flutter_localizations/lib/src/l10n/material_lv.arb index a7afb08c9692d..32c496d9a9564 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_lv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_lv.arb @@ -145,5 +145,6 @@ "collapsedHint": "Izvērsts", "menuDismissLabel": "Nerādīt izvēlni", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mk.arb b/packages/flutter_localizations/lib/src/l10n/material_mk.arb index bd2227b5adc5b..6b43ceb0ac867 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mk.arb @@ -143,5 +143,6 @@ "collapsedHint": "Проширено", "menuDismissLabel": "Отфрлете го менито", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ml.arb b/packages/flutter_localizations/lib/src/l10n/material_ml.arb index 2bffcdd5b3634..2a6737a51dad7 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ml.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ml.arb @@ -143,5 +143,6 @@ "collapsedHint": "വികസിപ്പിച്ചു", "menuDismissLabel": "മെനു ഡിസ്മിസ് ചെയ്യുക", "lookUpButtonLabel": "മുകളിലേക്ക് നോക്കുക", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mn.arb b/packages/flutter_localizations/lib/src/l10n/material_mn.arb index add93c96dd470..20f54fd252f9b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mn.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mn.arb @@ -145,5 +145,6 @@ "collapsedHint": "Дэлгэсэн", "menuDismissLabel": "Цэсийг хаах", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_mr.arb b/packages/flutter_localizations/lib/src/l10n/material_mr.arb index f6bcd09d85ddd..0889a9b10e709 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_mr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_mr.arb @@ -145,5 +145,6 @@ "collapsedHint": "विस्तार केले", "menuDismissLabel": "मेनू डिसमिस करा", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ms.arb b/packages/flutter_localizations/lib/src/l10n/material_ms.arb index a1ce5e8f95282..352736c017803 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ms.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ms.arb @@ -145,5 +145,6 @@ "collapsedHint": "Dikembangkan", "menuDismissLabel": "Ketepikan menu", "lookUpButtonLabel": "Lihat ke Atas", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_my.arb b/packages/flutter_localizations/lib/src/l10n/material_my.arb index 0f126392b2a1a..bdb51efcb5ec2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_my.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_my.arb @@ -143,5 +143,6 @@ "collapsedHint": "ဖြန့်ထားသည်", "menuDismissLabel": "မီနူးကိုပယ်ပါ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nb.arb b/packages/flutter_localizations/lib/src/l10n/material_nb.arb index a575c85b87bb4..51a9204053277 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nb.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nb.arb @@ -142,5 +142,6 @@ "collapsedHint": "Vises", "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ne.arb b/packages/flutter_localizations/lib/src/l10n/material_ne.arb index 82ad492e0c036..682ae42d45097 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ne.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ne.arb @@ -143,5 +143,6 @@ "collapsedHint": "एक्स्पान्ड गरियो", "menuDismissLabel": "मेनु खारेज गर्नुहोस्", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_nl.arb b/packages/flutter_localizations/lib/src/l10n/material_nl.arb index 3c9f1c1003c9c..ed6fa8d09939b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_nl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_nl.arb @@ -144,5 +144,6 @@ "collapsedHint": "Uitgevouwen", "menuDismissLabel": "Menu sluiten", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_no.arb b/packages/flutter_localizations/lib/src/l10n/material_no.arb index a575c85b87bb4..51a9204053277 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_no.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_no.arb @@ -142,5 +142,6 @@ "collapsedHint": "Vises", "menuDismissLabel": "Lukk menyen", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_or.arb b/packages/flutter_localizations/lib/src/l10n/material_or.arb index 1270c6debcf43..f912d335d0cad 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_or.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_or.arb @@ -143,5 +143,6 @@ "collapsedHint": "ବିସ୍ତାର କରାଯାଇଛି", "menuDismissLabel": "ମେନୁ ଖାରଜ କରନ୍ତୁ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pa.arb b/packages/flutter_localizations/lib/src/l10n/material_pa.arb index f6b7804cbe47e..3fef6da95ffd8 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pa.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pa.arb @@ -143,5 +143,6 @@ "collapsedHint": "ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ", "menuDismissLabel": "ਮੀਨੂ ਖਾਰਜ ਕਰੋ", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pl.arb b/packages/flutter_localizations/lib/src/l10n/material_pl.arb index 69826d57c4872..a7a4fe5d09997 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pl.arb @@ -150,5 +150,6 @@ "collapsedHint": "Rozwinięto", "menuDismissLabel": "Zamknij menu", "lookUpButtonLabel": "Sprawdź", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ps.arb b/packages/flutter_localizations/lib/src/l10n/material_ps.arb index 12905fde08770..6660397de90fd 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ps.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ps.arb @@ -145,5 +145,6 @@ "collapsedHint": "Expanded", "menuDismissLabel": "Dismiss menu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_pt.arb b/packages/flutter_localizations/lib/src/l10n/material_pt.arb index 6a8e0e31e7e42..daf092cf82109 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_pt.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_pt.arb @@ -146,5 +146,6 @@ "collapsedHint": "Aberto.", "menuDismissLabel": "Dispensar menu", "lookUpButtonLabel": "Pesquisar", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ro.arb b/packages/flutter_localizations/lib/src/l10n/material_ro.arb index 0f952ecc87638..d85a49ff1fdc2 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ro.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ro.arb @@ -148,5 +148,6 @@ "collapsedHint": "Extins", "menuDismissLabel": "Respingeți meniul", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ru.arb b/packages/flutter_localizations/lib/src/l10n/material_ru.arb index 1d71fd7e9e90c..a73207d20f4c7 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ru.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ru.arb @@ -151,5 +151,6 @@ "collapsedHint": "Развернуто", "menuDismissLabel": "Закрыть меню", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_si.arb b/packages/flutter_localizations/lib/src/l10n/material_si.arb index 60ea033025342..4d236f2a8c8a0 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_si.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_si.arb @@ -143,5 +143,6 @@ "collapsedHint": "දිග හරින ලදි", "menuDismissLabel": "මෙනුව අස් කරන්න", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sk.arb b/packages/flutter_localizations/lib/src/l10n/material_sk.arb index 27b838e489a00..5b2792a96a22b 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sk.arb @@ -150,5 +150,6 @@ "collapsedHint": "Rozbalené", "menuDismissLabel": "Zavrieť ponuku", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sl.arb b/packages/flutter_localizations/lib/src/l10n/material_sl.arb index 5371dc0f55d33..a850fcb0e73f4 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sl.arb @@ -150,5 +150,6 @@ "collapsedHint": "Razširjeno", "menuDismissLabel": "Opusti meni", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sq.arb b/packages/flutter_localizations/lib/src/l10n/material_sq.arb index 593342090c10b..82e7bf36597cb 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sq.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sq.arb @@ -143,5 +143,6 @@ "collapsedHint": "U zgjerua", "menuDismissLabel": "Hiqe menynë", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sr.arb b/packages/flutter_localizations/lib/src/l10n/material_sr.arb index db5d3c9991f65..b1b745fb08273 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sr.arb @@ -147,5 +147,6 @@ "collapsedHint": "Проширено је", "menuDismissLabel": "Одбаците мени", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sv.arb b/packages/flutter_localizations/lib/src/l10n/material_sv.arb index 83cf62ad9898a..6c3925b1cd261 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sv.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sv.arb @@ -144,5 +144,6 @@ "collapsedHint": "Utökades", "menuDismissLabel": "Stäng menyn", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_sw.arb b/packages/flutter_localizations/lib/src/l10n/material_sw.arb index 456a35e35fda9..8d42d166ea43a 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_sw.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_sw.arb @@ -145,5 +145,6 @@ "collapsedHint": "Imepanuliwa", "menuDismissLabel": "Ondoa menyu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ta.arb b/packages/flutter_localizations/lib/src/l10n/material_ta.arb index 0654dce9c02d9..6dbde632081c6 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ta.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ta.arb @@ -145,5 +145,6 @@ "collapsedHint": "விரிவாக்கப்பட்டது", "menuDismissLabel": "மெனுவை மூடும்", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_te.arb b/packages/flutter_localizations/lib/src/l10n/material_te.arb index 84e3bd000e472..bc1abeef65607 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_te.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_te.arb @@ -143,5 +143,6 @@ "collapsedHint": "విస్తరించబడింది", "menuDismissLabel": "మెనూను తీసివేయండి", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_th.arb b/packages/flutter_localizations/lib/src/l10n/material_th.arb index d29a952478b16..e12ffad42c386 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_th.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_th.arb @@ -144,5 +144,6 @@ "collapsedHint": "ขยาย", "menuDismissLabel": "ปิดเมนู", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tl.arb b/packages/flutter_localizations/lib/src/l10n/material_tl.arb index fe87826b1efab..81500d0ee0cb3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tl.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tl.arb @@ -144,5 +144,6 @@ "collapsedHint": "Naka-expand", "menuDismissLabel": "I-dismiss ang menu", "lookUpButtonLabel": "Tumingin sa Itaas", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_tr.arb b/packages/flutter_localizations/lib/src/l10n/material_tr.arb index f92fb50a73f9c..bfcbc7458b51c 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_tr.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_tr.arb @@ -144,5 +144,6 @@ "collapsedHint": "Genişletildi", "menuDismissLabel": "Menüyü kapat", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uk.arb b/packages/flutter_localizations/lib/src/l10n/material_uk.arb index c6e8f62de2770..40f9098644dde 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uk.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uk.arb @@ -150,5 +150,6 @@ "collapsedHint": "Розгорнуто", "menuDismissLabel": "Закрити меню", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_ur.arb b/packages/flutter_localizations/lib/src/l10n/material_ur.arb index ea8fe8549ee09..cb6c453d4fba3 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_ur.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_ur.arb @@ -144,5 +144,6 @@ "collapsedHint": "پھیلا ہوا", "menuDismissLabel": "مینو برخاست کریں", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_uz.arb b/packages/flutter_localizations/lib/src/l10n/material_uz.arb index 8a1b5cdb92f1d..842624888b050 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_uz.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_uz.arb @@ -143,5 +143,6 @@ "collapsedHint": "Yoyilgan", "menuDismissLabel": "Menyuni yopish", "lookUpButtonLabel": "Tepaga qarang", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_vi.arb b/packages/flutter_localizations/lib/src/l10n/material_vi.arb index 65c677158aaad..32b1cd43aa2d1 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_vi.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_vi.arb @@ -144,5 +144,6 @@ "collapsedHint": "Đã mở rộng", "menuDismissLabel": "Đóng trình đơn", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zh.arb b/packages/flutter_localizations/lib/src/l10n/material_zh.arb index e05be57f3ed1b..0d65ab605fb89 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zh.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zh.arb @@ -144,5 +144,6 @@ "collapsedHint": "已展开", "menuDismissLabel": "关闭菜单", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } diff --git a/packages/flutter_localizations/lib/src/l10n/material_zu.arb b/packages/flutter_localizations/lib/src/l10n/material_zu.arb index 04dbf5af003be..8cf22c29b915e 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_zu.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_zu.arb @@ -143,5 +143,6 @@ "collapsedHint": "Kunwetshiwe", "menuDismissLabel": "Chitha imenyu", "lookUpButtonLabel": "Look Up", - "searchWebButtonLabel": "Search Web" + "searchWebButtonLabel": "Search Web", + "shareButtonLabel": "Share..." } From d19fb632ec66d1282d6eda3467668b7796fc37ca Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 17 Aug 2023 16:45:57 -0700 Subject: [PATCH 0779/1547] Allow date pickers to not have selected date (#132343) This enables our various date picker classes to have a null `initialDate`. It also fixes the logic of some of the widgets which used to do something when you _changed_ the `initial*` parameters, which is wrong for `initial*` properties (they by definition should only impact the initial state) and wrong for properties in general (behaviour should not change based on whether the widget was built with a new value or not, that violates the reactive design principles). Fixes https://github.com/flutter/flutter/issues/638. --- .../material/date_and_time_picker_demo.dart | 6 +- .../src/material/calendar_date_picker.dart | 155 ++++----- .../flutter/lib/src/material/date_picker.dart | 50 +-- .../material/calendar_date_picker_test.dart | 304 ++++++++++++------ .../test/material/date_picker_test.dart | 41 ++- 5 files changed, 343 insertions(+), 213 deletions(-) diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart index fa7554e27a833..c22519d647cf3 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/date_and_time_picker_demo.dart @@ -62,7 +62,7 @@ class _DateTimePicker extends StatelessWidget { Future _selectDate(BuildContext context) async { final DateTime? picked = await showDatePicker( context: context, - initialDate: selectedDate!, + initialDate: selectedDate, firstDate: DateTime(2015, 8), lastDate: DateTime(2101), ); @@ -120,9 +120,9 @@ class DateAndTimePickerDemo extends StatefulWidget { } class _DateAndTimePickerDemoState extends State { - DateTime _fromDate = DateTime.now(); + DateTime? _fromDate = DateTime.now(); TimeOfDay _fromTime = const TimeOfDay(hour: 7, minute: 28); - DateTime _toDate = DateTime.now(); + DateTime? _toDate = DateTime.now(); TimeOfDay _toTime = const TimeOfDay(hour: 8, minute: 28); final List _allActivities = ['hiking', 'swimming', 'boating', 'fishing']; String? _activity = 'fishing'; diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 46bccac26f57f..878439b61b09e 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -60,8 +60,9 @@ const double _monthNavButtonsWidth = 108.0; class CalendarDatePicker extends StatefulWidget { /// Creates a calendar date picker. /// - /// It will display a grid of days for the [initialDate]'s month. The day - /// indicated by [initialDate] will be selected. + /// It will display a grid of days for the [initialDate]'s month, or, if that + /// is null, the [currentDate]'s month. The day indicated by [initialDate] will + /// be selected if it is not null. /// /// The optional [onDisplayedMonthChanged] callback can be used to track /// the currently displayed month. @@ -71,23 +72,20 @@ class CalendarDatePicker extends StatefulWidget { /// to start in the year selection interface with [initialCalendarMode] set /// to [DatePickerMode.year]. /// - /// The [initialDate], [firstDate], [lastDate], [onDateChanged], and - /// [initialCalendarMode] must be non-null. + /// The [lastDate] must be after or equal to [firstDate]. /// - /// [lastDate] must be after or equal to [firstDate]. + /// The [initialDate], if provided, must be between [firstDate] and [lastDate] + /// or equal to one of them. /// - /// [initialDate] must be between [firstDate] and [lastDate] or equal to - /// one of them. - /// - /// [currentDate] represents the current day (i.e. today). This + /// The [currentDate] represents the current day (i.e. today). This /// date will be highlighted in the day grid. If null, the date of /// `DateTime.now()` will be used. /// - /// If [selectableDayPredicate] is non-null, it must return `true` for the - /// [initialDate]. + /// If [selectableDayPredicate] and [initialDate] are both non-null, + /// [selectableDayPredicate] must return `true` for the [initialDate]. CalendarDatePicker({ super.key, - required DateTime initialDate, + required DateTime? initialDate, required DateTime firstDate, required DateTime lastDate, DateTime? currentDate, @@ -95,7 +93,7 @@ class CalendarDatePicker extends StatefulWidget { this.onDisplayedMonthChanged, this.initialCalendarMode = DatePickerMode.day, this.selectableDayPredicate, - }) : initialDate = DateUtils.dateOnly(initialDate), + }) : initialDate = initialDate == null ? null : DateUtils.dateOnly(initialDate), firstDate = DateUtils.dateOnly(firstDate), lastDate = DateUtils.dateOnly(lastDate), currentDate = DateUtils.dateOnly(currentDate ?? DateTime.now()) { @@ -104,21 +102,26 @@ class CalendarDatePicker extends StatefulWidget { 'lastDate ${this.lastDate} must be on or after firstDate ${this.firstDate}.', ); assert( - !this.initialDate.isBefore(this.firstDate), + this.initialDate == null || !this.initialDate!.isBefore(this.firstDate), 'initialDate ${this.initialDate} must be on or after firstDate ${this.firstDate}.', ); assert( - !this.initialDate.isAfter(this.lastDate), + this.initialDate == null || !this.initialDate!.isAfter(this.lastDate), 'initialDate ${this.initialDate} must be on or before lastDate ${this.lastDate}.', ); assert( - selectableDayPredicate == null || selectableDayPredicate!(this.initialDate), + selectableDayPredicate == null || this.initialDate == null || selectableDayPredicate!(this.initialDate!), 'Provided initialDate ${this.initialDate} must satisfy provided selectableDayPredicate.', ); } /// The initially selected [DateTime] that the picker should display. - final DateTime initialDate; + /// + /// Subsequently changing this has no effect. To change the selected date, + /// change the [key] to create a new instance of the [CalendarDatePicker], and + /// provide that widget the new [initialDate]. This will reset the widget's + /// interactive state. + final DateTime? initialDate; /// The earliest allowable [DateTime] that the user can select. final DateTime firstDate; @@ -136,6 +139,11 @@ class CalendarDatePicker extends StatefulWidget { final ValueChanged? onDisplayedMonthChanged; /// The initial display of the calendar picker. + /// + /// Subsequently changing this has no effect. To change the calendar mode, + /// change the [key] to create a new instance of the [CalendarDatePicker], and + /// provide that widget a new [initialCalendarMode]. This will reset the + /// widget's interactive state. final DatePickerMode initialCalendarMode; /// Function to provide full control over which dates in the calendar can be selected. @@ -149,7 +157,7 @@ class _CalendarDatePickerState extends State { bool _announcedInitialDate = false; late DatePickerMode _mode; late DateTime _currentDisplayedMonthDate; - late DateTime _selectedDate; + DateTime? _selectedDate; final GlobalKey _monthPickerKey = GlobalKey(); final GlobalKey _yearPickerKey = GlobalKey(); late MaterialLocalizations _localizations; @@ -159,18 +167,9 @@ class _CalendarDatePickerState extends State { void initState() { super.initState(); _mode = widget.initialCalendarMode; - _currentDisplayedMonthDate = DateTime(widget.initialDate.year, widget.initialDate.month); - _selectedDate = widget.initialDate; - } - - @override - void didUpdateWidget(CalendarDatePicker oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.initialCalendarMode != oldWidget.initialCalendarMode) { - _mode = widget.initialCalendarMode; - } - if (!DateUtils.isSameDay(widget.initialDate, oldWidget.initialDate)) { - _currentDisplayedMonthDate = DateTime(widget.initialDate.year, widget.initialDate.month); + final DateTime currentDisplayedDate = widget.initialDate ?? widget.currentDate; + _currentDisplayedMonthDate = DateTime(currentDisplayedDate.year, currentDisplayedDate.month); + if (widget.initialDate != null) { _selectedDate = widget.initialDate; } } @@ -183,12 +182,13 @@ class _CalendarDatePickerState extends State { assert(debugCheckHasDirectionality(context)); _localizations = MaterialLocalizations.of(context); _textDirection = Directionality.of(context); - if (!_announcedInitialDate) { + if (!_announcedInitialDate && widget.initialDate != null) { + assert(_selectedDate != null); _announcedInitialDate = true; final bool isToday = DateUtils.isSameDay(widget.currentDate, _selectedDate); final String semanticLabelSuffix = isToday ? ', ${_localizations.currentDateLabel}' : ''; SemanticsService.announce( - '${_localizations.formatFullDate(_selectedDate)}$semanticLabelSuffix', + '${_localizations.formatFullDate(_selectedDate!)}$semanticLabelSuffix', _textDirection, ); } @@ -211,16 +211,18 @@ class _CalendarDatePickerState extends State { _vibrate(); setState(() { _mode = mode; - if (_mode == DatePickerMode.day) { - SemanticsService.announce( - _localizations.formatMonthYear(_selectedDate), - _textDirection, - ); - } else { - SemanticsService.announce( - _localizations.formatYear(_selectedDate), - _textDirection, - ); + if (_selectedDate != null) { + if (_mode == DatePickerMode.day) { + SemanticsService.announce( + _localizations.formatMonthYear(_selectedDate!), + _textDirection, + ); + } else { + SemanticsService.announce( + _localizations.formatYear(_selectedDate!), + _textDirection, + ); + } } }); } @@ -238,7 +240,7 @@ class _CalendarDatePickerState extends State { _vibrate(); final int daysInMonth = DateUtils.getDaysInMonth(value.year, value.month); - final int preferredDay = math.min(_selectedDate.day, daysInMonth); + final int preferredDay = math.min(_selectedDate?.day ?? 1, daysInMonth); value = value.copyWith(day: preferredDay); if (value.isBefore(widget.firstDate)) { @@ -253,7 +255,7 @@ class _CalendarDatePickerState extends State { if (_isSelectable(value)) { _selectedDate = value; - widget.onDateChanged(_selectedDate); + widget.onDateChanged(_selectedDate!); } }); } @@ -262,7 +264,7 @@ class _CalendarDatePickerState extends State { _vibrate(); setState(() { _selectedDate = value; - widget.onDateChanged(_selectedDate); + widget.onDateChanged(_selectedDate!); }); } @@ -292,7 +294,6 @@ class _CalendarDatePickerState extends State { currentDate: widget.currentDate, firstDate: widget.firstDate, lastDate: widget.lastDate, - initialDate: _currentDisplayedMonthDate, selectedDate: _currentDisplayedMonthDate, onChanged: _handleYearChanged, ), @@ -452,10 +453,15 @@ class _MonthPicker extends StatefulWidget { required this.onDisplayedMonthChanged, this.selectableDayPredicate, }) : assert(!firstDate.isAfter(lastDate)), - assert(!selectedDate.isBefore(firstDate)), - assert(!selectedDate.isAfter(lastDate)); + assert(selectedDate == null || !selectedDate.isBefore(firstDate)), + assert(selectedDate == null || !selectedDate.isAfter(lastDate)); /// The initial month to display. + /// + /// Subsequently changing this has no effect. To change the selected month, + /// change the [key] to create a new instance of the [_MonthPicker], and + /// provide that widget the new [initialMonth]. This will reset the widget's + /// interactive state. final DateTime initialMonth; /// The current date. @@ -476,7 +482,7 @@ class _MonthPicker extends StatefulWidget { /// The currently selected date. /// /// This date is highlighted in the picker. - final DateTime selectedDate; + final DateTime? selectedDate; /// Called when the user picks a day. final ValueChanged onChanged; @@ -528,17 +534,6 @@ class _MonthPickerState extends State<_MonthPicker> { _textDirection = Directionality.of(context); } - @override - void didUpdateWidget(_MonthPicker oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.initialMonth != oldWidget.initialMonth && widget.initialMonth != _currentMonth) { - // We can't interrupt this widget build with a scroll, so do it next frame - WidgetsBinding.instance.addPostFrameCallback( - (Duration timeStamp) => _showMonth(widget.initialMonth, jump: true), - ); - } - } - @override void dispose() { _pageController.dispose(); @@ -834,13 +829,13 @@ class _DayPicker extends StatefulWidget { required this.onChanged, this.selectableDayPredicate, }) : assert(!firstDate.isAfter(lastDate)), - assert(!selectedDate.isBefore(firstDate)), - assert(!selectedDate.isAfter(lastDate)); + assert(selectedDate == null || !selectedDate.isBefore(firstDate)), + assert(selectedDate == null || !selectedDate.isAfter(lastDate)); /// The currently selected date. /// /// This date is highlighted in the picker. - final DateTime selectedDate; + final DateTime? selectedDate; /// The current date at the time the picker is displayed. final DateTime currentDate; @@ -1105,13 +1100,18 @@ class YearPicker extends StatefulWidget { DateTime? currentDate, required this.firstDate, required this.lastDate, + @Deprecated( + 'This parameter has no effect and can be removed. Previously it controlled ' + 'the month that was used in "onChanged" when a new year was selected, but ' + 'now that role is filled by "selectedDate" instead. ' + 'This feature was deprecated after v3.13.0-0.3.pre.' + ) DateTime? initialDate, required this.selectedDate, required this.onChanged, this.dragStartBehavior = DragStartBehavior.start, }) : assert(!firstDate.isAfter(lastDate)), - currentDate = DateUtils.dateOnly(currentDate ?? DateTime.now()), - initialDate = DateUtils.dateOnly(initialDate ?? selectedDate); + currentDate = DateUtils.dateOnly(currentDate ?? DateTime.now()); /// The current date. /// @@ -1124,13 +1124,10 @@ class YearPicker extends StatefulWidget { /// The latest date the user is permitted to pick. final DateTime lastDate; - /// The initial date to center the year display around. - final DateTime initialDate; - /// The currently selected date. /// /// This date is highlighted in the picker. - final DateTime selectedDate; + final DateTime? selectedDate; /// Called when the user picks a year. final ValueChanged onChanged; @@ -1151,14 +1148,14 @@ class _YearPickerState extends State { @override void initState() { super.initState(); - _scrollController = ScrollController(initialScrollOffset: _scrollOffsetForYear(widget.selectedDate)); + _scrollController = ScrollController(initialScrollOffset: _scrollOffsetForYear(widget.selectedDate ?? widget.firstDate)); } @override void didUpdateWidget(YearPicker oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.selectedDate != oldWidget.selectedDate) { - _scrollController.jumpTo(_scrollOffsetForYear(widget.selectedDate)); + if (widget.selectedDate != oldWidget.selectedDate && widget.selectedDate != null) { + _scrollController.jumpTo(_scrollOffsetForYear(widget.selectedDate!)); } } @@ -1189,7 +1186,7 @@ class _YearPickerState extends State { // Backfill the _YearPicker with disabled years if necessary. final int offset = _itemCount < minYears ? (minYears - _itemCount) ~/ 2 : 0; final int year = widget.firstDate.year + index - offset; - final bool isSelected = year == widget.selectedDate.year; + final bool isSelected = year == widget.selectedDate?.year; final bool isCurrentYear = year == widget.currentDate.year; final bool isDisabled = year < widget.firstDate.year || year > widget.lastDate.year; const double decorationHeight = 36.0; @@ -1241,9 +1238,19 @@ class _YearPickerState extends State { child: yearItem, ); } else { + DateTime date = DateTime(year, widget.selectedDate?.month ?? DateTime.january); + if (date.isBefore(DateTime(widget.firstDate.year, widget.firstDate.month))) { + // Ignore firstDate.day because we're just working in years and months here. + assert(date.year == widget.firstDate.year); + date = DateTime(year, widget.firstDate.month); + } else if (date.isAfter(widget.lastDate)) { + // No need to ignore the day here because it can only be bigger than what we care about. + assert(date.year == widget.lastDate.year); + date = DateTime(year, widget.lastDate.month); + } yearItem = InkWell( key: ValueKey(year), - onTap: () => widget.onChanged(DateTime(year, widget.initialDate.month)), + onTap: () => widget.onChanged(date), statesController: MaterialStatesController(states), overlayColor: overlayColor, child: yearItem, diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 93c699cc9d7f3..d5d2e1d0d0a5d 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -53,18 +53,19 @@ const double _kMaxTextScaleFactor = 1.3; /// The returned [Future] resolves to the date selected by the user when the /// user confirms the dialog. If the user cancels the dialog, null is returned. /// -/// When the date picker is first displayed, it will show the month of -/// [initialDate], with [initialDate] selected. +/// When the date picker is first displayed, if [initialDate] is not null, it +/// will show the month of [initialDate], with [initialDate] selected. Otherwise +/// it will show the [currentDate]'s month. /// /// The [firstDate] is the earliest allowable date. The [lastDate] is the latest -/// allowable date. [initialDate] must either fall between these dates, -/// or be equal to one of them. For each of these [DateTime] parameters, only -/// their dates are considered. Their time fields are ignored. They must all -/// be non-null. +/// allowable date. If [initialDate] is not null, it must either fall between +/// these dates, or be equal to one of them. For each of these [DateTime] +/// parameters, only their dates are considered. Their time fields are ignored. +/// They must all be non-null. /// /// The [currentDate] represents the current day (i.e. today). This /// date will be highlighted in the day grid. If null, the date of -/// `DateTime.now()` will be used. +/// [DateTime.now] will be used. /// /// An optional [initialEntryMode] argument can be used to display the date /// picker in the [DatePickerEntryMode.calendar] (a calendar month grid) @@ -123,8 +124,7 @@ const double _kMaxTextScaleFactor = 1.3; /// /// An optional [initialDatePickerMode] argument can be used to have the /// calendar date picker initially appear in the [DatePickerMode.year] or -/// [DatePickerMode.day] mode. It defaults to [DatePickerMode.day], and -/// must be non-null. +/// [DatePickerMode.day] mode. It defaults to [DatePickerMode.day]. /// /// {@macro flutter.widgets.RawDialogRoute} /// @@ -157,10 +157,9 @@ const double _kMaxTextScaleFactor = 1.3; /// * [DisplayFeatureSubScreen], which documents the specifics of how /// [DisplayFeature]s can split the screen into sub-screens. /// * [showTimePicker], which shows a dialog that contains a Material Design time picker. -/// Future showDatePicker({ required BuildContext context, - required DateTime initialDate, + DateTime? initialDate, required DateTime firstDate, required DateTime lastDate, DateTime? currentDate, @@ -188,7 +187,7 @@ Future showDatePicker({ final Icon? switchToInputEntryModeIcon, final Icon? switchToCalendarEntryModeIcon, }) async { - initialDate = DateUtils.dateOnly(initialDate); + initialDate = initialDate == null ? null : DateUtils.dateOnly(initialDate); firstDate = DateUtils.dateOnly(firstDate); lastDate = DateUtils.dateOnly(lastDate); assert( @@ -196,15 +195,15 @@ Future showDatePicker({ 'lastDate $lastDate must be on or after firstDate $firstDate.', ); assert( - !initialDate.isBefore(firstDate), + initialDate == null || !initialDate.isBefore(firstDate), 'initialDate $initialDate must be on or after firstDate $firstDate.', ); assert( - !initialDate.isAfter(lastDate), + initialDate == null || !initialDate.isAfter(lastDate), 'initialDate $initialDate must be on or before lastDate $lastDate.', ); assert( - selectableDayPredicate == null || selectableDayPredicate(initialDate), + selectableDayPredicate == null || initialDate == null || selectableDayPredicate(initialDate), 'Provided initialDate $initialDate must satisfy provided selectableDayPredicate.', ); assert(debugCheckHasMaterialLocalizations(context)); @@ -272,7 +271,7 @@ class DatePickerDialog extends StatefulWidget { /// A Material-style date picker dialog. DatePickerDialog({ super.key, - required DateTime initialDate, + DateTime? initialDate, required DateTime firstDate, required DateTime lastDate, DateTime? currentDate, @@ -291,7 +290,7 @@ class DatePickerDialog extends StatefulWidget { this.onDatePickerModeChange, this.switchToInputEntryModeIcon, this.switchToCalendarEntryModeIcon, - }) : initialDate = DateUtils.dateOnly(initialDate), + }) : initialDate = initialDate == null ? null : DateUtils.dateOnly(initialDate), firstDate = DateUtils.dateOnly(firstDate), lastDate = DateUtils.dateOnly(lastDate), currentDate = DateUtils.dateOnly(currentDate ?? DateTime.now()) { @@ -300,21 +299,24 @@ class DatePickerDialog extends StatefulWidget { 'lastDate ${this.lastDate} must be on or after firstDate ${this.firstDate}.', ); assert( - !this.initialDate.isBefore(this.firstDate), + initialDate == null || !this.initialDate!.isBefore(this.firstDate), 'initialDate ${this.initialDate} must be on or after firstDate ${this.firstDate}.', ); assert( - !this.initialDate.isAfter(this.lastDate), + initialDate == null || !this.initialDate!.isAfter(this.lastDate), 'initialDate ${this.initialDate} must be on or before lastDate ${this.lastDate}.', ); assert( - selectableDayPredicate == null || selectableDayPredicate!(this.initialDate), + selectableDayPredicate == null || initialDate == null || selectableDayPredicate!(this.initialDate!), 'Provided initialDate ${this.initialDate} must satisfy provided selectableDayPredicate', ); } /// The initially selected [DateTime] that the picker should display. - final DateTime initialDate; + /// + /// If this is null, there is no selected date. A date must be selected to + /// submit the dialog. + final DateTime? initialDate; /// The earliest allowable [DateTime] that the user can select. final DateTime firstDate; @@ -410,7 +412,7 @@ class DatePickerDialog extends StatefulWidget { } class _DatePickerDialogState extends State with RestorationMixin { - late final RestorableDateTime _selectedDate = RestorableDateTime(widget.initialDate); + late final RestorableDateTimeN _selectedDate = RestorableDateTimeN(widget.initialDate); late final _RestorableDatePickerEntryMode _entryMode = _RestorableDatePickerEntryMode(widget.initialEntryMode); final _RestorableAutovalidateMode _autovalidateMode = _RestorableAutovalidateMode(AutovalidateMode.disabled); @@ -639,7 +641,7 @@ class _DatePickerDialogState extends State with RestorationMix ? localizations.datePickerHelpText : localizations.datePickerHelpText.toUpperCase() ), - titleText: localizations.formatMediumDate(_selectedDate.value), + titleText: _selectedDate.value == null ? '' : localizations.formatMediumDate(_selectedDate.value!), titleStyle: headlineStyle, orientation: orientation, isShort: orientation == Orientation.landscape, @@ -1365,7 +1367,7 @@ class _DateRangePickerDialogState extends State with Rest _entryMode.value = DatePickerEntryMode.input; case DatePickerEntryMode.input: - // Validate the range dates + // Validate the range dates if (_selectedStart.value != null && (_selectedStart.value!.isBefore(widget.firstDate) || _selectedStart.value!.isAfter(widget.lastDate))) { _selectedStart.value = null; diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index d952a67860f8d..c3b3c80845cd1 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -34,7 +34,7 @@ void main() { textDirection: textDirection, child: CalendarDatePicker( key: key, - initialDate: initialDate ?? DateTime(2016, DateTime.january, 15), + initialDate: initialDate, firstDate: firstDate ?? DateTime(2001), lastDate: lastDate ?? DateTime(2031, DateTime.december, 31), currentDate: currentDate ?? DateTime(2016, DateTime.january, 3), @@ -65,7 +65,6 @@ void main() { child: YearPicker( key: key, selectedDate: selectedDate ?? DateTime(2016, DateTime.january, 15), - initialDate: initialDate ?? DateTime(2016, DateTime.january, 15), firstDate: firstDate ?? DateTime(2001), lastDate: lastDate ?? DateTime(2031, DateTime.december, 31), currentDate: currentDate ?? DateTime(2016, DateTime.january, 3), @@ -78,6 +77,16 @@ void main() { group('CalendarDatePicker', () { testWidgets('Can select a day', (WidgetTester tester) async { + DateTime? selectedDate; + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + onDateChanged: (DateTime date) => selectedDate = date, + )); + await tester.tap(find.text('12')); + expect(selectedDate, equals(DateTime(2016, DateTime.january, 12))); + }); + + testWidgets('Can select a day with nothing first selected', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( onDateChanged: (DateTime date) => selectedDate = date, @@ -87,6 +96,31 @@ void main() { }); testWidgets('Can select a month', (WidgetTester tester) async { + DateTime? displayedMonth; + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, + )); + expect(find.text('January 2016'), findsOneWidget); + + // Go back two months + await tester.tap(previousMonthIcon); + await tester.pumpAndSettle(); + expect(find.text('December 2015'), findsOneWidget); + expect(displayedMonth, equals(DateTime(2015, DateTime.december))); + await tester.tap(previousMonthIcon); + await tester.pumpAndSettle(); + expect(find.text('November 2015'), findsOneWidget); + expect(displayedMonth, equals(DateTime(2015, DateTime.november))); + + // Go forward a month + await tester.tap(nextMonthIcon); + await tester.pumpAndSettle(); + expect(find.text('December 2015'), findsOneWidget); + expect(displayedMonth, equals(DateTime(2015, DateTime.december))); + }); + + testWidgets('Can select a month with nothing first selected', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, @@ -111,6 +145,21 @@ void main() { }); testWidgets('Can select a year', (WidgetTester tester) async { + DateTime? displayedMonth; + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, + )); + + await tester.tap(find.text('January 2016')); // Switch to year mode. + await tester.pumpAndSettle(); + await tester.tap(find.text('2018')); + await tester.pumpAndSettle(); + expect(find.text('January 2018'), findsOneWidget); + expect(displayedMonth, equals(DateTime(2018))); + }); + + testWidgets('Can select a year with nothing first selected', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, @@ -150,6 +199,7 @@ void main() { testWidgets('Changing year does change selected date', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), onDateChanged: (DateTime date) => selectedDate = date, )); await tester.tap(find.text('4')); @@ -183,6 +233,7 @@ void main() { testWidgets('Changing year does not change the month', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, )); await tester.tap(nextMonthIcon); @@ -200,6 +251,7 @@ void main() { testWidgets('Can select a year and then a day', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), onDateChanged: (DateTime date) => selectedDate = date, )); await tester.tap(find.text('January 2016')); // Switch to year mode. @@ -308,14 +360,39 @@ void main() { onDateChanged: (DateTime date) => selectedDate = date, onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, )); + // Selected date is now 2018-05-04 (initialDate). + await tester.tap(find.text('May 2018')); + // Selected date is still 2018-05-04. + await tester.pumpAndSettle(); + await tester.tap(find.text('2019')); + // Selected date would become 2019-05-04 but gets clamped to the month of lastDate, so 2019-01-04. + await tester.pumpAndSettle(); + expect(find.text('January 2019'), findsOneWidget); + expect(displayedMonth, DateTime(2019)); + expect(selectedDate, DateTime(2019, DateTime.january, 4)); + }); + + testWidgets('Selecting lastDate year respects lastDate', (WidgetTester tester) async { + DateTime? selectedDate; + DateTime? displayedMonth; + await tester.pumpWidget(calendarDatePicker( + firstDate: DateTime(2016, DateTime.june, 9), + initialDate: DateTime(2018, DateTime.may, 15), + lastDate: DateTime(2019, DateTime.january, 4), + onDateChanged: (DateTime date) => selectedDate = date, + onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, + )); + // Selected date is now 2018-05-15 (initialDate). await tester.tap(find.text('May 2018')); + // Selected date is still 2018-05-15. await tester.pumpAndSettle(); await tester.tap(find.text('2019')); + // Selected date would become 2019-05-15 but gets clamped to the month of lastDate, so 2019-01-15. + // Day is now beyond the lastDate so that also gets clamped, to 2019-01-04. await tester.pumpAndSettle(); - // Month should be clamped to January as the range ends at January 2019. expect(find.text('January 2019'), findsOneWidget); expect(displayedMonth, DateTime(2019)); - expect(selectedDate, DateTime(2019, DateTime.january, 15)); + expect(selectedDate, DateTime(2019, DateTime.january, 4)); }); testWidgets('Only predicate days are selectable', (WidgetTester tester) async { @@ -350,6 +427,7 @@ void main() { testWidgets('Material2 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( useMaterial3: false, + initialDate: DateTime(2016, DateTime.january, 15), currentDate: DateTime(2016, 1, 2), )); const Color todayColor = Color(0xff2196f3); // default primary color @@ -367,6 +445,7 @@ void main() { testWidgets('Material3 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( useMaterial3: true, + initialDate: DateTime(2016, DateTime.january, 15), currentDate: DateTime(2016, 1, 2), )); const Color todayColor = Color(0xff6750a4); // default primary color @@ -437,107 +516,63 @@ void main() { expect(find.text('2017'), findsNothing); }); - testWidgets('Material2 - Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { - final Key pickerKey = UniqueKey(); - final DateTime initialDate = DateTime(2020, 1, 21); - final DateTime updatedDate = DateTime(1976, 2, 23); - final DateTime firstDate = DateTime(1970); - final DateTime lastDate = DateTime(2099, 31, 12); - const Color selectedColor = Color(0xff2196f3); // default primary color - - await tester.pumpWidget(calendarDatePicker( - key: pickerKey, - useMaterial3: false, - initialDate: initialDate, - firstDate: firstDate, - lastDate: lastDate, - onDateChanged: (DateTime value) {}, - )); - await tester.pumpAndSettle(); - - // Month should show as January 2020 - expect(find.text('January 2020'), findsOneWidget); - // Selected date should be painted with a colored circle. - expect( - Material.of(tester.element(find.text('21'))), - paints..circle(color: selectedColor, style: PaintingStyle.fill), - ); + for (final bool useMaterial3 in [false, true]) { + testWidgets('Updates to initialDate parameter are not reflected in the state (useMaterial3=$useMaterial3)', (WidgetTester tester) async { + final Key pickerKey = UniqueKey(); + final DateTime initialDate = DateTime(2020, 1, 21); + final DateTime updatedDate = DateTime(1976, 2, 23); + final DateTime firstDate = DateTime(1970); + final DateTime lastDate = DateTime(2099, 31, 12); + final Color selectedColor = useMaterial3 ? const Color(0xff6750a4) : const Color(0xff2196f3); // default primary color - // Change to the updated initialDate - await tester.pumpWidget(calendarDatePicker( - key: pickerKey, - useMaterial3: false, - initialDate: updatedDate, - firstDate: firstDate, - lastDate: lastDate, - onDateChanged: (DateTime value) {}, - )); - // Wait for the page scroll animation to finish. - await tester.pumpAndSettle(const Duration(milliseconds: 200)); - - // Month should show as February 1976 - expect(find.text('January 2020'), findsNothing); - expect(find.text('February 1976'), findsOneWidget); - // Selected date should be painted with a colored circle. - expect( - Material.of(tester.element(find.text('23'))), - paints..circle(color: selectedColor, style: PaintingStyle.fill), - ); - }); - - testWidgets('Material3 - Updates to initialDate parameter is reflected in the state', (WidgetTester tester) async { - final Key pickerKey = UniqueKey(); - final DateTime initialDate = DateTime(2020, 1, 21); - final DateTime updatedDate = DateTime(1976, 2, 23); - final DateTime firstDate = DateTime(1970); - final DateTime lastDate = DateTime(2099, 31, 12); - const Color selectedColor = Color(0xff6750a4); // default primary color - - await tester.pumpWidget(calendarDatePicker( - key: pickerKey, - useMaterial3: true, - initialDate: initialDate, - firstDate: firstDate, - lastDate: lastDate, - onDateChanged: (DateTime value) {}, - )); - await tester.pumpAndSettle(); - - // Month should show as January 2020 - expect(find.text('January 2020'), findsOneWidget); - // Selected date should be painted with a colored circle. - expect( - Material.of(tester.element(find.text('21'))), - paints..circle(color: selectedColor, style: PaintingStyle.fill), - ); + await tester.pumpWidget(calendarDatePicker( + key: pickerKey, + useMaterial3: useMaterial3, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + onDateChanged: (DateTime value) {}, + )); + await tester.pumpAndSettle(); - // Change to the updated initialDate - await tester.pumpWidget(calendarDatePicker( - key: pickerKey, - useMaterial3: true, - initialDate: updatedDate, - firstDate: firstDate, - lastDate: lastDate, - onDateChanged: (DateTime value) {}, - )); - // Wait for the page scroll animation to finish. - await tester.pumpAndSettle(const Duration(milliseconds: 200)); + // Month should show as January 2020. + expect(find.text('January 2020'), findsOneWidget); + // Selected date should be painted with a colored circle. + expect( + Material.of(tester.element(find.text('21'))), + paints..circle(color: selectedColor, style: PaintingStyle.fill), + ); - // Month should show as February 1976 - expect(find.text('January 2020'), findsNothing); - expect(find.text('February 1976'), findsOneWidget); - // Selected date should be painted with a colored circle. - expect( - Material.of(tester.element(find.text('23'))), - paints..circle(color: selectedColor, style: PaintingStyle.fill), - ); - }); + // Change to the updated initialDate. + // This should have no effect, the initialDate is only the _initial_ date. + await tester.pumpWidget(calendarDatePicker( + key: pickerKey, + useMaterial3: useMaterial3, + initialDate: updatedDate, + firstDate: firstDate, + lastDate: lastDate, + onDateChanged: (DateTime value) {}, + )); + // Wait for the page scroll animation to finish. + await tester.pumpAndSettle(const Duration(milliseconds: 200)); + + // Month should show as January 2020 still. + expect(find.text('January 2020'), findsOneWidget); + expect(find.text('February 1976'), findsNothing); + // Selected date should be painted with a colored circle. + expect( + Material.of(tester.element(find.text('21'))), + paints..circle(color: selectedColor, style: PaintingStyle.fill), + ); + }); + } - testWidgets('Updates to initialCalendarMode parameter is reflected in the state', (WidgetTester tester) async { + testWidgets('Updates to initialCalendarMode parameter is not reflected in the state', (WidgetTester tester) async { final Key pickerKey = UniqueKey(); await tester.pumpWidget(calendarDatePicker( key: pickerKey, + initialDate: DateTime(2016, DateTime.january, 15), initialCalendarMode: DatePickerMode.year, )); await tester.pumpAndSettle(); @@ -549,17 +584,20 @@ void main() { await tester.pumpWidget(calendarDatePicker( key: pickerKey, + initialDate: DateTime(2016, DateTime.january, 15), )); await tester.pumpAndSettle(); - // Should be in day mode. + // Should be in year mode still; updating an _initial_ parameter has no effect. expect(find.text('January 2016'), findsOneWidget); // Day/year selector - expect(find.text('15'), findsOneWidget); // day 15 in grid - expect(find.text('2016'), findsNothing); // 2016 in year grid + expect(find.text('15'), findsNothing); // day 15 in grid + expect(find.text('2016'), findsOneWidget); // 2016 in year grid }); testWidgets('Dragging more than half the width should not cause a jump', (WidgetTester tester) async { - await tester.pumpWidget(calendarDatePicker()); + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + )); await tester.pumpAndSettle(); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(PageView))); // This initial drag is required for the PageView to recognize the gesture, as it uses DragStartBehavior.start. @@ -579,7 +617,9 @@ void main() { group('Keyboard navigation', () { testWidgets('Can toggle to year mode', (WidgetTester tester) async { - await tester.pumpWidget(calendarDatePicker()); + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + )); expect(find.text('2016'), findsNothing); expect(find.text('January 2016'), findsOneWidget); // Navigate to the year selector and activate it. @@ -592,7 +632,9 @@ void main() { }); testWidgets('Can navigate next/previous months', (WidgetTester tester) async { - await tester.pumpWidget(calendarDatePicker()); + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + )); expect(find.text('January 2016'), findsOneWidget); // Navigate to the previous month button and activate it twice. await tester.sendKeyEvent(LogicalKeyboardKey.tab); @@ -621,6 +663,7 @@ void main() { testWidgets('Can navigate date grid with arrow keys', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), onDateChanged: (DateTime date) => selectedDate = date, )); // Navigate to the grid. @@ -650,6 +693,7 @@ void main() { testWidgets('Navigating with arrow keys scrolls months', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), onDateChanged: (DateTime date) => selectedDate = date, )); // Navigate to the grid. @@ -690,6 +734,7 @@ void main() { testWidgets('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), onDateChanged: (DateTime date) => selectedDate = date, textDirection: TextDirection.rtl, )); @@ -731,7 +776,9 @@ void main() { }); testWidgets('Selecting date vibrates', (WidgetTester tester) async { - await tester.pumpWidget(calendarDatePicker()); + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + )); await tester.tap(find.text('10')); await tester.pump(hapticFeedbackInterval); expect(feedback.hapticCount, 1); @@ -760,7 +807,9 @@ void main() { }); testWidgets('Changing modes and year vibrates', (WidgetTester tester) async { - await tester.pumpWidget(calendarDatePicker()); + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + )); await tester.tap(find.text('January 2016')); await tester.pump(hapticFeedbackInterval); expect(feedback.hapticCount, 1); @@ -774,7 +823,9 @@ void main() { testWidgets('day mode', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); - await tester.pumpWidget(calendarDatePicker()); + await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), + )); // Year mode drop down button. expect(tester.getSemantics(find.text('January 2016')), matchesSemantics( @@ -989,6 +1040,7 @@ void main() { final SemanticsHandle semantics = tester.ensureSemantics(); await tester.pumpWidget(calendarDatePicker( + initialDate: DateTime(2016, DateTime.january, 15), initialCalendarMode: DatePickerMode.year, )); @@ -1034,7 +1086,7 @@ void main() { DateTime? selectedYear; await tester.pumpWidget(yearPicker( firstDate: DateTime(2018, DateTime.june, 9), - initialDate: DateTime(2018, DateTime.july, 4), + selectedDate: DateTime(2018, DateTime.july, 4), lastDate: DateTime(2018, DateTime.december, 15), onChanged: (DateTime date) => selectedYear = date, )); @@ -1048,5 +1100,43 @@ void main() { await tester.pumpAndSettle(); expect(selectedYear, equals(DateTime(2018, DateTime.july))); }); + + testWidgets('Selecting year with no selected month uses earliest month', (WidgetTester tester) async { + DateTime? selectedYear; + await tester.pumpWidget(yearPicker( + firstDate: DateTime(2018, DateTime.june, 9), + lastDate: DateTime(2019, DateTime.december, 15), + onChanged: (DateTime date) => selectedYear = date, + )); + await tester.tap(find.text('2018')); + expect(selectedYear, equals(DateTime(2018, DateTime.june))); + await tester.pumpWidget(yearPicker( + firstDate: DateTime(2018, DateTime.june, 9), + lastDate: DateTime(2019, DateTime.december, 15), + selectedDate: DateTime(2018, DateTime.june), + onChanged: (DateTime date) => selectedYear = date, + )); + await tester.tap(find.text('2019')); + expect(selectedYear, equals(DateTime(2019, DateTime.june))); + }); + + testWidgets('Selecting year with no selected month uses January', (WidgetTester tester) async { + DateTime? selectedYear; + await tester.pumpWidget(yearPicker( + firstDate: DateTime(2018, DateTime.june, 9), + lastDate: DateTime(2019, DateTime.december, 15), + onChanged: (DateTime date) => selectedYear = date, + )); + await tester.tap(find.text('2019')); + expect(selectedYear, equals(DateTime(2019))); // january implied + await tester.pumpWidget(yearPicker( + firstDate: DateTime(2018, DateTime.june, 9), + lastDate: DateTime(2019, DateTime.december, 15), + selectedDate: DateTime(2018), + onChanged: (DateTime date) => selectedYear = date, + )); + await tester.tap(find.text('2018')); + expect(selectedYear, equals(DateTime(2018, DateTime.june))); + }); }); } diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index de670d7131512..4c47543d14775 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -14,7 +14,7 @@ void main() { late DateTime firstDate; late DateTime lastDate; - late DateTime initialDate; + late DateTime? initialDate; late DateTime today; late SelectableDayPredicate? selectableDayPredicate; late DatePickerEntryMode initialEntryMode; @@ -1044,6 +1044,37 @@ void main() { }); }); + testWidgets('Can select a day with no initial date', (WidgetTester tester) async { + initialDate = null; + await prepareDatePicker(tester, (Future date) async { + await tester.tap(find.text('12')); + await tester.tap(find.text('OK')); + expect(await date, equals(DateTime(2016, DateTime.january, 12))); + }); + }); + + testWidgets('Can select a month with no initial date', (WidgetTester tester) async { + initialDate = null; + await prepareDatePicker(tester, (Future date) async { + await tester.tap(previousMonthIcon); + await tester.pumpAndSettle(const Duration(seconds: 1)); + await tester.tap(find.text('25')); + await tester.tap(find.text('OK')); + expect(await date, DateTime(2015, DateTime.december, 25)); + }); + }); + + testWidgets('Can select a year with no initial date', (WidgetTester tester) async { + initialDate = null; + await prepareDatePicker(tester, (Future date) async { + await tester.tap(find.text('January 2016')); // Switch to year mode. + await tester.pump(); + await tester.tap(find.text('2018')); + await tester.pump(); + expect(find.text('January 2018'), findsOneWidget); + }); + }); + testWidgets('Selecting date does not change displayed month', (WidgetTester tester) async { initialDate = DateTime(2020, DateTime.march, 15); await prepareDatePicker(tester, (Future date) async { @@ -1105,8 +1136,8 @@ void main() { testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 15); - firstDate = initialDate; - lastDate = initialDate; + firstDate = initialDate!; + lastDate = initialDate!; await prepareDatePicker(tester, (Future date) async { // Earlier than firstDate. Should be ignored. await tester.tap(find.text('10')); @@ -1120,7 +1151,7 @@ void main() { testWidgets('Cannot select a month past last date', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 15); - firstDate = initialDate; + firstDate = initialDate!; lastDate = DateTime(2017, DateTime.february, 20); await prepareDatePicker(tester, (Future date) async { await tester.tap(nextMonthIcon); @@ -1133,7 +1164,7 @@ void main() { testWidgets('Cannot select a month before first date', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 15); firstDate = DateTime(2016, DateTime.december, 10); - lastDate = initialDate; + lastDate = initialDate!; await prepareDatePicker(tester, (Future date) async { await tester.tap(previousMonthIcon); await tester.pumpAndSettle(const Duration(seconds: 1)); From ced3e76626b1668b561e43fed9295d3ae99f227b Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Thu, 17 Aug 2023 16:53:06 -0700 Subject: [PATCH 0780/1547] Reland: "Reorganize and clarify API doc generator" (#132353) (#132710) ## Description This re-lands #132353 with some additional options for keeping around the staging directory, so that the recipe for publishing docs can give those options and have the staging directory left around for deploying to the website. Reverted in #132613 ## Related Issues - https://flutter-review.googlesource.com/c/recipes/+/49580 --- dev/bots/docs.sh | 209 ++-- dev/docs/dashing_postprocess.dart | 29 - dev/tools/create_api_docs.dart | 1141 ++++++++++++++++++++++ dev/tools/dartdoc.dart | 606 ------------ dev/tools/java_and_objc_doc.dart | 97 -- dev/tools/pubspec.yaml | 2 +- dev/tools/test/create_api_docs_test.dart | 197 ++++ dev/tools/test/dartdoc_test.dart | 98 -- 8 files changed, 1441 insertions(+), 938 deletions(-) delete mode 100644 dev/docs/dashing_postprocess.dart create mode 100644 dev/tools/create_api_docs.dart delete mode 100644 dev/tools/dartdoc.dart delete mode 100644 dev/tools/java_and_objc_doc.dart create mode 100644 dev/tools/test/create_api_docs_test.dart delete mode 100644 dev/tools/test/dartdoc_test.dart diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh index 6a0cec83c97d8..a213982482048 100755 --- a/dev/bots/docs.sh +++ b/dev/bots/docs.sh @@ -16,102 +16,13 @@ function script_location() { cd -P "$(dirname "$script_location")" >/dev/null && pwd } -function generate_docs() { - # Install and activate dartdoc. - # When updating to a new dartdoc version, please also update - # `dartdoc_options.yaml` to include newly introduced error and warning types. - "$DART" pub global activate dartdoc 6.3.0 - - # Install and activate the snippets tool, which resides in the - # assets-for-api-docs repo: - # https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets - "$DART" pub global activate snippets 0.3.1 - - # This script generates a unified doc set, and creates - # a custom index.html, placing everything into dev/docs/doc. - (cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get) - (cd "$FLUTTER_ROOT/dev/tools" && "$DART" pub get) - (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/dartdoc.dart") - (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/java_and_objc_doc.dart") -} - -# Zip up the docs so people can download them for offline usage. -function create_offline_zip() { - # Must be run from "$FLUTTER_ROOT/dev/docs" - echo "$(date): Zipping Flutter offline docs archive." - rm -rf flutter.docs.zip doc/offline - (cd ./doc; zip -r -9 -q ../flutter.docs.zip .) -} - -# Generate the docset for Flutter docs for use with Dash, Zeal, and Velocity. -function create_docset() { - # Must be run from "$FLUTTER_ROOT/dev/docs" - # Must have dashing installed: go get -u github.com/technosophos/dashing - # Dashing produces a LOT of log output (~30MB), so we redirect it, and just - # show the end of it if there was a problem. - echo "$(date): Building Flutter docset." - rm -rf flutter.docset - # If dashing gets stuck, Cirrus will time out the build after an hour, and we - # never get to see the logs. Thus, we run it in the background and tail the logs - # while we wait for it to complete. - dashing_log=/tmp/dashing.log - dashing build --source ./doc --config ./dashing.json > $dashing_log 2>&1 & - dashing_pid=$! - wait $dashing_pid && \ - cp ./doc/flutter/static-assets/favicon.png ./flutter.docset/icon.png && \ - "$DART" --disable-dart-dev --enable-asserts ./dashing_postprocess.dart && \ - tar cf flutter.docset.tar.gz --use-compress-program="gzip --best" flutter.docset - if [[ $? -ne 0 ]]; then - >&2 echo "Dashing docset generation failed" - tail -200 $dashing_log - exit 1 - fi -} - -function deploy_docs() { - case "$LUCI_BRANCH" in - master) - echo "$(date): Updating $LUCI_BRANCH docs: https://master-api.flutter.dev/" - # Disable search indexing on the master staging site so searches get only - # the stable site. - echo -e "User-agent: *\nDisallow: /" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt" - ;; - stable) - echo "$(date): Updating $LUCI_BRANCH docs: https://api.flutter.dev/" - # Enable search indexing on the master staging site so searches get only - # the stable site. - echo -e "# All robots welcome!" > "$FLUTTER_ROOT/dev/docs/doc/robots.txt" - ;; - *) - >&2 echo "Docs deployment cannot be run on the $LUCI_BRANCH branch." - exit 0 - esac -} - -# Move the offline archives into place, after all the processing of the doc -# directory is done. This avoids the tools recursively processing the archives -# as part of their process. -function move_offline_into_place() { - # Must be run from "$FLUTTER_ROOT/dev/docs" - echo "$(date): Moving offline data into place." - mkdir -p doc/offline - mv flutter.docs.zip doc/offline/flutter.docs.zip - du -sh doc/offline/flutter.docs.zip - if [[ "$LUCI_BRANCH" == "stable" ]]; then - echo -e "\n ${FLUTTER_VERSION_STRING}\n https://api.flutter.dev/offline/flutter.docset.tar.gz\n" > doc/offline/flutter.xml - else - echo -e "\n ${FLUTTER_VERSION_STRING}\n https://master-api.flutter.dev/offline/flutter.docset.tar.gz\n" > doc/offline/flutter.xml - fi - mv flutter.docset.tar.gz doc/offline/flutter.docset.tar.gz - du -sh doc/offline/flutter.docset.tar.gz -} - # So that users can run this script from anywhere and it will work as expected. SCRIPT_LOCATION="$(script_location)" # Sets the Flutter root to be "$(script_location)/../..": This script assumes # that it resides two directory levels down from the root, so if that changes, # then this line will need to as well. FLUTTER_ROOT="$(dirname "$(dirname "$SCRIPT_LOCATION")")" +export FLUTTER_ROOT echo "$(date): Running docs.sh" @@ -124,31 +35,115 @@ FLUTTER_BIN="$FLUTTER_ROOT/bin" DART_BIN="$FLUTTER_ROOT/bin/cache/dart-sdk/bin" FLUTTER="$FLUTTER_BIN/flutter" DART="$DART_BIN/dart" -export PATH="$FLUTTER_BIN:$DART_BIN:$PATH" +PATH="$FLUTTER_BIN:$DART_BIN:$PATH" -# Make sure dart is installed by invoking Flutter to download it. -# This also creates the 'version' file. -FLUTTER_VERSION=$("$FLUTTER" --version --machine) +# Make sure dart is installed by invoking Flutter to download it if it is missing. +# Also make sure the flutter command is ready to run before capturing output from +# it: if it has to rebuild itself or something, it'll spoil our JSON output. +"$FLUTTER" > /dev/null 2>&1 +FLUTTER_VERSION="$("$FLUTTER" --version --machine)" export FLUTTER_VERSION -FLUTTER_VERSION_STRING=$(cat "$FLUTTER_ROOT/version") # If the pub cache directory exists in the root, then use that. FLUTTER_PUB_CACHE="$FLUTTER_ROOT/.pub-cache" if [[ -d "$FLUTTER_PUB_CACHE" ]]; then # This has to be exported, because pub interprets setting it to the empty # string in the same way as setting it to ".". - export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}" + PUB_CACHE="${PUB_CACHE:-"$FLUTTER_PUB_CACHE"}" + export PUB_CACHE fi -generate_docs -# Skip publishing docs for PRs and release candidate branches -if [[ -n "$LUCI_CI" && -z "$LUCI_PR" ]]; then - (cd "$FLUTTER_ROOT/dev/docs"; create_offline_zip) - (cd "$FLUTTER_ROOT/dev/docs"; create_docset) - (cd "$FLUTTER_ROOT/dev/docs"; move_offline_into_place) - deploy_docs -fi +function usage() { + echo "Usage: $(basename "${BASH_SOURCE[0]}") [--keep-temp] [--output ]" + echo "" + echo " --keep-staging Do not delete the staging directory created while generating" + echo " docs. Normally the script deletes the staging directory after" + echo " generating the output ZIP file." + echo " --output specifies where the output ZIP file containing the documentation" + echo " data will be written." + echo " --staging-dir specifies where the temporary output files will be written while" + echo " generating docs. This directory will be deleted after generation" + echo " unless --keep-staging is also specified." + echo "" +} + +function parse_args() { + local arg + local args=() + STAGING_DIR= + KEEP_STAGING=0 + DESTINATION="$FLUTTER_ROOT/dev/docs/api_docs.zip" + while (( "$#" )); do + case "$1" in + --help) + usage + exit 0 + ;; + --staging-dir) + STAGING_DIR="$2" + shift + ;; + --keep-staging) + KEEP_STAGING=1 + ;; + --output) + DESTINATION="$2" + shift + ;; + *) + args=("${args[@]}" "$1") + ;; + esac + shift + done + if [[ -z $STAGING_DIR ]]; then + STAGING_DIR=$(mktemp -d /tmp/dartdoc.XXXXX) + fi + DOC_DIR="$STAGING_DIR/doc" + if [[ ${#args[@]} != 0 ]]; then + >&2 echo "ERROR: Unknown arguments: ${args[@]}" + usage + exit 1 + fi +} + +function generate_docs() { + # Install and activate dartdoc. + # When updating to a new dartdoc version, please also update + # `dartdoc_options.yaml` to include newly introduced error and warning types. + "$DART" pub global activate dartdoc 6.3.0 + + # Install and activate the snippets tool, which resides in the + # assets-for-api-docs repo: + # https://github.com/flutter/assets-for-api-docs/tree/master/packages/snippets + "$DART" pub global activate snippets 0.4.0 + + # This script generates a unified doc set, and creates + # a custom index.html, placing everything into DOC_DIR. + + # Make sure that create_api_docs.dart has all the dependencies it needs. + (cd "$FLUTTER_ROOT/dev/tools" && "$FLUTTER" pub get) + (cd "$FLUTTER_ROOT" && "$DART" --disable-dart-dev --enable-asserts "$FLUTTER_ROOT/dev/tools/create_api_docs.dart" --output-dir="$DOC_DIR") +} + +function main() { + echo "Writing docs build temporary output to $DOC_DIR" + mkdir -p "$DOC_DIR" + generate_docs + # If the destination isn't an absolute path, make it into one. + if ! [[ "$DESTINATION" =~ ^/ ]]; then + DESTINATION="$PWD/$DESTINATION" + fi + # Zip up doc directory and write the output to the destination. + (cd "$STAGING_DIR"; zip -r -9 -q "$DESTINATION" ./doc) + if [[ $KEEP_STAGING -eq 1 ]]; then + echo "Staging documentation output left in $STAGING_DIR" + else + echo "Removing staging documentation output from $STAGING_DIR" + rm -rf "$STAGING_DIR" + fi + echo "Wrote docs ZIP file to $DESTINATION" +} -# Zip docs -cd "$FLUTTER_ROOT/dev/docs" -zip -r api_docs.zip doc +parse_args "$@" +main diff --git a/dev/docs/dashing_postprocess.dart b/dev/docs/dashing_postprocess.dart deleted file mode 100644 index 9f186e4f2c315..0000000000000 --- a/dev/docs/dashing_postprocess.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:io'; - -/// This changes the DocSetPlatformFamily key to be "dartlang" instead of the -/// name of the package (usually "flutter"). -/// -/// This is so that the IntelliJ plugin for Dash will be able to go directly to -/// the docs for a symbol from a keystroke. Without this, flutter isn't part -/// of the list of package names it searches. After this, it finds the flutter -/// docs because they're declared here to be part of the "dartlang" family of -/// docs. -/// -/// Dashing doesn't have a way to configure this, so we modify the Info.plist -/// directly to make the change. -void main(List args) { - final File infoPlist = File('flutter.docset/Contents/Info.plist'); - String contents = infoPlist.readAsStringSync(); - - // Since I didn't want to add the XML package as a dependency just for this, - // I just used a regular expression to make this simple change. - final RegExp findRe = RegExp(r'(\s*DocSetPlatformFamily\s*)[^<]+()', multiLine: true); - contents = contents.replaceAllMapped(findRe, (Match match) { - return '${match.group(1)}dartlang${match.group(2)}'; - }); - infoPlist.writeAsStringSync(contents); -} diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart new file mode 100644 index 0000000000000..4cbef2287f7c2 --- /dev/null +++ b/dev/tools/create_api_docs.dart @@ -0,0 +1,1141 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert'; +import 'dart:io'; +import 'dart:math' as math; + +import 'package:archive/archive_io.dart'; +import 'package:args/args.dart'; +import 'package:file/file.dart'; +import 'package:file/local.dart'; +import 'package:http/http.dart' as http; +import 'package:intl/intl.dart'; +import 'package:meta/meta.dart'; +import 'package:path/path.dart' as path; +import 'package:platform/platform.dart'; +import 'package:process/process.dart'; +import 'package:pub_semver/pub_semver.dart'; + +import 'dartdoc_checker.dart'; + +const String kDummyPackageName = 'Flutter'; +const String kPlatformIntegrationPackageName = 'platform_integration'; + +/// This script will generate documentation for the packages in `packages/` and +/// write the documentation to the output directory specified on the command +/// line. +/// +/// This script also updates the index.html file so that it can be placed at the +/// root of api.flutter.dev. The files are kept inside of +/// api.flutter.dev/flutter, so we need to manipulate paths a bit. See +/// https://github.com/flutter/flutter/issues/3900 for more info. +/// +/// This will only work on UNIX systems, not Windows. It requires that 'git', +/// 'zip', and 'tar' be in the PATH. It requires that 'flutter' has been run +/// previously. It uses the version of Dart downloaded by the 'flutter' tool in +/// this repository and will fail if that is absent. +Future main(List arguments) async { + const FileSystem filesystem = LocalFileSystem(); + const ProcessManager processManager = LocalProcessManager(); + const Platform platform = LocalPlatform(); + + // The place to find customization files and configuration files for docs + // generation. + final Directory docsRoot = filesystem + .directory(FlutterInformation.instance.getFlutterRoot().childDirectory('dev').childDirectory('docs')) + .absolute; + final ArgParser argParser = _createArgsParser( + publishDefault: docsRoot.childDirectory('doc').path, + ); + final ArgResults args = argParser.parse(arguments); + if (args['help'] as bool) { + print('Usage:'); + print(argParser.usage); + exit(0); + } + + final Directory publishRoot = filesystem.directory(args['output-dir']! as String).absolute; + final Directory packageRoot = publishRoot.parent; + if (!filesystem.directory(packageRoot).existsSync()) { + filesystem.directory(packageRoot).createSync(recursive: true); + } + + if (!filesystem.directory(publishRoot).existsSync()) { + filesystem.directory(publishRoot).createSync(recursive: true); + } + + final Configurator configurator = Configurator( + publishRoot: publishRoot, + packageRoot: packageRoot, + docsRoot: docsRoot, + filesystem: filesystem, + processManager: processManager, + platform: platform, + ); + configurator.generateConfiguration(); + + final PlatformDocGenerator platformGenerator = PlatformDocGenerator(outputDir: publishRoot, filesystem: filesystem); + platformGenerator.generatePlatformDocs(); + + final DartdocGenerator dartdocGenerator = DartdocGenerator( + publishRoot: publishRoot, + packageRoot: packageRoot, + docsRoot: docsRoot, + filesystem: filesystem, + processManager: processManager, + useJson: args['json'] as bool? ?? true, + validateLinks: args['validate-links']! as bool, + verbose: args['verbose'] as bool? ?? false, + ); + + await dartdocGenerator.generateDartdoc(); + await configurator.generateOfflineAssetsIfNeeded(); +} + +ArgParser _createArgsParser({required String publishDefault}) { + final ArgParser parser = ArgParser(); + parser.addFlag('help', abbr: 'h', negatable: false, help: 'Show command help.'); + parser.addFlag('verbose', + defaultsTo: true, + help: 'Whether to report all error messages (on) or attempt to ' + 'filter out some known false positives (off). Shut this off ' + 'locally if you want to address Flutter-specific issues.'); + parser.addFlag('json', help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); + parser.addFlag('validate-links', help: 'Display warnings for broken links generated by dartdoc (slow)'); + parser.addOption('output-dir', defaultsTo: publishDefault, help: 'Sets the output directory for the documentation.'); + return parser; +} + +/// A class used to configure the staging area for building the docs in. +/// +/// The [generateConfiguration] function generates a dummy package with a +/// pubspec. It copies any assets and customization files from the framework +/// repo. It creates a metadata file for searches. +/// +/// Once the docs have been generated, [generateOfflineAssetsIfNeeded] will +/// create offline assets like Dash/Zeal docsets and an offline ZIP file of the +/// site if the build is a CI build that is not a presubmit build. +class Configurator { + Configurator({ + required this.docsRoot, + required this.publishRoot, + required this.packageRoot, + required this.filesystem, + required this.processManager, + required this.platform, + }); + + /// The root of the directory in the Flutter repo where configuration data is + /// stored. + final Directory docsRoot; + + /// The root of the output area for the dartdoc docs. + /// + /// Typically this is a "doc" subdirectory under the [packageRoot]. + final Directory publishRoot; + + /// The root of the staging area for creating docs. + final Directory packageRoot; + + /// The [FileSystem] object used to create [File] and [Directory] objects. + final FileSystem filesystem; + + /// The [ProcessManager] object used to invoke external processes. + /// + /// Can be replaced by tests to have a fake process manager. + final ProcessManager processManager; + + /// The [Platform] to use for this run. + /// + /// Can be replaced by tests to test behavior on different plaforms. + final Platform platform; + + void generateConfiguration() { + final Version version = FlutterInformation.instance.getFlutterVersion(); + _createDummyPubspec(); + _createDummyLibrary(); + _createPageFooter(packageRoot, version); + _copyCustomizations(); + _createSearchMetadata( + docsRoot.childDirectory('lib').childFile('opensearch.xml'), publishRoot.childFile('opensearch.xml')); + } + + Future generateOfflineAssetsIfNeeded() async { + // Only create the offline docs if we're running in a non-presubmit build: + // it takes too long otherwise. + if (platform.environment.containsKey('LUCI_CI') && (platform.environment['LUCI_PR'] ?? '').isEmpty) { + _createOfflineZipFile(); + await _createDocset(); + _moveOfflineIntoPlace(); + _createRobotsTxt(); + } + } + + /// Returns import or on-disk paths for all libraries in the Flutter SDK. + Iterable _libraryRefs() sync* { + for (final Directory dir in findPackages(filesystem)) { + final String dirName = dir.basename; + for (final FileSystemEntity file in dir.childDirectory('lib').listSync()) { + if (file is File && file.path.endsWith('.dart')) { + yield '$dirName/${file.basename}'; + } + } + } + + // Add a fake package for platform integration APIs. + yield '$kPlatformIntegrationPackageName/android.dart'; + yield '$kPlatformIntegrationPackageName/ios.dart'; + } + + void _createDummyPubspec() { + // Create the pubspec.yaml file. + final List pubspec = [ + 'name: $kDummyPackageName', + 'homepage: https://flutter.dev', + 'version: 0.0.0', + 'environment:', + " sdk: '>=3.0.0-0 <4.0.0'", + 'dependencies:', + for (final String package in findPackageNames(filesystem)) ' $package:\n sdk: flutter', + ' $kPlatformIntegrationPackageName: 0.0.1', + 'dependency_overrides:', + ' $kPlatformIntegrationPackageName:', + ' path: ${docsRoot.childDirectory(kPlatformIntegrationPackageName).path}', + ]; + + packageRoot.childFile('pubspec.yaml').writeAsStringSync(pubspec.join('\n')); + } + + void _createDummyLibrary() { + final Directory libDir = packageRoot.childDirectory('lib'); + libDir.createSync(); + + final StringBuffer contents = StringBuffer('library temp_doc;\n\n'); + for (final String libraryRef in _libraryRefs()) { + contents.writeln("import 'package:$libraryRef';"); + } + packageRoot.childDirectory('lib') + ..createSync(recursive: true) + ..childFile('temp_doc.dart').writeAsStringSync(contents.toString()); + } + + void _createPageFooter(Directory footerPath, Version version) { + final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now()); + final String gitBranch = FlutterInformation.instance.getBranchName(); + final String gitRevision = FlutterInformation.instance.getFlutterRevision(); + final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch'; + footerPath.childFile('footer.html').writeAsStringSync(''); + publishRoot.childDirectory('flutter').childFile('footer.js') + ..createSync(recursive: true) + ..writeAsStringSync(''' +(function() { + var span = document.querySelector('footer>span'); + if (span) { + span.innerText = 'Flutter $version • $timestamp • $gitRevision $gitBranchOut'; + } + var sourceLink = document.querySelector('a.source-link'); + if (sourceLink) { + sourceLink.href = sourceLink.href.replace('/master/', '/$gitRevision/'); + } +})(); +'''); + } + + void _copyCustomizations() { + final List files = [ + 'README.md', + 'analysis_options.yaml', + 'dartdoc_options.yaml', + ]; + for (final String file in files) { + final File source = docsRoot.childFile(file); + final File destination = packageRoot.childFile(file); + // Have to canonicalize because otherwise things like /foo/bar/baz and + // /foo/../foo/bar/baz won't compare as identical. + if (path.canonicalize(source.absolute.path) != path.canonicalize(destination.absolute.path)) { + source.copySync(destination.path); + print('Copied ${path.canonicalize(source.absolute.path)} to ${path.canonicalize(destination.absolute.path)}'); + } + } + final Directory assetsDir = filesystem.directory(publishRoot.childDirectory('assets')); + final Directory assetSource = docsRoot.childDirectory('assets'); + if (path.canonicalize(assetSource.absolute.path) == path.canonicalize(assetsDir.absolute.path)) { + // Don't try and copy the directory over itself. + return; + } + if (assetsDir.existsSync()) { + assetsDir.deleteSync(recursive: true); + } + copyDirectorySync( + docsRoot.childDirectory('assets'), + assetsDir, + onFileCopied: (File src, File dest) { + print('Copied ${path.canonicalize(src.absolute.path)} to ${path.canonicalize(dest.absolute.path)}'); + }, + filesystem: filesystem, + ); + } + + /// Generates an OpenSearch XML description that can be used to add a custom + /// search for Flutter API docs to the browser. Unfortunately, it has to know + /// the URL to which site to search, so we customize it here based upon the + /// branch name. + void _createSearchMetadata(File templatePath, File metadataPath) { + final String template = templatePath.readAsStringSync(); + final String branch = FlutterInformation.instance.getBranchName(); + final String metadata = template.replaceAll( + '{SITE_URL}', + branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/', + ); + metadataPath.parent.create(recursive: true); + metadataPath.writeAsStringSync(metadata); + } + + Future _createDocset() async { + // Must have dashing installed: go get -u github.com/technosophos/dashing + // Dashing produces a LOT of log output (~30MB), so we collect it, and just + // show the end of it if there was a problem. + print('${DateTime.now().toUtc()}: Building Flutter docset.'); + + // If dashing gets stuck, Cirrus will time out the build after an hour, and we + // never get to see the logs. Thus, we run it in the background and tail the + // logs only if it fails. + final ProcessWrapper result = ProcessWrapper( + await processManager.start( + [ + 'dashing', + 'build', + '--source', + publishRoot.path, + '--config', + docsRoot.childFile('dashing.json').path, + ], + workingDirectory: packageRoot.path, + ), + ); + final List buffer = []; + result.stdout.listen(buffer.addAll); + result.stderr.listen(buffer.addAll); + // If the dashing process exited with an error, print the last 200 lines of stderr and exit. + final int exitCode = await result.done; + if (exitCode != 0) { + print('Dashing docset generation failed with code $exitCode'); + final List output = systemEncoding.decode(buffer).split('\n'); + print(output.sublist(math.max(output.length - 200, 0)).join('\n')); + exit(exitCode); + } + buffer.clear(); + + // Copy the favicon file to the output directory. + final File faviconFile = + publishRoot.childDirectory('flutter').childDirectory('static-assets').childFile('favicon.png'); + final File iconFile = packageRoot.childDirectory('flutter.docset').childFile('icon.png'); + faviconFile + ..createSync(recursive: true) + ..copySync(iconFile.path); + + // Post-process the dashing output. + final File infoPlist = + packageRoot.childDirectory('flutter.docset').childDirectory('Contents').childFile('Info.plist'); + String contents = infoPlist.readAsStringSync(); + + // Since I didn't want to add the XML package as a dependency just for this, + // I just used a regular expression to make this simple change. + final RegExp findRe = RegExp(r'(\s*DocSetPlatformFamily\s*)[^<]+()', multiLine: true); + contents = contents.replaceAllMapped(findRe, (Match match) { + return '${match.group(1)}dartlang${match.group(2)}'; + }); + infoPlist.writeAsStringSync(contents); + final Directory offlineDir = publishRoot.childDirectory('offline'); + if (!offlineDir.existsSync()) { + offlineDir.createSync(recursive: true); + } + tarDirectory(packageRoot, offlineDir.childFile('flutter.docset.tar.gz'), processManager: processManager); + + // Write the Dash/Zeal XML feed file. + final bool isStable = platform.environment['LUCI_BRANCH'] == 'stable'; + offlineDir.childFile('flutter.xml').writeAsStringSync('\n' + ' ${FlutterInformation.instance.getFlutterVersion()}\n' + ' https://${isStable ? '' : 'master-'}api.flutter.dev/offline/flutter.docset.tar.gz\n' + '\n'); + } + + // Creates the offline ZIP file containing all of the website HTML files. + void _createOfflineZipFile() { + print('${DateTime.now().toLocal()}: Creating offline docs archive.'); + zipDirectory(publishRoot, packageRoot.childFile('flutter.docs.zip'), processManager: processManager); + } + + // Moves the generated offline archives into the publish directory so that + // they can be included in the output ZIP file. + void _moveOfflineIntoPlace() { + print('${DateTime.now().toUtc()}: Moving offline docs into place.'); + final Directory offlineDir = publishRoot.childDirectory('offline')..createSync(recursive: true); + packageRoot.childFile('flutter.docs.zip').renameSync(offlineDir.childFile('flutter.docs.zip').path); + } + + // Creates a robots.txt file that disallows indexing unless the branch is the + // stable branch. + void _createRobotsTxt() { + final File robotsTxt = publishRoot.childFile('robots.txt'); + if (FlutterInformation.instance.getBranchName() == 'stable') { + robotsTxt.writeAsStringSync('# All robots welcome!'); + } else { + robotsTxt.writeAsStringSync('User-agent: *\nDisallow: /'); + } + } +} + +/// Runs Dartdoc inside of the given pre-prepared staging area, prepared by +/// [Configurator.generateConfiguration]. +/// +/// Performs a sanity check of the output once the generation is complete. +class DartdocGenerator { + DartdocGenerator({ + required this.docsRoot, + required this.publishRoot, + required this.packageRoot, + required this.filesystem, + required this.processManager, + this.useJson = true, + this.validateLinks = true, + this.verbose = false, + }); + + /// The root of the directory in the Flutter repo where configuration data is + /// stored. + final Directory docsRoot; + + /// The root of the output area for the dartdoc docs. + /// + /// Typically this is a "doc" subdirectory under the [packageRoot]. + final Directory publishRoot; + + /// The root of the staging area for creating docs. + final Directory packageRoot; + + /// The [FileSystem] object used to create [File] and [Directory] objects. + final FileSystem filesystem; + + /// The [ProcessManager] object used to invoke external processes. + /// + /// Can be replaced by tests to have a fake process manager. + final ProcessManager processManager; + + /// Whether or not dartdoc should output an index.json file of the + /// documentation. + final bool useJson; + + // Whether or not to have dartdoc validate its own links. + final bool validateLinks; + + /// Whether or not to filter overly verbose log output from dartdoc. + final bool verbose; + + Future generateDartdoc() async { + final Directory flutterRoot = FlutterInformation.instance.getFlutterRoot(); + final Map pubEnvironment = { + 'FLUTTER_ROOT': flutterRoot.absolute.path, + }; + + // If there's a .pub-cache dir in the Flutter root, use that. + final File pubCache = flutterRoot.childFile('.pub-cache'); + if (pubCache.existsSync()) { + pubEnvironment['PUB_CACHE'] = pubCache.path; + } + + // Run pub. + ProcessWrapper process = ProcessWrapper(await runPubProcess( + arguments: ['get'], + workingDirectory: packageRoot, + environment: pubEnvironment, + filesystem: filesystem, + processManager: processManager, + )); + printStream(process.stdout, prefix: 'pub:stdout: '); + printStream(process.stderr, prefix: 'pub:stderr: '); + final int code = await process.done; + if (code != 0) { + exit(code); + } + + final Version version = FlutterInformation.instance.getFlutterVersion(); + + // Verify which version of snippets and dartdoc we're using. + final ProcessResult snippetsResult = Process.runSync( + FlutterInformation.instance.getDartBinaryPath().path, + [ + 'pub', + 'global', + 'list', + ], + workingDirectory: packageRoot.path, + environment: pubEnvironment, + stdoutEncoding: utf8, + ); + print(''); + final Iterable versionMatches = + RegExp(r'^(?snippets|dartdoc) (?[^\s]+)', multiLine: true) + .allMatches(snippetsResult.stdout as String); + for (final RegExpMatch match in versionMatches) { + print('${match.namedGroup('name')} version: ${match.namedGroup('version')}'); + } + + print('flutter version: $version\n'); + + // Dartdoc warnings and errors in these packages are considered fatal. + // All packages owned by flutter should be in the list. + final List flutterPackages = [ + kDummyPackageName, + kPlatformIntegrationPackageName, + ...findPackageNames(filesystem), + // TODO(goderbauer): Figure out how to only include `dart:ui` of + // `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278. + // 'sky_engine', + ]; + + // Generate the documentation. We don't need to exclude flutter_tools in + // this list because it's not in the recursive dependencies of the package + // defined at packageRoot + final List dartdocArgs = [ + 'global', + 'run', + '--enable-asserts', + 'dartdoc', + '--output', + publishRoot.childDirectory('flutter').path, + '--allow-tools', + if (useJson) '--json', + if (validateLinks) '--validate-links' else '--no-validate-links', + '--link-to-source-excludes', + flutterRoot.childDirectory('bin').childDirectory('cache').path, + '--link-to-source-root', + flutterRoot.path, + '--link-to-source-uri-template', + 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', + '--inject-html', + '--use-base-href', + '--header', + docsRoot.childFile('styles.html').path, + '--header', + docsRoot.childFile('analytics.html').path, + '--header', + docsRoot.childFile('survey.html').path, + '--header', + docsRoot.childFile('snippets.html').path, + '--header', + docsRoot.childFile('opensearch.html').path, + '--footer-text', + packageRoot.childFile('footer.html').path, + '--allow-warnings-in-packages', + flutterPackages.join(','), + '--exclude-packages', + [ + 'analyzer', + 'args', + 'barback', + 'csslib', + 'flutter_goldens', + 'flutter_goldens_client', + 'front_end', + 'fuchsia_remote_debug_protocol', + 'glob', + 'html', + 'http_multi_server', + 'io', + 'isolate', + 'js', + 'kernel', + 'logging', + 'mime', + 'mockito', + 'node_preamble', + 'plugin', + 'shelf', + 'shelf_packages_handler', + 'shelf_static', + 'shelf_web_socket', + 'utf', + 'watcher', + 'yaml', + ].join(','), + '--exclude', + [ + 'dart:io/network_policy.dart', // dart-lang/dartdoc#2437 + 'package:Flutter/temp_doc.dart', + 'package:http/browser_client.dart', + 'package:intl/intl_browser.dart', + 'package:matcher/mirror_matchers.dart', + 'package:quiver/io.dart', + 'package:quiver/mirrors.dart', + 'package:vm_service_client/vm_service_client.dart', + 'package:web_socket_channel/html.dart', + ].join(','), + '--favicon', + docsRoot.childFile('favicon.ico').absolute.path, + '--package-order', + 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver', + '--auto-include-dependencies', + ]; + + String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg; + print('Executing: (cd "${packageRoot.path}" ; ' + '${FlutterInformation.instance.getDartBinaryPath().path} ' + '${dartdocArgs.map(quote).join(' ')})'); + + process = ProcessWrapper(await runPubProcess( + arguments: dartdocArgs, + workingDirectory: packageRoot, + environment: pubEnvironment, + )); + printStream( + process.stdout, + prefix: useJson ? '' : 'dartdoc:stdout: ', + filter: [ + if (!verbose) RegExp(r'^Generating docs for library '), // Unnecessary verbosity + ], + ); + printStream( + process.stderr, + prefix: useJson ? '' : 'dartdoc:stderr: ', + filter: [ + if (!verbose) + RegExp( + // Remove warnings from packages outside our control + r'^ warning: .+: \(.+[\\/]\.pub-cache[\\/]hosted[\\/]pub.dartlang.org[\\/].+\)', + ), + ], + ); + final int exitCode = await process.done; + + if (exitCode != 0) { + exit(exitCode); + } + + _sanityCheckDocs(); + checkForUnresolvedDirectives(publishRoot.childDirectory('flutter').path); + + _createIndexAndCleanup(); + + print('Documentation written to ${publishRoot.path}'); + } + + void _sanityCheckExample(String fileString, String regExpString) { + final File file = filesystem.file(fileString); + if (file.existsSync()) { + final RegExp regExp = RegExp(regExpString, dotAll: true); + final String contents = file.readAsStringSync(); + if (!regExp.hasMatch(contents)) { + throw Exception("Missing example code matching '$regExpString' in ${file.path}."); + } + } else { + throw Exception( + "Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file."); + } + } + + /// Runs a sanity check by running a test. + void _sanityCheckDocs([Platform platform = const LocalPlatform()]) { + final Directory flutterDirectory = publishRoot.childDirectory('flutter'); + final Directory widgetsDirectory = flutterDirectory.childDirectory('widgets'); + + final List canaries = [ + publishRoot.childDirectory('assets').childFile('overrides.css'), + flutterDirectory.childDirectory('dart-io').childFile('File-class.html'), + flutterDirectory.childDirectory('dart-ui').childFile('Canvas-class.html'), + flutterDirectory.childDirectory('dart-ui').childDirectory('Canvas').childFile('drawRect.html'), + flutterDirectory + .childDirectory('flutter_driver') + .childDirectory('FlutterDriver') + .childFile('FlutterDriver.connectedTo.html'), + flutterDirectory.childDirectory('flutter_test').childDirectory('WidgetTester').childFile('pumpWidget.html'), + flutterDirectory.childDirectory('material').childFile('Material-class.html'), + flutterDirectory.childDirectory('material').childFile('Tooltip-class.html'), + widgetsDirectory.childFile('Widget-class.html'), + widgetsDirectory.childFile('Listener-class.html'), + ]; + for (final File canary in canaries) { + if (!canary.existsSync()) { + throw Exception('Missing "${canary.path}", which probably means the documentation failed to build correctly.'); + } + } + // Make sure at least one example of each kind includes source code. + + // Check a "sample" example, any one will do. + _sanityCheckExample( + widgetsDirectory.childFile('showGeneralDialog.html').path, + r'\s*\s*import 'package:flutter/material.dart';', + ); + + // Check a "snippet" example, any one will do. + _sanityCheckExample( + widgetsDirectory.childDirectory('ModalRoute').childFile('barrierColor.html').path, + r'\s*.*Color\s+get\s+barrierColor.*', + ); + + // Check a "dartpad" example, any one will do, and check for the correct URL + // arguments. + // Just use "master" for any branch other than the LUCI_BRANCH. + final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim(); + final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master'; + final List argumentRegExps = [ + r'split=\d+', + r'run=true', + r'sample_id=widgets\.Listener\.\d+', + 'sample_channel=$expectedBranch', + 'channel=$expectedBranch', + ]; + for (final String argumentRegExp in argumentRegExps) { + _sanityCheckExample( + widgetsDirectory.childFile('Listener-class.html').path, + r'\s*\s*<\/iframe>', + ); + } + } + + /// Creates a custom index.html because we try to maintain old + /// paths. Cleanup unused index.html files no longer needed. + void _createIndexAndCleanup() { + print('\nCreating a custom index.html in ${publishRoot.childFile('index.html').path}'); + _copyIndexToRootOfDocs(); + _addHtmlBaseToIndex(); + _changePackageToSdkInTitlebar(); + _putRedirectInOldIndexLocation(); + _writeSnippetsIndexFile(); + print('\nDocs ready to go!'); + } + + void _copyIndexToRootOfDocs() { + publishRoot.childDirectory('flutter').childFile('index.html').copySync(publishRoot.childFile('index.html').path); + } + + void _changePackageToSdkInTitlebar() { + final File indexFile = publishRoot.childFile('index.html'); + String indexContents = indexFile.readAsStringSync(); + indexContents = indexContents.replaceFirst( + '
  • Flutter package
  • ', + '
  • Flutter SDK
  • ', + ); + + indexFile.writeAsStringSync(indexContents); + } + + void _addHtmlBaseToIndex() { + final File indexFile = publishRoot.childFile('index.html'); + String indexContents = indexFile.readAsStringSync(); + indexContents = indexContents.replaceFirst( + '\n', + '\n \n', + ); + indexContents = indexContents.replaceAll( + 'href="Android/Android-library.html"', + 'href="/javadoc/"', + ); + indexContents = indexContents.replaceAll( + 'href="iOS/iOS-library.html"', + 'href="/objcdoc/"', + ); + + indexFile.writeAsStringSync(indexContents); + } + + void _putRedirectInOldIndexLocation() { + const String metaTag = ''; + publishRoot.childDirectory('flutter').childFile('index.html').writeAsStringSync(metaTag); + } + + void _writeSnippetsIndexFile() { + final Directory snippetsDir = publishRoot.childDirectory('snippets'); + if (snippetsDir.existsSync()) { + const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' '); + final Iterable files = + snippetsDir.listSync().whereType().where((File file) => path.extension(file.path) == '.json'); + // Combine all the metadata into a single JSON array. + final Iterable fileContents = files.map((File file) => file.readAsStringSync()); + final List metadataObjects = fileContents.map(json.decode).toList(); + final String jsonArray = jsonEncoder.convert(metadataObjects); + snippetsDir.childFile('index.json').writeAsStringSync(jsonArray); + } + } +} + +/// Downloads and unpacks the platform specific documentation generated by the +/// engine build. +/// +/// Unpacks and massages the data so that it can be properly included in the +/// output archive. +class PlatformDocGenerator { + PlatformDocGenerator({required this.outputDir, required this.filesystem}); + + final FileSystem filesystem; + final Directory outputDir; + final String engineRevision = FlutterInformation.instance.getEngineRevision(); + + /// This downloads an archive of platform docs for the engine from the artifact + /// store and extracts them to the location used for Dartdoc. + void generatePlatformDocs() { + final String javadocUrl = + 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; + _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); + + final String objcdocUrl = + 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; + _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); + } + + /// Fetches the zip archive at the specified url. + /// + /// Returns null if the archive fails to download after [maxTries] attempts. + Future _fetchArchive(String url, int maxTries) async { + List? responseBytes; + for (int i = 0; i < maxTries; i++) { + final http.Response response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + responseBytes = response.bodyBytes; + break; + } + stderr.writeln('Failed attempt ${i + 1} to fetch $url.'); + + // On failure print a short snipped from the body in case it's helpful. + final int bodyLength = math.min(1024, response.body.length); + stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}'); + sleep(const Duration(seconds: 1)); + } + return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); + } + + Future _extractDocs(String url, String docName, String checkFile, Directory outputDir) async { + const int maxTries = 5; + final Archive? archive = await _fetchArchive(url, maxTries); + if (archive == null) { + stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.'); + exit(1); + } + + final Directory output = outputDir.childDirectory(docName); + print('Extracting $docName to ${output.path}'); + output.createSync(recursive: true); + + for (final ArchiveFile af in archive) { + if (!af.name.endsWith('/')) { + final File file = filesystem.file('${output.path}/${af.name}'); + file.createSync(recursive: true); + file.writeAsBytesSync(af.content as List); + } + } + + /// If object then copy files to old location if the archive is using the new location. + final Directory objcDocsDir = output.childDirectory('objectc_docs'); + if (objcDocsDir.existsSync()) { + copyDirectorySync(objcDocsDir, output, filesystem: filesystem); + } + + final File testFile = output.childFile(checkFile); + if (!testFile.existsSync()) { + print('Expected file ${testFile.path} not found'); + exit(1); + } + print('$docName ready to go!'); + } +} + +/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if +/// specified, for each source/destination file pair. +/// +/// Creates `destDir` if needed. +void copyDirectorySync(Directory srcDir, Directory destDir, + {void Function(File srcFile, File destFile)? onFileCopied, required FileSystem filesystem}) { + if (!srcDir.existsSync()) { + throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); + } + + if (!destDir.existsSync()) { + destDir.createSync(recursive: true); + } + + for (final FileSystemEntity entity in srcDir.listSync()) { + final String newPath = path.join(destDir.path, path.basename(entity.path)); + if (entity is File) { + final File newFile = filesystem.file(newPath); + entity.copySync(newPath); + onFileCopied?.call(entity, newFile); + } else if (entity is Directory) { + copyDirectorySync(entity, filesystem.directory(newPath), filesystem: filesystem); + } else { + throw Exception('${entity.path} is neither File nor Directory'); + } + } +} + +void printStream(Stream> stream, {String prefix = '', List filter = const []}) { + stream.transform(utf8.decoder).transform(const LineSplitter()).listen((String line) { + if (!filter.any((Pattern pattern) => line.contains(pattern))) { + print('$prefix$line'.trim()); + } + }); +} + +void zipDirectory(Directory src, File output, {required ProcessManager processManager}) { + // We would use the archive package to do this in one line, but it + // is a lot slower, and doesn't do compression nearly as well. + final ProcessResult zipProcess = processManager.runSync( + [ + 'zip', + '-r', + '-9', + '-q', + output.path, + '.', + ], + workingDirectory: src.path, + ); + + if (zipProcess.exitCode != 0) { + print('Creating offline ZIP archive ${output.path} failed:'); + print(zipProcess.stderr); + exit(1); + } +} + +void tarDirectory(Directory src, File output, {required ProcessManager processManager}) { + // We would use the archive package to do this in one line, but it + // is a lot slower, and doesn't do compression nearly as well. + final ProcessResult tarProcess = processManager.runSync( + [ + 'tar', + 'cf', + output.path, + '--use-compress-program', + 'gzip --best', + 'flutter.docset', + ], + workingDirectory: src.path, + ); + + if (tarProcess.exitCode != 0) { + print('Creating a tarball ${output.path} failed:'); + print(tarProcess.stderr); + exit(1); + } +} + +Future runPubProcess({ + required List arguments, + Directory? workingDirectory, + Map? environment, + @visibleForTesting ProcessManager processManager = const LocalProcessManager(), + @visibleForTesting FileSystem filesystem = const LocalFileSystem(), +}) { + return processManager.start( + [FlutterInformation.instance.getDartBinaryPath().path, 'pub', ...arguments], + workingDirectory: (workingDirectory ?? filesystem.currentDirectory).path, + environment: environment, + ); +} + +List findPackageNames(FileSystem filesystem) { + return findPackages(filesystem).map((FileSystemEntity file) => path.basename(file.path)).toList(); +} + +/// Finds all packages in the Flutter SDK +List findPackages(FileSystem filesystem) { + return FlutterInformation.instance + .getFlutterRoot() + .childDirectory('packages') + .listSync() + .where((FileSystemEntity entity) { + if (entity is! Directory) { + return false; + } + final File pubspec = filesystem.file('${entity.path}/pubspec.yaml'); + if (!pubspec.existsSync()) { + print("Unexpected package '${entity.path}' found in packages directory"); + return false; + } + // TODO(ianh): Use a real YAML parser here + return !pubspec.readAsStringSync().contains('nodoc: true'); + }) + .cast() + .toList(); +} + +/// An exception class used to indicate problems when collecting information. +class DartdocException implements Exception { + DartdocException(this.message, {this.file, this.line}); + final String message; + final String? file; + final int? line; + + @override + String toString() { + if (file != null || line != null) { + final String fileStr = file == null ? '' : '$file:'; + final String lineStr = line == null ? '' : '$line:'; + return '$runtimeType: $fileStr$lineStr: $message'; + } else { + return '$runtimeType: $message'; + } + } +} + +/// A singleton used to consolidate the way in which information about the +/// Flutter repo and environment is collected. +/// +/// Collects the information once, and caches it for any later access. +/// +/// The singleton instance can be overridden by tests by setting [instance]. +class FlutterInformation { + FlutterInformation({ + this.platform = const LocalPlatform(), + this.processManager = const LocalProcessManager(), + this.filesystem = const LocalFileSystem(), + }); + + final Platform platform; + final ProcessManager processManager; + final FileSystem filesystem; + + static FlutterInformation? _instance; + + static FlutterInformation get instance => _instance ??= FlutterInformation(); + + @visibleForTesting + static set instance(FlutterInformation? value) => _instance = value; + + /// The path to the Dart binary in the Flutter repo. + /// + /// This is probably a shell script. + File getDartBinaryPath() { + return getFlutterRoot().childDirectory('bin').childFile('dart'); + } + + /// The path to the Flutter repo root directory. + /// + /// If the environment variable `FLUTTER_ROOT` is set, will use that instead + /// of looking for it. + /// + /// Otherwise, uses the output of `flutter --version --machine` to find the + /// Flutter root. + Directory getFlutterRoot() { + if (platform.environment['FLUTTER_ROOT'] != null) { + return filesystem.directory(platform.environment['FLUTTER_ROOT']); + } + return getFlutterInformation()['flutterRoot']! as Directory; + } + + /// Gets the semver version of the Flutter framework in the repo. + Version getFlutterVersion() => getFlutterInformation()['frameworkVersion']! as Version; + + /// Gets the git hash of the engine used by the Flutter framework in the repo. + String getEngineRevision() => getFlutterInformation()['engineRevision']! as String; + + /// Gets the git hash of the Flutter framework in the repo. + String getFlutterRevision() => getFlutterInformation()['flutterGitRevision']! as String; + + /// Gets the name of the current branch in the Flutter framework in the repo. + String getBranchName() => getFlutterInformation()['branchName']! as String; + + Map? _cachedFlutterInformation; + + /// Gets a Map of various kinds of information about the Flutter repo. + Map getFlutterInformation() { + if (_cachedFlutterInformation != null) { + return _cachedFlutterInformation!; + } + + String flutterVersionJson; + if (platform.environment['FLUTTER_VERSION'] != null) { + flutterVersionJson = platform.environment['FLUTTER_VERSION']!; + } else { + String flutterCommand; + if (platform.environment['FLUTTER_ROOT'] != null) { + flutterCommand = filesystem + .directory(platform.environment['FLUTTER_ROOT']) + .childDirectory('bin') + .childFile('flutter') + .absolute + .path; + } else { + flutterCommand = 'flutter'; + } + ProcessResult result; + try { + result = processManager.runSync([flutterCommand, '--version', '--machine'], stdoutEncoding: utf8); + } on ProcessException catch (e) { + throw DartdocException( + 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e'); + } + if (result.exitCode != 0) { + throw DartdocException('Unable to determine Flutter information, because of abnormal exit to flutter command.'); + } + flutterVersionJson = (result.stdout as String) + .replaceAll('Waiting for another flutter command to release the startup lock...', ''); + } + + final Map flutterVersion = json.decode(flutterVersionJson) as Map; + if (flutterVersion['flutterRoot'] == null || + flutterVersion['frameworkVersion'] == null || + flutterVersion['dartSdkVersion'] == null) { + throw DartdocException( + 'Flutter command output has unexpected format, unable to determine flutter root location.'); + } + + final Map info = {}; + final Directory flutterRoot = filesystem.directory(flutterVersion['flutterRoot']! as String); + info['flutterRoot'] = flutterRoot; + info['frameworkVersion'] = Version.parse(flutterVersion['frameworkVersion'] as String); + info['engineRevision'] = flutterVersion['engineRevision'] as String; + + final RegExpMatch? dartVersionRegex = RegExp(r'(?[\d.]+)(?:\s+\(build (?[-.\w]+)\))?') + .firstMatch(flutterVersion['dartSdkVersion'] as String); + if (dartVersionRegex == null) { + throw DartdocException( + 'Flutter command output has unexpected format, unable to parse dart SDK version ${flutterVersion['dartSdkVersion']}.'); + } + info['dartSdkVersion'] = + Version.parse(dartVersionRegex.namedGroup('detail') ?? dartVersionRegex.namedGroup('base')!); + + info['branchName'] = _getBranchName(); + info['flutterGitRevision'] = _getFlutterGitRevision(); + _cachedFlutterInformation = info; + + return info; + } + + // Get the name of the release branch. + // + // On LUCI builds, the git HEAD is detached, so first check for the env + // variable "LUCI_BRANCH"; if it is not set, fall back to calling git. + String _getBranchName() { + final String? luciBranch = platform.environment['LUCI_BRANCH']; + if (luciBranch != null && luciBranch.trim().isNotEmpty) { + return luciBranch.trim(); + } + final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain']); + if (gitResult.exitCode != 0) { + throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; + } + final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); + final RegExpMatch? gitBranchMatch = + gitBranchRegexp.firstMatch((gitResult.stdout as String).trim().split('\n').first); + return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first; + } + + // Get the git revision for the repo. + String _getFlutterGitRevision() { + const int kGitRevisionLength = 10; + + final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); + if (gitResult.exitCode != 0) { + throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; + } + final String gitRevision = (gitResult.stdout as String).trim(); + + return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision; + } +} diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart deleted file mode 100644 index 8bd8b39d73ac2..0000000000000 --- a/dev/tools/dartdoc.dart +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; -import 'dart:io'; - -import 'package:args/args.dart'; -import 'package:intl/intl.dart'; -import 'package:meta/meta.dart'; -import 'package:path/path.dart' as path; -import 'package:platform/platform.dart'; -import 'package:process/process.dart'; - -import 'dartdoc_checker.dart'; - -const String kDocsRoot = 'dev/docs'; -const String kPublishRoot = '$kDocsRoot/doc'; - -const String kDummyPackageName = 'Flutter'; -const String kPlatformIntegrationPackageName = 'platform_integration'; - -/// This script expects to run with the cwd as the root of the flutter repo. It -/// will generate documentation for the packages in `//packages/` and write the -/// documentation to `//dev/docs/doc/api/`. -/// -/// This script also updates the index.html file so that it can be placed -/// at the root of api.flutter.dev. We are keeping the files inside of -/// api.flutter.dev/flutter for now, so we need to manipulate paths -/// a bit. See https://github.com/flutter/flutter/issues/3900 for more info. -/// -/// This will only work on UNIX systems, not Windows. It requires that 'git' be -/// in your path. It requires that 'flutter' has been run previously. It uses -/// the version of Dart downloaded by the 'flutter' tool in this repository and -/// will crash if that is absent. -Future main(List arguments) async { - final ArgParser argParser = _createArgsParser(); - final ArgResults args = argParser.parse(arguments); - if (args['help'] as bool) { - print ('Usage:'); - print (argParser.usage); - exit(0); - } - // If we're run from the `tools` dir, set the cwd to the repo root. - if (path.basename(Directory.current.path) == 'tools') { - Directory.current = Directory.current.parent.parent; - } - - final ProcessResult flutter = Process.runSync('flutter', []); - final File versionFile = File('version'); - if (flutter.exitCode != 0 || !versionFile.existsSync()) { - throw Exception('Failed to determine Flutter version.'); - } - final String version = versionFile.readAsStringSync(); - - // Create the pubspec.yaml file. - final StringBuffer buf = StringBuffer(); - buf.writeln('name: $kDummyPackageName'); - buf.writeln('homepage: https://flutter.dev'); - buf.writeln('version: 0.0.0'); - buf.writeln('environment:'); - buf.writeln(" sdk: '>=3.0.0-0 <4.0.0'"); - buf.writeln('dependencies:'); - for (final String package in findPackageNames()) { - buf.writeln(' $package:'); - buf.writeln(' sdk: flutter'); - } - buf.writeln(' $kPlatformIntegrationPackageName: 0.0.1'); - buf.writeln('dependency_overrides:'); - buf.writeln(' $kPlatformIntegrationPackageName:'); - buf.writeln(' path: $kPlatformIntegrationPackageName'); - File('$kDocsRoot/pubspec.yaml').writeAsStringSync(buf.toString()); - - // Create the library file. - final Directory libDir = Directory('$kDocsRoot/lib'); - libDir.createSync(); - - final StringBuffer contents = StringBuffer('library temp_doc;\n\n'); - for (final String libraryRef in libraryRefs()) { - contents.writeln("import 'package:$libraryRef';"); - } - File('$kDocsRoot/lib/temp_doc.dart').writeAsStringSync(contents.toString()); - - final String flutterRoot = Directory.current.path; - final Map pubEnvironment = { - 'FLUTTER_ROOT': flutterRoot, - }; - - // If there's a .pub-cache dir in the flutter root, use that. - final String pubCachePath = '$flutterRoot/.pub-cache'; - if (Directory(pubCachePath).existsSync()) { - pubEnvironment['PUB_CACHE'] = pubCachePath; - } - - final String dartExecutable = '$flutterRoot/bin/cache/dart-sdk/bin/dart'; - - // Run pub. - ProcessWrapper process = ProcessWrapper(await runPubProcess( - dartBinaryPath: dartExecutable, - arguments: ['get'], - workingDirectory: kDocsRoot, - environment: pubEnvironment, - )); - printStream(process.stdout, prefix: 'pub:stdout: '); - printStream(process.stderr, prefix: 'pub:stderr: '); - final int code = await process.done; - if (code != 0) { - exit(code); - } - - createFooter('$kDocsRoot/lib/', version); - copyAssets(); - createSearchMetadata('$kDocsRoot/lib/opensearch.xml', '$kDocsRoot/doc/opensearch.xml'); - cleanOutSnippets(); - - final List dartdocBaseArgs = [ - 'global', - 'run', - if (args['checked'] as bool) '--enable-asserts', - 'dartdoc', - ]; - - // Verify which version of snippets and dartdoc we're using. - final ProcessResult snippetsResult = Process.runSync( - dartExecutable, - [ - 'pub', - 'global', - 'list', - ], - workingDirectory: kDocsRoot, - environment: pubEnvironment, - stdoutEncoding: utf8, - ); - print(''); - final Iterable versionMatches = RegExp(r'^(?snippets|dartdoc) (?[^\s]+)', multiLine: true) - .allMatches(snippetsResult.stdout as String); - for (final RegExpMatch match in versionMatches) { - print('${match.namedGroup('name')} version: ${match.namedGroup('version')}'); - } - - print('flutter version: $version\n'); - - // Dartdoc warnings and errors in these packages are considered fatal. - // All packages owned by flutter should be in the list. - final List flutterPackages = [ - kDummyPackageName, - kPlatformIntegrationPackageName, - ...findPackageNames(), - // TODO(goderbauer): Figure out how to only include `dart:ui` of `sky_engine` below, https://github.com/dart-lang/dartdoc/issues/2278. - // 'sky_engine', - ]; - - // Generate the documentation. - // We don't need to exclude flutter_tools in this list because it's not in the - // recursive dependencies of the package defined at dev/docs/pubspec.yaml - final List dartdocArgs = [ - ...dartdocBaseArgs, - '--allow-tools', - if (args['json'] as bool) '--json', - if (args['validate-links'] as bool) '--validate-links' else '--no-validate-links', - '--link-to-source-excludes', '../../bin/cache', - '--link-to-source-root', '../..', - '--link-to-source-uri-template', 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', - '--inject-html', - '--use-base-href', - '--header', 'styles.html', - '--header', 'analytics.html', - '--header', 'survey.html', - '--header', 'snippets.html', - '--header', 'opensearch.html', - '--footer-text', 'lib/footer.html', - '--allow-warnings-in-packages', flutterPackages.join(','), - '--exclude-packages', - [ - 'analyzer', - 'args', - 'barback', - 'csslib', - 'flutter_goldens', - 'flutter_goldens_client', - 'front_end', - 'fuchsia_remote_debug_protocol', - 'glob', - 'html', - 'http_multi_server', - 'io', - 'isolate', - 'js', - 'kernel', - 'logging', - 'mime', - 'mockito', - 'node_preamble', - 'plugin', - 'shelf', - 'shelf_packages_handler', - 'shelf_static', - 'shelf_web_socket', - 'utf', - 'watcher', - 'yaml', - ].join(','), - '--exclude', - [ - 'dart:io/network_policy.dart', // dart-lang/dartdoc#2437 - 'package:Flutter/temp_doc.dart', - 'package:http/browser_client.dart', - 'package:intl/intl_browser.dart', - 'package:matcher/mirror_matchers.dart', - 'package:quiver/io.dart', - 'package:quiver/mirrors.dart', - 'package:vm_service_client/vm_service_client.dart', - 'package:web_socket_channel/html.dart', - ].join(','), - '--favicon=favicon.ico', - '--package-order', 'flutter,Dart,$kPlatformIntegrationPackageName,flutter_test,flutter_driver', - '--auto-include-dependencies', - ]; - - String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg; - print('Executing: (cd $kDocsRoot ; $dartExecutable ${dartdocArgs.map(quote).join(' ')})'); - - process = ProcessWrapper(await runPubProcess( - dartBinaryPath: dartExecutable, - arguments: dartdocArgs, - workingDirectory: kDocsRoot, - environment: pubEnvironment, - )); - printStream(process.stdout, prefix: args['json'] as bool ? '' : 'dartdoc:stdout: ', - filter: args['verbose'] as bool ? const [] : [ - RegExp(r'^Generating docs for library '), // unnecessary verbosity - ], - ); - printStream(process.stderr, prefix: args['json'] as bool ? '' : 'dartdoc:stderr: ', - filter: args['verbose'] as bool ? const [] : [ - RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control - ], - ); - final int exitCode = await process.done; - - if (exitCode != 0) { - exit(exitCode); - } - - sanityCheckDocs(); - checkForUnresolvedDirectives('$kPublishRoot/api'); - - createIndexAndCleanup(); -} - -ArgParser _createArgsParser() { - final ArgParser parser = ArgParser(); - parser.addFlag('help', abbr: 'h', negatable: false, - help: 'Show command help.'); - parser.addFlag('verbose', defaultsTo: true, - help: 'Whether to report all error messages (on) or attempt to ' - 'filter out some known false positives (off). Shut this off ' - 'locally if you want to address Flutter-specific issues.'); - parser.addFlag('checked', abbr: 'c', - help: 'Run dartdoc with asserts enabled.'); - parser.addFlag('json', - help: 'Display json-formatted output from dartdoc and skip stdout/stderr prefixing.'); - parser.addFlag('validate-links', - help: 'Display warnings for broken links generated by dartdoc (slow)'); - return parser; -} - -final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); - -/// Get the name of the release branch. -/// -/// On LUCI builds, the git HEAD is detached, so first check for the env -/// variable "LUCI_BRANCH"; if it is not set, fall back to calling git. -String getBranchName({ - @visibleForTesting - Platform platform = const LocalPlatform(), - @visibleForTesting - ProcessManager processManager = const LocalProcessManager(), -}) { - final String? luciBranch = platform.environment['LUCI_BRANCH']; - if (luciBranch != null && luciBranch.trim().isNotEmpty) { - return luciBranch.trim(); - } - final ProcessResult gitResult = processManager.runSync(['git', 'status', '-b', '--porcelain']); - if (gitResult.exitCode != 0) { - throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; - } - final RegExpMatch? gitBranchMatch = gitBranchRegexp.firstMatch( - (gitResult.stdout as String).trim().split('\n').first); - return gitBranchMatch == null ? '' : gitBranchMatch.group(1)!.split('...').first; -} - -String gitRevision() { - const int kGitRevisionLength = 10; - - final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); - if (gitResult.exitCode != 0) { - throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; - } - final String gitRevision = (gitResult.stdout as String).trim(); - - return gitRevision.length > kGitRevisionLength ? gitRevision.substring(0, kGitRevisionLength) : gitRevision; -} - -void createFooter(String footerPath, String version) { - final String timestamp = DateFormat('yyyy-MM-dd HH:mm').format(DateTime.now()); - final String gitBranch = getBranchName(); - final String gitBranchOut = gitBranch.isEmpty ? '' : '• $gitBranch'; - File('${footerPath}footer.html').writeAsStringSync(''); - File('$kPublishRoot/api/footer.js') - ..createSync(recursive: true) - ..writeAsStringSync(''' -(function() { - var span = document.querySelector('footer>span'); - if (span) { - span.innerText = 'Flutter $version • $timestamp • ${gitRevision()} $gitBranchOut'; - } - var sourceLink = document.querySelector('a.source-link'); - if (sourceLink) { - sourceLink.href = sourceLink.href.replace('/master/', '/${gitRevision()}/'); - } -})(); -'''); -} - -/// Generates an OpenSearch XML description that can be used to add a custom -/// search for Flutter API docs to the browser. Unfortunately, it has to know -/// the URL to which site to search, so we customize it here based upon the -/// branch name. -void createSearchMetadata(String templatePath, String metadataPath) { - final String template = File(templatePath).readAsStringSync(); - final String branch = getBranchName(); - final String metadata = template.replaceAll( - '{SITE_URL}', - branch == 'stable' ? 'https://api.flutter.dev/' : 'https://master-api.flutter.dev/', - ); - Directory(path.dirname(metadataPath)).create(recursive: true); - File(metadataPath).writeAsStringSync(metadata); -} - -/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied], if -/// specified, for each source/destination file pair. -/// -/// Creates `destDir` if needed. -void copyDirectorySync(Directory srcDir, Directory destDir, [void Function(File srcFile, File destFile)? onFileCopied]) { - if (!srcDir.existsSync()) { - throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy'); - } - - if (!destDir.existsSync()) { - destDir.createSync(recursive: true); - } - - for (final FileSystemEntity entity in srcDir.listSync()) { - final String newPath = path.join(destDir.path, path.basename(entity.path)); - if (entity is File) { - final File newFile = File(newPath); - entity.copySync(newPath); - onFileCopied?.call(entity, newFile); - } else if (entity is Directory) { - copyDirectorySync(entity, Directory(newPath)); - } else { - throw Exception('${entity.path} is neither File nor Directory'); - } - } -} - -void copyAssets() { - final Directory assetsDir = Directory(path.join(kPublishRoot, 'assets')); - if (assetsDir.existsSync()) { - assetsDir.deleteSync(recursive: true); - } - copyDirectorySync( - Directory(path.join(kDocsRoot, 'assets')), - Directory(path.join(kPublishRoot, 'assets')), - (File src, File dest) => print('Copied ${src.path} to ${dest.path}')); -} - -/// Clean out any existing snippets so that we don't publish old files from -/// previous runs accidentally. -void cleanOutSnippets() { - final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets')); - if (snippetsDir.existsSync()) { - snippetsDir - ..deleteSync(recursive: true) - ..createSync(recursive: true); - } -} - -void _sanityCheckExample(String fileString, String regExpString) { - final File file = File(fileString); - if (file.existsSync()) { - final RegExp regExp = RegExp(regExpString, dotAll: true); - final String contents = file.readAsStringSync(); - if (!regExp.hasMatch(contents)) { - throw Exception("Missing example code matching '$regExpString' in ${file.path}."); - } - } else { - throw Exception( - "Missing example code sanity test file ${file.path}. Either it didn't get published, or you might have to update the test to look at a different file."); - } -} - -/// Runs a sanity check by running a test. -void sanityCheckDocs([Platform platform = const LocalPlatform()]) { - final List canaries = [ - '$kPublishRoot/assets/overrides.css', - '$kPublishRoot/api/dart-io/File-class.html', - '$kPublishRoot/api/dart-ui/Canvas-class.html', - '$kPublishRoot/api/dart-ui/Canvas/drawRect.html', - '$kPublishRoot/api/flutter_driver/FlutterDriver/FlutterDriver.connectedTo.html', - '$kPublishRoot/api/flutter_test/WidgetTester/pumpWidget.html', - '$kPublishRoot/api/material/Material-class.html', - '$kPublishRoot/api/material/Tooltip-class.html', - '$kPublishRoot/api/widgets/Widget-class.html', - '$kPublishRoot/api/widgets/Listener-class.html', - ]; - for (final String canary in canaries) { - if (!File(canary).existsSync()) { - throw Exception('Missing "$canary", which probably means the documentation failed to build correctly.'); - } - } - // Make sure at least one example of each kind includes source code. - - // Check a "sample" example, any one will do. - _sanityCheckExample( - '$kPublishRoot/api/widgets/showGeneralDialog.html', - r'\s*\s*import 'package:flutter/material.dart';', - ); - - // Check a "snippet" example, any one will do. - _sanityCheckExample( - '$kPublishRoot/api/widgets/ModalRoute/barrierColor.html', - r'\s*.*Color\s+get\s+barrierColor.*', - ); - - // Check a "dartpad" example, any one will do, and check for the correct URL - // arguments. - // Just use "master" for any branch other than the LUCI_BRANCH. - final String? luciBranch = platform.environment['LUCI_BRANCH']?.trim(); - final String expectedBranch = luciBranch != null && luciBranch.isNotEmpty ? luciBranch : 'master'; - final List argumentRegExps = [ - r'split=\d+', - r'run=true', - r'sample_id=widgets\.Listener\.\d+', - 'sample_channel=$expectedBranch', - 'channel=$expectedBranch', - ]; - for (final String argumentRegExp in argumentRegExps) { - _sanityCheckExample( - '$kPublishRoot/api/widgets/Listener-class.html', - r'\s*\s*<\/iframe>', - ); - } -} - -/// Creates a custom index.html because we try to maintain old -/// paths. Cleanup unused index.html files no longer needed. -void createIndexAndCleanup() { - print('\nCreating a custom index.html in $kPublishRoot/index.html'); - removeOldFlutterDocsDir(); - renameApiDir(); - copyIndexToRootOfDocs(); - addHtmlBaseToIndex(); - changePackageToSdkInTitlebar(); - putRedirectInOldIndexLocation(); - writeSnippetsIndexFile(); - print('\nDocs ready to go!'); -} - -void removeOldFlutterDocsDir() { - try { - Directory('$kPublishRoot/flutter').deleteSync(recursive: true); - } on FileSystemException { - // If the directory does not exist, that's OK. - } -} - -void renameApiDir() { - Directory('$kPublishRoot/api').renameSync('$kPublishRoot/flutter'); -} - -void copyIndexToRootOfDocs() { - File('$kPublishRoot/flutter/index.html').copySync('$kPublishRoot/index.html'); -} - -void changePackageToSdkInTitlebar() { - final File indexFile = File('$kPublishRoot/index.html'); - String indexContents = indexFile.readAsStringSync(); - indexContents = indexContents.replaceFirst( - '
  • Flutter package
  • ', - '
  • Flutter SDK
  • ', - ); - - indexFile.writeAsStringSync(indexContents); -} - -void addHtmlBaseToIndex() { - final File indexFile = File('$kPublishRoot/index.html'); - String indexContents = indexFile.readAsStringSync(); - indexContents = indexContents.replaceFirst( - '\n', - '\n \n', - ); - indexContents = indexContents.replaceAll( - 'href="Android/Android-library.html"', - 'href="/javadoc/"', - ); - indexContents = indexContents.replaceAll( - 'href="iOS/iOS-library.html"', - 'href="/objcdoc/"', - ); - - indexFile.writeAsStringSync(indexContents); -} - -void putRedirectInOldIndexLocation() { - const String metaTag = ''; - File('$kPublishRoot/flutter/index.html').writeAsStringSync(metaTag); -} - -void writeSnippetsIndexFile() { - final Directory snippetsDir = Directory(path.join(kPublishRoot, 'snippets')); - if (snippetsDir.existsSync()) { - const JsonEncoder jsonEncoder = JsonEncoder.withIndent(' '); - final Iterable files = snippetsDir - .listSync() - .whereType() - .where((File file) => path.extension(file.path) == '.json'); - // Combine all the metadata into a single JSON array. - final Iterable fileContents = files.map((File file) => file.readAsStringSync()); - final List metadataObjects = fileContents.map(json.decode).toList(); - final String jsonArray = jsonEncoder.convert(metadataObjects); - File('$kPublishRoot/snippets/index.json').writeAsStringSync(jsonArray); - } -} - -List findPackageNames() { - return findPackages().map((FileSystemEntity file) => path.basename(file.path)).toList(); -} - -/// Finds all packages in the Flutter SDK -List findPackages() { - return Directory('packages') - .listSync() - .where((FileSystemEntity entity) { - if (entity is! Directory) { - return false; - } - final File pubspec = File('${entity.path}/pubspec.yaml'); - if (!pubspec.existsSync()) { - print("Unexpected package '${entity.path}' found in packages directory"); - return false; - } - // TODO(ianh): Use a real YAML parser here - return !pubspec.readAsStringSync().contains('nodoc: true'); - }) - .cast() - .toList(); -} - -/// Returns import or on-disk paths for all libraries in the Flutter SDK. -Iterable libraryRefs() sync* { - for (final Directory dir in findPackages()) { - final String dirName = path.basename(dir.path); - for (final FileSystemEntity file in Directory('${dir.path}/lib').listSync()) { - if (file is File && file.path.endsWith('.dart')) { - yield '$dirName/${path.basename(file.path)}'; - } - } - } - - // Add a fake package for platform integration APIs. - yield '$kPlatformIntegrationPackageName/android.dart'; - yield '$kPlatformIntegrationPackageName/ios.dart'; -} - -void printStream(Stream> stream, { String prefix = '', List filter = const [] }) { - stream - .transform(utf8.decoder) - .transform(const LineSplitter()) - .listen((String line) { - if (!filter.any((Pattern pattern) => line.contains(pattern))) { - print('$prefix$line'.trim()); - } - }); -} - -Future runPubProcess({ - required String dartBinaryPath, - required List arguments, - String? workingDirectory, - Map? environment, - @visibleForTesting - ProcessManager processManager = const LocalProcessManager(), -}) { - return processManager.start( - [dartBinaryPath, 'pub', ...arguments], - workingDirectory: workingDirectory, - environment: environment, - ); -} diff --git a/dev/tools/java_and_objc_doc.dart b/dev/tools/java_and_objc_doc.dart deleted file mode 100644 index 260cdc7b6094f..0000000000000 --- a/dev/tools/java_and_objc_doc.dart +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:io'; -import 'dart:math'; - -import 'package:archive/archive.dart'; -import 'package:http/http.dart' as http; -import 'package:path/path.dart' as path; - -const String kDocRoot = 'dev/docs/doc'; - -/// This script downloads an archive of Javadoc and objc doc for the engine from -/// the artifact store and extracts them to the location used for Dartdoc. -Future main(List args) async { - final String engineVersion = File('bin/internal/engine.version').readAsStringSync().trim(); - String engineRealm = File('bin/internal/engine.realm').readAsStringSync().trim(); - if (engineRealm.isNotEmpty) { - engineRealm = '$engineRealm/'; - } - - final String javadocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/android-javadoc.zip'; - generateDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html'); - - final String objcdocUrl = 'https://storage.googleapis.com/${engineRealm}flutter_infra_release/flutter/$engineVersion/ios-objcdoc.zip'; - generateDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html'); -} - -/// Fetches the zip archive at the specified url. -/// -/// Returns null if the archive fails to download after [maxTries] attempts. -Future fetchArchive(String url, int maxTries) async { - List? responseBytes; - for (int i = 0; i < maxTries; i++) { - final http.Response response = await http.get(Uri.parse(url)); - if (response.statusCode == 200) { - responseBytes = response.bodyBytes; - break; - } - stderr.writeln('Failed attempt ${i+1} to fetch $url.'); - - // On failure print a short snipped from the body in case it's helpful. - final int bodyLength = min(1024, response.body.length); - stderr.writeln('Response status code ${response.statusCode}. Body: ${response.body.substring(0, bodyLength)}'); - sleep(const Duration(seconds: 1)); - } - return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); -} - -Future generateDocs(String url, String docName, String checkFile) async { - const int maxTries = 5; - final Archive? archive = await fetchArchive(url, maxTries); - if (archive == null) { - stderr.writeln('Failed to fetch zip archive from: $url after $maxTries attempts. Giving up.'); - exit(1); - } - - final Directory output = Directory('$kDocRoot/$docName'); - print('Extracting $docName to ${output.path}'); - output.createSync(recursive: true); - - for (final ArchiveFile af in archive) { - if (!af.name.endsWith('/')) { - final File file = File('${output.path}/${af.name}'); - file.createSync(recursive: true); - file.writeAsBytesSync(af.content as List); - } - } - - /// If object then copy files to old location if the archive is using the new location. - final bool exists = Directory('$kDocRoot/$docName/objectc_docs').existsSync(); - if (exists) { - copyFolder(Directory('$kDocRoot/$docName/objectc_docs'), Directory('$kDocRoot/$docName/')); - } - - final File testFile = File('${output.path}/$checkFile'); - if (!testFile.existsSync()) { - print('Expected file ${testFile.path} not found'); - exit(1); - } - print('$docName ready to go!'); -} - -/// Copies the files in a directory recursively to a new location. -void copyFolder(Directory source, Directory destination) { - source.listSync() - .forEach((FileSystemEntity entity) { - if (entity is Directory) { - final Directory newDirectory = Directory(path.join(destination.absolute.path, path.basename(entity.path))); - newDirectory.createSync(); - copyFolder(entity.absolute, newDirectory); - } else if (entity is File) { - entity.copySync(path.join(destination.path, path.basename(entity.path))); - } - }); -} diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 5d6b2bffc086d..6b859d666f22a 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: meta: 1.9.1 path: 1.8.3 process: 4.2.4 + pub_semver: 2.1.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,7 +46,6 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart new file mode 100644 index 0000000000000..31703a1b1cdb5 --- /dev/null +++ b/dev/tools/test/create_api_docs_test.dart @@ -0,0 +1,197 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:platform/platform.dart'; +import 'package:pub_semver/pub_semver.dart'; +import 'package:test/test.dart'; + +import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; +import '../create_api_docs.dart' as apidocs; +import '../examples_smoke_test.dart'; + +void main() { + test('getBranchName does not call git if env LUCI_BRANCH provided', () { + final Platform platform = FakePlatform( + environment: { + 'LUCI_BRANCH': branchName, + }, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + ], + ); + + expect( + apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH not provided', () { + final Platform platform = FakePlatform( + environment: {}, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + ], + ); + + expect( + apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH is empty', () { + final Platform platform = FakePlatform( + environment: { + 'LUCI_BRANCH': '', + }, + ); + + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + ], + ); + + expect( + apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), + branchName, + ); + expect(processManager, hasNoRemainingExpectations); + }); + + test("runPubProcess doesn't use the pub binary", () { + final Platform platform = FakePlatform( + environment: { + 'FLUTTER_ROOT': '/flutter', + }, + ); + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['/flutter/bin/dart', 'pub', '--one', '--two'], + ), + ], + ); + apidocs.FlutterInformation.instance = + apidocs.FlutterInformation(platform: platform, processManager: processManager); + + apidocs.runPubProcess( + arguments: ['--one', '--two'], + processManager: processManager, + filesystem: filesystem, + ); + + expect(processManager, hasNoRemainingExpectations); + }); + + group('FlutterInformation', () { + late FakeProcessManager fakeProcessManager; + late FakePlatform fakePlatform; + late MemoryFileSystem memoryFileSystem; + late apidocs.FlutterInformation flutterInformation; + + void setUpWithEnvironment(Map environment) { + fakePlatform = FakePlatform(environment: environment); + flutterInformation = apidocs.FlutterInformation( + filesystem: memoryFileSystem, + processManager: fakeProcessManager, + platform: fakePlatform, + ); + apidocs.FlutterInformation.instance = flutterInformation; + } + + setUp(() { + fakeProcessManager = FakeProcessManager.empty(); + memoryFileSystem = MemoryFileSystem(); + setUpWithEnvironment({}); + }); + + test('calls out to flutter if FLUTTER_VERSION is not set', () async { + fakeProcessManager.addCommand( + const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Map info = flutterInformation.getFlutterInformation(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); + }); + test("doesn't call out to flutter if FLUTTER_VERSION is set", () async { + setUpWithEnvironment({ + 'FLUTTER_VERSION': testVersionInfo, + }); + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Map info = flutterInformation.getFlutterInformation(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); + }); + test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set', () async { + fakeProcessManager.addCommand( + const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Directory root = flutterInformation.getFlutterRoot(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(root.path, equals('/home/user/flutter')); + }); + test("getFlutterRoot doesn't call out to flutter if FLUTTER_ROOT is set", () async { + setUpWithEnvironment({'FLUTTER_ROOT': '/home/user/flutter'}); + final Directory root = flutterInformation.getFlutterRoot(); + expect(fakeProcessManager, hasNoRemainingExpectations); + expect(root.path, equals('/home/user/flutter')); + }); + test('parses version properly', () async { + fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo; + fakeProcessManager.addCommand( + const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + final Map info = flutterInformation.getFlutterInformation(); + expect(info['frameworkVersion'], isNotNull); + expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); + expect(info['dartSdkVersion'], isNotNull); + expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev'))); + }); + }); +} + +const String branchName = 'stable'; +const String testVersionInfo = ''' +{ + "frameworkVersion": "2.5.0", + "channel": "$branchName", + "repositoryUrl": "git@github.com:flutter/flutter.git", + "frameworkRevision": "0000000000000000000000000000000000000000", + "frameworkCommitDate": "2021-07-28 13:03:40 -0700", + "engineRevision": "0000000000000000000000000000000000000001", + "dartSdkVersion": "2.14.0 (build 2.14.0-360.0.dev)", + "flutterRoot": "/home/user/flutter" +} +'''; diff --git a/dev/tools/test/dartdoc_test.dart b/dev/tools/test/dartdoc_test.dart deleted file mode 100644 index 5744650ee3fa8..0000000000000 --- a/dev/tools/test/dartdoc_test.dart +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:platform/platform.dart'; -import 'package:test/test.dart'; - -import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; -import '../dartdoc.dart' show getBranchName, runPubProcess; - -void main() { - const String branchName = 'stable'; - test('getBranchName does not call git if env LUCI_BRANCH provided', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': branchName, - }, - ); - - final ProcessManager processManager = FakeProcessManager.empty(); - - expect( - getBranchName( - platform: platform, - processManager: processManager, - ), - branchName, - ); - }); - - test('getBranchName calls git if env LUCI_BRANCH not provided', () { - final Platform platform = FakePlatform( - environment: {}, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - getBranchName( - platform: platform, - processManager: processManager, - ), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH is empty', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': '', - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - getBranchName( - platform: platform, - processManager: processManager, - ), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test("runPubProcess doesn't use the pub binary", () { - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['dart', 'pub', '--one', '--two'], - ), - ], - ); - - runPubProcess( - dartBinaryPath: 'dart', - arguments: ['--one', '--two'], - processManager: processManager, - ); - - expect(processManager, hasNoRemainingExpectations); - }); -} From f68d03f1cdf16dcffe2a53ae645ec87094e85d40 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Thu, 17 Aug 2023 16:55:05 -0700 Subject: [PATCH 0781/1547] Reland root predictive back (#132249) Root predictive back (https://github.com/flutter/flutter/pull/120385) was reverted in https://github.com/flutter/flutter/pull/132167. This PR is an attempt to reland it. The reversion happened due to failed Google tests (b/295073110). --- .../cupertino/cupertino_navigation_demo.dart | 4 +- .../material/full_screen_dialog_demo.dart | 31 +- .../demo/material/text_form_field_demo.dart | 19 +- .../demo/shrine/expanding_bottom_sheet.dart | 14 +- .../flutter_gallery/lib/gallery/home.dart | 14 +- .../navigation_bar/navigation_bar.2.dart | 8 +- examples/api/lib/widgets/form/form.1.dart | 166 ++++ .../navigator_pop_handler.0.dart | 164 ++++ .../navigator_pop_handler.1.dart | 250 +++++ .../lib/widgets/pop_scope/pop_scope.0.dart | 128 +++ .../will_pop_scope/will_pop_scope.0.dart | 77 -- .../api/test/widgets/form/form.1_test.dart | 37 + .../navigator_pop_handler.0_test.dart | 48 + .../navigator_pop_handler.1_test.dart | 38 + .../api/test/widgets/navigator_utils.dart | 20 + .../widgets/pop_scope/pop_scope.0_test.dart | 66 ++ .../will_pop_scope/will_pop_scope.0_test.dart | 32 - packages/flutter/lib/src/cupertino/app.dart | 6 + packages/flutter/lib/src/cupertino/route.dart | 3 +- .../flutter/lib/src/cupertino/tab_view.dart | 28 +- packages/flutter/lib/src/material/about.dart | 13 +- packages/flutter/lib/src/material/app.dart | 6 + .../lib/src/services/system_navigator.dart | 34 + packages/flutter/lib/src/widgets/app.dart | 73 +- packages/flutter/lib/src/widgets/binding.dart | 28 +- packages/flutter/lib/src/widgets/form.dart | 59 +- .../flutter/lib/src/widgets/navigator.dart | 294 +++++- .../src/widgets/navigator_pop_handler.dart | 110 +++ .../flutter/lib/src/widgets/pop_scope.dart | 137 +++ packages/flutter/lib/src/widgets/routes.dart | 217 +++-- .../lib/src/widgets/will_pop_scope.dart | 17 +- packages/flutter/lib/widgets.dart | 2 + .../test/cupertino/tab_scaffold_test.dart | 131 ++- .../flutter/test/widgets/navigator_test.dart | 866 ++++++++++++++++++ .../flutter/test/widgets/navigator_utils.dart | 20 + .../flutter/test/widgets/pop_scope_test.dart | 361 ++++++++ 36 files changed, 3224 insertions(+), 297 deletions(-) create mode 100644 examples/api/lib/widgets/form/form.1.dart create mode 100644 examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart create mode 100644 examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart create mode 100644 examples/api/lib/widgets/pop_scope/pop_scope.0.dart delete mode 100644 examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart create mode 100644 examples/api/test/widgets/form/form.1_test.dart create mode 100644 examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart create mode 100644 examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart create mode 100644 examples/api/test/widgets/navigator_utils.dart create mode 100644 examples/api/test/widgets/pop_scope/pop_scope.0_test.dart delete mode 100644 examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart create mode 100644 packages/flutter/lib/src/widgets/navigator_pop_handler.dart create mode 100644 packages/flutter/lib/src/widgets/pop_scope.dart create mode 100644 packages/flutter/test/widgets/navigator_utils.dart create mode 100644 packages/flutter/test/widgets/pop_scope_test.dart diff --git a/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart index f6626b85e20dd..a68c2a194c9b7 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/cupertino/cupertino_navigation_demo.dart @@ -48,9 +48,9 @@ class CupertinoNavigationDemo extends StatelessWidget { @override Widget build(BuildContext context) { - return WillPopScope( + return PopScope( // Prevent swipe popping of this page. Use explicit exit buttons only. - onWillPop: () => Future.value(true), + canPop: false, child: DefaultTextStyle( style: CupertinoTheme.of(context).textTheme.textStyle, child: CupertinoTabScaffold( diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart index b6f7bbe6b6afb..81ee4dacd8643 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/full_screen_dialog_demo.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; // This demo is based on @@ -109,16 +110,15 @@ class FullScreenDialogDemoState extends State { bool _hasName = false; late String _eventName; - Future _onWillPop() async { - _saveNeeded = _hasLocation || _hasName || _saveNeeded; - if (!_saveNeeded) { - return true; + Future _handlePopInvoked(bool didPop) async { + if (didPop) { + return; } final ThemeData theme = Theme.of(context); final TextStyle dialogTextStyle = theme.textTheme.titleMedium!.copyWith(color: theme.textTheme.bodySmall!.color); - return showDialog( + final bool? shouldDiscard = await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( @@ -130,19 +130,31 @@ class FullScreenDialogDemoState extends State { TextButton( child: const Text('CANCEL'), onPressed: () { - Navigator.of(context).pop(false); // Pops the confirmation dialog but not the page. + // Pop the confirmation dialog and indicate that the page should + // not be popped. + Navigator.of(context).pop(false); }, ), TextButton( child: const Text('DISCARD'), onPressed: () { - Navigator.of(context).pop(true); // Returning true to _onWillPop will pop again. + // Pop the confirmation dialog and indicate that the page should + // be popped, too. + Navigator.of(context).pop(true); }, ), ], ); }, - ) as Future; + ); + + if (shouldDiscard ?? false) { + // Since this is the root route, quit the app where possible by invoking + // the SystemNavigator. If this wasn't the root route, then + // Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + } } @override @@ -162,7 +174,8 @@ class FullScreenDialogDemoState extends State { ], ), body: Form( - onWillPop: _onWillPop, + canPop: !_saveNeeded && !_hasLocation && !_hasName, + onPopInvoked: _handlePopInvoked, child: Scrollbar( child: ListView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart index 5d3fee8d60f0c..c6f644ee74cd3 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/material/text_form_field_demo.dart @@ -143,10 +143,9 @@ class TextFormFieldDemoState extends State { return null; } - Future _warnUserAboutInvalidData() async { - final FormState? form = _formKey.currentState; - if (form == null || !_formWasEdited || form.validate()) { - return true; + Future _handlePopInvoked(bool didPop) async { + if (didPop) { + return; } final bool? result = await showDialog( @@ -168,7 +167,14 @@ class TextFormFieldDemoState extends State { ); }, ); - return result!; + + if (result ?? false) { + // Since this is the root route, quit the app where possible by invoking + // the SystemNavigator. If this wasn't the root route, then + // Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + } } @override @@ -185,7 +191,8 @@ class TextFormFieldDemoState extends State { child: Form( key: _formKey, autovalidateMode: _autovalidateMode, - onWillPop: _warnUserAboutInvalidData, + canPop: _formKey.currentState == null || !_formWasEdited || _formKey.currentState!.validate(), + onPopInvoked: _handlePopInvoked, child: Scrollbar( child: SingleChildScrollView( primary: true, diff --git a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart index 0391ef95bee47..de2cfa43ef714 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/shrine/expanding_bottom_sheet.dart @@ -3,7 +3,6 @@ // found in the LICENSE file. import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:scoped_model/scoped_model.dart'; import 'colors.dart'; @@ -361,14 +360,12 @@ class ExpandingBottomSheetState extends State with TickerP // Closes the cart if the cart is open, otherwise exits the app (this should // only be relevant for Android). - Future _onWillPop() async { - if (!_isOpen) { - await SystemNavigator.pop(); - return true; + void _handlePopInvoked(bool didPop) { + if (didPop) { + return; } close(); - return true; } @override @@ -378,8 +375,9 @@ class ExpandingBottomSheetState extends State with TickerP duration: const Duration(milliseconds: 225), curve: Curves.easeInOut, alignment: FractionalOffset.topLeft, - child: WillPopScope( - onWillPop: _onWillPop, + child: PopScope( + canPop: !_isOpen, + onPopInvoked: _handlePopInvoked, child: AnimatedBuilder( animation: widget.hideController, builder: _buildSlideAnimation, diff --git a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart index c661ce64486cd..4a5f01fede8de 100644 --- a/dev/integration_tests/flutter_gallery/lib/gallery/home.dart +++ b/dev/integration_tests/flutter_gallery/lib/gallery/home.dart @@ -325,14 +325,14 @@ class _GalleryHomeState extends State with SingleTickerProviderStat backgroundColor: isDark ? _kFlutterBlue : theme.primaryColor, body: SafeArea( bottom: false, - child: WillPopScope( - onWillPop: () { - // Pop the category page if Android back button is pressed. - if (_category != null) { - setState(() => _category = null); - return Future.value(false); + child: PopScope( + canPop: _category == null, + onPopInvoked: (bool didPop) { + if (didPop) { + return; } - return Future.value(true); + // Pop the category page if Android back button is pressed. + setState(() => _category = null); }, child: Backdrop( backTitle: const Text('Options'), diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart index 7af02cfe00708..981eb5d81216a 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart @@ -71,14 +71,10 @@ class _HomeState extends State with TickerProviderStateMixin { @override Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { + return NavigatorPopHandler( + onPop: () { final NavigatorState navigator = navigatorKeys[selectedIndex].currentState!; - if (!navigator.canPop()) { - return true; - } navigator.pop(); - return false; }, child: Scaffold( body: SafeArea( diff --git a/examples/api/lib/widgets/form/form.1.dart b/examples/api/lib/widgets/form/form.1.dart new file mode 100644 index 0000000000000..b5e8b6e09ca1f --- /dev/null +++ b/examples/api/lib/widgets/form/form.1.dart @@ -0,0 +1,166 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +/// This sample demonstrates showing a confirmation dialog when the user +/// attempts to navigate away from a page with unsaved [Form] data. + +void main() => runApp(const FormApp()); + +class FormApp extends StatelessWidget { + const FormApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Confirmation Dialog Example'), + ), + body: Center( + child: _SaveableForm(), + ), + ), + ); + } +} + +class _SaveableForm extends StatefulWidget { + @override + State<_SaveableForm> createState() => _SaveableFormState(); +} + +class _SaveableFormState extends State<_SaveableForm> { + final TextEditingController _controller = TextEditingController(); + String _savedValue = ''; + bool _isDirty = false; + + @override + void initState() { + super.initState(); + _controller.addListener(_onChanged); + } + + @override + void dispose() { + _controller.removeListener(_onChanged); + super.dispose(); + } + + void _onChanged() { + final bool nextIsDirty = _savedValue != _controller.text; + if (nextIsDirty == _isDirty) { + return; + } + setState(() { + _isDirty = nextIsDirty; + }); + } + + Future _showDialog() async { + final bool? shouldDiscard = await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Are you sure?'), + content: const Text('Any unsaved changes will be lost!'), + actions: [ + TextButton( + child: const Text('Yes, discard my changes'), + onPressed: () { + Navigator.pop(context, true); + }, + ), + TextButton( + child: const Text('No, continue editing'), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ], + ); + }, + ); + + if (shouldDiscard ?? false) { + // Since this is the root route, quit the app where possible by invoking + // the SystemNavigator. If this wasn't the root route, then + // Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + } + } + + void _save(String? value) { + setState(() { + _savedValue = value ?? ''; + }); + } + + @override + Widget build(BuildContext context) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('If the field below is unsaved, a confirmation dialog will be shown on back.'), + const SizedBox(height: 20.0), + Form( + canPop: !_isDirty, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + _showDialog(); + }, + autovalidateMode: AutovalidateMode.always, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextFormField( + controller: _controller, + onFieldSubmitted: (String? value) { + _save(value); + }, + ), + TextButton( + onPressed: () { + _save(_controller.text); + }, + child: Row( + children: [ + const Text('Save'), + if (_controller.text.isNotEmpty) + Icon( + _isDirty ? Icons.warning : Icons.check, + ), + ], + ), + ), + ], + ), + ), + TextButton( + onPressed: () { + if (_isDirty) { + _showDialog(); + return; + } + // Since this is the root route, quit the app where possible by + // invoking the SystemNavigator. If this wasn't the root route, + // then Navigator.maybePop could be used instead. + // See https://github.com/flutter/flutter/issues/11490 + SystemNavigator.pop(); + }, + child: const Text('Go back'), + ), + ], + ), + ); + } +} diff --git a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart new file mode 100644 index 0000000000000..d81b74f65f714 --- /dev/null +++ b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart @@ -0,0 +1,164 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// This sample demonstrates using [NavigatorPopHandler] to handle system back +/// gestures when there are nested [Navigator] widgets by delegating to the +/// current [Navigator]. + +void main() => runApp(const NavigatorPopHandlerApp()); + +class NavigatorPopHandlerApp extends StatelessWidget { + const NavigatorPopHandlerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _HomePage(), + '/nested_navigators': (BuildContext context) => const NestedNavigatorsPage(), + }, + ); + } +} + +class _HomePage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Nested Navigators Example'), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Home Page'), + const Text('A system back gesture here will exit the app.'), + const SizedBox(height: 20.0), + ListTile( + title: const Text('Nested Navigator route'), + subtitle: const Text('This route has another Navigator widget in addition to the one inside MaterialApp above.'), + onTap: () { + Navigator.of(context).pushNamed('/nested_navigators'); + }, + ), + ], + ), + ), + ); + } +} + +class NestedNavigatorsPage extends StatefulWidget { + const NestedNavigatorsPage({super.key}); + + @override + State createState() => _NestedNavigatorsPageState(); +} + +class _NestedNavigatorsPageState extends State { + final GlobalKey _nestedNavigatorKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return NavigatorPopHandler( + onPop: () { + _nestedNavigatorKey.currentState!.maybePop(); + }, + child: Navigator( + key: _nestedNavigatorKey, + initialRoute: 'nested_navigators/one', + onGenerateRoute: (RouteSettings settings) { + switch (settings.name) { + case 'nested_navigators/one': + final BuildContext rootContext = context; + return MaterialPageRoute( + builder: (BuildContext context) => NestedNavigatorsPageOne( + onBack: () { + Navigator.of(rootContext).pop(); + }, + ), + ); + case 'nested_navigators/one/another_one': + return MaterialPageRoute( + builder: (BuildContext context) => const NestedNavigatorsPageTwo( + ), + ); + default: + throw Exception('Invalid route: ${settings.name}'); + } + }, + ), + ); + } +} + +class NestedNavigatorsPageOne extends StatelessWidget { + const NestedNavigatorsPageOne({ + required this.onBack, + super.key, + }); + + final VoidCallback onBack; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Nested Navigators Page One'), + const Text('A system back here returns to the home page.'), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('nested_navigators/one/another_one'); + }, + child: const Text('Go to another route in this nested Navigator'), + ), + TextButton( + // Can't use Navigator.of(context).pop() because this is the root + // route, so it can't be popped. The Navigator above this needs to + // be popped. + onPressed: onBack, + child: const Text('Go back'), + ), + ], + ), + ), + ); + } +} + +class NestedNavigatorsPageTwo extends StatelessWidget { + const NestedNavigatorsPageTwo({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey.withBlue(180), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Nested Navigators Page Two'), + const Text('A system back here will go back to Nested Navigators Page One'), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Go back'), + ), + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart new file mode 100644 index 0000000000000..04fbdedd34e56 --- /dev/null +++ b/examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart @@ -0,0 +1,250 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This sample demonstrates nested navigation in a bottom navigation bar. + +import 'package:flutter/material.dart'; + +// There are three possible tabs. +enum _Tab { + home, + one, + two, +} + +// Each tab has two possible pages. +enum _TabPage { + home, + one, +} + +typedef _TabPageCallback = void Function(List<_TabPage> pages); + +void main() => runApp(const NavigatorPopHandlerApp()); + +class NavigatorPopHandlerApp extends StatelessWidget { + const NavigatorPopHandlerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + initialRoute: '/home', + routes: { + '/home': (BuildContext context) => const _BottomNavPage( + ), + }, + ); + } +} + +class _BottomNavPage extends StatefulWidget { + const _BottomNavPage(); + + @override + State<_BottomNavPage> createState() => _BottomNavPageState(); +} + +class _BottomNavPageState extends State<_BottomNavPage> { + _Tab _tab = _Tab.home; + + final GlobalKey _tabHomeKey = GlobalKey(); + final GlobalKey _tabOneKey = GlobalKey(); + final GlobalKey _tabTwoKey = GlobalKey(); + + List<_TabPage> _tabHomePages = <_TabPage>[_TabPage.home]; + List<_TabPage> _tabOnePages = <_TabPage>[_TabPage.home]; + List<_TabPage> _tabTwoPages = <_TabPage>[_TabPage.home]; + + BottomNavigationBarItem _itemForPage(_Tab page) { + switch (page) { + case _Tab.home: + return const BottomNavigationBarItem( + icon: Icon(Icons.home), + label: 'Go to Home', + ); + case _Tab.one: + return const BottomNavigationBarItem( + icon: Icon(Icons.one_k), + label: 'Go to One', + ); + case _Tab.two: + return const BottomNavigationBarItem( + icon: Icon(Icons.two_k), + label: 'Go to Two', + ); + } + } + + Widget _getPage(_Tab page) { + switch (page) { + case _Tab.home: + return _BottomNavTab( + key: _tabHomeKey, + title: 'Home Tab', + color: Colors.grey, + pages: _tabHomePages, + onChangedPages: (List<_TabPage> pages) { + setState(() { + _tabHomePages = pages; + }); + }, + ); + case _Tab.one: + return _BottomNavTab( + key: _tabOneKey, + title: 'Tab One', + color: Colors.amber, + pages: _tabOnePages, + onChangedPages: (List<_TabPage> pages) { + setState(() { + _tabOnePages = pages; + }); + }, + ); + case _Tab.two: + return _BottomNavTab( + key: _tabTwoKey, + title: 'Tab Two', + color: Colors.blueGrey, + pages: _tabTwoPages, + onChangedPages: (List<_TabPage> pages) { + setState(() { + _tabTwoPages = pages; + }); + }, + ); + } + } + + void _onItemTapped(int index) { + setState(() { + _tab = _Tab.values.elementAt(index); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: _getPage(_tab), + ), + bottomNavigationBar: BottomNavigationBar( + items: _Tab.values.map(_itemForPage).toList(), + currentIndex: _Tab.values.indexOf(_tab), + selectedItemColor: Colors.amber[800], + onTap: _onItemTapped, + ), + ); + } +} + +class _BottomNavTab extends StatefulWidget { + const _BottomNavTab({ + super.key, + required this.color, + required this.onChangedPages, + required this.pages, + required this.title, + }); + + final Color color; + final _TabPageCallback onChangedPages; + final List<_TabPage> pages; + final String title; + + @override + State<_BottomNavTab> createState() => _BottomNavTabState(); +} + +class _BottomNavTabState extends State<_BottomNavTab> { + final GlobalKey _navigatorKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return NavigatorPopHandler( + onPop: () { + _navigatorKey.currentState?.maybePop(); + }, + child: Navigator( + key: _navigatorKey, + onPopPage: (Route route, void result) { + if (!route.didPop(null)) { + return false; + } + widget.onChangedPages(<_TabPage>[ + ...widget.pages, + ]..removeLast()); + return true; + }, + pages: widget.pages.map((_TabPage page) { + switch (page) { + case _TabPage.home: + return MaterialPage( + child: _LinksPage( + title: 'Bottom nav - tab ${widget.title} - route $page', + backgroundColor: widget.color, + buttons: [ + TextButton( + onPressed: () { + widget.onChangedPages(<_TabPage>[ + ...widget.pages, + _TabPage.one, + ]); + }, + child: const Text('Go to another route in this nested Navigator'), + ), + ], + ), + ); + case _TabPage.one: + return MaterialPage( + child: _LinksPage( + backgroundColor: widget.color, + title: 'Bottom nav - tab ${widget.title} - route $page', + buttons: [ + TextButton( + onPressed: () { + widget.onChangedPages(<_TabPage>[ + ...widget.pages, + ]..removeLast()); + }, + child: const Text('Go back'), + ), + ], + ), + ); + } + }).toList(), + ), + ); + } +} + +class _LinksPage extends StatelessWidget { + const _LinksPage ({ + required this.backgroundColor, + this.buttons = const [], + required this.title, + }); + + final Color backgroundColor; + final List buttons; + final String title; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: backgroundColor, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(title), + ...buttons, + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/pop_scope/pop_scope.0.dart b/examples/api/lib/widgets/pop_scope/pop_scope.0.dart new file mode 100644 index 0000000000000..6d144bd088de1 --- /dev/null +++ b/examples/api/lib/widgets/pop_scope/pop_scope.0.dart @@ -0,0 +1,128 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This sample demonstrates showing a confirmation dialog before navigating +// away from a page. + +import 'package:flutter/material.dart'; + +void main() => runApp(const NavigatorPopHandlerApp()); + +class NavigatorPopHandlerApp extends StatelessWidget { + const NavigatorPopHandlerApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + initialRoute: '/home', + routes: { + '/home': (BuildContext context) => const _HomePage(), + '/two': (BuildContext context) => const _PageTwo(), + }, + ); + } +} + +class _HomePage extends StatefulWidget { + const _HomePage(); + + @override + State<_HomePage> createState() => _HomePageState(); +} + +class _HomePageState extends State<_HomePage> { + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Page One'), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/two'); + }, + child: const Text('Next page'), + ), + ], + ), + ), + ); + } +} + +class _PageTwo extends StatefulWidget { + const _PageTwo(); + + @override + State<_PageTwo> createState() => _PageTwoState(); +} + +class _PageTwoState extends State<_PageTwo> { + void _showBackDialog() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('Are you sure?'), + content: const Text( + 'Are you sure you want to leave this page?', + ), + actions: [ + TextButton( + style: TextButton.styleFrom( + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: const Text('Nevermind'), + onPressed: () { + Navigator.pop(context); + }, + ), + TextButton( + style: TextButton.styleFrom( + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: const Text('Leave'), + onPressed: () { + Navigator.pop(context); + Navigator.pop(context); + }, + ), + ], + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Page Two'), + PopScope( + canPop: false, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + _showBackDialog(); + }, + child: TextButton( + onPressed: () { + _showBackDialog(); + }, + child: const Text('Go back'), + ), + ), + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart b/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart deleted file mode 100644 index 46dafa57b98ce..0000000000000 --- a/examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -/// Flutter code sample for [WillPopScope]. - -void main() => runApp(const WillPopScopeExampleApp()); - -class WillPopScopeExampleApp extends StatelessWidget { - const WillPopScopeExampleApp({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - home: WillPopScopeExample(), - ); - } -} - -class WillPopScopeExample extends StatefulWidget { - const WillPopScopeExample({super.key}); - - @override - State createState() => _WillPopScopeExampleState(); -} - -class _WillPopScopeExampleState extends State { - bool shouldPop = true; - @override - Widget build(BuildContext context) { - return WillPopScope( - onWillPop: () async { - return shouldPop; - }, - child: Scaffold( - appBar: AppBar( - title: const Text('Flutter WillPopScope demo'), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - OutlinedButton( - child: const Text('Push'), - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (BuildContext context) { - return const WillPopScopeExample(); - }, - ), - ); - }, - ), - OutlinedButton( - child: Text('shouldPop: $shouldPop'), - onPressed: () { - setState( - () { - shouldPop = !shouldPop; - }, - ); - }, - ), - const Text('Push to a new screen, then tap on shouldPop ' - 'button to toggle its value. Press the back ' - 'button in the appBar to check its behavior ' - 'for different values of shouldPop'), - ], - ), - ), - ), - ); - } -} diff --git a/examples/api/test/widgets/form/form.1_test.dart b/examples/api/test/widgets/form/form.1_test.dart new file mode 100644 index 0000000000000..f9ccd71d521e8 --- /dev/null +++ b/examples/api/test/widgets/form/form.1_test.dart @@ -0,0 +1,37 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/form/form.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Can go back when form is clean', (WidgetTester tester) async { + await tester.pumpWidget( + const example.FormApp(), + ); + + expect(find.text('Are you sure?'), findsNothing); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Are you sure?'), findsNothing); + }); + + testWidgets('Cannot go back when form is dirty', (WidgetTester tester) async { + await tester.pumpWidget( + const example.FormApp(), + ); + + expect(find.text('Are you sure?'), findsNothing); + + await tester.enterText(find.byType(TextFormField), 'some new text'); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Are you sure?'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart new file mode 100644 index 0000000000000..88f29223f60a4 --- /dev/null +++ b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.0_test.dart @@ -0,0 +1,48 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/navigator_pop_handler/navigator_pop_handler.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +import '../navigator_utils.dart'; + +void main() { + testWidgets('Can go back with system back gesture', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Nested Navigators Example'), findsOneWidget); + expect(find.text('Nested Navigators Page One'), findsNothing); + expect(find.text('Nested Navigators Page Two'), findsNothing); + + await tester.tap(find.text('Nested Navigator route')); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsNothing); + expect(find.text('Nested Navigators Page One'), findsOneWidget); + expect(find.text('Nested Navigators Page Two'), findsNothing); + + await tester.tap(find.text('Go to another route in this nested Navigator')); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsNothing); + expect(find.text('Nested Navigators Page One'), findsNothing); + expect(find.text('Nested Navigators Page Two'), findsOneWidget); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsNothing); + expect(find.text('Nested Navigators Page One'), findsOneWidget); + expect(find.text('Nested Navigators Page Two'), findsNothing); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested Navigators Example'), findsOneWidget); + expect(find.text('Nested Navigators Page One'), findsNothing); + expect(find.text('Nested Navigators Page Two'), findsNothing); + }); +} diff --git a/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart new file mode 100644 index 0000000000000..a6ea0ac82806f --- /dev/null +++ b/examples/api/test/widgets/navigator_pop_handler/navigator_pop_handler.1_test.dart @@ -0,0 +1,38 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/navigator_pop_handler/navigator_pop_handler.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +import '../navigator_utils.dart'; + +void main() { + testWidgets("System back gesture operates on current tab's nested Navigator", (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.home'), findsOneWidget); + + // Go to the next route in this tab. + await tester.tap(find.text('Go to another route in this nested Navigator')); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.one'), findsOneWidget); + + // Go to another tab. + await tester.tap(find.text('Go to One')); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Tab One - route _TabPage.home'), findsOneWidget); + + // Return to the home tab. The navigation state is preserved. + await tester.tap(find.text('Go to Home')); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.one'), findsOneWidget); + + // A back pops the navigation stack of the current tab's nested Navigator. + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Bottom nav - tab Home Tab - route _TabPage.home'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/navigator_utils.dart b/examples/api/test/widgets/navigator_utils.dart new file mode 100644 index 0000000000000..46f1f9b1ac469 --- /dev/null +++ b/examples/api/test/widgets/navigator_utils.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Simulates a system back, like a back gesture on Android. +/// +/// Sends the same platform channel message that the engine sends when it +/// receives a system back. +Future simulateSystemBack() { + return TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + 'flutter/navigation', + const JSONMessageCodec().encodeMessage({ + 'method': 'popRoute', + }), + (ByteData? _) {}, + ); +} diff --git a/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart b/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart new file mode 100644 index 0000000000000..ac334fc3222f2 --- /dev/null +++ b/examples/api/test/widgets/pop_scope/pop_scope.0_test.dart @@ -0,0 +1,66 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_api_samples/widgets/pop_scope/pop_scope.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +import '../navigator_utils.dart'; + +void main() { + testWidgets('Can choose to stay on page', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Page One'), findsOneWidget); + expect(find.text('Page Two'), findsNothing); + expect(find.text('Are you sure?'), findsNothing); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsNothing); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsOneWidget); + + await tester.tap(find.text('Nevermind')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsNothing); + }); + + testWidgets('Can choose to go back', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigatorPopHandlerApp(), + ); + + expect(find.text('Page One'), findsOneWidget); + expect(find.text('Page Two'), findsNothing); + expect(find.text('Are you sure?'), findsNothing); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsNothing); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsNothing); + expect(find.text('Page Two'), findsOneWidget); + expect(find.text('Are you sure?'), findsOneWidget); + + await tester.tap(find.text('Leave')); + await tester.pumpAndSettle(); + expect(find.text('Page One'), findsOneWidget); + expect(find.text('Page Two'), findsNothing); + expect(find.text('Are you sure?'), findsNothing); + }); +} diff --git a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart b/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart deleted file mode 100644 index ad05943108708..0000000000000 --- a/examples/api/test/widgets/will_pop_scope/will_pop_scope.0_test.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter_api_samples/widgets/will_pop_scope/will_pop_scope.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('pressing shouldPop button changes shouldPop', (WidgetTester tester) async { - await tester.pumpWidget( - const example.WillPopScopeExampleApp(), - ); - - final Finder buttonFinder = find.text('shouldPop: true'); - expect(buttonFinder, findsOneWidget); - await tester.tap(buttonFinder); - await tester.pump(); - expect(find.text('shouldPop: false'), findsOneWidget); - }); - testWidgets('pressing Push button pushes route', (WidgetTester tester) async { - await tester.pumpWidget( - const example.WillPopScopeExampleApp(), - ); - - final Finder buttonFinder = find.text('Push'); - expect(buttonFinder, findsOneWidget); - expect(find.byType(example.WillPopScopeExample), findsOneWidget); - await tester.tap(buttonFinder); - await tester.pumpAndSettle(); - expect(find.byType(example.WillPopScopeExample, skipOffstage: false), findsNWidgets(2)); - }); -} diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index 47e45b198b0b9..43f92f56943a1 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -157,6 +157,7 @@ class CupertinoApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, + this.onNavigationNotification, List this.navigatorObservers = const [], this.builder, this.title = '', @@ -202,6 +203,7 @@ class CupertinoApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, + this.onNavigationNotification, this.color, this.locale, this.localizationsDelegates, @@ -268,6 +270,9 @@ class CupertinoApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} final RouteFactory? onUnknownRoute; + /// {@macro flutter.widgets.widgetsApp.onNavigationNotification} + final NotificationListenerCallback? onNavigationNotification; + /// {@macro flutter.widgets.widgetsApp.navigatorObservers} final List? navigatorObservers; @@ -573,6 +578,7 @@ class _CupertinoAppState extends State { onGenerateRoute: widget.onGenerateRoute, onGenerateInitialRoutes: widget.onGenerateInitialRoutes, onUnknownRoute: widget.onUnknownRoute, + onNavigationNotification: widget.onNavigationNotification, builder: widget.builder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index f922eaf33e946..211578214871d 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -196,7 +196,8 @@ mixin CupertinoRouteTransitionMixin on PageRoute { } // If attempts to dismiss this route might be vetoed such as in a page // with forms, then do not allow the user to dismiss the route with a swipe. - if (route.hasScopedWillPopCallback) { + if (route.hasScopedWillPopCallback + || route.popDisposition == RoutePopDisposition.doNotPop) { return false; } // Fullscreen dialogs aren't dismissible by back swipe. diff --git a/packages/flutter/lib/src/cupertino/tab_view.dart b/packages/flutter/lib/src/cupertino/tab_view.dart index 8728196eee9b8..f41d0a4a3175d 100644 --- a/packages/flutter/lib/src/cupertino/tab_view.dart +++ b/packages/flutter/lib/src/cupertino/tab_view.dart @@ -162,15 +162,39 @@ class _CupertinoTabViewState extends State { ..add(_heroController); } + GlobalKey? _ownedNavigatorKey; + GlobalKey get _navigatorKey { + if (widget.navigatorKey != null) { + return widget.navigatorKey!; + } + _ownedNavigatorKey ??= GlobalKey(); + return _ownedNavigatorKey!; + } + + // Whether this tab is currently the active tab. + bool get _isActive => TickerMode.of(context); + @override Widget build(BuildContext context) { - return Navigator( - key: widget.navigatorKey, + final Widget child = Navigator( + key: _navigatorKey, onGenerateRoute: _onGenerateRoute, onUnknownRoute: _onUnknownRoute, observers: _navigatorObservers, restorationScopeId: widget.restorationScopeId, ); + + // Handle system back gestures only if the tab is currently active. + return NavigatorPopHandler( + enabled: _isActive, + onPop: () { + if (!_isActive) { + return; + } + _navigatorKey.currentState!.pop(); + }, + child: child, + ); } Route? _onGenerateRoute(RouteSettings settings) { diff --git a/packages/flutter/lib/src/material/about.dart b/packages/flutter/lib/src/material/about.dart index 44d4e7b1cf4f8..76462c8c6033f 100644 --- a/packages/flutter/lib/src/material/about.dart +++ b/packages/flutter/lib/src/material/about.dart @@ -1179,9 +1179,10 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp _builtLayout = _LayoutMode.nested; final MaterialPageRoute masterPageRoute = _masterPageRoute(context); - return WillPopScope( - // Push pop check into nested navigator. - onWillPop: () async => !(await _navigatorKey.currentState!.maybePop()), + return NavigatorPopHandler( + onPop: () { + _navigatorKey.currentState!.maybePop(); + }, child: Navigator( key: _navigatorKey, initialRoute: 'initial', @@ -1234,12 +1235,10 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp MaterialPageRoute _detailPageRoute(Object? arguments) { return MaterialPageRoute(builder: (BuildContext context) { - return WillPopScope( - onWillPop: () async { + return PopScope( + onPopInvoked: (bool didPop) { // No need for setState() as rebuild happens on navigation pop. focus = _Focus.master; - Navigator.of(context).pop(); - return false; }, child: BlockSemantics(child: widget.detailPageBuilder(context, arguments, null)), ); diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index 2438c45828989..b3ef34adf659e 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -214,6 +214,7 @@ class MaterialApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, + this.onNavigationNotification, List this.navigatorObservers = const [], this.builder, this.title = '', @@ -267,6 +268,7 @@ class MaterialApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, + this.onNavigationNotification, this.color, this.theme, this.darkTheme, @@ -343,6 +345,9 @@ class MaterialApp extends StatefulWidget { /// {@macro flutter.widgets.widgetsApp.onUnknownRoute} final RouteFactory? onUnknownRoute; + /// {@macro flutter.widgets.widgetsApp.onNavigationNotification} + final NotificationListenerCallback? onNavigationNotification; + /// {@macro flutter.widgets.widgetsApp.navigatorObservers} final List? navigatorObservers; @@ -1019,6 +1024,7 @@ class _MaterialAppState extends State { onGenerateRoute: widget.onGenerateRoute, onGenerateInitialRoutes: widget.onGenerateInitialRoutes, onUnknownRoute: widget.onUnknownRoute, + onNavigationNotification: widget.onNavigationNotification, builder: _materialBuilder, title: widget.title, onGenerateTitle: widget.onGenerateTitle, diff --git a/packages/flutter/lib/src/services/system_navigator.dart b/packages/flutter/lib/src/services/system_navigator.dart index 9edff64b3cdf8..1ea16f921ac91 100644 --- a/packages/flutter/lib/src/services/system_navigator.dart +++ b/packages/flutter/lib/src/services/system_navigator.dart @@ -2,10 +2,44 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; + import 'system_channels.dart'; /// Controls specific aspects of the system navigation stack. abstract final class SystemNavigator { + /// Informs the platform of whether or not the Flutter framework will handle + /// back events. + /// + /// Currently, this is used only on Android to inform its use of the + /// predictive back gesture when exiting the app. When true, predictive back + /// is disabled. + /// + /// See also: + /// + /// * The + /// [migration guide](https://developer.android.com/guide/navigation/predictive-back-gesture) + /// for predictive back in native Android apps. + static Future setFrameworkHandlesBack(bool frameworkHandlesBack) async { + // Currently, this method call is only relevant on Android. + if (kIsWeb) { + return; + } + switch (defaultTargetPlatform) { + case TargetPlatform.iOS: + case TargetPlatform.macOS: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return; + case TargetPlatform.android: + return SystemChannels.platform.invokeMethod( + 'SystemNavigator.setFrameworkHandlesBack', + frameworkHandlesBack, + ); + } + } + /// Removes the topmost Flutter instance, presenting what was before /// it. /// diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index af5d404c43033..f8dc851ab00e5 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -19,6 +19,7 @@ import 'framework.dart'; import 'localizations.dart'; import 'media_query.dart'; import 'navigator.dart'; +import 'notification_listener.dart'; import 'pages.dart'; import 'performance_overlay.dart'; import 'restoration.dart'; @@ -313,6 +314,7 @@ class WidgetsApp extends StatefulWidget { this.onGenerateRoute, this.onGenerateInitialRoutes, this.onUnknownRoute, + this.onNavigationNotification, List this.navigatorObservers = const [], this.initialRoute, this.pageRouteBuilder, @@ -420,6 +422,7 @@ class WidgetsApp extends StatefulWidget { this.builder, this.title = '', this.onGenerateTitle, + this.onNavigationNotification, this.textStyle, required this.color, this.locale, @@ -701,6 +704,13 @@ class WidgetsApp extends StatefulWidget { /// {@endtemplate} final RouteFactory? onUnknownRoute; + /// {@template flutter.widgets.widgetsApp.onNavigationNotification} + /// The callback to use when receiving a [NavigationNotification]. + /// + /// By default this updates the engine with the navigation status. + /// {@endtemplate} + final NotificationListenerCallback? onNavigationNotification; + /// {@template flutter.widgets.widgetsApp.initialRoute} /// The name of the first route to show, if a [Navigator] is built. /// @@ -1328,6 +1338,28 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { ? WidgetsBinding.instance.platformDispatcher.defaultRouteName : widget.initialRoute ?? WidgetsBinding.instance.platformDispatcher.defaultRouteName; + AppLifecycleState? _appLifecycleState; + + /// The default value for [onNavigationNotification]. + /// + /// Does nothing and stops bubbling if the app is detached. Otherwise, updates + /// the platform with [NavigationNotification.canHandlePop] and stops + /// bubbling. + bool _defaultOnNavigationNotification(NavigationNotification notification) { + // Don't do anything with navigation notifications if there is no engine + // attached. + if (_appLifecycleState != AppLifecycleState.detached) { + SystemNavigator.setFrameworkHandlesBack(notification.canHandlePop); + } + return true; + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + _appLifecycleState = state; + super.didChangeAppLifecycleState(state); + } + @override void initState() { super.initState(); @@ -1751,25 +1783,28 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { return RootRestorationScope( restorationId: widget.restorationScopeId, child: SharedAppData( - child: Shortcuts( - debugLabel: '', - shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, - // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can - // fall through to the defaultShortcuts. - child: DefaultTextEditingShortcuts( - child: Actions( - actions: widget.actions ?? >{ - ...WidgetsApp.defaultActions, - ScrollIntent: Action.overridable(context: context, defaultAction: ScrollAction()), - }, - child: FocusTraversalGroup( - policy: ReadingOrderTraversalPolicy(), - child: TapRegionSurface( - child: ShortcutRegistrar( - child: Localizations( - locale: appLocale, - delegates: _localizationsDelegates.toList(), - child: title, + child: NotificationListener( + onNotification: widget.onNavigationNotification ?? _defaultOnNavigationNotification, + child: Shortcuts( + debugLabel: '', + shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, + // DefaultTextEditingShortcuts is nested inside Shortcuts so that it can + // fall through to the defaultShortcuts. + child: DefaultTextEditingShortcuts( + child: Actions( + actions: widget.actions ?? >{ + ...WidgetsApp.defaultActions, + ScrollIntent: Action.overridable(context: context, defaultAction: ScrollAction()), + }, + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: TapRegionSurface( + child: ShortcutRegistrar( + child: Localizations( + locale: appLocale, + delegates: _localizationsDelegates.toList(), + child: title, + ), ), ), ), diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index ca8347edbe485..f5d2a4fe8d59e 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -54,9 +54,8 @@ export 'dart:ui' show AppLifecycleState, Locale; /// ** See code in examples/api/lib/widgets/binding/widget_binding_observer.0.dart ** /// {@end-tool} abstract mixin class WidgetsBindingObserver { - /// Called when the system tells the app to pop the current route. - /// For example, on Android, this is called when the user presses - /// the back button. + /// Called when the system tells the app to pop the current route, such as + /// after a system back button press or back gesture. /// /// Observers are notified in registration order until one returns /// true. If none return true, the application quits. @@ -69,6 +68,8 @@ abstract mixin class WidgetsBindingObserver { /// /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. + /// + /// {@macro flutter.widgets.AndroidPredictiveBack} Future didPopRoute() => Future.value(false); /// Called when the host tells the application to push a new route onto the @@ -703,6 +704,27 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// /// This method exposes the `popRoute` notification from /// [SystemChannels.navigation]. + /// + /// {@template flutter.widgets.AndroidPredictiveBack} + /// ## Handling backs ahead of time + /// + /// Not all system backs will result in a call to this method. Some are + /// handled entirely by the system without informing the Flutter framework. + /// + /// Android API 33+ introduced a feature called predictive back, which allows + /// the user to peek behind the current app or route during a back gesture and + /// then decide to cancel or commit the back. Flutter enables or disables this + /// feature ahead of time, before a back gesture occurs, and back gestures + /// that trigger predictive back are handled entirely by the system and do not + /// trigger this method here in the framework. + /// + /// By default, the framework communicates when it would like to handle system + /// back gestures using [SystemNavigator.setFrameworkHandlesBack] in + /// [WidgetsApp]. This is done automatically based on the status of the + /// [Navigator] stack and the state of any [PopScope] widgets present. + /// Developers can manually set this by calling the method directly or by + /// using [NavigationNotification]. + /// {@endtemplate} @protected @visibleForTesting Future handlePopRoute() async { diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 0860532a78fb0..07476568a35bf 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -10,8 +10,10 @@ import 'package:flutter/rendering.dart'; import 'basic.dart'; import 'framework.dart'; import 'navigator.dart'; +import 'pop_scope.dart'; import 'restoration.dart'; import 'restoration_properties.dart'; +import 'routes.dart'; import 'will_pop_scope.dart'; // Duration for delay before announcement in IOS so that the announcement won't be interrupted. @@ -52,10 +54,17 @@ class Form extends StatefulWidget { const Form({ super.key, required this.child, + this.canPop, + this.onPopInvoked, + @Deprecated( + 'Use canPop and/or onPopInvoked instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) this.onWillPop, this.onChanged, AutovalidateMode? autovalidateMode, - }) : autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled; + }) : autovalidateMode = autovalidateMode ?? AutovalidateMode.disabled, + assert((onPopInvoked == null && canPop == null) || onWillPop == null, 'onWillPop is deprecated; use canPop and/or onPopInvoked.'); /// Returns the [FormState] of the closest [Form] widget which encloses the /// given context, or null if none is found. @@ -134,8 +143,44 @@ class Form extends StatefulWidget { /// /// * [WillPopScope], another widget that provides a way to intercept the /// back button. + @Deprecated( + 'Use canPop and/or onPopInvoked instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) final WillPopCallback? onWillPop; + /// {@macro flutter.widgets.PopScope.canPop} + /// + /// {@tool dartpad} + /// This sample demonstrates how to use this parameter to show a confirmation + /// dialog when a navigation pop would cause form data to be lost. + /// + /// ** See code in examples/api/lib/widgets/form/form.1.dart ** + /// {@end-tool} + /// + /// See also: + /// + /// * [onPopInvoked], which also comes from [PopScope] and is often used in + /// conjunction with this parameter. + /// * [PopScope.canPop], which is what [Form] delegates to internally. + final bool? canPop; + + /// {@macro flutter.widgets.navigator.onPopInvoked} + /// + /// {@tool dartpad} + /// This sample demonstrates how to use this parameter to show a confirmation + /// dialog when a navigation pop would cause form data to be lost. + /// + /// ** See code in examples/api/lib/widgets/form/form.1.dart ** + /// {@end-tool} + /// + /// See also: + /// + /// * [canPop], which also comes from [PopScope] and is often used in + /// conjunction with this parameter. + /// * [PopScope.onPopInvoked], which is what [Form] delegates to internally. + final PopInvokedCallback? onPopInvoked; + /// Called when one of the form fields changes. /// /// In addition to this callback being invoked, all the form fields themselves @@ -200,6 +245,18 @@ class FormState extends State { break; } + if (widget.canPop != null || widget.onPopInvoked != null) { + return PopScope( + canPop: widget.canPop ?? true, + onPopInvoked: widget.onPopInvoked, + child: _FormScope( + formState: this, + generation: _generation, + child: widget.child, + ), + ); + } + return WillPopScope( onWillPop: widget.onWillPop, child: _FormScope( diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 82c4090037c18..4f7041d45b6d5 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -20,6 +20,7 @@ import 'focus_scope.dart'; import 'focus_traversal.dart'; import 'framework.dart'; import 'heroes.dart'; +import 'notification_listener.dart'; import 'overlay.dart'; import 'restoration.dart'; import 'restoration_properties.dart'; @@ -67,6 +68,10 @@ typedef RoutePredicate = bool Function(Route route); /// /// Used by [Form.onWillPop], [ModalRoute.addScopedWillPopCallback], /// [ModalRoute.removeScopedWillPopCallback], and [WillPopScope]. +@Deprecated( + 'Use PopInvokedCallback instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', +) typedef WillPopCallback = Future Function(); /// Signature for the [Navigator.onPopPage] callback. @@ -89,19 +94,21 @@ typedef PopPageCallback = bool Function(Route route, dynamic result); enum RoutePopDisposition { /// Pop the route. /// - /// If [Route.willPop] returns [pop] then the back button will actually pop - /// the current route. + /// If [Route.willPop] or [Route.popDisposition] return [pop] then the back + /// button will actually pop the current route. pop, /// Do not pop the route. /// - /// If [Route.willPop] returns [doNotPop] then the back button will be ignored. + /// If [Route.willPop] or [Route.popDisposition] return [doNotPop] then the + /// back button will be ignored. doNotPop, /// Delegate this to the next level of navigation. /// - /// If [Route.willPop] returns [bubble] then the back button will be handled - /// by the [SystemNavigator], which will usually close the application. + /// If [Route.willPop] or [Route.popDisposition] return [bubble] then the back + /// button will be handled by the [SystemNavigator], which will usually close + /// the application. bubble, } @@ -294,10 +301,51 @@ abstract class Route { /// mechanism. /// * [WillPopScope], another widget that provides a way to intercept the /// back button. + @Deprecated( + 'Use popDisposition instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) Future willPop() async { return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop; } + /// Returns whether calling [Navigator.maybePop] when this [Route] is current + /// ([isCurrent]) should do anything. + /// + /// [Navigator.maybePop] is usually used instead of [Navigator.pop] to handle + /// the system back button, when it hasn't been disabled via + /// [SystemNavigator.setFrameworkHandlesBack]. + /// + /// By default, if a [Route] is the first route in the history (i.e., if + /// [isFirst]), it reports that pops should be bubbled + /// ([RoutePopDisposition.bubble]). This behavior prevents the user from + /// popping the first route off the history and being stranded at a blank + /// screen; instead, the larger scope is popped (e.g. the application quits, + /// so that the user returns to the previous application). + /// + /// In other cases, the default behavior is to accept the pop + /// ([RoutePopDisposition.pop]). + /// + /// The third possible value is [RoutePopDisposition.doNotPop], which causes + /// the pop request to be ignored entirely. + /// + /// See also: + /// + /// * [Form], which provides a [Form.canPop] boolean that is similar. + /// * [PopScope], a widget that provides a way to intercept the back button. + RoutePopDisposition get popDisposition { + return isFirst ? RoutePopDisposition.bubble : RoutePopDisposition.pop; + } + + /// {@template flutter.widgets.navigator.onPopInvoked} + /// Called after a route pop was handled. + /// + /// Even when the pop is canceled, for example by a [PopScope] widget, this + /// will still be called. The `didPop` parameter indicates whether or not the + /// back navigation actually happened successfully. + /// {@endtemplate} + void onPopInvoked(bool didPop) {} + /// Whether calling [didPop] would return false. bool get willHandlePopInternally => false; @@ -2415,6 +2463,9 @@ class Navigator extends StatefulWidget { /// the initial route. /// /// If there is no [Navigator] in scope, returns false. + /// + /// Does not consider anything that might externally prevent popping, such as + /// [PopEntry]. /// {@endtemplate} /// /// See also: @@ -2426,21 +2477,22 @@ class Navigator extends StatefulWidget { return navigator != null && navigator.canPop(); } - /// Consults the current route's [Route.willPop] method, and acts accordingly, - /// potentially popping the route as a result; returns whether the pop request - /// should be considered handled. + /// Consults the current route's [Route.popDisposition] getter or + /// [Route.willPop] method, and acts accordingly, potentially popping the + /// route as a result; returns whether the pop request should be considered + /// handled. /// /// {@template flutter.widgets.navigator.maybePop} - /// If [Route.willPop] returns [RoutePopDisposition.pop], then the [pop] + /// If the [RoutePopDisposition] is [RoutePopDisposition.pop], then the [pop] /// method is called, and this method returns true, indicating that it handled /// the pop request. /// - /// If [Route.willPop] returns [RoutePopDisposition.doNotPop], then this + /// If the [RoutePopDisposition] is [RoutePopDisposition.doNotPop], then this /// method returns true, but does not do anything beyond that. /// - /// If [Route.willPop] returns [RoutePopDisposition.bubble], then this method - /// returns false, and the caller is responsible for sending the request to - /// the containing scope (e.g. by closing the application). + /// If the [RoutePopDisposition] is [RoutePopDisposition.bubble], then this + /// method returns false, and the caller is responsible for sending the + /// request to the containing scope (e.g. by closing the application). /// /// This method is typically called for a user-initiated [pop]. For example on /// Android it's called by the binding for the system's back button. @@ -3015,6 +3067,7 @@ class _RouteEntry extends RouteTransitionRecord { assert(isPresent); pendingResult = result; currentState = _RouteLifecycle.pop; + route.onPopInvoked(true); } bool _reportRemovalToObserver = true; @@ -3295,12 +3348,78 @@ class _NavigatorReplaceObservation extends _NavigatorObservation { } } +typedef _IndexWhereCallback = bool Function(_RouteEntry element); + +/// A collection of _RouteEntries representing a navigation history. +/// +/// Acts as a ChangeNotifier and notifies after its List of _RouteEntries is +/// mutated. +class _History extends Iterable<_RouteEntry> with ChangeNotifier { + final List<_RouteEntry> _value = <_RouteEntry>[]; + + int indexWhere(_IndexWhereCallback test, [int start = 0]) { + return _value.indexWhere(test, start); + } + + void add(_RouteEntry element) { + _value.add(element); + notifyListeners(); + } + + void addAll(Iterable<_RouteEntry> elements) { + _value.addAll(elements); + if (elements.isNotEmpty) { + notifyListeners(); + } + } + + void clear() { + final bool valueWasEmpty = _value.isEmpty; + _value.clear(); + if (!valueWasEmpty) { + notifyListeners(); + } + } + + void insert(int index, _RouteEntry element) { + _value.insert(index, element); + notifyListeners(); + } + + _RouteEntry removeAt(int index) { + final _RouteEntry entry = _value.removeAt(index); + notifyListeners(); + return entry; + } + + _RouteEntry removeLast() { + final _RouteEntry entry = _value.removeLast(); + notifyListeners(); + return entry; + } + + _RouteEntry operator [](int index) { + return _value[index]; + } + + @override + Iterator<_RouteEntry> get iterator { + return _value.iterator; + } + + @override + String toString() { + return _value.toString(); + } +} + /// The state for a [Navigator] widget. /// /// A reference to this class can be obtained by calling [Navigator.of]. class NavigatorState extends State with TickerProviderStateMixin, RestorationMixin { late GlobalKey _overlayKey; - List<_RouteEntry> _history = <_RouteEntry>[]; + final _History _history = _History(); + /// A set for entries that are waiting to dispose until their subtrees are /// disposed. /// @@ -3330,12 +3449,43 @@ class NavigatorState extends State with TickerProviderStateMixin, Res late List _effectiveObservers; + bool get _usingPagesAPI => widget.pages != const >[]; + + void _handleHistoryChanged() { + final bool navigatorCanPop = canPop(); + late final bool routeBlocksPop; + if (!navigatorCanPop) { + final _RouteEntry? lastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate); + routeBlocksPop = lastEntry != null + && lastEntry.route.popDisposition == RoutePopDisposition.doNotPop; + } else { + routeBlocksPop = false; + } + final NavigationNotification notification = NavigationNotification( + canHandlePop: navigatorCanPop || routeBlocksPop, + ); + // Avoid dispatching a notification in the middle of a build. + switch (SchedulerBinding.instance.schedulerPhase) { + case SchedulerPhase.postFrameCallbacks: + notification.dispatch(context); + case SchedulerPhase.idle: + case SchedulerPhase.midFrameMicrotasks: + case SchedulerPhase.persistentCallbacks: + case SchedulerPhase.transientCallbacks: + SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { + if (!mounted) { + return; + } + notification.dispatch(context); + }); + } + } + @override void initState() { super.initState(); assert(() { - if (widget.pages != const >[]) { - // This navigator uses page API. + if (_usingPagesAPI) { if (widget.pages.isEmpty) { FlutterError.reportError( FlutterErrorDetails( @@ -3378,6 +3528,8 @@ class NavigatorState extends State with TickerProviderStateMixin, Res if (widget.reportsRouteUpdateToEngine) { SystemNavigator.selectSingleEntryHistory(); } + + _history.addListener(_handleHistoryChanged); } // Use [_nextPagelessRestorationScopeId] to get the next id. @@ -3560,7 +3712,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res void didUpdateWidget(Navigator oldWidget) { super.didUpdateWidget(oldWidget); assert(() { - if (widget.pages != const >[]) { + if (_usingPagesAPI) { // This navigator uses page API. if (widget.pages.isEmpty) { FlutterError.reportError( @@ -3672,6 +3824,8 @@ class NavigatorState extends State with TickerProviderStateMixin, Res _rawNextPagelessRestorationScopeId.dispose(); _serializableHistory.dispose(); userGestureInProgressNotifier.dispose(); + _history.removeListener(_handleHistoryChanged); + _history.dispose(); super.dispose(); // don't unlock, so that the object becomes unusable assert(_debugLocked); @@ -3957,7 +4111,7 @@ class NavigatorState extends State with TickerProviderStateMixin, Res pageRouteToPagelessRoutes: pageRouteToPagelessRoutes, ).cast<_RouteEntry>(); } - _history = <_RouteEntry>[]; + _history.clear(); // Adds the leading pageless routes if there is any. if (pageRouteToPagelessRoutes.containsKey(null)) { _history.addAll(pageRouteToPagelessRoutes[null]!); @@ -4973,17 +5127,17 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return true; // there's at least two routes, so we can pop } - /// Consults the current route's [Route.willPop] method, and acts accordingly, - /// potentially popping the route as a result; returns whether the pop request - /// should be considered handled. + /// Consults the current route's [Route.popDisposition] method, and acts + /// accordingly, potentially popping the route as a result; returns whether + /// the pop request should be considered handled. /// /// {@macro flutter.widgets.navigator.maybePop} /// /// See also: /// - /// * [Form], which provides an `onWillPop` callback that enables the form - /// to veto a [pop] initiated by the app's back button. - /// * [ModalRoute], which provides a `scopedWillPopCallback` that can be used + /// * [Form], which provides a [Form.canPop] boolean that enables the + /// form to prevent any [pop]s initiated by the app's back button. + /// * [ModalRoute], which provides a `scopedOnPopCallback` that can be used /// to define the route's `willPop` method. @optionalTypeArgs Future maybePop([ T? result ]) async { @@ -4992,23 +5146,31 @@ class NavigatorState extends State with TickerProviderStateMixin, Res return false; } assert(lastEntry.route._navigator == this); - final RoutePopDisposition disposition = await lastEntry.route.willPop(); // this is asynchronous + + // TODO(justinmc): When the deprecated willPop method is removed, delete + // this code and use only popDisposition, below. + final RoutePopDisposition willPopDisposition = await lastEntry.route.willPop(); if (!mounted) { // Forget about this pop, we were disposed in the meantime. return true; } + if (willPopDisposition == RoutePopDisposition.doNotPop) { + return true; + } final _RouteEntry? newLastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate); if (lastEntry != newLastEntry) { // Forget about this pop, something happened to our history in the meantime. return true; } - switch (disposition) { + + switch (lastEntry.route.popDisposition) { case RoutePopDisposition.bubble: return false; case RoutePopDisposition.pop: pop(result); return true; case RoutePopDisposition.doNotPop: + lastEntry.route.onPopInvoked(false); return true; } } @@ -5298,29 +5460,46 @@ class NavigatorState extends State with TickerProviderStateMixin, Res Widget build(BuildContext context) { assert(!_debugLocked); assert(_history.isNotEmpty); + // Hides the HeroControllerScope for the widget subtree so that the other // nested navigator underneath will not pick up the hero controller above // this level. return HeroControllerScope.none( - child: Listener( - onPointerDown: _handlePointerDown, - onPointerUp: _handlePointerUpOrCancel, - onPointerCancel: _handlePointerUpOrCancel, - child: AbsorbPointer( - absorbing: false, // it's mutated directly by _cancelActivePointers above - child: FocusTraversalGroup( - policy: FocusTraversalGroup.maybeOf(context), - child: Focus( - focusNode: focusNode, - autofocus: true, - skipTraversal: true, - includeSemantics: false, - child: UnmanagedRestorationScope( - bucket: bucket, - child: Overlay( - key: _overlayKey, - clipBehavior: widget.clipBehavior, - initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], + child: NotificationListener( + onNotification: (NavigationNotification notification) { + // If the state of this Navigator does not change whether or not the + // whole framework can pop, propagate the Notification as-is. + if (notification.canHandlePop || !canPop()) { + return false; + } + // Otherwise, dispatch a new Notification with the correct canPop and + // stop the propagation of the old Notification. + const NavigationNotification nextNotification = NavigationNotification( + canHandlePop: true, + ); + nextNotification.dispatch(context); + return true; + }, + child: Listener( + onPointerDown: _handlePointerDown, + onPointerUp: _handlePointerUpOrCancel, + onPointerCancel: _handlePointerUpOrCancel, + child: AbsorbPointer( + absorbing: false, // it's mutated directly by _cancelActivePointers above + child: FocusTraversalGroup( + policy: FocusTraversalGroup.maybeOf(context), + child: Focus( + focusNode: focusNode, + autofocus: true, + skipTraversal: true, + includeSemantics: false, + child: UnmanagedRestorationScope( + bucket: bucket, + child: Overlay( + key: _overlayKey, + clipBehavior: widget.clipBehavior, + initialEntries: overlay == null ? _allRouteOverlayEntries.toList(growable: false) : const [], + ), ), ), ), @@ -5481,7 +5660,7 @@ class _HistoryProperty extends RestorableProperty>?> { // Updating. - void update(List<_RouteEntry> history) { + void update(_History history) { assert(isRegistered); final bool wasUninitialized = _pageToPagelessRoutes == null; bool needsSerialization = wasUninitialized; @@ -5804,3 +5983,26 @@ class RestorableRouteFuture extends RestorableProperty { static NavigatorState _defaultNavigatorFinder(BuildContext context) => Navigator.of(context); } + +/// A notification that a change in navigation has taken place. +/// +/// Specifically, this notification indicates that at least one of the following +/// has occurred: +/// +/// * That route stack of a [Navigator] has changed in any way. +/// * The ability to pop has changed, such as controlled by [PopScope]. +class NavigationNotification extends Notification { + /// Creates a notification that some change in navigation has happened. + const NavigationNotification({ + required this.canHandlePop, + }); + + /// Indicates that the originator of this [Notification] is capable of + /// handling a navigation pop. + final bool canHandlePop; + + @override + String toString() { + return 'NavigationNotification canHandlePop: $canHandlePop'; + } +} diff --git a/packages/flutter/lib/src/widgets/navigator_pop_handler.dart b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart new file mode 100644 index 0000000000000..203a85beded18 --- /dev/null +++ b/packages/flutter/lib/src/widgets/navigator_pop_handler.dart @@ -0,0 +1,110 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'framework.dart'; +import 'navigator.dart'; +import 'notification_listener.dart'; +import 'pop_scope.dart'; + +/// Enables the handling of system back gestures. +/// +/// Typically wraps a nested [Navigator] widget and allows it to handle system +/// back gestures in the [onPop] callback. +/// +/// {@tool dartpad} +/// This sample demonstrates how to use this widget to properly handle system +/// back gestures when using nested [Navigator]s. +/// +/// ** See code in examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This sample demonstrates how to use this widget to properly handle system +/// back gestures with a bottom navigation bar whose tabs each have their own +/// nested [Navigator]s. +/// +/// ** See code in examples/api/lib/widgets/navigator_pop_handler/navigator_pop_handler.1.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [PopScope], which allows toggling the ability of a [Navigator] to +/// handle pops. +/// * [NavigationNotification], which indicates whether a [Navigator] in a +/// subtree can handle pops. +class NavigatorPopHandler extends StatefulWidget { + /// Creates an instance of [NavigatorPopHandler]. + const NavigatorPopHandler({ + super.key, + this.onPop, + this.enabled = true, + required this.child, + }); + + /// The widget to place below this in the widget tree. + /// + /// Typically this is a [Navigator] that will handle the pop when [onPop] is + /// called. + final Widget child; + + /// Whether this widget's ability to handle system back gestures is enabled or + /// disabled. + /// + /// When false, there will be no effect on system back gestures. If provided, + /// [onPop] will still be called. + /// + /// This can be used, for example, when the nested [Navigator] is no longer + /// active but remains in the widget tree, such as in an inactive tab. + /// + /// Defaults to true. + final bool enabled; + + /// Called when a handleable pop event happens. + /// + /// For example, a pop is handleable when a [Navigator] in [child] has + /// multiple routes on its stack. It's not handleable when it has only a + /// single route, and so [onPop] will not be called. + /// + /// Typically this is used to pop the [Navigator] in [child]. See the sample + /// code on [NavigatorPopHandler] for a full example of this. + final VoidCallback? onPop; + + @override + State createState() => _NavigatorPopHandlerState(); +} + +class _NavigatorPopHandlerState extends State { + bool _canPop = true; + + @override + Widget build(BuildContext context) { + // When the widget subtree indicates it can handle a pop, disable popping + // here, so that it can be manually handled in canPop. + return PopScope( + canPop: !widget.enabled || _canPop, + onPopInvoked: (bool didPop) { + if (didPop) { + return; + } + widget.onPop?.call(); + }, + // Listen to changes in the navigation stack in the widget subtree. + child: NotificationListener( + onNotification: (NavigationNotification notification) { + // If this subtree cannot handle pop, then set canPop to true so + // that our PopScope will allow the Navigator higher in the tree to + // handle the pop instead. + final bool nextCanPop = !notification.canHandlePop; + if (nextCanPop != _canPop) { + setState(() { + _canPop = nextCanPop; + }); + } + return false; + }, + child: widget.child, + ), + ); + } +} diff --git a/packages/flutter/lib/src/widgets/pop_scope.dart b/packages/flutter/lib/src/widgets/pop_scope.dart new file mode 100644 index 0000000000000..b47d83fcdbbd0 --- /dev/null +++ b/packages/flutter/lib/src/widgets/pop_scope.dart @@ -0,0 +1,137 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; + +import 'framework.dart'; +import 'navigator.dart'; +import 'routes.dart'; + +/// Manages system back gestures. +/// +/// The [canPop] parameter can be used to disable system back gestures. Defaults +/// to true, meaning that back gestures happen as usual. +/// +/// The [onPopInvoked] parameter reports when system back gestures occur, +/// regardless of whether or not they were successful. +/// +/// If [canPop] is false, then a system back gesture will not pop the route off +/// of the enclosing [Navigator]. [onPopInvoked] will still be called, and +/// `didPop` will be `false`. +/// +/// If [canPop] is true, then a system back gesture will cause the enclosing +/// [Navigator] to receive a pop as usual. [onPopInvoked] will be called with +/// `didPop` as `true`, unless the pop failed for reasons unrelated to +/// [PopScope], in which case it will be `false`. +/// +/// {@tool dartpad} +/// This sample demonstrates how to use this widget to handle nested navigation +/// in a bottom navigation bar. +/// +/// ** See code in examples/api/lib/widgets/pop_scope/pop_scope.0.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [NavigatorPopHandler], which is a less verbose way to handle system back +/// gestures in simple cases of nested [Navigator]s. +/// * [Form.canPop] and [Form.onPopInvoked], which can be used to handle system +/// back gestures in the case of a form with unsaved data. +/// * [ModalRoute.registerPopEntry] and [ModalRoute.unregisterPopEntry], +/// which this widget uses to integrate with Flutter's navigation system. +class PopScope extends StatefulWidget { + /// Creates a widget that registers a callback to veto attempts by the user to + /// dismiss the enclosing [ModalRoute]. + const PopScope({ + super.key, + required this.child, + this.canPop = true, + this.onPopInvoked, + }); + + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget child; + + /// {@template flutter.widgets.PopScope.onPopInvoked} + /// Called after a route pop was handled. + /// {@endtemplate} + /// + /// It's not possible to prevent the pop from happening at the time that this + /// method is called; the pop has already happened. Use [canPop] to + /// disable pops in advance. + /// + /// This will still be called even when the pop is canceled. A pop is canceled + /// when the relevant [Route.popDisposition] returns false, such as when + /// [canPop] is set to false on a [PopScope]. The `didPop` parameter + /// indicates whether or not the back navigation actually happened + /// successfully. + /// + /// See also: + /// + /// * [Route.onPopInvoked], which is similar. + final PopInvokedCallback? onPopInvoked; + + /// {@template flutter.widgets.PopScope.canPop} + /// When false, blocks the current route from being popped. + /// + /// This includes the root route, where upon popping, the Flutter app would + /// exit. + /// + /// If multiple [PopScope] widgets appear in a route's widget subtree, then + /// each and every `canPop` must be `true` in order for the route to be + /// able to pop. + /// + /// [Android's predictive back](https://developer.android.com/guide/navigation/predictive-back-gesture) + /// feature will not animate when this boolean is false. + /// {@endtemplate} + final bool canPop; + + @override + State createState() => _PopScopeState(); +} + +class _PopScopeState extends State implements PopEntry { + ModalRoute? _route; + + @override + PopInvokedCallback? get onPopInvoked => widget.onPopInvoked; + + @override + late final ValueNotifier canPopNotifier; + + @override + void initState() { + super.initState(); + canPopNotifier = ValueNotifier(widget.canPop); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final ModalRoute? nextRoute = ModalRoute.of(context); + if (nextRoute != _route) { + _route?.unregisterPopEntry(this); + _route = nextRoute; + _route?.registerPopEntry(this); + } + } + + @override + void didUpdateWidget(PopScope oldWidget) { + super.didUpdateWidget(oldWidget); + canPopNotifier.value = widget.canPop; + } + + @override + void dispose() { + _route?.unregisterPopEntry(this); + canPopNotifier.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) => widget.child; +} diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index 441486e5ed676..e54e46ab3c7b8 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -717,6 +717,10 @@ mixin LocalHistoryRoute on Route { } } + @Deprecated( + 'Use popDisposition instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) @override Future willPop() async { if (willHandlePopInternally) { @@ -725,6 +729,14 @@ mixin LocalHistoryRoute on Route { return super.willPop(); } + @override + RoutePopDisposition get popDisposition { + if (willHandlePopInternally) { + return RoutePopDisposition.pop; + } + return super.popDisposition; + } + @override bool didPop(T? result) { if (_localHistory != null && _localHistory!.isNotEmpty) { @@ -1490,6 +1502,8 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute _willPopCallbacks = []; + final Set _popEntries = {}; + /// Returns [RoutePopDisposition.doNotPop] if any of callbacks added with /// [addScopedWillPopCallback] returns either false or null. If they all /// return true, the base [Route.willPop]'s result will be returned. The @@ -1508,6 +1522,10 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute willPop() async { final _ModalScopeState? scope = _scopeKey.currentState; @@ -1520,25 +1538,43 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute { - /// ModalRoute? _route; - /// - /// // ... - /// - /// @override - /// void didChangeDependencies() { - /// super.didChangeDependencies(); - /// _route?.removeScopedWillPopCallback(askTheUserIfTheyAreSure); - /// _route = ModalRoute.of(context); - /// _route?.addScopedWillPopCallback(askTheUserIfTheyAreSure); - /// } - /// } - /// ``` - /// {@end-tool} - /// - /// {@tool snippet} - /// If you register a callback manually, be sure to remove the callback with - /// [removeScopedWillPopCallback] by the time the widget has been disposed. A - /// stateful widget can do this in its dispose method (continuing the previous - /// example): - /// - /// ```dart - /// abstract class _MyWidgetState2 extends State { - /// ModalRoute? _route; - /// - /// // ... - /// - /// @override - /// void dispose() { - /// _route?.removeScopedWillPopCallback(askTheUserIfTheyAreSure); - /// _route = null; - /// super.dispose(); - /// } - /// } - /// ``` - /// {@end-tool} - /// /// See also: /// /// * [WillPopScope], which manages the registration and unregistration @@ -1599,6 +1592,10 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute extends TransitionRoute with LocalHistoryRoute '${objectRuntimeType(this, 'ModalRoute')}($settings, animation: $_animation)'; } @@ -2212,3 +2279,33 @@ typedef RoutePageBuilder = Widget Function(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child); + +/// A callback type for informing that a navigation pop has been invoked, +/// whether or not it was handled successfully. +/// +/// Accepts a didPop boolean indicating whether or not back navigation +/// succeeded. +typedef PopInvokedCallback = void Function(bool didPop); + +/// Allows listening to and preventing pops. +/// +/// Can be registered in [ModalRoute] to listen to pops with [onPopInvoked] or +/// to enable/disable them with [canPopNotifier]. +/// +/// See also: +/// +/// * [PopScope], which provides similar functionality in a widget. +/// * [ModalRoute.registerPopEntry], which unregisters instances of this. +/// * [ModalRoute.unregisterPopEntry], which unregisters instances of this. +abstract class PopEntry { + /// {@macro flutter.widgets.PopScope.onPopInvoked} + PopInvokedCallback? get onPopInvoked; + + /// {@macro flutter.widgets.PopScope.canPop} + ValueListenable get canPopNotifier; + + @override + String toString() { + return 'PopEntry canPop: ${canPopNotifier.value}, onPopInvoked: $onPopInvoked'; + } +} diff --git a/packages/flutter/lib/src/widgets/will_pop_scope.dart b/packages/flutter/lib/src/widgets/will_pop_scope.dart index ab90c7f49de01..eefe437983375 100644 --- a/packages/flutter/lib/src/widgets/will_pop_scope.dart +++ b/packages/flutter/lib/src/widgets/will_pop_scope.dart @@ -9,26 +9,25 @@ import 'routes.dart'; /// Registers a callback to veto attempts by the user to dismiss the enclosing /// [ModalRoute]. /// -/// {@tool dartpad} -/// Whenever the back button is pressed, you will get a callback at [onWillPop], -/// which returns a [Future]. If the [Future] returns true, the screen is -/// popped. -/// -/// ** See code in examples/api/lib/widgets/will_pop_scope/will_pop_scope.0.dart ** -/// {@end-tool} -/// /// See also: /// /// * [ModalRoute.addScopedWillPopCallback] and [ModalRoute.removeScopedWillPopCallback], /// which this widget uses to register and unregister [onWillPop]. /// * [Form], which provides an `onWillPop` callback that enables the form /// to veto a `pop` initiated by the app's back button. -/// +@Deprecated( + 'Use PopScope instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', +) class WillPopScope extends StatefulWidget { /// Creates a widget that registers a callback to veto attempts by the user to /// dismiss the enclosing [ModalRoute]. /// /// The [child] argument must not be null. + @Deprecated( + 'Use PopScope instead. ' + 'This feature was deprecated after v3.12.0-1.0.pre.', + ) const WillPopScope({ super.key, required this.child, diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 539d6aac62956..3ca0999b994d0 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -81,6 +81,7 @@ export 'src/widgets/media_query.dart'; export 'src/widgets/modal_barrier.dart'; export 'src/widgets/navigation_toolbar.dart'; export 'src/widgets/navigator.dart'; +export 'src/widgets/navigator_pop_handler.dart'; export 'src/widgets/nested_scroll_view.dart'; export 'src/widgets/notification_listener.dart'; export 'src/widgets/orientation_builder.dart'; @@ -95,6 +96,7 @@ export 'src/widgets/placeholder.dart'; export 'src/widgets/platform_menu_bar.dart'; export 'src/widgets/platform_selectable_region_context_menu.dart'; export 'src/widgets/platform_view.dart'; +export 'src/widgets/pop_scope.dart'; export 'src/widgets/preferred_size.dart'; export 'src/widgets/primary_scroll_controller.dart'; export 'src/widgets/raw_keyboard_listener.dart'; diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index a8a43b510277d..b376a92ecf276 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; - import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import '../image_data.dart'; import '../rendering/rendering_tester.dart' show TestCallbackPainter; +import '../widgets/navigator_utils.dart'; late List selectedTabs; @@ -1215,6 +1216,132 @@ void main() { expect(find.text('Content 2'), findsNothing); expect(find.text('Content 3'), findsNothing); }); + + group('Android Predictive Back', () { + bool? lastFrameworkHandlesBack; + setUp(() { + // Initialize to false. Because this uses a static boolean internally, it + // is not reset between tests or calls to pumpWidget. Explicitly setting + // it to false before each test makes them behave deterministically. + SystemNavigator.setFrameworkHandlesBack(false); + lastFrameworkHandlesBack = null; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + lastFrameworkHandlesBack = methodCall.arguments as bool; + } + return; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + SystemNavigator.setFrameworkHandlesBack(true); + }); + + testWidgets('System back navigation inside of tabs', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: MediaQuery( + data: const MediaQueryData( + viewInsets: EdgeInsets.only(bottom: 200), + ), + child: CupertinoTabScaffold( + tabBar: _buildTabBar(), + tabBuilder: (BuildContext context, int index) { + return CupertinoTabView( + builder: (BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text('Page 1 of tab ${index + 1}'), + ), + child: Center( + child: CupertinoButton( + child: const Text('Next page'), + onPressed: () { + Navigator.of(context).push( + CupertinoPageRoute( + builder: (BuildContext context) { + return CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar( + middle: Text('Page 2 of tab ${index + 1}'), + ), + child: Center( + child: CupertinoButton( + child: const Text('Back'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + ); + }, + ), + ); + }, + ), + ), + ); + }, + ); + }, + ), + ), + ), + ); + + expect(find.text('Page 1 of tab 1'), findsOneWidget); + expect(find.text('Page 2 of tab 1'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsNothing); + expect(find.text('Page 2 of tab 1'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsOneWidget); + expect(find.text('Page 2 of tab 1'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Next page')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsNothing); + expect(find.text('Page 2 of tab 1'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Tab 2')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 2'), findsOneWidget); + expect(find.text('Page 2 of tab 2'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Tab 1')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsNothing); + expect(find.text('Page 2 of tab 1'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 1'), findsOneWidget); + expect(find.text('Page 2 of tab 1'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Tab 2')); + await tester.pumpAndSettle(); + expect(find.text('Page 1 of tab 2'), findsOneWidget); + expect(find.text('Page 2 of tab 2'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: kIsWeb, // [intended] frameworkHandlesBack not used on web. + ); + }); } CupertinoTabBar _buildTabBar({ int selectedTab = 0 }) { diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 26d1463639259..d403ceba9c80f 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -6,9 +6,12 @@ import 'dart:ui' show FlutterView; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'navigator_utils.dart'; import 'observer_tester.dart'; import 'semantics_tester.dart'; @@ -4153,6 +4156,719 @@ void main() { expect(const RouteSettings().toString(), 'RouteSettings(none, null)'); }); }); + + group('Android Predictive Back', () { + bool? lastFrameworkHandlesBack; + setUp(() { + // Initialize to false. Because this uses a static boolean internally, it + // is not reset between tests or calls to pumpWidget. Explicitly setting + // it to false before each test makes them behave deterministically. + SystemNavigator.setFrameworkHandlesBack(false); + lastFrameworkHandlesBack = null; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + lastFrameworkHandlesBack = methodCall.arguments as bool; + } + return; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + SystemNavigator.setFrameworkHandlesBack(true); + }); + + testWidgets('a single route is already defaulted to false', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Scaffold( + body: Text('home'), + ) + ) + ); + + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('navigating around a single Navigator with .pop', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/one/one': (BuildContext context) => const _LinksPage( + title: 'Page one - one', + ), + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to one/one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one - one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go back')); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('navigating around a single Navigator with system back', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/one/one': (BuildContext context) => const _LinksPage( + title: 'Page one - one', + ), + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to one/one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one - one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('a single Navigator with a PopScope that defaults to enabled', (WidgetTester tester) async { + bool canPop = true; + late StateSetter setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + canPop: canPop, + ), + }, + ); + }, + ), + ); + + expect(lastFrameworkHandlesBack, isFalse); + + setState(() { + canPop = false; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = true; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('a single Navigator with a PopScope that defaults to disabled', (WidgetTester tester) async { + bool canPop = false; + late StateSetter setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + canPop: canPop, + ), + }, + ); + }, + ), + ); + + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = true; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isFalse); + + setState(() { + canPop = false; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isTrue); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + // Test both system back gestures and Navigator.pop. + for (final _BackType backType in _BackType.values) { + testWidgets('navigating around nested Navigators', (WidgetTester tester) async { + final GlobalKey nav = GlobalKey(); + final GlobalKey nestedNav = GlobalKey(); + Future goBack() async { + switch (backType) { + case _BackType.systemBack: + return simulateSystemBack(); + case _BackType.navigatorPop: + if (nestedNav.currentState != null) { + if (nestedNav.currentState!.mounted && nestedNav.currentState!.canPop()) { + return nestedNav.currentState?.pop(); + } + } + return nav.currentState?.pop(); + } + } + await tester.pumpWidget( + MaterialApp( + navigatorKey: nav, + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/nested'); + }, + child: const Text('Go to nested'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/nested': (BuildContext context) => _NestedNavigatorsPage( + navigatorKey: nestedNav, + ), + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await goBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to nested')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to nested/one')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await goBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await goBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + } + + testWidgets('nested Navigators with a nested PopScope', (WidgetTester tester) async { + bool canPop = true; + late StateSetter setState; + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext context) => _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to one'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/nested'); + }, + child: const Text('Go to nested'), + ), + ], + ), + '/one': (BuildContext context) => _LinksPage( + title: 'Page one', + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one/one'); + }, + child: const Text('Go to one/one'), + ), + ], + ), + '/nested': (BuildContext context) => _NestedNavigatorsPage( + popScopePageEnabled: canPop, + ), + }, + ); + }, + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to nested')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to nested/popscope')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - PopScope'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + // Going back works because canPop is true. + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await tester.tap(find.text('Go to nested/popscope')); + await tester.pumpAndSettle(); + + expect(find.text('Nested - PopScope'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = false; + }); + await tester.pumpAndSettle(); + + expect(lastFrameworkHandlesBack, isTrue); + + // Now going back doesn't work because canPop is false, but it still + // has no effect on the system navigator due to all of the other routes. + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - PopScope'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + setState(() { + canPop = true; + }); + await tester.pump(); + + expect(lastFrameworkHandlesBack, isTrue); + + // And going back works again after switching canPop back to true. + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Nested - home'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + group('Navigator page API', () { + testWidgets('starting with one route as usual', (WidgetTester tester) async { + late StateSetter builderSetState; + final List<_Page> pages = <_Page>[_Page.home]; + bool canPop() => pages.length <= 1; + + await tester.pumpWidget( + MaterialApp( + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + builderSetState = setState; + return PopScope( + canPop: canPop(), + onPopInvoked: (bool success) { + if (success || pages.last == _Page.noPop) { + return; + } + setState(() { + pages.removeLast(); + }); + }, + child: Navigator( + onPopPage: (Route route, void result) { + if (!route.didPop(null)) { + return false; + } + setState(() { + pages.removeLast(); + }); + return true; + }, + pages: pages.map((_Page page) { + switch (page) { + case _Page.home: + return MaterialPage( + child: _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.one); + }); + }, + child: const Text('Go to _Page.one'), + ), + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.noPop); + }); + }, + child: const Text('Go to _Page.noPop'), + ), + ], + ), + ); + case _Page.one: + return const MaterialPage( + child: _LinksPage( + title: 'Page one', + ), + ); + case _Page.noPop: + return const MaterialPage( + child: _LinksPage( + title: 'Cannot pop page', + canPop: false, + ), + ); + } + }).toList(), + ), + ); + }, + ), + ), + ); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to _Page.one')); + await tester.pumpAndSettle(); + + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + + await tester.tap(find.text('Go to _Page.noPop')); + await tester.pumpAndSettle(); + + expect(find.text('Cannot pop page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Cannot pop page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + // Circumvent "Cannot pop page" by directly modifying pages. + builderSetState(() { + pages.removeLast(); + }); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + + testWidgets('starting with existing route history', (WidgetTester tester) async { + final List<_Page> pages = <_Page>[_Page.home, _Page.one]; + bool canPop() => pages.length <= 1; + + await tester.pumpWidget( + MaterialApp( + home: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return PopScope( + canPop: canPop(), + onPopInvoked: (bool success) { + if (success || pages.last == _Page.noPop) { + return; + } + setState(() { + pages.removeLast(); + }); + }, + child: Navigator( + onPopPage: (Route route, void result) { + if (!route.didPop(null)) { + return false; + } + setState(() { + pages.removeLast(); + }); + return true; + }, + pages: pages.map((_Page page) { + switch (page) { + case _Page.home: + return MaterialPage( + child: _LinksPage( + title: 'Home page', + buttons: [ + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.one); + }); + }, + child: const Text('Go to _Page.one'), + ), + TextButton( + onPressed: () { + setState(() { + pages.add(_Page.noPop); + }); + }, + child: const Text('Go to _Page.noPop'), + ), + ], + ), + ); + case _Page.one: + return const MaterialPage( + child: _LinksPage( + title: 'Page one', + ), + ); + case _Page.noPop: + return const MaterialPage( + child: _LinksPage( + title: 'Cannot pop page', + canPop: false, + ), + ); + } + }).toList(), + ), + ); + }, + ), + ), + ); + + expect(find.text('Home page'), findsNothing); + expect(find.text('Page one'), findsOneWidget); + expect(lastFrameworkHandlesBack, isTrue); + + await simulateSystemBack(); + await tester.pumpAndSettle(); + + expect(find.text('Home page'), findsOneWidget); + expect(find.text('Page one'), findsNothing); + expect(lastFrameworkHandlesBack, isFalse); + }, + variant: const TargetPlatformVariant({ TargetPlatform.android }), + skip: isBrowser, // [intended] only non-web Android supports predictive back. + ); + }); + }); } typedef AnnouncementCallBack = void Function(Route?); @@ -4435,3 +5151,153 @@ class TestDependencies extends StatelessWidget { ); } } + +enum _BackType { + systemBack, + navigatorPop, +} + +enum _Page { + home, + one, + noPop, +} + +class _LinksPage extends StatelessWidget { + const _LinksPage ({ + this.buttons = const [], + this.canPop, + required this.title, + this.onBack, + }); + + final List buttons; + final bool? canPop; + final VoidCallback? onBack; + final String title; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(title), + ...buttons, + if (Navigator.of(context).canPop()) + TextButton( + onPressed: onBack ?? () { + Navigator.of(context).pop(); + }, + child: const Text('Go back'), + ), + if (canPop != null) + PopScope( + canPop: canPop!, + child: const SizedBox.shrink(), + ), + ], + ), + ), + ); + } +} + +class _NestedNavigatorsPage extends StatefulWidget { + const _NestedNavigatorsPage({ + this.popScopePageEnabled, + this.navigatorKey, + }); + + /// Whether the PopScope on the /popscope page is enabled. + /// + /// If null, then no PopScope is built at all. + final bool? popScopePageEnabled; + + final GlobalKey? navigatorKey; + + @override + State<_NestedNavigatorsPage> createState() => _NestedNavigatorsPageState(); +} + +class _NestedNavigatorsPageState extends State<_NestedNavigatorsPage> { + late final GlobalKey _navigatorKey; + + @override + void initState() { + super.initState(); + _navigatorKey = widget.navigatorKey ?? GlobalKey(); + } + + @override + Widget build(BuildContext context) { + final BuildContext rootContext = context; + return NavigatorPopHandler( + onPop: () { + if (widget.popScopePageEnabled == false) { + return; + } + _navigatorKey.currentState!.pop(); + }, + child: Navigator( + key: _navigatorKey, + initialRoute: '/', + onGenerateRoute: (RouteSettings settings) { + switch (settings.name) { + case '/': + return MaterialPageRoute( + builder: (BuildContext context) { + return _LinksPage( + title: 'Nested - home', + onBack: () { + Navigator.of(rootContext).pop(); + }, + buttons: [ + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Go to nested/one'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/popscope'); + }, + child: const Text('Go to nested/popscope'), + ), + TextButton( + onPressed: () { + Navigator.of(rootContext).pop(); + }, + child: const Text('Go back out of nested nav'), + ), + ], + ); + }, + ); + case '/one': + return MaterialPageRoute( + builder: (BuildContext context) { + return const _LinksPage( + title: 'Nested - page one', + ); + }, + ); + case '/popscope': + return MaterialPageRoute( + builder: (BuildContext context) { + return _LinksPage( + canPop: widget.popScopePageEnabled, + title: 'Nested - PopScope', + ); + }, + ); + default: + throw Exception('Invalid route: ${settings.name}'); + } + }, + ), + ); + } +} diff --git a/packages/flutter/test/widgets/navigator_utils.dart b/packages/flutter/test/widgets/navigator_utils.dart new file mode 100644 index 0000000000000..46f1f9b1ac469 --- /dev/null +++ b/packages/flutter/test/widgets/navigator_utils.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +/// Simulates a system back, like a back gesture on Android. +/// +/// Sends the same platform channel message that the engine sends when it +/// receives a system back. +Future simulateSystemBack() { + return TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.handlePlatformMessage( + 'flutter/navigation', + const JSONMessageCodec().encodeMessage({ + 'method': 'popRoute', + }), + (ByteData? _) {}, + ); +} diff --git a/packages/flutter/test/widgets/pop_scope_test.dart b/packages/flutter/test/widgets/pop_scope_test.dart new file mode 100644 index 0000000000000..c5d0e88545034 --- /dev/null +++ b/packages/flutter/test/widgets/pop_scope_test.dart @@ -0,0 +1,361 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'navigator_utils.dart'; + +void main() { + bool? lastFrameworkHandlesBack; + setUp(() { + // Initialize to false. Because this uses a static boolean internally, it + // is not reset between tests or calls to pumpWidget. Explicitly setting + // it to false before each test makes them behave deterministically. + SystemNavigator.setFrameworkHandlesBack(false); + lastFrameworkHandlesBack = null; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + lastFrameworkHandlesBack = methodCall.arguments as bool; + } + return; + }); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + SystemNavigator.setFrameworkHandlesBack(true); + }); + + testWidgets('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { + bool canPop = false; + late StateSetter setState; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext buildContext) => Scaffold( + body: StatefulBuilder( + builder: (BuildContext buildContext, StateSetter stateSetter) { + context = buildContext; + setState = stateSetter; + return PopScope( + canPop: canPop, + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Home/PopScope Page'), + ], + ), + ), + ); + }, + ), + ), + }, + ), + ); + + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + setState(() { + canPop = true; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); + }, + variant: TargetPlatformVariant.all(), + ); + + testWidgets('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async { + final GlobalKey nav = GlobalKey(); + bool canPop = true; + late StateSetter setState; + late BuildContext homeContext; + late BuildContext oneContext; + late bool lastPopSuccess; + await tester.pumpWidget( + MaterialApp( + navigatorKey: nav, + initialRoute: '/', + routes: { + '/': (BuildContext context) { + homeContext = context; + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Home Page'), + TextButton( + onPressed: () { + Navigator.of(context).pushNamed('/one'); + }, + child: const Text('Next'), + ), + ], + ), + ), + ); + }, + '/one': (BuildContext context) => Scaffold( + body: StatefulBuilder( + builder: (BuildContext context, StateSetter stateSetter) { + oneContext = context; + setState = stateSetter; + return PopScope( + canPop: canPop, + onPopInvoked: (bool didPop) { + lastPopSuccess = didPop; + }, + child: const Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('PopScope Page'), + ], + ), + ), + ); + }, + ), + ), + }, + ), + ); + + expect(find.text('Home Page'), findsOneWidget); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + // When canPop is true, can use pop to go back. + nav.currentState!.maybePop(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + // When canPop is true, can use system back to go back. + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + setState(() { + canPop = false; + }); + await tester.pump(); + + // When canPop is false, can't use pop to go back. + nav.currentState!.maybePop(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, false); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.doNotPop); + + // When canPop is false, can't use system back to go back. + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, false); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.doNotPop); + + // Toggle canPop back to true and back works again. + setState(() { + canPop = true; + }); + await tester.pump(); + + nav.currentState!.maybePop(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + + await tester.tap(find.text('Next')); + await tester.pumpAndSettle(); + expect(find.text('PopScope Page'), findsOneWidget); + expect(find.text('Home Page'), findsNothing); + expect(ModalRoute.of(oneContext)!.popDisposition, RoutePopDisposition.pop); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + + await simulateSystemBack(); + await tester.pumpAndSettle(); + expect(lastPopSuccess, true); + expect(find.text('Home Page'), findsOneWidget); + expect(find.text('PopScope Page'), findsNothing); + expect(ModalRoute.of(homeContext)!.popDisposition, RoutePopDisposition.bubble); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + }, + variant: TargetPlatformVariant.all(), + ); + + testWidgets('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async { + bool usePopScope = true; + late StateSetter setState; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + initialRoute: '/', + routes: { + '/': (BuildContext buildContext) => Scaffold( + body: StatefulBuilder( + builder: (BuildContext buildContext, StateSetter stateSetter) { + context = buildContext; + setState = stateSetter; + const Widget child = Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Home/PopScope Page'), + ], + ), + ); + if (!usePopScope) { + return child; + } + return const PopScope( + canPop: false, + child: child, + ); + }, + ), + ), + }, + ), + ); + + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + setState(() { + usePopScope = false; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); + }, + variant: TargetPlatformVariant.all(), + ); + + testWidgets('identical PopScopes', (WidgetTester tester) async { + bool usePopScope1 = true; + bool usePopScope2 = true; + late StateSetter setState; + late BuildContext context; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: StatefulBuilder( + builder: (BuildContext buildContext, StateSetter stateSetter) { + context = buildContext; + setState = stateSetter; + return Column( + children: [ + if (usePopScope1) + const PopScope( + canPop: false, + child: Text('hello'), + ), + if (usePopScope2) + const PopScope( + canPop: false, + child: Text('hello'), + ), + ], + ); + }, + ), + ), + ), + ); + + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + // Despite being in the widget tree twice, the ModalRoute has only ever + // registered one PopScopeInterface for it. Removing one makes it think that + // both have been removed. + setState(() { + usePopScope1 = false; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isTrue); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.doNotPop); + + setState(() { + usePopScope2 = false; + }); + await tester.pump(); + if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) { + expect(lastFrameworkHandlesBack, isFalse); + } + expect(ModalRoute.of(context)!.popDisposition, RoutePopDisposition.bubble); + }, + variant: TargetPlatformVariant.all(), + ); +} From 579991cbb32d211d9551df390809117e9ad18f31 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Thu, 17 Aug 2023 17:11:57 -0700 Subject: [PATCH 0782/1547] Fix the name of the local-engine-host flag in the warning message (#132808) --- packages/flutter_tools/lib/src/base/user_messages.dart | 2 +- .../test/general.shard/runner/local_engine_test.dart | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 6ebaa13471ac1..54305b36f38d0 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -310,7 +310,7 @@ class UserMessages { 'You must specify --local-engine or --local-web-sdk if you are using a locally built engine or web sdk.'; // TODO(matanlurey): Make this an error, https://github.com/flutter/flutter/issues/132245. String runnerLocalEngineRequiresHostEngine({bool warning = false}) => - '${warning ? 'Warning! ' : ''}You are using a locally built engine (--local-engine) but have not specified --local-host-engine.\n' + '${warning ? 'Warning! ' : ''}You are using a locally built engine (--local-engine) but have not specified --local-engine-host.\n' 'You may be building with a different engine than the one you are running with. ' 'See https://github.com/flutter/flutter/issues/132245 for details (in the future this will become ' 'an error).'; diff --git a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart index b18a3633a2842..e8570fddfa0f1 100644 --- a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart @@ -119,7 +119,7 @@ void main() { expect(logger.traceText, contains('Local engine source at /arbitrary/engine/src')); }); - testWithoutContext('works but produces a warning if --local-engine is specified but not --local-host-engine', () async { + testWithoutContext('works but produces a warning if --local-engine is specified but not --local-engine-host', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final Directory localEngine = fileSystem .directory('$kArbitraryEngineRoot/src/out/android_debug_unopt_arm64/') @@ -142,7 +142,7 @@ void main() { targetEngine: '/arbitrary/engine/src/out/android_debug_unopt_arm64', ), ); - expect(logger.statusText, contains('Warning! You are using a locally built engine (--local-engine) but have not specified --local-host-engine')); + expect(logger.statusText, contains('Warning! You are using a locally built engine (--local-engine) but have not specified --local-engine-host')); }); testWithoutContext('fails if --local-engine-host is emitted and treatMissingLocalEngineHostAsFatal is set', () async { @@ -164,7 +164,7 @@ void main() { await expectLater( localEngineLocator.findEnginePath(localEngine: localEngine.path), - throwsToolExit(message: 'You are using a locally built engine (--local-engine) but have not specified --local-host-engine'), + throwsToolExit(message: 'You are using a locally built engine (--local-engine) but have not specified --local-engine-host'), ); }); From a1e3b3dae434dedcc84dcddf8bc827ce5f95e2e8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 17 Aug 2023 20:50:31 -0400 Subject: [PATCH 0783/1547] Roll Flutter Engine from 5019d6da655c to 866b43f656e4 (8 revisions) (#132812) https://github.com/flutter/engine/compare/5019d6da655c...866b43f656e4 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from 1bec2899ace8 to 1e62a2d4c429 (1 revision) (flutter/engine#44829) 2023-08-17 skia-flutter-autoroll@skia.org Roll Dart SDK from 7e4e5796ee99 to 7101eb7569ac (2 revisions) (flutter/engine#44828) 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from e4be2cab442f to 1bec2899ace8 (1 revision) (flutter/engine#44826) 2023-08-17 skia-flutter-autoroll@skia.org Roll Skia from bfd45173e5e3 to e4be2cab442f (3 revisions) (flutter/engine#44824) 2023-08-17 gspencergoog@users.noreply.github.com Add Doxygen doc generation for iOS, macOS, Linux, Windows, and Impeller (flutter/engine#43915) 2023-08-17 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from VW7WAVPT3Cj5erlae... to Tnp43n_nAR2N0l_gY... (flutter/engine#44823) 2023-08-17 jason-simmons@users.noreply.github.com Fix FlutterInjectorTest assumptions about how the executor service assigns tasks to threads (flutter/engine#44775) 2023-08-17 john@johnmccutchan.com Reenable HardwareBuffer backed Android Platform Views on SDK >= 29 (flutter/engine#44790) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from VW7WAVPT3Cj5 to Tnp43n_nAR2N If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d0d7105766e9a..6ceaf9d96897b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5019d6da655ca9dd0b1b041042c4983baa6eec39 +866b43f656e40bc755642b7f8218dbf9fde64d9b diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 96160304ec571..393fa78f4e85d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -VW7WAVPT3Cj5erlaez7LYgmKffc3Tf5FIxhG2GxzyO0C +Tnp43n_nAR2N0l_gYiE0YBpA4loAnzR2Zp_vGd3v_IMC From 03664d0acb16f29a804e6afb8c1532bbd47096fd Mon Sep 17 00:00:00 2001 From: Navaron Bracke Date: Fri, 18 Aug 2023 04:58:20 +0200 Subject: [PATCH 0784/1547] Fix description in index.html / manifest.json getting double quoted (#131842) This PR adjusts the quoting of the project description not not apply twice in the index.html / manifest.json of web builds. *List which issues are fixed by this PR. You must list at least one issue.* Fixes https://github.com/flutter/flutter/issues/131834 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/commands/create_base.dart | 2 +- packages/flutter_tools/lib/src/template.dart | 23 +++++++++++++++- .../commands.shard/permeable/create_test.dart | 26 +++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index b0de202c94baf..4f801acc9b72b 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -389,7 +389,7 @@ abstract class CreateBase extends FlutterCommand { 'macosIdentifier': appleIdentifier, 'linuxIdentifier': linuxIdentifier, 'windowsIdentifier': windowsIdentifier, - 'description': projectDescription != null ? escapeYamlString(projectDescription) : null, + 'description': projectDescription, 'dartSdk': '$flutterRoot/bin/cache/dart-sdk', 'androidMinApiLevel': android_common.minApiLevel, 'androidSdkVersion': kAndroidSdkMinVersion, diff --git a/packages/flutter_tools/lib/src/template.dart b/packages/flutter_tools/lib/src/template.dart index b86046ae94a36..a6bc9291ca42c 100644 --- a/packages/flutter_tools/lib/src/template.dart +++ b/packages/flutter_tools/lib/src/template.dart @@ -361,7 +361,13 @@ class Template { context['androidIdentifier'] = _escapeKotlinKeywords(androidIdentifier); } - final String renderedContents = _templateRenderer.renderString(templateContents, context); + // Use a copy of the context, + // since the original is used in rendering other templates. + final Map localContext = finalDestinationFile.path.endsWith('.yaml') + ? _createEscapedContextCopy(context) + : context; + + final String renderedContents = _templateRenderer.renderString(templateContents, localContext); finalDestinationFile.writeAsStringSync(renderedContents); @@ -377,6 +383,21 @@ class Template { } } +/// Create a copy of the given [context], escaping its values when necessary. +/// +/// Returns the copied context. +Map _createEscapedContextCopy(Map context) { + final Map localContext = Map.of(context); + + final String? description = localContext['description'] as String?; + + if (description != null && description.isNotEmpty) { + localContext['description'] = escapeYamlString(description); + } + + return localContext; +} + String _escapeKotlinKeywords(String androidIdentifier) { final List segments = androidIdentifier.split('.'); final List correctedSegments = segments.map( diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 4e5488513fb03..3d5c238a3a89c 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -3384,6 +3384,32 @@ void main() { FeatureFlags: () => TestFeatureFlags(), Logger: () => logger, }); + + testUsingContext('Does not double quote description in index.html on web', () async { + await _createProject( + projectDir, + ['--no-pub', '--platforms=web'], + ['pubspec.yaml', 'web/index.html'], + ); + + final String rawIndexHtml = await projectDir.childDirectory('web').childFile('index.html').readAsString(); + const String expectedDescription = ''; + + expect(rawIndexHtml.contains(expectedDescription), isTrue); + }); + + testUsingContext('Does not double quote description in manifest.json on web', () async { + await _createProject( + projectDir, + ['--no-pub', '--platforms=web'], + ['pubspec.yaml', 'web/manifest.json'], + ); + + final String rawManifestJson = await projectDir.childDirectory('web').childFile('manifest.json').readAsString(); + const String expectedDescription = '"description": "A new Flutter project."'; + + expect(rawManifestJson.contains(expectedDescription), isTrue); + }); } Future _createProject( From 633b1ce402c77fd550860002ef74ed6a35a90715 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 18 Aug 2023 00:00:25 -0400 Subject: [PATCH 0785/1547] Roll Flutter Engine from 866b43f656e4 to 58f7d8ee3e2c (1 revision) (#132820) https://github.com/flutter/engine/compare/866b43f656e4...58f7d8ee3e2c 2023-08-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 7101eb7569ac to 121fcbd8124c (1 revision) (flutter/engine#44832) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6ceaf9d96897b..fc4a4dd30f4ed 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -866b43f656e40bc755642b7f8218dbf9fde64d9b +58f7d8ee3e2cec3df2b5e7c53be3ae1f2861203d From 312ef541156c0b0c8553626678e37e551b99383a Mon Sep 17 00:00:00 2001 From: Tae Hyung Kim Date: Fri, 18 Aug 2023 15:01:09 +0000 Subject: [PATCH 0786/1547] [flutter_tools] Generate localizations on flutter pub get (#132172) Currently, flutter pub get generates localizations if there exists an l10n.yaml file where synthetic-package is not false. However, for any user who needs to turn off synthetic-package, their localizations are not generated. This PR should make the behavior more consistent. (Also it seems good to make it so that running flutter pub get once resolves all the dependencies so that people can get to work without running flutter gen-l10n manually.) Fixes https://github.com/flutter/flutter/issues/84979. --- .../lib/src/commands/packages.dart | 28 +++++++ .../permeable/packages_test.dart | 75 +++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart index 096bd72cd48bc..824077cd8c9f2 100644 --- a/packages/flutter_tools/lib/src/commands/packages.dart +++ b/packages/flutter_tools/lib/src/commands/packages.dart @@ -6,8 +6,10 @@ import 'package:args/args.dart'; import '../base/common.dart'; import '../base/os.dart'; +import '../base/utils.dart'; import '../build_info.dart'; import '../build_system/build_system.dart'; +import '../build_system/targets/localizations.dart'; import '../cache.dart'; import '../dart/generate_synthetic_packages.dart'; import '../dart/pub.dart'; @@ -304,6 +306,32 @@ class PackagesGetCommand extends FlutterCommand { environment: environment, buildSystem: globals.buildSystem, ); + } else if (rootProject.directory.childFile('l10n.yaml').existsSync()) { + final Environment environment = Environment( + artifacts: globals.artifacts!, + logger: globals.logger, + cacheDir: globals.cache.getRoot(), + engineVersion: globals.flutterVersion.engineRevision, + fileSystem: globals.fs, + flutterRootDir: globals.fs.directory(Cache.flutterRoot), + outputDir: globals.fs.directory(getBuildDirectory()), + processManager: globals.processManager, + platform: globals.platform, + usage: globals.flutterUsage, + projectDir: rootProject.directory, + generateDartPluginRegistry: true, + ); + final BuildResult result = await globals.buildSystem.build( + const GenerateLocalizationsTarget(), + environment, + ); + if (result.hasException) { + throwToolExit( + 'Generating synthetic localizations package failed with ${result.exceptions.length} ${pluralize('error', result.exceptions.length)}:' + '\n\n' + '${result.exceptions.values.map((ExceptionMeasurement e) => e.exception).join('\n\n')}', + ); + } } } final String? relativeTarget = target == null ? null : globals.fs.path.relative(target); diff --git a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart index 0a9be004bed09..df145350049e4 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -255,6 +255,81 @@ void main() { ), }); + testUsingContext('get generates synthetic package when l10n.yaml has synthetic-package: true', () async { + final String projectPath = await createProject(tempDir, + arguments: ['--no-pub', '--template=module']); + final Directory projectDir = globals.fs.directory(projectPath); + projectDir + .childDirectory('lib') + .childDirectory('l10n') + .childFile('app_en.arb') + ..createSync(recursive: true) + ..writeAsStringSync('{ "hello": "Hello world!" }'); + String pubspecFileContent = projectDir.childFile('pubspec.yaml').readAsStringSync(); + pubspecFileContent = pubspecFileContent.replaceFirst(RegExp(r'\nflutter\:'), ''' +flutter: + generate: true +'''); + projectDir + .childFile('pubspec.yaml') + .writeAsStringSync(pubspecFileContent); + projectDir + .childFile('l10n.yaml') + .writeAsStringSync('synthetic-package: true'); + await runCommandIn(projectPath, 'get'); + expect( + projectDir + .childDirectory('.dart_tool') + .childDirectory('flutter_gen') + .childDirectory('gen_l10n') + .childFile('app_localizations.dart') + .existsSync(), + true + ); + }, overrides: { + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); + + testUsingContext('get generates normal files when l10n.yaml has synthetic-package: false', () async { + final String projectPath = await createProject(tempDir, + arguments: ['--no-pub', '--template=module']); + final Directory projectDir = globals.fs.directory(projectPath); + projectDir + .childDirectory('lib') + .childDirectory('l10n') + .childFile('app_en.arb') + ..createSync(recursive: true) + ..writeAsStringSync('{ "hello": "Hello world!" }'); + projectDir + .childFile('l10n.yaml') + .writeAsStringSync('synthetic-package: false'); + await runCommandIn(projectPath, 'get'); + expect( + projectDir + .childDirectory('lib') + .childDirectory('l10n') + .childFile('app_localizations.dart') + .existsSync(), + true + ); + }, overrides: { + Pub: () => Pub( + fileSystem: globals.fs, + logger: globals.logger, + processManager: globals.processManager, + usage: globals.flutterUsage, + botDetector: globals.botDetector, + platform: globals.platform, + ), + }); + testUsingContext('set no plugins as usage value', () async { final String projectPath = await createProject(tempDir, arguments: ['--no-pub', '--template=module']); From b52297da0620f1b3df4860cea8338bb8d338dfd4 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:24:55 -0500 Subject: [PATCH 0787/1547] Fix Xcode 15 build failure due to DT_TOOLCHAIN_DIR (#132803) Starting in Xcode 15, when building macOS, DT_TOOLCHAIN_DIR cannot be used to evaluate LD_RUNPATH_SEARCH_PATHS or LIBRARY_SEARCH_PATHS. `xcodebuild` error message recommend using TOOLCHAIN_DIR instead. Since Xcode 15 isn't in CI, I tested it in a one-off `led` test: * [Pre-fix failure](https://luci-milo.appspot.com/raw/build/logs.chromium.org/flutter/led/vashworth_google.com/04e485a0b152a0720f5e561266f7a6e4fb64fc76227fcacc95b67486ae2771e7/+/build.proto) * [Post-fix success](https://luci-milo.appspot.com/raw/build/logs.chromium.org/flutter/led/vashworth_google.com/d454a3e181e1a97692bdc1fcc197738fe04e4acf1cb20026fd040fd78513f3b0/+/build.proto) Fixes https://github.com/flutter/flutter/issues/132755. --- .../lib/src/macos/cocoapods.dart | 6 + ...coapods_toolchain_directory_migration.dart | 62 ++++++++ .../flutter_tools/lib/src/xcode_project.dart | 9 +- .../ios/ios_project_migration_test.dart | 148 ++++++++++++++++++ 4 files changed, 222 insertions(+), 3 deletions(-) create mode 100644 packages/flutter_tools/lib/src/migrations/cocoapods_toolchain_directory_migration.dart diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index 95a967e450619..e675b50c5efa8 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -19,6 +19,7 @@ import '../build_info.dart'; import '../cache.dart'; import '../ios/xcodeproj.dart'; import '../migrations/cocoapods_script_symlink.dart'; +import '../migrations/cocoapods_toolchain_directory_migration.dart'; import '../reporting/reporting.dart'; import '../xcode_project.dart'; @@ -172,6 +173,11 @@ class CocoaPods { // This migrator works around a CocoaPods bug, and should be run after `pod install` is run. final ProjectMigration postPodMigration = ProjectMigration([ CocoaPodsScriptReadlink(xcodeProject, _xcodeProjectInterpreter, _logger), + CocoaPodsToolchainDirectoryMigration( + xcodeProject, + _xcodeProjectInterpreter, + _logger, + ), ]); postPodMigration.run(); diff --git a/packages/flutter_tools/lib/src/migrations/cocoapods_toolchain_directory_migration.dart b/packages/flutter_tools/lib/src/migrations/cocoapods_toolchain_directory_migration.dart new file mode 100644 index 0000000000000..4ab406bda6819 --- /dev/null +++ b/packages/flutter_tools/lib/src/migrations/cocoapods_toolchain_directory_migration.dart @@ -0,0 +1,62 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../base/file_system.dart'; +import '../base/project_migrator.dart'; +import '../base/version.dart'; +import '../ios/xcodeproj.dart'; +import '../xcode_project.dart'; + +/// Starting in Xcode 15, when building macOS, DT_TOOLCHAIN_DIR cannot be used +/// to evaluate LD_RUNPATH_SEARCH_PATHS or LIBRARY_SEARCH_PATHS. `xcodebuild` +/// error message recommend using TOOLCHAIN_DIR instead. +/// +/// This has been fixed upstream in CocoaPods, but migrate a copy of their +/// workaround so users don't need to update. +class CocoaPodsToolchainDirectoryMigration extends ProjectMigrator { + CocoaPodsToolchainDirectoryMigration( + XcodeBasedProject project, + XcodeProjectInterpreter xcodeProjectInterpreter, + super.logger, + ) : _podRunnerTargetSupportFiles = project.podRunnerTargetSupportFiles, + _xcodeProjectInterpreter = xcodeProjectInterpreter; + + final Directory _podRunnerTargetSupportFiles; + final XcodeProjectInterpreter _xcodeProjectInterpreter; + + @override + void migrate() { + if (!_podRunnerTargetSupportFiles.existsSync()) { + logger.printTrace('CocoaPods Pods-Runner Target Support Files not found, skipping TOOLCHAIN_DIR workaround.'); + return; + } + + final Version? version = _xcodeProjectInterpreter.version; + + // If Xcode not installed or less than 15, skip this migration. + if (version == null || version < Version(15, 0, 0)) { + logger.printTrace('Detected Xcode version is $version, below 15.0, skipping TOOLCHAIN_DIR workaround.'); + return; + } + + final List files = _podRunnerTargetSupportFiles.listSync(); + for (final FileSystemEntity file in files) { + if (file.basename.endsWith('xcconfig') && file is File) { + processFileLines(file); + } + } + } + + @override + String? migrateLine(String line) { + final String trimmedString = line.trim(); + if (trimmedString.startsWith('LD_RUNPATH_SEARCH_PATHS') || trimmedString.startsWith('LIBRARY_SEARCH_PATHS')) { + const String originalReadLinkLine = r'{DT_TOOLCHAIN_DIR}'; + const String replacementReadLinkLine = r'{TOOLCHAIN_DIR}'; + + return line.replaceAll(originalReadLinkLine, replacementReadLinkLine); + } + return line; + } +} diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index 0e658a410d1ab..add59a60b1b28 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -104,11 +104,14 @@ abstract class XcodeBasedProject extends FlutterProjectPlatform { File get podManifestLock => hostAppRoot.childDirectory('Pods').childFile('Manifest.lock'); /// The CocoaPods generated 'Pods-Runner-frameworks.sh'. - File get podRunnerFrameworksScript => hostAppRoot + File get podRunnerFrameworksScript => podRunnerTargetSupportFiles + .childFile('Pods-Runner-frameworks.sh'); + + /// The CocoaPods generated directory 'Pods-Runner'. + Directory get podRunnerTargetSupportFiles => hostAppRoot .childDirectory('Pods') .childDirectory('Target Support Files') - .childDirectory('Pods-Runner') - .childFile('Pods-Runner-frameworks.sh'); + .childDirectory('Pods-Runner'); } /// Represents the iOS sub-project of a Flutter project. diff --git a/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart index c5ed8b619cca7..3f2277a22c83b 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_project_migration_test.dart @@ -16,6 +16,7 @@ import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embed import 'package:flutter_tools/src/ios/migrations/xcode_build_system_migration.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/migrations/cocoapods_script_symlink.dart'; +import 'package:flutter_tools/src/migrations/cocoapods_toolchain_directory_migration.dart'; import 'package:flutter_tools/src/migrations/xcode_project_object_version_migration.dart'; import 'package:flutter_tools/src/migrations/xcode_script_build_phase_migration.dart'; import 'package:flutter_tools/src/migrations/xcode_thin_binary_build_phase_input_paths_migration.dart'; @@ -1003,6 +1004,150 @@ platform :ios, '11.0' expect(testLogger.statusText, contains('Upgrading Pods-Runner-frameworks.sh')); }); }); + + group('Cocoapods migrate toolchain directory', () { + late MemoryFileSystem memoryFileSystem; + late BufferLogger testLogger; + late FakeIosProject project; + late Directory podRunnerTargetSupportFiles; + late ProcessManager processManager; + late XcodeProjectInterpreter xcode15ProjectInterpreter; + + setUp(() { + memoryFileSystem = MemoryFileSystem(); + podRunnerTargetSupportFiles = memoryFileSystem.directory('Pods-Runner'); + testLogger = BufferLogger.test(); + project = FakeIosProject(); + processManager = FakeProcessManager.any(); + xcode15ProjectInterpreter = XcodeProjectInterpreter.test(processManager: processManager, version: Version(15, 0, 0)); + project.podRunnerTargetSupportFiles = podRunnerTargetSupportFiles; + }); + + testWithoutContext('skip if directory is missing', () { + final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration( + project, + xcode15ProjectInterpreter, + testLogger, + ); + iosProjectMigration.migrate(); + expect(podRunnerTargetSupportFiles.existsSync(), isFalse); + + expect(testLogger.traceText, contains('CocoaPods Pods-Runner Target Support Files not found')); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skip if xcconfig files are missing', () { + podRunnerTargetSupportFiles.createSync(); + final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration( + project, + xcode15ProjectInterpreter, + testLogger, + ); + iosProjectMigration.migrate(); + expect(podRunnerTargetSupportFiles.existsSync(), isTrue); + expect(testLogger.traceText, isEmpty); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skip if nothing to upgrade', () { + podRunnerTargetSupportFiles.createSync(); + final File debugConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.debug.xcconfig'); + const String contents = r''' +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +'''; + debugConfig.writeAsStringSync(contents); + + final File profileConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.profile.xcconfig'); + profileConfig.writeAsStringSync(contents); + + final File releaseConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.release.xcconfig'); + releaseConfig.writeAsStringSync(contents); + + final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration( + project, + xcode15ProjectInterpreter, + testLogger, + ); + iosProjectMigration.migrate(); + expect(debugConfig.existsSync(), isTrue); + expect(testLogger.traceText, isEmpty); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if Xcode version below 15', () { + podRunnerTargetSupportFiles.createSync(); + final File debugConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.debug.xcconfig'); + const String contents = r''' +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" +LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +'''; + debugConfig.writeAsStringSync(contents); + + final File profileConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.profile.xcconfig'); + profileConfig.writeAsStringSync(contents); + + final File releaseConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.release.xcconfig'); + releaseConfig.writeAsStringSync(contents); + + final XcodeProjectInterpreter xcode14ProjectInterpreter = XcodeProjectInterpreter.test( + processManager: processManager, + version: Version(14, 0, 0), + ); + + final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration( + project, + xcode14ProjectInterpreter, + testLogger, + ); + iosProjectMigration.migrate(); + expect(debugConfig.existsSync(), isTrue); + expect(testLogger.traceText, contains('Detected Xcode version is 14.0.0, below 15.0')); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('Xcode project is migrated and ignores leading whitespace', () { + podRunnerTargetSupportFiles.createSync(); + final File debugConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.debug.xcconfig'); + const String contents = r''' +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +'''; + debugConfig.writeAsStringSync(contents); + + final File profileConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.profile.xcconfig'); + profileConfig.writeAsStringSync(contents); + + final File releaseConfig = podRunnerTargetSupportFiles.childFile('Pods-Runner.release.xcconfig'); + releaseConfig.writeAsStringSync(contents); + + final CocoaPodsToolchainDirectoryMigration iosProjectMigration = CocoaPodsToolchainDirectoryMigration( + project, + xcode15ProjectInterpreter, + testLogger, + ); + iosProjectMigration.migrate(); + + expect(debugConfig.existsSync(), isTrue); + expect(debugConfig.readAsStringSync(), r''' +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +'''); + expect(profileConfig.existsSync(), isTrue); + expect(profileConfig.readAsStringSync(), r''' +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +'''); + expect(releaseConfig.existsSync(), isTrue); + expect(releaseConfig.readAsStringSync(), r''' +LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/../Frameworks' '@loader_path/Frameworks' "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +'''); + expect(testLogger.statusText, contains('Upgrading Pods-Runner.debug.xcconfig')); + expect(testLogger.statusText, contains('Upgrading Pods-Runner.profile.xcconfig')); + expect(testLogger.statusText, contains('Upgrading Pods-Runner.release.xcconfig')); + }); + }); }); group('update Xcode script build phase', () { @@ -1239,6 +1384,9 @@ class FakeIosProject extends Fake implements IosProject { @override File podRunnerFrameworksScript = MemoryFileSystem.test().file('podRunnerFrameworksScript'); + + @override + Directory podRunnerTargetSupportFiles = MemoryFileSystem.test().directory('Pods-Runner'); } class FakeIOSMigrator extends ProjectMigrator { From 5a556f8ecde63ae9deec22411000fe632cc6a6bd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 18 Aug 2023 11:45:21 -0400 Subject: [PATCH 0788/1547] Roll Packages from 3b602e77e69a to 4c16f3ef4033 (3 revisions) (#132848) https://github.com/flutter/packages/compare/3b602e77e69a...4c16f3ef4033 2023-08-17 katelovett@google.com [two_dimensional_scrollables] TableView (flutter/packages#4536) 2023-08-17 stuartmorgan@google.com [ci] Update minimums for 3.13 stable (flutter/packages#4731) 2023-08-17 10687576+bparrishMines@users.noreply.github.com Update stable version to efbf63d9c66b9f6ec30e9ad4611189aa80003d31 (flutter/packages#4730) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index f1007925ecde4..1e5628ab5aeb8 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -3b602e77e69aac91dbbf2e18260fb70d3a42df23 +4c16f3ef40333aa0aebe8a1e46ef7b9fef9a1c1f From 1cfba2620ac98739921957c7a2d848a84b19d3fe Mon Sep 17 00:00:00 2001 From: Andrey Suvorov <32621121+AndreySuworow@users.noreply.github.com> Date: Fri, 18 Aug 2023 19:38:54 +0300 Subject: [PATCH 0789/1547] fixes l10n for CupertinoDatePicker in monthYear mode (#130934) This PR fixes l10n issue when months names are being used in incorrect form in CupertinoDatePicker in CupertinoDatePickerMode.yearMonth (#130930). The idea of this proposal is to add an optional parameter `standalone` for `CupertinoLocalizations.datePickerMonth` to be able to choose when to use months names in base form (intl DateSymbols.STANDALONEMONTHS) and when in day-dependent form (intl DateSymbols.MONTHS)
    Before image image
    After image image
    --- .../lib/src/cupertino/date_picker.dart | 20 +++++--- .../lib/src/cupertino/localizations.dart | 19 ++++++++ .../lib/src/cupertino_localizations.dart | 12 +++++ .../test/cupertino/date_picker_test.dart | 47 +++++++++++++++++++ .../test/cupertino/translations_test.dart | 5 ++ 5 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 packages/flutter_localizations/test/cupertino/date_picker_test.dart diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 693b4069a3ee1..afc938624e9ad 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -438,8 +438,9 @@ class CupertinoDatePicker extends StatefulWidget { _PickerColumnType columnType, CupertinoLocalizations localizations, BuildContext context, - bool showDayOfWeek - ) { + bool showDayOfWeek, { + bool standaloneMonth = false, + }) { String longestText = ''; switch (columnType) { @@ -491,8 +492,10 @@ class CupertinoDatePicker extends StatefulWidget { } } case _PickerColumnType.month: - for (int i = 1; i <=12; i++) { - final String month = localizations.datePickerMonth(i); + for (int i = 1; i <= 12; i++) { + final String month = standaloneMonth + ? localizations.datePickerStandaloneMonth(i) + : localizations.datePickerMonth(i); if (longestText.length < month.length) { longestText = month; } @@ -1280,11 +1283,12 @@ class _CupertinoDatePickerDateState extends State { final int month = index + 1; final bool isInvalidMonth = (widget.minimumDate?.year == selectedYear && widget.minimumDate!.month > month) || (widget.maximumDate?.year == selectedYear && widget.maximumDate!.month < month); + final String monthName = (widget.mode == CupertinoDatePickerMode.monthYear) ? localizations.datePickerStandaloneMonth(month) : localizations.datePickerMonth(month); return itemPositioningBuilder( context, Text( - localizations.datePickerMonth(month), + monthName, style: _themeTextStyle(context, isValid: !isInvalidMonth), ), ); @@ -1577,7 +1581,8 @@ class _CupertinoDatePickerMonthYearState extends State { } void _refreshEstimatedColumnWidths() { - estimatedColumnWidths[_PickerColumnType.month.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.month, localizations, context, false); + estimatedColumnWidths[_PickerColumnType.month.index] = + CupertinoDatePicker._getColumnWidth(_PickerColumnType.month, localizations, context, false, standaloneMonth: widget.mode == CupertinoDatePickerMode.monthYear); estimatedColumnWidths[_PickerColumnType.year.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.year, localizations, context, false); } @@ -1613,11 +1618,12 @@ class _CupertinoDatePickerMonthYearState extends State { final int month = index + 1; final bool isInvalidMonth = (widget.minimumDate?.year == selectedYear && widget.minimumDate!.month > month) || (widget.maximumDate?.year == selectedYear && widget.maximumDate!.month < month); + final String monthName = (widget.mode == CupertinoDatePickerMode.monthYear) ? localizations.datePickerStandaloneMonth(month) : localizations.datePickerMonth(month); return itemPositioningBuilder( context, Text( - localizations.datePickerMonth(month), + monthName, style: _themeTextStyle(context, isValid: !isInvalidMonth), ), ); diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index 17bccd35b5859..02cb25970f3f0 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -76,9 +76,25 @@ abstract class CupertinoLocalizations { /// /// - US English: January /// - Korean: 1월 + /// - Russian: января // The global version uses date symbols data from the intl package. String datePickerMonth(int monthIndex); + /// Month that is shown in [CupertinoDatePicker] spinner corresponding to + /// the given month index in [CupertinoDatePickerMode.monthYear] mode. + /// + /// This is distinct from [datePickerMonth] because in some languages, like Russian, + /// the name of a month takes a different form depending + /// on whether it is preceded by a day or whether it stands alone. + /// + /// Examples: datePickerMonth(1) in: + /// + /// - US English: January + /// - Korean: 1월 + /// - Russian: Январь + // The global version uses date symbols data from the intl package. + String datePickerStandaloneMonth(int monthIndex); + /// Day of month that is shown in [CupertinoDatePicker] spinner corresponding /// to the given day index. /// @@ -367,6 +383,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { @override String datePickerMonth(int monthIndex) => _months[monthIndex - 1]; + @override + String datePickerStandaloneMonth(int monthIndex) => _months[monthIndex - 1]; + @override String datePickerDayOfMonth(int dayIndex, [int? weekDay]) { if (weekDay != null) { diff --git a/packages/flutter_localizations/lib/src/cupertino_localizations.dart b/packages/flutter_localizations/lib/src/cupertino_localizations.dart index 68a5c0bc8b0bd..ec9b82120785a 100644 --- a/packages/flutter_localizations/lib/src/cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/cupertino_localizations.dart @@ -100,6 +100,18 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations { return _fullYearFormat.dateSymbols.MONTHS[monthIndex - 1]; } + @override + String datePickerStandaloneMonth(int monthIndex) { + // It doesn't actually have anything to do with _fullYearFormat. It's just + // taking advantage of the fact that _fullYearFormat loaded the needed + // locale's symbols. + // + // Because this will be used without specifying any day of month, + // in most cases it should be capitalized (according to rules in specific language). + return intl.toBeginningOfSentenceCase(_fullYearFormat.dateSymbols.STANDALONEMONTHS[monthIndex - 1]) ?? + _fullYearFormat.dateSymbols.STANDALONEMONTHS[monthIndex - 1]; + } + @override String datePickerDayOfMonth(int dayIndex, [int? weekDay]) { if (weekDay != null) { diff --git a/packages/flutter_localizations/test/cupertino/date_picker_test.dart b/packages/flutter_localizations/test/cupertino/date_picker_test.dart new file mode 100644 index 0000000000000..d94b5343a9056 --- /dev/null +++ b/packages/flutter_localizations/test/cupertino/date_picker_test.dart @@ -0,0 +1,47 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Test correct month form for CupertinoDatePicker in monthYear mode', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: CupertinoPageScaffold( + child: Center( + child: CupertinoDatePicker( + initialDateTime: DateTime(2023, 5), + onDateTimeChanged: (_) {}, + mode: CupertinoDatePickerMode.monthYear, + )), + ), + supportedLocales: const [Locale('ru', 'RU')], + localizationsDelegates: GlobalCupertinoLocalizations.delegates, + ), + ); + + expect(find.text('Май'), findsWidgets); + }); + + testWidgets('Test correct month form for CupertinoDatePicker in date mode', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: CupertinoPageScaffold( + child: Center( + child: CupertinoDatePicker( + initialDateTime: DateTime(2023, 5), + onDateTimeChanged: (_) {}, + mode: CupertinoDatePickerMode.date, + )), + ), + supportedLocales: const [Locale('ru', 'RU')], + localizationsDelegates: GlobalCupertinoLocalizations.delegates, + ), + ); + + expect(find.text('мая'), findsWidgets); + }); +} diff --git a/packages/flutter_localizations/test/cupertino/translations_test.dart b/packages/flutter_localizations/test/cupertino/translations_test.dart index 736e5ddb25779..a827e0d498f6e 100644 --- a/packages/flutter_localizations/test/cupertino/translations_test.dart +++ b/packages/flutter_localizations/test/cupertino/translations_test.dart @@ -34,6 +34,11 @@ void main() { expect(localizations.datePickerMonth(11), isNotNull); expect(localizations.datePickerMonth(12), isNotNull); + expect(localizations.datePickerStandaloneMonth(1), isNotNull); + expect(localizations.datePickerStandaloneMonth(2), isNotNull); + expect(localizations.datePickerStandaloneMonth(11), isNotNull); + expect(localizations.datePickerStandaloneMonth(12), isNotNull); + expect(localizations.datePickerDayOfMonth(0), isNotNull); expect(localizations.datePickerDayOfMonth(1), isNotNull); expect(localizations.datePickerDayOfMonth(2), isNotNull); From 58019b34286233b193f51f92c2bc6d009f21f1a1 Mon Sep 17 00:00:00 2001 From: gmilou <139406084+gmilou@users.noreply.github.com> Date: Fri, 18 Aug 2023 09:50:06 -0700 Subject: [PATCH 0790/1547] =?UTF-8?q?Add=20a=20new=20MatrixTransition=20an?= =?UTF-8?q?d=20refactor=20ScaleTransition=20and=20RotationT=E2=80=A6=20(#1?= =?UTF-8?q?31084)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …ransition to derive from it. The MatrixTransition class uses a callback to handle any value => Matrix animation. The alignment and filterQuality logic that was in ScaleTransition and RotationTransition is now factored in MatrixTransition. The ScaleTransition.scale and RotationTransition.turns getters had to be kept because they're still referenced in https://github.com/flutter/packages/tree/main/packages/animations, and https://github.com/flutter/packages/flutter/test/. I plan to remove the references there, once this PR is generally available, and then remove the getters here. A RotationTransition test was updated to use matrixMoreOrLessEquals because using Matrix4.rotationZ doesn't have the special cases Transform.Rotation had, and zeroes in matrix weren't exactly zeroes. fixes #130946 --- .../flutter/lib/src/widgets/transitions.dart | 171 +++++++++--------- .../test/widgets/transitions_test.dart | 132 +++++++++++++- 2 files changed, 215 insertions(+), 88 deletions(-) diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart index bdde5fe12f8db..b91f4fb2ad4db 100644 --- a/packages/flutter/lib/src/widgets/transitions.dart +++ b/packages/flutter/lib/src/widgets/transitions.dart @@ -225,51 +225,51 @@ class SlideTransition extends AnimatedWidget { } } -/// Animates the scale of a transformed widget. +/// Signature for the callback to [MatrixTransition.onTransform]. /// -/// Here's an illustration of the [ScaleTransition] widget, with it's [alignment] -/// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn]: -/// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/scale_transition.mp4} -/// -/// {@tool dartpad} -/// The following code implements the [ScaleTransition] as seen in the video -/// above: +/// Computes a [Matrix4] to be used in the [MatrixTransition] transformed widget +/// from the [MatrixTransition.animation] value. +typedef TransformCallback = Matrix4 Function(double animationValue); + +/// Animates the [Matrix4] of a transformed widget. /// -/// ** See code in examples/api/lib/widgets/transitions/scale_transition.0.dart ** -/// {@end-tool} +/// The [onTransform] callback computes a [Matrix4] from the animated value, it +/// is called every time the [animation] changes its value. /// /// See also: /// -/// * [PositionedTransition], a widget that animates its child from a start -/// position to an end position over the lifetime of the animation. -/// * [RelativePositionedTransition], a widget that transitions its child's -/// position based on the value of a rectangle relative to a bounding box. -/// * [SizeTransition], a widget that animates its own size and clips and -/// aligns its child. -class ScaleTransition extends AnimatedWidget { - /// Creates a scale transition. +/// * [ScaleTransition], which animates the scale of a widget, by providing a +/// matrix which scales along the X and Y axis. +/// * [RotationTransition], which animates the rotation of a widget, by +/// providing a matrix which rotates along the Z axis. +class MatrixTransition extends AnimatedWidget { + /// Creates a matrix transition. /// - /// The [scale] argument must not be null. The [alignment] argument defaults - /// to [Alignment.center]. - const ScaleTransition({ + /// The [alignment] argument defaults to [Alignment.center]. + const MatrixTransition({ super.key, - required Animation scale, + required Animation animation, + required this.onTransform, this.alignment = Alignment.center, this.filterQuality, this.child, - }) : super(listenable: scale); + }) : super(listenable: animation); - /// The animation that controls the scale of the child. + /// The callback to compute a [Matrix4] from the [animation]. It's called + /// every time [animation] changes its value. + final TransformCallback onTransform; + + /// The animation that controls the matrix of the child. /// - /// If the current value of the scale animation is v, the child will be - /// painted v times its normal size. - Animation get scale => listenable as Animation; + /// The matrix will be computed from the animation with the [onTransform] + /// callback. + Animation get animation => listenable as Animation; - /// The alignment of the origin of the coordinate system in which the scale - /// takes place, relative to the size of the box. + /// The alignment of the origin of the coordinate system in which the + /// transform takes place, relative to the size of the box. /// - /// For example, to set the origin of the scale to bottom middle, you can use - /// an alignment of (0.0, 1.0). + /// For example, to set the origin of the transform to bottom middle, you can + /// use an alignment of (0.0, 1.0). final Alignment alignment; /// The filter quality with which to apply the transform as a bitmap operation. @@ -292,7 +292,7 @@ class ScaleTransition extends AnimatedWidget { // but leaving it in the layer tree before the animation has started or after // it has finished significantly hurts performance. final bool useFilterQuality; - switch (scale.status) { + switch (animation.status) { case AnimationStatus.dismissed: case AnimationStatus.completed: useFilterQuality = false; @@ -300,8 +300,8 @@ class ScaleTransition extends AnimatedWidget { case AnimationStatus.reverse: useFilterQuality = true; } - return Transform.scale( - scale: scale.value, + return Transform( + transform: onTransform(animation.value), alignment: alignment, filterQuality: useFilterQuality ? filterQuality : null, child: child, @@ -309,6 +309,49 @@ class ScaleTransition extends AnimatedWidget { } } +/// Animates the scale of a transformed widget. +/// +/// Here's an illustration of the [ScaleTransition] widget, with it's [alignment] +/// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn]: +/// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/scale_transition.mp4} +/// +/// {@tool dartpad} +/// The following code implements the [ScaleTransition] as seen in the video +/// above: +/// +/// ** See code in examples/api/lib/widgets/transitions/scale_transition.0.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [PositionedTransition], a widget that animates its child from a start +/// position to an end position over the lifetime of the animation. +/// * [RelativePositionedTransition], a widget that transitions its child's +/// position based on the value of a rectangle relative to a bounding box. +/// * [SizeTransition], a widget that animates its own size and clips and +/// aligns its child. +class ScaleTransition extends MatrixTransition { + /// Creates a scale transition. + /// + /// The [alignment] argument defaults to [Alignment.center]. + const ScaleTransition({ + super.key, + required Animation scale, + super.alignment = Alignment.center, + super.filterQuality, + super.child, + }) : super(animation: scale, onTransform: _handleScaleMatrix); + + /// The animation that controls the scale of the child. + Animation get scale => animation; + + /// The callback that controls the scale of the child. + /// + /// If the current value of the animation is v, the child will be + /// painted v times its normal size. + static Matrix4 _handleScaleMatrix(double value) => Matrix4.diagonal3Values(value, value, 1.0); +} + /// Animates the rotation of a widget. /// /// Here's an illustration of the [RotationTransition] widget, with it's [turns] @@ -328,66 +371,26 @@ class ScaleTransition extends AnimatedWidget { /// widget. /// * [SizeTransition], a widget that animates its own size and clips and /// aligns its child. -class RotationTransition extends AnimatedWidget { +class RotationTransition extends MatrixTransition { /// Creates a rotation transition. /// /// The [turns] argument must not be null. const RotationTransition({ super.key, required Animation turns, - this.alignment = Alignment.center, - this.filterQuality, - this.child, - }) : super(listenable: turns); + super.alignment = Alignment.center, + super.filterQuality, + super.child, + }) : super(animation: turns, onTransform: _handleTurnsMatrix); /// The animation that controls the rotation of the child. - /// - /// If the current value of the turns animation is v, the child will be - /// rotated v * 2 * pi radians before being painted. - Animation get turns => listenable as Animation; - - /// The alignment of the origin of the coordinate system around which the - /// rotation occurs, relative to the size of the box. - /// - /// For example, to set the origin of the rotation to top right corner, use - /// an alignment of (1.0, -1.0) or use [Alignment.topRight] - final Alignment alignment; - - /// The filter quality with which to apply the transform as a bitmap operation. - /// - /// When the animation is stopped (either in [AnimationStatus.dismissed] or - /// [AnimationStatus.completed]), the filter quality argument will be ignored. - /// - /// {@macro flutter.widgets.Transform.optional.FilterQuality} - final FilterQuality? filterQuality; + Animation get turns => animation; - /// The widget below this widget in the tree. + /// The callback that controls the rotation of the child. /// - /// {@macro flutter.widgets.ProxyWidget.child} - final Widget? child; - - @override - Widget build(BuildContext context) { - // The ImageFilter layer created by setting filterQuality will introduce - // a saveLayer call. This is usually worthwhile when animating the layer, - // but leaving it in the layer tree before the animation has started or after - // it has finished significantly hurts performance. - final bool useFilterQuality; - switch (turns.status) { - case AnimationStatus.dismissed: - case AnimationStatus.completed: - useFilterQuality = false; - case AnimationStatus.forward: - case AnimationStatus.reverse: - useFilterQuality = true; - } - return Transform.rotate( - angle: turns.value * math.pi * 2.0, - alignment: alignment, - filterQuality: useFilterQuality ? filterQuality : null, - child: child, - ); - } + /// If the current value of the animation is v, the child will be rotated + /// v * 2 * pi radians before being painted. + static Matrix4 _handleTurnsMatrix(double value) => Matrix4.rotationZ(value * math.pi * 2.0); } /// Animates its own size and clips and aligns its child. diff --git a/packages/flutter/test/widgets/transitions_test.dart b/packages/flutter/test/widgets/transitions_test.dart index 9b1a33bc9a9d2..9af19cf513d75 100644 --- a/packages/flutter/test/widgets/transitions_test.dart +++ b/packages/flutter/test/widgets/transitions_test.dart @@ -296,6 +296,67 @@ void main() { expect(actualPositionedBox.widthFactor, 1.0); }); + testWidgets('MatrixTransition animates', (WidgetTester tester) async { + final AnimationController controller = AnimationController(vsync: const TestVSync()); + final Widget widget = MatrixTransition( + alignment: Alignment.topRight, + onTransform: (double value) => Matrix4.translationValues(value, value, value), + animation: controller, + child: const Text( + 'Matrix', + textDirection: TextDirection.ltr, + ), + ); + + await tester.pumpWidget(widget); + Transform actualTransformedBox = tester.widget(find.byType(Transform)); + Matrix4 actualTransform = actualTransformedBox.transform; + expect(actualTransform, equals(Matrix4.rotationZ(0.0))); + + controller.value = 0.5; + await tester.pump(); + actualTransformedBox = tester.widget(find.byType(Transform)); + actualTransform = actualTransformedBox.transform; + expect(actualTransform, Matrix4.fromList([ + 1.0, 0.0, 0.0, 0.5, + 0.0, 1.0, 0.0, 0.5, + 0.0, 0.0, 1.0, 0.5, + 0.0, 0.0, 0.0, 1.0, + ])..transpose()); + + controller.value = 0.75; + await tester.pump(); + actualTransformedBox = tester.widget(find.byType(Transform)); + actualTransform = actualTransformedBox.transform; + expect(actualTransform, Matrix4.fromList([ + 1.0, 0.0, 0.0, 0.75, + 0.0, 1.0, 0.0, 0.75, + 0.0, 0.0, 1.0, 0.75, + 0.0, 0.0, 0.0, 1.0, + ])..transpose()); + }); + + testWidgets('MatrixTransition maintains chosen alignment during animation', (WidgetTester tester) async { + final AnimationController controller = AnimationController(vsync: const TestVSync()); + final Widget widget = MatrixTransition( + alignment: Alignment.topRight, + onTransform: (double value) => Matrix4.identity(), + animation: controller, + child: const Text('Matrix', textDirection: TextDirection.ltr), + ); + + await tester.pumpWidget(widget); + MatrixTransition actualTransformedBox = tester.widget(find.byType(MatrixTransition)); + Alignment actualAlignment = actualTransformedBox.alignment; + expect(actualAlignment, Alignment.topRight); + + controller.value = 0.5; + await tester.pump(); + actualTransformedBox = tester.widget(find.byType(MatrixTransition)); + actualAlignment = actualTransformedBox.alignment; + expect(actualAlignment, Alignment.topRight); + }); + testWidgets('RotationTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = RotationTransition( @@ -316,23 +377,23 @@ void main() { await tester.pump(); actualRotatedBox = tester.widget(find.byType(Transform)); actualTurns = actualRotatedBox.transform; - expect(actualTurns, Matrix4.fromList([ + expect(actualTurns, matrixMoreOrLessEquals(Matrix4.fromList([ -1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, - ])..transpose()); + ])..transpose())); controller.value = 0.75; await tester.pump(); actualRotatedBox = tester.widget(find.byType(Transform)); actualTurns = actualRotatedBox.transform; - expect(actualTurns, Matrix4.fromList([ + expect(actualTurns, matrixMoreOrLessEquals(Matrix4.fromList([ 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, - ])..transpose()); + ])..transpose())); }); testWidgets('RotationTransition maintains chosen alignment during animation', (WidgetTester tester) async { @@ -457,6 +518,69 @@ void main() { }); }); + group('MatrixTransition', () { + testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + final AnimationController controller = AnimationController(vsync: const TestVSync()); + final Animation animation = Tween(begin: 0.0, end: 1.0).animate(controller); + final Widget widget = Directionality( + textDirection: TextDirection.ltr, + child: MatrixTransition( + animation: animation, + onTransform: (double value) => Matrix4.identity(), + filterQuality: FilterQuality.none, + child: const Text('Matrix Transition'), + ), + ); + + await tester.pumpWidget(widget); + + // Validate that expensive layer is not left in tree before animation has started. + expect(tester.layers, isNot(contains(isA()))); + + controller.value = 0.25; + await tester.pump(); + + expect( + tester.layers, + contains(isA().having( + (ImageFilterLayer layer) => layer.imageFilter.toString(), + 'image filter', + startsWith('ImageFilter.matrix('), + )), + ); + + controller.value = 0.5; + await tester.pump(); + + expect( + tester.layers, + contains(isA().having( + (ImageFilterLayer layer) => layer.imageFilter.toString(), + 'image filter', + startsWith('ImageFilter.matrix('), + )), + ); + + controller.value = 0.75; + await tester.pump(); + + expect( + tester.layers, + contains(isA().having( + (ImageFilterLayer layer) => layer.imageFilter.toString(), + 'image filter', + startsWith('ImageFilter.matrix('), + )), + ); + + controller.value = 1; + await tester.pump(); + + // Validate that expensive layer is not left in tree after animation has finished. + expect(tester.layers, isNot(contains(isA()))); + }); + }); + group('ScaleTransition', () { testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); From 6875827f467d080fec549730edd8aa653440ddcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Ate=C5=9F=20Uzun?= Date: Fri, 18 Aug 2023 20:48:05 +0300 Subject: [PATCH 0791/1547] doc: add flag params (#132485) *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- packages/flutter_tools/bin/xcode_debug.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_tools/bin/xcode_debug.js b/packages/flutter_tools/bin/xcode_debug.js index 25f16a27298aa..20b8f2337b386 100644 --- a/packages/flutter_tools/bin/xcode_debug.js +++ b/packages/flutter_tools/bin/xcode_debug.js @@ -194,6 +194,7 @@ class CommandArguments { * return true. If the flag is not allowed for the current command, will * return `null`. * + * @param {!string} flag * @param {?string} value * @returns {?boolean} * @throws Will throw an error if the flag is allowed and `value` is not From 6cefc2ea61e2450248afc6b74f35e0ada3937f5d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 18 Aug 2023 14:28:02 -0400 Subject: [PATCH 0792/1547] Roll Flutter Engine from 58f7d8ee3e2c to 83fdadaf12f0 (7 revisions) (#132857) https://github.com/flutter/engine/compare/58f7d8ee3e2c...83fdadaf12f0 2023-08-18 zanderso@users.noreply.github.com Update Impeller benchmarks.md with a Pixel 7 link (flutter/engine#44834) 2023-08-18 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 7xOzci7fempFgHNk9... to pSqQ556xmZp7S4np5... (flutter/engine#44846) 2023-08-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 121fcbd8124c to 8109103e041b (1 revision) (flutter/engine#44844) 2023-08-18 jonahwilliams@google.com [Impeller] add trace events for VkRenderPass and VkFrameBuffer creation. (flutter/engine#44837) 2023-08-18 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Tnp43n_nAR2N0l_gY... to onEHyyETXAMieDyfP... (flutter/engine#44845) 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from 1e62a2d4c429 to c9294edc03b9 (2 revisions) (flutter/engine#44843) 2023-08-18 leroux_bruno@yahoo.fr [Android] Expose channel buffer resize and overflow calls (flutter/engine#44434) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 7xOzci7fempF to pSqQ556xmZp7 fuchsia/sdk/core/mac-amd64 from Tnp43n_nAR2N to onEHyyETXAMi If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fc4a4dd30f4ed..7b1739bf2b49d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -58f7d8ee3e2cec3df2b5e7c53be3ae1f2861203d +83fdadaf12f00ef0ca3aa9401918a2486fcb89a2 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index b4b78338fbebb..88c8e473eee55 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -7xOzci7fempFgHNk9DxPxpBKoI2onNU4Ye8ElQaNa_QC +pSqQ556xmZp7S4np5xyQXWu-Ul-5qoxDxu8WXLe2_xIC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 393fa78f4e85d..39bc51a6e2b8e 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Tnp43n_nAR2N0l_gYiE0YBpA4loAnzR2Zp_vGd3v_IMC +onEHyyETXAMieDyfP8hzVi3zqabh27iPDE9waYIkPc0C From 61242fa13b4801947c4f392b11187e8a0329f299 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:42:58 -0700 Subject: [PATCH 0793/1547] Updates app link gradle tasks and remove vm services (#131805) 1. Remove vm service registration 2. combine printApplicationId and printAppLinkDomain into one task dumpAppLinkSettings, which dump all the data in a json file The deeplink validation tool will be a static app in devtool instead of regular app. A Static app doesn't require a running app; therefore, we can't call these API through vmservices. I decided to convert these API into flutter analyzer command, which will be done in a separate PR https://github.com/flutter/flutter/pull/131009. The reason these print tasks are converted into file dumps is to reduce the amount of data encoding and decoding. Instead of passing data through stdout, the devtool can read the files generated by gradle tasks instead. --- .../gradle/src/main/groovy/flutter.groovy | 138 ++++++++++-------- .../android/android_app_link_settings.dart | 22 --- .../lib/src/android/android_builder.dart | 10 +- .../flutter_tools/lib/src/android/gradle.dart | 71 +-------- packages/flutter_tools/lib/src/project.dart | 18 +-- packages/flutter_tools/lib/src/vmservice.dart | 31 ---- .../android/android_gradle_builder_test.dart | 104 +------------ .../resident_web_runner_test.dart | 8 - .../test/general.shard/vmservice_test.dart | 45 +----- ...radle_outputs_app_link_settings_test.dart} | 70 +++++++-- ...roid_gradle_print_application_id_test.dart | 64 -------- .../test/src/android_common.dart | 7 +- 12 files changed, 161 insertions(+), 427 deletions(-) delete mode 100644 packages/flutter_tools/lib/src/android/android_app_link_settings.dart rename packages/flutter_tools/test/integration.shard/{android_gradle_print_app_link_domains_test.dart => android_gradle_outputs_app_link_settings_test.dart} (68%) delete mode 100644 packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index 21368a4c9959f..f3c1a4145cf24 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import static groovy.io.FileType.FILES - import com.android.build.OutputFile import groovy.json.JsonSlurper -import java.nio.file.Path +import groovy.json.JsonGenerator +import groovy.xml.QName import java.nio.file.Paths -import java.util.regex.Matcher -import java.util.regex.Pattern +import java.util.Set import org.apache.tools.ant.taskdefs.condition.Os import org.gradle.api.DefaultTask import org.gradle.api.GradleException @@ -30,7 +28,6 @@ import org.gradle.api.tasks.Optional import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.bundling.Jar import org.gradle.internal.os.OperatingSystem -import org.gradle.util.VersionNumber /** * For apps only. Provides the flutter extension used in app/build.gradle. @@ -750,80 +747,90 @@ class FlutterPlugin implements Plugin { } } - // Add a task that can be called on Flutter projects that prints application id of a build - // variant. - // - // This task prints the application id in this format: - // - // ApplicationId: com.example.my_id - // - // Format of the output of this task is used by `AndroidProject.getApplicationIdForVariant`. - private static void addTasksForPrintApplicationId(Project project) { - project.android.applicationVariants.all { variant -> - // Warning: The name of this task is used by `AndroidProject.getApplicationIdForVariant`. - project.tasks.register("print${variant.name.capitalize()}ApplicationId") { - description "Prints out application id for the given build variant of this Android project" - doLast { - println "ApplicationId: ${variant.applicationId}"; - } - } - } - } - - // Add a task that can be called on Flutter projects that prints app link domains of a build - // variant. + // Add a task that can be called on Flutter projects that outputs app link related project + // settings into a json file. // - // The app link domains refer to the host attributes of data tags in the apps' intent filters - // that support http/https schemes. See - // https://developer.android.com/guide/topics/manifest/intent-filter-element. + // See https://developer.android.com/training/app-links/ for more information about app link. // - // This task prints app link domains in this format: + // The json will be stored in /build/app/app-link-settings-.json // - // Domain: domain.com - // Domain: another-domain.dev + // An example json: + // { + // applicationId: "com.example.app", + // deeplinks: [ + // {"scheme":"http", "host":"example.com", "path":".*"}, + // {"scheme":"https","host":"example.com","path":".*"} + // ] + // } // - // Format of the output of this task is used by `AndroidProject.getAppLinkDomainsForVariant`. - private static void addTasksForPrintAppLinkDomains(Project project) { + // The output file is parsed and used by devtool. + private static void addTasksForOutputsAppLinkSettings(Project project) { project.android.applicationVariants.all { variant -> - // Warning: The name of this task is used by `AndroidProject.getAppLinkDomainsForVariant`. - project.tasks.register("print${variant.name.capitalize()}AppLinkDomains") { - description "Prints out app links domain for the given build variant of this Android project" + // Warning: The name of this task is used by AndroidBuilder.outputsAppLinkSettings + project.tasks.register("output${variant.name.capitalize()}AppLinkSettings") { + description "stores app links settings for the given build variant of this Android project into a json file." variant.outputs.all { output -> + // Deeplinks are defined in AndroidManifest.xml and is only available after + // `processResourcesProvider`. def processResources = output.hasProperty("processResourcesProvider") ? output.processResourcesProvider.get() : output.processResources dependsOn processResources.name } doLast { + def appLinkSettings = new AppLinkSettings() + appLinkSettings.applicationId = variant.applicationId + appLinkSettings.deeplinks = [] as Set variant.outputs.all { output -> def processResources = output.hasProperty("processResourcesProvider") ? output.processResourcesProvider.get() : output.processResources def manifest = new XmlParser().parse(processResources.manifestFile) manifest.application.activity.each { activity -> - // Find intent filters that have autoVerify = true and support http/https - // scheme. - activity.'intent-filter'.findAll { filter -> - def hasAutoVerify = filter.attributes().any { entry -> - return entry.key.getLocalPart() == "autoVerify" && entry.value - } - def hasHttpOrHttps = filter.data.any { data -> - data.attributes().any { entry -> - return entry.key.getLocalPart() == "scheme" && - (entry.value == "http" || entry.value == "https") - } - } - return hasAutoVerify && hasHttpOrHttps - }.each { appLinkIntent -> + activity.'intent-filter'.each { appLinkIntent -> // Print out the host attributes in data tags. + def schemes = [] as Set + def hosts = [] as Set + def paths = [] as Set appLinkIntent.data.each { data -> data.attributes().each { entry -> - if (entry.key.getLocalPart() == "host") { - println "Domain: ${entry.value}" + if (entry.key instanceof QName) { + switch (entry.key.getLocalPart()) { + case "scheme": + schemes.add(entry.value) + break + case "host": + hosts.add(entry.value) + break + case "pathAdvancedPattern": + case "pathPattern": + case "path": + paths.add(entry.value) + break + case "pathPrefix": + paths.add("${entry.value}.*") + break + case "pathSuffix": + paths.add(".*${entry.value}") + break + } + } + } + } + schemes.each {scheme -> + hosts.each { host -> + if (!paths) { + appLinkSettings.deeplinks.add(new Deeplink(scheme: scheme, host: host, path: ".*")) + } else { + paths.each { path -> + appLinkSettings.deeplinks.add(new Deeplink(scheme: scheme, host: host, path: path)) + } } } } } } } + def generator = new JsonGenerator.Options().build() + new File(project.buildDir, "app-link-settings-${variant.name}.json").write(generator.toJson(appLinkSettings)) } } } @@ -1004,8 +1011,7 @@ class FlutterPlugin implements Plugin { addTaskForJavaVersion(project) if(isFlutterAppProject()) { addTaskForPrintBuildVariants(project) - addTasksForPrintApplicationId(project) - addTasksForPrintAppLinkDomains(project) + addTasksForOutputsAppLinkSettings(project) } def targetPlatforms = getTargetPlatforms() def addFlutterDeps = { variant -> @@ -1234,6 +1240,24 @@ class FlutterPlugin implements Plugin { } } +class AppLinkSettings { + String applicationId + Set deeplinks +} + +class Deeplink { + String scheme, host, path + boolean equals(o) { + if (o == null) + throw new NullPointerException() + if (o.getClass() != getClass()) + return false + return scheme == o.scheme && + host == o.host && + path == o.path + } +} + abstract class BaseFlutterTask extends DefaultTask { @Internal File flutterRoot diff --git a/packages/flutter_tools/lib/src/android/android_app_link_settings.dart b/packages/flutter_tools/lib/src/android/android_app_link_settings.dart deleted file mode 100644 index 8769fd883f3c6..0000000000000 --- a/packages/flutter_tools/lib/src/android/android_app_link_settings.dart +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:meta/meta.dart'; - -/// A data class for app links related project settings. -/// -/// See https://developer.android.com/training/app-links. -@immutable -class AndroidAppLinkSettings { - const AndroidAppLinkSettings({ - required this.applicationId, - required this.domains, - }); - - /// The application id of the android sub-project. - final String applicationId; - - /// The associated web domains of the android sub-project. - final List domains; -} diff --git a/packages/flutter_tools/lib/src/android/android_builder.dart b/packages/flutter_tools/lib/src/android/android_builder.dart index 70a7d9ff3bd22..0ece6ceaaf09a 100644 --- a/packages/flutter_tools/lib/src/android/android_builder.dart +++ b/packages/flutter_tools/lib/src/android/android_builder.dart @@ -43,14 +43,8 @@ abstract class AndroidBuilder { /// Returns a list of available build variant from the Android project. Future> getBuildVariants({required FlutterProject project}); - /// Returns the application id for the given build variant. - Future getApplicationIdForVariant( - String buildVariant, { - required FlutterProject project, - }); - - /// Returns a list of app link domains for the given build variant. - Future> getAppLinkDomainsForVariant( + /// Outputs app link related project settings into a json file. + Future outputsAppLinkSettings( String buildVariant, { required FlutterProject project, }); diff --git a/packages/flutter_tools/lib/src/android/gradle.dart b/packages/flutter_tools/lib/src/android/gradle.dart index 6341cc173d752..c116923739fd8 100644 --- a/packages/flutter_tools/lib/src/android/gradle.dart +++ b/packages/flutter_tools/lib/src/android/gradle.dart @@ -52,31 +52,8 @@ final RegExp _kBuildVariantRegex = RegExp('^BuildVariant: (?<$_kBuildVariantRege const String _kBuildVariantRegexGroupName = 'variant'; const String _kBuildVariantTaskName = 'printBuildVariants'; -/// The regex to grab variant names from print${BuildVariant}ApplicationId gradle task -/// -/// The task is defined in flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy -/// -/// The expected output from the task should be similar to: -/// -/// ApplicationId: com.example.my_id -final RegExp _kApplicationIdRegex = RegExp('^ApplicationId: (?<$_kApplicationIdRegexGroupName>.*)\$'); -const String _kApplicationIdRegexGroupName = 'applicationId'; -String _getPrintApplicationIdTaskFor(String buildVariant) { - return _taskForBuildVariant('print', buildVariant, 'ApplicationId'); -} - -/// The regex to grab app link domains from print${BuildVariant}AppLinkDomains gradle task -/// -/// The task is defined in flutter/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy -/// -/// The expected output from the task should be similar to: -/// -/// Domain: domain.com -/// Domain: another-domain.dev -final RegExp _kAppLinkDomainsRegex = RegExp('^Domain: (?<$_kAppLinkDomainsGroupName>.*)\$'); -const String _kAppLinkDomainsGroupName = 'domain'; -String _getPrintAppLinkDomainsTaskFor(String buildVariant) { - return _taskForBuildVariant('print', buildVariant, 'AppLinkDomains'); +String _getOutputAppLinkSettingsTaskFor(String buildVariant) { + return _taskForBuildVariant('output', buildVariant, 'AppLinkSettings'); } /// The directory where the APK artifact is generated. @@ -817,11 +794,11 @@ class AndroidGradleBuilder implements AndroidBuilder { } @override - Future getApplicationIdForVariant( + Future outputsAppLinkSettings( String buildVariant, { required FlutterProject project, }) async { - final String taskName = _getPrintApplicationIdTaskFor(buildVariant); + final String taskName = _getOutputAppLinkSettingsTaskFor(buildVariant); final Stopwatch sw = Stopwatch() ..start(); final RunResult result = await _runGradleTask( @@ -829,50 +806,12 @@ class AndroidGradleBuilder implements AndroidBuilder { options: const ['-q'], project: project, ); - _usage.sendTiming('print', 'application id', sw.elapsed); + _usage.sendTiming('outputs', 'app link settings', sw.elapsed); if (result.exitCode != 0) { _logger.printStatus(result.stdout, wrap: false); _logger.printError(result.stderr, wrap: false); - return ''; - } - for (final String line in LineSplitter.split(result.stdout)) { - final RegExpMatch? match = _kApplicationIdRegex.firstMatch(line); - if (match != null) { - return match.namedGroup(_kApplicationIdRegexGroupName)!; - } - } - return ''; - } - - @override - Future> getAppLinkDomainsForVariant( - String buildVariant, { - required FlutterProject project, - }) async { - final String taskName = _getPrintAppLinkDomainsTaskFor(buildVariant); - final Stopwatch sw = Stopwatch() - ..start(); - final RunResult result = await _runGradleTask( - taskName, - options: const ['-q'], - project: project, - ); - _usage.sendTiming('print', 'application id', sw.elapsed); - - if (result.exitCode != 0) { - _logger.printStatus(result.stdout, wrap: false); - _logger.printError(result.stderr, wrap: false); - return const []; - } - final List domains = []; - for (final String line in LineSplitter.split(result.stdout)) { - final RegExpMatch? match = _kAppLinkDomainsRegex.firstMatch(line); - if (match != null) { - domains.add(match.namedGroup(_kAppLinkDomainsGroupName)!); - } } - return domains; } } diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 1aee9c281b29a..6ded1d332fefd 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -7,7 +7,6 @@ import 'package:xml/xml.dart'; import 'package:yaml/yaml.dart'; import '../src/convert.dart'; -import 'android/android_app_link_settings.dart'; import 'android/android_builder.dart'; import 'android/gradle_utils.dart' as gradle; import 'base/common.dart'; @@ -486,20 +485,15 @@ class AndroidProject extends FlutterProjectPlatform { return androidBuilder!.getBuildVariants(project: parent); } - /// Returns app link related project settings for a given build variant. + /// Outputs app link related settings into a json file. /// - /// Use [getBuildVariants] to get all of the available build variants. - Future getAppLinksSettings({required String variant}) async { + /// The file is stored in + /// `/build/app/app-link-settings-.json`. + Future outputsAppLinkSettings({required String variant}) async { if (!existsSync() || androidBuilder == null) { - return const AndroidAppLinkSettings( - applicationId: '', - domains: [], - ); + return; } - return AndroidAppLinkSettings( - applicationId: await androidBuilder!.getApplicationIdForVariant(variant, project: parent), - domains: await androidBuilder!.getAppLinkDomainsForVariant(variant, project: parent), - ); + await androidBuilder!.outputsAppLinkSettings(variant, project: parent); } bool _computeSupportedVersion() { diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 57228a9bdf75d..531e88408e162 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -7,7 +7,6 @@ import 'dart:async'; import 'package:meta/meta.dart' show visibleForTesting; import 'package:vm_service/vm_service.dart' as vm_service; -import 'android/android_app_link_settings.dart'; import 'base/common.dart'; import 'base/context.dart'; import 'base/io.dart' as io; @@ -43,9 +42,7 @@ const String kCompileExpressionServiceName = 'compileExpression'; const String kFlutterMemoryInfoServiceName = 'flutterMemoryInfo'; const String kFlutterGetSkSLServiceName = 'flutterGetSkSL'; const String kFlutterGetIOSBuildOptionsServiceName = 'flutterGetIOSBuildOptions'; -const String kFlutterGetAndroidBuildVariantsServiceName = 'flutterGetAndroidBuildVariants'; const String kFlutterGetIOSUniversalLinkSettingsServiceName = 'flutterGetIOSUniversalLinkSettings'; -const String kFlutterGetAndroidAppLinkSettingsName = 'flutterGetAndroidAppLinkSettings'; /// The error response code from an unrecoverable compilation failure. const int kIsolateReloadBarred = 1005; @@ -341,19 +338,6 @@ Future setUpVmService({ vmService.registerService(kFlutterGetIOSBuildOptionsServiceName, kFlutterToolAlias), ); - vmService.registerServiceCallback(kFlutterGetAndroidBuildVariantsServiceName, (Map params) async { - final List options = await flutterProject.android.getBuildVariants(); - return { - 'result': { - kResultType: kResultTypeSuccess, - 'variants': options, - }, - }; - }); - registrationRequests.add( - vmService.registerService(kFlutterGetAndroidBuildVariantsServiceName, kFlutterToolAlias), - ); - vmService.registerServiceCallback(kFlutterGetIOSUniversalLinkSettingsServiceName, (Map params) async { final XcodeUniversalLinkSettings settings = await flutterProject.ios.universalLinkSettings( configuration: params['configuration']! as String, @@ -372,21 +356,6 @@ Future setUpVmService({ registrationRequests.add( vmService.registerService(kFlutterGetIOSUniversalLinkSettingsServiceName, kFlutterToolAlias), ); - - vmService.registerServiceCallback(kFlutterGetAndroidAppLinkSettingsName, (Map params) async { - final String variant = params['variant']! as String; - final AndroidAppLinkSettings settings = await flutterProject.android.getAppLinksSettings(variant: variant); - return { - 'result': { - kResultType: kResultTypeSuccess, - 'applicationId': settings.applicationId, - 'domains': settings.domains, - }, - }; - }); - registrationRequests.add( - vmService.registerService(kFlutterGetAndroidAppLinkSettingsName, kFlutterToolAlias), - ); } if (printStructuredErrorLogMethod != null) { diff --git a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart index 217a6911b0369..5f5076c4fb43b 100644 --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart @@ -885,113 +885,13 @@ Gradle Crashed command: [ 'gradlew', '-q', - 'printFreeDebugApplicationId', + 'outputFreeDebugAppLinkSettings', ], - stdout: ''' -ApplicationId: com.example.id - ''', - )); - final String actual = await builder.getApplicationIdForVariant( - 'freeDebug', - project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), - ); - expect(actual, 'com.example.id'); - }, overrides: { - AndroidStudio: () => FakeAndroidStudio(), - }); - - testUsingContext('can call custom gradle task getApplicationIdForVariant with unknown crash', () async { - final AndroidGradleBuilder builder = AndroidGradleBuilder( - java: FakeJava(), - logger: logger, - processManager: processManager, - fileSystem: fileSystem, - artifacts: Artifacts.test(), - usage: testUsage, - gradleUtils: FakeGradleUtils(), - platform: FakePlatform(), - androidStudio: FakeAndroidStudio(), - ); - processManager.addCommand(const FakeCommand( - command: [ - 'gradlew', - '-q', - 'printFreeDebugApplicationId', - ], - stdout: ''' -unknown crash - ''', - )); - final String actual = await builder.getApplicationIdForVariant( - 'freeDebug', - project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), - ); - expect(actual, ''); - }, overrides: { - AndroidStudio: () => FakeAndroidStudio(), - }); - - testUsingContext('can call custom gradle task getAppLinkDomainsForVariant and parse the result', () async { - final AndroidGradleBuilder builder = AndroidGradleBuilder( - java: FakeJava(), - logger: logger, - processManager: processManager, - fileSystem: fileSystem, - artifacts: Artifacts.test(), - usage: testUsage, - gradleUtils: FakeGradleUtils(), - platform: FakePlatform(), - androidStudio: FakeAndroidStudio(), - ); - - processManager.addCommand(const FakeCommand( - command: [ - 'gradlew', - '-q', - 'printFreeDebugAppLinkDomains', - ], - stdout: ''' -Domain: example.com -Domain: example2.com - ''', - )); - final List actual = await builder.getAppLinkDomainsForVariant( - 'freeDebug', - project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), - ); - expect(actual, ['example.com', 'example2.com']); - }, overrides: { - AndroidStudio: () => FakeAndroidStudio(), - }); - - testUsingContext('can call custom gradle task getAppLinkDomainsForVariant with unknown crash', () async { - final AndroidGradleBuilder builder = AndroidGradleBuilder( - java: FakeJava(), - logger: logger, - processManager: processManager, - fileSystem: fileSystem, - artifacts: Artifacts.test(), - usage: testUsage, - gradleUtils: FakeGradleUtils(), - platform: FakePlatform(), - androidStudio: FakeAndroidStudio(), - ); - - processManager.addCommand(const FakeCommand( - command: [ - 'gradlew', - '-q', - 'printFreeDebugAppLinkDomains', - ], - stdout: ''' -unknown crash - ''', )); - final List actual = await builder.getAppLinkDomainsForVariant( + await builder.outputsAppLinkSettings( 'freeDebug', project: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), ); - expect(actual.isEmpty, isTrue); }, overrides: { AndroidStudio: () => FakeAndroidStudio(), }); diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index ff803f7bbc7f3..96105be45bec0 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -78,18 +78,10 @@ const List kAttachIsolateExpectations = 'service': kFlutterGetIOSBuildOptionsServiceName, 'alias': kFlutterToolAlias, }), - FakeVmServiceRequest(method: 'registerService', args: { - 'service': kFlutterGetAndroidBuildVariantsServiceName, - 'alias': kFlutterToolAlias, - }), FakeVmServiceRequest(method: 'registerService', args: { 'service': kFlutterGetIOSUniversalLinkSettingsServiceName, 'alias': kFlutterToolAlias, }), - FakeVmServiceRequest(method: 'registerService', args: { - 'service': kFlutterGetAndroidAppLinkSettingsName, - 'alias': kFlutterToolAlias, - }), FakeVmServiceRequest( method: 'streamListen', args: { diff --git a/packages/flutter_tools/test/general.shard/vmservice_test.dart b/packages/flutter_tools/test/general.shard/vmservice_test.dart index 841e06b51040d..d4f2fc3371f85 100644 --- a/packages/flutter_tools/test/general.shard/vmservice_test.dart +++ b/packages/flutter_tools/test/general.shard/vmservice_test.dart @@ -96,17 +96,6 @@ void main() { expect(mockVMService.services, containsPair(kFlutterGetIOSBuildOptionsServiceName, kFlutterToolAlias)); }); - testWithoutContext('VmService registers flutterGetAndroidBuildVariants service', () async { - final MockVMService mockVMService = MockVMService(); - final FlutterProject mockedFlutterProject = MockFlutterProject(); - await setUpVmService( - flutterProject: mockedFlutterProject, - vmService: mockVMService, - ); - - expect(mockVMService.services, containsPair(kFlutterGetAndroidBuildVariantsServiceName, kFlutterToolAlias)); - }); - testWithoutContext('VM Service registers flutterGetSkSL service', () async { final MockVMService mockVMService = MockVMService(); await setUpVmService( @@ -313,24 +302,6 @@ void main() { expect(result['schemes'], expectedProjectInfo.schemes); }); - testWithoutContext('VmService forward flutterGetAndroidBuildVariants request and response correctly', () async { - final MockVMService vmService = MockVMService(); - final List expectedOptions = ['debug', 'release', 'profile']; - final FlutterProject mockedFlutterProject = MockFlutterProject( - mockedAndroid: MockAndroidProject(mockedOptions: expectedOptions), - ); - await setUpVmService( - flutterProject: mockedFlutterProject, - vmService: vmService - ); - final vm_service.ServiceCallback cb = vmService.serviceCallBacks[kFlutterGetAndroidBuildVariantsServiceName]!; - - final Map response = await cb({}); - final Map result = response['result']! as Map; - expect(result[kResultType], kResultTypeSuccess); - expect(result['variants'], expectedOptions); - }); - testWithoutContext('VmService forward flutterGetIOSBuildOptions request and response correctly when no iOS project', () async { final MockVMService vmService = MockVMService(); final FlutterProject mockedFlutterProject = MockFlutterProject( @@ -940,15 +911,10 @@ void main() { class MockFlutterProject extends Fake implements FlutterProject { MockFlutterProject({ IosProject? mockedIos, - AndroidProject? mockedAndroid, - }) : ios = mockedIos ?? MockIosProject(), - android = mockedAndroid ?? MockAndroidProject(); + }) : ios = mockedIos ?? MockIosProject(); @override final IosProject ios; - - @override - final AndroidProject android; } class MockIosProject extends Fake implements IosProject { @@ -960,15 +926,6 @@ class MockIosProject extends Fake implements IosProject { Future projectInfo() async => mockedInfo; } -class MockAndroidProject extends Fake implements AndroidProject { - MockAndroidProject({this.mockedOptions = const []}); - - final List mockedOptions; - - @override - Future> getBuildVariants() async => mockedOptions; -} - class MockLogger extends Fake implements Logger { } class MockVMService extends Fake implements vm_service.VmService { diff --git a/packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart b/packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart similarity index 68% rename from packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart rename to packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart index 2533b264c535d..7a1bf43babe9a 100644 --- a/packages/flutter_tools/test/integration.shard/android_gradle_print_app_link_domains_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_gradle_outputs_app_link_settings_test.dart @@ -5,7 +5,6 @@ import 'dart:convert'; import 'dart:io' as io; -import 'package:collection/collection.dart'; import 'package:file/file.dart'; import 'package:flutter_tools/src/android/gradle_utils.dart' show getGradlewFileName; @@ -136,8 +135,15 @@ void main() { tryToDelete(tempDir); }); + void testDeeplink(dynamic deeplink, String scheme, String host, String path) { + deeplink as Map; + expect(deeplink['scheme'], scheme); + expect(deeplink['host'], host); + expect(deeplink['path'], path); + } + testWithoutContext( - 'gradle task exists named printAppLinkDomains that prints app link domains', () async { + 'gradle task outputsAppLinkSettings works when a project has app links', () async { // Create a new flutter project. final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); @@ -173,17 +179,61 @@ void main() { '.${platform.pathSeparator}${getGradlewFileName(platform)}', ...getLocalEngineArguments(), '-q', // quiet output. - 'printDebugAppLinkDomains', + 'outputDebugAppLinkSettings', + ], workingDirectory: androidApp.path); + + expect(result, const ProcessResultMatcher()); + + final io.File fileDump = tempDir.childDirectory('build').childDirectory('app').childFile('app-link-settings-debug.json'); + expect(fileDump.existsSync(), true); + final Map json = jsonDecode(fileDump.readAsStringSync()) as Map; + expect(json['applicationId'], 'com.example.testapp'); + final List deeplinks = json['deeplinks']! as List; + expect(deeplinks.length, 5); + testDeeplink(deeplinks[0], 'http', 'pure-http.com', '.*'); + testDeeplink(deeplinks[1], 'custom', 'custom.com', '.*'); + testDeeplink(deeplinks[2], 'custom', 'hybrid.com', '.*'); + testDeeplink(deeplinks[3], 'http', 'hybrid.com', '.*'); + testDeeplink(deeplinks[4], 'http', 'non-auto-verify.com', '.*'); + }); + + testWithoutContext( + 'gradle task outputsAppLinkSettings works when a project does not have app link', () async { + // Create a new flutter project. + final String flutterBin = + fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); + ProcessResult result = await processManager.run([ + flutterBin, + 'create', + tempDir.path, + '--project-name=testapp', + ], workingDirectory: tempDir.path); + expect(result, const ProcessResultMatcher()); + + // Ensure that gradle files exists from templates. + result = await processManager.run([ + flutterBin, + 'build', + 'apk', + '--config-only', + ], workingDirectory: tempDir.path); + expect(result, const ProcessResultMatcher()); + + final Directory androidApp = tempDir.childDirectory('android'); + result = await processManager.run([ + '.${platform.pathSeparator}${getGradlewFileName(platform)}', + ...getLocalEngineArguments(), + '-q', // quiet output. + 'outputDebugAppLinkSettings', ], workingDirectory: androidApp.path); expect(result, const ProcessResultMatcher()); - const List expectedLines = [ - // Should only pick up the pure and hybrid intent filters - 'Domain: pure-http.com', - 'Domain: hybrid.com', - ]; - final List actualLines = LineSplitter.split(result.stdout.toString()).toList(); - expect(const ListEquality().equals(actualLines, expectedLines), isTrue); + final io.File fileDump = tempDir.childDirectory('build').childDirectory('app').childFile('app-link-settings-debug.json'); + expect(fileDump.existsSync(), true); + final Map json = jsonDecode(fileDump.readAsStringSync()) as Map; + expect(json['applicationId'], 'com.example.testapp'); + final List deeplinks = json['deeplinks']! as List; + expect(deeplinks.length, 0); }); } diff --git a/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart b/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart deleted file mode 100644 index 82ec3c84f410e..0000000000000 --- a/packages/flutter_tools/test/integration.shard/android_gradle_print_application_id_test.dart +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:convert'; - -import 'package:collection/collection.dart'; -import 'package:file/file.dart'; -import 'package:flutter_tools/src/android/gradle_utils.dart' - show getGradlewFileName; -import 'package:flutter_tools/src/base/io.dart'; - -import '../src/common.dart'; -import 'test_utils.dart'; - -void main() { - late Directory tempDir; - - setUp(() async { - tempDir = createResolvedTempDirectorySync('run_test.'); - }); - - tearDown(() async { - tryToDelete(tempDir); - }); - - testWithoutContext( - 'gradle task exists named printApplicationId that prints application id', () async { - // Create a new flutter project. - final String flutterBin = - fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); - ProcessResult result = await processManager.run([ - flutterBin, - 'create', - tempDir.path, - '--project-name=testapp', - ], workingDirectory: tempDir.path); - expect(result, const ProcessResultMatcher()); - // Ensure that gradle files exists from templates. - result = await processManager.run([ - flutterBin, - 'build', - 'apk', - '--config-only', - ], workingDirectory: tempDir.path); - expect(result, const ProcessResultMatcher()); - - final Directory androidApp = tempDir.childDirectory('android'); - result = await processManager.run([ - '.${platform.pathSeparator}${getGradlewFileName(platform)}', - ...getLocalEngineArguments(), - '-q', // quiet output. - 'printDebugApplicationId', - ], workingDirectory: androidApp.path); - // Verify that gradlew has a javaVersion task. - expect(result, const ProcessResultMatcher()); - // Verify the format is a number on its own line. - const List expectedLines = [ - 'ApplicationId: com.example.testapp', - ]; - final List actualLines = LineSplitter.split(result.stdout.toString()).toList(); - expect(const ListEquality().equals(actualLines, expectedLines), isTrue); - }); -} diff --git a/packages/flutter_tools/test/src/android_common.dart b/packages/flutter_tools/test/src/android_common.dart index 109eb0ef6d338..2b1624d6a9bf9 100644 --- a/packages/flutter_tools/test/src/android_common.dart +++ b/packages/flutter_tools/test/src/android_common.dart @@ -41,10 +41,11 @@ class FakeAndroidBuilder implements AndroidBuilder { Future> getBuildVariants({required FlutterProject project}) async => const []; @override - Future> getAppLinkDomainsForVariant(String buildVariant, {required FlutterProject project}) async => const []; + Future outputsAppLinkSettings( + String buildVariant, { + required FlutterProject project, + }) async {} - @override - Future getApplicationIdForVariant(String buildVariant, {required FlutterProject project}) async => ''; } /// Creates a [FlutterProject] in a directory named [flutter_project] From 58171f0923fad0bfb7591d6fbb9a034c68a20ef8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 18 Aug 2023 15:23:06 -0400 Subject: [PATCH 0794/1547] Roll Flutter Engine from 83fdadaf12f0 to 72c4e61fdbfa (2 revisions) (#132861) https://github.com/flutter/engine/compare/83fdadaf12f0...72c4e61fdbfa 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from 31baf15e8f2c to e3adabdd0511 (2 revisions) (flutter/engine#44851) 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from c9294edc03b9 to 31baf15e8f2c (10 revisions) (flutter/engine#44850) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7b1739bf2b49d..a13aab9333cc8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -83fdadaf12f00ef0ca3aa9401918a2486fcb89a2 +72c4e61fdbfa7224136a7abfe6d05593d2fd76ad From 1bdef6fea7167336dc85f5b40662c76fcd2fb090 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 18 Aug 2023 17:09:19 -0400 Subject: [PATCH 0795/1547] Roll Flutter Engine from 72c4e61fdbfa to 654d3a2c8494 (3 revisions) (#132868) https://github.com/flutter/engine/compare/72c4e61fdbfa...654d3a2c8494 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from edf0c0ecc7b1 to cf37d99d844d (1 revision) (flutter/engine#44857) 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from e3adabdd0511 to edf0c0ecc7b1 (3 revisions) (flutter/engine#44854) 2023-08-18 jason-simmons@users.noreply.github.com Flush pending graphics commands when the unref queue is drained on the IO thread (flutter/engine#44831) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a13aab9333cc8..f99096a841cd5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -72c4e61fdbfa7224136a7abfe6d05593d2fd76ad +654d3a2c84946c5cfd7f6ebd932b050fa3ccb987 From d5a162b788982186c07d5807e89ca2c28d185534 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Fri, 18 Aug 2023 15:33:27 -0700 Subject: [PATCH 0796/1547] Forward port API docs creation realm handling from prior script (#132867) It looks like the logic added here: https://github.com/flutter/flutter/pull/131951/files#diff-297ee4cfe6d9bffc2fa1376918a50b8e4165ada4569575880c40811b6f749265R18 got dropped in the refactor here: https://github.com/flutter/flutter/pull/132710 --- dev/tools/create_api_docs.dart | 14 ++++++++++++-- dev/tools/test/create_api_docs_test.dart | 12 ++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index 4cbef2287f7c2..0119b5fb4db1e 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -775,16 +775,19 @@ class PlatformDocGenerator { final FileSystem filesystem; final Directory outputDir; final String engineRevision = FlutterInformation.instance.getEngineRevision(); + final String engineRealm = FlutterInformation.instance.getEngineRealm(); /// This downloads an archive of platform docs for the engine from the artifact /// store and extracts them to the location used for Dartdoc. void generatePlatformDocs() { + final String realm = engineRealm.isNotEmpty ? '$engineRealm/' : ''; + final String javadocUrl = - 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; + 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); final String objcdocUrl = - 'https://storage.googleapis.com/flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; + 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); } @@ -1034,6 +1037,10 @@ class FlutterInformation { /// Gets the git hash of the engine used by the Flutter framework in the repo. String getEngineRevision() => getFlutterInformation()['engineRevision']! as String; + /// Gets the value stored in bin/internal/engine.realm used by the Flutter + /// framework repo. + String getEngineRealm() => getFlutterInformation()['engineRealm']! as String; + /// Gets the git hash of the Flutter framework in the repo. String getFlutterRevision() => getFlutterInformation()['flutterGitRevision']! as String; @@ -1090,6 +1097,9 @@ class FlutterInformation { info['flutterRoot'] = flutterRoot; info['frameworkVersion'] = Version.parse(flutterVersion['frameworkVersion'] as String); info['engineRevision'] = flutterVersion['engineRevision'] as String; + info['engineRealm'] = filesystem.file( + path.join(flutterRoot.path, 'bin', 'internal', 'engine.realm', + )).readAsStringSync().trim(); final RegExpMatch? dartVersionRegex = RegExp(r'(?[\d.]+)(?:\s+\(build (?[-.\w]+)\))?') .firstMatch(flutterVersion['dartSdkVersion'] as String); diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart index 31703a1b1cdb5..edf4b63d2a3dc 100644 --- a/dev/tools/test/create_api_docs_test.dart +++ b/dev/tools/test/create_api_docs_test.dart @@ -4,6 +4,7 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; +import 'package:path/path.dart' as path; import 'package:platform/platform.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; @@ -179,6 +180,17 @@ void main() { expect(info['dartSdkVersion'], isNotNull); expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev'))); }); + test('the engine realm is read from the engine.realm file', () async { + const String flutterRoot = '/home/user/flutter'; + final File realmFile = memoryFileSystem.file( + path.join(flutterRoot, 'bin', 'internal', 'engine.realm', + )); + realmFile.writeAsStringSync('realm'); + setUpWithEnvironment({'FLUTTER_ROOT': flutterRoot}); + expect(fakeProcessManager, hasNoRemainingExpectations); + final Map info = flutterInformation.getFlutterInformation(); + expect(info['engineRealm'], equals('realm')); + }); }); } From 2ecb8866a2a6d68f797b818ea3e4857dc7a2996f Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Fri, 18 Aug 2023 16:45:16 -0700 Subject: [PATCH 0797/1547] SelectionArea on iOS should toggle the context menu when tapping on the previous selection (#132851) https://github.com/flutter/flutter/assets/948037/210fdee4-d922-422b-a257-4ee586a3814f Related: https://github.com/flutter/flutter/issues/129583 --- .../lib/src/widgets/selectable_region.dart | 15 +++- .../test/widgets/selectable_region_test.dart | 72 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 4b3d6e3730a15..16711e25d61b8 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -341,7 +341,20 @@ class SelectableRegionState extends State with TextSelectionDe _gestureRecognizers[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => TapGestureRecognizer(debugOwner: this), (TapGestureRecognizer instance) { - instance.onTap = _clearSelection; + instance.onTapUp = (TapUpDetails details) { + if (defaultTargetPlatform == TargetPlatform.iOS && _positionIsOnActiveSelection(globalPosition: details.globalPosition)) { + // On iOS when the tap occurs on the previous selection, instead of + // moving the selection, the context menu will be toggled. + final bool toolbarIsVisible = _selectionOverlay?.toolbarIsVisible ?? false; + if (toolbarIsVisible) { + hideToolbar(false); + } else { + _showToolbar(location: details.globalPosition); + } + } else { + _clearSelection(); + } + }; instance.onSecondaryTapDown = _handleRightClickDown; }, ); diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 2f70f266f9d58..a2e8bcb67fad4 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -886,6 +886,78 @@ void main() { await gesture.up(); }); + testWidgets( + 'single tap on the previous selection toggles the toolbar on iOS', + (WidgetTester tester) async { + Set buttonTypes = {}; + final UniqueKey toolbarKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionHandleControls, + contextMenuBuilder: ( + BuildContext context, + SelectableRegionState selectableRegionState, + ) { + buttonTypes = selectableRegionState.contextMenuButtonItems + .map((ContextMenuButtonItem buttonItem) => buttonItem.type) + .toSet(); + return SizedBox.shrink(key: toolbarKey); + }, + child: const Column( + children: [ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + + expect(buttonTypes.isEmpty, true); + expect(find.byKey(toolbarKey), findsNothing); + + final RenderParagraph paragraph = tester.renderObject(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2)); + addTearDown(gesture.removePointer); + await tester.pump(const Duration(milliseconds: 500)); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + expect(buttonTypes, contains(ContextMenuButtonType.copy)); + expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); + expect(find.byKey(toolbarKey), findsOneWidget); + + await gesture.down(textOffsetToPosition(paragraph, 2)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + expect(buttonTypes, contains(ContextMenuButtonType.copy)); + expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); + expect(find.byKey(toolbarKey), findsNothing); + + await gesture.down(textOffsetToPosition(paragraph, 2)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + expect(buttonTypes, contains(ContextMenuButtonType.copy)); + expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); + expect(find.byKey(toolbarKey), findsOneWidget); + + // Clear selection. + await tester.tapAt(textOffsetToPosition(paragraph, 9)); + await tester.pump(); + expect(paragraph.selections.isEmpty, true); + expect(find.byKey(toolbarKey), findsNothing); + }, + variant: TargetPlatformVariant.only(TargetPlatform.iOS), + skip: kIsWeb, // [intended] Web uses its native context menu. + ); + testWidgets( 'right-click mouse can select word at position on Apple platforms', (WidgetTester tester) async { From 6d757046f42906f6782e57cd24fa32c5613336f4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 18 Aug 2023 20:37:23 -0400 Subject: [PATCH 0798/1547] Roll Flutter Engine from 654d3a2c8494 to f4bffdcf8536 (5 revisions) (#132876) https://github.com/flutter/engine/compare/654d3a2c8494...f4bffdcf8536 2023-08-18 jacksongardner@google.com Allow optional codepoints to be expressed to the font subset generator. (flutter/engine#44864) 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from 2ddec49abd5c to e9cf3f1740eb (3 revisions) (flutter/engine#44862) 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from 2dd1ed0baa7d to 2ddec49abd5c (2 revisions) (flutter/engine#44860) 2023-08-18 skia-flutter-autoroll@skia.org Roll Skia from cf37d99d844d to 2dd1ed0baa7d (1 revision) (flutter/engine#44859) 2023-08-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 8109103e041b to a4908f67b63e (2 revisions) (flutter/engine#44858) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f99096a841cd5..2d229a1f8e8eb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -654d3a2c84946c5cfd7f6ebd932b050fa3ccb987 +f4bffdcf8536b24927ae2cdf39e291e187d63f33 From 6f227c078430d9c05f0944b6afcf750bd0d4b8d3 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Fri, 18 Aug 2023 19:04:15 -0700 Subject: [PATCH 0799/1547] Space character should be optional when tree shaking fonts (#132880) Addresses the other part of https://github.com/flutter/flutter/issues/132711 --- .../targets/icon_tree_shaker.dart | 26 +++++++++++++------ .../targets/icon_tree_shaker_test.dart | 4 +-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart b/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart index 91557e7b06bfc..7f3b0dee8bd56 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart @@ -138,15 +138,15 @@ class IconTreeShaker { if (codePoints == null) { throw IconTreeShakerException._('Expected to font code points for ${entry.key}, but none were found.'); } - if (_targetPlatform == TargetPlatform.web_javascript) { - if (!codePoints.contains(kSpacePoint)) { - codePoints.add(kSpacePoint); - } - } + + // Add space as an optional code point, as web uses it to measure the font height. + final List optionalCodePoints = _targetPlatform == TargetPlatform.web_javascript + ? [kSpacePoint] : []; result[entry.value] = _IconTreeShakerData( family: entry.key, relativePath: entry.value, codePoints: codePoints, + optionalCodePoints: optionalCodePoints, ); } _iconData = result; @@ -197,12 +197,17 @@ class IconTreeShaker { outputPath, input.path, ]; - final String codePoints = iconTreeShakerData.codePoints.join(' '); + final Iterable requiredCodePointStrings = iconTreeShakerData.codePoints + .map((int codePoint) => codePoint.toString()); + final Iterable optionalCodePointStrings = iconTreeShakerData.optionalCodePoints + .map((int codePoint) => 'optional:$codePoint'); + final String codePointsString = requiredCodePointStrings + .followedBy(optionalCodePointStrings).join(' '); _logger.printTrace('Running font-subset: ${cmd.join(' ')}, ' - 'using codepoints $codePoints'); + 'using codepoints $codePointsString'); final Process fontSubsetProcess = await _processManager.start(cmd); try { - fontSubsetProcess.stdin.writeln(codePoints); + fontSubsetProcess.stdin.writeln(codePointsString); await fontSubsetProcess.stdin.flush(); await fontSubsetProcess.stdin.close(); } on Exception { @@ -369,6 +374,7 @@ class _IconTreeShakerData { required this.family, required this.relativePath, required this.codePoints, + required this.optionalCodePoints, }); /// The font family name, e.g. "MaterialIcons". @@ -380,6 +386,10 @@ class _IconTreeShakerData { /// The list of code points for the font. final List codePoints; + /// The list of code points to be optionally added, if they exist in the + /// input font. Otherwise, the tool will silently omit them. + final List optionalCodePoints; + @override String toString() => 'FontSubsetData($family, $relativePath, $codePoints)'; } diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/icon_tree_shaker_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/icon_tree_shaker_test.dart index d786570798a1a..cb493e7cec765 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/icon_tree_shaker_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/icon_tree_shaker_test.dart @@ -411,7 +411,7 @@ void main() { expect(result, isTrue); final List codePoints = stdinSink.getAndClear().trim().split(whitespace); - expect(codePoints, isNot(contains('32'))); + expect(codePoints, isNot(contains('optional:32'))); expect(processManager, hasNoRemainingExpectations); }); @@ -456,7 +456,7 @@ void main() { expect(result, isTrue); final List codePoints = stdinSink.getAndClear().trim().split(whitespace); - expect(codePoints, containsAllInOrder(const ['59470', '32'])); + expect(codePoints, containsAllInOrder(const ['59470', 'optional:32'])); expect(processManager, hasNoRemainingExpectations); }); From 4ac85071e1a2520553cd6b80e93fc6dc5a9ff56d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 20 Aug 2023 19:08:40 -0400 Subject: [PATCH 0800/1547] Roll Flutter Engine from f4bffdcf8536 to 2dcfb6cb7e49 (4 revisions) (#132914) https://github.com/flutter/engine/compare/f4bffdcf8536...2dcfb6cb7e49 2023-08-20 skia-flutter-autoroll@skia.org Roll Skia from e9cf3f1740eb to 4f6b9d08b6d1 (2 revisions) (flutter/engine#44868) 2023-08-20 jonahwilliams@google.com Revert "Implementing TextScaler for nonlinear text scaling" (flutter/engine#44882) 2023-08-18 737941+loic-sharma@users.noreply.github.com [Embedder API] Add semantic string attributes (flutter/engine#44616) 2023-08-18 31859944+LongCatIsLooong@users.noreply.github.com Implementing TextScaler for nonlinear text scaling (flutter/engine#42062) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2d229a1f8e8eb..a223b12b6fc3c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f4bffdcf8536b24927ae2cdf39e291e187d63f33 +2dcfb6cb7e494d9cfa316dcddbf94e9109bc01cb From 3b7831acf306f4139ee71b3d683b28e078a05e2a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 20 Aug 2023 20:02:42 -0400 Subject: [PATCH 0801/1547] Roll Flutter Engine from 2dcfb6cb7e49 to 394554bd1630 (4 revisions) (#132918) https://github.com/flutter/engine/compare/2dcfb6cb7e49...394554bd1630 2023-08-20 chinmaygarde@google.com [Impeller] Document threading configuration with Vulkan. (flutter/engine#44874) 2023-08-20 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from onEHyyETXAMieDyfP... to fiGH0e7wu87NiNtTr... (flutter/engine#44875) 2023-08-20 skia-flutter-autoroll@skia.org Roll Dart SDK from a4908f67b63e to 632c8cccd30c (2 revisions) (flutter/engine#44872) 2023-08-20 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from pSqQ556xmZp7S4np5... to iQbvLoFBbhU8pkkqw... (flutter/engine#44878) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from pSqQ556xmZp7 to iQbvLoFBbhU8 fuchsia/sdk/core/mac-amd64 from onEHyyETXAMi to fiGH0e7wu87N If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a223b12b6fc3c..804c7cb3a4f2f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2dcfb6cb7e494d9cfa316dcddbf94e9109bc01cb +394554bd1630be06983c8e367d9efc4cd2195040 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 88c8e473eee55..c635e3ba45a91 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -pSqQ556xmZp7S4np5xyQXWu-Ul-5qoxDxu8WXLe2_xIC +iQbvLoFBbhU8pkkqwv_aYZJl-o6VuBXtm09qR63mFIEC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 39bc51a6e2b8e..648f5aaf7f520 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -onEHyyETXAMieDyfP8hzVi3zqabh27iPDE9waYIkPc0C +fiGH0e7wu87NiNtTrdmMJXDKjhuYP--6b-UzpOT55dIC From 45e464cb9dab441a8480cbc1317790dab2ff00bc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 20 Aug 2023 21:57:22 -0400 Subject: [PATCH 0802/1547] Roll Flutter Engine from 394554bd1630 to 8c7ce6ddde0f (2 revisions) (#132921) https://github.com/flutter/engine/compare/394554bd1630...8c7ce6ddde0f 2023-08-20 skia-flutter-autoroll@skia.org Roll Skia from 4f6b9d08b6d1 to d2369dac4a1d (6 revisions) (flutter/engine#44883) 2023-08-20 bdero@google.com [Impeller] Fix clip management for DrawPicture. (flutter/engine#44835) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 804c7cb3a4f2f..54ff6cf21b567 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -394554bd1630be06983c8e367d9efc4cd2195040 +8c7ce6ddde0fca50aa59dbd49e887d3c892473a3 From c328d039288b4fb59be3c27aedce6f27e79cf725 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 20 Aug 2023 23:21:32 -0400 Subject: [PATCH 0803/1547] Roll Flutter Engine from 8c7ce6ddde0f to e7d745111795 (1 revision) (#132925) https://github.com/flutter/engine/compare/8c7ce6ddde0f...e7d745111795 2023-08-21 skia-flutter-autoroll@skia.org Roll Dart SDK from 632c8cccd30c to c839eea7f0fa (1 revision) (flutter/engine#44886) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 54ff6cf21b567..47e423ba16356 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8c7ce6ddde0fca50aa59dbd49e887d3c892473a3 +e7d7451117950ca58f1112be02a7a5369c4b55b3 From 777192651705e8d64947c7d2f4be2b249e1af2b3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 04:41:22 -0400 Subject: [PATCH 0804/1547] Roll Flutter Engine from e7d745111795 to 36ab259a61ed (2 revisions) (#132937) https://github.com/flutter/engine/compare/e7d745111795...36ab259a61ed 2023-08-21 flar@google.com Split DisplayListBuilder into DlCanvas optimizer and DlOp recorder classes (flutter/engine#44718) 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from d2369dac4a1d to fca8fac08117 (1 revision) (flutter/engine#44888) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 47e423ba16356..65fcba3bdddcd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e7d7451117950ca58f1112be02a7a5369c4b55b3 +36ab259a61ed971e210b681dbd2c7c880d56a46d From 89e8295839c45fe881fb52f7771b41ba1de5eb3a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 06:55:24 -0400 Subject: [PATCH 0805/1547] Roll Flutter Engine from 36ab259a61ed to e2d9809d1af3 (1 revision) (#132944) https://github.com/flutter/engine/compare/36ab259a61ed...e2d9809d1af3 2023-08-21 skia-flutter-autoroll@skia.org Roll Dart SDK from c839eea7f0fa to af7860c1b2a5 (1 revision) (flutter/engine#44893) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 65fcba3bdddcd..daccf0ed933f5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -36ab259a61ed971e210b681dbd2c7c880d56a46d +e2d9809d1af3a3d34b6b0031a75e16416c0978e3 From 3c0f7ca6b5d2f0c494a235ec83fde6993109680e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 07:48:31 -0400 Subject: [PATCH 0806/1547] Roll Flutter Engine from e2d9809d1af3 to 14be26c91620 (2 revisions) (#132946) https://github.com/flutter/engine/compare/e2d9809d1af3...14be26c91620 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from fca8fac08117 to 475f07f5ca14 (2 revisions) (flutter/engine#44896) 2023-08-21 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from fiGH0e7wu87NiNtTr... to aXDvHIK6XMKTHieu_... (flutter/engine#44894) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from fiGH0e7wu87N to aXDvHIK6XMKT If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index daccf0ed933f5..9406277f7a2a5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e2d9809d1af3a3d34b6b0031a75e16416c0978e3 +14be26c91620d6c071ff0ada5f7fb8408122a33f diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 648f5aaf7f520..19f6d0ff21624 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -fiGH0e7wu87NiNtTrdmMJXDKjhuYP--6b-UzpOT55dIC +aXDvHIK6XMKTHieu_Lz24exKSmxWpRqXS5f3B7_Y1DEC From 5e6d88d766b91930f347f21417899a963eafc208 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 11:58:24 -0400 Subject: [PATCH 0807/1547] Roll Flutter Engine from 14be26c91620 to a9b00783bc7c (2 revisions) (#132955) https://github.com/flutter/engine/compare/14be26c91620...a9b00783bc7c 2023-08-21 skia-flutter-autoroll@skia.org Roll Dart SDK from af7860c1b2a5 to 7dd53a3df4cf (1 revision) (flutter/engine#44898) 2023-08-21 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from iQbvLoFBbhU8pkkqw... to lDn2QLh1I7rtNu01y... (flutter/engine#44895) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from iQbvLoFBbhU8 to lDn2QLh1I7rt If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9406277f7a2a5..9a53d42dcf065 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -14be26c91620d6c071ff0ada5f7fb8408122a33f +a9b00783bc7cf1b2577d888660e03f84291ca762 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index c635e3ba45a91..749b7da3efd9d 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -iQbvLoFBbhU8pkkqwv_aYZJl-o6VuBXtm09qR63mFIEC +lDn2QLh1I7rtNu01ySR9vzGYwVjpCO1GD89M5cyrXQ0C From e425b680460a8596217a736049799049d512f4d2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 12:12:07 -0400 Subject: [PATCH 0808/1547] Roll Packages from 4c16f3ef4033 to e26f3b9374d0 (5 revisions) (#132960) https://github.com/flutter/packages/compare/4c16f3ef4033...e26f3b9374d0 2023-08-21 raul.silveira@popcode.com.br [camera_android]: Fixes crash when record video on Android versions lower than 12 (flutter/packages#4635) 2023-08-19 engine-flutter-autoroll@skia.org Roll Flutter from 5a556f8ecde6 to 6f227c078430 (11 revisions) (flutter/packages#4749) 2023-08-18 10687576+bparrishMines@users.noreply.github.com Update release action Flutter version to 3.13.0 (flutter/packages#4745) 2023-08-18 stuartmorgan@google.com [google_maps_flutter] Fix async handling in examples (flutter/packages#4729) 2023-08-18 engine-flutter-autoroll@skia.org Roll Flutter from 2502b51f86c1 to 5a556f8ecde6 (42 revisions) (flutter/packages#4743) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 1e5628ab5aeb8..0a77a7cd892a5 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -4c16f3ef40333aa0aebe8a1e46ef7b9fef9a1c1f +e26f3b9374d062e814a279116a90dcdd5fbfa925 From 27dd111ad5da70cad6d72e592c8aa784c64d9735 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 13:06:42 -0400 Subject: [PATCH 0809/1547] Roll Flutter Engine from a9b00783bc7c to 0290d0bd79ee (1 revision) (#132962) https://github.com/flutter/engine/compare/a9b00783bc7c...0290d0bd79ee 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from 475f07f5ca14 to 7e5a3009a8d4 (1 revision) (flutter/engine#44900) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9a53d42dcf065..2997049112b99 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a9b00783bc7cf1b2577d888660e03f84291ca762 +0290d0bd79eef30c51494437e22624f4c3baaa0d From aeddab428d4d51dc2e7b070969572067a37d3650 Mon Sep 17 00:00:00 2001 From: fzyzcjy <5236035+fzyzcjy@users.noreply.github.com> Date: Tue, 22 Aug 2023 01:12:06 +0800 Subject: [PATCH 0810/1547] When resized network image has error, all future unrelated images using the same url will fail, even if the network becomes OK (#127456) Close #127265 The CI fails because of simple analyzer errors. Thus, I would like to hear your opinions first! --- .../lib/src/painting/image_provider.dart | 15 ++++ .../lib/src/painting/image_stream.dart | 81 ++++++++++++++++++- .../image_provider_network_image_test.dart | 38 ++++++++- packages/flutter/test/widgets/image_test.dart | 6 +- 4 files changed, 132 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index 0689ad192d423..54e21cc5977ef 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -1355,6 +1355,7 @@ class ResizeImage extends ImageProvider { if (!kReleaseMode) { completer.debugLabel = '${completer.debugLabel} - Resized(${key._width}×${key._height})'; } + _configureErrorListener(completer, key); return completer; } @@ -1377,6 +1378,7 @@ class ResizeImage extends ImageProvider { if (!kReleaseMode) { completer.debugLabel = '${completer.debugLabel} - Resized(${key._width}×${key._height})'; } + _configureErrorListener(completer, key); return completer; } @@ -1446,9 +1448,22 @@ class ResizeImage extends ImageProvider { if (!kReleaseMode) { completer.debugLabel = '${completer.debugLabel} - Resized(${key._width}×${key._height})'; } + _configureErrorListener(completer, key); return completer; } + void _configureErrorListener(ImageStreamCompleter completer, ResizeImageKey key) { + completer.addEphemeralErrorListener((Object exception, StackTrace? stackTrace) { + // The microtask is scheduled because of the same reason as NetworkImage: + // Depending on where the exception was thrown, the image cache may not + // have had a chance to track the key in the cache at all. + // Schedule a microtask to give the cache a chance to add the key. + scheduleMicrotask(() { + PaintingBinding.instance.imageCache.evict(key); + }); + }); + } + @override Future obtainKey(ImageConfiguration configuration) { Completer? completer; diff --git a/packages/flutter/lib/src/painting/image_stream.dart b/packages/flutter/lib/src/painting/image_stream.dart index 65baf777ebf1c..ccfa72d15b025 100644 --- a/packages/flutter/lib/src/painting/image_stream.dart +++ b/packages/flutter/lib/src/painting/image_stream.dart @@ -468,6 +468,7 @@ class ImageStreamCompleterHandle { /// configure it with the right [ImageStreamCompleter] when possible. abstract class ImageStreamCompleter with Diagnosticable { final List _listeners = []; + final List _ephemeralErrorListeners = []; ImageInfo? _currentImage; FlutterErrorDetails? _currentError; @@ -489,6 +490,9 @@ abstract class ImageStreamCompleter with Diagnosticable { /// and similarly, by overriding [removeListener], checking if [hasListeners] /// is false after calling `super.removeListener()`, and if so, stopping that /// same work. + /// + /// The ephemeral error listeners (added through [addEphemeralErrorListener]) + /// will not be taken into consideration in this property. @protected @visibleForTesting bool get hasListeners => _listeners.isNotEmpty; @@ -515,6 +519,11 @@ abstract class ImageStreamCompleter with Diagnosticable { /// this listener's [ImageStreamListener.onImage] will fire multiple times. /// /// {@macro flutter.painting.imageStream.addListener} + /// + /// See also: + /// + /// * [addEphemeralErrorListener], which adds an error listener that is + /// automatically removed after first image load or error. void addListener(ImageStreamListener listener) { _checkDisposed(); _hadAtLeastOneListener = true; @@ -548,6 +557,58 @@ abstract class ImageStreamCompleter with Diagnosticable { } } + /// Adds an error listener callback that is called when the first error is reported. + /// + /// The callback will be removed automatically after the first successful + /// image load or the first error - that is why it is called "ephemeral". + /// + /// If a concrete image is already available, the listener will be discarded + /// synchronously. If an error has been already reported, the listener + /// will be notified synchronously. + /// + /// The presence of a listener will affect neither the lifecycle of this object + /// nor what [hasListeners] reports. + /// + /// It is different from [addListener] in a few points: Firstly, this one only + /// listens to errors, while [addListener] listens to all kinds of events. + /// Secondly, this listener will be automatically removed according to the + /// rules mentioned above, while [addListener] will need manual removal. + /// Thirdly, this listener will not affect how this object is disposed, while + /// any non-removed listener added via [addListener] will forbid this object + /// from disposal. + /// + /// When you want to know full information and full control, use [addListener]. + /// When you only want to get notified for an error ephemerally, use this function. + /// + /// See also: + /// + /// * [addListener], which adds a full-featured listener and needs manual + /// removal. + void addEphemeralErrorListener(ImageErrorListener listener) { + _checkDisposed(); + if (_currentError != null) { + // immediately fire the listener, and no need to add to _ephemeralErrorListeners + try { + listener(_currentError!.exception, _currentError!.stack); + } catch (newException, newStack) { + if (newException != _currentError!.exception) { + FlutterError.reportError( + FlutterErrorDetails( + exception: newException, + library: 'image resource service', + context: ErrorDescription('by a synchronously-called image error listener'), + stack: newStack, + ), + ); + } + } + } else if (_currentImage == null) { + // add to _ephemeralErrorListeners to wait for the error, + // only if no image has been loaded + _ephemeralErrorListeners.add(listener); + } + } + int _keepAliveHandles = 0; /// Creates an [ImageStreamCompleterHandle] that will prevent this stream from /// being disposed at least until the handle is disposed. @@ -595,6 +656,7 @@ abstract class ImageStreamCompleter with Diagnosticable { return; } + _ephemeralErrorListeners.clear(); _currentImage?.dispose(); _currentImage = null; _disposed = true; @@ -640,6 +702,8 @@ abstract class ImageStreamCompleter with Diagnosticable { _currentImage?.dispose(); _currentImage = image; + _ephemeralErrorListeners.clear(); + if (_listeners.isEmpty) { return; } @@ -707,10 +771,14 @@ abstract class ImageStreamCompleter with Diagnosticable { ); // Make a copy to allow for concurrent modification. - final List localErrorListeners = _listeners - .map((ImageStreamListener listener) => listener.onError) - .whereType() - .toList(); + final List localErrorListeners = [ + ..._listeners + .map((ImageStreamListener listener) => listener.onError) + .whereType(), + ..._ephemeralErrorListeners, + ]; + + _ephemeralErrorListeners.clear(); bool handled = false; for (final ImageErrorListener errorListener in localErrorListeners) { @@ -764,6 +832,11 @@ abstract class ImageStreamCompleter with Diagnosticable { _listeners, ifPresent: '${_listeners.length} listener${_listeners.length == 1 ? "" : "s" }', )); + description.add(ObjectFlagProperty>( + 'ephemeralErrorListeners', + _ephemeralErrorListeners, + ifPresent: '${_ephemeralErrorListeners.length} ephemeralErrorListener${_ephemeralErrorListeners.length == 1 ? "" : "s" }', + )); description.add(FlagProperty('disposed', value: _disposed, ifTrue: '')); } } diff --git a/packages/flutter/test/painting/image_provider_network_image_test.dart b/packages/flutter/test/painting/image_provider_network_image_test.dart index 086ffa5669c5b..45f9ffaf9e35e 100644 --- a/packages/flutter/test/painting/image_provider_network_image_test.dart +++ b/packages/flutter/test/painting/image_provider_network_image_test.dart @@ -73,6 +73,42 @@ void main() { expect(httpClient.request.response.drained, true); }, skip: isBrowser); // [intended] Browser implementation does not use HTTP client but an tag. + test('Expect thrown exception with statusCode - evicts from cache and drains, when using ResizeImage', () async { + const int errorStatusCode = HttpStatus.notFound; + const String requestUrl = 'foo-url'; + + httpClient.request.response.statusCode = errorStatusCode; + + final Completer caughtError = Completer(); + + final ImageProvider imageProvider = ResizeImage(NetworkImage(nonconst(requestUrl)), width: 5, height: 5); + expect(imageCache.pendingImageCount, 0); + expect(imageCache.statusForKey(imageProvider).untracked, true); + + final ImageStream result = imageProvider.resolve(ImageConfiguration.empty); + + expect(imageCache.pendingImageCount, 1); + + result.addListener(ImageStreamListener((ImageInfo info, bool syncCall) {}, + onError: (dynamic error, StackTrace? stackTrace) { + caughtError.complete(error); + })); + + final Object? err = await caughtError.future; + await Future.delayed(Duration.zero); + + expect(imageCache.pendingImageCount, 0); + expect(imageCache.statusForKey(imageProvider).untracked, true); + + expect( + err, + isA() + .having((NetworkImageLoadException e) => e.statusCode, 'statusCode', errorStatusCode) + .having((NetworkImageLoadException e) => e.uri, 'uri', Uri.base.resolve(requestUrl)), + ); + expect(httpClient.request.response.drained, true); + }, skip: isBrowser); // [intended] Browser implementation does not use HTTP client but an tag. + test('Uses the HttpClient provided by debugNetworkImageHttpClientProvider if set', () async { httpClient.thrownError = 'client1'; final List capturedErrors = []; @@ -180,7 +216,7 @@ void main() { }, )); - final dynamic err = await caughtError.future; + final Object? err = await caughtError.future; expect(err, isA()); diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index ba06c7b42169a..2eb4b80b6437e 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -501,12 +501,12 @@ void main() { final _TestImageProvider imageProvider = _TestImageProvider(); await tester.pumpWidget(Image(image: imageProvider, excludeFromSemantics: true)); final State image = tester.state/*State*/(find.byType(Image)); - expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, unresolved, 2 listeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)')); + expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, unresolved, 2 listeners, 0 ephemeralErrorListeners), pixels: null, loadingProgress: null, frameNumber: null, wasSynchronouslyLoaded: false)')); imageProvider.complete(image100x100); await tester.pump(); - expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, $imageString @ 1.0x, 1 listener), pixels: $imageString @ 1.0x, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); + expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, $imageString @ 1.0x, 1 listener, 0 ephemeralErrorListeners), pixels: $imageString @ 1.0x, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); await tester.pumpWidget(Container()); - expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(lifecycle state: defunct, not mounted, stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, $imageString @ 1.0x, 0 listeners), pixels: null, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); + expect(image.toString(), equalsIgnoringHashCodes('_ImageState#00000(lifecycle state: defunct, not mounted, stream: ImageStream#00000(OneFrameImageStreamCompleter#00000, $imageString @ 1.0x, 0 listeners, 0 ephemeralErrorListeners), pixels: null, loadingProgress: null, frameNumber: 0, wasSynchronouslyLoaded: false)')); }); testWidgets('Stream completer errors can be listened to by attaching before resolving', (WidgetTester tester) async { From 0c78dce5294592fdbee1ce7cf90414128de80a26 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 21 Aug 2023 11:07:56 -0700 Subject: [PATCH 0811/1547] Bump memory usage for flutter gallery (#132968) Fixes https://github.com/flutter/flutter/issues/131006 Flakes related to out of memory in gradle when running tests. Opted not to add enforcement for gradle.properties in https://github.com/flutter/flutter/blob/master/dev/bots/analyze.dart because the memory usage has been stable for 6 years and not every example needs more memory. --- dev/integration_tests/flutter_gallery/android/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/integration_tests/flutter_gallery/android/gradle.properties b/dev/integration_tests/flutter_gallery/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/flutter_gallery/android/gradle.properties +++ b/dev/integration_tests/flutter_gallery/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true From 8e95ee2e9619508c42a1135bb8beed332a7e1643 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 21 Aug 2023 12:02:33 -0700 Subject: [PATCH 0812/1547] Docs on iOS's directional quote characters (#132869) When you type a single or double quote character on the default iOS keyboard, it doesn't actually insert the usual `'` or `"`. Instead, it inserts a directional version that tries to match with others. This is very tricky when allow/deny-listing characters, so I've added a section about this to the docs. Fixes https://github.com/flutter/flutter/issues/132232 --- packages/flutter/lib/src/services/text_formatter.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/flutter/lib/src/services/text_formatter.dart b/packages/flutter/lib/src/services/text_formatter.dart index a822b5c8aea88..d3c205b8489dd 100644 --- a/packages/flutter/lib/src/services/text_formatter.dart +++ b/packages/flutter/lib/src/services/text_formatter.dart @@ -251,6 +251,14 @@ class _TextEditingValueAccumulator { /// As an example, [FilteringTextInputFormatter] typically shouldn't be used /// with [RegExp]s that contain positional matchers (`^` or `$`) since these /// patterns are usually meant for matching the whole string. +/// +/// ### Quote characters on iOS +/// +/// When filtering single (`'`) or double (`"`) quote characters, be aware that +/// the default iOS keyboard actually inserts special directional versions of +/// these characters (`‘` and `’` for single quote, and `“` and `”` for double +/// quote). Consider including all three variants in your regular expressions to +/// support iOS. class FilteringTextInputFormatter extends TextInputFormatter { /// Creates a formatter that replaces banned patterns with the given /// [replacementString]. From 2b42a47724d7e23698a3cacfe8533aea193edf89 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 15:04:06 -0400 Subject: [PATCH 0813/1547] Roll Flutter Engine from 0290d0bd79ee to 210f5a8aa245 (1 revision) (#132973) https://github.com/flutter/engine/compare/0290d0bd79ee...210f5a8aa245 2023-08-21 jonahwilliams@google.com [Impeller] Remove sync switch (flutter/engine#44885) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2997049112b99..221baf0d34046 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0290d0bd79eef30c51494437e22624f4c3baaa0d +210f5a8aa2457b21bc17a60075c580ca0db097ba From 505f9d8954da04df6fb87e2e342acd7e254f15e6 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Mon, 21 Aug 2023 12:51:55 -0700 Subject: [PATCH 0814/1547] Change gradle lockfile generation script to use --config-only flag (#132967) The `generate_gradle_lockfiles.dart` script was generating the gradle wrapper by building a flavor that didn't exist. In the time since the script was written, the `--config-only` flag was created and should be used instead. Context https://github.com/flutter/flutter/pull/132406#discussion_r1300352602 --- dev/tools/bin/generate_gradle_lockfiles.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dev/tools/bin/generate_gradle_lockfiles.dart b/dev/tools/bin/generate_gradle_lockfiles.dart index 8daafdf7bfea4..e039e9f7577d2 100644 --- a/dev/tools/bin/generate_gradle_lockfiles.dart +++ b/dev/tools/bin/generate_gradle_lockfiles.dart @@ -86,13 +86,11 @@ void main(List arguments) { // Verify that the Gradlew wrapper exists. final File gradleWrapper = androidDirectory.childFile('gradlew'); - // Generate Gradle wrapper if it doesn't exists. - // This logic is embedded within the Flutter tool. - // To generate the wrapper, build a flavor that doesn't exist. + // Generate Gradle wrapper if it doesn't exist. if (!gradleWrapper.existsSync()) { Process.runSync( 'flutter', - ['build', 'apk', '--debug', '--flavor=does-not-exist'], + ['build', 'apk', '--config-only'], workingDirectory: appDirectory, ); } From af79b4c7a3a425814eabc8df32708b1426643f5c Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 21 Aug 2023 23:13:22 +0300 Subject: [PATCH 0815/1547] Update `ExpansionPanel` example for the updated `expansionCallback` callback (#132837) fixes [ExpansionPanelList can't expand/collapse on the latest stable/master ](https://github.com/flutter/flutter/issues/132759) https://github.com/flutter/flutter/pull/128082 updated the `expansionCallback` and also the `ExpansionPanel` sample in the Flutter gallery but not the API example. This PR fixes the API example and adds tests. --- dev/bots/check_code_samples.dart | 1 - .../expansion_panel_list.0.dart | 2 +- .../expansion_panel_list.0_test.dart | 75 +++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 examples/api/test/material/expansion_panel/expansion_panel_list.0_test.dart diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart index 0ffd56e510797..792fe54224d69 100644 --- a/dev/bots/check_code_samples.dart +++ b/dev/bots/check_code_samples.dart @@ -306,7 +306,6 @@ final Set _knownMissingTests = { 'examples/api/test/material/icon_button/icon_button.3_test.dart', 'examples/api/test/material/icon_button/icon_button.0_test.dart', 'examples/api/test/material/icon_button/icon_button.1_test.dart', - 'examples/api/test/material/expansion_panel/expansion_panel_list.0_test.dart', 'examples/api/test/material/expansion_panel/expansion_panel_list.expansion_panel_list_radio.0_test.dart', 'examples/api/test/material/input_decorator/input_decoration.1_test.dart', 'examples/api/test/material/input_decorator/input_decoration.prefix_icon_constraints.0_test.dart', diff --git a/examples/api/lib/material/expansion_panel/expansion_panel_list.0.dart b/examples/api/lib/material/expansion_panel/expansion_panel_list.0.dart index 740250e4f6097..6fb02ad07408f 100644 --- a/examples/api/lib/material/expansion_panel/expansion_panel_list.0.dart +++ b/examples/api/lib/material/expansion_panel/expansion_panel_list.0.dart @@ -67,7 +67,7 @@ class _ExpansionPanelListExampleState extends State { return ExpansionPanelList( expansionCallback: (int index, bool isExpanded) { setState(() { - _data[index].isExpanded = !isExpanded; + _data[index].isExpanded = isExpanded; }); }, children: _data.map((Item item) { diff --git a/examples/api/test/material/expansion_panel/expansion_panel_list.0_test.dart b/examples/api/test/material/expansion_panel/expansion_panel_list.0_test.dart new file mode 100644 index 0000000000000..fc64f447c9d3d --- /dev/null +++ b/examples/api/test/material/expansion_panel/expansion_panel_list.0_test.dart @@ -0,0 +1,75 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/expansion_panel/expansion_panel_list.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('ExpansionPanel can be expanded', (WidgetTester tester) async { + await tester.pumpWidget( + const example.ExpansionPanelListExampleApp(), + ); + + // Verify the first tile is collapsed. + expect(tester.widget(find.byType(ExpandIcon).first).isExpanded, false); + + // Tap to expand the first tile. + await tester.tap(find.byType(ExpandIcon).first); + await tester.pumpAndSettle(); + + // Verify that the first tile is expanded. + expect(tester.widget(find.byType(ExpandIcon).first).isExpanded, true); + }); + + testWidgets('Tap to delete a ExpansionPanel', (WidgetTester tester) async { + const int index = 3; + + await tester.pumpWidget( + const example.ExpansionPanelListExampleApp(), + ); + + expect(find.widgetWithText(ListTile, 'Panel $index'), findsOneWidget); + expect(tester.widget(find.byType(ExpandIcon).at(index)).isExpanded, false); + + // Tap to expand the tile at index 3. + await tester.tap(find.byType(ExpandIcon).at(index)); + await tester.pumpAndSettle(); + + expect(tester.widget(find.byType(ExpandIcon).at(index)).isExpanded, true); + + // Tap to delete the tile at index 3. + await tester.tap(find.byIcon(Icons.delete).at(index)); + await tester.pumpAndSettle(); + + // Verify that the tile at index 3 is deleted. + expect(find.widgetWithText(ListTile, 'Panel $index'), findsNothing); + }); + + testWidgets('ExpansionPanelList is scrollable', (WidgetTester tester) async { + await tester.pumpWidget( + const example.ExpansionPanelListExampleApp(), + ); + + expect(find.byType(SingleChildScrollView), findsOneWidget); + + // Expand all the tiles. + for (int i = 0; i < 8; i++) { + await tester.tap(find.byType(ExpandIcon).at(i)); + } + await tester.pumpAndSettle(); + + // Check panel 3 tile position. + Offset tilePosition = tester.getBottomLeft(find.widgetWithText(ListTile, 'Panel 3')); + expect(tilePosition.dy, 656.0); + + // Scroll up. + await tester.drag(find.byType(SingleChildScrollView), const Offset(0, -300)); + await tester.pumpAndSettle(); + + // Verify panel 3 tile position is updated after scrolling. + tilePosition = tester.getBottomLeft(find.widgetWithText(ListTile, 'Panel 3')); + expect(tilePosition.dy, 376.0); + }); +} From f05dcafddfad41607b07c6fa2bf74cd3c0860efa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 16:41:34 -0400 Subject: [PATCH 0816/1547] Roll Flutter Engine from 210f5a8aa245 to 2388b9db2be7 (6 revisions) (#132986) https://github.com/flutter/engine/compare/210f5a8aa245...2388b9db2be7 2023-08-21 john@johnmccutchan.com [Impeller] Initial Android Impeller docs on backend selection and platform views. (flutter/engine#44815) 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from da3bb89a5d88 to af4ecc4cd3e9 (1 revision) (flutter/engine#44911) 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from 7e5a3009a8d4 to da3bb89a5d88 (9 revisions) (flutter/engine#44906) 2023-08-21 zanderso@users.noreply.github.com Don't run clang_tidy --lint-all in presubmit (flutter/engine#44833) 2023-08-21 skia-flutter-autoroll@skia.org Roll Dart SDK from 7dd53a3df4cf to 1859f7202bba (1 revision) (flutter/engine#44903) 2023-08-21 gspencergoog@users.noreply.github.com Change Doxyfile options to not create subdirs (flutter/engine#44855) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 221baf0d34046..79ec43bdb1ebe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -210f5a8aa2457b21bc17a60075c580ca0db097ba +2388b9db2be7bc2613c5cadbe8de023faa9d2aac From 7f5de98ae2bc6b89aa56db533048ec1971e2b52e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 17:26:05 -0400 Subject: [PATCH 0817/1547] Roll Flutter Engine from 2388b9db2be7 to fc75109c3a1e (3 revisions) (#132992) https://github.com/flutter/engine/compare/2388b9db2be7...fc75109c3a1e 2023-08-21 brianosman@google.com Include GrVkTypes where necessary (flutter/engine#44916) 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from af4ecc4cd3e9 to ca891e495da1 (1 revision) (flutter/engine#44914) 2023-08-21 godofredoc@google.com Remove explicit mac cpu dimensions (flutter/engine#44836) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 79ec43bdb1ebe..c5517f2ea8a91 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2388b9db2be7bc2613c5cadbe8de023faa9d2aac +fc75109c3a1ee83b18b11a5cd14a26c1ceacdf9d From 254f235c7f94ee0cceee9eb66961ad05f6974717 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 18:26:59 -0400 Subject: [PATCH 0818/1547] Roll Flutter Engine from fc75109c3a1e to e5f690b829e5 (1 revision) (#132996) https://github.com/flutter/engine/compare/fc75109c3a1e...e5f690b829e5 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from ca891e495da1 to da6b74568ece (3 revisions) (flutter/engine#44917) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c5517f2ea8a91..f87780bc78572 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fc75109c3a1ee83b18b11a5cd14a26c1ceacdf9d +e5f690b829e5f2d5407a79cb99ee035957b52682 From f9b91734a15a92f031d9eb3c94d92057008a72f6 Mon Sep 17 00:00:00 2001 From: Angelo Silvestre Date: Mon, 21 Aug 2023 20:27:19 -0300 Subject: [PATCH 0819/1547] Add deleteBackwardByDecomposingPreviousCharacter mapping for tests (#132919) In `MacOSTestTextInputKeyHandler`, there are some mappings from shortcuts to generate macOS selectors. However, `ctrl + backspace` isn't mapped to `deleteBackwardByDecomposingPreviousCharacter:`. This PR adds the mapping for `deleteBackwardByDecomposingPreviousCharacter:`. Fixes: https://github.com/flutter/flutter/issues/132917 --- .../lib/src/test_text_input_key_handler.dart | 2 ++ .../test/test_text_input_test.dart | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/packages/flutter_test/lib/src/test_text_input_key_handler.dart b/packages/flutter_test/lib/src/test_text_input_key_handler.dart index 410f9d16616a3..7dba935d65794 100644 --- a/packages/flutter_test/lib/src/test_text_input_key_handler.dart +++ b/packages/flutter_test/lib/src/test_text_input_key_handler.dart @@ -50,6 +50,8 @@ class MacOSTestTextInputKeyHandler extends TestTextInputKeyHandler { alt: true, shift: pressShift): ['deleteWordBackward:'], SingleActivator(LogicalKeyboardKey.backspace, meta: true, shift: pressShift): ['deleteToBeginningOfLine:'], + SingleActivator(LogicalKeyboardKey.backspace, control: true, shift: pressShift): + ['deleteBackwardByDecomposingPreviousCharacter:'], SingleActivator(LogicalKeyboardKey.delete, shift: pressShift): [ 'deleteForward:' ], diff --git a/packages/flutter_test/test/test_text_input_test.dart b/packages/flutter_test/test/test_text_input_test.dart index eb911ff2c31d3..535a027b92cf3 100644 --- a/packages/flutter_test/test/test_text_input_test.dart +++ b/packages/flutter_test/test/test_text_input_test.dart @@ -76,4 +76,26 @@ void main() { expect(selectorNames, isNull); } }, variant: TargetPlatformVariant.all()); + + testWidgets('selector is called for ctrl + backspace on macOS', (WidgetTester tester) async { + List? selectorNames; + await SystemChannels.textInput.invokeMethod('TextInput.setClient', [1, {}]); + await SystemChannels.textInput.invokeMethod('TextInput.show'); + SystemChannels.textInput.setMethodCallHandler((MethodCall call) async { + if (call.method == 'TextInputClient.performSelectors') { + selectorNames = (call.arguments as List)[1] as List; + } + }); + await tester.sendKeyDownEvent(LogicalKeyboardKey.control); + await tester.sendKeyDownEvent(LogicalKeyboardKey.backspace); + await tester.sendKeyUpEvent(LogicalKeyboardKey.backspace); + await tester.sendKeyUpEvent(LogicalKeyboardKey.control); + await SystemChannels.textInput.invokeMethod('TextInput.clearClient'); + + if (defaultTargetPlatform == TargetPlatform.macOS) { + expect(selectorNames, ['deleteBackwardByDecomposingPreviousCharacter:']); + } else { + expect(selectorNames, isNull); + } + }, variant: TargetPlatformVariant.all()); } From 5a847b09594362ee47bcd815eef3a9e546769260 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 19:41:14 -0400 Subject: [PATCH 0820/1547] Roll Flutter Engine from e5f690b829e5 to 55b84268f2a6 (1 revision) (#133000) https://github.com/flutter/engine/compare/e5f690b829e5...55b84268f2a6 2023-08-21 godofredoc@google.com Use arm64 machines for ios_debug_sim_arm64 test. (flutter/engine#44920) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f87780bc78572..0ca0604e5f1f5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e5f690b829e5f2d5407a79cb99ee035957b52682 +55b84268f2a68273674a567f97e346f2d97fdf27 From 97e434f86ab7dfdc87fe895eefba0709c64337d6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 20:27:36 -0400 Subject: [PATCH 0821/1547] Roll Flutter Engine from 55b84268f2a6 to e5929d83e9b7 (3 revisions) (#133005) https://github.com/flutter/engine/compare/55b84268f2a6...e5929d83e9b7 2023-08-21 dnfield@google.com [Impeller] Disable Impeller on Fuchsia (flutter/engine#44925) 2023-08-21 30870216+gaaclarke@users.noreply.github.com [Impeller] Added recycled command buffers. (flutter/engine#44904) 2023-08-21 skia-flutter-autoroll@skia.org Roll Dart SDK from 1859f7202bba to 00f6f69187df (1 revision) (flutter/engine#44922) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0ca0604e5f1f5..820ca3e40f48a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -55b84268f2a68273674a567f97e346f2d97fdf27 +e5929d83e9b7d183c69cd99b1ae3ebbd278d4db8 From a021015ef6f4bac8502ccab33d9ddfea0258a2f9 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 21 Aug 2023 18:32:14 -0700 Subject: [PATCH 0822/1547] Always require `--local-engine-host` if `--local-engine` (#133003) Closes #132245. --- .../lib/src/base/user_messages.dart | 8 +-- .../flutter_tools/lib/src/context_runner.dart | 5 -- .../lib/src/runner/local_engine.dart | 35 +----------- .../runner/local_engine_test.dart | 55 +++++-------------- 4 files changed, 20 insertions(+), 83 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 54305b36f38d0..00956fa00f28e 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -308,12 +308,10 @@ class UserMessages { "you have compiled the engine in that directory, which should produce an 'out' directory"; String get runnerLocalEngineOrWebSdkRequired => 'You must specify --local-engine or --local-web-sdk if you are using a locally built engine or web sdk.'; - // TODO(matanlurey): Make this an error, https://github.com/flutter/flutter/issues/132245. - String runnerLocalEngineRequiresHostEngine({bool warning = false}) => - '${warning ? 'Warning! ' : ''}You are using a locally built engine (--local-engine) but have not specified --local-engine-host.\n' + String get runnerLocalEngineRequiresHostEngine => + 'You are using a locally built engine (--local-engine) but have not specified --local-engine-host.\n' 'You may be building with a different engine than the one you are running with. ' - 'See https://github.com/flutter/flutter/issues/132245 for details (in the future this will become ' - 'an error).'; + 'See https://github.com/flutter/flutter/issues/132245 for details.'; String runnerNoEngineBuild(String engineBuildPath) => 'No Flutter engine build found at $engineBuildPath.'; String runnerNoWebSdk(String webSdkPath) => diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index a3f0b268abe4a..a5a4f92c25048 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -276,11 +276,6 @@ Future runInContext( platform: globals.platform, fileSystem: globals.fs, flutterRoot: Cache.flutterRoot!, - // TODO(matanlurey): https://github.com/flutter/flutter/issues/132245. - // Even though we *think* this feature is stable, we'd like to verify - // that automated tests are all providing `--local-engine-host` before - // enforcing it for all users. - treatMissingLocalEngineHostAsFatal: runningOnBot, ), Logger: () => globals.platform.isWindows ? WindowsStdoutLogger( diff --git a/packages/flutter_tools/lib/src/runner/local_engine.dart b/packages/flutter_tools/lib/src/runner/local_engine.dart index 5170bf59e2ce4..24c0b1b353739 100644 --- a/packages/flutter_tools/lib/src/runner/local_engine.dart +++ b/packages/flutter_tools/lib/src/runner/local_engine.dart @@ -33,20 +33,17 @@ class LocalEngineLocator { required FileSystem fileSystem, required String flutterRoot, required UserMessages userMessages, - bool treatMissingLocalEngineHostAsFatal = false, }) : _platform = platform, _logger = logger, _fileSystem = fileSystem, _flutterRoot = flutterRoot, - _userMessages = userMessages, - _treatMissingLocalEngineHostAsFatal = treatMissingLocalEngineHostAsFatal; + _userMessages = userMessages; final Platform _platform; final Logger _logger; final FileSystem _fileSystem; final String _flutterRoot; final UserMessages _userMessages; - final bool _treatMissingLocalEngineHostAsFatal; /// Returns the engine build path of a local engine if one is located, otherwise `null`. Future findEnginePath({ @@ -170,26 +167,6 @@ class LocalEngineLocator { return engineSourcePath; } - // Determine the host engine directory associated with the local engine: - // Strip '_sim' since there are no host simulator builds. - String _getHostEngineBasename(String localEngineBasename) { - if (localEngineBasename.startsWith('web_') || - localEngineBasename.startsWith('wasm_') || - localEngineBasename.startsWith('host_')) { - // Don't modify the web or host local engine's basename. - return localEngineBasename; - } - - String tmpBasename = localEngineBasename.replaceFirst('_sim', ''); - tmpBasename = tmpBasename.substring(tmpBasename.indexOf('_') + 1); - // Strip suffix for various archs. - const List suffixes = ['_arm', '_arm64', '_x86', '_x64']; - for (final String suffix in suffixes) { - tmpBasename = tmpBasename.replaceFirst(RegExp('$suffix\$'), ''); - } - return 'host_$tmpBasename'; - } - EngineBuildPaths _findEngineBuildPath({ required String engineSourcePath, String? localEngine, @@ -209,16 +186,10 @@ class LocalEngineLocator { } if (localHostEngine == null) { - // TODO(matanlurey): https://github.com/flutter/flutter/issues/132245, always throwToolExit. - if (_treatMissingLocalEngineHostAsFatal) { - throwToolExit(_userMessages.runnerLocalEngineRequiresHostEngine()); - } - _logger.printStatus(_userMessages.runnerLocalEngineRequiresHostEngine(warning: true)); + throwToolExit(_userMessages.runnerLocalEngineRequiresHostEngine); } - final String basename = localHostEngine ?? _fileSystem.path.basename(engineBuildPath); - final String hostBasename = _getHostEngineBasename(basename); engineHostBuildPath = _fileSystem.path.normalize( - _fileSystem.path.join(_fileSystem.path.dirname(engineBuildPath), hostBasename), + _fileSystem.path.join(_fileSystem.path.dirname(engineBuildPath), localHostEngine), ); if (!_fileSystem.isDirectorySync(engineHostBuildPath)) { throwToolExit(_userMessages.runnerNoEngineBuild(engineHostBuildPath), exitCode: 2); diff --git a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart index e8570fddfa0f1..d84d5438ec32d 100644 --- a/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/local_engine_test.dart @@ -43,7 +43,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: 'ios_debug'), + await localEngineLocator.findEnginePath(localEngine: 'ios_debug', localHostEngine: 'host_debug'), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug', targetEngine: '/arbitrary/engine/src/out/ios_debug', @@ -58,7 +58,7 @@ void main() { .writeAsStringSync('sky_engine:file:///symlink/src/out/ios_debug/gen/dart-pkg/sky_engine/lib/'); expect( - await localEngineLocator.findEnginePath(localEngine: 'ios_debug'), + await localEngineLocator.findEnginePath(localEngine: 'ios_debug', localHostEngine: 'host_debug'), matchesEngineBuildPaths( hostEngine: '/symlink/src/out/host_debug', targetEngine: '/symlink/src/out/ios_debug', @@ -84,7 +84,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(engineSourcePath: '$kArbitraryEngineRoot/src', localEngine: 'ios_debug'), + await localEngineLocator.findEnginePath(engineSourcePath: '$kArbitraryEngineRoot/src', localEngine: 'ios_debug', localHostEngine: 'host_debug'), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug', targetEngine: '/arbitrary/engine/src/out/ios_debug', @@ -119,7 +119,7 @@ void main() { expect(logger.traceText, contains('Local engine source at /arbitrary/engine/src')); }); - testWithoutContext('works but produces a warning if --local-engine is specified but not --local-engine-host', () async { + testWithoutContext('fails if --local-engine-host is omitted', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final Directory localEngine = fileSystem .directory('$kArbitraryEngineRoot/src/out/android_debug_unopt_arm64/') @@ -135,33 +135,6 @@ void main() { platform: FakePlatform(environment: {}), ); - expect( - await localEngineLocator.findEnginePath(localEngine: localEngine.path), - matchesEngineBuildPaths( - hostEngine: '/arbitrary/engine/src/out/host_debug_unopt', - targetEngine: '/arbitrary/engine/src/out/android_debug_unopt_arm64', - ), - ); - expect(logger.statusText, contains('Warning! You are using a locally built engine (--local-engine) but have not specified --local-engine-host')); - }); - - testWithoutContext('fails if --local-engine-host is emitted and treatMissingLocalEngineHostAsFatal is set', () async { - final FileSystem fileSystem = MemoryFileSystem.test(); - final Directory localEngine = fileSystem - .directory('$kArbitraryEngineRoot/src/out/android_debug_unopt_arm64/') - ..createSync(recursive: true); - fileSystem.directory('$kArbitraryEngineRoot/src/out/host_debug_unopt/').createSync(recursive: true); - - final BufferLogger logger = BufferLogger.test(); - final LocalEngineLocator localEngineLocator = LocalEngineLocator( - fileSystem: fileSystem, - flutterRoot: 'flutter/flutter', - logger: logger, - userMessages: UserMessages(), - platform: FakePlatform(environment: {}), - treatMissingLocalEngineHostAsFatal: true, - ); - await expectLater( localEngineLocator.findEnginePath(localEngine: localEngine.path), throwsToolExit(message: 'You are using a locally built engine (--local-engine) but have not specified --local-engine-host'), @@ -186,7 +159,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: localEngine.path), + await localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: 'host_debug'), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug', targetEngine: '/arbitrary/engine/src/out/ios_debug', @@ -212,7 +185,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: localEngine.path), + await localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: localEngine.path), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug', targetEngine: '/arbitrary/engine/src/out/host_debug', @@ -237,7 +210,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: localEngine.path), + await localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: localEngine.path), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug_unopt_arm64', targetEngine: '/arbitrary/engine/src/out/host_debug_unopt_arm64', @@ -264,7 +237,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: localEngine.path), + await localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: 'host_debug'), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug', targetEngine: '/arbitrary/engine/src/out/ios_debug_sim', @@ -292,7 +265,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: localEngine.path), + await localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: 'host_debug_unopt'), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/host_debug_unopt', targetEngine: '/arbitrary/engine/src/out/ios_debug_sim_unopt', @@ -315,7 +288,7 @@ void main() { ); await expectToolExitLater( - localEngineLocator.findEnginePath(localEngine: localEngine.path), + localEngineLocator.findEnginePath(localEngine: localEngine.path, localHostEngine: 'host_debug'), contains('No Flutter engine build found at /arbitrary/engine/src/out/host_debug'), ); }); @@ -344,7 +317,7 @@ void main() { ); expect( - await localEngineLocator.findEnginePath(localEngine: 'ios_debug'), + await localEngineLocator.findEnginePath(localEngine: 'ios_debug', localHostEngine: 'host_debug'), matchesEngineBuildPaths( hostEngine: 'flutter/engine/src/out/host_debug', targetEngine: 'flutter/engine/src/out/ios_debug', @@ -366,7 +339,7 @@ void main() { ); await expectToolExitLater( - localEngineLocator.findEnginePath(localEngine: '/path/to/nothing'), + localEngineLocator.findEnginePath(localEngine: '/path/to/nothing', localHostEngine: '/path/to/nothing'), contains('Unable to detect local Flutter engine src directory'), ); }); @@ -390,7 +363,7 @@ void main() { ); expect( - await localWasmEngineLocator.findEnginePath(localEngine: localWasmEngine.path), + await localWasmEngineLocator.findEnginePath(localEngine: localWasmEngine.path, localHostEngine: localWasmEngine.path), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/wasm_whatever', targetEngine: '/arbitrary/engine/src/out/wasm_whatever', @@ -408,7 +381,7 @@ void main() { ); expect( - await localWebEngineLocator.findEnginePath(localEngine: localWebEngine.path), + await localWebEngineLocator.findEnginePath(localEngine: localWebEngine.path, localHostEngine: localWebEngine.path), matchesEngineBuildPaths( hostEngine: '/arbitrary/engine/src/out/web_whatever', targetEngine: '/arbitrary/engine/src/out/web_whatever', From 1cf3925d4dcd9791e0bb49b75c11550b31a98662 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 21:40:11 -0400 Subject: [PATCH 0823/1547] Roll Flutter Engine from e5929d83e9b7 to 5a292e42a593 (3 revisions) (#133010) https://github.com/flutter/engine/compare/e5929d83e9b7...5a292e42a593 2023-08-21 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from lDn2QLh1I7rtNu01y... to RVhmZNTYsaIiTyjwP... (flutter/engine#44932) 2023-08-21 skia-flutter-autoroll@skia.org Roll Skia from da6b74568ece to 40442138ec94 (3 revisions) (flutter/engine#44931) 2023-08-21 31859944+LongCatIsLooong@users.noreply.github.com Reland "Implementing TextScaler for nonlinear text scaling (#42062)" (flutter/engine#44907) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from lDn2QLh1I7rt to RVhmZNTYsaIi If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 820ca3e40f48a..f33ca5dfa689e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e5929d83e9b7d183c69cd99b1ae3ebbd278d4db8 +5a292e42a59341d33d13b730fdfebd9ba65c889f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 749b7da3efd9d..feac59b6d7da8 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -lDn2QLh1I7rtNu01ySR9vzGYwVjpCO1GD89M5cyrXQ0C +RVhmZNTYsaIiTyjwPz_v93og9qBqvH0fo75kFNmXe10C From a5b06f15a0b48907c818c13bdcffcab4c84f9de5 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Mon, 21 Aug 2023 20:46:23 -0500 Subject: [PATCH 0824/1547] Fix visual overflow for SliverMainAxisGroup (#132989) Fixes https://github.com/flutter/flutter/issues/132788 The SliverGeometry was not set properly for SliverMainAxisGroup. Omitting hasVisualOverflow affected the Viewport's choice to apply a clip, leading to the sliver being rendered outside of the bounds of the viewport. --- packages/flutter/lib/src/rendering/sliver_group.dart | 1 + .../flutter/test/widgets/sliver_main_axis_group_test.dart | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/flutter/lib/src/rendering/sliver_group.dart b/packages/flutter/lib/src/rendering/sliver_group.dart index 831590840894a..40e8ee85ec7bf 100644 --- a/packages/flutter/lib/src/rendering/sliver_group.dart +++ b/packages/flutter/lib/src/rendering/sliver_group.dart @@ -288,6 +288,7 @@ class RenderSliverMainAxisGroup extends RenderSliver with ContainerRenderObjectM scrollExtent: totalScrollExtent, paintExtent: calculatePaintOffset(constraints, from: 0, to: totalScrollExtent), maxPaintExtent: maxPaintExtent, + hasVisualOverflow: totalScrollExtent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0, ); } diff --git a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart index 597c196acb3e7..c0f89fa308b68 100644 --- a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart @@ -61,6 +61,7 @@ void main() { final RenderSliverMainAxisGroup renderGroup = tester.renderObject(find.byType(SliverMainAxisGroup)); expect(renderGroup.geometry!.scrollExtent, equals(300 * 20 + 200 * 20)); + expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); testWidgets('SliverMainAxisGroup is laid out properly when reversed', (WidgetTester tester) async { @@ -112,6 +113,7 @@ void main() { final RenderSliverMainAxisGroup renderGroup = tester.renderObject(find.byType(SliverMainAxisGroup)); expect(renderGroup.geometry!.scrollExtent, equals(300 * 20 + 200 * 20)); + expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); testWidgets('SliverMainAxisGroup is laid out properly when horizontal', (WidgetTester tester) async { @@ -168,6 +170,7 @@ void main() { final RenderSliverMainAxisGroup renderGroup = tester.renderObject(find.byType(SliverMainAxisGroup)); expect(renderGroup.geometry!.scrollExtent, equals(300 * 20 + 200 * 20)); + expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); testWidgets('SliverMainAxisGroup is laid out properly when horizontal, reversed', (WidgetTester tester) async { @@ -225,6 +228,7 @@ void main() { final RenderSliverMainAxisGroup renderGroup = tester.renderObject(find.byType(SliverMainAxisGroup)); expect(renderGroup.geometry!.scrollExtent, equals(300 * 20 + 200 * 20)); + expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); testWidgets('Hit test works properly on various parts of SliverMainAxisGroup', (WidgetTester tester) async { From 8e7304bb2781e5af7f9fde8b702d2ef9e484b3e5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 21 Aug 2023 22:35:36 -0400 Subject: [PATCH 0825/1547] Roll Flutter Engine from 5a292e42a593 to 1ab054967c1d (1 revision) (#133014) https://github.com/flutter/engine/compare/5a292e42a593...1ab054967c1d 2023-08-22 chinmaygarde@google.com [Impeller] Document rendering backend selection on Android. (flutter/engine#44933) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f33ca5dfa689e..568bea09ee775 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5a292e42a59341d33d13b730fdfebd9ba65c889f +1ab054967c1d0a081c82dc3ee25eff4ae4190ab6 From fedf0a8a118d30a5b9bdd985db7dfcd170b9b92a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 00:30:24 -0400 Subject: [PATCH 0826/1547] Roll Flutter Engine from 1ab054967c1d to 857840db5574 (2 revisions) (#133018) https://github.com/flutter/engine/compare/1ab054967c1d...857840db5574 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from 40442138ec94 to 9ecdc9265aaa (1 revision) (flutter/engine#44939) 2023-08-22 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from aXDvHIK6XMKTHieu_... to DA_PryqcVU6Um3j2k... (flutter/engine#44938) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from aXDvHIK6XMKT to DA_PryqcVU6U If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 568bea09ee775..a12cead26a755 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1ab054967c1d0a081c82dc3ee25eff4ae4190ab6 +857840db557449582a47239c871573e46cc97eff diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 19f6d0ff21624..b4ff53d7c3c17 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -aXDvHIK6XMKTHieu_Lz24exKSmxWpRqXS5f3B7_Y1DEC +DA_PryqcVU6Um3j2knmxFnoY0owmURpknkVTtrPBXXQC From 5b209884832afcba4f3ac584946db0bd4d42ee6e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 01:26:25 -0400 Subject: [PATCH 0827/1547] Roll Flutter Engine from 857840db5574 to 454e0e35f8e4 (1 revision) (#133020) https://github.com/flutter/engine/compare/857840db5574...454e0e35f8e4 2023-08-22 matanlurey@users.noreply.github.com Disallow using ./tools/gn --enable-unittests --android (or --ios) (flutter/engine#44930) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a12cead26a755..0cd82a82a0691 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -857840db557449582a47239c871573e46cc97eff +454e0e35f8e4ee3f9447c0d05a8983b3bac8827a From e085e613c82bb5ecaeb524fd5c4061622d2ae77b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 02:58:24 -0400 Subject: [PATCH 0828/1547] Roll Flutter Engine from 454e0e35f8e4 to e183e8a94093 (2 revisions) (#133026) https://github.com/flutter/engine/compare/454e0e35f8e4...e183e8a94093 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from 9ecdc9265aaa to 14e7b3b2d660 (1 revision) (flutter/engine#44942) 2023-08-22 bdero@google.com [Impeller] Supply a text backend to the AiksContext at runtime. (flutter/engine#44884) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0cd82a82a0691..1603fbac6f45c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -454e0e35f8e4ee3f9447c0d05a8983b3bac8827a +e183e8a94093bc9049394127733af41dad53e4ba From f238211e1f730f5c38565ea7f5b2399981ff65fd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 03:58:43 -0400 Subject: [PATCH 0829/1547] Roll Flutter Engine from e183e8a94093 to 5e84d733ef67 (1 revision) (#133030) https://github.com/flutter/engine/compare/e183e8a94093...5e84d733ef67 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from 14e7b3b2d660 to 399e90397a07 (1 revision) (flutter/engine#44943) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jsimmons@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1603fbac6f45c..914f328eeacd3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e183e8a94093bc9049394127733af41dad53e4ba +5e84d733ef6743d7a1d54c65d6ca87c422d3c074 From 7171c9b3944f1b583551b17a001c3ac44671c6e0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 04:51:24 -0400 Subject: [PATCH 0830/1547] Roll Flutter Engine from 5e84d733ef67 to 447981acbf36 (2 revisions) (#133031) https://github.com/flutter/engine/compare/5e84d733ef67...447981acbf36 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from 399e90397a07 to f13ee6ee5433 (1 revision) (flutter/engine#44944) 2023-08-22 leroux_bruno@yahoo.fr [Linux] Expose channel buffers 'resize' and 'overflow' control commands (flutter/engine#44636) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 914f328eeacd3..db4f05316515a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5e84d733ef6743d7a1d54c65d6ca87c422d3c074 +447981acbf36f6743764e904359afaffbe7f2eea From 54c98d7433c5cd869bac9c5f70e5280e4866240d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 05:36:40 -0400 Subject: [PATCH 0831/1547] Roll Flutter Engine from 447981acbf36 to f5f099a4a5e3 (1 revision) (#133035) https://github.com/flutter/engine/compare/447981acbf36...f5f099a4a5e3 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from f13ee6ee5433 to bf08da24a261 (1 revision) (flutter/engine#44946) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index db4f05316515a..8aa3e2b80ca7f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -447981acbf36f6743764e904359afaffbe7f2eea +f5f099a4a5e3ba2b819ddd1b0ce80807e18de7c6 From c00bdc832dd6a8df586f9b3de723329bd5d41c9b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 11:45:09 -0400 Subject: [PATCH 0832/1547] Roll Flutter Engine from f5f099a4a5e3 to c5e0152b01f4 (4 revisions) (#133049) https://github.com/flutter/engine/compare/f5f099a4a5e3...c5e0152b01f4 2023-08-22 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from DA_PryqcVU6Um3j2k... to G25oJMO5jbUi-UN4F... (flutter/engine#44951) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from bf08da24a261 to b3b8f3332cce (1 revision) (flutter/engine#44952) 2023-08-22 skia-flutter-autoroll@skia.org Roll Dart SDK from 00f6f69187df to ecb1e3aecfbb (1 revision) (flutter/engine#44950) 2023-08-22 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from RVhmZNTYsaIiTyjwP... to kKI09su99b0AKs8b3... (flutter/engine#44949) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from RVhmZNTYsaIi to kKI09su99b0A fuchsia/sdk/core/mac-amd64 from DA_PryqcVU6U to G25oJMO5jbUi If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8aa3e2b80ca7f..b31a1225a253b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f5f099a4a5e3ba2b819ddd1b0ce80807e18de7c6 +c5e0152b01f44e3e34ace6a68be42c74a384245d diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index feac59b6d7da8..e2a043b24b7c3 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -RVhmZNTYsaIiTyjwPz_v93og9qBqvH0fo75kFNmXe10C +kKI09su99b0AKs8b3VKTzXDVmeTaKm7ye2chxl9BE0EC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index b4ff53d7c3c17..ca462e033d535 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -DA_PryqcVU6Um3j2knmxFnoY0owmURpknkVTtrPBXXQC +G25oJMO5jbUi-UN4FM1owc2acv-i0u7MdKqblmI-czMC From 4e6da2dcc7f23059691716ff784b176459be6663 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 22 Aug 2023 08:50:48 -0700 Subject: [PATCH 0833/1547] Cover more tests with leak tracking. (#132806) This PR replaces some `testWidgets` with `testWidgestsWithLeakTracking`. --- .../flutter/test/material/app_bar_test.dart | 283 +++++++++--------- .../test/material/app_bar_theme_test.dart | 63 ++-- packages/flutter/test/material/app_test.dart | 103 +++---- .../test/material/back_button_test.dart | 2 +- .../test/material/radio_list_tile_test.dart | 55 ++-- 5 files changed, 255 insertions(+), 251 deletions(-) diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index af1ee49ad6411..e32a962de35b2 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -81,7 +82,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('AppBar centers title on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centers title on iOS', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.android), @@ -162,7 +163,7 @@ void main() { } }); - testWidgets('AppBar centerTitle:true centers on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centerTitle:true centers on Android', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.android), @@ -182,7 +183,7 @@ void main() { expect(center.dx, lessThan(400 + size.width / 2.0)); }); - testWidgets('AppBar centerTitle:false title start edge is 16.0 (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centerTitle:false title start edge is 16.0 (LTR)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -199,7 +200,7 @@ void main() { expect(tester.getTopRight(titleWidget).dx, 800 - 16.0); }); - testWidgets('AppBar centerTitle:false title start edge is 16.0 (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centerTitle:false title start edge is 16.0 (RTL)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -219,7 +220,7 @@ void main() { expect(tester.getTopLeft(titleWidget).dx, 16.0); }); - testWidgets('AppBar titleSpacing:32 title start edge is 32.0 (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar titleSpacing:32 title start edge is 32.0 (LTR)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -237,7 +238,7 @@ void main() { expect(tester.getTopRight(titleWidget).dx, 800 - 32.0); }); - testWidgets('AppBar titleSpacing:32 title start edge is 32.0 (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar titleSpacing:32 title start edge is 32.0 (RTL)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -258,7 +259,7 @@ void main() { expect(tester.getTopLeft(titleWidget).dx, 32.0); }); - testWidgets( + testWidgetsWithLeakTracking( 'AppBar centerTitle:false leading button title left edge is 72.0 (LTR)', (WidgetTester tester) async { await tester.pumpWidget( @@ -278,7 +279,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'AppBar centerTitle:false leading button title left edge is 72.0 (RTL)', (WidgetTester tester) async { await tester.pumpWidget( @@ -301,7 +302,7 @@ void main() { }, ); - testWidgets('AppBar centerTitle:false title overflow OK', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centerTitle:false title overflow OK', (WidgetTester tester) async { // The app bar's title should be constrained to fit within the available space // between the leading and actions widgets. @@ -362,7 +363,7 @@ void main() { expect(tester.getSize(title).width, equals(800.0 - 56.0 - 16.0 - 16.0 - 200.0)); }); - testWidgets('AppBar centerTitle:true title overflow OK (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centerTitle:true title overflow OK (LTR)', (WidgetTester tester) async { // The app bar's title should be constrained to fit within the available space // between the leading and actions widgets. When it's also centered it may // also be start or end justified if it doesn't fit in the overall center. @@ -414,7 +415,7 @@ void main() { expect(tester.getSize(title).width, equals(620.0)); }); - testWidgets('AppBar centerTitle:true title overflow OK (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar centerTitle:true title overflow OK (RTL)', (WidgetTester tester) async { // The app bar's title should be constrained to fit within the available space // between the leading and actions widgets. When it's also centered it may // also be start or end justified if it doesn't fit in the overall center. @@ -469,7 +470,7 @@ void main() { expect(tester.getSize(title).width, equals(620.0)); }); - testWidgets('AppBar with no Scaffold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar with no Scaffold', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SizedBox( @@ -489,7 +490,7 @@ void main() { expect(find.text('A2'), findsOneWidget); }); - testWidgets('AppBar render at zero size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar render at zero size', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Center( @@ -508,7 +509,7 @@ void main() { expect(tester.getSize(title).isEmpty, isTrue); }); - testWidgets('AppBar actions are vertically centered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar actions are vertically centered', (WidgetTester tester) async { final UniqueKey appBarKey = UniqueKey(); final UniqueKey leadingKey = UniqueKey(); final UniqueKey titleKey = UniqueKey(); @@ -540,7 +541,7 @@ void main() { expect(yCenter(appBarKey), equals(yCenter(action1Key))); }); - testWidgets('AppBar drawer icon has default size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar drawer icon has default size', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -558,7 +559,7 @@ void main() { ); }); - testWidgets('Material2 - AppBar drawer icon has default color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AppBar drawer icon has default color', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: false, @@ -578,7 +579,7 @@ void main() { expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onPrimary); }); - testWidgets('Material3 - AppBar drawer icon has default color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar drawer icon has default color', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: true, @@ -598,7 +599,7 @@ void main() { expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onSurfaceVariant); }); - testWidgets('AppBar drawer icon is sized by iconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar drawer icon is sized by iconTheme', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -616,7 +617,7 @@ void main() { ); }); - testWidgets('AppBar drawer icon is colored by iconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar drawer icon is colored by iconTheme', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from(colorScheme: const ColorScheme.light()); const Color color = Color(0xFF2196F3); @@ -636,7 +637,7 @@ void main() { expect(_iconStyle(tester, Icons.menu)?.color, color); }); - testWidgets('AppBar endDrawer icon has default size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar endDrawer icon has default size', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -655,7 +656,7 @@ void main() { ); }); - testWidgets('Material2 - AppBar endDrawer icon has default color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AppBar endDrawer icon has default color', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: false, @@ -675,7 +676,7 @@ void main() { expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onPrimary); }); - testWidgets('Material3 - AppBar endDrawer icon has default color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar endDrawer icon has default color', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: true, @@ -695,7 +696,7 @@ void main() { expect(_iconStyle(tester, Icons.menu)?.color, themeData.colorScheme.onSurfaceVariant); }); - testWidgets('AppBar endDrawer icon is sized by iconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar endDrawer icon is sized by iconTheme', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -713,7 +714,7 @@ void main() { ); }); - testWidgets('AppBar endDrawer icon is colored by iconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar endDrawer icon is colored by iconTheme', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from(colorScheme: const ColorScheme.light()); const Color color = Color(0xFF2196F3); @@ -733,7 +734,7 @@ void main() { expect(_iconStyle(tester, Icons.menu)?.color, color); }); - testWidgets('Material2 - leading widget extends to edge and is square', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - leading widget extends to edge and is square', (WidgetTester tester) async { final ThemeData themeData = ThemeData( platform: TargetPlatform.android, useMaterial3: false, @@ -791,7 +792,7 @@ void main() { expect(tester.getSize(leading), const Size(56.0, 56.0)); }); - testWidgets('Material3 - leading widget extends to edge and is square', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - leading widget extends to edge and is square', (WidgetTester tester) async { final ThemeData themeData = ThemeData( platform: TargetPlatform.android, useMaterial3: true, @@ -849,7 +850,7 @@ void main() { expect(tester.getSize(leading), const Size(56.0, 56.0)); }); - testWidgets('Material2 - Action is 4dp from edge and 48dp min', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Action is 4dp from edge and 48dp min', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, useMaterial3: false, @@ -889,7 +890,7 @@ void main() { expect(tester.getSize(shareButton), const Size(48.0, 56.0)); }); - testWidgets('Material3 - Action is 4dp from edge and 48dp min', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Action is 4dp from edge and 48dp min', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, useMaterial3: true, @@ -929,7 +930,7 @@ void main() { expect(tester.getSize(shareButton), const Size(48.0, 48.0)); }); - testWidgets('SliverAppBar default configuration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar default configuration', (WidgetTester tester) async { await tester.pumpWidget(buildSliverAppBarApp()); final ScrollController controller = primaryScrollController(tester); @@ -961,7 +962,7 @@ void main() { expect(tabBarHeight(tester), initialTabBarHeight); }); - testWidgets('SliverAppBar expandedHeight, pinned', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar expandedHeight, pinned', (WidgetTester tester) async { await tester.pumpWidget(buildSliverAppBarApp( pinned: true, expandedHeight: 128.0, @@ -992,7 +993,7 @@ void main() { expect(tabBarHeight(tester), initialTabBarHeight); }); - testWidgets('SliverAppBar expandedHeight, pinned and floating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar expandedHeight, pinned and floating', (WidgetTester tester) async { await tester.pumpWidget(buildSliverAppBarApp( floating: true, pinned: true, @@ -1024,7 +1025,7 @@ void main() { expect(tabBarHeight(tester), initialTabBarHeight); }); - testWidgets('SliverAppBar expandedHeight, floating with snap:true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar expandedHeight, floating with snap:true', (WidgetTester tester) async { await tester.pumpWidget(buildSliverAppBarApp( floating: true, snap: true, @@ -1104,7 +1105,7 @@ void main() { expect(appBarBottom(tester), lessThanOrEqualTo(0.0)); }); - testWidgets('SliverAppBar expandedHeight, floating and pinned with snap:true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar expandedHeight, floating and pinned with snap:true', (WidgetTester tester) async { await tester.pumpWidget(buildSliverAppBarApp( floating: true, pinned: true, @@ -1190,7 +1191,7 @@ void main() { expect(appBarBottom(tester), kTextTabBarHeight); }); - testWidgets('SliverAppBar expandedHeight, collapsedHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar expandedHeight, collapsedHeight', (WidgetTester tester) async { const double expandedAppBarHeight = 400.0; const double collapsedAppBarHeight = 200.0; @@ -1228,7 +1229,7 @@ void main() { expect(tabBarHeight(tester), initialTabBarHeight); }); - testWidgets('Material3 - SliverAppBar.medium defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SliverAppBar.medium defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 112; @@ -1317,7 +1318,7 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('Material3 - SliverAppBar.large defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SliverAppBar.large defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 152; @@ -1410,7 +1411,7 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('Material2 - AppBar uses the specified elevation or defaults to 4.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AppBar uses the specified elevation or defaults to 4.0', (WidgetTester tester) async { Widget buildAppBar([double? elevation]) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1434,7 +1435,7 @@ void main() { expect(getMaterial().elevation, 8.0); }); - testWidgets('Material3 - AppBar uses the specified elevation or defaults to 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar uses the specified elevation or defaults to 0', (WidgetTester tester) async { Widget buildAppBar([double? elevation]) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1458,7 +1459,7 @@ void main() { expect(getMaterial().elevation, 8.0); }); - testWidgets('scrolledUnderElevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrolledUnderElevation', (WidgetTester tester) async { Widget buildAppBar({double? elevation, double? scrolledUnderElevation}) { return MaterialApp( home: Scaffold( @@ -1491,7 +1492,7 @@ void main() { expect(getMaterial().elevation, 10); }); - testWidgets('Material3 - scrolledUnderElevation with nested scroll view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - scrolledUnderElevation with nested scroll view', (WidgetTester tester) async { Widget buildAppBar({double? scrolledUnderElevation}) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1560,7 +1561,7 @@ void main() { ); } - testWidgets('Respects forceElevated parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Respects forceElevated parameter', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59158. AppBar getAppBar() => tester.widget(find.byType(AppBar)); Material getMaterial() => tester.widget(find.byType(Material)); @@ -1583,7 +1584,7 @@ void main() { expect(getMaterial().elevation, 8.0); }); - testWidgets('Uses elevation of AppBarTheme by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses elevation of AppBarTheme by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/73525. Material getMaterial() => tester.widget(find.byType(Material)); @@ -1646,7 +1647,7 @@ void main() { ); } - testWidgets( + testWidgetsWithLeakTracking( 'forceMaterialTransparency == true allows gestures beneath the app bar', (WidgetTester tester) async { bool buttonWasPressed = false; final Widget widget = buildWidget( @@ -1664,7 +1665,7 @@ void main() { expect(buttonWasPressed, isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'forceMaterialTransparency == false does not allow gestures beneath the app bar', (WidgetTester tester) async { // Set this, and tester.tap(warnIfMissed:false), to suppress // errors/warning that the button is not hittable (which is expected). @@ -1687,7 +1688,7 @@ void main() { }); }); - testWidgets('AppBar dimensions, with and without bottom, primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar dimensions, with and without bottom, primary', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100.0)); await tester.pumpWidget( @@ -1812,7 +1813,7 @@ void main() { expect(tester.getTopLeft(find.text('title')).dy, lessThan(100.0)); }); - testWidgets('AppBar in body excludes bottom SafeArea padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar in body excludes bottom SafeArea padding', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/26163 await tester.pumpWidget( Localizations( @@ -1842,7 +1843,7 @@ void main() { expect(appBarHeight(tester), kToolbarHeight + 100.0); }); - testWidgets('AppBar.title sees the correct padding from MediaQuery', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.title sees the correct padding from MediaQuery', (WidgetTester tester) async { bool titleBuilt = false; await tester.pumpWidget( Localizations( @@ -1872,7 +1873,7 @@ void main() { expect(titleBuilt, isTrue); }); - testWidgets('AppBar updates when you add a drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar updates when you add a drawer', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1892,7 +1893,7 @@ void main() { expect(find.byIcon(Icons.menu), findsOneWidget); }); - testWidgets('AppBar does not draw menu for drawer if automaticallyImplyLeading is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar does not draw menu for drawer if automaticallyImplyLeading is false', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1906,7 +1907,7 @@ void main() { expect(find.byIcon(Icons.menu), findsNothing); }); - testWidgets('AppBar does not update the leading if a route is popped case 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar does not update the leading if a route is popped case 1', (WidgetTester tester) async { final Page page1 = MaterialPage( key: const ValueKey('1'), child: Scaffold( @@ -1944,7 +1945,7 @@ void main() { expect(find.byType(BackButton), findsNothing); }); - testWidgets('AppBar does not update the leading if a route is popped case 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar does not update the leading if a route is popped case 2', (WidgetTester tester) async { final Page page1 = MaterialPage( key: const ValueKey('1'), child: Scaffold( @@ -1997,7 +1998,7 @@ void main() { ); }); - testWidgets('Material2 - AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/58665 final Key key = UniqueKey(); await tester.pumpWidget( @@ -2044,7 +2045,7 @@ void main() { expect(painter, paints..save()..translate()..save()..translate()..circle(x: 24.0, y: 28.0)); }); - testWidgets('Material3 - AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar ink splash draw on the correct canvas', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/58665 final Key key = UniqueKey(); await tester.pumpWidget( @@ -2091,7 +2092,7 @@ void main() { expect(painter, paints..save()..translate()..save()..translate()..circle(x: 20.0, y: 20.0)); }); - testWidgets('AppBar handles loose children 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar handles loose children 0', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -2112,7 +2113,7 @@ void main() { expect(tester.renderObject(find.byKey(key)).size, const Size(56.0, 56.0)); }); - testWidgets('AppBar handles loose children 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar handles loose children 1', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -2142,7 +2143,7 @@ void main() { expect(tester.renderObject(find.byKey(key)).size, const Size(56.0, 56.0)); }); - testWidgets('AppBar handles loose children 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar handles loose children 2', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -2182,7 +2183,7 @@ void main() { expect(tester.renderObject(find.byKey(key)).size, const Size(56.0, 56.0)); }); - testWidgets('AppBar handles loose children 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar handles loose children 3', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -2213,7 +2214,7 @@ void main() { expect(tester.renderObject(find.byKey(key)).size, const Size(56.0, 56.0)); }); - testWidgets('AppBar positioning of leading and trailing widgets with top padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar positioning of leading and trailing widgets with top padding', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100)); final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); @@ -2256,7 +2257,7 @@ void main() { expect(tester.getTopLeft(find.byKey(titleKey)), const Offset(10 + NavigationToolbar.kMiddleSpacing, 72)); }); - testWidgets('SliverAppBar positioning of leading and trailing widgets with top padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar positioning of leading and trailing widgets with top padding', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100.0)); final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); @@ -2293,7 +2294,7 @@ void main() { expect(tester.getTopLeft(find.byKey(trailingKey)), const Offset(0.0, 100.0)); }); - testWidgets('SliverAppBar positioning of leading and trailing widgets with bottom padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar positioning of leading and trailing widgets with bottom padding', (WidgetTester tester) async { const MediaQueryData topPadding100 = MediaQueryData(padding: EdgeInsets.only(top: 100.0, bottom: 50.0)); final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); @@ -2329,7 +2330,7 @@ void main() { expect(tester.getRect(find.byKey(trailingKey)), const Rect.fromLTRB(0.0, 100.0, 400.0, 100.0 + 56.0)); }); - testWidgets('SliverAppBar provides correct semantics in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar provides correct semantics in LTR', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2410,7 +2411,7 @@ void main() { semantics.dispose(); }); - testWidgets('SliverAppBar provides correct semantics in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar provides correct semantics in RTL', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2502,7 +2503,7 @@ void main() { semantics.dispose(); }); - testWidgets('AppBar excludes header semantics correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar excludes header semantics correctly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2558,7 +2559,7 @@ void main() { semantics.dispose(); }); - testWidgets('SliverAppBar excludes header semantics correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar excludes header semantics correctly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -2627,7 +2628,7 @@ void main() { semantics.dispose(); }); - testWidgets('SliverAppBar with flexible space has correct semantics order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with flexible space has correct semantics order', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/64922. final SemanticsTester semantics = SemanticsTester(tester); @@ -2704,7 +2705,7 @@ void main() { semantics.dispose(); }); - testWidgets('Material2 - AppBar draws a light system bar for a dark background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AppBar draws a light system bar for a dark background', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(useMaterial3: false); await tester.pumpWidget(MaterialApp( theme: darkTheme, @@ -2722,7 +2723,7 @@ void main() { )); }); - testWidgets('Material3 - AppBar draws a light system bar for a dark background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar draws a light system bar for a dark background', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: darkTheme, @@ -2741,7 +2742,7 @@ void main() { )); }); - testWidgets('Material2 - AppBar draws a dark system bar for a light background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AppBar draws a dark system bar for a light background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData(primarySwatch: Colors.lightBlue, useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -2761,7 +2762,7 @@ void main() { )); }); - testWidgets('Material3 - AppBar draws a dark system bar for a light background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar draws a dark system bar for a light background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -2782,7 +2783,7 @@ void main() { )); }); - testWidgets('Material2 - Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { Widget buildAppBar(ThemeData theme) { return MaterialApp( theme: theme, @@ -2833,7 +2834,7 @@ void main() { } }); - testWidgets('Material3 - Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default system bar brightness based on AppBar background color brightness.', (WidgetTester tester) async { Widget buildAppBar(ThemeData theme) { return MaterialApp( theme: theme, @@ -2886,7 +2887,7 @@ void main() { } }); - testWidgets('Material2 - Default status bar color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default status bar color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( key: GlobalKey(), @@ -2905,7 +2906,7 @@ void main() { expect(SystemChrome.latestStyle!.statusBarColor, null); }); - testWidgets('Material3 - Default status bar color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default status bar color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( key: GlobalKey(), @@ -2924,7 +2925,7 @@ void main() { expect(SystemChrome.latestStyle!.statusBarColor, Colors.transparent); }); - testWidgets('AppBar systemOverlayStyle is use to style status bar and navigation bar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar systemOverlayStyle is use to style status bar and navigation bar', (WidgetTester tester) async { final SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.light.copyWith( statusBarColor: Colors.red, systemNavigationBarColor: Colors.green, @@ -2944,7 +2945,7 @@ void main() { expect(SystemChrome.latestStyle!.systemNavigationBarColor, Colors.green); }); - testWidgets('Changing SliverAppBar snap from true to false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing SliverAppBar snap from true to false', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17598 const double appBarHeight = 256.0; bool snap = true; @@ -3005,7 +3006,7 @@ void main() { await tester.pump(); }); - testWidgets('AppBar shape default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar shape default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: AppBar( @@ -3025,7 +3026,7 @@ void main() { expect(getMaterialWidget(materialFinder).shape, null); }); - testWidgets('AppBar with shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar with shape', (WidgetTester tester) async { const RoundedRectangleBorder roundedRectangleBorder = RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(15.0)), ); @@ -3049,7 +3050,7 @@ void main() { expect(getMaterialWidget(materialFinder).shape, roundedRectangleBorder); }); - testWidgets('SliverAppBar shape default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar shape default', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: CustomScrollView( @@ -3073,7 +3074,7 @@ void main() { expect(getMaterialWidget(materialFinder).shape, null); }); - testWidgets('SliverAppBar with shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with shape', (WidgetTester tester) async { const RoundedRectangleBorder roundedRectangleBorder = RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(15.0)), ); @@ -3101,7 +3102,7 @@ void main() { expect(getMaterialWidget(materialFinder).shape, roundedRectangleBorder); }); - testWidgets('AppBars title has upper limit on text scaling, textScaleFactor = 1, 1.34, 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBars title has upper limit on text scaling, textScaleFactor = 1, 1.34, 2', (WidgetTester tester) async { late double textScaleFactor; Widget buildFrame() { @@ -3139,7 +3140,7 @@ void main() { expect(tester.getRect(appBarTitle).height, 24); }); - testWidgets('AppBars with jumbo titles, textScaleFactor = 3, 3.5, 4', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBars with jumbo titles, textScaleFactor = 3, 3.5, 4', (WidgetTester tester) async { double textScaleFactor = 1.0; TextDirection textDirection = TextDirection.ltr; bool centerTitle = false; @@ -3209,7 +3210,7 @@ void main() { expect(tester.getCenter(appBarTitle).dy, tester.getCenter(toolbar).dy); }); - testWidgets('SliverAppBar configures the delegate properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar configures the delegate properly', (WidgetTester tester) async { Future buildAndVerifyDelegate({ required bool pinned, required bool floating, required bool snap }) async { await tester.pumpWidget( MaterialApp( @@ -3245,7 +3246,7 @@ void main() { await buildAndVerifyDelegate(pinned: true, floating: true, snap: true); }); - testWidgets('AppBar respects toolbarHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar respects toolbarHeight', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -3261,7 +3262,7 @@ void main() { expect(appBarHeight(tester), 48); }); - testWidgets('SliverAppBar default collapsedHeight with respect to toolbarHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar default collapsedHeight with respect to toolbarHeight', (WidgetTester tester) async { const double toolbarHeight = 100.0; await tester.pumpWidget(buildSliverAppBarApp( @@ -3280,7 +3281,7 @@ void main() { expect(appBarHeight(tester), toolbarHeight + initialTabBarHeight); }); - testWidgets('SliverAppBar collapsedHeight with toolbarHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar collapsedHeight with toolbarHeight', (WidgetTester tester) async { const double toolbarHeight = 100.0; const double collapsedHeight = 150.0; @@ -3299,7 +3300,7 @@ void main() { expect(appBarHeight(tester), collapsedHeight + initialTabBarHeight); }); - testWidgets('SliverAppBar collapsedHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar collapsedHeight', (WidgetTester tester) async { const double collapsedHeight = 56.0; await tester.pumpWidget(buildSliverAppBarApp( @@ -3316,7 +3317,7 @@ void main() { expect(appBarHeight(tester), collapsedHeight + initialTabBarHeight); }); - testWidgets('AppBar respects leadingWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar respects leadingWidth', (WidgetTester tester) async { const Key key = Key('leading'); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -3332,7 +3333,7 @@ void main() { expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0, 0, 100, 56)); }); - testWidgets('SliverAppBar respects leadingWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar respects leadingWidth', (WidgetTester tester) async { const Key key = Key('leading'); await tester.pumpWidget(const MaterialApp( home: CustomScrollView( @@ -3367,7 +3368,7 @@ void main() { expect(getAppBarWidget(appBarFinder).leading, null); }); - testWidgets('AppBar.titleSpacing defaults to NavigationToolbar.kMiddleSpacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.titleSpacing defaults to NavigationToolbar.kMiddleSpacing', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( appBar: AppBar( @@ -3380,14 +3381,14 @@ void main() { expect(navToolBar.middleSpacing, NavigationToolbar.kMiddleSpacing); }); - testWidgets('SliverAppBar.titleSpacing defaults to NavigationToolbar.kMiddleSpacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.titleSpacing defaults to NavigationToolbar.kMiddleSpacing', (WidgetTester tester) async { await tester.pumpWidget(buildSliverAppBarApp()); final NavigationToolbar navToolBar = tester.widget(find.byType(NavigationToolbar)); expect(navToolBar.middleSpacing, NavigationToolbar.kMiddleSpacing); }); - testWidgets('AppBar foregroundColor and backgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar foregroundColor and backgroundColor', (WidgetTester tester) async { const Color foregroundColor = Color(0xff00ff00); const Color backgroundColor = Color(0xff00ffff); final Key leadingIconKey = UniqueKey(); @@ -3438,7 +3439,7 @@ void main() { expect(actionIconColor(), foregroundColor); }); - testWidgets('Leading, title, and actions show correct default colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Leading, title, and actions show correct default colors', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light( onPrimary: Colors.blue, @@ -3476,7 +3477,7 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/107305 group('Material3 - Icons are colored correctly by IconTheme and ActionIconTheme', () { - testWidgets('Material3 - Icons and IconButtons are colored by IconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Icons and IconButtons are colored by IconTheme', (WidgetTester tester) async { const Color iconColor = Color(0xff00ff00); final Key leadingIconKey = UniqueKey(); final Key actionIconKey = UniqueKey(); @@ -3508,7 +3509,7 @@ void main() { expect(actionIconButtonColor(), iconColor); }); - testWidgets('Material3 - Action icons and IconButtons are colored by ActionIconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Action icons and IconButtons are colored by ActionIconTheme', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: true, @@ -3544,7 +3545,7 @@ void main() { expect(actionIconButtonColor(), actionsIconColor); }); - testWidgets('Material3 - The actionIconTheme property overrides iconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - The actionIconTheme property overrides iconTheme', (WidgetTester tester) async { final ThemeData themeData = ThemeData.from( colorScheme: const ColorScheme.light(), useMaterial3: true, @@ -3582,7 +3583,7 @@ void main() { expect(actionIconButtonColor(), actionsIconColor); }); - testWidgets('Material3 - AppBar.iconTheme should override any IconButtonTheme present in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.iconTheme should override any IconButtonTheme present in the theme', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3621,7 +3622,7 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('Material3 - AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.iconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3654,7 +3655,7 @@ void main() { }); - testWidgets('Material3 - AppBar.actionsIconTheme should override any IconButtonTheme present in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.actionsIconTheme should override any IconButtonTheme present in the theme', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3694,7 +3695,7 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('Material3 - AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.actionsIconTheme should override any IconButtonTheme present in the theme for widgets containing an iconButton', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3728,7 +3729,7 @@ void main() { expect(actionIconButtonSize(), 30.0); }); - testWidgets('Material3 - The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - The foregroundColor property of the AppBar overrides any IconButtonTheme present in the theme', (WidgetTester tester) async { final ThemeData themeData = ThemeData( iconButtonTheme: IconButtonThemeData( style: IconButton.styleFrom( @@ -3762,7 +3763,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/130485. - testWidgets('Material3 - AppBar.iconTheme is correctly applied in dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.iconTheme is correctly applied in dark mode', (WidgetTester tester) async { final ThemeData themeData = ThemeData( colorScheme: const ColorScheme.dark().copyWith(onSurfaceVariant: Colors.red), useMaterial3: true, @@ -3790,7 +3791,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/130485. - testWidgets('Material3 - AppBar.foregroundColor is correctly applied in dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.foregroundColor is correctly applied in dark mode', (WidgetTester tester) async { final ThemeData themeData = ThemeData( colorScheme: const ColorScheme.dark().copyWith(onSurfaceVariant: Colors.red), useMaterial3: true, @@ -3818,7 +3819,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/130485. - testWidgets('Material3 - AppBar.iconTheme is correctly applied in light mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.iconTheme is correctly applied in light mode', (WidgetTester tester) async { final ThemeData themeData = ThemeData( colorScheme: const ColorScheme.light().copyWith(onSurfaceVariant: Colors.red), useMaterial3: true, @@ -3846,7 +3847,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/130485. - testWidgets('Material3 - AppBar.foregroundColor is correctly applied in light mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBar.foregroundColor is correctly applied in light mode', (WidgetTester tester) async { final ThemeData themeData = ThemeData( colorScheme: const ColorScheme.light().copyWith(onSurfaceVariant: Colors.red), useMaterial3: true, @@ -3925,7 +3926,7 @@ void main() { ); } - testWidgets('backgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor', (WidgetTester tester) async { await tester.pumpWidget( buildSliverApp(contentHeight: 1200.0) ); @@ -3950,7 +3951,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, expandedHeight); }); - testWidgets('backgroundColor with FlexibleSpace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor with FlexibleSpace', (WidgetTester tester) async { await tester.pumpWidget( buildSliverApp(contentHeight: 1200.0, includeFlexibleSpace: true) ); @@ -3975,7 +3976,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, expandedHeight); }); - testWidgets('backgroundColor - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor - reverse', (WidgetTester tester) async { await tester.pumpWidget( buildSliverApp(contentHeight: 1200.0, reverse: true) ); @@ -4000,7 +4001,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, expandedHeight); }); - testWidgets('backgroundColor with FlexibleSpace - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor with FlexibleSpace - reverse', (WidgetTester tester) async { await tester.pumpWidget( buildSliverApp( contentHeight: 1200.0, @@ -4029,7 +4030,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, expandedHeight); }); - testWidgets('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async { await tester.pumpWidget( buildSliverApp(contentHeight: 200, reverse: true) ); @@ -4048,7 +4049,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, expandedHeight); }); - testWidgets('backgroundColor with FlexibleSpace - not triggered in reverse for short content', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor with FlexibleSpace - not triggered in reverse for short content', (WidgetTester tester) async { await tester.pumpWidget( buildSliverApp( contentHeight: 200, @@ -4102,7 +4103,7 @@ void main() { ); } - testWidgets('backgroundColor for horizontal scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor for horizontal scrolling', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -4160,7 +4161,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight); }); - testWidgets('backgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor', (WidgetTester tester) async { await tester.pumpWidget( buildAppBar(contentHeight: 1200.0) ); @@ -4185,7 +4186,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight); }); - testWidgets('backgroundColor with FlexibleSpace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor with FlexibleSpace', (WidgetTester tester) async { await tester.pumpWidget( buildAppBar(contentHeight: 1200.0, includeFlexibleSpace: true) ); @@ -4210,7 +4211,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight); }); - testWidgets('backgroundColor - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor - reverse', (WidgetTester tester) async { await tester.pumpWidget( buildAppBar(contentHeight: 1200.0, reverse: true) ); @@ -4238,7 +4239,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight); }); - testWidgets('backgroundColor with FlexibleSpace - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor with FlexibleSpace - reverse', (WidgetTester tester) async { await tester.pumpWidget( buildAppBar( contentHeight: 1200.0, @@ -4270,7 +4271,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight); }); - testWidgets('_handleScrollNotification safely calls setState()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('_handleScrollNotification safely calls setState()', (WidgetTester tester) async { // Regression test for failures found in Google internal issue b/185192049. final ScrollController controller = ScrollController(initialScrollOffset: 400); await tester.pumpWidget( @@ -4296,7 +4297,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('does not trigger on horizontal scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not trigger on horizontal scroll', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -4336,7 +4337,7 @@ void main() { expect(getAppBarBackgroundColor(tester), defaultColor); }); - testWidgets('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async { await tester.pumpWidget( buildAppBar( contentHeight: 200.0, @@ -4359,7 +4360,7 @@ void main() { expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight); }); - testWidgets('backgroundColor with FlexibleSpace - not triggered in reverse for short content', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backgroundColor with FlexibleSpace - not triggered in reverse for short content', (WidgetTester tester) async { await tester.pumpWidget( buildAppBar( contentHeight: 200.0, @@ -4386,7 +4387,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/80256 - testWidgets('The second page should have a back button even it has a end drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The second page should have a back button even it has a end drawer', (WidgetTester tester) async { final Page page1 = MaterialPage( key: const ValueKey('1'), child: Scaffold( @@ -4423,7 +4424,7 @@ void main() { ); }); - testWidgets('Only local entries that imply app bar dismissal will introduce an back button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Only local entries that imply app bar dismissal will introduce an back button', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -4450,7 +4451,7 @@ void main() { expect(find.byType(BackButton), findsOneWidget); }); - testWidgets('AppBar.preferredHeightFor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.preferredHeightFor', (WidgetTester tester) async { late double preferredHeight; late Size preferredSize; @@ -4503,7 +4504,7 @@ void main() { expect(preferredSize.height, 64); }); - testWidgets('AppBar title with actions should have the same position regardless of centerTitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar title with actions should have the same position regardless of centerTitle', (WidgetTester tester) async { final Key titleKey = UniqueKey(); bool centerTitle = false; @@ -4533,7 +4534,7 @@ void main() { expect(tester.getTopLeft(title).dx, 16.0); }); - testWidgets('AppBar leading widget can take up arbitrary space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar leading widget can take up arbitrary space', (WidgetTester tester) async { final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); late double leadingWidth; @@ -4563,7 +4564,7 @@ void main() { expect(tester.getSize(find.byKey(leadingKey)).width, leadingWidth); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverAppBar.medium collapsed title does not overlap with leading/actions widgets', (WidgetTester tester) async { const String title = 'Medium SliverAppBar Very Long Title'; @@ -4615,7 +4616,7 @@ void main() { expect(titleOffset.dx, lessThan(searchOffset.dx)); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverAppBar.large collapsed title does not overlap with leading/actions widgets', (WidgetTester tester) async { const String title = 'Large SliverAppBar Very Long Title'; @@ -4667,7 +4668,7 @@ void main() { expect(titleOffset.dx, lessThan(searchOffset.dx)); }); - testWidgets('SliverAppBar.medium respects title spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium respects title spacing', (WidgetTester tester) async { const String title = 'Medium SliverAppBar Very Long Title'; const double titleSpacing = 16.0; @@ -4760,7 +4761,7 @@ void main() { expect(titleOffset.dx, iconButtonOffset.dx); }); - testWidgets('SliverAppBar.large respects title spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large respects title spacing', (WidgetTester tester) async { const String title = 'Large SliverAppBar Very Long Title'; const double titleSpacing = 16.0; @@ -4852,7 +4853,7 @@ void main() { expect(titleOffset.dx, iconButtonOffset.dx); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverAppBar.medium without the leading widget updates collapsed title padding', (WidgetTester tester) async { const String title = 'Medium SliverAppBar Title'; @@ -4914,7 +4915,7 @@ void main() { expect(titleOffset.dx, titleSpacing); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverAppBar.large without the leading widget updates collapsed title padding', (WidgetTester tester) async { const String title = 'Large SliverAppBar Title'; @@ -4976,7 +4977,7 @@ void main() { expect(titleOffset.dx, titleSpacing); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverAppBar large & medium title respects automaticallyImplyLeading', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/121511 @@ -5034,7 +5035,7 @@ void main() { expect(titleOffset.dx, backButtonOffset.dx + titleSpacing); }); - testWidgets('SliverAppBar.medium with bottom widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium with bottom widget', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/115091 const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 112; @@ -5094,7 +5095,7 @@ void main() { expect(appBarHeight(tester), collapsedAppBarHeight + bottomHeight); }); - testWidgets('SliverAppBar.large with bottom widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large with bottom widget', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/115091 const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 152; @@ -5154,7 +5155,7 @@ void main() { expect(appBarHeight(tester), collapsedAppBarHeight + bottomHeight); }); - testWidgets('SliverAppBar.medium expanded title has upper limit on text scaling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium expanded title has upper limit on text scaling', (WidgetTester tester) async { const String title = 'Medium AppBar'; Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( @@ -5195,7 +5196,7 @@ void main() { _verifyTextNotClipped(expandedTitle, tester); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 - testWidgets('SliverAppBar.large expanded title has upper limit on text scaling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large expanded title has upper limit on text scaling', (WidgetTester tester) async { const String title = 'Large AppBar'; Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( @@ -5233,7 +5234,7 @@ void main() { expect(tester.getRect(expandedTitle).height, closeTo(48.0, 0.1)); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 - testWidgets('SliverAppBar.medium expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async { const String title = 'Medium AppBar'; Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( @@ -5274,7 +5275,7 @@ void main() { _verifyTextNotClipped(expandedTitle, tester); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 - testWidgets('SliverAppBar.large expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async { const String title = 'Large AppBar'; Widget buildAppBar({double textScaleFactor = 1.0}) { return MaterialApp( @@ -5358,7 +5359,7 @@ void main() { ); } - testWidgets( + testWidgetsWithLeakTracking( 'forceMaterialTransparency == true allows gestures beneath the app bar', (WidgetTester tester) async { bool buttonWasPressed = false; final Widget widget = buildWidget( @@ -5376,7 +5377,7 @@ void main() { expect(buttonWasPressed, isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'forceMaterialTransparency == false does not allow gestures beneath the app bar', (WidgetTester tester) async { // Set this, and tester.tap(warnIfMissed:false), to suppress @@ -5405,7 +5406,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Material2 - SliverAppBar.medium defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SliverAppBar.medium defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 112; @@ -5489,7 +5490,7 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('Material2 - SliverAppBar.large defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SliverAppBar.large defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 152; diff --git a/packages/flutter/test/material/app_bar_theme_test.dart b/packages/flutter/test/material/app_bar_theme_test.dart index 3f1c076fb3bf5..f73bd9f12dc0d 100644 --- a/packages/flutter/test/material/app_bar_theme_test.dart +++ b/packages/flutter/test/material/app_bar_theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { const AppBarTheme appBarTheme = AppBarTheme( @@ -42,7 +43,7 @@ void main() { expect(identical(AppBarTheme.lerp(data, data, 0.5), data), true); }); - testWidgets('Material2 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -77,7 +78,7 @@ void main() { expect(tester.getSize(find.byType(AppBar)).width, 800); }); - testWidgets('Material3 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Passing no AppBarTheme returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -117,7 +118,7 @@ void main() { expect(tester.getSize(find.byType(AppBar)).width, 800); }); - testWidgets('AppBar uses values from AppBarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar uses values from AppBarTheme', (WidgetTester tester) async { final AppBarTheme appBarTheme = _appBarTheme(); await tester.pumpWidget( @@ -154,7 +155,7 @@ void main() { expect(tester.getSize(find.byType(AppBar)).width, 800); }); - testWidgets('AppBar widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar widget properties take priority over theme', (WidgetTester tester) async { const Brightness brightness = Brightness.dark; const SystemUiOverlayStyle systemOverlayStyle = SystemUiOverlayStyle.light; const Color color = Colors.orange; @@ -210,7 +211,7 @@ void main() { expect(text.style, toolbarTextStyle); }); - testWidgets('AppBar icon color takes priority over everything', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar icon color takes priority over everything', (WidgetTester tester) async { const Color color = Colors.lime; const IconThemeData iconThemeData = IconThemeData(color: Colors.green); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue); @@ -230,7 +231,7 @@ void main() { expect(actionIconText.text.style!.color, color); }); - testWidgets('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async { final AppBarTheme appBarTheme = _appBarTheme(); await tester.pumpWidget( @@ -264,7 +265,7 @@ void main() { expect(text.style, appBarTheme.toolbarTextStyle); }); - testWidgets('Material2 - ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: false); final ThemeData darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: false); Widget buildFrame(ThemeData appTheme) { @@ -338,7 +339,7 @@ void main() { expect(text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface)); }); - testWidgets('Material3 - ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true); final ThemeData darkTheme = ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: true); Widget buildFrame(ThemeData appTheme) { @@ -412,7 +413,7 @@ void main() { expect(text.style, Typography.material2021().englishLike.bodyMedium!.merge(Typography.material2021().black.bodyMedium).copyWith(color: darkTheme.colorScheme.onSurface, decorationColor: darkTheme.colorScheme.onSurface)); }); - testWidgets('AppBar iconTheme with color=null defers to outer IconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar iconTheme with color=null defers to outer IconTheme', (WidgetTester tester) async { // Verify claim made in https://github.com/flutter/flutter/pull/71184#issuecomment-737419215 Widget buildFrame({ Color? appIconColor, Color? appBarIconColor }) { @@ -452,7 +453,7 @@ void main() { expect(getIconText().text.style!.color, Colors.purple); }); - testWidgets('AppBar uses AppBarTheme.centerTitle when centerTitle is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar uses AppBarTheme.centerTitle when centerTitle is null', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)), home: Scaffold(appBar: AppBar( @@ -464,7 +465,7 @@ void main() { expect(navToolBar.centerMiddle, true); }); - testWidgets('AppBar.centerTitle takes priority over AppBarTheme.centerTitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.centerTitle takes priority over AppBarTheme.centerTitle', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(centerTitle: true)), home: Scaffold( @@ -480,7 +481,7 @@ void main() { expect(navToolBar.centerMiddle, false); }); - testWidgets('AppBar.centerTitle adapts to TargetPlatform when AppBarTheme.centerTitle is null', (WidgetTester tester) async{ + testWidgetsWithLeakTracking('AppBar.centerTitle adapts to TargetPlatform when AppBarTheme.centerTitle is null', (WidgetTester tester) async{ await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.iOS), home: Scaffold(appBar: AppBar( @@ -494,7 +495,7 @@ void main() { expect(navToolBar.centerMiddle, true); }); - testWidgets('AppBar.shadowColor takes priority over AppBarTheme.shadowColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.shadowColor takes priority over AppBarTheme.shadowColor', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(shadowColor: Colors.red)), home: Scaffold( @@ -510,7 +511,7 @@ void main() { expect(appBar.shadowColor, Colors.yellow); }); - testWidgets('AppBar.surfaceTintColor takes priority over AppBarTheme.surfaceTintColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.surfaceTintColor takes priority over AppBarTheme.surfaceTintColor', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(surfaceTintColor: Colors.red)), home: Scaffold( @@ -526,7 +527,7 @@ void main() { expect(appBar.surfaceTintColor, Colors.yellow); }); - testWidgets('Material3 - AppBarTheme.iconTheme.color takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBarTheme.iconTheme.color takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { const IconThemeData overallIconTheme = IconThemeData(color: Colors.yellow); await tester.pumpWidget(MaterialApp( theme: ThemeData( @@ -552,7 +553,7 @@ void main() { expect(actionIconButtonColor, overallIconTheme.color); }); - testWidgets('Material3 - AppBarTheme.iconTheme.size takes priority over IconButtonTheme.iconSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBarTheme.iconTheme.size takes priority over IconButtonTheme.iconSize', (WidgetTester tester) async { const IconThemeData overallIconTheme = IconThemeData(size: 30.0); await tester.pumpWidget(MaterialApp( theme: ThemeData( @@ -579,7 +580,7 @@ void main() { }); - testWidgets('Material3 - AppBarTheme.actionsIconTheme.color takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBarTheme.actionsIconTheme.color takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { const IconThemeData actionsIconTheme = IconThemeData(color: Colors.yellow); final IconButtonThemeData iconButtonTheme = IconButtonThemeData( style: IconButton.styleFrom(foregroundColor: Colors.red), @@ -607,7 +608,7 @@ void main() { expect(actionIconButtonColor, actionsIconTheme.color); }); - testWidgets('Material3 - AppBarTheme.actionsIconTheme.size takes priority over IconButtonTheme.iconSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBarTheme.actionsIconTheme.size takes priority over IconButtonTheme.iconSize', (WidgetTester tester) async { const IconThemeData actionsIconTheme = IconThemeData(size: 30.0); final IconButtonThemeData iconButtonTheme = IconButtonThemeData( style: IconButton.styleFrom(iconSize: 32.0), @@ -634,7 +635,7 @@ void main() { expect(actionIconButtonSize, actionsIconTheme.size); }); - testWidgets('Material3 - AppBarTheme.foregroundColor takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBarTheme.foregroundColor takes priority over IconButtonTheme.foregroundColor', (WidgetTester tester) async { final IconButtonThemeData iconButtonTheme = IconButtonThemeData( style: IconButton.styleFrom(foregroundColor: Colors.red), ); @@ -669,7 +670,7 @@ void main() { expect(actionIconButtonColor, appBarTheme.foregroundColor); }); - testWidgets('AppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async { const double kTitleSpacing = 10; await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)), @@ -684,7 +685,7 @@ void main() { expect(navToolBar.middleSpacing, kTitleSpacing); }); - testWidgets('AppBar.titleSpacing takes priority over AppBarTheme.titleSpacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBar.titleSpacing takes priority over AppBarTheme.titleSpacing', (WidgetTester tester) async { const double kTitleSpacing = 10; await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)), @@ -700,7 +701,7 @@ void main() { expect(navToolBar.middleSpacing, 40); }); - testWidgets('SliverAppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar uses AppBarTheme.titleSpacing', (WidgetTester tester) async { const double kTitleSpacing = 10; await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)), @@ -717,7 +718,7 @@ void main() { expect(navToolBar.middleSpacing, kTitleSpacing); }); - testWidgets('SliverAppBar.titleSpacing takes priority over AppBarTheme.titleSpacing ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.titleSpacing takes priority over AppBarTheme.titleSpacing ', (WidgetTester tester) async { const double kTitleSpacing = 10; await tester.pumpWidget(MaterialApp( theme: ThemeData(appBarTheme: const AppBarTheme(titleSpacing: kTitleSpacing)), @@ -735,7 +736,7 @@ void main() { expect(navToolbar.middleSpacing, 40); }); - testWidgets('SliverAppBar.medium uses AppBarTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium uses AppBarTheme properties', (WidgetTester tester) async { const String title = 'Medium App Bar'; await tester.pumpWidget(MaterialApp( @@ -791,7 +792,7 @@ void main() { expect(titleOffset.dx, iconOffset.dx + appBarTheme.titleSpacing!); }); - testWidgets('SliverAppBar.medium properties take priority over AppBarTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium properties take priority over AppBarTheme properties', (WidgetTester tester) async { const String title = 'Medium App Bar'; const Color backgroundColor = Color(0xff000099); const Color foregroundColor = Color(0xff00ff98); @@ -868,7 +869,7 @@ void main() { expect(titleOffset.dx, iconOffset.dx + titleSpacing); }); - testWidgets('SliverAppBar.large uses AppBarTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large uses AppBarTheme properties', (WidgetTester tester) async { const String title = 'Large App Bar'; await tester.pumpWidget(MaterialApp( @@ -924,7 +925,7 @@ void main() { expect(titleOffset.dx, iconOffset.dx + appBarTheme.titleSpacing!); }); - testWidgets('SliverAppBar.large properties take priority over AppBarTheme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large properties take priority over AppBarTheme properties', (WidgetTester tester) async { const String title = 'Large App Bar'; const Color backgroundColor = Color(0xff000099); const Color foregroundColor = Color(0xff00ff98); @@ -1001,7 +1002,7 @@ void main() { expect(titleOffset.dx, iconOffset.dx + titleSpacing); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverAppBar medium & large supports foregroundColor', (WidgetTester tester) async { const String title = 'AppBar title'; const AppBarTheme appBarTheme = AppBarTheme(foregroundColor: Color(0xff00ff20)); @@ -1045,7 +1046,7 @@ void main() { expect(largeTitle.text.style!.color, foregroundColor); }); - testWidgets('Default AppBarTheme debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default AppBarTheme debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const AppBarTheme().debugFillProperties(builder); @@ -1057,7 +1058,7 @@ void main() { expect(description, []); }); - testWidgets('AppBarTheme implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppBarTheme implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const AppBarTheme( backgroundColor: Color(0xff000000), @@ -1112,7 +1113,7 @@ void main() { }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/87364 // This is a regression test for https://github.com/flutter/flutter/issues/130485. - testWidgets('Material3 - AppBarTheme.iconTheme correctly applies custom white color in dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AppBarTheme.iconTheme correctly applies custom white color in dark mode', (WidgetTester tester) async { final ThemeData themeData = ThemeData( useMaterial3: true, brightness: Brightness.dark, diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index d22565e195bea..cfad6de21e8a7 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class StateMarker extends StatefulWidget { const StateMarker({ super.key, this.child }); @@ -31,7 +32,7 @@ class StateMarkerState extends State { } void main() { - testWidgets('Can nest apps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can nest apps', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: MaterialApp( @@ -43,7 +44,7 @@ void main() { expect(find.text('Home sweet home'), findsOneWidget); }); - testWidgets('Focus handling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus handling', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget(MaterialApp( home: Material( @@ -70,7 +71,7 @@ void main() { expect(find.text('Home'), findsOneWidget); }); - testWidgets('Can show grid without losing sync', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can show grid without losing sync', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: StateMarker(), @@ -92,7 +93,7 @@ void main() { expect(state2.marker, equals('original')); }); - testWidgets('Do not rebuild page during a route transition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not rebuild page during a route transition', (WidgetTester tester) async { int buildCounter = 0; await tester.pumpWidget( MaterialApp( @@ -137,7 +138,7 @@ void main() { expect(find.text('Y'), findsOneWidget); }); - testWidgets('Do rebuild the home page if it changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do rebuild the home page if it changes', (WidgetTester tester) async { int buildCounter = 0; await tester.pumpWidget( MaterialApp( @@ -165,7 +166,7 @@ void main() { expect(find.text('B'), findsOneWidget); }); - testWidgets('Do not rebuild the home page if it does not actually change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not rebuild the home page if it does not actually change', (WidgetTester tester) async { int buildCounter = 0; final Widget home = Builder( builder: (BuildContext context) { @@ -187,7 +188,7 @@ void main() { expect(buildCounter, 1); }); - testWidgets('Do rebuild pages that come from the routes table if the MaterialApp changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do rebuild pages that come from the routes table if the MaterialApp changes', (WidgetTester tester) async { int buildCounter = 0; final Map routes = { '/': (BuildContext context) { @@ -209,7 +210,7 @@ void main() { expect(buildCounter, 2); }); - testWidgets('Cannot pop the initial route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot pop the initial route', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Text('Home'))); expect(find.text('Home'), findsOneWidget); @@ -222,7 +223,7 @@ void main() { expect(find.text('Home'), findsOneWidget); }); - testWidgets('Default initialRoute', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default initialRoute', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(routes: { '/': (BuildContext context) => const Text('route "/"'), })); @@ -230,7 +231,7 @@ void main() { expect(find.text('route "/"'), findsOneWidget); }); - testWidgets('One-step initial route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('One-step initial route', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( initialRoute: '/a', @@ -249,7 +250,7 @@ void main() { expect(find.text('route "/b"', skipOffstage: false), findsNothing); }); - testWidgets('Return value from pop is correct', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Return value from pop is correct', (WidgetTester tester) async { late Future result; await tester.pumpWidget( MaterialApp( @@ -289,7 +290,7 @@ void main() { expect(await result, equals('all done')); }); - testWidgets('Two-step initial route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Two-step initial route', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const Text('route "/"'), '/a': (BuildContext context) => const Text('route "/a"'), @@ -334,7 +335,7 @@ void main() { } }); - testWidgets('Make sure initialRoute is only used the first time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Make sure initialRoute is only used the first time', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const Text('route "/"'), '/a': (BuildContext context) => const Text('route "/a"'), @@ -369,7 +370,7 @@ void main() { expect(find.text('route "/b"', skipOffstage: false), findsNothing); }); - testWidgets('onGenerateRoute / onUnknownRoute', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onGenerateRoute / onUnknownRoute', (WidgetTester tester) async { final List log = []; await tester.pumpWidget( MaterialApp( @@ -391,7 +392,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('MaterialApp with builder and no route information works.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp with builder and no route information works.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/18904 await tester.pumpWidget( MaterialApp( @@ -402,7 +403,7 @@ void main() { ); }); - testWidgets("WidgetsApp doesn't rebuild routes when MediaQuery updates", (WidgetTester tester) async { + testWidgetsWithLeakTracking("WidgetsApp doesn't rebuild routes when MediaQuery updates", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/37878 addTearDown(tester.platformDispatcher.clearAllTestValues); addTearDown(tester.view.reset); @@ -462,7 +463,7 @@ void main() { expect(dependentBuildCount, equals(5)); }); - testWidgets('Can get text scale from media query', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can get text scale from media query', (WidgetTester tester) async { TextScaler? textScaler; await tester.pumpWidget(MaterialApp( home: Builder(builder:(BuildContext context) { @@ -473,7 +474,7 @@ void main() { expect(textScaler, TextScaler.noScaling); }); - testWidgets('MaterialApp.navigatorKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.navigatorKey', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp( navigatorKey: key, @@ -494,7 +495,7 @@ void main() { expect(key.currentState, isA()); }); - testWidgets('Has default material and cupertino localizations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Has default material and cupertino localizations', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Builder( @@ -516,7 +517,7 @@ void main() { expect(find.text('Select All'), findsOneWidget); }); - testWidgets('MaterialApp uses regular theme when themeMode is light', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses regular theme when themeMode is light', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a light platformBrightness. @@ -564,7 +565,7 @@ void main() { expect(appliedTheme.brightness, Brightness.light); }); - testWidgets('MaterialApp uses darkTheme when themeMode is dark', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses darkTheme when themeMode is dark', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a light platformBrightness. @@ -612,7 +613,7 @@ void main() { expect(appliedTheme.brightness, Brightness.dark); }); - testWidgets('MaterialApp uses regular theme when themeMode is system and platformBrightness is light', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses regular theme when themeMode is system and platformBrightness is light', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a light platformBrightness. @@ -640,7 +641,7 @@ void main() { expect(appliedTheme.brightness, Brightness.light); }); - testWidgets('MaterialApp uses darkTheme when themeMode is system and platformBrightness is dark', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses darkTheme when themeMode is system and platformBrightness is dark', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a dark platformBrightness. @@ -666,7 +667,7 @@ void main() { expect(appliedTheme.brightness, Brightness.dark); }); - testWidgets('MaterialApp uses light theme when platformBrightness is dark but no dark theme is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses light theme when platformBrightness is dark but no dark theme is provided', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a dark platformBrightness. @@ -691,7 +692,7 @@ void main() { expect(appliedTheme.brightness, Brightness.light); }); - testWidgets('MaterialApp uses fallback light theme when platformBrightness is dark but no theme is provided at all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses fallback light theme when platformBrightness is dark but no theme is provided at all', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a dark platformBrightness. @@ -713,7 +714,7 @@ void main() { expect(appliedTheme.brightness, Brightness.light); }); - testWidgets('MaterialApp uses fallback light theme when platformBrightness is light and a dark theme is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses fallback light theme when platformBrightness is light and a dark theme is provided', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a dark platformBrightness. @@ -738,7 +739,7 @@ void main() { expect(appliedTheme.brightness, Brightness.light); }); - testWidgets('MaterialApp uses dark theme when platformBrightness is dark', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses dark theme when platformBrightness is dark', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a dark platformBrightness. @@ -766,7 +767,7 @@ void main() { expect(appliedTheme.brightness, Brightness.dark); }); - testWidgets('MaterialApp uses high contrast theme when appropriate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses high contrast theme when appropriate', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); tester.platformDispatcher.platformBrightnessTestValue = Brightness.light; @@ -794,7 +795,7 @@ void main() { expect(appliedTheme.primaryColor, Colors.blue); }); - testWidgets('MaterialApp uses high contrast dark theme when appropriate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses high contrast dark theme when appropriate', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); tester.platformDispatcher.platformBrightnessTestValue = Brightness.dark; @@ -828,7 +829,7 @@ void main() { expect(appliedTheme.primaryColor, Colors.green); }); - testWidgets('MaterialApp uses dark theme when no high contrast dark theme is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp uses dark theme when no high contrast dark theme is provided', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); tester.platformDispatcher.platformBrightnessTestValue = Brightness.dark; @@ -856,7 +857,7 @@ void main() { expect(appliedTheme.primaryColor, Colors.lightGreen); }); - testWidgets('MaterialApp animates theme changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp animates theme changes', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.light(); final ThemeData darkTheme = ThemeData.dark(); await tester.pumpWidget( @@ -896,7 +897,7 @@ void main() { expect(tester.widget(find.byType(Material)).color, halfBGColor); }); - testWidgets('MaterialApp theme animation can be turned off', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp theme animation can be turned off', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.light(); final ThemeData darkTheme = ThemeData.dark(); int scaffoldRebuilds = 0; @@ -938,7 +939,7 @@ void main() { expect(scaffoldRebuilds, 2); }); - testWidgets('MaterialApp switches themes when the platformBrightness changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp switches themes when the platformBrightness changes.', (WidgetTester tester) async { addTearDown(tester.platformDispatcher.clearAllTestValues); // Mock the test to explicitly report a light platformBrightness. @@ -977,7 +978,7 @@ void main() { expect(themeAfterBrightnessChange!.brightness, Brightness.dark); }); - testWidgets('Material2 - MaterialApp provides default overscroll color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - MaterialApp provides default overscroll color', (WidgetTester tester) async { Future slowDrag(WidgetTester tester, Offset start, Offset offset) async { final TestGesture gesture = await tester.startGesture(start); for (int index = 0; index < 10; index += 1) { @@ -1009,7 +1010,7 @@ void main() { expect(painter, paints..circle(color: glowSecondaryColor)); }); - testWidgets('MaterialApp can customize initial routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp can customize initial routes', (WidgetTester tester) async { final GlobalKey navigatorKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -1056,7 +1057,7 @@ void main() { expect(find.text('regular page two'), findsNothing); }); - testWidgets('MaterialApp does create HeroController with the MaterialRectArcTween', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp does create HeroController with the MaterialRectArcTween', (WidgetTester tester) async { final HeroController controller = MaterialApp.createMaterialHeroController(); final Tween tween = controller.createRectTween!( const Rect.fromLTRB(0.0, 0.0, 10.0, 10.0), @@ -1065,7 +1066,7 @@ void main() { expect(tween, isA()); }); - testWidgets('MaterialApp.navigatorKey can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.navigatorKey can be updated', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); await tester.pumpWidget(MaterialApp( navigatorKey: key1, @@ -1137,7 +1138,7 @@ void main() { expect(find.text('popped'), findsOneWidget); }); - testWidgets('MaterialApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -1162,7 +1163,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -1216,7 +1217,7 @@ void main() { expect(find.text('popped'), findsOneWidget); }); - testWidgets('MaterialApp.builder can build app without a Navigator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.builder can build app without a Navigator', (WidgetTester tester) async { Widget? builderChild; await tester.pumpWidget(MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1227,7 +1228,7 @@ void main() { expect(builderChild, isNull); }); - testWidgets('MaterialApp has correct default ScrollBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp has correct default ScrollBehavior', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( MaterialApp( @@ -1242,7 +1243,7 @@ void main() { expect(ScrollConfiguration.of(capturedContext).runtimeType, MaterialScrollBehavior); }); - testWidgets('A ScrollBehavior can be set for MaterialApp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A ScrollBehavior can be set for MaterialApp', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( MaterialApp( @@ -1260,7 +1261,7 @@ void main() { expect(scrollBehavior.getScrollPhysics(capturedContext).runtimeType, NeverScrollableScrollPhysics); }); - testWidgets('Material2 - ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), scrollBehavior: const MaterialScrollBehavior(), @@ -1279,7 +1280,7 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsOneWidget); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Material3 - ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), scrollBehavior: const MaterialScrollBehavior(), @@ -1298,7 +1299,7 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), home: ListView( @@ -1316,7 +1317,7 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Overscroll indicator can be set by theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll indicator can be set by theme', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( // The current default is glowing, setting via the theme should override. theme: ThemeData().copyWith(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), @@ -1335,7 +1336,7 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Overscroll indicator in MaterialScrollBehavior takes precedence over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll indicator in MaterialScrollBehavior takes precedence over theme', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( // MaterialScrollBehavior.androidOverscrollIndicator takes precedence over theme. scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), @@ -1355,7 +1356,7 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Material3 - ListView clip behavior updates overscroll indicator clip behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - ListView clip behavior updates overscroll indicator clip behavior', (WidgetTester tester) async { Widget buildFrame(Clip clipBehavior) { return MaterialApp( theme: ThemeData(useMaterial3: true), @@ -1431,7 +1432,7 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available', (WidgetTester tester) async { late BuildContext capturedContext; final UniqueKey uniqueKey = UniqueKey(); await tester.pumpWidget( @@ -1451,7 +1452,7 @@ void main() { expect(capturedContext.dependOnInheritedWidgetOfExactType()?.key, uniqueKey); }); - testWidgets('Assert in buildScrollbar that controller != null when using it (vertical)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Assert in buildScrollbar that controller != null when using it (vertical)', (WidgetTester tester) async { const ScrollBehavior defaultBehavior = MaterialScrollBehavior(); late BuildContext capturedContext; @@ -1496,7 +1497,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Assert in buildScrollbar that controller != null when using it (horizontal)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Assert in buildScrollbar that controller != null when using it (horizontal)', (WidgetTester tester) async { const ScrollBehavior defaultBehavior = MaterialScrollBehavior(); late BuildContext capturedContext; diff --git a/packages/flutter/test/material/back_button_test.dart b/packages/flutter/test/material/back_button_test.dart index 9ba330182c168..164eaafee8b17 100644 --- a/packages/flutter/test/material/back_button_test.dart +++ b/packages/flutter/test/material/back_button_test.dart @@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('BackButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BackButton control test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: const Material(child: Text('Home')), diff --git a/packages/flutter/test/material/radio_list_tile_test.dart b/packages/flutter/test/material/radio_list_tile_test.dart index 84fcbe5d35e97..6507c250cbfd4 100644 --- a/packages/flutter/test/material/radio_list_tile_test.dart +++ b/packages/flutter/test/material/radio_list_tile_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -23,7 +24,7 @@ Widget wrap({Widget? child}) { } void main() { - testWidgets('RadioListTile should initialize according to groupValue', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile should initialize according to groupValue', (WidgetTester tester) async { final List values = [0, 1, 2]; int? selectedValue; // Constructor parameters are required for [RadioListTile], but they are @@ -83,7 +84,7 @@ void main() { expect(generatedRadioListTiles[2].checked, equals(false)); }); - testWidgets('RadioListTile simple control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile simple control test', (WidgetTester tester) async { final Key key = UniqueKey(); final Key titleKey = UniqueKey(); final List log = []; @@ -155,7 +156,7 @@ void main() { expect(log, equals([1])); }); - testWidgets('RadioListTile control tests', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile control tests', (WidgetTester tester) async { final List values = [0, 1, 2]; int? selectedValue; // Constructor parameters are required for [Radio], but they are irrelevant @@ -222,7 +223,7 @@ void main() { expect(log, equals([1, '-', 2])); }); - testWidgets('Selected RadioListTile should not trigger onChanged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selected RadioListTile should not trigger onChanged', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/30311 final List values = [0, 1, 2]; int? selectedValue; @@ -274,7 +275,7 @@ void main() { expect(log, equals([0])); }); - testWidgets('Selected RadioListTile should trigger onChanged when toggleable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selected RadioListTile should trigger onChanged when toggleable', (WidgetTester tester) async { final List values = [0, 1, 2]; int? selectedValue; // Constructor parameters are required for [Radio], but they are irrelevant @@ -328,7 +329,7 @@ void main() { expect(log, equals([0, null, 0])); }); - testWidgets('RadioListTile can be toggled when toggleable is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile can be toggled when toggleable is set', (WidgetTester tester) async { final Key key = UniqueKey(); final List log = []; @@ -383,7 +384,7 @@ void main() { expect(log, equals([1])); }); - testWidgets('RadioListTile semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -532,7 +533,7 @@ void main() { semantics.dispose(); }); - testWidgets('RadioListTile has semantic events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile has semantic events', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Key key = UniqueKey(); dynamic semanticEvent; @@ -571,7 +572,7 @@ void main() { tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, null); }); - testWidgets('RadioListTile can autofocus unless disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile can autofocus unless disabled.', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( @@ -605,7 +606,7 @@ void main() { expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isFalse); }); - testWidgets('RadioListTile contentPadding test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile contentPadding test', (WidgetTester tester) async { final Type radioType = const Radio( groupValue: true, value: true, @@ -645,7 +646,7 @@ void main() { expect(paddingRect.right, titleRect.right + 15); //right padding }); - testWidgets('RadioListTile respects shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects shape', (WidgetTester tester) async { const ShapeBorder shapeBorder = RoundedRectangleBorder( borderRadius: BorderRadius.horizontal(right: Radius.circular(100)), ); @@ -665,7 +666,7 @@ void main() { expect(tester.widget(find.byType(InkWell)).customBorder, shapeBorder); }); - testWidgets('RadioListTile respects tileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects tileColor', (WidgetTester tester) async { final Color tileColor = Colors.red.shade500; await tester.pumpWidget( @@ -685,7 +686,7 @@ void main() { expect(find.byType(Material), paints..rect(color: tileColor)); }); - testWidgets('RadioListTile respects selectedTileColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects selectedTileColor', (WidgetTester tester) async { final Color selectedTileColor = Colors.green.shade500; await tester.pumpWidget( @@ -706,7 +707,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('RadioListTile selected item text Color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile selected item text Color', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/76906 const Color activeColor = Color(0xff00ff00); @@ -746,7 +747,7 @@ void main() { expect(textColor('title'), activeColor); }); - testWidgets('RadioListTile respects visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects visualDensity', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( @@ -771,7 +772,7 @@ void main() { expect(box.size, equals(const Size(800, 56))); }); - testWidgets('RadioListTile respects focusNode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects focusNode', (WidgetTester tester) async { final GlobalKey childKey = GlobalKey(); await tester.pumpWidget( wrap( @@ -824,7 +825,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('Radio changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio changes mouse cursor when hovered', (WidgetTester tester) async { // Test Radio() constructor await tester.pumpWidget( wrap(child: MouseRegion( @@ -875,7 +876,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('RadioListTile respects fillColor in enabled/disabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects fillColor in enabled/disabled states', (WidgetTester tester) async { const Color activeEnabledFillColor = Color(0xFF000001); const Color activeDisabledFillColor = Color(0xFF000002); const Color inactiveEnabledFillColor = Color(0xFF000003); @@ -962,7 +963,7 @@ void main() { ); }); - testWidgets('RadioListTile respects fillColor in hovered state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects fillColor in hovered state', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredFillColor = Color(0xFF000001); @@ -1011,7 +1012,7 @@ void main() { ); }); - testWidgets('Material3 - RadioListTile respects hoverColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - RadioListTile respects hoverColor', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; final Color? hoverColor = Colors.orange[500]; @@ -1077,7 +1078,7 @@ void main() { ); }); - testWidgets('Material3 - RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -1202,7 +1203,7 @@ void main() { ); }); - testWidgets('RadioListTile respects splashRadius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects splashRadius', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; Widget buildApp() { @@ -1234,7 +1235,7 @@ void main() { ); }); - testWidgets('Radio respects materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio respects materialTapTargetSize', (WidgetTester tester) async { await tester.pumpWidget( wrap(child: RadioListTile( groupValue: true, @@ -1258,7 +1259,7 @@ void main() { expect(tester.getSize(find.byType(Radio)), const Size(48.0, 48.0)); }); - testWidgets('RadioListTile.adaptive shows the correct radio platform widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile.adaptive shows the correct radio platform widget', (WidgetTester tester) async { Widget buildApp(TargetPlatform platform) { return MaterialApp( theme: ThemeData(platform: platform), @@ -1300,7 +1301,7 @@ void main() { feedback.dispose(); }); - testWidgets('RadioListTile respects enableFeedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile respects enableFeedback', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(bool enableFeedback) async { return tester.pumpWidget( @@ -1338,7 +1339,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Material2 - RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - RadioListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -1442,7 +1443,7 @@ void main() { ); }); - testWidgets('Material2 - RadioListTile respects hoverColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - RadioListTile respects hoverColor', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; int? groupValue = 0; final Color? hoverColor = Colors.orange[500]; From 10b7712b5a048be65b05d8097ccafbb436191130 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Tue, 22 Aug 2023 09:21:53 -0700 Subject: [PATCH 0834/1547] Increase heap for gradle in examples/platform_view (#133052) Fixes https://github.com/flutter/flutter/issues/133051 --- examples/platform_view/android/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/platform_view/android/gradle.properties b/examples/platform_view/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/platform_view/android/gradle.properties +++ b/examples/platform_view/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true From b3005a318b5361e34e4c78b7f3c593825c2922d6 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Tue, 22 Aug 2023 12:22:06 -0500 Subject: [PATCH 0835/1547] Re-enable Xcode Debug tests (#132523) Re-enables Xcode Debug tests (still in bringup). It also has them use an older version of Xcode that is compatible with the host OS. Fixes https://github.com/flutter/flutter/issues/132309. --- .ci.yaml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 055e328f1c92a..4e79859be2d2b 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -3855,6 +3855,20 @@ targets: ["devicelab", "ios", "mac"] task_name: flutter_gallery_ios__start_up + - name: Mac_ios flutter_gallery_ios__start_up_xcode_debug + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: flutter_gallery_ios__start_up_xcode_debug + $flutter/osx_sdk : >- + { + "sdk_version": "14c18" + } + bringup: true + - name: Mac_ios flutter_view_ios__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -3922,6 +3936,20 @@ targets: ["devicelab", "ios", "mac"] task_name: integration_ui_ios_driver + - name: Mac_ios integration_ui_ios_driver_xcode_debug + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: integration_ui_ios_driver_xcode_debug + $flutter/osx_sdk : >- + { + "sdk_version": "14c18" + } + bringup: true + - name: Mac_ios integration_ui_ios_frame_number recipe: devicelab/devicelab_drone presubmit: false From 0278671bda121cafee337e40399bd875690bfd7c Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Tue, 22 Aug 2023 10:23:13 -0700 Subject: [PATCH 0836/1547] Fix memory leak in Form (#132987) Diposes some restorable variables that weren't disposed before. --- packages/flutter/lib/src/widgets/form.dart | 7 +++++++ packages/flutter/test/material/text_form_field_test.dart | 3 --- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 07476568a35bf..ca980ad93304f 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -573,6 +573,13 @@ class FormFieldState extends State> with RestorationMixin { super.deactivate(); } + @override + void dispose() { + _errorText.dispose(); + _hasInteractedByUser.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { if (widget.enabled) { diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index f95f8bfaaa535..8877ed8e9ecfe 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -247,9 +247,6 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.windows }), skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130467 - leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true, allowAllNotGCed: true), ); testWidgetsWithLeakTracking( From c475409b8a7f35f1a86174731623ce8436473363 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 14:02:49 -0400 Subject: [PATCH 0837/1547] Roll Flutter Engine from c5e0152b01f4 to ff375bf5d8eb (4 revisions) (#133062) https://github.com/flutter/engine/compare/c5e0152b01f4...ff375bf5d8eb 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from eff8446c42f8 to 50814d9ca5bb (1 revision) (flutter/engine#44958) 2023-08-22 brianosman@google.com Add missing GrVkTypes include (flutter/engine#44957) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from a548d28072ce to eff8446c42f8 (2 revisions) (flutter/engine#44955) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from b3b8f3332cce to a548d28072ce (3 revisions) (flutter/engine#44953) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b31a1225a253b..541c3ab9a809c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c5e0152b01f44e3e34ace6a68be42c74a384245d +ff375bf5d8eb965c6385c009ed14a118ffe9e60b From 6a2d1b94ca7b1e4c5d28e7976e036ecc23cf705f Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Tue, 22 Aug 2023 11:28:21 -0700 Subject: [PATCH 0838/1547] Increase heap size for examples/flutter_view gradle build (#133064) For the engine roll presubmit failure in https://ci.chromium.org/ui/p/flutter/builders/try/Linux%20build_tests_3_3/10805/overview --- examples/flutter_view/android/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/flutter_view/android/gradle.properties b/examples/flutter_view/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/flutter_view/android/gradle.properties +++ b/examples/flutter_view/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true From 43facd14fdf156ae220b0e769bb227cb5b329c7e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 15:02:58 -0400 Subject: [PATCH 0839/1547] Roll Flutter Engine from ff375bf5d8eb to 090754879679 (1 revision) (#133066) https://github.com/flutter/engine/compare/ff375bf5d8eb...090754879679 2023-08-22 skia-flutter-autoroll@skia.org Roll Dart SDK from ecb1e3aecfbb to 3ebf0fedfceb (1 revision) (flutter/engine#44962) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 541c3ab9a809c..13478cf0cf8e4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ff375bf5d8eb965c6385c009ed14a118ffe9e60b +0907548796799da484cb4c365fb34597fd44e208 From 184323777a83b408053f03039c900712d3d2e769 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 15:13:26 -0400 Subject: [PATCH 0840/1547] Roll Packages from e26f3b9374d0 to c730a90f2fcc (3 revisions) (#133067) https://github.com/flutter/packages/compare/e26f3b9374d0...c730a90f2fcc 2023-08-22 engine-flutter-autoroll@skia.org Roll Flutter from 5e6d88d766b9 to 54c98d7433c5 (24 revisions) (flutter/packages#4754) 2023-08-22 49699333+dependabot[bot]@users.noreply.github.com [pigeon]: Bump io.mockk:mockk from 1.13.5 to 1.13.7 in /packages/pigeon/platform_tests/test_plugin/android (flutter/packages#4736) 2023-08-21 engine-flutter-autoroll@skia.org Roll Flutter from 6f227c078430 to 5e6d88d766b9 (8 revisions) (flutter/packages#4751) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 0a77a7cd892a5..bb0781e91b6f2 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -e26f3b9374d062e814a279116a90dcdd5fbfa925 +c730a90f2fccee3b9f7b576b870bf8670ac189e6 From 5665655d399f78639c9d1b441ac3e2f60d290b60 Mon Sep 17 00:00:00 2001 From: Ivan Inozemtsev Date: Tue, 22 Aug 2023 21:40:18 +0200 Subject: [PATCH 0841/1547] Add support for `Future?>` to `MatchesGoldenFile` (#132965) Otherwise when tests use `expectLater(getBytesOrNull(), matchesGoldenFile(...))`, they may fail in sound null safety mode and pass in weak null safety mode. Fixes https://github.com/flutter/flutter/issues/132964 --- packages/flutter_test/lib/src/_matchers_io.dart | 5 +++-- packages/flutter_test/test/matchers_test.dart | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/flutter_test/lib/src/_matchers_io.dart b/packages/flutter_test/lib/src/_matchers_io.dart index 74a3d497609b5..0c17612d28d53 100644 --- a/packages/flutter_test/lib/src/_matchers_io.dart +++ b/packages/flutter_test/lib/src/_matchers_io.dart @@ -60,8 +60,9 @@ class MatchesGoldenFile extends AsyncMatcher { final Uri testNameUri = goldenFileComparator.getTestUri(key, version); Uint8List? buffer; - if (item is Future>) { - buffer = Uint8List.fromList(await item); + if (item is Future?>) { + final List? bytes = await item; + buffer = bytes == null ? null : Uint8List.fromList(bytes); } else if (item is List) { buffer = Uint8List.fromList(item); } diff --git a/packages/flutter_test/test/matchers_test.dart b/packages/flutter_test/test/matchers_test.dart index 7e37125c808bd..36598dc796c21 100644 --- a/packages/flutter_test/test/matchers_test.dart +++ b/packages/flutter_test/test/matchers_test.dart @@ -470,6 +470,14 @@ void main() { expect(comparator.imageBytes, equals([1, 2])); expect(comparator.golden, Uri.parse('foo.png')); }); + + testWidgets('future nullable list of integers', + (WidgetTester tester) async { + await expectLater(Future?>.value([1, 2]), matchesGoldenFile('foo.png')); + expect(comparator.invocation, _ComparatorInvocation.compare); + expect(comparator.imageBytes, equals([1, 2])); + expect(comparator.golden, Uri.parse('foo.png')); + }); }); group('does not match', () { From ee7788cf4c03788837639101fae8dd87cf87579d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 15:55:23 -0400 Subject: [PATCH 0842/1547] Roll Flutter Engine from 090754879679 to 21437d384b56 (1 revision) (#133072) https://github.com/flutter/engine/compare/090754879679...21437d384b56 2023-08-22 30870216+gaaclarke@users.noreply.github.com [Impeller] Tiny optimizations for text rendering (avoiding extra ops and copies). (flutter/engine#44822) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 13478cf0cf8e4..ad8018e9b3d2c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0907548796799da484cb4c365fb34597fd44e208 +21437d384b565dc3d4f0f3a12633bac6a14b0888 From 0283d8a8d0d807ad9055b189be8fda11abe90238 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 16:43:22 -0400 Subject: [PATCH 0843/1547] Roll Flutter Engine from 21437d384b56 to 28b8bd5d5d91 (1 revision) (#133075) https://github.com/flutter/engine/compare/21437d384b56...28b8bd5d5d91 2023-08-22 reidbaker@google.com i82973 scroll mouse wheel support (flutter/engine#44724) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ad8018e9b3d2c..462b13f658d04 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -21437d384b565dc3d4f0f3a12633bac6a14b0888 +28b8bd5d5d913d6c684df6ac980edc47c4bfc52f From db89df51c306a2982c34a63879a924b7aa79690d Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 22 Aug 2023 23:47:05 +0300 Subject: [PATCH 0844/1547] Fix `FlexibleSpaceBar.title` doesn't respect the leading widget (#132573) fixes [Long `FlexibleSpaceBar.title` doesn't respect the leading widget ](https://github.com/flutter/flutter/issues/132030) ### Description - This adds `FlexibleSpaceBarSettings.hasLeading` for the `FlexibleSpaceBar`'s title to respect the leading widget. - Use the new `FlexibleSpaceBarSettings.hasLeading` property in the `SliverAppBar` for its `FlexibleSpaceBar`. ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, brightness: Brightness.dark, ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text('TargetPlatform.Android'), Theme( data: Theme.of(context).copyWith( platform: TargetPlatform.android, ), child: Container( height: 250, padding: const EdgeInsets.all(8), decoration: BoxDecoration( border: Border.all( color: Colors.amber, width: 4, ), ), child: const AppBarLeading( showLeading: true, showTitle: false, ), ), ), const Text('TargetPlatform.iOS'), Theme( data: Theme.of(context).copyWith( platform: TargetPlatform.iOS, ), child: Container( height: 250, padding: const EdgeInsets.all(8), decoration: BoxDecoration( border: Border.all( color: Colors.amber, width: 2, ), ), child: const AppBarLeading( showLeading: true, showTitle: false, ), ), ), ], ), ); } } class AppBarLeading extends StatelessWidget { const AppBarLeading({ super.key, required this.showLeading, required this.showTitle, }); final bool showLeading; final bool showTitle; @override Widget build(BuildContext context) { return Scaffold( drawer: const Drawer(), body: CustomScrollView( slivers: [ SliverAppBar( automaticallyImplyLeading: showLeading, iconTheme: const IconThemeData( color: Colors.amber, ), title: showTitle ? const Text('AppBar') : null, flexibleSpace: FlexibleSpaceBar( title: Text('Title ' * 15), // centerTitle: true, ), toolbarHeight: showTitle ? 170 : 100, ), ], ), ); } } ```
    ### Before ![Screenshot 2023-08-15 at 18 11 34](https://github.com/flutter/flutter/assets/48603081/4b798998-8549-43aa-b564-933ea14f494c) ### After ![Screenshot 2023-08-15 at 18 11 45](https://github.com/flutter/flutter/assets/48603081/b085a33a-db7d-40d4-8a12-ee37197b5bd4) --- .../flutter/lib/src/material/app_bar.dart | 1 + .../lib/src/material/flexible_space_bar.dart | 18 +++- .../material/flexible_space_bar_test.dart | 88 +++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index c94bfa5e3c1a4..ab0567e25e163 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -1261,6 +1261,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { currentExtent: math.max(minExtent, maxExtent - shrinkOffset), toolbarOpacity: toolbarOpacity, isScrolledUnder: isScrolledUnder, + hasLeading: leading != null || automaticallyImplyLeading, child: AppBar( clipBehavior: clipBehavior, leading: leading, diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index 3b3fd352a7692..b3b3bf2355a1b 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -156,6 +156,7 @@ class FlexibleSpaceBar extends StatefulWidget { double? minExtent, double? maxExtent, bool? isScrolledUnder, + bool? hasLeading, required double currentExtent, required Widget child, }) { @@ -164,6 +165,7 @@ class FlexibleSpaceBar extends StatefulWidget { minExtent: minExtent ?? currentExtent, maxExtent: maxExtent ?? currentExtent, isScrolledUnder: isScrolledUnder, + hasLeading: hasLeading, currentExtent: currentExtent, child: child, ); @@ -321,7 +323,7 @@ class _FlexibleSpaceBarState extends State { final bool effectiveCenterTitle = _getEffectiveCenterTitle(theme); final EdgeInsetsGeometry padding = widget.titlePadding ?? EdgeInsetsDirectional.only( - start: effectiveCenterTitle ? 0.0 : 72.0, + start: effectiveCenterTitle && !(settings.hasLeading ?? false) ? 0.0 : 72.0, bottom: 16.0, ); final double scaleValue = Tween(begin: widget.expandedTitleScale, end: 1.0).transform(t); @@ -380,6 +382,7 @@ class FlexibleSpaceBarSettings extends InheritedWidget { required this.currentExtent, required super.child, this.isScrolledUnder, + this.hasLeading, }) : assert(minExtent >= 0), assert(maxExtent >= 0), assert(currentExtent >= 0), @@ -413,13 +416,24 @@ class FlexibleSpaceBarSettings extends InheritedWidget { /// overlaps the primary scrollable's contents. final bool? isScrolledUnder; + /// True if the FlexibleSpaceBar has a leading widget. + /// + /// This value is used by the [FlexibleSpaceBar] to determine + /// if there should be a gap between the leading widget and + /// the title. + /// + /// Null if the caller hasn't determined if the FlexibleSpaceBar + /// has a leading widget. + final bool? hasLeading; + @override bool updateShouldNotify(FlexibleSpaceBarSettings oldWidget) { return toolbarOpacity != oldWidget.toolbarOpacity || minExtent != oldWidget.minExtent || maxExtent != oldWidget.maxExtent || currentExtent != oldWidget.currentExtent - || isScrolledUnder != oldWidget.isScrolledUnder; + || isScrolledUnder != oldWidget.isScrolledUnder + || hasLeading != oldWidget.hasLeading; } } diff --git a/packages/flutter/test/material/flexible_space_bar_test.dart b/packages/flutter/test/material/flexible_space_bar_test.dart index b1f34bebd914e..283197333b918 100644 --- a/packages/flutter/test/material/flexible_space_bar_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_test.dart @@ -821,6 +821,94 @@ void main() { expect(RenderRebuildTracker.count, greaterThan(1)); expect(tester.layers.whereType(), isEmpty); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/132030. + testWidgetsWithLeakTracking('FlexibleSpaceBarSettings.hasLeading provides a gap between leading and title', (WidgetTester tester) async { + final FlexibleSpaceBarSettings customSettings = FlexibleSpaceBar.createSettings( + currentExtent: 200.0, + hasLeading: true, + child: AppBar( + leading: const Icon(Icons.menu), + flexibleSpace: FlexibleSpaceBar( + title: Text('title ' * 10), + centerTitle: true, + ), + ), + ) as FlexibleSpaceBarSettings; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: CustomScrollView( + slivers: [ + SliverPersistentHeader( + floating: true, + pinned: true, + delegate: TestDelegate(settings: customSettings), + ), + SliverToBoxAdapter( + child: Container( + height: 1200.0, + color: Colors.orange[400], + ), + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(tester.getTopLeft(find.byType(Text)).dx, closeTo(72.0, 0.01)); + }); + + // This is a regression test for https://github.com/flutter/flutter/issues/132030. + testWidgetsWithLeakTracking('Long centered FlexibleSpaceBar.title respects leading widget', (WidgetTester tester) async { + // Test start position of a long title when the leading widget is + // shown by default and the long title is centered. + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + drawer: const Drawer(), + body: CustomScrollView( + slivers: [ + SliverAppBar( + flexibleSpace: FlexibleSpaceBar( + title: Text('Title ' * 10), + centerTitle: true, + ), + ), + ], + ), + ), + ), + ); + + expect(tester.getTopLeft(find.byType(Text)).dx, 72.0); + + // Test start position of a long title when the leading widget is provided + // and the long title is centered. + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: CustomScrollView( + slivers: [ + SliverAppBar( + leading: const Icon(Icons.menu), + flexibleSpace: FlexibleSpaceBar( + title: Text('Title ' * 10), + centerTitle: true, + ), + ), + ], + ), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(tester.getTopLeft(find.byType(Text)).dx, 72.0); + }); } class TestDelegate extends SliverPersistentHeaderDelegate { From 469c6c33d0aa972ae6fc46f6dd24de579af7fc03 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 22 Aug 2023 18:20:59 -0400 Subject: [PATCH 0845/1547] Roll Flutter Engine from 28b8bd5d5d91 to b190f9015049 (3 revisions) (#133078) https://github.com/flutter/engine/compare/28b8bd5d5d91...b190f9015049 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from 50814d9ca5bb to 9f4b81aac175 (1 revision) (flutter/engine#44969) 2023-08-22 mdebbar@google.com [web] Move remaining web-only APIs to `dart:ui_web` (flutter/engine#44516) 2023-08-22 flar@google.com Revert "Split DisplayListBuilder into DlCanvas optimizer and DlOp recorder classes" (flutter/engine#44968) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 462b13f658d04..8bec0fce5f807 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -28b8bd5d5d913d6c684df6ac980edc47c4bfc52f +b190f90150494f593bd9d2c0c3186ac41170ea12 From 1bc791697c9f09157cdbdf55001c115f654ed95e Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 23 Aug 2023 01:21:00 +0300 Subject: [PATCH 0846/1547] Update default menu text styles for Material 3 (#131930) Related https://github.com/flutter/flutter/issues/131676 ## Description #### Fix default input text style for `DropdownMenu` ![dropdown_input](https://github.com/flutter/flutter/assets/48603081/301f8243-155a-4b8f-84a8-5e6b7bebb3bc) ### Fix default text style for `MenuAnchor`'s menu items (which `DropdownMenu` uses for menu items) ![dropdown_item](https://github.com/flutter/flutter/assets/48603081/6b5be81a-72fc-4705-a577-074c7a4cad8f) ### Default `DropdownMenu` Input text style ![Screenshot 2023-08-04 at 16 48 28](https://github.com/flutter/flutter/assets/48603081/bcd9da98-e74d-491e-ae64-6268ae0b3893) ### Default `DropdownMenu` menu item text style ![Screenshot 2023-08-04 at 16 50 19](https://github.com/flutter/flutter/assets/48603081/9592ca43-2854-45b5-8648-203ab65d9745) ### Default `MenuAnchor` menu item text style ![Screenshot 2023-08-04 at 14 34 28](https://github.com/flutter/flutter/assets/48603081/e87e1073-05f8-4dc7-a435-d864e9cce6ab) ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [DropdownMenu]s. The first dropdown menu has an outlined border. void main() => runApp(const DropdownMenuExample()); class DropdownMenuExample extends StatefulWidget { const DropdownMenuExample({super.key}); @override State createState() => _DropdownMenuExampleState(); } class _DropdownMenuExampleState extends State { final TextEditingController colorController = TextEditingController(); final TextEditingController iconController = TextEditingController(); ColorLabel? selectedColor; IconLabel? selectedIcon; @override Widget build(BuildContext context) { final List> colorEntries = >[]; for (final ColorLabel color in ColorLabel.values) { colorEntries.add( DropdownMenuEntry( value: color, label: color.label, enabled: color.label != 'Grey'), ); } final List> iconEntries = >[]; for (final IconLabel icon in IconLabel.values) { iconEntries .add(DropdownMenuEntry(value: icon, label: icon.label)); } return MaterialApp( theme: ThemeData( useMaterial3: true, colorSchemeSeed: Colors.green, // textTheme: const TextTheme( // bodyLarge: TextStyle( // fontWeight: FontWeight.bold, // fontStyle: FontStyle.italic, // decoration: TextDecoration.underline, // ), // ), ), home: Scaffold( body: SafeArea( child: Column( children: [ const Text('DropdownMenus'), Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ DropdownMenu( controller: colorController, label: const Text('Color'), dropdownMenuEntries: colorEntries, onSelected: (ColorLabel? color) { setState(() { selectedColor = color; }); }, ), const SizedBox(width: 20), DropdownMenu( controller: iconController, enableFilter: true, leadingIcon: const Icon(Icons.search), label: const Text('Icon'), dropdownMenuEntries: iconEntries, inputDecorationTheme: const InputDecorationTheme( filled: true, contentPadding: EdgeInsets.symmetric(vertical: 5.0), ), onSelected: (IconLabel? icon) { setState(() { selectedIcon = icon; }); }, ), ], ), ), const Text('Plain TextFields'), Padding( padding: const EdgeInsets.symmetric(vertical: 20), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 150, child: TextField( controller: TextEditingController(text: 'Blue'), decoration: const InputDecoration( suffixIcon: Icon(Icons.arrow_drop_down), labelText: 'Color', border: OutlineInputBorder(), )), ), const SizedBox(width: 20), SizedBox( width: 150, child: TextField( controller: TextEditingController(text: 'Smile'), decoration: const InputDecoration( prefixIcon: Icon(Icons.search), suffixIcon: Icon(Icons.arrow_drop_down), filled: true, labelText: 'Icon', )), ), ], ), ), if (selectedColor != null && selectedIcon != null) Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'You selected a ${selectedColor?.label} ${selectedIcon?.label}'), Padding( padding: const EdgeInsets.symmetric(horizontal: 5), child: Icon( selectedIcon?.icon, color: selectedColor?.color, ), ) ], ) else const Text('Please select a color and an icon.') ], ), ), ), ); } } enum ColorLabel { blue('Blue', Colors.blue), pink('Pink', Colors.pink), green('Green', Colors.green), yellow('Yellow', Colors.yellow), grey('Grey', Colors.grey); const ColorLabel(this.label, this.color); final String label; final Color color; } enum IconLabel { smile('Smile', Icons.sentiment_satisfied_outlined), cloud( 'Cloud', Icons.cloud_outlined, ), brush('Brush', Icons.brush_outlined), heart('Heart', Icons.favorite); const IconLabel(this.label, this.icon); final String label; final IconData icon; } ```
    --- dev/tools/gen_defaults/lib/menu_template.dart | 5 +- .../menu_accelerator_label.0_test.dart | 9 ++- .../menu_anchor/menu_anchor.1_test.dart | 10 ++- .../lib/src/material/dropdown_menu.dart | 4 +- .../flutter/lib/src/material/menu_anchor.dart | 6 +- .../test/material/dropdown_menu_test.dart | 75 ++++++++++++++++--- .../test/material/menu_anchor_test.dart | 71 ++++++++++++++++-- .../test/material/menu_style_test.dart | 7 +- 8 files changed, 159 insertions(+), 28 deletions(-) diff --git a/dev/tools/gen_defaults/lib/menu_template.dart b/dev/tools/gen_defaults/lib/menu_template.dart index 50dc6c4e2f708..6d2d6b443057a 100644 --- a/dev/tools/gen_defaults/lib/menu_template.dart +++ b/dev/tools/gen_defaults/lib/menu_template.dart @@ -65,6 +65,7 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { final BuildContext context; late final ColorScheme _colors = Theme.of(context).colorScheme; + late final TextTheme _textTheme = Theme.of(context).textTheme; @override MaterialStateProperty? get backgroundColor { @@ -180,7 +181,9 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty get textStyle { - return MaterialStatePropertyAll(${textStyle('md.comp.list.list-item.label-text')}); + // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs + // Update this when the token is available. + return MaterialStatePropertyAll(_textTheme.labelLarge); } @override diff --git a/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart b/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart index 89cadb7db30d0..5e69f5d8c1b4a 100644 --- a/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart +++ b/examples/api/test/material/menu_anchor/menu_accelerator_label.0_test.dart @@ -27,10 +27,11 @@ void main() { await tester.pump(); expect(find.text('About', findRichText: true), findsOneWidget); - expect( - tester.getRect(findMenu('About')), - equals(const Rect.fromLTRB(4.0, 48.0, 110.5, 208.0)), - ); + expect(tester.getRect(findMenu('About')).left, equals(4.0)); + expect(tester.getRect(findMenu('About')).top, equals(48.0)); + expect(tester.getRect(findMenu('About')).right, closeTo(98.5, 0.1)); + expect(tester.getRect(findMenu('About')).bottom, equals(208.0)); + expect(find.text('Save', findRichText: true), findsOneWidget); expect(find.text('Quit', findRichText: true), findsOneWidget); expect(find.text('Magnify', findRichText: true), findsNothing); diff --git a/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart b/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart index 0ac0e43ddb2bc..fdb3eeea4e4ee 100644 --- a/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart +++ b/examples/api/test/material/menu_anchor/menu_anchor.1_test.dart @@ -21,13 +21,19 @@ void main() { await tester.tapAt(const Offset(100, 200), buttons: kSecondaryButton); await tester.pumpAndSettle(); - expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 433.0, 360.0))); + expect(tester.getRect(findMenu()).left, equals(100.0)); + expect(tester.getRect(findMenu()).top, equals(200.0)); + expect(tester.getRect(findMenu()).right, closeTo(389.8, 0.1)); + expect(tester.getRect(findMenu()).bottom, equals(360.0)); // Make sure tapping in a different place causes the menu to move. await tester.tapAt(const Offset(200, 100), buttons: kSecondaryButton); await tester.pump(); - expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(200.0, 100.0, 533.0, 260.0))); + expect(tester.getRect(findMenu()).left, equals(200.0)); + expect(tester.getRect(findMenu()).top, equals(100.0)); + expect(tester.getRect(findMenu()).right, closeTo(489.8, 0.1)); + expect(tester.getRect(findMenu()).bottom, equals(260.0)); expect(find.text(example.MenuEntry.about.label), findsOneWidget); expect(find.text(example.MenuEntry.showMessage.label), findsOneWidget); diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 51a972a3398a6..27baf5951b92c 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -229,7 +229,7 @@ class DropdownMenu extends StatefulWidget { /// The text style for the [TextField] of the [DropdownMenu]; /// - /// Defaults to the overall theme's [TextTheme.labelLarge] + /// Defaults to the overall theme's [TextTheme.bodyLarge] /// if the dropdown menu theme's value is null. final TextStyle? textStyle; @@ -916,7 +916,7 @@ class _DropdownMenuDefaultsM3 extends DropdownMenuThemeData { late final ThemeData _theme = Theme.of(context); @override - TextStyle? get textStyle => _theme.textTheme.labelLarge; + TextStyle? get textStyle => _theme.textTheme.bodyLarge; @override MenuStyle get menuStyle { diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index f2dfeeea5ee49..3ad5543407b33 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -27,6 +27,7 @@ import 'menu_style.dart'; import 'menu_theme.dart'; import 'radio.dart'; import 'text_button.dart'; +import 'text_theme.dart'; import 'theme.dart'; import 'theme_data.dart'; @@ -3676,6 +3677,7 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { final BuildContext context; late final ColorScheme _colors = Theme.of(context).colorScheme; + late final TextTheme _textTheme = Theme.of(context).textTheme; @override MaterialStateProperty? get backgroundColor { @@ -3791,7 +3793,9 @@ class _MenuButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty get textStyle { - return MaterialStatePropertyAll(Theme.of(context).textTheme.bodyLarge); + // TODO(tahatesser): This is taken from https://m3.material.io/components/menus/specs + // Update this when the token is available. + return MaterialStatePropertyAll(_textTheme.labelLarge); } @override diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 45802fdb91a75..5d8a2c53141bf 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - import 'dart:ui'; import 'package:flutter/material.dart'; @@ -39,15 +38,19 @@ void main() { await tester.pumpWidget(buildTest(themeData, menuChildren)); final EditableText editableText = tester.widget(find.byType(EditableText)); - expect(editableText.style.color, themeData.textTheme.labelLarge!.color); - expect(editableText.style.background, themeData.textTheme.labelLarge!.background); - expect(editableText.style.shadows, themeData.textTheme.labelLarge!.shadows); - expect(editableText.style.decoration, themeData.textTheme.labelLarge!.decoration); - expect(editableText.style.locale, themeData.textTheme.labelLarge!.locale); - expect(editableText.style.wordSpacing, themeData.textTheme.labelLarge!.wordSpacing); + expect(editableText.style.color, themeData.textTheme.bodyLarge!.color); + expect(editableText.style.background, themeData.textTheme.bodyLarge!.background); + expect(editableText.style.shadows, themeData.textTheme.bodyLarge!.shadows); + expect(editableText.style.decoration, themeData.textTheme.bodyLarge!.decoration); + expect(editableText.style.locale, themeData.textTheme.bodyLarge!.locale); + expect(editableText.style.wordSpacing, themeData.textTheme.bodyLarge!.wordSpacing); + expect(editableText.style.fontSize, 16.0); + expect(editableText.style.height, 1.5); final TextField textField = tester.widget(find.byType(TextField)); expect(textField.decoration?.border, const OutlineInputBorder()); + expect(textField.style?.fontSize, 16.0); + expect(textField.style?.height, 1.5); await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_drop_down).first); await tester.pump(); @@ -74,6 +77,8 @@ void main() { expect(material.elevation, 0.0); expect(material.shape, const RoundedRectangleBorder()); expect(material.textStyle?.color, themeData.colorScheme.onSurface); + expect(material.textStyle?.fontSize, 14.0); + expect(material.textStyle?.height, 1.43); }); testWidgets('DropdownMenu can be disabled', (WidgetTester tester) async { @@ -177,7 +182,7 @@ void main() { final Finder textField = find.byType(TextField); final double anchorWidth = tester.getSize(textField).width; - expect(anchorWidth, 195.0); + expect(anchorWidth, closeTo(180.5, 0.1)); await tester.tap(find.byType(DropdownMenu)); await tester.pumpAndSettle(); @@ -187,7 +192,7 @@ void main() { matching: find.byType(Material), ); final double menuWidth = tester.getSize(menuMaterial).width; - expect(menuWidth, 195.0); + expect(menuWidth, closeTo(180.5, 0.1)); // The text field should have same width as the menu // when the width property is not null. @@ -391,7 +396,8 @@ void main() { matching: find.byType(Padding), ).first; final Size menuViewSize = tester.getSize(menuView); - expect(menuViewSize, const Size(195.0, 304.0)); // 304 = 288 + vertical padding(2 * 8) + expect(menuViewSize.width, closeTo(180.6, 0.1)); + expect(menuViewSize.height, equals(304.0)); // 304 = 288 + vertical padding(2 * 8) // Constrains the menu height. await tester.pumpWidget(Container()); @@ -407,7 +413,8 @@ void main() { ).first; final Size updatedMenuSize = tester.getSize(updatedMenu); - expect(updatedMenuSize, const Size(195.0, 100.0)); + expect(updatedMenuSize.width, closeTo(180.6, 0.1)); + expect(updatedMenuSize.height, equals(100.0)); }); testWidgets('The text in the menu button should be aligned with the text of ' @@ -1518,6 +1525,52 @@ void main() { expect(find.text('Item 5').hitTestable(), findsOneWidget); }); + // This is a regression test for https://github.com/flutter/flutter/issues/131676. + testWidgets('Material3 - DropdownMenu uses correct text styles', (WidgetTester tester) async { + const TextStyle inputTextThemeStyle = TextStyle( + fontSize: 18.5, + fontStyle: FontStyle.italic, + wordSpacing: 1.2, + decoration: TextDecoration.lineThrough, + ); + const TextStyle menuItemTextThemeStyle = TextStyle( + fontSize: 20.5, + fontStyle: FontStyle.italic, + wordSpacing: 2.1, + decoration: TextDecoration.underline, + ); + final ThemeData themeData = ThemeData( + useMaterial3: true, + textTheme: const TextTheme( + bodyLarge: inputTextThemeStyle, + labelLarge: menuItemTextThemeStyle, + ), + ); + await tester.pumpWidget(buildTest(themeData, menuChildren)); + + // Test input text style uses the TextTheme.bodyLarge. + final EditableText editableText = tester.widget(find.byType(EditableText)); + expect(editableText.style.fontSize, inputTextThemeStyle.fontSize); + expect(editableText.style.fontStyle, inputTextThemeStyle.fontStyle); + expect(editableText.style.wordSpacing, inputTextThemeStyle.wordSpacing); + expect(editableText.style.decoration, inputTextThemeStyle.decoration); + + // Open the menu. + await tester.tap(find.widgetWithIcon(IconButton, Icons.arrow_drop_down).first); + await tester.pump(); + + final Finder buttonMaterial = find.descendant( + of: find.byType(TextButton), + matching: find.byType(Material), + ).last; + + // Test menu item text style uses the TextTheme.labelLarge. + final Material material = tester.widget(buttonMaterial); + expect(material.textStyle?.fontSize, menuItemTextThemeStyle.fontSize); + expect(material.textStyle?.fontStyle, menuItemTextThemeStyle.fontStyle); + expect(material.textStyle?.wordSpacing, menuItemTextThemeStyle.wordSpacing); + expect(material.textStyle?.decoration, menuItemTextThemeStyle.decoration); + }); } enum TestMenu { diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index e7a745490fd4f..5416882eab7ed 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -237,7 +237,7 @@ void main() { ); }); - testWidgets('menu defaults colors', (WidgetTester tester) async { + testWidgets('Menu defaults', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -278,6 +278,8 @@ void main() { expect(material.elevation, 0.0); expect(material.shape, const RoundedRectangleBorder()); expect(material.textStyle?.color, themeData.colorScheme.onSurface); + expect(material.textStyle?.fontSize, 14.0); + expect(material.textStyle?.height, 1.43); // vertical menu await tester.tap(find.text(TestMenu.mainMenu1.label)); @@ -305,6 +307,8 @@ void main() { expect(material.elevation, 0.0); expect(material.shape, const RoundedRectangleBorder()); expect(material.textStyle?.color, themeData.colorScheme.onSurface); + expect(material.textStyle?.fontSize, 14.0); + expect(material.textStyle?.height, 1.43); await tester.tap(find.text(TestMenu.mainMenu0.label)); await tester.pump(); @@ -315,7 +319,7 @@ void main() { expect(iconRichText.text.style?.color, themeData.colorScheme.onSurfaceVariant); }); - testWidgets('menu defaults - disabled', (WidgetTester tester) async { + testWidgets('Menu defaults - disabled', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -3205,6 +3209,7 @@ void main() { style: SubmenuButton.styleFrom(fixedSize: const Size(88.0, 36.0)), menuChildren: [ MenuItemButton( + style: SubmenuButton.styleFrom(fixedSize: const Size(120.0, 36.0)), child: const Text('Item 0'), onPressed: () {}, ), @@ -3250,17 +3255,17 @@ void main() { ), TestSemantics( id: 6, - rect: const Rect.fromLTRB(0.0, 0.0, 123.0, 64.0), + rect: const Rect.fromLTRB(0.0, 0.0, 120.0, 64.0), children: [ TestSemantics( id: 7, - rect: const Rect.fromLTRB(0.0, 0.0, 123.0, 48.0), + rect: const Rect.fromLTRB(0.0, 0.0, 120.0, 48.0), flags: [SemanticsFlag.hasImplicitScrolling], children: [ TestSemantics( id: 8, label: 'Item 0', - rect: const Rect.fromLTRB(0.0, 0.0, 123.0, 48.0), + rect: const Rect.fromLTRB(0.0, 0.0, 120.0, 48.0), flags: [SemanticsFlag.hasEnabledState, SemanticsFlag.isEnabled, SemanticsFlag.isFocusable], actions: [SemanticsAction.tap], ), @@ -3320,6 +3325,62 @@ void main() { semantics.dispose(); }); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/131676. + testWidgets('Material3 - Menu uses correct text styles', (WidgetTester tester) async { + const TextStyle menuTextStyle = TextStyle( + fontSize: 18.5, + fontStyle: FontStyle.italic, + wordSpacing: 1.2, + decoration: TextDecoration.lineThrough, + ); + final ThemeData themeData = ThemeData( + textTheme: const TextTheme( + labelLarge: menuTextStyle, + ) + ); + await tester.pumpWidget( + MaterialApp( + theme: themeData, + home: Material( + child: MenuBar( + controller: controller, + children: createTestMenus( + onPressed: onPressed, + onOpen: onOpen, + onClose: onClose, + ), + ), + ), + ), + ); + + // Test menu button text style uses the TextTheme.labelLarge. + Finder buttonMaterial = find.descendant( + of: find.byType(TextButton), + matching: find.byType(Material), + ).first; + Material material = tester.widget(buttonMaterial); + expect(material.textStyle?.fontSize, menuTextStyle.fontSize); + expect(material.textStyle?.fontStyle, menuTextStyle.fontStyle); + expect(material.textStyle?.wordSpacing, menuTextStyle.wordSpacing); + expect(material.textStyle?.decoration, menuTextStyle.decoration); + + // Open the menu. + await tester.tap(find.text(TestMenu.mainMenu1.label)); + await tester.pump(); + + // Test menu item text style uses the TextTheme.labelLarge. + buttonMaterial = find.descendant( + of: find.widgetWithText(TextButton, TestMenu.subMenu10.label), + matching: find.byType(Material), + ).first; + material = tester.widget(buttonMaterial); + expect(material.textStyle?.fontSize, menuTextStyle.fontSize); + expect(material.textStyle?.fontStyle, menuTextStyle.fontStyle); + expect(material.textStyle?.wordSpacing, menuTextStyle.wordSpacing); + expect(material.textStyle?.decoration, menuTextStyle.decoration); + }); } List createTestMenus({ diff --git a/packages/flutter/test/material/menu_style_test.dart b/packages/flutter/test/material/menu_style_test.dart index dc501b68bc386..74ce6b8887a13 100644 --- a/packages/flutter/test/material/menu_style_test.dart +++ b/packages/flutter/test/material/menu_style_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -81,8 +82,10 @@ void main() { expect(tester.getRect(findMenuPanels().first).size, equals(const Size(600.0, 60.0))); // MenuTheme affects menus. - expect(tester.getRect(findMenuPanels().at(1)), equals(const Rect.fromLTRB(104.0, 54.0, 204.0, 154.0))); - expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); + if (!kIsWeb || isCanvasKit) { // https://github.com/flutter/flutter/issues/99933 + expect(tester.getRect(findMenuPanels().at(1)), equals(const Rect.fromLTRB(104.0, 54.0, 204.0, 154.0))); + expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); + } }); testWidgets('maximumSize affects geometry', (WidgetTester tester) async { From 00a99d3bc09bed0433319f05f5161557d11039f8 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 22 Aug 2023 15:32:01 -0700 Subject: [PATCH 0847/1547] [gallery] roll gallery to ecfb9e5352bd12032301b12b30d5853d83d89bda (#133083) This shrinks the size of the reply image attachments which should make it easier to find the actionable issues in https://github.com/flutter/flutter/issues/132690 --- dev/devicelab/lib/versions/gallery.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/devicelab/lib/versions/gallery.dart b/dev/devicelab/lib/versions/gallery.dart index d893328be209a..5a15fadaad044 100644 --- a/dev/devicelab/lib/versions/gallery.dart +++ b/dev/devicelab/lib/versions/gallery.dart @@ -3,4 +3,4 @@ // found in the LICENSE file. /// The pinned version of flutter gallery, used for devicelab tests. -const String galleryVersion = '6a8d738c94d0710e229d726729c09fdb5ccaf7ed'; +const String galleryVersion = 'ecfb9e5352bd12032301b12b30d5853d83d89bda'; From 5e9e959d570c2924430d9d9c12b27742a44af3eb Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 22 Aug 2023 16:36:00 -0700 Subject: [PATCH 0848/1547] Revert "[gallery] roll gallery to ecfb9e5352bd12032301b12b30d5853d83d89bda" (#133095) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts flutter/flutter#133083 failing on cocoapods: ``` [2023-08-22 16:28:37.783355] [STDOUT] stdout: [ ] Error output from CocoaPods: [2023-08-22 16:28:37.783379] [STDOUT] stdout: ↳ [2023-08-22 16:28:37.783402] [STDOUT] stdout: [ ] [!] The version of CocoaPods used to generate the lockfile (1.12.1) is higher than the version of the current executable (1.11.3). Incompatibility issues may arise. [2023-08-22 16:28:37.783423] [STDOUT] stdout: [2023-08-22 16:28:37.783445] [STDOUT] stdout: [!] Automatically assigning platform `iOS` with version `11.0` on target `Runner` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`. [2023-08-22 16:28:37.783469] [STDOUT] stdout: [2023-08-22 16:28:37.784059] [STDOUT] stderr: [ ] Error: CocoaPods's specs repository is too out-of-date to satisfy dependencies. [2023-08-22 16:28:37.784102] [STDOUT] stderr: To update the CocoaPods specs, run: [2023-08-22 16:28:37.784126] [STDOUT] stderr: pod repo update [2023-08-22 16:28:37.784147] [STDOUT] stderr: ``` https://ci.chromium.org/ui/p/flutter/builders/prod/Mac_ios%20new_gallery_ios__transition_perf/10590/overview --- dev/devicelab/lib/versions/gallery.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/devicelab/lib/versions/gallery.dart b/dev/devicelab/lib/versions/gallery.dart index 5a15fadaad044..d893328be209a 100644 --- a/dev/devicelab/lib/versions/gallery.dart +++ b/dev/devicelab/lib/versions/gallery.dart @@ -3,4 +3,4 @@ // found in the LICENSE file. /// The pinned version of flutter gallery, used for devicelab tests. -const String galleryVersion = 'ecfb9e5352bd12032301b12b30d5853d83d89bda'; +const String galleryVersion = '6a8d738c94d0710e229d726729c09fdb5ccaf7ed'; From 2afded6170efa3592cc2c44ad1108674074f88fe Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 22 Aug 2023 17:06:05 -0700 Subject: [PATCH 0849/1547] Add test to mark recording as leaking. (#133073) --- .../test/animation/animation_sheet_test.dart | 36 +++++++++++-- .../test/animation/live_binding_test.dart | 8 ++- .../test/material/date_range_picker_test.dart | 13 ++--- .../material/text_selection_theme_test.dart | 50 ++++++++++--------- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/packages/flutter/test/animation/animation_sheet_test.dart b/packages/flutter/test/animation/animation_sheet_test.dart index 0d60746c45dfb..df48b9e4baee5 100644 --- a/packages/flutter/test/animation/animation_sheet_test.dart +++ b/packages/flutter/test/animation/animation_sheet_test.dart @@ -11,6 +11,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { @@ -19,7 +20,25 @@ void main() { * because [matchesGoldenFile] does not use Skia Gold in its native package. */ - testWidgets('correctly records frames using collate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recording disposes images', + (WidgetTester tester) async { + final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); + + await tester.pumpFrames( + builder.record( + const _DecuplePixels(Duration(seconds: 1)), + ), + const Duration(milliseconds: 200), + const Duration(milliseconds: 100), + ); + }, + skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 + // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 + leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), + ); + + testWidgetsWithLeakTracking('correctly records frames using collate', + (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); await tester.pumpFrames( @@ -53,10 +72,15 @@ void main() { image, matchesGoldenFile('test.animation_sheet_builder.collate.png'), ); + image.dispose(); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + }, + skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 + // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 + leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), + ); // https://github.com/flutter/flutter/issues/56001 - testWidgets('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder( frameSize: const Size(8, 2), allLayers: true, @@ -88,7 +112,11 @@ void main() { matchesGoldenFile('test.animation_sheet_builder.out_of_tree.png'), ); image.dispose(); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + }, + skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 + // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 + leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), + ); } // An animation of a yellow pixel moving from left to right, in a container of diff --git a/packages/flutter/test/animation/live_binding_test.dart b/packages/flutter/test/animation/live_binding_test.dart index e0d523fb22ab4..5959c669bb272 100644 --- a/packages/flutter/test/animation/live_binding_test.dart +++ b/packages/flutter/test/animation/live_binding_test.dart @@ -79,7 +79,7 @@ void main() { // Currently skipped due to daily flake: https://github.com/flutter/flutter/issues/87588 }, skip: true); // Typically skip: isBrowser https://github.com/flutter/flutter/issues/42767 - testWidgets('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(200, 200), allLayers: true); final List taps = []; Widget target({bool recording = true}) => Container( @@ -138,5 +138,9 @@ void main() { matchesGoldenFile('LiveBinding.press.animation.2.png'), ); image.dispose(); - }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 + }, + skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 + // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 + leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), + ); } diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index 021a85b5db95e..6bd0e10eff513 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -255,12 +255,13 @@ void main() { await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); }, - // TODO(polina-c): remove after resolving - // https://github.com/flutter/flutter/issues/130354 - leakTrackingTestConfig: const LeakTrackingTestConfig( - allowAllNotGCed: true, - allowAllNotDisposed: true, - )); + // TODO(polina-c): remove after resolving + // https://github.com/flutter/flutter/issues/130354 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotGCed: true, + allowAllNotDisposed: true, + ), + ); }); testWidgets('Save and help text is used', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index ecd0850d8069d..947df64c3f3be 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -106,18 +106,19 @@ void main() { final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130469 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: { - 'ValueNotifier': 1, - 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, - }, - // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. - allowAllNotGCed: true, - )); + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130469 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'ValueNotifier': 1, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, + 'ValueNotifier': 2, + '_InputBorderGap': 1, + }, + // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. + allowAllNotGCed: true, + ), + ); testWidgetsWithLeakTracking('Material3 - Empty textSelectionTheme will use defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); @@ -167,18 +168,19 @@ void main() { final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130469 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: { - 'ValueNotifier': 1, - 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, - }, - // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. - allowAllNotGCed: true, - )); + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130469 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'ValueNotifier': 1, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, + 'ValueNotifier': 2, + '_InputBorderGap': 1, + }, + // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. + allowAllNotGCed: true, + ), + ); testWidgets('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { const TextSelectionThemeData textSelectionTheme = TextSelectionThemeData( From d8470f713c489a470b5fcc3ed297b9325d2e0992 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Tue, 22 Aug 2023 19:18:00 -0700 Subject: [PATCH 0850/1547] Don't run on Samsung S10, shift to Pixel 7 Pro (#133085) --- .ci.yaml | 123 ++++++++++++++++++++++--------------------------------- 1 file changed, 50 insertions(+), 73 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 4e79859be2d2b..1d4aa94a84712 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -62,16 +62,6 @@ platform_properties: os: Linux device_type: "Pixel 7 Pro" - linux_samsung_s10: - properties: - dependencies: >- - [ - {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "curl", "version": "version:7.64.0"} - ] - os: Linux - device_type: "SM-G973U1" linux_samsung_a02: properties: dependencies: >- @@ -82,6 +72,7 @@ platform_properties: ] os: Linux device_type: "SM-A025V" + mac: properties: dependencies: >- @@ -1668,17 +1659,18 @@ targets: ["devicelab", "android", "linux"] task_name: backdrop_filter_perf__e2e_summary - - name: Linux_samsung_s10 backdrop_filter_perf__timeline_summary + - name: Linux_pixel_7pro backdrop_filter_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: backdrop_filter_perf__timeline_summary - - name: Linux_samsung_s10 draw_atlas_perf_opengles__timeline_summary + - name: Linux_pixel_7pro draw_atlas_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -1686,10 +1678,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: draw_atlas_perf_opengles__timeline_summary - - name: Linux_samsung_s10 draw_atlas_perf__timeline_summary + - name: Linux_pixel_7pro draw_atlas_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -1697,10 +1689,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: draw_atlas_perf__timeline_summary - - name: Linux_samsung_s10 dynamic_path_tessellation_perf__timeline_summary + - name: Linux_pixel_7pro dynamic_path_tessellation_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -1708,10 +1700,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: dynamic_path_tessellation_perf__timeline_summary - - name: Linux_samsung_s10 static_path_tessellation_perf__timeline_summary + - name: Linux_pixel_7pro static_path_tessellation_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -1719,7 +1711,7 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: static_path_tessellation_perf__timeline_summary - name: Linux_android basic_material_app_android__compile @@ -1846,13 +1838,14 @@ targets: {"dependency": "open_jdk", "version": "version:11"} ] - - name: Linux_samsung_s10 complex_layout_scroll_perf__timeline_summary + - name: Linux_pixel_7pro complex_layout_scroll_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: complex_layout_scroll_perf__timeline_summary dependencies: >- [ @@ -1894,13 +1887,14 @@ targets: ["devicelab", "android", "linux"] task_name: cubic_bezier_perf__e2e_summary - - name: Linux_samsung_s10 cubic_bezier_perf__timeline_summary + - name: Linux_pixel_7pro cubic_bezier_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: cubic_bezier_perf__timeline_summary - name: Linux_android cull_opacity_perf__e2e_summary @@ -1912,13 +1906,14 @@ targets: ["devicelab", "android", "linux"] task_name: cull_opacity_perf__e2e_summary - - name: Linux_samsung_s10 cull_opacity_perf__timeline_summary + - name: Linux_pixel_7pro cull_opacity_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: cull_opacity_perf__timeline_summary - name: Linux_android devtools_profile_start_test @@ -2174,13 +2169,14 @@ targets: ["devicelab", "android", "linux"] task_name: imagefiltered_transform_animation_perf__timeline_summary - - name: Linux_samsung_s10 imagefiltered_transform_animation_perf__timeline_summary + - name: Linux_pixel_7pro imagefiltered_transform_animation_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: imagefiltered_transform_animation_perf__timeline_summary - name: Linux_android image_list_reported_duration @@ -2339,16 +2335,6 @@ targets: ["devicelab", "android", "linux"] task_name: new_gallery__transition_perf - # Samsung S10, Skia - - name: Linux_samsung_s10 new_gallery__transition_perf - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - tags: > - ["devicelab", "android", "linux", "samsung", "s10"] - task_name: new_gallery__transition_perf - # Pixel 7 Pro, Skia - name: Linux_pixel_7pro new_gallery__transition_perf recipe: devicelab/devicelab_drone @@ -2406,20 +2392,8 @@ targets: ["devicelab", "android", "linux", "samsung", "a02"] task_name: new_gallery_impeller__transition_perf - # Samsung S10, Impeller (Vulkan) - - name: Linux_samsung_s10 new_gallery_impeller__transition_perf - bringup: true # Flaky https://github.com/flutter/flutter/issues/124693 - recipe: devicelab/devicelab_drone - presubmit: false - timeout: 60 - properties: - ignore_flakiness: "true" - tags: > - ["devicelab", "android", "linux", "samsung", "s10"] - task_name: new_gallery_impeller__transition_perf - - # Samsung S10, Impeller (OpenGL) - - name: Linux_samsung_s10 new_gallery_opengles_impeller__transition_perf + # Pixel 7 Pro, Impeller (OpenGL) + - name: Linux_pixel_7pro new_gallery_opengles_impeller__transition_perf bringup: true recipe: devicelab/devicelab_drone presubmit: false @@ -2427,7 +2401,7 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: new_gallery_opengles_impeller__transition_perf - name: Linux_android picture_cache_perf__e2e_summary @@ -2439,13 +2413,14 @@ targets: ["devicelab", "android", "linux"] task_name: picture_cache_perf__e2e_summary - - name: Linux_samsung_s10 picture_cache_perf__timeline_summary + - name: Linux_pixel_7pro picture_cache_perf__timeline_summary recipe: devicelab/devicelab_drone + bringup: true presubmit: false timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: picture_cache_perf__timeline_summary - name: Linux_android android_picture_cache_complexity_scoring_perf__timeline_summary @@ -2502,13 +2477,14 @@ targets: ["devicelab", "android", "linux"] task_name: platform_views_scroll_perf__timeline_summary - - name: Linux_samsung_s10 platform_views_scroll_perf__timeline_summary + - name: Linux_pixel_7pro platform_views_scroll_perf__timeline_summary recipe: devicelab/devicelab_drone + bringup: true presubmit: false timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: platform_views_scroll_perf__timeline_summary - name: Linux_android platform_views_scroll_perf_impeller__timeline_summary @@ -2522,7 +2498,7 @@ targets: ["devicelab", "android", "linux"] task_name: platform_views_scroll_perf_impeller__timeline_summary - - name: Linux_samsung_s10 platform_views_scroll_perf_impeller__timeline_summary + - name: Linux_pixel_7pro platform_views_scroll_perf_impeller__timeline_summary bringup: true recipe: devicelab/devicelab_drone presubmit: false @@ -2530,7 +2506,7 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: platform_views_scroll_perf_impeller__timeline_summary - name: Linux_android platform_view__start_up @@ -2569,13 +2545,14 @@ targets: ["devicelab", "android", "linux"] task_name: textfield_perf__e2e_summary - - name: Linux_samsung_s10 textfield_perf__timeline_summary + - name: Linux_pixel_7pro textfield_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + bringup: true timeout: 60 properties: tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: textfield_perf__timeline_summary - name: Linux_android tiles_scroll_perf__timeline_summary @@ -2710,7 +2687,7 @@ targets: ["devicelab", "android", "linux"] task_name: animated_blur_backdrop_filter_perf__timeline_summary - - name: Linux_samsung_s10 animated_blur_backdrop_filter_perf__timeline_summary + - name: Linux_pixel_7pro animated_blur_backdrop_filter_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -2718,10 +2695,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: animated_blur_backdrop_filter_perf__timeline_summary - - name: Linux_samsung_s10 animated_advanced_blend_perf_opengles__timeline_summary + - name: Linux_pixel_7pro animated_advanced_blend_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -2729,10 +2706,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: animated_advanced_blend_perf_opengles__timeline_summary - - name: Linux_samsung_s10 animated_advanced_blend_perf__timeline_summary + - name: Linux_pixel_7pro animated_advanced_blend_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -2740,7 +2717,7 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: animated_advanced_blend_perf__timeline_summary - name: Mac_ios animated_advanced_blend_perf_ios__timeline_summary @@ -2753,7 +2730,7 @@ targets: ["devicelab", "ios", "mac"] task_name: animated_advanced_blend_perf_ios__timeline_summary - - name: Linux_samsung_s10 animated_blur_backdrop_filter_perf_opengles__timeline_summary + - name: Linux_pixel_7pro animated_blur_backdrop_filter_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -2761,10 +2738,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: animated_blur_backdrop_filter_perf_opengles__timeline_summary - - name: Linux_samsung_s10 draw_vertices_perf_opengles__timeline_summary + - name: Linux_pixel_7pro draw_vertices_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -2772,10 +2749,10 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: draw_vertices_perf_opengles__timeline_summary - - name: Linux_samsung_s10 draw_vertices_perf__timeline_summary + - name: Linux_pixel_7pro draw_vertices_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false bringup: true @@ -2783,7 +2760,7 @@ targets: properties: ignore_flakiness: "true" tags: > - ["devicelab", "android", "linux", "samsung", "s10"] + ["devicelab", "android", "linux", "pixel", "7pro"] task_name: draw_vertices_perf__timeline_summary - name: Mac_ios draw_vertices_perf_ios__timeline_summary From 487bd69078058629f5b6fa8ecbc411f0d27ad894 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 22 Aug 2023 20:35:22 -0700 Subject: [PATCH 0851/1547] Support disabling animations in the CLI (#132239) --- packages/flutter_tools/lib/executable.dart | 8 ++++ packages/flutter_tools/lib/runner.dart | 2 - .../lib/src/base/command_help.dart | 8 +++- .../flutter_tools/lib/src/base/logger.dart | 6 +-- .../flutter_tools/lib/src/base/terminal.dart | 17 +++++++- packages/flutter_tools/lib/src/features.dart | 18 +++++++-- .../lib/src/flutter_features.dart | 8 ++++ .../lib/src/reporting/first_run.dart | 5 ++- .../hermetic/custom_devices_test.dart | 3 ++ .../commands.shard/hermetic/devices_test.dart | 3 ++ .../commands.shard/hermetic/doctor_test.dart | 3 ++ .../general.shard/base/command_help_test.dart | 28 +++++++------ .../test/general.shard/base/logger_test.dart | 40 +++++++++++++++++++ .../runner/target_devices_test.dart | 3 ++ packages/flutter_tools/test/src/fakes.dart | 6 +++ 15 files changed, 131 insertions(+), 27 deletions(-) diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index b5ecf5a3bcb0d..9bd3ea190d1f7 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -124,6 +124,14 @@ Future main(List args) async { windows: globals.platform.isWindows, ); }, + Terminal: () { + return AnsiTerminal( + stdio: globals.stdio, + platform: globals.platform, + now: DateTime.now(), + isCliAnimationEnabled: featureFlags.isCliAnimationEnabled, + ); + }, PreRunValidator: () => PreRunValidator(fileSystem: globals.fs), }, shutdownHooks: globals.shutdownHooks, diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index 50f58d53b428a..d2dd7d6c535e6 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - - import 'dart:async'; import 'package:args/command_runner.dart'; diff --git a/packages/flutter_tools/lib/src/base/command_help.dart b/packages/flutter_tools/lib/src/base/command_help.dart index f9922dbc21679..982f72787e9dc 100644 --- a/packages/flutter_tools/lib/src/base/command_help.dart +++ b/packages/flutter_tools/lib/src/base/command_help.dart @@ -259,8 +259,12 @@ class CommandHelpOption { message.write(''.padLeft(width - parentheticalText.length)); message.write(_terminal.color(parentheticalText, TerminalColor.grey)); - // Terminals seem to require this because we have both bolded and colored - // a line. Otherwise the next line comes out bold until a reset bold. + // Some terminals seem to have a buggy implementation of the SGR ANSI escape + // codes and seem to require that we explicitly request "normal intensity" + // at the end of the line to prevent the next line comes out bold, despite + // the fact that the line already contains a "normal intensity" code. + // This doesn't make much sense but has been reproduced by multiple users. + // See: https://github.com/flutter/flutter/issues/52204 if (_terminal.supportsColor) { message.write(AnsiTerminal.resetBold); } diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart index 2c418a3b9dc0e..b6d185d067f80 100644 --- a/packages/flutter_tools/lib/src/base/logger.dart +++ b/packages/flutter_tools/lib/src/base/logger.dart @@ -36,7 +36,7 @@ abstract class Logger { /// If true, silences the logger output. bool quiet = false; - /// If true, this logger supports color output. + /// If true, this logger supports ANSI sequences and animations are enabled. bool get supportsColor; /// If true, this logger is connected to a terminal. @@ -443,7 +443,7 @@ class StdoutLogger extends Logger { bool get isVerbose => false; @override - bool get supportsColor => terminal.supportsColor; + bool get supportsColor => terminal.supportsColor && terminal.isCliAnimationEnabled; @override bool get hasTerminal => _stdio.stdinHasTerminal; @@ -772,7 +772,7 @@ class BufferLogger extends Logger { bool get isVerbose => _verbose; @override - bool get supportsColor => terminal.supportsColor; + bool get supportsColor => terminal.supportsColor && terminal.isCliAnimationEnabled; final StringBuffer _error = StringBuffer(); final StringBuffer _warning = StringBuffer(); diff --git a/packages/flutter_tools/lib/src/base/terminal.dart b/packages/flutter_tools/lib/src/base/terminal.dart index 720b92595fcf3..b782441b5996c 100644 --- a/packages/flutter_tools/lib/src/base/terminal.dart +++ b/packages/flutter_tools/lib/src/base/terminal.dart @@ -76,8 +76,14 @@ abstract class Terminal { factory Terminal.test({bool supportsColor, bool supportsEmoji}) = _TestTerminal; /// Whether the current terminal supports color escape codes. + /// + /// Check [isCliAnimationEnabled] as well before using `\r` or ANSI sequences + /// to perform animations. bool get supportsColor; + /// Whether to show animations on this terminal. + bool get isCliAnimationEnabled; + /// Whether the current terminal can display emoji. bool get supportsEmoji; @@ -152,6 +158,7 @@ class AnsiTerminal implements Terminal { required io.Stdio stdio, required Platform platform, DateTime? now, // Time used to determine preferredStyle. Defaults to 0001-01-01 00:00. + this.isCliAnimationEnabled = true, }) : _stdio = stdio, _platform = platform, @@ -199,6 +206,9 @@ class AnsiTerminal implements Terminal { @override bool get supportsColor => _platform.stdoutSupportsAnsi; + @override + final bool isCliAnimationEnabled; + // Assume unicode emojis are supported when not on Windows. // If we are on Windows, unicode emojis are supported in Windows Terminal, // which sets the WT_SESSION environment variable. See: @@ -275,14 +285,14 @@ class AnsiTerminal implements Terminal { } @override - String clearScreen() => supportsColor ? clear : '\n\n'; + String clearScreen() => supportsColor && isCliAnimationEnabled ? clear : '\n\n'; /// Returns ANSI codes to clear [numberOfLines] lines starting with the line /// the cursor is on. /// /// If the terminal does not support ANSI codes, returns an empty string. String clearLines(int numberOfLines) { - if (!supportsColor) { + if (!supportsColor || !isCliAnimationEnabled) { return ''; } return cursorBeginningOfLineCode + @@ -402,6 +412,9 @@ class _TestTerminal implements Terminal { @override final bool supportsColor; + @override + bool get isCliAnimationEnabled => supportsColor; + @override final bool supportsEmoji; diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index 2c5a1b3c10fee..1e9c303eef188 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -47,6 +47,9 @@ abstract class FeatureFlags { /// Whether WebAssembly compilation for Flutter Web is enabled. bool get isFlutterWebWasmEnabled => false; + /// Whether animations are used in the command line interface. + bool get isCliAnimationEnabled => true; + /// Whether a particular feature is enabled for the current channel. /// /// Prefer using one of the specific getters above instead of this API. @@ -64,6 +67,7 @@ const List allFeatures = [ flutterFuchsiaFeature, flutterCustomDevicesFeature, flutterWebWasm, + cliAnimation, ]; /// All current Flutter feature flags that can be configured. @@ -122,7 +126,7 @@ const Feature flutterFuchsiaFeature = Feature( ); const Feature flutterCustomDevicesFeature = Feature( - name: 'Early support for custom device types', + name: 'early support for custom device types', configSetting: 'enable-custom-devices', environmentOverride: 'FLUTTER_CUSTOM_DEVICES', master: FeatureChannelSetting( @@ -146,6 +150,14 @@ const Feature flutterWebWasm = Feature( ), ); +/// The [Feature] for CLI animations. +/// +/// The TERM environment variable set to "dumb" turns this off. +const Feature cliAnimation = Feature.fullyEnabled( + name: 'animations in the command line interface', + configSetting: 'cli-animations', +); + /// A [Feature] is a process for conditionally enabling tool features. /// /// All settings are optional, and if not provided will generally default to @@ -229,9 +241,9 @@ class Feature { ]; // Add channel info for settings only on some channels. if (channels.length == 1) { - buffer.write('\nThis setting applies to only the ${channels.single} channel.'); + buffer.write('\nThis setting applies only to the ${channels.single} channel.'); } else if (channels.length == 2) { - buffer.write('\nThis setting applies to only the ${channels.join(' and ')} channels.'); + buffer.write('\nThis setting applies only to the ${channels.join(' and ')} channels.'); } if (extraHelpText != null) { buffer.write(' $extraHelpText'); diff --git a/packages/flutter_tools/lib/src/flutter_features.dart b/packages/flutter_tools/lib/src/flutter_features.dart index e4102bdfe8b95..1f6de014e6f2e 100644 --- a/packages/flutter_tools/lib/src/flutter_features.dart +++ b/packages/flutter_tools/lib/src/flutter_features.dart @@ -47,6 +47,14 @@ class FlutterFeatureFlags implements FeatureFlags { @override bool get isFlutterWebWasmEnabled => isEnabled(flutterWebWasm); + @override + bool get isCliAnimationEnabled { + if (_platform.environment['TERM'] == 'dumb') { + return false; + } + return isEnabled(cliAnimation); + } + @override bool isEnabled(Feature feature) { final String currentChannel = _flutterVersion.channel; diff --git a/packages/flutter_tools/lib/src/reporting/first_run.dart b/packages/flutter_tools/lib/src/reporting/first_run.dart index 2d39fe3f53e68..0e2b0caab7ff1 100644 --- a/packages/flutter_tools/lib/src/reporting/first_run.dart +++ b/packages/flutter_tools/lib/src/reporting/first_run.dart @@ -25,8 +25,7 @@ const String _kFlutterFirstRunMessage = ''' ║ Flutter tool. ║ ║ ║ ║ By downloading the Flutter SDK, you agree to the Google Terms of Service. ║ - ║ Note: The Google Privacy Policy describes how data is handled in this ║ - ║ service. ║ + ║ The Google Privacy Policy describes how data is handled in this service. ║ ║ ║ ║ Moreover, Flutter includes the Dart SDK, which may send usage metrics and ║ ║ crash reports to Google. ║ @@ -36,6 +35,8 @@ const String _kFlutterFirstRunMessage = ''' ║ ║ ║ See Google's privacy policy: ║ ║ https://policies.google.com/privacy ║ + ║ ║ + ║ To disable animations in this tool, use 'flutter config --no-animations'. ║ ╚════════════════════════════════════════════════════════════════════════════╝ '''; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart index d0f3e6ea8f128..96563e92ef461 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart @@ -238,6 +238,9 @@ class FakeTerminal implements Terminal { @override bool get supportsColor => terminal.supportsColor; + @override + bool get isCliAnimationEnabled => terminal.isCliAnimationEnabled; + @override bool get supportsEmoji => terminal.supportsEmoji; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart index 7ffae20854d06..c9a2b131ec10a 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart @@ -882,6 +882,9 @@ class FakeTerminal extends Fake implements AnsiTerminal { @override final bool supportsColor; + @override + bool get isCliAnimationEnabled => supportsColor; + @override bool singleCharMode = false; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart index 9d42023235ab7..c732f97ae7bee 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/doctor_test.dart @@ -1228,4 +1228,7 @@ class FakeDevice extends Fake implements Device { class FakeTerminal extends Fake implements AnsiTerminal { @override final bool supportsColor = false; + + @override + bool get isCliAnimationEnabled => supportsColor; } diff --git a/packages/flutter_tools/test/general.shard/base/command_help_test.dart b/packages/flutter_tools/test/general.shard/base/command_help_test.dart index 43451e2f42356..0706e826cb540 100644 --- a/packages/flutter_tools/test/general.shard/base/command_help_test.dart +++ b/packages/flutter_tools/test/general.shard/base/command_help_test.dart @@ -79,6 +79,7 @@ void main() { group('CommandHelp', () { group('toString', () { testWithoutContext('ends with a resetBold when it has parenthetical text', () { + // This is apparently required to work around bugs in some terminal clients. final Platform platform = FakePlatform(stdoutSupportsAnsi: true); final AnsiTerminal terminal = AnsiTerminal(stdio: FakeStdio(), platform: platform); @@ -131,19 +132,19 @@ void main() { wrapColumn: maxLineWidth, ); - expect(commandHelp.I.toString(), endsWith('\x1B[90m(debugInvertOversizedImages)\x1B[39m\x1B[22m')); - expect(commandHelp.L.toString(), endsWith('\x1B[90m(debugDumpLayerTree)\x1B[39m\x1B[22m')); - expect(commandHelp.P.toString(), endsWith('\x1B[90m(WidgetsApp.showPerformanceOverlay)\x1B[39m\x1B[22m')); - expect(commandHelp.S.toString(), endsWith('\x1B[90m(debugDumpSemantics)\x1B[39m\x1B[22m')); - expect(commandHelp.U.toString(), endsWith('\x1B[90m(debugDumpSemantics)\x1B[39m\x1B[22m')); - expect(commandHelp.a.toString(), endsWith('\x1B[90m(debugProfileWidgetBuilds)\x1B[39m\x1B[22m')); - expect(commandHelp.b.toString(), endsWith('\x1B[90m(debugBrightnessOverride)\x1B[39m\x1B[22m')); - expect(commandHelp.f.toString(), endsWith('\x1B[90m(debugDumpFocusTree)\x1B[39m\x1B[22m')); - expect(commandHelp.i.toString(), endsWith('\x1B[90m(WidgetsApp.showWidgetInspectorOverride)\x1B[39m\x1B[22m')); - expect(commandHelp.o.toString(), endsWith('\x1B[90m(defaultTargetPlatform)\x1B[39m\x1B[22m')); - expect(commandHelp.p.toString(), endsWith('\x1B[90m(debugPaintSizeEnabled)\x1B[39m\x1B[22m')); - expect(commandHelp.t.toString(), endsWith('\x1B[90m(debugDumpRenderTree)\x1B[39m\x1B[22m')); - expect(commandHelp.w.toString(), endsWith('\x1B[90m(debugDumpApp)\x1B[39m\x1B[22m')); + expect(commandHelp.I.toString(), contains('\x1B[90m(debugInvertOversizedImages)\x1B[39m')); + expect(commandHelp.L.toString(), contains('\x1B[90m(debugDumpLayerTree)\x1B[39m')); + expect(commandHelp.P.toString(), contains('\x1B[90m(WidgetsApp.showPerformanceOverlay)\x1B[39m')); + expect(commandHelp.S.toString(), contains('\x1B[90m(debugDumpSemantics)\x1B[39m')); + expect(commandHelp.U.toString(), contains('\x1B[90m(debugDumpSemantics)\x1B[39m')); + expect(commandHelp.a.toString(), contains('\x1B[90m(debugProfileWidgetBuilds)\x1B[39m')); + expect(commandHelp.b.toString(), contains('\x1B[90m(debugBrightnessOverride)\x1B[39m')); + expect(commandHelp.f.toString(), contains('\x1B[90m(debugDumpFocusTree)\x1B[39m')); + expect(commandHelp.i.toString(), contains('\x1B[90m(WidgetsApp.showWidgetInspectorOverride)\x1B[39m')); + expect(commandHelp.o.toString(), contains('\x1B[90m(defaultTargetPlatform)\x1B[39m')); + expect(commandHelp.p.toString(), contains('\x1B[90m(debugPaintSizeEnabled)\x1B[39m')); + expect(commandHelp.t.toString(), contains('\x1B[90m(debugDumpRenderTree)\x1B[39m')); + expect(commandHelp.w.toString(), contains('\x1B[90m(debugDumpApp)\x1B[39m')); }); testWithoutContext('should not create a help text longer than maxLineWidth without ansi support', () { @@ -184,6 +185,7 @@ void main() { wrapColumn: maxLineWidth, ); + // The trailing \x1B[22m is to work around reported bugs in some terminal clients. expect(commandHelp.I.toString(), equals('\x1B[1mI\x1B[22m Toggle oversized image inversion. \x1B[90m(debugInvertOversizedImages)\x1B[39m\x1B[22m')); expect(commandHelp.L.toString(), equals('\x1B[1mL\x1B[22m Dump layer tree to the console. \x1B[90m(debugDumpLayerTree)\x1B[39m\x1B[22m')); expect(commandHelp.M.toString(), equals('\x1B[1mM\x1B[22m Write SkSL shaders to a unique file in the project directory.')); diff --git a/packages/flutter_tools/test/general.shard/base/logger_test.dart b/packages/flutter_tools/test/general.shard/base/logger_test.dart index 29a142acdc508..edb9e52a2a31d 100644 --- a/packages/flutter_tools/test/general.shard/base/logger_test.dart +++ b/packages/flutter_tools/test/general.shard/base/logger_test.dart @@ -1286,6 +1286,46 @@ void main() { expect(mockLogger.traceText, 'Oooh, I do I do I do\n'); expect(mockLogger.errorText, 'Helpless!\n$stackTrace\n'); }); + + testWithoutContext('Animations are disabled when, uh, disabled.', () async { + final Logger logger = StdoutLogger( + terminal: AnsiTerminal( + stdio: fakeStdio, + platform: _kNoAnsiPlatform, + isCliAnimationEnabled: false, + ), + stdio: fakeStdio, + outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40), + ); + logger.startProgress('po').stop(); + expect(outputStderr(), ['']); + expect(outputStdout(), [ + 'po 0ms', + '', + ]); + logger.startProgress('ta') + ..pause() + ..resume() + ..stop(); + expect(outputStderr(), ['']); + expect(outputStdout(), [ + 'po 0ms', + 'ta ', + 'ta 0ms', + '', + ]); + logger.startSpinner() + ..pause() + ..resume() + ..stop(); + expect(outputStderr(), ['']); + expect(outputStdout(), [ + 'po 0ms', + 'ta ', + 'ta 0ms', + '', + ]); + }); }); } diff --git a/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart b/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart index 6c89db8fa8e3c..7befa7793c947 100644 --- a/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/target_devices_test.dart @@ -2884,6 +2884,9 @@ class FakeTerminal extends Fake implements AnsiTerminal { @override final bool supportsColor; + @override + bool get isCliAnimationEnabled => supportsColor; + @override bool usesTerminalUi = true; diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index d51ec236dcaac..2cd16a00a7768 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -448,6 +448,7 @@ class TestFeatureFlags implements FeatureFlags { this.isFuchsiaEnabled = false, this.areCustomDevicesEnabled = false, this.isFlutterWebWasmEnabled = false, + this.isCliAnimationEnabled = true, }); @override @@ -477,6 +478,9 @@ class TestFeatureFlags implements FeatureFlags { @override final bool isFlutterWebWasmEnabled; + @override + final bool isCliAnimationEnabled; + @override bool isEnabled(Feature feature) { switch (feature) { @@ -496,6 +500,8 @@ class TestFeatureFlags implements FeatureFlags { return isFuchsiaEnabled; case flutterCustomDevicesFeature: return areCustomDevicesEnabled; + case cliAnimation: + return isCliAnimationEnabled; } return false; } From 88290989a174718713b825944b6e8a77e1708c76 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 22 Aug 2023 21:13:15 -0700 Subject: [PATCH 0852/1547] Reference AppLifecycleListener from widgets library (#132995) --- packages/flutter/lib/src/widgets/binding.dart | 8 ++++++++ packages/flutter/lib/src/widgets/framework.dart | 3 +++ 2 files changed, 11 insertions(+) diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index f5d2a4fe8d59e..d0fdbcf9ca00e 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -254,6 +254,11 @@ abstract mixin class WidgetsBindingObserver { /// documentation for the [WidgetsBindingObserver] class. /// /// This method exposes notifications from [SystemChannels.lifecycle]. + /// + /// See also: + /// + /// * [AppLifecycleListener], an alternative API for responding to + /// application lifecycle changes. void didChangeAppLifecycleState(AppLifecycleState state) { } /// Called when a request is received from the system to exit the application. @@ -1171,6 +1176,9 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// To artificially cause the entire widget tree to be disposed, consider /// calling [runApp] with a widget such as [SizedBox.shrink]. /// +/// To listen for platform shutdown messages (and other lifecycle changes), +/// consider the [AppLifecycleListener] API. +/// /// See also: /// /// * [WidgetsBinding.attachRootWidget], which creates the root widget for the diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index c1c45fcbfa097..4443a141333d1 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1317,6 +1317,9 @@ abstract class State with Diagnosticable { /// To artificially cause the entire widget tree to be disposed, consider /// calling [runApp] with a widget such as [SizedBox.shrink]. /// + /// To listen for platform shutdown messages (and other lifecycle changes), + /// consider the [AppLifecycleListener] API. + /// /// See also: /// /// * [deactivate], which is called prior to [dispose]. From 4bbcb780a6bc2520bdaf777d7b5d8bc9e6cc3d02 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 00:53:44 -0400 Subject: [PATCH 0853/1547] Manual roll Flutter Engine from b190f9015049 to 7d56840865d2 (15 revisions) (#133106) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/b190f9015049...7d56840865d2 2023-08-23 zanderso@users.noreply.github.com Revert "Roll Dart SDK from ab417bc74bb1 to c162b4979562 (1 revision)" (flutter/engine#44989) 2023-08-23 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from G25oJMO5jbUi-UN4F... to DoQ8KUxSk-5EU6VQ1... (flutter/engine#44988) 2023-08-23 zanderso@users.noreply.github.com Revert "Make `FontWeight` an enum, Remove unused text classes" (flutter/engine#44987) 2023-08-23 skia-flutter-autoroll@skia.org Roll Dart SDK from ab417bc74bb1 to c162b4979562 (1 revision) (flutter/engine#44986) 2023-08-23 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from kKI09su99b0AKs8b3... to VSvpNFoFjqXIQTcs6... (flutter/engine#44984) 2023-08-23 matanlurey@users.noreply.github.com Enable clang-tidy for pre-push (opt-out), exclude `performance-unnecessary-value-param` (flutter/engine#44936) 2023-08-22 john@johnmccutchan.com Restore old SurfaceTextureExternal drawing code (flutter/engine#44979) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from d0918de21c1a to aa208c8a2d60 (2 revisions) (flutter/engine#44981) 2023-08-22 jason-simmons@users.noreply.github.com Initialize the texture destruction callback in the Metal embedder test harness (flutter/engine#44973) 2023-08-22 matanlurey@users.noreply.github.com Further filter/clear `.setDither(true)`, this time in `DlSkPaintDispatchHelper` (flutter/engine#44912) 2023-08-22 skia-flutter-autoroll@skia.org Roll Dart SDK from 3ebf0fedfceb to ab417bc74bb1 (1 revision) (flutter/engine#44977) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from bf6019be75ef to d0918de21c1a (3 revisions) (flutter/engine#44975) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from c675298ddeda to bf6019be75ef (3 revisions) (flutter/engine#44974) 2023-08-22 31859944+LongCatIsLooong@users.noreply.github.com Make `FontWeight` an enum, Remove unused text classes (flutter/engine#44960) 2023-08-22 skia-flutter-autoroll@skia.org Roll Skia from 9f4b81aac175 to c675298ddeda (2 revisions) (flutter/engine#44971) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from kKI09su99b0A to VSvpNFoFjqXI fuchsia/sdk/core/mac-amd64 from G25oJMO5jbUi to DoQ8KUxSk-5E If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8bec0fce5f807..e5ef5261bfb76 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b190f90150494f593bd9d2c0c3186ac41170ea12 +7d56840865d2996dbebb4107ac72c615415b19aa diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index e2a043b24b7c3..94415ae710a33 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -kKI09su99b0AKs8b3VKTzXDVmeTaKm7ye2chxl9BE0EC +VSvpNFoFjqXIQTcs6DNCULAdo8w6qvh778kBCzS6sToC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ca462e033d535..75e3eade5d78d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -G25oJMO5jbUi-UN4FM1owc2acv-i0u7MdKqblmI-czMC +DoQ8KUxSk-5EU6VQ1y8J_jExb2kejowbTxAzuN59HjIC From 575fd7ee22e8792bf5fa3f9db9ffc2488cf2bd55 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 09:32:09 -0400 Subject: [PATCH 0854/1547] Roll Flutter Engine from 7d56840865d2 to 72a06427bd37 (8 revisions) (#133139) https://github.com/flutter/engine/compare/7d56840865d2...72a06427bd37 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from ee7404db8273 to d0c369eaa637 (1 revision) (flutter/engine#44997) 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from d0d2b7042bb9 to ee7404db8273 (1 revision) (flutter/engine#44995) 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from eac8f8ea2660 to d0d2b7042bb9 (1 revision) (flutter/engine#44994) 2023-08-23 zanderso@users.noreply.github.com Revert "FontVariation.lerp, custom FontVariation constructors, and more documentation" (flutter/engine#44993) 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from aa208c8a2d60 to eac8f8ea2660 (1 revision) (flutter/engine#44992) 2023-08-23 dkwingsmt@users.noreply.github.com Move Rasterizer::Draw's discard_callback to Delegate (flutter/engine#44813) 2023-08-23 ian@hixie.ch FontVariation.lerp, custom FontVariation constructors, and more documentation (flutter/engine#43750) 2023-08-23 ian@hixie.ch Make web tests start with an empty title (flutter/engine#43846) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e5ef5261bfb76..6478b07ba2995 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7d56840865d2996dbebb4107ac72c615415b19aa +72a06427bd37c009a0bb87536fed2423689004a5 From bd836cc63ae016a98c6a4ef054e05fdf40e1f498 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 11:40:06 -0400 Subject: [PATCH 0855/1547] Roll Packages from c730a90f2fcc to 3060b1aec99c (4 revisions) (#133149) https://github.com/flutter/packages/compare/c730a90f2fcc...3060b1aec99c 2023-08-23 ian@hixie.ch [rfw] Support web (as JS) (flutter/packages#4650) 2023-08-22 84124091+opxdelwin@users.noreply.github.com [webview_flutter] Update sample code. (flutter/packages#4727) 2023-08-22 ctrysbita@outlook.com [flutter_adaptive_scaffold] Fix top padding for NavigationBar (flutter/packages#4661) 2023-08-22 31859944+LongCatIsLooong@users.noreply.github.com Remove deprecated `ImageProvider` methods (flutter/packages#4725) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index bb0781e91b6f2..859dbb657005c 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -c730a90f2fccee3b9f7b576b870bf8670ac189e6 +3060b1aec99c54165fde27c1c8a58c553b657447 From 8ba40bb19bcc2f70011281c1d3a47ea22dde37d0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 13:06:07 -0400 Subject: [PATCH 0856/1547] Roll Flutter Engine from 72a06427bd37 to ac352ba95f43 (2 revisions) (#133158) https://github.com/flutter/engine/compare/72a06427bd37...ac352ba95f43 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from d0c369eaa637 to 2111e8126c08 (1 revision) (flutter/engine#45002) 2023-08-23 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from VSvpNFoFjqXIQTcs6... to -HcyJtxGxUDcqX-jo... (flutter/engine#44999) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from VSvpNFoFjqXI to -HcyJtxGxUDc If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6478b07ba2995..2784c275e8e52 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -72a06427bd37c009a0bb87536fed2423689004a5 +ac352ba95f43fc303082f2291d9abdf11510192f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 94415ae710a33..bafb73151ffbb 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -VSvpNFoFjqXIQTcs6DNCULAdo8w6qvh778kBCzS6sToC +-HcyJtxGxUDcqX-joRgopminL0PbfzDP9E1TMp9xBSgC From d8b1e81c1f055e3758804086ae58b04005d8af70 Mon Sep 17 00:00:00 2001 From: Jackson Gardner Date: Wed, 23 Aug 2023 10:07:41 -0700 Subject: [PATCH 0857/1547] Add `--experimental-wasm-type-reflection` and support newer emscripten builds. (#133084) This makes two changes to prepare for incoming changes to skwasm in the web engine: * We will (at least for now) be depending on the `WebAssembly.Function` constructor in `skwasm`, which is hidden behind the `--experimental-wasm-type-reflection` flag. We need to pass that when running skwasm benchmarks. * We are going to be upgrading the skwasm build to a newer version of emscripten, which exposes the wasm exports via the `wasmExports` property instead of the `asm` property. Make sure to support either, if passed. --- dev/devicelab/lib/framework/browser.dart | 7 +++++-- .../lib/src/web/file_generators/wasm_bootstrap.dart | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dev/devicelab/lib/framework/browser.dart b/dev/devicelab/lib/framework/browser.dart index 9d4581faec009..a35f6ac0d85d0 100644 --- a/dev/devicelab/lib/framework/browser.dart +++ b/dev/devicelab/lib/framework/browser.dart @@ -87,6 +87,10 @@ class Chrome { print('Launching Chrome...'); } + final String jsFlags = options.enableWasmGC ? [ + '--experimental-wasm-gc', + '--experimental-wasm-type-reflection', + ].join(' ') : ''; final bool withDebugging = options.debugPort != null; final List args = [ if (options.userDataDirectory != null) @@ -108,8 +112,7 @@ class Chrome { '--no-default-browser-check', '--disable-default-apps', '--disable-translate', - if (options.enableWasmGC) - '--js-flags=--experimental-wasm-gc', + if (jsFlags.isNotEmpty) '--js-flags=$jsFlags', ]; final io.Process chromeProcess = await _spawnChromiumProcess( diff --git a/packages/flutter_tools/lib/src/web/file_generators/wasm_bootstrap.dart b/packages/flutter_tools/lib/src/web/file_generators/wasm_bootstrap.dart index c2ee17b496025..0d1a755c0f2c2 100644 --- a/packages/flutter_tools/lib/src/web/file_generators/wasm_bootstrap.dart +++ b/packages/flutter_tools/lib/src/web/file_generators/wasm_bootstrap.dart @@ -46,7 +46,7 @@ String generateImports(bool isSkwasm) { const skwasmInstance = await skwasm(); window._flutter_skwasmInstance = skwasmInstance; resolve({ - 'skwasm': skwasmInstance.asm, + 'skwasm': skwasmInstance.asm ?? skwasmInstance.wasmExports, 'ffi': { 'memory': skwasmInstance.wasmMemory, } From fd155a34e422794afe6b3a3ea4a226d8dba9c409 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Wed, 23 Aug 2023 13:35:12 -0400 Subject: [PATCH 0858/1547] [web] Remove unnecessary lint ignore (#133164) This became unnecessary since https://github.com/flutter/flutter/pull/132087 --- dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart index a119268ce3464..614f6aa349b6f 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart @@ -4,10 +4,6 @@ import 'dart:async'; import 'dart:js_interop'; -// The analyzer currently thinks `js_interop_unsafe` is unused, but it is used -// for `JSObject.[]=`. -// ignore: unused_import -import 'dart:js_interop_unsafe'; import 'dart:math' as math; import 'dart:ui'; import 'dart:ui_web' as ui_web; From 3cfaa34f7def818d2433d840ffe3bac8d4be59de Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 14:01:14 -0400 Subject: [PATCH 0859/1547] Roll Flutter Engine from ac352ba95f43 to 58dc868c26cb (2 revisions) (#133165) https://github.com/flutter/engine/compare/ac352ba95f43...58dc868c26cb 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from 2111e8126c08 to 5428f147e632 (2 revisions) (flutter/engine#45008) 2023-08-23 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from DoQ8KUxSk-5EU6VQ1... to vJ6oaubpqgRM2nb1e... (flutter/engine#45005) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from DoQ8KUxSk-5E to vJ6oaubpqgRM If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2784c275e8e52..e921a33d29061 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ac352ba95f43fc303082f2291d9abdf11510192f +58dc868c26cb0f7e3751eec903c4c2bb8ea20316 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 75e3eade5d78d..68e5570621118 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -DoQ8KUxSk-5EU6VQ1y8J_jExb2kejowbTxAzuN59HjIC +vJ6oaubpqgRM2nb1e_i0xzq5u59ChjEAmndn9yPIFiUC From ad78cf350697dc1da5333fe5009792ea33e8cced Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Wed, 23 Aug 2023 11:31:04 -0700 Subject: [PATCH 0860/1547] Remove deprecated *TestValues from TestWindow (#131098) Part of https://github.com/flutter/flutter/issues/133171. Removes from `TestWindow`: * `localeTestValue` * `clearLocaleTestValue` * `localesTestValue` * `clearLocalesTestValue` * `initialLifecycleStateTestValue` * `alwaysUse24HourFormatTestValue` * `clearAlwaysUse24HourTestValue` * `brieflyShowPasswordTestValue` * `defaultRouteNameTestValue` * `clearDefaultRouteNameTestValue` * `semanticsEnabledTestValue` * `clearSemanticsEnabledTestValue` * `accessibilityFeaturesTestValue` * `clearAccessibilityFeaturesTestValue` These properties have reached the end of their deprecation period. --- packages/flutter_test/lib/src/binding.dart | 2 +- packages/flutter_test/lib/src/window.dart | 128 +------------------- packages/flutter_test/test/window_test.dart | 103 +--------------- 3 files changed, 4 insertions(+), 229 deletions(-) diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index f3398fe47d100..545490b836f5a 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -492,7 +492,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase } /// Re-attempts the initialization of the lifecycle state after providing - /// test values in [TestWindow.initialLifecycleStateTestValue]. + /// test values in [TestPlatformDispatcher.initialLifecycleStateTestValue]. void readTestInitialLifecycleStateFromNativeWindow() { readInitialLifecycleStateFromNativeWindow(); } diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index 50d6b2bac7dde..e344ad11f5a70 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -1186,7 +1186,7 @@ class _UnsupportedDisplay implements TestDisplay { /// If a test needs to override a real [SingletonFlutterWindow] property and /// then later return to using the real [SingletonFlutterWindow] property, /// [TestWindow] provides methods to clear each individual test value, e.g., -/// [clearLocaleTestValue]. +/// [clearDevicePixelRatioTestValue]. /// /// To clear all fake test values in a [TestWindow], consider using /// [clearAllTestValues]. @@ -1507,22 +1507,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override Locale get locale => platformDispatcher.locale; - /// Hides the real locale and reports the given [localeTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.localeTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set localeTestValue(Locale localeTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.localeTestValue = localeTestValue; - } - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearLocaleTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - /// Deletes any existing test locale and returns to using the real locale. - void clearLocaleTestValue() { - platformDispatcher.clearLocaleTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.locales instead. ' @@ -1531,22 +1515,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override List get locales => platformDispatcher.locales; - /// Hides the real locales and reports the given [localesTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.localesTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set localesTestValue(List localesTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.localesTestValue = localesTestValue; - } - /// Deletes any existing test locales and returns to using the real locales. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearLocalesTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearLocalesTestValue() { - platformDispatcher.clearLocalesTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.onLocaleChanged instead. ' @@ -1572,14 +1540,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override String get initialLifecycleState => platformDispatcher.initialLifecycleState; - /// Sets a faked initialLifecycleState for testing. - @Deprecated( - 'Use WidgetTester.platformDispatcher.initialLifecycleStateTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set initialLifecycleStateTestValue(String state) { // ignore: avoid_setters_without_getters - platformDispatcher.initialLifecycleStateTestValue = state; - } @Deprecated( 'Use WidgetTester.platformDispatcher.textScaleFactor instead. ' @@ -1656,24 +1616,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override bool get alwaysUse24HourFormat => platformDispatcher.alwaysUse24HourFormat; - /// Hides the real clock format and reports the given - /// [alwaysUse24HourFormatTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.alwaysUse24HourFormatTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set alwaysUse24HourFormatTestValue(bool alwaysUse24HourFormatTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.alwaysUse24HourFormatTestValue = alwaysUse24HourFormatTestValue; - } - /// Deletes any existing test clock format and returns to using the real clock - /// format. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearAlwaysUse24HourTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearAlwaysUse24HourTestValue() { - platformDispatcher.clearAlwaysUse24HourTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.onTextScaleFactorChanged instead. ' @@ -1715,15 +1657,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override bool get brieflyShowPassword => platformDispatcher.brieflyShowPassword; - /// Hides the real [brieflyShowPassword] and reports the given - /// `brieflyShowPasswordTestValue` instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.brieflyShowPasswordTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set brieflyShowPasswordTestValue(bool brieflyShowPasswordTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.brieflyShowPasswordTestValue = brieflyShowPasswordTestValue; - } @Deprecated( 'Use WidgetTester.platformDispatcher.onBeginFrame instead. ' @@ -1800,24 +1733,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override String get defaultRouteName => platformDispatcher.defaultRouteName; - /// Hides the real default route name and reports the given - /// [defaultRouteNameTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.defaultRouteNameTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set defaultRouteNameTestValue(String defaultRouteNameTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.defaultRouteNameTestValue = defaultRouteNameTestValue; - } - /// Deletes any existing test default route name and returns to using the real - /// default route name. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearDefaultRouteNameTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearDefaultRouteNameTestValue() { - platformDispatcher.clearDefaultRouteNameTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.scheduleFrame() instead. ' @@ -1846,24 +1761,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override bool get semanticsEnabled => platformDispatcher.semanticsEnabled; - /// Hides the real semantics enabled and reports the given - /// [semanticsEnabledTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.semanticsEnabledTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set semanticsEnabledTestValue(bool semanticsEnabledTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.semanticsEnabledTestValue = semanticsEnabledTestValue; - } - /// Deletes any existing test semantics enabled and returns to using the real - /// semantics enabled. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearSemanticsEnabledTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearSemanticsEnabledTestValue() { - platformDispatcher.clearSemanticsEnabledTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.onSemanticsEnabledChanged instead. ' @@ -1889,27 +1786,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override AccessibilityFeatures get accessibilityFeatures => platformDispatcher.accessibilityFeatures; - /// Hides the real accessibility features and reports the given - /// [accessibilityFeaturesTestValue] instead. - /// - /// Consider using [FakeAccessibilityFeatures] to provide specific - /// values for the various accessibility features under test. - @Deprecated( - 'Use WidgetTester.platformDispatcher.accessibilityFeaturesTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set accessibilityFeaturesTestValue(AccessibilityFeatures accessibilityFeaturesTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.accessibilityFeaturesTestValue = accessibilityFeaturesTestValue; - } - /// Deletes any existing test accessibility features and returns to using the - /// real accessibility features. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearAccessibilityFeaturesTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearAccessibilityFeaturesTestValue() { - platformDispatcher.clearAccessibilityFeaturesTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.onAccessibilityFeaturesChanged instead. ' @@ -1984,7 +1860,7 @@ class TestWindow implements SingletonFlutterWindow { /// [PlatformDispatcher] values are reported again. /// /// If desired, clearing of properties can be done on an individual basis, - /// e.g., [clearLocaleTestValue]. + /// e.g., [clearDevicePixelRatioTestValue]. @Deprecated( 'Use WidgetTester.platformDispatcher.clearAllTestValues() and WidgetTester.view.reset() instead. ' 'Deprecated to prepare for the upcoming multi-window support. ' diff --git a/packages/flutter_test/test/window_test.dart b/packages/flutter_test/test/window_test.dart index 144890c744093..3bcafbbf7c2b9 100644 --- a/packages/flutter_test/test/window_test.dart +++ b/packages/flutter_test/test/window_test.dart @@ -8,7 +8,7 @@ import 'dart:ui' as ui show window; import 'dart:ui'; -import 'package:flutter/widgets.dart' show WidgetsBinding, WidgetsBindingObserver; +import 'package:flutter/widgets.dart' show WidgetsBinding; import 'package:flutter_test/flutter_test.dart'; import 'utils/fake_and_mock_utils.dart'; @@ -83,34 +83,6 @@ void main() { ); }); - testWidgets('TestWindow can fake locale', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: ui.window.locale, - fakeValue: const Locale('fake_language_code'), - propertyRetriever: () { - return WidgetsBinding.instance.window.locale; - }, - propertyFaker: (TestWidgetsFlutterBinding binding, Locale fakeValue) { - binding.window.localeTestValue = fakeValue; - }, - ); - }); - - testWidgets('TestWindow can fake locales', (WidgetTester tester) async { - verifyPropertyFaked>( - tester: tester, - realValue: ui.window.locales, - fakeValue: [const Locale('fake_language_code')], - propertyRetriever: () { - return WidgetsBinding.instance.window.locales; - }, - propertyFaker: (TestWidgetsFlutterBinding binding, List fakeValue) { - binding.window.localesTestValue = fakeValue; - }, - ); - }); - testWidgets('TestWindow can fake text scale factor', (WidgetTester tester) async { verifyPropertyFaked( tester: tester, @@ -125,60 +97,6 @@ void main() { ); }); - testWidgets('TestWindow can fake clock format', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: ui.window.alwaysUse24HourFormat, - fakeValue: !ui.window.alwaysUse24HourFormat, - propertyRetriever: () { - return WidgetsBinding.instance.window.alwaysUse24HourFormat; - }, - propertyFaker: (TestWidgetsFlutterBinding binding, bool fakeValue) { - binding.window.alwaysUse24HourFormatTestValue = fakeValue; - }, - ); - }); - - testWidgets('TestWindow can fake brieflyShowPassword', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: ui.window.brieflyShowPassword, - fakeValue: !ui.window.brieflyShowPassword, - propertyRetriever: () => WidgetsBinding.instance.window.brieflyShowPassword, - propertyFaker: (TestWidgetsFlutterBinding binding, bool fakeValue) { - binding.window.brieflyShowPasswordTestValue = fakeValue; - }, - ); - }); - - testWidgets('TestWindow can fake default route name', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: ui.window.defaultRouteName, - fakeValue: 'fake_route', - propertyRetriever: () { - return WidgetsBinding.instance.window.defaultRouteName; - }, - propertyFaker: (TestWidgetsFlutterBinding binding, String fakeValue) { - binding.window.defaultRouteNameTestValue = fakeValue; - }, - ); - }); - - testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async { - verifyPropertyFaked( - tester: tester, - realValue: ui.window.accessibilityFeatures, - fakeValue: const FakeAccessibilityFeatures(), - propertyRetriever: () { - return WidgetsBinding.instance.window.accessibilityFeatures; - }, - propertyFaker: (TestWidgetsFlutterBinding binding, AccessibilityFeatures fakeValue) { - binding.window.accessibilityFeaturesTestValue = fakeValue; - }, - ); - }); - testWidgets('TestWindow can fake platform brightness', (WidgetTester tester) async { verifyPropertyFaked( tester: tester, @@ -210,16 +128,6 @@ void main() { expect(WidgetsBinding.instance.window.textScaleFactor, originalTextScaleFactor); }); - testWidgets('TestWindow sends fake locales when WidgetsBindingObserver notifiers are called', (WidgetTester tester) async { - final List defaultLocales = WidgetsBinding.instance.window.locales; - final TestObserver observer = TestObserver(); - retrieveTestBinding(tester).addObserver(observer); - final List expectedValue = [const Locale('fake_language_code')]; - retrieveTestBinding(tester).window.localesTestValue = expectedValue; - expect(observer.locales, equals(expectedValue)); - retrieveTestBinding(tester).window.localesTestValue = defaultLocales; - }); - testWidgets('Updates to window also update tester.view', (WidgetTester tester) async { tester.binding.window.devicePixelRatioTestValue = 7; tester.binding.window.displayFeaturesTestValue = [const DisplayFeature(bounds: Rect.fromLTWH(0, 0, 20, 300), type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)]; @@ -240,12 +148,3 @@ void main() { expect(tester.binding.window.gestureSettings, tester.view.gestureSettings); }); } - -class TestObserver with WidgetsBindingObserver { - List? locales; - - @override - void didChangeLocales(List? locales) { - this.locales = locales; - } -} From 9e59a68c98c44e49c216d307c66d5251978657ab Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Wed, 23 Aug 2023 11:31:06 -0700 Subject: [PATCH 0861/1547] [flutter_tools] Fix legacy version file not being ensured (#133097) Fixes https://github.com/flutter/flutter/issues/133093 When I introduced the new, more robust version file `//flutter/bin/cache/version.json` in https://github.com/flutter/flutter/pull/124558, I changed `class FlutterVersion` into an abstract interface, implemented by `_FlutterVersionFromGit` (which is essentially the previous behavior) and `_FlutterVersionFromFile`, which merely reads the data it would have computed via git from `//flutter/bin/cache/version.json`. While doing this, I made `_FlutterVersionFromGit.ensureVersionFile()` to be a no-op, since I assumed this would not be necessary since we already had a version file in the cache. However, this method was what was previously responsible for ensuring `//flutter/version` existed on disk. This means that if, for whatever reason, the user had `//flutter/bin/cache/flutter.version.json` present but NOT `//flutter/version`, the tool would have never created that file, and they would hit the tool crash seen in https://github.com/flutter/flutter/issues/133093. This fixes the tool by ensuring `//flutter/version` exists regardless of if we're hydrating `FlutterVersion` from `//flutter/bin/cache/flutter.version.json` or not. --- packages/flutter_tools/lib/src/version.dart | 28 +++++++++++--- .../test/general.shard/version_test.dart | 37 +++++++++++++++++++ 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index e3b66ffd94e54..0debc4482a876 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -532,7 +532,13 @@ class _FlutterVersionFromFile extends FlutterVersion { final String devToolsVersion; @override - void ensureVersionFile() {} + void ensureVersionFile() { + _ensureLegacyVersionFile( + fs: fs, + flutterRoot: flutterRoot, + frameworkVersion: frameworkVersion, + ); + } } class _FlutterVersionGit extends FlutterVersion { @@ -599,10 +605,11 @@ class _FlutterVersionGit extends FlutterVersion { @override void ensureVersionFile() { - final File legacyVersionFile = fs.file(fs.path.join(flutterRoot, 'version')); - if (!legacyVersionFile.existsSync()) { - legacyVersionFile.writeAsStringSync(frameworkVersion); - } + _ensureLegacyVersionFile( + fs: fs, + flutterRoot: flutterRoot, + frameworkVersion: frameworkVersion, + ); const JsonEncoder encoder = JsonEncoder.withIndent(' '); final File newVersionFile = FlutterVersion.getVersionFile(fs, flutterRoot); @@ -612,6 +619,17 @@ class _FlutterVersionGit extends FlutterVersion { } } +void _ensureLegacyVersionFile({ + required FileSystem fs, + required String flutterRoot, + required String frameworkVersion, +}) { + final File legacyVersionFile = fs.file(fs.path.join(flutterRoot, 'version')); + if (!legacyVersionFile.existsSync()) { + legacyVersionFile.writeAsStringSync(frameworkVersion); + } +} + /// Checks if the provided [version] is tracking a standard remote. /// /// A "standard remote" is one having the same url as(in order of precedence): diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index 0d82dedc5b032..7a0b182402e13 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -554,6 +554,43 @@ void main() { Cache: () => cache, }); + testUsingContext('_FlutterVersionFromFile.ensureVersionFile ensures legacy version file exists', () async { + final MemoryFileSystem fs = MemoryFileSystem.test(); + final Directory flutterRoot = fs.directory('/path/to/flutter'); + final Directory cacheDir = flutterRoot + .childDirectory('bin') + .childDirectory('cache') + ..createSync(recursive: true); + const String devToolsVersion = '0000000'; + final File legacyVersionFile = flutterRoot.childFile('version'); + const Map versionJson = { + 'channel': 'stable', + 'frameworkVersion': '1.2.3', + 'repositoryUrl': 'https://github.com/flutter/flutter.git', + 'frameworkRevision': '1234abcd', + 'frameworkCommitDate': '2023-04-28 12:34:56 -0400', + 'engineRevision': 'deadbeef', + 'dartSdkVersion': 'deadbeef2', + 'devToolsVersion': devToolsVersion, + 'flutterVersion': 'foo', + }; + cacheDir.childFile('flutter.version.json').writeAsStringSync( + jsonEncode(versionJson), + ); + expect(legacyVersionFile.existsSync(), isFalse); + final FlutterVersion flutterVersion = FlutterVersion( + clock: _testClock, + fs: fs, + flutterRoot: flutterRoot.path, + ); + flutterVersion.ensureVersionFile(); + expect(legacyVersionFile.existsSync(), isTrue); + expect(legacyVersionFile.readAsStringSync(), '1.2.3'); + }, overrides: { + ProcessManager: () => processManager, + Cache: () => cache, + }); + testUsingContext('FlutterVersion() falls back to git if .version.json is malformed', () async { final MemoryFileSystem fs = MemoryFileSystem.test(); final Directory flutterRoot = fs.directory(fs.path.join('path', 'to', 'flutter')); From 6fd338797773c4d8dfd4d7242d9d011c36c579dc Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Wed, 23 Aug 2023 12:38:32 -0700 Subject: [PATCH 0862/1547] Bump memory usage in gradle for platform views (#133155) fixes #133119 Similar to https://github.com/flutter/flutter/issues/131006 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. From 49306139990226aa0bb871b7a40a73bf93cbf3dd Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Wed, 23 Aug 2023 14:11:51 -0700 Subject: [PATCH 0863/1547] Add android analyzer commands for applinks (#131009) Since applink validation tool is going to be a static tool, It won't have access to vmservices. [flutter.dev/go/static-tooling-in-devtools](http://flutter.dev/go/static-tooling-in-devtools) I remove the vm services and also update the deeplink task to also include path pattern and custom scheme http://go/android-applink-apis (internal only) --- .../lib/src/commands/analyze.dart | 73 +++++++++- .../lib/src/commands/android_analyze.dart | 56 ++++++++ .../hermetic/android_analyze_test.dart | 129 ++++++++++++++++++ 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 packages/flutter_tools/lib/src/commands/android_analyze.dart create mode 100644 packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart index 2c1c63798bf3c..dff347f7cbacf 100644 --- a/packages/flutter_tools/lib/src/commands/analyze.dart +++ b/packages/flutter_tools/lib/src/commands/analyze.dart @@ -16,6 +16,7 @@ import '../runner/flutter_command.dart'; import 'analyze_base.dart'; import 'analyze_continuously.dart'; import 'analyze_once.dart'; +import 'android_analyze.dart'; import 'validate_project.dart'; class AnalyzeCommand extends FlutterCommand { @@ -99,6 +100,37 @@ class AnalyzeCommand extends FlutterCommand { argParser.addFlag('fatal-warnings', help: 'Treat warning level issues as fatal.', defaultsTo: true); + + argParser.addFlag('android', + negatable: false, + help: 'Analyze Android sub-project. Used by internal tools only.', + hide: !verboseHelp, + ); + + if (verboseHelp) { + argParser.addSeparator('Usage: flutter analyze --android [arguments]'); + } + + argParser.addFlag('list-build-variants', + negatable: false, + help: 'Print out a list of available build variants for the ' + 'Android sub-project.', + hide: !verboseHelp, + ); + + argParser.addFlag('output-app-link-settings', + negatable: false, + help: 'Output a JSON with Android app link settings into a file. ' + 'The "--build-variant" must also be set.', + hide: !verboseHelp, + ); + + argParser.addOption('build-variant', + help: 'Sets the Android build variant to be analyzed.', + valueHelp: 'use "flutter analyze --android --list-build-variants" to get ' + 'all available build variants', + hide: !verboseHelp, + ); } /// The working directory for testing analysis using dartanalyzer. @@ -142,12 +174,51 @@ class AnalyzeCommand extends FlutterCommand { return false; } + // Don't run pub if asking for android analysis. + if (boolArg('android')) { + return false; + } + return super.shouldRunPub; } @override Future runCommand() async { - if (boolArg('suggestions')) { + if (boolArg('android')) { + final AndroidAnalyzeOption option; + final String? buildVariant; + if (argResults!['list-build-variants'] as bool && argResults!['output-app-link-settings'] as bool) { + throwToolExit('Only one of "--list-build-variants" or "--output-app-link-settings" can be provided'); + } + if (argResults!['list-build-variants'] as bool) { + option = AndroidAnalyzeOption.listBuildVariant; + buildVariant = null; + } else if (argResults!['output-app-link-settings'] as bool) { + option = AndroidAnalyzeOption.outputAppLinkSettings; + buildVariant = argResults!['build-variant'] as String?; + if (buildVariant == null) { + throwToolExit('"--build-variant" must be provided'); + } + } else { + throwToolExit('No argument is provided to analyze. Use -h to see available commands.'); + } + final Set items = findDirectories(argResults!, _fileSystem); + final String directoryPath; + if (items.isEmpty) { // user did not specify any path + directoryPath = _fileSystem.currentDirectory.path; + } else if (items.length > 1) { // if the user sends more than one path + throwToolExit('The Android analyze can process only one directory path'); + } else { + directoryPath = items.first; + } + await AndroidAnalyze( + fileSystem: _fileSystem, + option: option, + userPath: directoryPath, + buildVariant: buildVariant, + logger: _logger, + ).analyze(); + } else if (boolArg('suggestions')) { final String directoryPath; if (boolArg('watch')) { throwToolExit('flag --watch is not compatible with --suggestions'); diff --git a/packages/flutter_tools/lib/src/commands/android_analyze.dart b/packages/flutter_tools/lib/src/commands/android_analyze.dart new file mode 100644 index 0000000000000..c4389ff41e166 --- /dev/null +++ b/packages/flutter_tools/lib/src/commands/android_analyze.dart @@ -0,0 +1,56 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import '../base/file_system.dart'; +import '../base/logger.dart'; +import '../convert.dart'; +import '../project.dart'; + +/// The type of analysis to perform. +enum AndroidAnalyzeOption { + /// Prints out available build variants of the Android sub-project. + /// + /// An example output: + /// ["debug", "profile", "release"] + listBuildVariant, + + /// Outputs app link settings of the Android sub-project into a file. + /// + /// The file path will be printed after the command is run successfully. + outputAppLinkSettings, +} + +/// Analyze the Android sub-project of a Flutter project. +/// +/// The [userPath] must be point to a flutter project. +class AndroidAnalyze { + AndroidAnalyze({ + required this.fileSystem, + required this.option, + required this.userPath, + this.buildVariant, + required this.logger, + }) : assert(option == AndroidAnalyzeOption.listBuildVariant || buildVariant != null); + + final FileSystem fileSystem; + final AndroidAnalyzeOption option; + final String? buildVariant; + final String userPath; + final Logger logger; + + Future analyze() async { + final FlutterProject project = FlutterProject.fromDirectory(fileSystem.directory(userPath)); + switch (option) { + case AndroidAnalyzeOption.listBuildVariant: + logger.printStatus(jsonEncode(await project.android.getBuildVariants())); + case AndroidAnalyzeOption.outputAppLinkSettings: + assert(buildVariant != null); + await project.android.outputsAppLinkSettings(variant: buildVariant!); + final String filePath = fileSystem.path.join(project.directory.path, 'build', 'app', 'app-link-settings-$buildVariant.json`'); + logger.printStatus('result saved in $filePath'); + } + } +} diff --git a/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart new file mode 100644 index 0000000000000..44c9c5fa34cd2 --- /dev/null +++ b/packages/flutter_tools/test/commands.shard/hermetic/android_analyze_test.dart @@ -0,0 +1,129 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:args/command_runner.dart'; +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/android/android_builder.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/cache.dart'; +import 'package:flutter_tools/src/commands/analyze.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/project_validator.dart'; +import 'package:test/fake.dart'; + +import '../../src/context.dart'; +import '../../src/test_flutter_command_runner.dart'; + +void main() { + + group('Android analyze command', () { + late FileSystem fileSystem; + late Platform platform; + late BufferLogger logger; + late FakeProcessManager processManager; + late Terminal terminal; + late AnalyzeCommand command; + late CommandRunner runner; + late Directory tempDir; + late FakeAndroidBuilder builder; + + setUpAll(() { + Cache.disableLocking(); + }); + + setUp(() async { + fileSystem = MemoryFileSystem.test(); + platform = FakePlatform(); + logger = BufferLogger.test(); + processManager = FakeProcessManager.empty(); + terminal = Terminal.test(); + command = AnalyzeCommand( + artifacts: Artifacts.test(), + fileSystem: fileSystem, + logger: logger, + platform: platform, + processManager: processManager, + terminal: terminal, + allProjectValidators: [], + suppressAnalytics: true, + ); + runner = createTestCommandRunner(command); + tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); + tempDir.childDirectory('android').createSync(); + + // Setup repo roots + const String homePath = '/home/user/flutter'; + Cache.flutterRoot = homePath; + for (final String dir in ['dev', 'examples', 'packages']) { + fileSystem.directory(homePath).childDirectory(dir).createSync(recursive: true); + } + builder = FakeAndroidBuilder(); + + }); + + testUsingContext('can list build variants', () async { + builder.variants = ['debug', 'release']; + await runner.run(['analyze', '--android', '--list-build-variants', tempDir.path]); + expect(logger.statusText, contains('["debug","release"]')); + }, overrides: { + AndroidBuilder: () => builder, + }); + + testUsingContext('throw if provide multiple path', () async { + final Directory anotherTempDir = fileSystem.systemTempDirectory.createTempSync('another'); + await expectLater( + runner.run(['analyze', '--android', '--list-build-variants', tempDir.path, anotherTempDir.path]), + throwsA( + isA().having( + (Exception e) => e.toString(), + 'description', + contains('The Android analyze can process only one directory path'), + ), + ), + ); + }); + + testUsingContext('can output app link settings', () async { + const String buildVariant = 'release'; + await runner.run(['analyze', '--android', '--output-app-link-settings', '--build-variant=$buildVariant', tempDir.path]); + expect(builder.outputVariant, buildVariant); + }, overrides: { + AndroidBuilder: () => builder, + }); + + testUsingContext('output app link settings throws if no build variant', () async { + await expectLater( + runner.run(['analyze', '--android', '--output-app-link-settings', tempDir.path]), + throwsA( + isA().having( + (Exception e) => e.toString(), + 'description', + contains('"--build-variant" must be provided'), + ), + ), + ); + }); + }); +} + +class FakeAndroidBuilder extends Fake implements AndroidBuilder { + List variants = const []; + String? outputVariant; + + @override + Future> getBuildVariants({required FlutterProject project}) async { + return variants; + } + + @override + Future outputsAppLinkSettings(String buildVariant, {required FlutterProject project}) async { + outputVariant = buildVariant; + } +} From 382ceb570703c81f5e8ced5d96fec7d2595cef0a Mon Sep 17 00:00:00 2001 From: Michael Goderbauer Date: Wed, 23 Aug 2023 14:35:54 -0700 Subject: [PATCH 0864/1547] Enable literal_only_boolean_expressions (#133186) Blocking issue (https://github.com/dart-lang/linter/issues/453) for this lint has been resolved. --- analysis_options.yaml | 2 +- .../lib/src/material/calendar_date_picker.dart | 5 +---- .../flutter/lib/src/material/date_picker.dart | 15 ++++----------- packages/flutter/lib/src/rendering/viewport.dart | 4 ++-- .../lib/src/runner/flutter_command.dart | 2 +- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a9d29631e12eb..4da1e9f1fb3a8 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -116,7 +116,7 @@ linter: - library_prefixes - library_private_types_in_public_api # - lines_longer_than_80_chars # not required by flutter style - # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 + - literal_only_boolean_expressions # - matching_super_parameters # blocked on https://github.com/dart-lang/language/issues/2509 - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 878439b61b09e..2a3e842dddb6a 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -915,14 +915,11 @@ class _DayPickerState extends State<_DayPicker> { /// List _dayHeaders(TextStyle? headerStyle, MaterialLocalizations localizations) { final List result = []; - for (int i = localizations.firstDayOfWeekIndex; true; i = (i + 1) % 7) { + for (int i = localizations.firstDayOfWeekIndex; result.length < DateTime.daysPerWeek; i = (i + 1) % DateTime.daysPerWeek) { final String weekday = localizations.narrowWeekdays[i]; result.add(ExcludeSemantics( child: Center(child: Text(weekday, style: headerStyle)), )); - if (i == (localizations.firstDayOfWeekIndex - 1) % 7) { - break; - } } return result; } diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index d5d2e1d0d0a5d..ea585561f5cb7 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -2093,14 +2093,11 @@ class _DayHeaders extends StatelessWidget { /// List _getDayHeaders(TextStyle headerStyle, MaterialLocalizations localizations) { final List result = []; - for (int i = localizations.firstDayOfWeekIndex; true; i = (i + 1) % 7) { + for (int i = localizations.firstDayOfWeekIndex; result.length < DateTime.daysPerWeek; i = (i + 1) % DateTime.daysPerWeek) { final String weekday = localizations.narrowWeekdays[i]; result.add(ExcludeSemantics( child: Center(child: Text(weekday, style: headerStyle)), )); - if (i == (localizations.firstDayOfWeekIndex - 1) % 7) { - break; - } } return result; } @@ -2512,13 +2509,9 @@ class _MonthItemState extends State<_MonthItem> { final double gridHeight = weeks * _monthItemRowHeight + (weeks - 1) * _monthItemSpaceBetweenRows; final List dayItems = []; - for (int i = 0; true; i += 1) { - // 1-based day of month, e.g. 1-31 for January, and 1-29 for February on - // a leap year. - final int day = i - dayOffset + 1; - if (day > daysInMonth) { - break; - } + // 1-based day of month, e.g. 1-31 for January, and 1-29 for February on + // a leap year. + for (int day = 0 - dayOffset + 1; day <= daysInMonth; day += 1) { if (day < 1) { dayItems.add(Container()); } else { diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index 44876d8326e54..66560c8521f48 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -1830,7 +1830,7 @@ class RenderShrinkWrappingViewport extends RenderViewportBase { } ddsEnabled = !boolArg('disable-dds'); // TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart) - if (false) { // ignore: dead_code + if (false) { // ignore: dead_code, literal_only_boolean_expressions if (ddsEnabled) { globals.printWarning('${globals.logger.terminal .warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.'); From 89907f6da3229e5e41df359c58202b32f7aefadc Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 23 Aug 2023 15:55:28 -0700 Subject: [PATCH 0865/1547] Enable ChangeNotifier clients to dispatch event of object creation in constructor. (#133060) --- .../lib/src/foundation/change_notifier.dart | 51 ++++++++++++++----- .../flutter/lib/src/widgets/shortcuts.dart | 7 +++ .../lib/src/widgets/snapshot_widget.dart | 4 ++ .../flutter/test/widgets/shortcuts_test.dart | 16 ++++++ 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/packages/flutter/lib/src/foundation/change_notifier.dart b/packages/flutter/lib/src/foundation/change_notifier.dart index 0b8c6f4ae9d85..d8ab7d5720e43 100644 --- a/packages/flutter/lib/src/foundation/change_notifier.dart +++ b/packages/flutter/lib/src/foundation/change_notifier.dart @@ -207,6 +207,39 @@ mixin class ChangeNotifier implements Listenable { @protected bool get hasListeners => _count > 0; + /// Dispatches event of object creation to [MemoryAllocations.instance]. + /// + /// If the event was already dispatched or [kFlutterMemoryAllocationsEnabled] + /// is false, the method is noop. + /// + /// Tools like leak_tracker use the event of object creation to help + /// developers identify the owner of the object, for troubleshooting purposes, + /// by taking stack trace at the moment of the event. + /// + /// But, as [ChangeNotifier] is mixin, it does not have its own constructor. So, it + /// communicates object creation in first `addListener`, that results + /// in the stack trace pointing to `addListener`, not to constructor. + /// + /// To make debugging easier, invoke [ChangeNotifier.maybeDispatchObjectCreation] + /// in constructor of the class. It will help + /// to identify the owner. + /// + /// Make sure to invoke it with condition `if (kFlutterMemoryAllocationsEnabled) ...` + /// so that the method is tree-shaken away when the flag is false. + @protected + void maybeDispatchObjectCreation() { + // Tree shaker does not include this method and the class MemoryAllocations + // if kFlutterMemoryAllocationsEnabled is false. + if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) { + MemoryAllocations.instance.dispatchObjectCreated( + library: _flutterFoundationLibrary, + className: '$ChangeNotifier', + object: this, + ); + _creationDispatched = true; + } + } + /// Register a closure to be called when the object changes. /// /// If the given closure is already registered, an additional instance is @@ -236,14 +269,11 @@ mixin class ChangeNotifier implements Listenable { @override void addListener(VoidCallback listener) { assert(ChangeNotifier.debugAssertNotDisposed(this)); - if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) { - MemoryAllocations.instance.dispatchObjectCreated( - library: _flutterFoundationLibrary, - className: '$ChangeNotifier', - object: this, - ); - _creationDispatched = true; + + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); } + if (_count == _listeners.length) { if (_count == 0) { _listeners = List.filled(1, null); @@ -505,13 +535,8 @@ class ValueNotifier extends ChangeNotifier implements ValueListenable { /// Creates a [ChangeNotifier] that wraps this value. ValueNotifier(this._value) { if (kFlutterMemoryAllocationsEnabled) { - MemoryAllocations.instance.dispatchObjectCreated( - library: _flutterFoundationLibrary, - className: '$ValueNotifier', - object: this, - ); + maybeDispatchObjectCreation(); } - _creationDispatched = true; } /// The current value stored in this notifier. diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 5bc3879de8dd2..5c66c42997205 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -1196,6 +1196,13 @@ class ShortcutRegistryEntry { /// widgets that are not descendants of the registry can listen to it (e.g. in /// overlays). class ShortcutRegistry with ChangeNotifier { + /// Creates an instance of [ShortcutRegistry]. + ShortcutRegistry() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + bool _notificationScheduled = false; bool _disposed = false; diff --git a/packages/flutter/lib/src/widgets/snapshot_widget.dart b/packages/flutter/lib/src/widgets/snapshot_widget.dart index 854512f1f4528..7d509ce28ba72 100644 --- a/packages/flutter/lib/src/widgets/snapshot_widget.dart +++ b/packages/flutter/lib/src/widgets/snapshot_widget.dart @@ -482,4 +482,8 @@ class _DefaultSnapshotPainter implements SnapshotPainter { @override bool shouldRepaint(covariant _DefaultSnapshotPainter oldPainter) => false; + + @override + @protected + void maybeDispatchObjectCreation() { } } diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index 0481f8cd6b585..064fdfb231e16 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -1852,6 +1852,22 @@ void main() { }, throwsAssertionError); token.dispose(); }); + + testWidgets('dispatches object creation in constructor', (WidgetTester tester) async { + final MemoryAllocations ma = MemoryAllocations.instance; + assert(!ma.hasListeners); + int eventCount = 0; + void listener(ObjectEvent event) => eventCount++; + ma.addListener(listener); + + final ShortcutRegistry registry = ShortcutRegistry(); + + expect(eventCount, 1); + + registry.dispose(); + ma.removeListener(listener); + assert(!ma.hasListeners); + }); }); } From 8c69fd550c6c63da3ae5a8ce9c38bab1ecf86149 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 23 Aug 2023 18:06:14 -0500 Subject: [PATCH 0866/1547] Remove deprecated MaterialButtonWithIconMixin (#133173) Part of https://github.com/flutter/flutter/issues/133171 --- .../flutter/lib/src/material/button_theme.dart | 4 ---- .../flutter/lib/src/material/material_button.dart | 14 -------------- 2 files changed, 18 deletions(-) diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart index 1406f2deb7672..438d8fc6d01ce 100644 --- a/packages/flutter/lib/src/material/button_theme.dart +++ b/packages/flutter/lib/src/material/button_theme.dart @@ -641,10 +641,6 @@ class ButtonThemeData with Diagnosticable { return button.padding!; } - if (button is MaterialButtonWithIconMixin) { - return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0); - } - if (_padding != null) { return _padding!; } diff --git a/packages/flutter/lib/src/material/material_button.dart b/packages/flutter/lib/src/material/material_button.dart index 365f8c5669188..2f3c5cc96ad7c 100644 --- a/packages/flutter/lib/src/material/material_button.dart +++ b/packages/flutter/lib/src/material/material_button.dart @@ -440,17 +440,3 @@ class MaterialButton extends StatelessWidget { properties.add(DiagnosticsProperty('materialTapTargetSize', materialTapTargetSize, defaultValue: null)); } } - -/// The distinguished type of [MaterialButton]. -/// -/// This class is deprecated and will be removed in a future release. -/// -/// This mixin only exists to give the "label and icon" button widgets a distinct -/// type for the sake of [ButtonTheme]. -@Deprecated( - 'This was used to differentiate types of FlatButton, RaisedButton, and OutlineButton in ButtonTheme. ' - 'These buttons have been replaced with TextButton, ElevatedButton, and OutlinedButton, each of which have their own respective themes now. ' - 'Use one of these button classes instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.', -) -mixin MaterialButtonWithIconMixin { } From cfe41a645110fb3e7147762c8d5893f8627663dc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 19:37:56 -0400 Subject: [PATCH 0867/1547] Roll Flutter Engine from 58dc868c26cb to 27d75f6221d2 (14 revisions) (#133211) https://github.com/flutter/engine/compare/58dc868c26cb...27d75f6221d2 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from 76898dad9fda to a631fefdba37 (2 revisions) (flutter/engine#45027) 2023-08-23 zanderso@users.noreply.github.com Revert "FontVariation.lerp, custom FontVariation constructors, and more documentation" (flutter/engine#45023) 2023-08-23 bdero@google.com [Impeller] Dat rvalue reference (fix engine head) (flutter/engine#45024) 2023-08-23 bdero@google.com Revert "Enable clang-tidy for pre-push (opt-out), exclude `performance-unnecessary-value-param`" (flutter/engine#45020) 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from 4e42b51cfe27 to 76898dad9fda (1 revision) (flutter/engine#45019) 2023-08-23 bdero@google.com [Impeller] Add STB text backend. (flutter/engine#44887) 2023-08-23 reidbaker@google.com Followup to https://github.com/flutter/engine/pull/44982 (flutter/engine#45018) 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from 5428f147e632 to 4e42b51cfe27 (4 revisions) (flutter/engine#45016) 2023-08-23 reidbaker@google.com Eliminate android test log spam (flutter/engine#44982) 2023-08-23 mdebbar@google.com [web] Remove some unused functions (flutter/engine#44505) 2023-08-23 lhkbob@gmail.com Use decal TileMode in blur image_filter_test.dart (flutter/engine#45004) 2023-08-23 ian@hixie.ch FontVariation.lerp, custom FontVariation constructors, and more documentation (flutter/engine#44996) 2023-08-23 jonahwilliams@google.com [impeller] combine sampler and texture maps. (flutter/engine#44990) 2023-08-23 bdero@google.com [Impeller] Flutter GPU: Add HostBuffer. (flutter/engine#44696) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e921a33d29061..ec8f1e30c76c4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -58dc868c26cb0f7e3751eec903c4c2bb8ea20316 +27d75f6221d2854a991d87b1e52798cb88c5838f From 87c1a461e13ebcfa20e8717ea487f66bb8eb26cc Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 23 Aug 2023 18:52:19 -0500 Subject: [PATCH 0868/1547] Remove deprecated PlatformViewsService.synchronizeToNativeViewHierarchy (#133175) Part of https://github.com/flutter/flutter/issues/133171 --- packages/flutter/lib/src/services/platform_views.dart | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/flutter/lib/src/services/platform_views.dart b/packages/flutter/lib/src/services/platform_views.dart index d5e84543758d2..0375d42747fac 100644 --- a/packages/flutter/lib/src/services/platform_views.dart +++ b/packages/flutter/lib/src/services/platform_views.dart @@ -196,13 +196,6 @@ class PlatformViewsService { return controller; } - /// Whether the render surface of the Android `FlutterView` should be converted to a `FlutterImageView`. - @Deprecated( - 'No longer necessary to improve performance. ' - 'This feature was deprecated after v2.11.0-0.1.pre.', - ) - static Future synchronizeToNativeViewHierarchy(bool yes) async {} - // TODO(amirh): reference the iOS plugin API for registering a UIView factory once it lands. /// This is work in progress, not yet ready to be used, and requires a custom engine build. Creates a controller for a new iOS UIView. /// From dc7fa47324e87a5fb9702c63d21d749c0931f6d3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 20:48:30 -0400 Subject: [PATCH 0869/1547] Roll Flutter Engine from 27d75f6221d2 to 67e8b825cc91 (1 revision) (#133214) https://github.com/flutter/engine/compare/27d75f6221d2...67e8b825cc91 2023-08-23 jonahwilliams@google.com [Impeller] combine uniform metadata and buffer slots. (flutter/engine#45021) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ec8f1e30c76c4..144df63018998 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -27d75f6221d2854a991d87b1e52798cb88c5838f +67e8b825cc91525debc3d70c07229834b1d64a4f From b32cd68f31802e0761526280c98b42d439b373df Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 23 Aug 2023 22:24:03 -0400 Subject: [PATCH 0870/1547] Roll Flutter Engine from 67e8b825cc91 to aa98a9d2e86f (4 revisions) (#133220) https://github.com/flutter/engine/compare/67e8b825cc91...aa98a9d2e86f 2023-08-24 dnfield@google.com [Impeller] Fix stencil buffer format selection on Vulkan backend, add support for D24UnormS8Uint (flutter/engine#45025) 2023-08-24 jason-simmons@users.noreply.github.com Fix a clang-tidy error seen in the latest toolchain roll (flutter/engine#45039) 2023-08-23 skia-flutter-autoroll@skia.org Roll Skia from a631fefdba37 to 9d4db3443527 (1 revision) (flutter/engine#45031) 2023-08-23 zanderso@users.noreply.github.com Roll clang with fix for ABI change (flutter/engine#44711) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 144df63018998..6ed6e4f40df97 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -67e8b825cc91525debc3d70c07229834b1d64a4f +aa98a9d2e86fa3684bac5dd5e8b7b882fea322ae From bede50cba21b176e4de0df3e8351c51b05512027 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 24 Aug 2023 00:49:29 -0400 Subject: [PATCH 0871/1547] Roll Flutter Engine from aa98a9d2e86f to 3b92bb6eda19 (4 revisions) (#133224) https://github.com/flutter/engine/compare/aa98a9d2e86f...3b92bb6eda19 2023-08-24 bdero@google.com [Impeller] Add debug captures and inspector. (flutter/engine#43764) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from e3ee267859a7 to 02eecda395ba (1 revision) (flutter/engine#45042) 2023-08-24 jason-simmons@users.noreply.github.com Remove a clang-tidy test that launches a full run of clang-tidy (flutter/engine#45033) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 9d4db3443527 to e3ee267859a7 (1 revision) (flutter/engine#45036) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6ed6e4f40df97..6fdbec0df98ad 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -aa98a9d2e86fa3684bac5dd5e8b7b882fea322ae +3b92bb6eda19c37b6d574f1a066a56fe1e3bc402 From deeb811ef0bb906a607788837c00136aa9b9072b Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 24 Aug 2023 08:00:37 -0700 Subject: [PATCH 0872/1547] Reverts "Roll Flutter Engine from aa98a9d2e86f to 3b92bb6eda19 (4 revisions) (#133224)" (#133255) Reverts https://github.com/flutter/flutter/pull/133224 Reverting for failing wide gamut test https://ci.chromium.org/ui/p/flutter/builders/prod/Mac_ios%20wide_gamut_ios/3186/overview --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6fdbec0df98ad..6ed6e4f40df97 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3b92bb6eda19c37b6d574f1a066a56fe1e3bc402 +aa98a9d2e86fa3684bac5dd5e8b7b882fea322ae From 9632f821f47f4fc752ed66d2a50265af811096f3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 24 Aug 2023 11:51:49 -0400 Subject: [PATCH 0873/1547] Roll Packages from 3060b1aec99c to 383bffa3991d (3 revisions) (#133256) https://github.com/flutter/packages/compare/3060b1aec99c...383bffa3991d 2023-08-24 joonas.kerttula@codemate.com [google_maps_flutter] cloud-based map styling implementation (flutter/packages#4638) 2023-08-23 stuartmorgan@google.com [image_picker] Fix exception when canceling `pickMultipleMedia` on iOS (flutter/packages#4761) 2023-08-23 engine-flutter-autoroll@skia.org Roll Flutter from 54c98d7433c5 to bd836cc63ae0 (24 revisions) (flutter/packages#4760) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 859dbb657005c..f28b62361fdf5 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -3060b1aec99c54165fde27c1c8a58c553b657447 +383bffa3991d6397eb4a00fb6f7f09f897252143 From 12cf9de68b090c90de016fcfc24c4636180332be Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Thu, 24 Aug 2023 10:03:17 -0700 Subject: [PATCH 0874/1547] Fix mac tool_integration_tests with Xcode 15 (#133217) Fixes https://github.com/flutter/flutter/issues/132990 --- .../test/integration.shard/test_test.dart | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/test/integration.shard/test_test.dart b/packages/flutter_tools/test/integration.shard/test_test.dart index 86e0d11bdc2b3..c48d354c09331 100644 --- a/packages/flutter_tools/test/integration.shard/test_test.dart +++ b/packages/flutter_tools/test/integration.shard/test_test.dart @@ -335,7 +335,10 @@ Future _testFile( reason: '"$testName" returned code ${exec.exitCode}\n\nstdout:\n' '${exec.stdout}\nstderr:\n${exec.stderr}', ); - final List output = (exec.stdout as String).split('\n'); + List output = (exec.stdout as String).split('\n'); + + output = _removeMacFontServerWarning(output); + if (output.first.startsWith('Waiting for another flutter command to release the startup lock...')) { output.removeAt(0); } @@ -398,6 +401,26 @@ Future _testFile( } } +final RegExp _fontServerProtocolPattern = RegExp(r'flutter_tester.*Font server protocol version mismatch'); +final RegExp _unableToConnectToFontDaemonPattern = RegExp(r'flutter_tester.*XType: unable to make a connection to the font daemon!'); +final RegExp _xtFontStaticRegistryPattern = RegExp(r'flutter_tester.*XType: XTFontStaticRegistry is enabled as fontd is not available'); + +// https://github.com/flutter/flutter/issues/132990 +List _removeMacFontServerWarning(List output) { + return output.where((String line) { + if (_fontServerProtocolPattern.hasMatch(line)) { + return false; + } + if (_unableToConnectToFontDaemonPattern.hasMatch(line)) { + return false; + } + if (_xtFontStaticRegistryPattern.hasMatch(line)) { + return false; + } + return true; + }).toList(); +} + Future _runFlutterTest( String? testName, String workingDirectory, From e1967ecabf014bf93d1731fde6a6547b06ca9c33 Mon Sep 17 00:00:00 2001 From: Andrew Kolos Date: Thu, 24 Aug 2023 10:36:19 -0700 Subject: [PATCH 0875/1547] handle exceptions raised while searching for configured android studio (#133180) Fixes #133055 --- .../lib/src/android/android_studio.dart | 63 ++++++++++++------- .../android/android_studio_test.dart | 45 +++++++++++++ 2 files changed, 87 insertions(+), 21 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/android_studio.dart b/packages/flutter_tools/lib/src/android/android_studio.dart index f83fdd2463c04..72d987583bdfe 100644 --- a/packages/flutter_tools/lib/src/android/android_studio.dart +++ b/packages/flutter_tools/lib/src/android/android_studio.dart @@ -236,16 +236,7 @@ class AndroidStudio { /// Android Studio found at that location is always returned, even if it is /// invalid. static AndroidStudio? latestValid() { - final String? configuredStudioPath = globals.config.getValue('android-studio-dir') as String?; - if (configuredStudioPath != null && !globals.fs.directory(configuredStudioPath).existsSync()) { - throwToolExit(''' -Could not find the Android Studio installation at the manually configured path "$configuredStudioPath". -Please verify that the path is correct and update it by running this command: flutter config --android-studio-dir '' - -To have flutter search for Android Studio installations automatically, remove -the configured path by running this command: flutter config --android-studio-dir '' -'''); - } + final Directory? configuredStudioDir = _configuredDir(); // Find all available Studio installations. final List studios = allInstalled(); @@ -255,8 +246,8 @@ the configured path by running this command: flutter config --android-studio-dir final AndroidStudio? manuallyConfigured = studios .where((AndroidStudio studio) => studio.configuredPath != null && - configuredStudioPath != null && - _pathsAreEqual(studio.configuredPath!, configuredStudioPath)) + configuredStudioDir != null && + _pathsAreEqual(studio.configuredPath!, configuredStudioDir.path)) .firstOrNull; if (manuallyConfigured != null) { @@ -323,16 +314,14 @@ the configured path by running this command: flutter config --android-studio-dir )); } - final String? configuredStudioDir = globals.config.getValue('android-studio-dir') as String?; - FileSystemEntity? configuredStudioDirAsEntity; + Directory? configuredStudioDir = _configuredDir(); if (configuredStudioDir != null) { - configuredStudioDirAsEntity = globals.fs.directory(configuredStudioDir); - if (configuredStudioDirAsEntity.basename == 'Contents') { - configuredStudioDirAsEntity = configuredStudioDirAsEntity.parent; + if (configuredStudioDir.basename == 'Contents') { + configuredStudioDir = configuredStudioDir.parent; } if (!candidatePaths - .any((FileSystemEntity e) => _pathsAreEqual(e.path, configuredStudioDirAsEntity!.path))) { - candidatePaths.add(configuredStudioDirAsEntity); + .any((FileSystemEntity e) => _pathsAreEqual(e.path, configuredStudioDir!.path))) { + candidatePaths.add(configuredStudioDir); } } @@ -357,13 +346,13 @@ the configured path by running this command: flutter config --android-studio-dir return candidatePaths .map((FileSystemEntity e) { - if (configuredStudioDirAsEntity == null) { + if (configuredStudioDir == null) { return AndroidStudio.fromMacOSBundle(e.path); } return AndroidStudio.fromMacOSBundle( e.path, - configuredPath: _pathsAreEqual(configuredStudioDirAsEntity.path, e.path) ? configuredStudioDir : null, + configuredPath: _pathsAreEqual(configuredStudioDir.path, e.path) ? configuredStudioDir.path : null, ); }) .whereType() @@ -493,6 +482,38 @@ the configured path by running this command: flutter config --android-studio-dir return studios; } + /// Gets the Android Studio install directory set by the user, if it is configured. + /// + /// The returned [Directory], if not null, is guaranteed to have existed during + /// this function's execution. + static Directory? _configuredDir() { + final String? configuredPath = globals.config.getValue('android-studio-dir') as String?; + if (configuredPath == null) { + return null; + } + final Directory result = globals.fs.directory(configuredPath); + + bool? configuredStudioPathExists; + String? exceptionMessage; + try { + configuredStudioPathExists = result.existsSync(); + } on FileSystemException catch (e) { + exceptionMessage = e.toString(); + } + + if (configuredStudioPathExists == false || exceptionMessage != null) { + throwToolExit(''' +Could not find the Android Studio installation at the manually configured path "$configuredPath". +${exceptionMessage == null ? '' : 'Encountered exception: $exceptionMessage\n\n'} +Please verify that the path is correct and update it by running this command: flutter config --android-studio-dir '' +To have flutter search for Android Studio installations automatically, remove +the configured path by running this command: flutter config --android-studio-dir +'''); + } + + return result; + } + static String? extractStudioPlistValueWithMatcher(String plistValue, RegExp keyMatcher) { return keyMatcher.stringMatch(plistValue)?.split('=').last.trim().replaceAll('"', ''); } diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart index ee018bcc363ed..cc8d8c2f36481 100644 --- a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart @@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/ios/plist_parser.dart'; +import 'package:path/path.dart' show Context; // flutter_ignore: package_path_import -- We only use Context as an interface. import 'package:test/fake.dart'; import '../../src/common.dart'; @@ -1287,6 +1288,20 @@ void main() { Platform: () => platform, ProcessManager: () => FakeProcessManager.any(), }); + + testUsingContext('handles file system exception when checking for explicitly configured Android Studio install', () { + const String androidStudioDir = '/Users/Dash/Desktop/android-studio'; + config.setValue('android-studio-dir', androidStudioDir); + + expect(() => AndroidStudio.latestValid(), + throwsToolExit(message: RegExp(r'[.\s\S]*Could not find[.\s\S]*FileSystemException[.\s\S]*'))); + }, overrides: { + Config: () => config, + Platform: () => platform, + FileSystem: () => _FakeFileSystem(), + FileSystemUtils: () => _FakeFsUtils(), + ProcessManager: () => FakeProcessManager.any(), + }); }); } @@ -1298,3 +1313,33 @@ class FakePlistUtils extends Fake implements PlistParser { return fileContents[plistFilePath]!; } } + +class _FakeFileSystem extends Fake implements FileSystem { + @override + Directory directory(dynamic path) { + return _NonExistentDirectory(); + } + + @override + Context get path { + return MemoryFileSystem.test().path; + } +} + +class _NonExistentDirectory extends Fake implements Directory { + @override + bool existsSync() { + throw const FileSystemException('OS Error: Filename, directory name, or volume label syntax is incorrect.'); + } + + @override + String get path => ''; + + @override + Directory get parent => _NonExistentDirectory(); +} + +class _FakeFsUtils extends Fake implements FileSystemUtils { + @override + String get homeDirPath => '/home/'; +} From 74ccd1d50c6674e941311468b31f2d226507b8e9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 24 Aug 2023 15:28:31 -0400 Subject: [PATCH 0876/1547] Roll Flutter Engine from aa98a9d2e86f to 965501a25d92 (24 revisions) (#133272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/flutter/engine/compare/aa98a9d2e86f...965501a25d92 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 8b0fd320865e to b17ee34f3378 (1 revision) (flutter/engine#45073) 2023-08-24 zanderso@users.noreply.github.com Revert Dart SDK to 3.2.0-97.0.dev (flutter/engine#45072) 2023-08-24 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 87a5a26b25fc to bcad589d5d81 (4 revisions) (flutter/engine#45065) 2023-08-24 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from P8oeVw3whCGS6pCjL... to jkVyhV_xfb8Mv43xj... (flutter/engine#45068) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from e008ee76b890 to 8b0fd320865e (3 revisions) (flutter/engine#45067) 2023-08-24 whesse@google.com Remove package linter from DEPS (flutter/engine#45053) 2023-08-24 zanderso@users.noreply.github.com Revert "[Impeller] Add debug captures and inspector." (flutter/engine#45062) 2023-08-24 jonahwilliams@google.com [Impeller] Don't place vertex buffer bindings in the Binding map. (flutter/engine#45040) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 994d5e03fa1c to e008ee76b890 (1 revision) (flutter/engine#45061) 2023-08-24 jonahwilliams@google.com Revert "[Impeller] add trace events for VkRenderPass and VkFrameBuffe… (flutter/engine#45047) 2023-08-24 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from XoUnFqSvX9mhbXqBJ... to 0kEa4JczTMD0Xus08... (flutter/engine#45060) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 68700a1a2be9 to 994d5e03fa1c (1 revision) (flutter/engine#45059) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 13a050278b1a to 68700a1a2be9 (1 revision) (flutter/engine#45058) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 317f4c2ba2ca to 13a050278b1a (1 revision) (flutter/engine#45054) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 17c0f4b72fcd to 317f4c2ba2ca (1 revision) (flutter/engine#45051) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 82472773892d to 17c0f4b72fcd (1 revision) (flutter/engine#45050) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 02eecda395ba to 82472773892d (1 revision) (flutter/engine#45049) 2023-08-24 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from vJ6oaubpqgRM2nb1e... to P8oeVw3whCGS6pCjL... (flutter/engine#45046) 2023-08-24 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from -HcyJtxGxUDcqX-jo... to XoUnFqSvX9mhbXqBJ... (flutter/engine#45044) 2023-08-24 skia-flutter-autoroll@skia.org Manual roll Dart SDK from ab417bc74bb1 to 87a5a26b25fc (4 revisions) (flutter/engine#45043) 2023-08-24 bdero@google.com [Impeller] Add debug captures and inspector. (flutter/engine#43764) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from e3ee267859a7 to 02eecda395ba (1 revision) (flutter/engine#45042) 2023-08-24 jason-simmons@users.noreply.github.com Remove a clang-tidy test that launches a full run of clang-tidy (flutter/engine#45033) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 9d4db3443527 to e3ee267859a7 (1 revision) (flutter/engine#45036) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from -HcyJtxGxUDc to 0kEa4JczTMD0 fuchsia/sdk/core/mac-amd64 from vJ6oaubpqgRM to jkVyhV_xfb8M If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6ed6e4f40df97..698b0e4c00ebc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -aa98a9d2e86fa3684bac5dd5e8b7b882fea322ae +965501a25d9216701c43332a55e577d78bf7658d diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index bafb73151ffbb..8b798535fb735 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ --HcyJtxGxUDcqX-joRgopminL0PbfzDP9E1TMp9xBSgC +0kEa4JczTMD0Xus08aFASyutpbphg0hMC0EqbOwjcRUC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 68e5570621118..56081abc93e99 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -vJ6oaubpqgRM2nb1e_i0xzq5u59ChjEAmndn9yPIFiUC +jkVyhV_xfb8Mv43xjXG7mCqcFhF4nOLIt-09DcU4YP4C From b4f4ece40d956ad86efa340ff7fe9d0fa6deea07 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 24 Aug 2023 12:38:27 -0700 Subject: [PATCH 0877/1547] Remove `ImageProvider.load`, `DecoderCallback` and `PaintingBinding.instantiateImageCodec` (#132679) ~The failing plugin tests should pass once https://github.com/flutter/packages/pull/4725 lands and rolls into flutter/flutter~ google tests are migrated. Part of https://github.com/flutter/flutter/issues/133171 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../lib/src/painting/_network_image_io.dart | 39 +-- .../lib/src/painting/_network_image_web.dart | 40 +--- .../flutter/lib/src/painting/binding.dart | 41 ---- .../lib/src/painting/image_decoder.dart | 9 +- .../lib/src/painting/image_provider.dart | 226 +++--------------- .../widgets/scroll_aware_image_provider.dart | 5 +- .../flutter/test/material/switch_test.dart | 4 +- .../test/painting/decoration_test.dart | 10 +- .../test/painting/fake_image_provider.dart | 2 +- .../test/painting/image_test_utils.dart | 5 - .../test/painting/mocks_for_image_cache.dart | 21 +- .../flutter/test/painting/painting_utils.dart | 4 +- .../test/painting/shape_decoration_test.dart | 2 +- .../test/widgets/box_decoration_test.dart | 2 +- .../test/widgets/fade_in_image_test.dart | 2 +- .../widgets/image_filter_quality_test.dart | 2 +- .../flutter/test/widgets/image_rtl_test.dart | 2 +- packages/flutter/test/widgets/image_test.dart | 4 +- 18 files changed, 75 insertions(+), 345 deletions(-) diff --git a/packages/flutter/lib/src/painting/_network_image_io.dart b/packages/flutter/lib/src/painting/_network_image_io.dart index 05dd8cb722291..5221279c61d16 100644 --- a/packages/flutter/lib/src/painting/_network_image_io.dart +++ b/packages/flutter/lib/src/painting/_network_image_io.dart @@ -13,6 +13,9 @@ import 'debug.dart'; import 'image_provider.dart' as image_provider; import 'image_stream.dart'; +// Method signature for _loadAsync decode callbacks. +typedef _SimpleDecoderCallback = Future Function(ui.ImmutableBuffer buffer); + /// The dart:io implementation of [image_provider.NetworkImage]. @immutable class NetworkImage extends image_provider.ImageProvider implements image_provider.NetworkImage { @@ -35,25 +38,6 @@ class NetworkImage extends image_provider.ImageProvider(this); } - @override - ImageStreamCompleter load(image_provider.NetworkImage key, image_provider.DecoderCallback decode) { - // Ownership of this controller is handed off to [_loadAsync]; it is that - // method's responsibility to close the controller's stream when the image - // has been loaded or an error is thrown. - final StreamController chunkEvents = StreamController(); - - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key as NetworkImage, chunkEvents, decodeDeprecated: decode), - chunkEvents: chunkEvents.stream, - scale: key.scale, - debugLabel: key.url, - informationCollector: () => [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), - ], - ); - } - @override ImageStreamCompleter loadBuffer(image_provider.NetworkImage key, image_provider.DecoderBufferCallback decode) { // Ownership of this controller is handed off to [_loadAsync]; it is that @@ -62,7 +46,7 @@ class NetworkImage extends image_provider.ImageProvider chunkEvents = StreamController(); return MultiFrameImageStreamCompleter( - codec: _loadAsync(key as NetworkImage, chunkEvents, decodeBufferDeprecated: decode), + codec: _loadAsync(key as NetworkImage, chunkEvents, decode: decode), chunkEvents: chunkEvents.stream, scale: key.scale, debugLabel: key.url, @@ -112,9 +96,7 @@ class NetworkImage extends image_provider.ImageProvider _loadAsync( NetworkImage key, StreamController chunkEvents, { - image_provider.ImageDecoderCallback? decode, - image_provider.DecoderBufferCallback? decodeBufferDeprecated, - image_provider.DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { try { assert(key == this); @@ -148,16 +130,7 @@ class NetworkImage extends image_provider.ImageProvider Function(ui.ImmutableBuffer buffer); + /// Default HTTP client. web.XMLHttpRequest _httpClient() { return web.XMLHttpRequest(); @@ -54,23 +57,6 @@ class NetworkImage return SynchronousFuture(this); } - @override - ImageStreamCompleter load(image_provider.NetworkImage key, image_provider.DecoderCallback decode) { - // Ownership of this controller is handed off to [_loadAsync]; it is that - // method's responsibility to close the controller's stream when the image - // has been loaded or an error is thrown. - final StreamController chunkEvents = - StreamController(); - - return MultiFrameImageStreamCompleter( - chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, null, null, decode, chunkEvents), - scale: key.scale, - debugLabel: key.url, - informationCollector: _imageStreamInformationCollector(key), - ); - } - @override ImageStreamCompleter loadBuffer(image_provider.NetworkImage key, image_provider.DecoderBufferCallback decode) { // Ownership of this controller is handed off to [_loadAsync]; it is that @@ -81,7 +67,7 @@ class NetworkImage return MultiFrameImageStreamCompleter( chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, null, decode, null, chunkEvents), + codec: _loadAsync(key as NetworkImage, decode, chunkEvents), scale: key.scale, debugLabel: key.url, informationCollector: _imageStreamInformationCollector(key), @@ -97,7 +83,7 @@ class NetworkImage return MultiFrameImageStreamCompleter( chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, decode, null, null, chunkEvents), + codec: _loadAsync(key as NetworkImage, decode, chunkEvents), scale: key.scale, debugLabel: key.url, informationCollector: _imageStreamInformationCollector(key), @@ -121,9 +107,7 @@ class NetworkImage // directly in place of the typical `instantiateImageCodec` method. Future _loadAsync( NetworkImage key, - image_provider.ImageDecoderCallback? decode, - image_provider.DecoderBufferCallback? decodeBufferDeprecated, - image_provider.DecoderCallback? decodeDeprecated, + _SimpleDecoderCallback decode, StreamController chunkEvents, ) async { assert(key == this); @@ -178,17 +162,7 @@ class NetworkImage throw image_provider.NetworkImageLoadException( statusCode: request.status, uri: resolved); } - - if (decode != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decode(buffer); - } else if (decodeBufferDeprecated != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decodeBufferDeprecated(buffer); - } else { - assert(decodeDeprecated != null); - return decodeDeprecated!(bytes); - } + return decode(await ui.ImmutableBuffer.fromUint8List(bytes)); } else { // This API only exists in the web engine implementation and is not // contained in the analyzer summary for Flutter. diff --git a/packages/flutter/lib/src/painting/binding.dart b/packages/flutter/lib/src/painting/binding.dart index 880db6d33fa23..02efc9082ac7c 100644 --- a/packages/flutter/lib/src/painting/binding.dart +++ b/packages/flutter/lib/src/painting/binding.dart @@ -78,47 +78,6 @@ mixin PaintingBinding on BindingBase, ServicesBinding { @protected ImageCache createImageCache() => ImageCache(); - /// Calls through to [dart:ui.instantiateImageCodec] from [ImageCache]. - /// - /// This method is deprecated. use [instantiateImageCodecFromBuffer] with an - /// [ImmutableBuffer] instance instead of this method. - /// - /// The `cacheWidth` and `cacheHeight` parameters, when specified, indicate - /// the size to decode the image to. - /// - /// Both `cacheWidth` and `cacheHeight` must be positive values greater than - /// or equal to 1, or null. It is valid to specify only one of `cacheWidth` - /// and `cacheHeight` with the other remaining null, in which case the omitted - /// dimension will be scaled to maintain the aspect ratio of the original - /// dimensions. When both are null or omitted, the image will be decoded at - /// its native resolution. - /// - /// The `allowUpscaling` parameter determines whether the `cacheWidth` or - /// `cacheHeight` parameters are clamped to the intrinsic width and height of - /// the original image. By default, the dimensions are clamped to avoid - /// unnecessary memory usage for images. Callers that wish to display an image - /// above its native resolution should prefer scaling the canvas the image is - /// drawn into. - @Deprecated( - 'Use instantiateImageCodecWithSize with an ImmutableBuffer instance instead. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', - ) - Future instantiateImageCodec( - Uint8List bytes, { - int? cacheWidth, - int? cacheHeight, - bool allowUpscaling = false, - }) { - assert(cacheWidth == null || cacheWidth > 0); - assert(cacheHeight == null || cacheHeight > 0); - return ui.instantiateImageCodec( - bytes, - targetWidth: cacheWidth, - targetHeight: cacheHeight, - allowUpscaling: allowUpscaling, - ); - } - /// Calls through to [dart:ui.instantiateImageCodecFromBuffer] from [ImageCache]. /// /// The [buffer] parameter should be an [ui.ImmutableBuffer] instance which can diff --git a/packages/flutter/lib/src/painting/image_decoder.dart b/packages/flutter/lib/src/painting/image_decoder.dart index 39d926ee341a1..328c840f7393f 100644 --- a/packages/flutter/lib/src/painting/image_decoder.dart +++ b/packages/flutter/lib/src/painting/image_decoder.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'dart:typed_data'; -import 'dart:ui' as ui show Codec, FrameInfo, Image; +import 'dart:ui' as ui show Codec, FrameInfo, Image, ImmutableBuffer; import 'binding.dart'; @@ -17,10 +17,11 @@ import 'binding.dart'; /// [instantiateImageCodec] if support for animated images is necessary. /// /// This function differs from [ui.decodeImageFromList] in that it defers to -/// [PaintingBinding.instantiateImageCodec], and therefore can be mocked in -/// tests. +/// [PaintingBinding.instantiateImageCodecWithSize], and therefore can be mocked +/// in tests. Future decodeImageFromList(Uint8List bytes) async { - final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodec(bytes); + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); + final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); final ui.FrameInfo frameInfo = await codec.getNextFrame(); return frameInfo.image; } diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index 54e21cc5977ef..b7067c2583dd7 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -160,25 +160,6 @@ class ImageConfiguration { } } -/// Performs the decode process for use in [ImageProvider.load]. -/// -/// This typedef is deprecated. Use [ImageDecoderCallback] with -/// [ImageProvider.loadImage] instead. -/// -/// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and -/// `allowUpscaling` parameters from implementations of [ImageProvider] that do -/// not expose them. -/// -/// See also: -/// -/// * [ResizeImage], which uses this to override the `cacheWidth`, -/// `cacheHeight`, and `allowUpscaling` parameters. -@Deprecated( - 'Use ImageDecoderCallback with ImageProvider.loadImage instead. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', -) -typedef DecoderCallback = Future Function(Uint8List buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling}); - /// Performs the decode process for use in [ImageProvider.loadBuffer]. /// /// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and @@ -195,6 +176,9 @@ typedef DecoderCallback = Future Function(Uint8List buffer, {int? cach ) typedef DecoderBufferCallback = Future Function(ui.ImmutableBuffer buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling}); +// Method signature for _loadAsync decode callbacks. +typedef _SimpleDecoderCallback = Future Function(ui.ImmutableBuffer buffer); + /// Performs the decode process for use in [ImageProvider.loadImage]. /// /// This callback allows decoupling of the `getTargetSize` parameter from @@ -250,7 +234,7 @@ typedef ImageDecoderCallback = Future Function( /// from the cache if possible, or call [loadImage] to fetch the encoded image /// bytes and schedule decoding. /// 4. The [loadImage] method is responsible for both fetching the encoded bytes -/// and decoding them using the provided [DecoderCallback]. It is called +/// and decoding them using the provided [ImageDecoderCallback]. It is called /// in a context that uses the [ImageErrorListener] to report errors back. /// /// Subclasses normally only have to implement the [loadImage] and [obtainKey] @@ -365,10 +349,10 @@ abstract class ImageProvider { /// /// This is the public entry-point of the [ImageProvider] class hierarchy. /// - /// Subclasses should implement [obtainKey] and [load], which are used by this - /// method. If they need to change the implementation of [ImageStream] used, - /// they should override [createStream]. If they need to manage the actual - /// resolution of the image, they should override [resolveStreamForKey]. + /// Subclasses should implement [obtainKey] and [loadImage], which are used by + /// this method. If they need to change the implementation of [ImageStream] + /// used, they should override [createStream]. If they need to manage the + /// actual resolution of the image, they should override [resolveStreamForKey]. /// /// See the Lifecycle documentation on [ImageProvider] for more information. @nonVirtual @@ -542,10 +526,6 @@ abstract class ImageProvider { // of type `_AbstractImageStreamCompleter`. if (result is _AbstractImageStreamCompleter) { result = loadBuffer(key, PaintingBinding.instance.instantiateImageCodecFromBuffer); - if (result is _AbstractImageStreamCompleter) { - // Same fallback as above but for the deprecated `load()` method. - result = load(key, PaintingBinding.instance.instantiateImageCodec); - } } return result; }, @@ -610,39 +590,17 @@ abstract class ImageProvider { /// that describes the precise image to load. /// /// The type of the key is determined by the subclass. It is a value that - /// unambiguously identifies the image (_including its scale_) that the [load] - /// method will fetch. Different [ImageProvider]s given the same constructor - /// arguments and [ImageConfiguration] objects should return keys that are - /// '==' to each other (possibly by using a class for the key that itself - /// implements [==]). + /// unambiguously identifies the image (_including its scale_) that the + /// [loadImage] method will fetch. Different [ImageProvider]s given the same + /// constructor arguments and [ImageConfiguration] objects should return keys + /// that are '==' to each other (possibly by using a class for the key that + /// itself implements [==]). /// /// If the result can be determined synchronously, this function should return /// a [SynchronousFuture]. This allows image resolution to progress /// synchronously during a frame rather than delaying image loading. Future obtainKey(ImageConfiguration configuration); - /// Converts a key into an [ImageStreamCompleter], and begins fetching the - /// image. - /// - /// This method is deprecated. Implement [loadImage] for faster image - /// loading. Only one of [load] and [loadImage] must be implemented, and - /// [loadImage] is preferred. - /// - /// The [decode] callback provides the logic to obtain the codec for the - /// image. - /// - /// See also: - /// - /// * [ResizeImage], for modifying the key to account for cache dimensions. - @protected - @Deprecated( - 'Implement loadImage for faster image loading. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', - ) - ImageStreamCompleter load(T key, DecoderCallback decode) { - throw UnsupportedError('Implement loadImage for faster image loading'); - } - /// Converts a key into an [ImageStreamCompleter], and begins fetching the /// image. /// @@ -776,25 +734,7 @@ abstract class AssetBundleImageProvider extends ImageProvider [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), - ]; - return true; - }()); - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeDeprecated: decode), + codec: _loadAsync(key, decode: decode), scale: key.scale, debugLabel: key.name, informationCollector: collector, @@ -804,48 +744,22 @@ abstract class AssetBundleImageProvider extends ImageProvider _loadAsync( AssetBundleImageKey key, { - ImageDecoderCallback? decode, - DecoderBufferCallback? decodeBufferDeprecated, - DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { - if (decode != null) { - ui.ImmutableBuffer buffer; - // Hot reload/restart could change whether an asset bundle or key in a - // bundle are available, or if it is a network backed bundle. - try { - buffer = await key.bundle.loadBuffer(key.name); - } on FlutterError { - PaintingBinding.instance.imageCache.evict(key); - rethrow; - } - return decode(buffer); - } - if (decodeBufferDeprecated != null) { - ui.ImmutableBuffer buffer; - // Hot reload/restart could change whether an asset bundle or key in a - // bundle are available, or if it is a network backed bundle. - try { - buffer = await key.bundle.loadBuffer(key.name); - } on FlutterError { - PaintingBinding.instance.imageCache.evict(key); - rethrow; - } - return decodeBufferDeprecated(buffer); - } - ByteData data; + final ui.ImmutableBuffer buffer; // Hot reload/restart could change whether an asset bundle or key in a // bundle are available, or if it is a network backed bundle. try { - data = await key.bundle.load(key.name); + buffer = await key.bundle.loadBuffer(key.name); } on FlutterError { PaintingBinding.instance.imageCache.evict(key); rethrow; } - return decodeDeprecated!(data.buffer.asUint8List()); + return decode(buffer); } } @@ -1337,28 +1251,6 @@ class ResizeImage extends ImageProvider { return provider; } - @override - @Deprecated( - 'Implement loadImage for faster image loading. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', - ) - ImageStreamCompleter load(ResizeImageKey key, DecoderCallback decode) { - Future decodeResize(Uint8List buffer, {int? cacheWidth, int? cacheHeight, bool? allowUpscaling}) { - assert( - cacheWidth == null && cacheHeight == null && allowUpscaling == null, - 'ResizeImage cannot be composed with another ImageProvider that applies ' - 'cacheWidth, cacheHeight, or allowUpscaling.', - ); - return decode(buffer, cacheWidth: width, cacheHeight: height, allowUpscaling: this.allowUpscaling); - } - final ImageStreamCompleter completer = imageProvider.load(key._providerCacheKey, decodeResize); - if (!kReleaseMode) { - completer.debugLabel = '${completer.debugLabel} - Resized(${key._width}×${key._height})'; - } - _configureErrorListener(completer, key); - return completer; - } - @override @Deprecated( 'Implement loadImage for image loading. ' @@ -1494,11 +1386,11 @@ class ResizeImage extends ImageProvider { /// /// The image will be cached regardless of cache headers from the server. /// -/// When a network image is used on the Web platform, the `cacheWidth` and -/// `cacheHeight` parameters of the [DecoderCallback] are only supported when the -/// application is running with the CanvasKit renderer. When the application is using -/// the HTML renderer, the web engine delegates image decoding of network images to the Web, -/// which does not support custom decode sizes. +/// When a network image is used on the Web platform, the `getTargetSize` +/// parameter of the [ImageDecoderCallback] is only supported when the +/// application is running with the CanvasKit renderer. When the application is +/// using the HTML renderer, the web engine delegates image decoding of network +/// images to the Web, which does not support custom decode sizes. /// /// See also: /// @@ -1525,9 +1417,6 @@ abstract class NetworkImage extends ImageProvider { /// When running Flutter on the web, headers are not used. Map? get headers; - @override - ImageStreamCompleter load(NetworkImage key, DecoderCallback decode); - @override ImageStreamCompleter loadBuffer(NetworkImage key, DecoderBufferCallback decode); @@ -1562,22 +1451,10 @@ class FileImage extends ImageProvider { return SynchronousFuture(this); } - @override - ImageStreamCompleter load(FileImage key, DecoderCallback decode) { - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeDeprecated: decode), - scale: key.scale, - debugLabel: key.file.path, - informationCollector: () => [ - ErrorDescription('Path: ${file.path}'), - ], - ); - } - @override ImageStreamCompleter loadBuffer(FileImage key, DecoderBufferCallback decode) { return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeBufferDeprecated: decode), + codec: _loadAsync(key, decode: decode), scale: key.scale, debugLabel: key.file.path, informationCollector: () => [ @@ -1601,12 +1478,9 @@ class FileImage extends ImageProvider { Future _loadAsync( FileImage key, { - ImageDecoderCallback? decode, - DecoderBufferCallback? decodeBufferDeprecated, - DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { assert(key == this); - // TODO(jonahwilliams): making this sync caused test failures that seem to // indicate that we can fail to call evict unless at least one await has // occurred in the test. @@ -1617,19 +1491,9 @@ class FileImage extends ImageProvider { PaintingBinding.instance.imageCache.evict(key); throw StateError('$file is empty and cannot be loaded as an image.'); } - if (decode != null) { - if (file.runtimeType == File) { - return decode(await ui.ImmutableBuffer.fromFilePath(file.path)); - } - return decode(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); - } - if (decodeBufferDeprecated != null) { - if (file.runtimeType == File) { - return decodeBufferDeprecated(await ui.ImmutableBuffer.fromFilePath(file.path)); - } - return decodeBufferDeprecated(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); - } - return decodeDeprecated!(await file.readAsBytes()); + return (file.runtimeType == File) + ? decode(await ui.ImmutableBuffer.fromFilePath(file.path)) + : decode(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); } @override @@ -1655,8 +1519,8 @@ class FileImage extends ImageProvider { /// The provided [bytes] buffer should not be changed after it is provided /// to a [MemoryImage]. To provide an [ImageStream] that represents an image /// that changes over time, consider creating a new subclass of [ImageProvider] -/// whose [load] method returns a subclass of [ImageStreamCompleter] that can -/// handle providing multiple images. +/// whose [loadImage] method returns a subclass of [ImageStreamCompleter] that +/// can handle providing multiple images. /// /// See also: /// @@ -1675,7 +1539,7 @@ class MemoryImage extends ImageProvider { /// /// See also: /// - /// * [PaintingBinding.instantiateImageCodec] + /// * [PaintingBinding.instantiateImageCodecWithSize] final Uint8List bytes; /// The scale to place in the [ImageInfo] object of the image. @@ -1691,19 +1555,11 @@ class MemoryImage extends ImageProvider { return SynchronousFuture(this); } - @override - ImageStreamCompleter load(MemoryImage key, DecoderCallback decode) { - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeDeprecated: decode), - scale: key.scale, - debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})', - ); - } - @override ImageStreamCompleter loadBuffer(MemoryImage key, DecoderBufferCallback decode) { + assert(key == this); return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeBufferDeprecated: decode), + codec: _loadAsync(key, decode: decode), scale: key.scale, debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})', ); @@ -1720,20 +1576,10 @@ class MemoryImage extends ImageProvider { Future _loadAsync( MemoryImage key, { - ImageDecoderCallback? decode, - DecoderBufferCallback? decodeBufferDeprecated, - DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { assert(key == this); - if (decode != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decode(buffer); - } - if (decodeBufferDeprecated != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decodeBufferDeprecated(buffer); - } - return decodeDeprecated!(bytes); + return decode(await ui.ImmutableBuffer.fromUint8List(bytes)); } @override diff --git a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart index 4009be91ed2ad..f408d8835be66 100644 --- a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart +++ b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart @@ -63,7 +63,7 @@ class ScrollAwareImageProvider extends ImageProvider { /// been resolved. final DisposableBuildContext context; - /// The wrapped image provider to delegate [obtainKey] and [load] to. + /// The wrapped image provider to delegate [obtainKey] and [loadImage] to. final ImageProvider imageProvider; @override @@ -105,9 +105,6 @@ class ScrollAwareImageProvider extends ImageProvider { imageProvider.resolveStreamForKey(configuration, stream, key, handleError); } - @override - ImageStreamCompleter load(T key, DecoderCallback decode) => imageProvider.load(key, decode); - @override ImageStreamCompleter loadBuffer(T key, DecoderBufferCallback decode) => imageProvider.loadBuffer(key, decode); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 9fbf97f7ac878..0959ad2d2fd43 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -3556,7 +3556,7 @@ class DelayedImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(DelayedImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(DelayedImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter(_completer.future); } @@ -3592,7 +3592,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart index 8750ba5e4862d..6cfa461d82d67 100644 --- a/packages/flutter/test/painting/decoration_test.dart +++ b/packages/flutter/test/painting/decoration_test.dart @@ -34,7 +34,7 @@ class SynchronousTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(TestImageInfo(key, image: image)), ); @@ -52,7 +52,7 @@ class SynchronousErrorTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { throw throwable; } } @@ -68,7 +68,7 @@ class AsyncTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( Future.value(TestImageInfo(key, image: image)), ); @@ -88,7 +88,7 @@ class DelayedImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(DelayedImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(DelayedImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter(_completer.future); } @@ -111,7 +111,7 @@ class MultiFrameImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(MultiFrameImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(MultiFrameImageProvider key, ImageDecoderCallback decode) { return completer; } diff --git a/packages/flutter/test/painting/fake_image_provider.dart b/packages/flutter/test/painting/fake_image_provider.dart index c352adaaab2df..a59f54670b58f 100644 --- a/packages/flutter/test/painting/fake_image_provider.dart +++ b/packages/flutter/test/painting/fake_image_provider.dart @@ -25,7 +25,7 @@ class FakeImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(FakeImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(FakeImageProvider key, ImageDecoderCallback decode) { assert(key == this); return MultiFrameImageStreamCompleter( codec: SynchronousFuture(_codec), diff --git a/packages/flutter/test/painting/image_test_utils.dart b/packages/flutter/test/painting/image_test_utils.dart index 847984663e269..4b137c3f349a6 100644 --- a/packages/flutter/test/painting/image_test_utils.dart +++ b/packages/flutter/test/painting/image_test_utils.dart @@ -28,11 +28,6 @@ class TestImageProvider extends ImageProvider { super.resolveStreamForKey(config, stream, key, handleError); } - @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { - throw UnsupportedError('Use ImageProvider.loadImage instead.'); - } - @override ImageStreamCompleter loadBuffer(TestImageProvider key, DecoderBufferCallback decode) { throw UnsupportedError('Use ImageProvider.loadImage instead.'); diff --git a/packages/flutter/test/painting/mocks_for_image_cache.dart b/packages/flutter/test/painting/mocks_for_image_cache.dart index 1273faa4c5e81..bc80315747f76 100644 --- a/packages/flutter/test/painting/mocks_for_image_cache.dart +++ b/packages/flutter/test/painting/mocks_for_image_cache.dart @@ -54,7 +54,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(TestImageInfo(imageValue, image: image.clone())), ); @@ -68,7 +68,7 @@ class FailingTestImageProvider extends TestImageProvider { const FailingTestImageProvider(super.key, super.imageValue, { required super.image }); @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter(Future.sync(() => Future.error('loading failed!'))); } } @@ -95,11 +95,6 @@ class ErrorImageProvider extends ImageProvider { throw Error(); } - @override - ImageStreamCompleter load(ErrorImageProvider key, DecoderCallback decode) { - throw Error(); - } - @override Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); @@ -121,11 +116,6 @@ class ObtainKeyErrorImageProvider extends ImageProvider obtainKey(ImageConfiguration configuration) { throw Error(); } - - @override - ImageStreamCompleter load(ObtainKeyErrorImageProvider key, DecoderCallback decode) { - throw UnimplementedError(); - } } class LoadErrorImageProvider extends ImageProvider { @@ -143,16 +133,11 @@ class LoadErrorImageProvider extends ImageProvider { Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } - - @override - ImageStreamCompleter load(LoadErrorImageProvider key, DecoderCallback decode) { - throw UnimplementedError(); - } } class LoadErrorCompleterImageProvider extends ImageProvider { @override - ImageStreamCompleter load(LoadErrorCompleterImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(LoadErrorCompleterImageProvider key, ImageDecoderCallback decode) { final Completer completer = Completer.sync(); completer.completeError(Error()); return OneFrameImageStreamCompleter(completer.future); diff --git a/packages/flutter/test/painting/painting_utils.dart b/packages/flutter/test/painting/painting_utils.dart index b7edc0da1227a..7d669fa1e3672 100644 --- a/packages/flutter/test/painting/painting_utils.dart +++ b/packages/flutter/test/painting/painting_utils.dart @@ -14,9 +14,9 @@ class PaintingBindingSpy extends BindingBase with SchedulerBinding, ServicesBind int get instantiateImageCodecCalledCount => counter; @override - Future instantiateImageCodec(Uint8List list, {int? cacheWidth, int? cacheHeight, bool allowUpscaling = false}) { + Future instantiateImageCodecWithSize(ui.ImmutableBuffer buffer, { ui.TargetImageSizeCallback? getTargetSize }) { counter++; - return ui.instantiateImageCodec(list); + return ui.instantiateImageCodecWithSize(buffer, getTargetSize: getTargetSize); } @override diff --git a/packages/flutter/test/painting/shape_decoration_test.dart b/packages/flutter/test/painting/shape_decoration_test.dart index 8a193a5faafff..269fb9e416b16 100644 --- a/packages/flutter/test/painting/shape_decoration_test.dart +++ b/packages/flutter/test/painting/shape_decoration_test.dart @@ -156,7 +156,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index 42f36c0657e3e..031006439d7f2 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -25,7 +25,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( future.then((void value) => ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index a10a77bd2498c..e88c6ca6e5084 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -58,7 +58,7 @@ class LoadTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { throw UnimplementedError(); } } diff --git a/packages/flutter/test/widgets/image_filter_quality_test.dart b/packages/flutter/test/widgets/image_filter_quality_test.dart index d8b1ee367b0f8..dcbeadfd438da 100644 --- a/packages/flutter/test/widgets/image_filter_quality_test.dart +++ b/packages/flutter/test/widgets/image_filter_quality_test.dart @@ -137,7 +137,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 2fb1aa68771db..6f2c075a00e0f 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -19,7 +19,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index 2eb4b80b6437e..cbabca138f9b4 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -2083,7 +2083,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } @@ -2198,7 +2198,7 @@ class _FailingImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { if (failOnLoad) { throw throws; } From 8175d693e5701d253fc831c06ae1cd92925c2201 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 20:06:51 +0000 Subject: [PATCH 0878/1547] Bump activesupport from 6.1.7.3 to 6.1.7.6 in /dev/ci/mac (#133225) Bumps [activesupport](https://github.com/rails/rails) from 6.1.7.3 to 6.1.7.6.
    Release notes

    Sourced from activesupport's releases.

    v6.1.7.6

    No changes between this and 6.1.7.5. This release was just to fix file permissions in the previous release.

    6.1.7.5 Release

    Active Support

    • Use a temporary file for storing unencrypted files while editing

      [CVE-2023-38037]

    Active Model

    • No changes.

    Active Record

    • No changes.

    Action View

    • No changes.

    Action Pack

    • No changes.

    Active Job

    • No changes.

    Action Mailer

    • No changes.

    Action Cable

    ... (truncated)

    Commits
    • 56bcc0a Preparing for 6.1.7.6 release
    • 1f03e9d Bumping version for new release
    • 3a1b615 Preparing for 6.1.7.5 release
    • c2af578 bumping version / changelog
    • c85cc66 Use a temporary file for storing unencrypted files while editing
    • 7d949d7 Preparing for 6.1.7.4 release
    • See full diff in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=activesupport&package-manager=bundler&previous-version=6.1.7.3&new-version=6.1.7.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/flutter/flutter/network/alerts).
    --- dev/ci/mac/Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/ci/mac/Gemfile.lock b/dev/ci/mac/Gemfile.lock index dd07f525d1544..c37fe1f100f62 100644 --- a/dev/ci/mac/Gemfile.lock +++ b/dev/ci/mac/Gemfile.lock @@ -3,7 +3,7 @@ GEM specs: CFPropertyList (3.0.5) rexml - activesupport (6.1.7.3) + activesupport (6.1.7.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -63,10 +63,10 @@ GEM fuzzy_match (2.0.4) gh_inspector (1.1.3) httpclient (2.8.3) - i18n (1.12.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) json (2.6.1) - minitest (5.18.0) + minitest (5.19.0) molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) @@ -85,7 +85,7 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) - zeitwerk (2.6.7) + zeitwerk (2.6.11) PLATFORMS ruby From afa37891cf36ca16a18998c6558bc03933dc53e6 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 24 Aug 2023 13:41:57 -0700 Subject: [PATCH 0879/1547] Users of ChangeNotifier should dispatch event of object creation in constructor. (#133210) --- .../flutter/lib/src/widgets/navigator.dart | 7 +++++++ .../lib/src/widgets/selectable_region.dart | 7 +++++++ .../lib/src/widgets/widget_inspector.dart | 7 +++++++ .../test/foundation/change_notifier_test.dart | 12 ++++++++++++ .../widgets/automatic_keep_alive_test.dart | 7 +++++++ .../route_notification_messages_test.dart | 6 +++++- .../test/widgets/router_restoration_test.dart | 12 ++++++++++++ packages/flutter/test/widgets/router_test.dart | 18 +++++++++++++++--- 8 files changed, 72 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 4f7041d45b6d5..e93ab22af4e6e 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -3355,6 +3355,13 @@ typedef _IndexWhereCallback = bool Function(_RouteEntry element); /// Acts as a ChangeNotifier and notifies after its List of _RouteEntries is /// mutated. class _History extends Iterable<_RouteEntry> with ChangeNotifier { + /// Creates an instance of [_History]. + _History() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + final List<_RouteEntry> _value = <_RouteEntry>[]; int indexWhere(_IndexWhereCallback test, [int start = 0]) { diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 16711e25d61b8..f08e20ec2551e 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -1567,6 +1567,13 @@ class _SelectableRegionContainerDelegate extends MultiSelectableSelectionContain /// This class optimize the selection update by keeping track of the /// [Selectable]s that currently contain the selection edges. abstract class MultiSelectableSelectionContainerDelegate extends SelectionContainerDelegate with ChangeNotifier { + /// Creates an instance of [MultiSelectableSelectionContainerDelegate]. + MultiSelectableSelectionContainerDelegate() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + /// Gets the list of selectables this delegate is managing. List selectables = []; diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 5873aaab7eda3..66cc2d5abddb0 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2895,6 +2895,13 @@ class _WidgetInspectorState extends State /// Mutable selection state of the inspector. class InspectorSelection with ChangeNotifier { + /// Creates an instance of [InspectorSelection]. + InspectorSelection() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + /// Render objects that are candidates to be selected. /// /// Tools may wish to iterate through the list of candidates. diff --git a/packages/flutter/test/foundation/change_notifier_test.dart b/packages/flutter/test/foundation/change_notifier_test.dart index a7adb3df3163f..d766c6198dce0 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart @@ -27,6 +27,12 @@ class A { } class B extends A with ChangeNotifier { + B() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + @override void test() { notifyListeners(); @@ -35,6 +41,12 @@ class B extends A with ChangeNotifier { } class Counter with ChangeNotifier { + Counter() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + int get value => _value; int _value = 0; set value(int value) { diff --git a/packages/flutter/test/widgets/automatic_keep_alive_test.dart b/packages/flutter/test/widgets/automatic_keep_alive_test.dart index eb2718fbd0543..5869793871fc4 100644 --- a/packages/flutter/test/widgets/automatic_keep_alive_test.dart +++ b/packages/flutter/test/widgets/automatic_keep_alive_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; @@ -631,6 +632,12 @@ class RenderSliverMultiBoxAdaptorAlt extends RenderSliver with } class LeakCheckerHandle with ChangeNotifier { + LeakCheckerHandle() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + @override bool get hasListeners => super.hasListeners; } diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index 940bf16fba354..1d79ee0ed1c7b 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -338,7 +338,11 @@ class SimpleRouterDelegate extends RouterDelegate with ChangeN required this.builder, this.onPopRoute, this.reportConfiguration = false, - }); + }) { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } RouteInformation get routeInformation => _routeInformation; late RouteInformation _routeInformation; diff --git a/packages/flutter/test/widgets/router_restoration_test.dart b/packages/flutter/test/widgets/router_restoration_test.dart index a2568f930b718..4892c9c841ffe 100644 --- a/packages/flutter/test/widgets/router_restoration_test.dart +++ b/packages/flutter/test/widgets/router_restoration_test.dart @@ -90,6 +90,12 @@ class _TestRouteInformationParser extends RouteInformationParser { } class _TestRouterDelegate extends RouterDelegate with ChangeNotifier { + _TestRouterDelegate() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + final List newRoutePaths = []; final List restoredRoutePaths = []; @@ -128,6 +134,12 @@ class _TestRouterDelegate extends RouterDelegate with ChangeNotifier { } class _TestRouteInformationProvider extends RouteInformationProvider with ChangeNotifier { + _TestRouteInformationProvider() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + @override RouteInformation get value => _value; RouteInformation _value = RouteInformation(uri: Uri.parse('/home')); diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index cf46e0fc3d476..a552d67b6c539 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1633,7 +1633,11 @@ class SimpleRouterDelegate extends RouterDelegate with ChangeN this.builder, this.onPopRoute, this.reportConfiguration = false, - }); + }) { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } RouteInformation? get routeInformation => _routeInformation; RouteInformation? _routeInformation; @@ -1717,7 +1721,11 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate wit class SimpleRouteInformationProvider extends RouteInformationProvider with ChangeNotifier { SimpleRouteInformationProvider({ this.onRouterReport, - }); + }) { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } RouterReportRouterInformation? onRouterReport; @@ -1773,7 +1781,11 @@ class CompleterRouteInformationParser extends RouteInformationParser with ChangeNotifier { SimpleAsyncRouterDelegate({ required this.builder, - }); + }) { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } RouteInformation? get routeInformation => _routeInformation; RouteInformation? _routeInformation; From cb72164a72941a711ab2bee473f83ef58a8ea0d2 Mon Sep 17 00:00:00 2001 From: Yegor Date: Thu, 24 Aug 2023 14:28:04 -0700 Subject: [PATCH 0880/1547] [web] benchmark the benchmark harness overhead (#132999) Add benchmarks that measure the overhead of the benchmark harness itself. We want the overhead to be minimal. Also, these numbers are useful to judge the quality of real benchmarks. If a real benchmark's result is too close to the harness overhead, then it's likely not measuring enough of useful work. --- .../lib/src/web/bench_harness.dart | 63 +++++++++++++++++++ .../macrobenchmarks/lib/web_benchmarks.dart | 9 ++- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 dev/benchmarks/macrobenchmarks/lib/src/web/bench_harness.dart diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_harness.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_harness.dart new file mode 100644 index 0000000000000..8c95cf42cf862 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_harness.dart @@ -0,0 +1,63 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +import 'recorder.dart'; + +class BenchWidgetRecorder extends WidgetRecorder { + BenchWidgetRecorder() : super(name: benchmarkName); + + static const String benchmarkName = 'bench_widget_recorder'; + + @override + Widget createWidget() { + // This is intentionally using a simple widget. The benchmark is meant to + // measure the overhead of the harness, so this method should induce as + // little work as possible. + return const SizedBox.expand(); + } +} + +class BenchWidgetBuildRecorder extends WidgetBuildRecorder { + BenchWidgetBuildRecorder() : super(name: benchmarkName); + + static const String benchmarkName = 'bench_widget_build_recorder'; + + @override + Widget createWidget() { + // This is intentionally using a simple widget. The benchmark is meant to + // measure the overhead of the harness, so this method should induce as + // little work as possible. + return const SizedBox.expand(); + } +} + +class BenchRawRecorder extends RawRecorder { + BenchRawRecorder() : super(name: benchmarkName); + + static const String benchmarkName = 'bench_raw_recorder'; + + @override + void body(Profile profile) { + profile.record('profile.record', () { + // This is intentionally empty. The benchmark only measures the overhead + // of the harness. + }, reported: true); + } +} + +class BenchSceneBuilderRecorder extends SceneBuilderRecorder { + BenchSceneBuilderRecorder() : super(name: benchmarkName); + + static const String benchmarkName = 'bench_scene_builder_recorder'; + + @override + void onDrawFrame(ui.SceneBuilder sceneBuilder) { + // This is intentionally empty. The benchmark only measures the overhead + // of the harness. + } +} diff --git a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart index e4e18d598b908..1beddb177940f 100644 --- a/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart +++ b/dev/benchmarks/macrobenchmarks/lib/web_benchmarks.dart @@ -17,6 +17,7 @@ import 'src/web/bench_clipped_out_pictures.dart'; import 'src/web/bench_default_target_platform.dart'; import 'src/web/bench_draw_rect.dart'; import 'src/web/bench_dynamic_clip_on_static_picture.dart'; +import 'src/web/bench_harness.dart'; import 'src/web/bench_image_decoding.dart'; import 'src/web/bench_material_3.dart'; import 'src/web/bench_material_3_semantics.dart'; @@ -43,7 +44,13 @@ const bool isSkwasm = bool.fromEnvironment('FLUTTER_WEB_USE_SKWASM'); /// When adding a new benchmark, add it to this map. Make sure that the name /// of your benchmark is unique. final Map benchmarks = { - // Benchmarks that run both in CanvasKit and HTML modes + // Benchmarks the overhead of the benchmark harness itself. + BenchRawRecorder.benchmarkName: () => BenchRawRecorder(), + BenchWidgetRecorder.benchmarkName: () => BenchWidgetRecorder(), + BenchWidgetBuildRecorder.benchmarkName: () => BenchWidgetBuildRecorder(), + BenchSceneBuilderRecorder.benchmarkName: () => BenchSceneBuilderRecorder(), + + // Benchmarks that run in all renderers. BenchDefaultTargetPlatform.benchmarkName: () => BenchDefaultTargetPlatform(), BenchBuildImage.benchmarkName: () => BenchBuildImage(), BenchCardInfiniteScroll.benchmarkName: () => BenchCardInfiniteScroll.forward(), From b2118918769788d04de8a274c25c7355d148fd15 Mon Sep 17 00:00:00 2001 From: Henry Riehl <73116038+whiskeyPeak@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:45:21 +0100 Subject: [PATCH 0881/1547] Add hover duration for `Inkwell` widget (#132176) Adds a `hoverDuration` property to the `Inkwell` widget. This allows the user to customise how long the change in colour animates between the default colour and the hovered colour. https://github.com/flutter/flutter/assets/73116038/2e7c5ccb-8651-4e08-8c7b-225cc005d594 Fixes #132170 --- .../flutter/lib/src/material/ink_well.dart | 12 +++++++++- .../flutter/test/material/ink_well_test.dart | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index 157e2b31884ad..8814a847ad1c6 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -332,6 +332,7 @@ class InkResponse extends StatelessWidget { this.onFocusChange, this.autofocus = false, this.statesController, + this.hoverDuration, }); /// The widget below this widget in the tree. @@ -621,6 +622,11 @@ class InkResponse extends StatelessWidget { /// {@endtemplate} final MaterialStatesController? statesController; + /// The duration of the animation that animates the hover effect. + /// + /// The default is 50ms. + final Duration? hoverDuration; + @override Widget build(BuildContext context) { final _ParentInkResponseState? parentState = _ParentInkResponseProvider.maybeOf(context); @@ -659,6 +665,7 @@ class InkResponse extends StatelessWidget { getRectCallback: getRectCallback, debugCheckContext: debugCheckContext, statesController: statesController, + hoverDuration: hoverDuration, child: child, ); } @@ -715,6 +722,7 @@ class _InkResponseStateWidget extends StatefulWidget { this.getRectCallback, required this.debugCheckContext, this.statesController, + this.hoverDuration, }); final Widget? child; @@ -752,6 +760,7 @@ class _InkResponseStateWidget extends StatefulWidget { final _GetRectCallback? getRectCallback; final _CheckContext debugCheckContext; final MaterialStatesController? statesController; + final Duration? hoverDuration; @override _InkResponseState createState() => _InkResponseState(); @@ -920,7 +929,7 @@ class _InkResponseState extends State<_InkResponseStateWidget> return const Duration(milliseconds: 200); case _HighlightType.hover: case _HighlightType.focus: - return const Duration(milliseconds: 50); + return widget.hoverDuration ?? const Duration(milliseconds: 50); } } @@ -1456,6 +1465,7 @@ class InkWell extends InkResponse { super.onFocusChange, super.autofocus, super.statesController, + super.hoverDuration, }) : super( containedInkWell: true, highlightShape: BoxShape.rectangle, diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index ed2a5411f3d8b..8f3903ad9feb1 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -2229,4 +2229,28 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t await gesture.up(); }); + + testWidgetsWithLeakTracking('try out hoverDuration property', (WidgetTester tester) async { + final List log = []; + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: Center( + child: InkWell( + hoverDuration: const Duration(milliseconds: 1000), + onTap: () { + log.add('tap'); + }, + ), + ), + ), + )); + + await tester.tap(find.byType(InkWell), pointer: 1); + await tester.pump(const Duration(seconds: 1)); + + expect(log, equals(['tap'])); + log.clear(); + }); } From 5fa8de05ee857a77ee392bd18c34510a127449e4 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 24 Aug 2023 14:54:56 -0700 Subject: [PATCH 0882/1547] l10n-related documentation improvements (#133114) --- .../localization/bin/gen_localizations.dart | 18 +++++++++--------- .../lib/src/cupertino/localizations.dart | 1 - .../src/material/material_localizations.dart | 5 +++-- .../flutter/lib/src/widgets/localizations.dart | 2 +- .../lib/src/l10n/README.md | 6 ++---- .../lib/src/l10n/material_en.arb | 4 ++-- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/dev/tools/localization/bin/gen_localizations.dart b/dev/tools/localization/bin/gen_localizations.dart index 91490fec321c4..af70e2368955f 100644 --- a/dev/tools/localization/bin/gen_localizations.dart +++ b/dev/tools/localization/bin/gen_localizations.dart @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This program generates a getMaterialTranslation() and a -// getCupertinoTranslation() function that look up the translations provided by +// This program generates getMaterialTranslation(), getCupertinoTranslation(), +// and getWidgetsTranslation() functions that look up the translations provided by // the arb files. The returned value is a generated instance of a -// GlobalMaterialLocalizations or a GlobalCupertinoLocalizations that -// corresponds to a single locale. +// GlobalMaterialLocalizations, GlobalCupertinoLocalizations, or +// GlobalWidgetsLocalizations object that corresponds to a single locale. // // The *.arb files are in packages/flutter_localizations/lib/src/l10n. // @@ -40,8 +40,8 @@ // ``` // // If the data looks good, use the `-w` or `--overwrite` option to overwrite the -// packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart -// and packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart file: +// generated_material_localizations.dart, generated_cupertino_localizations.dart, +// and generated_widgets_localizations.dart files in packages/flutter_localizations/lib/src/l10n/: // // ``` // dart dev/tools/localization/bin/gen_localizations.dart --overwrite @@ -543,19 +543,19 @@ void main(List rawArgs) { // Maps of locales to resource key/value pairs for Widgets ARBs. final Map> widgetsLocaleToResources = >{}; - // Maps of locales to resource key/attributes pairs for Widgets ARBs.. + // Maps of locales to resource key/attributes pairs for Widgets ARBs. // https://github.com/googlei18n/app-resource-bundle/wiki/ApplicationResourceBundleSpecification#resource-attributes final Map> widgetsLocaleToResourceAttributes = >{}; // Maps of locales to resource key/value pairs for Material ARBs. final Map> materialLocaleToResources = >{}; - // Maps of locales to resource key/attributes pairs for Material ARBs.. + // Maps of locales to resource key/attributes pairs for Material ARBs. // https://github.com/googlei18n/app-resource-bundle/wiki/ApplicationResourceBundleSpecification#resource-attributes final Map> materialLocaleToResourceAttributes = >{}; // Maps of locales to resource key/value pairs for Cupertino ARBs. final Map> cupertinoLocaleToResources = >{}; - // Maps of locales to resource key/attributes pairs for Cupertino ARBs.. + // Maps of locales to resource key/attributes pairs for Cupertino ARBs. // https://github.com/googlei18n/app-resource-bundle/wiki/ApplicationResourceBundleSpecification#resource-attributes final Map> cupertinoLocaleToResourceAttributes = >{}; diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index 02cb25970f3f0..2262d55f45b71 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -57,7 +57,6 @@ enum DatePickerDateOrder { /// /// * [DefaultCupertinoLocalizations], the default, English-only, implementation /// of this interface. -// TODO(xster): Supply non-english strings. abstract class CupertinoLocalizations { /// Year that is shown in [CupertinoDatePicker] spinner corresponding to the /// given year index. diff --git a/packages/flutter/lib/src/material/material_localizations.dart b/packages/flutter/lib/src/material/material_localizations.dart index 21d7515b5509a..8cfd4b046a677 100644 --- a/packages/flutter/lib/src/material/material_localizations.dart +++ b/packages/flutter/lib/src/material/material_localizations.dart @@ -179,10 +179,11 @@ abstract class MaterialLocalizations { /// Label indicating that a given date is the current date. String get currentDateLabel; - /// Label for the scrim rendered underneath the content of a modal route. + /// Label for the scrim rendered underneath a [BottomSheet]. String get scrimLabel; - /// Label for a BottomSheet. + /// Label for a [BottomSheet], used as the `modalRouteContentName` of the + /// [scrimOnTapHint]. String get bottomSheetLabel; /// Hint text announced when tapping on the scrim underneath the content of diff --git a/packages/flutter/lib/src/widgets/localizations.dart b/packages/flutter/lib/src/widgets/localizations.dart index 72f58ad1dfc91..499e21bdf96f9 100644 --- a/packages/flutter/lib/src/widgets/localizations.dart +++ b/packages/flutter/lib/src/widgets/localizations.dart @@ -96,7 +96,7 @@ Future> _loadAll(Locale locale, Iterable { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. diff --git a/packages/flutter_localizations/lib/src/l10n/README.md b/packages/flutter_localizations/lib/src/l10n/README.md index 857c687f18bad..4ff175ea1cd58 100644 --- a/packages/flutter_localizations/lib/src/l10n/README.md +++ b/packages/flutter_localizations/lib/src/l10n/README.md @@ -15,12 +15,10 @@ apps in general, see the ### Translations for one locale: .arb files The Material and Cupertino libraries use -[Application Resource Bundle](https://code.google.com/p/arb/wiki/ApplicationResourceBundleSpecification) +[Application Resource Bundle](https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification) files, which have a `.arb` extension, to store localized translations of messages, format strings, and other values. This format is also -used by the Dart [intl](https://pub.dev/packages/intl) -package and it is supported by the -[Google Translators Toolkit](https://translate.google.com/toolkit). +used by the Dart [intl](https://pub.dev/packages/intl) package. The Material and Cupertino libraries only depend on a small subset of the ARB format. Each .arb file contains a single JSON table that diff --git a/packages/flutter_localizations/lib/src/l10n/material_en.arb b/packages/flutter_localizations/lib/src/l10n/material_en.arb index de77ae0c163e1..bcce0e2b39801 100644 --- a/packages/flutter_localizations/lib/src/l10n/material_en.arb +++ b/packages/flutter_localizations/lib/src/l10n/material_en.arb @@ -73,7 +73,7 @@ "scrimLabel": "Scrim", "@scrimLabel": { - "description": "The label for the scrim rendered underneath the content of a modal route." + "description": "The label for the scrim rendered underneath the content of a bottom sheet (used as the 'modalRouteContentName' of the 'scrimOnTapHint' message)." }, "bottomSheetLabel": "Bottom Sheet", @@ -83,7 +83,7 @@ "scrimOnTapHint": "Close $modalRouteContentName", "@scrimOnTapHint": { - "description": "The onTapHint for the scrim rendered underneath the content of a modal route which users can tap to dismiss the content", + "description": "The onTapHint for the scrim rendered underneath the content of a modal route (especially a bottom sheet) which users can tap to dismiss the content.", "parameters": "modalRouteContentName" }, From d6bf1447f4942f2a62e3021202d77f1c2c588eee Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 24 Aug 2023 14:54:59 -0700 Subject: [PATCH 0883/1547] Update the tool to know about all our new platforms (#132423) ...and add a test so we remember to keep it in sync. --- dev/bots/analyze.dart | 81 +++++++++++++++++++ .../flutter/lib/src/foundation/binding.dart | 29 +++---- .../flutter/lib/src/foundation/platform.dart | 11 ++- .../lib/src/resident_runner.dart | 24 +++--- .../general.shard/resident_runner_test.dart | 8 +- .../general.shard/terminal_handler_test.dart | 12 +-- 6 files changed, 122 insertions(+), 43 deletions(-) diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart index 9e87d94f0e117..39f739277f716 100644 --- a/dev/bots/analyze.dart +++ b/dev/bots/analyze.dart @@ -87,6 +87,9 @@ Future run(List arguments) async { foundError(['The analyze.dart script must be run with --enable-asserts.']); } + printProgress('TargetPlatform tool/framework consistency'); + await verifyTargetPlatform(flutterRoot); + printProgress('No Double.clamp'); await verifyNoDoubleClamp(flutterRoot); @@ -266,6 +269,84 @@ class _DoubleClampVisitor extends RecursiveAstVisitor { } } +Future verifyTargetPlatform(String workingDirectory) async { + final File framework = File('$workingDirectory/packages/flutter/lib/src/foundation/platform.dart'); + final Set frameworkPlatforms = {}; + List lines = framework.readAsLinesSync(); + int index = 0; + while (true) { + if (index >= lines.length) { + foundError(['${framework.path}: Can no longer find TargetPlatform enum.']); + return; + } + if (lines[index].startsWith('enum TargetPlatform {')) { + index += 1; + break; + } + index += 1; + } + while (true) { + if (index >= lines.length) { + foundError(['${framework.path}: Could not find end of TargetPlatform enum.']); + return; + } + String line = lines[index].trim(); + final int comment = line.indexOf('//'); + if (comment >= 0) { + line = line.substring(0, comment); + } + if (line == '}') { + break; + } + if (line.isNotEmpty) { + if (line.endsWith(',')) { + frameworkPlatforms.add(line.substring(0, line.length - 1)); + } else { + foundError(['${framework.path}:$index: unparseable line when looking for TargetPlatform values']); + } + } + index += 1; + } + final File tool = File('$workingDirectory/packages/flutter_tools/lib/src/resident_runner.dart'); + final Set toolPlatforms = {}; + lines = tool.readAsLinesSync(); + index = 0; + while (true) { + if (index >= lines.length) { + foundError(['${tool.path}: Can no longer find nextPlatform logic.']); + return; + } + if (lines[index].trim().startsWith('const List platforms = [')) { + index += 1; + break; + } + index += 1; + } + while (true) { + if (index >= lines.length) { + foundError(['${tool.path}: Could not find end of nextPlatform logic.']); + return; + } + final String line = lines[index].trim(); + if (line.startsWith("'") && line.endsWith("',")) { + toolPlatforms.add(line.substring(1, line.length - 2)); + } else if (line == '];') { + break; + } else { + foundError(['${tool.path}:$index: unparseable line when looking for nextPlatform values']); + } + index += 1; + } + final Set frameworkExtra = frameworkPlatforms.difference(toolPlatforms); + if (frameworkExtra.isNotEmpty) { + foundError(['TargetPlatform has some extra values not found in the tool: ${frameworkExtra.join(", ")}']); + } + final Set toolExtra = toolPlatforms.difference(frameworkPlatforms); + if (toolExtra.isNotEmpty) { + foundError(['The nextPlatform logic in the tool has some extra values not found in TargetPlatform: ${toolExtra.join(", ")}']); + } +} + /// Verify that we use clampDouble instead of Double.clamp for performance reasons. /// /// We currently can't distinguish valid uses of clamp from problematic ones so diff --git a/packages/flutter/lib/src/foundation/binding.dart b/packages/flutter/lib/src/foundation/binding.dart index e898b808e5f1a..a663cf9716813 100644 --- a/packages/flutter/lib/src/foundation/binding.dart +++ b/packages/flutter/lib/src/foundation/binding.dart @@ -561,33 +561,22 @@ abstract class BindingBase { name: FoundationServiceExtensions.platformOverride.name, callback: (Map parameters) async { if (parameters.containsKey('value')) { - switch (parameters['value']) { - case 'android': - debugDefaultTargetPlatformOverride = TargetPlatform.android; - case 'fuchsia': - debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; - case 'iOS': - debugDefaultTargetPlatformOverride = TargetPlatform.iOS; - case 'linux': - debugDefaultTargetPlatformOverride = TargetPlatform.linux; - case 'macOS': - debugDefaultTargetPlatformOverride = TargetPlatform.macOS; - case 'windows': - debugDefaultTargetPlatformOverride = TargetPlatform.windows; - case 'default': - default: - debugDefaultTargetPlatformOverride = null; + final String value = parameters['value']!; + debugDefaultTargetPlatformOverride = null; + for (final TargetPlatform candidate in TargetPlatform.values) { + if (candidate.name == value) { + debugDefaultTargetPlatformOverride = candidate; + break; + } } _postExtensionStateChangedEvent( FoundationServiceExtensions.platformOverride.name, - defaultTargetPlatform.toString().substring('$TargetPlatform.'.length), + defaultTargetPlatform.name, ); await reassembleApplication(); } return { - 'value': defaultTargetPlatform - .toString() - .substring('$TargetPlatform.'.length), + 'value': defaultTargetPlatform.name, }; }, ); diff --git a/packages/flutter/lib/src/foundation/platform.dart b/packages/flutter/lib/src/foundation/platform.dart index d01d0305c9925..60d90b22d7730 100644 --- a/packages/flutter/lib/src/foundation/platform.dart +++ b/packages/flutter/lib/src/foundation/platform.dart @@ -35,7 +35,7 @@ import '_platform_io.dart' // // When adding support for a new platform (e.g. Windows Phone, Raspberry Pi), // first create a new value on the [TargetPlatform] enum, then add a rule for -// selecting that platform here. +// selecting that platform in `_platform_io.dart` and `_platform_web.dart`. // // It would be incorrect to make a platform that isn't supported by // [TargetPlatform] default to the behavior of another platform, because doing @@ -47,6 +47,15 @@ TargetPlatform get defaultTargetPlatform => platform.defaultTargetPlatform; /// The platform that user interaction should adapt to target. /// /// The [defaultTargetPlatform] getter returns the current platform. +/// +/// When using the "flutter run" command, the "o" key will toggle between +/// values of this enum when updating [debugDefaultTargetPlatformOverride]. +/// This lets one test how the application will work on various platforms +/// without having to switch emulators or physical devices. +// +// When you add values here, make sure to also add them to +// nextPlatform() in flutter_tools/lib/src/resident_runner.dart so that +// the tool can support the new platform for its "o" option. enum TargetPlatform { /// Android: android, diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index a3de310f5a612..ec1d2f4e60605 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -1877,19 +1877,17 @@ class DebugConnectionInfo { /// These values must match what is available in /// `packages/flutter/lib/src/foundation/binding.dart`. String nextPlatform(String currentPlatform) { - switch (currentPlatform) { - case 'android': - return 'iOS'; - case 'iOS': - return 'fuchsia'; - case 'fuchsia': - return 'macOS'; - case 'macOS': - return 'android'; - default: - assert(false); // Invalid current platform. - return 'android'; - } + const List platforms = [ + 'android', + 'iOS', + 'windows', + 'macOS', + 'linux', + 'fuchsia', + ]; + final int index = platforms.indexOf(currentPlatform); + assert(index >= 0, 'unknown platform "$currentPlatform"'); + return platforms[(index + 1) % platforms.length]; } /// A launcher for the devtools debugger and analysis tool. diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 6723487850953..bd93c7c85fca5 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -2210,9 +2210,11 @@ flutter: testUsingContext('nextPlatform moves through expected platforms', () { expect(nextPlatform('android'), 'iOS'); - expect(nextPlatform('iOS'), 'fuchsia'); - expect(nextPlatform('fuchsia'), 'macOS'); - expect(nextPlatform('macOS'), 'android'); + expect(nextPlatform('iOS'), 'windows'); + expect(nextPlatform('windows'), 'macOS'); + expect(nextPlatform('macOS'), 'linux'); + expect(nextPlatform('linux'), 'fuchsia'); + expect(nextPlatform('fuchsia'), 'android'); expect(() => nextPlatform('unknown'), throwsAssertionError); }); diff --git a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart index e234825ede40e..e6a38e5d39ae3 100644 --- a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart +++ b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart @@ -464,10 +464,10 @@ void main() { method: 'ext.flutter.platformOverride', args: { 'isolateId': '1', - 'value': 'fuchsia', + 'value': 'windows', }, jsonResponse: { - 'value': 'fuchsia', + 'value': 'windows', }, ), // Request 2. @@ -496,7 +496,7 @@ void main() { await terminalHandler.processTerminalInput('o'); await terminalHandler.processTerminalInput('O'); - expect(terminalHandler.logger.statusText, contains('Switched operating system to fuchsia')); + expect(terminalHandler.logger.statusText, contains('Switched operating system to windows')); expect(terminalHandler.logger.statusText, contains('Switched operating system to iOS')); }); @@ -518,10 +518,10 @@ void main() { method: 'ext.flutter.platformOverride', args: { 'isolateId': '1', - 'value': 'fuchsia', + 'value': 'windows', }, jsonResponse: { - 'value': 'fuchsia', + 'value': 'windows', }, ), // Request 2. @@ -550,7 +550,7 @@ void main() { await terminalHandler.processTerminalInput('o'); await terminalHandler.processTerminalInput('O'); - expect(terminalHandler.logger.statusText, contains('Switched operating system to fuchsia')); + expect(terminalHandler.logger.statusText, contains('Switched operating system to windows')); expect(terminalHandler.logger.statusText, contains('Switched operating system to iOS')); }); From d387f551a79f7e7ad83dc2c3a5a44f6481d58748 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 22:25:25 +0000 Subject: [PATCH 0884/1547] Bump actions/checkout from 3.5.3 to 3.6.0 (#133281) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0.
    Release notes

    Sourced from actions/checkout's releases.

    v3.6.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/checkout/compare/v3.5.3...v3.6.0

    Changelog

    Sourced from actions/checkout's changelog.

    Changelog

    v3.6.0

    v3.5.3

    v3.5.2

    v3.5.1

    v3.5.0

    v3.4.0

    v3.3.0

    v3.2.0

    v3.1.0

    v3.0.2

    v3.0.1

    v3.0.0

    ... (truncated)

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=3.5.3&new-version=3.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- .github/workflows/coverage.yml | 2 +- .github/workflows/scorecards-analysis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ff34165310d01..a1a23a0dbd350 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest if: ${{ github.repository == 'flutter/flutter' }} steps: - - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - name: ./bin/flutter test --coverage run: pushd packages/flutter;../../bin/flutter test --coverage -j 1;popd - name: upload coverage diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 1f96e564eff4e..05fec9a14f639 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 with: persist-credentials: false From c8b9ae50091584327e99bbb603c4762910896581 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 24 Aug 2023 20:40:32 -0400 Subject: [PATCH 0885/1547] Roll Flutter Engine from 965501a25d92 to b8ec4da8866c (11 revisions) (#133296) https://github.com/flutter/engine/compare/965501a25d92...b8ec4da8866c 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 99a76ea8e1b2 to 1428f16fc0de (1 revision) (flutter/engine#45086) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 25fafff5b32c to 99a76ea8e1b2 (2 revisions) (flutter/engine#45083) 2023-08-24 jacksongardner@google.com Revert "Turn on the `skia_enable_optimize_size` flag to save a bit of binary size" (flutter/engine#45082) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from d7d56885a49b to 25fafff5b32c (1 revision) (flutter/engine#45081) 2023-08-24 dnfield@google.com [Impeller] Do not build scene unless 3d define is true (flutter/engine#45028) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 177e8477faf9 to d7d56885a49b (1 revision) (flutter/engine#45078) 2023-08-24 dkwingsmt@users.noreply.github.com Reland: [Rasterizer] Make resubmit information temporary (flutter/engine#45037) 2023-08-24 34871572+gmackall@users.noreply.github.com Add case checking to android sdk cipd upload script (flutter/engine#45063) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from 007386294889 to 177e8477faf9 (1 revision) (flutter/engine#45076) 2023-08-24 jacksongardner@google.com Turn on the `skia_enable_optimize_size` flag to save a bit of binary size (flutter/engine#45029) 2023-08-24 skia-flutter-autoroll@skia.org Roll Skia from b17ee34f3378 to 007386294889 (1 revision) (flutter/engine#45075) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 698b0e4c00ebc..d91c7098c828c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -965501a25d9216701c43332a55e577d78bf7658d +b8ec4da8866cda0a92e3268f439944185f19c769 From 865b5b483187357787c93ecb5f0e8f44e0e0fad0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 24 Aug 2023 22:05:35 -0400 Subject: [PATCH 0886/1547] Roll Flutter Engine from b8ec4da8866c to 1382d6d79408 (1 revision) (#133298) https://github.com/flutter/engine/compare/b8ec4da8866c...1382d6d79408 2023-08-25 flar@google.com Reland "Split DisplayListBuilder into DlCanvas optimizer and DlOp recorder classes #44718" (flutter/engine#45085) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d91c7098c828c..a38f92d1e3a7a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b8ec4da8866cda0a92e3268f439944185f19c769 +1382d6d794087cfb34afdfa89f18b73bd04ca297 From 22a61b947f3f256ac5193bb93b189c5d980f6610 Mon Sep 17 00:00:00 2001 From: Lau Ching Jun Date: Thu, 24 Aug 2023 21:26:56 -0700 Subject: [PATCH 0887/1547] Allow passing verbose log from flutter daemon. (#132828) It would be helpful for debugging if we can choose to also receive remote verbose logs. --- .../lib/src/commands/daemon.dart | 16 ++++- .../commands.shard/hermetic/daemon_test.dart | 70 +++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index ab1659fecb95e..b63a9acdbb3c3 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -335,6 +335,7 @@ class DaemonDomain extends Domain { registerHandler('version', version); registerHandler('shutdown', shutdown); registerHandler('getSupportedPlatforms', getSupportedPlatforms); + registerHandler('setNotifyVerbose', setNotifyVerbose); sendEvent( 'daemon.connected', @@ -346,7 +347,7 @@ class DaemonDomain extends Domain { _subscription = daemon.notifyingLogger!.onMessage.listen((LogMessage message) { if (daemon.logToStdout) { - if (message.level == 'status') { + if (message.level == 'status' || message.level == 'trace') { // We use `print()` here instead of `stdout.writeln()` in order to // capture the print output for testing. // ignore: avoid_print @@ -461,6 +462,11 @@ class DaemonDomain extends Domain { }; } } + + /// If notifyVerbose is set, the daemon will forward all verbose logs. + Future setNotifyVerbose(Map args) async { + daemon.notifyingLogger?.notifyVerbose = _getBoolArg(args, 'verbose') ?? true; + } } typedef RunOrAttach = Future Function({ @@ -1210,7 +1216,7 @@ Object? _toJsonable(Object? obj) { } class NotifyingLogger extends DelegatingLogger { - NotifyingLogger({ required this.verbose, required Logger parent }) : super(parent) { + NotifyingLogger({ required this.verbose, required Logger parent, this.notifyVerbose = false }) : super(parent) { _messageController = StreamController.broadcast( onListen: _onListen, ); @@ -1220,6 +1226,8 @@ class NotifyingLogger extends DelegatingLogger { final List messageBuffer = []; late StreamController _messageController; + bool notifyVerbose = false; + void _onListen() { if (messageBuffer.isNotEmpty) { messageBuffer.forEach(_messageController.add); @@ -1277,6 +1285,10 @@ class NotifyingLogger extends DelegatingLogger { @override void printTrace(String message) { + if (notifyVerbose) { + _sendMessage(LogMessage('trace', message)); + return; + } if (!verbose) { return; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart index f0e1e4fc50c62..63f8f1fdea815 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart @@ -195,6 +195,63 @@ void main() { Logger: () => notifyingLogger, }); + testUsingContext('printTrace should send daemon.logMessage event when notifyVerbose is enabled', () async { + daemon = Daemon( + daemonConnection, + notifyingLogger: notifyingLogger, + ); + notifyingLogger.notifyVerbose = false; + globals.printTrace('daemon.logMessage test 1'); + notifyingLogger.notifyVerbose = true; + globals.printTrace('daemon.logMessage test 2'); + final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage message) { + return message.data['event'] == 'daemon.logMessage' && (message.data['params']! as Map)['level'] == 'trace'; + }); + expect(response.data['id'], isNull); + expect(response.data['event'], 'daemon.logMessage'); + final Map logMessage = castStringKeyedMap(response.data['params'])!.cast(); + expect(logMessage['level'], 'trace'); + expect(logMessage['message'], 'daemon.logMessage test 2'); + }, overrides: { + Logger: () => notifyingLogger, + }); + + testUsingContext('daemon.setNotifyVerbose command should update the notify verbose status to true', () async { + daemon = Daemon( + daemonConnection, + notifyingLogger: notifyingLogger, + ); + expect(notifyingLogger.notifyVerbose, false); + + daemonStreams.inputs.add(DaemonMessage({ + 'id': 0, + 'method': 'daemon.setNotifyVerbose', + 'params': { + 'verbose': true, + }, + })); + await daemonStreams.outputs.stream.firstWhere(_notEvent); + expect(notifyingLogger.notifyVerbose, true); + }); + + testUsingContext('daemon.setNotifyVerbose command should update the notify verbose status to false', () async { + daemon = Daemon( + daemonConnection, + notifyingLogger: notifyingLogger, + ); + notifyingLogger.notifyVerbose = false; + + daemonStreams.inputs.add(DaemonMessage({ + 'id': 0, + 'method': 'daemon.setNotifyVerbose', + 'params': { + 'verbose': false, + }, + })); + await daemonStreams.outputs.stream.firstWhere(_notEvent); + expect(notifyingLogger.notifyVerbose, false); + }); + testUsingContext('daemon.shutdown command should stop daemon', () async { daemon = Daemon( daemonConnection, @@ -755,6 +812,19 @@ void main() { expect(bufferLogger.errorText, isEmpty); }); + testUsingContext('sends trace messages in notify verbose mode', () async { + final NotifyingLogger logger = NotifyingLogger(verbose: false, parent: bufferLogger, notifyVerbose: true); + + final Future messageResult = logger.onMessage.first; + logger.printTrace('hello'); + + final LogMessage message = await messageResult; + + expect(message.level, 'trace'); + expect(message.message, 'hello'); + expect(bufferLogger.errorText, isEmpty); + }); + testUsingContext('buffers messages sent before a subscription', () async { final NotifyingLogger logger = NotifyingLogger(verbose: false, parent: bufferLogger); From 3aca26edec28af39a4f854e690e3e7c89077d82a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 01:01:31 -0400 Subject: [PATCH 0888/1547] Roll Flutter Engine from 1382d6d79408 to 9bcefc74b772 (2 revisions) (#133305) https://github.com/flutter/engine/compare/1382d6d79408...9bcefc74b772 2023-08-25 zanderso@users.noreply.github.com Revert ios cpu changes (flutter/engine#45095) 2023-08-25 30870216+gaaclarke@users.noreply.github.com [Impeller] Refactor: Create attachment descriptions without setting layouts (flutter/engine#45088) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a38f92d1e3a7a..3374fe1a13670 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1382d6d794087cfb34afdfa89f18b73bd04ca297 +9bcefc74b772d1a31678011b416c30be96c120fe From 9ab8d27a2c0ad90072e2337fac9ccee35d2f9b8c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 02:27:12 -0400 Subject: [PATCH 0889/1547] Roll Flutter Engine from 9bcefc74b772 to 09e620d26834 (1 revision) (#133307) https://github.com/flutter/engine/compare/9bcefc74b772...09e620d26834 2023-08-25 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 0kEa4JczTMD0Xus08... to R_deCnScH70FbSeii... (flutter/engine#45096) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 0kEa4JczTMD0 to R_deCnScH70F If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3374fe1a13670..bfe1439c47ea2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9bcefc74b772d1a31678011b416c30be96c120fe +09e620d26834475cc10d5f24198ebae7cd87c793 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 8b798535fb735..71b222cad0c72 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -0kEa4JczTMD0Xus08aFASyutpbphg0hMC0EqbOwjcRUC +R_deCnScH70FbSeiihSu6SbWh9b-3dhoFwF2veJPIG8C From 3c1dd2f9fa56fbe33b6572f361e695db0b622e9a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 03:05:27 -0400 Subject: [PATCH 0890/1547] Roll Flutter Engine from 09e620d26834 to 0f8962208a44 (2 revisions) (#133309) https://github.com/flutter/engine/compare/09e620d26834...0f8962208a44 2023-08-25 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from jkVyhV_xfb8Mv43xj... to 4LHUJjNlDT21v_pdT... (flutter/engine#45100) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 1428f16fc0de to 5a1b6567544c (1 revision) (flutter/engine#45099) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from jkVyhV_xfb8M to 4LHUJjNlDT21 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bfe1439c47ea2..eb7faf3b196e8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09e620d26834475cc10d5f24198ebae7cd87c793 +0f8962208a446bc6f0f452522185c0002d3cec01 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 56081abc93e99..8d467caedce04 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -jkVyhV_xfb8Mv43xjXG7mCqcFhF4nOLIt-09DcU4YP4C +4LHUJjNlDT21v_pdTCXu00_kXfo-jPVXux859BpEX-YC From 901a392ae5bd1bfa657b1c85f63d4924604e0715 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 07:23:26 -0400 Subject: [PATCH 0891/1547] Roll Flutter Engine from 0f8962208a44 to cb58abd77326 (3 revisions) (#133320) https://github.com/flutter/engine/compare/0f8962208a44...cb58abd77326 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from f867f82cc758 to 8a26fe31389d (1 revision) (flutter/engine#45104) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 5a1b6567544c to f867f82cc758 (2 revisions) (flutter/engine#45102) 2023-08-25 ian@hixie.ch FontVariation.lerp, custom FontVariation constructors, and more documentation (flutter/engine#45030) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index eb7faf3b196e8..360e042d9f055 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0f8962208a446bc6f0f452522185c0002d3cec01 +cb58abd773268d62008120f270759cb9a3904f11 From 5c17a37b0b3682a1bebec006efdea18026b3c48e Mon Sep 17 00:00:00 2001 From: Tomasz Gucio <72562119+tgucio@users.noreply.github.com> Date: Fri, 25 Aug 2023 14:35:49 +0200 Subject: [PATCH 0892/1547] Dispose overlay entries (#132826) --- examples/api/lib/widgets/overlay/overlay.0.dart | 1 + packages/flutter/lib/src/cupertino/context_menu.dart | 2 ++ packages/flutter/lib/src/material/range_slider.dart | 12 ++++++------ packages/flutter/lib/src/material/slider.dart | 12 ++++++------ packages/flutter/lib/src/widgets/autocomplete.dart | 2 ++ packages/flutter/lib/src/widgets/heroes.dart | 1 + packages/flutter/lib/src/widgets/magnifier.dart | 8 ++++---- .../flutter/lib/src/widgets/reorderable_list.dart | 1 + 8 files changed, 23 insertions(+), 16 deletions(-) diff --git a/examples/api/lib/widgets/overlay/overlay.0.dart b/examples/api/lib/widgets/overlay/overlay.0.dart index 41a769c9e8563..2a69e58f3d8a9 100644 --- a/examples/api/lib/widgets/overlay/overlay.0.dart +++ b/examples/api/lib/widgets/overlay/overlay.0.dart @@ -138,6 +138,7 @@ class _OverlayExampleState extends State { // Remove the OverlayEntry. void removeHighlightOverlay() { overlayEntry?.remove(); + overlayEntry?.dispose(); overlayEntry = null; } diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index da2aed2a092a8..113e923ab308f 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -572,6 +572,7 @@ class _CupertinoContextMenuState extends State with Ticker }); } _lastOverlayEntry?.remove(); + _lastOverlayEntry?.dispose(); _lastOverlayEntry = null; case AnimationStatus.completed: @@ -585,6 +586,7 @@ class _CupertinoContextMenuState extends State with Ticker // one frame. SchedulerBinding.instance.addPostFrameCallback((Duration _) { _lastOverlayEntry?.remove(); + _lastOverlayEntry?.dispose(); _lastOverlayEntry = null; _openController.reset(); }); diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index 99677cfff7560..c21c6b8ae6921 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -484,10 +484,9 @@ class _RangeSliderState extends State with TickerProviderStateMixin enableController.dispose(); startPositionController.dispose(); endPositionController.dispose(); - if (overlayEntry != null) { - overlayEntry!.remove(); - overlayEntry = null; - } + overlayEntry?.remove(); + overlayEntry?.dispose(); + overlayEntry = null; super.dispose(); } @@ -842,8 +841,9 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix parent: _state.valueIndicatorController, curve: Curves.fastOutSlowIn, )..addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.dismissed && _state.overlayEntry != null) { - _state.overlayEntry!.remove(); + if (status == AnimationStatus.dismissed) { + _state.overlayEntry?.remove(); + _state.overlayEntry?.dispose(); _state.overlayEntry = null; } }); diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 34b806c87c64e..c28a03bec17cb 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -654,10 +654,9 @@ class _SliderState extends State with TickerProviderStateMixin { valueIndicatorController.dispose(); enableController.dispose(); positionController.dispose(); - if (overlayEntry != null) { - overlayEntry!.remove(); - overlayEntry = null; - } + overlayEntry?.remove(); + overlayEntry?.dispose(); + overlayEntry = null; _focusNode?.dispose(); super.dispose(); } @@ -1116,8 +1115,9 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { parent: _state.valueIndicatorController, curve: Curves.fastOutSlowIn, )..addStatusListener((AnimationStatus status) { - if (status == AnimationStatus.dismissed && _state.overlayEntry != null) { - _state.overlayEntry!.remove(); + if (status == AnimationStatus.dismissed) { + _state.overlayEntry?.remove(); + _state.overlayEntry?.dispose(); _state.overlayEntry = null; } }); diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index c46d65d621234..9f6e226b5281f 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -446,6 +446,7 @@ class _RawAutocompleteState extends State> } _floatingOptions?.remove(); + _floatingOptions?.dispose(); if (_shouldShowOptions) { final OverlayEntry newFloatingOptions = OverlayEntry( builder: (BuildContext context) { @@ -562,6 +563,7 @@ class _RawAutocompleteState extends State> _focusNode.dispose(); } _floatingOptions?.remove(); + _floatingOptions?.dispose(); _floatingOptions = null; super.dispose(); } diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart index ca5e6d5f23063..3970b5e63fb79 100644 --- a/packages/flutter/lib/src/widgets/heroes.dart +++ b/packages/flutter/lib/src/widgets/heroes.dart @@ -568,6 +568,7 @@ class _HeroFlight { assert(overlayEntry != null); overlayEntry!.remove(); + overlayEntry!.dispose(); overlayEntry = null; // We want to keep the hero underneath the current page hidden. If // [AnimationStatus.completed], toHero will be the one on top and we keep diff --git a/packages/flutter/lib/src/widgets/magnifier.dart b/packages/flutter/lib/src/widgets/magnifier.dart index 74ef957a3b78e..ea598e90a903a 100644 --- a/packages/flutter/lib/src/widgets/magnifier.dart +++ b/packages/flutter/lib/src/widgets/magnifier.dart @@ -242,9 +242,8 @@ class MagnifierController { Widget? debugRequiredFor, OverlayEntry? below, }) async { - if (overlayEntry != null) { - overlayEntry!.remove(); - } + _overlayEntry?.remove(); + _overlayEntry?.dispose(); final OverlayState overlayState = Overlay.of( context, @@ -257,7 +256,7 @@ class MagnifierController { to: Navigator.maybeOf(context)?.context, ); - _overlayEntry = OverlayEntry( + _overlayEntry = OverlayEntry( builder: (BuildContext context) => capturedThemes.wrap(builder(context)), ); overlayState.insert(overlayEntry!, below: below); @@ -307,6 +306,7 @@ class MagnifierController { @visibleForTesting void removeFromOverlay() { _overlayEntry?.remove(); + _overlayEntry?.dispose(); _overlayEntry = null; } diff --git a/packages/flutter/lib/src/widgets/reorderable_list.dart b/packages/flutter/lib/src/widgets/reorderable_list.dart index cb9de37dec10d..bfb07016e7348 100644 --- a/packages/flutter/lib/src/widgets/reorderable_list.dart +++ b/packages/flutter/lib/src/widgets/reorderable_list.dart @@ -832,6 +832,7 @@ class SliverReorderableListState extends State with Ticke _recognizer?.dispose(); _recognizer = null; _overlayEntry?.remove(); + _overlayEntry?.dispose(); _overlayEntry = null; _finalDropPosition = null; } From 612117a690e3e1c27d0d53a7a4e5d8e5c420c61e Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 25 Aug 2023 17:47:08 +0300 Subject: [PATCH 0893/1547] Fix `Chip.shape`'s side is not used when provided in Material 3 (#132941) fixes [Chip border side color not working in Material3](https://github.com/flutter/flutter/issues/132922) ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( useMaterial3: true, chipTheme: const ChipThemeData( // shape: RoundedRectangleBorder( // side: BorderSide(color: Colors.amber), // borderRadius: BorderRadius.all(Radius.circular(12)), // ), // side: BorderSide(color: Colors.red), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return const Scaffold( body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), // side: BorderSide(color: Colors.red), label: Text('Chip'), ), ), ); } } ```
    --- ### Before When `RawChip.shape` is provided with a `BorderSide`. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 54 54](https://github.com/flutter/flutter/assets/48603081/89e2c9b5-44c2-432e-97ff-8bb95b0d0fb1) When `RawChip.shape` is provided with a `BorderSide` and also `RawChip.side` is provided. The `RawChip.side` overrides the shape's side. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), side: BorderSide(color: Colors.red), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 55 37](https://github.com/flutter/flutter/assets/48603081/938803cc-d514-464b-b06b-e4841b9ad040) --- ### After When `RawChip.shape` is provided with a `BorderSide`. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 51 29](https://github.com/flutter/flutter/assets/48603081/d6fcaaa9-8f5d-4180-ad14-062dd459ec45) When `RawChip.shape` is provided with a `BorderSide` and also `RawChip.side` is provided. The `RawChip.side` overrides the shape's side. ```dart body: Center( child: RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), borderRadius: BorderRadius.all(Radius.circular(12)), ), side: BorderSide(color: Colors.red), label: Text('Chip'), ), ), ``` ![Screenshot 2023-08-24 at 17 52 31](https://github.com/flutter/flutter/assets/48603081/3fa46341-43f0-4fe7-a922-f1d8ba34028c) --- --- dev/tools/gen_defaults/lib/chip_template.dart | 11 ++-- packages/flutter/lib/src/material/chip.dart | 12 ++-- packages/flutter/test/material/chip_test.dart | 54 +++++++++++++++++ .../test/material/chip_theme_test.dart | 58 +++++++++++++++++++ 4 files changed, 127 insertions(+), 8 deletions(-) diff --git a/dev/tools/gen_defaults/lib/chip_template.dart b/dev/tools/gen_defaults/lib/chip_template.dart index 4d9383399d16d..cdbe10362c11f 100644 --- a/dev/tools/gen_defaults/lib/chip_template.dart +++ b/dev/tools/gen_defaults/lib/chip_template.dart @@ -19,7 +19,6 @@ class _${blockName}DefaultsM3 extends ChipThemeData { _${blockName}DefaultsM3(this.context, this.isEnabled) : super( elevation: ${elevation("$tokenGroup$variant.container")}, - shape: ${shape("$tokenGroup.container")}, showCheckmark: true, ); @@ -47,9 +46,13 @@ class _${blockName}DefaultsM3 extends ChipThemeData { Color? get deleteIconColor => ${color("$tokenGroup.with-icon.selected.icon.color")}; @override - BorderSide? get side => isEnabled - ? ${border('$tokenGroup$variant.outline')} - : ${border('$tokenGroup$variant.disabled.outline')}; + OutlinedBorder? get shape { + return ${shape("$tokenGroup.container")}.copyWith( + side: isEnabled + ? ${border('$tokenGroup$variant.outline')} + : ${border('$tokenGroup$variant.disabled.outline')}, + ); + } @override IconThemeData? get iconTheme => IconThemeData( diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 3e1eb6d7bacf1..65ee8909eb0c9 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -997,6 +997,7 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs(widget.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipTheme.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipDefaults.shape, materialStates) + // TODO(tahatesser): Remove this fallback when Material 2 is deprecated. ?? const StadiumBorder(); return resolvedShape.copyWith(side: resolvedSide); } @@ -2234,7 +2235,6 @@ class _ChipDefaultsM3 extends ChipThemeData { _ChipDefaultsM3(this.context, this.isEnabled) : super( elevation: 0.0, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), showCheckmark: true, ); @@ -2262,9 +2262,13 @@ class _ChipDefaultsM3 extends ChipThemeData { Color? get deleteIconColor => null; @override - BorderSide? get side => isEnabled - ? BorderSide(color: _colors.outline) - : BorderSide(color: _colors.onSurface.withOpacity(0.12)); + OutlinedBorder? get shape { + return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))).copyWith( + side: isEnabled + ? BorderSide(color: _colors.outline) + : BorderSide(color: _colors.onSurface.withOpacity(0.12)), + ); + } @override IconThemeData? get iconTheme => IconThemeData( diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index d098936aa14e3..9f369c2ffa3a0 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -3503,6 +3503,60 @@ void main() { expect(calledDelete, isTrue); }); + testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { + Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: RawChip( + shape: shape, + side: side, + label: const Text('RawChip'), + ), + ), + ), + ); + } + + // Test [RawChip.shape] with a side. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + )), + ); + + // Chip should have the provided shape and the side from [RawChip.shape]. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + + // Test [RawChip.shape] with a side and [RawChip.side]. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + side: const BorderSide(color: Color(0xfffff000))), + ); + await tester.pumpAndSettle(); + + // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. + // [RawChip.shape]'s side should be ignored. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffff000)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 2303b56478cd3..4ff0c5c31773e 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -928,6 +928,64 @@ void main() { )), ); }); + + testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { + Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { + return MaterialApp( + theme: ThemeData( + useMaterial3: true, + chipTheme: ChipThemeData( + shape: shape, + side: side, + ), + ), + home: const Material( + child: Center( + child: RawChip( + label: Text('RawChip'), + ), + ), + ), + ); + } + + // Test [RawChip.shape] with a side. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + )), + ); + + // Chip should have the provided shape and the side from [RawChip.shape]. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + + // Test [RawChip.shape] with a side and [RawChip.side]. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + side: const BorderSide(color: Color(0xfffff000))), + ); + await tester.pumpAndSettle(); + + // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. + // [RawChip.shape]'s side should be ignored. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffff000)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + }); } class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder { From ea005219394211bea4c2b87011699c63cfabb115 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Fri, 25 Aug 2023 17:49:04 +0300 Subject: [PATCH 0894/1547] Fix `PopupMenuItem` with a `ListTile` doesn't use the correct style. (#133141) fixes [`PopupMenuItem` with a `ListTile` doesn't use the correct text style.](https://github.com/flutter/flutter/issues/133138) ### Description This fixes an issue text style issue for `PopupMenuItem` with a `ListTile` (for an elaborate popup menu) https://api.flutter.dev/flutter/material/PopupMenuItem-class.html
    expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [PopupMenuButton]. // This is the type used by the popup menu below. enum SampleItem { itemOne, itemTwo, itemThree } void main() => runApp(const PopupMenuApp()); class PopupMenuApp extends StatelessWidget { const PopupMenuApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( useMaterial3: true, textTheme: const TextTheme( labelLarge: TextStyle( fontStyle: FontStyle.italic, fontWeight: FontWeight.bold, ), ), ), home: const PopupMenuExample(), ); } } class PopupMenuExample extends StatefulWidget { const PopupMenuExample({super.key}); @override State createState() => _PopupMenuExampleState(); } class _PopupMenuExampleState extends State { SampleItem? selectedMenu; @override Widget build(BuildContext context) { return Scaffold( body: Center( child: SizedBox( width: 300, height: 130, child: Align( alignment: Alignment.topLeft, child: PopupMenuButton( initialValue: selectedMenu, // Callback that sets the selected popup menu item. onSelected: (SampleItem item) { setState(() { selectedMenu = item; }); }, itemBuilder: (BuildContext context) => >[ const PopupMenuItem( value: SampleItem.itemOne, child: Text('PopupMenuItem'), ), const CheckedPopupMenuItem( checked: true, value: SampleItem.itemTwo, child: Text('CheckedPopupMenuItem'), ), const PopupMenuItem( value: SampleItem.itemOne, child: ListTile( leading: Icon(Icons.cloud), title: Text('ListTile'), contentPadding: EdgeInsets.zero, trailing: Icon(Icons.arrow_right_rounded), ), ), ], ), ), ), ), ); } } ```
    ### Before ![Screenshot 2023-08-23 at 14 08 48](https://github.com/flutter/flutter/assets/48603081/434ac95e-2981-4ab5-9843-939b39d771a2) ### After ![Screenshot 2023-08-23 at 14 08 32](https://github.com/flutter/flutter/assets/48603081/f6aba7e0-3d03-454f-8e0b-c031492f3f2d) --- .../flutter/lib/src/material/popup_menu.dart | 1 + .../test/material/popup_menu_test.dart | 178 ++++++++++++++++-- 2 files changed, 168 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 7a3f7a5249bff..cc87623e63305 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -399,6 +399,7 @@ class PopupMenuItemState> extends State { mouseCursor: _EffectiveMouseCursor(widget.mouseCursor, popupMenuTheme.mouseCursor), child: ListTileTheme.merge( contentPadding: EdgeInsets.zero, + titleTextStyle: style, child: item, ), ), diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 60c576797dcd8..1bfb2e028f868 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -3423,14 +3423,14 @@ void main() { await tester.tapAt(const Offset(20.0, 20.0)); await tester.pumpAndSettle(); - // Test custom text theme text style. + // Test custom text theme. + const TextStyle customTextStyle = TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ); theme = theme.copyWith( - textTheme: theme.textTheme.copyWith( - labelLarge: const TextStyle( - fontSize: 20.0, - fontWeight: FontWeight.bold, - ) - ), + textTheme: const TextTheme(labelLarge: customTextStyle), ); await tester.pumpWidget(buildMenu()); @@ -3438,8 +3438,10 @@ void main() { await tester.tap(find.byKey(popupMenuButtonKey)); await tester.pumpAndSettle(); - expect(_labelStyle(tester, 'Item 1')!.fontSize, 20.0); - expect(_labelStyle(tester, 'Item 1')!.fontWeight, FontWeight.bold); + // Test custom text theme. + expect(_labelStyle(tester, 'Item 1')!.fontSize, customTextStyle.fontSize); + expect(_labelStyle(tester, 'Item 1')!.fontWeight, customTextStyle.fontWeight); + expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); }); testWidgets('CheckedPopupMenuItem.labelTextStyle resolve material states', (WidgetTester tester) async { @@ -3492,7 +3494,7 @@ void main() { ); }); - testWidgets('CheckedPopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { + testWidgets('CheckedPopupMenuItem overrides redundant ListTile.contentPadding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -3537,7 +3539,7 @@ void main() { expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); }); - testWidgets('PopupMenuItem overrides redundant ListTile content padding', (WidgetTester tester) async { + testWidgets('PopupMenuItem overrides redundant ListTile.contentPadding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -3581,6 +3583,160 @@ void main() { expect(getItemSafeArea('Item 0').minimum, EdgeInsets.zero); expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); }); + + testWidgets('Material3 - PopupMenuItem overrides ListTile.titleTextStyle', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + ThemeData theme = ThemeData(useMaterial3: true); + + Widget buildMenu() { + return MaterialApp( + theme: theme, + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + // Popup menu item with a Text widget. + const PopupMenuItem( + value: '0', + child: Text('Item 0'), + ), + // Popup menu item with a ListTile widget. + const PopupMenuItem( + value: '1', + child: ListTile(title: Text('Item 1')), + ), + ]; + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildMenu()); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + // Test popup menu item with a Text widget. + expect(_labelStyle(tester, 'Item 0')!.fontSize, 14.0); + expect(_labelStyle(tester, 'Item 0')!.color, theme.colorScheme.onSurface); + + // Test popup menu item with a ListTile widget. + expect(_labelStyle(tester, 'Item 1')!.fontSize, 14.0); + expect(_labelStyle(tester, 'Item 1')!.color, theme.colorScheme.onSurface); + + // Close the menu. + await tester.tapAt(const Offset(20.0, 20.0)); + await tester.pumpAndSettle(); + + // Test custom text theme. + const TextStyle customTextStyle = TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ); + theme = theme.copyWith( + textTheme: const TextTheme(labelLarge: customTextStyle), + ); + await tester.pumpWidget(buildMenu()); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + // Test popup menu item with a Text widget with custom text theme. + expect(_labelStyle(tester, 'Item 0')!.fontSize, customTextStyle.fontSize); + expect(_labelStyle(tester, 'Item 0')!.fontWeight, customTextStyle.fontWeight); + expect(_labelStyle(tester, 'Item 0')!.fontStyle, customTextStyle.fontStyle); + + // Test popup menu item with a ListTile widget with custom text theme. + expect(_labelStyle(tester, 'Item 1')!.fontSize, customTextStyle.fontSize); + expect(_labelStyle(tester, 'Item 1')!.fontWeight, customTextStyle.fontWeight); + expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); + }); + + testWidgets('Material2 - PopupMenuItem overrides ListTile.titleTextStyle', (WidgetTester tester) async { + final Key popupMenuButtonKey = UniqueKey(); + ThemeData theme = ThemeData(useMaterial3: false); + + Widget buildMenu() { + return MaterialApp( + theme: theme, + home: Scaffold( + body: Center( + child: PopupMenuButton( + key: popupMenuButtonKey, + child: const Text('button'), + onSelected: (String result) { }, + itemBuilder: (BuildContext context) { + return >[ + // Popup menu item with a Text widget. + const PopupMenuItem( + value: '0', + child: Text('Item 0'), + ), + // Popup menu item with a ListTile widget. + const PopupMenuItem( + value: '1', + child: ListTile(title: Text('Item 1')), + ), + ]; + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildMenu()); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + // Test popup menu item with a Text widget. + expect(_labelStyle(tester, 'Item 0')!.fontSize, 16.0); + expect(_labelStyle(tester, 'Item 0')!.color, theme.textTheme.subtitle1!.color); + + // Test popup menu item with a ListTile widget. + expect(_labelStyle(tester, 'Item 1')!.fontSize, 16.0); + expect(_labelStyle(tester, 'Item 1')!.color, theme.textTheme.subtitle1!.color); + + // Close the menu. + await tester.tapAt(const Offset(20.0, 20.0)); + await tester.pumpAndSettle(); + + // Test custom text theme. + const TextStyle customTextStyle = TextStyle( + fontSize: 20.0, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ); + theme = theme.copyWith( + textTheme: const TextTheme(subtitle1: customTextStyle), + ); + await tester.pumpWidget(buildMenu()); + + // Show the menu. + await tester.tap(find.byKey(popupMenuButtonKey)); + await tester.pumpAndSettle(); + + // Test popup menu item with a Text widget with custom text style. + expect(_labelStyle(tester, 'Item 0')!.fontSize, customTextStyle.fontSize); + expect(_labelStyle(tester, 'Item 0')!.fontWeight, customTextStyle.fontWeight); + expect(_labelStyle(tester, 'Item 0')!.fontStyle, customTextStyle.fontStyle); + + // Test popup menu item with a ListTile widget with custom text style. + expect(_labelStyle(tester, 'Item 1')!.fontSize, customTextStyle.fontSize); + expect(_labelStyle(tester, 'Item 1')!.fontWeight, customTextStyle.fontWeight); + expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); + }); } class TestApp extends StatelessWidget { From db22617b7292db24b9a24d024ae869c0d223e7b5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 13:19:02 -0400 Subject: [PATCH 0895/1547] Roll Flutter Engine from cb58abd77326 to 00f532dcaef4 (3 revisions) (#133333) https://github.com/flutter/engine/compare/cb58abd77326...00f532dcaef4 2023-08-25 godofredoc@google.com Remove cirrus build badge (flutter/engine#45103) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 8a26fe31389d to 4b30261160a2 (1 revision) (flutter/engine#45109) 2023-08-25 godofredoc@google.com Fix global tests doing nothing. (flutter/engine#45097) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 360e042d9f055..1a1a97919cffe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cb58abd773268d62008120f270759cb9a3904f11 +00f532dcaef468a890050f2a2b438aefc7187ad7 From b66fb2a4d983465ce55f04861c45e01d653cea4f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 14:03:13 -0400 Subject: [PATCH 0896/1547] Roll Flutter Engine from 00f532dcaef4 to 33fca02451ef (1 revision) (#133337) https://github.com/flutter/engine/compare/00f532dcaef4...33fca02451ef 2023-08-25 jonahwilliams@google.com [Impeller] fix validation warning on iOS/macOS when compiling external texture shader. (flutter/engine#45080) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1a1a97919cffe..c52dfcc28bac7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -00f532dcaef468a890050f2a2b438aefc7187ad7 +33fca02451ef314fc655634b116a7b6d1144b9f7 From 61d9f5566559639ef304f1d73f37e5dc63e28e60 Mon Sep 17 00:00:00 2001 From: Kenzie Davisson <43759233+kenzieschmoll@users.noreply.github.com> Date: Fri, 25 Aug 2023 11:03:35 -0700 Subject: [PATCH 0897/1547] Update flutter packages to pick up latest vm_service (#133335) Generated by running `flutter update-packages --force-upgrade` --- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/complex_layout/pubspec.yaml | 4 ++-- dev/benchmarks/macrobenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/microbenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 4 ++-- .../platform_channels_benchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_views_layout/pubspec.yaml | 4 ++-- .../pubspec.yaml | 4 ++-- dev/benchmarks/test_apps/stocks/pubspec.yaml | 4 ++-- dev/bots/pubspec.yaml | 8 ++++---- dev/conductor/core/pubspec.yaml | 4 ++-- dev/customer_testing/pubspec.yaml | 4 ++-- dev/devicelab/pubspec.yaml | 8 ++++---- .../android_semantics_testing/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 6 +++--- dev/integration_tests/channels/pubspec.yaml | 4 ++-- .../deferred_components_test/pubspec.yaml | 4 ++-- dev/integration_tests/external_ui/pubspec.yaml | 4 ++-- dev/integration_tests/flavors/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- .../gradle_deprecated_settings/pubspec.yaml | 4 ++-- .../hybrid_android_views/pubspec.yaml | 6 +++--- .../ios_platform_view_tests/pubspec.yaml | 4 ++-- .../platform_interaction/pubspec.yaml | 4 ++-- dev/integration_tests/release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- .../windows_startup_test/pubspec.yaml | 4 ++-- dev/tools/gen_defaults/pubspec.yaml | 4 ++-- dev/tools/gen_keycodes/pubspec.yaml | 4 ++-- dev/tools/pubspec.yaml | 4 ++-- dev/tools/vitool/pubspec.yaml | 6 +++--- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 5 +++-- examples/hello_world/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 4 ++-- examples/platform_channel_swift/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 4 ++-- packages/flutter/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_tools/pubspec.yaml | 10 +++++----- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 4 ++-- packages/integration_test/example/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 46 files changed, 103 insertions(+), 102 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index ead6706e5cebd..41def19d314f0 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -60,7 +60,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: e62c +# PUBSPEC CHECKSUM: e054 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index e3c9e2c19b4a5..3c92e17240663 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 9104 +# PUBSPEC CHECKSUM: 0c2c diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index c0d17d2e970e9..b70543f137319 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -210,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 9104 +# PUBSPEC CHECKSUM: 0c2c diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 031e6d636d415..f53ac6c2edc34 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -61,7 +61,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -137,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: c37b +# PUBSPEC CHECKSUM: 5ca3 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 5fcb375ce1870..7d2d5ddf5a46c 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: a2ca +# PUBSPEC CHECKSUM: cfcb diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index 03139bc65b7ca..7f3c2c3ce7f72 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3566 +# PUBSPEC CHECKSUM: a38e diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 046b61d52ac9c..582b150dade2f 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 9104 +# PUBSPEC CHECKSUM: 0c2c diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index f9b4c2e42ce01..4a5cd0a1bc9ce 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 9104 +# PUBSPEC CHECKSUM: 0c2c diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 4e9d5a2512a84..6f28048bdd846 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -66,7 +66,7 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: f526 +# PUBSPEC CHECKSUM: b44e diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index b832fcdb640ec..9962291e50eaa 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -45,7 +45,7 @@ dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pubspec_parse: 1.2.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,15 +63,15 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xml: 6.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xml: 6.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: e77b +# PUBSPEC CHECKSUM: b1a4 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index 9ce01ee17d988..b35162e04d1c1 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -59,10 +59,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f309 +# PUBSPEC CHECKSUM: 9f31 diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 62fdfeba11634..57fb59f418ff5 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -49,10 +49,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3054 +# PUBSPEC CHECKSUM: 727c diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 3b4a824cd0552..2a6eea6932fef 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -20,10 +20,10 @@ dependencies: shelf: 1.4.1 shelf_static: 1.1.2 stack_trace: 1.11.1 - vm_service: 11.9.0 + vm_service: 11.10.0 web: 0.1.4-beta webkit_inspection_protocol: 1.2.0 - xml: 6.3.0 + xml: 6.4.2 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -38,7 +38,7 @@ dependencies: js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" retry: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 72e8 +# PUBSPEC CHECKSUM: 1712 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index a33cce9dd52cb..cc08c524fe6bd 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a524 +# PUBSPEC CHECKSUM: 8f4c diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index c0c531866db86..4ee8988c6c649 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -45,10 +45,10 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -92,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0e57 +# PUBSPEC CHECKSUM: ef80 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index baa0f3f86e1b6..f723a63eff1d5 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -37,10 +37,10 @@ dev_dependencies: sync_http: 0.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0837 +# PUBSPEC CHECKSUM: 4b5f diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 3fb22a40146c5..1cd454e2d587d 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -80,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index ea600c3115324..e30c4b321f7fb 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fbac +# PUBSPEC CHECKSUM: c7d4 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index a2f6671b021c8..6207732e290a8 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 9a3fceb735b32..84d60886280b8 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -99,7 +99,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 5650 +# PUBSPEC CHECKSUM: 6978 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index f17db6ddf175e..2de843eb8b005 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9f06 +# PUBSPEC CHECKSUM: 4607 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index b6cc4937f4f0a..fd6513579c67c 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -43,10 +43,10 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0e57 +# PUBSPEC CHECKSUM: ef80 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index e83292fa8a448..53a17125a512b 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -77,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index f8cf9d1c4890f..802efe254f322 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fbac +# PUBSPEC CHECKSUM: c7d4 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 290bd144a9b07..184cb2bd40da3 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -32,6 +32,6 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1efd +# PUBSPEC CHECKSUM: 1e26 diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index 914fb126edb33..116124abacc4d 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -66,7 +66,7 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: c4a5 +# PUBSPEC CHECKSUM: 14cd diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index aaab446f158e8..41a22b1055c72 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 7338b68209bc1..6c5dd1db4b61d 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ea4f +# PUBSPEC CHECKSUM: fb77 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index 2cf2d44bfc83b..357ce19f799e7 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -36,9 +36,9 @@ dev_dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1efd +# PUBSPEC CHECKSUM: 1e26 diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 64094a0fa4848..5185ec88806c2 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -54,7 +54,7 @@ dependencies: test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,4 +62,4 @@ dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: fbac +# PUBSPEC CHECKSUM: c7d4 diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 6c93e29f00460..c4acf48f8d8fe 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -49,10 +49,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3054 +# PUBSPEC CHECKSUM: 727c diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index df82f1b4ba7b2..e8843db6e0f6b 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -51,10 +51,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f64c +# PUBSPEC CHECKSUM: 2974 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 6b859d666f22a..80787353f9be9 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -55,10 +55,10 @@ dev_dependencies: stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 9666 +# PUBSPEC CHECKSUM: fc8e diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index c88a5033c853e..657239e9c16fd 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -11,13 +11,13 @@ dependencies: sdk: flutter args: 2.4.2 vector_math: 2.1.4 - xml: 6.3.0 + xml: 6.4.2 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -37,4 +37,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: f2ec +# PUBSPEC CHECKSUM: 81ed diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 829f03ee2585b..7ced60bfcfec4 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: flutter: sdk: flutter - vm_service: 11.9.0 + vm_service: 11.10.0 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1efd +# PUBSPEC CHECKSUM: 1e26 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index be66089958428..3c5756d671a17 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -52,6 +52,7 @@ dev_dependencies: glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + intl: 0.18.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -79,7 +80,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -89,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4b19 +# PUBSPEC CHECKSUM: cf7b diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index dc4cef6891dfd..e96704b784ae2 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -61,11 +61,11 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index e1a69b943bede..32d58e5607a9c 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -61,7 +61,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index c270c209a2c28..35567bbf0cbd9 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -61,7 +61,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: bc69 +# PUBSPEC CHECKSUM: 0291 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index a42535013bebc..abd4a71675956 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -58,10 +58,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a524 +# PUBSPEC CHECKSUM: 8f4c diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index d9c92283e4da7..269c32c474ee5 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -68,10 +68,10 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1341 +# PUBSPEC CHECKSUM: 3769 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 925526eaf0c42..46e0231ae4a61 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: sdk: flutter path: 1.8.3 meta: 1.9.1 - vm_service: 11.9.0 + vm_service: 11.10.0 webdriver: 3.0.2 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0071 +# PUBSPEC CHECKSUM: 5599 diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index beab68d169791..7e8022f80ed57 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: usage: 4.1.1 webdriver: 3.0.2 webkit_inspection_protocol: 1.2.0 - xml: 6.3.0 + xml: 6.4.2 yaml: 3.1.2 native_stack_traces: 0.5.6 shelf: 1.4.1 @@ -56,7 +56,7 @@ dependencies: test_api: 0.6.1 test_core: 0.5.6 - vm_service: 11.9.0 + vm_service: 11.10.0 standard_message_codec: 0.0.1+3 @@ -64,7 +64,7 @@ dependencies: analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - built_value: 8.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + built_value: 8.6.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,7 +78,7 @@ dependencies: js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" json_rpc_2: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - petitparser: 5.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_proxy: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -107,4 +107,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: e480 +# PUBSPEC CHECKSUM: a4aa diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index 3645af9d3181c..f1a5ec18ee268 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -8,7 +8,7 @@ environment: dependencies: process: 4.2.4 - vm_service: 11.9.0 + vm_service: 11.10.0 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -63,4 +63,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: fb5c +# PUBSPEC CHECKSUM: 4e84 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index a6c80890b20a6..d4162338fb065 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -74,7 +74,7 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - vm_service: 11.9.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,4 +84,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 09d7 +# PUBSPEC CHECKSUM: 2b00 diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 7568c7237539f..6e11587637051 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: flutter_test: sdk: flutter path: 1.8.3 - vm_service: 11.9.0 + vm_service: 11.10.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 0837 +# PUBSPEC CHECKSUM: 4b5f From 284dfce70b0b11913821e0dad8a6ac3c10f76982 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 14:56:15 -0400 Subject: [PATCH 0898/1547] Roll Flutter Engine from 33fca02451ef to 3dcd2179336d (3 revisions) (#133340) https://github.com/flutter/engine/compare/33fca02451ef...3dcd2179336d 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 4b30261160a2 to ba7c5258d2b4 (5 revisions) (flutter/engine#45116) 2023-08-25 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from R_deCnScH70FbSeii... to u8ovJYTk3nN78xF4X... (flutter/engine#45115) 2023-08-25 gspencergoog@users.noreply.github.com Add quotes around Doxygen configuration values (flutter/engine#45087) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from R_deCnScH70F to u8ovJYTk3nN7 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c52dfcc28bac7..d72a0435fce47 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -33fca02451ef314fc655634b116a7b6d1144b9f7 +3dcd2179336d87a04178c561b323bd23821843b8 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 71b222cad0c72..c677845cfa102 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -R_deCnScH70FbSeiihSu6SbWh9b-3dhoFwF2veJPIG8C +u8ovJYTk3nN78xF4XDkt21AoQvutv5bbMKVQwMUs40AC From cd03eabdf8e455fdd91481a686722a0867940f37 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 16:05:08 -0400 Subject: [PATCH 0899/1547] Roll Flutter Engine from 3dcd2179336d to 1471967afb9b (3 revisions) (#133342) https://github.com/flutter/engine/compare/3dcd2179336d...1471967afb9b 2023-08-25 reidbaker@google.com Update gradle to 7.5.1 (flutter/engine#45113) 2023-08-25 ychris@google.com Ignore unguarded-availability for unit test (flutter/engine#44852) 2023-08-25 jonahwilliams@google.com [Impeller] avoid hashing and std::vector growth when binding descriptor sets. (flutter/engine#45070) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d72a0435fce47..dabc08c45d659 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3dcd2179336d87a04178c561b323bd23821843b8 +1471967afb9ba93e25fa8f1ea642bb4f9e0541d9 From 40af7db6bbac150987116f88c79075018b2b484b Mon Sep 17 00:00:00 2001 From: gmilou <139406084+gmilou@users.noreply.github.com> Date: Fri, 25 Aug 2023 13:09:58 -0700 Subject: [PATCH 0900/1547] Add an example showing how to use a MatrixTransition. (#132874) --- .../transitions/matrix_transition.0.dart | 75 +++++++++++++++++++ .../transitions/matrix_transition.0_test.dart | 56 ++++++++++++++ .../flutter/lib/src/widgets/transitions.dart | 9 ++- 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 examples/api/lib/widgets/transitions/matrix_transition.0.dart create mode 100644 examples/api/test/widgets/transitions/matrix_transition.0_test.dart diff --git a/examples/api/lib/widgets/transitions/matrix_transition.0.dart b/examples/api/lib/widgets/transitions/matrix_transition.0.dart new file mode 100644 index 0000000000000..2d687a31e7a70 --- /dev/null +++ b/examples/api/lib/widgets/transitions/matrix_transition.0.dart @@ -0,0 +1,75 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math'; + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [MatrixTransition]. + +void main() => runApp(const MatrixTransitionExampleApp()); + +class MatrixTransitionExampleApp extends StatelessWidget { + const MatrixTransitionExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: MatrixTransitionExample(), + ); + } +} + +class MatrixTransitionExample extends StatefulWidget { + const MatrixTransitionExample({super.key}); + + @override + State createState() => _MatrixTransitionExampleState(); +} + +/// [AnimationController]s can be created with `vsync: this` because of +/// [TickerProviderStateMixin]. +class _MatrixTransitionExampleState extends State with TickerProviderStateMixin { + late AnimationController _controller; + late Animation _animation; + + @override + void initState() { + super.initState(); + _controller = AnimationController( + duration: const Duration(seconds: 2), + vsync: this, + )..repeat(); + _animation = CurvedAnimation( + parent: _controller, + curve: Curves.linear, + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: MatrixTransition( + animation: _animation, + child: const Padding( + padding: EdgeInsets.all(8.0), + child: FlutterLogo(size: 150.0), + ), + onTransform: (double value) { + return Matrix4.identity() + ..setEntry(3, 2, 0.004) + ..rotateY(pi * 2.0 * value); + }, + ), + ), + ); + } +} diff --git a/examples/api/test/widgets/transitions/matrix_transition.0_test.dart b/examples/api/test/widgets/transitions/matrix_transition.0_test.dart new file mode 100644 index 0000000000000..afa0ddabf6ba3 --- /dev/null +++ b/examples/api/test/widgets/transitions/matrix_transition.0_test.dart @@ -0,0 +1,56 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/transitions/matrix_transition.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Shows Flutter logo inside a MatrixTransition', (WidgetTester tester) async { + await tester.pumpWidget( + const example.MatrixTransitionExampleApp(), + ); + + final Finder transformFinder = find.ancestor( + of: find.byType(FlutterLogo), + matching: find.byType(MatrixTransition), + ); + expect(transformFinder, findsOneWidget); + }); + + testWidgets('MatrixTransition animates', (WidgetTester tester) async { + await tester.pumpWidget( + const example.MatrixTransitionExampleApp(), + ); + + final Finder transformFinder = find.ancestor( + of: find.byType(FlutterLogo), + matching: find.byType(Transform), + ); + + Transform transformBox = tester.widget(transformFinder); + Matrix4 actualTransform = transformBox.transform; + + // Check initial transform. + expect(actualTransform, Matrix4.fromList([ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.004, 1.0, + ])..transpose()); + + // Animate half way. + await tester.pump(const Duration(seconds: 1)); + transformBox = tester.widget(transformFinder); + actualTransform = transformBox.transform; + + // The transform should be updated. + expect(actualTransform, isNot(Matrix4.fromList([ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.004, 1.0, + ])..transpose())); + }); +} diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart index b91f4fb2ad4db..f16100b0862b3 100644 --- a/packages/flutter/lib/src/widgets/transitions.dart +++ b/packages/flutter/lib/src/widgets/transitions.dart @@ -236,6 +236,13 @@ typedef TransformCallback = Matrix4 Function(double animationValue); /// The [onTransform] callback computes a [Matrix4] from the animated value, it /// is called every time the [animation] changes its value. /// +/// {@tool dartpad} +/// The following example implements a [MatrixTransition] with a rotation around +/// the Y axis, with a 3D perspective skew. +/// +/// ** See code in examples/api/lib/widgets/transitions/matrix_transition.0.dart ** +/// {@end-tool} +/// /// See also: /// /// * [ScaleTransition], which animates the scale of a widget, by providing a @@ -311,7 +318,7 @@ class MatrixTransition extends AnimatedWidget { /// Animates the scale of a transformed widget. /// -/// Here's an illustration of the [ScaleTransition] widget, with it's [alignment] +/// Here's an illustration of the [ScaleTransition] widget, with it's [scale] /// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn]: /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/scale_transition.mp4} /// From 721016c1dba3305e11d6ed2538fb72f6b50ab0c6 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Fri, 25 Aug 2023 15:13:42 -0500 Subject: [PATCH 0901/1547] Remove deprecated androidOverscrollIndicator from ScrollBehaviors (#133181) --- packages/flutter/lib/src/material/app.dart | 44 +++++-------- .../flutter/lib/src/material/theme_data.dart | 42 ------------ .../lib/src/widgets/overscroll_indicator.dart | 22 ++----- .../lib/src/widgets/scroll_configuration.dart | 64 ++----------------- packages/flutter/test/material/app_test.dart | 31 ++------- .../test/material/theme_data_test.dart | 5 -- .../test/widgets/scroll_behavior_test.dart | 42 ------------ 7 files changed, 32 insertions(+), 218 deletions(-) diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index b3ef34adf659e..a653e3c7099d1 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -785,35 +785,26 @@ class MaterialApp extends StatefulWidget { /// discoverable, so consider adding a Scrollbar in these cases, either directly /// or through the [buildScrollbar] method. /// -/// [MaterialScrollBehavior.androidOverscrollIndicator] specifies the -/// overscroll indicator that is used on [TargetPlatform.android]. When null, -/// [ThemeData.androidOverscrollIndicator] is used. If also null, the default -/// overscroll indicator is the [GlowingOverscrollIndicator]. These properties -/// are deprecated. In order to use the [StretchingOverscrollIndicator], use -/// the [ThemeData.useMaterial3] flag, or override -/// [ScrollBehavior.buildOverscrollIndicator]. +/// [ThemeData.useMaterial3] specifies the +/// overscroll indicator that is used on [TargetPlatform.android], which +/// defaults to true, resulting in a [StretchingOverscrollIndicator]. Setting +/// [ThemeData.useMaterial3] to false will instead use a +/// [GlowingOverscrollIndicator]. /// /// See also: /// /// * [ScrollBehavior], the default scrolling behavior extended by this class. class MaterialScrollBehavior extends ScrollBehavior { /// Creates a MaterialScrollBehavior that decorates [Scrollable]s with - /// [GlowingOverscrollIndicator]s and [Scrollbar]s based on the current + /// [StretchingOverscrollIndicator]s and [Scrollbar]s based on the current /// platform and provided [ScrollableDetails]. /// - /// [MaterialScrollBehavior.androidOverscrollIndicator] specifies the - /// overscroll indicator that is used on [TargetPlatform.android]. When null, - /// [ThemeData.androidOverscrollIndicator] is used. If also null, the default - /// overscroll indicator is the [GlowingOverscrollIndicator]. - const MaterialScrollBehavior({ - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - super.androidOverscrollIndicator, - }) : _androidOverscrollIndicator = androidOverscrollIndicator; - - final AndroidOverscrollIndicator? _androidOverscrollIndicator; + /// [ThemeData.useMaterial3] specifies the + /// overscroll indicator that is used on [TargetPlatform.android], which + /// defaults to true, resulting in a [StretchingOverscrollIndicator]. Setting + /// [ThemeData.useMaterial3] to false will instead use a + /// [GlowingOverscrollIndicator]. + const MaterialScrollBehavior(); @override TargetPlatform getPlatform(BuildContext context) => Theme.of(context).platform; @@ -847,14 +838,9 @@ class MaterialScrollBehavior extends ScrollBehavior { Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) { // When modifying this function, consider modifying the implementation in // the base class ScrollBehavior as well. - late final AndroidOverscrollIndicator indicator; - if (Theme.of(context).useMaterial3) { - indicator = AndroidOverscrollIndicator.stretch; - } else { - indicator = _androidOverscrollIndicator - ?? Theme.of(context).androidOverscrollIndicator - ?? androidOverscrollIndicator; - } + final AndroidOverscrollIndicator indicator = Theme.of(context).useMaterial3 + ? AndroidOverscrollIndicator.stretch + : AndroidOverscrollIndicator.glow; switch (getPlatform(context)) { case TargetPlatform.iOS: case TargetPlatform.linux: diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index d93ae531f9cad..6a24b4f30c760 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -335,11 +335,6 @@ class ThemeData with Diagnosticable { ToggleButtonsThemeData? toggleButtonsTheme, TooltipThemeData? tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - AndroidOverscrollIndicator? androidOverscrollIndicator, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -636,7 +631,6 @@ class ThemeData with Diagnosticable { toggleButtonsTheme: toggleButtonsTheme, tooltipTheme: tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator: androidOverscrollIndicator, toggleableActiveColor: toggleableActiveColor, selectedRowColor: selectedRowColor, errorColor: errorColor, @@ -747,11 +741,6 @@ class ThemeData with Diagnosticable { required this.toggleButtonsTheme, required this.tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - this.androidOverscrollIndicator, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -1449,27 +1438,6 @@ class ThemeData with Diagnosticable { // DEPRECATED (newest deprecations at the bottom) - /// Specifies which overscroll indicator to use on [TargetPlatform.android]. - /// - /// When null, the default value of - /// [MaterialScrollBehavior.androidOverscrollIndicator] is - /// [AndroidOverscrollIndicator.glow]. - /// - /// This property is deprecated. Use the [useMaterial3] flag instead, or - /// override [ScrollBehavior.buildOverscrollIndicator]. - /// - /// See also: - /// - /// * [StretchingOverscrollIndicator], a Material Design edge effect - /// that transforms the contents of a scrollable when overscrolled. - /// * [GlowingOverscrollIndicator], an edge effect that paints a glow - /// over the contents of a scrollable when overscrolled. - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - final AndroidOverscrollIndicator? androidOverscrollIndicator; - /// Obsolete property that was used for input validation errors, e.g. in /// [TextField] fields. Use [ColorScheme.error] instead. @Deprecated( @@ -1604,11 +1572,6 @@ class ThemeData with Diagnosticable { ToggleButtonsThemeData? toggleButtonsTheme, TooltipThemeData? tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - AndroidOverscrollIndicator? androidOverscrollIndicator, @Deprecated( 'No longer used by the framework, please remove any reference to it. ' 'For more information, consult the migration guide at ' @@ -1738,7 +1701,6 @@ class ThemeData with Diagnosticable { toggleButtonsTheme: toggleButtonsTheme ?? this.toggleButtonsTheme, tooltipTheme: tooltipTheme ?? this.tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, toggleableActiveColor: toggleableActiveColor ?? _toggleableActiveColor, selectedRowColor: selectedRowColor ?? _selectedRowColor, errorColor: errorColor ?? _errorColor, @@ -1932,7 +1894,6 @@ class ThemeData with Diagnosticable { toggleButtonsTheme: ToggleButtonsThemeData.lerp(a.toggleButtonsTheme, b.toggleButtonsTheme, t)!, tooltipTheme: TooltipThemeData.lerp(a.tooltipTheme, b.tooltipTheme, t)!, // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator:t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator, toggleableActiveColor: Color.lerp(a.toggleableActiveColor, b.toggleableActiveColor, t), selectedRowColor: Color.lerp(a.selectedRowColor, b.selectedRowColor, t), errorColor: Color.lerp(a.errorColor, b.errorColor, t), @@ -2038,7 +1999,6 @@ class ThemeData with Diagnosticable { other.toggleButtonsTheme == toggleButtonsTheme && other.tooltipTheme == tooltipTheme && // DEPRECATED (newest deprecations at the bottom) - other.androidOverscrollIndicator == androidOverscrollIndicator && other.toggleableActiveColor == toggleableActiveColor && other.selectedRowColor == selectedRowColor && other.errorColor == errorColor && @@ -2141,7 +2101,6 @@ class ThemeData with Diagnosticable { toggleButtonsTheme, tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator, toggleableActiveColor, selectedRowColor, errorColor, @@ -2246,7 +2205,6 @@ class ThemeData with Diagnosticable { properties.add(DiagnosticsProperty('toggleButtonsTheme', toggleButtonsTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('tooltipTheme', tooltipTheme, level: DiagnosticLevel.debug)); // DEPRECATED (newest deprecations at the bottom) - properties.add(EnumProperty('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug)); properties.add(ColorProperty('toggleableActiveColor', toggleableActiveColor, defaultValue: defaultData.toggleableActiveColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('selectedRowColor', selectedRowColor, defaultValue: defaultData.selectedRowColor, level: DiagnosticLevel.debug)); properties.add(ColorProperty('errorColor', errorColor, defaultValue: defaultData.errorColor, level: DiagnosticLevel.debug)); diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart index 1ae41dd5e2e65..2b65fd3f31f36 100644 --- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart +++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart @@ -613,19 +613,15 @@ enum _StretchDirection { /// To prevent the indicator from showing the indication, call /// [OverscrollIndicatorNotification.disallowIndicator] on the notification. /// -/// Created by [ScrollBehavior.buildOverscrollIndicator] on platforms +/// Created by [MaterialScrollBehavior.buildOverscrollIndicator] on platforms /// (e.g., Android) that commonly use this type of overscroll indication when -/// [ScrollBehavior.androidOverscrollIndicator] is -/// [AndroidOverscrollIndicator.stretch]. Otherwise, the default -/// [GlowingOverscrollIndicator] is applied. -/// [ScrollBehavior.androidOverscrollIndicator] is deprecated, use -/// [ThemeData.useMaterial3], or override -/// [ScrollBehavior.buildOverscrollIndicator] to choose the desired indicator. +/// [ThemeData.useMaterial3] is true. Otherwise, when [ThemeData.useMaterial3] +/// is false, a [GlowingOverscrollIndicator] is used instead.= /// /// See also: /// -/// * [OverscrollIndicatorNotification], which can be used to prevent the stretch -/// effect from being applied at all. +/// * [OverscrollIndicatorNotification], which can be used to prevent the +/// stretch effect from being applied at all. /// * [NotificationListener], to listen for the /// [OverscrollIndicatorNotification]. /// * [GlowingOverscrollIndicator], the default overscroll indicator for @@ -666,14 +662,6 @@ class StretchingOverscrollIndicator extends StatefulWidget { /// The overscroll indicator will apply a stretch effect to this child. This /// child (and its subtree) should include a source of [ScrollNotification] /// notifications. - /// - /// Typically a [StretchingOverscrollIndicator] is created by a - /// [ScrollBehavior.buildOverscrollIndicator] method when opted-in using the - /// [ScrollBehavior.androidOverscrollIndicator] flag. In this case - /// the child is usually the one provided as an argument to that method. - /// [ScrollBehavior.androidOverscrollIndicator] is deprecated, use - /// [ThemeData.useMaterial3], or override - /// [ScrollBehavior.buildOverscrollIndicator] to choose the desired indicator. final Widget? child; @override diff --git a/packages/flutter/lib/src/widgets/scroll_configuration.dart b/packages/flutter/lib/src/widgets/scroll_configuration.dart index 7258d602324ae..e8c72ab8d90bd 100644 --- a/packages/flutter/lib/src/widgets/scroll_configuration.dart +++ b/packages/flutter/lib/src/widgets/scroll_configuration.dart @@ -27,10 +27,6 @@ const Set _kTouchLikeDeviceTypes = { PointerDeviceKind.unknown, }; -/// The default overscroll indicator applied on [TargetPlatform.android]. -// TODO(Piinks): Complete migration to stretch by default. -const AndroidOverscrollIndicator _kDefaultAndroidOverscrollIndicator = AndroidOverscrollIndicator.glow; - /// Types of overscroll indicators supported by [TargetPlatform.android]. enum AndroidOverscrollIndicator { /// Utilizes a [StretchingOverscrollIndicator], which transforms the contents @@ -67,28 +63,7 @@ enum AndroidOverscrollIndicator { @immutable class ScrollBehavior { /// Creates a description of how [Scrollable] widgets should behave. - const ScrollBehavior({ - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - AndroidOverscrollIndicator? androidOverscrollIndicator, - }): _androidOverscrollIndicator = androidOverscrollIndicator; - - /// Specifies which overscroll indicator to use on [TargetPlatform.android]. - /// - /// Cannot be null. Defaults to [AndroidOverscrollIndicator.glow]. - /// - /// See also: - /// - /// * [MaterialScrollBehavior], which supports setting this property - /// using [ThemeData]. - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - AndroidOverscrollIndicator get androidOverscrollIndicator => _androidOverscrollIndicator ?? _kDefaultAndroidOverscrollIndicator; - final AndroidOverscrollIndicator? _androidOverscrollIndicator; + const ScrollBehavior(); /// Creates a copy of this ScrollBehavior, making it possible to /// easily toggle `scrollbar` and `overscrollIndicator` effects. @@ -105,11 +80,6 @@ class ScrollBehavior { Set? pointerAxisModifiers, ScrollPhysics? physics, TargetPlatform? platform, - @Deprecated( - 'Use ThemeData.useMaterial3 or override ScrollBehavior.buildOverscrollIndicator. ' - 'This feature was deprecated after v2.13.0-0.0.pre.' - ) - AndroidOverscrollIndicator? androidOverscrollIndicator, }) { return _WrappedScrollBehavior( delegate: this, @@ -119,7 +89,6 @@ class ScrollBehavior { pointerAxisModifiers: pointerAxisModifiers, physics: physics, platform: platform, - androidOverscrollIndicator: androidOverscrollIndicator ); } @@ -187,23 +156,13 @@ class ScrollBehavior { case TargetPlatform.windows: return child; case TargetPlatform.android: - switch (androidOverscrollIndicator) { - case AndroidOverscrollIndicator.stretch: - return StretchingOverscrollIndicator( - axisDirection: details.direction, - child: child, - ); - case AndroidOverscrollIndicator.glow: - break; - } case TargetPlatform.fuchsia: - break; + return GlowingOverscrollIndicator( + axisDirection: details.direction, + color: _kDefaultGlowColor, + child: child, + ); } - return GlowingOverscrollIndicator( - axisDirection: details.direction, - color: _kDefaultGlowColor, - child: child, - ); } /// Specifies the type of velocity tracker to use in the descendant @@ -289,9 +248,7 @@ class _WrappedScrollBehavior implements ScrollBehavior { Set? pointerAxisModifiers, this.physics, this.platform, - AndroidOverscrollIndicator? androidOverscrollIndicator, - }) : _androidOverscrollIndicator = androidOverscrollIndicator, - _dragDevices = dragDevices, + }) : _dragDevices = dragDevices, _pointerAxisModifiers = pointerAxisModifiers; final ScrollBehavior delegate; @@ -301,8 +258,6 @@ class _WrappedScrollBehavior implements ScrollBehavior { final TargetPlatform? platform; final Set? _dragDevices; final Set? _pointerAxisModifiers; - @override - final AndroidOverscrollIndicator? _androidOverscrollIndicator; @override Set get dragDevices => _dragDevices ?? delegate.dragDevices; @@ -310,9 +265,6 @@ class _WrappedScrollBehavior implements ScrollBehavior { @override Set get pointerAxisModifiers => _pointerAxisModifiers ?? delegate.pointerAxisModifiers; - @override - AndroidOverscrollIndicator get androidOverscrollIndicator => _androidOverscrollIndicator ?? delegate.androidOverscrollIndicator; - @override Widget buildOverscrollIndicator(BuildContext context, Widget child, ScrollableDetails details) { if (overscroll) { @@ -337,7 +289,6 @@ class _WrappedScrollBehavior implements ScrollBehavior { Set? pointerAxisModifiers, ScrollPhysics? physics, TargetPlatform? platform, - AndroidOverscrollIndicator? androidOverscrollIndicator }) { return delegate.copyWith( scrollbars: scrollbars ?? this.scrollbars, @@ -346,7 +297,6 @@ class _WrappedScrollBehavior implements ScrollBehavior { pointerAxisModifiers: pointerAxisModifiers ?? this.pointerAxisModifiers, physics: physics ?? this.physics, platform: platform ?? this.platform, - androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, ); } diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index cfad6de21e8a7..87e8564da509d 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -1299,9 +1299,8 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgetsWithLeakTracking('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialScrollBehavior default stretch android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( - scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), home: ListView( children: const [ SizedBox( @@ -1319,8 +1318,8 @@ void main() { testWidgetsWithLeakTracking('Overscroll indicator can be set by theme', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( - // The current default is glowing, setting via the theme should override. - theme: ThemeData().copyWith(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), + // The current default is M3 and stretch overscroll, setting via the theme should override. + theme: ThemeData().copyWith(useMaterial3: false), home: ListView( children: const [ SizedBox( @@ -1332,28 +1331,8 @@ void main() { ), )); - expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); - expect(find.byType(GlowingOverscrollIndicator), findsNothing); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - - testWidgetsWithLeakTracking('Overscroll indicator in MaterialScrollBehavior takes precedence over theme', (WidgetTester tester) async { - await tester.pumpWidget(MaterialApp( - // MaterialScrollBehavior.androidOverscrollIndicator takes precedence over theme. - scrollBehavior: const MaterialScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), - theme: ThemeData().copyWith(androidOverscrollIndicator: AndroidOverscrollIndicator.glow), - home: ListView( - children: const [ - SizedBox( - height: 1000.0, - width: 1000.0, - child: Text('Test'), - ), - ], - ), - )); - - expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); - expect(find.byType(GlowingOverscrollIndicator), findsNothing); + expect(find.byType(GlowingOverscrollIndicator), findsOneWidget); + expect(find.byType(StretchingOverscrollIndicator), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); testWidgetsWithLeakTracking('Material3 - ListView clip behavior updates overscroll indicator clip behavior', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index 0ec084f255d56..4c9e7794845e8 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -809,7 +809,6 @@ void main() { toggleButtonsTheme: const ToggleButtonsThemeData(textStyle: TextStyle(color: Colors.black)), tooltipTheme: const TooltipThemeData(height: 100), // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator: AndroidOverscrollIndicator.glow, toggleableActiveColor: Colors.black, selectedRowColor: Colors.black, errorColor: Colors.black, @@ -928,7 +927,6 @@ void main() { tooltipTheme: const TooltipThemeData(height: 100), // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator: AndroidOverscrollIndicator.stretch, toggleableActiveColor: Colors.white, selectedRowColor: Colors.white, errorColor: Colors.white, @@ -1030,7 +1028,6 @@ void main() { tooltipTheme: otherTheme.tooltipTheme, // DEPRECATED (newest deprecations at the bottom) - androidOverscrollIndicator: otherTheme.androidOverscrollIndicator, toggleableActiveColor: otherTheme.toggleableActiveColor, selectedRowColor: otherTheme.selectedRowColor, errorColor: otherTheme.errorColor, @@ -1133,7 +1130,6 @@ void main() { expect(themeDataCopy.tooltipTheme, equals(otherTheme.tooltipTheme)); // DEPRECATED (newest deprecations at the bottom) - expect(themeDataCopy.androidOverscrollIndicator, equals(otherTheme.androidOverscrollIndicator)); expect(themeDataCopy.toggleableActiveColor, equals(otherTheme.toggleableActiveColor)); expect(themeDataCopy.selectedRowColor, equals(otherTheme.selectedRowColor)); expect(themeDataCopy.errorColor, equals(otherTheme.errorColor)); @@ -1267,7 +1263,6 @@ void main() { 'toggleButtonsTheme', 'tooltipTheme', // DEPRECATED (newest deprecations at the bottom) - 'androidOverscrollIndicator', 'toggleableActiveColor', 'selectedRowColor', 'errorColor', diff --git a/packages/flutter/test/widgets/scroll_behavior_test.dart b/packages/flutter/test/widgets/scroll_behavior_test.dart index 287a1a82d0898..1d075e05ede62 100644 --- a/packages/flutter/test/widgets/scroll_behavior_test.dart +++ b/packages/flutter/test/widgets/scroll_behavior_test.dart @@ -154,32 +154,6 @@ void main() { expect(find.byType(GlowingOverscrollIndicator), findsOneWidget); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('ScrollBehavior stretch android overscroll indicator', (WidgetTester tester) async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: MediaQuery( - data: const MediaQueryData(size: Size(800, 600)), - child: ScrollConfiguration( - behavior: const ScrollBehavior(androidOverscrollIndicator: AndroidOverscrollIndicator.stretch), - child: ListView( - children: const [ - SizedBox( - height: 1000.0, - width: 1000.0, - child: Text('Test'), - ), - ], - ), - ), - ), - ), - ); - - expect(find.byType(StretchingOverscrollIndicator), findsOneWidget); - expect(find.byType(GlowingOverscrollIndicator), findsNothing); - }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - group('ScrollBehavior configuration is maintained over multiple copies', () { testWidgets('dragDevices', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 @@ -203,22 +177,6 @@ void main() { expect(twiceCopiedBehavior.dragDevices, PointerDeviceKind.values.toSet()); }); - testWidgets('androidOverscrollIndicator', (WidgetTester tester) async { - // Regression test for https://github.com/flutter/flutter/issues/91673 - const ScrollBehavior defaultBehavior = ScrollBehavior(); - expect(defaultBehavior.androidOverscrollIndicator, AndroidOverscrollIndicator.glow); - - // Use copyWith to modify androidOverscrollIndicator - final ScrollBehavior onceCopiedBehavior = defaultBehavior.copyWith( - androidOverscrollIndicator: AndroidOverscrollIndicator.stretch, - ); - expect(onceCopiedBehavior.androidOverscrollIndicator, AndroidOverscrollIndicator.stretch); - - // Copy again. The previously modified value should carry over. - final ScrollBehavior twiceCopiedBehavior = onceCopiedBehavior.copyWith(); - expect(twiceCopiedBehavior.androidOverscrollIndicator, AndroidOverscrollIndicator.stretch); - }); - testWidgets('physics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 late ScrollPhysics defaultPhysics; From 72bd36026fdeb779793dd56f4ddc8f4dcba3626e Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Fri, 25 Aug 2023 15:46:11 -0500 Subject: [PATCH 0902/1547] Remove deprecated onPlatformMessage from TestWindow and TestPlatformDispatcher (#133183) --- packages/flutter_test/lib/src/window.dart | 30 ----------------------- 1 file changed, 30 deletions(-) diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index e344ad11f5a70..c01dca0391c52 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -442,21 +442,6 @@ class TestPlatformDispatcher implements PlatformDispatcher { _platformDispatcher.sendPlatformMessage(name, data, callback); } - @Deprecated( - 'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. ' - 'This feature was deprecated after v2.1.0-10.0.pre.' - ) - @override - PlatformMessageCallback? get onPlatformMessage => _platformDispatcher.onPlatformMessage; - @Deprecated( - 'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. ' - 'This feature was deprecated after v2.1.0-10.0.pre.' - ) - @override - set onPlatformMessage(PlatformMessageCallback? callback) { - _platformDispatcher.onPlatformMessage = callback; - } - /// Delete any test value properties that have been set on this [TestPlatformDispatcher] /// and return to reporting the real [PlatformDispatcher] values for all /// [PlatformDispatcher] properties. @@ -1838,21 +1823,6 @@ class TestWindow implements SingletonFlutterWindow { platformDispatcher.sendPlatformMessage(name, data, callback); } - @Deprecated( - 'Instead of calling this callback, use ServicesBinding.instance.channelBuffers.push. ' - 'This feature was deprecated after v2.1.0-10.0.pre.' - ) - @override - PlatformMessageCallback? get onPlatformMessage => platformDispatcher.onPlatformMessage; - @Deprecated( - 'Instead of setting this callback, use ServicesBinding.instance.defaultBinaryMessenger.setMessageHandler. ' - 'This feature was deprecated after v2.1.0-10.0.pre.' - ) - @override - set onPlatformMessage(PlatformMessageCallback? callback) { - platformDispatcher.onPlatformMessage = callback; - } - /// Delete any test value properties that have been set on this [TestWindow] /// as well as its [platformDispatcher]. /// From 347f7bac9434c49e5a800691d6bf62aeddf80515 Mon Sep 17 00:00:00 2001 From: Chinmoy Date: Sat, 26 Aug 2023 02:54:05 +0530 Subject: [PATCH 0903/1547] Adds callback onWillAcceptWithDetails in DragTarget. (#131545) This PR adds onWillAcceptWithDetails callback to DragTarget to get information about offset. Fixes: #131378 This PR is subject to changes based on #131542 --- .../flutter/lib/src/widgets/drag_target.dart | 34 ++- .../flutter/test/widgets/draggable_test.dart | 234 ++++++++++++++++++ 2 files changed, 266 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index f55806353bd5f..a2ed56a7f3f19 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -20,6 +20,12 @@ import 'view.dart'; /// Used by [DragTarget.onWillAccept]. typedef DragTargetWillAccept = bool Function(T? data); +/// Signature for determining whether the given data will be accepted by a [DragTarget], +/// based on provided information. +/// +/// Used by [DragTarget.onWillAcceptWithDetails]. +typedef DragTargetWillAcceptWithDetails = bool Function(DragTargetDetails details); + /// Signature for causing a [DragTarget] to accept the given data. /// /// Used by [DragTarget.onAccept]. @@ -612,12 +618,13 @@ class DragTarget extends StatefulWidget { super.key, required this.builder, this.onWillAccept, + this.onWillAcceptWithDetails, this.onAccept, this.onAcceptWithDetails, this.onLeave, this.onMove, this.hitTestBehavior = HitTestBehavior.translucent, - }); + }) : assert(onWillAccept == null || onWillAcceptWithDetails == null, "Don't pass both onWillAccept and onWillAcceptWithDetails."); /// Called to build the contents of this widget. /// @@ -631,8 +638,25 @@ class DragTarget extends StatefulWidget { /// Called when a piece of data enters the target. This will be followed by /// either [onAccept] and [onAcceptWithDetails], if the data is dropped, or /// [onLeave], if the drag leaves the target. + /// + /// Equivalent to [onWillAcceptWithDetails], but only includes the data. + /// + /// Must not be provided if [onWillAcceptWithDetails] is provided. final DragTargetWillAccept? onWillAccept; + /// Called to determine whether this widget is interested in receiving a given + /// piece of data being dragged over this drag target. + /// + /// Called when a piece of data enters the target. This will be followed by + /// either [onAccept] and [onAcceptWithDetails], if the data is dropped, or + /// [onLeave], if the drag leaves the target. + /// + /// Equivalent to [onWillAccept], but with information, including the data, + /// in a [DragTargetDetails]. + /// + /// Must not be provided if [onWillAccept] is provided. + final DragTargetWillAcceptWithDetails? onWillAcceptWithDetails; + /// Called when an acceptable piece of data was dropped over this drag target. /// /// Equivalent to [onAcceptWithDetails], but only includes the data. @@ -684,7 +708,13 @@ class _DragTargetState extends State> { bool didEnter(_DragAvatar avatar) { assert(!_candidateAvatars.contains(avatar)); assert(!_rejectedAvatars.contains(avatar)); - if (widget.onWillAccept == null || widget.onWillAccept!(avatar.data as T?)) { + final bool resolvedWillAccept = (widget.onWillAccept == null && + widget.onWillAcceptWithDetails == null) || + (widget.onWillAccept != null && + widget.onWillAccept!(avatar.data as T?)) || + (widget.onWillAcceptWithDetails != null && + widget.onWillAcceptWithDetails!(DragTargetDetails(data: avatar.data! as T, offset: avatar._lastOffset!))); + if (resolvedWillAccept) { setState(() { _candidateAvatars.add(avatar); }); diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart index 3336a6feb6e7d..ac91266e41fe8 100644 --- a/packages/flutter/test/widgets/draggable_test.dart +++ b/packages/flutter/test/widgets/draggable_test.dart @@ -1293,6 +1293,83 @@ void main() { expect(onDraggableCanceledOffset, equals(Offset(secondLocation.dx, secondLocation.dy))); }); + testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with details', (WidgetTester tester) async { + final List accepted = []; + final List> acceptedDetails = >[]; + bool onDraggableCanceledCalled = false; + late Velocity onDraggableCanceledVelocity; + late Offset onDraggableCanceledOffset; + + await tester.pumpWidget(MaterialApp( + home: Column( + children: [ + Draggable( + data: 1, + feedback: const Text('Dragging'), + onDraggableCanceled: (Velocity velocity, Offset offset) { + onDraggableCanceledCalled = true; + onDraggableCanceledVelocity = velocity; + onDraggableCanceledOffset = offset; + }, + child: const Text('Source'), + ), + DragTarget( + builder: (BuildContext context, List data, List rejects) { + return const SizedBox( + height: 100.0, + child: Text('Target'), + ); + }, + onWillAcceptWithDetails: (DragTargetDetails details) => false, + onAccept: accepted.add, + onAcceptWithDetails: acceptedDetails.add, + ), + ], + ), + )); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(find.text('Target'), findsOneWidget); + expect(onDraggableCanceledCalled, isFalse); + + final Offset firstLocation = tester.getTopLeft(find.text('Source')); + final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(find.text('Target'), findsOneWidget); + expect(onDraggableCanceledCalled, isFalse); + + final Offset secondLocation = tester.getCenter(find.text('Target')); + await gesture.moveTo(secondLocation); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(find.text('Target'), findsOneWidget); + expect(onDraggableCanceledCalled, isFalse); + + await gesture.up(); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(find.text('Target'), findsOneWidget); + expect(onDraggableCanceledCalled, isTrue); + expect(onDraggableCanceledVelocity, equals(Velocity.zero)); + expect(onDraggableCanceledOffset, equals(Offset(secondLocation.dx, secondLocation.dy))); + }); + testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with correct velocity', (WidgetTester tester) async { final List accepted = []; final List> acceptedDetails = >[]; @@ -1421,6 +1498,82 @@ void main() { ); }); + testWidgets('Drag and drop - onDragEnd not called if dropped on non-accepting target with details', (WidgetTester tester) async { + final List accepted = []; + final List> acceptedDetails = >[]; + bool onDragEndCalled = false; + late DraggableDetails onDragEndDraggableDetails; + await tester.pumpWidget(MaterialApp( + home: Column( + children: [ + Draggable( + data: 1, + feedback: const Text('Dragging'), + onDragEnd: (DraggableDetails details) { + onDragEndCalled = true; + onDragEndDraggableDetails = details; + }, + child: const Text('Source'), + ), + DragTarget( + builder: (BuildContext context, List data, List rejects) { + return const SizedBox(height: 100.0, child: Text('Target')); + }, + onWillAcceptWithDetails: (DragTargetDetails data) => false, + onAccept: accepted.add, + onAcceptWithDetails: acceptedDetails.add, + ), + ], + ), + )); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(find.text('Target'), findsOneWidget); + expect(onDragEndCalled, isFalse); + + final Offset firstLocation = tester.getTopLeft(find.text('Source')); + final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(find.text('Target'), findsOneWidget); + expect(onDragEndCalled, isFalse); + + final Offset secondLocation = tester.getCenter(find.text('Target')); + await gesture.moveTo(secondLocation); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(find.text('Target'), findsOneWidget); + expect(onDragEndCalled, isFalse); + + await gesture.up(); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(find.text('Target'), findsOneWidget); + expect(onDragEndCalled, isTrue); + expect(onDragEndDraggableDetails, isNotNull); + expect(onDragEndDraggableDetails.wasAccepted, isFalse); + expect(onDragEndDraggableDetails.velocity, equals(Velocity.zero)); + expect( + onDragEndDraggableDetails.offset, + equals(Offset(secondLocation.dx, secondLocation.dy - firstLocation.dy)), + ); + }); + testWidgets('Drag and drop - DragTarget rebuilds with and without rejected data when a rejected draggable enters and leaves', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Column( @@ -1628,6 +1781,77 @@ void main() { expect(onDragCompletedCalled, isFalse); }); + testWidgets('Drag and drop - onDragCompleted not called if dropped on non-accepting target with details', (WidgetTester tester) async { + final List accepted = []; + final List> acceptedDetails = >[]; + bool onDragCompletedCalled = false; + + await tester.pumpWidget(MaterialApp( + home: Column( + children: [ + Draggable( + data: 1, + feedback: const Text('Dragging'), + onDragCompleted: () { + onDragCompletedCalled = true; + }, + child: const Text('Source'), + ), + DragTarget( + builder: (BuildContext context, List data, List rejects) { + return const SizedBox( + height: 100.0, + child: Text('Target'), + ); + }, + onWillAcceptWithDetails: (DragTargetDetails data) => false, + onAccept: accepted.add, + onAcceptWithDetails: acceptedDetails.add, + ), + ], + ), + )); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(find.text('Target'), findsOneWidget); + expect(onDragCompletedCalled, isFalse); + + final Offset firstLocation = tester.getTopLeft(find.text('Source')); + final TestGesture gesture = await tester.startGesture(firstLocation, pointer: 7); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(find.text('Target'), findsOneWidget); + expect(onDragCompletedCalled, isFalse); + + final Offset secondLocation = tester.getCenter(find.text('Target')); + await gesture.moveTo(secondLocation); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsOneWidget); + expect(find.text('Target'), findsOneWidget); + expect(onDragCompletedCalled, isFalse); + + await gesture.up(); + await tester.pump(); + + expect(accepted, isEmpty); + expect(acceptedDetails, isEmpty); + expect(find.text('Source'), findsOneWidget); + expect(find.text('Dragging'), findsNothing); + expect(find.text('Target'), findsOneWidget); + expect(onDragCompletedCalled, isFalse); + }); + testWidgets('Drag and drop - onDragEnd called if dropped on accepting target', (WidgetTester tester) async { final List accepted = []; final List> acceptedDetails = >[]; @@ -3237,6 +3461,16 @@ void main() { expect(find.text('Dragging'), findsNothing); await gesture3.up(); }); + + testWidgets('throws error when both onWillAccept and onWillAcceptWithDetails are provided', (WidgetTester tester) async { + expect(() => DragTarget( + builder: (BuildContext context, List data, List rejects) { + return const SizedBox(height: 100.0, child: Text('Target')); + }, + onWillAccept: (int? data) => true, + onWillAcceptWithDetails: (DragTargetDetails details) => false, + ), throwsAssertionError); + }); } Future _testLongPressDraggableHapticFeedback({ required WidgetTester tester, required bool hapticFeedbackOnStart, required int expectedHapticFeedbackCount }) async { From c4e1a1b387015cfac0b93ad25dd85b388a198a18 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Fri, 25 Aug 2023 14:30:07 -0700 Subject: [PATCH 0904/1547] Fix locking to work with flutter and dart running simultaneously (#133350) --- bin/dart | 3 ++- bin/flutter | 3 ++- bin/internal/shared.sh | 18 +++++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/bin/dart b/bin/dart index 0c1f402819bee..9ef65c2c43645 100755 --- a/bin/dart +++ b/bin/dart @@ -45,6 +45,7 @@ function follow_links() ( PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")" BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" +SHARED_NAME="$BIN_DIR/internal/shared.sh" OS="$(uname -s)" # If we're on Windows, invoke the batch script instead to get proper locking. @@ -53,6 +54,6 @@ if [[ $OS =~ MINGW.* || $OS =~ CYGWIN.* || $OS =~ MSYS.* ]]; then fi # To define `shared::execute()` function -source "$BIN_DIR/internal/shared.sh" +source "$SHARED_NAME" shared::execute "$@" diff --git a/bin/flutter b/bin/flutter index 9347b8dad6949..21c11c7e7e8ec 100755 --- a/bin/flutter +++ b/bin/flutter @@ -50,6 +50,7 @@ function follow_links() ( PROG_NAME="$(follow_links "${BASH_SOURCE[0]}")" BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" +SHARED_NAME="$BIN_DIR/internal/shared.sh" OS="$(uname -s)" # If we're on Windows, invoke the batch script instead to get proper locking. @@ -58,6 +59,6 @@ if [[ $OS =~ MINGW.* || $OS =~ CYGWIN.* || $OS =~ MSYS.* ]]; then fi # To define `shared::execute()` function -source "$BIN_DIR/internal/shared.sh" +source "$SHARED_NAME" shared::execute "$@" diff --git a/bin/internal/shared.sh b/bin/internal/shared.sh index 3532c23114a57..75d9d3013eb27 100644 --- a/bin/internal/shared.sh +++ b/bin/internal/shared.sh @@ -229,7 +229,23 @@ function shared::execute() { exit 1 fi - upgrade_flutter 7< "$PROG_NAME" + # File descriptor 7 is prepared here so that we can use it with + # flock(1) in _lock() (see above). + # + # We use number 7 because it's a luckier number than 3; luck is + # important when making locks work reliably. Also because that way + # if anyone is redirecting other file descriptors there's less + # chance of a conflict. + # + # In any case, the file we redirect into this file descriptor is + # this very source file you are reading right now, because that's + # the only file we can truly guarantee exists, since we're running + # it. We don't use PROG_NAME because otherwise if you run `dart` and + # `flutter` simultaneously they'll end up using different lock files + # and will corrupt each others' downloads. + # + # SHARED_NAME itself is prepared by the caller script. + upgrade_flutter 7< "$SHARED_NAME" BIN_NAME="$(basename "$PROG_NAME")" case "$BIN_NAME" in From d966f11f7b0822c38f4a96d31edc441ed4d4f9e8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 18:01:25 -0400 Subject: [PATCH 0905/1547] Roll Flutter Engine from 1471967afb9b to 1ec7b89f3a6b (6 revisions) (#133355) https://github.com/flutter/engine/compare/1471967afb9b...1ec7b89f3a6b 2023-08-25 zanderso@users.noreply.github.com Remove --enable-software-rendering from iOS scenario tests (flutter/engine#45093) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 56bb647a49ac to 76672468e8d7 (3 revisions) (flutter/engine#45121) 2023-08-25 yatendraroria2001@gmail.com Fix: Complete Documentation for RasterStatus::kSkipAndRetry (flutter/engine#44880) 2023-08-25 30870216+gaaclarke@users.noreply.github.com [Impeller] Updated TextureSourceVK docs and deleted unused ivars (flutter/engine#45123) 2023-08-25 zanderso@users.noreply.github.com Revert "Fix global tests doing nothing." (flutter/engine#45125) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from ba7c5258d2b4 to 56bb647a49ac (3 revisions) (flutter/engine#45118) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index dabc08c45d659..6ebbf48996174 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1471967afb9ba93e25fa8f1ea642bb4f9e0541d9 +1ec7b89f3a6b92dc1888724cb2a4dceda8cb1af1 From 1b40f05a138cc881ca9b72028b15f43ef41318fa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 18:53:27 -0400 Subject: [PATCH 0906/1547] Roll Flutter Engine from 1ec7b89f3a6b to 53595c937df1 (4 revisions) (#133362) https://github.com/flutter/engine/compare/1ec7b89f3a6b...53595c937df1 2023-08-25 bdero@google.com [Impeller] Fix mask blurs and the Gaussian blur coverage hint. (flutter/engine#45079) 2023-08-25 ychris@google.com ios: remove shared_application and support app extension build (flutter/engine#44732) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 76672468e8d7 to 40f4e01fca40 (3 revisions) (flutter/engine#45126) 2023-08-25 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 4LHUJjNlDT21v_pdT... to Qj4BGsKtF7EJssKIK... (flutter/engine#45127) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 4LHUJjNlDT21 to Qj4BGsKtF7EJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6ebbf48996174..17657e72e836b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1ec7b89f3a6b92dc1888724cb2a4dceda8cb1af1 +53595c937df156b932850807869f539c15042919 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 8d467caedce04..5d94b8c9d85e2 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -4LHUJjNlDT21v_pdTCXu00_kXfo-jPVXux859BpEX-YC +Qj4BGsKtF7EJssKIKONF3EjBwsWNJ1LGIXWpqBMclbQC From 305c4db6a6bb8b6925b77ae338aeda8cb55a287c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 19:40:25 -0400 Subject: [PATCH 0907/1547] Roll Flutter Engine from 53595c937df1 to 63fdf8a6701c (1 revision) (#133366) https://github.com/flutter/engine/compare/53595c937df1...63fdf8a6701c 2023-08-25 bdero@google.com [Impeller] Reland debug captures and inspector. (flutter/engine#45094) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 17657e72e836b..9b6d0df8d85af 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -53595c937df156b932850807869f539c15042919 +63fdf8a6701c9f26bb1572b43b2666fef46e8964 From 343000b6e96d738bfc15c9bd1a82f1afc814041d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 25 Aug 2023 17:03:47 -0700 Subject: [PATCH 0908/1547] _SelectableFragment should dispatch creation in constructor. (#133351) --- packages/flutter/lib/src/rendering/paragraph.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index f1b252b032c0d..488391333690e 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -1322,6 +1322,9 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM required this.fullText, required this.range, }) : assert(range.isValid && !range.isCollapsed && range.isNormalized) { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } _selectionGeometry = _getSelectionGeometry(); } From 95161d86a9013518b05648b497060f34afb04a1a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 25 Aug 2023 23:21:25 -0400 Subject: [PATCH 0909/1547] Roll Flutter Engine from 63fdf8a6701c to e280ed21f923 (3 revisions) (#133378) https://github.com/flutter/engine/compare/63fdf8a6701c...e280ed21f923 2023-08-26 skia-flutter-autoroll@skia.org Roll Skia from ac39b12fd835 to e64e8f4094b2 (1 revision) (flutter/engine#45136) 2023-08-26 skia-flutter-autoroll@skia.org Roll Skia from e67d9439a8c4 to ac39b12fd835 (1 revision) (flutter/engine#45133) 2023-08-25 skia-flutter-autoroll@skia.org Roll Skia from 40f4e01fca40 to e67d9439a8c4 (4 revisions) (flutter/engine#45132) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9b6d0df8d85af..503bd00bb9cb5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -63fdf8a6701c9f26bb1572b43b2666fef46e8964 +e280ed21f923cb7660a1e8563561a5743a09bd90 From 229b74d987720a0437039b6e44e13f20fb94ad51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 26 Aug 2023 04:11:06 -0400 Subject: [PATCH 0910/1547] Roll Flutter Engine from e280ed21f923 to c9b584d59219 (1 revision) (#133380) https://github.com/flutter/engine/compare/e280ed21f923...c9b584d59219 2023-08-26 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from u8ovJYTk3nN78xF4X... to IYiIm4zYdKPYfpOIG... (flutter/engine#45138) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from u8ovJYTk3nN7 to IYiIm4zYdKPY If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 503bd00bb9cb5..325aaa2cae6b6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e280ed21f923cb7660a1e8563561a5743a09bd90 +c9b584d59219db5204e9e6b9d6ac1c1424c8c9f2 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index c677845cfa102..5a60480458646 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -u8ovJYTk3nN78xF4XDkt21AoQvutv5bbMKVQwMUs40AC +IYiIm4zYdKPYfpOIGDmC5EC7pO8dSsV4PIaZNWJ0NU0C From 26972de9aebabb806bfa7fc7457e5c9c4b803011 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 26 Aug 2023 17:16:06 -0400 Subject: [PATCH 0911/1547] Roll Flutter Engine from c9b584d59219 to 4aaf77e33de6 (2 revisions) (#133389) https://github.com/flutter/engine/compare/c9b584d59219...4aaf77e33de6 2023-08-26 jonahwilliams@google.com Revert "[Impeller] DlAiksCanvas as a DlCanvas wrapper for impeller::Canvas" (flutter/engine#45149) 2023-08-26 dnfield@google.com [Impeller] DlAiksCanvas as a DlCanvas wrapper for impeller::Canvas (flutter/engine#45131) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 325aaa2cae6b6..8c00aafd0b304 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c9b584d59219db5204e9e6b9d6ac1c1424c8c9f2 +4aaf77e33de6257d3c6313b74b45d3f7933cc54e From dbf87fc8c620d4de7421d4c2124a6255553a1095 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 26 Aug 2023 19:02:32 -0400 Subject: [PATCH 0912/1547] Roll Flutter Engine from 4aaf77e33de6 to 683d7dc38928 (3 revisions) (#133393) https://github.com/flutter/engine/compare/4aaf77e33de6...683d7dc38928 2023-08-26 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Qj4BGsKtF7EJssKIK... to jZgLG9jWLutILTtsL... (flutter/engine#45153) 2023-08-26 skia-flutter-autoroll@skia.org Roll Skia from e64e8f4094b2 to 0f9e50daa879 (2 revisions) (flutter/engine#45152) 2023-08-26 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from IYiIm4zYdKPYfpOIG... to xYHxghcipvy5XZAK6... (flutter/engine#45151) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from IYiIm4zYdKPY to xYHxghcipvy5 fuchsia/sdk/core/mac-amd64 from Qj4BGsKtF7EJ to jZgLG9jWLutI If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8c00aafd0b304..83159019a40a4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4aaf77e33de6257d3c6313b74b45d3f7933cc54e +683d7dc389284953cefbc52a63aada286f0430a6 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 5a60480458646..c8da7f940efed 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -IYiIm4zYdKPYfpOIGDmC5EC7pO8dSsV4PIaZNWJ0NU0C +xYHxghcipvy5XZAK6Dhuqz6xZsL0JF6J4LKFXRUyDbgC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 5d94b8c9d85e2..668fc59e2cf30 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -Qj4BGsKtF7EJssKIKONF3EjBwsWNJ1LGIXWpqBMclbQC +jZgLG9jWLutILTtsL1jNe1V54jP-5r03lZcM1RY-hN4C From f11430cdcd8306a0bd3313505b72c5a86682418a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 27 Aug 2023 03:02:30 -0400 Subject: [PATCH 0913/1547] Roll Flutter Engine from 683d7dc38928 to b5f18218969b (1 revision) (#133401) https://github.com/flutter/engine/compare/683d7dc38928...b5f18218969b 2023-08-27 matanlurey@users.noreply.github.com Use `SkTextBlob::bounds` instead of `TextFrame::getBounds()`. (flutter/engine#45148) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 83159019a40a4..533cfd0b72891 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -683d7dc389284953cefbc52a63aada286f0430a6 +b5f18218969b4294bc14ed5316f2fe0a35267a55 From cd3aeef3a826463eac8d9e09a5b504bea3cd7011 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 27 Aug 2023 07:08:36 -0400 Subject: [PATCH 0914/1547] Roll Flutter Engine from b5f18218969b to b4e2758d6d43 (1 revision) (#133405) https://github.com/flutter/engine/compare/b5f18218969b...b4e2758d6d43 2023-08-27 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from xYHxghcipvy5XZAK6... to N-A8agqDgvTKiT2Wc... (flutter/engine#45155) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from xYHxghcipvy5 to N-A8agqDgvTK If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 533cfd0b72891..34d39f25a7030 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b5f18218969b4294bc14ed5316f2fe0a35267a55 +b4e2758d6d43fb07b1ea169e228608b22c4bebe4 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index c8da7f940efed..b55d0b29149bb 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -xYHxghcipvy5XZAK6Dhuqz6xZsL0JF6J4LKFXRUyDbgC +N-A8agqDgvTKiT2WcqRTJV0KrD_j1-GIHALBrxEUp-IC From 3f5583c819ac900e264466a5ee927586cc9bf98c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 27 Aug 2023 12:54:26 -0400 Subject: [PATCH 0915/1547] Roll Flutter Engine from b4e2758d6d43 to fc592728a7d0 (1 revision) (#133410) https://github.com/flutter/engine/compare/b4e2758d6d43...fc592728a7d0 2023-08-27 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from jZgLG9jWLutILTtsL... to 8nJB1-rSpC5L4digu... (flutter/engine#45156) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from jZgLG9jWLutI to 8nJB1-rSpC5L If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 34d39f25a7030..7ed89ca692ba8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b4e2758d6d43fb07b1ea169e228608b22c4bebe4 +fc592728a7d02685f7afc767c70e4d1a552b705d diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 668fc59e2cf30..ecc5c5b68e919 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -jZgLG9jWLutILTtsL1jNe1V54jP-5r03lZcM1RY-hN4C +8nJB1-rSpC5L4diguRxuRnrPvyA2teDU5ZsF4vcKNfwC From 6d22a11b62d3448df10ce18f2262c2b9ecc660c1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 27 Aug 2023 19:57:26 -0400 Subject: [PATCH 0916/1547] Roll Flutter Engine from fc592728a7d0 to 0593c0455fd6 (4 revisions) (#133419) https://github.com/flutter/engine/compare/fc592728a7d0...0593c0455fd6 2023-08-27 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from N-A8agqDgvTKiT2Wc... to jnDJLdEAx34diOWFx... (flutter/engine#45159) 2023-08-27 jonahwilliams@google.com [Impeller] SuboptimalKHR is not an exit condition. (flutter/engine#45157) 2023-08-27 matanlurey@users.noreply.github.com Use YAML >- to avoid strange formatting. (flutter/engine#45158) 2023-08-27 matanlurey@users.noreply.github.com [Impeller] Implement TextDecoration (i.e. dashed lines) (flutter/engine#45041) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from N-A8agqDgvTK to jnDJLdEAx34d If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7ed89ca692ba8..307787bee3089 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fc592728a7d02685f7afc767c70e4d1a552b705d +0593c0455fd64817afae8c49c6a1ee166ec8f297 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index b55d0b29149bb..6b36a251814d6 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -N-A8agqDgvTKiT2WcqRTJV0KrD_j1-GIHALBrxEUp-IC +jnDJLdEAx34diOWFxRS3qWbcmxmyulDSpEDi0AtMkHEC From 2660fdcff46f6cebcd1cfe8611e3e26218cb8e52 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 27 Aug 2023 23:07:25 -0400 Subject: [PATCH 0917/1547] Roll Flutter Engine from 0593c0455fd6 to f8a171aa173f (1 revision) (#133425) https://github.com/flutter/engine/compare/0593c0455fd6...f8a171aa173f 2023-08-27 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 8nJB1-rSpC5L4digu... to xRUHI4zSil6TevQTa... (flutter/engine#45160) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 8nJB1-rSpC5L to xRUHI4zSil6T If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 307787bee3089..3db57c5f1d092 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0593c0455fd64817afae8c49c6a1ee166ec8f297 +f8a171aa173f9ed603de60990f0b334b852d19d8 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ecc5c5b68e919..5504477e7de85 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -8nJB1-rSpC5L4diguRxuRnrPvyA2teDU5ZsF4vcKNfwC +xRUHI4zSil6TevQTayC6ixO1AF6BHpBc4ONyy5G6kLIC From 2e075d000b177e8c174bab4bad04f71647ab2104 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 02:12:15 -0400 Subject: [PATCH 0918/1547] Roll Flutter Engine from f8a171aa173f to 78c26aeff3ee (1 revision) (#133428) https://github.com/flutter/engine/compare/f8a171aa173f...78c26aeff3ee 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 0f9e50daa879 to 405c2ecb7f2a (1 revision) (flutter/engine#45161) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3db57c5f1d092..f7b630cf524bc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f8a171aa173f9ed603de60990f0b334b852d19d8 +78c26aeff3eefba9fe163a19abb289da31d3be59 From 9218f93f7ed3292989a3150c341faca7bd7190b8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 03:43:23 -0400 Subject: [PATCH 0919/1547] Roll Flutter Engine from 78c26aeff3ee to b26e2da130ab (2 revisions) (#133432) https://github.com/flutter/engine/compare/78c26aeff3ee...b26e2da130ab 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 2582a06b4618 to 1ce3c2af0971 (2 revisions) (flutter/engine#45163) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 405c2ecb7f2a to 2582a06b4618 (1 revision) (flutter/engine#45162) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f7b630cf524bc..646daa37d9336 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -78c26aeff3eefba9fe163a19abb289da31d3be59 +b26e2da130ab5181bfa4fec4fa43cb2b05bfb9dd From 7c13003939cbad2e27c01b26f76803a52df72453 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 07:01:09 -0400 Subject: [PATCH 0920/1547] Roll Flutter Engine from b26e2da130ab to d89824ab018f (2 revisions) (#133444) https://github.com/flutter/engine/compare/b26e2da130ab...d89824ab018f 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 1ce3c2af0971 to 0d39172f35d2 (1 revision) (flutter/engine#45164) 2023-08-28 skia-flutter-autoroll@skia.org Manual roll Dart SDK from ab417bc74bb1 to 5d3ab5db5037 (17 revisions) (flutter/engine#45165) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 646daa37d9336..523d61f373dc2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b26e2da130ab5181bfa4fec4fa43cb2b05bfb9dd +d89824ab018f1718e5f54e840a816f3e4634e387 From 830921618b5beb208cbe4b4e6dc2501cd47b8806 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 08:25:29 -0400 Subject: [PATCH 0921/1547] Roll Flutter Engine from d89824ab018f to 4924cf453398 (1 revision) (#133447) https://github.com/flutter/engine/compare/d89824ab018f...4924cf453398 2023-08-28 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from jnDJLdEAx34diOWFx... to AQZddYgKiWrQL8vny... (flutter/engine#45167) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from jnDJLdEAx34d to AQZddYgKiWrQ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 523d61f373dc2..5781fc8ccfdb8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d89824ab018f1718e5f54e840a816f3e4634e387 +4924cf45339893317f1e795564f07e035d1a4231 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 6b36a251814d6..25d0a832cb001 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -jnDJLdEAx34diOWFxRS3qWbcmxmyulDSpEDi0AtMkHEC +AQZddYgKiWrQL8vnyZlhYg3ltgH_oGTnzETLJ12cODkC From 0027d18ee54742d5512f58146c1153cb428a57cc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 10:57:26 -0400 Subject: [PATCH 0922/1547] Roll Flutter Engine from 4924cf453398 to 9ab2603db24f (1 revision) (#133449) https://github.com/flutter/engine/compare/4924cf453398...9ab2603db24f 2023-08-28 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from xRUHI4zSil6TevQTa... to u44zzvYd85WSDMpS3... (flutter/engine#45168) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from xRUHI4zSil6T to u44zzvYd85WS If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5781fc8ccfdb8..45880b6659252 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4924cf45339893317f1e795564f07e035d1a4231 +9ab2603db24f7537aff4ee1d57f8cd95cecd6bf5 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 5504477e7de85..3fa428392ed9d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -xRUHI4zSil6TevQTayC6ixO1AF6BHpBc4ONyy5G6kLIC +u44zzvYd85WSDMpS3HByB6bT_uFdClQ4RtTDaYFpC40C From 2ea5296616918f467ea4ddf770e332be2aa3f7ae Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 28 Aug 2023 08:46:10 -0700 Subject: [PATCH 0923/1547] PlatformRouteInformationProvider should dispatch creation in constructor. (#133353) --- packages/flutter/lib/src/widgets/router.dart | 6 +++++- packages/flutter/test/material/app_test.dart | 1 + packages/flutter/test/widgets/router_test.dart | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index 63db13e365483..f0ea0861005c8 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1465,7 +1465,11 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid /// provider. PlatformRouteInformationProvider({ required RouteInformation initialRouteInformation, - }) : _value = initialRouteInformation; + }) : _value = initialRouteInformation { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } static bool _equals(Uri a, Uri b) { return a.path == b.path diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 87e8564da509d..88aafa258aba2 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -1161,6 +1161,7 @@ void main() { routerDelegate: delegate, )); expect(tester.takeException(), isAssertionError); + provider.dispose(); }); testWidgetsWithLeakTracking('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index a552d67b6c539..f4286d4586d12 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1582,6 +1582,21 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester expect(info2.location, '/abc?def=ghi&def=jkl#mno'); }); }); + + test('$PlatformRouteInformationProvider dispatches object creation in constructor', () { + int eventCount = 0; + void listener(ObjectEvent event) => eventCount++; + MemoryAllocations.instance.addListener(listener); + + final PlatformRouteInformationProvider registry = PlatformRouteInformationProvider( + initialRouteInformation: RouteInformation(uri: Uri.parse('http://google.com')), + ); + + expect(eventCount, 1); + + registry.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); } Widget buildBoilerPlate(Widget child) { From 69f61a289e10a5389cbb658ce4b535ca9cef1051 Mon Sep 17 00:00:00 2001 From: "Salmanul Farisi.M" <104587392+salmanulfarisi@users.noreply.github.com> Date: Mon, 28 Aug 2023 21:21:56 +0530 Subject: [PATCH 0924/1547] added option to change color of heading row(flutter#132428) (#132728) Paginated datatable widget cannot give color to table header fixes #132428 --------- Co-authored-by: Hans Muller --- .../src/material/paginated_data_table.dart | 6 ++++ .../material/paginated_data_table_test.dart | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index f30cff990356e..06140bebb8fb7 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -17,6 +17,7 @@ import 'icon_button.dart'; import 'icons.dart'; import 'ink_decoration.dart'; import 'material_localizations.dart'; +import 'material_state.dart'; import 'progress_indicator.dart'; import 'theme.dart'; @@ -114,6 +115,7 @@ class PaginatedDataTable extends StatefulWidget { this.checkboxHorizontalMargin, this.controller, this.primary, + this.headingRowColor, }) : assert(actions == null || (header != null)), assert(columns.isNotEmpty), assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)), @@ -288,6 +290,9 @@ class PaginatedDataTable extends StatefulWidget { /// {@macro flutter.widgets.scroll_view.primary} final bool? primary; + /// {@macro flutter.material.dataTable.headingRowColor} + final MaterialStateProperty? headingRowColor; + @override PaginatedDataTableState createState() => PaginatedDataTableState(); } @@ -595,6 +600,7 @@ class PaginatedDataTableState extends State { showCheckboxColumn: widget.showCheckboxColumn, showBottomBorder: true, rows: _getRows(_firstRowIndex, widget.rowsPerPage), + headingRowColor: widget.headingRowColor, ), ), ), diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index 6a10073823a11..db7335627d4e2 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -1264,4 +1264,33 @@ void main() { final Scrollable footerScrollView = tester.widget(find.byType(Scrollable).last); expect(footerScrollView.controller, null); }); + + testWidgets('PaginatedDataTable custom heading row color', (WidgetTester tester) async { + const MaterialStateProperty headingRowColor = MaterialStatePropertyAll(Color(0xffFF0000)); + final TestDataSource source = TestDataSource(); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: PaginatedDataTable( + primary: true, + header: const Text('Test table'), + source: source, + rowsPerPage: 2, + headingRowColor: headingRowColor, + columns: const [ + DataColumn(label: Text('Name')), + DataColumn(label: Text('Calories'), numeric: true), + DataColumn(label: Text('Generation')), + ], + ), + ), + ) + ); + + final Table table = tester.widget(find.byType(Table)); + final TableRow tableRow = table.children[0]; + final BoxDecoration tableRowBoxDecoration = tableRow.decoration! as BoxDecoration; + expect(tableRowBoxDecoration.color, headingRowColor.resolve({})); + }); } From dfd4147ceaf0204feeb2e2c5ca25b6ddc4c84483 Mon Sep 17 00:00:00 2001 From: Justin McCandless Date: Mon, 28 Aug 2023 09:23:52 -0700 Subject: [PATCH 0925/1547] Fix stuck predictive back platform channel calls (#133368) Fix a Google test flakiness increase. --- packages/flutter/lib/src/widgets/app.dart | 17 ++-- .../test/cupertino/tab_scaffold_test.dart | 13 +-- packages/flutter/test/widgets/app_test.dart | 84 +++++++++++++++++++ .../flutter/test/widgets/navigator_test.dart | 13 +-- .../flutter/test/widgets/pop_scope_test.dart | 13 +-- 5 files changed, 117 insertions(+), 23 deletions(-) diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index f8dc851ab00e5..d8d649c103a45 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -1346,12 +1346,18 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { /// the platform with [NavigationNotification.canHandlePop] and stops /// bubbling. bool _defaultOnNavigationNotification(NavigationNotification notification) { - // Don't do anything with navigation notifications if there is no engine - // attached. - if (_appLifecycleState != AppLifecycleState.detached) { - SystemNavigator.setFrameworkHandlesBack(notification.canHandlePop); + switch (_appLifecycleState) { + case null: + case AppLifecycleState.detached: + case AppLifecycleState.inactive: + // Avoid updating the engine when the app isn't ready. + return true; + case AppLifecycleState.resumed: + case AppLifecycleState.hidden: + case AppLifecycleState.paused: + SystemNavigator.setFrameworkHandlesBack(notification.canHandlePop); + return true; } - return true; } @override @@ -1366,6 +1372,7 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { _updateRouting(); _locale = _resolveLocales(WidgetsBinding.instance.platformDispatcher.locales, widget.supportedLocales); WidgetsBinding.instance.addObserver(this); + _appLifecycleState = WidgetsBinding.instance.lifecycleState; } @override diff --git a/packages/flutter/test/cupertino/tab_scaffold_test.dart b/packages/flutter/test/cupertino/tab_scaffold_test.dart index b376a92ecf276..22270d83f0792 100644 --- a/packages/flutter/test/cupertino/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/tab_scaffold_test.dart @@ -1219,11 +1219,7 @@ void main() { group('Android Predictive Back', () { bool? lastFrameworkHandlesBack; - setUp(() { - // Initialize to false. Because this uses a static boolean internally, it - // is not reset between tests or calls to pumpWidget. Explicitly setting - // it to false before each test makes them behave deterministically. - SystemNavigator.setFrameworkHandlesBack(false); + setUp(() async { lastFrameworkHandlesBack = null; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -1233,12 +1229,17 @@ void main() { } return; }); + await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + 'flutter/lifecycle', + const StringCodec().encodeMessage(AppLifecycleState.resumed.toString()), + (ByteData? data) {}, + ); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, null); - SystemNavigator.setFrameworkHandlesBack(true); }); testWidgets('System back navigation inside of tabs', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/app_test.dart b/packages/flutter/test/widgets/app_test.dart index c74273310602c..3540930d1026f 100644 --- a/packages/flutter/test/widgets/app_test.dart +++ b/packages/flutter/test/widgets/app_test.dart @@ -683,6 +683,90 @@ void main() { expect(copySpy.invoked, isTrue); expect(pasteSpy.invoked, isTrue); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + + group('Android Predictive Back', () { + Future setAppLifeCycleState(AppLifecycleState state) async { + final ByteData? message = const StringCodec().encodeMessage(state.toString()); + await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .handlePlatformMessage('flutter/lifecycle', message, (ByteData? data) {}); + } + + final List frameworkHandlesBacks = []; + setUp(() async { + frameworkHandlesBacks.clear(); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { + if (methodCall.method == 'SystemNavigator.setFrameworkHandlesBack') { + expect(methodCall.arguments, isA()); + frameworkHandlesBacks.add(methodCall.arguments as bool); + } + return; + }); + }); + + tearDown(() async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform, null); + await setAppLifeCycleState(AppLifecycleState.resumed); + }); + + testWidgets('WidgetsApp calls setFrameworkHandlesBack only when app is ready', (WidgetTester tester) async { + // Start in the `resumed` state, where setFrameworkHandlesBack should be + // called like normal. + await setAppLifeCycleState(AppLifecycleState.resumed); + + late BuildContext currentContext; + await tester.pumpWidget( + WidgetsApp( + color: const Color(0xFF123456), + builder: (BuildContext context, Widget? child) { + currentContext = context; + return const Placeholder(); + }, + ), + ); + + expect(frameworkHandlesBacks, isEmpty); + + const NavigationNotification(canHandlePop: true).dispatch(currentContext); + await tester.pumpAndSettle(); + expect(frameworkHandlesBacks, isNotEmpty); + expect(frameworkHandlesBacks.last, isTrue); + + const NavigationNotification(canHandlePop: false).dispatch(currentContext); + await tester.pumpAndSettle(); + expect(frameworkHandlesBacks.last, isFalse); + + // Set the app state to inactive, where setFrameworkHandlesBack shouldn't + // be called. + await setAppLifeCycleState(AppLifecycleState.inactive); + + final int finalCallsLength = frameworkHandlesBacks.length; + const NavigationNotification(canHandlePop: true).dispatch(currentContext); + await tester.pumpAndSettle(); + expect(frameworkHandlesBacks, hasLength(finalCallsLength)); + + const NavigationNotification(canHandlePop: false).dispatch(currentContext); + await tester.pumpAndSettle(); + expect(frameworkHandlesBacks, hasLength(finalCallsLength)); + + // Set the app state to detached, which also shouldn't call + // setFrameworkHandlesBack. Must go to paused, then detached. + await setAppLifeCycleState(AppLifecycleState.paused); + await setAppLifeCycleState(AppLifecycleState.detached); + + const NavigationNotification(canHandlePop: true).dispatch(currentContext); + await tester.pumpAndSettle(); + expect(frameworkHandlesBacks, hasLength(finalCallsLength)); + + const NavigationNotification(canHandlePop: false).dispatch(currentContext); + await tester.pumpAndSettle(); + expect(frameworkHandlesBacks, hasLength(finalCallsLength)); + }, + skip: kIsWeb, // [intended] predictive back is only native Android. + variant: const TargetPlatformVariant({ TargetPlatform.android }) + ); + }); } typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation); diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index d403ceba9c80f..52cd934893d7a 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -4159,11 +4159,7 @@ void main() { group('Android Predictive Back', () { bool? lastFrameworkHandlesBack; - setUp(() { - // Initialize to false. Because this uses a static boolean internally, it - // is not reset between tests or calls to pumpWidget. Explicitly setting - // it to false before each test makes them behave deterministically. - SystemNavigator.setFrameworkHandlesBack(false); + setUp(() async { lastFrameworkHandlesBack = null; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -4173,12 +4169,17 @@ void main() { } return; }); + await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + 'flutter/lifecycle', + const StringCodec().encodeMessage(AppLifecycleState.resumed.toString()), + (ByteData? data) {}, + ); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, null); - SystemNavigator.setFrameworkHandlesBack(true); }); testWidgets('a single route is already defaulted to false', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/pop_scope_test.dart b/packages/flutter/test/widgets/pop_scope_test.dart index c5d0e88545034..116951ce78778 100644 --- a/packages/flutter/test/widgets/pop_scope_test.dart +++ b/packages/flutter/test/widgets/pop_scope_test.dart @@ -11,11 +11,7 @@ import 'navigator_utils.dart'; void main() { bool? lastFrameworkHandlesBack; - setUp(() { - // Initialize to false. Because this uses a static boolean internally, it - // is not reset between tests or calls to pumpWidget. Explicitly setting - // it to false before each test makes them behave deterministically. - SystemNavigator.setFrameworkHandlesBack(false); + setUp(() async { lastFrameworkHandlesBack = null; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -25,12 +21,17 @@ void main() { } return; }); + await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .handlePlatformMessage( + 'flutter/lifecycle', + const StringCodec().encodeMessage(AppLifecycleState.resumed.toString()), + (ByteData? data) {}, + ); }); tearDown(() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, null); - SystemNavigator.setFrameworkHandlesBack(true); }); testWidgets('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { From cf91262f75dde4a3a56e14a657e5c870fa1478a9 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 28 Aug 2023 09:38:05 -0700 Subject: [PATCH 0926/1547] ShortcutManager should dispatch creation in constructor. (#133356) --- .../flutter/lib/src/widgets/shortcuts.dart | 7 +++++- .../flutter/test/widgets/shortcuts_test.dart | 22 ++++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 5c66c42997205..c0118e633f608 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -747,7 +747,11 @@ class ShortcutManager with Diagnosticable, ChangeNotifier { ShortcutManager({ Map shortcuts = const {}, this.modal = false, - }) : _shortcuts = shortcuts; + }) : _shortcuts = shortcuts { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } /// True if the [ShortcutManager] should not pass on keys that it doesn't /// handle to any key-handling widgets that are ancestors to this one. @@ -1440,6 +1444,7 @@ class _ShortcutRegistrarState extends State { void dispose() { registry.removeListener(_shortcutsChanged); registry.dispose(); + manager.dispose(); super.dispose(); } diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index 064fdfb231e16..fedf7f9cd291f 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -666,6 +666,19 @@ void main() { expect(pressedKeys, isEmpty); }); + test('$ShortcutManager dispatches object creation in constructor', () { + int eventCount = 0; + void listener(ObjectEvent event) => eventCount++; + MemoryAllocations.instance.addListener(listener); + + final ShortcutManager registry = ShortcutManager(); + + expect(eventCount, 1); + + registry.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); + testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List pressedKeys = []; @@ -1853,20 +1866,17 @@ void main() { token.dispose(); }); - testWidgets('dispatches object creation in constructor', (WidgetTester tester) async { - final MemoryAllocations ma = MemoryAllocations.instance; - assert(!ma.hasListeners); + test('dispatches object creation in constructor', () { int eventCount = 0; void listener(ObjectEvent event) => eventCount++; - ma.addListener(listener); + MemoryAllocations.instance.addListener(listener); final ShortcutRegistry registry = ShortcutRegistry(); expect(eventCount, 1); registry.dispose(); - ma.removeListener(listener); - assert(!ma.hasListeners); + MemoryAllocations.instance.removeListener(listener); }); }); } From 703d60b5e952ed0a9f601c099fd961e9458dd3db Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 28 Aug 2023 09:38:19 -0700 Subject: [PATCH 0927/1547] FocusNode and FocusManager should dispatch creation in constructor. (#133352) --- packages/flutter/lib/src/material/drawer.dart | 1 + .../lib/src/widgets/focus_manager.dart | 7 +++ .../test/widgets/focus_manager_test.dart | 35 +++++++++++++ .../test/widgets/memory_allocations_test.dart | 50 ++++++++++++------- 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index c2b78ce0973f9..fb3ac51bbc36a 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -471,6 +471,7 @@ class DrawerControllerState extends State with SingleTickerPro void dispose() { _historyEntry?.remove(); _controller.dispose(); + _focusScopeNode.dispose(); super.dispose(); } diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 9a4576ea32a83..991cb81534b76 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -437,6 +437,10 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { _descendantsAreTraversable = descendantsAreTraversable { // Set it via the setter so that it does nothing on release builds. this.debugLabel = debugLabel; + + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } } /// If true, tells the focus traversal policy to skip over this node for @@ -1463,6 +1467,9 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { /// handlers, callers must call [registerGlobalHandlers]. See the /// documentation in that method for caveats to watch out for. FocusManager() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } rootScope._manager = this; } diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 0a49b56f4ece9..4516e6f31ce44 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -1609,6 +1609,41 @@ void main() { tester.binding.focusManager.removeListener(handleFocusChange); }); + test('$FocusManager dispatches object creation in constructor', () { + final List events = []; + void listener(ObjectEvent event) { + if (event.object.runtimeType == FocusManager) { + events.add(event); + } + } + MemoryAllocations.instance.addListener(listener); + + final FocusManager focusManager = FocusManager(); + + expect(events, hasLength(1)); + + focusManager.dispose(); + + MemoryAllocations.instance.removeListener(listener); + }); + + test('$FocusNode dispatches object creation in constructor', () { + final List events = []; + void listener(ObjectEvent event) { + if (event.object.runtimeType == FocusNode) { + events.add(event); + } + } + MemoryAllocations.instance.addListener(listener); + + final FocusNode focusManager = FocusNode(); + + expect(events, hasLength(1)); + + focusManager.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); + testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { final FocusNode nodeA = FocusNode(debugLabel: 'a'); final FocusNode nodeB = FocusNode(debugLabel: 'b'); diff --git a/packages/flutter/test/widgets/memory_allocations_test.dart b/packages/flutter/test/widgets/memory_allocations_test.dart index dbb44ac661851..aff4d51900db3 100644 --- a/packages/flutter/test/widgets/memory_allocations_test.dart +++ b/packages/flutter/test/widgets/memory_allocations_test.dart @@ -6,20 +6,26 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; + int _creations = 0; + int _disposals = 0; + void main() { final MemoryAllocations ma = MemoryAllocations.instance; - setUp(() { - assert(!ma.hasListeners); - }); - test('Publishers dispatch events in debug mode', () async { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; + void listener(ObjectEvent event) { + if (event is ObjectDisposed) { + _disposals++; + } + if (event is ObjectCreated) { + _creations++; + } + } ma.addListener(listener); - final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents(); - expect(eventCount, expectedEventCount); + final _EventStats actual = await _activateFlutterObjectsAndReturnCountOfEvents(); + expect(actual.creations, _creations); + expect(actual.disposals, _disposals); ma.removeListener(listener); expect(ma.hasListeners, isFalse); @@ -29,6 +35,8 @@ void main() { bool stateCreated = false; bool stateDisposed = false; + expect(ma.hasListeners, false); + void listener(ObjectEvent event) { if (event is ObjectCreated && event.object is State) { stateCreated = true; @@ -47,7 +55,7 @@ void main() { expect(stateCreated, isTrue); expect(stateDisposed, isTrue); ma.removeListener(listener); - expect(ma.hasListeners, isFalse); + expect(ma.hasListeners, false); }); } @@ -62,7 +70,8 @@ class _TestElement extends RenderObjectElement with RootElementMixin { _TestElement(): super(_TestLeafRenderObjectWidget()); void makeInactive() { - assignOwner(BuildOwner(focusManager: FocusManager())); + final FocusManager newFocusManager = FocusManager(); + assignOwner(BuildOwner(focusManager: newFocusManager)); mount(null, null); deactivate(); } @@ -109,15 +118,22 @@ class _TestStatefulWidgetState extends State<_TestStatefulWidget> { } } + +class _EventStats { + int creations = 0; + int disposals = 0; +} + /// Create and dispose Flutter objects to fire memory allocation events. -Future _activateFlutterObjectsAndReturnCountOfEvents() async { - int count = 0; +Future<_EventStats> _activateFlutterObjectsAndReturnCountOfEvents() async { + final _EventStats result = _EventStats(); - final _TestElement element = _TestElement(); count++; - final RenderObject renderObject = _TestRenderObject(); count++; + final _TestElement element = _TestElement(); result.creations++; + final RenderObject renderObject = _TestRenderObject(); result.creations++; - element.makeInactive(); element.unmount(); count += 3; - renderObject.dispose(); count++; + element.makeInactive(); result.creations += 3; // 1 for the new BuildOwner, 1 for the new FocusManager, 1 for the new FocusScopeNode + element.unmount(); result.disposals += 2; // 1 for the old BuildOwner, 1 for the element + renderObject.dispose(); result.disposals += 1; - return count; + return result; } From 05259ca938c9ea27aa551048b690d5a06371a6c0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 12:54:01 -0400 Subject: [PATCH 0928/1547] Roll Flutter Engine from 9ab2603db24f to 91522a188bda (2 revisions) (#133462) https://github.com/flutter/engine/compare/9ab2603db24f...91522a188bda 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from fe4f018ef935 to df783b542165 (1 revision) (flutter/engine#45171) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 0d39172f35d2 to fe4f018ef935 (1 revision) (flutter/engine#45169) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 45880b6659252..46aef26148911 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9ab2603db24f7537aff4ee1d57f8cd95cecd6bf5 +91522a188bdad2cef6ac34ffdd20386a6d9bcb4d From ec387a467a68fcef5a2a5a95aee3fd201cee0d8a Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 28 Aug 2023 12:34:23 -0500 Subject: [PATCH 0929/1547] Revert "ShortcutManager should dispatch creation in constructor." (#133472) Reverts flutter/flutter#133356 Tree is failing on customer_testing on this PR. https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20customer_testing/14646/overview --- .../flutter/lib/src/widgets/shortcuts.dart | 7 +----- .../flutter/test/widgets/shortcuts_test.dart | 22 +++++-------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index c0118e633f608..5c66c42997205 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -747,11 +747,7 @@ class ShortcutManager with Diagnosticable, ChangeNotifier { ShortcutManager({ Map shortcuts = const {}, this.modal = false, - }) : _shortcuts = shortcuts { - if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); - } - } + }) : _shortcuts = shortcuts; /// True if the [ShortcutManager] should not pass on keys that it doesn't /// handle to any key-handling widgets that are ancestors to this one. @@ -1444,7 +1440,6 @@ class _ShortcutRegistrarState extends State { void dispose() { registry.removeListener(_shortcutsChanged); registry.dispose(); - manager.dispose(); super.dispose(); } diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index fedf7f9cd291f..064fdfb231e16 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -666,19 +666,6 @@ void main() { expect(pressedKeys, isEmpty); }); - test('$ShortcutManager dispatches object creation in constructor', () { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; - MemoryAllocations.instance.addListener(listener); - - final ShortcutManager registry = ShortcutManager(); - - expect(eventCount, 1); - - registry.dispose(); - MemoryAllocations.instance.removeListener(listener); - }); - testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List pressedKeys = []; @@ -1866,17 +1853,20 @@ void main() { token.dispose(); }); - test('dispatches object creation in constructor', () { + testWidgets('dispatches object creation in constructor', (WidgetTester tester) async { + final MemoryAllocations ma = MemoryAllocations.instance; + assert(!ma.hasListeners); int eventCount = 0; void listener(ObjectEvent event) => eventCount++; - MemoryAllocations.instance.addListener(listener); + ma.addListener(listener); final ShortcutRegistry registry = ShortcutRegistry(); expect(eventCount, 1); registry.dispose(); - MemoryAllocations.instance.removeListener(listener); + ma.removeListener(listener); + assert(!ma.hasListeners); }); }); } From 76d6d36b7abee08b4fe57ac1dadc8cdcc3815898 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 28 Aug 2023 12:50:22 -0500 Subject: [PATCH 0930/1547] Revert "FocusNode and FocusManager should dispatch creation in constructor." (#133474) Reverts flutter/flutter#133352 Tree is failing on Mac and Linux customer_testing on this PR. https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20customer_testing/14646/overview https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20customer_testing/14974/overview --- packages/flutter/lib/src/material/drawer.dart | 1 - .../lib/src/widgets/focus_manager.dart | 7 --- .../test/widgets/focus_manager_test.dart | 35 ------------- .../test/widgets/memory_allocations_test.dart | 50 +++++++------------ 4 files changed, 17 insertions(+), 76 deletions(-) diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index fb3ac51bbc36a..c2b78ce0973f9 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -471,7 +471,6 @@ class DrawerControllerState extends State with SingleTickerPro void dispose() { _historyEntry?.remove(); _controller.dispose(); - _focusScopeNode.dispose(); super.dispose(); } diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 991cb81534b76..9a4576ea32a83 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -437,10 +437,6 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { _descendantsAreTraversable = descendantsAreTraversable { // Set it via the setter so that it does nothing on release builds. this.debugLabel = debugLabel; - - if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); - } } /// If true, tells the focus traversal policy to skip over this node for @@ -1467,9 +1463,6 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { /// handlers, callers must call [registerGlobalHandlers]. See the /// documentation in that method for caveats to watch out for. FocusManager() { - if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); - } rootScope._manager = this; } diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 4516e6f31ce44..0a49b56f4ece9 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -1609,41 +1609,6 @@ void main() { tester.binding.focusManager.removeListener(handleFocusChange); }); - test('$FocusManager dispatches object creation in constructor', () { - final List events = []; - void listener(ObjectEvent event) { - if (event.object.runtimeType == FocusManager) { - events.add(event); - } - } - MemoryAllocations.instance.addListener(listener); - - final FocusManager focusManager = FocusManager(); - - expect(events, hasLength(1)); - - focusManager.dispose(); - - MemoryAllocations.instance.removeListener(listener); - }); - - test('$FocusNode dispatches object creation in constructor', () { - final List events = []; - void listener(ObjectEvent event) { - if (event.object.runtimeType == FocusNode) { - events.add(event); - } - } - MemoryAllocations.instance.addListener(listener); - - final FocusNode focusManager = FocusNode(); - - expect(events, hasLength(1)); - - focusManager.dispose(); - MemoryAllocations.instance.removeListener(listener); - }); - testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { final FocusNode nodeA = FocusNode(debugLabel: 'a'); final FocusNode nodeB = FocusNode(debugLabel: 'b'); diff --git a/packages/flutter/test/widgets/memory_allocations_test.dart b/packages/flutter/test/widgets/memory_allocations_test.dart index aff4d51900db3..dbb44ac661851 100644 --- a/packages/flutter/test/widgets/memory_allocations_test.dart +++ b/packages/flutter/test/widgets/memory_allocations_test.dart @@ -6,26 +6,20 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; - int _creations = 0; - int _disposals = 0; - void main() { final MemoryAllocations ma = MemoryAllocations.instance; + setUp(() { + assert(!ma.hasListeners); + }); + test('Publishers dispatch events in debug mode', () async { - void listener(ObjectEvent event) { - if (event is ObjectDisposed) { - _disposals++; - } - if (event is ObjectCreated) { - _creations++; - } - } + int eventCount = 0; + void listener(ObjectEvent event) => eventCount++; ma.addListener(listener); - final _EventStats actual = await _activateFlutterObjectsAndReturnCountOfEvents(); - expect(actual.creations, _creations); - expect(actual.disposals, _disposals); + final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents(); + expect(eventCount, expectedEventCount); ma.removeListener(listener); expect(ma.hasListeners, isFalse); @@ -35,8 +29,6 @@ void main() { bool stateCreated = false; bool stateDisposed = false; - expect(ma.hasListeners, false); - void listener(ObjectEvent event) { if (event is ObjectCreated && event.object is State) { stateCreated = true; @@ -55,7 +47,7 @@ void main() { expect(stateCreated, isTrue); expect(stateDisposed, isTrue); ma.removeListener(listener); - expect(ma.hasListeners, false); + expect(ma.hasListeners, isFalse); }); } @@ -70,8 +62,7 @@ class _TestElement extends RenderObjectElement with RootElementMixin { _TestElement(): super(_TestLeafRenderObjectWidget()); void makeInactive() { - final FocusManager newFocusManager = FocusManager(); - assignOwner(BuildOwner(focusManager: newFocusManager)); + assignOwner(BuildOwner(focusManager: FocusManager())); mount(null, null); deactivate(); } @@ -118,22 +109,15 @@ class _TestStatefulWidgetState extends State<_TestStatefulWidget> { } } - -class _EventStats { - int creations = 0; - int disposals = 0; -} - /// Create and dispose Flutter objects to fire memory allocation events. -Future<_EventStats> _activateFlutterObjectsAndReturnCountOfEvents() async { - final _EventStats result = _EventStats(); +Future _activateFlutterObjectsAndReturnCountOfEvents() async { + int count = 0; - final _TestElement element = _TestElement(); result.creations++; - final RenderObject renderObject = _TestRenderObject(); result.creations++; + final _TestElement element = _TestElement(); count++; + final RenderObject renderObject = _TestRenderObject(); count++; - element.makeInactive(); result.creations += 3; // 1 for the new BuildOwner, 1 for the new FocusManager, 1 for the new FocusScopeNode - element.unmount(); result.disposals += 2; // 1 for the old BuildOwner, 1 for the element - renderObject.dispose(); result.disposals += 1; + element.makeInactive(); element.unmount(); count += 3; + renderObject.dispose(); count++; - return result; + return count; } From f1f46ef2d380dba878637a29c8627fcd7dfa5277 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 28 Aug 2023 13:13:21 -0500 Subject: [PATCH 0931/1547] Revert "PlatformRouteInformationProvider should dispatch creation in constructor." (#133479) Reverts flutter/flutter#133353 Tree is failing on Mac and Linux customer_testing on this PR. https://ci.chromium.org/ui/p/flutter/builders/prod/Mac%20customer_testing/14646/overview https://ci.chromium.org/ui/p/flutter/builders/prod/Linux%20customer_testing/14974/overview --- packages/flutter/lib/src/widgets/router.dart | 6 +----- packages/flutter/test/material/app_test.dart | 1 - packages/flutter/test/widgets/router_test.dart | 15 --------------- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index f0ea0861005c8..63db13e365483 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1465,11 +1465,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid /// provider. PlatformRouteInformationProvider({ required RouteInformation initialRouteInformation, - }) : _value = initialRouteInformation { - if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); - } - } + }) : _value = initialRouteInformation; static bool _equals(Uri a, Uri b) { return a.path == b.path diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 88aafa258aba2..87e8564da509d 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -1161,7 +1161,6 @@ void main() { routerDelegate: delegate, )); expect(tester.takeException(), isAssertionError); - provider.dispose(); }); testWidgetsWithLeakTracking('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index f4286d4586d12..a552d67b6c539 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1582,21 +1582,6 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester expect(info2.location, '/abc?def=ghi&def=jkl#mno'); }); }); - - test('$PlatformRouteInformationProvider dispatches object creation in constructor', () { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; - MemoryAllocations.instance.addListener(listener); - - final PlatformRouteInformationProvider registry = PlatformRouteInformationProvider( - initialRouteInformation: RouteInformation(uri: Uri.parse('http://google.com')), - ); - - expect(eventCount, 1); - - registry.dispose(); - MemoryAllocations.instance.removeListener(listener); - }); } Widget buildBoilerPlate(Widget child) { From e7fc5a6e517ab23c479e5a9397e027b883914f9b Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:36:32 -0500 Subject: [PATCH 0932/1547] Empty commit to re-trigger tests (#133495) An empty commit to re-trigger tests for https://github.com/flutter/tests/pull/291 From a0943e65336778b04101a9fed7408999f43f7a72 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 28 Aug 2023 23:52:54 +0300 Subject: [PATCH 0933/1547] Fix `DatePickerDialog` & `DateRangePickerDialog` overflow when resized from landscape to portrait (#133327) fixes [resize window with a `showDateRangePicker` will make RenderFlex overflowed error](https://github.com/flutter/flutter/issues/131989) ### Description - This fixes `DatePickerDialog` & `DateRangePickerDialog` overflow error when resized from landscape to portrait. - Added tests that check these two widgets from landscape to portrait for no overflow errors.
    expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: Example(), ); } } class Example extends StatefulWidget { const Example({super.key}); @override State createState() => _ExampleState(); } class _ExampleState extends State { bool _portait = false; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('DatePicker & DateRangePicker'), ), body: MediaQuery( data: MediaQuery.of(context).copyWith( size: _portait ? const Size(400, 800) : const Size(800, 400), ), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ DatePickerDialog( initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), initialEntryMode: DatePickerEntryMode.inputOnly, ), DateRangePickerDialog( currentDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), initialEntryMode: DatePickerEntryMode.inputOnly, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { _portait = !_portait; }); }, child: const Icon(Icons.refresh), ), ); } } ```
    ### Before https://github.com/flutter/flutter/assets/48603081/81387cbb-cdcf-42bd-b4f8-b7a08317c955 ### After https://github.com/flutter/flutter/assets/48603081/36d28ea9-cfed-48ad-90f5-0459755e08c0 --- .../flutter/lib/src/material/date_picker.dart | 40 ++++++++++++++----- .../test/material/date_picker_test.dart | 16 ++++++++ .../test/material/date_range_picker_test.dart | 19 +++++++++ 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index ea585561f5cb7..6b495fa88ba00 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -674,7 +674,12 @@ class _DatePickerDialogState extends State with RestorationMix // Constrain the textScaleFactor to the largest supported value to prevent // layout issues. maxScaleFactor: _kMaxTextScaleFactor, - child: Builder(builder: (BuildContext context) { + child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { + final Size portraitDialogSize = useMaterial3 ? _inputPortraitDialogSizeM3 : _inputPortraitDialogSizeM2; + // Make sure the portrait dialog can fit the contents comfortably when + // resized from the landscape dialog. + final bool isFullyPortrait = constraints.maxHeight >= portraitDialogSize.height; + switch (orientation) { case Orientation.portrait: return Column( @@ -683,8 +688,10 @@ class _DatePickerDialogState extends State with RestorationMix children: [ header, if (useMaterial3) Divider(height: 0, color: datePickerTheme.dividerColor), - Expanded(child: picker), - actions, + if (isFullyPortrait) ...[ + Expanded(child: picker), + actions, + ], ], ); case Orientation.landscape: @@ -2775,14 +2782,25 @@ class _InputDateRangePickerDialog extends StatelessWidget { switch (orientation) { case Orientation.portrait: - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - header, - Expanded(child: picker), - actions, - ], + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + final Size portraitDialogSize = useMaterial3 ? _inputPortraitDialogSizeM3 : _inputPortraitDialogSizeM2; + // Make sure the portrait dialog can fit the contents comfortably when + // resized from the landscape dialog. + final bool isFullyPortrait = constraints.maxHeight >= portraitDialogSize.height; + + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + header, + if (isFullyPortrait) ...[ + Expanded(child: picker), + actions, + ], + ], + ); + } ); case Orientation.landscape: diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 4c47543d14775..66cddc20c9138 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -1469,6 +1469,22 @@ void main() { expect(tester.takeException(), null); }); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/131989. + testWidgets('Dialog contents do not overflow when resized from landscape to portrait', + (WidgetTester tester) async { + addTearDown(tester.view.reset); + // Initial window size is wide for landscape mode. + tester.view.physicalSize = wideWindowSize; + tester.view.devicePixelRatio = 1.0; + + await prepareDatePicker(tester, (Future date) async { + // Change window size to narrow for portrait mode. + tester.view.physicalSize = narrowWindowSize; + await tester.pump(); + expect(tester.takeException(), null); + }); + }); }); group('Semantics', () { diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index 6bd0e10eff513..14f7b2e8adb7d 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -53,6 +53,9 @@ void main() { saveText = null; }); + const Size wideWindowSize = Size(1920.0, 1080.0); + const Size narrowWindowSize = Size(1070.0, 1770.0); + Future preparePicker( WidgetTester tester, Future Function(Future date) callback, { @@ -1065,6 +1068,22 @@ void main() { // Test the end date text field testInputDecorator(tester.widget(borderContainers.last), border, Colors.transparent); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/131989. + testWidgets('Dialog contents do not overflow when resized from landscape to portrait', + (WidgetTester tester) async { + addTearDown(tester.view.reset); + // Initial window size is wide for landscape mode. + tester.view.physicalSize = wideWindowSize; + tester.view.devicePixelRatio = 1.0; + + await preparePicker(tester, (Future range) async { + // Change window size to narrow for portrait mode. + tester.view.physicalSize = narrowWindowSize; + await tester.pump(); + expect(tester.takeException(), null); + }); + }); }); testWidgets('DatePickerDialog is state restorable', (WidgetTester tester) async { From c046627482709198e2e09c4a90995f0ca262713b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Aug 2023 21:59:11 +0000 Subject: [PATCH 0934/1547] Bump github/codeql-action from 2.21.4 to 2.21.5 (#133504) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.4 to 2.21.5.
    Changelog

    Sourced from github/codeql-action's changelog.

    CodeQL Action Changelog

    See the releases page for the relevant changes to the CodeQL CLI and language packs.

    [UNRELEASED]

    No user facing changes.

    2.21.5 - 28 Aug 2023

    • Update default CodeQL bundle version to 2.14.3. #1845
    • Fixed a bug in CodeQL Action 2.21.3 onwards that affected beta support for Project Lombok when analyzing Java. The environment variable CODEQL_EXTRACTOR_JAVA_RUN_ANNOTATION_PROCESSORS will now be respected if it was manually configured in the workflow. #1844
    • Enable support for Kotlin 1.9.20 when running with CodeQL CLI v2.13.4 through v2.14.3. #1853

    2.21.4 - 14 Aug 2023

    • Update default CodeQL bundle version to 2.14.2. #1831
    • Log a warning if the amount of available disk space runs low during a code scanning run. #1825
    • When downloading CodeQL bundle version 2.13.4 and later, cache these bundles in the Actions tool cache using a simpler version number. #1832
    • Fix an issue that first appeared in CodeQL Action v2.21.2 that prevented CodeQL invocations from being logged. #1833
    • We are rolling out a feature in August 2023 that will improve the quality of file coverage information. #1835

    2.21.3 - 08 Aug 2023

    • We are rolling out a feature in August 2023 that will improve multi-threaded performance on larger runners. #1817
    • We are rolling out a feature in August 2023 that adds beta support for Project Lombok when analyzing Java. #1809
    • Reduce disk space usage when downloading the CodeQL bundle. #1820

    2.21.2 - 28 Jul 2023

    • Update default CodeQL bundle version to 2.14.1. #1797
    • Avoid duplicating the analysis summary within the logs. #1811

    2.21.1 - 26 Jul 2023

    • Improve the handling of fatal errors from the CodeQL CLI. #1795
    • Add the sarif-output output to the analyze action that contains the path to the directory of the generated SARIF. #1799

    2.21.0 - 19 Jul 2023

    • CodeQL Action now requires CodeQL CLI 2.9.4 or later. For more information, see the corresponding changelog entry for CodeQL Action version 2.20.4. #1724

    2.20.4 - 14 Jul 2023

    • This is the last release of the Action that supports CodeQL CLI versions 2.8.5 to 2.9.3. These versions of the CodeQL CLI were deprecated on June 20, 2023 alongside GitHub Enterprise Server 3.5 and will not be supported by the next release of the CodeQL Action (2.21.0).
      • If you are using one of these versions, please update to CodeQL CLI version 2.9.4 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
      • Alternatively, if you want to continue using a version of the CodeQL CLI between 2.8.5 and 2.9.3, you can replace 'github/codeql-action/@​v2' by 'github/codeql-action/@​v2.20.4' in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
    • We are rolling out a feature in July 2023 that will slightly reduce the default amount of RAM used for query execution, in proportion to the runner's total memory. This will help to avoid out-of-memory failures on larger runners. #1760
    • Update default CodeQL bundle version to 2.14.0. #1762

    ... (truncated)

    Commits
    • 00e563e Merge pull request #1858 from github/update-v2.21.5-100912429
    • 7323c2a Update changelog for v2.21.5
    • 1009124 Merge pull request #1845 from github/update-bundle/codeql-bundle-v2.14.3
    • a2d14d3 Merge branch 'main' into update-bundle/codeql-bundle-v2.14.3
    • ff9cb43 Merge pull request #1853 from github/igfoo/kot1.9.10
    • 2f913c1 npm run build
    • 7dab600 Put upper limit on the CodeQL versions for which we override the Kotlin limit
    • 862b2cf Add a changelog entry for the Kotlin 1.9.10 support
    • 070dd05 npm run build
    • ff95d14 Kotlin: Fix lint
    • Additional commits viewable in compare view

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.21.4&new-version=2.21.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 05fec9a14f639..7da93dccfb729 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@a09933a12a80f87b87005513f0abb1494c27a716 + uses: github/codeql-action/upload-sarif@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8 with: sarif_file: results.sarif From ca33836b4516792e97e8786a66032a991ffaaedb Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Mon, 28 Aug 2023 15:27:39 -0700 Subject: [PATCH 0935/1547] Fix context menu button color on Android when textButtonTheme is set (#133271) Fixes #133027 When setting a `textButtonTheme` it should not override the native context menu colors. ```dart theme: ThemeData( textButtonTheme: const TextButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStatePropertyAll( Color(0xff05164d)), // blue color ), ), ), ``` Before|After --|-- Screenshot 2023-08-24 at 1 17 25 PM|Screenshot 2023-08-24 at 1 15 35 PM --- .../text_selection_toolbar_text_button.dart | 7 ++ ...xt_selection_toolbar_text_button_test.dart | 67 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart b/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart index e4ac077c14a5d..844da98ce053e 100644 --- a/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart +++ b/packages/flutter/lib/src/material/text_selection_toolbar_text_button.dart @@ -135,6 +135,12 @@ class TextSelectionToolbarTextButton extends StatelessWidget { static const Color _defaultForegroundColorLight = Color(0xff000000); static const Color _defaultForegroundColorDark = Color(0xffffffff); + // The background color is hardcoded to transparent by default so the buttons + // are the color of the container behind them. For example TextSelectionToolbar + // hardcodes the color value, and TextSelectionToolbarTextButtons that are its + // children become that color. + static const Color _defaultBackgroundColorTransparent = Color(0x00000000); + static Color _getForegroundColor(ColorScheme colorScheme) { final bool isDefaultOnSurface = switch (colorScheme.brightness) { Brightness.light => identical(ThemeData().colorScheme.onSurface, colorScheme.onSurface), @@ -154,6 +160,7 @@ class TextSelectionToolbarTextButton extends StatelessWidget { final ColorScheme colorScheme = Theme.of(context).colorScheme; return TextButton( style: TextButton.styleFrom( + backgroundColor: _defaultBackgroundColorTransparent, foregroundColor: _getForegroundColor(colorScheme), shape: const RoundedRectangleBorder(), minimumSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension), diff --git a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart index f2f6cbd10cf22..24de64a8000d2 100644 --- a/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_text_button_test.dart @@ -123,5 +123,72 @@ void main() { customForegroundColor, ); }); + + testWidgetsWithLeakTracking('background color by default', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/133027 + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: colorScheme, + ), + home: Scaffold( + body: Center( + child: TextSelectionToolbarTextButton( + padding: TextSelectionToolbarTextButton.getPadding(0, 1), + child: const Text('button'), + ), + ), + ), + ), + ); + + expect(find.byType(TextButton), findsOneWidget); + + final TextButton textButton = tester.widget(find.byType(TextButton)); + // The background color is hardcoded to transparent by default so the buttons + // are the color of the container behind them. For example TextSelectionToolbar + // hardcodes the color value, and TextSelectionToolbarTextButton that are its + // children should be that color. + expect( + textButton.style!.backgroundColor!.resolve({}), + Colors.transparent, + ); + }); + + testWidgetsWithLeakTracking('textButtonTheme should not override default background color', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/133027 + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: colorScheme, + textButtonTheme: const TextButtonThemeData( + style: ButtonStyle( + backgroundColor: MaterialStatePropertyAll(Colors.blue), + ), + ), + ), + home: Scaffold( + body: Center( + child: TextSelectionToolbarTextButton( + padding: TextSelectionToolbarTextButton.getPadding(0, 1), + child: const Text('button'), + ), + ), + ), + ), + ); + + expect(find.byType(TextButton), findsOneWidget); + + final TextButton textButton = tester.widget(find.byType(TextButton)); + // The background color is hardcoded to transparent by default so the buttons + // are the color of the container behind them. For example TextSelectionToolbar + // hardcodes the color value, and TextSelectionToolbarTextButton that are its + // children should be that color. + expect( + textButton.style!.backgroundColor!.resolve({}), + Colors.transparent, + ); + }); } } From 7772f6b05aede3b8b1356fbd1ce56e0723252bea Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Mon, 28 Aug 2023 15:39:10 -0700 Subject: [PATCH 0936/1547] =?UTF-8?q?Revert=20"Remove=20`ImageProvider.loa?= =?UTF-8?q?d`,=20`DecoderCallback`=20and=20`PaintingB=E2=80=A6=20(#133482)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …inding.instantiateImageCodec` (#132679)" This reverts commit b4f4ece40d956ad86efa340ff7fe9d0fa6deea07. Trial revert for https://github.com/flutter/flutter/issues/133398 Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> --- .../lib/src/painting/_network_image_io.dart | 39 ++- .../lib/src/painting/_network_image_web.dart | 40 +++- .../flutter/lib/src/painting/binding.dart | 41 ++++ .../lib/src/painting/image_decoder.dart | 9 +- .../lib/src/painting/image_provider.dart | 226 +++++++++++++++--- .../widgets/scroll_aware_image_provider.dart | 5 +- .../flutter/test/material/switch_test.dart | 4 +- .../test/painting/decoration_test.dart | 10 +- .../test/painting/fake_image_provider.dart | 2 +- .../test/painting/image_test_utils.dart | 5 + .../test/painting/mocks_for_image_cache.dart | 21 +- .../flutter/test/painting/painting_utils.dart | 4 +- .../test/painting/shape_decoration_test.dart | 2 +- .../test/widgets/box_decoration_test.dart | 2 +- .../test/widgets/fade_in_image_test.dart | 2 +- .../widgets/image_filter_quality_test.dart | 2 +- .../flutter/test/widgets/image_rtl_test.dart | 2 +- packages/flutter/test/widgets/image_test.dart | 4 +- 18 files changed, 345 insertions(+), 75 deletions(-) diff --git a/packages/flutter/lib/src/painting/_network_image_io.dart b/packages/flutter/lib/src/painting/_network_image_io.dart index 5221279c61d16..05dd8cb722291 100644 --- a/packages/flutter/lib/src/painting/_network_image_io.dart +++ b/packages/flutter/lib/src/painting/_network_image_io.dart @@ -13,9 +13,6 @@ import 'debug.dart'; import 'image_provider.dart' as image_provider; import 'image_stream.dart'; -// Method signature for _loadAsync decode callbacks. -typedef _SimpleDecoderCallback = Future Function(ui.ImmutableBuffer buffer); - /// The dart:io implementation of [image_provider.NetworkImage]. @immutable class NetworkImage extends image_provider.ImageProvider implements image_provider.NetworkImage { @@ -38,6 +35,25 @@ class NetworkImage extends image_provider.ImageProvider(this); } + @override + ImageStreamCompleter load(image_provider.NetworkImage key, image_provider.DecoderCallback decode) { + // Ownership of this controller is handed off to [_loadAsync]; it is that + // method's responsibility to close the controller's stream when the image + // has been loaded or an error is thrown. + final StreamController chunkEvents = StreamController(); + + return MultiFrameImageStreamCompleter( + codec: _loadAsync(key as NetworkImage, chunkEvents, decodeDeprecated: decode), + chunkEvents: chunkEvents.stream, + scale: key.scale, + debugLabel: key.url, + informationCollector: () => [ + DiagnosticsProperty('Image provider', this), + DiagnosticsProperty('Image key', key), + ], + ); + } + @override ImageStreamCompleter loadBuffer(image_provider.NetworkImage key, image_provider.DecoderBufferCallback decode) { // Ownership of this controller is handed off to [_loadAsync]; it is that @@ -46,7 +62,7 @@ class NetworkImage extends image_provider.ImageProvider chunkEvents = StreamController(); return MultiFrameImageStreamCompleter( - codec: _loadAsync(key as NetworkImage, chunkEvents, decode: decode), + codec: _loadAsync(key as NetworkImage, chunkEvents, decodeBufferDeprecated: decode), chunkEvents: chunkEvents.stream, scale: key.scale, debugLabel: key.url, @@ -96,7 +112,9 @@ class NetworkImage extends image_provider.ImageProvider _loadAsync( NetworkImage key, StreamController chunkEvents, { - required _SimpleDecoderCallback decode, + image_provider.ImageDecoderCallback? decode, + image_provider.DecoderBufferCallback? decodeBufferDeprecated, + image_provider.DecoderCallback? decodeDeprecated, }) async { try { assert(key == this); @@ -130,7 +148,16 @@ class NetworkImage extends image_provider.ImageProvider Function(ui.ImmutableBuffer buffer); - /// Default HTTP client. web.XMLHttpRequest _httpClient() { return web.XMLHttpRequest(); @@ -57,6 +54,23 @@ class NetworkImage return SynchronousFuture(this); } + @override + ImageStreamCompleter load(image_provider.NetworkImage key, image_provider.DecoderCallback decode) { + // Ownership of this controller is handed off to [_loadAsync]; it is that + // method's responsibility to close the controller's stream when the image + // has been loaded or an error is thrown. + final StreamController chunkEvents = + StreamController(); + + return MultiFrameImageStreamCompleter( + chunkEvents: chunkEvents.stream, + codec: _loadAsync(key as NetworkImage, null, null, decode, chunkEvents), + scale: key.scale, + debugLabel: key.url, + informationCollector: _imageStreamInformationCollector(key), + ); + } + @override ImageStreamCompleter loadBuffer(image_provider.NetworkImage key, image_provider.DecoderBufferCallback decode) { // Ownership of this controller is handed off to [_loadAsync]; it is that @@ -67,7 +81,7 @@ class NetworkImage return MultiFrameImageStreamCompleter( chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, decode, chunkEvents), + codec: _loadAsync(key as NetworkImage, null, decode, null, chunkEvents), scale: key.scale, debugLabel: key.url, informationCollector: _imageStreamInformationCollector(key), @@ -83,7 +97,7 @@ class NetworkImage return MultiFrameImageStreamCompleter( chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, decode, chunkEvents), + codec: _loadAsync(key as NetworkImage, decode, null, null, chunkEvents), scale: key.scale, debugLabel: key.url, informationCollector: _imageStreamInformationCollector(key), @@ -107,7 +121,9 @@ class NetworkImage // directly in place of the typical `instantiateImageCodec` method. Future _loadAsync( NetworkImage key, - _SimpleDecoderCallback decode, + image_provider.ImageDecoderCallback? decode, + image_provider.DecoderBufferCallback? decodeBufferDeprecated, + image_provider.DecoderCallback? decodeDeprecated, StreamController chunkEvents, ) async { assert(key == this); @@ -162,7 +178,17 @@ class NetworkImage throw image_provider.NetworkImageLoadException( statusCode: request.status, uri: resolved); } - return decode(await ui.ImmutableBuffer.fromUint8List(bytes)); + + if (decode != null) { + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); + return decode(buffer); + } else if (decodeBufferDeprecated != null) { + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); + return decodeBufferDeprecated(buffer); + } else { + assert(decodeDeprecated != null); + return decodeDeprecated!(bytes); + } } else { // This API only exists in the web engine implementation and is not // contained in the analyzer summary for Flutter. diff --git a/packages/flutter/lib/src/painting/binding.dart b/packages/flutter/lib/src/painting/binding.dart index 02efc9082ac7c..880db6d33fa23 100644 --- a/packages/flutter/lib/src/painting/binding.dart +++ b/packages/flutter/lib/src/painting/binding.dart @@ -78,6 +78,47 @@ mixin PaintingBinding on BindingBase, ServicesBinding { @protected ImageCache createImageCache() => ImageCache(); + /// Calls through to [dart:ui.instantiateImageCodec] from [ImageCache]. + /// + /// This method is deprecated. use [instantiateImageCodecFromBuffer] with an + /// [ImmutableBuffer] instance instead of this method. + /// + /// The `cacheWidth` and `cacheHeight` parameters, when specified, indicate + /// the size to decode the image to. + /// + /// Both `cacheWidth` and `cacheHeight` must be positive values greater than + /// or equal to 1, or null. It is valid to specify only one of `cacheWidth` + /// and `cacheHeight` with the other remaining null, in which case the omitted + /// dimension will be scaled to maintain the aspect ratio of the original + /// dimensions. When both are null or omitted, the image will be decoded at + /// its native resolution. + /// + /// The `allowUpscaling` parameter determines whether the `cacheWidth` or + /// `cacheHeight` parameters are clamped to the intrinsic width and height of + /// the original image. By default, the dimensions are clamped to avoid + /// unnecessary memory usage for images. Callers that wish to display an image + /// above its native resolution should prefer scaling the canvas the image is + /// drawn into. + @Deprecated( + 'Use instantiateImageCodecWithSize with an ImmutableBuffer instance instead. ' + 'This feature was deprecated after v2.13.0-1.0.pre.', + ) + Future instantiateImageCodec( + Uint8List bytes, { + int? cacheWidth, + int? cacheHeight, + bool allowUpscaling = false, + }) { + assert(cacheWidth == null || cacheWidth > 0); + assert(cacheHeight == null || cacheHeight > 0); + return ui.instantiateImageCodec( + bytes, + targetWidth: cacheWidth, + targetHeight: cacheHeight, + allowUpscaling: allowUpscaling, + ); + } + /// Calls through to [dart:ui.instantiateImageCodecFromBuffer] from [ImageCache]. /// /// The [buffer] parameter should be an [ui.ImmutableBuffer] instance which can diff --git a/packages/flutter/lib/src/painting/image_decoder.dart b/packages/flutter/lib/src/painting/image_decoder.dart index 328c840f7393f..39d926ee341a1 100644 --- a/packages/flutter/lib/src/painting/image_decoder.dart +++ b/packages/flutter/lib/src/painting/image_decoder.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'dart:typed_data'; -import 'dart:ui' as ui show Codec, FrameInfo, Image, ImmutableBuffer; +import 'dart:ui' as ui show Codec, FrameInfo, Image; import 'binding.dart'; @@ -17,11 +17,10 @@ import 'binding.dart'; /// [instantiateImageCodec] if support for animated images is necessary. /// /// This function differs from [ui.decodeImageFromList] in that it defers to -/// [PaintingBinding.instantiateImageCodecWithSize], and therefore can be mocked -/// in tests. +/// [PaintingBinding.instantiateImageCodec], and therefore can be mocked in +/// tests. Future decodeImageFromList(Uint8List bytes) async { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); + final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodec(bytes); final ui.FrameInfo frameInfo = await codec.getNextFrame(); return frameInfo.image; } diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index b7067c2583dd7..54e21cc5977ef 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -160,6 +160,25 @@ class ImageConfiguration { } } +/// Performs the decode process for use in [ImageProvider.load]. +/// +/// This typedef is deprecated. Use [ImageDecoderCallback] with +/// [ImageProvider.loadImage] instead. +/// +/// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and +/// `allowUpscaling` parameters from implementations of [ImageProvider] that do +/// not expose them. +/// +/// See also: +/// +/// * [ResizeImage], which uses this to override the `cacheWidth`, +/// `cacheHeight`, and `allowUpscaling` parameters. +@Deprecated( + 'Use ImageDecoderCallback with ImageProvider.loadImage instead. ' + 'This feature was deprecated after v2.13.0-1.0.pre.', +) +typedef DecoderCallback = Future Function(Uint8List buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling}); + /// Performs the decode process for use in [ImageProvider.loadBuffer]. /// /// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and @@ -176,9 +195,6 @@ class ImageConfiguration { ) typedef DecoderBufferCallback = Future Function(ui.ImmutableBuffer buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling}); -// Method signature for _loadAsync decode callbacks. -typedef _SimpleDecoderCallback = Future Function(ui.ImmutableBuffer buffer); - /// Performs the decode process for use in [ImageProvider.loadImage]. /// /// This callback allows decoupling of the `getTargetSize` parameter from @@ -234,7 +250,7 @@ typedef ImageDecoderCallback = Future Function( /// from the cache if possible, or call [loadImage] to fetch the encoded image /// bytes and schedule decoding. /// 4. The [loadImage] method is responsible for both fetching the encoded bytes -/// and decoding them using the provided [ImageDecoderCallback]. It is called +/// and decoding them using the provided [DecoderCallback]. It is called /// in a context that uses the [ImageErrorListener] to report errors back. /// /// Subclasses normally only have to implement the [loadImage] and [obtainKey] @@ -349,10 +365,10 @@ abstract class ImageProvider { /// /// This is the public entry-point of the [ImageProvider] class hierarchy. /// - /// Subclasses should implement [obtainKey] and [loadImage], which are used by - /// this method. If they need to change the implementation of [ImageStream] - /// used, they should override [createStream]. If they need to manage the - /// actual resolution of the image, they should override [resolveStreamForKey]. + /// Subclasses should implement [obtainKey] and [load], which are used by this + /// method. If they need to change the implementation of [ImageStream] used, + /// they should override [createStream]. If they need to manage the actual + /// resolution of the image, they should override [resolveStreamForKey]. /// /// See the Lifecycle documentation on [ImageProvider] for more information. @nonVirtual @@ -526,6 +542,10 @@ abstract class ImageProvider { // of type `_AbstractImageStreamCompleter`. if (result is _AbstractImageStreamCompleter) { result = loadBuffer(key, PaintingBinding.instance.instantiateImageCodecFromBuffer); + if (result is _AbstractImageStreamCompleter) { + // Same fallback as above but for the deprecated `load()` method. + result = load(key, PaintingBinding.instance.instantiateImageCodec); + } } return result; }, @@ -590,17 +610,39 @@ abstract class ImageProvider { /// that describes the precise image to load. /// /// The type of the key is determined by the subclass. It is a value that - /// unambiguously identifies the image (_including its scale_) that the - /// [loadImage] method will fetch. Different [ImageProvider]s given the same - /// constructor arguments and [ImageConfiguration] objects should return keys - /// that are '==' to each other (possibly by using a class for the key that - /// itself implements [==]). + /// unambiguously identifies the image (_including its scale_) that the [load] + /// method will fetch. Different [ImageProvider]s given the same constructor + /// arguments and [ImageConfiguration] objects should return keys that are + /// '==' to each other (possibly by using a class for the key that itself + /// implements [==]). /// /// If the result can be determined synchronously, this function should return /// a [SynchronousFuture]. This allows image resolution to progress /// synchronously during a frame rather than delaying image loading. Future obtainKey(ImageConfiguration configuration); + /// Converts a key into an [ImageStreamCompleter], and begins fetching the + /// image. + /// + /// This method is deprecated. Implement [loadImage] for faster image + /// loading. Only one of [load] and [loadImage] must be implemented, and + /// [loadImage] is preferred. + /// + /// The [decode] callback provides the logic to obtain the codec for the + /// image. + /// + /// See also: + /// + /// * [ResizeImage], for modifying the key to account for cache dimensions. + @protected + @Deprecated( + 'Implement loadImage for faster image loading. ' + 'This feature was deprecated after v2.13.0-1.0.pre.', + ) + ImageStreamCompleter load(T key, DecoderCallback decode) { + throw UnsupportedError('Implement loadImage for faster image loading'); + } + /// Converts a key into an [ImageStreamCompleter], and begins fetching the /// image. /// @@ -734,7 +776,25 @@ abstract class AssetBundleImageProvider extends ImageProvider [ + DiagnosticsProperty('Image provider', this), + DiagnosticsProperty('Image key', key), + ]; + return true; + }()); + return MultiFrameImageStreamCompleter( + codec: _loadAsync(key, decodeDeprecated: decode), scale: key.scale, debugLabel: key.name, informationCollector: collector, @@ -744,22 +804,48 @@ abstract class AssetBundleImageProvider extends ImageProvider _loadAsync( AssetBundleImageKey key, { - required _SimpleDecoderCallback decode, + ImageDecoderCallback? decode, + DecoderBufferCallback? decodeBufferDeprecated, + DecoderCallback? decodeDeprecated, }) async { - final ui.ImmutableBuffer buffer; + if (decode != null) { + ui.ImmutableBuffer buffer; + // Hot reload/restart could change whether an asset bundle or key in a + // bundle are available, or if it is a network backed bundle. + try { + buffer = await key.bundle.loadBuffer(key.name); + } on FlutterError { + PaintingBinding.instance.imageCache.evict(key); + rethrow; + } + return decode(buffer); + } + if (decodeBufferDeprecated != null) { + ui.ImmutableBuffer buffer; + // Hot reload/restart could change whether an asset bundle or key in a + // bundle are available, or if it is a network backed bundle. + try { + buffer = await key.bundle.loadBuffer(key.name); + } on FlutterError { + PaintingBinding.instance.imageCache.evict(key); + rethrow; + } + return decodeBufferDeprecated(buffer); + } + ByteData data; // Hot reload/restart could change whether an asset bundle or key in a // bundle are available, or if it is a network backed bundle. try { - buffer = await key.bundle.loadBuffer(key.name); + data = await key.bundle.load(key.name); } on FlutterError { PaintingBinding.instance.imageCache.evict(key); rethrow; } - return decode(buffer); + return decodeDeprecated!(data.buffer.asUint8List()); } } @@ -1251,6 +1337,28 @@ class ResizeImage extends ImageProvider { return provider; } + @override + @Deprecated( + 'Implement loadImage for faster image loading. ' + 'This feature was deprecated after v2.13.0-1.0.pre.', + ) + ImageStreamCompleter load(ResizeImageKey key, DecoderCallback decode) { + Future decodeResize(Uint8List buffer, {int? cacheWidth, int? cacheHeight, bool? allowUpscaling}) { + assert( + cacheWidth == null && cacheHeight == null && allowUpscaling == null, + 'ResizeImage cannot be composed with another ImageProvider that applies ' + 'cacheWidth, cacheHeight, or allowUpscaling.', + ); + return decode(buffer, cacheWidth: width, cacheHeight: height, allowUpscaling: this.allowUpscaling); + } + final ImageStreamCompleter completer = imageProvider.load(key._providerCacheKey, decodeResize); + if (!kReleaseMode) { + completer.debugLabel = '${completer.debugLabel} - Resized(${key._width}×${key._height})'; + } + _configureErrorListener(completer, key); + return completer; + } + @override @Deprecated( 'Implement loadImage for image loading. ' @@ -1386,11 +1494,11 @@ class ResizeImage extends ImageProvider { /// /// The image will be cached regardless of cache headers from the server. /// -/// When a network image is used on the Web platform, the `getTargetSize` -/// parameter of the [ImageDecoderCallback] is only supported when the -/// application is running with the CanvasKit renderer. When the application is -/// using the HTML renderer, the web engine delegates image decoding of network -/// images to the Web, which does not support custom decode sizes. +/// When a network image is used on the Web platform, the `cacheWidth` and +/// `cacheHeight` parameters of the [DecoderCallback] are only supported when the +/// application is running with the CanvasKit renderer. When the application is using +/// the HTML renderer, the web engine delegates image decoding of network images to the Web, +/// which does not support custom decode sizes. /// /// See also: /// @@ -1417,6 +1525,9 @@ abstract class NetworkImage extends ImageProvider { /// When running Flutter on the web, headers are not used. Map? get headers; + @override + ImageStreamCompleter load(NetworkImage key, DecoderCallback decode); + @override ImageStreamCompleter loadBuffer(NetworkImage key, DecoderBufferCallback decode); @@ -1451,10 +1562,22 @@ class FileImage extends ImageProvider { return SynchronousFuture(this); } + @override + ImageStreamCompleter load(FileImage key, DecoderCallback decode) { + return MultiFrameImageStreamCompleter( + codec: _loadAsync(key, decodeDeprecated: decode), + scale: key.scale, + debugLabel: key.file.path, + informationCollector: () => [ + ErrorDescription('Path: ${file.path}'), + ], + ); + } + @override ImageStreamCompleter loadBuffer(FileImage key, DecoderBufferCallback decode) { return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decode: decode), + codec: _loadAsync(key, decodeBufferDeprecated: decode), scale: key.scale, debugLabel: key.file.path, informationCollector: () => [ @@ -1478,9 +1601,12 @@ class FileImage extends ImageProvider { Future _loadAsync( FileImage key, { - required _SimpleDecoderCallback decode, + ImageDecoderCallback? decode, + DecoderBufferCallback? decodeBufferDeprecated, + DecoderCallback? decodeDeprecated, }) async { assert(key == this); + // TODO(jonahwilliams): making this sync caused test failures that seem to // indicate that we can fail to call evict unless at least one await has // occurred in the test. @@ -1491,9 +1617,19 @@ class FileImage extends ImageProvider { PaintingBinding.instance.imageCache.evict(key); throw StateError('$file is empty and cannot be loaded as an image.'); } - return (file.runtimeType == File) - ? decode(await ui.ImmutableBuffer.fromFilePath(file.path)) - : decode(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); + if (decode != null) { + if (file.runtimeType == File) { + return decode(await ui.ImmutableBuffer.fromFilePath(file.path)); + } + return decode(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); + } + if (decodeBufferDeprecated != null) { + if (file.runtimeType == File) { + return decodeBufferDeprecated(await ui.ImmutableBuffer.fromFilePath(file.path)); + } + return decodeBufferDeprecated(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); + } + return decodeDeprecated!(await file.readAsBytes()); } @override @@ -1519,8 +1655,8 @@ class FileImage extends ImageProvider { /// The provided [bytes] buffer should not be changed after it is provided /// to a [MemoryImage]. To provide an [ImageStream] that represents an image /// that changes over time, consider creating a new subclass of [ImageProvider] -/// whose [loadImage] method returns a subclass of [ImageStreamCompleter] that -/// can handle providing multiple images. +/// whose [load] method returns a subclass of [ImageStreamCompleter] that can +/// handle providing multiple images. /// /// See also: /// @@ -1539,7 +1675,7 @@ class MemoryImage extends ImageProvider { /// /// See also: /// - /// * [PaintingBinding.instantiateImageCodecWithSize] + /// * [PaintingBinding.instantiateImageCodec] final Uint8List bytes; /// The scale to place in the [ImageInfo] object of the image. @@ -1555,11 +1691,19 @@ class MemoryImage extends ImageProvider { return SynchronousFuture(this); } + @override + ImageStreamCompleter load(MemoryImage key, DecoderCallback decode) { + return MultiFrameImageStreamCompleter( + codec: _loadAsync(key, decodeDeprecated: decode), + scale: key.scale, + debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})', + ); + } + @override ImageStreamCompleter loadBuffer(MemoryImage key, DecoderBufferCallback decode) { - assert(key == this); return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decode: decode), + codec: _loadAsync(key, decodeBufferDeprecated: decode), scale: key.scale, debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})', ); @@ -1576,10 +1720,20 @@ class MemoryImage extends ImageProvider { Future _loadAsync( MemoryImage key, { - required _SimpleDecoderCallback decode, + ImageDecoderCallback? decode, + DecoderBufferCallback? decodeBufferDeprecated, + DecoderCallback? decodeDeprecated, }) async { assert(key == this); - return decode(await ui.ImmutableBuffer.fromUint8List(bytes)); + if (decode != null) { + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); + return decode(buffer); + } + if (decodeBufferDeprecated != null) { + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); + return decodeBufferDeprecated(buffer); + } + return decodeDeprecated!(bytes); } @override diff --git a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart index f408d8835be66..4009be91ed2ad 100644 --- a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart +++ b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart @@ -63,7 +63,7 @@ class ScrollAwareImageProvider extends ImageProvider { /// been resolved. final DisposableBuildContext context; - /// The wrapped image provider to delegate [obtainKey] and [loadImage] to. + /// The wrapped image provider to delegate [obtainKey] and [load] to. final ImageProvider imageProvider; @override @@ -105,6 +105,9 @@ class ScrollAwareImageProvider extends ImageProvider { imageProvider.resolveStreamForKey(configuration, stream, key, handleError); } + @override + ImageStreamCompleter load(T key, DecoderCallback decode) => imageProvider.load(key, decode); + @override ImageStreamCompleter loadBuffer(T key, DecoderBufferCallback decode) => imageProvider.loadBuffer(key, decode); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 0959ad2d2fd43..9fbf97f7ac878 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -3556,7 +3556,7 @@ class DelayedImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(DelayedImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(DelayedImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter(_completer.future); } @@ -3592,7 +3592,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { + ImageStreamCompleter load(Object key, DecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart index 6cfa461d82d67..8750ba5e4862d 100644 --- a/packages/flutter/test/painting/decoration_test.dart +++ b/packages/flutter/test/painting/decoration_test.dart @@ -34,7 +34,7 @@ class SynchronousTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { + ImageStreamCompleter load(int key, DecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(TestImageInfo(key, image: image)), ); @@ -52,7 +52,7 @@ class SynchronousErrorTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { + ImageStreamCompleter load(int key, DecoderCallback decode) { throw throwable; } } @@ -68,7 +68,7 @@ class AsyncTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { + ImageStreamCompleter load(int key, DecoderCallback decode) { return OneFrameImageStreamCompleter( Future.value(TestImageInfo(key, image: image)), ); @@ -88,7 +88,7 @@ class DelayedImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(DelayedImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(DelayedImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter(_completer.future); } @@ -111,7 +111,7 @@ class MultiFrameImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(MultiFrameImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(MultiFrameImageProvider key, DecoderCallback decode) { return completer; } diff --git a/packages/flutter/test/painting/fake_image_provider.dart b/packages/flutter/test/painting/fake_image_provider.dart index a59f54670b58f..c352adaaab2df 100644 --- a/packages/flutter/test/painting/fake_image_provider.dart +++ b/packages/flutter/test/painting/fake_image_provider.dart @@ -25,7 +25,7 @@ class FakeImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(FakeImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(FakeImageProvider key, DecoderCallback decode) { assert(key == this); return MultiFrameImageStreamCompleter( codec: SynchronousFuture(_codec), diff --git a/packages/flutter/test/painting/image_test_utils.dart b/packages/flutter/test/painting/image_test_utils.dart index 4b137c3f349a6..847984663e269 100644 --- a/packages/flutter/test/painting/image_test_utils.dart +++ b/packages/flutter/test/painting/image_test_utils.dart @@ -28,6 +28,11 @@ class TestImageProvider extends ImageProvider { super.resolveStreamForKey(config, stream, key, handleError); } + @override + ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + throw UnsupportedError('Use ImageProvider.loadImage instead.'); + } + @override ImageStreamCompleter loadBuffer(TestImageProvider key, DecoderBufferCallback decode) { throw UnsupportedError('Use ImageProvider.loadImage instead.'); diff --git a/packages/flutter/test/painting/mocks_for_image_cache.dart b/packages/flutter/test/painting/mocks_for_image_cache.dart index bc80315747f76..1273faa4c5e81 100644 --- a/packages/flutter/test/painting/mocks_for_image_cache.dart +++ b/packages/flutter/test/painting/mocks_for_image_cache.dart @@ -54,7 +54,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { + ImageStreamCompleter load(int key, DecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(TestImageInfo(imageValue, image: image.clone())), ); @@ -68,7 +68,7 @@ class FailingTestImageProvider extends TestImageProvider { const FailingTestImageProvider(super.key, super.imageValue, { required super.image }); @override - ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { + ImageStreamCompleter load(int key, DecoderCallback decode) { return OneFrameImageStreamCompleter(Future.sync(() => Future.error('loading failed!'))); } } @@ -95,6 +95,11 @@ class ErrorImageProvider extends ImageProvider { throw Error(); } + @override + ImageStreamCompleter load(ErrorImageProvider key, DecoderCallback decode) { + throw Error(); + } + @override Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); @@ -116,6 +121,11 @@ class ObtainKeyErrorImageProvider extends ImageProvider obtainKey(ImageConfiguration configuration) { throw Error(); } + + @override + ImageStreamCompleter load(ObtainKeyErrorImageProvider key, DecoderCallback decode) { + throw UnimplementedError(); + } } class LoadErrorImageProvider extends ImageProvider { @@ -133,11 +143,16 @@ class LoadErrorImageProvider extends ImageProvider { Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } + + @override + ImageStreamCompleter load(LoadErrorImageProvider key, DecoderCallback decode) { + throw UnimplementedError(); + } } class LoadErrorCompleterImageProvider extends ImageProvider { @override - ImageStreamCompleter loadImage(LoadErrorCompleterImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(LoadErrorCompleterImageProvider key, DecoderCallback decode) { final Completer completer = Completer.sync(); completer.completeError(Error()); return OneFrameImageStreamCompleter(completer.future); diff --git a/packages/flutter/test/painting/painting_utils.dart b/packages/flutter/test/painting/painting_utils.dart index 7d669fa1e3672..b7edc0da1227a 100644 --- a/packages/flutter/test/painting/painting_utils.dart +++ b/packages/flutter/test/painting/painting_utils.dart @@ -14,9 +14,9 @@ class PaintingBindingSpy extends BindingBase with SchedulerBinding, ServicesBind int get instantiateImageCodecCalledCount => counter; @override - Future instantiateImageCodecWithSize(ui.ImmutableBuffer buffer, { ui.TargetImageSizeCallback? getTargetSize }) { + Future instantiateImageCodec(Uint8List list, {int? cacheWidth, int? cacheHeight, bool allowUpscaling = false}) { counter++; - return ui.instantiateImageCodecWithSize(buffer, getTargetSize: getTargetSize); + return ui.instantiateImageCodec(list); } @override diff --git a/packages/flutter/test/painting/shape_decoration_test.dart b/packages/flutter/test/painting/shape_decoration_test.dart index 269fb9e416b16..8a193a5faafff 100644 --- a/packages/flutter/test/painting/shape_decoration_test.dart +++ b/packages/flutter/test/painting/shape_decoration_test.dart @@ -156,7 +156,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index 031006439d7f2..42f36c0657e3e 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -25,7 +25,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter( future.then((void value) => ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index e88c6ca6e5084..a10a77bd2498c 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -58,7 +58,7 @@ class LoadTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { + ImageStreamCompleter load(Object key, DecoderCallback decode) { throw UnimplementedError(); } } diff --git a/packages/flutter/test/widgets/image_filter_quality_test.dart b/packages/flutter/test/widgets/image_filter_quality_test.dart index dcbeadfd438da..d8b1ee367b0f8 100644 --- a/packages/flutter/test/widgets/image_filter_quality_test.dart +++ b/packages/flutter/test/widgets/image_filter_quality_test.dart @@ -137,7 +137,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { + ImageStreamCompleter load(Object key, DecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 6f2c075a00e0f..2fb1aa68771db 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -19,7 +19,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { + ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index cbabca138f9b4..2eb4b80b6437e 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -2083,7 +2083,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { + ImageStreamCompleter load(Object key, DecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } @@ -2198,7 +2198,7 @@ class _FailingImageProvider extends ImageProvider { } @override - ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { + ImageStreamCompleter load(int key, DecoderCallback decode) { if (failOnLoad) { throw throws; } From 2540412ba53b91d3aea6f9b333cf8de2e5a357d4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 18:40:04 -0400 Subject: [PATCH 0937/1547] Roll Flutter Engine from 91522a188bda to a7a4c1c70bad (11 revisions) (#133508) https://github.com/flutter/engine/compare/91522a188bda...a7a4c1c70bad 2023-08-28 matanlurey@users.noreply.github.com Explain how to update the embedder/fixtures golden outputs. (flutter/engine#45184) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from ded5d08a9999 to 83f6fbad8a38 (1 revision) (flutter/engine#45183) 2023-08-28 jonahwilliams@google.com [Impeller] Simplify color source + text with new Skia API. (flutter/engine#45090) 2023-08-28 matanlurey@users.noreply.github.com Re-write docs for DlSkCanvas{Adapter|Dispatcher}. (flutter/engine#44961) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 5baa2c74fbc6 to ded5d08a9999 (1 revision) (flutter/engine#45181) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 651ada29fcb0 to 5baa2c74fbc6 (2 revisions) (flutter/engine#45178) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 477659e6f41b to 651ada29fcb0 (3 revisions) (flutter/engine#45176) 2023-08-28 bdero@google.com [Impeller] Only enable captures in debug builds. (flutter/engine#45174) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from ce99ad7b587e to 477659e6f41b (1 revision) (flutter/engine#45173) 2023-08-28 jacksongardner@google.com Skwasm platform views (flutter/engine#43011) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from df783b542165 to ce99ad7b587e (2 revisions) (flutter/engine#45172) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 46aef26148911..06a4f585cdfcb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -91522a188bdad2cef6ac34ffdd20386a6d9bcb4d +a7a4c1c70badcc72f213cf7c3b07109d621de4e1 From e8df4349568470dce1e0aeeaf5b0763bd2409579 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 28 Aug 2023 15:51:01 -0700 Subject: [PATCH 0938/1547] PlatformRouteInformationProvider should dispatch creation in constructor. (#133492) --- packages/flutter/lib/src/widgets/router.dart | 6 +++++- packages/flutter/test/material/app_test.dart | 1 + packages/flutter/test/widgets/router_test.dart | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index 63db13e365483..f0ea0861005c8 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1465,7 +1465,11 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid /// provider. PlatformRouteInformationProvider({ required RouteInformation initialRouteInformation, - }) : _value = initialRouteInformation; + }) : _value = initialRouteInformation { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } static bool _equals(Uri a, Uri b) { return a.path == b.path diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 87e8564da509d..88aafa258aba2 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -1161,6 +1161,7 @@ void main() { routerDelegate: delegate, )); expect(tester.takeException(), isAssertionError); + provider.dispose(); }); testWidgetsWithLeakTracking('MaterialApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index a552d67b6c539..f4286d4586d12 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1582,6 +1582,21 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester expect(info2.location, '/abc?def=ghi&def=jkl#mno'); }); }); + + test('$PlatformRouteInformationProvider dispatches object creation in constructor', () { + int eventCount = 0; + void listener(ObjectEvent event) => eventCount++; + MemoryAllocations.instance.addListener(listener); + + final PlatformRouteInformationProvider registry = PlatformRouteInformationProvider( + initialRouteInformation: RouteInformation(uri: Uri.parse('http://google.com')), + ); + + expect(eventCount, 1); + + registry.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); } Widget buildBoilerPlate(Widget child) { From 5bd8579bc89173a108b62eddada46dbbd683422d Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Mon, 28 Aug 2023 16:12:16 -0700 Subject: [PATCH 0939/1547] Use flutter pub get instead of dart pub get in create_api_docs.dart (#133493) --- dev/tools/create_api_docs.dart | 47 +++-- dev/tools/examples_smoke_test.dart | 26 +-- dev/tools/test/create_api_docs_test.dart | 243 ++++++++++++----------- 3 files changed, 159 insertions(+), 157 deletions(-) diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index 0119b5fb4db1e..fd605d7879120 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -77,7 +77,7 @@ Future main(List arguments) async { configurator.generateConfiguration(); final PlatformDocGenerator platformGenerator = PlatformDocGenerator(outputDir: publishRoot, filesystem: filesystem); - platformGenerator.generatePlatformDocs(); + await platformGenerator.generatePlatformDocs(); final DartdocGenerator dartdocGenerator = DartdocGenerator( publishRoot: publishRoot, @@ -465,7 +465,7 @@ class DartdocGenerator { // Verify which version of snippets and dartdoc we're using. final ProcessResult snippetsResult = Process.runSync( - FlutterInformation.instance.getDartBinaryPath().path, + FlutterInformation.instance.getFlutterBinaryPath().path, [ 'pub', 'global', @@ -779,16 +779,16 @@ class PlatformDocGenerator { /// This downloads an archive of platform docs for the engine from the artifact /// store and extracts them to the location used for Dartdoc. - void generatePlatformDocs() { + Future generatePlatformDocs() async { final String realm = engineRealm.isNotEmpty ? '$engineRealm/' : ''; final String javadocUrl = 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; - _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); + await _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); final String objcdocUrl = 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; - _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); + await _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); } /// Fetches the zip archive at the specified url. @@ -935,7 +935,7 @@ Future runPubProcess({ @visibleForTesting FileSystem filesystem = const LocalFileSystem(), }) { return processManager.start( - [FlutterInformation.instance.getDartBinaryPath().path, 'pub', ...arguments], + [FlutterInformation.instance.getFlutterBinaryPath().path, 'pub', ...arguments], workingDirectory: (workingDirectory ?? filesystem.currentDirectory).path, environment: environment, ); @@ -968,21 +968,13 @@ List findPackages(FileSystem filesystem) { } /// An exception class used to indicate problems when collecting information. -class DartdocException implements Exception { - DartdocException(this.message, {this.file, this.line}); +class FlutterInformationException implements Exception { + FlutterInformationException(this.message); final String message; - final String? file; - final int? line; @override String toString() { - if (file != null || line != null) { - final String fileStr = file == null ? '' : '$file:'; - final String lineStr = line == null ? '' : '$line:'; - return '$runtimeType: $fileStr$lineStr: $message'; - } else { - return '$runtimeType: $message'; - } + return '$runtimeType: $message'; } } @@ -1017,6 +1009,13 @@ class FlutterInformation { return getFlutterRoot().childDirectory('bin').childFile('dart'); } + /// The path to the Dart binary in the Flutter repo. + /// + /// This is probably a shell script. + File getFlutterBinaryPath() { + return getFlutterRoot().childDirectory('bin').childFile('flutter'); + } + /// The path to the Flutter repo root directory. /// /// If the environment variable `FLUTTER_ROOT` is set, will use that instead @@ -1074,11 +1073,12 @@ class FlutterInformation { try { result = processManager.runSync([flutterCommand, '--version', '--machine'], stdoutEncoding: utf8); } on ProcessException catch (e) { - throw DartdocException( + throw FlutterInformationException( 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e'); } if (result.exitCode != 0) { - throw DartdocException('Unable to determine Flutter information, because of abnormal exit to flutter command.'); + throw FlutterInformationException( + 'Unable to determine Flutter information, because of abnormal exit to flutter command.'); } flutterVersionJson = (result.stdout as String) .replaceAll('Waiting for another flutter command to release the startup lock...', ''); @@ -1088,7 +1088,7 @@ class FlutterInformation { if (flutterVersion['flutterRoot'] == null || flutterVersion['frameworkVersion'] == null || flutterVersion['dartSdkVersion'] == null) { - throw DartdocException( + throw FlutterInformationException( 'Flutter command output has unexpected format, unable to determine flutter root location.'); } @@ -1097,14 +1097,13 @@ class FlutterInformation { info['flutterRoot'] = flutterRoot; info['frameworkVersion'] = Version.parse(flutterVersion['frameworkVersion'] as String); info['engineRevision'] = flutterVersion['engineRevision'] as String; - info['engineRealm'] = filesystem.file( - path.join(flutterRoot.path, 'bin', 'internal', 'engine.realm', - )).readAsStringSync().trim(); + final File engineRealm = flutterRoot.childDirectory('bin').childDirectory('internal').childFile('engine.realm'); + info['engineRealm'] = engineRealm.existsSync() ? engineRealm.readAsStringSync().trim() : ''; final RegExpMatch? dartVersionRegex = RegExp(r'(?[\d.]+)(?:\s+\(build (?[-.\w]+)\))?') .firstMatch(flutterVersion['dartSdkVersion'] as String); if (dartVersionRegex == null) { - throw DartdocException( + throw FlutterInformationException( 'Flutter command output has unexpected format, unable to parse dart SDK version ${flutterVersion['dartSdkVersion']}.'); } info['dartSdkVersion'] = diff --git a/dev/tools/examples_smoke_test.dart b/dev/tools/examples_smoke_test.dart index f4877ff11a222..84660fda38733 100644 --- a/dev/tools/examples_smoke_test.dart +++ b/dev/tools/examples_smoke_test.dart @@ -17,21 +17,21 @@ import 'package:path/path.dart' as path; import 'package:platform/platform.dart'; import 'package:process/process.dart'; -FileSystem filesystem = const LocalFileSystem(); -ProcessManager processManager = const LocalProcessManager(); -Platform platform = const LocalPlatform(); +const FileSystem _kFilesystem = LocalFileSystem(); +const ProcessManager _kProcessManager = LocalProcessManager(); +const Platform _kPlatform = LocalPlatform(); FutureOr main() async { - if (!platform.isLinux && !platform.isWindows && !platform.isMacOS) { + if (!_kPlatform.isLinux && !_kPlatform.isWindows && !_kPlatform.isMacOS) { stderr.writeln('Example smoke tests are only designed to run on desktop platforms'); exitCode = 4; return; } - final Directory flutterDir = filesystem.directory( + final Directory flutterDir = _kFilesystem.directory( path.absolute( path.dirname( path.dirname( - path.dirname(platform.script.toFilePath()), + path.dirname(_kPlatform.script.toFilePath()), ), ), ), @@ -63,16 +63,16 @@ Future runSmokeTests({ required Directory apiDir, }) async { final File flutterExe = - flutterDir.childDirectory('bin').childFile(platform.isWindows ? 'flutter.bat' : 'flutter'); + flutterDir.childDirectory('bin').childFile(_kPlatform.isWindows ? 'flutter.bat' : 'flutter'); final List cmd = [ // If we're in a container with no X display, then use the virtual framebuffer. - if (platform.isLinux && - (platform.environment['DISPLAY'] == null || - platform.environment['DISPLAY']!.isEmpty)) '/usr/bin/xvfb-run', + if (_kPlatform.isLinux && + (_kPlatform.environment['DISPLAY'] == null || + _kPlatform.environment['DISPLAY']!.isEmpty)) '/usr/bin/xvfb-run', flutterExe.absolute.path, 'test', '--reporter=expanded', - '--device-id=${platform.operatingSystem}', + '--device-id=${_kPlatform.operatingSystem}', integrationTest.absolute.path, ]; await runCommand(cmd, workingDirectory: apiDir); @@ -112,7 +112,7 @@ Future generateTest(Directory apiDir) async { .trim() .split('\n'); final Iterable examples = gitFiles.map((String examplePath) { - return filesystem.file(path.join(examplesLibDir.absolute.path, examplePath)); + return _kFilesystem.file(path.join(examplesLibDir.absolute.path, examplePath)); }); // Collect the examples, and import them all as separate symbols. @@ -202,7 +202,7 @@ Future runCommand( } try { - process = await processManager.start( + process = await _kProcessManager.start( cmd, workingDirectory: workingDirectory.absolute.path, environment: environment, diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart index edf4b63d2a3dc..6f98d1fae746e 100644 --- a/dev/tools/test/create_api_docs_test.dart +++ b/dev/tools/test/create_api_docs_test.dart @@ -4,116 +4,14 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; -import 'package:path/path.dart' as path; import 'package:platform/platform.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:test/test.dart'; import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; import '../create_api_docs.dart' as apidocs; -import '../examples_smoke_test.dart'; void main() { - test('getBranchName does not call git if env LUCI_BRANCH provided', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': branchName, - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH not provided', () { - final Platform platform = FakePlatform( - environment: {}, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test('getBranchName calls git if env LUCI_BRANCH is empty', () { - final Platform platform = FakePlatform( - environment: { - 'LUCI_BRANCH': '', - }, - ); - - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['flutter', '--version', '--machine'], - stdout: testVersionInfo, - ), - const FakeCommand( - command: ['git', 'status', '-b', '--porcelain'], - stdout: '## $branchName', - ), - ], - ); - - expect( - apidocs.FlutterInformation(platform: platform, processManager: processManager).getBranchName(), - branchName, - ); - expect(processManager, hasNoRemainingExpectations); - }); - - test("runPubProcess doesn't use the pub binary", () { - final Platform platform = FakePlatform( - environment: { - 'FLUTTER_ROOT': '/flutter', - }, - ); - final ProcessManager processManager = FakeProcessManager.list( - [ - const FakeCommand( - command: ['/flutter/bin/dart', 'pub', '--one', '--two'], - ), - ], - ); - apidocs.FlutterInformation.instance = - apidocs.FlutterInformation(platform: platform, processManager: processManager); - - apidocs.runPubProcess( - arguments: ['--one', '--two'], - processManager: processManager, - filesystem: filesystem, - ); - - expect(processManager, hasNoRemainingExpectations); - }); - group('FlutterInformation', () { late FakeProcessManager fakeProcessManager; late FakePlatform fakePlatform; @@ -136,11 +34,96 @@ void main() { setUpWithEnvironment({}); }); + test('getBranchName does not call git if env LUCI_BRANCH provided', () { + setUpWithEnvironment( + { + 'LUCI_BRANCH': branchName, + }, + ); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + expect( + apidocs.FlutterInformation.instance.getBranchName(), + branchName, + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH not provided', () { + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); + + expect( + apidocs.FlutterInformation.instance.getBranchName(), + branchName, + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + test('getBranchName calls git if env LUCI_BRANCH is empty', () { + setUpWithEnvironment( + { + 'LUCI_BRANCH': '', + }, + ); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); + + expect( + apidocs.FlutterInformation.instance.getBranchName(), + branchName, + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }); + + test("runPubProcess doesn't use the pub binary", () { + final Platform platform = FakePlatform( + environment: { + 'FLUTTER_ROOT': '/flutter', + }, + ); + final ProcessManager processManager = FakeProcessManager.list( + [ + const FakeCommand( + command: ['/flutter/bin/flutter', 'pub', '--one', '--two'], + ), + ], + ); + apidocs.FlutterInformation.instance = + apidocs.FlutterInformation(platform: platform, processManager: processManager, filesystem: memoryFileSystem); + + apidocs.runPubProcess( + arguments: ['--one', '--two'], + processManager: processManager, + filesystem: memoryFileSystem, + ); + + expect(processManager, hasNoRemainingExpectations); + }); + test('calls out to flutter if FLUTTER_VERSION is not set', () async { - fakeProcessManager.addCommand( - const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Map info = flutterInformation.getFlutterInformation(); expect(fakeProcessManager, hasNoRemainingExpectations); expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); @@ -149,17 +132,23 @@ void main() { setUpWithEnvironment({ 'FLUTTER_VERSION': testVersionInfo, }); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Map info = flutterInformation.getFlutterInformation(); expect(fakeProcessManager, hasNoRemainingExpectations); expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); }); test('getFlutterRoot calls out to flutter if FLUTTER_ROOT is not set', () async { - fakeProcessManager.addCommand( - const FakeCommand(command: ['flutter', '--version', '--machine'], stdout: testVersionInfo)); - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Directory root = flutterInformation.getFlutterRoot(); expect(fakeProcessManager, hasNoRemainingExpectations); expect(root.path, equals('/home/user/flutter')); @@ -172,8 +161,10 @@ void main() { }); test('parses version properly', () async { fakePlatform.environment['FLUTTER_VERSION'] = testVersionInfo; - fakeProcessManager.addCommand( - const FakeCommand(command: ['git', 'status', '-b', '--porcelain'], stdout: testVersionInfo)); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + )); final Map info = flutterInformation.getFlutterInformation(); expect(info['frameworkVersion'], isNotNull); expect(info['frameworkVersion'], equals(Version.parse('2.5.0'))); @@ -181,14 +172,26 @@ void main() { expect(info['dartSdkVersion'], equals(Version.parse('2.14.0-360.0.dev'))); }); test('the engine realm is read from the engine.realm file', () async { - const String flutterRoot = '/home/user/flutter'; - final File realmFile = memoryFileSystem.file( - path.join(flutterRoot, 'bin', 'internal', 'engine.realm', + final Directory flutterHome = memoryFileSystem + .directory('/home') + .childDirectory('user') + .childDirectory('flutter') + .childDirectory('bin') + .childDirectory('internal'); + flutterHome.childFile('engine.realm') + ..createSync(recursive: true) + ..writeAsStringSync('realm'); + setUpWithEnvironment({'FLUTTER_ROOT': '/home/user/flutter'}); + fakeProcessManager.addCommand(const FakeCommand( + command: ['/home/user/flutter/bin/flutter', '--version', '--machine'], + stdout: testVersionInfo, + )); + fakeProcessManager.addCommand(const FakeCommand( + command: ['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', )); - realmFile.writeAsStringSync('realm'); - setUpWithEnvironment({'FLUTTER_ROOT': flutterRoot}); - expect(fakeProcessManager, hasNoRemainingExpectations); final Map info = flutterInformation.getFlutterInformation(); + expect(fakeProcessManager, hasNoRemainingExpectations); expect(info['engineRealm'], equals('realm')); }); }); From bd1583f3e5c7f1fbdbd479b9ffb1056736154ae4 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 28 Aug 2023 16:19:32 -0700 Subject: [PATCH 0940/1547] FocusNode and FocusManager should dispatch creation in constructor. (#133490) --- packages/flutter/lib/src/material/drawer.dart | 1 + .../lib/src/widgets/focus_manager.dart | 7 +++ .../test/widgets/focus_manager_test.dart | 35 +++++++++++++ .../test/widgets/memory_allocations_test.dart | 50 ++++++++++++------- 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index c2b78ce0973f9..fb3ac51bbc36a 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -471,6 +471,7 @@ class DrawerControllerState extends State with SingleTickerPro void dispose() { _historyEntry?.remove(); _controller.dispose(); + _focusScopeNode.dispose(); super.dispose(); } diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 9a4576ea32a83..991cb81534b76 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -437,6 +437,10 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { _descendantsAreTraversable = descendantsAreTraversable { // Set it via the setter so that it does nothing on release builds. this.debugLabel = debugLabel; + + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } } /// If true, tells the focus traversal policy to skip over this node for @@ -1463,6 +1467,9 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { /// handlers, callers must call [registerGlobalHandlers]. See the /// documentation in that method for caveats to watch out for. FocusManager() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } rootScope._manager = this; } diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 0a49b56f4ece9..4516e6f31ce44 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -1609,6 +1609,41 @@ void main() { tester.binding.focusManager.removeListener(handleFocusChange); }); + test('$FocusManager dispatches object creation in constructor', () { + final List events = []; + void listener(ObjectEvent event) { + if (event.object.runtimeType == FocusManager) { + events.add(event); + } + } + MemoryAllocations.instance.addListener(listener); + + final FocusManager focusManager = FocusManager(); + + expect(events, hasLength(1)); + + focusManager.dispose(); + + MemoryAllocations.instance.removeListener(listener); + }); + + test('$FocusNode dispatches object creation in constructor', () { + final List events = []; + void listener(ObjectEvent event) { + if (event.object.runtimeType == FocusNode) { + events.add(event); + } + } + MemoryAllocations.instance.addListener(listener); + + final FocusNode focusManager = FocusNode(); + + expect(events, hasLength(1)); + + focusManager.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); + testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { final FocusNode nodeA = FocusNode(debugLabel: 'a'); final FocusNode nodeB = FocusNode(debugLabel: 'b'); diff --git a/packages/flutter/test/widgets/memory_allocations_test.dart b/packages/flutter/test/widgets/memory_allocations_test.dart index dbb44ac661851..aff4d51900db3 100644 --- a/packages/flutter/test/widgets/memory_allocations_test.dart +++ b/packages/flutter/test/widgets/memory_allocations_test.dart @@ -6,20 +6,26 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; + int _creations = 0; + int _disposals = 0; + void main() { final MemoryAllocations ma = MemoryAllocations.instance; - setUp(() { - assert(!ma.hasListeners); - }); - test('Publishers dispatch events in debug mode', () async { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; + void listener(ObjectEvent event) { + if (event is ObjectDisposed) { + _disposals++; + } + if (event is ObjectCreated) { + _creations++; + } + } ma.addListener(listener); - final int expectedEventCount = await _activateFlutterObjectsAndReturnCountOfEvents(); - expect(eventCount, expectedEventCount); + final _EventStats actual = await _activateFlutterObjectsAndReturnCountOfEvents(); + expect(actual.creations, _creations); + expect(actual.disposals, _disposals); ma.removeListener(listener); expect(ma.hasListeners, isFalse); @@ -29,6 +35,8 @@ void main() { bool stateCreated = false; bool stateDisposed = false; + expect(ma.hasListeners, false); + void listener(ObjectEvent event) { if (event is ObjectCreated && event.object is State) { stateCreated = true; @@ -47,7 +55,7 @@ void main() { expect(stateCreated, isTrue); expect(stateDisposed, isTrue); ma.removeListener(listener); - expect(ma.hasListeners, isFalse); + expect(ma.hasListeners, false); }); } @@ -62,7 +70,8 @@ class _TestElement extends RenderObjectElement with RootElementMixin { _TestElement(): super(_TestLeafRenderObjectWidget()); void makeInactive() { - assignOwner(BuildOwner(focusManager: FocusManager())); + final FocusManager newFocusManager = FocusManager(); + assignOwner(BuildOwner(focusManager: newFocusManager)); mount(null, null); deactivate(); } @@ -109,15 +118,22 @@ class _TestStatefulWidgetState extends State<_TestStatefulWidget> { } } + +class _EventStats { + int creations = 0; + int disposals = 0; +} + /// Create and dispose Flutter objects to fire memory allocation events. -Future _activateFlutterObjectsAndReturnCountOfEvents() async { - int count = 0; +Future<_EventStats> _activateFlutterObjectsAndReturnCountOfEvents() async { + final _EventStats result = _EventStats(); - final _TestElement element = _TestElement(); count++; - final RenderObject renderObject = _TestRenderObject(); count++; + final _TestElement element = _TestElement(); result.creations++; + final RenderObject renderObject = _TestRenderObject(); result.creations++; - element.makeInactive(); element.unmount(); count += 3; - renderObject.dispose(); count++; + element.makeInactive(); result.creations += 3; // 1 for the new BuildOwner, 1 for the new FocusManager, 1 for the new FocusScopeNode + element.unmount(); result.disposals += 2; // 1 for the old BuildOwner, 1 for the element + renderObject.dispose(); result.disposals += 1; - return count; + return result; } From 42e2f4fb3e2acbce6b5937da8511c86c15b3045b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 19:43:58 -0400 Subject: [PATCH 0941/1547] Roll Flutter Engine from a7a4c1c70bad to bd2132a0814f (3 revisions) (#133516) https://github.com/flutter/engine/compare/a7a4c1c70bad...bd2132a0814f 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 335f748463db to 66e367b12e96 (1 revision) (flutter/engine#45189) 2023-08-28 jonahwilliams@google.com [Impeller] Cache Skia text bounds computation. (flutter/engine#45150) 2023-08-28 skia-flutter-autoroll@skia.org Roll Skia from 83f6fbad8a38 to 335f748463db (1 revision) (flutter/engine#45186) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 06a4f585cdfcb..e53263f8ae8db 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a7a4c1c70badcc72f213cf7c3b07109d621de4e1 +bd2132a0814f6df95471e97f7d5efaca515506bd From 88717b3c65b68d362dabdc3e8bbfa17e3fc62e14 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Mon, 28 Aug 2023 17:31:14 -0700 Subject: [PATCH 0942/1547] add missing forwards of local-engine-host in benchmark runners (#133517) Some places where we are missing a forward of the `--local-engine-host` values in the benchmark code preventing local running of the benchmarks (does not affect CI usages which don't override local engine). --- dev/devicelab/bin/run.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev/devicelab/bin/run.dart b/dev/devicelab/bin/run.dart index 28da34ad507c8..a666e1aa48f86 100644 --- a/dev/devicelab/bin/run.dart +++ b/dev/devicelab/bin/run.dart @@ -120,6 +120,7 @@ Future main(List rawArgs) async { await runTasks(taskNames, silent: silent, localEngine: localEngine, + localEngineHost: localEngineHost, localEngineSrcPath: localEngineSrcPath, deviceId: deviceId, exitOnFirstTestFailure: exitOnFirstTestFailure, @@ -177,6 +178,7 @@ Future _runABTest({ taskName, silent: silent, localEngine: localEngine, + localEngineHost: localEngineHost, localWebSdk: localWebSdk, localEngineSrcPath: localEngineSrcPath, deviceId: deviceId, From 6cc01ced84bba8b602e249a695999669580852e1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 20:36:53 -0400 Subject: [PATCH 0943/1547] Roll Flutter Engine from bd2132a0814f to 45e2b41e5ae5 (2 revisions) (#133518) https://github.com/flutter/engine/compare/bd2132a0814f...45e2b41e5ae5 2023-08-28 jacksongardner@google.com [skwasm] encode PNGs using browser APIs (flutter/engine#45187) 2023-08-28 skia-flutter-autoroll@skia.org Roll Dart SDK from 5d3ab5db5037 to 2900ad211f38 (3 revisions) (flutter/engine#45192) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e53263f8ae8db..506671c1e3be1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bd2132a0814f6df95471e97f7d5efaca515506bd +45e2b41e5ae5563afbfaca45d873451a6962d8a3 From e6c7b849208e60feec4b5429550260a9a97d7fa8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 21:29:15 -0400 Subject: [PATCH 0944/1547] Roll Flutter Engine from 45e2b41e5ae5 to 1e821961e96a (2 revisions) (#133520) https://github.com/flutter/engine/compare/45e2b41e5ae5...1e821961e96a 2023-08-29 jonahwilliams@google.com [Impeller] Sync presentation when rendering into FlutterImageView. (flutter/engine#44881) 2023-08-28 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from AQZddYgKiWrQL8vny... to Ys38QMyFZToJxnXrF... (flutter/engine#45195) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from AQZddYgKiWrQ to Ys38QMyFZToJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 506671c1e3be1..d26abb1ccf265 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -45e2b41e5ae5563afbfaca45d873451a6962d8a3 +1e821961e96afab6aaa330a4c7561c2c5c43b692 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 25d0a832cb001..555e866fb0d62 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -AQZddYgKiWrQL8vnyZlhYg3ltgH_oGTnzETLJ12cODkC +Ys38QMyFZToJxnXrF8aJ6ZaggHtrqx6mEO02Lk9seYkC From 8845c80aaa8f3dd319afa23206012f4c42988970 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 22:22:07 -0400 Subject: [PATCH 0945/1547] Roll Flutter Engine from 1e821961e96a to ffda7e3cfc7f (2 revisions) (#133523) https://github.com/flutter/engine/compare/1e821961e96a...ffda7e3cfc7f 2023-08-29 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from u44zzvYd85WSDMpS3... to 68DESTl_q6I45UJyb... (flutter/engine#45197) 2023-08-29 matanlurey@users.noreply.github.com Rename `instrumentation` to `stopwatch` (flutter/engine#45196) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from u44zzvYd85WS to 68DESTl_q6I4 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d26abb1ccf265..f0d24ac816994 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1e821961e96afab6aaa330a4c7561c2c5c43b692 +ffda7e3cfc7f7f63beea51bd28e2e2fb6e6ea946 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 3fa428392ed9d..588306f3c120a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -u44zzvYd85WSDMpS3HByB6bT_uFdClQ4RtTDaYFpC40C +68DESTl_q6I45UJybf_gTTh2BU9FCq4XHR0QuJo5RJEC From 773287b7e48bcb6892d65a6e66729cddd72a9667 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 28 Aug 2023 23:36:15 -0400 Subject: [PATCH 0946/1547] Roll Flutter Engine from ffda7e3cfc7f to 9778c2cb1d51 (1 revision) (#133526) https://github.com/flutter/engine/compare/ffda7e3cfc7f...9778c2cb1d51 2023-08-29 jacksongardner@google.com Fix scene view canvas/platform view placement. (flutter/engine#45199) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f0d24ac816994..a3b203c0ca332 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ffda7e3cfc7f7f63beea51bd28e2e2fb6e6ea946 +9778c2cb1d5115f70382e6db34704f904c4c288a From 6dae269881b426c30ff214a1c719671c61dfd102 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 00:22:24 -0400 Subject: [PATCH 0947/1547] Roll Flutter Engine from 9778c2cb1d51 to c7c61ff9732c (2 revisions) (#133527) https://github.com/flutter/engine/compare/9778c2cb1d51...c7c61ff9732c 2023-08-29 skia-flutter-autoroll@skia.org Roll Dart SDK from 2900ad211f38 to 60a3bb84fa6d (1 revision) (flutter/engine#45201) 2023-08-29 matanlurey@users.noreply.github.com A minimal `engine_tools_lib` to use for local-repo Dart tooling (flutter/engine#45154) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a3b203c0ca332..1c94768c1bb7d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9778c2cb1d5115f70382e6db34704f904c4c288a +c7c61ff9732cb57e16d90f03613ae560042b7865 From f489256fcec9fec903b53f861b5f4a2a7cf7014b Mon Sep 17 00:00:00 2001 From: Dan Field Date: Mon, 28 Aug 2023 23:29:05 -0700 Subject: [PATCH 0948/1547] Fix bug in setPreferredOrientations example (#133503) The `ui.Display` is a simple data class (like `MediaQueryData`), and does not get updated when the display size changes. The provided sample code does not work as intended, but the update does. --- packages/flutter/lib/src/services/system_chrome.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/services/system_chrome.dart b/packages/flutter/lib/src/services/system_chrome.dart index 3d6881d658bf1..1ed5a0c88c9d8 100644 --- a/packages/flutter/lib/src/services/system_chrome.dart +++ b/packages/flutter/lib/src/services/system_chrome.dart @@ -388,7 +388,7 @@ abstract final class SystemChrome { /// } /// /// class _MyAppState extends State with WidgetsBindingObserver { - /// ui.Display? _display; + /// ui.FlutterView? _view; /// static const double kOrientationLockBreakpoint = 600; /// /// @override @@ -400,19 +400,19 @@ abstract final class SystemChrome { /// @override /// void didChangeDependencies() { /// super.didChangeDependencies(); - /// _display = View.maybeOf(context)?.display; + /// _view = View.maybeOf(context); /// } /// /// @override /// void dispose() { /// WidgetsBinding.instance.removeObserver(this); - /// _display = null; + /// _view = null; /// super.dispose(); /// } /// /// @override /// void didChangeMetrics() { - /// final ui.Display? display = _display; + /// final ui.Display? display = _view?.display; /// if (display == null) { /// return; /// } From d37a8e4693b292be2373f3317bea81aaad4c2c0c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 03:13:36 -0400 Subject: [PATCH 0949/1547] Roll Flutter Engine from c7c61ff9732c to 3d1faae1bc2f (1 revision) (#133530) https://github.com/flutter/engine/compare/c7c61ff9732c...3d1faae1bc2f 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 66e367b12e96 to b27fecd52899 (1 revision) (flutter/engine#45204) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jimgraham@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1c94768c1bb7d..ef83f3f29c687 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c7c61ff9732cb57e16d90f03613ae560042b7865 +3d1faae1bc2f44f270cf7d6d286b0902777de12f From d58f158a887ec92af482ebc27fdfe197e765fead Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 05:14:39 -0400 Subject: [PATCH 0950/1547] Roll Flutter Engine from 3d1faae1bc2f to c2ec683c4ea8 (4 revisions) (#133535) https://github.com/flutter/engine/compare/3d1faae1bc2f...c2ec683c4ea8 2023-08-29 zhongwuzw@qq.com [iOS] Don't call App lifecycle resumed when device is locked (flutter/engine#44947) 2023-08-29 skia-flutter-autoroll@skia.org Roll Dart SDK from 60a3bb84fa6d to f6c11801db41 (1 revision) (flutter/engine#45207) 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from b27fecd52899 to f576668bfe99 (1 revision) (flutter/engine#45206) 2023-08-29 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 3.5.3 to 3.6.0 (flutter/engine#45205) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ef83f3f29c687..07617231781be 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3d1faae1bc2f44f270cf7d6d286b0902777de12f +c2ec683c4ea8a58a32a74465cc05dafdf7778517 From c66e922aae90d3196ddebf5d5a39c266ec80a863 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 06:25:07 -0400 Subject: [PATCH 0951/1547] Roll Flutter Engine from c2ec683c4ea8 to 0625049b5ee3 (2 revisions) (#133538) https://github.com/flutter/engine/compare/c2ec683c4ea8...0625049b5ee3 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 01ee493cc113 to 5dd678aebdaf (1 revision) (flutter/engine#45210) 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from f576668bfe99 to 01ee493cc113 (1 revision) (flutter/engine#45208) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 07617231781be..3769ebe130a41 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c2ec683c4ea8a58a32a74465cc05dafdf7778517 +0625049b5ee314ee89223c7e4171482e3a7a77fc From dbe114d8c31c6280832a08957a9209c637195ec6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 11:13:17 -0400 Subject: [PATCH 0952/1547] Roll Flutter Engine from 0625049b5ee3 to d84763e04496 (6 revisions) (#133559) https://github.com/flutter/engine/compare/0625049b5ee3...d84763e04496 2023-08-29 skia-flutter-autoroll@skia.org Roll Dart SDK from 70066300aa83 to a4e0e792ef9a (1 revision) (flutter/engine#45221) 2023-08-29 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 68DESTl_q6I45UJyb... to QKekosWnIY_ObKstn... (flutter/engine#45217) 2023-08-29 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Ys38QMyFZToJxnXrF... to z9uQ0mXwjKFQF05Xl... (flutter/engine#45216) 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from e9e4d0dacc9d to 85377eca700d (1 revision) (flutter/engine#45215) 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 5dd678aebdaf to e9e4d0dacc9d (1 revision) (flutter/engine#45214) 2023-08-29 skia-flutter-autoroll@skia.org Roll Dart SDK from f6c11801db41 to 70066300aa83 (1 revision) (flutter/engine#45212) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from Ys38QMyFZToJ to z9uQ0mXwjKFQ fuchsia/sdk/core/mac-amd64 from 68DESTl_q6I4 to QKekosWnIY_O If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3769ebe130a41..9ff777219bcaa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0625049b5ee314ee89223c7e4171482e3a7a77fc +d84763e0449692e9acd3c68f1b18817ff1a26d35 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 555e866fb0d62..506a90e6b3e94 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -Ys38QMyFZToJxnXrF8aJ6ZaggHtrqx6mEO02Lk9seYkC +z9uQ0mXwjKFQF05XlBv-X8Em1QvkefyGcIJWrSZEm-sC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 588306f3c120a..3d30f2e975f5b 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -68DESTl_q6I45UJybf_gTTh2BU9FCq4XHR0QuJo5RJEC +QKekosWnIY_ObKstnfItjOWSgi14RL_O43p2q4KSarUC From 6c95737375db9fea61f25eea0ca43598acc4d9fc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 11:56:45 -0400 Subject: [PATCH 0953/1547] Roll Flutter Engine from d84763e04496 to 65438c7bb46a (1 revision) (#133563) https://github.com/flutter/engine/compare/d84763e04496...65438c7bb46a 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 85377eca700d to 7675f886f884 (7 revisions) (flutter/engine#45224) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9ff777219bcaa..218af5f1d9912 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d84763e0449692e9acd3c68f1b18817ff1a26d35 +65438c7bb46adb6ba11cb288ee8d9f6587fe0ce7 From dcdc4df99801bcb010c1d7c4bf717f019228b6c2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 12:27:05 -0400 Subject: [PATCH 0954/1547] Roll Packages from 383bffa3991d to d7d3150e5966 (13 revisions) (#133564) https://github.com/flutter/packages/compare/383bffa3991d...d7d3150e5966 2023-08-29 ian@hixie.ch [rfw] Implement /* block comments */ in the text format (flutter/packages#4769) 2023-08-29 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.4 to 2.21.5 (flutter/packages#4810) 2023-08-28 engine-flutter-autoroll@skia.org Roll Flutter from cd3aeef3a826 to ec387a467a68 (15 revisions) (flutter/packages#4807) 2023-08-28 49699333+dependabot[bot]@users.noreply.github.com [pigeon]: Bump org.jetbrains.kotlin:kotlin-gradle-plugin from 1.9.0 to 1.9.10 in /packages/pigeon/platform_tests/test_plugin/android (flutter/packages#4798) 2023-08-28 jhy03261997@gmail.com Fix popping repeated pages unexpectedly (flutter/packages#4763) 2023-08-28 tarrinneal@gmail.com [pigeon] primitive enums (flutter/packages#4580) 2023-08-27 engine-flutter-autoroll@skia.org Roll Flutter from 229b74d98772 to cd3aeef3a826 (4 revisions) (flutter/packages#4777) 2023-08-26 engine-flutter-autoroll@skia.org Roll Flutter from 61d9f5566559 to 229b74d98772 (13 revisions) (flutter/packages#4776) 2023-08-25 engine-flutter-autoroll@skia.org Roll Flutter from deeb811ef0bb to 61d9f5566559 (25 revisions) (flutter/packages#4774) 2023-08-25 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 3.5.3 to 3.6.0 (flutter/packages#4770) 2023-08-24 praconfi@gmail.com [css_colors] docs: Update deprecated link address (flutter/packages#4537) 2023-08-24 engine-flutter-autoroll@skia.org Roll Flutter (stable) from efbf63d9c66b to e1e47221e862 (3 revisions) (flutter/packages#4767) 2023-08-24 engine-flutter-autoroll@skia.org Roll Flutter from bd836cc63ae0 to deeb811ef0bb (17 revisions) (flutter/packages#4766) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index f28b62361fdf5..9d28099430a90 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -383bffa3991d6397eb4a00fb6f7f09f897252143 +d7d3150e596686c9769249d7b0910ff6f9f5ee3b From f6c20db64bb896bdec6a8883fae5b956e33b3860 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 13:00:13 -0400 Subject: [PATCH 0955/1547] Roll Flutter Engine from 65438c7bb46a to 50bd80773287 (1 revision) (#133565) https://github.com/flutter/engine/compare/65438c7bb46a...50bd80773287 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 7675f886f884 to 4048262b9b21 (2 revisions) (flutter/engine#45225) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 218af5f1d9912..7ebc125f073cd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -65438c7bb46adb6ba11cb288ee8d9f6587fe0ce7 +50bd80773287fe96dfe12775352bd426193a5440 From d8d7e019c17dbf03c39d1b4da009740b52fd7d2f Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 29 Aug 2023 20:31:02 +0300 Subject: [PATCH 0956/1547] Add FAB Additional Color Mappings example (#133453) fixes [Additional color mappings for FAB in Material 3](https://github.com/flutter/flutter/issues/130702) ### Preview ![image](https://github.com/flutter/flutter/assets/48603081/a6f9aef6-af80-41ce-8e59-50f095db047d) --- .../floating_action_button.1.dart | 8 +- .../floating_action_button.2.dart | 104 ++++++++++++++++++ .../floating_action_button.1_test.dart | 2 +- .../floating_action_button.2_test.dart | 37 +++++++ .../src/material/floating_action_button.dart | 7 ++ 5 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 examples/api/lib/material/floating_action_button/floating_action_button.2.dart create mode 100644 examples/api/test/material/floating_action_button/floating_action_button.2_test.dart diff --git a/examples/api/lib/material/floating_action_button/floating_action_button.1.dart b/examples/api/lib/material/floating_action_button/floating_action_button.1.dart index 9650247a25edd..3aef595986a5f 100644 --- a/examples/api/lib/material/floating_action_button/floating_action_button.1.dart +++ b/examples/api/lib/material/floating_action_button/floating_action_button.1.dart @@ -14,14 +14,14 @@ class FloatingActionButtonExampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true), - home: const FabExample(), + theme: ThemeData(useMaterial3: true), + home: const FloatingActionButtonExample(), ); } } -class FabExample extends StatelessWidget { - const FabExample({super.key}); +class FloatingActionButtonExample extends StatelessWidget { + const FloatingActionButtonExample({super.key}); @override Widget build(BuildContext context) { diff --git a/examples/api/lib/material/floating_action_button/floating_action_button.2.dart b/examples/api/lib/material/floating_action_button/floating_action_button.2.dart new file mode 100644 index 0000000000000..dda2e9b6db284 --- /dev/null +++ b/examples/api/lib/material/floating_action_button/floating_action_button.2.dart @@ -0,0 +1,104 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for [FloatingActionButton]. + +void main() => runApp(const FloatingActionButtonExampleApp()); + +class FloatingActionButtonExampleApp extends StatelessWidget { + const FloatingActionButtonExampleApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const FloatingActionButtonExample(), + ); + } +} + +class FloatingActionButtonExample extends StatelessWidget { + const FloatingActionButtonExample({super.key}); + + @override + Widget build(BuildContext context) { + final ColorScheme colorScheme = Theme.of(context).colorScheme; + + Widget titleBox(String title) { + return DecoratedBox( + decoration: BoxDecoration( + color: colorScheme.inverseSurface, + borderRadius: BorderRadius.circular(4), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: Text(title, style: TextStyle(color: colorScheme.onInverseSurface)), + ), + ); + } + + return Scaffold( + appBar: AppBar( + title: const Text('FAB Additional Color Mappings'), + ), + body: Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + // Surface color mapping. + Column( + mainAxisSize: MainAxisSize.min, + children: [ + FloatingActionButton.large( + foregroundColor: colorScheme.primary, + backgroundColor: colorScheme.surface, + onPressed: () { + // Add your onPressed code here! + }, + child: const Icon(Icons.edit_outlined), + ), + const SizedBox(height: 20), + titleBox('Surface'), + ], + ), + // Secondary color mapping. + Column( + mainAxisSize: MainAxisSize.min, + children: [ + FloatingActionButton.large( + foregroundColor: colorScheme.onSecondaryContainer, + backgroundColor: colorScheme.secondaryContainer, + onPressed: () { + // Add your onPressed code here! + }, + child: const Icon(Icons.edit_outlined), + ), + const SizedBox(height: 20), + titleBox('Secondary'), + ], + ), + // Tertiary color mapping. + Column( + mainAxisSize: MainAxisSize.min, + children: [ + FloatingActionButton.large( + foregroundColor: colorScheme.onTertiaryContainer, + backgroundColor: colorScheme.tertiaryContainer, + onPressed: () { + // Add your onPressed code here! + }, + child: const Icon(Icons.edit_outlined), + ), + const SizedBox(height: 20), + titleBox('Tertiary'), + ], + ), + ], + ), + ), + ); + } +} diff --git a/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart b/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart index d618defc169a3..d503e5df27b7a 100644 --- a/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart +++ b/examples/api/test/material/floating_action_button/floating_action_button.1_test.dart @@ -17,7 +17,7 @@ void main() { const example.FloatingActionButtonExampleApp(), ); - final ThemeData theme = ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true); + final ThemeData theme = ThemeData(useMaterial3: true); expect(find.byType(FloatingActionButton), findsNWidgets(4)); expect(find.byIcon(Icons.add), findsNWidgets(4)); diff --git a/examples/api/test/material/floating_action_button/floating_action_button.2_test.dart b/examples/api/test/material/floating_action_button/floating_action_button.2_test.dart new file mode 100644 index 0000000000000..1d4e9a26234ac --- /dev/null +++ b/examples/api/test/material/floating_action_button/floating_action_button.2_test.dart @@ -0,0 +1,37 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/floating_action_button/floating_action_button.2.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('FloatingActionButton variants', (WidgetTester tester) async { + await tester.pumpWidget( + const example.FloatingActionButtonExampleApp(), + ); + + FloatingActionButton getFAB(Finder finder) { + return tester.widget(finder); + } + + final ColorScheme colorScheme = ThemeData(useMaterial3: true).colorScheme; + + // Test the FAB with surface color mapping. + FloatingActionButton fab = getFAB(find.byType(FloatingActionButton).at(0)); + expect(fab.foregroundColor, colorScheme.primary); + expect(fab.backgroundColor, colorScheme.surface); + + // Test the FAB with secondary color mapping. + fab = getFAB(find.byType(FloatingActionButton).at(1)); + expect(fab.foregroundColor, colorScheme.onSecondaryContainer); + expect(fab.backgroundColor, colorScheme.secondaryContainer); + + // Test the FAB with tertiary color mapping. + fab = getFAB(find.byType(FloatingActionButton).at(2)); + expect(fab.foregroundColor, colorScheme.onTertiaryContainer); + expect(fab.backgroundColor, colorScheme.tertiaryContainer); + }); +} diff --git a/packages/flutter/lib/src/material/floating_action_button.dart b/packages/flutter/lib/src/material/floating_action_button.dart index e0f11dc6045c3..ab37361f383a6 100644 --- a/packages/flutter/lib/src/material/floating_action_button.dart +++ b/packages/flutter/lib/src/material/floating_action_button.dart @@ -67,6 +67,13 @@ enum _FloatingActionButtonType { /// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.1.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// This sample shows [FloatingActionButton] with additional color mappings as +/// described in: https://m3.material.io/components/floating-action-button/overview. +/// +/// ** See code in examples/api/lib/material/floating_action_button/floating_action_button.2.dart ** +/// {@end-tool} +/// /// See also: /// /// * [Scaffold], in which floating action buttons typically live. From ae64abc6146db98165b266a798978d01da1fa17e Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 29 Aug 2023 10:40:20 -0700 Subject: [PATCH 0957/1547] ShortcutManager should dispatch creation in constructor. (#133487) --- .../flutter/lib/src/widgets/shortcuts.dart | 7 +++++- .../material/text_selection_theme_test.dart | 2 -- .../flutter/test/widgets/shortcuts_test.dart | 22 ++++++++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 5c66c42997205..c0118e633f608 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -747,7 +747,11 @@ class ShortcutManager with Diagnosticable, ChangeNotifier { ShortcutManager({ Map shortcuts = const {}, this.modal = false, - }) : _shortcuts = shortcuts; + }) : _shortcuts = shortcuts { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } /// True if the [ShortcutManager] should not pass on keys that it doesn't /// handle to any key-handling widgets that are ancestors to this one. @@ -1440,6 +1444,7 @@ class _ShortcutRegistrarState extends State { void dispose() { registry.removeListener(_shortcutsChanged); registry.dispose(); + manager.dispose(); super.dispose(); } diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 947df64c3f3be..4a990a5a0a5d0 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -177,8 +177,6 @@ void main() { 'ValueNotifier': 2, '_InputBorderGap': 1, }, - // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. - allowAllNotGCed: true, ), ); diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index 064fdfb231e16..fedf7f9cd291f 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -666,6 +666,19 @@ void main() { expect(pressedKeys, isEmpty); }); + test('$ShortcutManager dispatches object creation in constructor', () { + int eventCount = 0; + void listener(ObjectEvent event) => eventCount++; + MemoryAllocations.instance.addListener(listener); + + final ShortcutManager registry = ShortcutManager(); + + expect(eventCount, 1); + + registry.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); + testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List pressedKeys = []; @@ -1853,20 +1866,17 @@ void main() { token.dispose(); }); - testWidgets('dispatches object creation in constructor', (WidgetTester tester) async { - final MemoryAllocations ma = MemoryAllocations.instance; - assert(!ma.hasListeners); + test('dispatches object creation in constructor', () { int eventCount = 0; void listener(ObjectEvent event) => eventCount++; - ma.addListener(listener); + MemoryAllocations.instance.addListener(listener); final ShortcutRegistry registry = ShortcutRegistry(); expect(eventCount, 1); registry.dispose(); - ma.removeListener(listener); - assert(!ma.hasListeners); + MemoryAllocations.instance.removeListener(listener); }); }); } From 7ef4290a3c674b0690852b34c0f7770679995f71 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 13:54:24 -0400 Subject: [PATCH 0958/1547] Roll Flutter Engine from 50bd80773287 to d1e6eb080f08 (2 revisions) (#133570) https://github.com/flutter/engine/compare/50bd80773287...d1e6eb080f08 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 4048262b9b21 to b0c1b2868129 (2 revisions) (flutter/engine#45227) 2023-08-29 mdebbar@google.com [web] Make devicePixelRatio ready for multi-view (flutter/engine#44783) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7ebc125f073cd..24f141cb0b902 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -50bd80773287fe96dfe12775352bd426193a5440 +d1e6eb080f0871ea290ec5d1c7fd58dece671188 From ff829fd8b2b45c639acb74ad89c521b989d75a1c Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 29 Aug 2023 11:12:02 -0700 Subject: [PATCH 0959/1547] Add doxygen doc generation. (#131356) --- dev/bots/docs.sh | 5 + dev/docs/README.md | 8 ++ dev/docs/platform_integration/lib/ios.dart | 2 +- dev/docs/platform_integration/lib/linux.dart | 6 + dev/docs/platform_integration/lib/macos.dart | 6 + .../platform_integration/lib/windows.dart | 6 + dev/docs/renderers/lib/impeller.dart | 6 + dev/docs/renderers/pubspec.yaml | 4 + dev/tools/create_api_docs.dart | 128 +++++++++++++----- 9 files changed, 135 insertions(+), 36 deletions(-) create mode 100644 dev/docs/platform_integration/lib/linux.dart create mode 100644 dev/docs/platform_integration/lib/macos.dart create mode 100644 dev/docs/platform_integration/lib/windows.dart create mode 100644 dev/docs/renderers/lib/impeller.dart create mode 100644 dev/docs/renderers/pubspec.yaml diff --git a/dev/bots/docs.sh b/dev/bots/docs.sh index a213982482048..c070086aac4ee 100755 --- a/dev/bots/docs.sh +++ b/dev/bots/docs.sh @@ -134,6 +134,11 @@ function main() { if ! [[ "$DESTINATION" =~ ^/ ]]; then DESTINATION="$PWD/$DESTINATION" fi + + # Make sure the destination has .zip as an extension, because zip will add it + # anyhow, and we want to print the correct output location. + DESTINATION=${DESTINATION%.zip}.zip + # Zip up doc directory and write the output to the destination. (cd "$STAGING_DIR"; zip -r -9 -q "$DESTINATION" ./doc) if [[ $KEEP_STAGING -eq 1 ]]; then diff --git a/dev/docs/README.md b/dev/docs/README.md index 2c20f3d199fdb..da52c41597bd4 100644 --- a/dev/docs/README.md +++ b/dev/docs/README.md @@ -14,6 +14,14 @@ This site hosts Flutter's API documentation. Other documentation can be found at the following locations: * [flutter.dev](https://flutter.dev) (main site) +* [api.flutter.dev](https://api.flutter.dev) (API docs reference site) +* Engine Embedder API documentation: + * [Android Embedder](https://api.flutter.dev/javadoc/index.html) + * [iOS Embedder](https://api.flutter.dev/ios-embedder/index.html) + * [macOS Embedder](https://api.flutter.dev/macos-embedder/index.html) + * [Linux Embedder](https://api.flutter.dev/linux-embedder/index.html) + * [Windows Embedder](https://api.flutter.dev/windows-embedder/index.html) + * [Web Embedder](https://api.flutter.dev/flutter/dart-ui_web/dart-ui_web-library.html) * [Installation](https://flutter.dev/docs/get-started/install) * [Codelabs](https://flutter.dev/docs/codelabs) * [Contributing to Flutter](https://github.com/flutter/flutter/blob/master/CONTRIBUTING.md) diff --git a/dev/docs/platform_integration/lib/ios.dart b/dev/docs/platform_integration/lib/ios.dart index 9645423e36fb8..92f8d0fc9629a 100644 --- a/dev/docs/platform_integration/lib/ios.dart +++ b/dev/docs/platform_integration/lib/ios.dart @@ -2,5 +2,5 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/// [Flutter platform integration APIs for iOS.](https://api.flutter.dev/objcdoc/) +/// [Flutter platform integration APIs for iOS.](https://api.flutter.dev/ios-embedder/) library iOS; diff --git a/dev/docs/platform_integration/lib/linux.dart b/dev/docs/platform_integration/lib/linux.dart new file mode 100644 index 0000000000000..97512455eca6f --- /dev/null +++ b/dev/docs/platform_integration/lib/linux.dart @@ -0,0 +1,6 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// [Flutter platform integration APIs for Linux.](https://api.flutter.dev/linux-embedder/) +library Linux; diff --git a/dev/docs/platform_integration/lib/macos.dart b/dev/docs/platform_integration/lib/macos.dart new file mode 100644 index 0000000000000..1d701ea9d17ea --- /dev/null +++ b/dev/docs/platform_integration/lib/macos.dart @@ -0,0 +1,6 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// [Flutter platform integration APIs for macOS.](https://api.flutter.dev/macos-embedder/) +library macOS; diff --git a/dev/docs/platform_integration/lib/windows.dart b/dev/docs/platform_integration/lib/windows.dart new file mode 100644 index 0000000000000..f92522f6d0110 --- /dev/null +++ b/dev/docs/platform_integration/lib/windows.dart @@ -0,0 +1,6 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// [Flutter platform integration APIs for Windows.](https://api.flutter.dev/windows-embedder/) +library Windows; diff --git a/dev/docs/renderers/lib/impeller.dart b/dev/docs/renderers/lib/impeller.dart new file mode 100644 index 0000000000000..86f04ee65c4ea --- /dev/null +++ b/dev/docs/renderers/lib/impeller.dart @@ -0,0 +1,6 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// [Flutter APIs for the Impeller renderer.](https://api.flutter.dev/impeller/) +library Impeller; diff --git a/dev/docs/renderers/pubspec.yaml b/dev/docs/renderers/pubspec.yaml new file mode 100644 index 0000000000000..fd0dff9f304d5 --- /dev/null +++ b/dev/docs/renderers/pubspec.yaml @@ -0,0 +1,4 @@ +name: renderers + +environment: + sdk: '>=2.19.0-0 <4.0.0' diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index fd605d7879120..cbc021e956e84 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -23,6 +23,58 @@ import 'dartdoc_checker.dart'; const String kDummyPackageName = 'Flutter'; const String kPlatformIntegrationPackageName = 'platform_integration'; +class PlatformDocsSection { + const PlatformDocsSection({ + required this.zipName, + required this.sectionName, + required this.checkFile, + required this.subdir, + }); + final String zipName; + final String sectionName; + final String checkFile; + final String subdir; +} + +const Map kPlatformDocs = { + 'android': PlatformDocsSection( + zipName: 'android-javadoc.zip', + sectionName: 'Android', + checkFile: 'io/flutter/view/FlutterView.html', + subdir: 'javadoc', + ), + 'ios': PlatformDocsSection( + zipName: 'ios-docs.zip', + sectionName: 'iOS', + checkFile: 'interface_flutter_view.html', + subdir: 'ios-embedder', + ), + 'macos': PlatformDocsSection( + zipName: 'macos-docs.zip', + sectionName: 'macOS', + checkFile: 'interface_flutter_view.html', + subdir: 'macos-embedder', + ), + 'linux': PlatformDocsSection( + zipName: 'linux-docs.zip', + sectionName: 'Linux', + checkFile: 'struct___fl_view.html', + subdir: 'linux-embedder', + ), + 'windows': PlatformDocsSection( + zipName: 'windows-docs.zip', + sectionName: 'Windows', + checkFile: 'classflutter_1_1_flutter_view.html', + subdir: 'windows-embedder', + ), + 'impeller': PlatformDocsSection( + zipName: 'impeller-docs.zip', + sectionName: 'Impeller', + checkFile: 'classimpeller_1_1_canvas.html', + subdir: 'impeller', + ), +}; + /// This script will generate documentation for the packages in `packages/` and /// write the documentation to the output directory specified on the command /// line. @@ -43,9 +95,8 @@ Future main(List arguments) async { // The place to find customization files and configuration files for docs // generation. - final Directory docsRoot = filesystem - .directory(FlutterInformation.instance.getFlutterRoot().childDirectory('dev').childDirectory('docs')) - .absolute; + final Directory docsRoot = + FlutterInformation.instance.getFlutterRoot().childDirectory('dev').childDirectory('docs').absolute; final ArgParser argParser = _createArgsParser( publishDefault: docsRoot.childDirectory('doc').path, ); @@ -187,6 +238,9 @@ class Configurator { // Add a fake package for platform integration APIs. yield '$kPlatformIntegrationPackageName/android.dart'; yield '$kPlatformIntegrationPackageName/ios.dart'; + yield '$kPlatformIntegrationPackageName/macos.dart'; + yield '$kPlatformIntegrationPackageName/linux.dart'; + yield '$kPlatformIntegrationPackageName/windows.dart'; } void _createDummyPubspec() { @@ -732,14 +786,15 @@ class DartdocGenerator { '\n', '\n \n', ); - indexContents = indexContents.replaceAll( - 'href="Android/Android-library.html"', - 'href="/javadoc/"', - ); - indexContents = indexContents.replaceAll( - 'href="iOS/iOS-library.html"', - 'href="/objcdoc/"', - ); + + for (final String platform in kPlatformDocs.keys) { + final String sectionName = kPlatformDocs[platform]!.sectionName; + final String subdir = kPlatformDocs[platform]!.subdir; + indexContents = indexContents.replaceAll( + 'href="$sectionName/$sectionName-library.html"', + 'href="../$subdir/index.html"', + ); + } indexFile.writeAsStringSync(indexContents); } @@ -782,13 +837,12 @@ class PlatformDocGenerator { Future generatePlatformDocs() async { final String realm = engineRealm.isNotEmpty ? '$engineRealm/' : ''; - final String javadocUrl = - 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/android-javadoc.zip'; - await _extractDocs(javadocUrl, 'javadoc', 'io/flutter/view/FlutterView.html', outputDir); - - final String objcdocUrl = - 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/ios-objcdoc.zip'; - await _extractDocs(objcdocUrl, 'objcdoc', 'Classes/FlutterViewController.html', outputDir); + for (final String platform in kPlatformDocs.keys) { + final String zipFile = kPlatformDocs[platform]!.zipName; + final String url = + 'https://storage.googleapis.com/${realm}flutter_infra_release/flutter/$engineRevision/$zipFile'; + await _extractDocs(url, platform, kPlatformDocs[platform]!, outputDir); + } } /// Fetches the zip archive at the specified url. @@ -812,7 +866,7 @@ class PlatformDocGenerator { return responseBytes == null ? null : ZipDecoder().decodeBytes(responseBytes); } - Future _extractDocs(String url, String docName, String checkFile, Directory outputDir) async { + Future _extractDocs(String url, String name, PlatformDocsSection platform, Directory outputDir) async { const int maxTries = 5; final Archive? archive = await _fetchArchive(url, maxTries); if (archive == null) { @@ -820,8 +874,8 @@ class PlatformDocGenerator { exit(1); } - final Directory output = outputDir.childDirectory(docName); - print('Extracting $docName to ${output.path}'); + final Directory output = outputDir.childDirectory(platform.subdir); + print('Extracting ${platform.zipName} to ${output.path}'); output.createSync(recursive: true); for (final ArchiveFile af in archive) { @@ -832,18 +886,12 @@ class PlatformDocGenerator { } } - /// If object then copy files to old location if the archive is using the new location. - final Directory objcDocsDir = output.childDirectory('objectc_docs'); - if (objcDocsDir.existsSync()) { - copyDirectorySync(objcDocsDir, output, filesystem: filesystem); - } - - final File testFile = output.childFile(checkFile); + final File testFile = output.childFile(platform.checkFile); if (!testFile.existsSync()) { print('Expected file ${testFile.path} not found'); exit(1); } - print('$docName ready to go!'); + print('${platform.sectionName} ready to go!'); } } @@ -955,12 +1003,13 @@ List findPackages(FileSystem filesystem) { if (entity is! Directory) { return false; } - final File pubspec = filesystem.file('${entity.path}/pubspec.yaml'); + final File pubspec = entity.childFile('pubspec.yaml'); if (!pubspec.existsSync()) { print("Unexpected package '${entity.path}' found in packages directory"); return false; } - // TODO(ianh): Use a real YAML parser here + // Would be nice to use a real YAML parser here, but we don't want to + // depend on a whole package for it, and this is sufficient. return !pubspec.readAsStringSync().contains('nodoc: true'); }) .cast() @@ -1058,6 +1107,9 @@ class FlutterInformation { if (platform.environment['FLUTTER_VERSION'] != null) { flutterVersionJson = platform.environment['FLUTTER_VERSION']!; } else { + // Determine which flutter command to run, which will determine which + // flutter root is eventually used. If the FLUTTER_ROOT is set, then use + // that flutter command, otherwise use the first one in the PATH. String flutterCommand; if (platform.environment['FLUTTER_ROOT'] != null) { flutterCommand = filesystem @@ -1071,15 +1123,21 @@ class FlutterInformation { } ProcessResult result; try { - result = processManager.runSync([flutterCommand, '--version', '--machine'], stdoutEncoding: utf8); + result = processManager.runSync( + [flutterCommand, '--version', '--machine'], + stdoutEncoding: utf8, + ); } on ProcessException catch (e) { throw FlutterInformationException( - 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place flutter command in your path.\n$e'); + 'Unable to determine Flutter information. Either set FLUTTER_ROOT, or place the ' + 'flutter command in your PATH.\n$e'); } if (result.exitCode != 0) { throw FlutterInformationException( - 'Unable to determine Flutter information, because of abnormal exit to flutter command.'); + 'Unable to determine Flutter information, because of abnormal exit of flutter command.'); } + // Strip out any non-JSON that might be printed along with the command + // output. flutterVersionJson = (result.stdout as String) .replaceAll('Waiting for another flutter command to release the startup lock...', ''); } @@ -1139,7 +1197,7 @@ class FlutterInformation { String _getFlutterGitRevision() { const int kGitRevisionLength = 10; - final ProcessResult gitResult = Process.runSync('git', ['rev-parse', 'HEAD']); + final ProcessResult gitResult = processManager.runSync(['git', 'rev-parse', 'HEAD']); if (gitResult.exitCode != 0) { throw 'git rev-parse exit with non-zero exit code: ${gitResult.exitCode}'; } From 9a9c2826d1640d1458f253ebd1f1f525f32f7d87 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Tue, 29 Aug 2023 14:56:07 -0400 Subject: [PATCH 0960/1547] [web] Migrate remaining web-only API usages to `dart:ui_web` (#132248) This is the last batch of web-only API migration. Depends on https://github.com/flutter/engine/pull/44516 Fixes https://github.com/flutter/flutter/issues/52899 Fixes https://github.com/flutter/flutter/issues/126831 --- .../lib/src/painting/_network_image_web.dart | 14 ++++++-------- packages/flutter_tools/lib/src/web/bootstrap.dart | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index 667f08f1e1b0d..aff650b08e8b0 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:js_interop'; import 'dart:ui' as ui; +import 'dart:ui_web' as ui_web; import 'package:flutter/foundation.dart'; import 'package:web/web.dart' as web; @@ -117,8 +118,8 @@ class NetworkImage } // Html renderer does not support decoding network images to a specified size. The decode parameter - // here is ignored and the web-only `ui.webOnlyInstantiateImageCodecFromUrl` will be used - // directly in place of the typical `instantiateImageCodec` method. + // here is ignored and `ui_web.createImageCodecFromUrl` will be used directly + // in place of the typical `instantiateImageCodec` method. Future _loadAsync( NetworkImage key, image_provider.ImageDecoderCallback? decode, @@ -133,7 +134,7 @@ class NetworkImage final bool containsNetworkImageHeaders = key.headers?.isNotEmpty ?? false; // We use a different method when headers are set because the - // `ui.webOnlyInstantiateImageCodecFromUrl` method is not capable of handling headers. + // `ui_web.createImageCodecFromUrl` method is not capable of handling headers. if (isCanvasKit || containsNetworkImageHeaders) { final Completer completer = Completer(); @@ -190,16 +191,13 @@ class NetworkImage return decodeDeprecated!(bytes); } } else { - // This API only exists in the web engine implementation and is not - // contained in the analyzer summary for Flutter. - // ignore: undefined_function, avoid_dynamic_calls - return ui.webOnlyInstantiateImageCodecFromUrl( + return ui_web.createImageCodecFromUrl( resolved, chunkCallback: (int bytes, int total) { chunkEvents.add(ImageChunkEvent( cumulativeBytesLoaded: bytes, expectedTotalBytes: total)); }, - ) as Future; + ); } } diff --git a/packages/flutter_tools/lib/src/web/bootstrap.dart b/packages/flutter_tools/lib/src/web/bootstrap.dart index 7b44bec7494a3..24e924e755fa1 100644 --- a/packages/flutter_tools/lib/src/web/bootstrap.dart +++ b/packages/flutter_tools/lib/src/web/bootstrap.dart @@ -231,8 +231,8 @@ String generateTestEntrypoint({ ui_web.debugEmulateFlutterTesterEnvironment = true; await ui_web.bootstrapEngine(); webGoldenComparator = DefaultWebGoldenComparator(Uri.parse('${Uri.file(absolutePath)}')); - (ui.window as dynamic).debugOverrideDevicePixelRatio(3.0); - (ui.window as dynamic).webOnlyDebugPhysicalSizeOverride = const ui.Size(2400, 1800); + ui_web.debugOverrideDevicePixelRatio(3.0); + ui.window.debugPhysicalSizeOverride = const ui.Size(2400, 1800); internalBootstrapBrowserTest(() { return ${testConfigPath != null ? "() => test_config.testExecutable(test.main)" : "test.main"}; From bfbfce49032115990043a51e15543ca81d260895 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 15:41:59 -0400 Subject: [PATCH 0961/1547] Roll Flutter Engine from d1e6eb080f08 to 73cc3fb451fd (3 revisions) (#133580) https://github.com/flutter/engine/compare/d1e6eb080f08...73cc3fb451fd 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from b7e826d5324f to 15de7f9c3b3b (3 revisions) (flutter/engine#45231) 2023-08-29 jonahwilliams@google.com [Impeller] its not safe to presentWithTransaction from a background thread. (flutter/engine#45182) 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from b0c1b2868129 to b7e826d5324f (4 revisions) (flutter/engine#45229) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 24f141cb0b902..3fbcb281f936a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d1e6eb080f0871ea290ec5d1c7fd58dece671188 +73cc3fb451fd8a4298abe26f065e242b92ff5f75 From 89310edaa222a58f3447d1ca4624391fc30c6f31 Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Tue, 29 Aug 2023 12:49:33 -0700 Subject: [PATCH 0962/1547] Use a fake stopwatch to remove flakiness. (#133229) Fixes https://github.com/flutter/flutter/issues/133215 --- packages/flutter_tools/test/general.shard/base/logger_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_tools/test/general.shard/base/logger_test.dart b/packages/flutter_tools/test/general.shard/base/logger_test.dart index edb9e52a2a31d..72a88ec25231a 100644 --- a/packages/flutter_tools/test/general.shard/base/logger_test.dart +++ b/packages/flutter_tools/test/general.shard/base/logger_test.dart @@ -1295,6 +1295,7 @@ void main() { isCliAnimationEnabled: false, ), stdio: fakeStdio, + stopwatchFactory: FakeStopwatchFactory(stopwatch: FakeStopwatch()), outputPreferences: OutputPreferences.test(wrapText: true, wrapColumn: 40), ); logger.startProgress('po').stop(); From 4022864c659ff2f0691aff4efce7be43a3ce757c Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Tue, 29 Aug 2023 13:01:49 -0700 Subject: [PATCH 0963/1547] Added DropdownMenuEntry.labelWidget (#133491) --- .../dropdown_menu_entry_label_widget.0.dart | 91 +++++++++++++++ ...opdown_menu_entry_label_widget.0_test.dart | 36 ++++++ .../lib/src/material/dropdown_menu.dart | 25 +++- .../test/material/dropdown_menu_test.dart | 109 ++++++++++++++++++ 4 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 examples/api/lib/material/dropdown_menu/dropdown_menu_entry_label_widget.0.dart create mode 100644 examples/api/test/material/dropdown_menu/dropdown_menu_entry_label_widget.0_test.dart diff --git a/examples/api/lib/material/dropdown_menu/dropdown_menu_entry_label_widget.0.dart b/examples/api/lib/material/dropdown_menu/dropdown_menu_entry_label_widget.0.dart new file mode 100644 index 0000000000000..a4c77c6244503 --- /dev/null +++ b/examples/api/lib/material/dropdown_menu/dropdown_menu_entry_label_widget.0.dart @@ -0,0 +1,91 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +/// Flutter code sample for the [DropdownMenuEntry] `labelWidget` property. + +enum ColorItem { + blue('Blue', Colors.blue), + pink('Pink', Colors.pink), + green('Green', Colors.green), + yellow('Yellow', Colors.yellow), + grey('Grey', Colors.grey); + + const ColorItem(this.label, this.color); + final String label; + final Color color; +} + +class DropdownMenuEntryLabelWidgetExample extends StatefulWidget { + const DropdownMenuEntryLabelWidgetExample({ super.key }); + + @override + State createState() => _DropdownMenuEntryLabelWidgetExampleState(); +} + +class _DropdownMenuEntryLabelWidgetExampleState extends State { + late final TextEditingController controller; + + @override + void initState() { + super.initState(); + controller = TextEditingController(); + } + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + // Created by Google Bard from 'create a lyrical phrase of about 25 words that begins with "is a color"'. + const String longText = 'is a color that sings of hope, A hue that shines like gold. It is the color of dreams, A shade that never grows old.'; + + return Scaffold( + body: Center( + child: DropdownMenu( + width: 300, + controller: controller, + initialSelection: ColorItem.green, + label: const Text('Color'), + onSelected: (ColorItem? color) { + print('Selected $color'); + }, + dropdownMenuEntries: ColorItem.values.map>((ColorItem item) { + final String labelText = '${item.label} $longText\n'; + return DropdownMenuEntry( + value: item, + label: labelText, + // Try commenting the labelWidget out or changing + // the labelWidget's Text parameters. + labelWidget: Text( + labelText, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ); + }).toList(), + ), + ), + ); + } +} + +class DropdownMenuEntryLabelWidgetExampleApp extends StatelessWidget { + const DropdownMenuEntryLabelWidgetExampleApp({ super.key }); + + @override + Widget build(BuildContext context) { + return const MaterialApp( + home: DropdownMenuEntryLabelWidgetExample(), + ); + } +} + +void main() { + runApp(const DropdownMenuEntryLabelWidgetExampleApp()); +} diff --git a/examples/api/test/material/dropdown_menu/dropdown_menu_entry_label_widget.0_test.dart b/examples/api/test/material/dropdown_menu/dropdown_menu_entry_label_widget.0_test.dart new file mode 100644 index 0000000000000..773c991e9cc08 --- /dev/null +++ b/examples/api/test/material/dropdown_menu/dropdown_menu_entry_label_widget.0_test.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/dropdown_menu/dropdown_menu_entry_label_widget.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('DropdownEntryLabelWidget appears', (WidgetTester tester) async { + await tester.pumpWidget( + const example.DropdownMenuEntryLabelWidgetExampleApp(), + ); + + const String longText = 'is a color that sings of hope, A hue that shines like gold. It is the color of dreams, A shade that never grows old.'; + Finder findMenuItemText(String label) { + final String labelText = '$label $longText\n'; + return find.descendant( + of: find.widgetWithText(MenuItemButton, labelText), + matching: find.byType(Text), + ).last; + } + + // Open the menu + await tester.tap(find.byType(TextField)); + expect(findMenuItemText('Blue'), findsOneWidget); + expect(findMenuItemText('Pink'), findsOneWidget); + expect(findMenuItemText('Green'), findsOneWidget); + expect(findMenuItemText('Yellow'), findsOneWidget); + expect(findMenuItemText('Grey'), findsOneWidget); + + // Close the menu + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + }); +} diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 27baf5951b92c..3beb00d3dda3d 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -44,6 +44,7 @@ class DropdownMenuEntry { const DropdownMenuEntry({ required this.value, required this.label, + this.labelWidget, this.leadingIcon, this.trailingIcon, this.enabled = true, @@ -58,6 +59,17 @@ class DropdownMenuEntry { /// The label displayed in the center of the menu item. final String label; + /// Overrides the default label widget which is `Text(label)`. + /// + /// {@tool dartpad} + /// This sample shows how to override the default label [Text] + /// widget with one that forces the menu entry to appear on one line + /// by specifying [Text.maxLines] and [Text.overflow]. + /// + /// ** See code in examples/api/lib/material/dropdown_menu/dropdown_menu_entry_label_widget.0.dart ** + /// {@end-tool} + final Widget? labelWidget; + /// An optional icon to display before the label. final Widget? leadingIcon; @@ -441,6 +453,15 @@ class _DropdownMenuState extends State> { final Color focusedBackgroundColor = effectiveStyle.foregroundColor?.resolve({MaterialState.focused}) ?? Theme.of(context).colorScheme.onSurface; + Widget label = entry.labelWidget ?? Text(entry.label); + if (widget.width != null) { + final double horizontalPadding = padding + _kDefaultHorizontalPadding; + label = ConstrainedBox( + constraints: BoxConstraints(maxWidth: widget.width! - horizontalPadding), + child: label, + ); + } + // Simulate the focused state because the text field should always be focused // during traversal. If the menu item has a custom foreground color, the "focused" // color will also change to foregroundColor.withOpacity(0.12). @@ -450,7 +471,7 @@ class _DropdownMenuState extends State> { ) : effectiveStyle; - final MenuItemButton menuItemButton = MenuItemButton( + final Widget menuItemButton = MenuItemButton( key: enableScrollToHighlight ? buttonItemKeys[i] : null, style: effectiveStyle, leadingIcon: entry.leadingIcon, @@ -465,7 +486,7 @@ class _DropdownMenuState extends State> { } : null, requestFocusOnHover: false, - child: Text(entry.label), + child: label, ); result.add(menuItemButton); } diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 5d8a2c53141bf..a499bcd262e5e 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { + const String longText = 'one two three four five six seven eight nine ten eleven twelve'; final List> menuChildren = >[]; for (final TestMenu value in TestMenu.values) { @@ -1571,6 +1572,114 @@ void main() { expect(material.textStyle?.wordSpacing, menuItemTextThemeStyle.wordSpacing); expect(material.textStyle?.decoration, menuItemTextThemeStyle.decoration); }); + + testWidgets('DropdownMenuEntries do not overflow when width is specified', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/126882 + final TextEditingController controller = TextEditingController(); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DropdownMenu( + controller: controller, + width: 100, + dropdownMenuEntries: TestMenu.values.map>((TestMenu item) { + return DropdownMenuEntry( + value: item, + label: '${item.label} $longText', + ); + }).toList(), + ), + ), + ), + ); + + // Opening the width=100 menu should not crash. + await tester.tap(find.byType(DropdownMenu)); + expect(tester.takeException(), isNull); + await tester.pumpAndSettle(); + + Finder findMenuItemText(String label) { + final String labelText = '$label $longText'; + return find.descendant( + of: find.widgetWithText(MenuItemButton, labelText), + matching: find.byType(Text), + ).last; + } + + // Actual size varies a little on web platforms. + final Matcher closeTo300 = closeTo(300, 0.25); + expect(tester.getSize(findMenuItemText('Item 0')).height, closeTo300); + expect(tester.getSize(findMenuItemText('Menu 1')).height, closeTo300); + expect(tester.getSize(findMenuItemText('Item 2')).height, closeTo300); + expect(tester.getSize(findMenuItemText('Item 3')).height, closeTo300); + + await tester.tap(findMenuItemText('Item 0')); + await tester.pumpAndSettle(); + expect(controller.text, 'Item 0 $longText'); + }); + + testWidgets('DropdownMenuEntry.labelWidget is Text that specifies maxLines 1 or 2', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/126882 + final TextEditingController controller = TextEditingController(); + + Widget buildFrame({ required int maxLines }) { + return MaterialApp( + home: Scaffold( + body: DropdownMenu( + key: ValueKey(maxLines), + controller: controller, + width: 100, + dropdownMenuEntries: TestMenu.values.map>((TestMenu item) { + return DropdownMenuEntry( + value: item, + label: '${item.label} $longText', + labelWidget: Text('${item.label} $longText', maxLines: maxLines), + ); + }).toList(), + ), + ) + ); + } + + Finder findMenuItemText(String label) { + final String labelText = '$label $longText'; + return find.descendant( + of: find.widgetWithText(MenuItemButton, labelText), + matching: find.byType(Text), + ).last; + } + + await tester.pumpWidget(buildFrame(maxLines: 1)); + await tester.tap(find.byType(DropdownMenu)); + + // Actual size varies a little on web platforms. + final Matcher closeTo20 = closeTo(20, 0.05); + expect(tester.getSize(findMenuItemText('Item 0')).height, closeTo20); + expect(tester.getSize(findMenuItemText('Menu 1')).height, closeTo20); + expect(tester.getSize(findMenuItemText('Item 2')).height, closeTo20); + expect(tester.getSize(findMenuItemText('Item 3')).height, closeTo20); + + // Close the menu + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + expect(controller.text, ''); // nothing selected + + await tester.pumpWidget(buildFrame(maxLines: 2)); + await tester.tap(find.byType(DropdownMenu)); + + // Actual size varies a little on web platforms. + final Matcher closeTo40 = closeTo(40, 0.05); + expect(tester.getSize(findMenuItemText('Item 0')).height, closeTo40); + expect(tester.getSize(findMenuItemText('Menu 1')).height, closeTo40); + expect(tester.getSize(findMenuItemText('Item 2')).height, closeTo40); + expect(tester.getSize(findMenuItemText('Item 3')).height, closeTo40); + + // Close the menu + await tester.tap(find.byType(TextField)); + await tester.pumpAndSettle(); + expect(controller.text, ''); // nothing selected + }); } enum TestMenu { From fc06fe6aa9d9f9f988867a11a4a27a0c9207a8b0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 17:10:46 -0400 Subject: [PATCH 0964/1547] Roll Flutter Engine from 73cc3fb451fd to 01a1579808b5 (3 revisions) (#133591) https://github.com/flutter/engine/compare/73cc3fb451fd...01a1579808b5 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 15de7f9c3b3b to fb09020ce62d (3 revisions) (flutter/engine#45233) 2023-08-29 matanlurey@users.noreply.github.com Use `runIfNot: ...` to avoid running Fuchsia try-jobs for some changes. (flutter/engine#45134) 2023-08-29 zanderso@users.noreply.github.com Clean up engine repo Dart code (flutter/engine#45203) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3fbcb281f936a..10710c15d9d8a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -73cc3fb451fd8a4298abe26f065e242b92ff5f75 +01a1579808b53e027c1730e6d246fac377fa9f00 From fb5abe45b8e41527362840c0be72885c4e31259b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 29 Aug 2023 14:23:10 -0700 Subject: [PATCH 0965/1547] Cover more tests with leak tracking. (#133596) --- packages/flutter/test/material/about_test.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index ddc3c2fd254f2..5540f319ed859 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -57,7 +57,7 @@ void main() { expect(find.text('View licenses'), findsOneWidget); }); - testWidgets('Material2 - AboutListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -140,7 +140,7 @@ void main() { expect(find.text('Pirate license'), findsOneWidget); }); - testWidgets('Material3 - AboutListTile control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - AboutListTile control test', (WidgetTester tester) async { const FlutterLogo logo = FlutterLogo(); await tester.pumpWidget( @@ -732,7 +732,7 @@ void main() { rootObserver = AboutDialogObserver(); }); - testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier is dismissible with default parameter', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( navigatorObservers: [rootObserver], @@ -764,7 +764,7 @@ void main() { expect(rootObserver.dialogCount, 0); }); - testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( navigatorObservers: [rootObserver], @@ -798,7 +798,7 @@ void main() { }); }); - testWidgets('Barrier color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -852,7 +852,7 @@ void main() { expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); }); - testWidgets('Barrier Label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier Label', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( From 67f9d7717740943e310d9eeda818c8062478323d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 29 Aug 2023 15:18:12 -0700 Subject: [PATCH 0966/1547] Upgrade packages. (#133593) --- .../gradle_deprecated_settings/pubspec.yaml | 14 +++++++------- packages/flutter/pubspec.yaml | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 2de843eb8b005..5688086b8231e 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -7,17 +7,17 @@ environment: dependencies: flutter: sdk: flutter - camera: 0.10.5+3 + camera: 0.10.5+4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_avfoundation: 0.9.13+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_platform_interface: 2.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_web: 0.3.2+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_avfoundation: 0.9.13+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_platform_interface: 2.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_web: 0.3.2+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - cross_file: 0.3.3+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + cross_file: 0.3.3+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter_plugin_android_lifecycle: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4607 +# PUBSPEC CHECKSUM: fb0d diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 269c32c474ee5..5f4d0bd30d76c 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,8 +22,8 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 9.0.5 - leak_tracker_flutter_testing: 1.0.2 + leak_tracker: 9.0.6 + leak_tracker_flutter_testing: 1.0.3 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3769 +# PUBSPEC CHECKSUM: 956b From acaa97350a70ee5d53171998027892db361c9733 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 18:36:41 -0400 Subject: [PATCH 0967/1547] Roll Flutter Engine from 01a1579808b5 to 1feb9302050c (1 revision) (#133604) https://github.com/flutter/engine/compare/01a1579808b5...1feb9302050c 2023-08-29 109111084+yaakovschectman@users.noreply.github.com Add callback to Embedder API to respond to new channel listeners, and use for Windows lifecycle (flutter/engine#44827) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 10710c15d9d8a..05aa27d58a3f0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -01a1579808b53e027c1730e6d246fac377fa9f00 +1feb9302050c5a6f7e822433915d7159365ad65c From 4736cd3d374db318bed4b04d84b3faa5378f2a55 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 29 Aug 2023 16:08:48 -0700 Subject: [PATCH 0968/1547] Fix one notDisposed leak and mark another. (#133595) --- packages/flutter/lib/src/material/bottom_sheet.dart | 6 ++++++ packages/flutter/test/material/bottom_sheet_test.dart | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index 0d683e3f23d87..df42645275215 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -1005,6 +1005,12 @@ class ModalBottomSheetRoute extends PopupRoute { final ValueNotifier _clipDetailsNotifier = ValueNotifier(EdgeInsets.zero); + @override + void dispose() { + _clipDetailsNotifier.dispose(); + super.dispose(); + } + /// Updates the details regarding how the [SemanticsNode.rect] (focus) of /// the barrier for this [ModalBottomSheetRoute] should be clipped. /// diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index 49695c859fa29..886b3d1efa17d 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -7,6 +7,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -1672,7 +1673,8 @@ void main() { }); group('Modal BottomSheet avoids overlapping display features', () { - testWidgets('positioning using anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning using anchorPoint', + (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1708,7 +1710,12 @@ void main() { // Should take the right side of the screen expect(tester.getTopLeft(find.byType(Placeholder)).dx, 410); expect(tester.getBottomRight(find.byType(Placeholder)).dx, 800); - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(polina-c): remove after fix + // https://github.com/flutter/flutter/issues/133594 + notDisposedAllowList: {'ValueNotifier': 1} + )); testWidgets('positioning using Directionality', (WidgetTester tester) async { await tester.pumpWidget( From 917d4760ce1741d8b04cd040caaf16c91b6f2828 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 19:21:51 -0400 Subject: [PATCH 0969/1547] Roll Flutter Engine from 1feb9302050c to db3ecf8b2739 (4 revisions) (#133609) https://github.com/flutter/engine/compare/1feb9302050c...db3ecf8b2739 2023-08-29 bdero@google.com [Impeller] Remove unused HasThreadingRestrictions capability. (flutter/engine#45242) 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from fb09020ce62d to 8a2754a1ae60 (6 revisions) (flutter/engine#45241) 2023-08-29 47866232+chunhtai@users.noreply.github.com [Impeller] Update xcode_frame_capture.md (flutter/engine#45230) 2023-08-29 109111084+yaakovschectman@users.noreply.github.com Update documentation for updater callback. (flutter/engine#45239) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 05aa27d58a3f0..842e711e8b15c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1feb9302050c5a6f7e822433915d7159365ad65c +db3ecf8b273912e8e41b1d4014ba69c09176d0ad From 50b3ee26efdc5f9f4dd307a7d43385522992bdd5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 20:09:15 -0400 Subject: [PATCH 0970/1547] Roll Flutter Engine from db3ecf8b2739 to c5854a6b3658 (1 revision) (#133610) https://github.com/flutter/engine/compare/db3ecf8b2739...c5854a6b3658 2023-08-29 skia-flutter-autoroll@skia.org Roll Dart SDK from a4e0e792ef9a to 0cea73a8d3c3 (1 revision) (flutter/engine#45245) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 842e711e8b15c..2270a558cafa2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -db3ecf8b273912e8e41b1d4014ba69c09176d0ad +c5854a6b3658366d4894c9ed95a70e6c2d71c195 From 670d011b71f25a1af3b24c9c5d9b2221862f6166 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Tue, 29 Aug 2023 19:40:01 -0500 Subject: [PATCH 0971/1547] No longer include `.packages` in created `.gitignore` files (#133484) The `.packages` file was deprecated in Dart 2.8 and slowly discontinued until support being fully removed in Dart 2.19. The file will no longer be created, so it can be safely dropped from the generated `.gitignore` files. --- packages/flutter_tools/templates/app_shared/.gitignore.tmpl | 1 - packages/flutter_tools/templates/module/common/.gitignore.tmpl | 1 - packages/flutter_tools/templates/package/.gitignore.tmpl | 1 - packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl | 1 - 4 files changed, 4 deletions(-) diff --git a/packages/flutter_tools/templates/app_shared/.gitignore.tmpl b/packages/flutter_tools/templates/app_shared/.gitignore.tmpl index 24476c5d1eb55..29a3a5017f048 100644 --- a/packages/flutter_tools/templates/app_shared/.gitignore.tmpl +++ b/packages/flutter_tools/templates/app_shared/.gitignore.tmpl @@ -27,7 +27,6 @@ migrate_working_dir/ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -.packages .pub-cache/ .pub/ /build/ diff --git a/packages/flutter_tools/templates/module/common/.gitignore.tmpl b/packages/flutter_tools/templates/module/common/.gitignore.tmpl index 9141595fb95f1..525e05cfbaf9e 100644 --- a/packages/flutter_tools/templates/module/common/.gitignore.tmpl +++ b/packages/flutter_tools/templates/module/common/.gitignore.tmpl @@ -1,7 +1,6 @@ .DS_Store .dart_tool/ -.packages .pub/ .idea/ diff --git a/packages/flutter_tools/templates/package/.gitignore.tmpl b/packages/flutter_tools/templates/package/.gitignore.tmpl index 96486fd930243..ac5aa9893e489 100644 --- a/packages/flutter_tools/templates/package/.gitignore.tmpl +++ b/packages/flutter_tools/templates/package/.gitignore.tmpl @@ -26,5 +26,4 @@ migrate_working_dir/ /pubspec.lock **/doc/api/ .dart_tool/ -.packages build/ diff --git a/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl b/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl index 96486fd930243..ac5aa9893e489 100644 --- a/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl +++ b/packages/flutter_tools/templates/plugin_shared/.gitignore.tmpl @@ -26,5 +26,4 @@ migrate_working_dir/ /pubspec.lock **/doc/api/ .dart_tool/ -.packages build/ From a9c16eb13530cab5151dc4b0ee668c3232630331 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 21:00:41 -0400 Subject: [PATCH 0972/1547] Roll Flutter Engine from c5854a6b3658 to 9f2cf5c99b0f (4 revisions) (#133616) https://github.com/flutter/engine/compare/c5854a6b3658...9f2cf5c99b0f 2023-08-29 skia-flutter-autoroll@skia.org Roll Skia from 8a2754a1ae60 to e6eb56d9b074 (3 revisions) (flutter/engine#45248) 2023-08-29 matanlurey@users.noreply.github.com Refactor `Stopwatch` into `StopwatchVisualizer` and `SkStopwatchVisualizer` (flutter/engine#45200) 2023-08-29 zanderso@users.noreply.github.com Roll buildroot (flutter/engine#45249) 2023-08-29 bdero@google.com [Impeller] Add GetDefaultDepthStencil to capabilities. (flutter/engine#45240) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2270a558cafa2..ddf0746bcf931 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c5854a6b3658366d4894c9ed95a70e6c2d71c195 +9f2cf5c99b0fc0282db88846c1d97e6bc3560d28 From b34955c2f4c22b419e0c9d6aa6b5dff34a83da2a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 22:07:09 -0400 Subject: [PATCH 0973/1547] Roll Flutter Engine from 9f2cf5c99b0f to 749e67a947bc (2 revisions) (#133618) https://github.com/flutter/engine/compare/9f2cf5c99b0f...749e67a947bc 2023-08-29 bdero@google.com [Impeller] Document the capabilities. (flutter/engine#45253) 2023-08-29 xilaizhang@google.com [flutter roll] Revert "ios: remove shared_application and support app extension build" (flutter/engine#45250) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ddf0746bcf931..74ed31183f371 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9f2cf5c99b0fc0282db88846c1d97e6bc3560d28 +749e67a947bc0183c90ba40f39ef95584f65ef9b From 6fd42536b7697eb4bd2a698b19308e0aacac70c7 Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Tue, 29 Aug 2023 19:59:02 -0700 Subject: [PATCH 0974/1547] [flutter roll] Revert "Fix `Chip.shape`'s side is not used when provided in Material 3" (#133615) Reverts flutter/flutter#132941 context: b/298110031 The rounded rectangle borders don't appear in some of the internal golden image tests. --- dev/tools/gen_defaults/lib/chip_template.dart | 11 ++-- packages/flutter/lib/src/material/chip.dart | 12 ++-- packages/flutter/test/material/chip_test.dart | 54 ----------------- .../test/material/chip_theme_test.dart | 58 ------------------- 4 files changed, 8 insertions(+), 127 deletions(-) diff --git a/dev/tools/gen_defaults/lib/chip_template.dart b/dev/tools/gen_defaults/lib/chip_template.dart index cdbe10362c11f..4d9383399d16d 100644 --- a/dev/tools/gen_defaults/lib/chip_template.dart +++ b/dev/tools/gen_defaults/lib/chip_template.dart @@ -19,6 +19,7 @@ class _${blockName}DefaultsM3 extends ChipThemeData { _${blockName}DefaultsM3(this.context, this.isEnabled) : super( elevation: ${elevation("$tokenGroup$variant.container")}, + shape: ${shape("$tokenGroup.container")}, showCheckmark: true, ); @@ -46,13 +47,9 @@ class _${blockName}DefaultsM3 extends ChipThemeData { Color? get deleteIconColor => ${color("$tokenGroup.with-icon.selected.icon.color")}; @override - OutlinedBorder? get shape { - return ${shape("$tokenGroup.container")}.copyWith( - side: isEnabled - ? ${border('$tokenGroup$variant.outline')} - : ${border('$tokenGroup$variant.disabled.outline')}, - ); - } + BorderSide? get side => isEnabled + ? ${border('$tokenGroup$variant.outline')} + : ${border('$tokenGroup$variant.disabled.outline')}; @override IconThemeData? get iconTheme => IconThemeData( diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 65ee8909eb0c9..3e1eb6d7bacf1 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -997,7 +997,6 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs(widget.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipTheme.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipDefaults.shape, materialStates) - // TODO(tahatesser): Remove this fallback when Material 2 is deprecated. ?? const StadiumBorder(); return resolvedShape.copyWith(side: resolvedSide); } @@ -2235,6 +2234,7 @@ class _ChipDefaultsM3 extends ChipThemeData { _ChipDefaultsM3(this.context, this.isEnabled) : super( elevation: 0.0, + shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), showCheckmark: true, ); @@ -2262,13 +2262,9 @@ class _ChipDefaultsM3 extends ChipThemeData { Color? get deleteIconColor => null; @override - OutlinedBorder? get shape { - return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))).copyWith( - side: isEnabled - ? BorderSide(color: _colors.outline) - : BorderSide(color: _colors.onSurface.withOpacity(0.12)), - ); - } + BorderSide? get side => isEnabled + ? BorderSide(color: _colors.outline) + : BorderSide(color: _colors.onSurface.withOpacity(0.12)); @override IconThemeData? get iconTheme => IconThemeData( diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 9f369c2ffa3a0..d098936aa14e3 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -3503,60 +3503,6 @@ void main() { expect(calledDelete, isTrue); }); - testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { - Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { - return MaterialApp( - theme: ThemeData(useMaterial3: true), - home: Material( - child: Center( - child: RawChip( - shape: shape, - side: side, - label: const Text('RawChip'), - ), - ), - ), - ); - } - - // Test [RawChip.shape] with a side. - await tester.pumpWidget(buildChip( - shape: const RoundedRectangleBorder( - side: BorderSide(color: Color(0xffff00ff)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - )), - ); - - // Chip should have the provided shape and the side from [RawChip.shape]. - expect( - getMaterial(tester).shape, - const RoundedRectangleBorder( - side: BorderSide(color: Color(0xffff00ff)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - ); - - // Test [RawChip.shape] with a side and [RawChip.side]. - await tester.pumpWidget(buildChip( - shape: const RoundedRectangleBorder( - side: BorderSide(color: Color(0xffff00ff)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - side: const BorderSide(color: Color(0xfffff000))), - ); - await tester.pumpAndSettle(); - - // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. - // [RawChip.shape]'s side should be ignored. - expect( - getMaterial(tester).shape, - const RoundedRectangleBorder( - side: BorderSide(color: Color(0xfffff000)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - ); - }); - group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 4ff0c5c31773e..2303b56478cd3 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -928,64 +928,6 @@ void main() { )), ); }); - - testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { - Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { - return MaterialApp( - theme: ThemeData( - useMaterial3: true, - chipTheme: ChipThemeData( - shape: shape, - side: side, - ), - ), - home: const Material( - child: Center( - child: RawChip( - label: Text('RawChip'), - ), - ), - ), - ); - } - - // Test [RawChip.shape] with a side. - await tester.pumpWidget(buildChip( - shape: const RoundedRectangleBorder( - side: BorderSide(color: Color(0xffff00ff)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - )), - ); - - // Chip should have the provided shape and the side from [RawChip.shape]. - expect( - getMaterial(tester).shape, - const RoundedRectangleBorder( - side: BorderSide(color: Color(0xffff00ff)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - ); - - // Test [RawChip.shape] with a side and [RawChip.side]. - await tester.pumpWidget(buildChip( - shape: const RoundedRectangleBorder( - side: BorderSide(color: Color(0xffff00ff)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - side: const BorderSide(color: Color(0xfffff000))), - ); - await tester.pumpAndSettle(); - - // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. - // [RawChip.shape]'s side should be ignored. - expect( - getMaterial(tester).shape, - const RoundedRectangleBorder( - side: BorderSide(color: Color(0xfffff000)), - borderRadius: BorderRadius.all(Radius.circular(7.0)), - ), - ); - }); } class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder { From cf4e09d025ce58f239b59cb5b5c7fec2436cf490 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 29 Aug 2023 23:00:12 -0400 Subject: [PATCH 0975/1547] Roll Flutter Engine from 749e67a947bc to 69f04bdfe952 (2 revisions) (#133621) https://github.com/flutter/engine/compare/749e67a947bc...69f04bdfe952 2023-08-30 jonahwilliams@google.com [Impeller] transform text path offsets so color sources match expected offsets for gradients. (flutter/engine#45255) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from e6eb56d9b074 to fde9fe141863 (1 revision) (flutter/engine#45260) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 74ed31183f371..1dbf7e027f6d6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -749e67a947bc0183c90ba40f39ef95584f65ef9b +69f04bdfe952b2f98f4cb2e02823f6e79a0dc7b4 From 56ea352cc0a7428d2978ae5b240e36fdfd374616 Mon Sep 17 00:00:00 2001 From: godofredoc Date: Tue, 29 Aug 2023 21:00:10 -0700 Subject: [PATCH 0976/1547] Remove cirrus tests from the flutter framework. (#133575) The flutter framework has been running tests both in luci and cirrus. We are removing Cirrus tests on favor of the LUCI ones. --- .cirrus.yml | 158 ---------------------------------------------------- 1 file changed, 158 deletions(-) delete mode 100644 .cirrus.yml diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 1a699600e49ad..0000000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,158 +0,0 @@ -# CIRRUS CONFIGURATION FILE -# https://cirrus-ci.org/guide/writing-tasks/ - -environment: - # For details about environment variables used in Cirrus, including how encrypted variables work, - # see https://cirrus-ci.org/guide/writing-tasks/#environment-variables - # We change Flutter's directory to include a space in its name (see $CIRRUS_WORKING_DIR) so that - # we constantly test path names with spaces in them. The FLUTTER_SDK_PATH_WITH_SPACE variable must - # therefore have a space in it. - FLUTTER_SDK_PATH_WITH_SPACE: "flutter sdk" - # We force BOT to true so that all our tools know we're in a CI environment. This avoids any - # dependency on precisely how Cirrus is detected by our tools. - BOT: "true" - -gcp_credentials: ENCRYPTED[!9409b709ab4de7293a70606cca13eaf42e9cbc704e8a6b4e3d2b09484cf997cbd2334e1eeafe23626ad07a726106df90!] - -# LINUX SHARDS -task: - gke_container: - dockerfile: "dev/ci/docker_linux/Dockerfile" - builder_image_name: docker-builder-linux # gce vm image - builder_image_project: flutter-cirrus - cluster_name: test-cluster - zone: us-central1-a - namespace: default - cpu: $CPU - memory: $MEMORY - use_in_memory_disk: $USE_IN_MEMORY_DISK - environment: - # We shrink our default resource requirement as much as possible because that way we are more - # likely to get scheduled. We require 4G of RAM because most of the shards (all but one as of - # October 2019) just get OOM-killed with less. Some shards may need more. When increasing the - # requirements for select shards, please leave a comment on those shards saying when you - # increased the requirements, what numbers you tried, and what the results were. - CPU: 1 # 0.1-8 without compute credits, 0.1-30 with (yes, you can go fractional) - MEMORY: 4G # 256M-24G without compute credits, 256M-90G with - CIRRUS_WORKING_DIR: "/tmp/$FLUTTER_SDK_PATH_WITH_SPACE" - CIRRUS_DOCKER_CONTEXT: "dev/" - PATH: "$CIRRUS_WORKING_DIR/bin:$CIRRUS_WORKING_DIR/bin/cache/dart-sdk/bin:$PATH" - ANDROID_SDK_ROOT: "/opt/android_sdk" - SHOULD_UPDATE_PACKAGES: 'TRUE' # can be overridden at the task level - USE_IN_MEMORY_DISK: false - pub_cache: - folder: $HOME/.pub-cache - fingerprint_script: echo $OS; grep -r --include=pubspec.yaml 'PUBSPEC CHECKSUM' "$CIRRUS_WORKING_DIR" - reupload_on_changes: false - flutter_pkg_cache: - folder: bin/cache/pkg - fingerprint_script: echo $OS; cat bin/internal/*.version - reupload_on_changes: false - artifacts_cache: - folder: bin/cache/artifacts - fingerprint_script: echo $OS; cat bin/internal/*.version - reupload_on_changes: false - setup_script: - - date - - git clean -xffd --exclude=bin/cache/ - - git fetch origin - - git fetch origin master # To set FETCH_HEAD, so that "git merge-base" works. - - flutter config --no-analytics - - if [ "$SHOULD_UPDATE_PACKAGES" == TRUE ]; then flutter update-packages; fi - - flutter doctor -v - - ./dev/bots/accept_android_sdk_licenses.sh - - date - on_failure: - failure_script: - - date - - which flutter - matrix: - - name: analyze-linux # linux-only - only_if: "$CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # Empirically, the analyze-linux shard runs surprisingly fast (under 15 minutes) with just 1 - # CPU. We noticed OOM failures with 6GB 4/2020, so we increased the memory. - CPU: 1 - MEMORY: 8G - script: - - dart --enable-asserts ./dev/bots/analyze.dart - - - name: framework_tests-widgets-linux - only_if: "changesInclude('.cirrus.yml', 'dev/**', 'packages/flutter/**', 'packages/flutter_test/**', 'packages/flutter_tools/lib/src/test/**', 'bin/**') && $CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # We use 3 CPUs because that's the minimum required to get framework_tests-widgets-linux - # running fast enough that it is not the long pole, as of October 2019. - CPU: 3 - script: - - dart --enable-asserts ./dev/bots/test.dart - - - name: framework_tests-libraries-linux - only_if: "changesInclude('.cirrus.yml', 'dev/**', 'packages/flutter/**', 'packages/flutter_test/**', 'packages/flutter_tools/lib/src/test/**', 'bin/**') && $CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # We use 3 CPUs because that's the minimum required to get the - # framework_tests-libraries-linux shard running fast enough that it is not the long pole, as - # of October 2019. - CPU: 3 - script: - - dart --enable-asserts ./dev/bots/test.dart - - - name: framework_tests-misc-linux - # this includes the tests for directories in dev/ - only_if: "changesInclude('.cirrus.yml', 'dev/**', 'packages/flutter/**', 'packages/flutter_goldens/**', 'packages/flutter_test/**', 'packages/flutter_tools/lib/src/test/**', 'bin/**') && $CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # We use 3 CPUs because that's the minimum required to get framework_tests-misc-linux - # running fast enough that it is not the long pole, as of October 2019. - CPU: 3 - script: - - dart --enable-asserts ./dev/bots/test.dart - - - name: tool_tests-general-linux - only_if: "changesInclude('.cirrus.yml', 'dev/**', 'packages/flutter_tools/**', 'bin/**') && $CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # As of November 2019, the tool_tests-general-linux shard got faster with more CPUs up to 4 - # CPUs, and needed at least 10G of RAM to not run out of memory. - CPU: 4 - MEMORY: 10G - SHOULD_UPDATE_PACKAGES: "FALSE" - script: - - (cd packages/flutter_tools; dart pub get) - - (cd packages/flutter_tools/test/data/asset_test/main; dart pub get) - - (cd packages/flutter_tools/test/data/asset_test/font; dart pub get) - - (cd dev/bots; dart pub get) - - dart --enable-asserts ./dev/bots/test.dart - - - name: tool_tests-commands-linux - only_if: "changesInclude('.cirrus.yml', 'dev/**', 'packages/flutter_tools/**', 'bin/**') && $CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # As of October 2019, the tool_tests-commands-linux shard got faster with more CPUs up to 6 - # CPUs, and needed at least 8G of RAM to not run out of memory. - # Increased to 10GB on 19th Nov 2019 due to significant number of OOMKilled failures on PR builds. - CPU: 6 - MEMORY: 10G - SHOULD_UPDATE_PACKAGES: "FALSE" - script: - - (cd packages/flutter_tools; dart pub get) - - (cd dev/bots; dart pub get) - - dart --enable-asserts ./dev/bots/test.dart - - - name: docs-linux # linux-only - environment: - CPU: 4 - MEMORY: 12G - only_if: "$CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - script: - - ./dev/bots/docs.sh - - - name: customer_testing-linux - only_if: "$CIRRUS_PR != '' && $CIRRUS_BASE_BRANCH == 'master'" - environment: - # Empirically, this shard runs fine at 1 CPU and 4G RAM as of October 2019. We will probably - # want to grow this container when we invite people to add their tests in large numbers. - SHOULD_UPDATE_PACKAGES: "FALSE" - script: - # Cirrus doesn't give us the master branch, so we have to fetch it for ourselves, - # otherwise we won't be able to figure out how old or new our current branch is. - - git config user.email "cirrus-bot@invalid" - - git fetch origin master:master - # The actual logic is in a shell script so that it can be shared between CIs. - - (cd dev/customer_testing/; ./ci.sh) From 1fe24956ac46b7805cf9de1b9f4e7dfc74e99dec Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Wed, 30 Aug 2023 15:25:35 +0200 Subject: [PATCH 0977/1547] Update SelectableRegion test for M3 (#129627) ## Description This PR fixes one selectable region test failure when switching to M3. The failure is somewhat tricky because it is related to the M3 typography (line height set to 1.43). ## Related Issue fixes https://github.com/flutter/flutter/issues/129626 ## Tests Updates 1 test. --- packages/flutter/lib/src/widgets/selectable_region.dart | 6 +++--- packages/flutter/test/widgets/selectable_region_test.dart | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index f08e20ec2551e..17abff5de57b3 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -2052,15 +2052,15 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai if (globalRect.contains(event.globalPosition)) { final SelectionGeometry existingGeometry = selectables[index].value; lastSelectionResult = dispatchSelectionEventToChild(selectables[index], event); + if (index == selectables.length - 1 && lastSelectionResult == SelectionResult.next) { + return SelectionResult.next; + } if (lastSelectionResult == SelectionResult.next) { continue; } if (index == 0 && lastSelectionResult == SelectionResult.previous) { return SelectionResult.previous; } - if (index == selectables.length - 1 && lastSelectionResult == SelectionResult.next) { - return SelectionResult.next; - } if (selectables[index].value != existingGeometry) { // Geometry has changed as a result of select word, need to clear the // selection of other selectables to keep selection in sync. diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index a2e8bcb67fad4..b4e3f5d0eeb48 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -1570,7 +1570,6 @@ void main() { final UniqueKey outerText = UniqueKey(); await tester.pumpWidget( MaterialApp( - theme: ThemeData(useMaterial3: false), home: SelectableRegion( focusNode: FocusNode(), selectionControls: materialTextSelectionControls, @@ -1595,8 +1594,13 @@ void main() { ), ); final RenderParagraph paragraph = tester.renderObject(find.descendant(of: find.byKey(outerText), matching: find.byType(RichText)).first); + + // Adjust `textOffsetToPosition` result because it returns the wrong vertical position (wrong line). + // TODO(bleroux): Remove when https://github.com/flutter/flutter/issues/133637 is fixed. + final Offset gestureOffset = textOffsetToPosition(paragraph, 125).translate(0, 10); + // Right click to select word at position. - final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 125), kind: PointerDeviceKind.mouse, buttons: kSecondaryMouseButton); + final TestGesture gesture = await tester.startGesture(gestureOffset, kind: PointerDeviceKind.mouse, buttons: kSecondaryMouseButton); addTearDown(gesture.removePointer); await tester.pump(); await gesture.up(); From 7368da037aed4b21f53bf7f4734367856333ebce Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot Date: Wed, 30 Aug 2023 08:00:14 -0700 Subject: [PATCH 0978/1547] Marks Windows module_test to be flaky (#133640) Issue link: https://github.com/flutter/flutter/issues/133639 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 1d4aa94a84712..dab1f17fb083c 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4591,6 +4591,7 @@ targets: - .ci.yaml - name: Windows module_test + bringup: true # Flaky https://github.com/flutter/flutter/issues/133639 recipe: devicelab/devicelab_drone timeout: 60 properties: From 44a9b364617d20c2c7debaf22b89ce522eda208a Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 30 Aug 2023 08:40:14 -0700 Subject: [PATCH 0979/1547] Bump gradle heap size limits in templates (#133671) For https://github.com/flutter/flutter/issues/133639 --- .../templates/app_shared/android.tmpl/gradle.properties.tmpl | 2 +- .../templates/module/android/gradle/gradle.properties.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/templates/app_shared/android.tmpl/gradle.properties.tmpl b/packages/flutter_tools/templates/app_shared/android.tmpl/gradle.properties.tmpl index 94adc3a3f97aa..598d13fee4463 100644 --- a/packages/flutter_tools/templates/app_shared/android.tmpl/gradle.properties.tmpl +++ b/packages/flutter_tools/templates/app_shared/android.tmpl/gradle.properties.tmpl @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/packages/flutter_tools/templates/module/android/gradle/gradle.properties.tmpl b/packages/flutter_tools/templates/module/android/gradle/gradle.properties.tmpl index 94adc3a3f97aa..598d13fee4463 100644 --- a/packages/flutter_tools/templates/module/android/gradle/gradle.properties.tmpl +++ b/packages/flutter_tools/templates/module/android/gradle/gradle.properties.tmpl @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true From 994aab4c78ff1fabc987929ea4cd1cafea2d6e0d Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 30 Aug 2023 19:40:59 +0300 Subject: [PATCH 0980/1547] Update & improve `TabBar.labelColor` tests (#133668) fixes [Improve `TabBar.labelColor` tests](https://github.com/flutter/flutter/issues/133665) While working on a fix for https://github.com/flutter/flutter/issues/109484, I found the existing test could use some improvement first. --- .../test/material/tab_bar_theme_test.dart | 73 ++++++ packages/flutter/test/material/tabs_test.dart | 238 ++++++++---------- 2 files changed, 172 insertions(+), 139 deletions(-) diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 0db83f44abc88..7d3789e7b4098 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -1216,4 +1216,77 @@ void main() { tabBarBox = tester.firstRenderObject(find.byType(TabBar)); expect(tabBarBox,paints..line(color: tabBarThemeIndicatorColor)); }); + + testWidgets('TabBarTheme.labelColor resolves material states', (WidgetTester tester) async { + const Color selectedColor = Color(0xff00ff00); + const Color unselectedColor = Color(0xffff0000); + final MaterialStateColor labelColor = MaterialStateColor.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return selectedColor; + } + return unselectedColor; + }); + + final TabBarTheme tabBarTheme = TabBarTheme(labelColor: labelColor); + + // Test labelColor correctly resolves material states. + await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme)); + + final IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + final IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + final TextStyle selectedTextStyle = tester.renderObject(find.text(_tab1Text)).text.style!; + final TextStyle unselectedTextStyle = tester.renderObject(find.text(_tab2Text)).text.style!; + + expect(selectedTabIcon.color, selectedColor); + expect(uselectedTabIcon.color, unselectedColor); + expect(selectedTextStyle.color, selectedColor); + expect(unselectedTextStyle.color, unselectedColor); + }); + + testWidgets('TabBarTheme.labelColor & TabBarTheme.unselectedLabelColor override material state TabBarTheme.labelColor', + (WidgetTester tester) async { + const Color selectedStateColor = Color(0xff00ff00); + const Color unselectedStateColor = Color(0xffff0000); + final MaterialStateColor labelColor = MaterialStateColor.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return selectedStateColor; + } + return unselectedStateColor; + }); + const Color selectedColor = Color(0xff00ffff); + const Color unselectedColor = Color(0xffff12ff); + + TabBarTheme tabBarTheme = TabBarTheme(labelColor: labelColor); + + // Test material state label color. + await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme)); + + IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + TextStyle selectedTextStyle = tester.renderObject(find.text(_tab1Text)).text.style!; + TextStyle unselectedTextStyle = tester.renderObject(find.text(_tab2Text)).text.style!; + + expect(selectedTabIcon.color, selectedStateColor); + expect(uselectedTabIcon.color, unselectedStateColor); + expect(selectedTextStyle.color, selectedStateColor); + expect(unselectedTextStyle.color, unselectedStateColor); + + // Test labelColor & unselectedLabelColor override material state labelColor. + tabBarTheme = const TabBarTheme( + labelColor: selectedColor, + unselectedLabelColor: unselectedColor, + ); + await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme)); + await tester.pumpAndSettle(); + + selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + selectedTextStyle = tester.renderObject(find.text(_tab1Text)).text.style!; + unselectedTextStyle = tester.renderObject(find.text(_tab2Text)).text.style!; + + expect(selectedTabIcon.color, selectedColor); + expect(uselectedTabIcon.color, unselectedColor); + expect(selectedTextStyle.color, selectedColor); + expect(unselectedTextStyle.color, unselectedColor); + }); } diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 461393d7ab557..bec9ffbe776a5 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -4511,139 +4511,99 @@ void main() { expect(iconTheme.color, equals(selectedTabColor)); }); - testWidgets('TabBar colors labels correctly', (WidgetTester tester) async { - MaterialStateColor buildMSC(Color selectedColor, Color unselectedColor) { - return MaterialStateColor - .resolveWith((Set states) { - if (states.contains(MaterialState.selected)) { - return selectedColor; - } - return unselectedColor; - }); - } + testWidgets('TabBar.labelColor resolves material states', (WidgetTester tester) async { + const String tab1 = 'Tab 1'; + const String tab2 = 'Tab 2'; + + const Color selectedColor = Color(0xff00ff00); + const Color unselectedColor = Color(0xffff0000); + final MaterialStateColor labelColor = MaterialStateColor.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return selectedColor; + } + return unselectedColor; + }); - final Color materialLabelColor = buildMSC(const Color(0x00000000), const Color(0x00000001)); - const Color labelColor = Color(0x00000002); - const Color unselectedLabelColor = Color(0x00000003); - - // this is to make sure labelStyles (in TabBar and in TabBarTheme) don't - // affect label's color. for details: https://github.com/flutter/flutter/pull/109541#issuecomment-1294241417 - const TextStyle labelStyle = TextStyle(color: Color(0x00000004)); - const TextStyle unselectedLabelStyle = TextStyle(color: Color(0x00000005)); - - final TabBarTheme materialTabBarTheme = TabBarTheme( - labelColor: buildMSC(const Color(0x00000006), const Color(0x00000007)), - unselectedLabelColor: const Color(0x00000008), - labelStyle: TextStyle(color: buildMSC(const Color(0x00000009), const Color(0x00000010))), - unselectedLabelStyle: const TextStyle(color: Color(0x00000011)), - ); - const TabBarTheme tabBarTheme = TabBarTheme( - labelColor: Color(0x00000012), - unselectedLabelColor: Color(0x00000013), - labelStyle: TextStyle(color: Color(0x00000014)), - unselectedLabelStyle: TextStyle(color: Color(0x00000015)), - ); - const TabBarTheme tabBarThemeWithNullUnselectedLabelColor = TabBarTheme( - labelColor: Color(0x00000016), - labelStyle: TextStyle(color: Color(0x00000017)), - unselectedLabelStyle: TextStyle(color: Color(0x00000018)), - ); - final ThemeData theme = ThemeData(useMaterial3: false); - Widget buildTabBar({ - bool isLabelColorMSC = false, - bool isLabelColorNull = false, - bool isUnselectedLabelColorNull = false, - bool isTabBarThemeMSC = false, - bool isTabBarThemeNull = false, - bool isTabBarThemeUnselectedLabelColorNull = false, - }) { - final TabBarTheme? effectiveTheme = isTabBarThemeNull - ? null : isTabBarThemeUnselectedLabelColorNull - ? tabBarThemeWithNullUnselectedLabelColor - : isTabBarThemeMSC - ? materialTabBarTheme - : tabBarTheme; + // Test labelColor correctly resolves material states. + await tester.pumpWidget(boilerplate( + child: DefaultTabController( + length: 2, + child: TabBar( + labelColor: labelColor, + tabs: const [ + Text(tab1), + Text(tab2), + ], + ), + ), + )); + + final IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(tab1))); + final IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(tab2))); + final TextStyle selectedTextStyle = tester.renderObject(find.text(tab1)).text.style!; + final TextStyle unselectedTextStyle = tester.renderObject(find.text(tab2)).text.style!; + + expect(selectedTabIcon.color, selectedColor); + expect(uselectedTabIcon.color, unselectedColor); + expect(selectedTextStyle.color, selectedColor); + expect(unselectedTextStyle.color, unselectedColor); + }); + + testWidgets('labelColor & unselectedLabelColor override material state labelColor', (WidgetTester tester) async { + const String tab1 = 'Tab 1'; + const String tab2 = 'Tab 2'; + + const Color selectedStateColor = Color(0xff00ff00); + const Color unselectedStateColor = Color(0xffff0000); + final MaterialStateColor labelColor = MaterialStateColor.resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return selectedStateColor; + } + return unselectedStateColor; + }); + const Color selectedColor = Color(0xff00ffff); + const Color unselectedColor = Color(0xffff12ff); + + Widget buildTabBar({ bool stateColor = true }){ return boilerplate( - child: Theme( - data: theme.copyWith(tabBarTheme: effectiveTheme), - child: DefaultTabController( - length: 2, - child: TabBar( - labelColor: isLabelColorNull ? null : isLabelColorMSC ? materialLabelColor : labelColor, - unselectedLabelColor: isUnselectedLabelColorNull ? null : unselectedLabelColor, - labelStyle: labelStyle, - unselectedLabelStyle: unselectedLabelStyle, - tabs: const [Text('1'), Text('2')], - ), - ), + child: DefaultTabController( + length: 2, + child: TabBar( + labelColor: stateColor ? labelColor : selectedColor, + unselectedLabelColor: stateColor ? null : unselectedColor, + tabs: const [ + Text(tab1), + Text(tab2), + ], ), - ); + )); } - // Returns int `color.value`s instead of Color `color`s to prevent false - // negative due to object types being different (Color != MaterialStateColor) - // when `expect`ing. - int? getTab1Color() => IconTheme.of(tester.element(find.text('1'))).color?.value; - int? getTab2Color() => IconTheme.of(tester.element(find.text('2'))).color?.value; - int getSelectedColor(Color color) => (color as MaterialStateColor) - .resolve({MaterialState.selected}).value; - int getUnselectedColor(Color color) => (color as MaterialStateColor) - .resolve({}).value; - - // highest precedence: labelColor as MaterialStateColor - await tester.pumpWidget(buildTabBar(isLabelColorMSC: true)); - expect(getTab1Color(), equals(getSelectedColor(materialLabelColor))); - expect(getTab2Color(), equals(getUnselectedColor(materialLabelColor))); - - // next precedence: labelColor and unselectedLabelColor + // Test material state label color. await tester.pumpWidget(buildTabBar()); - expect(getTab1Color(), equals(labelColor.value)); - expect(getTab2Color(), equals(unselectedLabelColor.value)); - // next precedence: tabBarTheme.labelColor as MaterialStateColor - await tester.pumpWidget(buildTabBar( - isLabelColorNull: true, - isTabBarThemeMSC: true, - )); - expect(getTab1Color(), equals(getSelectedColor(materialTabBarTheme.labelColor!))); - expect(getTab2Color(), equals(getUnselectedColor(materialTabBarTheme.labelColor!))); - - // next precedence: tabBarTheme.labelColor and - // tabBarTheme.unselectedLabelColor - await tester.pumpWidget(buildTabBar( - isLabelColorNull: true, - isUnselectedLabelColorNull: true, - )); - expect(getTab1Color(), equals(tabBarTheme.labelColor!.value)); - expect(getTab2Color(), equals(tabBarTheme.unselectedLabelColor!.value)); + IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(tab1))); + IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(tab2))); + TextStyle selectedTextStyle = tester.renderObject(find.text(tab1)).text.style!; + TextStyle unselectedTextStyle = tester.renderObject(find.text(tab2)).text.style!; - // next precedence: labelColor and labelColor at 70% opacity - await tester.pumpWidget(buildTabBar( - isUnselectedLabelColorNull: true, - isTabBarThemeUnselectedLabelColorNull: true, - )); - expect(getTab1Color(), equals(labelColor.value)); - expect(getTab2Color(), equals(labelColor.withAlpha(0xB2).value)); - - // next precedence: tabBarTheme.labelColor and tabBarTheme.labelColor at 70% - // opacity - await tester.pumpWidget(buildTabBar( - isLabelColorNull: true, - isUnselectedLabelColorNull: true, - isTabBarThemeUnselectedLabelColorNull: true, - )); - expect(getTab1Color(), equals(tabBarThemeWithNullUnselectedLabelColor.labelColor!.value)); - expect(getTab2Color(), equals(tabBarThemeWithNullUnselectedLabelColor.labelColor!.withAlpha(0xB2).value)); - - // last precedence: themeData.primaryTextTheme.bodyText1.color and - // themeData.primaryTextTheme.bodyText1.color.withAlpha(0xB2) - await tester.pumpWidget(buildTabBar( - isLabelColorNull: true, - isUnselectedLabelColorNull: true, - isTabBarThemeNull: true, - )); - expect(getTab1Color(), equals(theme.primaryTextTheme.bodyText1!.color!.value)); - expect(getTab2Color(), equals(theme.primaryTextTheme.bodyText1!.color!.withAlpha(0xB2).value)); + expect(selectedTabIcon.color, selectedStateColor); + expect(uselectedTabIcon.color, unselectedStateColor); + expect(selectedTextStyle.color, selectedStateColor); + expect(unselectedTextStyle.color, unselectedStateColor); + + // Test labelColor & unselectedLabelColor override material state labelColor. + await tester.pumpWidget(buildTabBar(stateColor: false)); + + selectedTabIcon = IconTheme.of(tester.element(find.text(tab1))); + uselectedTabIcon = IconTheme.of(tester.element(find.text(tab2))); + selectedTextStyle = tester.renderObject(find.text(tab1)).text.style!; + unselectedTextStyle = tester.renderObject(find.text(tab2)).text.style!; + + expect(selectedTabIcon.color, selectedColor); + expect(uselectedTabIcon.color, unselectedColor); + expect(selectedTextStyle.color, selectedColor); + expect(unselectedTextStyle.color, unselectedColor); }); testWidgets('Replacing the tabController after disposing the old one', (WidgetTester tester) async { @@ -5015,19 +4975,19 @@ void main() { late Color firstColor; late Color secondColor; - Widget buildTabBar({bool labelColorIsMaterialStateColor = false}) { - final Color labelColor = labelColorIsMaterialStateColor - ? MaterialStateColor - .resolveWith((Set states) { - if (states.contains(MaterialState.selected)) { - return Colors.white; - } else { - // this is a third color to also test if unselectedLabelColor - // is ignored when labelColor is MaterialStateColor - return Colors.transparent; - } - }) - : Colors.white; + Widget buildTabBar({ bool stateColor = false }) { + final Color labelColor = stateColor + ? MaterialStateColor + .resolveWith((Set states) { + if (states.contains(MaterialState.selected)) { + return Colors.white; + } else { + // this is a third color to also test if unselectedLabelColor + // is ignored when labelColor is MaterialStateColor + return Colors.transparent; + } + }) + : Colors.white; return boilerplate( child: TabBar( @@ -5087,7 +5047,7 @@ void main() { controller.index = 0; await tester.pump(); - await tester.pumpWidget(buildTabBar(labelColorIsMaterialStateColor: true)); + await tester.pumpWidget(buildTabBar(stateColor: true)); await testLabelColor(selectedColor: Colors.white, unselectedColor: Colors.transparent); }); From d49eb4afac5f6fad383755507399fffe4774df63 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 12:41:01 -0400 Subject: [PATCH 0981/1547] Roll Packages from d7d3150e5966 to 64af59e00bb7 (4 revisions) (#133675) https://github.com/flutter/packages/compare/d7d3150e5966...64af59e00bb7 2023-08-30 katelovett@google.com [two_dimensional_scrollables] Fix repaint boundary override in builder delegate (flutter/packages#4814) 2023-08-29 stuartmorgan@google.com [all] Add topics to pubspecs (flutter/packages#4771) 2023-08-29 engine-flutter-autoroll@skia.org Roll Flutter from ec387a467a68 to 6c95737375db (24 revisions) (flutter/packages#4813) 2023-08-29 panuj330@gmail.com Fixed AlertDialog Height of example in image_picker (flutter/packages#4800) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 9d28099430a90..672e1cf5c6e30 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -d7d3150e596686c9769249d7b0910ff6f9f5ee3b +64af59e00bb7f4b98470560378210846549f6ee3 From 7f3abea35ae470d6e3a4c512231d578f80c79507 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:28:10 -0700 Subject: [PATCH 0982/1547] Reland "Remove ImageProvider.load, DecoderCallback and `PaintingBinding.instantiateImageCodec` (#132679) (reverted in #133482) (#133605) Relanding the commit per https://github.com/flutter/flutter/pull/133482#issuecomment-1698030976 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../lib/src/painting/_network_image_io.dart | 39 +-- .../lib/src/painting/_network_image_web.dart | 40 +--- .../flutter/lib/src/painting/binding.dart | 41 ---- .../lib/src/painting/image_decoder.dart | 9 +- .../lib/src/painting/image_provider.dart | 226 +++--------------- .../widgets/scroll_aware_image_provider.dart | 5 +- .../flutter/test/material/switch_test.dart | 4 +- .../test/painting/decoration_test.dart | 10 +- .../test/painting/fake_image_provider.dart | 2 +- .../test/painting/image_test_utils.dart | 5 - .../test/painting/mocks_for_image_cache.dart | 21 +- .../flutter/test/painting/painting_utils.dart | 4 +- .../test/painting/shape_decoration_test.dart | 2 +- .../test/widgets/box_decoration_test.dart | 2 +- .../test/widgets/fade_in_image_test.dart | 2 +- .../widgets/image_filter_quality_test.dart | 2 +- .../flutter/test/widgets/image_rtl_test.dart | 2 +- packages/flutter/test/widgets/image_test.dart | 4 +- 18 files changed, 75 insertions(+), 345 deletions(-) diff --git a/packages/flutter/lib/src/painting/_network_image_io.dart b/packages/flutter/lib/src/painting/_network_image_io.dart index 05dd8cb722291..5221279c61d16 100644 --- a/packages/flutter/lib/src/painting/_network_image_io.dart +++ b/packages/flutter/lib/src/painting/_network_image_io.dart @@ -13,6 +13,9 @@ import 'debug.dart'; import 'image_provider.dart' as image_provider; import 'image_stream.dart'; +// Method signature for _loadAsync decode callbacks. +typedef _SimpleDecoderCallback = Future Function(ui.ImmutableBuffer buffer); + /// The dart:io implementation of [image_provider.NetworkImage]. @immutable class NetworkImage extends image_provider.ImageProvider implements image_provider.NetworkImage { @@ -35,25 +38,6 @@ class NetworkImage extends image_provider.ImageProvider(this); } - @override - ImageStreamCompleter load(image_provider.NetworkImage key, image_provider.DecoderCallback decode) { - // Ownership of this controller is handed off to [_loadAsync]; it is that - // method's responsibility to close the controller's stream when the image - // has been loaded or an error is thrown. - final StreamController chunkEvents = StreamController(); - - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key as NetworkImage, chunkEvents, decodeDeprecated: decode), - chunkEvents: chunkEvents.stream, - scale: key.scale, - debugLabel: key.url, - informationCollector: () => [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), - ], - ); - } - @override ImageStreamCompleter loadBuffer(image_provider.NetworkImage key, image_provider.DecoderBufferCallback decode) { // Ownership of this controller is handed off to [_loadAsync]; it is that @@ -62,7 +46,7 @@ class NetworkImage extends image_provider.ImageProvider chunkEvents = StreamController(); return MultiFrameImageStreamCompleter( - codec: _loadAsync(key as NetworkImage, chunkEvents, decodeBufferDeprecated: decode), + codec: _loadAsync(key as NetworkImage, chunkEvents, decode: decode), chunkEvents: chunkEvents.stream, scale: key.scale, debugLabel: key.url, @@ -112,9 +96,7 @@ class NetworkImage extends image_provider.ImageProvider _loadAsync( NetworkImage key, StreamController chunkEvents, { - image_provider.ImageDecoderCallback? decode, - image_provider.DecoderBufferCallback? decodeBufferDeprecated, - image_provider.DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { try { assert(key == this); @@ -148,16 +130,7 @@ class NetworkImage extends image_provider.ImageProvider Function(ui.ImmutableBuffer buffer); + /// Default HTTP client. web.XMLHttpRequest _httpClient() { return web.XMLHttpRequest(); @@ -55,23 +58,6 @@ class NetworkImage return SynchronousFuture(this); } - @override - ImageStreamCompleter load(image_provider.NetworkImage key, image_provider.DecoderCallback decode) { - // Ownership of this controller is handed off to [_loadAsync]; it is that - // method's responsibility to close the controller's stream when the image - // has been loaded or an error is thrown. - final StreamController chunkEvents = - StreamController(); - - return MultiFrameImageStreamCompleter( - chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, null, null, decode, chunkEvents), - scale: key.scale, - debugLabel: key.url, - informationCollector: _imageStreamInformationCollector(key), - ); - } - @override ImageStreamCompleter loadBuffer(image_provider.NetworkImage key, image_provider.DecoderBufferCallback decode) { // Ownership of this controller is handed off to [_loadAsync]; it is that @@ -82,7 +68,7 @@ class NetworkImage return MultiFrameImageStreamCompleter( chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, null, decode, null, chunkEvents), + codec: _loadAsync(key as NetworkImage, decode, chunkEvents), scale: key.scale, debugLabel: key.url, informationCollector: _imageStreamInformationCollector(key), @@ -98,7 +84,7 @@ class NetworkImage return MultiFrameImageStreamCompleter( chunkEvents: chunkEvents.stream, - codec: _loadAsync(key as NetworkImage, decode, null, null, chunkEvents), + codec: _loadAsync(key as NetworkImage, decode, chunkEvents), scale: key.scale, debugLabel: key.url, informationCollector: _imageStreamInformationCollector(key), @@ -122,9 +108,7 @@ class NetworkImage // in place of the typical `instantiateImageCodec` method. Future _loadAsync( NetworkImage key, - image_provider.ImageDecoderCallback? decode, - image_provider.DecoderBufferCallback? decodeBufferDeprecated, - image_provider.DecoderCallback? decodeDeprecated, + _SimpleDecoderCallback decode, StreamController chunkEvents, ) async { assert(key == this); @@ -179,17 +163,7 @@ class NetworkImage throw image_provider.NetworkImageLoadException( statusCode: request.status, uri: resolved); } - - if (decode != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decode(buffer); - } else if (decodeBufferDeprecated != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decodeBufferDeprecated(buffer); - } else { - assert(decodeDeprecated != null); - return decodeDeprecated!(bytes); - } + return decode(await ui.ImmutableBuffer.fromUint8List(bytes)); } else { return ui_web.createImageCodecFromUrl( resolved, diff --git a/packages/flutter/lib/src/painting/binding.dart b/packages/flutter/lib/src/painting/binding.dart index 880db6d33fa23..02efc9082ac7c 100644 --- a/packages/flutter/lib/src/painting/binding.dart +++ b/packages/flutter/lib/src/painting/binding.dart @@ -78,47 +78,6 @@ mixin PaintingBinding on BindingBase, ServicesBinding { @protected ImageCache createImageCache() => ImageCache(); - /// Calls through to [dart:ui.instantiateImageCodec] from [ImageCache]. - /// - /// This method is deprecated. use [instantiateImageCodecFromBuffer] with an - /// [ImmutableBuffer] instance instead of this method. - /// - /// The `cacheWidth` and `cacheHeight` parameters, when specified, indicate - /// the size to decode the image to. - /// - /// Both `cacheWidth` and `cacheHeight` must be positive values greater than - /// or equal to 1, or null. It is valid to specify only one of `cacheWidth` - /// and `cacheHeight` with the other remaining null, in which case the omitted - /// dimension will be scaled to maintain the aspect ratio of the original - /// dimensions. When both are null or omitted, the image will be decoded at - /// its native resolution. - /// - /// The `allowUpscaling` parameter determines whether the `cacheWidth` or - /// `cacheHeight` parameters are clamped to the intrinsic width and height of - /// the original image. By default, the dimensions are clamped to avoid - /// unnecessary memory usage for images. Callers that wish to display an image - /// above its native resolution should prefer scaling the canvas the image is - /// drawn into. - @Deprecated( - 'Use instantiateImageCodecWithSize with an ImmutableBuffer instance instead. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', - ) - Future instantiateImageCodec( - Uint8List bytes, { - int? cacheWidth, - int? cacheHeight, - bool allowUpscaling = false, - }) { - assert(cacheWidth == null || cacheWidth > 0); - assert(cacheHeight == null || cacheHeight > 0); - return ui.instantiateImageCodec( - bytes, - targetWidth: cacheWidth, - targetHeight: cacheHeight, - allowUpscaling: allowUpscaling, - ); - } - /// Calls through to [dart:ui.instantiateImageCodecFromBuffer] from [ImageCache]. /// /// The [buffer] parameter should be an [ui.ImmutableBuffer] instance which can diff --git a/packages/flutter/lib/src/painting/image_decoder.dart b/packages/flutter/lib/src/painting/image_decoder.dart index 39d926ee341a1..328c840f7393f 100644 --- a/packages/flutter/lib/src/painting/image_decoder.dart +++ b/packages/flutter/lib/src/painting/image_decoder.dart @@ -3,7 +3,7 @@ // found in the LICENSE file. import 'dart:typed_data'; -import 'dart:ui' as ui show Codec, FrameInfo, Image; +import 'dart:ui' as ui show Codec, FrameInfo, Image, ImmutableBuffer; import 'binding.dart'; @@ -17,10 +17,11 @@ import 'binding.dart'; /// [instantiateImageCodec] if support for animated images is necessary. /// /// This function differs from [ui.decodeImageFromList] in that it defers to -/// [PaintingBinding.instantiateImageCodec], and therefore can be mocked in -/// tests. +/// [PaintingBinding.instantiateImageCodecWithSize], and therefore can be mocked +/// in tests. Future decodeImageFromList(Uint8List bytes) async { - final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodec(bytes); + final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); + final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer); final ui.FrameInfo frameInfo = await codec.getNextFrame(); return frameInfo.image; } diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index 54e21cc5977ef..b7067c2583dd7 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -160,25 +160,6 @@ class ImageConfiguration { } } -/// Performs the decode process for use in [ImageProvider.load]. -/// -/// This typedef is deprecated. Use [ImageDecoderCallback] with -/// [ImageProvider.loadImage] instead. -/// -/// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and -/// `allowUpscaling` parameters from implementations of [ImageProvider] that do -/// not expose them. -/// -/// See also: -/// -/// * [ResizeImage], which uses this to override the `cacheWidth`, -/// `cacheHeight`, and `allowUpscaling` parameters. -@Deprecated( - 'Use ImageDecoderCallback with ImageProvider.loadImage instead. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', -) -typedef DecoderCallback = Future Function(Uint8List buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling}); - /// Performs the decode process for use in [ImageProvider.loadBuffer]. /// /// This callback allows decoupling of the `cacheWidth`, `cacheHeight`, and @@ -195,6 +176,9 @@ typedef DecoderCallback = Future Function(Uint8List buffer, {int? cach ) typedef DecoderBufferCallback = Future Function(ui.ImmutableBuffer buffer, {int? cacheWidth, int? cacheHeight, bool allowUpscaling}); +// Method signature for _loadAsync decode callbacks. +typedef _SimpleDecoderCallback = Future Function(ui.ImmutableBuffer buffer); + /// Performs the decode process for use in [ImageProvider.loadImage]. /// /// This callback allows decoupling of the `getTargetSize` parameter from @@ -250,7 +234,7 @@ typedef ImageDecoderCallback = Future Function( /// from the cache if possible, or call [loadImage] to fetch the encoded image /// bytes and schedule decoding. /// 4. The [loadImage] method is responsible for both fetching the encoded bytes -/// and decoding them using the provided [DecoderCallback]. It is called +/// and decoding them using the provided [ImageDecoderCallback]. It is called /// in a context that uses the [ImageErrorListener] to report errors back. /// /// Subclasses normally only have to implement the [loadImage] and [obtainKey] @@ -365,10 +349,10 @@ abstract class ImageProvider { /// /// This is the public entry-point of the [ImageProvider] class hierarchy. /// - /// Subclasses should implement [obtainKey] and [load], which are used by this - /// method. If they need to change the implementation of [ImageStream] used, - /// they should override [createStream]. If they need to manage the actual - /// resolution of the image, they should override [resolveStreamForKey]. + /// Subclasses should implement [obtainKey] and [loadImage], which are used by + /// this method. If they need to change the implementation of [ImageStream] + /// used, they should override [createStream]. If they need to manage the + /// actual resolution of the image, they should override [resolveStreamForKey]. /// /// See the Lifecycle documentation on [ImageProvider] for more information. @nonVirtual @@ -542,10 +526,6 @@ abstract class ImageProvider { // of type `_AbstractImageStreamCompleter`. if (result is _AbstractImageStreamCompleter) { result = loadBuffer(key, PaintingBinding.instance.instantiateImageCodecFromBuffer); - if (result is _AbstractImageStreamCompleter) { - // Same fallback as above but for the deprecated `load()` method. - result = load(key, PaintingBinding.instance.instantiateImageCodec); - } } return result; }, @@ -610,39 +590,17 @@ abstract class ImageProvider { /// that describes the precise image to load. /// /// The type of the key is determined by the subclass. It is a value that - /// unambiguously identifies the image (_including its scale_) that the [load] - /// method will fetch. Different [ImageProvider]s given the same constructor - /// arguments and [ImageConfiguration] objects should return keys that are - /// '==' to each other (possibly by using a class for the key that itself - /// implements [==]). + /// unambiguously identifies the image (_including its scale_) that the + /// [loadImage] method will fetch. Different [ImageProvider]s given the same + /// constructor arguments and [ImageConfiguration] objects should return keys + /// that are '==' to each other (possibly by using a class for the key that + /// itself implements [==]). /// /// If the result can be determined synchronously, this function should return /// a [SynchronousFuture]. This allows image resolution to progress /// synchronously during a frame rather than delaying image loading. Future obtainKey(ImageConfiguration configuration); - /// Converts a key into an [ImageStreamCompleter], and begins fetching the - /// image. - /// - /// This method is deprecated. Implement [loadImage] for faster image - /// loading. Only one of [load] and [loadImage] must be implemented, and - /// [loadImage] is preferred. - /// - /// The [decode] callback provides the logic to obtain the codec for the - /// image. - /// - /// See also: - /// - /// * [ResizeImage], for modifying the key to account for cache dimensions. - @protected - @Deprecated( - 'Implement loadImage for faster image loading. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', - ) - ImageStreamCompleter load(T key, DecoderCallback decode) { - throw UnsupportedError('Implement loadImage for faster image loading'); - } - /// Converts a key into an [ImageStreamCompleter], and begins fetching the /// image. /// @@ -776,25 +734,7 @@ abstract class AssetBundleImageProvider extends ImageProvider [ - DiagnosticsProperty('Image provider', this), - DiagnosticsProperty('Image key', key), - ]; - return true; - }()); - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeDeprecated: decode), + codec: _loadAsync(key, decode: decode), scale: key.scale, debugLabel: key.name, informationCollector: collector, @@ -804,48 +744,22 @@ abstract class AssetBundleImageProvider extends ImageProvider _loadAsync( AssetBundleImageKey key, { - ImageDecoderCallback? decode, - DecoderBufferCallback? decodeBufferDeprecated, - DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { - if (decode != null) { - ui.ImmutableBuffer buffer; - // Hot reload/restart could change whether an asset bundle or key in a - // bundle are available, or if it is a network backed bundle. - try { - buffer = await key.bundle.loadBuffer(key.name); - } on FlutterError { - PaintingBinding.instance.imageCache.evict(key); - rethrow; - } - return decode(buffer); - } - if (decodeBufferDeprecated != null) { - ui.ImmutableBuffer buffer; - // Hot reload/restart could change whether an asset bundle or key in a - // bundle are available, or if it is a network backed bundle. - try { - buffer = await key.bundle.loadBuffer(key.name); - } on FlutterError { - PaintingBinding.instance.imageCache.evict(key); - rethrow; - } - return decodeBufferDeprecated(buffer); - } - ByteData data; + final ui.ImmutableBuffer buffer; // Hot reload/restart could change whether an asset bundle or key in a // bundle are available, or if it is a network backed bundle. try { - data = await key.bundle.load(key.name); + buffer = await key.bundle.loadBuffer(key.name); } on FlutterError { PaintingBinding.instance.imageCache.evict(key); rethrow; } - return decodeDeprecated!(data.buffer.asUint8List()); + return decode(buffer); } } @@ -1337,28 +1251,6 @@ class ResizeImage extends ImageProvider { return provider; } - @override - @Deprecated( - 'Implement loadImage for faster image loading. ' - 'This feature was deprecated after v2.13.0-1.0.pre.', - ) - ImageStreamCompleter load(ResizeImageKey key, DecoderCallback decode) { - Future decodeResize(Uint8List buffer, {int? cacheWidth, int? cacheHeight, bool? allowUpscaling}) { - assert( - cacheWidth == null && cacheHeight == null && allowUpscaling == null, - 'ResizeImage cannot be composed with another ImageProvider that applies ' - 'cacheWidth, cacheHeight, or allowUpscaling.', - ); - return decode(buffer, cacheWidth: width, cacheHeight: height, allowUpscaling: this.allowUpscaling); - } - final ImageStreamCompleter completer = imageProvider.load(key._providerCacheKey, decodeResize); - if (!kReleaseMode) { - completer.debugLabel = '${completer.debugLabel} - Resized(${key._width}×${key._height})'; - } - _configureErrorListener(completer, key); - return completer; - } - @override @Deprecated( 'Implement loadImage for image loading. ' @@ -1494,11 +1386,11 @@ class ResizeImage extends ImageProvider { /// /// The image will be cached regardless of cache headers from the server. /// -/// When a network image is used on the Web platform, the `cacheWidth` and -/// `cacheHeight` parameters of the [DecoderCallback] are only supported when the -/// application is running with the CanvasKit renderer. When the application is using -/// the HTML renderer, the web engine delegates image decoding of network images to the Web, -/// which does not support custom decode sizes. +/// When a network image is used on the Web platform, the `getTargetSize` +/// parameter of the [ImageDecoderCallback] is only supported when the +/// application is running with the CanvasKit renderer. When the application is +/// using the HTML renderer, the web engine delegates image decoding of network +/// images to the Web, which does not support custom decode sizes. /// /// See also: /// @@ -1525,9 +1417,6 @@ abstract class NetworkImage extends ImageProvider { /// When running Flutter on the web, headers are not used. Map? get headers; - @override - ImageStreamCompleter load(NetworkImage key, DecoderCallback decode); - @override ImageStreamCompleter loadBuffer(NetworkImage key, DecoderBufferCallback decode); @@ -1562,22 +1451,10 @@ class FileImage extends ImageProvider { return SynchronousFuture(this); } - @override - ImageStreamCompleter load(FileImage key, DecoderCallback decode) { - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeDeprecated: decode), - scale: key.scale, - debugLabel: key.file.path, - informationCollector: () => [ - ErrorDescription('Path: ${file.path}'), - ], - ); - } - @override ImageStreamCompleter loadBuffer(FileImage key, DecoderBufferCallback decode) { return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeBufferDeprecated: decode), + codec: _loadAsync(key, decode: decode), scale: key.scale, debugLabel: key.file.path, informationCollector: () => [ @@ -1601,12 +1478,9 @@ class FileImage extends ImageProvider { Future _loadAsync( FileImage key, { - ImageDecoderCallback? decode, - DecoderBufferCallback? decodeBufferDeprecated, - DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { assert(key == this); - // TODO(jonahwilliams): making this sync caused test failures that seem to // indicate that we can fail to call evict unless at least one await has // occurred in the test. @@ -1617,19 +1491,9 @@ class FileImage extends ImageProvider { PaintingBinding.instance.imageCache.evict(key); throw StateError('$file is empty and cannot be loaded as an image.'); } - if (decode != null) { - if (file.runtimeType == File) { - return decode(await ui.ImmutableBuffer.fromFilePath(file.path)); - } - return decode(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); - } - if (decodeBufferDeprecated != null) { - if (file.runtimeType == File) { - return decodeBufferDeprecated(await ui.ImmutableBuffer.fromFilePath(file.path)); - } - return decodeBufferDeprecated(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); - } - return decodeDeprecated!(await file.readAsBytes()); + return (file.runtimeType == File) + ? decode(await ui.ImmutableBuffer.fromFilePath(file.path)) + : decode(await ui.ImmutableBuffer.fromUint8List(await file.readAsBytes())); } @override @@ -1655,8 +1519,8 @@ class FileImage extends ImageProvider { /// The provided [bytes] buffer should not be changed after it is provided /// to a [MemoryImage]. To provide an [ImageStream] that represents an image /// that changes over time, consider creating a new subclass of [ImageProvider] -/// whose [load] method returns a subclass of [ImageStreamCompleter] that can -/// handle providing multiple images. +/// whose [loadImage] method returns a subclass of [ImageStreamCompleter] that +/// can handle providing multiple images. /// /// See also: /// @@ -1675,7 +1539,7 @@ class MemoryImage extends ImageProvider { /// /// See also: /// - /// * [PaintingBinding.instantiateImageCodec] + /// * [PaintingBinding.instantiateImageCodecWithSize] final Uint8List bytes; /// The scale to place in the [ImageInfo] object of the image. @@ -1691,19 +1555,11 @@ class MemoryImage extends ImageProvider { return SynchronousFuture(this); } - @override - ImageStreamCompleter load(MemoryImage key, DecoderCallback decode) { - return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeDeprecated: decode), - scale: key.scale, - debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})', - ); - } - @override ImageStreamCompleter loadBuffer(MemoryImage key, DecoderBufferCallback decode) { + assert(key == this); return MultiFrameImageStreamCompleter( - codec: _loadAsync(key, decodeBufferDeprecated: decode), + codec: _loadAsync(key, decode: decode), scale: key.scale, debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})', ); @@ -1720,20 +1576,10 @@ class MemoryImage extends ImageProvider { Future _loadAsync( MemoryImage key, { - ImageDecoderCallback? decode, - DecoderBufferCallback? decodeBufferDeprecated, - DecoderCallback? decodeDeprecated, + required _SimpleDecoderCallback decode, }) async { assert(key == this); - if (decode != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decode(buffer); - } - if (decodeBufferDeprecated != null) { - final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromUint8List(bytes); - return decodeBufferDeprecated(buffer); - } - return decodeDeprecated!(bytes); + return decode(await ui.ImmutableBuffer.fromUint8List(bytes)); } @override diff --git a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart index 4009be91ed2ad..f408d8835be66 100644 --- a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart +++ b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart @@ -63,7 +63,7 @@ class ScrollAwareImageProvider extends ImageProvider { /// been resolved. final DisposableBuildContext context; - /// The wrapped image provider to delegate [obtainKey] and [load] to. + /// The wrapped image provider to delegate [obtainKey] and [loadImage] to. final ImageProvider imageProvider; @override @@ -105,9 +105,6 @@ class ScrollAwareImageProvider extends ImageProvider { imageProvider.resolveStreamForKey(configuration, stream, key, handleError); } - @override - ImageStreamCompleter load(T key, DecoderCallback decode) => imageProvider.load(key, decode); - @override ImageStreamCompleter loadBuffer(T key, DecoderBufferCallback decode) => imageProvider.loadBuffer(key, decode); diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 9fbf97f7ac878..0959ad2d2fd43 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -3556,7 +3556,7 @@ class DelayedImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(DelayedImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(DelayedImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter(_completer.future); } @@ -3592,7 +3592,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } diff --git a/packages/flutter/test/painting/decoration_test.dart b/packages/flutter/test/painting/decoration_test.dart index 8750ba5e4862d..6cfa461d82d67 100644 --- a/packages/flutter/test/painting/decoration_test.dart +++ b/packages/flutter/test/painting/decoration_test.dart @@ -34,7 +34,7 @@ class SynchronousTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(TestImageInfo(key, image: image)), ); @@ -52,7 +52,7 @@ class SynchronousErrorTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { throw throwable; } } @@ -68,7 +68,7 @@ class AsyncTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( Future.value(TestImageInfo(key, image: image)), ); @@ -88,7 +88,7 @@ class DelayedImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(DelayedImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(DelayedImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter(_completer.future); } @@ -111,7 +111,7 @@ class MultiFrameImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(MultiFrameImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(MultiFrameImageProvider key, ImageDecoderCallback decode) { return completer; } diff --git a/packages/flutter/test/painting/fake_image_provider.dart b/packages/flutter/test/painting/fake_image_provider.dart index c352adaaab2df..a59f54670b58f 100644 --- a/packages/flutter/test/painting/fake_image_provider.dart +++ b/packages/flutter/test/painting/fake_image_provider.dart @@ -25,7 +25,7 @@ class FakeImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(FakeImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(FakeImageProvider key, ImageDecoderCallback decode) { assert(key == this); return MultiFrameImageStreamCompleter( codec: SynchronousFuture(_codec), diff --git a/packages/flutter/test/painting/image_test_utils.dart b/packages/flutter/test/painting/image_test_utils.dart index 847984663e269..4b137c3f349a6 100644 --- a/packages/flutter/test/painting/image_test_utils.dart +++ b/packages/flutter/test/painting/image_test_utils.dart @@ -28,11 +28,6 @@ class TestImageProvider extends ImageProvider { super.resolveStreamForKey(config, stream, key, handleError); } - @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { - throw UnsupportedError('Use ImageProvider.loadImage instead.'); - } - @override ImageStreamCompleter loadBuffer(TestImageProvider key, DecoderBufferCallback decode) { throw UnsupportedError('Use ImageProvider.loadImage instead.'); diff --git a/packages/flutter/test/painting/mocks_for_image_cache.dart b/packages/flutter/test/painting/mocks_for_image_cache.dart index 1273faa4c5e81..bc80315747f76 100644 --- a/packages/flutter/test/painting/mocks_for_image_cache.dart +++ b/packages/flutter/test/painting/mocks_for_image_cache.dart @@ -54,7 +54,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(TestImageInfo(imageValue, image: image.clone())), ); @@ -68,7 +68,7 @@ class FailingTestImageProvider extends TestImageProvider { const FailingTestImageProvider(super.key, super.imageValue, { required super.image }); @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter(Future.sync(() => Future.error('loading failed!'))); } } @@ -95,11 +95,6 @@ class ErrorImageProvider extends ImageProvider { throw Error(); } - @override - ImageStreamCompleter load(ErrorImageProvider key, DecoderCallback decode) { - throw Error(); - } - @override Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); @@ -121,11 +116,6 @@ class ObtainKeyErrorImageProvider extends ImageProvider obtainKey(ImageConfiguration configuration) { throw Error(); } - - @override - ImageStreamCompleter load(ObtainKeyErrorImageProvider key, DecoderCallback decode) { - throw UnimplementedError(); - } } class LoadErrorImageProvider extends ImageProvider { @@ -143,16 +133,11 @@ class LoadErrorImageProvider extends ImageProvider { Future obtainKey(ImageConfiguration configuration) { return SynchronousFuture(this); } - - @override - ImageStreamCompleter load(LoadErrorImageProvider key, DecoderCallback decode) { - throw UnimplementedError(); - } } class LoadErrorCompleterImageProvider extends ImageProvider { @override - ImageStreamCompleter load(LoadErrorCompleterImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(LoadErrorCompleterImageProvider key, ImageDecoderCallback decode) { final Completer completer = Completer.sync(); completer.completeError(Error()); return OneFrameImageStreamCompleter(completer.future); diff --git a/packages/flutter/test/painting/painting_utils.dart b/packages/flutter/test/painting/painting_utils.dart index b7edc0da1227a..7d669fa1e3672 100644 --- a/packages/flutter/test/painting/painting_utils.dart +++ b/packages/flutter/test/painting/painting_utils.dart @@ -14,9 +14,9 @@ class PaintingBindingSpy extends BindingBase with SchedulerBinding, ServicesBind int get instantiateImageCodecCalledCount => counter; @override - Future instantiateImageCodec(Uint8List list, {int? cacheWidth, int? cacheHeight, bool allowUpscaling = false}) { + Future instantiateImageCodecWithSize(ui.ImmutableBuffer buffer, { ui.TargetImageSizeCallback? getTargetSize }) { counter++; - return ui.instantiateImageCodec(list); + return ui.instantiateImageCodecWithSize(buffer, getTargetSize: getTargetSize); } @override diff --git a/packages/flutter/test/painting/shape_decoration_test.dart b/packages/flutter/test/painting/shape_decoration_test.dart index 8a193a5faafff..269fb9e416b16 100644 --- a/packages/flutter/test/painting/shape_decoration_test.dart +++ b/packages/flutter/test/painting/shape_decoration_test.dart @@ -156,7 +156,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index 42f36c0657e3e..031006439d7f2 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -25,7 +25,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( future.then((void value) => ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index a10a77bd2498c..e88c6ca6e5084 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -58,7 +58,7 @@ class LoadTestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { throw UnimplementedError(); } } diff --git a/packages/flutter/test/widgets/image_filter_quality_test.dart b/packages/flutter/test/widgets/image_filter_quality_test.dart index d8b1ee367b0f8..dcbeadfd438da 100644 --- a/packages/flutter/test/widgets/image_filter_quality_test.dart +++ b/packages/flutter/test/widgets/image_filter_quality_test.dart @@ -137,7 +137,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 2fb1aa68771db..6f2c075a00e0f 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -19,7 +19,7 @@ class TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(TestImageProvider key, DecoderCallback decode) { + ImageStreamCompleter loadImage(TestImageProvider key, ImageDecoderCallback decode) { return OneFrameImageStreamCompleter( SynchronousFuture(ImageInfo(image: image)), ); diff --git a/packages/flutter/test/widgets/image_test.dart b/packages/flutter/test/widgets/image_test.dart index 2eb4b80b6437e..cbabca138f9b4 100644 --- a/packages/flutter/test/widgets/image_test.dart +++ b/packages/flutter/test/widgets/image_test.dart @@ -2083,7 +2083,7 @@ class _TestImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(Object key, DecoderCallback decode) { + ImageStreamCompleter loadImage(Object key, ImageDecoderCallback decode) { _loadCallCount += 1; return _streamCompleter; } @@ -2198,7 +2198,7 @@ class _FailingImageProvider extends ImageProvider { } @override - ImageStreamCompleter load(int key, DecoderCallback decode) { + ImageStreamCompleter loadImage(int key, ImageDecoderCallback decode) { if (failOnLoad) { throw throws; } From 15048a6b044b5866ba94c40ac5f456aa84dc7c3d Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Wed, 30 Aug 2023 11:51:04 -0700 Subject: [PATCH 0983/1547] Update the infrastructure issue template (#133519) *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .github/ISSUE_TEMPLATE/6_infrastructure.md | 22 ------ .github/ISSUE_TEMPLATE/6_infrastructure.yml | 75 +++++++++++++++++++++ 2 files changed, 75 insertions(+), 22 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/6_infrastructure.md create mode 100644 .github/ISSUE_TEMPLATE/6_infrastructure.yml diff --git a/.github/ISSUE_TEMPLATE/6_infrastructure.md b/.github/ISSUE_TEMPLATE/6_infrastructure.md deleted file mode 100644 index d12e41ae11aac..0000000000000 --- a/.github/ISSUE_TEMPLATE/6_infrastructure.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: The CI infrastructure used by Flutter has a problem -about: As a contributor, you want to file an issue about the build/test/release - infra, e.g. dashboards (http://flutter-dashboard.appspot.com), devicelab, - LUCI (https://ci.chromium.org/p/flutter) etc. -title: '' -labels: 'team: infra' -assignees: '' - ---- - - diff --git a/.github/ISSUE_TEMPLATE/6_infrastructure.yml b/.github/ISSUE_TEMPLATE/6_infrastructure.yml new file mode 100644 index 0000000000000..a6cfc9fc71eef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/6_infrastructure.yml @@ -0,0 +1,75 @@ +name: The CI infrastructure used by Flutter has a problem +description: | + As a contributor, you want to file an issue about the build/test/release + infra, e.g. dashboards (http://flutter-dashboard.appspot.com), devicelab, + LUCI (https://ci.chromium.org/p/flutter) etc. +labels: ['team-infra'] +body: + - type: markdown + attributes: + value: | + Thank you for using Flutter! + + It looks like you found an issue with our Infrastructure services. + Please complete the form below so that we can help to resolve your + issue as quickly as possible. + - type: checkboxes + attributes: + label: Is there an existing issue for this? + options: + - label: I have searched the [existing infra issues](https://github.com/flutter/flutter/issues?q=is%3Aopen+is%3Aissue+label%3Ateam-infra) + required: true + - type: dropdown + attributes: + label: Type of Request + description: | + Is this a bug, feature request or Infra Task? + + If you have a bug and you believe the issue is a blocker please add the P0 label and + set the project to 'Infra Ticket Queue.' + + If this is a devicelab feature such as a package update or a device is down please + add the 'device-lab' label to the created issue and set the project to 'Infra Ticket Queue.' + options: + - bug + - feature request + - infra task + default: 0 + validations: + required: true + - type: textarea + id: env + attributes: + label: Infrastructure Environment + description: | + Which part of the infrastructure is this issue occurring? Or, if this is a feature + request, where should the feature be implemented? + value: LUCI, Github, Cocoon scheduler, Autosubmit, etc... + validations: + required: true + - type: textarea + id: affects + attributes: + label: What is happening? + description: | + If this is an issue please describe what is happening? If this is a feature request, + please describe the use case and provide a proposal of the feature. + + Please include links to build pages, etc. + value: Please be descriptive. + validations: + required: true + - type: textarea + attributes: + label: Steps to reproduce + description: If you have a bug please include steps to reproduce the issue. + value: | + Step 1: + Step 2: + .. + Step n: + - type: textarea + attributes: + label: Expected results + description: If you have a bug, What should the expect output be? + value: I expect to see X when Y is finished. From b23105276f65f4686a29d29255de86a7527cee72 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Wed, 30 Aug 2023 21:02:06 +0200 Subject: [PATCH 0984/1547] Expose barrierDismissible in PageRoute constructor (#133659) ## Description This PR exposes `barrierDismissible` in `PageRoute`, `MaterialPageRoute` and `CupertinoPageRoute` constructors. Setting this property to true will enable the escape key binding. ## Related Issue Fixes https://github.com/flutter/flutter/issues/132138. ## Tests Adds one test. --- packages/flutter/lib/src/cupertino/route.dart | 4 ++ packages/flutter/lib/src/material/page.dart | 4 ++ packages/flutter/lib/src/widgets/pages.dart | 9 ++++- packages/flutter/test/material/page_test.dart | 40 +++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index 211578214871d..c53efc7e87eaf 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -311,6 +311,9 @@ mixin CupertinoRouteTransitionMixin on PageRoute { /// the route is popped from the stack via [Navigator.pop] when an optional /// `result` can be provided. /// +/// If `barrierDismissible` is true, then pressing the escape key on the keyboard +/// will cause the current route to be popped with null as the value. +/// /// See also: /// /// * [CupertinoRouteTransitionMixin], for a mixin that provides iOS transition @@ -334,6 +337,7 @@ class CupertinoPageRoute extends PageRoute with CupertinoRouteTransitionMi this.maintainState = true, super.fullscreenDialog, super.allowSnapshotting = true, + super.barrierDismissible = false, }) { assert(opaque); } diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index 73d677ff4cd78..0c1be0c83a2dc 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -20,6 +20,9 @@ import 'theme.dart'; /// fullscreen modal dialog. On iOS, those routes animate from the bottom to the /// top rather than horizontally. /// +/// If `barrierDismissible` is true, then pressing the escape key on the keyboard +/// will cause the current route to be popped with null as the value. +/// /// The type `T` specifies the return type of the route which can be supplied as /// the route is popped from the stack via [Navigator.pop] by providing the /// optional `result` argument. @@ -40,6 +43,7 @@ class MaterialPageRoute extends PageRoute with MaterialRouteTransitionMixi this.maintainState = true, super.fullscreenDialog, super.allowSnapshotting = true, + super.barrierDismissible = false, }) { assert(opaque); } diff --git a/packages/flutter/lib/src/widgets/pages.dart b/packages/flutter/lib/src/widgets/pages.dart index de3ff66f94391..989beb1f4283b 100644 --- a/packages/flutter/lib/src/widgets/pages.dart +++ b/packages/flutter/lib/src/widgets/pages.dart @@ -11,6 +11,9 @@ import 'routes.dart'; /// The [PageRouteBuilder] subclass provides a way to create a [PageRoute] using /// callbacks rather than by defining a new class via subclassing. /// +/// If `barrierDismissible` is true, then pressing the escape key on the keyboard +/// will cause the current route to be popped with null as the value. +/// /// See also: /// /// * [Route], which documents the meaning of the `T` generic type argument. @@ -20,7 +23,8 @@ abstract class PageRoute extends ModalRoute { super.settings, this.fullscreenDialog = false, this.allowSnapshotting = true, - }); + bool barrierDismissible = false, + }) : _barrierDismissible = barrierDismissible; /// {@template flutter.widgets.PageRoute.fullscreenDialog} /// Whether this page route is a full-screen dialog. @@ -39,7 +43,8 @@ abstract class PageRoute extends ModalRoute { bool get opaque => true; @override - bool get barrierDismissible => false; + bool get barrierDismissible => _barrierDismissible; + final bool _barrierDismissible; @override bool canTransitionTo(TransitionRoute nextRoute) => nextRoute is PageRoute; diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index 6f6728af70eff..d353803e779e6 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/cupertino.dart' show CupertinoPageRoute; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -1229,6 +1230,45 @@ void main() { expect(find.text('p1'), findsOneWidget); expect(find.text('count: 1'), findsOneWidget); }); + + testWidgets('MaterialPageRoute can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132138. + final GlobalKey scaffoldKey = GlobalKey(); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + key: scaffoldKey, + body: Center( + child: ElevatedButton( + onPressed: () { + Navigator.push(scaffoldKey.currentContext!, MaterialPageRoute( + builder: (BuildContext context) { + return const Scaffold( + body: Center(child: Text('route')), + ); + }, + barrierDismissible: true, + )); + }, + child: const Text('push'), + ), + ), + ), + ), + ); + + await tester.tap(find.text('push')); + await tester.pumpAndSettle(); + expect(find.text('route'), findsOneWidget); + expect(find.text('push'), findsNothing); + + // Try to dismiss the route with the escape key. + await tester.sendKeyEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(); + + expect(find.text('route'), findsNothing); + }); } class TransitionDetector extends DefaultTransitionDelegate { From d1410a11b6f071bce5b0d02807488e5141f6895b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 15:41:23 -0400 Subject: [PATCH 0985/1547] Roll Flutter Engine from 69f04bdfe952 to 31d5662dcb53 (14 revisions) (#133683) https://github.com/flutter/engine/compare/69f04bdfe952...31d5662dcb53 2023-08-30 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from Y2xfuZM0ec5GQfHV8... to gWpPuUyuR_hmz9Xmg... (flutter/engine#45287) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 7a246c9eb086 to 185fbe1a264d (3 revisions) (flutter/engine#45289) 2023-08-30 30870216+gaaclarke@users.noreply.github.com Revert "Roll Dart SDK from 0cea73a8d3c3 to 96d3a79547fc" (flutter/engine#45285) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 3489b6d1d613 to 7a246c9eb086 (4 revisions) (flutter/engine#45286) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from a58ccf8ae398 to 3489b6d1d613 (2 revisions) (flutter/engine#45283) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 6f4fd97d2f7e to a58ccf8ae398 (1 revision) (flutter/engine#45280) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from a2728a7ad2a3 to 6f4fd97d2f7e (2 revisions) (flutter/engine#45278) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 7492e29ad235 to a2728a7ad2a3 (1 revision) (flutter/engine#45273) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 80f4d2f303d0 to 7492e29ad235 (1 revision) (flutter/engine#45272) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 03289b20b5d3 to 80f4d2f303d0 (1 revision) (flutter/engine#45270) 2023-08-30 skia-flutter-autoroll@skia.org Roll Dart SDK from 96d3a79547fc to 4352efd8497d (1 revision) (flutter/engine#45267) 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from fde9fe141863 to 03289b20b5d3 (1 revision) (flutter/engine#45268) 2023-08-30 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from QKekosWnIY_ObKstn... to Y2xfuZM0ec5GQfHV8... (flutter/engine#45265) 2023-08-30 skia-flutter-autoroll@skia.org Roll Dart SDK from 0cea73a8d3c3 to 96d3a79547fc (1 revision) (flutter/engine#45262) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from QKekosWnIY_O to gWpPuUyuR_hm If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1dbf7e027f6d6..0811d6bb63b16 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -69f04bdfe952b2f98f4cb2e02823f6e79a0dc7b4 +31d5662dcb530e00f27b00fc605c2ca2f8f72b1c diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 3d30f2e975f5b..933a7b94539f3 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -QKekosWnIY_ObKstnfItjOWSgi14RL_O43p2q4KSarUC +gWpPuUyuR_hmz9XmgcrDgQq664PRigdV2BgG77idOv4C From 4b89fce108ac6350b4e73a436f98ba3c3b7d6a74 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Wed, 30 Aug 2023 12:49:56 -0700 Subject: [PATCH 0986/1547] Fixing memory leak in EditableTextState (#131377) --- packages/flutter/lib/src/widgets/editable_text.dart | 5 ++++- .../test/material/text_selection_theme_test.dart | 13 +------------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 246b9b7d71d2c..4136c2e7a5cae 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2125,6 +2125,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien late final Simulation _iosBlinkCursorSimulation = _DiscreteKeyFrameSimulation.iOSBlinkingCaret(); final ValueNotifier _cursorVisibilityNotifier = ValueNotifier(true); + late final ValueNotifier _debugCursorNotifier; final GlobalKey _editableKey = GlobalKey(); /// Detects whether the clipboard can paste. @@ -2789,6 +2790,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien _scrollController.addListener(_onEditableScroll); _cursorVisibilityNotifier.value = widget.showCursor; _spellCheckConfiguration = _inferSpellCheckConfiguration(widget.spellCheckConfiguration); + _debugCursorNotifier = ValueNotifier(widget.showCursor); } // Whether `TickerMode.of(context)` is true and animations (like blinking the @@ -2933,6 +2935,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void dispose() { + _debugCursorNotifier.dispose(); _internalScrollController?.dispose(); _currentAutofillScope?.unregister(autofillId); widget.controller.removeListener(_didChangeTextEditingValue); @@ -4853,7 +4856,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien cursorColor: _cursorColor, backgroundCursorColor: widget.backgroundCursorColor, showCursor: EditableText.debugDeterministicCursor - ? ValueNotifier(widget.showCursor) + ? _debugCursorNotifier : _cursorVisibilityNotifier, forceLine: widget.forceLine, readOnly: widget.readOnly, diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 4a990a5a0a5d0..2e628c562077c 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -167,18 +167,7 @@ void main() { await tester.pumpAndSettle(); final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); - }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130469 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: { - 'ValueNotifier': 1, - 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, - }, - ), - ); + }); testWidgets('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { const TextSelectionThemeData textSelectionTheme = TextSelectionThemeData( From 2f2a10d5400c135c53049e53b2c6aab99f752be3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 17:06:25 -0400 Subject: [PATCH 0987/1547] Roll Flutter Engine from 31d5662dcb53 to b63eee2e31cc (1 revision) (#133692) https://github.com/flutter/engine/compare/31d5662dcb53...b63eee2e31cc 2023-08-30 jason-simmons@users.noreply.github.com [Impeller] Reorganize the glyph atlas to improve efficiency when looking up runs of glyphs in the same font (flutter/engine#45191) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0811d6bb63b16..b7965ce5f3b4f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -31d5662dcb530e00f27b00fc605c2ca2f8f72b1c +b63eee2e31cc3739bf89d193fde6fa6f66fba04a From 1e770c3808e7a74fbef17a68f3dbd515f1d3c2a2 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 31 Aug 2023 00:16:13 +0300 Subject: [PATCH 0988/1547] Add `cancelButtonStyle` & `confirmButtonStyle` to the `DatePickerThemeData` (#132847) fixes [Unable to adjust the color for "Cancel" and "Ok" button in datePicker dialog](https://github.com/flutter/flutter/issues/127739) ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, datePickerTheme: DatePickerThemeData( cancelButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), side: BorderSide(color: Colors.red), ), backgroundColor: Colors.white, foregroundColor: Colors.red, elevation: 3, shadowColor: Colors.red, ), confirmButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), ), backgroundColor: Colors.green[700], foregroundColor: Colors.white, elevation: 3, shadowColor: Colors.green[700], ), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: DatePickerDialog( initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), ), ), ); } } ```
    ### Before Not possible to customize action buttons from the `DatePickerThemeData`. ### After ![Screenshot 2023-08-18 at 16 42 00](https://github.com/flutter/flutter/assets/48603081/4ec01e93-c661-491d-9253-d687da8b76f3) --- .../lib/date_picker_template.dart | 12 ++++- .../flutter/lib/src/material/date_picker.dart | 2 + .../lib/src/material/date_picker_theme.dart | 46 +++++++++++++++++-- .../test/material/date_picker_theme_test.dart | 37 ++++++++++++--- 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/dev/tools/gen_defaults/lib/date_picker_template.dart b/dev/tools/gen_defaults/lib/date_picker_template.dart index 6f45fdf35f67b..e1c8836dee8f4 100644 --- a/dev/tools/gen_defaults/lib/date_picker_template.dart +++ b/dev/tools/gen_defaults/lib/date_picker_template.dart @@ -56,6 +56,16 @@ class _${blockName}DefaultsM3 extends DatePickerThemeData { @override Color? get backgroundColor => ${componentColor("md.comp.date-picker.modal.container")}; + @override + ButtonStyle get cancelButtonStyle { + return TextButton.styleFrom(); + } + + @override + ButtonStyle get confirmButtonStyle { + return TextButton.styleFrom(); + } + @override Color? get shadowColor => ${colorOrTransparent("md.comp.date-picker.modal.container.shadow-color")}; @@ -231,8 +241,6 @@ class _${blockName}DefaultsM3 extends DatePickerThemeData { @override TextStyle? get rangePickerHeaderHelpStyle => ${textStyle("md.comp.date-picker.modal.range-selection.month.subhead")}; - - } '''; } diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 6b495fa88ba00..88614ec1bdfad 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -543,6 +543,7 @@ class _DatePickerDialogState extends State with RestorationMix spacing: 8, children: [ TextButton( + style: datePickerTheme.cancelButtonStyle ?? defaults.cancelButtonStyle, onPressed: _handleCancel, child: Text(widget.cancelText ?? ( useMaterial3 @@ -551,6 +552,7 @@ class _DatePickerDialogState extends State with RestorationMix )), ), TextButton( + style: datePickerTheme.confirmButtonStyle ?? defaults.confirmButtonStyle, onPressed: _handleOk, child: Text(widget.confirmText ?? localizations.okButtonLabel), ), diff --git a/packages/flutter/lib/src/material/date_picker_theme.dart b/packages/flutter/lib/src/material/date_picker_theme.dart index a970ffbd5dbd2..21ffc60ca57dc 100644 --- a/packages/flutter/lib/src/material/date_picker_theme.dart +++ b/packages/flutter/lib/src/material/date_picker_theme.dart @@ -7,10 +7,12 @@ import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'button_style.dart'; import 'color_scheme.dart'; import 'colors.dart'; import 'input_decorator.dart'; import 'material_state.dart'; +import 'text_button.dart'; import 'text_theme.dart'; import 'theme.dart'; @@ -70,6 +72,8 @@ class DatePickerThemeData with Diagnosticable { this.rangeSelectionOverlayColor, this.dividerColor, this.inputDecorationTheme, + this.cancelButtonStyle, + this.confirmButtonStyle, }); /// Overrides the default value of [Dialog.backgroundColor]. @@ -294,6 +298,12 @@ class DatePickerThemeData with Diagnosticable { /// If this is null, [ThemeData.inputDecorationTheme] is used instead. final InputDecorationTheme? inputDecorationTheme; + /// Overrides the default style of the cancel button of a [DatePickerDialog]. + final ButtonStyle? cancelButtonStyle; + + /// Overrrides the default style of the confirm (OK) button of a [DatePickerDialog]. + final ButtonStyle? confirmButtonStyle; + /// Creates a copy of this object with the given fields replaced with the /// new values. DatePickerThemeData copyWith({ @@ -331,6 +341,8 @@ class DatePickerThemeData with Diagnosticable { MaterialStateProperty? rangeSelectionOverlayColor, Color? dividerColor, InputDecorationTheme? inputDecorationTheme, + ButtonStyle? cancelButtonStyle, + ButtonStyle? confirmButtonStyle, }) { return DatePickerThemeData( backgroundColor: backgroundColor ?? this.backgroundColor, @@ -367,6 +379,8 @@ class DatePickerThemeData with Diagnosticable { rangeSelectionOverlayColor: rangeSelectionOverlayColor ?? this.rangeSelectionOverlayColor, dividerColor: dividerColor ?? this.dividerColor, inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme, + cancelButtonStyle: cancelButtonStyle ?? this.cancelButtonStyle, + confirmButtonStyle: confirmButtonStyle ?? this.confirmButtonStyle, ); } @@ -410,6 +424,8 @@ class DatePickerThemeData with Diagnosticable { rangeSelectionOverlayColor: MaterialStateProperty.lerp(a?.rangeSelectionOverlayColor, b?.rangeSelectionOverlayColor, t, Color.lerp), dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t), inputDecorationTheme: t < 0.5 ? a?.inputDecorationTheme : b?.inputDecorationTheme, + cancelButtonStyle: ButtonStyle.lerp(a?.cancelButtonStyle, b?.cancelButtonStyle, t), + confirmButtonStyle: ButtonStyle.lerp(a?.confirmButtonStyle, b?.confirmButtonStyle, t), ); } @@ -459,6 +475,8 @@ class DatePickerThemeData with Diagnosticable { rangeSelectionOverlayColor, dividerColor, inputDecorationTheme, + cancelButtonStyle, + confirmButtonStyle, ]); @override @@ -500,7 +518,9 @@ class DatePickerThemeData with Diagnosticable { && other.rangeSelectionBackgroundColor == rangeSelectionBackgroundColor && other.rangeSelectionOverlayColor == rangeSelectionOverlayColor && other.dividerColor == dividerColor - && other.inputDecorationTheme == inputDecorationTheme; + && other.inputDecorationTheme == inputDecorationTheme + && other.cancelButtonStyle == cancelButtonStyle + && other.confirmButtonStyle == confirmButtonStyle; } @override @@ -540,6 +560,8 @@ class DatePickerThemeData with Diagnosticable { properties.add(DiagnosticsProperty>('rangeSelectionOverlayColor', rangeSelectionOverlayColor, defaultValue: null)); properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null)); properties.add(DiagnosticsProperty('inputDecorationTheme', inputDecorationTheme, defaultValue: null)); + properties.add(DiagnosticsProperty('cancelButtonStyle', cancelButtonStyle, defaultValue: null)); + properties.add(DiagnosticsProperty('confirmButtonStyle', confirmButtonStyle, defaultValue: null)); } } @@ -658,6 +680,16 @@ class _DatePickerDefaultsM2 extends DatePickerThemeData { @override Color? get headerBackgroundColor => _isDark ? _colors.surface : _colors.primary; + @override + ButtonStyle get cancelButtonStyle { + return TextButton.styleFrom(); + } + + @override + ButtonStyle get confirmButtonStyle { + return TextButton.styleFrom(); + } + @override Color? get headerForegroundColor => _isDark ? _colors.onSurface : _colors.onPrimary; @@ -818,6 +850,16 @@ class _DatePickerDefaultsM3 extends DatePickerThemeData { @override Color? get backgroundColor => _colors.surface; + @override + ButtonStyle get cancelButtonStyle { + return TextButton.styleFrom(); + } + + @override + ButtonStyle get confirmButtonStyle { + return TextButton.styleFrom(); + } + @override Color? get shadowColor => Colors.transparent; @@ -993,8 +1035,6 @@ class _DatePickerDefaultsM3 extends DatePickerThemeData { @override TextStyle? get rangePickerHeaderHelpStyle => _textTheme.titleSmall; - - } // END GENERATED TOKEN PROPERTIES - DatePicker diff --git a/packages/flutter/test/material/date_picker_theme_test.dart b/packages/flutter/test/material/date_picker_theme_test.dart index 4eaaff12d5899..58bb87aed2b9f 100644 --- a/packages/flutter/test/material/date_picker_theme_test.dart +++ b/packages/flutter/test/material/date_picker_theme_test.dart @@ -46,7 +46,9 @@ void main() { inputDecorationTheme: InputDecorationTheme( fillColor: Color(0xffffff5f), border: UnderlineInputBorder(), - ) + ), + cancelButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll(Color(0xffffff6f))), + confirmButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll(Color(0xffffff7f))), ); Material findDialogMaterial(WidgetTester tester) { @@ -77,6 +79,10 @@ void main() { return container.decoration as BoxDecoration?; } + ButtonStyle actionButtonStyle(WidgetTester tester, String text) { + return tester.widget(find.widgetWithText(TextButton, text)).style!; + } + const Size wideWindowSize = Size(1920.0, 1080.0); const Size narrowWindowSize = Size(1070.0, 1770.0); @@ -126,6 +132,8 @@ void main() { expect(theme.rangeSelectionOverlayColor, null); expect(theme.dividerColor, null); expect(theme.inputDecorationTheme, null); + expect(theme.cancelButtonStyle, null); + expect(theme.confirmButtonStyle, null); }); testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async { @@ -201,6 +209,8 @@ void main() { expect(m3.rangePickerHeaderHelpStyle, textTheme.titleSmall); expect(m3.dividerColor, null); expect(m3.inputDecorationTheme, null); + expect(m3.cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); + expect(m3.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async { @@ -268,6 +278,8 @@ void main() { expect(m2.rangePickerHeaderHelpStyle, textTheme.labelSmall); expect(m2.dividerColor, null); expect(m2.inputDecorationTheme, null); + expect(m2.cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); + expect(m2.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async { @@ -292,9 +304,7 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect( - description, - equalsIgnoringHashCodes([ + expect(description, equalsIgnoringHashCodes([ 'backgroundColor: Color(0xfffffff0)', 'elevation: 6.0', 'shadowColor: Color(0xfffffff1)', @@ -328,9 +338,10 @@ void main() { 'rangeSelectionBackgroundColor: Color(0xffffff2f)', 'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))', 'dividerColor: Color(0xffffff4f)', - 'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())' - ]), - ); + 'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())', + 'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff6f)))', + 'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff7f)))' + ])); }); testWidgets('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async { @@ -426,6 +437,12 @@ void main() { await gesture.moveTo(tester.getCenter(find.text('2024'))); await tester.pumpAndSettle(); expect(inkFeatures, paints..rect(color: datePickerTheme.yearOverlayColor?.resolve({}))); + + final ButtonStyle cancelButtonStyle = actionButtonStyle(tester, 'Cancel'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.cancelButtonStyle.toString())); + + final ButtonStyle confirmButtonStyle = actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString())); }); testWidgets('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async { @@ -467,6 +484,12 @@ void main() { final InputDecoration inputDecoration = tester.widget(find.byType(TextField)).decoration!; expect(inputDecoration.fillColor, datePickerTheme.inputDecorationTheme?.fillColor); + + final ButtonStyle cancelButtonStyle = actionButtonStyle(tester, 'Cancel'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.cancelButtonStyle.toString())); + + final ButtonStyle confirmButtonStyle = actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString())); }); testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async { From 336d60d29c89912ef294c825c8fe1634ba81fe71 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Wed, 30 Aug 2023 14:33:54 -0700 Subject: [PATCH 0989/1547] Updated DropdownMenu example and added a test (#133592) --- dev/bots/check_code_samples.dart | 1 - .../dropdown_menu/dropdown_menu.0.dart | 105 ++++++++++-------- .../dropdown_menu/dropdown_menu.0_test.dart | 55 +++++++++ 3 files changed, 114 insertions(+), 47 deletions(-) create mode 100644 examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart index 792fe54224d69..78de4d43de00e 100644 --- a/dev/bots/check_code_samples.dart +++ b/dev/bots/check_code_samples.dart @@ -321,7 +321,6 @@ final Set _knownMissingTests = { 'examples/api/test/material/scrollbar/scrollbar.1_test.dart', 'examples/api/test/material/scrollbar/scrollbar.0_test.dart', 'examples/api/test/material/dropdown_menu/dropdown_menu.1_test.dart', - 'examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart', 'examples/api/test/material/radio/radio.toggleable.0_test.dart', 'examples/api/test/material/radio/radio.0_test.dart', 'examples/api/test/material/search_anchor/search_anchor.0_test.dart', diff --git a/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart b/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart index 8a8e51b66c987..0e1814b020cca 100644 --- a/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart +++ b/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart @@ -2,13 +2,45 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// which is the default configuration, and the second one has a filled input decoration. - import 'package:flutter/material.dart'; -/// Flutter code sample for [DropdownMenu]s. The first dropdown menu has an outlined border. +// Flutter code sample for [DropdownMenu]s. The first dropdown menu +// has the default outlined border and demos using the +// [DropdownMenuEntry] style parameter to customize its appearance. +// The second dropdown menu customizes the appearance of the dropdown +// menu's text field with its [InputDecorationTheme] parameter. + +void main() { + runApp(const DropdownMenuExample()); +} + +// DropdownMenuEntry labels and values for the first dropdown menu. +enum ColorLabel { + blue('Blue', Colors.blue), + pink('Pink', Colors.pink), + green('Green', Colors.green), + yellow('Orange', Colors.orange), + grey('Grey', Colors.grey); + + const ColorLabel(this.label, this.color); + final String label; + final Color color; +} + +// DropdownMenuEntry labels and values for the second dropdown menu. +enum IconLabel { + smile('Smile', Icons.sentiment_satisfied_outlined), + cloud( + 'Cloud', + Icons.cloud_outlined, + ), + brush('Brush', Icons.brush_outlined), + heart('Heart', Icons.favorite); -void main() => runApp(const DropdownMenuExample()); + const IconLabel(this.label, this.icon); + final String label; + final IconData icon; +} class DropdownMenuExample extends StatefulWidget { const DropdownMenuExample({super.key}); @@ -25,18 +57,6 @@ class _DropdownMenuExampleState extends State { @override Widget build(BuildContext context) { - final List> colorEntries = >[]; - for (final ColorLabel color in ColorLabel.values) { - colorEntries.add( - DropdownMenuEntry(value: color, label: color.label, enabled: color.label != 'Grey'), - ); - } - - final List> iconEntries = >[]; - for (final IconLabel icon in IconLabel.values) { - iconEntries.add(DropdownMenuEntry(value: icon, label: icon.label)); - } - return MaterialApp( theme: ThemeData( useMaterial3: true, @@ -55,20 +75,30 @@ class _DropdownMenuExampleState extends State { initialSelection: ColorLabel.green, controller: colorController, label: const Text('Color'), - dropdownMenuEntries: colorEntries, onSelected: (ColorLabel? color) { setState(() { selectedColor = color; }); }, + dropdownMenuEntries: ColorLabel.values.map>( + (ColorLabel color) { + return DropdownMenuEntry( + value: color, + label: color.label, + enabled: color.label != 'Grey', + style: MenuItemButton.styleFrom( + foregroundColor: color.color, + ), + ); + } + ).toList(), ), - const SizedBox(width: 20), + const SizedBox(width: 24), DropdownMenu( controller: iconController, enableFilter: true, leadingIcon: const Icon(Icons.search), label: const Text('Icon'), - dropdownMenuEntries: iconEntries, inputDecorationTheme: const InputDecorationTheme( filled: true, contentPadding: EdgeInsets.symmetric(vertical: 5.0), @@ -78,7 +108,16 @@ class _DropdownMenuExampleState extends State { selectedIcon = icon; }); }, - ) + dropdownMenuEntries: IconLabel.values.map>( + (IconLabel icon) { + return DropdownMenuEntry( + value: icon, + label: icon.label, + leadingIcon: Icon(icon.icon), + ); + }, + ).toList(), + ), ], ), ), @@ -105,29 +144,3 @@ class _DropdownMenuExampleState extends State { ); } } - -enum ColorLabel { - blue('Blue', Colors.blue), - pink('Pink', Colors.pink), - green('Green', Colors.green), - yellow('Yellow', Colors.yellow), - grey('Grey', Colors.grey); - - const ColorLabel(this.label, this.color); - final String label; - final Color color; -} - -enum IconLabel { - smile('Smile', Icons.sentiment_satisfied_outlined), - cloud( - 'Cloud', - Icons.cloud_outlined, - ), - brush('Brush', Icons.brush_outlined), - heart('Heart', Icons.favorite); - - const IconLabel(this.label, this.icon); - final String label; - final IconData icon; -} diff --git a/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart b/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart new file mode 100644 index 0000000000000..62e0c6e195d37 --- /dev/null +++ b/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart @@ -0,0 +1,55 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/dropdown_menu/dropdown_menu.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('DropdownMenu', (WidgetTester tester) async { + await tester.pumpWidget( + const example.DropdownMenuExample(), + ); + + expect(find.text('You selected a Blue Smile'), findsNothing); + + final Finder colorMenu = find.byType(DropdownMenu); + final Finder iconMenu = find.byType(DropdownMenu); + expect(colorMenu, findsOneWidget); + expect(iconMenu, findsOneWidget); + + Finder findMenuItem(String label) { + return find.widgetWithText(MenuItemButton, label).last; + } + + await tester.tap(colorMenu); + await tester.pumpAndSettle(); + expect(findMenuItem('Blue'), findsOneWidget); + expect(findMenuItem('Pink'), findsOneWidget); + expect(findMenuItem('Green'), findsOneWidget); + expect(findMenuItem('Orange'), findsOneWidget); + expect(findMenuItem('Grey'), findsOneWidget); + + await tester.tap(findMenuItem('Blue')); + + // The DropdownMenu's onSelected callback is delayed + // with SchedulerBinding.instance.addPostFrameCallback + // to give the focus a chance to return to where it was + // before the menu appeared. The pumpAndSettle() + // give the callback a chance to run. + await tester.pumpAndSettle(); + + await tester.tap(iconMenu); + await tester.pumpAndSettle(); + expect(findMenuItem('Smile'), findsOneWidget); + expect(findMenuItem('Cloud'), findsOneWidget); + expect(findMenuItem('Brush'), findsOneWidget); + expect(findMenuItem('Heart'), findsOneWidget); + + await tester.tap(findMenuItem('Smile')); + await tester.pumpAndSettle(); + + expect(find.text('You selected a Blue Smile'), findsOneWidget); + }); +} From d7a3a68275cf30a2c6be49817a455001b46122e0 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 31 Aug 2023 01:21:29 +0300 Subject: [PATCH 0990/1547] Fix `cancelButtonStyle` & `confirmButtonStyle` properties from `TimePickerTheme` aren't working (#132843) fixes [`TimePickerThemeData` action buttons styles aren't working](https://github.com/flutter/flutter/issues/132760) ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, timePickerTheme: TimePickerThemeData( cancelButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4)), side: BorderSide(color: Colors.red), ), backgroundColor: Colors.white, foregroundColor: Colors.red, elevation: 3, shadowColor: Colors.red, ), confirmButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4)), ), backgroundColor: Colors.green[700], foregroundColor: Colors.white, elevation: 3, shadowColor: Colors.green[700], ), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: TimePickerDialog(initialTime: TimeOfDay.now()), ), ); } } ```
    ### Before (action buttons don't use the style from the `TimePickerTheme`) ![Screenshot 2023-08-18 at 14 57 37](https://github.com/flutter/flutter/assets/48603081/c95160e2-76a2-4bb5-84e0-3731fce19c0b) ### After (action buttons use the style from the `TimePickerTheme`) ![Screenshot 2023-08-18 at 14 57 18](https://github.com/flutter/flutter/assets/48603081/422d348a-bee2-4696-8d9a-5fce56191aaa) --- .../flutter/lib/src/material/time_picker.dart | 2 + .../lib/src/material/time_picker_theme.dart | 2 +- .../test/material/time_picker_theme_test.dart | 154 +++++++++++++----- 3 files changed, 114 insertions(+), 44 deletions(-) diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index d2d9e428fde3e..e36e5a20c3500 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2384,6 +2384,7 @@ class _TimePickerDialogState extends State with RestorationMix overflowAlignment: OverflowBarAlignment.end, children: [ TextButton( + style: pickerTheme.cancelButtonStyle ?? defaultTheme.cancelButtonStyle, onPressed: _handleCancel, child: Text(widget.cancelText ?? (theme.useMaterial3 @@ -2391,6 +2392,7 @@ class _TimePickerDialogState extends State with RestorationMix : localizations.cancelButtonLabel.toUpperCase())), ), TextButton( + style: pickerTheme.confirmButtonStyle ?? defaultTheme.confirmButtonStyle, onPressed: _handleOk, child: Text(widget.confirmText ?? localizations.okButtonLabel), ), diff --git a/packages/flutter/lib/src/material/time_picker_theme.dart b/packages/flutter/lib/src/material/time_picker_theme.dart index cb18b266456fd..1d0a95776db74 100644 --- a/packages/flutter/lib/src/material/time_picker_theme.dart +++ b/packages/flutter/lib/src/material/time_picker_theme.dart @@ -72,7 +72,7 @@ class TimePickerThemeData with Diagnosticable { /// The style of the cancel button of a [TimePickerDialog]. final ButtonStyle? cancelButtonStyle; - /// The style of the conform (OK) button of a [TimePickerDialog]. + /// The style of the confirm (OK) button of a [TimePickerDialog]. final ButtonStyle? confirmButtonStyle; /// The color and weight of the day period's outline. diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index 44b480702a38c..784333c917100 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -20,22 +20,28 @@ void main() { test('TimePickerThemeData null fields by default', () { const TimePickerThemeData timePickerTheme = TimePickerThemeData(); expect(timePickerTheme.backgroundColor, null); - expect(timePickerTheme.hourMinuteTextColor, null); - expect(timePickerTheme.hourMinuteColor, null); - expect(timePickerTheme.dayPeriodTextColor, null); + expect(timePickerTheme.cancelButtonStyle, null); + expect(timePickerTheme.confirmButtonStyle, null); + expect(timePickerTheme.dayPeriodBorderSide, null); expect(timePickerTheme.dayPeriodColor, null); - expect(timePickerTheme.dialHandColor, null); + expect(timePickerTheme.dayPeriodShape, null); + expect(timePickerTheme.dayPeriodTextColor, null); + expect(timePickerTheme.dayPeriodTextStyle, null); expect(timePickerTheme.dialBackgroundColor, null); + expect(timePickerTheme.dialHandColor, null); expect(timePickerTheme.dialTextColor, null); + expect(timePickerTheme.dialTextStyle, null); + expect(timePickerTheme.elevation, null); expect(timePickerTheme.entryModeIconColor, null); - expect(timePickerTheme.hourMinuteTextStyle, null); - expect(timePickerTheme.dayPeriodTextStyle, null); expect(timePickerTheme.helpTextStyle, null); - expect(timePickerTheme.shape, null); + expect(timePickerTheme.hourMinuteColor, null); expect(timePickerTheme.hourMinuteShape, null); - expect(timePickerTheme.dayPeriodShape, null); - expect(timePickerTheme.dayPeriodBorderSide, null); + expect(timePickerTheme.hourMinuteTextColor, null); + expect(timePickerTheme.hourMinuteTextStyle, null); expect(timePickerTheme.inputDecorationTheme, null); + expect(timePickerTheme.entryModeIconColor, null); + expect(timePickerTheme.padding, null); + expect(timePickerTheme.shape, null); }); testWidgets('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async { @@ -53,22 +59,36 @@ void main() { testWidgets('TimePickerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TimePickerThemeData( - backgroundColor: Color(0xFFFFFFFF), - hourMinuteTextColor: Color(0xFFFFFFFF), - hourMinuteColor: Color(0xFFFFFFFF), - dayPeriodTextColor: Color(0xFFFFFFFF), - dayPeriodColor: Color(0xFFFFFFFF), - dialHandColor: Color(0xFFFFFFFF), - dialBackgroundColor: Color(0xFFFFFFFF), - dialTextColor: Color(0xFFFFFFFF), - entryModeIconColor: Color(0xFFFFFFFF), - hourMinuteTextStyle: TextStyle(), - dayPeriodTextStyle: TextStyle(), - helpTextStyle: TextStyle(), - shape: RoundedRectangleBorder(), - hourMinuteShape: RoundedRectangleBorder(), - dayPeriodShape: RoundedRectangleBorder(), - dayPeriodBorderSide: BorderSide(), + backgroundColor: Color(0xfffffff0), + cancelButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff1))), + confirmButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2))), + dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3)), + dayPeriodColor: Color(0xfffffff4), + dayPeriodShape: RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffffff5)), + ), + dayPeriodTextColor: Color(0xfffffff6), + dayPeriodTextStyle: TextStyle(color: Color(0xfffffff7)), + dialBackgroundColor: Color(0xfffffff8), + dialHandColor: Color(0xfffffff9), + dialTextColor: Color(0xfffffffa), + dialTextStyle: TextStyle(color: Color(0xfffffffb)), + elevation: 1.0, + entryModeIconColor: Color(0xfffffffc), + helpTextStyle: TextStyle(color: Color(0xfffffffd)), + hourMinuteColor: Color(0xfffffffe), + hourMinuteShape: RoundedRectangleBorder( + side: BorderSide(color: Color(0xffffffff)), + ), + hourMinuteTextColor: Color(0xfffffff0), + hourMinuteTextStyle: TextStyle(color: Color(0xfffffff1)), + inputDecorationTheme: InputDecorationTheme( + labelStyle: TextStyle(color: Color(0xfffffff2)), + ), + padding: EdgeInsets.all(1.0), + shape: RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffffff3)), + ), ).debugFillProperties(builder); final List description = builder.properties @@ -76,24 +96,30 @@ void main() { .map((DiagnosticsNode node) => node.toString()) .toList(); - expect(description, [ - 'backgroundColor: Color(0xffffffff)', - 'dayPeriodBorderSide: BorderSide', - 'dayPeriodColor: Color(0xffffffff)', - 'dayPeriodShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', - 'dayPeriodTextColor: Color(0xffffffff)', - 'dayPeriodTextStyle: TextStyle()', - 'dialBackgroundColor: Color(0xffffffff)', - 'dialHandColor: Color(0xffffffff)', - 'dialTextColor: Color(0xffffffff)', - 'entryModeIconColor: Color(0xffffffff)', - 'helpTextStyle: TextStyle()', - 'hourMinuteColor: Color(0xffffffff)', - 'hourMinuteShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)', - 'hourMinuteTextColor: Color(0xffffffff)', - 'hourMinuteTextStyle: TextStyle()', - 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)' - ]); + expect(description, equalsIgnoringHashCodes([ + 'backgroundColor: Color(0xfffffff0)', + 'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff1)))', + 'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2)))', + 'dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3))', + 'dayPeriodColor: Color(0xfffffff4)', + 'dayPeriodShape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff5)), BorderRadius.zero)', + 'dayPeriodTextColor: Color(0xfffffff6)', + 'dayPeriodTextStyle: TextStyle(inherit: true, color: Color(0xfffffff7))', + 'dialBackgroundColor: Color(0xfffffff8)', + 'dialHandColor: Color(0xfffffff9)', + 'dialTextColor: Color(0xfffffffa)', + 'dialTextStyle: TextStyle(inherit: true, color: Color(0xfffffffb))', + 'elevation: 1.0', + 'entryModeIconColor: Color(0xfffffffc)', + 'helpTextStyle: TextStyle(inherit: true, color: Color(0xfffffffd))', + 'hourMinuteColor: Color(0xfffffffe)', + 'hourMinuteShape: RoundedRectangleBorder(BorderSide(color: Color(0xffffffff)), BorderRadius.zero)', + 'hourMinuteTextColor: Color(0xfffffff0)', + 'hourMinuteTextStyle: TextStyle(inherit: true, color: Color(0xfffffff1))', + 'inputDecorationTheme: InputDecorationTheme#ff861(labelStyle: TextStyle(inherit: true, color: Color(0xfffffff2)))', + 'padding: EdgeInsets.all(1.0)', + 'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)' + ])); }); testWidgets('Material2 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { @@ -221,6 +247,12 @@ void main() { entryModeIconButton.color, defaultTheme.colorScheme.onSurface.withOpacity(0.6), ); + + final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); + + final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); testWidgets('Material3 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { @@ -363,6 +395,12 @@ void main() { final IconButton entryModeIconButton = _entryModeIconButton(tester); expect(entryModeIconButton.color, null); + + final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); + + final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); testWidgets('Material2 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { @@ -399,6 +437,12 @@ void main() { Typography.material2014().englishLike.displayMedium! .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36))) ); + + final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); + + final ButtonStyle confirmButtonStyle= _actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); testWidgets('Material3 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { @@ -438,6 +482,12 @@ void main() { hourDecoration.hintStyle, TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)) ); + + final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); + + final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); testWidgets('Material2 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { @@ -555,6 +605,12 @@ void main() { entryModeIconButton.color, timePickerTheme.entryModeIconColor, ); + + final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.cancelButtonStyle.toString())); + + final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString())); }); testWidgets('Material3 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { @@ -672,6 +728,12 @@ void main() { final IconButton entryModeIconButton = _entryModeIconButton(tester); expect(entryModeIconButton.color, null); + + final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel'); + expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.cancelButtonStyle.toString())); + + final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK'); + expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString())); }); testWidgets('Time picker uses values from TimePickerThemeData with InputDecorationTheme - input mode', (WidgetTester tester) async { @@ -713,6 +775,8 @@ TimePickerThemeData _timePickerTheme({bool includeInputDecoration = false}) { final MaterialStateColor materialStateColor = MaterialStateColor.resolveWith(getColor); return TimePickerThemeData( backgroundColor: Colors.orange, + cancelButtonStyle: TextButton.styleFrom(primary: Colors.red), + confirmButtonStyle: TextButton.styleFrom(primary: Colors.green), hourMinuteTextColor: materialStateColor, hourMinuteColor: materialStateColor, dayPeriodTextColor: materialStateColor, @@ -807,3 +871,7 @@ final Finder findDialPaint = find.descendant( of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_Dial'), matching: find.byWidgetPredicate((Widget w) => w is CustomPaint), ); + +ButtonStyle _actionButtonStyle(WidgetTester tester, String text) { + return tester.widget(find.widgetWithText(TextButton, text)).style!; +} From 31600c829e8dc821a72e19e001651b75f2970d35 Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Wed, 30 Aug 2023 15:29:05 -0700 Subject: [PATCH 0991/1547] Forward-fix a test that will break with an engine roll. (#133619) See https://github.com/flutter/engine/pull/44705 where it fails a framework smoke test. Partial work towards https://github.com/flutter/flutter/issues/112498. --- .../flutter/test/painting/text_style_test.dart | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/flutter/test/painting/text_style_test.dart b/packages/flutter/test/painting/text_style_test.dart index 1658eb59137e2..6480a7f822642 100644 --- a/packages/flutter/test/painting/text_style_test.dart +++ b/packages/flutter/test/painting/text_style_test.dart @@ -450,6 +450,13 @@ void main() { }); test('backgroundColor', () { + // TODO(matanlurey): Remove when https://github.com/flutter/engine/pull/44705 rolls into the framework. + // Currently, dithering is disabled by default, but it's about to be flipped (enabled by default), + // and deprecated. This avoids #44705 causing a breakage in this test. + // + // ignore: deprecated_member_use + Paint.enableDithering = true; + const TextStyle s1 = TextStyle(); expect(s1.backgroundColor, isNull); expect(s1.toString(), 'TextStyle()'); @@ -459,7 +466,16 @@ void main() { expect(s2.toString(), 'TextStyle(inherit: true, backgroundColor: Color(0xff00ff00))'); final ui.TextStyle ts2 = s2.getTextStyle(); - expect(ts2.toString(), contains('background: Paint(Color(0xff00ff00))')); + + // TODO(matanlurey): Remove when https://github.com/flutter/flutter/issues/133698 is resolved. + // There are 5+ implementations of Paint, so we should either align the toString() or stop + // testing it, IMO. + if (kIsWeb) { + // The web implementation never includes "dither: ..." as a property. + expect(ts2.toString(), contains('background: Paint(Color(0xff00ff00))')); + } else { + expect(ts2.toString(), contains('background: Paint(Color(0xff00ff00); dither: true)')); + } }); test('TextStyle background and backgroundColor combos', () { From 95e197ba69663b600ecda0768479c3c8308d1025 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 30 Aug 2023 16:07:35 -0700 Subject: [PATCH 0992/1547] _RawAutocompleteState should dispose _highlightedOptionIndex. (#133700) --- packages/flutter/lib/src/widgets/autocomplete.dart | 1 + packages/flutter/test/material/autocomplete_test.dart | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart index 9f6e226b5281f..d44ec4d414818 100644 --- a/packages/flutter/lib/src/widgets/autocomplete.dart +++ b/packages/flutter/lib/src/widgets/autocomplete.dart @@ -565,6 +565,7 @@ class _RawAutocompleteState extends State> _floatingOptions?.remove(); _floatingOptions?.dispose(); _floatingOptions = null; + _highlightedOptionIndex.dispose(); super.dispose(); } diff --git a/packages/flutter/test/material/autocomplete_test.dart b/packages/flutter/test/material/autocomplete_test.dart index 2113bf6387eff..e5509beb3c8ab 100644 --- a/packages/flutter/test/material/autocomplete_test.dart +++ b/packages/flutter/test/material/autocomplete_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class User { const User({ @@ -45,7 +46,8 @@ void main() { User(name: 'Charlie', email: 'charlie123@gmail.com'), ]; - testWidgets('can filter and select a list of string options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can filter and select a list of string options', (WidgetTester tester) async { + late String lastSelection; await tester.pumpWidget( MaterialApp( From 784629c9386ddc057eed025f0b631fdab675826a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 19:23:37 -0400 Subject: [PATCH 0993/1547] Roll Flutter Engine from b63eee2e31cc to d37cef84d40d (3 revisions) (#133706) https://github.com/flutter/engine/compare/b63eee2e31cc...d37cef84d40d 2023-08-30 jacksongardner@google.com [web] Roll to most recent fallback font data (flutter/engine#45301) 2023-08-30 matanlurey@users.noreply.github.com Increase maximum length of function names from 30 to 60. (flutter/engine#45296) 2023-08-30 jacksongardner@google.com Add an API in `ui_web` to create a `ui.Image` from an `ImageBitmap` (flutter/engine#45256) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b7965ce5f3b4f..7514f342ddb14 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b63eee2e31cc3739bf89d193fde6fa6f66fba04a +d37cef84d40d1616f91aa7160eb41d7809a28d1d From 2bc4c7a8884b75b0a80a2d9988f5617f3189a789 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 30 Aug 2023 16:25:18 -0700 Subject: [PATCH 0994/1547] Mark routing test as leaking. (#133697) --- packages/flutter/test/material/app_test.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 88aafa258aba2..14d7f270e0e81 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -57,7 +57,7 @@ void main() { expect(focusNode.hasFocus, isTrue); }); - testWidgets('Can place app inside FocusScope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can place app inside FocusScope', (WidgetTester tester) async { final FocusScopeNode focusScopeNode = FocusScopeNode(); await tester.pumpWidget(FocusScope( @@ -69,6 +69,7 @@ void main() { )); expect(find.text('Home'), findsOneWidget); + focusScopeNode.dispose(); }); testWidgetsWithLeakTracking('Can show grid without losing sync', (WidgetTester tester) async { @@ -310,7 +311,7 @@ void main() { expect(find.text('route "/b"', skipOffstage: false), findsNothing); }); - testWidgets('Initial route with missing step', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial route with missing step', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const Text('route "/"'), '/a': (BuildContext context) => const Text('route "/a"'), @@ -333,7 +334,12 @@ void main() { expect(find.text('route "/a/b"'), findsNothing); expect(find.text('route "/b"'), findsNothing); } - }); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/133695 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: {'ValueNotifier': 3}, + )); testWidgetsWithLeakTracking('Make sure initialRoute is only used the first time', (WidgetTester tester) async { final Map routes = { From be3e64abf161f3931e798412e667dd4a8471eb69 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 30 Aug 2023 17:09:09 -0700 Subject: [PATCH 0995/1547] Mark leak in _DraggableScrollableSheetState. (#133693) --- packages/flutter/test/material/about_test.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 5540f319ed859..911757e194424 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -1525,7 +1525,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgets('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1590,7 +1590,12 @@ void main() { expect(titleOffset, const Offset(292.0, 136.0)); expect(titleOffset.dx, lessThan(wideSize.width - 320)); // Default master view width is 320.0. expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/133705 + notDisposedAllowList: {'ValueNotifier':5}, + )); testWidgets('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; From 4b0bbe90591dce2dd408b6ebe682d06a3b2a9d90 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 20:10:24 -0400 Subject: [PATCH 0996/1547] Roll Flutter Engine from d37cef84d40d to 8f1b77b1ac69 (1 revision) (#133714) https://github.com/flutter/engine/compare/d37cef84d40d...8f1b77b1ac69 2023-08-30 skia-flutter-autoroll@skia.org Roll Skia from 185fbe1a264d to 5f3ef5363dbd (9 revisions) (flutter/engine#45305) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7514f342ddb14..f95104a6a54df 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d37cef84d40d1616f91aa7160eb41d7809a28d1d +8f1b77b1ac693524435fe9199ce2e0cb43662bd3 From 2434a9d98bbd615a55a4a7bdc119f8de2738a54b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 21:13:24 -0400 Subject: [PATCH 0997/1547] Roll Flutter Engine from 8f1b77b1ac69 to 73e86369614d (1 revision) (#133720) https://github.com/flutter/engine/compare/8f1b77b1ac69...73e86369614d 2023-08-30 matanlurey@users.noreply.github.com Add a `DlStopwatchVisualizer` and conditionally use it for Impeller (flutter/engine#45259) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f95104a6a54df..0d565a597ad98 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8f1b77b1ac693524435fe9199ce2e0cb43662bd3 +73e86369614d5b9850e5c1b280389aa87340c8c0 From 5296f8468f0b67e5e8ffd718704abccae0953166 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 30 Aug 2023 21:55:38 -0400 Subject: [PATCH 0998/1547] Roll Flutter Engine from 73e86369614d to 3b75e3de7ef3 (2 revisions) (#133724) https://github.com/flutter/engine/compare/73e86369614d...3b75e3de7ef3 2023-08-31 dnfield@google.com [Impeller] Reland DlAiksCanvas (flutter/engine#45232) 2023-08-31 matanlurey@users.noreply.github.com Add a build_bucket_golden_scraper tool. (flutter/engine#45243) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0d565a597ad98..ae79182bdb192 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -73e86369614d5b9850e5c1b280389aa87340c8c0 +3b75e3de7ef3788b13b8ab456d52ae3f8c4675b0 From a0862f1c3f9885136ff986aa75de1aa9bf8e61e0 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 30 Aug 2023 18:58:42 -0700 Subject: [PATCH 0999/1547] [framework] use ImageFilter for stretch overscroll. (#133613) Rather than changing the size of the child elements (relaying out text and potentially changing glyph shape and position due to pixel snapping), apply the stretch effect as a compositing effect - render the children to a texture and stretch the texture. If we end up using an image shader to apply an custom shader we'll need to do this anyway. Fixes https://github.com/flutter/flutter/issues/129528 ### Before https://github.com/flutter/flutter/assets/8975114/16e9eb57-f864-4093-b4a4-461082b89b43 ### After https://github.com/flutter/flutter/assets/8975114/14cf0167-8922-4876-a325-e3bc154b084f --- .../lib/src/widgets/overscroll_indicator.dart | 2 +- .../overscroll_stretch_indicator_test.dart | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart index 2b65fd3f31f36..810cbf6fab694 100644 --- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart +++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart @@ -786,10 +786,10 @@ class _StretchingOverscrollIndicatorState extends State()))); + + final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(CustomScrollView))); + // Overscroll + await gesture.moveBy(const Offset(200.0, 0.0)); + await tester.pumpAndSettle(); + + expect(tester.layers, contains(isA())); + }); } From cfdb91bfd6f2f93c8e940af5c04d4e6aef12d14a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 00:06:26 -0400 Subject: [PATCH 1000/1547] Roll Flutter Engine from 3b75e3de7ef3 to 0559a733c888 (1 revision) (#133734) https://github.com/flutter/engine/compare/3b75e3de7ef3...0559a733c888 2023-08-31 jonahwilliams@google.com [Impeller] CoverGeometry transforms its bounds. (flutter/engine#45308) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ae79182bdb192..1690271ce5adc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3b75e3de7ef3788b13b8ab456d52ae3f8c4675b0 +0559a733c888f8414397c1bd610a1ec7e17c0492 From dd51bf09703955239117e238d36ee12776ce6279 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 00:58:35 -0400 Subject: [PATCH 1001/1547] Roll Flutter Engine from 0559a733c888 to e88b21b6d4e8 (1 revision) (#133735) https://github.com/flutter/engine/compare/0559a733c888...e88b21b6d4e8 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 5f3ef5363dbd to af7fb958e7f7 (1 revision) (flutter/engine#45311) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1690271ce5adc..cb5d48cf85ad2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0559a733c888f8414397c1bd610a1ec7e17c0492 +e88b21b6d4e8f861895bcf318bf91724487b457b From 5603935d75bba32760a119b97085e028739935f0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 03:09:23 -0400 Subject: [PATCH 1002/1547] Roll Flutter Engine from e88b21b6d4e8 to 1f1071d3f5ba (1 revision) (#133737) https://github.com/flutter/engine/compare/e88b21b6d4e8...1f1071d3f5ba 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from af7fb958e7f7 to adaad6716b2c (1 revision) (flutter/engine#45312) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cb5d48cf85ad2..0ada76a854119 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e88b21b6d4e8f861895bcf318bf91724487b457b +1f1071d3f5ba76cdae2c575aae6385725a0236f6 From 0700801e2374c6c0d62c3cec24f10a9b5e6494c0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 04:05:24 -0400 Subject: [PATCH 1003/1547] Roll Flutter Engine from 1f1071d3f5ba to 1917fa95ea55 (2 revisions) (#133739) https://github.com/flutter/engine/compare/1f1071d3f5ba...1917fa95ea55 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from adaad6716b2c to 676a16152834 (1 revision) (flutter/engine#45314) 2023-08-31 matej.knopp@gmail.com [macOS] Implement unobstructed platform views (flutter/engine#42960) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0ada76a854119..3a054ec6aca28 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1f1071d3f5ba76cdae2c575aae6385725a0236f6 +1917fa95ea5545eae2284b4d200041593996c07a From 5e16d2ca757fe26c4b728782cec23ec9b17394b3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 04:51:40 -0400 Subject: [PATCH 1004/1547] Roll Flutter Engine from 1917fa95ea55 to 5156c03344eb (2 revisions) (#133745) https://github.com/flutter/engine/compare/1917fa95ea55...5156c03344eb 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 676a16152834 to 5f17219305ff (1 revision) (flutter/engine#45316) 2023-08-31 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from gWpPuUyuR_hmz9Xmg... to 7sFO_YvenNXCm6TdK... (flutter/engine#45315) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from gWpPuUyuR_hm to 7sFO_YvenNXC If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3a054ec6aca28..4a1dcc0d20014 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1917fa95ea5545eae2284b4d200041593996c07a +5156c03344ebf3e6298440caf9c3fcd8d493ec86 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 933a7b94539f3..f948260b0d3b7 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -gWpPuUyuR_hmz9XmgcrDgQq664PRigdV2BgG77idOv4C +7sFO_YvenNXCm6TdKxn5SBiNvU69Cfj-bRuyClfkN6gC From 9e9aa810bec31cc7a0cded6ad014e85a99543405 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 07:05:24 -0400 Subject: [PATCH 1005/1547] Roll Flutter Engine from 5156c03344eb to 772d5e996af8 (1 revision) (#133752) https://github.com/flutter/engine/compare/5156c03344eb...772d5e996af8 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 5f17219305ff to 1fae612aee7d (1 revision) (flutter/engine#45317) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4a1dcc0d20014..1de9bac6bbf67 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5156c03344ebf3e6298440caf9c3fcd8d493ec86 +772d5e996af825751c4cb8e7a34bc5a521965839 From dd1ee24fc2a5048d4d8e29f06d2ecfeca4f84a04 Mon Sep 17 00:00:00 2001 From: Delwin Mathew <84124091+opxdelwin@users.noreply.github.com> Date: Thu, 31 Aug 2023 18:59:18 +0530 Subject: [PATCH 1006/1547] `InputDecorationTheme.isCollapsed` doesn't work if `InputDecoration.isCollapsed` is not provided. (#133189) `appleDefault` method didn't include setting values for non-null (here `isCollapsed`) parameters initially, which has been updated and documented in this commit. Existing and new tests are passing. Fixes #133144 --- .../lib/src/material/input_decorator.dart | 18 +++++++++------- .../test/material/input_decorator_test.dart | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index c1dbc0988cf01..1a99e298cb821 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -2169,7 +2169,10 @@ class _InputDecoratorState extends State with TickerProviderStat return border.copyWith( borderSide: BorderSide( color: _getDefaultM2BorderColor(themeData), - width: (decoration.isCollapsed || decoration.border == InputBorder.none || !decoration.enabled) + width: ( + (decoration.isCollapsed ?? themeData.inputDecorationTheme.isCollapsed) + || decoration.border == InputBorder.none + || !decoration.enabled) ? 0.0 : isFocused ? 2.0 : 1.0, ), @@ -2402,7 +2405,8 @@ class _InputDecoratorState extends State with TickerProviderStat final EdgeInsets contentPadding; final double floatingLabelHeight; - if (decoration.isCollapsed) { + if (decoration.isCollapsed + ?? themeData.inputDecorationTheme.isCollapsed) { floatingLabelHeight = 0.0; contentPadding = decorationContentPadding ?? EdgeInsets.zero; } else if (!border.isOutline) { @@ -2430,7 +2434,7 @@ class _InputDecoratorState extends State with TickerProviderStat final _Decorator decorator = _Decorator( decoration: _Decoration( contentPadding: contentPadding, - isCollapsed: decoration.isCollapsed, + isCollapsed: decoration.isCollapsed ?? themeData.inputDecorationTheme.isCollapsed, floatingLabelHeight: floatingLabelHeight, floatingLabelAlignment: decoration.floatingLabelAlignment!, floatingLabelProgress: _floatingLabelAnimation.value, @@ -2577,7 +2581,7 @@ class InputDecoration { this.errorMaxLines, this.floatingLabelBehavior, this.floatingLabelAlignment, - this.isCollapsed = false, + this.isCollapsed, this.isDense, this.contentPadding, this.prefixIcon, @@ -2976,7 +2980,7 @@ class InputDecoration { /// A collapsed decoration cannot have [labelText], [errorText], an [icon]. /// /// To create a collapsed input decoration, use [InputDecoration.collapsed]. - final bool isCollapsed; + final bool? isCollapsed; /// An icon that appears before the [prefix] or [prefixText] and before /// the editable part of the text field, within the decoration's container. @@ -3620,7 +3624,7 @@ class InputDecoration { floatingLabelAlignment: floatingLabelAlignment ?? theme.floatingLabelAlignment, isDense: isDense ?? theme.isDense, contentPadding: contentPadding ?? theme.contentPadding, - isCollapsed: isCollapsed, + isCollapsed: isCollapsed ?? theme.isCollapsed, iconColor: iconColor ?? theme.iconColor, prefixStyle: prefixStyle ?? theme.prefixStyle, prefixIconColor: prefixIconColor ?? theme.prefixIconColor, @@ -3782,7 +3786,7 @@ class InputDecoration { if (floatingLabelAlignment != null) 'floatingLabelAlignment: $floatingLabelAlignment', if (isDense ?? false) 'isDense: $isDense', if (contentPadding != null) 'contentPadding: $contentPadding', - if (isCollapsed) 'isCollapsed: $isCollapsed', + if (isCollapsed ?? false) 'isCollapsed: $isCollapsed', if (prefixIcon != null) 'prefixIcon: $prefixIcon', if (prefixIconColor != null) 'prefixIconColor: $prefixIconColor', if (prefix != null) 'prefix: $prefix', diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 8647713698eee..b750c7a4f8438 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -6570,4 +6570,25 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(find.byType(InputDecorator), findsOneWidget); expect(tester.renderObject(find.text('COUNTER')).size, Size.zero); }); + + group('isCollapsed parameter works with themeData', () { + test('parameter is provided in InputDecorationTheme', () { + final InputDecoration decoration = const InputDecoration( + hintText: 'Hello, Flutter!', + ).applyDefaults(const InputDecorationTheme( + isCollapsed: true, + )); + + expect(decoration.isCollapsed, true); + }); + + test('parameter is provided in InputDecoration', () { + final InputDecoration decoration = const InputDecoration( + isCollapsed: true, + hintText: 'Hello, Flutter!', + ).applyDefaults(const InputDecorationTheme()); + + expect(decoration.isCollapsed, true); + }); + }); } From c175cf87a6a3d797fdc3f81cbd54419f639cd3d9 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 31 Aug 2023 09:57:07 -0500 Subject: [PATCH 1007/1547] Ignore macOS Cocoapods linting failure on DT_TOOLCHAIN_DIR error (#133588) Xcode 15 introduced an [error](https://github.com/flutter/flutter/issues/132755) into Cocoapods when building macOS apps. When `pod lib lint` runs, it under the covers is building the app with `xcodebuild`, which is why this error occurs when linting. A fix has been made in Cocoapods, but is not in an official release so we can't upgrade Cocoapods yet. This is to temporarily ignore lint failure due to that error. Fixes https://github.com/flutter/flutter/issues/132980. Tracking issue to upgrade Cocoapods when fix is in a release: https://github.com/flutter/flutter/issues/133584 Since Xcode 15 isn't in CI, I tested it in a one-off led test: * [Pre-fix failure](https://chromium-swarm.appspot.com/task?id=6431f228ecf98e10) * [Post-fix success](https://chromium-swarm.appspot.com/task?id=645ba7ebdab97210) --- dev/devicelab/bin/tasks/plugin_lint_mac.dart | 50 ++++++++++++++------ dev/devicelab/lib/framework/utils.dart | 3 +- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/dev/devicelab/bin/tasks/plugin_lint_mac.dart b/dev/devicelab/bin/tasks/plugin_lint_mac.dart index 79015aa39245f..f4a8f0faa8579 100644 --- a/dev/devicelab/bin/tasks/plugin_lint_mac.dart +++ b/dev/devicelab/bin/tasks/plugin_lint_mac.dart @@ -46,12 +46,9 @@ Future main() async { ); final String macosintegrationTestPodspec = path.join(integrationTestPackage, 'integration_test_macos', 'macos', 'integration_test_macos.podspec'); - await exec( - 'pod', + await _tryMacOSLint( + macosintegrationTestPodspec, [ - 'lib', - 'lint', - macosintegrationTestPodspec, '--verbose', // TODO(cyanglaz): remove allow-warnings when https://github.com/flutter/flutter/issues/125812 is fixed. // https://github.com/flutter/flutter/issues/125812 @@ -164,12 +161,9 @@ Future main() async { final String macOSPodspecPath = path.join(swiftPluginPath, 'macos', '$swiftPluginName.podspec'); await inDirectory(tempDir, () async { - await exec( - 'pod', + await _tryMacOSLint( + macOSPodspecPath, [ - 'lib', - 'lint', - macOSPodspecPath, '--allow-warnings', '--verbose', ], @@ -179,12 +173,9 @@ Future main() async { section('Lint Swift macOS podspec plugin as library'); await inDirectory(tempDir, () async { - await exec( - 'pod', + await _tryMacOSLint( + macOSPodspecPath, [ - 'lib', - 'lint', - macOSPodspecPath, '--allow-warnings', '--use-libraries', '--verbose', @@ -533,3 +524,32 @@ void _validateMacOSPodfile(String appPath) { 'macos', )); } + +Future _tryMacOSLint( + String podspecPath, + List extraArguments, +) async { + final StringBuffer lintStdout = StringBuffer(); + try { + await eval( + 'pod', + [ + 'lib', + 'lint', + podspecPath, + ...extraArguments, + ], + stdout: lintStdout, + ); + } on BuildFailedError { + // Temporarily ignore errors due to DT_TOOLCHAIN_DIR if it's the only error. + // This error was introduced with Xcode 15. Fix was made in Cocoapods, but + // is not in an official release yet. + // TODO(vashworth): Stop ignoring when https://github.com/flutter/flutter/issues/133584 is complete. + final String lintResult = lintStdout.toString(); + if (!(lintResult.contains('error: DT_TOOLCHAIN_DIR cannot be used to evaluate') && + lintResult.contains('did not pass validation, due to 1 error'))) { + rethrow; + } + } +} diff --git a/dev/devicelab/lib/framework/utils.dart b/dev/devicelab/lib/framework/utils.dart index 8b97890ac2cab..40b5820c21ea8 100644 --- a/dev/devicelab/lib/framework/utils.dart +++ b/dev/devicelab/lib/framework/utils.dart @@ -430,11 +430,12 @@ Future eval( Map? environment, bool canFail = false, // as in, whether failures are ok. False means that they are fatal. String? workingDirectory, + StringBuffer? stdout, // if not null, the stdout will be written here StringBuffer? stderr, // if not null, the stderr will be written here bool printStdout = true, bool printStderr = true, }) async { - final StringBuffer output = StringBuffer(); + final StringBuffer output = stdout ?? StringBuffer(); await _execute( executable, arguments, From 5a2b8dc4e629a56231fb454873c8953ce44cd169 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 11:06:05 -0400 Subject: [PATCH 1008/1547] Roll Flutter Engine from 772d5e996af8 to 1809b05a37a3 (1 revision) (#133762) https://github.com/flutter/engine/compare/772d5e996af8...1809b05a37a3 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 1fae612aee7d to 47a7d27ceb93 (1 revision) (flutter/engine#45318) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1de9bac6bbf67..03b2ab3370ac8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -772d5e996af825751c4cb8e7a34bc5a521965839 +1809b05a37a32da2d4f384b4cd9d69e9764ed7e0 From 28ec737d396679a556bdca13e0925de5c7d8eaa4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 11:45:49 -0400 Subject: [PATCH 1009/1547] Roll Packages from 64af59e00bb7 to e7d812cefce0 (6 revisions) (#133765) https://github.com/flutter/packages/compare/64af59e00bb7...e7d812cefce0 2023-08-30 50271102+talhakhan1297@users.noreply.github.com [path_provider] Fix93198: Added getDownloadsDirectory() for Android (flutter/packages#4708) 2023-08-30 stuartmorgan@google.com [in_app_purchase] Minor lint cleanup (flutter/packages#4818) 2023-08-30 tarrinneal@gmail.com [local_auth] Update to pigeon 11 and remove enum wrappers (flutter/packages#4809) 2023-08-30 vital@hey.com [image_picker] Fix link in README file. (flutter/packages#4775) 2023-08-30 mouad.debbar@gmail.com [web] Use new APIs from `dart:ui_web` (flutter/packages#4168) 2023-08-30 engine-flutter-autoroll@skia.org Roll Flutter from 6c95737375db to 1fe24956ac46 (24 revisions) (flutter/packages#4817) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 672e1cf5c6e30..ba405be3ea80d 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -64af59e00bb7f4b98470560378210846549f6ee3 +e7d812cefce083fa09762d25cd42303737d05b9f From 7fe4571af2b7dd57deb0c99faac574573809da05 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 11:51:33 -0400 Subject: [PATCH 1010/1547] Roll Flutter Engine from 1809b05a37a3 to e8de3dd63d47 (1 revision) (#133766) https://github.com/flutter/engine/compare/1809b05a37a3...e8de3dd63d47 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 47a7d27ceb93 to a13a9d6efbbc (2 revisions) (flutter/engine#45319) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 03b2ab3370ac8..28bcb26b1ec93 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1809b05a37a32da2d4f384b4cd9d69e9764ed7e0 +e8de3dd63d476e17c0204b9352f3516e0ac63faa From 414bff1403077de5bb351baa010d2a4ba20909ae Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Thu, 31 Aug 2023 17:52:06 +0200 Subject: [PATCH 1011/1547] ScrollController creation dispatching for memory leaks tracking (#133759) --- packages/flutter/lib/src/widgets/routes.dart | 1 + .../lib/src/widgets/scroll_controller.dart | 6 +- .../flutter/test/material/app_bar_test.dart | 73 +++++++++++-------- .../test/material/page_selector_test.dart | 48 ++++++++++-- .../test/material/refresh_indicator_test.dart | 14 ++++ .../flutter/test/material/scrollbar_test.dart | 49 ++++++++++++- .../test/material/scrollbar_theme_test.dart | 58 ++++++++++----- .../material/tabbed_scrollview_warp_test.dart | 9 ++- .../test/widgets/scroll_controller_test.dart | 18 +++++ 9 files changed, 217 insertions(+), 59 deletions(-) diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index e54e46ab3c7b8..b51cb4f61c7c7 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -884,6 +884,7 @@ class _ModalScopeState extends State<_ModalScope> { @override void dispose() { focusScopeNode.dispose(); + primaryScrollController.dispose(); super.dispose(); } diff --git a/packages/flutter/lib/src/widgets/scroll_controller.dart b/packages/flutter/lib/src/widgets/scroll_controller.dart index 8e38101bade3d..9f59adefc751a 100644 --- a/packages/flutter/lib/src/widgets/scroll_controller.dart +++ b/packages/flutter/lib/src/widgets/scroll_controller.dart @@ -65,7 +65,11 @@ class ScrollController extends ChangeNotifier { this.debugLabel, this.onAttach, this.onDetach, - }) : _initialScrollOffset = initialScrollOffset; + }) : _initialScrollOffset = initialScrollOffset { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } /// The initial value to use for [offset]. /// diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index e32a962de35b2..20b9df966e8fe 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -1609,40 +1609,45 @@ void main() { // Generates a MaterialApp with a SliverAppBar in a CustomScrollView. // The first cell of the scroll view contains a button at its top, and is // initially scrolled so that it is beneath the SliverAppBar. - Widget buildWidget({ + (ScrollController, Widget) buildWidget({ required bool forceMaterialTransparency, required VoidCallback onPressed }) { const double appBarHeight = 120; - return MaterialApp( - home: Scaffold( - body: CustomScrollView( - controller: ScrollController(initialScrollOffset:appBarHeight), - slivers: [ - SliverAppBar( - collapsedHeight: appBarHeight, - expandedHeight: appBarHeight, - pinned: true, - elevation: 0, - backgroundColor: Colors.transparent, - forceMaterialTransparency: forceMaterialTransparency, - title: const Text('AppBar'), - ), - SliverList( - delegate: SliverChildBuilderDelegate((BuildContext context, int index) { - return SizedBox( - height: appBarHeight, - child: index == 0 - ? Align( - alignment: Alignment.topCenter, - child: TextButton(onPressed: onPressed, child: const Text('press'))) - : const SizedBox(), - ); - }, - childCount: 20, + final ScrollController controller = ScrollController(initialScrollOffset: appBarHeight); + + return ( + controller, + MaterialApp( + home: Scaffold( + body: CustomScrollView( + controller: controller, + slivers: [ + SliverAppBar( + collapsedHeight: appBarHeight, + expandedHeight: appBarHeight, + pinned: true, + elevation: 0, + backgroundColor: Colors.transparent, + forceMaterialTransparency: forceMaterialTransparency, + title: const Text('AppBar'), + ), + SliverList( + delegate: SliverChildBuilderDelegate((BuildContext context, int index) { + return SizedBox( + height: appBarHeight, + child: index == 0 + ? Align( + alignment: Alignment.topCenter, + child: TextButton(onPressed: onPressed, child: const Text('press'))) + : const SizedBox(), + ); + }, + childCount: 20, + ), ), - ), - ]), + ]), + ), ), ); } @@ -1650,7 +1655,7 @@ void main() { testWidgetsWithLeakTracking( 'forceMaterialTransparency == true allows gestures beneath the app bar', (WidgetTester tester) async { bool buttonWasPressed = false; - final Widget widget = buildWidget( + final (ScrollController controller, Widget widget) = buildWidget( forceMaterialTransparency:true, onPressed:() { buttonWasPressed = true; }, ); @@ -1663,6 +1668,8 @@ void main() { await tester.tap(buttonFinder); await tester.pump(); expect(buttonWasPressed, isTrue); + + controller.dispose(); }); testWidgetsWithLeakTracking( @@ -1672,7 +1679,7 @@ void main() { WidgetController.hitTestWarningShouldBeFatal = false; bool buttonWasPressed = false; - final Widget widget = buildWidget( + final (ScrollController controller, Widget widget) = buildWidget( forceMaterialTransparency:false, onPressed:() { buttonWasPressed = true; }, ); @@ -1685,6 +1692,8 @@ void main() { await tester.tap(buttonFinder, warnIfMissed:false); await tester.pump(); expect(buttonWasPressed, isFalse); + + controller.dispose(); }); }); @@ -4295,6 +4304,8 @@ void main() { ); expect(tester.takeException(), isNull); + + controller.dispose(); }); testWidgetsWithLeakTracking('does not trigger on horizontal scroll', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 3d2d0fed6193e..08442967b3646 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -84,7 +84,14 @@ void main() { await tester.pump(); expect(tabController.index, 2); expect(indicatorColors(tester), const [kUnselectedColor, kUnselectedColor, kSelectedColor]); - }); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 1, + }, + )); testWidgetsWithLeakTracking('PageSelector responds correctly to TabController.animateTo()', (WidgetTester tester) async { final TabController tabController = TabController( @@ -127,7 +134,14 @@ void main() { await tester.pumpAndSettle(); expect(tabController.index, 2); expect(indicatorColors(tester), const [kUnselectedColor, kUnselectedColor, kSelectedColor]); - }); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 1, + }, + )); testWidgetsWithLeakTracking('PageSelector responds correctly to TabBarView drags', (WidgetTester tester) async { final TabController tabController = TabController( @@ -185,8 +199,14 @@ void main() { await tester.fling(find.byType(TabBarView), const Offset(100.0, 0.0), 1000.0); await tester.pumpAndSettle(); expect(indicatorColors(tester), const [kUnselectedColor, kSelectedColor, kUnselectedColor]); - - }); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 1, + }, + )); testWidgetsWithLeakTracking('PageSelector indicatorColors', (WidgetTester tester) async { const Color kRed = Color(0xFFFF0000); @@ -205,7 +225,14 @@ void main() { tabController.index = 0; await tester.pumpAndSettle(); expect(indicatorColors(tester), const [kBlue, kRed, kRed]); - }); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 1, + }, + )); testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( @@ -228,7 +255,7 @@ void main() { expect(tester.getSize(find.byType(TabPageSelector)).height, 24.0); }); - testWidgetsWithLeakTracking('PageSelector circle border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector circle border', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, @@ -272,5 +299,12 @@ void main() { for (final TabPageSelectorIndicator indicator in indicators) { expect(indicator.borderStyle, BorderStyle.solid); } - }); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 1, + }, + )); } diff --git a/packages/flutter/test/material/refresh_indicator_test.dart b/packages/flutter/test/material/refresh_indicator_test.dart index 23af4664430af..ede579db2e55d 100644 --- a/packages/flutter/test/material/refresh_indicator_test.dart +++ b/packages/flutter/test/material/refresh_indicator_test.dart @@ -423,6 +423,8 @@ void main() { expect(controller.offset, greaterThan(lastScrollOffset)); expect(controller.offset, lessThan(0.0)); expect(refreshCalled, isTrue); + + controller.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); testWidgetsWithLeakTracking('RefreshIndicator does not force child to relayout', (WidgetTester tester) async { @@ -618,6 +620,8 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the scroll animation await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0)); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('Reverse RefreshIndicator(anywhere mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { @@ -654,6 +658,8 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the scroll animation await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation expect(tester.getCenter(find.byType(RefreshProgressIndicator)).dy, lessThan(300.0)); + + scrollController.dispose(); }); // Regression test for https://github.com/flutter/flutter/issues/71936 @@ -691,6 +697,8 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the scroll animation await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation expect(find.byType(RefreshProgressIndicator), findsNothing); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('Top RefreshIndicator(onEdge mode) should not be shown when dragging from non-zero scroll position', (WidgetTester tester) async { @@ -725,6 +733,8 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the scroll animation await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation expect(find.byType(RefreshProgressIndicator), findsNothing); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('Reverse RefreshIndicator(onEdge mode) should be shown when dragging from non-zero scroll position', (WidgetTester tester) async { @@ -760,6 +770,8 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the scroll animation await tester.pump(const Duration(seconds: 1)); // finish the indicator settle animation expect(find.byType(RefreshProgressIndicator), findsNothing); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('ScrollController.jumpTo should not trigger the refresh indicator', (WidgetTester tester) async { @@ -792,6 +804,8 @@ void main() { await tester.pump(const Duration(seconds: 1)); // finish the indicator hide animation expect(refreshCalled, false); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('RefreshIndicator.adaptive', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index 741adf448c6a5..0a750cbc03322 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -203,6 +203,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); final AssertionError exception = tester.takeException() as AssertionError; expect(exception, isAssertionError); + + controller.dispose(); }); testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows', (WidgetTester tester) async { @@ -229,6 +231,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); await tester.pumpAndSettle(); expect(find.byType(Scrollbar), paints..rect()); + + controller.dispose(); }); testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows with PrimaryScrollController', (WidgetTester tester) async { @@ -261,6 +265,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); await tester.pumpAndSettle(); expect(find.byType(Scrollbar), paints..rect()); + + controller.dispose(); }); testWidgetsWithLeakTracking( @@ -314,6 +320,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); final AssertionError exception = tester.takeException() as AssertionError; expect(exception, isAssertionError); + + controller.dispose(); }, ); @@ -341,6 +349,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); await tester.pumpAndSettle(); expect(find.byType(Scrollbar), paints..rect()); + + controller.dispose(); }); testWidgetsWithLeakTracking('On first render with thumbVisibility: true, the thumb shows with PrimaryScrollController', (WidgetTester tester) async { @@ -373,6 +383,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); await tester.pumpAndSettle(); expect(find.byType(Scrollbar), paints..rect()); + + controller.dispose(); }); testWidgetsWithLeakTracking('On first render with thumbVisibility: false, the thumb is hidden', (WidgetTester tester) async { @@ -399,6 +411,8 @@ void main() { await tester.pumpWidget(viewWithScroll()); await tester.pumpAndSettle(); expect(find.byType(Scrollbar), isNot(paints..rect())); + + controller.dispose(); }); testWidgetsWithLeakTracking( @@ -452,6 +466,8 @@ void main() { await tester.pumpAndSettle(); // Scrollbar is not showing after scroll finishes expect(find.byType(Scrollbar), isNot(paints..rect())); + + controller.dispose(); }, ); @@ -501,6 +517,8 @@ void main() { await tester.pumpAndSettle(); // Scrollbar is not showing after scroll finishes expect(find.byType(Scrollbar), paints..rect()); + + controller.dispose(); }, ); @@ -561,6 +579,8 @@ void main() { await tester.pumpAndSettle(); // Scrollbar thumb is showing after scroll finishes and timer ends. expect(find.byType(Scrollbar), paints..rect()); + + controller.dispose(); }, ); @@ -610,6 +630,8 @@ void main() { await tester.tap(find.byType(FloatingActionButton)); await tester.pumpAndSettle(); expect(materialScrollbar, isNot(paints..rect())); + + controller.dispose(); }, ); @@ -673,6 +695,8 @@ void main() { )); await tester.pumpAndSettle(); + + controller.dispose(); }); testWidgetsWithLeakTracking('Tapping the track area pages the Scroll View', (WidgetTester tester) async { @@ -763,6 +787,8 @@ void main() { color: _kAndroidThumbIdleColor, ), ); + + scrollController.dispose(); }); testWidgets('Scrollbar never goes away until finger lift', (WidgetTester tester) async { @@ -936,6 +962,8 @@ void main() { color: _kAndroidThumbIdleColor, ), ); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('Scrollbar thumb color completes a hover animation', (WidgetTester tester) async { @@ -1331,6 +1359,8 @@ void main() { expect(find.byType(CupertinoScrollbar), paints..rrect()); final CupertinoScrollbar scrollbar = tester.widget(find.byType(CupertinoScrollbar)); expect(scrollbar.controller, isNotNull); + + controller.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); testWidgetsWithLeakTracking("Scrollbar doesn't show when scroll the inner scrollable widget", (WidgetTester tester) async { @@ -1463,6 +1493,8 @@ void main() { await tester.pumpAndSettle(); // The offset should not have changed. expect(scrollController.offset, scrollAmount); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); testWidgetsWithLeakTracking('Scrollbar dragging is disabled by default on Android', (WidgetTester tester) async { @@ -1557,6 +1589,8 @@ void main() { // The offset should not have changed. expect(scrollController.offset, scrollAmount * 2); expect(tapCount, 2); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('Simultaneous dragging and pointer scrolling does not cause a crash', (WidgetTester tester) async { @@ -1729,6 +1763,8 @@ void main() { color: const Color(0xffbcbcbc), ), ); + + scrollController.dispose(); }); testWidgetsWithLeakTracking('Scrollbar.thumbVisibility triggers assertion when multiple ScrollPositions are attached.', (WidgetTester tester) async { @@ -1796,7 +1832,16 @@ void main() { error.message, contains('The provided ScrollController is currently attached to more than one ScrollPosition.'), ); - }); + + scrollController.dispose(); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 2, + }, + )); testWidgetsWithLeakTracking('Scrollbar scrollOrientation works correctly', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); @@ -1844,5 +1889,7 @@ void main() { color: _kAndroidThumbIdleColor, ), ); + + scrollController.dispose(); }); } diff --git a/packages/flutter/test/material/scrollbar_theme_test.dart b/packages/flutter/test/material/scrollbar_theme_test.dart index de07fda289cc9..c1e616629c11a 100644 --- a/packages/flutter/test/material/scrollbar_theme_test.dart +++ b/packages/flutter/test/material/scrollbar_theme_test.dart @@ -113,6 +113,8 @@ void main() { color: const Color(0x80000000), ), ); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.macOS, @@ -204,6 +206,8 @@ void main() { color: const Color(0xff2196f3), ), ); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.macOS, @@ -253,6 +257,8 @@ void main() { color: const Color(0xFF000000), ), ); + + scrollController.dispose(); }, ); @@ -301,6 +307,8 @@ void main() { color: _kDefaultIdleThumbColor, ), ); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); testWidgetsWithLeakTracking('Scrollbar.interactive takes priority over ScrollbarTheme', (WidgetTester tester) async { @@ -349,6 +357,8 @@ void main() { color: _kDefaultIdleThumbColor, ), ); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.fuchsia })); testWidgetsWithLeakTracking('Scrollbar widget properties take priority over theme', (WidgetTester tester) async { @@ -442,6 +452,8 @@ void main() { color: const Color(0x80000000), ), ); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.macOS, @@ -451,30 +463,34 @@ void main() { ); testWidgetsWithLeakTracking('ThemeData colorScheme is used when no ScrollbarTheme is set', (WidgetTester tester) async { - Widget buildFrame(ThemeData appTheme) { + (ScrollController, Widget) buildFrame(ThemeData appTheme) { final ScrollController scrollController = ScrollController(); - return MaterialApp( - theme: appTheme, - home: ScrollConfiguration( - behavior: const NoScrollbarBehavior(), - child: Scrollbar( - thumbVisibility: true, - showTrackOnHover: true, - controller: scrollController, - child: SingleChildScrollView( - controller: scrollController, - child: const SizedBox(width: 4000.0, height: 4000.0), + return ( + scrollController, + MaterialApp( + theme: appTheme, + home: ScrollConfiguration( + behavior: const NoScrollbarBehavior(), + child: Scrollbar( + thumbVisibility: true, + showTrackOnHover: true, + controller: scrollController, + child: SingleChildScrollView( + controller: scrollController, + child: const SizedBox(width: 4000.0, height: 4000.0), + ), + ), ), ), - ), - ); + ); } // Scrollbar defaults for light themes: // - coloring based on ColorScheme.onSurface - await tester.pumpWidget(buildFrame(ThemeData( + final (ScrollController controller1, Widget frame1) = buildFrame(ThemeData( colorScheme: const ColorScheme.light(), - ))); + )); + await tester.pumpWidget(frame1); await tester.pumpAndSettle(); // Idle scrollbar behavior expect( @@ -545,9 +561,10 @@ void main() { // Scrollbar defaults for dark themes: // - coloring slightly different based on ColorScheme.onSurface - await tester.pumpWidget(buildFrame(ThemeData( + final (ScrollController controller2, Widget frame2) = buildFrame(ThemeData( colorScheme: const ColorScheme.dark(), - ))); + )); + await tester.pumpWidget(frame2); await tester.pumpAndSettle(); // Theme change animation // Idle scrollbar behavior @@ -610,6 +627,9 @@ void main() { color: const Color(0xa6ffffff), ), ); + + controller1.dispose(); + controller2.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.macOS, @@ -656,6 +676,8 @@ void main() { ) ..rrect(color: const Color(0xff4caf50)), ); + + scrollController.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.macOS, diff --git a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart index 98e1dd8280b40..b26b6a68c9b18 100644 --- a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart +++ b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart @@ -81,5 +81,12 @@ void main() { // should not crash. await tester.tap(find.text('Tab 2')); await tester.pumpAndSettle(); - }); + }, + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/133755 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'PageController': 1, + }, + )); } diff --git a/packages/flutter/test/widgets/scroll_controller_test.dart b/packages/flutter/test/widgets/scroll_controller_test.dart index 96eeea898ecd8..b4bad240f93f3 100644 --- a/packages/flutter/test/widgets/scroll_controller_test.dart +++ b/packages/flutter/test/widgets/scroll_controller_test.dart @@ -4,6 +4,7 @@ import 'dart:ui' as ui; +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -393,4 +394,21 @@ void main() { // should have been true expect(isScrolling, isTrue); }); + + test('$ScrollController dispatches object creation in constructor', () { + final List events = []; + void listener(ObjectEvent event) { + if (event.object.runtimeType == ScrollController) { + events.add(event); + } + } + MemoryAllocations.instance.addListener(listener); + + final ScrollController controller = ScrollController(); + + expect(events, hasLength(1)); + + controller.dispose(); + MemoryAllocations.instance.removeListener(listener); + }); } From be06151e7dafa566b0afc922a92b940a2702c8d4 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Thu, 31 Aug 2023 18:02:49 +0200 Subject: [PATCH 1012/1547] Cover some test/widgets tests with leak tracking (#133767) --- .../test/widgets/absorb_pointer_test.dart | 9 +- .../flutter/test/widgets/actions_test.dart | 96 +++++++++++-------- packages/flutter/test/widgets/align_test.dart | 13 +-- .../test/widgets/animated_align_test.dart | 13 +-- .../test/widgets/animated_container_test.dart | 17 ++-- .../widgets/animated_cross_fade_test.dart | 23 ++--- .../test/widgets/animated_grid_test.dart | 25 ++--- .../animated_image_filtered_repaint_test.dart | 3 +- .../test/widgets/animated_list_test.dart | 27 +++--- .../animated_opacity_repaint_test.dart | 7 +- .../test/widgets/animated_padding_test.dart | 7 +- .../widgets/animated_positioned_test.dart | 21 ++-- 12 files changed, 143 insertions(+), 118 deletions(-) diff --git a/packages/flutter/test/widgets/absorb_pointer_test.dart b/packages/flutter/test/widgets/absorb_pointer_test.dart index 6c2a88f58ca4a..afe8198a29ab2 100644 --- a/packages/flutter/test/widgets/absorb_pointer_test.dart +++ b/packages/flutter/test/widgets/absorb_pointer_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('AbsorbPointers do not block siblings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AbsorbPointers do not block siblings', (WidgetTester tester) async { bool tapped = false; await tester.pumpWidget( Column( @@ -29,7 +30,7 @@ void main() { }); group('AbsorbPointer semantics', () { - testWidgets('does not change semantics when not absorbing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not change semantics when not absorbing', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -56,7 +57,7 @@ void main() { ); }); - testWidgets('drops semantics when its ignoreSemantics is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drops semantics when its ignoreSemantics is true', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final UniqueKey key = UniqueKey(); await tester.pumpWidget( @@ -75,7 +76,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignores user interactions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores user interactions', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index b59f17f8eafc2..a5956f3118f67 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -8,10 +8,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group(ActionDispatcher, () { - testWidgets('ActionDispatcher invokes actions when asked.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionDispatcher invokes actions when asked.', (WidgetTester tester) async { await tester.pumpWidget(Container()); bool invoked = false; const ActionDispatcher dispatcher = ActionDispatcher(); @@ -48,7 +49,7 @@ void main() { setUp(clear); - testWidgets('Actions widget can invoke actions with default dispatcher', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can invoke actions with default dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -75,7 +76,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -102,7 +103,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('maybeInvoke returns null when no action is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maybeInvoke returns null when no action is found', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -129,7 +130,7 @@ void main() { expect(invoked, isFalse); }); - testWidgets('invoke throws when no action is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('invoke throws when no action is found', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -156,7 +157,7 @@ void main() { expect(invoked, isFalse); }); - testWidgets('Actions widget can invoke actions with custom dispatcher', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can invoke actions with custom dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -187,7 +188,7 @@ void main() { expect(invokedIntent, equals(intent)); }); - testWidgets('Actions can invoke actions in ancestor dispatcher', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions can invoke actions in ancestor dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -224,7 +225,7 @@ void main() { expect(invokedDispatcher.runtimeType, equals(TestDispatcher1)); }); - testWidgets("Actions can invoke actions in ancestor dispatcher if a lower one isn't specified", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Actions can invoke actions in ancestor dispatcher if a lower one isn't specified", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -260,7 +261,7 @@ void main() { expect(invokedDispatcher.runtimeType, equals(TestDispatcher1)); }); - testWidgets('Actions widget can be found with of', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can be found with of', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final ActionDispatcher testDispatcher = TestDispatcher1(postInvoke: collect); @@ -277,7 +278,7 @@ void main() { expect(dispatcher, equals(testDispatcher)); }); - testWidgets('Action can be found with find', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action can be found with find', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final ActionDispatcher testDispatcher = TestDispatcher1(postInvoke: collect); bool invoked = false; @@ -324,7 +325,7 @@ void main() { expect(Actions.maybeFind(containerKey.currentContext!), isNull); }); - testWidgets('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -392,9 +393,11 @@ void main() { await buildTest(true); expect(hovering, isFalse); expect(focusing, isFalse); + + focusNode.dispose(); }); - testWidgets('FocusableActionDetector changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MouseRegion( cursor: SystemMouseCursors.forbidden, @@ -427,7 +430,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden); }); - testWidgets('Actions.invoke returns the value of Action.invoke', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions.invoke returns the value of Action.invoke', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final Object sentinel = Object(); bool invoked = false; @@ -458,7 +461,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('ContextAction can return null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ContextAction can return null', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); const TestIntent intent = TestIntent(); final TestContextAction testAction = TestContextAction(); @@ -485,7 +488,7 @@ void main() { expect(testAction.capturedContexts.single, containerKey.currentContext); }); - testWidgets('Disabled actions stop propagation to an ancestor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled actions stop propagation to an ancestor', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -534,7 +537,7 @@ void main() { }); group('Listening', () { - testWidgets('can listen to enabled state of Actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can listen to enabled state of Actions', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked1 = false; bool invoked2 = false; @@ -756,7 +759,11 @@ void main() { ); }); - testWidgets('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { + tearDown(() async { + focusNode.dispose(); + }); + + testWidgetsWithLeakTracking('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -790,7 +797,7 @@ void main() { expect(focusing, isFalse); }); - testWidgets('FocusableActionDetector shows focus highlight appropriately when focused and disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector shows focus highlight appropriately when focused and disabled', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -821,7 +828,7 @@ void main() { expect(focusing, isTrue); }); - testWidgets('FocusableActionDetector can be used without callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector can be used without callbacks', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -855,7 +862,7 @@ void main() { expect(focusing, isFalse); }); - testWidgets( + testWidgetsWithLeakTracking( 'FocusableActionDetector can prevent its descendants from being focusable', (WidgetTester tester) async { final FocusNode buttonNode = FocusNode(debugLabel: 'Test'); @@ -896,19 +903,22 @@ void main() { buttonNode.requestFocus(); await tester.pump(); expect(buttonNode.hasFocus, isFalse); + + buttonNode.dispose(); }, ); - testWidgets( + testWidgetsWithLeakTracking( 'FocusableActionDetector can prevent its descendants from being traversable', (WidgetTester tester) async { final FocusNode buttonNode1 = FocusNode(debugLabel: 'Button Node 1'); final FocusNode buttonNode2 = FocusNode(debugLabel: 'Button Node 2'); + final FocusNode skipTraversalNode = FocusNode(skipTraversal: true); await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( - focusNode: FocusNode(skipTraversal: true), + focusNode: skipTraversalNode, child: Column( children: [ ElevatedButton( @@ -939,7 +949,7 @@ void main() { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( - focusNode: FocusNode(skipTraversal: true), + focusNode: skipTraversalNode, descendantsAreTraversable: false, child: Column( children: [ @@ -967,10 +977,14 @@ void main() { await tester.pump(); expect(buttonNode1.hasFocus, isTrue); expect(buttonNode2.hasFocus, isFalse); + + buttonNode1.dispose(); + buttonNode2.dispose(); + skipTraversalNode.dispose(); }, ); - testWidgets('FocusableActionDetector can exclude Focus semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector can exclude Focus semantics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( @@ -1076,7 +1090,7 @@ void main() { }); group('Action subclasses', () { - testWidgets('CallbackAction passes correct intent when invoked.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CallbackAction passes correct intent when invoked.', (WidgetTester tester) async { late Intent passedIntent; final TestAction action = TestAction(onInvoke: (Intent intent) { passedIntent = intent; @@ -1087,7 +1101,7 @@ void main() { expect(passedIntent, equals(intent)); }); - testWidgets('VoidCallbackAction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('VoidCallbackAction', (WidgetTester tester) async { bool called = false; void testCallback() { called = true; @@ -1097,7 +1111,7 @@ void main() { action.invoke(intent); expect(called, isTrue); }); - testWidgets('Base Action class default toKeyEventResult delegates to consumesKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Base Action class default toKeyEventResult delegates to consumesKey', (WidgetTester tester) async { expect( DefaultToKeyEventResultAction(consumesKey: false).toKeyEventResult(const DefaultToKeyEventResultIntent(), null), KeyEventResult.skipRemainingHandlers, @@ -1110,7 +1124,7 @@ void main() { }); group('Diagnostics', () { - testWidgets('default Intent debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default Intent debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); // ignore: invalid_use_of_protected_member @@ -1126,7 +1140,7 @@ void main() { expect(description, isEmpty); }); - testWidgets('default Actions debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default Actions debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Actions( @@ -1152,7 +1166,7 @@ void main() { ); }); - testWidgets('Actions implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Actions( @@ -1191,7 +1205,7 @@ void main() { invokingContext = null; }); - testWidgets('Basic usage', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Basic usage', (WidgetTester tester) async { late BuildContext invokingContext2; late BuildContext invokingContext3; await tester.pumpWidget( @@ -1256,7 +1270,7 @@ void main() { expect(invocations, ['action1.invoke']); }); - testWidgets('Does not break after use', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not break after use', (WidgetTester tester) async { late BuildContext invokingContext2; late BuildContext invokingContext3; await tester.pumpWidget( @@ -1323,7 +1337,7 @@ void main() { ]); }); - testWidgets('Does not override if not overridable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not override if not overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1366,7 +1380,7 @@ void main() { ]); }); - testWidgets('The final override controls isEnabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The final override controls isEnabled', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1453,7 +1467,7 @@ void main() { expect(invocations, []); }); - testWidgets('The override can choose to defer isActionEnabled to the overridable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The override can choose to defer isActionEnabled to the overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1543,7 +1557,7 @@ void main() { ]); }); - testWidgets('Throws on infinite recursions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws on infinite recursions', (WidgetTester tester) async { late StateSetter setState; BuildContext? action2LookupContext; await tester.pumpWidget( @@ -1602,7 +1616,7 @@ void main() { expect(exception?.toString(), contains('debugAssertIsEnabledMutuallyRecursive')); }); - testWidgets('Throws on invoking invalid override', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws on invoking invalid override', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context) { @@ -1640,7 +1654,7 @@ void main() { ); }); - testWidgets('Make an overridable action overridable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Make an overridable action overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1696,7 +1710,7 @@ void main() { ]); }); - testWidgets('Overriding Actions can change the intent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overriding Actions can change the intent', (WidgetTester tester) async { final List newLogChannel = []; await tester.pumpWidget( Builder( @@ -1746,7 +1760,7 @@ void main() { ]); }); - testWidgets('Override non-context overridable Actions with a ContextAction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override non-context overridable Actions with a ContextAction', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1799,7 +1813,7 @@ void main() { expect(LogInvocationContextAction.invokeContext, invokingContext); }); - testWidgets('Override a ContextAction with a regular Action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override a ContextAction with a regular Action', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { diff --git a/packages/flutter/test/widgets/align_test.dart b/packages/flutter/test/widgets/align_test.dart index aa44e27bce1aa..1a6e89f73f176 100644 --- a/packages/flutter/test/widgets/align_test.dart +++ b/packages/flutter/test/widgets/align_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Align smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align smoke test', (WidgetTester tester) async { await tester.pumpWidget( Align( alignment: const Alignment(0.50, 0.50), @@ -38,7 +39,7 @@ void main() { ); }); - testWidgets('Align control test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align control test (LTR)', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: Align( @@ -62,7 +63,7 @@ void main() { expect(tester.getBottomRight(find.byType(SizedBox)).dx, 100.0); }); - testWidgets('Align control test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align control test (RTL)', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.rtl, child: Align( @@ -86,7 +87,7 @@ void main() { expect(tester.getBottomRight(find.byType(SizedBox)).dx, 100.0); }); - testWidgets('Shrink wraps in finite space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shrink wraps in finite space', (WidgetTester tester) async { final GlobalKey alignKey = GlobalKey(); await tester.pumpWidget( SingleChildScrollView( @@ -105,7 +106,7 @@ void main() { expect(size.height, equals(10.0)); }); - testWidgets('Align widthFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -128,7 +129,7 @@ void main() { expect(box.size.width, equals(50.0)); }); - testWidgets('Align heightFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align heightFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/animated_align_test.dart b/packages/flutter/test/widgets/animated_align_test.dart index 032f2678654fb..0d0331505abdc 100644 --- a/packages/flutter/test/widgets/animated_align_test.dart +++ b/packages/flutter/test/widgets/animated_align_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedAlign.debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign.debugFillProperties', (WidgetTester tester) async { const AnimatedAlign box = AnimatedAlign( alignment: Alignment.topCenter, curve: Curves.ease, @@ -15,7 +16,7 @@ void main() { expect(box, hasOneLineDescription); }); - testWidgets('AnimatedAlign alignment visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign alignment visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -57,7 +58,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(800.0, 400.0)); }); - testWidgets('AnimatedAlign widthFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -82,7 +83,7 @@ void main() { expect(box.size.width, equals(50.0)); }); - testWidgets('AnimatedAlign heightFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign heightFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -106,7 +107,7 @@ void main() { expect(box.size.height, equals( 50.0)); }); - testWidgets('AnimatedAlign null height factor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign null height factor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -130,7 +131,7 @@ void main() { expect(box.size, equals(const Size(100.0, 100))); }); - testWidgets('AnimatedAlign null widthFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign null widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/animated_container_test.dart b/packages/flutter/test/widgets/animated_container_test.dart index 6d40f450cd5c9..d25156a595762 100644 --- a/packages/flutter/test/widgets/animated_container_test.dart +++ b/packages/flutter/test/widgets/animated_container_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedContainer.debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer.debugFillProperties', (WidgetTester tester) async { final AnimatedContainer container = AnimatedContainer( constraints: const BoxConstraints.tightFor(width: 17.0, height: 23.0), decoration: const BoxDecoration(color: Color(0xFF00FF00)), @@ -24,7 +25,7 @@ void main() { expect(container, hasOneLineDescription); }); - testWidgets('AnimatedContainer control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer control test', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const BoxDecoration decorationA = BoxDecoration( @@ -102,7 +103,7 @@ void main() { ); }); - testWidgets('AnimatedContainer overanimate test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer overanimate test', (WidgetTester tester) async { await tester.pumpWidget( AnimatedContainer( duration: const Duration(milliseconds: 200), @@ -139,7 +140,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('AnimatedContainer padding visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer padding visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -181,7 +182,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(700.0, 0.0)); }); - testWidgets('AnimatedContainer alignment visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer alignment visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -223,7 +224,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(800.0, 400.0)); }); - testWidgets('Animation rerun', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animation rerun', (WidgetTester tester) async { await tester.pumpWidget( Center( child: AnimatedContainer( @@ -291,7 +292,7 @@ void main() { expect(text.size.height, equals(100.0)); }); - testWidgets('AnimatedContainer sets transformAlignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer sets transformAlignment', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -339,7 +340,7 @@ void main() { expect(tester.getTopLeft(find.byKey(target)), const Offset(400.0, 300.0)); }); - testWidgets('AnimatedContainer sets clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer sets clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( AnimatedContainer( decoration: const BoxDecoration( diff --git a/packages/flutter/test/widgets/animated_cross_fade_test.dart b/packages/flutter/test/widgets/animated_cross_fade_test.dart index 7a4ac09b49bd8..ee3f88b132b32 100644 --- a/packages/flutter/test/widgets/animated_cross_fade_test.dart +++ b/packages/flutter/test/widgets/animated_cross_fade_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedCrossFade test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade test', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -61,7 +62,7 @@ void main() { expect(box.size.height, equals(150.0)); }); - testWidgets('AnimatedCrossFade test showSecond', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade test showSecond', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -88,7 +89,7 @@ void main() { expect(box.size.height, equals(200.0)); }); - testWidgets('AnimatedCrossFade alignment (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade alignment (VISUAL)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -146,7 +147,7 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); }); - testWidgets('AnimatedCrossFade alignment (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade alignment (LTR)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -204,7 +205,7 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); }); - testWidgets('AnimatedCrossFade alignment (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade alignment (RTL)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -274,7 +275,7 @@ void main() { ); } - testWidgets('AnimatedCrossFade preserves widget state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade preserves widget state', (WidgetTester tester) async { await tester.pumpWidget(crossFadeWithWatcher()); _TickerWatchingWidgetState findState() => tester.state(find.byType(_TickerWatchingWidget)); @@ -287,7 +288,7 @@ void main() { } }); - testWidgets('AnimatedCrossFade switches off TickerMode and semantics on faded out widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade switches off TickerMode and semantics on faded out widget', (WidgetTester tester) async { ExcludeSemantics findSemantics() { return tester.widget(find.descendant( of: find.byKey(const ValueKey(CrossFadeState.showFirst)), @@ -317,7 +318,7 @@ void main() { expect(findSemantics().excluding, true); }); - testWidgets('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -361,7 +362,7 @@ void main() { expect(find.text('AAA'), findsNothing); }); - testWidgets('AnimatedCrossFade test focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade test focus', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -385,7 +386,7 @@ void main() { expect(hiddenNode.hasPrimaryFocus, isFalse); }); - testWidgets('AnimatedCrossFade bottom child can have focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade bottom child can have focus', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -410,7 +411,7 @@ void main() { expect(hiddenNode.hasPrimaryFocus, isTrue); }); - testWidgets('AnimatedCrossFade second child do not receive touch events', + testWidgetsWithLeakTracking('AnimatedCrossFade second child do not receive touch events', (WidgetTester tester) async { int numberOfTouchEventNoticed = 0; diff --git a/packages/flutter/test/widgets/animated_grid_test.dart b/packages/flutter/test/widgets/animated_grid_test.dart index dcec143a9e705..c03c7143febd1 100644 --- a/packages/flutter/test/widgets/animated_grid_test.dart +++ b/packages/flutter/test/widgets/animated_grid_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('SliverAnimatedGrid.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAnimatedGrid.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -50,7 +51,7 @@ void main() { expect(finderCalled, true); }); - testWidgets('AnimatedGrid', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedGrid', (WidgetTester tester) async { Widget builder(BuildContext context, int index, Animation animation) { return SizedBox( height: 100.0, @@ -132,7 +133,7 @@ void main() { }); group('SliverAnimatedGrid', () { - testWidgets('initialItemCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialItemCount', (WidgetTester tester) async { final Map> animations = >{}; await tester.pumpWidget( @@ -170,7 +171,7 @@ void main() { expect(animations[1]!.value, 1.0); }); - testWidgets('insert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insert', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -250,7 +251,7 @@ void main() { expect(itemRight(2), 300.0); }); - testWidgets('insertAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insertAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -306,7 +307,7 @@ void main() { expect(itemRight(1), 200.0); }); - testWidgets('remove', (WidgetTester tester) async { + testWidgetsWithLeakTracking('remove', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -384,7 +385,7 @@ void main() { expect(itemRight(2), 200.0); }); - testWidgets('removeAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removeAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -436,7 +437,7 @@ void main() { expect(find.text('item 2'), findsNothing); }); - testWidgets('works in combination with other slivers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in combination with other slivers', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -505,7 +506,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')).dx, 0); }); - testWidgets('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', + testWidgetsWithLeakTracking('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { final List items = [0, 1, 2, 3]; final GlobalKey listKey = GlobalKey(); @@ -573,7 +574,7 @@ void main() { }); }); - testWidgets( + testWidgetsWithLeakTracking( 'AnimatedGrid.of() and maybeOf called with a context that does not contain AnimatedGrid', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -618,7 +619,7 @@ void main() { }, ); - testWidgets('AnimatedGrid.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedGrid.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { const Clip clipBehavior = Clip.none; await tester.pumpWidget( @@ -647,7 +648,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).clipBehavior, clipBehavior); }); - testWidgets('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart b/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart index 0ccd25107435e..75de31aea77d4 100644 --- a/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart +++ b/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async { RenderTestObject.paintCount = 0; await tester.pumpWidget( ColoredBox( diff --git a/packages/flutter/test/widgets/animated_list_test.dart b/packages/flutter/test/widgets/animated_list_test.dart index 6e585c9fcd2dc..ea74d98636b7b 100644 --- a/packages/flutter/test/widgets/animated_list_test.dart +++ b/packages/flutter/test/widgets/animated_list_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('SliverAnimatedList.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAnimatedList.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -47,7 +48,7 @@ void main() { expect(finderCalled, true); }); - testWidgets('AnimatedList', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList', (WidgetTester tester) async { Widget builder(BuildContext context, int index, Animation animation) { return SizedBox( height: 100.0, @@ -126,7 +127,7 @@ void main() { }); group('SliverAnimatedList', () { - testWidgets('initialItemCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialItemCount', (WidgetTester tester) async { final Map> animations = >{}; await tester.pumpWidget( @@ -159,7 +160,7 @@ void main() { expect(animations[1]!.value, 1.0); }); - testWidgets('insert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insert', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -245,7 +246,7 @@ void main() { }); // Test for insertAllItems with SliverAnimatedList - testWidgets('insertAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insertAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -302,7 +303,7 @@ void main() { }); // Test for removeAllItems with SliverAnimatedList - testWidgets('remove', (WidgetTester tester) async { + testWidgetsWithLeakTracking('remove', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -379,7 +380,7 @@ void main() { }); // Test for removeAllItems with SliverAnimatedList - testWidgets('removeAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removeAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -429,7 +430,7 @@ void main() { expect(find.text('item 2'), findsNothing); }); - testWidgets('works in combination with other slivers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in combination with other slivers', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -494,7 +495,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')).dy, 200); }); - testWidgets('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { final List items = [0, 1, 2, 3]; final GlobalKey listKey = GlobalKey(); @@ -556,7 +557,7 @@ void main() { }); }); - testWidgets( + testWidgetsWithLeakTracking( 'AnimatedList.of() and maybeOf called with a context that does not contain AnimatedList', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -601,7 +602,7 @@ void main() { }, ); - testWidgets('AnimatedList.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { const Clip clipBehavior = Clip.none; await tester.pumpWidget( @@ -625,7 +626,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).clipBehavior, clipBehavior); }); - testWidgets('AnimatedList.shrinkwrap is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList.shrinkwrap is forwarded to its inner CustomScrollView', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/115040 final ScrollController controller = ScrollController(); await tester.pumpWidget( @@ -650,7 +651,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).shrinkWrap, true); }); - testWidgets('AnimatedList applies MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList applies MediaQuery padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_opacity_repaint_test.dart b/packages/flutter/test/widgets/animated_opacity_repaint_test.dart index d3ce05edd2938..76badefaa5896 100644 --- a/packages/flutter/test/widgets/animated_opacity_repaint_test.dart +++ b/packages/flutter/test/widgets/animated_opacity_repaint_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('RenderAnimatedOpacityMixin does not drop layer when animating to 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin does not drop layer when animating to 1', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0, end: 1); @@ -40,7 +41,7 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgets('RenderAnimatedOpacityMixin avoids repainting child as it animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin avoids repainting child as it animates', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0, end: 0.99); // Layer is dropped at 1 @@ -73,7 +74,7 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgets('RenderAnimatedOpacityMixin allows opacity layer to be disposed when animating to 0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin allows opacity layer to be disposed when animating to 0 opacity', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0.99, end: 0); diff --git a/packages/flutter/test/widgets/animated_padding_test.dart b/packages/flutter/test/widgets/animated_padding_test.dart index e8cd37f1073e2..8542efdfd6113 100644 --- a/packages/flutter/test/widgets/animated_padding_test.dart +++ b/packages/flutter/test/widgets/animated_padding_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedPadding.debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding.debugFillProperties', (WidgetTester tester) async { final AnimatedPadding padding = AnimatedPadding( padding: const EdgeInsets.all(7.0), curve: Curves.ease, @@ -16,7 +17,7 @@ void main() { expect(padding, hasOneLineDescription); }); - testWidgets('AnimatedPadding padding visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding padding visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -58,7 +59,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(700.0, 0.0)); }); - testWidgets('AnimatedPadding animated padding clamped to positive values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding animated padding clamped to positive values', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_positioned_test.dart b/packages/flutter/test/widgets/animated_positioned_test.dart index f1a794069a4ce..8d3b5efe73faf 100644 --- a/packages/flutter/test/widgets/animated_positioned_test.dart +++ b/packages/flutter/test/widgets/animated_positioned_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedPositioned.fromRect control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned.fromRect control test', (WidgetTester tester) async { final AnimatedPositioned positioned = AnimatedPositioned.fromRect( rect: const Rect.fromLTWH(7.0, 5.0, 12.0, 16.0), duration: const Duration(milliseconds: 200), @@ -20,7 +21,7 @@ void main() { expect(positioned, hasOneLineDescription); }); - testWidgets('AnimatedPositioned - basics (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned - basics (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -102,7 +103,7 @@ void main() { ); }); - testWidgets('AnimatedPositionedDirectional - basics (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - basics (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -188,7 +189,7 @@ void main() { ); }); - testWidgets('AnimatedPositionedDirectional - basics (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - basics (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -274,7 +275,7 @@ void main() { ); }); - testWidgets('AnimatedPositioned - interrupted animation (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned - interrupted animation (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -357,7 +358,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(200.0, 200.0))); }); - testWidgets('AnimatedPositioned - switching variables (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned - switching variables (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -416,7 +417,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(350.0, 150.0))); }); - testWidgets('AnimatedPositionedDirectional - interrupted animation (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - interrupted animation (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -505,7 +506,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(200.0, 200.0))); }); - testWidgets('AnimatedPositionedDirectional - switching variables (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - switching variables (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -568,7 +569,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(350.0, 150.0))); }); - testWidgets('AnimatedPositionedDirectional - interrupted animation (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - interrupted animation (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -657,7 +658,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(600.0, 200.0))); }); - testWidgets('AnimatedPositionedDirectional - switching variables (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - switching variables (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; From 792e26df9540cf2cf510ea0c11a53ba10a243424 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier <101587250+pbo-linaro@users.noreply.github.com> Date: Thu, 31 Aug 2023 18:09:02 +0200 Subject: [PATCH 1013/1547] [Windows] Add target architecture to build path (#131843) To implement windows-arm64 support, it is needed to add architecture as a subdirectory (https://github.com/flutter/flutter/issues/129805). In short, when performing a flutter windows build, we have: - Before: build/windows/runner/Release/gallery.exe - After: build/windows/x64/runner/Release/gallery.exe This convention follows what flutter linux build does. Addresses: https://github.com/flutter/flutter/issues/129805 Addresses: https://github.com/flutter/flutter/issues/116196 Design doc: [flutter.dev/go/windows-arm64](https://flutter.dev/go/windows-arm64) --- .../windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/CMakeLists.txt | 7 +- dev/devicelab/lib/tasks/perf_tests.dart | 2 + dev/devicelab/lib/tasks/plugin_tests.dart | 2 +- dev/devicelab/lib/tasks/run_tests.dart | 4 +- .../windows/flutter/CMakeLists.txt | 8 +- .../ui/windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/CMakeLists.txt | 8 +- examples/api/windows/flutter/CMakeLists.txt | 8 +- .../windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/CMakeLists.txt | 7 +- .../layers/windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/CMakeLists.txt | 7 +- .../windows/flutter/CMakeLists.txt | 7 +- .../flutter_tools/lib/src/build_info.dart | 5 +- .../lib/src/windows/application_package.dart | 2 +- .../lib/src/windows/build_windows.dart | 26 +- .../build_architecture_migration.dart | 126 ++++++++ .../windows.tmpl/flutter/CMakeLists.txt | 7 +- .../hermetic/build_windows_test.dart | 42 +-- .../build_architecture_migration_test.dart | 299 ++++++++++++++++++ .../flutter_build_windows_test.dart | 1 + 23 files changed, 563 insertions(+), 40 deletions(-) create mode 100644 packages/flutter_tools/lib/src/windows/migrations/build_architecture_migration.dart create mode 100644 packages/flutter_tools/test/general.shard/windows/migrations/build_architecture_migration_test.dart diff --git a/dev/a11y_assessments/windows/flutter/CMakeLists.txt b/dev/a11y_assessments/windows/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/dev/a11y_assessments/windows/flutter/CMakeLists.txt +++ b/dev/a11y_assessments/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/dev/benchmarks/complex_layout/windows/flutter/CMakeLists.txt b/dev/benchmarks/complex_layout/windows/flutter/CMakeLists.txt index 10873dd1af99c..c8f7abf1ebea9 100644 --- a/dev/benchmarks/complex_layout/windows/flutter/CMakeLists.txt +++ b/dev/benchmarks/complex_layout/windows/flutter/CMakeLists.txt @@ -14,6 +14,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -96,7 +101,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 792cb51f352c8..80706c6e2c6e7 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -894,6 +894,7 @@ class StartupTest { testDirectory, 'build', 'windows', + 'x64', 'runner', 'Profile', '$basename.exe' @@ -1645,6 +1646,7 @@ class CompileTest { cwd, 'build', 'windows', + 'x64', 'runner', 'release', '$basename.exe'); diff --git a/dev/devicelab/lib/tasks/plugin_tests.dart b/dev/devicelab/lib/tasks/plugin_tests.dart index 4ef09183a8b11..5b0aeae53db99 100644 --- a/dev/devicelab/lib/tasks/plugin_tests.dart +++ b/dev/devicelab/lib/tasks/plugin_tests.dart @@ -294,7 +294,7 @@ public class $pluginClass: NSObject, FlutterPlugin { } case 'windows': if (await exec( - path.join(rootPath, 'build', 'windows', 'plugins', 'plugintest', 'Release', 'plugintest_test.exe'), + path.join(rootPath, 'build', 'windows', 'x64', 'plugins', 'plugintest', 'Release', 'plugintest_test.exe'), [], canFail: true, ) != 0) { diff --git a/dev/devicelab/lib/tasks/run_tests.dart b/dev/devicelab/lib/tasks/run_tests.dart index f7a41169e3004..a5c6f8c7547b3 100644 --- a/dev/devicelab/lib/tasks/run_tests.dart +++ b/dev/devicelab/lib/tasks/run_tests.dart @@ -178,7 +178,7 @@ class WindowsRunOutputTest extends DesktopRunOutputTest { multiLine: true, ); static final RegExp _builtOutput = RegExp( - r'Built build\\windows\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.', + r'Built build\\windows\\x64\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.', ); @override @@ -205,7 +205,7 @@ class WindowsRunOutputTest extends DesktopRunOutputTest { return true; }, - 'Built build\\windows\\runner\\$buildMode\\app.exe', + 'Built build\\windows\\x64\\runner\\$buildMode\\app.exe', ); } } diff --git a/dev/integration_tests/flutter_gallery/windows/flutter/CMakeLists.txt b/dev/integration_tests/flutter_gallery/windows/flutter/CMakeLists.txt index b2e4bd8d658b2..903f4899d6fce 100644 --- a/dev/integration_tests/flutter_gallery/windows/flutter/CMakeLists.txt +++ b/dev/integration_tests/flutter_gallery/windows/flutter/CMakeLists.txt @@ -1,3 +1,4 @@ +# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") @@ -9,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -91,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/dev/integration_tests/ui/windows/flutter/CMakeLists.txt b/dev/integration_tests/ui/windows/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/dev/integration_tests/ui/windows/flutter/CMakeLists.txt +++ b/dev/integration_tests/ui/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt b/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt +++ b/dev/integration_tests/windows_startup_test/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/dev/manual_tests/windows/flutter/CMakeLists.txt b/dev/manual_tests/windows/flutter/CMakeLists.txt index b2e4bd8d658b2..903f4899d6fce 100644 --- a/dev/manual_tests/windows/flutter/CMakeLists.txt +++ b/dev/manual_tests/windows/flutter/CMakeLists.txt @@ -1,3 +1,4 @@ +# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") @@ -9,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -91,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/examples/api/windows/flutter/CMakeLists.txt b/examples/api/windows/flutter/CMakeLists.txt index b2e4bd8d658b2..903f4899d6fce 100644 --- a/examples/api/windows/flutter/CMakeLists.txt +++ b/examples/api/windows/flutter/CMakeLists.txt @@ -1,3 +1,4 @@ +# This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") @@ -9,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -91,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/examples/flutter_view/windows/flutter/CMakeLists.txt b/examples/flutter_view/windows/flutter/CMakeLists.txt index 10873dd1af99c..c8f7abf1ebea9 100644 --- a/examples/flutter_view/windows/flutter/CMakeLists.txt +++ b/examples/flutter_view/windows/flutter/CMakeLists.txt @@ -14,6 +14,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -96,7 +101,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/examples/hello_world/windows/flutter/CMakeLists.txt b/examples/hello_world/windows/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/examples/hello_world/windows/flutter/CMakeLists.txt +++ b/examples/hello_world/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/examples/layers/windows/flutter/CMakeLists.txt b/examples/layers/windows/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/examples/layers/windows/flutter/CMakeLists.txt +++ b/examples/layers/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/examples/platform_channel/windows/flutter/CMakeLists.txt b/examples/platform_channel/windows/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/examples/platform_channel/windows/flutter/CMakeLists.txt +++ b/examples/platform_channel/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/examples/platform_view/windows/flutter/CMakeLists.txt b/examples/platform_view/windows/flutter/CMakeLists.txt index 10873dd1af99c..c8f7abf1ebea9 100644 --- a/examples/platform_view/windows/flutter/CMakeLists.txt +++ b/examples/platform_view/windows/flutter/CMakeLists.txt @@ -14,6 +14,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -96,7 +101,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 5dcc2948b1688..7c3455d116341 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -872,8 +872,9 @@ String getLinuxBuildDirectory([TargetPlatform? targetPlatform]) { } /// Returns the Windows build output directory. -String getWindowsBuildDirectory() { - return globals.fs.path.join(getBuildDirectory(), 'windows'); +String getWindowsBuildDirectory(TargetPlatform targetPlatform) { + final String arch = targetPlatform.simpleName; + return globals.fs.path.join(getBuildDirectory(), 'windows', arch); } /// Returns the Fuchsia build output directory. diff --git a/packages/flutter_tools/lib/src/windows/application_package.dart b/packages/flutter_tools/lib/src/windows/application_package.dart index bd38ece9ccc0b..a5b3cb6c80ac2 100644 --- a/packages/flutter_tools/lib/src/windows/application_package.dart +++ b/packages/flutter_tools/lib/src/windows/application_package.dart @@ -111,7 +111,7 @@ class BuildableWindowsApp extends WindowsApp { String executable(BuildMode buildMode) { final String? binaryName = getCmakeExecutableName(project); return globals.fs.path.join( - getWindowsBuildDirectory(), + getWindowsBuildDirectory(TargetPlatform.windows_x64), 'runner', sentenceCase(buildMode.cliName), '$binaryName.exe', diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index a665856d0cc45..5d88dddef5fed 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -18,6 +18,7 @@ import '../convert.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; +import 'migrations/build_architecture_migration.dart'; import 'migrations/show_window_migration.dart'; import 'migrations/version_migration.dart'; import 'visual_studio.dart'; @@ -52,10 +53,17 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { 'to learn about adding Windows support to a project.'); } + // TODO(pbo-linaro): Add support for windows-arm64 platform, https://github.com/flutter/flutter/issues/129807 + const TargetPlatform targetPlatform = TargetPlatform.windows_x64; + final Directory buildDirectory = globals.fs.directory( + getWindowsBuildDirectory(targetPlatform) + ); + final List migrators = [ CmakeCustomCommandMigration(windowsProject, globals.logger), VersionMigration(windowsProject, globals.logger), ShowWindowMigration(windowsProject, globals.logger), + BuildArchitectureMigration(windowsProject, buildDirectory, globals.logger), ]; final ProjectMigration migration = ProjectMigration(migrators); @@ -79,7 +87,6 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { } final String buildModeName = buildInfo.mode.cliName; - final Directory buildDirectory = globals.fs.directory(getWindowsBuildDirectory()); final Status status = globals.logger.startProgress( 'Building Windows application...', ); @@ -89,6 +96,7 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { generator: cmakeGenerator, buildDir: buildDirectory, sourceDir: windowsProject.cmakeFile.parent, + targetPlatform: targetPlatform, ); if (visualStudio.displayVersion == '17.1.0') { _fixBrokenCmakeGeneration(buildDirectory); @@ -124,7 +132,11 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { aotSnapshot: codeSizeFile, // This analysis is only supported for release builds. outputDirectory: globals.fs.directory( - globals.fs.path.join(getWindowsBuildDirectory(), 'runner', 'Release'), + globals.fs.path.join( + buildDirectory.path, + 'runner', + 'Release' + ), ), precompilerTrace: precompilerTrace, type: 'windows', @@ -153,11 +165,18 @@ Future _runCmakeGeneration({ required String generator, required Directory buildDir, required Directory sourceDir, + required TargetPlatform targetPlatform, }) async { + if (targetPlatform != TargetPlatform.windows_x64) { + throwToolExit('Windows build supports only x64 target architecture'); + } + final Stopwatch sw = Stopwatch()..start(); await buildDir.create(recursive: true); int result; + const String arch = 'x64'; + const String flutterTargetPlatform = 'windows-x64'; try { result = await globals.processUtils.stream( [ @@ -168,6 +187,9 @@ Future _runCmakeGeneration({ buildDir.path, '-G', generator, + '-A', + arch, + '-DFLUTTER_TARGET_PLATFORM=$flutterTargetPlatform', ], trace: true, ); diff --git a/packages/flutter_tools/lib/src/windows/migrations/build_architecture_migration.dart b/packages/flutter_tools/lib/src/windows/migrations/build_architecture_migration.dart new file mode 100644 index 0000000000000..442ade5c3ace8 --- /dev/null +++ b/packages/flutter_tools/lib/src/windows/migrations/build_architecture_migration.dart @@ -0,0 +1,126 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../../base/file_system.dart'; +import '../../base/project_migrator.dart'; +import '../../cmake_project.dart'; +import 'utils.dart'; + +const String _cmakeFileToolBackendBefore = r''' +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +'''; + +const String _cmakeFileToolBackendAfter = r''' +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +'''; + +const String _cmakeFileTargetPlatformBefore = r''' +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +'''; + +const String _cmakeFileTargetPlatformAfter = r''' +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +'''; + +/// Migrates Windows build to target specific architecture. +/// In more, it deletes old runner folder +class BuildArchitectureMigration extends ProjectMigrator { + BuildArchitectureMigration( + WindowsProject project, + Directory buildDirectory, + super.logger + ) + : _cmakeFile = project.managedCmakeFile, + _buildDirectory = buildDirectory; + + final File _cmakeFile; + final Directory _buildDirectory; + + @override + void migrate() { + final Directory oldRunnerDirectory = _buildDirectory + .parent + .childDirectory('runner'); + if (oldRunnerDirectory.existsSync()) { + logger.printTrace(''' +Deleting previous build folder ${oldRunnerDirectory.path}. +New binaries can be found in ${_buildDirectory.childDirectory('runner').path}. +'''); + try { + oldRunnerDirectory.deleteSync(recursive: true); + } on FileSystemException catch (error) { + logger.printError( + 'Failed to remove ${oldRunnerDirectory.path}: $error. ' + 'A program may still be using a file in the directory or the directory itself. ' + 'To find and stop such a program, see: ' + 'https://superuser.com/questions/1333118/cant-delete-empty-folder-because-it-is-used' + ); + } + } + + // Skip this migration if the affected file does not exist. This indicates + // the app has done non-trivial changes to its runner and this migration + // might not work as expected if applied. + if (!_cmakeFile.existsSync()) { + logger.printTrace(''' +windows/flutter/CMakeLists.txt file not found, skipping build architecture migration. + +This indicates non-trivial changes have been made to the "windows" folder. +If needed, you can reset it by deleting the "windows" folder and then using the +"flutter create --platforms=windows ." command. +'''); + return; + } + + // Migrate the windows/flutter/CMakeLists.txt file. + final String originalCmakeContents = _cmakeFile.readAsStringSync(); + final String cmakeContentsWithTargetPlatform = replaceFirst( + originalCmakeContents, + _cmakeFileTargetPlatformBefore, + _cmakeFileTargetPlatformAfter, + ); + final String newCmakeContents = replaceFirst( + cmakeContentsWithTargetPlatform, + _cmakeFileToolBackendBefore, + _cmakeFileToolBackendAfter, + ); + if (originalCmakeContents != newCmakeContents) { + logger.printStatus('windows/flutter/CMakeLists.txt does not use FLUTTER_TARGET_PLATFORM, updating.'); + _cmakeFile.writeAsStringSync(newCmakeContents); + } + } +} diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt b/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt index 930d2071a324e..903f4899d6fce 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index 4dbed14f96ced..f77e830ebdb23 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -82,9 +82,12 @@ void main() { '-S', fileSystem.path.absolute(fileSystem.path.dirname(buildFilePath)), '-B', - r'build\windows', + r'build\windows\x64', '-G', generator, + '-A', + 'x64', + '-DFLUTTER_TARGET_PLATFORM=windows-x64', ], onRun: onRun, ); @@ -100,7 +103,7 @@ void main() { command: [ _cmakePath, '--build', - r'build\windows', + r'build\windows\x64', '--config', buildMode, ...['--target', 'INSTALL'], @@ -222,21 +225,21 @@ Microsoft (R) Build Engine version 16.6.0+5ff7b0c9e for .NET Framework Copyright (C) Microsoft Corporation. All rights reserved. Checking Build System - Generating C:/foo/windows/flutter/ephemeral/flutter_windows.dll, [etc], _phony_ - Building Custom Rule C:/foo/windows/flutter/CMakeLists.txt + Generating C:/foo/windows/x64/flutter/ephemeral/flutter_windows.dll, [etc], _phony_ + Building Custom Rule C:/foo/windows/x64/flutter/CMakeLists.txt standard_codec.cc Generating Code... - flutter_wrapper_plugin.vcxproj -> C:\foo\build\windows\flutter\Debug\flutter_wrapper_plugin.lib -C:\foo\windows\runner\main.cpp(18): error C2220: the following warning is treated as an error [C:\foo\build\windows\runner\test.vcxproj] -C:\foo\windows\runner\main.cpp(18): warning C4706: assignment within conditional expression [C:\foo\build\windows\runner\test.vcxproj] -main.obj : error LNK2019: unresolved external symbol "void __cdecl Bar(void)" (?Bar@@YAXXZ) referenced in function wWinMain [C:\foo\build\windows\runner\test.vcxproj] -C:\foo\build\windows\runner\Debug\test.exe : fatal error LNK1120: 1 unresolved externals [C:\foo\build\windows\runner\test.vcxproj] - Building Custom Rule C:/foo/windows/runner/CMakeLists.txt + flutter_wrapper_plugin.vcxproj -> C:\foo\build\windows\x64\flutter\Debug\flutter_wrapper_plugin.lib +C:\foo\windows\x64\runner\main.cpp(18): error C2220: the following warning is treated as an error [C:\foo\build\windows\x64\runner\test.vcxproj] +C:\foo\windows\x64\runner\main.cpp(18): warning C4706: assignment within conditional expression [C:\foo\build\windows\x64\runner\test.vcxproj] +main.obj : error LNK2019: unresolved external symbol "void __cdecl Bar(void)" (?Bar@@YAXXZ) referenced in function wWinMain [C:\foo\build\windows\x64\runner\test.vcxproj] +C:\foo\build\windows\x64\runner\Debug\test.exe : fatal error LNK1120: 1 unresolved externals [C:\foo\build\windows\x64\runner\test.vcxproj] + Building Custom Rule C:/foo/windows/x64/runner/CMakeLists.txt flutter_window.cpp main.cpp -C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier [C:\foo\build\windows\runner\test.vcxproj] +C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier [C:\foo\build\windows\x64\runner\test.vcxproj] -- Install configuration: "Debug" - -- Installing: C:/foo/build/windows/runner/Debug/data/icudtl.dat + -- Installing: C:/foo/build/windows/x64/runner/Debug/data/icudtl.dat '''; processManager = FakeProcessManager.list([ @@ -251,11 +254,11 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier ); // Just the warnings and errors should be surfaced. expect(testLogger.errorText, r''' -C:\foo\windows\runner\main.cpp(18): error C2220: the following warning is treated as an error [C:\foo\build\windows\runner\test.vcxproj] -C:\foo\windows\runner\main.cpp(18): warning C4706: assignment within conditional expression [C:\foo\build\windows\runner\test.vcxproj] -main.obj : error LNK2019: unresolved external symbol "void __cdecl Bar(void)" (?Bar@@YAXXZ) referenced in function wWinMain [C:\foo\build\windows\runner\test.vcxproj] -C:\foo\build\windows\runner\Debug\test.exe : fatal error LNK1120: 1 unresolved externals [C:\foo\build\windows\runner\test.vcxproj] -C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier [C:\foo\build\windows\runner\test.vcxproj] +C:\foo\windows\x64\runner\main.cpp(18): error C2220: the following warning is treated as an error [C:\foo\build\windows\x64\runner\test.vcxproj] +C:\foo\windows\x64\runner\main.cpp(18): warning C4706: assignment within conditional expression [C:\foo\build\windows\x64\runner\test.vcxproj] +main.obj : error LNK2019: unresolved external symbol "void __cdecl Bar(void)" (?Bar@@YAXXZ) referenced in function wWinMain [C:\foo\build\windows\x64\runner\test.vcxproj] +C:\foo\build\windows\x64\runner\Debug\test.exe : fatal error LNK1120: 1 unresolved externals [C:\foo\build\windows\x64\runner\test.vcxproj] +C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier [C:\foo\build\windows\x64\runner\test.vcxproj] '''); }, overrides: { FileSystem: () => fileSystem, @@ -311,7 +314,7 @@ C:\foo\windows\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identifier - + Generating some files setlocal "C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -E env FOO=bar C:/src/flutter/packages/flutter_tools/bin/tool_backend.bat windows-x64 Debug @@ -391,6 +394,7 @@ if %errorlevel% neq 0 goto :VCEnd final File assembleProject = fileSystem.currentDirectory .childDirectory('build') .childDirectory('windows') + .childDirectory('x64') .childDirectory('flutter') .childFile('flutter_assemble.vcxproj'); assembleProject.createSync(recursive: true); @@ -892,7 +896,7 @@ if %errorlevel% neq 0 goto :VCEnd ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); - fileSystem.file(r'build\windows\runner\Release\app.so') + fileSystem.file(r'build\windows\x64\runner\Release\app.so') ..createSync(recursive: true) ..writeAsBytesSync(List.generate(10000, (int index) => 0)); diff --git a/packages/flutter_tools/test/general.shard/windows/migrations/build_architecture_migration_test.dart b/packages/flutter_tools/test/general.shard/windows/migrations/build_architecture_migration_test.dart new file mode 100644 index 0000000000000..0cc1e9d7873b5 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/windows/migrations/build_architecture_migration_test.dart @@ -0,0 +1,299 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/cmake_project.dart'; +import 'package:flutter_tools/src/windows/migrations/build_architecture_migration.dart'; +import 'package:test/fake.dart'; + +import '../../../src/common.dart'; + +void main () { + group('Windows Flutter build architecture migration', () { + late MemoryFileSystem memoryFileSystem; + late BufferLogger testLogger; + late FakeWindowsProject mockProject; + late File cmakeFile; + late Directory buildDirectory; + + setUp(() { + memoryFileSystem = MemoryFileSystem.test(); + cmakeFile = memoryFileSystem.file('CMakeLists.txt'); + buildDirectory = memoryFileSystem.directory('x64'); + + testLogger = BufferLogger( + terminal: Terminal.test(), + outputPreferences: OutputPreferences.test(), + ); + + mockProject = FakeWindowsProject(cmakeFile); + }); + + testWithoutContext('delete old runner directory', () { + buildDirectory.createSync(); + final Directory oldRunnerDirectory = + buildDirectory + .parent + .childDirectory('runner'); + oldRunnerDirectory.createSync(); + final File executable = oldRunnerDirectory.childFile('program.exe'); + executable.createSync(); + expect(oldRunnerDirectory.existsSync(), isTrue); + + final BuildArchitectureMigration migration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + migration.migrate(); + + expect(oldRunnerDirectory.existsSync(), isFalse); + expect(testLogger.traceText, + contains( + 'Deleting previous build folder ./runner.\n' + 'New binaries can be found in x64/runner.\n' + ) + ); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if CMake file is missing', () { + final BuildArchitectureMigration migration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + migration.migrate(); + expect(cmakeFile.existsSync(), isFalse); + + expect(testLogger.traceText, + contains('windows/flutter/CMakeLists.txt file not found, skipping build architecture migration')); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if nothing to migrate', () { + const String cmakeFileContents = 'Nothing to migrate'; + + cmakeFile.writeAsStringSync(cmakeFileContents); + + final DateTime cmakeUpdatedAt = cmakeFile.lastModifiedSync(); + + final BuildArchitectureMigration buildArchitectureMigration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + buildArchitectureMigration.migrate(); + + expect(cmakeFile.lastModifiedSync(), cmakeUpdatedAt); + expect(cmakeFile.readAsStringSync(), cmakeFileContents); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if already migrated', () { + const String cmakeFileContents = + '# TODO: Move the rest of this into files in ephemeral. See\n' + '# https://github.com/flutter/flutter/issues/57146.\n' + 'set(WRAPPER_ROOT "\${EPHEMERAL_DIR}/cpp_client_wrapper")\n' + '\n' + '# Set fallback configurations for older versions of the flutter tool.\n' + 'if (NOT DEFINED FLUTTER_TARGET_PLATFORM)\n' + ' set(FLUTTER_TARGET_PLATFORM "windows-x64")\n' + 'endif()\n' + '\n' + '# === Flutter Library ===\n' + '...\n' + 'add_custom_command(\n' + ' OUTPUT \${FLUTTER_LIBRARY} \${FLUTTER_LIBRARY_HEADERS}\n' + ' \${CPP_WRAPPER_SOURCES_CORE} \${CPP_WRAPPER_SOURCES_PLUGIN}\n' + ' \${CPP_WRAPPER_SOURCES_APP}\n' + ' \${PHONY_OUTPUT}\n' + ' COMMAND \${CMAKE_COMMAND} -E env\n' + ' \${FLUTTER_TOOL_ENVIRONMENT}\n' + ' "\${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"\n' + ' \${FLUTTER_TARGET_PLATFORM} \$\n' + ' VERBATIM\n' + ')\n'; + + cmakeFile.writeAsStringSync(cmakeFileContents); + + final DateTime cmakeUpdatedAt = cmakeFile.lastModifiedSync(); + + final BuildArchitectureMigration buildArchitectureMigration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + buildArchitectureMigration.migrate(); + + expect(cmakeFile.lastModifiedSync(), cmakeUpdatedAt); + expect(cmakeFile.readAsStringSync(), cmakeFileContents); + + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if already migrated (CRLF)', () { + const String cmakeFileContents = + '# TODO: Move the rest of this into files in ephemeral. See\r\n' + '# https://github.com/flutter/flutter/issues/57146.\r\n' + 'set(WRAPPER_ROOT "\${EPHEMERAL_DIR}/cpp_client_wrapper")\r\n' + '\r\n' + '# Set fallback configurations for older versions of the flutter tool.\r\n' + 'if (NOT DEFINED FLUTTER_TARGET_PLATFORM)\r\n' + ' set(FLUTTER_TARGET_PLATFORM "windows-x64")\r\n' + 'endif()\r\n' + '\r\n' + '# === Flutter Library ===\r\n' + '...\r\n' + 'add_custom_command(\r\n' + ' OUTPUT \${FLUTTER_LIBRARY} \${FLUTTER_LIBRARY_HEADERS}\r\n' + ' \${CPP_WRAPPER_SOURCES_CORE} \${CPP_WRAPPER_SOURCES_PLUGIN}\r\n' + ' \${CPP_WRAPPER_SOURCES_APP}\r\n' + ' \${PHONY_OUTPUT}\r\n' + ' COMMAND \${CMAKE_COMMAND} -E env\r\n' + ' \${FLUTTER_TOOL_ENVIRONMENT}\r\n' + ' "\${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"\r\n' + ' \${FLUTTER_TARGET_PLATFORM} \$\r\n' + ' VERBATIM\r\n' + ')\r\n'; + + cmakeFile.writeAsStringSync(cmakeFileContents); + + final DateTime cmakeUpdatedAt = cmakeFile.lastModifiedSync(); + + final BuildArchitectureMigration buildArchitectureMigration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + buildArchitectureMigration.migrate(); + + expect(cmakeFile.lastModifiedSync(), cmakeUpdatedAt); + expect(cmakeFile.readAsStringSync(), cmakeFileContents); + + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('migrates project to set the target platform', () { + cmakeFile.writeAsStringSync( + '# TODO: Move the rest of this into files in ephemeral. See\n' + '# https://github.com/flutter/flutter/issues/57146.\n' + 'set(WRAPPER_ROOT "\${EPHEMERAL_DIR}/cpp_client_wrapper")\n' + '\n' + '# === Flutter Library ===\n' + '...\n' + 'add_custom_command(\n' + ' OUTPUT \${FLUTTER_LIBRARY} \${FLUTTER_LIBRARY_HEADERS}\n' + ' \${CPP_WRAPPER_SOURCES_CORE} \${CPP_WRAPPER_SOURCES_PLUGIN}\n' + ' \${CPP_WRAPPER_SOURCES_APP}\n' + ' \${PHONY_OUTPUT}\n' + ' COMMAND \${CMAKE_COMMAND} -E env\n' + ' \${FLUTTER_TOOL_ENVIRONMENT}\n' + ' "\${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"\n' + ' windows-x64 \$\n' + ' VERBATIM\n' + ')\n' + ); + final BuildArchitectureMigration buildArchitectureMigration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + buildArchitectureMigration.migrate(); + + expect(cmakeFile.readAsStringSync(), + '# TODO: Move the rest of this into files in ephemeral. See\n' + '# https://github.com/flutter/flutter/issues/57146.\n' + 'set(WRAPPER_ROOT "\${EPHEMERAL_DIR}/cpp_client_wrapper")\n' + '\n' + '# Set fallback configurations for older versions of the flutter tool.\n' + 'if (NOT DEFINED FLUTTER_TARGET_PLATFORM)\n' + ' set(FLUTTER_TARGET_PLATFORM "windows-x64")\n' + 'endif()\n' + '\n' + '# === Flutter Library ===\n' + '...\n' + 'add_custom_command(\n' + ' OUTPUT \${FLUTTER_LIBRARY} \${FLUTTER_LIBRARY_HEADERS}\n' + ' \${CPP_WRAPPER_SOURCES_CORE} \${CPP_WRAPPER_SOURCES_PLUGIN}\n' + ' \${CPP_WRAPPER_SOURCES_APP}\n' + ' \${PHONY_OUTPUT}\n' + ' COMMAND \${CMAKE_COMMAND} -E env\n' + ' \${FLUTTER_TOOL_ENVIRONMENT}\n' + ' "\${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"\n' + ' \${FLUTTER_TARGET_PLATFORM} \$\n' + ' VERBATIM\n' + ')\n' + ); + + expect(testLogger.statusText, contains('windows/flutter/CMakeLists.txt does not use FLUTTER_TARGET_PLATFORM, updating.')); + }); + + testWithoutContext('migrates project to set the target platform (CRLF)', () { + cmakeFile.writeAsStringSync( + '# TODO: Move the rest of this into files in ephemeral. See\r\n' + '# https://github.com/flutter/flutter/issues/57146.\r\n' + 'set(WRAPPER_ROOT "\${EPHEMERAL_DIR}/cpp_client_wrapper")\r\n' + '\r\n' + '# === Flutter Library ===\r\n' + '...\r\n' + 'add_custom_command(\r\n' + ' OUTPUT \${FLUTTER_LIBRARY} \${FLUTTER_LIBRARY_HEADERS}\r\n' + ' \${CPP_WRAPPER_SOURCES_CORE} \${CPP_WRAPPER_SOURCES_PLUGIN}\r\n' + ' \${CPP_WRAPPER_SOURCES_APP}\r\n' + ' \${PHONY_OUTPUT}\r\n' + ' COMMAND \${CMAKE_COMMAND} -E env\r\n' + ' \${FLUTTER_TOOL_ENVIRONMENT}\r\n' + ' "\${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"\r\n' + ' windows-x64 \$\r\n' + ' VERBATIM\r\n' + ')\r\n' + ); + + final BuildArchitectureMigration buildArchitectureMigration = BuildArchitectureMigration( + mockProject, + buildDirectory, + testLogger, + ); + buildArchitectureMigration.migrate(); + + expect(cmakeFile.readAsStringSync(), + '# TODO: Move the rest of this into files in ephemeral. See\r\n' + '# https://github.com/flutter/flutter/issues/57146.\r\n' + 'set(WRAPPER_ROOT "\${EPHEMERAL_DIR}/cpp_client_wrapper")\r\n' + '\r\n' + '# Set fallback configurations for older versions of the flutter tool.\r\n' + 'if (NOT DEFINED FLUTTER_TARGET_PLATFORM)\r\n' + ' set(FLUTTER_TARGET_PLATFORM "windows-x64")\r\n' + 'endif()\r\n' + '\r\n' + '# === Flutter Library ===\r\n' + '...\r\n' + 'add_custom_command(\r\n' + ' OUTPUT \${FLUTTER_LIBRARY} \${FLUTTER_LIBRARY_HEADERS}\r\n' + ' \${CPP_WRAPPER_SOURCES_CORE} \${CPP_WRAPPER_SOURCES_PLUGIN}\r\n' + ' \${CPP_WRAPPER_SOURCES_APP}\r\n' + ' \${PHONY_OUTPUT}\r\n' + ' COMMAND \${CMAKE_COMMAND} -E env\r\n' + ' \${FLUTTER_TOOL_ENVIRONMENT}\r\n' + ' "\${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"\r\n' + ' \${FLUTTER_TARGET_PLATFORM} \$\r\n' + ' VERBATIM\r\n' + ')\r\n' + ); + + expect(testLogger.statusText, contains('windows/flutter/CMakeLists.txt does not use FLUTTER_TARGET_PLATFORM, updating.')); + }); + }); +} + +class FakeWindowsProject extends Fake implements WindowsProject { + FakeWindowsProject(this.managedCmakeFile); + + @override + final File managedCmakeFile; +} diff --git a/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart b/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart index c90a940e92d5d..d238bb226a75e 100644 --- a/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart +++ b/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart @@ -45,6 +45,7 @@ void main() { projectRoot.path, 'build', 'windows', + 'x64', 'runner', 'Release', )); From c57e4e79a2ed337fbd5943a11e1360492620c432 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 31 Aug 2023 11:46:02 -0500 Subject: [PATCH 1014/1547] Revert "Cover some test/widgets tests with leak tracking" (#133779) Reverts flutter/flutter#133767 Causing failures to Mac framework_tests_widgets and Linux framework_tests_widgets --- .../test/widgets/absorb_pointer_test.dart | 9 +- .../flutter/test/widgets/actions_test.dart | 96 ++++++++----------- packages/flutter/test/widgets/align_test.dart | 13 ++- .../test/widgets/animated_align_test.dart | 13 ++- .../test/widgets/animated_container_test.dart | 17 ++-- .../widgets/animated_cross_fade_test.dart | 23 +++-- .../test/widgets/animated_grid_test.dart | 25 +++-- .../animated_image_filtered_repaint_test.dart | 3 +- .../test/widgets/animated_list_test.dart | 27 +++--- .../animated_opacity_repaint_test.dart | 7 +- .../test/widgets/animated_padding_test.dart | 7 +- .../widgets/animated_positioned_test.dart | 21 ++-- 12 files changed, 118 insertions(+), 143 deletions(-) diff --git a/packages/flutter/test/widgets/absorb_pointer_test.dart b/packages/flutter/test/widgets/absorb_pointer_test.dart index afe8198a29ab2..6c2a88f58ca4a 100644 --- a/packages/flutter/test/widgets/absorb_pointer_test.dart +++ b/packages/flutter/test/widgets/absorb_pointer_test.dart @@ -4,12 +4,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgetsWithLeakTracking('AbsorbPointers do not block siblings', (WidgetTester tester) async { + testWidgets('AbsorbPointers do not block siblings', (WidgetTester tester) async { bool tapped = false; await tester.pumpWidget( Column( @@ -30,7 +29,7 @@ void main() { }); group('AbsorbPointer semantics', () { - testWidgetsWithLeakTracking('does not change semantics when not absorbing', (WidgetTester tester) async { + testWidgets('does not change semantics when not absorbing', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -57,7 +56,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('drops semantics when its ignoreSemantics is true', (WidgetTester tester) async { + testWidgets('drops semantics when its ignoreSemantics is true', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final UniqueKey key = UniqueKey(); await tester.pumpWidget( @@ -76,7 +75,7 @@ void main() { semantics.dispose(); }); - testWidgetsWithLeakTracking('ignores user interactions', (WidgetTester tester) async { + testWidgets('ignores user interactions', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index a5956f3118f67..b59f17f8eafc2 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -8,11 +8,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group(ActionDispatcher, () { - testWidgetsWithLeakTracking('ActionDispatcher invokes actions when asked.', (WidgetTester tester) async { + testWidgets('ActionDispatcher invokes actions when asked.', (WidgetTester tester) async { await tester.pumpWidget(Container()); bool invoked = false; const ActionDispatcher dispatcher = ActionDispatcher(); @@ -49,7 +48,7 @@ void main() { setUp(clear); - testWidgetsWithLeakTracking('Actions widget can invoke actions with default dispatcher', (WidgetTester tester) async { + testWidgets('Actions widget can invoke actions with default dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -76,7 +75,7 @@ void main() { expect(invoked, isTrue); }); - testWidgetsWithLeakTracking('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async { + testWidgets('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -103,7 +102,7 @@ void main() { expect(invoked, isTrue); }); - testWidgetsWithLeakTracking('maybeInvoke returns null when no action is found', (WidgetTester tester) async { + testWidgets('maybeInvoke returns null when no action is found', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -130,7 +129,7 @@ void main() { expect(invoked, isFalse); }); - testWidgetsWithLeakTracking('invoke throws when no action is found', (WidgetTester tester) async { + testWidgets('invoke throws when no action is found', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -157,7 +156,7 @@ void main() { expect(invoked, isFalse); }); - testWidgetsWithLeakTracking('Actions widget can invoke actions with custom dispatcher', (WidgetTester tester) async { + testWidgets('Actions widget can invoke actions with custom dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -188,7 +187,7 @@ void main() { expect(invokedIntent, equals(intent)); }); - testWidgetsWithLeakTracking('Actions can invoke actions in ancestor dispatcher', (WidgetTester tester) async { + testWidgets('Actions can invoke actions in ancestor dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -225,7 +224,7 @@ void main() { expect(invokedDispatcher.runtimeType, equals(TestDispatcher1)); }); - testWidgetsWithLeakTracking("Actions can invoke actions in ancestor dispatcher if a lower one isn't specified", (WidgetTester tester) async { + testWidgets("Actions can invoke actions in ancestor dispatcher if a lower one isn't specified", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -261,7 +260,7 @@ void main() { expect(invokedDispatcher.runtimeType, equals(TestDispatcher1)); }); - testWidgetsWithLeakTracking('Actions widget can be found with of', (WidgetTester tester) async { + testWidgets('Actions widget can be found with of', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final ActionDispatcher testDispatcher = TestDispatcher1(postInvoke: collect); @@ -278,7 +277,7 @@ void main() { expect(dispatcher, equals(testDispatcher)); }); - testWidgetsWithLeakTracking('Action can be found with find', (WidgetTester tester) async { + testWidgets('Action can be found with find', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final ActionDispatcher testDispatcher = TestDispatcher1(postInvoke: collect); bool invoked = false; @@ -325,7 +324,7 @@ void main() { expect(Actions.maybeFind(containerKey.currentContext!), isNull); }); - testWidgetsWithLeakTracking('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { + testWidgets('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -393,11 +392,9 @@ void main() { await buildTest(true); expect(hovering, isFalse); expect(focusing, isFalse); - - focusNode.dispose(); }); - testWidgetsWithLeakTracking('FocusableActionDetector changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgets('FocusableActionDetector changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MouseRegion( cursor: SystemMouseCursors.forbidden, @@ -430,7 +427,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden); }); - testWidgetsWithLeakTracking('Actions.invoke returns the value of Action.invoke', (WidgetTester tester) async { + testWidgets('Actions.invoke returns the value of Action.invoke', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final Object sentinel = Object(); bool invoked = false; @@ -461,7 +458,7 @@ void main() { expect(invoked, isTrue); }); - testWidgetsWithLeakTracking('ContextAction can return null', (WidgetTester tester) async { + testWidgets('ContextAction can return null', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); const TestIntent intent = TestIntent(); final TestContextAction testAction = TestContextAction(); @@ -488,7 +485,7 @@ void main() { expect(testAction.capturedContexts.single, containerKey.currentContext); }); - testWidgetsWithLeakTracking('Disabled actions stop propagation to an ancestor', (WidgetTester tester) async { + testWidgets('Disabled actions stop propagation to an ancestor', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -537,7 +534,7 @@ void main() { }); group('Listening', () { - testWidgetsWithLeakTracking('can listen to enabled state of Actions', (WidgetTester tester) async { + testWidgets('can listen to enabled state of Actions', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked1 = false; bool invoked2 = false; @@ -759,11 +756,7 @@ void main() { ); }); - tearDown(() async { - focusNode.dispose(); - }); - - testWidgetsWithLeakTracking('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { + testWidgets('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -797,7 +790,7 @@ void main() { expect(focusing, isFalse); }); - testWidgetsWithLeakTracking('FocusableActionDetector shows focus highlight appropriately when focused and disabled', (WidgetTester tester) async { + testWidgets('FocusableActionDetector shows focus highlight appropriately when focused and disabled', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -828,7 +821,7 @@ void main() { expect(focusing, isTrue); }); - testWidgetsWithLeakTracking('FocusableActionDetector can be used without callbacks', (WidgetTester tester) async { + testWidgets('FocusableActionDetector can be used without callbacks', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -862,7 +855,7 @@ void main() { expect(focusing, isFalse); }); - testWidgetsWithLeakTracking( + testWidgets( 'FocusableActionDetector can prevent its descendants from being focusable', (WidgetTester tester) async { final FocusNode buttonNode = FocusNode(debugLabel: 'Test'); @@ -903,22 +896,19 @@ void main() { buttonNode.requestFocus(); await tester.pump(); expect(buttonNode.hasFocus, isFalse); - - buttonNode.dispose(); }, ); - testWidgetsWithLeakTracking( + testWidgets( 'FocusableActionDetector can prevent its descendants from being traversable', (WidgetTester tester) async { final FocusNode buttonNode1 = FocusNode(debugLabel: 'Button Node 1'); final FocusNode buttonNode2 = FocusNode(debugLabel: 'Button Node 2'); - final FocusNode skipTraversalNode = FocusNode(skipTraversal: true); await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( - focusNode: skipTraversalNode, + focusNode: FocusNode(skipTraversal: true), child: Column( children: [ ElevatedButton( @@ -949,7 +939,7 @@ void main() { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( - focusNode: skipTraversalNode, + focusNode: FocusNode(skipTraversal: true), descendantsAreTraversable: false, child: Column( children: [ @@ -977,14 +967,10 @@ void main() { await tester.pump(); expect(buttonNode1.hasFocus, isTrue); expect(buttonNode2.hasFocus, isFalse); - - buttonNode1.dispose(); - buttonNode2.dispose(); - skipTraversalNode.dispose(); }, ); - testWidgetsWithLeakTracking('FocusableActionDetector can exclude Focus semantics', (WidgetTester tester) async { + testWidgets('FocusableActionDetector can exclude Focus semantics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( @@ -1090,7 +1076,7 @@ void main() { }); group('Action subclasses', () { - testWidgetsWithLeakTracking('CallbackAction passes correct intent when invoked.', (WidgetTester tester) async { + testWidgets('CallbackAction passes correct intent when invoked.', (WidgetTester tester) async { late Intent passedIntent; final TestAction action = TestAction(onInvoke: (Intent intent) { passedIntent = intent; @@ -1101,7 +1087,7 @@ void main() { expect(passedIntent, equals(intent)); }); - testWidgetsWithLeakTracking('VoidCallbackAction', (WidgetTester tester) async { + testWidgets('VoidCallbackAction', (WidgetTester tester) async { bool called = false; void testCallback() { called = true; @@ -1111,7 +1097,7 @@ void main() { action.invoke(intent); expect(called, isTrue); }); - testWidgetsWithLeakTracking('Base Action class default toKeyEventResult delegates to consumesKey', (WidgetTester tester) async { + testWidgets('Base Action class default toKeyEventResult delegates to consumesKey', (WidgetTester tester) async { expect( DefaultToKeyEventResultAction(consumesKey: false).toKeyEventResult(const DefaultToKeyEventResultIntent(), null), KeyEventResult.skipRemainingHandlers, @@ -1124,7 +1110,7 @@ void main() { }); group('Diagnostics', () { - testWidgetsWithLeakTracking('default Intent debugFillProperties', (WidgetTester tester) async { + testWidgets('default Intent debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); // ignore: invalid_use_of_protected_member @@ -1140,7 +1126,7 @@ void main() { expect(description, isEmpty); }); - testWidgetsWithLeakTracking('default Actions debugFillProperties', (WidgetTester tester) async { + testWidgets('default Actions debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Actions( @@ -1166,7 +1152,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Actions implements debugFillProperties', (WidgetTester tester) async { + testWidgets('Actions implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Actions( @@ -1205,7 +1191,7 @@ void main() { invokingContext = null; }); - testWidgetsWithLeakTracking('Basic usage', (WidgetTester tester) async { + testWidgets('Basic usage', (WidgetTester tester) async { late BuildContext invokingContext2; late BuildContext invokingContext3; await tester.pumpWidget( @@ -1270,7 +1256,7 @@ void main() { expect(invocations, ['action1.invoke']); }); - testWidgetsWithLeakTracking('Does not break after use', (WidgetTester tester) async { + testWidgets('Does not break after use', (WidgetTester tester) async { late BuildContext invokingContext2; late BuildContext invokingContext3; await tester.pumpWidget( @@ -1337,7 +1323,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Does not override if not overridable', (WidgetTester tester) async { + testWidgets('Does not override if not overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1380,7 +1366,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('The final override controls isEnabled', (WidgetTester tester) async { + testWidgets('The final override controls isEnabled', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1467,7 +1453,7 @@ void main() { expect(invocations, []); }); - testWidgetsWithLeakTracking('The override can choose to defer isActionEnabled to the overridable', (WidgetTester tester) async { + testWidgets('The override can choose to defer isActionEnabled to the overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1557,7 +1543,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Throws on infinite recursions', (WidgetTester tester) async { + testWidgets('Throws on infinite recursions', (WidgetTester tester) async { late StateSetter setState; BuildContext? action2LookupContext; await tester.pumpWidget( @@ -1616,7 +1602,7 @@ void main() { expect(exception?.toString(), contains('debugAssertIsEnabledMutuallyRecursive')); }); - testWidgetsWithLeakTracking('Throws on invoking invalid override', (WidgetTester tester) async { + testWidgets('Throws on invoking invalid override', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context) { @@ -1654,7 +1640,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Make an overridable action overridable', (WidgetTester tester) async { + testWidgets('Make an overridable action overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1710,7 +1696,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Overriding Actions can change the intent', (WidgetTester tester) async { + testWidgets('Overriding Actions can change the intent', (WidgetTester tester) async { final List newLogChannel = []; await tester.pumpWidget( Builder( @@ -1760,7 +1746,7 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Override non-context overridable Actions with a ContextAction', (WidgetTester tester) async { + testWidgets('Override non-context overridable Actions with a ContextAction', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1813,7 +1799,7 @@ void main() { expect(LogInvocationContextAction.invokeContext, invokingContext); }); - testWidgetsWithLeakTracking('Override a ContextAction with a regular Action', (WidgetTester tester) async { + testWidgets('Override a ContextAction with a regular Action', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { diff --git a/packages/flutter/test/widgets/align_test.dart b/packages/flutter/test/widgets/align_test.dart index 1a6e89f73f176..aa44e27bce1aa 100644 --- a/packages/flutter/test/widgets/align_test.dart +++ b/packages/flutter/test/widgets/align_test.dart @@ -4,10 +4,9 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('Align smoke test', (WidgetTester tester) async { + testWidgets('Align smoke test', (WidgetTester tester) async { await tester.pumpWidget( Align( alignment: const Alignment(0.50, 0.50), @@ -39,7 +38,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('Align control test (LTR)', (WidgetTester tester) async { + testWidgets('Align control test (LTR)', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: Align( @@ -63,7 +62,7 @@ void main() { expect(tester.getBottomRight(find.byType(SizedBox)).dx, 100.0); }); - testWidgetsWithLeakTracking('Align control test (RTL)', (WidgetTester tester) async { + testWidgets('Align control test (RTL)', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.rtl, child: Align( @@ -87,7 +86,7 @@ void main() { expect(tester.getBottomRight(find.byType(SizedBox)).dx, 100.0); }); - testWidgetsWithLeakTracking('Shrink wraps in finite space', (WidgetTester tester) async { + testWidgets('Shrink wraps in finite space', (WidgetTester tester) async { final GlobalKey alignKey = GlobalKey(); await tester.pumpWidget( SingleChildScrollView( @@ -106,7 +105,7 @@ void main() { expect(size.height, equals(10.0)); }); - testWidgetsWithLeakTracking('Align widthFactor', (WidgetTester tester) async { + testWidgets('Align widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -129,7 +128,7 @@ void main() { expect(box.size.width, equals(50.0)); }); - testWidgetsWithLeakTracking('Align heightFactor', (WidgetTester tester) async { + testWidgets('Align heightFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/animated_align_test.dart b/packages/flutter/test/widgets/animated_align_test.dart index 0d0331505abdc..032f2678654fb 100644 --- a/packages/flutter/test/widgets/animated_align_test.dart +++ b/packages/flutter/test/widgets/animated_align_test.dart @@ -4,10 +4,9 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('AnimatedAlign.debugFillProperties', (WidgetTester tester) async { + testWidgets('AnimatedAlign.debugFillProperties', (WidgetTester tester) async { const AnimatedAlign box = AnimatedAlign( alignment: Alignment.topCenter, curve: Curves.ease, @@ -16,7 +15,7 @@ void main() { expect(box, hasOneLineDescription); }); - testWidgetsWithLeakTracking('AnimatedAlign alignment visual-to-directional animation', (WidgetTester tester) async { + testWidgets('AnimatedAlign alignment visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -58,7 +57,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(800.0, 400.0)); }); - testWidgetsWithLeakTracking('AnimatedAlign widthFactor', (WidgetTester tester) async { + testWidgets('AnimatedAlign widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -83,7 +82,7 @@ void main() { expect(box.size.width, equals(50.0)); }); - testWidgetsWithLeakTracking('AnimatedAlign heightFactor', (WidgetTester tester) async { + testWidgets('AnimatedAlign heightFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -107,7 +106,7 @@ void main() { expect(box.size.height, equals( 50.0)); }); - testWidgetsWithLeakTracking('AnimatedAlign null height factor', (WidgetTester tester) async { + testWidgets('AnimatedAlign null height factor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -131,7 +130,7 @@ void main() { expect(box.size, equals(const Size(100.0, 100))); }); - testWidgetsWithLeakTracking('AnimatedAlign null widthFactor', (WidgetTester tester) async { + testWidgets('AnimatedAlign null widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/animated_container_test.dart b/packages/flutter/test/widgets/animated_container_test.dart index d25156a595762..6d40f450cd5c9 100644 --- a/packages/flutter/test/widgets/animated_container_test.dart +++ b/packages/flutter/test/widgets/animated_container_test.dart @@ -5,10 +5,9 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('AnimatedContainer.debugFillProperties', (WidgetTester tester) async { + testWidgets('AnimatedContainer.debugFillProperties', (WidgetTester tester) async { final AnimatedContainer container = AnimatedContainer( constraints: const BoxConstraints.tightFor(width: 17.0, height: 23.0), decoration: const BoxDecoration(color: Color(0xFF00FF00)), @@ -25,7 +24,7 @@ void main() { expect(container, hasOneLineDescription); }); - testWidgetsWithLeakTracking('AnimatedContainer control test', (WidgetTester tester) async { + testWidgets('AnimatedContainer control test', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const BoxDecoration decorationA = BoxDecoration( @@ -103,7 +102,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('AnimatedContainer overanimate test', (WidgetTester tester) async { + testWidgets('AnimatedContainer overanimate test', (WidgetTester tester) async { await tester.pumpWidget( AnimatedContainer( duration: const Duration(milliseconds: 200), @@ -140,7 +139,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgetsWithLeakTracking('AnimatedContainer padding visual-to-directional animation', (WidgetTester tester) async { + testWidgets('AnimatedContainer padding visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -182,7 +181,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(700.0, 0.0)); }); - testWidgetsWithLeakTracking('AnimatedContainer alignment visual-to-directional animation', (WidgetTester tester) async { + testWidgets('AnimatedContainer alignment visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -224,7 +223,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(800.0, 400.0)); }); - testWidgetsWithLeakTracking('Animation rerun', (WidgetTester tester) async { + testWidgets('Animation rerun', (WidgetTester tester) async { await tester.pumpWidget( Center( child: AnimatedContainer( @@ -292,7 +291,7 @@ void main() { expect(text.size.height, equals(100.0)); }); - testWidgetsWithLeakTracking('AnimatedContainer sets transformAlignment', (WidgetTester tester) async { + testWidgets('AnimatedContainer sets transformAlignment', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -340,7 +339,7 @@ void main() { expect(tester.getTopLeft(find.byKey(target)), const Offset(400.0, 300.0)); }); - testWidgetsWithLeakTracking('AnimatedContainer sets clipBehavior', (WidgetTester tester) async { + testWidgets('AnimatedContainer sets clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( AnimatedContainer( decoration: const BoxDecoration( diff --git a/packages/flutter/test/widgets/animated_cross_fade_test.dart b/packages/flutter/test/widgets/animated_cross_fade_test.dart index ee3f88b132b32..7a4ac09b49bd8 100644 --- a/packages/flutter/test/widgets/animated_cross_fade_test.dart +++ b/packages/flutter/test/widgets/animated_cross_fade_test.dart @@ -5,10 +5,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('AnimatedCrossFade test', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade test', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -62,7 +61,7 @@ void main() { expect(box.size.height, equals(150.0)); }); - testWidgetsWithLeakTracking('AnimatedCrossFade test showSecond', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade test showSecond', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -89,7 +88,7 @@ void main() { expect(box.size.height, equals(200.0)); }); - testWidgetsWithLeakTracking('AnimatedCrossFade alignment (VISUAL)', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade alignment (VISUAL)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -147,7 +146,7 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); }); - testWidgetsWithLeakTracking('AnimatedCrossFade alignment (LTR)', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade alignment (LTR)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -205,7 +204,7 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); }); - testWidgetsWithLeakTracking('AnimatedCrossFade alignment (RTL)', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade alignment (RTL)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -275,7 +274,7 @@ void main() { ); } - testWidgetsWithLeakTracking('AnimatedCrossFade preserves widget state', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade preserves widget state', (WidgetTester tester) async { await tester.pumpWidget(crossFadeWithWatcher()); _TickerWatchingWidgetState findState() => tester.state(find.byType(_TickerWatchingWidget)); @@ -288,7 +287,7 @@ void main() { } }); - testWidgetsWithLeakTracking('AnimatedCrossFade switches off TickerMode and semantics on faded out widget', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade switches off TickerMode and semantics on faded out widget', (WidgetTester tester) async { ExcludeSemantics findSemantics() { return tester.widget(find.descendant( of: find.byKey(const ValueKey(CrossFadeState.showFirst)), @@ -318,7 +317,7 @@ void main() { expect(findSemantics().excluding, true); }); - testWidgetsWithLeakTracking('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -362,7 +361,7 @@ void main() { expect(find.text('AAA'), findsNothing); }); - testWidgetsWithLeakTracking('AnimatedCrossFade test focus', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade test focus', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -386,7 +385,7 @@ void main() { expect(hiddenNode.hasPrimaryFocus, isFalse); }); - testWidgetsWithLeakTracking('AnimatedCrossFade bottom child can have focus', (WidgetTester tester) async { + testWidgets('AnimatedCrossFade bottom child can have focus', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -411,7 +410,7 @@ void main() { expect(hiddenNode.hasPrimaryFocus, isTrue); }); - testWidgetsWithLeakTracking('AnimatedCrossFade second child do not receive touch events', + testWidgets('AnimatedCrossFade second child do not receive touch events', (WidgetTester tester) async { int numberOfTouchEventNoticed = 0; diff --git a/packages/flutter/test/widgets/animated_grid_test.dart b/packages/flutter/test/widgets/animated_grid_test.dart index c03c7143febd1..dcec143a9e705 100644 --- a/packages/flutter/test/widgets/animated_grid_test.dart +++ b/packages/flutter/test/widgets/animated_grid_test.dart @@ -5,11 +5,10 @@ import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgetsWithLeakTracking('SliverAnimatedGrid.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgets('SliverAnimatedGrid.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -51,7 +50,7 @@ void main() { expect(finderCalled, true); }); - testWidgetsWithLeakTracking('AnimatedGrid', (WidgetTester tester) async { + testWidgets('AnimatedGrid', (WidgetTester tester) async { Widget builder(BuildContext context, int index, Animation animation) { return SizedBox( height: 100.0, @@ -133,7 +132,7 @@ void main() { }); group('SliverAnimatedGrid', () { - testWidgetsWithLeakTracking('initialItemCount', (WidgetTester tester) async { + testWidgets('initialItemCount', (WidgetTester tester) async { final Map> animations = >{}; await tester.pumpWidget( @@ -171,7 +170,7 @@ void main() { expect(animations[1]!.value, 1.0); }); - testWidgetsWithLeakTracking('insert', (WidgetTester tester) async { + testWidgets('insert', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -251,7 +250,7 @@ void main() { expect(itemRight(2), 300.0); }); - testWidgetsWithLeakTracking('insertAll', (WidgetTester tester) async { + testWidgets('insertAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -307,7 +306,7 @@ void main() { expect(itemRight(1), 200.0); }); - testWidgetsWithLeakTracking('remove', (WidgetTester tester) async { + testWidgets('remove', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -385,7 +384,7 @@ void main() { expect(itemRight(2), 200.0); }); - testWidgetsWithLeakTracking('removeAll', (WidgetTester tester) async { + testWidgets('removeAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -437,7 +436,7 @@ void main() { expect(find.text('item 2'), findsNothing); }); - testWidgetsWithLeakTracking('works in combination with other slivers', (WidgetTester tester) async { + testWidgets('works in combination with other slivers', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -506,7 +505,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')).dx, 0); }); - testWidgetsWithLeakTracking('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', + testWidgets('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { final List items = [0, 1, 2, 3]; final GlobalKey listKey = GlobalKey(); @@ -574,7 +573,7 @@ void main() { }); }); - testWidgetsWithLeakTracking( + testWidgets( 'AnimatedGrid.of() and maybeOf called with a context that does not contain AnimatedGrid', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -619,7 +618,7 @@ void main() { }, ); - testWidgetsWithLeakTracking('AnimatedGrid.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgets('AnimatedGrid.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { const Clip clipBehavior = Clip.none; await tester.pumpWidget( @@ -648,7 +647,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).clipBehavior, clipBehavior); }); - testWidgetsWithLeakTracking('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async { + testWidgets('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart b/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart index 75de31aea77d4..0ccd25107435e 100644 --- a/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart +++ b/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart @@ -7,10 +7,9 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async { + testWidgets('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async { RenderTestObject.paintCount = 0; await tester.pumpWidget( ColoredBox( diff --git a/packages/flutter/test/widgets/animated_list_test.dart b/packages/flutter/test/widgets/animated_list_test.dart index ea74d98636b7b..6e585c9fcd2dc 100644 --- a/packages/flutter/test/widgets/animated_list_test.dart +++ b/packages/flutter/test/widgets/animated_list_test.dart @@ -5,11 +5,10 @@ import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgetsWithLeakTracking('SliverAnimatedList.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgets('SliverAnimatedList.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -48,7 +47,7 @@ void main() { expect(finderCalled, true); }); - testWidgetsWithLeakTracking('AnimatedList', (WidgetTester tester) async { + testWidgets('AnimatedList', (WidgetTester tester) async { Widget builder(BuildContext context, int index, Animation animation) { return SizedBox( height: 100.0, @@ -127,7 +126,7 @@ void main() { }); group('SliverAnimatedList', () { - testWidgetsWithLeakTracking('initialItemCount', (WidgetTester tester) async { + testWidgets('initialItemCount', (WidgetTester tester) async { final Map> animations = >{}; await tester.pumpWidget( @@ -160,7 +159,7 @@ void main() { expect(animations[1]!.value, 1.0); }); - testWidgetsWithLeakTracking('insert', (WidgetTester tester) async { + testWidgets('insert', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -246,7 +245,7 @@ void main() { }); // Test for insertAllItems with SliverAnimatedList - testWidgetsWithLeakTracking('insertAll', (WidgetTester tester) async { + testWidgets('insertAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -303,7 +302,7 @@ void main() { }); // Test for removeAllItems with SliverAnimatedList - testWidgetsWithLeakTracking('remove', (WidgetTester tester) async { + testWidgets('remove', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -380,7 +379,7 @@ void main() { }); // Test for removeAllItems with SliverAnimatedList - testWidgetsWithLeakTracking('removeAll', (WidgetTester tester) async { + testWidgets('removeAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -430,7 +429,7 @@ void main() { expect(find.text('item 2'), findsNothing); }); - testWidgetsWithLeakTracking('works in combination with other slivers', (WidgetTester tester) async { + testWidgets('works in combination with other slivers', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -495,7 +494,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')).dy, 200); }); - testWidgetsWithLeakTracking('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { + testWidgets('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { final List items = [0, 1, 2, 3]; final GlobalKey listKey = GlobalKey(); @@ -557,7 +556,7 @@ void main() { }); }); - testWidgetsWithLeakTracking( + testWidgets( 'AnimatedList.of() and maybeOf called with a context that does not contain AnimatedList', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -602,7 +601,7 @@ void main() { }, ); - testWidgetsWithLeakTracking('AnimatedList.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgets('AnimatedList.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { const Clip clipBehavior = Clip.none; await tester.pumpWidget( @@ -626,7 +625,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).clipBehavior, clipBehavior); }); - testWidgetsWithLeakTracking('AnimatedList.shrinkwrap is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgets('AnimatedList.shrinkwrap is forwarded to its inner CustomScrollView', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/115040 final ScrollController controller = ScrollController(); await tester.pumpWidget( @@ -651,7 +650,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).shrinkWrap, true); }); - testWidgetsWithLeakTracking('AnimatedList applies MediaQuery padding', (WidgetTester tester) async { + testWidgets('AnimatedList applies MediaQuery padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_opacity_repaint_test.dart b/packages/flutter/test/widgets/animated_opacity_repaint_test.dart index 76badefaa5896..d3ce05edd2938 100644 --- a/packages/flutter/test/widgets/animated_opacity_repaint_test.dart +++ b/packages/flutter/test/widgets/animated_opacity_repaint_test.dart @@ -5,10 +5,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin does not drop layer when animating to 1', (WidgetTester tester) async { + testWidgets('RenderAnimatedOpacityMixin does not drop layer when animating to 1', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0, end: 1); @@ -41,7 +40,7 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin avoids repainting child as it animates', (WidgetTester tester) async { + testWidgets('RenderAnimatedOpacityMixin avoids repainting child as it animates', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0, end: 0.99); // Layer is dropped at 1 @@ -74,7 +73,7 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin allows opacity layer to be disposed when animating to 0 opacity', (WidgetTester tester) async { + testWidgets('RenderAnimatedOpacityMixin allows opacity layer to be disposed when animating to 0 opacity', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0.99, end: 0); diff --git a/packages/flutter/test/widgets/animated_padding_test.dart b/packages/flutter/test/widgets/animated_padding_test.dart index 8542efdfd6113..e8cd37f1073e2 100644 --- a/packages/flutter/test/widgets/animated_padding_test.dart +++ b/packages/flutter/test/widgets/animated_padding_test.dart @@ -4,10 +4,9 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('AnimatedPadding.debugFillProperties', (WidgetTester tester) async { + testWidgets('AnimatedPadding.debugFillProperties', (WidgetTester tester) async { final AnimatedPadding padding = AnimatedPadding( padding: const EdgeInsets.all(7.0), curve: Curves.ease, @@ -17,7 +16,7 @@ void main() { expect(padding, hasOneLineDescription); }); - testWidgetsWithLeakTracking('AnimatedPadding padding visual-to-directional animation', (WidgetTester tester) async { + testWidgets('AnimatedPadding padding visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -59,7 +58,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(700.0, 0.0)); }); - testWidgetsWithLeakTracking('AnimatedPadding animated padding clamped to positive values', (WidgetTester tester) async { + testWidgets('AnimatedPadding animated padding clamped to positive values', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_positioned_test.dart b/packages/flutter/test/widgets/animated_positioned_test.dart index 8d3b5efe73faf..f1a794069a4ce 100644 --- a/packages/flutter/test/widgets/animated_positioned_test.dart +++ b/packages/flutter/test/widgets/animated_positioned_test.dart @@ -4,10 +4,9 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('AnimatedPositioned.fromRect control test', (WidgetTester tester) async { + testWidgets('AnimatedPositioned.fromRect control test', (WidgetTester tester) async { final AnimatedPositioned positioned = AnimatedPositioned.fromRect( rect: const Rect.fromLTWH(7.0, 5.0, 12.0, 16.0), duration: const Duration(milliseconds: 200), @@ -21,7 +20,7 @@ void main() { expect(positioned, hasOneLineDescription); }); - testWidgetsWithLeakTracking('AnimatedPositioned - basics (VISUAL)', (WidgetTester tester) async { + testWidgets('AnimatedPositioned - basics (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -103,7 +102,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('AnimatedPositionedDirectional - basics (LTR)', (WidgetTester tester) async { + testWidgets('AnimatedPositionedDirectional - basics (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -189,7 +188,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('AnimatedPositionedDirectional - basics (RTL)', (WidgetTester tester) async { + testWidgets('AnimatedPositionedDirectional - basics (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -275,7 +274,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('AnimatedPositioned - interrupted animation (VISUAL)', (WidgetTester tester) async { + testWidgets('AnimatedPositioned - interrupted animation (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -358,7 +357,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(200.0, 200.0))); }); - testWidgetsWithLeakTracking('AnimatedPositioned - switching variables (VISUAL)', (WidgetTester tester) async { + testWidgets('AnimatedPositioned - switching variables (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -417,7 +416,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(350.0, 150.0))); }); - testWidgetsWithLeakTracking('AnimatedPositionedDirectional - interrupted animation (LTR)', (WidgetTester tester) async { + testWidgets('AnimatedPositionedDirectional - interrupted animation (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -506,7 +505,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(200.0, 200.0))); }); - testWidgetsWithLeakTracking('AnimatedPositionedDirectional - switching variables (LTR)', (WidgetTester tester) async { + testWidgets('AnimatedPositionedDirectional - switching variables (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -569,7 +568,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(350.0, 150.0))); }); - testWidgetsWithLeakTracking('AnimatedPositionedDirectional - interrupted animation (RTL)', (WidgetTester tester) async { + testWidgets('AnimatedPositionedDirectional - interrupted animation (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -658,7 +657,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(600.0, 200.0))); }); - testWidgetsWithLeakTracking('AnimatedPositionedDirectional - switching variables (RTL)', (WidgetTester tester) async { + testWidgets('AnimatedPositionedDirectional - switching variables (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; From a14989b3bf7fb5499e34239b25b90b76ff60074f Mon Sep 17 00:00:00 2001 From: yusuf-goog <91688203+yusuf-goog@users.noreply.github.com> Date: Thu, 31 Aug 2023 10:16:05 -0700 Subject: [PATCH 1015/1547] Tweaking CSS to make object docs more legible. (#133711) Bug:None *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- dev/docs/assets/overrides.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dev/docs/assets/overrides.css b/dev/docs/assets/overrides.css index 14758845f9e9f..c4e441bf8cb01 100644 --- a/dev/docs/assets/overrides.css +++ b/dev/docs/assets/overrides.css @@ -30,6 +30,15 @@ section.summary h2 { border-bottom: none; } +section.summary .name { + font-size: 1.5em; + margin-right: 0.2em; +} + +section.summary .returntype { + font-style:italic; +} + pre { margin: 0 0 15px 0; padding: 8px 12px; From 54402ae37516d775ea196699c9216067c7178824 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 31 Aug 2023 10:18:04 -0700 Subject: [PATCH 1016/1547] _ResetNotifier should communicate creation in constructor. (#133716) --- .../flutter/lib/src/widgets/draggable_scrollable_sheet.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 0a63839619d86..8b2012f903a49 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -1056,6 +1056,11 @@ class DraggableScrollableActuator extends StatelessWidget { /// A [ChangeNotifier] to use with [InheritedResetNotifier] to notify /// descendants that they should reset to initial state. class _ResetNotifier extends ChangeNotifier { + _ResetNotifier() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } /// Whether someone called [sendReset] or not. /// /// This flag should be reset after checking it. From c1256d535371e360886f4dc9faebb82e91e02934 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 31 Aug 2023 10:18:19 -0700 Subject: [PATCH 1017/1547] _FocusTraversalGroupNode should communicate creation in constructor. (#133717) --- packages/flutter/lib/src/widgets/focus_traversal.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 9cafbca24d6cf..203e13252958d 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -1784,7 +1784,11 @@ class _FocusTraversalGroupNode extends FocusNode { _FocusTraversalGroupNode({ super.debugLabel, required this.policy, - }); + }) { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } FocusTraversalPolicy policy; } From 127b90e1dee2d1f8a1a05d132a4574f9870264d5 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 31 Aug 2023 10:19:13 -0700 Subject: [PATCH 1018/1547] Test cover more tests with leak tracking. (#133712) --- .../adaptive_text_selection_toolbar_test.dart | 20 +++++++++----- .../flutter/test/material/app_bar_test.dart | 2 +- .../test/material/autocomplete_test.dart | 27 +++++++++---------- .../test/material/button_bar_test.dart | 4 +-- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart index 6313af09cd11c..4a3c51ee5b652 100644 --- a/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/adaptive_text_selection_toolbar_test.dart @@ -111,8 +111,10 @@ void main() { expect(find.byKey(key), findsOneWidget); }); - testWidgets('Can build from EditableTextState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can build from EditableTextState', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + final TextEditingController controller = TextEditingController(); + final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -120,9 +122,9 @@ void main() { child: SizedBox( width: 400, child: EditableText( - controller: TextEditingController(), + controller: controller, backgroundCursorColor: const Color(0xff00ffff), - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(), cursorColor: const Color(0xff00ffff), selectionControls: materialTextSelectionHandleControls, @@ -170,6 +172,8 @@ void main() { case TargetPlatform.macOS: expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsOneWidget); } + controller.dispose(); + focusNode.dispose(); }, skip: kIsWeb, // [intended] on web the browser handles the context menu. variant: TargetPlatformVariant.all(), @@ -233,13 +237,14 @@ void main() { ); group('buttonItems', () { - testWidgets('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getEditableTextButtonItems builds the correct button items per-platform', (WidgetTester tester) async { // Fill the clipboard so that the Paste option is available in the text // selection menu. await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); Set buttonTypes = {}; final TextEditingController controller = TextEditingController(); + final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MaterialApp( @@ -248,7 +253,7 @@ void main() { child: EditableText( controller: controller, backgroundCursorColor: Colors.grey, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.red, selectionControls: materialTextSelectionHandleControls, @@ -323,12 +328,15 @@ void main() { case TargetPlatform.macOS: expect(buttonTypes, isNot(contains(ContextMenuButtonType.selectAll))); } + + focusNode.dispose(); + controller.dispose(); }, variant: TargetPlatformVariant.all(), skip: kIsWeb, // [intended] ); - testWidgets('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getAdaptiveButtons builds the correct button widgets per-platform', (WidgetTester tester) async { const String buttonText = 'Click me'; await tester.pumpWidget( diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 20b9df966e8fe..c37613731f1f3 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -3360,7 +3360,7 @@ void main() { expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0, 0, 100, 56)); }); - testWidgets("AppBar with EndDrawer doesn't have leading", (WidgetTester tester) async { + testWidgetsWithLeakTracking("AppBar with EndDrawer doesn't have leading", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( appBar: AppBar(), diff --git a/packages/flutter/test/material/autocomplete_test.dart b/packages/flutter/test/material/autocomplete_test.dart index e5509beb3c8ab..47c02c4e90842 100644 --- a/packages/flutter/test/material/autocomplete_test.dart +++ b/packages/flutter/test/material/autocomplete_test.dart @@ -47,7 +47,6 @@ void main() { ]; testWidgetsWithLeakTracking('can filter and select a list of string options', (WidgetTester tester) async { - late String lastSelection; await tester.pumpWidget( MaterialApp( @@ -107,7 +106,7 @@ void main() { expect(list.semanticChildCount, 6); }); - testWidgets('can filter and select a list of custom User options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can filter and select a list of custom User options', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -161,7 +160,7 @@ void main() { expect(list.semanticChildCount, 1); }); - testWidgets('displayStringForOption is displayed in the options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('displayStringForOption is displayed in the options', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -204,7 +203,7 @@ void main() { expect(field.controller!.text, kOptionsUsers.first.name); }); - testWidgets('can build a custom field', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can build a custom field', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -228,7 +227,7 @@ void main() { expect(find.byType(TextFormField), findsNothing); }); - testWidgets('can build custom options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can build custom options', (WidgetTester tester) async { final GlobalKey optionsKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -257,7 +256,7 @@ void main() { expect(find.byKey(optionsKey), findsOneWidget); }); - testWidgets('the default Autocomplete options widget has a maximum height of 200', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the default Autocomplete options widget has a maximum height of 200', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(home: Scaffold( body: Autocomplete( optionsBuilder: (TextEditingValue textEditingValue) { @@ -278,7 +277,7 @@ void main() { expect(resultingHeight, equals(200)); }); - testWidgets('the options height restricts to max desired height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the options height restricts to max desired height', (WidgetTester tester) async { const double desiredHeight = 150.0; await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -307,7 +306,7 @@ void main() { expect(resultingHeight, equals(desiredHeight)); }); - testWidgets('The height of options shrinks to height of resulting items, if less than maxHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The height of options shrinks to height of resulting items, if less than maxHeight', (WidgetTester tester) async { // Returns a Future with the height of the default [Autocomplete] options widget // after the provided text had been entered into the [Autocomplete] field. Future getDefaultOptionsHeight( @@ -355,7 +354,7 @@ void main() { expect(oneItemsHeight, lessThan(twoItemsHeight)); }); - testWidgets('initialValue sets initial text field value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialValue sets initial text field value', (WidgetTester tester) async { late String lastSelection; await tester.pumpWidget( MaterialApp( @@ -416,7 +415,7 @@ void main() { } } - testWidgets('keyboard navigation of the options properly highlights the option', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard navigation of the options properly highlights the option', (WidgetTester tester) async { const Color highlightColor = Color(0xFF112233); await tester.pumpWidget( MaterialApp( @@ -455,7 +454,7 @@ void main() { checkOptionHighlight(tester, 'elephant', highlightColor); }); - testWidgets('keyboard navigation keeps the highlighted option scrolled into view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard navigation keeps the highlighted option scrolled into view', (WidgetTester tester) async { const Color highlightColor = Color(0xFF112233); await tester.pumpWidget( MaterialApp( @@ -519,7 +518,7 @@ void main() { }); group('optionsViewOpenDirection', () { - testWidgets('default (down)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default (down)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -534,7 +533,7 @@ void main() { expect(actual, equals(OptionsViewOpenDirection.down)); }); - testWidgets('down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('down', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -550,7 +549,7 @@ void main() { expect(actual, equals(OptionsViewOpenDirection.down)); }); - testWidgets('up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('up', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/button_bar_test.dart b/packages/flutter/test/material/button_bar_test.dart index f7bb7768b3d6e..a04d9115de168 100644 --- a/packages/flutter/test/material/button_bar_test.dart +++ b/packages/flutter/test/material/button_bar_test.dart @@ -340,7 +340,7 @@ void main() { group('layoutBehavior', () { - testWidgets('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar has a min height of 52 when using ButtonBarLayoutBehavior.constrained', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( @@ -363,7 +363,7 @@ void main() { expect(tester.getBottomRight(buttonBar).dy - tester.getTopRight(buttonBar).dy, 52.0); }); - testWidgets('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonBar has padding applied when using ButtonBarLayoutBehavior.padded', (WidgetTester tester) async { await tester.pumpWidget( const SingleChildScrollView( child: ListBody( From 82ded60350a8458ccd23f06bb2979e7e80a46875 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 14:01:06 -0400 Subject: [PATCH 1019/1547] Roll Flutter Engine from e8de3dd63d47 to 51090e3cfe79 (2 revisions) (#133784) https://github.com/flutter/engine/compare/e8de3dd63d47...51090e3cfe79 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from a295ff96782a to d113402de2ce (1 revision) (flutter/engine#45324) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from a13a9d6efbbc to a295ff96782a (2 revisions) (flutter/engine#45321) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 28bcb26b1ec93..17994e10e9a21 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e8de3dd63d476e17c0204b9352f3516e0ac63faa +51090e3cfe79ff0b4fe7e83e041a4910c777004e From b51859ec330317c1468a78cb098d8920094089e3 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 31 Aug 2023 12:03:14 -0700 Subject: [PATCH 1020/1547] Add benchmark for scrolling very long pictures (#133434) This benchmark will track the performance of the RTree implementation to cull very large pictures down to just the portion visible on the screen. --- .ci.yaml | 20 ++ TESTOWNERS | 2 + .../macrobenchmarks/lib/common.dart | 1 + dev/benchmarks/macrobenchmarks/lib/main.dart | 9 + .../lib/src/very_long_picture_scrolling.dart | 240 ++++++++++++++++++ .../very_long_picture_scrolling_perf_e2e.dart | 36 +++ ...g_picture_scrolling_perf__e2e_summary.dart | 14 + ...cture_scrolling_perf_ios__e2e_summary.dart | 14 + dev/devicelab/lib/tasks/perf_tests.dart | 7 + 9 files changed, 343 insertions(+) create mode 100644 dev/benchmarks/macrobenchmarks/lib/src/very_long_picture_scrolling.dart create mode 100644 dev/benchmarks/macrobenchmarks/test/very_long_picture_scrolling_perf_e2e.dart create mode 100644 dev/devicelab/bin/tasks/very_long_picture_scrolling_perf__e2e_summary.dart create mode 100644 dev/devicelab/bin/tasks/very_long_picture_scrolling_perf_ios__e2e_summary.dart diff --git a/.ci.yaml b/.ci.yaml index dab1f17fb083c..5bb50095d5747 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2114,6 +2114,16 @@ targets: ["devicelab", "android", "linux"] task_name: fullscreen_textfield_perf__e2e_summary + - name: Linux_android very_long_picture_scrolling_perf__e2e_summary + recipe: devicelab/devicelab_drone + bringup: true + presubmit: false + timeout: 120 + properties: + tags: > + ["devicelab", "android", "linux"] + task_name: very_long_picture_scrolling_perf__e2e_summary + - name: Linux_android hello_world__memory recipe: devicelab/devicelab_drone presubmit: false @@ -4196,6 +4206,16 @@ targets: ["devicelab", "ios", "mac"] task_name: fullscreen_textfield_perf_ios__e2e_summary + - name: Mac_ios very_long_picture_scrolling_perf_ios__e2e_summary + recipe: devicelab/devicelab_drone + bringup: true + presubmit: false + timeout: 120 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: very_long_picture_scrolling_perf_ios__e2e_summary + - name: Mac_ios tiles_scroll_perf_ios__timeline_summary recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index ed1c75770836c..7da41d661c617 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -89,6 +89,7 @@ /dev/devicelab/bin/tasks/spell_check_test_ios.dart @camsim99 @flutter/android /dev/devicelab/bin/tasks/spell_check_test.dart @camsim99 @flutter/android /dev/devicelab/bin/tasks/textfield_perf__e2e_summary.dart @zanderso @flutter/engine +/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf__e2e_summary.dart @flar @flutter/engine /dev/devicelab/bin/tasks/web_size__compile_test.dart @yjbanov @flutter/web /dev/devicelab/bin/tasks/wide_gamut_ios.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/animated_advanced_blend_perf__timeline_summary.dart @gaaclarke @flutter/engine @@ -212,6 +213,7 @@ /dev/devicelab/bin/tasks/route_test_ios.dart @vashworth @flutter/tool /dev/devicelab/bin/tasks/simple_animation_perf_ios.dart @cyanglaz @flutter/engine /dev/devicelab/bin/tasks/tiles_scroll_perf_ios__timeline_summary.dart @cyanglaz @flutter/engine +/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf_ios__e2e_summary.dart @flar @flutter/engine /dev/devicelab/bin/tasks/animated_blur_backdrop_filter_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine /dev/devicelab/bin/tasks/draw_points_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine /dev/devicelab/bin/tasks/draw_vertices_perf_ios__timeline_summary.dart @jonahwilliams @flutter/engine diff --git a/dev/benchmarks/macrobenchmarks/lib/common.dart b/dev/benchmarks/macrobenchmarks/lib/common.dart index e347f1b9063f4..0b4b380799063 100644 --- a/dev/benchmarks/macrobenchmarks/lib/common.dart +++ b/dev/benchmarks/macrobenchmarks/lib/common.dart @@ -13,6 +13,7 @@ const String kLargeImageChangerRouteName = '/large_image_changer'; const String kLargeImagesRouteName = '/large_images'; const String kPathTessellationRouteName = '/path_tessellation'; const String kTextRouteName = '/text'; +const String kVeryLongPictureScrollingRouteName = '/very_long_picture_scrolling'; const String kFullscreenTextRouteName = '/fullscreen_text'; const String kAnimatedPlaceholderRouteName = '/animated_placeholder'; const String kClipperCacheRouteName = '/clipper_cache'; diff --git a/dev/benchmarks/macrobenchmarks/lib/main.dart b/dev/benchmarks/macrobenchmarks/lib/main.dart index 5cc99cda8e521..23ec7817c4f48 100644 --- a/dev/benchmarks/macrobenchmarks/lib/main.dart +++ b/dev/benchmarks/macrobenchmarks/lib/main.dart @@ -42,6 +42,7 @@ import 'src/simple_scroll.dart'; import 'src/sliders.dart'; import 'src/stack_size.dart'; import 'src/text.dart'; +import 'src/very_long_picture_scrolling.dart'; const String kMacrobenchmarks = 'Macrobenchmarks'; @@ -97,6 +98,7 @@ class MacrobenchmarksApp extends StatelessWidget { kDrawVerticesPageRouteName: (BuildContext context) => const DrawVerticesPage(), kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(), kAnimatedAdvancedBlend: (BuildContext context) => const AnimatedAdvancedBlend(), + kVeryLongPictureScrollingRouteName: (BuildContext context) => const VeryLongPictureScrollingPerf(), }, ); } @@ -373,6 +375,13 @@ class HomePage extends StatelessWidget { Navigator.pushNamed(context, kAnimatedAdvancedBlend); }, ), + ElevatedButton( + key: const Key(kVeryLongPictureScrollingRouteName), + child: const Text('Very Long Picture Scrolling'), + onPressed: () { + Navigator.pushNamed(context, kVeryLongPictureScrollingRouteName); + }, + ), ], ), ); diff --git a/dev/benchmarks/macrobenchmarks/lib/src/very_long_picture_scrolling.dart b/dev/benchmarks/macrobenchmarks/lib/src/very_long_picture_scrolling.dart new file mode 100644 index 0000000000000..fb6a7cf20b6a8 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/lib/src/very_long_picture_scrolling.dart @@ -0,0 +1,240 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math'; +import 'dart:typed_data'; +import 'dart:ui'; +import 'package:flutter/material.dart'; + +// Adapted from test case submitted in +// https://github.com/flutter/flutter/issues/92366 +// Converted to use fixed data rather than reading a waveform file +class VeryLongPictureScrollingPerf extends StatefulWidget { + const VeryLongPictureScrollingPerf({super.key}); + + @override + State createState() => VeryLongPictureScrollingPerfState(); +} + +class VeryLongPictureScrollingPerfState extends State { + bool consolidate = false; + bool useList = false; + Int16List waveData = loadGraph(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + actions: [ + Row( + children: [ + const Text('list:'), + Checkbox(value: useList, onChanged: (bool? value) => setState(() { + useList = value!; + }),), + ], + ), + Row( + children: [ + const Text('consolidate:'), + Checkbox(value: consolidate, onChanged: (bool? value) => setState(() { + consolidate = value!; + }),), + ], + ), + ], + ), + backgroundColor: Colors.transparent, + body: SizedBox( + width: MediaQuery.of(context).size.width, + height: MediaQuery.of(context).size.height, + child: useList + ? ListView.builder( + key: const ValueKey('vlp_list_view_scrollable'), + scrollDirection: Axis.horizontal, + clipBehavior: Clip.none, + itemCount: (waveData.length / 200).ceil(), + itemExtent: 100, + itemBuilder: (BuildContext context, int index) => CustomPaint( + painter: PaintSomeTest( + waveData: waveData, + from: index * 200, + to: min((index + 1) * 200, waveData.length - 1), + ) + ), + ) + : SingleChildScrollView( + key: const ValueKey('vlp_single_child_scrollable'), + scrollDirection: Axis.horizontal, + child: SizedBox( + width: MediaQuery.of(context).size.width * 20, + height: MediaQuery.of(context).size.height, + child: RepaintBoundary( + child: CustomPaint( + isComplex: true, + painter: PaintTest( + consolidate: consolidate, + waveData: waveData, + ), + ), + ), + ), + ), + ), + ); + } +} + +class PaintTest extends CustomPainter { + const PaintTest({ + required this.consolidate, + required this.waveData, + }); + + final bool consolidate; + final Int16List waveData; + + @override + void paint(Canvas canvas, Size size) { + final double height = size.height; + double x = 0; + const double strokeSize = .5; + const double zoomFactor = .5; + + final Paint paintPos = Paint() + ..color = Colors.pink + ..strokeWidth = strokeSize + ..isAntiAlias = false + ..style = PaintingStyle.stroke; + + final Paint paintNeg = Paint() + ..color = Colors.pink + ..strokeWidth = strokeSize + ..isAntiAlias = false + ..style = PaintingStyle.stroke; + + final Paint paintZero = Paint() + ..color = Colors.green + ..strokeWidth = strokeSize + ..isAntiAlias = false + ..style = PaintingStyle.stroke; + + int index = 0; + Paint? listPaint; + final Float32List offsets = Float32List(consolidate ? waveData.length * 4 : 4); + int used = 0; + for (index = 0; index < waveData.length; index++) { + Paint curPaint; + Offset p1; + if (waveData[index].isNegative) { + curPaint = paintPos; + p1 = Offset(x, height * 1 / 2 - waveData[index] / 32768 * (height / 2)); + } else if (waveData[index] == 0) { + curPaint = paintZero; + p1 = Offset(x, height * 1 / 2 + 1); + } else { + curPaint = (waveData[index] == 0) ? paintZero : paintNeg; + p1 = Offset(x, height * 1 / 2 - waveData[index] / 32767 * (height / 2)); + } + final Offset p0 = Offset(x, height * 1 / 2); + if (consolidate) { + if (listPaint != null && listPaint != curPaint) { + canvas.drawRawPoints(PointMode.lines, offsets.sublist(0, used), listPaint); + used = 0; + } + listPaint = curPaint; + offsets[used++] = p0.dx; + offsets[used++] = p0.dy; + offsets[used++] = p1.dx; + offsets[used++] = p1.dy; + } else { + canvas.drawLine(p0, p1, curPaint); + } + x += zoomFactor; + } + if (consolidate && used > 0) { + canvas.drawRawPoints(PointMode.lines, offsets.sublist(0, used), listPaint!); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return oldDelegate is! PaintTest || + oldDelegate.consolidate != consolidate || + oldDelegate.waveData != waveData; + } +} + +class PaintSomeTest extends CustomPainter { + const PaintSomeTest({ + required this.waveData, + int? from, + int? to, + }) : from = from ?? 0, to = to?? waveData.length; + + final Int16List waveData; + final int from; + final int to; + + @override + void paint(Canvas canvas, Size size) { + final double height = size.height; + double x = 0; + const double strokeSize = .5; + const double zoomFactor = .5; + + final Paint paintPos = Paint() + ..color = Colors.pink + ..strokeWidth = strokeSize + ..isAntiAlias = false + ..style = PaintingStyle.stroke; + + final Paint paintNeg = Paint() + ..color = Colors.pink + ..strokeWidth = strokeSize + ..isAntiAlias = false + ..style = PaintingStyle.stroke; + + final Paint paintZero = Paint() + ..color = Colors.green + ..strokeWidth = strokeSize + ..isAntiAlias = false + ..style = PaintingStyle.stroke; + + for (int index = from; index <= to; index++) { + Paint curPaint; + Offset p1; + if (waveData[index].isNegative) { + curPaint = paintPos; + p1 = Offset(x, height * 1 / 2 - waveData[index] / 32768 * (height / 2)); + } else if (waveData[index] == 0) { + curPaint = paintZero; + p1 = Offset(x, height * 1 / 2 + 1); + } else { + curPaint = (waveData[index] == 0) ? paintZero : paintNeg; + p1 = Offset(x, height * 1 / 2 - waveData[index] / 32767 * (height / 2)); + } + final Offset p0 = Offset(x, height * 1 / 2); + canvas.drawLine(p0, p1, curPaint); + x += zoomFactor; + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return oldDelegate is! PaintSomeTest || + oldDelegate.waveData != waveData || + oldDelegate.from != from || + oldDelegate.to != to; + } +} + +Int16List loadGraph() { + final Int16List waveData = Int16List(350000); + final Random r = Random(0x42); + for (int i = 0; i < waveData.length; i++) { + waveData[i] = r.nextInt(32768) - 16384; + } + return waveData; +} diff --git a/dev/benchmarks/macrobenchmarks/test/very_long_picture_scrolling_perf_e2e.dart b/dev/benchmarks/macrobenchmarks/test/very_long_picture_scrolling_perf_e2e.dart new file mode 100644 index 0000000000000..ff54e0cce6dd4 --- /dev/null +++ b/dev/benchmarks/macrobenchmarks/test/very_long_picture_scrolling_perf_e2e.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:macrobenchmarks/common.dart'; + +import 'util.dart'; + +void main() { + macroPerfTestE2E( + 'very_long_picture_scrolling_perf', + kVeryLongPictureScrollingRouteName, + pageDelay: const Duration(seconds: 1), + duration: const Duration(seconds: 30), + body: (WidgetController controller) async { + final Finder nestedScroll = find.byKey(const ValueKey('vlp_single_child_scrollable')); + expect(nestedScroll, findsOneWidget); + Future scrollOnce(double offset) async { + await controller.timedDrag( + nestedScroll, + Offset(offset, 0.0), + const Duration(milliseconds: 3500), + ); + await Future.delayed(const Duration(milliseconds: 500)); + } + for (int i = 0; i < 2; i += 1) { + await scrollOnce(-3000.0); + await scrollOnce(-3000.0); + await scrollOnce(3000.0); + await scrollOnce(3000.0); + } + }, + ); +} diff --git a/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf__e2e_summary.dart b/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf__e2e_summary.dart new file mode 100644 index 0000000000000..ef738f8510a79 --- /dev/null +++ b/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + await task(createVeryLongPictureScrollingPerfE2ETest(enableImpeller: false)); +} diff --git a/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf_ios__e2e_summary.dart b/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf_ios__e2e_summary.dart new file mode 100644 index 0000000000000..99e61f877fe74 --- /dev/null +++ b/dev/devicelab/bin/tasks/very_long_picture_scrolling_perf_ios__e2e_summary.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/perf_tests.dart'; + +Future main() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createVeryLongPictureScrollingPerfE2ETest(enableImpeller: false)); +} diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 80706c6e2c6e7..9018dfda43819 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -308,6 +308,13 @@ TaskFunction createTextfieldPerfE2ETest() { ).run; } +TaskFunction createVeryLongPictureScrollingPerfE2ETest({required bool enableImpeller}) { + return PerfTest.e2e( + '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', + 'test/very_long_picture_scrolling_perf_e2e.dart', + enableImpeller: enableImpeller, + ).run; +} TaskFunction createSlidersPerfTest() { return PerfTest( '${flutterDirectory.path}/dev/benchmarks/macrobenchmarks', From 8128b2e2f6e1e844ae43dd763a97731766e616d4 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:41:07 -0500 Subject: [PATCH 1021/1547] Run Mac_arm64_ios run_debug_test_macos in presubmit (#133788) Fixes https://github.com/flutter/flutter/issues/118830. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 5bb50095d5747..9924b985915c3 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4317,7 +4317,6 @@ targets: - name: Mac_arm64_ios run_debug_test_macos recipe: devicelab/devicelab_drone - presubmit: false # https://github.com/flutter/flutter/issues/118827 timeout: 60 properties: tags: > From f32b6fed24a265870d6f34011e90344e58dc9606 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 31 Aug 2023 22:49:06 +0300 Subject: [PATCH 1022/1547] Fix `cursorColor` with an opacity is not respected (#133548) fixes [`cursorColor` with an opacity is not respected](https://github.com/flutter/flutter/issues/132886)
    expand to view the code sample ```dart import "package:flutter/material.dart"; // import "package:flutter/scheduler.dart"; // final color = Colors.red; const color = Color(0x55ff0000); void main() { // timeDilation = 4; runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: Example(), ); } } class Example extends StatefulWidget { const Example({super.key}); @override State createState() => _ExampleState(); } class _ExampleState extends State { late FocusNode _focusNode; late TextEditingController _controller; @override void initState() { super.initState(); _focusNode = FocusNode(); _controller = TextEditingController(text: 'Hello World'); } @override void dispose() { _focusNode.dispose(); _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { const bool cursorOpacityAnimates = false; double cursorWidth = 6; return Scaffold( body: Center( child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16, ), child: Column( children: [ const Spacer(), const Text('EditableText'), const SizedBox(height: 8), InputDecorator( decoration: InputDecoration( border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), ), child: EditableText( cursorColor: color, cursorWidth: cursorWidth, cursorOpacityAnimates: cursorOpacityAnimates, focusNode: _focusNode, controller: _controller, style: Theme.of(context).textTheme.bodyLarge!, backgroundCursorColor: Colors.amber, onSubmitted: (String value) { // Add your code here. }, ), ), const Spacer(), const Text('TextField'), const SizedBox(height: 8), TextField( cursorColor: color, cursorWidth: cursorWidth, cursorOpacityAnimates: cursorOpacityAnimates, controller: _controller, focusNode: _focusNode, onSubmitted: (String value) { // Add your code here. }, ), const Spacer(), ], ), ), ), ); } } ```
    ### Before ![Screenshot 2023-08-29 at 14 57 57](https://github.com/flutter/flutter/assets/48603081/cd55bb74-23b8-4980-915d-f13dee22a50f) ### After ![Screenshot 2023-08-29 at 14 58 20](https://github.com/flutter/flutter/assets/48603081/c94af4e3-f24b-44e7-bbed-7c6c21e90f2a) --- .../lib/src/widgets/editable_text.dart | 8 +++++-- .../test/widgets/editable_text_test.dart | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 4136c2e7a5cae..f5287bf5bb9a0 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2219,7 +2219,10 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override bool get wantKeepAlive => widget.focusNode.hasFocus; - Color get _cursorColor => widget.cursorColor.withOpacity(_cursorBlinkOpacityController.value); + Color get _cursorColor { + final double effectiveOpacity = math.min(widget.cursorColor.alpha / 255.0, _cursorBlinkOpacityController.value); + return widget.cursorColor.withOpacity(effectiveOpacity); + } @override bool get cutEnabled { @@ -3873,7 +3876,8 @@ class EditableTextState extends State with AutomaticKeepAliveClien } void _onCursorColorTick() { - renderEditable.cursorColor = widget.cursorColor.withOpacity(_cursorBlinkOpacityController.value); + final double effectiveOpacity = math.min(widget.cursorColor.alpha / 255.0, _cursorBlinkOpacityController.value); + renderEditable.cursorColor = widget.cursorColor.withOpacity(effectiveOpacity); _cursorVisibilityNotifier.value = widget.showCursor && _cursorBlinkOpacityController.value > 0; } diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 776793e9939f2..4efaf4992cbdd 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -16657,6 +16657,30 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(calls, equals(kIsWeb ? 0 : 2)); }); }); + + testWidgets('Cursor color with an opacity is respected', (WidgetTester tester) async { + final GlobalKey key = GlobalKey(); + const double opacity = 0.55; + await tester.pumpWidget( + MaterialApp( + home: EditableText( + key: key, + cursorColor: cursorColor.withOpacity(opacity), + backgroundCursorColor: Colors.grey, + controller: TextEditingController(text: 'blah blah'), + focusNode: focusNode, + style: textStyle, + ), + ), + ); + + // Tap to show the cursor. + await tester.tap(find.byKey(key)); + await tester.pumpAndSettle(); + + final EditableTextState state = tester.state(find.byType(EditableText)); + expect(state.renderEditable.cursorColor, cursorColor.withOpacity(opacity)); + }); } class UnsettableController extends TextEditingController { From acdcbae78a6458f91cd03539ace73607c682f853 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Thu, 31 Aug 2023 13:42:52 -0700 Subject: [PATCH 1023/1547] Revert "Fixing memory leak in EditableTextState" (#133804) Reverts flutter/flutter#131377 reverting because of internal google testing failures b/298310760 --- packages/flutter/lib/src/widgets/editable_text.dart | 5 +---- .../test/material/text_selection_theme_test.dart | 13 ++++++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index f5287bf5bb9a0..afd29530f951a 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2125,7 +2125,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien late final Simulation _iosBlinkCursorSimulation = _DiscreteKeyFrameSimulation.iOSBlinkingCaret(); final ValueNotifier _cursorVisibilityNotifier = ValueNotifier(true); - late final ValueNotifier _debugCursorNotifier; final GlobalKey _editableKey = GlobalKey(); /// Detects whether the clipboard can paste. @@ -2793,7 +2792,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien _scrollController.addListener(_onEditableScroll); _cursorVisibilityNotifier.value = widget.showCursor; _spellCheckConfiguration = _inferSpellCheckConfiguration(widget.spellCheckConfiguration); - _debugCursorNotifier = ValueNotifier(widget.showCursor); } // Whether `TickerMode.of(context)` is true and animations (like blinking the @@ -2938,7 +2936,6 @@ class EditableTextState extends State with AutomaticKeepAliveClien @override void dispose() { - _debugCursorNotifier.dispose(); _internalScrollController?.dispose(); _currentAutofillScope?.unregister(autofillId); widget.controller.removeListener(_didChangeTextEditingValue); @@ -4860,7 +4857,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien cursorColor: _cursorColor, backgroundCursorColor: widget.backgroundCursorColor, showCursor: EditableText.debugDeterministicCursor - ? _debugCursorNotifier + ? ValueNotifier(widget.showCursor) : _cursorVisibilityNotifier, forceLine: widget.forceLine, readOnly: widget.readOnly, diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 2e628c562077c..4a990a5a0a5d0 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -167,7 +167,18 @@ void main() { await tester.pumpAndSettle(); final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); - }); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130469 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'ValueNotifier': 1, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, + 'ValueNotifier': 2, + '_InputBorderGap': 1, + }, + ), + ); testWidgets('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { const TextSelectionThemeData textSelectionTheme = TextSelectionThemeData( From 1519553bed28910b84d1e174fb662194b666db26 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Thu, 31 Aug 2023 14:06:47 -0700 Subject: [PATCH 1024/1547] [flutter_tools] print out the unzipping method used by update_dart_sdk.ps1 (#133364) in case there are future issues with unzipping the dart sdk, such as https://github.com/flutter/flutter/issues/132592, we should log out what tool we are using to try to extract the archive. --- bin/internal/update_dart_sdk.ps1 | 5 ++++- .../test/integration.shard/batch_entrypoint_test.dart | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index 2d0d0fc732d2f..9dbef7cf5c9ab 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -83,18 +83,21 @@ Catch { $ProgressPreference = $OriginalProgressPreference } -Write-Host "Expanding downloaded archive..." If (Get-Command 7z -errorAction SilentlyContinue) { + Write-Host "Expanding downloaded archive with 7z..." # The built-in unzippers are painfully slow. Use 7-Zip, if available. & 7z x $dartSdkZip "-o$cachePath" -bd | Out-Null } ElseIf (Get-Command 7za -errorAction SilentlyContinue) { + Write-Host "Expanding downloaded archive with 7za..." # Use 7-Zip's standalone version 7za.exe, if available. & 7za x $dartSdkZip "-o$cachePath" -bd | Out-Null } ElseIf (Get-Command Microsoft.PowerShell.Archive\Expand-Archive -errorAction SilentlyContinue) { + Write-Host "Expanding downloaded archive with PowerShell..." # Use PowerShell's built-in unzipper, if available (requires PowerShell 5+). $global:ProgressPreference='SilentlyContinue' Microsoft.PowerShell.Archive\Expand-Archive $dartSdkZip -DestinationPath $cachePath } Else { + Write-Host "Expanding downloaded archive with Windows..." # As last resort: fall back to the Windows GUI. $shell = New-Object -com shell.application $zip = $shell.NameSpace($dartSdkZip) diff --git a/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart index e360aa9a8f5a0..233f978a3ca36 100644 --- a/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart +++ b/packages/flutter_tools/test/integration.shard/batch_entrypoint_test.dart @@ -49,7 +49,8 @@ Future main() async { // See: https://github.com/flutter/flutter/issues/132592 expect(dartSdkStamp.existsSync(), true); expect(output, contains('Downloading Dart SDK from Flutter engine ...')); - expect(output, contains('Expanding downloaded archive...')); + // Do not assert on the exact unzipping method, as this could change on CI + expect(output, contains(RegExp(r'Expanding downloaded archive with (.*)...'))); expect(output, isNot(contains('Use the -Force parameter' /* Luke */))); }, skip: !platform.isWindows); // [intended] Only Windows uses the batch entrypoint From c263c56dc6f55872ef2e1d2ceab0c1d72d9f5527 Mon Sep 17 00:00:00 2001 From: Andrew Kolos Date: Thu, 31 Aug 2023 14:08:59 -0700 Subject: [PATCH 1025/1547] give --task-args option in `test_runner` a help description (#133791) Fixes https://github.com/flutter/flutter/issues/133790 Provides help text for the `--task-args` option of the `test_runner` devicelab command. The current help text is just copypasta from another option's help text --- dev/devicelab/lib/command/test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/devicelab/lib/command/test.dart b/dev/devicelab/lib/command/test.dart index 186999403fe3f..e656c8bad1e7d 100644 --- a/dev/devicelab/lib/command/test.dart +++ b/dev/devicelab/lib/command/test.dart @@ -13,7 +13,7 @@ class TestCommand extends Command { help: 'The name of a task listed under bin/tasks.\n' ' Example: complex_layout__start_up.\n'); argParser.addMultiOption('task-args', - help: 'The name of a task listed under bin/tasks.\n' + help: 'List of arguments to pass to the task.\n' 'For example, "--task-args build" is passed as "bin/task/task.dart --build"'); argParser.addOption( 'device-id', From e98d3929ca421ca11dcc7662f59e73e0a7d293bd Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:34:48 -0500 Subject: [PATCH 1026/1547] Revert "Run Mac_arm64_ios run_debug_test_macos in presubmit" (#133808) Reverts flutter/flutter#133788 Something is wrong with bot https://chromium-swarm.appspot.com/bot?id=flutter-devicelab-mac-38, it's unable to open the project in Xcode. Failing consistently. https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8771213845302282993/+/u/ios_debug_symbol_doctor/recover_with_120_second_timeout/stdout So reverting until we can get the bot fixed. --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 9924b985915c3..5bb50095d5747 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4317,6 +4317,7 @@ targets: - name: Mac_arm64_ios run_debug_test_macos recipe: devicelab/devicelab_drone + presubmit: false # https://github.com/flutter/flutter/issues/118827 timeout: 60 properties: tags: > From b4753c328d7575223dfc1e05c8e6f213527df5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:37:46 -0700 Subject: [PATCH 1027/1547] Improve doctor output on incomplete Visual Studio installation (#133390) Flutter doctor warns if the user is updating Visual Studio or has paused a Visual Studio update. The current output recommends reinstalling Visual Studio. This is unnecessary as the user should be able to use the Visual Studio Installer app to complete the installation: ![image](https://github.com/flutter/flutter/assets/737941/49547413-ece1-4214-a971-f512bc39419f) This message is covered by this existing test: https://github.com/flutter/flutter/blob/229b74d987720a0437039b6e44e13f20fb94ad51/packages/flutter_tools/test/general.shard/windows/visual_studio_validator_test.dart#L68-L81 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../lib/src/base/user_messages.dart | 3 +- .../windows/visual_studio_validator_test.dart | 54 +++++++++++-------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart index 00956fa00f28e..92e6feb285a61 100644 --- a/packages/flutter_tools/lib/src/base/user_messages.dart +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -239,7 +239,8 @@ class UserMessages { 'supported by Flutter yet.'; String get visualStudioNotLaunchable => 'The current Visual Studio installation is not launchable. Please reinstall Visual Studio.'; - String get visualStudioIsIncomplete => 'The current Visual Studio installation is incomplete. Please reinstall Visual Studio.'; + String get visualStudioIsIncomplete => 'The current Visual Studio installation is incomplete.\n' + 'Please use Visual Studio Installer to complete the installation or reinstall Visual Studio.'; String get visualStudioRebootRequired => 'Visual Studio requires a reboot of your system to complete installation.'; // Messages used in LinuxDoctorValidator diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_validator_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_validator_test.dart index b501b5e901906..2858d7d25cd88 100644 --- a/packages/flutter_tools/test/general.shard/windows/visual_studio_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_validator_test.dart @@ -60,9 +60,12 @@ void main() { fakeVisualStudio.isPrerelease = true; final ValidationResult result = await validator.validate(); - final ValidationMessage expectedMessage = ValidationMessage(userMessages.visualStudioIsPrerelease); + const ValidationMessage expectedMessage = ValidationMessage( + 'The current Visual Studio installation is a pre-release version. ' + 'It may not be supported by Flutter yet.', + ); - expect(result.messages.contains(expectedMessage), true); + expect(result.messages, contains(expectedMessage)); }); testWithoutContext('Emits a partial status when Visual Studio installation is incomplete', () async { @@ -74,9 +77,12 @@ void main() { fakeVisualStudio.isComplete = false; final ValidationResult result = await validator.validate(); - final ValidationMessage expectedMessage = ValidationMessage.error(userMessages.visualStudioIsIncomplete); + const ValidationMessage expectedMessage = ValidationMessage.error( + 'The current Visual Studio installation is incomplete.\n' + 'Please use Visual Studio Installer to complete the installation or reinstall Visual Studio.', + ); - expect(result.messages.contains(expectedMessage), true); + expect(result.messages, contains(expectedMessage)); expect(result.type, ValidationType.partial); }); @@ -89,9 +95,11 @@ void main() { fakeVisualStudio.isRebootRequired = true; final ValidationResult result = await validator.validate(); - final ValidationMessage expectedMessage = ValidationMessage.error(userMessages.visualStudioRebootRequired); + const ValidationMessage expectedMessage = ValidationMessage.error( + 'Visual Studio requires a reboot of your system to complete installation.', + ); - expect(result.messages.contains(expectedMessage), true); + expect(result.messages, contains(expectedMessage)); expect(result.type, ValidationType.partial); }); @@ -104,9 +112,11 @@ void main() { fakeVisualStudio.isLaunchable = false; final ValidationResult result = await validator.validate(); - final ValidationMessage expectedMessage = ValidationMessage.error(userMessages.visualStudioNotLaunchable); + const ValidationMessage expectedMessage = ValidationMessage.error( + 'The current Visual Studio installation is not launchable. Please reinstall Visual Studio.', + ); - expect(result.messages.contains(expectedMessage), true); + expect(result.messages, contains(expectedMessage)); expect(result.type, ValidationType.partial); }); @@ -118,14 +128,13 @@ void main() { configureMockVisualStudioAsTooOld(); final ValidationResult result = await validator.validate(); - final ValidationMessage expectedMessage = ValidationMessage.error( - userMessages.visualStudioTooOld( - fakeVisualStudio.minimumVersionDescription, - fakeVisualStudio.workloadDescription, - ), + const ValidationMessage expectedMessage = ValidationMessage.error( + 'Visual Studio 2019 or later is required.\n' + 'Download at https://visualstudio.microsoft.com/downloads/.\n' + 'Please install the "Desktop development" workload, including all of its default components', ); - expect(result.messages.contains(expectedMessage), true); + expect(result.messages, contains(expectedMessage)); expect(result.type, ValidationType.partial); }); @@ -161,10 +170,11 @@ void main() { configureMockVisualStudioAsInstalled(); final ValidationResult result = await validator.validate(); - final ValidationMessage expectedDisplayNameMessage = ValidationMessage( - userMessages.visualStudioVersion(fakeVisualStudio.displayName!, fakeVisualStudio.fullVersion!)); + const ValidationMessage expectedDisplayNameMessage = ValidationMessage( + 'Visual Studio Community 2019 version 16.2', + ); - expect(result.messages.contains(expectedDisplayNameMessage), true); + expect(result.messages, contains(expectedDisplayNameMessage)); expect(result.type, ValidationType.success); }); @@ -176,13 +186,13 @@ void main() { configureMockVisualStudioAsNotInstalled(); final ValidationResult result = await validator.validate(); - final ValidationMessage expectedMessage = ValidationMessage.error( - userMessages.visualStudioMissing( - fakeVisualStudio.workloadDescription, - ), + const ValidationMessage expectedMessage = ValidationMessage.error( + 'Visual Studio not installed; this is necessary to develop Windows apps.\n' + 'Download at https://visualstudio.microsoft.com/downloads/.\n' + 'Please install the "Desktop development" workload, including all of its default components' ); - expect(result.messages.contains(expectedMessage), true); + expect(result.messages, contains(expectedMessage)); expect(result.type, ValidationType.missing); }); }); From e6e44de33c6586b694b462a2013363126a1c2b83 Mon Sep 17 00:00:00 2001 From: yaakovschectman <109111084+yaakovschectman@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:48:12 -0400 Subject: [PATCH 1028/1547] Add MacOS AppKitView class. (#132583) Add derived classes from the Darwin platform view base classes for MacOS. Functionality is largely the same as the `UiKitView`, but the two are decoupled and and can further diverge in the future as needed. Some unit tests remain skipped for now as the gesture recognizers for MacOS are not yet implemented. https://github.com/flutter/flutter/issues/128519 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Chris Bracken --- .../lib/src/rendering/platform_view.dart | 39 +- .../lib/src/services/platform_views.dart | 53 +- .../lib/src/widgets/platform_view.dart | 75 +- .../test/services/fake_platform_views.dart | 131 +++ .../test/widgets/platform_view_test.dart | 921 ++++++++++++++++++ 5 files changed, 1205 insertions(+), 14 deletions(-) diff --git a/packages/flutter/lib/src/rendering/platform_view.dart b/packages/flutter/lib/src/rendering/platform_view.dart index 6a0c19953cdf4..e2bfb28177476 100644 --- a/packages/flutter/lib/src/rendering/platform_view.dart +++ b/packages/flutter/lib/src/rendering/platform_view.dart @@ -279,7 +279,10 @@ abstract class RenderDarwinPlatformView RenderDarwinPlatformView({ required T viewController, required this.hitTestBehavior, - }) : _viewController = viewController; + required Set> gestureRecognizers, + }) : _viewController = viewController { + updateGestureRecognizers(gestureRecognizers); + } /// The unique identifier of the platform view controlled by this controller. @@ -313,6 +316,8 @@ abstract class RenderDarwinPlatformView PointerEvent? _lastPointerDownEvent; + _UiKitViewGestureRecognizer? _gestureRecognizer; + @override Size computeDryLayout(BoxConstraints constraints) { return constraints.biggest; @@ -374,6 +379,9 @@ abstract class RenderDarwinPlatformView GestureBinding.instance.pointerRouter.removeGlobalRoute(_handleGlobalPointerEvent); super.detach(); } + + /// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers} + void updateGestureRecognizers(Set> gestureRecognizers); } /// A render object for an iOS UIKit UIView. @@ -401,14 +409,11 @@ class RenderUiKitView extends RenderDarwinPlatformView { RenderUiKitView({ required super.viewController, required super.hitTestBehavior, - required Set> gestureRecognizers - }) { - updateGestureRecognizers(gestureRecognizers); - } + required super.gestureRecognizers, + }); - // TODO(schectman): Add gesture functionality to macOS platform view when implemented. - // https://github.com/flutter/flutter/issues/128519 /// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers} + @override void updateGestureRecognizers(Set> gestureRecognizers) { assert( _factoriesTypeSet(gestureRecognizers).length == gestureRecognizers.length, @@ -431,8 +436,6 @@ class RenderUiKitView extends RenderDarwinPlatformView { _lastPointerDownEvent = event.original ?? event; } - _UiKitViewGestureRecognizer? _gestureRecognizer; - @override void detach() { _gestureRecognizer!.reset(); @@ -440,6 +443,24 @@ class RenderUiKitView extends RenderDarwinPlatformView { } } +/// A render object for a macOS platform view. +class RenderAppKitView extends RenderDarwinPlatformView { + /// Creates a render object for a macOS AppKitView. + RenderAppKitView({ + required super.viewController, + required super.hitTestBehavior, + required super.gestureRecognizers, + }); + + // TODO(schectman): Add gesture functionality to macOS platform view when implemented. + // https://github.com/flutter/flutter/issues/128519 + // This method will need to behave the same as the same-named method for RenderUiKitView, + // but use a _AppKitViewGestureRecognizer or equivalent, whose constructor shall accept an + // AppKitViewController. + @override + void updateGestureRecognizers(Set> gestureRecognizers) {} +} + // This recognizer constructs gesture recognizers from a set of gesture recognizer factories // it was give, adds all of them to a gesture arena team with the _UiKitViewGestureRecognizer // as the team captain. diff --git a/packages/flutter/lib/src/services/platform_views.dart b/packages/flutter/lib/src/services/platform_views.dart index 0375d42747fac..c1774998ff6ff 100644 --- a/packages/flutter/lib/src/services/platform_views.dart +++ b/packages/flutter/lib/src/services/platform_views.dart @@ -220,6 +220,7 @@ class PlatformViewsService { assert(creationParams == null || creationParamsCodec != null); // TODO(amirh): pass layoutDirection once the system channel supports it. + // https://github.com/flutter/flutter/issues/133682 final Map args = { 'id': id, 'viewType': viewType, @@ -238,6 +239,49 @@ class PlatformViewsService { } return UiKitViewController._(id, layoutDirection); } + + /// Factory method to create an `AppKitView`. + /// + /// `id` is an unused unique identifier generated with [platformViewsRegistry]. + /// + /// `viewType` is the identifier of the iOS view type to be created, a + /// factory for this view type must have been registered on the platform side. + /// Platform view factories are typically registered by plugin code. + /// + /// `onFocus` is a callback that will be invoked when the UIKit view asks to + /// get the input focus. + /// The `id, `viewType, and `layoutDirection` parameters must not be null. + /// If `creationParams` is non null then `creationParamsCodec` must not be null. + static Future initAppKitView({ + required int id, + required String viewType, + required TextDirection layoutDirection, + dynamic creationParams, + MessageCodec? creationParamsCodec, + VoidCallback? onFocus, + }) async { + assert(creationParams == null || creationParamsCodec != null); + + // TODO(amirh): pass layoutDirection once the system channel supports it. + // https://github.com/flutter/flutter/issues/133682 + final Map args = { + 'id': id, + 'viewType': viewType, + }; + if (creationParams != null) { + final ByteData paramsByteData = creationParamsCodec!.encodeMessage(creationParams)!; + args['params'] = Uint8List.view( + paramsByteData.buffer, + 0, + paramsByteData.lengthInBytes, + ); + } + await SystemChannels.platform_views.invokeMethod('create', args); + if (onFocus != null) { + _instance._focusCallbacks[id] = onFocus; + } + return AppKitViewController._(id, layoutDirection); + } } /// Properties of an Android pointer. @@ -1317,7 +1361,6 @@ abstract class DarwinPlatformViewController { TextDirection layoutDirection, ) : _layoutDirection = layoutDirection; - /// The unique identifier of the iOS view controlled by this controller. /// /// This identifier is typically generated by @@ -1389,6 +1432,14 @@ class UiKitViewController extends DarwinPlatformViewController { ); } +/// Controller for a macOS platform view. +class AppKitViewController extends DarwinPlatformViewController { + AppKitViewController._( + super.id, + super.layoutDirection, + ); +} + /// An interface for controlling a single platform view. /// /// Used by [PlatformViewSurface] to interface with the platform view it embeds. diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index 96389c014b6a4..05b2b5753d9b7 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -325,6 +325,40 @@ class UiKitView extends _DarwinView { State createState() => _UiKitViewState(); } +/// Widget that contains a macOS AppKit view. +/// +/// Embedding macOS views is an expensive operation and should be avoided where +/// a Flutter equivalent is possible. +/// +/// The platform view's lifetime is the same as the lifetime of the [State] +/// object for this widget. When the [State] is disposed the platform view (and +/// auxiliary resources) are lazily released (some resources are immediately +/// released and some by platform garbage collector). A stateful widget's state +/// is disposed when the widget is removed from the tree or when it is moved +/// within the tree. If the stateful widget has a key and it's only moved +/// relative to its siblings, or it has a [GlobalKey] and it's moved within the +/// tree, it will not be disposed. +/// +/// Construction of AppKitViews is done asynchronously, before the underlying +/// NSView is ready this widget paints nothing while maintaining the same +/// layout constraints. +class AppKitView extends _DarwinView { + /// Creates a widget that embeds a macOS AppKit NSView. + const AppKitView({ + super.key, + required super.viewType, + super.onPlatformViewCreated, + super.hitTestBehavior = PlatformViewHitTestBehavior.opaque, + super.layoutDirection, + super.creationParams, + super.creationParamsCodec, + super.gestureRecognizers, + }); + + @override + State createState() => _AppKitViewState(); +} + /// Callback signature for when the platform view's DOM element was created. /// /// [element] is the DOM element that was created. @@ -711,6 +745,31 @@ class _UiKitViewState extends _DarwinViewState { + @override + Future createNewViewController(int id) async { + return PlatformViewsService.initAppKitView( + id: id, + viewType: widget.viewType, + layoutDirection: _layoutDirection!, + creationParams: widget.creationParams, + creationParamsCodec: widget.creationParamsCodec, + onFocus: () { + focusNode?.requestFocus(); + } + ); + } + + @override + _AppKitPlatformView childPlatformView() { + return _AppKitPlatformView( + controller: _controller!, + hitTestBehavior: widget.hitTestBehavior, + gestureRecognizers: widget.gestureRecognizers ?? _DarwinViewState._emptyRecognizersSet, + ); + } +} + class _AndroidPlatformView extends LeafRenderObjectWidget { const _AndroidPlatformView({ required this.controller, @@ -758,7 +817,8 @@ abstract class _DarwinPlatformView { + const _AppKitPlatformView({required super.controller, required super.hitTestBehavior, required super.gestureRecognizers}); @override - void updateRenderObject(BuildContext context, RenderUiKitView renderObject) { - super.updateRenderObject(context, renderObject); - renderObject.updateGestureRecognizers(gestureRecognizers); + RenderObject createRenderObject(BuildContext context) { + return RenderAppKitView( + viewController: controller, + hitTestBehavior: hitTestBehavior, + gestureRecognizers: gestureRecognizers, + ); } } diff --git a/packages/flutter/test/services/fake_platform_views.dart b/packages/flutter/test/services/fake_platform_views.dart index e3dfdd5adaa49..e67589bff156a 100644 --- a/packages/flutter/test/services/fake_platform_views.dart +++ b/packages/flutter/test/services/fake_platform_views.dart @@ -471,6 +471,109 @@ class FakeIosPlatformViewsController { } } +class FakeMacosPlatformViewsController { + FakeMacosPlatformViewsController() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform_views, _onMethodCall); + } + + Iterable get views => _views.values; + final Map _views = {}; + + final Set _registeredViewTypes = {}; + + // When this completer is non null, the 'create' method channel call will be + // delayed until it completes. + Completer? creationDelay; + + // Maps a view id to the number of gestures it accepted so far. + final Map gesturesAccepted = {}; + + // Maps a view id to the number of gestures it rejected so far. + final Map gesturesRejected = {}; + + void registerViewType(String viewType) { + _registeredViewTypes.add(viewType); + } + + void invokeViewFocused(int viewId) { + final MethodCodec codec = SystemChannels.platform_views.codec; + final ByteData data = codec.encodeMethodCall(MethodCall('viewFocused', viewId)); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .handlePlatformMessage(SystemChannels.platform_views.name, data, (ByteData? data) {}); + } + + Future _onMethodCall(MethodCall call) { + switch (call.method) { + case 'create': + return _create(call); + case 'dispose': + return _dispose(call); + case 'acceptGesture': + return _acceptGesture(call); + case 'rejectGesture': + return _rejectGesture(call); + } + return Future.sync(() => null); + } + + Future _create(MethodCall call) async { + if (creationDelay != null) { + await creationDelay!.future; + } + final Map args = call.arguments as Map; + final int id = args['id'] as int; + final String viewType = args['viewType'] as String; + final Uint8List? creationParams = args['params'] as Uint8List?; + + if (_views.containsKey(id)) { + throw PlatformException( + code: 'error', + message: 'Trying to create an already created platform view, view id: $id', + ); + } + + if (!_registeredViewTypes.contains(viewType)) { + throw PlatformException( + code: 'error', + message: 'Trying to create a platform view of unregistered type: $viewType', + ); + } + + _views[id] = FakeAppKitView(id, viewType, creationParams); + gesturesAccepted[id] = 0; + gesturesRejected[id] = 0; + return Future.sync(() => null); + } + + Future _acceptGesture(MethodCall call) async { + final Map args = call.arguments as Map; + final int id = args['id'] as int; + gesturesAccepted[id] = gesturesAccepted[id]! + 1; + return Future.sync(() => null); + } + + Future _rejectGesture(MethodCall call) async { + final Map args = call.arguments as Map; + final int id = args['id'] as int; + gesturesRejected[id] = gesturesRejected[id]! + 1; + return Future.sync(() => null); + } + + Future _dispose(MethodCall call) { + final int id = call.arguments as int; + + if (!_views.containsKey(id)) { + throw PlatformException( + code: 'error', + message: 'Trying to dispose a platform view with unknown id: $id', + ); + } + + _views.remove(id); + return Future.sync(() => null); + } +} + @immutable class FakeAndroidPlatformView { const FakeAndroidPlatformView(this.id, this.type, this.size, this.layoutDirection, @@ -585,3 +688,31 @@ class FakeUiKitView { return 'FakeUiKitView(id: $id, type: $type, creationParams: $creationParams)'; } } + +@immutable +class FakeAppKitView { + const FakeAppKitView(this.id, this.type, [this.creationParams]); + + final int id; + final String type; + final Uint8List? creationParams; + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + return other is FakeAppKitView + && other.id == id + && other.type == type + && other.creationParams == creationParams; + } + + @override + int get hashCode => Object.hash(id, type); + + @override + String toString() { + return 'FakeAppKitView(id: $id, type: $type, creationParams: $creationParams)'; + } +} diff --git a/packages/flutter/test/widgets/platform_view_test.dart b/packages/flutter/test/widgets/platform_view_test.dart index d9164b59c350f..ba01eb040b29f 100644 --- a/packages/flutter/test/widgets/platform_view_test.dart +++ b/packages/flutter/test/widgets/platform_view_test.dart @@ -2224,6 +2224,927 @@ void main() { }); }); + group('AppKitView', () { + testWidgets('Create AppView', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ); + + expect( + viewsController.views, + unorderedEquals([ + FakeAppKitView(currentViewId + 1, 'webview'), + ]), + ); + }); + + testWidgets('Change AppKitView view type', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + viewsController.registerViewType('maps'); + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ); + + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'maps', layoutDirection: TextDirection.ltr), + ), + ), + ); + + expect( + viewsController.views, + unorderedEquals([ + FakeAppKitView(currentViewId + 2, 'maps'), + ]), + ); + }); + + testWidgets('Dispose AppKitView ', (WidgetTester tester) async { + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ); + + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + ), + ), + ); + + expect( + viewsController.views, + isEmpty, + ); + }); + + testWidgets('Dispose AppKitView before creation completed ', (WidgetTester tester) async { + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + viewsController.creationDelay = Completer(); + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ); + + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + ), + ), + ); + + viewsController.creationDelay!.complete(); + + expect( + viewsController.views, + isEmpty, + ); + }); + + testWidgets('AppKitView survives widget tree change', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr, key: key), + ), + ), + ); + + await tester.pumpWidget( + Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr, key: key), + ), + ), + ); + + expect( + viewsController.views, + unorderedEquals([ + FakeAppKitView(currentViewId + 1, 'webview'), + ]), + ); + }); + + testWidgets('Create AppKitView with params', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView( + viewType: 'webview', + layoutDirection: TextDirection.ltr, + creationParams: 'creation parameters', + creationParamsCodec: StringCodec(), + ), + ), + ), + ); + + final FakeAppKitView fakeView = viewsController.views.first; + final Uint8List rawCreationParams = fakeView.creationParams!; + final ByteData byteData = ByteData.view( + rawCreationParams.buffer, + rawCreationParams.offsetInBytes, + rawCreationParams.lengthInBytes, + ); + final dynamic actualParams = const StringCodec().decodeMessage(byteData); + + expect(actualParams, 'creation parameters'); + expect( + viewsController.views, + unorderedEquals([ + FakeAppKitView(currentViewId + 1, 'webview', fakeView.creationParams), + ]), + ); + }); + + // TODO(schectman): De-skip the following tests once macOS gesture recognizers are present. + // https://github.com/flutter/flutter/issues/128519 + testWidgets('AppKitView accepts gestures', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + const Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 0); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.up(); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + }, skip: true); // https://github.com/flutter/flutter/issues/128519 + + testWidgets('AppKitView transparent hit test behavior', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + int numPointerDownsOnParent = 0; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: [ + Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: (PointerDownEvent e) { + numPointerDownsOnParent++; + }, + ), + const Positioned( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView( + viewType: 'webview', + hitTestBehavior: PlatformViewHitTestBehavior.transparent, + layoutDirection: TextDirection.ltr, + ), + ), + ), + ], + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.up(); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 0); + + expect(numPointerDownsOnParent, 1); + }, skip: true); // https://github.com/flutter/flutter/issues/128519 + + testWidgets('AppKitView translucent hit test behavior', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + int numPointerDownsOnParent = 0; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: [ + Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: (PointerDownEvent e) { + numPointerDownsOnParent++; + }, + ), + const Positioned( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView( + viewType: 'webview', + hitTestBehavior: PlatformViewHitTestBehavior.translucent, + layoutDirection: TextDirection.ltr, + ), + ), + ), + ], + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.up(); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + + expect(numPointerDownsOnParent, 1); + }, skip: true); // https://github.com/flutter/flutter/issues/128519 + + testWidgets('AppKitView opaque hit test behavior', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + int numPointerDownsOnParent = 0; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: [ + Listener( + behavior: HitTestBehavior.opaque, + onPointerDown: (PointerDownEvent e) { + numPointerDownsOnParent++; + }, + ), + const Positioned( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView( + viewType: 'webview', + layoutDirection: TextDirection.ltr, + ), + ), + ), + ], + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.up(); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(numPointerDownsOnParent, 0); + }, skip: true); // https://github.com/flutter/flutter/issues/128519 + + testWidgets('UiKitView can lose gesture arenas', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + + bool verticalDragAcceptedByParent = false; + await tester.pumpWidget( + Align( + alignment: Alignment.topLeft, + child: Container( + margin: const EdgeInsets.all(10.0), + child: GestureDetector( + onVerticalDragStart: (DragStartDetails d) { + verticalDragAcceptedByParent = true; + }, + child: const SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.moveBy(const Offset(0.0, 100.0)); + await gesture.up(); + + expect(verticalDragAcceptedByParent, true); + expect(viewsController.gesturesAccepted[currentViewId + 1], 0); + expect(viewsController.gesturesRejected[currentViewId + 1], 1); + }); + + testWidgets('UiKitView tap gesture recognizers', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + bool gestureAcceptedByParent = false; + await tester.pumpWidget( + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onVerticalDragStart: (DragStartDetails d) { + gestureAcceptedByParent = true; + }, + child: SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + gestureRecognizers: >{ + Factory( + () { + return VerticalDragGestureRecognizer(); + }, + ), + }, + layoutDirection: TextDirection.ltr, + ), + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.moveBy(const Offset(0.0, 100.0)); + await gesture.up(); + + expect(gestureAcceptedByParent, false); + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(viewsController.gesturesRejected[currentViewId + 1], 0); + }); + + testWidgets('UiKitView long press gesture recognizers', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + bool gestureAcceptedByParent = false; + await tester.pumpWidget( + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onLongPress: () { + gestureAcceptedByParent = true; + }, + child: SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + gestureRecognizers: >{ + Factory( + () { + return LongPressGestureRecognizer(); + }, + ), + }, + layoutDirection: TextDirection.ltr, + ), + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + await tester.longPressAt(const Offset(50.0, 50.0)); + + expect(gestureAcceptedByParent, false); + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(viewsController.gesturesRejected[currentViewId + 1], 0); + }); + + testWidgets('UiKitView drag gesture recognizers', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + bool verticalDragAcceptedByParent = false; + await tester.pumpWidget( + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onVerticalDragStart: (DragStartDetails d) { + verticalDragAcceptedByParent = true; + }, + child: SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + gestureRecognizers: >{ + Factory( + () { + return TapGestureRecognizer(); + }, + ), + }, + layoutDirection: TextDirection.ltr, + ), + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + await tester.tapAt(const Offset(50.0, 50.0)); + + expect(verticalDragAcceptedByParent, false); + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(viewsController.gesturesRejected[currentViewId + 1], 0); + }); + + testWidgets('UiKitView can claim gesture after all pointers are up', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + bool verticalDragAcceptedByParent = false; + // The long press recognizer rejects the gesture after the AndroidView gets the pointer up event. + // This test makes sure that the Android view can win the gesture after it got the pointer up event. + await tester.pumpWidget( + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onVerticalDragStart: (DragStartDetails d) { + verticalDragAcceptedByParent = true; + }, + onLongPress: () { }, + child: const SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + layoutDirection: TextDirection.ltr, + ), + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.up(); + + expect(verticalDragAcceptedByParent, false); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(viewsController.gesturesRejected[currentViewId + 1], 0); + }); + + testWidgets('UiKitView rebuilt during gesture', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + await tester.pumpWidget( + const Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + layoutDirection: TextDirection.ltr, + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.moveBy(const Offset(0.0, 100.0)); + + await tester.pumpWidget( + const Align( + alignment: Alignment.topLeft, + child: SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + layoutDirection: TextDirection.ltr, + ), + ), + ), + ); + + await gesture.up(); + + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(viewsController.gesturesRejected[currentViewId + 1], 0); + }); + + testWidgets('UiKitView with eager gesture recognizer', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + await tester.pumpWidget( + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onVerticalDragStart: (DragStartDetails d) { }, + child: SizedBox( + width: 200.0, + height: 100.0, + child: UiKitView( + viewType: 'webview', + gestureRecognizers: >{ + Factory( + () => EagerGestureRecognizer(), + ), + }, + layoutDirection: TextDirection.ltr, + ), + ), + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + await tester.startGesture(const Offset(50.0, 50.0)); + + // Normally (without the eager gesture recognizer) after just the pointer down event + // no gesture arena member will claim the arena (so no motion events will be dispatched to + // the Android view). Here we assert that with the eager recognizer in the gesture team the + // pointer down event is immediately dispatched. + expect(viewsController.gesturesAccepted[currentViewId + 1], 1); + expect(viewsController.gesturesRejected[currentViewId + 1], 0); + }); + + testWidgets('UiKitView rejects gestures absorbed by siblings', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + Stack( + alignment: Alignment.topLeft, + children: [ + const UiKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + Container( + color: const Color.fromARGB(255, 255, 255, 255), + width: 100, + height: 100, + ), + ], + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(50.0, 50.0)); + await gesture.up(); + + expect(viewsController.gesturesRejected[currentViewId + 1], 1); + expect(viewsController.gesturesAccepted[currentViewId + 1], 0); + }); + + testWidgets( + 'UiKitView rejects gestures absorbed by siblings if the touch is outside of the platform view bounds but inside platform view frame', + (WidgetTester tester) async { + // UiKitView is positioned at (left=0, top=100, right=300, bottom=600). + // Opaque container is on top of the UiKitView positioned at (left=0, top=500, right=300, bottom=600). + // Touch on (550, 150) is expected to be absorbed by the container. + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + SizedBox( + width: 300, + height: 600, + child: Stack( + alignment: Alignment.topLeft, + children: [ + Transform.translate( + offset: const Offset(0, 100), + child: const SizedBox( + width: 300, + height: 500, + child: UiKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + Transform.translate( + offset: const Offset(0, 500), + child: Container( + color: const Color.fromARGB(255, 255, 255, 255), + width: 300, + height: 100, + ), + ), + ], + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final TestGesture gesture = await tester.startGesture(const Offset(150, 550)); + await gesture.up(); + + expect(viewsController.gesturesRejected[currentViewId + 1], 1); + expect(viewsController.gesturesAccepted[currentViewId + 1], 0); + }, + ); + + testWidgets('UiKitView rebuilt with same gestureRecognizers', (WidgetTester tester) async { + final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); + viewsController.registerViewType('webview'); + + int factoryInvocationCount = 0; + EagerGestureRecognizer constructRecognizer() { + factoryInvocationCount += 1; + return EagerGestureRecognizer(); + } + + await tester.pumpWidget( + UiKitView( + viewType: 'webview', + gestureRecognizers: >{ + Factory(constructRecognizer), + }, + layoutDirection: TextDirection.ltr, + ), + ); + + await tester.pumpWidget( + UiKitView( + viewType: 'webview', + hitTestBehavior: PlatformViewHitTestBehavior.translucent, + gestureRecognizers: >{ + Factory(constructRecognizer), + }, + layoutDirection: TextDirection.ltr, + ), + ); + + expect(factoryInvocationCount, 1); + }); + + testWidgets('AppKitView can take input focus', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + final GlobalKey containerKey = GlobalKey(); + await tester.pumpWidget( + Center( + child: Column( + children: [ + const SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + Focus( + debugLabel: 'container', + child: Container(key: containerKey), + ), + ], + ), + ), + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final Focus uiKitViewFocusWidget = tester.widget( + find.descendant( + of: find.byType(AppKitView), + matching: find.byType(Focus), + ), + ); + final FocusNode uiKitViewFocusNode = uiKitViewFocusWidget.focusNode!; + final Element containerElement = tester.element(find.byKey(containerKey)); + final FocusNode containerFocusNode = Focus.of(containerElement); + + containerFocusNode.requestFocus(); + + await tester.pump(); + + expect(containerFocusNode.hasFocus, isTrue); + expect(uiKitViewFocusNode.hasFocus, isFalse); + + viewsController.invokeViewFocused(currentViewId + 1); + + await tester.pump(); + + expect(containerFocusNode.hasFocus, isFalse); + expect(uiKitViewFocusNode.hasFocus, isTrue); + }); + + testWidgets('AppKitView sends TextInput.setPlatformViewClient when focused', (WidgetTester tester) async { + + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + const AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr) + ); + + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final Focus uiKitViewFocusWidget = tester.widget( + find.descendant( + of: find.byType(AppKitView), + matching: find.byType(Focus), + ), + ); + final FocusNode uiKitViewFocusNode = uiKitViewFocusWidget.focusNode!; + + late Map channelArguments; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) { + if (call.method == 'TextInput.setPlatformViewClient') { + channelArguments = call.arguments as Map; + } + return null; + }); + + expect(uiKitViewFocusNode.hasFocus, false); + + uiKitViewFocusNode.requestFocus(); + await tester.pump(); + + expect(uiKitViewFocusNode.hasFocus, true); + expect(channelArguments['platformViewId'], currentViewId + 1); + }); + + testWidgets('FocusNode is disposed on UIView dispose', (WidgetTester tester) async { + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView(viewType: 'webview', layoutDirection: TextDirection.ltr), + ), + ), + ); + // casting to dynamic is required since the state class is private. + // ignore: avoid_dynamic_calls, invalid_assignment + final FocusNode node = (tester.state(find.byType(AppKitView)) as dynamic).focusNode; + expect(() => ChangeNotifier.debugAssertNotDisposed(node), isNot(throwsAssertionError)); + await tester.pumpWidget( + const Center( + child: SizedBox( + width: 200.0, + height: 100.0, + ), + ), + ); + expect(() => ChangeNotifier.debugAssertNotDisposed(node), throwsAssertionError); + }); + + testWidgets('AppKitView has correct semantics', (WidgetTester tester) async { + final SemanticsHandle handle = tester.ensureSemantics(); + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + expect(currentViewId, greaterThanOrEqualTo(0)); + final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); + viewsController.registerViewType('webview'); + + await tester.pumpWidget( + Semantics( + container: true, + child: const Align( + alignment: Alignment.bottomRight, + child: SizedBox( + width: 200.0, + height: 100.0, + child: AppKitView( + viewType: 'webview', + layoutDirection: TextDirection.ltr, + ), + ), + ), + ), + ); + // First frame is before the platform view was created so the render object + // is not yet in the tree. + await tester.pump(); + + final SemanticsNode semantics = tester.getSemantics( + find.descendant( + of: find.byType(AppKitView), + matching: find.byWidgetPredicate( + (Widget widget) => widget.runtimeType.toString() == '_AppKitPlatformView', + ), + ), + ); + + expect(semantics.platformViewId, currentViewId + 1); + expect(semantics.rect, const Rect.fromLTWH(0, 0, 200, 100)); + // A 200x100 rect positioned at bottom right of a 800x600 box. + expect(semantics.transform, Matrix4.translationValues(600, 500, 0)); + expect(semantics.childrenCount, 0); + + handle.dispose(); + }); + }); + group('Common PlatformView', () { late FakePlatformViewController controller; From 0b3b8cd5516d77658135ba4b830915c7ff43500d Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:50:54 -0700 Subject: [PATCH 1029/1547] =?UTF-8?q?Removes=20ios=20universal=20link=20vm?= =?UTF-8?q?services=20and=20let=20xcodeproject=20to=20dump=20js=E2=80=A6?= =?UTF-8?q?=20(#133709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …on file The deeplink validation tool will become an static app so it can't no longer access vm services. The goal will be then to turn them into flutter analyze command similar to `flutter analyze --android --[options]` that static app can use on. This pr only removes vm services and turn the api to dump a output file instead of printing everything to stdout. --- .../flutter_tools/lib/src/ios/xcodeproj.dart | 15 ---- packages/flutter_tools/lib/src/project.dart | 5 +- packages/flutter_tools/lib/src/vmservice.dart | 46 ----------- .../flutter_tools/lib/src/xcode_project.dart | 23 ++++-- .../test/general.shard/project_test.dart | 31 +++++--- .../resident_web_runner_test.dart | 8 -- .../test/general.shard/vmservice_test.dart | 77 ------------------- .../vmservice_integration_test.dart | 6 -- 8 files changed, 40 insertions(+), 171 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart index 011454bc00f7e..bb81534287652 100644 --- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart @@ -412,21 +412,6 @@ class XcodeProjectBuildContext { } } -/// The settings that are relevant for setting up universal links -@immutable -class XcodeUniversalLinkSettings { - const XcodeUniversalLinkSettings({ - this.bundleIdentifier, - this.teamIdentifier, - this.associatedDomains = const [], - }); - - final String? bundleIdentifier; - final String? teamIdentifier; - final List associatedDomains; -} - - /// Information about an Xcode project. /// /// Represents the output of `xcodebuild -list`. diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 6ded1d332fefd..24897e311d357 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -121,6 +121,9 @@ class FlutterProject { /// The location of this project. final Directory directory; + /// The location of the build folder. + Directory get buildDirectory => directory.childDirectory('build'); + /// The manifest of this project. final FlutterManifest manifest; @@ -657,7 +660,7 @@ $javaGradleCompatUrl /// The build directory where the Android artifacts are placed. Directory get buildDirectory { - return parent.directory.childDirectory('build'); + return parent.buildDirectory; } Future ensureReadyForPlatformSpecificTooling({DeprecationBehavior deprecationBehavior = DeprecationBehavior.none}) async { diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 531e88408e162..78a5b92bd7787 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -16,7 +16,6 @@ import 'cache.dart'; import 'convert.dart'; import 'device.dart'; import 'globals.dart' as globals; -import 'ios/xcodeproj.dart'; import 'project.dart'; import 'version.dart'; @@ -41,8 +40,6 @@ const String kFlutterVersionServiceName = 'flutterVersion'; const String kCompileExpressionServiceName = 'compileExpression'; const String kFlutterMemoryInfoServiceName = 'flutterMemoryInfo'; const String kFlutterGetSkSLServiceName = 'flutterGetSkSL'; -const String kFlutterGetIOSBuildOptionsServiceName = 'flutterGetIOSBuildOptions'; -const String kFlutterGetIOSUniversalLinkSettingsServiceName = 'flutterGetIOSUniversalLinkSettings'; /// The error response code from an unrecoverable compilation failure. const int kIsolateReloadBarred = 1005; @@ -315,49 +312,6 @@ Future setUpVmService({ registrationRequests.add(vmService.registerService(kFlutterGetSkSLServiceName, kFlutterToolAlias)); } - if (flutterProject != null) { - vmService.registerServiceCallback(kFlutterGetIOSBuildOptionsServiceName, (Map params) async { - final XcodeProjectInfo? info = await flutterProject.ios.projectInfo(); - if (info == null) { - return { - 'result': { - kResultType: kResultTypeSuccess, - }, - }; - } - return { - 'result': { - kResultType: kResultTypeSuccess, - 'targets': info.targets, - 'schemes': info.schemes, - 'buildConfigurations': info.buildConfigurations, - }, - }; - }); - registrationRequests.add( - vmService.registerService(kFlutterGetIOSBuildOptionsServiceName, kFlutterToolAlias), - ); - - vmService.registerServiceCallback(kFlutterGetIOSUniversalLinkSettingsServiceName, (Map params) async { - final XcodeUniversalLinkSettings settings = await flutterProject.ios.universalLinkSettings( - configuration: params['configuration']! as String, - scheme: params['scheme']! as String, - target: params['target']! as String, - ); - return { - 'result': { - kResultType: kResultTypeSuccess, - 'bundleIdentifier': settings.bundleIdentifier ?? '', - 'teamIdentifier': settings.teamIdentifier ?? '', - 'associatedDomains': settings.associatedDomains, - }, - }; - }); - registrationRequests.add( - vmService.registerService(kFlutterGetIOSUniversalLinkSettingsServiceName, kFlutterToolAlias), - ); - } - if (printStructuredErrorLogMethod != null) { vmService.onExtensionEvent.listen(printStructuredErrorLogMethod); registrationRequests.add(vmService diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index add59a60b1b28..c95ca87c4366e 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -7,6 +7,7 @@ import 'base/file_system.dart'; import 'base/utils.dart'; import 'build_info.dart'; import 'bundle.dart' as bundle; +import 'convert.dart'; import 'flutter_plugins.dart'; import 'globals.dart' as globals; import 'ios/code_signing.dart'; @@ -214,7 +215,11 @@ class IosProject extends XcodeBasedProject { return parent.isModule || _editableDirectory.existsSync(); } - Future universalLinkSettings({ + /// Output universal link related project settings of the iOS sub-project into + /// a json file. + /// + /// The return future will resolve to string path to the output file. + Future outputUniversalLinkSettings({ required String configuration, required String scheme, required String target, @@ -224,12 +229,16 @@ class IosProject extends XcodeBasedProject { scheme: scheme, target: target, ); - - return XcodeUniversalLinkSettings( - bundleIdentifier: await _productBundleIdentifierWithBuildContext(context), - teamIdentifier: await _getTeamIdentifier(context), - associatedDomains: await _getAssociatedDomains(context), - ); + final File file = await parent.buildDirectory + .childDirectory('deeplink_data') + .childFile('universal-link-settings-$configuration-$scheme-$target.json') + .create(recursive: true); + await file.writeAsString(jsonEncode({ + 'bundleIdentifier': await _productBundleIdentifierWithBuildContext(context), + 'teamIdentifier': await _getTeamIdentifier(context), + 'associatedDomains': await _getAssociatedDomains(context), + })); + return file.absolute.path; } /// The product bundle identifier of the host app, or null if not set or if diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index e80ba79de56c9..759ec7eae859f 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -751,13 +751,16 @@ apply plugin: 'kotlin-android' 'applinks:example2.com', ], ); - final XcodeUniversalLinkSettings settings = await project.ios.universalLinkSettings( + final String outputFilePath = await project.ios.outputUniversalLinkSettings( target: 'Runner', scheme: 'Debug', configuration: 'config', ); + final File outputFile = fs.file(outputFilePath); + final Map json = jsonDecode(outputFile.readAsStringSync()) as Map; + expect( - settings.associatedDomains, + json['associatedDomains'], unorderedEquals( [ 'example.com', @@ -765,8 +768,8 @@ apply plugin: 'kotlin-android' ], ), ); - expect(settings.teamIdentifier, 'ABC'); - expect(settings.bundleIdentifier, 'io.flutter.someProject.suffix'); + expect(json['teamIdentifier'], 'ABC'); + expect(json['bundleIdentifier'], 'io.flutter.someProject.suffix'); }); testWithMocks('can handle entitlement file in nested directory structure.', () async { @@ -796,13 +799,16 @@ apply plugin: 'kotlin-android' 'applinks:example2.com', ], ); - final XcodeUniversalLinkSettings settings = await project.ios.universalLinkSettings( + + final String outputFilePath = await project.ios.outputUniversalLinkSettings( target: 'Runner', scheme: 'Debug', configuration: 'config', ); + final File outputFile = fs.file(outputFilePath); + final Map json = jsonDecode(outputFile.readAsStringSync()) as Map; expect( - settings.associatedDomains, + json['associatedDomains'], unorderedEquals( [ 'example.com', @@ -810,8 +816,8 @@ apply plugin: 'kotlin-android' ], ), ); - expect(settings.teamIdentifier, 'ABC'); - expect(settings.bundleIdentifier, 'io.flutter.someProject.suffix'); + expect(json['teamIdentifier'], 'ABC'); + expect(json['bundleIdentifier'], 'io.flutter.someProject.suffix'); }); testWithMocks('return empty when no entitlement', () async { @@ -830,13 +836,16 @@ apply plugin: 'kotlin-android' }; xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo([], [], ['Runner'], logger); testPlistUtils.setProperty(PlistParser.kCFBundleIdentifierKey, r'$(PRODUCT_BUNDLE_IDENTIFIER)'); - final XcodeUniversalLinkSettings settings = await project.ios.universalLinkSettings( + final String outputFilePath = await project.ios.outputUniversalLinkSettings( target: 'Runner', scheme: 'Debug', configuration: 'config', ); - expect(settings.teamIdentifier, 'ABC'); - expect(settings.bundleIdentifier, 'io.flutter.someProject'); + final File outputFile = fs.file(outputFilePath); + final Map json = jsonDecode(outputFile.readAsStringSync()) as Map; + expect(json['teamIdentifier'], 'ABC'); + expect(json['bundleIdentifier'], 'io.flutter.someProject'); + expect(json['associatedDomains'], unorderedEquals([])); }); }); diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 96105be45bec0..01a1f098ed9bc 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -74,14 +74,6 @@ const List kAttachIsolateExpectations = 'service': kFlutterMemoryInfoServiceName, 'alias': kFlutterToolAlias, }), - FakeVmServiceRequest(method: 'registerService', args: { - 'service': kFlutterGetIOSBuildOptionsServiceName, - 'alias': kFlutterToolAlias, - }), - FakeVmServiceRequest(method: 'registerService', args: { - 'service': kFlutterGetIOSUniversalLinkSettingsServiceName, - 'alias': kFlutterToolAlias, - }), FakeVmServiceRequest( method: 'streamListen', args: { diff --git a/packages/flutter_tools/test/general.shard/vmservice_test.dart b/packages/flutter_tools/test/general.shard/vmservice_test.dart index d4f2fc3371f85..73e710c6567af 100644 --- a/packages/flutter_tools/test/general.shard/vmservice_test.dart +++ b/packages/flutter_tools/test/general.shard/vmservice_test.dart @@ -9,8 +9,6 @@ import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/device.dart'; -import 'package:flutter_tools/src/ios/xcodeproj.dart'; -import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/vmservice.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -85,17 +83,6 @@ void main() { expect(mockVMService.services, containsPair(kFlutterMemoryInfoServiceName, kFlutterToolAlias)); }); - testWithoutContext('VmService registers flutterGetIOSBuildOptions service', () async { - final MockVMService mockVMService = MockVMService(); - final FlutterProject mockedFlutterProject = MockFlutterProject(); - await setUpVmService( - flutterProject: mockedFlutterProject, - vmService: mockVMService, - ); - - expect(mockVMService.services, containsPair(kFlutterGetIOSBuildOptionsServiceName, kFlutterToolAlias)); - }); - testWithoutContext('VM Service registers flutterGetSkSL service', () async { final MockVMService mockVMService = MockVMService(); await setUpVmService( @@ -277,50 +264,6 @@ void main() { ])); }); - testWithoutContext('VmService forward flutterGetIOSBuildOptions request and response correctly', () async { - final MockVMService vmService = MockVMService(); - final XcodeProjectInfo expectedProjectInfo = XcodeProjectInfo( - ['target1', 'target2'], - ['config1', 'config2'], - ['scheme1', 'scheme2'], - MockLogger(), - ); - final FlutterProject mockedFlutterProject = MockFlutterProject( - mockedIos: MockIosProject(mockedInfo: expectedProjectInfo), - ); - await setUpVmService( - flutterProject: mockedFlutterProject, - vmService: vmService - ); - final vm_service.ServiceCallback cb = vmService.serviceCallBacks[kFlutterGetIOSBuildOptionsServiceName]!; - - final Map response = await cb({}); - final Map result = response['result']! as Map; - expect(result[kResultType], kResultTypeSuccess); - expect(result['targets'], expectedProjectInfo.targets); - expect(result['buildConfigurations'], expectedProjectInfo.buildConfigurations); - expect(result['schemes'], expectedProjectInfo.schemes); - }); - - testWithoutContext('VmService forward flutterGetIOSBuildOptions request and response correctly when no iOS project', () async { - final MockVMService vmService = MockVMService(); - final FlutterProject mockedFlutterProject = MockFlutterProject( - mockedIos: MockIosProject(), - ); - await setUpVmService( - flutterProject: mockedFlutterProject, - vmService: vmService - ); - final vm_service.ServiceCallback cb = vmService.serviceCallBacks[kFlutterGetIOSBuildOptionsServiceName]!; - - final Map response = await cb({}); - final Map result = response['result']! as Map; - expect(result[kResultType], kResultTypeSuccess); - expect(result['targets'], isNull); - expect(result['buildConfigurations'], isNull); - expect(result['schemes'], isNull); - }); - testWithoutContext('runInView forwards arguments correctly', () async { final FakeVmServiceHost fakeVmServiceHost = FakeVmServiceHost( requests: [ @@ -908,26 +851,6 @@ void main() { }); } -class MockFlutterProject extends Fake implements FlutterProject { - MockFlutterProject({ - IosProject? mockedIos, - }) : ios = mockedIos ?? MockIosProject(); - - @override - final IosProject ios; -} - -class MockIosProject extends Fake implements IosProject { - MockIosProject({this.mockedInfo}); - - final XcodeProjectInfo? mockedInfo; - - @override - Future projectInfo() async => mockedInfo; -} - -class MockLogger extends Fake implements Logger { } - class MockVMService extends Fake implements vm_service.VmService { final Map services = {}; final Map serviceCallBacks = {}; diff --git a/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart b/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart index 7768150930a00..45a0e86ebd89f 100644 --- a/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart +++ b/packages/flutter_tools/test/integration.shard/vmservice_integration_test.dart @@ -59,12 +59,6 @@ void main() { expect(response.type, 'Success'); }); - testWithoutContext('flutterGetIOSBuildOptions can be called', () async { - final Response response = - await vmService.callServiceExtension('s0.flutterGetIOSBuildOptions'); - expect(response.type, 'Success'); - }); - testWithoutContext('reloadSources can be called', () async { final VM vm = await vmService.getVM(); final IsolateRef? isolateRef = vm.isolates?.first; From 33210218ba4968f6a0c118239abdcd933049bb59 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Thu, 31 Aug 2023 15:01:10 -0700 Subject: [PATCH 1030/1547] [flutter_tools] Fix flutter upgrade not finding git tags (#133778) Fixes https://github.com/flutter/flutter/issues/133441 --- .../lib/src/commands/upgrade.dart | 6 ++- .../commands.shard/hermetic/upgrade_test.dart | 12 ++++++ .../downgrade_upgrade_integration_test.dart | 38 ++++++++++++++----- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart index b7b54a190aa6e..d9918e385efdc 100644 --- a/packages/flutter_tools/lib/src/commands/upgrade.dart +++ b/packages/flutter_tools/lib/src/commands/upgrade.dart @@ -77,7 +77,11 @@ class UpgradeCommand extends FlutterCommand { force: boolArg('force'), continueFlow: boolArg('continue'), testFlow: stringArg('working-directory') != null, - gitTagVersion: GitTagVersion.determine(globals.processUtils, globals.platform), + gitTagVersion: GitTagVersion.determine( + globals.processUtils, + globals.platform, + workingDirectory: _commandRunner.workingDirectory, + ), flutterVersion: stringArg('working-directory') == null ? globals.flutterVersion : FlutterVersion(flutterRoot: _commandRunner.workingDirectory!, fs: globals.fs), diff --git a/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart index 2a1db24d57a75..3b7c116fc6eae 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart @@ -23,9 +23,11 @@ void main() { late FakeProcessManager processManager; UpgradeCommand command; late CommandRunner runner; + const String flutterRoot = '/path/to/flutter'; setUpAll(() { Cache.disableLocking(); + Cache.flutterRoot = flutterRoot; }); setUp(() { @@ -214,28 +216,35 @@ void main() { const FakeCommand( command: ['git', 'tag', '--points-at', 'HEAD'], stdout: startingTag, + workingDirectory: flutterRoot, ), const FakeCommand( command: ['git', 'fetch', '--tags'], + workingDirectory: flutterRoot, ), const FakeCommand( command: ['git', 'rev-parse', '--verify', '@{upstream}'], stdout: upstreamHeadRevision, + workingDirectory: flutterRoot, ), const FakeCommand( command: ['git', 'tag', '--points-at', upstreamHeadRevision], stdout: latestUpstreamTag, + workingDirectory: flutterRoot, ), const FakeCommand( command: ['git', 'status', '-s'], + workingDirectory: flutterRoot, ), const FakeCommand( command: ['git', 'reset', '--hard', upstreamHeadRevision], + workingDirectory: flutterRoot, ), FakeCommand( command: const ['bin/flutter', 'upgrade', '--continue', '--no-version-check'], onRun: reEnterTool, completer: reEntryCompleter, + workingDirectory: flutterRoot, ), // commands following this are from the re-entrant `flutter upgrade --continue` call @@ -243,12 +252,15 @@ void main() { const FakeCommand( command: ['git', 'tag', '--points-at', 'HEAD'], stdout: latestUpstreamTag, + workingDirectory: flutterRoot, ), const FakeCommand( command: ['bin/flutter', '--no-color', '--no-version-check', 'precache'], + workingDirectory: flutterRoot, ), const FakeCommand( command: ['bin/flutter', '--no-version-check', 'doctor'], + workingDirectory: flutterRoot, ), ]); await runner.run(['upgrade']); diff --git a/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart b/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart index 8ca82c0d25cdd..20b7675b78a51 100644 --- a/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart +++ b/packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart @@ -15,14 +15,14 @@ const String _kInitialVersion = '3.0.0'; const String _kBranch = 'beta'; final Stdio stdio = Stdio(); -final ProcessUtils processUtils = ProcessUtils(processManager: processManager, logger: StdoutLogger( +final BufferLogger logger = BufferLogger.test( terminal: AnsiTerminal( platform: platform, stdio: stdio, ), - stdio: stdio, outputPreferences: OutputPreferences.test(wrapText: true), -)); +); +final ProcessUtils processUtils = ProcessUtils(processManager: processManager, logger: logger); final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter'); /// A test for flutter upgrade & downgrade that checks out a parallel flutter repo. @@ -48,13 +48,29 @@ void main() { 'git', 'config', '--system', 'core.longpaths', 'true', ]); + void checkExitCode(int code) { + expect( + exitCode, + 0, + reason: ''' +trace: +${logger.traceText} + +status: +${logger.statusText} + +error: +${logger.errorText}''', + ); + } + printOnFailure('Step 1 - clone the $_kBranch of flutter into the test directory'); exitCode = await processUtils.stream([ 'git', 'clone', 'https://github.com/flutter/flutter.git', ], workingDirectory: parentDirectory.path, trace: true); - expect(exitCode, 0); + checkExitCode(exitCode); printOnFailure('Step 2 - switch to the $_kBranch'); exitCode = await processUtils.stream([ @@ -65,7 +81,7 @@ void main() { _kBranch, 'origin/$_kBranch', ], workingDirectory: testDirectory.path, trace: true); - expect(exitCode, 0); + checkExitCode(exitCode); printOnFailure('Step 3 - revert back to $_kInitialVersion'); exitCode = await processUtils.stream([ @@ -74,7 +90,7 @@ void main() { '--hard', _kInitialVersion, ], workingDirectory: testDirectory.path, trace: true); - expect(exitCode, 0); + checkExitCode(exitCode); printOnFailure('Step 4 - upgrade to the newest $_kBranch'); // This should update the persistent tool state with the sha for HEAD @@ -84,8 +100,10 @@ void main() { 'upgrade', '--verbose', '--working-directory=${testDirectory.path}', - ], workingDirectory: testDirectory.path, trace: true); - expect(exitCode, 0); + // we intentionally run this in a directory outside the test repo to + // verify the tool overrides the working directory when invoking git + ], workingDirectory: parentDirectory.path, trace: true); + checkExitCode(exitCode); printOnFailure('Step 5 - verify that the version is different'); final RunResult versionResult = await processUtils.run([ @@ -105,8 +123,8 @@ void main() { 'downgrade', '--no-prompt', '--working-directory=${testDirectory.path}', - ], workingDirectory: testDirectory.path, trace: true); - expect(exitCode, 0); + ], workingDirectory: parentDirectory.path, trace: true); + checkExitCode(exitCode); printOnFailure('Step 7 - verify downgraded version matches original version'); final RunResult oldVersionResult = await processUtils.run([ From 7ade163885b7c46ebb0a99bc19a6e70e8075dbb2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 18:25:02 -0400 Subject: [PATCH 1031/1547] Roll Flutter Engine from 51090e3cfe79 to ca513c999257 (15 revisions) (#133810) https://github.com/flutter/engine/compare/51090e3cfe79...ca513c999257 2023-08-31 zanderso@users.noreply.github.com Revert "Reland "Build iOS unittest target in unopt builds" (#44356)"" (flutter/engine#45346) 2023-08-31 flar@google.com Lazily allocate RasterCacheItems only when caching is enabled (flutter/engine#45211) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 8ff4fd208c26 to 5d08dadd2ef4 (3 revisions) (flutter/engine#45340) 2023-08-31 ychris@google.com Reland "Build iOS unittest target in unopt builds" (#44356)" (flutter/engine#44821) 2023-08-31 yousefi@google.com Update comment const_finder.dart (flutter/engine#45180) 2023-08-31 dkwingsmt@users.noreply.github.com Replace an unnecessary util function with PostSync (flutter/engine#45190) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from cda0cfaadfd7 to 8ff4fd208c26 (3 revisions) (flutter/engine#45337) 2023-08-31 skia-flutter-autoroll@skia.org Roll Dart SDK from 0cea73a8d3c3 to ac3bc9f6351a (4 revisions) (flutter/engine#45336) 2023-08-31 chris@bracken.jp [macOS] Link __availability_version_check (flutter/engine#45333) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 8c05d5103d6b to cda0cfaadfd7 (3 revisions) (flutter/engine#45334) 2023-08-31 zanderso@users.noreply.github.com Adds an --rbe option to tools/gn that works on Linux hosts (flutter/engine#45271) 2023-08-31 brianosman@google.com Migrate VK calls of GrBackend* (flutter/engine#45325) 2023-08-31 zanderso@users.noreply.github.com Roll buildroot (flutter/engine#45329) 2023-08-31 zanderso@users.noreply.github.com Revert dl split (flutter/engine#45326) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from d113402de2ce to 8c05d5103d6b (4 revisions) (flutter/engine#45331) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 17994e10e9a21..d56a3ddbe1864 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -51090e3cfe79ff0b4fe7e83e041a4910c777004e +ca513c99925793198f1a72b2ce17d6d90f37ee3c From 5b6d748cb4c443904930b4491c77c843fd752627 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 31 Aug 2023 17:56:06 -0500 Subject: [PATCH 1032/1547] Fix sample code crash, add test (#133812) Fixes https://github.com/flutter/flutter/issues/133402 On web `1 << 32` crashes, 31 is the maximum. --- dev/bots/check_code_samples.dart | 1 - .../transitions/listenable_builder.3.dart | 2 +- .../listenable_builder.3_test.dart | 34 +++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 examples/api/test/widgets/transitions/listenable_builder.3_test.dart diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart index 78de4d43de00e..029e6322a1a1f 100644 --- a/dev/bots/check_code_samples.dart +++ b/dev/bots/check_code_samples.dart @@ -405,7 +405,6 @@ final Set _knownMissingTests = { 'examples/api/test/widgets/animated_switcher/animated_switcher.0_test.dart', 'examples/api/test/widgets/transitions/relative_positioned_transition.0_test.dart', 'examples/api/test/widgets/transitions/positioned_transition.0_test.dart', - 'examples/api/test/widgets/transitions/listenable_builder.3_test.dart', 'examples/api/test/widgets/transitions/sliver_fade_transition.0_test.dart', 'examples/api/test/widgets/transitions/align_transition.0_test.dart', 'examples/api/test/widgets/transitions/fade_transition.0_test.dart', diff --git a/examples/api/lib/widgets/transitions/listenable_builder.3.dart b/examples/api/lib/widgets/transitions/listenable_builder.3.dart index 9d65da22a6c92..8bc7ae1ed454c 100644 --- a/examples/api/lib/widgets/transitions/listenable_builder.3.dart +++ b/examples/api/lib/widgets/transitions/listenable_builder.3.dart @@ -39,7 +39,7 @@ class _ListenableBuilderExampleState extends State { appBar: AppBar(title: const Text('ListenableBuilder Example')), body: ListBody(listNotifier: _listNotifier), floatingActionButton: FloatingActionButton( - onPressed: () => _listNotifier.add(_random.nextInt(1 << 32)), // 1 << 32 is the maximum supported value + onPressed: () => _listNotifier.add(_random.nextInt(1 << 31)), // 1 << 31 is the maximum supported value child: const Icon(Icons.add), ), ), diff --git a/examples/api/test/widgets/transitions/listenable_builder.3_test.dart b/examples/api/test/widgets/transitions/listenable_builder.3_test.dart new file mode 100644 index 0000000000000..a618a4999b207 --- /dev/null +++ b/examples/api/test/widgets/transitions/listenable_builder.3_test.dart @@ -0,0 +1,34 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/transitions/listenable_builder.3.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Tapping FAB adds to values', (WidgetTester tester) async { + await tester.pumpWidget(const example.ListenableBuilderExample()); + + final Finder listContent = find.byWidgetPredicate((Widget widget) => widget is example.ListBody); + + expect(find.text('Current values:'), findsOneWidget); + expect(find.byIcon(Icons.add), findsOneWidget); + expect( + (tester.widget(listContent) as example.ListBody).listNotifier.values.isEmpty, + isTrue, + ); + + await tester.tap(find.byType(FloatingActionButton).first); + await tester.pumpAndSettle(); + expect( + (tester.widget(listContent) as example.ListBody).listNotifier.values.isEmpty, + isFalse, + ); + expect( + (tester.widget(listContent) as example.ListBody).listNotifier.values, + [1464685455], + ); + expect(find.text('1464685455'), findsOneWidget); + }); +} From 727b9fd106d528e0b60b76de5b9197395f198d16 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 19:20:25 -0400 Subject: [PATCH 1033/1547] Roll Flutter Engine from ca513c999257 to 10e2df60b053 (3 revisions) (#133815) https://github.com/flutter/engine/compare/ca513c999257...10e2df60b053 2023-08-31 ian@hixie.ch Avoid saying exactly who can give test exemptions (flutter/engine#45343) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from 5d08dadd2ef4 to bf6b239838d3 (1 revision) (flutter/engine#45344) 2023-08-31 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 7sFO_YvenNXCm6TdK... to _x3hf702RacYnw3E6... (flutter/engine#45348) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 7sFO_YvenNXC to _x3hf702RacY If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d56a3ddbe1864..97a0d9c5e8099 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ca513c99925793198f1a72b2ce17d6d90f37ee3c +10e2df60b053a16daa3868e425646eb837f136f1 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index f948260b0d3b7..ed5d7a1574e3c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -7sFO_YvenNXCm6TdKxn5SBiNvU69Cfj-bRuyClfkN6gC +_x3hf702RacYnw3E6sOdmEi6t8xZzaq4YxOLGSiRZ3UC From 956999a4b9239cfc69e13b348ad1159b67f788e8 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 31 Aug 2023 16:23:44 -0700 Subject: [PATCH 1034/1547] Make Route dispatching memory events. (#133721) --- .../flutter/lib/src/widgets/navigator.dart | 13 ++++++- packages/flutter/test/material/app_test.dart | 5 ++- .../flutter/test/widgets/navigator_test.dart | 36 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index e93ab22af4e6e..ccf3fbfb56ad9 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -140,7 +140,15 @@ abstract class Route { /// /// If the [settings] are not provided, an empty [RouteSettings] object is /// used instead. - Route({ RouteSettings? settings }) : _settings = settings ?? const RouteSettings(); + Route({ RouteSettings? settings }) : _settings = settings ?? const RouteSettings() { + if (kFlutterMemoryAllocationsEnabled) { + MemoryAllocations.instance.dispatchObjectCreated( + library: 'package:flutter/widgets.dart', + className: '$Route<$T>', + object: this, + ); + } + } /// The navigator that the route is in, if any. NavigatorState? get navigator => _navigator; @@ -503,6 +511,9 @@ abstract class Route { void dispose() { _navigator = null; _restorationScopeId.dispose(); + if (kFlutterMemoryAllocationsEnabled) { + MemoryAllocations.instance.dispatchObjectDisposed(object: this); + } } /// Whether this route is the top-most route on the navigator. diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 14d7f270e0e81..16bbac3557fcb 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -338,7 +338,10 @@ void main() { // TODO(polina-c): remove after fixing // https://github.com/flutter/flutter/issues/133695 leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: {'ValueNotifier': 3}, + notDisposedAllowList: { + 'ValueNotifier': 3, + 'MaterialPageRoute': 3, + }, )); testWidgetsWithLeakTracking('Make sure initialRoute is only used the first time', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 52cd934893d7a..886de4a712695 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'navigator_utils.dart'; import 'observer_tester.dart'; @@ -627,6 +628,41 @@ void main() { expect(observations[2].previous, '/A'); }); + testWidgetsWithLeakTracking('$Route dispatches memory events', (WidgetTester tester) async { + Future createAndDisposeRoute() async { + final GlobalKey nav = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + navigatorKey: nav, + home: const Scaffold( + body: Text('home'), + ) + ) + ); + + nav.currentState!.push(MaterialPageRoute(builder: (_) => const Placeholder())); // This should create a route + await tester.pumpAndSettle(); + + nav.currentState!.pop(); + await tester.pumpAndSettle(); // this should dispose the route. + } + + final List events = []; + void listener(ObjectEvent event) { + if (event.object.runtimeType == MaterialPageRoute) { + events.add(event); + } + } + MemoryAllocations.instance.addListener(listener); + + await createAndDisposeRoute(); + expect(events, hasLength(2)); + expect(events.first, isA()); + expect(events.last, isA()); + + MemoryAllocations.instance.removeListener(listener); + }); + testWidgets('Route didAdd and dispose in same frame work', (WidgetTester tester) async { // Regression Test for https://github.com/flutter/flutter/issues/61346. Widget buildNavigator() { From cf051e7db271a4bf994c6706a3d825eab135a45a Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 31 Aug 2023 18:50:39 -0500 Subject: [PATCH 1035/1547] Fix clipBehavior ignored in Scrollable of SingleChildScrollView (#133696) Fixes https://github.com/flutter/flutter/issues/133330 The clipBehavior was not passed to the underlying Scrollable, which informs things like the clip on the StretchingOverscrollIndicator. --- .../src/widgets/single_child_scroll_view.dart | 1 + .../single_child_scroll_view_test.dart | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index 3255c328eb641..d0cec39ae8909 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -248,6 +248,7 @@ class SingleChildScrollView extends StatelessWidget { controller: scrollController, physics: physics, restorationId: restorationId, + clipBehavior: clipBehavior, viewportBuilder: (BuildContext context, ViewportOffset offset) { return _SingleChildViewport( axisDirection: axisDirection, diff --git a/packages/flutter/test/widgets/single_child_scroll_view_test.dart b/packages/flutter/test/widgets/single_child_scroll_view_test.dart index 1cf85166116fb..83b8df226f8ad 100644 --- a/packages/flutter/test/widgets/single_child_scroll_view_test.dart +++ b/packages/flutter/test/widgets/single_child_scroll_view_test.dart @@ -119,13 +119,29 @@ void main() { renderObject.paint(context, Offset.zero); // ignore: avoid_dynamic_calls expect(context.clipBehavior, equals(Clip.hardEdge)); - // 3rd, pump a new widget to check that the render object can update its clip behavior. + // 3rd, check that the underlying Scrollable has the same clipBehavior + // Regression test for https://github.com/flutter/flutter/issues/133330 + Finder scrollable = find.byWidgetPredicate((Widget widget) => widget is Scrollable); + expect( + (tester.widget(scrollable) as Scrollable).clipBehavior, + Clip.hardEdge, + ); + + // 4th, pump a new widget to check that the render object can update its clip behavior. await tester.pumpWidget(SingleChildScrollView(clipBehavior: Clip.antiAlias, child: Container(height: 2000.0))); expect(renderObject.clipBehavior, equals(Clip.antiAlias)); // ignore: avoid_dynamic_calls - // 4th, check that a non-default clip behavior can be sent to the painting context. + // 5th, check that a non-default clip behavior can be sent to the painting context. renderObject.paint(context, Offset.zero); // ignore: avoid_dynamic_calls expect(context.clipBehavior, equals(Clip.antiAlias)); + + // 6th, check that the underlying Scrollable has the same clipBehavior + // Regression test for https://github.com/flutter/flutter/issues/133330 + scrollable = find.byWidgetPredicate((Widget widget) => widget is Scrollable); + expect( + (tester.widget(scrollable) as Scrollable).clipBehavior, + Clip.antiAlias, + ); }); testWidgets('SingleChildScrollView control test', (WidgetTester tester) async { From 62fb15a636ab9078afa8ad3bf6449d8832a3e216 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 19:58:05 -0400 Subject: [PATCH 1036/1547] Roll Flutter Engine from 10e2df60b053 to b867c4da54cc (3 revisions) (#133820) https://github.com/flutter/engine/compare/10e2df60b053...b867c4da54cc 2023-08-31 sra@google.com [web] More efficient fallback font selection (flutter/engine#44526) 2023-08-31 skia-flutter-autoroll@skia.org Roll Dart SDK from ac3bc9f6351a to 9f9bd8cddfb0 (1 revision) (flutter/engine#45352) 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from bf6b239838d3 to e1b27dcecd0a (1 revision) (flutter/engine#45349) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 97a0d9c5e8099..9455ca605068a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -10e2df60b053a16daa3868e425646eb837f136f1 +b867c4da54cc7f5aab511b44e9af95bcc63ff809 From 400702d1d631ea7ef515257b6b8d1195e81bdcdb Mon Sep 17 00:00:00 2001 From: Andrea Cioni Date: Fri, 1 Sep 2023 02:02:04 +0200 Subject: [PATCH 1037/1547] Add an example for `InputChip` generated by user input (#130645) New example for `InputChip` that demonstrate how to create/delete them based on user text inputs. The sample application shows a custom text area where user can enter text. After the user has typed and hits _Enter_ the text will be replaced with an `InputChip` that contains that text. Is it possible to continue typing and add more chips in this way. All of them will be placed in a scrollable horizontal row. Also is it possible to have suggestion displayed below the text input field in case the typed text match some of the available suggestions. Issue I'm trying to solve: - https://github.com/flutter/flutter/issues/128247 **Code structure:** The example app is composed of 2 main components that find places inside `MainScreen`: - `ChipsInput` - `ListView` `ChipsInput` emulates a `TextField` where you can enter text. This text field accepts also a list of values of generic type T (`Topping` in my example), that gets rendered as `InputChip` inside the text field, before the text inserted by the user. This widgets is basically an `InputDecorator` widget that implements `TextInputClient` to get `TextEditingValue` events from the user keyboard. At the end of the input field there is another component, the `TextCursor`, that is displayed just when the user give the focus to the field and emulates the carrets that `TextField` has. There are also some available callbacks that the user can use to capture events in the `ChipsInput` field like: `onChanged`, `onChipTapped`, `onSubmitted` and `onTextChanged`. This last callback is used to build a list of suggestion that will be placed just below the `ChipsInput` field inside the `ListView`. --- .../lib/material/input_chip/input_chip.1.dart | 369 ++++++++++++++++++ .../input_chip/input_chip.1_test.dart | 62 +++ .../flutter/lib/src/material/input_chip.dart | 10 + 3 files changed, 441 insertions(+) create mode 100644 examples/api/lib/material/input_chip/input_chip.1.dart create mode 100644 examples/api/test/material/input_chip/input_chip.1_test.dart diff --git a/examples/api/lib/material/input_chip/input_chip.1.dart b/examples/api/lib/material/input_chip/input_chip.1.dart new file mode 100644 index 0000000000000..c503e6ce7e0fa --- /dev/null +++ b/examples/api/lib/material/input_chip/input_chip.1.dart @@ -0,0 +1,369 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/material.dart'; + +const List _pizzaToppings = [ + 'Olives', + 'Tomato', + 'Cheese', + 'Pepperoni', + 'Bacon', + 'Onion', + 'Jalapeno', + 'Mushrooms', + 'Pineapple', +]; + +void main() => runApp(const EditableChipFieldApp()); + +class EditableChipFieldApp extends StatelessWidget { + const EditableChipFieldApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const EditableChipFieldExample(), + ); + } +} + +class EditableChipFieldExample extends StatefulWidget { + const EditableChipFieldExample({super.key}); + + @override + EditableChipFieldExampleState createState() { + return EditableChipFieldExampleState(); + } +} + +class EditableChipFieldExampleState extends State { + final FocusNode _chipFocusNode = FocusNode(); + List _toppings = [_pizzaToppings.first]; + List _suggestions = []; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Editable Chip Field Sample'), + ), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: ChipsInput( + values: _toppings, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.local_pizza_rounded), + hintText: 'Search for toppings', + ), + strutStyle: const StrutStyle(fontSize: 15), + onChanged: _onChanged, + onSubmitted: _onSubmitted, + chipBuilder: _chipBuilder, + onTextChanged: _onSearchChanged, + ), + ), + if (_suggestions.isNotEmpty) + Expanded( + child: ListView.builder( + itemCount: _suggestions.length, + itemBuilder: (BuildContext context, int index) { + return ToppingSuggestion( + _suggestions[index], + onTap: _selectSuggestion, + ); + }, + ), + ), + ], + ), + ); + } + + Future _onSearchChanged(String value) async { + final List results = await _suggestionCallback(value); + setState(() { + _suggestions = results + .where((String topping) => !_toppings.contains(topping)) + .toList(); + }); + } + + Widget _chipBuilder(BuildContext context, String topping) { + return ToppingInputChip( + topping: topping, + onDeleted: _onChipDeleted, + onSelected: _onChipTapped, + ); + } + + void _selectSuggestion(String topping) { + setState(() { + _toppings.add(topping); + _suggestions = []; + }); + } + + void _onChipTapped(String topping) {} + + void _onChipDeleted(String topping) { + setState(() { + _toppings.remove(topping); + _suggestions = []; + }); + } + + void _onSubmitted(String text) { + if (text.trim().isNotEmpty) { + setState(() { + _toppings = [..._toppings, text.trim()]; + }); + } else { + _chipFocusNode.unfocus(); + setState(() { + _toppings = []; + }); + } + } + + void _onChanged(List data) { + setState(() { + _toppings = data; + }); + } + + FutureOr> _suggestionCallback(String text) { + if (text.isNotEmpty) { + return _pizzaToppings.where((String topping) { + return topping.toLowerCase().contains(text.toLowerCase()); + }).toList(); + } + return const []; + } +} + +class ChipsInput extends StatefulWidget { + const ChipsInput({ + super.key, + required this.values, + this.decoration = const InputDecoration(), + this.style, + this.strutStyle, + required this.chipBuilder, + required this.onChanged, + this.onChipTapped, + this.onSubmitted, + this.onTextChanged, + }); + + final List values; + final InputDecoration decoration; + final TextStyle? style; + final StrutStyle? strutStyle; + + final ValueChanged> onChanged; + final ValueChanged? onChipTapped; + final ValueChanged? onSubmitted; + final ValueChanged? onTextChanged; + + final Widget Function(BuildContext context, T data) chipBuilder; + + @override + ChipsInputState createState() => ChipsInputState(); +} + +class ChipsInputState extends State> { + @visibleForTesting + late final ChipsInputEditingController controller; + + String _previousText = ''; + TextSelection? _previousSelection; + + @override + void initState() { + super.initState(); + + controller = ChipsInputEditingController( + [...widget.values], + widget.chipBuilder, + ); + controller.addListener(_textListener); + } + + @override + void dispose() { + controller.removeListener(_textListener); + controller.dispose(); + + super.dispose(); + } + + void _textListener() { + final String currentText = controller.text; + + if (_previousSelection != null) { + final int currentNumber = countReplacements(currentText); + final int previousNumber = countReplacements(_previousText); + + final int cursorEnd = _previousSelection!.extentOffset; + final int cursorStart = _previousSelection!.baseOffset; + + final List values = [...widget.values]; + + // If the current number and the previous number of replacements are different, then + // the user has deleted the InputChip using the keyboard. In this case, we trigger + // the onChanged callback. We need to be sure also that the current number of + // replacements is different from the input chip to avoid double-deletion. + if (currentNumber < previousNumber && currentNumber != values.length) { + if (cursorStart == cursorEnd) { + values.removeRange(cursorStart - 1, cursorEnd); + } else { + if (cursorStart > cursorEnd) { + values.removeRange(cursorEnd, cursorStart); + } else { + values.removeRange(cursorStart, cursorEnd); + } + } + widget.onChanged(values); + } + } + + _previousText = currentText; + _previousSelection = controller.selection; + } + + static int countReplacements(String text) { + return text.codeUnits + .where((int u) => u == ChipsInputEditingController.kObjectReplacementChar) + .length; + } + + @override + Widget build(BuildContext context) { + controller.updateValues([...widget.values]); + + return TextField( + minLines: 1, + maxLines: 3, + textInputAction: TextInputAction.done, + style: widget.style, + strutStyle: widget.strutStyle, + controller: controller, + onChanged: (String value) => + widget.onTextChanged?.call(controller.textWithoutReplacements), + onSubmitted: (String value) => + widget.onSubmitted?.call(controller.textWithoutReplacements), + ); + } +} + +class ChipsInputEditingController extends TextEditingController { + ChipsInputEditingController(this.values, this.chipBuilder) + : super( + text: String.fromCharCode(kObjectReplacementChar) * values.length, + ); + + // This constant character acts as a placeholder in the TextField text value. + // There will be one character for each of the InputChip displayed. + static const int kObjectReplacementChar = 0xFFFE; + + List values; + + final Widget Function(BuildContext context, T data) chipBuilder; + + /// Called whenever chip is either added or removed + /// from the outside the context of the text field. + void updateValues(List values) { + if (values.length != this.values.length) { + final String char = String.fromCharCode(kObjectReplacementChar); + final int length = values.length; + value = TextEditingValue( + text: char * length, + selection: TextSelection.collapsed(offset: length), + ); + this.values = values; + } + } + + String get textWithoutReplacements { + final String char = String.fromCharCode(kObjectReplacementChar); + return text.replaceAll(RegExp(char), ''); + } + + String get textWithReplacements => text; + + @override + TextSpan buildTextSpan( + {required BuildContext context, TextStyle? style, required bool withComposing}) { + + final Iterable chipWidgets = + values.map((T v) => WidgetSpan(child: chipBuilder(context, v))); + + return TextSpan( + style: style, + children: [ + ...chipWidgets, + if (textWithoutReplacements.isNotEmpty) + TextSpan(text: textWithoutReplacements) + ], + ); + } +} + +class ToppingSuggestion extends StatelessWidget { + const ToppingSuggestion(this.topping, {super.key, this.onTap}); + + final String topping; + final ValueChanged? onTap; + + @override + Widget build(BuildContext context) { + return ListTile( + key: ObjectKey(topping), + leading: CircleAvatar( + child: Text( + topping[0].toUpperCase(), + ), + ), + title: Text(topping), + onTap: () => onTap?.call(topping), + ); + } +} + +class ToppingInputChip extends StatelessWidget { + const ToppingInputChip({ + super.key, + required this.topping, + required this.onDeleted, + required this.onSelected, + }); + + final String topping; + final ValueChanged onDeleted; + final ValueChanged onSelected; + + @override + Widget build(BuildContext context) { + return Container( + margin: const EdgeInsets.only(right: 3), + child: InputChip( + key: ObjectKey(topping), + label: Text(topping), + avatar: CircleAvatar( + child: Text(topping[0].toUpperCase()), + ), + onDeleted: () => onDeleted(topping), + onSelected: (bool value) => onSelected(topping), + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + padding: const EdgeInsets.all(2), + ), + ); + } +} diff --git a/examples/api/test/material/input_chip/input_chip.1_test.dart b/examples/api/test/material/input_chip/input_chip.1_test.dart new file mode 100644 index 0000000000000..e55a483efd761 --- /dev/null +++ b/examples/api/test/material/input_chip/input_chip.1_test.dart @@ -0,0 +1,62 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/input_chip/input_chip.1.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + final String replacementChar = String.fromCharCode( + example.ChipsInputEditingController.kObjectReplacementChar); + + testWidgets('User input generates InputChips', (WidgetTester tester) async { + await tester.pumpWidget( + const example.EditableChipFieldApp(), + ); + await tester.pumpAndSettle(); + + expect(find.byType(example.EditableChipFieldApp), findsOneWidget); + expect(find.byType(example.ChipsInput), findsOneWidget); + expect(find.byType(InputChip), findsOneWidget); + + example.ChipsInputState state = + tester.state(find.byType(example.ChipsInput)); + expect(state.controller.textWithoutReplacements.isEmpty, true); + + await tester.tap(find.byType(example.ChipsInput)); + await tester.pumpAndSettle(); + expect(tester.testTextInput.isVisible, true); + // Simulating text typing on the input field. + tester.testTextInput.enterText('${replacementChar}ham'); + await tester.pumpAndSettle(); + expect(find.byType(InputChip), findsOneWidget); + + state = tester.state(find.byType(example.ChipsInput)); + await tester.pumpAndSettle(); + expect(state.controller.textWithoutReplacements, 'ham'); + + // Add new InputChip by sending the "done" action. + await tester.testTextInput.receiveAction(TextInputAction.done); + await tester.pumpAndSettle(); + expect(state.controller.textWithoutReplacements.isEmpty, true); + + expect(find.byType(InputChip), findsNWidgets(2)); + + // Simulate item deletion. + await tester.tap(find.descendant( + of: find.byType(InputChip), + matching: find.byType(InkWell).last, + )); + await tester.pumpAndSettle(); + expect(find.byType(InputChip), findsOneWidget); + + await tester.tap(find.descendant( + of: find.byType(InputChip), + matching: find.byType(InkWell).last, + )); + await tester.pumpAndSettle(); + expect(find.byType(InputChip), findsNothing); + }); +} diff --git a/packages/flutter/lib/src/material/input_chip.dart b/packages/flutter/lib/src/material/input_chip.dart index 56ef93fe6c94d..e2146d14d481c 100644 --- a/packages/flutter/lib/src/material/input_chip.dart +++ b/packages/flutter/lib/src/material/input_chip.dart @@ -42,6 +42,16 @@ import 'theme_data.dart'; /// ** See code in examples/api/lib/material/input_chip/input_chip.0.dart ** /// {@end-tool} /// +/// +/// {@tool dartpad} +/// The following example shows how to generate [InputChip]s from +/// user text input. When the user enters a pizza topping in the text field, +/// the user is presented with a list of suggestions. When selecting one of the +/// suggestions, an [InputChip] is generated in the text field. +/// +/// ** See code in examples/api/lib/material/input_chip/input_chip.1.dart ** +/// {@end-tool} +/// /// ## Material Design 3 /// /// [InputChip] can be used for Input chips from Material Design 3. From d67ec7c7715bad013c1b00e8197a8ee93868c63f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 20:47:40 -0400 Subject: [PATCH 1038/1547] Roll Flutter Engine from b867c4da54cc to 494fd7fe85a3 (1 revision) (#133823) https://github.com/flutter/engine/compare/b867c4da54cc...494fd7fe85a3 2023-08-31 skia-flutter-autoroll@skia.org Roll Skia from e1b27dcecd0a to 818f20f3f653 (2 revisions) (flutter/engine#45353) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9455ca605068a..73767802c64a9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b867c4da54cc7f5aab511b44e9af95bcc63ff809 +494fd7fe85a30ce4dfc28058961bb71920f514cc From 0a305bbc54209258820dea425516d10e65c27e13 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 21:41:28 -0400 Subject: [PATCH 1039/1547] Roll Flutter Engine from 494fd7fe85a3 to f28eb11e5bd4 (1 revision) (#133825) https://github.com/flutter/engine/compare/494fd7fe85a3...f28eb11e5bd4 2023-08-31 jonahwilliams@google.com [Impeller] copy data out of DlVertices. (flutter/engine#45355) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 73767802c64a9..3f19672edf9bb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -494fd7fe85a30ce4dfc28058961bb71920f514cc +f28eb11e5bd4a795dd15bc0c2dda4c4f634caf5e From a3a651d82270ff0c40ab2d1615ef6d36af11d580 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 23:04:18 -0400 Subject: [PATCH 1040/1547] Roll Flutter Engine from f28eb11e5bd4 to 01e74b252ee0 (1 revision) (#133830) https://github.com/flutter/engine/compare/f28eb11e5bd4...01e74b252ee0 2023-09-01 bdero@google.com Bump impeller-cmake-example to head (flutter/engine#45359) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3f19672edf9bb..f17bf6b23ee24 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f28eb11e5bd4a795dd15bc0c2dda4c4f634caf5e +01e74b252ee0d3a2fd828d8680e6cf35ebbd599e From e9448fdf619e042525743360e1096c155fb495b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 31 Aug 2023 23:49:06 -0400 Subject: [PATCH 1041/1547] Roll Flutter Engine from 01e74b252ee0 to a9ebed54c451 (2 revisions) (#133831) https://github.com/flutter/engine/compare/01e74b252ee0...a9ebed54c451 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 818f20f3f653 to e585fdc18134 (1 revision) (flutter/engine#45363) 2023-09-01 skia-flutter-autoroll@skia.org Roll Dart SDK from 9f9bd8cddfb0 to 0c121a6431cc (1 revision) (flutter/engine#45362) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f17bf6b23ee24..ae879335f41bd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -01e74b252ee0d3a2fd828d8680e6cf35ebbd599e +a9ebed54c45128792dc50b6720a94c448143049e From 4324d2112e7b94c6581d523049b90e97b3f3d656 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 1 Sep 2023 02:45:32 -0400 Subject: [PATCH 1042/1547] Roll Flutter Engine from a9ebed54c451 to 0769aba5b7d8 (2 revisions) (#133839) https://github.com/flutter/engine/compare/a9ebed54c451...0769aba5b7d8 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from e585fdc18134 to 2916365d0fa6 (1 revision) (flutter/engine#45366) 2023-09-01 jonahwilliams@google.com [Impeller] use correct blend mode for performance overlay (flutter/engine#45365) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ae879335f41bd..f57dd3befadbc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a9ebed54c45128792dc50b6720a94c448143049e +0769aba5b7d862485de7544aa3ba3c42712902f8 From c141126df0273012af4ec7bba1d0905073134985 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 1 Sep 2023 03:45:52 -0400 Subject: [PATCH 1043/1547] Roll Flutter Engine from 0769aba5b7d8 to 09cb3d99f24e (1 revision) (#133842) https://github.com/flutter/engine/compare/0769aba5b7d8...09cb3d99f24e 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 2916365d0fa6 to 6d95a1db276d (1 revision) (flutter/engine#45368) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f57dd3befadbc..2e8888e73df2e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0769aba5b7d862485de7544aa3ba3c42712902f8 +09cb3d99f24e1a14a2adeb09d56d7b7d9858f3e6 From f0b682bc053da57835a956a3b443fb2dceff81cb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 1 Sep 2023 04:43:11 -0400 Subject: [PATCH 1044/1547] Roll Flutter Engine from 09cb3d99f24e to ced8f1a71206 (1 revision) (#133844) https://github.com/flutter/engine/compare/09cb3d99f24e...ced8f1a71206 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 6d95a1db276d to 4eb9b17d8e84 (1 revision) (flutter/engine#45369) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2e8888e73df2e..23b9fa6639a10 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -09cb3d99f24e1a14a2adeb09d56d7b7d9858f3e6 +ced8f1a71206f4ffb66a4b43bd451d5f038c4ab9 From 510ecaa4e76cbe740bad20071040cb7cd15e7170 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Fri, 1 Sep 2023 11:08:21 +0200 Subject: [PATCH 1045/1547] Fix MaterialState.pressed is missing when pressing button with keyboard (#133558) ## Description This PR fixes changes how `InkWell` reacts to keyboard activation. **Before**: the activation started a splash and immediately terminated it which did not let time for widgets that resolve material state properties to react (visually it also mean the splash does not have time to expand). **After**: the activation starts and terminates after a delay (I arbitrary choose 200ms for the moment). ## Related Issue Fixes https://github.com/flutter/flutter/issues/132377. ## Tests Adds one test. --- .../flutter/lib/src/material/ink_well.dart | 29 +++++++++++++-- .../flutter/test/material/ink_well_test.dart | 35 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index 8814a847ad1c6..fe0fa9aca21fe 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; import 'dart:collection'; import 'package:flutter/foundation.dart'; @@ -809,8 +810,8 @@ class _InkResponseState extends State<_InkResponseStateWidget> bool _hovering = false; final Map<_HighlightType, InkHighlight?> _highlights = <_HighlightType, InkHighlight?>{}; late final Map> _actionMap = >{ - ActivateIntent: CallbackAction(onInvoke: simulateTap), - ButtonActivateIntent: CallbackAction(onInvoke: simulateTap), + ActivateIntent: CallbackAction(onInvoke: activateOnIntent), + ButtonActivateIntent: CallbackAction(onInvoke: activateOnIntent), }; MaterialStatesController? internalStatesController; @@ -818,6 +819,9 @@ class _InkResponseState extends State<_InkResponseStateWidget> final ObserverList<_ParentInkResponseState> _activeChildren = ObserverList<_ParentInkResponseState>(); + static const Duration _activationDuration = Duration(milliseconds: 100); + Timer? _activationTimer; + @override void markChildInkResponsePressed(_ParentInkResponseState childState, bool value) { final bool lastAnyPressed = _anyChildInkResponsePressed; @@ -833,6 +837,25 @@ class _InkResponseState extends State<_InkResponseStateWidget> } bool get _anyChildInkResponsePressed => _activeChildren.isNotEmpty; + void activateOnIntent(Intent? intent) { + _activationTimer?.cancel(); + _activationTimer = null; + _startNewSplash(context: context); + _currentSplash?.confirm(); + _currentSplash = null; + if (widget.onTap != null) { + if (widget.enableFeedback) { + Feedback.forTap(context); + } + widget.onTap?.call(); + } + // Delay the call to `updateHighlight` to simulate a pressed delay + // and give MaterialStatesController listeners a chance to react. + _activationTimer = Timer(_activationDuration, () { + updateHighlight(_HighlightType.pressed, value: false); + }); + } + void simulateTap([Intent? intent]) { _startNewSplash(context: context); handleTap(); @@ -917,6 +940,8 @@ class _InkResponseState extends State<_InkResponseStateWidget> FocusManager.instance.removeHighlightModeListener(handleFocusHighlightModeChange); statesController.removeListener(handleStatesControllerChange); internalStatesController?.dispose(); + _activationTimer?.cancel(); + _activationTimer = null; super.dispose(); } diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index 8f3903ad9feb1..0fe244a3c4f4d 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -2253,4 +2253,39 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(log, equals(['tap'])); log.clear(); }); + + testWidgetsWithLeakTracking('InkWell activation action does not end immediately', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132377. + final MaterialStatesController controller = MaterialStatesController(); + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: Shortcuts( + shortcuts: const { + SingleActivator(LogicalKeyboardKey.enter): ButtonActivateIntent(), + }, + child: Material( + child: Center( + child: InkWell( + autofocus: true, + onTap: () {}, + statesController: controller, + ), + ), + ), + ), + )); + + // Invoke the InkWell activation action. + await tester.sendKeyEvent(LogicalKeyboardKey.enter); + + // The InkWell is in pressed state. + await tester.pump(const Duration(milliseconds: 99)); + expect(controller.value.contains(MaterialState.pressed), isTrue); + + await tester.pumpAndSettle(); + expect(controller.value.contains(MaterialState.pressed), isFalse); + + controller.dispose(); + }); } From e3261999237659eead171caf16979c690732d0d4 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Fri, 1 Sep 2023 11:24:33 +0200 Subject: [PATCH 1046/1547] Add more documentation for SystemChannels.keyboard getKeyboardState (#133663) ## Description This PR adds some documentation to SystemChannels.keyboard getKeyboardState. This method was added in https://github.com/flutter/flutter/pull/122885. ## Related Issue Fixes https://github.com/flutter/flutter/issues/132938. ## Tests Documentation only. --- packages/flutter/lib/src/services/hardware_keyboard.dart | 4 ++++ packages/flutter/lib/src/services/system_channels.dart | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/flutter/lib/src/services/hardware_keyboard.dart b/packages/flutter/lib/src/services/hardware_keyboard.dart index 7c2af2bd843b6..ee994306f41bd 100644 --- a/packages/flutter/lib/src/services/hardware_keyboard.dart +++ b/packages/flutter/lib/src/services/hardware_keyboard.dart @@ -532,6 +532,10 @@ class HardwareKeyboard { } /// Query the engine and update _pressedKeys accordingly to the engine answer. + // + /// Both the framework and the engine maintain a state of the current pressed + /// keys. There are edge cases, related to startup and restart, where the framework + /// needs to resynchronize its keyboard state. Future syncKeyboardState() async { final Map? keyboardState = await SystemChannels.keyboard.invokeMapMethod( 'getKeyboardState', diff --git a/packages/flutter/lib/src/services/system_channels.dart b/packages/flutter/lib/src/services/system_channels.dart index 3a65302a2d1e1..5311d36c7c4c2 100644 --- a/packages/flutter/lib/src/services/system_channels.dart +++ b/packages/flutter/lib/src/services/system_channels.dart @@ -503,6 +503,10 @@ abstract final class SystemChannels { /// represents a pressed keyboard key. The entry key is the physical /// key ID and the entry value is the logical key ID. /// + /// Both the framework and the engine maintain a state of the current + /// pressed keys. There are edge cases, related to startup and restart, + /// where the framework needs to resynchronize its keyboard state. + /// /// See also: /// /// * [HardwareKeyboard.syncKeyboardState], which uses this channel to synchronize From eb77b525c2d7b22dc0ef533bb5558f6c9a9fcaa2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 1 Sep 2023 10:43:24 -0400 Subject: [PATCH 1047/1547] Roll Flutter Engine from ced8f1a71206 to 4c085b883d6f (2 revisions) (#133857) https://github.com/flutter/engine/compare/ced8f1a71206...4c085b883d6f 2023-09-01 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from _x3hf702RacYnw3E6... to sk7JBGzW1Jw10Wy-T... (flutter/engine#45372) 2023-09-01 leroux_bruno@yahoo.fr [Linux] Fix channel buffers control commands error handling (flutter/engine#45056) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from _x3hf702RacY to sk7JBGzW1Jw1 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 23b9fa6639a10..b8c39e63b76a7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ced8f1a71206f4ffb66a4b43bd451d5f038c4ab9 +4c085b883d6fc21c6e5a6348796db7477e317715 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ed5d7a1574e3c..661d8063ee75b 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -_x3hf702RacYnw3E6sOdmEi6t8xZzaq4YxOLGSiRZ3UC +sk7JBGzW1Jw10Wy-TPCTa9rp1SvNoaleR0wHIpz7HBEC From 1b1c8a160731be777e92885c205fc5d4fcfd0e6b Mon Sep 17 00:00:00 2001 From: Mark O'Sullivan Date: Fri, 1 Sep 2023 12:36:48 -0300 Subject: [PATCH 1048/1547] Fixed `PaginatedDataTable` not using `dataRowMinHeight` and `dataRowMaxHeight` from Theme (#133634) `PaginatedDataTable` will now make use of `dataRowMinHeight` and `dataRowMaxHeight` from the Theme *List which issues are fixed by this PR. You must list at least one issue.* Resolves #133633 --- .../src/material/paginated_data_table.dart | 10 +++--- .../material/paginated_data_table_test.dart | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index 06140bebb8fb7..eb04e9d00cee0 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -122,8 +122,8 @@ class PaginatedDataTable extends StatefulWidget { assert(dataRowMinHeight == null || dataRowMaxHeight == null || dataRowMaxHeight >= dataRowMinHeight), assert(dataRowHeight == null || (dataRowMinHeight == null && dataRowMaxHeight == null), 'dataRowHeight ($dataRowHeight) must not be set if dataRowMinHeight ($dataRowMinHeight) or dataRowMaxHeight ($dataRowMaxHeight) are set.'), - dataRowMinHeight = dataRowHeight ?? dataRowMinHeight ?? kMinInteractiveDimension, - dataRowMaxHeight = dataRowHeight ?? dataRowMaxHeight ?? kMinInteractiveDimension, + dataRowMinHeight = dataRowHeight ?? dataRowMinHeight, + dataRowMaxHeight = dataRowHeight ?? dataRowMaxHeight, assert(rowsPerPage > 0), assert(() { if (onRowsPerPageChanged != null) { @@ -192,13 +192,13 @@ class PaginatedDataTable extends StatefulWidget { /// /// This value is optional and defaults to [kMinInteractiveDimension] if not /// specified. - final double dataRowMinHeight; + final double? dataRowMinHeight; /// The maximum height of each row (excluding the row that contains column headings). /// - /// This value is optional and defaults to kMinInteractiveDimension if not + /// This value is optional and defaults to [kMinInteractiveDimension] if not /// specified. - final double dataRowMaxHeight; + final double? dataRowMaxHeight; /// The height of the heading row. /// diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index db7335627d4e2..53c289e8b18fe 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -1022,6 +1022,38 @@ void main() { await binding.setSurfaceSize(originalSize); }); + testWidgets('dataRowMinHeight & dataRowMaxHeight if not set will use DataTableTheme', (WidgetTester tester) async { + addTearDown(() => binding.setSurfaceSize(null)); + await binding.setSurfaceSize(const Size(800, 800)); + + const double minMaxDataRowHeight = 30.0; + + await tester.pumpWidget(MaterialApp( + theme: ThemeData( + dataTableTheme: const DataTableThemeData( + dataRowMinHeight: minMaxDataRowHeight, + dataRowMaxHeight: minMaxDataRowHeight, + ), + ), + home: PaginatedDataTable( + header: const Text('Test table'), + source: TestDataSource(allowSelection: true), + columns: const [ + DataColumn(label: Text('Name')), + DataColumn(label: Text('Calories'), numeric: true), + DataColumn(label: Text('Generation')), + ], + ), + )); + + final Container rowContainer = tester.widget(find.descendant( + of: find.byType(Table), + matching: find.byType(Container), + ).last); + expect(rowContainer.constraints?.minHeight, minMaxDataRowHeight); + expect(rowContainer.constraints?.maxHeight, minMaxDataRowHeight); + }); + testWidgets('PaginatedDataTable custom checkboxHorizontalMargin properly applied', (WidgetTester tester) async { const double customCheckboxHorizontalMargin = 15.0; const double customHorizontalMargin = 10.0; From 0f3bd90d9b108904cc0390e899c2b3c6ee2e76e0 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 1 Sep 2023 08:37:38 -0700 Subject: [PATCH 1049/1547] =?UTF-8?q?Adds=20a=20parent=20scope=20Traversal?= =?UTF-8?q?EdgeBehavior=20and=20fixes=20modal=20route=20to=20no=E2=80=A6?= =?UTF-8?q?=20(#130841)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …t trap the focus fixes https://github.com/flutter/flutter/issues/112567 Several things I done: 1. add new enum `parentScope` 2. refactor _sortAllDescendants so that it doesn't recursively looking into its descendant when it encounter a FocusScopeNode. 3. When the nextFocus try to focus into a FocusScopeNode, it will try to find the first focusable FocusNode in traversal order and focus it instead if it doesn't have a first focus. 4. Change the default in Navigator to always be `parentScope` 5. Only the root navigator will use `leaveFlutterView` if platform is web. Previously 2 and 3 are not needed because once a focusscope trapped the focus, there isn't a chance where the parent focusscope have to deal with next focus. If we don't do 2 and 3 after the change, it will cause it to stuck in the current scope again. Because once the focus leave the current scope, it needs to also remove the first focus in that scope (so that it can start fresh when focus traversal back to the scope in the future). At this point the current scope will have the primary focus without the first focus. The parent scope will then try to find the next focus, and it will place the focus to the first traversal child in the current scope again. ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- packages/flutter/lib/src/widgets/app.dart | 1 + .../lib/src/widgets/focus_traversal.dart | 138 +++++++++++++++--- .../flutter/lib/src/widgets/navigator.dart | 4 +- packages/flutter/lib/src/widgets/routes.dart | 25 +++- .../test/material/icon_button_test.dart | 10 +- .../flutter/test/widgets/actions_test.dart | 2 +- .../test/widgets/focus_traversal_test.dart | 86 +++++++++++ .../flutter/test/widgets/navigator_test.dart | 19 ++- 8 files changed, 250 insertions(+), 35 deletions(-) diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index d8d649c103a45..7a524639fb423 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -1685,6 +1685,7 @@ class _WidgetsAppState extends State with WidgetsBindingObserver { }, onUnknownRoute: _onUnknownRoute, observers: widget.navigatorObservers!, + routeTraversalEdgeBehavior: kIsWeb ? TraversalEdgeBehavior.leaveFlutterView : TraversalEdgeBehavior.parentScope, reportsRouteUpdateToEngine: true, ), ); diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 203e13252958d..f67080c71a028 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -120,6 +120,16 @@ enum TraversalEdgeBehavior { /// address bar, escape an `iframe`, or focus on HTML elements other than /// those managed by Flutter. leaveFlutterView, + + /// Allows focus to traverse up to parent scope. + /// + /// When reaching the edge of the current scope, requesting the next focus + /// will look up to the parent scope of the current scope and focus the focus + /// node next to the current scope. + /// + /// If there is no parent scope above the current scope, fallback to + /// [closedLoop] behavior. + parentScope, } /// Determines how focusable widgets are traversed within a [FocusTraversalGroup]. @@ -186,6 +196,60 @@ abstract class FocusTraversalPolicy with Diagnosticable { ); } + /// Request focus on a focus node as a result of a tab traversal. + /// + /// If the `node` is a [FocusScopeNode], this method will recursively find + /// the next focus from its descendants until it find a regular [FocusNode]. + /// + /// Returns true if this method focused a new focus node. + bool _requestTabTraversalFocus( + FocusNode node, { + ScrollPositionAlignmentPolicy? alignmentPolicy, + double? alignment, + Duration? duration, + Curve? curve, + required bool forward, + }) { + if (node is FocusScopeNode) { + if (node.focusedChild != null) { + // Can't stop here as the `focusedChild` may be a focus scope node + // without a first focus. The first focus will be picked in the + // next iteration. + return _requestTabTraversalFocus( + node.focusedChild!, + alignmentPolicy: alignmentPolicy, + alignment: alignment, + duration: duration, + curve: curve, + forward: forward, + ); + } + final List sortedChildren = _sortAllDescendants(node, node); + if (sortedChildren.isNotEmpty) { + _requestTabTraversalFocus( + forward ? sortedChildren.first : sortedChildren.last, + alignmentPolicy: alignmentPolicy, + alignment: alignment, + duration: duration, + curve: curve, + forward: forward, + ); + // Regardless if _requestTabTraversalFocus return true or false, a first + // focus has been picked. + return true; + } + } + final bool nodeHadPrimaryFocus = node.hasPrimaryFocus; + requestFocusCallback( + node, + alignmentPolicy: alignmentPolicy, + alignment: alignment, + duration: duration, + curve: curve, + ); + return !nodeHadPrimaryFocus; + } + /// Returns the node that should receive focus if focus is traversing /// forwards, and there is no current focus. /// @@ -352,10 +416,21 @@ abstract class FocusTraversalPolicy with Diagnosticable { @protected Iterable sortDescendants(Iterable descendants, FocusNode currentNode); - Map _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { + static Iterable _getDescendantsWithoutExpandingScope(FocusNode node) { + final List result = []; + for (final FocusNode child in node.children) { + if (child is! FocusScopeNode) { + result.addAll(_getDescendantsWithoutExpandingScope(child)); + } + result.add(child); + } + return result; + } + + static Map _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { final FocusTraversalPolicy defaultPolicy = scopeGroupNode?.policy ?? ReadingOrderTraversalPolicy(); final Map groups = {}; - for (final FocusNode node in scope.descendants) { + for (final FocusNode node in _getDescendantsWithoutExpandingScope(scope)) { final _FocusTraversalGroupNode? groupNode = FocusTraversalGroup._getGroupNode(node); // Group nodes need to be added to their parent's node, or to the "null" // node if no parent is found. This creates the hierarchy of group nodes @@ -388,7 +463,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { // Sort all descendants, taking into account the FocusTraversalGroup // that they are each in, and filtering out non-traversable/focusable nodes. - List _sortAllDescendants(FocusScopeNode scope, FocusNode currentNode) { + static List _sortAllDescendants(FocusScopeNode scope, FocusNode currentNode) { final _FocusTraversalGroupNode? scopeGroupNode = FocusTraversalGroup._getGroupNode(scope); // Build the sorting data structure, separating descendants into groups. final Map groups = _findGroups(scope, scopeGroupNode, currentNode); @@ -473,30 +548,42 @@ abstract class FocusTraversalPolicy with Diagnosticable { if (focusedChild == null) { final FocusNode? firstFocus = forward ? findFirstFocus(currentNode) : findLastFocus(currentNode); if (firstFocus != null) { - requestFocusCallback( + return _requestTabTraversalFocus( firstFocus, alignmentPolicy: forward ? ScrollPositionAlignmentPolicy.keepVisibleAtEnd : ScrollPositionAlignmentPolicy.keepVisibleAtStart, + forward: forward, ); - return true; } } focusedChild ??= nearestScope; final List sortedNodes = _sortAllDescendants(nearestScope, focusedChild); - assert(sortedNodes.contains(focusedChild)); - if (sortedNodes.length < 2) { - // If there are no nodes to traverse to, like when descendantsAreTraversable - // is false or skipTraversal for all the nodes is true. - return false; - } + if (forward && focusedChild == sortedNodes.last) { switch (nearestScope.traversalEdgeBehavior) { case TraversalEdgeBehavior.leaveFlutterView: focusedChild.unfocus(); return false; + case TraversalEdgeBehavior.parentScope: + final FocusScopeNode? parentScope = nearestScope.enclosingScope; + if (parentScope != null && parentScope != FocusManager.instance.rootScope) { + focusedChild.unfocus(); + parentScope.nextFocus(); + // Verify the focus really has changed. + return focusedChild.enclosingScope?.focusedChild != focusedChild; + } + // No valid parent scope. Fallback to closed loop behavior. + return _requestTabTraversalFocus( + sortedNodes.first, + alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd, + forward: forward, + ); case TraversalEdgeBehavior.closedLoop: - requestFocusCallback(sortedNodes.first, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd); - return true; + return _requestTabTraversalFocus( + sortedNodes.first, + alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd, + forward: forward, + ); } } if (!forward && focusedChild == sortedNodes.first) { @@ -504,9 +591,26 @@ abstract class FocusTraversalPolicy with Diagnosticable { case TraversalEdgeBehavior.leaveFlutterView: focusedChild.unfocus(); return false; + case TraversalEdgeBehavior.parentScope: + final FocusScopeNode? parentScope = nearestScope.enclosingScope; + if (parentScope != null && parentScope != FocusManager.instance.rootScope) { + focusedChild.unfocus(); + parentScope.previousFocus(); + // Verify the focus really has changed. + return focusedChild.enclosingScope?.focusedChild != focusedChild; + } + // No valid parent scope. Fallback to closed loop behavior. + return _requestTabTraversalFocus( + sortedNodes.last, + alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart, + forward: forward, + ); case TraversalEdgeBehavior.closedLoop: - requestFocusCallback(sortedNodes.last, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart); - return true; + return _requestTabTraversalFocus( + sortedNodes.last, + alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart, + forward: forward, + ); } } @@ -514,11 +618,11 @@ abstract class FocusTraversalPolicy with Diagnosticable { FocusNode? previousNode; for (final FocusNode node in maybeFlipped) { if (previousNode == focusedChild) { - requestFocusCallback( + return _requestTabTraversalFocus( node, alignmentPolicy: forward ? ScrollPositionAlignmentPolicy.keepVisibleAtEnd : ScrollPositionAlignmentPolicy.keepVisibleAtStart, + forward: forward, ); - return true; } previousNode = node; } diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index ccf3fbfb56ad9..bc57d8a391985 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -1146,9 +1146,7 @@ class DefaultTransitionDelegate extends TransitionDelegate { /// The default value of [Navigator.routeTraversalEdgeBehavior]. /// /// {@macro flutter.widgets.navigator.routeTraversalEdgeBehavior} -const TraversalEdgeBehavior kDefaultRouteTraversalEdgeBehavior = kIsWeb - ? TraversalEdgeBehavior.leaveFlutterView - : TraversalEdgeBehavior.closedLoop; +const TraversalEdgeBehavior kDefaultRouteTraversalEdgeBehavior = TraversalEdgeBehavior.parentScope; /// A widget that manages a set of child widgets with a stack discipline. /// diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index b51cb4f61c7c7..fc954fa0a1a2f 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -834,7 +834,9 @@ class _ModalScopeState extends State<_ModalScope> { late Listenable _listenable; /// The node this scope will use for its root [FocusScope] widget. - final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: '$_ModalScopeState Focus Scope'); + final FocusScopeNode focusScopeNode = FocusScopeNode( + debugLabel: '$_ModalScopeState Focus Scope', + ); final ScrollController primaryScrollController = ScrollController(); @override @@ -936,6 +938,8 @@ class _ModalScopeState extends State<_ModalScope> { controller: primaryScrollController, child: FocusScope( node: focusScopeNode, // immutable + // Only top most route can participate in focus traversal. + skipTraversal: !widget.route.isCurrent, child: RepaintBoundary( child: AnimatedBuilder( animation: _listenable, // immutable @@ -1704,11 +1708,26 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute? nextRoute) { + super.didChangeNext(nextRoute); + changedInternalState(); + } + + @override + void didPopNext(Route nextRoute) { + super.didPopNext(nextRoute); + changedInternalState(); + } + @override void changedInternalState() { super.changedInternalState(); - setState(() { /* internal state already changed */ }); - _modalBarrier.markNeedsBuild(); + // No need to mark dirty if this method is called during build phase. + if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks) { + setState(() { /* internal state already changed */ }); + _modalBarrier.markNeedsBuild(); + } _modalScope.maintainState = maintainState; } diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index fce7855170a55..02c6ad08d4270 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -4,6 +4,7 @@ import 'dart:ui'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -792,6 +793,10 @@ void main() { testWidgetsWithLeakTracking("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: 'IconButton 1'); final FocusNode focusNode2 = FocusNode(debugLabel: 'IconButton 2'); + addTearDown(() { + focusNode1.dispose(); + focusNode2.dispose(); + }); await tester.pumpWidget( wrap( @@ -821,11 +826,8 @@ void main() { expect(focusNode1.nextFocus(), isFalse); await tester.pump(); - expect(focusNode1.hasPrimaryFocus, isTrue); + expect(focusNode1.hasPrimaryFocus, !kIsWeb); expect(focusNode2.hasPrimaryFocus, isFalse); - - focusNode1.dispose(); - focusNode2.dispose(); }); group('feedback', () { diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index b59f17f8eafc2..6a246304e3f81 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -965,7 +965,7 @@ void main() { expect(buttonNode2.hasFocus, isFalse); primaryFocus!.nextFocus(); await tester.pump(); - expect(buttonNode1.hasFocus, isTrue); + expect(buttonNode1.hasFocus, isFalse); expect(buttonNode2.hasFocus, isFalse); }, ); diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index ff0b8c9729748..04cf497d08da4 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -430,6 +430,92 @@ void main() { }); + testWidgets('Nested navigator does not trap focus', (WidgetTester tester) async { + final FocusNode node1 = FocusNode(); + final FocusNode node2 = FocusNode(); + final FocusNode node3 = FocusNode(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: FocusScope( + child: Column( + children: [ + Focus( + focusNode: node1, + child: const SizedBox(width: 100, height: 100), + ), + SizedBox( + width: 100, + height: 100, + child: Navigator( + pages: >[ + MaterialPage( + child: Focus( + focusNode: node2, + child: const SizedBox(width: 100, height: 100), + ), + ), + ], + onPopPage: (_, __) => false, + ), + ), + Focus( + focusNode: node3, + child: const SizedBox(width: 100, height: 100), + ), + ], + ), + ), + ), + ), + ); + + node1.requestFocus(); + await tester.pump(); + + expect(node1.hasFocus, isTrue); + expect(node2.hasFocus, isFalse); + expect(node3.hasFocus, isFalse); + + node1.nextFocus(); + await tester.pump(); + expect(node1.hasFocus, isFalse); + expect(node2.hasFocus, isTrue); + expect(node3.hasFocus, isFalse); + + node2.nextFocus(); + await tester.pump(); + expect(node1.hasFocus, isFalse); + expect(node2.hasFocus, isFalse); + expect(node3.hasFocus, isTrue); + + node3.nextFocus(); + await tester.pump(); + expect(node1.hasFocus, isTrue); + expect(node2.hasFocus, isFalse); + expect(node3.hasFocus, isFalse); + + node1.previousFocus(); + await tester.pump(); + expect(node1.hasFocus, isFalse); + expect(node2.hasFocus, isFalse); + expect(node3.hasFocus, isTrue); + + node3.previousFocus(); + await tester.pump(); + expect(node1.hasFocus, isFalse); + expect(node2.hasFocus, isTrue); + expect(node3.hasFocus, isFalse); + + node2.previousFocus(); + await tester.pump(); + expect(node1.hasFocus, isTrue); + expect(node2.hasFocus, isFalse); + expect(node3.hasFocus, isFalse); + }); + group(ReadingOrderTraversalPolicy, () { testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 886de4a712695..95111931e34d2 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -1487,29 +1487,34 @@ void main() { return result; }, )); - expect(log, ['building page 1 - false']); + final List expected = ['building page 1 - false']; + expect(log, expected); key.currentState!.pushReplacement(PageRouteBuilder( pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { log.add('building page 2 - ${ModalRoute.of(context)!.canPop}'); return const Placeholder(); }, )); - expect(log, ['building page 1 - false']); + expect(log, expected); await tester.pump(); - expect(log, ['building page 1 - false', 'building page 2 - false']); + expected.add('building page 2 - false'); + expected.add('building page 1 - false'); // page 1 is rebuilt again because isCurrent changed. + expect(log, expected); await tester.pump(const Duration(milliseconds: 150)); - expect(log, ['building page 1 - false', 'building page 2 - false']); + expect(log, expected); key.currentState!.pushReplacement(PageRouteBuilder( pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) { log.add('building page 3 - ${ModalRoute.of(context)!.canPop}'); return const Placeholder(); }, )); - expect(log, ['building page 1 - false', 'building page 2 - false']); + expect(log, expected); await tester.pump(); - expect(log, ['building page 1 - false', 'building page 2 - false', 'building page 3 - false']); + expected.add('building page 3 - false'); + expected.add('building page 2 - false'); // page 2 is rebuilt again because isCurrent changed. + expect(log, expected); await tester.pump(const Duration(milliseconds: 200)); - expect(log, ['building page 1 - false', 'building page 2 - false', 'building page 3 - false']); + expect(log, expected); }); testWidgets('route semantics', (WidgetTester tester) async { From 78ff1226c9f90189a5f93dc54010873079073149 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 1 Sep 2023 08:53:53 -0700 Subject: [PATCH 1050/1547] Test cover more tests with leak tracking. (#133828) --- .../test/material/card_theme_test.dart | 19 ++-- .../material/checkbox_list_tile_test.dart | 4 +- .../flutter/test/material/checkbox_test.dart | 86 +++++++++++-------- .../test/material/checkbox_theme_test.dart | 2 +- .../flutter/test/material/debug_test.dart | 2 +- .../flutter/test/material/divider_test.dart | 21 ++--- .../test/material/divider_theme_test.dart | 27 +++--- 7 files changed, 87 insertions(+), 74 deletions(-) diff --git a/packages/flutter/test/material/card_theme_test.dart b/packages/flutter/test/material/card_theme_test.dart index 2e22d13132a01..f9ba9ce3fe571 100644 --- a/packages/flutter/test/material/card_theme_test.dart +++ b/packages/flutter/test/material/card_theme_test.dart @@ -9,6 +9,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('CardTheme copyWith, ==, hashCode basics', () { @@ -22,7 +23,7 @@ void main() { expect(identical(CardTheme.lerp(theme, theme, 0.5), theme), true); }); - testWidgets('Material3 - Passing no CardTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Passing no CardTheme returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, @@ -45,7 +46,7 @@ void main() { )); }); - testWidgets('Card uses values from CardTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card uses values from CardTheme', (WidgetTester tester) async { final CardTheme cardTheme = _cardTheme(); await tester.pumpWidget(MaterialApp( @@ -67,7 +68,7 @@ void main() { expect(material.shape, cardTheme.shape); }); - testWidgets('Card widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Card widget properties take priority over theme', (WidgetTester tester) async { const Clip clip = Clip.hardEdge; const Color color = Colors.orange; const Color shadowColor = Colors.pink; @@ -102,7 +103,7 @@ void main() { expect(material.shape, shape); }); - testWidgets('CardTheme properties take priority over ThemeData properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CardTheme properties take priority over ThemeData properties', (WidgetTester tester) async { final CardTheme cardTheme = _cardTheme(); final ThemeData themeData = _themeData().copyWith(cardTheme: cardTheme); @@ -117,7 +118,7 @@ void main() { expect(material.color, cardTheme.color); }); - testWidgets('Material3 - ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( @@ -131,7 +132,7 @@ void main() { expect(material.color, themeData.colorScheme.surface); }); - testWidgets('Material3 - CardTheme customizes shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - CardTheme customizes shape', (WidgetTester tester) async { const CardTheme cardTheme = CardTheme( color: Colors.white, shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(7))), @@ -165,7 +166,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Material2 - ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - ThemeData properties are used when no CardTheme is set', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: false); await tester.pumpWidget(MaterialApp( @@ -179,7 +180,7 @@ void main() { expect(material.color, themeData.cardColor); }); - testWidgets('Material2 - Passing no CardTheme returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Passing no CardTheme returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -201,7 +202,7 @@ void main() { )); }); - testWidgets('Material2 - CardTheme customizes shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - CardTheme customizes shape', (WidgetTester tester) async { const CardTheme cardTheme = CardTheme( color: Colors.white, shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(7))), diff --git a/packages/flutter/test/material/checkbox_list_tile_test.dart b/packages/flutter/test/material/checkbox_list_tile_test.dart index ef5f4971ae739..34d57a4e65bb6 100644 --- a/packages/flutter/test/material/checkbox_list_tile_test.dart +++ b/packages/flutter/test/material/checkbox_list_tile_test.dart @@ -743,7 +743,7 @@ void main() { ); }); - testWidgets('Material2 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -859,7 +859,7 @@ void main() { ); }); - testWidgets('Material3 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - CheckboxListTile respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart index fb9aabe4ebc0c..fe82a294f1ecb 100644 --- a/packages/flutter/test/material/checkbox_test.dart +++ b/packages/flutter/test/material/checkbox_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/src/gestures/constants.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -20,7 +21,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('Checkbox size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox size is configurable by ThemeData.materialTapTargetSize', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: theme.copyWith(materialTapTargetSize: MaterialTapTargetSize.padded), @@ -60,7 +61,7 @@ void main() { expect(tester.getSize(find.byType(Checkbox)), const Size(40.0, 40.0)); }); - testWidgets('Checkbox semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget(Theme( @@ -218,7 +219,7 @@ void main() { handle.dispose(); }); - testWidgets('Can wrap Checkbox with Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can wrap Checkbox with Semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget(Theme( @@ -247,7 +248,7 @@ void main() { handle.dispose(); }); - testWidgets('Checkbox tristate: true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox tristate: true', (WidgetTester tester) async { bool? checkBoxValue; await tester.pumpWidget( @@ -294,7 +295,7 @@ void main() { expect(checkBoxValue, null); }); - testWidgets('has semantics for tristate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantics for tristate', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Theme( @@ -370,7 +371,7 @@ void main() { semantics.dispose(); }); - testWidgets('has semantic events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantic events', (WidgetTester tester) async { dynamic semanticEvent; bool? checkboxValue = false; tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler(SystemChannels.accessibility, (dynamic message) async { @@ -413,7 +414,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('Material2 - Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); Widget buildFrame(bool? checkboxValue) { return Theme( @@ -473,7 +474,7 @@ void main() { expect(getCheckboxRenderer(), paints..line()); // null is rendered as a line (a "dash") }); - testWidgets('Material3 - Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox tristate rendering, programmatic transitions', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); Widget buildFrame(bool? checkboxValue) { return Theme( @@ -533,7 +534,7 @@ void main() { expect(getCheckboxRenderer(), paints..line()); // null is rendered as a line (a "dash") }); - testWidgets('Material2 - Checkbox color rendering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox color rendering', (WidgetTester tester) async { ThemeData theme = ThemeData(useMaterial3: false); const Color borderColor = Color(0xff2196f3); Color checkColor = const Color(0xffFFFFFF); @@ -588,7 +589,7 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: activeColor)); }); - testWidgets('Material3 - Checkbox color rendering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox color rendering', (WidgetTester tester) async { ThemeData theme = ThemeData(useMaterial3: true); const Color borderColor = Color(0xFF6750A4); Color checkColor = const Color(0xffFFFFFF); @@ -641,8 +642,9 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: activeColor)); }); - testWidgets('Material2 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp({bool enabled = true}) { @@ -711,8 +713,9 @@ void main() { ); }); - testWidgets('Material3 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); final ThemeData theme = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; @@ -782,7 +785,7 @@ void main() { ); }); - testWidgets('Checkbox with splash radius set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox with splash radius set', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const double splashRadius = 30; Widget buildApp() { @@ -811,7 +814,7 @@ void main() { ); }); - testWidgets('Checkbox starts the splash in center, even when tap is on the corner', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox starts the splash in center, even when tap is on the corner', (WidgetTester tester) async { Widget buildApp() { return MaterialApp( theme: theme, @@ -843,7 +846,7 @@ void main() { ); }); - testWidgets('Material2 - Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; final ThemeData theme = ThemeData(useMaterial3: false); @@ -900,7 +903,7 @@ void main() { ); }); - testWidgets('Material3 - Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; final ThemeData theme = ThemeData(useMaterial3: true); @@ -957,7 +960,7 @@ void main() { ); }); - testWidgets('Checkbox can be toggled by keyboard shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox can be toggled by keyboard shortcuts', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp({bool enabled = true}) { @@ -998,7 +1001,7 @@ void main() { expect(value, isTrue); }); - testWidgets('Checkbox responds to density changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox responds to density changes.', (WidgetTester tester) async { const Key key = Key('test'); Future buildTest(VisualDensity visualDensity) async { return tester.pumpWidget( @@ -1036,7 +1039,7 @@ void main() { expect(box.size, equals(const Size(60, 36))); }); - testWidgets('Checkbox stops hover animation when removed from the tree.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox stops hover animation when removed from the tree.', (WidgetTester tester) async { const Key checkboxKey = Key('checkbox'); bool? checkboxVal = true; @@ -1090,7 +1093,7 @@ void main() { }); - testWidgets('Checkbox changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox changes mouse cursor when hovered', (WidgetTester tester) async { // Test Checkbox() constructor await tester.pumpWidget( MaterialApp( @@ -1195,7 +1198,7 @@ void main() { }); - testWidgets('Checkbox fill color resolves in enabled/disabled states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox fill color resolves in enabled/disabled states', (WidgetTester tester) async { const Color activeEnabledFillColor = Color(0xFF000001); const Color activeDisabledFillColor = Color(0xFF000002); @@ -1239,8 +1242,10 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: activeDisabledFillColor)); }); - testWidgets('Checkbox fill color resolves in hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox fill color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'checkbox'); + addTearDown(() => focusNode.dispose()); + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredFillColor = Color(0xFF000001); const Color focusedFillColor = Color(0xFF000002); @@ -1295,7 +1300,7 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: hoveredFillColor)); }); - testWidgets('Checkbox respects shape and side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox respects shape and side', (WidgetTester tester) async { const RoundedRectangleBorder roundedRectangleBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))); @@ -1338,8 +1343,9 @@ void main() { ); }); - testWidgets('Material2 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: false); @@ -1405,8 +1411,9 @@ void main() { ); }); - testWidgets('Material3 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: true); @@ -1470,8 +1477,9 @@ void main() { ); }); - testWidgets('Checkbox overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -1606,7 +1614,7 @@ void main() { ); }); - testWidgets('Tristate Checkbox overlay color resolves in pressed active/inactive states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tristate Checkbox overlay color resolves in pressed active/inactive states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); @@ -1713,7 +1721,7 @@ void main() { await gesture.up(); }); - testWidgets('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when widget disappears while pointer is down', (WidgetTester tester) async { Widget buildCheckbox(bool show) { return MaterialApp( theme: theme, @@ -1737,7 +1745,7 @@ void main() { await gesture.up(); }); - testWidgets('Checkbox BorderSide side only applies when unselected in M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox BorderSide side only applies when unselected in M2', (WidgetTester tester) async { const Color borderColor = Color(0xfff44336); const Color activeColor = Color(0xff123456); const BorderSide side = BorderSide( @@ -1801,7 +1809,7 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: activeColor)); // checkbox fill }); - testWidgets('Material2 - Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { const Color borderColor = Color(0xfff44336); const BorderSide side = BorderSide( width: 4, @@ -1855,7 +1863,7 @@ void main() { expectBorder(); }); - testWidgets('Material3 - Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox MaterialStateBorderSide applies unconditionally', (WidgetTester tester) async { const Color borderColor = Color(0xfff44336); const BorderSide side = BorderSide( width: 4, @@ -1909,7 +1917,7 @@ void main() { expectBorder(); }); - testWidgets('disabled checkbox shows tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled checkbox shows tooltip', (WidgetTester tester) async { const String longPressTooltip = 'long press tooltip'; const String tapTooltip = 'tap tooltip'; await tester.pumpWidget( @@ -1963,8 +1971,9 @@ void main() { expect(find.text(tapTooltip), findsOneWidget); }); - testWidgets('Material3 - Checkbox has default error color when isError is set to true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox has default error color when isError is set to true', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); final ThemeData themeData = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; @@ -2035,8 +2044,9 @@ void main() { await tester.pump(); }); - testWidgets('Material3 - Checkbox MaterialStateBorderSide applies in error states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox MaterialStateBorderSide applies in error states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); + addTearDown(() => focusNode.dispose()); final ThemeData themeData = ThemeData(useMaterial3: true); const Color borderColor = Color(0xffffeb3b); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -2114,7 +2124,7 @@ void main() { await tester.pump(); }); - testWidgets('Material3 - Checkbox has correct default shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox has correct default shape', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); Widget buildApp() { @@ -2148,7 +2158,7 @@ void main() { ); }); - testWidgets('Checkbox.adaptive shows the correct platform widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox.adaptive shows the correct platform widget', (WidgetTester tester) async { Widget buildApp(TargetPlatform platform) { return MaterialApp( theme: ThemeData(platform: platform), @@ -2180,7 +2190,7 @@ void main() { } }); - testWidgets('Material2 - Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); const Color activeBackgroundColor = Color(0xff123456); const Color inactiveBackgroundColor = Color(0xff654321); @@ -2233,7 +2243,7 @@ void main() { expect(getCheckboxRenderer(), paints..path(color: inactiveBackgroundColor)); }); - testWidgets('Material3 - Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Checkbox respects fillColor when it is unchecked', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const Color activeBackgroundColor = Color(0xff123456); const Color inactiveBackgroundColor = Color(0xff654321); diff --git a/packages/flutter/test/material/checkbox_theme_test.dart b/packages/flutter/test/material/checkbox_theme_test.dart index 36e23779fac99..32d0e7c16b92b 100644 --- a/packages/flutter/test/material/checkbox_theme_test.dart +++ b/packages/flutter/test/material/checkbox_theme_test.dart @@ -301,7 +301,7 @@ void main() { expect(_getCheckboxMaterial(tester), paints..path(color: selectedFillColor)); }); - testWidgets('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox theme overlay color resolves in active/pressed states', (WidgetTester tester) async { const Color activePressedOverlayColor = Color(0xFF000001); const Color inactivePressedOverlayColor = Color(0xFF000002); diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index 4ff2481973ef7..780f19c2b3ad0 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -137,7 +137,7 @@ void main() { )); }); - testWidgets('debugCheckHasScaffoldMessenger control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasScaffoldMessenger control test', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final GlobalKey scaffoldMessengerKey = GlobalKey(); final SnackBar snackBar = SnackBar( diff --git a/packages/flutter/test/material/divider_test.dart b/packages/flutter/test/material/divider_test.dart index 9249ea6112a39..35cd3118883a4 100644 --- a/packages/flutter/test/material/divider_test.dart +++ b/packages/flutter/test/material/divider_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Material3 - Divider control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Divider control test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -20,7 +21,7 @@ void main() { expect(decoration.border!.bottom.width, 1.0); }); - testWidgets('Material2 - Divider control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Divider control test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -34,7 +35,7 @@ void main() { expect(decoration.border!.bottom.width, 0.0); }); - testWidgets('Divider custom thickness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Divider custom thickness', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -46,7 +47,7 @@ void main() { expect(decoration.border!.bottom.width, 5.0); }); - testWidgets('Horizontal divider custom indentation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal divider custom indentation', (WidgetTester tester) async { const double customIndent = 10.0; Rect dividerRect; Rect lineRect; @@ -91,7 +92,7 @@ void main() { expect(lineRect.right, dividerRect.right - customIndent); }); - testWidgets('Material3 - Vertical Divider Test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Vertical Divider Test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -106,7 +107,7 @@ void main() { expect(border.left.width, 1.0); }); - testWidgets('Material2 - Vertical Divider Test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Vertical Divider Test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -121,7 +122,7 @@ void main() { expect(border.left.width, 0.0); }); - testWidgets('Divider custom thickness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Divider custom thickness', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -134,7 +135,7 @@ void main() { expect(border.left.width, 5.0); }); - testWidgets('Vertical Divider Test 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical Divider Test 2', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -159,7 +160,7 @@ void main() { expect(find.byType(VerticalDivider), paints..path(strokeWidth: 0.0)); }); - testWidgets('Vertical divider custom indentation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical divider custom indentation', (WidgetTester tester) async { const double customIndent = 10.0; Rect dividerRect; Rect lineRect; @@ -205,7 +206,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/39533 - testWidgets('createBorderSide does not throw exception with null context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('createBorderSide does not throw exception with null context', (WidgetTester tester) async { // Passing a null context used to throw an exception but no longer does. expect(() => Divider.createBorderSide(null), isNot(throwsAssertionError)); expect(() => Divider.createBorderSide(null), isNot(throwsNoSuchMethodError)); diff --git a/packages/flutter/test/material/divider_theme_test.dart b/packages/flutter/test/material/divider_theme_test.dart index 6928a792d49a6..6611d6bc750da 100644 --- a/packages/flutter/test/material/divider_theme_test.dart +++ b/packages/flutter/test/material/divider_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('DividerThemeData copyWith, ==, hashCode basics', () { @@ -21,7 +22,7 @@ void main() { expect(dividerTheme.endIndent, null); }); - testWidgets('Default DividerThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default DividerThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DividerThemeData().debugFillProperties(builder); @@ -33,7 +34,7 @@ void main() { expect(description, []); }); - testWidgets('DividerThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DividerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DividerThemeData( color: Color(0xFFFFFFFF), @@ -58,7 +59,7 @@ void main() { }); group('Material3 - Horizontal Divider', () { - testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, @@ -82,7 +83,7 @@ void main() { expect(lineRect.right, dividerRect.right); }); - testWidgets('Uses values from DividerThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses values from DividerThemeData', (WidgetTester tester) async { final DividerThemeData dividerTheme = _dividerTheme(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true, dividerTheme: dividerTheme), @@ -105,7 +106,7 @@ void main() { expect(lineRect.right, dividerRect.right - dividerTheme.endIndent!); }); - testWidgets('DividerTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DividerTheme overrides defaults', (WidgetTester tester) async { final DividerThemeData dividerTheme = _dividerTheme(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), @@ -123,7 +124,7 @@ void main() { expect(decoration.border!.bottom.color, dividerTheme.color); }); - testWidgets('Widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget properties take priority over theme', (WidgetTester tester) async { const Color color = Colors.purple; const double height = 10.0; const double thickness = 5.0; @@ -160,7 +161,7 @@ void main() { }); group('Material3 - Vertical Divider', () { - testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( theme: theme, @@ -185,7 +186,7 @@ void main() { expect(lineRect.bottom, dividerRect.bottom); }); - testWidgets('Uses values from DividerThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses values from DividerThemeData', (WidgetTester tester) async { final DividerThemeData dividerTheme = _dividerTheme(); await tester.pumpWidget(MaterialApp( theme: ThemeData(dividerTheme: dividerTheme), @@ -209,7 +210,7 @@ void main() { expect(lineRect.bottom, dividerRect.bottom - dividerTheme.endIndent!); }); - testWidgets('DividerTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DividerTheme overrides defaults', (WidgetTester tester) async { final DividerThemeData dividerTheme = _dividerTheme(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), @@ -228,7 +229,7 @@ void main() { expect(border.left.color, dividerTheme.color); }); - testWidgets('Widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget properties take priority over theme', (WidgetTester tester) async { const Color color = Colors.purple; const double width = 10.0; const double thickness = 5.0; @@ -271,7 +272,7 @@ void main() { // can be deleted. group('Material2 - Horizontal Divider', () { - testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -295,7 +296,7 @@ void main() { expect(lineRect.right, dividerRect.right); }); - testWidgets('DividerTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DividerTheme overrides defaults', (WidgetTester tester) async { final DividerThemeData theme = _dividerTheme(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -314,7 +315,7 @@ void main() { }); group('Material2 - Vertical Divider', () { - testWidgets('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passing no DividerThemeData returns defaults', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( From 16b9e77070ae05af15665af04c1ee4b0f53a8310 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 1 Sep 2023 12:14:59 -0400 Subject: [PATCH 1051/1547] Roll Flutter Engine from 4c085b883d6f to ddd03f863897 (1 revision) (#133868) https://github.com/flutter/engine/compare/4c085b883d6f...ddd03f863897 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 4eb9b17d8e84 to d6266ef14a7e (1 revision) (flutter/engine#45376) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b8c39e63b76a7..99f2ea3ca18c2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4c085b883d6fc21c6e5a6348796db7477e317715 +ddd03f86389785e10fb504e67f16c1a0019d5f09 From 37c55bab2cea2bc84532bbee73dadc75c585d5c5 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:20:46 -0500 Subject: [PATCH 1052/1547] Run Mac_arm64_ios run_debug_test_macos in presubmit (#133869) Reland https://github.com/flutter/flutter/pull/133788. Fixes https://github.com/flutter/flutter/issues/118830. Fixes https://github.com/flutter/flutter/issues/125342. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 5bb50095d5747..9924b985915c3 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4317,7 +4317,6 @@ targets: - name: Mac_arm64_ios run_debug_test_macos recipe: devicelab/devicelab_drone - presubmit: false # https://github.com/flutter/flutter/issues/118827 timeout: 60 properties: tags: > From 033274c66a0d704af22e589eaa7401c2fa92d208 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:48:20 -0400 Subject: [PATCH 1053/1547] Change android_virtual_device to version 34 (#133809) Change from AVD 33 to [AVD 34](https://chrome-infra-packages.appspot.com/p/chromium/tools/android/avd/linux-amd64) in CI. Only affects two tests. We should also update the firebase virtual and physical devices when 34 is available there (for example [here](https://github.com/flutter/flutter/blob/e98d3929ca421ca11dcc7662f59e73e0a7d293bd/.ci.yaml#L441)), as that will allow us to update a lot more tests. --- .ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 9924b985915c3..9860dc459187b 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -266,7 +266,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "android_virtual_device", "version": "33"}, + {"dependency": "android_virtual_device", "version": "34"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -1574,7 +1574,7 @@ targets: task_name: android_defines_test dependencies: >- [ - {"dependency": "android_virtual_device", "version": "33"} + {"dependency": "android_virtual_device", "version": "34"} ] - name: Linux_android android_obfuscate_test From 8cbf42a7d9f5f8e511471589ee44d7f11fabe636 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 1 Sep 2023 13:35:13 -0400 Subject: [PATCH 1054/1547] Roll Flutter Engine from ddd03f863897 to d00b69a438a6 (2 revisions) (#133873) https://github.com/flutter/engine/compare/ddd03f863897...d00b69a438a6 2023-09-01 skia-flutter-autoroll@skia.org Roll ICU from de4ce0071eb4 to 985b9a6f70e1 (2 revisions) (flutter/engine#45382) 2023-09-01 brianosman@google.com Migrate Fuchsia VK calls of GrBackend* (flutter/engine#45380) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 99f2ea3ca18c2..41819c8ea6d73 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ddd03f86389785e10fb504e67f16c1a0019d5f09 +d00b69a438a672c995aa173084059d0595e4ea06 From 959cdb79fbd7f20f45ed51966d1b9a5de3b1113e Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Fri, 1 Sep 2023 13:31:16 -0700 Subject: [PATCH 1055/1547] Remove deprecated TestWindow.textScaleFactorTestValue/TestWindow.clearTextScaleFactorTestValue (#133176) Part of: https://github.com/flutter/flutter/issues/133171 --- packages/flutter_test/lib/src/window.dart | 20 +------------------- packages/flutter_test/test/window_test.dart | 4 ++-- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index c01dca0391c52..e73accd6fe187 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -1158,7 +1158,7 @@ class _UnsupportedDisplay implements TestDisplay { /// // Fake the desired properties of the TestWindow. All code running /// // within this test will perceive the following fake text scale /// // factor as the real text scale factor of the window. -/// testBinding.window.textScaleFactorTestValue = 2.5; // ignore: deprecated_member_use +/// testBinding.platformDispatcher.textScaleFactorTestValue = 2.5; /// /// // Test code that depends on text scale factor here. /// }); @@ -1533,24 +1533,6 @@ class TestWindow implements SingletonFlutterWindow { ) @override double get textScaleFactor => platformDispatcher.textScaleFactor; - /// Hides the real text scale factor and reports the given - /// [textScaleFactorTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.textScaleFactorTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set textScaleFactorTestValue(double textScaleFactorTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.textScaleFactorTestValue = textScaleFactorTestValue; - } - /// Deletes any existing test text scale factor and returns to using the real - /// text scale factor. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearTextScaleFactorTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearTextScaleFactorTestValue() { - platformDispatcher.clearTextScaleFactorTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.platformBrightness instead. ' diff --git a/packages/flutter_test/test/window_test.dart b/packages/flutter_test/test/window_test.dart index 3bcafbbf7c2b9..0483bea7e536c 100644 --- a/packages/flutter_test/test/window_test.dart +++ b/packages/flutter_test/test/window_test.dart @@ -92,7 +92,7 @@ void main() { return WidgetsBinding.instance.window.textScaleFactor; }, propertyFaker: (TestWidgetsFlutterBinding binding, double fakeValue) { - binding.window.textScaleFactorTestValue = fakeValue; + binding.platformDispatcher.textScaleFactorTestValue = fakeValue; }, ); }); @@ -118,7 +118,7 @@ void main() { // Set fake values for window properties. testWindow.devicePixelRatioTestValue = 2.5; - testWindow.textScaleFactorTestValue = 3.0; + tester.platformDispatcher.textScaleFactorTestValue = 3.0; // Erase fake window property values. testWindow.clearAllTestValues(); From a66eae17a257ce392fed44011bc9a36033f5351c Mon Sep 17 00:00:00 2001 From: Andrew Kolos Date: Fri, 1 Sep 2023 13:32:50 -0700 Subject: [PATCH 1056/1547] fix install checks in flavors devicelab tests (#133719) Fixes #133713 --- dev/devicelab/bin/tasks/flavors_test.dart | 54 ++++++++++--------- dev/devicelab/bin/tasks/flavors_test_ios.dart | 51 ++++++++++-------- .../bin/tasks/flavors_test_macos.dart | 41 +++++++------- 3 files changed, 81 insertions(+), 65 deletions(-) diff --git a/dev/devicelab/bin/tasks/flavors_test.dart b/dev/devicelab/bin/tasks/flavors_test.dart index 055f58aa29f7f..aab245b8894e0 100644 --- a/dev/devicelab/bin/tasks/flavors_test.dart +++ b/dev/devicelab/bin/tasks/flavors_test.dart @@ -13,31 +13,37 @@ Future main() async { await task(() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); - // test install and uninstall of flavors app - await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { - await flutter( - 'install', - options: ['--debug', '--flavor', 'paid'], - ); - await flutter( - 'install', - options: ['--debug', '--flavor', 'paid', '--uninstall-only'], - ); - final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: ['--flavor', 'bogus'], - ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('The Xcode project defines schemes: free, paid')) { - print(stderrString); - return TaskResult.failure('Should not succeed with bogus flavor'); - } - }); + final TaskResult installTestsResult = await inDirectory( + '${flutterDirectory.path}/dev/integration_tests/flavors', + () async { + await flutter( + 'install', + options: ['--debug', '--flavor', 'paid'], + ); + await flutter( + 'install', + options: ['--debug', '--flavor', 'paid', '--uninstall-only'], + ); - return TaskResult.success(null); + final StringBuffer stderr = StringBuffer(); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: ['--flavor', 'bogus'], + ); + + final String stderrString = stderr.toString(); + if (!stderrString.contains('"build/app/outputs/flutter-apk/app-bogus-release.apk" does not exist.')) { + print(stderrString); + return TaskResult.failure('Should not succeed with bogus flavor'); + } + + return TaskResult.success(null); + }, + ); + + return installTestsResult; }); } diff --git a/dev/devicelab/bin/tasks/flavors_test_ios.dart b/dev/devicelab/bin/tasks/flavors_test_ios.dart index 2fbfcb9e0a4af..4e84ed4ec3566 100644 --- a/dev/devicelab/bin/tasks/flavors_test_ios.dart +++ b/dev/devicelab/bin/tasks/flavors_test_ios.dart @@ -14,30 +14,35 @@ Future main() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); // test install and uninstall of flavors app - await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { - await flutter( - 'install', - options: ['--flavor', 'paid'], - ); - await flutter( - 'install', - options: ['--flavor', 'paid', '--uninstall-only'], - ); - final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: ['--flavor', 'bogus'], - ); + final TaskResult installTestsResult = await inDirectory( + '${flutterDirectory.path}/dev/integration_tests/flavors', + () async { + await flutter( + 'install', + options: ['--flavor', 'paid'], + ); + await flutter( + 'install', + options: ['--flavor', 'paid', '--uninstall-only'], + ); + final StringBuffer stderr = StringBuffer(); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: ['--flavor', 'bogus'], + ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('install failed, bogus flavor not found')) { - print(stderrString); - return TaskResult.failure('Should not succeed with bogus flavor'); - } - }); + final String stderrString = stderr.toString(); + if (!stderrString.contains('The Xcode project defines schemes: free, paid')) { + print(stderrString); + return TaskResult.failure('Should not succeed with bogus flavor'); + } - return TaskResult.success(null); + return TaskResult.success(null); + }, + ); + + return installTestsResult; }); } diff --git a/dev/devicelab/bin/tasks/flavors_test_macos.dart b/dev/devicelab/bin/tasks/flavors_test_macos.dart index 346bc31a19c98..e3bb56123bc4a 100644 --- a/dev/devicelab/bin/tasks/flavors_test_macos.dart +++ b/dev/devicelab/bin/tasks/flavors_test_macos.dart @@ -14,26 +14,31 @@ Future main() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); - await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { - final StringBuffer stderr = StringBuffer(); + final TaskResult installTestsResult = await inDirectory( + '${flutterDirectory.path}/dev/integration_tests/flavors', + () async { + final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: [ - '--d', 'macos', - '--flavor', 'free' - ], - ); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: [ + '--d', 'macos', + '--flavor', 'free' + ], + ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('Host and target are the same. Nothing to install.')) { - print(stderrString); - return TaskResult.failure('Installing a macOS app on macOS should no-op'); - } - }); + final String stderrString = stderr.toString(); + if (!stderrString.contains('Host and target are the same. Nothing to install.')) { + print(stderrString); + return TaskResult.failure('Installing a macOS app on macOS should no-op'); + } - return TaskResult.success(null); + return TaskResult.success(null); + }, + ); + + return installTestsResult; }); } From b1f691c9fc93f8a28c2c7edfd7b9fb3bdb98f851 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Fri, 1 Sep 2023 13:35:58 -0700 Subject: [PATCH 1057/1547] Remove deprecated TestWindow.platformBrightnessTestValue/TestWindow.clearPlatformBrightnessTestValue (#133178) Part of: https://github.com/flutter/flutter/issues/133171 --- packages/flutter_test/lib/src/window.dart | 18 ------------------ packages/flutter_test/test/window_test.dart | 2 +- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/packages/flutter_test/lib/src/window.dart b/packages/flutter_test/lib/src/window.dart index e73accd6fe187..c292b796e2e22 100644 --- a/packages/flutter_test/lib/src/window.dart +++ b/packages/flutter_test/lib/src/window.dart @@ -1557,24 +1557,6 @@ class TestWindow implements SingletonFlutterWindow { set onPlatformBrightnessChanged(VoidCallback? callback) { platformDispatcher.onPlatformBrightnessChanged = callback; } - /// Hides the real text scale factor and reports the given - /// [platformBrightnessTestValue] instead. - @Deprecated( - 'Use WidgetTester.platformDispatcher.platformBrightnessTestValue instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - set platformBrightnessTestValue(Brightness platformBrightnessTestValue) { // ignore: avoid_setters_without_getters - platformDispatcher.platformBrightnessTestValue = platformBrightnessTestValue; - } - /// Deletes any existing test platform brightness and returns to using the - /// real platform brightness. - @Deprecated( - 'Use WidgetTester.platformDispatcher.clearPlatformBrightnessTestValue() instead. ' - 'This feature was deprecated after v2.11.0-0.0.pre.' - ) - void clearPlatformBrightnessTestValue() { - platformDispatcher.clearPlatformBrightnessTestValue(); - } @Deprecated( 'Use WidgetTester.platformDispatcher.alwaysUse24HourFormat instead. ' diff --git a/packages/flutter_test/test/window_test.dart b/packages/flutter_test/test/window_test.dart index 0483bea7e536c..8ece4798eb405 100644 --- a/packages/flutter_test/test/window_test.dart +++ b/packages/flutter_test/test/window_test.dart @@ -106,7 +106,7 @@ void main() { return WidgetsBinding.instance.window.platformBrightness; }, propertyFaker: (TestWidgetsFlutterBinding binding, Brightness fakeValue) { - binding.window.platformBrightnessTestValue = fakeValue; + binding.platformDispatcher.platformBrightnessTestValue = fakeValue; }, ); }); From 5649161bd7fc591e313c12f35fccfe4c8e211dbe Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Fri, 1 Sep 2023 17:17:48 -0500 Subject: [PATCH 1058/1547] Revert "fix install checks in flavors devicelab tests" (#133894) Reverts flutter/flutter#133719 `Windows_android flavors_test_win` failed twice in a row in the tree --- dev/devicelab/bin/tasks/flavors_test.dart | 54 +++++++++---------- dev/devicelab/bin/tasks/flavors_test_ios.dart | 51 ++++++++---------- .../bin/tasks/flavors_test_macos.dart | 41 +++++++------- 3 files changed, 65 insertions(+), 81 deletions(-) diff --git a/dev/devicelab/bin/tasks/flavors_test.dart b/dev/devicelab/bin/tasks/flavors_test.dart index aab245b8894e0..055f58aa29f7f 100644 --- a/dev/devicelab/bin/tasks/flavors_test.dart +++ b/dev/devicelab/bin/tasks/flavors_test.dart @@ -13,37 +13,31 @@ Future main() async { await task(() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); + // test install and uninstall of flavors app + await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { + await flutter( + 'install', + options: ['--debug', '--flavor', 'paid'], + ); + await flutter( + 'install', + options: ['--debug', '--flavor', 'paid', '--uninstall-only'], + ); + final StringBuffer stderr = StringBuffer(); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: ['--flavor', 'bogus'], + ); - final TaskResult installTestsResult = await inDirectory( - '${flutterDirectory.path}/dev/integration_tests/flavors', - () async { - await flutter( - 'install', - options: ['--debug', '--flavor', 'paid'], - ); - await flutter( - 'install', - options: ['--debug', '--flavor', 'paid', '--uninstall-only'], - ); + final String stderrString = stderr.toString(); + if (!stderrString.contains('The Xcode project defines schemes: free, paid')) { + print(stderrString); + return TaskResult.failure('Should not succeed with bogus flavor'); + } + }); - final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: ['--flavor', 'bogus'], - ); - - final String stderrString = stderr.toString(); - if (!stderrString.contains('"build/app/outputs/flutter-apk/app-bogus-release.apk" does not exist.')) { - print(stderrString); - return TaskResult.failure('Should not succeed with bogus flavor'); - } - - return TaskResult.success(null); - }, - ); - - return installTestsResult; + return TaskResult.success(null); }); } diff --git a/dev/devicelab/bin/tasks/flavors_test_ios.dart b/dev/devicelab/bin/tasks/flavors_test_ios.dart index 4e84ed4ec3566..2fbfcb9e0a4af 100644 --- a/dev/devicelab/bin/tasks/flavors_test_ios.dart +++ b/dev/devicelab/bin/tasks/flavors_test_ios.dart @@ -14,35 +14,30 @@ Future main() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); // test install and uninstall of flavors app - final TaskResult installTestsResult = await inDirectory( - '${flutterDirectory.path}/dev/integration_tests/flavors', - () async { - await flutter( - 'install', - options: ['--flavor', 'paid'], - ); - await flutter( - 'install', - options: ['--flavor', 'paid', '--uninstall-only'], - ); - final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: ['--flavor', 'bogus'], - ); + await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { + await flutter( + 'install', + options: ['--flavor', 'paid'], + ); + await flutter( + 'install', + options: ['--flavor', 'paid', '--uninstall-only'], + ); + final StringBuffer stderr = StringBuffer(); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: ['--flavor', 'bogus'], + ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('The Xcode project defines schemes: free, paid')) { - print(stderrString); - return TaskResult.failure('Should not succeed with bogus flavor'); - } + final String stderrString = stderr.toString(); + if (!stderrString.contains('install failed, bogus flavor not found')) { + print(stderrString); + return TaskResult.failure('Should not succeed with bogus flavor'); + } + }); - return TaskResult.success(null); - }, - ); - - return installTestsResult; + return TaskResult.success(null); }); } diff --git a/dev/devicelab/bin/tasks/flavors_test_macos.dart b/dev/devicelab/bin/tasks/flavors_test_macos.dart index e3bb56123bc4a..346bc31a19c98 100644 --- a/dev/devicelab/bin/tasks/flavors_test_macos.dart +++ b/dev/devicelab/bin/tasks/flavors_test_macos.dart @@ -14,31 +14,26 @@ Future main() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); - final TaskResult installTestsResult = await inDirectory( - '${flutterDirectory.path}/dev/integration_tests/flavors', - () async { - final StringBuffer stderr = StringBuffer(); + await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { + final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: [ - '--d', 'macos', - '--flavor', 'free' - ], - ); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: [ + '--d', 'macos', + '--flavor', 'free' + ], + ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('Host and target are the same. Nothing to install.')) { - print(stderrString); - return TaskResult.failure('Installing a macOS app on macOS should no-op'); - } + final String stderrString = stderr.toString(); + if (!stderrString.contains('Host and target are the same. Nothing to install.')) { + print(stderrString); + return TaskResult.failure('Installing a macOS app on macOS should no-op'); + } + }); - return TaskResult.success(null); - }, - ); - - return installTestsResult; + return TaskResult.success(null); }); } From df8ee8d63a6e1d3c0a046ea1f3c11058fefd4b21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Fri, 1 Sep 2023 16:55:36 -0700 Subject: [PATCH 1059/1547] [Windows Arm64] Add first device lab test (#133895) Adds the first Windows Arm64 devicelab test. The builder for this test won't be created until after this lands on master, so we can't actually test this until this is merged. --- .ci.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 9860dc459187b..67977d1b39884 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -197,6 +197,15 @@ platform_properties: ] os: Windows-10 device_type: none + windows_arm64: + properties: + dependencies: >- + [ + {"dependency": "certs", "version": "version:9563bb"} + ] + os: Windows-10 + device_type: none + cpu: arm64 windows_android: properties: dependencies: >- @@ -4985,6 +4994,20 @@ targets: ] task_name: hello_world_win_desktop__compile + - name: Windows_arm64 hello_world_win_desktop__compile + recipe: devicelab/devicelab_drone + bringup: true + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + task_name: hello_world_win_desktop__compile + - name: Windows flutter_gallery_win_desktop__compile recipe: devicelab/devicelab_drone presubmit: false From 80f737d1e0ca37320a46c74a67d21161e8241831 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 1 Sep 2023 17:10:41 -0700 Subject: [PATCH 1060/1547] Mark leak in _DayPickerState. (#133863) --- packages/flutter/test/material/date_picker_test.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 66cddc20c9138..d58fa42ced2b5 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -172,11 +173,16 @@ void main() { }, useMaterial3: theme.useMaterial3); }); - testWidgets('Material3 uses sentence case labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 uses sentence case labels', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.text('Select date'), findsOneWidget); }, useMaterial3: true); - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/133862 + allowAllNotDisposed: true, + )); testWidgets('Cancel, confirm, and help text is used', (WidgetTester tester) async { cancelText = 'nope'; From a3362a9ff8e30c5b4c8ffb6fb5c6ecb0ec238970 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 1 Sep 2023 17:29:47 -0700 Subject: [PATCH 1061/1547] MaterialStatesController should dispatch creation in constructor. (#133826) This PR also updates other tests to use matcher. --- .../material_states_controller_test.dart | 5 +++ .../test/widgets/focus_manager_test.dart | 32 ++----------------- .../flutter/test/widgets/router_test.dart | 18 ++++------- .../test/widgets/scroll_controller_test.dart | 17 ++-------- .../flutter/test/widgets/shortcuts_test.dart | 23 ++----------- 5 files changed, 20 insertions(+), 75 deletions(-) diff --git a/packages/flutter/test/material/material_states_controller_test.dart b/packages/flutter/test/material/material_states_controller_test.dart index 3449e975b6029..f797d34e34bb1 100644 --- a/packages/flutter/test/material/material_states_controller_test.dart +++ b/packages/flutter/test/material/material_states_controller_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('MaterialStatesController constructor', () { @@ -12,6 +13,10 @@ void main() { expect(MaterialStatesController({MaterialState.selected}).value, {MaterialState.selected}); }); + test('MaterialStatesController dispatches memory events', () { + expect(()=> MaterialStatesController().dispose(), dispatchesMemoryEvents(MaterialStatesController)); + }); + test('MaterialStatesController update, listener', () { int count = 0; void valueChanged() { diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 4516e6f31ce44..600fdb16dd235 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { final GlobalKey widgetKey = GlobalKey(); @@ -1610,38 +1611,11 @@ void main() { }); test('$FocusManager dispatches object creation in constructor', () { - final List events = []; - void listener(ObjectEvent event) { - if (event.object.runtimeType == FocusManager) { - events.add(event); - } - } - MemoryAllocations.instance.addListener(listener); - - final FocusManager focusManager = FocusManager(); - - expect(events, hasLength(1)); - - focusManager.dispose(); - - MemoryAllocations.instance.removeListener(listener); + expect(()=> FocusManager().dispose(), dispatchesMemoryEvents(FocusManager)); }); test('$FocusNode dispatches object creation in constructor', () { - final List events = []; - void listener(ObjectEvent event) { - if (event.object.runtimeType == FocusNode) { - events.add(event); - } - } - MemoryAllocations.instance.addListener(listener); - - final FocusNode focusManager = FocusNode(); - - expect(events, hasLength(1)); - - focusManager.dispose(); - MemoryAllocations.instance.removeListener(listener); + expect(()=> FocusNode().dispose(), dispatchesMemoryEvents(FocusNode)); }); testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index f4286d4586d12..fdb3407467c52 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgets('Simple router basic functionality - synchronized', (WidgetTester tester) async { @@ -1584,18 +1585,13 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester }); test('$PlatformRouteInformationProvider dispatches object creation in constructor', () { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; - MemoryAllocations.instance.addListener(listener); - - final PlatformRouteInformationProvider registry = PlatformRouteInformationProvider( - initialRouteInformation: RouteInformation(uri: Uri.parse('http://google.com')), - ); - - expect(eventCount, 1); + void createAndDispose() { + PlatformRouteInformationProvider( + initialRouteInformation: RouteInformation(uri: Uri.parse('http://google.com')), + ).dispose(); + } - registry.dispose(); - MemoryAllocations.instance.removeListener(listener); + expect(createAndDispose, dispatchesMemoryEvents(PlatformRouteInformationProvider)); }); } diff --git a/packages/flutter/test/widgets/scroll_controller_test.dart b/packages/flutter/test/widgets/scroll_controller_test.dart index b4bad240f93f3..76a9820470c26 100644 --- a/packages/flutter/test/widgets/scroll_controller_test.dart +++ b/packages/flutter/test/widgets/scroll_controller_test.dart @@ -4,9 +4,9 @@ import 'dart:ui' as ui; -import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'states.dart'; @@ -396,19 +396,6 @@ void main() { }); test('$ScrollController dispatches object creation in constructor', () { - final List events = []; - void listener(ObjectEvent event) { - if (event.object.runtimeType == ScrollController) { - events.add(event); - } - } - MemoryAllocations.instance.addListener(listener); - - final ScrollController controller = ScrollController(); - - expect(events, hasLength(1)); - - controller.dispose(); - MemoryAllocations.instance.removeListener(listener); + expect(()=> ScrollController().dispose(), dispatchesMemoryEvents(ScrollController)); }); } diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index fedf7f9cd291f..a73bb38e803fe 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group(LogicalKeySet, () { @@ -667,16 +668,7 @@ void main() { }); test('$ShortcutManager dispatches object creation in constructor', () { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; - MemoryAllocations.instance.addListener(listener); - - final ShortcutManager registry = ShortcutManager(); - - expect(eventCount, 1); - - registry.dispose(); - MemoryAllocations.instance.removeListener(listener); + expect(()=> ShortcutManager().dispose(), dispatchesMemoryEvents(ShortcutManager)); }); testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { @@ -1867,16 +1859,7 @@ void main() { }); test('dispatches object creation in constructor', () { - int eventCount = 0; - void listener(ObjectEvent event) => eventCount++; - MemoryAllocations.instance.addListener(listener); - - final ShortcutRegistry registry = ShortcutRegistry(); - - expect(eventCount, 1); - - registry.dispose(); - MemoryAllocations.instance.removeListener(listener); + expect(()=> ShortcutRegistry().dispose(), dispatchesMemoryEvents(ShortcutRegistry)); }); }); } From 248645a2b2c9baac4603626d34193a5d0d712c51 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 1 Sep 2023 17:59:25 -0700 Subject: [PATCH 1062/1547] RestorableProperty should dispatch creation in constructor. (#133883) --- packages/flutter/lib/src/widgets/restoration.dart | 7 +++++++ packages/flutter/test/material/time_test.dart | 4 +++- .../flutter/test/widgets/restorable_property_test.dart | 5 +++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/restoration.dart b/packages/flutter/lib/src/widgets/restoration.dart index 101e6422daeff..367d90e47e80b 100644 --- a/packages/flutter/lib/src/widgets/restoration.dart +++ b/packages/flutter/lib/src/widgets/restoration.dart @@ -454,6 +454,13 @@ class _RootRestorationScopeState extends State { /// * [RestorationManager], which describes how state restoration works in /// Flutter. abstract class RestorableProperty extends ChangeNotifier { + /// Creates a [RestorableProperty]. + RestorableProperty(){ + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } + } + /// Called by the [RestorationMixin] if no restoration data is available to /// restore the value of the property from to obtain the default value for the /// property. diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index 6c71fef4565f5..2c9926ac17cd3 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -58,7 +58,9 @@ void main() { group('RestorableTimeOfDay tests', () { testWidgetsWithLeakTracking('value is not accessible when not registered', (WidgetTester tester) async { - expect(() => RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)).value, throwsAssertionError); + final RestorableTimeOfDay property = RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)); + addTearDown(() => property.dispose()); + expect(() => property.value, throwsAssertionError); }); testWidgets('work when not in restoration scope', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/restorable_property_test.dart b/packages/flutter/test/widgets/restorable_property_test.dart index ef33e0f5ebff0..bb985cd130806 100644 --- a/packages/flutter/test/widgets/restorable_property_test.dart +++ b/packages/flutter/test/widgets/restorable_property_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgets('value is not accessible when not registered', (WidgetTester tester) async { @@ -25,6 +26,10 @@ void main() { expect(() => _TestRestorableValue().value, throwsAssertionError); }); + testWidgetsWithLeakTracking('$RestorableProperty dispatches creation in constructor', (WidgetTester widgetTester) async { + expect(()=> RestorableDateTimeN(null).dispose(), dispatchesMemoryEvents(RestorableDateTimeN)); + }); + testWidgets('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); From 685ce14b2d0f4046bd596842208d0c17f9a21e57 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 2 Sep 2023 09:38:32 -0400 Subject: [PATCH 1063/1547] Roll Flutter Engine from d00b69a438a6 to 489c399e3dc6 (3 revisions) (#133879) https://github.com/flutter/engine/compare/d00b69a438a6...489c399e3dc6 2023-09-01 matanlurey@users.noreply.github.com Update (flipping the default from false -> true) and deprecate Paint.enableDithering. (flutter/engine#44705) 2023-09-01 jonahwilliams@google.com [Impeller] EntityPass::Clone needs to clone harder (flutter/engine#45313) 2023-09-01 ychris@google.com Reland "ios: remove shared_application and support app extension build #44732" (flutter/engine#45351) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 41819c8ea6d73..3285c148e918e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d00b69a438a672c995aa173084059d0595e4ea06 +489c399e3dc672ffd25ce2d49caafbe068790a0f From 3896912d447986ee535081bc331bc43150105cbc Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Sat, 2 Sep 2023 12:47:28 -0700 Subject: [PATCH 1064/1547] Fix for new analyzer lint (#133923) For https://github.com/flutter/flutter/issues/133922 --- packages/flutter/lib/src/widgets/framework.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 4443a141333d1..34421ae2e5efe 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -3110,7 +3110,7 @@ class BuildOwner { assert(_globalKeyRegistry.containsKey(key)); duplicates ??= >{}; // Uses ordered set to produce consistent error message. - final Set elements = duplicates.putIfAbsent(key, () => LinkedHashSet()); + final Set elements = duplicates.putIfAbsent(key, () => {}); elements.add(element); elements.add(_globalKeyRegistry[key]!); } From da51c6c7183937b6d8f4f013f85eac047d414a6d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 2 Sep 2023 16:40:36 -0400 Subject: [PATCH 1065/1547] Manual roll Flutter Engine from 489c399e3dc6 to e496eec40e21 (26 revisions) (#133924) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/489c399e3dc6...e496eec40e21 2023-09-02 skia-flutter-autoroll@skia.org Roll Skia from 2d8849f9f0cc to 15f77147a3ec (1 revision) (flutter/engine#45414) 2023-09-02 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from OF4TS05qlWCjukWw6... to MesZPNdj-uw8VdCyV... (flutter/engine#45413) 2023-09-02 dkwingsmt@users.noreply.github.com Remove --disable-service-auth-codes (flutter/engine#45356) 2023-09-02 bdero@google.com [Impeller] Import cstring for memcpy. (flutter/engine#45408) 2023-09-02 skia-flutter-autoroll@skia.org Roll Dart SDK from cdf1ce0c6d7e to a5c7102af509 (1 revision) (flutter/engine#45412) 2023-09-02 skia-flutter-autoroll@skia.org Roll ANGLE from 179bd7762ffa to ebf1e7163216 (1 revision) (flutter/engine#45411) 2023-09-02 dkwingsmt@users.noreply.github.com Remove deprecated MOCK_METHODx calls (flutter/engine#45307) 2023-09-02 jonahwilliams@google.com [Impeller] Better demonstrate blur and draw picture? (flutter/engine#45388) 2023-09-02 jonahwilliams@google.com [Impeller] Make paths externally immutable, update all tests to use PathBuilder to create Path. (flutter/engine#45393) 2023-09-02 skia-flutter-autoroll@skia.org Roll ANGLE from 962fdf7b7882 to 179bd7762ffa (1 revision) (flutter/engine#45409) 2023-09-02 flar@google.com Cull the RTree bounds when they are forwarded in DrawDisplayList (flutter/engine#45358) 2023-09-02 skia-flutter-autoroll@skia.org Roll Skia from fedff79a6afc to 2d8849f9f0cc (3 revisions) (flutter/engine#45407) 2023-09-02 jonahwilliams@google.com [impeller] premultiply vertices colors. (flutter/engine#45406) 2023-09-01 skia-flutter-autoroll@skia.org Roll ANGLE from 6a09e41ce6ea to 962fdf7b7882 (224 revisions) (flutter/engine#45400) 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 22ae23891e8e to fedff79a6afc (1 revision) (flutter/engine#45405) 2023-09-01 30870216+gaaclarke@users.noreply.github.com [Impeller] turned on validations for all debug builds (flutter/engine#45350) 2023-09-01 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from sk7JBGzW1Jw10Wy-T... to OF4TS05qlWCjukWw6... (flutter/engine#45403) 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 2c0405489966 to 22ae23891e8e (1 revision) (flutter/engine#45402) 2023-09-01 737941+loic-sharma@users.noreply.github.com [Windows] Update vsync on raster thread (flutter/engine#45310) 2023-09-01 skia-flutter-autoroll@skia.org Roll Dart SDK from a2ea759c16cc to cdf1ce0c6d7e (1 revision) (flutter/engine#45397) 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from f3f6c733c7e6 to 2c0405489966 (1 revision) (flutter/engine#45396) 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from 02fa14799c6c to f3f6c733c7e6 (1 revision) (flutter/engine#45394) 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from d5d3b0d4ee77 to 02fa14799c6c (2 revisions) (flutter/engine#45392) 2023-09-01 41930132+hellohuanlin@users.noreply.github.com [ios][ios17][text_input]fix text input system highlight in iOS 17 Beta 7 with firstRectForRange (flutter/engine#45303) 2023-09-01 skia-flutter-autoroll@skia.org Roll Skia from d6266ef14a7e to d5d3b0d4ee77 (2 revisions) (flutter/engine#45389) 2023-09-01 skia-flutter-autoroll@skia.org Roll Dart SDK from 0c121a6431cc to a2ea759c16cc (1 revision) (flutter/engine#45384) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from sk7JBGzW1Jw1 to MesZPNdj-uw8 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3285c148e918e..f27116e3d4c97 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -489c399e3dc672ffd25ce2d49caafbe068790a0f +e496eec40e21a91daccacece75b7f8c9731fdd62 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 661d8063ee75b..bc71cf0d49a3f 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -sk7JBGzW1Jw10Wy-TPCTa9rp1SvNoaleR0wHIpz7HBEC +MesZPNdj-uw8VdCyVaharrEIFcHKtnvGxELJWE1JJt4C From c67e6df16bcbb904b5a820e574b49caeafeb0422 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 2 Sep 2023 23:22:24 -0400 Subject: [PATCH 1066/1547] Roll Flutter Engine from e496eec40e21 to 020776662e92 (1 revision) (#133926) https://github.com/flutter/engine/compare/e496eec40e21...020776662e92 2023-09-03 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from MesZPNdj-uw8VdCyV... to E7CUB2EEOm7ShBUib... (flutter/engine#45417) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from MesZPNdj-uw8 to E7CUB2EEOm7S If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f27116e3d4c97..30b34864bcf7d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e496eec40e21a91daccacece75b7f8c9731fdd62 +020776662e929e44cd7b2f7025af4873f987b609 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index bc71cf0d49a3f..c42c1d458f198 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -MesZPNdj-uw8VdCyVaharrEIFcHKtnvGxELJWE1JJt4C +E7CUB2EEOm7ShBUibIpf1UwJIEHlggwx4grdC2n3yoEC From 96621ebf0fd509cd70c19d08c05fc8990afe7847 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 3 Sep 2023 10:04:33 -0400 Subject: [PATCH 1067/1547] Roll Flutter Engine from 020776662e92 to fbc6f4a54047 (1 revision) (#133935) https://github.com/flutter/engine/compare/020776662e92...fbc6f4a54047 2023-09-03 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from E7CUB2EEOm7ShBUib... to p56hmQk2lEbN-VwEg... (flutter/engine#45419) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from E7CUB2EEOm7S to p56hmQk2lEbN If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC aaclarke@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 30b34864bcf7d..2e6424b732dc3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -020776662e929e44cd7b2f7025af4873f987b609 +fbc6f4a54047e95abc0fef7077f27da9f8e55b77 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c42c1d458f198..7b660e37a30ca 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -E7CUB2EEOm7ShBUibIpf1UwJIEHlggwx4grdC2n3yoEC +p56hmQk2lEbN-VwEg4PhRZk9ZgoeqIW1WIBhfP0LP_8C From ef9befc9da9f358f301d052e900b36ea3e797565 Mon Sep 17 00:00:00 2001 From: Renzo Olivares Date: Sun, 3 Sep 2023 11:23:20 -0700 Subject: [PATCH 1068/1547] Reland leak fix for EditableTextState (#133806) Relands: https://github.com/flutter/flutter/pull/131377 Reverted in: https://github.com/flutter/flutter/pull/133804 --- .../lib/src/widgets/editable_text.dart | 6 +++- .../material/text_selection_theme_test.dart | 28 ++----------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index afd29530f951a..d3e8663271ac5 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2125,6 +2125,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien late final Simulation _iosBlinkCursorSimulation = _DiscreteKeyFrameSimulation.iOSBlinkingCaret(); final ValueNotifier _cursorVisibilityNotifier = ValueNotifier(true); + final ValueNotifier _debugCursorNotifier = ValueNotifier(true); final GlobalKey _editableKey = GlobalKey(); /// Detects whether the clipboard can paste. @@ -2802,6 +2803,8 @@ class EditableTextState extends State with AutomaticKeepAliveClien void didChangeDependencies() { super.didChangeDependencies(); + _debugCursorNotifier.value = widget.showCursor; + _style = MediaQuery.boldTextOf(context) ? widget.style.merge(const TextStyle(fontWeight: FontWeight.bold)) : widget.style; @@ -2956,6 +2959,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien clipboardStatus.removeListener(_onChangedClipboardStatus); clipboardStatus.dispose(); _cursorVisibilityNotifier.dispose(); + _debugCursorNotifier.dispose(); FocusManager.instance.removeListener(_unflagInternalFocus); super.dispose(); assert(_batchEditDepth <= 0, 'unfinished batch edits: $_batchEditDepth'); @@ -4857,7 +4861,7 @@ class EditableTextState extends State with AutomaticKeepAliveClien cursorColor: _cursorColor, backgroundCursorColor: widget.backgroundCursorColor, showCursor: EditableText.debugDeterministicCursor - ? ValueNotifier(widget.showCursor) + ? _debugCursorNotifier : _cursorVisibilityNotifier, forceLine: widget.forceLine, readOnly: widget.readOnly, diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 4a990a5a0a5d0..50553dc297f39 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -105,20 +105,7 @@ void main() { await tester.pumpAndSettle(); final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); - }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130469 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: { - 'ValueNotifier': 1, - 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, - }, - // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. - allowAllNotGCed: true, - ), - ); + }); testWidgetsWithLeakTracking('Material3 - Empty textSelectionTheme will use defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); @@ -167,18 +154,7 @@ void main() { await tester.pumpAndSettle(); final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); expect(handle, paints..path(color: defaultSelectionHandleColor)); - }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/130469 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: { - 'ValueNotifier': 1, - 'ValueNotifier<_OverlayEntryWidgetState?>': 2, - 'ValueNotifier': 2, - '_InputBorderGap': 1, - }, - ), - ); + }); testWidgets('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { const TextSelectionThemeData textSelectionTheme = TextSelectionThemeData( From 6eca007a81ad760c96ff9b86961252252d7edf0a Mon Sep 17 00:00:00 2001 From: Greg Spencer Date: Tue, 5 Sep 2023 10:00:22 -0700 Subject: [PATCH 1069/1547] Fix links in top level README (#133893) ## Description This fixes the top level links to the platform embedders in the README that is used to create the landing page on https://master-api.flutter.dev --- dev/docs/README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dev/docs/README.md b/dev/docs/README.md index da52c41597bd4..e8ac002be6631 100644 --- a/dev/docs/README.md +++ b/dev/docs/README.md @@ -13,15 +13,16 @@ SDK. This site hosts Flutter's API documentation. Other documentation can be found at the following locations: -* [flutter.dev](https://flutter.dev) (main site) -* [api.flutter.dev](https://api.flutter.dev) (API docs reference site) +* [flutter.dev](https://flutter.dev) (main Flutter site) +* [Stable channel API Docs](https://api.flutter.dev) +* [Main channel API Docs](https://master-api.flutter.dev) * Engine Embedder API documentation: - * [Android Embedder](https://api.flutter.dev/javadoc/index.html) - * [iOS Embedder](https://api.flutter.dev/ios-embedder/index.html) - * [macOS Embedder](https://api.flutter.dev/macos-embedder/index.html) - * [Linux Embedder](https://api.flutter.dev/linux-embedder/index.html) - * [Windows Embedder](https://api.flutter.dev/windows-embedder/index.html) - * [Web Embedder](https://api.flutter.dev/flutter/dart-ui_web/dart-ui_web-library.html) + * [Android Embedder](../javadoc/index.html) + * [iOS Embedder](../ios-embedder/index.html) + * [macOS Embedder](../macos-embedder/index.html) + * [Linux Embedder](../linux-embedder/index.html) + * [Windows Embedder](../windows-embedder/index.html) + * [Web Embedder](dart-ui_web/dart-ui_web-library.html) * [Installation](https://flutter.dev/docs/get-started/install) * [Codelabs](https://flutter.dev/docs/codelabs) * [Contributing to Flutter](https://github.com/flutter/flutter/blob/master/CONTRIBUTING.md) From 85bece26898cce9b5d8bddf0141a732e4671b3a3 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Tue, 5 Sep 2023 11:00:07 -0700 Subject: [PATCH 1070/1547] [flutter_tools] Fix TypeError when a FileSystemException happens during flutter doctor (#133373) Fixes https://github.com/flutter/flutter/issues/133086 --- .../lib/src/intellij/intellij_validator.dart | 5 +- .../android/android_studio_test.dart | 1 - .../base/error_handling_io_test.dart | 3 +- .../intellij/intellij_validator_test.dart | 59 +++++++++++++++++-- .../general.shard/xcode_backend_test.dart | 2 +- packages/flutter_tools/test/src/common.dart | 1 + 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart index 691d8e5ebe272..4b2b436a3b298 100644 --- a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart +++ b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart @@ -487,8 +487,11 @@ class IntelliJValidatorOnMac extends IntelliJValidator { // Remove JetBrains Toolbox link apps. These tiny apps just // link to the full app, will get detected elsewhere in our search. validators.removeWhere((DoctorValidator validator) { + if (validator is! IntelliJValidatorOnMac) { + return false; + } final String identifierKey = plistParser.getValueFromFile( - (validator as IntelliJValidatorOnMac).plistFile, + validator.plistFile, PlistParser.kCFBundleIdentifierKey, ) as String; return identifierKey.contains('com.jetbrains.toolbox.linkapp'); diff --git a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart index cc8d8c2f36481..2fca60b3de957 100644 --- a/packages/flutter_tools/test/general.shard/android/android_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_studio_test.dart @@ -11,7 +11,6 @@ import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/version.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/ios/plist_parser.dart'; -import 'package:path/path.dart' show Context; // flutter_ignore: package_path_import -- We only use Context as an interface. import 'package:test/fake.dart'; import '../../src/common.dart'; diff --git a/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart b/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart index f9fa8ef8d21d9..e6363ceb91b39 100644 --- a/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart +++ b/packages/flutter_tools/test/general.shard/base/error_handling_io_test.dart @@ -12,7 +12,6 @@ import 'package:flutter_tools/src/base/error_handling_io.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; -import 'package:path/path.dart' as p; // flutter_ignore: package_path_import import 'package:process/process.dart'; import 'package:test/fake.dart'; @@ -1293,7 +1292,7 @@ class FakeExistsFile extends Fake implements File { class FakeFileSystem extends Fake implements FileSystem { @override - p.Context get path => p.Context(); + Context get path => Context(); @override Directory get currentDirectory { diff --git a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart index bd7f810a58c9a..f2bc787c7615f 100644 --- a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart @@ -11,6 +11,7 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/intellij/intellij_validator.dart'; import 'package:flutter_tools/src/ios/plist_parser.dart'; +import 'package:test/fake.dart'; import '../../src/common.dart'; import '../../src/fake_process_manager.dart'; @@ -373,6 +374,29 @@ void main() { expect(validator.pluginsPath, '/path/to/JetBrainsToolboxApp.plugins'); }); + testWithoutContext('IntelliJValidatorOnMac.installed() handles FileSystemExceptions)', () async { + const FileSystemException exception = FileSystemException('cannot list'); + final FileSystem fileSystem = _ThrowingFileSystem(exception); + + final FakeProcessManager processManager = FakeProcessManager.empty(); + + final Iterable validators = IntelliJValidatorOnMac.installed( + fileSystem: fileSystem, + fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: macPlatform), + userMessages: UserMessages(), + plistParser: FakePlistParser({ + 'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp', + 'CFBundleIdentifier': 'com.jetbrains.toolbox.linkapp', + }), + processManager: processManager, + ); + + expect(validators.length, 1); + final DoctorValidator validator = validators.first; + expect(validator, isA()); + expect(validator.title, 'Cannot determine if IntelliJ is installed'); + }); + testWithoutContext('Remove JetBrains Toolbox', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final List installPaths = [ @@ -398,11 +422,9 @@ void main() { ], stdout: 'skip') ]); - final Iterable installed = - IntelliJValidatorOnMac.installed( + final Iterable installed = IntelliJValidatorOnMac.installed( fileSystem: fileSystem, - fileSystemUtils: - FileSystemUtils(fileSystem: fileSystem, platform: macPlatform), + fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: macPlatform), userMessages: UserMessages(), plistParser: FakePlistParser({ 'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp', @@ -412,6 +434,7 @@ void main() { ); expect(installed.length, 0); + expect(processManager, hasNoRemainingExpectations); }); } @@ -458,7 +481,6 @@ void createIntellijFlutterPluginJar(String pluginJarPath, FileSystem fileSystem, fileSystem.file(pluginJarPath) ..createSync(recursive: true) ..writeAsBytesSync(ZipEncoder().encode(flutterPlugins)!); - } /// A helper to create a Intellij Dart plugin jar. @@ -496,3 +518,30 @@ void createIntellijDartPluginJar(String pluginJarPath, FileSystem fileSystem) { ..createSync(recursive: true) ..writeAsBytesSync(ZipEncoder().encode(dartPlugins)!); } + +// TODO(fujino): this should use the MemoryFileSystem and a +// FileExceptionHandler, blocked by https://github.com/google/file.dart/issues/227. +class _ThrowingFileSystem extends Fake implements FileSystem { + _ThrowingFileSystem(this._exception); + + final Exception _exception; + final MemoryFileSystem memfs = MemoryFileSystem.test(); + + @override + Context get path => memfs.path; + + @override + Directory directory(dynamic _) => _ThrowingDirectory(_exception); +} + +class _ThrowingDirectory extends Fake implements Directory { + _ThrowingDirectory(this._exception); + + final Exception _exception; + + @override + bool existsSync() => true; + + @override + List listSync({bool recursive = false, bool followLinks = true}) => throw _exception; +} diff --git a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart index 482e4ede33d37..dd36810f897b5 100644 --- a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart @@ -7,7 +7,7 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/io.dart'; import '../../bin/xcode_backend.dart'; -import '../src/common.dart'; +import '../src/common.dart' hide Context; import '../src/fake_process_manager.dart'; void main() { diff --git a/packages/flutter_tools/test/src/common.dart b/packages/flutter_tools/test/src/common.dart index e97fb955e2563..ca005f21e521a 100644 --- a/packages/flutter_tools/test/src/common.dart +++ b/packages/flutter_tools/test/src/common.dart @@ -17,6 +17,7 @@ import 'package:path/path.dart' as path; // flutter_ignore: package_path_import import 'package:test/test.dart' as test_package show test; import 'package:test/test.dart' hide test; +export 'package:path/path.dart' show Context; // flutter_ignore: package_path_import export 'package:test/test.dart' hide isInstanceOf, test; void tryToDelete(FileSystemEntity fileEntity) { From cb0a613ec6955d58bf711a813332f97a9f6a6a6b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 11:00:22 -0700 Subject: [PATCH 1071/1547] SegmentedButton should not create new MaterialStatesController in every build. (#133949) --- .../lib/src/material/segmented_button.dart | 59 +++++++++++-------- .../test/material/segmented_button_test.dart | 5 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/flutter/lib/src/material/segmented_button.dart b/packages/flutter/lib/src/material/segmented_button.dart index 1e23716b90a7b..ea513282bd658 100644 --- a/packages/flutter/lib/src/material/segmented_button.dart +++ b/packages/flutter/lib/src/material/segmented_button.dart @@ -96,7 +96,7 @@ class ButtonSegment { /// [ToggleButtons]. /// * [Radio], an alternative way to present the user with a mutually exclusive set of options. /// * [FilterChip], [ChoiceChip], which can be used when you need to show more than five options. -class SegmentedButton extends StatelessWidget { +class SegmentedButton extends StatefulWidget { /// Creates a const [SegmentedButton]. /// /// [segments] must contain at least one segment, but it is recommended @@ -235,27 +235,33 @@ class SegmentedButton extends StatelessWidget { /// Defaults to an [Icon] with [Icons.check]. final Widget? selectedIcon; - bool get _enabled => onSelectionChanged != null; + @override + State> createState() => _SegmentedButtonState(); +} + +class _SegmentedButtonState extends State> { + bool get _enabled => widget.onSelectionChanged != null; + final Map, MaterialStatesController> _statesControllers = , MaterialStatesController>{}; void _handleOnPressed(T segmentValue) { if (!_enabled) { return; } - final bool onlySelectedSegment = selected.length == 1 && selected.contains(segmentValue); - final bool validChange = emptySelectionAllowed || !onlySelectedSegment; + final bool onlySelectedSegment = widget.selected.length == 1 && widget.selected.contains(segmentValue); + final bool validChange = widget.emptySelectionAllowed || !onlySelectedSegment; if (validChange) { - final bool toggle = multiSelectionEnabled || (emptySelectionAllowed && onlySelectedSegment); + final bool toggle = widget.multiSelectionEnabled || (widget.emptySelectionAllowed && onlySelectedSegment); final Set pressedSegment = {segmentValue}; late final Set updatedSelection; if (toggle) { - updatedSelection = selected.contains(segmentValue) - ? selected.difference(pressedSegment) - : selected.union(pressedSegment); + updatedSelection = widget.selected.contains(segmentValue) + ? widget.selected.difference(pressedSegment) + : widget.selected.union(pressedSegment); } else { updatedSelection = pressedSegment; } - if (!setEquals(updatedSelection, selected)) { - onSelectionChanged!(updatedSelection); + if (!setEquals(updatedSelection, widget.selected)) { + widget.onSelectionChanged!(updatedSelection); } } } @@ -271,7 +277,7 @@ class SegmentedButton extends StatelessWidget { final Set currentState = _enabled ? enabledState : disabledState; P? effectiveValue

    (P? Function(ButtonStyle? style) getProperty) { - late final P? widgetValue = getProperty(style); + late final P? widgetValue = getProperty(widget.style); late final P? themeValue = getProperty(theme.style); late final P? defaultValue = getProperty(defaults.style); return widgetValue ?? themeValue ?? defaultValue; @@ -305,25 +311,24 @@ class SegmentedButton extends StatelessWidget { ); } - final ButtonStyle segmentStyle = segmentStyleFor(style); + final ButtonStyle segmentStyle = segmentStyleFor(widget.style); final ButtonStyle segmentThemeStyle = segmentStyleFor(theme.style).merge(segmentStyleFor(defaults.style)); - final Widget? selectedIcon = showSelectedIcon - ? this.selectedIcon ?? theme.selectedIcon ?? defaults.selectedIcon + final Widget? selectedIcon = widget.showSelectedIcon + ? widget.selectedIcon ?? theme.selectedIcon ?? defaults.selectedIcon : null; Widget buttonFor(ButtonSegment segment) { final Widget label = segment.label ?? segment.icon ?? const SizedBox.shrink(); - final bool segmentSelected = selected.contains(segment.value); - final Widget? icon = (segmentSelected && showSelectedIcon) + final bool segmentSelected = widget.selected.contains(segment.value); + final Widget? icon = (segmentSelected && widget.showSelectedIcon) ? selectedIcon : segment.label != null ? segment.icon : null; - final MaterialStatesController controller = MaterialStatesController( - { + final MaterialStatesController controller = _statesControllers.putIfAbsent(segment, () => MaterialStatesController()); + controller.value = { if (segmentSelected) MaterialState.selected, - } - ); + }; final Widget button = icon != null ? TextButton.icon( @@ -350,7 +355,7 @@ class SegmentedButton extends StatelessWidget { return MergeSemantics( child: Semantics( checked: segmentSelected, - inMutuallyExclusiveGroup: multiSelectionEnabled ? null : true, + inMutuallyExclusiveGroup: widget.multiSelectionEnabled ? null : true, child: buttonWithTooltip, ), ); @@ -363,7 +368,7 @@ class SegmentedButton extends StatelessWidget { final OutlinedBorder enabledBorder = resolvedEnabledBorder.copyWith(side: enabledSide); final OutlinedBorder disabledBorder = resolvedDisabledBorder.copyWith(side: disabledSide); - final List buttons = segments.map(buttonFor).toList(); + final List buttons = widget.segments.map(buttonFor).toList(); return Material( type: MaterialType.transparency, @@ -374,7 +379,7 @@ class SegmentedButton extends StatelessWidget { child: TextButtonTheme( data: TextButtonThemeData(style: segmentThemeStyle), child: _SegmentedButtonRenderWidget( - segments: segments, + segments: widget.segments, enabledBorder: _enabled ? enabledBorder : disabledBorder, disabledBorder: disabledBorder, direction: direction, @@ -383,6 +388,14 @@ class SegmentedButton extends StatelessWidget { ), ); } + + @override + void dispose() { + for (final MaterialStatesController controller in _statesControllers.values) { + controller.dispose(); + } + super.dispose(); + } } class _SegmentedButtonRenderWidget extends MultiChildRenderObjectWidget { const _SegmentedButtonRenderWidget({ diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index 57b31588e8862..cb302dc3cd5e3 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -9,6 +9,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -21,7 +22,9 @@ Widget boilerplate({required Widget child}) { void main() { - testWidgets('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', + leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed(), + (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( From 22510632331500d2a67d8a16181db3c30bb3ca51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 14:51:56 -0400 Subject: [PATCH 1072/1547] Manual roll Flutter Engine from fbc6f4a54047 to 1a6b47af3eb0 (12 revisions) (#134049) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/fbc6f4a54047...1a6b47af3eb0 2023-09-04 skia-flutter-autoroll@skia.org Roll Dart SDK from 671cf059e4b6 to 43d4b1373788 (2 revisions) (flutter/engine#45435) 2023-09-04 skia-flutter-autoroll@skia.org Roll Skia from c9d527e6b535 to 8206402f3c35 (1 revision) (flutter/engine#45434) 2023-09-04 robert.ancell@canonical.com Fix building on Pango 1.49.4 (flutter/engine#45098) 2023-09-04 skia-flutter-autoroll@skia.org Roll Dart SDK from a5c7102af509 to 671cf059e4b6 (1 revision) (flutter/engine#45429) 2023-09-04 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from ynBQWN3XpE2JvSlfd... to A82pOZ3-NNgfJ2Da7... (flutter/engine#45428) 2023-09-04 skia-flutter-autoroll@skia.org Roll ANGLE from 1fb536394148 to ab9bbb9b11b3 (1 revision) (flutter/engine#45426) 2023-09-04 skia-flutter-autoroll@skia.org Roll Skia from 5eaf624077b5 to c9d527e6b535 (1 revision) (flutter/engine#45425) 2023-09-04 skia-flutter-autoroll@skia.org Roll ANGLE from ebf1e7163216 to 1fb536394148 (1 revision) (flutter/engine#45424) 2023-09-04 skia-flutter-autoroll@skia.org Roll Skia from 906dcd219276 to 5eaf624077b5 (1 revision) (flutter/engine#45423) 2023-09-04 skia-flutter-autoroll@skia.org Roll Skia from 4d0501380011 to 906dcd219276 (1 revision) (flutter/engine#45422) 2023-09-04 skia-flutter-autoroll@skia.org Roll Skia from 15f77147a3ec to 4d0501380011 (1 revision) (flutter/engine#45421) 2023-09-04 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from p56hmQk2lEbN-VwEg... to ynBQWN3XpE2JvSlfd... (flutter/engine#45420) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from p56hmQk2lEbN to A82pOZ3-NNgf If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2e6424b732dc3..340c289fe476c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fbc6f4a54047e95abc0fef7077f27da9f8e55b77 +1a6b47af3eb04edf82fd7fc497f67c7a5ddad59b diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7b660e37a30ca..335b2a447cc52 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -p56hmQk2lEbN-VwEg4PhRZk9ZgoeqIW1WIBhfP0LP_8C +A82pOZ3-NNgfJ2Da76Zu3A1TMRh7dpFbjB-G9Eu7FgIC From c05dc3e68e1da82ad5fa40f9169d5af7e8817f6f Mon Sep 17 00:00:00 2001 From: Andrew Kolos Date: Tue, 5 Sep 2023 11:55:23 -0700 Subject: [PATCH 1073/1547] [Reland] Fix flavors test install checks (#134060) Reland of https://github.com/flutter/flutter/pull/133719. Updates [the string comparison in flavor_test.dart](https://github.com/flutter/flutter/pull/134060/files#diff-53383b32b975bfed6875306dfb98911cad077a5251ca0591c5b0e125fb4a0f05R39) to use `path.join` to build the path string so that the generated path is correct for both Linux and Windows hosts. Fixes https://github.com/flutter/flutter/issues/133713 I've tested this on a Windows host targeting a physical Android device. --- dev/devicelab/bin/tasks/flavors_test.dart | 56 +++++++++++-------- dev/devicelab/bin/tasks/flavors_test_ios.dart | 51 +++++++++-------- .../bin/tasks/flavors_test_macos.dart | 41 ++++++++------ 3 files changed, 83 insertions(+), 65 deletions(-) diff --git a/dev/devicelab/bin/tasks/flavors_test.dart b/dev/devicelab/bin/tasks/flavors_test.dart index 055f58aa29f7f..2db0956f79a62 100644 --- a/dev/devicelab/bin/tasks/flavors_test.dart +++ b/dev/devicelab/bin/tasks/flavors_test.dart @@ -7,37 +7,45 @@ import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart'; +import 'package:path/path.dart' as path; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.android; await task(() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); - // test install and uninstall of flavors app - await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { - await flutter( - 'install', - options: ['--debug', '--flavor', 'paid'], - ); - await flutter( - 'install', - options: ['--debug', '--flavor', 'paid', '--uninstall-only'], - ); - final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: ['--flavor', 'bogus'], - ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('The Xcode project defines schemes: free, paid')) { - print(stderrString); - return TaskResult.failure('Should not succeed with bogus flavor'); - } - }); + final TaskResult installTestsResult = await inDirectory( + '${flutterDirectory.path}/dev/integration_tests/flavors', + () async { + await flutter( + 'install', + options: ['--debug', '--flavor', 'paid'], + ); + await flutter( + 'install', + options: ['--debug', '--flavor', 'paid', '--uninstall-only'], + ); - return TaskResult.success(null); + final StringBuffer stderr = StringBuffer(); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: ['--flavor', 'bogus'], + ); + + final String stderrString = stderr.toString(); + final String expectedApkPath = path.join('build', 'app', 'outputs', 'flutter-apk', 'app-bogus-release.apk'); + if (!stderrString.contains('"$expectedApkPath" does not exist.')) { + print(stderrString); + return TaskResult.failure('Should not succeed with bogus flavor'); + } + + return TaskResult.success(null); + }, + ); + + return installTestsResult; }); } diff --git a/dev/devicelab/bin/tasks/flavors_test_ios.dart b/dev/devicelab/bin/tasks/flavors_test_ios.dart index 2fbfcb9e0a4af..4e84ed4ec3566 100644 --- a/dev/devicelab/bin/tasks/flavors_test_ios.dart +++ b/dev/devicelab/bin/tasks/flavors_test_ios.dart @@ -14,30 +14,35 @@ Future main() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); // test install and uninstall of flavors app - await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { - await flutter( - 'install', - options: ['--flavor', 'paid'], - ); - await flutter( - 'install', - options: ['--flavor', 'paid', '--uninstall-only'], - ); - final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: ['--flavor', 'bogus'], - ); + final TaskResult installTestsResult = await inDirectory( + '${flutterDirectory.path}/dev/integration_tests/flavors', + () async { + await flutter( + 'install', + options: ['--flavor', 'paid'], + ); + await flutter( + 'install', + options: ['--flavor', 'paid', '--uninstall-only'], + ); + final StringBuffer stderr = StringBuffer(); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: ['--flavor', 'bogus'], + ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('install failed, bogus flavor not found')) { - print(stderrString); - return TaskResult.failure('Should not succeed with bogus flavor'); - } - }); + final String stderrString = stderr.toString(); + if (!stderrString.contains('The Xcode project defines schemes: free, paid')) { + print(stderrString); + return TaskResult.failure('Should not succeed with bogus flavor'); + } - return TaskResult.success(null); + return TaskResult.success(null); + }, + ); + + return installTestsResult; }); } diff --git a/dev/devicelab/bin/tasks/flavors_test_macos.dart b/dev/devicelab/bin/tasks/flavors_test_macos.dart index 346bc31a19c98..e3bb56123bc4a 100644 --- a/dev/devicelab/bin/tasks/flavors_test_macos.dart +++ b/dev/devicelab/bin/tasks/flavors_test_macos.dart @@ -14,26 +14,31 @@ Future main() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); - await inDirectory('${flutterDirectory.path}/dev/integration_tests/flavors', () async { - final StringBuffer stderr = StringBuffer(); + final TaskResult installTestsResult = await inDirectory( + '${flutterDirectory.path}/dev/integration_tests/flavors', + () async { + final StringBuffer stderr = StringBuffer(); - await evalFlutter( - 'install', - canFail: true, - stderr: stderr, - options: [ - '--d', 'macos', - '--flavor', 'free' - ], - ); + await evalFlutter( + 'install', + canFail: true, + stderr: stderr, + options: [ + '--d', 'macos', + '--flavor', 'free' + ], + ); - final String stderrString = stderr.toString(); - if (!stderrString.contains('Host and target are the same. Nothing to install.')) { - print(stderrString); - return TaskResult.failure('Installing a macOS app on macOS should no-op'); - } - }); + final String stderrString = stderr.toString(); + if (!stderrString.contains('Host and target are the same. Nothing to install.')) { + print(stderrString); + return TaskResult.failure('Installing a macOS app on macOS should no-op'); + } - return TaskResult.success(null); + return TaskResult.success(null); + }, + ); + + return installTestsResult; }); } From 7cdf314d0675064ee6f7b2b94935b250edae2f71 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 13:01:51 -0700 Subject: [PATCH 1074/1547] CupertinoAlertDialog should not create ScrollController on every build, if null values are passed in constructor. (#133918) --- .../flutter/lib/src/cupertino/dialog.dart | 48 ++++++++++++------- .../flutter/test/material/dialog_test.dart | 2 +- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index ef8c10936043b..2e4d27af75740 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -188,7 +188,7 @@ bool _isInAccessibilityMode(BuildContext context) { /// * [CupertinoDialogAction], which is an iOS-style dialog button. /// * [AlertDialog], a Material Design alert dialog. /// * -class CupertinoAlertDialog extends StatelessWidget { +class CupertinoAlertDialog extends StatefulWidget { /// Creates an iOS-style alert dialog. /// /// The [actions] must not be null. @@ -233,9 +233,6 @@ class CupertinoAlertDialog extends StatelessWidget { /// section when there are many actions. final ScrollController? scrollController; - ScrollController get _effectiveScrollController => - scrollController ?? ScrollController(); - /// A scroll controller that can be used to control the scrolling of the /// actions in the dialog. /// @@ -247,37 +244,49 @@ class CupertinoAlertDialog extends StatelessWidget { /// section when it is long. final ScrollController? actionScrollController; - ScrollController get _effectiveActionScrollController => - actionScrollController ?? ScrollController(); - /// {@macro flutter.material.dialog.insetAnimationDuration} final Duration insetAnimationDuration; /// {@macro flutter.material.dialog.insetAnimationCurve} final Curve insetAnimationCurve; + @override + State createState() => _CupertinoAlertDialogState(); +} + +class _CupertinoAlertDialogState extends State { + ScrollController? _backupScrollController; + + ScrollController? _backupActionScrollController; + + ScrollController get _effectiveScrollController => + widget.scrollController ?? (_backupScrollController ??= ScrollController()); + + ScrollController get _effectiveActionScrollController => + widget.actionScrollController ?? (_backupActionScrollController ??= ScrollController()); + Widget _buildContent(BuildContext context) { final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; final List children = [ - if (title != null || content != null) + if (widget.title != null || widget.content != null) Flexible( flex: 3, child: _CupertinoAlertContentSection( - title: title, - message: content, + title: widget.title, + message: widget.content, scrollController: _effectiveScrollController, titlePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, - bottom: content == null ? _kDialogEdgePadding : 1.0, + bottom: widget.content == null ? _kDialogEdgePadding : 1.0, top: _kDialogEdgePadding * textScaleFactor, ), messagePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, bottom: _kDialogEdgePadding * textScaleFactor, - top: title == null ? _kDialogEdgePadding : 1.0, + top: widget.title == null ? _kDialogEdgePadding : 1.0, ), titleTextStyle: _kCupertinoDialogTitleStyle.copyWith( color: CupertinoDynamicColor.resolve(CupertinoColors.label, context), @@ -303,10 +312,10 @@ class CupertinoAlertDialog extends StatelessWidget { Widget actionSection = Container( height: 0.0, ); - if (actions.isNotEmpty) { + if (widget.actions.isNotEmpty) { actionSection = _CupertinoAlertActionSection( scrollController: _effectiveActionScrollController, - children: actions, + children: widget.actions, ); } @@ -330,8 +339,8 @@ class CupertinoAlertDialog extends StatelessWidget { return AnimatedPadding( padding: MediaQuery.viewInsetsOf(context) + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), - duration: insetAnimationDuration, - curve: insetAnimationCurve, + duration: widget.insetAnimationDuration, + curve: widget.insetAnimationCurve, child: MediaQuery.removeViewInsets( removeLeft: true, removeTop: true, @@ -368,6 +377,13 @@ class CupertinoAlertDialog extends StatelessWidget { ), ); } + + @override + void dispose() { + _backupScrollController?.dispose(); + _backupActionScrollController?.dispose(); + super.dispose(); + } } /// Rounded rectangle surface that looks like an iOS popup surface, e.g., alert dialog diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index d26707e98629b..5e8d9f2ff9635 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -2664,7 +2664,7 @@ void main() { okNode.dispose(); }); - testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog.adaptive( content: Container( height: 5000.0, From c9f70e9fd265afdb0a89ce0f5a1d230c30636639 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 13:12:28 -0700 Subject: [PATCH 1075/1547] _SearchBarState should dispose FocusNode, if it created it. (#133947) --- packages/flutter/lib/src/material/search_anchor.dart | 3 +++ packages/flutter/test/material/search_anchor_test.dart | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 6cb8c22c1c627..4897de7449df8 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -1179,6 +1179,9 @@ class _SearchBarState extends State { @override void dispose() { _internalStatesController.dispose(); + if (widget.focusNode == null) { + _focusNode.dispose(); + } super.dispose(); } diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index c044bdfc0a4db..c2af15aad9ac1 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -6,9 +6,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SearchBar defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colorScheme = theme.colorScheme; From af1b7494d8f15b2ff00d051cb51e90bf6a4f36c1 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 13:40:14 -0700 Subject: [PATCH 1076/1547] RenderParagraph should dispose instances of SelectableFragments. (#133915) --- packages/flutter/lib/src/rendering/paragraph.dart | 4 +--- packages/flutter/test/material/elevated_button_test.dart | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 488391333690e..79e25371abe7c 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -437,9 +437,7 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin Date: Tue, 5 Sep 2023 13:41:10 -0700 Subject: [PATCH 1077/1547] _MaterialAppState should dispose MaterialHeroController. (#133951) --- packages/flutter/lib/src/material/app.dart | 6 + packages/flutter/lib/src/widgets/heroes.dart | 21 +++ .../flutter/test/material/snack_bar_test.dart | 5 +- .../flutter/test/material/stepper_test.dart | 120 +++++++++--------- .../test/material/switch_list_tile_test.dart | 2 +- 5 files changed, 93 insertions(+), 61 deletions(-) diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index a653e3c7099d1..41c5d9fc7ded6 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -880,6 +880,12 @@ class _MaterialAppState extends State { _heroController = MaterialApp.createMaterialHeroController(); } + @override + void dispose() { + _heroController.dispose(); + super.dispose(); + } + // Combine the Localizations for Material with the ones contributed // by the localizationsDelegates parameter, if any. Only the first delegate // of a particular LocalizationsDelegate.type is loaded so the diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart index 3970b5e63fb79..f0ff4a7b7f4e6 100644 --- a/packages/flutter/lib/src/widgets/heroes.dart +++ b/packages/flutter/lib/src/widgets/heroes.dart @@ -612,6 +612,19 @@ class _HeroFlight { navigator.userGestureInProgressNotifier.addListener(delayedPerformAnimationUpdate); } + /// Releases resources. + @mustCallSuper + void dispose() { + if (overlayEntry != null) { + overlayEntry!.remove(); + overlayEntry!.dispose(); + overlayEntry = null; + _proxyAnimation.parent = null; + _proxyAnimation.removeListener(onTick); + _proxyAnimation.removeStatusListener(_handleAnimationUpdate); + } + } + void onTick() { final RenderBox? toHeroBox = (!_aborted && manifest.toHero.mounted) ? manifest.toHero.context.findRenderObject() as RenderBox? @@ -1027,6 +1040,14 @@ class HeroController extends NavigatorObserver { }, ); } + + /// Releases resources. + @mustCallSuper + void dispose() { + for (final _HeroFlight flight in _flights.values) { + flight.dispose(); + } + } } /// Enables or disables [Hero]es in the widget subtree. diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index 667f482978916..bdef27eabbc0c 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -14,6 +14,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { testWidgets('SnackBar control test', (WidgetTester tester) async { @@ -2542,7 +2543,9 @@ void main() { expect(find.text(secondHeader), findsOneWidget); }); - testWidgets('Should have only one SnackBar during back swipe navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Should have only one SnackBar during back swipe navigation', + leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed(), + (WidgetTester tester) async { const String snackBarText = 'hello snackbar'; const Key snackTarget = Key('snack-target'); const Key transitionTarget = Key('transition-target'); diff --git a/packages/flutter/test/material/stepper_test.dart b/packages/flutter/test/material/stepper_test.dart index 2d3f0106d4033..405b7097a5e59 100644 --- a/packages/flutter/test/material/stepper_test.dart +++ b/packages/flutter/test/material/stepper_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Material3 has sentence case labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 has sentence case labels', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -38,7 +39,7 @@ void main() { expect(find.text('Cancel'), findsWidgets); }); - testWidgets('Stepper tap callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper tap callback test', (WidgetTester tester) async { int index = 0; await tester.pumpWidget( @@ -72,7 +73,7 @@ void main() { expect(index, 1); }); - testWidgets('Stepper expansion test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper expansion test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Center( @@ -139,7 +140,7 @@ void main() { expect(box.size.height, 432.0); }); - testWidgets('Stepper horizontal size test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper horizontal size test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Center( @@ -165,7 +166,7 @@ void main() { expect(box.size.height, 600.0); }); - testWidgets('Stepper visibility test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper visibility test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -214,7 +215,7 @@ void main() { expect(find.text('B'), findsOneWidget); }); - testWidgets('Material2 - Stepper button test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Stepper button test', (WidgetTester tester) async { bool continuePressed = false; bool cancelPressed = false; @@ -258,7 +259,7 @@ void main() { expect(cancelPressed, isTrue); }); - testWidgets('Material3 - Stepper button test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Stepper button test', (WidgetTester tester) async { bool continuePressed = false; bool cancelPressed = false; @@ -302,7 +303,7 @@ void main() { expect(cancelPressed, isTrue); }); - testWidgets('Stepper disabled step test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper disabled step test', (WidgetTester tester) async { int index = 0; await tester.pumpWidget( @@ -338,7 +339,7 @@ void main() { expect(index, 0); }); - testWidgets('Stepper scroll test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper scroll test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -412,7 +413,7 @@ void main() { expect(scrollableState.position.pixels, greaterThan(0.0)); }); - testWidgets('Stepper index test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper index test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Center( @@ -445,7 +446,7 @@ void main() { expect(find.text('2'), findsOneWidget); }); - testWidgets('Stepper custom controls test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper custom controls test', (WidgetTester tester) async { bool continuePressed = false; void setContinue() { continuePressed = true; @@ -524,7 +525,7 @@ void main() { expect(continuePressed, isTrue); }); -testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async { +testWidgetsWithLeakTracking('Stepper custom indexed controls test', (WidgetTester tester) async { int currentStep = 0; void setContinue() { @@ -619,7 +620,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(find.text('Continue to 2'), findsNWidgets(1)); }); - testWidgets('Stepper error test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper error test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Center( @@ -644,7 +645,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(find.text('!'), findsOneWidget); }); - testWidgets('Nested stepper error test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested stepper error test', (WidgetTester tester) async { late FlutterErrorDetails errorDetails; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { @@ -711,7 +712,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async }); ///https://github.com/flutter/flutter/issues/16920 - testWidgets('Stepper icons size test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper icons size test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -740,7 +741,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(renderObject.size, equals(const Size.square(18.0))); }); - testWidgets('Stepper physics scroll error test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper physics scroll error test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -773,7 +774,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(find.text('Text After Stepper'), findsNothing); }); - testWidgets("Vertical Stepper can't be focused when disabled.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Vertical Stepper can't be focused when disabled.", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -797,7 +798,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(disabledNode.hasPrimaryFocus, isFalse); }); - testWidgets("Horizontal Stepper can't be focused when disabled.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Horizontal Stepper can't be focused when disabled.", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -822,7 +823,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(disabledNode.hasPrimaryFocus, isFalse); }); - testWidgets('Stepper header title should not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper header title should not overflow', (WidgetTester tester) async { const String longText = 'A long long long long long long long long long long long long text'; @@ -848,7 +849,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(tester.takeException(), isNull); }); - testWidgets('Stepper header subtitle should not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper header subtitle should not overflow', (WidgetTester tester) async { const String longText = 'A long long long long long long long long long long long long text'; @@ -875,7 +876,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(tester.takeException(), isNull); }); - testWidgets('Material2 - Stepper enabled button styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Stepper enabled button styles', (WidgetTester tester) async { Widget buildFrame(ThemeData theme) { return MaterialApp( theme: theme, @@ -935,7 +936,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(tester.getRect(find.widgetWithText(TextButton, cancelStr)), cancelButtonRect); }); - testWidgets('Material3 - Stepper enabled button styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Stepper enabled button styles', (WidgetTester tester) async { Widget buildFrame(ThemeData theme) { return MaterialApp( theme: theme, @@ -1007,7 +1008,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async ); }); - testWidgets('Material2 - Stepper disabled button styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Stepper disabled button styles', (WidgetTester tester) async { Widget buildFrame(ThemeData theme) { return MaterialApp( theme: theme, @@ -1053,7 +1054,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(buttonMaterial(cancelStr).textStyle!.color!.value, 0x61ffffff); }); - testWidgets('Material3 - Stepper disabled button styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Stepper disabled button styles', (WidgetTester tester) async { Widget buildFrame(ThemeData theme) { return MaterialApp( theme: theme, @@ -1113,7 +1114,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async ); }); - testWidgets('Vertical and Horizontal Stepper physics test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical and Horizontal Stepper physics test', (WidgetTester tester) async { const ScrollPhysics physics = NeverScrollableScrollPhysics(); for (final StepperType type in StepperType.values) { @@ -1142,38 +1143,39 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async } }); - testWidgets('ScrollController is passed to the stepper listview', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); - for (final StepperType type in StepperType.values) { - await tester.pumpWidget( - MaterialApp( - home: Material( - child: Stepper( - controller: controller, - type: type, - steps: const [ - Step( - title: Text('Step 1'), - content: SizedBox( - width: 100.0, - height: 100.0, - ), + testWidgetsWithLeakTracking('ScrollController is passed to the stepper listview', (WidgetTester tester) async { + final ScrollController controller = ScrollController(); + addTearDown(() => controller.dispose()); + for (final StepperType type in StepperType.values) { + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Stepper( + controller: controller, + type: type, + steps: const [ + Step( + title: Text('Step 1'), + content: SizedBox( + width: 100.0, + height: 100.0, ), - ], - ), + ), + ], ), ), - ); + ), + ); - final ListView listView = tester.widget( - find.descendant(of: find.byType(Stepper), - matching: find.byType(ListView), - )); - expect(listView.controller, controller); - } - }); + final ListView listView = tester.widget( + find.descendant(of: find.byType(Stepper), + matching: find.byType(ListView), + )); + expect(listView.controller, controller); + } + }); - testWidgets('Stepper horizontal size test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper horizontal size test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/77732 Widget buildFrame({ bool isActive = true, Brightness? brightness }) { return MaterialApp( @@ -1218,7 +1220,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(circleFillColor(), dark.background); }); - testWidgets('Stepper custom elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper custom elevation', (WidgetTester tester) async { const double elevation = 4.0; await tester.pumpWidget( @@ -1252,7 +1254,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(material.elevation, elevation); }); - testWidgets('Stepper with default elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper with default elevation', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( @@ -1284,7 +1286,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(material.elevation, 2.0); }); - testWidgets('Stepper horizontal preserves state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper horizontal preserves state', (WidgetTester tester) async { const Color untappedColor = Colors.blue; const Color tappedColor = Colors.red; int index = 0; @@ -1355,7 +1357,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async // The color should still be `tappedColor` expect(getColor(), tappedColor); }); - testWidgets('Stepper custom margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper custom margin', (WidgetTester tester) async { const EdgeInsetsGeometry margin = EdgeInsetsDirectional.only( bottom: 20, @@ -1392,7 +1394,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(material.margin, equals(margin)); }); - testWidgets('Stepper with Alternative Label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper with Alternative Label', (WidgetTester tester) async { int index = 0; late TextStyle bodyLargeStyle; late TextStyle bodyMediumStyle; @@ -1476,7 +1478,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(bodyMediumStyle, nextLabelTextWidget.style); }); - testWidgets('Stepper Connector Style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper Connector Style', (WidgetTester tester) async { const Color selectedColor = Colors.black; const Color disabledColor = Colors.white; int index = 0; @@ -1545,7 +1547,7 @@ testWidgets('Stepper custom indexed controls test', (WidgetTester tester) async expect(lineColor('line0'), selectedColor); }); - testWidgets('Stepper stepIconBuilder test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stepper stepIconBuilder test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( diff --git a/packages/flutter/test/material/switch_list_tile_test.dart b/packages/flutter/test/material/switch_list_tile_test.dart index f3ee1be963477..b6dc0200ecfaa 100644 --- a/packages/flutter/test/material/switch_list_tile_test.dart +++ b/packages/flutter/test/material/switch_list_tile_test.dart @@ -865,7 +865,7 @@ void main() { ); }); - testWidgets('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SwitchListTile respects thumbColor in hovered/pressed states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredThumbColor = Color(0xFF4caf50); const Color pressedThumbColor = Color(0xFFF44336); From a7dbec31f1ad1da86cedee4ef614f5dce4d0f517 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 13:45:12 -0700 Subject: [PATCH 1078/1547] Cover more tests with leak tracking. (#133958) --- .../flutter/lib/src/material/time_picker.dart | 16 + .../flutter/test/material/checkbox_test.dart | 16 +- .../flutter/test/material/dialog_test.dart | 28 +- .../test/material/dialog_theme_test.dart | 49 +- .../test/material/drawer_button_test.dart | 4 +- .../flutter/test/material/drawer_test.dart | 35 +- .../test/material/drawer_theme_test.dart | 19 +- .../test/material/expansion_panel_test.dart | 4 +- .../test/material/filled_button_test.dart | 17 +- ...flexible_space_bar_collapse_mode_test.dart | 4 +- .../flexible_space_bar_stretch_mode_test.dart | 4 +- .../test/material/icon_button_test.dart | 8 +- .../test/material/inherited_theme_test.dart | 15 +- .../flutter/test/material/ink_paint_test.dart | 11 +- .../flutter/test/material/ink_well_test.dart | 3 +- .../input_date_picker_form_field_test.dart | 27 +- .../test/material/input_decorator_test.dart | 325 +++-- .../flutter/test/material/magnifier_test.dart | 92 +- .../test/material/menu_anchor_test.dart | 126 +- .../test/material/menu_bar_theme_test.dart | 2 +- .../test/material/menu_style_test.dart | 11 +- .../test/material/menu_theme_test.dart | 2 +- .../material/mergeable_material_test.dart | 8 +- .../test/material/navigation_drawer_test.dart | 19 +- .../navigation_drawer_theme_test.dart | 11 +- .../material/navigation_rail_theme_test.dart | 15 +- .../test/material/outlined_button_test.dart | 8 +- packages/flutter/test/material/page_test.dart | 54 +- .../material/page_transitions_theme_test.dart | 2 +- .../material/paginated_data_table_test.dart | 5 + .../test/material/popup_menu_test.dart | 127 +- .../test/material/radio_list_tile_test.dart | 4 +- .../flutter/test/material/radio_test.dart | 6 +- .../test/material/range_slider_test.dart | 93 +- .../test/material/reorderable_list_test.dart | 141 +- .../flutter/test/material/scaffold_test.dart | 126 +- .../test/material/scrollbar_paint_test.dart | 4 +- .../flutter/test/material/scrollbar_test.dart | 2 +- .../flutter/test/material/slider_test.dart | 141 +- .../test/material/slider_theme_test.dart | 84 +- .../test/material/snack_bar_theme_test.dart | 27 +- packages/flutter/test/material/tabs_test.dart | 180 +-- .../test/material/text_field_focus_test.dart | 41 +- .../material/text_field_helper_text_test.dart | 3 +- .../test/material/text_field_splash_test.dart | 5 +- .../test/material/text_field_test.dart | 1281 +++++++++-------- .../test/material/text_form_field_test.dart | 94 +- .../test/material/text_selection_test.dart | 43 +- .../material/text_selection_theme_test.dart | 6 +- .../test/material/theme_defaults_test.dart | 9 +- .../flutter/test/material/theme_test.dart | 73 +- .../test/material/time_picker_test.dart | 3 +- .../test/material/time_picker_theme_test.dart | 13 +- packages/flutter/test/material/time_test.dart | 10 +- .../flutter/test/material/tooltip_test.dart | 76 +- .../test/material/tooltip_theme_test.dart | 85 +- .../value_indicating_slider_test.dart | 8 +- .../flutter/test/material/will_pop_test.dart | 13 +- 58 files changed, 1989 insertions(+), 1649 deletions(-) diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index e36e5a20c3500..d55ab6a077693 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2206,6 +2206,15 @@ class _TimePickerDialogState extends State with RestorationMix static const Size _kTimePickerMinLandscapeSize = Size(416, 248); static const Size _kTimePickerMinInputSize = Size(312, 196); + @override + void dispose() { + _selectedTime.dispose(); + _entryMode.dispose(); + _autovalidateMode.dispose(); + _orientation.dispose(); + super.dispose(); + } + @override String? get restorationId => widget.restorationId; @@ -2586,6 +2595,13 @@ class _TimePickerState extends State<_TimePicker> with RestorationMixin { void dispose() { _vibrateTimer?.cancel(); _vibrateTimer = null; + _orientation.dispose(); + _selectedTime.dispose(); + _hourMinuteMode.dispose(); + _lastModeAnnounced.dispose(); + _autofocusHour.dispose(); + _autofocusMinute.dispose(); + _announcedInitialTime.dispose(); super.dispose(); } diff --git a/packages/flutter/test/material/checkbox_test.dart b/packages/flutter/test/material/checkbox_test.dart index fe82a294f1ecb..40edadc0b15bc 100644 --- a/packages/flutter/test/material/checkbox_test.dart +++ b/packages/flutter/test/material/checkbox_test.dart @@ -644,7 +644,7 @@ void main() { testWidgetsWithLeakTracking('Material2 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp({bool enabled = true}) { @@ -715,7 +715,7 @@ void main() { testWidgetsWithLeakTracking('Material3 - Checkbox is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); final ThemeData theme = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; @@ -1244,7 +1244,7 @@ void main() { testWidgetsWithLeakTracking('Checkbox fill color resolves in hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color hoveredFillColor = Color(0xFF000001); @@ -1345,7 +1345,7 @@ void main() { testWidgetsWithLeakTracking('Material2 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: false); @@ -1413,7 +1413,7 @@ void main() { testWidgetsWithLeakTracking('Material3 - Checkbox default overlay color in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: true); @@ -1479,7 +1479,7 @@ void main() { testWidgetsWithLeakTracking('Checkbox overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; const Color fillColor = Color(0xFF000000); @@ -1973,7 +1973,7 @@ void main() { testWidgetsWithLeakTracking('Material3 - Checkbox has default error color when isError is set to true', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); final ThemeData themeData = ThemeData(useMaterial3: true); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; @@ -2046,7 +2046,7 @@ void main() { testWidgetsWithLeakTracking('Material3 - Checkbox MaterialStateBorderSide applies in error states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Checkbox'); - addTearDown(() => focusNode.dispose()); + addTearDown(focusNode.dispose); final ThemeData themeData = ThemeData(useMaterial3: true); const Color borderColor = Color(0xffffeb3b); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 5e8d9f2ff9635..0a162059412d9 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -111,7 +111,7 @@ void main() { expect(materialWidget.color, customColor); }); - testWidgets('Dialog Defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog Defaults', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), content: Text('Y'), @@ -146,7 +146,7 @@ void main() { expect(material3Widget.elevation, 6.0); }); - testWidgets('Dialog.fullscreen Defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog.fullscreen Defaults', (WidgetTester tester) async { const String dialogTextM2 = 'Fullscreen Dialog - M2'; const String dialogTextM3 = 'Fullscreen Dialog - M3'; @@ -447,7 +447,7 @@ void main() { expect(textRect.bottom, dialogRect.bottom - customPadding.bottom); }); - testWidgets('Barrier dismissible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier dismissible', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -644,7 +644,7 @@ void main() { expect(actionsSize.width, dialogSize.width - (30.0 * 2)); }); - testWidgets('AlertDialog.buttonPadding defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlertDialog.buttonPadding defaults', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -1904,7 +1904,7 @@ void main() { semantics.dispose(); }); - testWidgets('Dismissible.confirmDismiss defers to an AlertDialog', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible.confirmDismiss defers to an AlertDialog', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final List dismissedItems = []; @@ -2035,7 +2035,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/28505. - testWidgets('showDialog only gets Theme from context on the first call', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showDialog only gets Theme from context on the first call', (WidgetTester tester) async { Widget buildFrame(Key builderKey) { return MaterialApp( home: Center( @@ -2072,7 +2072,7 @@ void main() { await tester.pump(); }); - testWidgets('showDialog safe area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showDialog safe area', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -2337,7 +2337,7 @@ void main() { }); group('AlertDialog.scrollable: ', () { - testWidgets('Title is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Title is scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final AlertDialog dialog = AlertDialog( title: Container( @@ -2377,7 +2377,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0))); }); - testWidgets('Title and content are scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Title and content are scrollable', (WidgetTester tester) async { final Key titleKey = UniqueKey(); final Key contentKey = UniqueKey(); final AlertDialog dialog = AlertDialog( @@ -2416,7 +2416,7 @@ void main() { }); }); - testWidgets('Dialog with RouteSettings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog with RouteSettings', (WidgetTester tester) async { late RouteSettings currentRouteSetting; await tester.pumpWidget( @@ -2510,7 +2510,7 @@ void main() { semantics.dispose(); }); - testWidgets('DialogRoute is state restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DialogRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -2706,7 +2706,7 @@ void main() { } }); - testWidgets('showAdaptiveDialog should not allow dismiss on barrier on iOS by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showAdaptiveDialog should not allow dismiss on barrier on iOS by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.iOS), @@ -2766,9 +2766,11 @@ void main() { expect(find.text('Dialog2'), findsOneWidget); }); - testWidgets('Uses open focus traversal when overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses open focus traversal when overridden', (WidgetTester tester) async { final FocusNode okNode = FocusNode(); + addTearDown(okNode.dispose); final FocusNode cancelNode = FocusNode(); + addTearDown(cancelNode.dispose); Future nextFocus() async { final bool result = Actions.invoke( diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index 0d41077d0c87b..e327542e005b7 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; MaterialApp _appWithDialog(WidgetTester tester, Widget dialog, { ThemeData? theme }) { return MaterialApp( @@ -54,7 +55,7 @@ void main() { expect(identical(DialogTheme.lerp(theme, theme, 0.5), theme), true); }); - testWidgets('Dialog Theme implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog Theme implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DialogTheme( backgroundColor: Color(0xff123456), @@ -83,7 +84,7 @@ void main() { ]); }); - testWidgets('Dialog background color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog background color', (WidgetTester tester) async { const Color customColor = Colors.pink; const AlertDialog dialog = AlertDialog( title: Text('Title'), @@ -99,7 +100,7 @@ void main() { expect(materialWidget.color, customColor); }); - testWidgets('Custom dialog elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom dialog elevation', (WidgetTester tester) async { const double customElevation = 12.0; const Color shadowColor = Color(0xFF000001); const Color surfaceTintColor = Color(0xFF000002); @@ -127,7 +128,7 @@ void main() { expect(materialWidget.surfaceTintColor, surfaceTintColor); }); - testWidgets('Custom dialog shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom dialog shape', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -146,7 +147,7 @@ void main() { expect(materialWidget.shape, customBorder); }); - testWidgets('Custom dialog alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom dialog alignment', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], @@ -166,7 +167,7 @@ void main() { expect(bottomLeft.dy, 576.0); }); - testWidgets('Material3 - Dialog alignment takes priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Dialog alignment takes priority over theme', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], @@ -192,7 +193,7 @@ void main() { } }); - testWidgets('Material2 - Dialog alignment takes priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Dialog alignment takes priority over theme', (WidgetTester tester) async { const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], @@ -213,7 +214,7 @@ void main() { expect(bottomLeft.dy, 104.0); }); - testWidgets('Material3 - Custom dialog shape matches golden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Custom dialog shape matches golden', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -235,7 +236,7 @@ void main() { ); }); - testWidgets('Material2 - Custom dialog shape matches golden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Custom dialog shape matches golden', (WidgetTester tester) async { const RoundedRectangleBorder customBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const AlertDialog dialog = AlertDialog( @@ -254,7 +255,7 @@ void main() { ); }); - testWidgets('Custom Icon Color - Constructor Param - highest preference', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Icon Color - Constructor Param - highest preference', (WidgetTester tester) async { const Color iconColor = Colors.pink, dialogThemeColor = Colors.green, iconThemeColor = Colors.yellow; final ThemeData theme = ThemeData( iconTheme: const IconThemeData(color: iconThemeColor), @@ -275,7 +276,7 @@ void main() { expect(text.text.style!.color, iconColor); }); - testWidgets('Custom Icon Color - Dialog Theme - preference over Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Icon Color - Dialog Theme - preference over Theme', (WidgetTester tester) async { const Color dialogThemeColor = Colors.green, iconThemeColor = Colors.yellow; final ThemeData theme = ThemeData( iconTheme: const IconThemeData(color: iconThemeColor), @@ -295,7 +296,7 @@ void main() { expect(text.text.style!.color, dialogThemeColor); }); - testWidgets('Material3 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); const AlertDialog dialog = AlertDialog( icon: Icon(Icons.ac_unit), @@ -311,7 +312,7 @@ void main() { expect(text.text.style!.color, theme.colorScheme.secondary); }); - testWidgets('Material2 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async { const Color iconThemeColor = Colors.yellow; final ThemeData theme = ThemeData(useMaterial3: false, iconTheme: const IconThemeData(color: iconThemeColor)); const AlertDialog dialog = AlertDialog( @@ -328,7 +329,7 @@ void main() { expect(text.text.style!.color, iconThemeColor); }); - testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( @@ -345,7 +346,7 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Custom Title Text Style - Dialog Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Title Text Style - Dialog Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( @@ -362,7 +363,7 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Material3 - Custom Title Text Style - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog(title: Text(titleText)); @@ -376,7 +377,7 @@ void main() { expect(title.text.style!.color, titleTextStyle.color); }); - testWidgets('Material2 - Custom Title Text Style - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog(title: Text(titleText)); @@ -390,7 +391,7 @@ void main() { expect(title.text.style!.color, titleTextStyle.color); }); - testWidgets('Simple Dialog - Custom Title Text Style - Constructor Param', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simple Dialog - Custom Title Text Style - Constructor Param', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const SimpleDialog dialog = SimpleDialog( @@ -406,7 +407,7 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Simple Dialog - Custom Title Text Style - Dialog Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simple Dialog - Custom Title Text Style - Dialog Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const SimpleDialog dialog = SimpleDialog( @@ -422,7 +423,7 @@ void main() { expect(title.text.style, titleTextStyle); }); - testWidgets('Simple Dialog - Custom Title Text Style - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simple Dialog - Custom Title Text Style - Theme', (WidgetTester tester) async { const String titleText = 'Title'; const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const SimpleDialog dialog = SimpleDialog( @@ -438,7 +439,7 @@ void main() { expect(title.text.style!.color, titleTextStyle.color); }); - testWidgets('Custom Content Text Style - Constructor Param', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Content Text Style - Constructor Param', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( @@ -455,7 +456,7 @@ void main() { expect(content.text.style, contentTextStyle); }); - testWidgets('Custom Content Text Style - Dialog Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom Content Text Style - Dialog Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog( @@ -472,7 +473,7 @@ void main() { expect(content.text.style, contentTextStyle); }); - testWidgets('Material3 - Custom Content Text Style - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Custom Content Text Style - Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog(content: Text(contentText),); @@ -486,7 +487,7 @@ void main() { expect(content.text.style!.color, contentTextStyle.color); }); - testWidgets('Material2 - Custom Content Text Style - Theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Custom Content Text Style - Theme', (WidgetTester tester) async { const String contentText = 'Content'; const TextStyle contentTextStyle = TextStyle(color: Colors.pink); const AlertDialog dialog = AlertDialog(content: Text(contentText)); diff --git a/packages/flutter/test/material/drawer_button_test.dart b/packages/flutter/test/material/drawer_button_test.dart index 4e42ba7dcd993..f65557d8c27d4 100644 --- a/packages/flutter/test/material/drawer_button_test.dart +++ b/packages/flutter/test/material/drawer_button_test.dart @@ -8,7 +8,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('DrawerButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -170,7 +170,7 @@ void main() { handle.dispose(); }, variant: TargetPlatformVariant.all()); - testWidgets('EndDrawerButton control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EndDrawerButton control test', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/drawer_test.dart b/packages/flutter/test/material/drawer_test.dart index faf3c2522bb09..e4d0475bbdea3 100644 --- a/packages/flutter/test/material/drawer_test.dart +++ b/packages/flutter/test/material/drawer_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('Drawer control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer control test', (WidgetTester tester) async { const Key containerKey = Key('container'); await tester.pumpWidget( @@ -57,7 +58,7 @@ void main() { expect(find.text('header'), findsOneWidget); }); - testWidgets('Drawer dismiss barrier has label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer dismiss barrier has label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( const MaterialApp( @@ -81,7 +82,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Drawer dismiss barrier has no label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer dismiss barrier has no label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( const MaterialApp( @@ -105,7 +106,7 @@ void main() { semantics.dispose(); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Scaffold drawerScrimColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold drawerScrimColor', (WidgetTester tester) async { // The scrim is a Container within a Semantics node labeled "Dismiss", // within a DrawerController. Sorry. Container getScrim() { @@ -167,7 +168,7 @@ void main() { expect(find.byType(Drawer), findsNothing); }); - testWidgets('Open/close drawers by flinging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Open/close drawers by flinging', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -381,7 +382,7 @@ void main() { expect(find.text('endDrawer'), findsOneWidget); }); - testWidgets('ScaffoldState close drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldState close drawer', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -404,7 +405,7 @@ void main() { expect(find.text('Drawer'), findsNothing); }); - testWidgets('ScaffoldState close drawer do not crash if drawer is already closed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldState close drawer do not crash if drawer is already closed', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -423,7 +424,7 @@ void main() { expect(find.text('Drawer'), findsNothing); }); - testWidgets('Disposing drawer does not crash if drawer is open and framework is locked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing drawer does not crash if drawer is open and framework is locked', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/34978 addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1800.0, 2400.0); @@ -464,7 +465,7 @@ void main() { expect(find.byType(BackButton), findsNothing); }); - testWidgets('Disposing endDrawer does not crash if endDrawer is open and framework is locked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing endDrawer does not crash if endDrawer is open and framework is locked', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/34978 addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1800.0, 2400.0); @@ -505,7 +506,7 @@ void main() { expect(find.byType(BackButton), findsNothing); }); - testWidgets('ScaffoldState close end drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldState close end drawer', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -528,7 +529,7 @@ void main() { expect(find.text('endDrawer'), findsNothing); }); - testWidgets('Drawer width defaults to Material spec', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer width defaults to Material spec', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -547,7 +548,7 @@ void main() { expect(box.size.width, equals(304.0)); }); - testWidgets('Drawer width can be customized by parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer width can be customized by parameter', (WidgetTester tester) async { const double smallWidth = 200; await tester.pumpWidget( @@ -569,7 +570,7 @@ void main() { expect(box.size.width, equals(smallWidth)); }); - testWidgets('Drawer default shape (ltr)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer default shape (ltr)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -629,7 +630,7 @@ void main() { ); }); - testWidgets('Drawer default shape (rtl)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer default shape (rtl)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -689,7 +690,7 @@ void main() { ); }); - testWidgets('Drawer clip behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer clip behavior', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -745,7 +746,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Drawer default shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer default shape', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -786,7 +787,7 @@ void main() { expect(material.shape, null); }); - testWidgets('Drawer clip behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer clip behavior', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/drawer_theme_test.dart b/packages/flutter/test/material/drawer_theme_test.dart index c7a24d2d48337..80aaccf5d85ba 100644 --- a/packages/flutter/test/material/drawer_theme_test.dart +++ b/packages/flutter/test/material/drawer_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('copyWith, ==, hashCode basics', () { @@ -18,7 +19,7 @@ void main() { expect(identical(DrawerThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DrawerThemeData().debugFillProperties(builder); @@ -30,7 +31,7 @@ void main() { expect(description, []); }); - testWidgets('Custom debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const DrawerThemeData( backgroundColor: Color(0x00000099), @@ -58,7 +59,7 @@ void main() { ]); }); - testWidgets('Material2 - Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( @@ -82,7 +83,7 @@ void main() { expect(_drawerRenderBox(tester).size.width, 304.0); }); - testWidgets('Material3 - Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -109,7 +110,7 @@ void main() { expect(_drawerRenderBox(tester).size.width, 304.0); }); - testWidgets('Material2 - Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: false); await tester.pumpWidget( @@ -133,7 +134,7 @@ void main() { expect(_drawerRenderBox(tester).size.width, 304.0); }); - testWidgets('Material3 - Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default values are used when no Drawer or DrawerThemeData properties are specified in end drawer', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -160,7 +161,7 @@ void main() { expect(_drawerRenderBox(tester).size.width, 304.0); }); - testWidgets('DrawerThemeData values are used when no Drawer properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerThemeData values are used when no Drawer properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0x00000001); const Color scrimColor = Color(0x00000002); const double elevation = 7.0; @@ -201,7 +202,7 @@ void main() { expect(_drawerRenderBox(tester).size.width, width); }); - testWidgets('Drawer values take priority over DrawerThemeData values when both properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer values take priority over DrawerThemeData values when both properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0x00000001); const Color scrimColor = Color(0x00000002); const double elevation = 7.0; @@ -248,7 +249,7 @@ void main() { expect(_drawerRenderBox(tester).size.width, width); }); - testWidgets('DrawerTheme values take priority over ThemeData.drawerTheme values when both properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrawerTheme values take priority over ThemeData.drawerTheme values when both properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0x00000001); const Color scrimColor = Color(0x00000002); const double elevation = 7.0; diff --git a/packages/flutter/test/material/expansion_panel_test.dart b/packages/flutter/test/material/expansion_panel_test.dart index c60cd9a0cc1d8..cfef2a5344fea 100644 --- a/packages/flutter/test/material/expansion_panel_test.dart +++ b/packages/flutter/test/material/expansion_panel_test.dart @@ -875,7 +875,7 @@ void main() { }, ); - testWidgets('No duplicate global keys at layout/build time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No duplicate global keys at layout/build time', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/13780 await tester.pumpWidget( StatefulBuilder( @@ -1586,7 +1586,7 @@ void main() { expect(expandIcon.color, expandIconColor); }); - testWidgets('elevation is propagated properly to MergeableMaterial', (WidgetTester tester) async { + testWidgetsWithLeakTracking('elevation is propagated properly to MergeableMaterial', (WidgetTester tester) async { const double elevation = 8; // Test for ExpansionPanelList. diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index 2940dac61076e..0b2062a7fab58 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -11,7 +11,7 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('FilledButton, FilledButton.icon defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton, FilledButton.icon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); final ThemeData theme = ThemeData.from(useMaterial3: false, colorScheme: colorScheme); @@ -124,7 +124,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('FilledButton.tonal, FilledButton.tonalIcon defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.tonal, FilledButton.tonalIcon defaults', (WidgetTester tester) async { const ColorScheme colorScheme = ColorScheme.light(); final ThemeData theme = ThemeData.from(colorScheme: colorScheme); @@ -239,6 +239,7 @@ void main() { testWidgets('Default FilledButton meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( @@ -1845,6 +1846,7 @@ void main() { count += 1; } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); controller.addListener(valueChanged); await tester.pumpWidget( @@ -1945,20 +1947,21 @@ void main() { await gesture.removePointer(); } - testWidgets('FilledButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('FilledButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled FilledButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled FilledButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); controller.addListener(valueChanged); await tester.pumpWidget( MaterialApp( @@ -1973,7 +1976,9 @@ void main() { ); expect(controller.value, {MaterialState.disabled}); expect(count, 1); - }); + }, + leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed(), + ); } diff --git a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart index f66f471b56196..c5ce2842a6643 100644 --- a/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_collapse_mode_test.dart @@ -50,7 +50,7 @@ void main() { expect(topAfterScroll.dy, equals(0.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgets('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode pin', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), @@ -88,7 +88,7 @@ void main() { expect(topAfterScroll.dy, equals(-100.0)); }, variant: TargetPlatformVariant.all(excluding: { TargetPlatform.fuchsia })); - testWidgets('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar collapse mode parallax', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: debugDefaultTargetPlatformOverride), diff --git a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart index f515061f0c3e4..1b047096e7aac 100644 --- a/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart +++ b/packages/flutter/test/material/flexible_space_bar_stretch_mode_test.dart @@ -91,7 +91,7 @@ void main() { ); }); - testWidgets('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode fadeTitle', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -135,7 +135,7 @@ void main() { expect(opacityWidget.opacity, equals(0.0)); }); - testWidgets('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FlexibleSpaceBar stretch mode ignored for non-overscroll physics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 02c6ad08d4270..949a2b1295ed2 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -121,7 +121,7 @@ void main() { focusNode.dispose(); }); - testWidgets('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when null, iconSize is overridden by closest IconTheme', (WidgetTester tester) async { RenderBox icon; final bool material3 = theme.useMaterial3; @@ -331,7 +331,7 @@ void main() { expect(box.size, const Size(80.0, 80.0)); }); - testWidgets('test default icon buttons can be stretched if specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test default icon buttons can be stretched if specified', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -407,7 +407,7 @@ void main() { expect(align.alignment, Alignment.center); }); - testWidgets('test tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test tooltip', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: theme, @@ -2588,7 +2588,7 @@ void main() { }); group('IconTheme tests in Material 3', () { - testWidgets('IconTheme overrides default values in M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme overrides default values in M3', (WidgetTester tester) async { // Theme's IconTheme await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/inherited_theme_test.dart b/packages/flutter/test/material/inherited_theme_test.dart index 6f58948a794f5..40ace7382aa50 100644 --- a/packages/flutter/test/material/inherited_theme_test.dart +++ b/packages/flutter/test/material/inherited_theme_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Theme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme.wrap()', (WidgetTester tester) async { const Color primaryColor = Color(0xFF00FF00); final Key primaryContainerKey = UniqueKey(); @@ -91,7 +92,7 @@ void main() { expect(containerColor(), isNot(primaryColor)); }); - testWidgets('PopupMenuTheme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuTheme.wrap()', (WidgetTester tester) async { const double menuFontSize = 24; const Color menuTextColor = Color(0xFF0000FF); @@ -145,7 +146,7 @@ void main() { await tester.pumpAndSettle(); // menu route animation }); - testWidgets('BannerTheme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BannerTheme.wrap()', (WidgetTester tester) async { const Color bannerBackgroundColor = Color(0xFF0000FF); const double bannerFontSize = 48; const Color bannerTextColor = Color(0xFF00FF00); @@ -243,7 +244,7 @@ void main() { expect(getTextStyle('hello').color, isNot(bannerTextColor)); }); - testWidgets('DividerTheme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DividerTheme.wrap()', (WidgetTester tester) async { const Color dividerColor = Color(0xFF0000FF); const double dividerSpace = 13; const double dividerThickness = 7; @@ -325,7 +326,7 @@ void main() { expect(dividerBorder().width, isNot(dividerThickness)); }); - testWidgets('ListTileTheme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTileTheme.wrap()', (WidgetTester tester) async { const Color tileSelectedColor = Color(0xFF00FF00); const Color tileIconColor = Color(0xFF0000FF); const Color tileTextColor = Color(0xFFFF0000); @@ -436,7 +437,7 @@ void main() { expect(getIconStyle(unselectedIconKey).color, isNot(tileIconColor)); }); - testWidgets('SliderTheme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderTheme.wrap()', (WidgetTester tester) async { const Color activeTrackColor = Color(0xFF00FF00); const Color inactiveTrackColor = Color(0xFF0000FF); const Color thumbColor = Color(0xFFFF0000); @@ -519,7 +520,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: thumbColor))); }); - testWidgets('ToggleButtonsTheme.wrap()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ToggleButtonsTheme.wrap()', (WidgetTester tester) async { const Color buttonColor = Color(0xFF00FF00); const Color selectedButtonColor = Color(0xFFFF0000); diff --git a/packages/flutter/test/material/ink_paint_test.dart b/packages/flutter/test/material/ink_paint_test.dart index 082e1a42efd32..14b0b500fe9f6 100644 --- a/packages/flutter/test/material/ink_paint_test.dart +++ b/packages/flutter/test/material/ink_paint_test.dart @@ -270,12 +270,13 @@ void main() { await gesture.up(); }); - testWidgets('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget renders an SelectAction or ActivateAction-induced ink ripple', (WidgetTester tester) async { const Color highlightColor = Color(0xAAFF0000); const Color splashColor = Color(0xB40000FF); const BorderRadius borderRadius = BorderRadius.all(Radius.circular(6.0)); final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); Future buildTest(Intent intent) async { return tester.pumpWidget( Shortcuts( @@ -453,9 +454,13 @@ void main() { })); }); - testWidgets('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The InkWell widget on OverlayPortal does not throw', (WidgetTester tester) async { final OverlayPortalController controller = OverlayPortalController(); controller.show(); + + late OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Center( child: RepaintBoundary( @@ -465,7 +470,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return Center( child: SizedBox.square( diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index 0fe244a3c4f4d..b0f2a59d9e9ed 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -2086,7 +2086,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(inkFeatures, paintsExactlyCountTimes(#drawCircle, 0)); }); - testWidgets('InkWell disposes statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkWell disposes statesController', (WidgetTester tester) async { int tapCount = 0; Widget buildFrame(MaterialStatesController? statesController) { return MaterialApp( @@ -2103,6 +2103,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); int pressedCount = 0; controller.addListener(() { if (controller.value.contains(MaterialState.pressed)) { diff --git a/packages/flutter/test/material/input_date_picker_form_field_test.dart b/packages/flutter/test/material/input_date_picker_form_field_test.dart index 076b3978f41a0..4e09c8f7da0f2 100644 --- a/packages/flutter/test/material/input_date_picker_form_field_test.dart +++ b/packages/flutter/test/material/input_date_picker_form_field_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; @@ -97,7 +98,7 @@ void main() { group('InputDatePickerFormField', () { - testWidgets('Initial date is the default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); final DateTime initialDate = DateTime(2016, DateTime.february, 21); DateTime? inputDate; @@ -111,7 +112,7 @@ void main() { expect(inputDate, equals(initialDate)); }); - testWidgets('Changing initial date is reflected in text value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing initial date is reflected in text value', (WidgetTester tester) async { final DateTime initialDate = DateTime(2016, DateTime.february, 21); final DateTime updatedInitialDate = DateTime(2016, DateTime.february, 23); await tester.pumpWidget(inputDatePickerField( @@ -126,7 +127,7 @@ void main() { expect(textFieldController(tester).value.text, equals('02/23/2016')); }); - testWidgets('Valid date entry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Valid date entry', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -139,7 +140,7 @@ void main() { expect(inputDate, equals(DateTime(2016, DateTime.february, 21))); }); - testWidgets('Invalid text entry shows errorFormat text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Invalid text entry shows errorFormat text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -166,7 +167,7 @@ void main() { expect(find.text('That is not a date.'), findsOneWidget); }); - testWidgets('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Valid text entry, but date outside first or last date shows bounds shows errorInvalid text', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -201,7 +202,7 @@ void main() { expect(find.text('Not in given range.'), findsOneWidget); }); - testWidgets('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectableDatePredicate will be used to show errorInvalid if date is not selectable', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); DateTime? inputDate; await tester.pumpWidget(inputDatePickerField( @@ -227,7 +228,7 @@ void main() { expect(find.text('Out of range.'), findsNothing); }); - testWidgets('Empty field shows hint text when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty field shows hint text when focused', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Focus on it await tester.tap(find.byType(TextField)); @@ -250,7 +251,7 @@ void main() { expect(textOpacity(tester, 'Enter some date'), equals(0.0)); }); - testWidgets('Label text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Label text', (WidgetTester tester) async { await tester.pumpWidget(inputDatePickerField()); // Default label expect(find.text('Enter Date'), findsOneWidget); @@ -262,7 +263,7 @@ void main() { expect(find.text('Give me a date!'), findsOneWidget); }); - testWidgets('Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); // Fill the clipboard so that the Paste option is available in the text @@ -291,7 +292,7 @@ void main() { semantics.dispose(); }); - testWidgets('InputDecorationTheme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme is honored', (WidgetTester tester) async { const InputBorder border = InputBorder.none; await tester.pumpWidget(inputDatePickerField( theme: ThemeData.from(colorScheme: const ColorScheme.light()).copyWith( @@ -325,7 +326,7 @@ void main() { expect(containerColor, equals(Colors.transparent)); }); - testWidgets('Date text localization', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Date text localization', (WidgetTester tester) async { final Iterable> delegates = >[ TestMaterialLocalizationsDelegate(), DefaultWidgetsLocalizations.delegate, @@ -348,7 +349,7 @@ void main() { ); }); - testWidgets('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is true, then errorFormatText is not shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( @@ -363,7 +364,7 @@ void main() { expect(find.text(errorFormatText), findsNothing); }); - testWidgets('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when an empty date is entered and acceptEmptyDate is false, then errorFormatText is shown', (WidgetTester tester) async { final GlobalKey formKey = GlobalKey(); const String errorFormatText = 'That is not a date.'; await tester.pumpWidget(inputDatePickerField( diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index b750c7a4f8438..27e57c2707403 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -14,6 +14,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Widget buildInputDecorator({ InputDecoration decoration = const InputDecoration(), @@ -161,7 +162,7 @@ void main() { } void runAllTests({ required bool useMaterial3 }) { - testWidgets('InputDecorator input/label text layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator input/label text layout', (WidgetTester tester) async { // The label appears above the input text await tester.pumpWidget( buildInputDecorator( @@ -389,7 +390,7 @@ void runAllTests({ required bool useMaterial3 }) { } }); - testWidgets('InputDecorator input/label widget layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator input/label widget layout', (WidgetTester tester) async { const Key key = Key('l'); // The label appears above the input text. @@ -733,7 +734,7 @@ void runAllTests({ required bool useMaterial3 }) { }); - testWidgets('InputDecorator floating label animation duration and curve', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator floating label animation duration and curve', (WidgetTester tester) async { Future pumpInputDecorator({ required bool isFocused, }) async { @@ -784,10 +785,12 @@ void runAllTests({ required bool useMaterial3 }) { group('alignLabelWithHint', () { group('expands false', () { - testWidgets('multiline TextField no-strut', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiline TextField no-strut', (WidgetTester tester) async { const String text = 'text'; final FocusNode focusNode = FocusNode(); final TextEditingController controller = TextEditingController(); + addTearDown(() { focusNode.dispose(); controller.dispose();}); + Widget buildFrame(bool alignLabelWithHint) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -835,10 +838,11 @@ void runAllTests({ required bool useMaterial3 }) { focusNode.unfocus(); }); - testWidgets('multiline TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiline TextField', (WidgetTester tester) async { const String text = 'text'; final FocusNode focusNode = FocusNode(); final TextEditingController controller = TextEditingController(); + addTearDown(() { focusNode.dispose(); controller.dispose();}); Widget buildFrame(bool alignLabelWithHint) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -887,10 +891,13 @@ void runAllTests({ required bool useMaterial3 }) { }); group('expands true', () { - testWidgets('multiline TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiline TextField', (WidgetTester tester) async { const String text = 'text'; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); + Widget buildFrame(bool alignLabelWithHint) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -939,10 +946,13 @@ void runAllTests({ required bool useMaterial3 }) { focusNode.unfocus(); }); - testWidgets('multiline TextField with outline border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiline TextField with outline border', (WidgetTester tester) async { const String text = 'text'; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); + Widget buildFrame(bool alignLabelWithHint) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1001,7 +1011,7 @@ void runAllTests({ required bool useMaterial3 }) { // 12 - top padding // 16 - input text (font size 16dps) // 12 - bottom padding - testWidgets('InputDecorator input/hint layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator input/hint layout', (WidgetTester tester) async { // The hint aligns with the input text await tester.pumpWidget( buildInputDecorator( @@ -1025,7 +1035,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getSize(find.text('hint')).width, tester.getSize(find.text('text')).width); }); - testWidgets('InputDecorator input/label/hint layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator input/label/hint layout', (WidgetTester tester) async { // Label is visible, hint is not (opacity 0.0). await tester.pumpWidget( buildInputDecorator( @@ -1136,7 +1146,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); - testWidgets('InputDecorator input/label/hint dense layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator input/label/hint dense layout', (WidgetTester tester) async { // Label is visible, hint is not (opacity 0.0). await tester.pumpWidget( buildInputDecorator( @@ -1200,7 +1210,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); - testWidgets('InputDecorator with no input border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator with no input border', (WidgetTester tester) async { // Label is visible, hint is not (opacity 0.0). await tester.pumpWidget( buildInputDecorator( @@ -1215,7 +1225,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 0.0); }); - testWidgets('InputDecorator error/helper/counter layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator error/helper/counter layout', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -1367,7 +1377,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('counter')), const Offset(788.0, 56.0)); }); - testWidgets('InputDecorator counter text, widget, and null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator counter text, widget, and null', (WidgetTester tester) async { Widget buildFrame({ InputCounterWidgetBuilder? buildCounter, String? counterText, @@ -1469,7 +1479,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(find.byKey(buildCounterKey), findsOneWidget); }); - testWidgets('InputDecoration errorMaxLines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration errorMaxLines', (WidgetTester tester) async { const String kError1 = 'e0'; const String kError2 = 'e0\ne1'; const String kError3 = 'e0\ne1\ne2'; @@ -1548,7 +1558,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getBottomLeft(find.text(kError1)), const Offset(12.0, 76.0)); }); - testWidgets('InputDecoration helperMaxLines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration helperMaxLines', (WidgetTester tester) async { const String kHelper1 = 'e0'; const String kHelper2 = 'e0\ne1'; const String kHelper3 = 'e0\ne1\ne2'; @@ -1645,7 +1655,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getBottomLeft(find.text(kHelper1)), const Offset(12.0, 76.0)); }); - testWidgets('InputDecorator shows error text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator shows error text', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -1658,7 +1668,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(find.text('errorText'), findsOneWidget); }); - testWidgets('InputDecorator shows error widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator shows error widget', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -1671,7 +1681,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(find.text('error'), findsOneWidget); }); - testWidgets('InputDecorator throws when error text and error widget are provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator throws when error text and error widget are provided', (WidgetTester tester) async { expect( () { buildInputDecorator( @@ -1686,7 +1696,7 @@ void runAllTests({ required bool useMaterial3 }) { ); }); - testWidgets('InputDecorator prefix/suffix texts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator prefix/suffix texts', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -1724,7 +1734,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('s')).dx)); }); - testWidgets('InputDecorator icon/prefix/suffix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator icon/prefix/suffix', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -1764,7 +1774,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('s')).dx)); }); - testWidgets('InputDecorator iconColor/prefixIconColor/suffixIconColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator iconColor/prefixIconColor/suffixIconColor', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -1788,7 +1798,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.widget(find.widgetWithIcon(IconTheme,Icons.close).first).data.color, Colors.red); }); - testWidgets('InputDecorator suffixIconColor in M3 error state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator suffixIconColor in M3 error state', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: true, iconButtonTheme: const IconButtonThemeData( @@ -1815,8 +1825,9 @@ void runAllTests({ required bool useMaterial3 }) { expect(getIconStyle(tester, Icons.close)?.color, theme.colorScheme.error); }); - testWidgets('InputDecoration default floatingLabelStyle resolves hovered/focused states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration default floatingLabelStyle resolves hovered/focused states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -1849,7 +1860,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getLabelStyle(tester).color, theme.colorScheme.onSurfaceVariant); }); - testWidgets('InputDecorator prefix/suffix widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator prefix/suffix widgets', (WidgetTester tester) async { const Key pKey = Key('p'); const Key sKey = Key('s'); await tester.pumpWidget( @@ -1901,7 +1912,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopRight(find.byKey(sKey)).dx)); }); - testWidgets('InputDecorator tall prefix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix', (WidgetTester tester) async { const Key pKey = Key('p'); await tester.pumpWidget( buildInputDecorator( @@ -1946,7 +1957,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.byKey(pKey)).dx, tester.getTopLeft(find.text('text')).dx); }); - testWidgets('InputDecorator tall prefix with border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix with border', (WidgetTester tester) async { const Key pKey = Key('p'); await tester.pumpWidget( buildInputDecorator( @@ -1997,7 +2008,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.byKey(pKey)).dx, tester.getTopLeft(find.text('text')).dx); }); - testWidgets('InputDecorator prefixIcon/suffixIcon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator prefixIcon/suffixIcon', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2033,7 +2044,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.byIcon(Icons.satellite)).dx)); }); - testWidgets('InputDecorator prefixIconConstraints/suffixIconConstraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator prefixIconConstraints/suffixIconConstraints', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2071,7 +2082,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.byIcon(Icons.satellite)).dx, 800.0); }); - testWidgets('prefix/suffix icons are centered when smaller than 48 by 48', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prefix/suffix icons are centered when smaller than 48 by 48', (WidgetTester tester) async { const Key prefixKey = Key('prefix'); await tester.pumpWidget( buildInputDecorator( @@ -2097,7 +2108,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.byKey(prefixKey)).dy, 16.0); }); - testWidgets('InputDecorator respects reduced theme visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator respects reduced theme visualDensity', (WidgetTester tester) async { // Label is visible, hint is not (opacity 0.0). await tester.pumpWidget( buildInputDecorator( @@ -2194,7 +2205,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); - testWidgets('InputDecorator respects increased theme visualDensity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator respects increased theme visualDensity', (WidgetTester tester) async { // Label is visible, hint is not (opacity 0.0). await tester.pumpWidget( buildInputDecorator( @@ -2291,7 +2302,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); - testWidgets('prefix/suffix icons increase height of decoration when larger than 48 by 48', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prefix/suffix icons increase height of decoration when larger than 48 by 48', (WidgetTester tester) async { const Key prefixKey = Key('prefix'); await tester.pumpWidget( buildInputDecorator( @@ -2315,7 +2326,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('constraints', () { - testWidgets('No InputDecorator constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No InputDecorator constraints', (WidgetTester tester) async { await tester.pumpWidget(buildInputDecorator( useMaterial3: useMaterial3, )); @@ -2324,7 +2335,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getSize(find.byType(InputDecorator)), const Size(800, 48)); }); - testWidgets('InputDecoratorThemeData constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoratorThemeData constraints', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2340,7 +2351,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getSize(find.byType(InputDecorator)), const Size(300, 40)); }); - testWidgets('InputDecorator constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator constraints', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2363,7 +2374,7 @@ void runAllTests({ required bool useMaterial3 }) { group('textAlignVertical position', () { group('simple case', () { - testWidgets('align top (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align top (default)', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2387,7 +2398,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 12.0); }); - testWidgets('align center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align center', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2411,7 +2422,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 290.0); }); - testWidgets('align bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align bottom', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2435,7 +2446,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 568.0); }); - testWidgets('align as a double', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align as a double', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2459,7 +2470,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 498.5); }); - testWidgets('works with density and content padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with density and content padding', (WidgetTester tester) async { const Key key = Key('child'); const Key containerKey = Key('container'); const double totalHeight = 100.0; @@ -2509,7 +2520,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('outline border', () { - testWidgets('align top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align top', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2535,7 +2546,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 24.0); }); - testWidgets('align center (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align center (default)', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2560,7 +2571,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 289.0); }); - testWidgets('align bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align bottom', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2587,7 +2598,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('prefix', () { - testWidgets('InputDecorator tall prefix align top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix align top', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2617,7 +2628,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.byKey(pKey)).dy, 12.0); }); - testWidgets('InputDecorator tall prefix align center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix align center', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2647,7 +2658,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.byKey(pKey)).dy, 12.0); }); - testWidgets('InputDecorator tall prefix align bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix align bottom', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2679,7 +2690,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('outline border and prefix', () { - testWidgets('InputDecorator tall prefix align center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix align center', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2711,7 +2722,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.byKey(pKey)).dy, 246.5); }); - testWidgets('InputDecorator tall prefix with border align top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix with border align top', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2745,7 +2756,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.byKey(pKey)).dy, 24.0); }); - testWidgets('InputDecorator tall prefix with border align bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix with border align bottom', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2777,7 +2788,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.byKey(pKey)).dy, 479.0); }); - testWidgets('InputDecorator tall prefix with border align double', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator tall prefix with border align double', (WidgetTester tester) async { const Key pKey = Key('p'); const String text = 'text'; await tester.pumpWidget( @@ -2811,7 +2822,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('label', () { - testWidgets('align top (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align top (default)', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2837,7 +2848,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 28.0); }); - testWidgets('align center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align center', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2863,7 +2874,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text(text)).dy, 298.0); }); - testWidgets('align bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('align bottom', (WidgetTester tester) async { const String text = 'text'; await tester.pumpWidget( buildInputDecorator( @@ -2893,7 +2904,7 @@ void runAllTests({ required bool useMaterial3 }) { group('OutlineInputBorder', () { group('default alignment', () { - testWidgets('Centers when border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Centers when border', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2910,7 +2921,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('Centers when border and label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Centers when border and label', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2928,7 +2939,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('Centers when border and contentPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Centers when border and contentPadding', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2949,7 +2960,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('Centers when border and contentPadding and label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Centers when border and contentPadding and label', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2970,7 +2981,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('Centers when border and lopsided contentPadding and label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Centers when border and lopsided contentPadding and label', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -2992,7 +3003,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('Floating label is aligned with prefixIcon by default in M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating label is aligned with prefixIcon by default in M3', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3011,7 +3022,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); - testWidgets('Floating label for filled input decoration is aligned with text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating label for filled input decoration is aligned with text', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3032,7 +3043,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('3 point interpolation alignment', () { - testWidgets('top align includes padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('top align includes padding', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3056,7 +3067,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('center align ignores padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center align ignores padding', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3080,7 +3091,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('bottom align includes padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bottom align includes padding', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3104,7 +3115,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('padding exceeds middle keeps top at middle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('padding exceeds middle keeps top at middle', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3130,7 +3141,7 @@ void runAllTests({ required bool useMaterial3 }) { }); }); - testWidgets('counter text has correct right margin - LTR, not dense', (WidgetTester tester) async { + testWidgetsWithLeakTracking('counter text has correct right margin - LTR, not dense', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3150,7 +3161,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getRect(find.text('test')).right, dx - 12.0); }); - testWidgets('counter text has correct right margin - RTL, not dense', (WidgetTester tester) async { + testWidgetsWithLeakTracking('counter text has correct right margin - RTL, not dense', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3170,7 +3181,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getRect(find.text('test')).left, 12.0); }); - testWidgets('counter text has correct right margin - LTR, dense', (WidgetTester tester) async { + testWidgetsWithLeakTracking('counter text has correct right margin - LTR, dense', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3191,7 +3202,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getRect(find.text('test')).right, dx - 12.0); }); - testWidgets('counter text has correct right margin - RTL, dense', (WidgetTester tester) async { + testWidgetsWithLeakTracking('counter text has correct right margin - RTL, dense', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3212,7 +3223,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getRect(find.text('test')).left, 12.0); }); - testWidgets('InputDecorator error/helper/counter RTL layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator error/helper/counter RTL layout', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3269,7 +3280,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(find.text('helper'), findsNothing); }); - testWidgets('InputDecorator prefix/suffix RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator prefix/suffix RTL', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3303,7 +3314,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('text')).dx, lessThanOrEqualTo(tester.getTopLeft(find.text('p')).dx)); }); - testWidgets('InputDecorator contentPadding RTL layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator contentPadding RTL layout', (WidgetTester tester) async { // LTR: content left edge is contentPadding.start: 40.0 await tester.pumpWidget( buildInputDecorator( @@ -3344,13 +3355,13 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('hint')).dx, 760.0); }); - testWidgets('FloatingLabelAlignment.toString()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingLabelAlignment.toString()', (WidgetTester tester) async { expect(FloatingLabelAlignment.start.toString(), 'FloatingLabelAlignment.start'); expect(FloatingLabelAlignment.center.toString(), 'FloatingLabelAlignment.center'); }); group('inputText width', () { - testWidgets('outline textField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('outline textField', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3363,7 +3374,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text('text')).dx, 12.0); expect(tester.getTopRight(find.text('text')).dx, 788.0); }); - testWidgets('outline textField with prefix and suffix icons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('outline textField with prefix and suffix icons', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3378,7 +3389,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text('text')).dx, 48.0); expect(tester.getTopRight(find.text('text')).dx, 752.0); }); - testWidgets('filled textField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('filled textField', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3391,7 +3402,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text('text')).dx, 12.0); expect(tester.getTopRight(find.text('text')).dx, 788.0); }); - testWidgets('filled textField with prefix and suffix icons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('filled textField with prefix and suffix icons', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3430,7 +3441,7 @@ void runAllTests({ required bool useMaterial3 }) { ); group('LTR with icon aligned', () { - testWidgets('start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('start', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.ltr, @@ -3454,7 +3465,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text('label')).dx, 80.0); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.ltr, @@ -3480,7 +3491,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('LTR without icon aligned', () { - testWidgets('start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('start', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.ltr, @@ -3504,7 +3515,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text('label')).dx, 40.0); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.ltr, @@ -3530,7 +3541,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('RTL with icon aligned', () { - testWidgets('start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('start', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.rtl, @@ -3554,7 +3565,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('label')).dx, 720.0); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.rtl, @@ -3580,7 +3591,7 @@ void runAllTests({ required bool useMaterial3 }) { }); group('RTL without icon aligned', () { - testWidgets('start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('start', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.rtl, @@ -3604,7 +3615,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('label')).dx, 760.0); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecoratorWithFloatingLabel( textDirection: TextDirection.rtl, @@ -3630,7 +3641,7 @@ void runAllTests({ required bool useMaterial3 }) { }); }); - testWidgets('InputDecorator prefix/suffix dense layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator prefix/suffix dense layout', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3672,7 +3683,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); - testWidgets('InputDecorator with empty InputDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator with empty InputDecoration', (WidgetTester tester) async { await tester.pumpWidget(buildInputDecorator( useMaterial3: useMaterial3, )); @@ -3689,7 +3700,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('contentPadding smaller than kMinInteractiveDimension', (WidgetTester tester) async { + testWidgetsWithLeakTracking('contentPadding smaller than kMinInteractiveDimension', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/42449 const double verticalPadding = 1.0; await tester.pumpWidget( @@ -3765,7 +3776,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 0.0); }); - testWidgets('InputDecorator.collapsed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator.collapsed', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3808,7 +3819,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 0.0); }); - testWidgets('InputDecorator with baseStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator with baseStyle', (WidgetTester tester) async { // Setting the baseStyle of the InputDecoration and the style of the input // text child to a smaller font reduces the InputDecoration's vertical size. const TextStyle style = TextStyle(fontSize: 10.0); @@ -3849,7 +3860,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopLeft(find.text('text')).dy, useMaterial3 ? 28 : 24.75); }); - testWidgets('InputDecorator with empty style overrides', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator with empty style overrides', (WidgetTester tester) async { // Same as not specifying any style overrides await tester.pumpWidget( buildInputDecorator( @@ -3892,7 +3903,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getTopRight(find.text('counter')), const Offset(788.0, 64.0)); }); - testWidgets('InputDecoration outline shape with no border and no floating placeholder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration outline shape with no border and no floating placeholder', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -3917,7 +3928,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 0.0); }); - testWidgets('InputDecoration outline shape with no border and no floating placeholder not empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration outline shape with no border and no floating placeholder not empty', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -4069,7 +4080,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(merged.constraints, overrideTheme.constraints); }); - testWidgets('InputDecorationTheme outline border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme outline border', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -4095,7 +4106,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('InputDecorationTheme outline border, dense layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme outline border, dense layout', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -4123,7 +4134,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 1.0); }); - testWidgets('InputDecorationTheme style overrides', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme style overrides', (WidgetTester tester) async { const TextStyle defaultStyle = TextStyle(fontSize: 16.0); final TextStyle labelStyle = defaultStyle.merge(const TextStyle(color: Colors.red)); final TextStyle hintStyle = defaultStyle.merge(const TextStyle(color: Colors.green)); @@ -4189,7 +4200,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getLabelStyle(tester).color, labelStyle.color); }); - testWidgets('InputDecorationTheme style overrides (focused)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme style overrides (focused)', (WidgetTester tester) async { const TextStyle defaultStyle = TextStyle(fontSize: 16.0); final TextStyle labelStyle = defaultStyle.merge(const TextStyle(color: Colors.red)); final TextStyle floatingLabelStyle = defaultStyle.merge(const TextStyle(color: Colors.indigo)); @@ -4257,7 +4268,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getLabelStyle(tester).color, floatingLabelStyle.color); }); - testWidgets('InputDecorator.toString()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator.toString()', (WidgetTester tester) async { const Widget child = InputDecorator( key: Key('key'), decoration: InputDecoration(), @@ -4271,7 +4282,7 @@ void runAllTests({ required bool useMaterial3 }) { ); }); - testWidgets('InputDecorator.debugDescribeChildren', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator.debugDescribeChildren', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -4313,7 +4324,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(nodeValues.length, 11); }); - testWidgets('InputDecorator with empty border and label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator with empty border and label', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/14165 await tester.pumpWidget( buildInputDecorator( @@ -4333,7 +4344,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(tester.getBottomLeft(find.text('label')).dy, 24.0); }); - testWidgets('InputDecorationTheme.inputDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme.inputDecoration', (WidgetTester tester) async { const TextStyle themeStyle = TextStyle(color: Color(0xFF00FFFF)); const Color themeColor = Color(0xFF00FF00); const InputBorder themeInputBorder = OutlineInputBorder( @@ -4510,7 +4521,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(decoration.constraints, const BoxConstraints(minWidth: 40, maxWidth: 50, minHeight: 60, maxHeight: 70)); }); - testWidgets('InputDecorationTheme.inputDecoration with MaterialState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme.inputDecoration with MaterialState', (WidgetTester tester) async { final MaterialStateTextStyle themeStyle = MaterialStateTextStyle.resolveWith((Set states) { return const TextStyle(color: Colors.green); }); @@ -4614,7 +4625,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(decoration.constraints, const BoxConstraints(minWidth: 10, maxWidth: 20, minHeight: 30, maxHeight: 40)); }); - testWidgets('InputDecorator OutlineInputBorder fillColor is clipped by border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator OutlineInputBorder fillColor is clipped by border', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/15742 await tester.pumpWidget( @@ -4655,7 +4666,7 @@ void runAllTests({ required bool useMaterial3 }) { )); }); - testWidgets('InputDecorator UnderlineInputBorder fillColor is clipped by border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator UnderlineInputBorder fillColor is clipped by border', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -4688,7 +4699,7 @@ void runAllTests({ required bool useMaterial3 }) { )); }); - testWidgets('InputDecorator constrained to 0x0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator constrained to 0x0', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17710 await tester.pumpWidget( Material( @@ -4708,7 +4719,7 @@ void runAllTests({ required bool useMaterial3 }) { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'InputDecorator OutlineBorder focused label with icon', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/82321 @@ -4756,7 +4767,7 @@ void runAllTests({ required bool useMaterial3 }) { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'InputDecorator OutlineBorder focused label with icon', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/18111 @@ -4802,7 +4813,7 @@ void runAllTests({ required bool useMaterial3 }) { }, ); - testWidgets('InputDecorator draws and animates hoverColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator draws and animates hoverColor', (WidgetTester tester) async { final Color fillColor = useMaterial3 ? const Color(0xffffffff) : const Color(0x0A000000); const Color hoverColor = Color(0xFF00FF00); final Color disabledColor =useMaterial3 ? const Color(0x0A000000) : const Color(0x05000000); @@ -4883,7 +4894,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderColor(tester), equals(disabledColor)); }); - testWidgets('InputDecorator draws and animates focusColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator draws and animates focusColor', (WidgetTester tester) async { const Color focusColor = Color(0xFF0000FF); const Color disabledColor = Color(0x05000000); final Color enabledBorderColor = useMaterial3 ? const Color(0xffffffff) : const Color(0x61000000); @@ -4937,7 +4948,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderColor(tester), equals(disabledColor)); }); - testWidgets('InputDecorator withdraws label when not empty or focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator withdraws label when not empty or focused', (WidgetTester tester) async { Future pumpDecorator({ required bool focused, bool enabled = true, @@ -5005,7 +5016,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getLabelRect(tester).size, equals(labelSize * 0.75)); }); - testWidgets('InputDecorationTheme.toString()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme.toString()', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/19305 expect( const InputDecorationTheme( @@ -5057,7 +5068,7 @@ void runAllTests({ required bool useMaterial3 }) { }); - testWidgets('InputDecoration default border uses colorScheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration default border uses colorScheme', (WidgetTester tester) async { final ThemeData theme = ThemeData.from(colorScheme: const ColorScheme.light()); final Color enabledColor = useMaterial3 ? theme.colorScheme.onSurfaceVariant : theme.colorScheme.onSurface.withOpacity(0.38); final Color disabledColor = useMaterial3 ? theme.colorScheme.onSurface.withOpacity(0.12) : theme.disabledColor; @@ -5149,7 +5160,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderColor(tester), useMaterial3 ? theme.colorScheme.onSurface.withOpacity(0.38) : Colors.transparent); }); - testWidgets('InputDecoration borders', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration borders', (WidgetTester tester) async { const InputBorder errorBorder = OutlineInputBorder( borderSide: BorderSide(color: Colors.red, width: 1.5), ); @@ -5291,7 +5302,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorder(tester), disabledBorder); }); - testWidgets('OutlineInputBorder borders scale down to fit when large values are passed in', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlineInputBorder borders scale down to fit when large values are passed in', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/34327 const double largerBorderRadius = 200.0; const double smallerBorderRadius = 100.0; @@ -5396,7 +5407,7 @@ void runAllTests({ required bool useMaterial3 }) { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317 - testWidgets('rounded OutlineInputBorder with zero padding just wraps the label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('rounded OutlineInputBorder with zero padding just wraps the label', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/82321 const double borderRadius = 30.0; const String labelText = 'label text'; @@ -5489,7 +5500,7 @@ void runAllTests({ required bool useMaterial3 }) { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317 -testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular border', (WidgetTester tester) async { +testWidgetsWithLeakTracking('OutlineInputBorder with BorderRadius.zero should draw a rectangular border', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/78855 const String labelText = 'Flutter'; @@ -5553,7 +5564,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/55317 - testWidgets('OutlineInputBorder radius carries over when lerping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlineInputBorder radius carries over when lerping', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/23982 const Key key = Key('textField'); @@ -5591,7 +5602,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(getBorderRadius(tester), BorderRadius.zero); }); - testWidgets('OutlineInputBorder async lerp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlineInputBorder async lerp', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28724 final Completer completer = Completer(); @@ -5723,7 +5734,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular ).hashCode)); }); - testWidgets('InputDecorationTheme implements debugFillDescription', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme implements debugFillDescription', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const InputDecorationTheme( labelStyle: TextStyle(), @@ -5774,12 +5785,15 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular ]); }); - testWidgets('uses alphabetic baseline for CJK layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses alphabetic baseline for CJK layout', (WidgetTester tester) async { await tester.binding.setLocale('zh', 'CN'); final Typography typography = Typography.material2018(); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); + // The dense theme uses ideographic baselines Widget buildFrame(bool alignLabelWithHint) { return MaterialApp( @@ -5817,7 +5831,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.getBottomLeft(find.text('hint')).dy, isBrowser ? 45.75 : 47.75); }); - testWidgets('InputDecorator floating label Y coordinate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator floating label Y coordinate', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/54028 await tester.pumpWidget( buildInputDecorator( @@ -5840,7 +5854,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.getTopLeft(find.text('label')).dy, -4.0); }); - testWidgets('InputDecorator floating label obeys floatingLabelBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator floating label obeys floatingLabelBehavior', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -5857,7 +5871,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.getTopLeft(find.text('label')).dy, 20.0); }); - testWidgets('InputDecorator hint is displayed when floatingLabelBehavior is always', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator hint is displayed when floatingLabelBehavior is always', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( useMaterial3: useMaterial3, @@ -5875,7 +5889,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(getOpacity(tester, 'hint'), 1.0); }); - testWidgets('InputDecorator floating label width scales when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator floating label width scales when focused', (WidgetTester tester) async { final String longStringA = String.fromCharCodes(List.generate(200, (_) => 65)); final String longStringB = String.fromCharCodes(List.generate(200, (_) => 66)); @@ -5936,7 +5950,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular ); }, skip: isBrowser); // TODO(yjbanov): https://github.com/flutter/flutter/issues/44020 - testWidgets('textAlignVertical can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textAlignVertical can be updated', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/56933 const String hintText = 'hint'; TextAlignVertical? alignment = TextAlignVertical.top; @@ -5976,7 +5990,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.getTopLeft(find.text(hintText)).dy, topPosition); }); - testWidgets("InputDecorator label width isn't affected by prefix or suffix", (WidgetTester tester) async { + testWidgetsWithLeakTracking("InputDecorator label width isn't affected by prefix or suffix", (WidgetTester tester) async { const String labelText = 'My Label'; const String prefixText = 'The five boxing wizards jump quickly.'; const String suffixText = 'Suffix'; @@ -6037,7 +6051,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular }); // Related issue: https://github.com/flutter/flutter/issues/64427 - testWidgets('OutlineInputBorder and InputDecorator long labels and in Floating, the width should ignore the icon width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlineInputBorder and InputDecorator long labels and in Floating, the width should ignore the icon width', (WidgetTester tester) async { const String labelText = 'Flutter is Google’s UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase.'; Widget getLabeledInputDecorator(FloatingLabelBehavior floatingLabelBehavior) => MaterialApp( @@ -6088,7 +6102,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(getLabelRect(tester).width, floatedLabelWidth); }); - testWidgets('given enough space, constrained and unconstrained heights result in the same size widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('given enough space, constrained and unconstrained heights result in the same size widget', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/65572 final UniqueKey keyUnconstrained = UniqueKey(); final UniqueKey keyConstrained = UniqueKey(); @@ -6139,7 +6153,9 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(constrainedHeightCompact, equals(unConstrainedHeightCompact)); }); - testWidgets('A vertically constrained TextField still positions its text inside of itself', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A vertically constrained TextField still positions its text inside of itself', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'A'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -6147,7 +6163,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular width: 200, height: 28, child: TextField( - controller: TextEditingController(text: 'A'), + controller: controller, ), ), ), @@ -6164,7 +6180,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(textTop, lessThan(textFieldBottom)); }); - testWidgets('visual density is included in the intrinsic height calculation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visual density is included in the intrinsic height calculation', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); final UniqueKey intrinsicHeightKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -6204,7 +6220,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(intrinsicHeight, equals(height)); }); - testWidgets('error message for negative baseline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('error message for negative baseline', (WidgetTester tester) async { FlutterErrorDetails? errorDetails; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { @@ -6242,7 +6258,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(errorDetails?.toString(), contains('RenderStack')); }); - testWidgets('min intrinsic height for TextField with no content padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('min intrinsic height for TextField with no content padding', (WidgetTester tester) async { // Regression test for: https://github.com/flutter/flutter/issues/75509 await tester.pumpWidget(const MaterialApp( home: Material( @@ -6267,7 +6283,10 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.takeException(), isNull); }); - testWidgets('min intrinsic height for TextField with prefix icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('min intrinsic height for TextField with prefix icon', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'input'); + addTearDown(controller.dispose); + // Regression test for: https://github.com/flutter/flutter/issues/87403 await tester.pumpWidget(MaterialApp( home: Material( @@ -6278,7 +6297,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular child: Column( children: [ TextField( - controller: TextEditingController(text: 'input'), + controller: controller, maxLines: null, decoration: const InputDecoration( prefixIcon: Icon(Icons.search), @@ -6295,7 +6314,10 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.takeException(), isNull); }); - testWidgets('min intrinsic height for TextField with suffix icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('min intrinsic height for TextField with suffix icon', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'input'); + addTearDown(controller.dispose); + // Regression test for: https://github.com/flutter/flutter/issues/87403 await tester.pumpWidget(MaterialApp( home: Material( @@ -6306,7 +6328,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular child: Column( children: [ TextField( - controller: TextEditingController(text: 'input'), + controller: controller, maxLines: null, decoration: const InputDecoration( suffixIcon: Icon(Icons.search), @@ -6323,7 +6345,10 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.takeException(), isNull); }); - testWidgets('min intrinsic height for TextField with prefix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('min intrinsic height for TextField with prefix', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'input'); + addTearDown(controller.dispose); + // Regression test for: https://github.com/flutter/flutter/issues/87403 await tester.pumpWidget(MaterialApp( home: Material( @@ -6334,7 +6359,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular child: Column( children: [ TextField( - controller: TextEditingController(text: 'input'), + controller: controller, maxLines: null, decoration: const InputDecoration( prefix: Text('prefix'), @@ -6351,7 +6376,10 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.takeException(), isNull); }); - testWidgets('min intrinsic height for TextField with suffix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('min intrinsic height for TextField with suffix', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'input'); + addTearDown(controller.dispose); + // Regression test for: https://github.com/flutter/flutter/issues/87403 await tester.pumpWidget(MaterialApp( home: Material( @@ -6362,7 +6390,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular child: Column( children: [ TextField( - controller: TextEditingController(text: 'input'), + controller: controller, maxLines: null, decoration: const InputDecoration( suffix: Text('suffix'), @@ -6379,7 +6407,10 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.takeException(), isNull); }); - testWidgets('min intrinsic height for TextField with icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('min intrinsic height for TextField with icon', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'input'); + addTearDown(controller.dispose); + // Regression test for: https://github.com/flutter/flutter/issues/87403 await tester.pumpWidget(MaterialApp( home: Material( @@ -6390,7 +6421,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular child: Column( children: [ TextField( - controller: TextEditingController(text: 'input'), + controller: controller, maxLines: null, decoration: const InputDecoration( icon: Icon(Icons.search), @@ -6407,7 +6438,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(tester.takeException(), isNull); }); - testWidgets('InputDecorationTheme floatingLabelStyle overrides label widget styles when the widget is a text widget (focused)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme floatingLabelStyle overrides label widget styles when the widget is a text widget (focused)', (WidgetTester tester) async { const TextStyle style16 = TextStyle(fontSize: 16.0); final TextStyle floatingLabelStyle = style16.merge(const TextStyle(color: Colors.indigo)); @@ -6449,7 +6480,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(getLabelStyle(tester).color, floatingLabelStyle.color); }); - testWidgets('InputDecorationTheme labelStyle overrides label widget styles when the widget is a text widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorationTheme labelStyle overrides label widget styles when the widget is a text widget', (WidgetTester tester) async { const TextStyle styleDefaultSize = TextStyle(fontSize: 16.0); final TextStyle labelStyle = styleDefaultSize.merge(const TextStyle(color: Colors.purple)); @@ -6490,7 +6521,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(getLabelStyle(tester).color, labelStyle.color); }); - testWidgets('hint style overflow works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hint style overflow works', (WidgetTester tester) async { final String hintText = 'hint text' * 20; const TextStyle hintStyle = TextStyle( fontSize: 14.0, @@ -6516,7 +6547,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(hintTextWidget.style!.overflow, decoration.hintStyle!.overflow); }); - testWidgets('prefixIcon in RTL with asymmetric padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prefixIcon in RTL with asymmetric padding', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/129591 const InputDecoration decoration = InputDecoration( contentPadding: EdgeInsetsDirectional.only(end: 24), @@ -6546,7 +6577,7 @@ testWidgets('OutlineInputBorder with BorderRadius.zero should draw a rectangular expect(decoratorRight, lessThanOrEqualTo(prefixRight)); }); - testWidgets('InputDecorator with counter does not crash when given a 0 size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecorator with counter does not crash when given a 0 size', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/129611 const InputDecoration decoration = InputDecoration( contentPadding: EdgeInsetsDirectional.all(99), diff --git a/packages/flutter/test/material/magnifier_test.dart b/packages/flutter/test/material/magnifier_test.dart index 9abf8906b2fcd..275550523ff99 100644 --- a/packages/flutter/test/material/magnifier_test.dart +++ b/packages/flutter/test/material/magnifier_test.dart @@ -8,6 +8,7 @@ library; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { final MagnifierController magnifierController = MagnifierController(); @@ -50,7 +51,7 @@ void main() { }); group('adaptiveMagnifierControllerBuilder', () { - testWidgets('should return a TextEditingMagnifier on Android', + testWidgetsWithLeakTracking('should return a TextEditingMagnifier on Android', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -58,16 +59,19 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + final ValueNotifier magnifierPositioner = ValueNotifier(MagnifierInfo.empty); + addTearDown(magnifierPositioner.dispose); + final Widget? builtWidget = TextMagnifier.adaptiveMagnifierConfiguration.magnifierBuilder( context, MagnifierController(), - ValueNotifier(MagnifierInfo.empty), + magnifierPositioner, ); expect(builtWidget, isA()); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('should return a CupertinoMagnifier on iOS', + testWidgetsWithLeakTracking('should return a CupertinoMagnifier on iOS', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -75,16 +79,19 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + final ValueNotifier magnifierPositioner = ValueNotifier(MagnifierInfo.empty); + addTearDown(magnifierPositioner.dispose); + final Widget? builtWidget = TextMagnifier.adaptiveMagnifierConfiguration.magnifierBuilder( context, MagnifierController(), - ValueNotifier(MagnifierInfo.empty), + magnifierPositioner, ); expect(builtWidget, isA()); }, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); - testWidgets('should return null on all platforms not Android, iOS', + testWidgetsWithLeakTracking('should return null on all platforms not Android, iOS', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -92,10 +99,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + final ValueNotifier magnifierPositioner = ValueNotifier(MagnifierInfo.empty); + addTearDown(magnifierPositioner.dispose); + final Widget? builtWidget = TextMagnifier.adaptiveMagnifierConfiguration.magnifierBuilder( context, MagnifierController(), - ValueNotifier(MagnifierInfo.empty), + magnifierPositioner, ); expect(builtWidget, isNull); @@ -110,7 +120,7 @@ void main() { group('magnifier', () { group('position', () { - testWidgets( + testWidgetsWithLeakTracking( 'should be at gesture position if does not violate any positioning rules', (WidgetTester tester) async { final Key textField = UniqueKey(); @@ -155,6 +165,7 @@ void main() { // The tap position is dragBelow units below the text field. globalGesturePosition: fakeTextFieldRect.center, )); + addTearDown(magnifierInfo.dispose); await showMagnifier(context, tester, magnifierInfo); @@ -166,7 +177,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'should never move outside the right bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -178,10 +189,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierPositioner; + addTearDown(() => magnifierPositioner.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, // Inflate these two to make sure we're bounding on the @@ -199,7 +213,7 @@ void main() { lessThanOrEqualTo(reasonableTextField.right)); }); - testWidgets( + testWidgetsWithLeakTracking( 'should never move outside the left bounds of the editing line', (WidgetTester tester) async { const double gestureOutsideLine = 100; @@ -211,10 +225,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierPositioner; + addTearDown(() => magnifierPositioner.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, // Inflate these two to make sure we're bounding on the @@ -231,7 +248,7 @@ void main() { greaterThanOrEqualTo(reasonableTextField.left)); }); - testWidgets('should position vertically at the center of the line', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should position vertically at the center of the line', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), )); @@ -239,10 +256,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierPositioner; + addTearDown(() => magnifierPositioner.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, fieldBounds: reasonableTextField, @@ -254,7 +274,7 @@ void main() { reasonableTextField.center.dy - basicOffset.dy); }); - testWidgets('should reposition vertically if mashed against the ceiling', + testWidgetsWithLeakTracking('should reposition vertically if mashed against the ceiling', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = Rect.fromPoints(Offset.zero, const Offset(200, 0)); @@ -266,10 +286,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierPositioner; + addTearDown(() => magnifierPositioner.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: topOfScreenTextFieldRect, fieldBounds: topOfScreenTextFieldRect, @@ -289,7 +312,7 @@ void main() { return magnifier.additionalFocalPointOffset; } - testWidgets( + testWidgetsWithLeakTracking( 'should shift focal point so that the lens sees nothing out of bounds', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( @@ -299,10 +322,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierPositioner; + addTearDown(() => magnifierPositioner.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, fieldBounds: reasonableTextField, @@ -317,7 +343,7 @@ void main() { lessThan(reasonableTextField.left)); }); - testWidgets( + testWidgetsWithLeakTracking( 'focal point should shift if mashed against the top to always point to text', (WidgetTester tester) async { final Rect topOfScreenTextFieldRect = @@ -330,10 +356,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierPositioner; + addTearDown(() => magnifierPositioner.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: topOfScreenTextFieldRect, fieldBounds: topOfScreenTextFieldRect, @@ -354,7 +383,7 @@ void main() { return animatedPositioned.duration.compareTo(Duration.zero) != 0; } - testWidgets('should not be animated on the initial state', + testWidgetsWithLeakTracking('should not be animated on the initial state', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -363,10 +392,13 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); + late ValueNotifier magnifierInfo; + addTearDown(() => magnifierInfo.dispose()); + await showMagnifier( context, tester, - ValueNotifier( + magnifierInfo = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, fieldBounds: reasonableTextField, @@ -379,7 +411,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgets('should not be animated on horizontal shifts', + testWidgetsWithLeakTracking('should not be animated on horizontal shifts', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Placeholder(), @@ -388,8 +420,7 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); - final ValueNotifier magnifierPositioner = - ValueNotifier( + final ValueNotifier magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, fieldBounds: reasonableTextField, @@ -397,6 +428,7 @@ void main() { globalGesturePosition: reasonableTextField.center, ), ); + addTearDown(magnifierPositioner.dispose); await showMagnifier(context, tester, magnifierPositioner); @@ -413,7 +445,7 @@ void main() { expect(getIsAnimated(tester), false); }); - testWidgets('should be animated on vertical shifts', + testWidgetsWithLeakTracking('should be animated on vertical shifts', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); @@ -424,8 +456,7 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); - final ValueNotifier magnifierPositioner = - ValueNotifier( + final ValueNotifier magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, fieldBounds: reasonableTextField, @@ -433,6 +464,7 @@ void main() { globalGesturePosition: reasonableTextField.center, ), ); + addTearDown(magnifierPositioner.dispose); await showMagnifier(context, tester, magnifierPositioner); @@ -449,7 +481,7 @@ void main() { expect(getIsAnimated(tester), true); }); - testWidgets('should stop being animated when timer is up', + testWidgetsWithLeakTracking('should stop being animated when timer is up', (WidgetTester tester) async { const Offset verticalShift = Offset(0, 200); @@ -460,8 +492,7 @@ void main() { final BuildContext context = tester.firstElement(find.byType(Placeholder)); - final ValueNotifier magnifierPositioner = - ValueNotifier( + final ValueNotifier magnifierPositioner = ValueNotifier( MagnifierInfo( currentLineBoundaries: reasonableTextField, fieldBounds: reasonableTextField, @@ -469,6 +500,7 @@ void main() { globalGesturePosition: reasonableTextField.center, ), ); + addTearDown(magnifierPositioner.dispose); await showMagnifier(context, tester, magnifierPositioner); diff --git a/packages/flutter/test/material/menu_anchor_test.dart b/packages/flutter/test/material/menu_anchor_test.dart index 5416882eab7ed..19e5b2e72c272 100644 --- a/packages/flutter/test/material/menu_anchor_test.dart +++ b/packages/flutter/test/material/menu_anchor_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -80,6 +81,7 @@ void main() { TextDirection textDirection = TextDirection.ltr, }) { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); return MaterialApp( theme: ThemeData(useMaterial3: false), home: Material( @@ -142,7 +144,7 @@ void main() { ); } - testWidgets('Menu responds to density changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Menu responds to density changes', (WidgetTester tester) async { Widget buildMenu({VisualDensity? visualDensity = VisualDensity.standard}) { return MaterialApp( theme: ThemeData(visualDensity: visualDensity, useMaterial3: false), @@ -237,7 +239,7 @@ void main() { ); }); - testWidgets('Menu defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Menu defaults', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -319,7 +321,7 @@ void main() { expect(iconRichText.text.style?.color, themeData.colorScheme.onSurfaceVariant); }); - testWidgets('Menu defaults - disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Menu defaults - disabled', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -394,7 +396,7 @@ void main() { expect(iconRichText.text.style?.color, themeData.colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('Menu scrollbar inherits ScrollbarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Menu scrollbar inherits ScrollbarTheme', (WidgetTester tester) async { const ScrollbarThemeData scrollbarTheme = ScrollbarThemeData( thumbColor: MaterialStatePropertyAll(Color(0xffff0000)), thumbVisibility: MaterialStatePropertyAll(true), @@ -489,8 +491,9 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('focus is returned to previous focus before invoking onPressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('focus is returned to previous focus before invoking onPressed', (WidgetTester tester) async { final FocusNode buttonFocus = FocusNode(debugLabel: 'Button Focus'); + addTearDown(buttonFocus.dispose); FocusNode? focusInOnPressed; void onMenuSelected(TestMenu item) { @@ -537,7 +540,7 @@ void main() { }); group('Menu functions', () { - testWidgets('basic menu structure', (WidgetTester tester) async { + testWidgetsWithLeakTracking('basic menu structure', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -590,7 +593,7 @@ void main() { expect(opened.last, equals(TestMenu.subMenu11)); }); - testWidgets('geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -655,7 +658,7 @@ void main() { ); }); - testWidgets('geometry with RTL direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('geometry with RTL direction', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -732,7 +735,7 @@ void main() { ); }); - testWidgets('menu alignment and offset in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menu alignment and offset in LTR', (WidgetTester tester) async { await tester.pumpWidget(buildTestApp()); final Rect buttonRect = tester.getRect(find.byType(ElevatedButton)); @@ -775,7 +778,7 @@ void main() { ); }); - testWidgets('menu alignment and offset in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menu alignment and offset in RTL', (WidgetTester tester) async { await tester.pumpWidget(buildTestApp(textDirection: TextDirection.rtl)); final Rect buttonRect = tester.getRect(find.byType(ElevatedButton)); @@ -817,7 +820,7 @@ void main() { expect(tester.getRect(findMenuScope).topLeft - menuRect.topLeft, equals(const Offset(-10, 20))); }); - testWidgets('menu position in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menu position in LTR', (WidgetTester tester) async { await tester.pumpWidget(buildTestApp(alignmentOffset: const Offset(100, 50))); final Rect buttonRect = tester.getRect(find.byType(ElevatedButton)); @@ -838,7 +841,7 @@ void main() { expect(tester.getRect(findMenuScope), equals(const Rect.fromLTRB(526.0, 476.0, 800.0, 588.0))); }); - testWidgets('menu position in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menu position in RTL', (WidgetTester tester) async { await tester.pumpWidget(buildTestApp( alignmentOffset: const Offset(100, 50), textDirection: TextDirection.rtl, @@ -863,7 +866,7 @@ void main() { expect(tester.getRect(findMenuScope), equals(const Rect.fromLTRB(526.0, 476.0, 800.0, 588.0))); }); - testWidgets('works with Padding around menu and overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with Padding around menu and overlay', (WidgetTester tester) async { await tester.pumpWidget( Padding( padding: const EdgeInsets.all(10.0), @@ -916,7 +919,7 @@ void main() { expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(22.0, 22.0, 778.0, 70.0))); }); - testWidgets('works with Padding around menu and overlay with RTL direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with Padding around menu and overlay with RTL direction', (WidgetTester tester) async { await tester.pumpWidget( Padding( padding: const EdgeInsets.all(10.0), @@ -972,7 +975,7 @@ void main() { expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(22.0, 22.0, 778.0, 70.0))); }); - testWidgets('visual attributes can be set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visual attributes can be set', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1003,7 +1006,7 @@ void main() { expect(material.color, equals(Colors.red)); }); - testWidgets('MenuAnchor clip behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MenuAnchor clip behavior', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1064,7 +1067,7 @@ void main() { expect(getMenuBarMaterial(tester).clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('open and close works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('open and close works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1113,7 +1116,7 @@ void main() { expect(closed, equals([TestMenu.mainMenu1])); }); - testWidgets('select works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1148,7 +1151,7 @@ void main() { expect(find.text(TestMenu.subMenu11.label), findsNothing); }); - testWidgets('diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('diagnostics', (WidgetTester tester) async { const MenuItemButton item = MenuItemButton( shortcut: SingleActivator(LogicalKeyboardKey.keyA), child: Text('label2'), @@ -1187,7 +1190,7 @@ void main() { ); }); - testWidgets('keyboard tab traversal works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard tab traversal works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1246,7 +1249,7 @@ void main() { expect(closed, [TestMenu.mainMenu0]); }); - testWidgets('keyboard directional traversal works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard directional traversal works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1326,7 +1329,7 @@ void main() { expect(focusedMenu, equals('MenuItemButton(Text("Sub Sub Menu 113"))')); }); - testWidgets('keyboard directional traversal works in RTL mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard directional traversal works in RTL mode', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -1412,7 +1415,7 @@ void main() { expect(focusedMenu, equals('MenuItemButton(Text("Sub Sub Menu 113"))')); }); - testWidgets('hover traversal works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hover traversal works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1468,8 +1471,9 @@ void main() { expect(focusedMenu, equals('MenuItemButton(Text("Sub Sub Menu 110"))')); }); - testWidgets('menus close on ancestor scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menus close on ancestor scroll', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -1506,9 +1510,10 @@ void main() { expect(closed, isNotEmpty); }); - testWidgets('menus do not close on root menu internal scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menus do not close on root menu internal scroll', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/122168. final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); bool rootOpened = false; await tester.pumpWidget( @@ -1578,8 +1583,9 @@ void main() { expect(closed, isNotEmpty); }); - testWidgets('menus close on view size change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('menus close on view size change', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final MediaQueryData mediaQueryData = MediaQueryData.fromView(tester.view); Widget build(Size size) { @@ -1668,7 +1674,7 @@ void main() { } }); - testWidgets('can invoke menu items', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can invoke menu items', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1724,7 +1730,7 @@ void main() { selected.clear(); }, variant: TargetPlatformVariant(nonApple)); - testWidgets('can combine with regular keyboard navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can combine with regular keyboard navigation', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1761,7 +1767,7 @@ void main() { expect(selected, equals([TestMenu.subSubMenu110])); }, variant: TargetPlatformVariant(nonApple)); - testWidgets('can combine with mouse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can combine with mouse', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1796,7 +1802,7 @@ void main() { expect(selected, equals([TestMenu.subSubMenu112])); }, variant: TargetPlatformVariant(nonApple)); - testWidgets("disabled items don't respond to accelerators", (WidgetTester tester) async { + testWidgetsWithLeakTracking("disabled items don't respond to accelerators", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1828,7 +1834,7 @@ void main() { expect(find.text(TestMenu.subMenu00.label), findsNothing); }, variant: TargetPlatformVariant(nonApple)); - testWidgets("Apple platforms don't react to accelerators", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Apple platforms don't react to accelerators", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1874,7 +1880,7 @@ void main() { }); group('MenuController', () { - testWidgets('Moving a controller to a new instance works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a controller to a new instance works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1912,7 +1918,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('closing via controller works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('closing via controller works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1955,7 +1961,7 @@ void main() { }); group('MenuItemButton', () { - testWidgets('Shortcut mnemonics are displayed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcut mnemonics are displayed', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2075,7 +2081,7 @@ void main() { expect(mnemonic2.data, equals('↵')); }, variant: TargetPlatformVariant.all()); - testWidgets('leadingIcon is used when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('leadingIcon is used when set', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2103,7 +2109,7 @@ void main() { expect(find.text('leadingIcon'), findsOneWidget); }); - testWidgets('trailingIcon is used when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('trailingIcon is used when set', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2131,7 +2137,7 @@ void main() { expect(find.text('trailingIcon'), findsOneWidget); }); - testWidgets('SubmenuButton uses supplied controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SubmenuButton uses supplied controller', (WidgetTester tester) async { final MenuController submenuController = MenuController(); await tester.pumpWidget( MaterialApp( @@ -2188,7 +2194,7 @@ void main() { expect(find.text(TestMenu.subMenu00.label), findsNothing); }); - testWidgets('diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('diagnostics', (WidgetTester tester) async { final ButtonStyle style = ButtonStyle( shape: MaterialStateProperty.all(const StadiumBorder()), elevation: MaterialStateProperty.all(10.0), @@ -2248,7 +2254,7 @@ void main() { ); }); - testWidgets('MenuItemButton respects closeOnActivate property', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MenuItemButton respects closeOnActivate property', (WidgetTester tester) async { final MenuController controller = MenuController(); await tester.pumpWidget(MaterialApp( home: Material( @@ -2346,7 +2352,7 @@ void main() { return menuRects; } - testWidgets('unconstrained menus show up in the right place in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('unconstrained menus show up in the right place in LTR', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(800, 600)); await tester.pumpWidget( MaterialApp( @@ -2390,7 +2396,7 @@ void main() { ); }); - testWidgets('unconstrained menus show up in the right place in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('unconstrained menus show up in the right place in RTL', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(800, 600)); await tester.pumpWidget( MaterialApp( @@ -2437,7 +2443,7 @@ void main() { ); }); - testWidgets('constrained menus show up in the right place in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('constrained menus show up in the right place in LTR', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(300, 300)); await tester.pumpWidget( MaterialApp( @@ -2482,7 +2488,7 @@ void main() { ); }); - testWidgets('constrained menus show up in the right place in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('constrained menus show up in the right place in RTL', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(300, 300)); await tester.pumpWidget( MaterialApp( @@ -2527,7 +2533,7 @@ void main() { ); }); - testWidgets('constrained menus show up in the right place with offset in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('constrained menus show up in the right place with offset in LTR', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(800, 600)); await tester.pumpWidget( MaterialApp( @@ -2604,7 +2610,7 @@ void main() { ); }); - testWidgets('constrained menus show up in the right place with offset in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('constrained menus show up in the right place with offset in RTL', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(800, 600)); await tester.pumpWidget( MaterialApp( @@ -2681,7 +2687,7 @@ void main() { ); }); - testWidgets('vertically constrained menus are positioned above the anchor by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('vertically constrained menus are positioned above the anchor by default', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(800, 600)); await tester.pumpWidget( MaterialApp( @@ -2732,7 +2738,7 @@ void main() { ); }); - testWidgets('vertically constrained menus are positioned above the anchor with the provided offset', + testWidgetsWithLeakTracking('vertically constrained menus are positioned above the anchor with the provided offset', (WidgetTester tester) async { await changeSurfaceSize(tester, const Size(800, 600)); await tester.pumpWidget( @@ -2819,7 +2825,7 @@ void main() { await tester.pump(); } - testWidgets('submenus account for density in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('submenus account for density in LTR', (WidgetTester tester) async { await buildDensityPaddingApp( tester, textDirection: TextDirection.ltr, @@ -2834,7 +2840,7 @@ void main() { ); }); - testWidgets('submenus account for menu density in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('submenus account for menu density in RTL', (WidgetTester tester) async { await buildDensityPaddingApp( tester, textDirection: TextDirection.rtl, @@ -2849,7 +2855,7 @@ void main() { ); }); - testWidgets('submenus account for compact menu density in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('submenus account for compact menu density in LTR', (WidgetTester tester) async { await buildDensityPaddingApp( tester, visualDensity: VisualDensity.compact, @@ -2865,7 +2871,7 @@ void main() { ); }); - testWidgets('submenus account for compact menu density in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('submenus account for compact menu density in RTL', (WidgetTester tester) async { await buildDensityPaddingApp( tester, visualDensity: VisualDensity.compact, @@ -2881,7 +2887,7 @@ void main() { ); }); - testWidgets('submenus account for padding in LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('submenus account for padding in LTR', (WidgetTester tester) async { await buildDensityPaddingApp( tester, menuPadding: const EdgeInsetsDirectional.only(start: 10, end: 11, top: 12, bottom: 13), @@ -2897,7 +2903,7 @@ void main() { ); }); - testWidgets('submenus account for padding in RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('submenus account for padding in RTL', (WidgetTester tester) async { await buildDensityPaddingApp( tester, menuPadding: const EdgeInsetsDirectional.only(start: 10, end: 11, top: 12, bottom: 13), @@ -2915,7 +2921,7 @@ void main() { }); group('LocalizedShortcutLabeler', () { - testWidgets('getShortcutLabel returns the right labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getShortcutLabel returns the right labels', (WidgetTester tester) async { String expectedMeta; String expectedCtrl; String expectedAlt; @@ -2993,7 +2999,7 @@ void main() { }); group('CheckboxMenuButton', () { - testWidgets('tapping toggles checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tapping toggles checkbox', (WidgetTester tester) async { bool? checkBoxValue; await tester.pumpWidget( MaterialApp( @@ -3047,7 +3053,7 @@ void main() { }); group('RadioMenuButton', () { - testWidgets('tapping toggles radio button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tapping toggles radio button', (WidgetTester tester) async { int? radioValue; await tester.pumpWidget( MaterialApp( @@ -3116,7 +3122,7 @@ void main() { }); group('Semantics', () { - testWidgets('MenuItemButton is not a semantic button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MenuItemButton is not a semantic button', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -3160,7 +3166,7 @@ void main() { semantics.dispose(); }); - testWidgets('SubMenuButton is not a semantic button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SubMenuButton is not a semantic button', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -3199,7 +3205,7 @@ void main() { semantics.dispose(); }); - testWidgets('SubmenuButton expanded/collapsed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SubmenuButton expanded/collapsed state', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( MaterialApp( @@ -3327,7 +3333,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/131676. - testWidgets('Material3 - Menu uses correct text styles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Menu uses correct text styles', (WidgetTester tester) async { const TextStyle menuTextStyle = TextStyle( fontSize: 18.5, fontStyle: FontStyle.italic, diff --git a/packages/flutter/test/material/menu_bar_theme_test.dart b/packages/flutter/test/material/menu_bar_theme_test.dart index 2b9dabe7f403d..b5dafecaec210 100644 --- a/packages/flutter/test/material/menu_bar_theme_test.dart +++ b/packages/flutter/test/material/menu_bar_theme_test.dart @@ -53,7 +53,7 @@ void main() { expect(identical(MenuBarThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('theme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_style_test.dart b/packages/flutter/test/material/menu_style_test.dart index 74ce6b8887a13..c3fc058976de0 100644 --- a/packages/flutter/test/material/menu_style_test.dart +++ b/packages/flutter/test/material/menu_style_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { @@ -43,7 +44,7 @@ void main() { expect(identical(MenuStyle.lerp(data, data, 0.5), data), true); }); - testWidgets('fixedSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fixedSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -88,7 +89,7 @@ void main() { } }); - testWidgets('maximumSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maximumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -131,7 +132,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(100.0, 100.0))); }); - testWidgets('minimumSize affects geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('minimumSize affects geometry', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -174,7 +175,7 @@ void main() { expect(tester.getRect(findMenuPanels().at(1)).size, equals(const Size(300.0, 300.0))); }); - testWidgets('Material parameters are honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material parameters are honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -240,7 +241,7 @@ void main() { expect(panelPadding.padding, equals(const EdgeInsets.all(20))); }); - testWidgets('visual density', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visual density', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/menu_theme_test.dart b/packages/flutter/test/material/menu_theme_test.dart index bb4c0cd3ce973..49089f724ce4d 100644 --- a/packages/flutter/test/material/menu_theme_test.dart +++ b/packages/flutter/test/material/menu_theme_test.dart @@ -54,7 +54,7 @@ void main() { expect(identical(MenuThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('theme is honored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('theme is honored', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), diff --git a/packages/flutter/test/material/mergeable_material_test.dart b/packages/flutter/test/material/mergeable_material_test.dart index 7598403270286..19539527b4f7c 100644 --- a/packages/flutter/test/material/mergeable_material_test.dart +++ b/packages/flutter/test/material/mergeable_material_test.dart @@ -79,7 +79,7 @@ void main() { expect(box.size.height, equals(0)); }); - testWidgets('MergeableMaterial update slice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial update slice', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -233,7 +233,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial skips shadow for zero elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( const MaterialApp( @@ -1167,7 +1167,7 @@ void main() { ); } - testWidgets('MergeableMaterial dividers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial dividers', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1329,7 +1329,7 @@ void main() { expect(decoration.border!.top.color, dividerColor); }); - testWidgets('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeableMaterial respects MaterialSlice.color', (WidgetTester tester) async { const Color themeCardColor = Colors.red; const Color materialSliceColor = Colors.green; diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index cde4e4eb0eace..8a6b6d0aafed0 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Navigation drawer updates destinations when tapped', + testWidgetsWithLeakTracking('Navigation drawer updates destinations when tapped', (WidgetTester tester) async { int mutatedIndex = -1; final GlobalKey scaffoldKey = GlobalKey(); @@ -49,7 +50,7 @@ void main() { expect(mutatedIndex, 0); }); - testWidgets('NavigationDrawer can update background color', + testWidgetsWithLeakTracking('NavigationDrawer can update background color', (WidgetTester tester) async { const Color color = Colors.yellow; final GlobalKey scaffoldKey = GlobalKey(); @@ -82,7 +83,7 @@ void main() { expect(_getMaterial(tester).color, equals(color)); }); - testWidgets('NavigationDrawer can update elevation', + testWidgetsWithLeakTracking('NavigationDrawer can update elevation', (WidgetTester tester) async { const double elevation = 42.0; final GlobalKey scaffoldKey = GlobalKey(); @@ -114,7 +115,7 @@ void main() { expect(_getMaterial(tester).elevation, equals(elevation)); }); - testWidgets( + testWidgetsWithLeakTracking( 'NavigationDrawer uses proper defaults when no parameters are given', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -163,7 +164,7 @@ void main() { expect(iconBox.size, const Size(24.0, 24.0)); }); - testWidgets('Navigation drawer is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation drawer is scrollable', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 500, viewHeight: 300); await tester.pumpWidget( @@ -210,7 +211,7 @@ void main() { expect(find.text('Label10'), findsNothing); }); - testWidgets('Safe Area test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe Area test', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const double viewHeight = 300; widgetSetup(tester, 500, viewHeight: viewHeight); @@ -251,7 +252,7 @@ void main() { expect(tester.getBottomRight(find.widgetWithText(NavigationDrawerDestination,'Label4')).dy, viewHeight); }); - testWidgets('Navigation drawer semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation drawer semantics', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme= ThemeData.from(colorScheme: const ColorScheme.light()); Widget widget({int selectedIndex = 0}) { @@ -321,7 +322,7 @@ void main() { ); }); - testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation destination updates indicator color and shape', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); final ThemeData theme = ThemeData(useMaterial3: true); const Color color = Color(0xff0000ff); @@ -372,7 +373,7 @@ void main() { expect(_getInkWell(tester)?.customBorder, shape); }); - testWidgets('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationDrawer.tilePadding defaults to EdgeInsets.symmetric(horizontal: 12.0)', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); widgetSetup(tester, 3000, viewHeight: 3000); final Widget widget = _buildWidget( diff --git a/packages/flutter/test/material/navigation_drawer_theme_test.dart b/packages/flutter/test/material/navigation_drawer_theme_test.dart index 2df6b7edf2b59..f055198c020f2 100644 --- a/packages/flutter/test/material/navigation_drawer_theme_test.dart +++ b/packages/flutter/test/material/navigation_drawer_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('NavigationDrawerThemeData copyWith, ==, hashCode, basics', () { @@ -18,7 +19,7 @@ void main() { expect(identical(NavigationDrawerThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationDrawerThemeData().debugFillProperties(builder); @@ -30,7 +31,7 @@ void main() { expect(description, []); }); - testWidgets('NavigationDrawerThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationDrawerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationDrawerThemeData( tileHeight: 50, @@ -66,7 +67,7 @@ void main() { )); }); - testWidgets( + testWidgetsWithLeakTracking( 'NavigationDrawerThemeData values are used when no NavigationDrawer properties are specified', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -134,7 +135,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'NavigationDrawer values take priority over NavigationDrawerThemeData values when both properties are specified', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); @@ -196,7 +197,7 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, indicatorShape); }); - testWidgets('Local NavigationDrawerTheme takes priority over ThemeData.navigationDrawerTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Local NavigationDrawerTheme takes priority over ThemeData.navigationDrawerTheme', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); const Color backgroundColor = Color(0x00000009); const double elevation = 7.0; diff --git a/packages/flutter/test/material/navigation_rail_theme_test.dart b/packages/flutter/test/material/navigation_rail_theme_test.dart index 7a56586ca2643..c3c29ce513511 100644 --- a/packages/flutter/test/material/navigation_rail_theme_test.dart +++ b/packages/flutter/test/material/navigation_rail_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('copyWith, ==, hashCode basics', () { @@ -12,7 +13,7 @@ void main() { expect(const NavigationRailThemeData().hashCode, const NavigationRailThemeData().copyWith().hashCode); }); - testWidgets('Material3 - Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); // Material 3 defaults await tester.pumpWidget( @@ -47,7 +48,7 @@ void main() { expect(inkResponse.customBorder, const StadiumBorder()); }); - testWidgets('Material2 - Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default values are used when no NavigationRail or NavigationRailThemeData properties are specified', (WidgetTester tester) async { // This test can be removed when `useMaterial3` is deprecated. await tester.pumpWidget( MaterialApp( @@ -77,7 +78,7 @@ void main() { expect(find.byType(NavigationIndicator), findsNothing); }); - testWidgets('NavigationRailThemeData values are used when no NavigationRail properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailThemeData values are used when no NavigationRail properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0x00000001); const double elevation = 7.0; const double selectedIconSize = 25.0; @@ -145,7 +146,7 @@ void main() { expect(_indicatorDecoration(tester)?.shape, indicatorShape); }); - testWidgets('NavigationRail values take priority over NavigationRailThemeData values when both properties are specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRail values take priority over NavigationRailThemeData values when both properties are specified', (WidgetTester tester) async { const Color backgroundColor = Color(0x00000001); const double elevation = 7.0; const double selectedIconSize = 25.0; @@ -229,14 +230,14 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/118618. - testWidgets('NavigationRailThemeData lerps correctly with null iconThemes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NavigationRailThemeData lerps correctly with null iconThemes', (WidgetTester tester) async { final NavigationRailThemeData lerp = NavigationRailThemeData.lerp(const NavigationRailThemeData(), const NavigationRailThemeData(), 0.5)!; expect(lerp.selectedIconTheme, isNull); expect(lerp.unselectedIconTheme, isNull); }); - testWidgets('Default debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationRailThemeData().debugFillProperties(builder); @@ -248,7 +249,7 @@ void main() { expect(description, []); }); - testWidgets('Custom debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const NavigationRailThemeData( backgroundColor: Color(0x00000099), diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index a147a4651e65c..6a8f626074115 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -1890,6 +1890,7 @@ void main() { count += 1; } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); controller.addListener(valueChanged); await tester.pumpWidget( @@ -1990,20 +1991,21 @@ void main() { await gesture.removePointer(); } - testWidgets('OutlinedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('OutlinedButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled OutlinedButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled OutlinedButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); controller.addListener(valueChanged); await tester.pumpWidget( diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index d353803e779e6..56b2d40642a3c 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -13,9 +13,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('test page transition (_FadeUpwardsPageTransition)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test page transition (_FadeUpwardsPageTransition)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: const Material(child: Text('Page 1')), @@ -79,7 +80,7 @@ void main() { expect(find.text('Page 2'), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('test page transition (CupertinoPageTransition)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test page transition (CupertinoPageTransition)', (WidgetTester tester) async { final Key page2Key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -160,7 +161,7 @@ void main() { expect(widget1InitialTopLeft == widget1TransientTopLeft, true); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('test page transition (_ZoomPageTransition) without rasterization', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test page transition (_ZoomPageTransition) without rasterization', (WidgetTester tester) async { Iterable findLayers(Finder of) { return tester.layerListOf( find.ancestor(of: of, matching: find.byType(SnapshotWidget)).first, @@ -239,7 +240,7 @@ void main() { expect(find.text('Page 2'), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Material2 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1000, 1000); tester.view.viewInsets = FakeViewPadding.zero; @@ -280,7 +281,7 @@ void main() { await expectLater(find.byKey(key), matchesGoldenFile('m2_zoom_page_transition.big.png')); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - testWidgets('Material3 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - test page transition (_ZoomPageTransition) with rasterization re-rasterizes when view insets change', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view.physicalSize = const Size(1000, 1000); tester.view.viewInsets = FakeViewPadding.zero; @@ -321,7 +322,7 @@ void main() { await expectLater(find.byKey(key), matchesGoldenFile('m3_zoom_page_transition.big.png')); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - testWidgets( + testWidgetsWithLeakTracking( 'test page transition (_ZoomPageTransition) with rasterization disables snapshotting for enter route', (WidgetTester tester) async { Iterable findLayers(Finder of) { @@ -403,7 +404,7 @@ void main() { expect(isSnapshotted(page1Finder), isFalse); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - testWidgets('test fullscreen dialog transition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test fullscreen dialog transition', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material(child: Text('Page 1')), @@ -463,7 +464,7 @@ void main() { expect(widget1InitialTopLeft == widget1TransientTopLeft, true); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('test no back gesture on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test no back gesture on Android', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: const Scaffold(body: Text('Page 1')), @@ -493,7 +494,7 @@ void main() { expect(tester.getTopLeft(find.text('Page 2')), Offset.zero); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('test back gesture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test back gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: const Scaffold(body: Text('Page 1')), @@ -534,7 +535,7 @@ void main() { expect(tester.getTopLeft(find.text('Page 2')), const Offset(100.0, 0.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('back gesture while OS changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('back gesture while OS changes', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => Material( child: TextButton( @@ -625,7 +626,7 @@ void main() { expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.macOS); }); - testWidgets('test no back gesture on fullscreen dialogs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test no back gesture on fullscreen dialogs', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold(body: Text('Page 1')), @@ -655,7 +656,7 @@ void main() { expect(tester.getTopLeft(find.text('Page 2')), Offset.zero); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('test adaptable transitions switch during execution', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test adaptable transitions switch during execution', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -736,7 +737,7 @@ void main() { expect(widget1InitialTopLeft == widget1TransientTopLeft, true); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test edge swipe then drop back at starting point works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( onGenerateRoute: (RouteSettings settings) { @@ -771,7 +772,7 @@ void main() { expect(find.text('Page 2'), isOnstage); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('test edge swipe then drop back at ending point works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test edge swipe then drop back at ending point works', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( onGenerateRoute: (RouteSettings settings) { @@ -804,7 +805,7 @@ void main() { expect(find.text('Page 2'), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Back swipe dismiss interrupted by route push', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28728 final GlobalKey scaffoldKey = GlobalKey(); @@ -899,7 +900,7 @@ void main() { expect(find.text('push'), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('During back swipe the route ignores input', (WidgetTester tester) async { + testWidgetsWithLeakTracking('During back swipe the route ignores input', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/39989 final GlobalKey homeScaffoldKey = GlobalKey(); @@ -969,7 +970,7 @@ void main() { expect(tester.getTopLeft(find.byKey(homeScaffoldKey)).dx, lessThan(0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('After a pop caused by a back-swipe, input reaches the exposed route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('After a pop caused by a back-swipe, input reaches the exposed route', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/41024 final GlobalKey homeScaffoldKey = GlobalKey(); @@ -1066,9 +1067,10 @@ void main() { // Title of the first route slides to the left. expect(titleInitialTopLeft.dy, equals(titleTransientTopLeft.dy)); expect(titleInitialTopLeft.dx, greaterThan(titleTransientTopLeft.dx)); - }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + }, + variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('MaterialPage works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialPage works', (WidgetTester tester) async { final LocalKey pageKey = UniqueKey(); final TransitionDetector detector = TransitionDetector(); List> myPages = >[ @@ -1111,7 +1113,7 @@ void main() { expect(find.text('second'), findsOneWidget); }); - testWidgets('MaterialPage can toggle MaintainState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialPage can toggle MaintainState', (WidgetTester tester) async { final LocalKey pageKeyOne = UniqueKey(); final LocalKey pageKeyTwo = UniqueKey(); final TransitionDetector detector = TransitionDetector(); @@ -1160,7 +1162,7 @@ void main() { expect(find.text('second'), findsOneWidget); }); - testWidgets('MaterialPage does not lose its state when transitioning out', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialPage does not lose its state when transitioning out', (WidgetTester tester) async { final GlobalKey navigator = GlobalKey(); await tester.pumpWidget(KeepsStateTestWidget(navigatorKey: navigator)); expect(find.text('subpage'), findsOneWidget); @@ -1173,7 +1175,7 @@ void main() { expect(find.text('home'), findsOneWidget); }); - testWidgets('MaterialPage restores its state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialPage restores its state', (WidgetTester tester) async { await tester.pumpWidget( RootRestorationScope( restorationId: 'root', @@ -1231,7 +1233,7 @@ void main() { expect(find.text('count: 1'), findsOneWidget); }); - testWidgets('MaterialPageRoute can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialPageRoute can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/132138. final GlobalKey scaffoldKey = GlobalKey(); @@ -1388,6 +1390,12 @@ class _TestRestorableWidgetState extends State with Restor ], ); } + + @override + void dispose() { + counter.dispose(); + super.dispose(); + } } class TestDependencies extends StatelessWidget { diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart index 210bc065c5785..2f79094a67c18 100644 --- a/packages/flutter/test/material/page_transitions_theme_test.dart +++ b/packages/flutter/test/material/page_transitions_theme_test.dart @@ -306,7 +306,7 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] rasterization is not used on the web. - testWidgets('_ZoomPageTransition only causes child widget built once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('_ZoomPageTransition only causes child widget built once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/58345 int builtCount = 0; diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index 53c289e8b18fe..560b0a12ed627 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -68,6 +68,7 @@ void main() { testWidgets('PaginatedDataTable paging', (WidgetTester tester) async { final TestDataSource source = TestDataSource(); + addTearDown(source.dispose); final List log = []; @@ -1218,7 +1219,9 @@ void main() { testWidgets('PaginatedDataTable can be scrolled using ScrollController', (WidgetTester tester) async { final TestDataSource source = TestDataSource(); + addTearDown(source.dispose); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildTable(TestDataSource source) { return Align( @@ -1267,7 +1270,9 @@ void main() { testWidgets('PaginatedDataTable uses PrimaryScrollController when primary ', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); final TestDataSource source = TestDataSource(); + addTearDown(source.dispose); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 1bfb2e028f868..fcc0fa1f8063e 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -9,12 +9,13 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; void main() { - testWidgets('Navigator.push works within a PopupMenuButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigator.push works within a PopupMenuButton', (WidgetTester tester) async { final Key targetKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -64,7 +65,7 @@ void main() { expect(find.text('Next'), findsOneWidget); }); - testWidgets('PopupMenuButton calls onOpened callback when the menu is opened', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton calls onOpened callback when the menu is opened', (WidgetTester tester) async { int opens = 0; late BuildContext popupContext; final Key noItemsKey = UniqueKey(); @@ -133,7 +134,7 @@ void main() { expect(opens, equals(1)); }); - testWidgets('PopupMenuButton calls onCanceled callback when an item is not selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton calls onCanceled callback when an item is not selected', (WidgetTester tester) async { int cancels = 0; late BuildContext popupContext; final Key noCallbackKey = UniqueKey(); @@ -199,7 +200,7 @@ void main() { expect(cancels, equals(2)); }); - testWidgets('Disabled PopupMenuButton will not call itemBuilder, onOpened, onSelected or onCanceled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled PopupMenuButton will not call itemBuilder, onOpened, onSelected or onCanceled', (WidgetTester tester) async { final GlobalKey popupButtonKey = GlobalKey(); bool itemBuilderCalled = false; bool onOpenedCalled = false; @@ -284,7 +285,7 @@ void main() { expect(onCanceledCalled, isFalse); }); - testWidgets('disabled PopupMenuButton is not focusable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled PopupMenuButton is not focusable', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final GlobalKey childKey = GlobalKey(); bool itemBuilderCalled = false; @@ -326,7 +327,7 @@ void main() { expect(onSelectedCalled, isFalse); }); - testWidgets('Disabled PopupMenuButton is focusable with directional navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled PopupMenuButton is focusable with directional navigation', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final GlobalKey childKey = GlobalKey(); @@ -367,7 +368,7 @@ void main() { expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isTrue); }); - testWidgets('PopupMenuItem onTap callback is called when defined', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem onTap callback is called when defined', (WidgetTester tester) async { final List menuItemTapCounters = [0, 0]; await tester.pumpWidget( @@ -429,7 +430,7 @@ void main() { expect(menuItemTapCounters, [2, 1]); }); - testWidgets('PopupMenuItem can have both onTap and value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem can have both onTap and value', (WidgetTester tester) async { final List menuItemTapCounters = [0, 0]; String? selected; @@ -500,7 +501,7 @@ void main() { expect(selected, 'third'); }); - testWidgets('PopupMenuItem is only focusable when enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem is only focusable when enabled', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final GlobalKey childKey = GlobalKey(); bool itemBuilderCalled = false; @@ -577,7 +578,7 @@ void main() { expect(Focus.of(childKey.currentContext!).hasPrimaryFocus, isFalse); }); - testWidgets('PopupMenuButton is horizontal on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton is horizontal on iOS', (WidgetTester tester) async { Widget build(TargetPlatform platform) { debugDefaultTargetPlatformOverride = platform; return MaterialApp( @@ -631,7 +632,7 @@ void main() { ]; } - testWidgets('PopupMenuButton fails when given both child and icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton fails when given both child and icon', (WidgetTester tester) async { expect(() { PopupMenuButton( icon: const Icon(Icons.view_carousel), @@ -641,7 +642,7 @@ void main() { }, throwsAssertionError); }); - testWidgets('PopupMenuButton creates IconButton when given an icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton creates IconButton when given an icon', (WidgetTester tester) async { final PopupMenuButton button = PopupMenuButton( icon: const Icon(Icons.view_carousel), itemBuilder: simplePopupMenuItemBuilder, @@ -661,7 +662,7 @@ void main() { }); }); - testWidgets('PopupMenu positioning', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu positioning', (WidgetTester tester) async { final Widget testButton = PopupMenuButton( itemBuilder: (BuildContext context) { return >[ @@ -841,8 +842,10 @@ void main() { await testPositioningDownThenUp(tester, TextDirection.rtl, Alignment.bottomCenter, TextDirection.rtl, const Rect.fromLTWH(450.0, 500.0, 0.0, 0.0)); }); - testWidgets('PopupMenu positioning inside nested Overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu positioning inside nested Overlay', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget( MaterialApp( @@ -852,7 +855,7 @@ void main() { padding: const EdgeInsets.all(8.0), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (_) => Center( child: PopupMenuButton( key: buttonKey, @@ -880,7 +883,7 @@ void main() { expect(tester.getTopLeft(popupFinder), buttonTopLeft); }); - testWidgets('PopupMenu positioning inside nested Navigator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu positioning inside nested Navigator', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -924,7 +927,7 @@ void main() { expect(tester.getTopLeft(popupFinder), buttonTopLeft); }); - testWidgets('PopupMenu positioning around display features', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu positioning around display features', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -984,7 +987,7 @@ void main() { expect(tester.getTopRight(popupFinder), const Offset(390 - 8, 8)); }); - testWidgets('PopupMenu removes MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu removes MediaQuery padding', (WidgetTester tester) async { late BuildContext popupContext; await tester.pumpWidget(MaterialApp( @@ -1025,7 +1028,7 @@ void main() { expect(MediaQuery.of(popupContext).padding, EdgeInsets.zero); }); - testWidgets('Popup Menu Offset Test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup Menu Offset Test', (WidgetTester tester) async { PopupMenuButton buildMenuButton({Offset offset = Offset.zero}) { return PopupMenuButton( offset: offset, @@ -1084,7 +1087,7 @@ void main() { expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), const Offset(50.0, 50.0)); }); - testWidgets('Opened PopupMenu has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Opened PopupMenu has correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( MaterialApp( @@ -1208,7 +1211,7 @@ void main() { semantics.dispose(); }); - testWidgets('PopupMenuItem merges the semantics of its descendants', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem merges the semantics of its descendants', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( MaterialApp( @@ -1296,7 +1299,7 @@ void main() { semantics.dispose(); }); - testWidgets('Disabled PopupMenuItem has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled PopupMenuItem has correct semantics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/45044. final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1419,7 +1422,7 @@ void main() { semantics.dispose(); }); - testWidgets('PopupMenuButton PopupMenuDivider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton PopupMenuDivider', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/27072 late String selectedValue; @@ -1471,7 +1474,7 @@ void main() { expect(selectedValue, '2'); }); - testWidgets('PopupMenuItem child height is a minimum, child is vertically centered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem child height is a minimum, child is vertically centered', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -1553,7 +1556,7 @@ void main() { ); }); - testWidgets('Material3 - PopupMenuItem default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - PopupMenuItem default padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1591,7 +1594,7 @@ void main() { expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 12.0)); }); - testWidgets('Material2 - PopupMenuItem default padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - PopupMenuItem default padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1629,7 +1632,7 @@ void main() { expect(tester.widget(find.widgetWithText(Container, 'Item 1')).padding, const EdgeInsets.symmetric(horizontal: 16.0)); }); - testWidgets('PopupMenuItem custom padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem custom padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -1691,7 +1694,7 @@ void main() { expect(tester.widget(find.widgetWithText(Container, 'Item 3')).padding, const EdgeInsets.all(20)); }); - testWidgets('CheckedPopupMenuItem child height is a minimum, child is vertically centered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckedPopupMenuItem child height is a minimum, child is vertically centered', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const CheckedPopupMenuItem(child: Text('item')).runtimeType; @@ -1780,7 +1783,7 @@ void main() { ); }); - testWidgets('CheckedPopupMenuItem custom padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckedPopupMenuItem custom padding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const CheckedPopupMenuItem(child: Text('item')).runtimeType; @@ -1841,7 +1844,7 @@ void main() { expect(tester.widget(find.widgetWithText(Container, 'Item 3')).padding, const EdgeInsets.all(20)); }); - testWidgets('Update PopupMenuItem layout while the menu is visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update PopupMenuItem layout while the menu is visible', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -1925,7 +1928,7 @@ void main() { }, throwsAssertionError); }); - testWidgets('PopupMenuButton default tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton default tooltip', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1981,7 +1984,7 @@ void main() { expect(find.byTooltip(const DefaultMaterialLocalizations().showMenuTooltip), findsNWidgets(3)); }); - testWidgets('PopupMenuButton custom tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton custom tooltip', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2038,7 +2041,7 @@ void main() { expect(find.byTooltip('Test tooltip'), findsNWidgets(3)); }); - testWidgets('Allow Widget for PopupMenuButton.icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Allow Widget for PopupMenuButton.icon', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2061,7 +2064,7 @@ void main() { expect(find.text('PopupMenuButton icon'), findsOneWidget); }); - testWidgets('showMenu uses nested navigator by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showMenu uses nested navigator by default', (WidgetTester tester) async { final MenuObserver rootObserver = MenuObserver(); final MenuObserver nestedObserver = MenuObserver(); @@ -2099,7 +2102,7 @@ void main() { expect(nestedObserver.menuCount, 1); }); - testWidgets('showMenu uses root navigator if useRootNavigator is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showMenu uses root navigator if useRootNavigator is true', (WidgetTester tester) async { final MenuObserver rootObserver = MenuObserver(); final MenuObserver nestedObserver = MenuObserver(); @@ -2138,7 +2141,7 @@ void main() { expect(nestedObserver.menuCount, 0); }); - testWidgets('PopupMenuButton calling showButtonMenu manually', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton calling showButtonMenu manually', (WidgetTester tester) async { final GlobalKey> globalKey = GlobalKey(); await tester.pumpWidget( @@ -2173,7 +2176,7 @@ void main() { expect(find.text('Tap me please!'), findsOneWidget); }); - testWidgets('PopupMenuItem changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem changes mouse cursor when hovered', (WidgetTester tester) async { const Key key = ValueKey(1); // Test PopupMenuItem() constructor await tester.pumpWidget( @@ -2252,7 +2255,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('CheckedPopupMenuItem changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckedPopupMenuItem changes mouse cursor when hovered', (WidgetTester tester) async { const Key key = ValueKey(1); // Test CheckedPopupMenuItem() constructor await tester.pumpWidget( @@ -2332,7 +2335,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('PopupMenu in AppBar does not overlap with the status bar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu in AppBar does not overlap with the status bar', (WidgetTester tester) async { const List> choices = >[ PopupMenuItem(value: 1, child: Text('Item 1')), PopupMenuItem(value: 2, child: Text('Item 2')), @@ -2391,7 +2394,7 @@ void main() { expect(tester.getTopLeft(find.byWidget(firstItem)).dy, greaterThan(statusBarHeight)); }); - testWidgets('Vertically long PopupMenu does not overlap with the status bar and bottom notch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertically long PopupMenu does not overlap with the status bar and bottom notch', (WidgetTester tester) async { const double windowPaddingTop = 44; const double windowPaddingBottom = 34; @@ -2435,7 +2438,7 @@ void main() { expect(bottomRightOfMenu.dy, 600.0 - windowPaddingBottom - 8.0); // Screen height is 600. }); - testWidgets('PopupMenu position test when have unsafe area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu position test when have unsafe area', (WidgetTester tester) async { final GlobalKey buttonKey = GlobalKey(); Widget buildFrame(double width, double height) { @@ -2493,7 +2496,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/82874 - testWidgets('PopupMenu position test when have unsafe area - left/right padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu position test when have unsafe area - left/right padding', (WidgetTester tester) async { final GlobalKey buttonKey = GlobalKey(); const EdgeInsets padding = EdgeInsets.only(left: 300.0, top: 32.0, right: 310.0, bottom: 64.0); EdgeInsets? mediaQueryPadding; @@ -2603,7 +2606,7 @@ void main() { ); } - testWidgets('PopupMenuButton enableFeedback works properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton enableFeedback works properly', (WidgetTester tester) async { expect(feedback.clickSoundCount, 0); expect(feedback.hapticCount, 0); @@ -2652,7 +2655,7 @@ void main() { }); }); - testWidgets('Can customize PopupMenuButton icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can customize PopupMenuButton icon', (WidgetTester tester) async { const Color iconColor = Color(0xffffff00); const double iconSize = 29.5; await tester.pumpWidget( @@ -2678,7 +2681,7 @@ void main() { expect(tester.getSize(find.byIcon(Icons.adaptive.more)), const Size(iconSize, iconSize)); }); - testWidgets('does not crash in small overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not crash in small overlay', (WidgetTester tester) async { final GlobalKey navigator = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -2719,7 +2722,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/80869 - testWidgets('The menu position test in the scrollable widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The menu position test in the scrollable widget', (WidgetTester tester) async { final GlobalKey buttonKey = GlobalKey(); await tester.pumpWidget( @@ -2783,7 +2786,7 @@ void main() { expect(popupMenu, const Offset(8.0, 50.0)); }); - testWidgets('PopupMenuButton custom splash radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuButton custom splash radius', (WidgetTester tester) async { Future buildFrameWithoutChild({double? splashRadius}) { return tester.pumpWidget( MaterialApp( @@ -2841,7 +2844,7 @@ void main() { testSplashRadius); }); - testWidgets('Can override menu size constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can override menu size constraints', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final Type menuItemType = const PopupMenuItem(child: Text('item')).runtimeType; @@ -2874,7 +2877,7 @@ void main() { expect(tester.getSize(find.widgetWithText(menuItemType, 'Item 0')).width, 500); }); - testWidgets('Can change menu position and offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can change menu position and offset', (WidgetTester tester) async { PopupMenuButton buildMenuButton({required PopupMenuPosition position}) { return PopupMenuButton( position: position, @@ -3003,7 +3006,7 @@ void main() { expect(tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_PopupMenu')), const Offset(8.0, 90.0)); }); - testWidgets("PopupMenuButton icon inherits IconTheme's size", (WidgetTester tester) async { + testWidgetsWithLeakTracking("PopupMenuButton icon inherits IconTheme's size", (WidgetTester tester) async { Widget buildPopupMenu({double? themeIconSize, double? iconSize}) { return MaterialApp( theme: ThemeData( @@ -3045,7 +3048,7 @@ void main() { expect(tester.getSize(find.byIcon(Icons.more_vert)), const Size(50.0, 50.0)); }); - testWidgets('Popup menu clip behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu clip behavior', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/107215 final Key popupButtonKey = UniqueKey(); const double radius = 20.0; @@ -3097,7 +3100,7 @@ void main() { expect(material.clipBehavior, Clip.hardEdge); }); - testWidgets('Uses closed loop focus traversal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses closed loop focus traversal', (WidgetTester tester) async { FocusNode nodeA() => Focus.of(find.text('A').evaluate().single); FocusNode nodeB() => Focus.of(find.text('B').evaluate().single); @@ -3171,7 +3174,7 @@ void main() { expect(nodeB().hasFocus, false); }); - testWidgets('Popup menu scrollbar inherits ScrollbarTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu scrollbar inherits ScrollbarTheme', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); const ScrollbarThemeData scrollbarTheme = ScrollbarThemeData( thumbColor: MaterialStatePropertyAll(Color(0xffff0000)), @@ -3259,7 +3262,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Popup menu with RouteSettings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu with RouteSettings', (WidgetTester tester) async { late RouteSettings currentRouteSetting; await tester.pumpWidget( @@ -3301,7 +3304,7 @@ void main() { expect(currentRouteSetting.name, '/'); }); - testWidgets('Popup menu is positioned under the child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popup menu is positioned under the child', (WidgetTester tester) async { final Key popupButtonKey = UniqueKey(); final Key childKey = UniqueKey(); await tester.pumpWidget( @@ -3339,7 +3342,7 @@ void main() { expect(childBottomLeft, menuTopLeft); }); - testWidgets('PopupMenuItem onTap should be calling after Navigator.pop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem onTap should be calling after Navigator.pop', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -3381,7 +3384,7 @@ void main() { expect(modalBottomSheet, findsOneWidget); }); - testWidgets('Material3 - CheckedPopupMenuItem.labelTextStyle uses correct text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - CheckedPopupMenuItem.labelTextStyle uses correct text style', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); ThemeData theme = ThemeData(useMaterial3: true); @@ -3444,7 +3447,7 @@ void main() { expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); }); - testWidgets('CheckedPopupMenuItem.labelTextStyle resolve material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckedPopupMenuItem.labelTextStyle resolve material states', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); final MaterialStateProperty labelTextStyle = MaterialStateProperty.resolveWith( (Set states) { @@ -3494,7 +3497,7 @@ void main() { ); }); - testWidgets('CheckedPopupMenuItem overrides redundant ListTile.contentPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckedPopupMenuItem overrides redundant ListTile.contentPadding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -3539,7 +3542,7 @@ void main() { expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); }); - testWidgets('PopupMenuItem overrides redundant ListTile.contentPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenuItem overrides redundant ListTile.contentPadding', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -3584,7 +3587,7 @@ void main() { expect(getItemSafeArea('Item 1').minimum, EdgeInsets.zero); }); - testWidgets('Material3 - PopupMenuItem overrides ListTile.titleTextStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - PopupMenuItem overrides ListTile.titleTextStyle', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); ThemeData theme = ThemeData(useMaterial3: true); @@ -3661,7 +3664,7 @@ void main() { expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); }); - testWidgets('Material2 - PopupMenuItem overrides ListTile.titleTextStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - PopupMenuItem overrides ListTile.titleTextStyle', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); ThemeData theme = ThemeData(useMaterial3: false); diff --git a/packages/flutter/test/material/radio_list_tile_test.dart b/packages/flutter/test/material/radio_list_tile_test.dart index 6507c250cbfd4..6793eb6ed8ec5 100644 --- a/packages/flutter/test/material/radio_list_tile_test.dart +++ b/packages/flutter/test/material/radio_list_tile_test.dart @@ -795,8 +795,10 @@ void main() { expect(tileNode.hasPrimaryFocus, isTrue); }); - testWidgets('RadioListTile onFocusChange callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RadioListTile onFocusChange callback', (WidgetTester tester) async { final FocusNode node = FocusNode(debugLabel: 'RadioListTile onFocusChange'); + addTearDown(node.dispose); + bool gotFocus = false; await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/radio_test.dart b/packages/flutter/test/material/radio_test.dart index f3605238b43c4..b1a1335664669 100644 --- a/packages/flutter/test/material/radio_test.dart +++ b/packages/flutter/test/material/radio_test.dart @@ -1311,7 +1311,7 @@ void main() { focusNode.dispose(); }); - testWidgets('Radio overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Radio overlay color resolves in active/pressed/focused/hovered states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -1634,7 +1634,7 @@ void main() { ); }); - testWidgets('Material2 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; @@ -1723,7 +1723,7 @@ void main() { focusNode.dispose(); }); - testWidgets('Material3 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Radio button default overlay colors in hover/focus/press states', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Radio'); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index f89cfe9957337..5bedc0cad01af 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -8,10 +8,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/105833 - testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag gesture uses provided gesture settings', (WidgetTester tester) async { RangeValues values = const RangeValues(0.1, 0.5); bool dragStarted = false; final Key sliderKey = UniqueKey(); @@ -117,7 +118,7 @@ void main() { expect(dragStarted, false); }); - testWidgets('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -171,7 +172,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgets('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -225,7 +226,7 @@ void main() { expect(values.end, moreOrLessEquals(0.9, epsilon: 0.01)); }); - testWidgets('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -283,7 +284,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgets('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can move when tapped (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -341,7 +342,7 @@ void main() { expect(values.end.round(), equals(90)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -385,7 +386,7 @@ void main() { expect(values.end, equals(1)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -429,7 +430,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -475,7 +476,7 @@ void main() { expect(values.end, equals(100)); }); - testWidgets('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged to the min and max (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -521,7 +522,7 @@ void main() { expect(values.start, equals(0)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -571,7 +572,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -621,7 +622,7 @@ void main() { expect(values.start, moreOrLessEquals(0.2, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -673,7 +674,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the start thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -725,7 +726,7 @@ void main() { expect(values.start, moreOrLessEquals(20, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -775,7 +776,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (continuous RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); await tester.pumpWidget( @@ -825,7 +826,7 @@ void main() { expect(values.end, moreOrLessEquals(0.8, epsilon: 0.05)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete LTR)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -877,7 +878,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgets('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumbs can be dragged together and the end thumb can be dragged apart (discrete RTL)', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); await tester.pumpWidget( @@ -929,7 +930,7 @@ void main() { expect(values.end, moreOrLessEquals(80, epsilon: 0.01)); }); - testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by tap', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); RangeValues? startValues; RangeValues? endValues; @@ -983,7 +984,7 @@ void main() { expect(endValues!.end, moreOrLessEquals(70, epsilon: 1)); }); - testWidgets('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider onChangeEnd and onChangeStart are called on an interaction initiated by drag', (WidgetTester tester) async { RangeValues values = const RangeValues(30, 70); late RangeValues startValues; late RangeValues endValues; @@ -1098,7 +1099,7 @@ void main() { ); } - testWidgets('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default enabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1127,7 +1128,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the active color', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1155,7 +1156,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when setting the inactive color', (WidgetTester tester) async { const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1182,7 +1183,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1215,7 +1216,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1245,7 +1246,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.disabledInactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a discrete slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1286,7 +1287,7 @@ void main() { expect(sliderBox, isNot(paints..circle(color: sliderTheme.inactiveTickMarkColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a default disabled slider', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; @@ -1306,7 +1307,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes for a disabled slider with active and inactive colors', (WidgetTester tester) async { const Color activeColor = Color(0xcafefeed); const Color inactiveColor = Color(0xdeadbeef); final ThemeData theme = buildTheme(); @@ -1333,7 +1334,7 @@ void main() { expect(sliderBox, isNot(paints..rect(color: sliderTheme.inactiveTrackColor))); }); - testWidgets('Range Slider uses the right theme colors for the right shapes when the value indicators are showing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider uses the right theme colors for the right shapes when the value indicators are showing', (WidgetTester tester) async { final ThemeData theme = buildTheme(); final SliderThemeData sliderTheme = theme.sliderTheme; RangeValues values = const RangeValues(0.5, 0.75); @@ -1391,7 +1392,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Range Slider removes value indicator from overlay if Slider gets disposed without value indicator animation completing.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider removes value indicator from overlay if Slider gets disposed without value indicator animation completing.', (WidgetTester tester) async { RangeValues values = const RangeValues(0.5, 0.75); const Color fillColor = Color(0xf55f5f5f); @@ -1495,7 +1496,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1562,7 +1563,7 @@ void main() { ); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1636,7 +1637,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider top value indicator gets stroked when overlapping with large text scale', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1713,7 +1714,7 @@ void main() { await gesture.up(); }); - testWidgets('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider thumb gets stroked when overlapping', (WidgetTester tester) async { RangeValues values = const RangeValues(0.3, 0.7); final ThemeData theme = ThemeData( @@ -1794,7 +1795,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101868 - testWidgets('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider.label info should not write to semantic node', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1852,7 +1853,7 @@ void main() { ); }); - testWidgets('Range Slider Semantics - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider Semantics - ltr', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -1936,7 +1937,7 @@ void main() { ]); }); - testWidgets('Range Slider Semantics - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider Semantics - rtl', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( @@ -2018,7 +2019,7 @@ void main() { ]); }); - testWidgets('Range Slider implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); RangeSlider( @@ -2049,7 +2050,7 @@ void main() { ]); }); - testWidgets('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is RoundedRectRange', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( @@ -2088,7 +2089,7 @@ void main() { ); }); - testWidgets('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Range Slider can be painted in a narrower constraint when track shape is Rectangular', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -2133,7 +2134,7 @@ void main() { ); }); - testWidgets('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update the divisions and values at the same time for RangeSlider', (WidgetTester tester) async { // Regress test for https://github.com/flutter/flutter/issues/65943 Widget buildFrame(double maxValue) { return MaterialApp( @@ -2177,7 +2178,7 @@ void main() { expect(nearEqual(activeTrackRect.right, (800.0 - 24.0 - 24.0) * (8 / 15) + 24.0, 0.01), true); }); - testWidgets('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider changes mouse cursor when hovered', (WidgetTester tester) async { const RangeValues values = RangeValues(50, 70); // Test default cursor. @@ -2232,7 +2233,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { RangeValues values = const RangeValues(50, 70); const MouseCursor disabledCursor = SystemMouseCursors.basic; const MouseCursor hoveredCursor = SystemMouseCursors.grab; @@ -2306,7 +2307,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), draggedCursor); }); - testWidgets('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2369,7 +2370,7 @@ void main() { ); }); - testWidgets('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); final ThemeData theme = ThemeData(); @@ -2425,7 +2426,7 @@ void main() { ); }); - testWidgets('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider overlayColor supports hovered and dragged states', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; RangeValues values = const RangeValues(50, 70); const Color hoverColor = Color(0xffff0000); @@ -2540,7 +2541,7 @@ void main() { ); }); - testWidgets('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128433 int startFired = 0; diff --git a/packages/flutter/test/material/reorderable_list_test.dart b/packages/flutter/test/material/reorderable_list_test.dart index 6bcf56fe5f378..e13dbf0437319 100644 --- a/packages/flutter/test/material/reorderable_list_test.dart +++ b/packages/flutter/test/material/reorderable_list_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('$ReorderableListView', () { @@ -71,7 +72,7 @@ void main() { }); group('in vertical mode', () { - testWidgets('reorder is not triggered when children length is less or equals to 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reorder is not triggered when children length is less or equals to 1', (WidgetTester tester) async { bool onReorderWasCalled = false; final List currentListItems = listItems.take(1).toList(); final ReorderableListView reorderableListView = ReorderableListView( @@ -97,7 +98,7 @@ void main() { expect(currentListItems, orderedEquals(['Item 1'])); }); - testWidgets('reorders its contents only when a drag finishes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reorders its contents only when a drag finishes', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(listItems, orderedEquals(originalListItems)); final TestGesture drag = await tester.startGesture(tester.getCenter(find.text('Item 1'))); @@ -110,7 +111,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 3', 'Item 1', 'Item 4'])); }); - testWidgets('allows reordering from the very top to the very bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows reordering from the very top to the very bottom', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(listItems, orderedEquals(originalListItems)); await longPressDrag( @@ -122,7 +123,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 3', 'Item 4', 'Item 1'])); }); - testWidgets('allows reordering from the very bottom to the very top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows reordering from the very bottom to the very top', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(listItems, orderedEquals(originalListItems)); await longPressDrag( @@ -134,7 +135,7 @@ void main() { expect(listItems, orderedEquals(['Item 4', 'Item 1', 'Item 2', 'Item 3'])); }); - testWidgets('allows reordering inside the middle of the widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows reordering inside the middle of the widget', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(listItems, orderedEquals(originalListItems)); await longPressDrag( @@ -146,7 +147,7 @@ void main() { expect(listItems, orderedEquals(['Item 1', 'Item 3', 'Item 2', 'Item 4'])); }); - testWidgets('properly reorders with a header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properly reorders with a header', (WidgetTester tester) async { await tester.pumpWidget(build(header: const Text('Header Text'))); expect(find.text('Header Text'), findsOneWidget); expect(listItems, orderedEquals(originalListItems)); @@ -160,7 +161,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 3', 'Item 4', 'Item 1'])); }); - testWidgets('properly reorders with a footer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properly reorders with a footer', (WidgetTester tester) async { await tester.pumpWidget(build(footer: const Text('Footer Text'))); expect(find.text('Footer Text'), findsOneWidget); expect(listItems, orderedEquals(originalListItems)); @@ -174,7 +175,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 3', 'Item 4', 'Item 1'])); }); - testWidgets('properly determines the vertical drop area extents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properly determines the vertical drop area extents', (WidgetTester tester) async { final Widget reorderableListView = ReorderableListView( onReorder: (int oldIndex, int newIndex) { }, children: const [ @@ -241,7 +242,7 @@ void main() { expect(getListHeight(), kDraggingListHeight); }); - testWidgets('Vertical drag in progress golden image', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical drag in progress golden image', (WidgetTester tester) async { debugDisableShadows = false; final Widget reorderableListView = ReorderableListView( children: [ @@ -266,6 +267,10 @@ void main() { ], onReorder: (int oldIndex, int newIndex) { }, ); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget(MaterialApp( home: Container( color: Colors.white, @@ -273,7 +278,7 @@ void main() { // Wrap in an overlay so that the golden image includes the dragged item. child: Overlay( initialEntries: [ - OverlayEntry(builder: (BuildContext context) { + entry = OverlayEntry(builder: (BuildContext context) { // Wrap the list in padding to test that the positioning // is correct when the origin of the overlay is different // from the list. @@ -305,7 +310,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('Preserves children states when the list parent changes the order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Preserves children states when the list parent changes the order', (WidgetTester tester) async { _StatefulState findState(Key key) { return find.byElementPredicate((Element element) => element.findAncestorWidgetOfExactType<_Stateful>()?.key == key) .evaluate() @@ -345,7 +350,7 @@ void main() { expect(findState(const Key('A')).checked, true); }); - testWidgets('Preserves children states when rebuilt', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Preserves children states when rebuilt', (WidgetTester tester) async { const Key firstBox = Key('key'); Widget build() { return MaterialApp( @@ -373,8 +378,9 @@ void main() { expect(e0, equals(e1)); }); - testWidgets('Uses the PrimaryScrollController when available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uses the PrimaryScrollController when available', (WidgetTester tester) async { final ScrollController primary = ScrollController(); + addTearDown(primary.dispose); final Widget reorderableList = ReorderableListView( children: const [ SizedBox(width: 100.0, height: 100.0, key: Key('C'), child: Text('C')), @@ -405,6 +411,8 @@ void main() { // Now try changing the primary scroll controller and checking that the scroll view gets updated. final ScrollController primary2 = ScrollController(); + addTearDown(primary2.dispose); + await tester.pumpWidget(buildWithScrollController(primary2)); scrollView = tester.widget( find.byType(Scrollable), @@ -412,11 +420,13 @@ void main() { expect(scrollView.controller, primary2); }); - testWidgets('Test custom ScrollController behavior when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Test custom ScrollController behavior when set', (WidgetTester tester) async { const Key firstBox = Key('C'); const Key secondBox = Key('B'); const Key thirdBox = Key('A'); final ScrollController customController = ScrollController(); + addTearDown(customController.dispose); + await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -474,9 +484,11 @@ void main() { expect(customController.offset, 120.0); }); - testWidgets('ReorderableList auto scrolling is fast enough', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableList auto scrolling is fast enough', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/121603. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -513,7 +525,7 @@ void main() { expect(controller.offset, greaterThan(kMinimumAllowedAutoScrollDistancePer5ms * 4)); }); - testWidgets('Still builds when no PrimaryScrollController is available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Still builds when no PrimaryScrollController is available', (WidgetTester tester) async { final Widget reorderableList = ReorderableListView( children: const [ SizedBox(width: 100.0, height: 100.0, key: Key('C'), child: Text('C')), @@ -522,9 +534,13 @@ void main() { ], onReorder: (int oldIndex, int newIndex) { }, ); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + final Widget overlay = Overlay( initialEntries: [ - OverlayEntry(builder: (BuildContext context) => reorderableList), + entry = OverlayEntry(builder: (BuildContext context) => reorderableList), ], ); final Widget boilerplate = Localizations( @@ -562,7 +578,7 @@ void main() { const CustomSemanticsAction moveUp = CustomSemanticsAction(label: 'Move up'); const CustomSemanticsAction moveDown = CustomSemanticsAction(label: 'Move down'); - testWidgets('Provides the correct accessibility actions in LTR and RTL modes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Provides the correct accessibility actions in LTR and RTL modes', (WidgetTester tester) async { // The a11y actions for a vertical list are the same in LTR and RTL modes. final SemanticsHandle handle = tester.ensureSemantics(); for (final TextDirection direction in TextDirection.values) { @@ -597,7 +613,7 @@ void main() { handle.dispose(); }); - testWidgets('First item accessibility (a11y) actions work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('First item accessibility (a11y) actions work', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); expect(listItems, orderedEquals(originalListItems)); @@ -618,7 +634,7 @@ void main() { handle.dispose(); }); - testWidgets('Middle item accessibility (a11y) actions work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Middle item accessibility (a11y) actions work', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); expect(listItems, orderedEquals(originalListItems)); @@ -653,7 +669,7 @@ void main() { handle.dispose(); }); - testWidgets('Last item accessibility (a11y) actions work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Last item accessibility (a11y) actions work', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); expect(listItems, orderedEquals(originalListItems)); @@ -674,7 +690,7 @@ void main() { handle.dispose(); }); - testWidgets("Doesn't hide accessibility when a child declares its own semantics", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Doesn't hide accessibility when a child declares its own semantics", (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final Widget reorderableListView = ReorderableListView( onReorder: (int oldIndex, int newIndex) { }, @@ -743,7 +759,7 @@ void main() { }); group('in horizontal mode', () { - testWidgets('reorder is not triggered when children length is less or equals to 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reorder is not triggered when children length is less or equals to 1', (WidgetTester tester) async { bool onReorderWasCalled = false; final List currentListItems = listItems.take(1).toList(); final ReorderableListView reorderableListView = ReorderableListView( @@ -770,7 +786,7 @@ void main() { expect(currentListItems, orderedEquals(['Item 1'])); }); - testWidgets('allows reordering from the very top to the very bottom', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows reordering from the very top to the very bottom', (WidgetTester tester) async { await tester.pumpWidget(build(scrollDirection: Axis.horizontal)); expect(listItems, orderedEquals(originalListItems)); await longPressDrag( @@ -782,7 +798,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 3', 'Item 4', 'Item 1'])); }); - testWidgets('allows reordering from the very bottom to the very top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows reordering from the very bottom to the very top', (WidgetTester tester) async { await tester.pumpWidget(build(scrollDirection: Axis.horizontal)); expect(listItems, orderedEquals(originalListItems)); await longPressDrag( @@ -794,7 +810,7 @@ void main() { expect(listItems, orderedEquals(['Item 4', 'Item 1', 'Item 2', 'Item 3'])); }); - testWidgets('allows reordering inside the middle of the widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows reordering inside the middle of the widget', (WidgetTester tester) async { await tester.pumpWidget(build(scrollDirection: Axis.horizontal)); expect(listItems, orderedEquals(originalListItems)); await longPressDrag( @@ -806,7 +822,7 @@ void main() { expect(listItems, orderedEquals(['Item 1', 'Item 3', 'Item 2', 'Item 4'])); }); - testWidgets('properly reorders with a header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properly reorders with a header', (WidgetTester tester) async { await tester.pumpWidget(build(header: const Text('Header Text'), scrollDirection: Axis.horizontal)); expect(find.text('Header Text'), findsOneWidget); expect(listItems, orderedEquals(originalListItems)); @@ -829,7 +845,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 4', 'Item 3', 'Item 1'])); }); - testWidgets('properly reorders with a footer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properly reorders with a footer', (WidgetTester tester) async { await tester.pumpWidget(build(footer: const Text('Footer Text'), scrollDirection: Axis.horizontal)); expect(find.text('Footer Text'), findsOneWidget); expect(listItems, orderedEquals(originalListItems)); @@ -852,7 +868,7 @@ void main() { expect(listItems, orderedEquals(['Item 2', 'Item 4', 'Item 3', 'Item 1'])); }); - testWidgets('properly determines the horizontal drop area extents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properly determines the horizontal drop area extents', (WidgetTester tester) async { final Widget reorderableListView = ReorderableListView( scrollDirection: Axis.horizontal, onReorder: (int oldIndex, int newIndex) { }, @@ -920,7 +936,7 @@ void main() { expect(getListWidth(), kDraggingListWidth); }); - testWidgets('Horizontal drag in progress golden image', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal drag in progress golden image', (WidgetTester tester) async { debugDisableShadows = false; final Widget reorderableListView = ReorderableListView( scrollDirection: Axis.horizontal, @@ -946,6 +962,10 @@ void main() { ), ], ); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget(MaterialApp( home: Container( color: Colors.white, @@ -953,7 +973,7 @@ void main() { // Wrap in an overlay so that the golden image includes the dragged item. child: Overlay( initialEntries: [ - OverlayEntry(builder: (BuildContext context) { + entry = OverlayEntry(builder: (BuildContext context) { // Wrap the list in padding to test that the positioning // is correct when the origin of the overlay is different // from the list. @@ -985,7 +1005,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('Preserves children states when the list parent changes the order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Preserves children states when the list parent changes the order', (WidgetTester tester) async { _StatefulState findState(Key key) { return find.byElementPredicate((Element element) => element.findAncestorWidgetOfExactType<_Stateful>()?.key == key) .evaluate() @@ -1027,7 +1047,7 @@ void main() { expect(findState(const Key('A')).checked, true); }); - testWidgets('Preserves children states when rebuilt', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Preserves children states when rebuilt', (WidgetTester tester) async { const Key firstBox = Key('key'); Widget build() { return MaterialApp( @@ -1070,7 +1090,7 @@ void main() { const CustomSemanticsAction moveLeft = CustomSemanticsAction(label: 'Move left'); const CustomSemanticsAction moveRight = CustomSemanticsAction(label: 'Move right'); - testWidgets('Provides the correct accessibility actions in LTR mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Provides the correct accessibility actions in LTR mode', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget(build(scrollDirection: Axis.horizontal)); @@ -1103,7 +1123,7 @@ void main() { handle.dispose(); }); - testWidgets('Provides the correct accessibility actions in Right-To-Left directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Provides the correct accessibility actions in Right-To-Left directionality', (WidgetTester tester) async { // In RTL mode, the right is the start and the left is the end. // The array representation is unchanged (LTR), but the direction of the motion actions is reversed. final SemanticsHandle handle = tester.ensureSemantics(); @@ -1138,7 +1158,7 @@ void main() { handle.dispose(); }); - testWidgets('First item accessibility (a11y) actions work in LTR mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('First item accessibility (a11y) actions work in LTR mode', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); expect(listItems, orderedEquals(originalListItems)); @@ -1159,7 +1179,7 @@ void main() { handle.dispose(); }); - testWidgets('First item accessibility (a11y) actions work in Right-To-Left directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('First item accessibility (a11y) actions work in Right-To-Left directionality', (WidgetTester tester) async { // In RTL mode, the right is the start and the left is the end. // The array representation is unchanged (LTR), but the direction of the motion actions is reversed. final SemanticsHandle handle = tester.ensureSemantics(); @@ -1182,7 +1202,7 @@ void main() { handle.dispose(); }); - testWidgets('Middle item accessibility (a11y) actions work in LTR mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Middle item accessibility (a11y) actions work in LTR mode', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); expect(listItems, orderedEquals(originalListItems)); @@ -1217,7 +1237,7 @@ void main() { handle.dispose(); }); - testWidgets('Middle item accessibility (a11y) actions work in Right-To-Left directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Middle item accessibility (a11y) actions work in Right-To-Left directionality', (WidgetTester tester) async { // In RTL mode, the right is the start and the left is the end. // The array representation is unchanged (LTR), but the direction of the motion actions is reversed. final SemanticsHandle handle = tester.ensureSemantics(); @@ -1254,7 +1274,7 @@ void main() { handle.dispose(); }); - testWidgets('Last item accessibility (a11y) actions work in LTR mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Last item accessibility (a11y) actions work in LTR mode', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); expect(listItems, orderedEquals(originalListItems)); @@ -1275,7 +1295,7 @@ void main() { handle.dispose(); }); - testWidgets('Last item accessibility (a11y) actions work in Right-To-Left directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Last item accessibility (a11y) actions work in Right-To-Left directionality', (WidgetTester tester) async { // In RTL mode, the right is the start and the left is the end. // The array representation is unchanged (LTR), but the direction of the motion actions is reversed. final SemanticsHandle handle = tester.ensureSemantics(); @@ -1302,7 +1322,7 @@ void main() { }); - testWidgets('ReorderableListView.builder asserts on negative childCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView.builder asserts on negative childCount', (WidgetTester tester) async { expect(() => ReorderableListView.builder( itemBuilder: (BuildContext context, int index) { return const SizedBox(); @@ -1312,7 +1332,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('ReorderableListView.builder only creates the children it needs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView.builder only creates the children it needs', (WidgetTester tester) async { final Set itemsCreated = {}; await tester.pumpWidget(MaterialApp( home: ReorderableListView.builder( @@ -1330,7 +1350,7 @@ void main() { }); group('Padding', () { - testWidgets('Padding with no header & footer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding with no header & footer', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.fromLTRB(10, 20, 30, 40); // Vertical @@ -1344,7 +1364,7 @@ void main() { expect(tester.getRect(find.byKey(const Key('Item 4'))), const Rect.fromLTRB(154, 20, 202, 560)); }); - testWidgets('Padding with header or footer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding with header or footer', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.fromLTRB(10, 20, 30, 40); const Key headerKey = Key('Header'); const Key footerKey = Key('Footer'); @@ -1403,7 +1423,7 @@ void main() { }); }); - testWidgets('ReorderableListView can be reversed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView can be reversed', (WidgetTester tester) async { final Widget reorderableListView = ReorderableListView( reverse: true, onReorder: (int oldIndex, int newIndex) { }, @@ -1428,7 +1448,7 @@ void main() { expect(tester.getCenter(find.text('A')).dy, greaterThan(tester.getCenter(find.text('B')).dy)); }); - testWidgets('Animation test when placing an item in place', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animation test when placing an item in place', (WidgetTester tester) async { const Key testItemKey = Key('Test item'); final Widget reorderableListView = ReorderableListView( onReorder: (int oldIndex, int newIndex) { }, @@ -1480,21 +1500,21 @@ void main() { }); // TODO(djshuckerow): figure out how to write a test for scrolling the list. - testWidgets('ReorderableListView on desktop platforms should have drag handles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView on desktop platforms should have drag handles', (WidgetTester tester) async { await tester.pumpWidget(build()); // All four items should have drag handles and not delayed listeners. expect(find.byIcon(Icons.drag_handle), findsNWidgets(4)); expect(find.byType(ReorderableDelayedDragStartListener), findsNothing); }, variant: TargetPlatformVariant.desktop()); - testWidgets('ReorderableListView on mobile platforms should not have drag handles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView on mobile platforms should not have drag handles', (WidgetTester tester) async { await tester.pumpWidget(build()); // All four items should have delayed listeners and not drag handles. expect(find.byType(ReorderableDelayedDragStartListener), findsNWidgets(4)); expect(find.byIcon(Icons.drag_handle), findsNothing); }, variant: TargetPlatformVariant.mobile()); - testWidgets('Vertical list renders drag handle in correct position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical list renders drag handle in correct position', (WidgetTester tester) async { await tester.pumpWidget(build(platform: TargetPlatform.macOS)); final Finder listView = find.byType(ReorderableListView); final Finder item1 = find.byKey(const Key('Item 1')); @@ -1505,7 +1525,7 @@ void main() { expect(tester.getTopRight(dragHandle).dx, tester.getSize(listView).width - 8); }); - testWidgets('Horizontal list renders drag handle in correct position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal list renders drag handle in correct position', (WidgetTester tester) async { await tester.pumpWidget(build(scrollDirection: Axis.horizontal, platform: TargetPlatform.macOS)); final Finder listView = find.byType(ReorderableListView); final Finder item1 = find.byKey(const Key('Item 1')); @@ -1517,7 +1537,7 @@ void main() { }); }); - testWidgets('ReorderableListView, can deal with the dragged item getting unmounted and rebuilt during drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView, can deal with the dragged item getting unmounted and rebuilt during drag', (WidgetTester tester) async { // See https://github.com/flutter/flutter/issues/74840 for more details. final List items = List.generate(100, (int index) => index); @@ -1585,7 +1605,7 @@ void main() { expect(items.take(8), orderedEquals([0, 1, 2, 3, 4, 5, 6, 7])); }); - testWidgets('ReorderableListView calls onReorderStart and onReorderEnd correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView calls onReorderStart and onReorderEnd correctly', (WidgetTester tester) async { final List items = List.generate(8, (int index) => index); int? startIndex, endIndex; final Finder item0 = find.textContaining('item 0'); @@ -1661,7 +1681,7 @@ void main() { expect(endIndex, equals(0)); }); - testWidgets('ReorderableListView throws an error when key is not passed to its children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView throws an error when key is not passed to its children', (WidgetTester tester) async { final Widget reorderableListView = ReorderableListView.builder( itemBuilder: (BuildContext context, int index) { return SizedBox(child: Text('Item $index')); @@ -1677,7 +1697,7 @@ void main() { expect(exception.toString(), contains('Every item of ReorderableListView must have a key.')); }); - testWidgets('Throws an error if no overlay present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws an error if no overlay present', (WidgetTester tester) async { final Widget reorderableList = ReorderableListView( children: const [ SizedBox(width: 100.0, height: 100.0, key: Key('C'), child: Text('C')), @@ -1709,7 +1729,7 @@ void main() { expect(exception.toString(), contains('ReorderableListView widgets require an Overlay widget ancestor')); }); - testWidgets('ReorderableListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { expect(() => ReorderableListView( itemExtent: 30, prototypeItem: const SizedBox(), @@ -1718,7 +1738,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('ReorderableListView.builder asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView.builder asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { final List numbers = [0,1,2]; expect(() => ReorderableListView.builder( itemBuilder: (BuildContext context, int index) { @@ -1738,7 +1758,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { final List numbers = [0,1,2]; await tester.pumpWidget( @@ -1777,7 +1797,7 @@ void main() { expect(item2Height, 30.0); }); - testWidgets('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { final List numbers = [0,1,2]; await tester.pumpWidget( @@ -1819,7 +1839,7 @@ void main() { expect(item2Height, 30.0); }); - testWidgets('ReorderableListView auto scrolls speed is configurable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableListView auto scrolls speed is configurable', (WidgetTester tester) async { Future pumpFor({ required Duration duration, Duration interval = const Duration(milliseconds: 50), @@ -1837,6 +1857,7 @@ void main() { Future pumpListAndDrag({required double autoScrollerVelocityScalar}) async { final List items = List.generate(10, (int index) => index); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/scaffold_test.dart b/packages/flutter/test/material/scaffold_test.dart index 55b38c18c86b2..28f87f4aa85cb 100644 --- a/packages/flutter/test/material/scaffold_test.dart +++ b/packages/flutter/test/material/scaffold_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -18,8 +19,10 @@ const Duration _bottomSheetExitDuration = Duration(milliseconds: 200); void main() { // Regression test for https://github.com/flutter/flutter/issues/103741 - testWidgets('extendBodyBehindAppBar change should not cause the body widget lose state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extendBodyBehindAppBar change should not cause the body widget lose state', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + Widget buildFrame({required bool extendBodyBehindAppBar}) { return MediaQuery( data: const MediaQueryData(), @@ -50,7 +53,7 @@ void main() { expect(controller.position.pixels, 100.0); }); - testWidgets('Scaffold drawer callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold drawer callback test', (WidgetTester tester) async { bool isDrawerOpen = false; bool isEndDrawerOpen = false; @@ -89,7 +92,7 @@ void main() { expect(isEndDrawerOpen, false); }); - testWidgets('Scaffold drawer callback test - only call when changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold drawer callback test - only call when changed', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/87914 bool onDrawerChangedCalled = false; bool onEndDrawerChangedCalled = false; @@ -123,7 +126,7 @@ void main() { expect(onEndDrawerChangedCalled, false); }); - testWidgets('Scaffold control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold control test', (WidgetTester tester) async { final Key bodyKey = UniqueKey(); Widget boilerplate(Widget child) { return Localizations( @@ -173,7 +176,7 @@ void main() { expect(bodyBox.size, equals(const Size(800.0, 544.0))); }); - testWidgets('Scaffold large bottom padding test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold large bottom padding test', (WidgetTester tester) async { final Key bodyKey = UniqueKey(); Widget boilerplate(Widget child) { @@ -230,7 +233,7 @@ void main() { expect(bodyBox.size, equals(const Size(800.0, 0.0))); }); - testWidgets('Floating action entrance/exit animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating action entrance/exit animation', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Scaffold( floatingActionButton: FloatingActionButton( key: Key('one'), @@ -346,7 +349,7 @@ void main() { } }); - testWidgets('Floating action button directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating action button directionality', (WidgetTester tester) async { Widget build(TextDirection textDirection) { return Directionality( textDirection: textDirection, @@ -374,7 +377,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(44.0, 356.0)); }); - testWidgets('Floating Action Button bottom padding not consumed by viewInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button bottom padding not consumed by viewInsets', (WidgetTester tester) async { final Widget child = Directionality( textDirection: TextDirection.ltr, child: Scaffold( @@ -412,7 +415,7 @@ void main() { expect(initialPoint, finalPoint); }); - testWidgets('viewPadding change should trigger _ScaffoldLayout re-layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('viewPadding change should trigger _ScaffoldLayout re-layout', (WidgetTester tester) async { Widget buildFrame(EdgeInsets viewPadding) { return MediaQuery( data: MediaQueryData( @@ -443,11 +446,12 @@ void main() { expect(renderBox.debugNeedsLayout, true); }); - testWidgets('Drawer scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer scrolling', (WidgetTester tester) async { final Key drawerKey = UniqueKey(); const double appBarHeight = 256.0; final ScrollController scrollOffset = ScrollController(); + addTearDown(scrollOffset.dispose); await tester.pumpWidget( MaterialApp( @@ -526,7 +530,7 @@ void main() { ); } - testWidgets('Tapping the status bar scrolls to top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping the status bar scrolls to top', (WidgetTester tester) async { await tester.pumpWidget(buildStatusBarTestApp(debugDefaultTargetPlatformOverride)); final ScrollableState scrollable = tester.state(find.byType(Scrollable)); scrollable.position.jumpTo(500.0); @@ -536,7 +540,7 @@ void main() { expect(scrollable.position.pixels, equals(0.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Tapping the status bar scrolls to top with ease out curve animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping the status bar scrolls to top with ease out curve animation', (WidgetTester tester) async { const int duration = 1000; final List stops = [0.842, 0.959, 0.993, 1.0]; const double scrollOffset = 1000; @@ -565,7 +569,7 @@ void main() { expect(scrollable.position.pixels, equals(0.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Tapping the status bar does not scroll to top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping the status bar does not scroll to top', (WidgetTester tester) async { await tester.pumpWidget(buildStatusBarTestApp(TargetPlatform.android)); final ScrollableState scrollable = tester.state(find.byType(Scrollable)); scrollable.position.jumpTo(500.0); @@ -576,7 +580,7 @@ void main() { expect(scrollable.position.pixels, equals(500.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.android })); - testWidgets('Bottom sheet cannot overlap app bar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Bottom sheet cannot overlap app bar', (WidgetTester tester) async { final Key sheetKey = UniqueKey(); await tester.pumpWidget( @@ -650,7 +654,7 @@ void main() { expect(initialPoint, finalPoint); }); - testWidgets('Persistent bottom buttons are persistent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Persistent bottom buttons are persistent', (WidgetTester tester) async { bool didPressButton = false; await tester.pumpWidget( MaterialApp( @@ -680,7 +684,7 @@ void main() { expect(didPressButton, isTrue); }); - testWidgets('Persistent bottom buttons alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Persistent bottom buttons alignment', (WidgetTester tester) async { Widget buildApp(AlignmentDirectional persistentAlignment) { return MaterialApp( home: Scaffold( @@ -715,7 +719,7 @@ void main() { expect(tester.getTopLeft(footerButton).dx, 8.0); }); - testWidgets('Persistent bottom buttons apply media padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Persistent bottom buttons apply media padding', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -742,7 +746,7 @@ void main() { expect(tester.getBottomRight(buttonsBar), const Offset(770.0, 560.0)); }); - testWidgets('persistentFooterButtons with bottomNavigationBar apply SafeArea properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('persistentFooterButtons with bottomNavigationBar apply SafeArea properly', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/92039 await tester.pumpWidget( MaterialApp( @@ -792,7 +796,7 @@ void main() { expect(tester.getTopLeft(buttonsBar), const Offset(0.0, 488.0)); }); - testWidgets('Persistent bottom buttons bottom padding is not consumed by viewInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Persistent bottom buttons bottom padding is not consumed by viewInsets', (WidgetTester tester) async { final Widget child = Directionality( textDirection: TextDirection.ltr, child: Scaffold( @@ -845,11 +849,11 @@ void main() { expect(icon.icon, expectedIcon); } - testWidgets('Back arrow uses correct default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Back arrow uses correct default', (WidgetTester tester) async { await expectBackIcon(tester, Icons.arrow_back); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia })); - testWidgets('Back arrow uses correct default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Back arrow uses correct default', (WidgetTester tester) async { await expectBackIcon(tester, kIsWeb ? Icons.arrow_back : Icons.arrow_back_ios); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); }); @@ -900,21 +904,21 @@ void main() { ); } - testWidgets('Close button shows correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Close button shows correctly', (WidgetTester tester) async { await expectCloseIcon(tester, materialRouteBuilder, 'materialRouteBuilder'); }, variant: TargetPlatformVariant.all()); - testWidgets('Close button shows correctly with PageRouteBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Close button shows correctly with PageRouteBuilder', (WidgetTester tester) async { await expectCloseIcon(tester, pageRouteBuilder, 'pageRouteBuilder'); }, variant: TargetPlatformVariant.all()); - testWidgets('Close button shows correctly with custom page route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Close button shows correctly with custom page route', (WidgetTester tester) async { await expectCloseIcon(tester, customPageRouteBuilder, 'customPageRouteBuilder'); }, variant: TargetPlatformVariant.all()); }); group('body size', () { - testWidgets('body size with container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('body size with container', (WidgetTester tester) async { final Key testKey = UniqueKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -931,7 +935,7 @@ void main() { expect(tester.renderObject(find.byKey(testKey)).localToGlobal(Offset.zero), Offset.zero); }); - testWidgets('body size with sized container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('body size with sized container', (WidgetTester tester) async { final Key testKey = UniqueKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -949,7 +953,7 @@ void main() { expect(tester.renderObject(find.byKey(testKey)).localToGlobal(Offset.zero), Offset.zero); }); - testWidgets('body size with centered container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('body size with centered container', (WidgetTester tester) async { final Key testKey = UniqueKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -968,7 +972,7 @@ void main() { expect(tester.renderObject(find.byKey(testKey)).localToGlobal(Offset.zero), Offset.zero); }); - testWidgets('body size with button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('body size with button', (WidgetTester tester) async { final Key testKey = UniqueKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -987,7 +991,7 @@ void main() { expect(tester.renderObject(find.byKey(testKey)).localToGlobal(Offset.zero), Offset.zero); }); - testWidgets('body size with extendBody', (WidgetTester tester) async { + testWidgetsWithLeakTracking('body size with extendBody', (WidgetTester tester) async { final Key bodyKey = UniqueKey(); late double mediaQueryBottom; @@ -1044,7 +1048,7 @@ void main() { expect(mediaQueryBottom, 0.0); }); - testWidgets('body size with extendBodyBehindAppBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('body size with extendBodyBehindAppBar', (WidgetTester tester) async { final Key appBarKey = UniqueKey(); final Key bodyKey = UniqueKey(); @@ -1141,7 +1145,7 @@ void main() { }); }); - testWidgets('Open drawer hides underlying semantics tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Open drawer hides underlying semantics tree', (WidgetTester tester) async { const String bodyLabel = 'I am the body'; const String persistentFooterButtonLabel = 'a button on the bottom'; const String bottomNavigationBarLabel = 'a bar in an app'; @@ -1177,7 +1181,7 @@ void main() { semantics.dispose(); }); - testWidgets('Scaffold and extreme window padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold and extreme window padding', (WidgetTester tester) async { final Key appBar = UniqueKey(); final Key body = UniqueKey(); final Key floatingActionButton = UniqueKey(); @@ -1282,7 +1286,7 @@ void main() { expect(tester.getRect(find.byKey(insideBottomNavigationBar)), const Rect.fromLTRB(20.0, 515.0, 750.0, 540.0)); }); - testWidgets('Scaffold and extreme window padding - persistent footer buttons only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold and extreme window padding - persistent footer buttons only', (WidgetTester tester) async { final Key appBar = UniqueKey(); final Key body = UniqueKey(); final Key floatingActionButton = UniqueKey(); @@ -1377,7 +1381,7 @@ void main() { group('ScaffoldGeometry', () { - testWidgets('bottomNavigationBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bottomNavigationBar', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp(home: Scaffold( body: Container(), @@ -1399,7 +1403,7 @@ void main() { ); }); - testWidgets('no bottomNavigationBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no bottomNavigationBar', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(home: Scaffold( body: ConstrainedBox( constraints: const BoxConstraints.expand(height: 80.0), @@ -1416,7 +1420,7 @@ void main() { ); }); - testWidgets('Scaffold BottomNavigationBar bottom padding is not consumed by viewInsets.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold BottomNavigationBar bottom padding is not consumed by viewInsets.', (WidgetTester tester) async { Widget boilerplate(Widget child) { return Localizations( locale: const Locale('en', 'us'), @@ -1479,7 +1483,7 @@ void main() { expect(initialPoint, finalPoint); }); - testWidgets('floatingActionButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('floatingActionButton', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp(home: Scaffold( body: Container(), @@ -1502,7 +1506,7 @@ void main() { ); }); - testWidgets('no floatingActionButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no floatingActionButton', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(home: Scaffold( body: ConstrainedBox( constraints: const BoxConstraints.expand(height: 80.0), @@ -1519,7 +1523,7 @@ void main() { ); }); - testWidgets('floatingActionButton entrance/exit animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('floatingActionButton entrance/exit animation', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(MaterialApp(home: Scaffold( body: ConstrainedBox( @@ -1581,7 +1585,7 @@ void main() { ); }); - testWidgets('change notifications', (WidgetTester tester) async { + testWidgetsWithLeakTracking('change notifications', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); int numNotificationsAtLastFrame = 0; await tester.pumpWidget(MaterialApp(home: Scaffold( @@ -1619,7 +1623,7 @@ void main() { numNotificationsAtLastFrame = listenerState.numNotifications; }); - testWidgets('Simultaneous drawers on either side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simultaneous drawers on either side', (WidgetTester tester) async { const String bodyLabel = 'I am the body'; const String drawerLabel = 'I am the label on start side'; const String endDrawerLabel = 'I am the label on end side'; @@ -1653,7 +1657,7 @@ void main() { semantics.dispose(); }); - testWidgets('Drawer state query correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer state query correctly', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SafeArea( @@ -1709,7 +1713,7 @@ void main() { expect(scaffoldState.isDrawerOpen, true); }); - testWidgets('Dual Drawer Opening', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dual Drawer Opening', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SafeArea( @@ -1761,7 +1765,7 @@ void main() { expect(find.text('drawer'), findsOneWidget); }); - testWidgets('Drawer opens correctly with padding from MediaQuery (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer opens correctly with padding from MediaQuery (LTR)', (WidgetTester tester) async { const double simulatedNotchSize = 40.0; await tester.pumpWidget( MaterialApp( @@ -1815,7 +1819,7 @@ void main() { expect(scaffoldState.isDrawerOpen, true); }); - testWidgets('Drawer opens correctly with padding from MediaQuery (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer opens correctly with padding from MediaQuery (RTL)', (WidgetTester tester) async { const double simulatedNotchSize = 40.0; await tester.pumpWidget( MaterialApp( @@ -1879,7 +1883,7 @@ void main() { }); }); - testWidgets('Drawer opens correctly with custom edgeDragWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer opens correctly with custom edgeDragWidth', (WidgetTester tester) async { // The default edge drag width is 20.0. await tester.pumpWidget( MaterialApp( @@ -1925,7 +1929,7 @@ void main() { expect(scaffoldState.isDrawerOpen, true); }); - testWidgets('Drawer does not open with a drag gesture when it is disabled on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer does not open with a drag gesture when it is disabled on mobile', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1989,7 +1993,7 @@ void main() { expect(scaffoldState.isDrawerOpen, false); }, variant: TargetPlatformVariant.mobile()); - testWidgets('Drawer does not open with a drag gesture on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer does not open with a drag gesture on desktop', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -2029,7 +2033,7 @@ void main() { expect(scaffoldState.isDrawerOpen, false); }, variant: TargetPlatformVariant.desktop()); - testWidgets('End drawer does not open with a drag gesture when it is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('End drawer does not open with a drag gesture when it is disabled', (WidgetTester tester) async { late double screenWidth; await tester.pumpWidget( MaterialApp( @@ -2099,7 +2103,7 @@ void main() { expect(scaffoldState.isEndDrawerOpen, false); }); - testWidgets('Nested scaffold body insets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested scaffold body insets', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/20295 final Key bodyKey = UniqueKey(); @@ -2200,7 +2204,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'didUpdate bottomSheet while a previous bottom sheet is still displayed', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -2255,7 +2259,7 @@ void main() { }, ); - testWidgets('Call to Scaffold.of() without context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Call to Scaffold.of() without context', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Builder( @@ -2328,7 +2332,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Call to Scaffold.geometryOf() without context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Call to Scaffold.geometryOf() without context', (WidgetTester tester) async { ValueListenable? geometry; await tester.pumpWidget( MaterialApp( @@ -2394,7 +2398,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('FloatingActionButton always keeps the same position regardless of extendBodyBehindAppBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FloatingActionButton always keeps the same position regardless of extendBodyBehindAppBar', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( appBar: AppBar(), @@ -2424,7 +2428,7 @@ void main() { }); }); - testWidgets('ScaffoldMessenger.maybeOf can return null if not found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger.maybeOf can return null if not found', (WidgetTester tester) async { ScaffoldMessengerState? scaffoldMessenger; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(Directionality( @@ -2455,7 +2459,7 @@ void main() { expect(scaffoldMessenger, isNull); }); - testWidgets('ScaffoldMessenger.of will assert if not found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger.of will assert if not found', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); final List exceptions = []; @@ -2518,7 +2522,7 @@ void main() { )); }); - testWidgets('ScaffoldMessenger checks for nesting when a new Scaffold is registered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger checks for nesting when a new Scaffold is registered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/77251 const String snackBarContent = 'SnackBar Content'; await tester.pumpWidget(MaterialApp( @@ -2589,7 +2593,7 @@ void main() { expect(find.text(snackBarContent), findsNothing); }); - testWidgets('Drawer can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/106131 bool isDrawerOpen = false; bool isEndDrawerOpen = false; @@ -2637,7 +2641,7 @@ void main() { expect(isEndDrawerOpen, false); }); - testWidgets('ScaffoldMessenger showSnackBar throws an intuitive error message if called during build', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger showSnackBar throws an intuitive error message if called during build', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Builder( @@ -2756,7 +2760,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('showBottomSheet removes scrim when draggable sheet is dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showBottomSheet removes scrim when draggable sheet is dismissed', (WidgetTester tester) async { final DraggableScrollableController draggableController = DraggableScrollableController(); final GlobalKey scaffoldKey = GlobalKey(); PersistentBottomSheetController? sheetController; @@ -2802,7 +2806,7 @@ void main() { expect(findModalBarrier(), findsNothing); }); - testWidgets("Closing bottom sheet & removing FAB at the same time doesn't throw assertion", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Closing bottom sheet & removing FAB at the same time doesn't throw assertion", (WidgetTester tester) async { final Key bottomSheetKey = UniqueKey(); PersistentBottomSheetController? controller; bool show = true; diff --git a/packages/flutter/test/material/scrollbar_paint_test.dart b/packages/flutter/test/material/scrollbar_paint_test.dart index 8c3ac02dd9127..09be56932fa0f 100644 --- a/packages/flutter/test/material/scrollbar_paint_test.dart +++ b/packages/flutter/test/material/scrollbar_paint_test.dart @@ -78,7 +78,7 @@ void main() { ); }); - testWidgets('works with MaterialApp and Scaffold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with MaterialApp and Scaffold', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -122,7 +122,7 @@ void main() { ); }); - testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { + testWidgetsWithLeakTracking("should not paint when there isn't enough space", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index 0a750cbc03322..a062cb0bbec03 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -791,7 +791,7 @@ void main() { scrollController.dispose(); }); - testWidgets('Scrollbar never goes away until finger lift', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar never goes away until finger lift', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scrollbar( diff --git a/packages/flutter/test/material/slider_test.dart b/packages/flutter/test/material/slider_test.dart index 10117fc38afba..cdc043fa31514 100644 --- a/packages/flutter/test/material/slider_test.dart +++ b/packages/flutter/test/material/slider_test.dart @@ -13,6 +13,7 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -100,7 +101,7 @@ class _StateDependentMouseCursor extends MaterialStateMouseCursor { } void main() { - testWidgets('The initial value should respect the discrete value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The initial value should respect the discrete value', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.20; final List log = []; @@ -140,7 +141,7 @@ void main() { expect(log[0], const Offset(212.0, 300.0)); }); - testWidgets('Slider can move when tapped (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can move when tapped (LTR)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; double? startValue; @@ -199,7 +200,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider can move when tapped (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can move when tapped (RTL)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; @@ -244,7 +245,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets("Slider doesn't send duplicate change events if tapped on the same value", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Slider doesn't send duplicate change events if tapped on the same value", (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; late double startValue; @@ -301,7 +302,7 @@ void main() { expect(endValueUpdates, equals(2)); }); - testWidgets('Value indicator shows for a bit after being tapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Value indicator shows for a bit after being tapped', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; @@ -351,7 +352,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Discrete Slider repaints and animates when dragged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Discrete Slider repaints and animates when dragged', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; final List log = []; @@ -419,7 +420,7 @@ void main() { await gesture.up(); }); - testWidgets("Slider doesn't send duplicate change events if tapped on the same value", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Slider doesn't send duplicate change events if tapped on the same value", (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; int updates = 0; @@ -460,7 +461,7 @@ void main() { expect(updates, equals(1)); }); - testWidgets('discrete Slider repaints when dragged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('discrete Slider repaints when dragged', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; final List log = []; @@ -528,7 +529,7 @@ void main() { await gesture.up(); }); - testWidgets('Slider take on discrete values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider take on discrete values', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; @@ -580,7 +581,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider can be given zero values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be given zero values', (WidgetTester tester) async { final List log = []; await tester.pumpWidget( MaterialApp( @@ -624,7 +625,7 @@ void main() { log.clear(); }); - testWidgets('Slider can tap in vertical scroller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can tap in vertical scroller', (WidgetTester tester) async { double value = 0.0; await tester.pumpWidget( MaterialApp( @@ -653,7 +654,7 @@ void main() { expect(value, equals(0.5)); }); - testWidgets('Slider drags immediately (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider drags immediately (LTR)', (WidgetTester tester) async { double value = 0.0; await tester.pumpWidget( MaterialApp( @@ -685,7 +686,7 @@ void main() { await gesture.up(); }); - testWidgets('Slider drags immediately (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider drags immediately (RTL)', (WidgetTester tester) async { double value = 0.0; await tester.pumpWidget( MaterialApp( @@ -717,7 +718,7 @@ void main() { await gesture.up(); }); - testWidgets('Slider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28115 int startFired = 0; @@ -757,7 +758,7 @@ void main() { expect(endFired, equals(1)); }); - testWidgets('Slider sizing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider sizing', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Directionality( @@ -816,7 +817,7 @@ void main() { expect(tester.renderObject(find.byType(Slider)).size, const Size(144.0 + 2.0 * 24.0, 48.0)); }); - testWidgets('Slider respects textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider respects textScaleFactor', (WidgetTester tester) async { debugDisableShadows = false; try { final Key sliderKey = UniqueKey(); @@ -971,7 +972,7 @@ void main() { } }); - testWidgets('Tick marks are skipped when they are too dense', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tick marks are skipped when they are too dense', (WidgetTester tester) async { Widget buildSlider({ required int divisions, }) { @@ -1018,7 +1019,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawCircle, 1)); }); - testWidgets('Slider has correct animations when reparented', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider has correct animations when reparented', (WidgetTester tester) async { final Key sliderKey = GlobalKey(debugLabel: 'A'); double value = 0.0; @@ -1147,7 +1148,7 @@ void main() { await testReparenting(true); }); - testWidgets('Slider Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider Semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -1309,7 +1310,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux })); - testWidgets('Slider Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider Semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1420,7 +1421,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Slider Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider Semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -1589,7 +1590,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.windows })); - testWidgets('Slider semantics with custom formatter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider semantics with custom formatter', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -1648,7 +1649,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101868 - testWidgets('Slider.label info should not write to semantic node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider.label info should not write to semantic node', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -1707,8 +1708,9 @@ void main() { semantics.dispose(); }); - testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Slider'); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: true); double value = 0.5; @@ -1755,8 +1757,9 @@ void main() { ); }); - testWidgets('Slider has correct focus color from overlayColor property', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider has correct focus color from overlayColor property', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Slider'); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; Widget buildApp({bool enabled = true}) { @@ -1808,7 +1811,7 @@ void main() { ); }); - testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: true); double value = 0.5; @@ -1878,7 +1881,7 @@ void main() { ); }); - testWidgets('Slider has correct hovered color from overlayColor property', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider has correct hovered color from overlayColor property', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; Widget buildApp({bool enabled = true}) { @@ -1939,12 +1942,13 @@ void main() { ); }); - testWidgets('Slider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; final ThemeData theme = ThemeData(useMaterial3: true); final Key sliderKey = UniqueKey(); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); Widget buildApp({bool enabled = true}) { return MaterialApp( @@ -2013,11 +2017,12 @@ void main() { ); }); - testWidgets('Slider has correct dragged color from overlayColor property', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider has correct dragged color from overlayColor property', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; final Key sliderKey = UniqueKey(); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); Widget buildApp({bool enabled = true}) { return MaterialApp( @@ -2082,8 +2087,9 @@ void main() { ); }); - testWidgets('OverlayColor property is correctly applied when activeColor is also provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverlayColor property is correctly applied when activeColor is also provided', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Slider'); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; const Color activeColor = Color(0xffff0000); @@ -2139,7 +2145,7 @@ void main() { ); }); - testWidgets('Slider can be incremented and decremented by keyboard shortcuts - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be incremented and decremented by keyboard shortcuts - LTR', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double startValue = 0.0; double currentValue = 0.5; @@ -2200,7 +2206,7 @@ void main() { expect(endValue, 0.5); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('Slider can be incremented and decremented by keyboard shortcuts - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be incremented and decremented by keyboard shortcuts - LTR', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double startValue = 0.0; double currentValue = 0.5; @@ -2261,7 +2267,7 @@ void main() { expect(endValue, 0.5); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Slider can be incremented and decremented by keyboard shortcuts - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be incremented and decremented by keyboard shortcuts - RTL', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double startValue = 0.0; double currentValue = 0.5; @@ -2325,7 +2331,7 @@ void main() { expect(endValue, 0.5); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('Slider can be incremented and decremented by keyboard shortcuts - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be incremented and decremented by keyboard shortcuts - RTL', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double startValue = 0.0; double currentValue = 0.5; @@ -2389,7 +2395,7 @@ void main() { expect(endValue, 0.5); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('In directional nav, Slider can be navigated out of by using up and down arrows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('In directional nav, Slider can be navigated out of by using up and down arrows', (WidgetTester tester) async { const Map shortcuts = { SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left), SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right), @@ -2485,10 +2491,11 @@ void main() { expect(bottomSliderValue, 0.5, reason: 'unfocused bottom Slider unaffected by third arrowRight'); }); - testWidgets('Slider gains keyboard focus when it gains semantics focus on Windows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider gains keyboard focus when it gains semantics focus on Windows', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -2552,7 +2559,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.windows })); - testWidgets('Value indicator appears when it should', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Value indicator appears when it should', (WidgetTester tester) async { final ThemeData baseTheme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -2636,7 +2643,7 @@ void main() { await expectValueIndicator(isVisible: false, theme: theme, enabled: false); }); - testWidgets("Slider doesn't start any animations after dispose", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Slider doesn't start any animations after dispose", (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; await tester.pumpWidget( @@ -2676,7 +2683,7 @@ void main() { await gesture.up(); }); - testWidgets('Slider removes value indicator from overlay if Slider gets disposed without value indicator animation completing.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider removes value indicator from overlay if Slider gets disposed without value indicator animation completing.', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); const Color fillColor = Color(0xf55f5f5f); double value = 0.0; @@ -2773,7 +2780,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Slider.adaptive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider.adaptive', (WidgetTester tester) async { double value = 0.5; Widget buildFrame(TargetPlatform platform) { @@ -2828,7 +2835,7 @@ void main() { } }); - testWidgets('Slider respects height from theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider respects height from theme', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; await tester.pumpWidget( @@ -2867,7 +2874,7 @@ void main() { expect(renderObject.size.height, 200); }); - testWidgets('Slider changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider changes mouse cursor when hovered', (WidgetTester tester) async { // Test Slider() constructor await tester.pumpWidget( MaterialApp( @@ -2942,7 +2949,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('Slider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider MaterialStateMouseCursor resolves correctly', (WidgetTester tester) async { const MouseCursor disabledCursor = SystemMouseCursors.basic; const MouseCursor hoveredCursor = SystemMouseCursors.grab; const MouseCursor draggedCursor = SystemMouseCursors.move; @@ -2992,7 +2999,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.move); }); - testWidgets('Slider implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const Slider( @@ -3025,7 +3032,7 @@ void main() { ]); }); - testWidgets('Slider track paints correctly when the shape is rectangular', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider track paints correctly when the shape is rectangular', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData( @@ -3060,7 +3067,7 @@ void main() { ); }); - testWidgets('SliderTheme change should trigger re-layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderTheme change should trigger re-layout', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/118955 double sliderValue = 0.0; Widget buildFrame(ThemeMode themeMode) { @@ -3105,7 +3112,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Slider can be painted in a narrower constraint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be painted in a narrower constraint', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Directionality( @@ -3141,7 +3148,7 @@ void main() { ); }); - testWidgets('Update the divisions and value at the same time for Slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update the divisions and value at the same time for Slider', (WidgetTester tester) async { // Regress test for https://github.com/flutter/flutter/issues/65943 Widget buildFrame(double maxValue) { return MaterialApp( @@ -3182,7 +3189,7 @@ void main() { expect(nearEqual(activeTrackRRect.right, (800.0 - 24.0 - 24.0) * (5 / 15) + 24.0, 0.01), true); }); - testWidgets('Slider paints thumbColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider paints thumbColor', (WidgetTester tester) async { const Color color = Color(0xffffc107); final Widget sliderAdaptive = MaterialApp( @@ -3204,7 +3211,7 @@ void main() { expect(material, paints..circle(color: color)); }); - testWidgets('Slider.adaptive paints thumbColor on Android', + testWidgetsWithLeakTracking('Slider.adaptive paints thumbColor on Android', (WidgetTester tester) async { const Color color = Color(0xffffc107); @@ -3227,7 +3234,7 @@ void main() { expect(material, paints..circle(color: color)); }); - testWidgets('If thumbColor is null, it defaults to CupertinoColors.white', + testWidgetsWithLeakTracking('If thumbColor is null, it defaults to CupertinoColors.white', (WidgetTester tester) async { final Widget sliderAdaptive = MaterialApp( theme: ThemeData(platform: TargetPlatform.iOS), @@ -3256,7 +3263,7 @@ void main() { ); }); - testWidgets('Slider.adaptive passes thumbColor to CupertinoSlider', + testWidgetsWithLeakTracking('Slider.adaptive passes thumbColor to CupertinoSlider', (WidgetTester tester) async { const Color color = Color(0xffffc107); @@ -3283,7 +3290,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/103566 - testWidgets('Drag gesture uses provided gesture settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag gesture uses provided gesture settings', (WidgetTester tester) async { double value = 0.5; bool dragStarted = false; final Key sliderKey = UniqueKey(); @@ -3389,7 +3396,7 @@ void main() { expect(dragStarted, false); }); - testWidgets('Overlay appear only when hovered on the thumb on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overlay appear only when hovered on the thumb on desktop', (WidgetTester tester) async { double value = 0.5; const Color overlayColor = Color(0xffff0000); @@ -3452,10 +3459,11 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Overlay remains when Slider is in focus on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overlay remains when Slider is in focus on desktop', (WidgetTester tester) async { double value = 0.5; const Color overlayColor = Color(0xffff0000); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); Widget buildApp({bool enabled = true}) { return MaterialApp( @@ -3517,7 +3525,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Value indicator disappears after adjusting the slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Value indicator disappears after adjusting the slider', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/123313. final ThemeData theme = ThemeData(useMaterial3: true); const double currentValue = 0.5; @@ -3567,9 +3575,10 @@ void main() { ); }); - testWidgets('Value indicator remains when Slider is in focus on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Value indicator remains when Slider is in focus on desktop', (WidgetTester tester) async { double value = 0.5; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); Widget buildApp({bool enabled = true}) { return MaterialApp( @@ -3636,7 +3645,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Event on Slider should perform no-op if already unmounted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Event on Slider should perform no-op if already unmounted', (WidgetTester tester) async { // Test covering crashing found in Google internal issue b/192329942. double value = 0.0; final ValueNotifier shouldShowSliderListenable = @@ -3701,7 +3710,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Slider can be hovered and has correct hover color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can be hovered and has correct hover color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(useMaterial3: false); double value = 0.5; @@ -3757,8 +3766,9 @@ void main() { ); }); - testWidgets('Slider is focusable and has correct focus color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider is focusable and has correct focus color', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Slider'); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final ThemeData theme = ThemeData(); double value = 0.5; @@ -3804,12 +3814,13 @@ void main() { ); }); - testWidgets('Slider is draggable and has correct dragged color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider is draggable and has correct dragged color', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; final ThemeData theme = ThemeData(); final Key sliderKey = UniqueKey(); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); Widget buildApp({bool enabled = true}) { return MaterialApp( @@ -3869,7 +3880,7 @@ void main() { }); group('Slider.allowedInteraction', () { - testWidgets('SliderInteraction.tapOnly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderInteraction.tapOnly', (WidgetTester tester) async { double value = 1.0; final Key sliderKey = UniqueKey(); // (slider's left padding (overlayRadius), windowHeight / 2) @@ -3911,7 +3922,7 @@ void main() { expect(value, 0.5); }); - testWidgets('SliderInteraction.tapAndSlide', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderInteraction.tapAndSlide', (WidgetTester tester) async { double value = 1.0; final Key sliderKey = UniqueKey(); // (slider's left padding (overlayRadius), windowHeight / 2) @@ -3957,7 +3968,7 @@ void main() { expect(value, 1.0); }); - testWidgets('SliderInteraction.slideOnly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderInteraction.slideOnly', (WidgetTester tester) async { double value = 1.0; final Key sliderKey = UniqueKey(); // (slider's left padding (overlayRadius), windowHeight / 2) @@ -4005,7 +4016,7 @@ void main() { expect(value, 1.0); }); - testWidgets('SliderInteraction.slideThumb', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderInteraction.slideThumb', (WidgetTester tester) async { double value = 1.0; final Key sliderKey = UniqueKey(); // (slider's left padding (overlayRadius), windowHeight / 2) diff --git a/packages/flutter/test/material/slider_theme_test.dart b/packages/flutter/test/material/slider_theme_test.dart index 383dc49d4f9b8..180cc2b4802ec 100644 --- a/packages/flutter/test/material/slider_theme_test.dart +++ b/packages/flutter/test/material/slider_theme_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('SliderThemeData copyWith, ==, hashCode basics', () { @@ -18,7 +19,7 @@ void main() { expect(identical(SliderThemeData.lerp(data, data, 0.5), data), true); }); - testWidgets('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SliderThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData().debugFillProperties(builder); @@ -30,7 +31,7 @@ void main() { expect(description, []); }); - testWidgets('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SliderThemeData( trackHeight: 7.0, @@ -102,7 +103,7 @@ void main() { ]); }); - testWidgets('Slider defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider defaults', (WidgetTester tester) async { debugDisableShadows = false; final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colorScheme = theme.colorScheme; @@ -233,7 +234,7 @@ void main() { } }); - testWidgets('Slider uses the right theme colors for the right components', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider uses the right theme colors for the right components', (WidgetTester tester) async { debugDisableShadows = false; try { const Color customColor1 = Color(0xcafefeed); @@ -500,7 +501,7 @@ void main() { } }); - testWidgets('Slider parameters overrides theme properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider parameters overrides theme properties', (WidgetTester tester) async { debugDisableShadows = false; const Color activeTrackColor = Color(0xffff0001); const Color inactiveTrackColor = Color(0xffff0002); @@ -554,7 +555,7 @@ void main() { } }); - testWidgets('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider uses ThemeData slider theme if present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -578,7 +579,7 @@ void main() { ); }); - testWidgets('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider overrides ThemeData theme if SliderTheme present', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.red, @@ -602,7 +603,7 @@ void main() { ); }); - testWidgets('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData generates correct opacities for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -632,7 +633,7 @@ void main() { expect(sliderTheme.valueIndicatorTextStyle!.color, equals(customColor4)); }); - testWidgets('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData generates correct shapes for fromPrimaryColors', (WidgetTester tester) async { const Color customColor1 = Color(0xcafefeed); const Color customColor2 = Color(0xdeadbeef); const Color customColor3 = Color(0xdecaface); @@ -656,7 +657,7 @@ void main() { expect(sliderTheme.rangeValueIndicatorShape, const PaddleRangeSliderValueIndicatorShape()); }); - testWidgets('SliderThemeData lerps correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderThemeData lerps correctly', (WidgetTester tester) async { final SliderThemeData sliderThemeBlack = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -690,7 +691,7 @@ void main() { expect(lerp.valueIndicatorTextStyle!.color, equals(middleGrey.withAlpha(0xff))); }); - testWidgets('Default slider track draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider track draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -726,7 +727,7 @@ void main() { ); }); - testWidgets('Default slider overlay draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider overlay draws correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -787,7 +788,7 @@ void main() { ); }); - testWidgets('Slider can use theme overlay with material states', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider can use theme overlay with material states', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -802,6 +803,7 @@ void main() { }), ); final FocusNode focusNode = FocusNode(debugLabel: 'Slider'); + addTearDown(focusNode.dispose); tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; double value = 0.5; @@ -846,7 +848,7 @@ void main() { ); }); - testWidgets('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider ticker and thumb shape draw correctly', (WidgetTester tester) async { final ThemeData theme = ThemeData( platform: TargetPlatform.android, primarySwatch: Colors.blue, @@ -890,7 +892,7 @@ void main() { ); }); - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1074,7 +1076,7 @@ void main() { } }); - testWidgets('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1258,7 +1260,7 @@ void main() { } }); - testWidgets('The slider track height can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider track height can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith(trackHeight: 16); const Radius radius = Radius.circular(8); const Radius activatedRadius = Radius.circular(9); @@ -1288,7 +1290,7 @@ void main() { ); }); - testWidgets('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider thumb shape sizes can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 7, @@ -1313,7 +1315,7 @@ void main() { ); }); - testWidgets('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider thumb shape disabled size can be inferred from the enabled size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 9, @@ -1336,7 +1338,7 @@ void main() { ); }); - testWidgets('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider tick mark shape size can be overridden', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( tickMarkShape: const RoundSliderTickMarkShape(tickMarkRadius: 5), activeTickMarkColor: const Color(0xfadedead), @@ -1369,7 +1371,7 @@ void main() { ); }); - testWidgets('The default slider overlay shape size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The default slider overlay shape size can be overridden', (WidgetTester tester) async { const double uniqueOverlayRadius = 23; final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: const RoundSliderOverlayShape( @@ -1396,7 +1398,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/74503 - testWidgets('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1437,7 +1439,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/125467 - testWidgets('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The RangeSlider track layout correctly when the overlay size is smaller than the thumb size', (WidgetTester tester) async { final SliderThemeData sliderTheme = ThemeData().sliderTheme.copyWith( overlayShape: SliderComponentShape.noOverlay, ); @@ -1488,7 +1490,7 @@ void main() { // // The value indicator can be skipped by passing the appropriate // [ShowValueIndicator]. - testWidgets('The slider can skip all of its component painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all of its component painting', (WidgetTester tester) async { // Pump a slider with all shapes skipped. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1509,7 +1511,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the track', (WidgetTester tester) async { // Pump a slider with just a track. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1530,7 +1532,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the tick marks', (WidgetTester tester) async { // Pump a slider with just tick marks. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1554,7 +1556,7 @@ void main() { expect(material, paintsExactlyCountTimes(#drawPath, 0)); }); - testWidgets('The slider can skip all component painting except the thumb', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the thumb', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a thumb. @@ -1580,7 +1582,7 @@ void main() { } }); - testWidgets('The slider can skip all component painting except the overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the overlay', (WidgetTester tester) async { // Pump a slider with just an overlay. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1608,7 +1610,7 @@ void main() { await gesture.up(); }); - testWidgets('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The slider can skip all component painting except the value indicator', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1638,7 +1640,7 @@ void main() { await gesture.up(); }); - testWidgets('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaddleSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1673,7 +1675,7 @@ void main() { await gesture.up(); }); - testWidgets('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default slider value indicator shape skips all painting at zero scale', (WidgetTester tester) async { // Pump a slider with just a value indicator. await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( @@ -1705,7 +1707,7 @@ void main() { }); - testWidgets('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -1755,7 +1757,7 @@ void main() { } }); - testWidgets('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default paddle range slider value indicator shape draws correctly with debugDisableShadows', (WidgetTester tester) async { debugDisableShadows = true; final ThemeData theme = ThemeData( platform: TargetPlatform.android, @@ -1801,7 +1803,7 @@ void main() { await gesture.up(); }); - testWidgets('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaddleRangeSliderValueIndicatorShape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1835,7 +1837,7 @@ void main() { } }); - testWidgets('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default range indicator shape skips all painting at zero scale', (WidgetTester tester) async { debugDisableShadows = false; try { // Pump a slider with just a value indicator. @@ -1871,7 +1873,7 @@ void main() { } }); - testWidgets('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { + testWidgetsWithLeakTracking('activeTrackRadius is taken into account when painting the border of the active track', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( trackShape: const RoundedRectSliderTrackShapeWithCustomAdditionalActiveTrackHeight( @@ -1898,7 +1900,7 @@ void main() { ); }); - testWidgets('The mouse cursor is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The mouse cursor is themeable', (WidgetTester tester) async { await tester.pumpWidget(_buildApp( ThemeData().sliderTheme.copyWith( mouseCursor: const MaterialStatePropertyAll(SystemMouseCursors.text), @@ -1913,7 +1915,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliderTheme.allowedInteraction is themeable', (WidgetTester tester) async { double value = 0.0; Widget buildApp({ @@ -2020,7 +2022,7 @@ void main() { await gesture.up(); }); - testWidgets('Default value indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( @@ -2083,7 +2085,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Slider defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider defaults', (WidgetTester tester) async { debugDisableShadows = false; final ThemeData theme = ThemeData(useMaterial3: false); const double trackHeight = 4.0; @@ -2233,7 +2235,7 @@ void main() { } }); - testWidgets('Default value indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default value indicator color', (WidgetTester tester) async { debugDisableShadows = false; try { final ThemeData theme = ThemeData( diff --git a/packages/flutter/test/material/snack_bar_theme_test.dart b/packages/flutter/test/material/snack_bar_theme_test.dart index c84df3b78cf22..d39bdf418c8cb 100644 --- a/packages/flutter/test/material/snack_bar_theme_test.dart +++ b/packages/flutter/test/material/snack_bar_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('SnackBarThemeData copyWith, ==, hashCode basics', () { @@ -45,7 +46,7 @@ void main() { throwsAssertionError); }); - testWidgets('Default SnackBarThemeData debugFillProperties', + testWidgetsWithLeakTracking('Default SnackBarThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SnackBarThemeData().debugFillProperties(builder); @@ -58,7 +59,7 @@ void main() { expect(description, []); }); - testWidgets('SnackBarThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SnackBarThemeData( backgroundColor: Color(0xFFFFFFFF), @@ -96,7 +97,7 @@ void main() { ]); }); - testWidgets('Material2 - Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { const String text = 'I am a snack bar.'; await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -130,7 +131,7 @@ void main() { expect(material.shape, null); }); - testWidgets('Material3 - Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Passing no SnackBarThemeData returns defaults', (WidgetTester tester) async { const String text = 'I am a snack bar.'; final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget(MaterialApp( @@ -165,7 +166,7 @@ void main() { expect(material.shape, null); }); - testWidgets('SnackBar uses values from SnackBarThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar uses values from SnackBarThemeData', (WidgetTester tester) async { const String text = 'I am a snack bar.'; const String action = 'ACTION'; final SnackBarThemeData snackBarTheme = _snackBarTheme(showCloseIcon: true); @@ -206,7 +207,7 @@ void main() { expect(icon.icon, Icons.close); }); - testWidgets('SnackBar widget properties take priority over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar widget properties take priority over theme', (WidgetTester tester) async { const Color backgroundColor = Colors.purple; const Color textColor = Colors.pink; const double elevation = 7.0; @@ -266,7 +267,7 @@ void main() { expect(snackBarBottomRight.dx, (800 + snackBarWidth) / 2); // Device width is 800. }); - testWidgets('SnackBarAction uses actionBackgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarAction uses actionBackgroundColor', (WidgetTester tester) async { final MaterialStateColor actionBackgroundColor = MaterialStateColor.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return Colors.blue; @@ -315,7 +316,7 @@ void main() { expect(materialAfterDismissed.color, Colors.blue); }); - testWidgets('SnackBarAction backgroundColor overrides SnackBarThemeData actionBackgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarAction backgroundColor overrides SnackBarThemeData actionBackgroundColor', (WidgetTester tester) async { final MaterialStateColor snackBarActionBackgroundColor = MaterialStateColor.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return Colors.amber; @@ -372,7 +373,7 @@ void main() { expect(materialAfterDismissed.color, Colors.amber); }); - testWidgets('SnackBarThemeData asserts when actionBackgroundColor is a MaterialStateColor and disabledActionBackgroundColor is also provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarThemeData asserts when actionBackgroundColor is a MaterialStateColor and disabledActionBackgroundColor is also provided', (WidgetTester tester) async { final MaterialStateColor actionBackgroundColor = MaterialStateColor.resolveWith((Set states) { if (states.contains(MaterialState.disabled)) { return Colors.blue; @@ -408,7 +409,7 @@ void main() { ); }); - testWidgets('SnackBar theme behavior is correct for floating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar theme behavior is correct for floating', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating)), @@ -448,7 +449,7 @@ void main() { expect(snackBarBottomCenter.dy == floatingActionButtonTopCenter.dy, true); }); - testWidgets('SnackBar theme behavior is correct for fixed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar theme behavior is correct for fixed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.fixed), @@ -529,7 +530,7 @@ void main() { ); } - testWidgets('SnackBar theme behavior will assert properly for margin use', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar theme behavior will assert properly for margin use', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84935 // SnackBarBehavior.floating set in theme does not assert with margin await tester.pumpWidget(buildApp( @@ -568,7 +569,7 @@ void main() { }); } - testWidgets('SnackBar theme behavior will assert properly for width use', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar theme behavior will assert properly for width use', (WidgetTester tester) async { // SnackBarBehavior.floating set in theme does not assert with width await tester.pumpWidget(buildApp( themedBehavior: SnackBarBehavior.floating, diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index bec9ffbe776a5..c35f8fb8d6951 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -271,12 +272,18 @@ RenderParagraph _getText(WidgetTester tester, String text) { return tester.renderObject(find.text(text)); } +TabController _tabController({required int length, required TickerProvider vsync, int initialIndex = 0, Duration? animationDuration}) { + final TabController result = TabController(length: length, vsync: vsync, initialIndex: initialIndex, animationDuration: animationDuration); + addTearDown(result.dispose); + return result; +} + void main() { setUp(() { debugResetSemanticsIdCounter(); }); - testWidgets('indicatorPadding update test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('indicatorPadding update test', (WidgetTester tester) async { // Regressing test for https://github.com/flutter/flutter/issues/108102 const Tab tab = Tab(text: 'A'); const EdgeInsets indicatorPadding = EdgeInsets.only(left: 7.0, right: 7.0); @@ -305,21 +312,21 @@ void main() { expect(tester.renderObject(find.byType(CustomPaint)).debugNeedsPaint, true); }); - testWidgets('Tab sizing - icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab sizing - icon', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp(home: Center(child: Material(child: Tab(icon: SizedBox(width: 10.0, height: 10.0))))), ); expect(tester.getSize(find.byType(Tab)), const Size(10.0, 46.0)); }); - testWidgets('Tab sizing - child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab sizing - child', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp(home: Center(child: Material(child: Tab(child: SizedBox(width: 10.0, height: 10.0))))), ); expect(tester.getSize(find.byType(Tab)), const Size(10.0, 46.0)); }); - testWidgets('Tab sizing - text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab sizing - text', (WidgetTester tester) async { final ThemeData theme = ThemeData(fontFamily: 'FlutterTest'); final bool material3 = theme.useMaterial3; await tester.pumpWidget( @@ -332,7 +339,7 @@ void main() { ); }); - testWidgets('Tab sizing - icon and text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab sizing - icon and text', (WidgetTester tester) async { final ThemeData theme = ThemeData(fontFamily: 'FlutterTest'); final bool material3 = theme.useMaterial3; await tester.pumpWidget( @@ -344,7 +351,7 @@ void main() { material3 ? const Size(14.25, 72.0) : const Size(14.0, 72.0)); }); - testWidgets('Tab sizing - icon, iconMargin and text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab sizing - icon, iconMargin and text', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(fontFamily: 'FlutterTest'), @@ -368,7 +375,7 @@ void main() { expect(tester.getSize(find.byType(Tab)), const Size(210.0, 72.0)); }); - testWidgets('Tab sizing - icon and child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab sizing - icon and child', (WidgetTester tester) async { final ThemeData theme = ThemeData(fontFamily: 'FlutterTest'); final bool material3 = theme.useMaterial3; await tester.pumpWidget( @@ -380,37 +387,37 @@ void main() { material3 ? const Size(14.25, 72.0) : const Size(14.0, 72.0)); }); - testWidgets('Tab color - normal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab color - normal', (WidgetTester tester) async { final ThemeData theme = ThemeData(fontFamily: 'FlutterTest'); final bool material3 = theme.useMaterial3; - final Widget tabBar = TabBar(tabs: const [SizedBox.shrink()], controller: TabController(length: 1, vsync: tester)); + final Widget tabBar = TabBar(tabs: const [SizedBox.shrink()], controller: _tabController(length: 1, vsync: tester)); await tester.pumpWidget( MaterialApp(theme: theme, home: Material(child: tabBar)), ); expect(find.byType(TabBar), paints..line(color: material3 ? theme.colorScheme.surfaceVariant : Colors.blue[500])); }); - testWidgets('Tab color - match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab color - match', (WidgetTester tester) async { final ThemeData theme = ThemeData(); final bool material3 = theme.useMaterial3; - final Widget tabBar = TabBar(tabs: const [SizedBox.shrink()], controller: TabController(length: 1, vsync: tester)); + final Widget tabBar = TabBar(tabs: const [SizedBox.shrink()], controller: _tabController(length: 1, vsync: tester)); await tester.pumpWidget( MaterialApp(theme: theme, home: Material(color: const Color(0xff2196f3), child: tabBar)), ); expect(find.byType(TabBar), paints..line(color: material3 ? theme.colorScheme.surfaceVariant : Colors.white)); }); - testWidgets('Tab color - transparency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab color - transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(); final bool material3 = theme.useMaterial3; - final Widget tabBar = TabBar(tabs: const [SizedBox.shrink()], controller: TabController(length: 1, vsync: tester)); + final Widget tabBar = TabBar(tabs: const [SizedBox.shrink()], controller: _tabController(length: 1, vsync: tester)); await tester.pumpWidget( MaterialApp(theme: theme, home: Material(type: MaterialType.transparency, child: tabBar)), ); expect(find.byType(TabBar), paints..line(color: material3 ? theme.colorScheme.surfaceVariant : Colors.blue[500])); }); - testWidgets('TabBar default selected/unselected label style (primary)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TabBar default selected/unselected label style (primary)', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final List tabs = ['A', 'B', 'C']; @@ -468,7 +475,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -517,7 +524,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -1316,7 +1323,7 @@ void main() { }); testWidgets('TabBar unselectedLabelColor control test', (WidgetTester tester) async { - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 2, ); @@ -1353,7 +1360,7 @@ void main() { }); testWidgets('TabBarView page left and right test', (WidgetTester tester) async { - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 2, ); @@ -1444,7 +1451,7 @@ void main() { const Duration animationDuration = Duration(milliseconds: 100); final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), initialIndex: 1, length: tabs.length, @@ -1494,7 +1501,7 @@ void main() { const Duration animationDuration = Duration(seconds: 2); final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), length: tabs.length, animationDuration: animationDuration, @@ -1553,7 +1560,7 @@ void main() { const Duration animationDuration = Duration(milliseconds: 100); final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), initialIndex: 1, length: tabs.length, @@ -1597,7 +1604,7 @@ void main() { const Duration animationDuration = Duration(milliseconds: 100); final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), initialIndex: 1, length: tabs.length, @@ -1775,7 +1782,7 @@ void main() { testWidgets('TabBarView skips animation when disabled in controller', (WidgetTester tester) async { final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), initialIndex: 1, length: tabs.length, @@ -1820,7 +1827,7 @@ void main() { testWidgets('TabBarView skips animation when disabled in controller - skip tabs', (WidgetTester tester) async { final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), length: tabs.length, animationDuration: Duration.zero, @@ -1865,7 +1872,7 @@ void main() { testWidgets('TabBarView skips animation when disabled in controller - skip tabs twice', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110970 final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), length: tabs.length, animationDuration: Duration.zero, @@ -1914,7 +1921,7 @@ void main() { testWidgets('TabBarView skips animation when disabled in controller - skip tabs followed by single tab navigation', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110970 final List tabs = ['A', 'B', 'C']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), length: tabs.length, animationDuration: Duration.zero, @@ -1966,7 +1973,7 @@ void main() { testWidgets('TabBarView skips animation when disabled in controller - two tabs', (WidgetTester tester) async { final List tabs = ['A', 'B']; - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), length: tabs.length, animationDuration: Duration.zero, @@ -2046,7 +2053,7 @@ void main() { // This is a regression test for this patch: // https://github.com/flutter/flutter/pull/9015 - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 2, ); @@ -2163,7 +2170,7 @@ void main() { testWidgets('TabBarView scrolls end close to a new page', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/9375 - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), initialIndex: 1, length: 3, @@ -2219,8 +2226,8 @@ void main() { testWidgets('Can switch to non-neighboring tab in nested TabBarView without crashing', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/18756 - final TabController mainTabController = TabController(length: 4, vsync: const TestVSync()); - final TabController nestedTabController = TabController(length: 2, vsync: const TestVSync()); + final TabController mainTabController = _tabController(length: 4, vsync: const TestVSync()); + final TabController nestedTabController = _tabController(length: 2, vsync: const TestVSync()); await tester.pumpWidget( MaterialApp( @@ -2263,7 +2270,7 @@ void main() { testWidgets('TabBarView can warp when child is kept alive and contains ink', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/57662. - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 3, ); @@ -2299,7 +2306,7 @@ void main() { }); testWidgets('TabBarView scrolls end close to a new page with custom physics', (WidgetTester tester) async { - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), initialIndex: 1, length: 3, @@ -2359,7 +2366,7 @@ void main() { return Tab(text: 'TAB #$index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, initialIndex: tabs.length - 1, @@ -2389,7 +2396,7 @@ void main() { return Tab(text: 'TAB #$index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, initialIndex: tabs.length - 1, @@ -2425,7 +2432,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2485,7 +2492,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2542,7 +2549,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2614,7 +2621,7 @@ void main() { const double indicatorWeight = 2.0; // the default - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2684,7 +2691,7 @@ void main() { const double indicatorWeight = 2.0; // the default - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2756,7 +2763,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2827,7 +2834,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2900,7 +2907,7 @@ void main() { const Decoration indicator = BoxDecoration(color: indicatorColor); const double indicatorWeight = 2.0; // the default - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -2979,7 +2986,7 @@ void main() { const Decoration indicator = BoxDecoration(color: indicatorColor); const double indicatorWeight = 2.0; // the default - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3056,7 +3063,7 @@ void main() { SizedBox(key: UniqueKey(), width: double.infinity, height: 40.0), ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3112,7 +3119,7 @@ void main() { SizedBox(key: UniqueKey(), width: 150.0, height: 50.0), ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3176,7 +3183,7 @@ void main() { SizedBox(key: UniqueKey(), width: 150.0, height: 50.0), ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3247,7 +3254,7 @@ void main() { SizedBox(key: UniqueKey(), width: 150.0, height: 50.0), ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3315,7 +3322,7 @@ void main() { SizedBox(key: UniqueKey(), width: 68.0, height: 40.0), ); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3380,7 +3387,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3457,7 +3464,7 @@ void main() { return Tab(text: 'TAB #$index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3531,7 +3538,7 @@ void main() { return Tab(text: 'This is a very wide tab #$index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3580,7 +3587,7 @@ void main() { }); testWidgets('TabBar etc with zero tabs', (WidgetTester tester) async { - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 0, ); @@ -3620,7 +3627,7 @@ void main() { }); testWidgets('TabBar etc with one tab', (WidgetTester tester) async { - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 1, ); @@ -3675,7 +3682,7 @@ void main() { }); testWidgets('can tap on indicator at very bottom of TabBar to switch tabs', (WidgetTester tester) async { - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 2, ); @@ -3724,7 +3731,7 @@ void main() { ); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -3810,7 +3817,7 @@ void main() { } final List tabs = ['A', 'B', 'C']; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, initialIndex: tabs.indexOf('C'), @@ -3934,12 +3941,12 @@ void main() { ); } - final TabController controller1 = TabController( + final TabController controller1 = _tabController( vsync: const TestVSync(), length: 2, ); - final TabController controller2 = TabController( + final TabController controller2 = _tabController( vsync: const TestVSync(), length: 2, ); @@ -4012,12 +4019,12 @@ void main() { ); } - final TabController controller1 = TabController( + final TabController controller1 = _tabController( vsync: const TestVSync(), length: 2, ); - final TabController controller2 = TabController( + final TabController controller2 = _tabController( vsync: const TestVSync(), length: 3, ); @@ -4030,7 +4037,6 @@ void main() { await tester.flingFrom(flingStart, const Offset(-200.0, 0.0), 10000.0); await tester.pump(const Duration(milliseconds: 10)); // start the fling animation - controller1.dispose(); await tester.pump(const Duration(milliseconds: 10)); await tester.pumpWidget(buildFrame(controller2)); // replace controller @@ -4047,7 +4053,7 @@ void main() { TabController? controller; Widget buildFrame(int length) { - controller = TabController( + controller = _tabController( vsync: const TestVSync(), length: length, initialIndex: length - 1, @@ -4086,11 +4092,11 @@ void main() { testWidgets('Do not throw when switching between a scrollable TabBar and a non-scrollable TabBar', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/120649 - final TabController controller1 = TabController( + final TabController controller1 = _tabController( vsync: const TestVSync(), length: 2, ); - final TabController controller2 = TabController( + final TabController controller2 = _tabController( vsync: const TestVSync(), length: 2, ); @@ -4288,7 +4294,7 @@ void main() { 'Tab3', 'Tab4', ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -4339,7 +4345,7 @@ void main() { 'Tab4', 'Tab5', ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -4391,7 +4397,7 @@ void main() { Tab(text: 'GABBA'), Tab(text: 'HEY'), ]; - final TabController controller = TabController(vsync: const TestVSync(), length: tabs.length); + final TabController controller = _tabController(vsync: const TestVSync(), length: tabs.length); Widget buildTestWidget({double? width, double? height}) { return MaterialApp( @@ -4626,7 +4632,7 @@ void main() { onPressed: () { setState(() { controller.dispose(); - controller = TabController(vsync: const TestVSync(), length: 3); + controller = _tabController(vsync: const TestVSync(), length: 3); }); }, ), @@ -4806,19 +4812,19 @@ void main() { testWidgets('TabBar - updating to and from zero tabs', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/68962. final List tabTitles = []; - TabController tabController = TabController(length: tabTitles.length, vsync: const TestVSync()); + TabController tabController = _tabController(length: tabTitles.length, vsync: const TestVSync()); void onTabAdd(StateSetter setState) { setState(() { tabTitles.add('Tab ${tabTitles.length + 1}'); - tabController = TabController(length: tabTitles.length, vsync: const TestVSync()); + tabController = _tabController(length: tabTitles.length, vsync: const TestVSync()); }); } void onTabRemove(StateSetter setState) { setState(() { tabTitles.removeLast(); - tabController = TabController(length: tabTitles.length, vsync: const TestVSync()); + tabController = _tabController(length: tabTitles.length, vsync: const TestVSync()); }); } @@ -4967,7 +4973,7 @@ void main() { }); testWidgets('TabController.offset changes reflect labelColor', (WidgetTester tester) async { - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 2, ); @@ -5059,7 +5065,7 @@ void main() { }); testWidgets("TabController's animation value should be in sync with TabBarView's scroll value when user interrupts ballistic scroll", (WidgetTester tester) async { - final TabController tabController = TabController( + final TabController tabController = _tabController( vsync: const TestVSync(), length: 3, ); @@ -5289,7 +5295,7 @@ void main() { home: Scaffold( appBar: AppBar( bottom: TabBar( - controller: TabController(length: 3, vsync: const TestVSync()), + controller: _tabController(length: 3, vsync: const TestVSync()), tabs: const [ Tab(text: 'Tab 1', icon: Icon(Icons.plus_one)), Tab(text: 'Tab 2'), @@ -5321,7 +5327,7 @@ void main() { appBar: AppBar( bottom: TabBar( labelPadding: labelPadding, - controller: TabController(length: 3, vsync: const TestVSync()), + controller: _tabController(length: 3, vsync: const TestVSync()), tabs: const [ Tab(text: 'Tab 1', icon: Icon(Icons.plus_one)), Tab(text: 'Tab 2'), @@ -5355,7 +5361,7 @@ void main() { home: Scaffold( appBar: AppBar( bottom: TabBar( - controller: TabController(length: 3, vsync: const TestVSync()), + controller: _tabController(length: 3, vsync: const TestVSync()), tabs: const [ Tab(text: 'Tab 1', icon: Icon(Icons.plus_one)), Tab(text: 'Tab 2'), @@ -5445,7 +5451,7 @@ void main() { testWidgets('Test semantics of TabPageSelector', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: 2, ); @@ -5554,17 +5560,17 @@ void main() { ); } - final TabController controller1 = TabController( + final TabController controller1 = _tabController( vsync: const TestVSync(), length: 3, ); - final TabController controller2 = TabController( + final TabController controller2 = _tabController( vsync: const TestVSync(), length: 2, ); - final TabController controller3 = TabController( + final TabController controller3 = _tabController( vsync: const TestVSync(), length: 3, ); @@ -5626,12 +5632,12 @@ void main() { ); } - final TabController controller1 = TabController( + final TabController controller1 = _tabController( vsync: const TestVSync(), length: 3, ); - final TabController controller2 = TabController( + final TabController controller2 = _tabController( vsync: const TestVSync(), length: 2, ); @@ -6324,7 +6330,7 @@ void main() { home: Scaffold( appBar: AppBar( bottom: TabBar( - controller: TabController(length: 3, vsync: const TestVSync()), + controller: _tabController(length: 3, vsync: const TestVSync()), tabs: const [ Tab(text: 'Tab 1'), Tab(text: 'Tab 2'), @@ -6481,7 +6487,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -6527,7 +6533,7 @@ void main() { return Tab(text: 'Tab $index'); }); - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); @@ -6577,7 +6583,7 @@ void main() { SizedBox(key: UniqueKey(), width: 150.0, height: 50.0), ]; - final TabController controller = TabController( + final TabController controller = _tabController( vsync: const TestVSync(), length: tabs.length, ); diff --git a/packages/flutter/test/material/text_field_focus_test.dart b/packages/flutter/test/material/text_field_focus_test.dart index 6612b36fdc14e..e194a0bdac255 100644 --- a/packages/flutter/test/material/text_field_focus_test.dart +++ b/packages/flutter/test/material/text_field_focus_test.dart @@ -7,10 +7,11 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/87099 - testWidgets('TextField.autofocus should skip the element that never layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField.autofocus should skip the element that never layout', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -27,10 +28,11 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Dialog interaction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog interaction', (WidgetTester tester) async { expect(tester.testTextInput.isVisible, isFalse); final FocusNode focusNode = FocusNode(debugLabel: 'Editable Text Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( @@ -70,8 +72,9 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('Request focus shows keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Request focus shows keyboard', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( @@ -97,7 +100,7 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('Autofocus shows keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Autofocus shows keyboard', (WidgetTester tester) async { expect(tester.testTextInput.isVisible, isFalse); await tester.pumpWidget( @@ -119,7 +122,7 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('Tap shows keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap shows keyboard', (WidgetTester tester) async { expect(tester.testTextInput.isVisible, isFalse); await tester.pumpWidget( @@ -158,8 +161,9 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('Focus triggers keep-alive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus triggers keep-alive', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( @@ -198,8 +202,9 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('Focus keep-alive works with GlobalKey reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus keep-alive works with GlobalKey reparenting', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); Widget makeTest(String? prefix) { return MaterialApp( @@ -233,7 +238,7 @@ void main() { expect(find.byType(TextField, skipOffstage: false), findsOneWidget); }); - testWidgets('TextField with decoration:null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with decoration:null', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/16880 await tester.pumpWidget( @@ -254,11 +259,14 @@ void main() { expect(tester.testTextInput.isVisible, isTrue); }); - testWidgets('Sibling FocusScopes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sibling FocusScopes', (WidgetTester tester) async { expect(tester.testTextInput.isVisible, isFalse); final FocusScopeNode focusScopeNode0 = FocusScopeNode(); + addTearDown(focusScopeNode0.dispose); final FocusScopeNode focusScopeNode1 = FocusScopeNode(); + addTearDown(focusScopeNode1.dispose); + final Key textField0 = UniqueKey(); final Key textField1 = UniqueKey(); @@ -320,7 +328,7 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('Sibling Navigators', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sibling Navigators', (WidgetTester tester) async { expect(tester.testTextInput.isVisible, isFalse); final Key textField0 = UniqueKey(); @@ -395,9 +403,12 @@ void main() { expect(tester.testTextInput.isVisible, isFalse); }); - testWidgets('A Focused text-field will lose focus when clicking outside of its hitbox with a mouse on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A Focused text-field will lose focus when clicking outside of its hitbox with a mouse on desktop', (WidgetTester tester) async { final FocusNode focusNodeA = FocusNode(); + addTearDown(focusNodeA.dispose); final FocusNode focusNodeB = FocusNode(); + addTearDown(focusNodeB.dispose); + final Key key = UniqueKey(); await tester.pumpWidget( @@ -452,8 +463,9 @@ void main() { expect(focusNodeB.hasFocus, true); }, variant: TargetPlatformVariant.desktop()); - testWidgets('A Focused text-field will not lose focus when clicking on its decoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A Focused text-field will not lose focus when clicking on its decoration', (WidgetTester tester) async { final FocusNode focusNodeA = FocusNode(); + addTearDown(focusNodeA.dispose); final Key iconKey = UniqueKey(); await tester.pumpWidget( @@ -489,9 +501,12 @@ void main() { expect(focusNodeA.hasFocus, true); }, variant: TargetPlatformVariant.desktop()); - testWidgets('A Focused text-field will lose focus when clicking outside of its hitbox with a mouse on desktop after tab navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A Focused text-field will lose focus when clicking outside of its hitbox with a mouse on desktop after tab navigation', (WidgetTester tester) async { final FocusNode focusNodeA = FocusNode(debugLabel: 'A'); + addTearDown(focusNodeA.dispose); final FocusNode focusNodeB = FocusNode(debugLabel: 'B'); + addTearDown(focusNodeB.dispose); + final Key key = UniqueKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/text_field_helper_text_test.dart b/packages/flutter/test/material/text_field_helper_text_test.dart index a5b4a06a421fd..962ea66a6527e 100644 --- a/packages/flutter/test/material/text_field_helper_text_test.dart +++ b/packages/flutter/test/material/text_field_helper_text_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('TextField works correctly when changing helperText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField works correctly when changing helperText', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Material(child: TextField(decoration: InputDecoration(helperText: 'Awesome'))))); expect(find.text('Awesome'), findsNWidgets(1)); await tester.pump(const Duration(milliseconds: 100)); diff --git a/packages/flutter/test/material/text_field_splash_test.dart b/packages/flutter/test/material/text_field_splash_test.dart index b16f0ced9b951..28169c992ad8c 100644 --- a/packages/flutter/test/material/text_field_splash_test.dart +++ b/packages/flutter/test/material/text_field_splash_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/gestures.dart' show kPressTimeout; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; bool confirmCalled = false; bool cancelCalled = false; @@ -76,7 +77,7 @@ void main() { cancelCalled = false; }); - testWidgets('Tapping should never cause a splash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping should never cause a splash', (WidgetTester tester) async { final Key textField1 = UniqueKey(); final Key textField2 = UniqueKey(); @@ -135,7 +136,7 @@ void main() { expect(cancelCalled, isFalse); }); - testWidgets('Splash should never be created or canceled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Splash should never be created or canceled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Theme( diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index c105dbb2179e2..fff87d55eb7a2 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -23,6 +23,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart'; @@ -79,6 +80,7 @@ Widget overlay({ required Widget child }) { ); }, ); + addTearDown(() => entry..remove()..dispose()); return overlayWithEntry(entry); } @@ -154,6 +156,18 @@ class TestFormatter extends TextInputFormatter { } } +FocusNode _focusNode() { + final FocusNode result = FocusNode(); + addTearDown(result.dispose); + return result; +} + +TextEditingController _textEditingController({String text = ''}) { + final TextEditingController result = TextEditingController(text: text); + addTearDown(result.dispose); + return result; +} + void main() { TestWidgetsFlutterBinding.ensureInitialized(); final MockClipboard mockClipboard = MockClipboard(); @@ -204,14 +218,14 @@ void main() { ); } - testWidgets( + testWidgetsWithLeakTracking( 'Live Text button shows and hides correctly when LiveTextStatus changes', (WidgetTester tester) async { final LiveTextInputTester liveTextInputTester = LiveTextInputTester(); addTearDown(liveTextInputTester.dispose); - final TextEditingController controller = TextEditingController(text: ''); + final TextEditingController controller = _textEditingController(); const Key key = ValueKey('TextField'); - final FocusNode focusNode = FocusNode(); + final FocusNode focusNode = _focusNode(); final Widget app = MaterialApp( theme: ThemeData(platform: TargetPlatform.iOS), home: Scaffold( @@ -245,7 +259,7 @@ void main() { }, ); - testWidgets('text field selection toolbar should hide when the user starts typing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text field selection toolbar should hide when the user starts typing', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -296,9 +310,9 @@ void main() { expect(state.selectionOverlay!.toolbarIsVisible, isFalse); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('Composing change does not hide selection handle caret', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Composing change does not hide selection handle caret', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/108673 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -386,8 +400,8 @@ void main() { expect(identical(handleRenderObjectBegin, handleRenderObjectEnd), true); }); - testWidgets('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'blah1 blah2', ); await tester.pumpWidget( @@ -461,8 +475,8 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('can use the desktop cut/copy/paste buttons on Windows and Linux', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can use the desktop cut/copy/paste buttons on Windows and Linux', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'blah1 blah2', ); await tester.pumpWidget( @@ -605,7 +619,7 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Look Up shows up on iOS only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Look Up shows up on iOS only', (WidgetTester tester) async { String? lastLookUp; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -616,7 +630,7 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Test ', ); await tester.pumpWidget( @@ -654,7 +668,7 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Search Web shows up on iOS only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Search Web shows up on iOS only', (WidgetTester tester) async { String? lastSearch; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -665,7 +679,7 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Test ', ); await tester.pumpWidget( @@ -703,7 +717,7 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Share shows up on iOS only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Share shows up on iOS only', (WidgetTester tester) async { String? lastShare; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -714,7 +728,7 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Test ', ); await tester.pumpWidget( @@ -752,7 +766,7 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('uses DefaultSelectionStyle for selection and cursor colors if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses DefaultSelectionStyle for selection and cursor colors if provided', (WidgetTester tester) async { const Color selectionColor = Colors.orange; const Color cursorColor = Colors.red; @@ -773,7 +787,7 @@ void main() { expect(state.widget.cursorColor, cursorColor); }); - testWidgets('sets cursorOpacityAnimates on EditableText correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sets cursorOpacityAnimates on EditableText correctly', (WidgetTester tester) async { // True @@ -802,10 +816,10 @@ void main() { expect(editableText.cursorOpacityAnimates, false); }); - testWidgets('Activates the text field when receives semantics focus on desktops', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activates the text field when receives semantics focus on desktops', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; - final FocusNode focusNode = FocusNode(); + final FocusNode focusNode = _focusNode(); await tester.pumpWidget( MaterialApp( home: Material( @@ -860,7 +874,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux })); - testWidgets('TextField passes onEditingComplete to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField passes onEditingComplete to EditableText', (WidgetTester tester) async { void onEditingComplete() { } await tester.pumpWidget( @@ -880,7 +894,7 @@ void main() { expect(editableTextWidget.onEditingComplete, onEditingComplete); }); - testWidgets('TextField has consistent size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField has consistent size', (WidgetTester tester) async { final Key textFieldKey = UniqueKey(); String? textFieldValue; @@ -923,7 +937,7 @@ void main() { expect(inputBox.size, equals(emptyInputSize)); }); - testWidgets('Cursor blinks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor blinks', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField( @@ -966,8 +980,8 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/78918. - testWidgets('RenderEditable sets correct text editing value', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'how are you'); + testWidgetsWithLeakTracking('RenderEditable sets correct text editing value', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'how are you'); final UniqueKey icon = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -992,7 +1006,7 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 0)); }); - testWidgets('Cursor radius is 2.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor radius is 2.0', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -1007,7 +1021,7 @@ void main() { expect(renderEditable.cursorRadius, const Radius.circular(2.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('cursor has expected defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor has expected defaults', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField(), @@ -1020,7 +1034,7 @@ void main() { expect(textField.cursorRadius, null); }); - testWidgets('cursor has expected radius value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor has expected radius value', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField( @@ -1034,7 +1048,7 @@ void main() { expect(textField.cursorRadius, const Radius.circular(3.0)); }); - testWidgets('clipBehavior has expected defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clipBehavior has expected defaults', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField(), @@ -1045,7 +1059,9 @@ void main() { expect(textField.clipBehavior, Clip.hardEdge); }); - testWidgets('Overflow clipBehavior none golden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow clipBehavior none golden', (WidgetTester tester) async { + final OverflowWidgetTextEditingController controller = OverflowWidgetTextEditingController(); + addTearDown(controller.dispose); final Widget widget = Theme( data: ThemeData(useMaterial3: false), child: overlay( @@ -1059,7 +1075,7 @@ void main() { // Make sure the input field is not high enough for the WidgetSpan. height: 50, child: TextField( - controller: OverflowWidgetTextEditingController(), + controller: controller, clipBehavior: Clip.none, ), ), @@ -1082,7 +1098,7 @@ void main() { ); }); - testWidgets('Material cursor android golden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material cursor android golden', (WidgetTester tester) async { final Widget widget = Theme( data: ThemeData(useMaterial3: false), child: overlay( @@ -1111,7 +1127,7 @@ void main() { ); }); - testWidgets('Material cursor golden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material cursor golden', (WidgetTester tester) async { final Widget widget = Theme( data: ThemeData(useMaterial3: false), child: overlay( @@ -1142,15 +1158,15 @@ void main() { ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('TextInputFormatter gets correct selection value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextInputFormatter gets correct selection value', (WidgetTester tester) async { late TextEditingValue actualOldValue; late TextEditingValue actualNewValue; void callBack(TextEditingValue oldValue, TextEditingValue newValue) { actualOldValue = oldValue; actualNewValue = newValue; } - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(text: '123'); + final FocusNode focusNode = _focusNode(); + final TextEditingController controller = _textEditingController(text: '123'); await tester.pumpWidget( boilerplate( child: TextField( @@ -1183,7 +1199,7 @@ void main() { ); }, skip: areKeyEventsHandledByPlatform); // [intended] only applies to platforms where we handle key events. - testWidgets('text field selection toolbar renders correctly inside opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text field selection toolbar renders correctly inside opacity', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -1235,9 +1251,9 @@ void main() { ); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('text field toolbar options correctly changes options', + testWidgetsWithLeakTracking('text field toolbar options correctly changes options', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -1286,8 +1302,8 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('text selection style 1', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('text selection style 1', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure\nhi\nwasssup!', ); await tester.pumpWidget( @@ -1335,8 +1351,8 @@ void main() { ); }); - testWidgets('text selection style 2', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('text selection style 2', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure\nhi\nwasssup!', ); await tester.pumpWidget( @@ -1400,10 +1416,10 @@ void main() { // Text selection styles are not fully supported on web. }, skip: isBrowser); // https://github.com/flutter/flutter/issues/93723 - testWidgets( + testWidgetsWithLeakTracking( 'text field toolbar options correctly changes options', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -1442,11 +1458,12 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('cursor layout has correct width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor layout has correct width', (WidgetTester tester) async { final TextEditingController controller = TextEditingController.fromValue( const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), ); - final FocusNode focusNode = FocusNode(); + addTearDown(controller.dispose); + final FocusNode focusNode = _focusNode(); EditableText.debugDeterministicCursor = true; await tester.pumpWidget( Theme( @@ -1472,11 +1489,12 @@ void main() { EditableText.debugDeterministicCursor = false; }); - testWidgets('cursor layout has correct radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor layout has correct radius', (WidgetTester tester) async { final TextEditingController controller = TextEditingController.fromValue( const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), ); - final FocusNode focusNode = FocusNode(); + addTearDown(controller.dispose); + final FocusNode focusNode = _focusNode(); EditableText.debugDeterministicCursor = true; await tester.pumpWidget( Theme( @@ -1503,11 +1521,13 @@ void main() { EditableText.debugDeterministicCursor = false; }); - testWidgets('cursor layout has correct height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor layout has correct height', (WidgetTester tester) async { final TextEditingController controller = TextEditingController.fromValue( const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), ); - final FocusNode focusNode = FocusNode(); + addTearDown(controller.dispose); + final FocusNode focusNode = _focusNode(); + EditableText.debugDeterministicCursor = true; await tester.pumpWidget( Theme( @@ -1534,8 +1554,8 @@ void main() { EditableText.debugDeterministicCursor = false; }); - testWidgets('Overflowing a line with spaces stops the cursor at the end', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Overflowing a line with spaces stops the cursor at the end', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( Theme( @@ -1610,7 +1630,7 @@ void main() { expect(cursorOffsetSpaces.dx, inputWidth - kCaretGap); }); - testWidgets('Overflowing a line with spaces stops the cursor at the end (rtl direction)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflowing a line with spaces stops the cursor at the end (rtl direction)', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField( @@ -1637,7 +1657,7 @@ void main() { expect(cursorOffsetSpaces.dx >= 0, isTrue); }); - testWidgets('mobile obscureText control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mobile obscureText control test', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField( @@ -1677,7 +1697,7 @@ void main() { expect(editText.substring(editText.length - 1), '\u2022'); }, variant: const TargetPlatformVariant({ TargetPlatform.android })); - testWidgets('desktop obscureText control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('desktop obscureText control test', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField( @@ -1716,8 +1736,8 @@ void main() { TargetPlatform.windows, })); - testWidgets('Caret position is updated on tap', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Caret position is updated on tap', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1743,8 +1763,8 @@ void main() { expect(controller.selection.extentOffset, tapIndex); }); - testWidgets('enableInteractiveSelection = false, tap', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('enableInteractiveSelection = false, tap', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1771,8 +1791,8 @@ void main() { expect(controller.selection.isCollapsed, isTrue); }); - testWidgets('Can long press to select', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can long press to select', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1806,8 +1826,8 @@ void main() { expect(controller.selection.baseOffset, testValue.indexOf('h')); }); - testWidgets("Slight movements in longpress don't hide/show handles", (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking("Slight movements in longpress don't hide/show handles", (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1845,10 +1865,13 @@ void main() { expect(handle.opacity.value, equals(1.0)); }); - testWidgets('Long pressing a field with selection 0,0 shows the selection menu', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Long pressing a field with selection 0,0 shows the selection menu', (WidgetTester tester) async { + late final TextEditingController controller; + addTearDown(() => controller.dispose()); + await tester.pumpWidget(overlay( child: TextField( - controller: TextEditingController.fromValue( + controller: controller = TextEditingController.fromValue( const TextEditingValue( selection: TextSelection(baseOffset: 0, extentOffset: 0), ), @@ -1863,8 +1886,8 @@ void main() { expect(find.text('Paste'), findsOneWidget); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('Entering text hides selection handle caret', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Entering text hides selection handle caret', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1905,9 +1928,9 @@ void main() { expect(handle.opacity.value, equals(0.0)); }); - testWidgets('selection handles are excluded from the semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection handles are excluded from the semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1951,8 +1974,8 @@ void main() { semantics.dispose(); }); - testWidgets('Mouse long press is just like a tap', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Mouse long press is just like a tap', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -1982,8 +2005,8 @@ void main() { expect(controller.selection.extentOffset, eIndex); }); - testWidgets('Read only text field basic', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'readonly'); + testWidgetsWithLeakTracking('Read only text field basic', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'readonly'); await tester.pumpWidget( overlay( @@ -2020,7 +2043,7 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('does not paint toolbar when no options available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not paint toolbar when no options available', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -2041,7 +2064,7 @@ void main() { expect(find.byType(CupertinoTextSelectionToolbar), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('text field build empty toolbar when no options available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text field build empty toolbar when no options available', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -2065,8 +2088,8 @@ void main() { expect(container.size, Size.zero); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('Swapping controllers should update selection', (WidgetTester tester) async { - TextEditingController controller = TextEditingController(text: 'readonly'); + testWidgetsWithLeakTracking('Swapping controllers should update selection', (WidgetTester tester) async { + TextEditingController controller = _textEditingController(text: 'readonly'); final OverlayEntry entry = OverlayEntry( builder: (BuildContext context) { return Center( @@ -2079,6 +2102,7 @@ void main() { ); }, ); + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget(overlayWithEntry(entry)); const int dIndex = 3; final Offset dPos = textOffsetToPosition(tester, dIndex); @@ -2097,6 +2121,7 @@ void main() { extentOffset: 7, )), ); + addTearDown(controller.dispose); // Mark entry to be dirty in order to trigger overlay update. entry.markNeedsBuild(); @@ -2107,13 +2132,14 @@ void main() { expect(currentOverlaySelection.extentOffset, 7); }); - testWidgets('Read only text should not compose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Read only text should not compose', (WidgetTester tester) async { final TextEditingController controller = TextEditingController.fromValue( const TextEditingValue( text: 'readonly', composing: TextRange(start: 0, end: 8), // Simulate text composing. ), ); + addTearDown(controller.dispose); await tester.pumpWidget( overlay( @@ -2129,8 +2155,8 @@ void main() { expect(renderEditable.text, TextSpan(text:'readonly', style: renderEditable.text!.style)); }); - testWidgets('Dynamically switching between read only and not read only should hide or show collapse cursor', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'readonly'); + testWidgetsWithLeakTracking('Dynamically switching between read only and not read only should hide or show collapse cursor', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'readonly'); bool readOnly = true; final OverlayEntry entry = OverlayEntry( builder: (BuildContext context) { @@ -2144,6 +2170,7 @@ void main() { ); }, ); + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget(overlayWithEntry(entry)); await tester.tap(find.byType(TextField)); await tester.pump(); @@ -2164,8 +2191,8 @@ void main() { expect(editableText.selectionOverlay!.handlesAreVisible, isFalse); }); - testWidgets('Dynamically switching to read only should close input connection', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'readonly'); + testWidgetsWithLeakTracking('Dynamically switching to read only should close input connection', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'readonly'); bool readOnly = false; final OverlayEntry entry = OverlayEntry( builder: (BuildContext context) { @@ -2179,6 +2206,7 @@ void main() { ); }, ); + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget(overlayWithEntry(entry)); await tester.tap(find.byType(TextField)); await tester.pump(); @@ -2192,8 +2220,8 @@ void main() { expect(tester.testTextInput.hasAnyClients, isBrowser ? isTrue : isFalse); }); - testWidgets('Dynamically switching to non read only should open input connection', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'readonly'); + testWidgetsWithLeakTracking('Dynamically switching to non read only should open input connection', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'readonly'); bool readOnly = true; final OverlayEntry entry = OverlayEntry( builder: (BuildContext context) { @@ -2207,6 +2235,7 @@ void main() { ); }, ); + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget(overlayWithEntry(entry)); await tester.tap(find.byType(TextField)); await tester.pump(); @@ -2220,8 +2249,8 @@ void main() { expect(tester.testTextInput.hasAnyClients, true); }); - testWidgets('enableInteractiveSelection = false, long-press', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('enableInteractiveSelection = false, long-press', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -2248,8 +2277,8 @@ void main() { expect(controller.selection.baseOffset, testValue.length); }); - testWidgets('Selection updates on tap down (Desktop platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Selection updates on tap down (Desktop platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2287,8 +2316,8 @@ void main() { variant: TargetPlatformVariant.desktop(), ); - testWidgets('Selection updates on tap up (Mobile platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Selection updates on tap up (Mobile platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); final bool isTargetPlatformApple = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( @@ -2341,9 +2370,9 @@ void main() { variant: TargetPlatformVariant.mobile(), ); - testWidgets('Can select text with a mouse when wrapped in a GestureDetector with tap/double tap callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select text with a mouse when wrapped in a GestureDetector with tap/double tap callbacks', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/129161. - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2387,8 +2416,8 @@ void main() { expect(controller.selection.extentOffset, testValue.indexOf('g')); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Can select text by dragging with a mouse', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can select text by dragging with a mouse', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2420,7 +2449,7 @@ void main() { }); testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2466,8 +2495,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets('Cursor should not move on a quick touch drag when touch does not begin on previous selection (iOS)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Cursor should not move on a quick touch drag when touch does not begin on previous selection (iOS)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2512,7 +2541,7 @@ void main() { ); testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS) - multiline', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2562,7 +2591,7 @@ void main() { testWidgets('Can move cursor when dragging, when tap is on collapsed selection (iOS) - ListView', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/122519 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2636,8 +2665,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets('Can move cursor when dragging (Android)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can move cursor when dragging (Android)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2680,8 +2709,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia }), ); - testWidgets('Can move cursor when dragging (Android) - multiline', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can move cursor when dragging (Android) - multiline', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2725,10 +2754,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia }), ); - testWidgets('Can move cursor when dragging (Android) - ListView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move cursor when dragging (Android) - ListView', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/122519 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2796,10 +2825,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia }), ); - testWidgets('Continuous dragging does not cause flickering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Continuous dragging does not cause flickering', (WidgetTester tester) async { int selectionChangedCount = 0; const String testValue = 'abc def ghi'; - final TextEditingController controller = TextEditingController(text: testValue); + final TextEditingController controller = _textEditingController(text: testValue); controller.addListener(() { selectionChangedCount++; @@ -2848,8 +2877,8 @@ void main() { expect(controller.selection.extentOffset, 9); }); - testWidgets('Dragging in opposite direction also works', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Dragging in opposite direction also works', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2880,8 +2909,8 @@ void main() { expect(controller.selection.extentOffset, testValue.indexOf('e')); }); - testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Slow mouse dragging also selects text', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -2911,8 +2940,8 @@ void main() { expect(controller.selection.extentOffset, testValue.indexOf('g')); }); - testWidgets('Can drag handles to change selection on Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can drag handles to change selection on Apple platforms', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -3023,8 +3052,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('Can drag handles to change selection on non-Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can drag handles to change selection on non-Apple platforms', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -3128,14 +3157,15 @@ void main() { variant: TargetPlatformVariant.all(excluding: { TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can drag the left handle while the right handle remains off-screen', (WidgetTester tester) async { // Text is longer than textfield width. const String testValue = 'aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb'; - final TextEditingController controller = TextEditingController(text: testValue); + final TextEditingController controller = _textEditingController(text: testValue); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( MaterialApp( @@ -3215,14 +3245,15 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Can drag the right handle while the left handle remains off-screen', (WidgetTester tester) async { // Text is longer than textfield width. const String testValue = 'aaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbb'; - final TextEditingController controller = TextEditingController(text: testValue); + final TextEditingController controller = _textEditingController(text: testValue); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( MaterialApp( @@ -3291,10 +3322,10 @@ void main() { }, ); - testWidgets('Drag handles trigger feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag handles trigger feedback', (WidgetTester tester) async { final FeedbackTester feedback = FeedbackTester(); addTearDown(feedback.dispose); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( child: TextField( @@ -3346,10 +3377,10 @@ void main() { expect(feedback.hapticCount, 2); }); - testWidgets('Dragging a collapsed handle should trigger feedback.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dragging a collapsed handle should trigger feedback.', (WidgetTester tester) async { final FeedbackTester feedback = FeedbackTester(); addTearDown(feedback.dispose); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( child: TextField( @@ -3401,8 +3432,8 @@ void main() { expect(feedback.hapticCount, 1); }); - testWidgets('Cannot drag one handle past the other', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Cannot drag one handle past the other', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -3461,8 +3492,8 @@ void main() { expect(controller.selection.extentOffset, 5); }); - testWidgets('Dragging between multiple lines keeps the contact point at the same place on the handle on Android', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Dragging between multiple lines keeps the contact point at the same place on the handle on Android', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( // 11 first line, 19 second line, 17 third line = length 49 text: 'a big house\njumped over a mouse\nOne more line yay', ); @@ -3649,8 +3680,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), ); - testWidgets('Dragging between multiple lines keeps the contact point at the same place on the handle on iOS', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Dragging between multiple lines keeps the contact point at the same place on the handle on iOS', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( // 11 first line, 19 second line, 17 third line = length 49 text: 'a big house\njumped over a mouse\nOne more line yay', ); @@ -3847,7 +3878,7 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets("dragging caret within a word doesn't affect composing region", (WidgetTester tester) async { + testWidgetsWithLeakTracking("dragging caret within a word doesn't affect composing region", (WidgetTester tester) async { const String testValue = 'abc def ghi'; final TextEditingController controller = TextEditingController.fromValue( const TextEditingValue( @@ -3863,6 +3894,7 @@ void main() { ), ), ); + addTearDown(controller.dispose); await tester.pumpWidget( overlay( child: TextField( @@ -3917,8 +3949,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.iOS }) ); - testWidgets('Can use selection toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can use selection toolbar', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -4011,12 +4043,12 @@ void main() { await tester.pump(const Duration(milliseconds: 200)); // skip past the frame where the opacity is zero } - testWidgets( + testWidgetsWithLeakTracking( 'Check the toolbar appears below the TextField when there is not enough space above the TextField to show it', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/29808 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -4065,10 +4097,10 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'the toolbar adjusts its position above/below when bottom inset changes', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -4133,12 +4165,12 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'Toolbar appears in the right places in multiline inputs', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/36749 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -4190,8 +4222,8 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Selection toolbar fades in', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Selection toolbar fades in', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -4236,11 +4268,11 @@ void main() { // End the test here to ensure the animation is properly disposed of. }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('An obscured TextField is selectable by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('An obscured TextField is selectable by default', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/32845 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); Widget buildFrame(bool obscureText) { return overlay( child: TextField( @@ -4263,11 +4295,11 @@ void main() { expect(controller.selection.isCollapsed, false); }); - testWidgets('An obscured TextField is not selectable when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('An obscured TextField is not selectable when disabled', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/32845 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); Widget buildFrame(bool obscureText, bool enableInteractiveSelection) { return overlay( child: TextField( @@ -4291,11 +4323,11 @@ void main() { expect(controller.selection.isCollapsed, true); }); - testWidgets('An obscured TextField is not selectable when read-only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('An obscured TextField is not selectable when read-only', (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/32845 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); Widget buildFrame(bool obscureText, bool readOnly) { return overlay( child: TextField( @@ -4319,8 +4351,8 @@ void main() { expect(controller.selection.isCollapsed, true); }); - testWidgets('An obscured TextField is selected as one word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('An obscured TextField is selected as one word', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget(overlay( child: TextField( @@ -4341,8 +4373,8 @@ void main() { expect(selection.extentOffset, 10); }); - testWidgets('An obscured TextField has correct default context menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('An obscured TextField has correct default context menu', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget(overlay( child: TextField( @@ -4377,7 +4409,7 @@ void main() { expect(find.text('Cut'), findsNothing); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('create selection overlay if none exists when toggleToolbar is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('create selection overlay if none exists when toggleToolbar is called', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/111660 final Widget testWidget = MaterialApp( home: Scaffold( @@ -4426,7 +4458,7 @@ void main() { expect(tester.takeException(), isNull); }, variant: const TargetPlatformVariant({TargetPlatform.iOS})); - testWidgets('TextField height with minLines unset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField height with minLines unset', (WidgetTester tester) async { await tester.pumpWidget(textFieldBuilder()); RenderBox findInputBox() => tester.renderObject(find.byKey(textFieldKey)); @@ -4490,7 +4522,7 @@ void main() { expect(inputBox.size.width, fourLineInputSize.width); }); - testWidgets('TextField height with minLines and maxLines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField height with minLines and maxLines', (WidgetTester tester) async { await tester.pumpWidget(textFieldBuilder()); RenderBox findInputBox() => tester.renderObject(find.byKey(textFieldKey)); @@ -4541,7 +4573,7 @@ void main() { }, throwsAssertionError); }); - testWidgets('Multiline text when wrapped in Expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiline text when wrapped in Expanded', (WidgetTester tester) async { Widget expandedTextFieldBuilder({ int? maxLines = 1, int? minLines, @@ -4598,7 +4630,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/pull/29093 - testWidgets('Multiline text when wrapped in IntrinsicHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiline text when wrapped in IntrinsicHeight', (WidgetTester tester) async { final Key intrinsicHeightKey = UniqueKey(); Widget intrinsicTextFieldBuilder(bool wrapInIntrinsic) { final TextFormField textField = TextFormField( @@ -4635,7 +4667,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/pull/29093 - testWidgets('errorText empty string', (WidgetTester tester) async { + testWidgetsWithLeakTracking('errorText empty string', (WidgetTester tester) async { Widget textFormFieldBuilder(String? errorText) { return boilerplate( child: Column( @@ -4680,7 +4712,7 @@ void main() { expect(inputBox.size.width, errorNullInputSize.width); }); - testWidgets('Growable TextField when content height exceeds parent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Growable TextField when content height exceeds parent', (WidgetTester tester) async { const double height = 200.0; const double padding = 24.0; @@ -4789,7 +4821,7 @@ void main() { ); }); - testWidgets('Multiline hint text will wrap up to maxLines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiline hint text will wrap up to maxLines', (WidgetTester tester) async { final Key textFieldKey = UniqueKey(); Widget builder(int? maxLines, final String hintMsg) { @@ -4826,8 +4858,8 @@ void main() { expect(findHintText(multipleLineText).size.height, greaterThanOrEqualTo(oneLineHintSize.height)); }); - testWidgets('Can drag handles to change selection in multiline', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can drag handles to change selection in multiline', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( Theme( @@ -4925,9 +4957,9 @@ void main() { } }); - testWidgets('Can scroll multiline input', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can scroll multiline input', (WidgetTester tester) async { final Key textFieldKey = UniqueKey(); - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: kMoreThanFourLines, ); @@ -5021,7 +5053,7 @@ void main() { expect(inputBox.hitTest(BoxHitTestResult(), position: inputBox.globalToLocal(newFourthPos)), isFalse); }); - testWidgets('TextField smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField smoke test', (WidgetTester tester) async { late String textFieldValue; await tester.pumpWidget( @@ -5049,7 +5081,7 @@ void main() { await checkText('Hello World'); }); - testWidgets('TextField with global key', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with global key', (WidgetTester tester) async { final GlobalKey textFieldKey = GlobalKey(debugLabel: 'textFieldKey'); late String textFieldValue; @@ -5079,7 +5111,7 @@ void main() { await checkText('Hello World'); }); - testWidgets('TextField errorText trumps helperText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField errorText trumps helperText', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -5097,7 +5129,7 @@ void main() { expect(find.text('error text'), findsOneWidget); }); - testWidgets('TextField with default helperStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with default helperStyle', (WidgetTester tester) async { final ThemeData themeData = ThemeData(hintColor: Colors.blue[500], useMaterial3: false); await tester.pumpWidget( overlay( @@ -5116,7 +5148,7 @@ void main() { expect(helperText.style!.fontSize, Typography.englishLike2014.bodySmall!.fontSize); }); - testWidgets('TextField with specified helperStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with specified helperStyle', (WidgetTester tester) async { final TextStyle style = TextStyle( inherit: false, color: Colors.pink[500], @@ -5137,7 +5169,7 @@ void main() { expect(helperText.style, style); }); - testWidgets('TextField with default hintStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with default hintStyle', (WidgetTester tester) async { final TextStyle style = TextStyle( color: Colors.pink[500], fontSize: 10.0, @@ -5165,7 +5197,7 @@ void main() { expect(hintText.style!.fontSize, style.fontSize); }); - testWidgets('TextField with specified hintStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with specified hintStyle', (WidgetTester tester) async { final TextStyle hintStyle = TextStyle( inherit: false, color: Colors.pink[500], @@ -5187,7 +5219,7 @@ void main() { expect(hintText.style, hintStyle); }); - testWidgets('TextField with specified prefixStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with specified prefixStyle', (WidgetTester tester) async { final TextStyle prefixStyle = TextStyle( inherit: false, color: Colors.pink[500], @@ -5209,12 +5241,12 @@ void main() { expect(prefixText.style, prefixStyle); }); - testWidgets('TextField prefix and suffix create a sibling node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField prefix and suffix create a sibling node', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( overlay( child: TextField( - controller: TextEditingController(text: 'some text'), + controller: _textEditingController(text: 'some text'), decoration: const InputDecoration( prefixText: 'Prefix', suffixText: 'Suffix', @@ -5251,7 +5283,7 @@ void main() { semantics.dispose(); }); - testWidgets('TextField with specified suffixStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField with specified suffixStyle', (WidgetTester tester) async { final TextStyle suffixStyle = TextStyle( color: Colors.pink[500], fontSize: 10.0, @@ -5272,7 +5304,7 @@ void main() { expect(suffixText.style, suffixStyle); }); - testWidgets('TextField prefix and suffix appear correctly with no hint or label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField prefix and suffix appear correctly with no hint or label', (WidgetTester tester) async { final Key secondKey = UniqueKey(); await tester.pumpWidget( @@ -5315,7 +5347,7 @@ void main() { expect(find.text('Suffix'), findsOneWidget); }); - testWidgets('TextField prefix and suffix appear correctly with hint text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField prefix and suffix appear correctly with hint text', (WidgetTester tester) async { final TextStyle hintStyle = TextStyle( inherit: false, color: Colors.pink[500], @@ -5375,7 +5407,7 @@ void main() { expect(suffixText.style, hintStyle); }); - testWidgets('TextField prefix and suffix appear correctly with label text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField prefix and suffix appear correctly with label text', (WidgetTester tester) async { final TextStyle prefixStyle = TextStyle( color: Colors.pink[500], fontSize: 10.0, @@ -5438,7 +5470,7 @@ void main() { expect(suffixText.style, suffixStyle); }); - testWidgets('TextField label text animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField label text animates', (WidgetTester tester) async { final Key secondKey = UniqueKey(); await tester.pumpWidget( @@ -5479,7 +5511,7 @@ void main() { expect(newPos.dy, lessThan(pos.dy)); }); - testWidgets('Icon is separated from input/label by 16+12', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon is separated from input/label by 16+12', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const TextField( @@ -5500,7 +5532,7 @@ void main() { expect(iconRight + 28.0, equals(tester.getTopLeft(find.byType(EditableText)).dx)); }); - testWidgets('Collapsed hint text placement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Collapsed hint text placement', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -5518,7 +5550,7 @@ void main() { expect(tester.getTopLeft(find.text('hint')), equals(tester.getTopLeft(find.byType(EditableText)))); }); - testWidgets('Can align to center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can align to center', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SizedBox( @@ -5553,7 +5585,7 @@ void main() { expect(topLeft.dx, equals(399.0)); }); - testWidgets('Can align to center within center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can align to center within center', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SizedBox( @@ -5589,11 +5621,11 @@ void main() { expect(topLeft.dx, equals(399.0)); }); - testWidgets('Controller can update server', (WidgetTester tester) async { - final TextEditingController controller1 = TextEditingController( + testWidgetsWithLeakTracking('Controller can update server', (WidgetTester tester) async { + final TextEditingController controller1 = _textEditingController( text: 'Initial Text', ); - final TextEditingController controller2 = TextEditingController( + final TextEditingController controller2 = _textEditingController( text: 'More Text', ); @@ -5672,8 +5704,8 @@ void main() { expect(tester.testTextInput.editingState!['text'], equals('The Final Cut')); }); - testWidgets('Cannot enter new lines onto single line TextField', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Cannot enter new lines onto single line TextField', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField(controller: textController, decoration: null), @@ -5684,8 +5716,8 @@ void main() { expect(textController.text, 'abcdef'); }); - testWidgets('Injected formatters are chained', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Injected formatters are chained', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -5705,8 +5737,8 @@ void main() { expect(textController.text, '#一#二#三#四#五#六'); }); - testWidgets('Injected formatters are chained (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Injected formatters are chained (deprecated names)', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -5726,8 +5758,8 @@ void main() { expect(textController.text, '#一#二#三#四#五#六'); }); - testWidgets('Chained formatters are in sequence', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Chained formatters are in sequence', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -5753,8 +5785,8 @@ void main() { expect(textController.text, '\n1\n2\n3'); }); - testWidgets('Chained formatters are in sequence (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Chained formatters are in sequence (deprecated names)', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -5780,8 +5812,8 @@ void main() { expect(textController.text, '\n1\n2\n3'); }); - testWidgets('Pasted values are formatted', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Pasted values are formatted', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget( overlay( @@ -5818,8 +5850,8 @@ void main() { expect(textController.text, '145623'); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('Pasted values are formatted (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('Pasted values are formatted (deprecated names)', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget( overlay( @@ -5856,7 +5888,7 @@ void main() { expect(textController.text, '145623'); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('Do not add LengthLimiting formatter to the user supplied list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not add LengthLimiting formatter to the user supplied list', (WidgetTester tester) async { final List formatters = []; await tester.pumpWidget( @@ -5872,8 +5904,8 @@ void main() { expect(formatters.isEmpty, isTrue); }); - testWidgets('Text field scrolls the caret into view', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Text field scrolls the caret into view', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( Theme( @@ -5915,8 +5947,8 @@ void main() { expect(scrollableState.position.pixels, equals(222.0)); }); - testWidgets('Multiline text field scrolls the caret into view', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Multiline text field scrolls the caret into view', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -5953,10 +5985,10 @@ void main() { expect(scrollableState.position.pixels, moreOrLessEquals(lineHeight, epsilon: 0.1)); }); - testWidgets('haptic feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('haptic feedback', (WidgetTester tester) async { final FeedbackTester feedback = FeedbackTester(); addTearDown(feedback.dispose); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -5980,11 +6012,11 @@ void main() { expect(feedback.hapticCount, 1); }); - testWidgets('Text field drops selection color when losing focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text field drops selection color when losing focus', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/103341. final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); - final TextEditingController controller1 = TextEditingController(); + final TextEditingController controller1 = _textEditingController(); const Color selectionColor = Colors.orange; const Color cursorColor = Colors.red; @@ -6035,8 +6067,8 @@ void main() { expect(state2.widget.selectionColor, selectionColor); }); - testWidgets('Selection is consistent with text length', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Selection is consistent with text length', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); controller.text = 'abcde'; controller.selection = const TextSelection.collapsed(offset: 5); @@ -6064,8 +6096,8 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/35848 - testWidgets('Clearing text field with suffixIcon does not cause text selection exception', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Clearing text field with suffixIcon does not cause text selection exception', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Prefilled text.', ); @@ -6087,8 +6119,8 @@ void main() { expect(controller.text, ''); }); - testWidgets('maxLength limits input.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength limits input.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6101,8 +6133,8 @@ void main() { expect(textController.text, '0123456789'); }); - testWidgets('maxLength limits input with surrogate pairs.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength limits input with surrogate pairs.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6116,8 +6148,8 @@ void main() { expect(textController.text, '${surrogatePair}012345678'); }); - testWidgets('maxLength limits input with grapheme clusters.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength limits input with grapheme clusters.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6131,9 +6163,9 @@ void main() { expect(textController.text, '${graphemeCluster}012345678'); }); - testWidgets('maxLength limits input in the center of a maxed-out field.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maxLength limits input in the center of a maxed-out field.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/37420. - final TextEditingController textController = TextEditingController(); + final TextEditingController textController = _textEditingController(); const String testValue = '0123456789'; await tester.pumpWidget(boilerplate( @@ -6156,10 +6188,10 @@ void main() { expect(textController.text, testValue); }); - testWidgets( + testWidgetsWithLeakTracking( 'maxLength limits input in the center of a maxed-out field, with collapsed selection', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + final TextEditingController textController = _textEditingController(); const String testValue = '0123456789'; await tester.pumpWidget(boilerplate( @@ -6201,10 +6233,10 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'maxLength limits input in the center of a maxed-out field, with non-collapsed selection', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + final TextEditingController textController = _textEditingController(); const String testValue = '0123456789'; await tester.pumpWidget(boilerplate( @@ -6236,8 +6268,8 @@ void main() { }, ); - testWidgets('maxLength limits input length even if decoration is null.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength limits input length even if decoration is null.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6251,8 +6283,8 @@ void main() { expect(textController.text, '0123456789'); }); - testWidgets('maxLength still works with other formatters', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength still works with other formatters', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6272,8 +6304,8 @@ void main() { expect(textController.text, '#一#二#三#四#五'); }); - testWidgets('maxLength still works with other formatters (deprecated names)', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength still works with other formatters (deprecated names)', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6293,8 +6325,8 @@ void main() { expect(textController.text, '#一#二#三#四#五'); }); - testWidgets("maxLength isn't enforced when maxLengthEnforcement.none.", (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking("maxLength isn't enforced when maxLengthEnforcement.none.", (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6308,8 +6340,8 @@ void main() { expect(textController.text, '0123456789101112'); }); - testWidgets('maxLength shows warning when maxLengthEnforcement.none.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength shows warning when maxLengthEnforcement.none.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); const TextStyle testStyle = TextStyle(color: Colors.deepPurpleAccent); await tester.pumpWidget(boilerplate( @@ -6338,8 +6370,8 @@ void main() { expect(counterTextWidget.style!.color, isNot(equals(Colors.deepPurpleAccent))); }); - testWidgets('maxLength shows warning in Material 3', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength shows warning in Material 3', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); final ThemeData theme = ThemeData.from( colorScheme: const ColorScheme.light().copyWith(error: Colors.deepPurpleAccent), useMaterial3: true, @@ -6370,8 +6402,8 @@ void main() { expect(counterTextWidget.style!.color, isNot(equals(Colors.deepPurpleAccent))); }); - testWidgets('maxLength shows warning when maxLengthEnforcement.none with surrogate pairs.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength shows warning when maxLengthEnforcement.none with surrogate pairs.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); const TextStyle testStyle = TextStyle(color: Colors.deepPurpleAccent); await tester.pumpWidget(boilerplate( @@ -6400,8 +6432,8 @@ void main() { expect(counterTextWidget.style!.color, isNot(equals(Colors.deepPurpleAccent))); }); - testWidgets('maxLength shows warning when maxLengthEnforcement.none with grapheme clusters.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength shows warning when maxLengthEnforcement.none with grapheme clusters.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); const TextStyle testStyle = TextStyle(color: Colors.deepPurpleAccent); await tester.pumpWidget(boilerplate( @@ -6430,8 +6462,8 @@ void main() { expect(counterTextWidget.style!.color, isNot(equals(Colors.deepPurpleAccent))); }); - testWidgets('maxLength limits input with surrogate pairs.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength limits input with surrogate pairs.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6445,8 +6477,8 @@ void main() { expect(textController.text, '${surrogatePair}012345678'); }); - testWidgets('maxLength limits input with grapheme clusters.', (WidgetTester tester) async { - final TextEditingController textController = TextEditingController(); + testWidgetsWithLeakTracking('maxLength limits input with grapheme clusters.', (WidgetTester tester) async { + final TextEditingController textController = _textEditingController(); await tester.pumpWidget(boilerplate( child: TextField( @@ -6460,7 +6492,7 @@ void main() { expect(textController.text, '${graphemeCluster}012345678'); }); - testWidgets('setting maxLength shows counter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setting maxLength shows counter', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: Center( @@ -6480,7 +6512,7 @@ void main() { expect(find.text('5/10'), findsOneWidget); }); - testWidgets('maxLength counter measures surrogate pairs as one character', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maxLength counter measures surrogate pairs as one character', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: Center( @@ -6501,7 +6533,7 @@ void main() { expect(find.text('1/10'), findsOneWidget); }); - testWidgets('maxLength counter measures grapheme clusters as one character', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maxLength counter measures grapheme clusters as one character', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: Center( @@ -6522,7 +6554,7 @@ void main() { expect(find.text('1/10'), findsOneWidget); }); - testWidgets('setting maxLength to TextField.noMaxLength shows only entered length', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setting maxLength to TextField.noMaxLength shows only entered length', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Material( child: Center( @@ -6542,7 +6574,7 @@ void main() { expect(find.text('5'), findsOneWidget); }); - testWidgets('passing a buildCounter shows returned widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing a buildCounter shows returned widget', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -6565,7 +6597,7 @@ void main() { expect(find.text('5 of 10'), findsOneWidget); }); - testWidgets('TextField identifies as text field in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField identifies as text field in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -6585,7 +6617,7 @@ void main() { semantics.dispose(); }); - testWidgets('Disabled text field does not have tap action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled text field does not have tap action', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( const MaterialApp( @@ -6604,7 +6636,7 @@ void main() { semantics.dispose(); }); - testWidgets('Disabled text field semantics node still contains value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled text field semantics node still contains value', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -6612,7 +6644,7 @@ void main() { home: Material( child: Center( child: TextField( - controller: TextEditingController(text: 'text'), + controller: _textEditingController(text: 'text'), maxLength: 10, enabled: false, ), @@ -6625,7 +6657,7 @@ void main() { semantics.dispose(); }); - testWidgets('Readonly text field does not have tap action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Readonly text field does not have tap action', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -6646,7 +6678,7 @@ void main() { semantics.dispose(); }); - testWidgets('Disabled text field hides helper and counter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled text field hides helper and counter', (WidgetTester tester) async { const String helperText = 'helper text'; const String counterText = 'counter text'; const String errorText = 'error text'; @@ -6693,8 +6725,8 @@ void main() { expect(errorWidget.style!.color, equals(Colors.transparent)); }); - testWidgets('Disabled text field has default M2 disabled text style for the input text', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Disabled text field has default M2 disabled text style for the input text', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); @@ -6715,8 +6747,8 @@ void main() { expect(editableText.style.color, Colors.black38); // Colors.black38 is the default disabled color for ThemeData.light(). }); - testWidgets('Disabled text field has default M3 disabled text style for the input text', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Disabled text field has default M3 disabled text style for the input text', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); @@ -6739,8 +6771,8 @@ void main() { expect(editableText.style.color, theme.textTheme.bodyLarge!.color!.withOpacity(0.38)); }); - testWidgets('Provided style correctly resolves for material states', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Provided style correctly resolves for material states', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); @@ -6774,9 +6806,9 @@ void main() { expect(editableText.style.color, Colors.blue); }); - testWidgets('currentValueLength/maxValueLength are in the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('currentValueLength/maxValueLength are in the tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -6815,7 +6847,7 @@ void main() { semantics.dispose(); }); - testWidgets('Read only TextField identifies as read only text field in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Read only TextField identifies as read only text field in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -6839,9 +6871,12 @@ void main() { semantics.dispose(); }); - testWidgets("Disabled TextField can't be traversed to.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Disabled TextField can't be traversed to.", (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: 'TextField 1'); + addTearDown(focusNode1.dispose); final FocusNode focusNode2 = FocusNode(debugLabel: 'TextField 2'); + addTearDown(focusNode2.dispose); + await tester.pumpWidget( MaterialApp( home: Material( @@ -6883,12 +6918,12 @@ void main() { late TextEditingController controller; setUp( () { - controller = TextEditingController(); + controller = _textEditingController(); }); Future setupWidget(WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - controller = TextEditingController(); + final FocusNode focusNode = _focusNode(); + controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -6906,7 +6941,7 @@ void main() { await tester.pump(); } - testWidgets('Shift test 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shift test 1', (WidgetTester tester) async { await setupWidget(tester); const String testValue = 'a big house'; await tester.enterText(find.byType(TextField), testValue); @@ -6923,7 +6958,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, -1); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Shift test 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shift test 2', (WidgetTester tester) async { await setupWidget(tester); const String testValue = 'abcdefghi'; @@ -6941,7 +6976,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, 1); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Control Shift test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Control Shift test', (WidgetTester tester) async { await setupWidget(tester); const String testValue = 'their big house'; await tester.enterText(find.byType(TextField), testValue); @@ -6958,7 +6993,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, 5); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Down and up test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Down and up test', (WidgetTester tester) async { await setupWidget(tester); const String testValue = 'a big house'; await tester.enterText(find.byType(TextField), testValue); @@ -6985,7 +7020,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, 0); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Down and up test 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Down and up test 2', (WidgetTester tester) async { await setupWidget(tester); const String testValue = 'a big house\njumped over a mouse\nOne more line yay'; // 11 \n 19 await tester.enterText(find.byType(TextField), testValue); @@ -7041,8 +7076,8 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, -5); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Read only keyboard selection test', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'readonly'); + testWidgetsWithLeakTracking('Read only keyboard selection test', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'readonly'); await tester.pumpWidget( overlay( child: TextField( @@ -7062,9 +7097,9 @@ void main() { }, variant: KeySimulatorTransitModeVariant.all()); }, skip: areKeyEventsHandledByPlatform); // [intended] only applies to platforms where we handle key events. - testWidgets('Copy paste test', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Copy paste test', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); + final TextEditingController controller = _textEditingController(); final TextField textField = TextField( controller: controller, @@ -7140,9 +7175,9 @@ void main() { ); // Regression test for https://github.com/flutter/flutter/issues/78219 - testWidgets('Paste does not crash after calling TextController.text setter', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Paste does not crash after calling TextController.text setter', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); + final TextEditingController controller = _textEditingController(); final TextField textField = TextField( controller: controller, obscureText: true, @@ -7192,9 +7227,9 @@ void main() { variant: KeySimulatorTransitModeVariant.all(), ); - testWidgets('Cut test', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Cut test', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); + final TextEditingController controller = _textEditingController(); final TextField textField = TextField( controller: controller, @@ -7271,9 +7306,9 @@ void main() { variant: KeySimulatorTransitModeVariant.all() ); - testWidgets('Select all test', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Select all test', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); + final TextEditingController controller = _textEditingController(); final TextField textField = TextField( controller: controller, @@ -7322,9 +7357,9 @@ void main() { variant: KeySimulatorTransitModeVariant.all() ); - testWidgets('Delete test', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Delete test', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); + final TextEditingController controller = _textEditingController(); final TextField textField = TextField( controller: controller, @@ -7376,13 +7411,13 @@ void main() { variant: KeySimulatorTransitModeVariant.all(), ); - testWidgets('Changing positions of text fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing positions of text fields', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + final FocusNode focusNode = _focusNode(); final List events = []; - final TextEditingController c1 = TextEditingController(); - final TextEditingController c2 = TextEditingController(); + final TextEditingController c1 = _textEditingController(); + final TextEditingController c2 = _textEditingController(); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); @@ -7471,12 +7506,12 @@ void main() { variant: KeySimulatorTransitModeVariant.all() ); - testWidgets('Changing focus test', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Changing focus test', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); final List events = []; - final TextEditingController c1 = TextEditingController(); - final TextEditingController c2 = TextEditingController(); + final TextEditingController c1 = _textEditingController(); + final TextEditingController c2 = _textEditingController(); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); @@ -7548,8 +7583,8 @@ void main() { variant: KeySimulatorTransitModeVariant.all() ); - testWidgets('Caret works when maxLines is null', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Caret works when maxLines is null', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( @@ -7575,9 +7610,9 @@ void main() { expect(controller.selection.baseOffset, 0); }); - testWidgets('TextField baseline alignment no-strut', (WidgetTester tester) async { - final TextEditingController controllerA = TextEditingController(text: 'A'); - final TextEditingController controllerB = TextEditingController(text: 'B'); + testWidgetsWithLeakTracking('TextField baseline alignment no-strut', (WidgetTester tester) async { + final TextEditingController controllerA = _textEditingController(text: 'A'); + final TextEditingController controllerB = _textEditingController(text: 'B'); final Key keyA = UniqueKey(); final Key keyB = UniqueKey(); @@ -7637,9 +7672,9 @@ void main() { expect(tester.getBottomLeft(find.byKey(keyB)).dy, rowBottomY); }); - testWidgets('TextField baseline alignment', (WidgetTester tester) async { - final TextEditingController controllerA = TextEditingController(text: 'A'); - final TextEditingController controllerB = TextEditingController(text: 'B'); + testWidgetsWithLeakTracking('TextField baseline alignment', (WidgetTester tester) async { + final TextEditingController controllerA = _textEditingController(text: 'A'); + final TextEditingController controllerB = _textEditingController(text: 'B'); final Key keyA = UniqueKey(); final Key keyB = UniqueKey(); @@ -7698,9 +7733,9 @@ void main() { expect(tester.getBottomLeft(find.byKey(keyB)).dy, rowBottomY); }); - testWidgets('TextField semantics include label when unfocused and label/hint when focused if input is empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics include label when unfocused and label/hint when focused if input is empty', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(text: ''); + final TextEditingController controller = _textEditingController(); final Key key = UniqueKey(); await tester.pumpWidget( @@ -7730,9 +7765,9 @@ void main() { semantics.dispose(); }); - testWidgets('TextField semantics alway include label and not hint when input value is not empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics alway include label and not hint when input value is not empty', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(text: 'value'); + final TextEditingController controller = _textEditingController(text: 'value'); final Key key = UniqueKey(); await tester.pumpWidget( @@ -7762,9 +7797,9 @@ void main() { semantics.dispose(); }); - testWidgets('TextField semantics always include label when no hint is given', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics always include label when no hint is given', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(text: 'value'); + final TextEditingController controller = _textEditingController(text: 'value'); final Key key = UniqueKey(); await tester.pumpWidget( @@ -7793,9 +7828,9 @@ void main() { semantics.dispose(); }); - testWidgets('TextField semantics only include hint when it is visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics only include hint when it is visible', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(text: 'value'); + final TextEditingController controller = _textEditingController(text: 'value'); final Key key = UniqueKey(); await tester.pumpWidget( @@ -7832,9 +7867,9 @@ void main() { semantics.dispose(); }); - testWidgets('TextField semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final Key key = UniqueKey(); await tester.pumpWidget( @@ -7965,9 +8000,9 @@ void main() { }); // Regressing test for https://github.com/flutter/flutter/issues/99763 - testWidgets('Update textField semantics when obscureText changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update textField semantics when obscureText changes', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget(_ObscureTextTestWidget(controller: controller)); controller.text = 'Hello'; @@ -8018,9 +8053,9 @@ void main() { semantics.dispose(); }); - testWidgets('TextField semantics, enableInteractiveSelection = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics, enableInteractiveSelection = false', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final Key key = UniqueKey(); await tester.pumpWidget( @@ -8061,9 +8096,9 @@ void main() { semantics.dispose(); }); - testWidgets('TextField semantics for selections', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics for selections', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController() + final TextEditingController controller = _textEditingController() ..text = 'Hello'; final Key key = UniqueKey(); @@ -8152,10 +8187,10 @@ void main() { semantics.dispose(); }); - testWidgets('TextField change selection with semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField change selection with semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; - final TextEditingController controller = TextEditingController() + final TextEditingController controller = _textEditingController() ..text = 'Hello'; final Key key = UniqueKey(); @@ -8249,14 +8284,14 @@ void main() { semantics.dispose(); }); - testWidgets('Can activate TextField with explicit controller via semantics ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can activate TextField with explicit controller via semantics ', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17801 const String textInTextField = 'Hello'; final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; - final TextEditingController controller = TextEditingController() + final TextEditingController controller = _textEditingController() ..text = textInTextField; final Key key = UniqueKey(); @@ -8321,12 +8356,12 @@ void main() { semantics.dispose(); }); - testWidgets('When clipboard empty, no semantics paste option', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When clipboard empty, no semantics paste option', (WidgetTester tester) async { const String textInTextField = 'Hello'; final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; - final TextEditingController controller = TextEditingController() + final TextEditingController controller = _textEditingController() ..text = textInTextField; final Key key = UniqueKey(); @@ -8398,7 +8433,7 @@ void main() { // https://github.com/flutter/flutter/pull/57139#issuecomment-629048058 }, skip: isBrowser); // [intended] see above. - testWidgets('TextField throws when not descended from a Material widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField throws when not descended from a Material widget', (WidgetTester tester) async { const Widget textField = TextField(); await tester.pumpWidget(textField); final dynamic exception = tester.takeException(); @@ -8406,8 +8441,9 @@ void main() { expect(exception.toString(), startsWith('No Material widget found.')); }); - testWidgets('TextField loses focus when disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField loses focus when disabled', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'TextField Focus Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( boilerplate( @@ -8473,7 +8509,7 @@ void main() { expect(focusNode.hasFocus, isTrue); }); - testWidgets('TextField displays text with text direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField displays text with text direction', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -8517,9 +8553,9 @@ void main() { expect(topLeft.dx, equals(160.0)); }); - testWidgets('TextField semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final Key key = UniqueKey(); await tester.pumpWidget( @@ -8609,9 +8645,9 @@ void main() { semantics.dispose(); }); - testWidgets('InputDecoration counterText can have a semanticCounterText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration counterText can have a semanticCounterText', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final Key key = UniqueKey(); await tester.pumpWidget( @@ -8658,9 +8694,9 @@ void main() { semantics.dispose(); }); - testWidgets('InputDecoration errorText semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration errorText semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final Key key = UniqueKey(); await tester.pumpWidget( @@ -8701,8 +8737,8 @@ void main() { semantics.dispose(); }); - testWidgets('floating label does not overlap with value at large textScaleFactors', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'Just some text'); + testWidgetsWithLeakTracking('floating label does not overlap with value at large textScaleFactors', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(text: 'Just some text'); await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -8726,12 +8762,13 @@ void main() { expect(labelRect.bottom, lessThanOrEqualTo(fieldRect.top)); }); - testWidgets('TextField scrolls into view but does not bounce (SingleChildScrollView)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField scrolls into view but does not bounce (SingleChildScrollView)', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/20485 final Key textField1 = UniqueKey(); final Key textField2 = UniqueKey(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); double? minOffset; double? maxOffset; @@ -8799,12 +8836,13 @@ void main() { expect(maxOffset, 200.0); }); - testWidgets('TextField scrolls into view but does not bounce (ListView)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField scrolls into view but does not bounce (ListView)', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/20485 final Key textField1 = UniqueKey(); final Key textField2 = UniqueKey(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); double? minOffset; double? maxOffset; @@ -8870,7 +8908,7 @@ void main() { expect(maxOffset, 50.0); }); - testWidgets('onTap is called upon tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( overlay( @@ -8893,7 +8931,7 @@ void main() { expect(tapCount, 3); }); - testWidgets('onTap is not called, field is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap is not called, field is disabled', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( overlay( @@ -8913,7 +8951,7 @@ void main() { expect(tapCount, 0); }); - testWidgets('Includes cursor for TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Includes cursor for TextField', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/24612 Widget buildFrame({ @@ -8989,7 +9027,7 @@ void main() { expect(tester.getSize(find.byType(TextField)).width, WIDTH_OF_CHAR * text.length + 18.0 + CARET_GAP); }); - testWidgets('TextField style is merged with theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField style is merged with theme', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23994 final ThemeData themeData = ThemeData( @@ -9040,7 +9078,7 @@ void main() { expect(editableText.style.color, isNull); }); - testWidgets('TextField style is merged with theme in Material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField style is merged with theme in Material 3', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23994 final ThemeData themeData = ThemeData( @@ -9095,7 +9133,7 @@ void main() { expect(editableText.style.color, isNull); }); - testWidgets('style enforces required fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('style enforces required fields', (WidgetTester tester) async { Widget buildFrame(TextStyle style) { return MaterialApp( home: Material( @@ -9126,10 +9164,10 @@ void main() { expect(tester.takeException(), isNotNull); }); - testWidgets( + testWidgetsWithLeakTracking( 'tap moves cursor to the edge of the word it tapped', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9161,10 +9199,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'tap with a mouse does not move cursor to the edge of the word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9197,8 +9235,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('tap moves cursor to the position tapped', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('tap moves cursor to the position tapped', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9228,10 +9266,10 @@ void main() { expect(find.byType(TextButton), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets( + testWidgetsWithLeakTracking( 'two slow taps do not trigger a word selection', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -9266,10 +9304,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Tapping on a collapsed selection toggles the toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neigse Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -9353,10 +9391,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Tapping on a non-collapsed selection toggles the toolbar and retains the selection', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -9429,10 +9467,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap selects word and first tap of double tap moves cursor (iOS)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9477,8 +9515,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets('iOS selectWordEdge works correctly', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('iOS selectWordEdge works correctly', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'blah1 blah2', ); await tester.pumpWidget( @@ -9508,10 +9546,10 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 0)); }, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); - testWidgets( + testWidgetsWithLeakTracking( 'double tap does not select word on read-only obscured field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9557,10 +9595,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap selects word and first tap of double tap moves cursor and shows toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9604,10 +9642,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Custom toolbar test - Android text selection controls', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9638,10 +9676,10 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu., ); - testWidgets( + testWidgetsWithLeakTracking( 'Custom toolbar test - Cupertino text selection controls', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -9672,7 +9710,7 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu., ); - testWidgets('selectionControls is passed to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectionControls is passed to EditableText', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -9689,10 +9727,10 @@ void main() { expect(widget.selectionControls, equals(materialTextSelectionControls)); }); - testWidgets( + testWidgetsWithLeakTracking( 'Can double click + drag with a mouse to select word by word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -9738,10 +9776,10 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Can double tap + drag to select word by word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -9804,11 +9842,11 @@ void main() { 'all good people\n' // 22 + 16 => 38 'to come to the aid\n' // 38 + 19 => 57 'of their country.'; // 57 + 17 => 74 - testWidgets( + testWidgetsWithLeakTracking( 'Can triple tap to select a paragraph on mobile platforms when tapping at a word edge', (WidgetTester tester) async { // TODO(Renzo-Olivares): Enable for iOS, currently broken because selection overlay blocks the TextSelectionGestureDetector https://github.com/flutter/flutter/issues/123415. - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final bool isTargetPlatformApple = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( @@ -9862,10 +9900,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple tap to select a paragraph on mobile platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); final bool isTargetPlatformApple = defaultTargetPlatform == TargetPlatform.iOS; await tester.pumpWidget( @@ -9918,11 +9956,11 @@ void main() { variant: TargetPlatformVariant.mobile(), ); - testWidgets( + testWidgetsWithLeakTracking( 'Triple click at the beginning of a line should not select the previous paragraph', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/132126 - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -9973,11 +10011,11 @@ void main() { variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Triple click at the end of text should select the previous paragraph', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/132126. - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -10029,10 +10067,10 @@ void main() { variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), ); - testWidgets( + testWidgetsWithLeakTracking( 'triple tap chains work on Non-Apple mobile platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -10120,10 +10158,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia }), ); - testWidgets( + testWidgetsWithLeakTracking( 'triple tap chains work on Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure\nThe fox jumped over the fence.', ); await tester.pumpWidget( @@ -10216,10 +10254,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'triple click chains work', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueA, ); await tester.pumpWidget( @@ -10337,10 +10375,10 @@ void main() { variant: TargetPlatformVariant.desktop(), ); - testWidgets( + testWidgetsWithLeakTracking( 'triple click after a click on desktop platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueA, ); await tester.pumpWidget( @@ -10405,10 +10443,10 @@ void main() { variant: TargetPlatformVariant.desktop(), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple tap to select all on a single-line textfield on mobile platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueB, ); final bool isTargetPlatformApple = defaultTargetPlatform == TargetPlatform.iOS; @@ -10460,10 +10498,10 @@ void main() { variant: TargetPlatformVariant.mobile(), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple click to select all on a single-line textfield on desktop platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueA, ); @@ -10516,10 +10554,10 @@ void main() { variant: TargetPlatformVariant.desktop(), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple click to select a line on Linux', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -10575,10 +10613,10 @@ void main() { variant: TargetPlatformVariant.only(TargetPlatform.linux), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple click to select a paragraph', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -10634,10 +10672,10 @@ void main() { variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple click + drag to select line by line on Linux', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -10735,10 +10773,10 @@ void main() { variant: TargetPlatformVariant.only(TargetPlatform.linux), ); - testWidgets( + testWidgetsWithLeakTracking( 'Can triple click + drag to select paragraph by paragraph', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -10836,10 +10874,10 @@ void main() { variant: TargetPlatformVariant.all(excluding: { TargetPlatform.linux }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Going past triple click retains the selection on Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueA, ); await tester.pumpWidget( @@ -10923,10 +10961,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Tap count resets when going past a triple tap on Android, Fuchsia, and Linux', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueA, ); await tester.pumpWidget( @@ -11037,10 +11075,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux }), ); - testWidgets( + testWidgetsWithLeakTracking( 'Double click and triple click alternate on Windows', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: testValueA, ); await tester.pumpWidget( @@ -11155,10 +11193,10 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'double tap on top of cursor also selects word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11206,11 +11244,11 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double double tap just shows the selection menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: '', + final TextEditingController controller = _textEditingController( + ); await tester.pumpWidget( MaterialApp( @@ -11241,11 +11279,11 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu., ); - testWidgets( + testWidgetsWithLeakTracking( 'double long press just shows the selection menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: '', + final TextEditingController controller = _textEditingController( + ); await tester.pumpWidget( MaterialApp( @@ -11272,11 +11310,11 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu., ); - testWidgets( + testWidgetsWithLeakTracking( 'A single tap hides the selection menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: '', + final TextEditingController controller = _textEditingController( + ); await tester.pumpWidget( MaterialApp( @@ -11303,8 +11341,8 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu., ); - testWidgets('Drag selection hides the selection menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Drag selection hides the selection menu', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'blah1 blah2', ); await tester.pumpWidget( @@ -11353,11 +11391,11 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'Long press on an autofocused field shows the selection menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: '', + final TextEditingController controller = _textEditingController( + ); await tester.pumpWidget( MaterialApp( @@ -11384,10 +11422,10 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu., ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap hold selects word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11435,10 +11473,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'tap after a double tap select is not affected', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -11485,10 +11523,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press moves cursor to the exact long press position and shows toolbar when the field is focused', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11529,10 +11567,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press that starts on an unfocused TextField selects the word at the exact long press position and shows toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11568,10 +11606,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press selects word and shows toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11602,10 +11640,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press tap cannot initiate a double tap', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11648,10 +11686,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press drag extends the selection to the word under the drag and shows toolbar on lift on non-Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11726,10 +11764,10 @@ void main() { variant: TargetPlatformVariant.all(excluding: { TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press drag on a focused TextField moves the cursor under the drag and shows toolbar on lift', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11802,10 +11840,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press drag on an unfocused TextField selects word-by-word and shows toolbar on lift', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -11871,8 +11909,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('long press drag can edge scroll on non-Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('long press drag can edge scroll on non-Apple platforms', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -11960,8 +11998,8 @@ void main() { expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257.0, epsilon: 1)); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('long press drag can edge scroll on Apple platforms - unfocused TextField', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('long press drag can edge scroll on Apple platforms - unfocused TextField', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12050,8 +12088,8 @@ void main() { expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257.0, epsilon: 1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('long press drag can edge scroll on Apple platforms - focused TextField', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('long press drag can edge scroll on Apple platforms - focused TextField', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12147,8 +12185,8 @@ void main() { expect(firstCharEndpoint[0].point.dx, moreOrLessEquals(-257.0, epsilon: 1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('mouse click and drag can edge scroll', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('mouse click and drag can edge scroll', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12216,8 +12254,8 @@ void main() { expect(textOffsetToPosition(tester, 0).dx, lessThan(-100.0)); }, variant: TargetPlatformVariant.all()); - testWidgets('keyboard selection change scrolls the field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('keyboard selection change scrolls the field', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12288,7 +12326,7 @@ void main() { ); testWidgets('long press drag can edge scroll vertically', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neigse Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12366,8 +12404,8 @@ void main() { ); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('keyboard selection change scrolls the field vertically', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('keyboard selection change scrolls the field vertically', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12440,8 +12478,8 @@ void main() { skip: isBrowser, // [intended] Browser handles arrow keys differently. ); - testWidgets('mouse click and drag can edge scroll vertically', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('mouse click and drag can edge scroll vertically', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges Atwater Peel Sherbrooke Bonaventure Angrignon Peel Côte-des-Neiges', ); await tester.pumpWidget( @@ -12519,10 +12557,10 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets( + testWidgetsWithLeakTracking( 'long tap after a double tap select is not affected', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -12572,10 +12610,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap after a long tap is not affected', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); // On iOS/iPadOS, during a tap we select the edge of the word closest to the tap. @@ -12630,10 +12668,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double click after a click on desktop platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -12689,10 +12727,10 @@ void main() { variant: TargetPlatformVariant.desktop(), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap chains work', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -12764,10 +12802,10 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double click chains work', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -12856,8 +12894,8 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux }), ); - testWidgets('double tapping a space selects the previous word on iOS', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('double tapping a space selects the previous word on iOS', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: ' blah blah \n blah', ); await tester.pumpWidget( @@ -12927,8 +12965,8 @@ void main() { expect(controller.value.selection.extentOffset, 14); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); - testWidgets('selecting a space selects the space on non-iOS platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('selecting a space selects the space on non-iOS platforms', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: ' blah blah', ); await tester.pumpWidget( @@ -12982,8 +13020,8 @@ void main() { expect(controller.value.selection.extentOffset, 1); }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux, TargetPlatform.fuchsia, TargetPlatform.android })); - testWidgets('selecting a space selects the space on Desktop platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('selecting a space selects the space on Desktop platforms', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: ' blah blah', ); await tester.pumpWidget( @@ -13054,8 +13092,8 @@ void main() { expect(controller.value.selection.extentOffset, 1); }, variant: const TargetPlatformVariant({ TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux })); - testWidgets('Force press does not set selection on Android or Fuchsia touch devices', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Force press does not set selection on Android or Fuchsia touch devices', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -13097,8 +13135,8 @@ void main() { expect(find.byType(TextButton), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia })); - testWidgets('Force press sets selection on desktop platforms that do not support it', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Force press sets selection on desktop platforms that do not support it', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -13140,8 +13178,8 @@ void main() { expect(find.byType(TextButton), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('force press selects word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('force press selects word', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -13189,8 +13227,8 @@ void main() { expect(find.byType(CupertinoButton), isContextMenuProvidedByPlatform ? findsNothing : findsNWidgets(6)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); - testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('tap on non-force-press-supported devices work', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget(Container(key: GlobalKey())); @@ -13245,7 +13283,7 @@ void main() { // https://github.com/flutter/flutter/issues/43445 }, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); - testWidgets('default TextField debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default TextField debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TextField().debugFillProperties(builder); @@ -13257,7 +13295,7 @@ void main() { expect(description, []); }); - testWidgets('TextField implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); // Not checking controller, inputFormatters, focusNode @@ -13315,7 +13353,7 @@ void main() { ]); }); - testWidgets( + testWidgetsWithLeakTracking( 'strut basic single line', (WidgetTester tester) async { await tester.pumpWidget( @@ -13340,7 +13378,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut TextStyle increases height', (WidgetTester tester) async { await tester.pumpWidget( @@ -13385,7 +13423,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut basic multi line', (WidgetTester tester) async { await tester.pumpWidget( @@ -13409,7 +13447,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut no force small strut', (WidgetTester tester) async { await tester.pumpWidget( @@ -13440,7 +13478,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut no force large strut', (WidgetTester tester) async { await tester.pumpWidget( @@ -13469,7 +13507,7 @@ void main() { skip: isBrowser, // TODO(mdebbar): https://github.com/flutter/flutter/issues/32243 ); - testWidgets( + testWidgetsWithLeakTracking( 'strut height override', (WidgetTester tester) async { await tester.pumpWidget( @@ -13498,7 +13536,7 @@ void main() { skip: isBrowser, // TODO(mdebbar): https://github.com/flutter/flutter/issues/32243 ); - testWidgets( + testWidgetsWithLeakTracking( 'strut forces field taller', (WidgetTester tester) async { await tester.pumpWidget( @@ -13529,7 +13567,7 @@ void main() { skip: isBrowser, // TODO(mdebbar): https://github.com/flutter/flutter/issues/32243 ); - testWidgets('Caret center position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret center position', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: Theme( @@ -13572,7 +13610,7 @@ void main() { expect(topLeft.dx, equals(383)); }); - testWidgets('Caret indexes into trailing whitespace center align', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret indexes into trailing whitespace center align', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: Theme( @@ -13624,9 +13662,9 @@ void main() { expect(topLeft.dx, equals(383)); // Should be same as equivalent in 'Caret center position' }); - testWidgets('selection handles are rendered and not faded away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection handles are rendered and not faded away', (WidgetTester tester) async { const String testText = 'lorem ipsum'; - final TextEditingController controller = TextEditingController(text: testText); + final TextEditingController controller = _textEditingController(text: testText); await tester.pumpWidget( MaterialApp( @@ -13657,9 +13695,9 @@ void main() { expect(right.opacity.value, equals(1.0)); }); - testWidgets('iOS selection handles are rendered and not faded away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('iOS selection handles are rendered and not faded away', (WidgetTester tester) async { const String testText = 'lorem ipsum'; - final TextEditingController controller = TextEditingController(text: testText); + final TextEditingController controller = _textEditingController(text: testText); await tester.pumpWidget( MaterialApp( @@ -13688,9 +13726,9 @@ void main() { expect(right.opacity.value, equals(1.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('iPad Scribble selection change shows selection handles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('iPad Scribble selection change shows selection handles', (WidgetTester tester) async { const String testText = 'lorem ipsum'; - final TextEditingController controller = TextEditingController(text: testText); + final TextEditingController controller = _textEditingController(text: testText); await tester.pumpWidget( MaterialApp( @@ -13720,8 +13758,8 @@ void main() { expect(right.opacity.value, equals(1.0)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS })); - testWidgets('Tap shows handles but not toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Tap shows handles but not toolbar', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -13742,10 +13780,10 @@ void main() { expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse); }); - testWidgets( + testWidgetsWithLeakTracking( 'Tap in empty text field does not show handles nor toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -13765,8 +13803,8 @@ void main() { }, ); - testWidgets('Long press shows handles and toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Long press shows handles and toolbar', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -13787,10 +13825,10 @@ void main() { expect(editableText.selectionOverlay!.toolbarIsVisible, isContextMenuProvidedByPlatform ? isFalse : isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'Long press in empty text field shows handles and toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -13810,8 +13848,8 @@ void main() { }, ); - testWidgets('Double tap shows handles and toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Double tap shows handles and toolbar', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -13834,10 +13872,10 @@ void main() { expect(editableText.selectionOverlay!.toolbarIsVisible, isContextMenuProvidedByPlatform ? isFalse : isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'Double tap in empty text field shows toolbar but not handles', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( @@ -13859,10 +13897,10 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Mouse tap does not show handles nor toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -13891,10 +13929,10 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Mouse long press does not show handles nor toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -13923,10 +13961,10 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Mouse double tap does not show handles nor toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -13959,8 +13997,8 @@ void main() { }, ); - testWidgets('Does not show handles when updated from the web engine', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Does not show handles when updated from the web engine', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -14001,8 +14039,8 @@ void main() { } }); - testWidgets('Tapping selection handles toggles the toolbar', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Tapping selection handles toggles the toolbar', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'abc def ghi', ); @@ -14042,8 +14080,9 @@ void main() { expect(editableText.selectionOverlay!.toolbarIsVisible, isFalse); }); - testWidgets('when TextField would be blocked by keyboard, it is shown with enough space for the selection handle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when TextField would be blocked by keyboard, it is shown with enough space for the selection handle', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -14072,9 +14111,10 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/74566 - testWidgets('TextField and last input character are visible on the screen when the cursor is not shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField and last input character are visible on the screen when the cursor is not shown', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); final ScrollController textFieldScrollController = ScrollController(); + addTearDown(() { scrollController.dispose(); textFieldScrollController.dispose(); }); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -14117,7 +14157,7 @@ void main() { }); group('height', () { - testWidgets('By default, TextField is at least kMinInteractiveDimension high', (WidgetTester tester) async { + testWidgetsWithLeakTracking('By default, TextField is at least kMinInteractiveDimension high', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(), home: const Scaffold( @@ -14131,7 +14171,7 @@ void main() { expect(renderBox.size.height, greaterThanOrEqualTo(kMinInteractiveDimension)); }); - testWidgets("When text is very small, TextField still doesn't go below kMinInteractiveDimension height", (WidgetTester tester) async { + testWidgetsWithLeakTracking("When text is very small, TextField still doesn't go below kMinInteractiveDimension height", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(), home: const Scaffold( @@ -14147,7 +14187,7 @@ void main() { expect(renderBox.size.height, kMinInteractiveDimension); }); - testWidgets('When isDense, TextField can go below kMinInteractiveDimension height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When isDense, TextField can go below kMinInteractiveDimension height', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(), home: const Scaffold( @@ -14192,14 +14232,14 @@ void main() { ); } - testWidgets('By default, intrinsic height is at least kMinInteractiveDimension high', (WidgetTester tester) async { + testWidgetsWithLeakTracking('By default, intrinsic height is at least kMinInteractiveDimension high', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/54729 // If the intrinsic height does not match that of the height after // performLayout, this will fail. await tester.pumpWidget(buildTest(isDense: false)); }); - testWidgets('When isDense, intrinsic height can go below kMinInteractiveDimension height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When isDense, intrinsic height can go below kMinInteractiveDimension height', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/54729 // If the intrinsic height does not match that of the height after // performLayout, this will fail. @@ -14208,17 +14248,25 @@ void main() { }); }); testWidgets("Arrow keys don't move input focus", (WidgetTester tester) async { - final TextEditingController controller1 = TextEditingController(); - final TextEditingController controller2 = TextEditingController(); - final TextEditingController controller3 = TextEditingController(); - final TextEditingController controller4 = TextEditingController(); - final TextEditingController controller5 = TextEditingController(); + final TextEditingController controller1 = _textEditingController(); + final TextEditingController controller2 = _textEditingController(); + final TextEditingController controller3 = _textEditingController(); + final TextEditingController controller4 = _textEditingController(); + final TextEditingController controller5 = _textEditingController(); final FocusNode focusNode1 = FocusNode(debugLabel: 'Field 1'); final FocusNode focusNode2 = FocusNode(debugLabel: 'Field 2'); final FocusNode focusNode3 = FocusNode(debugLabel: 'Field 3'); final FocusNode focusNode4 = FocusNode(debugLabel: 'Field 4'); final FocusNode focusNode5 = FocusNode(debugLabel: 'Field 5'); + addTearDown(() { + focusNode1.dispose(); + focusNode2.dispose(); + focusNode3.dispose(); + focusNode4.dispose(); + focusNode5.dispose(); + }); + // Lay out text fields in a "+" formation, and focus the center one. await tester.pumpWidget(MaterialApp( theme: ThemeData(), @@ -14296,7 +14344,7 @@ void main() { expect(focusNode3.hasPrimaryFocus, isTrue); }); - testWidgets('Scrolling shortcuts are disabled in text fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolling shortcuts are disabled in text fields', (WidgetTester tester) async { bool scrollInvoked = false; await tester.pumpWidget( MaterialApp( @@ -14332,7 +14380,7 @@ void main() { expect(scrollInvoked, isFalse); }); - testWidgets("A buildCounter that returns null doesn't affect the size of the TextField", (WidgetTester tester) async { + testWidgetsWithLeakTracking("A buildCounter that returns null doesn't affect the size of the TextField", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/44909 final GlobalKey textField1Key = GlobalKey(); @@ -14367,7 +14415,7 @@ void main() { (WidgetTester tester) async { // This is a regression test for // https://github.com/flutter/flutter/issues/43787 - final TextEditingController controller = TextEditingController( + final TextEditingController controller = _textEditingController( text: 'This is a test that shows some odd behavior with Text Selection!', ); @@ -14403,8 +14451,8 @@ void main() { }, ); - testWidgets('clipboard status is checked via hasStrings without getting the full clipboard contents', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('clipboard status is checked via hasStrings without getting the full clipboard contents', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -14451,7 +14499,7 @@ void main() { skip: kIsWeb, // [intended] web doesn't call hasStrings. ); - testWidgets('TextField changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -14525,7 +14573,7 @@ void main() { await gesture.moveTo(center); }); - testWidgets('TextField icons change mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField icons change mouse cursor when hovered', (WidgetTester tester) async { // Test default cursor in icons area. await tester.pumpWidget( const MaterialApp( @@ -14613,8 +14661,8 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets('Text selection menu does not change mouse cursor when hovered', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Text selection menu does not change mouse cursor when hovered', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -14651,12 +14699,12 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Caret rtl with changing width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret rtl with changing width', (WidgetTester tester) async { late StateSetter setState; bool isWide = false; const double wideWidth = 300.0; const double narrowWidth = 200.0; - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( boilerplate( child: StatefulBuilder( @@ -14710,8 +14758,8 @@ void main() { expect(cursorRight, inputWidth - kCaretGap); }); - testWidgets('Text selection menu hides after select all on desktop', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Text selection menu hides after select all on desktop', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -14761,8 +14809,8 @@ void main() { ); // Regressing test for https://github.com/flutter/flutter/issues/70625 - testWidgets('TextFields can inherit [FloatingLabelBehaviour] from InputDecorationTheme.', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('TextFields can inherit [FloatingLabelBehaviour] from InputDecorationTheme.', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); Widget textFieldBuilder({ FloatingLabelBehavior behavior = FloatingLabelBehavior.auto }) { return MaterialApp( theme: ThemeData( @@ -14835,7 +14883,7 @@ void main() { await tester.pumpAndSettle(); } - testWidgets('using none enforcement.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using none enforcement.', (WidgetTester tester) async { const MaxLengthEnforcement enforcement = MaxLengthEnforcement.none; await setupWidget(tester, enforcement); @@ -14855,7 +14903,7 @@ void main() { expect(state.currentTextEditingValue.composing, TextRange.empty); }); - testWidgets('using enforced.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using enforced.', (WidgetTester tester) async { const MaxLengthEnforcement enforcement = MaxLengthEnforcement.enforced; await setupWidget(tester, enforcement); @@ -14879,7 +14927,7 @@ void main() { expect(state.currentTextEditingValue.composing, const TextRange(start: 3, end: 5)); }); - testWidgets('using truncateAfterCompositionEnds.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using truncateAfterCompositionEnds.', (WidgetTester tester) async { const MaxLengthEnforcement enforcement = MaxLengthEnforcement.truncateAfterCompositionEnds; await setupWidget(tester, enforcement); @@ -14903,7 +14951,7 @@ void main() { expect(state.currentTextEditingValue.composing, TextRange.empty); }); - testWidgets('using default behavior for different platforms.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using default behavior for different platforms.', (WidgetTester tester) async { await setupWidget(tester, null); final EditableTextState state = tester.state(find.byType(EditableText)); @@ -14936,7 +14984,7 @@ void main() { }); }); - testWidgets('TextField does not leak touch events when deadline has exceeded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField does not leak touch events when deadline has exceeded', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/118340. int textFieldTapCount = 0; int prefixTapCount = 0; @@ -14987,7 +15035,7 @@ void main() { expect(suffixTapCount, 1); }); - testWidgets('prefix/suffix buttons do not leak touch events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prefix/suffix buttons do not leak touch events', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/39376. int textFieldTapCount = 0; @@ -15026,7 +15074,7 @@ void main() { expect(suffixTapCount, 1); }); - testWidgets('autofill info has hint text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autofill info has hint text', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -15049,7 +15097,7 @@ void main() { ); }); - testWidgets('TextField at rest does not push any layers with alwaysNeedsAddToScene', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField at rest does not push any layers with alwaysNeedsAddToScene', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -15063,8 +15111,8 @@ void main() { expect(tester.layers.any((Layer layer) => layer.debugSubtreeNeedsAddToScene!), isFalse); }); - testWidgets('Focused TextField does not push any layers with alwaysNeedsAddToScene', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Focused TextField does not push any layers with alwaysNeedsAddToScene', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); await tester.pumpWidget( MaterialApp( home: Material( @@ -15080,8 +15128,8 @@ void main() { expect(tester.layers.any((Layer layer) => layer.debugSubtreeNeedsAddToScene!), isFalse); }); - testWidgets('TextField does not push any layers with alwaysNeedsAddToScene after toolbar is dismissed', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('TextField does not push any layers with alwaysNeedsAddToScene after toolbar is dismissed', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); await tester.pumpWidget( MaterialApp( home: Material( @@ -15118,8 +15166,8 @@ void main() { expect(tester.layers.any((Layer layer) => layer.debugSubtreeNeedsAddToScene!), isFalse); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. - testWidgets('cursor blinking respects TickerMode', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('cursor blinking respects TickerMode', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); Widget builder({required bool tickerMode}) { return MaterialApp( home: Material( @@ -15198,8 +15246,8 @@ void main() { expect(editable.showCursor.value, isTrue); }); - testWidgets('can shift + tap to select with a keyboard (Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can shift + tap to select with a keyboard (Apple platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -15241,8 +15289,8 @@ void main() { expect(controller.selection.extentOffset, 4); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('can shift + tap to select with a keyboard (non-Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can shift + tap to select with a keyboard (non-Apple platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); await tester.pumpWidget( @@ -15286,11 +15334,11 @@ void main() { expect(controller.selection.extentOffset, 4); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('shift tapping an unfocused field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('shift tapping an unfocused field', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); - final FocusNode focusNode = FocusNode(); + final FocusNode focusNode = _focusNode(); await tester.pumpWidget( MaterialApp( home: Material( @@ -15341,8 +15389,8 @@ void main() { expect(controller.selection.extentOffset, 20); }, variant: TargetPlatformVariant.all()); - testWidgets('can shift + tap + drag to select with a keyboard (Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can shift + tap + drag to select with a keyboard (Apple platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; @@ -15446,8 +15494,8 @@ void main() { expect(controller.selection.extentOffset, 26); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('can shift + tap + drag to select with a keyboard (non-Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can shift + tap + drag to select with a keyboard (non-Apple platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.android @@ -15554,8 +15602,8 @@ void main() { expect(controller.selection.extentOffset, 26); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.windows })); - testWidgets('can shift + tap + drag to select with a keyboard, reversed (Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can shift + tap + drag to select with a keyboard, reversed (Apple platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.iOS; @@ -15658,8 +15706,8 @@ void main() { expect(controller.selection.extentOffset, 14); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('can shift + tap + drag to select with a keyboard, reversed (non-Apple platforms)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('can shift + tap + drag to select with a keyboard, reversed (non-Apple platforms)', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); final bool isTargetPlatformMobile = defaultTargetPlatform == TargetPlatform.android @@ -15767,8 +15815,8 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.windows })); // Regression test for https://github.com/flutter/flutter/issues/101587. - testWidgets('Right clicking menu behavior', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Right clicking menu behavior', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'blah1 blah2', ); await tester.pumpWidget( @@ -15846,8 +15894,8 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. ); - testWidgets('Cannot request focus when canRequestFocus is false', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Cannot request focus when canRequestFocus is false', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); // Default test. The canRequestFocus is true by default and the text field can be focused await tester.pumpWidget( @@ -15889,10 +15937,10 @@ void main() { }); group('Right click focus', () { - testWidgets('Can right click to focus multiple times', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can right click to focus multiple times', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/103228 - final FocusNode focusNode1 = FocusNode(); - final FocusNode focusNode2 = FocusNode(); + final FocusNode focusNode1 = _focusNode(); + final FocusNode focusNode2 = _focusNode(); final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); await tester.pumpWidget( @@ -15944,10 +15992,10 @@ void main() { expect(focusNode2.hasFocus, isFalse); }); - testWidgets('Can right click to focus on previously selected word on Apple platforms', (WidgetTester tester) async { - final FocusNode focusNode1 = FocusNode(); - final FocusNode focusNode2 = FocusNode(); - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('Can right click to focus on previously selected word on Apple platforms', (WidgetTester tester) async { + final FocusNode focusNode1 = _focusNode(); + final FocusNode focusNode2 = _focusNode(); + final TextEditingController controller = _textEditingController( text: 'first second', ); final UniqueKey key1 = UniqueKey(); @@ -16043,8 +16091,8 @@ void main() { expect(controller.selection.extentOffset, 5); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Right clicking cannot request focus if canRequestFocus is false', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Right clicking cannot request focus if canRequestFocus is false', (WidgetTester tester) async { + final FocusNode focusNode = _focusNode(); final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -16073,8 +16121,8 @@ void main() { }); group('context menu', () { - testWidgets('builds AdaptiveTextSelectionToolbar by default', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: ''); + testWidgetsWithLeakTracking('builds AdaptiveTextSelectionToolbar by default', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( home: Material( @@ -16104,9 +16152,9 @@ void main() { skip: kIsWeb, // [intended] on web the browser handles the context menu. ); - testWidgets('contextMenuBuilder is used in place of the default text selection toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('contextMenuBuilder is used in place of the default text selection toolbar', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); - final TextEditingController controller = TextEditingController(text: ''); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( home: Material( @@ -16142,9 +16190,9 @@ void main() { skip: kIsWeb, // [intended] on web the browser handles the context menu. ); - testWidgets('contextMenuBuilder changes from default to null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('contextMenuBuilder changes from default to null', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); - final TextEditingController controller = TextEditingController(text: ''); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget(MaterialApp(home: Material(child: TextField(key: key, controller: controller)))); await tester.pump(); // Wait for autofocus to take effect. @@ -16281,10 +16329,10 @@ void main() { late ValueNotifier magnifierInfo; final Widget fakeMagnifier = Container(key: UniqueKey()); - testWidgets( + testWidgetsWithLeakTracking( 'Can drag handles to show, unshow, and update magnifier', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( overlay( child: TextField( @@ -16345,8 +16393,8 @@ void main() { expect(find.byKey(fakeMagnifier.key!), findsNothing); }); - testWidgets('Can drag to show, unshow, and update magnifier', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can drag to show, unshow, and update magnifier', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); await tester.pumpWidget( MaterialApp( home: Material( @@ -16446,8 +16494,8 @@ void main() { expect(find.byKey(fakeMagnifier.key!), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets('Can long press to show, unshow, and update magnifier', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Can long press to show, unshow, and update magnifier', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController(); final bool isTargetPlatformAndroid = defaultTargetPlatform == TargetPlatform.android; await tester.pumpWidget( MaterialApp( @@ -16510,7 +16558,7 @@ void main() { expect(find.byKey(fakeMagnifier.key!), findsNothing); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets('magnifier does not show when tapping outside field', (WidgetTester tester) async { + testWidgetsWithLeakTracking('magnifier does not show when tapping outside field', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128321 await tester.pumpWidget( MaterialApp( @@ -16560,8 +16608,9 @@ void main() { }); group('TapRegion integration', () { - testWidgets('Tapping outside loses focus on desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping outside loses focus on desktop', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -16594,8 +16643,9 @@ void main() { expect(focusNode.hasPrimaryFocus, isFalse); }, variant: TargetPlatformVariant.desktop()); - testWidgets("Tapping outside doesn't lose focus on mobile", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Tapping outside doesn't lose focus on mobile", (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -16629,9 +16679,10 @@ void main() { expect(focusNode.hasPrimaryFocus, kIsWeb ? isFalse : isTrue); }, variant: TargetPlatformVariant.mobile()); - testWidgets("Tapping on toolbar doesn't lose focus", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Tapping on toolbar doesn't lose focus", (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); - final TextEditingController controller = TextEditingController(text: 'A B C'); + final TextEditingController controller = _textEditingController(text: 'A B C'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -16683,8 +16734,9 @@ void main() { skip: isBrowser, // [intended] On the web, the toolbar isn't rendered by Flutter. ); - testWidgets("Tapping on input decorator doesn't lose focus", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Tapping on input decorator doesn't lose focus", (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -16722,8 +16774,9 @@ void main() { // PointerDownEvents can't be trackpad events, apparently, so we skip that one. for (final PointerDeviceKind pointerDeviceKind in PointerDeviceKind.values.toSet()..remove(PointerDeviceKind.trackpad)) { - testWidgets('Default TextField handling of onTapOutside follows platform conventions for ${pointerDeviceKind.name}', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default TextField handling of onTapOutside follows platform conventions for ${pointerDeviceKind.name}', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Test'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -16777,7 +16830,7 @@ void main() { } }); - testWidgets('Builds the corresponding default spell check toolbar by platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Builds the corresponding default spell check toolbar by platform', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; late final BuildContext builderContext; @@ -16829,7 +16882,7 @@ void main() { } }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets('Builds the corresponding default spell check configuration by platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Builds the corresponding default spell check configuration by platform', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; @@ -16887,8 +16940,8 @@ void main() { ); }, variant: const TargetPlatformVariant({ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets('text selection toolbar is hidden on tap down', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( + testWidgetsWithLeakTracking('text selection toolbar is hidden on tap down', (WidgetTester tester) async { + final TextEditingController controller = _textEditingController( text: 'blah1 blah2', ); await tester.pumpWidget( diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 8877ed8e9ecfe..5b9ca7cafe832 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -26,10 +26,11 @@ void main() { await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); }); - testWidgets('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -106,6 +107,7 @@ void main() { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -243,7 +245,6 @@ void main() { expect(controller.text, ' blah2blah1'); expect(controller.selection, const TextSelection(baseOffset: 0, extentOffset: 0)); expect(find.byType(CupertinoButton), findsNothing); - controller.dispose(); }, variant: const TargetPlatformVariant({ TargetPlatform.linux, TargetPlatform.windows }), skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. @@ -255,6 +256,7 @@ void main() { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -273,15 +275,15 @@ void main() { await tester.tapAt(startBlah1); await tester.pumpAndSettle(); await tester.pump(); - controller.dispose(); }, skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the desktop cut/copy/paste buttons are disabled for read-only obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -322,10 +324,11 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('the desktop cut/copy buttons are disabled for obscured form fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the desktop cut/copy buttons are disabled for obscured form fields', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -373,7 +376,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField accepts TextField.noMaxLength as value to maxLength parameter', (WidgetTester tester) async { bool asserted; try { TextFormField( @@ -386,7 +389,7 @@ void main() { expect(asserted, false); }); - testWidgets('Passes textAlign to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textAlign to underlying TextField', (WidgetTester tester) async { const TextAlign alignment = TextAlign.center; await tester.pumpWidget( @@ -408,7 +411,7 @@ void main() { expect(textFieldWidget.textAlign, alignment); }); - testWidgets('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scrollPhysics to underlying TextField', (WidgetTester tester) async { const ScrollPhysics scrollPhysics = ScrollPhysics(); await tester.pumpWidget( @@ -430,7 +433,7 @@ void main() { expect(textFieldWidget.scrollPhysics, scrollPhysics); }); - testWidgets('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textAlignVertical to underlying TextField', (WidgetTester tester) async { const TextAlignVertical textAlignVertical = TextAlignVertical.bottom; await tester.pumpWidget( @@ -452,7 +455,7 @@ void main() { expect(textFieldWidget.textAlignVertical, textAlignVertical); }); - testWidgets('Passes textInputAction to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes textInputAction to underlying TextField', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -472,7 +475,7 @@ void main() { expect(textFieldWidget.textInputAction, TextInputAction.next); }); - testWidgets('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes onEditingComplete to underlying TextField', (WidgetTester tester) async { void onEditingComplete() { } await tester.pumpWidget( @@ -494,7 +497,7 @@ void main() { expect(textFieldWidget.onEditingComplete, onEditingComplete); }); - testWidgets('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes cursor attributes to underlying TextField', (WidgetTester tester) async { const double cursorWidth = 3.14; const double cursorHeight = 6.28; const Radius cursorRadius = Radius.circular(4); @@ -525,7 +528,7 @@ void main() { expect(textFieldWidget.cursorColor, cursorColor); }); - testWidgets('onFieldSubmit callbacks are called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onFieldSubmit callbacks are called', (WidgetTester tester) async { bool called = false; await tester.pumpWidget( @@ -546,7 +549,7 @@ void main() { expect(called, true); }); - testWidgets('onChanged callbacks are called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callbacks are called', (WidgetTester tester) async { late String value; await tester.pumpWidget( @@ -568,7 +571,7 @@ void main() { expect(value, 'Soup'); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -593,7 +596,7 @@ void main() { expect(validateCalled, 2); }); - testWidgets('validate is called if widget is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('validate is called if widget is enabled', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -620,7 +623,7 @@ void main() { }); - testWidgets('Disabled field hides helper and counter in M2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled field hides helper and counter in M2', (WidgetTester tester) async { const String helperText = 'helper text'; const String counterText = 'counter text'; const String errorText = 'error text'; @@ -668,7 +671,7 @@ void main() { expect(errorWidget.style!.color, equals(Colors.transparent)); }); - testWidgets('passing a buildCounter shows returned widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing a buildCounter shows returned widget', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Center( @@ -733,7 +736,7 @@ void main() { expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); }, skip: isBrowser); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgets('onTap is called upon tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( MaterialApp( @@ -760,7 +763,7 @@ void main() { expect(tapCount, 3); }); - testWidgets('onTapOutside is called upon tap outside', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTapOutside is called upon tap outside', (WidgetTester tester) async { int tapOutsideCount = 0; await tester.pumpWidget( MaterialApp( @@ -791,7 +794,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgets('reset resets the text fields value to the initialValue', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reset resets the text fields value to the initialValue', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -814,7 +817,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgets("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { + testWidgetsWithLeakTracking("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -837,7 +840,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34847. - testWidgets("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { + testWidgetsWithLeakTracking("reset resets the text field's value to empty when initialValue is null", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -860,7 +863,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/54472. - testWidgets('didChange changes text fields value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didChange changes text fields value', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -882,7 +885,7 @@ void main() { expect(find.text('changedValue'), findsOneWidget); }); - testWidgets('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callbacks value and FormFieldState.value are sync', (WidgetTester tester) async { bool called = false; late FormFieldState state; @@ -909,7 +912,7 @@ void main() { expect(called, true); }); - testWidgets('autofillHints is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autofillHints is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -926,7 +929,7 @@ void main() { expect(widget.autofillHints, equals(const [AutofillHints.countryName])); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -951,7 +954,7 @@ void main() { expect(validateCalled, 1); }); - testWidgets('textSelectionControls is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textSelectionControls is passed to super', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -968,7 +971,7 @@ void main() { expect(widget.selectionControls, equals(materialTextSelectionControls)); }); - testWidgets('TextFormField respects hintTextDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField respects hintTextDirection', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Directionality( @@ -1010,8 +1013,9 @@ void main() { expect(textDirection, TextDirection.rtl); }); - testWidgets('Passes scrollController to underlying TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scrollController to underlying TextField', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( MaterialApp( @@ -1032,7 +1036,7 @@ void main() { expect(textFieldWidget.scrollController, scrollController); }); - testWidgets('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -1096,10 +1100,11 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/101587. - testWidgets('Right clicking menu behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Right clicking menu behavior', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'blah1 blah2', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -1177,7 +1182,7 @@ void main() { skip: kIsWeb, // [intended] we don't supply the cut/copy/paste buttons on the web. ); - testWidgets('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('spellCheckConfiguration passes through to EditableText', (WidgetTester tester) async { final SpellCheckConfiguration mySpellCheckConfiguration = SpellCheckConfiguration( spellCheckService: DefaultSpellCheckService(), misspelledTextStyle: TextField.materialMisspelledTextStyle, @@ -1207,7 +1212,7 @@ void main() { ); }); - testWidgets('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('magnifierConfiguration passes through to EditableText', (WidgetTester tester) async { final TextMagnifierConfiguration myTextMagnifierConfiguration = TextMagnifierConfiguration( magnifierBuilder: (BuildContext context, MagnifierController controller, ValueNotifier notifier) { return const Placeholder(); @@ -1230,6 +1235,7 @@ void main() { testWidgets('Passes undoController to undoController TextField', (WidgetTester tester) async { final UndoHistoryController undoController = UndoHistoryController(value: UndoHistoryValue.empty); + addTearDown(undoController.dispose); await tester.pumpWidget( MaterialApp( @@ -1250,7 +1256,7 @@ void main() { expect(textFieldWidget.undoController, undoController); }); - testWidgets('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes cursorOpacityAnimates to cursorOpacityAnimates TextField', (WidgetTester tester) async { const bool cursorOpacityAnimates = true; await tester.pumpWidget( @@ -1272,7 +1278,7 @@ void main() { expect(textFieldWidget.cursorOpacityAnimates, cursorOpacityAnimates); }); - testWidgets('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes contentInsertionConfiguration to contentInsertionConfiguration TextField', (WidgetTester tester) async { final ContentInsertionConfiguration contentInsertionConfiguration = ContentInsertionConfiguration(onContentInserted: (KeyboardInsertedContent value) {}); @@ -1295,7 +1301,7 @@ void main() { expect(textFieldWidget.contentInsertionConfiguration, contentInsertionConfiguration); }); - testWidgets('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes clipBehavior to clipBehavior TextField', (WidgetTester tester) async { const Clip clipBehavior = Clip.antiAlias; await tester.pumpWidget( @@ -1317,7 +1323,7 @@ void main() { expect(textFieldWidget.clipBehavior, clipBehavior); }); - testWidgets('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes scribbleEnabled to scribbleEnabled TextField', (WidgetTester tester) async { const bool scribbleEnabled = false; await tester.pumpWidget( @@ -1339,7 +1345,7 @@ void main() { expect(textFieldWidget.scribbleEnabled, scribbleEnabled); }); - testWidgets('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes canRequestFocus to canRequestFocus TextField', (WidgetTester tester) async { const bool canRequestFocus = false; await tester.pumpWidget( @@ -1361,7 +1367,7 @@ void main() { expect(textFieldWidget.canRequestFocus, canRequestFocus); }); - testWidgets('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes onAppPrivateCommand to onAppPrivateCommand TextField', (WidgetTester tester) async { void onAppPrivateCommand(String p0, Map p1) {} await tester.pumpWidget( @@ -1383,7 +1389,7 @@ void main() { expect(textFieldWidget.onAppPrivateCommand, onAppPrivateCommand); }); - testWidgets('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes selectionHeightStyle to selectionHeightStyle TextField', (WidgetTester tester) async { const BoxHeightStyle selectionHeightStyle = BoxHeightStyle.max; await tester.pumpWidget( @@ -1405,7 +1411,7 @@ void main() { expect(textFieldWidget.selectionHeightStyle, selectionHeightStyle); }); - testWidgets('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes selectionWidthStyle to selectionWidthStyle TextField', (WidgetTester tester) async { const BoxWidthStyle selectionWidthStyle = BoxWidthStyle.max; await tester.pumpWidget( @@ -1427,7 +1433,7 @@ void main() { expect(textFieldWidget.selectionWidthStyle, selectionWidthStyle); }); - testWidgets('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes dragStartBehavior to dragStartBehavior TextField', (WidgetTester tester) async { const DragStartBehavior dragStartBehavior = DragStartBehavior.down; await tester.pumpWidget( @@ -1449,7 +1455,7 @@ void main() { expect(textFieldWidget.dragStartBehavior, dragStartBehavior); }); - testWidgets('Error color for cursor while validating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Error color for cursor while validating', (WidgetTester tester) async { const Color errorColor = Color(0xff123456); await tester.pumpWidget(MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/material/text_selection_test.dart b/packages/flutter/test/material/text_selection_test.dart index 37c22e7ecbfb8..bcef8636f7d2b 100644 --- a/packages/flutter/test/material/text_selection_test.dart +++ b/packages/flutter/test/material/text_selection_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart' show findRenderEditable, globalize, textOffsetToPosition; @@ -45,11 +46,15 @@ void main() { }) { final TextEditingController controller = TextEditingController(text: text) ..selection = selection ?? const TextSelection.collapsed(offset: -1); + addTearDown(controller.dispose); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + return MaterialApp( home: EditableText( key: key, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.black, backgroundCursorColor: Colors.black, @@ -57,13 +62,13 @@ void main() { ); } - testWidgets('should return false when there is no text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should return false when there is no text', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(createEditableText(key: key)); expect(materialTextSelectionControls.canSelectAll(key.currentState!), false); }); - testWidgets('should return true when there is text and collapsed selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should return true when there is text and collapsed selection', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(createEditableText( key: key, @@ -72,7 +77,7 @@ void main() { expect(materialTextSelectionControls.canSelectAll(key.currentState!), true); }); - testWidgets('should return true when there is text and partial uncollapsed selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should return true when there is text and partial uncollapsed selection', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(createEditableText( key: key, @@ -82,7 +87,7 @@ void main() { expect(materialTextSelectionControls.canSelectAll(key.currentState!), true); }); - testWidgets('should return false when there is text and full selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should return false when there is text and full selection', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(createEditableText( key: key, @@ -94,8 +99,9 @@ void main() { }); group('Text selection menu overflow (Android)', () { - testWidgets('All menu items show when they fit.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('All menu items show when they fit.', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'abc def ghi'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android), home: Directionality( @@ -156,12 +162,13 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), ); - testWidgets("When menu items don't fit, an overflow menu is used.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("When menu items don't fit, an overflow menu is used.", (WidgetTester tester) async { // Set the screen size to more narrow, so that Select all can't fit. tester.view.physicalSize = const Size(1000, 800); addTearDown(tester.view.reset); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android), home: Directionality( @@ -230,12 +237,13 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), ); - testWidgets('A smaller menu bumps more items to the overflow menu.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A smaller menu bumps more items to the overflow menu.', (WidgetTester tester) async { // Set the screen size so narrow that only Cut and Copy can fit. tester.view.physicalSize = const Size(800, 800); addTearDown(tester.view.reset); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android), home: Directionality( @@ -295,12 +303,13 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), ); - testWidgets('When the menu renders below the text, the overflow menu back button is at the top.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When the menu renders below the text, the overflow menu back button is at the top.', (WidgetTester tester) async { // Set the screen size to more narrow, so that Select all can't fit. tester.view.physicalSize = const Size(1000, 800); addTearDown(tester.view.reset); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android), home: Directionality( @@ -369,12 +378,13 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), ); - testWidgets('When the menu items change, the menu is closed and _closedWidth reset.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When the menu items change, the menu is closed and _closedWidth reset.', (WidgetTester tester) async { // Set the screen size to more narrow, so that Select all can't fit. tester.view.physicalSize = const Size(1000, 800); addTearDown(tester.view.reset); final TextEditingController controller = TextEditingController(text: 'abc def ghi'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android, useMaterial3: false), home: Directionality( @@ -477,8 +487,9 @@ void main() { }); group('menu position', () { - testWidgets('When renders below a block of text, menu appears below bottom endpoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When renders below a block of text, menu appears below bottom endpoint', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'abc\ndef\nghi\njkl\nmno\npqr'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android), home: Directionality( @@ -549,11 +560,12 @@ void main() { variant: const TargetPlatformVariant({ TargetPlatform.android }), ); - testWidgets( + testWidgetsWithLeakTracking( 'When selecting multiple lines over max lines', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'abc\ndef\nghi\njkl\nmno\npqr'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(platform: TargetPlatform.android), home: Directionality( @@ -627,7 +639,7 @@ void main() { }); group('material handles', () { - testWidgets('draws transparent handle correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('draws transparent handle correctly', (WidgetTester tester) async { await tester.pumpWidget(RepaintBoundary( child: Theme( data: ThemeData( @@ -661,7 +673,7 @@ void main() { ); }); - testWidgets('works with 3 positional parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with 3 positional parameters', (WidgetTester tester) async { await tester.pumpWidget(Theme( data: ThemeData( textSelectionTheme: const TextSelectionThemeData( @@ -694,10 +706,11 @@ void main() { }); }); - testWidgets('Paste only appears when clipboard has contents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paste only appears when clipboard has contents', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'Atwater Peel Sherbrooke Bonaventure', ); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( home: Material( diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 50553dc297f39..8234f29daec4c 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -156,7 +156,7 @@ void main() { expect(handle, paints..path(color: defaultSelectionHandleColor)); }); - testWidgets('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.textSelectionTheme will be used if provided', (WidgetTester tester) async { const TextSelectionThemeData textSelectionTheme = TextSelectionThemeData( cursorColor: Color(0xffaabbcc), selectionColor: Color(0x88888888), @@ -209,7 +209,7 @@ void main() { expect(handle, paints..path(color: textSelectionTheme.selectionHandleColor)); }); - testWidgets('TextSelectionTheme widget will override ThemeData.textSelectionTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextSelectionTheme widget will override ThemeData.textSelectionTheme', (WidgetTester tester) async { const TextSelectionThemeData defaultTextSelectionTheme = TextSelectionThemeData( cursorColor: Color(0xffaabbcc), selectionColor: Color(0x88888888), @@ -271,7 +271,7 @@ void main() { expect(handle, paints..path(color: widgetTextSelectionTheme.selectionHandleColor)); }); - testWidgets('TextField parameters will override theme settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField parameters will override theme settings', (WidgetTester tester) async { const TextSelectionThemeData defaultTextSelectionTheme = TextSelectionThemeData( cursorColor: Color(0xffaabbcc), selectionHandleColor: Color(0x00ccbbaa), diff --git a/packages/flutter/test/material/theme_defaults_test.dart b/packages/flutter/test/material/theme_defaults_test.dart index 4f60fc1735629..a6b94213a4722 100644 --- a/packages/flutter/test/material/theme_defaults_test.dart +++ b/packages/flutter/test/material/theme_defaults_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Duration defaultButtonDuration = Duration(milliseconds: 200); @@ -14,7 +15,7 @@ void main() { const ShapeBorder defaultFABShapeM3 = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const EdgeInsets defaultFABPadding = EdgeInsets.zero; - testWidgets('Material2 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -42,7 +43,7 @@ void main() { expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); - testWidgets('Material3 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -70,7 +71,7 @@ void main() { expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); - testWidgets('Material2 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -100,7 +101,7 @@ void main() { expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); - testWidgets('Material3 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { final ThemeData theme = ThemeData.light(useMaterial3: true); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index 63d133a0090f5..22149aac23843 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { const TextTheme defaultGeometryTheme = Typography.englishLike2014; @@ -19,7 +20,7 @@ void main() { expect(tween.lerp(0.25), equals(ThemeData.lerp(light, dark, 0.25))); }); - testWidgets('PopupMenu inherits app theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu inherits app theme', (WidgetTester tester) async { final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -47,7 +48,7 @@ void main() { expect(Theme.of(tester.element(find.text('menuItem'))).brightness, equals(Brightness.dark)); }); - testWidgets('Theme overrides selection style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme overrides selection style', (WidgetTester tester) async { final Key key = UniqueKey(); const Color defaultSelectionColor = Color(0x11111111); const Color defaultCursorColor = Color(0x22222222); @@ -96,7 +97,7 @@ void main() { expect(tester.widget(find.byType(EditableText)).cursorColor, themeCursorColor); }); - testWidgets('Material2 - Fallback theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Fallback theme', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( Theme( @@ -113,7 +114,7 @@ void main() { expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(useMaterial3: false), defaultGeometryTheme))); }); - testWidgets('Material3 - Fallback theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Fallback theme', (WidgetTester tester) async { late BuildContext capturedContextM3; await tester.pumpWidget( Theme( @@ -130,7 +131,7 @@ void main() { expect(Theme.of(capturedContextM3), equals(ThemeData.localize(ThemeData.fallback(useMaterial3: true), defaultGeometryThemeM3))); }); - testWidgets('ThemeData.localize memoizes the result', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.localize memoizes the result', (WidgetTester tester) async { final ThemeData light = ThemeData.light(); final ThemeData dark = ThemeData.dark(); @@ -153,17 +154,17 @@ void main() { ); }); - testWidgets('Material2 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { final ThemeData m2Theme = ThemeData(useMaterial3: false); expect(m2Theme.typography, Typography.material2014()); }); - testWidgets('Material3 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { final ThemeData m3Theme = ThemeData(useMaterial3: true); expect(m3Theme.typography, Typography.material2021(colorScheme: m3Theme.colorScheme)); }); - testWidgets('PopupMenu inherits shadowed app theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PopupMenu inherits shadowed app theme', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/5572 final Key popupMenuButtonKey = UniqueKey(); await tester.pumpWidget( @@ -231,7 +232,7 @@ void main() { } }); - testWidgets('ModalBottomSheet inherits shadowed app theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ModalBottomSheet inherits shadowed app theme', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(brightness: Brightness.dark), @@ -264,7 +265,7 @@ void main() { expect(Theme.of(tester.element(find.text('bottomSheet'))).brightness, equals(Brightness.light)); }); - testWidgets('Dialog inherits shadowed app theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dialog inherits shadowed app theme', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -298,7 +299,7 @@ void main() { expect(Theme.of(tester.element(find.text('dialog'))).brightness, equals(Brightness.light)); }); - testWidgets("Scaffold inherits theme's scaffoldBackgroundColor", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Scaffold inherits theme's scaffoldBackgroundColor", (WidgetTester tester) async { const Color green = Color(0xFF00FF00); await tester.pumpWidget( @@ -340,7 +341,7 @@ void main() { expect(materials[1].color, green); // dialog scaffold }); - testWidgets('IconThemes are applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconThemes are applied', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(iconTheme: const IconThemeData(color: Colors.green, size: 10.0)), @@ -373,7 +374,7 @@ void main() { expect(glyphText.text.style!.fontSize, 20.0); }); - testWidgets( + testWidgetsWithLeakTracking( 'Same ThemeData reapplied does not trigger descendants rebuilds', (WidgetTester tester) async { testBuildCalled = 0; @@ -408,7 +409,7 @@ void main() { }, ); - testWidgets('Text geometry set in Theme has higher precedence than that of Localizations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text geometry set in Theme has higher precedence than that of Localizations', (WidgetTester tester) async { const double kMagicFontSize = 4321.0; final ThemeData fallback = ThemeData.fallback(); final ThemeData customTheme = fallback.copyWith( @@ -439,7 +440,7 @@ void main() { expect(actualFontSize, kMagicFontSize); }); - testWidgets('Material2 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { late ThemeData theme; await tester.pumpWidget(Theme( data: ThemeData(useMaterial3: false), @@ -497,7 +498,7 @@ void main() { expect(theme.textTheme.displayLarge!.debugLabel, '(englishLike displayLarge 2014).merge(blackMountainView displayLarge)'); }); - testWidgets('Material3 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { late ThemeData theme; await tester.pumpWidget(Theme( data: ThemeData(useMaterial3: true), @@ -582,7 +583,7 @@ void main() { context = null; }); - testWidgets('Material2 - Default light theme has defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Default light theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData(useMaterial3: false)); expect(themeM2.brightness, Brightness.light); @@ -593,7 +594,7 @@ void main() { expect(themeM2.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Material3 - Default light theme has defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Default light theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData(useMaterial3: true)); expect(themeM3.brightness, Brightness.light); @@ -604,7 +605,7 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Material2 - Dark theme has defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Dark theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData.dark(useMaterial3: false)); expect(themeM2.brightness, Brightness.dark); @@ -615,7 +616,7 @@ void main() { expect(themeM2.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Material3 - Dark theme has defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Dark theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData.dark(useMaterial3: true)); expect(themeM3.brightness, Brightness.dark); @@ -626,7 +627,7 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('MaterialTheme overrides the brightness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialTheme overrides the brightness', (WidgetTester tester) async { await testTheme(tester, ThemeData.dark()); expect(CupertinoTheme.brightnessOf(context!), Brightness.dark); @@ -647,7 +648,7 @@ void main() { expect(CupertinoTheme.brightnessOf(context!), Brightness.light); }); - testWidgets('Material2 - Can override material theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Can override material theme', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( scaffoldBackgroundColor: CupertinoColors.lightBackgroundGray, @@ -665,7 +666,7 @@ void main() { expect(themeM2.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Material3 - Can override material theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Can override material theme', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( scaffoldBackgroundColor: CupertinoColors.lightBackgroundGray, @@ -683,7 +684,7 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Material2 - Can override properties that are independent of material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Can override properties that are independent of material', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( // The bar colors ignore all things material except brightness. @@ -697,7 +698,7 @@ void main() { expect(themeM2.barBackgroundColor, CupertinoColors.black); }); - testWidgets('Material3 - Can override properties that are independent of material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Can override properties that are independent of material', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( // The bar colors ignore all things material except brightness. @@ -711,7 +712,7 @@ void main() { expect(themeM3.barBackgroundColor, CupertinoColors.black); }); - testWidgets('Material2 - Changing material theme triggers rebuilds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Changing material theme triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( useMaterial3: false, primarySwatch: Colors.red, @@ -729,7 +730,7 @@ void main() { expect(themeM2.primaryColor, Colors.orange); }); - testWidgets('Material3 - Changing material theme triggers rebuilds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Changing material theme triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( useMaterial3: true, colorScheme: const ColorScheme.light( @@ -751,7 +752,7 @@ void main() { expect(themeM3.primaryColor, Colors.orange); }); - testWidgets( + testWidgetsWithLeakTracking( "CupertinoThemeData does not override material theme's icon theme", (WidgetTester tester) async { const Color materialIconColor = Colors.blue; @@ -767,7 +768,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Changing cupertino theme override triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( @@ -792,7 +793,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Cupertino theme override blocks derivative changes', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( @@ -819,7 +820,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Material2 - Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( @@ -848,7 +849,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Material3 - Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( @@ -881,7 +882,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Material2 - copyWith only copies the overrides, not the material or cupertino derivatives', (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( @@ -908,7 +909,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Material3 - copyWith only copies the overrides, not the material or cupertino derivatives', (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( @@ -935,7 +936,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( "Material2 - Material themes with no cupertino overrides can also be copyWith'ed", (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( @@ -958,7 +959,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( "Material3 - Material themes with no cupertino overrides can also be copyWith'ed", (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 2d5b880fa5ba0..cb875d6fe4f45 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -11,6 +11,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; @@ -23,7 +24,7 @@ void main() { return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first); } - testWidgets('Material2 - Dialog size - dial mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Dialog size - dial mode', (WidgetTester tester) async { addTearDown(tester.view.reset); const Size timePickerPortraitSize = Size(310, 468); diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index 784333c917100..5b5394995b4fd 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('TimePickerThemeData copyWith, ==, hashCode basics', () { @@ -44,7 +45,7 @@ void main() { expect(timePickerTheme.shape, null); }); - testWidgets('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TimePickerThemeData().debugFillProperties(builder); @@ -56,7 +57,7 @@ void main() { expect(description, []); }); - testWidgets('TimePickerThemeData implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TimePickerThemeData implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const TimePickerThemeData( backgroundColor: Color(0xfffffff0), @@ -122,7 +123,7 @@ void main() { ])); }); - testWidgets('Material2 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { final ThemeData defaultTheme = ThemeData(useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); await tester.tap(find.text('X')); @@ -255,7 +256,7 @@ void main() { expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); - testWidgets('Material3 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { final ThemeData defaultTheme = ThemeData(useMaterial3: true); await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); await tester.tap(find.text('X')); @@ -490,7 +491,7 @@ void main() { expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString())); }); - testWidgets('Material2 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(); final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); @@ -613,7 +614,7 @@ void main() { expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString())); }); - testWidgets('Material3 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(); final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: true); await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index 2c9926ac17cd3..37050875ab722 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -59,11 +59,11 @@ void main() { group('RestorableTimeOfDay tests', () { testWidgetsWithLeakTracking('value is not accessible when not registered', (WidgetTester tester) async { final RestorableTimeOfDay property = RestorableTimeOfDay(const TimeOfDay(hour: 20, minute: 4)); - addTearDown(() => property.dispose()); + addTearDown(property.dispose); expect(() => property.value, throwsAssertionError); }); - testWidgets('work when not in restoration scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); final _RestorableWidgetState state = tester.state(find.byType(_RestorableWidget)); @@ -196,4 +196,10 @@ class _RestorableWidgetState extends State<_RestorableWidget> with RestorationMi @override String get restorationId => 'widget'; + + @override + void dispose() { + timeOfDay.dispose(); + super.dispose(); + } } diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart index 94fcde0662911..6b568c56b490a 100644 --- a/packages/flutter/test/material/tooltip_test.dart +++ b/packages/flutter/test/material/tooltip_test.dart @@ -24,14 +24,17 @@ Finder _findTooltipContainer(String tooltipText) { } void main() { - testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -78,8 +81,11 @@ void main() { expect(tipInGlobal.dy, 20.0); }); - testWidgets('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center with padding outside overlay', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -87,7 +93,7 @@ void main() { padding: const EdgeInsets.all(20), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -137,8 +143,11 @@ void main() { expect(tipInGlobal.dy, 40.0); }); - testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - top left', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -146,7 +155,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -191,14 +200,17 @@ void main() { expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0))); }); - testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -244,14 +256,17 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -308,14 +323,17 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -360,8 +378,11 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -369,7 +390,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -417,8 +438,11 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -426,7 +450,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -474,7 +498,7 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0)); }); - testWidgets('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip should be fully visible when MediaQuery.viewInsets > 0', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23666 Widget materialAppWithViewInsets(double viewInsetsHeight) { final Widget scaffold = Scaffold( @@ -529,15 +553,18 @@ void main() { expect(tooltipTopRight.dy, lessThan(fabTopRight.dy)); }); - testWidgets('Custom tooltip margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom tooltip margin', (WidgetTester tester) async { const double customMarginValue = 10.0; final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Tooltip( key: tooltipKey, @@ -766,8 +793,11 @@ void main() { expect(textStyle.decorationStyle, isNot(TextDecorationStyle.double)); }); - testWidgets('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does tooltip end up with the right default size, shape, and color', (WidgetTester tester) async { final GlobalKey tooltipKey = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -775,7 +805,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Tooltip( key: tooltipKey, @@ -2277,7 +2307,7 @@ void main() { expect(element.dirty, isFalse); }); - testWidgets('Tooltip does not initialize animation controller in dispose process', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip does not initialize animation controller in dispose process', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Center( @@ -2296,7 +2326,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Tooltip does not crash when showing the tooltip but the OverlayPortal is unmounted, during dispose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip does not crash when showing the tooltip but the OverlayPortal is unmounted, during dispose', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: SelectionArea( diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart index 1c328e6b259d2..4548f331211c2 100644 --- a/packages/flutter/test/material/tooltip_theme_test.dart +++ b/packages/flutter/test/material/tooltip_theme_test.dart @@ -112,8 +112,10 @@ void main() { ]); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -128,7 +130,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -169,8 +171,12 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -183,7 +189,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -224,8 +230,11 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -240,7 +249,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -292,8 +301,12 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer above does not fit - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -306,7 +319,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -358,8 +371,10 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center preferBelow fits - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -374,7 +389,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -414,8 +429,12 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip verticalOffset, preferBelow; center prefer below fits - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -428,7 +447,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Stack( children: [ @@ -468,14 +487,18 @@ void main() { expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0)); }); - testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip margin - ThemeData', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Theme( data: ThemeData( @@ -523,14 +546,17 @@ void main() { expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue); }); - testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip margin - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return TooltipTheme( data: const TooltipThemeData( @@ -674,12 +700,14 @@ void main() { expect(textAlign, TextAlign.end); }); - testWidgets('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip decoration - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), color: Color(0x80800000), ); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -692,7 +720,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Tooltip( key: key, @@ -716,12 +744,16 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgets('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip decoration - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const Decoration customDecoration = ShapeDecoration( shape: StadiumBorder(), color: Color(0x80800000), ); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -731,7 +763,7 @@ void main() { data: const TooltipThemeData(decoration: customDecoration), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Tooltip( key: key, @@ -756,11 +788,14 @@ void main() { expect(tip, paints..rrect(color: const Color(0x80800000))); }); - testWidgets('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip height and padding - ThemeData.tooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingVal = 20.0; + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -773,7 +808,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Tooltip( key: key, @@ -803,10 +838,12 @@ void main() { expect(content.size.width, equals(tip.size.width - 2 * customPaddingVal)); }); - testWidgets('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tooltip height and padding - TooltipTheme', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double customTooltipHeight = 100.0; const double customPaddingValue = 20.0; + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget( Directionality( @@ -818,7 +855,7 @@ void main() { ), child: Overlay( initialEntries: [ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Tooltip( key: key, diff --git a/packages/flutter/test/material/value_indicating_slider_test.dart b/packages/flutter/test/material/value_indicating_slider_test.dart index c0c255badddd0..062115f2a7452 100644 --- a/packages/flutter/test/material/value_indicating_slider_test.dart +++ b/packages/flutter/test/material/value_indicating_slider_test.dart @@ -13,7 +13,7 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Slider value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -54,7 +54,7 @@ void main() { ); }); - testWidgets('Slider value indicator wide text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -195,7 +195,7 @@ void main() { // support is deprecated and the APIs are removed, these tests // can be deleted. - testWidgets('Slider value indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, @@ -233,7 +233,7 @@ void main() { ); }); - testWidgets('Slider value indicator wide text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider value indicator wide text', (WidgetTester tester) async { await _buildValueIndicatorStaticSlider( tester, value: 0, diff --git a/packages/flutter/test/material/will_pop_test.dart b/packages/flutter/test/material/will_pop_test.dart index b99e473d65b97..b5e584e6575cb 100644 --- a/packages/flutter/test/material/will_pop_test.dart +++ b/packages/flutter/test/material/will_pop_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; bool willPopValue = false; @@ -96,7 +97,7 @@ class _TestPage extends Page { } void main() { - testWidgets('ModalRoute scopedWillPopupCallback can inhibit back button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ModalRoute scopedWillPopupCallback can inhibit back button', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -151,7 +152,7 @@ void main() { expect(find.text('Sample Page'), findsNothing); }); - testWidgets('willPop will only pop if the callback returns true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('willPop will only pop if the callback returns true', (WidgetTester tester) async { Widget buildFrame() { return MaterialApp( home: Scaffold( @@ -190,7 +191,7 @@ void main() { expect(find.text('Sample Form'), findsNothing); }); - testWidgets('Form.willPop can inhibit back button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Form.willPop can inhibit back button', (WidgetTester tester) async { Widget buildFrame() { return MaterialApp( home: Scaffold( @@ -244,7 +245,7 @@ void main() { expect(willPopCount, 1); }); - testWidgets('Form.willPop callbacks do not accumulate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Form.willPop callbacks do not accumulate', (WidgetTester tester) async { Future showYesNoAlert(BuildContext context) async { return (await showDialog( context: context, @@ -336,7 +337,7 @@ void main() { expect(find.text('Sample Form'), findsNothing); }); - testWidgets('Route.scopedWillPop callbacks do not accumulate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route.scopedWillPop callbacks do not accumulate', (WidgetTester tester) async { late StateSetter contentsSetState; // call this to rebuild the route's SampleForm contents bool contentsEmpty = false; // when true, don't include the SampleForm in the route @@ -396,7 +397,7 @@ void main() { expect(route.hasCallback, isFalse); }); - testWidgets('should handle new route if page moved from one navigator to another', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should handle new route if page moved from one navigator to another', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/89133 late StateSetter contentsSetState; bool moveToAnotherNavigator = false; From e66ec8e0b04dbdb2011980e3622708c7c9fd69d4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 5 Sep 2023 13:49:05 -0700 Subject: [PATCH 1079/1547] Dispose AnimationSheetRecorder to avoid leaks (#133365) This PR adds `AnimationSheetRecorder.dispose`, which disposes all the images generated by the recorder, eliminating leaks. Fixes https://github.com/flutter/flutter/issues/133071. --- .../test/animation/animation_sheet_test.dart | 22 +---- .../test/animation/live_binding_test.dart | 9 +- .../material/progress_indicator_test.dart | 12 ++- .../flutter_test/lib/src/animation_sheet.dart | 99 +++++++++++++++---- 4 files changed, 94 insertions(+), 48 deletions(-) diff --git a/packages/flutter/test/animation/animation_sheet_test.dart b/packages/flutter/test/animation/animation_sheet_test.dart index df48b9e4baee5..c04bb535c5a38 100644 --- a/packages/flutter/test/animation/animation_sheet_test.dart +++ b/packages/flutter/test/animation/animation_sheet_test.dart @@ -7,8 +7,6 @@ @Tags(['reduced-test-set']) library; -import 'dart:ui' as ui; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; @@ -23,6 +21,7 @@ void main() { testWidgetsWithLeakTracking('recording disposes images', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); + addTearDown(builder.dispose); await tester.pumpFrames( builder.record( @@ -33,13 +32,12 @@ void main() { ); }, skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 - // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 - leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), ); testWidgetsWithLeakTracking('correctly records frames using collate', (WidgetTester tester) async { final AnimationSheetBuilder builder = AnimationSheetBuilder(frameSize: _DecuplePixels.size); + addTearDown(builder.dispose); await tester.pumpFrames( builder.record( @@ -66,18 +64,12 @@ void main() { const Duration(milliseconds: 100), ); - final ui.Image image = await builder.collate(5); - await expectLater( - image, + builder.collate(5), matchesGoldenFile('test.animation_sheet_builder.collate.png'), ); - - image.dispose(); }, skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 - // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 - leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), ); // https://github.com/flutter/flutter/issues/56001 testWidgetsWithLeakTracking('use allLayers to record out-of-subtree contents', (WidgetTester tester) async { @@ -85,6 +77,7 @@ void main() { frameSize: const Size(8, 2), allLayers: true, ); + addTearDown(builder.dispose); // The `record` (sized 8, 2) is placed on top of `_DecuplePixels` // (sized 12, 3), aligned at its top left. @@ -105,17 +98,12 @@ void main() { const Duration(milliseconds: 100), ); - final ui.Image image = await builder.collate(5); - await expectLater( - image, + builder.collate(5), matchesGoldenFile('test.animation_sheet_builder.out_of_tree.png'), ); - image.dispose(); }, skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 - // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 - leakTrackingTestConfig: const LeakTrackingTestConfig(allowAllNotDisposed: true), ); } diff --git a/packages/flutter/test/animation/live_binding_test.dart b/packages/flutter/test/animation/live_binding_test.dart index 5959c669bb272..751f0886a47f6 100644 --- a/packages/flutter/test/animation/live_binding_test.dart +++ b/packages/flutter/test/animation/live_binding_test.dart @@ -7,8 +7,6 @@ @Tags(['reduced-test-set']) library; -import 'dart:ui' as ui; - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; @@ -23,6 +21,7 @@ void main() { testWidgetsWithLeakTracking('Should show event indicator for pointer events', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(200, 200), allLayers: true); + addTearDown(animationSheet.dispose); final List taps = []; Widget target({bool recording = true}) => Container( padding: const EdgeInsets.fromLTRB(20, 10, 25, 20), @@ -81,6 +80,7 @@ void main() { testWidgetsWithLeakTracking('Should show event indicator for pointer events with setSurfaceSize', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(200, 200), allLayers: true); + addTearDown(animationSheet.dispose); final List taps = []; Widget target({bool recording = true}) => Container( padding: const EdgeInsets.fromLTRB(20, 10, 25, 20), @@ -131,13 +131,10 @@ void main() { await tester.pumpFrames(target(), const Duration(milliseconds: 50)); expect(taps, isEmpty); - final ui.Image image = await animationSheet.collate(6); - await expectLater( - image, + animationSheet.collate(6), matchesGoldenFile('LiveBinding.press.animation.2.png'), ); - image.dispose(); }, skip: isBrowser, // [intended] https://github.com/flutter/flutter/issues/56001 // TODO(polina-c): remove after fixing https://github.com/flutter/flutter/issues/133071 diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 2c1a72ce88fa6..91fe68bc3a11f 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -720,6 +720,7 @@ void main() { testWidgets('Material2 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); + addTearDown(animationSheet.dispose); await tester.pumpFrames(animationSheet.record( Theme( @@ -729,13 +730,14 @@ void main() { ), const Duration(seconds: 3)); await expectLater( - await animationSheet.collate(20), + animationSheet.collate(20), matchesGoldenFile('m2_material.refresh_progress_indicator.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 testWidgets('Material3 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); + addTearDown(animationSheet.dispose); await tester.pumpFrames(animationSheet.record( Theme( @@ -745,7 +747,7 @@ void main() { ), const Duration(seconds: 3)); await expectLater( - await animationSheet.collate(20), + animationSheet.collate(20), matchesGoldenFile('m3_material.refresh_progress_indicator.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 @@ -1017,6 +1019,7 @@ void main() { testWidgets('Material2 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); + addTearDown(animationSheet.dispose); await tester.pumpFrames(animationSheet.record( Theme( @@ -1032,13 +1035,14 @@ void main() { ), const Duration(seconds: 2)); await expectLater( - await animationSheet.collate(20), + animationSheet.collate(20), matchesGoldenFile('m2_material.circular_progress_indicator.indeterminate.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 testWidgets('Material3 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); + addTearDown(animationSheet.dispose); await tester.pumpFrames(animationSheet.record( Theme( @@ -1054,7 +1058,7 @@ void main() { ), const Duration(seconds: 2)); await expectLater( - await animationSheet.collate(20), + animationSheet.collate(20), matchesGoldenFile('m3_material.circular_progress_indicator.indeterminate.png'), ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 diff --git a/packages/flutter_test/lib/src/animation_sheet.dart b/packages/flutter_test/lib/src/animation_sheet.dart index aa69e50970908..48b5d269ab5de 100644 --- a/packages/flutter_test/lib/src/animation_sheet.dart +++ b/packages/flutter_test/lib/src/animation_sheet.dart @@ -9,6 +9,36 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; +// A Future that stores the resolved result. +class _AsyncImage { + _AsyncImage(Future task) { + _task = task.then((ui.Image image) { + _result = image; + }); + } + + // Returns the resolved image. + Future result() async { + if (_result != null) { + return _result!; + } + await _task; + assert(_result != null); + return _result!; + } + + late final Future _task; + ui.Image? _result; + + // Wait for a list of `_AsyncImage` and returns the list of its resolved + // images. + static Future> resolveList(List<_AsyncImage> targets) { + final Iterable> images = targets.map>( + (_AsyncImage target) => target.result()); + return Future.wait(images); + } +} + /// Records the frames of an animating widget, and later displays the frames as a /// grid in an animation sheet. /// @@ -20,6 +50,7 @@ import 'package:flutter/widgets.dart'; /// Using this class includes the following steps: /// /// * Create an instance of this class. +/// * Register [dispose] to the test's tear down callbacks. /// * Pump frames that render the target widget wrapped in [record]. Every frame /// that has `recording` being true will be recorded. /// * Acquire the output image with [collate] and compare against the golden @@ -33,6 +64,7 @@ import 'package:flutter/widgets.dart'; /// testWidgets('Inkwell animation sheet', (WidgetTester tester) async { /// // Create instance /// final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(48, 24)); +/// addTearDown(animationSheet.dispose); /// /// final Widget target = Material( /// child: Directionality( @@ -90,6 +122,24 @@ class AnimationSheetBuilder { this.allLayers = false, }) : assert(!kIsWeb); + /// Dispose all recorded frames and result images. + /// + /// This method must be called before the test case ends (usually as a tear + /// down callback) to properly deallocate the images. + /// + /// After this method is called, there will be no frames to [collate]. + Future dispose() async { + final List<_AsyncImage> targets = <_AsyncImage>[ + ..._recordedFrames, + ..._results, + ]; + _recordedFrames.clear(); + _results.clear(); + for (final ui.Image image in await _AsyncImage.resolveList(targets)) { + image.dispose(); + } + } + /// The size of the child to be recorded. /// /// This size is applied as a tight layout constraint for the child, and is @@ -112,20 +162,7 @@ class AnimationSheetBuilder { /// Defaults to false. final bool allLayers; - final List> _recordedFrames = >[]; - Future> get _frames async { - final List frames = await Future.wait(_recordedFrames, eagerError: true); - assert(() { - for (final ui.Image frame in frames) { - assert(frame.width == frameSize.width && frame.height == frameSize.height, - 'Unexpected size mismatch: frame has (${frame.width}, ${frame.height}) ' - 'while `frameSize` is $frameSize.' - ); - } - return true; - }()); - return frames; - } + final List<_AsyncImage> _recordedFrames = <_AsyncImage>[]; /// Returns a widget that renders a widget in a box that can be recorded. /// @@ -152,22 +189,41 @@ class AnimationSheetBuilder { key: key, size: frameSize, allLayers: allLayers, - handleRecorded: recording ? _recordedFrames.add : null, + handleRecorded: !recording ? null : (Future futureImage) { + _recordedFrames.add(_AsyncImage(() async { + final ui.Image image = await futureImage; + assert(image.width == frameSize.width && image.height == frameSize.height, + 'Unexpected size mismatch: frame has (${image.width}, ${image.height}) ' + 'while `frameSize` is $frameSize.' + ); + return image; + }())); + }, child: child, ); } + // The result images generated by `collate`. + // + // They're stored here to be disposed by [dispose]. + final List<_AsyncImage> _results = <_AsyncImage>[]; + /// Returns an result image by putting all frames together in a table. /// - /// This method returns a table of captured frames, `cellsPerRow` images - /// per row, from left to right, top to bottom. + /// This method returns an image that arranges the captured frames in a table, + /// which has `cellsPerRow` images per row with the order from left to right, + /// top to bottom. + /// + /// The result image of this method is managed by [AnimationSheetBuilder], + /// and should not be disposed by the caller. /// /// An example of using this method can be found at [AnimationSheetBuilder]. Future collate(int cellsPerRow) async { - final List frames = await _frames; - assert(frames.isNotEmpty, + assert(_recordedFrames.isNotEmpty, 'No frames are collected. Have you forgot to set `recording` to true?'); - return _collateFrames(frames, frameSize, cellsPerRow); + final _AsyncImage result = _AsyncImage(_collateFrames(_recordedFrames, frameSize, cellsPerRow)); + _results.add(result); + return result.result(); } } @@ -281,7 +337,8 @@ class _RenderPostFrameCallbacker extends RenderProxyBox { } } -Future _collateFrames(List frames, Size frameSize, int cellsPerRow) async { +Future _collateFrames(List<_AsyncImage> futureFrames, Size frameSize, int cellsPerRow) async { + final List frames = await _AsyncImage.resolveList(futureFrames); final int rowNum = (frames.length / cellsPerRow).ceil(); final ui.PictureRecorder recorder = ui.PictureRecorder(); From e30f9c4218b2f1884f79942983f12bbfe890dfad Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 14:03:53 -0700 Subject: [PATCH 1080/1547] Revert "_SearchBarState should dispose FocusNode, if it created it." (#134072) Reverts flutter/flutter#133947 as it causes build failures. --- packages/flutter/lib/src/material/search_anchor.dart | 3 --- packages/flutter/test/material/search_anchor_test.dart | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 4897de7449df8..6cb8c22c1c627 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -1179,9 +1179,6 @@ class _SearchBarState extends State { @override void dispose() { _internalStatesController.dispose(); - if (widget.focusNode == null) { - _focusNode.dispose(); - } super.dispose(); } diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index c2af15aad9ac1..c044bdfc0a4db 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -6,10 +6,9 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgetsWithLeakTracking('SearchBar defaults', (WidgetTester tester) async { + testWidgets('SearchBar defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colorScheme = theme.colorScheme; From a425e56252e315bdf0ac2378ad8be3801d1fdc76 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Tue, 5 Sep 2023 14:03:54 -0700 Subject: [PATCH 1081/1547] Revert "CupertinoAlertDialog should not create ScrollController on every build, if null values are passed in constructor." (#134071) Reverts flutter/flutter#133918 as it causes build failures. --- .../flutter/lib/src/cupertino/dialog.dart | 48 +++++++------------ .../flutter/test/material/dialog_test.dart | 2 +- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 2e4d27af75740..ef8c10936043b 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -188,7 +188,7 @@ bool _isInAccessibilityMode(BuildContext context) { /// * [CupertinoDialogAction], which is an iOS-style dialog button. /// * [AlertDialog], a Material Design alert dialog. /// * -class CupertinoAlertDialog extends StatefulWidget { +class CupertinoAlertDialog extends StatelessWidget { /// Creates an iOS-style alert dialog. /// /// The [actions] must not be null. @@ -233,6 +233,9 @@ class CupertinoAlertDialog extends StatefulWidget { /// section when there are many actions. final ScrollController? scrollController; + ScrollController get _effectiveScrollController => + scrollController ?? ScrollController(); + /// A scroll controller that can be used to control the scrolling of the /// actions in the dialog. /// @@ -244,49 +247,37 @@ class CupertinoAlertDialog extends StatefulWidget { /// section when it is long. final ScrollController? actionScrollController; + ScrollController get _effectiveActionScrollController => + actionScrollController ?? ScrollController(); + /// {@macro flutter.material.dialog.insetAnimationDuration} final Duration insetAnimationDuration; /// {@macro flutter.material.dialog.insetAnimationCurve} final Curve insetAnimationCurve; - @override - State createState() => _CupertinoAlertDialogState(); -} - -class _CupertinoAlertDialogState extends State { - ScrollController? _backupScrollController; - - ScrollController? _backupActionScrollController; - - ScrollController get _effectiveScrollController => - widget.scrollController ?? (_backupScrollController ??= ScrollController()); - - ScrollController get _effectiveActionScrollController => - widget.actionScrollController ?? (_backupActionScrollController ??= ScrollController()); - Widget _buildContent(BuildContext context) { final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; final List children = [ - if (widget.title != null || widget.content != null) + if (title != null || content != null) Flexible( flex: 3, child: _CupertinoAlertContentSection( - title: widget.title, - message: widget.content, + title: title, + message: content, scrollController: _effectiveScrollController, titlePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, - bottom: widget.content == null ? _kDialogEdgePadding : 1.0, + bottom: content == null ? _kDialogEdgePadding : 1.0, top: _kDialogEdgePadding * textScaleFactor, ), messagePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, bottom: _kDialogEdgePadding * textScaleFactor, - top: widget.title == null ? _kDialogEdgePadding : 1.0, + top: title == null ? _kDialogEdgePadding : 1.0, ), titleTextStyle: _kCupertinoDialogTitleStyle.copyWith( color: CupertinoDynamicColor.resolve(CupertinoColors.label, context), @@ -312,10 +303,10 @@ class _CupertinoAlertDialogState extends State { Widget actionSection = Container( height: 0.0, ); - if (widget.actions.isNotEmpty) { + if (actions.isNotEmpty) { actionSection = _CupertinoAlertActionSection( scrollController: _effectiveActionScrollController, - children: widget.actions, + children: actions, ); } @@ -339,8 +330,8 @@ class _CupertinoAlertDialogState extends State { return AnimatedPadding( padding: MediaQuery.viewInsetsOf(context) + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), - duration: widget.insetAnimationDuration, - curve: widget.insetAnimationCurve, + duration: insetAnimationDuration, + curve: insetAnimationCurve, child: MediaQuery.removeViewInsets( removeLeft: true, removeTop: true, @@ -377,13 +368,6 @@ class _CupertinoAlertDialogState extends State { ), ); } - - @override - void dispose() { - _backupScrollController?.dispose(); - _backupActionScrollController?.dispose(); - super.dispose(); - } } /// Rounded rectangle surface that looks like an iOS popup surface, e.g., alert dialog diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 0a162059412d9..98755d1daea06 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -2664,7 +2664,7 @@ void main() { okNode.dispose(); }); - testWidgetsWithLeakTracking('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { + testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog.adaptive( content: Container( height: 5000.0, From d6edbfc3d17194ca6aa39de26e444fcf5cc172eb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 17:18:12 -0400 Subject: [PATCH 1082/1547] Roll Flutter Engine from 1a6b47af3eb0 to f4975e04f35e (16 revisions) (#134069) https://github.com/flutter/engine/compare/1a6b47af3eb0...f4975e04f35e 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from c07fbf4c1d67 to a0572041af8e (3 revisions) (flutter/engine#45460) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from 9666d4d5f7c8 to dcd62fc41c3b (1 revision) (flutter/engine#45457) 2023-09-05 jonahwilliams@google.com [Impeller] compute path bounds once, use Skia computed bounds where possible. (flutter/engine#45456) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from d8ea902500a3 to c07fbf4c1d67 (2 revisions) (flutter/engine#45451) 2023-09-05 zanderso@users.noreply.github.com Adds a Dart library for loading and parsing build configs (flutter/engine#45390) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from 17c4741d70dd to 9666d4d5f7c8 (1 revision) (flutter/engine#45453) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 055b26152483 to d8ea902500a3 (1 revision) (flutter/engine#45448) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from e72efa276c45 to 17c4741d70dd (1 revision) (flutter/engine#45449) 2023-09-05 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from qe_q1aYCmE0eC-2Yz... to bHw1LzoikQJthLkTE... (flutter/engine#45447) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 9ef0225b5f8a to 055b26152483 (1 revision) (flutter/engine#45446) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from b62216047112 to e72efa276c45 (1 revision) (flutter/engine#45443) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 7d0e33e32427 to 9ef0225b5f8a (1 revision) (flutter/engine#45442) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from e691a4edb19a to b62216047112 (1 revision) (flutter/engine#45441) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 8206402f3c35 to 7d0e33e32427 (2 revisions) (flutter/engine#45440) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from ab9bbb9b11b3 to e691a4edb19a (1 revision) (flutter/engine#45437) 2023-09-05 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from A82pOZ3-NNgfJ2Da7... to qe_q1aYCmE0eC-2Yz... (flutter/engine#45436) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from A82pOZ3-NNgf to bHw1LzoikQJt If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 340c289fe476c..17475b9f371b3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1a6b47af3eb04edf82fd7fc497f67c7a5ddad59b +f4975e04f35e046eee3f632d551f9ac2003575af diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 335b2a447cc52..958e8c7f25db3 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -A82pOZ3-NNgfJ2Da76Zu3A1TMRh7dpFbjB-G9Eu7FgIC +bHw1LzoikQJthLkTEoO1kzf4AM2dzLpCWtz35OS5eKUC From 6c5642167f2073c14c5ec2b8e8a09a4425624140 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Tue, 5 Sep 2023 16:48:50 -0500 Subject: [PATCH 1083/1547] Retry connecting to device in CI after lost connection (#133769) Sometimes `ios-deploy` loses connection to the device after installing, starting debugserver, and launching. This is shown with an error message like: ``` Process 579 exited with status = -1 (0xffffffff) lost connection ``` This happens frequently in our CI system: https://github.com/flutter/flutter/issues/120808 Usually in CI, on retry it'll work and pass - so this is an attempt to retry without failing the test first. It's not guaranteed to fix since we're unable to recreate this error locally. --- .../flutter_tools/lib/src/ios/devices.dart | 109 +++++++++++++----- .../flutter_tools/lib/src/ios/ios_deploy.dart | 14 +++ .../ios/ios_device_start_prebuilt_test.dart | 83 +++++++++++++ 3 files changed, 175 insertions(+), 31 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 85d89aceeb274..fa6961e5e4611 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -537,34 +537,12 @@ class IOSDevice extends Device { int installationResult = 1; if (debuggingOptions.debuggingEnabled) { _logger.printTrace('Debugging is enabled, connecting to vmService'); - final DeviceLogReader deviceLogReader = getLogReader( - app: package, - usingCISystem: debuggingOptions.usingCISystem, - ); - - // If the device supports syslog reading, prefer launching the app without - // attaching the debugger to avoid the overhead of the unnecessary extra running process. - if (majorSdkVersion >= IOSDeviceLogReader.minimumUniversalLoggingSdkVersion) { - iosDeployDebugger = _iosDeploy.prepareDebuggerForLaunch( - deviceId: id, - bundlePath: bundle.path, - appDeltaDirectory: package.appDeltaDirectory, - launchArguments: launchArguments, - interfaceType: connectionInterface, - uninstallFirst: debuggingOptions.uninstallFirst, - ); - if (deviceLogReader is IOSDeviceLogReader) { - deviceLogReader.debuggerStream = iosDeployDebugger; - } - } - // Don't port foward if debugging with a wireless device. - vmServiceDiscovery = ProtocolDiscovery.vmService( - deviceLogReader, - portForwarder: isWirelesslyConnected ? null : portForwarder, - hostPort: debuggingOptions.hostVmServicePort, - devicePort: debuggingOptions.deviceVmServicePort, + vmServiceDiscovery = _setupDebuggerAndVmServiceDiscovery( + package: package, + bundle: bundle, + debuggingOptions: debuggingOptions, + launchArguments: launchArguments, ipv6: ipv6, - logger: _logger, ); } @@ -589,10 +567,7 @@ class IOSDevice extends Device { installationResult = await iosDeployDebugger!.launchAndAttach() ? 0 : 1; } if (installationResult != 0) { - _logger.printError('Could not run ${bundle.path} on $id.'); - _logger.printError('Try launching Xcode and selecting "Product > Run" to fix the problem:'); - _logger.printError(' open ios/Runner.xcworkspace'); - _logger.printError(''); + _printInstallError(bundle); await dispose(); return LaunchResult.failed(); } @@ -704,6 +679,31 @@ class IOSDevice extends Device { ); } else { localUri = await vmServiceDiscovery?.uri; + // If the `ios-deploy` debugger loses connection before it finds the + // Dart Service VM url, try starting the debugger and launching the + // app again. + if (localUri == null && + debuggingOptions.usingCISystem && + iosDeployDebugger != null && + iosDeployDebugger!.lostConnection) { + _logger.printStatus('Lost connection to device. Trying to connect again...'); + await dispose(); + vmServiceDiscovery = _setupDebuggerAndVmServiceDiscovery( + package: package, + bundle: bundle, + debuggingOptions: debuggingOptions, + launchArguments: launchArguments, + ipv6: ipv6, + skipInstall: true, + ); + installationResult = await iosDeployDebugger!.launchAndAttach() ? 0 : 1; + if (installationResult != 0) { + _printInstallError(bundle); + await dispose(); + return LaunchResult.failed(); + } + localUri = await vmServiceDiscovery.uri; + } } } timer.cancel(); @@ -723,6 +723,53 @@ class IOSDevice extends Device { } } + void _printInstallError(Directory bundle) { + _logger.printError('Could not run ${bundle.path} on $id.'); + _logger.printError('Try launching Xcode and selecting "Product > Run" to fix the problem:'); + _logger.printError(' open ios/Runner.xcworkspace'); + _logger.printError(''); + } + + ProtocolDiscovery _setupDebuggerAndVmServiceDiscovery({ + required IOSApp package, + required Directory bundle, + required DebuggingOptions debuggingOptions, + required List launchArguments, + required bool ipv6, + bool skipInstall = false, + }) { + final DeviceLogReader deviceLogReader = getLogReader( + app: package, + usingCISystem: debuggingOptions.usingCISystem, + ); + + // If the device supports syslog reading, prefer launching the app without + // attaching the debugger to avoid the overhead of the unnecessary extra running process. + if (majorSdkVersion >= IOSDeviceLogReader.minimumUniversalLoggingSdkVersion) { + iosDeployDebugger = _iosDeploy.prepareDebuggerForLaunch( + deviceId: id, + bundlePath: bundle.path, + appDeltaDirectory: package.appDeltaDirectory, + launchArguments: launchArguments, + interfaceType: connectionInterface, + uninstallFirst: debuggingOptions.uninstallFirst, + skipInstall: skipInstall, + ); + if (deviceLogReader is IOSDeviceLogReader) { + deviceLogReader.debuggerStream = iosDeployDebugger; + } + } + // Don't port foward if debugging with a wireless device. + return ProtocolDiscovery.vmService( + deviceLogReader, + portForwarder: isWirelesslyConnected ? null : portForwarder, + hostPort: debuggingOptions.hostVmServicePort, + devicePort: debuggingOptions.deviceVmServicePort, + ipv6: ipv6, + logger: _logger, + ); + } + /// Starting with Xcode 15 and iOS 17, `ios-deploy` stopped working due to /// the new CoreDevice connectivity stack. Previously, `ios-deploy` was used /// to install the app, launch the app, and start `debugserver`. diff --git a/packages/flutter_tools/lib/src/ios/ios_deploy.dart b/packages/flutter_tools/lib/src/ios/ios_deploy.dart index 846b9b4c79ef5..71cb6dbee63d7 100644 --- a/packages/flutter_tools/lib/src/ios/ios_deploy.dart +++ b/packages/flutter_tools/lib/src/ios/ios_deploy.dart @@ -129,6 +129,7 @@ class IOSDeploy { required DeviceConnectionInterface interfaceType, Directory? appDeltaDirectory, required bool uninstallFirst, + bool skipInstall = false, }) { appDeltaDirectory?.createSync(recursive: true); // Interactive debug session to support sending the lldb detach command. @@ -148,6 +149,8 @@ class IOSDeploy { ], if (uninstallFirst) '--uninstall', + if (skipInstall) + '--noinstall', '--debug', if (interfaceType != DeviceConnectionInterface.wireless) '--no-wifi', @@ -327,6 +330,14 @@ class IOSDeployDebugger { /// The future should be completed once the backtraces are logged. Completer? _processResumeCompleter; + // Process 525 exited with status = -1 (0xffffffff) lost connection + static final RegExp _lostConnectionPattern = RegExp(r'exited with status = -1 \(0xffffffff\) lost connection'); + + /// Whether ios-deploy received a message matching [_lostConnectionPattern], + /// indicating that it lost connection to the device. + bool get lostConnection => _lostConnection; + bool _lostConnection = false; + /// Launch the app on the device, and attach the debugger. /// /// Returns whether or not the debugger successfully attached. @@ -448,6 +459,9 @@ class IOSDeployDebugger { // The app exited or crashed, so exit. Continue passing debugging // messages to the log reader until it exits to capture crash dumps. _logger.printTrace(line); + if (line.contains(_lostConnectionPattern)) { + _lostConnection = true; + } exit(); return; } diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 8e8e2235a6bcf..f163f32e2fa77 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -75,6 +75,7 @@ FakeCommand attachDebuggerCommand({ String stdout = '(lldb) run\nsuccess', Completer? completer, bool isWirelessDevice = false, + bool skipInstall = false, }) { return FakeCommand( command: [ @@ -87,6 +88,8 @@ FakeCommand attachDebuggerCommand({ '123', '--bundle', '/', + if (skipInstall) + '--noinstall', '--debug', if (!isWirelessDevice) '--no-wifi', '--args', @@ -339,6 +342,86 @@ void main() { MDnsVmServiceDiscovery: () => FakeMDnsVmServiceDiscovery(), }); + testWithoutContext('IOSDevice.startApp retries when ios-deploy loses connection the first time in CI', () async { + final BufferLogger logger = BufferLogger.test(); + final FileSystem fileSystem = MemoryFileSystem.test(); + final Completer completer = Completer(); + final FakeProcessManager processManager = FakeProcessManager.list([ + attachDebuggerCommand( + stdout: '(lldb) run\nsuccess\nProcess 525 exited with status = -1 (0xffffffff) lost connection', + ), + attachDebuggerCommand( + stdout: '(lldb) run\nsuccess\nThe Dart VM service is listening on http://127.0.0.1:456', + completer: completer, + skipInstall: true, + ), + ]); + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: fileSystem.currentDirectory, + applicationPackage: fileSystem.currentDirectory, + ); + + device.portForwarder = const NoOpDevicePortForwarder(); + + final LaunchResult launchResult = await device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled( + BuildInfo.debug, + usingCISystem: true, + ), + platformArgs: {}, + ); + completer.complete(); + + expect(processManager, hasNoRemainingExpectations); + expect(launchResult.started, true); + expect(launchResult.hasVmService, true); + expect(await device.stopApp(iosApp), false); + }); + + testWithoutContext('IOSDevice.startApp does not retry when ios-deploy loses connection if not in CI', () async { + final BufferLogger logger = BufferLogger.test(); + final FileSystem fileSystem = MemoryFileSystem.test(); + final FakeProcessManager processManager = FakeProcessManager.list([ + attachDebuggerCommand( + stdout: '(lldb) run\nsuccess\nProcess 525 exited with status = -1 (0xffffffff) lost connection', + ), + ]); + final IOSDevice device = setUpIOSDevice( + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + final IOSApp iosApp = PrebuiltIOSApp( + projectBundleId: 'app', + bundleName: 'Runner', + uncompressedBundle: fileSystem.currentDirectory, + applicationPackage: fileSystem.currentDirectory, + ); + + device.portForwarder = const NoOpDevicePortForwarder(); + + final LaunchResult launchResult = await device.startApp(iosApp, + prebuiltApplication: true, + debuggingOptions: DebuggingOptions.enabled( + BuildInfo.debug, + ), + platformArgs: {}, + ); + + expect(processManager, hasNoRemainingExpectations); + expect(launchResult.started, false); + expect(launchResult.hasVmService, false); + expect(await device.stopApp(iosApp), false); + }); + testWithoutContext('IOSDevice.startApp succeeds in release mode', () async { final FileSystem fileSystem = MemoryFileSystem.test(); final FakeProcessManager processManager = FakeProcessManager.list([ From 9bde4f7033bf715a267ade44ad21e98193d4c47e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 18:40:06 -0400 Subject: [PATCH 1084/1547] Roll Flutter Engine from f4975e04f35e to 98b036ae708e (3 revisions) (#134077) https://github.com/flutter/engine/compare/f4975e04f35e...98b036ae708e 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 72c56fab439c to 7e80aedd05b6 (1 revision) (flutter/engine#45464) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from a0572041af8e to 72c56fab439c (1 revision) (flutter/engine#45463) 2023-09-05 skia-flutter-autoroll@skia.org Roll ANGLE from dcd62fc41c3b to 0ff71d5ecd25 (2 revisions) (flutter/engine#45462) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 17475b9f371b3..bb9e3218dc2d2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f4975e04f35e046eee3f632d551f9ac2003575af +98b036ae708ec31c9c6c6efefaf8c6faef99de6f From db0daa092b5a099a9c05c6798799666bdc5b7b4d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 19:19:15 -0400 Subject: [PATCH 1085/1547] Roll Flutter Engine from 98b036ae708e to 5b2cc9d9b8fe (2 revisions) (#134080) https://github.com/flutter/engine/compare/98b036ae708e...5b2cc9d9b8fe 2023-09-05 ychris@google.com Fix iOS unittests leak in shared.invoke method channel that causes crash (flutter/engine#45416) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 7e80aedd05b6 to 2b9fc6a2c250 (1 revision) (flutter/engine#45465) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bb9e3218dc2d2..98535ccba3594 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -98b036ae708ec31c9c6c6efefaf8c6faef99de6f +5b2cc9d9b8fe2f8bd24c8fc3c057090753902cb9 From 3871139f3a5591f5074eb5f2a565220f3ec179b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 20:18:25 -0400 Subject: [PATCH 1086/1547] Roll Flutter Engine from 5b2cc9d9b8fe to 590349006d23 (2 revisions) (#134081) https://github.com/flutter/engine/compare/5b2cc9d9b8fe...590349006d23 2023-09-05 ychris@google.com [iOS ] Fix errors in unittest and scenario tests running against iOS 17 simulators (details in the description) (flutter/engine#45391) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 2b9fc6a2c250 to 1019c10a2d38 (2 revisions) (flutter/engine#45466) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 98535ccba3594..d99362db6202d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5b2cc9d9b8fe2f8bd24c8fc3c057090753902cb9 +590349006d235f594423af3112de9842beab915c From 70c35bb5517e44e38ac369443e682c0e84809bb5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 22:17:03 -0400 Subject: [PATCH 1087/1547] Roll Flutter Engine from 590349006d23 to 8bacc3b38707 (5 revisions) (#134089) https://github.com/flutter/engine/compare/590349006d23...8bacc3b38707 2023-09-06 jonahwilliams@google.com [Impeller] construct text frames on UI thread. (flutter/engine#45418) 2023-09-06 jiahaog@users.noreply.github.com Add import for `` to fix the g3 build (flutter/engine#45471) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from af473004622f to 0a253625a76a (2 revisions) (flutter/engine#45470) 2023-09-05 skia-flutter-autoroll@skia.org Roll Skia from 1019c10a2d38 to af473004622f (2 revisions) (flutter/engine#45469) 2023-09-05 zanderso@users.noreply.github.com Adds a comment on clang_arm64_apilevel26 toolchain usage (flutter/engine#45467) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d99362db6202d..b5aa771392160 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -590349006d235f594423af3112de9842beab915c +8bacc3b38707c4d22517e2bb6cd34d18c93e84b9 From 1db39ddc8abf13aabe444efb0110b7a85d2dc051 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Tue, 5 Sep 2023 23:38:06 -0400 Subject: [PATCH 1088/1547] Roll Flutter Engine from 8bacc3b38707 to 0c663258fd09 (3 revisions) (#134096) https://github.com/flutter/engine/compare/8bacc3b38707...0c663258fd09 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 3a3a64670e08 to 72d57724bcb8 (1 revision) (flutter/engine#45476) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from ce2da423cb5d to 3a3a64670e08 (1 revision) (flutter/engine#45475) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 0a253625a76a to ce2da423cb5d (1 revision) (flutter/engine#45473) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b5aa771392160..3a8932a0afa20 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8bacc3b38707c4d22517e2bb6cd34d18c93e84b9 +0c663258fd0912536ff524f087ca5047f36c6e08 From f4a6f69dba3b9fb07f57927abbdc363d8598586f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 00:59:26 -0400 Subject: [PATCH 1089/1547] Roll Flutter Engine from 0c663258fd09 to 0c8c1647dcd0 (1 revision) (#134100) https://github.com/flutter/engine/compare/0c663258fd09...0c8c1647dcd0 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 0ff71d5ecd25 to d664543f3e6d (1 revision) (flutter/engine#45477) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3a8932a0afa20..2a2696289094d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0c663258fd0912536ff524f087ca5047f36c6e08 +0c8c1647dcd07dcc2a8d1c999ea06fa354c21ca3 From 7b0b0e2734c66a647f35ab9067102a308b5e7c08 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 01:48:15 -0400 Subject: [PATCH 1090/1547] Roll Flutter Engine from 0c8c1647dcd0 to 9344685efbc3 (1 revision) (#134103) https://github.com/flutter/engine/compare/0c8c1647dcd0...9344685efbc3 2023-09-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from bHw1LzoikQJthLkTE... to dFe-t1SosqZwU5lZR... (flutter/engine#45479) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from bHw1LzoikQJt to dFe-t1SosqZw If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2a2696289094d..3bf19ec87b319 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0c8c1647dcd07dcc2a8d1c999ea06fa354c21ca3 +9344685efbc3ac3661b165a06511173ba3715386 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 958e8c7f25db3..ad5b0387d9620 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -bHw1LzoikQJthLkTEoO1kzf4AM2dzLpCWtz35OS5eKUC +dFe-t1SosqZwU5lZRJfhlmiQNzNSKCiUmS_h3uirntsC From 3e65d04cfb5e950bdf3ab6069b7ab48c892a72fe Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 02:45:33 -0400 Subject: [PATCH 1091/1547] Roll Flutter Engine from 9344685efbc3 to bace539bb654 (1 revision) (#134104) https://github.com/flutter/engine/compare/9344685efbc3...bace539bb654 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 72d57724bcb8 to 619eef2d0d67 (1 revision) (flutter/engine#45481) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3bf19ec87b319..4c85037e08f10 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9344685efbc3ac3661b165a06511173ba3715386 +bace539bb654e49c32a53c68ff1ce11e22256fa3 From 151e8b576d90096ccd16fd1478dff1a08b949c49 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 07:52:25 -0400 Subject: [PATCH 1092/1547] Roll Flutter Engine from bace539bb654 to 3d9989f1e155 (3 revisions) (#134128) https://github.com/flutter/engine/compare/bace539bb654...3d9989f1e155 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from d664543f3e6d to 5116f54eca4f (1 revision) (flutter/engine#45487) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from a7f50692638d to 0d91e2410d0e (1 revision) (flutter/engine#45485) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 619eef2d0d67 to a7f50692638d (1 revision) (flutter/engine#45483) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4c85037e08f10..c2570fe30f54d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -bace539bb654e49c32a53c68ff1ce11e22256fa3 +3d9989f1e155d169470d3a619b84756c0d3f9122 From 90d6b0bfab9470f0439ee971a7bd28be2f3ac802 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 09:02:21 -0400 Subject: [PATCH 1093/1547] Roll Flutter Engine from 3d9989f1e155 to c7fd088291e2 (1 revision) (#134132) https://github.com/flutter/engine/compare/3d9989f1e155...c7fd088291e2 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 5116f54eca4f to 55d3636b66e0 (1 revision) (flutter/engine#45488) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c2570fe30f54d..5485dc2b2e7fd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3d9989f1e155d169470d3a619b84756c0d3f9122 +c7fd088291e26a3790b9ca32f51eebba14abd78b From c97e7fd49a37d4140f6e9a3f8a3f28fbb557f76a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 09:47:32 -0400 Subject: [PATCH 1094/1547] Roll Flutter Engine from c7fd088291e2 to 5253a33096d1 (1 revision) (#134135) https://github.com/flutter/engine/compare/c7fd088291e2...5253a33096d1 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 0d91e2410d0e to 2cc5d8f0b0ef (1 revision) (flutter/engine#45489) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5485dc2b2e7fd..599dc4e48c732 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c7fd088291e26a3790b9ca32f51eebba14abd78b +5253a33096d1880769e839ef4f718405d5c8a0f4 From 03fcfbef211c84b9d1050b1f67946be5ed6ffc0c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 10:31:15 -0400 Subject: [PATCH 1095/1547] Roll Flutter Engine from 5253a33096d1 to a5e7fa6bf81a (1 revision) (#134137) https://github.com/flutter/engine/compare/5253a33096d1...a5e7fa6bf81a 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 2cc5d8f0b0ef to d603af2045ce (1 revision) (flutter/engine#45490) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 599dc4e48c732..7010703ab180e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5253a33096d1880769e839ef4f718405d5c8a0f4 +a5e7fa6bf81a7cb15be526308f0d7abe4aa0457a From 03b60ac75b8e64703c4454220c91cc2545ebd98f Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 6 Sep 2023 08:12:10 -0700 Subject: [PATCH 1096/1547] _DropdownMenuState should dispose TextEditingController. (#133914) --- packages/flutter/lib/src/material/dropdown_menu.dart | 3 +++ packages/flutter/test/material/dropdown_menu_theme_test.dart | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 3beb00d3dda3d..ca439552ba00e 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -541,6 +541,9 @@ class _DropdownMenuState extends State> { @override void dispose() { + if (widget.controller == null) { + _textEditingController.dispose(); + } super.dispose(); } diff --git a/packages/flutter/test/material/dropdown_menu_theme_test.dart b/packages/flutter/test/material/dropdown_menu_theme_test.dart index dabb572db8295..f0c0f17962323 100644 --- a/packages/flutter/test/material/dropdown_menu_theme_test.dart +++ b/packages/flutter/test/material/dropdown_menu_theme_test.dart @@ -100,7 +100,7 @@ void main() { expect(material.textStyle?.color, themeData.colorScheme.onSurface); }); - testWidgets('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.dropdownMenuTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( dropdownMenuTheme: DropdownMenuThemeData( textStyle: TextStyle( From 99f5cf07df376400cf6231d92e573bc0324d9e51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 11:54:19 -0400 Subject: [PATCH 1097/1547] Roll Flutter Engine from a5e7fa6bf81a to 839051596b1d (2 revisions) (#134140) https://github.com/flutter/engine/compare/a5e7fa6bf81a...839051596b1d 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from a74a98890cc1 to 596a1f192faa (1 revision) (flutter/engine#45492) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from d603af2045ce to a74a98890cc1 (2 revisions) (flutter/engine#45491) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7010703ab180e..618b4fb22b172 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a5e7fa6bf81a7cb15be526308f0d7abe4aa0457a +839051596b1d888c6792c37b71761daa3d9ec10b From 61a388a44849d19d0b8586e6650ebae901af75d5 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 6 Sep 2023 09:14:57 -0700 Subject: [PATCH 1098/1547] Fix not disposed items in Cupertino app and route. (#134085) --- packages/flutter/lib/src/cupertino/app.dart | 6 ++++++ packages/flutter/lib/src/cupertino/route.dart | 6 ++++++ packages/flutter/test/cupertino/app_test.dart | 12 +++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index 43f92f56943a1..b4b0b818fa66f 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -506,6 +506,12 @@ class _CupertinoAppState extends State { _heroController = CupertinoApp.createCupertinoHeroController(); } + @override + void dispose() { + _heroController.dispose(); + super.dispose(); + } + // Combine the default localization for Cupertino with the ones contributed // by the localizationsDelegates parameter, if any. Only the first delegate // of a particular LocalizationsDelegate.type is loaded so the diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index c53efc7e87eaf..a354078c02b97 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -121,6 +121,12 @@ mixin CupertinoRouteTransitionMixin on PageRoute { return _previousTitle!; } + @override + void dispose() { + _previousTitle?.dispose(); + super.dispose(); + } + @override void didChangePrevious(Route? previousRoute) { final String? previousTitleString = previousRoute is CupertinoRouteTransitionMixin diff --git a/packages/flutter/test/cupertino/app_test.dart b/packages/flutter/test/cupertino/app_test.dart index d61df5b38cb6d..50265a8f66951 100644 --- a/packages/flutter/test/cupertino/app_test.dart +++ b/packages/flutter/test/cupertino/app_test.dart @@ -7,9 +7,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Heroes work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes work', (WidgetTester tester) async { await tester.pumpWidget(CupertinoApp( home: ListView(children: [ const Hero(tag: 'a', child: Text('foo')), @@ -394,6 +395,11 @@ void main() { return renderEditable!; } + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); + await tester.pumpWidget( CupertinoApp( theme: const CupertinoThemeData( @@ -405,8 +411,8 @@ void main() { return EditableText( backgroundCursorColor: DefaultSelectionStyle.of(context).selectionColor!, cursorColor: DefaultSelectionStyle.of(context).cursorColor!, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), ); }, From 195dca02c0e376bbac834c5148169242d5590a10 Mon Sep 17 00:00:00 2001 From: Christopher Fujino Date: Wed, 6 Sep 2023 10:22:13 -0700 Subject: [PATCH 1099/1547] [flutter_tools] Fix "FormatException: Invalid date format" during version freshness check (#134088) Fixes https://github.com/flutter/flutter/issues/134067 --- packages/flutter_tools/lib/src/version.dart | 2 + .../test/general.shard/version_test.dart | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/packages/flutter_tools/lib/src/version.dart b/packages/flutter_tools/lib/src/version.dart index 0debc4482a876..c2af8566ddb8d 100644 --- a/packages/flutter_tools/lib/src/version.dart +++ b/packages/flutter_tools/lib/src/version.dart @@ -279,6 +279,8 @@ abstract class FlutterVersion { localFrameworkCommitDate = DateTime.parse(_gitCommitDate(workingDirectory: flutterRoot)); } on VersionCheckError { return; + } on FormatException { + return; } final DateTime? latestFlutterCommitDate = await _getLatestAvailableFlutterDate(); diff --git a/packages/flutter_tools/test/general.shard/version_test.dart b/packages/flutter_tools/test/general.shard/version_test.dart index 7a0b182402e13..54ba0bcc16673 100644 --- a/packages/flutter_tools/test/general.shard/version_test.dart +++ b/packages/flutter_tools/test/general.shard/version_test.dart @@ -133,6 +133,50 @@ void main() { Cache: () => cache, }); + testUsingContext('does not crash when git log outputs malformed output', () async { + const String flutterUpstreamUrl = 'https://github.com/flutter/flutter.git'; + + final String malformedGitLogOutput = '${getChannelUpToDateVersion()}[0x7FF9E2A75000] ANOMALY: meaningless REX prefix used'; + processManager.addCommands([ + const FakeCommand( + command: ['git', '-c', 'log.showSignature=false', 'log', '-n', '1', '--pretty=format:%H'], + stdout: '1234abcd', + ), + const FakeCommand( + command: ['git', 'tag', '--points-at', '1234abcd'], + ), + const FakeCommand( + command: ['git', 'describe', '--match', '*.*.*', '--long', '--tags', '1234abcd'], + stdout: '0.1.2-3-1234abcd', + ), + FakeCommand( + command: const ['git', 'symbolic-ref', '--short', 'HEAD'], + stdout: channel, + ), + FakeCommand( + command: const ['git', 'rev-parse', '--abbrev-ref', '--symbolic', '@{upstream}'], + stdout: 'origin/$channel', + ), + const FakeCommand( + command: ['git', 'ls-remote', '--get-url', 'origin'], + stdout: flutterUpstreamUrl, + ), + FakeCommand( + command: const ['git', '-c', 'log.showSignature=false', 'log', 'HEAD', '-n', '1', '--pretty=format:%ad', '--date=iso'], + stdout: malformedGitLogOutput, + ), + ]); + + final FlutterVersion flutterVersion = FlutterVersion(clock: _testClock, fs: fs, flutterRoot: flutterRoot); + await flutterVersion.checkFlutterVersionFreshness(); + + expect(testLogger.statusText, isEmpty); + expect(processManager, hasNoRemainingExpectations); + }, overrides: { + ProcessManager: () => processManager, + Cache: () => cache, + }); + testWithoutContext('prints nothing when Flutter installation looks out-of-date but is actually up-to-date', () async { final FakeFlutterVersion flutterVersion = FakeFlutterVersion(branch: channel); final BufferLogger logger = BufferLogger.test(); From ee0a15d4f5ba67bb911ad493a5179193c7efcde1 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 6 Sep 2023 11:00:56 -0700 Subject: [PATCH 1100/1547] MinimumTextContrastGuideline should dispose image. (#133861) --- packages/flutter/test/material/color_scheme_test.dart | 3 ++- packages/flutter_test/lib/src/accessibility.dart | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/material/color_scheme_test.dart b/packages/flutter/test/material/color_scheme_test.dart index 570cb8645316e..d1e05c17f03be 100644 --- a/packages/flutter/test/material/color_scheme_test.dart +++ b/packages/flutter/test/material/color_scheme_test.dart @@ -6,6 +6,7 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; @@ -443,7 +444,7 @@ void main() { ); }); - testWidgets('generated scheme "on" colors meet a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('generated scheme "on" colors meet a11y contrast guidelines', (WidgetTester tester) async { final ColorScheme colors = ColorScheme.fromSeed(seedColor: Colors.teal); Widget label(String text, Color textColor, Color background) { diff --git a/packages/flutter_test/lib/src/accessibility.dart b/packages/flutter_test/lib/src/accessibility.dart index 17d711d2500f5..513e652236d9c 100644 --- a/packages/flutter_test/lib/src/accessibility.dart +++ b/packages/flutter_test/lib/src/accessibility.dart @@ -329,7 +329,9 @@ class MinimumTextContrastGuideline extends AccessibilityGuideline { // the last transform layer. final double ratio = 1 / renderView.flutterView.devicePixelRatio; image = await layer.toImage(renderView.paintBounds, pixelRatio: ratio); - return image.toByteData(); + final ByteData? data = await image.toByteData(); + image.dispose(); + return data; }, ); From b0e5a5ca67b9b6b1e1744b008377bbb1160e2292 Mon Sep 17 00:00:00 2001 From: Tirth Date: Thu, 7 Sep 2023 00:03:00 +0530 Subject: [PATCH 1101/1547] Add `CheckedPopupMenuItem.onTap` callback (#134000) Adds parent prop `onTap` to CheckedPopupMenuItem. Fixes #127800 --- .../flutter/lib/src/material/popup_menu.dart | 1 + .../test/material/popup_menu_test.dart | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index cc87623e63305..4d81e0959daae 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -486,6 +486,7 @@ class CheckedPopupMenuItem extends PopupMenuItem { super.labelTextStyle, super.mouseCursor, super.child, + super.onTap, }); /// Whether to display a checkmark next to the menu item. diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index fcc0fa1f8063e..79e3a7f6f6b17 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -3740,6 +3740,51 @@ void main() { expect(_labelStyle(tester, 'Item 1')!.fontWeight, customTextStyle.fontWeight); expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); }); + + testWidgets('CheckedPopupMenuItem.onTap callback is called when defined', (WidgetTester tester) async { + int count = 0; + await tester.pumpWidget( + TestApp( + textDirection: TextDirection.ltr, + child: Material( + child: RepaintBoundary( + child: PopupMenuButton( + child: const Text('button'), + itemBuilder: (BuildContext context) { + return >[ + CheckedPopupMenuItem( + onTap: () { + count += 1; + }, + value: 'item1', + child: const Text('Item with onTap'), + ), + const CheckedPopupMenuItem( + value: 'item2', + child: Text('Item without onTap'), + ), + ]; + }, + ), + ), + ), + ), + ); + + // Tap a checked menu item with onTap. + await tester.tap(find.text('button')); + await tester.pumpAndSettle(); + await tester.tap(find.widgetWithText(CheckedPopupMenuItem, 'Item with onTap')); + await tester.pumpAndSettle(); + expect(count, 1); + + // Tap a checked menu item without onTap. + await tester.tap(find.text('button')); + await tester.pumpAndSettle(); + await tester.tap(find.widgetWithText(CheckedPopupMenuItem, 'Item without onTap')); + await tester.pumpAndSettle(); + expect(count, 1); + }); } class TestApp extends StatelessWidget { From cd9a257d741f4593190f56f594cb3441f076aa9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20=C4=B0mdat?= <70351342+burakJs@users.noreply.github.com> Date: Wed, 6 Sep 2023 21:54:45 +0300 Subject: [PATCH 1102/1547] Fix `subtitleTextStyle.color` isn't applied to the `ListTile.subtitle` in Material 2 (#133422) The difference between header text style and subtitle text style and the reason why it doesn't work is the code difference below. If we make the subtitle text style the same as the title text style it will work

    Title Text Style ### All Code ```dart TextStyle titleStyle = titleTextStyle ?? tileTheme.titleTextStyle ?? defaults.titleTextStyle!; final Color? titleColor = effectiveColor; titleStyle = titleStyle.copyWith( color: titleColor, fontSize: _isDenseLayout(theme, tileTheme) ? 13.0 : null, ); final Widget titleText = AnimatedDefaultTextStyle( style: titleStyle, duration: kThemeChangeDuration, child: title ?? const SizedBox(), ); ``` ## Different Code Section ```dart final Color? titleColor = effectiveColor; ```
    Subtitle Text Style ## All Code ```dart subtitleStyle = subtitleTextStyle ?? tileTheme.subtitleTextStyle ?? defaults.subtitleTextStyle!; final Color? subtitleColor = effectiveColor ?? (theme.useMaterial3 ? null : theme.textTheme.bodySmall!.color); subtitleStyle = subtitleStyle.copyWith( color: subtitleColor, fontSize: _isDenseLayout(theme, tileTheme) ? 12.0 : null, ); subtitleText = AnimatedDefaultTextStyle( style: subtitleStyle, duration: kThemeChangeDuration, child: subtitle!, ); ``` ## Different Code Section ```dart final Color? subtitleColor = effectiveColor ?? (theme.useMaterial3 ? null : theme.textTheme.bodySmall!.color); ``` ### Description for code - The value `theme.textTheme.bodySmall!.color` is given because the `effectiveColor` value is `null` and the `theme.useMaterial3` value is `false`
    Problem solved code ## All Code ```dart subtitleStyle = subtitleTextStyle ?? tileTheme.subtitleTextStyle ?? defaults.subtitleTextStyle!; final Color? subtitleColor = effectiveColor; subtitleStyle = subtitleStyle.copyWith( color: subtitleColor, fontSize: _isDenseLayout(theme, tileTheme) ? 12.0 : null, ); subtitleText = AnimatedDefaultTextStyle( style: subtitleStyle, duration: kThemeChangeDuration, child: subtitle!, ); ```
    Screenshot of the result after making the necessary change
    #133412 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../flutter/lib/src/material/list_tile.dart | 6 +- .../test/material/list_tile_theme_test.dart | 229 ++++++++++++++++-- 2 files changed, 207 insertions(+), 28 deletions(-) diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart index 074862beb3c68..741787207d5de 100644 --- a/packages/flutter/lib/src/material/list_tile.dart +++ b/packages/flutter/lib/src/material/list_tile.dart @@ -801,8 +801,7 @@ class ListTile extends StatelessWidget { subtitleStyle = subtitleTextStyle ?? tileTheme.subtitleTextStyle ?? defaults.subtitleTextStyle!; - final Color? subtitleColor = effectiveColor - ?? (theme.useMaterial3 ? null : theme.textTheme.bodySmall!.color); + final Color? subtitleColor = effectiveColor; subtitleStyle = subtitleStyle.copyWith( color: subtitleColor, fontSize: _isDenseLayout(theme, tileTheme) ? 12.0 : null, @@ -1533,7 +1532,8 @@ class _LisTileDefaultsM2 extends ListTileThemeData { } @override - TextStyle? get subtitleTextStyle => _textTheme.bodyMedium; + TextStyle? get subtitleTextStyle => _textTheme.bodyMedium! + .copyWith(color: _textTheme.bodySmall!.color); @override TextStyle? get leadingAndTrailingTextStyle => _textTheme.bodyMedium; diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index 8b92ae3ab60ee..f779e489b93fd 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -393,14 +393,30 @@ void main() { }); testWidgetsWithLeakTracking( - "ListTile respects ListTileTheme's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle", + "Material3 - ListTile respects ListTileTheme's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle", (WidgetTester tester) async { + const TextStyle titleTextStyle = TextStyle( + fontSize: 23.0, + color: Color(0xffff0000), + fontStyle: FontStyle.italic, + ); + const TextStyle subtitleTextStyle = TextStyle( + fontSize: 20.0, + color: Color(0xff00ff00), + fontStyle: FontStyle.italic, + ); + const TextStyle leadingAndTrailingTextStyle = TextStyle( + fontSize: 18.0, + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + final ThemeData theme = ThemeData( useMaterial3: true, listTileTheme: const ListTileThemeData( - titleTextStyle: TextStyle(fontSize: 20.0), - subtitleTextStyle: TextStyle(fontSize: 17.5), - leadingAndTrailingTextStyle: TextStyle(fontSize: 15.0), + titleTextStyle: titleTextStyle, + subtitleTextStyle: subtitleTextStyle, + leadingAndTrailingTextStyle: leadingAndTrailingTextStyle, ), ); @@ -426,31 +442,51 @@ void main() { await tester.pumpWidget(buildFrame()); final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); - expect(leading.text.style!.fontSize, 15.0); + expect(leading.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(leading.text.style!.color, leadingAndTrailingTextStyle.color); + expect(leading.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); final RenderParagraph title = _getTextRenderObject(tester, 'title'); - expect(title.text.style!.fontSize, 20.0); + expect(title.text.style!.fontSize, titleTextStyle.fontSize); + expect(title.text.style!.color, titleTextStyle.color); + expect(title.text.style!.fontStyle, titleTextStyle.fontStyle); final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); - expect(subtitle.text.style!.fontSize, 17.5); + expect(subtitle.text.style!.fontSize, subtitleTextStyle.fontSize); + expect(subtitle.text.style!.color, subtitleTextStyle.color); + expect(subtitle.text.style!.fontStyle, subtitleTextStyle.fontStyle); final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); - expect(trailing.text.style!.fontSize, 15.0); + expect(trailing.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(trailing.text.style!.color, leadingAndTrailingTextStyle.color); + expect(trailing.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); }); testWidgetsWithLeakTracking( - "ListTile's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle are overridden by ListTile properties", + "Material2 - ListTile respects ListTileTheme's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle", (WidgetTester tester) async { + const TextStyle titleTextStyle = TextStyle( + fontSize: 23.0, + color: Color(0xffff0000), + fontStyle: FontStyle.italic, + ); + const TextStyle subtitleTextStyle = TextStyle( + fontSize: 20.0, + color: Color(0xff00ff00), + fontStyle: FontStyle.italic, + ); + const TextStyle leadingAndTrailingTextStyle = TextStyle( + fontSize: 18.0, + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + final ThemeData theme = ThemeData( - useMaterial3: true, - listTileTheme: const ListTileThemeData( - titleTextStyle: TextStyle(fontSize: 20.0), - subtitleTextStyle: TextStyle(fontSize: 17.5), - leadingAndTrailingTextStyle: TextStyle(fontSize: 15.0), + useMaterial3: false, + listTileTheme: const ListTileThemeData( + titleTextStyle: titleTextStyle, + subtitleTextStyle: subtitleTextStyle, + leadingAndTrailingTextStyle: leadingAndTrailingTextStyle, ), ); - const TextStyle titleTextStyle = TextStyle(fontSize: 23.0); - const TextStyle subtitleTextStyle = TextStyle(fontSize: 20.0); - const TextStyle leadingAndTrailingTextStyle = TextStyle(fontSize: 18.0); - Widget buildFrame() { return MaterialApp( theme: theme, @@ -459,9 +495,6 @@ void main() { child: Builder( builder: (BuildContext context) { return const ListTile( - titleTextStyle: titleTextStyle, - subtitleTextStyle: subtitleTextStyle, - leadingAndTrailingTextStyle: leadingAndTrailingTextStyle, leading: TestText('leading'), title: TestText('title'), subtitle: TestText('subtitle'), @@ -476,13 +509,159 @@ void main() { await tester.pumpWidget(buildFrame()); final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); - expect(leading.text.style!.fontSize, 18.0); + expect(leading.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(leading.text.style!.color, leadingAndTrailingTextStyle.color); + expect(leading.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); final RenderParagraph title = _getTextRenderObject(tester, 'title'); - expect(title.text.style!.fontSize, 23.0); + expect(title.text.style!.fontSize, titleTextStyle.fontSize); + expect(title.text.style!.color, titleTextStyle.color); + expect(title.text.style!.fontStyle, titleTextStyle.fontStyle); final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); - expect(subtitle.text.style!.fontSize, 20.0); + expect(subtitle.text.style!.fontSize, subtitleTextStyle.fontSize); + expect(subtitle.text.style!.color, subtitleTextStyle.color); + expect(subtitle.text.style!.fontStyle, subtitleTextStyle.fontStyle); final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); - expect(trailing.text.style!.fontSize, 18.0); + expect(trailing.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(trailing.text.style!.color, leadingAndTrailingTextStyle.color); + expect(trailing.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); + }); + + testWidgetsWithLeakTracking( + "Material3 - ListTile's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle are overridden by ListTile properties", + (WidgetTester tester) async { + final ThemeData theme = ThemeData( + useMaterial3: true, + listTileTheme: const ListTileThemeData( + titleTextStyle: TextStyle(fontSize: 20.0), + subtitleTextStyle: TextStyle(fontSize: 17.5), + leadingAndTrailingTextStyle: TextStyle(fontSize: 15.0), + ), + ); + const TextStyle titleTextStyle = TextStyle( + fontSize: 23.0, + color: Color(0xffff0000), + fontStyle: FontStyle.italic, + ); + const TextStyle subtitleTextStyle = TextStyle( + fontSize: 20.0, + color: Color(0xff00ff00), + fontStyle: FontStyle.italic, + ); + const TextStyle leadingAndTrailingTextStyle = TextStyle( + fontSize: 18.0, + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + + Widget buildFrame() { + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return const ListTile( + titleTextStyle: titleTextStyle, + subtitleTextStyle: subtitleTextStyle, + leadingAndTrailingTextStyle: leadingAndTrailingTextStyle, + leading: TestText('leading'), + title: TestText('title'), + subtitle: TestText('subtitle'), + trailing: TestText('trailing'), + ); + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame()); + final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); + expect(leading.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(leading.text.style!.color, leadingAndTrailingTextStyle.color); + expect(leading.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); + final RenderParagraph title = _getTextRenderObject(tester, 'title'); + expect(title.text.style!.fontSize, titleTextStyle.fontSize); + expect(title.text.style!.color, titleTextStyle.color); + expect(title.text.style!.fontStyle, titleTextStyle.fontStyle); + final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); + expect(subtitle.text.style!.fontSize, subtitleTextStyle.fontSize); + expect(subtitle.text.style!.color, subtitleTextStyle.color); + expect(subtitle.text.style!.fontStyle, subtitleTextStyle.fontStyle); + final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); + expect(trailing.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(trailing.text.style!.color, leadingAndTrailingTextStyle.color); + expect(trailing.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); + }); + + testWidgetsWithLeakTracking( + "Material2 - ListTile's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle are overridden by ListTile properties", + (WidgetTester tester) async { + final ThemeData theme = ThemeData( + useMaterial3: false, + listTileTheme: const ListTileThemeData( + titleTextStyle: TextStyle(fontSize: 20.0), + subtitleTextStyle: TextStyle(fontSize: 17.5), + leadingAndTrailingTextStyle: TextStyle(fontSize: 15.0), + ), + ); + const TextStyle titleTextStyle = TextStyle( + fontSize: 23.0, + color: Color(0xffff0000), + fontStyle: FontStyle.italic, + ); + const TextStyle subtitleTextStyle = TextStyle( + fontSize: 20.0, + color: Color(0xff00ff00), + fontStyle: FontStyle.italic, + ); + const TextStyle leadingAndTrailingTextStyle = TextStyle( + fontSize: 18.0, + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + + Widget buildFrame() { + return MaterialApp( + theme: theme, + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return const ListTile( + titleTextStyle: titleTextStyle, + subtitleTextStyle: subtitleTextStyle, + leadingAndTrailingTextStyle: leadingAndTrailingTextStyle, + leading: TestText('leading'), + title: TestText('title'), + subtitle: TestText('subtitle'), + trailing: TestText('trailing'), + ); + }, + ), + ), + ), + ); + } + + await tester.pumpWidget(buildFrame()); + final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); + expect(leading.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(leading.text.style!.color, leadingAndTrailingTextStyle.color); + expect(leading.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); + final RenderParagraph title = _getTextRenderObject(tester, 'title'); + expect(title.text.style!.fontSize, titleTextStyle.fontSize); + expect(title.text.style!.color, titleTextStyle.color); + expect(title.text.style!.fontStyle, titleTextStyle.fontStyle); + final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); + expect(subtitle.text.style!.fontSize, subtitleTextStyle.fontSize); + expect(subtitle.text.style!.color, subtitleTextStyle.color); + expect(subtitle.text.style!.fontStyle, subtitleTextStyle.fontStyle); + final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); + expect(trailing.text.style!.fontSize, leadingAndTrailingTextStyle.fontSize); + expect(trailing.text.style!.color, leadingAndTrailingTextStyle.color); + expect(trailing.text.style!.fontStyle, leadingAndTrailingTextStyle.fontStyle); }); testWidgetsWithLeakTracking("ListTile respects ListTileTheme's tileColor & selectedTileColor", (WidgetTester tester) async { From d792c664a26f866ecac63cadf803f5dc82101732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 6 Sep 2023 11:59:20 -0700 Subject: [PATCH 1103/1547] [Windows Arm64] Also use Windows 11 for Devicelab tests (#134082) Currently, the Windows Arm64 tests try to run on Windows 10 devices. However, [all Windows Arm64 devices use Windows 11](https://chromium-swarm.appspot.com/botlist?c=id&c=task&c=os&c=status&d=asc&f=cpu%3Aarm64&f=os%3AWindows-11&f=pool%3Aluci.flutter.staging&s=id) which result in the Windows Arm64 tests not running. This updates the configuration to accept both Windows 10 and 11 (ideally the tests would run on both OSes). ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 67977d1b39884..82ae7f830f3a9 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -203,7 +203,7 @@ platform_properties: [ {"dependency": "certs", "version": "version:9563bb"} ] - os: Windows-10 + os: Windows device_type: none cpu: arm64 windows_android: @@ -4996,7 +4996,7 @@ targets: - name: Windows_arm64 hello_world_win_desktop__compile recipe: devicelab/devicelab_drone - bringup: true + bringup: true # https://github.com/flutter/flutter/issues/134083 presubmit: false timeout: 60 properties: From 4184a1d29d0fa8b68ec550be07c97ee4aa4b288f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 15:59:24 -0400 Subject: [PATCH 1104/1547] Roll Flutter Engine from 839051596b1d to b04c2a378302 (7 revisions) (#134158) https://github.com/flutter/engine/compare/839051596b1d...b04c2a378302 2023-09-06 nshahan@google.com Update deps on DDC build targets (flutter/engine#45404) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 99bcee22f87d to 487cd9240571 (1 revision) (flutter/engine#45500) 2023-09-06 30870216+gaaclarke@users.noreply.github.com Remove android API 26 bump for validation layers (flutter/engine#45468) 2023-09-06 zanderso@users.noreply.github.com Roll buildroot (flutter/engine#45480) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 4468ef79f3d7 to 99bcee22f87d (5 revisions) (flutter/engine#45495) 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 55d3636b66e0 to 1b8ab5382ff6 (1 revision) (flutter/engine#45494) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 596a1f192faa to 4468ef79f3d7 (2 revisions) (flutter/engine#45493) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 618b4fb22b172..0424966703795 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -839051596b1d888c6792c37b71761daa3d9ec10b +b04c2a378302ae9800720620fc1b3786ca583240 From 420aa9f7f1d2a828e8b678e62ec1e11d75738da0 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 6 Sep 2023 13:10:56 -0700 Subject: [PATCH 1105/1547] Clean the fixed TODOs. (#133859) https://github.com/flutter/flutter/issues/130354 is fixed, but the test still fails, so converted it back to 'testWidgets' to investigate later. --- .../test/material/date_range_picker_test.dart | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/flutter/test/material/date_range_picker_test.dart b/packages/flutter/test/material/date_range_picker_test.dart index 14f7b2e8adb7d..aa57e709cc9a9 100644 --- a/packages/flutter/test/material/date_range_picker_test.dart +++ b/packages/flutter/test/material/date_range_picker_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'feedback_tester.dart'; void main() { @@ -252,19 +251,12 @@ void main() { await tester.pumpAndSettle(); }); - testWidgetsWithLeakTracking('landscape', (WidgetTester tester) async { + testWidgets('landscape', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizeLandscape); expect(tester.widget(find.text('Jan 15 – Jan 25, 2016')).style?.fontSize, 24); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); - }, - // TODO(polina-c): remove after resolving - // https://github.com/flutter/flutter/issues/130354 - leakTrackingTestConfig: const LeakTrackingTestConfig( - allowAllNotGCed: true, - allowAllNotDisposed: true, - ), - ); + }); }); testWidgets('Save and help text is used', (WidgetTester tester) async { From 41ebf282d423f005445030c0a63d75c2f9038c9a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 16:44:04 -0400 Subject: [PATCH 1106/1547] Roll Flutter Engine from b04c2a378302 to 2c69d05dfafb (3 revisions) (#134164) https://github.com/flutter/engine/compare/b04c2a378302...2c69d05dfafb 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 1b8ab5382ff6 to 7b0bb0f6e785 (2 revisions) (flutter/engine#45503) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 487cd9240571 to 59e54ccf25a4 (1 revision) (flutter/engine#45504) 2023-09-06 zanderso@users.noreply.github.com Roll clang to 576b184d6e3b633f51b908b61ebd281d2ecbf66f (flutter/engine#45499) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0424966703795..172138cfdb4cb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b04c2a378302ae9800720620fc1b3786ca583240 +2c69d05dfafbbedca38c48238e05bbb26c462b69 From 1f0730e67af4cfbe7ad76bbfd3cc0267ffe074cb Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Wed, 6 Sep 2023 15:07:07 -0700 Subject: [PATCH 1107/1547] DraggableScrollableActuator should dispose notifier. (#133917) --- .../widgets/draggable_scrollable_sheet.dart | 20 +++++++++++++++---- .../floating_action_button_location_test.dart | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 8b2012f903a49..9c229776964e2 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -1015,12 +1015,12 @@ class _DraggableScrollableSheetScrollPosition extends ScrollPositionWithSingleCo /// in library users' code). Generally, it's easier to control the sheet /// directly by creating a controller and passing the controller to the sheet in /// its constructor (see [DraggableScrollableSheet.controller]). -class DraggableScrollableActuator extends StatelessWidget { +class DraggableScrollableActuator extends StatefulWidget { /// Creates a widget that can notify descendent [DraggableScrollableSheet]s /// to reset to their initial position. /// /// The [child] parameter is required. - DraggableScrollableActuator({ + const DraggableScrollableActuator({ super.key, required this.child, }); @@ -1031,7 +1031,6 @@ class DraggableScrollableActuator extends StatelessWidget { /// Must not be null. final Widget child; - final _ResetNotifier _notifier = _ResetNotifier(); /// Notifies any descendant [DraggableScrollableSheet] that it should reset /// to its initial position. @@ -1047,9 +1046,22 @@ class DraggableScrollableActuator extends StatelessWidget { return notifier._sendReset(); } + @override + State createState() => _DraggableScrollableActuatorState(); +} + +class _DraggableScrollableActuatorState extends State { + final _ResetNotifier _notifier = _ResetNotifier(); + @override Widget build(BuildContext context) { - return _InheritedResetNotifier(notifier: _notifier, child: child); + return _InheritedResetNotifier(notifier: _notifier, child: widget.child); + } + + @override + void dispose() { + _notifier.dispose(); + super.dispose(); } } diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index 5b87324bc5a73..b43449f2435d4 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -415,7 +415,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _floatOffsetY)); }); - testWidgets('centerFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('centerFloat', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.centerFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _floatOffsetY)); @@ -1037,7 +1037,7 @@ void main() { ); }); - testWidgets('centerFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('centerFloat', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(372.0, 478.0, 428.0, 534.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(372.0, 422.0, 428.0, 478.0); From f0394437b0d674bc975bd846614d6112467067c6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Wed, 6 Sep 2023 18:07:09 -0400 Subject: [PATCH 1108/1547] Roll Flutter Engine from 2c69d05dfafb to fa14d337449b (6 revisions) (#134169) https://github.com/flutter/engine/compare/2c69d05dfafb...fa14d337449b 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from e5ed4ffaaaa4 to a274609c442c (2 revisions) (flutter/engine#45510) 2023-09-06 zanderso@users.noreply.github.com Roll Fuchsia with license script fix (flutter/engine#45498) 2023-09-06 dkwingsmt@users.noreply.github.com Enforce the rule of calling `FlutterView.Render` (flutter/engine#45300) 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 7b0bb0f6e785 to 00daa451320c (1 revision) (flutter/engine#45507) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 59e54ccf25a4 to e5ed4ffaaaa4 (4 revisions) (flutter/engine#45506) 2023-09-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from dFe-t1SosqZwU5lZR... to hHwU6r12A0sy5Bq-0... (flutter/engine#45505) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from z9uQ0mXwjKFQ to 8dgICHnG28wN fuchsia/sdk/core/mac-amd64 from dFe-t1SosqZw to hHwU6r12A0sy If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 172138cfdb4cb..afb05bba3b4f6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2c69d05dfafbbedca38c48238e05bbb26c462b69 +fa14d337449b1736dfec71cdc5f916de353008ef diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 506a90e6b3e94..19e27d3c83f66 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -z9uQ0mXwjKFQF05XlBv-X8Em1QvkefyGcIJWrSZEm-sC +8dgICHnG28wNHzoz33qFF_nQu52I3PVTfNbXzV6PWTQC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ad5b0387d9620..6cd711c3ea435 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -dFe-t1SosqZwU5lZRJfhlmiQNzNSKCiUmS_h3uirntsC +hHwU6r12A0sy5Bq-0EiKQzK-Mv4l3N9k7MroYgVJExQC From cf1968aa666e694aa60670a32b7cee556edbe1e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 22:18:54 +0000 Subject: [PATCH 1109/1547] Bump actions/upload-artifact from 3.1.2 to 3.1.3 (#134173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.2 to 3.1.3.
    Release notes

    Sourced from actions/upload-artifact's releases.

    v3.1.3

    What's Changed

    Full Changelog: https://github.com/actions/upload-artifact/compare/v3...v3.1.3

    Commits

    [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=3.1.2&new-version=3.1.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
    Dependabot commands and options
    You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 7da93dccfb729..74e214d4e84ca 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -43,7 +43,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 with: name: SARIF file path: results.sarif From e8ff2aed31692142fb3494e2ee8b5b11d3e28693 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Wed, 6 Sep 2023 18:01:16 -0700 Subject: [PATCH 1110/1547] Revert "Roll Flutter Engine from 2c69d05dfafb to fa14d337449b (6 revisions)" (#134183) Reverts flutter/flutter#134169 windows_startup_test is failing following the roll --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index afb05bba3b4f6..172138cfdb4cb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fa14d337449b1736dfec71cdc5f916de353008ef +2c69d05dfafbbedca38c48238e05bbb26c462b69 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 19e27d3c83f66..506a90e6b3e94 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -8dgICHnG28wNHzoz33qFF_nQu52I3PVTfNbXzV6PWTQC +z9uQ0mXwjKFQF05XlBv-X8Em1QvkefyGcIJWrSZEm-sC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 6cd711c3ea435..ad5b0387d9620 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -hHwU6r12A0sy5Bq-0EiKQzK-Mv4l3N9k7MroYgVJExQC +dFe-t1SosqZwU5lZRJfhlmiQNzNSKCiUmS_h3uirntsC From 14ced7599f35ffc377bfffdba72e0b7a49f3fd1a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 7 Sep 2023 00:04:33 -0400 Subject: [PATCH 1111/1547] Manual roll Flutter Engine from 2c69d05dfafb to 75437a3bd002 (15 revisions) (#134188) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/2c69d05dfafb...75437a3bd002 2023-09-07 zanderso@users.noreply.github.com Revert "Enforce the rule of calling `FlutterView.Render`" (flutter/engine#45525) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 2b76d1113497 to 9e86d3f6239a (1 revision) (flutter/engine#45521) 2023-09-07 bdero@google.com [Impeller] Gaussian blur: Remove the current blur style implementation. (flutter/engine#45520) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 9c9757c5d17d to 2b76d1113497 (2 revisions) (flutter/engine#45518) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 0039caadd635 to 9c9757c5d17d (1 revision) (flutter/engine#45516) 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 00daa451320c to 60b56591dee5 (1 revision) (flutter/engine#45517) 2023-09-06 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 8dgICHnG28wNHzoz3... to SCoDb2m_zQDLrMhwT... (flutter/engine#45514) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from a274609c442c to 0039caadd635 (2 revisions) (flutter/engine#45513) 2023-09-06 stuartmorgan@google.com Add macOS support for plugin value publishing (flutter/engine#45502) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from e5ed4ffaaaa4 to a274609c442c (2 revisions) (flutter/engine#45510) 2023-09-06 zanderso@users.noreply.github.com Roll Fuchsia with license script fix (flutter/engine#45498) 2023-09-06 dkwingsmt@users.noreply.github.com Enforce the rule of calling `FlutterView.Render` (flutter/engine#45300) 2023-09-06 skia-flutter-autoroll@skia.org Roll ANGLE from 7b0bb0f6e785 to 00daa451320c (1 revision) (flutter/engine#45507) 2023-09-06 skia-flutter-autoroll@skia.org Roll Skia from 59e54ccf25a4 to e5ed4ffaaaa4 (4 revisions) (flutter/engine#45506) 2023-09-06 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from dFe-t1SosqZwU5lZR... to hHwU6r12A0sy5Bq-0... (flutter/engine#45505) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from z9uQ0mXwjKFQ to SCoDb2m_zQDL fuchsia/sdk/core/mac-amd64 from dFe-t1SosqZw to hHwU6r12A0sy If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 172138cfdb4cb..6cfddfa6e46b3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2c69d05dfafbbedca38c48238e05bbb26c462b69 +75437a3bd0025e833c33498b8e0c5013b213f726 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 506a90e6b3e94..6c8226582dda9 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -z9uQ0mXwjKFQF05XlBv-X8Em1QvkefyGcIJWrSZEm-sC +SCoDb2m_zQDLrMhwTwp5WCNL_BjAwYCPHfEbuLUUIZgC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ad5b0387d9620..6cd711c3ea435 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -dFe-t1SosqZwU5lZRJfhlmiQNzNSKCiUmS_h3uirntsC +hHwU6r12A0sy5Bq-0EiKQzK-Mv4l3N9k7MroYgVJExQC From 83c24274bbc2eabd3be250367c7c529fd81dfe96 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 7 Sep 2023 01:20:06 -0400 Subject: [PATCH 1112/1547] Roll Flutter Engine from 75437a3bd002 to 187c5b3c5f71 (1 revision) (#134193) https://github.com/flutter/engine/compare/75437a3bd002...187c5b3c5f71 2023-09-07 bdero@google.com [Impeller] Gaussian blur: Remove lingering BlurStyle vertex data/uniforms. (flutter/engine#45524) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6cfddfa6e46b3..f4c96b587aa0d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -75437a3bd0025e833c33498b8e0c5013b213f726 +187c5b3c5f71d14c38608ee18b192eb3e09c15ee From ded8b8e31cce3b0f3a11f2f3393dd250d0224860 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 7 Sep 2023 10:58:00 +0300 Subject: [PATCH 1113/1547] Reland "Fix `Chip.shape`'s side is not used when provided in Material 3" (#133856) fixes [Chip border side color not working in Material3](https://github.com/flutter/flutter/issues/132922) Relands https://github.com/flutter/flutter/pull/132941 with an updated fix and a regression test.
    expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData(useMaterial3: true), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Chips'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ const RawChip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), ), side: BorderSide(color: Colors.red), label: Text('RawChip'), ), const Chip( shape: RoundedRectangleBorder( side: BorderSide(color: Colors.amber), ), side: BorderSide(color: Colors.red), label: Text('Chip'), ), ActionChip( shape: const RoundedRectangleBorder( side: BorderSide(color: Colors.amber), ), side: const BorderSide(color: Colors.red), label: const Text('ActionChip'), onPressed: () {}, ), FilterChip( shape: const RoundedRectangleBorder( side: BorderSide(color: Colors.amber), ), side: const BorderSide(color: Colors.red), label: const Text('FilterChip'), onSelected: (value) {}, ), ChoiceChip( shape: const RoundedRectangleBorder( side: BorderSide(color: Colors.amber), ), side: const BorderSide(color: Colors.red), label: const Text('ChoiceChip'), selected: false, onSelected: (value) {}, ), InputChip( shape: const RoundedRectangleBorder( side: BorderSide(color: Colors.amber), ), side: const BorderSide(color: Colors.red), label: const Text('InputChip'), onSelected: (value) {}, ), ], ), ), ); } } ```
    --- packages/flutter/lib/src/material/chip.dart | 14 +++- packages/flutter/test/material/chip_test.dart | 79 +++++++++++++++++++ .../test/material/chip_theme_test.dart | 58 ++++++++++++++ 3 files changed, 148 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 3e1eb6d7bacf1..b3bc897845a78 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -992,13 +992,21 @@ class _RawChipState extends State with MaterialStateMixin, TickerProvid OutlinedBorder _getShape(ThemeData theme, ChipThemeData chipTheme, ChipThemeData chipDefaults) { final BorderSide? resolvedSide = MaterialStateProperty.resolveAs(widget.side, materialStates) - ?? MaterialStateProperty.resolveAs(chipTheme.side, materialStates) - ?? MaterialStateProperty.resolveAs(chipDefaults.side, materialStates); + ?? MaterialStateProperty.resolveAs(chipTheme.side, materialStates); final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs(widget.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipTheme.shape, materialStates) ?? MaterialStateProperty.resolveAs(chipDefaults.shape, materialStates) + // TODO(tahatesser): Remove this fallback when Material 2 is deprecated. ?? const StadiumBorder(); - return resolvedShape.copyWith(side: resolvedSide); + // If the side is provided, shape uses the provided side. + if (resolvedSide != null) { + return resolvedShape.copyWith(side: resolvedSide); + } + // If the side is not provided and the shape's side is not [BorderSide.none], + // then the shape's side is used. Otherwise, the default side is used. + return resolvedShape.side != BorderSide.none + ? resolvedShape + : resolvedShape.copyWith(side: chipDefaults.side); } Color? resolveColor({ diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index d098936aa14e3..0d8c0576409f4 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -3503,6 +3503,85 @@ void main() { expect(calledDelete, isTrue); }); + // This is a regression test for https://github.com/flutter/flutter/pull/133615. + testWidgets('Material3 - Custom shape without provided side uses default side', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Material( + child: Center( + child: RawChip( + // No side provided. + shape: StadiumBorder(), + label: Text('RawChip'), + ), + ), + ), + ), + ); + + // Chip should have the default side. + expect( + getMaterial(tester).shape, + StadiumBorder(side: BorderSide(color: theme.colorScheme.outline)), + ); + }); + + testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { + Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: RawChip( + shape: shape, + side: side, + label: const Text('RawChip'), + ), + ), + ), + ); + } + + // Test [RawChip.shape] with a side. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + )), + ); + + // Chip should have the provided shape and the side from [RawChip.shape]. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + + // Test [RawChip.shape] with a side and [RawChip.side]. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + side: const BorderSide(color: Color(0xfffff000))), + ); + await tester.pumpAndSettle(); + + // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. + // [RawChip.shape]'s side should be ignored. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffff000)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests diff --git a/packages/flutter/test/material/chip_theme_test.dart b/packages/flutter/test/material/chip_theme_test.dart index 2303b56478cd3..4ff0c5c31773e 100644 --- a/packages/flutter/test/material/chip_theme_test.dart +++ b/packages/flutter/test/material/chip_theme_test.dart @@ -928,6 +928,64 @@ void main() { )), ); }); + + testWidgets("Material3 - RawChip.shape's side is used when provided", (WidgetTester tester) async { + Widget buildChip({ OutlinedBorder? shape, BorderSide? side }) { + return MaterialApp( + theme: ThemeData( + useMaterial3: true, + chipTheme: ChipThemeData( + shape: shape, + side: side, + ), + ), + home: const Material( + child: Center( + child: RawChip( + label: Text('RawChip'), + ), + ), + ), + ); + } + + // Test [RawChip.shape] with a side. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + )), + ); + + // Chip should have the provided shape and the side from [RawChip.shape]. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + + // Test [RawChip.shape] with a side and [RawChip.side]. + await tester.pumpWidget(buildChip( + shape: const RoundedRectangleBorder( + side: BorderSide(color: Color(0xffff00ff)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + side: const BorderSide(color: Color(0xfffff000))), + ); + await tester.pumpAndSettle(); + + // Chip use shape from [RawChip.shape] and the side from [RawChip.side]. + // [RawChip.shape]'s side should be ignored. + expect( + getMaterial(tester).shape, + const RoundedRectangleBorder( + side: BorderSide(color: Color(0xfffff000)), + borderRadius: BorderRadius.all(Radius.circular(7.0)), + ), + ); + }); } class _MaterialStateOutlinedBorder extends StadiumBorder implements MaterialStateOutlinedBorder { From 3b0359a024235668ec1abaeb089d1a356d71138f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 7 Sep 2023 04:19:50 -0400 Subject: [PATCH 1114/1547] Roll Flutter Engine from 187c5b3c5f71 to d864ae68db3c (2 revisions) (#134199) https://github.com/flutter/engine/compare/187c5b3c5f71...d864ae68db3c 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 5b7a07a6356f to c99601816d84 (1 revision) (flutter/engine#45528) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 9e86d3f6239a to 5b7a07a6356f (1 revision) (flutter/engine#45527) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f4c96b587aa0d..b670ad5ac0066 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -187c5b3c5f71d14c38608ee18b192eb3e09c15ee +d864ae68db3c0491cd7f55119d0d9c79c9ff153a From 75797a8a7e2b309891bccaede7f8b157a076d45b Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 7 Sep 2023 11:55:53 +0300 Subject: [PATCH 1115/1547] Fix `DataTable`'s `headingTextStyle` & `dataTextStyle` are not merged with default text style (#134138) fixes [Inconsistent text color on DataTable in different platforms](https://github.com/flutter/flutter/issues/114470) ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [DataTable]. void main() => runApp(const DataTableExampleApp()); class DataTableExampleApp extends StatelessWidget { const DataTableExampleApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( themeMode: ThemeMode.dark, theme: ThemeData(), darkTheme: ThemeData.dark(), home: Scaffold( appBar: AppBar(title: const Text('DataTable Sample')), body: const DataTableExample(), ), ); } } class DataTableExample extends StatelessWidget { const DataTableExample({super.key}); @override Widget build(BuildContext context) { return DataTable( headingTextStyle: const TextStyle(), dataTextStyle: const TextStyle(), columns: const [ DataColumn( label: Expanded( child: Text( 'Name', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), DataColumn( label: Expanded( child: Text( 'Age', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), DataColumn( label: Expanded( child: Text( 'Role', style: TextStyle(fontStyle: FontStyle.italic), ), ), ), ], rows: const [ DataRow( cells: [ DataCell(Text('Sarah')), DataCell(Text('19')), DataCell(Text('Student')), ], ), DataRow( cells: [ DataCell(Text('Janine')), DataCell(Text('43')), DataCell(Text('Professor')), ], ), DataRow( cells: [ DataCell(Text('William')), DataCell(Text('27')), DataCell(Text('Associate Professor')), ], ), ], ); } } ```
    ### Before | Desktop | Mobile | | --------------- | --------------- | | | | ### After | Desktop | Mobile | | --------------- | --------------- | | | | --- .../flutter/lib/src/material/data_table.dart | 8 ++-- .../test/material/data_table_test.dart | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index a7ed565f3a159..fe03482e27f87 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -857,7 +857,7 @@ class DataTable extends StatelessWidget { height: effectiveHeadingRowHeight, alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart, child: AnimatedDefaultTextStyle( - style: effectiveHeadingTextStyle, + style: DefaultTextStyle.of(context).style.merge(effectiveHeadingTextStyle), softWrap: false, duration: _sortArrowAnimationDuration, child: label, @@ -926,9 +926,9 @@ class DataTable extends StatelessWidget { constraints: BoxConstraints(minHeight: effectiveDataRowMinHeight, maxHeight: effectiveDataRowMaxHeight), alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart, child: DefaultTextStyle( - style: effectiveDataTextStyle.copyWith( - color: placeholder ? effectiveDataTextStyle.color!.withOpacity(0.6) : null, - ), + style: DefaultTextStyle.of(context).style + .merge(effectiveDataTextStyle) + .copyWith(color: placeholder ? effectiveDataTextStyle.color!.withOpacity(0.6) : null), child: DropdownButtonHideUnderline(child: label), ), ); diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index fed5e1a04dac7..fc738b73a63e3 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -2279,4 +2279,46 @@ void main() { // Test that cursor is updated for the row. expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.copy); }); + + // This is a regression test for https://github.com/flutter/flutter/issues/114470. + testWidgetsWithLeakTracking('DataTable text styles are merged with default text style', (WidgetTester tester) async { + late DefaultTextStyle defaultTextStyle; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + defaultTextStyle = DefaultTextStyle.of(context); + return DataTable( + headingTextStyle: const TextStyle(), + dataTextStyle: const TextStyle(), + columns: const [ + DataColumn(label: Text('Header 1')), + DataColumn(label: Text('Header 2')), + ], + rows: const [ + DataRow( + cells: [ + DataCell(Text('Data 1')), + DataCell(Text('Data 2')), + ], + ), + ], + ); + } + ), + ), + ), + ); + + final TextStyle? headingTextStyle = _getTextRenderObject(tester, 'Header 1').text.style; + expect(headingTextStyle, defaultTextStyle.style); + + final TextStyle? dataTextStyle = _getTextRenderObject(tester, 'Data 1').text.style; + expect(dataTextStyle, defaultTextStyle.style); + }); +} + +RenderParagraph _getTextRenderObject(WidgetTester tester, String text) { + return tester.renderObject(find.text(text)); } From f5355af4a3e584a75f4e1303528c5abd7d659b87 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 7 Sep 2023 12:19:05 +0300 Subject: [PATCH 1116/1547] Fix `TabBar` doesn't use `labelStyle` & `unselectedLabelStyle` color (#133989) Fixes [TabBar labelStyle.color and unselectedLabelStyle.color does not take effect](https://github.com/flutter/flutter/issues/109484) ### Code sample
    expand to view the code sample ```dart import 'package:flutter/material.dart'; /// Flutter code sample for [TabBar]. const Color labelColor = Color(0xFFFF0000); const Color unselectedLabelColor = Color(0x95FF0000); const TextStyle labelStyle = TextStyle( color: Color(0xff0000ff), fontWeight: FontWeight.bold, ); const TextStyle unselectedLabelStyle = TextStyle( color: Color(0x950000ff), fontStyle: FontStyle.italic, ); void main() => runApp(const TabBarApp()); class TabBarApp extends StatelessWidget { const TabBarApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData(useMaterial3: true), home: const TabBarExample(), ); } } class TabBarExample extends StatelessWidget { const TabBarExample({super.key}); @override Widget build(BuildContext context) { return DefaultTabController( initialIndex: 1, length: 3, child: Scaffold( appBar: AppBar( title: const Text('TabBar Sample'), bottom: const TabBar( // labelColor: labelColor, // unselectedLabelColor: unselectedLabelColor, labelStyle: labelStyle, unselectedLabelStyle: unselectedLabelStyle, tabs: [ Tab( icon: Icon(Icons.cloud_outlined), text: 'Cloudy', ), Tab( icon: Icon(Icons.beach_access_sharp), text: 'Sunny', ), Tab( icon: Icon(Icons.brightness_5_sharp), text: 'Rainy', ), ], ), ), body: const TabBarView( children: [ Center( child: Text("It's cloudy here"), ), Center( child: Text("It's rainy here"), ), Center( child: Text("It's sunny here"), ), ], ), ), ); } } ```
    #### When `labelStyle` and `unselectedLabelStyle` are specified with a color. ### Before ![image](https://github.com/flutter/flutter/assets/48603081/4138f928-aa63-40bc-9d4e-4d2aeefe72c1) ### After ![image](https://github.com/flutter/flutter/assets/48603081/2ce552c5-3972-4b5d-9492-eb487764e58f) --- packages/flutter/lib/src/material/tabs.dart | 48 +++-- .../test/material/tab_bar_theme_test.dart | 174 ++++++++++++++++++ packages/flutter/test/material/tabs_test.dart | 112 +++++++++++ 3 files changed, 315 insertions(+), 19 deletions(-) diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 79e9954051f98..b727c8a3d47ad 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -231,6 +231,8 @@ class _TabStyle extends AnimatedWidget { // details: https://github.com/flutter/flutter/pull/109541#issuecomment-1294241417 Color selectedColor = labelColor ?? tabBarTheme.labelColor + ?? labelStyle?.color + ?? tabBarTheme.labelStyle?.color ?? defaults.labelColor!; final Color unselectedColor; @@ -243,6 +245,8 @@ class _TabStyle extends AnimatedWidget { // when labelColor is a MaterialStateColor. unselectedColor = unselectedLabelColor ?? tabBarTheme.unselectedLabelColor + ?? unselectedLabelStyle?.color + ?? tabBarTheme.unselectedLabelStyle?.color ?? (themeData.useMaterial3 ? defaults.unselectedLabelColor! : selectedColor.withAlpha(0xB2)); // 70% alpha @@ -267,18 +271,18 @@ class _TabStyle extends AnimatedWidget { // To enable TextStyle.lerp(style1, style2, value), both styles must have // the same value of inherit. Force that to be inherit=true here. - final TextStyle defaultStyle = (labelStyle + final TextStyle selectedStyle = (labelStyle ?? tabBarTheme.labelStyle ?? defaults.labelStyle! ).copyWith(inherit: true); - final TextStyle defaultUnselectedStyle = (unselectedLabelStyle + final TextStyle unselectedStyle = (unselectedLabelStyle ?? tabBarTheme.unselectedLabelStyle ?? labelStyle ?? defaults.unselectedLabelStyle! ).copyWith(inherit: true); final TextStyle textStyle = isSelected - ? TextStyle.lerp(defaultStyle, defaultUnselectedStyle, animation.value)! - : TextStyle.lerp(defaultUnselectedStyle, defaultStyle, animation.value)!; + ? TextStyle.lerp(selectedStyle, unselectedStyle, animation.value)! + : TextStyle.lerp(unselectedStyle, selectedStyle, animation.value)!; final Color color = _resolveWithLabelColor(context).resolve(states); return DefaultTextStyle( @@ -955,8 +959,9 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// [MaterialState.selected] state, i.e. if the [Tab] is selected or not, /// ignoring [unselectedLabelColor] even if it's non-null. /// - /// The color specified in the [labelStyle] and the [TabBarTheme.labelStyle] - /// do not affect the effective [labelColor]. + /// When this color or the [TabBarTheme.labelColor] is specified, it overrides + /// the [TextStyle.color] specified for the [labelStyle] or the + /// [TabBarTheme.labelStyle]. /// /// See also: /// @@ -975,9 +980,9 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// will be used, otherwise unselected tab labels are rendered with /// [labelColor] at 70% opacity. /// - /// The color specified in the [unselectedLabelStyle] and the - /// [TabBarTheme.unselectedLabelStyle] are ignored in [unselectedLabelColor]'s - /// precedence calculation. + /// When this color or the [TabBarTheme.unselectedLabelColor] is specified, it + /// overrides the [TextStyle.color] specified for the [unselectedLabelStyle] + /// or the [TabBarTheme.unselectedLabelStyle]. /// /// See also: /// @@ -986,27 +991,32 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { /// The text style of the selected tab labels. /// - /// This does not influence color of the tab labels even if [TextStyle.color] - /// is non-null. Refer [labelColor] to color selected tab labels instead. + /// The color specified in [labelStyle] and [TabBarTheme.labelStyle] is used + /// to style the label when [labelColor] or [TabBarTheme.labelColor] are not + /// specified. /// /// If [unselectedLabelStyle] is null, then this text style will be used for /// both selected and unselected label styles. /// - /// If this property is null and [ThemeData.useMaterial3] is true, [TextTheme.titleSmall] + /// If this property is null, then [TabBarTheme.labelStyle] will be used. + /// + /// If that is also null and [ThemeData.useMaterial3] is true, [TextTheme.titleSmall] /// will be used, otherwise the text style of the [ThemeData.primaryTextTheme]'s /// [TextTheme.bodyLarge] definition is used. final TextStyle? labelStyle; /// The text style of the unselected tab labels. /// - /// This does not influence color of the tab labels even if [TextStyle.color] - /// is non-null. Refer [unselectedLabelColor] to color unselected tab labels - /// instead. + /// The color specified in [unselectedLabelStyle] and [TabBarTheme.unselectedLabelStyle] + /// is used to style the label when [unselectedLabelColor] or [TabBarTheme.unselectedLabelColor] + /// are not specified. + /// + /// If this property is null, then [TabBarTheme.unselectedLabelStyle] will be used. /// - /// If this property is null and [ThemeData.useMaterial3] is true, - /// [TextTheme.titleSmall] will be used, otherwise then the [labelStyle] value - /// is used. If [labelStyle] is null, the text style of the - /// [ThemeData.primaryTextTheme]'s [TextTheme.bodyLarge] definition is used. + /// If that is also null and [ThemeData.useMaterial3] is true, [TextTheme.titleSmall] + /// will be used, otherwise then the [labelStyle] value is used. If [labelStyle] is null, + /// the text style of the [ThemeData.primaryTextTheme]'s [TextTheme.bodyLarge] + /// definition is used. final TextStyle? unselectedLabelStyle; /// The padding added to each of the tab labels. diff --git a/packages/flutter/test/material/tab_bar_theme_test.dart b/packages/flutter/test/material/tab_bar_theme_test.dart index 7d3789e7b4098..2fec5877bbbe0 100644 --- a/packages/flutter/test/material/tab_bar_theme_test.dart +++ b/packages/flutter/test/material/tab_bar_theme_test.dart @@ -875,6 +875,180 @@ void main() { expect(tabTwoRect.right, equals(tabTwoRight)); }); + testWidgets( + 'TabBar labels use colors from TabBarTheme.labelStyle & TabBarTheme.unselectedLabelStyle', + (WidgetTester tester) async { + const TextStyle labelStyle = TextStyle( + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + const TextStyle unselectedLabelStyle = TextStyle( + color: Color(0x950000ff), + fontStyle: FontStyle.italic, + ); + const TabBarTheme tabBarTheme = TabBarTheme( + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + ); + + // Test tab bar with TabBarTheme labelStyle & unselectedLabelStyle. + await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme)); + + final IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + final IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + final TextStyle selectedTextStyle = tester.renderObject(find.text(_tab1Text)) + .text.style!; + final TextStyle unselectedTextStyle = tester.renderObject(find.text(_tab2Text)) + .text.style!; + + // Selected tab should use labelStyle color. + expect(selectedTabIcon.color, labelStyle.color); + expect(selectedTextStyle.color, labelStyle.color); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use unselectedLabelStyle color. + expect(uselectedTabIcon.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + }); + + testWidgets( + "TabBarTheme's labelColor & unselectedLabelColor override labelStyle & unselectedLabelStyle colors", + (WidgetTester tester) async { + const Color labelColor = Color(0xfff00000); + const Color unselectedLabelColor = Color(0x95ff0000); + const TextStyle labelStyle = TextStyle( + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + const TextStyle unselectedLabelStyle = TextStyle( + color: Color(0x950000ff), + fontStyle: FontStyle.italic, + ); + TabBarTheme tabBarTheme = const TabBarTheme( + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + ); + + await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme)); + + // Test tab bar with TabBarTheme labelStyle & unselectedLabelStyle. + await tester.pumpWidget(buildTabBar()); + + IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + TextStyle selectedTextStyle = tester.renderObject(find.text(_tab1Text)) + .text.style!; + TextStyle unselectedTextStyle = tester.renderObject(find.text(_tab2Text)) + .text.style!; + + // Selected tab should use the labelStyle color. + expect(selectedTabIcon.color, labelStyle.color); + expect(selectedTextStyle.color, labelStyle.color); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use the unselectedLabelStyle color. + expect(uselectedTabIcon.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + + // Update the TabBarTheme with labelColor & unselectedLabelColor. + tabBarTheme = const TabBarTheme( + labelColor: labelColor, + unselectedLabelColor: unselectedLabelColor, + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + ); + await tester.pumpWidget(buildTabBar(tabBarTheme: tabBarTheme)); + await tester.pumpAndSettle(); + + selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + selectedTextStyle = tester.renderObject(find.text(_tab1Text)).text.style!; + unselectedTextStyle = tester.renderObject(find.text(_tab2Text)).text.style!; + + // Selected tab should use the labelColor. + expect(selectedTabIcon.color, labelColor); + expect(selectedTextStyle.color, labelColor); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use the unselectedLabelColor. + expect(uselectedTabIcon.color, unselectedLabelColor); + expect(unselectedTextStyle.color, unselectedLabelColor); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + }); + + testWidgets( + "TabBarTheme's labelColor & unselectedLabelColor override TabBar.labelStyle & TabBar.unselectedLabelStyle colors", + (WidgetTester tester) async { + const Color labelColor = Color(0xfff00000); + const Color unselectedLabelColor = Color(0x95ff0000); + const TextStyle labelStyle = TextStyle( + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + const TextStyle unselectedLabelStyle = TextStyle( + color: Color(0x950000ff), + fontStyle: FontStyle.italic, + ); + + Widget buildTabBar({TabBarTheme? tabBarTheme}) { + return MaterialApp( + theme: ThemeData(tabBarTheme: tabBarTheme), + home: const Material( + child: DefaultTabController( + length: 2, + child: TabBar( + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + tabs: [ + Tab(text: _tab1Text), + Tab(text: _tab2Text), + ], + ), + ), + ), + ); + } + + // Test tab bar with [TabBar.labeStyle] & [TabBar.unselectedLabelStyle]. + await tester.pumpWidget(buildTabBar()); + + IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + TextStyle selectedTextStyle = tester.renderObject(find.text(_tab1Text)) + .text.style!; + TextStyle unselectedTextStyle = tester.renderObject(find.text(_tab2Text)) + .text.style!; + + // Selected tab should use the [TabBar.labelStyle] color. + expect(selectedTabIcon.color, labelStyle.color); + expect(selectedTextStyle.color, labelStyle.color); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use the [TabBar.unselectedLabelStyle] color. + expect(uselectedTabIcon.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + + // Add TabBarTheme with labelColor & unselectedLabelColor. + await tester.pumpWidget(buildTabBar(tabBarTheme: const TabBarTheme( + labelColor: labelColor, + unselectedLabelColor: unselectedLabelColor, + ))); + await tester.pumpAndSettle(); + + selectedTabIcon = IconTheme.of(tester.element(find.text(_tab1Text))); + uselectedTabIcon = IconTheme.of(tester.element(find.text(_tab2Text))); + selectedTextStyle = tester.renderObject(find.text(_tab1Text)).text.style!; + unselectedTextStyle = tester.renderObject(find.text(_tab2Text)).text.style!; + + // Selected tab should use the [TabBarTheme.labelColor]. + expect(selectedTabIcon.color, labelColor); + expect(selectedTextStyle.color, labelColor); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use the [TabBarTheme.unselectedLabelColor]. + expect(uselectedTabIcon.color, unselectedLabelColor); + expect(unselectedTextStyle.color, unselectedLabelColor); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index c35f8fb8d6951..144fbaf3b39f9 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -6387,6 +6387,118 @@ void main() { expect(tester.getSize(find.byType(CustomPaint).at(1)).width, 360); }); + testWidgets('TabBar labels use colors from labelStyle & unselectedLabelStyle', (WidgetTester tester) async { + const String tab1 = 'Tab 1'; + const String tab2 = 'Tab 2'; + + const TextStyle labelStyle = TextStyle( + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + const TextStyle unselectedLabelStyle = TextStyle( + color: Color(0x950000ff), + fontStyle: FontStyle.italic, + ); + + // Test tab bar with labeStyle & unselectedLabelStyle. + await tester.pumpWidget(boilerplate( + child: const DefaultTabController( + length: 2, + child: TabBar( + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + tabs: [ + Tab(text: tab1), + Tab(text: tab2), + ], + ), + ), + )); + + final IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(tab1))); + final IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(tab2))); + final TextStyle selectedTextStyle = tester.renderObject(find.text(tab1)).text.style!; + final TextStyle unselectedTextStyle = tester.renderObject(find.text(tab2)).text.style!; + + // Selected tab should use the labelStyle color. + expect(selectedTabIcon.color, labelStyle.color); + expect(selectedTextStyle.color, labelStyle.color); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use the unselectedLabelStyle color. + expect(uselectedTabIcon.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + }); + + testWidgets('labelColor & unselectedLabelColor override labelStyle & unselectedLabelStyle colors', (WidgetTester tester) async { + const String tab1 = 'Tab 1'; + const String tab2 = 'Tab 2'; + + const Color labelColor = Color(0xfff00000); + const Color unselectedLabelColor = Color(0x95ff0000); + const TextStyle labelStyle = TextStyle( + color: Color(0xff0000ff), + fontStyle: FontStyle.italic, + ); + const TextStyle unselectedLabelStyle = TextStyle( + color: Color(0x950000ff), + fontStyle: FontStyle.italic, + ); + + Widget buildTabBar({ Color? labelColor, Color? unselectedLabelColor }) { + return boilerplate( + child: DefaultTabController( + length: 2, + child: TabBar( + labelColor: labelColor, + unselectedLabelColor: unselectedLabelColor, + labelStyle: labelStyle, + unselectedLabelStyle: unselectedLabelStyle, + tabs: const [ + Tab(text: tab1), + Tab(text: tab2), + ], + ), + ), + ); + } + + // Test tab bar with labeStyle & unselectedLabelStyle. + await tester.pumpWidget(buildTabBar()); + + IconThemeData selectedTabIcon = IconTheme.of(tester.element(find.text(tab1))); + IconThemeData uselectedTabIcon = IconTheme.of(tester.element(find.text(tab2))); + TextStyle selectedTextStyle = tester.renderObject(find.text(tab1)).text.style!; + TextStyle unselectedTextStyle = tester.renderObject(find.text(tab2)).text.style!; + + // Selected tab should use labelStyle color. + expect(selectedTabIcon.color, labelStyle.color); + expect(selectedTextStyle.color, labelStyle.color); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use unselectedLabelStyle color. + expect(uselectedTabIcon.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.color, unselectedLabelStyle.color); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + + // Update tab bar with labelColor & unselectedLabelColor. + await tester.pumpWidget(buildTabBar(labelColor: labelColor, unselectedLabelColor: unselectedLabelColor)); + await tester.pumpAndSettle(); + + selectedTabIcon = IconTheme.of(tester.element(find.text(tab1))); + uselectedTabIcon = IconTheme.of(tester.element(find.text(tab2))); + selectedTextStyle = tester.renderObject(find.text(tab1)).text.style!; + unselectedTextStyle = tester.renderObject(find.text(tab2)).text.style!; + + // Selected tab should use the labelColor. + expect(selectedTabIcon.color, labelColor); + expect(selectedTextStyle.color, labelColor); + expect(selectedTextStyle.fontStyle, labelStyle.fontStyle); + // Unselected tab should use the unselectedLabelColor. + expect(uselectedTabIcon.color, unselectedLabelColor); + expect(unselectedTextStyle.color, unselectedLabelColor); + expect(unselectedTextStyle.fontStyle, unselectedLabelStyle.fontStyle); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests From 3744050be395f478808e809c423e752c6ef82048 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 7 Sep 2023 05:27:18 -0400 Subject: [PATCH 1117/1547] Roll Flutter Engine from d864ae68db3c to 5a45ecd24aa3 (1 revision) (#134201) https://github.com/flutter/engine/compare/d864ae68db3c...5a45ecd24aa3 2023-09-07 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from hHwU6r12A0sy5Bq-0... to WbB3tmMXnuwJBAHoi... (flutter/engine#45529) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from hHwU6r12A0sy to WbB3tmMXnuwJ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b670ad5ac0066..866a97c2a63cc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d864ae68db3c0491cd7f55119d0d9c79c9ff153a +5a45ecd24aa3e24b089ec8d1fcb5fae59338527e diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 6cd711c3ea435..89cc5d81ad805 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -hHwU6r12A0sy5Bq-0EiKQzK-Mv4l3N9k7MroYgVJExQC +WbB3tmMXnuwJBAHoi1HLqjMfKBh5zvsqNWbcd7TjKU0C From bbf5d11aadb49b923046e574cd99ed7d0485051b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 7 Sep 2023 07:27:28 -0400 Subject: [PATCH 1118/1547] Roll Flutter Engine from 5a45ecd24aa3 to 558136a1ccbf (1 revision) (#134206) https://github.com/flutter/engine/compare/5a45ecd24aa3...558136a1ccbf 2023-09-07 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from SCoDb2m_zQDLrMhwT... to N915IZbyx6MSrwwS-... (flutter/engine#45532) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from SCoDb2m_zQDL to N915IZbyx6MS If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 866a97c2a63cc..f06bd020296d2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5a45ecd24aa3e24b089ec8d1fcb5fae59338527e +558136a1ccbfead80240ed7edf2e8e429c4ced70 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 6c8226582dda9..186cca0b4b744 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -SCoDb2m_zQDLrMhwTwp5WCNL_BjAwYCPHfEbuLUUIZgC +N915IZbyx6MSrwwS-3J0xJZoPKn9b8mmLqTUqZ-XPfUC From 6ddb3b04b4fe5cdb93f88f70553e2d63d1c6bb53 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 7 Sep 2023 12:00:49 -0400 Subject: [PATCH 1119/1547] Roll Flutter Engine from 558136a1ccbf to 71bea01d3abe (2 revisions) (#134216) https://github.com/flutter/engine/compare/558136a1ccbf...71bea01d3abe 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 826f9f5d20b6 to 9a41a83f96d7 (2 revisions) (flutter/engine#45534) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from c99601816d84 to 826f9f5d20b6 (1 revision) (flutter/engine#45533) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f06bd020296d2..f1e1270e53016 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -558136a1ccbfead80240ed7edf2e8e429c4ced70 +71bea01d3abe7bd828aa0b52961bc89e2340f607 From 2867b31f5ed4ab45d2697cda0fd4281c62e64220 Mon Sep 17 00:00:00 2001 From: Matheus Kirchesch Date: Thu, 7 Sep 2023 14:21:52 -0300 Subject: [PATCH 1120/1547] Fixed [NavigationRailDestination]'s label opacity while disabled not being coherent with the icon (#132345) Fixing the opacity of the NavigationRailDestination widget label while it is disabled, right now it doesn't get affected by the disabled attribute, which doesn't match the icon that gets affected * https://github.com/flutter/flutter/issues/132344 I believe this PR should be marked as [test-exempt] ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. --- .../lib/src/material/navigation_rail.dart | 4 +- .../test/material/navigation_rail_test.dart | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index 4219d52d302ad..6b7228f5cf785 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -594,7 +594,9 @@ class _RailDestination extends StatelessWidget { child: icon, ); final Widget styledLabel = DefaultTextStyle( - style: labelTextStyle, + style: disabled + ? labelTextStyle.copyWith(color: theme.colorScheme.onSurface.withOpacity(0.38)) + : labelTextStyle, child: label, ); diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index b94dc65194656..ae0b4571747f7 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -3290,6 +3290,47 @@ void main() { tester.pumpAndSettle(); }); + testWidgetsWithLeakTracking("Destination's label with the right opacity while disabled", (WidgetTester tester) async { + await _pumpNavigationRail( + tester, + navigationRail: NavigationRail( + selectedIndex: 0, + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.favorite_border), + selectedIcon: Icon(Icons.favorite), + label: Text('Abc'), + ), + NavigationRailDestination( + icon: Icon(Icons.bookmark_border), + selectedIcon: Icon(Icons.bookmark), + label: Text('Bcd'), + disabled: true, + ), + ], + onDestinationSelected: (int index) {}, + labelType: NavigationRailLabelType.all, + ), + ); + + await tester.pumpAndSettle(); + + double? defaultTextStyleOpacity(String text) { + return tester.widget( + find.ancestor( + of: find.text(text), + matching: find.byType(DefaultTextStyle), + ).first, + ).style.color?.opacity; + } + + final double? abcLabelOpacity = defaultTextStyleOpacity('Abc'); + final double? bcdLabelOpacity = defaultTextStyleOpacity('Bcd'); + + expect(abcLabelOpacity, 1.0); + expect(bcdLabelOpacity, closeTo(0.38, 0.01)); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests From 0d198c7ba6ea9fbdf364426f47e952c49775a1f9 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Thu, 7 Sep 2023 11:13:55 -0700 Subject: [PATCH 1121/1547] SearchDelegate should dispose resources. (#133948) --- packages/flutter/lib/src/material/search.dart | 9 +++++++++ packages/flutter/test/material/search_test.dart | 4 +++- .../flutter/test/material/segmented_button_test.dart | 4 +--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/material/search.dart b/packages/flutter/lib/src/material/search.dart index e465c5492ebb0..507af6df90d55 100644 --- a/packages/flutter/lib/src/material/search.dart +++ b/packages/flutter/lib/src/material/search.dart @@ -377,6 +377,15 @@ abstract class SearchDelegate { } _SearchPageRoute? _route; + + /// Releases the resources. + @mustCallSuper + void dispose() { + _currentBodyNotifier.dispose(); + _focusNode?.dispose(); + _queryTextController.dispose(); + _proxyAnimation.parent = null; + } } /// Describes the body that is currently shown under the [AppBar] in the diff --git a/packages/flutter/test/material/search_test.dart b/packages/flutter/test/material/search_test.dart index e1623b664fe8a..4e1e07954172d 100644 --- a/packages/flutter/test/material/search_test.dart +++ b/packages/flutter/test/material/search_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/semantics_tester.dart'; @@ -25,8 +26,9 @@ void main() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null); }); - testWidgets('Changing query moves cursor to the end of query', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing query moves cursor to the end of query', (WidgetTester tester) async { final _TestSearchDelegate delegate = _TestSearchDelegate(); + addTearDown(() => delegate.dispose()); await tester.pumpWidget(TestHomePage(delegate: delegate)); await tester.tap(find.byTooltip('Search')); diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index cb302dc3cd5e3..06e3d13e546e8 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -22,9 +22,7 @@ Widget boilerplate({required Widget child}) { void main() { - testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', - leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed(), - (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( From aca91df6b78415501f878856eed183811633d6ac Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Thu, 7 Sep 2023 20:24:29 +0200 Subject: [PATCH 1122/1547] Cover some test/widgets tests with leak tracking (#133803) --- .../test/widgets/absorb_pointer_test.dart | 9 +- .../flutter/test/widgets/actions_test.dart | 98 +++++++++------ packages/flutter/test/widgets/align_test.dart | 13 +- .../test/widgets/animated_align_test.dart | 13 +- .../test/widgets/animated_container_test.dart | 17 +-- .../widgets/animated_cross_fade_test.dart | 23 ++-- .../test/widgets/animated_grid_test.dart | 25 ++-- .../animated_image_filtered_repaint_test.dart | 3 +- .../test/widgets/animated_list_test.dart | 30 +++-- .../animated_opacity_repaint_test.dart | 10 +- .../test/widgets/animated_padding_test.dart | 7 +- .../widgets/animated_positioned_test.dart | 21 ++-- .../test/widgets/animated_size_test.dart | 17 +-- .../test/widgets/animated_switcher_test.dart | 23 ++-- .../test/widgets/annotated_region_test.dart | 6 +- .../widgets/app_lifecycle_listener_test.dart | 11 +- .../test/widgets/app_navigator_key_test.dart | 3 +- .../test/widgets/app_overrides_test.dart | 11 +- packages/flutter/test/widgets/app_test.dart | 118 +++++++++++------- .../flutter/test/widgets/app_title_test.dart | 7 +- .../test/widgets/aspect_ratio_test.dart | 5 +- packages/flutter/test/widgets/async_test.dart | 57 ++++----- .../test/widgets/autocomplete_test.dart | 51 ++++---- .../test/widgets/autofill_group_test.dart | 9 +- .../widgets/automatic_keep_alive_test.dart | 26 ++-- .../test/widgets/backdrop_filter_test.dart | 9 +- .../flutter/test/widgets/banner_test.dart | 5 +- .../flutter/test/widgets/baseline_test.dart | 11 +- packages/flutter/test/widgets/basic_test.dart | 59 ++++----- .../binding_deferred_first_frame_test.dart | 5 +- .../flutter/test/widgets/binding_test.dart | 25 ++-- .../test/widgets/box_decoration_test.dart | 27 ++-- .../test/widgets/build_context_test.dart | 5 +- .../test/widgets/build_scope_test.dart | 5 +- .../flutter/test/widgets/center_test.dart | 3 +- .../test/widgets/clamp_overscrolls_test.dart | 8 +- packages/flutter/test/widgets/clip_test.dart | 56 +++++---- .../test/widgets/color_filter_test.dart | 7 +- .../flutter/test/widgets/column_test.dart | 37 +++--- .../widgets/composited_transform_test.dart | 29 ++--- .../test/widgets/constrained_box_test.dart | 19 +-- .../flutter/test/widgets/container_test.dart | 31 ++--- .../widgets/context_menu_controller_test.dart | 9 +- .../test/widgets/coordinates_test.dart | 3 +- .../custom_multi_child_layout_test.dart | 26 ++-- .../test/widgets/custom_paint_test.dart | 9 +- .../test/widgets/custom_painter_test.dart | 25 ++-- .../test/widgets/custom_scroll_view_test.dart | 11 +- .../custom_single_child_layout_test.dart | 10 +- packages/flutter/test/widgets/debug_test.dart | 9 +- .../test/widgets/decorated_sliver_test.dart | 30 +++-- .../test/widgets/default_colors_test.dart | 36 +++--- .../default_text_editing_shortcuts_test.dart | 60 ++++++--- .../default_text_height_behavior_test.dart | 9 +- .../test/widgets/default_text_style_test.dart | 5 +- .../test/widgets/did_update_widget_test.dart | 3 +- .../test/widgets/directionality_test.dart | 9 +- .../test/widgets/dismissible_test.dart | 73 +++++------ .../display_feature_sub_screen_test.dart | 15 +-- .../disposable_build_context_test.dart | 3 +- 60 files changed, 733 insertions(+), 566 deletions(-) diff --git a/packages/flutter/test/widgets/absorb_pointer_test.dart b/packages/flutter/test/widgets/absorb_pointer_test.dart index 6c2a88f58ca4a..afe8198a29ab2 100644 --- a/packages/flutter/test/widgets/absorb_pointer_test.dart +++ b/packages/flutter/test/widgets/absorb_pointer_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('AbsorbPointers do not block siblings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AbsorbPointers do not block siblings', (WidgetTester tester) async { bool tapped = false; await tester.pumpWidget( Column( @@ -29,7 +30,7 @@ void main() { }); group('AbsorbPointer semantics', () { - testWidgets('does not change semantics when not absorbing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not change semantics when not absorbing', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -56,7 +57,7 @@ void main() { ); }); - testWidgets('drops semantics when its ignoreSemantics is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drops semantics when its ignoreSemantics is true', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final UniqueKey key = UniqueKey(); await tester.pumpWidget( @@ -75,7 +76,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignores user interactions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores user interactions', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index 6a246304e3f81..38f548ee210b0 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -8,10 +8,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group(ActionDispatcher, () { - testWidgets('ActionDispatcher invokes actions when asked.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ActionDispatcher invokes actions when asked.', (WidgetTester tester) async { await tester.pumpWidget(Container()); bool invoked = false; const ActionDispatcher dispatcher = ActionDispatcher(); @@ -48,7 +49,7 @@ void main() { setUp(clear); - testWidgets('Actions widget can invoke actions with default dispatcher', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can invoke actions with default dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -75,7 +76,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can invoke actions with default dispatcher and maybeInvoke', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -102,7 +103,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('maybeInvoke returns null when no action is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('maybeInvoke returns null when no action is found', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -129,7 +130,7 @@ void main() { expect(invoked, isFalse); }); - testWidgets('invoke throws when no action is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('invoke throws when no action is found', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -156,7 +157,7 @@ void main() { expect(invoked, isFalse); }); - testWidgets('Actions widget can invoke actions with custom dispatcher', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can invoke actions with custom dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -187,7 +188,7 @@ void main() { expect(invokedIntent, equals(intent)); }); - testWidgets('Actions can invoke actions in ancestor dispatcher', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions can invoke actions in ancestor dispatcher', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -224,7 +225,7 @@ void main() { expect(invokedDispatcher.runtimeType, equals(TestDispatcher1)); }); - testWidgets("Actions can invoke actions in ancestor dispatcher if a lower one isn't specified", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Actions can invoke actions in ancestor dispatcher if a lower one isn't specified", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -260,7 +261,7 @@ void main() { expect(invokedDispatcher.runtimeType, equals(TestDispatcher1)); }); - testWidgets('Actions widget can be found with of', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions widget can be found with of', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final ActionDispatcher testDispatcher = TestDispatcher1(postInvoke: collect); @@ -277,7 +278,7 @@ void main() { expect(dispatcher, equals(testDispatcher)); }); - testWidgets('Action can be found with find', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action can be found with find', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final ActionDispatcher testDispatcher = TestDispatcher1(postInvoke: collect); bool invoked = false; @@ -324,7 +325,7 @@ void main() { expect(Actions.maybeFind(containerKey.currentContext!), isNull); }); - testWidgets('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); bool invoked = false; @@ -339,6 +340,8 @@ void main() { bool hovering = false; bool focusing = false; + addTearDown(focusNode.dispose); + Future buildTest(bool enabled) async { await tester.pumpWidget( Center( @@ -394,7 +397,7 @@ void main() { expect(focusing, isFalse); }); - testWidgets('FocusableActionDetector changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MouseRegion( cursor: SystemMouseCursors.forbidden, @@ -427,7 +430,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.forbidden); }); - testWidgets('Actions.invoke returns the value of Action.invoke', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions.invoke returns the value of Action.invoke', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final Object sentinel = Object(); bool invoked = false; @@ -458,7 +461,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('ContextAction can return null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ContextAction can return null', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); const TestIntent intent = TestIntent(); final TestContextAction testAction = TestContextAction(); @@ -485,7 +488,7 @@ void main() { expect(testAction.capturedContexts.single, containerKey.currentContext); }); - testWidgets('Disabled actions stop propagation to an ancestor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled actions stop propagation to an ancestor', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked = false; const TestIntent intent = TestIntent(); @@ -534,7 +537,7 @@ void main() { }); group('Listening', () { - testWidgets('can listen to enabled state of Actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can listen to enabled state of Actions', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); bool invoked1 = false; bool invoked2 = false; @@ -756,7 +759,11 @@ void main() { ); }); - testWidgets('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { + tearDown(() async { + focusNode.dispose(); + }); + + testWidgetsWithLeakTracking('FocusableActionDetector keeps track of focus and hover even when disabled.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -790,7 +797,7 @@ void main() { expect(focusing, isFalse); }); - testWidgets('FocusableActionDetector shows focus highlight appropriately when focused and disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector shows focus highlight appropriately when focused and disabled', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -821,7 +828,7 @@ void main() { expect(focusing, isTrue); }); - testWidgets('FocusableActionDetector can be used without callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector can be used without callbacks', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final GlobalKey containerKey = GlobalKey(); @@ -855,11 +862,13 @@ void main() { expect(focusing, isFalse); }); - testWidgets( + testWidgetsWithLeakTracking( 'FocusableActionDetector can prevent its descendants from being focusable', (WidgetTester tester) async { final FocusNode buttonNode = FocusNode(debugLabel: 'Test'); + addTearDown(buttonNode.dispose); + await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( @@ -899,16 +908,23 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'FocusableActionDetector can prevent its descendants from being traversable', (WidgetTester tester) async { final FocusNode buttonNode1 = FocusNode(debugLabel: 'Button Node 1'); final FocusNode buttonNode2 = FocusNode(debugLabel: 'Button Node 2'); + final FocusNode skipTraversalNode = FocusNode(skipTraversal: true); + + addTearDown(() { + buttonNode1.dispose(); + buttonNode2.dispose(); + skipTraversalNode.dispose(); + }); await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( - focusNode: FocusNode(skipTraversal: true), + focusNode: skipTraversalNode, child: Column( children: [ ElevatedButton( @@ -939,7 +955,7 @@ void main() { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( - focusNode: FocusNode(skipTraversal: true), + focusNode: skipTraversalNode, descendantsAreTraversable: false, child: Column( children: [ @@ -970,7 +986,7 @@ void main() { }, ); - testWidgets('FocusableActionDetector can exclude Focus semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusableActionDetector can exclude Focus semantics', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: FocusableActionDetector( @@ -1076,7 +1092,7 @@ void main() { }); group('Action subclasses', () { - testWidgets('CallbackAction passes correct intent when invoked.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CallbackAction passes correct intent when invoked.', (WidgetTester tester) async { late Intent passedIntent; final TestAction action = TestAction(onInvoke: (Intent intent) { passedIntent = intent; @@ -1087,7 +1103,7 @@ void main() { expect(passedIntent, equals(intent)); }); - testWidgets('VoidCallbackAction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('VoidCallbackAction', (WidgetTester tester) async { bool called = false; void testCallback() { called = true; @@ -1097,7 +1113,7 @@ void main() { action.invoke(intent); expect(called, isTrue); }); - testWidgets('Base Action class default toKeyEventResult delegates to consumesKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Base Action class default toKeyEventResult delegates to consumesKey', (WidgetTester tester) async { expect( DefaultToKeyEventResultAction(consumesKey: false).toKeyEventResult(const DefaultToKeyEventResultIntent(), null), KeyEventResult.skipRemainingHandlers, @@ -1110,7 +1126,7 @@ void main() { }); group('Diagnostics', () { - testWidgets('default Intent debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default Intent debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); // ignore: invalid_use_of_protected_member @@ -1126,7 +1142,7 @@ void main() { expect(description, isEmpty); }); - testWidgets('default Actions debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default Actions debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Actions( @@ -1152,7 +1168,7 @@ void main() { ); }); - testWidgets('Actions implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); Actions( @@ -1191,7 +1207,7 @@ void main() { invokingContext = null; }); - testWidgets('Basic usage', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Basic usage', (WidgetTester tester) async { late BuildContext invokingContext2; late BuildContext invokingContext3; await tester.pumpWidget( @@ -1256,7 +1272,7 @@ void main() { expect(invocations, ['action1.invoke']); }); - testWidgets('Does not break after use', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not break after use', (WidgetTester tester) async { late BuildContext invokingContext2; late BuildContext invokingContext3; await tester.pumpWidget( @@ -1323,7 +1339,7 @@ void main() { ]); }); - testWidgets('Does not override if not overridable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not override if not overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1366,7 +1382,7 @@ void main() { ]); }); - testWidgets('The final override controls isEnabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The final override controls isEnabled', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1453,7 +1469,7 @@ void main() { expect(invocations, []); }); - testWidgets('The override can choose to defer isActionEnabled to the overridable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The override can choose to defer isActionEnabled to the overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1543,7 +1559,7 @@ void main() { ]); }); - testWidgets('Throws on infinite recursions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws on infinite recursions', (WidgetTester tester) async { late StateSetter setState; BuildContext? action2LookupContext; await tester.pumpWidget( @@ -1602,7 +1618,7 @@ void main() { expect(exception?.toString(), contains('debugAssertIsEnabledMutuallyRecursive')); }); - testWidgets('Throws on invoking invalid override', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws on invoking invalid override', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context) { @@ -1640,7 +1656,7 @@ void main() { ); }); - testWidgets('Make an overridable action overridable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Make an overridable action overridable', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1696,7 +1712,7 @@ void main() { ]); }); - testWidgets('Overriding Actions can change the intent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overriding Actions can change the intent', (WidgetTester tester) async { final List newLogChannel = []; await tester.pumpWidget( Builder( @@ -1746,7 +1762,7 @@ void main() { ]); }); - testWidgets('Override non-context overridable Actions with a ContextAction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override non-context overridable Actions with a ContextAction', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { @@ -1799,7 +1815,7 @@ void main() { expect(LogInvocationContextAction.invokeContext, invokingContext); }); - testWidgets('Override a ContextAction with a regular Action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Override a ContextAction with a regular Action', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context1) { diff --git a/packages/flutter/test/widgets/align_test.dart b/packages/flutter/test/widgets/align_test.dart index aa44e27bce1aa..1a6e89f73f176 100644 --- a/packages/flutter/test/widgets/align_test.dart +++ b/packages/flutter/test/widgets/align_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Align smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align smoke test', (WidgetTester tester) async { await tester.pumpWidget( Align( alignment: const Alignment(0.50, 0.50), @@ -38,7 +39,7 @@ void main() { ); }); - testWidgets('Align control test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align control test (LTR)', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: Align( @@ -62,7 +63,7 @@ void main() { expect(tester.getBottomRight(find.byType(SizedBox)).dx, 100.0); }); - testWidgets('Align control test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align control test (RTL)', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.rtl, child: Align( @@ -86,7 +87,7 @@ void main() { expect(tester.getBottomRight(find.byType(SizedBox)).dx, 100.0); }); - testWidgets('Shrink wraps in finite space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shrink wraps in finite space', (WidgetTester tester) async { final GlobalKey alignKey = GlobalKey(); await tester.pumpWidget( SingleChildScrollView( @@ -105,7 +106,7 @@ void main() { expect(size.height, equals(10.0)); }); - testWidgets('Align widthFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -128,7 +129,7 @@ void main() { expect(box.size.width, equals(50.0)); }); - testWidgets('Align heightFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Align heightFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/animated_align_test.dart b/packages/flutter/test/widgets/animated_align_test.dart index 032f2678654fb..0d0331505abdc 100644 --- a/packages/flutter/test/widgets/animated_align_test.dart +++ b/packages/flutter/test/widgets/animated_align_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedAlign.debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign.debugFillProperties', (WidgetTester tester) async { const AnimatedAlign box = AnimatedAlign( alignment: Alignment.topCenter, curve: Curves.ease, @@ -15,7 +16,7 @@ void main() { expect(box, hasOneLineDescription); }); - testWidgets('AnimatedAlign alignment visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign alignment visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -57,7 +58,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(800.0, 400.0)); }); - testWidgets('AnimatedAlign widthFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -82,7 +83,7 @@ void main() { expect(box.size.width, equals(50.0)); }); - testWidgets('AnimatedAlign heightFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign heightFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -106,7 +107,7 @@ void main() { expect(box.size.height, equals( 50.0)); }); - testWidgets('AnimatedAlign null height factor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign null height factor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -130,7 +131,7 @@ void main() { expect(box.size, equals(const Size(100.0, 100))); }); - testWidgets('AnimatedAlign null widthFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign null widthFactor', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/animated_container_test.dart b/packages/flutter/test/widgets/animated_container_test.dart index 6d40f450cd5c9..d25156a595762 100644 --- a/packages/flutter/test/widgets/animated_container_test.dart +++ b/packages/flutter/test/widgets/animated_container_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedContainer.debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer.debugFillProperties', (WidgetTester tester) async { final AnimatedContainer container = AnimatedContainer( constraints: const BoxConstraints.tightFor(width: 17.0, height: 23.0), decoration: const BoxDecoration(color: Color(0xFF00FF00)), @@ -24,7 +25,7 @@ void main() { expect(container, hasOneLineDescription); }); - testWidgets('AnimatedContainer control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer control test', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const BoxDecoration decorationA = BoxDecoration( @@ -102,7 +103,7 @@ void main() { ); }); - testWidgets('AnimatedContainer overanimate test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer overanimate test', (WidgetTester tester) async { await tester.pumpWidget( AnimatedContainer( duration: const Duration(milliseconds: 200), @@ -139,7 +140,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('AnimatedContainer padding visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer padding visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -181,7 +182,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(700.0, 0.0)); }); - testWidgets('AnimatedContainer alignment visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer alignment visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -223,7 +224,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(800.0, 400.0)); }); - testWidgets('Animation rerun', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animation rerun', (WidgetTester tester) async { await tester.pumpWidget( Center( child: AnimatedContainer( @@ -291,7 +292,7 @@ void main() { expect(text.size.height, equals(100.0)); }); - testWidgets('AnimatedContainer sets transformAlignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer sets transformAlignment', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -339,7 +340,7 @@ void main() { expect(tester.getTopLeft(find.byKey(target)), const Offset(400.0, 300.0)); }); - testWidgets('AnimatedContainer sets clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer sets clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( AnimatedContainer( decoration: const BoxDecoration( diff --git a/packages/flutter/test/widgets/animated_cross_fade_test.dart b/packages/flutter/test/widgets/animated_cross_fade_test.dart index 7a4ac09b49bd8..ee3f88b132b32 100644 --- a/packages/flutter/test/widgets/animated_cross_fade_test.dart +++ b/packages/flutter/test/widgets/animated_cross_fade_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedCrossFade test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade test', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -61,7 +62,7 @@ void main() { expect(box.size.height, equals(150.0)); }); - testWidgets('AnimatedCrossFade test showSecond', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade test showSecond', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -88,7 +89,7 @@ void main() { expect(box.size.height, equals(200.0)); }); - testWidgets('AnimatedCrossFade alignment (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade alignment (VISUAL)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -146,7 +147,7 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); }); - testWidgets('AnimatedCrossFade alignment (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade alignment (LTR)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -204,7 +205,7 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); }); - testWidgets('AnimatedCrossFade alignment (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade alignment (RTL)', (WidgetTester tester) async { final Key firstKey = UniqueKey(); final Key secondKey = UniqueKey(); @@ -274,7 +275,7 @@ void main() { ); } - testWidgets('AnimatedCrossFade preserves widget state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade preserves widget state', (WidgetTester tester) async { await tester.pumpWidget(crossFadeWithWatcher()); _TickerWatchingWidgetState findState() => tester.state(find.byType(_TickerWatchingWidget)); @@ -287,7 +288,7 @@ void main() { } }); - testWidgets('AnimatedCrossFade switches off TickerMode and semantics on faded out widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade switches off TickerMode and semantics on faded out widget', (WidgetTester tester) async { ExcludeSemantics findSemantics() { return tester.widget(find.descendant( of: find.byKey(const ValueKey(CrossFadeState.showFirst)), @@ -317,7 +318,7 @@ void main() { expect(findSemantics().excluding, true); }); - testWidgets('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -361,7 +362,7 @@ void main() { expect(find.text('AAA'), findsNothing); }); - testWidgets('AnimatedCrossFade test focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade test focus', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -385,7 +386,7 @@ void main() { expect(hiddenNode.hasPrimaryFocus, isFalse); }); - testWidgets('AnimatedCrossFade bottom child can have focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedCrossFade bottom child can have focus', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -410,7 +411,7 @@ void main() { expect(hiddenNode.hasPrimaryFocus, isTrue); }); - testWidgets('AnimatedCrossFade second child do not receive touch events', + testWidgetsWithLeakTracking('AnimatedCrossFade second child do not receive touch events', (WidgetTester tester) async { int numberOfTouchEventNoticed = 0; diff --git a/packages/flutter/test/widgets/animated_grid_test.dart b/packages/flutter/test/widgets/animated_grid_test.dart index dcec143a9e705..c03c7143febd1 100644 --- a/packages/flutter/test/widgets/animated_grid_test.dart +++ b/packages/flutter/test/widgets/animated_grid_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('SliverAnimatedGrid.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAnimatedGrid.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -50,7 +51,7 @@ void main() { expect(finderCalled, true); }); - testWidgets('AnimatedGrid', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedGrid', (WidgetTester tester) async { Widget builder(BuildContext context, int index, Animation animation) { return SizedBox( height: 100.0, @@ -132,7 +133,7 @@ void main() { }); group('SliverAnimatedGrid', () { - testWidgets('initialItemCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialItemCount', (WidgetTester tester) async { final Map> animations = >{}; await tester.pumpWidget( @@ -170,7 +171,7 @@ void main() { expect(animations[1]!.value, 1.0); }); - testWidgets('insert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insert', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -250,7 +251,7 @@ void main() { expect(itemRight(2), 300.0); }); - testWidgets('insertAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insertAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -306,7 +307,7 @@ void main() { expect(itemRight(1), 200.0); }); - testWidgets('remove', (WidgetTester tester) async { + testWidgetsWithLeakTracking('remove', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -384,7 +385,7 @@ void main() { expect(itemRight(2), 200.0); }); - testWidgets('removeAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removeAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -436,7 +437,7 @@ void main() { expect(find.text('item 2'), findsNothing); }); - testWidgets('works in combination with other slivers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in combination with other slivers', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -505,7 +506,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')).dx, 0); }); - testWidgets('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', + testWidgetsWithLeakTracking('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { final List items = [0, 1, 2, 3]; final GlobalKey listKey = GlobalKey(); @@ -573,7 +574,7 @@ void main() { }); }); - testWidgets( + testWidgetsWithLeakTracking( 'AnimatedGrid.of() and maybeOf called with a context that does not contain AnimatedGrid', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -618,7 +619,7 @@ void main() { }, ); - testWidgets('AnimatedGrid.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedGrid.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { const Clip clipBehavior = Clip.none; await tester.pumpWidget( @@ -647,7 +648,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).clipBehavior, clipBehavior); }); - testWidgets('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart b/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart index 0ccd25107435e..75de31aea77d4 100644 --- a/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart +++ b/packages/flutter/test/widgets/animated_image_filtered_repaint_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageFiltered avoids repainting child as it animates', (WidgetTester tester) async { RenderTestObject.paintCount = 0; await tester.pumpWidget( ColoredBox( diff --git a/packages/flutter/test/widgets/animated_list_test.dart b/packages/flutter/test/widgets/animated_list_test.dart index 6e585c9fcd2dc..d8d637bb43083 100644 --- a/packages/flutter/test/widgets/animated_list_test.dart +++ b/packages/flutter/test/widgets/animated_list_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('SliverAnimatedList.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAnimatedList.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -47,7 +48,7 @@ void main() { expect(finderCalled, true); }); - testWidgets('AnimatedList', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList', (WidgetTester tester) async { Widget builder(BuildContext context, int index, Animation animation) { return SizedBox( height: 100.0, @@ -126,7 +127,7 @@ void main() { }); group('SliverAnimatedList', () { - testWidgets('initialItemCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialItemCount', (WidgetTester tester) async { final Map> animations = >{}; await tester.pumpWidget( @@ -159,7 +160,7 @@ void main() { expect(animations[1]!.value, 1.0); }); - testWidgets('insert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insert', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -245,7 +246,7 @@ void main() { }); // Test for insertAllItems with SliverAnimatedList - testWidgets('insertAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insertAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -302,7 +303,7 @@ void main() { }); // Test for removeAllItems with SliverAnimatedList - testWidgets('remove', (WidgetTester tester) async { + testWidgetsWithLeakTracking('remove', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -379,7 +380,7 @@ void main() { }); // Test for removeAllItems with SliverAnimatedList - testWidgets('removeAll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removeAll', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); final List items = [0, 1, 2]; @@ -429,7 +430,7 @@ void main() { expect(find.text('item 2'), findsNothing); }); - testWidgets('works in combination with other slivers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in combination with other slivers', (WidgetTester tester) async { final GlobalKey listKey = GlobalKey(); await tester.pumpWidget( @@ -494,7 +495,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')).dy, 200); }); - testWidgets('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passes correctly derived index of findChildIndexCallback to the inner SliverChildBuilderDelegate', (WidgetTester tester) async { final List items = [0, 1, 2, 3]; final GlobalKey listKey = GlobalKey(); @@ -556,7 +557,7 @@ void main() { }); }); - testWidgets( + testWidgetsWithLeakTracking( 'AnimatedList.of() and maybeOf called with a context that does not contain AnimatedList', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); @@ -601,7 +602,7 @@ void main() { }, ); - testWidgets('AnimatedList.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList.clipBehavior is forwarded to its inner CustomScrollView', (WidgetTester tester) async { const Clip clipBehavior = Clip.none; await tester.pumpWidget( @@ -625,9 +626,12 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).clipBehavior, clipBehavior); }); - testWidgets('AnimatedList.shrinkwrap is forwarded to its inner CustomScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList.shrinkwrap is forwarded to its inner CustomScrollView', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/115040 final ScrollController controller = ScrollController(); + + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -650,7 +654,7 @@ void main() { expect(tester.widget(find.byType(CustomScrollView)).shrinkWrap, true); }); - testWidgets('AnimatedList applies MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedList applies MediaQuery padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_opacity_repaint_test.dart b/packages/flutter/test/widgets/animated_opacity_repaint_test.dart index d3ce05edd2938..bc9f44653829b 100644 --- a/packages/flutter/test/widgets/animated_opacity_repaint_test.dart +++ b/packages/flutter/test/widgets/animated_opacity_repaint_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('RenderAnimatedOpacityMixin does not drop layer when animating to 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin does not drop layer when animating to 1', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0, end: 1); @@ -40,7 +41,7 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgets('RenderAnimatedOpacityMixin avoids repainting child as it animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin avoids repainting child as it animates', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0, end: 0.99); // Layer is dropped at 1 @@ -73,10 +74,13 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgets('RenderAnimatedOpacityMixin allows opacity layer to be disposed when animating to 0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderAnimatedOpacityMixin allows opacity layer to be disposed when animating to 0 opacity', (WidgetTester tester) async { RenderTestObject.paintCount = 0; final AnimationController controller = AnimationController(vsync: const TestVSync(), duration: const Duration(seconds: 1)); final Tween opacityTween = Tween(begin: 0.99, end: 0); + + addTearDown(controller.dispose); + await tester.pumpWidget( ColoredBox( color: Colors.red, diff --git a/packages/flutter/test/widgets/animated_padding_test.dart b/packages/flutter/test/widgets/animated_padding_test.dart index e8cd37f1073e2..8542efdfd6113 100644 --- a/packages/flutter/test/widgets/animated_padding_test.dart +++ b/packages/flutter/test/widgets/animated_padding_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedPadding.debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding.debugFillProperties', (WidgetTester tester) async { final AnimatedPadding padding = AnimatedPadding( padding: const EdgeInsets.all(7.0), curve: Curves.ease, @@ -16,7 +17,7 @@ void main() { expect(padding, hasOneLineDescription); }); - testWidgets('AnimatedPadding padding visual-to-directional animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding padding visual-to-directional animation', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( @@ -58,7 +59,7 @@ void main() { expect(tester.getTopRight(find.byKey(target)), const Offset(700.0, 0.0)); }); - testWidgets('AnimatedPadding animated padding clamped to positive values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding animated padding clamped to positive values', (WidgetTester tester) async { final Key target = UniqueKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/animated_positioned_test.dart b/packages/flutter/test/widgets/animated_positioned_test.dart index f1a794069a4ce..8d3b5efe73faf 100644 --- a/packages/flutter/test/widgets/animated_positioned_test.dart +++ b/packages/flutter/test/widgets/animated_positioned_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedPositioned.fromRect control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned.fromRect control test', (WidgetTester tester) async { final AnimatedPositioned positioned = AnimatedPositioned.fromRect( rect: const Rect.fromLTWH(7.0, 5.0, 12.0, 16.0), duration: const Duration(milliseconds: 200), @@ -20,7 +21,7 @@ void main() { expect(positioned, hasOneLineDescription); }); - testWidgets('AnimatedPositioned - basics (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned - basics (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -102,7 +103,7 @@ void main() { ); }); - testWidgets('AnimatedPositionedDirectional - basics (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - basics (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -188,7 +189,7 @@ void main() { ); }); - testWidgets('AnimatedPositionedDirectional - basics (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - basics (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -274,7 +275,7 @@ void main() { ); }); - testWidgets('AnimatedPositioned - interrupted animation (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned - interrupted animation (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -357,7 +358,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(200.0, 200.0))); }); - testWidgets('AnimatedPositioned - switching variables (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned - switching variables (VISUAL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -416,7 +417,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(350.0, 150.0))); }); - testWidgets('AnimatedPositionedDirectional - interrupted animation (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - interrupted animation (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -505,7 +506,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(200.0, 200.0))); }); - testWidgets('AnimatedPositionedDirectional - switching variables (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - switching variables (LTR)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -568,7 +569,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(350.0, 150.0))); }); - testWidgets('AnimatedPositionedDirectional - interrupted animation (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - interrupted animation (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; @@ -657,7 +658,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(600.0, 200.0))); }); - testWidgets('AnimatedPositionedDirectional - switching variables (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional - switching variables (RTL)', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); RenderBox box; diff --git a/packages/flutter/test/widgets/animated_size_test.dart b/packages/flutter/test/widgets/animated_size_test.dart index 1e70d3446b8c8..01b75263c33d2 100644 --- a/packages/flutter/test/widgets/animated_size_test.dart +++ b/packages/flutter/test/widgets/animated_size_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestPaintingContext implements PaintingContext { final List invocations = []; @@ -17,7 +18,7 @@ class TestPaintingContext implements PaintingContext { void main() { group('AnimatedSize', () { - testWidgets('animates forwards then backwards with stable-sized children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animates forwards then backwards with stable-sized children', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: AnimatedSize( @@ -87,7 +88,7 @@ void main() { expect(box.size.height, equals(100.0)); }); - testWidgets('clamps animated size to constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clamps animated size to constraints', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: SizedBox ( @@ -132,7 +133,7 @@ void main() { expect(box.size.height, equals(100.0)); }); - testWidgets('tracks unstable child, then resumes animation when child stabilizes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tracks unstable child, then resumes animation when child stabilizes', (WidgetTester tester) async { Future pumpMillis(int millis) async { await tester.pump(Duration(milliseconds: millis)); } @@ -215,7 +216,7 @@ void main() { verify(size: 100.0, state: RenderAnimatedSizeState.stable); }); - testWidgets('resyncs its animation controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('resyncs its animation controller', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: AnimatedSize( @@ -246,7 +247,7 @@ void main() { expect(box.size.width, equals(150.0)); }); - testWidgets('does not run animation unnecessarily', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not run animation unnecessarily', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: AnimatedSize( @@ -269,7 +270,7 @@ void main() { } }); - testWidgets('can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: AnimatedSize( @@ -303,7 +304,7 @@ void main() { } }); - testWidgets('works wrapped in IntrinsicHeight and Wrap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works wrapped in IntrinsicHeight and Wrap', (WidgetTester tester) async { Future pumpWidget(Size size, [Duration? duration]) async { return tester.pumpWidget( Center( @@ -350,7 +351,7 @@ void main() { expect(tester.renderObject(find.byType(IntrinsicHeight)).size, const Size(222, 222)); }); - testWidgets('re-attach with interrupted animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('re-attach with interrupted animation', (WidgetTester tester) async { const Key key1 = ValueKey('key1'); const Key key2 = ValueKey('key2'); late StateSetter setState; diff --git a/packages/flutter/test/widgets/animated_switcher_test.dart b/packages/flutter/test/widgets/animated_switcher_test.dart index 0d914cb73ed9c..70de6e294d385 100644 --- a/packages/flutter/test/widgets/animated_switcher_test.dart +++ b/packages/flutter/test/widgets/animated_switcher_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('AnimatedSwitcher fades in a new child.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher fades in a new child.', (WidgetTester tester) async { final UniqueKey containerOne = UniqueKey(); final UniqueKey containerTwo = UniqueKey(); final UniqueKey containerThree = UniqueKey(); @@ -50,7 +51,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('AnimatedSwitcher can handle back-to-back changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher can handle back-to-back changes.', (WidgetTester tester) async { final UniqueKey container1 = UniqueKey(); final UniqueKey container2 = UniqueKey(); final UniqueKey container3 = UniqueKey(); @@ -85,7 +86,7 @@ void main() { expect(find.byKey(container3), findsOneWidget); }); - testWidgets("AnimatedSwitcher doesn't transition in a new child of the same type.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("AnimatedSwitcher doesn't transition in a new child of the same type.", (WidgetTester tester) async { await tester.pumpWidget( AnimatedSwitcher( duration: const Duration(milliseconds: 100), @@ -111,7 +112,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('AnimatedSwitcher handles null children.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher handles null children.', (WidgetTester tester) async { await tester.pumpWidget( const AnimatedSwitcher( duration: Duration(milliseconds: 100), @@ -166,7 +167,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets("AnimatedSwitcher doesn't start any animations after dispose.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("AnimatedSwitcher doesn't start any animations after dispose.", (WidgetTester tester) async { await tester.pumpWidget(AnimatedSwitcher( duration: const Duration(milliseconds: 100), child: Container(color: const Color(0xff000000)), @@ -178,7 +179,7 @@ void main() { expect(await tester.pumpAndSettle(), equals(1)); }); - testWidgets('AnimatedSwitcher uses custom layout.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher uses custom layout.', (WidgetTester tester) async { Widget newLayoutBuilder(Widget? currentChild, List previousChildren) { return Column( children: [ @@ -199,7 +200,7 @@ void main() { expect(find.byType(Column), findsOneWidget); }); - testWidgets('AnimatedSwitcher uses custom transitions.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher uses custom transitions.', (WidgetTester tester) async { late List foundChildren; Widget newLayoutBuilder(Widget? currentChild, List previousChildren) { foundChildren = [ @@ -254,7 +255,7 @@ void main() { } }); - testWidgets("AnimatedSwitcher doesn't reset state of the children in transitions.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("AnimatedSwitcher doesn't reset state of the children in transitions.", (WidgetTester tester) async { final UniqueKey statefulOne = UniqueKey(); final UniqueKey statefulTwo = UniqueKey(); final UniqueKey statefulThree = UniqueKey(); @@ -305,7 +306,7 @@ void main() { expect(StatefulTestState.generation, equals(3)); }); - testWidgets('AnimatedSwitcher updates widgets without animating if they are isomorphic.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher updates widgets without animating if they are isomorphic.', (WidgetTester tester) async { Future pumpChild(Widget child) async { return tester.pumpWidget( Directionality( @@ -332,7 +333,7 @@ void main() { expect(find.text('2'), findsOneWidget); }); - testWidgets('AnimatedSwitcher updates previous child transitions if the transitionBuilder changes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher updates previous child transitions if the transitionBuilder changes.', (WidgetTester tester) async { final UniqueKey containerOne = UniqueKey(); final UniqueKey containerTwo = UniqueKey(); final UniqueKey containerThree = UniqueKey(); @@ -416,7 +417,7 @@ void main() { } }); - testWidgets('AnimatedSwitcher does not duplicate animations if the same child is entered twice.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSwitcher does not duplicate animations if the same child is entered twice.', (WidgetTester tester) async { Future pumpChild(Widget child) async { return tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/annotated_region_test.dart b/packages/flutter/test/widgets/annotated_region_test.dart index ec159c90a11aa..66ab89b630354 100644 --- a/packages/flutter/test/widgets/annotated_region_test.dart +++ b/packages/flutter/test/widgets/annotated_region_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('provides a value to the layer tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('provides a value to the layer tree', (WidgetTester tester) async { await tester.pumpWidget( const AnnotatedRegion( value: 1, @@ -18,7 +19,8 @@ void main() { final AnnotatedRegionLayer layer = layers.whereType>().first; expect(layer.value, 1); }); - testWidgets('provides a value to the layer tree in a particular region', (WidgetTester tester) async { + + testWidgetsWithLeakTracking('provides a value to the layer tree in a particular region', (WidgetTester tester) async { await tester.pumpWidget( Transform.translate( offset: const Offset(25.0, 25.0), diff --git a/packages/flutter/test/widgets/app_lifecycle_listener_test.dart b/packages/flutter/test/widgets/app_lifecycle_listener_test.dart index a93b97628b37e..d704785804b3b 100644 --- a/packages/flutter/test/widgets/app_lifecycle_listener_test.dart +++ b/packages/flutter/test/widgets/app_lifecycle_listener_test.dart @@ -7,6 +7,7 @@ import 'dart:ui'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { late AppLifecycleListener listener; @@ -47,13 +48,13 @@ void main() { 'There were ${TestAppLifecycleListener.registerCount} listeners that were not disposed of in tests.'); }); - testWidgets('Default Diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default Diagnostics', (WidgetTester tester) async { listener = TestAppLifecycleListener(binding: tester.binding); expect(listener.toString(), equalsIgnoringHashCodes('TestAppLifecycleListener#00000(binding: )')); }); - testWidgets('Diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Diagnostics', (WidgetTester tester) async { Future handleExitRequested() async { return AppExitResponse.cancel; } @@ -69,7 +70,7 @@ void main() { 'TestAppLifecycleListener#00000(binding: , onStateChange, onExitRequested)')); }); - testWidgets('listens to AppLifecycleState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('listens to AppLifecycleState', (WidgetTester tester) async { final List states = [tester.binding.lifecycleState!]; void stateChange(AppLifecycleState state) { states.add(state); @@ -95,7 +96,7 @@ void main() { ])); }); - testWidgets('Triggers correct state transition callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Triggers correct state transition callbacks', (WidgetTester tester) async { final List transitions = []; listener = TestAppLifecycleListener( binding: WidgetsBinding.instance, @@ -148,7 +149,7 @@ void main() { await setAppLifeCycleState(AppLifecycleState.detached); }); - testWidgets('Receives exit requests', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Receives exit requests', (WidgetTester tester) async { bool exitRequested = false; Future handleExitRequested() async { exitRequested = true; diff --git a/packages/flutter/test/widgets/app_navigator_key_test.dart b/packages/flutter/test/widgets/app_navigator_key_test.dart index a989516e14347..57c959329038b 100644 --- a/packages/flutter/test/widgets/app_navigator_key_test.dart +++ b/packages/flutter/test/widgets/app_navigator_key_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Route generateRoute(RouteSettings settings) => PageRouteBuilder( settings: settings, @@ -13,7 +14,7 @@ Route generateRoute(RouteSettings settings) => PageRouteBuilder( ); void main() { - testWidgets('WidgetsApp.navigatorKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp.navigatorKey', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(WidgetsApp( navigatorKey: key, diff --git a/packages/flutter/test/widgets/app_overrides_test.dart b/packages/flutter/test/widgets/app_overrides_test.dart index 66a7a1c6c0c57..601db0b84c394 100644 --- a/packages/flutter/test/widgets/app_overrides_test.dart +++ b/packages/flutter/test/widgets/app_overrides_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestRoute extends PageRoute { TestRoute({ required this.child, super.settings }); @@ -40,7 +41,7 @@ Future pumpApp(WidgetTester tester) async { } void main() { - testWidgets('WidgetsApp control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp control test', (WidgetTester tester) async { await pumpApp(tester); expect(find.byType(WidgetsApp), findsOneWidget); expect(find.byType(Navigator), findsOneWidget); @@ -48,7 +49,7 @@ void main() { expect(find.byType(CheckedModeBanner), findsOneWidget); }); - testWidgets('showPerformanceOverlayOverride true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showPerformanceOverlayOverride true', (WidgetTester tester) async { expect(WidgetsApp.showPerformanceOverlayOverride, false); WidgetsApp.showPerformanceOverlayOverride = true; await pumpApp(tester); @@ -59,7 +60,7 @@ void main() { WidgetsApp.showPerformanceOverlayOverride = false; }); - testWidgets('showPerformanceOverlayOverride false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showPerformanceOverlayOverride false', (WidgetTester tester) async { WidgetsApp.showPerformanceOverlayOverride = true; expect(WidgetsApp.showPerformanceOverlayOverride, true); WidgetsApp.showPerformanceOverlayOverride = false; @@ -70,7 +71,7 @@ void main() { expect(find.byType(CheckedModeBanner), findsOneWidget); }); - testWidgets('debugAllowBannerOverride false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugAllowBannerOverride false', (WidgetTester tester) async { expect(WidgetsApp.showPerformanceOverlayOverride, false); expect(WidgetsApp.debugAllowBannerOverride, true); WidgetsApp.debugAllowBannerOverride = false; @@ -82,7 +83,7 @@ void main() { WidgetsApp.debugAllowBannerOverride = true; // restore to default value }); - testWidgets('debugAllowBannerOverride true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugAllowBannerOverride true', (WidgetTester tester) async { WidgetsApp.debugAllowBannerOverride = false; expect(WidgetsApp.showPerformanceOverlayOverride, false); expect(WidgetsApp.debugAllowBannerOverride, false); diff --git a/packages/flutter/test/widgets/app_test.dart b/packages/flutter/test/widgets/app_test.dart index 3540930d1026f..d6274ce11e19b 100644 --- a/packages/flutter/test/widgets/app_test.dart +++ b/packages/flutter/test/widgets/app_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestIntent extends Intent { const TestIntent(); @@ -23,7 +24,7 @@ class TestAction extends Action { } void main() { - testWidgets('WidgetsApp with builder only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp with builder only', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( WidgetsApp( @@ -37,7 +38,7 @@ void main() { expect(find.byKey(key), findsOneWidget); }); - testWidgets('WidgetsApp default key bindings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp default key bindings', (WidgetTester tester) async { bool? checked = false; final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -64,7 +65,7 @@ void main() { expect(checked, isTrue); }); - testWidgets('WidgetsApp can override default key bindings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp can override default key bindings', (WidgetTester tester) async { final TestAction action = TestAction(); bool? checked = false; final GlobalKey key = GlobalKey(); @@ -101,7 +102,7 @@ void main() { expect(action.calls, equals(1)); }); - testWidgets('WidgetsApp default activation key mappings work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp default activation key mappings work', (WidgetTester tester) async { bool? checked = false; await tester.pumpWidget( @@ -168,7 +169,7 @@ void main() { } } - testWidgets('push unknown route when onUnknownRoute is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('push unknown route when onUnknownRoute is null', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); expectFlutterError( key: key, @@ -196,7 +197,7 @@ void main() { ); }); - testWidgets('push unknown route when onUnknownRoute returns null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('push unknown route when onUnknownRoute returns null', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); expectFlutterError( key: key, @@ -218,7 +219,7 @@ void main() { }); }); - testWidgets('WidgetsApp can customize initial routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp can customize initial routes', (WidgetTester tester) async { final GlobalKey navigatorKey = GlobalKey(); await tester.pumpWidget( WidgetsApp( @@ -271,12 +272,13 @@ void main() { expect(find.text('regular page'), findsNothing); }); - testWidgets('WidgetsApp.router works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp.router works', (WidgetTester tester) async { final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( uri: Uri.parse('initial'), ), ); + addTearDown(provider.dispose); final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -288,6 +290,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); await tester.pumpWidget(WidgetsApp.router( routeInformationProvider: provider, routeInformationParser: SimpleRouteInformationParser(), @@ -301,9 +304,14 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('WidgetsApp.router route information parser is optional', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + notDisposedAllowList: {'_RestorableRouteInformation': 1}, + )); + + testWidgetsWithLeakTracking('WidgetsApp.router route information parser is optional', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -315,6 +323,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); await tester.pumpWidget(WidgetsApp.router( routerDelegate: delegate, @@ -327,9 +336,14 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('WidgetsApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + notDisposedAllowList: {'_RestorableRouteInformation': 1}, + )); + + testWidgetsWithLeakTracking('WidgetsApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -341,12 +355,14 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( uri: Uri.parse('initial'), ), ); + addTearDown(provider.dispose); await expectLater(() async { await tester.pumpWidget(WidgetsApp.router( routeInformationProvider: provider, @@ -356,7 +372,7 @@ void main() { }, throwsAssertionError); }); - testWidgets('WidgetsApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -368,6 +384,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); final RouterConfig routerConfig = RouterConfig(routerDelegate: delegate); await expectLater(() async { @@ -379,25 +396,29 @@ void main() { }, throwsAssertionError); }); - testWidgets('WidgetsApp.router router config works', (WidgetTester tester) async { - final RouterConfig routerConfig = RouterConfig( - routeInformationProvider: PlatformRouteInformationProvider( - initialRouteInformation: RouteInformation( - uri: Uri.parse('initial'), - ), + testWidgetsWithLeakTracking('WidgetsApp.router router config works', (WidgetTester tester) async { + final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( + builder: (BuildContext context, RouteInformation information) { + return Text(information.uri.toString()); + }, + onPopPage: (Route route, void result, SimpleNavigatorRouterDelegate delegate) { + delegate.routeInformation = RouteInformation( + uri: Uri.parse('popped'), + ); + return route.didPop(result); + }, + ); + addTearDown(delegate.dispose); + final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( + initialRouteInformation: RouteInformation( + uri: Uri.parse('initial'), ), + ); + addTearDown(provider.dispose); + final RouterConfig routerConfig = RouterConfig( + routeInformationProvider: provider, routeInformationParser: SimpleRouteInformationParser(), - routerDelegate: SimpleNavigatorRouterDelegate( - builder: (BuildContext context, RouteInformation information) { - return Text(information.uri.toString()); - }, - onPopPage: (Route route, void result, SimpleNavigatorRouterDelegate delegate) { - delegate.routeInformation = RouteInformation( - uri: Uri.parse('popped'), - ); - return route.didPop(result); - }, - ), + routerDelegate: delegate, backButtonDispatcher: RootBackButtonDispatcher() ); await tester.pumpWidget(WidgetsApp.router( @@ -411,24 +432,35 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('WidgetsApp.router has correct default', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + notDisposedAllowList: {'_RestorableRouteInformation': 1}, + )); + + testWidgetsWithLeakTracking('WidgetsApp.router has correct default', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); }, onPopPage: (Route route, Object? result, SimpleNavigatorRouterDelegate delegate) => true, ); + addTearDown(delegate.dispose); await tester.pumpWidget(WidgetsApp.router( routeInformationParser: SimpleRouteInformationParser(), routerDelegate: delegate, color: const Color(0xFF123456), )); expect(find.text('/'), findsOneWidget); - }); - - testWidgets('WidgetsApp has correct default ScrollBehavior', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(someone): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + notDisposedAllowList: {'_RestorableRouteInformation': 1}, + )); + + testWidgetsWithLeakTracking('WidgetsApp has correct default ScrollBehavior', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( WidgetsApp( @@ -569,7 +601,7 @@ void main() { ); }); - testWidgets("WidgetsApp reports an exception if the selected locale isn't supported", (WidgetTester tester) async { + testWidgetsWithLeakTracking("WidgetsApp reports an exception if the selected locale isn't supported", (WidgetTester tester) async { late final List? localesArg; late final Iterable supportedLocalesArg; await tester.pumpWidget( @@ -593,7 +625,7 @@ void main() { expect(tester.takeException(), "Warning: This application's locale, C_UTF-8, is not supported by all of its localization delegates."); }); - testWidgets("WidgetsApp doesn't have dependency on MediaQuery", (WidgetTester tester) async { + testWidgetsWithLeakTracking("WidgetsApp doesn't have dependency on MediaQuery", (WidgetTester tester) async { int routeBuildCount = 0; final Widget widget = WidgetsApp( @@ -619,8 +651,10 @@ void main() { expect(routeBuildCount, equals(1)); }); - testWidgets('WidgetsApp provides meta based shortcuts for iOS and macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp provides meta based shortcuts for iOS and macOS', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + final SelectAllSpy selectAllSpy = SelectAllSpy(); final CopySpy copySpy = CopySpy(); final PasteSpy pasteSpy = PasteSpy(); @@ -710,7 +744,7 @@ void main() { await setAppLifeCycleState(AppLifecycleState.resumed); }); - testWidgets('WidgetsApp calls setFrameworkHandlesBack only when app is ready', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp calls setFrameworkHandlesBack only when app is ready', (WidgetTester tester) async { // Start in the `resumed` state, where setFrameworkHandlesBack should be // called like normal. await setAppLifeCycleState(AppLifecycleState.resumed); diff --git a/packages/flutter/test/widgets/app_title_test.dart b/packages/flutter/test/widgets/app_title_test.dart index 7cddafb6d56ea..1528c3c6c12a1 100644 --- a/packages/flutter/test/widgets/app_title_test.dart +++ b/packages/flutter/test/widgets/app_title_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Color kTitleColor = Color(0xFF333333); const String kTitleString = 'Hello World'; @@ -30,13 +31,13 @@ Future pumpApp(WidgetTester tester, { GenerateAppTitle? onGenerateTitle, C } void main() { - testWidgets('Specified title and color are used to build a Title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Specified title and color are used to build a Title', (WidgetTester tester) async { await pumpApp(tester); expect(tester.widget(find.byType(Title)).title, kTitleString); expect(tester.widget<Title>(find.byType(Title)).color, kTitleColor); }); - testWidgets('Specified color is made opaque for Title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Specified color is made opaque for Title', (WidgetTester tester) async { // The Title widget can only handle fully opaque colors, the WidgetApp should // ensure it only uses a fully opaque version of its color for the title. const Color transparentBlue = Color(0xDD0000ff); @@ -45,7 +46,7 @@ void main() { expect(tester.widget<Title>(find.byType(Title)).color, opaqueBlue); }); - testWidgets('onGenerateTitle handles changing locales', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onGenerateTitle handles changing locales', (WidgetTester tester) async { String generateTitle(BuildContext context) { return Localizations.localeOf(context).toString(); } diff --git a/packages/flutter/test/widgets/aspect_ratio_test.dart b/packages/flutter/test/widgets/aspect_ratio_test.dart index b103f381cf909..f480fa37cee97 100644 --- a/packages/flutter/test/widgets/aspect_ratio_test.dart +++ b/packages/flutter/test/widgets/aspect_ratio_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Future<Size> _getSize(WidgetTester tester, BoxConstraints constraints, double aspectRatio) async { final Key childKey = UniqueKey(); @@ -25,12 +26,12 @@ Future<Size> _getSize(WidgetTester tester, BoxConstraints constraints, double as } void main() { - testWidgets('Aspect ratio control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Aspect ratio control test', (WidgetTester tester) async { expect(await _getSize(tester, BoxConstraints.loose(const Size(500.0, 500.0)), 2.0), equals(const Size(500.0, 250.0))); expect(await _getSize(tester, BoxConstraints.loose(const Size(500.0, 500.0)), 0.5), equals(const Size(250.0, 500.0))); }); - testWidgets('Aspect ratio infinite width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Aspect ratio infinite width', (WidgetTester tester) async { final Key childKey = UniqueKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/async_test.dart b/packages/flutter/test/widgets/async_test.dart index 9c685412061aa..c3eb815cc00d3 100644 --- a/packages/flutter/test/widgets/async_test.dart +++ b/packages/flutter/test/widgets/async_test.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { Widget snapshotText(BuildContext context, AsyncSnapshot<String> snapshot) { @@ -66,21 +67,21 @@ void main() { }); }); group('Async smoke tests', () { - testWidgets('FutureBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FutureBuilder', (WidgetTester tester) async { await tester.pumpWidget(FutureBuilder<String>( future: Future<String>.value('hello'), builder: snapshotText, )); await eventFiring(tester); }); - testWidgets('StreamBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StreamBuilder', (WidgetTester tester) async { await tester.pumpWidget(StreamBuilder<String>( stream: Stream<String>.fromIterable(<String>['hello', 'world']), builder: snapshotText, )); await eventFiring(tester); }); - testWidgets('StreamFold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StreamFold', (WidgetTester tester) async { await tester.pumpWidget(StringCollector( stream: Stream<String>.fromIterable(<String>['hello', 'world']), )); @@ -88,7 +89,7 @@ void main() { }); }); group('FutureBuilder', () { - testWidgets('gives expected snapshot with SynchronousFuture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gives expected snapshot with SynchronousFuture', (WidgetTester tester) async { final SynchronousFuture<String> future = SynchronousFuture<String>('flutter'); await tester.pumpWidget(FutureBuilder<String>( future: future, @@ -102,7 +103,7 @@ void main() { )); }); - testWidgets('gracefully handles transition from null future', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition from null future', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(FutureBuilder<String>( key: key, builder: snapshotText, future: null, @@ -114,7 +115,7 @@ void main() { )); expect(find.text('AsyncSnapshot<String>(ConnectionState.waiting, null, null, null)'), findsOneWidget); }); - testWidgets('gracefully handles transition to null future', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition to null future', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final Completer<String> completer = Completer<String>(); await tester.pumpWidget(FutureBuilder<String>( @@ -129,7 +130,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.none, null, null, null)'), findsOneWidget); }); - testWidgets('gracefully handles transition to other future', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition to other future', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final Completer<String> completerA = Completer<String>(); final Completer<String> completerB = Completer<String>(); @@ -146,7 +147,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, B, null, null)'), findsOneWidget); }); - testWidgets('tracks life-cycle of Future to success', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tracks life-cycle of Future to success', (WidgetTester tester) async { final Completer<String> completer = Completer<String>(); await tester.pumpWidget(FutureBuilder<String>( future: completer.future, builder: snapshotText, @@ -156,7 +157,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, hello, null, null)'), findsOneWidget); }); - testWidgets('tracks life-cycle of Future to error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tracks life-cycle of Future to error', (WidgetTester tester) async { final Completer<String> completer = Completer<String>(); await tester.pumpWidget(FutureBuilder<String>( future: completer.future, builder: snapshotText, @@ -166,7 +167,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, null, bad, trace)'), findsOneWidget); }); - testWidgets('runs the builder using given initial data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('runs the builder using given initial data', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(FutureBuilder<String>( key: key, @@ -176,7 +177,7 @@ void main() { )); expect(find.text('AsyncSnapshot<String>(ConnectionState.none, I, null, null)'), findsOneWidget); }); - testWidgets('ignores initialData when reconfiguring', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores initialData when reconfiguring', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(FutureBuilder<String>( key: key, @@ -194,7 +195,7 @@ void main() { )); expect(find.text('AsyncSnapshot<String>(ConnectionState.waiting, I, null, null)'), findsOneWidget); }); - testWidgets('debugRethrowError rethrows caught error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugRethrowError rethrows caught error', (WidgetTester tester) async { FutureBuilder.debugRethrowError = true; final Completer<void> caughtError = Completer<void>(); await runZonedGuarded(() async { @@ -214,7 +215,7 @@ void main() { }); }); group('StreamBuilder', () { - testWidgets('gracefully handles transition from null stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition from null stream', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(StreamBuilder<String>( key: key, builder: snapshotText, stream: null, @@ -226,7 +227,7 @@ void main() { )); expect(find.text('AsyncSnapshot<String>(ConnectionState.waiting, null, null, null)'), findsOneWidget); }); - testWidgets('gracefully handles transition to null stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition to null stream', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final StreamController<String> controller = StreamController<String>(); await tester.pumpWidget(StreamBuilder<String>( @@ -238,7 +239,7 @@ void main() { )); expect(find.text('AsyncSnapshot<String>(ConnectionState.none, null, null, null)'), findsOneWidget); }); - testWidgets('gracefully handles transition to other stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition to other stream', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final StreamController<String> controllerA = StreamController<String>(); final StreamController<String> controllerB = StreamController<String>(); @@ -254,7 +255,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.active, B, null, null)'), findsOneWidget); }); - testWidgets('tracks events and errors of stream until completion', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tracks events and errors of stream until completion', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final StreamController<String> controller = StreamController<String>(); await tester.pumpWidget(StreamBuilder<String>( @@ -274,7 +275,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, 4, null, null)'), findsOneWidget); }); - testWidgets('runs the builder using given initial data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('runs the builder using given initial data', (WidgetTester tester) async { final StreamController<String> controller = StreamController<String>(); await tester.pumpWidget(StreamBuilder<String>( stream: controller.stream, @@ -283,7 +284,7 @@ void main() { )); expect(find.text('AsyncSnapshot<String>(ConnectionState.waiting, I, null, null)'), findsOneWidget); }); - testWidgets('ignores initialData when reconfiguring', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores initialData when reconfiguring', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(StreamBuilder<String>( key: key, @@ -303,7 +304,7 @@ void main() { }); }); group('FutureBuilder and StreamBuilder behave identically on Stream from Future', () { - testWidgets('when completing with data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when completing with data', (WidgetTester tester) async { final Completer<String> completer = Completer<String>(); await tester.pumpWidget(Column(children: <Widget>[ FutureBuilder<String>(future: completer.future, builder: snapshotText), @@ -314,7 +315,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, hello, null, null)'), findsNWidgets(2)); }); - testWidgets('when completing with error and with empty stack trace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when completing with error and with empty stack trace', (WidgetTester tester) async { final Completer<String> completer = Completer<String>(); await tester.pumpWidget(Column(children: <Widget>[ FutureBuilder<String>(future: completer.future, builder: snapshotText), @@ -325,7 +326,7 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, null, bad, )'), findsNWidgets(2)); }); - testWidgets('when completing with error and with stack trace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when completing with error and with stack trace', (WidgetTester tester) async { final Completer<String> completer = Completer<String>(); await tester.pumpWidget(Column(children: <Widget>[ FutureBuilder<String>(future: completer.future, builder: snapshotText), @@ -336,21 +337,21 @@ void main() { await eventFiring(tester); expect(find.text('AsyncSnapshot<String>(ConnectionState.done, null, bad, trace)'), findsNWidgets(2)); }); - testWidgets('when Future is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when Future is null', (WidgetTester tester) async { await tester.pumpWidget(Column(children: <Widget>[ FutureBuilder<String>(builder: snapshotText, future: null), StreamBuilder<String>(builder: snapshotText, stream: null,), ])); expect(find.text('AsyncSnapshot<String>(ConnectionState.none, null, null, null)'), findsNWidgets(2)); }); - testWidgets('when initialData is used with null Future and Stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when initialData is used with null Future and Stream', (WidgetTester tester) async { await tester.pumpWidget(Column(children: <Widget>[ FutureBuilder<String>(builder: snapshotText, initialData: 'I', future: null), StreamBuilder<String>(builder: snapshotText, initialData: 'I', stream: null), ])); expect(find.text('AsyncSnapshot<String>(ConnectionState.none, I, null, null)'), findsNWidgets(2)); }); - testWidgets('when using initialData and completing with data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when using initialData and completing with data', (WidgetTester tester) async { final Completer<String> completer = Completer<String>(); await tester.pumpWidget(Column(children: <Widget>[ FutureBuilder<String>(future: completer.future, builder: snapshotText, initialData: 'I'), @@ -363,7 +364,7 @@ void main() { }); }); group('StreamBuilderBase', () { - testWidgets('gracefully handles transition from null stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition from null stream', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(StringCollector(key: key)); expect(find.text(''), findsOneWidget); @@ -371,7 +372,7 @@ void main() { await tester.pumpWidget(StringCollector(key: key, stream: controller.stream)); expect(find.text('conn'), findsOneWidget); }); - testWidgets('gracefully handles transition to null stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition to null stream', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final StreamController<String> controller = StreamController<String>(); await tester.pumpWidget(StringCollector(key: key, stream: controller.stream)); @@ -379,7 +380,7 @@ void main() { await tester.pumpWidget(StringCollector(key: key)); expect(find.text('conn, disc'), findsOneWidget); }); - testWidgets('gracefully handles transition to other stream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('gracefully handles transition to other stream', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final StreamController<String> controllerA = StreamController<String>(); final StreamController<String> controllerB = StreamController<String>(); @@ -390,7 +391,7 @@ void main() { await eventFiring(tester); expect(find.text('conn, disc, conn, data:B'), findsOneWidget); }); - testWidgets('tracks events and errors until completion', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tracks events and errors until completion', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final StreamController<String> controller = StreamController<String>(); await tester.pumpWidget(StringCollector(key: key, stream: controller.stream)); diff --git a/packages/flutter/test/widgets/autocomplete_test.dart b/packages/flutter/test/widgets/autocomplete_test.dart index cbedb27c76977..adcac0830525a 100644 --- a/packages/flutter/test/widgets/autocomplete_test.dart +++ b/packages/flutter/test/widgets/autocomplete_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class User { const User({ @@ -45,7 +46,7 @@ void main() { User(name: 'Charlie', email: 'charlie123@gmail.com'), ]; - testWidgets('can filter and select a list of string options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can filter and select a list of string options', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -129,7 +130,7 @@ void main() { expect(lastOptions.elementAt(5), 'northern white rhinoceros'); }); - testWidgets('tapping on an option selects it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tapping on an option selects it', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -199,7 +200,7 @@ void main() { expect(textEditingController.text, equals(kOptions[2])); }); - testWidgets('can filter and select a list of custom User options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can filter and select a list of custom User options', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<User> lastOptions; @@ -277,7 +278,7 @@ void main() { expect(lastOptions.elementAt(0), kOptionsUsers[1]); }); - testWidgets('can specify a custom display string for a list of custom User options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can specify a custom display string for a list of custom User options', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<User> lastOptions; @@ -360,7 +361,7 @@ void main() { expect(lastOptions.elementAt(0), kOptionsUsers[1]); }); - testWidgets('onFieldSubmitted selects the first option', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onFieldSubmitted selects the first option', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -422,7 +423,7 @@ void main() { }); group('optionsViewOpenDirection', () { - testWidgets('unset (default behavior): open downward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('unset (default behavior): open downward', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -445,7 +446,7 @@ void main() { offsetMoreOrLessEquals(tester.getTopLeft(find.text('a')))); }); - testWidgets('down: open downward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('down: open downward', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -469,7 +470,7 @@ void main() { offsetMoreOrLessEquals(tester.getTopLeft(find.text('a')))); }); - testWidgets('up: open upward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('up: open upward', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -494,10 +495,12 @@ void main() { }); group('fieldViewBuilder not passed', () { - testWidgets('down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('down', (WidgetTester tester) async { final GlobalKey autocompleteKey = GlobalKey(); final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -525,10 +528,12 @@ void main() { offsetMoreOrLessEquals(tester.getTopLeft(find.text('a')))); }); - testWidgets('up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('up', (WidgetTester tester) async { final GlobalKey autocompleteKey = GlobalKey(); final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -559,7 +564,7 @@ void main() { }); }); - testWidgets('options follow field when it moves', (WidgetTester tester) async { + testWidgetsWithLeakTracking('options follow field when it moves', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late StateSetter setState; @@ -633,7 +638,7 @@ void main() { expect(optionsOffsetOpen.dy, fieldOffset.dy + fieldSize.height); }); - testWidgets('can prevent options from showing by returning an empty iterable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can prevent options from showing by returning an empty iterable', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -696,13 +701,15 @@ void main() { expect(lastOptions.elementAt(1), 'elephant'); }); - testWidgets('can create a field outside of fieldViewBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can create a field outside of fieldViewBuilder', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); final GlobalKey autocompleteKey = GlobalKey(); late Iterable<String> lastOptions; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final TextEditingController textEditingController = TextEditingController(); + addTearDown(textEditingController.dispose); await tester.pumpWidget( MaterialApp( @@ -762,7 +769,7 @@ void main() { expect(textEditingController.text, lastOptions.elementAt(0)); }); - testWidgets('initialValue sets initial text field value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialValue sets initial text field value', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -822,9 +829,11 @@ void main() { expect(textEditingController.text, selection); }); - testWidgets('initialValue cannot be defined if TextEditingController is defined', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialValue cannot be defined if TextEditingController is defined', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final TextEditingController textEditingController = TextEditingController(); + addTearDown(textEditingController.dispose); expect( () { @@ -854,7 +863,7 @@ void main() { ); }); - testWidgets('support asynchronous options builder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('support asynchronous options builder', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late FocusNode focusNode; @@ -915,7 +924,7 @@ void main() { expect(lastOptions, <String>['dingo', 'flamingo']); }); - testWidgets('can navigate options with the keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can navigate options with the keyboard', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -1001,7 +1010,7 @@ void main() { expect(textEditingController.text, 'goose'); }); - testWidgets('can hide and show options with the keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can hide and show options with the keyboard', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -1091,7 +1100,7 @@ void main() { expect(find.byKey(optionsKey), findsNothing); }); - testWidgets('re-invokes DismissIntent if options not shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('re-invokes DismissIntent if options not shown', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late FocusNode focusNode; @@ -1150,7 +1159,7 @@ void main() { expect(wrappingActionInvoked, true); }); - testWidgets('optionsViewBuilders can use AutocompleteHighlightedOption to highlight selected option', (WidgetTester tester) async { + testWidgetsWithLeakTracking('optionsViewBuilders can use AutocompleteHighlightedOption to highlight selected option', (WidgetTester tester) async { final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); late Iterable<String> lastOptions; @@ -1231,7 +1240,7 @@ void main() { expect(lastHighlighted, 5); }); - testWidgets('floating menu goes away on select', (WidgetTester tester) async { + testWidgetsWithLeakTracking('floating menu goes away on select', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/99749. final GlobalKey fieldKey = GlobalKey(); final GlobalKey optionsKey = GlobalKey(); diff --git a/packages/flutter/test/widgets/autofill_group_test.dart b/packages/flutter/test/widgets/autofill_group_test.dart index 9721fca8a588d..3ac6b860744ee 100644 --- a/packages/flutter/test/widgets/autofill_group_test.dart +++ b/packages/flutter/test/widgets/autofill_group_test.dart @@ -4,12 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; final Matcher _matchesCommit = isMethodCall('TextInput.finishAutofillContext', arguments: true); final Matcher _matchesCancel = isMethodCall('TextInput.finishAutofillContext', arguments: false); void main() { - testWidgets('AutofillGroup has the right clients', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutofillGroup has the right clients', (WidgetTester tester) async { const Key outerKey = Key('outer'); const Key innerKey = Key('inner'); @@ -44,7 +45,7 @@ void main() { expect(innerState.autofillClients.toList(), <State<TextField>>[clientState2]); }); - testWidgets('new clients can be added & removed to a scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('new clients can be added & removed to a scope', (WidgetTester tester) async { const Key scopeKey = Key('scope'); const TextField client1 = TextField(autofillHints: <String>['1']); @@ -92,7 +93,7 @@ void main() { expect(scopeState.autofillClients, <State<TextField>>[clientState1]); }); - testWidgets('AutofillGroup has the right clients after reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutofillGroup has the right clients after reparenting', (WidgetTester tester) async { const Key outerKey = Key('outer'); const Key innerKey = Key('inner'); final GlobalKey keyClient3 = GlobalKey(); @@ -151,7 +152,7 @@ void main() { expect(innerState.autofillClients, <State<TextField>>[clientState2]); }); - testWidgets('disposing AutofillGroups', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disposing AutofillGroups', (WidgetTester tester) async { late StateSetter setState; const Key group1 = Key('group1'); const Key group2 = Key('group2'); diff --git a/packages/flutter/test/widgets/automatic_keep_alive_test.dart b/packages/flutter/test/widgets/automatic_keep_alive_test.dart index 5869793871fc4..60bf9e7cf588d 100644 --- a/packages/flutter/test/widgets/automatic_keep_alive_test.dart +++ b/packages/flutter/test/widgets/automatic_keep_alive_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Leaf extends StatefulWidget { const Leaf({ required Key key, required this.child }) : super(key: key); @@ -21,7 +22,7 @@ class _LeafState extends State<Leaf> { @override void deactivate() { - _handle?.release(); + _handle?.dispose(); _handle = null; super.deactivate(); } @@ -34,7 +35,7 @@ class _LeafState extends State<Leaf> { KeepAliveNotification(_handle!).dispatch(context); } } else { - _handle?.release(); + _handle?.dispose(); _handle = null; } } @@ -67,7 +68,7 @@ List<Widget> generateList(Widget child, { required bool impliedMode }) { } void tests({ required bool impliedMode }) { - testWidgets('AutomaticKeepAlive with ListView with itemExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive with ListView with itemExtent', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -115,7 +116,7 @@ void tests({ required bool impliedMode }) { expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing); }); - testWidgets('AutomaticKeepAlive with ListView without itemExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive with ListView without itemExtent', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -165,7 +166,7 @@ void tests({ required bool impliedMode }) { expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing); }); - testWidgets('AutomaticKeepAlive with GridView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive with GridView', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -222,7 +223,7 @@ void main() { group('Explicit automatic keep-alive', () { tests(impliedMode: false); }); group('Implied automatic keep-alive', () { tests(impliedMode: true); }); - testWidgets('AutomaticKeepAlive double', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive double', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -306,7 +307,7 @@ void main() { expect(find.byKey(const GlobalObjectKey<_LeafState>(3)), findsOneWidget); }); - testWidgets('AutomaticKeepAlive double 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive double 2', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -474,7 +475,7 @@ void main() { expect(find.byKey(const GlobalObjectKey<_LeafState>(0), skipOffstage: false), findsNothing); }); - testWidgets('AutomaticKeepAlive with keepAlive set to true before initState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive with keepAlive set to true before initState', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( @@ -509,7 +510,7 @@ void main() { expect(find.text('FooBar 2'), findsNothing); }); - testWidgets('AutomaticKeepAlive with keepAlive set to true before initState and widget goes out of scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive with keepAlive set to true before initState and widget goes out of scope', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( @@ -548,19 +549,22 @@ void main() { expect(find.text('FooBar 73'), findsOneWidget); }); - testWidgets('AutomaticKeepAlive with SliverKeepAliveWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AutomaticKeepAlive with SliverKeepAliveWidget', (WidgetTester tester) async { // We're just doing a basic test here to make sure that the functionality of // RenderSliverWithKeepAliveMixin doesn't get regressed or deleted. As testing // the full functionality would be cumbersome. final RenderSliverMultiBoxAdaptorAlt alternate = RenderSliverMultiBoxAdaptorAlt(); + addTearDown(alternate.dispose); final RenderBox child = RenderBoxKeepAlive(); + addTearDown(child.dispose); alternate.insert(child); expect(alternate.children.length, 1); }); - testWidgets('Keep alive Listenable has its listener removed once called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keep alive Listenable has its listener removed once called', (WidgetTester tester) async { final LeakCheckerHandle handle = LeakCheckerHandle(); + addTearDown(handle.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( diff --git a/packages/flutter/test/widgets/backdrop_filter_test.dart b/packages/flutter/test/widgets/backdrop_filter_test.dart index a112fe9e666c8..9fc7e9cb4f384 100644 --- a/packages/flutter/test/widgets/backdrop_filter_test.dart +++ b/packages/flutter/test/widgets/backdrop_filter_test.dart @@ -11,9 +11,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets("Material2 - BackdropFilter's cull rect does not shrink", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Material2 - BackdropFilter's cull rect does not shrink", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -51,7 +52,7 @@ void main() { ); }); - testWidgets("Material3 - BackdropFilter's cull rect does not shrink", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Material3 - BackdropFilter's cull rect does not shrink", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), @@ -89,7 +90,7 @@ void main() { ); }); - testWidgets('Material2 - BackdropFilter blendMode on saveLayer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - BackdropFilter blendMode on saveLayer', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -148,7 +149,7 @@ void main() { ); }); - testWidgets('Material3 - BackdropFilter blendMode on saveLayer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - BackdropFilter blendMode on saveLayer', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: true), diff --git a/packages/flutter/test/widgets/banner_test.dart b/packages/flutter/test/widgets/banner_test.dart index 2282d73143911..ca3d32b9df068 100644 --- a/packages/flutter/test/widgets/banner_test.dart +++ b/packages/flutter/test/widgets/banner_test.dart @@ -6,6 +6,7 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestCanvas implements Canvas { final List<Invocation> invocations = <Invocation>[]; @@ -245,7 +246,7 @@ void main() { expect(rotateCommand.positionalArguments[0], equals(math.pi / 4.0)); }); - testWidgets('Banner widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Banner widget', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget( const Directionality( @@ -265,7 +266,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('Banner widget in MaterialApp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Banner widget in MaterialApp', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget(const MaterialApp(home: Placeholder())); expect(find.byType(CheckedModeBanner), paints diff --git a/packages/flutter/test/widgets/baseline_test.dart b/packages/flutter/test/widgets/baseline_test.dart index 707707fdc8fa4..912f639163330 100644 --- a/packages/flutter/test/widgets/baseline_test.dart +++ b/packages/flutter/test/widgets/baseline_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Baseline - control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Baseline - control test', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: DefaultTextStyle( @@ -20,7 +21,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.text('X')).size, const Size(100.0, 100.0)); }); - testWidgets('Baseline - position test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Baseline - position test', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: Baseline( @@ -43,7 +44,7 @@ void main() { ); }); - testWidgets('Chip caches baseline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip caches baseline', (WidgetTester tester) async { int calls = 0; await tester.pumpWidget( MaterialApp( @@ -68,7 +69,7 @@ void main() { expect(calls, 2); }); - testWidgets('ListTile caches baseline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile caches baseline', (WidgetTester tester) async { int calls = 0; await tester.pumpWidget( MaterialApp( @@ -93,7 +94,7 @@ void main() { expect(calls, 2); }); - testWidgets("LayoutBuilder returns child's baseline", (WidgetTester tester) async { + testWidgetsWithLeakTracking("LayoutBuilder returns child's baseline", (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( diff --git a/packages/flutter/test/widgets/basic_test.dart b/packages/flutter/test/widgets/basic_test.dart index 86782c7700f09..b3d97f690a7e9 100644 --- a/packages/flutter/test/widgets/basic_test.dart +++ b/packages/flutter/test/widgets/basic_test.dart @@ -15,12 +15,13 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { group('RawImage', () { - testWidgets('properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properties', (WidgetTester tester) async { final ui.Image image1 = (await tester.runAsync<ui.Image>(() => createTestImage()))!; await tester.pumpWidget( @@ -110,7 +111,7 @@ void main() { }); group('PhysicalShape', () { - testWidgets('properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('properties', (WidgetTester tester) async { await tester.pumpWidget( const PhysicalShape( clipper: ShapeBorderClipper(shape: CircleBorder()), @@ -126,7 +127,7 @@ void main() { expect(renderObject.elevation, 2.0); }); - testWidgets('hit test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hit test', (WidgetTester tester) async { await tester.pumpWidget( PhysicalShape( clipper: const ShapeBorderClipper(shape: CircleBorder()), @@ -156,7 +157,7 @@ void main() { }); group('FractionalTranslation', () { - testWidgets('hit test - entirely inside the bounding box', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hit test - entirely inside the bounding box', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); bool pointerDown = false; @@ -185,7 +186,7 @@ void main() { expect(pointerDown, isTrue); }); - testWidgets('hit test - partially inside the bounding box', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hit test - partially inside the bounding box', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); bool pointerDown = false; @@ -214,7 +215,7 @@ void main() { expect(pointerDown, isTrue); }); - testWidgets('hit test - completely outside the bounding box', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hit test - completely outside the bounding box', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); bool pointerDown = false; @@ -243,7 +244,7 @@ void main() { expect(pointerDown, isTrue); }); - testWidgets('semantics bounds are updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics bounds are updated', (WidgetTester tester) async { final GlobalKey fractionalTranslationKey = GlobalKey(); final GlobalKey textKey = GlobalKey(); Offset offset = const Offset(0.4, 0.4); @@ -307,7 +308,7 @@ void main() { }); group('Semantics', () { - testWidgets('Semantics can set attributed Text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics can set attributed Text', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -358,7 +359,7 @@ void main() { expect(attributedHint.attributes[0].range, const TextRange(start:1, end: 2)); }); - testWidgets('Semantics can merge attributed strings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics can merge attributed strings', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -413,7 +414,7 @@ void main() { expect(attributedHint.attributes[1].range, const TextRange(start:6, end: 7)); }); - testWidgets('Semantics can merge attributed strings with non attributed string', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics can merge attributed strings with non attributed string', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -453,7 +454,7 @@ void main() { }); group('Row', () { - testWidgets('multiple baseline aligned children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiple baseline aligned children', (WidgetTester tester) async { final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); // The point size of the font must be a multiple of 4 until @@ -507,7 +508,7 @@ void main() { expect(tester.getTopLeft(find.byKey(key2)).dy, aboveBaseline1 - aboveBaseline2); }); - testWidgets('baseline aligned children account for a larger, no-baseline child size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('baseline aligned children account for a larger, no-baseline child size', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/58898 final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); @@ -575,7 +576,7 @@ void main() { ); }); - testWidgets('UnconstrainedBox can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UnconstrainedBox can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(const UnconstrainedBox()); final RenderConstraintsTransformBox renderObject = tester.allRenderObjects.whereType<RenderConstraintsTransformBox>().first; expect(renderObject.clipBehavior, equals(Clip.none)); @@ -584,7 +585,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('UnconstrainedBox warns only when clipBehavior is Clip.none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UnconstrainedBox warns only when clipBehavior is Clip.none', (WidgetTester tester) async { for (final Clip? clip in <Clip?>[null, ...Clip.values]) { // Clear any render objects that were there before so that we can see more // than one error. Otherwise, it just throws the first one and skips the @@ -660,7 +661,7 @@ void main() { mockCanvas = mockContext.canvas; }); - testWidgets('ColoredBox - no size, no child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ColoredBox - no size, no child', (WidgetTester tester) async { await tester.pumpWidget(const Flex( direction: Axis.horizontal, textDirection: TextDirection.ltr, @@ -681,7 +682,7 @@ void main() { expect(mockContext.offsets, isEmpty); }); - testWidgets('ColoredBox - no size, child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ColoredBox - no size, child', (WidgetTester tester) async { const ValueKey<int> key = ValueKey<int>(0); const Widget child = SizedBox.expand(key: key); await tester.pumpWidget(const Flex( @@ -705,7 +706,7 @@ void main() { expect(mockContext.offsets.single, Offset.zero); }); - testWidgets('ColoredBox - size, no child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ColoredBox - size, no child', (WidgetTester tester) async { await tester.pumpWidget(const ColoredBox(color: colorToPaint)); expect(find.byType(ColoredBox), findsOneWidget); final RenderObject renderColoredBox = tester.renderObject(find.byType(ColoredBox)); @@ -718,7 +719,7 @@ void main() { expect(mockContext.offsets, isEmpty); }); - testWidgets('ColoredBox - size, child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ColoredBox - size, child', (WidgetTester tester) async { const ValueKey<int> key = ValueKey<int>(0); const Widget child = SizedBox.expand(key: key); await tester.pumpWidget(const ColoredBox(color: colorToPaint, child: child)); @@ -734,7 +735,7 @@ void main() { expect(mockContext.offsets.single, Offset.zero); }); - testWidgets('ColoredBox - debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ColoredBox - debugFillProperties', (WidgetTester tester) async { const ColoredBox box = ColoredBox(color: colorToPaint); final DiagnosticPropertiesBuilder properties = DiagnosticPropertiesBuilder(); box.debugFillProperties(properties); @@ -742,7 +743,7 @@ void main() { expect(properties.properties.first.value, colorToPaint); }); }); - testWidgets('Inconsequential golden test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inconsequential golden test', (WidgetTester tester) async { // The test validates the Flutter Gold integration. Any changes to the // golden file can be approved at any time. await tester.pumpWidget(RepaintBoundary( @@ -758,7 +759,7 @@ void main() { ); }); - testWidgets('IgnorePointer ignores pointers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IgnorePointer ignores pointers', (WidgetTester tester) async { final List<String> logs = <String>[]; Widget target({required bool ignoring}) => Align( alignment: Alignment.topLeft, @@ -836,7 +837,7 @@ void main() { }); group('IgnorePointer semantics', () { - testWidgets('does not change semantics when not ignoring', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not change semantics when not ignoring', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -863,7 +864,7 @@ void main() { ); }); - testWidgets('can toggle the ignoring.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can toggle the ignoring.', (WidgetTester tester) async { final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); final UniqueKey key3 = UniqueKey(); @@ -982,7 +983,7 @@ void main() { ); }); - testWidgets('drops semantics when its ignoringSemantics is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drops semantics when its ignoringSemantics is true', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final UniqueKey key = UniqueKey(); await tester.pumpWidget( @@ -1001,7 +1002,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignores user interactions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores user interactions', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1028,7 +1029,7 @@ void main() { }); }); - testWidgets('AbsorbPointer absorbs pointers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AbsorbPointer absorbs pointers', (WidgetTester tester) async { final List<String> logs = <String>[]; Widget target({required bool absorbing}) => Align( alignment: Alignment.topLeft, @@ -1105,7 +1106,7 @@ void main() { logs.clear(); }); - testWidgets('Wrap implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const Wrap( spacing: 8.0, // gap between adjacent Text widget @@ -1136,7 +1137,7 @@ void main() { ])); }); - testWidgets('Row and IgnoreBaseline (control -- with baseline)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row and IgnoreBaseline (control -- with baseline)', (WidgetTester tester) async { await tester.pumpWidget( const Row( crossAxisAlignment: CrossAxisAlignment.baseline, @@ -1163,7 +1164,7 @@ void main() { expect(bPos.dy, 96.0 - 24.0); }); - testWidgets('Row and IgnoreBaseline (with ignored baseline)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row and IgnoreBaseline (with ignored baseline)', (WidgetTester tester) async { await tester.pumpWidget( const Row( crossAxisAlignment: CrossAxisAlignment.baseline, diff --git a/packages/flutter/test/widgets/binding_deferred_first_frame_test.dart b/packages/flutter/test/widgets/binding_deferred_first_frame_test.dart index dc7208c5dd17a..afac6ff2a4894 100644 --- a/packages/flutter/test/widgets/binding_deferred_first_frame_test.dart +++ b/packages/flutter/test/widgets/binding_deferred_first_frame_test.dart @@ -8,12 +8,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const String _actualContent = 'Actual Content'; const String _loading = 'Loading...'; void main() { - testWidgets('deferFirstFrame/allowFirstFrame stops sending frames to engine', (WidgetTester tester) async { + testWidgetsWithLeakTracking('deferFirstFrame/allowFirstFrame stops sending frames to engine', (WidgetTester tester) async { expect(RendererBinding.instance.sendFramesToEngine, isTrue); final Completer<void> completer = Completer<void>(); @@ -50,7 +51,7 @@ void main() { expect(RendererBinding.instance.sendFramesToEngine, isTrue); }); - testWidgets('Two widgets can defer frames', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Two widgets can defer frames', (WidgetTester tester) async { expect(RendererBinding.instance.sendFramesToEngine, isTrue); final Completer<void> completer1 = Completer<void>(); diff --git a/packages/flutter/test/widgets/binding_test.dart b/packages/flutter/test/widgets/binding_test.dart index b42df5fe09430..d0ded5fb100d3 100644 --- a/packages/flutter/test/widgets/binding_test.dart +++ b/packages/flutter/test/widgets/binding_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class MemoryPressureObserver with WidgetsBindingObserver { bool sawMemoryPressure = false; @@ -143,7 +144,7 @@ void main() { .handlePlatformMessage('flutter/lifecycle', message, (_) { }); } - testWidgets('Rentrant observer callbacks do not result in exceptions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rentrant observer callbacks do not result in exceptions', (WidgetTester tester) async { final RentrantObserver observer = RentrantObserver(); WidgetsBinding.instance.handleAccessibilityFeaturesChanged(); WidgetsBinding.instance.handleAppLifecycleStateChanged(AppLifecycleState.resumed); @@ -160,7 +161,7 @@ void main() { expect(observer.removeSelf(), 0); }); - testWidgets('didHaveMemoryPressure callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didHaveMemoryPressure callback', (WidgetTester tester) async { final MemoryPressureObserver observer = MemoryPressureObserver(); WidgetsBinding.instance.addObserver(observer); final ByteData message = const JSONMessageCodec().encodeMessage(<String, dynamic>{'type': 'memoryPressure'})!; @@ -169,7 +170,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('handleLifecycleStateChanged callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handleLifecycleStateChanged callback', (WidgetTester tester) async { final AppLifecycleStateObserver observer = AppLifecycleStateObserver(); WidgetsBinding.instance.addObserver(observer); @@ -228,7 +229,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('didPushRoute callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didPushRoute callback', (WidgetTester tester) async { final PushRouteObserver observer = PushRouteObserver(); WidgetsBinding.instance.addObserver(observer); @@ -240,7 +241,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('didPushRouteInformation calls didPushRoute by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didPushRouteInformation calls didPushRoute by default', (WidgetTester tester) async { final PushRouteObserver observer = PushRouteObserver(); WidgetsBinding.instance.addObserver(observer); @@ -258,7 +259,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('didPushRouteInformation calls didPushRoute correctly when handling url', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didPushRouteInformation calls didPushRoute correctly when handling url', (WidgetTester tester) async { final PushRouteObserver observer = PushRouteObserver(); WidgetsBinding.instance.addObserver(observer); @@ -290,7 +291,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('didPushRouteInformation callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didPushRouteInformation callback', (WidgetTester tester) async { final PushRouteInformationObserver observer = PushRouteInformationObserver(); WidgetsBinding.instance.addObserver(observer); @@ -307,7 +308,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('didPushRouteInformation callback can handle url', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didPushRouteInformation callback can handle url', (WidgetTester tester) async { final PushRouteInformationObserver observer = PushRouteInformationObserver(); WidgetsBinding.instance.addObserver(observer); @@ -325,7 +326,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('didPushRouteInformation callback with null state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didPushRouteInformation callback with null state', (WidgetTester tester) async { final PushRouteInformationObserver observer = PushRouteInformationObserver(); WidgetsBinding.instance.addObserver(observer); @@ -343,7 +344,7 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); - testWidgets('Application lifecycle affects frame scheduling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Application lifecycle affects frame scheduling', (WidgetTester tester) async { expect(tester.binding.hasScheduledFrame, isFalse); await setAppLifeCycleState(AppLifecycleState.paused); @@ -397,7 +398,7 @@ void main() { await tester.pump(); }); - testWidgets('scheduleFrameCallback error control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scheduleFrameCallback error control test', (WidgetTester tester) async { late FlutterError error; try { tester.binding.scheduleFrameCallback((Duration _) { }, rescheduling: true); @@ -429,7 +430,7 @@ void main() { ); }); - testWidgets('defaultStackFilter elides framework Element mounting stacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('defaultStackFilter elides framework Element mounting stacks', (WidgetTester tester) async { final FlutterExceptionHandler? oldHandler = FlutterError.onError; late FlutterErrorDetails errorDetails; FlutterError.onError = (FlutterErrorDetails details) { diff --git a/packages/flutter/test/widgets/box_decoration_test.dart b/packages/flutter/test/widgets/box_decoration_test.dart index 031006439d7f2..f21a9b33118b5 100644 --- a/packages/flutter/test/widgets/box_decoration_test.dart +++ b/packages/flutter/test/widgets/box_decoration_test.dart @@ -9,6 +9,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; @@ -36,7 +37,7 @@ Future<void> main() async { AutomatedTestWidgetsFlutterBinding(); TestImageProvider.image = await decodeImageFromList(Uint8List.fromList(kTransparentImage)); - testWidgets('DecoratedBox handles loading images', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedBox handles loading images', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final Completer<void> completer = Completer<void>(); await tester.pumpWidget( @@ -59,7 +60,7 @@ Future<void> main() async { expect(tester.binding.hasScheduledFrame, isFalse); }); - testWidgets('Moving a DecoratedBox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a DecoratedBox', (WidgetTester tester) async { final Completer<void> completer = Completer<void>(); final Widget subtree = KeyedSubtree( key: GlobalKey(), @@ -88,7 +89,7 @@ Future<void> main() async { expect(tester.binding.hasScheduledFrame, isFalse); }); - testWidgets('Circles can have uniform borders', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Circles can have uniform borders', (WidgetTester tester) async { await tester.pumpWidget( Container( padding: const EdgeInsets.all(50.0), @@ -101,7 +102,7 @@ Future<void> main() async { ); }); - testWidgets('Bordered Container insets its child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Bordered Container insets its child', (WidgetTester tester) async { const Key key = Key('outerContainer'); await tester.pumpWidget( Center( @@ -118,7 +119,7 @@ Future<void> main() async { expect(tester.getSize(find.byKey(key)), equals(const Size(45.0, 45.0))); }); - testWidgets('BoxDecoration paints its border correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxDecoration paints its border correctly', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/7672 const Key key = Key('Container with BoxDecoration'); @@ -169,7 +170,7 @@ Future<void> main() async { ); }); - testWidgets('BoxDecoration paints its border correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxDecoration paints its border correctly', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/12165 await tester.pumpWidget( Column( @@ -254,7 +255,7 @@ Future<void> main() async { ); }); - testWidgets('Can hit test on BoxDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can hit test on BoxDecoration', (WidgetTester tester) async { late List<int> itemsTapped; @@ -291,7 +292,7 @@ Future<void> main() async { }); - testWidgets('Can hit test on BoxDecoration circle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can hit test on BoxDecoration circle', (WidgetTester tester) async { late List<int> itemsTapped; @@ -331,7 +332,7 @@ Future<void> main() async { }); - testWidgets('Can hit test on BoxDecoration border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can hit test on BoxDecoration border', (WidgetTester tester) async { late List<int> itemsTapped; const Key key = Key('Container with BoxDecoration'); Widget buildFrame(Border border) { @@ -369,7 +370,7 @@ Future<void> main() async { expect(itemsTapped, <int>[1,1]); }); - testWidgets('BoxDecoration not tap outside rounded angles - Top Left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxDecoration not tap outside rounded angles - Top Left', (WidgetTester tester) async { const double height = 50.0; const double width = 50.0; const double radius = 12.3; @@ -429,7 +430,7 @@ Future<void> main() async { }); - testWidgets('BoxDecoration tap inside rounded angles - Top Left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxDecoration tap inside rounded angles - Top Left', (WidgetTester tester) async { const double height = 50.0; const double width = 50.0; const double radius = 12.3; @@ -477,7 +478,7 @@ Future<void> main() async { expect(itemsTapped, <int>[1,1,1,1]); }); - testWidgets('BoxDecoration rounded angles other corner works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxDecoration rounded angles other corner works', (WidgetTester tester) async { const double height = 50.0; const double width = 50.0; const double radius = 20; @@ -545,7 +546,7 @@ Future<void> main() async { expect(itemsTapped, <int>[1,1,1,1,1], reason: 'top left tapped'); }); - testWidgets("BoxDecoration doesn't crash with BorderRadiusDirectional", (WidgetTester tester) async { + testWidgetsWithLeakTracking("BoxDecoration doesn't crash with BorderRadiusDirectional", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/88039 await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/build_context_test.dart b/packages/flutter/test/widgets/build_context_test.dart index f6b78aa8b5c69..77650f640a957 100644 --- a/packages/flutter/test/widgets/build_context_test.dart +++ b/packages/flutter/test/widgets/build_context_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('StatefulWidget BuildContext.mounted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StatefulWidget BuildContext.mounted', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget(TestStatefulWidget( onBuild: (BuildContext context) { @@ -18,7 +19,7 @@ void main() { expect(capturedContext.mounted, isFalse); }); - testWidgets('StatelessWidget BuildContext.mounted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StatelessWidget BuildContext.mounted', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget(TestStatelessWidget( onBuild: (BuildContext context) { diff --git a/packages/flutter/test/widgets/build_scope_test.dart b/packages/flutter/test/widgets/build_scope_test.dart index 8fb7a786c31b2..8cb0802da9da6 100644 --- a/packages/flutter/test/widgets/build_scope_test.dart +++ b/packages/flutter/test/widgets/build_scope_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; @@ -133,7 +134,7 @@ class Wrapper extends StatelessWidget { } void main() { - testWidgets('Legal times for setState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Legal times for setState', (WidgetTester tester) async { final GlobalKey flipKey = GlobalKey(); expect(ProbeWidgetState.buildCount, equals(0)); await tester.pumpWidget(const ProbeWidget(key: Key('a'))); @@ -171,7 +172,7 @@ void main() { expect(tester.takeException(), isNotNull); }); - testWidgets('Dirty element list sort order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dirty element list sort order', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: 'key1'); final GlobalKey key2 = GlobalKey(debugLabel: 'key2'); diff --git a/packages/flutter/test/widgets/center_test.dart b/packages/flutter/test/widgets/center_test.dart index 5d32e3deb46fd..6cdb8d504eefb 100644 --- a/packages/flutter/test/widgets/center_test.dart +++ b/packages/flutter/test/widgets/center_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can be placed in an infinite box', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be placed in an infinite box', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/clamp_overscrolls_test.dart b/packages/flutter/test/widgets/clamp_overscrolls_test.dart index 03457a9dd8bb4..856648f0aa095 100644 --- a/packages/flutter/test/widgets/clamp_overscrolls_test.dart +++ b/packages/flutter/test/widgets/clamp_overscrolls_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // Assuming that the test container is 800x600. The height of the // viewport's contents is 650.0, the top and bottom text children @@ -32,7 +33,7 @@ Widget buildFrame(ScrollPhysics physics, { ScrollController? scrollController }) } void main() { - testWidgets('ClampingScrollPhysics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClampingScrollPhysics', (WidgetTester tester) async { // Scroll the target text widget by offset and then return its origin // in global coordinates. @@ -59,7 +60,7 @@ void main() { expect(origin.dy, equals(500.0)); }); - testWidgets('ClampingScrollPhysics affects ScrollPosition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClampingScrollPhysics affects ScrollPosition', (WidgetTester tester) async { // BouncingScrollPhysics @@ -91,9 +92,10 @@ void main() { expect(scrollable.position.pixels, equals(50.0)); }); - testWidgets('ClampingScrollPhysics handles out of bounds ScrollPosition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClampingScrollPhysics handles out of bounds ScrollPosition', (WidgetTester tester) async { Future<void> testOutOfBounds(ScrollPhysics physics, double initialOffset, double expectedOffset) async { final ScrollController scrollController = ScrollController(initialScrollOffset: initialOffset); + addTearDown(scrollController.dispose); await tester.pumpWidget(buildFrame(physics, scrollController: scrollController)); final ScrollableState scrollable = tester.state(find.byType(Scrollable)); diff --git a/packages/flutter/test/widgets/clip_test.dart b/packages/flutter/test/widgets/clip_test.dart index a959fa047cc49..b9e3e64b90fe4 100644 --- a/packages/flutter/test/widgets/clip_test.dart +++ b/packages/flutter/test/widgets/clip_test.dart @@ -11,6 +11,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_border.dart' show TestBorder; @@ -58,7 +59,7 @@ class NotifyClipper<T> extends CustomClipper<T> { } void main() { - testWidgets('ClipRect with a FittedBox child sized to zero works with semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRect with a FittedBox child sized to zero works with semantics', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ClipRect( @@ -77,7 +78,7 @@ void main() { expect(find.byType(FittedBox), findsOneWidget); }); - testWidgets('ClipRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async { await tester.pumpWidget(const ClipRect()); final RenderClipRect renderClip = tester.allRenderObjects.whereType<RenderClipRect>().first; @@ -99,7 +100,7 @@ void main() { expect(clipRRect.borderRadius, equals(BorderRadius.zero)); }); - testWidgets('ClipRRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRRect updates clipBehavior in updateRenderObject', (WidgetTester tester) async { await tester.pumpWidget(const ClipRRect()); final RenderClipRRect renderClip = tester.allRenderObjects.whereType<RenderClipRRect>().first; @@ -115,7 +116,7 @@ void main() { expect(renderClip.clipBehavior, equals(Clip.none)); }); - testWidgets('ClipOval updates clipBehavior in updateRenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipOval updates clipBehavior in updateRenderObject', (WidgetTester tester) async { await tester.pumpWidget(const ClipOval()); final RenderClipOval renderClip = tester.allRenderObjects.whereType<RenderClipOval>().first; @@ -131,7 +132,7 @@ void main() { expect(renderClip.clipBehavior, equals(Clip.none)); }); - testWidgets('ClipPath updates clipBehavior in updateRenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipPath updates clipBehavior in updateRenderObject', (WidgetTester tester) async { await tester.pumpWidget(const ClipPath()); final RenderClipPath renderClip = tester.allRenderObjects.whereType<RenderClipPath>().first; @@ -147,7 +148,7 @@ void main() { expect(renderClip.clipBehavior, equals(Clip.none)); }); - testWidgets('ClipPath', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipPath', (WidgetTester tester) async { await tester.pumpWidget( ClipPath( clipper: PathClipper(), @@ -168,7 +169,7 @@ void main() { log.clear(); }); - testWidgets('ClipOval', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipOval', (WidgetTester tester) async { await tester.pumpWidget( ClipOval( child: GestureDetector( @@ -188,7 +189,7 @@ void main() { log.clear(); }); - testWidgets('Transparent ClipOval hit test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Transparent ClipOval hit test', (WidgetTester tester) async { await tester.pumpWidget( Opacity( opacity: 0.0, @@ -211,7 +212,7 @@ void main() { log.clear(); }); - testWidgets('ClipRect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRect', (WidgetTester tester) async { await tester.pumpWidget( Align( alignment: Alignment.topLeft, @@ -334,7 +335,7 @@ void main() { log.clear(); }); - testWidgets('debugPaintSizeEnabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugPaintSizeEnabled', (WidgetTester tester) async { await tester.pumpWidget( const ClipRect( child: Placeholder(), @@ -356,7 +357,7 @@ void main() { debugPaintSizeEnabled = false; }); - testWidgets('ClipRect painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRect painting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -399,7 +400,7 @@ void main() { ); }); - testWidgets('ClipRect save, overlay, and antialiasing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRect save, overlay, and antialiasing', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary( child: Stack( @@ -438,7 +439,7 @@ void main() { ); }); - testWidgets('ClipRRect painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRRect painting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -487,7 +488,7 @@ void main() { ); }); - testWidgets('ClipOval painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipOval painting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -530,7 +531,7 @@ void main() { ); }); - testWidgets('ClipPath painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipPath painting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -615,7 +616,7 @@ void main() { ); } - testWidgets('PhysicalModel painting with Clip.antiAlias', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalModel painting with Clip.antiAlias', (WidgetTester tester) async { await tester.pumpWidget(genPhysicalModel(Clip.antiAlias)); await expectLater( find.byType(RepaintBoundary).first, @@ -623,7 +624,7 @@ void main() { ); }); - testWidgets('PhysicalModel painting with Clip.hardEdge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalModel painting with Clip.hardEdge', (WidgetTester tester) async { await tester.pumpWidget(genPhysicalModel(Clip.hardEdge)); await expectLater( find.byType(RepaintBoundary).first, @@ -633,7 +634,7 @@ void main() { // There will be bleeding edges on the rect edges, but there shouldn't be any bleeding edges on the // round corners. - testWidgets('PhysicalModel painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalModel painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async { await tester.pumpWidget(genPhysicalModel(Clip.antiAliasWithSaveLayer)); await expectLater( find.byType(RepaintBoundary).first, @@ -641,7 +642,7 @@ void main() { ); }); - testWidgets('Default PhysicalModel painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default PhysicalModel painting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -724,7 +725,7 @@ void main() { ); } - testWidgets('PhysicalShape painting with Clip.antiAlias', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalShape painting with Clip.antiAlias', (WidgetTester tester) async { await tester.pumpWidget(genPhysicalShape(Clip.antiAlias)); await expectLater( find.byType(RepaintBoundary).first, @@ -732,7 +733,7 @@ void main() { ); }); - testWidgets('PhysicalShape painting with Clip.hardEdge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalShape painting with Clip.hardEdge', (WidgetTester tester) async { await tester.pumpWidget(genPhysicalShape(Clip.hardEdge)); await expectLater( find.byType(RepaintBoundary).first, @@ -740,7 +741,7 @@ void main() { ); }); - testWidgets('PhysicalShape painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalShape painting with Clip.antiAliasWithSaveLayer', (WidgetTester tester) async { await tester.pumpWidget(genPhysicalShape(Clip.antiAliasWithSaveLayer)); await expectLater( find.byType(RepaintBoundary).first, @@ -748,7 +749,7 @@ void main() { ); }); - testWidgets('PhysicalShape painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalShape painting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -794,7 +795,7 @@ void main() { ); }); - testWidgets('ClipPath.shape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipPath.shape', (WidgetTester tester) async { final List<String> logs = <String>[]; final ShapeBorder shape = TestBorder((String message) { logs.add(message); }); Widget buildClipPath() { @@ -851,8 +852,9 @@ void main() { ]); }); - testWidgets('CustomClipper reclips when notified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomClipper reclips when notified', (WidgetTester tester) async { final ValueNotifier<Rect> clip = ValueNotifier<Rect>(const Rect.fromLTWH(50.0, 50.0, 100.0, 100.0)); + addTearDown(clip.dispose); await tester.pumpWidget( ClipRect( @@ -884,7 +886,7 @@ void main() { ); }); - testWidgets('ClipRRect supports BorderRadiusDirectional', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRRect supports BorderRadiusDirectional', (WidgetTester tester) async { const Radius startRadius = Radius.circular(15.0); const Radius endRadius = Radius.circular(30.0); @@ -911,7 +913,7 @@ void main() { } }); - testWidgets('ClipRRect is direction-aware', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ClipRRect is direction-aware', (WidgetTester tester) async { const Radius startRadius = Radius.circular(15.0); const Radius endRadius = Radius.circular(30.0); TextDirection textDirection = TextDirection.ltr; diff --git a/packages/flutter/test/widgets/color_filter_test.dart b/packages/flutter/test/widgets/color_filter_test.dart index 3135844c03db0..fa512f682b672 100644 --- a/packages/flutter/test/widgets/color_filter_test.dart +++ b/packages/flutter/test/widgets/color_filter_test.dart @@ -11,9 +11,10 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Color filter - red', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Color filter - red', (WidgetTester tester) async { await tester.pumpWidget( const RepaintBoundary( child: ColorFiltered( @@ -28,7 +29,7 @@ void main() { ); }); - testWidgets('Color filter - sepia', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Color filter - sepia', (WidgetTester tester) async { const ColorFilter sepia = ColorFilter.matrix(<double>[ 0.39, 0.769, 0.189, 0, 0, // 0.349, 0.686, 0.168, 0, 0, // @@ -65,7 +66,7 @@ void main() { ); }); - testWidgets('Color filter - reuses its layer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Color filter - reuses its layer', (WidgetTester tester) async { Future<void> pumpWithColor(Color color) async { await tester.pumpWidget( RepaintBoundary( diff --git a/packages/flutter/test/widgets/column_test.dart b/packages/flutter/test/widgets/column_test.dart index 7f86f285e9f45..1b45f093d1477 100644 --- a/packages/flutter/test/widgets/column_test.dart +++ b/packages/flutter/test/widgets/column_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // DOWN (default) - testWidgets('Column with one flexible child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with one flexible child', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -55,7 +56,7 @@ void main() { expect(boxParentData.offset.dy, equals(500.0)); }); - testWidgets('Column with default main axis parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with default main axis parameters', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -101,7 +102,7 @@ void main() { expect(boxParentData.offset.dy, equals(200.0)); }); - testWidgets('Column with MainAxisAlignment.center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.center', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -139,7 +140,7 @@ void main() { expect(boxParentData.offset.dy, equals(300.0)); }); - testWidgets('Column with MainAxisAlignment.end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.end', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -185,7 +186,7 @@ void main() { expect(boxParentData.offset.dy, equals(500.0)); }); - testWidgets('Column with MainAxisAlignment.spaceBetween', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.spaceBetween', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -231,7 +232,7 @@ void main() { expect(boxParentData.offset.dy, equals(500.0)); }); - testWidgets('Column with MainAxisAlignment.spaceAround', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.spaceAround', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -285,7 +286,7 @@ void main() { expect(boxParentData.offset.dy, equals(475.0)); }); - testWidgets('Column with MainAxisAlignment.spaceEvenly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.spaceEvenly', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -331,7 +332,7 @@ void main() { expect(boxParentData.offset.dy, equals(445.0)); }); - testWidgets('Column and MainAxisSize.min', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column and MainAxisSize.min', (WidgetTester tester) async { const Key flexKey = Key('flexKey'); // Default is MainAxisSize.max so the Column should be as high as the test: 600. @@ -364,7 +365,7 @@ void main() { expect(renderBox.size.height, equals(250.0)); }); - testWidgets('Column MainAxisSize.min layout at zero size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column MainAxisSize.min layout at zero size', (WidgetTester tester) async { const Key childKey = Key('childKey'); await tester.pumpWidget(const Center( @@ -390,7 +391,7 @@ void main() { // UP - testWidgets('Column with one flexible child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with one flexible child', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -437,7 +438,7 @@ void main() { expect(boxParentData.offset.dy, equals(0.0)); }); - testWidgets('Column with default main axis parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with default main axis parameters', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -484,7 +485,7 @@ void main() { expect(boxParentData.offset.dy, equals(300.0)); }); - testWidgets('Column with MainAxisAlignment.center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.center', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -523,7 +524,7 @@ void main() { expect(boxParentData.offset.dy, equals(200.0)); }); - testWidgets('Column with MainAxisAlignment.end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.end', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -570,7 +571,7 @@ void main() { expect(boxParentData.offset.dy, equals(0.0)); }); - testWidgets('Column with MainAxisAlignment.spaceBetween', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.spaceBetween', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -617,7 +618,7 @@ void main() { expect(boxParentData.offset.dy, equals(0.0)); }); - testWidgets('Column with MainAxisAlignment.spaceAround', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.spaceAround', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -672,7 +673,7 @@ void main() { expect(boxParentData.offset.dy, equals(500.0 - 475.0)); }); - testWidgets('Column with MainAxisAlignment.spaceEvenly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column with MainAxisAlignment.spaceEvenly', (WidgetTester tester) async { const Key columnKey = Key('column'); const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -719,7 +720,7 @@ void main() { expect(boxParentData.offset.dy, equals(600.0 - 445.0 - 20.0)); }); - testWidgets('Column and MainAxisSize.min', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column and MainAxisSize.min', (WidgetTester tester) async { const Key flexKey = Key('flexKey'); // Default is MainAxisSize.max so the Column should be as high as the test: 600. @@ -754,7 +755,7 @@ void main() { expect(renderBox.size.height, equals(250.0)); }); - testWidgets('Column MainAxisSize.min layout at zero size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Column MainAxisSize.min layout at zero size', (WidgetTester tester) async { const Key childKey = Key('childKey'); await tester.pumpWidget(const Center( diff --git a/packages/flutter/test/widgets/composited_transform_test.dart b/packages/flutter/test/widgets/composited_transform_test.dart index f46294f3046e8..319702c277c94 100644 --- a/packages/flutter/test/widgets/composited_transform_test.dart +++ b/packages/flutter/test/widgets/composited_transform_test.dart @@ -7,11 +7,12 @@ import 'dart:ui' as ui; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { final LayerLink link = LayerLink(); - testWidgets('Change link during layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Change link during layout', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); Widget build({ LayerLink? linkToUse }) { return Directionality( @@ -56,7 +57,7 @@ void main() { expect(box.localToGlobal(Offset.zero), const Offset(118.0, 451.0)); }); - testWidgets('LeaderLayer should not cause error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LeaderLayer should not cause error', (WidgetTester tester) async { final LayerLink link = LayerLink(); Widget buildWidget({ @@ -116,19 +117,19 @@ void main() { ); } - testWidgets('topLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('topLeft', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.topLeft, followerAlignment: Alignment.topLeft)); final RenderBox box = key.currentContext!.findRenderObject()! as RenderBox; expect(box.localToGlobal(Offset.zero), const Offset(123.0, 456.0)); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.center, followerAlignment: Alignment.center)); final RenderBox box = key.currentContext!.findRenderObject()! as RenderBox; expect(box.localToGlobal(Offset.zero), const Offset(118.0, 451.0)); }); - testWidgets('bottomRight - topRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bottomRight - topRight', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.bottomRight, followerAlignment: Alignment.topRight)); final RenderBox box = key.currentContext!.findRenderObject()! as RenderBox; expect(box.localToGlobal(Offset.zero), const Offset(113.0, 466.0)); @@ -172,7 +173,7 @@ void main() { ), ); } - testWidgets('topLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('topLeft', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.topLeft, followerAlignment: Alignment.topLeft)); final RenderBox box1 = key1.currentContext!.findRenderObject()! as RenderBox; final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; @@ -181,7 +182,7 @@ void main() { expect(position1, offsetMoreOrLessEquals(position2)); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.center, followerAlignment: Alignment.center)); final RenderBox box1 = key1.currentContext!.findRenderObject()! as RenderBox; final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; @@ -190,7 +191,7 @@ void main() { expect(position1, offsetMoreOrLessEquals(position2)); }); - testWidgets('bottomRight - topRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bottomRight - topRight', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.bottomRight, followerAlignment: Alignment.topRight)); final RenderBox box1 = key1.currentContext!.findRenderObject()! as RenderBox; final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; @@ -249,7 +250,7 @@ void main() { ), ); } - testWidgets('topLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('topLeft', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.topLeft, followerAlignment: Alignment.topLeft)); final RenderBox box1 = key1.currentContext!.findRenderObject()! as RenderBox; final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; @@ -258,7 +259,7 @@ void main() { expect(position1, offsetMoreOrLessEquals(position2)); }); - testWidgets('center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('center', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.center, followerAlignment: Alignment.center)); final RenderBox box1 = key1.currentContext!.findRenderObject()! as RenderBox; final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; @@ -267,7 +268,7 @@ void main() { expect(position1, offsetMoreOrLessEquals(position2)); }); - testWidgets('bottomRight - topRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bottomRight - topRight', (WidgetTester tester) async { await tester.pumpWidget(build(targetAlignment: Alignment.bottomRight, followerAlignment: Alignment.topRight)); final RenderBox box1 = key1.currentContext!.findRenderObject()! as RenderBox; final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; @@ -321,7 +322,7 @@ void main() { for (final Alignment targetAlignment in alignments) { for (final Alignment followerAlignment in alignments) { - testWidgets('$targetAlignment - $followerAlignment', (WidgetTester tester) async{ + testWidgetsWithLeakTracking('$targetAlignment - $followerAlignment', (WidgetTester tester) async{ await tester.pumpWidget(build(targetAlignment: targetAlignment, followerAlignment: followerAlignment)); final RenderBox box2 = key2.currentContext!.findRenderObject()! as RenderBox; expect(box2.size, const Size(2.0, 2.0)); @@ -333,7 +334,7 @@ void main() { } }); - testWidgets('Leader after Follower asserts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Leader after Follower asserts', (WidgetTester tester) async { final LayerLink link = LayerLink(); await tester.pumpWidget( CompositedTransformFollower( @@ -351,7 +352,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( '`FollowerLayer` (`CompositedTransformFollower`) has null pointer error when using with some kinds of `Layer`s', (WidgetTester tester) async { final LayerLink link = LayerLink(); diff --git a/packages/flutter/test/widgets/constrained_box_test.dart b/packages/flutter/test/widgets/constrained_box_test.dart index 26d7e51df9fd3..b09d9e9a934cc 100644 --- a/packages/flutter/test/widgets/constrained_box_test.dart +++ b/packages/flutter/test/widgets/constrained_box_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Placeholder intrinsics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Placeholder intrinsics', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); expect(tester.renderObject<RenderBox>(find.byType(Placeholder)).getMinIntrinsicWidth(double.infinity), 0.0); expect(tester.renderObject<RenderBox>(find.byType(Placeholder)).getMaxIntrinsicWidth(double.infinity), 0.0); @@ -14,7 +15,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(Placeholder)).getMaxIntrinsicHeight(double.infinity), 0.0); }); - testWidgets('ConstrainedBox intrinsics - minHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - minHeight', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints( @@ -29,7 +30,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 20.0); }); - testWidgets('ConstrainedBox intrinsics - minWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - minWidth', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints( @@ -44,7 +45,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); }); - testWidgets('ConstrainedBox intrinsics - maxHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - maxHeight', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints( @@ -59,7 +60,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); }); - testWidgets('ConstrainedBox intrinsics - maxWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - maxWidth', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints( @@ -74,7 +75,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); }); - testWidgets('ConstrainedBox intrinsics - tight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - tight', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints.tightFor(width: 10.0, height: 30.0), @@ -88,7 +89,7 @@ void main() { }); - testWidgets('ConstrainedBox intrinsics - minHeight - with infinite width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - minHeight - with infinite width', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints( @@ -104,7 +105,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 20.0); }); - testWidgets('ConstrainedBox intrinsics - minWidth - with infinite height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - minWidth - with infinite height', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints( @@ -120,7 +121,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(ConstrainedBox)).getMaxIntrinsicHeight(double.infinity), 0.0); }); - testWidgets('ConstrainedBox intrinsics - infinite', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ConstrainedBox intrinsics - infinite', (WidgetTester tester) async { await tester.pumpWidget( ConstrainedBox( constraints: const BoxConstraints.tightFor(width: double.infinity, height: double.infinity), diff --git a/packages/flutter/test/widgets/container_test.dart b/packages/flutter/test/widgets/container_test.dart index fd5cc476f0b66..19492ee751864 100644 --- a/packages/flutter/test/widgets/container_test.dart +++ b/packages/flutter/test/widgets/container_test.dart @@ -9,6 +9,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('Container control tests:', () { @@ -37,7 +38,7 @@ void main() { ), ); - testWidgets('paints as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('paints as expected', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -54,7 +55,7 @@ void main() { }); group('diagnostics', () { - testWidgets('has reasonable default diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has reasonable default diagnostics', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -66,7 +67,7 @@ void main() { expect(box, hasAGoodToStringDeep); }); - testWidgets('has expected info diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has expected info diagnostics', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -138,7 +139,7 @@ void main() { ); }); - testWidgets('has expected debug diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has expected debug diagnostics', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -243,7 +244,7 @@ void main() { ); }); - testWidgets('has expected fine diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has expected fine diagnostics', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -376,7 +377,7 @@ void main() { ); }); - testWidgets('has expected hidden diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has expected hidden diagnostics', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -533,7 +534,7 @@ void main() { ); }); - testWidgets('painting error has expected diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('painting error has expected diagnostics', (WidgetTester tester) async { await tester.pumpWidget(Align( alignment: Alignment.topLeft, child: container, @@ -564,7 +565,7 @@ void main() { }); }); - testWidgets('Can be placed in an infinite box', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be placed in an infinite box', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -573,7 +574,7 @@ void main() { ); }); - testWidgets('Container transformAlignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Container transformAlignment', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( @@ -620,7 +621,7 @@ void main() { expect(tester.getBottomRight(finder), equals(const Offset(200, 200))); }); - testWidgets('giving clipBehaviour Clip.None, will not add a ClipPath to the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('giving clipBehaviour Clip.None, will not add a ClipPath to the tree', (WidgetTester tester) async { await tester.pumpWidget( Container( decoration: const BoxDecoration( @@ -635,7 +636,7 @@ void main() { ); }); - testWidgets('giving clipBehaviour not a Clip.None, will add a ClipPath to the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('giving clipBehaviour not a Clip.None, will add a ClipPath to the tree', (WidgetTester tester) async { final Container container = Container( clipBehavior: Clip.hardEdge, decoration: const BoxDecoration( @@ -652,7 +653,7 @@ void main() { ); }); - testWidgets('getClipPath() works for lots of kinds of decorations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getClipPath() works for lots of kinds of decorations', (WidgetTester tester) async { Future<void> test(Decoration decoration) async { await tester.pumpWidget( Directionality( @@ -682,7 +683,7 @@ void main() { await test(const FlutterLogoDecoration()); }); - testWidgets('Container is hittable only when having decorations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Container is hittable only when having decorations', (WidgetTester tester) async { bool tapped = false; await tester.pumpWidget(GestureDetector( onTap: () { tapped = true; }, @@ -736,7 +737,7 @@ void main() { expect(tapped, false); }); - testWidgets('Container discards alignment when the child parameter is null and constraints is not Tight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Container discards alignment when the child parameter is null and constraints is not Tight', (WidgetTester tester) async { await tester.pumpWidget( Container( decoration: const BoxDecoration( @@ -751,7 +752,7 @@ void main() { ); }); - testWidgets('using clipBehaviour and shadow, should not clip the shadow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using clipBehaviour and shadow, should not clip the shadow', (WidgetTester tester) async { final Container container = Container( clipBehavior: Clip.hardEdge, decoration: const BoxDecoration( diff --git a/packages/flutter/test/widgets/context_menu_controller_test.dart b/packages/flutter/test/widgets/context_menu_controller_test.dart index 1a6155881e2c0..2328238dcf80d 100644 --- a/packages/flutter/test/widgets/context_menu_controller_test.dart +++ b/packages/flutter/test/widgets/context_menu_controller_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'clipboard_utils.dart'; import 'editable_text_utils.dart'; @@ -20,7 +21,7 @@ void main() { await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); }); - testWidgets('Hides and shows only a single menu', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hides and shows only a single menu', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); late final BuildContext context; @@ -90,7 +91,7 @@ void main() { expect(find.byKey(key2), findsNothing); }); - testWidgets('A menu can be hidden and then reshown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A menu can be hidden and then reshown', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); late final BuildContext context; @@ -141,7 +142,7 @@ void main() { expect(find.byKey(key1), findsOneWidget); }); - testWidgets('markNeedsBuild causes the builder to update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('markNeedsBuild causes the builder to update', (WidgetTester tester) async { int buildCount = 0; late final BuildContext context; @@ -178,7 +179,7 @@ void main() { controller.remove(); }); - testWidgets('Calling show when a built-in widget is already showing its context menu hides the built-in menu', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Calling show when a built-in widget is already showing its context menu hides the built-in menu', (WidgetTester tester) async { final GlobalKey builtInKey = GlobalKey(); final GlobalKey directKey = GlobalKey(); late final BuildContext context; diff --git a/packages/flutter/test/widgets/coordinates_test.dart b/packages/flutter/test/widgets/coordinates_test.dart index 847f7482f26fd..f2668521cab92 100644 --- a/packages/flutter/test/widgets/coordinates_test.dart +++ b/packages/flutter/test/widgets/coordinates_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Comparing coordinates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Comparing coordinates', (WidgetTester tester) async { final Key keyA = GlobalKey(); final Key keyB = GlobalKey(); diff --git a/packages/flutter/test/widgets/custom_multi_child_layout_test.dart b/packages/flutter/test/widgets/custom_multi_child_layout_test.dart index a12887496a040..8a31b2877548e 100644 --- a/packages/flutter/test/widgets/custom_multi_child_layout_test.dart +++ b/packages/flutter/test/widgets/custom_multi_child_layout_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestMultiChildLayoutDelegate extends MultiChildLayoutDelegate { late BoxConstraints getSizeConstraints; @@ -163,7 +164,7 @@ class LayoutWithMissingId extends ParentDataWidget<MultiChildLayoutParentData> { } void main() { - testWidgets('Control test for CustomMultiChildLayout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Control test for CustomMultiChildLayout', (WidgetTester tester) async { final TestMultiChildLayoutDelegate delegate = TestMultiChildLayoutDelegate(); await tester.pumpWidget(buildFrame(delegate)); @@ -181,7 +182,7 @@ void main() { expect(delegate.performLayoutIsChild, false); }); - testWidgets('Test MultiChildDelegate shouldRelayout method', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Test MultiChildDelegate shouldRelayout method', (WidgetTester tester) async { TestMultiChildLayoutDelegate delegate = TestMultiChildLayoutDelegate(); await tester.pumpWidget(buildFrame(delegate)); @@ -204,7 +205,7 @@ void main() { expect(delegate.performLayoutSize, isNotNull); }); - testWidgets('Nested CustomMultiChildLayouts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested CustomMultiChildLayouts', (WidgetTester tester) async { final TestMultiChildLayoutDelegate delegate = TestMultiChildLayoutDelegate(); await tester.pumpWidget(Center( child: CustomMultiChildLayout( @@ -227,7 +228,7 @@ void main() { }); - testWidgets('Loose constraints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Loose constraints', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget(Center( child: CustomMultiChildLayout( @@ -251,8 +252,9 @@ void main() { expect(box.size.height, equals(250.0)); }); - testWidgets('Can use listener for relayout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can use listener for relayout', (WidgetTester tester) async { final ValueNotifier<Size> size = ValueNotifier<Size>(const Size(100.0, 200.0)); + addTearDown(size.dispose); await tester.pumpWidget( Center( @@ -302,7 +304,7 @@ void main() { expect((errors.first.exception as FlutterError).toStringDeep(), equalsIgnoringHashCodes(message)); } - testWidgets('layoutChild on non existent child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('layoutChild on non existent child', (WidgetTester tester) async { await expectFlutterErrorMessage( tester: tester, delegate: ZeroAndOneIdLayoutDelegate(), @@ -314,7 +316,7 @@ void main() { ); }); - testWidgets('layoutChild more than once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('layoutChild more than once', (WidgetTester tester) async { await expectFlutterErrorMessage( tester: tester, delegate: DuplicateLayoutDelegate(), @@ -326,7 +328,7 @@ void main() { ); }); - testWidgets('layoutChild on invalid size constraint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('layoutChild on invalid size constraint', (WidgetTester tester) async { await expectFlutterErrorMessage( tester: tester, delegate: InvalidConstraintsChildLayoutDelegate(), @@ -345,7 +347,7 @@ void main() { ); }); - testWidgets('positionChild on non existent child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positionChild on non existent child', (WidgetTester tester) async { await expectFlutterErrorMessage( tester: tester, delegate: NonExistentPositionDelegate(), @@ -357,7 +359,7 @@ void main() { ); }); - testWidgets("_callPerformLayout on child that doesn't have id", (WidgetTester tester) async { + testWidgetsWithLeakTracking("_callPerformLayout on child that doesn't have id", (WidgetTester tester) async { await expectFlutterErrorMessage( widget: Center( child: CustomMultiChildLayout( @@ -383,7 +385,7 @@ void main() { ); }); - testWidgets('performLayout did not layout a child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('performLayout did not layout a child', (WidgetTester tester) async { await expectFlutterErrorMessage( widget: Center( child: CustomMultiChildLayout( @@ -405,7 +407,7 @@ void main() { ); }); - testWidgets('performLayout did not layout multiple child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('performLayout did not layout multiple child', (WidgetTester tester) async { await expectFlutterErrorMessage( widget: Center( child: CustomMultiChildLayout( diff --git a/packages/flutter/test/widgets/custom_paint_test.dart b/packages/flutter/test/widgets/custom_paint_test.dart index 933b5b6b4f79c..70071f62dae8a 100644 --- a/packages/flutter/test/widgets/custom_paint_test.dart +++ b/packages/flutter/test/widgets/custom_paint_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestCustomPainter extends CustomPainter { TestCustomPainter({ required this.log, this.name }); @@ -40,7 +41,7 @@ class MockPaintingContext extends Fake implements PaintingContext { } void main() { - testWidgets('Control test for custom painting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Control test for custom painting', (WidgetTester tester) async { final List<String?> log = <String?>[]; await tester.pumpWidget(CustomPaint( painter: TestCustomPainter( @@ -62,7 +63,7 @@ void main() { expect(log, equals(<String>['background', 'child', 'foreground'])); }); - testWidgets('Throws FlutterError on custom painter incorrect restore/save calls', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws FlutterError on custom painter incorrect restore/save calls', (WidgetTester tester) async { final GlobalKey target = GlobalKey(); final List<String?> log = <String?>[]; await tester.pumpWidget(CustomPaint( @@ -118,7 +119,7 @@ void main() { expect(error.toStringDeep(), contains('2 more times')); }); - testWidgets('CustomPaint sizing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomPaint sizing', (WidgetTester tester) async { final GlobalKey target = GlobalKey(); await tester.pumpWidget(Center( @@ -153,7 +154,7 @@ void main() { }); - testWidgets('Raster cache hints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Raster cache hints', (WidgetTester tester) async { final GlobalKey target = GlobalKey(); final List<String?> log = <String?>[]; diff --git a/packages/flutter/test/widgets/custom_painter_test.dart b/packages/flutter/test/widgets/custom_painter_test.dart index e9320e21df167..322e974c94779 100644 --- a/packages/flutter/test/widgets/custom_painter_test.dart +++ b/packages/flutter/test/widgets/custom_painter_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -22,7 +23,7 @@ void main() { } void _defineTests() { - testWidgets('builds no semantics by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds no semantics by default', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(CustomPaint( @@ -36,7 +37,7 @@ void _defineTests() { semanticsTester.dispose(); }); - testWidgets('provides foreground semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('provides foreground semantics', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(CustomPaint( @@ -72,7 +73,7 @@ void _defineTests() { semanticsTester.dispose(); }); - testWidgets('provides background semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('provides background semantics', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(CustomPaint( @@ -108,7 +109,7 @@ void _defineTests() { semanticsTester.dispose(); }); - testWidgets('combines background, child and foreground semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('combines background, child and foreground semantics', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(CustomPaint( @@ -167,7 +168,7 @@ void _defineTests() { semanticsTester.dispose(); }); - testWidgets('applies $SemanticsProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applies $SemanticsProperties', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(CustomPaint( @@ -270,7 +271,7 @@ void _defineTests() { semanticsTester.dispose(); }); - testWidgets('Can toggle semantics on, off, on without crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can toggle semantics on, off, on without crash', (WidgetTester tester) async { await tester.pumpWidget(CustomPaint( painter: _PainterWithSemantics( semantics: const CustomPainterSemantics( @@ -312,7 +313,7 @@ void _defineTests() { semantics.dispose(); }, semanticsEnabled: false); - testWidgets('Supports all actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Supports all actions', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<SemanticsAction> performedActions = <SemanticsAction>[]; @@ -410,7 +411,7 @@ void _defineTests() { semantics.dispose(); }); - testWidgets('Supports all flags', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Supports all flags', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // checked state and toggled state are mutually exclusive. await tester.pumpWidget(CustomPaint( @@ -525,7 +526,7 @@ void _defineTests() { }); group('diffing', () { - testWidgets('complains about duplicate keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('complains about duplicate keys', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); await tester.pumpWidget(CustomPaint( painter: _SemanticsDiffTest(<String>[ @@ -622,7 +623,7 @@ void _defineTests() { }); }); - testWidgets('rebuilds semantics upon resize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('rebuilds semantics upon resize', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); final _PainterWithSemantics painter = _PainterWithSemantics( @@ -667,7 +668,7 @@ void _defineTests() { semanticsTester.dispose(); }); - testWidgets('does not rebuild when shouldRebuildSemantics is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not rebuild when shouldRebuildSemantics is false', (WidgetTester tester) async { final SemanticsTester semanticsTester = SemanticsTester(tester); const CustomPainterSemantics testSemantics = CustomPainterSemantics( @@ -712,7 +713,7 @@ void _defineTests() { } void _testDiff(String description, Future<void> Function(_DiffTester tester) testFunction) { - testWidgets(description, (WidgetTester tester) async { + testWidgetsWithLeakTracking(description, (WidgetTester tester) async { await testFunction(_DiffTester(tester)); }); } diff --git a/packages/flutter/test/widgets/custom_scroll_view_test.dart b/packages/flutter/test/widgets/custom_scroll_view_test.dart index 02c3281332338..20f5f475f38eb 100644 --- a/packages/flutter/test/widgets/custom_scroll_view_test.dart +++ b/packages/flutter/test/widgets/custom_scroll_view_test.dart @@ -4,10 +4,11 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/96024 - testWidgets('CustomScrollView.center update test 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView.center update test 1', (WidgetTester tester) async { final Key centerKey = UniqueKey(); late StateSetter setState; bool hasKey = false; @@ -49,7 +50,7 @@ void main() { // Pass without throw. }); - testWidgets('CustomScrollView.center update test 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView.center update test 2', (WidgetTester tester) async { const List<Widget> slivers1 = <Widget>[ SliverToBoxAdapter(key: Key('a'), child: SizedBox(height: 100.0)), SliverToBoxAdapter(key: Key('b'), child: SizedBox(height: 100.0)), @@ -81,7 +82,7 @@ void main() { // Pass without throw. }); - testWidgets('CustomScrollView.center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView.center', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: CustomScrollView( @@ -103,7 +104,7 @@ void main() { ); }); - testWidgets('CustomScrollView.center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView.center', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: CustomScrollView( @@ -135,7 +136,7 @@ void main() { ); }); - testWidgets('CustomScrollView.anchor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView.anchor', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: CustomScrollView( diff --git a/packages/flutter/test/widgets/custom_single_child_layout_test.dart b/packages/flutter/test/widgets/custom_single_child_layout_test.dart index 5e2f67e092b67..724f71bde79c0 100644 --- a/packages/flutter/test/widgets/custom_single_child_layout_test.dart +++ b/packages/flutter/test/widgets/custom_single_child_layout_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestSingleChildLayoutDelegate extends SingleChildLayoutDelegate { late BoxConstraints constraintsFromGetSize; @@ -93,7 +94,7 @@ Widget buildFrame(SingleChildLayoutDelegate delegate) { } void main() { - testWidgets('Control test for CustomSingleChildLayout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Control test for CustomSingleChildLayout', (WidgetTester tester) async { final TestSingleChildLayoutDelegate delegate = TestSingleChildLayoutDelegate(); await tester.pumpWidget(buildFrame(delegate)); @@ -114,7 +115,7 @@ void main() { expect(delegate.childSizeFromGetPositionForChild.height, 400.0); }); - testWidgets('Test SingleChildDelegate shouldRelayout method', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Test SingleChildDelegate shouldRelayout method', (WidgetTester tester) async { TestSingleChildLayoutDelegate delegate = TestSingleChildLayoutDelegate(); await tester.pumpWidget(buildFrame(delegate)); @@ -138,7 +139,7 @@ void main() { expect(delegate.constraintsFromGetConstraintsForChild, isNotNull); }); - testWidgets('Delegate can change size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Delegate can change size', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(FixedSizeLayoutDelegate(const Size(100.0, 200.0)))); RenderBox box = tester.renderObject(find.byType(CustomSingleChildLayout)); @@ -150,8 +151,9 @@ void main() { expect(box.size, equals(const Size(150.0, 240.0))); }); - testWidgets('Can use listener for relayout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can use listener for relayout', (WidgetTester tester) async { final ValueNotifier<Size> size = ValueNotifier<Size>(const Size(100.0, 200.0)); + addTearDown(size.dispose); await tester.pumpWidget(buildFrame(NotifierLayoutDelegate(size))); diff --git a/packages/flutter/test/widgets/debug_test.dart b/packages/flutter/test/widgets/debug_test.dart index 8ae59d0aa05a7..fd362bc06a4f0 100644 --- a/packages/flutter/test/widgets/debug_test.dart +++ b/packages/flutter/test/widgets/debug_test.dart @@ -7,6 +7,7 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('debugChildrenHaveDuplicateKeys control test', () { @@ -64,7 +65,7 @@ void main() { } }); - testWidgets('debugCheckHasTable control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasTable control test', (WidgetTester tester) async { await tester.pumpWidget( Builder( builder: (BuildContext context) { @@ -95,7 +96,7 @@ void main() { ); }); - testWidgets('debugCheckHasMediaQuery control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasMediaQuery control test', (WidgetTester tester) async { // Cannot use tester.pumpWidget here because it wraps the widget in a View, // which introduces a MediaQuery ancestor. await pumpWidgetWithoutViewWrapper( @@ -231,7 +232,7 @@ void main() { } }); - testWidgets('debugCheckHasWidgetsLocalizations throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasWidgetsLocalizations throws', (WidgetTester tester) async { final GlobalKey noLocalizationsAvailable = GlobalKey(); final GlobalKey localizationsAvailable = GlobalKey(); @@ -280,7 +281,7 @@ void main() { debugHighlightDeprecatedWidgets = false; }); - testWidgets('debugCreator of layers should not be null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCreator of layers should not be null', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Directionality( diff --git a/packages/flutter/test/widgets/decorated_sliver_test.dart b/packages/flutter/test/widgets/decorated_sliver_test.dart index e5815243fdaae..5800d8db16146 100644 --- a/packages/flutter/test/widgets/decorated_sliver_test.dart +++ b/packages/flutter/test/widgets/decorated_sliver_test.dart @@ -9,9 +9,10 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('DecoratedSliver creates, paints, and disposes BoxPainter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver creates, paints, and disposes BoxPainter', (WidgetTester tester) async { final TestDecoration decoration = TestDecoration(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -39,7 +40,7 @@ void main() { expect(decoration.painters.last.disposed, true); }); - testWidgets('DecoratedSliver can update box painter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver can update box painter', (WidgetTester tester) async { final TestDecoration decorationA = TestDecoration(); final TestDecoration decorationB = TestDecoration(); @@ -79,7 +80,7 @@ void main() { expect(decorationB.painters.last.paintCount, 1); }); - testWidgets('DecoratedSliver can update DecorationPosition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver can update DecorationPosition', (WidgetTester tester) async { final TestDecoration decoration = TestDecoration(); DecorationPosition activePosition = DecorationPosition.foreground; @@ -117,7 +118,7 @@ void main() { expect(decoration.painters.last.paintCount, 2); }); - testWidgets('DecoratedSliver golden test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver golden test', (WidgetTester tester) async { const BoxDecoration decoration = BoxDecoration( color: Colors.blue, ); @@ -198,10 +199,11 @@ void main() { await expectLater(find.byKey(foregroundKey), matchesGoldenFile('decorated_sliver.moon.foreground.png')); }); - testWidgets('DecoratedSliver paints its border correctly vertically', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver paints its border correctly vertically', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( @@ -234,10 +236,11 @@ void main() { )); }); - testWidgets('DecoratedSliver paints its border correctly vertically reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver paints its border correctly vertically reverse', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( @@ -273,10 +276,11 @@ void main() { - testWidgets('DecoratedSliver paints its border correctly horizontally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver paints its border correctly horizontally', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( @@ -310,10 +314,11 @@ void main() { )); }); - testWidgets('DecoratedSliver paints its border correctly horizontally reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver paints its border correctly horizontally reverse', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( @@ -349,10 +354,11 @@ void main() { }); - testWidgets('DecoratedSliver works with SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver works with SliverMainAxisGroup', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( @@ -387,10 +393,11 @@ void main() { )); }); - testWidgets('DecoratedSliver works with SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver works with SliverCrossAxisGroup', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( @@ -425,10 +432,11 @@ void main() { )); }); - testWidgets('DecoratedSliver draws only up to the bottom cache when sliver has infinite scroll extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecoratedSliver draws only up to the bottom cache when sliver has infinite scroll extent', (WidgetTester tester) async { const Key key = Key('DecoratedSliver with border'); const Color black = Color(0xFF000000); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Align( diff --git a/packages/flutter/test/widgets/default_colors_test.dart b/packages/flutter/test/widgets/default_colors_test.dart index af9fa9dca52f0..90b89bfedea47 100644 --- a/packages/flutter/test/widgets/default_colors_test.dart +++ b/packages/flutter/test/widgets/default_colors_test.dart @@ -7,6 +7,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const double _crispText = 100.0; // this font size is selected to avoid needing any antialiasing. const String _expText = 'Éxp'; // renders in the test font as: @@ -19,7 +20,7 @@ const String _expText = 'Éxp'; // renders in the test font as: // ÉÉÉÉxxxxpppp void main() { - testWidgets('Default background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default background', (WidgetTester tester) async { await tester.pumpWidget(const Align( alignment: Alignment.topLeft, child: Text(_expText, textDirection: TextDirection.ltr, style: TextStyle(color: Color(0xFF345678), fontSize: _crispText))), @@ -40,7 +41,7 @@ void main() { ); }, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently. - testWidgets('Default text color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default text color', (WidgetTester tester) async { await tester.pumpWidget(const ColoredBox( color: Color(0xFFABCDEF), child: Align( @@ -65,8 +66,22 @@ void main() { ); }, skip: !canCaptureImage); // [intended] Test relies on captureImage, which is not supported on web currently. - testWidgets('Default text selection color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default text selection color', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + final OverlayEntry overlayEntry = OverlayEntry( + builder: (BuildContext context) => SelectableRegion( + focusNode: focusNode, + selectionControls: emptyTextSelectionControls, + child: Align( + key: key, + alignment: Alignment.topLeft, + child: const Text('Éxp', textDirection: TextDirection.ltr, style: TextStyle(fontSize: _crispText, color: Color(0xFF000000))), + ), + ), + ); + addTearDown(() => overlayEntry..remove()..dispose()); await tester.pumpWidget( ColoredBox( color: const Color(0xFFFFFFFF), @@ -75,19 +90,7 @@ void main() { child: MediaQuery( data: const MediaQueryData(), child: Overlay( - initialEntries: <OverlayEntry>[ - OverlayEntry( - builder: (BuildContext context) => SelectableRegion( - focusNode: FocusNode(), - selectionControls: emptyTextSelectionControls, - child: Align( - key: key, - alignment: Alignment.topLeft, - child: const Text('Éxp', textDirection: TextDirection.ltr, style: TextStyle(fontSize: _crispText, color: Color(0xFF000000))), - ), - ), - ), - ], + initialEntries: <OverlayEntry>[overlayEntry], ), ), ), @@ -132,6 +135,7 @@ Color _getPixel(ByteData bytes, int x, int y, int width) { Future<void> _expectColors(WidgetTester tester, Finder finder, Set<Color> allowedColors, [ Map<Offset, Color>? spotChecks ]) async { final TestWidgetsFlutterBinding binding = tester.binding; final ui.Image image = (await binding.runAsync<ui.Image>(() => captureImage(finder.evaluate().single)))!; + addTearDown(image.dispose); final ByteData bytes = (await binding.runAsync<ByteData?>(() => image.toByteData(format: ui.ImageByteFormat.rawStraightRgba)))!; final Set<int> actualColorValues = <int>{}; for (int offset = 0; offset < bytes.lengthInBytes; offset += 4) { diff --git a/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart b/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart index 61b1365083919..c3d8a71aa312c 100644 --- a/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart +++ b/packages/flutter/test/widgets/default_text_editing_shortcuts_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'keyboard_utils.dart'; @@ -14,6 +15,9 @@ void main() { required FocusNode editableFocusNode, required FocusNode spyFocusNode, }) { + final TextEditingController controller = TextEditingController(text: 'dummy text'); + addTearDown(controller.dispose); + return MaterialApp( home: Align( alignment: Alignment.topLeft, @@ -24,7 +28,7 @@ void main() { child: ActionSpy( focusNode: spyFocusNode, child: EditableText( - controller: TextEditingController(text: 'dummy text'), + controller: controller, showSelectionHandles: true, autofocus: true, focusNode: editableFocusNode, @@ -50,7 +54,7 @@ void main() { final FocusNode editable = FocusNode(); final FocusNode spy = FocusNode(); - testWidgets('backspace with and without word modifier', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace with and without word modifier', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown(tester.binding.testTextInput.register); @@ -74,7 +78,7 @@ void main() { expect(state.lastIntent, isNull); }, variant: iOS); - testWidgets('delete with and without word modifier', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete with and without word modifier', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown(tester.binding.testTextInput.register); @@ -98,7 +102,7 @@ void main() { expect(state.lastIntent, isNull); }, variant: iOS); - testWidgets('Exception: deleting to line boundary is handled by the framework', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Exception: deleting to line boundary is handled by the framework', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown(tester.binding.testTextInput.register); @@ -128,13 +132,15 @@ void main() { group('macOS does not accept shortcuts if focus under EditableText', () { final TargetPlatformVariant macOSOnly = TargetPlatformVariant.only(TargetPlatform.macOS); - testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowLeft', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -151,13 +157,15 @@ void main() { expect(state.lastIntent, isNull); }, variant: macOSOnly); - testWidgets('word modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowRight', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -174,13 +182,15 @@ void main() { expect(state.lastIntent, isNull); }, variant: macOSOnly); - testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowLeft', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -197,13 +207,15 @@ void main() { expect(state.lastIntent, isNull); }, variant: macOSOnly); - testWidgets('line modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowRight', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -220,13 +232,15 @@ void main() { expect(state.lastIntent, isNull); }, variant: macOSOnly); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -255,13 +269,15 @@ void main() { expect(state.lastIntent, isNull); }, variant: macOSOnly); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -293,13 +309,15 @@ void main() { group('macOS does accept shortcuts if focus above EditableText', () { final TargetPlatformVariant macOSOnly = TargetPlatformVariant.only(TargetPlatform.macOS); - testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowLeft', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -316,13 +334,15 @@ void main() { expect(state.lastIntent, isA<ExtendSelectionToNextWordBoundaryIntent>()); }, variant: macOSOnly); - testWidgets('word modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowRight', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -339,13 +359,15 @@ void main() { expect(state.lastIntent, isA<ExtendSelectionToNextWordBoundaryIntent>()); }, variant: macOSOnly); - testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowLeft', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -362,13 +384,15 @@ void main() { expect(state.lastIntent, isA<ExtendSelectionToLineBreakIntent>()); }, variant: macOSOnly); - testWidgets('line modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowRight', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -385,13 +409,15 @@ void main() { expect(state.lastIntent, isA<ExtendSelectionToLineBreakIntent>()); }, variant: macOSOnly); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, @@ -422,13 +448,15 @@ void main() { expect(state.lastIntent, isA<ExtendSelectionToNextWordBoundaryIntent>()); }, variant: macOSOnly); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { tester.binding.testTextInput.unregister(); addTearDown((){ tester.binding.testTextInput.register(); }); final FocusNode editable = FocusNode(); + addTearDown(editable.dispose); final FocusNode spy = FocusNode(); + addTearDown(spy.dispose); await tester.pumpWidget( buildSpyAboveEditableText( editableFocusNode: editable, diff --git a/packages/flutter/test/widgets/default_text_height_behavior_test.dart b/packages/flutter/test/widgets/default_text_height_behavior_test.dart index a3974dffb0965..5649d75a2c6c4 100644 --- a/packages/flutter/test/widgets/default_text_height_behavior_test.dart +++ b/packages/flutter/test/widgets/default_text_height_behavior_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Text widget parameter takes precedence over DefaultTextHeightBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text widget parameter takes precedence over DefaultTextHeightBehavior', (WidgetTester tester) async { const TextHeightBehavior behavior1 = TextHeightBehavior( applyHeightToLastDescent: false, applyHeightToFirstAscent: false, @@ -31,7 +32,7 @@ void main() { expect(text.textHeightBehavior, behavior1); }); - testWidgets('DefaultTextStyle.textHeightBehavior takes precedence over DefaultTextHeightBehavior ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DefaultTextStyle.textHeightBehavior takes precedence over DefaultTextHeightBehavior ', (WidgetTester tester) async { const TextHeightBehavior behavior1 = TextHeightBehavior( applyHeightToLastDescent: false, applyHeightToFirstAscent: false, @@ -77,7 +78,7 @@ void main() { expect(text.textHeightBehavior, behavior1); }); - testWidgets('DefaultTextHeightBehavior changes propagate to Text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DefaultTextHeightBehavior changes propagate to Text', (WidgetTester tester) async { const Text textWidget = Text('Hello', textDirection: TextDirection.ltr); const TextHeightBehavior behavior1 = TextHeightBehavior( applyHeightToLastDescent: false, @@ -107,7 +108,7 @@ void main() { expect(text.textHeightBehavior, behavior2); }); - testWidgets( + testWidgetsWithLeakTracking( 'DefaultTextHeightBehavior.of(context) returns null if no ' 'DefaultTextHeightBehavior widget in tree', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/default_text_style_test.dart b/packages/flutter/test/widgets/default_text_style_test.dart index ddd9c6a986d9c..9b26768b91b85 100644 --- a/packages/flutter/test/widgets/default_text_style_test.dart +++ b/packages/flutter/test/widgets/default_text_style_test.dart @@ -6,9 +6,10 @@ import 'dart:ui' as ui show TextHeightBehavior; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('DefaultTextStyle changes propagate to Text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DefaultTextStyle changes propagate to Text', (WidgetTester tester) async { const Text textWidget = Text('Hello', textDirection: TextDirection.ltr); const TextStyle s1 = TextStyle( fontSize: 10.0, @@ -43,7 +44,7 @@ void main() { expect(text.maxLines, 3); }); - testWidgets('AnimatedDefaultTextStyle changes propagate to Text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedDefaultTextStyle changes propagate to Text', (WidgetTester tester) async { const Text textWidget = Text('Hello', textDirection: TextDirection.ltr); const TextStyle s1 = TextStyle( fontSize: 10.0, diff --git a/packages/flutter/test/widgets/did_update_widget_test.dart b/packages/flutter/test/widgets/did_update_widget_test.dart index afe802a5df8ea..d697cdbebd2fa 100644 --- a/packages/flutter/test/widgets/did_update_widget_test.dart +++ b/packages/flutter/test/widgets/did_update_widget_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can call setState from didUpdateWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can call setState from didUpdateWidget', (WidgetTester tester) async { await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, child: WidgetUnderTest(text: 'hello'), diff --git a/packages/flutter/test/widgets/directionality_test.dart b/packages/flutter/test/widgets/directionality_test.dart index 8472eb46ad979..4f83dc35fb36b 100644 --- a/packages/flutter/test/widgets/directionality_test.dart +++ b/packages/flutter/test/widgets/directionality_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directionality', (WidgetTester tester) async { final List<TextDirection> log = <TextDirection>[]; final Widget inner = Builder( builder: (BuildContext context) { @@ -51,7 +52,7 @@ void main() { expect(log, <TextDirection>[TextDirection.ltr, TextDirection.rtl, TextDirection.ltr]); }); - testWidgets('Directionality default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directionality default', (WidgetTester tester) async { bool good = false; await tester.pumpWidget(Builder( builder: (BuildContext context) { @@ -63,7 +64,7 @@ void main() { expect(good, isTrue); }); - testWidgets('Directionality.maybeOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directionality.maybeOf', (WidgetTester tester) async { final GlobalKey hasDirectionality = GlobalKey(); final GlobalKey noDirectionality = GlobalKey(); await tester.pumpWidget( @@ -81,7 +82,7 @@ void main() { expect(Directionality.maybeOf(hasDirectionality.currentContext!), TextDirection.rtl); }); - testWidgets('Directionality.of', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directionality.of', (WidgetTester tester) async { final GlobalKey hasDirectionality = GlobalKey(); final GlobalKey noDirectionality = GlobalKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/dismissible_test.dart b/packages/flutter/test/widgets/dismissible_test.dart index b948dc1331faa..878ea08bd0cfa 100644 --- a/packages/flutter/test/widgets/dismissible_test.dart +++ b/packages/flutter/test/widgets/dismissible_test.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const DismissDirection defaultDismissDirection = DismissDirection.horizontal; const double crossAxisEndOffset = 0.5; @@ -252,7 +253,7 @@ void main() { dismissedItems = <int>[]; }); - testWidgets('Horizontal drag triggers dismiss scrollDirection=vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal drag triggers dismiss scrollDirection=vertical', (WidgetTester tester) async { await tester.pumpWidget( buildTest(), ); @@ -269,7 +270,7 @@ void main() { expect(reportedDismissDirection, DismissDirection.endToStart); }); - testWidgets('Horizontal fling triggers dismiss scrollDirection=vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal fling triggers dismiss scrollDirection=vertical', (WidgetTester tester) async { await tester.pumpWidget( buildTest(), ); @@ -286,7 +287,7 @@ void main() { expect(reportedDismissDirection, DismissDirection.endToStart); }); - testWidgets('Horizontal fling does not trigger at zero offset, but does otherwise', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal fling does not trigger at zero offset, but does otherwise', (WidgetTester tester) async { await tester.pumpWidget( buildTest( startToEndThreshold: 0.95, @@ -313,7 +314,7 @@ void main() { expect(reportedDismissDirection, DismissDirection.endToStart); }); - testWidgets('Vertical drag triggers dismiss scrollDirection=horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical drag triggers dismiss scrollDirection=horizontal', (WidgetTester tester) async { await tester.pumpWidget( buildTest( scrollDirection: Axis.horizontal, @@ -333,7 +334,7 @@ void main() { expect(reportedDismissDirection, DismissDirection.down); }); - testWidgets('drag-left with DismissDirection.endToStart triggers dismiss (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-left with DismissDirection.endToStart triggers dismiss (LTR)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( dismissDirection: DismissDirection.endToStart, @@ -352,7 +353,7 @@ void main() { await dismissItem(tester, 1, gestureDirection: AxisDirection.left); }); - testWidgets('drag-right with DismissDirection.startToEnd triggers dismiss (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-right with DismissDirection.startToEnd triggers dismiss (LTR)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( dismissDirection: DismissDirection.startToEnd, @@ -369,7 +370,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('drag-right with DismissDirection.endToStart triggers dismiss (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-right with DismissDirection.endToStart triggers dismiss (RTL)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( textDirection: TextDirection.rtl, @@ -388,7 +389,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('drag-left with DismissDirection.startToEnd triggers dismiss (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-left with DismissDirection.startToEnd triggers dismiss (RTL)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( textDirection: TextDirection.rtl, @@ -408,7 +409,7 @@ void main() { await dismissItem(tester, 1, gestureDirection: AxisDirection.left); }); - testWidgets('fling-left with DismissDirection.endToStart triggers dismiss (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-left with DismissDirection.endToStart triggers dismiss (LTR)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( dismissDirection: DismissDirection.endToStart, @@ -427,7 +428,7 @@ void main() { await dismissItem(tester, 1, gestureDirection: AxisDirection.left); }); - testWidgets('fling-right with DismissDirection.startToEnd triggers dismiss (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-right with DismissDirection.startToEnd triggers dismiss (LTR)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( dismissDirection: DismissDirection.startToEnd, @@ -445,7 +446,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('fling-right with DismissDirection.endToStart triggers dismiss (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-right with DismissDirection.endToStart triggers dismiss (RTL)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( textDirection: TextDirection.rtl, @@ -463,7 +464,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('fling-left with DismissDirection.startToEnd triggers dismiss (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-left with DismissDirection.startToEnd triggers dismiss (RTL)', (WidgetTester tester) async { await tester.pumpWidget( buildTest( textDirection: TextDirection.rtl, @@ -483,7 +484,7 @@ void main() { await dismissItem(tester, 1, mechanism: flingElement, gestureDirection: AxisDirection.left); }); - testWidgets('drag-up with DismissDirection.up triggers dismiss', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-up with DismissDirection.up triggers dismiss', (WidgetTester tester) async { await tester.pumpWidget( buildTest( scrollDirection: Axis.horizontal, @@ -501,7 +502,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('drag-down with DismissDirection.down triggers dismiss', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-down with DismissDirection.down triggers dismiss', (WidgetTester tester) async { await tester.pumpWidget( buildTest( scrollDirection: Axis.horizontal, @@ -519,7 +520,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('fling-up with DismissDirection.up triggers dismiss', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-up with DismissDirection.up triggers dismiss', (WidgetTester tester) async { await tester.pumpWidget( buildTest( scrollDirection: Axis.horizontal, @@ -537,7 +538,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('fling-down with DismissDirection.down triggers dismiss', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-down with DismissDirection.down triggers dismiss', (WidgetTester tester) async { await tester.pumpWidget( buildTest( scrollDirection: Axis.horizontal, @@ -555,7 +556,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('drag-left has no effect on dismissible with a high dismiss threshold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag-left has no effect on dismissible with a high dismiss threshold', (WidgetTester tester) async { await tester.pumpWidget( buildTest( startToEndThreshold: 1.0, @@ -572,7 +573,7 @@ void main() { expect(dismissedItems, equals(<int>[0])); }); - testWidgets('fling-left has no effect on dismissible with a high dismiss threshold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling-left has no effect on dismissible with a high dismiss threshold', (WidgetTester tester) async { await tester.pumpWidget( buildTest( startToEndThreshold: 1.0, @@ -595,7 +596,7 @@ void main() { // now since we migrated to the new repo. The bug was fixed by // https://github.com/flutter/engine/pull/1134 at the time, and later made // irrelevant by fn3, but just in case... - testWidgets('Verify that drag-move events do not assert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that drag-move events do not assert', (WidgetTester tester) async { await tester.pumpWidget( buildTest( scrollDirection: Axis.horizontal, @@ -622,7 +623,7 @@ void main() { // died in the migration to the new repo). Don't copy this test; it doesn't // actually remove the dismissed widget, which is a violation of the // Dismissible contract. This is not an example of good practice. - testWidgets('dismissing bottom then top (smoketest)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dismissing bottom then top (smoketest)', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -654,7 +655,7 @@ void main() { expect(find.text('2'), findsNothing); }); - testWidgets('Dismissible starts from the full size when collapsing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible starts from the full size when collapsing', (WidgetTester tester) async { await tester.pumpWidget( buildTest( background: const Text('background'), @@ -672,7 +673,7 @@ void main() { expect(backgroundBox.size.height, equals(100.0)); }); - testWidgets('Checking fling item before movementDuration completes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checking fling item before movementDuration completes', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(dismissedItems, isEmpty); @@ -683,7 +684,7 @@ void main() { expect(find.text('1'), findsOneWidget); }); - testWidgets('Checking fling item after movementDuration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checking fling item after movementDuration', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(dismissedItems, isEmpty); @@ -694,7 +695,7 @@ void main() { expect(find.text('0'), findsNothing); }); - testWidgets('Horizontal fling less than threshold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal fling less than threshold', (WidgetTester tester) async { await tester.pumpWidget(buildTest(scrollDirection: Axis.horizontal)); expect(dismissedItems, isEmpty); @@ -707,7 +708,7 @@ void main() { expect(dismissedItems, isEmpty); }); - testWidgets('Vertical fling less than threshold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical fling less than threshold', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(dismissedItems, isEmpty); @@ -720,7 +721,7 @@ void main() { expect(dismissedItems, isEmpty); }); - testWidgets('confirmDismiss returns values: true, false, null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('confirmDismiss returns values: true, false, null', (WidgetTester tester) async { late DismissDirection confirmDismissDirection; Widget buildFrame(bool? confirmDismissValue) { @@ -777,7 +778,7 @@ void main() { expect(confirmDismissDirection, DismissDirection.endToStart); }); - testWidgets('Pending confirmDismiss does not cause errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Pending confirmDismiss does not cause errors', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/54990 late Completer<bool?> completer; @@ -839,7 +840,7 @@ void main() { await tester.pump(); }); - testWidgets('Dismissible cannot be dragged with pending confirmDismiss', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible cannot be dragged with pending confirmDismiss', (WidgetTester tester) async { final Completer<bool?> completer = Completer<bool?>(); await tester.pumpWidget( buildTest( @@ -863,7 +864,7 @@ void main() { expect(tester.getTopLeft(find.text('0')), position); }); - testWidgets('Drag to end and release - items does not get stuck if confirmDismiss returns false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag to end and release - items does not get stuck if confirmDismiss returns false', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/87556 final Completer<bool?> completer = Completer<bool?>(); @@ -882,7 +883,7 @@ void main() { expect(tester.getTopLeft(find.text('0')), position); }); - testWidgets('Dismissible with null resizeDuration calls onDismissed immediately', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible with null resizeDuration calls onDismissed immediately', (WidgetTester tester) async { bool resized = false; bool dismissed = false; @@ -914,7 +915,7 @@ void main() { expect(resized, false); }); - testWidgets('setState that does not remove the Dismissible from tree should throw Error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setState that does not remove the Dismissible from tree should throw Error', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: StatefulBuilder( @@ -971,7 +972,7 @@ void main() { ); }); - testWidgets('Dismissible.behavior should behave correctly during hit testing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible.behavior should behave correctly during hit testing', (WidgetTester tester) async { bool didReceivePointerDown = false; Widget buildStack({required Widget child}) { @@ -1040,7 +1041,7 @@ void main() { expect(didReceivePointerDown, isTrue); }); - testWidgets('DismissDirection.none does not trigger dismiss', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DismissDirection.none does not trigger dismiss', (WidgetTester tester) async { await tester.pumpWidget(buildTest( dismissDirection: DismissDirection.none, scrollPhysics: const NeverScrollableScrollPhysics(), @@ -1054,7 +1055,7 @@ void main() { expect(find.text('0'), findsOneWidget); }); - testWidgets('DismissDirection.none does not prevent scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DismissDirection.none does not prevent scrolling', (WidgetTester tester) async { final ScrollController controller = ScrollController(); await tester.pumpWidget( @@ -1077,7 +1078,7 @@ void main() { controller.dispose(); }); - testWidgets('onUpdate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onUpdate', (WidgetTester tester) async { await tester.pumpWidget(buildTest( scrollDirection: Axis.horizontal, )); @@ -1131,7 +1132,7 @@ void main() { expect(reportedDismissUpdateProgress, 0.0); }); - testWidgets('Change direction does not lose child state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Change direction does not lose child state', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/108961 Widget buildFrame(DismissDirection direction) { return Directionality( diff --git a/packages/flutter/test/widgets/display_feature_sub_screen_test.dart b/packages/flutter/test/widgets/display_feature_sub_screen_test.dart index 926a459a81d62..e61042887f05f 100644 --- a/packages/flutter/test/widgets/display_feature_sub_screen_test.dart +++ b/packages/flutter/test/widgets/display_feature_sub_screen_test.dart @@ -6,10 +6,11 @@ import 'dart:ui'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('DisplayFeatureSubScreen', () { - testWidgets('without Directionality or anchor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('without Directionality or anchor', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ @@ -37,7 +38,7 @@ void main() { expect(message, contains('Directionality')); }); - testWidgets('with anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ @@ -68,7 +69,7 @@ void main() { expect(renderBox.localToGlobal(Offset.zero), equals(const Offset(410,0))); }); - testWidgets('with infinity anchorpoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with infinity anchorpoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ @@ -99,7 +100,7 @@ void main() { expect(renderBox.localToGlobal(Offset.zero), equals(const Offset(410,0))); }); - testWidgets('with horizontal hinge and anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with horizontal hinge and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ @@ -129,7 +130,7 @@ void main() { expect(renderBox.localToGlobal(Offset.zero), equals(const Offset(0,310))); }); - testWidgets('with multiple display features and anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with multiple display features and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ @@ -164,7 +165,7 @@ void main() { expect(renderBox.localToGlobal(Offset.zero), equals(const Offset(410,310))); }); - testWidgets('with non-splitting display features and anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with non-splitting display features and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ @@ -209,7 +210,7 @@ void main() { expect(renderBox.localToGlobal(Offset.zero), equals(Offset.zero)); }); - testWidgets('with size 0 display feature in half-opened posture and anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with size 0 display feature in half-opened posture and anchorPoint', (WidgetTester tester) async { const Key childKey = Key('childKey'); final MediaQueryData mediaQuery = MediaQueryData.fromView(tester.view).copyWith( displayFeatures: <DisplayFeature>[ diff --git a/packages/flutter/test/widgets/disposable_build_context_test.dart b/packages/flutter/test/widgets/disposable_build_context_test.dart index 4acac47d8749d..c9473665dc47f 100644 --- a/packages/flutter/test/widgets/disposable_build_context_test.dart +++ b/packages/flutter/test/widgets/disposable_build_context_test.dart @@ -4,10 +4,11 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('DisposableBuildContext asserts on disposed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DisposableBuildContext asserts on disposed state', (WidgetTester tester) async { final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); await tester.pumpWidget(TestWidget(key)); From 12e6ff2c5464f1719aef2d50c6f51616870955f3 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 11:30:43 -0700 Subject: [PATCH 1123/1547] DropdownRoutePage should dispose the created ScrollController. (#133941) --- .../flutter/lib/src/material/dropdown.dart | 62 +++++++++++++------ .../material/paginated_data_table_test.dart | 3 +- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index 48adf8ebeaed6..91ffca3e302d0 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -102,9 +102,11 @@ class _DropdownMenuItemButton<T> extends StatefulWidget { required this.constraints, required this.itemIndex, required this.enableFeedback, + required this.scrollController, }); final _DropdownRoute<T> route; + final ScrollController scrollController; final EdgeInsets? padding; final Rect buttonRect; final BoxConstraints constraints; @@ -131,7 +133,7 @@ class _DropdownMenuItemButtonState<T> extends State<_DropdownMenuItemButton<T>> widget.constraints.maxHeight, widget.itemIndex, ); - widget.route.scrollController!.animateTo( + widget.scrollController.animateTo( menuLimits.scrollOffset, curve: Curves.easeInOut, duration: const Duration(milliseconds: 100), @@ -205,6 +207,7 @@ class _DropdownMenu<T> extends StatefulWidget { this.dropdownColor, required this.enableFeedback, this.borderRadius, + required this.scrollController, }); final _DropdownRoute<T> route; @@ -214,6 +217,7 @@ class _DropdownMenu<T> extends StatefulWidget { final Color? dropdownColor; final bool enableFeedback; final BorderRadius? borderRadius; + final ScrollController scrollController; @override _DropdownMenuState<T> createState() => _DropdownMenuState<T>(); @@ -264,6 +268,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> { constraints: widget.constraints, itemIndex: itemIndex, enableFeedback: widget.enableFeedback, + scrollController: widget.scrollController, ), ]; @@ -304,7 +309,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> { platform: Theme.of(context).platform, ), child: PrimaryScrollController( - controller: widget.route.scrollController!, + controller: widget.scrollController, child: Scrollbar( thumbVisibility: true, child: ListView( @@ -447,7 +452,6 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> { final BorderRadius? borderRadius; final List<double> itemHeights; - ScrollController? scrollController; @override Duration get transitionDuration => _kDropdownMenuDuration; @@ -572,7 +576,7 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> { } } -class _DropdownRoutePage<T> extends StatelessWidget { +class _DropdownRoutePage<T> extends StatefulWidget { const _DropdownRoutePage({ super.key, required this.route, @@ -603,8 +607,15 @@ class _DropdownRoutePage<T> extends StatelessWidget { final BorderRadius? borderRadius; @override - Widget build(BuildContext context) { - assert(debugCheckHasDirectionality(context)); + State<_DropdownRoutePage<T>> createState() => _DropdownRoutePageState<T>(); +} + +class _DropdownRoutePageState<T> extends State<_DropdownRoutePage<T>> { + late ScrollController _scrollSontroller; + + @override + void initState(){ + super.initState(); // Computing the initialScrollOffset now, before the items have been laid // out. This only works if the item heights are effectively fixed, i.e. either @@ -612,20 +623,25 @@ class _DropdownRoutePage<T> extends StatelessWidget { // and all of the items' intrinsic heights are less than kMinInteractiveDimension. // Otherwise the initialScrollOffset is just a rough approximation based on // treating the items as if their heights were all equal to kMinInteractiveDimension. - if (route.scrollController == null) { - final _MenuLimits menuLimits = route.getMenuLimits(buttonRect, constraints.maxHeight, selectedIndex); - route.scrollController = ScrollController(initialScrollOffset: menuLimits.scrollOffset); - } + final _MenuLimits menuLimits = widget.route.getMenuLimits(widget.buttonRect, widget.constraints.maxHeight, widget.selectedIndex); + _scrollSontroller = ScrollController(initialScrollOffset: menuLimits.scrollOffset); + } + + + @override + Widget build(BuildContext context) { + assert(debugCheckHasDirectionality(context)); final TextDirection? textDirection = Directionality.maybeOf(context); final Widget menu = _DropdownMenu<T>( - route: route, - padding: padding.resolve(textDirection), - buttonRect: buttonRect, - constraints: constraints, - dropdownColor: dropdownColor, - enableFeedback: enableFeedback, - borderRadius: borderRadius, + route: widget.route, + padding: widget.padding.resolve(textDirection), + buttonRect: widget.buttonRect, + constraints: widget.constraints, + dropdownColor: widget.dropdownColor, + enableFeedback: widget.enableFeedback, + borderRadius: widget.borderRadius, + scrollController: _scrollSontroller, ); return MediaQuery.removePadding( @@ -638,16 +654,22 @@ class _DropdownRoutePage<T> extends StatelessWidget { builder: (BuildContext context) { return CustomSingleChildLayout( delegate: _DropdownMenuRouteLayout<T>( - buttonRect: buttonRect, - route: route, + buttonRect: widget.buttonRect, + route: widget.route, textDirection: textDirection, ), - child: capturedThemes.wrap(menu), + child: widget.capturedThemes.wrap(menu), ); }, ), ); } + + @override + void dispose() { + _scrollSontroller.dispose(); + super.dispose(); + } } // This widget enables _DropdownRoute to look up the sizes of diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index 560b0a12ed627..88fd469a93ee7 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'data_table_test_utils.dart'; @@ -66,7 +67,7 @@ class TestDataSource extends DataTableSource { void main() { final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('PaginatedDataTable paging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable paging', (WidgetTester tester) async { final TestDataSource source = TestDataSource(); addTearDown(source.dispose); From 11ad759aee202eeac1868e959efa5802dae7aaca Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 14:37:08 -0400 Subject: [PATCH 1124/1547] Roll Flutter Engine from 71bea01d3abe to f0b718e28779 (2 revisions) (#134231) https://github.com/flutter/engine/compare/71bea01d3abe...f0b718e28779 2023-09-07 kjlubick@users.noreply.github.com Explicitly encode SkImages in SkPictures as PNG (flutter/engine#45511) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 9a41a83f96d7 to 16df0c27bc0e (3 revisions) (flutter/engine#45537) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f1e1270e53016..2471cd2a652cc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -71bea01d3abe7bd828aa0b52961bc89e2340f607 +f0b718e28779a55f86f6a8a784beac8a56869b80 From ea351694fe5bdc824d1e9fba89a2ff086dcd8474 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 14:38:50 -0400 Subject: [PATCH 1125/1547] Roll Packages from e7d812cefce0 to 22d475491502 (9 revisions) (#134232) https://github.com/flutter/packages/compare/e7d812cefce0...22d475491502 2023-09-07 engine-flutter-autoroll@skia.org Roll Flutter (stable) from ff5b5b5fa6f3 to 2524052335ec (6 revisions) (flutter/packages#4866) 2023-09-07 maurits@vnbskm.nl [webview_flutter_platform_interface] Adds option to override console log (flutter/packages#4701) 2023-09-01 stuartmorgan@google.com [tools,pigeon] Update tooling to handle Windows build output changes (flutter/packages#4826) 2023-08-31 amuramoto@users.noreply.github.com [google_maps_flutter] Cloud-based map styling support (flutter/packages#3682) 2023-08-31 stuartmorgan@google.com [ci] Convert version presubmit check to LUCI (flutter/packages#4822) 2023-08-31 rajveer0malviya@gmail.com [url_launcher_android] Add support for Custom Tabs (flutter/packages#4739) 2023-08-31 tarrinneal@gmail.com [webview_flutter] update pigeon to 11 (flutter/packages#4821) 2023-08-31 engine-flutter-autoroll@skia.org Roll Flutter (stable) from e1e47221e862 to ff5b5b5fa6f3 (1 revision) (flutter/packages#4823) 2023-08-31 engine-flutter-autoroll@skia.org Roll Flutter from 1fe24956ac46 to c175cf87a6a3 (30 revisions) (flutter/packages#4825) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index ba405be3ea80d..59a33a9d1f228 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -e7d812cefce083fa09762d25cd42303737d05b9f +22d475491502301d020b3af37b4a5e29e5182f7c From 445e02dd631aa9e9665e58d9fc4133950d199efd Mon Sep 17 00:00:00 2001 From: Andrew Kolos <andrewrkolos@gmail.com> Date: Thu, 7 Sep 2023 12:36:55 -0700 Subject: [PATCH 1126/1547] fix `--exit` flag in dev/devicelab/bin/run.dart (#134162) Fixes #134154 This PR also changes the default value of the `--exit` flag from `true` to `false`. Effectively, this is not a change in behavior since `--exit` didn't previously work. --- dev/devicelab/bin/run.dart | 1 - dev/devicelab/lib/framework/runner.dart | 15 +++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dev/devicelab/bin/run.dart b/dev/devicelab/bin/run.dart index a666e1aa48f86..e90ffe36bb062 100644 --- a/dev/devicelab/bin/run.dart +++ b/dev/devicelab/bin/run.dart @@ -293,7 +293,6 @@ ArgParser createArgParser(List<String> taskNames) { ) ..addFlag( 'exit', - defaultsTo: true, help: 'Exit on the first test failure. Currently flakes are intentionally (though ' 'incorrectly) not considered to be failures.', ) diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index 5f11b4ffc7684..39d0015db5e29 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -47,8 +47,8 @@ Future<void> runTasks( }) async { for (final String taskName in taskNames) { TaskResult result = TaskResult.success(null); - int retry = 0; - while (retry <= Cocoon.retryNumber) { + int failureCount = 0; + while (failureCount <= Cocoon.retryNumber) { result = await rerunTask( taskName, deviceId: deviceId, @@ -66,11 +66,14 @@ Future<void> runTasks( ); if (!result.succeeded) { - retry += 1; + failureCount += 1; + if (exitOnFirstTestFailure) { + break; + } } else { section('Flaky status for "$taskName"'); - if (retry > 0) { - print('Total ${retry+1} executions: $retry failures and 1 false positive.'); + if (failureCount > 0) { + print('Total ${failureCount+1} executions: $failureCount failures and 1 false positive.'); print('flaky: true'); // TODO(ianh): stop ignoring this failure. We should set exitCode=1, and quit // if exitOnFirstTestFailure is true. @@ -84,7 +87,7 @@ Future<void> runTasks( if (!result.succeeded) { section('Flaky status for "$taskName"'); - print('Consistently failed across all $retry executions.'); + print('Consistently failed across all $failureCount executions.'); print('flaky: false'); exitCode = 1; if (exitOnFirstTestFailure) { From aea4552acdc72393a4e51780dd318d9e32978c1f Mon Sep 17 00:00:00 2001 From: Andrew Kolos <andrewrkolos@gmail.com> Date: Thu, 7 Sep 2023 12:38:05 -0700 Subject: [PATCH 1127/1547] add --exit flag to dev/devicelab/bin/test_runner.dart (#134165) Resolves #134070 Adds a flag to the `test_runner.dart test` script that will cause the test runner to exit upon first failure (or, said another way, exit without retrying). This is in parity with the `--exit` flag of `dev/devicelab/bin/run.dart`. --- dev/devicelab/lib/command/test.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dev/devicelab/lib/command/test.dart b/dev/devicelab/lib/command/test.dart index e656c8bad1e7d..c65a5da287d6f 100644 --- a/dev/devicelab/lib/command/test.dart +++ b/dev/devicelab/lib/command/test.dart @@ -24,6 +24,11 @@ class TestCommand extends Command<void> { 'settings in the test case, and will results in error if no device\n' 'with given ID/ID prefix is found.', ); + argParser.addFlag( + 'exit', + help: 'Exit on the first test failure. Currently flakes are intentionally (though ' + 'incorrectly) not considered to be failures.', + ); argParser.addOption( 'git-branch', help: '[Flutter infrastructure] Git branch of the current commit. LUCI\n' @@ -90,6 +95,7 @@ class TestCommand extends Command<void> { silent: (argResults!['silent'] as bool?) ?? false, useEmulator: (argResults!['use-emulator'] as bool?) ?? false, taskArgs: taskArgs, + exitOnFirstTestFailure: argResults!['exit'] as bool, ); } } From e308722e08b7552776aba7cc9b12a21a04a6bf9e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 16:16:14 -0400 Subject: [PATCH 1128/1547] Roll Flutter Engine from f0b718e28779 to 8d07c2947e60 (3 revisions) (#134240) https://github.com/flutter/engine/compare/f0b718e28779...8d07c2947e60 2023-09-07 matanlurey@users.noreply.github.com [Impeller] Document and slightly refactor `ResourceManagerVK` & friends. (flutter/engine#45474) 2023-09-07 uysalere@gmail.com [fuchsia] Restructure Flatland vsync loop (flutter/engine#45531) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 16df0c27bc0e to c3d6534b0ac3 (3 revisions) (flutter/engine#45543) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2471cd2a652cc..f8fe9c840f526 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f0b718e28779a55f86f6a8a784beac8a56869b80 +8d07c2947e6078f65f43eb8b697e7b349f1a8eb1 From 2032fcc571b9e04acd1df667aef7a10e90fa7976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Thu, 7 Sep 2023 13:25:36 -0700 Subject: [PATCH 1129/1547] [Windows Arm64] Remove device_type property (#134181) The Windows Arm64 tests are failing to start as no machines match desired properties. This removes the `device_type: none` property as no Windows Arm64 machines match this ([with `device_type`](https://chromium-swarm.appspot.com/botlist?c=id&c=task&c=os&c=status&d=asc&f=cpu%3Aarm64&f=os%3AWindows&f=pool%3Aluci.flutter.staging&f=device_type%3Anone&s=id), [without `device_type`](https://chromium-swarm.appspot.com/botlist?c=id&c=task&c=os&c=status&d=asc&f=cpu%3Aarm64&f=os%3AWindows&f=pool%3Aluci.flutter.staging&s=id)). This allows the tests to run on the Windows Arm64 machine pool. [I tested this manually using `led`](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/d96efacb0ccd274798d5c18c9822903543bb1513d620ba9e50240e3ee2375905/+/build.proto?server=chromium-swarm.appspot.com). ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 82ae7f830f3a9..4ce84b8cdae10 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -204,7 +204,6 @@ platform_properties: {"dependency": "certs", "version": "version:9563bb"} ] os: Windows - device_type: none cpu: arm64 windows_android: properties: From 30234a00ee217ea60f3b30d068169f11e3bec360 Mon Sep 17 00:00:00 2001 From: Taha Tesser <tessertaha@gmail.com> Date: Fri, 8 Sep 2023 00:55:32 +0300 Subject: [PATCH 1130/1547] Fix `ExpansionTile` properties cannot be updated with `setState` (#134218) fixes [`ExpansionTile` properties aren't updated with `setState`](https://github.com/flutter/flutter/issues/24493) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: Example(), ); } } class Example extends StatefulWidget { const Example({super.key}); @override State<Example> createState() => _ExampleState(); } class _ExampleState extends State<Example> { ShapeBorder collapsedShape = const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4)), ); Color collapsedTextColor = const Color(0xffffffff); Color collapsedBackgroundColor = const Color(0xffff0000); Color collapsedIconColor = const Color(0xffffffff); ShapeBorder shape = const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), ); Color backgroundColor = const Color(0xffff0000); Color textColor = const Color(0xffffffff); Color iconColor = const Color(0xffffffff); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ExpansionTile( shape: shape, backgroundColor: backgroundColor, textColor: textColor, iconColor: iconColor, collapsedShape: collapsedShape, collapsedTextColor: collapsedTextColor, collapsedBackgroundColor: collapsedBackgroundColor, collapsedIconColor: collapsedIconColor, title: const Text('Collapsed ExpansionTile'), children: const [ ListTile( title: Text('Revealed!'), ), ], ), const SizedBox(height: 16), ExpansionTile( shape: shape, backgroundColor: backgroundColor, textColor: textColor, iconColor: iconColor, initiallyExpanded: true, title: const Text('Expanded ExpansionTile'), children: const [ ListTile( title: Text('Revealed!'), ), ], ), const SizedBox(height: 16), FilledButton( onPressed: () { setState(() { collapsedShape = const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(50)), ); collapsedTextColor = const Color(0xfff00000); collapsedBackgroundColor = const Color(0xffffff00); collapsedIconColor = const Color(0xfff00000); shape = const RoundedRectangleBorder(); backgroundColor = const Color(0xfffff000); textColor = const Color(0xfff00000); iconColor = const Color(0xfff00000); }); }, child: const Text('Update properties'), ), ], ), ), ), ); } } ``` </details> ### Before https://github.com/flutter/flutter/assets/48603081/b29aed98-38ff-40a3-9ed3-c4342ada35b6 ### After https://github.com/flutter/flutter/assets/48603081/5e0b6a34-c577-40ed-8456-7ef55caa277b --- .../lib/src/material/expansion_tile.dart | 44 ++++- .../test/material/expansion_tile_test.dart | 156 ++++++++++++++++++ 2 files changed, 199 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/expansion_tile.dart b/packages/flutter/lib/src/material/expansion_tile.dart index bf865d39f4360..6756931c5866b 100644 --- a/packages/flutter/lib/src/material/expansion_tile.dart +++ b/packages/flutter/lib/src/material/expansion_tile.dart @@ -668,6 +668,32 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider ); } + @override + void didUpdateWidget(covariant ExpansionTile oldWidget) { + super.didUpdateWidget(oldWidget); + final ThemeData theme = Theme.of(context); + final ExpansionTileThemeData expansionTileTheme = ExpansionTileTheme.of(context); + final ExpansionTileThemeData defaults = theme.useMaterial3 + ? _ExpansionTileDefaultsM3(context) + : _ExpansionTileDefaultsM2(context); + if (widget.collapsedShape != oldWidget.collapsedShape + || widget.shape != oldWidget.shape) { + _updateShapeBorder(expansionTileTheme, theme); + } + if (widget.collapsedTextColor != oldWidget.collapsedTextColor + || widget.textColor != oldWidget.textColor) { + _updateHeaderColor(expansionTileTheme, defaults); + } + if (widget.collapsedIconColor != oldWidget.collapsedIconColor + || widget.iconColor != oldWidget.iconColor) { + _updateIconColor(expansionTileTheme, defaults); + } + if (widget.backgroundColor != oldWidget.backgroundColor + || widget.collapsedBackgroundColor != oldWidget.collapsedBackgroundColor) { + _updateBackgroundColor(expansionTileTheme); + } + } + @override void didChangeDependencies() { final ThemeData theme = Theme.of(context); @@ -675,6 +701,14 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider final ExpansionTileThemeData defaults = theme.useMaterial3 ? _ExpansionTileDefaultsM3(context) : _ExpansionTileDefaultsM2(context); + _updateShapeBorder(expansionTileTheme, theme); + _updateHeaderColor(expansionTileTheme, defaults); + _updateIconColor(expansionTileTheme, defaults); + _updateBackgroundColor(expansionTileTheme); + super.didChangeDependencies(); + } + + void _updateShapeBorder(ExpansionTileThemeData expansionTileTheme, ThemeData theme) { _borderTween ..begin = widget.collapsedShape ?? expansionTileTheme.collapsedShape @@ -688,20 +722,28 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider top: BorderSide(color: theme.dividerColor), bottom: BorderSide(color: theme.dividerColor), ); + } + + void _updateHeaderColor(ExpansionTileThemeData expansionTileTheme, ExpansionTileThemeData defaults) { _headerColorTween ..begin = widget.collapsedTextColor ?? expansionTileTheme.collapsedTextColor ?? defaults.collapsedTextColor ..end = widget.textColor ?? expansionTileTheme.textColor ?? defaults.textColor; + } + + void _updateIconColor(ExpansionTileThemeData expansionTileTheme, ExpansionTileThemeData defaults) { _iconColorTween ..begin = widget.collapsedIconColor ?? expansionTileTheme.collapsedIconColor ?? defaults.collapsedIconColor ..end = widget.iconColor ?? expansionTileTheme.iconColor ?? defaults.iconColor; + } + + void _updateBackgroundColor(ExpansionTileThemeData expansionTileTheme) { _backgroundColorTween ..begin = widget.collapsedBackgroundColor ?? expansionTileTheme.collapsedBackgroundColor ..end = widget.backgroundColor ?? expansionTileTheme.backgroundColor; - super.didChangeDependencies(); } @override diff --git a/packages/flutter/test/material/expansion_tile_test.dart b/packages/flutter/test/material/expansion_tile_test.dart index 3c6d9640a52f1..9900a1101c9f5 100644 --- a/packages/flutter/test/material/expansion_tile_test.dart +++ b/packages/flutter/test/material/expansion_tile_test.dart @@ -893,6 +893,162 @@ void main() { handle.dispose(); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); + testWidgetsWithLeakTracking('Collapsed ExpansionTile properties can be updated with setState', (WidgetTester tester) async { + const Key expansionTileKey = Key('expansionTileKey'); + ShapeBorder collapsedShape = const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4)), + ); + Color collapsedTextColor = const Color(0xffffffff); + Color collapsedBackgroundColor = const Color(0xffff0000); + Color collapsedIconColor = const Color(0xffffffff); + + await tester.pumpWidget(MaterialApp( + home: Material( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Column( + children: <Widget>[ + ExpansionTile( + key: expansionTileKey, + collapsedShape: collapsedShape, + collapsedTextColor: collapsedTextColor, + collapsedBackgroundColor: collapsedBackgroundColor, + collapsedIconColor: collapsedIconColor, + title: const TestText('title'), + trailing: const TestIcon(), + children: const <Widget>[ + SizedBox(height: 100, width: 100), + ], + ), + // This button is used to update the ExpansionTile properties. + FilledButton( + onPressed: () { + setState(() { + collapsedShape = const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16)), + ); + collapsedTextColor = const Color(0xff000000); + collapsedBackgroundColor = const Color(0xffffff00); + collapsedIconColor = const Color(0xff000000); + }); + }, + child: const Text('Update collapsed properties'), + ), + ], + ); + } + ), + ), + )); + + ShapeDecoration shapeDecoration = tester.firstWidget<Container>(find.descendant( + of: find.byKey(expansionTileKey), + matching: find.byType(Container), + )).decoration! as ShapeDecoration; + + // Test initial ExpansionTile properties. + expect(shapeDecoration.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4)))); + expect(shapeDecoration.color, const Color(0xffff0000)); + expect(tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color, const Color(0xffffffff)); + expect(tester.state<TestTextState>(find.byType(TestText)).textStyle.color, const Color(0xffffffff)); + + // Tap the button to update the ExpansionTile properties. + await tester.tap(find.text('Update collapsed properties')); + await tester.pumpAndSettle(); + + shapeDecoration = tester.firstWidget<Container>(find.descendant( + of: find.byKey(expansionTileKey), + matching: find.byType(Container), + )).decoration! as ShapeDecoration; + + // Test updated ExpansionTile properties. + expect(shapeDecoration.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16)))); + expect(shapeDecoration.color, const Color(0xffffff00)); + expect(tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color, const Color(0xff000000)); + expect(tester.state<TestTextState>(find.byType(TestText)).textStyle.color, const Color(0xff000000)); + }); + + testWidgetsWithLeakTracking('Expanded ExpansionTile properties can be updated with setState', (WidgetTester tester) async { + const Key expansionTileKey = Key('expansionTileKey'); + ShapeBorder shape = const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ); + Color textColor = const Color(0xff00ffff); + Color backgroundColor = const Color(0xff0000ff); + Color iconColor = const Color(0xff00ffff); + + await tester.pumpWidget(MaterialApp( + home: Material( + child: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Column( + children: <Widget>[ + ExpansionTile( + key: expansionTileKey, + shape: shape, + textColor: textColor, + backgroundColor: backgroundColor, + iconColor: iconColor, + title: const TestText('title'), + trailing: const TestIcon(), + children: const <Widget>[ + SizedBox(height: 100, width: 100), + ], + ), + // This button is used to update the ExpansionTile properties. + FilledButton( + onPressed: () { + setState(() { + shape = const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6)), + ); + textColor = const Color(0xffffffff); + backgroundColor = const Color(0xff123456); + iconColor = const Color(0xffffffff); + }); + }, + child: const Text('Update collapsed properties'), + ), + ], + ); + } + ), + ), + )); + + // Tap to expand the ExpansionTile. + await tester.tap(find.text('title')); + await tester.pumpAndSettle(); + + ShapeDecoration shapeDecoration = tester.firstWidget<Container>(find.descendant( + of: find.byKey(expansionTileKey), + matching: find.byType(Container), + )).decoration! as ShapeDecoration; + + // Test initial ExpansionTile properties. + expect(shapeDecoration.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12)))); + expect(shapeDecoration.color, const Color(0xff0000ff)); + expect(tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color, const Color(0xff00ffff)); + expect(tester.state<TestTextState>(find.byType(TestText)).textStyle.color, const Color(0xff00ffff)); + + // Tap the button to update the ExpansionTile properties. + await tester.tap(find.text('Update collapsed properties')); + await tester.pumpAndSettle(); + + shapeDecoration = tester.firstWidget<Container>(find.descendant( + of: find.byKey(expansionTileKey), + matching: find.byType(Container), + )).decoration! as ShapeDecoration; + iconColor = tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color!; + textColor = tester.state<TestTextState>(find.byType(TestText)).textStyle.color!; + + // Test updated ExpansionTile properties. + expect(shapeDecoration.shape, const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(6)))); + expect(shapeDecoration.color, const Color(0xff123456)); + expect(tester.state<TestIconState>(find.byType(TestIcon)).iconTheme.color, const Color(0xffffffff)); + expect(tester.state<TestTextState>(find.byType(TestText)).textStyle.color, const Color(0xffffffff)); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests From c79868b068c391601699ea6147e601bfebbb63b5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 18:06:07 -0400 Subject: [PATCH 1131/1547] Roll Flutter Engine from 8d07c2947e60 to 2dba8ceca824 (2 revisions) (#134243) https://github.com/flutter/engine/compare/8d07c2947e60...2dba8ceca824 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from c3d6534b0ac3 to 59a2610cd83d (1 revision) (flutter/engine#45545) 2023-09-07 bdero@google.com Update impeller-cmake-example (flutter/engine#45526) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f8fe9c840f526..2387854533b4b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8d07c2947e6078f65f43eb8b697e7b349f1a8eb1 +2dba8ceca82445f0ae601aa72cf3b3053da472de From 827b5dff026ed9db9dcc4c9d66fc1db8f86b31aa Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Thu, 7 Sep 2023 18:32:48 -0400 Subject: [PATCH 1132/1547] [integration_test] Allow capture of screenshots for `FlutterFragmentActivity`s (#132406) Fixes https://github.com/flutter/flutter/issues/89683. The changes to `getFlutterView` in `FlutterDeviceScreenshot` are the fix that was required, everything else was done to get tests running (such as re-generating some lockfiles and modifying the android manifest). The code was all currently not unit tested, and there were no other easy examples to base these java unit tests off in flutter/flutter, so let me know if this approach to testing is wrong. --- .ci.yaml | 6 +-- dev/bots/test.dart | 17 ++++++ .../integration_test/android/build.gradle | 5 +- .../android/src/main/AndroidManifest.xml | 2 +- .../FlutterDeviceScreenshot.java | 17 ++++-- .../FlutterDeviceScreenshotTest.java | 52 +++++++++++++++++++ .../android/project-integration_test.lockfile | 5 ++ 7 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 packages/integration_test/android/src/test/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshotTest.java diff --git a/.ci.yaml b/.ci.yaml index 4ce84b8cdae10..fa11c98b6c986 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -598,7 +598,7 @@ targets: {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "build_id:8787856497187628321"}, {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests @@ -3092,7 +3092,7 @@ targets: [ {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "gems", "version": "v3.3.14"}, - {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests @@ -4502,7 +4502,7 @@ targets: [ {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"}, - {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "android_sdk", "version": "version:33v6"} ] shard: framework_tests diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 8408e452d4970..8d9dd00c6ce34 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1004,6 +1004,23 @@ Future<void> _runFrameworkTests() async { // Web-specific tests depend on Chromium, so they run as part of the web_long_running_tests shard. '--exclude-tags=web', ]); + // Run java unit tests for integration_test + // + // Generate Gradle wrapper if it doesn't exist. + Process.runSync( + flutter, + <String>['build', 'apk', '--config-only'], + workingDirectory: path.join(flutterRoot, 'packages', 'integration_test', 'example', 'android'), + ); + await runCommand( + path.join(flutterRoot, 'packages', 'integration_test', 'example', 'android', 'gradlew$bat'), + <String>[ + ':integration_test:testDebugUnitTest', + '--tests', + 'dev.flutter.plugins.integration_test.FlutterDeviceScreenshotTest', + ], + workingDirectory: path.join(flutterRoot, 'packages', 'integration_test', 'example', 'android'), + ); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations')); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test')); diff --git a/packages/integration_test/android/build.gradle b/packages/integration_test/android/build.gradle index ba3e75cde3acb..2f8e2f988feda 100644 --- a/packages/integration_test/android/build.gradle +++ b/packages/integration_test/android/build.gradle @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -group 'com.example.integration_test' +group 'dev.flutter.plugins.integration_test' version '1.0-SNAPSHOT' buildscript { @@ -47,7 +47,8 @@ android { dependencies { // TODO(egarciad): These dependencies should not be added to release builds. // https://github.com/flutter/flutter/issues/56591 - api 'junit:junit:4.12' + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-inline:5.0.0' // https://developer.android.com/jetpack/androidx/releases/test/#1.2.0 api 'androidx.test:runner:1.2.0' diff --git a/packages/integration_test/android/src/main/AndroidManifest.xml b/packages/integration_test/android/src/main/AndroidManifest.xml index b362178b96554..76ada4d34cdad 100644 --- a/packages/integration_test/android/src/main/AndroidManifest.xml +++ b/packages/integration_test/android/src/main/AndroidManifest.xml @@ -3,5 +3,5 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="dev.flutter.integration_test"> + package="dev.flutter.integration_test"> </manifest> diff --git a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshot.java b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshot.java index e9494439d7017..5b376b0277be2 100644 --- a/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshot.java +++ b/packages/integration_test/android/src/main/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshot.java @@ -19,7 +19,11 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.android.FlutterFragment; +import io.flutter.embedding.android.FlutterFragmentActivity; import io.flutter.embedding.android.FlutterSurfaceView; import io.flutter.embedding.android.FlutterView; import io.flutter.plugin.common.MethodChannel; @@ -51,8 +55,15 @@ class FlutterDeviceScreenshot { * @return the Flutter view. */ @Nullable - private static FlutterView getFlutterView(@NonNull Activity activity) { - return (FlutterView)activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID); + @VisibleForTesting + public static FlutterView getFlutterView(@NonNull Activity activity) { + if (activity instanceof FlutterActivity) { + return (FlutterView)activity.findViewById(FlutterActivity.FLUTTER_VIEW_ID); + } else if (activity instanceof FlutterFragmentActivity) { + return (FlutterView)activity.findViewById(FlutterFragment.FLUTTER_VIEW_ID); + } else { + return null; + } } /** @@ -110,7 +121,7 @@ static void revertFlutterImage(@NonNull Activity activity) { } } - // Handlers use to capture a view. + // Handlers used to capture a view. private static Handler backgroundHandler; private static Handler mainHandler; diff --git a/packages/integration_test/android/src/test/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshotTest.java b/packages/integration_test/android/src/test/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshotTest.java new file mode 100644 index 0000000000000..15dfad615ea7a --- /dev/null +++ b/packages/integration_test/android/src/test/java/dev/flutter/plugins/integration_test/FlutterDeviceScreenshotTest.java @@ -0,0 +1,52 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package dev.flutter.plugins.integration_test; + +import androidx.test.runner.AndroidJUnitRunner; + +import org.junit.Test; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.Activity; + +import io.flutter.embedding.android.FlutterActivity; +import io.flutter.embedding.android.FlutterFragment; +import io.flutter.embedding.android.FlutterFragmentActivity; +import io.flutter.embedding.android.FlutterView; + +public class FlutterDeviceScreenshotTest extends AndroidJUnitRunner { + @Test + public void getFlutterView_returnsNullForNonFlutterActivity() { + Activity mockActivity = mock(Activity.class); + assertNull(FlutterDeviceScreenshot.getFlutterView(mockActivity)); + } + + @Test + public void getFlutterView_returnsFlutterViewForFlutterActivity() { + FlutterView mockFlutterView = mock(FlutterView.class); + FlutterActivity mockFlutterActivity = mock(FlutterActivity.class); + when(mockFlutterActivity.findViewById(FlutterActivity.FLUTTER_VIEW_ID)) + .thenReturn(mockFlutterView); + assertEquals( + FlutterDeviceScreenshot.getFlutterView(mockFlutterActivity), + mockFlutterView + ); + } + + @Test + public void getFlutterView_returnsFlutterViewForFlutterFragmentActivity() { + FlutterView mockFlutterView = mock(FlutterView.class); + FlutterFragmentActivity mockFlutterFragmentActivity = mock(FlutterFragmentActivity.class); + when(mockFlutterFragmentActivity.findViewById(FlutterFragment.FLUTTER_VIEW_ID)) + .thenReturn(mockFlutterView); + assertEquals( + FlutterDeviceScreenshot.getFlutterView(mockFlutterFragmentActivity), + mockFlutterView + ); + } +} diff --git a/packages/integration_test/example/android/project-integration_test.lockfile b/packages/integration_test/example/android/project-integration_test.lockfile index 83502ee6b2a0e..0b94d008cc840 100644 --- a/packages/integration_test/example/android/project-integration_test.lockfile +++ b/packages/integration_test/example/android/project-integration_test.lockfile @@ -82,6 +82,8 @@ javax.activation:javax.activation-api:1.2.0=lintClassPath javax.inject:javax.inject:1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath javax.xml.bind:jaxb-api:2.3.1=lintClassPath junit:junit:4.12=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.12.22=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy:1.12.22=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.sf.jopt-simple:jopt-simple:4.9=lintClassPath net.sf.kxml:kxml2:2.3.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.apache.commons:commons-compress:1.12=lintClassPath @@ -118,6 +120,9 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClass org.jetbrains.trove4j:trove4j:20160824=lintClassPath org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jvnet.staxex:stax-ex:1.8=lintClassPath +org.mockito:mockito-core:5.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.mockito:mockito-inline:5.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.objenesis:objenesis:3.3=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-analysis:7.0=lintClassPath org.ow2.asm:asm-analysis:9.2=androidJacocoAnt org.ow2.asm:asm-commons:7.0=lintClassPath From 5a8a20c63e2153546ce0c95e0d7efbb466a3770a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 18:45:35 -0400 Subject: [PATCH 1133/1547] Roll Flutter Engine from 2dba8ceca824 to a828c26e7e97 (8 revisions) (#134249) https://github.com/flutter/engine/compare/2dba8ceca824...a828c26e7e97 2023-09-07 skia-flutter-autoroll@skia.org Roll ANGLE from 204c07a56b64 to cdbc45a9f37e (1 revision) (flutter/engine#45551) 2023-09-07 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from WbB3tmMXnuwJBAHoi... to EuBfOtm5TZIdgNaQe... (flutter/engine#45550) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from ee741e5e8cf3 to ce2c94883cb5 (1 revision) (flutter/engine#45552) 2023-09-07 30870216+gaaclarke@users.noreply.github.com [Impeller] Started tracking the pool with the command buffer. (flutter/engine#45298) 2023-09-07 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 3.6.0 to 4.0.0 (flutter/engine#45439) 2023-09-07 41930132+hellohuanlin@users.noreply.github.com Reverts part of "fix auto-correction highlight on top left corner (Again)" (flutter/engine#45523) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 59a2610cd83d to ee741e5e8cf3 (4 revisions) (flutter/engine#45548) 2023-09-07 skia-flutter-autoroll@skia.org Roll ANGLE from 60b56591dee5 to 204c07a56b64 (7 revisions) (flutter/engine#45546) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from WbB3tmMXnuwJ to EuBfOtm5TZId If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2387854533b4b..0b9fb3382a9be 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2dba8ceca82445f0ae601aa72cf3b3053da472de +a828c26e7e975754045729a9f2f5ef0671f176ac diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 89cc5d81ad805..aae20d716bd9c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -WbB3tmMXnuwJBAHoi1HLqjMfKBh5zvsqNWbcd7TjKU0C +EuBfOtm5TZIdgNaQeJWWcKPpJi17Qi1VVWusGGy1miIC From 1c0b4ad53ab8b935459fbf45c8b17077c7df20c9 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 16:27:12 -0700 Subject: [PATCH 1134/1547] _SearchBarState should dispose FocusNode, if it created it. (#134076) Relanding of revert: https://github.com/flutter/flutter/pull/134072 Verified failed tests succeeded now: --- packages/flutter/lib/src/material/search_anchor.dart | 3 +++ packages/flutter/test/material/search_anchor_test.dart | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 6cb8c22c1c627..4897de7449df8 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -1179,6 +1179,9 @@ class _SearchBarState extends State<SearchBar> { @override void dispose() { _internalStatesController.dispose(); + if (widget.focusNode == null) { + _focusNode.dispose(); + } super.dispose(); } diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index c044bdfc0a4db..c2af15aad9ac1 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -6,9 +6,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SearchBar defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); final ColorScheme colorScheme = theme.colorScheme; From a863ad6e764399e2cb1f5dbb5624d996689b7ae8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 19:27:15 -0400 Subject: [PATCH 1135/1547] Roll Flutter Engine from a828c26e7e97 to 65f6fb841c7a (1 revision) (#134254) https://github.com/flutter/engine/compare/a828c26e7e97...65f6fb841c7a 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from ce2c94883cb5 to efd438ed1c06 (2 revisions) (flutter/engine#45554) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0b9fb3382a9be..2b0288f04aca2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a828c26e7e975754045729a9f2f5ef0671f176ac +65f6fb841c7a4b4932f4825e713d4ab1421b4d61 From cc95ace32cd8022b0206e36f30d5851094eafebd Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 16:59:58 -0700 Subject: [PATCH 1136/1547] CupertinoAlertDialog should not create ScrollController on every build, if null values are passed in constructor. (#134075) Relanding of https://github.com/flutter/flutter/pull/134071 Verified failed tests succeeded now: --- .../flutter/lib/src/cupertino/dialog.dart | 48 ++++++++++++------- .../flutter/test/material/dialog_test.dart | 2 +- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index ef8c10936043b..2e4d27af75740 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -188,7 +188,7 @@ bool _isInAccessibilityMode(BuildContext context) { /// * [CupertinoDialogAction], which is an iOS-style dialog button. /// * [AlertDialog], a Material Design alert dialog. /// * <https://developer.apple.com/ios/human-interface-guidelines/views/alerts/> -class CupertinoAlertDialog extends StatelessWidget { +class CupertinoAlertDialog extends StatefulWidget { /// Creates an iOS-style alert dialog. /// /// The [actions] must not be null. @@ -233,9 +233,6 @@ class CupertinoAlertDialog extends StatelessWidget { /// section when there are many actions. final ScrollController? scrollController; - ScrollController get _effectiveScrollController => - scrollController ?? ScrollController(); - /// A scroll controller that can be used to control the scrolling of the /// actions in the dialog. /// @@ -247,37 +244,49 @@ class CupertinoAlertDialog extends StatelessWidget { /// section when it is long. final ScrollController? actionScrollController; - ScrollController get _effectiveActionScrollController => - actionScrollController ?? ScrollController(); - /// {@macro flutter.material.dialog.insetAnimationDuration} final Duration insetAnimationDuration; /// {@macro flutter.material.dialog.insetAnimationCurve} final Curve insetAnimationCurve; + @override + State<CupertinoAlertDialog> createState() => _CupertinoAlertDialogState(); +} + +class _CupertinoAlertDialogState extends State<CupertinoAlertDialog> { + ScrollController? _backupScrollController; + + ScrollController? _backupActionScrollController; + + ScrollController get _effectiveScrollController => + widget.scrollController ?? (_backupScrollController ??= ScrollController()); + + ScrollController get _effectiveActionScrollController => + widget.actionScrollController ?? (_backupActionScrollController ??= ScrollController()); + Widget _buildContent(BuildContext context) { final double textScaleFactor = MediaQuery.textScalerOf(context).textScaleFactor; final List<Widget> children = <Widget>[ - if (title != null || content != null) + if (widget.title != null || widget.content != null) Flexible( flex: 3, child: _CupertinoAlertContentSection( - title: title, - message: content, + title: widget.title, + message: widget.content, scrollController: _effectiveScrollController, titlePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, - bottom: content == null ? _kDialogEdgePadding : 1.0, + bottom: widget.content == null ? _kDialogEdgePadding : 1.0, top: _kDialogEdgePadding * textScaleFactor, ), messagePadding: EdgeInsets.only( left: _kDialogEdgePadding, right: _kDialogEdgePadding, bottom: _kDialogEdgePadding * textScaleFactor, - top: title == null ? _kDialogEdgePadding : 1.0, + top: widget.title == null ? _kDialogEdgePadding : 1.0, ), titleTextStyle: _kCupertinoDialogTitleStyle.copyWith( color: CupertinoDynamicColor.resolve(CupertinoColors.label, context), @@ -303,10 +312,10 @@ class CupertinoAlertDialog extends StatelessWidget { Widget actionSection = Container( height: 0.0, ); - if (actions.isNotEmpty) { + if (widget.actions.isNotEmpty) { actionSection = _CupertinoAlertActionSection( scrollController: _effectiveActionScrollController, - children: actions, + children: widget.actions, ); } @@ -330,8 +339,8 @@ class CupertinoAlertDialog extends StatelessWidget { return AnimatedPadding( padding: MediaQuery.viewInsetsOf(context) + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), - duration: insetAnimationDuration, - curve: insetAnimationCurve, + duration: widget.insetAnimationDuration, + curve: widget.insetAnimationCurve, child: MediaQuery.removeViewInsets( removeLeft: true, removeTop: true, @@ -368,6 +377,13 @@ class CupertinoAlertDialog extends StatelessWidget { ), ); } + + @override + void dispose() { + _backupScrollController?.dispose(); + _backupActionScrollController?.dispose(); + super.dispose(); + } } /// Rounded rectangle surface that looks like an iOS popup surface, e.g., alert dialog diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 98755d1daea06..0a162059412d9 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -2664,7 +2664,7 @@ void main() { okNode.dispose(); }); - testWidgets('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adaptive AlertDialog shows correct widget on each platform', (WidgetTester tester) async { final AlertDialog dialog = AlertDialog.adaptive( content: Container( height: 5000.0, From e08173e767e33c54c8da261584616912ddc54d3b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 20:31:23 -0400 Subject: [PATCH 1137/1547] Roll Flutter Engine from 65f6fb841c7a to 505ef3c33102 (4 revisions) (#134260) https://github.com/flutter/engine/compare/65f6fb841c7a...505ef3c33102 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from 17f36a6a101e to 1b8a25d05c45 (2 revisions) (flutter/engine#45560) 2023-09-07 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from N915IZbyx6MSrwwS-... to 33DToYd0jNpWX1jNv... (flutter/engine#45559) 2023-09-07 skia-flutter-autoroll@skia.org Roll Skia from efd438ed1c06 to 17f36a6a101e (2 revisions) (flutter/engine#45557) 2023-09-07 skia-flutter-autoroll@skia.org Roll ANGLE from cdbc45a9f37e to a412b149d5b1 (2 revisions) (flutter/engine#45556) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from N915IZbyx6MS to 33DToYd0jNpW If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2b0288f04aca2..679714223eedd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -65f6fb841c7a4b4932f4825e713d4ab1421b4d61 +505ef3c331022bc1e1fe3c04adc06e76361b9eb7 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 186cca0b4b744..9389cb1cbdaff 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -N915IZbyx6MSrwwS-3J0xJZoPKn9b8mmLqTUqZ-XPfUC +33DToYd0jNpWX1jNvzNb2QKwGX6NoNO2y9C4Ai2V7cgC From 0d30546c74afb2fdb648aa6dce5ad2ae1a28f43b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 17:49:33 -0700 Subject: [PATCH 1138/1547] TestWidgetsFlutterBinding should dispose old RestorationManager on reset. (#133999) --- packages/flutter_test/lib/src/binding.dart | 1 + .../test/bindings_reset_test.dart | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 packages/flutter_test/test/bindings_reset_test.dart diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index 545490b836f5a..b87105680848a 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -244,6 +244,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase /// If [registerTestTextInput] returns true when this method is called, /// the [testTextInput] is configured to simulate the keyboard. void reset() { + _restorationManager?.dispose(); _restorationManager = null; resetGestureBinding(); testTextInput.reset(); diff --git a/packages/flutter_test/test/bindings_reset_test.dart b/packages/flutter_test/test/bindings_reset_test.dart new file mode 100644 index 0000000000000..57dee3220438e --- /dev/null +++ b/packages/flutter_test/test/bindings_reset_test.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('Disposes restoration manager on reset.', () { + final AutomatedTestWidgetsFlutterBinding binding = AutomatedTestWidgetsFlutterBinding(); + int oldCounter = 0; + final TestRestorationManager oldRestorationManager = binding.restorationManager; + oldRestorationManager.addListener(() => oldCounter++); + + oldRestorationManager.notifyListeners(); + expect(oldCounter, 1); + + binding.reset(); + expect(oldRestorationManager.notifyListeners, throwsA((Object e) => e.toString().contains('disposed'))); + }); +} From 161c7090ffbee26af7be560047cd9bee73342c85 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 17:49:59 -0700 Subject: [PATCH 1139/1547] EditableTextState should dispose cursorVisibilityNotifier. (#133858) --- packages/flutter/lib/src/widgets/editable_text.dart | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index d3e8663271ac5..264ca6665bcf0 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -2125,7 +2125,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien late final Simulation _iosBlinkCursorSimulation = _DiscreteKeyFrameSimulation.iOSBlinkingCaret(); final ValueNotifier<bool> _cursorVisibilityNotifier = ValueNotifier<bool>(true); - final ValueNotifier<bool> _debugCursorNotifier = ValueNotifier<bool>(true); final GlobalKey _editableKey = GlobalKey(); /// Detects whether the clipboard can paste. @@ -2803,8 +2802,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien void didChangeDependencies() { super.didChangeDependencies(); - _debugCursorNotifier.value = widget.showCursor; - _style = MediaQuery.boldTextOf(context) ? widget.style.merge(const TextStyle(fontWeight: FontWeight.bold)) : widget.style; @@ -2959,7 +2956,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien clipboardStatus.removeListener(_onChangedClipboardStatus); clipboardStatus.dispose(); _cursorVisibilityNotifier.dispose(); - _debugCursorNotifier.dispose(); FocusManager.instance.removeListener(_unflagInternalFocus); super.dispose(); assert(_batchEditDepth <= 0, 'unfinished batch edits: $_batchEditDepth'); @@ -3879,7 +3875,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien void _onCursorColorTick() { final double effectiveOpacity = math.min(widget.cursorColor.alpha / 255.0, _cursorBlinkOpacityController.value); renderEditable.cursorColor = widget.cursorColor.withOpacity(effectiveOpacity); - _cursorVisibilityNotifier.value = widget.showCursor && _cursorBlinkOpacityController.value > 0; + _cursorVisibilityNotifier.value = widget.showCursor && (EditableText.debugDeterministicCursor || _cursorBlinkOpacityController.value > 0); } bool get _showBlinkingCursor => _hasFocus && _value.selection.isCollapsed && widget.showCursor && _tickersEnabled; @@ -4860,9 +4856,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien value: _value, cursorColor: _cursorColor, backgroundCursorColor: widget.backgroundCursorColor, - showCursor: EditableText.debugDeterministicCursor - ? _debugCursorNotifier - : _cursorVisibilityNotifier, + showCursor: _cursorVisibilityNotifier, forceLine: widget.forceLine, readOnly: widget.readOnly, hasFocus: _hasFocus, From 237ddcc3399b4377c852ba9376b92e9121cebd45 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 17:50:23 -0700 Subject: [PATCH 1140/1547] Remove non needed controllers in SegmentedButton. (#134064) --- .../lib/src/material/segmented_button.dart | 30 ++++++++++-- .../test/material/segmented_button_test.dart | 46 +++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/material/segmented_button.dart b/packages/flutter/lib/src/material/segmented_button.dart index ea513282bd658..df5ab3a6d8e9a 100644 --- a/packages/flutter/lib/src/material/segmented_button.dart +++ b/packages/flutter/lib/src/material/segmented_button.dart @@ -236,12 +236,32 @@ class SegmentedButton<T> extends StatefulWidget { final Widget? selectedIcon; @override - State<SegmentedButton<T>> createState() => _SegmentedButtonState<T>(); + State<SegmentedButton<T>> createState() => SegmentedButtonState<T>(); } -class _SegmentedButtonState<T> extends State<SegmentedButton<T>> { +/// State for [SegmentedButton]. +@visibleForTesting +class SegmentedButtonState<T> extends State<SegmentedButton<T>> { bool get _enabled => widget.onSelectionChanged != null; - final Map<ButtonSegment<T>, MaterialStatesController> _statesControllers = <ButtonSegment<T>, MaterialStatesController>{}; + + /// Controllers for the [ButtonSegment]s. + @visibleForTesting + final Map<ButtonSegment<T>, MaterialStatesController> statesControllers = <ButtonSegment<T>, MaterialStatesController>{}; + + @override + void didUpdateWidget(covariant SegmentedButton<T> oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget != widget) { + statesControllers.removeWhere((ButtonSegment<T> segment, MaterialStatesController controller) { + if (widget.segments.contains(segment)) { + return false; + } else { + controller.dispose(); + return true; + } + }); + } + } void _handleOnPressed(T segmentValue) { if (!_enabled) { @@ -325,7 +345,7 @@ class _SegmentedButtonState<T> extends State<SegmentedButton<T>> { : segment.label != null ? segment.icon : null; - final MaterialStatesController controller = _statesControllers.putIfAbsent(segment, () => MaterialStatesController()); + final MaterialStatesController controller = statesControllers.putIfAbsent(segment, () => MaterialStatesController()); controller.value = <MaterialState>{ if (segmentSelected) MaterialState.selected, }; @@ -391,7 +411,7 @@ class _SegmentedButtonState<T> extends State<SegmentedButton<T>> { @override void dispose() { - for (final MaterialStatesController controller in _statesControllers.values) { + for (final MaterialStatesController controller in statesControllers.values) { controller.dispose(); } super.dispose(); diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index 06e3d13e546e8..bc53f6766d200 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -21,6 +21,52 @@ Widget boilerplate({required Widget child}) { } void main() { + testWidgetsWithLeakTracking('SegmentedButton releases state controllers for deleted segments', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + final Key key = UniqueKey(); + + Widget buildApp(Widget button) { + return MaterialApp( + theme: theme, + home: Scaffold( + body: Center( + child: button, + ), + ), + ); + } + + await tester.pumpWidget( + buildApp( + SegmentedButton<int>( + key: key, + segments: const <ButtonSegment<int>>[ + ButtonSegment<int>(value: 1, label: Text('1')), + ButtonSegment<int>(value: 2, label: Text('2')), + ], + selected: const <int>{2}, + ), + ), + ); + + await tester.pumpWidget( + buildApp( + SegmentedButton<int>( + key: key, + segments: const <ButtonSegment<int>>[ + ButtonSegment<int>(value: 2, label: Text('2')), + ButtonSegment<int>(value: 3, label: Text('3')), + ], + selected: const <int>{2}, + ), + ), + ); + + final SegmentedButtonState<int> state = tester.state(find.byType(SegmentedButton<int>)); + expect(state.statesControllers, hasLength(2)); + expect(state.statesControllers.keys.first.value, 2); + expect(state.statesControllers.keys.last.value, 3); + }); testWidgetsWithLeakTracking('SegmentedButton is built with Material of type MaterialType.transparency', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); From 3ff0beb5fa8f1b5084bd3bb62e11f2828e59609d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 7 Sep 2023 17:50:45 -0700 Subject: [PATCH 1141/1547] _TabBarViewState should dispose created instances of PageController. (#134091) --- packages/flutter/lib/src/material/tabs.dart | 20 +++++---- .../test/material/page_selector_test.dart | 45 +++---------------- .../flutter/test/material/scrollbar_test.dart | 9 +--- .../material/tabbed_scrollview_warp_test.dart | 9 +--- 4 files changed, 19 insertions(+), 64 deletions(-) diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index b727c8a3d47ad..761540d77c91b 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -1783,7 +1783,7 @@ class TabBarView extends StatefulWidget { class _TabBarViewState extends State<TabBarView> { TabController? _controller; - late PageController _pageController; + PageController? _pageController; late List<Widget> _childrenWithKey; int? _currentIndex; int _warpUnderwayCount = 0; @@ -1825,7 +1825,7 @@ class _TabBarViewState extends State<TabBarView> { void _jumpToPage(int page) { _warpUnderwayCount += 1; - _pageController.jumpToPage(page); + _pageController!.jumpToPage(page); _warpUnderwayCount -= 1; } @@ -1835,7 +1835,7 @@ class _TabBarViewState extends State<TabBarView> { required Curve curve, }) async { _warpUnderwayCount += 1; - await _pageController.animateToPage(page, duration: duration, curve: curve); + await _pageController!.animateToPage(page, duration: duration, curve: curve); _warpUnderwayCount -= 1; } @@ -1850,6 +1850,8 @@ class _TabBarViewState extends State<TabBarView> { super.didChangeDependencies(); _updateTabController(); _currentIndex = _controller!.index; + // TODO(chunhtai): https://github.com/flutter/flutter/issues/134253 + _pageController?.dispose(); _pageController = PageController( initialPage: _currentIndex!, viewportFraction: widget.viewportFraction, @@ -1877,6 +1879,7 @@ class _TabBarViewState extends State<TabBarView> { _controller!.animation!.removeListener(_handleTabControllerAnimationTick); } _controller = null; + _pageController?.dispose(); // We don't own the _controller Animation, so it's not disposed here. super.dispose(); } @@ -1897,7 +1900,7 @@ class _TabBarViewState extends State<TabBarView> { } void _warpToCurrentIndex() { - if (!mounted || _pageController.page == _currentIndex!.toDouble()) { + if (!mounted || _pageController!.page == _currentIndex!.toDouble()) { return; } @@ -1957,7 +1960,7 @@ class _TabBarViewState extends State<TabBarView> { } void _syncControllerOffset() { - _controller!.offset = clampDouble(_pageController.page! - _controller!.index, -1.0, 1.0); + _controller!.offset = clampDouble(_pageController!.page! - _controller!.index, -1.0, 1.0); } // Called when the PageView scrolls @@ -1975,15 +1978,16 @@ class _TabBarViewState extends State<TabBarView> { } _scrollUnderwayCount += 1; + final double page = _pageController!.page!; if (notification is ScrollUpdateNotification && !_controller!.indexIsChanging) { - final bool pageChanged = (_pageController.page! - _controller!.index).abs() > 1.0; + final bool pageChanged = (page - _controller!.index).abs() > 1.0; if (pageChanged) { - _controller!.index = _pageController.page!.round(); + _controller!.index = page.round(); _currentIndex =_controller!.index; } _syncControllerOffset(); } else if (notification is ScrollEndNotification) { - _controller!.index = _pageController.page!.round(); + _controller!.index = page.round(); _currentIndex = _controller!.index; if (!_controller!.indexIsChanging) { _syncControllerOffset(); diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 08442967b3646..431770fd6460d 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -84,14 +84,7 @@ void main() { await tester.pump(); expect(tabController.index, 2); expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]); - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 1, - }, - )); + }); testWidgetsWithLeakTracking('PageSelector responds correctly to TabController.animateTo()', (WidgetTester tester) async { final TabController tabController = TabController( @@ -134,14 +127,7 @@ void main() { await tester.pumpAndSettle(); expect(tabController.index, 2); expect(indicatorColors(tester), const <Color>[kUnselectedColor, kUnselectedColor, kSelectedColor]); - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 1, - }, - )); + }); testWidgetsWithLeakTracking('PageSelector responds correctly to TabBarView drags', (WidgetTester tester) async { final TabController tabController = TabController( @@ -199,14 +185,7 @@ void main() { await tester.fling(find.byType(TabBarView), const Offset(100.0, 0.0), 1000.0); await tester.pumpAndSettle(); expect(indicatorColors(tester), const <Color>[kUnselectedColor, kSelectedColor, kUnselectedColor]); - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 1, - }, - )); + }); testWidgetsWithLeakTracking('PageSelector indicatorColors', (WidgetTester tester) async { const Color kRed = Color(0xFFFF0000); @@ -225,14 +204,7 @@ void main() { tabController.index = 0; await tester.pumpAndSettle(); expect(indicatorColors(tester), const <Color>[kBlue, kRed, kRed]); - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 1, - }, - )); + }); testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( @@ -299,12 +271,5 @@ void main() { for (final TabPageSelectorIndicator indicator in indicators) { expect(indicator.borderStyle, BorderStyle.solid); } - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 1, - }, - )); + }); } diff --git a/packages/flutter/test/material/scrollbar_test.dart b/packages/flutter/test/material/scrollbar_test.dart index a062cb0bbec03..25e2fdf4e00b6 100644 --- a/packages/flutter/test/material/scrollbar_test.dart +++ b/packages/flutter/test/material/scrollbar_test.dart @@ -1834,14 +1834,7 @@ void main() { ); scrollController.dispose(); - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 2, - }, - )); + }); testWidgetsWithLeakTracking('Scrollbar scrollOrientation works correctly', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); diff --git a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart index b26b6a68c9b18..98e1dd8280b40 100644 --- a/packages/flutter/test/material/tabbed_scrollview_warp_test.dart +++ b/packages/flutter/test/material/tabbed_scrollview_warp_test.dart @@ -81,12 +81,5 @@ void main() { // should not crash. await tester.tap(find.text('Tab 2')); await tester.pumpAndSettle(); - }, - // TODO(someone): remove after fixing - // https://github.com/flutter/flutter/issues/133755 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{ - 'PageController': 1, - }, - )); + }); } From 7cbaa2a41e6829fa1e7a0a479abaf4b4d226c092 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 21:29:29 -0400 Subject: [PATCH 1142/1547] Roll Flutter Engine from 505ef3c33102 to df3965a55fd8 (1 revision) (#134263) https://github.com/flutter/engine/compare/505ef3c33102...df3965a55fd8 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from a412b149d5b1 to 99d39241ad4d (1 revision) (flutter/engine#45562) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 679714223eedd..5f57fd2b388c8 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -505ef3c331022bc1e1fe3c04adc06e76361b9eb7 +df3965a55fd8db28a4190fe6d661295b55282bdd From 1c3c0f8a566d585e17d6cbbbcf6a8630c20198fa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 7 Sep 2023 23:24:37 -0400 Subject: [PATCH 1143/1547] Roll Flutter Engine from df3965a55fd8 to 4ac4429a206b (1 revision) (#134267) https://github.com/flutter/engine/compare/df3965a55fd8...4ac4429a206b 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 1b8a25d05c45 to 658025e9efdd (1 revision) (flutter/engine#45563) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5f57fd2b388c8..995f670772b50 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -df3965a55fd8db28a4190fe6d661295b55282bdd +4ac4429a206beb32f6511932a36e442f35c000df From fa1133586a2070f43d1912ef013b0aa09f3ff6c0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 00:08:32 -0400 Subject: [PATCH 1144/1547] Roll Flutter Engine from 4ac4429a206b to ea1d0d28e26f (1 revision) (#134270) https://github.com/flutter/engine/compare/4ac4429a206b...ea1d0d28e26f 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 658025e9efdd to fb4faa8646f8 (1 revision) (flutter/engine#45564) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 995f670772b50..cf1dac1a76e53 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4ac4429a206beb32f6511932a36e442f35c000df +ea1d0d28e26fae41a3611aa551bc85322ca48766 From bb8de2167aa3a5da902fad16f914f4ce2a4a48cb Mon Sep 17 00:00:00 2001 From: Taha Tesser <tessertaha@gmail.com> Date: Fri, 8 Sep 2023 11:14:05 +0300 Subject: [PATCH 1145/1547] Fix `Drawer` examples are missing `dartpad` tag (#134219) fixes [`Drawer` examples are misssing `dartpad` tag]( https://github.com/flutter/flutter/issues/134217) these examples were updated in https://github.com/flutter/flutter/pull/130523 --- packages/flutter/lib/src/material/drawer.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index fb3ac51bbc36a..b4bd85a94709c 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -79,11 +79,11 @@ const Duration _kBaseSettleDuration = Duration(milliseconds: 246); /// are a little bit different, see the Material 3 spec at /// <https://m3.material.io/components/navigation-drawer/overview> for /// more details. While the [Drawer] widget can have only one child, the -/// [NavigationDrawer] widget can have list of widgets, which typically contains +/// [NavigationDrawer] widget can have a list of widgets, which typically contains /// [NavigationDrawerDestination] widgets and/or customized widgets like headlines /// and dividers. /// -/// {@tool snippet} +/// {@tool dartpad} /// This example shows how to create a [Scaffold] that contains an [AppBar] and /// a [Drawer]. A user taps the "menu" icon in the [AppBar] to open the /// [Drawer]. The [Drawer] displays four items: A header and three menu items. @@ -93,10 +93,10 @@ const Duration _kBaseSettleDuration = Duration(milliseconds: 246); /// ** See code in examples/api/lib/material/drawer/drawer.0.dart ** /// {@end-tool} /// -/// {@tool snippet} +/// {@tool dartpad} /// This example shows how to migrate the above [Drawer] to a [NavigationDrawer]. /// -/// ** See code in examples/api/lib/material/navigation_drawer/navigation_drawer.1.dart ** +/// ** See code in examples/api/lib/material/navigation_drawer/navigation_drawer.0.dart ** /// {@end-tool} /// /// An open drawer may be closed with a swipe to close gesture, pressing the From f4707c2b3dabfb5ec4b15159c9257db37a15a59a Mon Sep 17 00:00:00 2001 From: xubaolin <xubaolin@oppo.com> Date: Fri, 8 Sep 2023 17:40:49 +0800 Subject: [PATCH 1146/1547] fix a Scrollbar example crash (#127925) Fix a scrollbar example crash. https://api.flutter.dev/flutter/material/Scrollbar-class.html#material.Scrollbar.1 --- dev/bots/check_code_samples.dart | 1 - .../lib/material/scrollbar/scrollbar.0.dart | 1 + .../material/scrollbar/scrollbar.0_test.dart | 21 +++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 examples/api/test/material/scrollbar/scrollbar.0_test.dart diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart index 029e6322a1a1f..8e4aab41d4e8d 100644 --- a/dev/bots/check_code_samples.dart +++ b/dev/bots/check_code_samples.dart @@ -319,7 +319,6 @@ final Set<String> _knownMissingTests = <String>{ 'examples/api/test/material/filled_button/filled_button.0_test.dart', 'examples/api/test/material/text_form_field/text_form_field.1_test.dart', 'examples/api/test/material/scrollbar/scrollbar.1_test.dart', - 'examples/api/test/material/scrollbar/scrollbar.0_test.dart', 'examples/api/test/material/dropdown_menu/dropdown_menu.1_test.dart', 'examples/api/test/material/radio/radio.toggleable.0_test.dart', 'examples/api/test/material/radio/radio.0_test.dart', diff --git a/examples/api/lib/material/scrollbar/scrollbar.0.dart b/examples/api/lib/material/scrollbar/scrollbar.0.dart index d8a09486b6cb0..07f1eb4646ad5 100644 --- a/examples/api/lib/material/scrollbar/scrollbar.0.dart +++ b/examples/api/lib/material/scrollbar/scrollbar.0.dart @@ -29,6 +29,7 @@ class ScrollbarExample extends StatelessWidget { Widget build(BuildContext context) { return Scrollbar( child: GridView.builder( + primary: true, itemCount: 120, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3), itemBuilder: (BuildContext context, int index) { diff --git a/examples/api/test/material/scrollbar/scrollbar.0_test.dart b/examples/api/test/material/scrollbar/scrollbar.0_test.dart new file mode 100644 index 0000000000000..330f4f9408fcf --- /dev/null +++ b/examples/api/test/material/scrollbar/scrollbar.0_test.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/scrollbar/scrollbar.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('Scrollbar.0 works well on all platforms', (WidgetTester tester) async { + + await tester.pumpWidget( + const example.ScrollbarExampleApp(), + ); + + final Finder buttonFinder = find.byType(Scrollbar); + await tester.drag(buttonFinder.last, const Offset(0, 100.0)); + + expect(tester.takeException(), isNull); + }, variant: TargetPlatformVariant.all()); +} From 0ddfe9090f67b841a23a5c49dbf270b596ff6aa1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 06:55:12 -0400 Subject: [PATCH 1147/1547] Roll Flutter Engine from ea1d0d28e26f to a140ab4a4ec6 (5 revisions) (#134288) https://github.com/flutter/engine/compare/ea1d0d28e26f...a140ab4a4ec6 2023-09-08 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from EuBfOtm5TZIdgNaQe... to h_bQLstuirD8blCZW... (flutter/engine#45571) 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from 99d39241ad4d to e60556f75b68 (1 revision) (flutter/engine#45569) 2023-09-08 bdero@google.com [Impeller] Aiks image filters; allow setting effect transforms after FilterContents instantiation. (flutter/engine#45530) 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from ce3ec572ae77 to ece9f3a15b08 (1 revision) (flutter/engine#45568) 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from fb4faa8646f8 to ce3ec572ae77 (1 revision) (flutter/engine#45567) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from EuBfOtm5TZId to h_bQLstuirD8 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cf1dac1a76e53..5c996dc3d1d05 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ea1d0d28e26fae41a3611aa551bc85322ca48766 +a140ab4a4ec6e12086d57c179a43e1b101995157 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index aae20d716bd9c..70bf494ee87c2 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -EuBfOtm5TZIdgNaQeJWWcKPpJi17Qi1VVWusGGy1miIC +h_bQLstuirD8blCZWjrkPzMPx4VbRdEiV93QgP9zvckC From 2d9680bab2a03371da6ceda6ac30235ebe57128a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 08:09:26 -0400 Subject: [PATCH 1148/1547] Roll Flutter Engine from a140ab4a4ec6 to f146d4bf244b (1 revision) (#134290) https://github.com/flutter/engine/compare/a140ab4a4ec6...f146d4bf244b 2023-09-08 whesse@google.com Add dart2wasm dependency to flutter_frontend_server (flutter/engine#45570) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5c996dc3d1d05..5fc351587b76b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a140ab4a4ec6e12086d57c179a43e1b101995157 +f146d4bf244b5bb5119a12cd0ea873cc3942d51b From 2681e873e29b0781d4a13607f83d49512a5c7dbc Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 09:32:11 -0400 Subject: [PATCH 1149/1547] Roll Flutter Engine from f146d4bf244b to c38feb382e96 (1 revision) (#134293) https://github.com/flutter/engine/compare/f146d4bf244b...c38feb382e96 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from e60556f75b68 to 65ec697f4183 (1 revision) (flutter/engine#45572) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5fc351587b76b..b8cad7f87cbe1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f146d4bf244b5bb5119a12cd0ea873cc3942d51b +c38feb382e964b10697403615f5428407708d5aa From 7b06874ef56522693759e256c687e013bfaeb574 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 10:13:16 -0400 Subject: [PATCH 1150/1547] Roll Flutter Engine from c38feb382e96 to f09a139101c3 (1 revision) (#134299) https://github.com/flutter/engine/compare/c38feb382e96...f09a139101c3 2023-09-08 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 33DToYd0jNpWX1jNv... to KvtLknmg3f23uqWVm... (flutter/engine#45573) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 33DToYd0jNpW to KvtLknmg3f23 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b8cad7f87cbe1..fd4ae8f514f5b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c38feb382e964b10697403615f5428407708d5aa +f09a139101c35a3dd041265c3a10f2105f30fa88 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 9389cb1cbdaff..85ab851fadfad 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -33DToYd0jNpWX1jNvzNb2QKwGX6NoNO2y9C4Ai2V7cgC +KvtLknmg3f23uqWVmAC4HGmxtv2DgAUqg3fBk-q6qloC From 53017f8525e6c68c27533a15c98bc2e0e08e8c86 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 11:38:28 -0400 Subject: [PATCH 1151/1547] Roll Packages from 22d475491502 to aaae5ef97a45 (7 revisions) (#134301) https://github.com/flutter/packages/compare/22d475491502...aaae5ef97a45 2023-09-08 43054281+camsim99@users.noreply.github.com [tool] Add Android dependency (gradle) option to update dependencies command (flutter/packages#4757) 2023-09-08 43054281+camsim99@users.noreply.github.com [camerax] Implement resolution configuration (flutter/packages#3799) 2023-09-07 engine-flutter-autoroll@skia.org Manual roll Flutter from 685ce14b2d0f to aea4552acdc7 (64 revisions) (flutter/packages#4870) 2023-09-07 ditman@gmail.com [rfw, ci] Regenerate goldens, manually roll #4835 (flutter/packages#4862) 2023-09-07 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 3.6.0 to 4.0.0 (flutter/packages#4845) 2023-09-07 defuncart@gmail.com [video_player] Add optional web options [web] (flutter/packages#4551) 2023-09-07 me@nils.re [flutter_markdown] Remove `ignore: avoid_init_to_null` since the package uses Dart 3 (flutter/packages#4852) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 59a33a9d1f228..0ebad43927a54 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -22d475491502301d020b3af37b4a5e29e5182f7c +aaae5ef97a45885fdf5eac0b655a8085a80a25e4 From 3ce6174e6b49a92663419a9dc31d2acdca909c27 Mon Sep 17 00:00:00 2001 From: Greg Spencer <gspencergoog@users.noreply.github.com> Date: Fri, 8 Sep 2023 09:42:50 -0700 Subject: [PATCH 1152/1547] Update links to iOS embedder docs to point to new Doxygen docs (#134246) ## Description Now that we are using Doxygen for building docs for the embedders, this updates the links to point to the correct URLs. ## Related Issues - https://github.com/flutter/flutter/issues/124833 ## Related PRs - https://github.com/flutter/engine/pull/45561 --- packages/flutter/lib/src/rendering/layer.dart | 4 ++-- packages/flutter/lib/src/rendering/texture.dart | 4 ++-- packages/flutter/lib/src/services/restoration.dart | 2 +- packages/flutter/lib/src/widgets/platform_view.dart | 4 ++-- packages/flutter/lib/src/widgets/texture.dart | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index d7777918636b9..b8cd83fac5e32 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -919,9 +919,9 @@ class PictureLayer extends Layer { /// /// See also: /// -/// * <https://api.flutter.dev/javadoc/io/flutter/view/TextureRegistry.html> +/// * [TextureRegistry](/javadoc/io/flutter/view/TextureRegistry.html) /// for how to create and manage backend textures on Android. -/// * <https://api.flutter.dev/objcdoc/Protocols/FlutterTextureRegistry.html> +/// * [TextureRegistry Protocol](/ios-embedder/protocol_flutter_texture_registry-p.html) /// for how to create and manage backend textures on iOS. class TextureLayer extends Layer { /// Creates a texture layer bounded by [rect] and with backend texture diff --git a/packages/flutter/lib/src/rendering/texture.dart b/packages/flutter/lib/src/rendering/texture.dart index 0485ab12abe95..fcbaaa3ed09d9 100644 --- a/packages/flutter/lib/src/rendering/texture.dart +++ b/packages/flutter/lib/src/rendering/texture.dart @@ -29,9 +29,9 @@ import 'object.dart'; /// /// See also: /// -/// * <https://api.flutter.dev/javadoc/io/flutter/view/TextureRegistry.html> +/// * [TextureRegistry](/javadoc/io/flutter/view/TextureRegistry.html) /// for how to create and manage backend textures on Android. -/// * <https://api.flutter.dev/objcdoc/Protocols/FlutterTextureRegistry.html> +/// * [TextureRegistry Protocol](/ios-embedder/protocol_flutter_texture_registry-p.html) /// for how to create and manage backend textures on iOS. class TextureBox extends RenderBox { /// Creates a box backed by the texture identified by [textureId], and use diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index b55c438f44345..0e638d84b4771 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -92,7 +92,7 @@ typedef _BucketVisitor = void Function(RestorationBucket bucket); /// ## State Restoration on iOS /// /// To enable state restoration on iOS, a restoration identifier has to be -/// assigned to the [FlutterViewController](https://api.flutter.dev/objcdoc/Classes/FlutterViewController.html). +/// assigned to the [FlutterViewController](/ios-embedder/interface_flutter_view_controller.html). /// If the standard embedding (produced by `flutter create`) is used, this can /// be accomplished with the following steps: /// diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index 05b2b5753d9b7..1115bb887038f 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -230,13 +230,13 @@ abstract class _DarwinView extends StatefulWidget { /// {@macro flutter.widgets.AndroidView.layoutDirection} final TextDirection? layoutDirection; - /// Passed as the `arguments` argument of [-\[FlutterPlatformViewFactory createWithFrame:viewIdentifier:arguments:\]](/objcdoc/Protocols/FlutterPlatformViewFactory.html#/c:objc(pl)FlutterPlatformViewFactory(im)createWithFrame:viewIdentifier:arguments:) + /// Passed as the `arguments` argument of [-\[FlutterPlatformViewFactory createWithFrame:viewIdentifier:arguments:\]](/ios-embedder/protocol_flutter_platform_view_factory-p.html#a4e3c4390cd6ebd982390635e9bca4edc) /// /// This can be used by plugins to pass constructor parameters to the embedded iOS view. final dynamic creationParams; /// The codec used to encode `creationParams` before sending it to the - /// platform side. It should match the codec returned by [-\[FlutterPlatformViewFactory createArgsCodec:\]](/objcdoc/Protocols/FlutterPlatformViewFactory.html#/c:objc(pl)FlutterPlatformViewFactory(im)createArgsCodec) + /// platform side. It should match the codec returned by [-\[FlutterPlatformViewFactory createArgsCodec:\]](/ios-embedder/protocol_flutter_platform_view_factory-p.html#a32c3c067cb45a83dfa720c74a0d5c93c) /// /// This is typically one of: [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]. /// diff --git a/packages/flutter/lib/src/widgets/texture.dart b/packages/flutter/lib/src/widgets/texture.dart index ce68edef1e191..4f506b46e1a89 100644 --- a/packages/flutter/lib/src/widgets/texture.dart +++ b/packages/flutter/lib/src/widgets/texture.dart @@ -28,9 +28,9 @@ import 'framework.dart'; /// /// See also: /// -/// * <https://api.flutter.dev/javadoc/io/flutter/view/TextureRegistry.html> +/// * [TextureRegistry](/javadoc/io/flutter/view/TextureRegistry.html) /// for how to create and manage backend textures on Android. -/// * <https://api.flutter.dev/objcdoc/Protocols/FlutterTextureRegistry.html> +/// * [TextureRegistry Protocol](/ios-embedder/protocol_flutter_texture_registry-p.html) /// for how to create and manage backend textures on iOS. class Texture extends LeafRenderObjectWidget { /// Creates a widget backed by the texture identified by [textureId], and use From fc671188c4852c80a41e23c8937719706da13759 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 12:52:55 -0400 Subject: [PATCH 1153/1547] Roll Flutter Engine from f09a139101c3 to 6d6b44886175 (3 revisions) (#134306) https://github.com/flutter/engine/compare/f09a139101c3...6d6b44886175 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 71e40cc0faf6 to c5e67d222f46 (4 revisions) (flutter/engine#45576) 2023-09-08 rmolivares@renzo-olivares.dev [Web] Fix insertions/deletions at inverted selection for TextEditingDeltas (flutter/engine#44693) 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from ece9f3a15b08 to 71e40cc0faf6 (1 revision) (flutter/engine#45575) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fd4ae8f514f5b..4a8def898d978 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f09a139101c35a3dd041265c3a10f2105f30fa88 +6d6b44886175f4982dbe7aa42ffc39b654442b71 From 804a7b285f6d5ce2f4f3b70ea1ee81ff2744cd7a Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 8 Sep 2023 09:52:57 -0700 Subject: [PATCH 1154/1547] Make `CupertinoTextField` at least as tall as its first line of placeholder (#134198) Fixes https://github.com/flutter/flutter/issues/133241 and some CupertinoTextField cleanup. --- .../lib/src/cupertino/search_field.dart | 2 +- .../flutter/lib/src/cupertino/text_field.dart | 173 ++++++++++-------- .../src/cupertino/text_form_field_row.dart | 2 +- packages/flutter/lib/src/rendering/stack.dart | 14 +- .../test/cupertino/text_field_test.dart | 66 ++++++- 5 files changed, 161 insertions(+), 96 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/search_field.dart b/packages/flutter/lib/src/cupertino/search_field.dart index 0748feb13fff3..a5ffc2c5c4990 100644 --- a/packages/flutter/lib/src/cupertino/search_field.dart +++ b/packages/flutter/lib/src/cupertino/search_field.dart @@ -444,7 +444,7 @@ class _CupertinoSearchTextFieldState extends State<CupertinoSearchTextField> suffix: suffix, keyboardType: widget.keyboardType, onTap: widget.onTap, - enabled: widget.enabled, + enabled: widget.enabled ?? true, suffixMode: widget.suffixMode, placeholder: placeholder, placeholderStyle: placeholderStyle, diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index 4c4b940fcef6d..bda1ad6aecc55 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -261,7 +261,7 @@ class CupertinoTextField extends StatefulWidget { this.onSubmitted, this.onTapOutside, this.inputFormatters, - this.enabled, + this.enabled = true, this.cursorWidth = 2.0, this.cursorHeight, this.cursorRadius = const Radius.circular(2.0), @@ -393,7 +393,7 @@ class CupertinoTextField extends StatefulWidget { this.onSubmitted, this.onTapOutside, this.inputFormatters, - this.enabled, + this.enabled = true, this.cursorWidth = 2.0, this.cursorHeight, this.cursorRadius = const Radius.circular(2.0), @@ -653,7 +653,9 @@ class CupertinoTextField extends StatefulWidget { /// Text fields in disabled states have a light grey background and don't /// respond to touch events including the [prefix], [suffix] and the clear /// button. - final bool? enabled; + /// + /// Defaults to true. + final bool enabled; /// {@macro flutter.widgets.editableText.cursorWidth} final double cursorWidth; @@ -946,7 +948,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio if (widget.controller == null) { _createLocalController(); } - _effectiveFocusNode.canRequestFocus = widget.enabled ?? true; + _effectiveFocusNode.canRequestFocus = widget.enabled; _effectiveFocusNode.addListener(_handleFocusChanged); } @@ -965,7 +967,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio (oldWidget.focusNode ?? _focusNode)?.removeListener(_handleFocusChanged); (widget.focusNode ?? _focusNode)?.addListener(_handleFocusChanged); } - _effectiveFocusNode.canRequestFocus = widget.enabled ?? true; + _effectiveFocusNode.canRequestFocus = widget.enabled; } @override @@ -1079,41 +1081,16 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio @override bool get wantKeepAlive => _controller?.value.text.isNotEmpty ?? false; - bool _shouldShowAttachment({ + static bool _shouldShowAttachment({ required OverlayVisibilityMode attachment, required bool hasText, }) { - switch (attachment) { - case OverlayVisibilityMode.never: - return false; - case OverlayVisibilityMode.always: - return true; - case OverlayVisibilityMode.editing: - return hasText; - case OverlayVisibilityMode.notEditing: - return !hasText; - } - } - - bool _showPrefixWidget(TextEditingValue text) { - return widget.prefix != null && _shouldShowAttachment( - attachment: widget.prefixMode, - hasText: text.text.isNotEmpty, - ); - } - - bool _showSuffixWidget(TextEditingValue text) { - return widget.suffix != null && _shouldShowAttachment( - attachment: widget.suffixMode, - hasText: text.text.isNotEmpty, - ); - } - - bool _showClearButton(TextEditingValue text) { - return _shouldShowAttachment( - attachment: widget.clearButtonMode, - hasText: text.text.isNotEmpty, - ); + return switch (attachment) { + OverlayVisibilityMode.never => false, + OverlayVisibilityMode.always => true, + OverlayVisibilityMode.editing => hasText, + OverlayVisibilityMode.notEditing => !hasText, + }; } // True if any surrounding decoration widgets will be shown. @@ -1134,6 +1111,32 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio return _hasDecoration ? TextAlignVertical.center : TextAlignVertical.top; } + void _onClearButtonTapped() { + final bool hadText = _effectiveController.text.isNotEmpty; + _effectiveController.clear(); + if (hadText) { + // Tapping the clear button is also considered a "user initiated" change + // (instead of a programmatical one), so call `onChanged` if the text + // changed as a result. + widget.onChanged?.call(_effectiveController.text); + } + } + + Widget _buildClearButton() { + return GestureDetector( + key: _clearGlobalKey, + onTap: widget.enabled ? _onClearButtonTapped : null, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 6.0), + child: Icon( + CupertinoIcons.clear_thick_circled, + size: 18.0, + color: CupertinoDynamicColor.resolve(_kClearButtonColor, context), + ), + ), + ); + } + Widget _addTextDependentAttachments(Widget editableText, TextStyle textStyle, TextStyle placeholderStyle) { // If there are no surrounding widgets, just return the core editable text // part. @@ -1145,59 +1148,69 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio return ValueListenableBuilder<TextEditingValue>( valueListenable: _effectiveController, child: editableText, - builder: (BuildContext context, TextEditingValue? text, Widget? child) { + builder: (BuildContext context, TextEditingValue text, Widget? child) { + final bool hasText = text.text.isNotEmpty; + final String? placeholderText = widget.placeholder; + final Widget? placeholder = placeholderText == null + ? null + // Make the placeholder invisible when hasText is true. + : Visibility( + maintainAnimation: true, + maintainSize: true, + maintainState: true, + visible: !hasText, + child: SizedBox( + width: double.infinity, + child: Padding( + padding: widget.padding, + child: Text( + placeholderText, + // This is to make sure the text field is always tall enough + // to accommodate the first line of the placeholder, so the + // text does not shrink vertically as you type (however in + // rare circumstances, the height may still change when + // there's no placeholder text). + maxLines: hasText ? 1 : widget.maxLines, + overflow: placeholderStyle.overflow, + style: placeholderStyle, + textAlign: widget.textAlign, + ), + ), + ), + ); + + final Widget? prefixWidget = _shouldShowAttachment(attachment: widget.prefixMode, hasText: hasText) ? widget.prefix : null; + + // Show user specified suffix if applicable and fall back to clear button. + final bool showUserSuffix = _shouldShowAttachment(attachment: widget.suffixMode, hasText: hasText); + final bool showClearButton = _shouldShowAttachment(attachment: widget.clearButtonMode, hasText: hasText); + final Widget? suffixWidget = switch ((showUserSuffix, showClearButton)) { + (false, false) => null, + (true, false) => widget.suffix, + (true, true) => widget.suffix ?? _buildClearButton(), + (false, true) => _buildClearButton(), + }; return Row(children: <Widget>[ // Insert a prefix at the front if the prefix visibility mode matches // the current text state. - if (_showPrefixWidget(text!)) widget.prefix!, + if (prefixWidget != null) prefixWidget, // In the middle part, stack the placeholder on top of the main EditableText // if needed. Expanded( child: Stack( + // Ideally this should be baseline aligned. However that comes at + // the cost of the ability to compute the intrinsic dimensions of + // this widget. + // See also https://github.com/flutter/flutter/issues/13715. + alignment: AlignmentDirectional.center, + textDirection: widget.textDirection, children: <Widget>[ - if (widget.placeholder != null && text.text.isEmpty) - SizedBox( - width: double.infinity, - child: Padding( - padding: widget.padding, - child: Text( - widget.placeholder!, - maxLines: widget.maxLines, - overflow: placeholderStyle.overflow ?? TextOverflow.ellipsis, - style: placeholderStyle, - textAlign: widget.textAlign, - ), - ), - ), - child!, + if (placeholder != null) placeholder, + editableText, ], ), ), - // First add the explicit suffix if the suffix visibility mode matches. - if (_showSuffixWidget(text)) - widget.suffix! - // Otherwise, try to show a clear button if its visibility mode matches. - else if (_showClearButton(text)) - GestureDetector( - key: _clearGlobalKey, - onTap: widget.enabled ?? true ? () { - // Special handle onChanged for ClearButton - // Also call onChanged when the clear button is tapped. - final bool textChanged = _effectiveController.text.isNotEmpty; - _effectiveController.clear(); - if (widget.onChanged != null && textChanged) { - widget.onChanged!(_effectiveController.text); - } - } : null, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 6.0), - child: Icon( - CupertinoIcons.clear_thick_circled, - size: 18.0, - color: CupertinoDynamicColor.resolve(_kClearButtonColor, context), - ), - ), - ), + if (suffixWidget != null) suffixWidget ]); }, ); @@ -1251,7 +1264,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio }; } - final bool enabled = widget.enabled ?? true; + final bool enabled = widget.enabled; final Offset cursorOffset = Offset(_iOSHorizontalCursorOffsetPixels / MediaQuery.devicePixelRatioOf(context), 0); final List<TextInputFormatter> formatters = <TextInputFormatter>[ ...?widget.inputFormatters, diff --git a/packages/flutter/lib/src/cupertino/text_form_field_row.dart b/packages/flutter/lib/src/cupertino/text_form_field_row.dart index 268d8c06125f2..ed20b583a5fc0 100644 --- a/packages/flutter/lib/src/cupertino/text_form_field_row.dart +++ b/packages/flutter/lib/src/cupertino/text_form_field_row.dart @@ -219,7 +219,7 @@ class CupertinoTextFormFieldRow extends FormField<String> { onEditingComplete: onEditingComplete, onSubmitted: onFieldSubmitted, inputFormatters: inputFormatters, - enabled: enabled, + enabled: enabled ?? true, cursorWidth: cursorWidth, cursorHeight: cursorHeight, cursorColor: cursorColor, diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart index fb8aa3f97ee09..83ebbaaf447e1 100644 --- a/packages/flutter/lib/src/rendering/stack.dart +++ b/packages/flutter/lib/src/rendering/stack.dart @@ -569,15 +569,11 @@ class RenderStack extends RenderBox double width = constraints.minWidth; double height = constraints.minHeight; - final BoxConstraints nonPositionedConstraints; - switch (fit) { - case StackFit.loose: - nonPositionedConstraints = constraints.loosen(); - case StackFit.expand: - nonPositionedConstraints = BoxConstraints.tight(constraints.biggest); - case StackFit.passthrough: - nonPositionedConstraints = constraints; - } + final BoxConstraints nonPositionedConstraints = switch (fit) { + StackFit.loose => constraints.loosen(), + StackFit.expand => BoxConstraints.tight(constraints.biggest), + StackFit.passthrough => constraints, + }; RenderBox? child = firstChild; while (child != null) { diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index 46c6262b1f669..bd5721aba3c64 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -1071,7 +1071,8 @@ void main() { await tester.enterText(find.byType(CupertinoTextField), 'input'); await tester.pump(); - expect(find.text('placeholder'), findsNothing); + final Element element = tester.element(find.text('placeholder')); + expect(Visibility.of(element), false); }, ); @@ -1964,7 +1965,9 @@ void main() { expect(find.text('field 1'), findsOneWidget); expect(find.text("j'aime la poutine"), findsOneWidget); - expect(find.text('field 2'), findsNothing); + + final Element placeholder2Element = tester.element(find.text('field 2')); + expect(Visibility.of(placeholder2Element), false); }, skip: isContextMenuProvidedByPlatform); // [intended] only applies to platforms where we supply the context menu. testWidgets( @@ -8096,9 +8099,7 @@ void main() { await tester.pumpWidget( const CupertinoApp( home: Center( - child: CupertinoTextField( - enabled: true, - ), + child: CupertinoTextField(), ), ), ); @@ -9867,4 +9868,59 @@ void main() { skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu. variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS }), ); + + testWidgets('Does not shrink in height when enters text when there is large single-line placeholder', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/133241. + final TextEditingController controller = TextEditingController(); + await tester.pumpWidget( + CupertinoApp( + home: Align( + alignment: Alignment.topCenter, + child: CupertinoTextField( + placeholderStyle: const TextStyle(fontSize: 100), + placeholder: 'p', + controller: controller, + ), + ), + ), + ); + + final Rect rectWithPlaceholder = tester.getRect(find.byType(CupertinoTextField)); + controller.value = const TextEditingValue(text: 'input'); + await tester.pump(); + + final Rect rectWithText = tester.getRect(find.byType(CupertinoTextField)); + expect(rectWithPlaceholder, rectWithText); + }); + + testWidgets('Does not match the height of a multiline placeholder', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(); + await tester.pumpWidget( + CupertinoApp( + home: Align( + alignment: Alignment.topCenter, + child: CupertinoTextField( + placeholderStyle: const TextStyle(fontSize: 100), + placeholder: 'p' * 50, + maxLines: null, + controller: controller, + ), + ), + ), + ); + + final Rect rectWithPlaceholder = tester.getRect(find.byType(CupertinoTextField)); + controller.value = const TextEditingValue(text: 'input'); + await tester.pump(); + + final Rect rectWithText = tester.getRect(find.byType(CupertinoTextField)); + // The text field is still top aligned. + expect(rectWithPlaceholder.top, rectWithText.top); + // But after entering text the text field should shrink since the + // placeholder text is huge and multiline. + expect(rectWithPlaceholder.height, greaterThan(rectWithText.height)); + // But still should be taller than or the same height of the first line of + // placeholder. + expect(rectWithText.height, greaterThan(100)); + }); } From da676f79aa372f4efcc63fa71bbce062491c2acf Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Fri, 8 Sep 2023 10:08:21 -0700 Subject: [PATCH 1155/1547] Marks Linux_android very_long_picture_scrolling_perf__e2e_summary to be unflaky (#134116) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_android very_long_picture_scrolling_perf__e2e_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux_android%20very_long_picture_scrolling_perf__e2e_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index fa11c98b6c986..ba31dfac1451b 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2124,7 +2124,6 @@ targets: - name: Linux_android very_long_picture_scrolling_perf__e2e_summary recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 120 properties: From d73e1b69f705f6cc2353dfe52fc9dc6aa3375f2a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 13:43:20 -0400 Subject: [PATCH 1156/1547] Roll Flutter Engine from 6d6b44886175 to 47a79306eed3 (2 revisions) (#134310) https://github.com/flutter/engine/compare/6d6b44886175...47a79306eed3 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from c5e67d222f46 to 5b1e40fc0548 (5 revisions) (flutter/engine#45578) 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from 65ec697f4183 to 83030fed595b (1 revision) (flutter/engine#45577) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4a8def898d978..725b053ffca1f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6d6b44886175f4982dbe7aa42ffc39b654442b71 +47a79306eed39beff2b9702ca98d2fdabdd4f15e From 2f66f25f34f32a0728452f80826dd91a34d45a35 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 15:08:16 -0400 Subject: [PATCH 1157/1547] Roll Flutter Engine from 47a79306eed3 to b2cb1d271a88 (5 revisions) (#134313) https://github.com/flutter/engine/compare/47a79306eed3...b2cb1d271a88 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 5181fcf6184e to 948959b6b53e (4 revisions) (flutter/engine#45583) 2023-09-08 gspencergoog@users.noreply.github.com Remove usage of the Jazzy document formatter for Objective C, in favor of Doxygen. (flutter/engine#45561) 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from 83030fed595b to a507f31285b8 (1 revision) (flutter/engine#45582) 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 5b1e40fc0548 to 5181fcf6184e (2 revisions) (flutter/engine#45580) 2023-09-08 matanlurey@users.noreply.github.com Document and provide small cleanups to `CommandPoolVk`. (flutter/engine#45558) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 725b053ffca1f..5fefaa863c7da 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -47a79306eed39beff2b9702ca98d2fdabdd4f15e +b2cb1d271a881d3b8ba583522bcc257ac64352d6 From f851e7faf0849f24af8ad91f3004e76c7b0ddfb7 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 8 Sep 2023 12:22:44 -0700 Subject: [PATCH 1158/1547] Add ios analyzer command for universal links (#134155) ios version of https://github.com/flutter/flutter/pull/131009/files --- .../lib/src/commands/analyze.dart | 93 +++++++++- .../lib/src/commands/ios_analyze.dart | 69 ++++++++ .../flutter_tools/lib/src/xcode_project.dart | 4 +- .../hermetic/ios_analyze_test.dart | 162 ++++++++++++++++++ .../test/general.shard/project_test.dart | 6 +- 5 files changed, 327 insertions(+), 7 deletions(-) create mode 100644 packages/flutter_tools/lib/src/commands/ios_analyze.dart create mode 100644 packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart index dff347f7cbacf..9a558fe8d4a41 100644 --- a/packages/flutter_tools/lib/src/commands/analyze.dart +++ b/packages/flutter_tools/lib/src/commands/analyze.dart @@ -11,12 +11,14 @@ import '../base/file_system.dart'; import '../base/logger.dart'; import '../base/platform.dart'; import '../base/terminal.dart'; +import '../project.dart'; import '../project_validator.dart'; import '../runner/flutter_command.dart'; import 'analyze_base.dart'; import 'analyze_continuously.dart'; import 'analyze_once.dart'; import 'android_analyze.dart'; +import 'ios_analyze.dart'; import 'validate_project.dart'; class AnalyzeCommand extends FlutterCommand { @@ -107,6 +109,12 @@ class AnalyzeCommand extends FlutterCommand { hide: !verboseHelp, ); + argParser.addFlag('ios', + negatable: false, + help: 'Analyze iOS Xcode sub-project. Used by internal tools only.', + hide: !verboseHelp, + ); + if (verboseHelp) { argParser.addSeparator('Usage: flutter analyze --android [arguments]'); } @@ -127,8 +135,42 @@ class AnalyzeCommand extends FlutterCommand { argParser.addOption('build-variant', help: 'Sets the Android build variant to be analyzed.', - valueHelp: 'use "flutter analyze --android --list-build-variants" to get ' - 'all available build variants', + valueHelp: 'build variant', + hide: !verboseHelp, + ); + + if (verboseHelp) { + argParser.addSeparator('Usage: flutter analyze --ios [arguments]'); + } + + argParser.addFlag('list-build-options', + help: 'Print out a list of available build options for the ' + 'iOS Xcode sub-project.', + hide: !verboseHelp, + ); + + argParser.addFlag('output-universal-link-settings', + negatable: false, + help: 'Output a JSON with iOS Xcode universal link settings into a file. ' + 'The "--configuration", "--scheme", and "--target" must also be set.', + hide: !verboseHelp, + ); + + argParser.addOption('configuration', + help: 'Sets the iOS build configuration to be analyzed.', + valueHelp: 'configuration', + hide: !verboseHelp, + ); + + argParser.addOption('scheme', + help: 'Sets the iOS build scheme to be analyzed.', + valueHelp: 'scheme', + hide: !verboseHelp, + ); + + argParser.addOption('target', + help: 'Sets the iOS build target to be analyzed.', + valueHelp: 'target', hide: !verboseHelp, ); } @@ -218,6 +260,53 @@ class AnalyzeCommand extends FlutterCommand { buildVariant: buildVariant, logger: _logger, ).analyze(); + } else if (boolArg('ios')) { + final IOSAnalyzeOption option; + final String? configuration; + final String? target; + final String? scheme; + if (argResults!['list-build-options'] as bool && argResults!['output-universal-link-settings'] as bool) { + throwToolExit('Only one of "--list-build-options" or "--output-universal-link-settings" can be provided'); + } + if (argResults!['list-build-options'] as bool) { + option = IOSAnalyzeOption.listBuildOptions; + configuration = null; + target = null; + scheme = null; + } else if (argResults!['output-universal-link-settings'] as bool) { + option = IOSAnalyzeOption.outputUniversalLinkSettings; + configuration = argResults!['configuration'] as String?; + if (configuration == null) { + throwToolExit('"--configuration" must be provided'); + } + target = argResults!['target'] as String?; + if (target == null) { + throwToolExit('"--target" must be provided'); + } + scheme = argResults!['scheme'] as String?; + if (scheme == null) { + throwToolExit('"--scheme" must be provided'); + } + } else { + throwToolExit('No argument is provided to analyze. Use -h to see available commands.'); + } + final Set<String> items = findDirectories(argResults!, _fileSystem); + final String directoryPath; + if (items.isEmpty) { // user did not specify any path + directoryPath = _fileSystem.currentDirectory.path; + } else if (items.length > 1) { // if the user sends more than one path + throwToolExit('The iOS analyze can process only one directory path'); + } else { + directoryPath = items.first; + } + await IOSAnalyze( + project: FlutterProject.fromDirectory(_fileSystem.directory(directoryPath)), + option: option, + configuration: configuration, + target: target, + scheme: scheme, + logger: _logger, + ).analyze(); } else if (boolArg('suggestions')) { final String directoryPath; if (boolArg('watch')) { diff --git a/packages/flutter_tools/lib/src/commands/ios_analyze.dart b/packages/flutter_tools/lib/src/commands/ios_analyze.dart new file mode 100644 index 0000000000000..ae8f0bab76729 --- /dev/null +++ b/packages/flutter_tools/lib/src/commands/ios_analyze.dart @@ -0,0 +1,69 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import '../base/logger.dart'; +import '../convert.dart'; +import '../ios/xcodeproj.dart'; +import '../project.dart'; + +/// The type of analysis to perform. +enum IOSAnalyzeOption { + /// Prints out available build variants of the iOS Xcode sub-project. + /// + /// An example output: + /// + /// {"configurations":["Debug","Release","Profile"],"schemes":["Runner"],"targets":["Runner","RunnerTests"]} + listBuildOptions, + + /// Outputs universal link settings of the iOS Xcode sub-project into a file. + /// + /// The file path will be printed after the command is run successfully. + outputUniversalLinkSettings, +} + +/// Analyze the iOS Xcode sub-project of a Flutter project. +/// +/// The [userPath] must be point to a flutter project. +class IOSAnalyze { + IOSAnalyze({ + required this.project, + required this.option, + this.configuration, + this.scheme, + this.target, + required this.logger, + }) : assert(option == IOSAnalyzeOption.listBuildOptions || + (configuration != null && scheme != null && target != null)); + + final FlutterProject project; + final IOSAnalyzeOption option; + final String? configuration; + final String? scheme; + final String? target; + final Logger logger; + + Future<void> analyze() async { + switch (option) { + case IOSAnalyzeOption.listBuildOptions: + final XcodeProjectInfo? info = await project.ios.projectInfo(); + final Map<String, List<String>> result; + if (info == null) { + result = const <String, List<String>>{}; + } else { + result = <String, List<String>>{ + 'configurations': info.buildConfigurations, + 'schemes': info.schemes, + 'targets': info.targets, + }; + } + logger.printStatus(jsonEncode(result)); + case IOSAnalyzeOption.outputUniversalLinkSettings: + await project.ios.outputsUniversalLinkSettings(configuration: configuration!, scheme: scheme!, target: target!); + final String filePath = await project.ios.outputsUniversalLinkSettings(configuration: configuration!, scheme: scheme!, target: target!); + logger.printStatus('result saved in $filePath'); + } + } +} diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index c95ca87c4366e..ff17490a88200 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -215,11 +215,11 @@ class IosProject extends XcodeBasedProject { return parent.isModule || _editableDirectory.existsSync(); } - /// Output universal link related project settings of the iOS sub-project into + /// Outputs universal link related project settings of the iOS sub-project into /// a json file. /// /// The return future will resolve to string path to the output file. - Future<String> outputUniversalLinkSettings({ + Future<String> outputsUniversalLinkSettings({ required String configuration, required String scheme, required String target, diff --git a/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart new file mode 100644 index 0000000000000..5290d5d38ee04 --- /dev/null +++ b/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart @@ -0,0 +1,162 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; + +import 'package:args/command_runner.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/cache.dart'; +import 'package:flutter_tools/src/commands/analyze.dart'; +import 'package:flutter_tools/src/commands/ios_analyze.dart'; +import 'package:flutter_tools/src/ios/xcodeproj.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:flutter_tools/src/project_validator.dart'; +import 'package:test/fake.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/test_flutter_command_runner.dart'; + +void main() { + group('ios analyze command', () { + late BufferLogger logger; + late FileSystem fileSystem; + late Platform platform; + late FakeProcessManager processManager; + late Terminal terminal; + late AnalyzeCommand command; + late CommandRunner<void> runner; + + setUpAll(() { + Cache.disableLocking(); + }); + + setUp(() { + logger = BufferLogger.test(); + fileSystem = MemoryFileSystem.test(); + platform = FakePlatform(); + processManager = FakeProcessManager.empty(); + terminal = Terminal.test(); + command = AnalyzeCommand( + artifacts: Artifacts.test(), + fileSystem: fileSystem, + logger: logger, + platform: platform, + processManager: processManager, + terminal: terminal, + allProjectValidators: <ProjectValidator>[], + suppressAnalytics: true, + ); + runner = createTestCommandRunner(command); + + // Setup repo roots + const String homePath = '/home/user/flutter'; + Cache.flutterRoot = homePath; + for (final String dir in <String>['dev', 'examples', 'packages']) { + fileSystem.directory(homePath).childDirectory(dir).createSync(recursive: true); + } + }); + + testWithoutContext('can output json file', () async { + final MockIosProject ios = MockIosProject(); + final MockFlutterProject project = MockFlutterProject(ios); + const String expectedConfig = 'someConfig'; + const String expectedScheme = 'someScheme'; + const String expectedTarget = 'someConfig'; + const String expectedOutputFile = '/someFile'; + ios.outputFileLocation = expectedOutputFile; + await IOSAnalyze( + project: project, + option: IOSAnalyzeOption.outputUniversalLinkSettings, + configuration: expectedConfig, + scheme: expectedScheme, + target: expectedTarget, + logger: logger, + ).analyze(); + expect(logger.statusText, contains(expectedOutputFile)); + expect(ios.outputConfiguration, expectedConfig); + expect(ios.outputScheme, expectedScheme); + expect(ios.outputTarget, expectedTarget); + }); + + testWithoutContext('can list build options', () async { + final MockIosProject ios = MockIosProject(); + final MockFlutterProject project = MockFlutterProject(ios); + const List<String> targets = <String>['target1', 'target2']; + const List<String> configs = <String>['config1', 'config2']; + const List<String> schemes = <String>['scheme1', 'scheme2']; + ios.expectedProjectInfo = XcodeProjectInfo(targets, configs, schemes, logger); + await IOSAnalyze( + project: project, + option: IOSAnalyzeOption.listBuildOptions, + logger: logger, + ).analyze(); + final Map<String, Object?> jsonOutput = jsonDecode(logger.statusText) as Map<String, Object?>; + expect(jsonOutput['targets'], unorderedEquals(targets)); + expect(jsonOutput['configurations'], unorderedEquals(configs)); + expect(jsonOutput['schemes'], unorderedEquals(schemes)); + }); + + testUsingContext('throws if provide multiple path', () async { + final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('someTemp'); + final Directory anotherTempDir = fileSystem.systemTempDirectory.createTempSync('another'); + await expectLater( + runner.run(<String>['analyze', '--ios', '--list-build-options', tempDir.path, anotherTempDir.path]), + throwsA( + isA<Exception>().having( + (Exception e) => e.toString(), + 'description', + contains('The iOS analyze can process only one directory path'), + ), + ), + ); + }); + + testUsingContext('throws if not enough parameters', () async { + final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('someTemp'); + await expectLater( + runner.run(<String>['analyze', '--ios', '--output-universal-link-settings', tempDir.path]), + throwsA( + isA<Exception>().having( + (Exception e) => e.toString(), + 'description', + contains('"--configuration" must be provided'), + ), + ), + ); + }); + }); +} + +class MockFlutterProject extends Fake implements FlutterProject { + MockFlutterProject(this.ios); + + @override + final IosProject ios; +} + +class MockIosProject extends Fake implements IosProject { + String? outputConfiguration; + String? outputScheme; + String? outputTarget; + late String outputFileLocation; + late XcodeProjectInfo expectedProjectInfo; + + @override + Future<String> outputsUniversalLinkSettings({required String configuration, required String scheme, required String target}) async { + outputConfiguration = configuration; + outputScheme = scheme; + outputTarget = target; + return outputFileLocation; + } + @override + Future<XcodeProjectInfo> projectInfo() async => expectedProjectInfo; + +} diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index 759ec7eae859f..ad30284a0b1c7 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -751,7 +751,7 @@ apply plugin: 'kotlin-android' 'applinks:example2.com', ], ); - final String outputFilePath = await project.ios.outputUniversalLinkSettings( + final String outputFilePath = await project.ios.outputsUniversalLinkSettings( target: 'Runner', scheme: 'Debug', configuration: 'config', @@ -800,7 +800,7 @@ apply plugin: 'kotlin-android' ], ); - final String outputFilePath = await project.ios.outputUniversalLinkSettings( + final String outputFilePath = await project.ios.outputsUniversalLinkSettings( target: 'Runner', scheme: 'Debug', configuration: 'config', @@ -836,7 +836,7 @@ apply plugin: 'kotlin-android' }; xcodeProjectInterpreter.xcodeProjectInfo = XcodeProjectInfo(<String>[], <String>[], <String>['Runner'], logger); testPlistUtils.setProperty(PlistParser.kCFBundleIdentifierKey, r'$(PRODUCT_BUNDLE_IDENTIFIER)'); - final String outputFilePath = await project.ios.outputUniversalLinkSettings( + final String outputFilePath = await project.ios.outputsUniversalLinkSettings( target: 'Runner', scheme: 'Debug', configuration: 'config', From 90c524dcdf49b78e8530776979f7480863c65759 Mon Sep 17 00:00:00 2001 From: Taha Tesser <tessertaha@gmail.com> Date: Fri, 8 Sep 2023 22:41:18 +0300 Subject: [PATCH 1159/1547] Update chip docs to clarify how to specify a shape with no border & explain default values for Material 3 (#134298) fixes [Update chip docs for Material 3 defaults.](https://github.com/flutter/flutter/issues/134296) Addresses a [comment](https://github.com/flutter/flutter/pull/133856#discussion_r1313513284) from @HansMuller as well --- packages/flutter/lib/src/material/chip.dart | 48 +++++++++++++++------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index b3bc897845a78..f158eb316db76 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -76,8 +76,9 @@ abstract interface class ChipAttributes { /// The style to be applied to the chip's label. /// - /// The default label style is [TextTheme.bodyLarge] from the overall - /// theme's [ThemeData.textTheme]. + /// If this is null and [ThemeData.useMaterial3] is true, then + /// [TextTheme.labelLarge] is used. Otherwise, [TextTheme.bodyLarge] + /// is used. // /// This only has an effect on widgets that respect the [DefaultTextStyle], /// such as [Text]. @@ -95,12 +96,17 @@ abstract interface class ChipAttributes { /// The color and weight of the chip's outline. /// /// Defaults to the border side in the ambient [ChipThemeData]. If the theme - /// border side resolves to null, the default is the border side of [shape]. + /// border side resolves to null and [ThemeData.useMaterial3] is true, then + /// [BorderSide] with a [ColorScheme.outline] color is used when the chip is + /// enabled, and [BorderSide] with a [ColorScheme.onSurface] color with an + /// opacity of 0.12 is used when the chip is disabled. Otherwise, it defaults + /// to null. /// /// This value is combined with [shape] to create a shape decorated with an - /// outline. If it is a [MaterialStateBorderSide], - /// [MaterialStateProperty.resolve] is used for the following - /// [MaterialState]s: + /// outline. To omit the outline entirely, pass [BorderSide.none] to [side]. + /// + /// If it is a [MaterialStateBorderSide], [MaterialStateProperty.resolve] is + /// used for the following [MaterialState]s: /// /// * [MaterialState.disabled]. /// * [MaterialState.selected]. @@ -112,12 +118,15 @@ abstract interface class ChipAttributes { /// The [OutlinedBorder] to draw around the chip. /// /// Defaults to the shape in the ambient [ChipThemeData]. If the theme - /// shape resolves to null, the default is [StadiumBorder]. + /// shape resolves to null and [ThemeData.useMaterial3] is true, then + /// [RoundedRectangleBorder] with a circular border radius of 8.0 is used. + /// Otherwise, [StadiumBorder] is used. /// /// This shape is combined with [side] to create a shape decorated with an - /// outline. If it is a [MaterialStateOutlinedBorder], - /// [MaterialStateProperty.resolve] is used for the following - /// [MaterialState]s: + /// outline. To omit the outline entirely, pass [BorderSide.none] to [side]. + /// + /// If it is a [MaterialStateOutlinedBorder], [MaterialStateProperty.resolve] + /// is used for the following [MaterialState]s: /// /// * [MaterialState.disabled]. /// * [MaterialState.selected]. @@ -139,6 +148,8 @@ abstract interface class ChipAttributes { /// The color that fills the chip, in all [MaterialState]s. /// + /// Defaults to null. + /// /// Resolves in the following states: /// * [MaterialState.selected]. /// * [MaterialState.disabled]. @@ -151,7 +162,9 @@ abstract interface class ChipAttributes { /// The padding between the contents of the chip and the outside [shape]. /// - /// Defaults to 4 logical pixels on all sides. + /// If this is null and [ThemeData.useMaterial3] is true, then + /// a padding of 8.0 logical pixels on all sides is used. Otherwise, + /// it defaults to a padding of 4.0 logical pixels on all sides. EdgeInsetsGeometry? get padding; /// Defines how compact the chip's layout will be. @@ -190,18 +203,25 @@ abstract interface class ChipAttributes { /// Color of the chip's shadow when the elevation is greater than 0. /// - /// The default is null. + /// If this is null and [ThemeData.useMaterial3] is true, then + /// [Colors.transparent] color is used. Otherwise, it defaults to null. Color? get shadowColor; /// Color of the chip's surface tint overlay when its elevation is /// greater than 0. /// - /// The default is null. + /// If this is null and [ThemeData.useMaterial3] is true, then + /// [ColorScheme.surfaceTint] color is used. Otherwise, it defaults + /// to null. Color? get surfaceTintColor; /// Theme used for all icons in the chip. /// - /// The default is null. + /// If this is null and [ThemeData.useMaterial3] is true, then [IconThemeData] + /// with a [ColorScheme.primary] color and a size of 18.0 is used when + /// the chip is enabled, and [IconThemeData] with a [ColorScheme.onSurface] + /// color and a size of 18.0 is used when the chip is disabled. Otherwise, + /// it defaults to null. IconThemeData? get iconTheme; } From fa9c301a844295d771d2a068e244cdc7396f4487 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 15:59:13 -0400 Subject: [PATCH 1160/1547] Roll Flutter Engine from b2cb1d271a88 to 2da727e23518 (1 revision) (#134314) https://github.com/flutter/engine/compare/b2cb1d271a88...2da727e23518 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 948959b6b53e to 244c9ba5d0d7 (2 revisions) (flutter/engine#45584) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5fefaa863c7da..4969036205e61 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b2cb1d271a881d3b8ba583522bcc257ac64352d6 +2da727e235182c4c58da054d991a3c57d9ef5712 From 97cdc0ec07d2b9bfbda4ce1fa461a691964737c9 Mon Sep 17 00:00:00 2001 From: Renzo Olivares <rmolivares@renzo-olivares.dev> Date: Fri, 8 Sep 2023 15:01:50 -0700 Subject: [PATCH 1161/1547] InputDecoration.error should activate error state (#134001) When passed an `error` widget, `InputDecoration` should activate its error state. Before this change the `errorBorder` would only activate if an `errorText` was provided. This change solves this issue by accounting for a provided `error` widget. --- .../lib/src/material/input_decorator.dart | 14 +-- .../flutter/lib/src/material/text_field.dart | 2 +- .../test/material/input_decorator_test.dart | 99 +++++++++++++++++++ .../test/material/text_field_test.dart | 36 +++++++ 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 1a99e298cb821..9e3a67ee4dff1 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -1971,6 +1971,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat TextAlign? get textAlign => widget.textAlign; bool get isFocused => widget.isFocused; + bool get _hasError => decoration.errorText != null || decoration.error != null; bool get isHovering => widget.isHovering && decoration.enabled; bool get isEmpty => widget.isEmpty; bool get _floatingLabelEnabled { @@ -2011,7 +2012,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ? Colors.transparent : themeData.disabledColor; } - if (decoration.errorText != null) { + if (_hasError) { return themeData.colorScheme.error; } if (isFocused) { @@ -2107,7 +2108,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat TextStyle _getFloatingLabelStyle(ThemeData themeData, InputDecorationTheme defaults) { TextStyle defaultTextStyle = MaterialStateProperty.resolveAs(defaults.floatingLabelStyle!, materialState); - if (decoration.errorText != null && decoration.errorStyle?.color != null) { + if (_hasError && decoration.errorStyle?.color != null) { defaultTextStyle = defaultTextStyle.copyWith(color: decoration.errorStyle?.color); } defaultTextStyle = defaultTextStyle.merge(decoration.floatingLabelStyle ?? decoration.labelStyle); @@ -2137,7 +2138,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat if (!decoration.enabled) MaterialState.disabled, if (isFocused) MaterialState.focused, if (isHovering) MaterialState.hovered, - if (decoration.errorText != null) MaterialState.error, + if (_hasError) MaterialState.error, }; } @@ -2205,14 +2206,13 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat ), ); - final bool isError = decoration.errorText != null; InputBorder? border; if (!decoration.enabled) { - border = isError ? decoration.errorBorder : decoration.disabledBorder; + border = _hasError ? decoration.errorBorder : decoration.disabledBorder; } else if (isFocused) { - border = isError ? decoration.focusedErrorBorder : decoration.focusedBorder; + border = _hasError ? decoration.focusedErrorBorder : decoration.focusedBorder; } else { - border = isError ? decoration.errorBorder : decoration.enabledBorder; + border = _hasError ? decoration.errorBorder : decoration.enabledBorder; } border ??= _getDefaultBorder(themeData, defaults); diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 3e0cfe9f90ca4..9679f0c47d3d3 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -945,7 +945,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements bool get _hasIntrinsicError => widget.maxLength != null && widget.maxLength! > 0 && _effectiveController.value.text.characters.length > widget.maxLength!; - bool get _hasError => widget.decoration?.errorText != null || _hasIntrinsicError; + bool get _hasError => widget.decoration?.errorText != null || widget.decoration?.error != null || _hasIntrinsicError; Color get _errorColor => widget.decoration?.errorStyle?.color ?? Theme.of(context).colorScheme.error; diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index 27e57c2707403..dbcca1b8197b9 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -1668,6 +1668,105 @@ void runAllTests({ required bool useMaterial3 }) { expect(find.text('errorText'), findsOneWidget); }); + testWidgets('InputDecoration shows error border for errorText and error widget', (WidgetTester tester) async { + const InputBorder errorBorder = OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 1.5), + ); + const InputBorder focusedErrorBorder = OutlineInputBorder( + borderSide: BorderSide(color: Colors.teal, width: 5.0), + ); + + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isFocused: true, + decoration: const InputDecoration( + errorText: 'error', + // enabled: true (default) + errorBorder: errorBorder, + focusedErrorBorder: focusedErrorBorder, + ), + ), + ); + await tester.pumpAndSettle(); // Border changes are animated. + expect(getBorder(tester), focusedErrorBorder); + + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + // isFocused: false (default) + decoration: const InputDecoration( + errorText: 'error', + // enabled: true (default) + errorBorder: errorBorder, + focusedErrorBorder: focusedErrorBorder, + ), + ), + ); + await tester.pumpAndSettle(); // Border changes are animated. + expect(getBorder(tester), errorBorder); + + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + // isFocused: false (default) + decoration: const InputDecoration( + errorText: 'error', + enabled: false, + errorBorder: errorBorder, + focusedErrorBorder: focusedErrorBorder, + ), + ), + ); + await tester.pumpAndSettle(); // Border changes are animated. + expect(getBorder(tester), errorBorder); + + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isFocused: true, + decoration: const InputDecoration( + error: Text('error'), + // enabled: true (default) + errorBorder: errorBorder, + focusedErrorBorder: focusedErrorBorder, + ), + ), + ); + await tester.pumpAndSettle(); // Border changes are animated. + expect(getBorder(tester), focusedErrorBorder); + + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + // isFocused: false (default) + decoration: const InputDecoration( + error: Text('error'), + // enabled: true (default) + errorBorder: errorBorder, + focusedErrorBorder: focusedErrorBorder, + ), + ), + ); + await tester.pumpAndSettle(); // Border changes are animated. + expect(getBorder(tester), errorBorder); + + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + // isFocused: false (default) + decoration: const InputDecoration( + error: Text('error'), + enabled: false, + errorBorder: errorBorder, + focusedErrorBorder: focusedErrorBorder, + ), + ), + ); + await tester.pumpAndSettle(); // Border changes are animated. + expect(getBorder(tester), errorBorder); + }); + testWidgetsWithLeakTracking('InputDecorator shows error widget', (WidgetTester tester) async { await tester.pumpWidget( buildInputDecorator( diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index fff87d55eb7a2..6e4d47857126a 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -787,6 +787,42 @@ void main() { expect(state.widget.cursorColor, cursorColor); }); + testWidgets('Use error cursor color when an InputDecoration with an errorText or error widget is provided', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: TextField( + autofocus: true, + decoration: InputDecoration( + error: Text('error'), + errorStyle: TextStyle(color: Colors.teal), + ), + ), + ), + ), + ); + await tester.pump(); + EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); + expect(state.widget.cursorColor, Colors.teal); + + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: TextField( + autofocus: true, + decoration: InputDecoration( + errorText: 'error', + errorStyle: TextStyle(color: Colors.teal), + ), + ), + ), + ), + ); + await tester.pump(); + state = tester.state<EditableTextState>(find.byType(EditableText)); + expect(state.widget.cursorColor, Colors.teal); + }); + testWidgetsWithLeakTracking('sets cursorOpacityAnimates on EditableText correctly', (WidgetTester tester) async { // True From 621ad9872c12f6e488a5e4ac4555f800e0a6034d Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 8 Sep 2023 15:01:52 -0700 Subject: [PATCH 1162/1547] Remove TextPainter migration flag from the framework (#134274) The migration flag in `ParagraphBuilder` will be removed next. --- .../lib/src/painting/text_painter.dart | 23 ++++--------------- .../flutter/lib/src/rendering/binding.dart | 7 +----- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 6457e7cd37f46..0d1b24c7594b3 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -279,12 +279,6 @@ class _TextLayout { // object when it's no logner needed. ui.Paragraph _paragraph; - // TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/31707 - // remove this hack as well as the flooring in `layout`. - @pragma('vm:prefer-inline') - // ignore: deprecated_member_use - static double _applyFloatingPointHack(double layoutValue) => ui.ParagraphBuilder.shouldDisableRoundingHack ? layoutValue : layoutValue.ceilToDouble(); - /// Whether this layout has been invalidated and disposed. /// /// Only for use when asserts are enabled. @@ -294,23 +288,23 @@ class _TextLayout { /// /// If a line ends with trailing spaces, the trailing spaces may extend /// outside of the horizontal paint bounds defined by [width]. - double get width => _applyFloatingPointHack(_paragraph.width); + double get width => _paragraph.width; /// The vertical space required to paint this text. - double get height => _applyFloatingPointHack(_paragraph.height); + double get height => _paragraph.height; /// The width at which decreasing the width of the text would prevent it from /// painting itself completely within its bounds. - double get minIntrinsicLineExtent => _applyFloatingPointHack(_paragraph.minIntrinsicWidth); + double get minIntrinsicLineExtent => _paragraph.minIntrinsicWidth; /// The width at which increasing the width of the text no longer decreases the height. /// /// Includes trailing spaces if any. - double get maxIntrinsicLineExtent => _applyFloatingPointHack(_paragraph.maxIntrinsicWidth); + double get maxIntrinsicLineExtent => _paragraph.maxIntrinsicWidth; /// The distance from the left edge of the leftmost glyph to the right edge of /// the rightmost glyph in the paragraph. - double get longestLine => _applyFloatingPointHack(_paragraph.longestLine); + double get longestLine => _paragraph.longestLine; /// Returns the distance from the top of the text to the first baseline of the /// given type. @@ -359,13 +353,6 @@ class _TextPainterLayoutCacheWithOffset { ui.Paragraph get paragraph => layout._paragraph; static double _contentWidthFor(double minWidth, double maxWidth, TextWidthBasis widthBasis, _TextLayout layout) { - // TODO(LongCatIsLooong): remove the rounding when _applyFloatingPointHack - // is removed. - // ignore: deprecated_member_use - if (!ui.ParagraphBuilder.shouldDisableRoundingHack) { - minWidth = minWidth.floorToDouble(); - maxWidth = maxWidth.floorToDouble(); - } return switch (widthBasis) { TextWidthBasis.longestLine => clampDouble(layout.longestLine, minWidth, maxWidth), TextWidthBasis.parent => clampDouble(layout.maxIntrinsicLineExtent, minWidth, maxWidth), diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index bb9bd4fe77610..5d1552ec3cb54 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:ui' as ui show ParagraphBuilder, SemanticsUpdate; +import 'dart:ui' as ui show SemanticsUpdate; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -49,11 +49,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture addPostFrameCallback(_handleWebFirstFrame); } rootPipelineOwner.attach(_manifold); - // TODO(LongCatIsLooong): clean up after - // https://github.com/flutter/flutter/issues/31707 is fully migrated. - if (!const bool.fromEnvironment('SKPARAGRAPH_REMOVE_ROUNDING_HACK', defaultValue: true)) { - ui.ParagraphBuilder.setDisableRoundingHack(false); - } } /// The current [RendererBinding], if one has been created. From 834f5dc2964788ce976d9c4453572129bd8afbf1 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Fri, 8 Sep 2023 15:05:43 -0700 Subject: [PATCH 1163/1547] RestorationManager should dispatch creation in constructor. (#133911) --- packages/flutter/lib/src/services/restoration.dart | 3 +++ packages/flutter/test/services/restoration_test.dart | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index 0e638d84b4771..d3046a0e252cd 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -154,6 +154,9 @@ class RestorationManager extends ChangeNotifier { /// Construct the restoration manager and set up the communications channels /// with the engine to get restoration messages (by calling [initChannels]). RestorationManager() { + if (kFlutterMemoryAllocationsEnabled) { + maybeDispatchObjectCreation(); + } initChannels(); } diff --git a/packages/flutter/test/services/restoration_test.dart b/packages/flutter/test/services/restoration_test.dart index 8bfc04d121abd..7e872c5e215d0 100644 --- a/packages/flutter/test/services/restoration_test.dart +++ b/packages/flutter/test/services/restoration_test.dart @@ -8,10 +8,15 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'restoration.dart'; void main() { + testWidgetsWithLeakTracking('$RestorationManager dispatches memory events', (WidgetTester tester) async { + expect(() => RestorationManager().dispose(), dispatchesMemoryEvents(RestorationManager)); + }); + group('RestorationManager', () { testWidgets('root bucket retrieval', (WidgetTester tester) async { final List<MethodCall> callsToEngine = <MethodCall>[]; From 5d5da38810ca2979a4cf9e84c22d6f7410ee6b98 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Sat, 9 Sep 2023 00:06:26 +0200 Subject: [PATCH 1164/1547] Fix memory leak in _DraggableScrollableSheetState (#134212) --- .../widgets/draggable_scrollable_sheet.dart | 6 +- .../flutter/test/material/about_test.dart | 7 +- .../draggable_scrollable_sheet_test.dart | 111 +++++++++++------- 3 files changed, 72 insertions(+), 52 deletions(-) diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 9c229776964e2..0cb003af71a02 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -718,7 +718,11 @@ class _DraggableScrollableSheetState extends State<DraggableScrollableSheet> { @override void dispose() { - widget.controller?._detach(disposeExtent: true); + if (widget.controller == null) { + _extent.dispose(); + } else { + widget.controller!._detach(disposeExtent: true); + } _scrollController.dispose(); super.dispose(); } diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 911757e194424..044a58970419d 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -1590,12 +1590,7 @@ void main() { expect(titleOffset, const Offset(292.0, 136.0)); expect(titleOffset.dx, lessThan(wideSize.width - 320)); // Default master view width is 320.0. expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/133705 - notDisposedAllowList: <String, int?> {'ValueNotifier<double>':5}, - )); + }); testWidgets('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; diff --git a/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart b/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart index db3fbb8d2d62a..c9da896314c61 100644 --- a/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart +++ b/packages/flutter/test/widgets/draggable_scrollable_sheet_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { Widget boilerplateWidget(VoidCallback? onButtonPressed, { @@ -71,7 +72,7 @@ void main() { ); } - testWidgets('Do not crash when replacing scroll position during the drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when replacing scroll position during the drag', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/89681 bool showScrollbars = false; await tester.pumpWidget( @@ -119,7 +120,7 @@ void main() { // Go without throw. }); - testWidgets('Scrolls correct amount when maxChildSize < 1.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolls correct amount when maxChildSize < 1.0', (WidgetTester tester) async { const Key key = ValueKey<String>('container'); await tester.pumpWidget(boilerplateWidget( null, @@ -135,7 +136,7 @@ void main() { expect(tester.getRect(find.byKey(key)), const Rect.fromLTRB(0.0, 325.0, 800.0, 600.0)); }); - testWidgets('Scrolls correct amount when maxChildSize == 1.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolls correct amount when maxChildSize == 1.0', (WidgetTester tester) async { const Key key = ValueKey<String>('container'); await tester.pumpWidget(boilerplateWidget( null, @@ -172,7 +173,7 @@ void main() { }); group('Scroll Physics', () { - testWidgets('Can be dragged up without covering its container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be dragged up without covering its container', (WidgetTester tester) async { int taps = 0; await tester.pumpWidget(boilerplateWidget(() => taps++)); @@ -193,7 +194,7 @@ void main() { expect(find.text('Item 31'), findsOneWidget); }, variant: TargetPlatformVariant.all()); - testWidgets('Can be dragged down when not full height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be dragged down when not full height', (WidgetTester tester) async { await tester.pumpWidget(boilerplateWidget(null)); expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 21'), findsOneWidget); @@ -206,7 +207,7 @@ void main() { expect(find.text('Item 36'), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Can be dragged down when list is shorter than full height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be dragged down when list is shorter than full height', (WidgetTester tester) async { await tester.pumpWidget(boilerplateWidget(null, itemCount: 30, initialChildSize: .25)); expect(find.text('Item 1').hitTestable(), findsOneWidget); @@ -223,7 +224,7 @@ void main() { expect(find.text('Item 29').hitTestable(), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Can be dragged up and cover its container and scroll in single motion, and then dragged back down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be dragged up and cover its container and scroll in single motion, and then dragged back down', (WidgetTester tester) async { int taps = 0; await tester.pumpWidget(boilerplateWidget(() => taps++)); @@ -252,7 +253,7 @@ void main() { expect(find.text('Item 36'), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Can be flung up gently', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be flung up gently', (WidgetTester tester) async { int taps = 0; await tester.pumpWidget(boilerplateWidget(() => taps++)); @@ -275,7 +276,7 @@ void main() { expect(find.text('Item 70'), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Can be flung up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be flung up', (WidgetTester tester) async { int taps = 0; await tester.pumpWidget(boilerplateWidget(() => taps++)); @@ -301,7 +302,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Can be flung down when not full height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be flung down when not full height', (WidgetTester tester) async { await tester.pumpWidget(boilerplateWidget(null)); expect(find.text('Item 1'), findsOneWidget); expect(find.text('Item 21'), findsOneWidget); @@ -314,7 +315,7 @@ void main() { expect(find.text('Item 36'), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Can be flung up and then back down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be flung up and then back down', (WidgetTester tester) async { int taps = 0; await tester.pumpWidget(boilerplateWidget(() => taps++)); @@ -358,7 +359,7 @@ void main() { expect(find.text('Item 70'), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Ballistic animation on fling can be interrupted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ballistic animation on fling can be interrupted', (WidgetTester tester) async { int taps = 0; await tester.pumpWidget(boilerplateWidget(() => taps++)); @@ -392,7 +393,7 @@ void main() { expect(find.text('Item 70'), findsNothing); }, variant: TargetPlatformVariant.all()); - testWidgets('Ballistic animation on fling should not leak Ticker', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ballistic animation on fling should not leak Ticker', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/101061 await tester.pumpWidget( Directionality( @@ -447,7 +448,7 @@ void main() { }); }); - testWidgets('Does not snap away from initial child on build', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not snap away from initial child on build', (WidgetTester tester) async { const Key containerKey = ValueKey<String>('container'); const Key stackKey = ValueKey<String>('stack'); await tester.pumpWidget(boilerplateWidget(null, @@ -467,10 +468,11 @@ void main() { }, variant: TargetPlatformVariant.all()); for (final bool useActuator in <bool>[false, true]) { - testWidgets('Does not snap away from initial child on ${useActuator ? 'actuator' : 'controller'}.reset()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not snap away from initial child on ${useActuator ? 'actuator' : 'controller'}.reset()', (WidgetTester tester) async { const Key containerKey = ValueKey<String>('container'); const Key stackKey = ValueKey<String>('stack'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, controller: controller, @@ -504,7 +506,7 @@ void main() { } for (final Duration? snapAnimationDuration in <Duration?>[null, const Duration(seconds: 2)]) { - testWidgets( + testWidgetsWithLeakTracking( 'Zero velocity drag snaps to nearest snap target with ' 'snapAnimationDuration: $snapAnimationDuration', (WidgetTester tester) async { @@ -563,7 +565,7 @@ void main() { } for (final List<double>? snapSizes in <List<double>?>[null, <double>[]]) { - testWidgets('Setting snapSizes to $snapSizes resolves to min and max', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting snapSizes to $snapSizes resolves to min and max', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); await tester.pumpWidget(boilerplateWidget(null, @@ -591,7 +593,7 @@ void main() { }, variant: TargetPlatformVariant.all()); } - testWidgets('Min and max are implicitly added to snapSizes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Min and max are implicitly added to snapSizes', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); await tester.pumpWidget(boilerplateWidget(null, @@ -618,7 +620,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('Changes to widget parameters are propagated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changes to widget parameters are propagated', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); await tester.pumpWidget(boilerplateWidget( @@ -726,7 +728,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('Fling snaps in direction of momentum', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fling snaps in direction of momentum', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); await tester.pumpWidget(boilerplateWidget(null, @@ -754,7 +756,7 @@ void main() { }, variant: TargetPlatformVariant.all()); - testWidgets("Changing parameters with an un-listened controller doesn't throw", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Changing parameters with an un-listened controller doesn't throw", (WidgetTester tester) async { await tester.pumpWidget(boilerplateWidget( null, snap: true, @@ -769,7 +771,7 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.all()); - testWidgets('Transitioning between scrollable children sharing a scroll controller will not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Transitioning between scrollable children sharing a scroll controller will not throw', (WidgetTester tester) async { int s = 0; await tester.pumpWidget(MaterialApp( home: StatefulBuilder( @@ -826,7 +828,7 @@ void main() { // Completes without throwing }); - testWidgets('ScrollNotification correctly dispatched when flung without covering its container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollNotification correctly dispatched when flung without covering its container', (WidgetTester tester) async { final List<Type> notificationTypes = <Type>[]; await tester.pumpWidget(boilerplateWidget( null, @@ -847,7 +849,7 @@ void main() { expect(notificationTypes, equals(types)); }); - testWidgets('ScrollNotification correctly dispatched when flung with contents scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollNotification correctly dispatched when flung with contents scroll', (WidgetTester tester) async { final List<Type> notificationTypes = <Type>[]; await tester.pumpWidget(boilerplateWidget( null, @@ -870,7 +872,7 @@ void main() { expect(notificationTypes, types); }); - testWidgets('Emits DraggableScrollableNotification with shouldCloseOnMinExtent set to non-default value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Emits DraggableScrollableNotification with shouldCloseOnMinExtent set to non-default value', (WidgetTester tester) async { DraggableScrollableNotification? receivedNotification; await tester.pumpWidget(boilerplateWidget( null, @@ -886,7 +888,7 @@ void main() { expect(receivedNotification!.shouldCloseOnMinExtent, isFalse); }); - testWidgets('Do not crash when remove the tree during animation.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when remove the tree during animation.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/89214 await tester.pumpWidget(boilerplateWidget( null, @@ -905,10 +907,11 @@ void main() { }); for (final bool shouldAnimate in <bool>[true, false]) { - testWidgets('Can ${shouldAnimate ? 'animate' : 'jump'} to arbitrary positions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can ${shouldAnimate ? 'animate' : 'jump'} to arbitrary positions', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, controller: controller, @@ -980,10 +983,11 @@ void main() { }); } - testWidgets('Can animateTo with a nonlinear curve', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can animateTo with a nonlinear curve', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, controller: controller, @@ -1027,10 +1031,11 @@ void main() { ); }); - testWidgets('Can animateTo with a Curves.easeInOutBack curve begin min-size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can animateTo with a Curves.easeInOutBack curve begin min-size', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, initialChildSize: 0.25, @@ -1050,10 +1055,11 @@ void main() { ); }); - testWidgets('Can reuse a controller after the old controller is disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can reuse a controller after the old controller is disposed', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, controller: controller, @@ -1080,10 +1086,11 @@ void main() { ); }); - testWidgets('animateTo interrupts other animations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animateTo interrupts other animations', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: boilerplateWidget( @@ -1116,10 +1123,11 @@ void main() { expect(find.text('Item 1'), findsOneWidget); }); - testWidgets('Other animations interrupt animateTo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Other animations interrupt animateTo', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: boilerplateWidget( @@ -1149,10 +1157,11 @@ void main() { ); }); - testWidgets('animateTo can be interrupted by other animateTo or jumpTo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animateTo can be interrupted by other animateTo or jumpTo', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: boilerplateWidget( @@ -1191,10 +1200,11 @@ void main() { ); }); - testWidgets('Can get size and pixels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can get size and pixels', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, controller: controller, @@ -1223,6 +1233,7 @@ void main() { testWidgets('Cannot attach a controller to multiple sheets', (WidgetTester tester) async { final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Stack( @@ -1241,11 +1252,12 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('Can listen for changes in sheet size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can listen for changes in sheet size', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final List<double> loggedSizes = <double>[]; final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); controller.addListener(() { loggedSizes.add(controller.size); }); @@ -1289,11 +1301,12 @@ void main() { loggedSizes.clear(); }); - testWidgets('Listener does not fire on parameter change and persists after change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Listener does not fire on parameter change and persists after change', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final List<double> loggedSizes = <double>[]; final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); controller.addListener(() { loggedSizes.add(controller.size); }); @@ -1331,11 +1344,12 @@ void main() { loggedSizes.clear(); }); - testWidgets('Listener fires if a parameter change forces a change in size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Listener fires if a parameter change forces a change in size', (WidgetTester tester) async { const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final List<double> loggedSizes = <double>[]; final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); controller.addListener(() { loggedSizes.add(controller.size); }); @@ -1382,8 +1396,9 @@ void main() { loggedSizes.clear(); }); - testWidgets('Invalid controller interactions throw assertion errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Invalid controller interactions throw assertion errors', (WidgetTester tester) async { final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); // Can't use a controller before attaching it. expect(() => controller.jumpTo(.1), throwsAssertionError); @@ -1414,8 +1429,9 @@ void main() { expect(() => controller.animateTo(.5, duration: Duration.zero, curve: Curves.linear), throwsAssertionError); }); - testWidgets('DraggableScrollableController must be attached before using any of its parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableController must be attached before using any of its parameters', (WidgetTester tester) async { final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); expect(controller.isAttached, false); expect(()=>controller.size, throwsAssertionError); final Widget boilerplate = boilerplateWidget( @@ -1428,8 +1444,9 @@ void main() { expect(controller.size, isNotNull); }); - testWidgets('DraggableScrollableController.animateTo after detach', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableController.animateTo after detach', (WidgetTester tester) async { final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget(() {}, controller: controller)); controller.animateTo(0.0, curve: Curves.linear, duration: const Duration(milliseconds: 200)); @@ -1442,11 +1459,12 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('DraggableScrollableSheet should not reset programmatic drag on rebuild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableSheet should not reset programmatic drag on rebuild', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/101114 const Key stackKey = ValueKey<String>('stack'); const Key containerKey = ValueKey<String>('container'); final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); await tester.pumpWidget(boilerplateWidget( null, controller: controller, @@ -1508,9 +1526,10 @@ void main() { ); }); - testWidgets('DraggableScrollableSheet should respect NeverScrollableScrollPhysics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableSheet should respect NeverScrollableScrollPhysics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/121021 final DraggableScrollableController controller = DraggableScrollableController(); + addTearDown(controller.dispose); Widget buildFrame(ScrollPhysics? physics) { return MaterialApp( home: Scaffold( @@ -1553,7 +1572,7 @@ void main() { expect(controller.pixels, initPixels + 300.0); }); - testWidgets('DraggableScrollableSheet should not rebuild every frame while dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableSheet should not rebuild every frame while dragging', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/67219 int buildCount = 0; await tester.pumpWidget(MaterialApp( @@ -1600,9 +1619,11 @@ void main() { expect(buildCount, 2); }); - testWidgets('DraggableScrollableSheet controller can be changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableSheet controller can be changed', (WidgetTester tester) async { final DraggableScrollableController controller1 = DraggableScrollableController(); + addTearDown(controller1.dispose); final DraggableScrollableController controller2 = DraggableScrollableController(); + addTearDown(controller2.dispose); final List<double> loggedSizes = <double>[]; DraggableScrollableController controller = controller1; @@ -1658,7 +1679,7 @@ void main() { expect(loggedSizes, <double>[1.0].map((double v) => closeTo(v, precisionErrorTolerance))); }); - testWidgets('DraggableScrollableSheet controller can be changed while animating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DraggableScrollableSheet controller can be changed while animating', (WidgetTester tester) async { final DraggableScrollableController controller1 = DraggableScrollableController(); final DraggableScrollableController controller2 = DraggableScrollableController(); From 9dde2166b72fa5d8c7f1abe1337645f4bf591a2c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 18:09:05 -0400 Subject: [PATCH 1165/1547] Roll Flutter Engine from 2da727e23518 to 8d2892211366 (1 revision) (#134316) https://github.com/flutter/engine/compare/2da727e23518...8d2892211366 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 244c9ba5d0d7 to 4996cc1ef9ba (2 revisions) (flutter/engine#45586) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4969036205e61..b2c85c3fa9a7e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2da727e235182c4c58da054d991a3c57d9ef5712 +8d2892211366590ee6cb5770d7d5ff41b001b59f From 9c210237c965049a8398e4b5ee2702edb71fbcc6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 18:51:29 -0400 Subject: [PATCH 1166/1547] Roll Flutter Engine from 8d2892211366 to 66bec85d5005 (3 revisions) (#134321) https://github.com/flutter/engine/compare/8d2892211366...66bec85d5005 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from 765bca2f810a to 98b0855b9a71 (1 revision) (flutter/engine#45589) 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 4996cc1ef9ba to 1012ef8349ba (1 revision) (flutter/engine#45588) 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from a507f31285b8 to 765bca2f810a (1 revision) (flutter/engine#45587) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b2c85c3fa9a7e..dd9e0ae543baa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8d2892211366590ee6cb5770d7d5ff41b001b59f +66bec85d5005ad1d89e3f19f3694b77640ed168e From 996eb112457d55657271c5d1e73d466530283247 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 20:31:24 -0400 Subject: [PATCH 1167/1547] Roll Flutter Engine from 66bec85d5005 to d6aa2d9061c1 (1 revision) (#134324) https://github.com/flutter/engine/compare/66bec85d5005...d6aa2d9061c1 2023-09-08 skia-flutter-autoroll@skia.org Roll Skia from 1012ef8349ba to 7f1d86d81d41 (1 revision) (flutter/engine#45594) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index dd9e0ae543baa..fe72745d342cf 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -66bec85d5005ad1d89e3f19f3694b77640ed168e +d6aa2d9061c141ed7eb0f48e83a6fefa2c494977 From 0c2f1af055346e59deca6c422855aa24a3e67099 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 22:05:27 -0400 Subject: [PATCH 1168/1547] Roll Flutter Engine from d6aa2d9061c1 to 3a5f3ad1d054 (3 revisions) (#134327) https://github.com/flutter/engine/compare/d6aa2d9061c1...3a5f3ad1d054 2023-09-09 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from KvtLknmg3f23uqWVm... to jYqYNRum5gWGFyoHR... (flutter/engine#45599) 2023-09-09 skia-flutter-autoroll@skia.org Roll Skia from 7f1d86d81d41 to e5987e341cfd (1 revision) (flutter/engine#45597) 2023-09-08 skia-flutter-autoroll@skia.org Roll ANGLE from 98b0855b9a71 to fce1e57401bf (3 revisions) (flutter/engine#45596) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from KvtLknmg3f23 to jYqYNRum5gWG If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fe72745d342cf..beb1d8f75a5a6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d6aa2d9061c141ed7eb0f48e83a6fefa2c494977 +3a5f3ad1d054a7ba2eec4e29f2a350c5f023c528 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 85ab851fadfad..75932c3ffd12e 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -KvtLknmg3f23uqWVmAC4HGmxtv2DgAUqg3fBk-q6qloC +jYqYNRum5gWGFyoHRKDQxHUgkILMJP2OvI_vl-UZ6-AC From e5d919caedb15f5d5ab602c7fb7e80f298227872 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 8 Sep 2023 22:51:25 -0400 Subject: [PATCH 1169/1547] Roll Flutter Engine from 3a5f3ad1d054 to 1f2da3d69da7 (1 revision) (#134328) https://github.com/flutter/engine/compare/3a5f3ad1d054...1f2da3d69da7 2023-09-09 30870216+gaaclarke@users.noreply.github.com Makes Skia's vkQueueSubmit threadsafe. (flutter/engine#45459) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index beb1d8f75a5a6..23285cc6929c2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3a5f3ad1d054a7ba2eec4e29f2a350c5f023c528 +1f2da3d69da705337b7700ec276012369997eb43 From 12ce42b73ae2e188e58c7808fef8f45837d42639 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 00:24:27 -0400 Subject: [PATCH 1170/1547] Roll Flutter Engine from 1f2da3d69da7 to 7af8a5d8d556 (2 revisions) (#134332) https://github.com/flutter/engine/compare/1f2da3d69da7...7af8a5d8d556 2023-09-09 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from h_bQLstuirD8blCZW... to RbgNQ_B-mcwvmNSq3... (flutter/engine#45603) 2023-09-09 skia-flutter-autoroll@skia.org Roll ANGLE from fce1e57401bf to 48e2c605adcd (2 revisions) (flutter/engine#45602) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from h_bQLstuirD8 to RbgNQ_B-mcwv If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 23285cc6929c2..872646da22f86 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1f2da3d69da705337b7700ec276012369997eb43 +7af8a5d8d556869c7f9f1a7056c86eb1c9db4af5 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 70bf494ee87c2..a83c337c8ee01 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -h_bQLstuirD8blCZWjrkPzMPx4VbRdEiV93QgP9zvckC +RbgNQ_B-mcwvmNSq3OUtEnvQ40BeyIue-9CEUNFOABIC From 2b642822b0f0ca97bb5126e6b3c47edc266b932d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 04:27:40 -0400 Subject: [PATCH 1171/1547] Roll Flutter Engine from 7af8a5d8d556 to 00ef109b845e (1 revision) (#134336) https://github.com/flutter/engine/compare/7af8a5d8d556...00ef109b845e 2023-09-09 skia-flutter-autoroll@skia.org Roll Skia from e5987e341cfd to 3dfd4316b80d (1 revision) (flutter/engine#45607) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 872646da22f86..4a32d26e53e4a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7af8a5d8d556869c7f9f1a7056c86eb1c9db4af5 +00ef109b845ee9c8d8d46893ca9b6565d7c3ceeb From 3f4ee3fbcc338a3a32640c232c3138e8c6699abb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 10:42:37 -0400 Subject: [PATCH 1172/1547] Roll Flutter Engine from 00ef109b845e to 348e3a376807 (1 revision) (#134349) https://github.com/flutter/engine/compare/00ef109b845e...348e3a376807 2023-09-09 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from jYqYNRum5gWGFyoHR... to i9IPFS-XpkPjlH235... (flutter/engine#45609) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from jYqYNRum5gWG to i9IPFS-XpkPj If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4a32d26e53e4a..b05ccd37ef88f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -00ef109b845ee9c8d8d46893ca9b6565d7c3ceeb +348e3a3768073a49138624abb2709534cd5f5ff2 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 75932c3ffd12e..fd2db8e288995 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -jYqYNRum5gWGFyoHRKDQxHUgkILMJP2OvI_vl-UZ6-AC +i9IPFS-XpkPjlH235d8PSdtIJk5TQ-Kobxu4CcD_CAMC From 55558367127f32efc9d87b5917013e0fbd4a7ec0 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Sat, 9 Sep 2023 08:45:27 -0700 Subject: [PATCH 1173/1547] Day picker should dispose created MaterialStatesController's. (#133884) Fixes https://github.com/flutter/flutter/issues/133862 --- .../src/material/calendar_date_picker.dart | 12 +++++++++- .../material/calendar_date_picker_test.dart | 24 +++++++++++++++++++ .../test/material/date_picker_test.dart | 10 ++------ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 2a3e842dddb6a..4b1f892dd88ea 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -868,6 +868,10 @@ class _DayPickerState extends State<_DayPicker> { /// List of [FocusNode]s, one for each day of the month. late List<FocusNode> _dayFocusNodes; + // TODO(polina-c): a cleaner solution is to create separate statefull widget for a day. + // https://github.com/flutter/flutter/issues/134323 + final Map<int, MaterialStatesController> _statesControllers = <int, MaterialStatesController>{}; + @override void initState() { super.initState(); @@ -893,6 +897,9 @@ class _DayPickerState extends State<_DayPicker> { for (final FocusNode node in _dayFocusNodes) { node.dispose(); } + for (final MaterialStatesController controller in _statesControllers.values) { + controller.dispose(); + } super.dispose(); } @@ -973,6 +980,9 @@ class _DayPickerState extends State<_DayPicker> { if (isSelectedDay) MaterialState.selected, }; + final MaterialStatesController statesController = _statesControllers.putIfAbsent(day, () => MaterialStatesController()); + statesController.value = states; + final Color? dayForegroundColor = resolve<Color?>((DatePickerThemeData? theme) => isToday ? theme?.todayForegroundColor : theme?.dayForegroundColor, states); final Color? dayBackgroundColor = resolve<Color?>((DatePickerThemeData? theme) => isToday ? theme?.todayBackgroundColor : theme?.dayBackgroundColor, states); final MaterialStateProperty<Color?> dayOverlayColor = MaterialStateProperty.resolveWith<Color?>( @@ -1008,7 +1018,7 @@ class _DayPickerState extends State<_DayPicker> { focusNode: _dayFocusNodes[day - 1], onTap: () => widget.onChanged(dayToBuild), radius: _dayPickerRowHeight / 2 + 4, - statesController: MaterialStatesController(states), + statesController: statesController, overlayColor: dayOverlayColor, child: Semantics( // We want the day of month to be spoken first irrespective of the diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index c3b3c80845cd1..98b95e8c42743 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -516,6 +516,30 @@ void main() { expect(find.text('2017'), findsNothing); }); + testWidgets('Selecting disabled date does not change current selection', (WidgetTester tester) async { + DateTime day(int day) => DateTime(2020, DateTime.may, day); + + DateTime selection = day(2); + await tester.pumpWidget(calendarDatePicker( + initialDate: selection, + firstDate: day(2), + lastDate: day(3), + onDateChanged: (DateTime date) { + selection = date; + }, + )); + + await tester.tap(find.text('3')); + await tester.pumpAndSettle(); + expect(selection, day(3)); + await tester.tap(find.text('4')); + await tester.pumpAndSettle(); + expect(selection, day(3)); + await tester.tap(find.text('5')); + await tester.pumpAndSettle(); + expect(selection, day(3)); + }); + for (final bool useMaterial3 in <bool>[false, true]) { testWidgets('Updates to initialDate parameter are not reflected in the state (useMaterial3=$useMaterial3)', (WidgetTester tester) async { final Key pickerKey = UniqueKey(); diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index d58fa42ced2b5..66cddc20c9138 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -8,7 +8,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -173,16 +172,11 @@ void main() { }, useMaterial3: theme.useMaterial3); }); - testWidgetsWithLeakTracking('Material3 uses sentence case labels', (WidgetTester tester) async { + testWidgets('Material3 uses sentence case labels', (WidgetTester tester) async { await prepareDatePicker(tester, (Future<DateTime?> date) async { expect(find.text('Select date'), findsOneWidget); }, useMaterial3: true); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/133862 - allowAllNotDisposed: true, - )); + }); testWidgets('Cancel, confirm, and help text is used', (WidgetTester tester) async { cancelText = 'nope'; From 6660cc981669297dc36bd7cb6062a01976268a5b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 11:52:13 -0400 Subject: [PATCH 1174/1547] Roll Flutter Engine from 348e3a376807 to 4e3231af6efc (1 revision) (#134353) https://github.com/flutter/engine/compare/348e3a376807...4e3231af6efc 2023-09-09 skia-flutter-autoroll@skia.org Roll Skia from 3dfd4316b80d to 58e39bd84ab2 (1 revision) (flutter/engine#45610) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b05ccd37ef88f..33d78a9378b63 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -348e3a3768073a49138624abb2709534cd5f5ff2 +4e3231af6efce01725f0ab68020fcfee6bf9ee23 From 7c28e8eb07348f1de58e1a41485859069fb1e186 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 12:48:23 -0400 Subject: [PATCH 1175/1547] Roll Flutter Engine from 4e3231af6efc to d1913cb6a276 (1 revision) (#134355) https://github.com/flutter/engine/compare/4e3231af6efc...d1913cb6a276 2023-09-09 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from RbgNQ_B-mcwvmNSq3... to 51fG0shrG6fW64BtN... (flutter/engine#45612) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from RbgNQ_B-mcwv to 51fG0shrG6fW If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 33d78a9378b63..93cd510d960e1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4e3231af6efce01725f0ab68020fcfee6bf9ee23 +d1913cb6a2765cef8efb4dacf8a6ef431f5e256d diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index a83c337c8ee01..3b5f240aed3eb 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -RbgNQ_B-mcwvmNSq3OUtEnvQ40BeyIue-9CEUNFOABIC +51fG0shrG6fW64BtN1B2n9Lrnq0A8GI_gbX4D9udU3MC From cc317dff86c4ae9acdd5844a75c6e73ca260a3e2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 14:06:18 -0400 Subject: [PATCH 1176/1547] Roll Flutter Engine from d1913cb6a276 to b8afb6deacf3 (1 revision) (#134356) https://github.com/flutter/engine/compare/d1913cb6a276...b8afb6deacf3 2023-09-09 skia-flutter-autoroll@skia.org Roll Skia from 58e39bd84ab2 to 386c7a6a56fd (1 revision) (flutter/engine#45614) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 93cd510d960e1..6075bcf271d50 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d1913cb6a2765cef8efb4dacf8a6ef431f5e256d +b8afb6deacf35bf1cd2f84be13872a6759e43cdd From c7665ff84cdb2b792590947b25fb12f5bc2d5340 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 17:26:17 -0400 Subject: [PATCH 1177/1547] Roll Flutter Engine from b8afb6deacf3 to 4edbefa5e8f7 (1 revision) (#134360) https://github.com/flutter/engine/compare/b8afb6deacf3...4edbefa5e8f7 2023-09-09 skia-flutter-autoroll@skia.org Roll Skia from 386c7a6a56fd to 1bb0f15f2cff (1 revision) (flutter/engine#45615) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6075bcf271d50..3bab2c32fae85 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b8afb6deacf35bf1cd2f84be13872a6759e43cdd +4edbefa5e8f747c92d7738ef526a7b84f16b5bac From 2c477b181297a9089f73d508acb7d07bd4784f89 Mon Sep 17 00:00:00 2001 From: Renzo Olivares <rmolivares@renzo-olivares.dev> Date: Sat, 9 Sep 2023 15:03:23 -0700 Subject: [PATCH 1178/1547] SelectableRegion onSelectionChange should be called when the selection changes (#134215) This change makes sure to call `onSelectionChange` in all cases when selection might change including: * Dragging selection handles * Mouse drag to select * Keyboard actions * Long press drag to select --- .../lib/src/widgets/selectable_region.dart | 10 + .../test/widgets/selectable_region_test.dart | 255 +++++++++++++++++- 2 files changed, 256 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 17abff5de57b3..b0a26c11d04ad 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -502,6 +502,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe case 2: _selectWordAt(offset: details.globalPosition); } + _updateSelectedContentIfNeeded(); } void _handleMouseDragStart(TapDragStartDetails details) { @@ -509,6 +510,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe case 1: _selectStartTo(offset: details.globalPosition); } + _updateSelectedContentIfNeeded(); } void _handleMouseDragUpdate(TapDragUpdateDetails details) { @@ -518,6 +520,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe case 2: _selectEndTo(offset: details.globalPosition, continuous: true, textGranularity: TextGranularity.word); } + _updateSelectedContentIfNeeded(); } void _handleMouseDragEnd(TapDragEndDetails details) { @@ -543,6 +546,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe void _handleTouchLongPressMoveUpdate(LongPressMoveUpdateDetails details) { _selectEndTo(offset: details.globalPosition, textGranularity: TextGranularity.word); + _updateSelectedContentIfNeeded(); } void _handleTouchLongPressEnd(LongPressEndDetails details) { @@ -717,6 +721,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe details.globalPosition, _selectionDelegate.value.startSelectionPoint!, )); + _updateSelectedContentIfNeeded(); } void _handleSelectionStartHandleDragUpdate(DragUpdateDetails details) { @@ -730,6 +735,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe details.globalPosition, _selectionDelegate.value.startSelectionPoint!, )); + _updateSelectedContentIfNeeded(); } void _handleSelectionEndHandleDragStart(DragStartDetails details) { @@ -742,6 +748,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe details.globalPosition, _selectionDelegate.value.endSelectionPoint!, )); + _updateSelectedContentIfNeeded(); } void _handleSelectionEndHandleDragUpdate(DragUpdateDetails details) { @@ -755,6 +762,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe details.globalPosition, _selectionDelegate.value.endSelectionPoint!, )); + _updateSelectedContentIfNeeded(); } MagnifierInfo _buildInfoForMagnifier(Offset globalGesturePosition, SelectionPoint selectionPoint) { @@ -1067,6 +1075,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe granularity: granularity, ), ); + _updateSelectedContentIfNeeded(); } double? _directionalHorizontalBaseline; @@ -1088,6 +1097,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe dx: globalSelectionPointOffset.dx, ), ); + _updateSelectedContentIfNeeded(); } // [TextSelectionDelegate] overrides. diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index b4e3f5d0eeb48..1e25ba4e7ff41 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -2713,7 +2713,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + testWidgets('onSelectionChange is called when the selection changes through gestures', (WidgetTester tester) async { SelectedContent? content; await tester.pumpWidget( @@ -2728,27 +2728,264 @@ void main() { ), ), ); + final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); - final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 4), kind: PointerDeviceKind.mouse); + final TestGesture mouseGesture = await tester.startGesture(textOffsetToPosition(paragraph, 4), kind: PointerDeviceKind.mouse); + final TestGesture touchGesture = await tester.createGesture(); + expect(content, isNull); - addTearDown(gesture.removePointer); + addTearDown(mouseGesture.removePointer); + addTearDown(touchGesture.removePointer); await tester.pump(); - await gesture.moveTo(textOffsetToPosition(paragraph, 7)); - await gesture.up(); - await tester.pump(); + // Called on drag. + await mouseGesture.moveTo(textOffsetToPosition(paragraph, 7)); + await tester.pumpAndSettle(); expect(content, isNotNull); expect(content!.plainText, 'are'); + // Updates on drag. + await mouseGesture.moveTo(textOffsetToPosition(paragraph, 10)); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'are yo'); + + // Called on drag end. + await mouseGesture.up(); + await tester.pump(); + expect(content, isNotNull); + expect(content!.plainText, 'are yo'); + // Backwards selection. - await gesture.down(textOffsetToPosition(paragraph, 3)); + await mouseGesture.down(textOffsetToPosition(paragraph, 3)); await tester.pumpAndSettle(); expect(content, isNull); - await gesture.moveTo(textOffsetToPosition(paragraph, 0)); - await gesture.up(); + + await mouseGesture.moveTo(textOffsetToPosition(paragraph, 0)); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'How'); + + await mouseGesture.up(); + await tester.pump(); + expect(content, isNotNull); + expect(content!.plainText, 'How'); + + // Called on double tap. + await mouseGesture.down(textOffsetToPosition(paragraph, 6)); + await tester.pump(); + await mouseGesture.up(); await tester.pump(); + await mouseGesture.down(textOffsetToPosition(paragraph, 6)); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'are'); + await mouseGesture.up(); + await tester.pumpAndSettle(); + + // Called on tap. + await mouseGesture.down(textOffsetToPosition(paragraph, 0)); + await tester.pumpAndSettle(); + expect(content, isNull); + await mouseGesture.up(); + await tester.pumpAndSettle(); + + // With touch gestures. + + // Called on long press start. + await touchGesture.down(textOffsetToPosition(paragraph, 0)); + await tester.pumpAndSettle(kLongPressTimeout); expect(content, isNotNull); expect(content!.plainText, 'How'); + + // Called on long press update. + await touchGesture.moveTo(textOffsetToPosition(paragraph, 5)); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'How are'); + + // Called on long press end. + await touchGesture.up(); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'How are'); + + // Long press to select 'you'. + await touchGesture.down(textOffsetToPosition(paragraph, 9)); + await tester.pumpAndSettle(kLongPressTimeout); + expect(content, isNotNull); + expect(content!.plainText, 'you'); + await touchGesture.up(); + await tester.pumpAndSettle(); + + // Called while moving selection handles. + final List<TextBox> boxes = paragraph.getBoxesForSelection(paragraph.selections[0]); + expect(boxes.length, 1); + final Offset startHandlePos = globalize(boxes[0].toRect().bottomLeft, paragraph); + final Offset endHandlePos = globalize(boxes[0].toRect().bottomRight, paragraph); + final Offset startPos = Offset(textOffsetToPosition(paragraph, 4).dx, startHandlePos.dy); + final Offset endPos = Offset(textOffsetToPosition(paragraph, 6).dx, endHandlePos.dy); + + // Start handle. + await touchGesture.down(startHandlePos); + await touchGesture.moveTo(startPos); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'are you'); + await touchGesture.up(); + await tester.pumpAndSettle(); + + // End handle. + await touchGesture.down(endHandlePos); + await touchGesture.moveTo(endPos); + await tester.pumpAndSettle(); + expect(content, isNotNull); + expect(content!.plainText, 'ar'); + await touchGesture.up(); + await tester.pumpAndSettle(); + }); + + testWidgets('onSelectionChange is called when the selection changes through keyboard actions', (WidgetTester tester) async { + SelectedContent? content; + + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + onSelectionChanged: (SelectedContent? selectedContent) => content = selectedContent, + focusNode: FocusNode(), + selectionControls: materialTextSelectionControls, + child: const Column( + children: <Widget>[ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + + expect(content, isNull); + await tester.pump(); + + final RenderParagraph paragraph1 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + final RenderParagraph paragraph2 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText))); + final RenderParagraph paragraph3 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('Fine, thank you.'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 2), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.moveTo(textOffsetToPosition(paragraph1, 6)); + await gesture.up(); + await tester.pump(); + + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 6); + expect(content, isNotNull); + expect(content!.plainText, 'w ar'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 7); + expect(content, isNotNull); + expect(content!.plainText, 'w are'); + + for (int i = 0; i < 5; i += 1) { + await sendKeyCombination(tester, + const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 8 + i); + expect(content, isNotNull); + } + expect(content, isNotNull); + expect(content!.plainText, 'w are you?'); + + for (int i = 0; i < 5; i += 1) { + await sendKeyCombination(tester, + const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 11 - i); + expect(content, isNotNull); + } + expect(content, isNotNull); + expect(content!.plainText, 'w are'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 12); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 8); + expect(content, isNotNull); + expect(content!.plainText, 'w are you?Good, an'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 12); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 14); + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 0); + expect(paragraph3.selections[0].end, 9); + expect(content, isNotNull); + expect(content!.plainText, 'w are you?Good, and you?Fine, tha'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 12); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 14); + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 0); + expect(paragraph3.selections[0].end, 16); + expect(content, isNotNull); + expect(content!.plainText, 'w are you?Good, and you?Fine, thank you.'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 12); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 8); + expect(paragraph3.selections.length, 0); + expect(content, isNotNull); + expect(content!.plainText, 'w are you?Good, an'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 2); + expect(paragraph1.selections[0].end, 7); + expect(paragraph2.selections.length, 0); + expect(paragraph3.selections.length, 0); + expect(content, isNotNull); + expect(content!.plainText, 'w are'); + + await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true)); + await tester.pump(); + expect(paragraph1.selections.length, 1); + expect(paragraph1.selections[0].start, 0); + expect(paragraph1.selections[0].end, 2); + expect(paragraph2.selections.length, 0); + expect(paragraph3.selections.length, 0); + expect(content, isNotNull); + expect(content!.plainText, 'Ho'); }); group('BrowserContextMenu', () { From 8919140c0a670073f8f2771e3b08f886f92d1234 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 9 Sep 2023 23:37:11 -0400 Subject: [PATCH 1179/1547] Roll Flutter Engine from 4edbefa5e8f7 to feea98d6d0ae (1 revision) (#134365) https://github.com/flutter/engine/compare/4edbefa5e8f7...feea98d6d0ae 2023-09-10 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from i9IPFS-XpkPjlH235... to U70-bvYinYjKdGGSt... (flutter/engine#45618) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from i9IPFS-XpkPj to U70-bvYinYjK If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3bab2c32fae85..942e19e7643b2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4edbefa5e8f747c92d7738ef526a7b84f16b5bac +feea98d6d0aef69da20a1213015b818e8287d10c diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index fd2db8e288995..bd7f39b2448d2 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -i9IPFS-XpkPjlH235d8PSdtIJk5TQ-Kobxu4CcD_CAMC +U70-bvYinYjKdGGStMi2yKvQjCrMLuEQU_ujw0KK7NsC From 690800bca3198e63bdcdd212d0bf2ab59f5bcbfa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sun, 10 Sep 2023 01:41:26 -0400 Subject: [PATCH 1180/1547] Roll Flutter Engine from feea98d6d0ae to 47d1a045d140 (1 revision) (#134368) https://github.com/flutter/engine/compare/feea98d6d0ae...47d1a045d140 2023-09-10 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 51fG0shrG6fW64BtN... to VciXahwZgiusifyh8... (flutter/engine#45620) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 51fG0shrG6fW to VciXahwZgius If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 942e19e7643b2..c12752eadf7aa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -feea98d6d0aef69da20a1213015b818e8287d10c +47d1a045d1407325b80694e4b3690fb516842d52 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 3b5f240aed3eb..bcf3eeb031fb2 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -51fG0shrG6fW64BtN1B2n9Lrnq0A8GI_gbX4D9udU3MC +VciXahwZgiusifyh8fc6jIjfaKr6VGDrWeIN0Lul1yYC From aa36db1d29eb53b74dd1dda5a12e37800c628358 Mon Sep 17 00:00:00 2001 From: Daco Harkes <dacoharkes@google.com> Date: Sun, 10 Sep 2023 10:07:13 +0200 Subject: [PATCH 1181/1547] Native assets support for MacOS and iOS (#130494) Support for FFI calls with `@Native external` functions through Native assets on MacOS and iOS. This enables bundling native code without any build-system boilerplate code. For more info see: * https://github.com/flutter/flutter/issues/129757 ### Implementation details for MacOS and iOS. Dylibs are bundled by (1) making them fat binaries if multiple architectures are targeted, (2) code signing these, and (3) copying them to the frameworks folder. These steps are done manual rather than via CocoaPods. CocoaPods would have done the same steps, but (a) needs the dylibs to be there before the `xcodebuild` invocation (we could trick it, by having a minimal dylib in the place and replace it during the build process, that works), and (b) can't deal with having no dylibs to be bundled (we'd have to bundle a dummy dylib or include some dummy C code in the build file). The dylibs are build as a new target inside flutter assemble, as that is the moment we know what build-mode and architecture to target. The mapping from asset id to dylib-path is passed in to every kernel compilation path. The interesting case is hot-restart where the initial kernel file is compiled by the "inner" flutter assemble, while after hot restart the "outer" flutter run compiled kernel file is pushed to the device. Both kernel files need to contain the mapping. The "inner" flutter assemble gets its mapping from the NativeAssets target which builds the native assets. The "outer" flutter run get its mapping from a dry-run invocation. Since this hot restart can be used for multiple target devices (`flutter run -d all`) it contains the mapping for all known targets. ### Example vs template The PR includes a new template that uses the new native assets in a package and has an app importing that. Separate discussion in: https://github.com/flutter/flutter/issues/131209. ### Tests This PR adds new tests to cover the various use cases. * dev/devicelab/bin/tasks/native_assets_ios.dart * Runs an example app with native assets in all build modes, doing hot reload and hot restart in debug mode. * dev/devicelab/bin/tasks/native_assets_ios_simulator.dart * Runs an example app with native assets, doing hot reload and hot restart. * packages/flutter_tools/test/integration.shard/native_assets_test.dart * Runs (incl hot reload/hot restart), builds, builds frameworks for iOS, MacOS and flutter-tester. * packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart * Unit tests the new Target in the backend. * packages/flutter_tools/test/general.shard/ios/native_assets_test.dart * packages/flutter_tools/test/general.shard/macos/native_assets_test.dart * Unit tests the native assets being packaged on a iOS/MacOS build. It also extends various existing tests: * dev/devicelab/bin/tasks/module_test_ios.dart * Exercises the add2app scenario. * packages/flutter_tools/test/general.shard/features_test.dart * Unit test the new feature flag. --- .ci.yaml | 20 + TESTOWNERS | 2 + dev/devicelab/bin/tasks/module_test_ios.dart | 65 ++- .../bin/tasks/native_assets_ios.dart | 14 + .../tasks/native_assets_ios_simulator.dart | 31 ++ .../lib/tasks/native_assets_test.dart | 191 +++++++++ .../ios_host_app/flutterapp/lib/main | 6 + packages/flutter_tools/bin/macos_assemble.sh | 15 +- packages/flutter_tools/bin/xcode_backend.dart | 81 +++- .../flutter_tools/lib/src/build_info.dart | 2 + .../lib/src/build_system/targets/common.dart | 12 + .../build_system/targets/native_assets.dart | 183 +++++++++ .../lib/src/commands/build_ios_framework.dart | 22 + .../src/commands/build_macos_framework.dart | 21 + .../lib/src/commands/create.dart | 92 ++++- .../lib/src/commands/create_base.dart | 5 +- packages/flutter_tools/lib/src/compile.dart | 44 +- packages/flutter_tools/lib/src/features.dart | 14 + .../lib/src/flutter_device_manager.dart | 1 - .../lib/src/flutter_features.dart | 3 + .../lib/src/flutter_plugins.dart | 2 +- .../lib/src/flutter_project_metadata.dart | 18 + .../lib/src/ios/native_assets.dart | 171 ++++++++ .../lib/src/macos/native_assets.dart | 162 ++++++++ .../lib/src/macos/native_assets_host.dart | 141 +++++++ .../flutter_tools/lib/src/native_assets.dart | 378 +++++++++++++++++ packages/flutter_tools/lib/src/run_hot.dart | 15 + .../lib/src/test/test_compiler.dart | 24 ++ .../lib/src/tester/flutter_tester.dart | 12 +- packages/flutter_tools/pubspec.yaml | 7 +- .../templates/app/lib/main.dart.tmpl | 8 +- .../module/common/test/widget_test.dart.tmpl | 4 +- .../templates/package_ffi/.gitignore.tmpl | 30 ++ .../templates/package_ffi/.metadata.tmpl | 10 + .../templates/package_ffi/CHANGELOG.md.tmpl | 3 + .../templates/package_ffi/LICENSE.tmpl | 1 + .../templates/package_ffi/README.md.tmpl | 49 +++ .../package_ffi/analysis_options.yaml.tmpl | 4 + .../templates/package_ffi/build.dart.tmpl | 24 ++ .../templates/package_ffi/ffigen.yaml.tmpl | 20 + .../package_ffi/lib/projectName.dart.tmpl | 108 +++++ .../projectName_bindings_generated.dart.tmpl | 30 ++ .../templates/package_ffi/pubspec.yaml.tmpl | 19 + .../package_ffi/src.tmpl/projectName.c.tmpl | 29 ++ .../package_ffi/src.tmpl/projectName.h.tmpl | 30 ++ .../test/projectName_test.dart.tmpl | 14 + .../templates/plugin_shared/.metadata.tmpl | 3 + .../templates/plugin_shared/pubspec.yaml.tmpl | 8 +- .../templates/template_manifest.json | 15 + .../hermetic/create_usage_test.dart | 31 ++ .../permeable/build_bundle_test.dart | 1 + .../commands.shard/permeable/create_test.dart | 90 ++-- .../build_system/targets/common_test.dart | 43 ++ .../targets/native_assets_test.dart | 140 +++++++ .../general.shard/compile_batch_test.dart | 51 +++ .../custom_devices/custom_device_test.dart | 1 + .../test/general.shard/devfs_test.dart | 13 +- .../fake_native_assets_build_runner.dart | 91 +++++ .../test/general.shard/features_test.dart | 8 + .../flutter_project_metadata_test.dart | 15 + .../test/general.shard/hot_test.dart | 145 ++++++- .../general.shard/ios/native_assets_test.dart | 274 +++++++++++++ .../macos/native_assets_test.dart | 385 ++++++++++++++++++ .../general.shard/preview_device_test.dart | 1 + .../general.shard/resident_runner_test.dart | 85 +++- .../resident_web_runner_test.dart | 1 + .../test/test_compiler_test.dart | 1 + .../tester/flutter_tester_test.dart | 2 - .../general.shard/web/devfs_web_test.dart | 1 + .../ios_content_validation_test.dart | 1 + .../integration.shard/native_assets_test.dart | 360 ++++++++++++++++ .../overall_experience_test.dart | 301 +------------- .../transition_test_utils.dart | 338 +++++++++++++++ packages/flutter_tools/test/src/fakes.dart | 6 + 74 files changed, 4134 insertions(+), 414 deletions(-) create mode 100644 dev/devicelab/bin/tasks/native_assets_ios.dart create mode 100644 dev/devicelab/bin/tasks/native_assets_ios_simulator.dart create mode 100644 dev/devicelab/lib/tasks/native_assets_test.dart create mode 100644 packages/flutter_tools/lib/src/build_system/targets/native_assets.dart create mode 100644 packages/flutter_tools/lib/src/ios/native_assets.dart create mode 100644 packages/flutter_tools/lib/src/macos/native_assets.dart create mode 100644 packages/flutter_tools/lib/src/macos/native_assets_host.dart create mode 100644 packages/flutter_tools/lib/src/native_assets.dart create mode 100644 packages/flutter_tools/templates/package_ffi/.gitignore.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/.metadata.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/CHANGELOG.md.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/LICENSE.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/README.md.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/analysis_options.yaml.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/build.dart.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/ffigen.yaml.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/lib/projectName.dart.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/lib/projectName_bindings_generated.dart.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.c.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.h.tmpl create mode 100644 packages/flutter_tools/templates/package_ffi/test/projectName_test.dart.tmpl create mode 100644 packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart create mode 100644 packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart create mode 100644 packages/flutter_tools/test/general.shard/ios/native_assets_test.dart create mode 100644 packages/flutter_tools/test/general.shard/macos/native_assets_test.dart create mode 100644 packages/flutter_tools/test/integration.shard/native_assets_test.dart create mode 100644 packages/flutter_tools/test/integration.shard/transition_test_utils.dart diff --git a/.ci.yaml b/.ci.yaml index ba31dfac1451b..07fd6f54df8ea 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4069,6 +4069,26 @@ targets: ["devicelab", "ios", "mac"] task_name: microbenchmarks_ios + - name: Mac_ios native_assets_ios_simulator + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true # TODO(dacoharkes): Set to false in follow up PR and check that test works on CI. + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: native_assets_ios_simulator + + - name: Mac_ios native_assets_ios + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true # TODO(dacoharkes): Set to false in follow up PR and check that test works on CI. + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: native_assets_ios + - name: Mac_ios native_platform_view_ui_tests_ios recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index 7da41d661c617..635215f523090 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -199,6 +199,8 @@ /dev/devicelab/bin/tasks/large_image_changer_perf_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/macos_chrome_dev_mode.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/microbenchmarks_ios.dart @cyanglaz @flutter/engine +/dev/devicelab/bin/tasks/native_assets_ios_simulator.dart @dacoharkes @flutter/ios +/dev/devicelab/bin/tasks/native_assets_ios.dart @dacoharkes @flutter/ios /dev/devicelab/bin/tasks/native_platform_view_ui_tests_ios.dart @hellohuanlin @flutter/ios /dev/devicelab/bin/tasks/new_gallery_ios__transition_perf.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/new_gallery_skia_ios__transition_perf.dart @zanderso @flutter/engine diff --git a/dev/devicelab/bin/tasks/module_test_ios.dart b/dev/devicelab/bin/tasks/module_test_ios.dart index a213bbee26fef..cd6218e451782 100644 --- a/dev/devicelab/bin/tasks/module_test_ios.dart +++ b/dev/devicelab/bin/tasks/module_test_ios.dart @@ -59,6 +59,36 @@ Future<void> main() async { final File marquee = File(path.join(flutterModuleLibSource.path, 'marquee')); marquee.copySync(path.join(flutterModuleLibDestination.path, 'marquee.dart')); + section('Create package with native assets'); + + await flutter( + 'config', + options: <String>['--enable-native-assets'], + ); + + const String ffiPackageName = 'ffi_package'; + await _createFfiPackage(ffiPackageName, tempDir); + + section('Add FFI package'); + + final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml')); + String content = await pubspec.readAsString(); + content = content.replaceFirst( + 'dependencies:\n', + ''' +dependencies: + $ffiPackageName: + path: ../$ffiPackageName +''', + ); + await pubspec.writeAsString(content, flush: true); + await inDirectory(projectDir, () async { + await flutter( + 'packages', + options: <String>['get'], + ); + }); + section('Build ephemeral host app in release mode without CocoaPods'); await inDirectory(projectDir, () async { @@ -162,10 +192,8 @@ Future<void> main() async { section('Add plugins'); - final File pubspec = File(path.join(projectDir.path, 'pubspec.yaml')); - String content = await pubspec.readAsString(); content = content.replaceFirst( - '\ndependencies:\n', + 'dependencies:\n', // One framework, one Dart-only, one that does not support iOS, and one with a resource bundle. ''' dependencies: @@ -221,6 +249,11 @@ dependencies: // Dart-only, no embedded framework. checkDirectoryNotExists(path.join(ephemeralIOSHostApp.path, 'Frameworks', '$dartPluginName.framework')); + // Native assets embedded, no embedded framework. + const String libFfiPackageDylib = 'lib$ffiPackageName.dylib'; + checkFileExists(path.join(ephemeralIOSHostApp.path, 'Frameworks', libFfiPackageDylib)); + checkDirectoryNotExists(path.join(ephemeralIOSHostApp.path, 'Frameworks', '$ffiPackageName.framework')); + section('Clean and pub get module'); await inDirectory(projectDir, () async { @@ -350,6 +383,11 @@ end 'isolate_snapshot_data', )); + checkFileExists(path.join( + hostFrameworksDirectory, + libFfiPackageDylib, + )); + section('Check the NOTICE file is correct'); final String licenseFilePath = path.join( @@ -449,6 +487,13 @@ end throw TaskResult.failure('Unexpected armv7 architecture slice in $builtAppBinary'); } + // Check native assets are bundled. + checkFileExists(path.join( + archivedAppPath, + 'Frameworks', + libFfiPackageDylib, + )); + // The host app example builds plugins statically, url_launcher_ios.framework // should not exist. checkDirectoryNotExists(path.join( @@ -685,3 +730,17 @@ class $dartPluginClass { // Remove the native plugin code. await Directory(path.join(pluginDir, 'ios')).delete(recursive: true); } + +Future<void> _createFfiPackage(String name, Directory parent) async { + await inDirectory(parent, () async { + await flutter( + 'create', + options: <String>[ + '--org', + 'io.flutter.devicelab', + '--template=package_ffi', + name, + ], + ); + }); +} diff --git a/dev/devicelab/bin/tasks/native_assets_ios.dart b/dev/devicelab/bin/tasks/native_assets_ios.dart new file mode 100644 index 0000000000000..9db75bf3c86e5 --- /dev/null +++ b/dev/devicelab/bin/tasks/native_assets_ios.dart @@ -0,0 +1,14 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/native_assets_test.dart'; + +Future<void> main() async { + await task(() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + return createNativeAssetsTest()(); + }); +} diff --git a/dev/devicelab/bin/tasks/native_assets_ios_simulator.dart b/dev/devicelab/bin/tasks/native_assets_ios_simulator.dart new file mode 100644 index 0000000000000..73579452434cf --- /dev/null +++ b/dev/devicelab/bin/tasks/native_assets_ios_simulator.dart @@ -0,0 +1,31 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/framework/ios.dart'; +import 'package:flutter_devicelab/framework/task_result.dart'; +import 'package:flutter_devicelab/tasks/native_assets_test.dart'; + +Future<void> main() async { + await task(() async { + deviceOperatingSystem = DeviceOperatingSystem.ios; + String? simulatorDeviceId; + try { + await testWithNewIOSSimulator( + 'TestNativeAssetsSim', + (String deviceId) async { + simulatorDeviceId = deviceId; + await createNativeAssetsTest( + deviceIdOverride: deviceId, + isIosSimulator: true, + )(); + }, + ); + } finally { + await removeIOSimulator(simulatorDeviceId); + } + return TaskResult.success(null); + }); +} diff --git a/dev/devicelab/lib/tasks/native_assets_test.dart b/dev/devicelab/lib/tasks/native_assets_test.dart new file mode 100644 index 0000000000000..7d93272e7eb4b --- /dev/null +++ b/dev/devicelab/lib/tasks/native_assets_test.dart @@ -0,0 +1,191 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:path/path.dart' as path; + +import '../framework/devices.dart'; +import '../framework/framework.dart'; +import '../framework/task_result.dart'; +import '../framework/utils.dart'; + +const String _packageName = 'package_with_native_assets'; + +const List<String> _buildModes = <String>[ + 'debug', + 'profile', + 'release', +]; + +TaskFunction createNativeAssetsTest({ + String? deviceIdOverride, + bool checkAppRunningOnLocalDevice = true, + bool isIosSimulator = false, +}) { + return () async { + if (deviceIdOverride == null) { + final Device device = await devices.workingDevice; + await device.unlock(); + deviceIdOverride = device.deviceId; + } + + await enableNativeAssets(); + + for (final String buildMode in _buildModes) { + if (buildMode != 'debug' && isIosSimulator) { + continue; + } + final TaskResult buildModeResult = await inTempDir((Directory tempDirectory) async { + final Directory packageDirectory = await createTestProject(_packageName, tempDirectory); + final Directory exampleDirectory = dir(packageDirectory.uri.resolve('example/').toFilePath()); + + final List<String> options = <String>[ + '-d', + deviceIdOverride!, + '--no-android-gradle-daemon', + '--no-publish-port', + '--verbose', + '--uninstall-first', + '--$buildMode', + ]; + int transitionCount = 0; + bool done = false; + + await inDirectory<void>(exampleDirectory, () async { + final int runFlutterResult = await runFlutter( + options: options, + onLine: (String line, Process process) { + if (done) { + return; + } + switch (transitionCount) { + case 0: + if (!line.contains('Flutter run key commands.')) { + return; + } + if (buildMode == 'debug') { + // Do a hot reload diff on the initial dill file. + process.stdin.writeln('r'); + } else { + done = true; + process.stdin.writeln('q'); + } + case 1: + if (!line.contains('Reloaded')) { + return; + } + process.stdin.writeln('R'); + case 2: + // Do a hot restart, pushing a new complete dill file. + if (!line.contains('Restarted application')) { + return; + } + // Do another hot reload, pushing a diff to the second dill file. + process.stdin.writeln('r'); + case 3: + if (!line.contains('Reloaded')) { + return; + } + done = true; + process.stdin.writeln('q'); + } + transitionCount += 1; + }, + ); + if (runFlutterResult != 0) { + print('Flutter run returned non-zero exit code: $runFlutterResult.'); + } + }); + + final int expectedNumberOfTransitions = buildMode == 'debug' ? 4 : 1; + if (transitionCount != expectedNumberOfTransitions) { + return TaskResult.failure( + 'Did not get expected number of transitions: $transitionCount ' + '(expected $expectedNumberOfTransitions)', + ); + } + return TaskResult.success(null); + }); + if (buildModeResult.failed) { + return buildModeResult; + } + } + return TaskResult.success(null); + }; +} + +Future<int> runFlutter({ + required List<String> options, + required void Function(String, Process) onLine, +}) async { + final Process process = await startFlutter( + 'run', + options: options, + ); + + final Completer<void> stdoutDone = Completer<void>(); + final Completer<void> stderrDone = Completer<void>(); + process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen((String line) { + onLine(line, process); + print('stdout: $line'); + }, onDone: stdoutDone.complete); + + process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen( + (String line) => print('stderr: $line'), + onDone: stderrDone.complete, + ); + + await Future.wait<void>(<Future<void>>[stdoutDone.future, stderrDone.future]); + final int exitCode = await process.exitCode; + return exitCode; +} + +final String _flutterBin = path.join(flutterDirectory.path, 'bin', 'flutter'); + +Future<void> enableNativeAssets() async { + print('Enabling configs for native assets...'); + final int configResult = await exec( + _flutterBin, + <String>[ + 'config', + '-v', + '--enable-native-assets', + ], + canFail: true); + if (configResult != 0) { + print('Failed to enable configuration, tasks may not run.'); + } +} + +Future<Directory> createTestProject( + String packageName, + Directory tempDirectory, +) async { + final int createResult = await exec( + _flutterBin, + <String>[ + 'create', + '--template=package_ffi', + packageName, + ], + workingDirectory: tempDirectory.path, + canFail: true, + ); + assert(createResult == 0); + + final Directory packageDirectory = Directory.fromUri(tempDirectory.uri.resolve('$packageName/')); + return packageDirectory; +} + +Future<T> inTempDir<T>(Future<T> Function(Directory tempDirectory) fun) async { + final Directory tempDirectory = dir(Directory.systemTemp.createTempSync().resolveSymbolicLinksSync()); + try { + return await fun(tempDirectory); + } finally { + tempDirectory.deleteSync(recursive: true); + } +} diff --git a/dev/integration_tests/ios_host_app/flutterapp/lib/main b/dev/integration_tests/ios_host_app/flutterapp/lib/main index 2f5c09d11b734..78ea99b18b875 100644 --- a/dev/integration_tests/ios_host_app/flutterapp/lib/main +++ b/dev/integration_tests/ios_host_app/flutterapp/lib/main @@ -7,6 +7,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:ffi_package/ffi_package.dart'; import 'marquee.dart'; @@ -116,10 +117,15 @@ class _MyHomePageState extends State<MyHomePage> { // button on the Flutter page has been tapped. int _counter = 0; + late int sumResult; + late Future<int> sumAsyncResult; + @override void initState() { super.initState(); _platform.setMessageHandler(_handlePlatformIncrement); + sumResult = sum(1, 2); + sumAsyncResult = sumAsync(3, 4); } /// Directly increments our internal counter and rebuilds the UI. diff --git a/packages/flutter_tools/bin/macos_assemble.sh b/packages/flutter_tools/bin/macos_assemble.sh index 50f85fd227c4e..3f21624e7c964 100755 --- a/packages/flutter_tools/bin/macos_assemble.sh +++ b/packages/flutter_tools/bin/macos_assemble.sh @@ -144,8 +144,8 @@ BuildApp() { RunCommand "${flutter_args[@]}" } -# Adds the App.framework as an embedded binary and the flutter_assets as -# resources. +# Adds the App.framework as an embedded binary, the flutter_assets as +# resources, and the native assets. EmbedFrameworks() { # Embed App.framework from Flutter into the app (after creating the Frameworks directory # if it doesn't already exist). @@ -164,6 +164,17 @@ EmbedFrameworks() { RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/App.framework/App" RunCommand codesign --force --verbose --sign "${EXPANDED_CODE_SIGN_IDENTITY}" -- "${xcode_frameworks_dir}/FlutterMacOS.framework/FlutterMacOS" fi + + # Copy the native assets. These do not have to be codesigned here because, + # they are already codesigned in buildNativeAssetsMacOS. + local project_path="${SOURCE_ROOT}/.." + if [[ -n "$FLUTTER_APPLICATION_PATH" ]]; then + project_path="${FLUTTER_APPLICATION_PATH}" + fi + local native_assets_path="${project_path}/${FLUTTER_BUILD_DIR}/native_assets/macos/" + if [[ -d "$native_assets_path" ]]; then + RunCommand rsync -av --filter "- .DS_Store" --filter "- native_assets.yaml" "${native_assets_path}" "${xcode_frameworks_dir}" + fi } # Main entry point. diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index 15da6b525ed47..87d1c22313a5f 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -171,6 +171,32 @@ class Context { exitApp(-1); } + /// Copies all files from [source] to [destination]. + /// + /// Does not copy `.DS_Store`. + /// + /// If [delete], delete extraneous files from [destination]. + void runRsync( + String source, + String destination, { + List<String> extraArgs = const <String>[], + bool delete = false, + }) { + runSync( + 'rsync', + <String>[ + '-8', // Avoid mangling filenames with encodings that do not match the current locale. + '-av', + if (delete) '--delete', + '--filter', + '- .DS_Store', + ...extraArgs, + source, + destination, + ], + ); + } + // Adds the App.framework as an embedded binary and the flutter_assets as // resources. void embedFlutterFrameworks() { @@ -185,33 +211,46 @@ class Context { xcodeFrameworksDir, ] ); - runSync( - 'rsync', - <String>[ - '-8', // Avoid mangling filenames with encodings that do not match the current locale. - '-av', - '--delete', - '--filter', - '- .DS_Store', - '${environment['BUILT_PRODUCTS_DIR']}/App.framework', - xcodeFrameworksDir, - ], + runRsync( + delete: true, + '${environment['BUILT_PRODUCTS_DIR']}/App.framework', + xcodeFrameworksDir, ); // Embed the actual Flutter.framework that the Flutter app expects to run against, // which could be a local build or an arch/type specific build. - runSync( - 'rsync', - <String>[ - '-av', - '--delete', - '--filter', - '- .DS_Store', - '${environment['BUILT_PRODUCTS_DIR']}/Flutter.framework', - '$xcodeFrameworksDir/', - ], + runRsync( + delete: true, + '${environment['BUILT_PRODUCTS_DIR']}/Flutter.framework', + '$xcodeFrameworksDir/', ); + // Copy the native assets. These do not have to be codesigned here because, + // they are already codesigned in buildNativeAssetsMacOS. + final String sourceRoot = environment['SOURCE_ROOT'] ?? ''; + String projectPath = '$sourceRoot/..'; + if (environment['FLUTTER_APPLICATION_PATH'] != null) { + projectPath = environment['FLUTTER_APPLICATION_PATH']!; + } + final String flutterBuildDir = environment['FLUTTER_BUILD_DIR']!; + final String nativeAssetsPath = '$projectPath/$flutterBuildDir/native_assets/ios/'; + final bool verbose = (environment['VERBOSE_SCRIPT_LOGGING'] ?? '').isNotEmpty; + if (Directory(nativeAssetsPath).existsSync()) { + if (verbose) { + print('♦ Copying native assets from $nativeAssetsPath.'); + } + runRsync( + extraArgs: <String>[ + '--filter', + '- native_assets.yaml', + ], + nativeAssetsPath, + xcodeFrameworksDir, + ); + } else if (verbose) { + print("♦ No native assets to bundle. $nativeAssetsPath doesn't exist."); + } + addVmServiceBonjourService(); } diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 7c3455d116341..fea9da5c415fc 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -777,6 +777,8 @@ TargetPlatform getTargetPlatformForName(String platform) { return TargetPlatform.windows_x64; case 'web-javascript': return TargetPlatform.web_javascript; + case 'flutter-tester': + return TargetPlatform.tester; } throw Exception('Unsupported platform name "$platform"'); } diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 039bb5a7fdd6f..951febd5b477c 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -6,6 +6,7 @@ import 'package:package_config/package_config.dart'; import '../../artifacts.dart'; import '../../base/build.dart'; +import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; @@ -19,6 +20,7 @@ import 'assets.dart'; import 'dart_plugin_registrant.dart'; import 'icon_tree_shaker.dart'; import 'localizations.dart'; +import 'native_assets.dart'; import 'shader_compiler.dart'; /// Copies the pre-built flutter bundle. @@ -125,6 +127,7 @@ class KernelSnapshot extends Target { @override List<Source> get inputs => const <Source>[ + Source.pattern('{BUILD_DIR}/native_assets.yaml'), Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'), Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), Source.artifact(Artifact.platformKernelDill), @@ -142,6 +145,7 @@ class KernelSnapshot extends Target { @override List<Target> get dependencies => const <Target>[ + NativeAssets(), GenerateLocalizationsTarget(), DartPluginRegistrantTarget(), ]; @@ -178,6 +182,13 @@ class KernelSnapshot extends Target { final List<String>? fileSystemRoots = environment.defines[kFileSystemRoots]?.split(','); final String? fileSystemScheme = environment.defines[kFileSystemScheme]; + final File nativeAssetsFile = environment.buildDir.childFile('native_assets.yaml'); + final String nativeAssets = nativeAssetsFile.path; + if (!await nativeAssetsFile.exists()) { + throwToolExit("$nativeAssets doesn't exist."); + } + environment.logger.printTrace('Embedding native assets mapping $nativeAssets in kernel.'); + TargetModel targetModel = TargetModel.flutter; if (targetPlatform == TargetPlatform.fuchsia_x64 || targetPlatform == TargetPlatform.fuchsia_arm64) { @@ -251,6 +262,7 @@ class KernelSnapshot extends Target { buildDir: environment.buildDir, targetOS: targetOS, checkDartPluginRegistry: environment.generateDartPluginRegistry, + nativeAssets: nativeAssets, ); if (output == null || output.errorCount != 0) { throw Exception(); diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart new file mode 100644 index 0000000000000..073b5863833dc --- /dev/null +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -0,0 +1,183 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' show Asset; + +import '../../base/common.dart'; +import '../../base/file_system.dart'; +import '../../base/platform.dart'; +import '../../build_info.dart'; +import '../../ios/native_assets.dart'; +import '../../macos/native_assets.dart'; +import '../../macos/xcode.dart'; +import '../../native_assets.dart'; +import '../build_system.dart'; +import '../depfile.dart'; +import '../exceptions.dart'; +import 'common.dart'; + +/// Builds the right native assets for a Flutter app. +/// +/// The build mode and target architecture can be changed from the +/// native build project (Xcode etc.), so only `flutter assemble` has the +/// information about build-mode and target architecture. +/// Invocations of flutter_tools other than `flutter assemble` are dry runs. +/// +/// This step needs to be consistent with the dry run invocations in `flutter +/// run`s so that the kernel mapping of asset id to dylib lines up after hot +/// restart. +/// +/// [KernelSnapshot] depends on this target. We produce a native_assets.yaml +/// here, and embed that mapping inside the kernel snapshot. +/// +/// The build always produces a valid native_assets.yaml and a native_assets.d +/// even if there are no native assets. This way the caching logic won't try to +/// rebuild. +class NativeAssets extends Target { + const NativeAssets({ + @visibleForTesting NativeAssetsBuildRunner? buildRunner, + }) : _buildRunner = buildRunner; + + final NativeAssetsBuildRunner? _buildRunner; + + @override + Future<void> build(Environment environment) async { + final String? targetPlatformEnvironment = environment.defines[kTargetPlatform]; + if (targetPlatformEnvironment == null) { + throw MissingDefineException(kTargetPlatform, name); + } + final TargetPlatform targetPlatform = getTargetPlatformForName(targetPlatformEnvironment); + + final Uri projectUri = environment.projectDir.uri; + final FileSystem fileSystem = environment.fileSystem; + final NativeAssetsBuildRunner buildRunner = _buildRunner ?? NativeAssetsBuildRunnerImpl(projectUri, fileSystem, environment.logger); + + final List<Uri> dependencies; + switch (targetPlatform) { + case TargetPlatform.ios: + final String? iosArchsEnvironment = environment.defines[kIosArchs]; + if (iosArchsEnvironment == null) { + throw MissingDefineException(kIosArchs, name); + } + final List<DarwinArch> iosArchs = iosArchsEnvironment.split(' ').map(getDarwinArchForName).toList(); + final String? environmentBuildMode = environment.defines[kBuildMode]; + if (environmentBuildMode == null) { + throw MissingDefineException(kBuildMode, name); + } + final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); + final String? sdkRoot = environment.defines[kSdkRoot]; + if (sdkRoot == null) { + throw MissingDefineException(kSdkRoot, name); + } + final EnvironmentType environmentType = environmentTypeFromSdkroot(sdkRoot, environment.fileSystem)!; + dependencies = await buildNativeAssetsIOS( + environmentType: environmentType, + darwinArchs: iosArchs, + buildMode: buildMode, + projectUri: projectUri, + codesignIdentity: environment.defines[kCodesignIdentity], + fileSystem: fileSystem, + buildRunner: buildRunner, + yamlParentDirectory: environment.buildDir.uri, + ); + case TargetPlatform.darwin: + final String? darwinArchsEnvironment = environment.defines[kDarwinArchs]; + if (darwinArchsEnvironment == null) { + throw MissingDefineException(kDarwinArchs, name); + } + final List<DarwinArch> darwinArchs = darwinArchsEnvironment.split(' ').map(getDarwinArchForName).toList(); + final String? environmentBuildMode = environment.defines[kBuildMode]; + if (environmentBuildMode == null) { + throw MissingDefineException(kBuildMode, name); + } + final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); + (_, dependencies) = await buildNativeAssetsMacOS( + darwinArchs: darwinArchs, + buildMode: buildMode, + projectUri: projectUri, + codesignIdentity: environment.defines[kCodesignIdentity], + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); + case TargetPlatform.tester: + if (const LocalPlatform().isMacOS) { + (_, dependencies) = await buildNativeAssetsMacOS( + buildMode: BuildMode.debug, + projectUri: projectUri, + codesignIdentity: environment.defines[kCodesignIdentity], + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + flutterTester: true, + ); + } else { + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + // Write the file we claim to have in the [outputs]. + await writeNativeAssetsYaml(<Asset>[], environment.buildDir.uri, fileSystem); + dependencies = <Uri>[]; + } + case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: + case TargetPlatform.android_x64: + case TargetPlatform.android_x86: + case TargetPlatform.android: + case TargetPlatform.fuchsia_arm64: + case TargetPlatform.fuchsia_x64: + case TargetPlatform.linux_arm64: + case TargetPlatform.linux_x64: + case TargetPlatform.web_javascript: + case TargetPlatform.windows_x64: + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + // Write the file we claim to have in the [outputs]. + await writeNativeAssetsYaml(<Asset>[], environment.buildDir.uri, fileSystem); + dependencies = <Uri>[]; + } + + final File nativeAssetsFile = environment.buildDir.childFile('native_assets.yaml'); + final Depfile depfile = Depfile( + <File>[ + for (final Uri dependency in dependencies) fileSystem.file(dependency), + ], + <File>[ + nativeAssetsFile, + ], + ); + final File outputDepfile = environment.buildDir.childFile('native_assets.d'); + if (!outputDepfile.parent.existsSync()) { + outputDepfile.parent.createSync(recursive: true); + } + environment.depFileService.writeToFile(depfile, outputDepfile); + if (!await nativeAssetsFile.exists()) { + throwToolExit("${nativeAssetsFile.path} doesn't exist."); + } + if (!await outputDepfile.exists()) { + throwToolExit("${outputDepfile.path} doesn't exist."); + } + } + + @override + List<String> get depfiles => <String>[ + 'native_assets.d', + ]; + + @override + List<Target> get dependencies => <Target>[]; + + @override + List<Source> get inputs => const <Source>[ + Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart'), + // If different packages are resolved, different native assets might need to be built. + Source.pattern('{PROJECT_DIR}/.dart_tool/package_config_subset'), + ]; + + @override + String get name => 'native_assets'; + + @override + List<Source> get outputs => const <Source>[ + Source.pattern('{BUILD_DIR}/native_assets.yaml'), + ]; +} diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index ea3c50bbfa9c1..66eea554289b6 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -270,6 +270,28 @@ class BuildIOSFrameworkCommand extends BuildFrameworkCommand { final Status status = globals.logger.startProgress( ' └─Moving to ${globals.fs.path.relative(modeDirectory.path)}'); + + // Copy the native assets. The native assets have already been signed in + // buildNativeAssetsMacOS. + final Directory nativeAssetsDirectory = globals.fs + .directory(getBuildDirectory()) + .childDirectory('native_assets/ios/'); + if (await nativeAssetsDirectory.exists()) { + final ProcessResult rsyncResult = await globals.processManager.run(<Object>[ + 'rsync', + '-av', + '--filter', + '- .DS_Store', + '--filter', + '- native_assets.yaml', + nativeAssetsDirectory.path, + modeDirectory.path, + ]); + if (rsyncResult.exitCode != 0) { + throwToolExit('Failed to copy native assets:\n${rsyncResult.stderr}'); + } + } + try { // Delete the intermediaries since they would have been copied into our // output frameworks. diff --git a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart index 77a02511dc01b..19c1e17ed505f 100644 --- a/packages/flutter_tools/lib/src/commands/build_macos_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_macos_framework.dart @@ -6,6 +6,7 @@ import 'package:meta/meta.dart'; import '../base/common.dart'; import '../base/file_system.dart'; +import '../base/io.dart'; import '../base/logger.dart'; import '../base/process.dart'; import '../base/utils.dart'; @@ -96,6 +97,26 @@ class BuildMacOSFrameworkCommand extends BuildFrameworkCommand { globals.logger.printStatus(' └─Moving to ${globals.fs.path.relative(modeDirectory.path)}'); + // Copy the native assets. + final Directory nativeAssetsDirectory = globals.fs + .directory(getBuildDirectory()) + .childDirectory('native_assets/macos/'); + if (await nativeAssetsDirectory.exists()) { + final ProcessResult rsyncResult = await globals.processManager.run(<Object>[ + 'rsync', + '-av', + '--filter', + '- .DS_Store', + '--filter', + '- native_assets.yaml', + nativeAssetsDirectory.path, + modeDirectory.path, + ]); + if (rsyncResult.exitCode != 0) { + throwToolExit('Failed to copy native assets:\n${rsyncResult.stderr}'); + } + } + // Delete the intermediaries since they would have been copied into our // output frameworks. if (buildOutput.existsSync()) { diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 66a9e1127e600..0c6ca3a02cda6 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -36,10 +36,11 @@ class CreateCommand extends CreateBase { argParser.addOption( 'template', abbr: 't', - allowed: FlutterProjectType.values.map<String>((FlutterProjectType e) => e.cliName), + allowed: FlutterProjectType.enabledValues + .map<String>((FlutterProjectType e) => e.cliName), help: 'Specify the type of project to create.', valueHelp: 'type', - allowedHelp: CliEnum.allowedHelp(FlutterProjectType.values), + allowedHelp: CliEnum.allowedHelp(FlutterProjectType.enabledValues), ); argParser.addOption( 'sample', @@ -206,12 +207,14 @@ class CreateCommand extends CreateBase { final FlutterProjectType template = _getProjectType(projectDir); final bool generateModule = template == FlutterProjectType.module; final bool generateMethodChannelsPlugin = template == FlutterProjectType.plugin; + final bool generateFfiPackage = template == FlutterProjectType.packageFfi; final bool generateFfiPlugin = template == FlutterProjectType.pluginFfi; + final bool generateFfi = generateFfiPlugin || generateFfiPackage; final bool generatePackage = template == FlutterProjectType.package; final List<String> platforms = stringsArg('platforms'); // `--platforms` does not support module or package. - if (argResults!.wasParsed('platforms') && (generateModule || generatePackage)) { + if (argResults!.wasParsed('platforms') && (generateModule || generatePackage || generateFfiPackage)) { final String template = generateModule ? 'module' : 'package'; throwToolExit( 'The "--platforms" argument is not supported in $template template.', @@ -225,15 +228,15 @@ class CreateCommand extends CreateBase { 'The web platform is not supported in plugin_ffi template.', exitCode: 2, ); - } else if (generateFfiPlugin && argResults!.wasParsed('ios-language')) { + } else if (generateFfi && argResults!.wasParsed('ios-language')) { throwToolExit( - 'The "ios-language" option is not supported with the plugin_ffi ' + 'The "ios-language" option is not supported with the ${template.cliName} ' 'template: the language will always be C or C++.', exitCode: 2, ); - } else if (generateFfiPlugin && argResults!.wasParsed('android-language')) { + } else if (generateFfi && argResults!.wasParsed('android-language')) { throwToolExit( - 'The "android-language" option is not supported with the plugin_ffi ' + 'The "android-language" option is not supported with the ${template.cliName} ' 'template: the language will always be C or C++.', exitCode: 2, ); @@ -306,6 +309,7 @@ class CreateCommand extends CreateBase { flutterRoot: flutterRoot, withPlatformChannelPluginHook: generateMethodChannelsPlugin, withFfiPluginHook: generateFfiPlugin, + withFfiPackage: generateFfiPackage, withEmptyMain: emptyArgument, androidLanguage: stringArg('android-language'), iosLanguage: stringArg('ios-language'), @@ -393,6 +397,15 @@ class CreateCommand extends CreateBase { projectType: template, ); pubContext = PubContext.createPlugin; + case FlutterProjectType.packageFfi: + generatedFileCount += await _generateFfiPackage( + relativeDir, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: !creatingNewProject, + projectType: template, + ); + pubContext = PubContext.createPackage; } if (boolArg('pub')) { @@ -403,14 +416,21 @@ class CreateCommand extends CreateBase { offline: boolArg('offline'), outputMode: PubOutputMode.summaryOnly, ); - await project.ensureReadyForPlatformSpecificTooling( - androidPlatform: includeAndroid, - iosPlatform: includeIos, - linuxPlatform: includeLinux, - macOSPlatform: includeMacos, - windowsPlatform: includeWindows, - webPlatform: includeWeb, - ); + // Setting `includeIos` etc to false as with FlutterProjectType.package + // causes the example sub directory to not get os sub directories. + // This will lead to `flutter build ios` to fail in the example. + // TODO(dacoharkes): Uncouple the app and parent project platforms. https://github.com/flutter/flutter/issues/133874 + // Then this if can be removed. + if (!generateFfiPackage) { + await project.ensureReadyForPlatformSpecificTooling( + androidPlatform: includeAndroid, + iosPlatform: includeIos, + linuxPlatform: includeLinux, + macOSPlatform: includeMacos, + windowsPlatform: includeWindows, + webPlatform: includeWeb, + ); + } } if (sampleCode != null) { _applySample(relativeDir, sampleCode); @@ -663,6 +683,48 @@ Your $application code is in $relativeAppMain. return generatedCount; } + Future<int> _generateFfiPackage( + Directory directory, + Map<String, Object?> templateContext, { + bool overwrite = false, + bool printStatusWhenWriting = true, + required FlutterProjectType projectType, + }) async { + int generatedCount = 0; + final String? description = argResults!.wasParsed('description') + ? stringArg('description') + : 'A new Dart FFI package project.'; + templateContext['description'] = description; + generatedCount += await renderMerged( + <String>[ + 'package_ffi', + ], + directory, + templateContext, + overwrite: overwrite, + printStatusWhenWriting: printStatusWhenWriting, + ); + + final FlutterProject project = FlutterProject.fromDirectory(directory); + + final String? projectName = templateContext['projectName'] as String?; + final String exampleProjectName = '${projectName}_example'; + templateContext['projectName'] = exampleProjectName; + templateContext['description'] = 'Demonstrates how to use the $projectName package.'; + templateContext['pluginProjectName'] = projectName; + + generatedCount += await generateApp( + <String>['app'], + project.example.directory, + templateContext, + overwrite: overwrite, + pluginExampleApp: true, + printStatusWhenWriting: printStatusWhenWriting, + projectType: projectType, + ); + return generatedCount; + } + // Takes an application template and replaces the main.dart with one from the // documentation website in sampleCode. Returns the difference in the number // of files after applying the sample, since it also deletes the application's diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index 4f801acc9b72b..2ad3f6b7a5d10 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -352,6 +352,7 @@ abstract class CreateBase extends FlutterCommand { String? gradleVersion, bool withPlatformChannelPluginHook = false, bool withFfiPluginHook = false, + bool withFfiPackage = false, bool withEmptyMain = false, bool ios = false, bool android = false, @@ -399,9 +400,11 @@ abstract class CreateBase extends FlutterCommand { 'pluginClassCapitalSnakeCase': pluginClassCapitalSnakeCase, 'pluginDartClass': pluginDartClass, 'pluginProjectUUID': const Uuid().v4().toUpperCase(), + 'withFfi': withFfiPluginHook || withFfiPackage, + 'withFfiPackage': withFfiPackage, 'withFfiPluginHook': withFfiPluginHook, 'withPlatformChannelPluginHook': withPlatformChannelPluginHook, - 'withPluginHook': withFfiPluginHook || withPlatformChannelPluginHook, + 'withPluginHook': withFfiPluginHook || withFfiPackage || withPlatformChannelPluginHook, 'withEmptyMain': withEmptyMain, 'androidLanguage': androidLanguage, 'iosLanguage': iosLanguage, diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index 1329c9fcd1a18..8ba7d1e89f39c 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -240,6 +240,7 @@ class KernelCompiler { required bool trackWidgetCreation, required List<String> dartDefines, required PackageConfig packageConfig, + String? nativeAssets, }) async { final TargetPlatform? platform = targetModel == TargetModel.dartdevc ? TargetPlatform.web_javascript : null; final String frontendServer = _artifacts.getArtifactPath( @@ -337,6 +338,10 @@ class KernelCompiler { 'package:flutter/src/dart_plugin_registrant.dart', '-Dflutter.dart_plugin_registrant=$dartPluginRegistrantUri', ], + if (nativeAssets != null) ...<String>[ + '--native-assets', + nativeAssets, + ], // See: https://github.com/flutter/flutter/issues/103994 '--verbosity=error', ...?extraFrontEndOptions, @@ -381,9 +386,10 @@ class _RecompileRequest extends _CompilationRequest { this.invalidatedFiles, this.outputPath, this.packageConfig, - this.suppressErrors, - {this.additionalSourceUri} - ); + this.suppressErrors, { + this.additionalSourceUri, + this.nativeAssetsYamlUri, + }); Uri mainUri; List<Uri>? invalidatedFiles; @@ -391,6 +397,7 @@ class _RecompileRequest extends _CompilationRequest { PackageConfig packageConfig; bool suppressErrors; final Uri? additionalSourceUri; + final Uri? nativeAssetsYamlUri; @override Future<CompilerOutput?> _run(DefaultResidentCompiler compiler) async => @@ -515,6 +522,7 @@ abstract class ResidentCompiler { bool suppressErrors = false, bool checkDartPluginRegistry = false, File? dartPluginRegistrant, + Uri? nativeAssetsYaml, }); Future<CompilerOutput?> compileExpression( @@ -663,6 +671,7 @@ class DefaultResidentCompiler implements ResidentCompiler { File? dartPluginRegistrant, String? projectRootPath, FileSystem? fs, + Uri? nativeAssetsYaml, }) async { if (!_controller.hasListener) { _controller.stream.listen(_handleCompilationRequest); @@ -681,6 +690,7 @@ class DefaultResidentCompiler implements ResidentCompiler { packageConfig, suppressErrors, additionalSourceUri: additionalSourceUri, + nativeAssetsYamlUri: nativeAssetsYaml, )); return completer.future; } @@ -699,12 +709,22 @@ class DefaultResidentCompiler implements ResidentCompiler { toMultiRootPath(request.additionalSourceUri!, fileSystemScheme, fileSystemRoots, _platform.isWindows); } + final String? nativeAssets = request.nativeAssetsYamlUri?.toString(); final Process? server = _server; if (server == null) { - return _compile(mainUri, request.outputPath, additionalSourceUri: additionalSourceUri); + return _compile( + mainUri, + request.outputPath, + additionalSourceUri: additionalSourceUri, + nativeAssetsUri: nativeAssets, + ); } final String inputKey = Uuid().generateV4(); + if (nativeAssets != null && nativeAssets.isNotEmpty) { + server.stdin.writeln('native-assets $nativeAssets'); + _logger.printTrace('<- native-assets $nativeAssets'); + } server.stdin.writeln('recompile $mainUri $inputKey'); _logger.printTrace('<- recompile $mainUri $inputKey'); final List<Uri>? invalidatedFiles = request.invalidatedFiles; @@ -746,9 +766,10 @@ class DefaultResidentCompiler implements ResidentCompiler { Future<CompilerOutput?> _compile( String scriptUri, - String? outputPath, - {String? additionalSourceUri} - ) async { + String? outputPath, { + String? additionalSourceUri, + String? nativeAssetsUri, + }) async { final TargetPlatform? platform = (targetModel == TargetModel.dartdevc) ? TargetPlatform.web_javascript : null; final String frontendServer = artifacts.getArtifactPath( Artifact.frontendServerSnapshotForEngineDartSdk, @@ -806,6 +827,10 @@ class DefaultResidentCompiler implements ResidentCompiler { 'package:flutter/src/dart_plugin_registrant.dart', '-Dflutter.dart_plugin_registrant=$additionalSourceUri', ], + if (nativeAssetsUri != null) ...<String>[ + '--native-assets', + nativeAssetsUri, + ], if (platformDill != null) ...<String>[ '--platform', platformDill!, @@ -842,6 +867,11 @@ class DefaultResidentCompiler implements ResidentCompiler { } })); + if (nativeAssetsUri != null && nativeAssetsUri.isNotEmpty) { + _server?.stdin.writeln('native-assets $nativeAssetsUri'); + _logger.printTrace('<- native-assets $nativeAssetsUri'); + } + _server?.stdin.writeln('compile $scriptUri'); _logger.printTrace('<- compile $scriptUri'); diff --git a/packages/flutter_tools/lib/src/features.dart b/packages/flutter_tools/lib/src/features.dart index 1e9c303eef188..284416992133b 100644 --- a/packages/flutter_tools/lib/src/features.dart +++ b/packages/flutter_tools/lib/src/features.dart @@ -50,6 +50,9 @@ abstract class FeatureFlags { /// Whether animations are used in the command line interface. bool get isCliAnimationEnabled => true; + /// Whether native assets compilation and bundling is enabled. + bool get isNativeAssetsEnabled => false; + /// Whether a particular feature is enabled for the current channel. /// /// Prefer using one of the specific getters above instead of this API. @@ -68,6 +71,7 @@ const List<Feature> allFeatures = <Feature>[ flutterCustomDevicesFeature, flutterWebWasm, cliAnimation, + nativeAssets, ]; /// All current Flutter feature flags that can be configured. @@ -158,6 +162,16 @@ const Feature cliAnimation = Feature.fullyEnabled( configSetting: 'cli-animations', ); +/// Enable native assets compilation and bundling. +const Feature nativeAssets = Feature( + name: 'native assets compilation and bundling', + configSetting: 'enable-native-assets', + environmentOverride: 'FLUTTER_NATIVE_ASSETS', + master: FeatureChannelSetting( + available: true, + ), +); + /// A [Feature] is a process for conditionally enabling tool features. /// /// All settings are optional, and if not provided will generally default to diff --git a/packages/flutter_tools/lib/src/flutter_device_manager.dart b/packages/flutter_tools/lib/src/flutter_device_manager.dart index 47411190ca349..dc98b4a7d0dcb 100644 --- a/packages/flutter_tools/lib/src/flutter_device_manager.dart +++ b/packages/flutter_tools/lib/src/flutter_device_manager.dart @@ -87,7 +87,6 @@ class FlutterDeviceManager extends DeviceManager { processManager: processManager, logger: logger, artifacts: artifacts, - operatingSystemUtils: operatingSystemUtils, ), MacOSDevices( processManager: processManager, diff --git a/packages/flutter_tools/lib/src/flutter_features.dart b/packages/flutter_tools/lib/src/flutter_features.dart index 1f6de014e6f2e..1418e90009631 100644 --- a/packages/flutter_tools/lib/src/flutter_features.dart +++ b/packages/flutter_tools/lib/src/flutter_features.dart @@ -55,6 +55,9 @@ class FlutterFeatureFlags implements FeatureFlags { return isEnabled(cliAnimation); } + @override + bool get isNativeAssetsEnabled => isEnabled(nativeAssets); + @override bool isEnabled(Feature feature) { final String currentChannel = _flutterVersion.channel; diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 27fa5d611a2c8..50f14c0644091 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -970,7 +970,7 @@ Future<void> _writeWebPluginRegistrant(FlutterProject project, List<Plugin> plug /// be created only if missing. /// /// This uses [project.flutterPluginsDependenciesFile], so it should only be -/// run after refreshPluginList has been run since the last plugin change. +/// run after [refreshPluginsList] has been run since the last plugin change. void createPluginSymlinks(FlutterProject project, {bool force = false, @visibleForTesting FeatureFlags? featureFlagsOverride}) { final FeatureFlags localFeatureFlags = featureFlagsOverride ?? featureFlags; Map<String, Object?>? platformPlugins; diff --git a/packages/flutter_tools/lib/src/flutter_project_metadata.dart b/packages/flutter_tools/lib/src/flutter_project_metadata.dart index 708f79fd5c72a..c4c1e9146d1af 100644 --- a/packages/flutter_tools/lib/src/flutter_project_metadata.dart +++ b/packages/flutter_tools/lib/src/flutter_project_metadata.dart @@ -7,6 +7,7 @@ import 'package:yaml/yaml.dart'; import 'base/file_system.dart'; import 'base/logger.dart'; import 'base/utils.dart'; +import 'features.dart'; import 'project.dart'; import 'template.dart'; import 'version.dart'; @@ -28,6 +29,9 @@ enum FlutterProjectType implements CliEnum { /// components, only Dart. package, + /// This is a Dart package project with external builds for native components. + packageFfi, + /// This is a native plugin project. plugin, @@ -52,6 +56,10 @@ enum FlutterProjectType implements CliEnum { 'Generate a shareable Flutter project containing an API ' 'in Dart code with a platform-specific implementation through dart:ffi for Android, iOS, ' 'Linux, macOS, Windows, or any combination of these.', + FlutterProjectType.packageFfi => + 'Generate a shareable Dart/Flutter project containing an API ' + 'in Dart code with a platform-specific implementation through dart:ffi for Android, iOS, ' + 'Linux, macOS, and Windows.', FlutterProjectType.module => 'Generate a project to add a Flutter module to an existing Android or iOS application.', }; @@ -64,6 +72,16 @@ enum FlutterProjectType implements CliEnum { } return null; } + + static List<FlutterProjectType> get enabledValues { + return <FlutterProjectType>[ + for (final FlutterProjectType value in values) + if (value == FlutterProjectType.packageFfi) ...<FlutterProjectType>[ + if (featureFlags.isNativeAssetsEnabled) value + ] else + value, + ]; + } } /// Verifies the expected yaml keys are present in the file. diff --git a/packages/flutter_tools/lib/src/ios/native_assets.dart b/packages/flutter_tools/lib/src/ios/native_assets.dart new file mode 100644 index 0000000000000..3e2d595fba494 --- /dev/null +++ b/packages/flutter_tools/lib/src/ios/native_assets.dart @@ -0,0 +1,171 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; + +import '../base/file_system.dart'; +import '../build_info.dart'; +import '../globals.dart' as globals; + +import '../macos/native_assets_host.dart'; +import '../native_assets.dart'; + +/// Dry run the native builds. +/// +/// This does not build native assets, it only simulates what the final paths +/// of all assets will be so that this can be embedded in the kernel file and +/// the Xcode project. +Future<Uri?> dryRunNativeAssetsIOS({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + required FileSystem fileSystem, +}) async { + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + return null; + } + + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.iOS); + final Iterable<Asset> assetTargetLocations = await dryRunNativeAssetsIOSInternal( + fileSystem, + projectUri, + buildRunner, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + assetTargetLocations, + buildUri_, + fileSystem, + ); + return nativeAssetsUri; +} + +Future<Iterable<Asset>> dryRunNativeAssetsIOSInternal( + FileSystem fileSystem, + Uri projectUri, + NativeAssetsBuildRunner buildRunner, +) async { + const OS targetOs = OS.iOS; + globals.logger.printTrace('Dry running native assets for $targetOs.'); + final List<Asset> nativeAssets = (await buildRunner.dryRun( + linkModePreference: LinkModePreference.dynamic, + targetOs: targetOs, + workingDirectory: projectUri, + includeParentEnvironment: true, + )) + .assets; + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Dry running native assets for $targetOs done.'); + final Iterable<Asset> assetTargetLocations = _assetTargetLocations(nativeAssets).values; + return assetTargetLocations; +} + +/// Builds native assets. +Future<List<Uri>> buildNativeAssetsIOS({ + required NativeAssetsBuildRunner buildRunner, + required List<DarwinArch> darwinArchs, + required EnvironmentType environmentType, + required Uri projectUri, + required BuildMode buildMode, + String? codesignIdentity, + required Uri yamlParentDirectory, + required FileSystem fileSystem, +}) async { + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory, fileSystem); + return <Uri>[]; + } + + final List<Target> targets = darwinArchs.map(_getNativeTarget).toList(); + final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); + + const OS targetOs = OS.iOS; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + final IOSSdk iosSdk = _getIOSSdk(environmentType); + + globals.logger.printTrace('Building native assets for $targets $buildModeCli.'); + final List<Asset> nativeAssets = <Asset>[]; + final Set<Uri> dependencies = <Uri>{}; + for (final Target target in targets) { + final BuildResult result = await buildRunner.build( + linkModePreference: LinkModePreference.dynamic, + target: target, + targetIOSSdk: iosSdk, + buildMode: buildModeCli, + workingDirectory: projectUri, + includeParentEnvironment: true, + cCompilerConfig: await buildRunner.cCompilerConfig, + ); + nativeAssets.addAll(result.assets); + dependencies.addAll(result.dependencies); + } + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Building native assets for $targets done.'); + final Map<AssetPath, List<Asset>> fatAssetTargetLocations = _fatAssetTargetLocations(nativeAssets); + await copyNativeAssetsMacOSHost( + buildUri_, + fatAssetTargetLocations, + codesignIdentity, + buildMode, + fileSystem, + ); + + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets); + await writeNativeAssetsYaml( + assetTargetLocations.values, + yamlParentDirectory, + fileSystem, + ); + return dependencies.toList(); +} + +IOSSdk _getIOSSdk(EnvironmentType environmentType) { + switch (environmentType) { + case EnvironmentType.physical: + return IOSSdk.iPhoneOs; + case EnvironmentType.simulator: + return IOSSdk.iPhoneSimulator; + } +} + +/// Extract the [Target] from a [DarwinArch]. +Target _getNativeTarget(DarwinArch darwinArch) { + switch (darwinArch) { + case DarwinArch.armv7: + return Target.iOSArm; + case DarwinArch.arm64: + return Target.iOSArm64; + case DarwinArch.x86_64: + return Target.iOSX64; + } +} + +Map<AssetPath, List<Asset>> _fatAssetTargetLocations(List<Asset> nativeAssets) { + final Map<AssetPath, List<Asset>> result = <AssetPath, List<Asset>>{}; + for (final Asset asset in nativeAssets) { + final AssetPath path = _targetLocationIOS(asset).path; + result[path] ??= <Asset>[]; + result[path]!.add(asset); + } + return result; +} + +Map<Asset, Asset> _assetTargetLocations(List<Asset> nativeAssets) => <Asset, Asset>{ + for (final Asset asset in nativeAssets) + asset: _targetLocationIOS(asset), +}; + +Asset _targetLocationIOS(Asset asset) { + final AssetPath path = asset.path; + switch (path) { + case AssetSystemPath _: + case AssetInExecutable _: + case AssetInProcess _: + return asset; + case AssetAbsolutePath _: + final String fileName = path.uri.pathSegments.last; + return asset.copyWith(path: AssetAbsolutePath(Uri(path: fileName))); + } + throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); +} diff --git a/packages/flutter_tools/lib/src/macos/native_assets.dart b/packages/flutter_tools/lib/src/macos/native_assets.dart new file mode 100644 index 0000000000000..c62c28fc111f2 --- /dev/null +++ b/packages/flutter_tools/lib/src/macos/native_assets.dart @@ -0,0 +1,162 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; + +import '../base/file_system.dart'; +import '../build_info.dart'; +import '../globals.dart' as globals; +import '../native_assets.dart'; +import 'native_assets_host.dart'; + +/// Dry run the native builds. +/// +/// This does not build native assets, it only simulates what the final paths +/// of all assets will be so that this can be embedded in the kernel file and +/// the Xcode project. +Future<Uri?> dryRunNativeAssetsMacOS({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + bool flutterTester = false, + required FileSystem fileSystem, +}) async { + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + return null; + } + + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.macOS); + final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, flutterTester, buildRunner); + final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); + return nativeAssetsUri; +} + +Future<Iterable<Asset>> dryRunNativeAssetsMacOSInternal( + FileSystem fileSystem, + Uri projectUri, + bool flutterTester, + NativeAssetsBuildRunner buildRunner, +) async { + const OS targetOs = OS.macOS; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + + globals.logger.printTrace('Dry running native assets for $targetOs.'); + final List<Asset> nativeAssets = (await buildRunner.dryRun( + linkModePreference: LinkModePreference.dynamic, + targetOs: targetOs, + workingDirectory: projectUri, + includeParentEnvironment: true, + )) + .assets; + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Dry running native assets for $targetOs done.'); + final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); + final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values; + return nativeAssetPaths; +} + +/// Builds native assets. +/// +/// If [darwinArchs] is omitted, the current target architecture is used. +/// +/// If [flutterTester] is true, absolute paths are emitted in the native +/// assets mapping. This can be used for JIT mode without sandbox on the host. +/// This is used in `flutter test` and `flutter run -d flutter-tester`. +Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsMacOS({ + required NativeAssetsBuildRunner buildRunner, + List<DarwinArch>? darwinArchs, + required Uri projectUri, + required BuildMode buildMode, + bool flutterTester = false, + String? codesignIdentity, + Uri? yamlParentDirectory, + required FileSystem fileSystem, +}) async { + const OS targetOs = OS.macOS; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); + return (nativeAssetsYaml, <Uri>[]); + } + + final List<Target> targets = darwinArchs != null ? darwinArchs.map(_getNativeTarget).toList() : <Target>[Target.current]; + final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); + + globals.logger.printTrace('Building native assets for $targets $buildModeCli.'); + final List<Asset> nativeAssets = <Asset>[]; + final Set<Uri> dependencies = <Uri>{}; + for (final Target target in targets) { + final BuildResult result = await buildRunner.build( + linkModePreference: LinkModePreference.dynamic, + target: target, + buildMode: buildModeCli, + workingDirectory: projectUri, + includeParentEnvironment: true, + cCompilerConfig: await buildRunner.cCompilerConfig, + ); + nativeAssets.addAll(result.assets); + dependencies.addAll(result.dependencies); + } + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Building native assets for $targets done.'); + final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); + final Map<AssetPath, List<Asset>> fatAssetTargetLocations = _fatAssetTargetLocations(nativeAssets, absolutePath); + await copyNativeAssetsMacOSHost(buildUri_, fatAssetTargetLocations, codesignIdentity, buildMode, fileSystem); + final Uri nativeAssetsUri = await writeNativeAssetsYaml(assetTargetLocations.values, yamlParentDirectory ?? buildUri_, fileSystem); + return (nativeAssetsUri, dependencies.toList()); +} + +/// Extract the [Target] from a [DarwinArch]. +Target _getNativeTarget(DarwinArch darwinArch) { + switch (darwinArch) { + case DarwinArch.arm64: + return Target.macOSArm64; + case DarwinArch.x86_64: + return Target.macOSX64; + case DarwinArch.armv7: + throw Exception('Unknown DarwinArch: $darwinArch.'); + } +} + +Map<AssetPath, List<Asset>> _fatAssetTargetLocations(List<Asset> nativeAssets, Uri? absolutePath) { + final Map<AssetPath, List<Asset>> result = <AssetPath, List<Asset>>{}; + for (final Asset asset in nativeAssets) { + final AssetPath path = _targetLocationMacOS(asset, absolutePath).path; + result[path] ??= <Asset>[]; + result[path]!.add(asset); + } + return result; +} + +Map<Asset, Asset> _assetTargetLocations(List<Asset> nativeAssets, Uri? absolutePath) => <Asset, Asset>{ + for (final Asset asset in nativeAssets) + asset: _targetLocationMacOS(asset, absolutePath), +}; + +Asset _targetLocationMacOS(Asset asset, Uri? absolutePath) { + final AssetPath path = asset.path; + switch (path) { + case AssetSystemPath _: + case AssetInExecutable _: + case AssetInProcess _: + return asset; + case AssetAbsolutePath _: + final String fileName = path.uri.pathSegments.last; + Uri uri; + if (absolutePath != null) { + // Flutter tester needs full host paths. + uri = absolutePath.resolve(fileName); + } else { + // Flutter Desktop needs "absolute" paths inside the app. + // "relative" in the context of native assets would be relative to the + // kernel or aot snapshot. + uri = Uri(path: fileName); + } + return asset.copyWith(path: AssetAbsolutePath(uri)); + } + throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); +} diff --git a/packages/flutter_tools/lib/src/macos/native_assets_host.dart b/packages/flutter_tools/lib/src/macos/native_assets_host.dart new file mode 100644 index 0000000000000..107ac9045c18f --- /dev/null +++ b/packages/flutter_tools/lib/src/macos/native_assets_host.dart @@ -0,0 +1,141 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Shared logic between iOS and macOS implementations of native assets. + +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; + +import '../base/common.dart'; +import '../base/file_system.dart'; +import '../base/io.dart'; +import '../build_info.dart'; +import '../convert.dart'; +import '../globals.dart' as globals; + +/// The target location for native assets on macOS. +/// +/// Because we need to have a multi-architecture solution for +/// `flutter run --release`, we use `lipo` to combine all target architectures +/// into a single file. +/// +/// We need to set the install name so that it matches what the place it will +/// be bundled in the final app. +/// +/// Code signing is also done here, so that we don't have to worry about it +/// in xcode_backend.dart and macos_assemble.sh. +Future<void> copyNativeAssetsMacOSHost( + Uri buildUri, + Map<AssetPath, List<Asset>> assetTargetLocations, + String? codesignIdentity, + BuildMode buildMode, + FileSystem fileSystem, +) async { + if (assetTargetLocations.isNotEmpty) { + globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); + final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); + if (!buildDir.existsSync()) { + buildDir.createSync(recursive: true); + } + for (final MapEntry<AssetPath, List<Asset>> assetMapping in assetTargetLocations.entries) { + final Uri target = (assetMapping.key as AssetAbsolutePath).uri; + final List<Uri> sources = <Uri>[for (final Asset source in assetMapping.value) (source.path as AssetAbsolutePath).uri]; + final Uri targetUri = buildUri.resolveUri(target); + final String targetFullPath = targetUri.toFilePath(); + await lipoDylibs(targetFullPath, sources); + await setInstallNameDylib(targetUri); + await codesignDylib(codesignIdentity, buildMode, targetFullPath); + } + globals.logger.printTrace('Copying native assets done.'); + } +} + +/// Combines dylibs from [sources] into a fat binary at [targetFullPath]. +/// +/// The dylibs must have different architectures. E.g. a dylib targeting +/// arm64 ios simulator cannot be combined with a dylib targeting arm64 +/// ios device or macos arm64. +Future<void> lipoDylibs(String targetFullPath, List<Uri> sources) async { + final ProcessResult lipoResult = await globals.processManager.run( + <String>[ + 'lipo', + '-create', + '-output', + targetFullPath, + for (final Uri source in sources) source.toFilePath(), + ], + ); + if (lipoResult.exitCode != 0) { + throwToolExit('Failed to create universal binary:\n${lipoResult.stderr}'); + } + globals.logger.printTrace(lipoResult.stdout as String); + globals.logger.printTrace(lipoResult.stderr as String); +} + +/// Sets the install name in a dylib with a Mach-O format. +/// +/// On macOS and iOS, opening a dylib at runtime fails if the path inside the +/// dylib itself does not correspond to the path that the file is at. Therefore, +/// native assets copied into their final location also need their install name +/// updated with the `install_name_tool`. +Future<void> setInstallNameDylib(Uri targetUri) async { + final String fileName = targetUri.pathSegments.last; + final ProcessResult installNameResult = await globals.processManager.run( + <String>[ + 'install_name_tool', + '-id', + '@executable_path/Frameworks/$fileName', + targetUri.toFilePath(), + ], + ); + if (installNameResult.exitCode != 0) { + throwToolExit('Failed to change the install name of $targetUri:\n${installNameResult.stderr}'); + } +} + +Future<void> codesignDylib( + String? codesignIdentity, + BuildMode buildMode, + String targetFullPath, +) async { + if (codesignIdentity == null || codesignIdentity.isEmpty) { + codesignIdentity = '-'; + } + final List<String> codesignCommand = <String>[ + 'codesign', + '--force', + '--sign', + codesignIdentity, + if (buildMode != BuildMode.release) ...<String>[ + // Mimic Xcode's timestamp codesigning behavior on non-release binaries. + '--timestamp=none', + ], + targetFullPath, + ]; + globals.logger.printTrace(codesignCommand.join(' ')); + final ProcessResult codesignResult = await globals.processManager.run(codesignCommand); + if (codesignResult.exitCode != 0) { + throwToolExit('Failed to code sign binary:\n${codesignResult.stderr}'); + } + globals.logger.printTrace(codesignResult.stdout as String); + globals.logger.printTrace(codesignResult.stderr as String); +} + +/// Flutter expects `xcrun` to be on the path on macOS hosts. +/// +/// Use the `clang`, `ar`, and `ld` that would be used if run with `xcrun`. +Future<CCompilerConfig> cCompilerConfigMacOS() async { + final ProcessResult xcrunResult = await globals.processManager.run(<String>['xcrun', 'clang', '--version']); + if (xcrunResult.exitCode != 0) { + throwToolExit('Failed to find clang with xcrun:\n${xcrunResult.stderr}'); + } + final String installPath = LineSplitter.split(xcrunResult.stdout as String) + .firstWhere((String s) => s.startsWith('InstalledDir: ')) + .split(' ') + .last; + return CCompilerConfig( + cc: Uri.file('$installPath/clang'), + ar: Uri.file('$installPath/ar'), + ld: Uri.file('$installPath/ld'), + ); +} diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart new file mode 100644 index 0000000000000..0255a3c4dd4a6 --- /dev/null +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -0,0 +1,378 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Logic for native assets shared between all host OSes. + +import 'package:logging/logging.dart' as logging; +import 'package:native_assets_builder/native_assets_builder.dart' as native_assets_builder; +import 'package:native_assets_cli/native_assets_cli.dart'; +import 'package:package_config/package_config_types.dart'; + +import 'base/common.dart'; +import 'base/file_system.dart'; +import 'base/logger.dart'; +import 'base/platform.dart'; +import 'build_info.dart' as build_info; +import 'cache.dart'; +import 'features.dart'; +import 'globals.dart' as globals; +import 'ios/native_assets.dart'; +import 'macos/native_assets.dart'; +import 'macos/native_assets_host.dart'; +import 'resident_runner.dart'; + +/// Programmatic API to be used by Dart launchers to invoke native builds. +/// +/// It enables mocking `package:native_assets_builder` package. +/// It also enables mocking native toolchain discovery via [cCompilerConfig]. +abstract class NativeAssetsBuildRunner { + /// Whether the project has a `.dart_tools/package_config.json`. + /// + /// If there is no package config, [packagesWithNativeAssets], [build], and + /// [dryRun] must not be invoked. + Future<bool> hasPackageConfig(); + + /// All packages in the transitive dependencies that have a `build.dart`. + Future<List<Package>> packagesWithNativeAssets(); + + /// Runs all [packagesWithNativeAssets] `build.dart` in dry run. + Future<native_assets_builder.DryRunResult> dryRun({ + required bool includeParentEnvironment, + required LinkModePreference linkModePreference, + required OS targetOs, + required Uri workingDirectory, + }); + + /// Runs all [packagesWithNativeAssets] `build.dart`. + Future<native_assets_builder.BuildResult> build({ + required bool includeParentEnvironment, + required BuildMode buildMode, + required LinkModePreference linkModePreference, + required Target target, + required Uri workingDirectory, + CCompilerConfig? cCompilerConfig, + int? targetAndroidNdkApi, + IOSSdk? targetIOSSdk, + }); + + /// The C compiler config to use for compilation. + Future<CCompilerConfig> get cCompilerConfig; +} + +/// Uses `package:native_assets_builder` for its implementation. +class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { + NativeAssetsBuildRunnerImpl(this.projectUri, this.fileSystem, this.logger); + + final Uri projectUri; + final FileSystem fileSystem; + final Logger logger; + + late final logging.Logger _logger = logging.Logger('') + ..onRecord.listen((logging.LogRecord record) { + final int levelValue = record.level.value; + final String message = record.message; + if (levelValue >= logging.Level.SEVERE.value) { + logger.printError(message); + } else if (levelValue >= logging.Level.WARNING.value) { + logger.printWarning(message); + } else if (levelValue >= logging.Level.INFO.value) { + logger.printTrace(message); + } else { + logger.printTrace(message); + } + }); + + late final Uri _dartExecutable = fileSystem.directory(Cache.flutterRoot).uri.resolve('bin/dart'); + + late final native_assets_builder.NativeAssetsBuildRunner _buildRunner = native_assets_builder.NativeAssetsBuildRunner( + logger: _logger, + dartExecutable: _dartExecutable, + ); + + native_assets_builder.PackageLayout? _packageLayout; + + @override + Future<bool> hasPackageConfig() { + final File packageConfigJson = fileSystem + .directory(projectUri.toFilePath()) + .childDirectory('.dart_tool') + .childFile('package_config.json'); + return packageConfigJson.exists(); + } + + @override + Future<List<Package>> packagesWithNativeAssets() async { + _packageLayout ??= await native_assets_builder.PackageLayout.fromRootPackageRoot(projectUri); + return _packageLayout!.packagesWithNativeAssets; + } + + @override + Future<native_assets_builder.DryRunResult> dryRun({ + required bool includeParentEnvironment, + required LinkModePreference linkModePreference, + required OS targetOs, + required Uri workingDirectory, + }) { + return _buildRunner.dryRun( + includeParentEnvironment: includeParentEnvironment, + linkModePreference: linkModePreference, + targetOs: targetOs, + workingDirectory: workingDirectory, + ); + } + + @override + Future<native_assets_builder.BuildResult> build({ + required bool includeParentEnvironment, + required BuildMode buildMode, + required LinkModePreference linkModePreference, + required Target target, + required Uri workingDirectory, + CCompilerConfig? cCompilerConfig, + int? targetAndroidNdkApi, + IOSSdk? targetIOSSdk, + }) { + return _buildRunner.build( + buildMode: buildMode, + cCompilerConfig: cCompilerConfig, + includeParentEnvironment: includeParentEnvironment, + linkModePreference: linkModePreference, + target: target, + targetAndroidNdkApi: targetAndroidNdkApi, + targetIOSSdk: targetIOSSdk, + workingDirectory: workingDirectory, + ); + } + + @override + late final Future<CCompilerConfig> cCompilerConfig = () { + if (globals.platform.isMacOS || globals.platform.isIOS) { + return cCompilerConfigMacOS(); + } + throwToolExit( + 'Native assets feature not yet implemented for Linux, Windows and Android.', + ); + }(); +} + +/// Write [assets] to `native_assets.yaml` in [yamlParentDirectory]. +Future<Uri> writeNativeAssetsYaml( + Iterable<Asset> assets, + Uri yamlParentDirectory, + FileSystem fileSystem, +) async { + globals.logger.printTrace('Writing native_assets.yaml.'); + final String nativeAssetsDartContents = assets.toNativeAssetsFile(); + final Directory parentDirectory = fileSystem.directory(yamlParentDirectory); + if (!await parentDirectory.exists()) { + await parentDirectory.create(recursive: true); + } + final File nativeAssetsFile = parentDirectory.childFile('native_assets.yaml'); + await nativeAssetsFile.writeAsString(nativeAssetsDartContents); + globals.logger.printTrace('Writing ${nativeAssetsFile.path} done.'); + return nativeAssetsFile.uri; +} + +/// Select the native asset build mode for a given Flutter build mode. +BuildMode nativeAssetsBuildMode(build_info.BuildMode buildMode) { + switch (buildMode) { + case build_info.BuildMode.debug: + return BuildMode.debug; + case build_info.BuildMode.jitRelease: + case build_info.BuildMode.profile: + case build_info.BuildMode.release: + return BuildMode.release; + } +} + +/// Checks whether this project does not yet have a package config file. +/// +/// A project has no package config when `pub get` has not yet been run. +/// +/// Native asset builds cannot be run without a package config. If there is +/// no package config, leave a logging trace about that. +Future<bool> hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async { + final bool packageConfigExists = await buildRunner.hasPackageConfig(); + if (!packageConfigExists) { + globals.logger.printTrace('No package config found. Skipping native assets compilation.'); + } + return !packageConfigExists; +} + +/// Checks that if native assets is disabled, none of the dependencies declare +/// native assets. +/// +/// If any of the dependencies have native assets, but native assets are +/// disabled, exits the tool. +Future<bool> isDisabledAndNoNativeAssets(NativeAssetsBuildRunner buildRunner) async { + if (featureFlags.isNativeAssetsEnabled) { + return false; + } + final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets(); + if (packagesWithNativeAssets.isEmpty) { + return true; + } + final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' '); + throwToolExit( + 'Package(s) $packageNames require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ); +} + +/// Ensures that either this project has no native assets, or that native assets +/// are supported on that operating system. +/// +/// Exits the tool if the above condition is not satisfied. +Future<void> ensureNoNativeAssetsOrOsIsSupported( + Uri workingDirectory, + String os, + FileSystem fileSystem, + NativeAssetsBuildRunner buildRunner, +) async { + if (await hasNoPackageConfig(buildRunner)) { + return; + } + final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets(); + if (packagesWithNativeAssets.isEmpty) { + return; + } + final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' '); + throwToolExit( + 'Package(s) $packageNames require the native assets feature. ' + 'This feature has not yet been implemented for `$os`. ' + 'For more info see https://github.com/flutter/flutter/issues/129757.', + ); +} + +/// Ensure all native assets have a linkmode declared to be dynamic loading. +/// +/// In JIT, the link mode must always be dynamic linking. +/// In AOT, the static linking has not yet been implemented in Dart: +/// https://github.com/dart-lang/sdk/issues/49418. +/// +/// Therefore, ensure all `build.dart` scripts return only dynamic libraries. +void ensureNoLinkModeStatic(List<Asset> nativeAssets) { + final Iterable<Asset> staticAssets = nativeAssets.whereLinkMode(LinkMode.static); + if (staticAssets.isNotEmpty) { + final String assetIds = staticAssets.map((Asset a) => a.id).toSet().join(', '); + throwToolExit( + 'Native asset(s) $assetIds have their link mode set to static, ' + 'but this is not yet supported. ' + 'For more info see https://github.com/dart-lang/sdk/issues/49418.', + ); + } +} + +/// This should be the same for different archs, debug/release, etc. +/// It should work for all macOS. +Uri nativeAssetsBuildUri(Uri projectUri, OS os) { + final String buildDir = build_info.getBuildDirectory(); + return projectUri.resolve('$buildDir/native_assets/$os/'); +} + +/// Gets the native asset id to dylib mapping to embed in the kernel file. +/// +/// Run hot compiles a kernel file that is pushed to the device after hot +/// restart. We need to embed the native assets mapping in order to access +/// native assets after hot restart. +Future<Uri?> dryRunNativeAssets({ + required Uri projectUri, + required FileSystem fileSystem, + required NativeAssetsBuildRunner buildRunner, + required List<FlutterDevice> flutterDevices, +}) async { + if (flutterDevices.length != 1) { + return dryRunNativeAssetsMultipeOSes( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: flutterDevices.map((FlutterDevice d) => d.targetPlatform).nonNulls, + buildRunner: buildRunner, + ); + } + final FlutterDevice flutterDevice = flutterDevices.single; + final build_info.TargetPlatform targetPlatform = flutterDevice.targetPlatform!; + + final Uri? nativeAssetsYaml; + switch (targetPlatform) { + case build_info.TargetPlatform.darwin: + nativeAssetsYaml = await dryRunNativeAssetsMacOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); + case build_info.TargetPlatform.ios: + nativeAssetsYaml = await dryRunNativeAssetsIOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); + case build_info.TargetPlatform.tester: + if (const LocalPlatform().isMacOS) { + nativeAssetsYaml = await dryRunNativeAssetsMacOS( + projectUri: projectUri, + flutterTester: true, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); + } else { + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + const LocalPlatform().operatingSystem, + fileSystem, + buildRunner, + ); + nativeAssetsYaml = null; + } + case build_info.TargetPlatform.android_arm: + case build_info.TargetPlatform.android_arm64: + case build_info.TargetPlatform.android_x64: + case build_info.TargetPlatform.android_x86: + case build_info.TargetPlatform.android: + case build_info.TargetPlatform.fuchsia_arm64: + case build_info.TargetPlatform.fuchsia_x64: + case build_info.TargetPlatform.linux_arm64: + case build_info.TargetPlatform.linux_x64: + case build_info.TargetPlatform.web_javascript: + case build_info.TargetPlatform.windows_x64: + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + targetPlatform.toString(), + fileSystem, + buildRunner, + ); + nativeAssetsYaml = null; + } + return nativeAssetsYaml; +} + +/// Dry run the native builds for multiple OSes. +/// +/// Needed for `flutter run -d all`. +Future<Uri?> dryRunNativeAssetsMultipeOSes({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + required FileSystem fileSystem, + required Iterable<build_info.TargetPlatform> targetPlatforms, +}) async { + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + return null; + } + + final Uri buildUri_ = buildUriMultiple(projectUri); + final Iterable<Asset> nativeAssetPaths = <Asset>[ + if (targetPlatforms.contains(build_info.TargetPlatform.darwin) || + (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS)) + ...await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, false, buildRunner), + if (targetPlatforms.contains(build_info.TargetPlatform.ios)) ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) + ]; + final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); + return nativeAssetsUri; +} + +/// With `flutter run -d all` we need a place to store the native assets +/// mapping for multiple OSes combined. +Uri buildUriMultiple(Uri projectUri) { + final String buildDir = build_info.getBuildDirectory(); + return projectUri.resolve('$buildDir/native_assets/multiple/'); +} diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index fdebdcab7314c..8665ec322ef4f 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -21,6 +21,7 @@ import 'dart/package_map.dart'; import 'devfs.dart'; import 'device.dart'; import 'globals.dart' as globals; +import 'native_assets.dart'; import 'project.dart'; import 'reporting/reporting.dart'; import 'resident_runner.dart'; @@ -92,9 +93,11 @@ class HotRunner extends ResidentRunner { StopwatchFactory stopwatchFactory = const StopwatchFactory(), ReloadSourcesHelper reloadSourcesHelper = defaultReloadSourcesHelper, ReassembleHelper reassembleHelper = _defaultReassembleHelper, + NativeAssetsBuildRunner? buildRunner, }) : _stopwatchFactory = stopwatchFactory, _reloadSourcesHelper = reloadSourcesHelper, _reassembleHelper = reassembleHelper, + _buildRunner = buildRunner, super( hotMode: true, ); @@ -132,6 +135,8 @@ class HotRunner extends ResidentRunner { String? _sdkName; bool? _emulator; + NativeAssetsBuildRunner? _buildRunner; + Future<void> _calculateTargetPlatform() async { if (_targetPlatform != null) { return; @@ -360,6 +365,15 @@ class HotRunner extends ResidentRunner { }) async { await _calculateTargetPlatform(); + final Uri projectUri = Uri.directory(projectRootPath); + _buildRunner ??= NativeAssetsBuildRunnerImpl(projectUri, fileSystem, globals.logger); + final Uri? nativeAssetsYaml = await dryRunNativeAssets( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: _buildRunner!, + flutterDevices: flutterDevices, + ); + final Stopwatch appStartedTimer = Stopwatch()..start(); final File mainFile = globals.fs.file(mainPath); firstBuildTime = DateTime.now(); @@ -391,6 +405,7 @@ class HotRunner extends ResidentRunner { packageConfig: debuggingOptions.buildInfo.packageConfig, projectRootPath: FlutterProject.current().directory.absolute.path, fs: globals.fs, + nativeAssetsYaml: nativeAssetsYaml, ).then((CompilerOutput? output) { compileTimer.stop(); totalCompileTime += compileTimer.elapsed; diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 37db867caa076..067838482ba13 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -10,11 +10,14 @@ import 'package:meta/meta.dart'; import '../artifacts.dart'; import '../base/file_system.dart'; +import '../base/platform.dart'; import '../build_info.dart'; import '../bundle.dart'; import '../compile.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; +import '../macos/native_assets.dart'; +import '../native_assets.dart'; import '../project.dart'; import 'test_time_recorder.dart'; @@ -163,6 +166,26 @@ class TestCompiler { invalidatedRegistrantFiles.add(flutterProject!.dartPluginRegistrant.absolute.uri); } + Uri? nativeAssetsYaml; + final Uri projectUri = FlutterProject.current().directory.uri; + final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl(projectUri, globals.fs, globals.logger); + if (globals.platform.isMacOS) { + (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( + buildMode: BuildMode.debug, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); + } else { + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + const LocalPlatform().operatingSystem, + globals.fs, + buildRunner, + ); + } + final CompilerOutput? compilerOutput = await compiler!.recompile( request.mainUri, <Uri>[request.mainUri, ...invalidatedRegistrantFiles], @@ -171,6 +194,7 @@ class TestCompiler { projectRootPath: flutterProject?.directory.absolute.path, checkDartPluginRegistry: true, fs: globals.fs, + nativeAssetsYaml: nativeAssetsYaml, ); final String? outputPath = compilerOutput?.outputFilename; diff --git a/packages/flutter_tools/lib/src/tester/flutter_tester.dart b/packages/flutter_tools/lib/src/tester/flutter_tester.dart index 5b9f6fe1a5d0b..241b132a75ab1 100644 --- a/packages/flutter_tools/lib/src/tester/flutter_tester.dart +++ b/packages/flutter_tools/lib/src/tester/flutter_tester.dart @@ -11,7 +11,6 @@ import '../artifacts.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; -import '../base/os.dart'; import '../build_info.dart'; import '../bundle.dart'; import '../bundle_builder.dart'; @@ -50,13 +49,11 @@ class FlutterTesterDevice extends Device { required Logger logger, required FileSystem fileSystem, required Artifacts artifacts, - required OperatingSystemUtils operatingSystemUtils, }) : _processManager = processManager, _flutterVersion = flutterVersion, _logger = logger, _fileSystem = fileSystem, - _artifacts = artifacts, - _operatingSystemUtils = operatingSystemUtils, + _artifacts = artifacts, super( platformType: null, category: null, @@ -68,7 +65,6 @@ class FlutterTesterDevice extends Device { final Logger _logger; final FileSystem _fileSystem; final Artifacts _artifacts; - final OperatingSystemUtils _operatingSystemUtils; Process? _process; final DevicePortForwarder _portForwarder = const NoOpDevicePortForwarder(); @@ -157,7 +153,7 @@ class FlutterTesterDevice extends Device { buildInfo: buildInfo, mainPath: mainPath, applicationKernelFilePath: applicationKernelFilePath, - platform: getTargetPlatformForName(getNameForHostPlatform(_operatingSystemUtils.hostPlatform)), + platform: TargetPlatform.tester, assetDirPath: assetDirectory.path, ); @@ -258,15 +254,13 @@ class FlutterTesterDevices extends PollingDeviceDiscovery { required ProcessManager processManager, required Logger logger, required FlutterVersion flutterVersion, - required OperatingSystemUtils operatingSystemUtils, }) : _testerDevice = FlutterTesterDevice( kTesterDeviceId, fileSystem: fileSystem, artifacts: artifacts, processManager: processManager, logger: logger, - flutterVersion: flutterVersion, - operatingSystemUtils: operatingSystemUtils, + flutterVersion: flutterVersion, ), super('Flutter tester'); diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 7e8022f80ed57..942598884bf24 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -50,6 +50,11 @@ dependencies: async: 2.11.0 unified_analytics: 3.0.0 + cli_config: 0.1.1 + graphs: 2.3.1 + native_assets_builder: 0.2.0 + native_assets_cli: 0.2.0 + # We depend on very specific internal implementation details of the # 'test' package, which change between versions, so when upgrading # this, make sure the tests are still running correctly. @@ -107,4 +112,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: a4aa +# PUBSPEC CHECKSUM: 284b diff --git a/packages/flutter_tools/templates/app/lib/main.dart.tmpl b/packages/flutter_tools/templates/app/lib/main.dart.tmpl index e7ad70d7544f0..78e535632ce35 100644 --- a/packages/flutter_tools/templates/app/lib/main.dart.tmpl +++ b/packages/flutter_tools/templates/app/lib/main.dart.tmpl @@ -27,11 +27,11 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:{{pluginProjectName}}/{{pluginProjectName}}.dart'; {{/withPlatformChannelPluginHook}} -{{#withFfiPluginHook}} +{{#withFfi}} import 'dart:async'; import 'package:{{pluginProjectName}}/{{pluginProjectName}}.dart' as {{pluginProjectName}}; -{{/withFfiPluginHook}} +{{/withFfi}} void main() { runApp(const MyApp()); @@ -213,7 +213,7 @@ class _MyAppState extends State<MyApp> { } } {{/withPlatformChannelPluginHook}} -{{#withFfiPluginHook}} +{{#withFfi}} class MyApp extends StatefulWidget { const MyApp({super.key}); @@ -279,5 +279,5 @@ class _MyAppState extends State<MyApp> { ); } } -{{/withFfiPluginHook}} +{{/withFfi}} {{/withEmptyMain}} diff --git a/packages/flutter_tools/templates/module/common/test/widget_test.dart.tmpl b/packages/flutter_tools/templates/module/common/test/widget_test.dart.tmpl index c27006fbc8407..f05c069c1335a 100644 --- a/packages/flutter_tools/templates/module/common/test/widget_test.dart.tmpl +++ b/packages/flutter_tools/templates/module/common/test/widget_test.dart.tmpl @@ -8,9 +8,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -{{^withFfiPluginHook}} +{{^withFfi}} import 'package:{{projectName}}/main.dart'; -{{/withFfiPluginHook}} +{{/withFfi}} {{^withPluginHook}} void main() { diff --git a/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl b/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl new file mode 100644 index 0000000000000..96486fd930243 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/.gitignore.tmpl @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/packages/flutter_tools/templates/package_ffi/.metadata.tmpl b/packages/flutter_tools/templates/package_ffi/.metadata.tmpl new file mode 100644 index 0000000000000..e1a1dd9321432 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/.metadata.tmpl @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: {{flutterRevision}} + channel: {{flutterChannel}} + +project_type: package_ffi diff --git a/packages/flutter_tools/templates/package_ffi/CHANGELOG.md.tmpl b/packages/flutter_tools/templates/package_ffi/CHANGELOG.md.tmpl new file mode 100644 index 0000000000000..41cc7d8192ecf --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/CHANGELOG.md.tmpl @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/packages/flutter_tools/templates/package_ffi/LICENSE.tmpl b/packages/flutter_tools/templates/package_ffi/LICENSE.tmpl new file mode 100644 index 0000000000000..ba75c69f7f217 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/LICENSE.tmpl @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/flutter_tools/templates/package_ffi/README.md.tmpl b/packages/flutter_tools/templates/package_ffi/README.md.tmpl new file mode 100644 index 0000000000000..3a636eb722def --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/README.md.tmpl @@ -0,0 +1,49 @@ +# {{projectName}} + +{{description}} + +## Getting Started + +This project is a starting point for a Flutter +[FFI package](https://docs.flutter.dev/development/platform-integration/c-interop), +a specialized package that includes native code directly invoked with Dart FFI. + +## Project stucture + +This template uses the following structure: + +* `src`: Contains the native source code, and a CmakeFile.txt file for building + that source code into a dynamic library. + +* `lib`: Contains the Dart code that defines the API of the plugin, and which + calls into the native code using `dart:ffi`. + +* `bin`: Contains the `build.dart` that performs the external native builds. + +## Buidling and bundling native code + +`build.dart` does the building of native components. + +Bundling is done by Flutter based on the output from `build.dart`. + +## Binding to native code + +To use the native code, bindings in Dart are needed. +To avoid writing these by hand, they are generated from the header file +(`src/{{projectName}}.h`) by `package:ffigen`. +Regenerate the bindings by running `flutter pub run ffigen --config ffigen.yaml`. + +## Invoking native code + +Very short-running native functions can be directly invoked from any isolate. +For example, see `sum` in `lib/{{projectName}}.dart`. + +Longer-running functions should be invoked on a helper isolate to avoid +dropping frames in Flutter applications. +For example, see `sumAsync` in `lib/{{projectName}}.dart`. + +## Flutter help + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/packages/flutter_tools/templates/package_ffi/analysis_options.yaml.tmpl b/packages/flutter_tools/templates/package_ffi/analysis_options.yaml.tmpl new file mode 100644 index 0000000000000..a5744c1cfbe77 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/analysis_options.yaml.tmpl @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/flutter_tools/templates/package_ffi/build.dart.tmpl b/packages/flutter_tools/templates/package_ffi/build.dart.tmpl new file mode 100644 index 0000000000000..3fe2224500d23 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/build.dart.tmpl @@ -0,0 +1,24 @@ +import 'package:native_toolchain_c/native_toolchain_c.dart'; +import 'package:logging/logging.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; + +const packageName = '{{projectName}}'; + +void main(List<String> args) async { + final buildConfig = await BuildConfig.fromArgs(args); + final buildOutput = BuildOutput(); + final cbuilder = CBuilder.library( + name: packageName, + assetId: + 'package:$packageName/${packageName}_bindings_generated.dart', + sources: [ + 'src/$packageName.c', + ], + ); + await cbuilder.run( + buildConfig: buildConfig, + buildOutput: buildOutput, + logger: Logger('')..onRecord.listen((record) => print(record.message)), + ); + await buildOutput.writeToFile(outDir: buildConfig.outDir); +} diff --git a/packages/flutter_tools/templates/package_ffi/ffigen.yaml.tmpl b/packages/flutter_tools/templates/package_ffi/ffigen.yaml.tmpl new file mode 100644 index 0000000000000..c33bb9f92cdaa --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/ffigen.yaml.tmpl @@ -0,0 +1,20 @@ +# Run with `flutter pub run ffigen --config ffigen.yaml`. +name: {{pluginDartClass}}Bindings +description: | + Bindings for `src/{{projectName}}.h`. + + Regenerate bindings with `flutter pub run ffigen --config ffigen.yaml`. +output: 'lib/{{projectName}}_bindings_generated.dart' +headers: + entry-points: + - 'src/{{projectName}}.h' + include-directives: + - 'src/{{projectName}}.h' +ffi-native: +preamble: | + // ignore_for_file: always_specify_types + // ignore_for_file: camel_case_types + // ignore_for_file: non_constant_identifier_names +comments: + style: any + length: full diff --git a/packages/flutter_tools/templates/package_ffi/lib/projectName.dart.tmpl b/packages/flutter_tools/templates/package_ffi/lib/projectName.dart.tmpl new file mode 100644 index 0000000000000..2c3d5cd443cac --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/lib/projectName.dart.tmpl @@ -0,0 +1,108 @@ +import 'dart:async'; +import 'dart:isolate'; + +import '{{projectName}}_bindings_generated.dart' as bindings; + +/// A very short-lived native function. +/// +/// For very short-lived functions, it is fine to call them on the main isolate. +/// They will block the Dart execution while running the native function, so +/// only do this for native functions which are guaranteed to be short-lived. +int sum(int a, int b) => bindings.sum(a, b); + +/// A longer lived native function, which occupies the thread calling it. +/// +/// Do not call these kind of native functions in the main isolate. They will +/// block Dart execution. This will cause dropped frames in Flutter applications. +/// Instead, call these native functions on a separate isolate. +/// +/// Modify this to suit your own use case. Example use cases: +/// +/// 1. Reuse a single isolate for various different kinds of requests. +/// 2. Use multiple helper isolates for parallel execution. +Future<int> sumAsync(int a, int b) async { + final SendPort helperIsolateSendPort = await _helperIsolateSendPort; + final int requestId = _nextSumRequestId++; + final _SumRequest request = _SumRequest(requestId, a, b); + final Completer<int> completer = Completer<int>(); + _sumRequests[requestId] = completer; + helperIsolateSendPort.send(request); + return completer.future; +} + +/// A request to compute `sum`. +/// +/// Typically sent from one isolate to another. +class _SumRequest { + final int id; + final int a; + final int b; + + const _SumRequest(this.id, this.a, this.b); +} + +/// A response with the result of `sum`. +/// +/// Typically sent from one isolate to another. +class _SumResponse { + final int id; + final int result; + + const _SumResponse(this.id, this.result); +} + +/// Counter to identify [_SumRequest]s and [_SumResponse]s. +int _nextSumRequestId = 0; + +/// Mapping from [_SumRequest] `id`s to the completers corresponding to the correct future of the pending request. +final Map<int, Completer<int>> _sumRequests = <int, Completer<int>>{}; + +/// The SendPort belonging to the helper isolate. +Future<SendPort> _helperIsolateSendPort = () async { + // The helper isolate is going to send us back a SendPort, which we want to + // wait for. + final Completer<SendPort> completer = Completer<SendPort>(); + + // Receive port on the main isolate to receive messages from the helper. + // We receive two types of messages: + // 1. A port to send messages on. + // 2. Responses to requests we sent. + final ReceivePort receivePort = ReceivePort() + ..listen((dynamic data) { + if (data is SendPort) { + // The helper isolate sent us the port on which we can sent it requests. + completer.complete(data); + return; + } + if (data is _SumResponse) { + // The helper isolate sent us a response to a request we sent. + final Completer<int> completer = _sumRequests[data.id]!; + _sumRequests.remove(data.id); + completer.complete(data.result); + return; + } + throw UnsupportedError('Unsupported message type: ${data.runtimeType}'); + }); + + // Start the helper isolate. + await Isolate.spawn((SendPort sendPort) async { + final ReceivePort helperReceivePort = ReceivePort() + ..listen((dynamic data) { + // On the helper isolate listen to requests and respond to them. + if (data is _SumRequest) { + final int result = bindings.sum_long_running(data.a, data.b); + final _SumResponse response = _SumResponse(data.id, result); + sendPort.send(response); + return; + } + throw UnsupportedError('Unsupported message type: ${data.runtimeType}'); + }); + + // Send the the port to the main isolate on which we can receive requests. + sendPort.send(helperReceivePort.sendPort); + }, receivePort.sendPort); + + // Wait until the helper isolate has sent us back the SendPort on which we + // can start sending requests. + return completer.future; +}(); diff --git a/packages/flutter_tools/templates/package_ffi/lib/projectName_bindings_generated.dart.tmpl b/packages/flutter_tools/templates/package_ffi/lib/projectName_bindings_generated.dart.tmpl new file mode 100644 index 0000000000000..65642b4381817 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/lib/projectName_bindings_generated.dart.tmpl @@ -0,0 +1,30 @@ +// ignore_for_file: always_specify_types +// ignore_for_file: camel_case_types +// ignore_for_file: non_constant_identifier_names + +// AUTO GENERATED FILE, DO NOT EDIT. +// +// Generated by `package:ffigen`. +import 'dart:ffi' as ffi; + +/// A very short-lived native function. +/// +/// For very short-lived functions, it is fine to call them on the main isolate. +/// They will block the Dart execution while running the native function, so +/// only do this for native functions which are guaranteed to be short-lived. +@ffi.Native<ffi.IntPtr Function(ffi.IntPtr, ffi.IntPtr)>() +external int sum( + int a, + int b, +); + +/// A longer lived native function, which occupies the thread calling it. +/// +/// Do not call these kind of native functions in the main isolate. They will +/// block Dart execution. This will cause dropped frames in Flutter applications. +/// Instead, call these native functions on a separate isolate. +@ffi.Native<ffi.IntPtr Function(ffi.IntPtr, ffi.IntPtr)>() +external int sum_long_running( + int a, + int b, +); diff --git a/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl b/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl new file mode 100644 index 0000000000000..8fa5f3ac67ad0 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl @@ -0,0 +1,19 @@ +name: {{projectName}} +description: {{description}} +version: 0.0.1 +homepage: + +environment: + sdk: {{dartSdkVersionBounds}} + +dependencies: + cli_config: ^0.1.1 + logging: ^1.1.1 + native_assets_cli: ^0.2.0 + native_toolchain_c: ^0.2.0 + +dev_dependencies: + ffi: ^2.0.2 + ffigen: ^9.0.0 + flutter_lints: ^2.0.0 + test: ^1.21.0 diff --git a/packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.c.tmpl b/packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.c.tmpl new file mode 100644 index 0000000000000..a0d23594f02de --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.c.tmpl @@ -0,0 +1,29 @@ +#include "{{projectName}}.h" + +// A very short-lived native function. +// +// For very short-lived functions, it is fine to call them on the main isolate. +// They will block the Dart execution while running the native function, so +// only do this for native functions which are guaranteed to be short-lived. +FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b) { +#ifdef DEBUG + return a + b + 1000; +#else + return a + b; +#endif +} + +// A longer-lived native function, which occupies the thread calling it. +// +// Do not call these kind of native functions in the main isolate. They will +// block Dart execution. This will cause dropped frames in Flutter applications. +// Instead, call these native functions on a separate isolate. +FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b) { + // Simulate work. +#if _WIN32 + Sleep(5000); +#else + usleep(5000 * 1000); +#endif + return a + b; +} diff --git a/packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.h.tmpl b/packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.h.tmpl new file mode 100644 index 0000000000000..084c64228f465 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/src.tmpl/projectName.h.tmpl @@ -0,0 +1,30 @@ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#if _WIN32 +#include <windows.h> +#else +#include <pthread.h> +#include <unistd.h> +#endif + +#if _WIN32 +#define FFI_PLUGIN_EXPORT __declspec(dllexport) +#else +#define FFI_PLUGIN_EXPORT +#endif + +// A very short-lived native function. +// +// For very short-lived functions, it is fine to call them on the main isolate. +// They will block the Dart execution while running the native function, so +// only do this for native functions which are guaranteed to be short-lived. +FFI_PLUGIN_EXPORT intptr_t sum(intptr_t a, intptr_t b); + +// A longer lived native function, which occupies the thread calling it. +// +// Do not call these kind of native functions in the main isolate. They will +// block Dart execution. This will cause dropped frames in Flutter applications. +// Instead, call these native functions on a separate isolate. +FFI_PLUGIN_EXPORT intptr_t sum_long_running(intptr_t a, intptr_t b); diff --git a/packages/flutter_tools/templates/package_ffi/test/projectName_test.dart.tmpl b/packages/flutter_tools/templates/package_ffi/test/projectName_test.dart.tmpl new file mode 100644 index 0000000000000..f19bce25aab86 --- /dev/null +++ b/packages/flutter_tools/templates/package_ffi/test/projectName_test.dart.tmpl @@ -0,0 +1,14 @@ +import 'package:test/test.dart'; + +import 'package:{{projectName}}/{{projectName}}.dart'; + +void main() { + test('invoke native function', () { + // Tests are run in debug mode. + expect(sum(24, 18), 1042); + }); + + test('invoke async native callback', () async { + expect(await sumAsync(24, 18), 42); + }); +} diff --git a/packages/flutter_tools/templates/plugin_shared/.metadata.tmpl b/packages/flutter_tools/templates/plugin_shared/.metadata.tmpl index 89546c72e7604..8cb05910ce97d 100644 --- a/packages/flutter_tools/templates/plugin_shared/.metadata.tmpl +++ b/packages/flutter_tools/templates/plugin_shared/.metadata.tmpl @@ -10,6 +10,9 @@ version: {{#withFfiPluginHook}} project_type: plugin_ffi {{/withFfiPluginHook}} +{{#withFfiPackage}} +project_type: package_ffi +{{/withFfiPackage}} {{#withPlatformChannelPluginHook}} project_type: plugin {{/withPlatformChannelPluginHook}} diff --git a/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl b/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl index 5b0d6b2967ac5..c8d9bbf05af21 100644 --- a/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl +++ b/packages/flutter_tools/templates/plugin_shared/pubspec.yaml.tmpl @@ -17,10 +17,10 @@ dependencies: plugin_platform_interface: ^2.0.2 dev_dependencies: -{{#withFfiPluginHook}} - ffi: ^2.0.1 - ffigen: ^6.1.2 -{{/withFfiPluginHook}} +{{#withFfi}} + ffi: ^2.0.2 + ffigen: ^9.0.0 +{{/withFfi}} flutter_test: sdk: flutter flutter_lints: ^2.0.0 diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json index 3729d8909fa75..f7cc14a3b9573 100644 --- a/packages/flutter_tools/templates/template_manifest.json +++ b/packages/flutter_tools/templates/template_manifest.json @@ -248,6 +248,21 @@ "templates/package/README.md.tmpl", "templates/package/test/projectName_test.dart.tmpl", + "templates/package_ffi/.gitignore.tmpl", + "templates/package_ffi/.metadata.tmpl", + "templates/package_ffi/analysis_options.yaml.tmpl", + "templates/package_ffi/build.dart.tmpl", + "templates/package_ffi/CHANGELOG.md.tmpl", + "templates/package_ffi/ffigen.yaml.tmpl", + "templates/package_ffi/lib/projectName_bindings_generated.dart.tmpl", + "templates/package_ffi/lib/projectName.dart.tmpl", + "templates/package_ffi/LICENSE.tmpl", + "templates/package_ffi/pubspec.yaml.tmpl", + "templates/package_ffi/README.md.tmpl", + "templates/package_ffi/src.tmpl/projectName.c.tmpl", + "templates/package_ffi/src.tmpl/projectName.h.tmpl", + "templates/package_ffi/test/projectName_test.dart.tmpl", + "templates/plugin/android-java.tmpl/build.gradle.tmpl", "templates/plugin/android-java.tmpl/projectName_android.iml.tmpl", "templates/plugin/android-java.tmpl/src/main/java/androidIdentifier/pluginClass.java.tmpl", diff --git a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart index 088caf9e754a0..068bac8a2d0c3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart @@ -10,11 +10,14 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; +import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:test/fake.dart'; +import '../../src/common.dart'; import '../../src/context.dart'; +import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; import '../../src/testbed.dart'; @@ -79,6 +82,7 @@ void main() { globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'skeleton'), globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'module', 'common'), globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'package'), + globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'package_ffi'), globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin'), globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin_ffi'), globals.fs.path.join('flutter', 'packages', 'flutter_tools', 'templates', 'plugin_shared'), @@ -109,6 +113,7 @@ void main() { flutterManifest.writeAsStringSync('{"files":[]}'); }, overrides: <Type, Generator>{ DoctorValidatorsProvider: () => FakeDoctorValidatorsProvider(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), }); }); @@ -133,6 +138,9 @@ void main() { await runner.run(<String>['create', '--no-pub', '--template=plugin_ffi', 'testy5']); expect((await command.usageValues).commandCreateProjectType, 'plugin_ffi'); + + await runner.run(<String>['create', '--no-pub', '--template=package_ffi', 'testy6']); + expect((await command.usageValues).commandCreateProjectType, 'package_ffi'); })); testUsingContext('set iOS host language type as usage value', () => testbed.run(() async { @@ -183,6 +191,29 @@ void main() { }, overrides: <Type, Generator>{ Pub: () => fakePub, })); + + testUsingContext('package_ffi template not enabled', () async { + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + expect( + runner.run( + <String>[ + 'create', + '--no-pub', + '--template=package_ffi', + 'my_ffi_package', + ], + ), + throwsUsageException( + message: '"package_ffi" is not an allowed value for option "template"', + ), + ); + }, overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags( + isNativeAssetsEnabled: false, // ignore: avoid_redundant_argument_values, If we graduate the feature to true by default, don't break this test. + ), + }); }); } diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart index a0d34ace2777b..f20ec4999dd85 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart @@ -856,6 +856,7 @@ class FakeBundleBuilder extends Fake implements BundleBuilder { String? applicationKernelFilePath, String? depfilePath, String? assetDirPath, + Uri? nativeAssets, @visibleForTesting BuildSystem? buildSystem, }) async {} } diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 3d5c238a3a89c..b9d0ed6d2d6ef 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -2610,6 +2610,18 @@ void main() { , throwsToolExit(message: 'The "--platforms" argument is not supported', exitCode: 2)); }); + testUsingContext('create an ffi package with --platforms throws error.', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + await expectLater( + runner.run(<String>['create', '--no-pub', '--template=package_ffi', '--platform=ios', projectDir.path]) + , throwsToolExit(message: 'The "--platforms" argument is not supported', exitCode: 2)); + }, overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + }); + testUsingContext('create a plugin with android, delete then re-create folders', () async { Cache.flutterRoot = '../..'; @@ -3315,43 +3327,49 @@ void main() { FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), }); - testUsingContext('FFI plugins error android language', () async { - final CreateCommand command = CreateCommand(); - final CommandRunner<void> runner = createTestCommandRunner(command); - final List<String> args = <String>[ - 'create', - '--no-pub', - '--template=plugin_ffi', - '-a', - 'kotlin', - '--platforms=android', - projectDir.path, - ]; - - await expectLater( - runner.run(args), - throwsToolExit(message: 'The "android-language" option is not supported with the plugin_ffi template: the language will always be C or C++.'), - ); - }); - - testUsingContext('FFI plugins error ios language', () async { - final CreateCommand command = CreateCommand(); - final CommandRunner<void> runner = createTestCommandRunner(command); - final List<String> args = <String>[ - 'create', - '--no-pub', - '--template=plugin_ffi', - '--ios-language', - 'swift', - '--platforms=ios', - projectDir.path, - ]; + for (final String template in <String>['package_ffi', 'plugin_ffi']) { + testUsingContext('$template error android language', () async { + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<String> args = <String>[ + 'create', + '--no-pub', + '--template=$template', + '-a', + 'kotlin', + if (template == 'plugin_ffi') '--platforms=android', + projectDir.path, + ]; + + await expectLater( + runner.run(args), + throwsToolExit(message: 'The "android-language" option is not supported with the $template template: the language will always be C or C++.'), + ); + }, overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + }); - await expectLater( - runner.run(args), - throwsToolExit(message: 'The "ios-language" option is not supported with the plugin_ffi template: the language will always be C or C++.'), - ); - }); + testUsingContext('$template error ios language', () async { + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<String> args = <String>[ + 'create', + '--no-pub', + '--template=$template', + '--ios-language', + 'swift', + if (template == 'plugin_ffi') '--platforms=ios', + projectDir.path, + ]; + + await expectLater( + runner.run(args), + throwsToolExit(message: 'The "ios-language" option is not supported with the $template template: the language will always be C or C++.'), + ); + }, overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + }); + } testUsingContext('FFI plugins error web platform', () async { final CreateCommand command = CreateCommand(); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 5aab1be653bf3..31d9d86ac2d2e 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -71,10 +71,21 @@ void main() { throwsA(isA<MissingDefineException>())); }); + const String emptyNativeAssets = ''' +format-version: + - 1 + - 0 + - 0 +native-assets: {} +'''; + testWithoutContext('KernelSnapshot handles null result from kernel compilation', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = androidEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -102,6 +113,8 @@ void main() { '$build/app.dill', '--depfile', '$build/kernel_snapshot.d', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'file:///lib/main.dart', ], exitCode: 1), @@ -115,6 +128,9 @@ void main() { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = androidEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -142,6 +158,8 @@ void main() { '$build/app.dill', '--depfile', '$build/kernel_snapshot.d', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'file:///lib/main.dart', ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'), @@ -156,6 +174,9 @@ void main() { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = androidEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -183,6 +204,8 @@ void main() { '$build/app.dill', '--depfile', '$build/kernel_snapshot.d', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'file:///lib/main.dart', ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'), @@ -198,6 +221,9 @@ void main() { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = androidEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -225,6 +251,8 @@ void main() { '$build/app.dill', '--depfile', '$build/kernel_snapshot.d', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'foo', 'bar', @@ -242,6 +270,9 @@ void main() { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = androidEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -268,6 +299,8 @@ void main() { '--incremental', '--initialize-from-dill', '$build/app.dill', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'file:///lib/main.dart', ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'), @@ -284,6 +317,9 @@ void main() { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = androidEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -309,6 +345,8 @@ void main() { '--incremental', '--initialize-from-dill', '$build/app.dill', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'file:///lib/main.dart', ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'), @@ -338,6 +376,9 @@ void main() { fileSystem: fileSystem, logger: logger, ); + testEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); final String build = testEnvironment.buildDir.path; final String flutterPatchedSdkPath = artifacts.getArtifactPath( Artifact.flutterPatchedSdkPath, @@ -365,6 +406,8 @@ void main() { '--incremental', '--initialize-from-dill', '$build/app.dill', + '--native-assets', + '$build/native_assets.yaml', '--verbosity=error', 'file:///lib/main.dart', ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey /build/653e11a8e6908714056a57cd6b4f602a/app.dill 0\n'), diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart new file mode 100644 index 0000000000000..86660f3a7909a --- /dev/null +++ b/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart @@ -0,0 +1,140 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/build_system/exceptions.dart'; +import 'package:flutter_tools/src/build_system/targets/native_assets.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; + +import '../../../src/common.dart'; +import '../../../src/context.dart'; +import '../../../src/fakes.dart'; +import '../../fake_native_assets_build_runner.dart'; + +void main() { + late FakeProcessManager processManager; + late Environment iosEnvironment; + late Artifacts artifacts; + late FileSystem fileSystem; + late Logger logger; + + setUp(() { + processManager = FakeProcessManager.empty(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + fileSystem = MemoryFileSystem.test(); + iosEnvironment = Environment.test( + fileSystem.currentDirectory, + defines: <String, String>{ + kBuildMode: BuildMode.profile.cliName, + kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios), + kIosArchs: 'arm64', + kSdkRoot: 'path/to/iPhoneOS.sdk', + }, + inputs: <String, String>{}, + artifacts: artifacts, + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + iosEnvironment.buildDir.createSync(recursive: true); + }); + + testWithoutContext('NativeAssets throws error if missing target platform', () async { + iosEnvironment.defines.remove(kTargetPlatform); + expect(const NativeAssets().build(iosEnvironment), throwsA(isA<MissingDefineException>())); + }); + + testUsingContext('NativeAssets throws error if missing ios archs', () async { + iosEnvironment.defines.remove(kIosArchs); + expect(const NativeAssets().build(iosEnvironment), throwsA(isA<MissingDefineException>())); + }); + + testUsingContext('NativeAssets throws error if missing sdk root', () async { + iosEnvironment.defines.remove(kSdkRoot); + expect(const NativeAssets().build(iosEnvironment), throwsA(isA<MissingDefineException>())); + }); + + // The NativeAssets Target should _always_ be creating a yaml an d file. + // The caching logic depends on this. + for (final bool isNativeAssetsEnabled in <bool>[true, false]) { + final String postFix = isNativeAssetsEnabled ? 'enabled' : 'disabled'; + testUsingContext( + 'Successfull native_assets.yaml and native_assets.d creation with feature $postFix', + overrides: <Type, Generator>{ + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + FeatureFlags: () => TestFeatureFlags( + isNativeAssetsEnabled: isNativeAssetsEnabled, + ), + }, + () async { + final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(); + await NativeAssets(buildRunner: buildRunner).build(iosEnvironment); + + expect(iosEnvironment.buildDir.childFile('native_assets.d'), exists); + expect(iosEnvironment.buildDir.childFile('native_assets.yaml'), exists); + }, + ); + } + + testUsingContext( + 'NativeAssets with an asset', + overrides: <Type, Generator>{ + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + }, + () async { + final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + buildResult: FakeNativeAssetsBuilderResult(assets: <native_assets_cli.Asset>[ + native_assets_cli.Asset( + id: 'package:foo/foo.dart', + linkMode: native_assets_cli.LinkMode.dynamic, + target: native_assets_cli.Target.iOSArm64, + path: native_assets_cli.AssetAbsolutePath( + Uri.file('libfoo.dylib'), + ), + ) + ], dependencies: <Uri>[ + Uri.file('src/foo.c'), + ]), + ); + await NativeAssets(buildRunner: buildRunner).build(iosEnvironment); + + final File nativeAssetsYaml = iosEnvironment.buildDir.childFile('native_assets.yaml'); + final File depsFile = iosEnvironment.buildDir.childFile('native_assets.d'); + expect(depsFile, exists); + // We don't care about the specific format, but it should contain the + // yaml as the file depending on the source files that went in to the + // build. + expect( + depsFile.readAsStringSync(), + stringContainsInOrder(<String>[ + nativeAssetsYaml.path, + ':', + 'src/foo.c', + ]), + ); + expect(nativeAssetsYaml, exists); + // We don't care about the specific format, but it should contain the + // asset id and the path to the dylib. + expect( + nativeAssetsYaml.readAsStringSync(), + stringContainsInOrder(<String>[ + 'package:foo/foo.dart', + 'libfoo.dylib', + ]), + ); + }, + ); +} diff --git a/packages/flutter_tools/test/general.shard/compile_batch_test.dart b/packages/flutter_tools/test/general.shard/compile_batch_test.dart index 0b17a694bf446..e82fb93fe600e 100644 --- a/packages/flutter_tools/test/general.shard/compile_batch_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_batch_test.dart @@ -435,4 +435,55 @@ void main() { completer.complete(); await output; }); + + testWithoutContext('KernelCompiler passes native assets', () async { + final BufferLogger logger = BufferLogger.test(); + final StdoutHandler stdoutHandler = StdoutHandler(logger: logger, fileSystem: MemoryFileSystem.test()); + final Completer<void> completer = Completer<void>(); + + final KernelCompiler kernelCompiler = KernelCompiler( + artifacts: Artifacts.test(), + fileSystem: MemoryFileSystem.test(), + fileSystemRoots: <String>[], + fileSystemScheme: '', + logger: logger, + processManager: FakeProcessManager.list(<FakeCommand>[ + FakeCommand(command: const <String>[ + 'Artifact.engineDartBinary', + '--disable-dart-dev', + 'Artifact.frontendServerSnapshotForEngineDartSdk', + '--sdk-root', + '/path/to/sdkroot/', + '--target=flutter', + '--no-print-incremental-dependencies', + '-Ddart.vm.profile=false', + '-Ddart.vm.product=false', + '--enable-asserts', + '--no-link-platform', + '--packages', + '.packages', + '--native-assets', + 'path/to/native_assets.yaml', + '--verbosity=error', + 'file:///path/to/main.dart', + ], completer: completer), + ]), + stdoutHandler: stdoutHandler, + ); + final Future<CompilerOutput?> output = kernelCompiler.compile( + sdkRoot: '/path/to/sdkroot', + mainPath: '/path/to/main.dart', + buildMode: BuildMode.debug, + trackWidgetCreation: false, + dartDefines: const <String>[], + packageConfig: PackageConfig.empty, + packagesPath: '.packages', + nativeAssets: 'path/to/native_assets.yaml', + ); + stdoutHandler.compilerOutput + ?.complete(const CompilerOutput('', 0, <Uri>[])); + completer.complete(); + + expect((await output)?.outputFilename, ''); + }); } diff --git a/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart b/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart index 981ead6085bce..fd18c1ce27219 100644 --- a/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart +++ b/packages/flutter_tools/test/general.shard/custom_devices/custom_device_test.dart @@ -644,6 +644,7 @@ class FakeBundleBuilder extends Fake implements BundleBuilder { String? applicationKernelFilePath, String? depfilePath, String? assetDirPath, + Uri? nativeAssets, @visibleForTesting BuildSystem? buildSystem }) async {} } diff --git a/packages/flutter_tools/test/general.shard/devfs_test.dart b/packages/flutter_tools/test/general.shard/devfs_test.dart index 1f02688181abe..d4b4e5fcf1098 100644 --- a/packages/flutter_tools/test/general.shard/devfs_test.dart +++ b/packages/flutter_tools/test/general.shard/devfs_test.dart @@ -702,7 +702,18 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { Future<CompilerOutput> Function(Uri mainUri, List<Uri>? invalidatedFiles)? onRecompile; @override - Future<CompilerOutput> recompile(Uri mainUri, List<Uri>? invalidatedFiles, {String? outputPath, PackageConfig? packageConfig, String? projectRootPath, FileSystem? fs, bool suppressErrors = false, bool checkDartPluginRegistry = false, File? dartPluginRegistrant}) { + Future<CompilerOutput> recompile( + Uri mainUri, + List<Uri>? invalidatedFiles, { + String? outputPath, + PackageConfig? packageConfig, + String? projectRootPath, + FileSystem? fs, + bool suppressErrors = false, + bool checkDartPluginRegistry = false, + File? dartPluginRegistrant, + Uri? nativeAssetsYaml, + }) { return onRecompile?.call(mainUri, invalidatedFiles) ?? Future<CompilerOutput>.value(const CompilerOutput('', 1, <Uri>[])); } diff --git a/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart b/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart new file mode 100644 index 0000000000000..bcdd74c2d8b52 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart @@ -0,0 +1,91 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_tools/src/native_assets.dart'; +import 'package:native_assets_builder/native_assets_builder.dart' + as native_assets_builder; +import 'package:native_assets_cli/native_assets_cli.dart'; +import 'package:package_config/package_config_types.dart'; + +/// Mocks all logic instead of using `package:native_assets_builder`, which +/// relies on doing process calls to `pub` and the local file system. +class FakeNativeAssetsBuildRunner implements NativeAssetsBuildRunner { + FakeNativeAssetsBuildRunner({ + this.hasPackageConfigResult = true, + this.packagesWithNativeAssetsResult = const <Package>[], + this.dryRunResult = const FakeNativeAssetsBuilderResult(), + this.buildResult = const FakeNativeAssetsBuilderResult(), + CCompilerConfig? cCompilerConfigResult, + }) : cCompilerConfigResult = cCompilerConfigResult ?? CCompilerConfig(); + + final native_assets_builder.BuildResult buildResult; + final native_assets_builder.DryRunResult dryRunResult; + final bool hasPackageConfigResult; + final List<Package> packagesWithNativeAssetsResult; + final CCompilerConfig cCompilerConfigResult; + + int buildInvocations = 0; + int dryRunInvocations = 0; + int hasPackageConfigInvocations = 0; + int packagesWithNativeAssetsInvocations = 0; + + @override + Future<native_assets_builder.BuildResult> build({ + required bool includeParentEnvironment, + required BuildMode buildMode, + required LinkModePreference linkModePreference, + required Target target, + required Uri workingDirectory, + CCompilerConfig? cCompilerConfig, + int? targetAndroidNdkApi, + IOSSdk? targetIOSSdk, + }) async { + buildInvocations++; + return buildResult; + } + + @override + Future<native_assets_builder.DryRunResult> dryRun({ + required bool includeParentEnvironment, + required LinkModePreference linkModePreference, + required OS targetOs, + required Uri workingDirectory, + }) async { + dryRunInvocations++; + return dryRunResult; + } + + @override + Future<bool> hasPackageConfig() async { + hasPackageConfigInvocations++; + return hasPackageConfigResult; + } + + @override + Future<List<Package>> packagesWithNativeAssets() async { + packagesWithNativeAssetsInvocations++; + return packagesWithNativeAssetsResult; + } + + @override + Future<CCompilerConfig> get cCompilerConfig async => cCompilerConfigResult; +} + +final class FakeNativeAssetsBuilderResult + implements native_assets_builder.BuildResult { + const FakeNativeAssetsBuilderResult({ + this.assets = const <Asset>[], + this.dependencies = const <Uri>[], + this.success = true, + }); + + @override + final List<Asset> assets; + + @override + final List<Uri> dependencies; + + @override + final bool success; +} diff --git a/packages/flutter_tools/test/general.shard/features_test.dart b/packages/flutter_tools/test/general.shard/features_test.dart index f15220e90b542..07d870b0f5363 100644 --- a/packages/flutter_tools/test/general.shard/features_test.dart +++ b/packages/flutter_tools/test/general.shard/features_test.dart @@ -400,5 +400,13 @@ void main() { }); } + test('${nativeAssets.name} availability and default enabled', () { + expect(nativeAssets.master.enabledByDefault, false); + expect(nativeAssets.master.available, true); + expect(nativeAssets.beta.enabledByDefault, false); + expect(nativeAssets.beta.available, false); + expect(nativeAssets.stable.enabledByDefault, false); + expect(nativeAssets.stable.available, false); + }); }); } diff --git a/packages/flutter_tools/test/general.shard/flutter_project_metadata_test.dart b/packages/flutter_tools/test/general.shard/flutter_project_metadata_test.dart index f0033b9e871cf..6e2970faf8b90 100644 --- a/packages/flutter_tools/test/general.shard/flutter_project_metadata_test.dart +++ b/packages/flutter_tools/test/general.shard/flutter_project_metadata_test.dart @@ -5,10 +5,13 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/flutter_project_metadata.dart'; import 'package:flutter_tools/src/project.dart'; import '../src/common.dart'; +import '../src/context.dart'; +import '../src/fakes.dart'; void main() { late FileSystem fileSystem; @@ -184,4 +187,16 @@ migration: expect(logger.traceText, contains('The key `create_revision` was not found')); }); + + testUsingContext('enabledValues does not contain packageFfi if native-assets not enabled', () { + expect(FlutterProjectType.enabledValues, isNot(contains(FlutterProjectType.packageFfi))); + expect(FlutterProjectType.enabledValues, contains(FlutterProjectType.plugin)); + }); + + testUsingContext('enabledValues contains packageFfi if natives-assets enabled', () { + expect(FlutterProjectType.enabledValues, contains(FlutterProjectType.packageFfi)); + expect(FlutterProjectType.enabledValues, contains(FlutterProjectType.plugin)); + }, overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + }); } diff --git a/packages/flutter_tools/test/general.shard/hot_test.dart b/packages/flutter_tools/test/general.shard/hot_test.dart index b8be90ff0b46a..b30361d367655 100644 --- a/packages/flutter_tools/test/general.shard/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/hot_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - - import 'package:file/memory.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/artifacts.dart'; @@ -16,12 +14,15 @@ import 'package:flutter_tools/src/build_system/targets/shader_compiler.dart'; import 'package:flutter_tools/src/compile.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; +import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_devtools_handler.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/vmservice.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; import 'package:package_config/package_config.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -29,6 +30,7 @@ import 'package:vm_service/vm_service.dart' as vm_service; import '../src/common.dart'; import '../src/context.dart'; import '../src/fakes.dart'; +import 'fake_native_assets_build_runner.dart'; void main() { group('validateReloadReport', () { @@ -548,6 +550,134 @@ void main() { expect(flutterDevice2.stoppedEchoingDeviceLog, true); }); }); + + group('native assets', () { + late TestHotRunnerConfig testingConfig; + late FileSystem fileSystem; + + setUp(() { + fileSystem = MemoryFileSystem.test(); + testingConfig = TestHotRunnerConfig( + successfulHotRestartSetup: true, + ); + }); + testUsingContext('native assets restart', () async { + final FakeDevice device = FakeDevice(); + final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); + final List<FlutterDevice> devices = <FlutterDevice>[ + fakeFlutterDevice, + ]; + + fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( + success: true, + invalidatedSourcesCount: 6, + syncedBytes: 8, + scannedSourcesCount: 16, + compileDuration: const Duration(seconds: 16), + transferDuration: const Duration(seconds: 32), + ); + + (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); + + final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', fileSystem.currentDirectory.uri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ); + + final HotRunner hotRunner = HotRunner( + devices, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + buildRunner: buildRunner, + ); + final OperationResult result = await hotRunner.restart(fullRestart: true); + expect(result.isOk, true); + // Hot restart does not require reruning anything for native assets. + // The previous native assets mapping should be used. + expect(buildRunner.buildInvocations, 0); + expect(buildRunner.dryRunInvocations, 0); + expect(buildRunner.hasPackageConfigInvocations, 0); + expect(buildRunner.packagesWithNativeAssetsInvocations, 0); + }, overrides: <Type, Generator>{ + HotRunnerConfig: () => testingConfig, + Artifacts: () => Artifacts.test(), + FileSystem: () => fileSystem, + Platform: () => FakePlatform(), + ProcessManager: () => FakeProcessManager.empty(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), + }); + + testUsingContext('native assets run unsupported', () async { + final FakeDevice device = FakeDevice(targetPlatform: TargetPlatform.android_arm64); + final FakeFlutterDevice fakeFlutterDevice = FakeFlutterDevice(device); + final List<FlutterDevice> devices = <FlutterDevice>[ + fakeFlutterDevice, + ]; + + fakeFlutterDevice.updateDevFSReportCallback = () async => UpdateFSReport( + success: true, + invalidatedSourcesCount: 6, + syncedBytes: 8, + scannedSourcesCount: 16, + compileDuration: const Duration(seconds: 16), + transferDuration: const Duration(seconds: 32), + ); + + (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); + + final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', fileSystem.currentDirectory.uri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ); + + final HotRunner hotRunner = HotRunner( + devices, + debuggingOptions: DebuggingOptions.disabled(BuildInfo.debug), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + buildRunner: buildRunner, + ); + expect( + () => hotRunner.run(), + throwsToolExit( message: + 'Package(s) bar require the native assets feature. ' + 'This feature has not yet been implemented for `TargetPlatform.android_arm64`. ' + 'For more info see https://github.com/flutter/flutter/issues/129757.', + ) + ); + + }, overrides: <Type, Generator>{ + HotRunnerConfig: () => testingConfig, + Artifacts: () => Artifacts.test(), + FileSystem: () => fileSystem, + Platform: () => FakePlatform(), + ProcessManager: () => FakeProcessManager.empty(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), + }); + }); } class FakeDevFs extends Fake implements DevFS { @@ -580,6 +710,12 @@ class FakeDevFs extends Fake implements DevFS { // Until we fix that, we have to also ignore related lints here. // ignore: avoid_implementing_value_types class FakeDevice extends Fake implements Device { + FakeDevice({ + TargetPlatform targetPlatform = TargetPlatform.tester, + }) : _targetPlatform = targetPlatform; + + final TargetPlatform _targetPlatform; + bool disposed = false; @override @@ -595,7 +731,7 @@ class FakeDevice extends Fake implements Device { bool supportsFlutterExit = true; @override - Future<TargetPlatform> get targetPlatform async => TargetPlatform.tester; + Future<TargetPlatform> get targetPlatform async => _targetPlatform; @override Future<String> get sdkNameAndVersion async => 'Tester'; @@ -658,6 +794,9 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { required List<Uri> invalidatedFiles, required PackageConfig packageConfig, }) => updateDevFSReportCallback(); + + @override + TargetPlatform? get targetPlatform => device._targetPlatform; } class TestFlutterDevice extends FlutterDevice { diff --git a/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart b/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart new file mode 100644 index 0000000000000..0a6b7805785b6 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart @@ -0,0 +1,274 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/ios/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; +import 'package:package_config/package_config_types.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fakes.dart'; +import '../fake_native_assets_build_runner.dart'; + +void main() { + late FakeProcessManager processManager; + late Environment environment; + late Artifacts artifacts; + late FileSystem fileSystem; + late BufferLogger logger; + late Uri projectUri; + + setUp(() { + processManager = FakeProcessManager.empty(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + fileSystem = MemoryFileSystem.test(); + environment = Environment.test( + fileSystem.currentDirectory, + inputs: <String, String>{}, + artifacts: artifacts, + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + environment.buildDir.createSync(recursive: true); + projectUri = environment.projectDir.uri; + }); + + testUsingContext('dry run with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + expect( + await dryRunNativeAssetsIOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ), + null, + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('build with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await buildNativeAssetsIOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + environmentType: EnvironmentType.simulator, + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + yamlParentDirectory: environment.buildDir.uri, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsIOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('dry run with assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final Uri? nativeAssetsYaml = await dryRunNativeAssetsIOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSX64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/ios/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + contains('package:bar/bar.dart'), + ); + }); + + testUsingContext('build with assets but not enabled', () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => buildNativeAssetsIOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + environmentType: EnvironmentType.simulator, + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + yamlParentDirectory: environment.buildDir.uri, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('build no assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + await buildNativeAssetsIOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + environmentType: EnvironmentType.simulator, + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + yamlParentDirectory: environment.buildDir.uri, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ); + expect( + environment.buildDir.childFile('native_assets.yaml'), + exists, + ); + }); + + testUsingContext('build with assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + <FakeCommand>[ + const FakeCommand( + command: <Pattern>[ + 'lipo', + '-create', + '-output', + '/build/native_assets/ios/bar.dylib', + 'bar.dylib', + ], + ), + const FakeCommand( + command: <Pattern>[ + 'install_name_tool', + '-id', + '@executable_path/Frameworks/bar.dylib', + '/build/native_assets/ios/bar.dylib', + ], + ), + const FakeCommand( + command: <Pattern>[ + 'codesign', + '--force', + '--sign', + '-', + '--timestamp=none', + '/build/native_assets/ios/bar.dylib', + ], + ), + ], + ), + }, () async { + if (const LocalPlatform().isWindows) { + return; // Backslashes in commands, but we will never run these commands on Windows. + } + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + await buildNativeAssetsIOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + environmentType: EnvironmentType.simulator, + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + yamlParentDirectory: environment.buildDir.uri, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + buildResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ), + ); + expect( + environment.buildDir.childFile('native_assets.yaml'), + exists, + ); + }); +} diff --git a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart new file mode 100644 index 0000000000000..8c9e865c8d7f2 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart @@ -0,0 +1,385 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/macos/native_assets.dart'; +import 'package:flutter_tools/src/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; +import 'package:package_config/package_config_types.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fakes.dart'; +import '../fake_native_assets_build_runner.dart'; + +void main() { + late FakeProcessManager processManager; + late Environment environment; + late Artifacts artifacts; + late FileSystem fileSystem; + late BufferLogger logger; + late Uri projectUri; + + setUp(() { + processManager = FakeProcessManager.empty(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + fileSystem = MemoryFileSystem.test(); + environment = Environment.test( + fileSystem.currentDirectory, + inputs: <String, String>{}, + artifacts: artifacts, + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + environment.buildDir.createSync(recursive: true); + projectUri = environment.projectDir.uri; + }); + + testUsingContext('dry run with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + expect( + await dryRunNativeAssetsMacOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ), + null, + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('build with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await buildNativeAssetsMacOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run for multiple OSes with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await dryRunNativeAssetsMultipeOSes( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: <TargetPlatform>[ + TargetPlatform.darwin, + TargetPlatform.ios, + ], + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsMacOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('dry run with assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final Uri? nativeAssetsYaml = await dryRunNativeAssetsMacOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSX64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/macos/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + contains('package:bar/bar.dart'), + ); + }); + + testUsingContext('build with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => buildNativeAssetsMacOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('build no assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsMacOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/macos/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + isNot(contains('package:bar/bar.dart')), + ); + }); + + for (final bool flutterTester in <bool>[false, true]) { + String testName = ''; + if (flutterTester) { + testName += ' flutter tester'; + } + testUsingContext('build with assets$testName', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + <FakeCommand>[ + const FakeCommand( + command: <Pattern>[ + 'lipo', + '-create', + '-output', + '/build/native_assets/macos/bar.dylib', + 'bar.dylib', + ], + ), + const FakeCommand( + command: <Pattern>[ + 'install_name_tool', + '-id', + '@executable_path/Frameworks/bar.dylib', + '/build/native_assets/macos/bar.dylib', + ], + ), + const FakeCommand( + command: <Pattern>[ + 'codesign', + '--force', + '--sign', + '-', + '--timestamp=none', + '/build/native_assets/macos/bar.dylib', + ], + ), + ], + ), + }, () async { + if (const LocalPlatform().isWindows) { + return; // Backslashes in commands, but we will never run these commands on Windows. + } + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsMacOS( + darwinArchs: <DarwinArch>[DarwinArch.arm64], + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + flutterTester: flutterTester, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + buildResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/macos/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + stringContainsInOrder(<String>[ + 'package:bar/bar.dart', + if (flutterTester) + // Tests run on host system, so the have the full path on the system. + '- ${projectUri.resolve('/build/native_assets/macos/bar.dylib').toFilePath()}' + else + // Apps are a bundle with the dylibs on their dlopen path. + '- bar.dylib', + ]), + ); + }); + } + + testUsingContext('static libs not supported', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsMacOS( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.a')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.macOSX64, + path: AssetAbsolutePath(Uri.file('bar.a')), + ), + ], + ), + ), + ), + throwsToolExit( + message: 'Native asset(s) package:bar/bar.dart have their link mode set to ' + 'static, but this is not yet supported. ' + 'For more info see https://github.com/dart-lang/sdk/issues/49418.', + ), + ); + }); + + // This logic is mocked in the other tests to avoid having test order + // randomization causing issues with what processes are invoked. + // Exercise the parsing of the process output in this separate test. + testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + <FakeCommand>[ + const FakeCommand( + command: <Pattern>['xcrun', 'clang', '--version'], + stdout: ''' +Apple clang version 14.0.0 (clang-1400.0.29.202) +Target: arm64-apple-darwin22.6.0 +Thread model: posix +InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin''', + ) + ], + ), + }, () async { + if (!const LocalPlatform().isMacOS) { + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + return; + } + + final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl(projectUri, fileSystem, logger); + final CCompilerConfig result = await runner.cCompilerConfig; + expect( + result.cc, + Uri.file( + '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang', + ), + ); + }); +} diff --git a/packages/flutter_tools/test/general.shard/preview_device_test.dart b/packages/flutter_tools/test/general.shard/preview_device_test.dart index fa94d8600f366..876dbc64950ad 100644 --- a/packages/flutter_tools/test/general.shard/preview_device_test.dart +++ b/packages/flutter_tools/test/general.shard/preview_device_test.dart @@ -99,6 +99,7 @@ class FakeBundleBuilder extends Fake implements BundleBuilder { String? applicationKernelFilePath, String? depfilePath, String? assetDirPath, + Uri? nativeAssets, @visibleForTesting BuildSystem? buildSystem }) async { final Directory assetDirectory = fileSystem diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index bd93c7c85fca5..42b8dafb90d04 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -18,6 +18,7 @@ import 'package:flutter_tools/src/base/io.dart' as io; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/targets/scene_importer.dart'; import 'package:flutter_tools/src/build_system/targets/shader_compiler.dart'; import 'package:flutter_tools/src/compile.dart'; @@ -25,6 +26,7 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/devfs.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/device_port_forwarder.dart'; +import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; @@ -34,6 +36,9 @@ import 'package:flutter_tools/src/run_cold.dart'; import 'package:flutter_tools/src/run_hot.dart'; import 'package:flutter_tools/src/version.dart'; import 'package:flutter_tools/src/vmservice.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' + hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; import 'package:package_config/package_config.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart' as vm_service; @@ -43,6 +48,7 @@ import '../src/context.dart'; import '../src/fake_vm_services.dart'; import '../src/fakes.dart'; import '../src/testbed.dart'; +import 'fake_native_assets_build_runner.dart'; final vm_service.Event fakeUnpausedEvent = vm_service.Event( kind: vm_service.EventKind.kResume, @@ -2322,6 +2328,82 @@ flutter: expect(flutterDevice.devFS!.hasSetAssetDirectory, true); expect(fakeVmServiceHost!.hasRemainingExpectations, false); })); + + testUsingContext( + 'native assets', + () => testbed.run(() async { + final FileSystem fileSystem = globals.fs; + final Environment environment = Environment.test( + fileSystem.currentDirectory, + inputs: <String, String>{}, + artifacts: Artifacts.test(), + processManager: FakeProcessManager.empty(), + fileSystem: fileSystem, + logger: BufferLogger.test(), + ); + final Uri projectUri = environment.projectDir.uri; + + final FakeDevice device = FakeDevice( + targetPlatform: TargetPlatform.darwin, + sdkNameAndVersion: 'Macos', + ); + final FakeFlutterDevice flutterDevice = FakeFlutterDevice() + ..testUri = testUri + ..vmServiceHost = (() => fakeVmServiceHost) + ..device = device + .._devFS = devFS + ..targetPlatform = TargetPlatform.darwin; + + fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[ + listViews, + listViews, + ]); + globals.fs + .file(globals.fs.path.join('lib', 'main.dart')) + .createSync(recursive: true); + final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.dylib')), + ), + ], + ), + ); + residentRunner = HotRunner( + <FlutterDevice>[ + flutterDevice, + ], + stayResident: false, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + trackWidgetCreation: true, + )), + target: 'main.dart', + devtoolsHandler: createNoOpHandler, + buildRunner: buildRunner, + ); + + final int? result = await residentRunner.run(); + expect(result, 0); + + expect(buildRunner.buildInvocations, 0); + expect(buildRunner.dryRunInvocations, 1); + expect(buildRunner.hasPackageConfigInvocations, 1); + expect(buildRunner.packagesWithNativeAssetsInvocations, 0); + }), + overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.any(), + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true, isMacOSEnabled: true), + }); } // This implements [dds.DartDevelopmentService], not the [DartDevelopmentService] @@ -2386,7 +2468,7 @@ class FakeFlutterDevice extends Fake implements FlutterDevice { DevelopmentShaderCompiler get developmentShaderCompiler => const FakeShaderCompiler(); @override - TargetPlatform get targetPlatform => TargetPlatform.android; + TargetPlatform targetPlatform = TargetPlatform.android; @override Stream<Uri?> get vmServiceUris => Stream<Uri?>.value(testUri); @@ -2521,6 +2603,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { bool suppressErrors = false, bool checkDartPluginRegistry = false, File? dartPluginRegistrant, + Uri? nativeAssetsYaml, }) async { didSuppressErrors = suppressErrors; return nextOutput ?? const CompilerOutput('foo.dill', 0, <Uri>[]); diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 01a1f098ed9bc..4fc88ae771b6a 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -1444,6 +1444,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { bool suppressErrors = false, bool checkDartPluginRegistry = false, File? dartPluginRegistrant, + Uri? nativeAssetsYaml, }) async { return const CompilerOutput('foo.dill', 0, <Uri>[]); } diff --git a/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart b/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart index 7aa5bbb4ddaa3..429e94890d743 100644 --- a/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart +++ b/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart @@ -234,6 +234,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { bool suppressErrors = false, bool checkDartPluginRegistry = false, File? dartPluginRegistrant, + Uri? nativeAssetsYaml, }) async { if (compilerOutput != null) { fileSystem!.file(compilerOutput!.outputFilename).createSync(recursive: true); diff --git a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart index 6cc826e7deed0..165075e067fb7 100644 --- a/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart +++ b/packages/flutter_tools/test/general.shard/tester/flutter_tester_test.dart @@ -98,7 +98,6 @@ void main() { artifacts: Artifacts.test(), logger: BufferLogger.test(), flutterVersion: FakeFlutterVersion(), - operatingSystemUtils: FakeOperatingSystemUtils(), ); logLines = <String>[]; device.getLogReader().logLines.listen(logLines.add); @@ -213,7 +212,6 @@ FlutterTesterDevices setUpFlutterTesterDevices() { processManager: FakeProcessManager.any(), fileSystem: MemoryFileSystem.test(), flutterVersion: FakeFlutterVersion(), - operatingSystemUtils: FakeOperatingSystemUtils(), ); } diff --git a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart index e457408c05f08..6936829941b06 100644 --- a/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart +++ b/packages/flutter_tools/test/general.shard/web/devfs_web_test.dart @@ -1190,6 +1190,7 @@ class FakeResidentCompiler extends Fake implements ResidentCompiler { bool suppressErrors = false, bool checkDartPluginRegistry = false, File? dartPluginRegistrant, + Uri? nativeAssetsYaml, }) async { return output; } diff --git a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart index 3b3de5f7921ee..c35287c6e048d 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart @@ -254,6 +254,7 @@ void main() { 'VERBOSE_SCRIPT_LOGGING': '1', 'FLUTTER_BUILD_MODE': 'release', 'ACTION': 'install', + 'FLUTTER_BUILD_DIR': 'build', // Skip bitcode stripping since we just checked that above. }, ); diff --git a/packages/flutter_tools/test/integration.shard/native_assets_test.dart b/packages/flutter_tools/test/integration.shard/native_assets_test.dart new file mode 100644 index 0000000000000..e539e74a27a75 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/native_assets_test.dart @@ -0,0 +1,360 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This test exercises the embedding of the native assets mapping in dill files. +// An initial dill file is created by `flutter assemble` and used for running +// the application. This dill must contain the mapping. +// When doing hot reload, this mapping must stay in place. +// When doing a hot restart, a new dill file is pushed. This dill file must also +// contain the native assets mapping. +// When doing a hot reload, this mapping must stay in place. + +@Timeout(Duration(minutes: 10)) +library; + +import 'dart:io'; + +import 'package:file/file.dart'; +import 'package:file_testing/file_testing.dart'; + +import '../src/common.dart'; +import 'test_utils.dart' show fileSystem, platform; +import 'transition_test_utils.dart'; + +final String hostOs = platform.operatingSystem; + +final List<String> devices = <String>[ + 'flutter-tester', + hostOs, +]; + +final List<String> buildSubcommands = <String>[ + hostOs, + if (hostOs == 'macos') 'ios', +]; + +final List<String> add2appBuildSubcommands = <String>[ + if (hostOs == 'macos') ...<String>[ + 'macos-framework', + 'ios-framework', + ], +]; + +/// The build modes to target for each flutter command that supports passing +/// a build mode. +/// +/// The flow of compiling kernel as well as bundling dylibs can differ based on +/// build mode, so we should cover this. +const List<String> buildModes = <String>[ + 'debug', + 'profile', + 'release', +]; + +const String packageName = 'package_with_native_assets'; + +const String exampleAppName = '${packageName}_example'; + +const String dylibName = 'lib$packageName.dylib'; + +void main() { + if (!platform.isMacOS) { + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + return; + } + + setUpAll(() { + processManager.runSync(<String>[ + flutterBin, + 'config', + '--enable-native-assets', + ]); + }); + + for (final String device in devices) { + for (final String buildMode in buildModes) { + if (device == 'flutter-tester' && buildMode != 'debug') { + continue; + } + final String hotReload = buildMode == 'debug' ? ' hot reload and hot restart' : ''; + testWithoutContext('flutter run$hotReload with native assets $device $buildMode', () async { + await inTempDir((Directory tempDirectory) async { + final Directory packageDirectory = await createTestProject(packageName, tempDirectory); + final Directory exampleDirectory = packageDirectory.childDirectory('example'); + + final ProcessTestResult result = await runFlutter( + <String>[ + 'run', + '-d$device', + '--$buildMode', + ], + exampleDirectory.path, + <Transition>[ + Multiple(<Pattern>[ + 'Flutter run key commands.', + ], handler: (String line) { + if (buildMode == 'debug') { + // Do a hot reload diff on the initial dill file. + return 'r'; + } else { + // No hot reload and hot restart in release mode. + return 'q'; + } + }), + if (buildMode == 'debug') ...<Transition>[ + Barrier( + 'Performing hot reload...'.padRight(progressMessageWidth), + logging: true, + ), + Multiple(<Pattern>[ + RegExp('Reloaded .*'), + ], handler: (String line) { + // Do a hot restart, pushing a new complete dill file. + return 'R'; + }), + Barrier('Performing hot restart...'.padRight(progressMessageWidth)), + Multiple(<Pattern>[ + RegExp('Restarted application .*'), + ], handler: (String line) { + // Do another hot reload, pushing a diff to the second dill file. + return 'r'; + }), + Barrier( + 'Performing hot reload...'.padRight(progressMessageWidth), + logging: true, + ), + Multiple(<Pattern>[ + RegExp('Reloaded .*'), + ], handler: (String line) { + return 'q'; + }), + ], + const Barrier('Application finished.'), + ], + logging: false, + ); + if (result.exitCode != 0) { + throw Exception('flutter run failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}'); + } + final String stdout = result.stdout.join('\n'); + // Check that we did not fail to resolve the native function in the + // dynamic library. + expect(stdout, isNot(contains("Invalid argument(s): Couldn't resolve native function 'sum'"))); + // And also check that we did not have any other exceptions that might + // shadow the exception we would have gotten. + expect(stdout, isNot(contains('EXCEPTION CAUGHT BY WIDGETS LIBRARY'))); + + if (device == 'macos') { + expectDylibIsBundledMacOS(exampleDirectory, buildMode); + } + if (device == hostOs) { + expectCCompilerIsConfigured(exampleDirectory); + } + }); + }); + } + } + + testWithoutContext('flutter test with native assets', () async { + await inTempDir((Directory tempDirectory) async { + final Directory packageDirectory = await createTestProject(packageName, tempDirectory); + + final ProcessTestResult result = await runFlutter( + <String>[ + 'test', + ], + packageDirectory.path, + <Transition>[ + Barrier(RegExp('.* All tests passed!')), + ], + logging: false, + ); + if (result.exitCode != 0) { + throw Exception('flutter test failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}'); + } + }); + }); + + for (final String buildSubcommand in buildSubcommands) { + for (final String buildMode in buildModes) { + testWithoutContext('flutter build $buildSubcommand with native assets $buildMode', () async { + await inTempDir((Directory tempDirectory) async { + final Directory packageDirectory = await createTestProject(packageName, tempDirectory); + final Directory exampleDirectory = packageDirectory.childDirectory('example'); + + final ProcessResult result = processManager.runSync( + <String>[ + flutterBin, + 'build', + buildSubcommand, + '--$buildMode', + if (buildSubcommand == 'ios') '--no-codesign', + ], + workingDirectory: exampleDirectory.path, + ); + if (result.exitCode != 0) { + throw Exception('flutter build failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}'); + } + + if (buildSubcommand == 'macos') { + expectDylibIsBundledMacOS(exampleDirectory, buildMode); + } else if (buildSubcommand == 'ios') { + expectDylibIsBundledIos(exampleDirectory, buildMode); + } + expectCCompilerIsConfigured(exampleDirectory); + }); + }); + } + + // This could be an hermetic unit test if the native_assets_builder + // could mock process runs and file system. + // https://github.com/dart-lang/native/issues/90. + testWithoutContext('flutter build $buildSubcommand error on static libraries', () async { + await inTempDir((Directory tempDirectory) async { + final Directory packageDirectory = await createTestProject(packageName, tempDirectory); + final File buildDotDart = packageDirectory.childFile('build.dart'); + final String buildDotDartContents = await buildDotDart.readAsString(); + // Overrides the build to output static libraries. + final String buildDotDartContentsNew = buildDotDartContents.replaceFirst( + 'final buildConfig = await BuildConfig.fromArgs(args);', + r''' + final buildConfig = await BuildConfig.fromArgs([ + '-D${LinkModePreference.configKey}=${LinkModePreference.static}', + ...args, + ]); +''', + ); + expect(buildDotDartContentsNew, isNot(buildDotDartContents)); + await buildDotDart.writeAsString(buildDotDartContentsNew); + final Directory exampleDirectory = packageDirectory.childDirectory('example'); + + final ProcessResult result = processManager.runSync( + <String>[ + flutterBin, + 'build', + buildSubcommand, + if (buildSubcommand == 'ios') '--no-codesign', + ], + workingDirectory: exampleDirectory.path, + ); + expect(result.exitCode, isNot(0)); + expect(result.stderr, contains('link mode set to static, but this is not yet supported')); + }); + }); + } + + for (final String add2appBuildSubcommand in add2appBuildSubcommands) { + testWithoutContext('flutter build $add2appBuildSubcommand with native assets', () async { + await inTempDir((Directory tempDirectory) async { + final Directory packageDirectory = await createTestProject(packageName, tempDirectory); + final Directory exampleDirectory = packageDirectory.childDirectory('example'); + + final ProcessResult result = processManager.runSync( + <String>[ + flutterBin, + 'build', + add2appBuildSubcommand, + ], + workingDirectory: exampleDirectory.path, + ); + if (result.exitCode != 0) { + throw Exception('flutter build failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}'); + } + + for (final String buildMode in buildModes) { + expectDylibIsBundledWithFrameworks(exampleDirectory, buildMode, add2appBuildSubcommand.replaceAll('-framework', '')); + } + expectCCompilerIsConfigured(exampleDirectory); + }); + }); + } +} + +/// For `flutter build` we can't easily test whether running the app works. +/// Check that we have the dylibs in the app. +void expectDylibIsBundledMacOS(Directory appDirectory, String buildMode) { + final Directory appBundle = appDirectory.childDirectory('build/$hostOs/Build/Products/${buildMode.upperCaseFirst()}/$exampleAppName.app'); + expect(appBundle, exists); + final Directory dylibsFolder = appBundle.childDirectory('Contents/Frameworks'); + expect(dylibsFolder, exists); + final File dylib = dylibsFolder.childFile(dylibName); + expect(dylib, exists); +} + +void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { + final Directory appBundle = appDirectory.childDirectory('build/ios/${buildMode.upperCaseFirst()}-iphoneos/Runner.app'); + expect(appBundle, exists); + final Directory dylibsFolder = appBundle.childDirectory('Frameworks'); + expect(dylibsFolder, exists); + final File dylib = dylibsFolder.childFile(dylibName); + expect(dylib, exists); +} + +/// For `flutter build` we can't easily test whether running the app works. +/// Check that we have the dylibs in the app. +void expectDylibIsBundledWithFrameworks(Directory appDirectory, String buildMode, String os) { + final Directory frameworksFolder = appDirectory.childDirectory('build/$os/framework/${buildMode.upperCaseFirst()}'); + expect(frameworksFolder, exists); + final File dylib = frameworksFolder.childFile(dylibName); + expect(dylib, exists); +} + +/// Check that the native assets are built with the C Compiler that Flutter uses. +/// +/// This inspects the build configuration to see if the C compiler was configured. +void expectCCompilerIsConfigured(Directory appDirectory) { + final Directory nativeAssetsBuilderDir = appDirectory.childDirectory('.dart_tool/native_assets_builder/'); + for (final Directory subDir in nativeAssetsBuilderDir.listSync().whereType<Directory>()) { + final File config = subDir.childFile('config.yaml'); + expect(config, exists); + final String contents = config.readAsStringSync(); + // Dry run does not pass compiler info. + if (contents.contains('dry_run: true')) { + continue; + } + expect(contents, contains('cc: ')); + } +} + +extension on String { + String upperCaseFirst() { + return replaceFirst(this[0], this[0].toUpperCase()); + } +} + +Future<Directory> createTestProject(String packageName, Directory tempDirectory) async { + final ProcessResult result = processManager.runSync( + <String>[ + flutterBin, + 'create', + '--template=package_ffi', + packageName, + ], + workingDirectory: tempDirectory.path, + ); + + if (result.exitCode != 0) { + throw Exception('flutter create failed: ${result.exitCode}\n${result.stderr}\n${result.stdout}'); + } + + final Directory packageDirectory = tempDirectory.childDirectory(packageName); + + // No platform-specific boilerplate files. + expect(packageDirectory.childDirectory('android/'), isNot(exists)); + expect(packageDirectory.childDirectory('ios/'), isNot(exists)); + expect(packageDirectory.childDirectory('linux/'), isNot(exists)); + expect(packageDirectory.childDirectory('macos/'), isNot(exists)); + expect(packageDirectory.childDirectory('windows/'), isNot(exists)); + + return packageDirectory; +} + +Future<void> inTempDir(Future<void> Function(Directory tempDirectory) fun) async { + final Directory tempDirectory = fileSystem.directory(fileSystem.systemTempDirectory.createTempSync().resolveSymbolicLinksSync()); + try { + await fun(tempDirectory); + } finally { + tryToDelete(tempDirectory); + } +} diff --git a/packages/flutter_tools/test/integration.shard/overall_experience_test.dart b/packages/flutter_tools/test/integration.shard/overall_experience_test.dart index e9071b5a5573c..8cc4fff7e374e 100644 --- a/packages/flutter_tools/test/integration.shard/overall_experience_test.dart +++ b/packages/flutter_tools/test/integration.shard/overall_experience_test.dart @@ -26,310 +26,11 @@ @Tags(<String>['no-shuffle']) library; -import 'dart:async'; -import 'dart:convert'; import 'dart:io'; -import 'package:meta/meta.dart'; -import 'package:process/process.dart'; - import '../src/common.dart'; import 'test_utils.dart' show fileSystem; - -const ProcessManager processManager = LocalProcessManager(); -final String flutterRoot = getFlutterRoot(); -final String flutterBin = fileSystem.path.join(flutterRoot, 'bin', 'flutter'); - -void debugPrint(String message) { - // This is called to intentionally print debugging output when a test is - // either taking too long or has failed. - // ignore: avoid_print - print(message); -} - -typedef LineHandler = String? Function(String line); - -abstract class Transition { - const Transition({this.handler, this.logging}); - - /// Callback that is invoked when the transition matches. - /// - /// This should not throw, even if the test is failing. (For example, don't use "expect" - /// in these callbacks.) Throwing here would prevent the [runFlutter] function from running - /// to completion, which would leave zombie `flutter` processes around. - final LineHandler? handler; - - /// Whether to enable or disable logging when this transition is matched. - /// - /// The default value, null, leaves the logging state unaffected. - final bool? logging; - - bool matches(String line); - - @protected - bool lineMatchesPattern(String line, Pattern pattern) { - if (pattern is String) { - return line == pattern; - } - return line.contains(pattern); - } - - @protected - String describe(Pattern pattern) { - if (pattern is String) { - return '"$pattern"'; - } - if (pattern is RegExp) { - return '/${pattern.pattern}/'; - } - return '$pattern'; - } -} - -class Barrier extends Transition { - const Barrier(this.pattern, {super.handler, super.logging}); - final Pattern pattern; - - @override - bool matches(String line) => lineMatchesPattern(line, pattern); - - @override - String toString() => describe(pattern); -} - -class Multiple extends Transition { - Multiple(List<Pattern> patterns, { - super.handler, - super.logging, - }) : _originalPatterns = patterns, - patterns = patterns.toList(); - - final List<Pattern> _originalPatterns; - final List<Pattern> patterns; - - @override - bool matches(String line) { - for (int index = 0; index < patterns.length; index += 1) { - if (lineMatchesPattern(line, patterns[index])) { - patterns.removeAt(index); - break; - } - } - return patterns.isEmpty; - } - - @override - String toString() { - if (patterns.isEmpty) { - return '${_originalPatterns.map(describe).join(', ')} (all matched)'; - } - return '${_originalPatterns.map(describe).join(', ')} (matched ${_originalPatterns.length - patterns.length} so far)'; - } -} - -class LogLine { - const LogLine(this.channel, this.stamp, this.message); - final String channel; - final String stamp; - final String message; - - bool get couldBeCrash => message.contains('Oops; flutter has exited unexpectedly:'); - - @override - String toString() => '$stamp $channel: $message'; - - void printClearly() { - debugPrint('$stamp $channel: ${clarify(message)}'); - } - - static String clarify(String line) { - return line.runes.map<String>((int rune) { - if (rune >= 0x20 && rune <= 0x7F) { - return String.fromCharCode(rune); - } - switch (rune) { - case 0x00: return '<NUL>'; - case 0x07: return '<BEL>'; - case 0x08: return '<TAB>'; - case 0x09: return '<BS>'; - case 0x0A: return '<LF>'; - case 0x0D: return '<CR>'; - } - return '<${rune.toRadixString(16).padLeft(rune <= 0xFF ? 2 : rune <= 0xFFFF ? 4 : 5, '0')}>'; - }).join(); - } -} - -class ProcessTestResult { - const ProcessTestResult(this.exitCode, this.logs); - final int exitCode; - final List<LogLine> logs; - - List<String> get stdout { - return logs - .where((LogLine log) => log.channel == 'stdout') - .map<String>((LogLine log) => log.message) - .toList(); - } - - List<String> get stderr { - return logs - .where((LogLine log) => log.channel == 'stderr') - .map<String>((LogLine log) => log.message) - .toList(); - } - - @override - String toString() => 'exit code $exitCode\nlogs:\n ${logs.join('\n ')}\n'; -} - -Future<ProcessTestResult> runFlutter( - List<String> arguments, - String workingDirectory, - List<Transition> transitions, { - bool debug = false, - bool logging = true, - Duration expectedMaxDuration = const Duration(minutes: 10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml. -}) async { - final Stopwatch clock = Stopwatch()..start(); - final Process process = await processManager.start( - <String>[flutterBin, ...arguments], - workingDirectory: workingDirectory, - ); - final List<LogLine> logs = <LogLine>[]; - int nextTransition = 0; - void describeStatus() { - if (transitions.isNotEmpty) { - debugPrint('Expected state transitions:'); - for (int index = 0; index < transitions.length; index += 1) { - debugPrint( - '${index.toString().padLeft(5)} ' - '${index < nextTransition ? 'ALREADY MATCHED ' : - index == nextTransition ? 'NOW WAITING FOR>' : - ' '} ${transitions[index]}'); - } - } - if (logs.isEmpty) { - debugPrint('So far nothing has been logged${ debug ? "" : "; use debug:true to print all output" }.'); - } else { - debugPrint('Log${ debug ? "" : " (only contains logged lines; use debug:true to print all output)" }:'); - for (final LogLine log in logs) { - log.printClearly(); - } - } - } - bool streamingLogs = false; - Timer? timeout; - void processTimeout() { - if (!streamingLogs) { - streamingLogs = true; - if (!debug) { - debugPrint('Test is taking a long time (${clock.elapsed.inSeconds} seconds so far).'); - } - describeStatus(); - debugPrint('(streaming all logs from this point on...)'); - } else { - debugPrint('(taking a long time...)'); - } - } - String stamp() => '[${(clock.elapsed.inMilliseconds / 1000.0).toStringAsFixed(1).padLeft(5)}s]'; - void processStdout(String line) { - final LogLine log = LogLine('stdout', stamp(), line); - if (logging) { - logs.add(log); - } - if (streamingLogs) { - log.printClearly(); - } - if (nextTransition < transitions.length && transitions[nextTransition].matches(line)) { - if (streamingLogs) { - debugPrint('(matched ${transitions[nextTransition]})'); - } - if (transitions[nextTransition].logging != null) { - if (!logging && transitions[nextTransition].logging!) { - logs.add(log); - } - logging = transitions[nextTransition].logging!; - if (streamingLogs) { - if (logging) { - debugPrint('(enabled logging)'); - } else { - debugPrint('(disabled logging)'); - } - } - } - if (transitions[nextTransition].handler != null) { - final String? command = transitions[nextTransition].handler!(line); - if (command != null) { - final LogLine inLog = LogLine('stdin', stamp(), command); - logs.add(inLog); - if (streamingLogs) { - inLog.printClearly(); - } - process.stdin.write(command); - } - } - nextTransition += 1; - timeout?.cancel(); - timeout = Timer(expectedMaxDuration ~/ 5, processTimeout); // This is not a failure timeout, just when to start logging verbosely to help debugging. - } - } - void processStderr(String line) { - final LogLine log = LogLine('stdout', stamp(), line); - logs.add(log); - if (streamingLogs) { - log.printClearly(); - } - } - if (debug) { - processTimeout(); - } else { - timeout = Timer(expectedMaxDuration ~/ 2, processTimeout); // This is not a failure timeout, just when to start logging verbosely to help debugging. - } - process.stdout.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(processStdout); - process.stderr.transform<String>(utf8.decoder).transform<String>(const LineSplitter()).listen(processStderr); - unawaited(process.exitCode.timeout(expectedMaxDuration, onTimeout: () { // This is a failure timeout, must not be short. - debugPrint('${stamp()} (process is not quitting, trying to send a "q" just in case that helps)'); - debugPrint('(a functional test should never reach this point)'); - final LogLine inLog = LogLine('stdin', stamp(), 'q'); - logs.add(inLog); - if (streamingLogs) { - inLog.printClearly(); - } - process.stdin.write('q'); - return -1; // discarded - }).then( - (int i) => i, - onError: (Object error) { - // ignore errors here, they will be reported on the next line - return -1; // discarded - }, - )); - final int exitCode = await process.exitCode; - if (streamingLogs) { - debugPrint('${stamp()} (process terminated with exit code $exitCode)'); - } - timeout?.cancel(); - if (nextTransition < transitions.length) { - debugPrint('The subprocess terminated before all the expected transitions had been matched.'); - if (logs.any((LogLine line) => line.couldBeCrash)) { - debugPrint('The subprocess may in fact have crashed. Check the stderr logs below.'); - } - debugPrint('The transition that we were hoping to see next but that we never saw was:'); - debugPrint('${nextTransition.toString().padLeft(5)} NOW WAITING FOR> ${transitions[nextTransition]}'); - if (!streamingLogs) { - describeStatus(); - debugPrint('(process terminated with exit code $exitCode)'); - } - throw TestFailure('Missed some expected transitions.'); - } - if (streamingLogs) { - debugPrint('${stamp()} (completed execution successfully!)'); - } - return ProcessTestResult(exitCode, logs); -} - -const int progressMessageWidth = 64; +import 'transition_test_utils.dart'; void main() { testWithoutContext('flutter run writes and clears pidfile appropriately', () async { diff --git a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart new file mode 100644 index 0000000000000..9c34917600395 --- /dev/null +++ b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart @@ -0,0 +1,338 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:meta/meta.dart'; +import 'package:process/process.dart'; + +import '../src/common.dart'; +import 'test_utils.dart' show fileSystem; + +const ProcessManager processManager = LocalProcessManager(); +final String flutterRoot = getFlutterRoot(); +final String flutterBin = fileSystem.path.join(flutterRoot, 'bin', 'flutter'); + +void debugPrint(String message) { + // This is called to intentionally print debugging output when a test is + // either taking too long or has failed. + // ignore: avoid_print + print(message); +} + +typedef LineHandler = String? Function(String line); + +abstract class Transition { + const Transition({this.handler, this.logging}); + + /// Callback that is invoked when the transition matches. + /// + /// This should not throw, even if the test is failing. (For example, don't use "expect" + /// in these callbacks.) Throwing here would prevent the [runFlutter] function from running + /// to completion, which would leave zombie `flutter` processes around. + final LineHandler? handler; + + /// Whether to enable or disable logging when this transition is matched. + /// + /// The default value, null, leaves the logging state unaffected. + final bool? logging; + + bool matches(String line); + + @protected + bool lineMatchesPattern(String line, Pattern pattern) { + if (pattern is String) { + return line == pattern; + } + return line.contains(pattern); + } + + @protected + String describe(Pattern pattern) { + if (pattern is String) { + return '"$pattern"'; + } + if (pattern is RegExp) { + return '/${pattern.pattern}/'; + } + return '$pattern'; + } +} + +class Barrier extends Transition { + const Barrier(this.pattern, {super.handler, super.logging}); + final Pattern pattern; + + @override + bool matches(String line) => lineMatchesPattern(line, pattern); + + @override + String toString() => describe(pattern); +} + +class Multiple extends Transition { + Multiple( + List<Pattern> patterns, { + super.handler, + super.logging, + }) : _originalPatterns = patterns, + patterns = patterns.toList(); + + final List<Pattern> _originalPatterns; + final List<Pattern> patterns; + + @override + bool matches(String line) { + for (int index = 0; index < patterns.length; index += 1) { + if (lineMatchesPattern(line, patterns[index])) { + patterns.removeAt(index); + break; + } + } + return patterns.isEmpty; + } + + @override + String toString() { + if (patterns.isEmpty) { + return '${_originalPatterns.map(describe).join(', ')} (all matched)'; + } + return '${_originalPatterns.map(describe).join(', ')} (matched ${_originalPatterns.length - patterns.length} so far)'; + } +} + +class LogLine { + const LogLine(this.channel, this.stamp, this.message); + final String channel; + final String stamp; + final String message; + + bool get couldBeCrash => + message.contains('Oops; flutter has exited unexpectedly:'); + + @override + String toString() => '$stamp $channel: $message'; + + void printClearly() { + debugPrint('$stamp $channel: ${clarify(message)}'); + } + + static String clarify(String line) { + return line.runes.map<String>((int rune) { + if (rune >= 0x20 && rune <= 0x7F) { + return String.fromCharCode(rune); + } + switch (rune) { + case 0x00: + return '<NUL>'; + case 0x07: + return '<BEL>'; + case 0x08: + return '<TAB>'; + case 0x09: + return '<BS>'; + case 0x0A: + return '<LF>'; + case 0x0D: + return '<CR>'; + } + return '<${rune.toRadixString(16).padLeft(rune <= 0xFF ? 2 : rune <= 0xFFFF ? 4 : 5, '0')}>'; + }).join(); + } +} + +class ProcessTestResult { + const ProcessTestResult(this.exitCode, this.logs); + final int exitCode; + final List<LogLine> logs; + + List<String> get stdout { + return logs + .where((LogLine log) => log.channel == 'stdout') + .map<String>((LogLine log) => log.message) + .toList(); + } + + List<String> get stderr { + return logs + .where((LogLine log) => log.channel == 'stderr') + .map<String>((LogLine log) => log.message) + .toList(); + } + + @override + String toString() => 'exit code $exitCode\nlogs:\n ${logs.join('\n ')}\n'; +} + +Future<ProcessTestResult> runFlutter( + List<String> arguments, + String workingDirectory, + List<Transition> transitions, { + bool debug = false, + bool logging = true, + Duration expectedMaxDuration = const Duration( + minutes: + 10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml. +}) async { + final Stopwatch clock = Stopwatch()..start(); + final Process process = await processManager.start( + <String>[flutterBin, ...arguments], + workingDirectory: workingDirectory, + ); + final List<LogLine> logs = <LogLine>[]; + int nextTransition = 0; + void describeStatus() { + if (transitions.isNotEmpty) { + debugPrint('Expected state transitions:'); + for (int index = 0; index < transitions.length; index += 1) { + debugPrint('${index.toString().padLeft(5)} ' + '${index < nextTransition ? 'ALREADY MATCHED ' : index == nextTransition ? 'NOW WAITING FOR>' : ' '} ${transitions[index]}'); + } + } + if (logs.isEmpty) { + debugPrint( + 'So far nothing has been logged${debug ? "" : "; use debug:true to print all output"}.'); + } else { + debugPrint( + 'Log${debug ? "" : " (only contains logged lines; use debug:true to print all output)"}:'); + for (final LogLine log in logs) { + log.printClearly(); + } + } + } + + bool streamingLogs = false; + Timer? timeout; + void processTimeout() { + if (!streamingLogs) { + streamingLogs = true; + if (!debug) { + debugPrint( + 'Test is taking a long time (${clock.elapsed.inSeconds} seconds so far).'); + } + describeStatus(); + debugPrint('(streaming all logs from this point on...)'); + } else { + debugPrint('(taking a long time...)'); + } + } + + String stamp() => + '[${(clock.elapsed.inMilliseconds / 1000.0).toStringAsFixed(1).padLeft(5)}s]'; + void processStdout(String line) { + final LogLine log = LogLine('stdout', stamp(), line); + if (logging) { + logs.add(log); + } + if (streamingLogs) { + log.printClearly(); + } + if (nextTransition < transitions.length && + transitions[nextTransition].matches(line)) { + if (streamingLogs) { + debugPrint('(matched ${transitions[nextTransition]})'); + } + if (transitions[nextTransition].logging != null) { + if (!logging && transitions[nextTransition].logging!) { + logs.add(log); + } + logging = transitions[nextTransition].logging!; + if (streamingLogs) { + if (logging) { + debugPrint('(enabled logging)'); + } else { + debugPrint('(disabled logging)'); + } + } + } + if (transitions[nextTransition].handler != null) { + final String? command = transitions[nextTransition].handler!(line); + if (command != null) { + final LogLine inLog = LogLine('stdin', stamp(), command); + logs.add(inLog); + if (streamingLogs) { + inLog.printClearly(); + } + process.stdin.write(command); + } + } + nextTransition += 1; + timeout?.cancel(); + timeout = Timer(expectedMaxDuration ~/ 5, + processTimeout); // This is not a failure timeout, just when to start logging verbosely to help debugging. + } + } + + void processStderr(String line) { + final LogLine log = LogLine('stdout', stamp(), line); + logs.add(log); + if (streamingLogs) { + log.printClearly(); + } + } + + if (debug) { + processTimeout(); + } else { + timeout = Timer(expectedMaxDuration ~/ 2, + processTimeout); // This is not a failure timeout, just when to start logging verbosely to help debugging. + } + process.stdout + .transform<String>(utf8.decoder) + .transform<String>(const LineSplitter()) + .listen(processStdout); + process.stderr + .transform<String>(utf8.decoder) + .transform<String>(const LineSplitter()) + .listen(processStderr); + unawaited(process.exitCode.timeout(expectedMaxDuration, onTimeout: () { + // This is a failure timeout, must not be short. + debugPrint( + '${stamp()} (process is not quitting, trying to send a "q" just in case that helps)'); + debugPrint('(a functional test should never reach this point)'); + final LogLine inLog = LogLine('stdin', stamp(), 'q'); + logs.add(inLog); + if (streamingLogs) { + inLog.printClearly(); + } + process.stdin.write('q'); + return -1; // discarded + }).then( + (int i) => i, + onError: (Object error) { + // ignore errors here, they will be reported on the next line + return -1; // discarded + }, + )); + final int exitCode = await process.exitCode; + if (streamingLogs) { + debugPrint('${stamp()} (process terminated with exit code $exitCode)'); + } + timeout?.cancel(); + if (nextTransition < transitions.length) { + debugPrint( + 'The subprocess terminated before all the expected transitions had been matched.'); + if (logs.any((LogLine line) => line.couldBeCrash)) { + debugPrint( + 'The subprocess may in fact have crashed. Check the stderr logs below.'); + } + debugPrint( + 'The transition that we were hoping to see next but that we never saw was:'); + debugPrint( + '${nextTransition.toString().padLeft(5)} NOW WAITING FOR> ${transitions[nextTransition]}'); + if (!streamingLogs) { + describeStatus(); + debugPrint('(process terminated with exit code $exitCode)'); + } + throw TestFailure('Missed some expected transitions.'); + } + if (streamingLogs) { + debugPrint('${stamp()} (completed execution successfully!)'); + } + return ProcessTestResult(exitCode, logs); +} + +const int progressMessageWidth = 64; diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index 2cd16a00a7768..4cc4ab1c227e8 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -449,6 +449,7 @@ class TestFeatureFlags implements FeatureFlags { this.areCustomDevicesEnabled = false, this.isFlutterWebWasmEnabled = false, this.isCliAnimationEnabled = true, + this.isNativeAssetsEnabled = false, }); @override @@ -481,6 +482,9 @@ class TestFeatureFlags implements FeatureFlags { @override final bool isCliAnimationEnabled; + @override + final bool isNativeAssetsEnabled; + @override bool isEnabled(Feature feature) { switch (feature) { @@ -502,6 +506,8 @@ class TestFeatureFlags implements FeatureFlags { return areCustomDevicesEnabled; case cliAnimation: return isCliAnimationEnabled; + case nativeAssets: + return isNativeAssetsEnabled; } return false; } From 2da03e54a99527ec502620bdd98f4fff88719f02 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sun, 10 Sep 2023 09:15:26 -0400 Subject: [PATCH 1182/1547] Roll Flutter Engine from 47d1a045d140 to a2af0c6965be (1 revision) (#134375) https://github.com/flutter/engine/compare/47d1a045d140...a2af0c6965be 2023-09-10 skia-flutter-autoroll@skia.org Roll Skia from 1bb0f15f2cff to 4eea73a072d3 (1 revision) (flutter/engine#45623) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c12752eadf7aa..10fb7ab372a2d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -47d1a045d1407325b80694e4b3690fb516842d52 +a2af0c6965be496b0733072de56350c8b814ecfd From de25def7784a2e63a9e7d5cc50dff84db8f69298 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sun, 10 Sep 2023 13:25:28 -0400 Subject: [PATCH 1183/1547] Roll Flutter Engine from a2af0c6965be to 59b08263f7cc (1 revision) (#134384) https://github.com/flutter/engine/compare/a2af0c6965be...59b08263f7cc 2023-09-10 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from U70-bvYinYjKdGGSt... to a024p4HJVVgmCW5Jo... (flutter/engine#45624) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from U70-bvYinYjK to a024p4HJVVgm If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 10fb7ab372a2d..8ff10cb6172ed 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a2af0c6965be496b0733072de56350c8b814ecfd +59b08263f7cc491d98ab5ed7f562c0f9b558e52c diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index bd7f39b2448d2..6aa8785d33f34 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -U70-bvYinYjKdGGStMi2yKvQjCrMLuEQU_ujw0KK7NsC +a024p4HJVVgmCW5JoT7TXrMrB319HQQOAhRYtitFPhAC From 44131ae4cf7578da212d1742112c6535a7cba899 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sun, 10 Sep 2023 17:00:31 -0400 Subject: [PATCH 1184/1547] Roll Flutter Engine from 59b08263f7cc to 2acd60d6baed (1 revision) (#134391) https://github.com/flutter/engine/compare/59b08263f7cc...2acd60d6baed 2023-09-10 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from VciXahwZgiusifyh8... to 6PrTSjMiSCsSb0muF... (flutter/engine#45626) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from VciXahwZgius to 6PrTSjMiSCsS If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8ff10cb6172ed..92eb3863fb912 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -59b08263f7cc491d98ab5ed7f562c0f9b558e52c +2acd60d6baedcf90e0ca38eff9d78cee9f1130bd diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index bcf3eeb031fb2..7d3d5a7da695f 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -VciXahwZgiusifyh8fc6jIjfaKr6VGDrWeIN0Lul1yYC +6PrTSjMiSCsSb0muF_aumVDnNeyj4kDruWyGDGmjgCYC From 0d9ea627565f79517f07b40c4918eae99901658b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sun, 10 Sep 2023 18:34:24 -0400 Subject: [PATCH 1185/1547] Roll Flutter Engine from 2acd60d6baed to 04d836f69571 (1 revision) (#134392) https://github.com/flutter/engine/compare/2acd60d6baed...04d836f69571 2023-09-10 skia-flutter-autoroll@skia.org Roll Skia from 4eea73a072d3 to 947f91dcacf5 (1 revision) (flutter/engine#45629) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 92eb3863fb912..c7d2f73dd57d9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2acd60d6baedcf90e0ca38eff9d78cee9f1130bd +04d836f6957150d8ff67873230993bfe63502a31 From 69f6e7d15d15f2186355d7e5c7f6f3dfac774c51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 00:50:38 -0400 Subject: [PATCH 1186/1547] Roll Flutter Engine from 04d836f69571 to 7e41b064eb23 (1 revision) (#134396) https://github.com/flutter/engine/compare/04d836f69571...7e41b064eb23 2023-09-11 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from a024p4HJVVgmCW5Jo... to SFM4ele7RYnVMhr7S... (flutter/engine#45632) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from a024p4HJVVgm to SFM4ele7RYnV If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c7d2f73dd57d9..f8627eaa586af 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -04d836f6957150d8ff67873230993bfe63502a31 +7e41b064eb234b73d2f2951b1753e231bbd61016 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 6aa8785d33f34..80f505c434a28 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -a024p4HJVVgmCW5JoT7TXrMrB319HQQOAhRYtitFPhAC +SFM4ele7RYnVMhr7SeFYTHdGCF5IecvVZtl3Ee16lSQC From ffe1ebd207c7b9d3fcf7a8672734c70388908f0c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 03:46:15 -0400 Subject: [PATCH 1187/1547] Roll Flutter Engine from 7e41b064eb23 to 1aa11b644855 (2 revisions) (#134404) https://github.com/flutter/engine/compare/7e41b064eb23...1aa11b644855 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 5aff628b1c47 to 2e80ffb2ebea (1 revision) (flutter/engine#45634) 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 947f91dcacf5 to 5aff628b1c47 (1 revision) (flutter/engine#45633) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f8627eaa586af..7961f2743ce05 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7e41b064eb234b73d2f2951b1753e231bbd61016 +1aa11b644855ea6bd2f199d71dfe28ac8c67a897 From 954444a0e38b4caa4d12248af18d01e7c63eff94 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 05:00:23 -0400 Subject: [PATCH 1188/1547] Roll Flutter Engine from 1aa11b644855 to ac6be4dbf821 (1 revision) (#134407) https://github.com/flutter/engine/compare/1aa11b644855...ac6be4dbf821 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 2e80ffb2ebea to 4c50e0870461 (1 revision) (flutter/engine#45635) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7961f2743ce05..e0de853bb251f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1aa11b644855ea6bd2f199d71dfe28ac8c67a897 +ac6be4dbf821bf98ec4661c6a36b3f8195331554 From c6fa26162f0b1b7bb6e71431065e284985ea6b7a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 05:41:25 -0400 Subject: [PATCH 1189/1547] Roll Flutter Engine from ac6be4dbf821 to e9f1696e5060 (1 revision) (#134410) https://github.com/flutter/engine/compare/ac6be4dbf821...e9f1696e5060 2023-09-11 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 6PrTSjMiSCsSb0muF... to 7Zk_dvFh301kgQte4... (flutter/engine#45636) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 6PrTSjMiSCsS to 7Zk_dvFh301k If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e0de853bb251f..76932de7f4661 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ac6be4dbf821bf98ec4661c6a36b3f8195331554 +e9f1696e50608e744c96ed2becc138a0322957bf diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7d3d5a7da695f..16b155767d9ca 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -6PrTSjMiSCsSb0muF_aumVDnNeyj4kDruWyGDGmjgCYC +7Zk_dvFh301kgQte47pTgn_aAWmEVZ3YE4WFpXPQF2QC From 6de4e16985871aab0a703fcfc843d34e0c290c1f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 09:23:33 -0400 Subject: [PATCH 1190/1547] Roll Flutter Engine from e9f1696e5060 to 2b5961cbc40d (1 revision) (#134424) https://github.com/flutter/engine/compare/e9f1696e5060...2b5961cbc40d 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 4c50e0870461 to 787b61f00100 (1 revision) (flutter/engine#45639) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 76932de7f4661..3d81b9eddef38 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e9f1696e50608e744c96ed2becc138a0322957bf +2b5961cbc40d0be5f455642e06956f19cfd1d4fe From 219efce7f16dab9bb9eb361721cffd206af5a29f Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Mon, 11 Sep 2023 09:42:27 -0700 Subject: [PATCH 1191/1547] Cover more tests with leak tracking. (#134363) --- .../flutter/test/material/about_test.dart | 8 +- .../test/material/bottom_sheet_test.dart | 110 +++++++------- .../material/bottom_sheet_theme_test.dart | 4 +- .../test/material/button_theme_test.dart | 3 +- .../flutter/test/material/drawer_test.dart | 10 +- .../material/dropdown_form_field_test.dart | 62 ++++---- .../material/dropdown_menu_theme_test.dart | 6 +- .../test/material/elevated_button_test.dart | 2 +- .../test/material/filled_button_test.dart | 4 +- .../floating_action_button_location_test.dart | 48 +++--- .../material/floating_action_button_test.dart | 10 +- .../test/material/icon_button_test.dart | 2 +- .../flutter/test/material/ink_well_test.dart | 2 +- .../test/material/input_decorator_test.dart | 2 +- .../test/material/list_tile_theme_test.dart | 2 +- .../test/material/material_button_test.dart | 2 +- .../test/material/outlined_button_test.dart | 6 +- .../test/material/page_selector_test.dart | 2 +- packages/flutter/test/material/page_test.dart | 2 +- .../material/paginated_data_table_test.dart | 95 ++++++------ .../persistent_bottom_sheet_test.dart | 18 +-- .../test/material/popup_menu_test.dart | 2 +- .../material/progress_indicator_test.dart | 8 +- .../flutter/test/material/scaffold_test.dart | 12 +- .../test/material/search_bar_theme_test.dart | 12 +- .../test/material/segmented_button_test.dart | 22 +-- .../material/segmented_button_theme_test.dart | 8 +- .../test/material/selection_area_test.dart | 28 ++-- .../flutter/test/material/snack_bar_test.dart | 138 +++++++++--------- .../flutter/test/material/switch_test.dart | 2 +- .../test/material/text_button_test.dart | 14 +- .../material/text_field_restoration_test.dart | 5 +- .../text_form_field_restoration_test.dart | 9 +- .../test/material/text_form_field_test.dart | 2 +- .../material/text_selection_toolbar_test.dart | 4 +- .../flutter/test/material/theme_test.dart | 2 +- packages/flutter/test/material/time_test.dart | 6 +- 37 files changed, 349 insertions(+), 325 deletions(-) diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart index 044a58970419d..4af66cc40b84a 100644 --- a/packages/flutter/test/material/about_test.dart +++ b/packages/flutter/test/material/about_test.dart @@ -1460,7 +1460,7 @@ void main() { expect(find.text('Exception: Injected failure'), findsOneWidget); }); - testWidgets('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - ltr', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.ltr; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1592,7 +1592,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(160, 356)); }); - testWidgets('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1657,7 +1657,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgets('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - LicensePage master view layout position - rtl', (WidgetTester tester) async { const TextDirection textDirection = TextDirection.rtl; const Size defaultSize = Size(800.0, 600.0); const Size wideSize = Size(1200.0, 600.0); @@ -1724,7 +1724,7 @@ void main() { expect(tester.getCenter(find.byType(ListView)), const Offset(1040.0, 356.0)); }); - testWidgets('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('License page title in lateral UI does not use AppBarTheme.foregroundColor', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/108991 final ThemeData theme = ThemeData( appBarTheme: const AppBarTheme(foregroundColor: Color(0xFFFFFFFF)), diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index 886b3d1efa17d..fa5e91d1a9caf 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -27,7 +27,7 @@ void main() { expect(dyDelta1, isNot(moreOrLessEquals(dyDelta2, epsilon: 0.1))); } - testWidgets('Throw if enable drag without an animation controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throw if enable drag without an animation controller', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/89168 await tester.pumpWidget( MaterialApp( @@ -54,7 +54,7 @@ void main() { FlutterError.onError = handler; }); - testWidgets('Disposing app while bottom sheet is disappearing does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing app while bottom sheet is disappearing does not crash', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget( @@ -91,7 +91,7 @@ void main() { await tester.pumpWidget(Container()); }); - testWidgets('Swiping down a BottomSheet should dismiss it by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swiping down a BottomSheet should dismiss it by default', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); bool showBottomSheetThenCalled = false; @@ -126,7 +126,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Swiping down a BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swiping down a BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); bool showBottomSheetThenCalled = false; @@ -163,7 +163,7 @@ void main() { expect(find.text('BottomSheet'), findsOneWidget); }); - testWidgets('Swiping down a BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swiping down a BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); bool showBottomSheetThenCalled = false; @@ -200,7 +200,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Tapping on a BottomSheet should not trigger a rebuild when enableDrag is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping on a BottomSheet should not trigger a rebuild when enableDrag is true', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/126833. final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); int buildCount = 0; @@ -237,7 +237,7 @@ void main() { expect(find.text('BottomSheet'), findsOneWidget); }); - testWidgets('Modal BottomSheet builder should only be called once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal BottomSheet builder should only be called once', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -268,7 +268,7 @@ void main() { expect(numBuilderCalls, 1); }); - testWidgets('Tapping on a modal BottomSheet should not dismiss it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping on a modal BottomSheet should not dismiss it', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget( @@ -304,7 +304,7 @@ void main() { expect(showBottomSheetThenCalled, isFalse); }); - testWidgets('Tapping outside a modal BottomSheet should dismiss it by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping outside a modal BottomSheet should dismiss it by default', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -338,7 +338,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Tapping outside a modal BottomSheet should dismiss it when isDismissible=true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping outside a modal BottomSheet should dismiss it when isDismissible=true', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -372,7 +372,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Verify that the BottomSheet animates non-linearly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that the BottomSheet animates non-linearly', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -405,7 +405,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/121098 - testWidgets('Verify that accessibleNavigation has no impact on the BottomSheet animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that accessibleNavigation has no impact on the BottomSheet animation', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( builder: (BuildContext context, Widget? child) { return MediaQuery( @@ -430,7 +430,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Tapping outside a modal BottomSheet should not dismiss it when isDismissible=false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping outside a modal BottomSheet should not dismiss it when isDismissible=false', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget( @@ -467,7 +467,7 @@ void main() { expect(find.text('BottomSheet'), findsOneWidget); }); - testWidgets('Swiping down a modal BottomSheet should dismiss it by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swiping down a modal BottomSheet should dismiss it by default', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -502,7 +502,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Swiping down a modal BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swiping down a modal BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -538,7 +538,7 @@ void main() { expect(find.text('BottomSheet'), findsOneWidget); }); - testWidgets('Swiping down a modal BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swiping down a modal BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -573,7 +573,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Modal BottomSheet builder should only be called once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal BottomSheet builder should only be called once', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget(MaterialApp( @@ -604,7 +604,7 @@ void main() { expect(numBuilderCalls, 1); }); - testWidgets('Verify that a downwards fling dismisses a persistent BottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a downwards fling dismisses a persistent BottomSheet', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); bool showBottomSheetThenCalled = false; @@ -661,7 +661,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('Verify that dragging past the bottom dismisses a persistent BottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that dragging past the bottom dismisses a persistent BottomSheet', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/5528 final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -691,7 +691,7 @@ void main() { expect(find.text('BottomSheet'), findsNothing); }); - testWidgets('modal BottomSheet has no top MediaQuery', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modal BottomSheet has no top MediaQuery', (WidgetTester tester) async { late BuildContext outerContext; late BuildContext innerContext; @@ -742,7 +742,7 @@ void main() { ); }); - testWidgets('modal BottomSheet can insert a SafeArea', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modal BottomSheet can insert a SafeArea', (WidgetTester tester) async { late BuildContext outerContext; late BuildContext innerContext; @@ -814,7 +814,7 @@ void main() { expect(MediaQuery.of(innerContext).padding, const EdgeInsets.fromLTRB(0, 0, 0, 50.0)); }); - testWidgets('modal BottomSheet has semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modal BottomSheet has semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -871,7 +871,7 @@ void main() { semantics.dispose(); }); - testWidgets('Verify that visual properties are passed through', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that visual properties are passed through', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); const Color color = Colors.pink; const double elevation = 9.0; @@ -911,7 +911,7 @@ void main() { expect(modalBarrier.color, barrierColor); }); - testWidgets('BottomSheet uses fallback values in material3', + testWidgetsWithLeakTracking('BottomSheet uses fallback values in material3', (WidgetTester tester) async { const Color surfaceColor = Colors.pink; const Color surfaceTintColor = Colors.blue; @@ -951,7 +951,7 @@ void main() { expect(tester.getSize(finder).width, 640); }); - testWidgets('BottomSheet has transparent shadow in material3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomSheet has transparent shadow in material3', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: true, @@ -975,7 +975,7 @@ void main() { expect(material.shadowColor, Colors.transparent); }); - testWidgets('modal BottomSheet with scrollController has semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modal BottomSheet with scrollController has semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -1048,7 +1048,7 @@ void main() { semantics.dispose(); }); - testWidgets('modal BottomSheet with drag handle has semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modal BottomSheet with drag handle has semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -1117,7 +1117,7 @@ void main() { semantics.dispose(); }); - testWidgets('Drag handle color can take MaterialStateProperty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag handle color can take MaterialStateProperty', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); const Color defaultColor=Colors.blue; const Color hoveringColor=Colors.green; @@ -1180,7 +1180,7 @@ void main() { expect(boxDecoration.color, hoveringColor); }); - testWidgets('showModalBottomSheet does not use root Navigator by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showModalBottomSheet does not use root Navigator by default', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -1210,7 +1210,7 @@ void main() { expect(tester.getBottomLeft(find.byType(BottomSheet)).dy, 544.0); }); - testWidgets('showModalBottomSheet uses root Navigator when specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showModalBottomSheet uses root Navigator when specified', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: Navigator(onGenerateRoute: (RouteSettings settings) => MaterialPageRoute<void>(builder: (_) { @@ -1239,7 +1239,7 @@ void main() { expect(tester.getBottomLeft(find.byType(BottomSheet)).dy, 600.0); }); - testWidgets('Verify that route settings can be set in the showModalBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that route settings can be set in the showModalBottomSheet', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); const RouteSettings routeSettings = RouteSettings(name: 'route_name', arguments: 'route_argument'); @@ -1267,7 +1267,7 @@ void main() { expect(retrievedRouteSettings, routeSettings); }); - testWidgets('Verify showModalBottomSheet use AnimationController if provided.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify showModalBottomSheet use AnimationController if provided.', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -1324,7 +1324,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/87592 - testWidgets('the framework do not dispose the transitionAnimationController provided by user.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the framework do not dispose the transitionAnimationController provided by user.', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); final AnimationController controller = AnimationController( vsync: const TestVSync(), @@ -1386,7 +1386,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Verify persistence BottomSheet use AnimationController if provided.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify persistence BottomSheet use AnimationController if provided.', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); const Key tapTargetToClose = Key('tap-target-to-close'); await tester.pumpWidget(MaterialApp( @@ -1448,7 +1448,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/87708 - testWidgets('Each of the internal animation controllers should be disposed by the framework.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Each of the internal animation controllers should be disposed by the framework.', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -1491,7 +1491,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/99627 - testWidgets('The old route entry should be removed when a new sheet popup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The old route entry should be removed when a new sheet popup', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey(); PersistentBottomSheetController<void>? sheetController; @@ -1535,7 +1535,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/87708 - testWidgets('The framework does not dispose of the transitionAnimationController provided by user.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The framework does not dispose of the transitionAnimationController provided by user.', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); const Key tapTargetToClose = Key('tap-target-to-close'); final AnimationController controller = AnimationController( @@ -1591,7 +1591,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Calling PersistentBottomSheetController.close does not crash when it is not the current bottom sheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Calling PersistentBottomSheetController.close does not crash when it is not the current bottom sheet', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/93717 PersistentBottomSheetController<void>? sheetController1; await tester.pumpWidget(MaterialApp( @@ -1643,7 +1643,7 @@ void main() { expect(find.text('BottomSheet 2'), findsOneWidget); }); - testWidgets('ModalBottomSheetRoute shows BottomSheet correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ModalBottomSheetRoute shows BottomSheet correctly', (WidgetTester tester) async { late BuildContext savedContext; await tester.pumpWidget( @@ -1717,7 +1717,7 @@ void main() { notDisposedAllowList: <String, int?> {'ValueNotifier<EdgeInsets>': 1} )); - testWidgets('positioning using Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning using Directionality', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1757,7 +1757,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)).dx, 800); }); - testWidgets('default positioning', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default positioning', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1796,7 +1796,7 @@ void main() { }); group('constraints', () { - testWidgets('default constraints are max width 640 in material 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default constraints are max width 640 in material 3', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.light(useMaterial3: true), @@ -1812,7 +1812,7 @@ void main() { expect(tester.getSize(find.byType(Placeholder)).width, 640); }); - testWidgets('No constraints by default for bottomSheet property', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No constraints by default for bottomSheet property', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -1827,7 +1827,7 @@ void main() { ); }); - testWidgets('No constraints by default for showBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No constraints by default for showBottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -1855,7 +1855,7 @@ void main() { ); }); - testWidgets('No constraints by default for showModalBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No constraints by default for showModalBottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -1884,7 +1884,7 @@ void main() { ); }); - testWidgets('Theme constraints used for bottomSheet property', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme constraints used for bottomSheet property', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -1912,7 +1912,7 @@ void main() { ); }); - testWidgets('Theme constraints used for showBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme constraints used for showBottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -1946,7 +1946,7 @@ void main() { ); }); - testWidgets('Theme constraints used for showModalBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme constraints used for showModalBottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -1981,7 +1981,7 @@ void main() { ); }); - testWidgets('constraints param overrides theme for showBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('constraints param overrides theme for showBottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -2016,7 +2016,7 @@ void main() { ); }); - testWidgets('constraints param overrides theme for showModalBottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('constraints param overrides theme for showModalBottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -2094,20 +2094,20 @@ void main() { ); } - testWidgets('works at 9 / 16', (WidgetTester tester) { + testWidgetsWithLeakTracking('works at 9 / 16', (WidgetTester tester) { return test(tester, false, 9.0 / 16.0); }); - testWidgets('works at 8 / 16', (WidgetTester tester) { + testWidgetsWithLeakTracking('works at 8 / 16', (WidgetTester tester) { return test(tester, false, 8.0 / 16.0); }); - testWidgets('works at isScrollControlled', (WidgetTester tester) { + testWidgetsWithLeakTracking('works at isScrollControlled', (WidgetTester tester) { return test(tester, true, 8.0 / 16.0); }); }); }); group('showModalBottomSheet modalBarrierDismissLabel', () { - testWidgets('Verify that modalBarrierDismissLabel is used if provided', + testWidgetsWithLeakTracking('Verify that modalBarrierDismissLabel is used if provided', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); const String customLabel = 'custom label'; @@ -2133,7 +2133,7 @@ void main() { expect(modalBarrier.semanticsLabel, customLabel); }); - testWidgets('Verify that modalBarrierDismissLabel from context is used if barrierLabel is not provided', + testWidgetsWithLeakTracking('Verify that modalBarrierDismissLabel from context is used if barrierLabel is not provided', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/material/bottom_sheet_theme_test.dart b/packages/flutter/test/material/bottom_sheet_theme_test.dart index 9d203e5ceff77..6b9b526c732b4 100644 --- a/packages/flutter/test/material/bottom_sheet_theme_test.dart +++ b/packages/flutter/test/material/bottom_sheet_theme_test.dart @@ -170,7 +170,7 @@ void main() { expect(material.clipBehavior, clipBehavior); }); - testWidgets('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal bottom sheet-specific parameters are used for modal bottom sheets', (WidgetTester tester) async { const double modalElevation = 5.0; const double persistentElevation = 7.0; const Color modalBackgroundColor = Colors.yellow; @@ -249,7 +249,7 @@ void main() { expect(material.color, null); }); - testWidgets('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal bottom sheets respond to theme changes', (WidgetTester tester) async { const double lightElevation = 5.0; const double darkElevation = 3.0; const Color lightBackgroundColor = Colors.green; diff --git a/packages/flutter/test/material/button_theme_test.dart b/packages/flutter/test/material/button_theme_test.dart index 4657e1b5f4b13..1b8f3689e2378 100644 --- a/packages/flutter/test/material/button_theme_test.dart +++ b/packages/flutter/test/material/button_theme_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { @@ -67,7 +68,7 @@ void main() { expect(theme.colorScheme, const ColorScheme.dark()); }); - testWidgets('ButtonTheme alignedDropdown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ButtonTheme alignedDropdown', (WidgetTester tester) async { final Key dropdownKey = UniqueKey(); Widget buildFrame({ required bool alignedDropdown, required TextDirection textDirection }) { diff --git a/packages/flutter/test/material/drawer_test.dart b/packages/flutter/test/material/drawer_test.dart index e4d0475bbdea3..a83b1bef962bd 100644 --- a/packages/flutter/test/material/drawer_test.dart +++ b/packages/flutter/test/material/drawer_test.dart @@ -213,7 +213,7 @@ void main() { expect(state.isEndDrawerOpen, equals(false)); }); - testWidgets('Scaffold.drawer - null restorationId ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold.drawer - null restorationId ', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -236,7 +236,7 @@ void main() { expect(find.text('drawer'), findsNothing); }); - testWidgets('Scaffold.endDrawer - null restorationId ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold.endDrawer - null restorationId ', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -259,7 +259,7 @@ void main() { expect(find.text('endDrawer'), findsNothing); }); - testWidgets('Scaffold.drawer state restoration test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold.drawer state restoration test', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -290,7 +290,7 @@ void main() { expect(find.text('drawer'), findsOneWidget); }); - testWidgets('Scaffold.endDrawer state restoration test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold.endDrawer state restoration test', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -321,7 +321,7 @@ void main() { expect(find.text('endDrawer'), findsOneWidget); }); - testWidgets('Both drawer and endDrawer state restoration test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Both drawer and endDrawer state restoration test', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index 582f0e88882cf..094c8cb30e735 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -7,6 +7,7 @@ import 'dart:math' as math; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const List<String> menuItems = <String>['one', 'two', 'three', 'four']; void onChanged<T>(T _) { } @@ -148,7 +149,7 @@ void verifyPaintedShadow(Finder customPaint, int elevation) { void main() { // Regression test for https://github.com/flutter/flutter/issues/87102 - testWidgets('label position test - show hint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show hint', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -199,7 +200,7 @@ void main() { expect(hintEmptyLabel, oneValueLabel); }); - testWidgets('label position test - show disabledHint: disable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: disable', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -237,7 +238,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: enable + null item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -262,7 +263,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show disabledHint: enable + empty item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -287,7 +288,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - show hint: enable + empty item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show hint: enable + empty item', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -312,7 +313,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 12.0)); }); - testWidgets('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - no hint shown: enable + no selected + disabledHint', (WidgetTester tester) async { int? value; await tester.pumpWidget( @@ -350,7 +351,7 @@ void main() { expect(hintEmptyLabel, const Offset(0.0, 24.0)); }); - testWidgets('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('label position test - show selected item: disabled + hint + disabledHint', (WidgetTester tester) async { const int value = 1; await tester.pumpWidget( @@ -390,7 +391,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/82910 - testWidgets('null value test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null value test', (WidgetTester tester) async { int? value = 1; await tester.pumpWidget( @@ -442,7 +443,7 @@ void main() { expect(nonEmptyLabel, nullValueLabel); }); - testWidgets('DropdownButtonFormField with autovalidation test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField with autovalidation test', (WidgetTester tester) async { String? value = 'one'; int validateCalled = 0; @@ -491,7 +492,7 @@ void main() { expect(value, equals('three')); }); - testWidgets('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); // There shouldn't be overflow when expanded although list contains longer items. @@ -526,7 +527,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true aligns selected menu item', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); await tester.pumpWidget( @@ -566,7 +567,7 @@ void main() { } }); - testWidgets('DropdownButtonFormField with isDense:true does not clip large scale text', + testWidgetsWithLeakTracking('DropdownButtonFormField with isDense:true does not clip large scale text', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -605,7 +606,7 @@ void main() { expect(box.size.height, 72.0); }); - testWidgets('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField.isDense is true by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46844 final Key buttonKey = UniqueKey(); const String value = 'two'; @@ -636,7 +637,7 @@ void main() { expect(box.size.height, 48.0); }); - testWidgets('DropdownButtonFormField - custom text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - custom text style', (WidgetTester tester) async { const String value = 'foo'; final UniqueKey itemKey = UniqueKey(); @@ -674,7 +675,7 @@ void main() { expect(richText.text.style!.fontSize, 20.0); }); - testWidgets('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when the items list is empty, when items is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List<String>? items }) { @@ -721,7 +722,7 @@ void main() { }, ); - testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List<String>? items }) { @@ -741,7 +742,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint is null by default', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List<String>? items }) { @@ -761,7 +762,7 @@ void main() { expect(find.text('hint used when disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabledHint displays when onChanged is null', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List<String>? items, ValueChanged<String?>? onChanged }) { @@ -779,7 +780,7 @@ void main() { expect(find.text('disabled'), findsOneWidget); }); - testWidgets('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - disabled hint should be of same size as enabled hint', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); Widget build({ List<String>? items}) { @@ -804,7 +805,7 @@ void main() { expect(enabledHintBox.size, equals(disabledHintBox.size)); }); - testWidgets('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - Custom icon size and colors', (WidgetTester tester) async { final Key iconKey = UniqueKey(); final Icon customIcon = Icon(Icons.assessment, key: iconKey); @@ -837,7 +838,7 @@ void main() { expect(disabledRichText.text.style!.color, Colors.orange); }); - testWidgets('DropdownButtonFormField - default elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - default elevation', (WidgetTester tester) async { final Key buttonKey = UniqueKey(); debugDisableShadows = false; await tester.pumpWidget(buildFormFrame( @@ -857,7 +858,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('DropdownButtonFormField - custom elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - custom elevation', (WidgetTester tester) async { debugDisableShadows = false; final Key buttonKeyOne = UniqueKey(); final Key buttonKeyTwo = UniqueKey(); @@ -894,7 +895,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField does not allow duplicate item values', (WidgetTester tester) async { final List<DropdownMenuItem<String>> itemsWithDuplicateValues = <String>['a', 'b', 'c', 'c'] .map<DropdownMenuItem<String>>((String value) { return DropdownMenuItem<String>( @@ -923,7 +924,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField value should only appear in one menu item', (WidgetTester tester) async { final List<DropdownMenuItem<String>> itemsWithDuplicateValues = <String>['a', 'b', 'c', 'd'] .map<DropdownMenuItem<String>>((String value) { return DropdownMenuItem<String>( @@ -952,7 +953,7 @@ void main() { ); }); - testWidgets('DropdownButtonFormField - selectedItemBuilder builds custom buttons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - selectedItemBuilder builds custom buttons', (WidgetTester tester) async { const List<String> items = <String>[ 'One', 'Two', @@ -996,7 +997,7 @@ void main() { expect(find.text('Two as an Arabic numeral: 2'), findsOneWidget); }); - testWidgets('DropdownButton onTap callback is called when defined', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButton onTap callback is called when defined', (WidgetTester tester) async { int dropdownButtonTapCounter = 0; String? value = 'one'; void onChanged(String? newValue) { @@ -1042,7 +1043,7 @@ void main() { expect(dropdownButtonTapCounter, 2); // Should not change. }); - testWidgets('DropdownButtonFormField should re-render if value param changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField should re-render if value param changes', (WidgetTester tester) async { String currentValue = 'two'; await tester.pumpWidget( @@ -1088,7 +1089,7 @@ void main() { expect(find.text(currentValue), findsOneWidget); }); - testWidgets('autovalidateMode is passed to super', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autovalidateMode is passed to super', (WidgetTester tester) async { int validateCalled = 0; await tester.pumpWidget( @@ -1117,7 +1118,7 @@ void main() { expect(validateCalled, 1); }); - testWidgets('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownButtonFormField - Custom button alignment', (WidgetTester tester) async { await tester.pumpWidget(buildFormFrame( buttonAlignment: AlignmentDirectional.center, items: <String>['one'], @@ -1134,13 +1135,14 @@ void main() { ); }); - testWidgets('InputDecoration borders are used for clipping', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration borders are used for clipping', (WidgetTester tester) async { const BorderRadius errorBorderRadius = BorderRadius.all(Radius.circular(5.0)); const BorderRadius focusedErrorBorderRadius = BorderRadius.all(Radius.circular(6.0)); const BorderRadius focusedBorder = BorderRadius.all(Radius.circular(7.0)); const BorderRadius enabledBorder = BorderRadius.all(Radius.circular(9.0)); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); const String errorText = 'This is an error'; bool showError = false; diff --git a/packages/flutter/test/material/dropdown_menu_theme_test.dart b/packages/flutter/test/material/dropdown_menu_theme_test.dart index f0c0f17962323..279f60256a288 100644 --- a/packages/flutter/test/material/dropdown_menu_theme_test.dart +++ b/packages/flutter/test/material/dropdown_menu_theme_test.dart @@ -43,7 +43,7 @@ void main() { expect(description, <String>[]); }); - testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData themeData = ThemeData(); await tester.pumpWidget( MaterialApp( @@ -179,7 +179,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownMenuTheme overrides ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, @@ -282,7 +282,7 @@ void main() { expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget parameters overrides DropdownMenuTheme, ThemeData and defaults', (WidgetTester tester) async { final DropdownMenuThemeData global = DropdownMenuThemeData( textStyle: TextStyle( color: Colors.orange, diff --git a/packages/flutter/test/material/elevated_button_test.dart b/packages/flutter/test/material/elevated_button_test.dart index 89b2fe6308fa5..0f3796c87f7e8 100644 --- a/packages/flutter/test/material/elevated_button_test.dart +++ b/packages/flutter/test/material/elevated_button_test.dart @@ -160,7 +160,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Default ElevatedButton meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default ElevatedButton meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index 0b2062a7fab58..5c71f5395f105 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -237,7 +237,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Default FilledButton meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default FilledButton meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); addTearDown(focusNode.dispose); @@ -1750,7 +1750,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FilledButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart index b43449f2435d4..a94253aa2e99a 100644 --- a/packages/flutter/test/material/floating_action_button_location_test.dart +++ b/packages/flutter/test/material/floating_action_button_location_test.dart @@ -184,7 +184,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting motion towards the StartTop location.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting motion towards the StartTop location.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -197,7 +197,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting entrance to remove the fab.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting entrance to remove the fab.', (WidgetTester tester) async { await tester.pumpWidget(_buildFrame(fab: null, location: FloatingActionButtonLocation.centerFloat, listener: geometryListener)); setupListener(tester); @@ -216,7 +216,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('interrupting entrance of a new fab.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interrupting entrance of a new fab.', (WidgetTester tester) async { await tester.pumpWidget( _buildFrame( fab: null, @@ -409,7 +409,7 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _topOffsetY)); }); - testWidgets('startFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('startFloat', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.startFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _floatOffsetY)); @@ -421,25 +421,25 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _floatOffsetY)); }); - testWidgets('endFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endFloat', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _floatOffsetY)); }); - testWidgets('startDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('startDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.startDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_leftOffsetX, _dockedOffsetY)); }); - testWidgets('centerDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('centerDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.centerDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _dockedOffsetY)); }); - testWidgets('endDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.endDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_rightOffsetX, _dockedOffsetY)); @@ -463,31 +463,31 @@ void main() { expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniRightOffsetX, _topOffsetY)); }); - testWidgets('miniStartFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartFloat', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniStartFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniLeftOffsetX, _miniFloatOffsetY)); }); - testWidgets('miniCenterFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniCenterFloat', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniCenterFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_centerOffsetX, _miniFloatOffsetY)); }); - testWidgets('miniEndFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniEndFloat', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniEndFloat)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniRightOffsetX, _miniFloatOffsetY)); }); - testWidgets('miniStartDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniStartDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniLeftOffsetX, _dockedOffsetY)); }); - testWidgets('miniEndDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniEndDocked', (WidgetTester tester) async { await tester.pumpWidget(_singleFabScaffold(FloatingActionButtonLocation.miniEndDocked)); expect(tester.getCenter(find.byType(FloatingActionButton)), const Offset(_miniRightOffsetX, _dockedOffsetY)); @@ -1000,7 +1000,7 @@ void main() { ); } - testWidgets('startFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('startFloat', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(16.0, 478.0, 72.0, 534.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(16.0, 422.0, 72.0, 478.0); @@ -1018,7 +1018,7 @@ void main() { ); }); - testWidgets('miniStartFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartFloat', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(12.0, 490.0, 60.0, 538.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(12.0, 434.0, 60.0, 482.0); @@ -1055,7 +1055,7 @@ void main() { ); }); - testWidgets('miniCenterFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniCenterFloat', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(376.0, 490.0, 424.0, 538.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(376.0, 434.0, 424.0, 482.0); @@ -1074,7 +1074,7 @@ void main() { ); }); - testWidgets('endFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endFloat', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(728.0, 478.0, 784.0, 534.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(728.0, 422.0, 784.0, 478.0); @@ -1092,7 +1092,7 @@ void main() { ); }); - testWidgets('miniEndFloat', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniEndFloat', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(740.0, 490.0, 788.0, 538.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(740.0, 434.0, 788.0, 482.0); @@ -1363,7 +1363,7 @@ void main() { ); } - testWidgets('startDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('startDocked', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(16.0, 494.0, 72.0, 550.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(16.0, 466.0, 72.0, 522.0); @@ -1381,7 +1381,7 @@ void main() { ); }); - testWidgets('miniStartDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniStartDocked', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(12.0, 502.0, 60.0, 550.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(12.0, 470.0, 60.0, 518.0); @@ -1400,7 +1400,7 @@ void main() { ); }); - testWidgets('centerDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('centerDocked', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(372.0, 494.0, 428.0, 550.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(372.0, 466.0, 428.0, 522.0); @@ -1418,7 +1418,7 @@ void main() { ); }); - testWidgets('miniCenterDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniCenterDocked', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(376.0, 502.0, 424.0, 550.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(376.0, 470.0, 424.0, 518.0); @@ -1437,7 +1437,7 @@ void main() { ); }); - testWidgets('endDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('endDocked', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(728.0, 494.0, 784.0, 550.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(728.0, 466.0, 784.0, 522.0); @@ -1455,7 +1455,7 @@ void main() { ); }); - testWidgets('miniEndDocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('miniEndDocked', (WidgetTester tester) async { const Rect defaultRect = Rect.fromLTRB(740.0, 502.0, 788.0, 550.0); // Positioned relative to BottomNavigationBar const Rect bottomNavigationBarRect = Rect.fromLTRB(740.0, 470.0, 788.0, 518.0); diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart index 7cda152c9e057..7c286f442396c 100644 --- a/packages/flutter/test/material/floating_action_button_test.dart +++ b/packages/flutter/test/material/floating_action_button_test.dart @@ -325,7 +325,7 @@ void main() { expect(tester.widget<PhysicalShape>(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -720,7 +720,7 @@ void main() { semantics.dispose(); }); - testWidgets('extended FAB hero transitions succeed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extended FAB hero transitions succeed', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/18782 await tester.pumpWidget( @@ -786,7 +786,7 @@ void main() { }); // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( @@ -1167,7 +1167,7 @@ void main() { expect(tester.widget<PhysicalShape>(find.byType(PhysicalShape)).elevation, 6.0); }); - testWidgets('Floating Action Button states elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button states elevation', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -1332,7 +1332,7 @@ void main() { // This test prevents https://github.com/flutter/flutter/issues/20483 - testWidgets('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating Action Button clips ink splash and highlight', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 949a2b1295ed2..611a62cdfef85 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -2023,7 +2023,7 @@ void main() { expect(iconColor(), colorScheme.onSurface.withOpacity(0.38)); }); - testWidgets('Default IconButton meets a11y contrast guidelines - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default IconButton meets a11y contrast guidelines - M3', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index b0f2a59d9e9ed..e2ffd3f116b76 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -1041,7 +1041,7 @@ testWidgetsWithLeakTracking('InkResponse radius can be updated', (WidgetTester t expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkResponse containing selectable text changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index dbcca1b8197b9..edf9bec88c351 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -1668,7 +1668,7 @@ void runAllTests({ required bool useMaterial3 }) { expect(find.text('errorText'), findsOneWidget); }); - testWidgets('InputDecoration shows error border for errorText and error widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InputDecoration shows error border for errorText and error widget', (WidgetTester tester) async { const InputBorder errorBorder = OutlineInputBorder( borderSide: BorderSide(color: Colors.red, width: 1.5), ); diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index f779e489b93fd..4be26d698df19 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -746,7 +746,7 @@ void main() { expect(find.byType(Material), paints..rect(color: selectedTileColor)); }); - testWidgets('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListTile uses ListTileTheme shape in a drawer', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/106303 final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); diff --git a/packages/flutter/test/material/material_button_test.dart b/packages/flutter/test/material/material_button_test.dart index 3ef6687f05f98..e68e9d8511808 100644 --- a/packages/flutter/test/material/material_button_test.dart +++ b/packages/flutter/test/material/material_button_test.dart @@ -243,7 +243,7 @@ void main() { expect(material.color, const Color(0xff00ff00)); }); - testWidgets('Default MaterialButton meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default MaterialButton meets a11y contrast guidelines', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/outlined_button_test.dart b/packages/flutter/test/material/outlined_button_test.dart index 6a8f626074115..cc6ec12f4fcf4 100644 --- a/packages/flutter/test/material/outlined_button_test.dart +++ b/packages/flutter/test/material/outlined_button_test.dart @@ -322,7 +322,7 @@ void main() { focusNode.dispose(); }); - testWidgets('Default OutlinedButton meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default OutlinedButton meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -371,7 +371,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('OutlinedButton with colored theme meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton with colored theme meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); Color getTextColor(Set<MaterialState> states) { @@ -1837,7 +1837,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OutlinedButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index 431770fd6460d..b1bf60008c4d1 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -206,7 +206,7 @@ void main() { expect(indicatorColors(tester), const <Color>[kBlue, kRed, kRed]); }); - testWidgets('PageSelector indicatorSize', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageSelector indicatorSize', (WidgetTester tester) async { final TabController tabController = TabController( vsync: const TestVSync(), initialIndex: 1, diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart index 56b2d40642a3c..8b130928a9abb 100644 --- a/packages/flutter/test/material/page_test.dart +++ b/packages/flutter/test/material/page_test.dart @@ -1041,7 +1041,7 @@ void main() { expect(pageTapCount, 1); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('A MaterialPageRoute should slide out with CupertinoPageTransition when a compatible PageRoute is pushed on top of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A MaterialPageRoute should slide out with CupertinoPageTransition when a compatible PageRoute is pushed on top of it', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/44864. await tester.pumpWidget( diff --git a/packages/flutter/test/material/paginated_data_table_test.dart b/packages/flutter/test/material/paginated_data_table_test.dart index 88fd469a93ee7..8004dc5312762 100644 --- a/packages/flutter/test/material/paginated_data_table_test.dart +++ b/packages/flutter/test/material/paginated_data_table_test.dart @@ -67,10 +67,11 @@ class TestDataSource extends DataTableSource { void main() { final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); - testWidgetsWithLeakTracking('PaginatedDataTable paging', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); - addTearDown(source.dispose); + late TestDataSource source; + setUp(() => source = TestDataSource()); + tearDown(() => source.dispose()); + testWidgetsWithLeakTracking('PaginatedDataTable paging', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(MaterialApp( @@ -172,8 +173,7 @@ void main() { log.clear(); }); - testWidgets('PaginatedDataTable footer page number', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); + testWidgetsWithLeakTracking('PaginatedDataTable footer page number', (WidgetTester tester) async { int rowsPerPage = 2; Widget buildTable(TestDataSource source, int rowsPerPage) { @@ -303,9 +303,10 @@ void main() { expect(find.text('497–500 of 500'), findsOneWidget); }); - testWidgets('PaginatedDataTable control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable control test', (WidgetTester tester) async { TestDataSource source = TestDataSource() ..generation = 42; + addTearDown(source.dispose); final List<String> log = <String>[]; @@ -369,6 +370,7 @@ void main() { source = TestDataSource() ..generation = 15; + addTearDown(source.dispose); await tester.pumpWidget(MaterialApp( home: buildTable(source), @@ -396,11 +398,11 @@ void main() { log.clear(); }); - testWidgets('PaginatedDataTable text alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: PaginatedDataTable( header: const Text('HEADER'), - source: TestDataSource(), + source: source, rowsPerPage: 8, availableRowsPerPage: const <int>[ 8, 9, @@ -418,17 +420,20 @@ void main() { expect(tester.getTopRight(find.text('8')).dx, tester.getTopRight(find.text('Rows per page:')).dx + 40.0); // per spec }); - testWidgets('PaginatedDataTable with and without header and actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable with and without header and actions', (WidgetTester tester) async { await binding.setSurfaceSize(const Size(800, 800)); const String headerText = 'HEADER'; final List<Widget> actions = <Widget>[ IconButton(onPressed: () {}, icon: const Icon(Icons.add)), ]; + final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); + Widget buildTable({String? header, List<Widget>? actions}) => MaterialApp( home: PaginatedDataTable( header: header != null ? Text(header) : null, actions: actions, - source: TestDataSource(allowSelection: true), + source: source, columns: const <DataColumn>[ DataColumn(label: Text('Name')), DataColumn(label: Text('Calories'), numeric: true), @@ -454,8 +459,7 @@ void main() { await binding.setSurfaceSize(null); }); - testWidgets('PaginatedDataTable with large text', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); + testWidgetsWithLeakTracking('PaginatedDataTable with large text', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -491,8 +495,7 @@ void main() { expect(tester.getTopRight(find.text('501')).dx, greaterThanOrEqualTo(tester.getTopRight(find.text('Rows per page:')).dx + 40.0)); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/43433 - testWidgets('PaginatedDataTable footer scrolls', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); + testWidgetsWithLeakTracking('PaginatedDataTable footer scrolls', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Align( @@ -527,9 +530,7 @@ void main() { expect(tester.getTopLeft(find.text('Rows per page:')).dx, 18.0); // 14 padding in the footer row, 4 padding from the card }); - testWidgets('PaginatedDataTable custom row height', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); - + testWidgetsWithLeakTracking('PaginatedDataTable custom row height', (WidgetTester tester) async { Widget buildCustomHeightPaginatedTable({ double? dataRowHeight, double? dataRowMinHeight, @@ -619,7 +620,7 @@ void main() { ).size.height, 51.0); }); - testWidgets('PaginatedDataTable custom horizontal padding - checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable custom horizontal padding - checkbox', (WidgetTester tester) async { const double defaultHorizontalMargin = 24.0; const double defaultColumnSpacing = 56.0; const double customHorizontalMargin = 10.0; @@ -635,6 +636,7 @@ void main() { await binding.setSurfaceSize(const Size(width, height)); final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); Finder cellContent; Finder checkbox; Finder padding; @@ -782,12 +784,11 @@ void main() { await binding.setSurfaceSize(originalSize); }); - testWidgets('PaginatedDataTable custom horizontal padding - no checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable custom horizontal padding - no checkbox', (WidgetTester tester) async { const double defaultHorizontalMargin = 24.0; const double defaultColumnSpacing = 56.0; const double customHorizontalMargin = 10.0; const double customColumnSpacing = 15.0; - final TestDataSource source = TestDataSource(); Finder cellContent; Finder padding; @@ -905,9 +906,7 @@ void main() { ); }); - testWidgets('PaginatedDataTable table fills Card width', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); - + testWidgetsWithLeakTracking('PaginatedDataTable table fills Card width', (WidgetTester tester) async { // 800 is wide enough to ensure that all of the columns fit in the // Card. The test makes sure that the DataTable is exactly as wide // as the Card, minus the Card's margin. @@ -969,14 +968,16 @@ void main() { await binding.setSurfaceSize(originalSize); }); - testWidgets('PaginatedDataTable with optional column checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable with optional column checkbox', (WidgetTester tester) async { await binding.setSurfaceSize(const Size(800, 800)); addTearDown(() => binding.setSurfaceSize(null)); + final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); Widget buildTable(bool checkbox) => MaterialApp( home: PaginatedDataTable( header: const Text('Test table'), - source: TestDataSource(allowSelection: true), + source: source, showCheckboxColumn: checkbox, columns: const <DataColumn>[ DataColumn(label: Text('Name')), @@ -993,11 +994,14 @@ void main() { expect(find.byType(Checkbox), findsNothing); }); - testWidgets('Table should not use decoration from DataTableTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table should not use decoration from DataTableTheme', (WidgetTester tester) async { final Size originalSize = binding.renderView.size; await binding.setSurfaceSize(const Size(800, 800)); Widget buildTable() { + final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); + return MaterialApp( theme: ThemeData.light().copyWith( dataTableTheme: const DataTableThemeData( @@ -1006,7 +1010,7 @@ void main() { ), home: PaginatedDataTable( header: const Text('Test table'), - source: TestDataSource(allowSelection: true), + source: source, columns: const <DataColumn>[ DataColumn(label: Text('Name')), DataColumn(label: Text('Calories'), numeric: true), @@ -1024,12 +1028,15 @@ void main() { await binding.setSurfaceSize(originalSize); }); - testWidgets('dataRowMinHeight & dataRowMaxHeight if not set will use DataTableTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dataRowMinHeight & dataRowMaxHeight if not set will use DataTableTheme', (WidgetTester tester) async { addTearDown(() => binding.setSurfaceSize(null)); await binding.setSurfaceSize(const Size(800, 800)); const double minMaxDataRowHeight = 30.0; + final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); + await tester.pumpWidget(MaterialApp( theme: ThemeData( dataTableTheme: const DataTableThemeData( @@ -1039,7 +1046,7 @@ void main() { ), home: PaginatedDataTable( header: const Text('Test table'), - source: TestDataSource(allowSelection: true), + source: source, columns: const <DataColumn>[ DataColumn(label: Text('Name')), DataColumn(label: Text('Calories'), numeric: true), @@ -1056,7 +1063,7 @@ void main() { expect(rowContainer.constraints?.maxHeight, minMaxDataRowHeight); }); - testWidgets('PaginatedDataTable custom checkboxHorizontalMargin properly applied', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable custom checkboxHorizontalMargin properly applied', (WidgetTester tester) async { const double customCheckboxHorizontalMargin = 15.0; const double customHorizontalMargin = 10.0; @@ -1070,6 +1077,8 @@ void main() { await binding.setSurfaceSize(const Size(width, height)); final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); + Finder cellContent; Finder checkbox; Finder padding; @@ -1122,17 +1131,20 @@ void main() { await binding.setSurfaceSize(originalSize); }); - testWidgets('Items selected text uses secondary color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Items selected text uses secondary color', (WidgetTester tester) async { const Color selectedTextColor = Color(0xff00ddff); final ColorScheme colors = const ColorScheme.light().copyWith(secondary: selectedTextColor); final ThemeData theme = ThemeData.from(colorScheme: colors); + final TestDataSource source = TestDataSource(allowSelection: true); + addTearDown(source.dispose); + Widget buildTable() { return MaterialApp( theme: theme, home: PaginatedDataTable( header: const Text('Test table'), - source: TestDataSource(allowSelection: true), + source: source, columns: const <DataColumn>[ DataColumn(label: Text('Name')), DataColumn(label: Text('Calories'), numeric: true), @@ -1161,7 +1173,7 @@ void main() { await binding.setSurfaceSize(null); }); - testWidgets('PaginatedDataTable arrowHeadColor set properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable arrowHeadColor set properly', (WidgetTester tester) async { await binding.setSurfaceSize(const Size(800, 800)); addTearDown(() => binding.setSurfaceSize(null)); const Color arrowHeadColor = Color(0xFFE53935); @@ -1172,7 +1184,7 @@ void main() { arrowHeadColor: arrowHeadColor, showFirstLastButtons: true, header: const Text('Test table'), - source: TestDataSource(), + source: source, columns: const <DataColumn>[ DataColumn(label: Text('Name')), DataColumn(label: Text('Calories'), numeric: true), @@ -1190,7 +1202,7 @@ void main() { expect(icons.elementAt(3).color, arrowHeadColor); }); - testWidgets('OverflowBar header left alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar header left alignment', (WidgetTester tester) async { // Test an old special case that tried to align the first child of a ButtonBar // and the left edge of a Text header widget. Still possible with OverflowBar // albeit without any special case in the implementation's build method. @@ -1199,7 +1211,7 @@ void main() { home: PaginatedDataTable( header: header, rowsPerPage: 2, - source: TestDataSource(), + source: source, columns: const <DataColumn>[ DataColumn(label: Text('Name')), DataColumn(label: Text('Calories'), numeric: true), @@ -1218,9 +1230,7 @@ void main() { expect(headerX, tester.getTopLeft(find.byType(ElevatedButton)).dx); }); - testWidgets('PaginatedDataTable can be scrolled using ScrollController', (WidgetTester tester) async { - final TestDataSource source = TestDataSource(); - addTearDown(source.dispose); + testWidgetsWithLeakTracking('PaginatedDataTable can be scrolled using ScrollController', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); addTearDown(scrollController.dispose); @@ -1269,11 +1279,9 @@ void main() { expect(scrollController.offset, 50.0); }); - testWidgets('PaginatedDataTable uses PrimaryScrollController when primary ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable uses PrimaryScrollController when primary ', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); addTearDown(primaryScrollController.dispose); - final TestDataSource source = TestDataSource(); - addTearDown(source.dispose); await tester.pumpWidget( MaterialApp( @@ -1303,9 +1311,8 @@ void main() { expect(footerScrollView.controller, null); }); - testWidgets('PaginatedDataTable custom heading row color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PaginatedDataTable custom heading row color', (WidgetTester tester) async { const MaterialStateProperty<Color> headingRowColor = MaterialStatePropertyAll<Color>(Color(0xffFF0000)); - final TestDataSource source = TestDataSource(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/persistent_bottom_sheet_test.dart b/packages/flutter/test/material/persistent_bottom_sheet_test.dart index cb8025e14f91c..8254715db181e 100644 --- a/packages/flutter/test/material/persistent_bottom_sheet_test.dart +++ b/packages/flutter/test/material/persistent_bottom_sheet_test.dart @@ -23,7 +23,7 @@ void main() { expect(dyDelta1, isNot(moreOrLessEquals(dyDelta2, epsilon: 0.1))); } - testWidgets('Persistent draggableScrollableSheet localHistoryEntries test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Persistent draggableScrollableSheet localHistoryEntries test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110123 Widget buildFrame(Widget? bottomSheet) { return MaterialApp( @@ -79,7 +79,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/83668 - testWidgets('Scaffold.bottomSheet update test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold.bottomSheet update test', (WidgetTester tester) async { Widget buildFrame(Widget? bottomSheet) { return MaterialApp( home: Scaffold( @@ -123,7 +123,7 @@ void main() { expect(buildCount, equals(2)); }); - testWidgets('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a persistent BottomSheet cannot be dismissed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Scaffold( body: const Center(child: Text('body')), @@ -186,7 +186,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify DraggableScrollableSheet.shouldCloseOnMinExtent == false prevents dismissal', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget(MaterialApp( @@ -259,7 +259,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify that a scrollControlled BottomSheet can be dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a scrollControlled BottomSheet can be dismissed', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget(MaterialApp( @@ -298,7 +298,7 @@ void main() { expect(find.text('Two'), findsNothing); }); - testWidgets('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a persistent BottomSheet can fling up and hide the fab', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -348,7 +348,7 @@ void main() { expect(find.byType(FloatingActionButton).hitTestable(), findsNothing); }); - testWidgets('Verify that a back button resets a persistent BottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a back button resets a persistent BottomSheet', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -409,7 +409,7 @@ void main() { expect(find.text('Item 22'), findsNothing); }); - testWidgets('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a scrollable BottomSheet hides the fab when scrolled up', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget(MaterialApp( @@ -530,7 +530,7 @@ void main() { ); }); - testWidgets('Scaffold.bottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold.bottomSheet', (WidgetTester tester) async { final Key bottomSheetKey = UniqueKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index 79e3a7f6f6b17..e2fa281b6387d 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -3741,7 +3741,7 @@ void main() { expect(_labelStyle(tester, 'Item 1')!.fontStyle, customTextStyle.fontStyle); }); - testWidgets('CheckedPopupMenuItem.onTap callback is called when defined', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CheckedPopupMenuItem.onTap callback is called when defined', (WidgetTester tester) async { int count = 0; await tester.pumpWidget( TestApp( diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 91fe68bc3a11f..12ec99d24994c 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -718,7 +718,7 @@ void main() { expect(tester.hasRunningAnimations, isTrue); }); - testWidgets('Material2 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); addTearDown(animationSheet.dispose); @@ -735,7 +735,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgets('Material3 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - RefreshProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(50, 50)); addTearDown(animationSheet.dispose); @@ -1017,7 +1017,7 @@ void main() { handle.dispose(); }); - testWidgets('Material2 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); addTearDown(animationSheet.dispose); @@ -1040,7 +1040,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/56001 - testWidgets('Material3 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Indeterminate CircularProgressIndicator uses expected animation', (WidgetTester tester) async { final AnimationSheetBuilder animationSheet = AnimationSheetBuilder(frameSize: const Size(40, 40)); addTearDown(animationSheet.dispose); diff --git a/packages/flutter/test/material/scaffold_test.dart b/packages/flutter/test/material/scaffold_test.dart index 28f87f4aa85cb..b883025a5d207 100644 --- a/packages/flutter/test/material/scaffold_test.dart +++ b/packages/flutter/test/material/scaffold_test.dart @@ -271,7 +271,7 @@ void main() { expect(tester.binding.transientCallbackCount, greaterThan(0)); }); - testWidgets('Floating action button shrinks when bottom sheet becomes dominant', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating action button shrinks when bottom sheet becomes dominant', (WidgetTester tester) async { final DraggableScrollableController draggableController = DraggableScrollableController(); const double kBottomSheetDominatesPercentage = 0.3; @@ -310,7 +310,7 @@ void main() { } }); - testWidgets('Scaffold shows scrim when bottom sheet becomes dominant', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scaffold shows scrim when bottom sheet becomes dominant', (WidgetTester tester) async { final DraggableScrollableController draggableController = DraggableScrollableController(); const double kBottomSheetDominatesPercentage = 0.3; const double kMinBottomSheetScrimOpacity = 0.1; @@ -621,7 +621,7 @@ void main() { expect(appBarBottomRight, equals(sheetTopRight)); }); - testWidgets('BottomSheet bottom padding is not consumed by viewInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomSheet bottom padding is not consumed by viewInsets', (WidgetTester tester) async { final Widget child = Directionality( textDirection: TextDirection.ltr, child: Scaffold( @@ -2155,7 +2155,7 @@ void main() { }); group('FlutterError control test', () { - testWidgets('showBottomSheet() while Scaffold has bottom sheet', + testWidgetsWithLeakTracking('showBottomSheet() while Scaffold has bottom sheet', (WidgetTester tester) async { final GlobalKey<ScaffoldState> key = GlobalKey<ScaffoldState>(); await tester.pumpWidget( @@ -2658,7 +2658,7 @@ void main() { expect(summary.toString(), 'The showSnackBar() method cannot be called during build.'); }); - testWidgets('Persistent BottomSheet is not dismissible via a11y means', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Persistent BottomSheet is not dismissible via a11y means', (WidgetTester tester) async { final Key bottomSheetKey = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -2681,7 +2681,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/117004 - testWidgets('can rebuild and remove bottomSheet at the same time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can rebuild and remove bottomSheet at the same time', (WidgetTester tester) async { bool themeIsLight = true; bool? defaultBottomSheet = true; final GlobalKey bottomSheetKey1 = GlobalKey(); diff --git a/packages/flutter/test/material/search_bar_theme_test.dart b/packages/flutter/test/material/search_bar_theme_test.dart index cfa506499784e..358c7ddb79e36 100644 --- a/packages/flutter/test/material/search_bar_theme_test.dart +++ b/packages/flutter/test/material/search_bar_theme_test.dart @@ -242,19 +242,19 @@ void main() { expect(trailingRect.right, barRect.right - 16.0); } - testWidgets('SearchBar properties overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar properties overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgets('SearchBar theme data overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar theme data overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); }); - testWidgets('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); checkSearchBar(tester); @@ -262,7 +262,7 @@ void main() { // Same as the previous tests with empty SearchBarThemeData's instead of null. - testWidgets('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar properties overrides defaults, empty theme and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(useSearchBarProperties: true, searchBarThemeData: const SearchBarThemeData(), overallTheme: const SearchBarThemeData())); @@ -270,14 +270,14 @@ void main() { checkSearchBar(tester); }); - testWidgets('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SearchBar theme overrides defaults and overall theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(searchBarThemeData: searchBarTheme, overallTheme: const SearchBarThemeData())); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); }); - testWidgets('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overall Theme SearchBar theme overrides defaults and null theme', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(overallTheme: searchBarTheme)); await tester.pumpAndSettle(); // allow the animations to finish checkSearchBar(tester); diff --git a/packages/flutter/test/material/segmented_button_test.dart b/packages/flutter/test/material/segmented_button_test.dart index bc53f6766d200..3f8053b940fa8 100644 --- a/packages/flutter/test/material/segmented_button_test.dart +++ b/packages/flutter/test/material/segmented_button_test.dart @@ -97,7 +97,7 @@ void main() { expect(material.type, MaterialType.transparency); }); - testWidgets('SegmentedButton supports exclusive choice by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton supports exclusive choice by default', (WidgetTester tester) async { int callbackCount = 0; int selectedSegment = 2; @@ -147,7 +147,7 @@ void main() { expect(selectedSegment, 3); }); - testWidgets('SegmentedButton supports multiple selected segments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton supports multiple selected segments', (WidgetTester tester) async { int callbackCount = 0; Set<int> selection = <int>{1}; @@ -202,7 +202,7 @@ void main() { expect(selection, <int>{2, 3}); }); -testWidgets('SegmentedButton allows for empty selection', (WidgetTester tester) async { +testWidgetsWithLeakTracking('SegmentedButton allows for empty selection', (WidgetTester tester) async { int callbackCount = 0; int? selectedSegment = 1; @@ -255,7 +255,7 @@ testWidgets('SegmentedButton allows for empty selection', (WidgetTester tester) expect(selectedSegment, 3); }); -testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTester tester) async { +testWidgetsWithLeakTracking('SegmentedButton shows checkboxes for selected segments', (WidgetTester tester) async { Widget frameWithSelection(int selected) { return Material( child: boilerplate( @@ -292,7 +292,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byIcon(Icons.check), findsOneWidget); }); - testWidgets('SegmentedButton shows selected checkboxes in place of icon if it has a label as well', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton shows selected checkboxes in place of icon if it has a label as well', (WidgetTester tester) async { Widget frameWithSelection(int selected) { return Material( child: boilerplate( @@ -335,7 +335,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byIcon(Icons.add_alarm), findsNothing); }); - testWidgets('SegmentedButton shows selected checkboxes next to icon if there is no label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton shows selected checkboxes next to icon if there is no label', (WidgetTester tester) async { Widget frameWithSelection(int selected) { return Material( child: boilerplate( @@ -376,7 +376,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgets('SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -455,7 +455,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes }); - testWidgets('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multi-select SegmentedButtons have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -532,7 +532,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes semantics.dispose(); }); - testWidgets('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton default overlayColor and foregroundColor resolve pressed state', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( @@ -580,7 +580,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(material.textStyle?.color, theme.colorScheme.onSurface); }); - testWidgets('SegmentedButton has no tooltips by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton has no tooltips by default', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -604,7 +604,7 @@ testWidgets('SegmentedButton shows checkboxes for selected segments', (WidgetTes expect(find.byType(Tooltip), findsNothing); }); - testWidgets('SegmentedButton has correct tooltips', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButton has correct tooltips', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/segmented_button_theme_test.dart b/packages/flutter/test/material/segmented_button_theme_test.dart index a273f3633e8ad..5efee131502ef 100644 --- a/packages/flutter/test/material/segmented_button_theme_test.dart +++ b/packages/flutter/test/material/segmented_button_theme_test.dart @@ -42,7 +42,7 @@ void main() { expect(description, <String>[]); }); - testWidgets('With no other configuration, defaults are used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With no other configuration, defaults are used', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -109,7 +109,7 @@ void main() { } }); - testWidgets('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ThemeData.segmentedButtonTheme overrides defaults', (WidgetTester tester) async { final ThemeData theme = ThemeData( useMaterial3: true, segmentedButtonTheme: SegmentedButtonThemeData( @@ -202,7 +202,7 @@ void main() { } }); - testWidgets('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedButtonTheme overrides ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { @@ -329,7 +329,7 @@ void main() { } }); - testWidgets('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget parameters overrides SegmentedTheme, ThemeData and defaults', (WidgetTester tester) async { final SegmentedButtonThemeData global = SegmentedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) { diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index 8e19b78f6f7d2..8e786831dc026 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { @@ -17,7 +18,7 @@ Offset textOffsetToPosition(RenderParagraph paragraph, int offset) { } void main() { - testWidgets('SelectionArea uses correct selection controls', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectionArea uses correct selection controls', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('abc'), @@ -39,7 +40,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not crash when long pressing on padding after dragging', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/123378 await tester.pumpWidget( const MaterialApp( @@ -70,11 +71,14 @@ void main() { }); - testWidgets('builds the default context menu by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds the default context menu by default', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectionArea( - focusNode: FocusNode(), + focusNode: focusNode, child: const Text('How are you?'), ), ), @@ -97,12 +101,15 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('builds a custom context menu if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds a custom context menu if provided', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectionArea( - focusNode: FocusNode(), + focusNode: focusNode, contextMenuBuilder: ( BuildContext context, SelectableRegionState selectableRegionState, @@ -133,7 +140,7 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('onSelectionChange is called when the selection changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes', (WidgetTester tester) async { SelectedContent? content; await tester.pumpWidget(MaterialApp( @@ -165,7 +172,10 @@ void main() { expect(content!.plainText, 'How'); }); - testWidgets('stopping drag of end handle will show the toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('stopping drag of end handle will show the toolbar', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + // Regression test for https://github.com/flutter/flutter/issues/119314 await tester.pumpWidget( MaterialApp( @@ -177,7 +187,7 @@ void main() { children: <Widget>[ const Text('How are you?'), SelectionArea( - focusNode: FocusNode(), + focusNode: focusNode, child: const Text('Good, and you?'), ), const Text('Fine, thank you.'), diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index bdef27eabbc0c..bf7e4fe7b9fbd 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -17,7 +17,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SnackBar control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar control test', (WidgetTester tester) async { const String helloSnackBar = 'Hello SnackBar'; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( @@ -62,7 +62,7 @@ void main() { expect(find.text(helloSnackBar), findsNothing); }); - testWidgets('SnackBar twice test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar twice test', (WidgetTester tester) async { int snackBarCount = 0; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( @@ -137,7 +137,7 @@ void main() { expect(find.text('bar2'), findsNothing); }); - testWidgets('SnackBar cancel test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar cancel test', (WidgetTester tester) async { int snackBarCount = 0; const Key tapTarget = Key('tap-target'); late int time; @@ -223,7 +223,7 @@ void main() { expect(find.text('bar2'), findsNothing); }); - testWidgets('SnackBar dismiss test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar dismiss test', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); late DismissDirection dismissDirection; late double width; @@ -265,7 +265,7 @@ void main() { ); }); - testWidgets('SnackBar cannot be tapped twice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar cannot be tapped twice', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -304,7 +304,7 @@ void main() { expect(tapCount, equals(1)); }); - testWidgets('Material2 - Light theme SnackBar has dark background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Light theme SnackBar has dark background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -346,7 +346,7 @@ void main() { expect(renderModel.color, equals(const Color(0xFF333333))); }); - testWidgets('Material3 - Light theme SnackBar has dark background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Light theme SnackBar has dark background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData.light(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -385,7 +385,7 @@ void main() { expect(renderModel.color, equals(lightTheme.colorScheme.inverseSurface)); }); - testWidgets('Dark theme SnackBar has light background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dark theme SnackBar has light background', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(); await tester.pumpWidget( MaterialApp( @@ -424,7 +424,7 @@ void main() { expect(renderModel.color, equals(darkTheme.colorScheme.onSurface)); }); - testWidgets('Material2 - Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(useMaterial3: false); await tester.pumpWidget( MaterialApp( @@ -463,7 +463,7 @@ void main() { expect(buttonTextStyle.color, equals(darkTheme.colorScheme.primary)); }); - testWidgets('Material3 - Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Dark theme SnackBar has primary text buttons', (WidgetTester tester) async { final ThemeData darkTheme = ThemeData.dark(useMaterial3: true); await tester.pumpWidget( MaterialApp( @@ -502,7 +502,7 @@ void main() { expect(buttonTextStyle.color, equals(darkTheme.colorScheme.inversePrimary)); }); - testWidgets('SnackBar should inherit theme data from its ancestor.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar should inherit theme data from its ancestor.', (WidgetTester tester) async { final SliderThemeData sliderTheme = SliderThemeData.fromPrimaryColors( primaryColor: Colors.black, primaryColorDark: Colors.black, @@ -636,7 +636,7 @@ void main() { expect(comparedTheme, themeAfterSnackBar); }); - testWidgets('Snackbar margin can be customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar margin can be customized', (WidgetTester tester) async { const double padding = 20.0; await tester.pumpWidget( MaterialApp( @@ -676,7 +676,7 @@ void main() { expect(snackBarBottomRight.dx, 800 - padding); // Device width is 800. }); - testWidgets('SnackbarBehavior.floating is positioned within safe area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackbarBehavior.floating is positioned within safe area', (WidgetTester tester) async { const double viewPadding = 50.0; const double floatingSnackBarDefaultBottomMargin = 10.0; await tester.pumpWidget( @@ -723,7 +723,7 @@ void main() { ); }); - testWidgets('Snackbar padding can be customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar padding can be customized', (WidgetTester tester) async { const double padding = 20.0; await tester.pumpWidget( MaterialApp( @@ -766,7 +766,7 @@ void main() { expect(textTopRight.dy - snackBarTopRight.dy, padding); }); - testWidgets('Snackbar width can be customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar width can be customized', (WidgetTester tester) async { const double width = 200.0; await tester.pumpWidget( MaterialApp( @@ -805,7 +805,7 @@ void main() { expect(snackBarBottomRight.dx, (800 + width) / 2); // Device width is 800. }); - testWidgets('Snackbar width can be customized from ThemeData', + testWidgetsWithLeakTracking('Snackbar width can be customized from ThemeData', (WidgetTester tester) async { const double width = 200.0; await tester.pumpWidget( @@ -847,7 +847,7 @@ void main() { expect(snackBarBottomRight.dx, (800 + width) / 2); // Device width is 800. }); - testWidgets('Snackbar width customization takes preference of widget over theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar width customization takes preference of widget over theme', (WidgetTester tester) async { const double themeWidth = 200.0; const double widgetWidth = 400.0; await tester.pumpWidget( @@ -890,7 +890,7 @@ void main() { expect(snackBarBottomRight.dx, (800 + widgetWidth) / 2); // Device width is 800. }); - testWidgets('Material2 - Snackbar labels can be colored as MaterialColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Snackbar labels can be colored as MaterialColor', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -935,7 +935,7 @@ void main() { } }); - testWidgets('Material3 - Snackbar labels can be colored as MaterialColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Snackbar labels can be colored as MaterialColor', (WidgetTester tester) async { const MaterialColor usedColor = Colors.teal; await tester.pumpWidget( @@ -986,7 +986,7 @@ void main() { } }); - testWidgets('Snackbar labels can be colored as MaterialStateColor (Material 3)', + testWidgetsWithLeakTracking('Snackbar labels can be colored as MaterialStateColor (Material 3)', (WidgetTester tester) async { const _TestMaterialStateColor usedColor = _TestMaterialStateColor(); @@ -1038,7 +1038,7 @@ void main() { } }); - testWidgets('Material2 - SnackBar button text alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: MediaQuery( @@ -1086,7 +1086,7 @@ void main() { expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 17.0 + 40.0); // margin + bottom padding }); - testWidgets('Material3 - SnackBar button text alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: MediaQuery( @@ -1248,7 +1248,7 @@ void main() { }, ); - testWidgets('SnackBar should push FloatingActionButton above', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar should push FloatingActionButton above', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: MediaQuery( data: const MediaQueryData( @@ -1303,7 +1303,7 @@ void main() { expect(fabRect.bottomRight.dy, snackBarTopRight.dy - defaultFabPadding); }); - testWidgets('Material2 - Floating SnackBar button text alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Floating SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: false, @@ -1354,7 +1354,7 @@ void main() { expect(snackBarBottomRight.dy - actionTextBottomRight.dy, 27.0); // margin (with no bottom padding) }); - testWidgets('Material3 - Floating SnackBar button text alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Floating SnackBar button text alignment', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData( useMaterial3: true, @@ -1525,7 +1525,7 @@ void main() { }, ); - testWidgets('SnackBarClosedReason', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarClosedReason', (WidgetTester tester) async { final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>(); bool actionPressed = false; SnackBarClosedReason? closedReason; @@ -1603,7 +1603,7 @@ void main() { expect(closedReason, equals(SnackBarClosedReason.timeout)); }); - testWidgets('accessible navigation behavior with action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('accessible navigation behavior with action', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget(MaterialApp( @@ -1646,7 +1646,7 @@ void main() { expect(find.text('ACTION'), findsNothing); }); - testWidgets('contributes dismiss semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('contributes dismiss semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -1689,7 +1689,7 @@ void main() { handle.dispose(); }); - testWidgets('SnackBar default display duration test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar default display duration test', (WidgetTester tester) async { const String helloSnackBar = 'Hello SnackBar'; const Key tapTarget = Key('tap-target'); await tester.pumpWidget(MaterialApp( @@ -1737,7 +1737,7 @@ void main() { expect(find.text(helloSnackBar), findsNothing); }); - testWidgets('SnackBar handles updates to accessibleNavigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar handles updates to accessibleNavigation', (WidgetTester tester) async { Future<void> boilerplate({ required bool accessibleNavigation }) { return tester.pumpWidget(MaterialApp( home: MediaQuery( @@ -1785,7 +1785,7 @@ void main() { expect(find.text('test'), findsNothing); }); - testWidgets('Snackbar calls onVisible once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar calls onVisible once', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); int called = 0; await tester.pumpWidget(MaterialApp( @@ -1822,7 +1822,7 @@ void main() { expect(called, 1); }); - testWidgets('Snackbar does not call onVisible when it is queued', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar does not call onVisible when it is queued', (WidgetTester tester) async { const Key tapTarget = Key('tap-target'); int called = 0; await tester.pumpWidget(MaterialApp( @@ -2280,7 +2280,7 @@ void main() { 'Scaffold.bottomNavigationBar take up too much vertical space.\n' 'Consider constraining the size of these widgets to allow room for the SnackBar to be visible.'; - testWidgets('Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.floatingActionButton', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.floatingActionButton', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 Future<void> boilerplate({required double? fabHeight}) { return tester.pumpWidget( @@ -2317,7 +2317,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Material2 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 await tester.pumpWidget( MaterialApp( @@ -2335,7 +2335,7 @@ void main() { expect(exception.message, offScreenMessage); }); - testWidgets('Material3 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.persistentFooterButtons', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 await tester.pumpWidget( MaterialApp( @@ -2359,7 +2359,7 @@ void main() { expect(errorMessages.contains(offScreenMessage), isTrue); }); - testWidgets('Material2 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 await tester.pumpWidget( MaterialApp( @@ -2376,7 +2376,7 @@ void main() { expect(exception.message, offScreenMessage); }); - testWidgets('Material3 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Snackbar with SnackBarBehavior.floating will assert when offset too high by a large Scaffold.bottomNavigationBar', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84263 await tester.pumpWidget( MaterialApp( @@ -2474,7 +2474,7 @@ void main() { ); }); - testWidgets('SnackBars hero across transitions when using ScaffoldMessenger', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBars hero across transitions when using ScaffoldMessenger', (WidgetTester tester) async { const String snackBarText = 'hello snackbar'; const String firstHeader = 'home'; const String secondHeader = 'second'; @@ -2621,7 +2621,7 @@ void main() { expect(find.text(snackBarText), findsOneWidget); }); - testWidgets('Material2 - SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -2647,7 +2647,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.workWithBottomSheet.png')); }); - testWidgets('Material3 - SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - SnackBars should be shown above the bottomSheet', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: const Scaffold( @@ -2673,7 +2673,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.workWithBottomSheet.png')); }); - testWidgets('ScaffoldMessenger does not duplicate a SnackBar when presenting a MaterialBanner.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessenger does not duplicate a SnackBar when presenting a MaterialBanner.', (WidgetTester tester) async { const Key materialBannerTapTarget = Key('materialbanner-tap-target'); const Key snackBarTapTarget = Key('snackbar-tap-target'); const String snackBarText = 'SnackBar'; @@ -2730,7 +2730,7 @@ void main() { expect(find.text(materialBannerText), findsOneWidget); }); - testWidgets('Material2 - ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -2763,7 +2763,7 @@ void main() { expect(snackBarTopRight.dy, 465.0); }); - testWidgets('Material3 - ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: Scaffold( @@ -2797,7 +2797,7 @@ void main() { }); - testWidgets('ScaffoldMessengerState clearSnackBars works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScaffoldMessengerState clearSnackBars works as expected', (WidgetTester tester) async { final List<String> snackBars = <String>['Hello Snackbar', 'Hi Snackbar', 'Bye Snackbar']; int snackBarCounter = 0; const Key tapTarget = Key('tap-target'); @@ -2881,7 +2881,7 @@ void main() { ); } - testWidgets('Setting SnackBarBehavior.fixed will still assert for margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting SnackBarBehavior.fixed will still assert for margin', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84935 await tester.pumpWidget(doBuildApp( behavior: SnackBarBehavior.fixed, @@ -2898,7 +2898,7 @@ void main() { ); }); - testWidgets('Default SnackBarBehavior will still assert for margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SnackBarBehavior will still assert for margin', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84935 await tester.pumpWidget(doBuildApp( behavior: null, @@ -2915,7 +2915,7 @@ void main() { ); }); - testWidgets('Setting SnackBarBehavior.fixed will still assert for width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting SnackBarBehavior.fixed will still assert for width', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84935 await tester.pumpWidget(doBuildApp( behavior: SnackBarBehavior.fixed, @@ -2932,7 +2932,7 @@ void main() { ); }); - testWidgets('Default SnackBarBehavior will still assert for width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default SnackBarBehavior will still assert for width', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84935 await tester.pumpWidget(doBuildApp( behavior: null, @@ -2950,7 +2950,7 @@ void main() { }); for (final double overflowThreshold in <double>[-1.0, -.0001, 1.000001, 5]) { - testWidgets('SnackBar will assert for actionOverflowThreshold outside of 0-1 range', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar will assert for actionOverflowThreshold outside of 0-1 range', (WidgetTester tester) async { await tester.pumpWidget(doBuildApp( actionOverflowThreshold: overflowThreshold, behavior: SnackBarBehavior.fixed, @@ -2964,7 +2964,7 @@ void main() { }); } - testWidgets('Material2 - Snackbar by default clips BackdropFilter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Snackbar by default clips BackdropFilter', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/98205 await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), @@ -2997,7 +2997,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.backdropFilter.png')); }); - testWidgets('Material3 - Snackbar by default clips BackdropFilter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Snackbar by default clips BackdropFilter', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/98205 await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), @@ -3030,7 +3030,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.backdropFilter.png')); }); - testWidgets('Floating snackbar can display optional icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating snackbar can display optional icon', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -3062,7 +3062,7 @@ void main() { 'snack_bar.goldenTest.floatingWithActionWithIcon.png')); }); - testWidgets('Material2 - Fixed width snackbar can display optional icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Fixed width snackbar can display optional icon', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -3089,7 +3089,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.fixedWithActionWithIcon.png')); }); - testWidgets('Material3 - Fixed width snackbar can display optional icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Fixed width snackbar can display optional icon', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: const Scaffold( @@ -3116,7 +3116,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.fixedWithActionWithIcon.png')); }); - testWidgets('Material2 - Fixed snackbar can display optional icon without action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Fixed snackbar can display optional icon without action', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -3144,7 +3144,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.fixedWithIcon.png')); }); - testWidgets('Material3 - Fixed snackbar can display optional icon without action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Fixed snackbar can display optional icon without action', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: const Scaffold( @@ -3172,7 +3172,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.fixedWithIcon.png')); }); - testWidgets('Material2 - Floating width snackbar can display optional icon without action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Floating width snackbar can display optional icon without action', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -3198,7 +3198,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.floatingWithIcon.png')); }); - testWidgets('Material3 - Floating width snackbar can display optional icon without action', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Floating width snackbar can display optional icon without action', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: const Scaffold( @@ -3224,7 +3224,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.floatingWithIcon.png')); }); - testWidgets('Material2 - Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -3251,7 +3251,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m2_snack_bar.goldenTest.multiLineWithIcon.png')); }); - testWidgets('Material3 - Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Floating multi-line snackbar with icon is aligned correctly', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: const Scaffold( @@ -3278,7 +3278,7 @@ void main() { await expectLater(find.byType(MaterialApp), matchesGoldenFile('m3_snack_bar.goldenTest.multiLineWithIcon.png')); }); - testWidgets('Material2 - Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: const Scaffold( @@ -3308,7 +3308,7 @@ void main() { ); }); - testWidgets('Material3 - Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Floating multi-line snackbar with icon and actionOverflowThreshold=1 is aligned correctly', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: true), home: const Scaffold( @@ -3367,7 +3367,7 @@ void main() { ); }); -testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tester) async { +testWidgetsWithLeakTracking('SnackBarAction backgroundColor works as a Color', (WidgetTester tester) async { const Color backgroundColor = Colors.blue; await tester.pumpWidget( @@ -3416,7 +3416,7 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes expect(materialAfterDismissed.color, Colors.transparent); }); - testWidgets('SnackBarAction backgroundColor works as a MaterialStateColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarAction backgroundColor works as a MaterialStateColor', (WidgetTester tester) async { final MaterialStateColor backgroundColor = MaterialStateColor.resolveWith((Set<MaterialState> states) { if (states.contains(MaterialState.disabled)) { return Colors.blue; @@ -3470,7 +3470,7 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes expect(materialAfterDismissed.color, Colors.blue); }); - testWidgets('SnackBarAction disabledBackgroundColor works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarAction disabledBackgroundColor works as expected', (WidgetTester tester) async { const Color backgroundColor = Colors.blue; const Color disabledBackgroundColor = Colors.red; @@ -3521,7 +3521,7 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes expect(materialAfterDismissed.color, disabledBackgroundColor); }); - testWidgets('SnackBarAction asserts when backgroundColor is a MaterialStateColor and disabledBackgroundColor is also provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBarAction asserts when backgroundColor is a MaterialStateColor and disabledBackgroundColor is also provided', (WidgetTester tester) async { final Color backgroundColor = MaterialStateColor.resolveWith((Set<MaterialState> states) { if (states.contains(MaterialState.disabled)) { return Colors.blue; @@ -3568,7 +3568,7 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes ); }); - testWidgets('SnackBar material applies SnackBar.clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnackBar material applies SnackBar.clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -3612,7 +3612,7 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes expect(material.clipBehavior, Clip.antiAlias); }); - testWidgets('Tap on button behind snack bar defined by width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap on button behind snack bar defined by width', (WidgetTester tester) async { tester.view.physicalSize = const Size.square(200); tester.view.devicePixelRatio = 1; addTearDown(tester.view.resetPhysicalSize); @@ -3668,7 +3668,7 @@ testWidgets('SnackBarAction backgroundColor works as a Color', (WidgetTester tes }); - testWidgets('Tap on button behind snack bar defined by margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap on button behind snack bar defined by margin', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/78537. tester.view.physicalSize = const Size.square(200); tester.view.devicePixelRatio = 1; diff --git a/packages/flutter/test/material/switch_test.dart b/packages/flutter/test/material/switch_test.dart index 0959ad2d2fd43..df4d7bef3c559 100644 --- a/packages/flutter/test/material/switch_test.dart +++ b/packages/flutter/test/material/switch_test.dart @@ -2988,7 +2988,7 @@ void main() { expect(state.position.value, greaterThan(1)); }); - testWidgets('Switch thumb shows correct pressed color - M3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switch thumb shows correct pressed color - M3', (WidgetTester tester) async { final ThemeData themeData = ThemeData(useMaterial3: true); final ColorScheme colors = themeData.colorScheme; Widget buildApp({bool enabled = true, bool value = true}) { diff --git a/packages/flutter/test/material/text_button_test.dart b/packages/flutter/test/material/text_button_test.dart index 862eadb1bbd41..56ef76f9bd00c 100644 --- a/packages/flutter/test/material/text_button_test.dart +++ b/packages/flutter/test/material/text_button_test.dart @@ -155,7 +155,7 @@ void main() { expect(material.type, MaterialType.button); }); - testWidgets('Default TextButton meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default TextButton meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); await tester.pumpWidget( @@ -203,7 +203,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44115 ); - testWidgets('TextButton with colored theme meets a11y contrast guidelines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton with colored theme meets a11y contrast guidelines', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); Color getTextColor(Set<MaterialState> states) { @@ -1636,7 +1636,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton in SelectionArea changes mouse cursor when hovered', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104595. await tester.pumpWidget(MaterialApp( home: SelectionArea( @@ -1689,6 +1689,7 @@ void main() { count += 1; } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); controller.addListener(valueChanged); await tester.pumpWidget( @@ -1789,20 +1790,21 @@ void main() { await gesture.removePointer(); } - testWidgets('TextButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton statesController', (WidgetTester tester) async { testStatesController(null, tester); }); - testWidgets('TextButton.icon statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextButton.icon statesController', (WidgetTester tester) async { testStatesController(const Icon(Icons.add), tester); }); - testWidgets('Disabled TextButton statesController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disabled TextButton statesController', (WidgetTester tester) async { int count = 0; void valueChanged() { count += 1; } final MaterialStatesController controller = MaterialStatesController(); + addTearDown(controller.dispose); controller.addListener(valueChanged); await tester.pumpWidget( diff --git a/packages/flutter/test/material/text_field_restoration_test.dart b/packages/flutter/test/material/text_field_restoration_test.dart index acc7bddd4af01..6e3a23d1d8dc6 100644 --- a/packages/flutter/test/material/text_field_restoration_test.dart +++ b/packages/flutter/test/material/text_field_restoration_test.dart @@ -4,12 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const String text = 'Hello World! How are you? Life is good!'; const String alternativeText = 'Everything is awesome!!'; void main() { - testWidgets('TextField restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField restoration', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -20,7 +21,7 @@ void main() { await restoreAndVerify(tester); }); - testWidgets('TextField restoration with external controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField restoration with external controller', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'root', diff --git a/packages/flutter/test/material/text_form_field_restoration_test.dart b/packages/flutter/test/material/text_form_field_restoration_test.dart index fd9d365e234ef..570e8fa11c001 100644 --- a/packages/flutter/test/material/text_form_field_restoration_test.dart +++ b/packages/flutter/test/material/text_form_field_restoration_test.dart @@ -4,12 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const String text = 'Hello World! How are you? Life is good!'; const String alternativeText = 'Everything is awesome!!'; void main() { - testWidgets('TextField restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField restoration', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -20,7 +21,7 @@ void main() { await restoreAndVerify(tester); }); - testWidgets('TextField restoration with external controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextField restoration with external controller', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'root', @@ -33,7 +34,7 @@ void main() { await restoreAndVerify(tester); }); - testWidgets('State restoration (No Form ancestor) - onUserInteraction error text validation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('State restoration (No Form ancestor) - onUserInteraction error text validation', (WidgetTester tester) async { String? errorText(String? value) => '$value/error'; late GlobalKey<FormFieldState<String>> formState; @@ -91,7 +92,7 @@ void main() { expect(find.text(errorText('bar')!), findsOneWidget); }); - testWidgets('State Restoration (No Form ancestor) - validator sets the error text only when validate is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('State Restoration (No Form ancestor) - validator sets the error text only when validate is called', (WidgetTester tester) async { String? errorText(String? value) => '$value/error'; late GlobalKey<FormFieldState<String>> formState; diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 5b9ca7cafe832..9d52c9c0de45d 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -1233,7 +1233,7 @@ void main() { expect(editableText.magnifierConfiguration, equals(myTextMagnifierConfiguration)); }); - testWidgets('Passes undoController to undoController TextField', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passes undoController to undoController TextField', (WidgetTester tester) async { final UndoHistoryController undoController = UndoHistoryController(value: UndoHistoryValue.empty); addTearDown(undoController.dispose); diff --git a/packages/flutter/test/material/text_selection_toolbar_test.dart b/packages/flutter/test/material/text_selection_toolbar_test.dart index f3317c109c98f..857ed6d0fcb3c 100644 --- a/packages/flutter/test/material/text_selection_toolbar_test.dart +++ b/packages/flutter/test/material/text_selection_toolbar_test.dart @@ -123,7 +123,7 @@ void main() { expect(findOverflowButton(), findsOneWidget); }); - testWidgets('positions itself at anchorAbove if it fits', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positions itself at anchorAbove if it fits', (WidgetTester tester) async { late StateSetter setState; const double height = 44.0; const double anchorBelowY = 500.0; @@ -172,7 +172,7 @@ void main() { expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); }); - testWidgets('can create and use a custom toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index 22149aac23843..1100bbe0c3a9f 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -196,7 +196,7 @@ void main() { expect(Theme.of(tester.element(find.text('menuItem'))).brightness, equals(Brightness.light)); }); - testWidgets('DropdownMenu inherits shadowed app theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DropdownMenu inherits shadowed app theme', (WidgetTester tester) async { final Key dropdownMenuButtonKey = UniqueKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/material/time_test.dart b/packages/flutter/test/material/time_test.dart index 37050875ab722..97bb94617a145 100644 --- a/packages/flutter/test/material/time_test.dart +++ b/packages/flutter/test/material/time_test.dart @@ -80,7 +80,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 2, minute: 2)); }); - testWidgets('restart and restore', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restart and restore', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -108,7 +108,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 2, minute: 2)); }); - testWidgets('restore to older state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restore to older state', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -139,7 +139,7 @@ void main() { expect(state.timeOfDay.value, const TimeOfDay(hour: 10, minute: 5)); }); - testWidgets('call notifiers when value changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('call notifiers when value changes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), From 0844726ab3da72a43609257b4be827de6515e903 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Mon, 11 Sep 2023 10:12:02 -0700 Subject: [PATCH 1192/1547] Mark leak: instances of OpacityLayer, created by _RenderChip, should be disposed. (#134395) --- packages/flutter/test/material/chip_test.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 0d8c0576409f4..e7708dd28c505 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -217,7 +217,7 @@ Finder findTooltipContainer(String tooltipText) { } void main() { - testWidgets('M2 Chip defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('M2 Chip defaults', (WidgetTester tester) async { late TextTheme textTheme; Widget buildFrame(Brightness brightness) { @@ -292,7 +292,12 @@ void main() { expect(labelStyle.overflow, textTheme.bodyLarge?.overflow); expect(labelStyle.textBaseline, textTheme.bodyLarge?.textBaseline); expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing); - }); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134394 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: <String, int?>{'OpacityLayer': 2}, + )); testWidgetsWithLeakTracking('M3 Chip defaults', (WidgetTester tester) async { late TextTheme textTheme; From 6562d52634f29ef4d7244ca3b3f827a819f5bf9d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 13:31:23 -0400 Subject: [PATCH 1193/1547] Roll Flutter Engine from 2b5961cbc40d to d593002b7159 (3 revisions) (#134439) https://github.com/flutter/engine/compare/2b5961cbc40d...d593002b7159 2023-09-11 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from SFM4ele7RYnVMhr7S... to cUKimo52R-2EIfHh5... (flutter/engine#45647) 2023-09-11 kjlubick@users.noreply.github.com Use safer GrDirectContext APIs (flutter/engine#45644) 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 787b61f00100 to 2fa311521fb2 (1 revision) (flutter/engine#45642) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from SFM4ele7RYnV to cUKimo52R-2E If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3d81b9eddef38..6ccc219c216c5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2b5961cbc40d0be5f455642e06956f19cfd1d4fe +d593002b71590de2a4378dbacda3fd3f08c77037 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 80f505c434a28..01aae5cec60bd 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -SFM4ele7RYnVMhr7SeFYTHdGCF5IecvVZtl3Ee16lSQC +cUKimo52R-2EIfHh5zsJZBokuNVytOkTEle-leUr-oQC From b831c9f44ff92fdd4bc2a0db52f155eb90139a15 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 14:17:25 -0400 Subject: [PATCH 1194/1547] Roll Packages from aaae5ef97a45 to ef0c65ea4ccd (6 revisions) (#134445) https://github.com/flutter/packages/compare/aaae5ef97a45...ef0c65ea4ccd 2023-09-11 engine-flutter-autoroll@skia.org Roll Flutter from 7c28e8eb0734 to 219efce7f16d (16 revisions) (flutter/packages#4901) 2023-09-11 chris.langham32@gmail.com [url_launcher] migrating iOS tests from objc to swift (flutter/packages#4758) 2023-09-09 engine-flutter-autoroll@skia.org Roll Flutter from da676f79aa37 to 7c28e8eb0734 (20 revisions) (flutter/packages#4879) 2023-09-09 49699333+dependabot[bot]@users.noreply.github.com Bump actions/upload-artifact from 3.1.2 to 3.1.3 (flutter/packages#4863) 2023-09-08 engine-flutter-autoroll@skia.org Roll Flutter from aea4552acdc7 to da676f79aa37 (28 revisions) (flutter/packages#4874) 2023-09-08 48349434+paulppn@users.noreply.github.com [webview_flutter_android] Added the functionality to fullscreen html5 video (flutter/packages#3879) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 0ebad43927a54..d1ae1a64d70a7 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -aaae5ef97a45885fdf5eac0b655a8085a80a25e4 +ef0c65ea4ccd83c41ec38ffaf8e4713ab2dbf3cb From 9dbbd5b4bfefb34514b569f962f267ebe22c9399 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 14:19:20 -0400 Subject: [PATCH 1195/1547] Roll Flutter Engine from d593002b7159 to e42fd367adcb (1 revision) (#134444) https://github.com/flutter/engine/compare/d593002b7159...e42fd367adcb 2023-09-11 30870216+gaaclarke@users.noreply.github.com Revert "Makes Skia's vkQueueSubmit threadsafe." (flutter/engine#45650) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6ccc219c216c5..5e0ccd51ff991 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d593002b71590de2a4378dbacda3fd3f08c77037 +e42fd367adcbe16484743e3e5e2a4afe90655eb1 From 969911d1d09d6c4f145e9ce27c08093e8c285561 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 15:14:03 -0400 Subject: [PATCH 1196/1547] Roll Flutter Engine from e42fd367adcb to 0774ddcda9b0 (1 revision) (#134447) https://github.com/flutter/engine/compare/e42fd367adcb...0774ddcda9b0 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 2fa311521fb2 to 3ed290acb65f (1 revision) (flutter/engine#45653) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5e0ccd51ff991..4f77a2a708da7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e42fd367adcbe16484743e3e5e2a4afe90655eb1 +0774ddcda9b0b7878e586a6135a026095d4feb33 From e7058f568faf49458f83d479577f66c923bf8445 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Mon, 11 Sep 2023 22:46:04 +0200 Subject: [PATCH 1197/1547] Fix memory leak in RenderAnimatedSize (#133653) `AnimationController` and `CurvedAnimation` objects were not disposed in `RenderAnimatedSize`. ### Description - Fixes https://github.com/flutter/flutter/issues/133903; - Adds the missing `dispose()` calls for `AnimationController` and `CurvedAnimation` in `RenderAnimatedSize`. ### Tests - Updates `animated_size_test.dart` to test that `AnimationController` and `CurvedAnimation` are disposed after `RenderSize` disposal. --- .../lib/src/rendering/animated_size.dart | 36 ++++++++++++++++++ .../test/widgets/animated_size_test.dart | 37 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/packages/flutter/lib/src/rendering/animated_size.dart b/packages/flutter/lib/src/rendering/animated_size.dart index 845d60896aff6..5f3aaea161701 100644 --- a/packages/flutter/lib/src/rendering/animated_size.dart +++ b/packages/flutter/lib/src/rendering/animated_size.dart @@ -99,8 +99,42 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { ); } + /// When asserts are enabled, returns the animation controller that is used + /// to drive the resizing. + /// + /// Otherwise, returns null. + /// + /// This getter is intended for use in framework unit tests. Applications must + /// not depend on its value. + @visibleForTesting + AnimationController? get debugController { + AnimationController? controller; + assert(() { + controller = _controller; + return true; + }()); + return controller; + } + + /// When asserts are enabled, returns the animation that drives the resizing. + /// + /// Otherwise, returns null. + /// + /// This getter is intended for use in framework unit tests. Applications must + /// not depend on its value. + @visibleForTesting + CurvedAnimation? get debugAnimation { + CurvedAnimation? animation; + assert(() { + animation = _animation; + return true; + }()); + return animation; + } + late final AnimationController _controller; late final CurvedAnimation _animation; + final SizeTween _sizeTween = SizeTween(); late bool _hasVisualOverflow; double? _lastValue; @@ -351,6 +385,8 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { @override void dispose() { _clipRectLayer.layer = null; + _controller.dispose(); + _animation.dispose(); super.dispose(); } } diff --git a/packages/flutter/test/widgets/animated_size_test.dart b/packages/flutter/test/widgets/animated_size_test.dart index 01b75263c33d2..75a9272d05f8f 100644 --- a/packages/flutter/test/widgets/animated_size_test.dart +++ b/packages/flutter/test/widgets/animated_size_test.dart @@ -434,5 +434,42 @@ void main() { const Size.square(150), ); }); + + testWidgets('disposes animation and controller', (WidgetTester tester) async { + await tester.pumpWidget( + const Center( + child: AnimatedSize( + duration: Duration(milliseconds: 200), + child: SizedBox( + width: 100.0, + height: 100.0, + ), + ), + ), + ); + + final RenderAnimatedSize box = tester.renderObject(find.byType(AnimatedSize)); + + await tester.pumpWidget( + const Center(), + ); + + expect(box.debugAnimation, isNotNull); + expect(box.debugAnimation!.isDisposed, isTrue); + expect(box.debugController, isNotNull); + expect( + () => box.debugController!.dispose(), + throwsA(isA<AssertionError>().having( + (AssertionError error) => error.message, + 'message', + equalsIgnoringHashCodes( + 'AnimationController.dispose() called more than once.\n' + 'A given AnimationController cannot be disposed more than once.\n' + 'The following AnimationController object was disposed multiple times:\n' + ' AnimationController#00000(⏮ 0.000; paused; DISPOSED)', + ), + )), + ); + }); }); } From b90c1a87661dfea28b85b04b18eace853fa994ff Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 18:01:23 -0400 Subject: [PATCH 1198/1547] Roll Flutter Engine from 0774ddcda9b0 to 06696e768c1b (4 revisions) (#134462) https://github.com/flutter/engine/compare/0774ddcda9b0...06696e768c1b 2023-09-11 jacksongardner@google.com Revert "Remove some of our hacks around JSPromise now that we have better APIs." (flutter/engine#45660) 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 3ed290acb65f to e6225224fb4e (2 revisions) (flutter/engine#45658) 2023-09-11 kjlubick@users.noreply.github.com Update skwasm build to use safer flush call (flutter/engine#45652) 2023-09-11 jacksongardner@google.com Remove some of our hacks around JSPromise now that we have better APIs. (flutter/engine#45591) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4f77a2a708da7..df48d2e90baf4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0774ddcda9b0b7878e586a6135a026095d4feb33 +06696e768c1b1abd2393099d4ccacfdff2ad4739 From adaf78a60dd9af5b7d16f87b56a7c35b981af29f Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Tue, 12 Sep 2023 00:35:09 +0200 Subject: [PATCH 1199/1547] Cover focus tests with leak tracking (#134457) --- .../test/widgets/focus_manager_test.dart | 271 ++++++++++++++---- .../test/widgets/focus_scope_test.dart | 133 ++++++--- .../test/widgets/focus_traversal_test.dart | 248 ++++++++++++---- 3 files changed, 501 insertions(+), 151 deletions(-) diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 600fdb16dd235..fea504a93e826 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -21,13 +21,16 @@ void main() { } group(FocusNode, () { - testWidgets('Can add children.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can add children.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusNode parent = FocusNode(); + addTearDown(parent.dispose); final FocusAttachment parentAttachment = parent.attach(context); final FocusNode child1 = FocusNode(); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); parentAttachment.reparent(parent: tester.binding.focusManager.rootScope); child1Attachment.reparent(parent: parent); @@ -41,13 +44,16 @@ void main() { expect(parent.children.last, equals(child2)); }); - testWidgets('Can remove children.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can remove children.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusNode parent = FocusNode(); + addTearDown(parent.dispose); final FocusAttachment parentAttachment = parent.attach(context); final FocusNode child1 = FocusNode(); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); parentAttachment.reparent(parent: tester.binding.focusManager.rootScope); child1Attachment.reparent(parent: parent); @@ -67,9 +73,12 @@ void main() { expect(parent.children, isEmpty); }); - testWidgets('Geometry is transformed properly.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Geometry is transformed properly.', (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: 'Test Node 1'); + addTearDown(focusNode1.dispose); final FocusNode focusNode2 = FocusNode(debugLabel: 'Test Node 2'); + addTearDown(focusNode2.dispose); + await tester.pumpWidget( Padding( padding: const EdgeInsets.all(8.0), @@ -104,17 +113,22 @@ void main() { expect(focusNode2.offset, equals(const Offset(443.0, 194.5))); }); - testWidgets('descendantsAreFocusable disables focus for descendants.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('descendantsAreFocusable disables focus for descendants.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parent1Attachment.reparent(parent: scope); @@ -152,17 +166,22 @@ void main() { expect(scope.traversalDescendants.contains(child2), isFalse); }); - testWidgets('descendantsAreTraversable disables traversal for descendants.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('descendantsAreTraversable disables traversal for descendants.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -185,17 +204,22 @@ void main() { expect(scope.traversalDescendants, equals(<FocusNode>[])); }); - testWidgets("canRequestFocus doesn't affect traversalChildren", (WidgetTester tester) async { + testWidgetsWithLeakTracking("canRequestFocus doesn't affect traversalChildren", (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parent1Attachment.reparent(parent: scope); @@ -216,11 +240,11 @@ void main() { expect(scope.traversalChildren.contains(parent2), isFalse); }); - testWidgets('implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - FocusNode( - debugLabel: 'Label', - ).debugFillProperties(builder); + final FocusNode focusNode = FocusNode(debugLabel: 'Label'); + addTearDown(focusNode.dispose); + focusNode.debugFillProperties(builder); final List<String> description = builder.properties.map((DiagnosticsNode n) => n.toString()).toList(); expect(description, <String>[ 'context: null', @@ -232,8 +256,13 @@ void main() { ]); }); - testWidgets('onKeyEvent and onKey correctly cooperate', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(debugLabel: 'Test Node 3'); + testWidgetsWithLeakTracking('onKeyEvent and onKey correctly cooperate', (WidgetTester tester) async { + final FocusNode focusNode1 = FocusNode(debugLabel: 'Test Node 1'); + addTearDown(focusNode1.dispose); + final FocusNode focusNode2 = FocusNode(debugLabel: 'Test Node 2'); + addTearDown(focusNode2.dispose); + final FocusNode focusNode3 = FocusNode(debugLabel: 'Test Node 3'); + addTearDown(focusNode3.dispose); List<List<KeyEventResult>> results = <List<KeyEventResult>>[ <KeyEventResult>[KeyEventResult.ignored, KeyEventResult.ignored], <KeyEventResult>[KeyEventResult.ignored, KeyEventResult.ignored], @@ -243,7 +272,7 @@ void main() { await tester.pumpWidget( Focus( - focusNode: FocusNode(debugLabel: 'Test Node 1'), + focusNode: focusNode1, onKeyEvent: (_, KeyEvent event) { logs.add(0); return results[0][0]; @@ -253,7 +282,7 @@ void main() { return results[0][1]; }, child: Focus( - focusNode: FocusNode(debugLabel: 'Test Node 2'), + focusNode: focusNode2, onKeyEvent: (_, KeyEvent event) { logs.add(10); return results[1][0]; @@ -263,7 +292,7 @@ void main() { return results[1][1]; }, child: Focus( - focusNode: focusNode, + focusNode: focusNode3, onKeyEvent: (_, KeyEvent event) { logs.add(20); return results[2][0]; @@ -277,7 +306,7 @@ void main() { ), ), ); - focusNode.requestFocus(); + focusNode3.requestFocus(); await tester.pump(); // All ignored. @@ -328,15 +357,19 @@ void main() { group(FocusScopeNode, () { - testWidgets('Can setFirstFocus on a scope with no manager.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can setFirstFocus on a scope with no manager.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); scope.attach(context); final FocusScopeNode parent = FocusScopeNode(debugLabel: 'Parent'); + addTearDown(parent.dispose); parent.attach(context); final FocusScopeNode child1 = FocusScopeNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusScopeNode child2 = FocusScopeNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); child2.attach(context); scope.setFirstFocus(parent); parent.setFirstFocus(child1); @@ -353,15 +386,19 @@ void main() { expect(scope.focusedChild, equals(parent)); }); - testWidgets('Removing a node removes it from scope.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Removing a node removes it from scope.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent = FocusNode(); + addTearDown(parent.dispose); final FocusAttachment parentAttachment = parent.attach(context); final FocusNode child1 = FocusNode(); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parentAttachment.reparent(parent: scope); @@ -378,15 +415,19 @@ void main() { expect(scope.focusedChild, isNull); }); - testWidgets('Can add children to scope and focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can add children to scope and focus', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent = FocusNode(); + addTearDown(parent.dispose); final FocusAttachment parentAttachment = parent.attach(context); final FocusNode child1 = FocusNode(); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parentAttachment.reparent(parent: scope); @@ -418,11 +459,13 @@ void main() { expect(child2.hasPrimaryFocus, isTrue); }); - testWidgets('Requesting focus before adding to tree results in a request after adding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Requesting focus before adding to tree results in a request after adding', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode child = FocusNode(); + addTearDown(child.dispose); child.requestFocus(); expect(child.hasPrimaryFocus, isFalse); // not attached yet. @@ -438,15 +481,19 @@ void main() { expect(child.hasPrimaryFocus, isTrue); // now attached and parented, so focus finally happened. }); - testWidgets('Autofocus works.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Autofocus works.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent = FocusNode(debugLabel: 'Parent'); + addTearDown(parent.dispose); final FocusAttachment parentAttachment = parent.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parentAttachment.reparent(parent: scope); @@ -475,15 +522,19 @@ void main() { expect(child2.hasPrimaryFocus, isFalse); }); - testWidgets('Adding a focusedChild to a scope sets scope as focusedChild in parent scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adding a focusedChild to a scope sets scope as focusedChild in parent scope', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode child1 = FocusNode(); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: scope1); @@ -507,17 +558,22 @@ void main() { expect(child2.hasPrimaryFocus, isFalse); }); - testWidgets('Can move node with focus without losing focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move node with focus without losing focus', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parent1Attachment.reparent(parent: scope); @@ -544,17 +600,22 @@ void main() { expect(parent2.children.first, equals(child1)); }); - testWidgets('canRequestFocus affects children.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('canRequestFocus affects children.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parent1Attachment.reparent(parent: scope); @@ -584,17 +645,22 @@ void main() { expect(parent1.traversalChildren.contains(child2), isFalse); }); - testWidgets("skipTraversal doesn't affect children.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("skipTraversal doesn't affect children.", (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope'); + addTearDown(scope.dispose); final FocusAttachment scopeAttachment = scope.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); scopeAttachment.reparent(parent: tester.binding.focusManager.rootScope); parent1Attachment.reparent(parent: scope); @@ -619,23 +685,31 @@ void main() { expect(scope.traversalDescendants.contains(child2), isTrue); }); - testWidgets('Can move node between scopes and lose scope focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move node between scopes and lose scope focus', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1')..attach(context); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'child3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'child4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -657,23 +731,31 @@ void main() { expect(parent2.children.contains(child1), isTrue); }); - testWidgets('ancestors and descendants are computed and recomputed properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors and descendants are computed and recomputed properly', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1'); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'child3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'child4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -693,23 +775,31 @@ void main() { expect(tester.binding.focusManager.rootScope.descendants, equals(<FocusNode>[child1, child3, child4, parent2, scope2, child2, parent1, scope1])); }); - testWidgets('Can move focus between scopes and keep focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move focus between scopes and keep focus', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -751,23 +841,31 @@ void main() { expect(scope2.focusedChild, equals(child4)); }); - testWidgets('Unfocus with disposition previouslyFocusedChild works properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unfocus with disposition previouslyFocusedChild works properly', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1')..attach(context); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'child3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'child4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -832,23 +930,31 @@ void main() { expect(child3.hasPrimaryFocus, isTrue); }); - testWidgets('Unfocus with disposition scope works properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unfocus with disposition scope works properly', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1')..attach(context); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'child3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'child4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -917,23 +1023,31 @@ void main() { expect(FocusManager.instance.rootScope.hasPrimaryFocus, isTrue); }); - testWidgets('Unfocus works properly when some nodes are unfocusable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unfocus works properly when some nodes are unfocusable', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1')..attach(context); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'child3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'child4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -983,23 +1097,31 @@ void main() { expect(child2.hasPrimaryFocus, isFalse); }); - testWidgets('Requesting focus on a scope works properly when some focusedChild nodes are unfocusable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Requesting focus on a scope works properly when some focusedChild nodes are unfocusable', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1')..attach(context); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'child3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'child4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -1037,7 +1159,7 @@ void main() { expect(child4.hasPrimaryFocus, isTrue); }); - testWidgets('Key handling bubbles up and terminates when handled.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Key handling bubbles up and terminates when handled.', (WidgetTester tester) async { final Set<FocusNode> receivedAnEvent = <FocusNode>{}; final Set<FocusNode> shouldHandle = <FocusNode>{}; KeyEventResult handleEvent(FocusNode node, RawKeyEvent event) { @@ -1055,20 +1177,28 @@ void main() { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'Scope 1'); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context, onKey: handleEvent); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'Scope 2'); + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context, onKey: handleEvent); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1', onKey: handleEvent); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2', onKey: handleEvent); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context, onKey: handleEvent); final FocusNode child2 = FocusNode(debugLabel: 'Child 2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context, onKey: handleEvent); final FocusNode child3 = FocusNode(debugLabel: 'Child 3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context, onKey: handleEvent); final FocusNode child4 = FocusNode(debugLabel: 'Child 4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context, onKey: handleEvent); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -1101,7 +1231,7 @@ void main() { expect(receivedAnEvent, isEmpty); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Initial highlight mode guesses correctly.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial highlight mode guesses correctly.', (WidgetTester tester) async { FocusManager.instance.highlightStrategy = FocusHighlightStrategy.automatic; switch (defaultTargetPlatform) { case TargetPlatform.fuchsia: @@ -1115,7 +1245,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('Mouse events change initial focus highlight mode on mobile.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse events change initial focus highlight mode on mobile.', (WidgetTester tester) async { expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.touch)); RendererBinding.instance.initMouseTracker(); // Clear out the mouse state. final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 0); @@ -1123,7 +1253,7 @@ void main() { expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional)); }, variant: TargetPlatformVariant.mobile()); - testWidgets('Mouse events change initial focus highlight mode on desktop.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse events change initial focus highlight mode on desktop.', (WidgetTester tester) async { expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional)); RendererBinding.instance.initMouseTracker(); // Clear out the mouse state. final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 0); @@ -1131,12 +1261,12 @@ void main() { expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional)); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Keyboard events change initial focus highlight mode.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard events change initial focus highlight mode.', (WidgetTester tester) async { await tester.sendKeyEvent(LogicalKeyboardKey.enter); expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.traditional)); }, variant: TargetPlatformVariant.all()); - testWidgets('Events change focus highlight mode.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Events change focus highlight mode.', (WidgetTester tester) async { await setupWidget(tester); int callCount = 0; FocusHighlightMode? lastMode; @@ -1177,11 +1307,11 @@ void main() { expect(FocusManager.instance.highlightMode, equals(FocusHighlightMode.touch)); }); - testWidgets('implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - FocusScopeNode( - debugLabel: 'Scope Label', - ).debugFillProperties(builder); + final FocusScopeNode scope = FocusScopeNode(debugLabel: 'Scope Label'); + addTearDown(scope.dispose); + scope.debugFillProperties(builder); final List<String> description = builder.properties.map((DiagnosticsNode n) => n.toString()).toList(); expect(description, <String>[ 'context: null', @@ -1193,23 +1323,31 @@ void main() { ]); }); - testWidgets('debugDescribeFocusTree produces correct output', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugDescribeFocusTree produces correct output', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'Scope 1'); + addTearDown(scope1.dispose); final FocusAttachment scope1Attachment = scope1.attach(context); final FocusScopeNode scope2 = FocusScopeNode(); // No label, Just to test that it works. + addTearDown(scope2.dispose); final FocusAttachment scope2Attachment = scope2.attach(context); final FocusNode parent1 = FocusNode(debugLabel: 'Parent 1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode parent2 = FocusNode(debugLabel: 'Parent 2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'Child 1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(); // No label, Just to test that it works. + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); final FocusNode child3 = FocusNode(debugLabel: 'Child 3'); + addTearDown(child3.dispose); final FocusAttachment child3Attachment = child3.attach(context); final FocusNode child4 = FocusNode(debugLabel: 'Child 4'); + addTearDown(child4.dispose); final FocusAttachment child4Attachment = child4.attach(context); scope1Attachment.reparent(parent: tester.binding.focusManager.rootScope); scope2Attachment.reparent(parent: tester.binding.focusManager.rootScope); @@ -1269,11 +1407,13 @@ void main() { }); group('Autofocus', () { - testWidgets( + testWidgetsWithLeakTracking( 'works when the previous focused node is detached', (WidgetTester tester) async { final FocusNode node1 = FocusNode(); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(); + addTearDown(node2.dispose); await tester.pumpWidget( FocusScope( @@ -1294,11 +1434,13 @@ void main() { expect(node2.hasPrimaryFocus, isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'node detached before autofocus is applied', (WidgetTester tester) async { final FocusScopeNode scopeNode = FocusScopeNode(); + addTearDown(scopeNode.dispose); final FocusNode node1 = FocusNode(); + addTearDown(node1.dispose); await tester.pumpWidget( FocusScope( @@ -1322,10 +1464,13 @@ void main() { expect(scopeNode.hasPrimaryFocus, isTrue); }); - testWidgets('autofocus the first candidate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autofocus the first candidate', (WidgetTester tester) async { final FocusNode node1 = FocusNode(); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(); + addTearDown(node2.dispose); final FocusNode node3 = FocusNode(); + addTearDown(node3.dispose); await tester.pumpWidget( Directionality( @@ -1355,10 +1500,13 @@ void main() { expect(node1.hasPrimaryFocus, isTrue); }); - testWidgets('Autofocus works with global key reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Autofocus works with global key reparenting', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1'); + addTearDown(scope1.dispose); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -1409,15 +1557,19 @@ void main() { }); }); - testWidgets("Doesn't lose focused child when reparenting if the nearestScope doesn't change.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Doesn't lose focused child when reparenting if the nearestScope doesn't change.", (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode parent1 = FocusScopeNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusScopeNode parent2 = FocusScopeNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); parent1Attachment.reparent(parent: tester.binding.focusManager.rootScope); child1Attachment.reparent(parent: parent1); @@ -1435,7 +1587,7 @@ void main() { expect(parent1.focusedChild, equals(child2)); }); - testWidgets('Ancestors get notified exactly as often as needed if focused child changes focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ancestors get notified exactly as often as needed if focused child changes focus.', (WidgetTester tester) async { bool topFocus = false; bool parent1Focus = false; bool parent2Focus = false; @@ -1460,14 +1612,19 @@ void main() { } final BuildContext context = await setupWidget(tester); final FocusScopeNode top = FocusScopeNode(debugLabel: 'top'); + addTearDown(top.dispose); final FocusAttachment topAttachment = top.attach(context); final FocusScopeNode parent1 = FocusScopeNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusScopeNode parent2 = FocusScopeNode(debugLabel: 'parent2'); + addTearDown(parent2.dispose); final FocusAttachment parent2Attachment = parent2.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); topAttachment.reparent(parent: tester.binding.focusManager.rootScope); parent1Attachment.reparent(parent: top); @@ -1566,13 +1723,16 @@ void main() { expect(child2Notify, equals(0)); }); - testWidgets('Focus changes notify listeners.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus changes notify listeners.', (WidgetTester tester) async { final BuildContext context = await setupWidget(tester); final FocusScopeNode parent1 = FocusScopeNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); final FocusNode child2 = FocusNode(debugLabel: 'child2'); + addTearDown(child2.dispose); final FocusAttachment child2Attachment = child2.attach(context); parent1Attachment.reparent(parent: tester.binding.focusManager.rootScope); child1Attachment.reparent(parent: parent1); @@ -1618,9 +1778,12 @@ void main() { expect(()=> FocusNode().dispose(), dispatchesMemoryEvents(FocusNode)); }); - testWidgets('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { final FocusNode nodeA = FocusNode(debugLabel: 'a'); + addTearDown(nodeA.dispose); final FocusNode nodeB = FocusNode(debugLabel: 'b'); + addTearDown(nodeB.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -1664,7 +1827,7 @@ void main() { tester.binding.focusManager.removeListener(handleFocusChange); }); - testWidgets('debugFocusChanges causes logging of focus changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugFocusChanges causes logging of focus changes', (WidgetTester tester) async { final bool oldDebugFocusChanges = debugFocusChanges; final DebugPrintCallback oldDebugPrint = debugPrint; final StringBuffer messages = StringBuffer(); @@ -1675,8 +1838,10 @@ void main() { try { final BuildContext context = await setupWidget(tester); final FocusScopeNode parent1 = FocusScopeNode(debugLabel: 'parent1'); + addTearDown(parent1.dispose); final FocusAttachment parent1Attachment = parent1.attach(context); final FocusNode child1 = FocusNode(debugLabel: 'child1'); + addTearDown(child1.dispose); final FocusAttachment child1Attachment = child1.attach(context); parent1Attachment.reparent(parent: tester.binding.focusManager.rootScope); child1Attachment.reparent(parent: parent1); @@ -1709,7 +1874,7 @@ void main() { expect(messagesStr, contains(RegExp(r'FOCUS: Scheduling update, current focus is null, next focus will be FocusScopeNode#.*parent1'))); }); - testWidgets("doesn't call toString on a focus node when debugFocusChanges is false", (WidgetTester tester) async { + testWidgetsWithLeakTracking("doesn't call toString on a focus node when debugFocusChanges is false", (WidgetTester tester) async { final bool oldDebugFocusChanges = debugFocusChanges; final DebugPrintCallback oldDebugPrint = debugPrint; final StringBuffer messages = StringBuffer(); diff --git a/packages/flutter/test/widgets/focus_scope_test.dart b/packages/flutter/test/widgets/focus_scope_test.dart index b11590fe8fb39..2f09b957badae 100644 --- a/packages/flutter/test/widgets/focus_scope_test.dart +++ b/packages/flutter/test/widgets/focus_scope_test.dart @@ -6,12 +6,13 @@ import 'package:flutter/semantics.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { group('FocusScope', () { - testWidgets('Can focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can focus', (WidgetTester tester) async { final GlobalKey<TestFocusState> key = GlobalKey(); await tester.pumpWidget( @@ -27,7 +28,7 @@ void main() { expect(find.text('A FOCUSED'), findsOneWidget); }); - testWidgets('Can unfocus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can unfocus', (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); await tester.pumpWidget( @@ -62,7 +63,7 @@ void main() { expect(find.text('B FOCUSED'), findsOneWidget); }); - testWidgets('Autofocus works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Autofocus works', (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); await tester.pumpWidget( @@ -82,7 +83,7 @@ void main() { expect(find.text('B FOCUSED'), findsOneWidget); }); - testWidgets('Can have multiple focused children and they update accordingly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can have multiple focused children and they update accordingly', (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); @@ -129,9 +130,11 @@ void main() { // This moves a focus node first into a focus scope that is added to its // parent, and then out of that focus scope again. - testWidgets('Can move focus in and out of FocusScope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move focus in and out of FocusScope', (WidgetTester tester) async { final FocusScopeNode parentFocusScope = FocusScopeNode(debugLabel: 'Parent Scope Node'); + addTearDown(parentFocusScope.dispose); final FocusScopeNode childFocusScope = FocusScopeNode(debugLabel: 'Child Scope Node'); + addTearDown(childFocusScope.dispose); final GlobalKey<TestFocusState> key = GlobalKey(); // Initially create the focus inside of the parent FocusScope. @@ -274,10 +277,13 @@ void main() { childAttachment.detach(); }); - testWidgets('Setting first focus requests focus for the scope properly.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting first focus requests focus for the scope properly.', (WidgetTester tester) async { final FocusScopeNode parentFocusScope = FocusScopeNode(debugLabel: 'Parent Scope Node'); + addTearDown(parentFocusScope.dispose); final FocusScopeNode childFocusScope1 = FocusScopeNode(debugLabel: 'Child Scope Node 1'); + addTearDown(childFocusScope1.dispose); final FocusScopeNode childFocusScope2 = FocusScopeNode(debugLabel: 'Child Scope Node 2'); + addTearDown(childFocusScope2.dispose); final GlobalKey<TestFocusState> keyA = GlobalKey(debugLabel: 'Key A'); final GlobalKey<TestFocusState> keyB = GlobalKey(debugLabel: 'Key B'); final GlobalKey<TestFocusState> keyC = GlobalKey(debugLabel: 'Key C'); @@ -376,7 +382,7 @@ void main() { expect(childFocusScope2.isFirstFocus, isFalse); }); - testWidgets('Removing focused widget moves focus to next widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Removing focused widget moves focus to next widget', (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); @@ -420,10 +426,12 @@ void main() { expect(find.text('b'), findsOneWidget); }); - testWidgets('Adding a new FocusScope attaches the child to its parent.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adding a new FocusScope attaches the child to its parent.', (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final FocusScopeNode parentFocusScope = FocusScopeNode(debugLabel: 'Parent Scope Node'); + addTearDown(parentFocusScope.dispose); final FocusScopeNode childFocusScope = FocusScopeNode(debugLabel: 'Child Scope Node'); + addTearDown(childFocusScope.dispose); await tester.pumpWidget( FocusScope( @@ -466,11 +474,15 @@ void main() { expect(find.text('A FOCUSED'), findsOneWidget); }); - testWidgets('Setting parentNode determines focus tree hierarchy.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting parentNode determines focus tree hierarchy.', (WidgetTester tester) async { final FocusNode topNode = FocusNode(debugLabel: 'Top'); + addTearDown(topNode.dispose); final FocusNode parentNode = FocusNode(debugLabel: 'Parent'); + addTearDown(parentNode.dispose); final FocusNode childNode = FocusNode(debugLabel: 'Child'); + addTearDown(childNode.dispose); final FocusNode insertedNode = FocusNode(debugLabel: 'Inserted'); + addTearDown(insertedNode.dispose); await tester.pumpWidget( FocusScope( @@ -532,11 +544,15 @@ void main() { expect(insertedNode.hasFocus, isFalse); }); - testWidgets('Setting parentNode determines focus scope tree hierarchy.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting parentNode determines focus scope tree hierarchy.', (WidgetTester tester) async { final FocusScopeNode topNode = FocusScopeNode(debugLabel: 'Top'); + addTearDown(topNode.dispose); final FocusScopeNode parentNode = FocusScopeNode(debugLabel: 'Parent'); + addTearDown(parentNode.dispose); final FocusScopeNode childNode = FocusScopeNode(debugLabel: 'Child'); + addTearDown(childNode.dispose); final FocusScopeNode insertedNode = FocusScopeNode(debugLabel: 'Inserted'); + addTearDown(insertedNode.dispose); await tester.pumpWidget( FocusScope.withExternalFocusNode( @@ -599,10 +615,11 @@ void main() { }); // Arguably, this isn't correct behavior, but it is what happens now. - testWidgets("Removing focused widget doesn't move focus to next widget within FocusScope", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Removing focused widget doesn't move focus to next widget within FocusScope", (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); final FocusScopeNode parentFocusScope = FocusScopeNode(debugLabel: 'Parent Scope'); + addTearDown(parentFocusScope.dispose); await tester.pumpWidget( FocusScope( @@ -656,12 +673,13 @@ void main() { expect(find.text('b'), findsOneWidget); }); - testWidgets('Removing a FocusScope removes its node from the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Removing a FocusScope removes its node from the tree', (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); final GlobalKey<TestFocusState> scopeKeyA = GlobalKey(); final GlobalKey<TestFocusState> scopeKeyB = GlobalKey(); final FocusScopeNode parentFocusScope = FocusScopeNode(debugLabel: 'Parent Scope'); + addTearDown(parentFocusScope.dispose); // This checks both FocusScopes that have their own nodes, as well as those // that use external nodes. @@ -719,13 +737,15 @@ void main() { }); // By "pinned", it means kept in the tree by a GlobalKey. - testWidgets("Removing pinned focused scope doesn't move focus to focused widget within next FocusScope", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Removing pinned focused scope doesn't move focus to focused widget within next FocusScope", (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); final GlobalKey<TestFocusState> scopeKeyA = GlobalKey(); final GlobalKey<TestFocusState> scopeKeyB = GlobalKey(); final FocusScopeNode parentFocusScope1 = FocusScopeNode(debugLabel: 'Parent Scope 1'); + addTearDown(parentFocusScope1.dispose); final FocusScopeNode parentFocusScope2 = FocusScopeNode(debugLabel: 'Parent Scope 2'); + addTearDown(parentFocusScope2.dispose); await tester.pumpWidget( FocusTraversalGroup( @@ -805,11 +825,13 @@ void main() { expect(find.text('B FOCUSED'), findsOneWidget); }); - testWidgets("Removing unpinned focused scope doesn't move focus to focused widget within next FocusScope", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Removing unpinned focused scope doesn't move focus to focused widget within next FocusScope", (WidgetTester tester) async { final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); final FocusScopeNode parentFocusScope1 = FocusScopeNode(debugLabel: 'Parent Scope 1'); + addTearDown(parentFocusScope1.dispose); final FocusScopeNode parentFocusScope2 = FocusScopeNode(debugLabel: 'Parent Scope 2'); + addTearDown(parentFocusScope2.dispose); await tester.pumpWidget( FocusTraversalGroup( @@ -885,9 +907,11 @@ void main() { expect(find.text('B FOCUSED'), findsOneWidget); }); - testWidgets('Moving widget from one scope to another retains focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving widget from one scope to another retains focus', (WidgetTester tester) async { final FocusScopeNode parentFocusScope1 = FocusScopeNode(); + addTearDown(parentFocusScope1.dispose); final FocusScopeNode parentFocusScope2 = FocusScopeNode(); + addTearDown(parentFocusScope2.dispose); final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); @@ -966,9 +990,11 @@ void main() { expect(find.text('b'), findsOneWidget); }); - testWidgets('Moving FocusScopeNodes retains focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving FocusScopeNodes retains focus', (WidgetTester tester) async { final FocusScopeNode parentFocusScope1 = FocusScopeNode(debugLabel: 'Scope 1'); + addTearDown(parentFocusScope1.dispose); final FocusScopeNode parentFocusScope2 = FocusScopeNode(debugLabel: 'Scope 2'); + addTearDown(parentFocusScope2.dispose); final GlobalKey<TestFocusState> keyA = GlobalKey(); final GlobalKey<TestFocusState> keyB = GlobalKey(); @@ -1052,7 +1078,7 @@ void main() { expect(find.text('b'), findsOneWidget); }); - testWidgets('Can focus root node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can focus root node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); await tester.pumpWidget( Focus( @@ -1071,8 +1097,9 @@ void main() { expect(rootNode, equals(firstElement.owner!.focusManager.rootScope)); }); - testWidgets('Can autofocus a node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can autofocus a node.', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( Focus( focusNode: focusNode, @@ -1095,9 +1122,11 @@ void main() { expect(focusNode.hasPrimaryFocus, isTrue); }); - testWidgets("Won't autofocus a node if one is already focused.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Won't autofocus a node if one is already focused.", (WidgetTester tester) async { final FocusNode focusNodeA = FocusNode(debugLabel: 'Test Node A'); + addTearDown(focusNodeA.dispose); final FocusNode focusNodeB = FocusNode(debugLabel: 'Test Node B'); + addTearDown(focusNodeB.dispose); await tester.pumpWidget( Column( children: <Widget>[ @@ -1134,9 +1163,10 @@ void main() { expect(focusNodeA.hasPrimaryFocus, isTrue); }); - testWidgets("FocusScope doesn't update the focusNode attributes when the widget updates if withExternalFocusNode is used", (WidgetTester tester) async { + testWidgetsWithLeakTracking("FocusScope doesn't update the focusNode attributes when the widget updates if withExternalFocusNode is used", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusScopeNode focusScopeNode = FocusScopeNode(); + addTearDown(focusScopeNode.dispose); bool? keyEventHandled; KeyEventResult handleCallback(FocusNode node, RawKeyEvent event) { keyEventHandled = true; @@ -1205,7 +1235,7 @@ void main() { }); group('Focus', () { - testWidgets('Focus.of stops at the nearest Focus widget.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus.of stops at the nearest Focus widget.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -1213,6 +1243,7 @@ void main() { final GlobalKey key5 = GlobalKey(debugLabel: '5'); final GlobalKey key6 = GlobalKey(debugLabel: '6'); final FocusScopeNode scopeNode = FocusScopeNode(); + addTearDown(scopeNode.dispose); await tester.pumpWidget( FocusScope( key: key1, @@ -1252,7 +1283,7 @@ void main() { expect(Focus.of(element5).parent!.parent, equals(root)); expect(Focus.of(element6).parent!.parent!.parent, equals(root)); }); - testWidgets('Can traverse Focus children.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can traverse Focus children.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -1326,7 +1357,7 @@ void main() { expect(keys, equals(<Key>[key7, key8])); }); - testWidgets('Can set focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set focus.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); late bool gotFocus; await tester.pumpWidget( @@ -1346,7 +1377,7 @@ void main() { expect(node.hasFocus, isTrue); }); - testWidgets('Focus is ignored when set to not focusable.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus is ignored when set to not focusable.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); bool? gotFocus; await tester.pumpWidget( @@ -1367,7 +1398,7 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('Focus is lost when set to not focusable.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus is lost when set to not focusable.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); bool? gotFocus; await tester.pumpWidget( @@ -1407,10 +1438,11 @@ void main() { expect(node.hasFocus, isFalse); }); - testWidgets('Child of unfocusable Focus can get focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Child of unfocusable Focus can get focus.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? gotFocus; await tester.pumpWidget( Focus( @@ -1439,7 +1471,7 @@ void main() { expect(unfocusableNode.hasFocus, isTrue); }); - testWidgets('Nodes are removed when all Focuses are removed.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nodes are removed when all Focuses are removed.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); late bool gotFocus; await tester.pumpWidget( @@ -1465,7 +1497,7 @@ void main() { expect(FocusManager.instance.rootScope.descendants, isEmpty); }); - testWidgets('Focus widgets set Semantics information about focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus widgets set Semantics information about focus', (WidgetTester tester) async { final GlobalKey<TestFocusState> key = GlobalKey(); await tester.pumpWidget( @@ -1494,7 +1526,7 @@ void main() { expect(semantics.hasFlag(SemanticsFlag.isFocusable), isFalse); }); - testWidgets('Setting canRequestFocus on focus node causes update.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting canRequestFocus on focus node causes update.', (WidgetTester tester) async { final GlobalKey<TestFocusState> key = GlobalKey(); final TestFocus testFocus = TestFocus(key: key); @@ -1511,7 +1543,7 @@ void main() { expect(key.currentState!.focusNode.canRequestFocus, isFalse); }); - testWidgets('canRequestFocus causes descendants of scope to be skipped.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('canRequestFocus causes descendants of scope to be skipped.', (WidgetTester tester) async { final GlobalKey scope1 = GlobalKey(debugLabel: 'scope1'); final GlobalKey scope2 = GlobalKey(debugLabel: 'scope2'); final GlobalKey focus1 = GlobalKey(debugLabel: 'focus1'); @@ -1620,11 +1652,15 @@ void main() { expect(Focus.of(container1.currentContext!).hasFocus, isTrue); }); - testWidgets('skipTraversal works as expected.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('skipTraversal works as expected.', (WidgetTester tester) async { final FocusScopeNode scope1 = FocusScopeNode(debugLabel: 'scope1'); + addTearDown(scope1.dispose); final FocusScopeNode scope2 = FocusScopeNode(debugLabel: 'scope2'); + addTearDown(scope2.dispose); final FocusNode focus1 = FocusNode(debugLabel: 'focus1'); + addTearDown(focus1.dispose); final FocusNode focus2 = FocusNode(debugLabel: 'focus2'); + addTearDown(focus2.dispose); Future<void> pumpTest({ bool traverseScope1 = false, @@ -1674,10 +1710,11 @@ void main() { expect(scope1.traversalDescendants, equals(<FocusNode>[focus2, focus1, scope2])); }); - testWidgets('descendantsAreFocusable works as expected.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('descendantsAreFocusable works as expected.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? gotFocus; await tester.pumpWidget( Focus( @@ -1713,11 +1750,15 @@ void main() { expect(unfocusableNode.hasFocus, isFalse); }); - testWidgets('descendantsAreTraversable works as expected.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('descendantsAreTraversable works as expected.', (WidgetTester tester) async { final FocusScopeNode scopeNode = FocusScopeNode(debugLabel: 'scope'); + addTearDown(scopeNode.dispose); final FocusNode node1 = FocusNode(debugLabel: 'node 1'); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(debugLabel: 'node 2'); + addTearDown(node2.dispose); final FocusNode node3 = FocusNode(debugLabel: 'node 3'); + addTearDown(node3.dispose); await tester.pumpWidget( FocusScope( @@ -1746,7 +1787,7 @@ void main() { expect(node2.traversalDescendants, equals(<FocusNode>[])); }); - testWidgets("Focus doesn't introduce a Semantics node when includeSemantics is false", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Focus doesn't introduce a Semantics node when includeSemantics is false", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Focus(includeSemantics: false, child: Container())); final TestSemantics expectedSemantics = TestSemantics.root(); @@ -1754,9 +1795,10 @@ void main() { semantics.dispose(); }); - testWidgets('Focus updates the onKey handler when the widget updates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus updates the onKey handler when the widget updates', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? keyEventHandled; KeyEventResult handleCallback(FocusNode node, RawKeyEvent event) { keyEventHandled = true; @@ -1803,9 +1845,10 @@ void main() { expect(keyEventHandled, isTrue); }); - testWidgets('Focus updates the onKeyEvent handler when the widget updates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus updates the onKeyEvent handler when the widget updates', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? keyEventHandled; KeyEventResult handleEventCallback(FocusNode node, KeyEvent event) { keyEventHandled = true; @@ -1852,9 +1895,10 @@ void main() { expect(keyEventHandled, isTrue); }); - testWidgets("Focus doesn't update the focusNode attributes when the widget updates if withExternalFocusNode is used", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Focus doesn't update the focusNode attributes when the widget updates if withExternalFocusNode is used", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? keyEventHandled; KeyEventResult handleCallback(FocusNode node, RawKeyEvent event) { keyEventHandled = true; @@ -1921,7 +1965,7 @@ void main() { expect(keyEventHandled, isTrue); }); - testWidgets('Focus passes changes in attribute values to its focus node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus passes changes in attribute values to its focus node', (WidgetTester tester) async { await tester.pumpWidget( Focus( child: Container(), @@ -1931,10 +1975,11 @@ void main() { }); group('ExcludeFocus', () { - testWidgets("Descendants of ExcludeFocus aren't focusable.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Descendants of ExcludeFocus aren't focusable.", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? gotFocus; await tester.pumpWidget( ExcludeFocus( @@ -1970,10 +2015,13 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/61700 - testWidgets("ExcludeFocus doesn't transfer focus to another descendant.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ExcludeFocus doesn't transfer focus to another descendant.", (WidgetTester tester) async { final FocusNode parentFocusNode = FocusNode(debugLabel: 'group'); + addTearDown(parentFocusNode.dispose); final FocusNode focusNode1 = FocusNode(debugLabel: 'node 1'); + addTearDown(focusNode1.dispose); final FocusNode focusNode2 = FocusNode(debugLabel: 'node 2'); + addTearDown(focusNode2.dispose); await tester.pumpWidget( ExcludeFocus( excluding: false, @@ -2039,7 +2087,7 @@ void main() { expect(parentFocusNode.enclosingScope!.hasPrimaryFocus, isTrue); }); - testWidgets("ExcludeFocus doesn't introduce a Semantics node", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ExcludeFocus doesn't introduce a Semantics node", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(ExcludeFocus(child: Container())); final TestSemantics expectedSemantics = TestSemantics.root(); @@ -2048,8 +2096,9 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/92693 - testWidgets('Setting parent FocusScope.canRequestFocus to false, does not set descendant Focus._internalNode._canRequestFocus to false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting parent FocusScope.canRequestFocus to false, does not set descendant Focus._internalNode._canRequestFocus to false', (WidgetTester tester) async { final FocusNode childFocusNode = FocusNode(debugLabel: 'node 1'); + addTearDown(childFocusNode.dispose); Widget buildFocusTree({required bool parentCanRequestFocus}) { return FocusScope( diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index 04cf497d08da4..2ce49be74e93d 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -8,12 +8,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { group(WidgetOrderTraversalPolicy, () { - testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Find the initial focus if there is none yet.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -52,7 +53,7 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Find the initial focus if there is none yet and traversing backwards.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Find the initial focus if there is none yet and traversing backwards.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -95,7 +96,7 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Move focus to next node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move focus to next node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -212,7 +213,7 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Move focus to previous node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move focus to previous node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -286,9 +287,15 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Move focus to next/previous node while skipping nodes in policy', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move focus to next/previous node while skipping nodes in policy', (WidgetTester tester) async { final List<FocusNode> nodes = List<FocusNode>.generate(7, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + await tester.pumpWidget( FocusTraversalGroup( policy: SkipAllButFirstAndLastPolicy(), @@ -320,11 +327,14 @@ void main() { expect(nodes[0].hasPrimaryFocus, isTrue); }); - testWidgets('Find the initial focus when a route is pushed or popped.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Find the initial focus when a route is pushed or popped.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode testNode1 = FocusNode(debugLabel: 'First Focus Node'); + addTearDown(testNode1.dispose); final FocusNode testNode2 = FocusNode(debugLabel: 'Second Focus Node'); + addTearDown(testNode2.dispose); + await tester.pumpWidget( MaterialApp( home: FocusTraversalGroup( @@ -386,9 +396,10 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Custom requestFocusCallback gets called on the next/previous focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom requestFocusCallback gets called on the next/previous focus.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode testNode1 = FocusNode(debugLabel: 'Focus Node'); + addTearDown(testNode1.dispose); bool calledCallback = false; await tester.pumpWidget( @@ -430,10 +441,14 @@ void main() { }); - testWidgets('Nested navigator does not trap focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested navigator does not trap focus', (WidgetTester tester) async { final FocusNode node1 = FocusNode(); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(); + addTearDown(node2.dispose); final FocusNode node3 = FocusNode(); + addTearDown(node3.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -517,7 +532,7 @@ void main() { }); group(ReadingOrderTraversalPolicy, () { - testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Find the initial focus if there is none yet.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -556,7 +571,7 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Move reading focus to next node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move reading focus to next node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -671,7 +686,7 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Move reading focus to previous node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move reading focus to previous node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); @@ -745,10 +760,17 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Focus order is correct in the presence of different directionalities.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus order is correct in the presence of different directionalities.', (WidgetTester tester) async { const int nodeCount = 10; final FocusScopeNode scopeNode = FocusScopeNode(); + addTearDown(scopeNode.dispose); final List<FocusNode> nodes = List<FocusNode>.generate(nodeCount, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + Widget buildTest(TextDirection topDirection) { return Directionality( textDirection: topDirection, @@ -860,9 +882,15 @@ void main() { expect(order, orderedEquals(<int>[0, 1, 2, 4, 3, 5, 6, 8, 7, 9])); }); - testWidgets('Focus order is reading order regardless of widget order, even when overlapping.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus order is reading order regardless of widget order, even when overlapping.', (WidgetTester tester) async { const int nodeCount = 10; final List<FocusNode> nodes = List<FocusNode>.generate(nodeCount, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -954,9 +982,10 @@ void main() { expect(order, orderedEquals(<int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 0])); }); - testWidgets('Custom requestFocusCallback gets called on the next/previous focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom requestFocusCallback gets called on the next/previous focus.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode testNode1 = FocusNode(debugLabel: 'Focus Node'); + addTearDown(testNode1.dispose); bool calledCallback = false; await tester.pumpWidget( @@ -1001,7 +1030,7 @@ void main() { }); group(OrderedTraversalPolicy, () { - testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Find the initial focus if there is none yet.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); await tester.pumpWidget(FocusTraversalGroup( @@ -1040,9 +1069,15 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Fall back to the secondary sort if no FocusTraversalOrder exists.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fall back to the secondary sort if no FocusTraversalOrder exists.', (WidgetTester tester) async { const int nodeCount = 10; final List<FocusNode> nodes = List<FocusNode>.generate(nodeCount, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -1079,9 +1114,15 @@ void main() { } }); - testWidgets('Move focus to next/previous node using numerical order.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move focus to next/previous node using numerical order.', (WidgetTester tester) async { const int nodeCount = 10; final List<FocusNode> nodes = List<FocusNode>.generate(nodeCount, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1120,12 +1161,18 @@ void main() { } }); - testWidgets('Move focus to next/previous node using lexical order.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move focus to next/previous node using lexical order.', (WidgetTester tester) async { const int nodeCount = 10; /// Generate ['J' ... 'A']; final List<String> keys = List<String>.generate(nodeCount, (int index) => String.fromCharCode('A'.codeUnits[0] + nodeCount - index - 1)); final List<FocusNode> nodes = List<FocusNode>.generate(nodeCount, (int index) => FocusNode(debugLabel: 'Node ${keys[index]}')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1164,10 +1211,17 @@ void main() { } }); - testWidgets('Focus order is correct in the presence of FocusTraversalPolicyGroups.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus order is correct in the presence of FocusTraversalPolicyGroups.', (WidgetTester tester) async { const int nodeCount = 10; final FocusScopeNode scopeNode = FocusScopeNode(); + addTearDown(scopeNode.dispose); final List<FocusNode> nodes = List<FocusNode>.generate(nodeCount, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1291,11 +1345,14 @@ void main() { expect(order, orderedEquals(expectedOrder)); }); - testWidgets('Find the initial focus when a route is pushed or popped.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Find the initial focus when a route is pushed or popped.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode testNode1 = FocusNode(debugLabel: 'First Focus Node'); + addTearDown(testNode1.dispose); final FocusNode testNode2 = FocusNode(debugLabel: 'Second Focus Node'); + addTearDown(testNode2.dispose); + await tester.pumpWidget( MaterialApp( home: FocusTraversalGroup( @@ -1363,9 +1420,10 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Custom requestFocusCallback gets called on the next/previous focus.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom requestFocusCallback gets called on the next/previous focus.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode testNode1 = FocusNode(debugLabel: 'Focus Node'); + addTearDown(testNode1.dispose); bool calledCallback = false; await tester.pumpWidget( @@ -1410,7 +1468,7 @@ void main() { }); group(DirectionalFocusTraversalPolicyMixin, () { - testWidgets('Move focus in all directions.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Move focus in all directions.', (WidgetTester tester) async { final GlobalKey upperLeftKey = GlobalKey(debugLabel: 'upperLeftKey'); final GlobalKey upperRightKey = GlobalKey(debugLabel: 'upperRightKey'); final GlobalKey lowerLeftKey = GlobalKey(debugLabel: 'lowerLeftKey'); @@ -1550,9 +1608,15 @@ void main() { expect(scope.hasFocus, isTrue); }); - testWidgets('Directional focus avoids hysteresis.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directional focus avoids hysteresis.', (WidgetTester tester) async { List<bool?> focus = List<bool?>.generate(6, (int _) => null); final List<FocusNode> nodes = List<FocusNode>.generate(6, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); + Focus makeFocus(int index) { return Focus( debugLabel: '[$index]', @@ -1668,11 +1732,16 @@ void main() { clear(); }); - testWidgets('Directional prefers the closest node even on irregular grids', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directional prefers the closest node even on irregular grids', (WidgetTester tester) async { const int cols = 3; const int rows = 3; List<bool?> focus = List<bool?>.generate(rows * cols, (int _) => null); final List<FocusNode> nodes = List<FocusNode>.generate(rows * cols, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); Widget makeFocus(int row, int col) { final int index = row * rows + col; @@ -1804,10 +1873,15 @@ void main() { clear(); }); - testWidgets('Closest vertical is picked when only out of band items are considered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Closest vertical is picked when only out of band items are considered', (WidgetTester tester) async { const int rows = 4; List<bool?> focus = List<bool?>.generate(rows, (int _) => null); final List<FocusNode> nodes = List<FocusNode>.generate(rows, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); Widget makeFocus(int row) { return Padding( @@ -1890,10 +1964,15 @@ void main() { clear(); }); - testWidgets('Closest horizontal is picked when only out of band items are considered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Closest horizontal is picked when only out of band items are considered', (WidgetTester tester) async { const int cols = 4; List<bool?> focus = List<bool?>.generate(cols, (int _) => null); final List<FocusNode> nodes = List<FocusNode>.generate(cols, (int index) => FocusNode(debugLabel: 'Node $index')); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); Widget makeFocus(int col) { return Padding( @@ -1976,7 +2055,7 @@ void main() { clear(); }); - testWidgets('Can find first focus in all directions.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can find first focus in all directions.', (WidgetTester tester) async { final GlobalKey upperLeftKey = GlobalKey(debugLabel: 'upperLeftKey'); final GlobalKey upperRightKey = GlobalKey(debugLabel: 'upperRightKey'); final GlobalKey lowerLeftKey = GlobalKey(debugLabel: 'lowerLeftKey'); @@ -2036,10 +2115,13 @@ void main() { expect(policy.findFirstFocusInDirection(scope, TraversalDirection.right), equals(upperLeftNode)); }); - testWidgets('Can find focus when policy data dirty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can find focus when policy data dirty', (WidgetTester tester) async { final FocusNode focusTop = FocusNode(debugLabel: 'top'); + addTearDown(focusTop.dispose); final FocusNode focusCenter = FocusNode(debugLabel: 'center'); + addTearDown(focusCenter.dispose); final FocusNode focusBottom = FocusNode(debugLabel: 'bottom'); + addTearDown(focusBottom.dispose); final FocusTraversalPolicy policy = ReadingOrderTraversalPolicy(); await tester.pumpWidget(FocusTraversalGroup( @@ -2087,7 +2169,7 @@ void main() { expect(focusTop.hasFocus, isTrue); }); - testWidgets('Focus traversal actions are invoked when shortcuts are used.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal actions are invoked when shortcuts are used.', (WidgetTester tester) async { final GlobalKey upperLeftKey = GlobalKey(debugLabel: 'upperLeftKey'); final GlobalKey upperRightKey = GlobalKey(debugLabel: 'upperRightKey'); final GlobalKey lowerLeftKey = GlobalKey(debugLabel: 'lowerLeftKey'); @@ -2176,7 +2258,7 @@ void main() { expect(Focus.of(upperLeftKey.currentContext!).hasPrimaryFocus, isTrue); }, skip: isBrowser, variant: KeySimulatorTransitModeVariant.all()); // https://github.com/flutter/flutter/issues/35347 - testWidgets('Focus traversal actions works when current focus skip traversal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal actions works when current focus skip traversal', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: 'key1'); final GlobalKey key2 = GlobalKey(debugLabel: 'key2'); final GlobalKey key3 = GlobalKey(debugLabel: 'key3'); @@ -2231,12 +2313,21 @@ void main() { expect(Focus.of(key3.currentContext!).hasPrimaryFocus, isTrue); }, skip: isBrowser, variant: KeySimulatorTransitModeVariant.all()); // https://github.com/flutter/flutter/issues/35347 - testWidgets('Focus traversal inside a vertical scrollable scrolls to stay visible.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal inside a vertical scrollable scrolls to stay visible.', (WidgetTester tester) async { final List<int> items = List<int>.generate(11, (int index) => index).toList(); final List<FocusNode> nodes = List<FocusNode>.generate(11, (int index) => FocusNode(debugLabel: 'Item ${index + 1}')).toList(); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); final FocusNode topNode = FocusNode(debugLabel: 'Header'); + addTearDown(topNode.dispose); final FocusNode bottomNode = FocusNode(debugLabel: 'Footer'); + addTearDown(bottomNode.dispose); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Column( @@ -2328,12 +2419,21 @@ void main() { expect(controller.offset, equals(0.0)); }, skip: isBrowser, variant: KeySimulatorTransitModeVariant.all()); // https://github.com/flutter/flutter/issues/35347 - testWidgets('Focus traversal inside a horizontal scrollable scrolls to stay visible.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal inside a horizontal scrollable scrolls to stay visible.', (WidgetTester tester) async { final List<int> items = List<int>.generate(11, (int index) => index).toList(); final List<FocusNode> nodes = List<FocusNode>.generate(11, (int index) => FocusNode(debugLabel: 'Item ${index + 1}')).toList(); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); final FocusNode leftNode = FocusNode(debugLabel: 'Left Side'); + addTearDown(leftNode.dispose); final FocusNode rightNode = FocusNode(debugLabel: 'Right Side'); + addTearDown(rightNode.dispose); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Row( @@ -2426,23 +2526,31 @@ void main() { expect(controller.offset, equals(0.0)); }, skip: isBrowser, variant: KeySimulatorTransitModeVariant.all()); // https://github.com/flutter/flutter/issues/35347 - testWidgets('Arrow focus traversal actions can be re-enabled for text fields.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Arrow focus traversal actions can be re-enabled for text fields.', (WidgetTester tester) async { final GlobalKey upperLeftKey = GlobalKey(debugLabel: 'upperLeftKey'); final GlobalKey upperRightKey = GlobalKey(debugLabel: 'upperRightKey'); final GlobalKey lowerLeftKey = GlobalKey(debugLabel: 'lowerLeftKey'); final GlobalKey lowerRightKey = GlobalKey(debugLabel: 'lowerRightKey'); final TextEditingController controller1 = TextEditingController(); + addTearDown(controller1.dispose); final TextEditingController controller2 = TextEditingController(); + addTearDown(controller2.dispose); final TextEditingController controller3 = TextEditingController(); + addTearDown(controller3.dispose); final TextEditingController controller4 = TextEditingController(); + addTearDown(controller4.dispose); final FocusNode focusNodeUpperLeft = FocusNode(debugLabel: 'upperLeft'); + addTearDown(focusNodeUpperLeft.dispose); final FocusNode focusNodeUpperRight = FocusNode(debugLabel: 'upperRight'); + addTearDown(focusNodeUpperRight.dispose); final FocusNode focusNodeLowerLeft = FocusNode(debugLabel: 'lowerLeft'); + addTearDown(focusNodeLowerLeft.dispose); final FocusNode focusNodeLowerRight = FocusNode(debugLabel: 'lowerRight'); + addTearDown(focusNodeLowerRight.dispose); - Widget generateTestWidgets(bool ignoreTextFields) { + Widget generatetestWidgetsWithLeakTracking(bool ignoreTextFields) { final Map<ShortcutActivator, Intent> shortcuts = <ShortcutActivator, Intent>{ const SingleActivator(LogicalKeyboardKey.arrowLeft): DirectionalFocusIntent(TraversalDirection.left, ignoreTextFields: ignoreTextFields), const SingleActivator(LogicalKeyboardKey.arrowRight): DirectionalFocusIntent(TraversalDirection.right, ignoreTextFields: ignoreTextFields), @@ -2521,7 +2629,7 @@ void main() { ); } - await tester.pumpWidget(generateTestWidgets(false)); + await tester.pumpWidget(generatetestWidgetsWithLeakTracking(false)); expect(focusNodeUpperLeft.hasPrimaryFocus, isTrue); await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); @@ -2533,7 +2641,7 @@ void main() { await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp); expect(focusNodeUpperLeft.hasPrimaryFocus, isTrue); - await tester.pumpWidget(generateTestWidgets(true)); + await tester.pumpWidget(generatetestWidgetsWithLeakTracking(true)); expect(focusNodeUpperLeft.hasPrimaryFocus, isTrue); await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); @@ -2549,7 +2657,7 @@ void main() { expect(focusNodeUpperLeft.hasPrimaryFocus, isTrue); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Focus traversal does not break when no focusable is available on a MaterialApp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal does not break when no focusable is available on a MaterialApp', (WidgetTester tester) async { final List<Object> events = <Object>[]; await tester.pumpWidget(MaterialApp(home: Container())); @@ -2565,7 +2673,7 @@ void main() { expect(events.length, 2); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Focus traversal does not throw when no focusable is available in a group', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal does not throw when no focusable is available in a group', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: Scaffold(body: ListTile(title: Text('title'))))); final FocusNode? initialFocus = primaryFocus; await tester.sendKeyEvent(LogicalKeyboardKey.tab); @@ -2573,7 +2681,7 @@ void main() { expect(primaryFocus, equals(initialFocus)); }); - testWidgets('Focus traversal does not break when no focusable is available on a WidgetsApp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Focus traversal does not break when no focusable is available on a WidgetsApp', (WidgetTester tester) async { final List<RawKeyEvent> events = <RawKeyEvent>[]; await tester.pumpWidget( @@ -2599,9 +2707,10 @@ void main() { expect(events.length, 2); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Custom requestFocusCallback gets called on focusInDirection up/down/left/right.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom requestFocusCallback gets called on focusInDirection up/down/left/right.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final FocusNode testNode1 = FocusNode(debugLabel: 'Focus Node'); + addTearDown(testNode1.dispose); bool calledCallback = false; await tester.pumpWidget( @@ -2655,7 +2764,7 @@ void main() { }); group(FocusTraversalGroup, () { - testWidgets("Focus traversal group doesn't introduce a Semantics node", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Focus traversal group doesn't introduce a Semantics node", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(FocusTraversalGroup(child: Container())); final TestSemantics expectedSemantics = TestSemantics.root(); @@ -2663,11 +2772,13 @@ void main() { semantics.dispose(); }); - testWidgets("Descendants of FocusTraversalGroup aren't focusable if descendantsAreFocusable is false.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Descendants of FocusTraversalGroup aren't focusable if descendantsAreFocusable is false.", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? gotFocus; + await tester.pumpWidget( FocusTraversalGroup( descendantsAreFocusable: false, @@ -2702,13 +2813,16 @@ void main() { expect(unfocusableNode.hasFocus, isFalse); }); - testWidgets('Group applies correct policy if focus tree is different from widget tree.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Group applies correct policy if focus tree is different from widget tree.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final GlobalKey key3 = GlobalKey(debugLabel: '3'); final GlobalKey key4 = GlobalKey(debugLabel: '4'); final FocusNode focusNode = FocusNode(debugLabel: 'child'); + addTearDown(focusNode.dispose); final FocusNode parentFocusNode = FocusNode(debugLabel: 'parent'); + addTearDown(parentFocusNode.dispose); + await tester.pumpWidget( Column( children: <Widget>[ @@ -2744,9 +2858,11 @@ void main() { expect(FocusTraversalGroup.of(key2.currentContext!), const TypeMatcher<SkipAllButFirstAndLastPolicy>()); }); - testWidgets("Descendants of FocusTraversalGroup aren't traversable if descendantsAreTraversable is false.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Descendants of FocusTraversalGroup aren't traversable if descendantsAreTraversable is false.", (WidgetTester tester) async { final FocusNode node1 = FocusNode(); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(); + addTearDown(node2.dispose); await tester.pumpWidget( FocusTraversalGroup( @@ -2779,9 +2895,11 @@ void main() { expect(node2.hasPrimaryFocus, isFalse); }); - testWidgets("FocusTraversalGroup with skipTraversal for all descendants set to true doesn't cause an exception.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("FocusTraversalGroup with skipTraversal for all descendants set to true doesn't cause an exception.", (WidgetTester tester) async { final FocusNode node1 = FocusNode(); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(); + addTearDown(node2.dispose); await tester.pumpWidget( FocusTraversalGroup( @@ -2815,11 +2933,13 @@ void main() { expect(node2.hasPrimaryFocus, isFalse); }); - testWidgets("Nested FocusTraversalGroup with unfocusable children doesn't assert.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Nested FocusTraversalGroup with unfocusable children doesn't assert.", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); bool? gotFocus; + await tester.pumpWidget( FocusTraversalGroup( child: Column( @@ -2864,9 +2984,11 @@ void main() { expect(unfocusableNode.hasFocus, isFalse); }); - testWidgets("Empty FocusTraversalGroup doesn't cause an exception.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Empty FocusTraversalGroup doesn't cause an exception.", (WidgetTester tester) async { final GlobalKey key = GlobalKey(debugLabel: 'Test Key'); final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); + await tester.pumpWidget( FocusTraversalGroup( child: Directionality( @@ -2895,9 +3017,11 @@ void main() { }); group(RawKeyboardListener, () { - testWidgets('Raw keyboard listener introduces a Semantics node by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Raw keyboard listener introduces a Semantics node by default', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( RawKeyboardListener( focusNode: focusNode, @@ -2922,9 +3046,11 @@ void main() { semantics.dispose(); }); - testWidgets("Raw keyboard listener doesn't introduce a Semantics node when specified", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Raw keyboard listener doesn't introduce a Semantics node when specified", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( RawKeyboardListener( focusNode: focusNode, @@ -2939,11 +3065,15 @@ void main() { }); group(ExcludeFocusTraversal, () { - testWidgets("Descendants aren't traversable", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Descendants aren't traversable", (WidgetTester tester) async { final FocusNode node1 = FocusNode(debugLabel: 'node 1'); + addTearDown(node1.dispose); final FocusNode node2 = FocusNode(debugLabel: 'node 2'); + addTearDown(node2.dispose); final FocusNode node3 = FocusNode(debugLabel: 'node 3'); + addTearDown(node3.dispose); final FocusNode node4 = FocusNode(debugLabel: 'node 4'); + addTearDown(node4.dispose); await tester.pumpWidget( FocusTraversalGroup( @@ -2987,7 +3117,7 @@ void main() { expect(node4.hasPrimaryFocus, isTrue); }); - testWidgets("Doesn't introduce a Semantics node", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Doesn't introduce a Semantics node", (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(ExcludeFocusTraversal(child: Container())); final TestSemantics expectedSemantics = TestSemantics.root(); @@ -3003,9 +3133,11 @@ void main() { // other focusable HTML elements surrounding Flutter. // // See also: https://github.com/flutter/flutter/issues/114463 - testWidgets('Default route edge traversal behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default route edge traversal behavior', (WidgetTester tester) async { final FocusNode nodeA = FocusNode(); + addTearDown(nodeA.dispose); final FocusNode nodeB = FocusNode(); + addTearDown(nodeB.dispose); Future<bool> nextFocus() async { final bool result = Actions.invoke( @@ -3083,12 +3215,15 @@ void main() { // This test creates a FocusScopeNode configured to traverse focus in a closed // loop. After traversing one loop, it changes the behavior to leave the // FlutterView, then verifies that the new behavior did indeed take effect. - testWidgets('FocusScopeNode.traversalEdgeBehavior takes effect after update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusScopeNode.traversalEdgeBehavior takes effect after update', (WidgetTester tester) async { final FocusScopeNode scope = FocusScopeNode(); + addTearDown(scope.dispose); expect(scope.traversalEdgeBehavior, TraversalEdgeBehavior.closedLoop); final FocusNode nodeA = FocusNode(); + addTearDown(nodeA.dispose); final FocusNode nodeB = FocusNode(); + addTearDown(nodeB.dispose); Future<bool> nextFocus() async { final bool result = Actions.invoke( @@ -3172,7 +3307,7 @@ void main() { expect(nodeB.hasFocus, true); }); - testWidgets('NextFocusAction converts invoke result to KeyEventResult', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NextFocusAction converts invoke result to KeyEventResult', (WidgetTester tester) async { expect( NextFocusAction().toKeyEventResult(const NextFocusIntent(), true), KeyEventResult.handled, @@ -3183,7 +3318,7 @@ void main() { ); }); - testWidgets('PreviousFocusAction converts invoke result to KeyEventResult', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PreviousFocusAction converts invoke result to KeyEventResult', (WidgetTester tester) async { expect( PreviousFocusAction().toKeyEventResult(const PreviousFocusIntent(), true), KeyEventResult.handled, @@ -3194,9 +3329,10 @@ void main() { ); }); - testWidgets('RequestFocusAction calls the RequestFocusIntent.requestFocusCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RequestFocusAction calls the RequestFocusIntent.requestFocusCallback', (WidgetTester tester) async { bool calledCallback = false; final FocusNode nodeA = FocusNode(); + addTearDown(nodeA.dispose); await tester.pumpWidget( MaterialApp( From b76b82aa7106de95c621383e5413d5d17440fc60 Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Mon, 11 Sep 2023 16:33:09 -0700 Subject: [PATCH 1200/1547] [flutter_tools] disallow -O0 for flutter build web (#134185) Fixes https://github.com/flutter/flutter/issues/133404. Per the dart2js team on the linked issue, `-O0` is not intended for end users, but more for actual debugging/development of the compiler. --- .../lib/src/commands/build_web.dart | 5 +- .../hermetic/build_web_test.dart | 46 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart index 3b5128b9f8334..a0afbe2232cb3 100644 --- a/packages/flutter_tools/lib/src/commands/build_web.dart +++ b/packages/flutter_tools/lib/src/commands/build_web.dart @@ -72,8 +72,9 @@ class BuildWebCommand extends BuildSubCommand { ); argParser.addOption('dart2js-optimization', help: 'Sets the optimization level used for Dart compilation to JavaScript. ' - 'Valid values range from O0 to O4.', - defaultsTo: JsCompilerConfig.kDart2jsDefaultOptimizationLevel + 'Valid values range from O1 to O4.', + defaultsTo: JsCompilerConfig.kDart2jsDefaultOptimizationLevel, + allowed: const <String>['O1', 'O2', 'O3', 'O4'], ); argParser.addFlag('dump-info', negatable: false, help: 'Passes "--dump-info" to the Javascript compiler which generates ' diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart index 8cb79fb7cc1d7..c9a5547239e52 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart @@ -142,6 +142,52 @@ void main() { }), }); + testUsingContext('Does not allow -O0 optimization level', () async { + final BuildCommand buildCommand = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: fileSystem, + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + final CommandRunner<void> runner = createTestCommandRunner(buildCommand); + setupFileSystemForEndToEndTest(fileSystem); + await expectLater( + () => runner.run(<String>[ + 'build', + 'web', + '--no-pub', '--no-web-resources-cdn', '--dart-define=foo=a', '--dart2js-optimization=O0']), + throwsUsageException(message: '"O0" is not an allowed value for option "dart2js-optimization"'), + ); + + final Directory buildDir = fileSystem.directory(fileSystem.path.join('build', 'web')); + + expect(buildDir.existsSync(), isFalse); + }, overrides: <Type, Generator>{ + Platform: () => fakePlatform, + FileSystem: () => fileSystem, + FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), + ProcessManager: () => FakeProcessManager.any(), + BuildSystem: () => TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) { + expect(environment.defines, <String, String>{ + 'TargetFile': 'lib/main.dart', + 'HasWebPlugins': 'true', + 'cspMode': 'false', + 'SourceMaps': 'false', + 'NativeNullAssertions': 'true', + 'ServiceWorkerStrategy': 'offline-first', + 'Dart2jsDumpInfo': 'false', + 'Dart2jsNoFrequencyBasedMinification': 'false', + 'Dart2jsOptimization': 'O3', + 'BuildMode': 'release', + 'DartDefines': 'Zm9vPWE=,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==', + 'DartObfuscation': 'false', + 'TrackWidgetCreation': 'false', + 'TreeShakeIcons': 'true', + }); + }), + }); + testUsingContext('Setup for a web build with a user specified output directory', () async { final BuildCommand buildCommand = BuildCommand( From 0770c60af35a5cc4a9ebcbf61fcfa8969a6deaaa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 19:39:08 -0400 Subject: [PATCH 1201/1547] Roll Flutter Engine from 06696e768c1b to 8389ad914b21 (2 revisions) (#134469) https://github.com/flutter/engine/compare/06696e768c1b...8389ad914b21 2023-09-11 109111084+yaakovschectman@users.noreply.github.com Merge `Window` into `FlutterWindow` (flutter/engine#45542) 2023-09-11 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 7Zk_dvFh301kgQte4... to fSmVaZwp41ZGp5hKn... (flutter/engine#45665) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 7Zk_dvFh301k to fSmVaZwp41ZG If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index df48d2e90baf4..5adb3bc19fb4b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -06696e768c1b1abd2393099d4ccacfdff2ad4739 +8389ad914b21af99999c432fd04ba4c84d95e2fc diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 16b155767d9ca..d06e1adc72ba9 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -7Zk_dvFh301kgQte47pTgn_aAWmEVZ3YE4WFpXPQF2QC +fSmVaZwp41ZGp5hKnDIGj56IAdgVpbpMTPwN21pR_DYC From 4a3ab6828a74a8b5f7db47452694581a3f654194 Mon Sep 17 00:00:00 2001 From: Chinmay Kabi <chinmay@blend.to> Date: Tue, 12 Sep 2023 05:25:53 +0530 Subject: [PATCH 1202/1547] Fix DataTable example not being scrollable (#131556) --- dev/bots/check_code_samples.dart | 1 - .../lib/material/data_table/data_table.1.dart | 5 ++-- .../data_table/data_table.1_test.dart | 24 +++++++++++++++++++ .../flutter/lib/src/material/data_table.dart | 7 ++++++ 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 examples/api/test/material/data_table/data_table.1_test.dart diff --git a/dev/bots/check_code_samples.dart b/dev/bots/check_code_samples.dart index 8e4aab41d4e8d..1082702e9b5be 100644 --- a/dev/bots/check_code_samples.dart +++ b/dev/bots/check_code_samples.dart @@ -292,7 +292,6 @@ final Set<String> _knownMissingTests = <String>{ 'examples/api/test/material/stepper/stepper.controls_builder.0_test.dart', 'examples/api/test/material/stepper/stepper.0_test.dart', 'examples/api/test/material/flexible_space_bar/flexible_space_bar.0_test.dart', - 'examples/api/test/material/data_table/data_table.1_test.dart', 'examples/api/test/material/data_table/data_table.0_test.dart', 'examples/api/test/material/floating_action_button_location/standard_fab_location.0_test.dart', 'examples/api/test/material/chip/deletable_chip_attributes.on_deleted.0_test.dart', diff --git a/examples/api/lib/material/data_table/data_table.1.dart b/examples/api/lib/material/data_table/data_table.1.dart index cdb47e73bd0d2..36690d3617496 100644 --- a/examples/api/lib/material/data_table/data_table.1.dart +++ b/examples/api/lib/material/data_table/data_table.1.dart @@ -30,13 +30,12 @@ class DataTableExample extends StatefulWidget { } class _DataTableExampleState extends State<DataTableExample> { - static const int numItems = 10; + static const int numItems = 20; List<bool> selected = List<bool>.generate(numItems, (int index) => false); @override Widget build(BuildContext context) { - return SizedBox( - width: double.infinity, + return SingleChildScrollView( child: DataTable( columns: const <DataColumn>[ DataColumn( diff --git a/examples/api/test/material/data_table/data_table.1_test.dart b/examples/api/test/material/data_table/data_table.1_test.dart new file mode 100644 index 0000000000000..6b14a8cefb721 --- /dev/null +++ b/examples/api/test/material/data_table/data_table.1_test.dart @@ -0,0 +1,24 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/data_table/data_table.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('DataTable is scrollable', (WidgetTester tester) async { + await tester.pumpWidget( + const example.DataTableExampleApp(), + ); + + expect(find.byType(SingleChildScrollView), findsOneWidget); + + expect(tester.getTopLeft(find.text('Row 5')), const Offset(66.0, 366.0)); + + await tester.drag(find.byType(SingleChildScrollView), const Offset(0.0, -200.0)); + await tester.pumpAndSettle(); + + expect(tester.getTopLeft(find.text('Row 5')), const Offset(66.0, 186.0)); + }); +} diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index fe03482e27f87..d4d280b6960da 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -357,6 +357,13 @@ class DataCell { /// [PaginatedDataTable] which automatically splits the data into /// multiple pages. /// +/// ## Performance considerations when wrapping [DataTable] with [SingleChildScrollView] +/// +/// Wrapping a [DataTable] with [SingleChildScrollView] is expensive as [SingleChildScrollView] +/// mounts and paints the entire [DataTable] even when only some rows are visible. If scrolling in +/// one direction is necessary, then consider using a [CustomScrollView], otherwise use [PaginatedDataTable] +/// to split the data into smaller pages. +/// /// {@tool dartpad} /// This sample shows how to display a [DataTable] with three columns: name, age, and /// role. The columns are defined by three [DataColumn] objects. The table From 82cb74932f7e1bf7965aaa5d4f4562e7feb08050 Mon Sep 17 00:00:00 2001 From: Kohei Seino <kouhei.seino@woven-planet.global> Date: Tue, 12 Sep 2023 10:01:38 +0900 Subject: [PATCH 1203/1547] ScaleGestureRecognizer: make pointerCount public (#127310) make `pointCount` in `ScaleGestureRecognizer` public to handle pointer event depending on the number of pointers. https://github.com/flutter/flutter/issues/127309 --- packages/flutter/lib/src/gestures/scale.dart | 22 +++++++++++-------- .../flutter/test/gestures/scale_test.dart | 2 ++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/gestures/scale.dart b/packages/flutter/lib/src/gestures/scale.dart index a67283c7e5df2..11b53cf52d48d 100644 --- a/packages/flutter/lib/src/gestures/scale.dart +++ b/packages/flutter/lib/src/gestures/scale.dart @@ -393,6 +393,14 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { /// {@endtemplate} Offset trackpadScrollToScaleFactor; + /// The number of pointers being tracked by the gesture recognizer. + /// + /// Typically this is the number of fingers being used to pan the widget using the gesture + /// recognizer. + int get pointerCount { + return _pointerPanZooms.length + _pointerQueue.length; + } + late Offset _initialFocalPoint; Offset? _currentFocalPoint; late double _initialSpan; @@ -443,10 +451,6 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { return scale; } - int get _pointerCount { - return _pointerPanZooms.length + _pointerQueue.length; - } - double _computeRotationFactor() { double factor = 0.0; if (_initialLine != null && _currentLine != null) { @@ -566,7 +570,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { for (final _PointerPanZoomData p in _pointerPanZooms.values) { focalPoint += p.focalPoint; } - _currentFocalPoint = _pointerCount > 0 ? focalPoint / _pointerCount.toDouble() : Offset.zero; + _currentFocalPoint = pointerCount > 0 ? focalPoint / pointerCount.toDouble() : Offset.zero; if (previousFocalPoint == null) { _localFocalPoint = PointerEvent.transformPosition( @@ -662,9 +666,9 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { if (pixelsPerSecond.distanceSquared > kMaxFlingVelocity * kMaxFlingVelocity) { velocity = Velocity(pixelsPerSecond: (pixelsPerSecond / pixelsPerSecond.distance) * kMaxFlingVelocity); } - invokeCallback<void>('onEnd', () => onEnd!(ScaleEndDetails(velocity: velocity, scaleVelocity: _scaleVelocityTracker?.getVelocity().pixelsPerSecond.dx ?? -1, pointerCount: _pointerCount))); + invokeCallback<void>('onEnd', () => onEnd!(ScaleEndDetails(velocity: velocity, scaleVelocity: _scaleVelocityTracker?.getVelocity().pixelsPerSecond.dx ?? -1, pointerCount: pointerCount))); } else { - invokeCallback<void>('onEnd', () => onEnd!(ScaleEndDetails(scaleVelocity: _scaleVelocityTracker?.getVelocity().pixelsPerSecond.dx ?? -1, pointerCount: _pointerCount))); + invokeCallback<void>('onEnd', () => onEnd!(ScaleEndDetails(scaleVelocity: _scaleVelocityTracker?.getVelocity().pixelsPerSecond.dx ?? -1, pointerCount: pointerCount))); } } _state = _ScaleState.accepted; @@ -706,7 +710,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { focalPoint: _currentFocalPoint!, localFocalPoint: _localFocalPoint, rotation: _computeRotationFactor(), - pointerCount: _pointerCount, + pointerCount: pointerCount, focalPointDelta: _delta, )); }); @@ -721,7 +725,7 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer { onStart!(ScaleStartDetails( focalPoint: _currentFocalPoint!, localFocalPoint: _localFocalPoint, - pointerCount: _pointerCount, + pointerCount: pointerCount, )); }); } diff --git a/packages/flutter/test/gestures/scale_test.dart b/packages/flutter/test/gestures/scale_test.dart index a844c54cdf790..6892dcccc5295 100644 --- a/packages/flutter/test/gestures/scale_test.dart +++ b/packages/flutter/test/gestures/scale_test.dart @@ -79,6 +79,7 @@ void main() { updatedDelta = null; expect(didEndScale, isFalse); expect(didTap, isFalse); + expect(scale.pointerCount, 1); // Two-finger scaling final TestPointer pointer2 = TestPointer(2); @@ -87,6 +88,7 @@ void main() { tap.addPointer(down2); tester.closeArena(2); tester.route(down2); + expect(scale.pointerCount, 2); expect(didEndScale, isTrue); didEndScale = false; From e645fb7d5ebe989006b493edef4bf5be70dd5fad Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 22:15:07 -0400 Subject: [PATCH 1204/1547] Roll Flutter Engine from 8389ad914b21 to a98348946d61 (4 revisions) (#134487) https://github.com/flutter/engine/compare/8389ad914b21...a98348946d61 2023-09-12 jason-simmons@users.noreply.github.com Roll libwebp to 1.3.1 (flutter/engine#45675) 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from 0b8d2203ab35 to c4e94d5febdc (5 revisions) (flutter/engine#45679) 2023-09-11 chinmaygarde@google.com Pipe VMA asserts to FML. (flutter/engine#45661) 2023-09-11 skia-flutter-autoroll@skia.org Roll Skia from e6225224fb4e to 0b8d2203ab35 (9 revisions) (flutter/engine#45671) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5adb3bc19fb4b..a5949d3c10ecb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8389ad914b21af99999c432fd04ba4c84d95e2fc +a98348946d615380f20e9b3130da6fc9cf214af3 From a9fac73361d3a86fa9dc7921e773f1aa0d0cae71 Mon Sep 17 00:00:00 2001 From: xubaolin <xubaolin@oppo.com> Date: Tue, 12 Sep 2023 10:16:48 +0800 Subject: [PATCH 1205/1547] [New feature] Allowing the `ListView` slivers to have different extents while still having scrolling performance (#131393) Fixes https://github.com/flutter/flutter/issues/113431 Currently we only support specifying all slivers to have the same extent. This patch introduces an `itemExtentBuilder` property for `ListView`, allowing the slivers to have different extents while still having scrolling performance, especially when the scroll position changes drastically(such as scrolling by the scrollbar or controller.jumpTo()). @Piinks Hi, Any thoughts about this? :) --- .../lib/src/material/reorderable_list.dart | 19 +- .../flutter/lib/src/rendering/sliver.dart | 79 +++++++- .../rendering/sliver_fixed_extent_list.dart | 176 ++++++++++++----- .../lib/src/widgets/reorderable_list.dart | 30 ++- .../flutter/lib/src/widgets/scroll_view.dart | 59 +++++- .../widgets/sliver_varied_extent_list.dart | 137 +++++++++++++ packages/flutter/lib/widgets.dart | 1 + .../flutter/test/widgets/list_view_test.dart | 186 ++++++++++++++++++ 8 files changed, 614 insertions(+), 73 deletions(-) create mode 100644 packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart diff --git a/packages/flutter/lib/src/material/reorderable_list.dart b/packages/flutter/lib/src/material/reorderable_list.dart index a91f2a47e82bd..6a928e0da809d 100644 --- a/packages/flutter/lib/src/material/reorderable_list.dart +++ b/packages/flutter/lib/src/material/reorderable_list.dart @@ -5,6 +5,7 @@ import 'dart:ui' show lerpDouble; import 'package:flutter/gestures.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'debug.dart'; @@ -76,6 +77,7 @@ class ReorderableListView extends StatefulWidget { this.onReorderStart, this.onReorderEnd, this.itemExtent, + this.itemExtentBuilder, this.prototypeItem, this.proxyDecorator, this.buildDefaultDragHandles = true, @@ -96,8 +98,10 @@ class ReorderableListView extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.autoScrollerVelocityScalar, }) : assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both', + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', ), assert( children.every((Widget w) => w.key != null), @@ -142,6 +146,7 @@ class ReorderableListView extends StatefulWidget { this.onReorderStart, this.onReorderEnd, this.itemExtent, + this.itemExtentBuilder, this.prototypeItem, this.proxyDecorator, this.buildDefaultDragHandles = true, @@ -163,8 +168,10 @@ class ReorderableListView extends StatefulWidget { this.autoScrollerVelocityScalar, }) : assert(itemCount >= 0), assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both', + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', ); /// {@macro flutter.widgets.reorderable_list.itemBuilder} @@ -269,6 +276,9 @@ class ReorderableListView extends StatefulWidget { /// {@macro flutter.widgets.list_view.itemExtent} final double? itemExtent; + /// {@macro flutter.widgets.list_view.itemExtentBuilder} + final ItemExtentBuilder? itemExtentBuilder; + /// {@macro flutter.widgets.list_view.prototypeItem} final Widget? prototypeItem; @@ -440,6 +450,7 @@ class _ReorderableListViewState extends State<ReorderableListView> { sliver: SliverReorderableList( itemBuilder: _itemBuilder, itemExtent: widget.itemExtent, + itemExtentBuilder: widget.itemExtentBuilder, prototypeItem: widget.prototypeItem, itemCount: widget.itemCount, onReorder: widget.onReorder, diff --git a/packages/flutter/lib/src/rendering/sliver.dart b/packages/flutter/lib/src/rendering/sliver.dart index 7ccc6eaa19d71..020d8a9abdf6f 100644 --- a/packages/flutter/lib/src/rendering/sliver.dart +++ b/packages/flutter/lib/src/rendering/sliver.dart @@ -16,6 +16,71 @@ import 'viewport_offset.dart'; // CORE TYPES FOR SLIVERS // The RenderSliver base class and its helper types. +/// Called to get the item extent by the index of item. +/// +/// Used by [ListView.itemExtentBuilder] and [SliverVariedExtentList.itemExtentBuilder]. +typedef ItemExtentBuilder = double Function(int index, SliverLayoutDimensions dimensions); + +/// Relates the dimensions of the [RenderSliver] during layout. +/// +/// Used by [ListView.itemExtentBuilder] and [SliverVariedExtentList.itemExtentBuilder]. +@immutable +class SliverLayoutDimensions { + /// Constructs a [SliverLayoutDimensions] with the specified parameters. + const SliverLayoutDimensions({ + required this.scrollOffset, + required this.precedingScrollExtent, + required this.viewportMainAxisExtent, + required this.crossAxisExtent + }); + + /// {@macro flutter.rendering.SliverConstraints.scrollOffset} + final double scrollOffset; + + /// {@macro flutter.rendering.SliverConstraints.precedingScrollExtent} + final double precedingScrollExtent; + + /// The number of pixels the viewport can display in the main axis. + /// + /// For a vertical list, this is the height of the viewport. + final double viewportMainAxisExtent; + + /// The number of pixels in the cross-axis. + /// + /// For a vertical list, this is the width of the sliver. + final double crossAxisExtent; + + @override + bool operator ==(Object other) { + if (identical(this, other)) { + return true; + } + if (other is! SliverLayoutDimensions) { + return false; + } + return other.scrollOffset == scrollOffset && + other.precedingScrollExtent == precedingScrollExtent && + other.viewportMainAxisExtent == viewportMainAxisExtent && + other.crossAxisExtent == crossAxisExtent; + } + + @override + String toString() { + return 'scrollOffset: $scrollOffset' + ' precedingScrollExtent: $precedingScrollExtent' + ' viewportMainAxisExtent: $viewportMainAxisExtent' + ' crossAxisExtent: $crossAxisExtent'; + } + + @override + int get hashCode => Object.hash( + scrollOffset, + precedingScrollExtent, + viewportMainAxisExtent, + viewportMainAxisExtent + ); +} + /// The direction in which a sliver's contents are ordered, relative to the /// scroll offset axis. /// @@ -224,12 +289,13 @@ class SliverConstraints extends Constraints { /// {@macro flutter.rendering.ScrollDirection.sample} final ScrollDirection userScrollDirection; + /// {@template flutter.rendering.SliverConstraints.scrollOffset} /// The scroll offset, in this sliver's coordinate system, that corresponds to /// the earliest visible part of this sliver in the [AxisDirection] if - /// [growthDirection] is [GrowthDirection.forward] or in the opposite - /// [AxisDirection] direction if [growthDirection] is [GrowthDirection.reverse]. + /// [SliverConstraints.growthDirection] is [GrowthDirection.forward] or in the opposite + /// [AxisDirection] direction if [SliverConstraints.growthDirection] is [GrowthDirection.reverse]. /// - /// For example, if [AxisDirection] is [AxisDirection.down] and [growthDirection] + /// For example, if [AxisDirection] is [AxisDirection.down] and [SliverConstraints.growthDirection] /// is [GrowthDirection.forward], then scroll offset is the amount the top of /// the sliver has been scrolled past the top of the viewport. /// @@ -240,7 +306,7 @@ class SliverConstraints extends Constraints { /// /// For slivers whose top is not past the top of the viewport, the /// [scrollOffset] is `0` when [AxisDirection] is [AxisDirection.down] and - /// [growthDirection] is [GrowthDirection.forward]. The set of slivers with + /// [SliverConstraints.growthDirection] is [GrowthDirection.forward]. The set of slivers with /// [scrollOffset] `0` includes all the slivers that are below the bottom of the /// viewport. /// @@ -249,9 +315,11 @@ class SliverConstraints extends Constraints { /// partially 'protrude in' from the bottom of the viewport. /// /// Whether this corresponds to the beginning or the end of the sliver's - /// contents depends on the [growthDirection]. + /// contents depends on the [SliverConstraints.growthDirection]. + /// {@endtemplate} final double scrollOffset; + /// {@template flutter.rendering.SliverConstraints.precedingScrollExtent} /// The scroll distance that has been consumed by all [RenderSliver]s that /// came before this [RenderSliver]. /// @@ -273,6 +341,7 @@ class SliverConstraints extends Constraints { /// content forever without reaching the end. For any [RenderSliver]s that /// appear after the infinite [RenderSliver], the [precedingScrollExtent] will /// be [double.infinity]. + /// {@endtemplate} final double precedingScrollExtent; /// The number of pixels from where the pixels corresponding to the diff --git a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart index 4fe59a70264df..28a9c92ba71ec 100644 --- a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart +++ b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart @@ -10,16 +10,17 @@ import 'box.dart'; import 'sliver.dart'; import 'sliver_multi_box_adaptor.dart'; -/// A sliver that contains multiple box children that have the same extent in +/// A sliver that contains multiple box children that have the explicit extent in /// the main axis. /// /// [RenderSliverFixedExtentBoxAdaptor] places its children in a linear array -/// along the main axis. Each child is forced to have the [itemExtent] in the -/// main axis and the [SliverConstraints.crossAxisExtent] in the cross axis. +/// along the main axis. Each child is forced to have the returned value of [itemExtentBuilder] +/// when the [itemExtentBuilder] is non-null or the [itemExtent] when [itemExtentBuilder] +/// is null in the main axis and the [SliverConstraints.crossAxisExtent] in the cross axis. /// -/// Subclasses should override [itemExtent] to control the size of the children -/// in the main axis. For a concrete subclass with a configurable [itemExtent], -/// see [RenderSliverFixedExtentList]. +/// Subclasses should override [itemExtent] or [itemExtentBuilder] to control +/// the size of the children in the main axis. For a concrete subclass with a +/// configurable [itemExtent], see [RenderSliverFixedExtentList] or [RenderSliverVariedExtentList]. /// /// [RenderSliverFixedExtentBoxAdaptor] is more efficient than /// [RenderSliverList] because [RenderSliverFixedExtentBoxAdaptor] does not need @@ -44,56 +45,83 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda }); /// The main-axis extent of each item. - double get itemExtent; + /// + /// If this is non-null, the [itemExtentBuilder] must be null. + /// If this is null, the [itemExtentBuilder] must be non-null. + double? get itemExtent; + + /// The main-axis extent builder of each item. + /// + /// If this is non-null, the [itemExtent] must be null. + /// If this is null, the [itemExtent] must be non-null. + ItemExtentBuilder? get itemExtentBuilder => null; /// The layout offset for the child with the given index. /// - /// This function is given the [itemExtent] as an argument to avoid - /// recomputing [itemExtent] repeatedly during layout. + /// This function uses the returned value of [itemExtentBuilder] or the [itemExtent] + /// as an argument to avoid recomputing item size repeatedly during layout. /// /// By default, places the children in order, without gaps, starting from /// layout offset zero. @protected - double indexToLayoutOffset(double itemExtent, int index) => itemExtent * index; + double indexToLayoutOffset(double itemExtent, int index) { + if (itemExtentBuilder == null) { + return itemExtent * index; + } else { + double offset = 0.0; + for (int i = 0; i < index; i++) { + offset += itemExtentBuilder!(i, _currentLayoutDimensions); + } + return offset; + } + } /// The minimum child index that is visible at the given scroll offset. /// - /// This function is given the [itemExtent] as an argument to avoid - /// recomputing [itemExtent] repeatedly during layout. + /// This function uses the returned value of [itemExtentBuilder] or the [itemExtent] + /// as an argument to avoid recomputing item size repeatedly during layout. /// /// By default, returns a value consistent with the children being placed in /// order, without gaps, starting from layout offset zero. @protected int getMinChildIndexForScrollOffset(double scrollOffset, double itemExtent) { - if (itemExtent > 0.0) { - final double actual = scrollOffset / itemExtent; - final int round = actual.round(); - if ((actual * itemExtent - round * itemExtent).abs() < precisionErrorTolerance) { - return round; + if (itemExtentBuilder == null) { + if (itemExtent > 0.0) { + final double actual = scrollOffset / itemExtent; + final int round = actual.round(); + if ((actual * itemExtent - round * itemExtent).abs() < precisionErrorTolerance) { + return round; + } + return actual.floor(); } - return actual.floor(); + return 0; + } else { + return _getChildIndexForScrollOffset(scrollOffset, itemExtentBuilder!); } - return 0; } /// The maximum child index that is visible at the given scroll offset. /// - /// This function is given the [itemExtent] as an argument to avoid - /// recomputing [itemExtent] repeatedly during layout. + /// This function uses the returned value of [itemExtentBuilder] or the [itemExtent] + /// as an argument to avoid recomputing item size repeatedly during layout. /// /// By default, returns a value consistent with the children being placed in /// order, without gaps, starting from layout offset zero. @protected int getMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) { - if (itemExtent > 0.0) { - final double actual = scrollOffset / itemExtent - 1; - final int round = actual.round(); - if ((actual * itemExtent - round * itemExtent).abs() < precisionErrorTolerance) { - return math.max(0, round); + if (itemExtentBuilder == null) { + if (itemExtent > 0.0) { + final double actual = scrollOffset / itemExtent - 1; + final int round = actual.round(); + if ((actual * itemExtent - round * itemExtent).abs() < precisionErrorTolerance) { + return math.max(0, round); + } + return math.max(0, actual.ceil()); } - return math.max(0, actual.ceil()); + return 0; + } else { + return _getChildIndexForScrollOffset(scrollOffset, itemExtentBuilder!); } - return 0; } /// Called to estimate the total scrollable extents of this object. @@ -138,8 +166,10 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda /// [childManager] returns an infinite number of children for positive /// indices. /// - /// By default, multiplies the [itemExtent] by the number of children reported - /// by [RenderSliverBoxChildManager.childCount]. + /// If [itemExtentBuilder] is null, multiplies the [itemExtent] by the number + /// of children reported by [RenderSliverBoxChildManager.childCount]. + /// If [itemExtentBuilder] is non-null, sum the extents of the first + /// [RenderSliverBoxChildManager.childCount] children. /// /// See also: /// @@ -147,7 +177,15 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda /// values. @protected double computeMaxScrollOffset(SliverConstraints constraints, double itemExtent) { - return childManager.childCount * itemExtent; + if (itemExtentBuilder == null) { + return childManager.childCount * itemExtent; + } else { + double offset = 0.0; + for (int i = 0; i < childManager.childCount; i++) { + offset += itemExtentBuilder!(i, _currentLayoutDimensions); + } + return offset; + } } int _calculateLeadingGarbage(int firstIndex) { @@ -170,28 +208,61 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda return trailingGarbage; } + int _getChildIndexForScrollOffset(double scrollOffset, ItemExtentBuilder callback) { + if (scrollOffset == 0.0) { + return 0; + } + double position = 0.0; + int index = 0; + while (position < scrollOffset) { + position += callback(index, _currentLayoutDimensions); + ++index; + } + return index - 1; + } + + BoxConstraints _getChildConstraints(int index) { + double extent; + if (itemExtentBuilder == null) { + extent = itemExtent!; + } else { + extent = itemExtentBuilder!(index, _currentLayoutDimensions); + } + return constraints.asBoxConstraints( + minExtent: extent, + maxExtent: extent, + ); + } + + late SliverLayoutDimensions _currentLayoutDimensions; + @override void performLayout() { + assert((itemExtent != null && itemExtentBuilder == null) || + (itemExtent == null && itemExtentBuilder != null)); + assert(itemExtentBuilder != null || (itemExtent!.isFinite && itemExtent! >= 0)); + final SliverConstraints constraints = this.constraints; childManager.didStartLayout(); childManager.setDidUnderflow(false); - final double itemExtent = this.itemExtent; - + final double itemFixedExtent = itemExtent ?? 0; final double scrollOffset = constraints.scrollOffset + constraints.cacheOrigin; assert(scrollOffset >= 0.0); final double remainingExtent = constraints.remainingCacheExtent; assert(remainingExtent >= 0.0); final double targetEndScrollOffset = scrollOffset + remainingExtent; - final BoxConstraints childConstraints = constraints.asBoxConstraints( - minExtent: itemExtent, - maxExtent: itemExtent, + _currentLayoutDimensions = SliverLayoutDimensions( + scrollOffset: constraints.scrollOffset, + precedingScrollExtent: constraints.precedingScrollExtent, + viewportMainAxisExtent: constraints.viewportMainAxisExtent, + crossAxisExtent: constraints.crossAxisExtent ); - final int firstIndex = getMinChildIndexForScrollOffset(scrollOffset, itemExtent); + final int firstIndex = getMinChildIndexForScrollOffset(scrollOffset, itemFixedExtent); final int? targetLastIndex = targetEndScrollOffset.isFinite ? - getMaxChildIndexForScrollOffset(targetEndScrollOffset, itemExtent) : null; + getMaxChildIndexForScrollOffset(targetEndScrollOffset, itemFixedExtent) : null; if (firstChild != null) { final int leadingGarbage = _calculateLeadingGarbage(firstIndex); @@ -202,13 +273,13 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda } if (firstChild == null) { - if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemExtent, firstIndex))) { + if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemFixedExtent, firstIndex))) { // There are either no children, or we are past the end of all our children. final double max; if (firstIndex <= 0) { max = 0.0; } else { - max = computeMaxScrollOffset(constraints, itemExtent); + max = computeMaxScrollOffset(constraints, itemFixedExtent); } geometry = SliverGeometry( scrollExtent: max, @@ -222,24 +293,24 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda RenderBox? trailingChildWithLayout; for (int index = indexOf(firstChild!) - 1; index >= firstIndex; --index) { - final RenderBox? child = insertAndLayoutLeadingChild(childConstraints); + final RenderBox? child = insertAndLayoutLeadingChild(_getChildConstraints(index)); if (child == null) { // Items before the previously first child are no longer present. // Reset the scroll offset to offset all items prior and up to the // missing item. Let parent re-layout everything. - geometry = SliverGeometry(scrollOffsetCorrection: index * itemExtent); + geometry = SliverGeometry(scrollOffsetCorrection: indexToLayoutOffset(itemFixedExtent, index)); return; } final SliverMultiBoxAdaptorParentData childParentData = child.parentData! as SliverMultiBoxAdaptorParentData; - childParentData.layoutOffset = indexToLayoutOffset(itemExtent, index); + childParentData.layoutOffset = indexToLayoutOffset(itemFixedExtent, index); assert(childParentData.index == index); trailingChildWithLayout ??= child; } if (trailingChildWithLayout == null) { - firstChild!.layout(childConstraints); + firstChild!.layout(_getChildConstraints(indexOf(firstChild!))); final SliverMultiBoxAdaptorParentData childParentData = firstChild!.parentData! as SliverMultiBoxAdaptorParentData; - childParentData.layoutOffset = indexToLayoutOffset(itemExtent, firstIndex); + childParentData.layoutOffset = indexToLayoutOffset(itemFixedExtent, firstIndex); trailingChildWithLayout = firstChild; } @@ -247,24 +318,24 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda for (int index = indexOf(trailingChildWithLayout!) + 1; targetLastIndex == null || index <= targetLastIndex; ++index) { RenderBox? child = childAfter(trailingChildWithLayout!); if (child == null || indexOf(child) != index) { - child = insertAndLayoutChild(childConstraints, after: trailingChildWithLayout); + child = insertAndLayoutChild(_getChildConstraints(index), after: trailingChildWithLayout); if (child == null) { // We have run out of children. - estimatedMaxScrollOffset = index * itemExtent; + estimatedMaxScrollOffset = indexToLayoutOffset(itemFixedExtent, index); break; } } else { - child.layout(childConstraints); + child.layout(_getChildConstraints(index)); } trailingChildWithLayout = child; final SliverMultiBoxAdaptorParentData childParentData = child.parentData! as SliverMultiBoxAdaptorParentData; assert(childParentData.index == index); - childParentData.layoutOffset = indexToLayoutOffset(itemExtent, childParentData.index!); + childParentData.layoutOffset = indexToLayoutOffset(itemFixedExtent, childParentData.index!); } final int lastIndex = indexOf(lastChild!); - final double leadingScrollOffset = indexToLayoutOffset(itemExtent, firstIndex); - final double trailingScrollOffset = indexToLayoutOffset(itemExtent, lastIndex + 1); + final double leadingScrollOffset = indexToLayoutOffset(itemFixedExtent, firstIndex); + final double trailingScrollOffset = indexToLayoutOffset(itemFixedExtent, lastIndex + 1); assert(firstIndex == 0 || childScrollOffset(firstChild!)! - scrollOffset <= precisionErrorTolerance); assert(debugAssertChildListIsNonEmptyAndContiguous()); @@ -296,7 +367,8 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda final double targetEndScrollOffsetForPaint = constraints.scrollOffset + constraints.remainingPaintExtent; final int? targetLastIndexForPaint = targetEndScrollOffsetForPaint.isFinite ? - getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint, itemExtent) : null; + getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint, itemFixedExtent) : null; + geometry = SliverGeometry( scrollExtent: estimatedMaxScrollOffset, paintExtent: paintExtent, diff --git a/packages/flutter/lib/src/widgets/reorderable_list.dart b/packages/flutter/lib/src/widgets/reorderable_list.dart index bfb07016e7348..0f0d5e78ccec3 100644 --- a/packages/flutter/lib/src/widgets/reorderable_list.dart +++ b/packages/flutter/lib/src/widgets/reorderable_list.dart @@ -21,6 +21,7 @@ import 'scrollable.dart'; import 'scrollable_helpers.dart'; import 'sliver.dart'; import 'sliver_prototype_extent_list.dart'; +import 'sliver_varied_extent_list.dart'; import 'ticker_provider.dart'; import 'transitions.dart'; @@ -118,6 +119,7 @@ class ReorderableList extends StatefulWidget { this.onReorderStart, this.onReorderEnd, this.itemExtent, + this.itemExtentBuilder, this.prototypeItem, this.proxyDecorator, this.padding, @@ -135,10 +137,12 @@ class ReorderableList extends StatefulWidget { this.clipBehavior = Clip.hardEdge, this.autoScrollerVelocityScalar, }) : assert(itemCount >= 0), - assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both', - ); + assert( + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', + ); /// {@template flutter.widgets.reorderable_list.itemBuilder} /// Called, as needed, to build list item widgets. @@ -253,6 +257,9 @@ class ReorderableList extends StatefulWidget { /// {@macro flutter.widgets.list_view.itemExtent} final double? itemExtent; + /// {@macro flutter.widgets.list_view.itemExtentBuilder} + final ItemExtentBuilder? itemExtentBuilder; + /// {@macro flutter.widgets.list_view.prototypeItem} final Widget? prototypeItem; @@ -450,14 +457,17 @@ class SliverReorderableList extends StatefulWidget { this.onReorderStart, this.onReorderEnd, this.itemExtent, + this.itemExtentBuilder, this.prototypeItem, this.proxyDecorator, double? autoScrollerVelocityScalar, }) : autoScrollerVelocityScalar = autoScrollerVelocityScalar ?? _kDefaultAutoScrollVelocityScalar, assert(itemCount >= 0), assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both', + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', ); // An eyeballed value for a smooth scrolling experience. @@ -487,6 +497,9 @@ class SliverReorderableList extends StatefulWidget { /// {@macro flutter.widgets.list_view.itemExtent} final double? itemExtent; + /// {@macro flutter.widgets.list_view.itemExtentBuilder} + final ItemExtentBuilder? itemExtentBuilder; + /// {@macro flutter.widgets.list_view.prototypeItem} final Widget? prototypeItem; @@ -1036,6 +1049,11 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke delegate: childrenDelegate, itemExtent: widget.itemExtent!, ); + } else if (widget.itemExtentBuilder != null) { + return SliverVariedExtentList( + delegate: childrenDelegate, + itemExtentBuilder: widget.itemExtentBuilder!, + ); } else if (widget.prototypeItem != null) { return SliverPrototypeExtentList( delegate: childrenDelegate, diff --git a/packages/flutter/lib/src/widgets/scroll_view.dart b/packages/flutter/lib/src/widgets/scroll_view.dart index c097a1b785756..666990cd3ccc2 100644 --- a/packages/flutter/lib/src/widgets/scroll_view.dart +++ b/packages/flutter/lib/src/widgets/scroll_view.dart @@ -24,6 +24,7 @@ import 'scrollable.dart'; import 'scrollable_helpers.dart'; import 'sliver.dart'; import 'sliver_prototype_extent_list.dart'; +import 'sliver_varied_extent_list.dart'; import 'viewport.dart'; // Examples can assume: @@ -1230,6 +1231,7 @@ class ListView extends BoxScrollView { super.shrinkWrap, super.padding, this.itemExtent, + this.itemExtentBuilder, this.prototypeItem, bool addAutomaticKeepAlives = true, bool addRepaintBoundaries = true, @@ -1242,8 +1244,10 @@ class ListView extends BoxScrollView { super.restorationId, super.clipBehavior, }) : assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both.', + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', ), childrenDelegate = SliverChildListDelegate( children, @@ -1303,6 +1307,7 @@ class ListView extends BoxScrollView { super.shrinkWrap, super.padding, this.itemExtent, + this.itemExtentBuilder, this.prototypeItem, required NullableIndexedWidgetBuilder itemBuilder, ChildIndexGetter? findChildIndexCallback, @@ -1319,8 +1324,10 @@ class ListView extends BoxScrollView { }) : assert(itemCount == null || itemCount >= 0), assert(semanticChildCount == null || semanticChildCount <= itemCount!), assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both.', + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', ), childrenDelegate = SliverChildBuilderDelegate( itemBuilder, @@ -1408,6 +1415,7 @@ class ListView extends BoxScrollView { super.clipBehavior, }) : assert(itemCount >= 0), itemExtent = null, + itemExtentBuilder = null, prototypeItem = null, childrenDelegate = SliverChildBuilderDelegate( (BuildContext context, int index) { @@ -1528,6 +1536,7 @@ class ListView extends BoxScrollView { super.padding, this.itemExtent, this.prototypeItem, + this.itemExtentBuilder, required this.childrenDelegate, super.cacheExtent, super.semanticChildCount, @@ -1536,8 +1545,10 @@ class ListView extends BoxScrollView { super.restorationId, super.clipBehavior, }) : assert( - itemExtent == null || prototypeItem == null, - 'You can only pass itemExtent or prototypeItem, not both', + (itemExtent == null && prototypeItem == null) || + (itemExtent == null && itemExtentBuilder == null) || + (prototypeItem == null && itemExtentBuilder == null), + 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', ); /// {@template flutter.widgets.list_view.itemExtent} @@ -1556,9 +1567,38 @@ class ListView extends BoxScrollView { /// extent along the main axis. /// * The [prototypeItem] property, which allows forcing the children's /// extent to be the same as the given widget. + /// * The [itemExtentBuilder] property, which allows forcing the children's + /// extent to be the value returned by the callback. /// {@endtemplate} final double? itemExtent; + /// {@template flutter.widgets.list_view.itemExtentBuilder} + /// If non-null, forces the children to have the corresponding extent returned + /// by the builder. + /// + /// Specifying an [itemExtentBuilder] is more efficient than letting the children + /// determine their own extent because the scrolling machinery can make use of + /// the foreknowledge of the children's extent to save work, for example when + /// the scroll position changes drastically. + /// + /// This will be called multiple times during the layout phase of a frame to find + /// the items that should be loaded by the lazy loading process. + /// + /// Unlike [itemExtent] or [prototypeItem], this allows children to have + /// different extents. + /// + /// See also: + /// + /// * [SliverVariedExtentList], the sliver used internally when this property + /// is provided. It constrains its box children to have a specific given + /// extent along the main axis. + /// * The [itemExtent] property, which allows forcing the children's extent + /// to a given value. + /// * The [prototypeItem] property, which allows forcing the children's + /// extent to be the same as the given widget. + /// {@endtemplate} + final ItemExtentBuilder? itemExtentBuilder; + /// {@template flutter.widgets.list_view.prototypeItem} /// If non-null, forces the children to have the same extent as the given /// widget in the scroll direction. @@ -1575,6 +1615,8 @@ class ListView extends BoxScrollView { /// extent as a prototype item along the main axis. /// * The [itemExtent] property, which allows forcing the children's extent /// to a given value. + /// * The [itemExtentBuilder] property, which allows forcing the children's + /// extent to be the value returned by the callback. /// {@endtemplate} final Widget? prototypeItem; @@ -1593,6 +1635,11 @@ class ListView extends BoxScrollView { delegate: childrenDelegate, itemExtent: itemExtent!, ); + } else if (itemExtentBuilder != null) { + return SliverVariedExtentList( + delegate: childrenDelegate, + itemExtentBuilder: itemExtentBuilder!, + ); } else if (prototypeItem != null) { return SliverPrototypeExtentList( delegate: childrenDelegate, diff --git a/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart b/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart new file mode 100644 index 0000000000000..e79b7dfc27f81 --- /dev/null +++ b/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart @@ -0,0 +1,137 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/rendering.dart'; + +import 'framework.dart'; +import 'scroll_delegate.dart'; +import 'sliver.dart'; + +/// A sliver that places its box children in a linear array and constrains them +/// to have the corresponding extent returned by [itemExtentBuilder]. +/// +/// _To learn more about slivers, see [CustomScrollView.slivers]._ +/// +/// [SliverVariedExtentList] arranges its children in a line along +/// the main axis starting at offset zero and without gaps. Each child is +/// constrained to the corresponding extent along the main axis +/// and the [SliverConstraints.crossAxisExtent] along the cross axis. +/// +/// [SliverVariedExtentList] is more efficient than [SliverList] because +/// [SliverVariedExtentList] does not need to lay out its children to obtain +/// their extent along the main axis. It's a little more flexible than +/// [SliverFixedExtentList] because this allow the children to have different extents. +/// +/// See also: +/// +/// * [SliverFixedExtentList], whose children are forced to a given pixel +/// extent. +/// * [SliverList], which does not require its children to have the same +/// extent in the main axis. +/// * [SliverFillViewport], which sizes its children based on the +/// size of the viewport, regardless of what else is in the scroll view. +class SliverVariedExtentList extends SliverMultiBoxAdaptorWidget { + /// Creates a sliver that places box children with the same main axis extent + /// in a linear array. + const SliverVariedExtentList({ + super.key, + required super.delegate, + required this.itemExtentBuilder, + }); + + /// A sliver that places multiple box children in a linear array along the main + /// axis. + /// + /// [SliverVariedExtentList] places its children in a linear array along the main + /// axis starting at offset zero and without gaps. Each child is forced to have + /// the returned extent of [itemExtentBuilder] in the main axis and the + /// [SliverConstraints.crossAxisExtent] in the cross axis. + /// + /// This constructor is appropriate for sliver lists with a large (or + /// infinite) number of children whose extent is already determined. + /// + /// Providing a non-null `itemCount` improves the ability of the [SliverGrid] + /// to estimate the maximum scroll extent. + SliverVariedExtentList.builder({ + super.key, + required NullableIndexedWidgetBuilder itemBuilder, + required this.itemExtentBuilder, + ChildIndexGetter? findChildIndexCallback, + int? itemCount, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + }) : super(delegate: SliverChildBuilderDelegate( + itemBuilder, + findChildIndexCallback: findChildIndexCallback, + childCount: itemCount, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + addSemanticIndexes: addSemanticIndexes, + )); + + /// A sliver that places multiple box children in a linear array along the main + /// axis. + /// + /// [SliverVariedExtentList] places its children in a linear array along the main + /// axis starting at offset zero and without gaps. Each child is forced to have + /// the returned extent of [itemExtentBuilder] in the main axis and the + /// [SliverConstraints.crossAxisExtent] in the cross axis. + /// + /// This constructor uses a list of [Widget]s to build the sliver. + SliverVariedExtentList.list({ + super.key, + required List<Widget> children, + required this.itemExtentBuilder, + bool addAutomaticKeepAlives = true, + bool addRepaintBoundaries = true, + bool addSemanticIndexes = true, + }) : super(delegate: SliverChildListDelegate( + children, + addAutomaticKeepAlives: addAutomaticKeepAlives, + addRepaintBoundaries: addRepaintBoundaries, + addSemanticIndexes: addSemanticIndexes, + )); + + /// The children extent builder. + final ItemExtentBuilder itemExtentBuilder; + + @override + RenderSliverVariedExtentList createRenderObject(BuildContext context) { + final SliverMultiBoxAdaptorElement element = context as SliverMultiBoxAdaptorElement; + return RenderSliverVariedExtentList(childManager: element, itemExtentBuilder: itemExtentBuilder); + } + + @override + void updateRenderObject(BuildContext context, RenderSliverVariedExtentList renderObject) { + renderObject.itemExtentBuilder = itemExtentBuilder; + } +} + +/// A sliver that places multiple box children with the corresponding main axis extent in +/// a linear array. +class RenderSliverVariedExtentList extends RenderSliverFixedExtentBoxAdaptor { + /// Creates a sliver that contains multiple box children that have a explicit + /// extent in the main axis. + /// + /// The [childManager] argument must not be null. + RenderSliverVariedExtentList({ + required super.childManager, + required ItemExtentBuilder itemExtentBuilder, + }) : _itemExtentBuilder = itemExtentBuilder; + + @override + ItemExtentBuilder get itemExtentBuilder => _itemExtentBuilder; + ItemExtentBuilder _itemExtentBuilder; + set itemExtentBuilder(ItemExtentBuilder value) { + if (_itemExtentBuilder == value) { + return; + } + _itemExtentBuilder = value; + markNeedsLayout(); + } + + @override + double? get itemExtent => null; +} diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 3ca0999b994d0..cc188608a8519 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -136,6 +136,7 @@ export 'src/widgets/sliver_fill.dart'; export 'src/widgets/sliver_layout_builder.dart'; export 'src/widgets/sliver_persistent_header.dart'; export 'src/widgets/sliver_prototype_extent_list.dart'; +export 'src/widgets/sliver_varied_extent_list.dart'; export 'src/widgets/slotted_render_object_widget.dart'; export 'src/widgets/snapshot_widget.dart'; export 'src/widgets/spacer.dart'; diff --git a/packages/flutter/test/widgets/list_view_test.dart b/packages/flutter/test/widgets/list_view_test.dart index ab9185d18442b..bfb39cfcce424 100644 --- a/packages/flutter/test/widgets/list_view_test.dart +++ b/packages/flutter/test/widgets/list_view_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -776,4 +777,189 @@ void main() { final RenderViewport renderObject = tester.allRenderObjects.whereType<RenderViewport>().first; expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); + + // Regression test for https://github.com/flutter/flutter/pull/131393 + testWidgets('itemExtentBuilder test', (WidgetTester tester) async { + final ScrollController controller = ScrollController(); + final List<int> buildLog = <int>[]; + late SliverLayoutDimensions sliverLayoutDimensions; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ListView.builder( + controller: controller, + itemExtentBuilder: (int index, SliverLayoutDimensions dimensions) { + sliverLayoutDimensions = dimensions; + return 100.0; + }, + itemBuilder: (BuildContext context, int index) { + buildLog.insert(0, index); + return Text('Item $index'); + }, + ), + ), + ); + + expect(find.text('Item 0'), findsOneWidget); + expect(find.text('Item 5'), findsOneWidget); + expect(find.text('Item 6'), findsNothing); + expect( + sliverLayoutDimensions, + const SliverLayoutDimensions( + scrollOffset: 0.0, + precedingScrollExtent: 0.0, + viewportMainAxisExtent: 600.0, + crossAxisExtent: 800.0, + ) + ); + // viewport(600.0) + cache extent after(250.0) + expect(buildLog.length, 9); + expect(buildLog.min, 0); + expect(buildLog.max, 8); + + buildLog.clear(); + + // Scrolling drastically. + controller.jumpTo(10000.0); + await tester.pump(); + + expect(find.text('Item 99'), findsNothing); + expect(find.text('Item 100'), findsOneWidget); + expect(find.text('Item 105'), findsOneWidget); + expect(find.text('Item 106'), findsNothing); + expect( + sliverLayoutDimensions, + const SliverLayoutDimensions( + scrollOffset: 10000.0, + precedingScrollExtent: 0.0, + viewportMainAxisExtent: 600.0, + crossAxisExtent: 800.0, + ) + ); + // Scrolling drastically only loading the visible and cached area items. + // cache extent before(250.0) + viewport(600.0) + cache extent after(250.0) + expect(buildLog.length, 12); + expect(buildLog.min, 97); + expect(buildLog.max, 108); + + buildLog.clear(); + controller.jumpTo(5000.0); + await tester.pump(); + + expect(find.text('Item 49'), findsNothing); + expect(find.text('Item 50'), findsOneWidget); + expect(find.text('Item 55'), findsOneWidget); + expect(find.text('Item 56'), findsNothing); + expect( + sliverLayoutDimensions, + const SliverLayoutDimensions( + scrollOffset: 5000.0, + precedingScrollExtent: 0.0, + viewportMainAxisExtent: 600.0, + crossAxisExtent: 800.0, + ) + ); + // cache extent before(250.0) + viewport(600.0) + cache extent after(250.0) + expect(buildLog.length, 12); + expect(buildLog.min, 47); + expect(buildLog.max, 58); + + buildLog.clear(); + controller.jumpTo(4700.0); + await tester.pump(); + + expect(find.text('Item 46'), findsNothing); + expect(find.text('Item 47'), findsOneWidget); + expect(find.text('Item 52'), findsOneWidget); + expect(find.text('Item 53'), findsNothing); + expect( + sliverLayoutDimensions, + const SliverLayoutDimensions( + scrollOffset: 4700.0, + precedingScrollExtent: 0.0, + viewportMainAxisExtent: 600.0, + crossAxisExtent: 800.0, + ) + ); + // Only newly entered cached area items need to be loaded. + expect(buildLog.length, 3); + expect(buildLog.min, 44); + expect(buildLog.max, 46); + + buildLog.clear(); + controller.jumpTo(5300.0); + await tester.pump(); + + expect(find.text('Item 52'), findsNothing); + expect(find.text('Item 53'), findsOneWidget); + expect(find.text('Item 58'), findsOneWidget); + expect(find.text('Item 59'), findsNothing); + expect( + sliverLayoutDimensions, + const SliverLayoutDimensions( + scrollOffset: 5300.0, + precedingScrollExtent: 0.0, + viewportMainAxisExtent: 600.0, + crossAxisExtent: 800.0, + ) + ); + // Only newly entered cached area items need to be loaded. + expect(buildLog.length, 6); + expect(buildLog.min, 56); + expect(buildLog.max, 61); + }); + + testWidgets('itemExtent, prototypeItem and itemExtentBuilder conflicts test', (WidgetTester tester) async { + Object? error; + try { + await tester.pumpWidget( + ListView.builder( + itemExtentBuilder: (int index, SliverLayoutDimensions dimensions) { + return 100.0; + }, + itemExtent: 100.0, + itemBuilder: (BuildContext context, int index) { + return Text('Item $index'); + }, + ), + ); + } catch (e) { + error = e; + } + expect(error, isNotNull); + + error = null; + try { + await tester.pumpWidget( + ListView.builder( + itemExtentBuilder: (int index, SliverLayoutDimensions dimensions) { + return 100.0; + }, + prototypeItem: Container(), + itemBuilder: (BuildContext context, int index) { + return Text('Item $index'); + }, + ), + ); + } catch (e) { + error = e; + } + expect(error, isNotNull); + + error = null; + try { + await tester.pumpWidget( + ListView.builder( + itemExtent: 100.0, + prototypeItem: Container(), + itemBuilder: (BuildContext context, int index) { + return Text('Item $index'); + }, + ), + ); + } catch (e) { + error = e; + } + expect(error, isNotNull); + }); } From bc594bd448452b71ad1adf25e70e372d4653e4b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 11 Sep 2023 22:58:25 -0400 Subject: [PATCH 1206/1547] Roll Flutter Engine from a98348946d61 to 6ddee4423d2c (1 revision) (#134490) https://github.com/flutter/engine/compare/a98348946d61...6ddee4423d2c 2023-09-12 matej.knopp@gmail.com [Web] Properly report inverted selection (flutter/engine#44806) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a5949d3c10ecb..45933c4b504cc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a98348946d615380f20e9b3130da6fc9cf214af3 +6ddee4423d2c0dce1301e203fd98073b5a856e89 From e95c745b3368d0d94d129088d3ad3ce9626ac525 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 02:06:14 -0400 Subject: [PATCH 1207/1547] Roll Flutter Engine from 6ddee4423d2c to ee7215553deb (2 revisions) (#134505) https://github.com/flutter/engine/compare/6ddee4423d2c...ee7215553deb 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from c4e94d5febdc to 62aa41ee8135 (2 revisions) (flutter/engine#45690) 2023-09-12 matanlurey@users.noreply.github.com [Impeller] Fix thread leak in ResourceManagerVK. (flutter/engine#45686) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 45933c4b504cc..44a393bdacf4b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6ddee4423d2c0dce1301e203fd98073b5a856e89 +ee7215553debd4ac4960b318535bba8e5faeff05 From c7f38599764dd592420f97749baaecd9cdd54e98 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 02:56:23 -0400 Subject: [PATCH 1208/1547] Roll Flutter Engine from ee7215553deb to 4d8265cbc133 (1 revision) (#134506) https://github.com/flutter/engine/compare/ee7215553deb...4d8265cbc133 2023-09-12 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from cUKimo52R-2EIfHh5... to vGleXqh2SRUNJM7JN... (flutter/engine#45691) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from cUKimo52R-2E to vGleXqh2SRUN If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 44a393bdacf4b..e9bf1add4bcd9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ee7215553debd4ac4960b318535bba8e5faeff05 +4d8265cbc133b814513d163762d749e98f92185b diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 01aae5cec60bd..c381a80c6d8e9 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -cUKimo52R-2EIfHh5zsJZBokuNVytOkTEle-leUr-oQC +vGleXqh2SRUNJM7JNwpEoinm9VFaEF4eIgBF0M_-V9sC From 6f96d5eb612840d4f24840ab61bce9b74bf1e180 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 04:21:08 -0400 Subject: [PATCH 1209/1547] Roll Flutter Engine from 4d8265cbc133 to 2f1efe5967f3 (3 revisions) (#134511) https://github.com/flutter/engine/compare/4d8265cbc133...2f1efe5967f3 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from ba5d081cd448 to 9f92b15074a6 (1 revision) (flutter/engine#45695) 2023-09-12 49699333+dependabot[bot]@users.noreply.github.com Bump actions/upload-artifact from 3.1.2 to 3.1.3 (flutter/engine#45694) 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 62aa41ee8135 to ba5d081cd448 (3 revisions) (flutter/engine#45692) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e9bf1add4bcd9..4c30e233c9dc2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4d8265cbc133b814513d163762d749e98f92185b +2f1efe5967f3a3462be669cde11b69d6d3c3a61d From bb079949bb95fd2df947e94aba929fcdde96bd1e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 05:10:10 -0400 Subject: [PATCH 1210/1547] Roll Flutter Engine from 2f1efe5967f3 to 1369ab35aaa7 (1 revision) (#134512) https://github.com/flutter/engine/compare/2f1efe5967f3...1369ab35aaa7 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 9f92b15074a6 to 72e5b5c8d5f0 (1 revision) (flutter/engine#45696) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4c30e233c9dc2..fadae7af0c83e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2f1efe5967f3a3462be669cde11b69d6d3c3a61d +1369ab35aaa79639f566dbdbbbb5476eda889e31 From ac79c84615723593722a91a81bcac99e73788cd9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 07:14:36 -0400 Subject: [PATCH 1211/1547] Roll Flutter Engine from 1369ab35aaa7 to 85f3f02e5c37 (1 revision) (#134519) https://github.com/flutter/engine/compare/1369ab35aaa7...85f3f02e5c37 2023-09-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from fSmVaZwp41ZGp5hKn... to QgAHx3BtJfN3TmodS... (flutter/engine#45700) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from fSmVaZwp41ZG to QgAHx3BtJfN3 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fadae7af0c83e..ce1a95bab43ae 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1369ab35aaa79639f566dbdbbbb5476eda889e31 +85f3f02e5c37ddebb2557e90dfbc2b8bbdd782f7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index d06e1adc72ba9..28999760cc613 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -fSmVaZwp41ZGp5hKnDIGj56IAdgVpbpMTPwN21pR_DYC +QgAHx3BtJfN3TmodSqY480Oyo-FI8WHUnMIAuYsoSukC From 278b145ae47dca4cd9541f9b88f91a9a5717bdf9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 09:44:21 -0400 Subject: [PATCH 1212/1547] Roll Flutter Engine from 85f3f02e5c37 to 54175da7ba90 (2 revisions) (#134531) https://github.com/flutter/engine/compare/85f3f02e5c37...54175da7ba90 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 5b94fc73a36e to 8d11fcb3068a (1 revision) (flutter/engine#45703) 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 72e5b5c8d5f0 to 5b94fc73a36e (1 revision) (flutter/engine#45701) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ce1a95bab43ae..79f875b458832 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -85f3f02e5c37ddebb2557e90dfbc2b8bbdd782f7 +54175da7ba90fce5bfe80db072dfc041fb1e1a6a From 127c76b91bef46c6baffaaee8873870c3054ea02 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 10:34:25 -0400 Subject: [PATCH 1213/1547] Roll Flutter Engine from 54175da7ba90 to 4091167e402d (1 revision) (#134532) https://github.com/flutter/engine/compare/54175da7ba90...4091167e402d 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 8d11fcb3068a to 55c9c377f0b0 (1 revision) (flutter/engine#45705) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 79f875b458832..cc66a27c89dd0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -54175da7ba90fce5bfe80db072dfc041fb1e1a6a +4091167e402d3ce4f1637bde2a805c2df251aa56 From 9e891f2dc97829ac6a7feb7514d6492779c0112c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 11:34:08 -0400 Subject: [PATCH 1214/1547] Roll Flutter Engine from 4091167e402d to 25be03186d82 (1 revision) (#134536) https://github.com/flutter/engine/compare/4091167e402d...25be03186d82 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 55c9c377f0b0 to a1ff98bebf89 (1 revision) (flutter/engine#45706) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cc66a27c89dd0..5e77124decc26 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4091167e402d3ce4f1637bde2a805c2df251aa56 +25be03186d82699ad88758e944be4a287148af29 From bdd96032a05321d70ec1771b4bc9e3c827f1fbfc Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Tue, 12 Sep 2023 08:37:30 -0700 Subject: [PATCH 1215/1547] Marks Windows_android channels_integration_test_win to be unflaky (#133129) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows_android channels_integration_test_win" } --> The issue https://github.com/flutter/flutter/issues/130732 has been closed, and the test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Windows_android%20channels_integration_test_win%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 07fd6f54df8ea..3ccd3707a56bb 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -5102,7 +5102,6 @@ targets: - name: Windows_android channels_integration_test_win recipe: devicelab/devicelab_drone - bringup: true # https://github.com/flutter/flutter/issues/130732 presubmit: false timeout: 60 properties: From 5900c4baa751aff8f05e820287a02b60cdd62dfa Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:18:40 -0700 Subject: [PATCH 1216/1547] =?UTF-8?q?Revert=20"Adds=20a=20parent=20scope?= =?UTF-8?q?=20TraversalEdgeBehavior=20and=20fixes=20modal=20rou=E2=80=A6?= =?UTF-8?q?=20(#134550)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …te to no… (#130841)" This reverts commit 0f3bd90d9b108904cc0390e899c2b3c6ee2e76e0. Internal test needs migration ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- packages/flutter/lib/src/widgets/app.dart | 1 - .../lib/src/widgets/focus_traversal.dart | 138 +++--------------- .../flutter/lib/src/widgets/navigator.dart | 4 +- packages/flutter/lib/src/widgets/routes.dart | 25 +--- .../test/material/icon_button_test.dart | 10 +- .../flutter/test/widgets/actions_test.dart | 2 +- .../test/widgets/focus_traversal_test.dart | 90 ------------ .../flutter/test/widgets/navigator_test.dart | 19 +-- 8 files changed, 35 insertions(+), 254 deletions(-) diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index 7a524639fb423..d8d649c103a45 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -1685,7 +1685,6 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver { }, onUnknownRoute: _onUnknownRoute, observers: widget.navigatorObservers!, - routeTraversalEdgeBehavior: kIsWeb ? TraversalEdgeBehavior.leaveFlutterView : TraversalEdgeBehavior.parentScope, reportsRouteUpdateToEngine: true, ), ); diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index f67080c71a028..203e13252958d 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -120,16 +120,6 @@ enum TraversalEdgeBehavior { /// address bar, escape an `iframe`, or focus on HTML elements other than /// those managed by Flutter. leaveFlutterView, - - /// Allows focus to traverse up to parent scope. - /// - /// When reaching the edge of the current scope, requesting the next focus - /// will look up to the parent scope of the current scope and focus the focus - /// node next to the current scope. - /// - /// If there is no parent scope above the current scope, fallback to - /// [closedLoop] behavior. - parentScope, } /// Determines how focusable widgets are traversed within a [FocusTraversalGroup]. @@ -196,60 +186,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { ); } - /// Request focus on a focus node as a result of a tab traversal. - /// - /// If the `node` is a [FocusScopeNode], this method will recursively find - /// the next focus from its descendants until it find a regular [FocusNode]. - /// - /// Returns true if this method focused a new focus node. - bool _requestTabTraversalFocus( - FocusNode node, { - ScrollPositionAlignmentPolicy? alignmentPolicy, - double? alignment, - Duration? duration, - Curve? curve, - required bool forward, - }) { - if (node is FocusScopeNode) { - if (node.focusedChild != null) { - // Can't stop here as the `focusedChild` may be a focus scope node - // without a first focus. The first focus will be picked in the - // next iteration. - return _requestTabTraversalFocus( - node.focusedChild!, - alignmentPolicy: alignmentPolicy, - alignment: alignment, - duration: duration, - curve: curve, - forward: forward, - ); - } - final List<FocusNode> sortedChildren = _sortAllDescendants(node, node); - if (sortedChildren.isNotEmpty) { - _requestTabTraversalFocus( - forward ? sortedChildren.first : sortedChildren.last, - alignmentPolicy: alignmentPolicy, - alignment: alignment, - duration: duration, - curve: curve, - forward: forward, - ); - // Regardless if _requestTabTraversalFocus return true or false, a first - // focus has been picked. - return true; - } - } - final bool nodeHadPrimaryFocus = node.hasPrimaryFocus; - requestFocusCallback( - node, - alignmentPolicy: alignmentPolicy, - alignment: alignment, - duration: duration, - curve: curve, - ); - return !nodeHadPrimaryFocus; - } - /// Returns the node that should receive focus if focus is traversing /// forwards, and there is no current focus. /// @@ -416,21 +352,10 @@ abstract class FocusTraversalPolicy with Diagnosticable { @protected Iterable<FocusNode> sortDescendants(Iterable<FocusNode> descendants, FocusNode currentNode); - static Iterable<FocusNode> _getDescendantsWithoutExpandingScope(FocusNode node) { - final List<FocusNode> result = <FocusNode>[]; - for (final FocusNode child in node.children) { - if (child is! FocusScopeNode) { - result.addAll(_getDescendantsWithoutExpandingScope(child)); - } - result.add(child); - } - return result; - } - - static Map<FocusNode?, _FocusTraversalGroupInfo> _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { + Map<FocusNode?, _FocusTraversalGroupInfo> _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { final FocusTraversalPolicy defaultPolicy = scopeGroupNode?.policy ?? ReadingOrderTraversalPolicy(); final Map<FocusNode?, _FocusTraversalGroupInfo> groups = <FocusNode?, _FocusTraversalGroupInfo>{}; - for (final FocusNode node in _getDescendantsWithoutExpandingScope(scope)) { + for (final FocusNode node in scope.descendants) { final _FocusTraversalGroupNode? groupNode = FocusTraversalGroup._getGroupNode(node); // Group nodes need to be added to their parent's node, or to the "null" // node if no parent is found. This creates the hierarchy of group nodes @@ -463,7 +388,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { // Sort all descendants, taking into account the FocusTraversalGroup // that they are each in, and filtering out non-traversable/focusable nodes. - static List<FocusNode> _sortAllDescendants(FocusScopeNode scope, FocusNode currentNode) { + List<FocusNode> _sortAllDescendants(FocusScopeNode scope, FocusNode currentNode) { final _FocusTraversalGroupNode? scopeGroupNode = FocusTraversalGroup._getGroupNode(scope); // Build the sorting data structure, separating descendants into groups. final Map<FocusNode?, _FocusTraversalGroupInfo> groups = _findGroups(scope, scopeGroupNode, currentNode); @@ -548,42 +473,30 @@ abstract class FocusTraversalPolicy with Diagnosticable { if (focusedChild == null) { final FocusNode? firstFocus = forward ? findFirstFocus(currentNode) : findLastFocus(currentNode); if (firstFocus != null) { - return _requestTabTraversalFocus( + requestFocusCallback( firstFocus, alignmentPolicy: forward ? ScrollPositionAlignmentPolicy.keepVisibleAtEnd : ScrollPositionAlignmentPolicy.keepVisibleAtStart, - forward: forward, ); + return true; } } focusedChild ??= nearestScope; final List<FocusNode> sortedNodes = _sortAllDescendants(nearestScope, focusedChild); - assert(sortedNodes.contains(focusedChild)); + assert(sortedNodes.contains(focusedChild)); + if (sortedNodes.length < 2) { + // If there are no nodes to traverse to, like when descendantsAreTraversable + // is false or skipTraversal for all the nodes is true. + return false; + } if (forward && focusedChild == sortedNodes.last) { switch (nearestScope.traversalEdgeBehavior) { case TraversalEdgeBehavior.leaveFlutterView: focusedChild.unfocus(); return false; - case TraversalEdgeBehavior.parentScope: - final FocusScopeNode? parentScope = nearestScope.enclosingScope; - if (parentScope != null && parentScope != FocusManager.instance.rootScope) { - focusedChild.unfocus(); - parentScope.nextFocus(); - // Verify the focus really has changed. - return focusedChild.enclosingScope?.focusedChild != focusedChild; - } - // No valid parent scope. Fallback to closed loop behavior. - return _requestTabTraversalFocus( - sortedNodes.first, - alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd, - forward: forward, - ); case TraversalEdgeBehavior.closedLoop: - return _requestTabTraversalFocus( - sortedNodes.first, - alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd, - forward: forward, - ); + requestFocusCallback(sortedNodes.first, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd); + return true; } } if (!forward && focusedChild == sortedNodes.first) { @@ -591,26 +504,9 @@ abstract class FocusTraversalPolicy with Diagnosticable { case TraversalEdgeBehavior.leaveFlutterView: focusedChild.unfocus(); return false; - case TraversalEdgeBehavior.parentScope: - final FocusScopeNode? parentScope = nearestScope.enclosingScope; - if (parentScope != null && parentScope != FocusManager.instance.rootScope) { - focusedChild.unfocus(); - parentScope.previousFocus(); - // Verify the focus really has changed. - return focusedChild.enclosingScope?.focusedChild != focusedChild; - } - // No valid parent scope. Fallback to closed loop behavior. - return _requestTabTraversalFocus( - sortedNodes.last, - alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart, - forward: forward, - ); case TraversalEdgeBehavior.closedLoop: - return _requestTabTraversalFocus( - sortedNodes.last, - alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart, - forward: forward, - ); + requestFocusCallback(sortedNodes.last, alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtStart); + return true; } } @@ -618,11 +514,11 @@ abstract class FocusTraversalPolicy with Diagnosticable { FocusNode? previousNode; for (final FocusNode node in maybeFlipped) { if (previousNode == focusedChild) { - return _requestTabTraversalFocus( + requestFocusCallback( node, alignmentPolicy: forward ? ScrollPositionAlignmentPolicy.keepVisibleAtEnd : ScrollPositionAlignmentPolicy.keepVisibleAtStart, - forward: forward, ); + return true; } previousNode = node; } diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index bc57d8a391985..ccf3fbfb56ad9 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -1146,7 +1146,9 @@ class DefaultTransitionDelegate<T> extends TransitionDelegate<T> { /// The default value of [Navigator.routeTraversalEdgeBehavior]. /// /// {@macro flutter.widgets.navigator.routeTraversalEdgeBehavior} -const TraversalEdgeBehavior kDefaultRouteTraversalEdgeBehavior = TraversalEdgeBehavior.parentScope; +const TraversalEdgeBehavior kDefaultRouteTraversalEdgeBehavior = kIsWeb + ? TraversalEdgeBehavior.leaveFlutterView + : TraversalEdgeBehavior.closedLoop; /// A widget that manages a set of child widgets with a stack discipline. /// diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index fc954fa0a1a2f..b51cb4f61c7c7 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -834,9 +834,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> { late Listenable _listenable; /// The node this scope will use for its root [FocusScope] widget. - final FocusScopeNode focusScopeNode = FocusScopeNode( - debugLabel: '$_ModalScopeState Focus Scope', - ); + final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: '$_ModalScopeState Focus Scope'); final ScrollController primaryScrollController = ScrollController(); @override @@ -938,8 +936,6 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> { controller: primaryScrollController, child: FocusScope( node: focusScopeNode, // immutable - // Only top most route can participate in focus traversal. - skipTraversal: !widget.route.isCurrent, child: RepaintBoundary( child: AnimatedBuilder( animation: _listenable, // immutable @@ -1708,26 +1704,11 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T changedInternalState(); } - @override - void didChangeNext(Route<dynamic>? nextRoute) { - super.didChangeNext(nextRoute); - changedInternalState(); - } - - @override - void didPopNext(Route<dynamic> nextRoute) { - super.didPopNext(nextRoute); - changedInternalState(); - } - @override void changedInternalState() { super.changedInternalState(); - // No need to mark dirty if this method is called during build phase. - if (SchedulerBinding.instance.schedulerPhase != SchedulerPhase.persistentCallbacks) { - setState(() { /* internal state already changed */ }); - _modalBarrier.markNeedsBuild(); - } + setState(() { /* internal state already changed */ }); + _modalBarrier.markNeedsBuild(); _modalScope.maintainState = maintainState; } diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 611a62cdfef85..44da15a62e6ec 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -4,7 +4,6 @@ import 'dart:ui'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -793,10 +792,6 @@ void main() { testWidgetsWithLeakTracking("Disabled IconButton can't be traversed to when disabled.", (WidgetTester tester) async { final FocusNode focusNode1 = FocusNode(debugLabel: 'IconButton 1'); final FocusNode focusNode2 = FocusNode(debugLabel: 'IconButton 2'); - addTearDown(() { - focusNode1.dispose(); - focusNode2.dispose(); - }); await tester.pumpWidget( wrap( @@ -826,8 +821,11 @@ void main() { expect(focusNode1.nextFocus(), isFalse); await tester.pump(); - expect(focusNode1.hasPrimaryFocus, !kIsWeb); + expect(focusNode1.hasPrimaryFocus, isTrue); expect(focusNode2.hasPrimaryFocus, isFalse); + + focusNode1.dispose(); + focusNode2.dispose(); }); group('feedback', () { diff --git a/packages/flutter/test/widgets/actions_test.dart b/packages/flutter/test/widgets/actions_test.dart index 38f548ee210b0..b0ee37f40828c 100644 --- a/packages/flutter/test/widgets/actions_test.dart +++ b/packages/flutter/test/widgets/actions_test.dart @@ -981,7 +981,7 @@ void main() { expect(buttonNode2.hasFocus, isFalse); primaryFocus!.nextFocus(); await tester.pump(); - expect(buttonNode1.hasFocus, isFalse); + expect(buttonNode1.hasFocus, isTrue); expect(buttonNode2.hasFocus, isFalse); }, ); diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index 2ce49be74e93d..d8ccbbc8389a8 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -441,96 +441,6 @@ void main() { }); - testWidgetsWithLeakTracking('Nested navigator does not trap focus', (WidgetTester tester) async { - final FocusNode node1 = FocusNode(); - addTearDown(node1.dispose); - final FocusNode node2 = FocusNode(); - addTearDown(node2.dispose); - final FocusNode node3 = FocusNode(); - addTearDown(node3.dispose); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: FocusTraversalGroup( - policy: ReadingOrderTraversalPolicy(), - child: FocusScope( - child: Column( - children: <Widget>[ - Focus( - focusNode: node1, - child: const SizedBox(width: 100, height: 100), - ), - SizedBox( - width: 100, - height: 100, - child: Navigator( - pages: <Page<void>>[ - MaterialPage<void>( - child: Focus( - focusNode: node2, - child: const SizedBox(width: 100, height: 100), - ), - ), - ], - onPopPage: (_, __) => false, - ), - ), - Focus( - focusNode: node3, - child: const SizedBox(width: 100, height: 100), - ), - ], - ), - ), - ), - ), - ); - - node1.requestFocus(); - await tester.pump(); - - expect(node1.hasFocus, isTrue); - expect(node2.hasFocus, isFalse); - expect(node3.hasFocus, isFalse); - - node1.nextFocus(); - await tester.pump(); - expect(node1.hasFocus, isFalse); - expect(node2.hasFocus, isTrue); - expect(node3.hasFocus, isFalse); - - node2.nextFocus(); - await tester.pump(); - expect(node1.hasFocus, isFalse); - expect(node2.hasFocus, isFalse); - expect(node3.hasFocus, isTrue); - - node3.nextFocus(); - await tester.pump(); - expect(node1.hasFocus, isTrue); - expect(node2.hasFocus, isFalse); - expect(node3.hasFocus, isFalse); - - node1.previousFocus(); - await tester.pump(); - expect(node1.hasFocus, isFalse); - expect(node2.hasFocus, isFalse); - expect(node3.hasFocus, isTrue); - - node3.previousFocus(); - await tester.pump(); - expect(node1.hasFocus, isFalse); - expect(node2.hasFocus, isTrue); - expect(node3.hasFocus, isFalse); - - node2.previousFocus(); - await tester.pump(); - expect(node1.hasFocus, isTrue); - expect(node2.hasFocus, isFalse); - expect(node3.hasFocus, isFalse); - }); - group(ReadingOrderTraversalPolicy, () { testWidgetsWithLeakTracking('Find the initial focus if there is none yet.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 95111931e34d2..886de4a712695 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -1487,34 +1487,29 @@ void main() { return result; }, )); - final List<String> expected = <String>['building page 1 - false']; - expect(log, expected); + expect(log, <String>['building page 1 - false']); key.currentState!.pushReplacement(PageRouteBuilder<int>( pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { log.add('building page 2 - ${ModalRoute.of(context)!.canPop}'); return const Placeholder(); }, )); - expect(log, expected); + expect(log, <String>['building page 1 - false']); await tester.pump(); - expected.add('building page 2 - false'); - expected.add('building page 1 - false'); // page 1 is rebuilt again because isCurrent changed. - expect(log, expected); + expect(log, <String>['building page 1 - false', 'building page 2 - false']); await tester.pump(const Duration(milliseconds: 150)); - expect(log, expected); + expect(log, <String>['building page 1 - false', 'building page 2 - false']); key.currentState!.pushReplacement(PageRouteBuilder<int>( pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { log.add('building page 3 - ${ModalRoute.of(context)!.canPop}'); return const Placeholder(); }, )); - expect(log, expected); + expect(log, <String>['building page 1 - false', 'building page 2 - false']); await tester.pump(); - expected.add('building page 3 - false'); - expected.add('building page 2 - false'); // page 2 is rebuilt again because isCurrent changed. - expect(log, expected); + expect(log, <String>['building page 1 - false', 'building page 2 - false', 'building page 3 - false']); await tester.pump(const Duration(milliseconds: 200)); - expect(log, expected); + expect(log, <String>['building page 1 - false', 'building page 2 - false', 'building page 3 - false']); }); testWidgets('route semantics', (WidgetTester tester) async { From f9aef4f21e315955e06d9bdcb61077e9ab1dfc76 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 12:50:18 -0400 Subject: [PATCH 1217/1547] Roll Packages from ef0c65ea4ccd to e04ba886a85e (5 revisions) (#134546) https://github.com/flutter/packages/compare/ef0c65ea4ccd...e04ba886a85e 2023-09-12 stuartmorgan@google.com [tool] Add a package inclusion filter (flutter/packages#4904) 2023-09-12 me@nils.re [flutter_markdown] Fix changelog regarding minimum supported SDK version (flutter/packages#4851) 2023-09-12 stuartmorgan@google.com [ios_platform_images] Add integration tests (flutter/packages#4899) 2023-09-12 robert@odrowaz.dev [image_picker] Copy exif tags in categories II and III (flutter/packages#4738) 2023-09-11 233583+mossmana@users.noreply.github.com [google_maps_flutter_android] Fix for testToggleInfoWindow persistently flaky (flutter/packages#4768) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index d1ae1a64d70a7..317d6304a6253 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -ef0c65ea4ccd83c41ec38ffaf8e4713ab2dbf3cb +e04ba886a85edfd4fcea794d0e06be062953d480 From ce39d01d520951b97ea19c3b375c55aa040d1ed4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 12:52:21 -0400 Subject: [PATCH 1218/1547] Roll Flutter Engine from 25be03186d82 to 8a8ddaeecf8a (1 revision) (#134545) https://github.com/flutter/engine/compare/25be03186d82...8a8ddaeecf8a 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from a1ff98bebf89 to 7e9b94634911 (2 revisions) (flutter/engine#45707) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5e77124decc26..64270da816acb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -25be03186d82699ad88758e944be4a287148af29 +8a8ddaeecf8aabf7fa60d17134781c008f2f5d3e From 90ae98f576424a738f047bad1f75d725c267a25d Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Tue, 12 Sep 2023 12:14:18 -0500 Subject: [PATCH 1219/1547] Remove deprecated TextSelectionOverlay.fadeDuration (#134485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of https://github.com/flutter/flutter/issues/133171 This was deprecated in https://github.com/flutter/flutter/pull/100381 Th replacement is to use `SelectionOverlay.fadeDuration` instead. This migration is supported by dart fix. ✠--- packages/flutter/lib/src/widgets/text_selection.dart | 7 ------- packages/flutter/test/widgets/text_selection_test.dart | 4 ---- 2 files changed, 11 deletions(-) diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index 12d780ca72c60..e805b572793dd 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -374,13 +374,6 @@ class TextSelectionOverlay { /// {@endtemplate} final BuildContext context; - /// Controls the fade-in and fade-out animations for the toolbar and handles. - @Deprecated( - 'Use `SelectionOverlay.fadeDuration` instead. ' - 'This feature was deprecated after v2.12.0-4.1.pre.' - ) - static const Duration fadeDuration = SelectionOverlay.fadeDuration; - // TODO(mpcomplete): what if the renderObject is removed or replaced, or // moves? Not sure what cases I need to handle, or how to handle them. /// The editable line in which the selected text is being displayed. diff --git a/packages/flutter/test/widgets/text_selection_test.dart b/packages/flutter/test/widgets/text_selection_test.dart index 67d49cb5e3272..b1b51f021a412 100644 --- a/packages/flutter/test/widgets/text_selection_test.dart +++ b/packages/flutter/test/widgets/text_selection_test.dart @@ -99,10 +99,6 @@ void main() { ); } - test('TextSelectionOverlay.fadeDuration exist', () async { - expect(TextSelectionOverlay.fadeDuration, SelectionOverlay.fadeDuration); - }); - testWidgets('a series of taps all call onTaps', (WidgetTester tester) async { await pumpGestureDetector(tester); await tester.tapAt(const Offset(200, 200)); From cba7daf3ce67930bcc5ba456f75d21aed681ca7e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 14:22:52 -0400 Subject: [PATCH 1220/1547] Roll Flutter Engine from 8a8ddaeecf8a to d4698c65aa8d (2 revisions) (#134553) https://github.com/flutter/engine/compare/8a8ddaeecf8a...d4698c65aa8d 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 7e9b94634911 to f3f0cab7efd0 (1 revision) (flutter/engine#45710) 2023-09-12 derekx@google.com Add trace-to-file switch (flutter/engine#45553) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 64270da816acb..ecfa349c5a423 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8a8ddaeecf8aabf7fa60d17134781c008f2f5d3e +d4698c65aa8d9e42d4aa70391c804270506a5f82 From 4e7a07af882c5d76d88fd458fa4b653c5e7a12fe Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Tue, 12 Sep 2023 13:23:52 -0500 Subject: [PATCH 1221/1547] Remove chip tooltip deprecations (#134486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of https://github.com/flutter/flutter/issues/133171 These deprecations were introduced in https://github.com/flutter/flutter/pull/96174 The replacement is to use `deleteButtonTooltipMessage`. This migration is supported by dart fix. ✠--- packages/flutter/lib/src/material/chip.dart | 38 +------------------ .../flutter/lib/src/material/input_chip.dart | 12 ------ packages/flutter/test/material/chip_test.dart | 27 ------------- 3 files changed, 2 insertions(+), 75 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index f158eb316db76..a91c94a45f066 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -279,16 +279,6 @@ abstract interface class DeletableChipAttributes { /// If null, the default [MaterialLocalizations.deleteButtonTooltip] will be /// used. String? get deleteButtonTooltipMessage; - - /// Whether to use a tooltip on the chip's delete button showing the - /// [deleteButtonTooltipMessage]. - /// - /// Defaults to true. - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - bool get useDeleteButtonTooltip; } /// An interface for Material Design chips that can have check marks. @@ -597,11 +587,6 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri this.shadowColor, this.surfaceTintColor, this.iconTheme, - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - this.useDeleteButtonTooltip = true, }) : assert(elevation == null || elevation >= 0.0); @override @@ -648,12 +633,6 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri final Color? surfaceTintColor; @override final IconThemeData? iconTheme; - @override - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - final bool useDeleteButtonTooltip; @override Widget build(BuildContext context) { @@ -666,7 +645,6 @@ class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttri deleteIcon: deleteIcon, onDeleted: onDeleted, deleteIconColor: deleteIconColor, - useDeleteButtonTooltip: useDeleteButtonTooltip, deleteButtonTooltipMessage: deleteButtonTooltipMessage, tapEnabled: false, side: side, @@ -771,11 +749,6 @@ class RawChip extends StatefulWidget this.showCheckmark, this.checkmarkColor, this.avatarBorder = const CircleBorder(), - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - this.useDeleteButtonTooltip = true, }) : assert(pressElevation == null || pressElevation >= 0.0), assert(elevation == null || elevation >= 0.0), deleteIcon = deleteIcon ?? _kDefaultDeleteIcon; @@ -855,12 +828,6 @@ class RawChip extends StatefulWidget final Color? checkmarkColor; @override final ShapeBorder avatarBorder; - @override - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - final bool useDeleteButtonTooltip; /// If set, this indicates that the chip should be disabled if all of the /// tap callbacks ([onSelected], [onPressed]) are null. @@ -1159,9 +1126,8 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid container: true, button: true, child: _wrapWithTooltip( - tooltip: widget.useDeleteButtonTooltip - ? widget.deleteButtonTooltipMessage ?? MaterialLocalizations.of(context).deleteButtonTooltip - : null, + tooltip: widget.deleteButtonTooltipMessage + ?? MaterialLocalizations.of(context).deleteButtonTooltip, enabled: widget.onDeleted != null, child: InkWell( // Radius should be slightly less than the full size of the chip. diff --git a/packages/flutter/lib/src/material/input_chip.dart b/packages/flutter/lib/src/material/input_chip.dart index e2146d14d481c..33a4bfd841d53 100644 --- a/packages/flutter/lib/src/material/input_chip.dart +++ b/packages/flutter/lib/src/material/input_chip.dart @@ -123,11 +123,6 @@ class InputChip extends StatelessWidget this.showCheckmark, this.checkmarkColor, this.avatarBorder = const CircleBorder(), - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - this.useDeleteButtonTooltip = true, }) : assert(pressElevation == null || pressElevation >= 0.0), assert(elevation == null || elevation >= 0.0); @@ -199,12 +194,6 @@ class InputChip extends StatelessWidget final ShapeBorder avatarBorder; @override final IconThemeData? iconTheme; - @override - @Deprecated( - 'Migrate to deleteButtonTooltipMessage. ' - 'This feature was deprecated after v2.10.0-0.3.pre.' - ) - final bool useDeleteButtonTooltip; @override Widget build(BuildContext context) { @@ -223,7 +212,6 @@ class InputChip extends StatelessWidget deleteIcon: resolvedDeleteIcon, onDeleted: onDeleted, deleteIconColor: deleteIconColor, - useDeleteButtonTooltip: useDeleteButtonTooltip, deleteButtonTooltipMessage: deleteButtonTooltipMessage, onSelected: onSelected, onPressed: onPressed, diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index e7708dd28c505..992bd5947b05c 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -138,7 +138,6 @@ Widget chipWithOptionalDeleteButton({ Key? labelKey, required bool deletable, TextDirection textDirection = TextDirection.ltr, - bool useDeleteButtonTooltip = true, String? chipTooltip, String? deleteButtonTooltipMessage, VoidCallback? onPressed = doNothing, @@ -154,7 +153,6 @@ Widget chipWithOptionalDeleteButton({ onPressed: onPressed, onDeleted: deletable ? doNothing : null, deleteIcon: Icon(Icons.close, key: deleteButtonKey), - useDeleteButtonTooltip: useDeleteButtonTooltip, deleteButtonTooltipMessage: deleteButtonTooltipMessage, label: Text( deletable @@ -3204,31 +3202,6 @@ void main() { expect(box.size, equals(const Size(128, 24.0 + 16.0))); }); - testWidgetsWithLeakTracking('Chip delete button tooltip can be disabled using useDeleteButtonTooltip', (WidgetTester tester) async { - await tester.pumpWidget( - chipWithOptionalDeleteButton( - deletable: true, - useDeleteButtonTooltip: false, - ), - ); - - // Tap at the delete icon of the chip, which is at the right side of the - // chip - final Offset topRightOfInkwell = tester.getTopLeft(find.byType(InkWell).first); - final Offset tapLocationOfDeleteButton = topRightOfInkwell + const Offset(8, 8); - final TestGesture tapGesture = await tester.startGesture(tapLocationOfDeleteButton); - - await tester.pump(); - - // Wait for some more time while pressing and holding the delete button - await tester.pumpAndSettle(); - - // There should be no delete button tooltip - expect(findTooltipContainer('Delete'), findsNothing); - - await tapGesture.up(); - }); - testWidgetsWithLeakTracking('Chip delete button tooltip is disabled if deleteButtonTooltipMessage is empty', (WidgetTester tester) async { final UniqueKey deleteButtonKey = UniqueKey(); await tester.pumpWidget( From b966b2beee640c56620ec90b34560860e45c18e8 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer <goderbauer@google.com> Date: Tue, 12 Sep 2023 11:29:00 -0700 Subject: [PATCH 1222/1547] Enable private field promotion for dev (#134480) New feature in upcoming Dart 3.2. See https://github.com/dart-lang/language/issues/2020. Feature is enabled by bumping the min SDK version to 3.2. Part of https://github.com/flutter/flutter/issues/134476. --- dev/automated_tests/pubspec.yaml | 2 +- dev/benchmarks/complex_layout/pubspec.yaml | 2 +- dev/benchmarks/macrobenchmarks/pubspec.yaml | 2 +- dev/benchmarks/microbenchmarks/pubspec.yaml | 2 +- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 2 +- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 2 +- dev/benchmarks/platform_views_layout/pubspec.yaml | 2 +- .../platform_views_layout_hybrid_composition/pubspec.yaml | 2 +- dev/benchmarks/test_apps/stocks/pubspec.yaml | 2 +- dev/bots/analyze_snippet_code.dart | 8 ++++---- dev/bots/pubspec.yaml | 2 +- dev/conductor/core/pubspec.yaml | 2 +- dev/customer_testing/pubspec.yaml | 2 +- dev/devicelab/bin/tasks/plugin_dependencies_test.dart | 2 +- dev/devicelab/pubspec.yaml | 2 +- dev/docs/platform_integration/pubspec.yaml | 2 +- dev/docs/renderers/pubspec.yaml | 2 +- dev/forbidden_from_release_tests/pubspec.yaml | 2 +- .../abstract_method_smoke_test/pubspec.yaml | 2 +- .../android_embedding_v2_smoke_test/pubspec.yaml | 2 +- .../android_semantics_testing/pubspec.yaml | 2 +- .../android_views/lib/motion_events_page.dart | 2 -- dev/integration_tests/android_views/pubspec.yaml | 2 +- dev/integration_tests/channels/pubspec.yaml | 2 +- .../deferred_components_test/pubspec.yaml | 2 +- dev/integration_tests/external_ui/pubspec.yaml | 2 +- dev/integration_tests/flavors/pubspec.yaml | 2 +- dev/integration_tests/flutter_gallery/pubspec.yaml | 2 +- .../gradle_deprecated_settings/pubspec.yaml | 2 +- dev/integration_tests/hybrid_android_views/pubspec.yaml | 2 +- .../ios_add2app_life_cycle/flutterapp/pubspec.yaml | 2 +- .../ios_app_with_extensions/pubspec.yaml | 2 +- .../ios_platform_view_tests/pubspec.yaml | 2 +- dev/integration_tests/non_nullable/pubspec.yaml | 2 +- dev/integration_tests/platform_interaction/pubspec.yaml | 2 +- dev/integration_tests/release_smoke_test/pubspec.yaml | 2 +- dev/integration_tests/spell_check/pubspec.yaml | 2 +- dev/integration_tests/ui/pubspec.yaml | 2 +- dev/integration_tests/web/pubspec.yaml | 2 +- dev/integration_tests/web_compile_tests/pubspec.yaml | 2 +- dev/integration_tests/web_e2e_tests/pubspec.yaml | 2 +- dev/integration_tests/wide_gamut_test/pubspec.yaml | 2 +- dev/integration_tests/windows_startup_test/pubspec.yaml | 2 +- dev/manual_tests/pubspec.yaml | 2 +- dev/missing_dependency_tests/pubspec.yaml | 2 +- dev/tools/create_api_docs.dart | 2 +- dev/tools/gen_defaults/pubspec.yaml | 2 +- dev/tools/gen_keycodes/pubspec.yaml | 2 +- dev/tools/pubspec.yaml | 2 +- dev/tools/vitool/pubspec.yaml | 2 +- 50 files changed, 52 insertions(+), 54 deletions(-) diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 41def19d314f0..7983b4afc9d05 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_automated_tests environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 3c92e17240663..a694b759c3a3c 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -2,7 +2,7 @@ name: complex_layout description: A benchmark of a relatively complex layout. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index b70543f137319..c01a06ccc1f38 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -2,7 +2,7 @@ name: macrobenchmarks description: Performance benchmarks using flutter drive. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index f53ac6c2edc34..dab505297d934 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -2,7 +2,7 @@ name: microbenchmarks description: Small benchmarks for very specific parts of the Flutter framework. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: meta: 1.9.1 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 7d2d5ddf5a46c..57c87babf7661 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -4,7 +4,7 @@ description: A module that is embedded in the multiple_flutters benchmark test. version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index 7f3c2c3ce7f72..1be876ebbbceb 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 582b150dade2f..602a685f3fa9d 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -2,7 +2,7 @@ name: platform_views_layout description: A benchmark for platform views. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 4a5cd0a1bc9ce..90323063f92c3 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -2,7 +2,7 @@ name: platform_views_layout_hybrid_composition description: A benchmark for platform views, using hybrid composition on android. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 6f28048bdd846..90f815e22a98f 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -1,7 +1,7 @@ name: stocks environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/bots/analyze_snippet_code.dart b/dev/bots/analyze_snippet_code.dart index b2bae35d7cdb3..924ae2a03efb5 100644 --- a/dev/bots/analyze_snippet_code.dart +++ b/dev/bots/analyze_snippet_code.dart @@ -515,14 +515,14 @@ class _SnippetChecker { /// Returns true if any errors are found, false otherwise. Future<bool> checkSnippets() async { final Map<String, _SnippetFile> snippets = <String, _SnippetFile>{}; - if (_dartUiLocation != null && !_dartUiLocation!.existsSync()) { - stderr.writeln('Unable to analyze engine dart snippets at ${_dartUiLocation!.path}.'); + if (_dartUiLocation != null && !_dartUiLocation.existsSync()) { + stderr.writeln('Unable to analyze engine dart snippets at ${_dartUiLocation.path}.'); } final List<File> filesToAnalyze = <File>[ for (final Directory flutterPackage in _flutterPackages) ..._listDartFiles(flutterPackage, recursive: true), - if (_dartUiLocation != null && _dartUiLocation!.existsSync()) - ..._listDartFiles(_dartUiLocation!, recursive: true), + if (_dartUiLocation != null && _dartUiLocation.existsSync()) + ..._listDartFiles(_dartUiLocation, recursive: true), ]; final Set<Object> errors = <Object>{}; errors.addAll(await _extractSnippets(filesToAnalyze, snippetMap: snippets)); diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 9962291e50eaa..42892499fa465 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -2,7 +2,7 @@ name: tests_on_bots description: Scripts which run on bots. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: args: 2.4.2 diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index b35162e04d1c1..d5cfab651b770 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -4,7 +4,7 @@ description: Flutter Automated Release Tool publish_to: none environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: archive: 3.3.2 diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index 57fb59f418ff5..ffafd00e3ab7a 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -2,7 +2,7 @@ name: customer_testing description: Tool to run the tests listed in the flutter/tests repository. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: args: 2.4.2 diff --git a/dev/devicelab/bin/tasks/plugin_dependencies_test.dart b/dev/devicelab/bin/tasks/plugin_dependencies_test.dart index da776743dbb5d..bf74614c3c544 100644 --- a/dev/devicelab/bin/tasks/plugin_dependencies_test.dart +++ b/dev/devicelab/bin/tasks/plugin_dependencies_test.dart @@ -101,7 +101,7 @@ dependencies: sdk: flutter environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: ">=1.5.0" ''', flush: true); diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 2a6eea6932fef..63be4031993d3 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter continuous integration performance and correctness tests. homepage: https://github.com/flutter/flutter environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: archive: 3.3.2 diff --git a/dev/docs/platform_integration/pubspec.yaml b/dev/docs/platform_integration/pubspec.yaml index 62caada10c640..ebe28969f054a 100644 --- a/dev/docs/platform_integration/pubspec.yaml +++ b/dev/docs/platform_integration/pubspec.yaml @@ -1,4 +1,4 @@ name: platform_integration environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' diff --git a/dev/docs/renderers/pubspec.yaml b/dev/docs/renderers/pubspec.yaml index fd0dff9f304d5..76bdb8ce03b0d 100644 --- a/dev/docs/renderers/pubspec.yaml +++ b/dev/docs/renderers/pubspec.yaml @@ -1,4 +1,4 @@ name: renderers environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index f2b7c096d1816..6244f6b3ce944 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -2,7 +2,7 @@ name: forbidden_from_release_tests publish_to: 'none' environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: args: 2.4.2 diff --git a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml index d86e14fd533a3..6105b6e5d1239 100644 --- a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml +++ b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml @@ -4,7 +4,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index dfc3dd210bcf4..824bef6aa9919 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -14,7 +14,7 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index cc08c524fe6bd..ffaa0525a1873 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -1,7 +1,7 @@ name: android_semantics_testing description: Integration testing library for Android semantics environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/android_views/lib/motion_events_page.dart b/dev/integration_tests/android_views/lib/motion_events_page.dart index 1b4f6cc6a2cbf..740aa6041f017 100644 --- a/dev/integration_tests/android_views/lib/motion_events_page.dart +++ b/dev/integration_tests/android_views/lib/motion_events_page.dart @@ -236,7 +236,6 @@ class MotionEventsBodyState extends State<MotionEventsBody> { flutterViewEvents.removeLast(); } setState(() {}); - break; } return Future<dynamic>.value(); } @@ -250,7 +249,6 @@ class MotionEventsBodyState extends State<MotionEventsBody> { embeddedViewEvents.removeLast(); } setState(() {}); - break; } return Future<dynamic>.value(); } diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 4ee8988c6c649..5abef88592677 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none description: An integration test for embedded platform views version: 1.0.0+1 environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index f723a63eff1d5..fdaca2cd1d168 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -2,7 +2,7 @@ name: channels description: Integration test for platform channels. environment: - sdk: '>=2.19.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 1cd454e2d587d..41f8fa7057cbd 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -3,7 +3,7 @@ description: Integration test application for basic deferred components function publish_to: 'none' version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index e30c4b321f7fb..fadfda2ad9135 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -2,7 +2,7 @@ name: external_ui description: A test of Flutter integrating external UIs. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 6207732e290a8..295014a784bc4 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -2,7 +2,7 @@ name: flavors description: Integration test for build flavors. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 84d60886280b8..445a0a32bb614 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_gallery environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 5688086b8231e..f2d670c9424c5 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -2,7 +2,7 @@ name: gradle_deprecated_settings description: Integration test for the current settings.gradle. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index fd6513579c67c..ea6f2bc1f0b84 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -4,7 +4,7 @@ publish_to: none description: An integration test for hybrid composition on Android version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index 698feeebb8bb9..cb719011ebb1d 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -14,7 +14,7 @@ description: A new flutter module project. version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index 784d8671ca485..bcffc6b087ece 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -13,7 +13,7 @@ name: ios_app_with_extensions version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 53a17125a512b..146809226c998 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -3,7 +3,7 @@ name: ios_platform_view_tests version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index bd7361e39858e..74984d2002f3f 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 802efe254f322..a842b975026e6 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -2,7 +2,7 @@ name: platform_interaction description: Integration test for platform interactions. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 184cb2bd40da3..e250a1ebe52cc 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -1,7 +1,7 @@ name: release_smoke_test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index 116124abacc4d..cf81a0a1c533b 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 41a22b1055c72..f5b3d7876e39a 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -2,7 +2,7 @@ name: integration_ui description: Flutter non-plugin UI integration tests. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index b8a0604b50ba9..9b90e3aaa2b42 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -2,7 +2,7 @@ name: web_integration description: Integration test for web compilation. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: assets: diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index cc4bd2c9612b7..f9e9ed8d4131b 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -1,6 +1,6 @@ name: web_compile_tests environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 6c5dd1db4b61d..b48834f447a60 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -2,7 +2,7 @@ name: web_e2e_tests publish_to: none environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: assets: diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index 357ce19f799e7..7177e44a09df8 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -5,7 +5,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 5185ec88806c2..15424e16b06c5 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -2,7 +2,7 @@ name: windows_startup_test description: Integration test for Windows app's startup. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 68e63d7b2a28c..8d552b3a502fb 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -1,7 +1,7 @@ name: manual_tests environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/missing_dependency_tests/pubspec.yaml b/dev/missing_dependency_tests/pubspec.yaml index a322c188f3ee5..6499f49c5f8a1 100644 --- a/dev/missing_dependency_tests/pubspec.yaml +++ b/dev/missing_dependency_tests/pubspec.yaml @@ -1,7 +1,7 @@ name: missing_dependency_tests environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index cbc021e956e84..87c556e98a612 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -250,7 +250,7 @@ class Configurator { 'homepage: https://flutter.dev', 'version: 0.0.0', 'environment:', - " sdk: '>=3.0.0-0 <4.0.0'", + " sdk: '>=3.2.0-0 <4.0.0'", 'dependencies:', for (final String package in findPackageNames(filesystem)) ' $package:\n sdk: flutter', ' $kPlatformIntegrationPackageName: 0.0.1', diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index c4acf48f8d8fe..77c781054e3fe 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -3,7 +3,7 @@ description: A command line script to generate Material component defaults from version: 1.0.0 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: args: 2.4.2 diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index e8843db6e0f6b..049ada19f7815 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -2,7 +2,7 @@ name: gen_keycodes description: Generates keycode source files from various resources. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: args: 2.4.2 diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 80787353f9be9..95c68bfe19c74 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -2,7 +2,7 @@ name: dev_tools description: Various repository development tools for flutter. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: archive: 3.3.2 diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 657239e9c16fd..18ffb4f4b611e 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.1 homepage: https://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: From 64c1223b9cf4e2df65d72a14e9c72df47d786a96 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Tue, 12 Sep 2023 11:29:02 -0700 Subject: [PATCH 1223/1547] Retry Linux web tests 1 time on roll presubmit (#134552) A flake in this shard caused an engine roll to fail here https://github.com/flutter/flutter/pull/134526 --- .ci.yaml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 3ccd3707a56bb..7e1d3e5b05964 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1140,6 +1140,8 @@ targets: subshard: "1_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1160,6 +1162,8 @@ targets: subshard: "2_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1180,6 +1184,8 @@ targets: subshard: "3_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1200,6 +1206,8 @@ targets: subshard: "4_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1220,6 +1228,8 @@ targets: subshard: "5_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1240,6 +1250,8 @@ targets: subshard: "0" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1260,6 +1272,8 @@ targets: subshard: "1" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1280,6 +1294,8 @@ targets: subshard: "2" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1300,6 +1316,8 @@ targets: subshard: "3" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1320,6 +1338,8 @@ targets: subshard: "4" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1340,6 +1360,8 @@ targets: subshard: "5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1360,6 +1382,8 @@ targets: subshard: "6" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1380,6 +1404,8 @@ targets: subshard: "7_last" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1400,6 +1426,8 @@ targets: subshard: "0" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1420,6 +1448,8 @@ targets: subshard: "1" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1440,6 +1470,8 @@ targets: subshard: "2" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1460,6 +1492,8 @@ targets: subshard: "3" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1480,6 +1514,8 @@ targets: subshard: "4" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1500,6 +1536,8 @@ targets: subshard: "5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1520,6 +1558,8 @@ targets: subshard: "6" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1540,6 +1580,8 @@ targets: subshard: "7_last" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1561,6 +1603,8 @@ targets: subshard: "1_1" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/flutter_tools/** From 05733402f77d274ed8e5e2a201eaf1ddd8ecd58f Mon Sep 17 00:00:00 2001 From: Michael Goderbauer <goderbauer@google.com> Date: Tue, 12 Sep 2023 11:42:01 -0700 Subject: [PATCH 1224/1547] Enable private field promotion for examples (#134478) New feature in upcoming Dart 3.2. See https://github.com/dart-lang/language/issues/2020. Feature is enabled by bumping the min SDK version to 3.2. In these packages, no private fields were found to be promotable. Part of https://github.com/flutter/flutter/issues/134476. --- examples/api/pubspec.yaml | 2 +- examples/flutter_view/pubspec.yaml | 2 +- examples/hello_world/pubspec.yaml | 2 +- examples/image_list/pubspec.yaml | 2 +- examples/layers/pubspec.yaml | 2 +- examples/platform_channel/pubspec.yaml | 2 +- examples/platform_channel_swift/pubspec.yaml | 2 +- examples/platform_view/pubspec.yaml | 2 +- examples/splash/pubspec.yaml | 2 +- examples/texture/pubspec.yaml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 3c5756d671a17..630181e7f7a6f 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -7,7 +7,7 @@ publish_to: 'none' version: 1.0.0 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: ">=2.5.0-6.0.pre.30 <3.0.0" dependencies: diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index c60c5f2cdbcd8..68e8b23a86289 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_view description: A new flutter project. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index e96704b784ae2..3cf792dae6753 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -1,7 +1,7 @@ name: hello_world environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index a52f0df8f06f3..e3fab334ea232 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -4,7 +4,7 @@ description: Simple Flutter project used for benchmarking image loading over net version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index ab1ffaef8d2b1..e4c2f9d8740d8 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_examples_layers environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 32d58e5607a9c..20e34a60266cc 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -1,7 +1,7 @@ name: platform_channel environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 35567bbf0cbd9..7f70178476f82 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -1,7 +1,7 @@ name: platform_channel_swift environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index c1bc2cbf392d8..663dc5ae94243 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -1,7 +1,7 @@ name: platform_view environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index a9f123f19594f..618f6eed651c3 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -1,7 +1,7 @@ name: splash environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index abd4a71675956..d2b513e317af9 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -1,7 +1,7 @@ name: texture environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: From 240825a555900d177fc1460f48f7c11d79412758 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer <goderbauer@google.com> Date: Tue, 12 Sep 2023 13:20:04 -0700 Subject: [PATCH 1225/1547] Enable private field promotion for flutter_tools (#134474) New feature in upcoming Dart 3.2. See https://github.com/dart-lang/language/issues/2020. Feature is enabled by bumping the min SDK version to 3.2. Part of https://github.com/flutter/flutter/issues/134476. --- .../src/android/android_device_discovery.dart | 4 +-- .../lib/src/android/android_emulator.dart | 2 +- .../lib/src/android/android_workflow.dart | 24 ++++++++-------- ...studio_java_gradle_conflict_migration.dart | 4 +-- .../flutter_tools/lib/src/base/context.dart | 2 +- packages/flutter_tools/lib/src/cache.dart | 2 +- .../lib/src/commands/attach.dart | 2 +- .../lib/src/commands/update_packages.dart | 4 +-- packages/flutter_tools/lib/src/device.dart | 2 +- .../lib/src/ios/application_package.dart | 4 +-- .../lib/src/resident_devtools_handler.dart | 18 ++++++------ .../lib/src/resident_runner.dart | 2 +- .../lib/src/windows/visual_studio.dart | 4 +-- packages/flutter_tools/pubspec.yaml | 2 +- .../hermetic/analyze_continuously_test.dart | 2 +- .../hermetic/generate_localizations_test.dart | 4 +-- .../hermetic/update_packages_test.dart | 4 +-- .../test/data/asset_test/font/pubspec.yaml | 2 +- .../test/data/asset_test/main/pubspec.yaml | 2 +- .../build_system/build_system_test.dart | 2 +- .../targets/dart_plugin_registrant_test.dart | 2 +- .../test/test_compiler_test.dart | 2 +- .../general.shard/update_packages_test.dart | 6 ++-- .../integration.shard/analyze_once_test.dart | 2 +- .../break_on_framework_exceptions_test.dart | 2 +- .../test_data/background_project.dart | 4 +-- .../test_data/basic_project.dart | 10 +++---- .../test_data/compile_error_project.dart | 2 +- .../deferred_components_project.dart | 2 +- .../test_data/gen_l10n_project.dart | 2 +- .../test_data/hot_reload_const_project.dart | 2 +- .../test_data/hot_reload_project.dart | 2 +- .../test_data/hot_reload_with_asset.dart | 2 +- .../test_data/integration_tests_project.dart | 2 +- .../test_data/migrate_project.dart | 2 +- .../test_data/multidex_project.dart | 2 +- .../test_data/project_with_early_error.dart | 2 +- .../test_data/stateless_stateful_project.dart | 2 +- .../test_data/stepping_project.dart | 4 +-- .../test_data/test_project.dart | 2 +- .../test_data/tests_project.dart | 2 +- .../test/src/fake_http_client.dart | 2 +- .../test/src/fake_process_manager.dart | 2 +- packages/flutter_tools/test/src/io.dart | 28 +++++++++---------- .../test/src/test_build_system.dart | 12 ++++---- packages/flutter_tools/test/src/testbed.dart | 2 +- 46 files changed, 98 insertions(+), 98 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/android_device_discovery.dart b/packages/flutter_tools/lib/src/android/android_device_discovery.dart index c9655a11e9fab..1a5dd74d7dcaf 100644 --- a/packages/flutter_tools/lib/src/android/android_device_discovery.dart +++ b/packages/flutter_tools/lib/src/android/android_device_discovery.dart @@ -105,8 +105,8 @@ class AndroidDevices extends PollingDeviceDiscovery { bool _doesNotHaveAdb() { return _androidSdk == null || - _androidSdk?.adbPath == null || - !_processManager.canRun(_androidSdk!.adbPath); + _androidSdk.adbPath == null || + !_processManager.canRun(_androidSdk.adbPath); } // 015d172c98400a03 device usb:340787200X product:nakasi model:Nexus_7 device:grouper diff --git a/packages/flutter_tools/lib/src/android/android_emulator.dart b/packages/flutter_tools/lib/src/android/android_emulator.dart index 204bc12a5fd83..bb92bb5be9aba 100644 --- a/packages/flutter_tools/lib/src/android/android_emulator.dart +++ b/packages/flutter_tools/lib/src/android/android_emulator.dart @@ -141,7 +141,7 @@ class AndroidEmulator extends Emulator { @override PlatformType get platformType => PlatformType.android; - String? _prop(String name) => _properties != null ? _properties![name] : null; + String? _prop(String name) => _properties != null ? _properties[name] : null; @override Future<void> launch({@visibleForTesting Duration? startupDuration, bool coldBoot = false}) async { diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart index 40b96eb33056b..8bc53d099b7c5 100644 --- a/packages/flutter_tools/lib/src/android/android_workflow.dart +++ b/packages/flutter_tools/lib/src/android/android_workflow.dart @@ -53,12 +53,12 @@ class AndroidWorkflow implements Workflow { @override bool get canListDevices => appliesToHostPlatform && _androidSdk != null - && _androidSdk?.adbPath != null; + && _androidSdk.adbPath != null; @override bool get canLaunchDevices => appliesToHostPlatform && _androidSdk != null - && _androidSdk?.adbPath != null - && (_androidSdk?.validateSdkWellFormed().isEmpty ?? false); + && _androidSdk.adbPath != null + && _androidSdk.validateSdkWellFormed().isEmpty; @override bool get canListEmulators => canListDevices && _androidSdk?.emulatorPath != null; @@ -105,13 +105,13 @@ class AndroidValidator extends DoctorValidator { return false; } messages.add(ValidationMessage(_userMessages.androidJdkLocation(_java!.binaryPath))); - if (!_java!.canRun()) { - messages.add(ValidationMessage.error(_userMessages.androidCantRunJavaBinary(_java!.binaryPath))); + if (!_java.canRun()) { + messages.add(ValidationMessage.error(_userMessages.androidCantRunJavaBinary(_java.binaryPath))); return false; } Version? javaVersion; try { - javaVersion = _java!.version; + javaVersion = _java.version; } on Exception catch (error) { _logger.printTrace(error.toString()); } @@ -253,13 +253,13 @@ class AndroidLicenseValidator extends DoctorValidator { final List<ValidationMessage> messages = <ValidationMessage>[]; // Match pre-existing early termination behavior - if (_androidSdk == null || _androidSdk?.latestVersion == null || - _androidSdk!.validateSdkWellFormed().isNotEmpty || + if (_androidSdk == null || _androidSdk.latestVersion == null || + _androidSdk.validateSdkWellFormed().isNotEmpty || ! await _checkJavaVersionNoOutput()) { return ValidationResult(ValidationType.missing, messages); } - final String sdkVersionText = _userMessages.androidStatusInfo(_androidSdk!.latestVersion!.buildToolsVersionName); + final String sdkVersionText = _userMessages.androidStatusInfo(_androidSdk.latestVersion!.buildToolsVersionName); // Check for licenses. switch (await licensesAccepted) { @@ -371,7 +371,7 @@ class AndroidLicenseValidator extends DoctorValidator { try { final Process process = await _processManager.start( - <String>[_androidSdk!.sdkManagerPath!, '--licenses'], + <String>[_androidSdk.sdkManagerPath!, '--licenses'], environment: _java?.environment, ); @@ -404,7 +404,7 @@ class AndroidLicenseValidator extends DoctorValidator { final int exitCode = await process.exitCode; if (exitCode != 0) { throwToolExit(_userMessages.androidCannotRunSdkManager( - _androidSdk?.sdkManagerPath ?? '', + _androidSdk.sdkManagerPath ?? '', 'exited code $exitCode', _platform, )); @@ -412,7 +412,7 @@ class AndroidLicenseValidator extends DoctorValidator { return true; } on ProcessException catch (e) { throwToolExit(_userMessages.androidCannotRunSdkManager( - _androidSdk?.sdkManagerPath ?? '', + _androidSdk.sdkManagerPath ?? '', e.toString(), _platform, )); diff --git a/packages/flutter_tools/lib/src/android/migrations/android_studio_java_gradle_conflict_migration.dart b/packages/flutter_tools/lib/src/android/migrations/android_studio_java_gradle_conflict_migration.dart index 0a8307171336f..b8d4888370121 100644 --- a/packages/flutter_tools/lib/src/android/migrations/android_studio_java_gradle_conflict_migration.dart +++ b/packages/flutter_tools/lib/src/android/migrations/android_studio_java_gradle_conflict_migration.dart @@ -91,10 +91,10 @@ class AndroidStudioJavaGradleConflictMigration extends ProjectMigrator { return; } - if (_androidStudio == null || _androidStudio!.version == null) { + if (_androidStudio == null || _androidStudio.version == null) { logger.printTrace(androidStudioNotFound); return; - } else if (_androidStudio!.version!.major < androidStudioFlamingo.major) { + } else if (_androidStudio.version!.major < androidStudioFlamingo.major) { logger.printTrace(androidStudioVersionBelowFlamingo); return; } diff --git a/packages/flutter_tools/lib/src/base/context.dart b/packages/flutter_tools/lib/src/base/context.dart index ebf2333dfdc8f..bcd1ed2545361 100644 --- a/packages/flutter_tools/lib/src/base/context.dart +++ b/packages/flutter_tools/lib/src/base/context.dart @@ -116,7 +116,7 @@ class AppContext { T? get<T>() { dynamic value = _generateIfNecessary(T, _overrides); if (value == null && _parent != null) { - value = _parent!.get<T>(); + value = _parent.get<T>(); } return _unboxNull(value ?? _generateIfNecessary(T, _fallbacks)) as T?; } diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 7cfa8ce22fec2..5a03827cb3ecd 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -558,7 +558,7 @@ class Cache { /// Return the top-level directory in the cache; this is `bin/cache`. Directory getRoot() { if (_rootOverride != null) { - return _fileSystem.directory(_fileSystem.path.join(_rootOverride!.path, 'bin', 'cache')); + return _fileSystem.directory(_fileSystem.path.join(_rootOverride.path, 'bin', 'cache')); } else { return _fileSystem.directory(_fileSystem.path.join(flutterRoot!, 'bin', 'cache')); } diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 303f6e6676b94..dfcd365d4098c 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -277,7 +277,7 @@ known, it can be explicitly provided to attach via the command-line, e.g. logger: _logger, ), notifyingLogger: (_logger is NotifyingLogger) - ? _logger as NotifyingLogger + ? _logger : NotifyingLogger(verbose: _logger.isVerbose, parent: _logger), logToStdout: true, ) diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 5d240051fba88..4a060dc728c96 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -1753,7 +1753,7 @@ Directory createTemporaryFlutterSdk( // Fill in SDK dependency constraint. output.write(''' environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' '''); output.writeln('dependencies:'); @@ -1785,7 +1785,7 @@ description: Dart SDK extensions for dart:ui homepage: http://flutter.io # sky_engine requires sdk_ext support in the analyzer which was added in 1.11.x environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' '''); return directory; diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index c601c543d0329..aecf35a70b38e 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -393,7 +393,7 @@ class DeviceDiscoverySupportFilter { if (_flutterProject == null) { return true; } - return device.isSupportedForProject(_flutterProject!); + return device.isSupportedForProject(_flutterProject); } } diff --git a/packages/flutter_tools/lib/src/ios/application_package.dart b/packages/flutter_tools/lib/src/ios/application_package.dart index c760492cd4746..5472bb6d1fcd8 100644 --- a/packages/flutter_tools/lib/src/ios/application_package.dart +++ b/packages/flutter_tools/lib/src/ios/application_package.dart @@ -141,7 +141,7 @@ class BuildableIOSApp extends IOSApp { // not a top-level output directory. // Specifying `build/ios/archive/Runner` will result in `build/ios/archive/Runner.xcarchive`. String get archiveBundlePath => globals.fs.path.join(getIosBuildDirectory(), 'archive', - _hostAppBundleName == null ? 'Runner' : globals.fs.path.withoutExtension(_hostAppBundleName!)); + _hostAppBundleName == null ? 'Runner' : globals.fs.path.withoutExtension(_hostAppBundleName)); // The output xcarchive bundle path `build/ios/archive/Runner.xcarchive`. String get archiveBundleOutputPath => @@ -150,7 +150,7 @@ class BuildableIOSApp extends IOSApp { String get builtInfoPlistPathAfterArchive => globals.fs.path.join(archiveBundleOutputPath, 'Products', 'Applications', - _hostAppBundleName == null ? 'Runner.app' : _hostAppBundleName!, + _hostAppBundleName ?? 'Runner.app', 'Info.plist'); String get projectAppIconDirName => _projectImageAssetDirName(_appIconAsset); diff --git a/packages/flutter_tools/lib/src/resident_devtools_handler.dart b/packages/flutter_tools/lib/src/resident_devtools_handler.dart index 3b7521480fa83..5eac9320ac090 100644 --- a/packages/flutter_tools/lib/src/resident_devtools_handler.dart +++ b/packages/flutter_tools/lib/src/resident_devtools_handler.dart @@ -79,19 +79,19 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { return; } if (devToolsServerAddress != null) { - _devToolsLauncher!.devToolsUrl = devToolsServerAddress; + _devToolsLauncher.devToolsUrl = devToolsServerAddress; } else { - await _devToolsLauncher!.serve(); + await _devToolsLauncher.serve(); _served = true; } - await _devToolsLauncher!.ready; + await _devToolsLauncher.ready; // Do not attempt to print debugger list if the connection has failed or if we're shutting down. - if (_devToolsLauncher!.activeDevToolsServer == null || _shutdown) { + if (_devToolsLauncher.activeDevToolsServer == null || _shutdown) { assert(!_readyToAnnounce); return; } - final Uri? devToolsUrl = _devToolsLauncher!.devToolsUrl; + final Uri? devToolsUrl = _devToolsLauncher.devToolsUrl; if (devToolsUrl != null) { for (final FlutterDevice? device in flutterDevices) { if (device == null) { @@ -130,7 +130,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { } _readyToAnnounce = true; - assert(_devToolsLauncher!.activeDevToolsServer != null); + assert(_devToolsLauncher.activeDevToolsServer != null); if (_residentRunner.reportedDebuggers) { // Since the DevTools only just became available, we haven't had a chance to // report their URLs yet. Do so now. @@ -148,9 +148,9 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { if (!_residentRunner.supportsServiceProtocol || _devToolsLauncher == null) { return false; } - if (_devToolsLauncher!.devToolsUrl == null) { + if (_devToolsLauncher.devToolsUrl == null) { _logger.startProgress('Waiting for Flutter DevTools to be served...'); - unawaited(_devToolsLauncher!.ready.then((_) { + unawaited(_devToolsLauncher.ready.then((_) { _launchDevToolsForDevices(flutterDevices); })); } else { @@ -294,7 +294,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler { } _shutdown = true; _readyToAnnounce = false; - await _devToolsLauncher!.close(); + await _devToolsLauncher.close(); } } diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index ec1d2f4e60605..00ae359d634b6 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -1690,7 +1690,7 @@ class TerminalHandler { _addSignalHandler(io.ProcessSignal.sigusr2, _handleSignal); if (_pidFile != null) { _logger.printTrace('Writing pid to: $_pidFile'); - _actualPidFile = _processInfo.writePidFile(_pidFile!); + _actualPidFile = _processInfo.writePidFile(_pidFile); } } } diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart index c1c6cf9f35a3c..e9c39aa2fa4db 100644 --- a/packages/flutter_tools/lib/src/windows/visual_studio.dart +++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart @@ -81,7 +81,7 @@ class VisualStudio { if (_bestVisualStudioDetails == null) { return false; } - return _bestVisualStudioDetails!.isComplete ?? true; + return _bestVisualStudioDetails.isComplete ?? true; } /// True if Visual Studio is launchable. @@ -91,7 +91,7 @@ class VisualStudio { if (_bestVisualStudioDetails == null) { return false; } - return _bestVisualStudioDetails!.isLaunchable ?? true; + return _bestVisualStudioDetails.isLaunchable ?? true; } /// True if the Visual Studio installation is a pre-release version. diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 942598884bf24..7af5c077c77ca 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -3,7 +3,7 @@ description: Tools for building Flutter applications homepage: https://flutter.dev environment: - sdk: '>=3.0.0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart index ece77ecc4b088..adfbf616176fc 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart @@ -60,7 +60,7 @@ void main() { pubspecFile.writeAsStringSync(''' name: foo_project environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' '''); final File dartFile = fileSystem.file(fileSystem.path.join(directory.path, 'lib', 'main.dart')); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart index 263254ddc8bdd..4c43876481e86 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart @@ -427,7 +427,7 @@ format: true pubspecFile.writeAsStringSync(''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: @@ -466,7 +466,7 @@ format: true pubspecFile.writeAsStringSync(''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart index 7e75ca9bfbb0a..7ca7ca01489a3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/update_packages_test.dart @@ -23,7 +23,7 @@ description: A framework for writing Flutter applications homepage: http://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". @@ -60,7 +60,7 @@ homepage: http://flutter.dev version: 1.0.0 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: ">=2.5.0-6.0.pre.30 <3.0.0" dependencies: diff --git a/packages/flutter_tools/test/data/asset_test/font/pubspec.yaml b/packages/flutter_tools/test/data/asset_test/font/pubspec.yaml index 4408e2ac59587..c16803941d9ba 100644 --- a/packages/flutter_tools/test/data/asset_test/font/pubspec.yaml +++ b/packages/flutter_tools/test/data/asset_test/font/pubspec.yaml @@ -2,7 +2,7 @@ name: font description: A test project that contains a font. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: uses-material-design: true diff --git a/packages/flutter_tools/test/data/asset_test/main/pubspec.yaml b/packages/flutter_tools/test/data/asset_test/main/pubspec.yaml index 8611c6daa8545..3cbb5d3994711 100644 --- a/packages/flutter_tools/test/data/asset_test/main/pubspec.yaml +++ b/packages/flutter_tools/test/data/asset_test/main/pubspec.yaml @@ -2,7 +2,7 @@ name: main description: A test project that has a package with a font as a dependency. environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: font: diff --git a/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart b/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart index c5bd533f12712..22bfa2ae942de 100644 --- a/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/build_system_test.dart @@ -701,7 +701,7 @@ class TestTarget extends Target { @override bool canSkip(Environment environment) { if (_canSkip != null) { - return _canSkip!(environment); + return _canSkip(environment); } return super.canSkip(environment); } diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart index 7c78b96eb89f7..bee12ddd04c68 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/dart_plugin_registrant_test.dart @@ -86,7 +86,7 @@ flutter: pluginClass: none environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: ">=1.20.0" '''; diff --git a/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart b/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart index 429e94890d743..58b8f2f3a4cde 100644 --- a/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart +++ b/packages/flutter_tools/test/general.shard/test/test_compiler_test.dart @@ -166,7 +166,7 @@ flutter: linux: dartPluginClass: APlugin environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: ">=2.5.0" '''); diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index b92fe6b15a40e..9741eb48d11e4 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -17,7 +17,7 @@ description: A framework for writing Flutter applications homepage: http://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". @@ -51,7 +51,7 @@ description: A dummy pubspec with no dependencies homepage: http://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' '''; const String kInvalidGitPubspec = ''' @@ -60,7 +60,7 @@ description: A framework for writing Flutter applications homepage: http://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter_tools/test/integration.shard/analyze_once_test.dart b/packages/flutter_tools/test/integration.shard/analyze_once_test.dart index 6c993dd0dae46..b9588a5555624 100644 --- a/packages/flutter_tools/test/integration.shard/analyze_once_test.dart +++ b/packages/flutter_tools/test/integration.shard/analyze_once_test.dart @@ -481,7 +481,7 @@ class _MyHomePageState extends State<MyHomePage> { const String pubspecYamlSrc = r''' name: flutter_project environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/break_on_framework_exceptions_test.dart b/packages/flutter_tools/test/integration.shard/break_on_framework_exceptions_test.dart index d9419765f3ec6..ea59152b81ecd 100644 --- a/packages/flutter_tools/test/integration.shard/break_on_framework_exceptions_test.dart +++ b/packages/flutter_tools/test/integration.shard/break_on_framework_exceptions_test.dart @@ -637,7 +637,7 @@ class TestProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/background_project.dart b/packages/flutter_tools/test/integration.shard/test_data/background_project.dart index 783004b55e674..fea73341f67b7 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/background_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/background_project.dart @@ -12,7 +12,7 @@ class BackgroundProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: @@ -63,7 +63,7 @@ class RepeatingBackgroundProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart b/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart index 93a2d090cf275..7db831fcf685a 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/basic_project.dart @@ -10,7 +10,7 @@ class BasicProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: @@ -63,7 +63,7 @@ class BasicProjectThatThrows extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: @@ -120,7 +120,7 @@ class BasicProjectWithTimelineTraces extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: @@ -169,7 +169,7 @@ class BasicProjectWithFlutterGen extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: @@ -194,7 +194,7 @@ class BasicProjectWithUnaryMain extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: sdk: flutter diff --git a/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart b/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart index 3232d7f44c76d..879c7f66b938a 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/compile_error_project.dart @@ -10,7 +10,7 @@ class CompileErrorProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart index fb59d2aa65406..927cd4e457df4 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart @@ -13,7 +13,7 @@ class DeferredComponentsProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart b/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart index 68cc153f92fe9..3444979b77dcd 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/gen_l10n_project.dart @@ -34,7 +34,7 @@ class GenL10nProject extends Project { final String pubspec = ''' name: test_l10n_project environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_const_project.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_const_project.dart index 355919fd90415..f51e2d8defa49 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_const_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_const_project.dart @@ -10,7 +10,7 @@ class HotReloadConstProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart index 7e188c0b2608a..643832696e110 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_project.dart @@ -12,7 +12,7 @@ class HotReloadProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart index 27d3665968d02..4c2f8950aaf8e 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/hot_reload_with_asset.dart @@ -10,7 +10,7 @@ class HotReloadWithAssetProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart b/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart index a67f1bbc900ef..62a1313170d27 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/integration_tests_project.dart @@ -14,7 +14,7 @@ class IntegrationTestsProject extends Project implements TestsProject { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/migrate_project.dart b/packages/flutter_tools/test/integration.shard/test_data/migrate_project.dart index d4a3ca385986d..a5d6d77c5c55a 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/migrate_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/migrate_project.dart @@ -175,7 +175,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart index ea958e983ce9e..f5e245b426f0b 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart @@ -38,7 +38,7 @@ class MultidexProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/project_with_early_error.dart b/packages/flutter_tools/test/integration.shard/test_data/project_with_early_error.dart index 6d37629f4c365..7ab284fcf2200 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/project_with_early_error.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/project_with_early_error.dart @@ -10,7 +10,7 @@ class ProjectWithEarlyError extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/stateless_stateful_project.dart b/packages/flutter_tools/test/integration.shard/test_data/stateless_stateful_project.dart index ecf1834be50cc..a8a8232870f7b 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/stateless_stateful_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/stateless_stateful_project.dart @@ -10,7 +10,7 @@ class HotReloadProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart b/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart index 87bc6a29c8129..9eb8e1325f384 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart @@ -9,7 +9,7 @@ class SteppingProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: sdk: flutter @@ -65,7 +65,7 @@ class WebSteppingProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: sdk: flutter diff --git a/packages/flutter_tools/test/integration.shard/test_data/test_project.dart b/packages/flutter_tools/test/integration.shard/test_data/test_project.dart index 436a86e009974..a87386ebc1a5f 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/test_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/test_project.dart @@ -10,7 +10,7 @@ class TestProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/integration.shard/test_data/tests_project.dart b/packages/flutter_tools/test/integration.shard/test_data/tests_project.dart index 45ee250104a30..2f7390d9f5fbc 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/tests_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/tests_project.dart @@ -13,7 +13,7 @@ class TestsProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/flutter_tools/test/src/fake_http_client.dart b/packages/flutter_tools/test/src/fake_http_client.dart index eea9b6ae9cd89..b30074274b411 100644 --- a/packages/flutter_tools/test/src/fake_http_client.dart +++ b/packages/flutter_tools/test/src/fake_http_client.dart @@ -341,7 +341,7 @@ class _FakeHttpClientRequest implements HttpClientRequest { }); await completer.future; if (_responseError != null) { - return Future<HttpClientResponse>.error(_responseError!); + return Future<HttpClientResponse>.error(_responseError); } return _FakeHttpClientResponse(_response); } diff --git a/packages/flutter_tools/test/src/fake_process_manager.dart b/packages/flutter_tools/test/src/fake_process_manager.dart index 5486b959e5698..427f19a5233ac 100644 --- a/packages/flutter_tools/test/src/fake_process_manager.dart +++ b/packages/flutter_tools/test/src/fake_process_manager.dart @@ -401,7 +401,7 @@ abstract class FakeProcessManager implements ProcessManager { return false; } if (fakeProcess._completer != null) { - fakeProcess._completer!.complete(); + fakeProcess._completer.complete(); } return true; } diff --git a/packages/flutter_tools/test/src/io.dart b/packages/flutter_tools/test/src/io.dart index 43cf2689e4b1f..db4eb37e7fc33 100644 --- a/packages/flutter_tools/test/src/io.dart +++ b/packages/flutter_tools/test/src/io.dart @@ -27,7 +27,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.createDirectory(path); } - return _fileSystemDelegate!.directory(path); + return _fileSystemDelegate.directory(path); } @override @@ -35,7 +35,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.createFile(path); } - return _fileSystemDelegate!.file(path); + return _fileSystemDelegate.file(path); } @override @@ -43,7 +43,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.createLink(path); } - return _fileSystemDelegate!.link(path); + return _fileSystemDelegate.link(path); } @override @@ -51,7 +51,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.fsWatch(path, events, recursive); } - return _fileSystemDelegate!.file(path).watch(events: events, recursive: recursive); + return _fileSystemDelegate.file(path).watch(events: events, recursive: recursive); } @override @@ -59,7 +59,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.fsWatchIsSupported(); } - return _fileSystemDelegate!.isWatchSupported; + return _fileSystemDelegate.isWatchSupported; } @override @@ -67,7 +67,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.fseGetType(path, followLinks); } - return _fileSystemDelegate!.type(path, followLinks: followLinks); + return _fileSystemDelegate.type(path, followLinks: followLinks); } @override @@ -75,7 +75,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.fseGetTypeSync(path, followLinks); } - return _fileSystemDelegate!.typeSync(path, followLinks: followLinks); + return _fileSystemDelegate.typeSync(path, followLinks: followLinks); } @override @@ -83,7 +83,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.fseIdentical(path1, path2); } - return _fileSystemDelegate!.identical(path1, path2); + return _fileSystemDelegate.identical(path1, path2); } @override @@ -91,7 +91,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.fseIdenticalSync(path1, path2); } - return _fileSystemDelegate!.identicalSync(path1, path2); + return _fileSystemDelegate.identicalSync(path1, path2); } @override @@ -99,7 +99,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.getCurrentDirectory(); } - return _fileSystemDelegate!.currentDirectory; + return _fileSystemDelegate.currentDirectory; } @override @@ -107,7 +107,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.getSystemTempDirectory(); } - return _fileSystemDelegate!.systemTempDirectory; + return _fileSystemDelegate.systemTempDirectory; } @override @@ -115,7 +115,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.setCurrentDirectory(path); } - _fileSystemDelegate!.currentDirectory = path; + _fileSystemDelegate.currentDirectory = path; } @override @@ -123,7 +123,7 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.stat(path); } - return _fileSystemDelegate!.stat(path); + return _fileSystemDelegate.stat(path); } @override @@ -131,6 +131,6 @@ class FlutterIOOverrides extends io.IOOverrides { if (_fileSystemDelegate == null) { return super.statSync(path); } - return _fileSystemDelegate!.statSync(path); + return _fileSystemDelegate.statSync(path); } } diff --git a/packages/flutter_tools/test/src/test_build_system.dart b/packages/flutter_tools/test/src/test_build_system.dart index 88e0db9524e24..e47e98c65e53a 100644 --- a/packages/flutter_tools/test/src/test_build_system.dart +++ b/packages/flutter_tools/test/src/test_build_system.dart @@ -34,13 +34,13 @@ class TestBuildSystem implements BuildSystem { @override Future<BuildResult> build(Target target, Environment environment, {BuildSystemConfig buildSystemConfig = const BuildSystemConfig()}) async { if (_onRun != null) { - _onRun?.call(target, environment); + _onRun.call(target, environment); } if (_exception != null) { - throw _exception!; + throw _exception; } if (_singleResult != null) { - return _singleResult!; + return _singleResult; } if (_nextResult >= _results.length) { throw StateError('Unexpected build request of ${target.name}'); @@ -51,13 +51,13 @@ class TestBuildSystem implements BuildSystem { @override Future<BuildResult> buildIncremental(Target target, Environment environment, BuildResult? previousBuild) async { if (_onRun != null) { - _onRun?.call(target, environment); + _onRun.call(target, environment); } if (_exception != null) { - throw _exception!; + throw _exception; } if (_singleResult != null) { - return _singleResult!; + return _singleResult; } if (_nextResult >= _results.length) { throw StateError('Unexpected buildIncremental request of ${target.name}'); diff --git a/packages/flutter_tools/test/src/testbed.dart b/packages/flutter_tools/test/src/testbed.dart index ba84512124625..d46cf36c9b0ec 100644 --- a/packages/flutter_tools/test/src/testbed.dart +++ b/packages/flutter_tools/test/src/testbed.dart @@ -126,7 +126,7 @@ class Testbed { body: () async { Cache.flutterRoot = ''; if (_setup != null) { - await _setup?.call(); + await _setup.call(); } await test(); Cache.flutterRoot = originalFlutterRoot; From 93103b4221b736df6e14fa7ae33ee3c2317597f2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 16:22:08 -0400 Subject: [PATCH 1226/1547] Roll Flutter Engine from d4698c65aa8d to 496ef6a9c277 (6 revisions) (#134569) https://github.com/flutter/engine/compare/d4698c65aa8d...496ef6a9c277 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 7cafb622ee7f to a4f8f5177c8b (1 revision) (flutter/engine#45719) 2023-09-12 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from vGleXqh2SRUNJM7JN... to MWWrSP9mSVlGIOaDo... (flutter/engine#45718) 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 438ec87ea2be to 7cafb622ee7f (1 revision) (flutter/engine#45716) 2023-09-12 matanlurey@users.noreply.github.com [Impeller] Make `CreateMockVulkanContext()` thread-safe (flutter/engine#45687) 2023-09-12 30870216+gaaclarke@users.noreply.github.com [Impeller] moved validation layers on by default logic to gni scripts (flutter/engine#45682) 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from f3f0cab7efd0 to 438ec87ea2be (1 revision) (flutter/engine#45714) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from vGleXqh2SRUN to MWWrSP9mSVlG If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ecfa349c5a423..10be309802d6b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d4698c65aa8d9e42d4aa70391c804270506a5f82 +496ef6a9c277e5572fa4350a50ff140816c73845 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index c381a80c6d8e9..28a64e41cf9ac 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -vGleXqh2SRUNJM7JNwpEoinm9VFaEF4eIgBF0M_-V9sC +MWWrSP9mSVlGIOaDoAhSNSx_v1fGNKJtHenmI0aa4IAC From 983ecf069cba1fb7cfd82bcb5989b4a86e66580a Mon Sep 17 00:00:00 2001 From: Michael Goderbauer <goderbauer@google.com> Date: Tue, 12 Sep 2023 14:08:19 -0700 Subject: [PATCH 1227/1547] Enable private field promotion for other packages (#134475) New feature in upcoming Dart 3.2. See https://github.com/dart-lang/language/issues/2020. Feature is enabled by bumping the min SDK version to 3.2. Part of https://github.com/flutter/flutter/issues/134476. --- packages/flutter_driver/pubspec.yaml | 2 +- packages/flutter_goldens/pubspec.yaml | 2 +- packages/flutter_goldens_client/pubspec.yaml | 2 +- packages/flutter_localizations/pubspec.yaml | 2 +- packages/flutter_test/pubspec.yaml | 2 +- .../flutter_test/test/test_config/project_root/pubspec.yaml | 2 +- packages/flutter_web_plugins/pubspec.yaml | 2 +- packages/fuchsia_remote_debug_protocol/pubspec.yaml | 2 +- packages/integration_test/example/pubspec.yaml | 2 +- packages/integration_test/integration_test_macos/pubspec.yaml | 2 +- packages/integration_test/lib/common.dart | 4 ++-- packages/integration_test/pubspec.yaml | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 46e0231ae4a61..b85d1c4ca4d25 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -3,7 +3,7 @@ description: Integration and performance test API for Flutter applications homepage: https://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: file: 6.1.4 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index 399745f994670..f76185c6d2127 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_goldens environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter_goldens_client/pubspec.yaml b/packages/flutter_goldens_client/pubspec.yaml index c1bdb5bbe6bfa..dea9d647002e6 100644 --- a/packages/flutter_goldens_client/pubspec.yaml +++ b/packages/flutter_goldens_client/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_goldens_client environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index 0c6726ca5e1c1..2c2db43d59b59 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_localizations environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index 0d4595b09d196..0b726abf67c93 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -1,7 +1,7 @@ name: flutter_test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter_test/test/test_config/project_root/pubspec.yaml b/packages/flutter_test/test/test_config/project_root/pubspec.yaml index f4d908c200388..75c96b122feef 100644 --- a/packages/flutter_test/test/test_config/project_root/pubspec.yaml +++ b/packages/flutter_test/test/test_config/project_root/pubspec.yaml @@ -4,6 +4,6 @@ name: dummy environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' # PUBSPEC CHECKSUM: 0000 diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index a0d29127b4648..ef2ebb0e07a35 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -3,7 +3,7 @@ description: Library to register Flutter Web plugins homepage: https://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index f1a5ec18ee268..c73ea6b80c23e 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -4,7 +4,7 @@ description: Provides an API to test/debug Flutter applications on remote Fuchsi homepage: https://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: process: 4.2.4 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index d4162338fb065..9245d22fa4656 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -3,7 +3,7 @@ description: Demonstrates how to use the integration_test plugin. publish_to: 'none' environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' flutter: ">=1.6.7" dependencies: diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 07164b3cc5cce..e2a8860af37b7 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -10,7 +10,7 @@ flutter: pluginClass: IntegrationTestPlugin environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: diff --git a/packages/integration_test/lib/common.dart b/packages/integration_test/lib/common.dart index 8e8490a551d1a..e5307f924e2a7 100644 --- a/packages/integration_test/lib/common.dart +++ b/packages/integration_test/lib/common.dart @@ -107,11 +107,11 @@ class Response { /// Create a list of Strings from [_failureDetails]. List<String> _failureDetailsAsString() { final List<String> list = <String>[]; - if (_failureDetails == null || _failureDetails!.isEmpty) { + if (_failureDetails == null || _failureDetails.isEmpty) { return list; } - for (final Failure failure in _failureDetails!) { + for (final Failure failure in _failureDetails) { list.add(failure.toJson()); } diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 6e11587637051..4fe03e19a69b5 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -3,7 +3,7 @@ description: Runs tests that use the flutter_test API as integration tests. publish_to: none environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: flutter: From 3e1e869a547931ae3b073dfc70f3bd91fb7f2066 Mon Sep 17 00:00:00 2001 From: keyonghan <54558023+keyonghan@users.noreply.github.com> Date: Tue, 12 Sep 2023 15:20:39 -0700 Subject: [PATCH 1228/1547] Revert "Retry Linux web tests 1 time on roll presubmit" (#134586) Reverts flutter/flutter#134552 --- .ci.yaml | 44 -------------------------------------------- 1 file changed, 44 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 7e1d3e5b05964..3ccd3707a56bb 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1140,8 +1140,6 @@ targets: subshard: "1_5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1162,8 +1160,6 @@ targets: subshard: "2_5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1184,8 +1180,6 @@ targets: subshard: "3_5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1206,8 +1200,6 @@ targets: subshard: "4_5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1228,8 +1220,6 @@ targets: subshard: "5_5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1250,8 +1240,6 @@ targets: subshard: "0" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1272,8 +1260,6 @@ targets: subshard: "1" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1294,8 +1280,6 @@ targets: subshard: "2" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1316,8 +1300,6 @@ targets: subshard: "3" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1338,8 +1320,6 @@ targets: subshard: "4" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1360,8 +1340,6 @@ targets: subshard: "5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1382,8 +1360,6 @@ targets: subshard: "6" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1404,8 +1380,6 @@ targets: subshard: "7_last" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1426,8 +1400,6 @@ targets: subshard: "0" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1448,8 +1420,6 @@ targets: subshard: "1" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1470,8 +1440,6 @@ targets: subshard: "2" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1492,8 +1460,6 @@ targets: subshard: "3" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1514,8 +1480,6 @@ targets: subshard: "4" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1536,8 +1500,6 @@ targets: subshard: "5" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1558,8 +1520,6 @@ targets: subshard: "6" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1580,8 +1540,6 @@ targets: subshard: "7_last" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1603,8 +1561,6 @@ targets: subshard: "1_1" tags: > ["framework", "hostonly", "shard", "linux"] - # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 - presubmit_max_attempts: "2" runIf: - dev/** - packages/flutter_tools/** From fcba7b3dc27eb87f573d82b53448250143845f41 Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Tue, 12 Sep 2023 17:38:23 -0500 Subject: [PATCH 1229/1547] Fix SliverList example descriptions (#134483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/flutter/flutter/issues/134142 The description for the SliverList.list example was just wrong, describing something other than the sample. 🙃 Tweaked some of the language on the others while I was here. --- packages/flutter/lib/src/widgets/sliver.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart index f5240dd7b73d6..65ce9e48d76fe 100644 --- a/packages/flutter/lib/src/widgets/sliver.dart +++ b/packages/flutter/lib/src/widgets/sliver.dart @@ -177,8 +177,8 @@ class SliverList extends SliverMultiBoxAdaptorWidget { /// [SliverChildBuilderDelegate.addSemanticIndexes] property. /// /// {@tool snippet} - /// This example, which would be inserted into a [CustomScrollView.slivers] - /// list, shows an infinite number of items in varying shades of blue: + /// This example, which would be provided in [CustomScrollView.slivers], + /// shows an infinite number of items in varying shades of blue: /// /// ```dart /// SliverList.builder( @@ -236,10 +236,11 @@ class SliverList extends SliverMultiBoxAdaptorWidget { /// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The /// `addSemanticIndexes` argument corresponds to the /// [SliverChildBuilderDelegate.addSemanticIndexes] property. - /// {@tool snippet} /// + /// {@tool snippet} /// This example shows how to create a [SliverList] whose [Container] items - /// are separated by [Divider]s. + /// are separated by [Divider]s. The [SliverList] would be provided in + /// [CustomScrollView.slivers]. /// /// ```dart /// SliverList.separated( @@ -303,8 +304,8 @@ class SliverList extends SliverMultiBoxAdaptorWidget { /// [SliverChildBuilderDelegate.addSemanticIndexes] property. /// /// {@tool snippet} - /// This example, which would be inserted into a [CustomScrollView.slivers] - /// list, shows an infinite number of items in varying shades of blue: + /// This example, which would be provided in [CustomScrollView.slivers], + /// shows a list containing two [Text] widgets: /// /// ```dart /// SliverList.list( From dc8377b1d4e5c0ab697215717982cd9a43effa7b Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Tue, 12 Sep 2023 15:41:45 -0700 Subject: [PATCH 1230/1547] Ensure OverlayPortal.overlayChild's renderObject is reachable via treewalk (#134497) Fixes https://github.com/flutter/flutter/issues/133545 ` child._layoutSurrogate.markNeedsLayout();` was called when `_skipMarkNeedsLayout` is set true so when there's no relayout boundary between the layout surrogate and the RenderTheater, no dirty render objects will be added to the PipelineOwner's dirty list. It's ok to mark the RenderTheater dirty when there's no layout boundary between it and the layout surrogate. --- .../flutter/lib/src/rendering/object.dart | 2 +- packages/flutter/lib/src/widgets/overlay.dart | 34 ++++---- .../test/widgets/overlay_portal_test.dart | 82 +++++++++++++++++++ 3 files changed, 101 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index c6fc50a84e3f6..2683563f8c6e5 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -1960,7 +1960,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge final bool mutationsToDirtySubtreesAllowed = activeLayoutRoot.owner?._debugAllowMutationsToDirtySubtrees ?? false; final bool doingLayoutWithCallback = activeLayoutRoot._doingThisLayoutWithCallback; // Mutations on this subtree is allowed when: - // - the subtree is being mutated in a layout callback. + // - the "activeLayoutRoot" subtree is being mutated in a layout callback. // - a different part of the render tree is doing a layout callback, // and this subtree is being reparented to that subtree, as a result // of global key reparenting. diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index e88aafad20b6e..4a0d6ef2becfc 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -1031,12 +1031,14 @@ class _RenderTheater extends RenderBox with ContainerRenderObjectMixin<RenderBox void _addDeferredChild(_RenderDeferredLayoutBox child) { assert(!_skipMarkNeedsLayout); _skipMarkNeedsLayout = true; - adoptChild(child); - // When child has never been laid out before, mark its layout surrogate as - // needing layout so it's reachable via tree walk. - child._layoutSurrogate.markNeedsLayout(); _skipMarkNeedsLayout = false; + + // After adding `child` to the render tree, we want to make sure it will be + // laid out in the same frame. This is done by calling markNeedsLayout on the + // layout surrgate. This ensures `child` is reachable via tree walk (see + // _RenderLayoutSurrogateProxyBox.performLayout). + child._layoutSurrogate.markNeedsLayout(); } void _removeDeferredChild(_RenderDeferredLayoutBox child) { @@ -1048,10 +1050,9 @@ class _RenderTheater extends RenderBox with ContainerRenderObjectMixin<RenderBox @override void markNeedsLayout() { - if (_skipMarkNeedsLayout) { - return; + if (!_skipMarkNeedsLayout) { + super.markNeedsLayout(); } - super.markNeedsLayout(); } RenderBox? get _firstOnstageChild { @@ -2088,7 +2089,7 @@ final class _RenderDeferredLayoutBox extends RenderProxyBox with _RenderTheaterM RenderObject? get debugLayoutParent => _layoutSurrogate; void layoutByLayoutSurrogate() { - assert(!_parentDoingLayout); + assert(!_theaterDoingThisLayout); final _RenderTheater? theater = parent as _RenderTheater?; if (theater == null || !attached) { assert(false, '$this is not attached to parent'); @@ -2097,25 +2098,26 @@ final class _RenderDeferredLayoutBox extends RenderProxyBox with _RenderTheaterM super.layout(BoxConstraints.tight(theater.constraints.biggest)); } - bool _parentDoingLayout = false; + bool _theaterDoingThisLayout = false; @override void layout(Constraints constraints, { bool parentUsesSize = false }) { assert(_needsLayout == debugNeedsLayout); // Only _RenderTheater calls this implementation. assert(parent != null); final bool scheduleDeferredLayout = _needsLayout || this.constraints != constraints; - assert(!_parentDoingLayout); - _parentDoingLayout = true; + assert(!_theaterDoingThisLayout); + _theaterDoingThisLayout = true; super.layout(constraints, parentUsesSize: parentUsesSize); - assert(_parentDoingLayout); - _parentDoingLayout = false; + assert(_theaterDoingThisLayout); + _theaterDoingThisLayout = false; _needsLayout = false; assert(!debugNeedsLayout); if (scheduleDeferredLayout) { final _RenderTheater parent = this.parent! as _RenderTheater; // Invoking markNeedsLayout as a layout callback allows this node to be - // merged back to the `PipelineOwner` if it's not already dirty. Otherwise - // this may cause some dirty descendants to performLayout a second time. + // merged back to the `PipelineOwner`'s dirty list in the right order, if + // it's not already dirty. Otherwise this may cause some dirty descendants + // to performLayout a second time. parent.invokeLayoutCallback((BoxConstraints constraints) { markNeedsLayout(); }); } } @@ -2129,7 +2131,7 @@ final class _RenderDeferredLayoutBox extends RenderProxyBox with _RenderTheaterM @override void performLayout() { assert(!_debugMutationsLocked); - if (_parentDoingLayout) { + if (_theaterDoingThisLayout) { _needsLayout = false; return; } diff --git a/packages/flutter/test/widgets/overlay_portal_test.dart b/packages/flutter/test/widgets/overlay_portal_test.dart index 702a5db64058d..d361f0c5d6b61 100644 --- a/packages/flutter/test/widgets/overlay_portal_test.dart +++ b/packages/flutter/test/widgets/overlay_portal_test.dart @@ -255,6 +255,42 @@ void main() { expect(tester.takeException(), isNull); }); + testWidgets('No relayout boundary between OverlayPortal and Overlay', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/133545. + final GlobalKey key = GlobalKey(debugLabel: 'key'); + final Widget widget = Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + initialEntries: <OverlayEntry>[ + OverlayEntry( + builder: (BuildContext context) { + // The Positioned widget prevents a relayout boundary from being + // introduced between the Overlay and OverlayPortal. + return Positioned( + top: 0, + left: 0, + child: OverlayPortal( + controller: controller1, + overlayChildBuilder: (BuildContext context) => SizedBox(key: key), + child: const SizedBox(), + ), + ); + }, + ), + ], + ), + ); + + controller1.hide(); + await tester.pumpWidget(widget); + + controller1.show(); + await tester.pump(); + expect(find.byKey(key), findsOneWidget); + expect(tester.takeException(), isNull); + verifyTreeIsClean(); + }); + testWidgets('Throws when the same controller is attached to multiple OverlayPortal', (WidgetTester tester) async { final OverlayPortalController controller = OverlayPortalController(debugLabel: 'local controller'); final Widget widget = Directionality( @@ -516,6 +552,52 @@ void main() { expect(tester.takeException(), isNull); }); + testWidgets('works in a LayoutBuilder 3', (WidgetTester tester) async { + late StateSetter setState; + bool shouldShowChild = false; + + Widget layoutBuilder(BuildContext context, BoxConstraints constraints) { + return OverlayPortal( + controller: controller2, + overlayChildBuilder: (BuildContext context) => const SizedBox(), + child: const SizedBox(), + ); + } + controller1.hide(); + controller2.hide(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Overlay( + initialEntries: <OverlayEntry>[ + OverlayStatefulEntry(builder: (BuildContext context, StateSetter setter) { + setState = setter; + // The Positioned widget ensures there's no relayout boundary + // between the Overlay and the OverlayPortal. + return Positioned( + top: 0, + left: 0, + child: OverlayPortal( + controller: controller1, + overlayChildBuilder: (BuildContext context) => const SizedBox(), + child: shouldShowChild ? LayoutBuilder(builder: layoutBuilder) : null, + ), + ); + }), + ], + ), + ), + ); + + controller1.show(); + controller2.show(); + setState(() { shouldShowChild = true; }); + + await tester.pump(); + expect(tester.takeException(), isNull); + }); + testWidgets('throws when no Overlay', (WidgetTester tester) async { await tester.pumpWidget( Directionality( From e9beaea0619dd2f3cd3bc014c77e1b3bbdb059a9 Mon Sep 17 00:00:00 2001 From: Elias Yishak <42216813+eliasyishak@users.noreply.github.com> Date: Tue, 12 Sep 2023 18:49:05 -0400 Subject: [PATCH 1231/1547] Clean up analytics opt in/out flags (#132588) Fixes: - #132258 --- packages/flutter_tools/lib/runner.dart | 22 +++++++++---------- .../lib/src/commands/config.dart | 6 ++++- packages/flutter_tools/lib/src/globals.dart | 2 +- .../src/runner/flutter_command_runner.dart | 20 ++++++++--------- .../general.shard/runner/runner_test.dart | 12 +++++----- 5 files changed, 33 insertions(+), 29 deletions(-) diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index d2dd7d6c535e6..9b33580af03e5 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -61,20 +61,20 @@ Future<int> run( StackTrace? firstStackTrace; return runZoned<Future<int>>(() async { try { - if (args.contains('--disable-telemetry') && - args.contains('--enable-telemetry')) { + if (args.contains('--disable-analytics') && + args.contains('--enable-analytics')) { throwToolExit( - 'Both enable and disable telemetry commands were detected ' + 'Both enable and disable analytics commands were detected ' 'when only one can be supplied per invocation.', exitCode: 1); } - // Disable analytics if user passes in the `--disable-telemetry` option - // `flutter --disable-telemetry` + // Disable analytics if user passes in the `--disable-analytics` option + // "flutter --disable-analytics" // - // Same functionality as `flutter config --no-analytics` for disabling + // Same functionality as "flutter config --no-analytics" for disabling // except with the `value` hard coded as false - if (args.contains('--disable-telemetry')) { + if (args.contains('--disable-analytics')) { // The tool sends the analytics event *before* toggling the flag // intentionally to be sure that opt-out events are sent correctly. AnalyticsConfigEvent(enabled: false).send(); @@ -93,12 +93,12 @@ Future<int> run( await globals.analytics.setTelemetry(false); } - // Enable analytics if user passes in the `--enable-telemetry` option - // `flutter --enable-telemetry` + // Enable analytics if user passes in the `--enable-analytics` option + // `flutter --enable-analytics` // // Same functionality as `flutter config --analytics` for enabling // except with the `value` hard coded as true - if (args.contains('--enable-telemetry')) { + if (args.contains('--enable-analytics')) { // The tool sends the analytics event *before* toggling the flag // intentionally to be sure that opt-out events are sent correctly. AnalyticsConfigEvent(enabled: true).send(); @@ -315,7 +315,7 @@ Future<int> _exit(int code, {required ShutdownHooks shutdownHooks}) async { 'the flutter tool is migrating to a new analytics system. ' 'Disabling analytics collection will disable both the legacy ' 'and new analytics collection systems. ' - 'You can disable analytics reporting by running `flutter --disable-telemetry`\n'); + 'You can disable analytics reporting by running `flutter --disable-analytics`\n'); } // Invoking this will onboard the flutter tool onto diff --git a/packages/flutter_tools/lib/src/commands/config.dart b/packages/flutter_tools/lib/src/commands/config.dart index ae03cf38616b6..9d0d3d6abfabb 100644 --- a/packages/flutter_tools/lib/src/commands/config.dart +++ b/packages/flutter_tools/lib/src/commands/config.dart @@ -11,11 +11,15 @@ import '../features.dart'; import '../globals.dart' as globals; import '../reporting/reporting.dart'; import '../runner/flutter_command.dart'; +import '../runner/flutter_command_runner.dart'; class ConfigCommand extends FlutterCommand { ConfigCommand({ bool verboseHelp = false }) { argParser.addFlag('analytics', - help: 'Enable or disable reporting anonymously tool usage statistics and crash reports.'); + hide: !verboseHelp, + help: 'Enable or disable reporting anonymously tool usage statistics and crash reports.\n' + '(An alias for "--${FlutterGlobalOptions.kEnableAnalyticsFlag}" ' + 'and "--${FlutterGlobalOptions.kDisableAnalyticsFlag}" top level flags.)'); argParser.addFlag('clear-ios-signing-cert', negatable: false, help: 'Clear the saved development certificate choice used to sign apps for iOS device deployment.'); diff --git a/packages/flutter_tools/lib/src/globals.dart b/packages/flutter_tools/lib/src/globals.dart index 59045aa442359..48eaa42f11b8c 100644 --- a/packages/flutter_tools/lib/src/globals.dart +++ b/packages/flutter_tools/lib/src/globals.dart @@ -88,7 +88,7 @@ final BotDetector _defaultBotDetector = BotDetector( ); Future<bool> get isRunningOnBot => botDetector.isRunningOnBot; -// Analytics instance for package:unified_analytics for telemetry +// Analytics instance for package:unified_analytics for analytics // reporting for all Flutter and Dart related tooling Analytics get analytics => context.get<Analytics>()!; diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index 0f752bc98b625..25e0ddb12d195 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -26,8 +26,8 @@ abstract final class FlutterGlobalOptions { static const String kColorFlag = 'color'; static const String kContinuousIntegrationFlag = 'ci'; static const String kDeviceIdOption = 'device-id'; - static const String kDisableTelemetryFlag = 'disable-telemetry'; - static const String kEnableTelemetryFlag = 'enable-telemetry'; + static const String kDisableAnalyticsFlag = 'disable-analytics'; + static const String kEnableAnalyticsFlag = 'enable-analytics'; static const String kLocalEngineOption = 'local-engine'; static const String kLocalEngineSrcPathOption = 'local-engine-src-path'; static const String kLocalEngineHostOption = 'local-engine-host'; @@ -101,17 +101,17 @@ class FlutterCommandRunner extends CommandRunner<void> { defaultsTo: true, hide: !verboseHelp, help: 'Allow Flutter to check for updates when this command runs.'); - argParser.addFlag(FlutterGlobalOptions.kSuppressAnalyticsFlag, + argParser.addFlag(FlutterGlobalOptions.kEnableAnalyticsFlag, negatable: false, - help: 'Suppress analytics reporting for the current CLI invocation.'); - argParser.addFlag(FlutterGlobalOptions.kDisableTelemetryFlag, + help: 'Enable telemetry reporting each time a flutter or dart ' + 'command runs.'); + argParser.addFlag(FlutterGlobalOptions.kDisableAnalyticsFlag, negatable: false, help: 'Disable telemetry reporting each time a flutter or dart ' 'command runs, until it is re-enabled.'); - argParser.addFlag(FlutterGlobalOptions.kEnableTelemetryFlag, + argParser.addFlag(FlutterGlobalOptions.kSuppressAnalyticsFlag, negatable: false, - help: 'Enable telemetry reporting each time a flutter or dart ' - 'command runs.'); + help: 'Suppress analytics reporting for the current CLI invocation.'); argParser.addOption(FlutterGlobalOptions.kPackagesOption, hide: !verboseHelp, help: 'Path to your "package_config.json" file.'); @@ -237,8 +237,8 @@ class FlutterCommandRunner extends CommandRunner<void> { // If the flag for enabling or disabling telemetry is passed in, // we will return out - if (topLevelResults.wasParsed(FlutterGlobalOptions.kDisableTelemetryFlag) || - topLevelResults.wasParsed(FlutterGlobalOptions.kEnableTelemetryFlag)) { + if (topLevelResults.wasParsed(FlutterGlobalOptions.kDisableAnalyticsFlag) || + topLevelResults.wasParsed(FlutterGlobalOptions.kEnableAnalyticsFlag)) { return; } diff --git a/packages/flutter_tools/test/general.shard/runner/runner_test.dart b/packages/flutter_tools/test/general.shard/runner/runner_test.dart index bd8f56a446556..4bf6a18a7c910 100644 --- a/packages/flutter_tools/test/general.shard/runner/runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/runner_test.dart @@ -326,7 +326,7 @@ void main() { expect(globals.analytics.shouldShowMessage, true); await runner.run( - <String>['--disable-telemetry'], + <String>['--disable-analytics'], () => <FlutterCommand>[], // This flutterVersion disables crash reporting. flutterVersion: '[user-branch]/', @@ -343,7 +343,7 @@ void main() { ); testUsingContext( - 'runner enabling telemetry with flag', + 'runner enabling analytics with flag', () async { io.setExitFunctionForTests((int exitCode) {}); @@ -351,7 +351,7 @@ void main() { expect(globals.analytics.shouldShowMessage, false); await runner.run( - <String>['--enable-telemetry'], + <String>['--enable-analytics'], () => <FlutterCommand>[], // This flutterVersion disables crash reporting. flutterVersion: '[user-branch]/', @@ -377,8 +377,8 @@ void main() { final int exitCode = await runner.run( <String>[ - '--disable-telemetry', - '--enable-telemetry', + '--disable-analytics', + '--enable-analytics', ], () => <FlutterCommand>[], // This flutterVersion disables crash reporting. @@ -538,7 +538,7 @@ class WaitingCrashReporter implements CrashReporter { } /// A fake [Analytics] that will be used to test -/// the --disable-telemetry flag +/// the --disable-analytics flag class FakeAnalytics extends Fake implements Analytics { FakeAnalytics({bool fakeTelemetryStatusOverride = true}) From 083ac65c512c3627e4466b82c284cf231a31b1f0 Mon Sep 17 00:00:00 2001 From: Bruno Leroux <leroux_bruno@yahoo.fr> Date: Wed, 13 Sep 2023 01:09:26 +0200 Subject: [PATCH 1232/1547] Fix TabBarView desynchronized after animation interruption (#132748) --- .../lib/src/widgets/scroll_activity.dart | 22 ++++++-- packages/flutter/test/material/tabs_test.dart | 51 +++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/widgets/scroll_activity.dart b/packages/flutter/lib/src/widgets/scroll_activity.dart index 64376b7dd5e73..d42d0374e203b 100644 --- a/packages/flutter/lib/src/widgets/scroll_activity.dart +++ b/packages/flutter/lib/src/widgets/scroll_activity.dart @@ -63,6 +63,8 @@ abstract class ScrollActivity { ScrollActivityDelegate get delegate => _delegate; ScrollActivityDelegate _delegate; + bool _isDisposed = false; + /// Updates the activity's link to the [ScrollActivityDelegate]. /// /// This should only be called when an activity is being moved from a defunct @@ -134,7 +136,9 @@ abstract class ScrollActivity { /// Called when the scroll view stops performing this activity. @mustCallSuper - void dispose() { } + void dispose() { + _isDisposed = true; + } @override String toString() => describeIdentity(this); @@ -535,7 +539,7 @@ class BallisticScrollActivity extends ScrollActivity { ) ..addListener(_tick) ..animateWith(simulation) - .whenComplete(_end); // won't trigger if we dispose _controller first + .whenComplete(_end); // won't trigger if we dispose _controller before it completes. } late AnimationController _controller; @@ -569,7 +573,11 @@ class BallisticScrollActivity extends ScrollActivity { } void _end() { - delegate.goBallistic(0.0); + // Check if the activity was disposed before going ballistic because _end might be called + // if _controller is disposed just after completion. + if (!_isDisposed) { + delegate.goBallistic(0.0); + } } @override @@ -628,7 +636,7 @@ class DrivenScrollActivity extends ScrollActivity { ) ..addListener(_tick) ..animateTo(to, duration: duration, curve: curve) - .whenComplete(_end); // won't trigger if we dispose _controller first + .whenComplete(_end); // won't trigger if we dispose _controller before it completes. } late final Completer<void> _completer; @@ -648,7 +656,11 @@ class DrivenScrollActivity extends ScrollActivity { } void _end() { - delegate.goBallistic(velocity); + // Check if the activity was disposed before going ballistic because _end might be called + // if _controller is disposed just after completion. + if (!_isDisposed) { + delegate.goBallistic(velocity); + } } @override diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 144fbaf3b39f9..098ad754c954c 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -2224,6 +2224,57 @@ void main() { expect(tabController.index, 0); }); + testWidgets('On going TabBarView animation can be interrupted by a new animation', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/132293. + + final List<String> tabs = <String>['A', 'B', 'C']; + final TabController tabController = TabController( + vsync: const TestVSync(), + length: tabs.length, + ); + await tester.pumpWidget(boilerplate( + child: Column( + children: <Widget>[ + TabBar( + tabs: tabs.map<Widget>((String tab) => Tab(text: tab)).toList(), + controller: tabController, + ), + SizedBox( + width: 400.0, + height: 400.0, + child: TabBarView( + controller: tabController, + children: const <Widget>[ + Center(child: Text('0')), + Center(child: Text('1')), + Center(child: Text('2')), + ], + ), + ), + ], + ), + )); + + // First page is visible. + expect(tabController.index, 0); + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Animate to the second page. + tabController.animateTo(1); + await tester.pump(); + await tester.pump(const Duration(milliseconds: 300)); + + // Animate back to the first page before the previous animation ends. + tabController.animateTo(0); + await tester.pumpAndSettle(); + + // First page should be visible. + expect(tabController.index, 0); + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + }); + testWidgets('Can switch to non-neighboring tab in nested TabBarView without crashing', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/18756 final TabController mainTabController = _tabController(length: 4, vsync: const TestVSync()); From 7d0c9b7211d5be55b9566f582cd6b972c045af25 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Wed, 13 Sep 2023 02:43:34 +0200 Subject: [PATCH 1233/1547] Cover more test/widgets tests with leak tracking (#134387) --- packages/flutter/test/widgets/app_test.dart | 8 +- .../flutter/test/widgets/draggable_test.dart | 132 +- .../flutter/test/widgets/drawer_test.dart | 19 +- .../widgets/dual_transition_builder_test.dart | 15 +- .../widgets/editable_text_cursor_test.dart | 210 ++- .../widgets/editable_text_shortcuts_test.dart | 187 +-- .../editable_text_show_on_screen_test.dart | 136 +- .../test/widgets/editable_text_test.dart | 1425 +++++++++-------- .../test/widgets/ensure_visible_test.dart | 35 +- .../widgets/error_widget_builder_test.dart | 5 +- .../test/widgets/fade_in_image_test.dart | 53 +- .../test/widgets/fade_transition_test.dart | 3 +- .../flutter/test/widgets/fitted_box_test.dart | 29 +- packages/flutter/test/widgets/flex_test.dart | 11 +- packages/flutter/test/widgets/flow_test.dart | 11 +- 15 files changed, 1209 insertions(+), 1070 deletions(-) diff --git a/packages/flutter/test/widgets/app_test.dart b/packages/flutter/test/widgets/app_test.dart index d6274ce11e19b..38c67439767be 100644 --- a/packages/flutter/test/widgets/app_test.dart +++ b/packages/flutter/test/widgets/app_test.dart @@ -306,7 +306,7 @@ void main() { expect(find.text('popped'), findsOneWidget); }, leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(someone): remove after fixing + // TODO(ksokolovskyi): remove after fixing // https://github.com/flutter/flutter/issues/134205 notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1}, )); @@ -338,7 +338,7 @@ void main() { expect(find.text('popped'), findsOneWidget); }, leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(someone): remove after fixing + // TODO(ksokolovskyi): remove after fixing // https://github.com/flutter/flutter/issues/134205 notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1}, )); @@ -434,7 +434,7 @@ void main() { expect(find.text('popped'), findsOneWidget); }, leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(someone): remove after fixing + // TODO(ksokolovskyi): remove after fixing // https://github.com/flutter/flutter/issues/134205 notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1}, )); @@ -455,7 +455,7 @@ void main() { expect(find.text('/'), findsOneWidget); }, leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(someone): remove after fixing + // TODO(ksokolovskyi): remove after fixing // https://github.com/flutter/flutter/issues/134205 notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1}, )); diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart index ac91266e41fe8..f03125c352bd8 100644 --- a/packages/flutter/test/widgets/draggable_test.dart +++ b/packages/flutter/test/widgets/draggable_test.dart @@ -14,11 +14,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Drag and drop - control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - control test', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; int dragStartedCount = 0; @@ -93,7 +94,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/76825 - testWidgets('Drag and drop - onLeave callback fires correctly with generic parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onLeave callback fires correctly with generic parameter', (WidgetTester tester) async { final Map<String,int> leftBehind = <String,int>{ 'Target 1': 0, 'Target 2': 0, @@ -168,7 +169,7 @@ void main() { expect(leftBehind['Target 2'], equals(1)); }); - testWidgets('Drag and drop - onLeave callback fires correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onLeave callback fires correctly', (WidgetTester tester) async { final Map<String,int> leftBehind = <String,int>{ 'Target 1': 0, 'Target 2': 0, @@ -244,7 +245,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/76825 - testWidgets('Drag and drop - onMove callback fires correctly with generic parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onMove callback fires correctly with generic parameter', (WidgetTester tester) async { final Map<String,int> targetMoveCount = <String,int>{ 'Target 1': 0, 'Target 2': 0, @@ -317,7 +318,7 @@ void main() { expect(targetMoveCount['Target 2'], equals(1)); }); - testWidgets('Drag and drop - onMove callback fires correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onMove callback fires correctly', (WidgetTester tester) async { final Map<String,int> targetMoveCount = <String,int>{ 'Target 1': 0, 'Target 2': 0, @@ -394,7 +395,7 @@ void main() { expect(targetMoveCount['Target 2'], equals(1)); }); - testWidgets('Drag and drop - dragging over button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - dragging over button', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation; @@ -487,7 +488,7 @@ void main() { events.clear(); }); - testWidgets('Drag and drop - tapping button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - tapping button', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation; @@ -544,7 +545,7 @@ void main() { events.clear(); }); - testWidgets('Drag and drop - long press draggable, short press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - long press draggable, short press', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation; @@ -593,7 +594,7 @@ void main() { expect(events, isEmpty); }); - testWidgets('Drag and drop - long press draggable, long press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - long press draggable, long press', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation; @@ -644,7 +645,7 @@ void main() { expect(events, equals(<String>['drop', 'details'])); }); - testWidgets('Drag and drop - horizontal and vertical draggables in vertical block', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - horizontal and vertical draggables in vertical block', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation, thirdLocation; @@ -754,7 +755,7 @@ void main() { events.clear(); }); - testWidgets('Drag and drop - horizontal and vertical draggables in horizontal block', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - horizontal and vertical draggables in horizontal block', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation, thirdLocation; @@ -913,7 +914,7 @@ void main() { ), ); } - testWidgets('Null axis draggable moves along all axes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Null axis draggable moves along all axes', (WidgetTester tester) async { await tester.pumpWidget(build()); final Offset firstLocation = tester.getTopLeft(find.text('N')); final Offset secondLocation = firstLocation + const Offset(300.0, 300.0); @@ -928,7 +929,7 @@ void main() { expect(tester.getTopLeft(find.text('N')), thirdLocation); }); - testWidgets('Horizontal axis draggable moves horizontally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal axis draggable moves horizontally', (WidgetTester tester) async { await tester.pumpWidget(build()); final Offset firstLocation = tester.getTopLeft(find.text('H')); final Offset secondLocation = firstLocation + const Offset(300.0, 0.0); @@ -943,7 +944,7 @@ void main() { expect(tester.getTopLeft(find.text('H')), thirdLocation); }); - testWidgets('Horizontal axis draggable does not move vertically', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal axis draggable does not move vertically', (WidgetTester tester) async { await tester.pumpWidget(build()); final Offset firstLocation = tester.getTopLeft(find.text('H')); final Offset secondDragLocation = firstLocation + const Offset(300.0, 200.0); @@ -961,7 +962,7 @@ void main() { expect(tester.getTopLeft(find.text('H')), thirdWidgetLocation); }); - testWidgets('Vertical axis draggable moves vertically', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical axis draggable moves vertically', (WidgetTester tester) async { await tester.pumpWidget(build()); final Offset firstLocation = tester.getTopLeft(find.text('V')); final Offset secondLocation = firstLocation + const Offset(0.0, 300.0); @@ -976,7 +977,7 @@ void main() { expect(tester.getTopLeft(find.text('V')), thirdLocation); }); - testWidgets('Vertical axis draggable does not move horizontally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical axis draggable does not move horizontally', (WidgetTester tester) async { await tester.pumpWidget(build()); final Offset firstLocation = tester.getTopLeft(find.text('V')); final Offset secondDragLocation = firstLocation + const Offset(200.0, 300.0); @@ -1042,7 +1043,7 @@ void main() { ); } - testWidgets('Null axis onDragUpdate called only if draggable moves in any direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Null axis onDragUpdate called only if draggable moves in any direction', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(updated, 0); @@ -1077,7 +1078,7 @@ void main() { expect(dragDelta.dy, 10); }); - testWidgets('Vertical axis onDragUpdate only called if draggable moves vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical axis onDragUpdate only called if draggable moves vertical', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(updated, 0); @@ -1112,7 +1113,7 @@ void main() { expect(dragDelta.dy, 10); }); - testWidgets('Horizontal axis onDragUpdate only called if draggable moves horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal axis onDragUpdate only called if draggable moves horizontal', (WidgetTester tester) async { await tester.pumpWidget(build()); expect(updated, 0); @@ -1148,7 +1149,7 @@ void main() { }); }); - testWidgets('Drag and drop - onDraggableCanceled not called if dropped on accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDraggableCanceled not called if dropped on accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDraggableCanceledCalled = false; @@ -1216,7 +1217,7 @@ void main() { expect(onDraggableCanceledCalled, isFalse); }); - testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDraggableCanceled called if dropped on non-accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDraggableCanceledCalled = false; @@ -1293,7 +1294,7 @@ void main() { expect(onDraggableCanceledOffset, equals(Offset(secondLocation.dx, secondLocation.dy))); }); - testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with details', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with details', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDraggableCanceledCalled = false; @@ -1370,7 +1371,7 @@ void main() { expect(onDraggableCanceledOffset, equals(Offset(secondLocation.dx, secondLocation.dy))); }); - testWidgets('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with correct velocity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDraggableCanceled called if dropped on non-accepting target with correct velocity', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDraggableCanceledCalled = false; @@ -1422,7 +1423,7 @@ void main() { expect(onDraggableCanceledOffset, equals(Offset(flingStart.dx, flingStart.dy) + const Offset(0.0, 100.0))); }); - testWidgets('Drag and drop - onDragEnd not called if dropped on non-accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDragEnd not called if dropped on non-accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragEndCalled = false; @@ -1498,7 +1499,7 @@ void main() { ); }); - testWidgets('Drag and drop - onDragEnd not called if dropped on non-accepting target with details', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDragEnd not called if dropped on non-accepting target with details', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragEndCalled = false; @@ -1574,7 +1575,7 @@ void main() { ); }); - testWidgets('Drag and drop - DragTarget rebuilds with and without rejected data when a rejected draggable enters and leaves', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - DragTarget rebuilds with and without rejected data when a rejected draggable enters and leaves', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Column( children: <Widget>[ @@ -1628,7 +1629,7 @@ void main() { }); - testWidgets('Drag and drop - Can drag and drop over a non-accepting target multiple times', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - Can drag and drop over a non-accepting target multiple times', (WidgetTester tester) async { int numberOfTimesOnDraggableCanceledCalled = 0; await tester.pumpWidget(MaterialApp( home: Column( @@ -1710,7 +1711,7 @@ void main() { expect(find.text('Rejected'), findsNothing); }); - testWidgets('Drag and drop - onDragCompleted not called if dropped on non-accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDragCompleted not called if dropped on non-accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragCompletedCalled = false; @@ -1781,7 +1782,7 @@ void main() { expect(onDragCompletedCalled, isFalse); }); - testWidgets('Drag and drop - onDragCompleted not called if dropped on non-accepting target with details', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDragCompleted not called if dropped on non-accepting target with details', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragCompletedCalled = false; @@ -1852,7 +1853,7 @@ void main() { expect(onDragCompletedCalled, isFalse); }); - testWidgets('Drag and drop - onDragEnd called if dropped on accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDragEnd called if dropped on accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragEndCalled = false; @@ -1928,7 +1929,7 @@ void main() { expect(onDragEndDraggableDetails.offset, equals(expectedDropOffset)); }); - testWidgets('DragTarget does not call onDragEnd when remove from the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DragTarget does not call onDragEnd when remove from the tree', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation; int timesOnDragEndCalled = 0; @@ -1994,7 +1995,7 @@ void main() { await tester.pump(); }); - testWidgets('Drag and drop - onDragCompleted called if dropped on accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - onDragCompleted called if dropped on accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragCompletedCalled = false; @@ -2062,7 +2063,7 @@ void main() { expect(onDragCompletedCalled, isTrue); }); - testWidgets('Drag and drop - allow pass through of unaccepted data test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - allow pass through of unaccepted data test', (WidgetTester tester) async { final List<int> acceptedInts = <int>[]; final List<DragTargetDetails<int>> acceptedIntsDetails = <DragTargetDetails<int>>[]; final List<double> acceptedDoubles = <double>[]; @@ -2196,7 +2197,7 @@ void main() { expect(find.text('DoubleDragging'), findsNothing); }); - testWidgets('Drag and drop - allow pass through of unaccepted data twice test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - allow pass through of unaccepted data twice test', (WidgetTester tester) async { final List<DragTargetData> acceptedDragTargetDatas = <DragTargetData>[]; final List<DragTargetDetails<DragTargetData>> acceptedDragTargetDataDetails = <DragTargetDetails<DragTargetData>>[]; final List<ExtendedDragTargetData> acceptedExtendedDragTargetDatas = <ExtendedDragTargetData>[]; @@ -2264,7 +2265,7 @@ void main() { } }); - testWidgets('Drag and drop - maxSimultaneousDrags', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - maxSimultaneousDrags', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; @@ -2391,14 +2392,17 @@ void main() { expect(find.text('Target'), findsOneWidget); }); - testWidgets('Draggable disposes recognizer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Draggable disposes recognizer', (WidgetTester tester) async { + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + bool didTap = false; await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) => GestureDetector( onTap: () { didTap = true; @@ -2430,7 +2434,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/6128. - testWidgets('Draggable plays nice with onTap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Draggable plays nice with onTap', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2463,7 +2467,7 @@ void main() { await secondGesture.up(); }); - testWidgets('DragTarget does not set state when remove from the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DragTarget does not set state when remove from the tree', (WidgetTester tester) async { final List<String> events = <String>[]; Offset firstLocation, secondLocation; @@ -2525,7 +2529,7 @@ void main() { await tester.pump(); }); - testWidgets('Drag and drop - remove draggable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - remove draggable', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; @@ -2605,7 +2609,7 @@ void main() { expect(find.text('Target'), findsOneWidget); }); - testWidgets('Tap above long-press draggable works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap above long-press draggable works', (WidgetTester tester) async { final List<String> events = <String>[]; await tester.pumpWidget(MaterialApp( @@ -2629,7 +2633,7 @@ void main() { expect(events, equals(<String>['tap'])); }); - testWidgets('long-press draggable calls onDragEnd called if dropped on accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long-press draggable calls onDragEnd called if dropped on accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragEndCalled = false; @@ -2716,7 +2720,7 @@ void main() { expect(onDragEndDraggableDetails.offset, equals(expectedDropOffset)); }); - testWidgets('long-press draggable calls onDragCompleted called if dropped on accepting target', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long-press draggable calls onDragCompleted called if dropped on accepting target', (WidgetTester tester) async { final List<int> accepted = <int>[]; final List<DragTargetDetails<int>> acceptedDetails = <DragTargetDetails<int>>[]; bool onDragCompletedCalled = false; @@ -2792,7 +2796,7 @@ void main() { expect(onDragCompletedCalled, isTrue); }); - testWidgets('long-press draggable calls onDragStartedCalled after long press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long-press draggable calls onDragStartedCalled after long press', (WidgetTester tester) async { bool onDragStartedCalled = false; await tester.pumpWidget(MaterialApp( @@ -2825,7 +2829,7 @@ void main() { expect(onDragStartedCalled, isTrue); }); - testWidgets('Custom long press delay for LongPressDraggable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom long press delay for LongPressDraggable', (WidgetTester tester) async { bool onDragStartedCalled = false; await tester.pumpWidget(MaterialApp( home: LongPressDraggable<int>( @@ -2859,7 +2863,7 @@ void main() { expect(onDragStartedCalled, isTrue); }); - testWidgets('Default long press delay for LongPressDraggable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default long press delay for LongPressDraggable', (WidgetTester tester) async { bool onDragStartedCalled = false; await tester.pumpWidget(MaterialApp( home: LongPressDraggable<int>( @@ -2892,23 +2896,23 @@ void main() { expect(onDragStartedCalled, isTrue); }); - testWidgets('long-press draggable calls Haptic Feedback onStart', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long-press draggable calls Haptic Feedback onStart', (WidgetTester tester) async { await _testLongPressDraggableHapticFeedback(tester: tester, hapticFeedbackOnStart: true, expectedHapticFeedbackCount: 1); }); - testWidgets('long-press draggable can disable Haptic Feedback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long-press draggable can disable Haptic Feedback', (WidgetTester tester) async { await _testLongPressDraggableHapticFeedback(tester: tester, hapticFeedbackOnStart: false, expectedHapticFeedbackCount: 0); }); - testWidgets('Drag feedback with child anchor positions correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag feedback with child anchor positions correctly', (WidgetTester tester) async { await _testChildAnchorFeedbackPosition(tester: tester); }); - testWidgets('Drag feedback with child anchor within a non-global Overlay positions correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag feedback with child anchor within a non-global Overlay positions correctly', (WidgetTester tester) async { await _testChildAnchorFeedbackPosition(tester: tester, left: 100.0, top: 100.0); }); - testWidgets('Drag feedback is put on root overlay with [rootOverlay] flag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag feedback is put on root overlay with [rootOverlay] flag', (WidgetTester tester) async { final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>(); final GlobalKey<NavigatorState> childNavigatorKey = GlobalKey<NavigatorState>(); // Create a [MaterialApp], with a nested [Navigator], which has the @@ -2976,7 +2980,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/72483 - testWidgets('Drag and drop - DragTarget<Object> can accept Draggable<int> data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - DragTarget<Object> can accept Draggable<int> data', (WidgetTester tester) async { final List<Object> accepted = <Object>[]; await tester.pumpWidget(MaterialApp( home: Column( @@ -3012,7 +3016,7 @@ void main() { expect(accepted, equals(<int>[1])); }); - testWidgets('Drag and drop - DragTarget<int> can accept Draggable<Object> data when runtime type is int', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - DragTarget<int> can accept Draggable<Object> data when runtime type is int', (WidgetTester tester) async { final List<int> accepted = <int>[]; await tester.pumpWidget(MaterialApp( home: Column( @@ -3048,7 +3052,7 @@ void main() { expect(accepted, equals(<int>[1])); }); - testWidgets('Drag and drop - DragTarget<int> should not accept Draggable<Object> data when runtime type null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - DragTarget<int> should not accept Draggable<Object> data when runtime type null', (WidgetTester tester) async { final List<int> accepted = <int>[]; bool isReceiveNullDataForCheck = false; await tester.pumpWidget(MaterialApp( @@ -3091,7 +3095,7 @@ void main() { expect(isReceiveNullDataForCheck, true); }); - testWidgets('Drag and drop can contribute semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop can contribute semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( home: ListView( @@ -3257,7 +3261,7 @@ void main() { semantics.dispose(); }); - testWidgets('Drag and drop - when a dragAnchorStrategy is provided it gets called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag and drop - when a dragAnchorStrategy is provided it gets called', (WidgetTester tester) async { bool dragAnchorStrategyCalled = false; await tester.pumpWidget(MaterialApp( @@ -3281,7 +3285,7 @@ void main() { expect(dragAnchorStrategyCalled, true); }); - testWidgets('configurable Draggable hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('configurable Draggable hit test behavior', (WidgetTester tester) async { const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild; await tester.pumpWidget( @@ -3301,7 +3305,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/92083 - testWidgets('feedback respect the MouseRegion cursor configure', (WidgetTester tester) async { + testWidgetsWithLeakTracking('feedback respect the MouseRegion cursor configure', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Column( @@ -3329,7 +3333,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.grabbing); }); - testWidgets('configurable feedback ignore pointer behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('configurable feedback ignore pointer behavior', (WidgetTester tester) async { bool onTap = false; await tester.pumpWidget( MaterialApp( @@ -3358,7 +3362,7 @@ void main() { expect(onTap, true); }); - testWidgets('configurable feedback ignore pointer behavior - LongPressDraggable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('configurable feedback ignore pointer behavior - LongPressDraggable', (WidgetTester tester) async { bool onTap = false; await tester.pumpWidget( MaterialApp( @@ -3389,7 +3393,7 @@ void main() { expect(onTap, true); }); - testWidgets('configurable DragTarget hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('configurable DragTarget hit test behavior', (WidgetTester tester) async { const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild; await tester.pumpWidget( @@ -3410,7 +3414,7 @@ void main() { expect(tester.widget<MetaData>(find.byType(MetaData)).behavior, hitTestBehavior); }); - testWidgets('LongPressDraggable.dragAnchorStrategy', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LongPressDraggable.dragAnchorStrategy', (WidgetTester tester) async { const Widget widget1 = Placeholder(key: ValueKey<int>(1)); const Widget widget2 = Placeholder(key: ValueKey<int>(2)); Offset dummyStrategy(Draggable<Object> draggable, BuildContext context, Offset position) => Offset.zero; @@ -3420,7 +3424,7 @@ void main() { expect(LongPressDraggable<int>(feedback: widget2, dragAnchorStrategy: dummyStrategy, child: widget1).dragAnchorStrategy, dummyStrategy); }); - testWidgets('Test allowedButtonsFilter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Test allowedButtonsFilter', (WidgetTester tester) async { Widget build(bool Function(int buttons)? allowedButtonsFilter) { return MaterialApp( home: Draggable<int>( @@ -3462,7 +3466,7 @@ void main() { await gesture3.up(); }); - testWidgets('throws error when both onWillAccept and onWillAcceptWithDetails are provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('throws error when both onWillAccept and onWillAcceptWithDetails are provided', (WidgetTester tester) async { expect(() => DragTarget<int>( builder: (BuildContext context, List<int?> data, List<dynamic> rejects) { return const SizedBox(height: 100.0, child: Text('Target')); diff --git a/packages/flutter/test/widgets/drawer_test.dart b/packages/flutter/test/widgets/drawer_test.dart index cb3aba7fd8280..d1a7ce8f3b22c 100644 --- a/packages/flutter/test/widgets/drawer_test.dart +++ b/packages/flutter/test/widgets/drawer_test.dart @@ -8,12 +8,13 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Drawer control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer control test', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); late BuildContext savedContext; await tester.pumpWidget( @@ -44,7 +45,7 @@ void main() { expect(find.text('drawer'), findsNothing); }); - testWidgets('Drawer tap test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer tap test', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -76,7 +77,7 @@ void main() { expect(find.text('drawer'), findsNothing); }); - testWidgets('Drawer hover test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer hover test', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); final List<String> logs = <String>[]; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); @@ -146,7 +147,7 @@ void main() { logs.clear(); }); - testWidgets('Drawer drag cancel resume (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer drag cancel resume (LTR)', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -197,7 +198,7 @@ void main() { await gesture.up(); }); - testWidgets('Drawer drag cancel resume (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer drag cancel resume (RTL)', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); await tester.pumpWidget( MaterialApp( @@ -251,7 +252,7 @@ void main() { await gesture.up(); }); - testWidgets('Drawer navigator back button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer navigator back button', (WidgetTester tester) async { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); bool buttonPressed = false; @@ -299,7 +300,7 @@ void main() { expect(buttonPressed, equals(true)); }); - testWidgets('Dismissible ModalBarrier includes button in semantic tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible ModalBarrier includes button in semantic tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -326,7 +327,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible ModalBarrier is hidden on Android (back button is used to dismiss)', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @@ -354,7 +355,7 @@ void main() { semantics.dispose(); }, variant: TargetPlatformVariant.only(TargetPlatform.android)); - testWidgets('Drawer contains route semantics flags', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drawer contains route semantics flags', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); diff --git a/packages/flutter/test/widgets/dual_transition_builder_test.dart b/packages/flutter/test/widgets/dual_transition_builder_test.dart index 4ffca538d978e..531aeead57ea3 100644 --- a/packages/flutter/test/widgets/dual_transition_builder_test.dart +++ b/packages/flutter/test/widgets/dual_transition_builder_test.dart @@ -4,13 +4,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('runs animations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('runs animations', (WidgetTester tester) async { final AnimationController controller = AnimationController( vsync: const TestVSync(), duration: const Duration(milliseconds: 300), ); + addTearDown(controller.dispose); await tester.pumpWidget(Center( child: DualTransitionBuilder( @@ -74,11 +76,12 @@ void main() { expect(_getOpacity(tester), 1.0); }); - testWidgets('keeps state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keeps state', (WidgetTester tester) async { final AnimationController controller = AnimationController( vsync: const TestVSync(), duration: const Duration(milliseconds: 300), ); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -138,11 +141,13 @@ void main() { expect(state, same(tester.state(find.byType(_StatefulTestWidget)))); }); - testWidgets('does not jump when interrupted - forward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not jump when interrupted - forward', (WidgetTester tester) async { final AnimationController controller = AnimationController( vsync: const TestVSync(), duration: const Duration(milliseconds: 300), ); + addTearDown(controller.dispose); + await tester.pumpWidget(Center( child: DualTransitionBuilder( animation: controller, @@ -202,12 +207,14 @@ void main() { expect(_getOpacity(tester), 1.0); }); - testWidgets('does not jump when interrupted - reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not jump when interrupted - reverse', (WidgetTester tester) async { final AnimationController controller = AnimationController( value: 1.0, vsync: const TestVSync(), duration: const Duration(milliseconds: 300), ); + addTearDown(controller.dispose); + await tester.pumpWidget(Center( child: DualTransitionBuilder( animation: controller, diff --git a/packages/flutter/test/widgets/editable_text_cursor_test.dart b/packages/flutter/test/widgets/editable_text_cursor_test.dart index e52e7bcf91bf8..ab1d8137b721a 100644 --- a/packages/flutter/test/widgets/editable_text_cursor_test.dart +++ b/packages/flutter/test/widgets/editable_text_cursor_test.dart @@ -15,23 +15,34 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'editable_text_utils.dart'; -final TextEditingController controller = TextEditingController(); -final FocusNode focusNode = FocusNode(); -final FocusScopeNode focusScopeNode = FocusScopeNode(); const TextStyle textStyle = TextStyle(); const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00); void main() { + late TextEditingController controller; + late FocusNode focusNode; + late FocusScopeNode focusScopeNode; + setUp(() async { // Fill the clipboard so that the Paste option is available in the text // selection menu. await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); + controller = TextEditingController(); + focusNode = FocusNode(); + focusScopeNode = FocusScopeNode(); + }); + + tearDown(() { + controller.dispose(); + focusNode.dispose(); + focusScopeNode.dispose(); }); - testWidgets('cursor has expected width, height, and radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor has expected width, height, and radius', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -57,7 +68,7 @@ void main() { expect(editableText.cursorRadius!.x, 2.0); }); - testWidgets('cursor layout has correct width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor layout has correct width', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>(); @@ -68,8 +79,8 @@ void main() { child: EditableText( backgroundCursorColor: Colors.grey, key: editableTextKey, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -113,7 +124,7 @@ void main() { EditableText.debugDeterministicCursor = false; }); - testWidgets('cursor layout has correct radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor layout has correct radius', (WidgetTester tester) async { final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>(); late String changedValue; @@ -123,8 +134,8 @@ void main() { child: EditableText( backgroundCursorColor: Colors.grey, key: editableTextKey, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -168,7 +179,7 @@ void main() { ); }); - testWidgets('Cursor animates on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor animates on iOS', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -219,7 +230,7 @@ void main() { await verifyKeyFrame(opacity: 1.0, at: 1000000); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('Cursor does not animate on non-iOS platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor does not animate on non-iOS platforms', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material(child: TextField(maxLines: 3)), @@ -238,7 +249,7 @@ void main() { } }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('Cursor does not animate on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor does not animate on Android', (WidgetTester tester) async { final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value); const Widget widget = MaterialApp( home: Material( @@ -276,9 +287,14 @@ void main() { await tester.pump(const Duration(milliseconds: 500)); expect(renderEditable.cursorColor!.alpha, 0); expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); - }); - - testWidgets('Cursor does not animates when debugDeterministicCursor is set', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 5}, + )); + + testWidgetsWithLeakTracking('Cursor does not animates when debugDeterministicCursor is set', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value); const Widget widget = MaterialApp( @@ -314,9 +330,15 @@ void main() { expect(renderEditable, paints..rrect(color: defaultCursorColor)); EditableText.debugDeterministicCursor = false; - }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - - testWidgets('Cursor does not animate on Android when debugDeterministicCursor is set', (WidgetTester tester) async { + }, + variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 6}, + )); + + testWidgetsWithLeakTracking('Cursor does not animate on Android when debugDeterministicCursor is set', (WidgetTester tester) async { final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value); EditableText.debugDeterministicCursor = true; const Widget widget = MaterialApp( @@ -353,17 +375,23 @@ void main() { expect(renderEditable, paints..rect(color: defaultCursorColor)); EditableText.debugDeterministicCursor = false; - }); - - testWidgets('Cursor animation restarts when it is moved using keys on desktop', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 4}, + )); + + testWidgetsWithLeakTracking('Cursor animation restarts when it is moved using keys on desktop', (WidgetTester tester) async { debugDefaultTargetPlatformOverride = TargetPlatform.macOS; const String testText = 'Some text long enough to move the cursor around'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; + final Widget widget = MaterialApp( home: EditableText( controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(fontSize: 20.0), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -430,9 +458,15 @@ void main() { expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); debugDefaultTargetPlatformOverride = null; - }, variant: KeySimulatorTransitModeVariant.all()); - - testWidgets('Cursor does not show when showCursor set to false', (WidgetTester tester) async { + }, + variant: KeySimulatorTransitModeVariant.all(), + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 18}, + )); + + testWidgetsWithLeakTracking('Cursor does not show when showCursor set to false', (WidgetTester tester) async { const Widget widget = MaterialApp( home: Material( child: TextField( @@ -458,11 +492,15 @@ void main() { await tester.pump(const Duration(milliseconds: 200)); expect(renderEditable, paintsExactlyCountTimes(#drawRect, 0)); - }); - - testWidgets('Cursor does not show when not focused', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 3}, + )); + + testWidgetsWithLeakTracking('Cursor does not show when not focused', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/106512 . - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MaterialApp( home: Material( @@ -489,9 +527,14 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); expect(renderEditable, isNot(paintsExactlyCountTimes(#drawRect, 0))); - }); - - testWidgets('Cursor radius is 2.0', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 2}, + )); + + testWidgetsWithLeakTracking('Cursor radius is 2.0', (WidgetTester tester) async { const Widget widget = MaterialApp( home: Material( child: TextField( @@ -507,10 +550,9 @@ void main() { expect(renderEditable.cursorRadius, const Radius.circular(2.0)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Cursor gets placed correctly after going out of bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor gets placed correctly after going out of bounds', (WidgetTester tester) async { const String text = 'hello world this is fun and cool and awesome!'; controller.text = text; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MediaQuery( @@ -602,10 +644,9 @@ void main() { expect(controller.selection.baseOffset, 10); }); - testWidgets('Updating the floating cursor correctly moves the cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updating the floating cursor correctly moves the cursor', (WidgetTester tester) async { const String text = 'hello world this is fun and cool and awesome!'; controller.text = text; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MediaQuery( @@ -659,10 +700,9 @@ void main() { expect(controller.selection.baseOffset, 10); }); - testWidgets('Updating the floating cursor can end without update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updating the floating cursor can end without update', (WidgetTester tester) async { const String text = 'hello world this is fun and cool and awesome!'; controller.text = text; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MediaQuery( @@ -703,10 +743,9 @@ void main() { expect(tester.takeException(), null); }); - testWidgets("Drag the floating cursor, it won't blink.", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Drag the floating cursor, it won't blink.", (WidgetTester tester) async { const String text = 'hello world this is fun and cool and awesome!'; controller.text = text; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MediaQuery( @@ -770,7 +809,7 @@ void main() { await checkCursorBlinking(); }); - testWidgets('Turning showCursor off stops the cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Turning showCursor off stops the cursor', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/108187. final bool debugDeterministicCursor = EditableText.debugDeterministicCursor; // This doesn't really matter. @@ -819,10 +858,9 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/pull/30475. - testWidgets('Trying to select with the floating cursor does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Trying to select with the floating cursor does not crash', (WidgetTester tester) async { const String text = 'hello world this is fun and cool and awesome!'; controller.text = text; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MediaQuery( @@ -885,12 +923,10 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('autofocus sets cursor to the end of text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('autofocus sets cursor to the end of text', (WidgetTester tester) async { const String text = 'hello world'; - final FocusScopeNode focusScopeNode = FocusScopeNode(); - final FocusNode focusNode = FocusNode(); - controller.text = text; + await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -917,12 +953,10 @@ void main() { expect(controller.selection.baseOffset, text.length); }); - testWidgets('Floating cursor is painted', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('Floating cursor is painted', (WidgetTester tester) async { const TextStyle textStyle = TextStyle(); const String text = 'hello world this is fun and cool and awesome!'; controller.text = text; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MaterialApp( @@ -995,9 +1029,15 @@ void main() { editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.End)); await tester.pumpAndSettle(); debugDefaultTargetPlatformOverride = null; - }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - - testWidgets('cursor layout', (WidgetTester tester) async { + }, + variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 4}, + )); + + testWidgetsWithLeakTracking('cursor layout', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>(); @@ -1011,8 +1051,8 @@ void main() { EditableText( backgroundCursorColor: Colors.grey, key: editableTextKey, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: Typography.material2018(platform: TargetPlatform.iOS).black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -1058,7 +1098,7 @@ void main() { EditableText.debugDeterministicCursor = false; }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('cursor layout has correct height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cursor layout has correct height', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>(); @@ -1072,8 +1112,8 @@ void main() { EditableText( backgroundCursorColor: Colors.grey, key: editableTextKey, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: Typography.material2018(platform: TargetPlatform.iOS).black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -1120,7 +1160,7 @@ void main() { EditableText.debugDeterministicCursor = false; }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('password briefly does not show last character when disabled by system', (WidgetTester tester) async { + testWidgetsWithLeakTracking('password briefly does not show last character when disabled by system', (WidgetTester tester) async { final bool debugDeterministicCursor = EditableText.debugDeterministicCursor; EditableText.debugDeterministicCursor = false; addTearDown(() { @@ -1156,23 +1196,23 @@ void main() { expect((findRenderEditable(tester).text! as TextSpan).text, '•••'); }); - testWidgets('getLocalRectForCaret with empty text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getLocalRectForCaret with empty text', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; addTearDown(() { EditableText.debugDeterministicCursor = false; }); const String text = '12'; - final TextEditingController controller = TextEditingController.fromValue( const TextEditingValue( text: text, selection: TextSelection.collapsed(offset: text.length), ), ); + addTearDown(controller.dispose); final Widget widget = EditableText( autofocus: true, backgroundCursorColor: Colors.grey, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(fontSize: 20), textAlign: TextAlign.center, keyboardType: TextInputType.text, @@ -1201,21 +1241,23 @@ void main() { expect(controller.text, isEmpty); }); - testWidgets('Caret center space test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret center space test', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; addTearDown(() { EditableText.debugDeterministicCursor = false; }); final String text = 'test${' ' * 1000}'; + final TextEditingController controller = TextEditingController.fromValue( + TextEditingValue( + text: text, + selection: TextSelection.collapsed(offset: text.length, affinity: TextAffinity.upstream), + ), + ); + addTearDown(controller.dispose); final Widget widget = EditableText( autofocus: true, backgroundCursorColor: Colors.grey, - controller: TextEditingController.fromValue( - TextEditingValue( - text: text, - selection: TextSelection.collapsed(offset: text.length, affinity: TextAffinity.upstream), - ), - ), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), textAlign: TextAlign.center, keyboardType: TextInputType.text, @@ -1243,25 +1285,31 @@ void main() { renderEditable, paints..rect(color: cursorColor, rect: caretRect), ); - }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 - - testWidgets('getLocalRectForCaret reports the real caret Rect', (WidgetTester tester) async { + }, + skip: isBrowser && !isCanvasKit, // https://github.com/flutter/flutter/issues/56308 + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 1}, + )); + + testWidgetsWithLeakTracking('getLocalRectForCaret reports the real caret Rect', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; addTearDown(() { EditableText.debugDeterministicCursor = false; }); final String text = 'test${' ' * 50}\n' '2nd line\n' '\n'; - final TextEditingController controller = TextEditingController.fromValue(TextEditingValue( text: text, selection: const TextSelection.collapsed(offset: 0), )); + addTearDown(controller.dispose); final Widget widget = EditableText( autofocus: true, backgroundCursorColor: Colors.grey, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(fontSize: 20), textAlign: TextAlign.center, keyboardType: TextInputType.text, @@ -1287,5 +1335,11 @@ void main() { paints..rect(color: cursorColor, rect: localRect.shift(editableTextRect.topLeft)), ); } - }, variant: TargetPlatformVariant.all()); + }, + variant: TargetPlatformVariant.all(), + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 792}, + )); } diff --git a/packages/flutter/test/widgets/editable_text_shortcuts_test.dart b/packages/flutter/test/widgets/editable_text_shortcuts_test.dart index b6efb36c221db..449fe0029eb50 100644 --- a/packages/flutter/test/widgets/editable_text_shortcuts_test.dart +++ b/packages/flutter/test/widgets/editable_text_shortcuts_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'clipboard_utils.dart'; import 'keyboard_utils.dart'; @@ -97,7 +98,7 @@ void main() { group('backspace', () { const LogicalKeyboardKey trigger = LogicalKeyboardKey.backspace; - testWidgets('backspace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace', (WidgetTester tester) async { controller.text = testText; // Move the selection to the beginning of the 2nd line (after the newline // character). @@ -122,7 +123,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('backspace readonly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace readonly', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 20, @@ -140,7 +141,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('backspace at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -163,7 +164,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('backspace at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -187,7 +188,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('backspace inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 1, @@ -208,7 +209,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('backspace at cluster boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('backspace at cluster boundary', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 8, @@ -233,7 +234,7 @@ void main() { group('delete: ', () { const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete; - testWidgets('delete', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete', (WidgetTester tester) async { controller.text = testText; // Move the selection to the beginning of the 2nd line (after the newline // character). @@ -259,7 +260,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('delete readonly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete readonly', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 20, @@ -277,7 +278,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('delete at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -300,7 +301,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('delete at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -324,7 +325,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('delete inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 1, @@ -345,7 +346,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('delete at cluster boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('delete at cluster boundary', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 8, @@ -371,7 +372,7 @@ void main() { // This shares the same logic as backspace. const LogicalKeyboardKey trigger = LogicalKeyboardKey.delete; - testWidgets('inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection( baseOffset: 9, @@ -392,7 +393,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('at the boundaries of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at the boundaries of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection( baseOffset: 8, @@ -413,7 +414,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('cross-cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cross-cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection( baseOffset: 1, @@ -434,7 +435,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('cross-cluster obscured text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cross-cluster obscured text', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection( baseOffset: 1, @@ -464,7 +465,7 @@ void main() { return SingleActivator(trigger, control: !isApple, alt: isApple); } - testWidgets('WordModifier-backspace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WordModifier-backspace', (WidgetTester tester) async { controller.text = testText; // Place the caret before "people". controller.selection = const TextSelection.collapsed( @@ -489,7 +490,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('readonly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('readonly', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 29, @@ -507,7 +508,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -530,7 +531,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -554,7 +555,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 1, @@ -575,7 +576,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('at cluster boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at cluster boundary', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 8, @@ -604,7 +605,7 @@ void main() { return SingleActivator(trigger, control: !isApple, alt: isApple); } - testWidgets('WordModifier-delete', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WordModifier-delete', (WidgetTester tester) async { controller.text = testText; // Place the caret after "all". controller.selection = const TextSelection.collapsed( @@ -629,7 +630,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('readonly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('readonly', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 23, @@ -647,7 +648,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -670,7 +671,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -687,7 +688,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 1, @@ -708,7 +709,7 @@ void main() { ); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('at cluster boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at cluster boundary', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 8, @@ -737,7 +738,7 @@ void main() { return SingleActivator(trigger, meta: isApple, alt: !isApple); } - testWidgets('alt-backspace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('alt-backspace', (WidgetTester tester) async { controller.text = testText; // Place the caret before "people". controller.selection = const TextSelection.collapsed( @@ -762,7 +763,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('softwrap line boundary, upstream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('softwrap line boundary, upstream', (WidgetTester tester) async { controller.text = testSoftwrapText; // Place the caret at the end of the 2nd line. controller.selection = const TextSelection.collapsed( @@ -786,7 +787,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('softwrap line boundary, downstream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('softwrap line boundary, downstream', (WidgetTester tester) async { controller.text = testSoftwrapText; // Place the caret at the beginning of the 3rd line. controller.selection = const TextSelection.collapsed( @@ -803,7 +804,7 @@ void main() { expect(controller.text, testSoftwrapText); }, variant: TargetPlatformVariant.all()); - testWidgets('readonly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('readonly', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 29, @@ -821,7 +822,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -844,7 +845,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -867,7 +868,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 1, @@ -888,7 +889,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at cluster boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at cluster boundary', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 8, @@ -917,7 +918,7 @@ void main() { return SingleActivator(trigger, meta: isApple, alt: !isApple); } - testWidgets('alt-delete', (WidgetTester tester) async { + testWidgetsWithLeakTracking('alt-delete', (WidgetTester tester) async { controller.text = testText; // Place the caret after "all". controller.selection = const TextSelection.collapsed( @@ -942,7 +943,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('softwrap line boundary, upstream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('softwrap line boundary, upstream', (WidgetTester tester) async { controller.text = testSoftwrapText; // Place the caret at the end of the 2nd line. controller.selection = const TextSelection.collapsed( @@ -961,7 +962,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('softwrap line boundary, downstream', (WidgetTester tester) async { + testWidgetsWithLeakTracking('softwrap line boundary, downstream', (WidgetTester tester) async { controller.text = testSoftwrapText; // Place the caret at the beginning of the 3rd line. controller.selection = const TextSelection.collapsed( @@ -984,7 +985,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('readonly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('readonly', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 23, @@ -1002,7 +1003,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -1025,7 +1026,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -1042,7 +1043,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('inside of a cluster', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inside of a cluster', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 1, @@ -1063,7 +1064,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('at cluster boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at cluster boundary', (WidgetTester tester) async { controller.text = testCluster; controller.selection = const TextSelection.collapsed( offset: 8, @@ -1089,7 +1090,7 @@ void main() { group('left', () { const LogicalKeyboardKey trigger = LogicalKeyboardKey.arrowLeft; - testWidgets('at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -1109,7 +1110,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('base arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('base arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 20, @@ -1123,7 +1124,7 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 7, // Before the first "the" @@ -1137,7 +1138,7 @@ void main() { )); }, variant: allExceptApple); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 24, // Before the "good". @@ -1155,7 +1156,7 @@ void main() { group('right', () { const LogicalKeyboardKey trigger = LogicalKeyboardKey.arrowRight; - testWidgets('at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -1172,7 +1173,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('base arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('base arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 20, @@ -1186,7 +1187,7 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 7, // Before the first "the" @@ -1200,7 +1201,7 @@ void main() { )); }, variant: allExceptApple); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 24, // Before the "good". @@ -1217,7 +1218,7 @@ void main() { }); group('With initial non-collapsed selection', () { - testWidgets('base arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('base arrow key movement', (WidgetTester tester) async { controller.text = testText; // The word "all" is selected. controller.selection = const TextSelection( @@ -1269,7 +1270,7 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; // "good" to "come" is selected. controller.selection = const TextSelection( @@ -1322,7 +1323,7 @@ void main() { )); }, variant: allExceptApple); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; // "good" to "come" is selected. controller.selection = const TextSelection( @@ -1378,7 +1379,7 @@ void main() { }); group('vertical movement', () { - testWidgets('at start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at start', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -1411,7 +1412,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('at end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('at end', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 72, @@ -1438,7 +1439,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('run', (WidgetTester tester) async { + testWidgetsWithLeakTracking('run', (WidgetTester tester) async { controller.text = 'aa\n' // 3 'a\n' // 3 + 2 = 5 @@ -1525,7 +1526,7 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - testWidgets('run with page down/up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('run with page down/up', (WidgetTester tester) async { controller.text = 'aa\n' // 3 'a\n' // 3 + 2 = 5 @@ -1560,7 +1561,7 @@ void main() { )); }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{TargetPlatform.iOS, TargetPlatform.macOS})); // intended: on macOS Page Up/Down only scrolls - testWidgets('run can be interrupted by layout changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('run can be interrupted by layout changes', (WidgetTester tester) async { controller.text = 'aa\n' // 3 'a\n' // 3 + 2 = 5 @@ -1589,7 +1590,7 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - testWidgets('run can be interrupted by selection changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('run can be interrupted by selection changes', (WidgetTester tester) async { controller.text = 'aa\n' // 3 'a\n' // 3 + 2 = 5 @@ -1624,7 +1625,7 @@ void main() { )); }, variant: TargetPlatformVariant.all()); - testWidgets('long run with fractional text height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long run with fractional text height', (WidgetTester tester) async { controller.text = "${'źdźbło\n' * 49}źdźbło"; controller.selection = const TextSelection.collapsed(offset: 2); await tester.pumpWidget(buildEditableText(style: const TextStyle(fontSize: 13.0, height: 1.17))); @@ -1658,7 +1659,7 @@ void main() { group('macOS shortcuts', () { final TargetPlatformVariant macOSOnly = TargetPlatformVariant.only(TargetPlatform.macOS); - testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowLeft', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 7, // Before the first "the" @@ -1672,7 +1673,7 @@ void main() { )); }, variant: macOSOnly); - testWidgets('word modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowRight', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 7, // Before the first "the" @@ -1686,7 +1687,7 @@ void main() { )); }, variant: macOSOnly); - testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowLeft', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 24, // Before the "good". @@ -1700,7 +1701,7 @@ void main() { )); }, variant: macOSOnly); - testWidgets('line modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowRight', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 24, // Before the "good". @@ -1715,7 +1716,7 @@ void main() { )); }, variant: macOSOnly); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; // "good" to "come" is selected. controller.selection = const TextSelection( @@ -1768,7 +1769,7 @@ void main() { )); }, variant: macOSOnly); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; // "good" to "come" is selected. controller.selection = const TextSelection( @@ -1828,7 +1829,7 @@ void main() { const TargetPlatformVariant appleOnly = TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS, TargetPlatform.iOS }); group('macOS shortcuts', () { - testWidgets('word modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowLeft', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 7, // Before the first "the" @@ -1840,7 +1841,7 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 7)); }, variant: appleOnly); - testWidgets('word modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrowRight', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 7, // Before the first "the" @@ -1852,7 +1853,7 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 7)); }, variant: appleOnly); - testWidgets('line modifier + arrowLeft', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowLeft', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 24, // Before the "good". @@ -1864,7 +1865,7 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 24,)); }, variant: appleOnly); - testWidgets('line modifier + arrowRight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrowRight', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 24, // Before the "good". @@ -1878,7 +1879,7 @@ void main() { )); }, variant: appleOnly); - testWidgets('word modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('word modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection( baseOffset: 24, @@ -1931,7 +1932,7 @@ void main() { )); }, variant: appleOnly); - testWidgets('line modifier + arrow key movement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('line modifier + arrow key movement', (WidgetTester tester) async { controller.text = testText; // "good" to "come" is selected. controller.selection = const TextSelection( @@ -1988,7 +1989,7 @@ void main() { }, variant: appleOnly); }); - testWidgets('vertical movement outside of selection', + testWidgetsWithLeakTracking('vertical movement outside of selection', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( @@ -2014,7 +2015,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('select all non apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all non apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -2027,7 +2028,7 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 0)); }, variant: allExceptApple); - testWidgets('select all apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed( offset: 0, @@ -2040,7 +2041,7 @@ void main() { expect(controller.selection, const TextSelection.collapsed(offset: 0)); }, variant: appleOnly); - testWidgets('copy non apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('copy non apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, @@ -2055,7 +2056,7 @@ void main() { expect(clipboardData['text'], 'empty'); }, variant: allExceptApple); - testWidgets('copy apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('copy apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, @@ -2070,7 +2071,7 @@ void main() { expect(clipboardData['text'], 'empty'); }, variant: appleOnly); - testWidgets('cut non apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cut non apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, @@ -2089,7 +2090,7 @@ void main() { )); }, variant: allExceptApple); - testWidgets('cut apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cut apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, @@ -2108,7 +2109,7 @@ void main() { )); }, variant: appleOnly); - testWidgets('paste non apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('paste non apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed(offset: 0); mockClipboard.clipboardData = <String, dynamic>{ @@ -2121,7 +2122,7 @@ void main() { expect(controller.text, testText); }, variant: allExceptApple); - testWidgets('paste apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('paste apple', (WidgetTester tester) async { controller.text = testText; controller.selection = const TextSelection.collapsed(offset: 0); mockClipboard.clipboardData = <String, dynamic>{ @@ -2137,7 +2138,7 @@ void main() { }, skip: !kIsWeb);// [intended] specific tests target web. group('Web does accept', () { - testWidgets('select up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select up', (WidgetTester tester) async { const SingleActivator selectUp = SingleActivator(LogicalKeyboardKey.arrowUp, shift: true); controller.text = testVerticalText; @@ -2159,7 +2160,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select down', (WidgetTester tester) async { const SingleActivator selectDown = SingleActivator(LogicalKeyboardKey.arrowDown, shift: true); controller.text = testVerticalText; @@ -2181,7 +2182,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select all up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all up', (WidgetTester tester) async { final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; final SingleActivator selectAllUp = isMacOS ? const SingleActivator(LogicalKeyboardKey.arrowUp, @@ -2207,7 +2208,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select all down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all down', (WidgetTester tester) async { final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; final SingleActivator selectAllDown = isMacOS ? const SingleActivator(LogicalKeyboardKey.arrowDown, @@ -2233,7 +2234,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select left', (WidgetTester tester) async { const SingleActivator selectLeft = SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true); controller.text = 'testing'; @@ -2253,7 +2254,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select right', (WidgetTester tester) async { const SingleActivator selectRight = SingleActivator(LogicalKeyboardKey.arrowRight, shift: true); controller.text = 'testing'; @@ -2273,7 +2274,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets( + testWidgetsWithLeakTracking( 'select left should not expand selection if selection is disabled', (WidgetTester tester) async { const SingleActivator selectLeft = @@ -2296,7 +2297,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets( + testWidgetsWithLeakTracking( 'select right should not expand selection if selection is disabled', (WidgetTester tester) async { const SingleActivator selectRight = @@ -2317,7 +2318,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select all left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all left', (WidgetTester tester) async { final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; final SingleActivator selectAllLeft = isMacOS ? const SingleActivator(LogicalKeyboardKey.arrowLeft, @@ -2341,7 +2342,7 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('select all right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all right', (WidgetTester tester) async { final bool isMacOS = defaultTargetPlatform == TargetPlatform.macOS; final SingleActivator selectAllRight = isMacOS ? const SingleActivator(LogicalKeyboardKey.arrowRight, diff --git a/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart b/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart index 2c4a9edbc5576..33b51dc4ccd42 100644 --- a/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart +++ b/packages/flutter/test/widgets/editable_text_show_on_screen_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/src/foundation/constants.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { _TestSliverPersistentHeaderDelegate({ @@ -40,11 +41,23 @@ class _TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate void main() { const TextStyle textStyle = TextStyle(); const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00); - final FocusNode focusNode = FocusNode(); - testWidgets('tapping on a partly visible editable brings it fully on screen', (WidgetTester tester) async { + late TextEditingController controller; + late FocusNode focusNode; + + setUp(() { + controller = TextEditingController(); + focusNode = FocusNode(); + }); + + tearDown(() { + controller.dispose(); + focusNode.dispose(); + }); + + testWidgetsWithLeakTracking('tapping on a partly visible editable brings it fully on screen', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); - final TextEditingController controller = TextEditingController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(MaterialApp( home: Center( @@ -80,10 +93,9 @@ void main() { expect(scrollController.offset, 0.0); }); - testWidgets('tapping on a partly visible editable brings it fully on screen with scrollInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tapping on a partly visible editable brings it fully on screen with scrollInsets', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + addTearDown(scrollController.dispose); await tester.pumpWidget(MaterialApp( home: Center( @@ -126,10 +138,9 @@ void main() { expect(scrollController.offset, greaterThan(200.0 - 50.0 - 5.0)); }); - testWidgets('editable comes back on screen when entering text while it is off-screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('editable comes back on screen when entering text while it is off-screen', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(initialScrollOffset: 100.0); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + addTearDown(scrollController.dispose); await tester.pumpWidget(MaterialApp( home: Center( @@ -173,12 +184,10 @@ void main() { expect(find.byType(EditableText), findsOneWidget); }); - testWidgets('entering text does not scroll when scrollPhysics.allowImplicitScrolling = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('entering text does not scroll when scrollPhysics.allowImplicitScrolling = false', (WidgetTester tester) async { // regression test for https://github.com/flutter/flutter/issues/19523 - final ScrollController scrollController = ScrollController(initialScrollOffset: 100.0); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + addTearDown(scrollController.dispose); await tester.pumpWidget(MaterialApp( home: Center( @@ -223,11 +232,10 @@ void main() { expect(find.byType(EditableText), findsNothing); }); - testWidgets('entering text does not scroll a surrounding PageView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('entering text does not scroll a surrounding PageView', (WidgetTester tester) async { // regression test for https://github.com/flutter/flutter/issues/19523 - - final TextEditingController textController = TextEditingController(); final PageController pageController = PageController(initialPage: 1); + addTearDown(pageController.dispose); await tester.pumpWidget( MaterialApp( @@ -245,7 +253,7 @@ void main() { ColoredBox( color: Colors.green, child: TextField( - controller: textController, + controller: controller, ), ), Container( @@ -261,7 +269,7 @@ void main() { await tester.showKeyboard(find.byType(EditableText)); await tester.pumpAndSettle(); - expect(textController.text, ''); + expect(controller.text, ''); tester.testTextInput.enterText('H'); final int frames = await tester.pumpAndSettle(); @@ -269,13 +277,12 @@ void main() { // that the surrounding PageView is incorrectly scrolling back-and-forth. expect(frames, 1); - expect(textController.text, 'H'); + expect(controller.text, 'H'); }); - testWidgets('focused multi-line editable scrolls caret back into view when typing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('focused multi-line editable scrolls caret back into view when typing', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + addTearDown(scrollController.dispose); controller.text = "Start${'\n' * 39}End"; await tester.pumpWidget(MaterialApp( @@ -322,10 +329,9 @@ void main() { expect(scrollController.offset, greaterThan(0.0)); }); - testWidgets('focused multi-line editable does not scroll to old position when non-collapsed selection set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('focused multi-line editable does not scroll to old position when non-collapsed selection set', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + addTearDown(scrollController.dispose); final String text = "Start${'\n' * 39}End"; controller.value = TextEditingValue(text: text, selection: TextSelection.collapsed(offset: text.length - 3)); @@ -374,11 +380,9 @@ void main() { expect(scrollController.offset, 28.0); }); - testWidgets('scrolls into view with scrollInserts after the keyboard pops up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrolls into view with scrollInserts after the keyboard pops up', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); - + addTearDown(scrollController.dispose); const Key container = Key('container'); await tester.pumpWidget(MaterialApp( @@ -418,15 +422,14 @@ void main() { expect(find.byKey(container), findsNothing); }); - testWidgets( + testWidgetsWithLeakTracking( 'A pinned persistent header should not scroll when its descendant EditableText gains focus', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25507. - ScrollController controller; - final TextEditingController textEditingController = TextEditingController(); - final FocusNode focusNode = FocusNode(); - + final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); const Key headerKey = Key('header'); + await tester.pumpWidget( MaterialApp( home: Center( @@ -434,7 +437,7 @@ void main() { height: 600.0, width: 600.0, child: CustomScrollView( - controller: controller = ScrollController(), + controller: scrollController, slivers: List<Widget>.generate(50, (int i) { return i == 10 ? SliverPersistentHeader( @@ -447,7 +450,7 @@ void main() { child: EditableText( key: headerKey, backgroundCursorColor: Colors.grey, - controller: textEditingController, + controller: controller, focusNode: focusNode, style: textStyle, cursorColor: cursorColor, @@ -469,24 +472,23 @@ void main() { ); // The persistent header should now be pinned at the top. - controller.jumpTo(100.0 * 15); + scrollController.jumpTo(100.0 * 15); await tester.pumpAndSettle(); - expect(controller.offset, 100.0 * 15); + expect(scrollController.offset, 100.0 * 15); focusNode.requestFocus(); await tester.pumpAndSettle(); // The scroll offset should remain the same. - expect(controller.offset, 100.0 * 15); + expect(scrollController.offset, 100.0 * 15); }, ); - testWidgets( + testWidgetsWithLeakTracking( 'A pinned persistent header should not scroll when its descendant EditableText gains focus (no animation)', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25507. - ScrollController controller; - final TextEditingController textEditingController = TextEditingController(); - final FocusNode focusNode = FocusNode(); + final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); const Key headerKey = Key('header'); await tester.pumpWidget( @@ -496,7 +498,7 @@ void main() { height: 600.0, width: 600.0, child: CustomScrollView( - controller: controller = ScrollController(), + controller: scrollController, slivers: List<Widget>.generate(50, (int i) { return i == 10 ? SliverPersistentHeader( @@ -510,7 +512,7 @@ void main() { child: EditableText( key: headerKey, backgroundCursorColor: Colors.grey, - controller: textEditingController, + controller: controller, focusNode: focusNode, style: textStyle, cursorColor: cursorColor, @@ -532,20 +534,19 @@ void main() { ); // The persistent header should now be pinned at the top. - controller.jumpTo(100.0 * 15); + scrollController.jumpTo(100.0 * 15); await tester.pumpAndSettle(); - expect(controller.offset, 100.0 * 15); + expect(scrollController.offset, 100.0 * 15); focusNode.requestFocus(); await tester.pumpAndSettle(); // The scroll offset should remain the same. - expect(controller.offset, 100.0 * 15); + expect(scrollController.offset, 100.0 * 15); }, ); void testShowCaretOnScreen({ required bool readOnly }) { group('EditableText._showCaretOnScreen, readOnly=$readOnly', () { - final TextEditingController textEditingController = TextEditingController(); final TextInputFormatter rejectEverythingFormatter = TextInputFormatter.withFunction((TextEditingValue old, TextEditingValue value) => old); bool isCaretOnScreen(WidgetTester tester) { @@ -574,7 +575,7 @@ void main() { const SizedBox(height: 599), EditableText( backgroundCursorColor: Colors.grey, - controller: textEditingController, + controller: controller, scrollController: editableScrollController, inputFormatters: <TextInputFormatter>[if (rejectUserInputs) rejectEverythingFormatter], focusNode: focusNode, @@ -588,11 +589,13 @@ void main() { ); } - testWidgets('focus-triggered showCaretOnScreen', (WidgetTester tester) async { - textEditingController.text = 'a' * 100; - textEditingController.selection = const TextSelection.collapsed(offset: 100); + testWidgetsWithLeakTracking('focus-triggered showCaretOnScreen', (WidgetTester tester) async { + controller.text = 'a' * 100; + controller.selection = const TextSelection.collapsed(offset: 100); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final ScrollController editableScrollController = ScrollController(); + addTearDown(editableScrollController.dispose); await tester.pumpWidget( buildEditableText( @@ -617,11 +620,13 @@ void main() { expect(editableScrollController.offset, readOnly ? 0.0 : greaterThan(0.0)); }); - testWidgets('selection-triggered showCaretOnScreen: virtual keyboard', (WidgetTester tester) async { - textEditingController.text = 'a' * 100; - textEditingController.selection = const TextSelection.collapsed(offset: 80); + testWidgetsWithLeakTracking('selection-triggered showCaretOnScreen: virtual keyboard', (WidgetTester tester) async { + controller.text = 'a' * 100; + controller.selection = const TextSelection.collapsed(offset: 80); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final ScrollController editableScrollController = ScrollController(); + addTearDown(editableScrollController.dispose); await tester.pumpWidget( buildEditableText( @@ -675,11 +680,13 @@ void main() { expect(editableScrollController.offset, readOnly && !kIsWeb ? 0.0 : greaterThan(0.0)); }); - testWidgets('selection-triggered showCaretOnScreen: text selection delegate', (WidgetTester tester) async { - textEditingController.text = 'a' * 100; - textEditingController.selection = const TextSelection.collapsed(offset: 80); + testWidgetsWithLeakTracking('selection-triggered showCaretOnScreen: text selection delegate', (WidgetTester tester) async { + controller.text = 'a' * 100; + controller.selection = const TextSelection.collapsed(offset: 80); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final ScrollController editableScrollController = ScrollController(); + addTearDown(editableScrollController.dispose); await tester.pumpWidget( buildEditableText( @@ -739,10 +746,11 @@ void main() { }); // Regression text for https://github.com/flutter/flutter/pull/74722. - testWidgets('does NOT randomly trigger when cursor blinks', (WidgetTester tester) async { - textEditingController.text = 'a' * 100; - textEditingController.selection = const TextSelection.collapsed(offset: 0); + testWidgetsWithLeakTracking('does NOT randomly trigger when cursor blinks', (WidgetTester tester) async { + controller.text = 'a' * 100; + controller.selection = const TextSelection.collapsed(offset: 0); final ScrollController editableScrollController = ScrollController(); + addTearDown(editableScrollController.dispose); final bool deterministicCursor = EditableText.debugDeterministicCursor; EditableText.debugDeterministicCursor = false; @@ -751,7 +759,7 @@ void main() { home: Scaffold( body: EditableText( backgroundCursorColor: Colors.grey, - controller: textEditingController, + controller: controller, scrollController: editableScrollController, focusNode: focusNode, style: textStyle, @@ -770,7 +778,7 @@ void main() { expect(editableScrollController.offset, 0.0); // Change the text but keep the cursor location. - state.updateEditingValue(textEditingController.value.copyWith( + state.updateEditingValue(controller.value.copyWith( text: 'a' * 101, )); diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 4efaf4992cbdd..dc5b7fb797ad4 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import 'editable_text_utils.dart'; @@ -43,9 +44,6 @@ class _MatchesMethodCall extends Matcher { } } -late TextEditingController controller; -final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Node'); -final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'EditableText Scope Node'); const TextStyle textStyle = TextStyle(); const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00); @@ -63,21 +61,29 @@ TextEditingValue collapsedAtEnd(String text) { } void main() { + late TextEditingController controller; + late FocusNode focusNode; + late FocusScopeNode focusScopeNode; + setUp(() async { final MockClipboard mockClipboard = MockClipboard(); TestWidgetsFlutterBinding.ensureInitialized() .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall); debugResetSemanticsIdCounter(); - controller = TextEditingController(); // Fill the clipboard so that the Paste option is available in the text // selection menu. await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); + controller = TextEditingController(); + focusNode = FocusNode(debugLabel: 'EditableText Node'); + focusScopeNode = FocusScopeNode(debugLabel: 'EditableText Scope Node'); }); tearDown(() { TestWidgetsFlutterBinding.ensureInitialized() .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null); controller.dispose(); + focusNode.dispose(); + focusScopeNode.dispose(); }); // Tests that the desired keyboard action button is requested. @@ -119,12 +125,11 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals(serializedActionName)); } - testWidgets( + testWidgetsWithLeakTracking( 'Tapping the Live Text button calls onLiveTextInput', (WidgetTester tester) async { bool invokedLiveTextInputSuccessfully = false; final GlobalKey key = GlobalKey(); - final TextEditingController controller = TextEditingController(text: ''); await tester.pumpWidget( MaterialApp( home: Align( @@ -136,7 +141,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.subtitle1!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -189,15 +194,20 @@ void main() { ); // Regression test for https://github.com/flutter/flutter/issues/126312. - testWidgets('when open input connection in didUpdateWidget, should not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when open input connection in didUpdateWidget, should not throw', (WidgetTester tester) async { final Key key = GlobalKey(); + final TextEditingController controller1 = TextEditingController(text: 'blah blah'); + addTearDown(controller1.dispose); + final TextEditingController controller2 = TextEditingController(text: 'blah blah'); + addTearDown(controller2.dispose); + await tester.pumpWidget( MaterialApp( home: EditableText( key: key, backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller1, focusNode: focusNode, readOnly: true, style: textStyle, @@ -219,7 +229,7 @@ void main() { child: EditableText( key: key, backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller2, focusNode: focusNode, style: textStyle, cursorColor: cursorColor, @@ -230,14 +240,13 @@ void main() { ); }); - testWidgets('Text with selection can be shown on the screen when the keyboard shown', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text with selection can be shown on the screen when the keyboard shown', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/119628 addTearDown(tester.view.reset); final ScrollController scrollController = ScrollController(); - final TextEditingController textController = TextEditingController.fromValue( - const TextEditingValue(text: 'I love flutter'), - ); + addTearDown(scrollController.dispose); + controller.value = const TextEditingValue(text: 'I love flutter'); final Widget widget = MaterialApp( home: Scaffold( @@ -249,7 +258,7 @@ void main() { SizedBox( height: 20.0, child: EditableText( - controller: textController, + controller: controller, backgroundCursorColor: Colors.grey, focusNode: focusNode, style: const TextStyle(), @@ -265,9 +274,9 @@ void main() { await tester.showKeyboard(find.byType(EditableText)); tester.view.viewInsets = const FakeViewPadding(bottom: 500); - textController.selection = TextSelection( + controller.selection = TextSelection( baseOffset: 0, - extentOffset: textController.text.length, + extentOffset: controller.text.length, ); await tester.pump(); @@ -278,10 +287,11 @@ void main() { }); // Related issue: https://github.com/flutter/flutter/issues/98115 - testWidgets('ScheduleShowCaretOnScreen with no animation when the view changes metrics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScheduleShowCaretOnScreen with no animation when the view changes metrics', (WidgetTester tester) async { addTearDown(tester.view.reset); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final Widget widget = MaterialApp( home: Scaffold( body: SingleChildScrollView( @@ -302,7 +312,7 @@ void main() { SizedBox( height: 20, child: EditableText( - controller: TextEditingController(), + controller: controller, backgroundCursorColor: Colors.grey, focusNode: focusNode, style: const TextStyle(), @@ -325,8 +335,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/34538. - testWidgets('RTL arabic correct caret placement after trailing whitespace', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('RTL arabic correct caret placement after trailing whitespace', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -379,7 +388,7 @@ void main() { expect(state.currentTextEditingValue.text, equals('گیگ ')); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/78550. - testWidgets('has expected defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has expected defaults', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -409,7 +418,7 @@ void main() { expect(editableText.textHeightBehavior, isNull); }); - testWidgets('when backgroundCursorColor is updated, RenderEditable should be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when backgroundCursorColor is updated, RenderEditable should be updated', (WidgetTester tester) async { Widget buildWidget(Color backgroundCursorColor) { return MediaQuery( data: const MediaQueryData(), @@ -433,7 +442,7 @@ void main() { expect(render.backgroundCursorColor, Colors.green); }); - testWidgets('text keyboard is requested when maxLines is default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text keyboard is requested when maxLines is default', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -465,7 +474,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.done')); }); - testWidgets('Keyboard is configured for "unspecified" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "unspecified" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.unspecified, @@ -473,7 +482,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "none" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "none" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.none, @@ -481,7 +490,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "done" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "done" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.done, @@ -489,7 +498,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "send" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "send" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.send, @@ -497,7 +506,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "go" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "go" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.go, @@ -505,7 +514,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "search" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "search" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.search, @@ -513,7 +522,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "send" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "send" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.send, @@ -521,7 +530,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "next" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "next" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.next, @@ -529,7 +538,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "previous" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "previous" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.previous, @@ -537,7 +546,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "continue" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "continue" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.continueAction, @@ -545,7 +554,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "join" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "join" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.join, @@ -553,7 +562,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "route" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "route" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.route, @@ -561,7 +570,7 @@ void main() { ); }); - testWidgets('Keyboard is configured for "emergencyCall" action when explicitly requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keyboard is configured for "emergencyCall" action when explicitly requested', (WidgetTester tester) async { await desiredKeyboardActionIsRequested( tester: tester, action: TextInputAction.emergencyCall, @@ -569,7 +578,7 @@ void main() { ); }); - testWidgets('insertContent does not throw and parses data correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('insertContent does not throw and parses data correctly', (WidgetTester tester) async { String? latestUri; await tester.pumpWidget( MediaQuery( @@ -625,7 +634,7 @@ void main() { expect(latestUri, equals(uri)); }); - testWidgets('onAppPrivateCommand does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onAppPrivateCommand does not throw', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -673,7 +682,7 @@ void main() { }); group('Infer keyboardType from autofillHints', () { - testWidgets( + testWidgetsWithLeakTracking( 'infer keyboard types from autofillHints: ios', (WidgetTester tester) async { await tester.pumpWidget( @@ -712,7 +721,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'infer keyboard types from autofillHints: non-ios', (WidgetTester tester) async { await tester.pumpWidget( @@ -745,7 +754,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'inferred keyboard types can be overridden: ios', (WidgetTester tester) async { await tester.pumpWidget( @@ -780,7 +789,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'inferred keyboard types can be overridden: non-ios', (WidgetTester tester) async { await tester.pumpWidget( @@ -815,7 +824,7 @@ void main() { ); }); - testWidgets('multiline keyboard is requested when set explicitly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiline keyboard is requested when set explicitly', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -846,7 +855,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.newline')); }); - testWidgets('EditableText sends enableInteractiveSelection to config', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText sends enableInteractiveSelection to config', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -898,7 +907,7 @@ void main() { expect(state.textInputConfiguration.enableInteractiveSelection, isFalse); }); - testWidgets('selection persists when unfocused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection persists when unfocused', (WidgetTester tester) async { const TextEditingValue value = TextEditingValue( text: 'test test', selection: TextSelection(affinity: TextAffinity.upstream, baseOffset: 5, extentOffset: 7), @@ -952,7 +961,7 @@ void main() { expect(focusNode.hasFocus, isFalse); }); - testWidgets('selection rects re-sent when refocused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection rects re-sent when refocused', (WidgetTester tester) async { final List<List<SelectionRect>> log = <List<SelectionRect>>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { if (methodCall.method == 'TextInput.setSelectionRects') { @@ -969,8 +978,8 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); controller.text = 'Text1'; Future<void> pumpEditableText({ double? width, double? height, TextAlign textAlign = TextAlign.start }) async { @@ -1034,7 +1043,7 @@ void main() { // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('EditableText does not derive selection color from DefaultSelectionStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText does not derive selection color from DefaultSelectionStyle', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/103341. const TextEditingValue value = TextEditingValue( text: 'test test', @@ -1065,7 +1074,7 @@ void main() { expect(state.renderEditable.selectionColor, null); }); - testWidgets('visiblePassword keyboard is requested when set explicitly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visiblePassword keyboard is requested when set explicitly', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1096,8 +1105,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.done')); }); - testWidgets('enableSuggestions flag is sent to the engine properly', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('enableSuggestions flag is sent to the engine properly', (WidgetTester tester) async { const bool enableSuggestions = false; await tester.pumpWidget( MediaQuery( @@ -1126,8 +1134,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['enableSuggestions'], enableSuggestions); }); - testWidgets('enableIMEPersonalizedLearning flag is sent to the engine properly', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('enableIMEPersonalizedLearning flag is sent to the engine properly', (WidgetTester tester) async { const bool enableIMEPersonalizedLearning = false; await tester.pumpWidget( MediaQuery( @@ -1157,8 +1164,7 @@ void main() { }); group('smartDashesType and smartQuotesType', () { - testWidgets('sent to the engine properly', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('sent to the engine properly', (WidgetTester tester) async { const SmartDashesType smartDashesType = SmartDashesType.disabled; const SmartQuotesType smartQuotesType = SmartQuotesType.disabled; await tester.pumpWidget( @@ -1190,8 +1196,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['smartQuotesType'], smartQuotesType.index.toString()); }); - testWidgets('default to true when obscureText is false', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('default to true when obscureText is false', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1219,8 +1224,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['smartQuotesType'], '1'); }); - testWidgets('default to false when obscureText is true', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('default to false when obscureText is true', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1250,12 +1254,9 @@ void main() { }); }); - testWidgets('selection overlay will update when text grow bigger', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController.fromValue( - const TextEditingValue( - text: 'initial value', - ), - ); + testWidgetsWithLeakTracking('selection overlay will update when text grow bigger', (WidgetTester tester) async { + controller.value = const TextEditingValue(text: 'initial value'); + Future<void> pumpEditableTextWithTextStyle(TextStyle style) async { await tester.pumpWidget( MaterialApp( @@ -1310,9 +1311,18 @@ void main() { expect(handles[1].localToGlobal(Offset.zero), const Offset(197.0, 17.0)); }); - testWidgets('can update style of previous activated EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can update style of previous activated EditableText', (WidgetTester tester) async { + final TextEditingController controller1 = TextEditingController(); + addTearDown(controller1.dispose); + final TextEditingController controller2 = TextEditingController(); + addTearDown(controller2.dispose); + final TextEditingController controller3 = TextEditingController(); + addTearDown(controller3.dispose); + final TextEditingController controller4 = TextEditingController(); + addTearDown(controller4.dispose); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); + await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1325,7 +1335,7 @@ void main() { children: <Widget>[ EditableText( key: key1, - controller: TextEditingController(), + controller: controller1, backgroundCursorColor: Colors.grey, focusNode: focusNode, style: const TextStyle(fontSize: 9), @@ -1333,7 +1343,7 @@ void main() { ), EditableText( key: key2, - controller: TextEditingController(), + controller: controller2, backgroundCursorColor: Colors.grey, focusNode: focusNode, style: const TextStyle(fontSize: 9), @@ -1368,7 +1378,7 @@ void main() { children: <Widget>[ EditableText( key: key1, - controller: TextEditingController(), + controller: controller3, backgroundCursorColor: Colors.grey, focusNode: focusNode, style: const TextStyle(fontSize: 20), @@ -1376,7 +1386,7 @@ void main() { ), EditableText( key: key2, - controller: TextEditingController(), + controller: controller4, backgroundCursorColor: Colors.grey, focusNode: focusNode, style: const TextStyle(fontSize: 9), @@ -1393,7 +1403,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Multiline keyboard with newline action is requested when maxLines = null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiline keyboard with newline action is requested when maxLines = null', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1424,7 +1434,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.newline')); }); - testWidgets('Text keyboard is requested when explicitly set and maxLines = null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text keyboard is requested when explicitly set and maxLines = null', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1456,7 +1466,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.done')); }); - testWidgets('Correct keyboard is requested when set explicitly and maxLines > 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Correct keyboard is requested when set explicitly and maxLines > 1', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1488,7 +1498,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.done')); }); - testWidgets('multiline keyboard is requested when set implicitly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('multiline keyboard is requested when set implicitly', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1519,7 +1529,7 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.newline')); }); - testWidgets('single line inputs have correct default keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('single line inputs have correct default keyboard', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1550,7 +1560,7 @@ void main() { }); // Test case for https://github.com/flutter/flutter/issues/123523. - testWidgets( + testWidgetsWithLeakTracking( 'The focus and callback behavior are correct when TextInputClient.onConnectionClosed message received', (WidgetTester tester) async { bool onSubmittedInvoked = false; @@ -1600,7 +1610,7 @@ void main() { } }); - testWidgets('connection is closed when TextInputClient.onConnectionClosed message received', (WidgetTester tester) async { + testWidgetsWithLeakTracking('connection is closed when TextInputClient.onConnectionClosed message received', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1643,7 +1653,7 @@ void main() { expect(tester.testTextInput.log, isEmpty); }); - testWidgets('closed connection reopened when user focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('closed connection reopened when user focused', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -1694,7 +1704,7 @@ void main() { expect(state.wantKeepAlive, true); }); - testWidgets('closed connection reopened when user focused on another field', (WidgetTester tester) async { + testWidgetsWithLeakTracking('closed connection reopened when user focused on another field', (WidgetTester tester) async { final EditableText testNameField = EditableText( backgroundCursorColor: Colors.grey, @@ -1769,7 +1779,7 @@ void main() { expect(state.wantKeepAlive, true); }); - testWidgets( + testWidgetsWithLeakTracking( 'kept-alive EditableText does not crash when layout is skipped', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84896. @@ -1847,7 +1857,7 @@ void main() { // cut. It might also provide additional functionality depending on the // browser (such as translation). Due to this, in browsers, we should not // show a Flutter toolbar for the editable text elements. - testWidgets('can show toolbar when there is text and a selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can show toolbar when there is text and a selection', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -1912,7 +1922,7 @@ void main() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.contextMenu, null); }); - testWidgets('web can show flutter context menu when the browser context menu is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('web can show flutter context menu when the browser context menu is disabled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -1960,7 +1970,7 @@ void main() { ); }); - testWidgets('can hide toolbar with DismissIntent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can hide toolbar with DismissIntent', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -1995,7 +2005,7 @@ void main() { expect(find.text('Paste'), findsNothing); }); - testWidgets('toolbar hidden on mobile when orientation changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toolbar hidden on mobile when orientation changes', (WidgetTester tester) async { addTearDown(tester.view.reset); await tester.pumpWidget( @@ -2043,7 +2053,7 @@ void main() { // toolbar. Until we change that, this test should remain skipped. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android })); // [intended] - testWidgets('Paste is shown only when there is something to paste', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paste is shown only when there is something to paste', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2093,8 +2103,10 @@ void main() { expect(find.text('Paste'), findsNothing); }); - testWidgets('Copy selection does not collapse selection on desktop and iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Copy selection does not collapse selection on desktop and iOS', (WidgetTester tester) async { final TextEditingController localController = TextEditingController(text: 'Hello world'); + addTearDown(localController.dispose); + await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2131,8 +2143,10 @@ void main() { expect(find.text('Copy'), findsNothing); }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows })); // [intended] - testWidgets('Copy selection collapses selection and hides the toolbar on Android and Fuchsia', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Copy selection collapses selection and hides the toolbar on Android and Fuchsia', (WidgetTester tester) async { final TextEditingController localController = TextEditingController(text: 'Hello world'); + addTearDown(localController.dispose); + await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2171,7 +2185,7 @@ void main() { expect(find.text('Copy'), findsNothing); }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia })); // [intended] - testWidgets('can show the toolbar after clearing all text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can show the toolbar after clearing all text', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/35998. await tester.pumpWidget( MaterialApp( @@ -2210,12 +2224,14 @@ void main() { expect(find.text('Paste'), kIsWeb ? findsNothing : findsOneWidget); }); - testWidgets('can dynamically disable options in toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can dynamically disable options in toolbar', (WidgetTester tester) async { + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, toolbarOptions: const ToolbarOptions( copy: true, @@ -2246,13 +2262,15 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('can dynamically disable select all option in toolbar - cupertino', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can dynamically disable select all option in toolbar - cupertino', (WidgetTester tester) async { // Regression test: https://github.com/flutter/flutter/issues/40711 + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, toolbarOptions: ToolbarOptions.empty, style: textStyle, @@ -2275,13 +2293,15 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('can dynamically disable select all option in toolbar - material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can dynamically disable select all option in toolbar - material', (WidgetTester tester) async { // Regression test: https://github.com/flutter/flutter/issues/40711 + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, toolbarOptions: const ToolbarOptions( copy: true, @@ -2311,12 +2331,14 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('cut and paste are disabled in read only mode even if explicitly set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cut and paste are disabled in read only mode even if explicitly set', (WidgetTester tester) async { + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, readOnly: true, toolbarOptions: const ToolbarOptions( @@ -2350,12 +2372,14 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('cut and copy are disabled in obscured mode even if explicitly set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cut and copy are disabled in obscured mode even if explicitly set', (WidgetTester tester) async { + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -2392,12 +2416,14 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('cut and copy do nothing in obscured mode even if explicitly called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cut and copy do nothing in obscured mode even if explicitly called', (WidgetTester tester) async { + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, obscureText: true, style: textStyle, @@ -2432,12 +2458,14 @@ void main() { expect(data!.text, isEmpty); }); - testWidgets('select all does nothing if obscured and read-only, even if explicitly called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all does nothing if obscured and read-only, even if explicitly called', (WidgetTester tester) async { + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, obscureText: true, readOnly: true, @@ -2458,11 +2486,13 @@ void main() { }); group('buttonItemsForToolbarOptions', () { - testWidgets('returns null when toolbarOptions are empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns null when toolbarOptions are empty', (WidgetTester tester) async { + controller.text = 'TEXT'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'TEXT'), + controller: controller, toolbarOptions: ToolbarOptions.empty, focusNode: focusNode, style: textStyle, @@ -2479,11 +2509,13 @@ void main() { expect(state.buttonItemsForToolbarOptions(), isNull); }); - testWidgets('returns empty array when only cut is selected in toolbarOptions but cut is not enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns empty array when only cut is selected in toolbarOptions but cut is not enabled', (WidgetTester tester) async { + controller.text = 'TEXT'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'TEXT'), + controller: controller, toolbarOptions: const ToolbarOptions(cut: true), readOnly: true, focusNode: focusNode, @@ -2502,9 +2534,9 @@ void main() { expect(state.buttonItemsForToolbarOptions(), isEmpty); }); - testWidgets('returns only cut button when only cut is selected in toolbarOptions and cut is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns only cut button when only cut is selected in toolbarOptions and cut is enabled', (WidgetTester tester) async { const String text = 'TEXT'; - final TextEditingController controller = TextEditingController(text: text); + controller.text = text; await tester.pumpWidget( MaterialApp( @@ -2547,11 +2579,13 @@ void main() { expect(data!.text, equals(text)); }); - testWidgets('returns empty array when only copy is selected in toolbarOptions but copy is not enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns empty array when only copy is selected in toolbarOptions but copy is not enabled', (WidgetTester tester) async { + controller.text = 'TEXT'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'TEXT'), + controller: controller, toolbarOptions: const ToolbarOptions(copy: true), obscureText: true, focusNode: focusNode, @@ -2570,9 +2604,9 @@ void main() { expect(state.buttonItemsForToolbarOptions(), isEmpty); }); - testWidgets('returns only copy button when only copy is selected in toolbarOptions and copy is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns only copy button when only copy is selected in toolbarOptions and copy is enabled', (WidgetTester tester) async { const String text = 'TEXT'; - final TextEditingController controller = TextEditingController(text: text); + controller.text = text; await tester.pumpWidget( MaterialApp( @@ -2615,11 +2649,13 @@ void main() { expect(data!.text, equals(text)); }); - testWidgets('returns empty array when only paste is selected in toolbarOptions but paste is not enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns empty array when only paste is selected in toolbarOptions but paste is not enabled', (WidgetTester tester) async { + controller.text = 'TEXT'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'TEXT'), + controller: controller, toolbarOptions: const ToolbarOptions(paste: true), readOnly: true, focusNode: focusNode, @@ -2638,9 +2674,9 @@ void main() { expect(state.buttonItemsForToolbarOptions(), isEmpty); }); - testWidgets('returns only paste button when only paste is selected in toolbarOptions and paste is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns only paste button when only paste is selected in toolbarOptions and paste is enabled', (WidgetTester tester) async { const String text = 'TEXT'; - final TextEditingController controller = TextEditingController(text: text); + controller.text = text; await tester.pumpWidget( MaterialApp( @@ -2680,11 +2716,13 @@ void main() { expect(controller.text, equals(text + text)); }); - testWidgets('returns empty array when only selectAll is selected in toolbarOptions but selectAll is not enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns empty array when only selectAll is selected in toolbarOptions but selectAll is not enabled', (WidgetTester tester) async { + controller.text = 'TEXT'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'TEXT'), + controller: controller, toolbarOptions: const ToolbarOptions(selectAll: true), readOnly: true, obscureText: true, @@ -2704,9 +2742,9 @@ void main() { expect(state.buttonItemsForToolbarOptions(), isEmpty); }); - testWidgets('returns only selectAll button when only selectAll is selected in toolbarOptions and selectAll is enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns only selectAll button when only selectAll is selected in toolbarOptions and selectAll is enabled', (WidgetTester tester) async { const String text = 'TEXT'; - final TextEditingController controller = TextEditingController(text: text); + controller.text = text; await tester.pumpWidget( MaterialApp( @@ -2741,9 +2779,9 @@ void main() { }); }); - testWidgets('Handles the read-only flag correctly', (WidgetTester tester) async { - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); + testWidgetsWithLeakTracking('Handles the read-only flag correctly', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; + await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2783,9 +2821,9 @@ void main() { } }); - testWidgets('Does not accept updates when read-only', (WidgetTester tester) async { - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); + testWidgetsWithLeakTracking('Does not accept updates when read-only', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; + await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2824,12 +2862,10 @@ void main() { } }); - testWidgets('Read-only fields do not format text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Read-only fields do not format text', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; late SelectionChangedCause selectionCause; - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); - await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2864,12 +2900,10 @@ void main() { } }); - testWidgets('Selection changes during Scribble interaction should have the scribble cause', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selection changes during Scribble interaction should have the scribble cause', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; late SelectionChangedCause selectionCause; - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); - await tester.pumpWidget( MaterialApp( home: EditableText( @@ -2912,9 +2946,8 @@ void main() { await tester.testTextInput.finishScribbleInteraction(); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('Requests focus and changes the selection when onScribbleFocus is called', (WidgetTester tester) async { - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); + testWidgetsWithLeakTracking('Requests focus and changes the selection when onScribbleFocus is called', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; late SelectionChangedCause selectionCause; await tester.pumpWidget( @@ -2944,9 +2977,8 @@ void main() { // will never be SelectionChangedCause.scribble. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('Declares itself for Scribble interaction if the bounds overlap the scribble rect and the widget is touchable', (WidgetTester tester) async { - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); + testWidgetsWithLeakTracking('Declares itself for Scribble interaction if the bounds overlap the scribble rect and the widget is touchable', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; await tester.pumpWidget( MaterialApp( @@ -3038,9 +3070,8 @@ void main() { // never request the scribble elements. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('single line Scribble fields can show a horizontal placeholder', (WidgetTester tester) async { - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); + testWidgetsWithLeakTracking('single line Scribble fields can show a horizontal placeholder', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; await tester.pumpWidget( MaterialApp( @@ -3113,9 +3144,8 @@ void main() { // will not handle placeholders. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('multiline Scribble fields can show a vertical placeholder', (WidgetTester tester) async { - final TextEditingController controller = - TextEditingController(text: 'Lorem ipsum dolor sit amet'); + testWidgetsWithLeakTracking('multiline Scribble fields can show a vertical placeholder', (WidgetTester tester) async { + controller.text = 'Lorem ipsum dolor sit amet'; await tester.pumpWidget( MaterialApp( @@ -3191,10 +3221,10 @@ void main() { // will not handle placeholders. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('Sends "updateConfig" when read-only flag is flipped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sends "updateConfig" when read-only flag is flipped', (WidgetTester tester) async { bool readOnly = true; late StateSetter setState; - final TextEditingController controller = TextEditingController(text: 'Lorem ipsum dolor sit amet'); + controller.text = 'Lorem ipsum dolor sit amet'; await tester.pumpWidget( MaterialApp( @@ -3229,10 +3259,10 @@ void main() { expect(tester.testTextInput.setClientArgs!['readOnly'], isFalse); }); - testWidgets('Sends "updateConfig" when obscureText is flipped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sends "updateConfig" when obscureText is flipped', (WidgetTester tester) async { bool obscureText = true; late StateSetter setState; - final TextEditingController controller = TextEditingController(text: 'Lorem'); + controller.text = 'Lorem'; await tester.pumpWidget( MaterialApp( @@ -3265,13 +3295,13 @@ void main() { expect(tester.testTextInput.setClientArgs!['obscureText'], isFalse); }); - testWidgets('Fires onChanged when text changes via TextSelectionOverlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fires onChanged when text changes via TextSelectionOverlay', (WidgetTester tester) async { late String changedValue; final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -3308,7 +3338,7 @@ void main() { TextInputAction.values.toSet(), ); - testWidgets('Handles focus correctly when action is invoked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Handles focus correctly when action is invoked', (WidgetTester tester) async { // The expectations for each of the types of TextInputAction. const Map<TextInputAction, bool> actionShouldLoseFocus = <TextInputAction, bool>{ TextInputAction.none: false, @@ -3335,7 +3365,6 @@ void main() { bool shouldFocusNext = false, bool shouldFocusPrevious = false, }) async { - final FocusNode focusNode = FocusNode(); final GlobalKey previousKey = GlobalKey(); final GlobalKey nextKey = GlobalKey(); @@ -3348,7 +3377,7 @@ void main() { ), EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -3388,13 +3417,11 @@ void main() { } }, variant: focusVariants); - testWidgets('Does not lose focus by default when "done" action is pressed and onEditingComplete is provided', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - + testWidgetsWithLeakTracking('Does not lose focus by default when "done" action is pressed and onEditingComplete is provided', (WidgetTester tester) async { final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -3422,16 +3449,14 @@ void main() { expect(focusNode.hasFocus, true); }); - testWidgets('When "done" is pressed callbacks are invoked: onEditingComplete > onSubmitted', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - + testWidgetsWithLeakTracking('When "done" is pressed callbacks are invoked: onEditingComplete > onSubmitted', (WidgetTester tester) async { bool onEditingCompleteCalled = false; bool onSubmittedCalled = false; final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -3462,16 +3487,14 @@ void main() { // and onSubmission callbacks. }); - testWidgets('When "next" is pressed callbacks are invoked: onEditingComplete > onSubmitted', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - + testWidgetsWithLeakTracking('When "next" is pressed callbacks are invoked: onEditingComplete > onSubmitted', (WidgetTester tester) async { bool onEditingCompleteCalled = false; bool onSubmittedCalled = false; final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -3502,16 +3525,14 @@ void main() { // and onSubmission callbacks. }); - testWidgets('When "newline" action is called on a Editable text with maxLines == 1 callbacks are invoked: onEditingComplete > onSubmitted', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - + testWidgetsWithLeakTracking('When "newline" action is called on a Editable text with maxLines == 1 callbacks are invoked: onEditingComplete > onSubmitted', (WidgetTester tester) async { bool onEditingCompleteCalled = false; bool onSubmittedCalled = false; final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -3541,16 +3562,14 @@ void main() { // and onSubmission callbacks. }); - testWidgets('When "newline" action is called on a Editable text with maxLines != 1, onEditingComplete and onSubmitted callbacks are not invoked.', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); - + testWidgetsWithLeakTracking('When "newline" action is called on a Editable text with maxLines != 1, onEditingComplete and onSubmitted callbacks are not invoked.', (WidgetTester tester) async { bool onEditingCompleteCalled = false; bool onSubmittedCalled = false; final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -3581,7 +3600,7 @@ void main() { assert(!onEditingCompleteCalled); }); - testWidgets( + testWidgetsWithLeakTracking( 'finalizeEditing should reset the input connection when shouldUnfocus is true but the unfocus is cancelled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84240 . @@ -3646,7 +3665,7 @@ void main() { ]))); }); - testWidgets( + testWidgetsWithLeakTracking( 'requesting focus in the onSubmitted callback should keep the onscreen keyboard visible', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/95154 . @@ -3689,10 +3708,11 @@ void main() { ]))); }); - testWidgets( + testWidgetsWithLeakTracking( 'iOS autocorrection rectangle should appear on demand and dismiss when the text changes or when focus is lost', (WidgetTester tester) async { const Color rectColor = Color(0xFFFF0000); + controller.text = 'ABCDEFG'; void verifyAutocorrectionRectVisibility({ required bool expectVisible }) { PaintPattern evaluate() { @@ -3721,9 +3741,6 @@ void main() { expect(findRenderEditable(tester), evaluate()); } - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController(text: 'ABCDEFG'); - final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, @@ -3769,17 +3786,23 @@ void main() { verifyAutocorrectionRectVisibility(expectVisible: false); }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 5}, + ), ); - testWidgets('Changing controller updates EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing controller updates EditableText', (WidgetTester tester) async { final TextEditingController controller1 = TextEditingController(text: 'Wibble'); + addTearDown(controller1.dispose); final TextEditingController controller2 = TextEditingController(text: 'Wobble'); + addTearDown(controller2.dispose); TextEditingController currentController = controller1; late StateSetter setState; - final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); Widget builder() { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -3858,7 +3881,7 @@ void main() { ); }); - testWidgets('EditableText identifies as text field (w/ focus) in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText identifies as text field (w/ focus) in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -3898,7 +3921,7 @@ void main() { semantics.dispose(); }); - testWidgets('EditableText sets multi-line flag in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText sets multi-line flag in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -3958,11 +3981,10 @@ void main() { semantics.dispose(); }); - testWidgets('EditableText includes text as value in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText includes text as value in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const String value1 = 'EditableText content'; - controller.text = value1; await tester.pumpWidget( @@ -4008,7 +4030,7 @@ void main() { semantics.dispose(); }); - testWidgets('exposes correct cursor movement semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('exposes correct cursor movement semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); controller.text = 'test'; @@ -4091,7 +4113,7 @@ void main() { semantics.dispose(); }); - testWidgets('can move cursor with a11y means - character', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can move cursor with a11y means - character', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const bool doNotExtendSelection = false; @@ -4196,7 +4218,7 @@ void main() { semantics.dispose(); }); - testWidgets('can move cursor with a11y means - word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can move cursor with a11y means - word', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const bool doNotExtendSelection = false; @@ -4309,7 +4331,7 @@ void main() { semantics.dispose(); }); - testWidgets('can extend selection with a11y means - character', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can extend selection with a11y means - character', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const bool extendSelection = true; const bool doNotExtendSelection = false; @@ -4425,7 +4447,7 @@ void main() { semantics.dispose(); }); - testWidgets('can extend selection with a11y means - word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can extend selection with a11y means - word', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const bool extendSelection = true; const bool doNotExtendSelection = false; @@ -4539,7 +4561,7 @@ void main() { semantics.dispose(); }); - testWidgets('password fields have correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('password fields have correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); controller.text = 'super-secret-password!!1'; @@ -4594,7 +4616,7 @@ void main() { semantics.dispose(); }); - testWidgets('password fields become obscured with the right semantics when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('password fields become obscured with the right semantics when set', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const String originalText = 'super-secret-password!!1'; @@ -4709,7 +4731,7 @@ void main() { semantics.dispose(); }); - testWidgets('password fields can have their obscuring character customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('password fields can have their obscuring character customized', (WidgetTester tester) async { const String originalText = 'super-secret-password!!1'; controller.text = originalText; @@ -4730,7 +4752,7 @@ void main() { expect((findRenderEditable(tester).text! as TextSpan).text, expectedValue); }); - testWidgets('password briefly shows last character when entered on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('password briefly shows last character when entered on mobile', (WidgetTester tester) async { final bool debugDeterministicCursor = EditableText.debugDeterministicCursor; EditableText.debugDeterministicCursor = false; addTearDown(() { @@ -4784,7 +4806,7 @@ void main() { controls = MockTextSelectionControls(); }); - testWidgets('are exposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('are exposed', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); controls.testCanCopy = false; @@ -4881,7 +4903,7 @@ void main() { semantics.dispose(); }); - testWidgets('can copy/cut/paste with a11y', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can copy/cut/paste with a11y', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); controls.testCanCopy = true; @@ -4954,10 +4976,11 @@ void main() { }); // Regression test for b/201218542. - testWidgets('copying with a11y works even when toolbar is hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('copying with a11y works even when toolbar is hidden', (WidgetTester tester) async { Future<void> testByControls(TextSelectionControls controls) async { final SemanticsTester semantics = SemanticsTester(tester); final TextEditingController controller = TextEditingController(text: 'ABCDEFG'); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: EditableText( @@ -4999,7 +5022,7 @@ void main() { }); }); - testWidgets('can set text with a11y', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can set text with a11y', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( home: EditableText( @@ -5064,7 +5087,7 @@ void main() { semantics.dispose(); }); - testWidgets('allows customizing text style in subclasses', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows customizing text style in subclasses', (WidgetTester tester) async { controller.text = 'Hello World'; await tester.pumpWidget(MaterialApp( @@ -5081,9 +5104,8 @@ void main() { expect(render.text!.style!.fontStyle, FontStyle.italic); }); - testWidgets('onChanged callback only invoked on text changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callback only invoked on text changes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/111651 . - final TextEditingController controller = TextEditingController(); int onChangedCount = 0; bool preventInput = false; final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) { @@ -5096,7 +5118,7 @@ void main() { controller: controller, backgroundCursorColor: Colors.red, cursorColor: Colors.red, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, onChanged: (String newString) { onChangedCount += 1; }, inputFormatters: <TextInputFormatter>[formatter], @@ -5127,20 +5149,19 @@ void main() { expect(onChangedCount , 2); }); - testWidgets('Formatters are skipped if text has not changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Formatters are skipped if text has not changed', (WidgetTester tester) async { int called = 0; final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) { called += 1; return newValue; }); - final TextEditingController controller = TextEditingController(); final MediaQuery mediaQuery = MediaQuery( data: const MediaQueryData(), child: EditableText( controller: controller, backgroundCursorColor: Colors.red, cursorColor: Colors.red, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, inputFormatters: <TextInputFormatter>[ formatter, @@ -5171,7 +5192,7 @@ void main() { expect(called, 2); }); - testWidgets('default keyboardAppearance is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default keyboardAppearance is respected', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/22212. final List<MethodCall> log = <MethodCall>[]; @@ -5180,7 +5201,6 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController(); await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -5188,7 +5208,7 @@ void main() { textDirection: TextDirection.ltr, child: EditableText( controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -5203,14 +5223,13 @@ void main() { expect(((setClient.arguments as Iterable<dynamic>).last as Map<String, dynamic>)['keyboardAppearance'], 'Brightness.light'); }); - testWidgets('location of widget is sent on show keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('location of widget is sent on show keyboard', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); return null; }); - final TextEditingController controller = TextEditingController(); await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -5218,7 +5237,7 @@ void main() { textDirection: TextDirection.ltr, child: EditableText( controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -5239,7 +5258,7 @@ void main() { ); }); - testWidgets('transform and size is reset when text connection opens', (WidgetTester tester) async { + testWidgetsWithLeakTracking('transform and size is reset when text connection opens', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); @@ -5247,7 +5266,13 @@ void main() { }); final TextEditingController controller1 = TextEditingController(); + addTearDown(controller1.dispose); + final FocusNode focusNode1 = FocusNode(); + addTearDown(focusNode1.dispose); final TextEditingController controller2 = TextEditingController(); + addTearDown(controller2.dispose); + final FocusNode focusNode2 = FocusNode(); + addTearDown(focusNode2.dispose); controller1.text = 'Text1'; controller2.text = 'Text2'; @@ -5262,7 +5287,7 @@ void main() { EditableText( key: ValueKey<String>(controller1.text), controller: controller1, - focusNode: FocusNode(), + focusNode: focusNode1, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -5271,7 +5296,7 @@ void main() { EditableText( key: ValueKey<String>(controller2.text), controller: controller2, - focusNode: FocusNode(), + focusNode: focusNode2, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -5325,7 +5350,7 @@ void main() { ); }); - testWidgets('size and transform are sent when they change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('size and transform are sent when they change', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); @@ -5368,7 +5393,7 @@ void main() { ); }); - testWidgets('selection rects are sent when they change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection rects are sent when they change', (WidgetTester tester) async { addTearDown(tester.view.reset); // Ensure selection rects are sent on iPhone (using SE 3rd gen size) tester.view.physicalSize = const Size(750.0, 1334.0); @@ -5389,8 +5414,8 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); controller.text = 'Text1'; Future<void> pumpEditableText({ double? width, double? height, TextAlign textAlign = TextAlign.start }) async { @@ -5508,14 +5533,13 @@ void main() { // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('selection rects are not sent if scribbleEnabled is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection rects are not sent if scribbleEnabled is false', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); return null; }); - final TextEditingController controller = TextEditingController(); controller.text = 'Text1'; await tester.pumpWidget( @@ -5529,7 +5553,7 @@ void main() { EditableText( key: ValueKey<String>(controller.text), controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -5548,7 +5572,7 @@ void main() { // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('selection rects sent even when character corners are outside of paintBounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection rects sent even when character corners are outside of paintBounds', (WidgetTester tester) async { final List<List<SelectionRect>> log = <List<SelectionRect>>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) { if (methodCall.method == 'TextInput.setSelectionRects') { @@ -5565,8 +5589,8 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); controller.text = 'Text1'; final GlobalKey<EditableTextState> editableTextKey = GlobalKey(); @@ -5606,7 +5630,9 @@ void main() { // Scroll so that the top of each character is above the top of the renderEditable // and the bottom of each character is below the bottom of the renderEditable. - editableTextKey.currentState!.renderEditable.offset = ViewportOffset.fixed(0.5); + final ViewportOffset offset = ViewportOffset.fixed(0.5); + addTearDown(offset.dispose); + editableTextKey.currentState!.renderEditable.offset = offset; await tester.showKeyboard(find.byType(EditableText)); // We should get all the rects. @@ -5622,21 +5648,20 @@ void main() { // On web, we should rely on the browser's implementation of Scribble, so we will not send selection rects. }, skip: kIsWeb, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); // [intended] - testWidgets('text styling info is sent on show keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text styling info is sent on show keyboard', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); return null; }); - final TextEditingController controller = TextEditingController(); await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), child: EditableText( textDirection: TextDirection.rtl, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle( fontSize: 20.0, fontFamily: 'Roboto', @@ -5662,21 +5687,20 @@ void main() { ); }); - testWidgets('text styling info is sent on show keyboard (bold override)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text styling info is sent on show keyboard (bold override)', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); return null; }); - final TextEditingController controller = TextEditingController(); await tester.pumpWidget( MediaQuery( data: const MediaQueryData(boldText: true), child: EditableText( textDirection: TextDirection.rtl, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle( fontSize: 20.0, fontFamily: 'Roboto', @@ -5702,7 +5726,7 @@ void main() { ); }); - testWidgets('text styling info is sent on style update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text styling info is sent on style update', (WidgetTester tester) async { final GlobalKey<EditableTextState> editableTextKey = GlobalKey<EditableTextState>(); late StateSetter setState; const TextStyle textStyle1 = TextStyle( @@ -5732,7 +5756,7 @@ void main() { backgroundCursorColor: Colors.grey, key: editableTextKey, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: currentTextStyle, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -5787,7 +5811,7 @@ void main() { child: EditableText( backgroundCursorColor: Colors.grey, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -5801,7 +5825,7 @@ void main() { ); } - testWidgets( + testWidgetsWithLeakTracking( 'called with proper coordinates', (WidgetTester tester) async { controller.value = TextEditingValue(text: 'a' * 50); @@ -5843,7 +5867,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'only send updates when necessary', (WidgetTester tester) async { controller.value = TextEditingValue(text: 'a' * 100); @@ -5861,7 +5885,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'not sent with selection', (WidgetTester tester) async { controller.value = TextEditingValue( @@ -5888,7 +5912,7 @@ void main() { child: EditableText( backgroundCursorColor: Colors.grey, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -5902,7 +5926,7 @@ void main() { ); } - testWidgets( + testWidgetsWithLeakTracking( 'called when the composing range changes', (WidgetTester tester) async { controller.value = TextEditingValue(text: 'a' * 100); @@ -5936,7 +5960,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'only send updates when necessary', (WidgetTester tester) async { controller.value = TextEditingValue(text: 'a' * 100, composing: const TextRange(start: 0, end: 10)); @@ -5954,7 +5978,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'zero matrix paint transform', (WidgetTester tester) async { controller.value = TextEditingValue(text: 'a' * 100, composing: const TextRange(start: 0, end: 10)); @@ -5976,7 +6000,7 @@ void main() { }); - testWidgets('custom keyboardAppearance is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('custom keyboardAppearance is respected', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/22212. final List<MethodCall> log = <MethodCall>[]; @@ -5985,7 +6009,6 @@ void main() { return null; }); - final TextEditingController controller = TextEditingController(); await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -5993,7 +6016,7 @@ void main() { textDirection: TextDirection.ltr, child: EditableText( controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -6009,15 +6032,12 @@ void main() { expect(((setClient.arguments as Iterable<dynamic>).last as Map<String, dynamic>)['keyboardAppearance'], 'Brightness.dark'); }); - testWidgets('Composing text is underlined and underline is cleared when losing focus', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController.fromValue( - const TextEditingValue( - text: 'text composing text', - selection: TextSelection.collapsed(offset: 14), - composing: TextRange(start: 5, end: 14), - ), + testWidgetsWithLeakTracking('Composing text is underlined and underline is cleared when losing focus', (WidgetTester tester) async { + controller.value = const TextEditingValue( + text: 'text composing text', + selection: TextSelection.collapsed(offset: 14), + composing: TextRange(start: 5, end: 14), ); - final FocusNode focusNode = FocusNode(debugLabel: 'Test Focus Node'); await tester.pumpWidget(MaterialApp( // So we can show overlays. home: EditableText( @@ -6057,9 +6077,8 @@ void main() { expect(renderEditable.text!.style!.decoration, isNull); }); - testWidgets('text selection toolbar visibility', (WidgetTester tester) async { - const String testText = 'hello \n world \n this \n is \n text'; - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('text selection toolbar visibility', (WidgetTester tester) async { + controller.text = 'hello \n world \n this \n is \n text'; await tester.pumpWidget(MaterialApp( home: Align( @@ -6070,7 +6089,7 @@ void main() { child: EditableText( showSelectionHandles: true, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -6126,10 +6145,9 @@ void main() { // toolbar. Until we change that, this test should remain skipped. }, skip: kIsWeb); // [intended] - testWidgets('text selection handle visibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text selection handle visibility', (WidgetTester tester) async { // Text with two separate words to select. - const String testText = 'XXXXX XXXXX'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = 'XXXXX XXXXX'; await tester.pumpWidget(MaterialApp( home: Align( @@ -6139,7 +6157,7 @@ void main() { child: EditableText( showSelectionHandles: true, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -6298,10 +6316,9 @@ void main() { // toolbar. Until we change that, this test should remain skipped. }, skip: kIsWeb); // [intended] - testWidgets('text selection handle visibility RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text selection handle visibility RTL', (WidgetTester tester) async { // Text with two separate words to select. - const String testText = 'XXXXX XXXXX'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = 'XXXXX XXXXX'; await tester.pumpWidget(MaterialApp( home: Align( @@ -6311,7 +6328,7 @@ void main() { child: EditableText( controller: controller, showSelectionHandles: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -6368,7 +6385,7 @@ void main() { Future<void> testTextEditing(WidgetTester tester, {required TargetPlatform targetPlatform}) async { final String targetPlatformString = targetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -6386,7 +6403,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -7367,7 +7384,7 @@ void main() { } } - testWidgets('keyboard text selection works (RawKeyEvent)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard text selection works (RawKeyEvent)', (WidgetTester tester) async { debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.rawKeyData; await testTextEditing(tester, targetPlatform: defaultTargetPlatform); @@ -7377,7 +7394,7 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('keyboard text selection works (ui.KeyData then RawKeyEvent)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard text selection works (ui.KeyData then RawKeyEvent)', (WidgetTester tester) async { debugKeyEventSimulatorTransitModeOverride = KeyDataTransitMode.keyDataThenRawKeyData; await testTextEditing(tester, targetPlatform: defaultTargetPlatform); @@ -7387,11 +7404,11 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets( + testWidgetsWithLeakTracking( 'keyboard shortcuts respect read-only', (WidgetTester tester) async { final String platform = defaultTargetPlatform.name.toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: testText.length ~/2, @@ -7407,7 +7424,7 @@ void main() { readOnly: true, controller: controller, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -7566,10 +7583,10 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('home/end keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('home/end keys', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -7587,7 +7604,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -7712,11 +7729,11 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('home keys and wordwraps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('home keys and wordwraps', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); const String testText = 'Now is the time for all good people to come to the aid of their country. Now is the time for all good people to come to the aid of their country.'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -7734,7 +7751,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -7868,11 +7885,11 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('end keys and wordwraps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('end keys and wordwraps', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); const String testText = 'Now is the time for all good people to come to the aid of their country. Now is the time for all good people to come to the aid of their country.'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -7890,7 +7907,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8026,10 +8043,10 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('shift + home/end keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shift + home/end keys', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8047,7 +8064,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8220,8 +8237,8 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('shift + home/end keys (Windows only)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('shift + home/end keys (Windows only)', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8237,7 +8254,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8331,9 +8348,9 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.windows }) ); - testWidgets('home/end keys scrolling (Mac only)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('home/end keys scrolling (Mac only)', (WidgetTester tester) async { const String testText = 'Now is the time for all good people to come to the aid of their country. Now is the time for all good people to come to the aid of their country.'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8349,7 +8366,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8392,11 +8409,11 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) ); - testWidgets('shift + home keys and wordwraps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shift + home keys and wordwraps', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); const String testText = 'Now is the time for all good people to come to the aid of their country. Now is the time for all good people to come to the aid of their country.'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8414,7 +8431,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8577,11 +8594,11 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('shift + end keys and wordwraps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shift + end keys and wordwraps', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); const String testText = 'Now is the time for all good people to come to the aid of their country. Now is the time for all good people to come to the aid of their country.'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8599,7 +8616,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8764,9 +8781,9 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('shift + home/end keys to document boundary (Mac only)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shift + home/end keys to document boundary (Mac only)', (WidgetTester tester) async { const String testText = 'Now is the time for all good people to come to the aid of their country. Now is the time for all good people to come to the aid of their country.'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8783,7 +8800,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8868,8 +8885,8 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) ); - testWidgets('control + home/end keys (Windows only)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('control + home/end keys (Windows only)', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8885,7 +8902,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -8933,8 +8950,8 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.windows }) ); - testWidgets('control + shift + home/end keys (Windows only)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('control + shift + home/end keys (Windows only)', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -8950,7 +8967,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9020,14 +9037,15 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.windows }) ); - testWidgets('pageup/pagedown keys on Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('pageup/pagedown keys on Apple platforms', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, affinity: TextAffinity.upstream, ); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); const int lines = 2; await tester.pumpWidget(MaterialApp( home: Align( @@ -9041,7 +9059,7 @@ void main() { scrollController: scrollController, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.subtitle1!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9115,14 +9133,15 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('pageup/pagedown keys in a one line field on Apple platforms', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('pageup/pagedown keys in a one line field on Apple platforms', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, affinity: TextAffinity.upstream, ); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(MaterialApp( home: Align( alignment: Alignment.topLeft, @@ -9134,7 +9153,7 @@ void main() { scrollController: scrollController, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.subtitle1!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9193,10 +9212,9 @@ void main() { ); // Regression test for https://github.com/flutter/flutter/issues/31287 - testWidgets('text selection handle visibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text selection handle visibility', (WidgetTester tester) async { // Text with two separate words to select. - const String testText = 'XXXXX XXXXX'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = 'XXXXX XXXXX'; await tester.pumpWidget(MaterialApp( home: Align( @@ -9206,7 +9224,7 @@ void main() { child: EditableText( showSelectionHandles: true, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018(platform: TargetPlatform.iOS).black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9365,10 +9383,9 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }) ); - testWidgets("scrolling doesn't bounce", (WidgetTester tester) async { + testWidgetsWithLeakTracking("scrolling doesn't bounce", (WidgetTester tester) async { // 3 lines of text, where the last line overflows and requires scrolling. - const String testText = 'XXXXX\nXXXXX\nXXXXX'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = 'XXXXX\nXXXXX\nXXXXX'; await tester.pumpWidget(MaterialApp( home: Align( @@ -9379,7 +9396,7 @@ void main() { showSelectionHandles: true, maxLines: 2, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9415,11 +9432,13 @@ void main() { expect(scrollable.controller!.position.pixels, equals(renderEditable.maxScrollExtent)); }); - testWidgets('bringIntoView brings the caret into view when in a viewport', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bringIntoView brings the caret into view when in a viewport', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/55547. - final TextEditingController controller = TextEditingController(text: testText * 20); + controller.text = testText * 20; final ScrollController editableScrollController = ScrollController(); + addTearDown(editableScrollController.dispose); final ScrollController outerController = ScrollController(); + addTearDown(outerController.dispose); await tester.pumpWidget(MaterialApp( home: Align( @@ -9433,7 +9452,7 @@ void main() { maxLines: null, controller: controller, scrollController: editableScrollController, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9457,9 +9476,10 @@ void main() { expect(editableScrollController.offset, 0); }); - testWidgets('bringIntoView does nothing if the physics prohibits implicit scrolling', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText * 20); + testWidgetsWithLeakTracking('bringIntoView does nothing if the physics prohibits implicit scrolling', (WidgetTester tester) async { + controller.text = testText * 20; final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Future<void> buildWithPhysics({ ScrollPhysics? physics }) async { await tester.pumpWidget(MaterialApp( @@ -9472,7 +9492,7 @@ void main() { maxLines: null, controller: controller, scrollController: scrollController, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9504,15 +9524,18 @@ void main() { expect(scrollController.offset, 0); }); - testWidgets('can change scroll controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can change scroll controller', (WidgetTester tester) async { + controller.text = 'A' * 1000; final _TestScrollController scrollController1 = _TestScrollController(); + addTearDown(scrollController1.dispose); final _TestScrollController scrollController2 = _TestScrollController(); + addTearDown(scrollController2.dispose); await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A' * 1000), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9528,8 +9551,8 @@ void main() { await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A' * 1000), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9545,8 +9568,8 @@ void main() { await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A' * 1000), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9561,8 +9584,8 @@ void main() { await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A' * 1000), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9575,15 +9598,15 @@ void main() { expect(scrollController2.attached, isTrue); }); - testWidgets('getLocalRectForCaret does not throw when it sees an infinite point', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getLocalRectForCaret does not throw when it sees an infinite point', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: SkipPainting( child: Transform( transform: Matrix4.zero(), child: EditableText( - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -9599,8 +9622,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('obscured multiline fields throw an exception', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('obscured multiline fields throw an exception', (WidgetTester tester) async { expect( () { EditableText( @@ -9631,33 +9653,32 @@ void main() { }); group('batch editing', () { - final TextEditingController controller = TextEditingController(text: testText); - final EditableText editableText = EditableText( - showSelectionHandles: true, - maxLines: 2, - controller: controller, - focusNode: FocusNode(), - cursorColor: Colors.red, - backgroundCursorColor: Colors.blue, - style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), - keyboardType: TextInputType.text, - ); - - final Widget widget = MediaQuery( - data: const MediaQueryData(), - child: Directionality( - textDirection: TextDirection.ltr, - child: editableText, - ), - ); + Widget buildWidget() { + return MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: EditableText( + showSelectionHandles: true, + maxLines: 2, + controller: controller, + focusNode: focusNode, + cursorColor: Colors.red, + backgroundCursorColor: Colors.blue, + style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), + keyboardType: TextInputType.text, + ), + ), + ); + } - testWidgets('batch editing works', (WidgetTester tester) async { - await tester.pumpWidget(widget); + testWidgetsWithLeakTracking('batch editing works', (WidgetTester tester) async { + await tester.pumpWidget(buildWidget()); // Connect. await tester.showKeyboard(find.byType(EditableText)); - final EditableTextState state = tester.state<EditableTextState>(find.byWidget(editableText)); + final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); state.updateEditingValue(const TextEditingValue(text: 'remote value')); tester.testTextInput.log.clear(); @@ -9690,13 +9711,13 @@ void main() { ); }); - testWidgets('batch edits need to be nested properly', (WidgetTester tester) async { - await tester.pumpWidget(widget); + testWidgetsWithLeakTracking('batch edits need to be nested properly', (WidgetTester tester) async { + await tester.pumpWidget(buildWidget()); // Connect. await tester.showKeyboard(find.byType(EditableText)); - final EditableTextState state = tester.state<EditableTextState>(find.byWidget(editableText)); + final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); state.updateEditingValue(const TextEditingValue(text: 'remote value')); tester.testTextInput.log.clear(); @@ -9710,13 +9731,13 @@ void main() { expect(errorString, contains('Unbalanced call to endBatchEdit')); }); - testWidgets('catch unfinished batch edits on disposal', (WidgetTester tester) async { - await tester.pumpWidget(widget); + testWidgetsWithLeakTracking('catch unfinished batch edits on disposal', (WidgetTester tester) async { + await tester.pumpWidget(buildWidget()); // Connect. await tester.showKeyboard(find.byType(EditableText)); - final EditableTextState state = tester.state<EditableTextState>(find.byWidget(editableText)); + final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); state.updateEditingValue(const TextEditingValue(text: 'remote value')); tester.testTextInput.log.clear(); @@ -9729,12 +9750,12 @@ void main() { }); group('EditableText does not send editing values more than once', () { - Widget boilerplate(TextEditingController controller) { + Widget boilerplate() { final EditableText editableText = EditableText( showSelectionHandles: true, maxLines: 2, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -9760,9 +9781,9 @@ void main() { ); } - testWidgets('input from text input plugin', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); - await tester.pumpWidget(boilerplate(controller)); + testWidgetsWithLeakTracking('input from text input plugin', (WidgetTester tester) async { + controller.text = testText; + await tester.pumpWidget(boilerplate()); // Connect. await tester.showKeyboard(find.byType(EditableText)); @@ -9790,9 +9811,9 @@ void main() { expect(tester.testTextInput.log, isEmpty); }); - testWidgets('input from text selection menu', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); - await tester.pumpWidget(boilerplate(controller)); + testWidgetsWithLeakTracking('input from text selection menu', (WidgetTester tester) async { + controller.text = testText; + await tester.pumpWidget(boilerplate()); // Connect. await tester.showKeyboard(find.byType(EditableText)); @@ -9815,9 +9836,9 @@ void main() { tester.testTextInput.log.clear(); }); - testWidgets('input from controller', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); - await tester.pumpWidget(boilerplate(controller)); + testWidgetsWithLeakTracking('input from controller', (WidgetTester tester) async { + controller.text = testText; + await tester.pumpWidget(boilerplate()); // Connect. await tester.showKeyboard(find.byType(EditableText)); @@ -9832,8 +9853,7 @@ void main() { expect(updates, <TextEditingValue>[collapsedAtEnd('remoteremoteremote listener')]); }); - testWidgets('input from changing controller', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('input from changing controller', (WidgetTester tester) async { Widget build({ TextEditingController? textEditingController }) { return MediaQuery( data: const MediaQueryData(), @@ -9843,7 +9863,7 @@ void main() { showSelectionHandles: true, maxLines: 2, controller: textEditingController ?? controller, - focusNode: FocusNode(), + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -9859,7 +9879,9 @@ void main() { // Connect. await tester.showKeyboard(find.byType(EditableText)); tester.testTextInput.log.clear(); - await tester.pumpWidget(build(textEditingController: TextEditingController(text: 'new text'))); + final TextEditingController controller1 = TextEditingController(text: 'new text'); + addTearDown(controller1.dispose); + await tester.pumpWidget(build(textEditingController: controller1)); List<TextEditingValue> updates = tester.testTextInput.log .where((MethodCall call) => call.method == 'TextInput.setEditingState') @@ -9869,7 +9891,9 @@ void main() { expect(updates, const <TextEditingValue>[TextEditingValue(text: 'new text')]); tester.testTextInput.log.clear(); - await tester.pumpWidget(build(textEditingController: TextEditingController(text: 'new new text'))); + final TextEditingController controller2 = TextEditingController(text: 'new new text'); + addTearDown(controller2.dispose); + await tester.pumpWidget(build(textEditingController: controller2)); updates = tester.testTextInput.log .where((MethodCall call) => call.method == 'TextInput.setEditingState') @@ -9880,14 +9904,13 @@ void main() { }); }); - testWidgets('input imm channel calls are ordered correctly', (WidgetTester tester) async { - const String testText = 'flutter is the best!'; - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('input imm channel calls are ordered correctly', (WidgetTester tester) async { + controller.text = 'flutter is the best!'; final EditableText et = EditableText( showSelectionHandles: true, maxLines: 2, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -9928,26 +9951,34 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'keyboard is requested after setEditingState after switching to a new text field', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/68571. + final TextEditingController controller1 = TextEditingController(); + addTearDown(controller1.dispose); + final FocusNode focusNode1 = FocusNode(); + addTearDown(focusNode1.dispose); final EditableText editableText1 = EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller1, + focusNode: focusNode1, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), keyboardType: TextInputType.text, ); + final TextEditingController controller2 = TextEditingController(); + addTearDown(controller2.dispose); + final FocusNode focusNode2 = FocusNode(); + addTearDown(focusNode2.dispose); final EditableText editableText2 = EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller2, + focusNode: focusNode2, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -9990,15 +10021,18 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'Autofill does not request focus', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91354 . + final TextEditingController controller1 = TextEditingController(); + addTearDown(controller1.dispose); final FocusNode focusNode1 = FocusNode(); + addTearDown(focusNode1.dispose); final EditableText editableText1 = EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController(), + controller: controller1, focusNode: focusNode1, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, @@ -10006,11 +10040,14 @@ void main() { keyboardType: TextInputType.text, ); + final TextEditingController controller2 = TextEditingController(); + addTearDown(controller2.dispose); final FocusNode focusNode2 = FocusNode(); + addTearDown(focusNode2.dispose); final EditableText editableText2 = EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController(), + controller: controller2, focusNode: focusNode2, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, @@ -10041,15 +10078,14 @@ void main() { expect(focusNode2.hasFocus, isFalse); }); - testWidgets('setEditingState is not called when text changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setEditingState is not called when text changes', (WidgetTester tester) async { // We shouldn't get a message here because this change is owned by the platform side. - const String testText = 'flutter is the best!'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = 'flutter is the best!'; final EditableText et = EditableText( showSelectionHandles: true, maxLines: 2, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -10090,15 +10126,14 @@ void main() { expect(tester.testTextInput.editingState!['text'], 'flutter is the best!'); }); - testWidgets('setEditingState is called when text changes on controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setEditingState is called when text changes on controller', (WidgetTester tester) async { // We should get a message here because this change is owned by the framework side. - const String testText = 'flutter is the best!'; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = 'flutter is the best!'; final EditableText et = EditableText( showSelectionHandles: true, maxLines: 2, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -10140,7 +10175,7 @@ void main() { expect(tester.testTextInput.editingState!['text'], 'flutter is the best!...'); }); - testWidgets('Synchronous test of local and remote editing values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Synchronous test of local and remote editing values', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/65059 final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { @@ -10153,10 +10188,8 @@ void main() { } return newValue; }); - final TextEditingController controller = TextEditingController(); late StateSetter setState; - final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); Widget builder() { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -10271,7 +10304,7 @@ void main() { ); }); - testWidgets('Send text input state to engine when the input formatter rejects user input', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Send text input state to engine when the input formatter rejects user input', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/67828 final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { @@ -10281,9 +10314,7 @@ void main() { final TextInputFormatter formatter = TextInputFormatter.withFunction((TextEditingValue oldValue, TextEditingValue newValue) { return collapsedAtEnd('Flutter is the best!'); }); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); Widget builder() { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -10346,16 +10377,14 @@ void main() { ))); }); - testWidgets('Repeatedly receiving [TextEditingValue] will not trigger a keyboard request', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Repeatedly receiving [TextEditingValue] will not trigger a keyboard request', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66036 final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); return null; }); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); Widget builder() { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -10433,8 +10462,7 @@ void main() { }); group('TextEditingController', () { - testWidgets('TextEditingController.text set to empty string clears field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('TextEditingController.text set to empty string clears field', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: MediaQuery( @@ -10468,16 +10496,14 @@ void main() { expect(find.text('...'), findsNothing); }); - testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextEditingController.clear() behavior test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66316 final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall methodCall) async { log.add(methodCall); return null; }); - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); Widget builder() { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -10543,8 +10569,9 @@ void main() { ); }); - testWidgets('TextEditingController.buildTextSpan receives build context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextEditingController.buildTextSpan receives build context', (WidgetTester tester) async { final _AccentColorTextEditingController controller = _AccentColorTextEditingController('a'); + addTearDown(controller.dispose); const Color color = Color.fromARGB(255, 1, 2, 3); final ThemeData lightTheme = ThemeData.light(); await tester.pumpWidget(MaterialApp( @@ -10553,7 +10580,7 @@ void main() { ), home: EditableText( controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -10565,9 +10592,8 @@ void main() { expect(textSpan.style!.color, color); }); - testWidgets('controller listener changes value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('controller listener changes value', (WidgetTester tester) async { const double maxValue = 5.5555; - final TextEditingController controller = TextEditingController(); controller.addListener(() { final double value = double.tryParse(controller.text.trim()) ?? .0; @@ -10601,8 +10627,8 @@ void main() { }); }); - testWidgets('autofocus:true on first frame does not throw', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('autofocus:true on first frame does not throw', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -10615,7 +10641,7 @@ void main() { controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -10632,7 +10658,7 @@ void main() { expect(exception, isNull); }); - testWidgets('updateEditingValue filters multiple calls from formatter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('updateEditingValue filters multiple calls from formatter', (WidgetTester tester) async { final MockTextFormatter formatter = MockTextFormatter(); await tester.pumpWidget( MediaQuery( @@ -10704,7 +10730,7 @@ void main() { expect(formatter.log, referenceLog); }); - testWidgets('formatter logic handles repeat filtering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('formatter logic handles repeat filtering', (WidgetTester tester) async { final MockTextFormatter formatter = MockTextFormatter(); await tester.pumpWidget( MediaQuery( @@ -10785,7 +10811,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/53612 - testWidgets('formatter logic handles initial repeat edge case', (WidgetTester tester) async { + testWidgetsWithLeakTracking('formatter logic handles initial repeat edge case', (WidgetTester tester) async { final MockTextFormatter formatter = MockTextFormatter(); await tester.pumpWidget( MediaQuery( @@ -10827,7 +10853,7 @@ void main() { expect(formatter.lastOldValue.text, 'test'); }); - testWidgets('EditableText changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -10884,13 +10910,13 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('Can access characters on editing string', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can access characters on editing string', (WidgetTester tester) async { late int charactersLength; final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, selectionControls: materialTextSelectionControls, @@ -10910,7 +10936,7 @@ void main() { expect(charactersLength, 1); }); - testWidgets('EditableText can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(MediaQuery( data: const MediaQueryData(), child: Directionality( @@ -10952,7 +10978,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('EditableText inherits DefaultTextHeightBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText inherits DefaultTextHeightBehavior', (WidgetTester tester) async { const TextHeightBehavior customTextHeightBehavior = TextHeightBehavior( applyHeightToFirstAscent: false, ); @@ -10980,7 +11006,7 @@ void main() { expect(renderObject.textHeightBehavior, equals(customTextHeightBehavior)); }); - testWidgets('EditableText defaultTextHeightBehavior is used over inherited widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText defaultTextHeightBehavior is used over inherited widget', (WidgetTester tester) async { const TextHeightBehavior inheritedTextHeightBehavior = TextHeightBehavior( applyHeightToFirstAscent: false, ); @@ -11018,7 +11044,9 @@ void main() { void expectToAssert(TextEditingValue value, bool shouldAssert) { dynamic initException; dynamic updateException; - controller = TextEditingController(); + + TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); try { controller = TextEditingController.fromValue(value); } catch (e) { @@ -11026,6 +11054,7 @@ void main() { } controller = TextEditingController(); + addTearDown(controller.dispose); try { controller.value = value; } catch (e) { @@ -11042,7 +11071,7 @@ void main() { expectToAssert(const TextEditingValue(text: 'test', composing: TextRange(start: -1, end: 9)), false); }); - testWidgets('Preserves composing range if cursor moves within that range', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Preserves composing range if cursor moves within that range', (WidgetTester tester) async { final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, @@ -11064,7 +11093,7 @@ void main() { expect(state.currentTextEditingValue.composing, const TextRange(start: 4, end: 12)); }); - testWidgets('Clears composing range if cursor moves outside that range', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Clears composing range if cursor moves outside that range', (WidgetTester tester) async { final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, @@ -11105,7 +11134,7 @@ void main() { expect(state.currentTextEditingValue.composing, TextRange.empty); }); - testWidgets('Clears composing range if cursor moves outside that range - case two', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Clears composing range if cursor moves outside that range - case two', (WidgetTester tester) async { final Widget widget = MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, @@ -11187,7 +11216,7 @@ void main() { } // Regression test for https://github.com/flutter/flutter/issues/65374. - testWidgets('will not cause crash while the TextEditingValue is composing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will not cause crash while the TextEditingValue is composing', (WidgetTester tester) async { await setupWidget( tester, LengthLimitingTextInputFormatter( @@ -11213,7 +11242,7 @@ void main() { expect(state.currentTextEditingValue.composing, TextRange.empty); }); - testWidgets('handles composing text correctly, continued', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles composing text correctly, continued', (WidgetTester tester) async { await setupWidget( tester, LengthLimitingTextInputFormatter( @@ -11245,7 +11274,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/68086. - testWidgets('enforced composing truncated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('enforced composing truncated', (WidgetTester tester) async { await setupWidget( tester, LengthLimitingTextInputFormatter( @@ -11283,7 +11312,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/68086. - testWidgets('default truncate behaviors with different platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default truncate behaviors with different platforms', (WidgetTester tester) async { await setupWidget(tester, LengthLimitingTextInputFormatter(maxLength)); final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); @@ -11323,7 +11352,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/68086. - testWidgets("composing range removed if it's overflowed the truncated value's length", (WidgetTester tester) async { + testWidgetsWithLeakTracking("composing range removed if it's overflowed the truncated value's length", (WidgetTester tester) async { await setupWidget( tester, LengthLimitingTextInputFormatter( @@ -11352,7 +11381,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/68086. - testWidgets('composing range removed with different platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('composing range removed with different platforms', (WidgetTester tester) async { await setupWidget(tester, LengthLimitingTextInputFormatter(maxLength)); final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); @@ -11383,7 +11412,7 @@ void main() { } }); - testWidgets("composing range handled correctly when it's overflowed", (WidgetTester tester) async { + testWidgetsWithLeakTracking("composing range handled correctly when it's overflowed", (WidgetTester tester) async { const String string = '👨‍👩‍👦0123456'; await setupWidget(tester, LengthLimitingTextInputFormatter(maxLength)); @@ -11404,7 +11433,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/68086. - testWidgets('typing in the middle with different platforms.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('typing in the middle with different platforms.', (WidgetTester tester) async { await setupWidget(tester, LengthLimitingTextInputFormatter(maxLength)); final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); @@ -11446,15 +11475,15 @@ void main() { group('callback errors', () { const String errorText = 'Test EditableText callback error'; - testWidgets('onSelectionChanged can throw errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChanged can throw errors', (WidgetTester tester) async { + controller.text = 'flutter is the best!'; + await tester.pumpWidget(MaterialApp( home: EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController( - text: 'flutter is the best!', - ), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -11473,15 +11502,15 @@ void main() { expect(error.toString(), contains(errorText)); }); - testWidgets('onChanged can throw errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged can throw errors', (WidgetTester tester) async { + controller.text = 'flutter is the best!'; + await tester.pumpWidget(MaterialApp( home: EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController( - text: 'flutter is the best!', - ), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -11499,15 +11528,15 @@ void main() { expect(error.toString(), contains(errorText)); }); - testWidgets('onEditingComplete can throw errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onEditingComplete can throw errors', (WidgetTester tester) async { + controller.text = 'flutter is the best!'; + await tester.pumpWidget(MaterialApp( home: EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController( - text: 'flutter is the best!', - ), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -11530,15 +11559,15 @@ void main() { expect(error.toString(), contains(errorText)); }); - testWidgets('onSubmitted can throw errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSubmitted can throw errors', (WidgetTester tester) async { + controller.text = 'flutter is the best!'; + await tester.pumpWidget(MaterialApp( home: EditableText( showSelectionHandles: true, maxLines: 2, - controller: TextEditingController( - text: 'flutter is the best!', - ), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -11561,20 +11590,19 @@ void main() { expect(error.toString(), contains(errorText)); }); - testWidgets('input formatters can throw errors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('input formatters can throw errors', (WidgetTester tester) async { final TextInputFormatter badFormatter = TextInputFormatter.withFunction( (TextEditingValue oldValue, TextEditingValue newValue) => throw FlutterError(errorText), ); - final TextEditingController controller = TextEditingController( - text: 'flutter is the best!', - ); + controller.text = 'flutter is the best!'; + await tester.pumpWidget(MaterialApp( home: EditableText( showSelectionHandles: true, maxLines: 2, controller: controller, inputFormatters: <TextInputFormatter>[badFormatter], - focusNode: FocusNode(), + focusNode: focusNode, cursorColor: Colors.red, backgroundCursorColor: Colors.blue, style: Typography.material2018().black.titleMedium!.copyWith(fontFamily: 'Roboto'), @@ -11596,8 +11624,10 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/72400. - testWidgets("delete doesn't cause crash when selection is -1,-1", (WidgetTester tester) async { + testWidgetsWithLeakTracking("delete doesn't cause crash when selection is -1,-1", (WidgetTester tester) async { final UnsettableController unsettableController = UnsettableController(); + addTearDown(unsettableController.dispose); + await tester.pumpWidget( MediaQuery( data: const MediaQueryData(), @@ -11629,7 +11659,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('can change behavior by overriding text editing shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can change behavior by overriding text editing shortcuts', (WidgetTester tester) async { const Map<SingleActivator, Intent> testShortcuts = <SingleActivator, Intent>{ SingleActivator(LogicalKeyboardKey.arrowLeft): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), SingleActivator(LogicalKeyboardKey.keyX, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), @@ -11637,7 +11667,7 @@ void main() { SingleActivator(LogicalKeyboardKey.keyV, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), SingleActivator(LogicalKeyboardKey.keyA, control: true): ExtendSelectionByCharacterIntent(forward: true, collapseSelection: true), }; - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -11694,8 +11724,8 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, skip: kIsWeb); // [intended] - testWidgets('navigating by word', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'word word word'); + testWidgetsWithLeakTracking('navigating by word', (WidgetTester tester) async { + controller.text = 'word word word'; // word wo|rd| word controller.selection = const TextSelection( baseOffset: 7, @@ -11831,9 +11861,8 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('navigating multiline text', (WidgetTester tester) async { - const String multilineText = 'word word word\nword word\nword'; // 15 + 10 + 4; - final TextEditingController controller = TextEditingController(text: multilineText); + testWidgetsWithLeakTracking('navigating multiline text', (WidgetTester tester) async { + controller.text = 'word word word\nword word\nword'; // 15 + 10 + 4; // wo|rd wo|rd controller.selection = const TextSelection( baseOffset: 17, @@ -11990,9 +12019,8 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets("Mac's expand by line behavior on multiple lines", (WidgetTester tester) async { - const String multilineText = 'word word word\nword word\nword'; // 15 + 10 + 4; - final TextEditingController controller = TextEditingController(text: multilineText); + testWidgetsWithLeakTracking("Mac's expand by line behavior on multiple lines", (WidgetTester tester) async { + controller.text = 'word word word\nword word\nword'; // 15 + 10 + 4; // word word word // wo|rd word // w|ord @@ -12092,9 +12120,8 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) ); - testWidgets("Mac's expand extent position", (WidgetTester tester) async { - const String testText = 'Now is the time for all good people to come to the aid of their country'; - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking("Mac's expand extent position", (WidgetTester tester) async { + controller.text = 'Now is the time for all good people to come to the aid of their country'; // Start the selection in the middle somewhere. controller.selection = const TextSelection.collapsed(offset: 10); await tester.pumpWidget(MaterialApp( @@ -12326,8 +12353,8 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) ); - testWidgets('expanding selection to start/end single line', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'word word word'); + testWidgetsWithLeakTracking('expanding selection to start/end single line', (WidgetTester tester) async { + controller.text = 'word word word'; // word wo|rd| word controller.selection = const TextSelection( baseOffset: 7, @@ -12413,8 +12440,8 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }) ); - testWidgets('can change text editing behavior by overriding actions', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: testText); + testWidgetsWithLeakTracking('can change text editing behavior by overriding actions', (WidgetTester tester) async { + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -12459,10 +12486,8 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, skip: kIsWeb); // [intended] - testWidgets('ignore key event from web platform', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController( - text: 'test\ntest', - ); + testWidgetsWithLeakTracking('ignore key event from web platform', (WidgetTester tester) async { + controller.text = 'test\ntest'; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -12515,7 +12540,7 @@ void main() { } }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('the toolbar is disposed when selection changes and there is no selectionControls', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the toolbar is disposed when selection changes and there is no selectionControls', (WidgetTester tester) async { late StateSetter setState; bool enableInteractiveSelection = true; await tester.pumpWidget( @@ -12581,13 +12606,14 @@ void main() { // On web, using keyboard for selection is handled by the browser. }, skip: kIsWeb); // [intended] - testWidgets('EditableText does not leak animation controllers', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('EditableText does not leak animation controllers', (WidgetTester tester) async { + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( autofocus: true, - controller: TextEditingController(text: 'A'), + controller: controller, focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, @@ -12617,12 +12643,12 @@ void main() { expect(tester.hasRunningAnimations, isFalse); }); - testWidgets('Floating cursor affinity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating cursor affinity', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; - final FocusNode focusNode = FocusNode(); final GlobalKey key = GlobalKey(); // Set it up so that there will be word-wrap. - final TextEditingController controller = TextEditingController(text: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz'); + controller.text = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz'; + await tester.pumpWidget( MaterialApp( home: Center( @@ -12679,16 +12705,20 @@ void main() { )); EditableText.debugDeterministicCursor = false; - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 2}, + )); -testWidgets('Floating cursor ending with selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating cursor ending with selection', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; - final FocusNode focusNode = FocusNode(); final GlobalKey key = GlobalKey(); SelectionChangedCause? lastSelectionChangedCause; - - final TextEditingController controller = TextEditingController(text: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ\n1234567890'); + controller.text = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ\n1234567890'; controller.selection = const TextSelection.collapsed(offset: 0); + await tester.pumpWidget( MaterialApp( home: EditableText( @@ -12860,8 +12890,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async lastSelectionChangedCause = null; EditableText.debugDeterministicCursor = false; - }); - + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134386 + notDisposedAllowList: <String, int?> {'LeaderLayer': 8}, + )); group('Selection changed scroll into view', () { final String text = List<int>.generate(64, (int index) => index).join('\n'); @@ -12869,6 +12903,11 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async final ScrollController scrollController = ScrollController(); late double maxScrollExtent; + tearDownAll(() { + controller.dispose(); + scrollController.dispose(); + }); + Future<void> resetSelectionAndScrollOffset(WidgetTester tester, {required bool setMaxScrollExtent}) async { controller.value = controller.value.copyWith( text: text, @@ -12882,7 +12921,6 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(scrollController.offset, targetOffset); } - Future<TextSelectionDelegate> pumpLongScrollableText(WidgetTester tester) async { final GlobalKey<EditableTextState> key = GlobalKey<EditableTextState>(); @@ -12913,7 +12951,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async return key.currentState!; } - testWidgets('SelectAll toolbar action will not set max scroll on designated platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectAll toolbar action will not set max scroll on designated platforms', (WidgetTester tester) async { final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester); await resetSelectionAndScrollOffset(tester, setMaxScrollExtent: false); @@ -12922,7 +12960,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(scrollController.offset, 0.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selection will be scrolled into view with SelectionChangedCause', (WidgetTester tester) async { final TextSelectionDelegate textSelectionDelegate = await pumpLongScrollableText(tester); // Cut @@ -12971,13 +13009,11 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); }); - testWidgets('Should not scroll on paste if caret already visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Should not scroll on paste if caret already visible', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/96658. final ScrollController scrollController = ScrollController(); - final TextEditingController controller = TextEditingController( - text: 'Lorem ipsum please paste here: \n${".\n" * 50}', - ); - final FocusNode focusNode = FocusNode(); + addTearDown(scrollController.dispose); + controller.text = 'Lorem ipsum please paste here: \n${".\n" * 50}'; await tester.pumpWidget( MaterialApp( @@ -13015,13 +13051,14 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(scrollController.offset, 0.0); }); - testWidgets('Autofill enabled by default', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Autofill enabled by default', (WidgetTester tester) async { + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( autofocus: true, - controller: TextEditingController(text: 'A'), + controller: controller, focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, @@ -13038,13 +13075,14 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets('Autofill can be disabled', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Autofill can be disabled', (WidgetTester tester) async { + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( autofocus: true, - controller: TextEditingController(text: 'A'), + controller: controller, focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, @@ -13078,11 +13116,11 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async Future<void> sendUndo(WidgetTester tester) => sendUndoRedo(tester); Future<void> sendRedo(WidgetTester tester) => sendUndoRedo(tester, true); - Widget boilerplate(TextEditingController controller, [FocusNode? focusNode]) { + Widget boilerplate() { return MaterialApp( home: EditableText( controller: controller, - focusNode: focusNode ?? FocusNode(), + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -13122,9 +13160,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async selection: TextSelection.collapsed(offset: textAC.length), ); - testWidgets('Should have no effect on an empty and non-focused field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - await tester.pumpWidget(boilerplate(controller)); + testWidgetsWithLeakTracking('Should have no effect on an empty and non-focused field', (WidgetTester tester) async { + await tester.pumpWidget(boilerplate()); expect(controller.value, TextEditingValue.empty); // Undo/redo have no effect on an empty field that has never been edited. @@ -13138,10 +13175,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('Should have no effect on an empty and focused field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + testWidgetsWithLeakTracking('Should have no effect on an empty and focused field', (WidgetTester tester) async { + await tester.pumpWidget(boilerplate()); await waitForThrottling(tester); expect(controller.value, TextEditingValue.empty); @@ -13149,31 +13184,29 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // state saved in text editing history. focusNode.requestFocus(); await tester.pump(); - expect(controller.value, emptyTextCollapsed); + expect(controller.value, emptyTextCollapsed); await waitForThrottling(tester); // Undo/redo should have no effect. The field is focused and the value has // changed, but the text remains empty. await sendUndo(tester); - expect(controller.value, emptyTextCollapsed); + expect(controller.value, emptyTextCollapsed); await sendRedo(tester); - expect(controller.value, emptyTextCollapsed); + expect(controller.value, emptyTextCollapsed); // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('Can undo/redo a single insertion', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + testWidgetsWithLeakTracking('Can undo/redo a single insertion', (WidgetTester tester) async { + await tester.pumpWidget(boilerplate()); // Focus the field and wait for throttling delay to get the initial // state saved in text editing history. focusNode.requestFocus(); await tester.pump(); await waitForThrottling(tester); - expect(controller.value, emptyTextCollapsed); + expect(controller.value, emptyTextCollapsed); // First insertion. await tester.enterText(find.byType(EditableText), textA); @@ -13203,17 +13236,15 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('Can undo/redo multiple insertions', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + testWidgetsWithLeakTracking('Can undo/redo multiple insertions', (WidgetTester tester) async { + await tester.pumpWidget(boilerplate()); // Focus the field and wait for throttling delay to get the initial // state saved in text editing history. focusNode.requestFocus(); await tester.pump(); await waitForThrottling(tester); - expect(controller.value, emptyTextCollapsed); + expect(controller.value, emptyTextCollapsed); // First insertion. await tester.enterText(find.byType(EditableText), textA); @@ -13247,17 +13278,15 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // Regression test for https://github.com/flutter/flutter/issues/120794. // This is only reproducible on Android platform because it is the only // platform where composing changes are saved in the editing history. - testWidgets('Can undo as intented when adding a delay between undos', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + testWidgetsWithLeakTracking('Can undo as intented when adding a delay between undos', (WidgetTester tester) async { + await tester.pumpWidget(boilerplate()); // Focus the field and wait for throttling delay to get the initial // state saved in text editing history. focusNode.requestFocus(); await tester.pump(); await waitForThrottling(tester); - expect(controller.value, emptyTextCollapsed); + expect(controller.value, emptyTextCollapsed); final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText)); @@ -13303,11 +13332,10 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] // Regression test for https://github.com/flutter/flutter/issues/120194. - testWidgets('Cursor does not jump after undo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor does not jump after undo', (WidgetTester tester) async { // Initialize the controller with a non empty text. - final TextEditingController controller = TextEditingController(text: textA); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + controller.text = textA; + await tester.pumpWidget(boilerplate()); // Focus the field and wait for throttling delay to get the initial // state saved in text editing history. @@ -13328,11 +13356,10 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('Initial value is recorded when an undo is received just after getting the focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial value is recorded when an undo is received just after getting the focus', (WidgetTester tester) async { // Initialize the controller with a non empty text. - final TextEditingController controller = TextEditingController(text: textA); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + controller.text = textA; + await tester.pumpWidget(boilerplate()); // Focus the field and do not wait for throttling delay before calling undo. focusNode.requestFocus(); @@ -13354,10 +13381,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('Can make changes in the middle of the history', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); - await tester.pumpWidget(boilerplate(controller, focusNode)); + testWidgetsWithLeakTracking('Can make changes in the middle of the history', (WidgetTester tester) async { + await tester.pumpWidget(boilerplate()); // Focus the field and wait for throttling delay to get the initial // state saved in text editing history. @@ -13408,9 +13433,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('inside EditableText, duplicate changes', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('inside EditableText, duplicate changes', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -13539,14 +13562,13 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('inside EditableText, autofocus', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); + testWidgetsWithLeakTracking('inside EditableText, autofocus', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( autofocus: true, controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: textStyle, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -13612,9 +13634,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('does not save composing changes (except Android)', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('does not save composing changes (except Android)', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -13773,9 +13793,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.android }), skip: kIsWeb); // [intended] - testWidgets('does save composing changes on Android', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('does save composing changes on Android', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -14007,9 +14025,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // On web, these keyboard shortcuts are handled by the browser. }, variant: TargetPlatformVariant.only(TargetPlatform.android), skip: kIsWeb); // [intended] - testWidgets('saves right up to composing change even when throttled', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(); - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('saves right up to composing change even when throttled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( @@ -14209,9 +14225,11 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] }); - testWidgets('pasting with the keyboard collapses the selection and places it after the pasted content', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pasting with the keyboard collapses the selection and places it after the pasted content', (WidgetTester tester) async { Future<void> testPasteSelection(WidgetTester tester, _VoidFutureCallback paste) async { final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: EditableText( @@ -14344,7 +14362,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, skip: kIsWeb); // [intended] // Regression test for https://github.com/flutter/flutter/issues/98322. - testWidgets('EditableText consumes ActivateIntent and ButtonActivateIntent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText consumes ActivateIntent and ButtonActivateIntent', (WidgetTester tester) async { bool receivedIntent = false; await tester.pumpWidget( MaterialApp( @@ -14386,8 +14404,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }); // Regression test for https://github.com/flutter/flutter/issues/100585. - testWidgets('can paste and remove field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'text'); + testWidgetsWithLeakTracking('can paste and remove field', (WidgetTester tester) async { + controller.text = 'text'; late StateSetter setState; bool showField = true; final _CustomTextSelectionControls controls = _CustomTextSelectionControls( @@ -14436,8 +14454,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, skip: kIsWeb); // [intended] // Regression test for https://github.com/flutter/flutter/issues/100585. - testWidgets('can cut and remove field', (WidgetTester tester) async { - final TextEditingController controller = TextEditingController(text: 'text'); + testWidgetsWithLeakTracking('can cut and remove field', (WidgetTester tester) async { + controller.text = 'text'; late StateSetter setState; bool showField = true; final _CustomTextSelectionControls controls = _CustomTextSelectionControls( @@ -14487,10 +14505,10 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }, skip: kIsWeb); // [intended] group('Mac document shortcuts', () { - testWidgets('ctrl-A/E', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ctrl-A/E', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -14506,7 +14524,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -14568,10 +14586,10 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('ctrl-F/B', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ctrl-F/B', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -14587,7 +14605,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -14634,10 +14652,10 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('ctrl-N/P', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ctrl-N/P', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -14653,7 +14671,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -14713,11 +14731,11 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async await tester.pump(); } - testWidgets('with normal characters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with normal characters', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController(text: testText); + controller.text = testText; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -14733,7 +14751,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -14808,15 +14826,13 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('with extended grapheme clusters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('with extended grapheme clusters', (WidgetTester tester) async { final String targetPlatformString = defaultTargetPlatform.toString(); final String platform = targetPlatformString.substring(targetPlatformString.indexOf('.') + 1).toLowerCase(); - final TextEditingController controller = TextEditingController( - // One extended grapheme cluster of length 8 and one surrogate pair of - // length 2. - text: '👨‍👩‍👦😆', - ); + // One extended grapheme cluster of length 8 and one surrogate pair of + // length 2. + controller.text = '👨‍👩‍👦😆'; controller.selection = const TextSelection( baseOffset: 0, extentOffset: 0, @@ -14832,7 +14848,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -14892,7 +14908,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets('macOS selectors work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('macOS selectors work', (WidgetTester tester) async { controller.text = 'test\nline2'; controller.selection = TextSelection.collapsed(offset: controller.text.length); @@ -14909,7 +14925,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -14950,9 +14966,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }); }); - testWidgets('contextMenuBuilder is used in place of the default text selection toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('contextMenuBuilder is used in place of the default text selection toolbar', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); - final TextEditingController controller = TextEditingController(text: ''); await tester.pumpWidget(MaterialApp( home: Align( alignment: Alignment.topLeft, @@ -14963,7 +14978,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.subtitle1!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15001,14 +15016,16 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); group('Spell check', () { - testWidgets( + testWidgetsWithLeakTracking( 'Spell check configured properly when spell check disabled by default', (WidgetTester tester) async { + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15023,14 +15040,16 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(state.spellCheckEnabled, isFalse); }); - testWidgets( + testWidgetsWithLeakTracking( 'Spell check configured properly when spell check disabled manually', (WidgetTester tester) async { + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15046,14 +15065,16 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(state.spellCheckEnabled, isFalse); }); - testWidgets( + testWidgetsWithLeakTracking( 'Error thrown when spell check configuration defined without specifying misspelled text style', (WidgetTester tester) async { + controller.text = 'A'; + expect( () { EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15066,17 +15087,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets( + testWidgetsWithLeakTracking( 'Spell check configured properly when spell check enabled without specified spell check service and native spell check service defined', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; + controller.text = 'A'; await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15100,16 +15122,17 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async tester.binding.platformDispatcher.clearNativeSpellCheckServiceDefined(); }); - testWidgets( + testWidgetsWithLeakTracking( 'Spell check configured properly with specified spell check service', (WidgetTester tester) async { final FakeSpellCheckService fakeSpellCheckService = FakeSpellCheckService(); + controller.text = 'A'; await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15132,17 +15155,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets( + testWidgetsWithLeakTracking( 'Spell check disabled when spell check configuration specified but no default spell check service available', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = false; + controller.text = 'A'; await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15163,16 +15187,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async tester.binding.platformDispatcher.clearNativeSpellCheckServiceDefined(); }); - testWidgets( + testWidgetsWithLeakTracking( 'findSuggestionSpanAtCursorIndex finds correct span with cursor in middle of a word', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15206,16 +15232,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(suggestionSpan, equals(expectedSpan)); }); - testWidgets( + testWidgetsWithLeakTracking( 'findSuggestionSpanAtCursorIndex finds correct span with cursor on edge of a word', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15248,16 +15276,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(suggestionSpan, equals(expectedSpan)); }); - testWidgets( + testWidgetsWithLeakTracking( 'findSuggestionSpanAtCursorIndex finds no span when cursor out of range of spans', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15290,16 +15320,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(suggestionSpan, isNull); }); - testWidgets( + testWidgetsWithLeakTracking( 'findSuggestionSpanAtCursorIndex finds no span when word correctly spelled', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; + controller.text = 'A'; + await tester.pumpWidget( MaterialApp( home: EditableText( - controller: TextEditingController(text: 'A'), - focusNode: FocusNode(), + controller: controller, + focusNode: focusNode, style: const TextStyle(), cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15332,7 +15364,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(suggestionSpan, isNull); }); - testWidgets('can show spell check suggestions toolbar when there are spell check results', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can show spell check suggestions toolbar when there are spell check results', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; const TextEditingValue value = TextEditingValue( @@ -15393,7 +15425,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(find.text('DELETE'), matcher); }); - testWidgets('can show spell check suggestions toolbar when there are no spell check results on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can show spell check suggestions toolbar when there are no spell check results on iOS', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; const TextEditingValue value = TextEditingValue( @@ -15455,7 +15487,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async skip: kIsWeb, // [intended] ); - testWidgets('cupertino spell check suggestions toolbar buttons correctly change the composing region', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cupertino spell check suggestions toolbar buttons correctly change the composing region', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; const TextEditingValue value = TextEditingValue( @@ -15516,7 +15548,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async } }); - testWidgets('material spell check suggestions toolbar buttons correctly change the composing region', (WidgetTester tester) async { + testWidgetsWithLeakTracking('material spell check suggestions toolbar buttons correctly change the composing region', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; const TextEditingValue value = TextEditingValue( @@ -15581,7 +15613,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async } }); - testWidgets('replacing puts cursor at the end of the word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('replacing puts cursor at the end of the word', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; controller.value = const TextEditingValue( @@ -15693,7 +15725,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async skip: kIsWeb, // [intended] ); - testWidgets('tapping on a misspelled word hides the handles', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tapping on a misspelled word hides the handles', (WidgetTester tester) async { tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue = true; controller.value = const TextEditingValue( @@ -15756,12 +15788,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }); group('magnifier', () { - testWidgets('should build nothing by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should build nothing by default', (WidgetTester tester) async { final EditableText editableText = EditableText( controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15777,27 +15809,29 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); final BuildContext context = tester.firstElement(find.byType(EditableText)); + final ValueNotifier<MagnifierInfo> notifier = ValueNotifier<MagnifierInfo>(MagnifierInfo.empty); + addTearDown(notifier.dispose); expect( - editableText.magnifierConfiguration.magnifierBuilder( - context, - MagnifierController(), - ValueNotifier<MagnifierInfo>(MagnifierInfo.empty) - ), - isNull, + editableText.magnifierConfiguration.magnifierBuilder( + context, + MagnifierController(), + notifier, + ), + isNull, ); }); }); // Regression test for: https://github.com/flutter/flutter/issues/117418. - testWidgets('can handle the partial selection of a multi-code-unit glyph', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can handle the partial selection of a multi-code-unit glyph', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( controller: controller, showSelectionHandles: true, autofocus: true, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15833,12 +15867,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(tester.takeException(), null); }); - testWidgets('does not crash when didChangeMetrics is called after unmounting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not crash when didChangeMetrics is called after unmounting', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( controller: controller, - focusNode: FocusNode(), + focusNode: focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, @@ -15855,13 +15889,9 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async state.didChangeMetrics(); }); - testWidgets('_CompositionCallback widget does not skip frames', (WidgetTester tester) async { + testWidgetsWithLeakTracking('_CompositionCallback widget does not skip frames', (WidgetTester tester) async { EditableText.debugDeterministicCursor = true; - final FocusNode focusNode = FocusNode(); - final TextEditingController controller = TextEditingController.fromValue( - const TextEditingValue(selection: TextSelection.collapsed(offset: 0)), - ); - + controller.value = const TextEditingValue(selection: TextSelection.collapsed(offset: 0)); Offset offset = Offset.zero; late StateSetter setState; @@ -15916,13 +15946,17 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }); group('selection behavior when receiving focus', () { - testWidgets('tabbing between fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tabbing between fields', (WidgetTester tester) async { final TextEditingController controller1 = TextEditingController(); + addTearDown(controller1.dispose); final TextEditingController controller2 = TextEditingController(); + addTearDown(controller2.dispose); controller1.text = 'Text1'; controller2.text = 'Text2\nLine2'; final FocusNode focusNode1 = FocusNode(); + addTearDown(focusNode1.dispose); final FocusNode focusNode2 = FocusNode(); + addTearDown(focusNode2.dispose); await tester.pumpWidget( MaterialApp( @@ -16052,11 +16086,9 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets('Selection is updated when the field has focus and the new selection is invalid', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selection is updated when the field has focus and the new selection is invalid', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/120631. - final TextEditingController controller = TextEditingController(); controller.text = 'Text'; - final FocusNode focusNode = FocusNode(); await tester.pumpWidget( MaterialApp( @@ -16111,11 +16143,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets('when having focus stolen between frames on web', (WidgetTester tester) async { - final TextEditingController controller1 = TextEditingController(); - controller1.text = 'Text1'; + testWidgetsWithLeakTracking('when having focus stolen between frames on web', (WidgetTester tester) async { + controller.text = 'Text1'; final FocusNode focusNode1 = FocusNode(); + addTearDown(focusNode1.dispose); final FocusNode focusNode2 = FocusNode(); + addTearDown(focusNode2.dispose); await tester.pumpWidget( MaterialApp( @@ -16123,8 +16156,8 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ EditableText( - key: ValueKey<String>(controller1.text), - controller: controller1, + key: ValueKey<String>(controller.text), + controller: controller, focusNode: focusNode1, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, @@ -16144,7 +16177,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(focusNode1.hasFocus, isFalse); expect(focusNode2.hasFocus, isFalse); expect( - controller1.selection, + controller.selection, const TextSelection.collapsed(offset: -1), ); @@ -16153,7 +16186,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async // Set the text editing value in order to trigger an internal call to // requestFocus. state.userUpdateTextEditingValue( - controller1.value, + controller.value, SelectionChangedCause.keyboard, ); // Focus takes a frame to update, so it hasn't changed yet. @@ -16174,10 +16207,10 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(focusNode1.hasFocus, isTrue); expect(focusNode2.hasFocus, isFalse); expect( - controller1.selection, + controller.selection, TextSelection( baseOffset: 0, - extentOffset: controller1.text.length, + extentOffset: controller.text.length, ), ); }, @@ -16185,7 +16218,7 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ); }); - testWidgets('EditableText respects MediaQuery.boldText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText respects MediaQuery.boldText', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: MediaQuery( @@ -16206,12 +16239,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async expect(state.buildTextSpan().style!.fontWeight, FontWeight.bold); }); - testWidgets('code points are treated as single characters in obscure mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('code points are treated as single characters in obscure mode', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -16342,12 +16375,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async skip: kIsWeb, // [intended] ); - testWidgets('when manually placing the cursor in the middle of a code point', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when manually placing the cursor in the middle of a code point', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -16426,12 +16459,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async skip: kIsWeb, // [intended] ); - testWidgets('when inserting a malformed string', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when inserting a malformed string', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -16488,12 +16521,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async skip: kIsWeb, // [intended] ); - testWidgets('when inserting a malformed string that is a sequence of dangling high surrogates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when inserting a malformed string that is a sequence of dangling high surrogates', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -16548,12 +16581,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async skip: kIsWeb, // [intended] ); - testWidgets('when inserting a malformed string that is a sequence of dangling low surrogates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when inserting a malformed string that is a sequence of dangling low surrogates', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -16625,12 +16658,12 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async .defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null); }); - testWidgets('web avoids the paste permissions prompt by not calling hasStrings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('web avoids the paste permissions prompt by not calling hasStrings', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: EditableText( backgroundCursorColor: Colors.grey, - controller: TextEditingController(), + controller: controller, focusNode: focusNode, obscureText: true, toolbarOptions: const ToolbarOptions( @@ -16658,16 +16691,18 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async }); }); - testWidgets('Cursor color with an opacity is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor color with an opacity is respected', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); const double opacity = 0.55; + controller.text = 'blah blah'; + await tester.pumpWidget( MaterialApp( home: EditableText( key: key, cursorColor: cursorColor.withOpacity(opacity), backgroundCursorColor: Colors.grey, - controller: TextEditingController(text: 'blah blah'), + controller: controller, focusNode: focusNode, style: textStyle, ), @@ -16964,6 +16999,16 @@ class TransformedEditableText extends StatefulWidget { class _TransformedEditableTextState extends State<TransformedEditableText> { bool _isTransformed = false; + final TextEditingController _controller = TextEditingController(); + final FocusNode _focusNode = FocusNode(); + + @override + void dispose() { + _controller.dispose(); + _focusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return MediaQuery( @@ -16976,8 +17021,8 @@ class _TransformedEditableTextState extends State<TransformedEditableText> { Transform.translate( offset: _isTransformed ? widget.offset : Offset.zero, child: EditableText( - controller: TextEditingController(), - focusNode: FocusNode(), + controller: _controller, + focusNode: _focusNode, style: Typography.material2018().black.titleMedium!, cursorColor: Colors.blue, backgroundCursorColor: Colors.grey, diff --git a/packages/flutter/test/widgets/ensure_visible_test.dart b/packages/flutter/test/widgets/ensure_visible_test.dart index 16f493804cadb..329388ee11a88 100644 --- a/packages/flutter/test/widgets/ensure_visible_test.dart +++ b/packages/flutter/test/widgets/ensure_visible_test.dart @@ -7,6 +7,7 @@ import 'dart:math' as math; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Finder findKey(int i) => find.byKey(ValueKey<int>(i), skipOffstage: false); @@ -68,7 +69,7 @@ Widget buildListView(Axis scrollDirection, { bool reverse = false, bool shrinkWr void main() { group('SingleChildScrollView', () { - testWidgets('SingleChildScrollView ensureVisible Axis.vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView ensureVisible Axis.vertical', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical)); @@ -95,7 +96,7 @@ void main() { expect(tester.getTopLeft(findKey(3)).dy, equals(100.0)); }); - testWidgets('SingleChildScrollView ensureVisible Axis.horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView ensureVisible Axis.horizontal', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal)); @@ -122,7 +123,7 @@ void main() { expect(tester.getTopLeft(findKey(3)).dx, equals(100.0)); }); - testWidgets('SingleChildScrollView ensureVisible Axis.vertical reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView ensureVisible Axis.vertical reverse', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); await tester.pumpWidget(buildSingleChildScrollView(Axis.vertical, reverse: true)); @@ -190,7 +191,7 @@ void main() { expect(tester.getBottomLeft(findKey(6)).dy, equals(500.0)); }); - testWidgets('SingleChildScrollView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); await tester.pumpWidget(buildSingleChildScrollView(Axis.horizontal, reverse: true)); @@ -263,7 +264,7 @@ void main() { expect(tester.getBottomLeft(findKey(6)).dx, equals(500.0)); }); - testWidgets('SingleChildScrollView ensureVisible rotated child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView ensureVisible rotated child', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); await tester.pumpWidget( @@ -310,7 +311,7 @@ void main() { expect(tester.getTopLeft(findKey(0)).dy, moreOrLessEquals(500.0, epsilon: 0.1)); }); - testWidgets('Nested SingleChildScrollView ensureVisible behavior test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested SingleChildScrollView ensureVisible behavior test', (WidgetTester tester) async { // Regressing test for https://github.com/flutter/flutter/issues/65100 Finder findKey(String coordinate) => find.byKey(ValueKey<String>(coordinate)); BuildContext findContext(String coordinate) => tester.element(findKey(coordinate)); @@ -388,7 +389,7 @@ void main() { }); group('ListView', () { - testWidgets('ListView ensureVisible Axis.vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.vertical', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -424,7 +425,7 @@ void main() { expect(tester.getTopLeft(findKey(3)).dy, equals(100.0)); }); - testWidgets('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -460,7 +461,7 @@ void main() { expect(tester.getTopLeft(findKey(3)).dx, equals(100.0)); }); - testWidgets('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -536,7 +537,7 @@ void main() { expect(tester.getBottomLeft(findKey(0)).dy, equals(500.0)); }); - testWidgets('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -617,7 +618,7 @@ void main() { expect(tester.getBottomLeft(findKey(0)).dx, equals(500.0)); }); - testWidgets('ListView ensureVisible negative child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible negative child', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -675,7 +676,7 @@ void main() { expect(getOffset(), equals(-400.0)); }); - testWidgets('ListView ensureVisible rotated child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible rotated child', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -728,7 +729,7 @@ void main() { }); group('ListView shrinkWrap', () { - testWidgets('ListView ensureVisible Axis.vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.vertical', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -764,7 +765,7 @@ void main() { expect(tester.getTopLeft(findKey(3)).dy, equals(100.0)); }); - testWidgets('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.horizontal', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -800,7 +801,7 @@ void main() { expect(tester.getTopLeft(findKey(3)).dx, equals(100.0)); }); - testWidgets('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.vertical reverse', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -876,7 +877,7 @@ void main() { expect(tester.getBottomLeft(findKey(0)).dy, equals(500.0)); }); - testWidgets('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView ensureVisible Axis.horizontal reverse', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); @@ -959,7 +960,7 @@ void main() { }); group('Scrollable with center', () { - testWidgets('ensureVisible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ensureVisible', (WidgetTester tester) async { BuildContext findContext(int i) => tester.element(findKey(i)); Future<void> prepare(double offset) async { tester.state<ScrollableState>(find.byType(Scrollable)).position.jumpTo(offset); diff --git a/packages/flutter/test/widgets/error_widget_builder_test.dart b/packages/flutter/test/widgets/error_widget_builder_test.dart index 141f522209d71..c5c075897aded 100644 --- a/packages/flutter/test/widgets/error_widget_builder_test.dart +++ b/packages/flutter/test/widgets/error_widget_builder_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('ErrorWidget.builder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ErrorWidget.builder', (WidgetTester tester) async { final ErrorWidgetBuilder oldBuilder = ErrorWidget.builder; ErrorWidget.builder = (FlutterErrorDetails details) { return const Text('oopsie!', textDirection: TextDirection.ltr); @@ -25,7 +26,7 @@ void main() { ErrorWidget.builder = oldBuilder; }); - testWidgets('ErrorWidget.builder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ErrorWidget.builder', (WidgetTester tester) async { final ErrorWidgetBuilder oldBuilder = ErrorWidget.builder; ErrorWidget.builder = (FlutterErrorDetails details) { return ErrorWidget(''); diff --git a/packages/flutter/test/widgets/fade_in_image_test.dart b/packages/flutter/test/widgets/fade_in_image_test.dart index e88c6ca6e5084..e12f2ecb76784 100644 --- a/packages/flutter/test/widgets/fade_in_image_test.dart +++ b/packages/flutter/test/widgets/fade_in_image_test.dart @@ -8,6 +8,7 @@ import 'dart:ui' as ui; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; import '../painting/image_test_utils.dart'; @@ -90,14 +91,26 @@ FadeInImageParts findFadeInImage(WidgetTester tester) { } } -Future<void> main() async { +void main() { // These must run outside test zone to complete - final ui.Image targetImage = await createTestImage(); - final ui.Image placeholderImage = await createTestImage(); - final ui.Image replacementImage = await createTestImage(); + late final ui.Image targetImage; + late final ui.Image placeholderImage; + late final ui.Image replacementImage; + + setUpAll(() async { + targetImage = await createTestImage(); + placeholderImage = await createTestImage(); + replacementImage = await createTestImage(); + }); + + tearDownAll(() { + targetImage.dispose(); + placeholderImage.dispose(); + replacementImage.dispose(); + }); group('FadeInImage', () { - testWidgets('animates an uncached image', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animates an uncached image', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -147,7 +160,7 @@ Future<void> main() async { expect(findFadeInImage(tester).target.opacity, 1); }); - testWidgets("FadeInImage's image obeys gapless playback", (WidgetTester tester) async { + testWidgetsWithLeakTracking("FadeInImage's image obeys gapless playback", (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); final TestImageProvider secondImageProvider = TestImageProvider(replacementImage); @@ -188,7 +201,7 @@ Future<void> main() async { }); // Regression test for https://github.com/flutter/flutter/issues/111011 - testWidgets("FadeInImage's image obeys gapless playback when first image is cached but second isn't", + testWidgetsWithLeakTracking("FadeInImage's image obeys gapless playback when first image is cached but second isn't", (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -225,7 +238,7 @@ Future<void> main() async { expect(parts.target.opacity, 1); }); - testWidgets("FadeInImage's placeholder obeys gapless playback", (WidgetTester tester) async { + testWidgetsWithLeakTracking("FadeInImage's placeholder obeys gapless playback", (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider secondPlaceholderProvider = TestImageProvider(replacementImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -261,7 +274,7 @@ Future<void> main() async { expect(parts.placeholder!.opacity, 1); }); - testWidgets('shows a cached image immediately when skipFadeOnSynchronousLoad=true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows a cached image immediately when skipFadeOnSynchronousLoad=true', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); imageProvider.resolve(ImageConfiguration.empty); @@ -277,7 +290,7 @@ Future<void> main() async { expect(findFadeInImage(tester).target.opacity, 1); }); - testWidgets('handles updating the placeholder image', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles updating the placeholder image', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider secondPlaceholderProvider = TestImageProvider(replacementImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -309,7 +322,7 @@ Future<void> main() async { expect(findFadeInImage(tester).state, same(state)); }); - testWidgets('does not keep the placeholder in the tree if it is invisible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not keep the placeholder in the tree if it is invisible', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -331,7 +344,7 @@ Future<void> main() async { expect(find.byType(Image), findsOneWidget); }); - testWidgets("doesn't interrupt in-progress animation when animation values are updated", (WidgetTester tester) async { + testWidgetsWithLeakTracking("doesn't interrupt in-progress animation when animation values are updated", (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -434,7 +447,7 @@ Future<void> main() async { }); group('semantics', () { - testWidgets('only one Semantics node appears within FadeInImage', (WidgetTester tester) async { + testWidgetsWithLeakTracking('only one Semantics node appears within FadeInImage', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -446,7 +459,7 @@ Future<void> main() async { expect(find.byType(Semantics), findsOneWidget); }); - testWidgets('is excluded if excludeFromSemantics is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is excluded if excludeFromSemantics is true', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -462,7 +475,7 @@ Future<void> main() async { group('label', () { const String imageSemanticText = 'Test image semantic label'; - testWidgets('defaults to image label if placeholder label is unspecified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('defaults to image label if placeholder label is unspecified', (WidgetTester tester) async { Semantics semanticsWidget() => tester.widget(find.byType(Semantics)); final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); @@ -489,7 +502,7 @@ Future<void> main() async { expect(semanticsWidget().properties.label, imageSemanticText); }); - testWidgets('is empty without any specified semantics labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is empty without any specified semantics labels', (WidgetTester tester) async { Semantics semanticsWidget() => tester.widget(find.byType(Semantics)); final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); @@ -515,7 +528,7 @@ Future<void> main() async { }); group("placeholder's BoxFit", () { - testWidgets("should be the image's BoxFit when not set", (WidgetTester tester) async { + testWidgetsWithLeakTracking("should be the image's BoxFit when not set", (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -529,7 +542,7 @@ Future<void> main() async { expect(findFadeInImage(tester).placeholder!.fit, equals(BoxFit.cover)); }); - testWidgets('should be the given value when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should be the given value when set', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -546,7 +559,7 @@ Future<void> main() async { }); group("placeholder's FilterQuality", () { - testWidgets("should be the image's FilterQuality when not set", (WidgetTester tester) async { + testWidgetsWithLeakTracking("should be the image's FilterQuality when not set", (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); @@ -560,7 +573,7 @@ Future<void> main() async { expect(findFadeInImage(tester).placeholder!.filterQuality, equals(FilterQuality.medium)); }); - testWidgets('should be the given value when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should be the given value when set', (WidgetTester tester) async { final TestImageProvider placeholderProvider = TestImageProvider(placeholderImage); final TestImageProvider imageProvider = TestImageProvider(targetImage); diff --git a/packages/flutter/test/widgets/fade_transition_test.dart b/packages/flutter/test/widgets/fade_transition_test.dart index edcfce8630e62..e35013867e8e5 100644 --- a/packages/flutter/test/widgets/fade_transition_test.dart +++ b/packages/flutter/test/widgets/fade_transition_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('FadeTransition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FadeTransition', (WidgetTester tester) async { final DebugPrintCallback oldPrint = debugPrint; final List<String> log = <String>[]; debugPrint = (String? message, { int? wrapWidth }) { diff --git a/packages/flutter/test/widgets/fitted_box_test.dart b/packages/flutter/test/widgets/fitted_box_test.dart index bc5d30cb42fc1..bcc8aee897c5f 100644 --- a/packages/flutter/test/widgets/fitted_box_test.dart +++ b/packages/flutter/test/widgets/fitted_box_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can size according to aspect ratio', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can size according to aspect ratio', (WidgetTester tester) async { final Key outside = UniqueKey(); final Key inside = UniqueKey(); @@ -42,7 +43,7 @@ void main() { expect(insidePoint, equals(outsidePoint)); }); - testWidgets('Can contain child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can contain child', (WidgetTester tester) async { final Key outside = UniqueKey(); final Key inside = UniqueKey(); @@ -77,7 +78,7 @@ void main() { expect(insidePoint, equals(outsidePoint)); }); - testWidgets('Child can cover', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Child can cover', (WidgetTester tester) async { final Key outside = UniqueKey(); final Key inside = UniqueKey(); @@ -113,7 +114,7 @@ void main() { expect(insidePoint, equals(outsidePoint)); }); - testWidgets('FittedBox with no child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FittedBox with no child', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Center( @@ -129,7 +130,7 @@ void main() { expect(box.size.height, 0.0); }); - testWidgets('Child can be aligned multiple ways in a row', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Child can be aligned multiple ways in a row', (WidgetTester tester) async { final Key outside = UniqueKey(); final Key inside = UniqueKey(); @@ -339,7 +340,7 @@ void main() { } }); - testWidgets('FittedBox layers - contain', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FittedBox layers - contain', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: SizedBox( @@ -360,7 +361,7 @@ void main() { expect(getLayers(), <Type>[TransformLayer, TransformLayer, OffsetLayer]); }); - testWidgets('FittedBox layers - cover - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FittedBox layers - cover - horizontal', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: SizedBox( @@ -383,7 +384,7 @@ void main() { expect(getLayers(), <Type>[TransformLayer, ClipRectLayer, TransformLayer, OffsetLayer]); }); - testWidgets('FittedBox layers - cover - vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FittedBox layers - cover - vertical', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: SizedBox( @@ -406,7 +407,7 @@ void main() { expect(getLayers(), <Type>[TransformLayer, ClipRectLayer, TransformLayer, OffsetLayer]); }); - testWidgets('FittedBox layers - none - clip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FittedBox layers - none - clip', (WidgetTester tester) async { final List<double> values = <double>[10.0, 50.0, 100.0]; for (final double a in values) { for (final double b in values) { @@ -442,7 +443,7 @@ void main() { } }); - testWidgets('Big child into small fitted box - hit testing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Big child into small fitted box - hit testing', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); bool pointerDown = false; await tester.pumpWidget( @@ -474,7 +475,7 @@ void main() { expect(pointerDown, isTrue); }); - testWidgets('Can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(FittedBox(fit: BoxFit.none, child: Container())); final RenderFittedBox renderObject = tester.allRenderObjects.whereType<RenderFittedBox>().first; expect(renderObject.clipBehavior, equals(Clip.none)); @@ -483,7 +484,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('BoxFit.scaleDown matches size of child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxFit.scaleDown matches size of child', (WidgetTester tester) async { final Key outside = UniqueKey(); final Key inside = UniqueKey(); @@ -544,7 +545,7 @@ void main() { expect(insidePoint - outsidePoint, equals(Offset.zero)); }); - testWidgets('Switching to and from BoxFit.scaleDown causes relayout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switching to and from BoxFit.scaleDown causes relayout', (WidgetTester tester) async { final Key outside = UniqueKey(); final Widget scaleDownWidget = Center( @@ -588,7 +589,7 @@ void main() { expect(outsideBox.size.height, 50.0); }); - testWidgets('FittedBox without child does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FittedBox without child does not throw', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: SizedBox( diff --git a/packages/flutter/test/widgets/flex_test.dart b/packages/flutter/test/widgets/flex_test.dart index 1a29b997e29aa..ea48423f574f8 100644 --- a/packages/flutter/test/widgets/flex_test.dart +++ b/packages/flutter/test/widgets/flex_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can hit test flex children of stacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can hit test flex children of stacks', (WidgetTester tester) async { bool didReceiveTap = false; await tester.pumpWidget( Directionality( @@ -47,7 +48,7 @@ void main() { expect(didReceiveTap, isTrue); }); - testWidgets('Flexible defaults to loose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flexible defaults to loose', (WidgetTester tester) async { await tester.pumpWidget( const Row( textDirection: TextDirection.ltr, @@ -61,7 +62,7 @@ void main() { expect(box.size.width, 100.0); }); - testWidgets("Doesn't overflow because of floating point accumulated error", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Doesn't overflow because of floating point accumulated error", (WidgetTester tester) async { // both of these cases have failed in the past due to floating point issues await tester.pumpWidget( const Center( @@ -99,7 +100,7 @@ void main() { ); }); - testWidgets('Error information is printed correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Error information is printed correctly', (WidgetTester tester) async { // We run this twice, the first time without an error, so that the second time // we only get a single exception. Otherwise we'd get two, the one we want and // an extra one when we discover we never computed a size. @@ -133,7 +134,7 @@ void main() { expect(message, contains('\nSee also:')); }); - testWidgets('Can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(const Flex(direction: Axis.vertical)); final RenderFlex renderObject = tester.allRenderObjects.whereType<RenderFlex>().first; expect(renderObject.clipBehavior, equals(Clip.none)); diff --git a/packages/flutter/test/widgets/flow_test.dart b/packages/flutter/test/widgets/flow_test.dart index 0746896d9f31d..2a517963e20af 100644 --- a/packages/flutter/test/widgets/flow_test.dart +++ b/packages/flutter/test/widgets/flow_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestFlowDelegate extends FlowDelegate { TestFlowDelegate({required this.startOffset}) : super(repaint: startOffset); @@ -61,7 +62,7 @@ class DuplicatePainterOpacityFlowDelegate extends OpacityFlowDelegate { } void main() { - testWidgets('Flow control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flow control test', (WidgetTester tester) async { final AnimationController startOffset = AnimationController.unbounded( vsync: tester, ); @@ -115,7 +116,7 @@ void main() { expect(log, equals(<int>[0])); }); - testWidgets('paintChild gets called twice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('paintChild gets called twice', (WidgetTester tester) async { await tester.pumpWidget( Flow( delegate: DuplicatePainterOpacityFlowDelegate(1.0), @@ -137,7 +138,7 @@ void main() { )); }); - testWidgets('Flow opacity layer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flow opacity layer', (WidgetTester tester) async { const double opacity = 0.2; await tester.pumpWidget( Flow( @@ -157,7 +158,7 @@ void main() { expect(layer!.firstChild, isA<TransformLayer>()); }); - testWidgets('Flow can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flow can set and update clipBehavior', (WidgetTester tester) async { const double opacity = 0.2; await tester.pumpWidget( Flow( @@ -186,7 +187,7 @@ void main() { } }); - testWidgets('Flow.unwrapped can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flow.unwrapped can set and update clipBehavior', (WidgetTester tester) async { const double opacity = 0.2; await tester.pumpWidget( Flow.unwrapped( From cef737c412ff9941a2b14ad6e724e08329a91d7d Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Tue, 12 Sep 2023 17:44:18 -0700 Subject: [PATCH 1234/1547] _YearPicker should dispose ScrollController and MaterialSatesController. (#134393) --- .../lib/src/material/calendar_date_picker.dart | 15 ++++++++++++--- .../lib/src/widgets/scroll_controller.dart | 2 -- .../test/material/calendar_date_picker_test.dart | 5 +++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 4b1f892dd88ea..303bb43be1773 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -1147,7 +1147,8 @@ class YearPicker extends StatefulWidget { } class _YearPickerState extends State<YearPicker> { - late ScrollController _scrollController; + ScrollController? _scrollController; + final MaterialStatesController _statesController = MaterialStatesController(); // The approximate number of years necessary to fill the available space. static const int minYears = 18; @@ -1158,11 +1159,18 @@ class _YearPickerState extends State<YearPicker> { _scrollController = ScrollController(initialScrollOffset: _scrollOffsetForYear(widget.selectedDate ?? widget.firstDate)); } + @override + void dispose() { + _scrollController?.dispose(); + _statesController.dispose(); + super.dispose(); + } + @override void didUpdateWidget(YearPicker oldWidget) { super.didUpdateWidget(oldWidget); if (widget.selectedDate != oldWidget.selectedDate && widget.selectedDate != null) { - _scrollController.jumpTo(_scrollOffsetForYear(widget.selectedDate!)); + _scrollController!.jumpTo(_scrollOffsetForYear(widget.selectedDate!)); } } @@ -1255,10 +1263,11 @@ class _YearPickerState extends State<YearPicker> { assert(date.year == widget.lastDate.year); date = DateTime(year, widget.lastDate.month); } + _statesController.value = states; yearItem = InkWell( key: ValueKey<int>(year), onTap: () => widget.onChanged(date), - statesController: MaterialStatesController(states), + statesController: _statesController, overlayColor: overlayColor, child: yearItem, ); diff --git a/packages/flutter/lib/src/widgets/scroll_controller.dart b/packages/flutter/lib/src/widgets/scroll_controller.dart index 9f59adefc751a..1f794b2ee2c9b 100644 --- a/packages/flutter/lib/src/widgets/scroll_controller.dart +++ b/packages/flutter/lib/src/widgets/scroll_controller.dart @@ -57,8 +57,6 @@ typedef ScrollControllerCallback = void Function(ScrollPosition position); /// listen to scrolling occur without using a [ScrollController]. class ScrollController extends ChangeNotifier { /// Creates a controller for a scrollable widget. - /// - /// The values of `initialScrollOffset` and `keepScrollOffset` must not be null. ScrollController({ double initialScrollOffset = 0.0, this.keepScrollOffset = true, diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index 98b95e8c42743..7dcf81209da9e 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'feedback_tester.dart'; @@ -211,7 +212,7 @@ void main() { expect(selectedDate, equals(DateTime(2018, DateTime.january, 4))); }); - testWidgets('Changing year for february 29th', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing year for february 29th', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2020, DateTime.february, 29), @@ -230,7 +231,7 @@ void main() { expect(selectedDate, equals(DateTime(2020, DateTime.february, 28))); }); - testWidgets('Changing year does not change the month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing year does not change the month', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), From 57d2bad7baf98a0688b3420168fcbdc8ddfa831e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 20:46:31 -0400 Subject: [PATCH 1235/1547] Manual roll Flutter Engine from 496ef6a9c277 to c90fadf45d44 (6 revisions) (#134589) Manual roll requested by bdero@google.com https://github.com/flutter/engine/compare/496ef6a9c277...c90fadf45d44 2023-09-12 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 43d4b1373788 to 1ee7ef8bbc65 (6 revisions) (flutter/engine#45726) 2023-09-12 ychris@google.com Reland "Build iOS unittest target in unopt builds" (#44356)"" (#45346)" (flutter/engine#45519) 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from a4f8f5177c8b to 211d63b1e1f5 (2 revisions) (flutter/engine#45724) 2023-09-12 jacksongardner@google.com Fix JS interop signatures to use only JS types. (flutter/engine#45668) 2023-09-12 ychris@google.com [ios] Fix testDeallocated failing locally. (flutter/engine#45663) 2023-09-12 ychris@google.com [iOS] move arm64 builds to arm machines (flutter/engine#45721) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 10be309802d6b..b495f0d43d2ff 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -496ef6a9c277e5572fa4350a50ff140816c73845 +c90fadf45d44167e338d957f04786527aa7a3f55 From 6c7ddb859dc56e4f01fe7bd9f318689db3f5ee2e Mon Sep 17 00:00:00 2001 From: hangyu <jhy03261997@gmail.com> Date: Tue, 12 Sep 2023 18:52:41 -0700 Subject: [PATCH 1236/1547] Update BottomSheetTest (#134562) --- packages/flutter/test/material/bottom_sheet_test.dart | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart index fa5e91d1a9caf..1fe54d95d8faa 100644 --- a/packages/flutter/test/material/bottom_sheet_test.dart +++ b/packages/flutter/test/material/bottom_sheet_test.dart @@ -1673,8 +1673,7 @@ void main() { }); group('Modal BottomSheet avoids overlapping display features', () { - testWidgetsWithLeakTracking('positioning using anchorPoint', - (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning using anchorPoint', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1710,12 +1709,7 @@ void main() { // Should take the right side of the screen expect(tester.getTopLeft(find.byType(Placeholder)).dx, 410); expect(tester.getBottomRight(find.byType(Placeholder)).dx, 800); - }, - leakTrackingTestConfig: const LeakTrackingTestConfig( - // TODO(polina-c): remove after fix - // https://github.com/flutter/flutter/issues/133594 - notDisposedAllowList: <String, int?> {'ValueNotifier<EdgeInsets>': 1} - )); + }); testWidgetsWithLeakTracking('positioning using Directionality', (WidgetTester tester) async { await tester.pumpWidget( From 15b00bf6a7a8222a7fca2a2539aa8fd299f1ebe9 Mon Sep 17 00:00:00 2001 From: chrisdlangham <chris.langham32@gmail.com> Date: Tue, 12 Sep 2023 21:52:25 -0500 Subject: [PATCH 1237/1547] removed unused variable in the example code of semantic event (#134551) removes unused variable in the example code of semantic events https://api.flutter.dev/flutter/semantics/FocusSemanticEvent-class.html --- packages/flutter/lib/src/semantics/semantics_event.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/flutter/lib/src/semantics/semantics_event.dart b/packages/flutter/lib/src/semantics/semantics_event.dart index ce2759e774012..6350a9a47f1ee 100644 --- a/packages/flutter/lib/src/semantics/semantics_event.dart +++ b/packages/flutter/lib/src/semantics/semantics_event.dart @@ -188,7 +188,6 @@ class TapSemanticEvent extends SemanticsEvent { /// } /// /// class _MyWidgetState extends State<MyWidget> { -/// bool noticeAccepted = false; /// final GlobalKey mykey = GlobalKey(); /// /// @override From 68ce499e115185d4de2a1beeac92ceede5337944 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 12 Sep 2023 22:53:54 -0400 Subject: [PATCH 1238/1547] Roll Flutter Engine from c90fadf45d44 to 7c78ea210c19 (10 revisions) (#134597) https://github.com/flutter/engine/compare/c90fadf45d44...7c78ea210c19 2023-09-12 zanderso@users.noreply.github.com Revert "Lazily allocate RasterCacheItems only when caching is enabled" (flutter/engine#45734) 2023-09-12 1961493+harryterkelsen@users.noreply.github.com Revert "Use a single OffscreenCanvas for rendering in CanvasKit" (flutter/engine#45744) 2023-09-12 chinmaygarde@google.com [Impeller] Patch the compiler to account for subpass inputs and PSO metadata. (flutter/engine#45739) 2023-09-12 chinmaygarde@google.com [Impeller] Fix swapchain recreation for non-polling cases. (flutter/engine#45740) 2023-09-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from QgAHx3BtJfN3TmodS... to UCa49z8fu0hD9cypj... (flutter/engine#45738) 2023-09-12 ychris@google.com [ios] upload extension safe artifacts (flutter/engine#45664) 2023-09-12 30870216+gaaclarke@users.noreply.github.com Added test to assert the vulkan embedder threadsafe vkqueue usage (flutter/engine#45732) 2023-09-12 chinmaygarde@google.com [Impeller] If validations are enabled but not found, still create the VK context. (flutter/engine#45674) 2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 211d63b1e1f5 to 2d295711337c (7 revisions) (flutter/engine#45729) 2023-09-12 1961493+harryterkelsen@users.noreply.github.com Use a single OffscreenCanvas for rendering in CanvasKit (flutter/engine#42672) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from QgAHx3BtJfN3 to UCa49z8fu0hD If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b495f0d43d2ff..d81f7924ecd48 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c90fadf45d44167e338d957f04786527aa7a3f55 +7c78ea210c194ebaba08189ae116fe021b48d716 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 28999760cc613..1d7ef91f067e2 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -QgAHx3BtJfN3TmodSqY480Oyo-FI8WHUnMIAuYsoSukC +UCa49z8fu0hD9cypjheuQiKHVf0WO6mAuqEQBeedVz4C From 9ec7ce6348b79984412dbf40bc28def5c7e67d4a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 00:37:38 -0400 Subject: [PATCH 1239/1547] Roll Flutter Engine from 7c78ea210c19 to 1273bfaa70c6 (1 revision) (#134602) https://github.com/flutter/engine/compare/7c78ea210c19...1273bfaa70c6 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 2d295711337c to b7d77eb2a9d3 (2 revisions) (flutter/engine#45753) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d81f7924ecd48..e5a9c72bd77e9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7c78ea210c194ebaba08189ae116fe021b48d716 +1273bfaa70c6589e5cc05dde660ff1a57cb1730b From 3bd6294891aedd071d5f9d0eac099c80e36cdbb0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 01:30:13 -0400 Subject: [PATCH 1240/1547] Roll Flutter Engine from 1273bfaa70c6 to fb60ecf44c22 (1 revision) (#134606) https://github.com/flutter/engine/compare/1273bfaa70c6...fb60ecf44c22 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from b7d77eb2a9d3 to 29e7723e1f8c (2 revisions) (flutter/engine#45755) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e5a9c72bd77e9..e6839af1c7bff 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1273bfaa70c6589e5cc05dde660ff1a57cb1730b +fb60ecf44c2217c82d4de94e96d95665e9dba5f6 From d3bc797758fd46440ad1140f38c215f3ac7ed403 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 03:13:39 -0400 Subject: [PATCH 1241/1547] Roll Flutter Engine from fb60ecf44c22 to 8611cb0ce32d (1 revision) (#134610) https://github.com/flutter/engine/compare/fb60ecf44c22...8611cb0ce32d 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 29e7723e1f8c to 2ec12c767ec7 (1 revision) (flutter/engine#45758) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e6839af1c7bff..24ac2144bdf3c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fb60ecf44c2217c82d4de94e96d95665e9dba5f6 +8611cb0ce32d50c4c2ab92d16d28de989cbf213f From f7997c54e013a502b13dad65166787f62db54836 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 03:57:28 -0400 Subject: [PATCH 1242/1547] Roll Flutter Engine from 8611cb0ce32d to c2224989356f (2 revisions) (#134612) https://github.com/flutter/engine/compare/8611cb0ce32d...c2224989356f 2023-09-13 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from MWWrSP9mSVlGIOaDo... to ftcEc93bjtc0q2a6s... (flutter/engine#45760) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 2ec12c767ec7 to 0d6b0aadb065 (1 revision) (flutter/engine#45759) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from MWWrSP9mSVlG to ftcEc93bjtc0 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 24ac2144bdf3c..1f318fb267d85 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8611cb0ce32d50c4c2ab92d16d28de989cbf213f +c2224989356f3b1cd50ce94bb15a3e8409e5913f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 28a64e41cf9ac..2c68ed00ec956 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -MWWrSP9mSVlGIOaDoAhSNSx_v1fGNKJtHenmI0aa4IAC +ftcEc93bjtc0q2a6skMN1MORORVVwcAJIW8gUyhP_Q4C From e0160cb4e451e1fefd84f59da4c514ed76ac0191 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 08:05:24 -0400 Subject: [PATCH 1243/1547] Roll Flutter Engine from c2224989356f to 19cfb4ca29bf (1 revision) (#134646) https://github.com/flutter/engine/compare/c2224989356f...19cfb4ca29bf 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 0d6b0aadb065 to 3ff43577d04b (1 revision) (flutter/engine#45763) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1f318fb267d85..85b130722e7dc 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c2224989356f3b1cd50ce94bb15a3e8409e5913f +19cfb4ca29bf7f27563ce0e8d511c47c592bad38 From 3f76be54495ad32e407a6746a8284288c74a8e8d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 08:49:34 -0400 Subject: [PATCH 1244/1547] Roll Flutter Engine from 19cfb4ca29bf to a8d7d8125382 (1 revision) (#134648) https://github.com/flutter/engine/compare/19cfb4ca29bf...a8d7d8125382 2023-09-13 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from UCa49z8fu0hD9cypj... to gHhOd3d6V3Zv6CzK2... (flutter/engine#45764) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from UCa49z8fu0hD to gHhOd3d6V3Zv If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 85b130722e7dc..954af9b78831b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -19cfb4ca29bf7f27563ce0e8d511c47c592bad38 +a8d7d812538288fbf754c5a2b02c1bfad356356b diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 1d7ef91f067e2..958c35133ad8a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -UCa49z8fu0hD9cypjheuQiKHVf0WO6mAuqEQBeedVz4C +gHhOd3d6V3Zv6CzK2s7BcyuC4jOjrn9t1vfN-QWP3nMC From 622c2b2b07217335cb0fda5447fa0c0b46ecfab8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 09:35:29 -0400 Subject: [PATCH 1245/1547] Roll Flutter Engine from a8d7d8125382 to 5e671d5c90f9 (1 revision) (#134650) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/flutter/engine/compare/a8d7d8125382...5e671d5c90f9 2023-09-13 whesse@google.com Roll devtools from acbc179425b4596b7c2ba7d9c4263077f2e18098 to adfb08… (flutter/engine#45766) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 954af9b78831b..03f0fa49f0a59 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a8d7d812538288fbf754c5a2b02c1bfad356356b +5e671d5c90f9088c7cad498dc8ecfbab8d03336a From 0aa879919cb26d1c4e8ab89285726db450389f80 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 11:52:08 -0400 Subject: [PATCH 1246/1547] Roll Packages from e04ba886a85e to 06cd9e967b9f (3 revisions) (#134662) https://github.com/flutter/packages/compare/e04ba886a85e...06cd9e967b9f 2023-09-13 kevmoo@users.noreply.github.com Replace collection type lints with more general lint (flutter/packages#4912) 2023-09-12 engine-flutter-autoroll@skia.org Roll Flutter from 219efce7f16d to 4e7a07af882c (30 revisions) (flutter/packages#4910) 2023-09-12 43054281+camsim99@users.noreply.github.com [camerax] Implement `startVideoCapturing` and `onVideoRecordedEvent` (flutter/packages#4815) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 317d6304a6253..3e7efced9baae 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -e04ba886a85edfd4fcea794d0e06be062953d480 +06cd9e967b9f17da3eea812a6f85394f62278aec From 639c092b5d566f80eb9b3ace873619b1fefc47a3 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Wed, 13 Sep 2023 09:35:22 -0700 Subject: [PATCH 1247/1547] Marks Windows_android channels_integration_test_win to be flaky (#134637) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows_android channels_integration_test_win" } --> Issue link: https://github.com/flutter/flutter/issues/134636 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 3ccd3707a56bb..e918b6500e5d6 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -5101,6 +5101,7 @@ targets: task_name: basic_material_app_win__compile - name: Windows_android channels_integration_test_win + bringup: true # Flaky https://github.com/flutter/flutter/issues/134636 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 From f38dcb122905d234e74950b10b2ec5cacb320023 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Wed, 13 Sep 2023 09:36:18 -0700 Subject: [PATCH 1248/1547] Marks Windows module_custom_host_app_name_test to be flaky (#134645) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows module_custom_host_app_name_test" } --> Issue link: https://github.com/flutter/flutter/issues/134644 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index e918b6500e5d6..57c5c163479d0 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4599,6 +4599,7 @@ targets: task_name: hot_mode_dev_cycle_win_target__benchmark - name: Windows module_custom_host_app_name_test + bringup: true # Flaky https://github.com/flutter/flutter/issues/134644 recipe: devicelab/devicelab_drone timeout: 60 properties: From 7cd8b4074fa43a073bbf4a67c6b0c54a78b36f1a Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Wed, 13 Sep 2023 18:54:19 +0200 Subject: [PATCH 1249/1547] Cover more test/widgets tests with leak tracking #4 (#134663) --- .../widgets/implicit_animations_test.dart | 52 ++++---- .../test/widgets/implicit_semantics_test.dart | 5 +- .../widgets/inherited_dependencies_test.dart | 3 +- .../test/widgets/inherited_model_test.dart | 9 +- .../flutter/test/widgets/inherited_test.dart | 27 ++-- .../test/widgets/inherited_theme_test.dart | 7 +- .../flutter/test/widgets/init_state_test.dart | 3 +- .../test/widgets/interactive_viewer_test.dart | 126 ++++++++---------- .../test/widgets/intrinsic_width_test.dart | 3 +- .../test/widgets/invert_colors_test.dart | 5 +- .../flutter/test/widgets/keep_alive_test.dart | 9 +- packages/flutter/test/widgets/key_test.dart | 3 +- .../test/widgets/keyboard_listener_test.dart | 16 ++- .../layout_builder_and_global_keys_test.dart | 5 +- .../layout_builder_and_parent_data_test.dart | 3 +- .../layout_builder_and_state_test.dart | 3 +- .../layout_builder_mutations_test.dart | 7 +- .../test/widgets/layout_builder_test.dart | 31 +++-- .../test/widgets/linked_scroll_view_test.dart | 5 +- .../flutter/test/widgets/list_body_test.dart | 13 +- .../test/widgets/list_view_builder_test.dart | 27 ++-- .../widgets/list_view_correction_test.dart | 13 +- .../test/widgets/list_view_fling_test.dart | 3 +- .../widgets/list_view_horizontal_test.dart | 9 +- .../test/widgets/list_view_misc_test.dart | 14 +- .../test/widgets/list_view_relayout_test.dart | 13 +- .../widgets/list_view_semantics_test.dart | 13 +- .../flutter/test/widgets/list_view_test.dart | 62 +++++---- .../test/widgets/list_view_vertical_test.dart | 5 +- .../widgets/list_view_viewporting_test.dart | 50 ++++--- .../list_view_with_inherited_test.dart | 3 +- 31 files changed, 301 insertions(+), 246 deletions(-) diff --git a/packages/flutter/test/widgets/implicit_animations_test.dart b/packages/flutter/test/widgets/implicit_animations_test.dart index 4059687665586..d71b942d23dba 100644 --- a/packages/flutter/test/widgets/implicit_animations_test.dart +++ b/packages/flutter/test/widgets/implicit_animations_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class MockOnEndFunction { int called = 0; @@ -24,7 +25,7 @@ void main() { mockOnEndFunction = MockOnEndFunction(); }); - testWidgets('BoxConstraintsTween control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BoxConstraintsTween control test', (WidgetTester tester) async { final BoxConstraintsTween tween = BoxConstraintsTween( begin: BoxConstraints.tight(const Size(20.0, 50.0)), end: BoxConstraints.tight(const Size(10.0, 30.0)), @@ -36,7 +37,7 @@ void main() { expect(result.maxHeight, 45.0); }); - testWidgets('DecorationTween control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationTween control test', (WidgetTester tester) async { final DecorationTween tween = DecorationTween( begin: const BoxDecoration(color: Color(0xFF00FF00)), end: const BoxDecoration(color: Color(0xFFFFFF00)), @@ -45,7 +46,7 @@ void main() { expect(result.color, const Color(0xFF3FFF00)); }); - testWidgets('EdgeInsetsTween control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EdgeInsetsTween control test', (WidgetTester tester) async { final EdgeInsetsTween tween = EdgeInsetsTween( begin: const EdgeInsets.symmetric(vertical: 50.0), end: const EdgeInsets.only(top: 10.0, bottom: 30.0), @@ -57,7 +58,7 @@ void main() { expect(result.bottom, 45.0); }); - testWidgets('Matrix4Tween control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Matrix4Tween control test', (WidgetTester tester) async { final Matrix4Tween tween = Matrix4Tween( begin: Matrix4.translationValues(10.0, 20.0, 30.0), end: Matrix4.translationValues(14.0, 24.0, 34.0), @@ -66,7 +67,7 @@ void main() { expect(result, equals(Matrix4.translationValues(11.0, 21.0, 31.0))); }); - testWidgets('AnimatedContainer onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedContainer onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -89,7 +90,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedPadding onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPadding onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -112,7 +113,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedAlign onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedAlign onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -135,7 +136,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedPositioned onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositioned onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -158,7 +159,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedPositionedDirectional onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPositionedDirectional onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -181,7 +182,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedSlide onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSlide onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -203,7 +204,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedSlide transition test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedSlide transition test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( switchKey: switchKey, @@ -241,7 +242,7 @@ void main() { expect(state.builds, equals(2)); }); - testWidgets('AnimatedScale onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedScale onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -263,7 +264,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedScale transition test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedScale transition test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( switchKey: switchKey, @@ -301,7 +302,7 @@ void main() { expect(state.builds, equals(2)); }); - testWidgets('AnimatedRotation onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedRotation onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -323,7 +324,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedRotation transition test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedRotation transition test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( switchKey: switchKey, @@ -361,7 +362,7 @@ void main() { expect(state.builds, equals(2)); }); - testWidgets('AnimatedOpacity onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedOpacity onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -383,7 +384,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedOpacity transition test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedOpacity transition test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( switchKey: switchKey, @@ -421,7 +422,7 @@ void main() { expect(state.builds, equals(2)); }); - testWidgets('AnimatedFractionallySizedBox onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedFractionallySizedBox onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -443,7 +444,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('SliverAnimatedOpacity onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAnimatedOpacity onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(TestAnimatedWidget( callback: mockOnEndFunction.handler, switchKey: switchKey, @@ -464,7 +465,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('SliverAnimatedOpacity transition test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAnimatedOpacity transition test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( switchKey: switchKey, @@ -502,7 +503,7 @@ void main() { expect(state.builds, equals(2)); }); - testWidgets('AnimatedDefaultTextStyle onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedDefaultTextStyle onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -525,7 +526,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -548,7 +549,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('TweenAnimationBuilder onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TweenAnimationBuilder onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -571,7 +572,7 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('AnimatedTheme onEnd callback test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedTheme onEnd callback test', (WidgetTester tester) async { await tester.pumpWidget(wrap( child: TestAnimatedWidget( callback: mockOnEndFunction.handler, @@ -594,11 +595,12 @@ void main() { await tapTest2and3(tester, widgetFinder, mockOnEndFunction); }); - testWidgets('Ensure CurvedAnimations are disposed on widget change', + testWidgetsWithLeakTracking('Ensure CurvedAnimations are disposed on widget change', (WidgetTester tester) async { final GlobalKey<ImplicitlyAnimatedWidgetState<AnimatedOpacity>> key = GlobalKey<ImplicitlyAnimatedWidgetState<AnimatedOpacity>>(); final ValueNotifier<Curve> curve = ValueNotifier<Curve>(const Interval(0.0, 0.5)); + addTearDown(curve.dispose); await tester.pumpWidget(wrap( child: ValueListenableBuilder<Curve>( valueListenable: curve, diff --git a/packages/flutter/test/widgets/implicit_semantics_test.dart b/packages/flutter/test/widgets/implicit_semantics_test.dart index 42ef79223539a..41d6ac7e21fbd 100644 --- a/packages/flutter/test/widgets/implicit_semantics_test.dart +++ b/packages/flutter/test/widgets/implicit_semantics_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Implicit Semantics merge behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Implicit Semantics merge behavior', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -172,7 +173,7 @@ void main() { semantics.dispose(); }); - testWidgets('Do not merge with conflicts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not merge with conflicts', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/inherited_dependencies_test.dart b/packages/flutter/test/widgets/inherited_dependencies_test.dart index 2ed743e47cc07..22840f52892f8 100644 --- a/packages/flutter/test/widgets/inherited_dependencies_test.dart +++ b/packages/flutter/test/widgets/inherited_dependencies_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/src/widgets/basic.dart'; import 'package:flutter/src/widgets/framework.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('InheritedWidget dependencies show up in diagnostic properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedWidget dependencies show up in diagnostic properties', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(Directionality( key: key, diff --git a/packages/flutter/test/widgets/inherited_model_test.dart b/packages/flutter/test/widgets/inherited_model_test.dart index 6753361cb42e4..b1ae5ef2f69c9 100644 --- a/packages/flutter/test/widgets/inherited_model_test.dart +++ b/packages/flutter/test/widgets/inherited_model_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // A simple "flat" InheritedModel: the data model is just 3 integer // valued fields: a, b, c. @@ -73,7 +74,7 @@ class _ShowABCFieldState extends State<ShowABCField> { } void main() { - testWidgets('InheritedModel basics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedModel basics', (WidgetTester tester) async { int a = 0; int b = 1; int c = 2; @@ -189,7 +190,7 @@ void main() { expect(find.text('a: 2 b: 2 c: 3'), findsOneWidget); }); - testWidgets('Looking up an non existent InheritedModel ancestor returns null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Looking up an non existent InheritedModel ancestor returns null', (WidgetTester tester) async { ABCModel? inheritedModel; await tester.pumpWidget( @@ -205,7 +206,7 @@ void main() { expect(inheritedModel, null); }); - testWidgets('Inner InheritedModel shadows the outer one', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inner InheritedModel shadows the outer one', (WidgetTester tester) async { int a = 0; int b = 1; int c = 2; @@ -323,7 +324,7 @@ void main() { expect(find.text('a: 102 b: 102 c: null'), findsOneWidget); }); - testWidgets('InheritedModel inner models supported aspect change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedModel inner models supported aspect change', (WidgetTester tester) async { int a = 0; int b = 1; int c = 2; diff --git a/packages/flutter/test/widgets/inherited_test.dart b/packages/flutter/test/widgets/inherited_test.dart index e1c9b8c83f011..478ed93d419d4 100644 --- a/packages/flutter/test/widgets/inherited_test.dart +++ b/packages/flutter/test/widgets/inherited_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; @@ -55,7 +56,7 @@ class ChangeNotifierInherited extends InheritedNotifier<ChangeNotifier> { } void main() { - testWidgets('Inherited notifies dependents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited notifies dependents', (WidgetTester tester) async { final List<TestInherited> log = <TestInherited>[]; final Builder builder = Builder( @@ -81,7 +82,7 @@ void main() { expect(log, equals(<TestInherited>[first, third])); }); - testWidgets('Update inherited when reparenting state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update inherited when reparenting state', (WidgetTester tester) async { final GlobalKey globalKey = GlobalKey(); final List<TestInherited> log = <TestInherited>[]; @@ -111,7 +112,7 @@ void main() { expect(log, equals(<TestInherited>[first, second])); }); - testWidgets('Update inherited when removing node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update inherited when removing node', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -166,7 +167,7 @@ void main() { log.clear(); }); - testWidgets('Update inherited when removing node and child has global key', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update inherited when removing node and child has global key', (WidgetTester tester) async { final List<String> log = <String>[]; @@ -230,7 +231,7 @@ void main() { log.clear(); }); - testWidgets('Update inherited when removing node and child has global key with constant child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update inherited when removing node and child has global key with constant child', (WidgetTester tester) async { final List<int> log = <int>[]; final Key key = GlobalKey(); @@ -289,7 +290,7 @@ void main() { log.clear(); }); - testWidgets('Update inherited when removing node and child has global key with constant child, minimised', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Update inherited when removing node and child has global key with constant child, minimised', (WidgetTester tester) async { final List<int> log = <int>[]; @@ -336,7 +337,7 @@ void main() { log.clear(); }); - testWidgets('Inherited widget notifies descendants when descendant previously failed to find a match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited widget notifies descendants when descendant previously failed to find a match', (WidgetTester tester) async { int? inheritedValue = -1; final Widget inner = Container( @@ -365,7 +366,7 @@ void main() { expect(inheritedValue, equals(3)); }); - testWidgets("Inherited widget doesn't notify descendants when descendant did not previously fail to find a match and had no dependencies", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Inherited widget doesn't notify descendants when descendant did not previously fail to find a match and had no dependencies", (WidgetTester tester) async { int buildCount = 0; final Widget inner = Container( @@ -392,7 +393,7 @@ void main() { expect(buildCount, equals(1)); }); - testWidgets('Inherited widget does notify descendants when descendant did not previously fail to find a match but did have other dependencies', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited widget does notify descendants when descendant did not previously fail to find a match but did have other dependencies', (WidgetTester tester) async { int buildCount = 0; final Widget inner = Container( @@ -423,10 +424,11 @@ void main() { expect(buildCount, equals(2)); }); - testWidgets("BuildContext.getInheritedWidgetOfExactType doesn't create a dependency", (WidgetTester tester) async { + testWidgetsWithLeakTracking("BuildContext.getInheritedWidgetOfExactType doesn't create a dependency", (WidgetTester tester) async { int buildCount = 0; final GlobalKey<void> inheritedKey = GlobalKey(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); final Widget builder = Builder( builder: (BuildContext context) { @@ -449,7 +451,7 @@ void main() { expect(buildCount, equals(1)); }); - testWidgets('initState() dependency on Inherited asserts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initState() dependency on Inherited asserts', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/5491 bool exceptionCaught = false; @@ -461,9 +463,10 @@ void main() { expect(exceptionCaught, isTrue); }); - testWidgets('InheritedNotifier', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedNotifier', (WidgetTester tester) async { int buildCount = 0; final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); final Widget builder = Builder( builder: (BuildContext context) { diff --git a/packages/flutter/test/widgets/inherited_theme_test.dart b/packages/flutter/test/widgets/inherited_theme_test.dart index 1b677ac81af26..6315cc4674a04 100644 --- a/packages/flutter/test/widgets/inherited_theme_test.dart +++ b/packages/flutter/test/widgets/inherited_theme_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestRoute extends PageRouteBuilder<void> { TestRoute(Widget child) : super( @@ -26,7 +27,7 @@ class IconTextBox extends StatelessWidget { } void main() { - testWidgets('InheritedTheme.captureAll()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedTheme.captureAll()', (WidgetTester tester) async { const double fontSize = 32; const double iconSize = 48; const Color textColor = Color(0xFF00FF00); @@ -146,7 +147,7 @@ void main() { expect(getIconStyle().fontSize, iconSize); }); - testWidgets('InheritedTheme.captureAll() multiple IconTheme ancestors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedTheme.captureAll() multiple IconTheme ancestors', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/39087 const Color outerColor = Color(0xFF0000FF); @@ -206,7 +207,7 @@ void main() { expect(getIconStyle(icon2).fontSize, iconSize); }); - testWidgets('InheritedTheme.captureAll() multiple DefaultTextStyle ancestors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InheritedTheme.captureAll() multiple DefaultTextStyle ancestors', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/39087 const Color textColor = Color(0xFF00FF00); diff --git a/packages/flutter/test/widgets/init_state_test.dart b/packages/flutter/test/widgets/init_state_test.dart index d6b74a256d30b..759f325d9171c 100644 --- a/packages/flutter/test/widgets/init_state_test.dart +++ b/packages/flutter/test/widgets/init_state_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; List<String> ancestors = <String>[]; @@ -28,7 +29,7 @@ class TestWidgetState extends State<TestWidget> { } void main() { - testWidgets('initState() is called when we are in the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initState() is called when we are in the tree', (WidgetTester tester) async { await tester.pumpWidget(const Parent(child: TestWidget())); expect(ancestors, containsAllInOrder(<String>['Parent', 'View', 'RootWidget'])); }); diff --git a/packages/flutter/test/widgets/interactive_viewer_test.dart b/packages/flutter/test/widgets/interactive_viewer_test.dart index b2adda8d87b1f..cf6be6a599864 100644 --- a/packages/flutter/test/widgets/interactive_viewer_test.dart +++ b/packages/flutter/test/widgets/interactive_viewer_test.dart @@ -8,14 +8,24 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'package:vector_math/vector_math_64.dart' show Matrix4, Quad, Vector3; import 'gesture_utils.dart'; void main() { group('InteractiveViewer', () { - testWidgets('child fits in viewport', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + late TransformationController transformationController; + + setUp(() { + transformationController = TransformationController(); + }); + + tearDown(() { + transformationController.dispose(); + }); + + testWidgetsWithLeakTracking('child fits in viewport', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -65,8 +75,7 @@ void main() { expect(transformationController.value, isNot(equals(Matrix4.identity()))); }); - testWidgets('boundary slightly bigger than child', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('boundary slightly bigger than child', (WidgetTester tester) async { const double boundaryMargin = 10.0; await tester.pumpWidget( MaterialApp( @@ -121,8 +130,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), 200.0 / 220.0); }); - testWidgets('child bigger than viewport', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('child bigger than viewport', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -197,8 +205,7 @@ void main() { expect(transformationController.value, isNot(equals(Matrix4.identity()))); }); - testWidgets('child has no dimensions', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('child has no dimensions', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -232,8 +239,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('no boundary', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('no boundary', (WidgetTester tester) async { const double minScale = 0.8; await tester.pumpWidget( MaterialApp( @@ -288,8 +294,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), minScale); }); - testWidgets('PanAxis.free allows panning in all directions for diagonal gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.free allows panning in all directions for diagonal gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -326,8 +331,7 @@ void main() { expect(translation.y, childOffset.dy - childInterior.dy); }); - testWidgets('PanAxis.aligned allows panning in one direction only for diagonal gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.aligned allows panning in one direction only for diagonal gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -365,8 +369,7 @@ void main() { expect(translation.y, childOffset.dy - childInterior.dy); }); - testWidgets('PanAxis.aligned allows panning in one direction only for horizontal leaning gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.aligned allows panning in one direction only for horizontal leaning gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -404,8 +407,7 @@ void main() { expect(translation.y, 0.0); }); - testWidgets('PanAxis.horizontal allows panning in the horizontal direction only for diagonal gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.horizontal allows panning in the horizontal direction only for diagonal gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -443,8 +445,7 @@ void main() { expect(translation.y, 0.0); }); - testWidgets('PanAxis.horizontal allows panning in the horizontal direction only for horizontal leaning gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.horizontal allows panning in the horizontal direction only for horizontal leaning gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -482,8 +483,7 @@ void main() { expect(translation.y, 0.0); }); - testWidgets('PanAxis.horizontal does not allow panning in vertical direction on vertical gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.horizontal does not allow panning in vertical direction on vertical gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -521,8 +521,7 @@ void main() { expect(translation.y, 0.0); }); - testWidgets('PanAxis.vertical allows panning in the vertical direction only for diagonal gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.vertical allows panning in the vertical direction only for diagonal gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -560,8 +559,7 @@ void main() { expect(translation.x, 0.0); }); - testWidgets('PanAxis.vertical allows panning in the vertical direction only for vertical leaning gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.vertical allows panning in the vertical direction only for vertical leaning gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -599,8 +597,7 @@ void main() { expect(translation.x, 0.0); }); - testWidgets('PanAxis.vertical does not allow panning in horizontal direction on vertical gesture', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('PanAxis.vertical does not allow panning in horizontal direction on vertical gesture', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -638,8 +635,7 @@ void main() { expect(translation.y, 0.0); }); - testWidgets('inertia fling and boundary sliding', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('inertia fling and boundary sliding', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( @@ -697,8 +693,7 @@ void main() { expect(translation.y, moreOrLessEquals(boundaryMargin, epsilon: 1e-9)); }); - testWidgets('Scaling automatically causes a centering translation', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Scaling automatically causes a centering translation', (WidgetTester tester) async { const double boundaryMargin = 50.0; const double minScale = 0.1; await tester.pumpWidget( @@ -782,8 +777,7 @@ void main() { expect(newSceneFocalPoint.dy, moreOrLessEquals(sceneFocalPoint.dy, epsilon: 1.0)); }); - testWidgets('Scaling automatically causes a centering translation even when alignPanAxis is set', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Scaling automatically causes a centering translation even when alignPanAxis is set', (WidgetTester tester) async { const double boundaryMargin = 50.0; const double minScale = 0.1; await tester.pumpWidget( @@ -874,8 +868,7 @@ void main() { expect(newSceneFocalPoint.dy, moreOrLessEquals(sceneFocalPoint.dy, epsilon: 1.0)); }); - testWidgets('Can scale with mouse', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Can scale with mouse', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -896,8 +889,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), greaterThan(1.0)); }); - testWidgets('Cannot scale with mouse when scale is disabled', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Cannot scale with mouse when scale is disabled', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -919,8 +911,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), equals(1.0)); }); - testWidgets('Scale with mouse returns onInteraction properties', (WidgetTester tester) async{ - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Scale with mouse returns onInteraction properties', (WidgetTester tester) async{ late Offset focalPoint; late Offset localFocalPoint; late double scaleChange; @@ -971,8 +962,7 @@ void main() { expect(scenePoint, const Offset(100, 100)); }); - testWidgets('Scaling amount is equal forth and back with a mouse scroll', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Scaling amount is equal forth and back with a mouse scroll', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1003,8 +993,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), 1.0); }); - testWidgets('onInteraction can be used to get scene point', (WidgetTester tester) async{ - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('onInteraction can be used to get scene point', (WidgetTester tester) async{ late Offset focalPoint; late Offset localFocalPoint; late double scaleChange; @@ -1057,8 +1046,7 @@ void main() { expect(scenePoint.dy, greaterThan(0.0)); }); - testWidgets('onInteraction is called even when disabled (touch)', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('onInteraction is called even when disabled (touch)', (WidgetTester tester) async { bool calledStart = false; bool calledUpdate = false; bool calledEnd = false; @@ -1129,8 +1117,7 @@ void main() { expect(calledEnd, isTrue); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets('onInteraction is called even when disabled (mouse)', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('onInteraction is called even when disabled (mouse)', (WidgetTester tester) async { bool calledStart = false; bool calledUpdate = false; bool calledEnd = false; @@ -1189,10 +1176,9 @@ void main() { expect(calledEnd, isTrue); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS, TargetPlatform.linux, TargetPlatform.windows })); - testWidgets('viewport changes size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('viewport changes size', (WidgetTester tester) async { addTearDown(tester.view.reset); - final TransformationController transformationController = TransformationController(); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1239,8 +1225,7 @@ void main() { expect(transformationController.value, equals(Matrix4.identity())); }); - testWidgets('gesture can start as pan and become scale', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('gesture can start as pan and become scale', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( @@ -1297,8 +1282,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/65304 - testWidgets('can view beyond boundary when necessary for a small child', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('can view beyond boundary when necessary for a small child', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1337,8 +1321,7 @@ void main() { expect(transformationController.value, equals(Matrix4.identity())); }); - testWidgets('scale does not jump when wrapped in GestureDetector', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('scale does not jump when wrapped in GestureDetector', (WidgetTester tester) async { double? initialScale; double? scale; await tester.pumpWidget( @@ -1413,7 +1396,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), greaterThan(1.0)); }); - testWidgets('Check if ClipRect is present in the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Check if ClipRect is present in the tree', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1454,8 +1437,7 @@ void main() { ); }); - testWidgets('builder can change widgets that are off-screen', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('builder can change widgets that are off-screen', (WidgetTester tester) async { const double childHeight = 10.0; await tester.pumpWidget( MaterialApp( @@ -1539,7 +1521,7 @@ void main() { // Accessing the intrinsic size of a LayoutBuilder throws an error, so // InteractiveViewer only uses a LayoutBuilder when it's needed by // InteractiveViewer.builder. - testWidgets('LayoutBuilder is only used for InteractiveViewer.builder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder is only used for InteractiveViewer.builder', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1571,9 +1553,8 @@ void main() { expect(find.byType(LayoutBuilder), findsOneWidget); }); - testWidgets('scaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scaleFactor', (WidgetTester tester) async { const double scrollAmount = 30.0; - final TransformationController transformationController = TransformationController(); Future<void> pumpScaleFactor(double scaleFactor) { return tester.pumpWidget( MaterialApp( @@ -1651,7 +1632,7 @@ void main() { expect(scaleHighZoomedIn - scaleHighZoomedOut, lessThan(scaleZoomedIn - scaleZoomedOut)); }); - testWidgets('alignment argument is used properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('alignment argument is used properly', (WidgetTester tester) async { const Alignment alignment = Alignment.center; await tester.pumpWidget(MaterialApp( @@ -1667,9 +1648,10 @@ void main() { expect(transform.alignment, alignment); }); - testWidgets('interactionEndFrictionCoefficient', (WidgetTester tester) async { + testWidgetsWithLeakTracking('interactionEndFrictionCoefficient', (WidgetTester tester) async { // Use the default interactionEndFrictionCoefficient. final TransformationController transformationController1 = TransformationController(); + addTearDown(transformationController1.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1695,6 +1677,7 @@ void main() { // Next try a custom interactionEndFrictionCoefficient. final TransformationController transformationController2 = TransformationController(); + addTearDown(transformationController2.dispose); await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -1723,8 +1706,7 @@ void main() { expect(translation2.y, lessThan(translation1.y)); }); - testWidgets('discrete scroll pointer events', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('discrete scroll pointer events', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( @@ -1767,8 +1749,7 @@ void main() { expect(translation.y, -125); }); - testWidgets('discrete scale pointer event', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('discrete scale pointer event', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( @@ -1804,8 +1785,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), 2.5); // capped at maxScale (2.5) }); - testWidgets('trackpadScrollCausesScale', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('trackpadScrollCausesScale', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( @@ -1840,8 +1820,7 @@ void main() { expect(transformationController.value.getMaxScaleOnAxis(), moreOrLessEquals(1.499302500056767)); }); - testWidgets('trackpad pointer scroll events cause scale', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('trackpad pointer scroll events cause scale', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( @@ -1891,8 +1870,7 @@ void main() { expect(translation.y, moreOrLessEquals(-99.37155332430822)); }); - testWidgets('Scaling inertia', (WidgetTester tester) async { - final TransformationController transformationController = TransformationController(); + testWidgetsWithLeakTracking('Scaling inertia', (WidgetTester tester) async { const double boundaryMargin = 50.0; await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/intrinsic_width_test.dart b/packages/flutter/test/widgets/intrinsic_width_test.dart index 20848ef9f8d30..b3c1c05e58a14 100644 --- a/packages/flutter/test/widgets/intrinsic_width_test.dart +++ b/packages/flutter/test/widgets/intrinsic_width_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Intrinsic stepWidth, stepHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Intrinsic stepWidth, stepHeight', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25224 Widget buildFrame(double? stepWidth, double? stepHeight) { return Center( diff --git a/packages/flutter/test/widgets/invert_colors_test.dart b/packages/flutter/test/widgets/invert_colors_test.dart index 2c475a9715efe..11be7632ae117 100644 --- a/packages/flutter/test/widgets/invert_colors_test.dart +++ b/packages/flutter/test/widgets/invert_colors_test.dart @@ -10,9 +10,10 @@ library; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('InvertColors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InvertColors', (WidgetTester tester) async { await tester.pumpWidget(const RepaintBoundary( child: SizedBox( width: 200.0, @@ -29,7 +30,7 @@ void main() { ); }); - testWidgets('InvertColors and ColorFilter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InvertColors and ColorFilter', (WidgetTester tester) async { await tester.pumpWidget(const RepaintBoundary( child: SizedBox( width: 200.0, diff --git a/packages/flutter/test/widgets/keep_alive_test.dart b/packages/flutter/test/widgets/keep_alive_test.dart index b25a14d45d677..6bd324f990466 100644 --- a/packages/flutter/test/widgets/keep_alive_test.dart +++ b/packages/flutter/test/widgets/keep_alive_test.dart @@ -7,6 +7,7 @@ import 'dart:io' show Platform; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Leaf extends StatefulWidget { const Leaf({ @@ -46,7 +47,7 @@ List<Widget> generateList(Widget child) { } void main() { - testWidgets('KeepAlive with ListView with itemExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('KeepAlive with ListView with itemExtent', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -94,7 +95,7 @@ void main() { expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing); }); - testWidgets('KeepAlive with ListView without itemExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('KeepAlive with ListView without itemExtent', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -141,7 +142,7 @@ void main() { expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing); }); - testWidgets('KeepAlive with GridView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('KeepAlive with GridView', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -190,7 +191,7 @@ void main() { expect(find.byKey(const GlobalObjectKey<_LeafState>(90), skipOffstage: false), findsNothing); }); - testWidgets('KeepAlive render tree description', (WidgetTester tester) async { + testWidgetsWithLeakTracking('KeepAlive render tree description', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/key_test.dart b/packages/flutter/test/widgets/key_test.dart index b6031887325b8..8ba6247659e0a 100644 --- a/packages/flutter/test/widgets/key_test.dart +++ b/packages/flutter/test/widgets/key_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestValueKey<T> extends ValueKey<T> { const TestValueKey(super.value); @@ -19,7 +20,7 @@ class NotEquals { } void main() { - testWidgets('Keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Keys', (WidgetTester tester) async { expect(ValueKey<int>(nonconst(3)) == ValueKey<int>(nonconst(3)), isTrue); expect(ValueKey<num>(nonconst(3)) == ValueKey<int>(nonconst(3)), isFalse); expect(ValueKey<int>(nonconst(3)) == ValueKey<int>(nonconst(2)), isFalse); diff --git a/packages/flutter/test/widgets/keyboard_listener_test.dart b/packages/flutter/test/widgets/keyboard_listener_test.dart index 985e5dd3f91be..1149bddd68444 100644 --- a/packages/flutter/test/widgets/keyboard_listener_test.dart +++ b/packages/flutter/test/widgets/keyboard_listener_test.dart @@ -5,19 +5,22 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can dispose without keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can dispose without keyboard', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget(KeyboardListener(focusNode: focusNode, child: Container())); await tester.pumpWidget(KeyboardListener(focusNode: focusNode, child: Container())); await tester.pumpWidget(Container()); }); - testWidgets('Fuchsia key event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fuchsia key event', (WidgetTester tester) async { final List<KeyEvent> events = <KeyEvent>[]; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( KeyboardListener( @@ -39,13 +42,13 @@ void main() { expect(events[0].logicalKey, LogicalKeyboardKey.metaLeft); await tester.pumpWidget(Container()); - focusNode.dispose(); }, skip: isBrowser); // [intended] This is a Fuchsia-specific test. - testWidgets('Web key event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Web key event', (WidgetTester tester) async { final List<KeyEvent> events = <KeyEvent>[]; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( KeyboardListener( @@ -67,13 +70,13 @@ void main() { expect(events[0].logicalKey, LogicalKeyboardKey.metaLeft); await tester.pumpWidget(Container()); - focusNode.dispose(); }); - testWidgets('Defunct listeners do not receive events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Defunct listeners do not receive events', (WidgetTester tester) async { final List<KeyEvent> events = <KeyEvent>[]; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( KeyboardListener( @@ -101,6 +104,5 @@ void main() { expect(events.length, 0); await tester.pumpWidget(Container()); - focusNode.dispose(); }); } diff --git a/packages/flutter/test/widgets/layout_builder_and_global_keys_test.dart b/packages/flutter/test/widgets/layout_builder_and_global_keys_test.dart index 68e6f4ee27dd8..d3c9178eaa3b9 100644 --- a/packages/flutter/test/widgets/layout_builder_and_global_keys_test.dart +++ b/packages/flutter/test/widgets/layout_builder_and_global_keys_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/src/rendering/sliver.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Wrapper extends StatelessWidget { const Wrapper({ @@ -41,7 +42,7 @@ class StatefulWrapperState extends State<StatefulWrapper> { } void main() { - testWidgets('Moving global key inside a LayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving global key inside a LayoutBuilder', (WidgetTester tester) async { final GlobalKey<StatefulWrapperState> key = GlobalKey<StatefulWrapperState>(); await tester.pumpWidget( LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { @@ -60,7 +61,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Moving global key inside a SliverLayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving global key inside a SliverLayoutBuilder', (WidgetTester tester) async { final GlobalKey<StatefulWrapperState> key = GlobalKey<StatefulWrapperState>(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/layout_builder_and_parent_data_test.dart b/packages/flutter/test/widgets/layout_builder_and_parent_data_test.dart index 6388fa320e509..b98714269530a 100644 --- a/packages/flutter/test/widgets/layout_builder_and_parent_data_test.dart +++ b/packages/flutter/test/widgets/layout_builder_and_parent_data_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class SizeChanger extends StatefulWidget { const SizeChanger({ @@ -42,7 +43,7 @@ class SizeChangerState extends State<SizeChanger> { } void main() { - testWidgets('Applying parent data inside a LayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Applying parent data inside a LayoutBuilder', (WidgetTester tester) async { int frame = 1; await tester.pumpWidget(SizeChanger( // when this is triggered, the child LayoutBuilder will build again child: LayoutBuilder(builder: (BuildContext context, BoxConstraints constraints) { diff --git a/packages/flutter/test/widgets/layout_builder_and_state_test.dart b/packages/flutter/test/widgets/layout_builder_and_state_test.dart index f5687492e7144..3db4baef0b78d 100644 --- a/packages/flutter/test/widgets/layout_builder_and_state_test.dart +++ b/packages/flutter/test/widgets/layout_builder_and_state_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; @@ -49,7 +50,7 @@ class Wrapper extends StatelessWidget { } void main() { - testWidgets('Calling setState on a widget that moves into a LayoutBuilder in the same frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Calling setState on a widget that moves into a LayoutBuilder in the same frame', (WidgetTester tester) async { StatefulWrapperState statefulWrapper; final Widget inner = Wrapper( child: StatefulWrapper( diff --git a/packages/flutter/test/widgets/layout_builder_mutations_test.dart b/packages/flutter/test/widgets/layout_builder_mutations_test.dart index 14f151bfe01a1..d5e4748d0280b 100644 --- a/packages/flutter/test/widgets/layout_builder_mutations_test.dart +++ b/packages/flutter/test/widgets/layout_builder_mutations_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/src/widgets/media_query.dart'; import 'package:flutter/src/widgets/scroll_view.dart'; import 'package:flutter/src/widgets/sliver_layout_builder.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Wrapper extends StatelessWidget { const Wrapper({ @@ -25,7 +26,7 @@ class Wrapper extends StatelessWidget { } void main() { - testWidgets('Moving a global key from another LayoutBuilder at layout time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a global key from another LayoutBuilder at layout time', (WidgetTester tester) async { final GlobalKey victimKey = GlobalKey(); await tester.pumpWidget(Row( @@ -71,7 +72,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Moving a global key from another SliverLayoutBuilder at layout time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a global key from another SliverLayoutBuilder at layout time', (WidgetTester tester) async { final GlobalKey victimKey1 = GlobalKey(); final GlobalKey victimKey2 = GlobalKey(); @@ -128,7 +129,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('LayoutBuilder does not layout twice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder does not layout twice', (WidgetTester tester) async { // This widget marks itself dirty when the closest MediaQuery changes. final _LayoutCount widget = _LayoutCount(); late StateSetter setState; diff --git a/packages/flutter/test/widgets/layout_builder_test.dart b/packages/flutter/test/widgets/layout_builder_test.dart index 6a298b4a88b75..18542fcd1a5de 100644 --- a/packages/flutter/test/widgets/layout_builder_test.dart +++ b/packages/flutter/test/widgets/layout_builder_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('LayoutBuilder parent size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder parent size', (WidgetTester tester) async { late Size layoutBuilderSize; final Key childKey = UniqueKey(); final Key parentKey = UniqueKey(); @@ -38,7 +39,7 @@ void main() { expect(childBox.size, equals(const Size(50.0, 100.0))); }); - testWidgets('SliverLayoutBuilder parent geometry', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverLayoutBuilder parent geometry', (WidgetTester tester) async { late SliverConstraints parentConstraints1; late SliverConstraints parentConstraints2; final Key childKey1 = UniqueKey(); @@ -88,7 +89,7 @@ void main() { expect(childSliver2.geometry, parentSliver2.geometry); }); - testWidgets('LayoutBuilder stateful child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder stateful child', (WidgetTester tester) async { late Size layoutBuilderSize; late StateSetter setState; final Key childKey = UniqueKey(); @@ -134,7 +135,7 @@ void main() { expect(childBox.size, equals(const Size(100.0, 200.0))); }); - testWidgets('SliverLayoutBuilder stateful descendants', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverLayoutBuilder stateful descendants', (WidgetTester tester) async { late StateSetter setState; double childWidth = 10.0; double childHeight = 20.0; @@ -203,7 +204,7 @@ void main() { expect(parentSliver.geometry!.paintExtent, 600); }); - testWidgets('LayoutBuilder stateful parent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder stateful parent', (WidgetTester tester) async { late Size layoutBuilderSize; late StateSetter setState; final Key childKey = UniqueKey(); @@ -247,7 +248,7 @@ void main() { expect(box.size, equals(const Size(100.0, 200.0))); }); - testWidgets('LayoutBuilder and Inherited -- do not rebuild when not using inherited', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder and Inherited -- do not rebuild when not using inherited', (WidgetTester tester) async { int built = 0; final Widget target = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -270,7 +271,7 @@ void main() { expect(built, 1); }); - testWidgets('LayoutBuilder and Inherited -- do rebuild when using inherited', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder and Inherited -- do rebuild when using inherited', (WidgetTester tester) async { int built = 0; final Widget target = LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -294,7 +295,7 @@ void main() { expect(built, 2); }); - testWidgets('SliverLayoutBuilder and Inherited -- do not rebuild when not using inherited', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverLayoutBuilder and Inherited -- do not rebuild when not using inherited', (WidgetTester tester) async { int built = 0; final Widget target = Directionality( textDirection: TextDirection.ltr, @@ -325,7 +326,7 @@ void main() { expect(built, 1); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverLayoutBuilder and Inherited -- do rebuild when not using inherited', (WidgetTester tester) async { int built = 0; @@ -360,7 +361,7 @@ void main() { }, ); - testWidgets('nested SliverLayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('nested SliverLayoutBuilder', (WidgetTester tester) async { late SliverConstraints parentConstraints1; late SliverConstraints parentConstraints2; final Key childKey = UniqueKey(); @@ -405,10 +406,11 @@ void main() { expect(parentSliver1.geometry, parentSliver2.geometry); }); - testWidgets('localToGlobal works with SliverLayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('localToGlobal works with SliverLayoutBuilder', (WidgetTester tester) async { final Key childKey1 = UniqueKey(); final Key childKey2 = UniqueKey(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( @@ -461,8 +463,9 @@ void main() { ); }); - testWidgets('hitTest works within SliverLayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hitTest works within SliverLayoutBuilder', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); List<int> hitCounts = <int> [0, 0, 0]; await tester.pumpWidget( @@ -589,7 +592,7 @@ void main() { expect(hitCounts, const <int> [0, 0, 0]); }); - testWidgets('LayoutBuilder does not call builder when layout happens but layout constraints do not change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder does not call builder when layout happens but layout constraints do not change', (WidgetTester tester) async { int builderInvocationCount = 0; Future<void> pumpTestWidget(Size size) async { @@ -665,7 +668,7 @@ void main() { expect(spy.performResizeCount, 2); }); - testWidgets('LayoutBuilder descendant widget can access [RenderBox.size] when rebuilding during layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayoutBuilder descendant widget can access [RenderBox.size] when rebuilding during layout', (WidgetTester tester) async { Size? childSize; int buildCount = 0; diff --git a/packages/flutter/test/widgets/linked_scroll_view_test.dart b/packages/flutter/test/widgets/linked_scroll_view_test.dart index ee2a5c5921c11..ee1373ec545ac 100644 --- a/packages/flutter/test/widgets/linked_scroll_view_test.dart +++ b/packages/flutter/test/widgets/linked_scroll_view_test.dart @@ -14,6 +14,7 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class LinkedScrollController extends ScrollController { LinkedScrollController({ this.before, this.after }); @@ -381,7 +382,7 @@ class _TestState extends State<Test> { } void main() { - testWidgets('LinkedScrollController - 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinkedScrollController - 1', (WidgetTester tester) async { await tester.pumpWidget(const Test()); expect(find.text('Hello A'), findsOneWidget); expect(find.text('Hello 1'), findsOneWidget); @@ -459,7 +460,7 @@ void main() { expect(find.text('Hello D'), findsNothing); expect(find.text('Hello 4'), findsOneWidget); }); - testWidgets('LinkedScrollController - 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LinkedScrollController - 2', (WidgetTester tester) async { await tester.pumpWidget(const Test()); expect(find.text('Hello A'), findsOneWidget); expect(find.text('Hello B'), findsOneWidget); diff --git a/packages/flutter/test/widgets/list_body_test.dart b/packages/flutter/test/widgets/list_body_test.dart index 6ac39df8d32d5..0bf2b609b8243 100644 --- a/packages/flutter/test/widgets/list_body_test.dart +++ b/packages/flutter/test/widgets/list_body_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/src/foundation/assertions.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const List<Widget> children = <Widget>[ SizedBox(width: 200.0, height: 150.0), @@ -29,7 +30,7 @@ void expectRects(WidgetTester tester, List<Rect> expected) { void main() { - testWidgets('ListBody down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListBody down', (WidgetTester tester) async { await tester.pumpWidget(const Flex( direction: Axis.vertical, children: <Widget>[ ListBody(children: children) ], @@ -46,7 +47,7 @@ void main() { ); }); - testWidgets('ListBody up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListBody up', (WidgetTester tester) async { await tester.pumpWidget(const Flex( direction: Axis.vertical, children: <Widget>[ ListBody(reverse: true, children: children) ], @@ -63,7 +64,7 @@ void main() { ); }); - testWidgets('ListBody right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListBody right', (WidgetTester tester) async { await tester.pumpWidget(const Flex( textDirection: TextDirection.ltr, direction: Axis.horizontal, @@ -86,7 +87,7 @@ void main() { ); }); - testWidgets('ListBody left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListBody left', (WidgetTester tester) async { await tester.pumpWidget(const Flex( textDirection: TextDirection.ltr, direction: Axis.horizontal, @@ -109,7 +110,7 @@ void main() { ); }); - testWidgets('Limited space along main axis error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Limited space along main axis error', (WidgetTester tester) async { final FlutterExceptionHandler oldHandler = FlutterError.onError!; final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); @@ -142,7 +143,7 @@ void main() { )); }); - testWidgets('Nested ListBody unbounded cross axis error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested ListBody unbounded cross axis error', (WidgetTester tester) async { final FlutterExceptionHandler oldHandler = FlutterError.onError!; final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); diff --git a/packages/flutter/test/widgets/list_view_builder_test.dart b/packages/flutter/test/widgets/list_view_builder_test.dart index 52b095735e0f5..ccc83e248383a 100644 --- a/packages/flutter/test/widgets/list_view_builder_test.dart +++ b/packages/flutter/test/widgets/list_view_builder_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; void main() { - testWidgets('ListView.builder mount/dismount smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder mount/dismount smoke test', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // the root view is 800x600 in the test environment @@ -61,7 +62,7 @@ void main() { check(visible: <int>[0, 1, 2, 3, 4, 5], hidden: <int>[ 6, 7, 8]); }); - testWidgets('ListView.builder vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder vertical', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // the root view is 800x600 in the test environment @@ -79,11 +80,14 @@ void main() { } Widget buildWidget() { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); + return Directionality( textDirection: TextDirection.ltr, child: FlipWidget( left: ListView.builder( - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, itemExtent: 200.0, itemBuilder: itemBuilder, ), @@ -134,7 +138,7 @@ void main() { callbackTracker.clear(); }); - testWidgets('ListView.builder horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder horizontal', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // the root view is 800x600 in the test environment @@ -152,11 +156,14 @@ void main() { } Widget buildWidget() { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); + return Directionality( textDirection: TextDirection.ltr, child: FlipWidget( left: ListView.builder( - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, itemBuilder: itemBuilder, itemExtent: 200.0, scrollDirection: Axis.horizontal, @@ -208,7 +215,7 @@ void main() { callbackTracker.clear(); }); - testWidgets('ListView.builder 10 items, 2-3 items visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder 10 items, 2-3 items visible', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // The root view is 800x600 in the test environment and our list @@ -261,7 +268,7 @@ void main() { callbackTracker.clear(); }); - testWidgets('ListView.builder 30 items with big jump, using prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder 30 items with big jump, using prototypeItem', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // The root view is 800x600 in the test environment and our list @@ -309,7 +316,7 @@ void main() { callbackTracker.clear(); }); - testWidgets('ListView.separated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated', (WidgetTester tester) async { Widget buildFrame({ required int itemCount }) { return Directionality( textDirection: TextDirection.ltr, @@ -355,7 +362,7 @@ void main() { }); - testWidgets('ListView.separated uses correct semanticChildCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated uses correct semanticChildCount', (WidgetTester tester) async { Widget buildFrame({ required int itemCount}) { return Directionality( textDirection: TextDirection.ltr, @@ -403,7 +410,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/72292 - testWidgets('ListView.builder and SingleChildScrollView can work well together', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder and SingleChildScrollView can work well together', (WidgetTester tester) async { Widget builder(int itemCount) { return Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/list_view_correction_test.dart b/packages/flutter/test/widgets/list_view_correction_test.dart index 804e74e113944..c6d44618e9ea0 100644 --- a/packages/flutter/test/widgets/list_view_correction_test.dart +++ b/packages/flutter/test/widgets/list_view_correction_test.dart @@ -4,10 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('ListView can handle shrinking top elements', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView can handle shrinking top elements', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -65,8 +68,10 @@ void main() { expect(tester.getTopLeft(find.text('2')).dy, equals(200.0)); }); - testWidgets('ListView can handle shrinking top elements with cache extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView can handle shrinking top elements with cache extent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -122,8 +127,10 @@ void main() { expect(tester.getTopLeft(find.text('2')).dy, equals(150.0)); }); - testWidgets('ListView can handle inserts at 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView can handle inserts at 0', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/list_view_fling_test.dart b/packages/flutter/test/widgets/list_view_fling_test.dart index ebf7019b4b48b..aa76b397aeebd 100644 --- a/packages/flutter/test/widgets/list_view_fling_test.dart +++ b/packages/flutter/test/widgets/list_view_fling_test.dart @@ -4,12 +4,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const double kHeight = 10.0; const double kFlingOffset = kHeight * 20.0; void main() { - testWidgets("Flings don't stutter", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Flings don't stutter", (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/list_view_horizontal_test.dart b/packages/flutter/test/widgets/list_view_horizontal_test.dart index 26b0533da0ac1..7e3999b4507b8 100644 --- a/packages/flutter/test/widgets/list_view_horizontal_test.dart +++ b/packages/flutter/test/widgets/list_view_horizontal_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const List<int> items = <int>[0, 1, 2, 3, 4, 5]; @@ -28,7 +29,7 @@ Widget buildFrame({ bool reverse = false, required TextDirection textDirection } } void main() { - testWidgets('Drag horizontally with scroll anchor at start (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag horizontally with scroll anchor at start (LTR)', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr)); await tester.pump(const Duration(seconds: 1)); @@ -147,7 +148,7 @@ void main() { expect(find.text('5'), findsNothing); }); - testWidgets('Drag horizontally with scroll anchor at end (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag horizontally with scroll anchor at end (LTR)', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.ltr)); await tester.pump(const Duration(seconds: 1)); @@ -247,7 +248,7 @@ void main() { expect(find.text('5'), findsOneWidget); }); - testWidgets('Drag horizontally with scroll anchor at start (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag horizontally with scroll anchor at start (RTL)', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(textDirection: TextDirection.rtl)); await tester.pump(const Duration(seconds: 1)); @@ -347,7 +348,7 @@ void main() { expect(find.text('5'), findsOneWidget); }); - testWidgets('Drag horizontally with scroll anchor at end (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag horizontally with scroll anchor at end (LTR)', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl)); await tester.pump(const Duration(seconds: 1)); diff --git a/packages/flutter/test/widgets/list_view_misc_test.dart b/packages/flutter/test/widgets/list_view_misc_test.dart index 42c216c8966f2..c58b7a2316943 100644 --- a/packages/flutter/test/widgets/list_view_misc_test.dart +++ b/packages/flutter/test/widgets/list_view_misc_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Key blockKey = Key('test'); void main() { - testWidgets('Cannot scroll a non-overflowing block', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot scroll a non-overflowing block', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -36,7 +37,7 @@ void main() { await gesture.up(); }); - testWidgets('Can scroll an overflowing block', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can scroll an overflowing block', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -67,7 +68,7 @@ void main() { await gesture.up(); }); - testWidgets('ListView reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView reverse', (WidgetTester tester) async { int first = 0; int second = 0; @@ -111,8 +112,9 @@ void main() { expect(second, equals(1)); }); - testWidgets('ListView controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView controller', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); Widget buildBlock() { return Directionality( @@ -127,7 +129,7 @@ void main() { expect(controller.offset, equals(0.0)); }); - testWidgets('SliverBlockChildListDelegate.estimateMaxScrollOffset hits end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverBlockChildListDelegate.estimateMaxScrollOffset hits end', (WidgetTester tester) async { final SliverChildListDelegate delegate = SliverChildListDelegate(<Widget>[ Container(), Container(), @@ -161,7 +163,7 @@ void main() { expect(maxScrollOffset, equals(26.0)); }); - testWidgets('Resizing a ListView child restores scroll offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Resizing a ListView child restores scroll offset', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/9221 final AnimationController controller = AnimationController( vsync: const TestVSync(), diff --git a/packages/flutter/test/widgets/list_view_relayout_test.dart b/packages/flutter/test/widgets/list_view_relayout_test.dart index 7d0ff9bb14c9c..f0d0e53ed03c8 100644 --- a/packages/flutter/test/widgets/list_view_relayout_test.dart +++ b/packages/flutter/test/widgets/list_view_relayout_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Nested ListView with shrinkWrap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested ListView with shrinkWrap', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -36,7 +37,7 @@ void main() { ); }); - testWidgets('Underflowing ListView should relayout for additional children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Underflowing ListView should relayout for additional children', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/5950 await tester.pumpWidget( @@ -65,7 +66,7 @@ void main() { expect(find.text('200'), findsOneWidget); }); - testWidgets('Underflowing ListView contentExtent should track additional children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Underflowing ListView contentExtent should track additional children', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -102,7 +103,7 @@ void main() { expect(list.geometry!.scrollExtent, equals(0.0)); }); - testWidgets('Overflowing ListView should relayout for missing children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflowing ListView should relayout for missing children', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -143,7 +144,7 @@ void main() { expect(find.text('400'), findsNothing); }); - testWidgets('Overflowing ListView should not relayout for additional children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflowing ListView should not relayout for additional children', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -177,7 +178,7 @@ void main() { expect(find.text('100'), findsNothing); }); - testWidgets('Overflowing ListView should become scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflowing ListView should become scrollable', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/5920 // When a ListView's viewport hasn't overflowed, scrolling is disabled. // When children are added that cause it to overflow, scrolling should diff --git a/packages/flutter/test/widgets/list_view_semantics_test.dart b/packages/flutter/test/widgets/list_view_semantics_test.dart index c801973a1c072..3fdf022de9552 100644 --- a/packages/flutter/test/widgets/list_view_semantics_test.dart +++ b/packages/flutter/test/widgets/list_view_semantics_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -14,9 +15,10 @@ void main() { const int itemCount = 10; const double itemHeight = 150.0; - testWidgets('forward vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forward vertical', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -44,9 +46,10 @@ void main() { semantics.dispose(); }); - testWidgets('reverse vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reverse vertical', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -75,9 +78,10 @@ void main() { semantics.dispose(); }); - testWidgets('forward horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forward horizontal', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -106,9 +110,10 @@ void main() { semantics.dispose(); }); - testWidgets('reverse horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reverse horizontal', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/list_view_test.dart b/packages/flutter/test/widgets/list_view_test.dart index bfb39cfcce424..a9ef0063f05ab 100644 --- a/packages/flutter/test/widgets/list_view_test.dart +++ b/packages/flutter/test/widgets/list_view_test.dart @@ -6,6 +6,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; @@ -77,7 +78,7 @@ class _StatefulListViewState extends State<_StatefulListView> { void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('ListView.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -113,7 +114,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('ListView.separator respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separator respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -149,7 +150,7 @@ void main() { expect(finderCalled, true); }); - testWidgets('ListView default control', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView default control', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -160,7 +161,7 @@ void main() { ); }); - testWidgets('ListView itemExtent control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView itemExtent control test', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -207,7 +208,7 @@ void main() { expect(find.text('5'), findsNothing); }); - testWidgets('ListView large scroll jump', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView large scroll jump', (WidgetTester tester) async { final List<int> log = <int>[]; await tester.pumpWidget( @@ -249,7 +250,7 @@ void main() { log.clear(); }); - testWidgets('ListView large scroll jump and keepAlive first child not keepAlive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView large scroll jump and keepAlive first child not keepAlive', (WidgetTester tester) async { Future<void> checkAndScroll([ String zero = '0:false' ]) async { expect(find.text(zero), findsOneWidget); expect(find.text('1:false'), findsOneWidget); @@ -286,7 +287,7 @@ void main() { await checkAndScroll('0:true'); }); - testWidgets('ListView can build out of underflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView can build out of underflow', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -342,7 +343,7 @@ void main() { expect(find.text('5'), findsNothing); }); - testWidgets('ListView can build out of overflow padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView can build out of overflow padding', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -361,7 +362,7 @@ void main() { expect(find.text('padded', skipOffstage: false), findsOneWidget); }); - testWidgets('ListView with itemExtent in unbounded context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView with itemExtent in unbounded context', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -381,7 +382,7 @@ void main() { expect(find.text('19'), findsOneWidget); }); - testWidgets('ListView with shrink wrap in bounded context correctly uses cache extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView with shrink wrap in bounded context correctly uses cache extent', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Directionality( @@ -405,7 +406,7 @@ void main() { handle.dispose(); }); - testWidgets('ListView hidden items should stay hidden if their semantics are updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView hidden items should stay hidden if their semantics are updated', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Directionality( @@ -440,7 +441,7 @@ void main() { handle.dispose(); }); - testWidgets('didFinishLayout has correct indices', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didFinishLayout has correct indices', (WidgetTester tester) async { final TestSliverChildListDelegate delegate = TestSliverChildListDelegate( List<Widget>.generate( 20, @@ -486,7 +487,7 @@ void main() { delegate.log.clear(); }); - testWidgets('ListView automatically pad MediaQuery on axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView automatically pad MediaQuery on axis', (WidgetTester tester) async { EdgeInsets? innerMediaQueryPadding; await tester.pumpWidget( @@ -514,7 +515,7 @@ void main() { expect(innerMediaQueryPadding, const EdgeInsets.symmetric(horizontal: 30.0)); }); - testWidgets('ListView clips if overflow is smaller than cacheExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView clips if overflow is smaller than cacheExtent', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17426. await tester.pumpWidget( @@ -545,7 +546,7 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); }); - testWidgets('ListView does not clips if no overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView does not clips if no overflow', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -568,7 +569,7 @@ void main() { expect(find.byType(Viewport), isNot(paints..clipRect())); }); - testWidgets('ListView (fixed extent) clips if overflow is smaller than cacheExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView (fixed extent) clips if overflow is smaller than cacheExtent', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17426. await tester.pumpWidget( @@ -600,7 +601,7 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); }); - testWidgets('ListView (fixed extent) does not clips if no overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView (fixed extent) does not clips if no overflow', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -624,7 +625,7 @@ void main() { expect(find.byType(Viewport), isNot(paints..clipRect())); }); - testWidgets('ListView.horizontal has implicit scrolling by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.horizontal has implicit scrolling by default', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( Directionality( @@ -657,9 +658,10 @@ void main() { handle.dispose(); }); - testWidgets('Updates viewport dimensions when scroll direction changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updates viewport dimensions when scroll direction changes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/43380. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); Widget buildListView({ required Axis scrollDirection }) { return Directionality( @@ -694,7 +696,7 @@ void main() { expect(controller.position.viewportDimension, 100.0); }); - testWidgets('ListView respects clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -728,9 +730,14 @@ void main() { // 4th, check that a non-default clip behavior can be sent to the painting context. renderObject.paint(context, Offset.zero); expect(context.clipBehavior, equals(Clip.antiAlias)); - }); - - testWidgets('ListView.builder respects clipBehavior', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134572 + notDisposedAllowList: <String, int?> {'ContainerLayer': 1}, + )); + + testWidgetsWithLeakTracking('ListView.builder respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -745,7 +752,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('ListView.custom respects clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.custom respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -762,7 +769,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('ListView.separated respects clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -779,8 +786,9 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/pull/131393 - testWidgets('itemExtentBuilder test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('itemExtentBuilder test', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<int> buildLog = <int>[]; late SliverLayoutDimensions sliverLayoutDimensions; await tester.pumpWidget( @@ -909,7 +917,7 @@ void main() { expect(buildLog.max, 61); }); - testWidgets('itemExtent, prototypeItem and itemExtentBuilder conflicts test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('itemExtent, prototypeItem and itemExtentBuilder conflicts test', (WidgetTester tester) async { Object? error; try { await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/list_view_vertical_test.dart b/packages/flutter/test/widgets/list_view_vertical_test.dart index 73b0910b0a757..16a103732d0ae 100644 --- a/packages/flutter/test/widgets/list_view_vertical_test.dart +++ b/packages/flutter/test/widgets/list_view_vertical_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const List<int> items = <int>[0, 1, 2, 3, 4, 5]; @@ -20,7 +21,7 @@ Widget buildFrame() { } void main() { - testWidgets('Drag vertically', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag vertically', (WidgetTester tester) async { await tester.pumpWidget(buildFrame()); await tester.pump(); @@ -63,7 +64,7 @@ void main() { expect(find.text('5'), findsNothing); }); - testWidgets('Drag vertically', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag vertically', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/list_view_viewporting_test.dart b/packages/flutter/test/widgets/list_view_viewporting_test.dart index 0648cf99d57d0..51764016a3ba4 100644 --- a/packages/flutter/test/widgets/list_view_viewporting_test.dart +++ b/packages/flutter/test/widgets/list_view_viewporting_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; void main() { - testWidgets('ListView mount/dismount smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView mount/dismount smoke test', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // the root view is 800x600 in the test environment @@ -59,7 +60,7 @@ void main() { ])); }); - testWidgets('ListView vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView vertical', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // the root view is 800x600 in the test environment @@ -77,11 +78,14 @@ void main() { } Widget builder() { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); + return Directionality( textDirection: TextDirection.ltr, child: FlipWidget( left: ListView.builder( - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, itemBuilder: itemBuilder, ), right: const Text('Not Today'), @@ -122,7 +126,7 @@ void main() { callbackTracker.clear(); }); - testWidgets('ListView horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView horizontal', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; // the root view is 800x600 in the test environment @@ -140,12 +144,15 @@ void main() { } Widget builder() { + final ScrollController controller = ScrollController(initialScrollOffset: 500.0); + addTearDown(controller.dispose); + return Directionality( textDirection: TextDirection.ltr, child: FlipWidget( left: ListView.builder( scrollDirection: Axis.horizontal, - controller: ScrollController(initialScrollOffset: 500.0), + controller: controller, itemBuilder: itemBuilder, ), right: const Text('Not Today'), @@ -176,7 +183,7 @@ void main() { callbackTracker.clear(); }); - testWidgets('ListView reinvoke builders', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView reinvoke builders', (WidgetTester tester) async { final List<int> callbackTracker = <int>[]; final List<String?> text = <String?>[]; @@ -228,7 +235,7 @@ void main() { text.clear(); }); - testWidgets('ListView reinvoke builders', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView reinvoke builders', (WidgetTester tester) async { late StateSetter setState; ThemeData themeData = ThemeData.light(useMaterial3: false); @@ -271,7 +278,7 @@ void main() { expect(widget.color, equals(Colors.green)); }); - testWidgets('ListView padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView padding', (WidgetTester tester) async { Widget itemBuilder(BuildContext context, int index) { return Container( key: ValueKey<int>(index), @@ -298,7 +305,7 @@ void main() { expect(firstBox.size.width, equals(800.0 - 12.0)); }); - testWidgets('ListView underflow extents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView underflow extents', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -433,8 +440,11 @@ void main() { expect(position.minScrollExtent, equals(0.0)); }); - testWidgets('ListView should not paint hidden children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView should not paint hidden children', (WidgetTester tester) async { const Text text = Text('test'); + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -443,7 +453,7 @@ void main() { height: 200.0, child: ListView( cacheExtent: 500.0, - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, children: const <Widget>[ SizedBox(height: 140.0, child: text), SizedBox(height: 160.0, child: text), @@ -462,14 +472,17 @@ void main() { expect(list, paintsExactlyCountTimes(#drawParagraph, 2)); }); - testWidgets('ListView should paint with offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView should paint with offset', (WidgetTester tester) async { + final ScrollController controller = ScrollController(initialScrollOffset: 120.0); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Scaffold( body: SizedBox( height: 500.0, child: CustomScrollView( - controller: ScrollController(initialScrollOffset: 120.0), + controller: controller, slivers: <Widget>[ const SliverAppBar( expandedHeight: 250.0, @@ -493,9 +506,14 @@ void main() { final RenderObject renderObject = tester.renderObject(find.byType(Scrollable)); expect(renderObject, paintsExactlyCountTimes(#drawParagraph, 10)); - }); - - testWidgets('ListView should paint with rtl', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134661 + notDisposedAllowList: <String, int?> {'AnnotatedRegionLayer<SystemUiOverlayStyle>': 1}, + )); + + testWidgetsWithLeakTracking('ListView should paint with rtl', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, diff --git a/packages/flutter/test/widgets/list_view_with_inherited_test.dart b/packages/flutter/test/widgets/list_view_with_inherited_test.dart index 1cfdbdaecea89..d47e6f96f9bf4 100644 --- a/packages/flutter/test/widgets/list_view_with_inherited_test.dart +++ b/packages/flutter/test/widgets/list_view_with_inherited_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; List<String> items = <String>[ 'one', @@ -40,7 +41,7 @@ Widget buildFrame() { } void main() { - testWidgets('ListView is a build function (smoketest)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView is a build function (smoketest)', (WidgetTester tester) async { await tester.pumpWidget(buildFrame()); expect(find.text('one'), findsOneWidget); expect(find.text('two'), findsOneWidget); From 61b890bfcbc106bc011007c6ac6fd42ec87c9818 Mon Sep 17 00:00:00 2001 From: Hans Muller <hans.muller@gmail.com> Date: Wed, 13 Sep 2023 10:33:08 -0700 Subject: [PATCH 1250/1547] Updated MaterialStatesController class api doc (#134592) Resolves https://github.com/flutter/flutter/pull/133977#discussion_r1320373180 --- .../flutter/lib/src/material/material_state.dart | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/material_state.dart b/packages/flutter/lib/src/material/material_state.dart index 6fad0799ffad2..59d5dfcb71ee9 100644 --- a/packages/flutter/lib/src/material/material_state.dart +++ b/packages/flutter/lib/src/material/material_state.dart @@ -735,11 +735,21 @@ class MaterialStatePropertyAll<T> implements MaterialStateProperty<T> { /// /// Used by widgets that expose their internal state for the sake of /// extensions that add support for additional states. See -/// [TextButton.statesController] for example. +/// [TextButton] for an example. /// /// The controller's [value] is its current set of states. Listeners /// are notified whenever the [value] changes. The [value] should only be /// changed with [update]; it should not be modified directly. +/// +/// The controller's [value] represents the set of states that a +/// widget's visual properties, typically [MaterialStateProperty] +/// values, are resolved against. It is _not_ the intrinsic state of +/// the widget. The widget is responsible for ensuring that the +/// controller's [value] tracks its intrinsic state. For example one +/// cannot request the keyboard focus for a widget by adding +/// [MaterialState.focused] to its controller. When the widget gains the +/// or loses the focus it will [update] its controller's [value] and +/// notify listeners of the change. class MaterialStatesController extends ValueNotifier<Set<MaterialState>> { /// Creates a MaterialStatesController. MaterialStatesController([Set<MaterialState>? value]) : super(<MaterialState>{...?value}); From 4d5a1d91e136c8ab05c567aa581bea1eacf364db Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:36:24 -0700 Subject: [PATCH 1251/1547] Bump gradle heap size limit in *everywhere* (#134665) I'm seeing these in the bot reports every week. Hopefully this is all of them, and hopefully 4GB is enough. --- dev/a11y_assessments/android/gradle.properties | 2 +- dev/benchmarks/complex_layout/android/gradle.properties | 2 +- dev/benchmarks/macrobenchmarks/android/gradle.properties | 2 +- dev/benchmarks/microbenchmarks/android/gradle.properties | 2 +- dev/benchmarks/multiple_flutters/android/gradle.properties | 4 ++-- .../platform_views_layout/android/gradle.properties | 2 +- .../android/gradle.properties | 2 +- dev/benchmarks/test_apps/stocks/android/gradle.properties | 2 +- .../abstract_method_smoke_test/android/gradle.properties | 2 +- .../android_custom_host_app/gradle.properties | 2 +- .../android_embedding_v2_smoke_test/android/gradle.properties | 2 +- .../android_host_app_v2_embedding/gradle.properties | 2 +- .../android_semantics_testing/android/gradle.properties | 2 +- dev/integration_tests/android_views/android/gradle.properties | 2 +- dev/integration_tests/channels/android/gradle.properties | 2 +- .../deferred_components_test/android/gradle.properties | 2 +- dev/integration_tests/external_ui/android/gradle.properties | 2 +- dev/integration_tests/flavors/android/gradle.properties | 2 +- .../gradle_deprecated_settings/android/gradle.properties | 4 ++-- .../hybrid_android_views/android/gradle.properties | 2 +- .../gradle.properties | 2 +- dev/integration_tests/non_nullable/android/gradle.properties | 2 +- .../platform_interaction/android/gradle.properties | 2 +- .../release_smoke_test/android/gradle.properties | 2 +- dev/integration_tests/spell_check/android/gradle.properties | 2 +- dev/integration_tests/ui/android/gradle.properties | 2 +- dev/manual_tests/android/gradle.properties | 2 +- dev/tracing_tests/android/gradle.properties | 2 +- examples/api/android/gradle.properties | 2 +- examples/hello_world/android/gradle.properties | 2 +- examples/image_list/android/gradle.properties | 2 +- examples/layers/android/gradle.properties | 2 +- examples/platform_channel/android/gradle.properties | 2 +- .../android_plugin_example_app_build_test.dart | 2 +- .../test_data/deferred_components_project.dart | 2 +- .../test/integration.shard/test_data/multidex_project.dart | 2 +- packages/integration_test/android/gradle.properties | 2 +- packages/integration_test/example/android/gradle.properties | 2 +- 38 files changed, 40 insertions(+), 40 deletions(-) diff --git a/dev/a11y_assessments/android/gradle.properties b/dev/a11y_assessments/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/a11y_assessments/android/gradle.properties +++ b/dev/a11y_assessments/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/benchmarks/complex_layout/android/gradle.properties b/dev/benchmarks/complex_layout/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/benchmarks/complex_layout/android/gradle.properties +++ b/dev/benchmarks/complex_layout/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/benchmarks/macrobenchmarks/android/gradle.properties b/dev/benchmarks/macrobenchmarks/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/benchmarks/macrobenchmarks/android/gradle.properties +++ b/dev/benchmarks/macrobenchmarks/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/benchmarks/microbenchmarks/android/gradle.properties b/dev/benchmarks/microbenchmarks/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/benchmarks/microbenchmarks/android/gradle.properties +++ b/dev/benchmarks/microbenchmarks/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/benchmarks/multiple_flutters/android/gradle.properties b/dev/benchmarks/multiple_flutters/android/gradle.properties index 98bed167dc90f..9930279818e98 100644 --- a/dev/benchmarks/multiple_flutters/android/gradle.properties +++ b/dev/benchmarks/multiple_flutters/android/gradle.properties @@ -6,7 +6,7 @@ # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. -org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx4G -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects @@ -18,4 +18,4 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true # Kotlin code style for this project: "official" or "obsolete": -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official diff --git a/dev/benchmarks/platform_views_layout/android/gradle.properties b/dev/benchmarks/platform_views_layout/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/benchmarks/platform_views_layout/android/gradle.properties +++ b/dev/benchmarks/platform_views_layout/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/android/gradle.properties b/dev/benchmarks/platform_views_layout_hybrid_composition/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/android/gradle.properties +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/benchmarks/test_apps/stocks/android/gradle.properties b/dev/benchmarks/test_apps/stocks/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/benchmarks/test_apps/stocks/android/gradle.properties +++ b/dev/benchmarks/test_apps/stocks/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/abstract_method_smoke_test/android/gradle.properties b/dev/integration_tests/abstract_method_smoke_test/android/gradle.properties index 08f2b5f91bff6..f17eebabc3990 100644 --- a/dev/integration_tests/abstract_method_smoke_test/android/gradle.properties +++ b/dev/integration_tests/abstract_method_smoke_test/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.enableJetifier=true android.useAndroidX=true diff --git a/dev/integration_tests/android_custom_host_app/gradle.properties b/dev/integration_tests/android_custom_host_app/gradle.properties index 759a1767410a2..7413f6ce06495 100644 --- a/dev/integration_tests/android_custom_host_app/gradle.properties +++ b/dev/integration_tests/android_custom_host_app/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true flutter.hostAppProjectName=SampleApp diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/android/gradle.properties b/dev/integration_tests/android_embedding_v2_smoke_test/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/android/gradle.properties +++ b/dev/integration_tests/android_embedding_v2_smoke_test/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/android_host_app_v2_embedding/gradle.properties b/dev/integration_tests/android_host_app_v2_embedding/gradle.properties index 47a56de84bd00..598d13fee4463 100644 --- a/dev/integration_tests/android_host_app_v2_embedding/gradle.properties +++ b/dev/integration_tests/android_host_app_v2_embedding/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/android_semantics_testing/android/gradle.properties b/dev/integration_tests/android_semantics_testing/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/android_semantics_testing/android/gradle.properties +++ b/dev/integration_tests/android_semantics_testing/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/android_views/android/gradle.properties b/dev/integration_tests/android_views/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/android_views/android/gradle.properties +++ b/dev/integration_tests/android_views/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/channels/android/gradle.properties b/dev/integration_tests/channels/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/channels/android/gradle.properties +++ b/dev/integration_tests/channels/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/deferred_components_test/android/gradle.properties b/dev/integration_tests/deferred_components_test/android/gradle.properties index 507f4a3fcd52a..e5a6f71ad43f8 100644 --- a/dev/integration_tests/deferred_components_test/android/gradle.properties +++ b/dev/integration_tests/deferred_components_test/android/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true android.enableR8=true diff --git a/dev/integration_tests/external_ui/android/gradle.properties b/dev/integration_tests/external_ui/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/external_ui/android/gradle.properties +++ b/dev/integration_tests/external_ui/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/flavors/android/gradle.properties b/dev/integration_tests/flavors/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/flavors/android/gradle.properties +++ b/dev/integration_tests/flavors/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties b/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties index 4d3226abc21bb..598d13fee4463 100644 --- a/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties +++ b/dev/integration_tests/gradle_deprecated_settings/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true -android.enableJetifier=true \ No newline at end of file +android.enableJetifier=true diff --git a/dev/integration_tests/hybrid_android_views/android/gradle.properties b/dev/integration_tests/hybrid_android_views/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/hybrid_android_views/android/gradle.properties +++ b/dev/integration_tests/hybrid_android_views/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/module_host_with_custom_build_v2_embedding/gradle.properties b/dev/integration_tests/module_host_with_custom_build_v2_embedding/gradle.properties index 47a56de84bd00..598d13fee4463 100644 --- a/dev/integration_tests/module_host_with_custom_build_v2_embedding/gradle.properties +++ b/dev/integration_tests/module_host_with_custom_build_v2_embedding/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536m +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/non_nullable/android/gradle.properties b/dev/integration_tests/non_nullable/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/non_nullable/android/gradle.properties +++ b/dev/integration_tests/non_nullable/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/platform_interaction/android/gradle.properties b/dev/integration_tests/platform_interaction/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/platform_interaction/android/gradle.properties +++ b/dev/integration_tests/platform_interaction/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/release_smoke_test/android/gradle.properties b/dev/integration_tests/release_smoke_test/android/gradle.properties index d1ab454e543a7..4512f01215d27 100644 --- a/dev/integration_tests/release_smoke_test/android/gradle.properties +++ b/dev/integration_tests/release_smoke_test/android/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true android.useAndroidX=true diff --git a/dev/integration_tests/spell_check/android/gradle.properties b/dev/integration_tests/spell_check/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/spell_check/android/gradle.properties +++ b/dev/integration_tests/spell_check/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/integration_tests/ui/android/gradle.properties b/dev/integration_tests/ui/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/integration_tests/ui/android/gradle.properties +++ b/dev/integration_tests/ui/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/manual_tests/android/gradle.properties b/dev/manual_tests/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/manual_tests/android/gradle.properties +++ b/dev/manual_tests/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/dev/tracing_tests/android/gradle.properties b/dev/tracing_tests/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/dev/tracing_tests/android/gradle.properties +++ b/dev/tracing_tests/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/examples/api/android/gradle.properties b/examples/api/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/api/android/gradle.properties +++ b/examples/api/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/examples/hello_world/android/gradle.properties b/examples/hello_world/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/hello_world/android/gradle.properties +++ b/examples/hello_world/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/examples/image_list/android/gradle.properties b/examples/image_list/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/image_list/android/gradle.properties +++ b/examples/image_list/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/examples/layers/android/gradle.properties b/examples/layers/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/layers/android/gradle.properties +++ b/examples/layers/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/examples/platform_channel/android/gradle.properties b/examples/platform_channel/android/gradle.properties index 94adc3a3f97aa..598d13fee4463 100644 --- a/examples/platform_channel/android/gradle.properties +++ b/examples/platform_channel/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true diff --git a/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart b/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart index 9c91e16d2767c..3a4d27477f6b3 100644 --- a/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart +++ b/packages/flutter_tools/test/integration.shard/android_plugin_example_app_build_test.dart @@ -112,7 +112,7 @@ void main() { expect(gradleProperties, exists); gradleProperties.writeAsStringSync(''' -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true android.enableR8=true'''); diff --git a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart index 927cd4e457df4..4a0ec4be1cd30 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/deferred_components_project.dart @@ -232,7 +232,7 @@ class BasicDeferredComponentsConfig extends DeferredComponentsConfig { @override String get androidGradleProperties => ''' - org.gradle.jvmargs=-Xmx1536M + org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true android.enableR8=true diff --git a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart index f5e245b426f0b..80ffcec941603 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/multidex_project.dart @@ -194,7 +194,7 @@ class MultidexProject extends Project { '''; String get androidGradleProperties => ''' - org.gradle.jvmargs=-Xmx1536M + org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true android.enableR8=true diff --git a/packages/integration_test/android/gradle.properties b/packages/integration_test/android/gradle.properties index 8bd86f6805108..95b4763a84734 100644 --- a/packages/integration_test/android/gradle.properties +++ b/packages/integration_test/android/gradle.properties @@ -1 +1 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G diff --git a/packages/integration_test/example/android/gradle.properties b/packages/integration_test/example/android/gradle.properties index 53a43b8d74fff..d513e21975fc1 100644 --- a/packages/integration_test/example/android/gradle.properties +++ b/packages/integration_test/example/android/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G android.useAndroidX=true android.enableJetifier=true From af5ac930d8e6fa3011b279343a01700c63c7daaa Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:08:35 -0500 Subject: [PATCH 1252/1547] Set the CONFIGURATION_BUILD_DIR in generated xcconfig when debugging core device (#134493) Xcode uses the CONFIGURATION_BUILD_DIR build setting to determine the location of the bundle to build and install. When launching an app via Xcode with the Xcode debug workflow (for iOS 17 physical devices), temporarily set the CONFIGURATION_BUILD_DIR to the location of the bundle so Xcode can find it. Also, added a Xcode Debug version of the `microbenchmarks_ios` integration test since it uses `flutter run --profile` without using `--use-application-binary`. Fixes https://github.com/flutter/flutter/issues/134186. --- .ci.yaml | 11 +++ TESTOWNERS | 1 + .../microbenchmarks_ios_xcode_debug.dart | 21 +++++ dev/devicelab/lib/microbenchmarks.dart | 6 ++ dev/devicelab/lib/tasks/microbenchmarks.dart | 7 +- .../flutter_tools/lib/src/ios/devices.dart | 30 ++++++- packages/flutter_tools/lib/src/ios/mac.dart | 2 - .../lib/src/ios/xcode_build_settings.dart | 13 +-- .../ios_device_start_nonprebuilt_test.dart | 82 +++++++++++++++++++ .../general.shard/ios/xcodeproj_test.dart | 41 ++-------- 10 files changed, 170 insertions(+), 44 deletions(-) create mode 100644 dev/devicelab/bin/tasks/microbenchmarks_ios_xcode_debug.dart diff --git a/.ci.yaml b/.ci.yaml index 57c5c163479d0..e01d5b5ccd341 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4069,6 +4069,17 @@ targets: ["devicelab", "ios", "mac"] task_name: microbenchmarks_ios + # TODO(vashworth): Remove after Xcode 15 and iOS 17 are in CI (https://github.com/flutter/flutter/issues/132128) + - name: Mac_ios microbenchmarks_ios_xcode_debug + recipe: devicelab/devicelab_drone + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "ios", "mac"] + task_name: microbenchmarks_ios_xcode_debug + bringup: true + - name: Mac_ios native_assets_ios_simulator recipe: devicelab/devicelab_drone presubmit: false diff --git a/TESTOWNERS b/TESTOWNERS index 635215f523090..bdb7499e3cee8 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -199,6 +199,7 @@ /dev/devicelab/bin/tasks/large_image_changer_perf_ios.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/macos_chrome_dev_mode.dart @zanderso @flutter/tool /dev/devicelab/bin/tasks/microbenchmarks_ios.dart @cyanglaz @flutter/engine +/dev/devicelab/bin/tasks/microbenchmarks_ios_xcode_debug.dart @vashworth @flutter/engine /dev/devicelab/bin/tasks/native_assets_ios_simulator.dart @dacoharkes @flutter/ios /dev/devicelab/bin/tasks/native_assets_ios.dart @dacoharkes @flutter/ios /dev/devicelab/bin/tasks/native_platform_view_ui_tests_ios.dart @hellohuanlin @flutter/ios diff --git a/dev/devicelab/bin/tasks/microbenchmarks_ios_xcode_debug.dart b/dev/devicelab/bin/tasks/microbenchmarks_ios_xcode_debug.dart new file mode 100644 index 0000000000000..3373a683672e8 --- /dev/null +++ b/dev/devicelab/bin/tasks/microbenchmarks_ios_xcode_debug.dart @@ -0,0 +1,21 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_devicelab/framework/devices.dart'; +import 'package:flutter_devicelab/framework/framework.dart'; +import 'package:flutter_devicelab/tasks/microbenchmarks.dart'; + +/// Runs microbenchmarks on iOS. +Future<void> main() async { + // XcodeDebug workflow is used for CoreDevices (iOS 17+ and Xcode 15+). Use + // FORCE_XCODE_DEBUG environment variable to force the use of XcodeDebug + // workflow in CI to test from older versions since devicelab has not yet been + // updated to iOS 17 and Xcode 15. + deviceOperatingSystem = DeviceOperatingSystem.ios; + await task(createMicrobenchmarkTask( + environment: <String, String>{ + 'FORCE_XCODE_DEBUG': 'true', + }, + )); +} diff --git a/dev/devicelab/lib/microbenchmarks.dart b/dev/devicelab/lib/microbenchmarks.dart index 0cf3d8192466e..451be27b1a550 100644 --- a/dev/devicelab/lib/microbenchmarks.dart +++ b/dev/devicelab/lib/microbenchmarks.dart @@ -64,6 +64,12 @@ Future<Map<String, double>> readJsonResults(Process process) { // See https://github.com/flutter/flutter/issues/19208 process.stdin.write('q'); await process.stdin.flush(); + + // Give the process a couple of seconds to exit and run shutdown hooks + // before sending kill signal. + // TODO(fujino): https://github.com/flutter/flutter/issues/134566 + await Future<void>.delayed(const Duration(seconds: 2)); + // Also send a kill signal in case the `q` above didn't work. process.kill(ProcessSignal.sigint); try { diff --git a/dev/devicelab/lib/tasks/microbenchmarks.dart b/dev/devicelab/lib/tasks/microbenchmarks.dart index 967bb58dfe607..6bd01aac1d2e8 100644 --- a/dev/devicelab/lib/tasks/microbenchmarks.dart +++ b/dev/devicelab/lib/tasks/microbenchmarks.dart @@ -15,7 +15,10 @@ import '../microbenchmarks.dart'; /// Creates a device lab task that runs benchmarks in /// `dev/benchmarks/microbenchmarks` reports results to the dashboard. -TaskFunction createMicrobenchmarkTask({bool? enableImpeller}) { +TaskFunction createMicrobenchmarkTask({ + bool? enableImpeller, + Map<String, String> environment = const <String, String>{}, +}) { return () async { final Device device = await devices.workingDevice; await device.unlock(); @@ -41,9 +44,9 @@ TaskFunction createMicrobenchmarkTask({bool? enableImpeller}) { return startFlutter( 'run', options: options, + environment: environment, ); }); - return readJsonResults(flutterProcess); } diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index fa6961e5e4611..e7133b0ad3228 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -34,6 +34,7 @@ import 'ios_deploy.dart'; import 'ios_workflow.dart'; import 'iproxy.dart'; import 'mac.dart'; +import 'xcode_build_settings.dart'; import 'xcode_debug.dart'; import 'xcodeproj.dart'; @@ -500,7 +501,6 @@ class IOSDevice extends Device { targetOverride: mainPath, activeArch: cpuArchitecture, deviceID: id, - isCoreDevice: isCoreDevice || forceXcodeDebugWorkflow, ); if (!buildResult.success) { _logger.printError('Could not build the precompiled application for the device.'); @@ -551,6 +551,7 @@ class IOSDevice extends Device { debuggingOptions: debuggingOptions, package: package, launchArguments: launchArguments, + mainPath: mainPath, discoveryTimeout: discoveryTimeout, shutdownHooks: shutdownHooks ?? globals.shutdownHooks, ) ? 0 : 1; @@ -784,6 +785,7 @@ class IOSDevice extends Device { required DebuggingOptions debuggingOptions, required IOSApp package, required List<String> launchArguments, + required String? mainPath, required ShutdownHooks shutdownHooks, @visibleForTesting Duration? discoveryTimeout, }) async { @@ -822,6 +824,7 @@ class IOSDevice extends Device { }); XcodeDebugProject debugProject; + final FlutterProject flutterProject = FlutterProject.current(); if (package is PrebuiltIOSApp) { debugProject = await _xcodeDebug.createXcodeProjectWithCustomBundle( @@ -830,6 +833,19 @@ class IOSDevice extends Device { verboseLogging: _logger.isVerbose, ); } else if (package is BuildableIOSApp) { + // Before installing/launching/debugging with Xcode, update the build + // settings to use a custom configuration build directory so Xcode + // knows where to find the app bundle to launch. + final Directory bundle = _fileSystem.directory( + package.deviceBundlePath, + ); + await updateGeneratedXcodeProperties( + project: flutterProject, + buildInfo: debuggingOptions.buildInfo, + targetOverride: mainPath, + configurationBuildDir: bundle.parent.absolute.path, + ); + final IosProject project = package.project; final XcodeProjectInfo? projectInfo = await project.projectInfo(); if (projectInfo == null) { @@ -870,6 +886,18 @@ class IOSDevice extends Device { shutdownHooks.addShutdownHook(() => _xcodeDebug.exit(force: true)); } + if (package is BuildableIOSApp) { + // After automating Xcode, reset the Generated settings to not include + // the custom configuration build directory. This is to prevent + // confusion if the project is later ran via Xcode rather than the + // Flutter CLI. + await updateGeneratedXcodeProperties( + project: flutterProject, + buildInfo: debuggingOptions.buildInfo, + targetOverride: mainPath, + ); + } + return debugSuccess; } } diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart index f51d436b971e2..8819b5cfe1dea 100644 --- a/packages/flutter_tools/lib/src/ios/mac.dart +++ b/packages/flutter_tools/lib/src/ios/mac.dart @@ -133,7 +133,6 @@ Future<XcodeBuildResult> buildXcodeProject({ DarwinArch? activeArch, bool codesign = true, String? deviceID, - bool isCoreDevice = false, bool configOnly = false, XcodeBuildAction buildAction = XcodeBuildAction.build, }) async { @@ -242,7 +241,6 @@ Future<XcodeBuildResult> buildXcodeProject({ project: project, targetOverride: targetOverride, buildInfo: buildInfo, - usingCoreDevice: isCoreDevice, ); await processPodsIfNeeded(project.ios, getIosBuildDirectory(), buildInfo.mode); if (configOnly) { diff --git a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart index df53b38695671..8bf662b4b31ce 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_build_settings.dart @@ -35,7 +35,7 @@ Future<void> updateGeneratedXcodeProperties({ String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, - bool usingCoreDevice = false, + String? configurationBuildDir, }) async { final List<String> xcodeBuildSettings = await _xcodeBuildSettingsLines( project: project, @@ -43,7 +43,7 @@ Future<void> updateGeneratedXcodeProperties({ targetOverride: targetOverride, useMacOSConfig: useMacOSConfig, buildDirOverride: buildDirOverride, - usingCoreDevice: usingCoreDevice, + configurationBuildDir: configurationBuildDir, ); _updateGeneratedXcodePropertiesFile( @@ -145,7 +145,7 @@ Future<List<String>> _xcodeBuildSettingsLines({ String? targetOverride, bool useMacOSConfig = false, String? buildDirOverride, - bool usingCoreDevice = false, + String? configurationBuildDir, }) async { final List<String> xcodeBuildSettings = <String>[]; @@ -174,9 +174,10 @@ Future<List<String>> _xcodeBuildSettingsLines({ xcodeBuildSettings.add('FLUTTER_BUILD_NUMBER=$buildNumber'); // CoreDevices in debug and profile mode are launched, but not built, via Xcode. - // Set the BUILD_DIR so Xcode knows where to find the app bundle to launch. - if (usingCoreDevice && !buildInfo.isRelease) { - xcodeBuildSettings.add('BUILD_DIR=${globals.fs.path.absolute(getIosBuildDirectory())}'); + // Set the CONFIGURATION_BUILD_DIR so Xcode knows where to find the app + // bundle to launch. + if (configurationBuildDir != null) { + xcodeBuildSettings.add('CONFIGURATION_BUILD_DIR=$configurationBuildDir'); } final LocalEngineInfo? localEngineInfo = globals.artifacts?.localEngineInfo; diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart index d7f354cd6148a..00d19d1edeab3 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart @@ -519,6 +519,82 @@ void main() { Xcode: () => xcode, }); + testUsingContext('updates Generated.xcconfig before and after launch', () async { + final Completer<void> debugStartedCompleter = Completer<void>(); + final Completer<void> debugEndedCompleter = Completer<void>(); + final IOSDevice iosDevice = setUpIOSDevice( + fileSystem: fileSystem, + processManager: FakeProcessManager.any(), + logger: logger, + artifacts: artifacts, + isCoreDevice: true, + coreDeviceControl: FakeIOSCoreDeviceControl(), + xcodeDebug: FakeXcodeDebug( + expectedProject: XcodeDebugProject( + scheme: 'Runner', + xcodeWorkspace: fileSystem.directory('/ios/Runner.xcworkspace'), + xcodeProject: fileSystem.directory('/ios/Runner.xcodeproj'), + ), + expectedDeviceId: '123', + expectedLaunchArguments: <String>['--enable-dart-profiling'], + debugStartedCompleter: debugStartedCompleter, + debugEndedCompleter: debugEndedCompleter, + ), + ); + + setUpIOSProject(fileSystem); + final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); + final BuildableIOSApp buildableIOSApp = BuildableIOSApp(flutterProject.ios, 'flutter', 'My Super Awesome App.app'); + fileSystem.directory('build/ios/Release-iphoneos/My Super Awesome App.app').createSync(recursive: true); + + final FakeDeviceLogReader deviceLogReader = FakeDeviceLogReader(); + + iosDevice.portForwarder = const NoOpDevicePortForwarder(); + iosDevice.setLogReader(buildableIOSApp, deviceLogReader); + + // Start writing messages to the log reader. + Timer.run(() { + deviceLogReader.addLine('Foo'); + deviceLogReader.addLine('The Dart VM service is listening on http://127.0.0.1:456'); + }); + + final Future<LaunchResult> futureLaunchResult = iosDevice.startApp( + buildableIOSApp, + debuggingOptions: DebuggingOptions.enabled(const BuildInfo( + BuildMode.debug, + null, + buildName: '1.2.3', + buildNumber: '4', + treeShakeIcons: false, + )), + platformArgs: <String, Object>{}, + ); + + await debugStartedCompleter.future; + + // Validate CoreDevice build settings were used + final File config = fileSystem.directory('ios').childFile('Flutter/Generated.xcconfig'); + expect(config.existsSync(), isTrue); + + String contents = config.readAsStringSync(); + expect(contents, contains('CONFIGURATION_BUILD_DIR=/build/ios/iphoneos')); + + debugEndedCompleter.complete(); + + await futureLaunchResult; + + // Validate CoreDevice build settings were removed after launch + contents = config.readAsStringSync(); + expect(contents.contains('CONFIGURATION_BUILD_DIR'), isFalse); + }, overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.any(), + FileSystem: () => fileSystem, + Logger: () => logger, + Platform: () => macPlatform, + XcodeProjectInterpreter: () => fakeXcodeProjectInterpreter, + Xcode: () => xcode, + }); + testUsingContext('fails when Xcode project is not found', () async { final IOSDevice iosDevice = setUpIOSDevice( fileSystem: fileSystem, @@ -750,6 +826,8 @@ class FakeXcodeDebug extends Fake implements XcodeDebug { this.expectedProject, this.expectedDeviceId, this.expectedLaunchArguments, + this.debugStartedCompleter, + this.debugEndedCompleter, }); final bool debugSuccess; @@ -757,6 +835,8 @@ class FakeXcodeDebug extends Fake implements XcodeDebug { final XcodeDebugProject? expectedProject; final String? expectedDeviceId; final List<String>? expectedLaunchArguments; + final Completer<void>? debugStartedCompleter; + final Completer<void>? debugEndedCompleter; @override Future<bool> debugApp({ @@ -764,6 +844,7 @@ class FakeXcodeDebug extends Fake implements XcodeDebug { required String deviceId, required List<String> launchArguments, }) async { + debugStartedCompleter?.complete(); if (expectedProject != null) { expect(project.scheme, expectedProject!.scheme); expect(project.xcodeWorkspace.path, expectedProject!.xcodeWorkspace.path); @@ -776,6 +857,7 @@ class FakeXcodeDebug extends Fake implements XcodeDebug { if (expectedLaunchArguments != null) { expect(expectedLaunchArguments, launchArguments); } + await debugEndedCompleter?.future; return debugSuccess; } } diff --git a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart index 4dacb94625ae9..0d5a24ea3c8e7 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcodeproj_test.dart @@ -1308,66 +1308,41 @@ flutter: }); group('CoreDevice', () { - testUsingContext('sets BUILD_DIR for core devices in debug mode', () async { + testUsingContext('sets CONFIGURATION_BUILD_DIR when configurationBuildDir is set', () async { const BuildInfo buildInfo = BuildInfo.debug; final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - useMacOSConfig: true, - usingCoreDevice: true, + configurationBuildDir: 'path/to/project/build/ios/iphoneos' ); - final File config = fs.file('path/to/project/macos/Flutter/ephemeral/Flutter-Generated.xcconfig'); - expect(config.existsSync(), isTrue); - - final String contents = config.readAsStringSync(); - expect(contents, contains('\nBUILD_DIR=/build/ios\n')); - }, overrides: <Type, Generator>{ - Artifacts: () => localIosArtifacts, - Platform: () => macOS, - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - XcodeProjectInterpreter: () => xcodeProjectInterpreter, - }); - - testUsingContext('does not set BUILD_DIR for core devices in release mode', () async { - const BuildInfo buildInfo = BuildInfo.release; - final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); - await updateGeneratedXcodeProperties( - project: project, - buildInfo: buildInfo, - useMacOSConfig: true, - usingCoreDevice: true, - ); - - final File config = fs.file('path/to/project/macos/Flutter/ephemeral/Flutter-Generated.xcconfig'); + final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); final String contents = config.readAsStringSync(); - expect(contents.contains('\nBUILD_DIR'), isFalse); + expect(contents, contains('CONFIGURATION_BUILD_DIR=path/to/project/build/ios/iphoneos')); }, overrides: <Type, Generator>{ Artifacts: () => localIosArtifacts, - Platform: () => macOS, + // Platform: () => macOS, FileSystem: () => fs, ProcessManager: () => FakeProcessManager.any(), XcodeProjectInterpreter: () => xcodeProjectInterpreter, }); - testUsingContext('does not set BUILD_DIR for non core devices', () async { + testUsingContext('does not set CONFIGURATION_BUILD_DIR when configurationBuildDir is not set', () async { const BuildInfo buildInfo = BuildInfo.debug; final FlutterProject project = FlutterProject.fromDirectoryTest(fs.directory('path/to/project')); await updateGeneratedXcodeProperties( project: project, buildInfo: buildInfo, - useMacOSConfig: true, ); - final File config = fs.file('path/to/project/macos/Flutter/ephemeral/Flutter-Generated.xcconfig'); + final File config = fs.file('path/to/project/ios/Flutter/Generated.xcconfig'); expect(config.existsSync(), isTrue); final String contents = config.readAsStringSync(); - expect(contents.contains('\nBUILD_DIR'), isFalse); + expect(contents.contains('CONFIGURATION_BUILD_DIR'), isFalse); }, overrides: <Type, Generator>{ Artifacts: () => localIosArtifacts, Platform: () => macOS, From 12261f987afbd677eb061f103b6628bedab8a6ec Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 14:34:04 -0400 Subject: [PATCH 1253/1547] Roll Flutter Engine from 5e671d5c90f9 to b71b366e3de3 (4 revisions) (#134676) https://github.com/flutter/engine/compare/5e671d5c90f9...b71b366e3de3 2023-09-13 matanlurey@users.noreply.github.com Do not run real processes in `clang_tidy_test.dart` (flutter/engine#45748) 2023-09-13 30870216+gaaclarke@users.noreply.github.com [Impeller] Adds test to verify wide gamut indexed png decompression fix for Skia. (flutter/engine#45399) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 284c333d7eb2 to 78d18d509475 (2 revisions) (flutter/engine#45769) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 3ff43577d04b to 284c333d7eb2 (1 revision) (flutter/engine#45768) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 03f0fa49f0a59..a3510f822f3d3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5e671d5c90f9088c7cad498dc8ecfbab8d03336a +b71b366e3de3be6720b193086271a3934ead3901 From 2daf91771778467be384424fb62d843ce1305f10 Mon Sep 17 00:00:00 2001 From: Jonah Williams <jonahwilliams@google.com> Date: Wed, 13 Sep 2023 12:29:06 -0700 Subject: [PATCH 1254/1547] [framework] reduce ink sparkle uniform count. (#133897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/flutter/flutter/issues/133325 Due to the number of uniforms present, the ink_sparkle shader can't run without post processing (on all target platforms) that the impellerc offline compiler doesn't perform. However, we can't just move the uniforms into a uniform buffer object (UBO) because the Skia backend doesn't support it. Rather than work around this in the compiler, we can reduce the uniform count by 1) packing four floats into a single vec4 2) removing a uniform for what is effectively a constant. This should have no visible effects, and if any scubas fail it means I did this wrong 😆 --- .../flutter/lib/src/material/ink_sparkle.dart | 54 ++++++++----------- .../lib/src/material/shaders/ink_sparkle.frag | 37 ++++++------- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/packages/flutter/lib/src/material/ink_sparkle.dart b/packages/flutter/lib/src/material/ink_sparkle.dart index a46fd28cd00e2..9f63819fbe16c 100644 --- a/packages/flutter/lib/src/material/ink_sparkle.dart +++ b/packages/flutter/lib/src/material/ink_sparkle.dart @@ -326,50 +326,42 @@ class InkSparkle extends InteractiveInkFeature { ..setFloat(1, _color.green / 255.0) ..setFloat(2, _color.blue / 255.0) ..setFloat(3, _color.alpha / 255.0) - // uAlpha + // Composite 1 (u_alpha, u_sparkle_alpha, u_blur, u_radius_scale) ..setFloat(4, _alpha.value) - // uSparkleColor - ..setFloat(5, 1.0) + ..setFloat(5, _sparkleAlpha.value) ..setFloat(6, 1.0) - ..setFloat(7, 1.0) - ..setFloat(8, 1.0) - // uSparkleAlpha - ..setFloat(9, _sparkleAlpha.value) - // uBlur - ..setFloat(10, 1.0) + ..setFloat(7, _radiusScale.value) // uCenter - ..setFloat(11, _center.value.x) - ..setFloat(12, _center.value.y) - // uRadiusScale - ..setFloat(13, _radiusScale.value) + ..setFloat(8, _center.value.x) + ..setFloat(9, _center.value.y) // uMaxRadius - ..setFloat(14, _targetRadius) + ..setFloat(10, _targetRadius) // uResolutionScale - ..setFloat(15, 1.0 / _width) - ..setFloat(16, 1.0 / _height) + ..setFloat(11, 1.0 / _width) + ..setFloat(12, 1.0 / _height) // uNoiseScale - ..setFloat(17, _noiseDensity / _width) - ..setFloat(18, _noiseDensity / _height) + ..setFloat(13, _noiseDensity / _width) + ..setFloat(14, _noiseDensity / _height) // uNoisePhase - ..setFloat(19, noisePhase / 1000.0) + ..setFloat(15, noisePhase / 1000.0) // uCircle1 - ..setFloat(20, turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.cos(turbulenceScale * 0.55))) - ..setFloat(21, turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.sin(turbulenceScale * 0.55))) + ..setFloat(16, turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.cos(turbulenceScale * 0.55))) + ..setFloat(17, turbulenceScale * 0.5 + (turbulencePhase * 0.01 * math.sin(turbulenceScale * 0.55))) // uCircle2 - ..setFloat(22, turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.45))) - ..setFloat(23, turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.45))) + ..setFloat(18, turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.45))) + ..setFloat(19, turbulenceScale * 0.2 + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.45))) // uCircle3 - ..setFloat(24, turbulenceScale + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.35))) - ..setFloat(25, turbulenceScale + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.35))) + ..setFloat(20, turbulenceScale + (turbulencePhase * -0.0066 * math.cos(turbulenceScale * 0.35))) + ..setFloat(21, turbulenceScale + (turbulencePhase * -0.0066 * math.sin(turbulenceScale * 0.35))) // uRotation1 - ..setFloat(26, math.cos(rotation1)) - ..setFloat(27, math.sin(rotation1)) + ..setFloat(22, math.cos(rotation1)) + ..setFloat(23, math.sin(rotation1)) // uRotation2 - ..setFloat(28, math.cos(rotation2)) - ..setFloat(29, math.sin(rotation2)) + ..setFloat(24, math.cos(rotation2)) + ..setFloat(25, math.sin(rotation2)) // uRotation3 - ..setFloat(30, math.cos(rotation3)) - ..setFloat(31, math.sin(rotation3)); + ..setFloat(26, math.cos(rotation3)) + ..setFloat(27, math.sin(rotation3)); } /// Transforms the canvas for an ink feature to be painted on the [canvas]. diff --git a/packages/flutter/lib/src/material/shaders/ink_sparkle.frag b/packages/flutter/lib/src/material/shaders/ink_sparkle.frag index aa82583921fbb..f9f3ce6be3dd5 100644 --- a/packages/flutter/lib/src/material/shaders/ink_sparkle.frag +++ b/packages/flutter/lib/src/material/shaders/ink_sparkle.frag @@ -11,22 +11,19 @@ precision highp float; // TODO(antrob): Put these in a more logical order (e.g. separate consts vs varying, etc) layout(location = 0) uniform vec4 u_color; -layout(location = 1) uniform float u_alpha; -layout(location = 2) uniform vec4 u_sparkle_color; -layout(location = 3) uniform float u_sparkle_alpha; -layout(location = 4) uniform float u_blur; -layout(location = 5) uniform vec2 u_center; -layout(location = 6) uniform float u_radius_scale; -layout(location = 7) uniform float u_max_radius; -layout(location = 8) uniform vec2 u_resolution_scale; -layout(location = 9) uniform vec2 u_noise_scale; -layout(location = 10) uniform float u_noise_phase; -layout(location = 11) uniform vec2 u_circle1; -layout(location = 12) uniform vec2 u_circle2; -layout(location = 13) uniform vec2 u_circle3; -layout(location = 14) uniform vec2 u_rotation1; -layout(location = 15) uniform vec2 u_rotation2; -layout(location = 16) uniform vec2 u_rotation3; +// u_alpha, u_sparkle_alpha, u_blur, u_radius_scale +layout(location = 1) uniform vec4 u_composite_1; +layout(location = 2) uniform vec2 u_center; +layout(location = 3) uniform float u_max_radius; +layout(location = 4) uniform vec2 u_resolution_scale; +layout(location = 5) uniform vec2 u_noise_scale; +layout(location = 6) uniform float u_noise_phase; +layout(location = 7) uniform vec2 u_circle1; +layout(location = 8) uniform vec2 u_circle2; +layout(location = 9) uniform vec2 u_circle3; +layout(location = 10) uniform vec2 u_rotation1; +layout(location = 11) uniform vec2 u_rotation2; +layout(location = 12) uniform vec2 u_rotation3; layout(location = 0) out vec4 fragColor; @@ -36,6 +33,11 @@ const float PI_ROTATE_LEFT = PI * -0.0078125; const float ONE_THIRD = 1./3.; const vec2 TURBULENCE_SCALE = vec2(0.8); +float u_alpha = u_composite_1.x; +float u_sparkle_alpha = u_composite_1.y; +float u_blur = u_composite_1.z; +float u_radius_scale = u_composite_1.w; + float triangle_noise(highp vec2 n) { n = fract(n * vec2(5.3987, 5.4421)); n += dot(n.yx, n.xy + vec2(21.5351, 14.3137)); @@ -99,6 +101,5 @@ void main() { float sparkle = sparkle(density_uv, u_noise_phase) * ring * turbulence * u_sparkle_alpha; float wave_alpha = soft_circle(p, u_center, radius, u_blur) * u_alpha * u_color.a; vec4 wave_color = vec4(u_color.rgb * wave_alpha, wave_alpha); - vec4 sparkle_color = vec4(u_sparkle_color.rgb * u_sparkle_color.a, u_sparkle_color.a); - fragColor = mix(wave_color, sparkle_color, sparkle); + fragColor = mix(wave_color, vec4(1.0), sparkle); } From ab1b865e58a69e7f6c2f3566532b5bbc838d678d Mon Sep 17 00:00:00 2001 From: hangyu <jhy03261997@gmail.com> Date: Wed, 13 Sep 2023 12:36:51 -0700 Subject: [PATCH 1255/1547] Dispose routes in navigator when throwing exception (#134596) fixes: #133695 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- packages/flutter/lib/src/widgets/navigator.dart | 3 +++ packages/flutter/test/material/app_test.dart | 10 +--------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index ccf3fbfb56ad9..e2f350d299b0e 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -2792,6 +2792,9 @@ class Navigator extends StatefulWidget { ); return true; }()); + for (final Route<dynamic>? route in result) { + route?.dispose(); + } result.clear(); } } else if (initialRouteName != Navigator.defaultRouteName) { diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 16bbac3557fcb..31d86997a8815 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -334,15 +334,7 @@ void main() { expect(find.text('route "/a/b"'), findsNothing); expect(find.text('route "/b"'), findsNothing); } - }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/133695 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?> { - 'ValueNotifier<String?>': 3, - 'MaterialPageRoute<dynamic>': 3, - }, - )); + }); testWidgetsWithLeakTracking('Make sure initialRoute is only used the first time', (WidgetTester tester) async { final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ From 3d7cd3594a12dacf2ddf45f630bb4bcc401e6f17 Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Wed, 13 Sep 2023 13:05:29 -0700 Subject: [PATCH 1256/1547] [flutter_tools] Run ShutdownHooks when handling signals (#134590) Fixes https://github.com/flutter/flutter/issues/134566. Prior to this fix, `ShutdownHooks` were run in the private helper function `_exit()` defined in the `package:flutter_tools/runner.dart` library. Independent of this, the tool had signal handling logic that traps SIGINT and SIGTERM. However, these handlers called `exit()` from `dart:io`, and didn't run these hooks. This PR moves the `_exit()` private helper to `package:flutter_tools/src/base/process.dart` and renames it to `exitWithHooks()`, so that it can be called by the signal handlers in `package:flutter_tools/src/base/signals.dart`. --- packages/flutter_tools/lib/runner.dart | 86 ++----------------- .../flutter_tools/lib/src/base/process.dart | 75 ++++++++++++++++ .../flutter_tools/lib/src/base/signals.dart | 13 ++- .../test/general.shard/base/signals_test.dart | 40 ++++++++- 4 files changed, 129 insertions(+), 85 deletions(-) diff --git a/packages/flutter_tools/lib/runner.dart b/packages/flutter_tools/lib/runner.dart index 9b33580af03e5..262eed522926b 100644 --- a/packages/flutter_tools/lib/runner.dart +++ b/packages/flutter_tools/lib/runner.dart @@ -20,7 +20,6 @@ import 'src/context_runner.dart'; import 'src/doctor.dart'; import 'src/globals.dart' as globals; import 'src/reporting/crash_reporting.dart'; -import 'src/reporting/first_run.dart'; import 'src/reporting/reporting.dart'; import 'src/runner/flutter_command.dart'; import 'src/runner/flutter_command_runner.dart'; @@ -115,7 +114,7 @@ Future<int> run( // Triggering [runZoned]'s error callback does not necessarily mean that // we stopped executing the body. See https://github.com/dart-lang/sdk/issues/42150. if (firstError == null) { - return await _exit(0, shutdownHooks: shutdownHooks); + return await exitWithHooks(0, shutdownHooks: shutdownHooks); } // We already hit some error, so don't return success. The error path @@ -151,7 +150,7 @@ Future<int> _handleToolError( globals.printError('${error.message}\n'); globals.printError("Run 'flutter -h' (or 'flutter <command> -h') for available flutter commands and options."); // Argument error exit code. - return _exit(64, shutdownHooks: shutdownHooks); + return exitWithHooks(64, shutdownHooks: shutdownHooks); } else if (error is ToolExit) { if (error.message != null) { globals.printError(error.message!); @@ -159,14 +158,14 @@ Future<int> _handleToolError( if (verbose) { globals.printError('\n$stackTrace\n'); } - return _exit(error.exitCode ?? 1, shutdownHooks: shutdownHooks); + return exitWithHooks(error.exitCode ?? 1, shutdownHooks: shutdownHooks); } else if (error is ProcessExit) { // We've caught an exit code. if (error.immediate) { exit(error.exitCode); return error.exitCode; } else { - return _exit(error.exitCode, shutdownHooks: shutdownHooks); + return exitWithHooks(error.exitCode, shutdownHooks: shutdownHooks); } } else { // We've crashed; emit a log report. @@ -176,7 +175,7 @@ Future<int> _handleToolError( // Print the stack trace on the bots - don't write a crash report. globals.stdio.stderrWrite('$error\n'); globals.stdio.stderrWrite('$stackTrace\n'); - return _exit(1, shutdownHooks: shutdownHooks); + return exitWithHooks(1, shutdownHooks: shutdownHooks); } // Report to both [Usage] and [CrashReportSender]. @@ -217,7 +216,7 @@ Future<int> _handleToolError( final File file = await _createLocalCrashReport(details); await globals.crashReporter!.informUser(details, file); - return _exit(1, shutdownHooks: shutdownHooks); + return exitWithHooks(1, shutdownHooks: shutdownHooks); // This catch catches all exceptions to ensure the message below is printed. } catch (error, st) { // ignore: avoid_catches_without_on_clauses globals.stdio.stderrWrite( @@ -283,76 +282,3 @@ Future<File> _createLocalCrashReport(CrashDetails details) async { return crashFile; } - -Future<int> _exit(int code, {required ShutdownHooks shutdownHooks}) async { - // Need to get the boolean returned from `messenger.shouldDisplayLicenseTerms()` - // before invoking the print welcome method because the print welcome method - // will set `messenger.shouldDisplayLicenseTerms()` to false - final FirstRunMessenger messenger = - FirstRunMessenger(persistentToolState: globals.persistentToolState!); - final bool legacyAnalyticsMessageShown = - messenger.shouldDisplayLicenseTerms(); - - // Prints the welcome message if needed for legacy analytics. - globals.flutterUsage.printWelcome(); - - // Ensure that the consent message has been displayed for unified analytics - if (globals.analytics.shouldShowMessage) { - globals.logger.printStatus(globals.analytics.getConsentMessage); - if (!globals.flutterUsage.enabled) { - globals.printStatus( - 'Please note that analytics reporting was already disabled, ' - 'and will continue to be disabled.\n'); - } - - // Because the legacy analytics may have also sent a message, - // the conditional below will print additional messaging informing - // users that the two consent messages they are receiving is not a - // bug - if (legacyAnalyticsMessageShown) { - globals.logger - .printStatus('You have received two consent messages because ' - 'the flutter tool is migrating to a new analytics system. ' - 'Disabling analytics collection will disable both the legacy ' - 'and new analytics collection systems. ' - 'You can disable analytics reporting by running `flutter --disable-analytics`\n'); - } - - // Invoking this will onboard the flutter tool onto - // the package on the developer's machine and will - // allow for events to be sent to Google Analytics - // on subsequent runs of the flutter tool (ie. no events - // will be sent on the first run to allow developers to - // opt out of collection) - globals.analytics.clientShowedMessage(); - } - - // Send any last analytics calls that are in progress without overly delaying - // the tool's exit (we wait a maximum of 250ms). - if (globals.flutterUsage.enabled) { - final Stopwatch stopwatch = Stopwatch()..start(); - await globals.flutterUsage.ensureAnalyticsSent(); - globals.printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms'); - } - - // Run shutdown hooks before flushing logs - await shutdownHooks.runShutdownHooks(globals.logger); - - final Completer<void> completer = Completer<void>(); - - // Give the task / timer queue one cycle through before we hard exit. - Timer.run(() { - try { - globals.printTrace('exiting with code $code'); - exit(code); - completer.complete(); - // This catches all exceptions because the error is propagated on the - // completer. - } catch (error, stackTrace) { // ignore: avoid_catches_without_on_clauses - completer.completeError(error, stackTrace); - } - }); - - await completer.future; - return code; -} diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart index 82a3c89b1d919..6fb36b0bc046a 100644 --- a/packages/flutter_tools/lib/src/base/process.dart +++ b/packages/flutter_tools/lib/src/base/process.dart @@ -8,6 +8,8 @@ import 'package:meta/meta.dart'; import 'package:process/process.dart'; import '../convert.dart'; +import '../globals.dart' as globals; +import '../reporting/first_run.dart'; import 'io.dart'; import 'logger.dart'; @@ -564,3 +566,76 @@ class _DefaultProcessUtils implements ProcessUtils { } } } + +Future<int> exitWithHooks(int code, {required ShutdownHooks shutdownHooks}) async { + // Need to get the boolean returned from `messenger.shouldDisplayLicenseTerms()` + // before invoking the print welcome method because the print welcome method + // will set `messenger.shouldDisplayLicenseTerms()` to false + final FirstRunMessenger messenger = + FirstRunMessenger(persistentToolState: globals.persistentToolState!); + final bool legacyAnalyticsMessageShown = + messenger.shouldDisplayLicenseTerms(); + + // Prints the welcome message if needed for legacy analytics. + globals.flutterUsage.printWelcome(); + + // Ensure that the consent message has been displayed for unified analytics + if (globals.analytics.shouldShowMessage) { + globals.logger.printStatus(globals.analytics.getConsentMessage); + if (!globals.flutterUsage.enabled) { + globals.printStatus( + 'Please note that analytics reporting was already disabled, ' + 'and will continue to be disabled.\n'); + } + + // Because the legacy analytics may have also sent a message, + // the conditional below will print additional messaging informing + // users that the two consent messages they are receiving is not a + // bug + if (legacyAnalyticsMessageShown) { + globals.logger + .printStatus('You have received two consent messages because ' + 'the flutter tool is migrating to a new analytics system. ' + 'Disabling analytics collection will disable both the legacy ' + 'and new analytics collection systems. ' + 'You can disable analytics reporting by running `flutter --disable-analytics`\n'); + } + + // Invoking this will onboard the flutter tool onto + // the package on the developer's machine and will + // allow for events to be sent to Google Analytics + // on subsequent runs of the flutter tool (ie. no events + // will be sent on the first run to allow developers to + // opt out of collection) + globals.analytics.clientShowedMessage(); + } + + // Send any last analytics calls that are in progress without overly delaying + // the tool's exit (we wait a maximum of 250ms). + if (globals.flutterUsage.enabled) { + final Stopwatch stopwatch = Stopwatch()..start(); + await globals.flutterUsage.ensureAnalyticsSent(); + globals.printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms'); + } + + // Run shutdown hooks before flushing logs + await shutdownHooks.runShutdownHooks(globals.logger); + + final Completer<void> completer = Completer<void>(); + + // Give the task / timer queue one cycle through before we hard exit. + Timer.run(() { + try { + globals.printTrace('exiting with code $code'); + exit(code); + completer.complete(); + // This catches all exceptions because the error is propagated on the + // completer. + } catch (error, stackTrace) { // ignore: avoid_catches_without_on_clauses + completer.completeError(error, stackTrace); + } + }); + + await completer.future; + return code; +} diff --git a/packages/flutter_tools/lib/src/base/signals.dart b/packages/flutter_tools/lib/src/base/signals.dart index 9185762cdfe54..a83d85b622e86 100644 --- a/packages/flutter_tools/lib/src/base/signals.dart +++ b/packages/flutter_tools/lib/src/base/signals.dart @@ -6,6 +6,8 @@ import 'dart:async'; import 'package:meta/meta.dart'; +import '../base/process.dart'; +import '../globals.dart' as globals; import 'async_guard.dart'; import 'io.dart'; @@ -18,7 +20,8 @@ abstract class Signals { @visibleForTesting factory Signals.test({ List<ProcessSignal> exitSignals = defaultExitSignals, - }) => LocalSignals._(exitSignals); + ShutdownHooks? shutdownHooks, + }) => LocalSignals._(exitSignals, shutdownHooks: shutdownHooks); // The default list of signals that should cause the process to exit. static const List<ProcessSignal> defaultExitSignals = <ProcessSignal>[ @@ -50,13 +53,17 @@ abstract class Signals { /// We use a singleton instance of this class to ensure that all handlers for /// fatal signals run before this class calls exit(). class LocalSignals implements Signals { - LocalSignals._(this.exitSignals); + LocalSignals._( + this.exitSignals, { + ShutdownHooks? shutdownHooks, + }) : _shutdownHooks = shutdownHooks ?? globals.shutdownHooks; static LocalSignals instance = LocalSignals._( Signals.defaultExitSignals, ); final List<ProcessSignal> exitSignals; + final ShutdownHooks _shutdownHooks; // A table mapping (signal, token) -> signal handler. final Map<ProcessSignal, Map<Object, SignalHandler>> _handlersTable = @@ -144,7 +151,7 @@ class LocalSignals implements Signals { // If this was a signal that should cause the process to go down, then // call exit(); if (_shouldExitFor(s)) { - exit(0); + await exitWithHooks(0, shutdownHooks: _shutdownHooks); } } diff --git a/packages/flutter_tools/test/general.shard/base/signals_test.dart b/packages/flutter_tools/test/general.shard/base/signals_test.dart index 0d8cae24c1830..d2b321b102c4f 100644 --- a/packages/flutter_tools/test/general.shard/base/signals_test.dart +++ b/packages/flutter_tools/test/general.shard/base/signals_test.dart @@ -6,19 +6,24 @@ import 'dart:async'; import 'dart:io' as io; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/base/signals.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; +import '../../src/context.dart'; void main() { group('Signals', () { late Signals signals; late FakeProcessSignal fakeSignal; late ProcessSignal signalUnderTest; + late FakeShutdownHooks shutdownHooks; setUp(() { - signals = Signals.test(); + shutdownHooks = FakeShutdownHooks(); + signals = Signals.test(shutdownHooks: shutdownHooks); fakeSignal = FakeProcessSignal(); signalUnderTest = ProcessSignal(fakeSignal); }); @@ -168,9 +173,10 @@ void main() { expect(errList, isEmpty); }); - testWithoutContext('all handlers for exiting signals are run before exit', () async { + testUsingContext('all handlers for exiting signals are run before exit', () async { final Signals signals = Signals.test( exitSignals: <ProcessSignal>[signalUnderTest], + shutdownHooks: shutdownHooks, ); final Completer<void> completer = Completer<void>(); bool first = false; @@ -201,6 +207,27 @@ void main() { fakeSignal.controller.add(fakeSignal); await completer.future; + expect(shutdownHooks.ranShutdownHooks, isTrue); + }); + + testUsingContext('ShutdownHooks run before exiting', () async { + final Signals signals = Signals.test( + exitSignals: <ProcessSignal>[signalUnderTest], + shutdownHooks: shutdownHooks, + ); + final Completer<void> completer = Completer<void>(); + + setExitFunctionForTests((int exitCode) { + expect(exitCode, 0); + restoreExitFunction(); + completer.complete(); + }); + + signals.addHandler(signalUnderTest, (ProcessSignal s) {}); + + fakeSignal.controller.add(fakeSignal); + await completer.future; + expect(shutdownHooks.ranShutdownHooks, isTrue); }); }); } @@ -211,3 +238,12 @@ class FakeProcessSignal extends Fake implements io.ProcessSignal { @override Stream<io.ProcessSignal> watch() => controller.stream; } + +class FakeShutdownHooks extends Fake implements ShutdownHooks { + bool ranShutdownHooks = false; + + @override + Future<void> runShutdownHooks(Logger logger) async { + ranShutdownHooks = true; + } +} From 5243d18e8db19b29cf4c681256cdae7d525cc80d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 16:33:16 -0400 Subject: [PATCH 1257/1547] Roll Flutter Engine from b71b366e3de3 to 154d6fd601a3 (6 revisions) (#134683) https://github.com/flutter/engine/compare/b71b366e3de3...154d6fd601a3 2023-09-13 godofredoc@google.com Auto update dependencies for web_ui. (flutter/engine#45754) 2023-09-13 30870216+gaaclarke@users.noreply.github.com Revert "[Impeller] Patch the compiler to account for subpass inputs and PSO metadata." (flutter/engine#45777) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 471216072c74 to e39cf360ea93 (4 revisions) (flutter/engine#45776) 2023-09-13 chinmaygarde@google.com [Impeller] Remove dependency on //flutter/vulkan and use a single proc table. (flutter/engine#45741) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 78d18d509475 to 471216072c74 (4 revisions) (flutter/engine#45774) 2023-09-13 47866232+chunhtai@users.noreply.github.com [Impeller] Fixes stroke path geometry that can draw outside of path if the path ends at sharp turn. (flutter/engine#45252) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a3510f822f3d3..112fb747993e5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b71b366e3de3be6720b193086271a3934ead3901 +154d6fd601a3442559e430f8fe197a58ac99867a From 04ad1da1ae167c42ae8ba484758036ef9e50ddc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 22:28:23 +0000 Subject: [PATCH 1258/1547] Bump github/codeql-action from 2.21.5 to 2.21.6 (#134692) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.5 to 2.21.6. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/github/codeql-action/blob/main/CHANGELOG.md">github/codeql-action's changelog</a>.</em></p> <blockquote> <h1>CodeQL Action Changelog</h1> <p>See the <a href="https://github.com/github/codeql-action/releases">releases page</a> for the relevant changes to the CodeQL CLI and language packs.</p> <h2>[UNRELEASED]</h2> <p>No user facing changes.</p> <h2>2.21.6 - 13 Sep 2023</h2> <ul> <li>Better error message when there is a failure to determine the merge base of the code to analysis. <a href="https://redirect.github.com/github/codeql-action/pull/1860">#1860</a></li> <li>Improve the calculation of default amount of RAM used for query execution on GitHub Enterprise Server. This now reduces in proportion to the runner's total memory to better account for system memory usage, helping to avoid out-of-memory failures on larger runners. This feature is already available to GitHub.com users. <a href="https://redirect.github.com/github/codeql-action/pull/1866">#1866</a></li> <li>Enable improved file coverage information for GitHub Enterprise Server users. This feature is already available to GitHub.com users. <a href="https://redirect.github.com/github/codeql-action/pull/1867">#1867</a></li> <li>Update default CodeQL bundle version to 2.14.4. <a href="https://redirect.github.com/github/codeql-action/pull/1873">#1873</a></li> </ul> <h2>2.21.5 - 28 Aug 2023</h2> <ul> <li>Update default CodeQL bundle version to 2.14.3. <a href="https://redirect.github.com/github/codeql-action/pull/1845">#1845</a></li> <li>Fixed a bug in CodeQL Action 2.21.3 onwards that affected beta support for <a href="https://projectlombok.org/">Project Lombok</a> when analyzing Java. The environment variable <code>CODEQL_EXTRACTOR_JAVA_RUN_ANNOTATION_PROCESSORS</code> will now be respected if it was manually configured in the workflow. <a href="https://redirect.github.com/github/codeql-action/pull/1844">#1844</a></li> <li>Enable support for Kotlin 1.9.20 when running with CodeQL CLI v2.13.4 through v2.14.3. <a href="https://redirect.github.com/github/codeql-action/pull/1853">#1853</a></li> </ul> <h2>2.21.4 - 14 Aug 2023</h2> <ul> <li>Update default CodeQL bundle version to 2.14.2. <a href="https://redirect.github.com/github/codeql-action/pull/1831">#1831</a></li> <li>Log a warning if the amount of available disk space runs low during a code scanning run. <a href="https://redirect.github.com/github/codeql-action/pull/1825">#1825</a></li> <li>When downloading CodeQL bundle version 2.13.4 and later, cache these bundles in the Actions tool cache using a simpler version number. <a href="https://redirect.github.com/github/codeql-action/pull/1832">#1832</a></li> <li>Fix an issue that first appeared in CodeQL Action v2.21.2 that prevented CodeQL invocations from being logged. <a href="https://redirect.github.com/github/codeql-action/pull/1833">#1833</a></li> <li>We are rolling out a feature in August 2023 that will improve the quality of file coverage information. <a href="https://redirect.github.com/github/codeql-action/pull/1835">#1835</a></li> </ul> <h2>2.21.3 - 08 Aug 2023</h2> <ul> <li>We are rolling out a feature in August 2023 that will improve multi-threaded performance on larger runners. <a href="https://redirect.github.com/github/codeql-action/pull/1817">#1817</a></li> <li>We are rolling out a feature in August 2023 that adds beta support for <a href="https://projectlombok.org/">Project Lombok</a> when analyzing Java. <a href="https://redirect.github.com/github/codeql-action/pull/1809">#1809</a></li> <li>Reduce disk space usage when downloading the CodeQL bundle. <a href="https://redirect.github.com/github/codeql-action/pull/1820">#1820</a></li> </ul> <h2>2.21.2 - 28 Jul 2023</h2> <ul> <li>Update default CodeQL bundle version to 2.14.1. <a href="https://redirect.github.com/github/codeql-action/pull/1797">#1797</a></li> <li>Avoid duplicating the analysis summary within the logs. <a href="https://redirect.github.com/github/codeql-action/pull/1811">#1811</a></li> </ul> <h2>2.21.1 - 26 Jul 2023</h2> <ul> <li>Improve the handling of fatal errors from the CodeQL CLI. <a href="https://redirect.github.com/github/codeql-action/pull/1795">#1795</a></li> <li>Add the <code>sarif-output</code> output to the analyze action that contains the path to the directory of the generated SARIF. <a href="https://redirect.github.com/github/codeql-action/pull/1799">#1799</a></li> </ul> <h2>2.21.0 - 19 Jul 2023</h2> <ul> <li>CodeQL Action now requires CodeQL CLI 2.9.4 or later. For more information, see the corresponding changelog entry for CodeQL Action version 2.20.4. <a href="https://redirect.github.com/github/codeql-action/pull/1724">#1724</a></li> </ul> <h2>2.20.4 - 14 Jul 2023</h2> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/github/codeql-action/commit/701f152f28d4350ad289a5e31435e9ab6169a7ca"><code>701f152</code></a> Merge pull request <a href="https://redirect.github.com/github/codeql-action/issues/1875">#1875</a> from github/update-v2.21.6-6a6a82470</li> <li><a href="https://github.com/github/codeql-action/commit/1b6299040ad80bda41f4a39badd92c941bb4f691"><code>1b62990</code></a> Fix misplaced changelog entry</li> <li><a href="https://github.com/github/codeql-action/commit/5462f691537a95d1496acdc934d234930f8300bb"><code>5462f69</code></a> Update changelog for v2.21.6</li> <li><a href="https://github.com/github/codeql-action/commit/6a6a824702bd1d44a92996212781e3a602e71d70"><code>6a6a824</code></a> Merge pull request <a href="https://redirect.github.com/github/codeql-action/issues/1873">#1873</a> from github/update-bundle/codeql-bundle-v2.14.4</li> <li><a href="https://github.com/github/codeql-action/commit/88c7a5c4ccbf66f35fe5cb09c52cbd1c28618a67"><code>88c7a5c</code></a> Add changelog note</li> <li><a href="https://github.com/github/codeql-action/commit/da650354980b498016b5c3d94088fccf593a40ba"><code>da65035</code></a> Update default bundle to codeql-bundle-v2.14.4</li> <li><a href="https://github.com/github/codeql-action/commit/43750fe4fc4f068f04f2215206e6f6a29c78c763"><code>43750fe</code></a> Merge pull request <a href="https://redirect.github.com/github/codeql-action/issues/1872">#1872</a> from github/henrymercer/user-errors-for-upload-sarif</li> <li><a href="https://github.com/github/codeql-action/commit/a7c12a522555ecd630965e7f80e9e3dc35dc0268"><code>a7c12a5</code></a> Address PR comments</li> <li><a href="https://github.com/github/codeql-action/commit/7218de5369ba3e5f3959e134631f2af1f41079f9"><code>7218de5</code></a> Merge branch 'main' into henrymercer/user-errors-for-upload-sarif</li> <li><a href="https://github.com/github/codeql-action/commit/4764dce02f71916cc65cfef3af053e331cc6831c"><code>4764dce</code></a> Merge pull request <a href="https://redirect.github.com/github/codeql-action/issues/1866">#1866</a> from github/henrymercer/enable-scaling-reserved-ram-...</li> <li>Additional commits viewable in <a href="https://github.com/github/codeql-action/compare/00e563ead9f72a8461b24876bee2d0c2e8bd2ee8...701f152f28d4350ad289a5e31435e9ab6169a7ca">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github/codeql-action&package-manager=github_actions&previous-version=2.21.5&new-version=2.21.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 74e214d4e84ca..9ee5be88b630b 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8 + uses: github/codeql-action/upload-sarif@701f152f28d4350ad289a5e31435e9ab6169a7ca with: sarif_file: results.sarif From a80af67a0030dbc4ee5a524384e0b5e20853fb4c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 13 Sep 2023 18:30:08 -0400 Subject: [PATCH 1259/1547] Roll Flutter Engine from 154d6fd601a3 to cd90cc8469fb (3 revisions) (#134691) https://github.com/flutter/engine/compare/154d6fd601a3...cd90cc8469fb 2023-09-13 godofredoc@google.com Update dependabot.yml (flutter/engine#45788) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from e39cf360ea93 to b38989859b81 (4 revisions) (flutter/engine#45787) 2023-09-13 109111084+yaakovschectman@users.noreply.github.com Use `start` instead of `extent` for Windows IME cursor position (flutter/engine#45667) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 112fb747993e5..c7f0a1d004853 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -154d6fd601a3442559e430f8fe197a58ac99867a +cd90cc8469fbc789e0b44adc79f330f8d4d2744c From b4953c37694e7c8ab0e4daa15c4ab6deb97b7fde Mon Sep 17 00:00:00 2001 From: Delwin Mathew <84124091+opxdelwin@users.noreply.github.com> Date: Thu, 14 Sep 2023 04:25:05 +0530 Subject: [PATCH 1260/1547] Fix null check crash by ReorderableList (#132153) Fix issue where if you drag the last element of `ReorderableList` and put it in the same index, a `Null check` error arises. This happens as index in `_items` is out of bounds (when `reverse: true`). Fix is to check if last element, dragged element and drop index is same, and return as nothing has changed. Find this video attached. https://github.com/flutter/flutter/assets/84124091/8043cac3-eb08-42e1-87e7-8095ecab09dc Fixes issue #132077 --- .../lib/src/widgets/reorderable_list.dart | 19 ++++++++ .../test/widgets/reorderable_list_test.dart | 45 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/packages/flutter/lib/src/widgets/reorderable_list.dart b/packages/flutter/lib/src/widgets/reorderable_list.dart index 0f0d5e78ccec3..af912e5ac2c13 100644 --- a/packages/flutter/lib/src/widgets/reorderable_list.dart +++ b/packages/flutter/lib/src/widgets/reorderable_list.dart @@ -798,6 +798,25 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke } void _dragEnd(_DragInfo item) { + // No changes required if last child is being inserted into the last position. + if ((_insertIndex! + 1 == _items.length) && _reverse) { + final RenderBox lastItemRenderBox = _items[_items.length - 1]!.context.findRenderObject()! as RenderBox; + final Offset lastItemOffset = lastItemRenderBox.localToGlobal(Offset.zero); + + // When drag starts, the corresponding element is removed from + // the list, and moves inside of [ReorderableListState.CustomScrollView], + // which gives [CustomScrollView] a variable height. + // + // So when the element is moved, delta would change accordingly, + // and since it's the last element, + // we animate it back to it's position and add it back to the list. + final double delta = item.itemSize.height; + + setState(() { + _finalDropPosition = Offset(lastItemOffset.dx, lastItemOffset.dy - delta); + }); + return; + } setState(() { if (_insertIndex == item.index) { _finalDropPosition = _itemOffsetAt(_insertIndex! + (_reverse ? 1 : 0)); diff --git a/packages/flutter/test/widgets/reorderable_list_test.dart b/packages/flutter/test/widgets/reorderable_list_test.dart index 1437c597109fa..496d2242b1b33 100644 --- a/packages/flutter/test/widgets/reorderable_list_test.dart +++ b/packages/flutter/test/widgets/reorderable_list_test.dart @@ -1309,6 +1309,51 @@ void main() { expect(offsetForFastScroller / offsetForSlowScroller, fastVelocityScalar / slowVelocityScalar); }); + + testWidgets('Null check error when dragging and dropping last element into last index with reverse:true', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/132077 + const int itemCount = 5; + final List<String> items = List<String>.generate(itemCount, (int index) => 'Item ${index+1}'); + + await tester.pumpWidget( + MaterialApp( + home: ReorderableList( + onReorder: (int oldIndex, int newIndex) { + if (newIndex > oldIndex) { + newIndex -= 1; + } + final String item = items.removeAt(oldIndex); + items.insert(newIndex, item); + }, + itemCount: items.length, + reverse: true, + itemBuilder: (BuildContext context, int index) { + return ReorderableDragStartListener( + key: Key('$index'), + index: index, + child: Material( + child: ListTile( + title: Text(items[index]), + ), + ), + ); + }, + ), + ) + ); + + // Start gesture on last item + final TestGesture drag = await tester.startGesture(tester.getCenter(find.text('Item 5'))); + await tester.pump(kLongPressTimeout); + + // Drag to move up the last item, and drop at the last index + await drag.moveBy(const Offset(0, -50)); + await tester.pump(); + await drag.up(); + await tester.pumpAndSettle(); + + expect(tester.takeException(), null); + }); } class TestList extends StatelessWidget { From 2ea9edc1ad51c742d4f3c55610820a33456d2b62 Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Wed, 13 Sep 2023 18:16:14 -0500 Subject: [PATCH 1261/1547] Update KeepAlive.debugTypicalAncestorWidgetClass (#133498) --- .../flutter/lib/src/cupertino/dialog.dart | 3 +-- .../flutter/lib/src/widgets/framework.dart | 26 ++++++++++++++----- packages/flutter/lib/src/widgets/sliver.dart | 12 ++++++--- .../flutter/test/widgets/keep_alive_test.dart | 8 ++++++ 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 2e4d27af75740..4b969a2b3146e 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -1577,8 +1577,7 @@ class _ActionButtonParentDataWidget } @override - Type get debugTypicalAncestorWidgetClass => - _CupertinoDialogActionsRenderWidget; + Type get debugTypicalAncestorWidgetClass => _CupertinoDialogActionsRenderWidget; } // ParentData applied to individual action buttons that report whether or not diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 34421ae2e5efe..ebe4e60e849cd 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1592,15 +1592,19 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget { return renderObject.parentData is T; } - /// The [RenderObjectWidget] that is typically used to set up the [ParentData] - /// that [applyParentData] will write to. + /// Describes the [RenderObjectWidget] that is typically used to set up the + /// [ParentData] that [applyParentData] will write to. /// /// This is only used in error messages to tell users what widget typically - /// wraps this [ParentDataWidget]. + /// wraps this [ParentDataWidget] through + /// [debugTypicalAncestorWidgetDescription]. /// /// ## Implementations /// - /// The returned type should be a subclass of `RenderObjectWidget`. + /// The returned Type should describe a subclass of `RenderObjectWidget`. If + /// more than one Type is supported, use + /// [debugTypicalAncestorWidgetDescription], which typically inserts this + /// value but can be overridden to describe more than one Type. /// /// ```dart /// @override @@ -1612,6 +1616,16 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget { /// type is specialized), or specifying the upper bound (e.g. `Foo<Object?>`). Type get debugTypicalAncestorWidgetClass; + /// Describes the [RenderObjectWidget] that is typically used to set up the + /// [ParentData] that [applyParentData] will write to. + /// + /// This is only used in error messages to tell users what widget typically + /// wraps this [ParentDataWidget]. + /// + /// Returns [debugTypicalAncestorWidgetClass] by default as a String. This can + /// be overridden to describe more than one Type of valid parent. + String get debugTypicalAncestorWidgetDescription => '$debugTypicalAncestorWidgetClass'; + Iterable<DiagnosticsNode> _debugDescribeIncorrectParentDataType({ required ParentData? parentData, RenderObjectWidget? parentDataCreator, @@ -1632,7 +1646,7 @@ abstract class ParentDataWidget<T extends ParentData> extends ProxyWidget { ), ErrorHint( 'Usually, this means that the $runtimeType widget has the wrong ancestor RenderObjectWidget. ' - 'Typically, $runtimeType widgets are placed directly inside $debugTypicalAncestorWidgetClass widgets.', + 'Typically, $runtimeType widgets are placed directly inside $debugTypicalAncestorWidgetDescription widgets.', ), if (parentDataCreator != null) ErrorHint( @@ -6300,7 +6314,7 @@ abstract class RenderObjectElement extends Element { ErrorSummary('Incorrect use of ParentDataWidget.'), ErrorDescription('The following ParentDataWidgets are providing parent data to the same RenderObject:'), for (final ParentDataElement<ParentData> ancestor in badAncestors) - ErrorDescription('- ${ancestor.widget} (typically placed directly inside a ${(ancestor.widget as ParentDataWidget<ParentData>).debugTypicalAncestorWidgetClass} widget)'), + ErrorDescription('- ${ancestor.widget} (typically placed directly inside a ${(ancestor.widget as ParentDataWidget<ParentData>).debugTypicalAncestorWidgetDescription} widget)'), ErrorDescription('However, a RenderObject can only receive parent data from at most one ParentDataWidget.'), ErrorHint('Usually, this indicates that at least one of the offending ParentDataWidgets listed above is not placed directly inside a compatible ancestor widget.'), ErrorDescription('The ownership chain for the RenderObject that received the parent data was:\n ${debugGetCreatorChain(10)}'), diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart index 65ce9e48d76fe..f4bb14da73cc3 100644 --- a/packages/flutter/lib/src/widgets/sliver.dart +++ b/packages/flutter/lib/src/widgets/sliver.dart @@ -1311,8 +1311,8 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement { /// Mark a child as needing to stay alive even when it's in a lazy list that /// would otherwise remove it. /// -/// This widget is for use in [SliverWithKeepAliveWidget]s, such as -/// [SliverGrid] or [SliverList]. +/// This widget is for use in a [RenderAbstractViewport]s, such as +/// [Viewport] or [TwoDimensionalViewport]. /// /// This widget is rarely used directly. The [SliverChildBuilderDelegate] and /// [SliverChildListDelegate] delegates, used with [SliverList] and @@ -1322,6 +1322,9 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement { /// each child, causing [KeepAlive] widgets to be automatically added and /// configured in response to [KeepAliveNotification]s. /// +/// The same `addAutomaticKeepAlives` feature is supported by the +/// [TwoDimensionalChildBuilderDelegate] and [TwoDimensionalChildListDelegate]. +/// /// Therefore, to keep a widget alive, it is more common to use those /// notifications than to directly deal with [KeepAlive] widgets. /// @@ -1365,7 +1368,10 @@ class KeepAlive extends ParentDataWidget<KeepAliveParentDataMixin> { bool debugCanApplyOutOfTurn() => keepAlive; @override - Type get debugTypicalAncestorWidgetClass => SliverWithKeepAliveWidget; + Type get debugTypicalAncestorWidgetClass => throw FlutterError('Multiple Types are supported, use debugTypicalAncestorWidgetDescription.'); + + @override + String get debugTypicalAncestorWidgetDescription => 'SliverWithKeepAliveWidget or TwoDimensionalViewport'; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { diff --git a/packages/flutter/test/widgets/keep_alive_test.dart b/packages/flutter/test/widgets/keep_alive_test.dart index 6bd324f990466..c44843916d72c 100644 --- a/packages/flutter/test/widgets/keep_alive_test.dart +++ b/packages/flutter/test/widgets/keep_alive_test.dart @@ -47,6 +47,14 @@ List<Widget> generateList(Widget child) { } void main() { + test('KeepAlive debugTypicalAncestorWidgetClass', () { + final KeepAlive keepAlive = KeepAlive(keepAlive: false, child: Container()); + expect( + keepAlive.debugTypicalAncestorWidgetDescription, + 'SliverWithKeepAliveWidget or TwoDimensionalViewport', + ); + }); + testWidgetsWithLeakTracking('KeepAlive with ListView with itemExtent', (WidgetTester tester) async { await tester.pumpWidget( Directionality( From b2f3404ca0d71b853c1d93557aaf74748bc8fab4 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Wed, 13 Sep 2023 16:27:13 -0700 Subject: [PATCH 1262/1547] Remove `Path.combine` call from `CupertionoTextSelectionToolbar` (#134369) Hopefully this fixes https://github.com/flutter/flutter/issues/110076 by removing the `Path.combine` call. Not sure how I can verify in a test that `Path.combine` is not called. --- .../src/cupertino/text_selection_toolbar.dart | 148 +++++++++++------- .../test/cupertino/text_field_test.dart | 11 +- 2 files changed, 101 insertions(+), 58 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart index e4703a60f1d94..ff1bd07c7a3a0 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:collection'; +import 'dart:math' as math show pi; import 'dart:ui' as ui; import 'package:flutter/foundation.dart' show Brightness, clampDouble; @@ -279,87 +280,127 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { markNeedsLayout(); } - // The child is tall enough to have the arrow clipped out of it on both sides - // top and bottom. Since _kToolbarHeight includes the height of one arrow, the - // total height that the child is given is that plus one more arrow height. - // The extra height on the opposite side of the arrow will be clipped out. By - // using this approach, the buttons don't need any special padding that - // depends on isAbove. - final BoxConstraints _heightConstraint = BoxConstraints.tightFor( - height: _kToolbarHeight + _kToolbarArrowSize.height, - ); - @override void performLayout() { + final RenderBox? child = this.child; if (child == null) { return; } - final BoxConstraints enforcedConstraint = constraints.loosen(); + // The child is tall enough to have the arrow clipped out of it on both sides + // top and bottom. Since _kToolbarHeight includes the height of one arrow, the + // total height that the child is given is that plus one more arrow height. + // The extra height on the opposite side of the arrow will be clipped out. By + // using this approach, the buttons don't need any special padding that + // depends on isAbove. + final BoxConstraints heightConstraint = BoxConstraints( + minHeight: _kToolbarHeight + _kToolbarArrowSize.height, + maxHeight: _kToolbarHeight + _kToolbarArrowSize.height, + minWidth: _kToolbarArrowSize.width + _kToolbarBorderRadius.x * 2, + ).enforce(constraints.loosen()); - child!.layout(_heightConstraint.enforce(enforcedConstraint), parentUsesSize: true); + child.layout(heightConstraint, parentUsesSize: true); // The height of one arrow will be clipped off of the child, so adjust the // size and position to remove that piece from the layout. - final BoxParentData childParentData = child!.parentData! as BoxParentData; + final BoxParentData childParentData = child.parentData! as BoxParentData; childParentData.offset = Offset( 0.0, _isAbove ? -_kToolbarArrowSize.height : 0.0, ); size = Size( - child!.size.width, - child!.size.height - _kToolbarArrowSize.height, + child.size.width, + child.size.height - _kToolbarArrowSize.height, ); } + // Adds the given `rrect` to the current `path`, starting from the last point + // in `path` and ends after the last corner of the rrect (closest corner to + // `startAngle` in the counterclockwise direction), without closing the path. + // + // The `startAngle` argument must be a multiple of pi / 2, with 0 being the + // positive half of the x-axis, and pi / 2 being the negative half of the + // y-axis. + // + // For instance, if `startAngle` equals pi/2 then this method draws a line + // segment to the bottom-left corner of `rrect` from the last point in `path`, + // and follows the `rrect` path clockwise until the bottom-right corner is + // added, then this method returns the mutated path without closing it. + static Path _addRRectToPath(Path path, RRect rrect, { required double startAngle }) { + const double halfPI = math.pi / 2; + assert(startAngle % halfPI == 0); + final Rect rect = rrect.outerRect; + + final List<(Offset, Radius)> rrectCorners = <(Offset, Radius)>[ + (rect.bottomRight, -rrect.brRadius), + (rect.bottomLeft, Radius.elliptical(rrect.blRadiusX, -rrect.blRadiusY)), + (rect.topLeft, rrect.tlRadius), + (rect.topRight, Radius.elliptical(-rrect.trRadiusX, rrect.trRadiusY)), + ]; + + // Add the 4 corners to the path clockwise. Convert radians to quadrants + // to avoid fp arithmetics. The order is br -> bl -> tl -> tr if the starting + // angle is 0. + final int startQuadrantIndex = startAngle ~/ halfPI; + for (int i = startQuadrantIndex; i < rrectCorners.length + startQuadrantIndex; i += 1) { + final (Offset vertex, Radius rectCenterOffset) = rrectCorners[i % rrectCorners.length]; + final Offset otherVertex = Offset(vertex.dx + 2 * rectCenterOffset.x, vertex.dy + 2 * rectCenterOffset.y); + final Rect rect = Rect.fromPoints(vertex, otherVertex); + path.arcTo(rect, halfPI * i, halfPI, false); + } + return path; + } + // The path is described in the toolbar's coordinate system. - Path _clipPath() { - final BoxParentData childParentData = child!.parentData! as BoxParentData; - final Path rrect = Path() - ..addRRect( - RRect.fromRectAndRadius( - Offset(0.0, _kToolbarArrowSize.height) - & Size( - child!.size.width, - child!.size.height - _kToolbarArrowSize.height * 2, - ), - _kToolbarBorderRadius, - ), - ); + Path _clipPath(RenderBox child) { + final Rect rect = Offset(0.0, _isAbove ? 0 : _kToolbarArrowSize.height) + & Size(size.width, size.height - _kToolbarArrowSize.height); + final RRect rrect = RRect.fromRectAndRadius(rect, _kToolbarBorderRadius).scaleRadii(); + + final Path path = Path(); + // If there isn't enough width for the arrow + radii, ignore the arrow. + // Because of the constraints we gave children in performLayout, this should + // only happen if the parent isn't wide enough which should be very rare, and + // when that happens the arrow won't be too useful anyways. + if (_kToolbarBorderRadius.x * 2 + _kToolbarArrowSize.width > size.width) { + return path..addRRect(rrect); + } final Offset localAnchor = globalToLocal(_anchor); - final double centerX = childParentData.offset.dx + child!.size.width / 2; - final double arrowXOffsetFromCenter = localAnchor.dx - centerX; - final double arrowTipX = child!.size.width / 2 + arrowXOffsetFromCenter; - - final double arrowBaseY = _isAbove - ? child!.size.height - _kToolbarArrowSize.height - : _kToolbarArrowSize.height; - - final double arrowTipY = _isAbove ? child!.size.height : 0; - - final Path arrow = Path() - ..moveTo(arrowTipX, arrowTipY) - ..lineTo(arrowTipX - _kToolbarArrowSize.width / 2, arrowBaseY) - ..lineTo(arrowTipX + _kToolbarArrowSize.width / 2, arrowBaseY) - ..close(); + final double arrowTipX = clampDouble( + localAnchor.dx, + _kToolbarBorderRadius.x + _kToolbarArrowSize.width / 2, + size.width - _kToolbarArrowSize.width / 2 - _kToolbarBorderRadius.x, + ); - return Path.combine(PathOperation.union, rrect, arrow); + // Draw the path clockwise, starting from the beginning side of the arrow. + if (_isAbove) { + path + ..moveTo(arrowTipX + _kToolbarArrowSize.width / 2, rect.bottom) // right side of the arrow triangle + ..lineTo(arrowTipX, rect.bottom + _kToolbarArrowSize.height) // The tip of the arrow + ..lineTo(arrowTipX - _kToolbarArrowSize.width / 2, rect.bottom); // left side of the arrow triangle + } else { + path + ..moveTo(arrowTipX - _kToolbarArrowSize.width / 2, rect.top) // right side of the arrow triangle + ..lineTo(arrowTipX, rect.top) // The tip of the arrow + ..lineTo(arrowTipX + _kToolbarArrowSize.width / 2, rect.top); // left side of the arrow triangle + } + final double startAngle = _isAbove ? math.pi / 2 : -math.pi / 2; + return _addRRectToPath(path, rrect, startAngle: startAngle)..close(); } @override void paint(PaintingContext context, Offset offset) { + final RenderBox? child = this.child; if (child == null) { return; } - - final BoxParentData childParentData = child!.parentData! as BoxParentData; _clipPathLayer.layer = context.pushClipPath( needsCompositing, - offset + childParentData.offset, - Offset.zero & child!.size, - _clipPath(), - (PaintingContext innerContext, Offset innerOffset) => innerContext.paintChild(child!, innerOffset), + offset, + Offset.zero & size, + _clipPath(child), + super.paint, oldLayer: _clipPathLayer.layer, ); } @@ -376,11 +417,12 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { @override void debugPaintSize(PaintingContext context, Offset offset) { assert(() { + final RenderBox? child = this.child; if (child == null) { return true; } - _debugPaint ??= Paint() + final ui.Paint debugPaint = _debugPaint ??= Paint() ..shader = ui.Gradient.linear( Offset.zero, const Offset(10.0, 10.0), @@ -391,8 +433,8 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { ..strokeWidth = 2.0 ..style = PaintingStyle.stroke; - final BoxParentData childParentData = child!.parentData! as BoxParentData; - context.canvas.drawPath(_clipPath().shift(offset + childParentData.offset), _debugPaint!); + final BoxParentData childParentData = child.parentData! as BoxParentData; + context.canvas.drawPath(_clipPath(child).shift(offset + childParentData.offset), debugPaint); return true; }()); } diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index bd5721aba3c64..df3001ce6ce60 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -6835,8 +6835,9 @@ void main() { bottomLeftSelectionPosition.translate(0, 8 + 0.1), ], includes: <Offset> [ - // Expected center of the arrow. - Offset(26.0, bottomLeftSelectionPosition.dy + 8 + 0.1), + // Expected center of the arrow. The arrow should stay clear of + // the edges of the selection toolbar. + Offset(26.0, bottomLeftSelectionPosition.dy + 7.0 + 8.0 + 0.1), ], ), ), @@ -6846,7 +6847,7 @@ void main() { find.byType(CupertinoTextSelectionToolbar), paints..clipPath( pathMatcher: PathBoundsMatcher( - topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8, epsilon: 0.01), + topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 7 + 8, epsilon: 0.01), leftMatcher: moreOrLessEquals(8), rightMatcher: lessThanOrEqualTo(400 - 8), bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8 + 45, epsilon: 0.01), @@ -6897,7 +6898,7 @@ void main() { ], includes: <Offset> [ // Expected center of the arrow. - Offset(400 - 26.0, bottomLeftSelectionPosition.dy + 8 + 0.1), + Offset(400 - 26.0, bottomLeftSelectionPosition.dy + 7 + 8 + 0.1), ], ), ), @@ -6907,7 +6908,7 @@ void main() { find.byType(CupertinoTextSelectionToolbar), paints..clipPath( pathMatcher: PathBoundsMatcher( - topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8, epsilon: 0.01), + topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 7 + 8, epsilon: 0.01), rightMatcher: moreOrLessEquals(400.0 - 8), bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8 + 45, epsilon: 0.01), leftMatcher: greaterThanOrEqualTo(8), From ee9aef0130fd9ec2cd958f92508d93679f7ce46b Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Wed, 13 Sep 2023 19:48:22 -0700 Subject: [PATCH 1263/1547] _DayPicker should build days using separate stetefull widget _Day. (#134607) Fixes https://github.com/flutter/flutter/issues/134323 --- .../src/material/calendar_date_picker.dart | 207 +++++++++++------- 1 file changed, 125 insertions(+), 82 deletions(-) diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 303bb43be1773..9bc419eac50dd 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -868,10 +868,6 @@ class _DayPickerState extends State<_DayPicker> { /// List of [FocusNode]s, one for each day of the month. late List<FocusNode> _dayFocusNodes; - // TODO(polina-c): a cleaner solution is to create separate statefull widget for a day. - // https://github.com/flutter/flutter/issues/134323 - final Map<int, MaterialStatesController> _statesControllers = <int, MaterialStatesController>{}; - @override void initState() { super.initState(); @@ -897,9 +893,6 @@ class _DayPickerState extends State<_DayPicker> { for (final FocusNode node in _dayFocusNodes) { node.dispose(); } - for (final MaterialStatesController controller in _statesControllers.values) { - controller.dispose(); - } super.dispose(); } @@ -937,7 +930,6 @@ class _DayPickerState extends State<_DayPicker> { final DatePickerThemeData datePickerTheme = DatePickerTheme.of(context); final DatePickerThemeData defaults = DatePickerTheme.defaults(context); final TextStyle? weekdayStyle = datePickerTheme.weekdayStyle ?? defaults.weekdayStyle; - final TextStyle? dayStyle = datePickerTheme.dayStyle ?? defaults.dayStyle; final int year = widget.displayedMonth.year; final int month = widget.displayedMonth.month; @@ -945,18 +937,6 @@ class _DayPickerState extends State<_DayPicker> { final int daysInMonth = DateUtils.getDaysInMonth(year, month); final int dayOffset = DateUtils.firstDayOffset(year, month, localizations); - T? effectiveValue<T>(T? Function(DatePickerThemeData? theme) getProperty) { - return getProperty(datePickerTheme) ?? getProperty(defaults); - } - - T? resolve<T>(MaterialStateProperty<T>? Function(DatePickerThemeData? theme) getProperty, Set<MaterialState> states) { - return effectiveValue( - (DatePickerThemeData? theme) { - return getProperty(theme)?.resolve(states); - }, - ); - } - final List<Widget> dayItems = _dayHeaders(weekdayStyle, localizations); // 1-based day of month, e.g. 1-31 for January, and 1-29 for February on // a leap year. @@ -973,71 +953,18 @@ class _DayPickerState extends State<_DayPicker> { (widget.selectableDayPredicate != null && !widget.selectableDayPredicate!(dayToBuild)); final bool isSelectedDay = DateUtils.isSameDay(widget.selectedDate, dayToBuild); final bool isToday = DateUtils.isSameDay(widget.currentDate, dayToBuild); - final String semanticLabelSuffix = isToday ? ', ${localizations.currentDateLabel}' : ''; - - final Set<MaterialState> states = <MaterialState>{ - if (isDisabled) MaterialState.disabled, - if (isSelectedDay) MaterialState.selected, - }; - - final MaterialStatesController statesController = _statesControllers.putIfAbsent(day, () => MaterialStatesController()); - statesController.value = states; - final Color? dayForegroundColor = resolve<Color?>((DatePickerThemeData? theme) => isToday ? theme?.todayForegroundColor : theme?.dayForegroundColor, states); - final Color? dayBackgroundColor = resolve<Color?>((DatePickerThemeData? theme) => isToday ? theme?.todayBackgroundColor : theme?.dayBackgroundColor, states); - final MaterialStateProperty<Color?> dayOverlayColor = MaterialStateProperty.resolveWith<Color?>( - (Set<MaterialState> states) => effectiveValue((DatePickerThemeData? theme) => theme?.dayOverlayColor?.resolve(states)), - ); - final BoxDecoration decoration = isToday - ? BoxDecoration( - color: dayBackgroundColor, - border: Border.fromBorderSide( - (datePickerTheme.todayBorder ?? defaults.todayBorder!) - .copyWith(color: dayForegroundColor) - ), - shape: BoxShape.circle, - ) - : BoxDecoration( - color: dayBackgroundColor, - shape: BoxShape.circle, - ); - - Widget dayWidget = Container( - decoration: decoration, - child: Center( - child: Text(localizations.formatDecimal(day), style: dayStyle?.apply(color: dayForegroundColor)), + dayItems.add( + _Day( + dayToBuild, + key: ValueKey<DateTime>(dayToBuild), + isDisabled: isDisabled, + isSelectedDay: isSelectedDay, + isToday: isToday, + onChanged: widget.onChanged, + focusNode: _dayFocusNodes[day - 1], ), ); - - if (isDisabled) { - dayWidget = ExcludeSemantics( - child: dayWidget, - ); - } else { - dayWidget = InkResponse( - focusNode: _dayFocusNodes[day - 1], - onTap: () => widget.onChanged(dayToBuild), - radius: _dayPickerRowHeight / 2 + 4, - statesController: statesController, - overlayColor: dayOverlayColor, - child: Semantics( - // We want the day of month to be spoken first irrespective of the - // locale-specific preferences or TextDirection. This is because - // an accessibility user is more likely to be interested in the - // day of month before the rest of the date, as they are looking - // for the day of month. To do that we prepend day of month to the - // formatted full date. - label: '${localizations.formatDecimal(day)}, ${localizations.formatFullDate(dayToBuild)}$semanticLabelSuffix', - // Set button to true to make the date selectable. - button: true, - selected: isSelectedDay, - excludeSemantics: true, - child: dayWidget, - ), - ); - } - - dayItems.add(dayWidget); } } @@ -1057,6 +984,122 @@ class _DayPickerState extends State<_DayPicker> { } } +class _Day extends StatefulWidget { + const _Day( + this.day, { + super.key, + required this.isDisabled, + required this.isSelectedDay, + required this.isToday, + required this.onChanged, + required this.focusNode, + }); + + final DateTime day; + final bool isDisabled; + final bool isSelectedDay; + final bool isToday; + final ValueChanged<DateTime> onChanged; + final FocusNode? focusNode; + + @override + State<_Day> createState() => _DayState(); +} + +class _DayState extends State<_Day> { + final MaterialStatesController _statesController = MaterialStatesController(); + + @override + Widget build(BuildContext context) { + final DatePickerThemeData defaults = DatePickerTheme.defaults(context); + final DatePickerThemeData datePickerTheme = DatePickerTheme.of(context); + final TextStyle? dayStyle = datePickerTheme.dayStyle ?? defaults.dayStyle; + T? effectiveValue<T>(T? Function(DatePickerThemeData? theme) getProperty) { + return getProperty(datePickerTheme) ?? getProperty(defaults); + } + + T? resolve<T>(MaterialStateProperty<T>? Function(DatePickerThemeData? theme) getProperty, Set<MaterialState> states) { + return effectiveValue( + (DatePickerThemeData? theme) { + return getProperty(theme)?.resolve(states); + }, + ); + } + + final MaterialLocalizations localizations = MaterialLocalizations.of(context); + final String semanticLabelSuffix = widget.isToday ? ', ${localizations.currentDateLabel}' : ''; + + final Set<MaterialState> states = <MaterialState>{ + if (widget.isDisabled) MaterialState.disabled, + if (widget.isSelectedDay) MaterialState.selected, + }; + + _statesController.value = states; + + final Color? dayForegroundColor = resolve<Color?>((DatePickerThemeData? theme) => widget.isToday ? theme?.todayForegroundColor : theme?.dayForegroundColor, states); + final Color? dayBackgroundColor = resolve<Color?>((DatePickerThemeData? theme) => widget.isToday ? theme?.todayBackgroundColor : theme?.dayBackgroundColor, states); + final MaterialStateProperty<Color?> dayOverlayColor = MaterialStateProperty.resolveWith<Color?>( + (Set<MaterialState> states) => effectiveValue((DatePickerThemeData? theme) => theme?.dayOverlayColor?.resolve(states)), + ); + final BoxDecoration decoration = widget.isToday + ? BoxDecoration( + color: dayBackgroundColor, + border: Border.fromBorderSide( + (datePickerTheme.todayBorder ?? defaults.todayBorder!) + .copyWith(color: dayForegroundColor) + ), + shape: BoxShape.circle, + ) + : BoxDecoration( + color: dayBackgroundColor, + shape: BoxShape.circle, + ); + + Widget dayWidget = Container( + decoration: decoration, + child: Center( + child: Text(localizations.formatDecimal(widget.day.day), style: dayStyle?.apply(color: dayForegroundColor)), + ), + ); + + if (widget.isDisabled) { + dayWidget = ExcludeSemantics( + child: dayWidget, + ); + } else { + dayWidget = InkResponse( + focusNode: widget.focusNode, + onTap: () => widget.onChanged(widget.day), + radius: _dayPickerRowHeight / 2 + 4, + statesController: _statesController, + overlayColor: dayOverlayColor, + child: Semantics( + // We want the day of month to be spoken first irrespective of the + // locale-specific preferences or TextDirection. This is because + // an accessibility user is more likely to be interested in the + // day of month before the rest of the date, as they are looking + // for the day of month. To do that we prepend day of month to the + // formatted full date. + label: '${localizations.formatDecimal(widget.day.day)}, ${localizations.formatFullDate(widget.day)}$semanticLabelSuffix', + // Set button to true to make the date selectable. + button: true, + selected: widget.isSelectedDay, + excludeSemantics: true, + child: dayWidget, + ), + ); + } + + return dayWidget; + } + + @override + void dispose() { + _statesController.dispose(); + super.dispose(); + } +} + class _DayPickerGridDelegate extends SliverGridDelegate { const _DayPickerGridDelegate(); From 4db47db177492eade1b0cf6199aa05a6e58b3f3d Mon Sep 17 00:00:00 2001 From: Justin McCandless <jmccandless@google.com> Date: Wed, 13 Sep 2023 20:39:58 -0700 Subject: [PATCH 1264/1547] LinkedText (Linkify) (#125927) New LinkedText widget and TextLinker class for easily adding hyperlinks to text. --- .../painting/text_linker/text_linker.0.dart | 213 +++++++++ .../painting/text_linker/text_linker.1.dart | 235 ++++++++++ .../widgets/linked_text/linked_text.0.dart | 75 ++++ .../widgets/linked_text/linked_text.1.dart | 85 ++++ .../widgets/linked_text/linked_text.2.dart | 92 ++++ .../widgets/linked_text/linked_text.3.dart | 184 ++++++++ .../text_linker/text_linker.0_test.dart | 36 ++ .../text_linker/text_linker.1_test.dart | 36 ++ .../linked_text/linked_text.0_test.dart | 27 ++ .../linked_text/linked_text.1_test.dart | 27 ++ .../linked_text/linked_text.2_test.dart | 27 ++ .../linked_text/linked_text.3_test.dart | 36 ++ packages/flutter/lib/painting.dart | 1 + .../flutter/lib/src/painting/text_linker.dart | 422 ++++++++++++++++++ .../flutter/lib/src/widgets/linked_text.dart | 334 ++++++++++++++ packages/flutter/lib/widgets.dart | 1 + .../test/painting/text_linker_test.dart | 322 +++++++++++++ .../test/widgets/linked_text_test.dart | 367 +++++++++++++++ 18 files changed, 2520 insertions(+) create mode 100644 examples/api/lib/painting/text_linker/text_linker.0.dart create mode 100644 examples/api/lib/painting/text_linker/text_linker.1.dart create mode 100644 examples/api/lib/widgets/linked_text/linked_text.0.dart create mode 100644 examples/api/lib/widgets/linked_text/linked_text.1.dart create mode 100644 examples/api/lib/widgets/linked_text/linked_text.2.dart create mode 100644 examples/api/lib/widgets/linked_text/linked_text.3.dart create mode 100644 examples/api/test/painting/text_linker/text_linker.0_test.dart create mode 100644 examples/api/test/painting/text_linker/text_linker.1_test.dart create mode 100644 examples/api/test/widgets/linked_text/linked_text.0_test.dart create mode 100644 examples/api/test/widgets/linked_text/linked_text.1_test.dart create mode 100644 examples/api/test/widgets/linked_text/linked_text.2_test.dart create mode 100644 examples/api/test/widgets/linked_text/linked_text.3_test.dart create mode 100644 packages/flutter/lib/src/painting/text_linker.dart create mode 100644 packages/flutter/lib/src/widgets/linked_text.dart create mode 100644 packages/flutter/test/painting/text_linker_test.dart create mode 100644 packages/flutter/test/widgets/linked_text_test.dart diff --git a/examples/api/lib/painting/text_linker/text_linker.0.dart b/examples/api/lib/painting/text_linker/text_linker.0.dart new file mode 100644 index 0000000000000..15bcd93b537a2 --- /dev/null +++ b/examples/api/lib/painting/text_linker/text_linker.0.dart @@ -0,0 +1,213 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// This example demonstrates highlighting both URLs and Twitter handles with +// different actions and different styles. + +void main() { + runApp(const TextLinkerApp()); +} + +class TextLinkerApp extends StatelessWidget { + const TextLinkerApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter Link Twitter Handle Demo'), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({ + super.key, + required this.title + }); + + final String title; + static const String _text = '@FlutterDev is our Twitter account, or find us at www.flutter.dev'; + + void _handleTapTwitterHandle(BuildContext context, String linkString) { + final String handleWithoutAt = linkString.substring(1); + final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; + final Uri? uri = Uri.tryParse(twitterUriString); + if (uri == null) { + throw Exception('Failed to parse $twitterUriString.'); + } + _showDialog(context, uri); + } + + void _handleTapUrl(BuildContext context, String urlText) { + final Uri? uri = Uri.tryParse(urlText); + if (uri == null) { + throw Exception('Failed to parse $urlText.'); + } + _showDialog(context, uri); + } + + void _showDialog(BuildContext context, Uri uri) { + // A package like url_launcher would be useful for actually opening the URL + // here instead of just showing a dialog. + Navigator.of(context).push( + DialogRoute<void>( + context: context, + builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Builder( + builder: (BuildContext context) { + return SelectionArea( + child: _TwitterAndUrlLinkedText( + text: _text, + onTapUrl: (String urlString) => _handleTapUrl(context, urlString), + onTapTwitterHandle: (String handleString) => _handleTapTwitterHandle(context, handleString), + ), + ); + }, + ), + ), + ); + } +} + +class _TwitterAndUrlLinkedText extends StatefulWidget { + const _TwitterAndUrlLinkedText({ + required this.text, + required this.onTapUrl, + required this.onTapTwitterHandle, + }); + + final String text; + final ValueChanged<String> onTapUrl; + final ValueChanged<String> onTapTwitterHandle; + + @override + State<_TwitterAndUrlLinkedText> createState() => _TwitterAndUrlLinkedTextState(); +} + +class _TwitterAndUrlLinkedTextState extends State<_TwitterAndUrlLinkedText> { + final List<GestureRecognizer> _recognizers = <GestureRecognizer>[]; + late Iterable<InlineSpan> _linkedSpans; + late final List<TextLinker> _textLinkers; + + final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); + + void _disposeRecognizers() { + for (final GestureRecognizer recognizer in _recognizers) { + recognizer.dispose(); + } + _recognizers.clear(); + } + + void _linkSpans() { + _disposeRecognizers(); + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + <TextSpan>[TextSpan(text: widget.text)], + _textLinkers, + ); + _linkedSpans = linkedSpans; + } + + @override + void initState() { + super.initState(); + + _textLinkers = <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () => widget.onTapUrl(linkString); + _recognizers.add(recognizer); + return _MyInlineLinkSpan( + text: displayString, + color: const Color(0xff0000ee), + recognizer: recognizer, + ); + }, + ), + TextLinker( + regExp: _twitterHandleRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () => widget.onTapTwitterHandle(linkString); + _recognizers.add(recognizer); + return _MyInlineLinkSpan( + text: displayString, + color: const Color(0xff00aaaa), + recognizer: recognizer, + ); + }, + ), + ]; + + _linkSpans(); + } + + @override + void didUpdateWidget(_TwitterAndUrlLinkedText oldWidget) { + super.didUpdateWidget(oldWidget); + + if (widget.text != oldWidget.text + || widget.onTapUrl != oldWidget.onTapUrl + || widget.onTapTwitterHandle != oldWidget.onTapTwitterHandle) { + _linkSpans(); + } + } + + @override + void dispose() { + _disposeRecognizers(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_linkedSpans.isEmpty) { + return const SizedBox.shrink(); + } + + return Text.rich( + TextSpan( + style: DefaultTextStyle.of(context).style, + children: _linkedSpans.toList(), + ), + ); + } +} + +class _MyInlineLinkSpan extends TextSpan { + _MyInlineLinkSpan({ + required String text, + required Color color, + required super.recognizer, + }) : super( + style: TextStyle( + color: color, + decorationColor: color, + decoration: TextDecoration.underline, + ), + mouseCursor: SystemMouseCursors.click, + text: text, + ); +} diff --git a/examples/api/lib/painting/text_linker/text_linker.1.dart b/examples/api/lib/painting/text_linker/text_linker.1.dart new file mode 100644 index 0000000000000..203a926cdd62f --- /dev/null +++ b/examples/api/lib/painting/text_linker/text_linker.1.dart @@ -0,0 +1,235 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// This example demonstrates creating links in a TextSpan tree instead of a flat +// String. + +void main() { + runApp(const TextLinkerApp()); +} + +class TextLinkerApp extends StatelessWidget { + const TextLinkerApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter TextLinker Span Demo'), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({ + super.key, + required this.title + }); + + final String title; + + void _handleTapTwitterHandle(BuildContext context, String linkString) { + final String handleWithoutAt = linkString.substring(1); + final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; + final Uri? uri = Uri.tryParse(twitterUriString); + if (uri == null) { + throw Exception('Failed to parse $twitterUriString.'); + } + _showDialog(context, uri); + } + + void _handleTapUrl(BuildContext context, String urlText) { + final Uri? uri = Uri.tryParse(urlText); + if (uri == null) { + throw Exception('Failed to parse $urlText.'); + } + _showDialog(context, uri); + } + + void _showDialog(BuildContext context, Uri uri) { + // A package like url_launcher would be useful for actually opening the URL + // here instead of just showing a dialog. + Navigator.of(context).push( + DialogRoute<void>( + context: context, + builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Builder( + builder: (BuildContext context) { + return SelectionArea( + child: _TwitterAndUrlLinkedText( + spans: <InlineSpan>[ + TextSpan( + text: '@FlutterDev is our Twitter, or find us at www.', + style: DefaultTextStyle.of(context).style, + children: const <InlineSpan>[ + TextSpan( + style: TextStyle( + fontWeight: FontWeight.w800, + ), + text: 'flutter', + ), + ], + ), + TextSpan( + text: '.dev', + style: DefaultTextStyle.of(context).style, + ), + ], + onTapUrl: (String urlString) => _handleTapUrl(context, urlString), + onTapTwitterHandle: (String handleString) => _handleTapTwitterHandle(context, handleString), + ), + ); + }, + ), + ), + ); + } +} + +class _TwitterAndUrlLinkedText extends StatefulWidget { + const _TwitterAndUrlLinkedText({ + required this.spans, + required this.onTapUrl, + required this.onTapTwitterHandle, + }); + + final List<InlineSpan> spans; + final ValueChanged<String> onTapUrl; + final ValueChanged<String> onTapTwitterHandle; + + @override + State<_TwitterAndUrlLinkedText> createState() => _TwitterAndUrlLinkedTextState(); +} + +class _TwitterAndUrlLinkedTextState extends State<_TwitterAndUrlLinkedText> { + final List<GestureRecognizer> _recognizers = <GestureRecognizer>[]; + late Iterable<InlineSpan> _linkedSpans; + late final List<TextLinker> _textLinkers; + + final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); + + void _disposeRecognizers() { + for (final GestureRecognizer recognizer in _recognizers) { + recognizer.dispose(); + } + _recognizers.clear(); + } + + void _linkSpans() { + _disposeRecognizers(); + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + widget.spans, + _textLinkers, + ); + _linkedSpans = linkedSpans; + } + + @override + void initState() { + super.initState(); + + _textLinkers = <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + // The linkString always contains the full matched text, so that's + // what should be linked to. + ..onTap = () => widget.onTapUrl(linkString); + _recognizers.add(recognizer); + return _MyInlineLinkSpan( + // The displayString contains only the portion of the matched text + // in a given TextSpan. For example, the bold "flutter" text in + // the overall "www.flutter.dev" URL is in its own TextSpan with its + // bold styling. linkBuilder is called separately for each part. + text: displayString, + color: const Color(0xff0000ee), + recognizer: recognizer, + ); + }, + ), + TextLinker( + regExp: _twitterHandleRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () => widget.onTapTwitterHandle(linkString); + _recognizers.add(recognizer); + return _MyInlineLinkSpan( + text: displayString, + color: const Color(0xff00aaaa), + recognizer: recognizer, + ); + }, + ), + ]; + + _linkSpans(); + } + + @override + void didUpdateWidget(_TwitterAndUrlLinkedText oldWidget) { + super.didUpdateWidget(oldWidget); + + if (widget.spans != oldWidget.spans + || widget.onTapUrl != oldWidget.onTapUrl + || widget.onTapTwitterHandle != oldWidget.onTapTwitterHandle) { + _linkSpans(); + } + } + + @override + void dispose() { + _disposeRecognizers(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (_linkedSpans.isEmpty) { + return const SizedBox.shrink(); + } + + return Text.rich( + TextSpan( + style: DefaultTextStyle.of(context).style, + children: _linkedSpans.toList(), + ), + ); + } +} + +class _MyInlineLinkSpan extends TextSpan { + _MyInlineLinkSpan({ + required String text, + required Color color, + required super.recognizer, + }) : super( + style: TextStyle( + color: color, + decorationColor: color, + decoration: TextDecoration.underline, + ), + mouseCursor: SystemMouseCursors.click, + text: text, + ); +} diff --git a/examples/api/lib/widgets/linked_text/linked_text.0.dart b/examples/api/lib/widgets/linked_text/linked_text.0.dart new file mode 100644 index 0000000000000..e9c3b5cdaff50 --- /dev/null +++ b/examples/api/lib/widgets/linked_text/linked_text.0.dart @@ -0,0 +1,75 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +// This example demonstrates using LinkedText to make URLs open on tap. + +void main() { + runApp(const LinkedTextApp()); +} + +class LinkedTextApp extends StatelessWidget { + const LinkedTextApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter Link Demo'), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({ + super.key, + required this.title, + }); + + final String title; + static const String _text = 'Check out https://www.flutter.dev, or maybe just flutter.dev or www.flutter.dev.'; + + void _handleTapUri(BuildContext context, Uri uri) { + // A package like url_launcher would be useful for actually opening the URL + // here instead of just showing a dialog. + Navigator.of(context).push( + DialogRoute<void>( + context: context, + builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Builder( + builder: (BuildContext context) { + return SelectionArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: <Widget>[ + LinkedText( + text: _text, + onTapUri: (Uri uri) => _handleTapUri(context, uri), + ), + ], + ), + ); + }, + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/linked_text/linked_text.1.dart b/examples/api/lib/widgets/linked_text/linked_text.1.dart new file mode 100644 index 0000000000000..48c4df841ff1e --- /dev/null +++ b/examples/api/lib/widgets/linked_text/linked_text.1.dart @@ -0,0 +1,85 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +// This example demonstrates highlighting and linking Twitter handles. + +void main() { + runApp(const LinkedTextApp()); +} + +class LinkedTextApp extends StatelessWidget { + const LinkedTextApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Flutter Link Twitter Handle Demo'), + ); + } +} + +class MyHomePage extends StatelessWidget { + MyHomePage({ + super.key, + required this.title + }); + + final String title; + static const String _text = 'Please check out @FlutterDev on Twitter for the latest.'; + + void _handleTapTwitterHandle(BuildContext context, String linkText) { + final String handleWithoutAt = linkText.substring(1); + final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; + final Uri? uri = Uri.tryParse(twitterUriString); + if (uri == null) { + throw Exception('Failed to parse $twitterUriString.'); + } + + // A package like url_launcher would be useful for actually opening the URL + // here instead of just showing a dialog. + Navigator.of(context).push( + DialogRoute<void>( + context: context, + builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), + ), + ); + } + + final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Builder( + builder: (BuildContext context) { + return SelectionArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: <Widget>[ + LinkedText.regExp( + text: _text, + regExp: _twitterHandleRegExp, + onTap: (String twitterHandleString) => _handleTapTwitterHandle(context, twitterHandleString), + ), + ], + ), + ); + }, + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/linked_text/linked_text.2.dart b/examples/api/lib/widgets/linked_text/linked_text.2.dart new file mode 100644 index 0000000000000..a19a07e4d85e6 --- /dev/null +++ b/examples/api/lib/widgets/linked_text/linked_text.2.dart @@ -0,0 +1,92 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +// This example demonstrates highlighting URLs in a TextSpan tree instead of a +// flat String. + +void main() { + runApp(const LinkedTextApp()); +} + +class LinkedTextApp extends StatelessWidget { + const LinkedTextApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter LinkedText.spans Demo'), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({ + super.key, + required this.title, + }); + + final String title; + + void _onTapUri (BuildContext context, Uri uri) { + // A package like url_launcher would be useful for actually opening the URL + // here instead of just showing a dialog. + Navigator.of(context).push( + DialogRoute<void>( + context: context, + builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Builder( + builder: (BuildContext context) { + return SelectionArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: <Widget>[ + LinkedText( + onTapUri: (Uri uri) => _onTapUri(context, uri), + spans: <InlineSpan>[ + TextSpan( + text: 'Check out https://www.', + style: DefaultTextStyle.of(context).style, + children: const <InlineSpan>[ + TextSpan( + style: TextStyle( + fontWeight: FontWeight.w800, + ), + text: 'flutter', + ), + ], + ), + TextSpan( + text: '.dev!', + style: DefaultTextStyle.of(context).style, + ), + ], + ), + ], + ), + ); + }, + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/linked_text/linked_text.3.dart b/examples/api/lib/widgets/linked_text/linked_text.3.dart new file mode 100644 index 0000000000000..72db9ec91358e --- /dev/null +++ b/examples/api/lib/widgets/linked_text/linked_text.3.dart @@ -0,0 +1,184 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +// This example demonstrates highlighting both URLs and Twitter handles with +// different actions and different styles. + +void main() { + runApp(const LinkedTextApp()); +} + +class LinkedTextApp extends StatelessWidget { + const LinkedTextApp({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter Link Twitter Handle Demo'), + ); + } +} + +class MyHomePage extends StatelessWidget { + const MyHomePage({ + super.key, + required this.title + }); + + final String title; + static const String _text = '@FlutterDev is our Twitter account, or find us at www.flutter.dev'; + + void _handleTapTwitterHandle(BuildContext context, String linkText) { + final String handleWithoutAt = linkText.substring(1); + final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; + final Uri? uri = Uri.tryParse(twitterUriString); + if (uri == null) { + throw Exception('Failed to parse $twitterUriString.'); + } + _showDialog(context, uri); + } + + void _handleTapUrl(BuildContext context, String urlText) { + final Uri? uri = Uri.tryParse(urlText); + if (uri == null) { + throw Exception('Failed to parse $urlText.'); + } + _showDialog(context, uri); + } + + void _showDialog(BuildContext context, Uri uri) { + // A package like url_launcher would be useful for actually opening the URL + // here instead of just showing a dialog. + Navigator.of(context).push( + DialogRoute<void>( + context: context, + builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(title), + ), + body: Center( + child: Builder( + builder: (BuildContext context) { + return SelectionArea( + child: _TwitterAndUrlLinkedText( + text: _text, + onTapUrl: (String urlString) => _handleTapUrl(context, urlString), + onTapTwitterHandle: (String handleString) => _handleTapTwitterHandle(context, handleString), + ), + ); + }, + ), + ), + ); + } +} + +class _TwitterAndUrlLinkedText extends StatefulWidget { + const _TwitterAndUrlLinkedText({ + required this.text, + required this.onTapUrl, + required this.onTapTwitterHandle, + }); + + final String text; + final ValueChanged<String> onTapUrl; + final ValueChanged<String> onTapTwitterHandle; + + @override + State<_TwitterAndUrlLinkedText> createState() => _TwitterAndUrlLinkedTextState(); +} + +class _TwitterAndUrlLinkedTextState extends State<_TwitterAndUrlLinkedText> { + final List<GestureRecognizer> _recognizers = <GestureRecognizer>[]; + late final List<TextLinker> _textLinkers; + + final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); + + void _disposeRecognizers() { + for (final GestureRecognizer recognizer in _recognizers) { + recognizer.dispose(); + } + _recognizers.clear(); + } + + @override + void initState() { + super.initState(); + + _textLinkers = <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayText, String linkText) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () => widget.onTapUrl(linkText); + _recognizers.add(recognizer); + return _MyInlineLinkSpan( + text: displayText, + color: const Color(0xff0000ee), + recognizer: recognizer, + ); + }, + ), + TextLinker( + regExp: _twitterHandleRegExp, + linkBuilder: (String displayText, String linkText) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () => widget.onTapTwitterHandle(linkText); + _recognizers.add(recognizer); + return _MyInlineLinkSpan( + text: displayText, + color: const Color(0xff00aaaa), + recognizer: recognizer, + ); + }, + ), + ]; + } + + @override + void dispose() { + _disposeRecognizers(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return LinkedText.textLinkers( + text: widget.text, + textLinkers: _textLinkers, + ); + } +} + +class _MyInlineLinkSpan extends TextSpan { + _MyInlineLinkSpan({ + required String text, + required Color color, + required super.recognizer, + }) : super( + style: TextStyle( + color: color, + decorationColor: color, + decoration: TextDecoration.underline, + ), + mouseCursor: SystemMouseCursors.click, + text: text, + ); +} diff --git a/examples/api/test/painting/text_linker/text_linker.0_test.dart b/examples/api/test/painting/text_linker/text_linker.0_test.dart new file mode 100644 index 0000000000000..a9ef1fe947a19 --- /dev/null +++ b/examples/api/test/painting/text_linker/text_linker.0_test.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/painting/text_linker/text_linker.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('can tap different link types with different results', (WidgetTester tester) async { + await tester.pumpWidget( + const example.TextLinkerApp(), + ); + + final Finder textFinder = find.descendant( + of: find.byType(SelectionArea), + matching: find.byType(Text), + ); + expect(textFinder, findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getTopLeft(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); + + await tester.tapAt(tester.getTopLeft(find.byType(Scaffold))); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getCenter(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: www.flutter.dev'), findsOneWidget); + }); +} diff --git a/examples/api/test/painting/text_linker/text_linker.1_test.dart b/examples/api/test/painting/text_linker/text_linker.1_test.dart new file mode 100644 index 0000000000000..3d32fe9fea155 --- /dev/null +++ b/examples/api/test/painting/text_linker/text_linker.1_test.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/painting/text_linker/text_linker.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('can tap different link types with different results', (WidgetTester tester) async { + await tester.pumpWidget( + const example.TextLinkerApp(), + ); + + final Finder textFinder = find.descendant( + of: find.byType(SelectionArea), + matching: find.byType(Text), + ); + expect(textFinder, findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getTopLeft(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); + + await tester.tapAt(tester.getTopLeft(find.byType(Scaffold))); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getCenter(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: www.flutter.dev'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/linked_text/linked_text.0_test.dart b/examples/api/test/widgets/linked_text/linked_text.0_test.dart new file mode 100644 index 0000000000000..d397d94f790d9 --- /dev/null +++ b/examples/api/test/widgets/linked_text/linked_text.0_test.dart @@ -0,0 +1,27 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/linked_text/linked_text.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('tapping a link shows a dialog with the tapped uri', (WidgetTester tester) async { + await tester.pumpWidget( + const example.LinkedTextApp(), + ); + + final Finder textFinder = find.descendant( + of: find.byType(LinkedText), + matching: find.byType(RichText), + ); + expect(textFinder, findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getCenter(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: https://www.flutter.dev'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/linked_text/linked_text.1_test.dart b/examples/api/test/widgets/linked_text/linked_text.1_test.dart new file mode 100644 index 0000000000000..7ba5b7ce945cd --- /dev/null +++ b/examples/api/test/widgets/linked_text/linked_text.1_test.dart @@ -0,0 +1,27 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/linked_text/linked_text.1.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('tapping a Twitter handle shows a dialog with the uri of the user', (WidgetTester tester) async { + await tester.pumpWidget( + const example.LinkedTextApp(), + ); + + final Finder textFinder = find.descendant( + of: find.byType(LinkedText), + matching: find.byType(RichText), + ); + expect(textFinder, findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getCenter(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/linked_text/linked_text.2_test.dart b/examples/api/test/widgets/linked_text/linked_text.2_test.dart new file mode 100644 index 0000000000000..1d5f97f90a4b7 --- /dev/null +++ b/examples/api/test/widgets/linked_text/linked_text.2_test.dart @@ -0,0 +1,27 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/linked_text/linked_text.2.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('can tap links generated from TextSpans', (WidgetTester tester) async { + await tester.pumpWidget( + const example.LinkedTextApp(), + ); + + final Finder textFinder = find.descendant( + of: find.byType(LinkedText), + matching: find.byType(RichText), + ); + expect(textFinder, findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getCenter(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: https://www.flutter.dev'), findsOneWidget); + }); +} diff --git a/examples/api/test/widgets/linked_text/linked_text.3_test.dart b/examples/api/test/widgets/linked_text/linked_text.3_test.dart new file mode 100644 index 0000000000000..4911cb8334110 --- /dev/null +++ b/examples/api/test/widgets/linked_text/linked_text.3_test.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/widgets/linked_text/linked_text.3.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('can tap different link types with different results', (WidgetTester tester) async { + await tester.pumpWidget( + const example.LinkedTextApp(), + ); + + final Finder textFinder = find.descendant( + of: find.byType(SelectionArea), + matching: find.byType(Text), + ); + expect(textFinder, findsOneWidget); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getTopLeft(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); + + await tester.tapAt(tester.getTopLeft(find.byType(Scaffold))); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsNothing); + + await tester.tapAt(tester.getCenter(textFinder)); + await tester.pumpAndSettle(); + expect(find.byType(AlertDialog), findsOneWidget); + expect(find.text('You tapped: www.flutter.dev'), findsOneWidget); + }); +} diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart index 2fa89c23cf8bc..952763378515e 100644 --- a/packages/flutter/lib/painting.dart +++ b/packages/flutter/lib/painting.dart @@ -59,6 +59,7 @@ export 'src/painting/shape_decoration.dart'; export 'src/painting/stadium_border.dart'; export 'src/painting/star_border.dart'; export 'src/painting/strut_style.dart'; +export 'src/painting/text_linker.dart'; export 'src/painting/text_painter.dart'; export 'src/painting/text_scaler.dart'; export 'src/painting/text_span.dart'; diff --git a/packages/flutter/lib/src/painting/text_linker.dart b/packages/flutter/lib/src/painting/text_linker.dart new file mode 100644 index 0000000000000..4684be30fb083 --- /dev/null +++ b/packages/flutter/lib/src/painting/text_linker.dart @@ -0,0 +1,422 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math' as math; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; + +import 'inline_span.dart'; +import 'text_span.dart'; + +/// Signature for a function that builds an [InlineSpan] link. +/// +/// The link displays [displayString] and links to [linkString] when tapped. +/// These are distinct because sometimes a link may be split across multiple +/// [TextSpan]s. +/// +/// For example, consider the [TextSpan]s +/// `[TextSpan(text: 'http://'), TextSpan(text: 'google.com'), TextSpan(text: '/')]`. +/// This builder would be called three times, with the following parameters: +/// +/// 1. `displayString: 'http://', linkString: 'http://google.com/'` +/// 2. `displayString: 'google.com', linkString: 'http://google.com/'` +/// 3. `displayString: '/', linkString: 'http://google.com/'` +/// +/// {@template flutter.painting.LinkBuilder.recognizer} +/// It's necessary for the owning widget to manage the lifecycle of any +/// [GestureRecognizer]s created in this function, such as for handling a tap on +/// the link. See [TextSpan.recognizer] for more. +/// {@endtemplate} +/// +/// {@tool dartpad} +/// This example shows how to use [TextLinker] to link both URLs and Twitter +/// handles in a [TextSpan] tree. It also illustrates the difference between +/// `displayString` and `linkString`. +/// +/// ** See code in examples/api/lib/painting/text_linker/text_linker.1.dart ** +/// {@end-tool} +typedef InlineLinkBuilder = InlineSpan Function( + String displayString, + String linkString, +); + +/// Specifies a way to find and style parts of some text. +/// +/// [TextLinker]s can be applied to some text using the [linkSpans] method. +/// +/// {@tool dartpad} +/// This example shows how to use [TextLinker] to link both URLs and Twitter +/// handles in the same text. +/// +/// ** See code in examples/api/lib/painting/text_linker/text_linker.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This example shows how to use [TextLinker] to link both URLs and Twitter +/// handles in a [TextSpan] tree instead of a flat string. +/// +/// ** See code in examples/api/lib/painting/text_linker/text_linker.1.dart ** +/// {@end-tool} +/// +/// See also: +/// +/// * [LinkedText.textLinkers], which uses [TextLinker]s to allow full control +/// over matching and building different types of links. +/// * [LinkedText.new], which is simpler than using [TextLinker] and +/// automatically manages the lifecycle of any [GestureRecognizer]s. +class TextLinker { + /// Creates an instance of [TextLinker] with a [RegExp] and an [InlineLinkBuilder + /// [InlineLinkBuilder]. + /// + /// Does not manage the lifecycle of any [GestureRecognizer]s created in the + /// [InlineLinkBuilder], so it's the responsibility of the caller to do so. + /// See [TextSpan.recognizer] for more. + TextLinker({ + required this.regExp, + required this.linkBuilder, + }); + + /// Builds an [InlineSpan] to display the text that it's passed. + /// + /// {@macro flutter.painting.LinkBuilder.recognizer} + final InlineLinkBuilder linkBuilder; + + /// Matches text that should be turned into a link with [linkBuilder]. + final RegExp regExp; + + /// Applies the given [TextLinker]s to the given [InlineSpan]s and returns the + /// new resulting spans and any created [GestureRecognizer]s. + static Iterable<InlineSpan> linkSpans(Iterable<InlineSpan> spans, Iterable<TextLinker> textLinkers) { + final _LinkedSpans linkedSpans = _LinkedSpans( + spans: spans, + textLinkers: textLinkers, + ); + return linkedSpans.linkedSpans; + } + + // Turns all matches from the regExp into a list of TextRanges. + static Iterable<TextRange> _textRangesFromText(String text, RegExp regExp) { + final Iterable<RegExpMatch> matches = regExp.allMatches(text); + return matches.map((RegExpMatch match) { + return TextRange( + start: match.start, + end: match.end, + ); + }); + } + + /// Apply this [TextLinker] to a [String]. + Iterable<_TextLinkerMatch> _link(String text) { + final Iterable<TextRange> textRanges = _textRangesFromText(text, regExp); + return textRanges.map((TextRange textRange) { + return _TextLinkerMatch( + textRange: textRange, + linkBuilder: linkBuilder, + linkString: text.substring(textRange.start, textRange.end), + ); + }); + } + + @override + String toString() => '${objectRuntimeType(this, 'TextLinker')}($regExp)'; +} + +/// A matched replacement on some string. +/// +/// Produced by applying a [TextLinker]'s [RegExp] to a string. +class _TextLinkerMatch { + _TextLinkerMatch({ + required this.textRange, + required this.linkBuilder, + required this.linkString, + }) : assert(textRange.end - textRange.start == linkString.length); + + final InlineLinkBuilder linkBuilder; + final TextRange textRange; + + /// The string that [textRange] matches. + final String linkString; + + /// Get all [_TextLinkerMatch]s obtained from applying the given + /// `textLinker`s with the given `text`. + static List<_TextLinkerMatch> fromTextLinkers(Iterable<TextLinker> textLinkers, String text) { + return textLinkers + .fold<List<_TextLinkerMatch>>( + <_TextLinkerMatch>[], + (List<_TextLinkerMatch> previousValue, TextLinker value) { + return previousValue..addAll(value._link(text)); + }); + } + + @override + String toString() => '${objectRuntimeType(this, '_TextLinkerMatch')}($textRange, $linkBuilder, $linkString)'; +} + +/// Used to cache information about a span's recursive text. +/// +/// Avoids repeatedly calling [TextSpan.toPlainText]. +class _TextCache { + factory _TextCache({ + required InlineSpan span, + }) { + if (span is! TextSpan) { + return _TextCache._( + text: '', + lengths: <InlineSpan, int>{span: 0}, + ); + } + + _TextCache childrenTextCache = _TextCache._empty(); + for (final InlineSpan child in span.children ?? <InlineSpan>[]) { + final _TextCache childTextCache = _TextCache( + span: child, + ); + childrenTextCache = childrenTextCache._merge(childTextCache); + } + + final String text = (span.text ?? '') + childrenTextCache.text; + return _TextCache._( + text: text, + lengths: <InlineSpan, int>{ + span: text.length, + ...childrenTextCache._lengths, + }, + ); + } + + factory _TextCache.fromMany({ + required Iterable<InlineSpan> spans, + }) { + _TextCache textCache = _TextCache._empty(); + for (final InlineSpan span in spans) { + final _TextCache spanTextCache = _TextCache( + span: span, + ); + textCache = textCache._merge(spanTextCache); + } + return textCache; + } + + _TextCache._empty( + ) : text = '', + _lengths = <InlineSpan, int>{}; + + const _TextCache._({ + required this.text, + required Map<InlineSpan, int> lengths, + }) : _lengths = lengths; + + /// The flattened text of all spans in the span tree. + final String text; + + /// A [Map] containing the lengths of all spans in the span tree. + /// + /// The length is defined as the length of the flattened text at the point in + /// the tree where the node resides. + /// + /// The length of [text] is the length of the root node in [_lengths]. + final Map<InlineSpan, int> _lengths; + + /// Merges the given _TextCache with this one by appending it to the end. + /// + /// Returns a new _TextCache and makes no modifications to either passed in. + _TextCache _merge(_TextCache other) { + return _TextCache._( + text: text + other.text, + lengths: Map<InlineSpan, int>.from(_lengths)..addAll(other._lengths), + ); + } + + int? getLength(InlineSpan span) => _lengths[span]; + + @override + String toString() => '${objectRuntimeType(this, '_TextCache')}($text, $_lengths)'; +} + +/// Signature for the output of linking an InlineSpan to some +/// _TextLinkerMatches. +typedef _LinkSpanRecursion = ( + /// The output of linking the input InlineSpan. + InlineSpan linkedSpan, + /// The provided _TextLinkerMatches, but with those completely used during + /// linking removed. + Iterable<_TextLinkerMatch> unusedTextLinkerMatches, +); + +/// Signature for the output of linking a List of InlineSpans to some +/// _TextLinkerMatches. +typedef _LinkSpansRecursion = ( + /// The output of linking the input InlineSpans. + Iterable<InlineSpan> linkedSpans, + /// The provided _TextLinkerMatches, but with those completely used during + /// linking removed. + Iterable<_TextLinkerMatch> unusedTextLinkerMatches, +); + +/// Applies some [TextLinker]s to some [InlineSpan]s and produces a new list of +/// [linkedSpans] as well as the [recognizers] created for each generated link. +class _LinkedSpans { + factory _LinkedSpans({ + required Iterable<InlineSpan> spans, + required Iterable<TextLinker> textLinkers, + }) { + // Flatten the spans and store all string lengths, so that matches across + // span boundaries can be matched in the flat string. This is calculated + // once in the beginning to avoid recomputing. + final _TextCache textCache = _TextCache.fromMany(spans: spans); + + final Iterable<_TextLinkerMatch> textLinkerMatches = + _cleanTextLinkerMatches( + _TextLinkerMatch.fromTextLinkers(textLinkers, textCache.text), + ); + + final (Iterable<InlineSpan> linkedSpans, Iterable<_TextLinkerMatch> _) = + _linkSpansRecurse( + spans, + textCache, + textLinkerMatches, + ); + + return _LinkedSpans._( + linkedSpans: linkedSpans, + ); + } + + const _LinkedSpans._({ + required this.linkedSpans, + }); + + final Iterable<InlineSpan> linkedSpans; + + static List<_TextLinkerMatch> _cleanTextLinkerMatches(Iterable<_TextLinkerMatch> textLinkerMatches) { + final List<_TextLinkerMatch> nextTextLinkerMatches = textLinkerMatches.toList(); + + // Sort by start. + nextTextLinkerMatches.sort((_TextLinkerMatch a, _TextLinkerMatch b) { + return a.textRange.start.compareTo(b.textRange.start); + }); + + // Validate that there are no overlapping matches. + int lastEnd = 0; + for (final _TextLinkerMatch textLinkerMatch in nextTextLinkerMatches) { + if (textLinkerMatch.textRange.start < lastEnd) { + throw ArgumentError('Matches must not overlap. Overlapping text was "${textLinkerMatch.linkString}" located at ${textLinkerMatch.textRange.start}-${textLinkerMatch.textRange.end}.'); + } + lastEnd = textLinkerMatch.textRange.end; + } + + // Remove empty ranges. + nextTextLinkerMatches.removeWhere((_TextLinkerMatch textLinkerMatch) { + return textLinkerMatch.textRange.start == textLinkerMatch.textRange.end; + }); + + return nextTextLinkerMatches; + } + + // `index` is the index of the start of `span` in the overall flattened tree + // string. + static _LinkSpansRecursion _linkSpansRecurse(Iterable<InlineSpan> spans, _TextCache textCache, Iterable<_TextLinkerMatch> textLinkerMatches, [int index = 0]) { + final List<InlineSpan> output = <InlineSpan>[]; + Iterable<_TextLinkerMatch> nextTextLinkerMatches = textLinkerMatches; + int nextIndex = index; + for (final InlineSpan span in spans) { + final (InlineSpan childSpan, Iterable<_TextLinkerMatch> childTextLinkerMatches) = _linkSpanRecurse( + span, + textCache, + nextTextLinkerMatches, + nextIndex, + ); + output.add(childSpan); + nextTextLinkerMatches = childTextLinkerMatches; + nextIndex += textCache.getLength(span)!; + } + + return (output, nextTextLinkerMatches); + } + + // `index` is the index of the start of `span` in the overall flattened tree + // string. + static _LinkSpanRecursion _linkSpanRecurse(InlineSpan span, _TextCache textCache, Iterable<_TextLinkerMatch> textLinkerMatches, [int index = 0]) { + if (span is! TextSpan) { + return (span, textLinkerMatches); + } + + final List<InlineSpan> nextChildren = <InlineSpan>[]; + List<_TextLinkerMatch> nextTextLinkerMatches = <_TextLinkerMatch>[...textLinkerMatches]; + int lastLinkEnd = index; + if (span.text?.isNotEmpty ?? false) { + final int textEnd = index + span.text!.length; + for (final _TextLinkerMatch textLinkerMatch in textLinkerMatches) { + if (textLinkerMatch.textRange.start >= textEnd) { + // Because ranges is ordered, there are no more relevant ranges for this + // text. + break; + } + if (textLinkerMatch.textRange.end <= index) { + // This range ends before this span and is therefore irrelevant to it. + // It should have been removed from ranges. + assert(false, 'Invalid ranges.'); + nextTextLinkerMatches.removeAt(0); + continue; + } + if (textLinkerMatch.textRange.start > index) { + // Add the unlinked text before the range. + nextChildren.add(TextSpan( + text: span.text!.substring( + lastLinkEnd - index, + textLinkerMatch.textRange.start - index, + ), + )); + } + // Add the link itself. + final int linkStart = math.max(textLinkerMatch.textRange.start, index); + lastLinkEnd = math.min(textLinkerMatch.textRange.end, textEnd); + final InlineSpan nextChild = textLinkerMatch.linkBuilder( + span.text!.substring(linkStart - index, lastLinkEnd - index), + textLinkerMatch.linkString, + ); + nextChildren.add(nextChild); + if (textLinkerMatch.textRange.end > textEnd) { + // If we only partially used this range, keep it in nextRanges. Since + // overlapping ranges have been removed, this must be the last relevant + // range for this span. + break; + } + nextTextLinkerMatches.removeAt(0); + } + + // Add any extra text after any ranges. + final String remainingText = span.text!.substring(lastLinkEnd - index); + if (remainingText.isNotEmpty) { + nextChildren.add(TextSpan( + text: remainingText, + )); + } + } + + // Recurse on the children. + if (span.children?.isNotEmpty ?? false) { + final ( + Iterable<InlineSpan> childrenSpans, + Iterable<_TextLinkerMatch> childrenTextLinkerMatches, + ) = _linkSpansRecurse( + span.children!, + textCache, + nextTextLinkerMatches, + index + (span.text?.length ?? 0), + ); + nextTextLinkerMatches = childrenTextLinkerMatches.toList(); + nextChildren.addAll(childrenSpans); + } + + return ( + TextSpan( + style: span.style, + children: nextChildren, + ), + nextTextLinkerMatches, + ); + } +} diff --git a/packages/flutter/lib/src/widgets/linked_text.dart b/packages/flutter/lib/src/widgets/linked_text.dart new file mode 100644 index 0000000000000..9031adc0fc340 --- /dev/null +++ b/packages/flutter/lib/src/widgets/linked_text.dart @@ -0,0 +1,334 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; + +import 'basic.dart'; +import 'framework.dart'; +import 'text.dart'; + +/// Singature for a function that builds the [Widget] output by [LinkedText]. +/// +/// Typically a [Text.rich] containing a [TextSpan] whose children are the +/// [linkedSpans]. +typedef LinkedTextWidgetBuilder = Widget Function ( + BuildContext context, + Iterable<InlineSpan> linkedSpans, +); + +/// A widget that displays text with parts of it made interactive. +/// +/// By default, any URLs in the text are made interactive, and clicking one +/// calls the provided callback. +/// +/// Works with either a flat [String] (`text`) or a list of [InlineSpan]s +/// (`spans`). When using `spans`, only [TextSpan]s will be converted to links. +/// +/// {@tool dartpad} +/// This example shows how to create a [LinkedText] that turns URLs into +/// working links. +/// +/// ** See code in examples/api/lib/widgets/linked_text/linked_text.0.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This example shows how to use [LinkedText] to link Twitter handles by +/// passing in a custom [RegExp]. +/// +/// ** See code in examples/api/lib/widgets/linked_text/linked_text.1.dart ** +/// {@end-tool} +/// +/// {@tool dartpad} +/// This example shows how to use [LinkedText] to link URLs in a TextSpan tree +/// instead of in a flat string. +/// +/// ** See code in examples/api/lib/widgets/linked_text/linked_text.2.dart ** +/// {@end-tool} +class LinkedText extends StatefulWidget { + /// Creates an instance of [LinkedText] from the given [text] or [spans], + /// turning any URLs into interactive links. + /// + /// See also: + /// + /// * [LinkedText.regExp], which matches based on any given [RegExp]. + /// * [LinkedText.textLinkers], which uses [TextLinker]s to allow full + /// control over matching and building different types of links. + LinkedText({ + super.key, + required ValueChanged<Uri> onTapUri, + this.builder = _defaultBuilder, + List<InlineSpan>? spans, + String? text, + }) : assert((text == null) != (spans == null), 'Must specify exactly one to link: either text or spans.'), + spans = spans ?? <InlineSpan>[ + TextSpan( + text: text, + ), + ], + onTap = _getOnTap(onTapUri), + regExp = defaultUriRegExp, + textLinkers = null; + + /// Creates an instance of [LinkedText] from the given [text] or [spans], + /// turning anything matched by [regExp] into interactive links. + /// + /// {@tool dartpad} + /// This example shows how to use [LinkedText] to link Twitter handles by + /// passing in a custom [RegExp]. + /// + /// ** See code in examples/api/lib/widgets/linked_text/linked_text.1.dart ** + /// {@end-tool} + /// + /// See also: + /// + /// * [LinkedText.new], which matches [Uri]s. + /// * [LinkedText.textLinkers], which uses [TextLinker]s to allow full + /// control over matching and building different types of links. + LinkedText.regExp({ + super.key, + required this.onTap, + required this.regExp, + this.builder = _defaultBuilder, + List<InlineSpan>? spans, + String? text, + }) : assert((text == null) != (spans == null), 'Must specify exactly one to link: either text or spans.'), + spans = spans ?? <InlineSpan>[ + TextSpan( + text: text, + ), + ], + textLinkers = null; + + /// Creates an instance of [LinkedText] where the given [textLinkers] are + /// applied. + /// + /// Useful for independently matching different types of strings with + /// different behaviors. For example, highlighting both URLs and Twitter + /// handles with different style and/or behavior. + /// + /// {@tool dartpad} + /// This example shows how to use [LinkedText] to link both URLs and Twitter + /// handles in the same text. + /// + /// ** See code in examples/api/lib/widgets/linked_text/linked_text.3.dart ** + /// {@end-tool} + /// + /// See also: + /// + /// * [LinkedText.new], which matches [Uri]s. + /// * [LinkedText.regExp], which matches based on any given [RegExp]. + LinkedText.textLinkers({ + super.key, + this.builder = _defaultBuilder, + String? text, + List<InlineSpan>? spans, + required List<TextLinker> textLinkers, + }) : assert((text == null) != (spans == null), 'Must specify exactly one to link: either text or spans.'), + assert(textLinkers.isNotEmpty), + textLinkers = textLinkers, // ignore: prefer_initializing_formals + spans = spans ?? <InlineSpan>[ + TextSpan( + text: text, + ), + ], + onTap = null, + regExp = null; + + /// The spans on which to create links. + /// + /// It's also possible to specify a plain string by using the `text` + /// parameter instead. + final List<InlineSpan> spans; + + /// Builds the [Widget] that is output by [LinkedText]. + /// + /// By default, builds a [Text.rich] with a single [TextSpan] whose children + /// are the linked [TextSpan]s, and whose style is [DefaultTextStyle]. + final LinkedTextWidgetBuilder builder; + + /// Handles tapping on a link. + /// + /// This is irrelevant when using [LinkedText.textLinkers], where this is + /// controlled with an [InlineLinkBuilder] instead. + final ValueChanged<String>? onTap; + + /// Matches the text that should be turned into a link. + /// + /// This is irrelevant when using [LinkedText.textLinkers], where each + /// [TextLinker] specifies its own [TextLinker.regExp]. + /// + /// {@tool dartpad} + /// This example shows how to use [LinkedText] to link Twitter handles by + /// passing in a custom [RegExp]. + /// + /// ** See code in examples/api/lib/widgets/linked_text/linked_text.1.dart ** + /// {@end-tool} + final RegExp? regExp; + + /// Defines what parts of the text to match and how to link them. + /// + /// [TextLinker]s are applied in the order given. Overlapping matches are not + /// supported and will produce an error. + /// + /// {@tool dartpad} + /// This example shows how to use [LinkedText] to link both URLs and Twitter + /// handles in the same text with [TextLinker]s. + /// + /// ** See code in examples/api/lib/widgets/linked_text/linked_text.3.dart ** + /// {@end-tool} + final List<TextLinker>? textLinkers; + + /// The default [RegExp], which matches [Uri]s by default. + /// + /// Matches with and without a host, but only "http" or "https". Ignores email + /// addresses. + static final RegExp defaultUriRegExp = RegExp(r'(?<!@[a-zA-Z0-9-]*)(?<![\/\.a-zA-Z0-9-])((https?:\/\/)?(([a-zA-Z0-9-]*\.)*[a-zA-Z0-9-]+(\.[a-zA-Z]+)+))(?::\d{1,5})?(?:\/[^\s]*)?(?:\?[^\s#]*)?(?:#[^\s]*)?(?![a-zA-Z0-9-]*@)'); + + /// Returns a generic [ValueChanged]<String> given a callback specifically for + /// tapping on a [Uri]. + static ValueChanged<String> _getOnTap(ValueChanged<Uri> onTapUri) { + return (String linkString) { + Uri uri = Uri.parse(linkString); + if (uri.host.isEmpty) { + // defaultUriRegExp matches Uris without a host, but packages like + // url_launcher require a host to launch a Uri. So add the host. + uri = Uri.parse('https://$linkString'); + } + onTapUri(uri); + }; + } + + /// The default value of [builder]. + /// + /// Builds a [Text.rich] with a single [TextSpan] whose children are the + /// linked [TextSpan]s, and whose style is [DefaultTextStyle]. If there are no + /// linked [TextSpan]s to display, builds a [SizedBox.shrink]. + static Widget _defaultBuilder(BuildContext context, Iterable<InlineSpan> linkedSpans) { + if (linkedSpans.isEmpty) { + return const SizedBox.shrink(); + } + + return Text.rich( + TextSpan( + style: DefaultTextStyle.of(context).style, + children: linkedSpans.toList(), + ), + ); + } + + /// The style used for the link by default if none is given. + @visibleForTesting + static TextStyle defaultLinkStyle = _InlineLinkSpan.defaultLinkStyle; + + @override + State<LinkedText> createState() => _LinkedTextState(); +} + +class _LinkedTextState extends State<LinkedText> { + final List<GestureRecognizer> _recognizers = <GestureRecognizer>[]; + late Iterable<InlineSpan> _linkedSpans; + late final List<TextLinker> _textLinkers; + + void _disposeRecognizers() { + for (final GestureRecognizer recognizer in _recognizers) { + recognizer.dispose(); + } + _recognizers.clear(); + } + + void _linkSpans() { + _disposeRecognizers(); + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + widget.spans, + _textLinkers, + ); + _linkedSpans = linkedSpans; + } + + @override + void initState() { + super.initState(); + _textLinkers = widget.textLinkers ?? <TextLinker>[ + TextLinker( + regExp: widget.regExp ?? LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () => widget.onTap!(linkString); + // Keep track of created recognizers so that they can be disposed. + _recognizers.add(recognizer); + return _InlineLinkSpan( + recognizer: recognizer, + style: LinkedText.defaultLinkStyle, + text: displayString, + ); + }, + ), + ]; + _linkSpans(); + } + + @override + void didUpdateWidget(LinkedText oldWidget) { + super.didUpdateWidget(oldWidget); + + if (widget.spans != oldWidget.spans || widget.textLinkers != oldWidget.textLinkers) { + _linkSpans(); + } + } + + @override + void dispose() { + _disposeRecognizers(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.builder(context, _linkedSpans); + } +} + +/// An inline, interactive text link. +/// +/// See also: +/// +/// * [LinkedText], which creates links with this class by default. +class _InlineLinkSpan extends TextSpan { + /// Create an instance of [_InlineLinkSpan]. + _InlineLinkSpan({ + required String text, + TextStyle? style, + super.recognizer, + }) : super( + style: style ?? defaultLinkStyle, + mouseCursor: SystemMouseCursors.click, + text: text, + ); + + static Color get _linkColor { + return switch (defaultTargetPlatform) { + // This value was taken from Safari on an iPhone 14 Pro iOS 16.4 + // simulator. + TargetPlatform.iOS => const Color(0xff1717f0), + // This value was taken from Chrome on macOS 13.4.1. + TargetPlatform.macOS => const Color(0xff0000ee), + // This value was taken from Chrome on Android 14. + TargetPlatform.android || TargetPlatform.fuchsia => const Color(0xff0e0eef), + // This value was taken from the Chrome browser running on GNOME 43.3 on + // Debian. + TargetPlatform.linux => const Color(0xff0026e8), + // This value was taken from the Edge browser running on Windows 10. + TargetPlatform.windows => const Color(0xff1e2b8b), + }; + } + + /// The style used for the link by default if none is given. + @visibleForTesting + static TextStyle defaultLinkStyle = TextStyle( + color: _linkColor, + decorationColor: _linkColor, + decoration: TextDecoration.underline, + ); +} diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index cc188608a8519..7c55f76192286 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -73,6 +73,7 @@ export 'src/widgets/inherited_theme.dart'; export 'src/widgets/interactive_viewer.dart'; export 'src/widgets/keyboard_listener.dart'; export 'src/widgets/layout_builder.dart'; +export 'src/widgets/linked_text.dart'; export 'src/widgets/list_wheel_scroll_view.dart'; export 'src/widgets/localizations.dart'; export 'src/widgets/lookup_boundary.dart'; diff --git a/packages/flutter/test/painting/text_linker_test.dart b/packages/flutter/test/painting/text_linker_test.dart new file mode 100644 index 0000000000000..aee0a5fea1659 --- /dev/null +++ b/packages/flutter/test/painting/text_linker_test.dart @@ -0,0 +1,322 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + final RegExp hashTagRegExp = RegExp(r'#[a-zA-Z0-9]*'); + final RegExp urlRegExp = RegExp(r'(?<!@[a-zA-Z0-9-]*)(?<![\/\.a-zA-Z0-9-])((https?:\/\/)?(([a-zA-Z0-9-]*\.)*[a-zA-Z0-9-]+(\.[a-zA-Z]+)+))(?::\d{1,5})?(?:\/[^\s]*)?(?:\?[^\s#]*)?(?:#[^\s]*)?(?![a-zA-Z0-9-]*@)'); + + group('TextLinker.linkSpans', () { + group('url matching', () { + for (final String text in <String>[ + 'https://www.example.com', + 'www.example123.co.uk', + 'subdomain.example.net', + 'ftp.subdomain.example.net', + 'http://subdomain.example.net', + 'https://subdomain.example.net', + 'http://example.com/', + 'https://www.example.org/', + 'ftp.subdomain.example.net', + 'example.com', + 'subdomain.example.io', + 'www.example123.co.uk', + 'http://example.com:8080/', + 'https://www.example.com/path/to/resource', + 'http://www.example.com/index.php?query=test#fragment', + 'https://subdomain.example.io:8443/resource/file.html?search=query#result', + 'example.com', + 'subsub.www.example.com', + 'https://subsub.www.example.com' + ]) { + test('converts the valid url $text to a link by default', () { + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + <InlineSpan>[ + TextSpan( + text: text, + ), + ], + <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + ); + }, + ), + ], + ); + + expect(linkedSpans, hasLength(1)); + expect(linkedSpans.first, isA<TextSpan>()); + + final TextSpan wrapperSpan = linkedSpans.first as TextSpan; + expect(wrapperSpan.text, isNull); + expect(wrapperSpan.children, hasLength(1)); + + final TextSpan span = wrapperSpan.children!.first as TextSpan; + + expect(span.text, text); + expect(span.style, LinkedText.defaultLinkStyle); + expect(span.children, isNull); + }); + } + + for (final String text in <String>[ + 'abcd://subdomain.example.net', + 'ftp://subdomain.example.net', + ]) { + test('does nothing to the invalid url $text', () { + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + <InlineSpan>[ + TextSpan( + text: text, + ), + ], + <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + return TextSpan( + text: displayString, + ); + }, + ), + ], + ); + + expect(linkedSpans, hasLength(1)); + expect(linkedSpans.first, isA<TextSpan>()); + + final TextSpan wrapperSpan = linkedSpans.first as TextSpan; + expect(wrapperSpan.text, isNull); + expect(wrapperSpan.children, hasLength(1)); + + final TextSpan span = wrapperSpan.children!.first as TextSpan; + + expect(span.text, text); + expect(span.style, isNull); + expect(span.children, isNull); + }); + } + + for (final String text in <String>[ + '"example.com"', + "'example.com'", + '(example.com)', + ]) { + test('can parse url $text with leading and trailing characters', () { + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + <InlineSpan>[ + TextSpan( + text: text, + ), + ], + <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + ); + }, + ), + ], + ); + + expect(linkedSpans, hasLength(1)); + expect(linkedSpans.first, isA<TextSpan>()); + + final TextSpan wrapperSpan = linkedSpans.first as TextSpan; + expect(wrapperSpan.text, isNull); + expect(wrapperSpan.children, hasLength(3)); + + expect(wrapperSpan.children!.first, isA<TextSpan>()); + final TextSpan leadingSpan = wrapperSpan.children!.first as TextSpan; + expect(leadingSpan.text, hasLength(1)); + expect(leadingSpan.style, isNull); + expect(leadingSpan.children, isNull); + + expect(wrapperSpan.children![1], isA<TextSpan>()); + final TextSpan bodySpan = wrapperSpan.children![1] as TextSpan; + expect(bodySpan.text, 'example.com'); + expect(bodySpan.style, LinkedText.defaultLinkStyle); + expect(bodySpan.children, isNull); + + expect(wrapperSpan.children!.last, isA<TextSpan>()); + final TextSpan trailingSpan = wrapperSpan.children!.last as TextSpan; + expect(trailingSpan.text, hasLength(1)); + expect(trailingSpan.style, isNull); + expect(trailingSpan.children, isNull); + }); + } + }); + + test('multiple TextLinkers', () { + final TextLinker urlTextLinker = TextLinker( + regExp: urlRegExp, + linkBuilder: (String displayString, String linkString) { + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + ); + }, + ); + final TextLinker hashTagTextLinker = TextLinker( + regExp: hashTagRegExp, + linkBuilder: (String displayString, String linkString) { + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + ); + }, + ); + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + <InlineSpan>[ + const TextSpan( + text: 'Flutter is great #crossplatform #declarative check out flutter.dev.', + ), + ], + <TextLinker>[urlTextLinker, hashTagTextLinker], + ); + + expect(linkedSpans, hasLength(1)); + expect(linkedSpans.first, isA<TextSpan>()); + + final TextSpan wrapperSpan = linkedSpans.first as TextSpan; + expect(wrapperSpan.text, isNull); + expect(wrapperSpan.children, hasLength(7)); + + expect(wrapperSpan.children!.first, isA<TextSpan>()); + final TextSpan textSpan1 = wrapperSpan.children!.first as TextSpan; + expect(textSpan1.text, 'Flutter is great '); + expect(textSpan1.style, isNull); + expect(textSpan1.children, isNull); + + expect(wrapperSpan.children![1], isA<TextSpan>()); + final TextSpan hashTagSpan1 = wrapperSpan.children![1] as TextSpan; + expect(hashTagSpan1.text, '#crossplatform'); + expect(hashTagSpan1.style, LinkedText.defaultLinkStyle); + expect(hashTagSpan1.children, isNull); + + expect(wrapperSpan.children![2], isA<TextSpan>()); + final TextSpan textSpan2 = wrapperSpan.children![2] as TextSpan; + expect(textSpan2.text, ' '); + expect(textSpan2.style, isNull); + expect(textSpan2.children, isNull); + + expect(wrapperSpan.children![3], isA<TextSpan>()); + final TextSpan hashTagSpan2 = wrapperSpan.children![3] as TextSpan; + expect(hashTagSpan2.text, '#declarative'); + expect(hashTagSpan2.style, LinkedText.defaultLinkStyle); + expect(hashTagSpan2.children, isNull); + + expect(wrapperSpan.children![4], isA<TextSpan>()); + final TextSpan textSpan3 = wrapperSpan.children![4] as TextSpan; + expect(textSpan3.text, ' check out '); + expect(textSpan3.style, isNull); + expect(textSpan3.children, isNull); + + expect(wrapperSpan.children![5], isA<TextSpan>()); + final TextSpan urlSpan = wrapperSpan.children![5] as TextSpan; + expect(urlSpan.text, 'flutter.dev'); + expect(urlSpan.style, LinkedText.defaultLinkStyle); + expect(urlSpan.children, isNull); + + expect(wrapperSpan.children![6], isA<TextSpan>()); + final TextSpan textSpan4 = wrapperSpan.children![6] as TextSpan; + expect(textSpan4.text, '.'); + expect(textSpan4.style, isNull); + expect(textSpan4.children, isNull); + }); + + test('complex span tree', () { + final Iterable<InlineSpan> linkedSpans = TextLinker.linkSpans( + const <InlineSpan>[ + TextSpan( + text: 'Check out https://www.', + children: <InlineSpan>[ + TextSpan( + style: TextStyle( + fontWeight: FontWeight.w800, + ), + text: 'flutter', + ), + ], + ), + TextSpan( + text: '.dev!', + ), + ], + <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + ); + }, + ), + ], + ); + + expect(linkedSpans, hasLength(2)); + + expect(linkedSpans.first, isA<TextSpan>()); + final TextSpan span1 = linkedSpans.first as TextSpan; + expect(span1.text, isNull); + expect(span1.style, isNull); + expect(span1.children, hasLength(3)); + + // First span's children ('Check out https://www.flutter'). + expect(span1.children![0], isA<TextSpan>()); + final TextSpan span1Child1 = span1.children![0] as TextSpan; + expect(span1Child1.text, 'Check out '); + expect(span1Child1.style, isNull); + expect(span1Child1.children, isNull); + + expect(span1.children![1], isA<TextSpan>()); + final TextSpan span1Child2 = span1.children![1] as TextSpan; + expect(span1Child2.text, 'https://www.'); + expect(span1Child2.style, LinkedText.defaultLinkStyle); + expect(span1Child2.children, isNull); + + expect(span1.children![2], isA<TextSpan>()); + final TextSpan span1Child3 = span1.children![2] as TextSpan; + expect(span1Child3.text, null); + expect(span1Child3.style, const TextStyle(fontWeight: FontWeight.w800)); + expect(span1Child3.children, hasLength(1)); + + expect(span1Child3.children![0], isA<TextSpan>()); + final TextSpan span1Child3Child1 = span1Child3.children![0] as TextSpan; + expect(span1Child3Child1.text, 'flutter'); + expect(span1Child3Child1.style, LinkedText.defaultLinkStyle); + expect(span1Child3Child1.children, isNull); + + // Second span's children ('.dev!'). + expect(linkedSpans.elementAt(1), isA<TextSpan>()); + final TextSpan span2 = linkedSpans.elementAt(1) as TextSpan; + expect(span2.text, isNull); + expect(span2.children, hasLength(2)); + expect(span2.style, isNull); + + expect(span2.children![0], isA<TextSpan>()); + final TextSpan span2Child1 = span2.children![0] as TextSpan; + expect(span2Child1.text, '.dev'); + expect(span2Child1.style, LinkedText.defaultLinkStyle); + expect(span2Child1.children, isNull); + + expect(span2.children![1], isA<TextSpan>()); + final TextSpan span2Child2 = span2.children![1] as TextSpan; + expect(span2Child2.text, '!'); + expect(span2Child2.children, isNull); + }); + }); +} diff --git a/packages/flutter/test/widgets/linked_text_test.dart b/packages/flutter/test/widgets/linked_text_test.dart new file mode 100644 index 0000000000000..9a1b2ab09c55d --- /dev/null +++ b/packages/flutter/test/widgets/linked_text_test.dart @@ -0,0 +1,367 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + final RegExp hashTagRegExp = RegExp(r'#[a-zA-Z0-9]*'); + final RegExp urlRegExp = RegExp(r'(?<!@[a-zA-Z0-9-]*)(?<![\/\.a-zA-Z0-9-])((https?:\/\/)?(([a-zA-Z0-9-]*\.)*[a-zA-Z0-9-]+(\.[a-zA-Z]+)+))(?::\d{1,5})?(?:\/[^\s]*)?(?:\?[^\s#]*)?(?:#[^\s]*)?(?![a-zA-Z0-9-]*@)'); + + testWidgets('links urls by default', (WidgetTester tester) async { + Uri? lastTappedUri; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText( + onTapUri: (Uri uri) { + lastTappedUri = uri; + }, + text: 'Check out flutter.dev.', + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedUri, isNull); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + + // The https:// host is automatically added. + expect(lastTappedUri, Uri.parse('https://flutter.dev')); + }); + + testWidgets('can pass custom regexp', (WidgetTester tester) async { + String? lastTappedLink; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText.regExp( + regExp: hashTagRegExp, + onTap: (String linkString) { + lastTappedLink = linkString; + }, + text: 'Flutter is great #crossplatform #declarative', + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedLink, isNull); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + expect(lastTappedLink, '#crossplatform'); + }); + + testWidgets('can pass custom regexp with .textLinkers', (WidgetTester tester) async { + String? lastTappedLink; + final List<TapGestureRecognizer> recognizers = <TapGestureRecognizer>[]; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText.textLinkers( + textLinkers: <TextLinker>[ + TextLinker( + regExp: hashTagRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () { + lastTappedLink = linkString; + }; + recognizers.add(recognizer); + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + recognizer: recognizer, + ); + }, + ), + ], + text: 'Flutter is great #crossplatform #declarative', + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedLink, isNull); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + expect(lastTappedLink, '#crossplatform'); + + expect(recognizers, hasLength(2)); + for (final TapGestureRecognizer recognizer in recognizers) { + recognizer.dispose(); + } + }); + + testWidgets('can link multiple different types', (WidgetTester tester) async { + String? lastTappedLink; + final List<TapGestureRecognizer> recognizers = <TapGestureRecognizer>[]; + final TextLinker urlTextLinker = TextLinker( + regExp: urlRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () { + lastTappedLink = linkString; + }; + recognizers.add(recognizer); + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + recognizer: recognizer, + ); + }, + ); + final TextLinker hashTagTextLinker = TextLinker( + regExp: hashTagRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () { + lastTappedLink = linkString; + }; + recognizers.add(recognizer); + return TextSpan( + style: LinkedText.defaultLinkStyle, + text: displayString, + recognizer: recognizer, + ); + }, + ); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText.textLinkers( + textLinkers: <TextLinker>[urlTextLinker, hashTagTextLinker], + text: 'flutter.dev is great #crossplatform #declarative', + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedLink, isNull); + + await tester.tapAt(tester.getTopLeft(find.byType(RichText))); + expect(lastTappedLink, 'flutter.dev'); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + expect(lastTappedLink, '#crossplatform'); + + expect(recognizers, hasLength(3)); + for (final TapGestureRecognizer recognizer in recognizers) { + recognizer.dispose(); + } + }); + + testWidgets('can customize linkBuilder', (WidgetTester tester) async { + String? lastTappedLink; + final List<TapGestureRecognizer> recognizers = <TapGestureRecognizer>[]; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText.textLinkers( + textLinkers: <TextLinker>[ + TextLinker( + regExp: LinkedText.defaultUriRegExp, + linkBuilder: (String displayString, String linkString) { + final TapGestureRecognizer recognizer = TapGestureRecognizer() + ..onTap = () { + lastTappedLink = linkString; + }; + recognizers.add(recognizer); + return TextSpan( + recognizer: recognizer, + text: displayString, + mouseCursor: SystemMouseCursors.help, + ); + }, + ), + ], + text: 'Check out flutter.dev.', + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedLink, isNull); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); + await gesture.addPointer(location: tester.getCenter(find.byType(Scaffold))); + await tester.pump(); + expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); + await gesture.moveTo(tester.getCenter(find.byType(RichText))); + expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.help); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + expect(lastTappedLink, 'flutter.dev'); + + expect(recognizers, hasLength(1)); + for (final TapGestureRecognizer recognizer in recognizers) { + recognizer.dispose(); + } + }); + + testWidgets('can take nested spans', (WidgetTester tester) async { + Uri? lastTappedUri; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText( + onTapUri: (Uri uri) { + lastTappedUri = uri; + }, + spans: <InlineSpan>[ + TextSpan( + text: 'Check out fl', + style: DefaultTextStyle.of(context).style, + children: const <InlineSpan>[ + TextSpan( + text: 'u', + children: <InlineSpan>[ + TextSpan( + style: TextStyle( + fontWeight: FontWeight.w800, + ), + text: 'tt', + ), + TextSpan( + text: 'er', + ), + ], + ), + ], + ), + const TextSpan( + text: '.dev.', + ), + ], + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedUri, isNull); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + + // The https:// host is automatically added. + expect(lastTappedUri, Uri.parse('https://flutter.dev')); + }); + + testWidgets('can handle WidgetSpans', (WidgetTester tester) async { + Uri? lastTappedUri; + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText( + onTapUri: (Uri uri) { + lastTappedUri = uri; + }, + spans: <InlineSpan>[ + TextSpan( + text: 'Check out fl', + style: DefaultTextStyle.of(context).style, + children: const <InlineSpan>[ + TextSpan( + text: 'u', + children: <InlineSpan>[ + TextSpan( + style: TextStyle( + fontWeight: FontWeight.w800, + ), + text: 'tt', + ), + WidgetSpan( + child: FlutterLogo(), + ), + TextSpan( + text: 'er', + ), + ], + ), + ], + ), + const TextSpan( + text: '.dev.', + ), + ], + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + expect(lastTappedUri, isNull); + + await tester.tapAt(tester.getCenter(find.byType(RichText))); + + // The WidgetSpan is ignored, so a link is still produced even though it has + // a FlutterLogo in the middle of it. + expect(lastTappedUri, Uri.parse('https://flutter.dev')); + }); + + testWidgets('builds the widget specified by builder', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return LinkedText( + onTapUri: (Uri uri) {}, + text: 'Check out flutter.dev.', + builder: (BuildContext context, Iterable<InlineSpan> linkedSpans) { + return RichText( + textAlign: TextAlign.center, + text: TextSpan( + children: linkedSpans.toList(), + ), + ); + }, + ); + }, + ), + ), + ), + ); + + expect(find.byType(RichText), findsOneWidget); + final RichText richText = tester.widget(find.byType(RichText)); + expect(richText.textAlign, TextAlign.center); + }); +} From 77a5a5d3a8c1fa0fb0ef05238daa0335667a5657 Mon Sep 17 00:00:00 2001 From: Daco Harkes <dacoharkes@google.com> Date: Thu, 14 Sep 2023 08:42:41 +0200 Subject: [PATCH 1265/1547] Update plugin_ffi generated file to match FFIgen 9.0.0 (#134614) Template plugin_ffi uses FFIgen and generates both the FFIgen inputs and the generated file. We rolled FFIgen to 9.0.0 in https://github.com/flutter/flutter/pull/130494, which means a slight change to the generated file. * https://github.com/dart-lang/ffigen/issues/619 Note, because of https://github.com/flutter/flutter/issues/105695, we run the test on the FFIgen repo rather than on the flutter CI. --- .../plugin_ffi/lib/projectName_bindings_generated.dart.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/flutter_tools/templates/plugin_ffi/lib/projectName_bindings_generated.dart.tmpl b/packages/flutter_tools/templates/plugin_ffi/lib/projectName_bindings_generated.dart.tmpl index cb21d861d25b1..11b9f06a22854 100644 --- a/packages/flutter_tools/templates/plugin_ffi/lib/projectName_bindings_generated.dart.tmpl +++ b/packages/flutter_tools/templates/plugin_ffi/lib/projectName_bindings_generated.dart.tmpl @@ -5,6 +5,7 @@ // AUTO GENERATED FILE, DO NOT EDIT. // // Generated by `package:ffigen`. +// ignore_for_file: type=lint import 'dart:ffi' as ffi; /// Bindings for `src/{{projectName}}.h`. From 58ba6c295d8ccf125366b7e871b1c41fe2255f75 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 11:52:22 -0400 Subject: [PATCH 1266/1547] Roll Packages from 06cd9e967b9f to 275b76ccffa5 (1 revision) (#134734) https://github.com/flutter/packages/compare/06cd9e967b9f...275b76ccffa5 2023-09-13 kevmoo@users.noreply.github.com go_router_builder: support the latest pkg:analyzer (flutter/packages#4921) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 3e7efced9baae..fab924a8ffcd1 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -06cd9e967b9f17da3eea812a6f85394f62278aec +275b76ccffa56ec1bfe5bd94a6539fa09518eced From 57ad4ff01875e2ce260710919d22a1c91842452f Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Thu, 14 Sep 2023 09:13:35 -0700 Subject: [PATCH 1267/1547] Added a devicelab test for vulkan validation layers (#134685) This makes sure validation layers are being used and that there are no validation errors fixes https://github.com/flutter/flutter/issues/134175 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 10 +++ TESTOWNERS | 1 + .../bin/tasks/hello_world_impeller.dart | 81 +++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 dev/devicelab/bin/tasks/hello_world_impeller.dart diff --git a/.ci.yaml b/.ci.yaml index e01d5b5ccd341..59ae1ab2bd1c1 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1567,6 +1567,16 @@ targets: - bin/** - .ci.yaml + - name: Linux_android hello_world_impeller + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux"] + task_name: hello_world_impeller + - name: Linux_android android_defines_test recipe: devicelab/devicelab_drone presubmit: true diff --git a/TESTOWNERS b/TESTOWNERS index bdb7499e3cee8..4f4096f01b11a 100644 --- a/TESTOWNERS +++ b/TESTOWNERS @@ -135,6 +135,7 @@ /dev/devicelab/bin/tasks/fullscreen_textfield_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world__memory.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hello_world_android__compile.dart @zanderso @flutter/tool +/dev/devicelab/bin/tasks/hello_world_impeller.dart @gaaclarke @flutter/engine /dev/devicelab/bin/tasks/home_scroll_perf__timeline_summary.dart @zanderso @flutter/engine /dev/devicelab/bin/tasks/hot_mode_dev_cycle__benchmark.dart @eliasyishak @flutter/tool /dev/devicelab/bin/tasks/hybrid_android_views_integration_test.dart @stuartmorgan @flutter/plugin diff --git a/dev/devicelab/bin/tasks/hello_world_impeller.dart b/dev/devicelab/bin/tasks/hello_world_impeller.dart new file mode 100644 index 0000000000000..e67a25b48e6d3 --- /dev/null +++ b/dev/devicelab/bin/tasks/hello_world_impeller.dart @@ -0,0 +1,81 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async' show Completer, StreamSubscription; +import 'dart:io' show Directory, Process; + +import 'package:flutter_devicelab/framework/devices.dart' + show Device, DeviceOperatingSystem, deviceOperatingSystem, devices; +import 'package:flutter_devicelab/framework/framework.dart' show task; +import 'package:flutter_devicelab/framework/task_result.dart' show TaskResult; +import 'package:flutter_devicelab/framework/utils.dart' + show dir, flutter, flutterDirectory, inDirectory, startFlutter; +import 'package:path/path.dart' as path; + +Future<TaskResult> run() async { + deviceOperatingSystem = DeviceOperatingSystem.android; + final Device device = await devices.workingDevice; + await device.unlock(); + final Directory appDir = + dir(path.join(flutterDirectory.path, 'examples/hello_world')); + + bool isUsingValidationLayers = false; + bool hasValidationErrors = false; + int impellerBackendCount = 0; + final Completer<void> didReceiveBackendMessage = Completer<void>(); + + await inDirectory(appDir, () async { + await flutter('packages', options: <String>['get']); + + final StreamSubscription<String> adb = device.logcat.listen( + (String data) { + if (data.contains('Using the Impeller rendering backend')) { + // Sometimes more than one of these will be printed out if there is a + // fallback. + if (!didReceiveBackendMessage.isCompleted) { + didReceiveBackendMessage.complete(); + } + impellerBackendCount += 1; + } + if (data.contains( + 'Using the Impeller rendering backend (Vulkan with Validation Layers)')) { + isUsingValidationLayers = true; + } + // "ImpellerValidationBreak" comes from the engine: + // https://github.com/flutter/engine/blob/4160ebacdae2081d6f3160432f5f0dd87dbebec1/impeller/base/validation.cc#L40 + if (data.contains('ImpellerValidationBreak')) { + hasValidationErrors = true; + } + }, + ); + + final Process process = await startFlutter( + 'run', + options: <String>[ + '--enable-impeller', + '-d', + device.deviceId, + ], + ); + + await didReceiveBackendMessage.future; + // Since we are waiting for the lack of errors, there is no determinate + // amount of time we can wait. + await Future<void>.delayed(const Duration(seconds: 30)); + process.stdin.write('q'); + await adb.cancel(); + }); + + if (!isUsingValidationLayers || impellerBackendCount != 1) { + return TaskResult.failure('Not using Vulkan validation layers.'); + } + if (hasValidationErrors){ + return TaskResult.failure('Impeller validation errors detected.'); + } + return TaskResult.success(null); +} + +Future<void> main() async { + await task(run); +} From 63f25b0db2c058475a85831a8bf7e7a6311e08e6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 12:53:15 -0400 Subject: [PATCH 1268/1547] Roll Flutter Engine from cd90cc8469fb to 4160ebacdae2 (5 revisions) (#134695) https://github.com/flutter/engine/compare/cd90cc8469fb...4160ebacdae2 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from b38989859b81 to a30fbf83f2e9 (3 revisions) (flutter/engine#45796) 2023-09-13 49699333+dependabot[bot]@users.noreply.github.com Bump quiver from 3.0.0 to 3.2.1 in /lib/web_ui (flutter/engine#45792) 2023-09-13 49699333+dependabot[bot]@users.noreply.github.com Bump http from 0.13.5 to 1.1.0 in /lib/web_ui (flutter/engine#45791) 2023-09-13 49699333+dependabot[bot]@users.noreply.github.com Bump archive from 3.1.2 to 3.3.9 in /lib/web_ui (flutter/engine#45795) 2023-09-13 mdebbar@google.com [web] Use DOM to render paragraphs with letter spacing (flutter/engine#45651) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c7f0a1d004853..72f3c176c51a7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cd90cc8469fbc789e0b44adc79f330f8d4d2744c +4160ebacdae2081d6f3160432f5f0dd87dbebec1 From 9fa09ea4d32215c43b9c04f39ebaf62050c137e2 Mon Sep 17 00:00:00 2001 From: Bruno Leroux <leroux_bruno@yahoo.fr> Date: Thu, 14 Sep 2023 19:03:40 +0200 Subject: [PATCH 1269/1547] Fix NavigationRail hover misplaced when using large icons (#134719) ## Description This PR fixes `NavigationRail` hover position when using enlarged icons whose size is specified using `NavigationRailThemeData.selectedIconTheme` and `NavigationRailThemeData.unselectedIconTheme`. ## Related Issue Fixes https://github.com/flutter/flutter/issues/133799. ## Tests Adds 1 test, updates 1 test (to replace some magic numbers). --- .../lib/src/material/navigation_rail.dart | 28 +++- .../test/material/navigation_rail_test.dart | 126 +++++++++++++++++- 2 files changed, 147 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index 6b7228f5cf785..abc417813d43a 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -602,13 +602,19 @@ class _RailDestination extends StatelessWidget { Widget content; + // The indicator height is fixed and equal to _kIndicatorHeight. + // When the icon height is larger than the indicator height the indicator + // vertical offset is used to vertically center the indicator. + final bool isLargeIconSize = iconTheme.size != null && iconTheme.size! > _kIndicatorHeight; + final double indicatorVerticalOffset = isLargeIconSize ? (iconTheme.size! - _kIndicatorHeight) / 2 : 0; + switch (labelType) { case NavigationRailLabelType.none: // Split the destination spacing across the top and bottom to keep the icon centered. final Widget? spacing = material3 ? const SizedBox(height: _verticalDestinationSpacingM3 / 2) : null; indicatorOffset = Offset( minWidth / 2 + destinationPadding.left, - _verticalDestinationSpacingM3 / 2 + destinationPadding.top, + _verticalDestinationSpacingM3 / 2 + destinationPadding.top + indicatorVerticalOffset, ); final Widget iconPart = Column( children: <Widget>[ @@ -687,9 +693,15 @@ class _RailDestination extends StatelessWidget { final Widget bottomSpacing = SizedBox(height: material3 ? _verticalDestinationSpacingM3 : verticalPadding); final double indicatorHorizontalPadding = (destinationPadding.left / 2) - (destinationPadding.right / 2); final double indicatorVerticalPadding = destinationPadding.top; - indicatorOffset = Offset(minWidth / 2 + indicatorHorizontalPadding, indicatorVerticalPadding); + indicatorOffset = Offset( + minWidth / 2 + indicatorHorizontalPadding, + indicatorVerticalPadding + indicatorVerticalOffset, + ); if (minWidth < _NavigationRailDefaultsM2(context).minWidth!) { - indicatorOffset = Offset(minWidth / 2 + _horizontalDestinationSpacingM3, indicatorVerticalPadding); + indicatorOffset = Offset( + minWidth / 2 + _horizontalDestinationSpacingM3, + indicatorVerticalPadding + indicatorVerticalOffset, + ); } content = Container( constraints: BoxConstraints( @@ -734,9 +746,15 @@ class _RailDestination extends StatelessWidget { final Widget bottomSpacing = SizedBox(height: material3 ? _verticalDestinationSpacingM3 : _verticalDestinationPaddingWithLabel); final double indicatorHorizontalPadding = (destinationPadding.left / 2) - (destinationPadding.right / 2); final double indicatorVerticalPadding = destinationPadding.top; - indicatorOffset = Offset(minWidth / 2 + indicatorHorizontalPadding, indicatorVerticalPadding); + indicatorOffset = Offset( + minWidth / 2 + indicatorHorizontalPadding, + indicatorVerticalPadding + indicatorVerticalOffset, + ); if (minWidth < _NavigationRailDefaultsM2(context).minWidth!) { - indicatorOffset = Offset(minWidth / 2 + _horizontalDestinationSpacingM3, indicatorVerticalPadding); + indicatorOffset = Offset( + minWidth / 2 + _horizontalDestinationSpacingM3, + indicatorVerticalPadding + indicatorVerticalOffset, + ); } content = Container( constraints: BoxConstraints( diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index ae0b4571747f7..b1e99e8d406de 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -3117,6 +3117,9 @@ void main() { const double destinationWidth = 72.0; const double destinationHorizontalPadding = 8.0; const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalIconLabelSpacing = 4.0; + const double verticalDestinationSpacing = 12.0; // The navigation rail width is larger than default because of the first destination long label. final double railWidth = tester.getSize(find.byType(NavigationRail)).width; @@ -3128,6 +3131,12 @@ void main() { final Rect includedRect = indicatorRect; final Rect excludedRect = includedRect.inflate(10); + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double labelHeight = 16; // fontSize is 12 and height is 1.3. + const double destinationHeight = indicatorHeight + verticalIconLabelSpacing + labelHeight + verticalDestinationSpacing; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset; + expect( inkFeatures, paints @@ -3152,7 +3161,116 @@ void main() { color: const Color(0x0a6750a4), ) ..rrect( - rrect: RRect.fromLTRBR(indicatorLeft, 72.0, indicatorRight, 104.0, const Radius.circular(16)), + rrect: RRect.fromLTRBR( + indicatorLeft, + secondIndicatorVerticalOffset, + indicatorRight, + secondIndicatorVerticalOffset + indicatorHeight, + const Radius.circular(16), + ), + color: const Color(0xffe8def8), + ), + ); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 + + testWidgetsWithLeakTracking('NavigationRail indicator renders properly with large icon', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/133799. + const double iconSize = 50; + await _pumpNavigationRail( + tester, + navigationRailTheme: const NavigationRailThemeData( + selectedIconTheme: IconThemeData(size: iconSize), + unselectedIconTheme: IconThemeData(size: iconSize), + ), + navigationRail: NavigationRail( + selectedIndex: 1, + destinations: const <NavigationRailDestination>[ + NavigationRailDestination( + icon: Icon(Icons.favorite_border), + selectedIcon: Icon(Icons.favorite), + label: Text('ABC'), + ), + NavigationRailDestination( + icon: Icon(Icons.bookmark_border), + selectedIcon: Icon(Icons.bookmark), + label: Text('DEF'), + ), + ], + labelType: NavigationRailLabelType.all, + ), + ); + + // Hover the first destination. + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byIcon(Icons.favorite_border))); + await tester.pumpAndSettle(); + + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + + // Default values from M3 specification. + const double railMinWidth = 80.0; + const double indicatorHeight = 32.0; + const double destinationWidth = 72.0; + const double destinationHorizontalPadding = 8.0; + const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalIconLabelSpacing = 4.0; + const double verticalDestinationSpacing = 12.0; + + // The navigation rail width is the default one because labels are short. + final double railWidth = tester.getSize(find.byType(NavigationRail)).width; + expect(railWidth, railMinWidth); + + // Expected indicator position. + final double indicatorLeft = (railWidth - indicatorWidth) / 2; + final double indicatorRight = (railWidth + indicatorWidth) / 2; + const double indicatorTop = (iconSize - indicatorHeight) / 2; + const double indicatorBottom = (iconSize + indicatorHeight) / 2; + final Rect indicatorRect = Rect.fromLTRB(indicatorLeft, indicatorTop, indicatorRight, indicatorBottom); + final Rect includedRect = indicatorRect; + final Rect excludedRect = includedRect.inflate(10); + + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double labelHeight = 16; // fontSize is 12 and height is 1.3. + const double destinationHeight = iconSize + verticalIconLabelSpacing + labelHeight + verticalDestinationSpacing; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double indicatorOffset = (iconSize - indicatorHeight) / 2; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset + indicatorOffset; + + expect( + inkFeatures, + paints + ..clipPath( + pathMatcher: isPathThat( + includes: <Offset>[ + includedRect.centerLeft, + includedRect.topCenter, + includedRect.centerRight, + includedRect.bottomCenter, + ], + excludes: <Offset>[ + excludedRect.centerLeft, + excludedRect.topCenter, + excludedRect.centerRight, + excludedRect.bottomCenter, + ], + ), + ) + // Hover highlight for the hovered destination (the one with 'favorite' icon). + ..rect( + rect: indicatorRect, + color: const Color(0x0a6750a4), + ) + // Indicator for the selected destination (the one with 'bookmark' icon). + ..rrect( + rrect: RRect.fromLTRBR( + indicatorLeft, + secondIndicatorVerticalOffset, + indicatorRight, + secondIndicatorVerticalOffset + indicatorHeight, + const Radius.circular(16), + ), color: const Color(0xffe8def8), ), ); @@ -5228,10 +5346,14 @@ Future<void> _pumpNavigationRail( double textScaleFactor = 1.0, required NavigationRail navigationRail, bool useMaterial3 = true, + NavigationRailThemeData? navigationRailTheme, }) async { await tester.pumpWidget( MaterialApp( - theme: ThemeData(useMaterial3: useMaterial3), + theme: ThemeData( + useMaterial3: useMaterial3, + navigationRailTheme: navigationRailTheme, + ), home: Builder( builder: (BuildContext context) { return MediaQuery( From 5c09ccad392e51e7e28561a80cbf0a0b5538e237 Mon Sep 17 00:00:00 2001 From: Alex Li <github@alexv525.com> Date: Fri, 15 Sep 2023 02:29:18 +0800 Subject: [PATCH 1270/1547] =?UTF-8?q?=F0=9F=90=9B=20Setup=20color=20tween?= =?UTF-8?q?=20for=20`RefreshIndicator`=20in=20a=20better=20way=20(#134492)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/flutter/flutter/issues/134489. --- .../lib/src/material/refresh_indicator.dart | 45 +++++++------ .../test/material/refresh_indicator_test.dart | 63 +++++++++++++++++++ 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/packages/flutter/lib/src/material/refresh_indicator.dart b/packages/flutter/lib/src/material/refresh_indicator.dart index 47791c416ecb4..0fed2b47849ed 100644 --- a/packages/flutter/lib/src/material/refresh_indicator.dart +++ b/packages/flutter/lib/src/material/refresh_indicator.dart @@ -275,6 +275,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS late Future<void> _pendingRefreshFuture; bool? _isIndicatorAtTop; double? _dragOffset; + late Color _effectiveValueColor = widget.color ?? Theme.of(context).colorScheme.primary; static final Animatable<double> _threeQuarterTween = Tween<double>(begin: 0.0, end: 0.75); static final Animatable<double> _kDragSizeFactorLimitTween = Tween<double>(begin: 0.0, end: _kDragSizeFactorLimit); @@ -293,15 +294,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS @override void didChangeDependencies() { - final ThemeData theme = Theme.of(context); - _valueColor = _positionController.drive( - ColorTween( - begin: (widget.color ?? theme.colorScheme.primary).withOpacity(0.0), - end: (widget.color ?? theme.colorScheme.primary).withOpacity(1.0), - ).chain(CurveTween( - curve: const Interval(0.0, 1.0 / _kDragSizeFactorLimit), - )), - ); + _setupColorTween(); super.didChangeDependencies(); } @@ -309,15 +302,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS void didUpdateWidget(covariant RefreshIndicator oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.color != widget.color) { - final ThemeData theme = Theme.of(context); - _valueColor = _positionController.drive( - ColorTween( - begin: (widget.color ?? theme.colorScheme.primary).withOpacity(0.0), - end: (widget.color ?? theme.colorScheme.primary).withOpacity(1.0), - ).chain(CurveTween( - curve: const Interval(0.0, 1.0 / _kDragSizeFactorLimit), - )), - ); + _setupColorTween(); } } @@ -328,6 +313,28 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS super.dispose(); } + void _setupColorTween() { + // Reset the current value color. + _effectiveValueColor = widget.color ?? Theme.of(context).colorScheme.primary; + final Color color = _effectiveValueColor; + if (color.alpha == 0x00) { + // Set an always stopped animation instead of a driven tween. + _valueColor = AlwaysStoppedAnimation<Color>(color); + } else { + // Respect the alpha of the given color. + _valueColor = _positionController.drive( + ColorTween( + begin: color.withAlpha(0), + end: color.withAlpha(color.alpha), + ).chain( + CurveTween( + curve: const Interval(0.0, 1.0 / _kDragSizeFactorLimit), + ), + ), + ); + } + } + bool _shouldStart(ScrollNotification notification) { // If the notification.dragDetails is null, this scroll is not triggered by // user dragging. It may be a result of ScrollController.jumpTo or ballistic scroll. @@ -448,7 +455,7 @@ class RefreshIndicatorState extends State<RefreshIndicator> with TickerProviderS newValue = math.max(newValue, 1.0 / _kDragSizeFactorLimit); } _positionController.value = clampDouble(newValue, 0.0, 1.0); // this triggers various rebuilds - if (_mode == _RefreshIndicatorMode.drag && _valueColor.value!.alpha == 0xFF) { + if (_mode == _RefreshIndicatorMode.drag && _valueColor.value!.alpha == _effectiveValueColor.alpha) { _mode = _RefreshIndicatorMode.armed; } } diff --git a/packages/flutter/test/material/refresh_indicator_test.dart b/packages/flutter/test/material/refresh_indicator_test.dart index ede579db2e55d..e3c1bd8933337 100644 --- a/packages/flutter/test/material/refresh_indicator_test.dart +++ b/packages/flutter/test/material/refresh_indicator_test.dart @@ -1070,4 +1070,67 @@ void main() { expect(refreshCalled, true); expect(stretchAccepted, false); }); + + testWidgetsWithLeakTracking('RefreshIndicator manipulates value color opacity correctly', (WidgetTester tester) async { + final List<Color> colors = <Color>[ + Colors.black, + Colors.black54, + Colors.white, + Colors.white54, + Colors.transparent, + ]; + const List<double> positions = <double>[50.0, 100.0, 150.0]; + + Future<void> testColor(Color color) async { + final AnimationController positionController = AnimationController(vsync: const TestVSync()); + // Correspond to [_setupColorTween]. + final Animation<Color?> valueColorAnimation = positionController.drive( + ColorTween( + begin: color.withAlpha(0), + end: color.withAlpha(color.alpha), + ).chain( + CurveTween( + // Correspond to [_kDragSizeFactorLimit]. + curve: const Interval(0.0, 1.0 / 1.5), + ), + ), + ); + await tester.pumpWidget( + MaterialApp( + home: RefreshIndicator( + onRefresh: refresh, + color: color, + child: ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: const <Widget>[Text('X')], + ), + ), + ), + ); + + RefreshProgressIndicator getIndicator() { + return tester.widget<RefreshProgressIndicator>( + find.byType(RefreshProgressIndicator), + ); + } + + // Correspond to [_kDragContainerExtentPercentage]. + final double maxPosition = tester.view.physicalSize.height / tester.view.devicePixelRatio * 0.25; + for (final double position in positions) { + await tester.fling(find.text('X'), Offset(0.0, position), 1.0); + await tester.pump(); + positionController.value = position / maxPosition; + expect( + getIndicator().valueColor!.value!.alpha, + valueColorAnimation.value!.alpha, + ); + // Wait until the fling finishes before starting the next fling. + await tester.pumpAndSettle(); + } + } + + for (final Color color in colors) { + await testColor(color); + } + }); } From d2ff24172b66635cbe520c80480840bd29f728a8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 14:31:36 -0400 Subject: [PATCH 1271/1547] Roll Flutter Engine from 4160ebacdae2 to 2cd34d23c1a2 (18 revisions) (#134749) https://github.com/flutter/engine/compare/4160ebacdae2...2cd34d23c1a2 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 91d5a781ebaf to 54253f58533d (2 revisions) (flutter/engine#45829) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 08fb9768d1b8 to 91d5a781ebaf (3 revisions) (flutter/engine#45828) 2023-09-14 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from f4jtyOMeNSKGqqI4y... to FF4r9-tqhioBbRG9f... (flutter/engine#45827) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 45ba26fae9cd to 08fb9768d1b8 (2 revisions) (flutter/engine#45825) 2023-09-14 godofredoc@google.com Fix script (flutter/engine#45598) 2023-09-14 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 5aKvHj_QcSHJkbWjr... to MzLcTzBiWJ7o3Q2_Z... (flutter/engine#45823) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 4bb29f80ed43 to 45ba26fae9cd (1 revision) (flutter/engine#45821) 2023-09-14 49699333+dependabot[bot]@users.noreply.github.com Bump html from 0.15.0 to 0.15.4 in /lib/web_ui (flutter/engine#45819) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 5ff47ea11c13 to 4bb29f80ed43 (1 revision) (flutter/engine#45818) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 5f18d2ead8c8 to 5ff47ea11c13 (1 revision) (flutter/engine#45815) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from b2a4969c7782 to 5f18d2ead8c8 (2 revisions) (flutter/engine#45814) 2023-09-14 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from gHhOd3d6V3Zv6CzK2... to f4jtyOMeNSKGqqI4y... (flutter/engine#45813) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from ad51509c8e3f to b2a4969c7782 (3 revisions) (flutter/engine#45812) 2023-09-14 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ftcEc93bjtc0q2a6s... to 5aKvHj_QcSHJkbWjr... (flutter/engine#45808) 2023-09-14 49699333+dependabot[bot]@users.noreply.github.com Bump uuid from 3.0.6 to 4.0.0 in /lib/web_ui (flutter/engine#45794) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from 5c7d604c81b0 to ad51509c8e3f (1 revision) (flutter/engine#45802) 2023-09-13 jacksongardner@google.com Compile a platform dill for dart2wasm (flutter/engine#45797) 2023-09-13 skia-flutter-autoroll@skia.org Roll Skia from a30fbf83f2e9 to 5c7d604c81b0 (2 revisions) (flutter/engine#45800) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ftcEc93bjtc0 to MzLcTzBiWJ7o fuchsia/sdk/core/mac-amd64 from gHhOd3d6V3Zv to FF4r9-tqhioB If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 72f3c176c51a7..81b116fc1b92d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4160ebacdae2081d6f3160432f5f0dd87dbebec1 +2cd34d23c1a290936d4ce5e62f68cff612c9dbc6 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 2c68ed00ec956..e55c23ede46d4 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ftcEc93bjtc0q2a6skMN1MORORVVwcAJIW8gUyhP_Q4C +MzLcTzBiWJ7o3Q2_ZoCskAyXV_qzdvkqbOC7R1VhrY8C diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 958c35133ad8a..292bb8d6f999c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -gHhOd3d6V3Zv6CzK2s7BcyuC4jOjrn9t1vfN-QWP3nMC +FF4r9-tqhioBbRG9fMFASuWfOKHBuLBdZtdnlvEPZY0C From 5467363306291c681e7804a43b8335e8a17104fc Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:36:55 +0200 Subject: [PATCH 1272/1547] Cover some Services tests with leak tracing (#134381) --- packages/flutter/test/services/asset_bundle_test.dart | 5 +++-- packages/flutter/test/services/lifecycle_test.dart | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/flutter/test/services/asset_bundle_test.dart b/packages/flutter/test/services/asset_bundle_test.dart index c6946425d2256..2177935357c80 100644 --- a/packages/flutter/test/services/asset_bundle_test.dart +++ b/packages/flutter/test/services/asset_bundle_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestAssetBundle extends CachingAssetBundle { Map<String, int> loadCallCount = <String, int>{}; @@ -135,7 +136,7 @@ void main() { expect(await data, 1); }); - testWidgets('loadStructuredData handles exceptions correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('loadStructuredData handles exceptions correctly', (WidgetTester tester) async { final TestAssetBundle bundle = TestAssetBundle(); try { await bundle.loadStructuredData('AssetManifest.json', (String value) => Future<String>.error('what do they say?')); @@ -145,7 +146,7 @@ void main() { } }); - testWidgets('loadStructuredBinaryData handles exceptions correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('loadStructuredBinaryData handles exceptions correctly', (WidgetTester tester) async { final TestAssetBundle bundle = TestAssetBundle(); try { await bundle.loadStructuredBinaryData('AssetManifest.bin', (ByteData value) => Future<String>.error('buy more crystals')); diff --git a/packages/flutter/test/services/lifecycle_test.dart b/packages/flutter/test/services/lifecycle_test.dart index c275691b3cd0c..6737ce15fa1cf 100644 --- a/packages/flutter/test/services/lifecycle_test.dart +++ b/packages/flutter/test/services/lifecycle_test.dart @@ -6,9 +6,10 @@ import 'dart:ui'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('initialLifecycleState is used to init state paused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('initialLifecycleState is used to init state paused', (WidgetTester tester) async { expect(ServicesBinding.instance.lifecycleState, isNull); final TestWidgetsFlutterBinding binding = tester.binding; binding.resetLifecycleState(); @@ -20,7 +21,7 @@ void main() { // even though no lifecycle event was fired from the platform. expect(binding.lifecycleState.toString(), equals('AppLifecycleState.paused')); }); - testWidgets('Handles all of the allowed states of AppLifecycleState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Handles all of the allowed states of AppLifecycleState', (WidgetTester tester) async { final TestWidgetsFlutterBinding binding = tester.binding; for (final AppLifecycleState state in AppLifecycleState.values) { binding.resetLifecycleState(); From eb4b97d63c1640e704d2d59b1d5833190052ab1b Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Thu, 14 Sep 2023 13:56:00 -0500 Subject: [PATCH 1273/1547] Set xcode version to older compatible version for microbenchmarks_ios_xcode_debug test (#134693) Test added in https://github.com/flutter/flutter/pull/134493 requires an older version of Xcode because default version of Xcode is not compatible with macOS version in CI. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 59ae1ab2bd1c1..475a91c640683 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4088,6 +4088,10 @@ targets: tags: > ["devicelab", "ios", "mac"] task_name: microbenchmarks_ios_xcode_debug + $flutter/osx_sdk : >- + { + "sdk_version": "14c18" + } bringup: true - name: Mac_ios native_assets_ios_simulator From ba233b8a1a85a206cdf87aa319691c58485b714e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 15:13:12 -0400 Subject: [PATCH 1274/1547] Roll Flutter Engine from 2cd34d23c1a2 to e0b5b6c4eb76 (2 revisions) (#134755) https://github.com/flutter/engine/compare/2cd34d23c1a2...e0b5b6c4eb76 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 54253f58533d to 87025d1e162c (1 revision) (flutter/engine#45833) 2023-09-14 bdero@google.com [Impeller] Incorporate filters in subpass coverage. (flutter/engine#45778) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 81b116fc1b92d..8cef192f2f77f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2cd34d23c1a290936d4ce5e62f68cff612c9dbc6 +e0b5b6c4eb7632df420e2724b8a71f05e2593db7 From ff10c52ad6de098b4946f9ef33fdde8ebd5bc594 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Thu, 14 Sep 2023 21:26:41 +0200 Subject: [PATCH 1275/1547] Cover more test/widgets tests with leak tracking #3 (#134576) --- packages/flutter/test/widgets/form_test.dart | 47 +++---- .../widgets/fractionally_sized_box_test.dart | 9 +- .../flutter/test/widgets/framework_test.dart | 115 ++++++++++-------- .../gesture_detector_semantics_test.dart | 43 +++---- .../test/widgets/gesture_detector_test.dart | 43 +++---- .../widgets/gesture_disambiguation_test.dart | 3 +- .../widgets/global_keys_duplicated_test.dart | 9 +- .../test/widgets/global_keys_moving_test.dart | 3 +- .../flutter/test/widgets/grid_paper_test.dart | 3 +- .../test/widgets/grid_view_layout_test.dart | 3 +- .../flutter/test/widgets/grid_view_test.dart | 76 +++++++----- .../flutter/test/widgets/heroes_test.dart | 96 ++++++++------- .../test/widgets/hit_testing_test.dart | 7 +- .../flutter/test/widgets/hyperlink_test.dart | 3 +- packages/flutter/test/widgets/icon_test.dart | 31 ++--- .../widgets/image_filter_quality_test.dart | 7 +- .../test/widgets/image_filter_test.dart | 17 +-- .../test/widgets/image_headers_test.dart | 3 +- .../flutter/test/widgets/image_icon_test.dart | 15 +-- .../test/widgets/image_resolution_test.dart | 32 +++-- .../flutter/test/widgets/image_rtl_test.dart | 41 ++++--- 21 files changed, 333 insertions(+), 273 deletions(-) diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart index 6fa4bbd42acd6..90f5fe727bf33 100644 --- a/packages/flutter/test/widgets/form_test.dart +++ b/packages/flutter/test/widgets/form_test.dart @@ -6,9 +6,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('onSaved callback is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSaved callback is called', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); String? fieldValue; @@ -48,7 +49,7 @@ void main() { await checkText(''); }); - testWidgets('onChanged callback is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onChanged callback is called', (WidgetTester tester) async { String? fieldValue; Widget builder() { @@ -85,7 +86,7 @@ void main() { await checkText(''); }); - testWidgets('Validator sets the error text only when validate is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Validator sets the error text only when validate is called', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); String? errorText(String? value) => '${value ?? ''}/error'; @@ -139,7 +140,7 @@ void main() { await checkErrorText(''); }); - testWidgets('Should announce error text when validate returns error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Should announce error text when validate returns error', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); await tester.pumpWidget( MaterialApp( @@ -178,7 +179,7 @@ void main() { }); - testWidgets('isValid returns true when a field is valid', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isValid returns true when a field is valid', (WidgetTester tester) async { final GlobalKey<FormFieldState<String>> fieldKey1 = GlobalKey<FormFieldState<String>>(); final GlobalKey<FormFieldState<String>> fieldKey2 = GlobalKey<FormFieldState<String>>(); const String validString = 'Valid string'; @@ -223,7 +224,7 @@ void main() { expect(fieldKey2.currentState!.isValid, isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'isValid returns false when the field is invalid and does not change error display', (WidgetTester tester) async { final GlobalKey<FormFieldState<String>> fieldKey1 = GlobalKey<FormFieldState<String>>(); @@ -272,7 +273,7 @@ void main() { }, ); - testWidgets('Multiple TextFormFields communicate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiple TextFormFields communicate', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); final GlobalKey<FormFieldState<String>> fieldKey = GlobalKey<FormFieldState<String>>(); // Input 2's validator depends on a input 1's value. @@ -322,7 +323,7 @@ void main() { await checkErrorText(''); }); - testWidgets('Provide initial value to input when no controller is specified', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Provide initial value to input when no controller is specified', (WidgetTester tester) async { const String initialValue = 'hello'; final GlobalKey<FormFieldState<String>> inputKey = GlobalKey<FormFieldState<String>>(); @@ -366,8 +367,9 @@ void main() { expect(editableText.widget.controller.text, equals('world')); }); - testWidgets('Controller defines initial value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Controller defines initial value', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'hello'); + addTearDown(controller.dispose); const String initialValue = 'hello'; final GlobalKey<FormFieldState<String>> inputKey = GlobalKey<FormFieldState<String>>(); @@ -413,10 +415,11 @@ void main() { expect(controller.text, equals('world')); }); - testWidgets('TextFormField resets to its initial value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextFormField resets to its initial value', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); final GlobalKey<FormFieldState<String>> inputKey = GlobalKey<FormFieldState<String>>(); final TextEditingController controller = TextEditingController(text: 'Plover'); + addTearDown(controller.dispose); Widget builder() { return MaterialApp( @@ -459,9 +462,11 @@ void main() { expect(controller.text, equals('Plover')); }); - testWidgets('TextEditingController updates to/from form field value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextEditingController updates to/from form field value', (WidgetTester tester) async { final TextEditingController controller1 = TextEditingController(text: 'Foo'); + addTearDown(controller1.dispose); final TextEditingController controller2 = TextEditingController(text: 'Bar'); + addTearDown(controller2.dispose); final GlobalKey<FormFieldState<String>> inputKey = GlobalKey<FormFieldState<String>>(); TextEditingController? currentController; @@ -566,7 +571,7 @@ void main() { expect(controller2.text, equals('Xyzzy')); }); - testWidgets('No crash when a TextFormField is removed from the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No crash when a TextFormField is removed from the tree', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); String? fieldValue; @@ -620,7 +625,7 @@ void main() { expect(formKey.currentState!.validate(), isTrue); }); - testWidgets('Does not auto-validate before value changes when autovalidateMode is set to onUserInteraction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not auto-validate before value changes when autovalidateMode is set to onUserInteraction', (WidgetTester tester) async { late FormFieldState<String> formFieldState; String? errorText(String? value) => '$value/error'; @@ -656,7 +661,7 @@ void main() { expect(find.text(errorText('foo')!), findsNothing); }); - testWidgets('auto-validate before value changes if autovalidateMode was set to always', (WidgetTester tester) async { + testWidgetsWithLeakTracking('auto-validate before value changes if autovalidateMode was set to always', (WidgetTester tester) async { late FormFieldState<String> formFieldState; String? errorText(String? value) => '$value/error'; @@ -689,7 +694,7 @@ void main() { expect(formFieldState.hasError, isTrue); }); - testWidgets('Form auto-validates form fields only after one of them changes if autovalidateMode is onUserInteraction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Form auto-validates form fields only after one of them changes if autovalidateMode is onUserInteraction', (WidgetTester tester) async { const String initialValue = 'foo'; String? errorText(String? value) => 'error/$value'; @@ -743,7 +748,7 @@ void main() { expect(find.text(errorText(initialValue)!), findsNWidgets(2)); }); - testWidgets('Form auto-validates form fields even before any have changed if autovalidateMode is set to always', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Form auto-validates form fields even before any have changed if autovalidateMode is set to always', (WidgetTester tester) async { String? errorText(String? value) => 'error/$value'; Widget builder() { @@ -773,7 +778,7 @@ void main() { expect(find.text(errorText('')!), findsOneWidget); }); - testWidgets('Form.reset() resets form fields, and auto validation will only happen on the next user interaction if autovalidateMode is onUserInteraction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Form.reset() resets form fields, and auto validation will only happen on the next user interaction if autovalidateMode is onUserInteraction', (WidgetTester tester) async { final GlobalKey<FormState> formState = GlobalKey<FormState>(); String? errorText(String? value) => '$value/error'; @@ -818,7 +823,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/63753. - testWidgets('Validate form should return correct validation if the value is composing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Validate form should return correct validation if the value is composing', (WidgetTester tester) async { final GlobalKey<FormState> formKey = GlobalKey<FormState>(); String? fieldValue; @@ -855,7 +860,7 @@ void main() { expect(formKey.currentState!.validate(), isFalse); }); - testWidgets('hasInteractedByUser returns false when the input has not changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hasInteractedByUser returns false when the input has not changed', (WidgetTester tester) async { final GlobalKey<FormFieldState<String>> fieldKey = GlobalKey<FormFieldState<String>>(); final Widget widget = MaterialApp( @@ -879,7 +884,7 @@ void main() { expect(fieldKey.currentState!.hasInteractedByUser, isFalse); }); - testWidgets('hasInteractedByUser returns true after the input has changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hasInteractedByUser returns true after the input has changed', (WidgetTester tester) async { final GlobalKey<FormFieldState<String>> fieldKey = GlobalKey<FormFieldState<String>>(); final Widget widget = MaterialApp( @@ -908,7 +913,7 @@ void main() { expect(fieldKey.currentState!.hasInteractedByUser, isTrue); }); - testWidgets('hasInteractedByUser returns false after the field is reset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hasInteractedByUser returns false after the field is reset', (WidgetTester tester) async { final GlobalKey<FormFieldState<String>> fieldKey = GlobalKey<FormFieldState<String>>(); final Widget widget = MaterialApp( diff --git a/packages/flutter/test/widgets/fractionally_sized_box_test.dart b/packages/flutter/test/widgets/fractionally_sized_box_test.dart index ddebf06919963..1a9f7ef67574f 100644 --- a/packages/flutter/test/widgets/fractionally_sized_box_test.dart +++ b/packages/flutter/test/widgets/fractionally_sized_box_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('FractionallySizedBox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FractionallySizedBox', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(OverflowBox( minWidth: 0.0, @@ -29,7 +30,7 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(const Offset(25.0, 37.5))); }); - testWidgets('FractionallySizedBox alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FractionallySizedBox alignment', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.rtl, @@ -45,7 +46,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(800.0 - 400.0 / 2.0, 0.0 + 300.0 / 2.0))); }); - testWidgets('FractionallySizedBox alignment (direction-sensitive)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FractionallySizedBox alignment (direction-sensitive)', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.rtl, @@ -61,7 +62,7 @@ void main() { expect(box.localToGlobal(box.size.center(Offset.zero)), equals(const Offset(0.0 + 400.0 / 2.0, 0.0 + 300.0 / 2.0))); }); - testWidgets('OverflowBox alignment with FractionallySizedBox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBox alignment with FractionallySizedBox', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.rtl, diff --git a/packages/flutter/test/widgets/framework_test.dart b/packages/flutter/test/widgets/framework_test.dart index 4d82aa85308ab..bfa44287a29fd 100644 --- a/packages/flutter/test/widgets/framework_test.dart +++ b/packages/flutter/test/widgets/framework_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; typedef ElementRebuildCallback = void Function(StatefulElement element); @@ -22,13 +23,13 @@ class _MyGlobalObjectKey<T extends State<StatefulWidget>> extends GlobalObjectKe } void main() { - testWidgets('UniqueKey control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UniqueKey control test', (WidgetTester tester) async { final Key key = UniqueKey(); expect(key, hasOneLineDescription); expect(key, isNot(equals(UniqueKey()))); }); - testWidgets('ObjectKey control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ObjectKey control test', (WidgetTester tester) async { final Object a = Object(); final Object b = Object(); final Key keyA = ObjectKey(a); @@ -41,7 +42,7 @@ void main() { expect(keyA, isNot(equals(keyB))); }); - testWidgets('GlobalObjectKey toString test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalObjectKey toString test', (WidgetTester tester) async { const GlobalObjectKey one = GlobalObjectKey(1); const GlobalObjectKey<TestState> two = GlobalObjectKey<TestState>(2); const GlobalObjectKey three = _MyGlobalObjectKey(3); @@ -53,7 +54,7 @@ void main() { expect(four.toString(), equals('[_MyGlobalObjectKey<TestState> ${describeIdentity(4)}]')); }); - testWidgets('GlobalObjectKey control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalObjectKey control test', (WidgetTester tester) async { final Object a = Object(); final Object b = Object(); final Key keyA = GlobalObjectKey(a); @@ -66,7 +67,7 @@ void main() { expect(keyA, isNot(equals(keyB))); }); - testWidgets('GlobalKey correct case 1 - can move global key from container widget to layoutbuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey correct case 1 - can move global key from container widget to layoutbuilder', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'correct'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -101,7 +102,7 @@ void main() { )); }); - testWidgets('GlobalKey correct case 2 - can move global key from layoutbuilder to container widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey correct case 2 - can move global key from layoutbuilder to container widget', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'correct'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -135,7 +136,7 @@ void main() { )); }); - testWidgets('GlobalKey correct case 3 - can deal with early rebuild in layoutbuilder - move backward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey correct case 3 - can deal with early rebuild in layoutbuilder - move backward', (WidgetTester tester) async { const Key key1 = GlobalObjectKey('Text1'); const Key key2 = GlobalObjectKey('Text2'); Key? rebuiltKeyOfSecondChildBeforeLayout; @@ -224,7 +225,7 @@ void main() { expect(rebuiltKeyOfSecondChildAfterLayout, key1); }); - testWidgets('GlobalKey correct case 4 - can deal with early rebuild in layoutbuilder - move forward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey correct case 4 - can deal with early rebuild in layoutbuilder - move forward', (WidgetTester tester) async { const Key key1 = GlobalObjectKey('Text1'); const Key key2 = GlobalObjectKey('Text2'); const Key key3 = GlobalObjectKey('Text3'); @@ -327,7 +328,7 @@ void main() { expect(rebuiltKeyOfThirdChildAfterLayout, key2); }); - testWidgets('GlobalKey correct case 5 - can deal with early rebuild in layoutbuilder - only one global key', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey correct case 5 - can deal with early rebuild in layoutbuilder - only one global key', (WidgetTester tester) async { const Key key1 = GlobalObjectKey('Text1'); Key? rebuiltKeyOfSecondChildBeforeLayout; Key? rebuiltKeyOfThirdChildAfterLayout; @@ -418,7 +419,7 @@ void main() { expect(rebuiltKeyOfThirdChildAfterLayout, key1); }); - testWidgets('GlobalKey duplication 1 - double appearance', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 1 - double appearance', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -447,7 +448,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 2 - splitting and changing type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 2 - splitting and changing type', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( @@ -493,7 +494,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 3 - splitting and changing type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 3 - splitting and changing type', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -520,7 +521,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 4 - splitting and half changing type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 4 - splitting and half changing type', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -547,7 +548,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 5 - splitting and half changing type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 5 - splitting and half changing type', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -565,7 +566,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 6 - splitting and not changing type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 6 - splitting and not changing type', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -583,7 +584,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 7 - appearing later', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 7 - appearing later', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -602,7 +603,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 8 - appearing earlier', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 8 - appearing earlier', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -621,7 +622,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 9 - moving and appearing later', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 9 - moving and appearing later', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -642,7 +643,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 10 - moving and appearing earlier', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 10 - moving and appearing earlier', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -663,7 +664,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 11 - double sibling appearance', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 11 - double sibling appearance', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -675,7 +676,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 12 - all kinds of badness at once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 12 - all kinds of badness at once', (WidgetTester tester) async { final Key key1 = GlobalKey(debugLabel: 'problematic'); final Key key2 = GlobalKey(debugLabel: 'problematic'); // intentionally the same label final Key key3 = GlobalKey(debugLabel: 'also problematic'); @@ -723,7 +724,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 13 - all kinds of badness at once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 13 - all kinds of badness at once', (WidgetTester tester) async { final Key key1 = GlobalKey(debugLabel: 'problematic'); final Key key2 = GlobalKey(debugLabel: 'problematic'); // intentionally the same label final Key key3 = GlobalKey(debugLabel: 'also problematic'); @@ -770,7 +771,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 14 - moving during build - before', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 14 - moving during build - before', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -789,7 +790,7 @@ void main() { )); }); - testWidgets('GlobalKey duplication 15 - duplicating during build - before', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 15 - duplicating during build - before', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -810,7 +811,7 @@ void main() { expect(tester.takeException(), isFlutterError); }); - testWidgets('GlobalKey duplication 16 - moving during build - after', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 16 - moving during build - after', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -829,7 +830,7 @@ void main() { )); }); - testWidgets('GlobalKey duplication 17 - duplicating during build - after', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 17 - duplicating during build - after', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); await tester.pumpWidget(Stack( textDirection: TextDirection.ltr, @@ -857,7 +858,7 @@ void main() { expect(count, 1); }); - testWidgets('GlobalKey duplication 18 - subtree build duplicate key with same type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 18 - subtree build duplicate key with same type', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); final Stack stack = Stack( textDirection: TextDirection.ltr, @@ -894,7 +895,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 19 - subtree build duplicate key with different types', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 19 - subtree build duplicate key with different types', (WidgetTester tester) async { final Key key = GlobalKey(debugLabel: 'problematic'); final Stack stack = Stack( textDirection: TextDirection.ltr, @@ -922,7 +923,7 @@ void main() { ); }); - testWidgets('GlobalKey duplication 20 - real duplication with early rebuild in layoutbuilder will throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey duplication 20 - real duplication with early rebuild in layoutbuilder will throw', (WidgetTester tester) async { const Key key1 = GlobalObjectKey('Text1'); const Key key2 = GlobalObjectKey('Text2'); Key? rebuiltKeyOfSecondChildBeforeLayout; @@ -1023,14 +1024,17 @@ void main() { ); }); - testWidgets('GlobalKey - detach and re-attach child to different parents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey - detach and re-attach child to different parents', (WidgetTester tester) async { + final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); + await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Center( child: SizedBox( height: 100, child: CustomScrollView( - controller: ScrollController(), + controller: scrollController, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(<Widget>[ @@ -1058,7 +1062,7 @@ void main() { element.createChild(0, after: null); }); - testWidgets('GlobalKey - re-attach child to new parents, and the old parent is deactivated(unmounted)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey - re-attach child to new parents, and the old parent is deactivated(unmounted)', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/62055 const Key key1 = GlobalObjectKey('key1'); const Key key2 = GlobalObjectKey('key2'); @@ -1104,7 +1108,7 @@ void main() { expect(tabController.index, 0); }); - testWidgets('Defunct setState throws exception', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Defunct setState throws exception', (WidgetTester tester) async { late StateSetter setState; await tester.pumpWidget(StatefulBuilder( @@ -1122,12 +1126,12 @@ void main() { expect(() { setState(() { }); }, throwsFlutterError); }); - testWidgets('State toString', (WidgetTester tester) async { + testWidgetsWithLeakTracking('State toString', (WidgetTester tester) async { final TestState state = TestState(); expect(state.toString(), contains('no widget')); }); - testWidgets('debugPrintGlobalKeyedWidgetLifecycle control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugPrintGlobalKeyedWidgetLifecycle control test', (WidgetTester tester) async { expect(debugPrintGlobalKeyedWidgetLifecycle, isFalse); final DebugPrintCallback oldCallback = debugPrint; @@ -1150,7 +1154,7 @@ void main() { expect(log[1], matches('Discarding .+ from inactive elements list.')); }); - testWidgets('MultiChildRenderObjectElement.children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MultiChildRenderObjectElement.children', (WidgetTester tester) async { GlobalKey key0, key1, key2; await tester.pumpWidget(Column( key: key0 = GlobalKey(), @@ -1169,7 +1173,7 @@ void main() { ); }); - testWidgets('Can not attach a non-RenderObjectElement to the MultiChildRenderObjectElement - mount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can not attach a non-RenderObjectElement to the MultiChildRenderObjectElement - mount', (WidgetTester tester) async { await tester.pumpWidget( Column( children: <Widget>[ @@ -1194,7 +1198,7 @@ void main() { ); }); - testWidgets('Can not attach a non-RenderObjectElement to the MultiChildRenderObjectElement - update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can not attach a non-RenderObjectElement to the MultiChildRenderObjectElement - update', (WidgetTester tester) async { await tester.pumpWidget( Column( children: <Widget>[ @@ -1227,7 +1231,7 @@ void main() { ); }); - testWidgets('Element diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Element diagnostics', (WidgetTester tester) async { GlobalKey key0; await tester.pumpWidget(Column( key: key0 = GlobalKey(), @@ -1319,7 +1323,7 @@ void main() { } }); - testWidgets('didUpdateDependencies is not called on a State that never rebuilds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('didUpdateDependencies is not called on a State that never rebuilds', (WidgetTester tester) async { final GlobalKey<DependentState> key = GlobalKey<DependentState>(); /// Initial build - should call didChangeDependencies, not deactivate @@ -1348,7 +1352,7 @@ void main() { expect(state.deactivatedCount, 2); }); - testWidgets('StatefulElement subclass can decorate State.build', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StatefulElement subclass can decorate State.build', (WidgetTester tester) async { late bool isDidChangeDependenciesDecorated; late bool isBuildDecorated; @@ -1372,7 +1376,7 @@ void main() { expect(isDidChangeDependenciesDecorated, isFalse); }); group('BuildContext.debugDoingbuild', () { - testWidgets('StatelessWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StatelessWidget', (WidgetTester tester) async { late bool debugDoingBuildOnBuild; await tester.pumpWidget( StatelessWidgetSpy( @@ -1387,7 +1391,7 @@ void main() { expect(context.debugDoingBuild, isFalse); expect(debugDoingBuildOnBuild, isTrue); }); - testWidgets('StatefulWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('StatefulWidget', (WidgetTester tester) async { late bool debugDoingBuildOnBuild; late bool debugDoingBuildOnInitState; late bool debugDoingBuildOnDidChangeDependencies; @@ -1456,11 +1460,12 @@ void main() { expect(debugDoingBuildOnDispose, isFalse); expect(debugDoingBuildOnDeactivate, isFalse); }); - testWidgets('RenderObjectWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjectWidget', (WidgetTester tester) async { late bool debugDoingBuildOnCreateRenderObject; bool? debugDoingBuildOnUpdateRenderObject; bool? debugDoingBuildOnDidUnmountRenderObject; final ValueNotifier<int> notifier = ValueNotifier<int>(0); + addTearDown(notifier.dispose); late BuildContext spyContext; @@ -1516,7 +1521,7 @@ void main() { }); }); - testWidgets('A widget whose element has an invalid visitChildren implementation triggers a useful error message', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A widget whose element has an invalid visitChildren implementation triggers a useful error message', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(_WidgetWithNoVisitChildren(_StatefulLeaf(key: key))); (key.currentState! as _StatefulLeafState).markNeedsBuild(); @@ -1542,11 +1547,13 @@ void main() { ); }); - testWidgets('Can create BuildOwner that does not interfere with pointer router or raw key event handler', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can create BuildOwner that does not interfere with pointer router or raw key event handler', (WidgetTester tester) async { final int pointerRouterCount = GestureBinding.instance.pointerRouter.debugGlobalRouteCount; final RawKeyEventHandler? rawKeyEventHandler = RawKeyboard.instance.keyEventHandler; expect(rawKeyEventHandler, isNotNull); - BuildOwner(focusManager: FocusManager()); + final FocusManager focusManager = FocusManager(); + addTearDown(focusManager.dispose); + BuildOwner(focusManager: focusManager); expect(GestureBinding.instance.pointerRouter.debugGlobalRouteCount, pointerRouterCount); expect(RawKeyboard.instance.keyEventHandler, same(rawKeyEventHandler)); }); @@ -1601,7 +1608,7 @@ void main() { expect(dependenciesProperty.toDescription(), '[ButtonBarTheme, Directionality, FocusTraversalOrder]'); }); - testWidgets('BuildOwner.globalKeyCount keeps track of in-use global keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BuildOwner.globalKeyCount keeps track of in-use global keys', (WidgetTester tester) async { final int initialCount = tester.binding.buildOwner!.globalKeyCount; final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); @@ -1615,7 +1622,7 @@ void main() { expect(tester.binding.buildOwner!.globalKeyCount, initialCount + 0); }); - testWidgets('Widget and State properties are nulled out when unmounted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget and State properties are nulled out when unmounted', (WidgetTester tester) async { await tester.pumpWidget(const _StatefulLeaf()); final StatefulElement element = tester.element<StatefulElement>(find.byType(_StatefulLeaf)); expect(element.state, isA<State<_StatefulLeaf>>()); @@ -1631,7 +1638,7 @@ void main() { expect(() => element.widget, throwsA(isA<TypeError>())); }); - testWidgets('LayerLink can be swapped between parent and child container layers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LayerLink can be swapped between parent and child container layers', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/96959. final LayerLink link = LayerLink(); await tester.pumpWidget(_TestLeaderLayerWidget( @@ -1653,7 +1660,7 @@ void main() { }); - testWidgets('Deactivate and activate are called correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Deactivate and activate are called correctly', (WidgetTester tester) async { final List<String> states = <String>[]; Widget build([Key? key]) { return StatefulWidgetSpy( @@ -1687,7 +1694,7 @@ void main() { expect(states, <String>['deactivate', 'dispose']); }); - testWidgets('RenderObjectElement.unmount disposes of its renderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjectElement.unmount disposes of its renderObject', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); final RenderObjectElement element = tester.allElements.whereType<RenderObjectElement>().last; final RenderObject renderObject = element.renderObject; @@ -1699,7 +1706,7 @@ void main() { expect(renderObject.debugDisposed, true); }); - testWidgets('Getting the render object of an unmounted element throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Getting the render object of an unmounted element throws', (WidgetTester tester) async { await tester.pumpWidget(const _StatefulLeaf()); final StatefulElement element = tester.element<StatefulElement>(find.byType(_StatefulLeaf)); expect(element.state, isA<State<_StatefulLeaf>>()); @@ -1754,7 +1761,7 @@ The findRenderObject() method was called for the following element: expect(child.doesDependOnInheritedElement(ancestor), isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'MultiChildRenderObjectElement.updateChildren test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/120762. diff --git a/packages/flutter/test/widgets/gesture_detector_semantics_test.dart b/packages/flutter/test/widgets/gesture_detector_semantics_test.dart index 4632cf53bc596..fc43260892e64 100644 --- a/packages/flutter/test/widgets/gesture_detector_semantics_test.dart +++ b/packages/flutter/test/widgets/gesture_detector_semantics_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Vertical gesture detector has up/down actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical gesture detector has up/down actions', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int callCount = 0; @@ -44,7 +45,7 @@ void main() { semantics.dispose(); }); - testWidgets('Horizontal gesture detector has up/down actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal gesture detector has up/down actions', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int callCount = 0; @@ -78,7 +79,7 @@ void main() { semantics.dispose(); }); - testWidgets('All registered handlers for the gesture kind are called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('All registered handlers for the gesture kind are called', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Set<String> logs = <String>{}; @@ -102,7 +103,7 @@ void main() { semantics.dispose(); }); - testWidgets('Replacing recognizers should update semantic handlers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Replacing recognizers should update semantic handlers', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // How the test is set up: @@ -173,7 +174,7 @@ void main() { }); group("RawGestureDetector's custom semantics delegate", () { - testWidgets('should update semantics notations when switching from the default delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should update semantics notations when switching from the default delegate', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Map<Type, GestureRecognizerFactory> gestures = _buildGestureMap(() => LongPressGestureRecognizer(), null) @@ -208,7 +209,7 @@ void main() { semantics.dispose(); }); - testWidgets('should update semantics notations when switching to the default delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should update semantics notations when switching to the default delegate', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Map<Type, GestureRecognizerFactory> gestures = _buildGestureMap(() => LongPressGestureRecognizer(), null) @@ -243,7 +244,7 @@ void main() { semantics.dispose(); }); - testWidgets('should update semantics notations when switching from a different custom delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should update semantics notations when switching from a different custom delegate', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Map<Type, GestureRecognizerFactory> gestures = _buildGestureMap(() => LongPressGestureRecognizer(), null) @@ -279,7 +280,7 @@ void main() { semantics.dispose(); }); - testWidgets('should correctly call callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should correctly call callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> logs = <String>[]; final GlobalKey<RawGestureDetectorState> detectorKey = GlobalKey(); @@ -321,7 +322,7 @@ void main() { group("RawGestureDetector's default semantics delegate", () { group('should map onTap to', () { - testWidgets('null when there is no TapGR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null when there is no TapGR', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -339,7 +340,7 @@ void main() { semantics.dispose(); }); - testWidgets('non-null when there is TapGR with no callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('non-null when there is TapGR with no callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -360,7 +361,7 @@ void main() { semantics.dispose(); }); - testWidgets('a callback that correctly calls callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('a callback that correctly calls callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey detectorKey = GlobalKey(); final List<String> logs = <String>[]; @@ -394,7 +395,7 @@ void main() { }); group('should map onLongPress to', () { - testWidgets('null when there is no LongPressGR ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null when there is no LongPressGR ', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -412,7 +413,7 @@ void main() { semantics.dispose(); }); - testWidgets('non-null when there is LongPressGR with no callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('non-null when there is LongPressGR with no callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -433,7 +434,7 @@ void main() { semantics.dispose(); }); - testWidgets('a callback that correctly calls callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('a callback that correctly calls callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey detectorKey = GlobalKey(); final List<String> logs = <String>[]; @@ -466,7 +467,7 @@ void main() { }); group('should map onHorizontalDragUpdate to', () { - testWidgets('null when there is no matching recognizers ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null when there is no matching recognizers ', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -484,7 +485,7 @@ void main() { semantics.dispose(); }); - testWidgets('non-null when there is either matching recognizer with no callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('non-null when there is either matching recognizer with no callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -526,7 +527,7 @@ void main() { semantics.dispose(); }); - testWidgets('a callback that correctly calls callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('a callback that correctly calls callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey detectorKey = GlobalKey(); final List<String> logs = <String>[]; @@ -576,7 +577,7 @@ void main() { }); group('should map onVerticalDragUpdate to', () { - testWidgets('null when there is no matching recognizers ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null when there is no matching recognizers ', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -594,7 +595,7 @@ void main() { semantics.dispose(); }); - testWidgets('non-null when there is either matching recognizer with no callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('non-null when there is either matching recognizer with no callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( @@ -617,7 +618,7 @@ void main() { semantics.dispose(); }); - testWidgets('a callback that correctly calls callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('a callback that correctly calls callbacks', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey detectorKey = GlobalKey(); final List<String> logs = <String>[]; @@ -666,7 +667,7 @@ void main() { }); }); - testWidgets('should update semantics notations when receiving new gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should update semantics notations when receiving new gestures', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Center( diff --git a/packages/flutter/test/widgets/gesture_detector_test.dart b/packages/flutter/test/widgets/gesture_detector_test.dart index 40d3569d11715..3d30a8f32ff1b 100644 --- a/packages/flutter/test/widgets/gesture_detector_test.dart +++ b/packages/flutter/test/widgets/gesture_detector_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { const Offset forcePressOffset = Offset(400.0, 50.0); - testWidgets('Uncontested scrolls start immediately', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Uncontested scrolls start immediately', (WidgetTester tester) async { bool didStartDrag = false; double? updatedDragDelta; bool didEndDrag = false; @@ -58,7 +59,7 @@ void main() { await tester.pumpWidget(Container()); }); - testWidgets('Match two scroll gestures in succession', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Match two scroll gestures in succession', (WidgetTester tester) async { int gestureCount = 0; double dragDistance = 0.0; @@ -91,7 +92,7 @@ void main() { await tester.pumpWidget(Container()); }); - testWidgets("Pan doesn't crash", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Pan doesn't crash", (WidgetTester tester) async { bool didStartPan = false; Offset? panDelta; bool didEndPan = false; @@ -135,7 +136,7 @@ void main() { }, ); - testWidgets('Translucent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Translucent', (WidgetTester tester) async { bool didReceivePointerDown; bool didTap; @@ -206,7 +207,7 @@ void main() { expect(didTap, isTrue); }, variant: buttonVariant); - testWidgets('Empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty', (WidgetTester tester) async { bool didTap = false; await tester.pumpWidget( Center( @@ -228,7 +229,7 @@ void main() { expect(didTap, isTrue); }, variant: buttonVariant); - testWidgets('Only container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Only container', (WidgetTester tester) async { bool didTap = false; await tester.pumpWidget( Center( @@ -251,7 +252,7 @@ void main() { expect(didTap, isFalse); }, variant: buttonVariant); - testWidgets('cache render object', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cache render object', (WidgetTester tester) async { void inputCallback() { } await tester.pumpWidget( @@ -283,7 +284,7 @@ void main() { expect(renderObj1, same(renderObj2)); }, variant: buttonVariant); - testWidgets('Tap down occurs after kPressTimeout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap down occurs after kPressTimeout', (WidgetTester tester) async { int tapDown = 0; int tap = 0; int tapCancel = 0; @@ -391,7 +392,7 @@ void main() { expect(longPress, 1); }, variant: buttonVariant); - testWidgets('Long Press Up Callback called after long press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Long Press Up Callback called after long press', (WidgetTester tester) async { int longPressUp = 0; await tester.pumpWidget( @@ -441,7 +442,7 @@ void main() { }, variant: buttonVariant); }); - testWidgets('Primary and secondary long press callbacks should work together in GestureDetector', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Primary and secondary long press callbacks should work together in GestureDetector', (WidgetTester tester) async { bool primaryLongPress = false, secondaryLongPress = false; await tester.pumpWidget( @@ -477,7 +478,7 @@ void main() { expect(secondaryLongPress, isTrue); }); - testWidgets('Force Press Callback called after force press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Force Press Callback called after force press', (WidgetTester tester) async { int forcePressStart = 0; int forcePressPeaked = 0; int forcePressUpdate = 0; @@ -580,7 +581,7 @@ void main() { expect(forcePressEnded, 1); }); - testWidgets('Force Press Callback not called if long press triggered before force press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Force Press Callback not called if long press triggered before force press', (WidgetTester tester) async { int forcePressStart = 0; int longPressTimes = 0; @@ -645,7 +646,7 @@ void main() { expect(forcePressStart, 0); }); - testWidgets('Force Press Callback not called if drag triggered before force press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Force Press Callback not called if drag triggered before force press', (WidgetTester tester) async { int forcePressStart = 0; int horizontalDragStart = 0; @@ -706,7 +707,7 @@ void main() { }); group("RawGestureDetectorState's debugFillProperties", () { - testWidgets('when default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when default', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); final GlobalKey key = GlobalKey(); await tester.pumpWidget(RawGestureDetector( @@ -724,7 +725,7 @@ void main() { ]); }); - testWidgets('should show gestures, custom semantics and behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should show gestures, custom semantics and behavior', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); final GlobalKey key = GlobalKey(); await tester.pumpWidget(RawGestureDetector( @@ -761,7 +762,7 @@ void main() { ]); }); - testWidgets('should not show semantics when excludeFromSemantics is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should not show semantics when excludeFromSemantics is true', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); final GlobalKey key = GlobalKey(); await tester.pumpWidget(RawGestureDetector( @@ -832,7 +833,7 @@ void main() { } }); - testWidgets('replaceGestureRecognizers not during layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('replaceGestureRecognizers not during layout', (WidgetTester tester) async { final GlobalKey<RawGestureDetectorState> key = GlobalKey<RawGestureDetectorState>(); await tester.pumpWidget( Directionality( @@ -876,7 +877,7 @@ void main() { }); }); - testWidgets('supportedDevices update test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('supportedDevices update test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/111716 bool didStartPan = false; Offset? panDelta; @@ -946,7 +947,7 @@ void main() { expect(didEndPan, isTrue); }); - testWidgets('supportedDevices is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('supportedDevices is respected', (WidgetTester tester) async { bool didStartPan = false; Offset? panDelta; bool didEndPan = false; @@ -994,7 +995,7 @@ void main() { }); group('DoubleTap', () { - testWidgets('onDoubleTap is called even if onDoubleTapDown has not been not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onDoubleTap is called even if onDoubleTapDown has not been not provided', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( Directionality( @@ -1017,7 +1018,7 @@ void main() { expect(log, <String>['double-tap']); }); - testWidgets('onDoubleTapDown is called even if onDoubleTap has not been not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onDoubleTapDown is called even if onDoubleTap has not been not provided', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/gesture_disambiguation_test.dart b/packages/flutter/test/widgets/gesture_disambiguation_test.dart index 0788d5a5c1653..617e1046deb7a 100644 --- a/packages/flutter/test/widgets/gesture_disambiguation_test.dart +++ b/packages/flutter/test/widgets/gesture_disambiguation_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('onTap detection with canceled pointer and a drag listener', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap detection with canceled pointer and a drag listener', (WidgetTester tester) async { int detector1TapCount = 0; int detector2TapCount = 0; diff --git a/packages/flutter/test/widgets/global_keys_duplicated_test.dart b/packages/flutter/test/widgets/global_keys_duplicated_test.dart index ec37b19be247d..f2e2430cf8f7b 100644 --- a/packages/flutter/test/widgets/global_keys_duplicated_test.dart +++ b/packages/flutter/test/widgets/global_keys_duplicated_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // There's also some duplicate GlobalKey tests in the framework_test.dart file. void main() { - testWidgets('GlobalKey children of one node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey children of one node', (WidgetTester tester) async { // This is actually a test of the regular duplicate key logic, which // happens before the duplicate GlobalKey logic. await tester.pumpWidget(const Stack(children: <Widget>[ @@ -23,7 +24,7 @@ void main() { expect(error.toString(), contains('[GlobalObjectKey ${describeIdentity(0)}]')); }); - testWidgets('GlobalKey children of two nodes - A', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey children of two nodes - A', (WidgetTester tester) async { await tester.pumpWidget(const Stack( textDirection: TextDirection.ltr, children: <Widget>[ @@ -43,7 +44,7 @@ void main() { expect(error.toString(), endsWith('\nA GlobalKey can only be specified on one widget at a time in the widget tree.')); }); - testWidgets('GlobalKey children of two different nodes - B', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey children of two different nodes - B', (WidgetTester tester) async { await tester.pumpWidget(const Stack( textDirection: TextDirection.ltr, children: <Widget>[ @@ -61,7 +62,7 @@ void main() { expect(error.toString(), endsWith('\nA GlobalKey can only be specified on one widget at a time in the widget tree.')); }); - testWidgets('GlobalKey children of two nodes - C', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GlobalKey children of two nodes - C', (WidgetTester tester) async { late StateSetter nestedSetState; bool flag = false; await tester.pumpWidget(Stack( diff --git a/packages/flutter/test/widgets/global_keys_moving_test.dart b/packages/flutter/test/widgets/global_keys_moving_test.dart index 4984289950a31..1fd8eaf1be174 100644 --- a/packages/flutter/test/widgets/global_keys_moving_test.dart +++ b/packages/flutter/test/widgets/global_keys_moving_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Item { GlobalKey key1 = GlobalKey(); @@ -55,7 +56,7 @@ Widget builder() { } void main() { - testWidgets('moving subtrees with global keys - smoketest', (WidgetTester tester) async { + testWidgetsWithLeakTracking('moving subtrees with global keys - smoketest', (WidgetTester tester) async { await tester.pumpWidget(builder()); final StatefulLeafState leaf = tester.firstState(find.byType(StatefulLeaf)); leaf.markNeedsBuild(); diff --git a/packages/flutter/test/widgets/grid_paper_test.dart b/packages/flutter/test/widgets/grid_paper_test.dart index d64a14cfc7431..cd0c8d93bb802 100644 --- a/packages/flutter/test/widgets/grid_paper_test.dart +++ b/packages/flutter/test/widgets/grid_paper_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('GridPaper control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridPaper control test', (WidgetTester tester) async { await tester.pumpWidget(const GridPaper()); final List<Layer> layers1 = tester.layers; await tester.pumpWidget(const GridPaper()); diff --git a/packages/flutter/test/widgets/grid_view_layout_test.dart b/packages/flutter/test/widgets/grid_view_layout_test.dart index 221b96080b1be..ea1e43e725dd5 100644 --- a/packages/flutter/test/widgets/grid_view_layout_test.dart +++ b/packages/flutter/test/widgets/grid_view_layout_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Empty GridView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty GridView', (WidgetTester tester) async { final List<Widget> children = <Widget>[ const DecoratedBox(decoration: BoxDecoration()), const DecoratedBox(decoration: BoxDecoration()), diff --git a/packages/flutter/test/widgets/grid_view_test.dart b/packages/flutter/test/widgets/grid_view_test.dart index f1abdebe6fc13..03014dbd2984e 100644 --- a/packages/flutter/test/widgets/grid_view_test.dart +++ b/packages/flutter/test/widgets/grid_view_test.dart @@ -6,13 +6,14 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; import 'states.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('GridView.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -50,7 +51,7 @@ void main() { expect(finderCalled, true); }); - testWidgets('Empty GridView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty GridView', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -62,7 +63,7 @@ void main() { ); }); - testWidgets('GridView.count control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.count control test', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -135,7 +136,7 @@ void main() { log.clear(); }); - testWidgets('GridView.extent control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.extent control test', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -182,7 +183,7 @@ void main() { log.clear(); }); - testWidgets('GridView large scroll jump', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView large scroll jump', (WidgetTester tester) async { final List<int> log = <int>[]; await tester.pumpWidget( @@ -274,7 +275,7 @@ void main() { } }); - testWidgets('GridView - change crossAxisCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView - change crossAxisCount', (WidgetTester tester) async { final List<int> log = <int>[]; await tester.pumpWidget( @@ -345,7 +346,7 @@ void main() { expect(find.text('4'), findsNothing); }); - testWidgets('SliverGridRegularTileLayout - can handle close to zero mainAxisStride', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGridRegularTileLayout - can handle close to zero mainAxisStride', (WidgetTester tester) async { const SliverGridDelegateWithMaxCrossAxisExtent delegate = SliverGridDelegateWithMaxCrossAxisExtent( childAspectRatio: 1e300, maxCrossAxisExtent: 500.0, @@ -369,7 +370,7 @@ void main() { expect(layout.getMinChildIndexForScrollOffset(1000.0), 0.0); }); - testWidgets('GridView - change maxChildCrossAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView - change maxChildCrossAxisExtent', (WidgetTester tester) async { final List<int> log = <int>[]; await tester.pumpWidget( @@ -440,7 +441,7 @@ void main() { expect(find.text('4'), findsNothing); }); - testWidgets('One-line GridView paints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('One-line GridView paints', (WidgetTester tester) async { const Color green = Color(0xFF00FF00); final Container container = Container( @@ -469,7 +470,7 @@ void main() { expect(find.byType(GridView), isNot(paints..rect(color: green)..rect(color: green)..rect(color: green))); }); - testWidgets('GridView in zero context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView in zero context', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -490,7 +491,7 @@ void main() { expect(find.text('1'), findsNothing); }); - testWidgets('GridView in unbounded context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView in unbounded context', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -510,7 +511,7 @@ void main() { expect(find.text('19'), findsOneWidget); }); - testWidgets('GridView.builder control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder control test', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -531,7 +532,7 @@ void main() { expect(find.text('12'), findsNothing); }); - testWidgets('GridView.builder with undefined itemCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder with undefined itemCount', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -553,7 +554,7 @@ void main() { expect(find.text('13'), findsOneWidget); }); - testWidgets('GridView cross axis layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView cross axis layout', (WidgetTester tester) async { final Key target = UniqueKey(); Widget build(TextDirection textDirection) { @@ -579,7 +580,7 @@ void main() { expect(tester.getBottomRight(find.byKey(target)), const Offset(800.0, 200.0)); }); - testWidgets('GridView crossAxisSpacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView crossAxisSpacing', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/27151. final Key target = UniqueKey(); @@ -607,7 +608,7 @@ void main() { expect(tester.getBottomRight(find.byKey(target)), const Offset(800.0, 194.0)); }); - testWidgets('GridView does not cache itemBuilder calls', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView does not cache itemBuilder calls', (WidgetTester tester) async { final Map<int, int> counters = <int, int>{}; await tester.pumpWidget(Directionality( @@ -642,7 +643,7 @@ void main() { expect(counters[4], 2); }); - testWidgets('GridView does not report visual overflow unnecessarily', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView does not report visual overflow unnecessarily', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -663,9 +664,18 @@ void main() { final TestClipPaintingContext context = TestClipPaintingContext(); renderObject.paint(context, Offset.zero); expect(context.clipBehavior, equals(Clip.none)); - }); - - testWidgets('GridView respects clipBehavior', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + notDisposedAllowList: <String, int?> { + // https://github.com/flutter/flutter/issues/134575 + 'OffsetLayer': 1, + // https://github.com/flutter/flutter/issues/134572 + 'ContainerLayer': 1, + }, + )); + + testWidgetsWithLeakTracking('GridView respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -729,9 +739,14 @@ void main() { // 4th, check that a non-default clip behavior can be sent to the painting context. renderObject.paint(context, Offset.zero); expect(context.clipBehavior, equals(Clip.antiAlias)); - }); - - testWidgets('GridView.builder respects clipBehavior', (WidgetTester tester) async { + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134572 + notDisposedAllowList: <String, int?> {'ContainerLayer': 1}, + )); + + testWidgetsWithLeakTracking('GridView.builder respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -747,7 +762,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('GridView.custom respects clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.custom respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -765,7 +780,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('GridView.count respects clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.count respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -780,7 +795,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('GridView.extent respects clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.extent respects clipBehavior', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -795,7 +810,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('SliverGridDelegateWithFixedCrossAxisCount mainAxisExtent works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGridDelegateWithFixedCrossAxisCount mainAxisExtent works as expected', (WidgetTester tester) async { const int crossAxisCount = 4; const double mainAxisExtent = 100.0; @@ -821,7 +836,7 @@ void main() { expect(tester.getSize(find.text('4')), equals(const Size(200.0, mainAxisExtent))); }); - testWidgets('SliverGridDelegateWithMaxCrossAxisExtent mainAxisExtent works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGridDelegateWithMaxCrossAxisExtent mainAxisExtent works as expected', (WidgetTester tester) async { const double maxCrossAxisExtent = 200.0; const double mainAxisExtent = 100.0; @@ -847,7 +862,7 @@ void main() { expect(tester.getSize(find.text('4')), equals(const Size(200.0, mainAxisExtent))); }); - testWidgets('SliverGridDelegateWithMaxCrossAxisExtent throws assertion error when maxCrossAxisExtent is 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGridDelegateWithMaxCrossAxisExtent throws assertion error when maxCrossAxisExtent is 0', (WidgetTester tester) async { const double maxCrossAxisExtent = 0; expect(() => Directionality( @@ -858,9 +873,10 @@ void main() { ), throwsAssertionError); }); - testWidgets('SliverGrid sets correct extent for null returning builder delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGrid sets correct extent for null returning builder delegate', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/130685 final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: GridView.builder( diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart index 463f5ba99c8d4..46d26c1ea10c0 100644 --- a/packages/flutter/test/widgets/heroes_test.dart +++ b/packages/flutter/test/widgets/heroes_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../painting/image_test_utils.dart' show TestImageProvider; @@ -190,7 +191,7 @@ Future<void> main() async { transitionFromUserGestures = false; }); - testWidgets('Heroes animate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes animate', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(routes: routes)); @@ -300,7 +301,7 @@ Future<void> main() async { expect(find.byKey(thirdKey), isInCard); }); - testWidgets('Heroes still animate after hero controller is swapped.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes still animate after hero controller is swapped.', (WidgetTester tester) async { final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>(); final UniqueKey heroKey = UniqueKey(); await tester.pumpWidget( @@ -395,7 +396,7 @@ Future<void> main() async { expect(find.byKey(heroKey), findsNothing); }); - testWidgets('Heroes animate should hide original hero', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes animate should hide original hero', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(routes: routes)); // Checks initial state. expect(find.byKey(firstKey), isOnstage); @@ -418,7 +419,7 @@ Future<void> main() async { expect(find.byKey(secondKey), isInCard); }); - testWidgets('Destination hero is rebuilt midflight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination hero is rebuilt midflight', (WidgetTester tester) async { final MutatingRoute route = MutatingRoute(); await tester.pumpWidget(MaterialApp( @@ -443,7 +444,7 @@ Future<void> main() async { await tester.pump(const Duration(seconds: 1)); }); - testWidgets('Heroes animation is fastOutSlowIn', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes animation is fastOutSlowIn', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(routes: routes)); await tester.tap(find.text('two')); await tester.pump(); // begin navigation @@ -483,7 +484,7 @@ Future<void> main() async { ); }); - testWidgets('Heroes are not interactive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes are not interactive', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(MaterialApp( @@ -553,7 +554,7 @@ Future<void> main() async { expect(log, equals(<String>['bar'])); }); - testWidgets('Popping on first frame does not cause hero observer to crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popping on first frame does not cause hero observer to crash', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute<void>( @@ -574,7 +575,7 @@ Future<void> main() async { await tester.pump(); // ...and removes it straight away (since it's already at 0.0) }); - testWidgets('Overlapping starting and ending a hero transition works ok', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overlapping starting and ending a hero transition works ok', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute<void>( @@ -603,7 +604,7 @@ Future<void> main() async { await tester.pump(); }); - testWidgets('One route, two heroes, same tag, throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('One route, two heroes, same tag, throws', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: ListView( @@ -658,7 +659,7 @@ Future<void> main() async { ); }); - testWidgets('Hero push transition interrupted by a pop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero push transition interrupted by a pop', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( routes: routes, )); @@ -723,7 +724,7 @@ Future<void> main() async { expect(find.byKey(secondKey), findsNothing); }); - testWidgets('Hero pop transition interrupted by a push', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero pop transition interrupted by a push', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( routes: routes, @@ -800,7 +801,7 @@ Future<void> main() async { expect(find.byKey(firstKey), findsNothing); }); - testWidgets('Destination hero disappears mid-flight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination hero disappears mid-flight', (WidgetTester tester) async { const Key homeHeroKey = Key('home hero'); const Key routeHeroKey = Key('route hero'); bool routeIncludesHero = true; @@ -903,7 +904,7 @@ Future<void> main() async { }); - testWidgets('Destination hero scrolls mid-flight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination hero scrolls mid-flight', (WidgetTester tester) async { const Key homeHeroKey = Key('home hero'); const Key routeHeroKey = Key('route hero'); const Key routeContainerKey = Key('route hero container'); @@ -990,7 +991,7 @@ Future<void> main() async { expect(finalHeroY, 75.0); // 100 less 25 for the scroll }); - testWidgets('Destination hero scrolls out of view mid-flight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Destination hero scrolls out of view mid-flight', (WidgetTester tester) async { const Key homeHeroKey = Key('home hero'); const Key routeHeroKey = Key('route hero'); const Key routeContainerKey = Key('route hero container'); @@ -1067,7 +1068,7 @@ Future<void> main() async { expect(find.byKey(routeHeroKey), findsNothing); }); - testWidgets('Aborted flight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Aborted flight', (WidgetTester tester) async { // See https://github.com/flutter/flutter/issues/5798 const Key heroABKey = Key('AB hero'); const Key heroBCKey = Key('BC hero'); @@ -1202,7 +1203,7 @@ Future<void> main() async { expect(tester.getTopLeft(find.byKey(heroBCKey)).dy, 0.0); }); - testWidgets('Stateful hero child state survives flight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stateful hero child state survives flight', (WidgetTester tester) async { final MaterialPageRoute<void> route = MaterialPageRoute<void>( builder: (BuildContext context) { return Material( @@ -1286,7 +1287,7 @@ Future<void> main() async { }); - testWidgets('Hero createRectTween', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero createRectTween', (WidgetTester tester) async { RectTween createRectTween(Rect? begin, Rect? end) { return MaterialRectCenterArcTween(begin: begin, end: end); } @@ -1398,7 +1399,7 @@ Future<void> main() async { expect(tester.getCenter(find.byKey(firstKey)), const Offset(50.0, 50.0)); }); - testWidgets('Hero createRectTween for Navigator that is not full screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero createRectTween for Navigator that is not full screen', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25272 RectTween createRectTween(Rect? begin, Rect? end) { @@ -1519,7 +1520,7 @@ Future<void> main() async { }); - testWidgets('Pop interrupts push, reverses flight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Pop interrupts push, reverses flight', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp(routes: routes)); await tester.tap(find.text('twoInset')); await tester.pump(); // begin navigation from / to /twoInset. @@ -1612,7 +1613,7 @@ Future<void> main() async { expect(tester.getTopLeft(find.byKey(firstKey)).dx, x0); }); - testWidgets('Can override flight shuttle in to hero', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can override flight shuttle in to hero', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: ListView( @@ -1656,7 +1657,7 @@ Future<void> main() async { expect(find.text('baz'), findsOneWidget); }); - testWidgets('Can override flight shuttle in from hero', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can override flight shuttle in from hero', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: ListView( @@ -1699,7 +1700,7 @@ Future<void> main() async { }); // Regression test for https://github.com/flutter/flutter/issues/77720. - testWidgets("toHero's shuttle builder over fromHero's shuttle builder", (WidgetTester tester) async { + testWidgetsWithLeakTracking("toHero's shuttle builder over fromHero's shuttle builder", (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: ListView( @@ -1752,7 +1753,7 @@ Future<void> main() async { expect(find.text('toHero text'), findsOneWidget); }); - testWidgets('Can override flight launch pads', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can override flight launch pads', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: ListView( @@ -1799,7 +1800,7 @@ Future<void> main() async { expect(find.text('Joker'), findsOneWidget); }); - testWidgets('Heroes do not transition on back gestures by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes do not transition on back gestures by default', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( routes: routes, )); @@ -1838,7 +1839,7 @@ Future<void> main() async { expect(find.byKey(secondKey), isInCard); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Heroes can transition on gesture in one frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes can transition on gesture in one frame', (WidgetTester tester) async { transitionFromUserGestures = true; await tester.pumpWidget(MaterialApp( routes: routes, @@ -1881,7 +1882,7 @@ Future<void> main() async { expect(find.byKey(secondKey), findsNothing); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Heroes animate should hide destination hero and display original hero in case of dismissed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes animate should hide destination hero and display original hero in case of dismissed', (WidgetTester tester) async { transitionFromUserGestures = true; await tester.pumpWidget(MaterialApp( routes: routes, @@ -1917,7 +1918,7 @@ Future<void> main() async { expect(find.byKey(secondKey), isInCard); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Handles transitions when a non-default initial route is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Handles transitions when a non-default initial route is set', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( routes: routes, initialRoute: '/two', @@ -1927,7 +1928,7 @@ Future<void> main() async { expect(find.text('three'), findsOneWidget); }); - testWidgets('Can push/pop on outer Navigator if nested Navigator contains Heroes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can push/pop on outer Navigator if nested Navigator contains Heroes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28042. const String heroTag = 'You are my hero!'; @@ -2001,7 +2002,7 @@ Future<void> main() async { expect(find.byKey(nestedRouteHeroBottom, skipOffstage: false), findsOneWidget); }); - testWidgets('Can hero from route in root Navigator to route in nested Navigator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can hero from route in root Navigator to route in nested Navigator', (WidgetTester tester) async { const String heroTag = 'foo'; final GlobalKey<NavigatorState> rootNavigator = GlobalKey(); final Key smallContainer = UniqueKey(); @@ -2087,7 +2088,7 @@ Future<void> main() async { expect(tester.getSize(find.byKey(smallContainer)), const Size(100,100)); }); - testWidgets('Hero within a Hero, throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero within a Hero, throws', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -2105,7 +2106,7 @@ Future<void> main() async { expect(tester.takeException(), isAssertionError); }); - testWidgets('Can push/pop on outer Navigator if nested Navigators contains same Heroes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can push/pop on outer Navigator if nested Navigators contains same Heroes', (WidgetTester tester) async { const String heroTag = 'foo'; final GlobalKey<NavigatorState> rootNavigator = GlobalKey<NavigatorState>(); final Key rootRouteHero = UniqueKey(); @@ -2189,7 +2190,7 @@ Future<void> main() async { expect(find.byKey(nestedRouteHeroOne, skipOffstage: false), findsOneWidget); }); - testWidgets('Hero within a Hero subtree, throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero within a Hero subtree, throws', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -2207,7 +2208,7 @@ Future<void> main() async { expect(tester.takeException(), isAssertionError); }); - testWidgets('Hero within a Hero subtree with Builder, throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero within a Hero subtree with Builder, throws', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2229,7 +2230,7 @@ Future<void> main() async { expect(tester.takeException(),isAssertionError); }); - testWidgets('Hero within a Hero subtree with LayoutBuilder, throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero within a Hero subtree with LayoutBuilder, throws', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -2251,7 +2252,7 @@ Future<void> main() async { expect(tester.takeException(), isAssertionError); }); - testWidgets('Heroes fly on pushReplacement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes fly on pushReplacement', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28041. const String heroTag = 'foo'; @@ -2338,7 +2339,7 @@ Future<void> main() async { expect(tester.getSize(find.byKey(smallContainer)), const Size(100,100)); }); - testWidgets('On an iOS back swipe and snap, only a single flight should take place', (WidgetTester tester) async { + testWidgetsWithLeakTracking('On an iOS back swipe and snap, only a single flight should take place', (WidgetTester tester) async { int shuttlesBuilt = 0; Widget shuttleBuilder( BuildContext flightContext, @@ -2401,7 +2402,7 @@ Future<void> main() async { expect(shuttlesBuilt, 2); }); - testWidgets( + testWidgetsWithLeakTracking( "From hero's state should be preserved, " 'heroes work well with child widgets that has global keys', (WidgetTester tester) async { @@ -2468,7 +2469,7 @@ Future<void> main() async { }, ); - testWidgets( + testWidgetsWithLeakTracking( "Hero works with images that don't have both width and height specified", // Regression test for https://github.com/flutter/flutter/issues/32356 // and https://github.com/flutter/flutter/issues/31503 @@ -2556,7 +2557,7 @@ Future<void> main() async { ); // Regression test for https://github.com/flutter/flutter/issues/38183. - testWidgets('Remove user gesture driven flights when the gesture is invalid', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Remove user gesture driven flights when the gesture is invalid', (WidgetTester tester) async { transitionFromUserGestures = true; await tester.pumpWidget(MaterialApp( routes: routes, @@ -2585,7 +2586,7 @@ Future<void> main() async { }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); // Regression test for https://github.com/flutter/flutter/issues/40239. - testWidgets( + testWidgetsWithLeakTracking( 'In a pop transition, when fromHero is null, the to hero should eventually become visible', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey(); @@ -2634,7 +2635,7 @@ Future<void> main() async { }, ); - testWidgets('popped hero uses fastOutSlowIn curve', (WidgetTester tester) async { + testWidgetsWithLeakTracking('popped hero uses fastOutSlowIn curve', (WidgetTester tester) async { final Key container1 = UniqueKey(); final Key container2 = UniqueKey(); final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); @@ -2712,7 +2713,7 @@ Future<void> main() async { expect(heroSize, tween.transform(1.0)); }); - testWidgets('Heroes in enabled HeroMode do transition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes in enabled HeroMode do transition', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Column( @@ -2783,7 +2784,7 @@ Future<void> main() async { expect(find.byKey(secondKey), isInCard); }); - testWidgets('Heroes in disabled HeroMode do not transition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Heroes in disabled HeroMode do not transition', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Column( @@ -2861,7 +2862,7 @@ Future<void> main() async { expect(find.byKey(secondKey), isOnstage); }); - testWidgets('kept alive Hero does not throw when the transition begins', (WidgetTester tester) async { + testWidgetsWithLeakTracking('kept alive Hero does not throw when the transition begins', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget( @@ -2914,9 +2915,10 @@ Future<void> main() async { expect(find.byType(Placeholder), findsOneWidget); }); - testWidgets('toHero becomes unpaintable after the transition begins', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toHero becomes unpaintable after the transition begins', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); RenderAnimatedOpacity? findRenderAnimatedOpacity() { RenderObject? parent = tester.renderObject(find.byType(Placeholder)); @@ -2989,7 +2991,7 @@ Future<void> main() async { expect(find.byType(Placeholder), findsNothing); }); - testWidgets('diverting to a keepalive but unpaintable hero', (WidgetTester tester) async { + testWidgetsWithLeakTracking('diverting to a keepalive but unpaintable hero', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget( @@ -3069,7 +3071,7 @@ Future<void> main() async { expect(tester.takeException(), isNull); }); - testWidgets('smooth transition between different incoming data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('smooth transition between different incoming data', (WidgetTester tester) async { addTearDown(tester.view.reset); final GlobalKey<NavigatorState> navigatorKey = GlobalKey(); diff --git a/packages/flutter/test/widgets/hit_testing_test.dart b/packages/flutter/test/widgets/hit_testing_test.dart index bd4cd9377a99b..39ff67cca8950 100644 --- a/packages/flutter/test/widgets/hit_testing_test.dart +++ b/packages/flutter/test/widgets/hit_testing_test.dart @@ -6,16 +6,17 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toString control test', (WidgetTester tester) async { await tester.pumpWidget(const Center(child: Text('Hello', textDirection: TextDirection.ltr))); final HitTestResult result = tester.hitTestOnBinding(Offset.zero); expect(result, hasOneLineDescription); expect(result.path.first, hasOneLineDescription); }); - testWidgets('A mouse click should only cause one hit test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A mouse click should only cause one hit test', (WidgetTester tester) async { int hitCount = 0; await tester.pumpWidget( _HitTestCounter( @@ -31,7 +32,7 @@ void main() { expect(hitCount, 1); }); - testWidgets('Non-mouse events should not cause movement hit tests', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Non-mouse events should not cause movement hit tests', (WidgetTester tester) async { int hitCount = 0; await tester.pumpWidget( _HitTestCounter( diff --git a/packages/flutter/test/widgets/hyperlink_test.dart b/packages/flutter/test/widgets/hyperlink_test.dart index 4e303befd1d2d..d35d45ed5b626 100644 --- a/packages/flutter/test/widgets/hyperlink_test.dart +++ b/packages/flutter/test/widgets/hyperlink_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can tap a hyperlink', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can tap a hyperlink', (WidgetTester tester) async { bool didTapLeft = false; final TapGestureRecognizer tapLeft = TapGestureRecognizer() ..onTap = () { diff --git a/packages/flutter/test/widgets/icon_test.dart b/packages/flutter/test/widgets/icon_test.dart index 4b53d670a33ed..bdb690995aecf 100644 --- a/packages/flutter/test/widgets/icon_test.dart +++ b/packages/flutter/test/widgets/icon_test.dart @@ -6,11 +6,12 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Can set opacity for an Icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set opacity for an Icon', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -27,7 +28,7 @@ void main() { expect(text.text.style!.color, const Color(0xFF666666).withOpacity(0.5)); }); - testWidgets('Icon sizing - no theme, default size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon sizing - no theme, default size', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -41,7 +42,7 @@ void main() { expect(renderObject.size, equals(const Size.square(24.0))); }); - testWidgets('Icon sizing - no theme, explicit size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon sizing - no theme, explicit size', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -58,7 +59,7 @@ void main() { expect(renderObject.size, equals(const Size.square(96.0))); }); - testWidgets('Icon sizing - sized theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon sizing - sized theme', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -75,7 +76,7 @@ void main() { expect(renderObject.size, equals(const Size.square(36.0))); }); - testWidgets('Icon sizing - sized theme, explicit size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon sizing - sized theme, explicit size', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -95,7 +96,7 @@ void main() { expect(renderObject.size, equals(const Size.square(48.0))); }); - testWidgets('Icon sizing - sizeless theme, default size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon sizing - sizeless theme, default size', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -113,7 +114,7 @@ void main() { }); - testWidgets('Icon with custom font', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon with custom font', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -127,7 +128,7 @@ void main() { expect(richText.text.style!.fontFamily, equals('Roboto')); }); - testWidgets('Icon with custom fontFamilyFallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon with custom fontFamilyFallback', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -141,7 +142,7 @@ void main() { expect(richText.text.style!.fontFamilyFallback, equals(<String>['FallbackFont'])); }); - testWidgets('Icon with semantic label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon with semantic label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -161,7 +162,7 @@ void main() { semantics.dispose(); }); - testWidgets('Null icon with semantic label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Null icon with semantic label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -181,7 +182,7 @@ void main() { semantics.dispose(); }); - testWidgets("Changing semantic label from null doesn't rebuild tree ", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Changing semantic label from null doesn't rebuild tree ", (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -212,7 +213,7 @@ void main() { expect(richText2, same(richText1)); }); - testWidgets('IconData comparison', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconData comparison', (WidgetTester tester) async { expect(const IconData(123), const IconData(123)); expect(const IconData(123), isNot(const IconData(123, matchTextDirection: true))); expect(const IconData(123), isNot(const IconData(123, fontFamily: 'f'))); @@ -225,7 +226,7 @@ void main() { }); - testWidgets('Fill, weight, grade, and optical size variations are passed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fill, weight, grade, and optical size variations are passed', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -258,7 +259,7 @@ void main() { ]); }); - testWidgets('Fill, weight, grade, and optical size can be set at the theme-level', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fill, weight, grade, and optical size can be set at the theme-level', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -283,7 +284,7 @@ void main() { ]); }); - testWidgets('Theme-level fill, weight, grade, and optical size can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme-level fill, weight, grade, and optical size can be overridden', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/image_filter_quality_test.dart b/packages/flutter/test/widgets/image_filter_quality_test.dart index dcbeadfd438da..5025b25e1867e 100644 --- a/packages/flutter/test/widgets/image_filter_quality_test.dart +++ b/packages/flutter/test/widgets/image_filter_quality_test.dart @@ -13,17 +13,18 @@ import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Image at default filterQuality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image at default filterQuality', (WidgetTester tester) async { await testImageQuality(tester, null); }); - testWidgets('Image at high filterQuality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image at high filterQuality', (WidgetTester tester) async { await testImageQuality(tester, ui.FilterQuality.high); }); - testWidgets('Image at none filterQuality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image at none filterQuality', (WidgetTester tester) async { await testImageQuality(tester, ui.FilterQuality.none); }); } diff --git a/packages/flutter/test/widgets/image_filter_test.dart b/packages/flutter/test/widgets/image_filter_test.dart index 29da67bae4d7a..0cad97b4c46b7 100644 --- a/packages/flutter/test/widgets/image_filter_test.dart +++ b/packages/flutter/test/widgets/image_filter_test.dart @@ -14,9 +14,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Image filter - blur', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - blur', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary( child: ImageFiltered( @@ -31,7 +32,7 @@ void main() { ); }); - testWidgets('Image filter - blur with offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - blur with offset', (WidgetTester tester) async { final Key key = GlobalKey(); await tester.pumpWidget( RepaintBoundary( @@ -51,7 +52,7 @@ void main() { ); }); - testWidgets('Image filter - dilate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - dilate', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary( child: ImageFiltered( @@ -66,7 +67,7 @@ void main() { ); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/101874 - testWidgets('Image filter - erode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - erode', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary( child: ImageFiltered( @@ -82,7 +83,7 @@ void main() { ); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/101874 - testWidgets('Image filter - matrix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - matrix', (WidgetTester tester) async { final ImageFilter matrix = ImageFilter.matrix(Float64List.fromList(<double>[ 0.5, 0.0, 0.0, 0.0, // 0.0, 0.5, 0.0, 0.0, // @@ -119,7 +120,7 @@ void main() { ); }); - testWidgets('Image filter - matrix with offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - matrix with offset', (WidgetTester tester) async { final Matrix4 matrix = Matrix4.rotationZ(pi / 18); final ImageFilter matrixFilter = ImageFilter.matrix(matrix.storage); final Key key = GlobalKey(); @@ -157,7 +158,7 @@ void main() { ); }); - testWidgets('Image filter - reuses its layer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - reuses its layer', (WidgetTester tester) async { Future<void> pumpWithSigma(double sigma) async { await tester.pumpWidget( RepaintBoundary( @@ -178,7 +179,7 @@ void main() { expect(renderObject.debugLayer, same(originalLayer)); }); - testWidgets('Image filter - enabled and disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image filter - enabled and disabled', (WidgetTester tester) async { Future<void> pumpWithEnabledState(bool enabled) async { await tester.pumpWidget( RepaintBoundary( diff --git a/packages/flutter/test/widgets/image_headers_test.dart b/packages/flutter/test/widgets/image_headers_test.dart index f00f00fcdaecb..2d833f49e0205 100644 --- a/packages/flutter/test/widgets/image_headers_test.dart +++ b/packages/flutter/test/widgets/image_headers_test.dart @@ -7,13 +7,14 @@ import 'dart:io'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; void main() { final MockHttpClient client = MockHttpClient(); - testWidgets('Headers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Headers', (WidgetTester tester) async { HttpOverrides.runZoned<Future<void>>(() async { await tester.pumpWidget(Image.network( 'https://www.example.com/images/frame.png', diff --git a/packages/flutter/test/widgets/image_icon_test.dart b/packages/flutter/test/widgets/image_icon_test.dart index 0d4709406a9c8..2aa1d73290341 100644 --- a/packages/flutter/test/widgets/image_icon_test.dart +++ b/packages/flutter/test/widgets/image_icon_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../painting/mocks_for_image_cache.dart'; @@ -20,7 +21,7 @@ void main() { ); }); - testWidgets('ImageIcon sizing - no theme, default size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageIcon sizing - no theme, default size', (WidgetTester tester) async { await tester.pumpWidget( Center( child: ImageIcon(image), @@ -32,7 +33,7 @@ void main() { expect(find.byType(Image), findsOneWidget); }); - testWidgets('Icon opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Icon opacity', (WidgetTester tester) async { await tester.pumpWidget( Center( child: IconTheme( @@ -45,7 +46,7 @@ void main() { expect(tester.widget<Image>(find.byType(Image)).color!.alpha, equals(128)); }); - testWidgets('ImageIcon sizing - no theme, explicit size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageIcon sizing - no theme, explicit size', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: ImageIcon( @@ -59,7 +60,7 @@ void main() { expect(renderObject.size, equals(const Size.square(96.0))); }); - testWidgets('ImageIcon sizing - sized theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageIcon sizing - sized theme', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: IconTheme( @@ -73,7 +74,7 @@ void main() { expect(renderObject.size, equals(const Size.square(36.0))); }); - testWidgets('ImageIcon sizing - sized theme, explicit size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageIcon sizing - sized theme, explicit size', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: IconTheme( @@ -90,7 +91,7 @@ void main() { expect(renderObject.size, equals(const Size.square(48.0))); }); - testWidgets('ImageIcon sizing - sizeless theme, default size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageIcon sizing - sizeless theme, default size', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: IconTheme( @@ -104,7 +105,7 @@ void main() { expect(renderObject.size, equals(const Size.square(24.0))); }); - testWidgets('ImageIcon has semantics data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ImageIcon has semantics data', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( const Directionality( diff --git a/packages/flutter/test/widgets/image_resolution_test.dart b/packages/flutter/test/widgets/image_resolution_test.dart index 46f0478058d59..afacf9ae92283 100644 --- a/packages/flutter/test/widgets/image_resolution_test.dart +++ b/packages/flutter/test/widgets/image_resolution_test.dart @@ -13,6 +13,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; @@ -155,6 +156,7 @@ void main() { const String image = 'assets/image.png'; final Map<double, ui.Image> images = <double, ui.Image>{}; + setUpAll(() async { for (final double scale in const <double>[0.5, 1.0, 1.5, 2.0, 4.0, 10.0]) { final int dimension = (48 * scale).floor(); @@ -162,7 +164,13 @@ void main() { } }); - testWidgets('Image for device pixel ratio 1.0', (WidgetTester tester) async { + tearDownAll(() { + for (final ui.Image image in images.values) { + image.dispose(); + } + }); + + testWidgetsWithLeakTracking('Image for device pixel ratio 1.0', (WidgetTester tester) async { const double ratio = 1.0; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -174,7 +182,7 @@ void main() { expect(getRenderImage(tester, key).scale, 1.0); }); - testWidgets('Image for device pixel ratio 0.5', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 0.5', (WidgetTester tester) async { const double ratio = 0.5; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -186,7 +194,7 @@ void main() { expect(getRenderImage(tester, key).scale, 1.0); }); - testWidgets('Image for device pixel ratio 1.5', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 1.5', (WidgetTester tester) async { const double ratio = 1.5; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -201,7 +209,7 @@ void main() { // A 1.75 DPR screen is typically a low-resolution screen, such that physical // pixels are visible to the user. For such screens we prefer to pick the // higher resolution image, if available. - testWidgets('Image for device pixel ratio 1.75', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 1.75', (WidgetTester tester) async { const double ratio = 1.75; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -213,7 +221,7 @@ void main() { expect(getRenderImage(tester, key).scale, 2.0); }); - testWidgets('Image for device pixel ratio 2.3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 2.3', (WidgetTester tester) async { const double ratio = 2.3; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -225,7 +233,7 @@ void main() { expect(getRenderImage(tester, key).scale, 2.0); }); - testWidgets('Image for device pixel ratio 3.7', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 3.7', (WidgetTester tester) async { const double ratio = 3.7; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -237,7 +245,7 @@ void main() { expect(getRenderImage(tester, key).scale, 4.0); }); - testWidgets('Image for device pixel ratio 5.1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 5.1', (WidgetTester tester) async { const double ratio = 5.1; Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageAtRatio(image, key, ratio, false, images)); @@ -249,7 +257,7 @@ void main() { expect(getRenderImage(tester, key).scale, 4.0); }); - testWidgets('Image for device pixel ratio 1.0, with a main asset and a 1.0x asset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image for device pixel ratio 1.0, with a main asset and a 1.0x asset', (WidgetTester tester) async { // If both a main asset and a 1.0x asset are specified, then prefer // the 1.0x asset. @@ -279,19 +287,19 @@ void main() { expect(getRenderImage(tester, key).image!.height, 480); }); - testWidgets('Image cache resize upscale display 5', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image cache resize upscale display 5', (WidgetTester tester) async { final Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageCacheResized(image, key, 5, 5, 20, 20)); expect(getRenderImage(tester, key).size, const Size(5.0, 5.0)); }); - testWidgets('Image cache resize upscale display 50', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image cache resize upscale display 50', (WidgetTester tester) async { final Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageCacheResized(image, key, 50, 50, 20, 20)); expect(getRenderImage(tester, key).size, const Size(50.0, 50.0)); }); - testWidgets('Image cache resize downscale display 5', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image cache resize downscale display 5', (WidgetTester tester) async { final Key key = GlobalKey(); await pumpTreeToLayout(tester, buildImageCacheResized(image, key, 5, 5, 1, 1)); expect(getRenderImage(tester, key).size, const Size(5.0, 5.0)); @@ -301,7 +309,7 @@ void main() { // visible physical pixel size (see the test for 1.75 DPR above). However, // if higher resolution assets are not available we will pick the best // available. - testWidgets('Low-resolution assets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Low-resolution assets', (WidgetTester tester) async { const Map<Object?, Object?> manifest = <Object?, Object?>{ 'assets/image.png': <Map<String, Object>>[ <String, Object>{'asset': 'assets/image.png'}, diff --git a/packages/flutter/test/widgets/image_rtl_test.dart b/packages/flutter/test/widgets/image_rtl_test.dart index 6f2c075a00e0f..905ba88d4aa4b 100644 --- a/packages/flutter/test/widgets/image_rtl_test.dart +++ b/packages/flutter/test/widgets/image_rtl_test.dart @@ -7,6 +7,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestImageProvider extends ImageProvider<TestImageProvider> { const TestImageProvider(this.image); @@ -28,10 +29,16 @@ class TestImageProvider extends ImageProvider<TestImageProvider> { void main() { late ui.Image testImage; + setUpAll(() async { testImage = await createTestImage(width: 16, height: 9); }); - testWidgets('DecorationImage RTL with alignment topEnd and match', (WidgetTester tester) async { + + tearDownAll(() { + testImage.dispose(); + }); + + testWidgetsWithLeakTracking('DecorationImage RTL with alignment topEnd and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -70,7 +77,7 @@ void main() { expect(find.byType(Container), isNot(paints..scale()..scale())); }); - testWidgets('DecorationImage LTR with alignment topEnd (and pointless match)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage LTR with alignment topEnd (and pointless match)', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -106,7 +113,7 @@ void main() { expect(find.byType(Container), isNot(paints..scale())); }); - testWidgets('DecorationImage RTL with alignment topEnd', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage RTL with alignment topEnd', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -141,7 +148,7 @@ void main() { expect(find.byType(Container), isNot(paints..scale())); }); - testWidgets('DecorationImage LTR with alignment topEnd', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage LTR with alignment topEnd', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -176,7 +183,7 @@ void main() { expect(find.byType(Container), isNot(paints..scale())); }); - testWidgets('DecorationImage RTL with alignment center-right and match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage RTL with alignment center-right and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -208,7 +215,7 @@ void main() { expect(find.byType(Container), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('DecorationImage RTL with alignment center-right and no match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage RTL with alignment center-right and no match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -235,7 +242,7 @@ void main() { expect(find.byType(Container), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('DecorationImage LTR with alignment center-right and match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage LTR with alignment center-right and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -263,7 +270,7 @@ void main() { expect(find.byType(Container), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('DecorationImage LTR with alignment center-right and no match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DecorationImage LTR with alignment center-right and no match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -291,7 +298,7 @@ void main() { expect(find.byType(Container), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('Image RTL with alignment topEnd and match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image RTL with alignment topEnd and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -328,7 +335,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..scale()..scale())); }); - testWidgets('Image LTR with alignment topEnd (and pointless match)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image LTR with alignment topEnd (and pointless match)', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -362,7 +369,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..scale())); }); - testWidgets('Image RTL with alignment topEnd', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image RTL with alignment topEnd', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -395,7 +402,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..scale())); }); - testWidgets('Image LTR with alignment topEnd', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image LTR with alignment topEnd', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -428,7 +435,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..scale())); }); - testWidgets('Image RTL with alignment center-right and match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image RTL with alignment center-right and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -456,7 +463,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('Image RTL with alignment center-right and no match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image RTL with alignment center-right and no match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -481,7 +488,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('Image LTR with alignment center-right and match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image LTR with alignment center-right and match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -507,7 +514,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('Image LTR with alignment center-right and no match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image LTR with alignment center-right and no match', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -533,7 +540,7 @@ void main() { expect(find.byType(SizedBox), isNot(paints..drawImageRect()..drawImageRect())); }); - testWidgets('Image - Switch needing direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Image - Switch needing direction', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, From 6ec1ff2308594f180caf0bddf3f319c1fa9b184a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 16:18:56 -0400 Subject: [PATCH 1276/1547] Roll Flutter Engine from e0b5b6c4eb76 to 035932d64017 (2 revisions) (#134763) https://github.com/flutter/engine/compare/e0b5b6c4eb76...035932d64017 2023-09-14 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 1ee7ef8bbc65 to d25e8d682c8f (22 revisions) (flutter/engine#45836) 2023-09-14 godofredoc@google.com Update webdriver imports. (flutter/engine#45816) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8cef192f2f77f..2d63dc5442653 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e0b5b6c4eb7632df420e2724b8a71f05e2593db7 +035932d6401744ea474b8bcf4ba48a22b2d9941f From 0e521942a3d7e317ded68b91f6c00efcc8810724 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Thu, 14 Sep 2023 14:00:55 -0700 Subject: [PATCH 1277/1547] Allows page removal that contains Localhistoryentry (#134757) fixes https://github.com/flutter/flutter/issues/97836 fixes https://github.com/flutter/flutter/issues/134752 fixes https://github.com/flutter/flutter/issues/118645 --- .../flutter/lib/src/widgets/navigator.dart | 18 ++++ packages/flutter/lib/src/widgets/routes.dart | 8 -- .../flutter/test/widgets/navigator_test.dart | 84 +++++++++++++++++++ 3 files changed, 102 insertions(+), 8 deletions(-) diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index e2f350d299b0e..41b570be858f5 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -2927,6 +2927,10 @@ class _RouteEntry extends RouteTransitionRecord { final _RestorationInformation? restorationInformation; final bool pageBased; + /// The limit this route entry will attempt to pop in the case of route being + /// remove as a result of a page update. + static const int kDebugPopAttemptLimit = 100; + static final Route<dynamic> notAnnounced = _NotAnnounced(); _RouteLifecycle currentState; @@ -3268,6 +3272,20 @@ class _RouteEntry extends RouteTransitionRecord { 'This route cannot be marked for pop. Either a decision has already been ' 'made or it does not require an explicit decision on how to transition out.', ); + // Remove state that prevents a pop, e.g. LocalHistoryEntry[s]. + int attempt = 0; + while (route.willHandlePopInternally) { + assert( + () { + attempt += 1; + return attempt < kDebugPopAttemptLimit; + }(), + 'Attempted to pop $route $kDebugPopAttemptLimit times, but still failed', + ); + final bool popResult = route.didPop(result); + assert(!popResult); + + } pop<dynamic>(result); _isWaitingForExitingDecision = false; } diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index b51cb4f61c7c7..d779df692d587 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -1832,14 +1832,6 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T ]; } - @override - bool get willHandlePopInternally { - final bool popEntriesCanPop = _popEntries.every((PopEntry popEntry) { - return popEntry.canPopNotifier.value; - }); - return !popEntriesCanPop || super.willHandlePopInternally; - } - @override String toString() => '${objectRuntimeType(this, 'ModalRoute')}($settings, animation: $_animation)'; } diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart index 886de4a712695..8044583a7b276 100644 --- a/packages/flutter/test/widgets/navigator_test.dart +++ b/packages/flutter/test/widgets/navigator_test.dart @@ -2910,6 +2910,90 @@ void main() { ); }); + testWidgets('Can pop route with local history entries using page api', (WidgetTester tester) async { + List<Page<void>> myPages = const <Page<void>>[ + MaterialPage<void>(child: Text('page1')), + MaterialPage<void>(child: Text('page2')), + ]; + await tester.pumpWidget( + MediaQuery( + data: MediaQueryData.fromView(tester.view), + child: Localizations( + locale: const Locale('en', 'US'), + delegates: const <LocalizationsDelegate<dynamic>>[ + DefaultMaterialLocalizations.delegate, + DefaultWidgetsLocalizations.delegate, + ], + child: Navigator( + pages: myPages, + onPopPage: (_, __) => false, + ), + ), + ), + ); + expect(find.text('page2'), findsOneWidget); + final ModalRoute<void> route = ModalRoute.of(tester.element(find.text('page2')))!; + bool entryRemoved = false; + route.addLocalHistoryEntry(LocalHistoryEntry(onRemove: () => entryRemoved = true)); + expect(route.willHandlePopInternally, true); + + myPages = const <Page<void>>[ + MaterialPage<void>(child: Text('page1')), + ]; + + await tester.pumpWidget( + MediaQuery( + data: MediaQueryData.fromView(tester.view), + child: Localizations( + locale: const Locale('en', 'US'), + delegates: const <LocalizationsDelegate<dynamic>>[ + DefaultMaterialLocalizations.delegate, + DefaultWidgetsLocalizations.delegate, + ], + child: Navigator( + pages: myPages, + onPopPage: (_, __) => false, + ), + ), + ), + ); + expect(find.text('page1'), findsOneWidget); + expect(entryRemoved, isTrue); + }); + + testWidgets('ModalRoute must comply with willHandlePopInternally when there is a PopScope', (WidgetTester tester) async { + const List<Page<void>> myPages = <Page<void>>[ + MaterialPage<void>(child: Text('page1')), + MaterialPage<void>( + child: PopScope( + canPop: false, + child: Text('page2'), + ), + ), + ]; + await tester.pumpWidget( + MediaQuery( + data: MediaQueryData.fromView(tester.view), + child: Localizations( + locale: const Locale('en', 'US'), + delegates: const <LocalizationsDelegate<dynamic>>[ + DefaultMaterialLocalizations.delegate, + DefaultWidgetsLocalizations.delegate, + ], + child: Navigator( + pages: myPages, + onPopPage: (_, __) => false, + ), + ), + ), + ); + final ModalRoute<void> route = ModalRoute.of(tester.element(find.text('page2')))!; + // PopScope only prevents user trigger action, e.g. Navigator.maybePop. + // The page can still be popped by the system if it needs to. + expect(route.willHandlePopInternally, false); + expect(route.didPop(null), true); + }); + testWidgets('can push and pop pages using page api', (WidgetTester tester) async { late Animation<double> secondaryAnimationOfRouteOne; late Animation<double> primaryAnimationOfRouteOne; From ab715b2068d35d43e558e0d9352e1ee43cd184c1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 17:02:06 -0400 Subject: [PATCH 1278/1547] Roll Flutter Engine from 035932d64017 to 3a3a2807c3b6 (5 revisions) (#134769) https://github.com/flutter/engine/compare/035932d64017...3a3a2807c3b6 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 9bdf01416042 to 0f003d5748bc (4 revisions) (flutter/engine#45841) 2023-09-14 jacksongardner@google.com Declare the js context as nullable in skwasm surface callback (flutter/engine#45810) 2023-09-14 matanlurey@users.noreply.github.com [Impeller] Release a texture during Playground teardown (flutter/engine#45832) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 87025d1e162c to 9bdf01416042 (1 revision) (flutter/engine#45835) 2023-09-14 matanlurey@users.noreply.github.com Make `fml::ScopedCleanupClosure` `std::move`-able and add unit tests. (flutter/engine#45772) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2d63dc5442653..aacc301938e9f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -035932d6401744ea474b8bcf4ba48a22b2d9941f +3a3a2807c3b6e1a426536631b19d76b85f0f31b9 From 98bee6777d1f0d8a8c17031cfd9cd6e8a10e33d3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 14 Sep 2023 17:47:01 -0400 Subject: [PATCH 1279/1547] Roll Flutter Engine from 3a3a2807c3b6 to 683bca53d4d7 (3 revisions) (#134778) https://github.com/flutter/engine/compare/3a3a2807c3b6...683bca53d4d7 2023-09-14 bdero@google.com [Impeller] Assert IMPELLER_ENABLE_3D when importing scene_contents.h. (flutter/engine#45848) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 0f003d5748bc to 6bc9f5886ddf (2 revisions) (flutter/engine#45847) 2023-09-14 bdero@google.com [Impeller] Add AbsorbOpacity enum. (flutter/engine#45838) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index aacc301938e9f..662785feea428 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3a3a2807c3b6e1a426536631b19d76b85f0f31b9 +683bca53d4d72e5bb891006dac0e75b667a792d8 From 783f2f483073dfee7e1294b07e5e7e0ccbc8e638 Mon Sep 17 00:00:00 2001 From: Pavel Mazhnik <pavel.mazhnik@gmail.com> Date: Fri, 15 Sep 2023 00:17:08 +0200 Subject: [PATCH 1280/1547] [web] provide serviceWorkerVersion to the getNewServiceWorker function (#131240) Fixes https://github.com/flutter/flutter/issues/130212 Fix `Unresolved variable or type 'serviceWorkerVersion'` in the `_getNewServiceWorker` function. Supersedes https://github.com/flutter/flutter/pull/130206 --- dev/bots/service_worker_test.dart | 139 ++++++++++++++++++ dev/bots/test.dart | 1 + ...ndex_with_flutterjs_custom_sw_version.html | 39 +++++ .../lib/src/web/file_generators/js/flutter.js | 5 +- 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 dev/integration_tests/web/web/index_with_flutterjs_custom_sw_version.html diff --git a/dev/bots/service_worker_test.dart b/dev/bots/service_worker_test.dart index 019ccdd90b79c..b110b66875302 100644 --- a/dev/bots/service_worker_test.dart +++ b/dev/bots/service_worker_test.dart @@ -37,6 +37,8 @@ enum ServiceWorkerTestType { withFlutterJsEntrypointLoadedEvent, // Same as withFlutterJsEntrypointLoadedEvent, but with TrustedTypes enabled. withFlutterJsTrustedTypesOn, + // Uses custom serviceWorkerVersion. + withFlutterJsCustomServiceWorkerVersion, // Entrypoint generated by `flutter create`. generatedEntrypoint, } @@ -58,6 +60,7 @@ Future<void> main() async { await runWebServiceWorkerTestWithCachingResources(headless: false, testType: ServiceWorkerTestType.withFlutterJsTrustedTypesOn); await runWebServiceWorkerTestWithGeneratedEntrypoint(headless: false); await runWebServiceWorkerTestWithBlockedServiceWorkers(headless: false); + await runWebServiceWorkerTestWithCustomServiceWorkerVersion(headless: false); if (hasError) { reportErrorsAndExit('${bold}One or more tests failed.$reset'); @@ -117,6 +120,8 @@ String _testTypeToIndexFile(ServiceWorkerTestType type) { indexFile = 'index_with_flutterjs_entrypoint_loaded.html'; case ServiceWorkerTestType.withFlutterJsTrustedTypesOn: indexFile = 'index_with_flutterjs_el_tt_on.html'; + case ServiceWorkerTestType.withFlutterJsCustomServiceWorkerVersion: + indexFile = 'index_with_flutterjs_custom_sw_version.html'; case ServiceWorkerTestType.generatedEntrypoint: indexFile = 'generated_entrypoint.html'; } @@ -703,3 +708,137 @@ Future<void> runWebServiceWorkerTestWithBlockedServiceWorkers({ } print('END runWebServiceWorkerTestWithBlockedServiceWorkers(headless: $headless)'); } + +/// Regression test for https://github.com/flutter/flutter/issues/130212. +Future<void> runWebServiceWorkerTestWithCustomServiceWorkerVersion({ + required bool headless, +}) async { + final Map<String, int> requestedPathCounts = <String, int>{}; + void expectRequestCounts(Map<String, int> expectedCounts) => + _expectRequestCounts(expectedCounts, requestedPathCounts); + + AppServer? server; + Future<void> waitForAppToLoad(Map<String, int> waitForCounts) async => + _waitForAppToLoad(waitForCounts, requestedPathCounts, server); + + Future<void> startAppServer({ + required String cacheControl, + }) async { + final int serverPort = await findAvailablePortAndPossiblyCauseFlakyTests(); + final int browserDebugPort = await findAvailablePortAndPossiblyCauseFlakyTests(); + server = await AppServer.start( + headless: headless, + cacheControl: cacheControl, + // TODO(yjbanov): use a better port disambiguation strategy than trying + // to guess what ports other tests use. + appUrl: 'http://localhost:$serverPort/index.html', + serverPort: serverPort, + browserDebugPort: browserDebugPort, + appDirectory: _appBuildDirectory, + additionalRequestHandlers: <Handler>[ + (Request request) { + final String requestedPath = request.url.path; + requestedPathCounts.putIfAbsent(requestedPath, () => 0); + requestedPathCounts[requestedPath] = requestedPathCounts[requestedPath]! + 1; + if (requestedPath == 'CLOSE') { + return Response.ok('OK'); + } + return Response.notFound(''); + }, + ], + ); + } + + // Preserve old index.html as index_og.html so we can restore it later for other tests + await runCommand( + 'mv', + <String>[ + 'index.html', + 'index_og.html', + ], + workingDirectory: _testAppWebDirectory, + ); + + print('BEGIN runWebServiceWorkerTestWithCustomServiceWorkerVersion(headless: $headless)'); + try { + await _rebuildApp(version: 1, testType: ServiceWorkerTestType.withFlutterJsCustomServiceWorkerVersion, target: _target); + + print('Test page load'); + await startAppServer(cacheControl: 'max-age=0'); + await waitForAppToLoad(<String, int>{ + 'CLOSE': 1, + 'flutter_service_worker.js': 1, + 'assets/fonts/MaterialIcons-Regular.otf': 1, + }); + expectRequestCounts(<String, int>{ + 'index.html': 2, + 'flutter.js': 1, + 'main.dart.js': 1, + 'CLOSE': 1, + 'flutter_service_worker.js': 1, + 'assets/FontManifest.json': 1, + 'assets/AssetManifest.json': 1, + 'assets/fonts/MaterialIcons-Regular.otf': 1, + // In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'. + if (!headless) + ...<String, int>{ + 'manifest.json': 1, + 'favicon.ico': 1, + }, + }); + + print('Test page reload, ensure service worker is not reloaded'); + await server!.chrome.reloadPage(ignoreCache: true); + await waitForAppToLoad(<String, int>{ + 'CLOSE': 1, + 'flutter.js': 1, + }); + expectRequestCounts(<String, int>{ + 'index.html': 1, + 'flutter.js': 1, + 'main.dart.js': 1, + 'assets/FontManifest.json': 1, + 'assets/fonts/MaterialIcons-Regular.otf': 1, + 'CLOSE': 1, + // In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'. + if (!headless) + ...<String, int>{ + 'manifest.json': 1, + 'favicon.ico': 1, + }, + }); + + print('Test page reload after rebuild, ensure service worker is not reloaded'); + await _rebuildApp(version: 1, testType: ServiceWorkerTestType.withFlutterJsCustomServiceWorkerVersion, target: _target); + await server!.chrome.reloadPage(ignoreCache: true); + await waitForAppToLoad(<String, int>{ + 'CLOSE': 1, + 'flutter.js': 1, + }); + expectRequestCounts(<String, int>{ + 'index.html': 1, + 'flutter.js': 1, + 'main.dart.js': 1, + 'assets/FontManifest.json': 1, + 'assets/fonts/MaterialIcons-Regular.otf': 1, + 'CLOSE': 1, + // In headless mode Chrome does not load 'manifest.json' and 'favicon.ico'. + if (!headless) + ...<String, int>{ + 'manifest.json': 1, + 'favicon.ico': 1, + }, + }); + } finally { + await runCommand( + 'mv', + <String>[ + 'index_og.html', + 'index.html', + ], + workingDirectory: _testAppWebDirectory, + ); + await server?.stop(); + } + print('END runWebServiceWorkerTestWithCustomServiceWorkerVersion(headless: $headless)'); +} diff --git a/dev/bots/test.dart b/dev/bots/test.dart index 8d9dd00c6ce34..30618d6279d49 100644 --- a/dev/bots/test.dart +++ b/dev/bots/test.dart @@ -1249,6 +1249,7 @@ Future<void> _runWebLongRunningTests() async { () => runWebServiceWorkerTestWithCachingResources(headless: true, testType: ServiceWorkerTestType.withFlutterJsTrustedTypesOn), () => runWebServiceWorkerTestWithGeneratedEntrypoint(headless: true), () => runWebServiceWorkerTestWithBlockedServiceWorkers(headless: true), + () => runWebServiceWorkerTestWithCustomServiceWorkerVersion(headless: true), () => _runWebStackTraceTest('profile', 'lib/stack_trace.dart'), () => _runWebStackTraceTest('release', 'lib/stack_trace.dart'), () => _runWebStackTraceTest('profile', 'lib/framework_stack_trace.dart'), diff --git a/dev/integration_tests/web/web/index_with_flutterjs_custom_sw_version.html b/dev/integration_tests/web/web/index_with_flutterjs_custom_sw_version.html new file mode 100644 index 0000000000000..886afa4df72cd --- /dev/null +++ b/dev/integration_tests/web/web/index_with_flutterjs_custom_sw_version.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<!-- Copyright 2014 The Flutter Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. --> +<html> +<head> + <meta charset="UTF-8"> + <meta content="IE=Edge" http-equiv="X-UA-Compatible"> + + <title>Integration test. App load with flutter.js. Custom serviceWorkerVersion provided. + + + + + + + + + + + + + + diff --git a/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js b/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js index c60bf3555e5a4..4fd0e51f345ee 100644 --- a/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js +++ b/packages/flutter_tools/lib/src/web/file_generators/js/flutter.js @@ -144,7 +144,7 @@ _flutter.loader = null; const serviceWorkerActivation = navigator.serviceWorker .register(url) - .then(this._getNewServiceWorker) + .then((serviceWorkerRegistration) => this._getNewServiceWorker(serviceWorkerRegistration, serviceWorkerVersion)) .then(this._waitForServiceWorkerActivation); // Timeout race promise @@ -162,9 +162,10 @@ _flutter.loader = null; * awaiting to be installed/updated. * * @param {ServiceWorkerRegistration} serviceWorkerRegistration + * @param {String} serviceWorkerVersion * @returns {Promise} */ - async _getNewServiceWorker(serviceWorkerRegistration) { + async _getNewServiceWorker(serviceWorkerRegistration, serviceWorkerVersion) { if (!serviceWorkerRegistration.active && (serviceWorkerRegistration.installing || serviceWorkerRegistration.waiting)) { // No active web worker and we have installed or are installing // one for the first time. Simply wait for it to activate. From 0f4ca5150ee74ca9b91a7820803191155fe24c61 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Thu, 14 Sep 2023 18:42:57 -0400 Subject: [PATCH 1281/1547] Roll Flutter Engine from 683bca53d4d7 to 45bc4307cda3 (2 revisions) (#134789) https://github.com/flutter/engine/compare/683bca53d4d7...45bc4307cda3 2023-09-14 goderbauer@google.com Enable private field promotion (flutter/engine#45722) 2023-09-14 bdero@google.com [Impeller] Add Entity::RenderingMode enum. (flutter/engine#45845) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 662785feea428..b257616358ee0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -683bca53d4d72e5bb891006dac0e75b667a792d8 +45bc4307cda3f7af61915d5d7875d9ccb6bc637d From 1e4a1be6815cbdac14a010cf3cb2d88d58651c26 Mon Sep 17 00:00:00 2001 From: Zachary Anderson Date: Thu, 14 Sep 2023 19:10:37 -0700 Subject: [PATCH 1282/1547] Move two tests on Pixel 7 from staging to prod (#134784) Related https://github.com/flutter/flutter/issues/134698 --- .ci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 475a91c640683..a224a8fb1d3d4 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1859,7 +1859,6 @@ targets: - name: Linux_pixel_7pro complex_layout_scroll_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > @@ -2365,7 +2364,6 @@ targets: # Pixel 7 Pro, Skia - name: Linux_pixel_7pro new_gallery__transition_perf recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 60 properties: From 09acfe6341e51d306b44dcd047f4bc041f702122 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Fri, 15 Sep 2023 05:52:22 +0200 Subject: [PATCH 1283/1547] Fix memory leak in ListWheelScrollView (#134732) --- .../src/widgets/list_wheel_scroll_view.dart | 21 ++-- .../widgets/list_wheel_scroll_view_test.dart | 103 ++++++++++++++++-- 2 files changed, 100 insertions(+), 24 deletions(-) diff --git a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart index d8d43ef7bfc48..96f56b2d026d1 100644 --- a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart @@ -7,7 +7,6 @@ import 'dart:math' as math; import 'package:flutter/physics.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter/scheduler.dart'; import 'basic.dart'; import 'framework.dart'; @@ -709,12 +708,14 @@ class ListWheelScrollView extends StatefulWidget { class _ListWheelScrollViewState extends State { int _lastReportedItemIndex = 0; - ScrollController? scrollController; + ScrollController? _backupController; + + ScrollController get _effectiveController => + widget.controller ?? (_backupController ??= FixedExtentScrollController()); @override void initState() { super.initState(); - scrollController = widget.controller ?? FixedExtentScrollController(); if (widget.controller is FixedExtentScrollController) { final FixedExtentScrollController controller = widget.controller! as FixedExtentScrollController; _lastReportedItemIndex = controller.initialItem; @@ -722,15 +723,9 @@ class _ListWheelScrollViewState extends State { } @override - void didUpdateWidget(ListWheelScrollView oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.controller != null && widget.controller != scrollController) { - final ScrollController? oldScrollController = scrollController; - SchedulerBinding.instance.addPostFrameCallback((_) { - oldScrollController!.dispose(); - }); - scrollController = widget.controller; - } + void dispose() { + _backupController?.dispose(); + super.dispose(); } bool _handleScrollNotification(ScrollNotification notification) { @@ -754,7 +749,7 @@ class _ListWheelScrollViewState extends State { return NotificationListener( onNotification: _handleScrollNotification, child: _FixedExtentScrollable( - controller: scrollController, + controller: _effectiveController, physics: widget.physics, itemExtent: widget.itemExtent, restorationId: widget.restorationId, diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart index a0e14026f8d93..ef2361d50039c 100644 --- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart +++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart @@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestCallbackPainter, TestClipPaintingContext; @@ -1285,7 +1286,7 @@ void main() { expect(controller.selectedItem, 10); }); - testWidgets('controller hot swappable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('controller hot swappable', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1302,14 +1303,16 @@ void main() { await tester.drag(find.byType(ListWheelScrollView), const Offset(0.0, -500.0)); await tester.pump(); - final FixedExtentScrollController newController = + final FixedExtentScrollController controller1 = FixedExtentScrollController(initialItem: 30); + addTearDown(controller1.dispose); + // Attaching first controller. await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: ListWheelScrollView( - controller: newController, + controller: controller1, itemExtent: 100.0, children: List.generate(100, (int index) { return const Placeholder(); @@ -1320,17 +1323,94 @@ void main() { // initialItem doesn't do anything since the scroll position was already // created. - expect(newController.selectedItem, 5); + expect(controller1.selectedItem, 5); - newController.jumpToItem(50); - expect(newController.selectedItem, 50); - expect(newController.position.pixels, 5000.0); + controller1.jumpToItem(50); + expect(controller1.selectedItem, 50); + expect(controller1.position.pixels, 5000.0); + + final FixedExtentScrollController controller2 = + FixedExtentScrollController(initialItem: 33); + addTearDown(controller2.dispose); + + // Attaching the second controller. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ListWheelScrollView( + controller: controller2, + itemExtent: 100.0, + children: List.generate(100, (int index) { + return const Placeholder(); + }), + ), + ), + ); + + // First controller is now detached. + expect(controller1.hasClients, isFalse); + // initialItem doesn't do anything since the scroll position was already + // created. + expect(controller2.selectedItem, 50); + + controller2.jumpToItem(40); + expect(controller2.selectedItem, 40); + expect(controller2.position.pixels, 4000.0); + + // Now, use the internal controller. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ListWheelScrollView( + itemExtent: 100.0, + children: List.generate(100, (int index) { + return const Placeholder(); + }), + ), + ), + ); + + // Both controllers are now detached. + expect(controller1.hasClients, isFalse); + expect(controller2.hasClients, isFalse); + }); + + testWidgetsWithLeakTracking('controller can be reused', (WidgetTester tester) async { + final FixedExtentScrollController controller = + FixedExtentScrollController(initialItem: 3); + addTearDown(controller.dispose); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ListWheelScrollView( + controller: controller, + itemExtent: 100.0, + children: List.generate(100, (int index) { + return const Placeholder(); + }), + ), + ), + ); + + // selectedItem is equal to the initialItem. + expect(controller.selectedItem, 3); + expect(controller.position.pixels, 300.0); + + controller.jumpToItem(10); + expect(controller.selectedItem, 10); + expect(controller.position.pixels, 1000.0); + + await tester.pumpWidget(const Center()); + + // Controller is now detached. + expect(controller.hasClients, isFalse); - // Now remove the controller await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: ListWheelScrollView( + controller: controller, itemExtent: 100.0, children: List.generate(100, (int index) { return const Placeholder(); @@ -1339,9 +1419,10 @@ void main() { ), ); - // Internally, that same controller is still attached and still at the - // same place. - expect(newController.selectedItem, 50); + // Controller is now attached again. + expect(controller.hasClients, isTrue); + expect(controller.selectedItem, 3); + expect(controller.position.pixels, 300.0); }); }); From 0b540a87f1be9a5bb7e550c777dfe5221c53a112 Mon Sep 17 00:00:00 2001 From: K9i - Kota Hayashi Date: Fri, 15 Sep 2023 13:39:30 +0900 Subject: [PATCH 1284/1547] Applied the logo to the Discord badge. (#134339) Before image After image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55de23b6d9950..7fa62d9b5e88e 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Information on how to get started can be found in our [Build Status - Cirrus]: https://api.cirrus-ci.com/github/flutter/flutter.svg [Build status]: https://cirrus-ci.com/github/flutter/flutter/master [Discord instructions]: https://github.com/flutter/flutter/wiki/Chat -[Discord badge]: https://img.shields.io/discord/608014603317936148 +[Discord badge]: https://img.shields.io/discord/608014603317936148?logo=discord [Twitter handle]: https://img.shields.io/twitter/follow/flutterdev.svg?style=social&label=Follow [Twitter badge]: https://twitter.com/intent/follow?screen_name=flutterdev [layered architecture]: https://docs.flutter.dev/resources/inside-flutter From 2a7ad01e559c614ac00e74ec8ee1ef525c34fdc9 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Fri, 15 Sep 2023 17:15:06 +0200 Subject: [PATCH 1285/1547] Fix navigation rail hover misplaced when direction is RTL and extended is true (#134815) ## Description This PR fixes `NavigationRail` hover position when text direction is set to RTL and `NavigationRail.extended` is true. ## Related Issue Fixes https://github.com/flutter/flutter/issues/134361. ## Tests Adds 1 test. --- .../lib/src/material/navigation_rail.dart | 17 +++- .../test/material/navigation_rail_test.dart | 99 +++++++++++++++++++ 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index abc417813d43a..0524542d1ef20 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -581,9 +581,9 @@ class _RailDestination extends StatelessWidget { ); final ThemeData theme = Theme.of(context); - + final TextDirection textDirection = Directionality.of(context); final bool material3 = theme.useMaterial3; - final EdgeInsets destinationPadding = (padding ?? EdgeInsets.zero).resolve(Directionality.of(context)); + final EdgeInsets destinationPadding = (padding ?? EdgeInsets.zero).resolve(textDirection); Offset indicatorOffset; bool applyXOffset = false; @@ -798,6 +798,7 @@ class _RailDestination extends StatelessWidget { useMaterial3: material3, indicatorOffset: indicatorOffset, applyXOffset: applyXOffset, + textDirection: textDirection, child: content, ), ), @@ -821,6 +822,7 @@ class _IndicatorInkWell extends InkResponse { required this.useMaterial3, required this.indicatorOffset, required this.applyXOffset, + required this.textDirection, }) : super( containedInkWell: true, highlightShape: BoxShape.rectangle, @@ -829,16 +831,25 @@ class _IndicatorInkWell extends InkResponse { ); final bool useMaterial3; + // The offset used to position Ink highlight. final Offset indicatorOffset; + // Whether the horizontal offset from indicatorOffset should be used to position Ink highlight. // If true, Ink highlight uses the indicator horizontal offset. If false, Ink highlight is centered horizontally. final bool applyXOffset; + // The text direction used to adjust the indicator horizontal offset. + final TextDirection textDirection; + @override RectCallback? getRectCallback(RenderBox referenceBox) { if (useMaterial3) { - final double indicatorHorizontalCenter = applyXOffset ? indicatorOffset.dx : referenceBox.size.width / 2; + final double boxWidth = referenceBox.size.width; + double indicatorHorizontalCenter = applyXOffset ? indicatorOffset.dx : boxWidth / 2; + if (textDirection == TextDirection.rtl) { + indicatorHorizontalCenter = boxWidth - indicatorHorizontalCenter; + } return () { return Rect.fromLTWH( indicatorHorizontalCenter - (_kCircularIndicatorDiameter / 2), diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index b1e99e8d406de..3689777c1c40e 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -3276,6 +3276,105 @@ void main() { ); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 + testWidgetsWithLeakTracking('NavigationRail indicator renders properly when text direction is rtl', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/134361. + await tester.pumpWidget(_buildWidget( + NavigationRail( + selectedIndex: 1, + extended: true, + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.favorite_border), + selectedIcon: Icon(Icons.favorite), + label: Text('ABC'), + ), + NavigationRailDestination( + icon: Icon(Icons.bookmark_border), + selectedIcon: Icon(Icons.bookmark), + label: Text('DEF'), + ), + ], + ), + isRTL: true, + )); + + // Hover the first destination. + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byIcon(Icons.favorite_border))); + await tester.pumpAndSettle(); + + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + + // Default values from M3 specification. + const double railMinExtendedWidth = 256.0; + const double indicatorHeight = 32.0; + const double destinationWidth = 72.0; + const double destinationHorizontalPadding = 8.0; + const double indicatorWidth = destinationWidth - 2 * destinationHorizontalPadding; // 56.0 + const double verticalSpacer = 8.0; + const double verticalDestinationSpacingM3 = 12.0; + + // The navigation rail width is the default one because labels are short. + final double railWidth = tester.getSize(find.byType(NavigationRail)).width; + expect(railWidth, railMinExtendedWidth); + + // Expected indicator position. + final double indicatorLeft = railWidth - (destinationWidth - destinationHorizontalPadding / 2); + final double indicatorRight = indicatorLeft + indicatorWidth; + final Rect indicatorRect = Rect.fromLTRB( + indicatorLeft, + verticalDestinationSpacingM3 / 2, + indicatorRight, + verticalDestinationSpacingM3 / 2 + indicatorHeight, + ); + final Rect includedRect = indicatorRect; + final Rect excludedRect = includedRect.inflate(10); + + // Compute the vertical position for the selected destination (the one with 'bookmark' icon). + const double destinationHeight = indicatorHeight + verticalDestinationSpacingM3; + const double secondDestinationVerticalOffset = verticalSpacer + destinationHeight; + const double secondIndicatorVerticalOffset = secondDestinationVerticalOffset + verticalDestinationSpacingM3 / 2; + const double secondDestinationHorizontalOffset = 800 - railMinExtendedWidth; // RTL. + + expect( + inkFeatures, + paints + ..clipPath( + pathMatcher: isPathThat( + includes: [ + includedRect.centerLeft, + includedRect.topCenter, + includedRect.centerRight, + includedRect.bottomCenter, + ], + excludes: [ + excludedRect.centerLeft, + excludedRect.topCenter, + excludedRect.centerRight, + excludedRect.bottomCenter, + ], + ), + ) + // Hover highlight for the hovered destination (the one with 'favorite' icon). + ..rect( + rect: indicatorRect, + color: const Color(0x0a6750a4), + ) + // Indicator for the selected destination (the one with 'bookmark' icon). + ..rrect( + rrect: RRect.fromLTRBR( + secondDestinationHorizontalOffset + indicatorLeft, + secondIndicatorVerticalOffset, + secondDestinationHorizontalOffset + indicatorRight, + secondIndicatorVerticalOffset + indicatorHeight, + const Radius.circular(16), + ), + color: const Color(0xffe8def8), + ), + ); + }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/99933 + testWidgetsWithLeakTracking('NavigationRail indicator scale transform', (WidgetTester tester) async { int selectedIndex = 0; Future buildWidget() async { From 0b9551e6a6f771aa64997cb8c10637292ace4283 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 15 Sep 2023 11:52:08 -0400 Subject: [PATCH 1286/1547] Roll Packages from 275b76ccffa5 to bc8c2f20910b (7 revisions) (#134823) https://github.com/flutter/packages/compare/275b76ccffa5...bc8c2f20910b 2023-09-15 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.6 to 2.21.7 (flutter/packages#4930) 2023-09-14 stuartmorgan@google.com [ios_platform_images] Add extension tests (flutter/packages#4925) 2023-09-14 engine-flutter-autoroll@skia.org Roll Flutter (stable) from 2524052335ec to 367f9ea16bfa (3 revisions) (flutter/packages#4929) 2023-09-14 stuartmorgan@google.com [ci] Enable ios_platform_images tests (flutter/packages#4920) 2023-09-14 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.5 to 2.21.6 (flutter/packages#4922) 2023-09-14 engine-flutter-autoroll@skia.org Roll Flutter from 61b890bfcbc1 to 58ba6c295d8c (16 revisions) (flutter/packages#4928) 2023-09-14 43054281+camsim99@users.noreply.github.com Manual Roll of Flutter from 4e7a07af882c to 61b890bfcbc1 (flutter/packages#4919) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index fab924a8ffcd1..43566584c7ebd 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -275b76ccffa56ec1bfe5bd94a6539fa09518eced +bc8c2f20910bd3e70b1c16622b0d482ef73a0449 From 72b69f944915e8aae2af6a5475d4d6d4f4a4e4af Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 15 Sep 2023 08:55:50 -0700 Subject: [PATCH 1287/1547] Date picker dialog state should dispose members. (#134804) --- .../flutter/lib/src/material/date_picker.dart | 8 + .../test/material/date_picker_test.dart | 182 +++++++++--------- 2 files changed, 103 insertions(+), 87 deletions(-) diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index 88614ec1bdfad..f1b86a3cf3e08 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -416,6 +416,14 @@ class _DatePickerDialogState extends State with RestorationMix late final _RestorableDatePickerEntryMode _entryMode = _RestorableDatePickerEntryMode(widget.initialEntryMode); final _RestorableAutovalidateMode _autovalidateMode = _RestorableAutovalidateMode(AutovalidateMode.disabled); + @override + void dispose() { + _selectedDate.dispose(); + _entryMode.dispose(); + _autovalidateMode.dispose(); + super.dispose(); + } + @override String? get restorationId => widget.restorationId; diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart index 66cddc20c9138..10c2a74f602e5 100644 --- a/packages/flutter/test/material/date_picker_test.dart +++ b/packages/flutter/test/material/date_picker_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -122,7 +123,7 @@ void main() { } group('showDatePicker Dialog', () { - testWidgets('Default dialog size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default dialog size', (WidgetTester tester) async { Future showPicker(WidgetTester tester, Size size) async { tester.view.physicalSize = size; tester.view.devicePixelRatio = 1.0; @@ -149,7 +150,7 @@ void main() { expect(dialogContainerSize, calendarPortraitDialogSizeM3); }); - testWidgets('Default dialog properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default dialog properties', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: true); await prepareDatePicker(tester, (Future date) async { final Material dialogMaterial = tester.widget( @@ -172,13 +173,13 @@ void main() { }, useMaterial3: theme.useMaterial3); }); - testWidgets('Material3 uses sentence case labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 uses sentence case labels', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.text('Select date'), findsOneWidget); }, useMaterial3: true); }); - testWidgets('Cancel, confirm, and help text is used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cancel, confirm, and help text is used', (WidgetTester tester) async { cancelText = 'nope'; confirmText = 'yep'; helpText = 'help'; @@ -189,21 +190,21 @@ void main() { }); }); - testWidgets('Initial date is the default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('OK')); expect(await date, DateTime(2016, DateTime.january, 15)); }); }); - testWidgets('Can cancel', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can cancel', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('CANCEL')); expect(await date, isNull); }); }); - testWidgets('Can switch from calendar to input entry mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can switch from calendar to input entry mode', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsNothing); await tester.tap(find.byIcon(Icons.edit)); @@ -212,7 +213,7 @@ void main() { }); }); - testWidgets('Can switch from input to calendar entry mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can switch from input to calendar entry mode', (WidgetTester tester) async { initialEntryMode = DatePickerEntryMode.input; await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsOneWidget); @@ -222,7 +223,7 @@ void main() { }); }); - testWidgets('Can not switch out of calendarOnly mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can not switch out of calendarOnly mode', (WidgetTester tester) async { initialEntryMode = DatePickerEntryMode.calendarOnly; await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsNothing); @@ -230,7 +231,7 @@ void main() { }); }); - testWidgets('Can not switch out of inputOnly mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can not switch out of inputOnly mode', (WidgetTester tester) async { initialEntryMode = DatePickerEntryMode.inputOnly; await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsOneWidget); @@ -238,7 +239,7 @@ void main() { }); }); - testWidgets('Switching to input mode keeps selected date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switching to input mode keeps selected date', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('12')); await tester.tap(find.byIcon(Icons.edit)); @@ -248,7 +249,7 @@ void main() { }); }); - testWidgets('Input only mode should validate date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Input only mode should validate date', (WidgetTester tester) async { initialEntryMode = DatePickerEntryMode.inputOnly; await prepareDatePicker(tester, (Future date) async { // Enter text input mode and type an invalid date to get error. @@ -259,7 +260,7 @@ void main() { }); }); - testWidgets('Switching to input mode resets input error state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Switching to input mode resets input error state', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { // Enter text input mode and type an invalid date to get error. await tester.tap(find.byIcon(Icons.edit)); @@ -283,7 +284,7 @@ void main() { }); }); - testWidgets('builder parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builder parameter', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection) { return MaterialApp( home: Material( @@ -340,7 +341,7 @@ void main() { rootObserver = _DatePickerObserver(); }); - testWidgets('Barrier is dismissible with default parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier is dismissible with default parameter', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( navigatorObservers: [rootObserver], @@ -378,7 +379,7 @@ void main() { expect(rootObserver.datePickerCount, 0); }); - testWidgets('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier is not dismissible with barrierDismissible is false', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( navigatorObservers: [rootObserver], @@ -418,7 +419,7 @@ void main() { }); }); - testWidgets('Barrier color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -484,7 +485,7 @@ void main() { expect(tester.widget(find.byType(ModalBarrier).last).color, Colors.pink); }); - testWidgets('Barrier Label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Barrier Label', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -517,7 +518,7 @@ void main() { expect(tester.widget(find.byType(ModalBarrier).last).semanticsLabel, 'Custom Label'); }); - testWidgets('uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final _DatePickerObserver rootObserver = _DatePickerObserver(); final _DatePickerObserver nestedObserver = _DatePickerObserver(); @@ -554,7 +555,7 @@ void main() { expect(nestedObserver.datePickerCount, 1); }); - testWidgets('honors DialogTheme for shape and elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('honors DialogTheme for shape and elevation', (WidgetTester tester) async { // Test that the defaults work const DialogTheme datePickerDefaultDialogTheme = DialogTheme( shape: RoundedRectangleBorder( @@ -627,7 +628,7 @@ void main() { expect(themeDialogMaterial.elevation, customDialogTheme.elevation); }); - testWidgets('OK Cancel button layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OK Cancel button layout', (WidgetTester tester) async { Widget buildFrame(TextDirection textDirection) { return MaterialApp( theme: ThemeData(useMaterial3: false), @@ -703,7 +704,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('honors switchToInputEntryModeIcon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('honors switchToInputEntryModeIcon', (WidgetTester tester) async { Widget buildApp({bool? useMaterial3, Icon? switchToInputEntryModeIcon}) { return MaterialApp( theme: ThemeData( @@ -759,7 +760,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('honors switchToCalendarEntryModeIcon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('honors switchToCalendarEntryModeIcon', (WidgetTester tester) async { Widget buildApp({bool? useMaterial3, Icon? switchToCalendarEntryModeIcon}) { return MaterialApp( theme: ThemeData( @@ -818,7 +819,7 @@ void main() { }); group('Calendar mode', () { - testWidgets('Default Calendar mode layout (Landscape)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default Calendar mode layout (Landscape)', (WidgetTester tester) async { final Finder helpText = find.text('Select date'); final Finder headerText = find.text('Fri, Jan 15'); final Finder subHeaderText = find.text('January 2016'); @@ -917,7 +918,7 @@ void main() { expect(cancelButtonTopRight.dx, okButtonTopLeft.dx - 8); }); - testWidgets('Default Calendar mode layout (Portrait)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default Calendar mode layout (Portrait)', (WidgetTester tester) async { final Finder helpText = find.text('Select date'); final Finder headerText = find.text('Fri, Jan 15'); final Finder subHeaderText = find.text('January 2016'); @@ -1016,7 +1017,7 @@ void main() { expect(cancelButtonTopRight.dx, okButtonTopLeft.dx - 8); }); - testWidgets('Can select a day', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a day', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('12')); await tester.tap(find.text('OK')); @@ -1024,7 +1025,7 @@ void main() { }); }); - testWidgets('Can select a month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a month', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(previousMonthIcon); await tester.pumpAndSettle(const Duration(seconds: 1)); @@ -1034,7 +1035,7 @@ void main() { }); }); - testWidgets('Can select a year', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('January 2016')); // Switch to year mode. await tester.pump(); @@ -1044,7 +1045,7 @@ void main() { }); }); - testWidgets('Can select a day with no initial date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a day with no initial date', (WidgetTester tester) async { initialDate = null; await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('12')); @@ -1053,7 +1054,7 @@ void main() { }); }); - testWidgets('Can select a month with no initial date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a month with no initial date', (WidgetTester tester) async { initialDate = null; await prepareDatePicker(tester, (Future date) async { await tester.tap(previousMonthIcon); @@ -1064,7 +1065,7 @@ void main() { }); }); - testWidgets('Can select a year with no initial date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year with no initial date', (WidgetTester tester) async { initialDate = null; await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('January 2016')); // Switch to year mode. @@ -1075,7 +1076,7 @@ void main() { }); }); - testWidgets('Selecting date does not change displayed month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting date does not change displayed month', (WidgetTester tester) async { initialDate = DateTime(2020, DateTime.march, 15); await prepareDatePicker(tester, (Future date) async { await tester.tap(nextMonthIcon); @@ -1089,7 +1090,7 @@ void main() { }); }); - testWidgets('Changing year does change selected date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing year does change selected date', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('January 2016')); await tester.pump(); @@ -1100,7 +1101,7 @@ void main() { }); }); - testWidgets('Changing year does not change the month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing year does not change the month', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(nextMonthIcon); await tester.pumpAndSettle(); @@ -1114,7 +1115,7 @@ void main() { }); }); - testWidgets('Can select a year and then a day', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year and then a day', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('January 2016')); // Switch to year mode. await tester.pump(); @@ -1126,7 +1127,7 @@ void main() { }); }); - testWidgets('Current year is visible in year picker', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Current year is visible in year picker', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('January 2016')); // Switch to year mode. await tester.pump(); @@ -1134,7 +1135,7 @@ void main() { }); }); - testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select a day outside bounds', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 15); firstDate = initialDate!; lastDate = initialDate!; @@ -1149,7 +1150,7 @@ void main() { }); }); - testWidgets('Cannot select a month past last date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select a month past last date', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 15); firstDate = initialDate!; lastDate = DateTime(2017, DateTime.february, 20); @@ -1161,7 +1162,7 @@ void main() { }); }); - testWidgets('Cannot select a month before first date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select a month before first date', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 15); firstDate = DateTime(2016, DateTime.december, 10); lastDate = initialDate!; @@ -1173,7 +1174,7 @@ void main() { }); }); - testWidgets('Cannot select disabled year', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select disabled year', (WidgetTester tester) async { initialDate = DateTime(2018, DateTime.july, 4); firstDate = DateTime(2018, DateTime.june, 9); lastDate = DateTime(2018, DateTime.december, 15); @@ -1188,7 +1189,7 @@ void main() { }); }); - testWidgets('Selecting firstDate year respects firstDate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting firstDate year respects firstDate', (WidgetTester tester) async { initialDate = DateTime(2018, DateTime.may, 4); firstDate = DateTime(2016, DateTime.june, 9); lastDate = DateTime(2019, DateTime.january, 15); @@ -1202,7 +1203,7 @@ void main() { }); }); - testWidgets('Selecting lastDate year respects lastDate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting lastDate year respects lastDate', (WidgetTester tester) async { initialDate = DateTime(2018, DateTime.may, 4); firstDate = DateTime(2016, DateTime.june, 9); lastDate = DateTime(2019, DateTime.january, 15); @@ -1216,7 +1217,7 @@ void main() { }); }); - testWidgets('Only predicate days are selectable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Only predicate days are selectable', (WidgetTester tester) async { initialDate = DateTime(2017, DateTime.january, 16); firstDate = DateTime(2017, DateTime.january, 10); lastDate = DateTime(2017, DateTime.january, 20); @@ -1230,7 +1231,7 @@ void main() { }); }); - testWidgets('Can select initial calendar picker mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select initial calendar picker mode', (WidgetTester tester) async { initialDate = DateTime(2014, DateTime.january, 15); initialCalendarMode = DatePickerMode.year; await prepareDatePicker(tester, (Future date) async { @@ -1243,7 +1244,7 @@ void main() { }); }); - testWidgets('currentDate is highlighted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('currentDate is highlighted', (WidgetTester tester) async { today = DateTime(2016, 1, 2); await prepareDatePicker(tester, (Future date) async { await tester.pump(); @@ -1256,7 +1257,7 @@ void main() { }); }); - testWidgets('Date picker dayOverlayColor resolves pressed state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Date picker dayOverlayColor resolves pressed state', (WidgetTester tester) async { today = DateTime(2023, 5, 4); final ThemeData theme = ThemeData(); final bool material3 = theme.useMaterial3; @@ -1288,7 +1289,7 @@ void main() { }, theme: theme); }); - testWidgets('Selecting date does not switch picker to year selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting date does not switch picker to year selection', (WidgetTester tester) async { initialDate = DateTime(2020, DateTime.may, 10); initialCalendarMode = DatePickerMode.year; await prepareDatePicker(tester, (Future date) async { @@ -1312,7 +1313,7 @@ void main() { initialEntryMode = DatePickerEntryMode.input; }); - testWidgets('Default InputDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default InputDecoration', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { final InputDecoration decoration = tester.widget( find.byType(TextField)).decoration!; @@ -1324,13 +1325,13 @@ void main() { }, useMaterial3: true); }); - testWidgets('Initial entry mode is used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial entry mode is used', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsOneWidget); }); }); - testWidgets('Hint, label, and help text is used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hint, label, and help text is used', (WidgetTester tester) async { cancelText = 'nope'; confirmText = 'yep'; fieldHintText = 'hint'; @@ -1345,7 +1346,7 @@ void main() { }); }); - testWidgets('KeyboardType is used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('KeyboardType is used', (WidgetTester tester) async { keyboardType = TextInputType.text; await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); @@ -1353,14 +1354,14 @@ void main() { }); }); - testWidgets('Initial date is the default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Initial date is the default', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { await tester.tap(find.text('OK')); expect(await date, DateTime(2016, DateTime.january, 15)); }); }); - testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can toggle to calendar entry mode', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsOneWidget); await tester.tap(find.byIcon(Icons.calendar_today)); @@ -1369,7 +1370,7 @@ void main() { }); }); - testWidgets('Toggle to calendar mode keeps selected date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Toggle to calendar mode keeps selected date', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); field.controller!.clear(); @@ -1382,7 +1383,7 @@ void main() { }); }); - testWidgets('Entered text returns date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Entered text returns date', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); field.controller!.clear(); @@ -1393,7 +1394,7 @@ void main() { }); }); - testWidgets('Too short entered text shows error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Too short entered text shows error', (WidgetTester tester) async { errorFormatText = 'oops'; await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); @@ -1409,7 +1410,7 @@ void main() { }); }); - testWidgets('Bad format entered text shows error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Bad format entered text shows error', (WidgetTester tester) async { errorFormatText = 'oops'; await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); @@ -1426,7 +1427,7 @@ void main() { }); }); - testWidgets('Invalid entered text shows error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Invalid entered text shows error', (WidgetTester tester) async { errorInvalidText = 'oops'; await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); @@ -1442,7 +1443,7 @@ void main() { }); }); - testWidgets('Invalid entered text shows error on autovalidate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Invalid entered text shows error on autovalidate', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/126397. await prepareDatePicker(tester, (Future date) async { final TextField field = textField(tester); @@ -1471,7 +1472,7 @@ void main() { }); // This is a regression test for https://github.com/flutter/flutter/issues/131989. - testWidgets('Dialog contents do not overflow when resized from landscape to portrait', + testWidgetsWithLeakTracking('Dialog contents do not overflow when resized from landscape to portrait', (WidgetTester tester) async { addTearDown(tester.view.reset); // Initial window size is wide for landscape mode. @@ -1488,7 +1489,7 @@ void main() { }); group('Semantics', () { - testWidgets('calendar mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('calendar mode', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); await prepareDatePicker(tester, (Future date) async { @@ -1537,7 +1538,7 @@ void main() { semantics.dispose(); }); - testWidgets('input mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('input mode', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); initialEntryMode = DatePickerEntryMode.input; @@ -1582,7 +1583,7 @@ void main() { }); group('Keyboard navigation', () { - testWidgets('Can toggle to calendar entry mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can toggle to calendar entry mode', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.byType(TextField), findsNothing); // Navigate to the entry toggle button and activate it @@ -1598,7 +1599,7 @@ void main() { }); }); - testWidgets('Can toggle to year mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can toggle to year mode', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.text('2016'), findsNothing); // Navigate to the year selector and activate it @@ -1610,7 +1611,7 @@ void main() { }); }); - testWidgets('Can navigate next/previous months', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can navigate next/previous months', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { expect(find.text('January 2016'), findsOneWidget); // Navigate to the previous month button and activate it twice @@ -1638,7 +1639,7 @@ void main() { }); }); - testWidgets('Can navigate date grid with arrow keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can navigate date grid with arrow keys', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { // Navigate to the grid await tester.sendKeyEvent(LogicalKeyboardKey.tab); @@ -1674,7 +1675,7 @@ void main() { }); }); - testWidgets('Navigating with arrow keys scrolls months', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigating with arrow keys scrolls months', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { // Navigate to the grid await tester.sendKeyEvent(LogicalKeyboardKey.tab); @@ -1722,7 +1723,7 @@ void main() { }); }); - testWidgets('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { // Navigate to the grid await tester.sendKeyEvent(LogicalKeyboardKey.tab); @@ -1787,49 +1788,49 @@ void main() { await tester.pumpAndSettle(); } - testWidgets('common screen size - portrait', (WidgetTester tester) async { + testWidgetsWithLeakTracking('common screen size - portrait', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizePortrait); expect(tester.takeException(), isNull); }); - testWidgets('common screen size - landscape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('common screen size - landscape', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizeLandscape); expect(tester.takeException(), isNull); }); - testWidgets('common screen size - portrait - textScale 1.3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('common screen size - portrait - textScale 1.3', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizePortrait, 1.3); expect(tester.takeException(), isNull); }); - testWidgets('common screen size - landscape - textScale 1.3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('common screen size - landscape - textScale 1.3', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizeLandscape, 1.3); expect(tester.takeException(), isNull); }); - testWidgets('small screen size - portrait', (WidgetTester tester) async { + testWidgetsWithLeakTracking('small screen size - portrait', (WidgetTester tester) async { await showPicker(tester, kSmallScreenSizePortrait); expect(tester.takeException(), isNull); }); - testWidgets('small screen size - landscape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('small screen size - landscape', (WidgetTester tester) async { await showPicker(tester, kSmallScreenSizeLandscape); expect(tester.takeException(), isNull); }); - testWidgets('small screen size - portrait -textScale 1.3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('small screen size - portrait -textScale 1.3', (WidgetTester tester) async { await showPicker(tester, kSmallScreenSizePortrait, 1.3); expect(tester.takeException(), isNull); }); - testWidgets('small screen size - landscape - textScale 1.3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('small screen size - landscape - textScale 1.3', (WidgetTester tester) async { await showPicker(tester, kSmallScreenSizeLandscape, 1.3); expect(tester.takeException(), isNull); }); }); group('showDatePicker avoids overlapping display features', () { - testWidgets('positioning with anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with anchorPoint', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1867,7 +1868,7 @@ void main() { expect(tester.getBottomRight(find.byType(DatePickerDialog)), const Offset(800.0, 600.0)); }); - testWidgets('positioning with Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with Directionality', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1907,7 +1908,7 @@ void main() { expect(tester.getBottomRight(find.byType(DatePickerDialog)), const Offset(800.0, 600.0)); }); - testWidgets('positioning with defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with defaults', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1945,7 +1946,7 @@ void main() { }); }); - testWidgets('DatePickerDialog is state restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DatePickerDialog is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -1998,7 +1999,7 @@ void main() { expect(find.text('30/7/2021'), findsOneWidget); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('DatePickerDialog state restoration - DatePickerEntryMode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DatePickerDialog state restoration - DatePickerEntryMode', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', @@ -2047,7 +2048,7 @@ void main() { expect(find.byIcon(Icons.edit), findsNothing); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('Test Callback on Toggle of DatePicker Mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Test Callback on Toggle of DatePicker Mode', (WidgetTester tester) async { prepareDatePicker(tester, (Future date) async { await tester.tap(find.byIcon(Icons.edit)); expect(currentMode, DatePickerEntryMode.input); @@ -2075,14 +2076,14 @@ void main() { await prepareDatePicker(tester, (Future date) async { }, useMaterial3: true); } - testWidgets('portrait', (WidgetTester tester) async { + testWidgetsWithLeakTracking('portrait', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizePortrait); expect(tester.widget(find.text('Fri, Jan 15')).style?.fontSize, 32); await tester.tap(find.text('Cancel')); await tester.pumpAndSettle(); }); - testWidgets('landscape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('landscape', (WidgetTester tester) async { await showPicker(tester, kCommonScreenSizeLandscape); expect(tester.widget(find.text('Fri, Jan 15')).style?.fontSize, 24); await tester.tap(find.text('Cancel')); @@ -2096,7 +2097,7 @@ void main() { // can be deleted. group('showDatePicker Dialog', () { - testWidgets('Default dialog size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default dialog size', (WidgetTester tester) async { Future showPicker(WidgetTester tester, Size size) async { tester.view.physicalSize = size; tester.view.devicePixelRatio = 1.0; @@ -2125,7 +2126,7 @@ void main() { expect(dialogContainerSize, calendarPortraitDialogSizeM2); }); - testWidgets('Default dialog properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default dialog properties', (WidgetTester tester) async { final ThemeData theme = ThemeData(useMaterial3: false); await prepareDatePicker(tester, (Future date) async { final Material dialogMaterial = tester.widget( @@ -2157,7 +2158,7 @@ void main() { initialEntryMode = DatePickerEntryMode.input; }); - testWidgets('Default InputDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default InputDecoration', (WidgetTester tester) async { await prepareDatePicker(tester, (Future date) async { final InputDecoration decoration = tester.widget( find.byType(TextField)).decoration!; @@ -2201,6 +2202,13 @@ class _RestorableDatePickerDialogTestWidgetState extends State<_RestorableDatePi }, ); + @override + void dispose() { + _selectedDate.dispose(); + _restorableDatePickerRouteFuture.dispose(); + super.dispose(); + } + @override void restoreState(RestorationBucket? oldBucket, bool initialRestore) { registerForRestoration(_selectedDate, 'selected_date'); From 8ebb8d4f11283a3c12eea594d3667147bc3eae34 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Fri, 15 Sep 2023 21:23:08 +0200 Subject: [PATCH 1288/1547] Speed up native assets target (#134523) Speeds up the native assets target in the backend by 1. changing other targets `gen_dart_plugin_registrant` and `release_unpack_ios` to do async I/O, 2. not reparsing the package config, and 3. not calling `dart pub deps --json` for 0 or 1 packages (fixed package:native_assets_builder). * https://github.com/flutter/flutter/issues/134427 ``` [ +2 ms] native_assets: Starting due to {} [ +2 ms] Skipping target: gen_localizations [ +1 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged: The following inputs have updated contents: /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/package_config_subset} [ +33 ms] gen_dart_plugin_registrant: Complete [ +107 ms] release_unpack_ios: Complete [ +60 ms] Writing native_assets.yaml. [ +7 ms] Writing /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/flutter_build/be2692bbfbc0b9a27fcd2422d52354c6/native_assets.yaml done. [ ] native_assets: Complete ``` -> ``` [ +4 ms] native_assets: Starting due to {} [ ] Skipping target: gen_localizations [ +1 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged: The following inputs have updated contents: /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/package_config_subset} [ +31 ms] Writing native_assets.yaml. [ +8 ms] Writing /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/flutter_build/f9451a65a465bfab70d004e21d6cc1d6/native_assets.yaml done. [ +1 ms] native_assets: Complete ``` ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../lib/src/build_system/targets/ios.dart | 31 ++++++++----- .../lib/src/build_system/targets/macos.dart | 12 +++-- .../build_system/targets/native_assets.dart | 18 +++++++- .../lib/src/flutter_plugins.dart | 46 +++++++++++-------- .../flutter_tools/lib/src/native_assets.dart | 38 +++++++++++---- packages/flutter_tools/lib/src/run_hot.dart | 7 ++- .../lib/src/test/test_compiler.dart | 7 ++- packages/flutter_tools/pubspec.yaml | 4 +- .../targets/native_assets_test.dart | 16 +++++++ .../macos/native_assets_test.dart | 18 +++++++- 10 files changed, 145 insertions(+), 52 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index 2ced8b0164798..9f43d01fafb4d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -287,21 +287,21 @@ abstract class UnpackIOS extends Target { if (archs == null) { throw MissingDefineException(kIosArchs, name); } - _copyFramework(environment, sdkRoot); + await _copyFramework(environment, sdkRoot); final File frameworkBinary = environment.outputDir.childDirectory('Flutter.framework').childFile('Flutter'); final String frameworkBinaryPath = frameworkBinary.path; - if (!frameworkBinary.existsSync()) { + if (!await frameworkBinary.exists()) { throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin'); } - _thinFramework(environment, frameworkBinaryPath, archs); + await _thinFramework(environment, frameworkBinaryPath, archs); if (buildMode == BuildMode.release) { - _bitcodeStripFramework(environment, frameworkBinaryPath); + await _bitcodeStripFramework(environment, frameworkBinaryPath); } await _signFramework(environment, frameworkBinary, buildMode); } - void _copyFramework(Environment environment, String sdkRoot) { + Future _copyFramework(Environment environment, String sdkRoot) async { final EnvironmentType? environmentType = environmentTypeFromSdkroot(sdkRoot, environment.fileSystem); final String basePath = environment.artifacts.getArtifactPath( Artifact.flutterFramework, @@ -310,7 +310,7 @@ abstract class UnpackIOS extends Target { environmentType: environmentType, ); - final ProcessResult result = environment.processManager.runSync([ + final ProcessResult result = await environment.processManager.run([ 'rsync', '-av', '--delete', @@ -328,16 +328,20 @@ abstract class UnpackIOS extends Target { } /// Destructively thin Flutter.framework to include only the specified architectures. - void _thinFramework(Environment environment, String frameworkBinaryPath, String archs) { + Future _thinFramework( + Environment environment, + String frameworkBinaryPath, + String archs, + ) async { final List archList = archs.split(' ').toList(); - final ProcessResult infoResult = environment.processManager.runSync([ + final ProcessResult infoResult = await environment.processManager.run([ 'lipo', '-info', frameworkBinaryPath, ]); final String lipoInfo = infoResult.stdout as String; - final ProcessResult verifyResult = environment.processManager.runSync([ + final ProcessResult verifyResult = await environment.processManager.run([ 'lipo', frameworkBinaryPath, '-verify_arch', @@ -355,7 +359,7 @@ abstract class UnpackIOS extends Target { } // Thin in-place. - final ProcessResult extractResult = environment.processManager.runSync([ + final ProcessResult extractResult = await environment.processManager.run([ 'lipo', '-output', frameworkBinaryPath, @@ -374,8 +378,11 @@ abstract class UnpackIOS extends Target { /// Destructively strip bitcode from the framework. This can be removed /// when the framework is no longer built with bitcode. - void _bitcodeStripFramework(Environment environment, String frameworkBinaryPath) { - final ProcessResult stripResult = environment.processManager.runSync([ + Future _bitcodeStripFramework( + Environment environment, + String frameworkBinaryPath, + ) async { + final ProcessResult stripResult = await environment.processManager.run([ 'xcrun', 'bitcode_strip', frameworkBinaryPath, diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index 366268d59f0e4..dadf976f473ac 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -80,7 +80,7 @@ abstract class UnpackMacOS extends Target { if (!frameworkBinary.existsSync()) { throw Exception('Binary $frameworkBinaryPath does not exist, cannot thin'); } - _thinFramework(environment, frameworkBinaryPath); + await _thinFramework(environment, frameworkBinaryPath); } static const List _copyDenylist = ['entitlements.txt', 'without_entitlements.txt']; @@ -96,17 +96,21 @@ abstract class UnpackMacOS extends Target { } } - void _thinFramework(Environment environment, String frameworkBinaryPath) { + Future _thinFramework( + Environment environment, + String frameworkBinaryPath, + ) async { final String archs = environment.defines[kDarwinArchs] ?? 'x86_64 arm64'; final List archList = archs.split(' ').toList(); - final ProcessResult infoResult = environment.processManager.runSync([ + final ProcessResult infoResult = + await environment.processManager.run([ 'lipo', '-info', frameworkBinaryPath, ]); final String lipoInfo = infoResult.stdout as String; - final ProcessResult verifyResult = environment.processManager.runSync([ + final ProcessResult verifyResult = await environment.processManager.run([ 'lipo', frameworkBinaryPath, '-verify_arch', diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index 073b5863833dc..6e73882927f99 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -4,11 +4,13 @@ import 'package:meta/meta.dart'; import 'package:native_assets_cli/native_assets_cli.dart' show Asset; +import 'package:package_config/package_config_types.dart'; import '../../base/common.dart'; import '../../base/file_system.dart'; import '../../base/platform.dart'; import '../../build_info.dart'; +import '../../dart/package_map.dart'; import '../../ios/native_assets.dart'; import '../../macos/native_assets.dart'; import '../../macos/xcode.dart'; @@ -52,7 +54,21 @@ class NativeAssets extends Target { final Uri projectUri = environment.projectDir.uri; final FileSystem fileSystem = environment.fileSystem; - final NativeAssetsBuildRunner buildRunner = _buildRunner ?? NativeAssetsBuildRunnerImpl(projectUri, fileSystem, environment.logger); + final File packagesFile = fileSystem + .directory(projectUri) + .childDirectory('.dart_tool') + .childFile('package_config.json'); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + packagesFile, + logger: environment.logger, + ); + final NativeAssetsBuildRunner buildRunner = _buildRunner ?? + NativeAssetsBuildRunnerImpl( + projectUri, + packageConfig, + fileSystem, + environment.logger, + ); final List dependencies; switch (targetPlatform) { diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 50f14c0644091..87880d7583b83 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -26,14 +26,20 @@ import 'platform_plugins.dart'; import 'plugins.dart'; import 'project.dart'; -void _renderTemplateToFile(String template, Object? context, File file, TemplateRenderer templateRenderer) { +Future _renderTemplateToFile( + String template, + Object? context, + File file, + TemplateRenderer templateRenderer, +) async { final String renderedTemplate = templateRenderer .renderString(template, context); - file.createSync(recursive: true); - file.writeAsStringSync(renderedTemplate); + await file.create(recursive: true); + await file.writeAsString(renderedTemplate); } -Plugin? _pluginFromPackage(String name, Uri packageRoot, Set appDependencies, {FileSystem? fileSystem}) { +Future _pluginFromPackage(String name, Uri packageRoot, Set appDependencies, + {FileSystem? fileSystem}) async { final FileSystem fs = fileSystem ?? globals.fs; final File pubspecFile = fs.file(packageRoot.resolve('pubspec.yaml')); if (!pubspecFile.existsSync()) { @@ -42,7 +48,7 @@ Plugin? _pluginFromPackage(String name, Uri packageRoot, Set appDependen Object? pubspec; try { - pubspec = loadYaml(pubspecFile.readAsStringSync()); + pubspec = loadYaml(await pubspecFile.readAsString()); } on YamlException catch (err) { globals.printTrace('Failed to parse plugin manifest for $name: $err'); // Do nothing, potentially not a plugin. @@ -85,7 +91,7 @@ Future> findPlugins(FlutterProject project, { bool throwOnError = t ); for (final Package package in packageConfig.packages) { final Uri packageRoot = package.packageUriRoot.resolve('..'); - final Plugin? plugin = _pluginFromPackage( + final Plugin? plugin = await _pluginFromPackage( package.name, packageRoot, project.manifest.dependencies, @@ -445,7 +451,7 @@ Future _writeAndroidPluginRegistrant(FlutterProject project, List templateContent = _androidPluginRegistryTemplateOldEmbedding; } globals.printTrace('Generating $registryPath'); - _renderTemplateToFile( + await _renderTemplateToFile( templateContent, templateContext, globals.fs.file(registryPath), @@ -774,20 +780,20 @@ Future _writeIOSPluginRegistrant(FlutterProject project, List plug }; if (project.isModule) { final Directory registryDirectory = project.ios.pluginRegistrantHost; - _renderTemplateToFile( + await _renderTemplateToFile( _pluginRegistrantPodspecTemplate, context, registryDirectory.childFile('FlutterPluginRegistrant.podspec'), globals.templateRenderer, ); } - _renderTemplateToFile( + await _renderTemplateToFile( _objcPluginRegistryHeaderTemplate, context, project.ios.pluginRegistrantHeader, globals.templateRenderer, ); - _renderTemplateToFile( + await _renderTemplateToFile( _objcPluginRegistryImplementationTemplate, context, project.ios.pluginRegistrantImplementation, @@ -829,13 +835,13 @@ Future _writeLinuxPluginFiles(FlutterProject project, List plugins } Future _writeLinuxPluginRegistrant(Directory destination, Map templateContext) async { - _renderTemplateToFile( + await _renderTemplateToFile( _linuxPluginRegistryHeaderTemplate, templateContext, destination.childFile('generated_plugin_registrant.h'), globals.templateRenderer, ); - _renderTemplateToFile( + await _renderTemplateToFile( _linuxPluginRegistryImplementationTemplate, templateContext, destination.childFile('generated_plugin_registrant.cc'), @@ -844,7 +850,7 @@ Future _writeLinuxPluginRegistrant(Directory destination, Map _writePluginCmakefile(File destinationFile, Map templateContext, TemplateRenderer templateRenderer) async { - _renderTemplateToFile( + await _renderTemplateToFile( _pluginCmakefileTemplate, templateContext, destinationFile, @@ -860,7 +866,7 @@ Future _writeMacOSPluginRegistrant(FlutterProject project, List pl 'framework': 'FlutterMacOS', 'methodChannelPlugins': macosMethodChannelPlugins, }; - _renderTemplateToFile( + await _renderTemplateToFile( _swiftPluginRegistryTemplate, context, project.macos.managedDirectory.childFile('GeneratedPluginRegistrant.swift'), @@ -931,13 +937,13 @@ Future writeWindowsPluginFiles(FlutterProject project, List plugin } Future _writeCppPluginRegistrant(Directory destination, Map templateContext, TemplateRenderer templateRenderer) async { - _renderTemplateToFile( + await _renderTemplateToFile( _cppPluginRegistryHeaderTemplate, templateContext, destination.childFile('generated_plugin_registrant.h'), templateRenderer, ); - _renderTemplateToFile( + await _renderTemplateToFile( _cppPluginRegistryImplementationTemplate, templateContext, destination.childFile('generated_plugin_registrant.cc'), @@ -955,7 +961,7 @@ Future _writeWebPluginRegistrant(FlutterProject project, List plug final String template = webPlugins.isEmpty ? _noopDartPluginRegistryTemplate : _dartPluginRegistryTemplate; - _renderTemplateToFile( + await _renderTemplateToFile( template, context, pluginFile, @@ -1411,8 +1417,8 @@ Future generateMainDartWithPluginRegistrant( final File newMainDart = rootProject.dartPluginRegistrant; if (resolutions.isEmpty) { try { - if (newMainDart.existsSync()) { - newMainDart.deleteSync(); + if (await newMainDart.exists()) { + await newMainDart.delete(); } } on FileSystemException catch (error) { globals.printWarning( @@ -1428,7 +1434,7 @@ Future generateMainDartWithPluginRegistrant( (templateContext[resolution.platform] as List?)?.add(resolution.toMap()); } try { - _renderTemplateToFile( + await _renderTemplateToFile( _dartPluginRegistryForNonWebTemplate, templateContext, newMainDart, diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index 0255a3c4dd4a6..3253d29191581 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -5,7 +5,8 @@ // Logic for native assets shared between all host OSes. import 'package:logging/logging.dart' as logging; -import 'package:native_assets_builder/native_assets_builder.dart' as native_assets_builder; +import 'package:native_assets_builder/native_assets_builder.dart' hide NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart' as native_assets_builder show NativeAssetsBuildRunner; import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:package_config/package_config_types.dart'; @@ -37,7 +38,7 @@ abstract class NativeAssetsBuildRunner { Future> packagesWithNativeAssets(); /// Runs all [packagesWithNativeAssets] `build.dart` in dry run. - Future dryRun({ + Future dryRun({ required bool includeParentEnvironment, required LinkModePreference linkModePreference, required OS targetOs, @@ -45,7 +46,7 @@ abstract class NativeAssetsBuildRunner { }); /// Runs all [packagesWithNativeAssets] `build.dart`. - Future build({ + Future build({ required bool includeParentEnvironment, required BuildMode buildMode, required LinkModePreference linkModePreference, @@ -62,9 +63,15 @@ abstract class NativeAssetsBuildRunner { /// Uses `package:native_assets_builder` for its implementation. class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { - NativeAssetsBuildRunnerImpl(this.projectUri, this.fileSystem, this.logger); + NativeAssetsBuildRunnerImpl( + this.projectUri, + this.packageConfig, + this.fileSystem, + this.logger, + ); final Uri projectUri; + final PackageConfig packageConfig; final FileSystem fileSystem; final Logger logger; @@ -90,8 +97,6 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { dartExecutable: _dartExecutable, ); - native_assets_builder.PackageLayout? _packageLayout; - @override Future hasPackageConfig() { final File packageConfigJson = fileSystem @@ -103,27 +108,35 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { @override Future> packagesWithNativeAssets() async { - _packageLayout ??= await native_assets_builder.PackageLayout.fromRootPackageRoot(projectUri); - return _packageLayout!.packagesWithNativeAssets; + final PackageLayout packageLayout = PackageLayout.fromPackageConfig( + packageConfig, + projectUri.resolve('.dart_tool/package_config.json'), + ); + return packageLayout.packagesWithNativeAssets; } @override - Future dryRun({ + Future dryRun({ required bool includeParentEnvironment, required LinkModePreference linkModePreference, required OS targetOs, required Uri workingDirectory, }) { + final PackageLayout packageLayout = PackageLayout.fromPackageConfig( + packageConfig, + projectUri.resolve('.dart_tool/package_config.json'), + ); return _buildRunner.dryRun( includeParentEnvironment: includeParentEnvironment, linkModePreference: linkModePreference, targetOs: targetOs, workingDirectory: workingDirectory, + packageLayout: packageLayout, ); } @override - Future build({ + Future build({ required bool includeParentEnvironment, required BuildMode buildMode, required LinkModePreference linkModePreference, @@ -133,6 +146,10 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { int? targetAndroidNdkApi, IOSSdk? targetIOSSdk, }) { + final PackageLayout packageLayout = PackageLayout.fromPackageConfig( + packageConfig, + projectUri.resolve('.dart_tool/package_config.json'), + ); return _buildRunner.build( buildMode: buildMode, cCompilerConfig: cCompilerConfig, @@ -142,6 +159,7 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { targetAndroidNdkApi: targetAndroidNdkApi, targetIOSSdk: targetIOSSdk, workingDirectory: workingDirectory, + packageLayout: packageLayout, ); } diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 8665ec322ef4f..6e829ed18c73e 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -366,7 +366,12 @@ class HotRunner extends ResidentRunner { await _calculateTargetPlatform(); final Uri projectUri = Uri.directory(projectRootPath); - _buildRunner ??= NativeAssetsBuildRunnerImpl(projectUri, fileSystem, globals.logger); + _buildRunner ??= NativeAssetsBuildRunnerImpl( + projectUri, + debuggingOptions.buildInfo.packageConfig, + fileSystem, + globals.logger, + ); final Uri? nativeAssetsYaml = await dryRunNativeAssets( projectUri: projectUri, fileSystem: fileSystem, diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 067838482ba13..8f50eb9268b05 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -168,7 +168,12 @@ class TestCompiler { Uri? nativeAssetsYaml; final Uri projectUri = FlutterProject.current().directory.uri; - final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl(projectUri, globals.fs, globals.logger); + final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( + projectUri, + buildInfo.packageConfig, + globals.fs, + globals.logger, + ); if (globals.platform.isMacOS) { (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( buildMode: BuildMode.debug, diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 7af5c077c77ca..7993203176de3 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -52,7 +52,7 @@ dependencies: cli_config: 0.1.1 graphs: 2.3.1 - native_assets_builder: 0.2.0 + native_assets_builder: 0.2.3 native_assets_cli: 0.2.0 # We depend on very specific internal implementation details of the @@ -112,4 +112,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 284b +# PUBSPEC CHECKSUM: 7f4e diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart index 86660f3a7909a..09fe96148d81f 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart @@ -55,11 +55,15 @@ void main() { }); testUsingContext('NativeAssets throws error if missing ios archs', () async { + await createPackageConfig(iosEnvironment); + iosEnvironment.defines.remove(kIosArchs); expect(const NativeAssets().build(iosEnvironment), throwsA(isA())); }); testUsingContext('NativeAssets throws error if missing sdk root', () async { + await createPackageConfig(iosEnvironment); + iosEnvironment.defines.remove(kSdkRoot); expect(const NativeAssets().build(iosEnvironment), throwsA(isA())); }); @@ -78,6 +82,8 @@ void main() { ), }, () async { + await createPackageConfig(iosEnvironment); + final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(); await NativeAssets(buildRunner: buildRunner).build(iosEnvironment); @@ -95,6 +101,8 @@ void main() { FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), }, () async { + await createPackageConfig(iosEnvironment); + final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( buildResult: FakeNativeAssetsBuilderResult(assets: [ native_assets_cli.Asset( @@ -138,3 +146,11 @@ void main() { }, ); } + +Future createPackageConfig(Environment iosEnvironment) async { + final File packageConfig = iosEnvironment.projectDir + .childDirectory('.dart_tool') + .childFile('package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); +} diff --git a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart index 8c9e865c8d7f2..07cdd2bbd3742 100644 --- a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart @@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/dart/package_map.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/macos/native_assets.dart'; @@ -373,7 +374,22 @@ InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault return; } - final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl(projectUri, fileSystem, logger); + final File packagesFile = fileSystem + .directory(projectUri) + .childDirectory('.dart_tool') + .childFile('package_config.json'); + await packagesFile.parent.create(); + await packagesFile.create(); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + packagesFile, + logger: environment.logger, + ); + final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl( + projectUri, + packageConfig, + fileSystem, + logger, + ); final CCompilerConfig result = await runner.cCompilerConfig; expect( result.cc, From 43260cced935c942704a42b74897c5c6e698e7dd Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:28:16 -0700 Subject: [PATCH 1289/1547] moved hello_world_impeller to a 7pro (#134830) arm64 is necessary for this test ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .ci.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index a224a8fb1d3d4..21d5c4d9a1abf 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1567,16 +1567,6 @@ targets: - bin/** - .ci.yaml - - name: Linux_android hello_world_impeller - recipe: devicelab/devicelab_drone - presubmit: false - bringup: true - timeout: 60 - properties: - tags: > - ["devicelab", "android", "linux"] - task_name: hello_world_impeller - - name: Linux_android android_defines_test recipe: devicelab/devicelab_drone presubmit: true @@ -1732,6 +1722,16 @@ targets: ["devicelab", "android", "linux", "pixel", "7pro"] task_name: static_path_tessellation_perf__timeline_summary + - name: Linux_pixel_7pro hello_world_impeller + recipe: devicelab/devicelab_drone + presubmit: false + bringup: true + timeout: 60 + properties: + tags: > + ["devicelab", "android", "linux", "pixel", "7pro"] + task_name: hello_world_impeller + - name: Linux_android basic_material_app_android__compile recipe: devicelab/devicelab_drone presubmit: false From ec47148036008f6fab98956edbd6006c07377fb9 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Fri, 15 Sep 2023 12:53:24 -0700 Subject: [PATCH 1290/1547] [Windows_android channels_integration_test] Column -> ListView (#134836) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix https://github.com/flutter/flutter/issues/134636. The column can get really tall, especially when there's line wrapping. This is the layout on a tablet, so on a motor g4 this column is likely going to overflow. ``` RenderParagraph#66251 relayoutBoundary=up3 │ creator: RichText ← Text-[<'status'>] ← Column ← │ FutureBuilder ← Padding ← │ KeyedSubtree-[GlobalKey#0f29e] ← _BodyBuilder ← MediaQuery ← │ LayoutId-[<_ScaffoldSlot.body>] ← CustomMultiChildLayout ← │ _ActionsScope ← Actions ← ⋯ | parentData: offset=Offset(0.0, 600.0); flex=null; fit=null ``` ![flutter_01](https://github.com/flutter/flutter/assets/31859944/5e700d21-3c5e-4990-bfb5-153f44f1c517) --- dev/integration_tests/channels/lib/src/test_step.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/integration_tests/channels/lib/src/test_step.dart b/dev/integration_tests/channels/lib/src/test_step.dart index 7c34e9622e9f9..443db5a6fa669 100644 --- a/dev/integration_tests/channels/lib/src/test_step.dart +++ b/dev/integration_tests/channels/lib/src/test_step.dart @@ -69,8 +69,7 @@ class TestStepResult { ); Widget asWidget(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, + return ListView( children: [ Text('Step: $name', style: bold), Text(description), From f629dc8771984b824cb0f9cebe06ad9140f4dcc4 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Fri, 15 Sep 2023 12:53:51 -0700 Subject: [PATCH 1291/1547] Dispose layers in test. (#134802) --- packages/flutter/test/material/material_test.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index cbf76ec4de523..44081098f443f 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -1078,7 +1078,7 @@ void main() { }); }); - testWidgets('InkFeature skips painting if intermediate node skips', (WidgetTester tester) async { + testWidgetsWithLeakTracking('InkFeature skips painting if intermediate node skips', (WidgetTester tester) async { final GlobalKey sizedBoxKey = GlobalKey(); final GlobalKey materialKey = GlobalKey(); await tester.pumpWidget(Material( @@ -1096,8 +1096,11 @@ void main() { controller.addInkFeature(tracker); expect(tracker.paintCount, 0); + final ContainerLayer layer1 = ContainerLayer(); + addTearDown(layer1.dispose); + // Force a repaint. Since it's offstage, the ink feature should not get painted. - materialKey.currentContext!.findRenderObject()!.paint(PaintingContext(ContainerLayer(), Rect.largest), Offset.zero); + materialKey.currentContext!.findRenderObject()!.paint(PaintingContext(layer1, Rect.largest), Offset.zero); expect(tracker.paintCount, 0); await tester.pumpWidget(Material( @@ -1111,8 +1114,11 @@ void main() { // now onstage. expect(tracker.paintCount, 1); + final ContainerLayer layer2 = ContainerLayer(); + addTearDown(layer2.dispose); + // Force a repaint again. This time, it gets repainted because it is onstage. - materialKey.currentContext!.findRenderObject()!.paint(PaintingContext(ContainerLayer(), Rect.largest), Offset.zero); + materialKey.currentContext!.findRenderObject()!.paint(PaintingContext(layer2, Rect.largest), Offset.zero); expect(tracker.paintCount, 2); }); From 367203b3011fc1752cfa1f51adf9751d090c94e6 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:01:05 -0700 Subject: [PATCH 1292/1547] =?UTF-8?q?Makes=20scheme=20and=20target=20optio?= =?UTF-8?q?nal=20parameter=20when=20getting=20universal=20lin=E2=80=A6=20(?= =?UTF-8?q?#134571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …k settings the show build settings xcode command can only accept one of the target or scheme flag. Therefore I make them optional. --- .../flutter_tools/lib/src/commands/analyze.dart | 15 +-------------- .../lib/src/commands/ios_analyze.dart | 13 ++++++------- packages/flutter_tools/lib/src/xcode_project.dart | 5 ++--- .../commands.shard/hermetic/ios_analyze_test.dart | 13 +++---------- .../test/general.shard/project_test.dart | 6 ------ 5 files changed, 12 insertions(+), 40 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart index 9a558fe8d4a41..68b66a425caca 100644 --- a/packages/flutter_tools/lib/src/commands/analyze.dart +++ b/packages/flutter_tools/lib/src/commands/analyze.dart @@ -152,7 +152,7 @@ class AnalyzeCommand extends FlutterCommand { argParser.addFlag('output-universal-link-settings', negatable: false, help: 'Output a JSON with iOS Xcode universal link settings into a file. ' - 'The "--configuration", "--scheme", and "--target" must also be set.', + 'The "--configuration" and "--target" must be set.', hide: !verboseHelp, ); @@ -162,12 +162,6 @@ class AnalyzeCommand extends FlutterCommand { hide: !verboseHelp, ); - argParser.addOption('scheme', - help: 'Sets the iOS build scheme to be analyzed.', - valueHelp: 'scheme', - hide: !verboseHelp, - ); - argParser.addOption('target', help: 'Sets the iOS build target to be analyzed.', valueHelp: 'target', @@ -264,7 +258,6 @@ class AnalyzeCommand extends FlutterCommand { final IOSAnalyzeOption option; final String? configuration; final String? target; - final String? scheme; if (argResults!['list-build-options'] as bool && argResults!['output-universal-link-settings'] as bool) { throwToolExit('Only one of "--list-build-options" or "--output-universal-link-settings" can be provided'); } @@ -272,7 +265,6 @@ class AnalyzeCommand extends FlutterCommand { option = IOSAnalyzeOption.listBuildOptions; configuration = null; target = null; - scheme = null; } else if (argResults!['output-universal-link-settings'] as bool) { option = IOSAnalyzeOption.outputUniversalLinkSettings; configuration = argResults!['configuration'] as String?; @@ -283,10 +275,6 @@ class AnalyzeCommand extends FlutterCommand { if (target == null) { throwToolExit('"--target" must be provided'); } - scheme = argResults!['scheme'] as String?; - if (scheme == null) { - throwToolExit('"--scheme" must be provided'); - } } else { throwToolExit('No argument is provided to analyze. Use -h to see available commands.'); } @@ -304,7 +292,6 @@ class AnalyzeCommand extends FlutterCommand { option: option, configuration: configuration, target: target, - scheme: scheme, logger: _logger, ).analyze(); } else if (boolArg('suggestions')) { diff --git a/packages/flutter_tools/lib/src/commands/ios_analyze.dart b/packages/flutter_tools/lib/src/commands/ios_analyze.dart index ae8f0bab76729..4b5a1b0956ccb 100644 --- a/packages/flutter_tools/lib/src/commands/ios_analyze.dart +++ b/packages/flutter_tools/lib/src/commands/ios_analyze.dart @@ -15,7 +15,7 @@ enum IOSAnalyzeOption { /// /// An example output: /// - /// {"configurations":["Debug","Release","Profile"],"schemes":["Runner"],"targets":["Runner","RunnerTests"]} + /// {"configurations":["Debug","Release","Profile"],"targets":["Runner","RunnerTests"]} listBuildOptions, /// Outputs universal link settings of the iOS Xcode sub-project into a file. @@ -32,16 +32,14 @@ class IOSAnalyze { required this.project, required this.option, this.configuration, - this.scheme, this.target, required this.logger, }) : assert(option == IOSAnalyzeOption.listBuildOptions || - (configuration != null && scheme != null && target != null)); + (configuration != null && target != null)); final FlutterProject project; final IOSAnalyzeOption option; final String? configuration; - final String? scheme; final String? target; final Logger logger; @@ -55,14 +53,15 @@ class IOSAnalyze { } else { result = >{ 'configurations': info.buildConfigurations, - 'schemes': info.schemes, 'targets': info.targets, }; } logger.printStatus(jsonEncode(result)); case IOSAnalyzeOption.outputUniversalLinkSettings: - await project.ios.outputsUniversalLinkSettings(configuration: configuration!, scheme: scheme!, target: target!); - final String filePath = await project.ios.outputsUniversalLinkSettings(configuration: configuration!, scheme: scheme!, target: target!); + final String filePath = await project.ios.outputsUniversalLinkSettings( + configuration: configuration!, + target: target!, + ); logger.printStatus('result saved in $filePath'); } } diff --git a/packages/flutter_tools/lib/src/xcode_project.dart b/packages/flutter_tools/lib/src/xcode_project.dart index ff17490a88200..48e7041d8aac6 100644 --- a/packages/flutter_tools/lib/src/xcode_project.dart +++ b/packages/flutter_tools/lib/src/xcode_project.dart @@ -221,18 +221,17 @@ class IosProject extends XcodeBasedProject { /// The return future will resolve to string path to the output file. Future outputsUniversalLinkSettings({ required String configuration, - required String scheme, required String target, }) async { final XcodeProjectBuildContext context = XcodeProjectBuildContext( configuration: configuration, - scheme: scheme, target: target, ); final File file = await parent.buildDirectory .childDirectory('deeplink_data') - .childFile('universal-link-settings-$configuration-$scheme-$target.json') + .childFile('universal-link-settings-$configuration-$target.json') .create(recursive: true); + await file.writeAsString(jsonEncode({ 'bundleIdentifier': await _productBundleIdentifierWithBuildContext(context), 'teamIdentifier': await _getTeamIdentifier(context), diff --git a/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart index 5290d5d38ee04..065a0543fe3be 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/ios_analyze_test.dart @@ -68,21 +68,18 @@ void main() { final MockIosProject ios = MockIosProject(); final MockFlutterProject project = MockFlutterProject(ios); const String expectedConfig = 'someConfig'; - const String expectedScheme = 'someScheme'; - const String expectedTarget = 'someConfig'; + const String expectedTarget = 'someTarget'; const String expectedOutputFile = '/someFile'; ios.outputFileLocation = expectedOutputFile; await IOSAnalyze( project: project, option: IOSAnalyzeOption.outputUniversalLinkSettings, configuration: expectedConfig, - scheme: expectedScheme, target: expectedTarget, logger: logger, ).analyze(); expect(logger.statusText, contains(expectedOutputFile)); expect(ios.outputConfiguration, expectedConfig); - expect(ios.outputScheme, expectedScheme); expect(ios.outputTarget, expectedTarget); }); @@ -91,8 +88,7 @@ void main() { final MockFlutterProject project = MockFlutterProject(ios); const List targets = ['target1', 'target2']; const List configs = ['config1', 'config2']; - const List schemes = ['scheme1', 'scheme2']; - ios.expectedProjectInfo = XcodeProjectInfo(targets, configs, schemes, logger); + ios.expectedProjectInfo = XcodeProjectInfo(targets, configs, const [], logger); await IOSAnalyze( project: project, option: IOSAnalyzeOption.listBuildOptions, @@ -101,7 +97,6 @@ void main() { final Map jsonOutput = jsonDecode(logger.statusText) as Map; expect(jsonOutput['targets'], unorderedEquals(targets)); expect(jsonOutput['configurations'], unorderedEquals(configs)); - expect(jsonOutput['schemes'], unorderedEquals(schemes)); }); testUsingContext('throws if provide multiple path', () async { @@ -144,15 +139,13 @@ class MockFlutterProject extends Fake implements FlutterProject { class MockIosProject extends Fake implements IosProject { String? outputConfiguration; - String? outputScheme; String? outputTarget; late String outputFileLocation; late XcodeProjectInfo expectedProjectInfo; @override - Future outputsUniversalLinkSettings({required String configuration, required String scheme, required String target}) async { + Future outputsUniversalLinkSettings({required String configuration, required String target}) async { outputConfiguration = configuration; - outputScheme = scheme; outputTarget = target; return outputFileLocation; } diff --git a/packages/flutter_tools/test/general.shard/project_test.dart b/packages/flutter_tools/test/general.shard/project_test.dart index ad30284a0b1c7..2cd3ca26f8bf6 100644 --- a/packages/flutter_tools/test/general.shard/project_test.dart +++ b/packages/flutter_tools/test/general.shard/project_test.dart @@ -733,7 +733,6 @@ apply plugin: 'kotlin-android' const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext( target: 'Runner', - scheme: 'Debug', configuration: 'config', ); xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = { @@ -753,7 +752,6 @@ apply plugin: 'kotlin-android' ); final String outputFilePath = await project.ios.outputsUniversalLinkSettings( target: 'Runner', - scheme: 'Debug', configuration: 'config', ); final File outputFile = fs.file(outputFilePath); @@ -781,7 +779,6 @@ apply plugin: 'kotlin-android' const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext( target: 'Runner', - scheme: 'Debug', configuration: 'config', ); xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = { @@ -802,7 +799,6 @@ apply plugin: 'kotlin-android' final String outputFilePath = await project.ios.outputsUniversalLinkSettings( target: 'Runner', - scheme: 'Debug', configuration: 'config', ); final File outputFile = fs.file(outputFilePath); @@ -827,7 +823,6 @@ apply plugin: 'kotlin-android' const XcodeProjectBuildContext buildContext = XcodeProjectBuildContext( target: 'Runner', - scheme: 'Debug', configuration: 'config', ); xcodeProjectInterpreter.buildSettingsByBuildContext[buildContext] = { @@ -838,7 +833,6 @@ apply plugin: 'kotlin-android' testPlistUtils.setProperty(PlistParser.kCFBundleIdentifierKey, r'$(PRODUCT_BUNDLE_IDENTIFIER)'); final String outputFilePath = await project.ios.outputsUniversalLinkSettings( target: 'Runner', - scheme: 'Debug', configuration: 'config', ); final File outputFile = fs.file(outputFilePath); From 18ad09efe87035be9e7b86f3fdf32d60aba58415 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 15 Sep 2023 23:35:06 -0400 Subject: [PATCH 1293/1547] Roll Flutter Engine from 45bc4307cda3 to 67dd12f8dfca (6 revisions) (#134791) https://github.com/flutter/engine/compare/45bc4307cda3...67dd12f8dfca 2023-09-14 skia-flutter-autoroll@skia.org Roll Dart SDK from d25e8d682c8f to 7e4d9f4d8e52 (3 revisions) (flutter/engine#45854) 2023-09-14 kustermann@google.com Remove @pragma('vm:entry-point') annotations on members that aren't accessed from C++ (flutter/engine#45697) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 6bc9f5886ddf to 9b7c116ed6c2 (1 revision) (flutter/engine#45853) 2023-09-14 54558023+keyonghan@users.noreply.github.com Switch linux_android_debug_engine from goma to reclient (flutter/engine#45345) 2023-09-14 54558023+keyonghan@users.noreply.github.com Switch goma to reclient fro standalone targets (flutter/engine#45804) 2023-09-14 109111084+yaakovschectman@users.noreply.github.com Handle external window's `WM_CLOSE` in lifecycle manager (flutter/engine#45840) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b257616358ee0..b11011dc7a854 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -45bc4307cda3f7af61915d5d7875d9ccb6bc637d +67dd12f8dfca92bcbdd17480251c90666d83d2a6 From 30cd285c1f30b8925d4030ef5cbb6269ea981366 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 00:26:07 -0400 Subject: [PATCH 1294/1547] Manual roll Flutter Engine from 67dd12f8dfca to 5aa9db365ed6 (5 revisions) (#134856) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/67dd12f8dfca...5aa9db365ed6 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 37ea783440ea to 7aa8bfaa63fc (1 revision) (flutter/engine#45861) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 8c9e378c4902 to 37ea783440ea (1 revision) (flutter/engine#45859) 2023-09-14 findyou795@gmail.com Reduce unnecessary Dart_TimelineGetMicros call (flutter/engine#45637) 2023-09-14 skia-flutter-autoroll@skia.org Roll Skia from 9b7c116ed6c2 to 8c9e378c4902 (3 revisions) (flutter/engine#45858) 2023-09-14 15619084+vashworth@users.noreply.github.com Set tests to run on macOS 12 (flutter/engine#45855) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b11011dc7a854..9161c26bf37c9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -67dd12f8dfca92bcbdd17480251c90666d83d2a6 +5aa9db365ed6c05f96b050d148d54036f2246c3a From ae743699fc78b203344c4381c1149d44dd593d13 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 01:15:03 -0400 Subject: [PATCH 1295/1547] Manual roll Flutter Engine from 5aa9db365ed6 to c0eaf2633686 (5 revisions) (#134860) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/5aa9db365ed6...c0eaf2633686 2023-09-15 skia-flutter-autoroll@skia.org Roll Dart SDK from c0a505f9d1dd to 65117290c3b0 (1 revision) (flutter/engine#45867) 2023-09-15 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from FF4r9-tqhioBbRG9f... to --OUw__L3ekVTG-5c... (flutter/engine#45866) 2023-09-15 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from MzLcTzBiWJ7o3Q2_Z... to ES0r-mYplPOBYHvUQ... (flutter/engine#45865) 2023-09-15 skia-flutter-autoroll@skia.org Roll Dart SDK from 7e4d9f4d8e52 to c0a505f9d1dd (1 revision) (flutter/engine#45864) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 7aa8bfaa63fc to c0cabb0f93c9 (1 revision) (flutter/engine#45863) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from MzLcTzBiWJ7o to ES0r-mYplPOB fuchsia/sdk/core/mac-amd64 from FF4r9-tqhioB to --OUw__L3ekV If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9161c26bf37c9..0d2611f14feee 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5aa9db365ed6c05f96b050d148d54036f2246c3a +c0eaf2633686f61f4602532713d8a64c67ba1fdf diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index e55c23ede46d4..386c17aacbd20 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -MzLcTzBiWJ7o3Q2_ZoCskAyXV_qzdvkqbOC7R1VhrY8C +ES0r-mYplPOBYHvUQWej_QitxiDHZC6VI_W-1-F2Im4C diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 292bb8d6f999c..61415eb5371bc 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -FF4r9-tqhioBbRG9fMFASuWfOKHBuLBdZtdnlvEPZY0C +--OUw__L3ekVTG-5cM1VmVBddza1REkMCIN9c0D3m_MC From 0032d9bbed26c53731524b1c0c029b34f3b3ccd3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 02:15:37 -0400 Subject: [PATCH 1296/1547] Manual roll Flutter Engine from c0eaf2633686 to d623ecf43c66 (5 revisions) (#134861) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/c0eaf2633686...d623ecf43c66 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 3492fc567816 to de56f293eb41 (1 revision) (flutter/engine#45878) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 6e286034109e to 3492fc567816 (1 revision) (flutter/engine#45876) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 824b1973703d to 6e286034109e (1 revision) (flutter/engine#45875) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 4f7aafd0c853 to 824b1973703d (1 revision) (flutter/engine#45871) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from c0cabb0f93c9 to 4f7aafd0c853 (1 revision) (flutter/engine#45868) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0d2611f14feee..05c5715cc0e58 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c0eaf2633686f61f4602532713d8a64c67ba1fdf +d623ecf43c66056b4b0df2a9ab3638e0b09bab56 From b8dc118b7f5503cdfeb0870d256059c54a69e233 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 03:31:23 -0400 Subject: [PATCH 1297/1547] Manual roll Flutter Engine from d623ecf43c66 to 51e643de62aa (5 revisions) (#134865) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/d623ecf43c66...51e643de62aa 2023-09-15 zanderso@users.noreply.github.com Adds a --quiet flag to run_tests.py (flutter/engine#45880) 2023-09-15 reidbaker@google.com Update AGP and Kotlin for scenario app (flutter/engine#45549) 2023-09-15 kjlubick@users.noreply.github.com Migrate GrMipmapped->skgpu::Mipmapped (flutter/engine#45881) 2023-09-15 30870216+gaaclarke@users.noreply.github.com [Impeller] Introduce mock vulkan context builder (flutter/engine#45834) 2023-09-15 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ES0r-mYplPOBYHvUQ... to wWzXsy6kx1sp8Km34... (flutter/engine#45879) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ES0r-mYplPOB to wWzXsy6kx1sp If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 05c5715cc0e58..39615d2a9fbab 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d623ecf43c66056b4b0df2a9ab3638e0b09bab56 +51e643de62aaac978856dd8a111679e073f68885 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 386c17aacbd20..4e17a83970c53 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ES0r-mYplPOBYHvUQWej_QitxiDHZC6VI_W-1-F2Im4C +wWzXsy6kx1sp8Km34yMP4z_bIX4Hp2IigySu6bjGR-oC From e1428bffd464082e8853dcfa54756be0812a900e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 11:49:23 -0400 Subject: [PATCH 1298/1547] Manual roll Flutter Engine from 51e643de62aa to 326faf1762d6 (6 revisions) (#134875) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/51e643de62aa...326faf1762d6 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from c79441fc8016 to 4f26f22daa4b (1 revision) (flutter/engine#45893) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 58c509b1a24a to c79441fc8016 (1 revision) (flutter/engine#45892) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from fffef1047640 to 58c509b1a24a (2 revisions) (flutter/engine#45888) 2023-09-15 skia-flutter-autoroll@skia.org Roll Dart SDK from 65117290c3b0 to a5ee0055cf20 (1 revision) (flutter/engine#45887) 2023-09-15 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from --OUw__L3ekVTG-5c... to -_edKGA5GTkDFxVgl... (flutter/engine#45886) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from de56f293eb41 to fffef1047640 (2 revisions) (flutter/engine#45885) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from --OUw__L3ekV to -_edKGA5GTkD If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 39615d2a9fbab..a9773e518075d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -51e643de62aaac978856dd8a111679e073f68885 +326faf1762d67f88fe903ec138e551d57564fb80 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 61415eb5371bc..e7a6ca7d8ae98 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ ---OUw__L3ekVTG-5cM1VmVBddza1REkMCIN9c0D3m_MC +-_edKGA5GTkDFxVglA5Eeh776tpMq4tePGwvozCb52gC From e5e36ad340588c4243d757f0b97cb90bf0229ce0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 12:37:25 -0400 Subject: [PATCH 1299/1547] Manual roll Flutter Engine from 326faf1762d6 to 30b7e9ded7a0 (5 revisions) (#134876) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/326faf1762d6...30b7e9ded7a0 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 7f88bda24f7f to 0057898979a1 (1 revision) (flutter/engine#45904) 2023-09-15 matanlurey@users.noreply.github.com [Impeller] Test `FenceWaiterVK` and fix termination bugs (flutter/engine#45870) 2023-09-15 skia-flutter-autoroll@skia.org Roll Dart SDK from a5ee0055cf20 to e9452310189b (1 revision) (flutter/engine#45902) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 4f26f22daa4b to 7f88bda24f7f (5 revisions) (flutter/engine#45901) 2023-09-15 jonahwilliams@google.com [Impeller] dont cache failed render target allocations. (flutter/engine#45895) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a9773e518075d..8526a99701fb3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -326faf1762d67f88fe903ec138e551d57564fb80 +30b7e9ded7a01df5ff82141d1a46e2c18f359768 From 042c07578fe8be98ac1ff903999112aa94f9bc1e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 13:17:44 -0400 Subject: [PATCH 1300/1547] Manual roll Flutter Engine from 30b7e9ded7a0 to cdcbdcc7ccba (5 revisions) (#134877) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/30b7e9ded7a0...cdcbdcc7ccba 2023-09-16 jonahwilliams@google.com Revert "[Impeller] construct text frames on UI thread." (flutter/engine#45910) 2023-09-16 skia-flutter-autoroll@skia.org Roll Skia from 7c179932cc06 to c19cc483c619 (1 revision) (flutter/engine#45911) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 917fd16e6f26 to 7c179932cc06 (1 revision) (flutter/engine#45907) 2023-09-15 skia-flutter-autoroll@skia.org Roll Skia from 0057898979a1 to 917fd16e6f26 (1 revision) (flutter/engine#45906) 2023-09-15 matanlurey@users.noreply.github.com Do not convert an open path to a closed rect. (flutter/engine#45903) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8526a99701fb3..e8ffb804c4b03 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -30b7e9ded7a01df5ff82141d1a46e2c18f359768 +cdcbdcc7ccba6a8742e82ac6eea866bd0946beab From d9cffa051897e654eb4176425bb88dc5ccb423d1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 14:10:31 -0400 Subject: [PATCH 1301/1547] Manual roll Flutter Engine from cdcbdcc7ccba to 490925676b91 (5 revisions) (#134879) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/cdcbdcc7ccba...490925676b91 2023-09-16 matanlurey@users.noreply.github.com Add a single MacOS+Vulkan+SwiftShader CI test (flutter/engine#45918) 2023-09-16 skia-flutter-autoroll@skia.org Roll Skia from 696ac041ea82 to a1f8fb54299a (1 revision) (flutter/engine#45917) 2023-09-16 skia-flutter-autoroll@skia.org Roll Skia from 4851cd29e1dd to 696ac041ea82 (1 revision) (flutter/engine#45915) 2023-09-16 skia-flutter-autoroll@skia.org Roll Skia from c19cc483c619 to 4851cd29e1dd (1 revision) (flutter/engine#45913) 2023-09-16 skia-flutter-autoroll@skia.org Roll Dart SDK from e9452310189b to 029d6d73c860 (1 revision) (flutter/engine#45912) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e8ffb804c4b03..e8a181d9958f5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cdcbdcc7ccba6a8742e82ac6eea866bd0946beab +490925676b91de84f64127d7eec3bea73a265520 From c66ca4f14b8a4aeb20174cc65e8ba4467daf8acb Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 15:22:32 -0400 Subject: [PATCH 1302/1547] Manual roll Flutter Engine from 490925676b91 to 8c2203bb6c3b (6 revisions) (#134882) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/490925676b91...8c2203bb6c3b 2023-09-16 skia-flutter-autoroll@skia.org Roll Skia from b33e0e6706b0 to 2eaaa5bf7dae (1 revision) (flutter/engine#45926) 2023-09-16 skia-flutter-autoroll@skia.org Roll Skia from a1f8fb54299a to b33e0e6706b0 (1 revision) (flutter/engine#45923) 2023-09-16 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from -_edKGA5GTkDFxVgl... to 3Tb9CQTTiBv1lb673... (flutter/engine#45922) 2023-09-16 skia-flutter-autoroll@skia.org Roll Dart SDK from 029d6d73c860 to a0ca39c63c16 (1 revision) (flutter/engine#45921) 2023-09-16 matanlurey@users.noreply.github.com [Impeller] `vk::CommandPool` resets via `ResourceManager` (flutter/engine#45654) 2023-09-16 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from wWzXsy6kx1sp8Km34... to ZhY53WD7bFJSA3xoO... (flutter/engine#45919) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from wWzXsy6kx1sp to ZhY53WD7bFJS fuchsia/sdk/core/mac-amd64 from -_edKGA5GTkD to 3Tb9CQTTiBv1 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e8a181d9958f5..c3e76a4bd2b3d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -490925676b91de84f64127d7eec3bea73a265520 +8c2203bb6c3b4445207c9d1e50d737e800fd7a14 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 4e17a83970c53..a867f8b1ddce9 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -wWzXsy6kx1sp8Km34yMP4z_bIX4Hp2IigySu6bjGR-oC +ZhY53WD7bFJSA3xoOchmSzb5zambmf3zOGFuK0GVv_YC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index e7a6ca7d8ae98..470e3baadd786 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ --_edKGA5GTkDFxVglA5Eeh776tpMq4tePGwvozCb52gC +3Tb9CQTTiBv1lb673dy6Hni3h6dG144nwKugXqH74TkC From 60fae58a24aafe51cc266b917935b099c2cd4779 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Sat, 16 Sep 2023 12:50:23 -0700 Subject: [PATCH 1303/1547] Add disposal mechanism for created Layers to TestRecordingPaintingContext. (#134768) Contributes to https://github.com/flutter/flutter/issues/134575 --- .../flutter_test/lib/src/recording_canvas.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/flutter_test/lib/src/recording_canvas.dart b/packages/flutter_test/lib/src/recording_canvas.dart index 47f3478c1a856..c958006a499bf 100644 --- a/packages/flutter_test/lib/src/recording_canvas.dart +++ b/packages/flutter_test/lib/src/recording_canvas.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; /// An [Invocation] and the [stack] trace that led to it. @@ -96,6 +97,8 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex /// Creates a [PaintingContext] for tests that use [TestRecordingCanvas]. TestRecordingPaintingContext(this.canvas); + final List _createdLayers = []; + @override final Canvas canvas; @@ -170,7 +173,18 @@ class TestRecordingPaintingContext extends ClipContext implements PaintingContex canvas.saveLayer(null, Paint()); // TODO(ianh): Expose the alpha somewhere. painter(this, offset); canvas.restore(); - return OpacityLayer(); + final OpacityLayer layer = OpacityLayer(); + _createdLayers.add(layer); + return layer; + } + + /// Releases allocated resources. + @mustCallSuper + void dispose() { + for (final OpacityLayer layer in _createdLayers) { + layer.dispose(); + } + _createdLayers.clear(); } @override From 854bbb901c7d85be99aa44924dbb3c99423236a0 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Sat, 16 Sep 2023 23:59:13 +0200 Subject: [PATCH 1304/1547] Fix memory leak in CupertinoActionSheet (#134885) --- .../flutter/lib/src/cupertino/dialog.dart | 56 +++++++++------ .../test/cupertino/action_sheet_test.dart | 68 ++++++++++--------- 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 4b969a2b3146e..7adfe82eb6a53 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -474,7 +474,7 @@ class CupertinoPopupSurface extends StatelessWidget { /// /// * [CupertinoActionSheetAction], which is an iOS-style action sheet button. /// * -class CupertinoActionSheet extends StatelessWidget { +class CupertinoActionSheet extends StatefulWidget { /// Creates an iOS-style action sheet. /// /// An action sheet must have a non-null value for at least one of the @@ -520,30 +520,46 @@ class CupertinoActionSheet extends StatelessWidget { /// short. final ScrollController? messageScrollController; - ScrollController get _effectiveMessageScrollController => - messageScrollController ?? ScrollController(); - /// A scroll controller that can be used to control the scrolling of the /// [actions] in the action sheet. /// /// This attribute is typically not needed. final ScrollController? actionScrollController; - ScrollController get _effectiveActionScrollController => - actionScrollController ?? ScrollController(); - /// The optional cancel button that is grouped separately from the other /// actions. /// /// Typically this is an [CupertinoActionSheetAction] widget. final Widget? cancelButton; + @override + State createState() => _CupertinoActionSheetState(); +} + +class _CupertinoActionSheetState extends State { + ScrollController? _backupMessageScrollController; + + ScrollController? _backupActionScrollController; + + ScrollController get _effectiveMessageScrollController => + widget.messageScrollController ?? (_backupMessageScrollController ??= ScrollController()); + + ScrollController get _effectiveActionScrollController => + widget.actionScrollController ?? (_backupActionScrollController ??= ScrollController()); + + @override + void dispose() { + _backupMessageScrollController?.dispose(); + _backupActionScrollController?.dispose(); + super.dispose(); + } + Widget _buildContent(BuildContext context) { final List content = []; - if (title != null || message != null) { + if (widget.title != null || widget.message != null) { final Widget titleSection = _CupertinoAlertContentSection( - title: title, - message: message, + title: widget.title, + message: widget.message, scrollController: _effectiveMessageScrollController, titlePadding: const EdgeInsets.only( left: _kActionSheetContentHorizontalPadding, @@ -554,13 +570,13 @@ class CupertinoActionSheet extends StatelessWidget { messagePadding: EdgeInsets.only( left: _kActionSheetContentHorizontalPadding, right: _kActionSheetContentHorizontalPadding, - bottom: title == null ? _kActionSheetContentVerticalPadding : 22.0, - top: title == null ? _kActionSheetContentVerticalPadding : 0.0, + bottom: widget.title == null ? _kActionSheetContentVerticalPadding : 22.0, + top: widget.title == null ? _kActionSheetContentVerticalPadding : 0.0, ), - titleTextStyle: message == null + titleTextStyle: widget.message == null ? _kActionSheetContentStyle : _kActionSheetContentStyle.copyWith(fontWeight: FontWeight.w600), - messageTextStyle: title == null + messageTextStyle: widget.title == null ? _kActionSheetContentStyle.copyWith(fontWeight: FontWeight.w600) : _kActionSheetContentStyle, additionalPaddingBetweenTitleAndMessage: const EdgeInsets.only(top: 8.0), @@ -579,26 +595,26 @@ class CupertinoActionSheet extends StatelessWidget { } Widget _buildActions() { - if (actions == null || actions!.isEmpty) { + if (widget.actions == null || widget.actions!.isEmpty) { return Container( height: 0.0, ); } return _CupertinoAlertActionSection( scrollController: _effectiveActionScrollController, - hasCancelButton: cancelButton != null, + hasCancelButton: widget.cancelButton != null, isActionSheet: true, - children: actions!, + children: widget.actions!, ); } Widget _buildCancelButton() { - final double cancelPadding = (actions != null || message != null || title != null) + final double cancelPadding = (widget.actions != null || widget.message != null || widget.title != null) ? _kActionSheetCancelButtonPadding : 0.0; return Padding( padding: EdgeInsets.only(top: cancelPadding), child: _CupertinoActionSheetCancelButton( - child: cancelButton, + child: widget.cancelButton, ), ); } @@ -621,7 +637,7 @@ class CupertinoActionSheet extends StatelessWidget { ), ), ), - if (cancelButton != null) _buildCancelButton(), + if (widget.cancelButton != null) _buildCancelButton(), ]; final Orientation orientation = MediaQuery.orientationOf(context); diff --git a/packages/flutter/test/cupertino/action_sheet_test.dart b/packages/flutter/test/cupertino/action_sheet_test.dart index b7ef4cde77a39..f5f3dde5892de 100644 --- a/packages/flutter/test/cupertino/action_sheet_test.dart +++ b/packages/flutter/test/cupertino/action_sheet_test.dart @@ -9,11 +9,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('Verify that a tap on modal barrier dismisses an action sheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a tap on modal barrier dismisses an action sheet', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( const CupertinoActionSheet( @@ -30,9 +31,9 @@ void main() { await tester.tapAt(const Offset(20.0, 20.0)); await tester.pump(); expect(find.text('Action Sheet'), findsNothing); - }); + }, leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed()); - testWidgets('Verify that a tap on title section (not buttons) does not dismiss an action sheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Verify that a tap on title section (not buttons) does not dismiss an action sheet', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( const CupertinoActionSheet( @@ -52,7 +53,7 @@ void main() { expect(find.text('Action Sheet'), findsOneWidget); }); - testWidgets('Action sheet destructive text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet destructive text style', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( CupertinoActionSheetAction( @@ -73,7 +74,7 @@ void main() { )); }); - testWidgets('Action sheet dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet dark mode', (WidgetTester tester) async { final Widget action = CupertinoActionSheetAction( child: const Text('action'), onPressed: () {}, @@ -130,7 +131,7 @@ void main() { ); }); - testWidgets('Action sheet default text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet default text style', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( CupertinoActionSheetAction( @@ -146,7 +147,7 @@ void main() { expect(widget.style.fontWeight, equals(FontWeight.w600)); }); - testWidgets('Action sheet text styles are correct when both title and message are included', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet text styles are correct when both title and message are included', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( const CupertinoActionSheet( @@ -166,7 +167,7 @@ void main() { expect(messageStyle.style.fontWeight, FontWeight.w400); }); - testWidgets('Action sheet text styles are correct when title but no message is included', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet text styles are correct when title but no message is included', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( const CupertinoActionSheet( @@ -183,7 +184,7 @@ void main() { expect(titleStyle.style.fontWeight, FontWeight.w400); }); - testWidgets('Action sheet text styles are correct when message but no title is included', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet text styles are correct when message but no title is included', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( const CupertinoActionSheet( @@ -200,8 +201,9 @@ void main() { expect(messageStyle.style.fontWeight, FontWeight.w600); }); - testWidgets('Content section but no actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Content section but no actions', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -237,8 +239,9 @@ void main() { ); }); - testWidgets('Actions but no content section', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions but no content section', (WidgetTester tester) async { final ScrollController actionScrollController = ScrollController(); + addTearDown(actionScrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -285,8 +288,9 @@ void main() { ); }); - testWidgets('Action section is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action section is scrollable', (WidgetTester tester) async { final ScrollController actionScrollController = ScrollController(); + addTearDown(actionScrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( Builder(builder: (BuildContext context) { @@ -350,8 +354,9 @@ void main() { expect(tester.getSize(find.widgetWithText(CupertinoActionSheetAction, 'Five')).height, equals(92.0)); }); - testWidgets('Content section is scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Content section is scrollable', (WidgetTester tester) async { final ScrollController messageScrollController = ScrollController(); + addTearDown(messageScrollController.dispose); late double screenHeight; await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( @@ -392,7 +397,7 @@ void main() { expect(tester.getSize(find.byType(CupertinoActionSheet)).height, screenHeight); }); - testWidgets('CupertinoActionSheet scrollbars controllers should be different', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoActionSheet scrollbars controllers should be different', (WidgetTester tester) async { // https://github.com/flutter/flutter/pull/81278 await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( @@ -422,7 +427,7 @@ void main() { expect(scrollbars[0].controller != scrollbars[1].controller, isTrue); }); - testWidgets('Tap on button calls onPressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap on button calls onPressed', (WidgetTester tester) async { bool wasPressed = false; await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( @@ -459,7 +464,7 @@ void main() { expect(find.text('One'), findsNothing); }); - testWidgets('Action sheet width is correct when given infinite horizontal space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet width is correct when given infinite horizontal space', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( Row( @@ -487,7 +492,7 @@ void main() { expect(tester.getSize(find.byType(CupertinoActionSheet)).width, 600.0); }); - testWidgets('Action sheet height is correct when given infinite vertical space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet height is correct when given infinite vertical space', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( Column( @@ -515,7 +520,7 @@ void main() { expect(tester.getSize(find.byType(CupertinoActionSheet)).height, moreOrLessEquals(132.33333333333334)); }); - testWidgets('1 action button with cancel button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('1 action button with cancel button', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -542,7 +547,7 @@ void main() { expect(findScrollableActionsSectionRenderBox(tester).size.height, 56.0); }); - testWidgets('2 action buttons with cancel button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('2 action buttons with cancel button', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -572,7 +577,7 @@ void main() { expect(findScrollableActionsSectionRenderBox(tester).size.height, moreOrLessEquals(112.33333333333331)); }); - testWidgets('3 action buttons with cancel button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('3 action buttons with cancel button', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -606,7 +611,7 @@ void main() { expect(findScrollableActionsSectionRenderBox(tester).size.height, moreOrLessEquals(168.66666666666669)); }); - testWidgets('4+ action buttons with cancel button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('4+ action buttons with cancel button', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -644,7 +649,7 @@ void main() { expect(findScrollableActionsSectionRenderBox(tester).size.height, moreOrLessEquals(84.33333333333337)); }); - testWidgets('1 action button without cancel button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('1 action button without cancel button', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -666,7 +671,7 @@ void main() { expect(findScrollableActionsSectionRenderBox(tester).size.height, 56.0); }); - testWidgets('2+ action buttons without cancel button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('2+ action buttons without cancel button', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -692,7 +697,7 @@ void main() { expect(findScrollableActionsSectionRenderBox(tester).size.height, moreOrLessEquals(84.33333333333337)); }); - testWidgets('Action sheet with just cancel button is correct', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet with just cancel button is correct', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -712,7 +717,7 @@ void main() { expect(tester.getSize(find.byType(CupertinoActionSheet)).width, 600.0); }); - testWidgets('Cancel button tap calls onPressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cancel button tap calls onPressed', (WidgetTester tester) async { bool wasPressed = false; await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( @@ -747,7 +752,7 @@ void main() { expect(find.text('Cancel'), findsNothing); }); - testWidgets('Layout is correct when cancel button is present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Layout is correct when cancel button is present', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -784,7 +789,7 @@ void main() { expect(tester.getBottomLeft(find.widgetWithText(CupertinoActionSheetAction, 'Two')).dy, 526.0); }); - testWidgets('Enter/exit animation is correct', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Enter/exit animation is correct', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -861,7 +866,7 @@ void main() { expect(find.byType(CupertinoActionSheet), findsNothing); }); - testWidgets('Modal barrier is pressed during transition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Modal barrier is pressed during transition', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( @@ -919,7 +924,7 @@ void main() { }); - testWidgets('Action sheet semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Action sheet semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1028,9 +1033,10 @@ void main() { semantics.dispose(); }); - testWidgets('Conflicting scrollbars are not applied by ScrollBehavior to CupertinoActionSheet', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Conflicting scrollbars are not applied by ScrollBehavior to CupertinoActionSheet', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/83819 final ScrollController actionScrollController = ScrollController(); + addTearDown(actionScrollController.dispose); await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( Builder(builder: (BuildContext context) { @@ -1068,7 +1074,7 @@ void main() { expect(find.byType(CupertinoScrollbar), findsNWidgets(2)); }, variant: TargetPlatformVariant.all()); - testWidgets('Hovering over Cupertino action sheet action updates cursor to clickable on Web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovering over Cupertino action sheet action updates cursor to clickable on Web', (WidgetTester tester) async { await tester.pumpWidget( createAppWithButtonThatLaunchesActionSheet( CupertinoActionSheet( From 1bad8c4f45846b9c5a3a6e4ec8ede639da330ef9 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sat, 16 Sep 2023 19:00:23 -0400 Subject: [PATCH 1305/1547] Roll Flutter Engine from 8c2203bb6c3b to 444689fd4060 (1 revision) (#134886) https://github.com/flutter/engine/compare/8c2203bb6c3b...444689fd4060 2023-09-16 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 3Tb9CQTTiBv1lb673... to IJXVQbD3CpkL2_ihZ... (flutter/engine#45928) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 3Tb9CQTTiBv1 to IJXVQbD3CpkL If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c3e76a4bd2b3d..28472749886a9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -8c2203bb6c3b4445207c9d1e50d737e800fd7a14 +444689fd4060476af570795c7697407d8f871f31 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 470e3baadd786..7ebe129349d2e 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -3Tb9CQTTiBv1lb673dy6Hni3h6dG144nwKugXqH74TkC +IJXVQbD3CpkL2_ihZcSSLPiJeFWfFVT7pijN8i-f8ZwC From 13a03cefa262bedc8b6fd656544c8b2044d2d1d1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 17 Sep 2023 01:10:31 -0400 Subject: [PATCH 1306/1547] Roll Flutter Engine from 444689fd4060 to e07bb975ee85 (1 revision) (#134889) https://github.com/flutter/engine/compare/444689fd4060...e07bb975ee85 2023-09-17 skia-flutter-autoroll@skia.org Roll Skia from 2eaaa5bf7dae to a160e7fb80db (1 revision) (flutter/engine#45933) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 28472749886a9..8600724a4012f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -444689fd4060476af570795c7697407d8f871f31 +e07bb975ee8535ece2e96f8ea241c3eddefff983 From 1b18b1327a590ad295ad53bb758ce0eac006e577 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 17 Sep 2023 04:07:02 -0400 Subject: [PATCH 1307/1547] Roll Flutter Engine from e07bb975ee85 to 57a4ff3c7ff8 (1 revision) (#134895) https://github.com/flutter/engine/compare/e07bb975ee85...57a4ff3c7ff8 2023-09-17 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from IJXVQbD3CpkL2_ihZ... to AjL85L6CVMEuMWPVZ... (flutter/engine#45937) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from IJXVQbD3CpkL to AjL85L6CVMEu If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8600724a4012f..28ba8c6aca6d5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e07bb975ee8535ece2e96f8ea241c3eddefff983 +57a4ff3c7ff889effc6c3f36dc3cabce31ab1e67 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7ebe129349d2e..0e8474fb24174 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -IJXVQbD3CpkL2_ihZcSSLPiJeFWfFVT7pijN8i-f8ZwC +AjL85L6CVMEuMWPVZzN1EMWG4cwS6R6cOpbv7-jDjEsC From e599dae423d346e1607c9186537386831ccdcc36 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Sun, 17 Sep 2023 17:34:39 -0400 Subject: [PATCH 1308/1547] Roll Flutter Engine from 57a4ff3c7ff8 to 9f3e46a21e51 (1 revision) (#134909) https://github.com/flutter/engine/compare/57a4ff3c7ff8...9f3e46a21e51 2023-09-17 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from AjL85L6CVMEuMWPVZ... to 2TJNsB32jPioIfFao... (flutter/engine#45945) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from AjL85L6CVMEu to 2TJNsB32jPio If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 28ba8c6aca6d5..cb409a417368a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -57a4ff3c7ff889effc6c3f36dc3cabce31ab1e67 +9f3e46a21e5113bc8db7dc874cd284536afbdb30 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 0e8474fb24174..c4866edb17756 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -AjL85L6CVMEuMWPVZzN1EMWG4cwS6R6cOpbv7-jDjEsC +2TJNsB32jPioIfFaoLtDUK2JsGct6o1oo_fISGZ_vWgC From 2e67d8c0344c57b60bc91d067a9bef2e45f285b0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 01:40:22 -0400 Subject: [PATCH 1309/1547] Roll Flutter Engine from 9f3e46a21e51 to f53681fb2220 (1 revision) (#134916) https://github.com/flutter/engine/compare/9f3e46a21e51...f53681fb2220 2023-09-18 skia-flutter-autoroll@skia.org Roll Skia from a160e7fb80db to 0d02aa8cb640 (1 revision) (flutter/engine#45952) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cb409a417368a..61efa47d6cad6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9f3e46a21e5113bc8db7dc874cd284536afbdb30 +f53681fb22207df8c159d2bdb06789f6d80406d0 From 466fa6080e35a0a0d91733b81b720262ef8b35fa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 02:32:10 -0400 Subject: [PATCH 1310/1547] Roll Flutter Engine from f53681fb2220 to 51a402860f5b (1 revision) (#134918) https://github.com/flutter/engine/compare/f53681fb2220...51a402860f5b 2023-09-18 skia-flutter-autoroll@skia.org Roll Dart SDK from a0ca39c63c16 to 5eef4301567f (1 revision) (flutter/engine#45956) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 61efa47d6cad6..af27e25f0893b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f53681fb22207df8c159d2bdb06789f6d80406d0 +51a402860f5b537720b72af69a98ad85209671e7 From b03f5337df560cdeda8ddeb9ef3b652deb4f0f59 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 03:17:24 -0400 Subject: [PATCH 1311/1547] Roll Flutter Engine from 51a402860f5b to 573e44b91887 (1 revision) (#134920) https://github.com/flutter/engine/compare/51a402860f5b...573e44b91887 2023-09-18 skia-flutter-autoroll@skia.org Roll Skia from 0d02aa8cb640 to eac827d9eed3 (1 revision) (flutter/engine#45957) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index af27e25f0893b..c91cda81634e1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -51a402860f5b537720b72af69a98ad85209671e7 +573e44b91887d8ad177c05ee11b4fbad6bbe46e1 From c2b1e483ddd9733127e890b5ae2dcbf50037b6d7 Mon Sep 17 00:00:00 2001 From: huycozy <104349824+huycozy@users.noreply.github.com> Date: Mon, 18 Sep 2023 15:33:14 +0700 Subject: [PATCH 1312/1547] Improve DropdownMenu sample code for requestFocusOnTap on mobile platforms (#134867) ### Description This PR is to improve `DropdownMenu` sample code. By default, `requestFocusOnTap` is false on mobile platforms. When users run API sample code on mobile platforms, they can not edit the text field and think it is a bug. Although it is detailed at https://api.flutter.dev/flutter/material/DropdownMenu/requestFocusOnTap.html, users often do not pay attention to it. ### Related issue Fixes https://github.com/flutter/flutter/issues/127672 --- .../dropdown_menu/dropdown_menu.0.dart | 6 +++++ .../dropdown_menu/dropdown_menu.0_test.dart | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart b/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart index 0e1814b020cca..e7b1ea9b3db3d 100644 --- a/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart +++ b/examples/api/lib/material/dropdown_menu/dropdown_menu.0.dart @@ -74,6 +74,11 @@ class _DropdownMenuExampleState extends State { DropdownMenu( initialSelection: ColorLabel.green, controller: colorController, + // requestFocusOnTap is enabled/disabled by platforms when it is null. + // On mobile platforms, this is false by default. Setting this to true will + // trigger focus request on the text field and virtual keyboard will appear + // afterward. On desktop platforms however, this defaults to true. + requestFocusOnTap: true, label: const Text('Color'), onSelected: (ColorLabel? color) { setState(() { @@ -97,6 +102,7 @@ class _DropdownMenuExampleState extends State { DropdownMenu( controller: iconController, enableFilter: true, + requestFocusOnTap: true, leadingIcon: const Icon(Icons.search), label: const Text('Icon'), inputDecorationTheme: const InputDecorationTheme( diff --git a/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart b/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart index 62e0c6e195d37..c1c662f0ec4c4 100644 --- a/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart +++ b/examples/api/test/material/dropdown_menu/dropdown_menu.0_test.dart @@ -52,4 +52,26 @@ void main() { expect(find.text('You selected a Blue Smile'), findsOneWidget); }); + + testWidgets('DropdownMenu has focus when tapping on the text field', (WidgetTester tester) async { + await tester.pumpWidget( + const example.DropdownMenuExample(), + ); + + // Make sure the dropdown menus are there. + final Finder colorMenu = find.byType(DropdownMenu); + final Finder iconMenu = find.byType(DropdownMenu); + expect(colorMenu, findsOneWidget); + expect(iconMenu, findsOneWidget); + + // Tap on the color menu and make sure it is focused. + await tester.tap(colorMenu); + await tester.pumpAndSettle(); + expect(FocusScope.of(tester.element(colorMenu)).hasFocus, isTrue); + + // Tap on the icon menu and make sure it is focused. + await tester.tap(iconMenu); + await tester.pumpAndSettle(); + expect(FocusScope.of(tester.element(iconMenu)).hasFocus, isTrue); + }); } From 6068ff2a77abd823ebdbed421d0611af89c0b351 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 05:13:36 -0400 Subject: [PATCH 1313/1547] Roll Flutter Engine from 573e44b91887 to 75e5ba3c4671 (1 revision) (#134923) https://github.com/flutter/engine/compare/573e44b91887...75e5ba3c4671 2023-09-18 skia-flutter-autoroll@skia.org Roll Skia from eac827d9eed3 to f8065ca00d0c (2 revisions) (flutter/engine#45962) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c91cda81634e1..3c42636e47661 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -573e44b91887d8ad177c05ee11b4fbad6bbe46e1 +75e5ba3c46714c72eef28e3a80ef68294545d007 From cf317b5a1d331e717c95432f323a35cfe26a9f09 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 06:09:27 -0400 Subject: [PATCH 1314/1547] Roll Flutter Engine from 75e5ba3c4671 to 77965cabbaf9 (1 revision) (#134925) https://github.com/flutter/engine/compare/75e5ba3c4671...77965cabbaf9 2023-09-18 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 2TJNsB32jPioIfFao... to 3_Lh8otTpmVuf-Zwb... (flutter/engine#45963) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 2TJNsB32jPio to 3_Lh8otTpmVu If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 3c42636e47661..61351e566e6fe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -75e5ba3c46714c72eef28e3a80ef68294545d007 +77965cabbaf96e62df3b78d500629b7f23b877ec diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c4866edb17756..c6ce50c165d4e 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -2TJNsB32jPioIfFaoLtDUK2JsGct6o1oo_fISGZ_vWgC +3_Lh8otTpmVuf-Zwb5yQy61cqmV-4g7xjO1wsANaeC0C From d6d90b0f52b0478b52007da555e63f5fc9aa4e49 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 06:55:33 -0400 Subject: [PATCH 1315/1547] Roll Flutter Engine from 77965cabbaf9 to 4107ee0dc8b1 (1 revision) (#134927) https://github.com/flutter/engine/compare/77965cabbaf9...4107ee0dc8b1 2023-09-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 5eef4301567f to 5c56e0f3fe13 (1 revision) (flutter/engine#45966) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 61351e566e6fe..2b1c4ea28a063 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -77965cabbaf96e62df3b78d500629b7f23b877ec +4107ee0dc8b11cdd7bd7e890deb8f4783e2aecbb From 2337c64d0ca2a53e22cd6c523ec8a2c30433248c Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Mon, 18 Sep 2023 13:13:37 +0200 Subject: [PATCH 1316/1547] Native assets support for Linux (#134031) Support for FFI calls with `@Native external` functions through Native assets on Linux. This enables bundling native code without any build-system boilerplate code. For more info see: * https://github.com/flutter/flutter/issues/129757 ### Implementation details for Linux. Mainly follows the design of https://github.com/flutter/flutter/pull/130494. Some differences are: * Linux does not support cross compiling or compiling for multiple architectures, so this has not been implemented. * Linux has no add2app. The assets copying is done in the install-phase of the CMake build of a flutter app. CMake requires the native assets folder to exist, so we create it also when the feature is disabled or there are no assets. ### Tests This PR adds new tests to cover the various use cases. * packages/flutter_tools/test/general.shard/linux/native_assets_test.dart * Unit tests the Linux-specific part of building native assets. It also extends various existing tests: * packages/flutter_tools/test/integration.shard/native_assets_test.dart * Runs (incl hot reload/hot restart), builds, builds frameworks for Linux and flutter-tester. --- .ci.yaml | 24 +- .../build_system/targets/native_assets.dart | 27 +- .../lib/src/linux/build_linux.dart | 2 + .../lib/src/linux/native_assets.dart | 238 +++++++++++ .../cmake_native_assets_migration.dart | 65 +++ .../flutter_tools/lib/src/native_assets.dart | 27 +- .../lib/src/test/test_compiler.dart | 11 +- .../app_shared/linux.tmpl/CMakeLists.txt.tmpl | 6 + .../linux/native_assets_test.dart | 374 ++++++++++++++++++ .../cmake_project_migration_test.dart | 127 ++++++ .../integration.shard/native_assets_test.dart | 30 +- .../transition_test_utils.dart | 9 +- 12 files changed, 919 insertions(+), 21 deletions(-) create mode 100644 packages/flutter_tools/lib/src/linux/native_assets.dart create mode 100644 packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart create mode 100644 packages/flutter_tools/test/general.shard/linux/native_assets_test.dart diff --git a/.ci.yaml b/.ci.yaml index 21d5c4d9a1abf..5b7e2d2e1e5b3 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -951,8 +951,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "1_4" @@ -975,8 +977,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "2_4" @@ -999,8 +1003,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "3_4" @@ -1023,8 +1029,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:115.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "4_4" diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index 6e73882927f99..c92c1d6949581 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -12,6 +12,7 @@ import '../../base/platform.dart'; import '../../build_info.dart'; import '../../dart/package_map.dart'; import '../../ios/native_assets.dart'; +import '../../linux/native_assets.dart'; import '../../macos/native_assets.dart'; import '../../macos/xcode.dart'; import '../../native_assets.dart'; @@ -118,6 +119,21 @@ class NativeAssets extends Target { fileSystem: fileSystem, buildRunner: buildRunner, ); + case TargetPlatform.linux_arm64: + case TargetPlatform.linux_x64: + final String? environmentBuildMode = environment.defines[kBuildMode]; + if (environmentBuildMode == null) { + throw MissingDefineException(kBuildMode, name); + } + final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); + (_, dependencies) = await buildNativeAssetsLinux( + targetPlatform: targetPlatform, + buildMode: buildMode, + projectUri: projectUri, + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); case TargetPlatform.tester: if (const LocalPlatform().isMacOS) { (_, dependencies) = await buildNativeAssetsMacOS( @@ -129,6 +145,15 @@ class NativeAssets extends Target { buildRunner: buildRunner, flutterTester: true, ); + } else if (const LocalPlatform().isLinux) { + (_, dependencies) = await buildNativeAssetsLinux( + buildMode: BuildMode.debug, + projectUri: projectUri, + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + flutterTester: true, + ); } else { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 // Write the file we claim to have in the [outputs]. @@ -142,8 +167,6 @@ class NativeAssets extends Target { case TargetPlatform.android: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: - case TargetPlatform.linux_arm64: - case TargetPlatform.linux_x64: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 410416aa63062..1bcf07361fd65 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -17,6 +17,7 @@ import '../convert.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; +import '../migrations/cmake_native_assets_migration.dart'; // Matches the following error and warning patterns: // - ::: (fatal) error: @@ -45,6 +46,7 @@ Future buildLinux( final List migrators = [ CmakeCustomCommandMigration(linuxProject, logger), + CmakeNativeAssetsMigration(linuxProject, 'linux', logger), ]; final ProjectMigration migration = ProjectMigration(migrators); diff --git a/packages/flutter_tools/lib/src/linux/native_assets.dart b/packages/flutter_tools/lib/src/linux/native_assets.dart new file mode 100644 index 0000000000000..a9dcb334d870f --- /dev/null +++ b/packages/flutter_tools/lib/src/linux/native_assets.dart @@ -0,0 +1,238 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; + +import '../base/common.dart'; +import '../base/file_system.dart'; +import '../base/io.dart'; +import '../build_info.dart'; +import '../globals.dart' as globals; +import '../native_assets.dart'; + +/// Dry run the native builds. +/// +/// This does not build native assets, it only simulates what the final paths +/// of all assets will be so that this can be embedded in the kernel file. +Future dryRunNativeAssetsLinux({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + bool flutterTester = false, + required FileSystem fileSystem, +}) async { + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + return null; + } + + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.linux); + final Iterable nativeAssetPaths = await dryRunNativeAssetsLinuxInternal( + fileSystem, + projectUri, + flutterTester, + buildRunner, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + nativeAssetPaths, + buildUri_, + fileSystem, + ); + return nativeAssetsUri; +} + +Future> dryRunNativeAssetsLinuxInternal( + FileSystem fileSystem, + Uri projectUri, + bool flutterTester, + NativeAssetsBuildRunner buildRunner, +) async { + const OS targetOs = OS.linux; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + + globals.logger.printTrace('Dry running native assets for $targetOs.'); + final List nativeAssets = (await buildRunner.dryRun( + linkModePreference: LinkModePreference.dynamic, + targetOs: targetOs, + workingDirectory: projectUri, + includeParentEnvironment: true, + )) + .assets; + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Dry running native assets for $targetOs done.'); + final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Map assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); + final Iterable nativeAssetPaths = assetTargetLocations.values; + return nativeAssetPaths; +} + +/// Builds native assets. +/// +/// If [targetPlatform] is omitted, the current target architecture is used. +/// +/// If [flutterTester] is true, absolute paths are emitted in the native +/// assets mapping. This can be used for JIT mode without sandbox on the host. +/// This is used in `flutter test` and `flutter run -d flutter-tester`. +Future<(Uri? nativeAssetsYaml, List dependencies)> buildNativeAssetsLinux({ + required NativeAssetsBuildRunner buildRunner, + TargetPlatform? targetPlatform, + required Uri projectUri, + required BuildMode buildMode, + bool flutterTester = false, + Uri? yamlParentDirectory, + required FileSystem fileSystem, +}) async { + const OS targetOs = OS.linux; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + final Directory buildDir = fileSystem.directory(buildUri_); + if (!await buildDir.exists()) { + // CMake requires the folder to exist to do copying. + await buildDir.create(recursive: true); + } + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + final Uri nativeAssetsYaml = await writeNativeAssetsYaml([], yamlParentDirectory ?? buildUri_, fileSystem); + return (nativeAssetsYaml, []); + } + + final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current; + final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); + + globals.logger.printTrace('Building native assets for $target $buildModeCli.'); + final BuildResult result = await buildRunner.build( + linkModePreference: LinkModePreference.dynamic, + target: target, + buildMode: buildModeCli, + workingDirectory: projectUri, + includeParentEnvironment: true, + cCompilerConfig: await buildRunner.cCompilerConfig, + ); + final List nativeAssets = result.assets; + final Set dependencies = result.dependencies.toSet(); + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Building native assets for $target done.'); + final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Map assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); + await _copyNativeAssetsLinux( + buildUri_, + assetTargetLocations, + buildMode, + fileSystem, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + assetTargetLocations.values, + yamlParentDirectory ?? buildUri_, + fileSystem, + ); + return (nativeAssetsUri, dependencies.toList()); +} + +Map _assetTargetLocations( + List nativeAssets, + Uri? absolutePath, +) => + { + for (final Asset asset in nativeAssets) asset: _targetLocationLinux(asset, absolutePath), + }; + +Asset _targetLocationLinux(Asset asset, Uri? absolutePath) { + final AssetPath path = asset.path; + switch (path) { + case AssetSystemPath _: + case AssetInExecutable _: + case AssetInProcess _: + return asset; + case AssetAbsolutePath _: + final String fileName = path.uri.pathSegments.last; + Uri uri; + if (absolutePath != null) { + // Flutter tester needs full host paths. + uri = absolutePath.resolve(fileName); + } else { + // Flutter Desktop needs "absolute" paths inside the app. + // "relative" in the context of native assets would be relative to the + // kernel or aot snapshot. + uri = Uri(path: fileName); + } + return asset.copyWith(path: AssetAbsolutePath(uri)); + } + throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); +} + +/// Extract the [Target] from a [TargetPlatform]. +Target _getNativeTarget(TargetPlatform targetPlatform) { + switch (targetPlatform) { + case TargetPlatform.linux_x64: + return Target.linuxX64; + case TargetPlatform.linux_arm64: + return Target.linuxArm64; + case TargetPlatform.android: + case TargetPlatform.ios: + case TargetPlatform.darwin: + case TargetPlatform.windows_x64: + case TargetPlatform.fuchsia_arm64: + case TargetPlatform.fuchsia_x64: + case TargetPlatform.tester: + case TargetPlatform.web_javascript: + case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: + case TargetPlatform.android_x64: + case TargetPlatform.android_x86: + throw Exception('Unknown targetPlatform: $targetPlatform.'); + } +} + +Future _copyNativeAssetsLinux( + Uri buildUri, + Map assetTargetLocations, + BuildMode buildMode, + FileSystem fileSystem, +) async { + if (assetTargetLocations.isNotEmpty) { + globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); + final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); + if (!buildDir.existsSync()) { + buildDir.createSync(recursive: true); + } + for (final MapEntry assetMapping in assetTargetLocations.entries) { + final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri; + final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri; + final Uri targetUri = buildUri.resolveUri(target); + final String targetFullPath = targetUri.toFilePath(); + await fileSystem.file(source).copy(targetFullPath); + } + globals.logger.printTrace('Copying native assets done.'); + } +} + +/// Flutter expects `clang++` to be on the path on Linux hosts. +/// +/// Search for the accompanying `clang`, `ar`, and `ld`. +Future cCompilerConfigLinux() async { + const String kClangPlusPlusBinary = 'clang++'; + const String kClangBinary = 'clang'; + const String kArBinary = 'llvm-ar'; + const String kLdBinary = 'ld.lld'; + + final ProcessResult whichResult = await globals.processManager.run(['which', kClangPlusPlusBinary]); + if (whichResult.exitCode != 0) { + throwToolExit('Failed to find $kClangPlusPlusBinary on PATH.'); + } + File clangPpFile = globals.fs.file((whichResult.stdout as String).trim()); + clangPpFile = globals.fs.file(await clangPpFile.resolveSymbolicLinks()); + + final Directory clangDir = clangPpFile.parent; + final Map binaryPaths = {}; + for (final String binary in [kClangBinary, kArBinary, kLdBinary]) { + final File binaryFile = clangDir.childFile(binary); + if (!await binaryFile.exists()) { + throwToolExit("Failed to find $binary relative to $clangPpFile: $binaryFile doesn't exist."); + } + binaryPaths[binary] = binaryFile.uri; + } + return CCompilerConfig( + ar: binaryPaths[kArBinary], + cc: binaryPaths[kClangBinary], + ld: binaryPaths[kLdBinary], + ); +} diff --git a/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart new file mode 100644 index 0000000000000..fe9ba86a035ac --- /dev/null +++ b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart @@ -0,0 +1,65 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../base/file_system.dart'; +import '../base/project_migrator.dart'; +import '../cmake_project.dart'; + +/// Adds the snippet to the CMake file that copies the native assets. +/// +/// ```cmake +/// # Copy the native assets provided by the build.dart from all packages. +/// set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +/// install(DIRECTORY "${NATIVE_ASSETS_DIR}" +/// DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" +/// COMPONENT Runtime) +/// ``` +class CmakeNativeAssetsMigration extends ProjectMigrator { + CmakeNativeAssetsMigration(CmakeBasedProject project, this.os, super.logger) + : _cmakeFile = project.managedCmakeFile; + + final File _cmakeFile; + final String os; + + @override + void migrate() { + if (!_cmakeFile.existsSync()) { + logger.printTrace('CMake project not found, skipping install() NATIVE_ASSETS_DIR migration.'); + return; + } + + final String originalProjectContents = _cmakeFile.readAsStringSync(); + + if (originalProjectContents.contains('set(NATIVE_ASSETS_DIR')) { + // Command is already present. + return; + } + + final String copyNativeAssetsCommand = ''' + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "\${PROJECT_BUILD_DIR}native_assets/$os/") +install(DIRECTORY "\${NATIVE_ASSETS_DIR}" + DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +'''; + + // Insert the new command after the bundled libraries loop. + const String bundleLibrariesCommandEnd = r''' +endforeach(bundled_library) +'''; + + String newProjectContents = originalProjectContents; + + newProjectContents = originalProjectContents.replaceFirst( + bundleLibrariesCommandEnd, + '$bundleLibrariesCommandEnd$copyNativeAssetsCommand', + ); + + if (originalProjectContents != newProjectContents) { + logger.printStatus('CMake missing install() NATIVE_ASSETS_DIR command, updating.'); + _cmakeFile.writeAsStringSync(newProjectContents); + } + } +} diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index 3253d29191581..b269fd876ed6a 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -19,6 +19,7 @@ import 'cache.dart'; import 'features.dart'; import 'globals.dart' as globals; import 'ios/native_assets.dart'; +import 'linux/native_assets.dart'; import 'macos/native_assets.dart'; import 'macos/native_assets_host.dart'; import 'resident_runner.dart'; @@ -168,6 +169,9 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { if (globals.platform.isMacOS || globals.platform.isIOS) { return cCompilerConfigMacOS(); } + if (globals.platform.isLinux) { + return cCompilerConfigLinux(); + } throwToolExit( 'Native assets feature not yet implemented for Linux, Windows and Android.', ); @@ -333,6 +337,13 @@ Future dryRunNativeAssets({ fileSystem: fileSystem, buildRunner: buildRunner, ); + } else if (const LocalPlatform().isLinux) { + nativeAssetsYaml = await dryRunNativeAssetsLinux( + projectUri: projectUri, + flutterTester: true, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); } else { await ensureNoNativeAssetsOrOsIsSupported( projectUri, @@ -342,6 +353,13 @@ Future dryRunNativeAssets({ ); nativeAssetsYaml = null; } + case build_info.TargetPlatform.linux_arm64: + case build_info.TargetPlatform.linux_x64: + nativeAssetsYaml = await dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); case build_info.TargetPlatform.android_arm: case build_info.TargetPlatform.android_arm64: case build_info.TargetPlatform.android_x64: @@ -349,8 +367,6 @@ Future dryRunNativeAssets({ case build_info.TargetPlatform.android: case build_info.TargetPlatform.fuchsia_arm64: case build_info.TargetPlatform.fuchsia_x64: - case build_info.TargetPlatform.linux_arm64: - case build_info.TargetPlatform.linux_x64: case build_info.TargetPlatform.web_javascript: case build_info.TargetPlatform.windows_x64: await ensureNoNativeAssetsOrOsIsSupported( @@ -382,7 +398,12 @@ Future dryRunNativeAssetsMultipeOSes({ if (targetPlatforms.contains(build_info.TargetPlatform.darwin) || (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS)) ...await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, false, buildRunner), - if (targetPlatforms.contains(build_info.TargetPlatform.ios)) ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) + if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) || + targetPlatforms.contains(build_info.TargetPlatform.linux_x64) || + (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.linux)) + ...await dryRunNativeAssetsLinuxInternal(fileSystem, projectUri, false, buildRunner), + if (targetPlatforms.contains(build_info.TargetPlatform.ios)) + ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) ]; final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); return nativeAssetsUri; diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 8f50eb9268b05..347f3623ff593 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -16,6 +16,7 @@ import '../bundle.dart'; import '../compile.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; +import '../linux/native_assets.dart'; import '../macos/native_assets.dart'; import '../native_assets.dart'; import '../project.dart'; @@ -181,7 +182,15 @@ class TestCompiler { flutterTester: true, fileSystem: globals.fs, buildRunner: buildRunner, - ); + ); + } else if (globals.platform.isLinux) { + (nativeAssetsYaml, _) = await buildNativeAssetsLinux( + buildMode: BuildMode.debug, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); } else { await ensureNoNativeAssetsOrOsIsSupported( projectUri, diff --git a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl index a4fc907bec376..580180401d132 100644 --- a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl @@ -127,6 +127,12 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart new file mode 100644 index 0000000000000..34d2fc552f820 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart @@ -0,0 +1,374 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/dart/package_map.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/linux/native_assets.dart'; +import 'package:flutter_tools/src/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; +import 'package:package_config/package_config_types.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fakes.dart'; +import '../fake_native_assets_build_runner.dart'; + +void main() { + late FakeProcessManager processManager; + late Environment environment; + late Artifacts artifacts; + late FileSystem fileSystem; + late BufferLogger logger; + late Uri projectUri; + + setUp(() { + processManager = FakeProcessManager.empty(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + fileSystem = MemoryFileSystem.test(); + environment = Environment.test( + fileSystem.currentDirectory, + inputs: {}, + artifacts: artifacts, + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + environment.buildDir.createSync(recursive: true); + projectUri = environment.projectDir.uri; + }); + + testUsingContext('dry run with no package config', overrides: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + expect( + await dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ), + null, + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('build with no package config', overrides: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run for multiple OSes with no package config', overrides: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await dryRunNativeAssetsMultipeOSes( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: [ + TargetPlatform.darwin, + TargetPlatform.ios, + ], + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run with assets but not enabled', overrides: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('dry run with assets', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final Uri? nativeAssetsYaml = await dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: [ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.linuxX64, + path: AssetAbsolutePath(Uri.file('libbar.so')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.linuxArm64, + path: AssetAbsolutePath(Uri.file('libbar.so')), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/linux/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + contains('package:bar/bar.dart'), + ); + }); + + testUsingContext('build with assets but not enabled', overrides: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('build no assets', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/linux/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + isNot(contains('package:bar/bar.dart')), + ); + expect( + environment.projectDir + .childDirectory('build') + .childDirectory('native_assets') + .childDirectory('linux'), + exists, + ); + }); + + for (final bool flutterTester in [false, true]) { + String testName = ''; + if (flutterTester) { + testName += ' flutter tester'; + } + testUsingContext('build with assets$testName', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + if (const LocalPlatform().isWindows) { + return; // Backslashes in commands, but we will never run these commands on Windows. + } + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final File dylibAfterCompiling = fileSystem.file('libbar.so'); + // The mock doesn't create the file, so create it here. + await dylibAfterCompiling.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + flutterTester: flutterTester, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + buildResult: FakeNativeAssetsBuilderResult( + assets: [ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.linuxX64, + path: AssetAbsolutePath(dylibAfterCompiling.uri), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/linux/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + stringContainsInOrder([ + 'package:bar/bar.dart', + if (flutterTester) + // Tests run on host system, so the have the full path on the system. + '- ${projectUri.resolve('/build/native_assets/linux/libbar.so').toFilePath()}' + else + // Apps are a bundle with the dylibs on their dlopen path. + '- libbar.so', + ]), + ); + }); + } + + testUsingContext('static libs not supported', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: [ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.a')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.macOSX64, + path: AssetAbsolutePath(Uri.file('bar.a')), + ), + ], + ), + ), + ), + throwsToolExit( + message: 'Native asset(s) package:bar/bar.dart have their link mode set to ' + 'static, but this is not yet supported. ' + 'For more info see https://github.com/dart-lang/sdk/issues/49418.', + ), + ); + }); + + // This logic is mocked in the other tests to avoid having test order + // randomization causing issues with what processes are invoked. + // Exercise the parsing of the process output in this separate test. + testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + [ + const FakeCommand( + command: ['which', 'clang++'], + stdout: ''' +/some/path/to/clang++ +''', // Newline at the end of the string. + ) + ], + ), + FileSystem: () => fileSystem, + }, () async { + if (!const LocalPlatform().isLinux) { + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + return; + } + + await fileSystem.directory('/some/path/to/').create(recursive: true); + await fileSystem.file('/some/path/to/clang++').create(); + await fileSystem.file('/some/path/to/clang').create(); + await fileSystem.file('/some/path/to/llvm-ar').create(); + await fileSystem.file('/some/path/to/ld.lld').create(); + + final File packagesFile = fileSystem + .directory(projectUri) + .childDirectory('.dart_tool') + .childFile('package_config.json'); + await packagesFile.parent.create(); + await packagesFile.create(); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + packagesFile, + logger: environment.logger, + ); + final NativeAssetsBuildRunner runner = + NativeAssetsBuildRunnerImpl(projectUri, packageConfig, fileSystem, logger); + final CCompilerConfig result = await runner.cCompilerConfig; + expect(result.cc, Uri.file('/some/path/to/clang')); + }); +} diff --git a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart index 36ee8d7824a3a..8689febb15ae8 100644 --- a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cmake_project.dart'; import 'package:flutter_tools/src/migrations/cmake_custom_command_migration.dart'; +import 'package:flutter_tools/src/migrations/cmake_native_assets_migration.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; @@ -155,6 +156,132 @@ add_custom_command( expect(testLogger.statusText, contains('add_custom_command() missing VERBATIM or FLUTTER_TARGET_PLATFORM, updating.')); }); }); + + group('migrate add install() NATIVE_ASSETS_DIR command', () { + late MemoryFileSystem memoryFileSystem; + late BufferLogger testLogger; + late FakeCmakeProject mockCmakeProject; + late File managedCmakeFile; + + setUp(() { + memoryFileSystem = MemoryFileSystem.test(); + managedCmakeFile = memoryFileSystem.file('CMakeLists.txtx'); + + testLogger = BufferLogger( + terminal: Terminal.test(), + outputPreferences: OutputPreferences.test(), + ); + + mockCmakeProject = FakeCmakeProject(managedCmakeFile); + }); + + testWithoutContext('skipped if files are missing', () { + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + expect(managedCmakeFile.existsSync(), isFalse); + + expect(testLogger.traceText, contains('CMake project not found, skipping install() NATIVE_ASSETS_DIR migration.')); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if nothing to migrate', () { + const String contents = 'Nothing to migrate'; + managedCmakeFile.writeAsStringSync(contents); + final DateTime projectLastModified = managedCmakeFile.lastModifiedSync(); + + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.lastModifiedSync(), projectLastModified); + expect(managedCmakeFile.readAsStringSync(), contents); + + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if already migrated', () { + const String contents = r''' +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +'''; + managedCmakeFile.writeAsStringSync(contents); + final DateTime projectLastModified = managedCmakeFile.lastModifiedSync(); + + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.lastModifiedSync(), projectLastModified); + expect(managedCmakeFile.readAsStringSync(), contents); + + expect(testLogger.statusText, isEmpty); + }); + + // TODO(dacoharkes): Add test for Windows when adding Windows support. https://github.com/flutter/flutter/issues/129757 + testWithoutContext('is migrated to copy native assets', () { + managedCmakeFile.writeAsStringSync(r''' +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) +'''); + + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.readAsStringSync(), r''' +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) +'''); + + expect(testLogger.statusText, contains('CMake missing install() NATIVE_ASSETS_DIR command, updating.')); + }); + }); }); } diff --git a/packages/flutter_tools/test/integration.shard/native_assets_test.dart b/packages/flutter_tools/test/integration.shard/native_assets_test.dart index e539e74a27a75..c6824fb35774e 100644 --- a/packages/flutter_tools/test/integration.shard/native_assets_test.dart +++ b/packages/flutter_tools/test/integration.shard/native_assets_test.dart @@ -17,6 +17,7 @@ import 'dart:io'; import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; import '../src/common.dart'; import 'test_utils.dart' show fileSystem, platform; @@ -56,10 +57,8 @@ const String packageName = 'package_with_native_assets'; const String exampleAppName = '${packageName}_example'; -const String dylibName = 'lib$packageName.dylib'; - void main() { - if (!platform.isMacOS) { + if (!platform.isMacOS && !platform.isLinux) { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 return; } @@ -148,6 +147,9 @@ void main() { if (device == 'macos') { expectDylibIsBundledMacOS(exampleDirectory, buildMode); } + if (device == 'linux') { + expectDylibIsBundledLinux(exampleDirectory, buildMode); + } if (device == hostOs) { expectCCompilerIsConfigured(exampleDirectory); } @@ -201,6 +203,8 @@ void main() { expectDylibIsBundledMacOS(exampleDirectory, buildMode); } else if (buildSubcommand == 'ios') { expectDylibIsBundledIos(exampleDirectory, buildMode); + } else if (buildSubcommand == 'linux') { + expectDylibIsBundledLinux(exampleDirectory, buildMode); } expectCCompilerIsConfigured(exampleDirectory); }); @@ -278,7 +282,7 @@ void expectDylibIsBundledMacOS(Directory appDirectory, String buildMode) { expect(appBundle, exists); final Directory dylibsFolder = appBundle.childDirectory('Contents/Frameworks'); expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(dylibName); + final File dylib = dylibsFolder.childFile(OS.macOS.dylibFileName(packageName)); expect(dylib, exists); } @@ -287,7 +291,21 @@ void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { expect(appBundle, exists); final Directory dylibsFolder = appBundle.childDirectory('Frameworks'); expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(dylibName); + final File dylib = dylibsFolder.childFile(OS.iOS.dylibFileName(packageName)); + expect(dylib, exists); +} + +/// Checks that dylibs are bundled. +/// +/// Sample path: build/linux/x64/release/bundle/lib/libmy_package.so +void expectDylibIsBundledLinux(Directory appDirectory, String buildMode) { + // Linux does not support cross compilation, so always only check current architecture. + final String architecture = Architecture.current.dartPlatform; + final Directory appBundle = appDirectory.childDirectory('build/$hostOs/$architecture/$buildMode/bundle/'); + expect(appBundle, exists); + final Directory dylibsFolder = appBundle.childDirectory('lib/'); + expect(dylibsFolder, exists); + final File dylib = dylibsFolder.childFile(OS.linux.dylibFileName(packageName)); expect(dylib, exists); } @@ -296,7 +314,7 @@ void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { void expectDylibIsBundledWithFrameworks(Directory appDirectory, String buildMode, String os) { final Directory frameworksFolder = appDirectory.childDirectory('build/$os/framework/${buildMode.upperCaseFirst()}'); expect(frameworksFolder, exists); - final File dylib = frameworksFolder.childFile(dylibName); + final File dylib = frameworksFolder.childFile(OS.macOS.dylibFileName(packageName)); expect(dylib, exists); } diff --git a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart index 9c34917600395..fa3a7f3b9e5b8 100644 --- a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart +++ b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_tools/src/base/platform.dart'; import 'package:meta/meta.dart'; import 'package:process/process.dart'; @@ -177,9 +178,15 @@ Future runFlutter( minutes: 10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml. }) async { + const LocalPlatform platform = LocalPlatform(); final Stopwatch clock = Stopwatch()..start(); final Process process = await processManager.start( - [flutterBin, ...arguments], + [ + // In a container with no X display, use the virtual framebuffer. + if (platform.isLinux && (platform.environment['DISPLAY'] ?? '').isEmpty) '/usr/bin/xvfb-run', + flutterBin, + ...arguments, + ], workingDirectory: workingDirectory, ); final List logs = []; From 06e346a8a0231cef4e95d85d90da8b87f0150a8a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 10:47:21 -0400 Subject: [PATCH 1317/1547] Roll Flutter Engine from 4107ee0dc8b1 to be7a039c5451 (1 revision) (#134937) https://github.com/flutter/engine/compare/4107ee0dc8b1...be7a039c5451 2023-09-18 skia-flutter-autoroll@skia.org Roll Dart SDK from 5c56e0f3fe13 to 5b0e7bda1379 (1 revision) (flutter/engine#45974) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2b1c4ea28a063..df32a53951b42 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -4107ee0dc8b11cdd7bd7e890deb8f4783e2aecbb +be7a039c5451dcb9c8d3b2bbbb8a864576ad1276 From b7d0e8c9ed70126ac95a1b2d3e1651555913ee3b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 12:22:46 -0400 Subject: [PATCH 1318/1547] Roll Packages from bc8c2f20910b to d4e245421737 (6 revisions) (#134945) https://github.com/flutter/packages/compare/bc8c2f20910b...d4e245421737 2023-09-18 me@nils.re [camera_android] Removes usage of `_ambiguate` method in example (flutter/packages#4924) 2023-09-17 engine-flutter-autoroll@skia.org Roll Flutter from e5e36ad34058 to 1b18b1327a59 (8 revisions) (flutter/packages#4940) 2023-09-16 engine-flutter-autoroll@skia.org Roll Flutter from 72b69f944915 to e5e36ad34058 (12 revisions) (flutter/packages#4938) 2023-09-15 49699333+dependabot[bot]@users.noreply.github.com [webview]: Bump androidx.annotation:annotation from 1.5.0 to 1.7.0 in /packages/webview_flutter/webview_flutter_android/android (flutter/packages#4891) 2023-09-15 engine-flutter-autoroll@skia.org Roll Flutter from 58ba6c295d8c to 72b69f944915 (21 revisions) (flutter/packages#4934) 2023-09-15 stuartmorgan@google.com [image_picker] Add missing entitlements to macOS example (flutter/packages#4931) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 43566584c7ebd..ea3bd83ec2020 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -bc8c2f20910bd3e70b1c16622b0d482ef73a0449 +d4e24542173774e2f9d78de8fd17d34713478bf4 From b195c944cc334fa9839abdfc2c0ecfcc1ed908b6 Mon Sep 17 00:00:00 2001 From: huycozy <104349824+huycozy@users.noreply.github.com> Date: Mon, 18 Sep 2023 23:40:07 +0700 Subject: [PATCH 1319/1547] Migrate the "Missing frames / speed related performance issues" issue template to use Github forms (#134033) Closes #119921 ### Demo - Demo issue template: [Issue: My app is slow or missing frames](https://github.com/huycozy/flutter/issues/new?assignees=&labels=from%3A+performance+template&projects=&template=5_performance_speed.yml) - Demo a filed issue: https://github.com/huycozy/flutter/issues/5 --- .github/ISSUE_TEMPLATE/5_performance_speed.md | 81 --------- .../ISSUE_TEMPLATE/5_performance_speed.yml | 172 ++++++++++++++++++ 2 files changed, 172 insertions(+), 81 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/5_performance_speed.md create mode 100644 .github/ISSUE_TEMPLATE/5_performance_speed.yml diff --git a/.github/ISSUE_TEMPLATE/5_performance_speed.md b/.github/ISSUE_TEMPLATE/5_performance_speed.md deleted file mode 100644 index 0c7054c535829..0000000000000 --- a/.github/ISSUE_TEMPLATE/5_performance_speed.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: My app is slow or missing frames -about: You are writing an application but have discovered that it is slow, you are - not hitting 60Hz, or you are getting jank (missed frames). -title: '' -labels: 'from: performance template' -assignees: '' - ---- - - - -## Details - - - - - -**Target Platform:** -**Target OS version/browser:** -**Devices:** - -## Logs - -
    -Logs - - - -``` -``` - - - -``` -``` - -
    diff --git a/.github/ISSUE_TEMPLATE/5_performance_speed.yml b/.github/ISSUE_TEMPLATE/5_performance_speed.yml new file mode 100644 index 0000000000000..8133968f98397 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/5_performance_speed.yml @@ -0,0 +1,172 @@ +name: My app is slow or missing frames +description: | + You are writing an application but have discovered that it is slow, + you are not hitting 60Hz, or you are getting jank (missed frames). +labels: 'from: performance template' +body: + - type: markdown + attributes: + value: | + Thank you for using Flutter! + + If you are looking for support, please check out our documentation + or consider asking a question on Stack Overflow: + + - https://flutter.dev/ + - https://api.flutter.dev/ + - https://stackoverflow.com/questions/tagged/flutter?sort=frequent + - type: textarea + attributes: + label: Steps to reproduce + description: Please tell us exactly how to reproduce the problem you are running into. + placeholder: | + 1. ... + 2. ... + 3. ... + validations: + required: true + - type: textarea + attributes: + label: Code sample + description: | + Please create a minimal reproducible sample that shows the problem and attach it below between the lines with the backticks. + + Try to reproduce the problem in a test app. Either run `flutter create janktest` and recreate the situation you are experiencing in that app, or clone your app and delete code until you have the jank reproducing with a single `.dart` file. + + If you need more than just a `.dart` file (for example, assets are needed to reproduce the issue, or plugins/packages are needed to reproduce the issue) then create a GitHub repository and upload code there. + + Without this we will unlikely be able to progress on the issue, and because of that we regretfully will have to close it. + + Note: Please do not upload screenshots of text. Instead, use code blocks or the above mentioned ways to upload your code sample. + value: | +
    Code sample + + ```dart + [Paste your code here] + ``` + +
    + validations: + required: true + - type: checkboxes + attributes: + label: Performance profiling on master channel + description: | + Switch flutter to master channel and run this app on a physical device using profile mode with Skia tracing enabled, as follows: + ```console + flutter channel master + flutter run --profile --trace-skia + ``` + The bleeding edge master channel is encouraged here because Flutter is constantly fixing bugs and improving its performance. Your problem in an older Flutter version may have already been solved in the master channel. + options: + - label: The issue still persists on the master channel + required: true + - type: textarea + attributes: + label: Timeline Traces + description: | + Open Flutter DevTools and save a timeline trace of the performance issue so we know which functions might be causing it. See "How to Collect and Read Timeline Traces" on this blog post: https://medium.com/flutter/profiling-flutter-applications-using-the-timeline-a1a434964af3#a499 + + Make sure the performance overlay is turned OFF when recording the trace as that may affect the performance of the profile run. (Pressing ‘P’ on the command line toggles the overlay.) + + If the trace are too large to be uploaded to GitHub, you may upload them as a `zip` file or use online tools like https://pastebin.com to share it. + value: | +
    Timeline Traces JSON + + ```json + [Paste the Timeline Traces here] + ``` + +
    + validations: + required: true + - type: textarea + attributes: + label: Video demonstration + description: | + Record a video of the performance issue using another phone so we can have an intuitive understanding of what happened. + + Don’t use "adb screenrecord", as that affects the performance of the profile run. + value: | +
    + Video demonstration + + [Upload media here] + +
    + - type: dropdown + id: target_platforms + attributes: + label: What target platforms are you seeing this bug on? + multiple: true + options: + - Android + - iOS + - Web + - macOS + - Linux + - Windows + validations: + required: true + - type: textarea + attributes: + label: OS/Browser name and version | Device information + description: | + Which target OS version is the test system running? For Web, please provide browser version. + Please also include the device information (model, CPU architecture, etc). + validations: + required: true + - type: dropdown + id: device-kind + attributes: + label: Does the problem occur on emulator/simulator as well as on physical devices? + options: + - "Unknown" + - "Yes" + - "No" + validations: + required: true + - type: dropdown + id: enable-impeller + attributes: + label: Is the problem only reproducible with Impeller? + description: | + Please check https://docs.flutter.dev/perf/impeller as the guideline on how to enable/disable it. + options: + - "N/A" + - "Yes" + - "No" + validations: + required: true + - type: textarea + attributes: + label: Logs + description: | + Include the full logs of the commands you are running between the lines with the backticks below. If you are running any `flutter` commands, please include the output of running them with `--verbose`; for example, the output of running `flutter --verbose create foo`. + + If the logs are too large to be uploaded to GitHub, you may upload them as a `txt` file or use online tools like https://pastebin.com to share it. + + Note: Please do not upload screenshots of text. Instead, use code blocks or the above mentioned ways to upload logs. + value: | +
    Logs + + ```console + [Paste your logs here] + ``` + +
    + - type: textarea + attributes: + label: Flutter Doctor output + description: | + Finally, paste the output of running `flutter doctor -v` here, with your device plugged in. + value: | +
    Doctor output + + ```console + [Paste your output here] + ``` + +
    + validations: + required: true From bac5e5d518bf0eec035f4f462a3853fcc6c8700e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 18 Sep 2023 14:13:13 -0400 Subject: [PATCH 1320/1547] Roll Flutter Engine from be7a039c5451 to e1c784e3f841 (3 revisions) (#134956) https://github.com/flutter/engine/compare/be7a039c5451...e1c784e3f841 2023-09-18 skia-flutter-autoroll@skia.org Roll Skia from f8065ca00d0c to 0c990ab9e097 (7 revisions) (flutter/engine#45979) 2023-09-18 mdebbar@google.com [web] ScreenOrientation singleton (flutter/engine#45304) 2023-09-18 mdebbar@google.com [web] De-singletonize MouseCursor for multi-view (flutter/engine#45295) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index df32a53951b42..71dcbe8aaf38b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -be7a039c5451dcb9c8d3b2bbbb8a864576ad1276 +e1c784e3f8415f529a24886568806548f385c1d4 From 9dd3e1e6fce922852dd0b98522efe7252ed13c7a Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Mon, 18 Sep 2023 20:39:01 +0200 Subject: [PATCH 1321/1547] Fix memory leak in _DarwinViewState. (#134938) --- .../lib/src/widgets/platform_view.dart | 3 + .../test/widgets/platform_view_test.dart | 209 +++++++++--------- 2 files changed, 108 insertions(+), 104 deletions(-) diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index 1115bb887038f..f8c2144c63693 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -665,6 +665,9 @@ abstract class _DarwinViewState(); @@ -1421,7 +1422,7 @@ void main() { ); }); - testWidgets('UIView survives widget tree change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UIView survives widget tree change', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1454,7 +1455,7 @@ void main() { ); }); - testWidgets('Create UIView with params', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Create UIView with params', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1492,7 +1493,7 @@ void main() { ); }); - testWidgets('UiKitView accepts gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView accepts gestures', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1520,7 +1521,7 @@ void main() { expect(viewsController.gesturesAccepted[currentViewId + 1], 1); }); - testWidgets('UiKitView transparent hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView transparent hit test behavior', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1565,7 +1566,7 @@ void main() { expect(numPointerDownsOnParent, 1); }); - testWidgets('UiKitView translucent hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView translucent hit test behavior', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1610,7 +1611,7 @@ void main() { expect(numPointerDownsOnParent, 1); }); - testWidgets('UiKitView opaque hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView opaque hit test behavior', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1653,7 +1654,7 @@ void main() { expect(numPointerDownsOnParent, 0); }); - testWidgets('UiKitView can lose gesture arenas', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView can lose gesture arenas', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1691,7 +1692,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 1); }); - testWidgets('UiKitView tap gesture recognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView tap gesture recognizers', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1735,7 +1736,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView long press gesture recognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView long press gesture recognizers', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1777,7 +1778,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView drag gesture recognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView drag gesture recognizers', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1819,7 +1820,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView can claim gesture after all pointers are up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView can claim gesture after all pointers are up', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1859,7 +1860,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView rebuilt during gesture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView rebuilt during gesture', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1904,7 +1905,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView with eager gesture recognizer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView with eager gesture recognizer', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1944,7 +1945,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView rejects gestures absorbed by siblings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView rejects gestures absorbed by siblings', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -1974,7 +1975,7 @@ void main() { expect(viewsController.gesturesAccepted[currentViewId + 1], 0); }); - testWidgets( + testWidgetsWithLeakTracking( 'UiKitView rejects gestures absorbed by siblings if the touch is outside of the platform view bounds but inside platform view frame', (WidgetTester tester) async { // UiKitView is positioned at (left=0, top=100, right=300, bottom=600). @@ -2024,7 +2025,7 @@ void main() { }, ); - testWidgets('UiKitView rebuilt with same gestureRecognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView rebuilt with same gestureRecognizers', (WidgetTester tester) async { final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2058,7 +2059,7 @@ void main() { expect(factoryInvocationCount, 1); }); - testWidgets('UiKitView can take input focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView can take input focus', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2111,7 +2112,7 @@ void main() { expect(uiKitViewFocusNode.hasFocus, isTrue); }); - testWidgets('UiKitView sends TextInput.setPlatformViewClient when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView sends TextInput.setPlatformViewClient when focused', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); @@ -2150,7 +2151,7 @@ void main() { expect(channelArguments['platformViewId'], currentViewId + 1); }); - testWidgets('FocusNode is disposed on UIView dispose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusNode is disposed on UIView dispose', (WidgetTester tester) async { final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2178,7 +2179,7 @@ void main() { expect(() => ChangeNotifier.debugAssertNotDisposed(node), throwsAssertionError); }); - testWidgets('UiKitView has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView has correct semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); expect(currentViewId, greaterThanOrEqualTo(0)); @@ -2225,7 +2226,7 @@ void main() { }); group('AppKitView', () { - testWidgets('Create AppView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Create AppView', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2248,7 +2249,7 @@ void main() { ); }); - testWidgets('Change AppKitView view type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Change AppKitView view type', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2281,7 +2282,7 @@ void main() { ); }); - testWidgets('Dispose AppKitView ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dispose AppKitView ', (WidgetTester tester) async { final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); await tester.pumpWidget( @@ -2309,7 +2310,7 @@ void main() { ); }); - testWidgets('Dispose AppKitView before creation completed ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dispose AppKitView before creation completed ', (WidgetTester tester) async { final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); viewsController.creationDelay = Completer(); @@ -2340,7 +2341,7 @@ void main() { ); }); - testWidgets('AppKitView survives widget tree change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView survives widget tree change', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2373,7 +2374,7 @@ void main() { ); }); - testWidgets('Create AppKitView with params', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Create AppKitView with params', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2413,7 +2414,7 @@ void main() { // TODO(schectman): De-skip the following tests once macOS gesture recognizers are present. // https://github.com/flutter/flutter/issues/128519 - testWidgets('AppKitView accepts gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView accepts gestures', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2441,7 +2442,7 @@ void main() { expect(viewsController.gesturesAccepted[currentViewId + 1], 1); }, skip: true); // https://github.com/flutter/flutter/issues/128519 - testWidgets('AppKitView transparent hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView transparent hit test behavior', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2486,7 +2487,7 @@ void main() { expect(numPointerDownsOnParent, 1); }, skip: true); // https://github.com/flutter/flutter/issues/128519 - testWidgets('AppKitView translucent hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView translucent hit test behavior', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2531,7 +2532,7 @@ void main() { expect(numPointerDownsOnParent, 1); }, skip: true); // https://github.com/flutter/flutter/issues/128519 - testWidgets('AppKitView opaque hit test behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView opaque hit test behavior', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2574,7 +2575,7 @@ void main() { expect(numPointerDownsOnParent, 0); }, skip: true); // https://github.com/flutter/flutter/issues/128519 - testWidgets('UiKitView can lose gesture arenas', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView can lose gesture arenas', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2612,7 +2613,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 1); }); - testWidgets('UiKitView tap gesture recognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView tap gesture recognizers', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2656,7 +2657,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView long press gesture recognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView long press gesture recognizers', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2698,7 +2699,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView drag gesture recognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView drag gesture recognizers', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2740,7 +2741,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView can claim gesture after all pointers are up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView can claim gesture after all pointers are up', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2780,7 +2781,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView rebuilt during gesture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView rebuilt during gesture', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2825,7 +2826,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView with eager gesture recognizer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView with eager gesture recognizer', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2865,7 +2866,7 @@ void main() { expect(viewsController.gesturesRejected[currentViewId + 1], 0); }); - testWidgets('UiKitView rejects gestures absorbed by siblings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView rejects gestures absorbed by siblings', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2895,7 +2896,7 @@ void main() { expect(viewsController.gesturesAccepted[currentViewId + 1], 0); }); - testWidgets( + testWidgetsWithLeakTracking( 'UiKitView rejects gestures absorbed by siblings if the touch is outside of the platform view bounds but inside platform view frame', (WidgetTester tester) async { // UiKitView is positioned at (left=0, top=100, right=300, bottom=600). @@ -2945,7 +2946,7 @@ void main() { }, ); - testWidgets('UiKitView rebuilt with same gestureRecognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UiKitView rebuilt with same gestureRecognizers', (WidgetTester tester) async { final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -2979,7 +2980,7 @@ void main() { expect(factoryInvocationCount, 1); }); - testWidgets('AppKitView can take input focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView can take input focus', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -3032,7 +3033,7 @@ void main() { expect(uiKitViewFocusNode.hasFocus, isTrue); }); - testWidgets('AppKitView sends TextInput.setPlatformViewClient when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView sends TextInput.setPlatformViewClient when focused', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); @@ -3071,7 +3072,7 @@ void main() { expect(channelArguments['platformViewId'], currentViewId + 1); }); - testWidgets('FocusNode is disposed on UIView dispose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FocusNode is disposed on UIView dispose', (WidgetTester tester) async { final FakeMacosPlatformViewsController viewsController = FakeMacosPlatformViewsController(); viewsController.registerViewType('webview'); @@ -3099,7 +3100,7 @@ void main() { expect(() => ChangeNotifier.debugAssertNotDisposed(node), throwsAssertionError); }); - testWidgets('AppKitView has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AppKitView has correct semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); expect(currentViewId, greaterThanOrEqualTo(0)); @@ -3152,7 +3153,7 @@ void main() { controller = FakePlatformViewController(0); }); - testWidgets('PlatformViewSurface should create platform view layer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface should create platform view layer', (WidgetTester tester) async { final PlatformViewSurface surface = PlatformViewSurface( controller: controller, hitTestBehavior: PlatformViewHitTestBehavior.opaque, @@ -3162,7 +3163,7 @@ void main() { expect(() => tester.layers.whereType().first, returnsNormally); }); - testWidgets('PlatformViewSurface can lose gesture arenas', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface can lose gesture arenas', (WidgetTester tester) async { bool verticalDragAcceptedByParent = false; await tester.pumpWidget( Align( @@ -3198,7 +3199,7 @@ void main() { ); }); - testWidgets('PlatformViewSurface gesture recognizers dispatch events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface gesture recognizers dispatch events', (WidgetTester tester) async { bool verticalDragAcceptedByParent = false; await tester.pumpWidget( Align( @@ -3237,7 +3238,7 @@ void main() { ); }); - testWidgets('PlatformViewSurface can claim gesture after all pointers are up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface can claim gesture after all pointers are up', (WidgetTester tester) async { bool verticalDragAcceptedByParent = false; // The long press recognizer rejects the gesture after the PlatformViewSurface gets the pointer up event. // This test makes sure that the PlatformViewSurface can win the gesture after it got the pointer up event. @@ -3272,7 +3273,7 @@ void main() { ); }); - testWidgets('PlatformViewSurface rebuilt during gesture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface rebuilt during gesture', (WidgetTester tester) async { await tester.pumpWidget( Align( alignment: Alignment.topLeft, @@ -3314,7 +3315,7 @@ void main() { ); }); - testWidgets('PlatformViewSurface with eager gesture recognizer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface with eager gesture recognizer', (WidgetTester tester) async { await tester.pumpWidget( Align( alignment: Alignment.topLeft, @@ -3349,7 +3350,7 @@ void main() { ); }); - testWidgets('PlatformViewRenderBox reconstructed with same gestureRecognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewRenderBox reconstructed with same gestureRecognizers', (WidgetTester tester) async { int factoryInvocationCount = 0; EagerGestureRecognizer constructRecognizer() { ++factoryInvocationCount; @@ -3373,7 +3374,7 @@ void main() { expect(factoryInvocationCount, 2); }); - testWidgets('PlatformViewSurface rebuilt with same gestureRecognizers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewSurface rebuilt with same gestureRecognizers', (WidgetTester tester) async { int factoryInvocationCount = 0; EagerGestureRecognizer constructRecognizer() { ++factoryInvocationCount; @@ -3406,7 +3407,7 @@ void main() { expect(factoryInvocationCount, 1); }); - testWidgets( + testWidgetsWithLeakTracking( 'PlatformViewLink Widget init, should create a placeholder widget before onPlatformViewCreated and a PlatformViewSurface after', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); @@ -3450,7 +3451,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'PlatformViewLink widget should not trigger creation with an empty size', (WidgetTester tester) async { late PlatformViewController controller; @@ -3492,7 +3493,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'PlatformViewLink calls create when needed for Android texture display modes', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); @@ -3547,7 +3548,7 @@ void main() { }, ); - testWidgets('PlatformViewLink includes offset in create call when using texture layer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink includes offset in create call when using texture layer', (WidgetTester tester) async { addTearDown(tester.view.reset); late FakeAndroidViewController controller; @@ -3591,7 +3592,7 @@ void main() { expect(controller.createPosition, const Offset(150, 75)); }); - testWidgets( + testWidgetsWithLeakTracking( 'PlatformViewLink does not double-call create for Android Hybrid Composition', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); @@ -3641,7 +3642,7 @@ void main() { }, ); - testWidgets('PlatformViewLink Widget dispose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink Widget dispose', (WidgetTester tester) async { late FakePlatformViewController disposedController; final PlatformViewLink platformViewLink = PlatformViewLink( viewType: 'webview', @@ -3666,7 +3667,7 @@ void main() { expect(disposedController.disposed, true); }); - testWidgets('PlatformViewLink handles onPlatformViewCreated when disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink handles onPlatformViewCreated when disposed', (WidgetTester tester) async { late PlatformViewCreationParams creationParams; late FakePlatformViewController controller; final PlatformViewLink platformViewLink = PlatformViewLink( @@ -3692,7 +3693,7 @@ void main() { expect(() => creationParams.onPlatformViewCreated(creationParams.id), returnsNormally); }); - testWidgets('PlatformViewLink widget survives widget tree change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink widget survives widget tree change', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final List ids = []; @@ -3747,7 +3748,7 @@ void main() { ); }); - testWidgets('PlatformViewLink re-initializes when view type changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink re-initializes when view type changes', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final List ids = []; final List surfaceViewIds = []; @@ -3819,7 +3820,7 @@ void main() { ); }); - testWidgets('PlatformViewLink can take any widget to return in the SurfaceFactory', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink can take any widget to return in the SurfaceFactory', (WidgetTester tester) async { final PlatformViewLink platformViewLink = PlatformViewLink( viewType: 'webview', onCreatePlatformView: (PlatformViewCreationParams params) { @@ -3836,7 +3837,7 @@ void main() { expect(() => tester.allWidgets.whereType().first, returnsNormally); }); - testWidgets('PlatformViewLink manages the focus properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink manages the focus properly', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); late FakePlatformViewController controller; late ValueChanged focusChanged; @@ -3901,7 +3902,7 @@ void main() { expect(controller.focusCleared, true); }); - testWidgets('PlatformViewLink sets a platform view text input client when focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformViewLink sets a platform view text input client when focused', (WidgetTester tester) async { late FakePlatformViewController controller; late int viewId; @@ -3951,7 +3952,7 @@ void main() { }); }); - testWidgets('Platform views respect hitTestBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Platform views respect hitTestBehavior', (WidgetTester tester) async { final FakePlatformViewController controller = FakePlatformViewController(0); final List logs = []; @@ -4090,7 +4091,7 @@ void main() { expect(controller.dispatchedPointerEvents[0], isA()); }); - testWidgets('HtmlElementView can be instantiated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('HtmlElementView can be instantiated', (WidgetTester tester) async { late final Widget htmlElementView; expect(() { htmlElementView = const HtmlElementView(viewType: 'webview'); From 6425a3b4319294f5129e8c10a034ebecf029319f Mon Sep 17 00:00:00 2001 From: Xilai Zhang Date: Mon, 18 Sep 2023 12:49:10 -0700 Subject: [PATCH 1322/1547] [flutter roll] Revert "LinkedText (Linkify)" (#134955) Reverts flutter/flutter#125927 context: b/300804374 Looks like a g3 fix might involve changing the names of widget on the customer app, and I am not sure if that would be the right approach forward. Putting up a revert to be safe for now. --- .../painting/text_linker/text_linker.0.dart | 213 --------- .../painting/text_linker/text_linker.1.dart | 235 ---------- .../widgets/linked_text/linked_text.0.dart | 75 ---- .../widgets/linked_text/linked_text.1.dart | 85 ---- .../widgets/linked_text/linked_text.2.dart | 92 ---- .../widgets/linked_text/linked_text.3.dart | 184 -------- .../text_linker/text_linker.0_test.dart | 36 -- .../text_linker/text_linker.1_test.dart | 36 -- .../linked_text/linked_text.0_test.dart | 27 -- .../linked_text/linked_text.1_test.dart | 27 -- .../linked_text/linked_text.2_test.dart | 27 -- .../linked_text/linked_text.3_test.dart | 36 -- packages/flutter/lib/painting.dart | 1 - .../flutter/lib/src/painting/text_linker.dart | 422 ------------------ .../flutter/lib/src/widgets/linked_text.dart | 334 -------------- packages/flutter/lib/widgets.dart | 1 - .../test/painting/text_linker_test.dart | 322 ------------- .../test/widgets/linked_text_test.dart | 367 --------------- 18 files changed, 2520 deletions(-) delete mode 100644 examples/api/lib/painting/text_linker/text_linker.0.dart delete mode 100644 examples/api/lib/painting/text_linker/text_linker.1.dart delete mode 100644 examples/api/lib/widgets/linked_text/linked_text.0.dart delete mode 100644 examples/api/lib/widgets/linked_text/linked_text.1.dart delete mode 100644 examples/api/lib/widgets/linked_text/linked_text.2.dart delete mode 100644 examples/api/lib/widgets/linked_text/linked_text.3.dart delete mode 100644 examples/api/test/painting/text_linker/text_linker.0_test.dart delete mode 100644 examples/api/test/painting/text_linker/text_linker.1_test.dart delete mode 100644 examples/api/test/widgets/linked_text/linked_text.0_test.dart delete mode 100644 examples/api/test/widgets/linked_text/linked_text.1_test.dart delete mode 100644 examples/api/test/widgets/linked_text/linked_text.2_test.dart delete mode 100644 examples/api/test/widgets/linked_text/linked_text.3_test.dart delete mode 100644 packages/flutter/lib/src/painting/text_linker.dart delete mode 100644 packages/flutter/lib/src/widgets/linked_text.dart delete mode 100644 packages/flutter/test/painting/text_linker_test.dart delete mode 100644 packages/flutter/test/widgets/linked_text_test.dart diff --git a/examples/api/lib/painting/text_linker/text_linker.0.dart b/examples/api/lib/painting/text_linker/text_linker.0.dart deleted file mode 100644 index 15bcd93b537a2..0000000000000 --- a/examples/api/lib/painting/text_linker/text_linker.0.dart +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; - -// This example demonstrates highlighting both URLs and Twitter handles with -// different actions and different styles. - -void main() { - runApp(const TextLinkerApp()); -} - -class TextLinkerApp extends StatelessWidget { - const TextLinkerApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter Link Twitter Handle Demo'), - ); - } -} - -class MyHomePage extends StatelessWidget { - const MyHomePage({ - super.key, - required this.title - }); - - final String title; - static const String _text = '@FlutterDev is our Twitter account, or find us at www.flutter.dev'; - - void _handleTapTwitterHandle(BuildContext context, String linkString) { - final String handleWithoutAt = linkString.substring(1); - final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; - final Uri? uri = Uri.tryParse(twitterUriString); - if (uri == null) { - throw Exception('Failed to parse $twitterUriString.'); - } - _showDialog(context, uri); - } - - void _handleTapUrl(BuildContext context, String urlText) { - final Uri? uri = Uri.tryParse(urlText); - if (uri == null) { - throw Exception('Failed to parse $urlText.'); - } - _showDialog(context, uri); - } - - void _showDialog(BuildContext context, Uri uri) { - // A package like url_launcher would be useful for actually opening the URL - // here instead of just showing a dialog. - Navigator.of(context).push( - DialogRoute( - context: context, - builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: Builder( - builder: (BuildContext context) { - return SelectionArea( - child: _TwitterAndUrlLinkedText( - text: _text, - onTapUrl: (String urlString) => _handleTapUrl(context, urlString), - onTapTwitterHandle: (String handleString) => _handleTapTwitterHandle(context, handleString), - ), - ); - }, - ), - ), - ); - } -} - -class _TwitterAndUrlLinkedText extends StatefulWidget { - const _TwitterAndUrlLinkedText({ - required this.text, - required this.onTapUrl, - required this.onTapTwitterHandle, - }); - - final String text; - final ValueChanged onTapUrl; - final ValueChanged onTapTwitterHandle; - - @override - State<_TwitterAndUrlLinkedText> createState() => _TwitterAndUrlLinkedTextState(); -} - -class _TwitterAndUrlLinkedTextState extends State<_TwitterAndUrlLinkedText> { - final List _recognizers = []; - late Iterable _linkedSpans; - late final List _textLinkers; - - final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); - - void _disposeRecognizers() { - for (final GestureRecognizer recognizer in _recognizers) { - recognizer.dispose(); - } - _recognizers.clear(); - } - - void _linkSpans() { - _disposeRecognizers(); - final Iterable linkedSpans = TextLinker.linkSpans( - [TextSpan(text: widget.text)], - _textLinkers, - ); - _linkedSpans = linkedSpans; - } - - @override - void initState() { - super.initState(); - - _textLinkers = [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () => widget.onTapUrl(linkString); - _recognizers.add(recognizer); - return _MyInlineLinkSpan( - text: displayString, - color: const Color(0xff0000ee), - recognizer: recognizer, - ); - }, - ), - TextLinker( - regExp: _twitterHandleRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () => widget.onTapTwitterHandle(linkString); - _recognizers.add(recognizer); - return _MyInlineLinkSpan( - text: displayString, - color: const Color(0xff00aaaa), - recognizer: recognizer, - ); - }, - ), - ]; - - _linkSpans(); - } - - @override - void didUpdateWidget(_TwitterAndUrlLinkedText oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget.text != oldWidget.text - || widget.onTapUrl != oldWidget.onTapUrl - || widget.onTapTwitterHandle != oldWidget.onTapTwitterHandle) { - _linkSpans(); - } - } - - @override - void dispose() { - _disposeRecognizers(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - if (_linkedSpans.isEmpty) { - return const SizedBox.shrink(); - } - - return Text.rich( - TextSpan( - style: DefaultTextStyle.of(context).style, - children: _linkedSpans.toList(), - ), - ); - } -} - -class _MyInlineLinkSpan extends TextSpan { - _MyInlineLinkSpan({ - required String text, - required Color color, - required super.recognizer, - }) : super( - style: TextStyle( - color: color, - decorationColor: color, - decoration: TextDecoration.underline, - ), - mouseCursor: SystemMouseCursors.click, - text: text, - ); -} diff --git a/examples/api/lib/painting/text_linker/text_linker.1.dart b/examples/api/lib/painting/text_linker/text_linker.1.dart deleted file mode 100644 index 203a926cdd62f..0000000000000 --- a/examples/api/lib/painting/text_linker/text_linker.1.dart +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; - -// This example demonstrates creating links in a TextSpan tree instead of a flat -// String. - -void main() { - runApp(const TextLinkerApp()); -} - -class TextLinkerApp extends StatelessWidget { - const TextLinkerApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter TextLinker Span Demo'), - ); - } -} - -class MyHomePage extends StatelessWidget { - const MyHomePage({ - super.key, - required this.title - }); - - final String title; - - void _handleTapTwitterHandle(BuildContext context, String linkString) { - final String handleWithoutAt = linkString.substring(1); - final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; - final Uri? uri = Uri.tryParse(twitterUriString); - if (uri == null) { - throw Exception('Failed to parse $twitterUriString.'); - } - _showDialog(context, uri); - } - - void _handleTapUrl(BuildContext context, String urlText) { - final Uri? uri = Uri.tryParse(urlText); - if (uri == null) { - throw Exception('Failed to parse $urlText.'); - } - _showDialog(context, uri); - } - - void _showDialog(BuildContext context, Uri uri) { - // A package like url_launcher would be useful for actually opening the URL - // here instead of just showing a dialog. - Navigator.of(context).push( - DialogRoute( - context: context, - builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: Builder( - builder: (BuildContext context) { - return SelectionArea( - child: _TwitterAndUrlLinkedText( - spans: [ - TextSpan( - text: '@FlutterDev is our Twitter, or find us at www.', - style: DefaultTextStyle.of(context).style, - children: const [ - TextSpan( - style: TextStyle( - fontWeight: FontWeight.w800, - ), - text: 'flutter', - ), - ], - ), - TextSpan( - text: '.dev', - style: DefaultTextStyle.of(context).style, - ), - ], - onTapUrl: (String urlString) => _handleTapUrl(context, urlString), - onTapTwitterHandle: (String handleString) => _handleTapTwitterHandle(context, handleString), - ), - ); - }, - ), - ), - ); - } -} - -class _TwitterAndUrlLinkedText extends StatefulWidget { - const _TwitterAndUrlLinkedText({ - required this.spans, - required this.onTapUrl, - required this.onTapTwitterHandle, - }); - - final List spans; - final ValueChanged onTapUrl; - final ValueChanged onTapTwitterHandle; - - @override - State<_TwitterAndUrlLinkedText> createState() => _TwitterAndUrlLinkedTextState(); -} - -class _TwitterAndUrlLinkedTextState extends State<_TwitterAndUrlLinkedText> { - final List _recognizers = []; - late Iterable _linkedSpans; - late final List _textLinkers; - - final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); - - void _disposeRecognizers() { - for (final GestureRecognizer recognizer in _recognizers) { - recognizer.dispose(); - } - _recognizers.clear(); - } - - void _linkSpans() { - _disposeRecognizers(); - final Iterable linkedSpans = TextLinker.linkSpans( - widget.spans, - _textLinkers, - ); - _linkedSpans = linkedSpans; - } - - @override - void initState() { - super.initState(); - - _textLinkers = [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - // The linkString always contains the full matched text, so that's - // what should be linked to. - ..onTap = () => widget.onTapUrl(linkString); - _recognizers.add(recognizer); - return _MyInlineLinkSpan( - // The displayString contains only the portion of the matched text - // in a given TextSpan. For example, the bold "flutter" text in - // the overall "www.flutter.dev" URL is in its own TextSpan with its - // bold styling. linkBuilder is called separately for each part. - text: displayString, - color: const Color(0xff0000ee), - recognizer: recognizer, - ); - }, - ), - TextLinker( - regExp: _twitterHandleRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () => widget.onTapTwitterHandle(linkString); - _recognizers.add(recognizer); - return _MyInlineLinkSpan( - text: displayString, - color: const Color(0xff00aaaa), - recognizer: recognizer, - ); - }, - ), - ]; - - _linkSpans(); - } - - @override - void didUpdateWidget(_TwitterAndUrlLinkedText oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget.spans != oldWidget.spans - || widget.onTapUrl != oldWidget.onTapUrl - || widget.onTapTwitterHandle != oldWidget.onTapTwitterHandle) { - _linkSpans(); - } - } - - @override - void dispose() { - _disposeRecognizers(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - if (_linkedSpans.isEmpty) { - return const SizedBox.shrink(); - } - - return Text.rich( - TextSpan( - style: DefaultTextStyle.of(context).style, - children: _linkedSpans.toList(), - ), - ); - } -} - -class _MyInlineLinkSpan extends TextSpan { - _MyInlineLinkSpan({ - required String text, - required Color color, - required super.recognizer, - }) : super( - style: TextStyle( - color: color, - decorationColor: color, - decoration: TextDecoration.underline, - ), - mouseCursor: SystemMouseCursors.click, - text: text, - ); -} diff --git a/examples/api/lib/widgets/linked_text/linked_text.0.dart b/examples/api/lib/widgets/linked_text/linked_text.0.dart deleted file mode 100644 index e9c3b5cdaff50..0000000000000 --- a/examples/api/lib/widgets/linked_text/linked_text.0.dart +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -// This example demonstrates using LinkedText to make URLs open on tap. - -void main() { - runApp(const LinkedTextApp()); -} - -class LinkedTextApp extends StatelessWidget { - const LinkedTextApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter Link Demo'), - ); - } -} - -class MyHomePage extends StatelessWidget { - const MyHomePage({ - super.key, - required this.title, - }); - - final String title; - static const String _text = 'Check out https://www.flutter.dev, or maybe just flutter.dev or www.flutter.dev.'; - - void _handleTapUri(BuildContext context, Uri uri) { - // A package like url_launcher would be useful for actually opening the URL - // here instead of just showing a dialog. - Navigator.of(context).push( - DialogRoute( - context: context, - builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: Builder( - builder: (BuildContext context) { - return SelectionArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - LinkedText( - text: _text, - onTapUri: (Uri uri) => _handleTapUri(context, uri), - ), - ], - ), - ); - }, - ), - ), - ); - } -} diff --git a/examples/api/lib/widgets/linked_text/linked_text.1.dart b/examples/api/lib/widgets/linked_text/linked_text.1.dart deleted file mode 100644 index 48c4df841ff1e..0000000000000 --- a/examples/api/lib/widgets/linked_text/linked_text.1.dart +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -// This example demonstrates highlighting and linking Twitter handles. - -void main() { - runApp(const LinkedTextApp()); -} - -class LinkedTextApp extends StatelessWidget { - const LinkedTextApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: MyHomePage(title: 'Flutter Link Twitter Handle Demo'), - ); - } -} - -class MyHomePage extends StatelessWidget { - MyHomePage({ - super.key, - required this.title - }); - - final String title; - static const String _text = 'Please check out @FlutterDev on Twitter for the latest.'; - - void _handleTapTwitterHandle(BuildContext context, String linkText) { - final String handleWithoutAt = linkText.substring(1); - final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; - final Uri? uri = Uri.tryParse(twitterUriString); - if (uri == null) { - throw Exception('Failed to parse $twitterUriString.'); - } - - // A package like url_launcher would be useful for actually opening the URL - // here instead of just showing a dialog. - Navigator.of(context).push( - DialogRoute( - context: context, - builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), - ), - ); - } - - final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: Builder( - builder: (BuildContext context) { - return SelectionArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - LinkedText.regExp( - text: _text, - regExp: _twitterHandleRegExp, - onTap: (String twitterHandleString) => _handleTapTwitterHandle(context, twitterHandleString), - ), - ], - ), - ); - }, - ), - ), - ); - } -} diff --git a/examples/api/lib/widgets/linked_text/linked_text.2.dart b/examples/api/lib/widgets/linked_text/linked_text.2.dart deleted file mode 100644 index a19a07e4d85e6..0000000000000 --- a/examples/api/lib/widgets/linked_text/linked_text.2.dart +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -// This example demonstrates highlighting URLs in a TextSpan tree instead of a -// flat String. - -void main() { - runApp(const LinkedTextApp()); -} - -class LinkedTextApp extends StatelessWidget { - const LinkedTextApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter LinkedText.spans Demo'), - ); - } -} - -class MyHomePage extends StatelessWidget { - const MyHomePage({ - super.key, - required this.title, - }); - - final String title; - - void _onTapUri (BuildContext context, Uri uri) { - // A package like url_launcher would be useful for actually opening the URL - // here instead of just showing a dialog. - Navigator.of(context).push( - DialogRoute( - context: context, - builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: Builder( - builder: (BuildContext context) { - return SelectionArea( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - LinkedText( - onTapUri: (Uri uri) => _onTapUri(context, uri), - spans: [ - TextSpan( - text: 'Check out https://www.', - style: DefaultTextStyle.of(context).style, - children: const [ - TextSpan( - style: TextStyle( - fontWeight: FontWeight.w800, - ), - text: 'flutter', - ), - ], - ), - TextSpan( - text: '.dev!', - style: DefaultTextStyle.of(context).style, - ), - ], - ), - ], - ), - ); - }, - ), - ), - ); - } -} diff --git a/examples/api/lib/widgets/linked_text/linked_text.3.dart b/examples/api/lib/widgets/linked_text/linked_text.3.dart deleted file mode 100644 index 72db9ec91358e..0000000000000 --- a/examples/api/lib/widgets/linked_text/linked_text.3.dart +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; - -// This example demonstrates highlighting both URLs and Twitter handles with -// different actions and different styles. - -void main() { - runApp(const LinkedTextApp()); -} - -class LinkedTextApp extends StatelessWidget { - const LinkedTextApp({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - primarySwatch: Colors.blue, - ), - home: const MyHomePage(title: 'Flutter Link Twitter Handle Demo'), - ); - } -} - -class MyHomePage extends StatelessWidget { - const MyHomePage({ - super.key, - required this.title - }); - - final String title; - static const String _text = '@FlutterDev is our Twitter account, or find us at www.flutter.dev'; - - void _handleTapTwitterHandle(BuildContext context, String linkText) { - final String handleWithoutAt = linkText.substring(1); - final String twitterUriString = 'https://www.twitter.com/$handleWithoutAt'; - final Uri? uri = Uri.tryParse(twitterUriString); - if (uri == null) { - throw Exception('Failed to parse $twitterUriString.'); - } - _showDialog(context, uri); - } - - void _handleTapUrl(BuildContext context, String urlText) { - final Uri? uri = Uri.tryParse(urlText); - if (uri == null) { - throw Exception('Failed to parse $urlText.'); - } - _showDialog(context, uri); - } - - void _showDialog(BuildContext context, Uri uri) { - // A package like url_launcher would be useful for actually opening the URL - // here instead of just showing a dialog. - Navigator.of(context).push( - DialogRoute( - context: context, - builder: (BuildContext context) => AlertDialog(title: Text('You tapped: $uri')), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(title), - ), - body: Center( - child: Builder( - builder: (BuildContext context) { - return SelectionArea( - child: _TwitterAndUrlLinkedText( - text: _text, - onTapUrl: (String urlString) => _handleTapUrl(context, urlString), - onTapTwitterHandle: (String handleString) => _handleTapTwitterHandle(context, handleString), - ), - ); - }, - ), - ), - ); - } -} - -class _TwitterAndUrlLinkedText extends StatefulWidget { - const _TwitterAndUrlLinkedText({ - required this.text, - required this.onTapUrl, - required this.onTapTwitterHandle, - }); - - final String text; - final ValueChanged onTapUrl; - final ValueChanged onTapTwitterHandle; - - @override - State<_TwitterAndUrlLinkedText> createState() => _TwitterAndUrlLinkedTextState(); -} - -class _TwitterAndUrlLinkedTextState extends State<_TwitterAndUrlLinkedText> { - final List _recognizers = []; - late final List _textLinkers; - - final RegExp _twitterHandleRegExp = RegExp(r'@[a-zA-Z0-9]{4,15}'); - - void _disposeRecognizers() { - for (final GestureRecognizer recognizer in _recognizers) { - recognizer.dispose(); - } - _recognizers.clear(); - } - - @override - void initState() { - super.initState(); - - _textLinkers = [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayText, String linkText) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () => widget.onTapUrl(linkText); - _recognizers.add(recognizer); - return _MyInlineLinkSpan( - text: displayText, - color: const Color(0xff0000ee), - recognizer: recognizer, - ); - }, - ), - TextLinker( - regExp: _twitterHandleRegExp, - linkBuilder: (String displayText, String linkText) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () => widget.onTapTwitterHandle(linkText); - _recognizers.add(recognizer); - return _MyInlineLinkSpan( - text: displayText, - color: const Color(0xff00aaaa), - recognizer: recognizer, - ); - }, - ), - ]; - } - - @override - void dispose() { - _disposeRecognizers(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return LinkedText.textLinkers( - text: widget.text, - textLinkers: _textLinkers, - ); - } -} - -class _MyInlineLinkSpan extends TextSpan { - _MyInlineLinkSpan({ - required String text, - required Color color, - required super.recognizer, - }) : super( - style: TextStyle( - color: color, - decorationColor: color, - decoration: TextDecoration.underline, - ), - mouseCursor: SystemMouseCursors.click, - text: text, - ); -} diff --git a/examples/api/test/painting/text_linker/text_linker.0_test.dart b/examples/api/test/painting/text_linker/text_linker.0_test.dart deleted file mode 100644 index a9ef1fe947a19..0000000000000 --- a/examples/api/test/painting/text_linker/text_linker.0_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/painting/text_linker/text_linker.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('can tap different link types with different results', (WidgetTester tester) async { - await tester.pumpWidget( - const example.TextLinkerApp(), - ); - - final Finder textFinder = find.descendant( - of: find.byType(SelectionArea), - matching: find.byType(Text), - ); - expect(textFinder, findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getTopLeft(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); - - await tester.tapAt(tester.getTopLeft(find.byType(Scaffold))); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getCenter(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: www.flutter.dev'), findsOneWidget); - }); -} diff --git a/examples/api/test/painting/text_linker/text_linker.1_test.dart b/examples/api/test/painting/text_linker/text_linker.1_test.dart deleted file mode 100644 index 3d32fe9fea155..0000000000000 --- a/examples/api/test/painting/text_linker/text_linker.1_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/painting/text_linker/text_linker.1.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('can tap different link types with different results', (WidgetTester tester) async { - await tester.pumpWidget( - const example.TextLinkerApp(), - ); - - final Finder textFinder = find.descendant( - of: find.byType(SelectionArea), - matching: find.byType(Text), - ); - expect(textFinder, findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getTopLeft(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); - - await tester.tapAt(tester.getTopLeft(find.byType(Scaffold))); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getCenter(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: www.flutter.dev'), findsOneWidget); - }); -} diff --git a/examples/api/test/widgets/linked_text/linked_text.0_test.dart b/examples/api/test/widgets/linked_text/linked_text.0_test.dart deleted file mode 100644 index d397d94f790d9..0000000000000 --- a/examples/api/test/widgets/linked_text/linked_text.0_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/widgets/linked_text/linked_text.0.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('tapping a link shows a dialog with the tapped uri', (WidgetTester tester) async { - await tester.pumpWidget( - const example.LinkedTextApp(), - ); - - final Finder textFinder = find.descendant( - of: find.byType(LinkedText), - matching: find.byType(RichText), - ); - expect(textFinder, findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getCenter(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: https://www.flutter.dev'), findsOneWidget); - }); -} diff --git a/examples/api/test/widgets/linked_text/linked_text.1_test.dart b/examples/api/test/widgets/linked_text/linked_text.1_test.dart deleted file mode 100644 index 7ba5b7ce945cd..0000000000000 --- a/examples/api/test/widgets/linked_text/linked_text.1_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/widgets/linked_text/linked_text.1.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('tapping a Twitter handle shows a dialog with the uri of the user', (WidgetTester tester) async { - await tester.pumpWidget( - const example.LinkedTextApp(), - ); - - final Finder textFinder = find.descendant( - of: find.byType(LinkedText), - matching: find.byType(RichText), - ); - expect(textFinder, findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getCenter(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); - }); -} diff --git a/examples/api/test/widgets/linked_text/linked_text.2_test.dart b/examples/api/test/widgets/linked_text/linked_text.2_test.dart deleted file mode 100644 index 1d5f97f90a4b7..0000000000000 --- a/examples/api/test/widgets/linked_text/linked_text.2_test.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/widgets/linked_text/linked_text.2.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('can tap links generated from TextSpans', (WidgetTester tester) async { - await tester.pumpWidget( - const example.LinkedTextApp(), - ); - - final Finder textFinder = find.descendant( - of: find.byType(LinkedText), - matching: find.byType(RichText), - ); - expect(textFinder, findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getCenter(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: https://www.flutter.dev'), findsOneWidget); - }); -} diff --git a/examples/api/test/widgets/linked_text/linked_text.3_test.dart b/examples/api/test/widgets/linked_text/linked_text.3_test.dart deleted file mode 100644 index 4911cb8334110..0000000000000 --- a/examples/api/test/widgets/linked_text/linked_text.3_test.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_api_samples/widgets/linked_text/linked_text.3.dart' as example; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - testWidgets('can tap different link types with different results', (WidgetTester tester) async { - await tester.pumpWidget( - const example.LinkedTextApp(), - ); - - final Finder textFinder = find.descendant( - of: find.byType(SelectionArea), - matching: find.byType(Text), - ); - expect(textFinder, findsOneWidget); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getTopLeft(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: https://www.twitter.com/FlutterDev'), findsOneWidget); - - await tester.tapAt(tester.getTopLeft(find.byType(Scaffold))); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsNothing); - - await tester.tapAt(tester.getCenter(textFinder)); - await tester.pumpAndSettle(); - expect(find.byType(AlertDialog), findsOneWidget); - expect(find.text('You tapped: www.flutter.dev'), findsOneWidget); - }); -} diff --git a/packages/flutter/lib/painting.dart b/packages/flutter/lib/painting.dart index 952763378515e..2fa89c23cf8bc 100644 --- a/packages/flutter/lib/painting.dart +++ b/packages/flutter/lib/painting.dart @@ -59,7 +59,6 @@ export 'src/painting/shape_decoration.dart'; export 'src/painting/stadium_border.dart'; export 'src/painting/star_border.dart'; export 'src/painting/strut_style.dart'; -export 'src/painting/text_linker.dart'; export 'src/painting/text_painter.dart'; export 'src/painting/text_scaler.dart'; export 'src/painting/text_span.dart'; diff --git a/packages/flutter/lib/src/painting/text_linker.dart b/packages/flutter/lib/src/painting/text_linker.dart deleted file mode 100644 index 4684be30fb083..0000000000000 --- a/packages/flutter/lib/src/painting/text_linker.dart +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:math' as math; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; - -import 'inline_span.dart'; -import 'text_span.dart'; - -/// Signature for a function that builds an [InlineSpan] link. -/// -/// The link displays [displayString] and links to [linkString] when tapped. -/// These are distinct because sometimes a link may be split across multiple -/// [TextSpan]s. -/// -/// For example, consider the [TextSpan]s -/// `[TextSpan(text: 'http://'), TextSpan(text: 'google.com'), TextSpan(text: '/')]`. -/// This builder would be called three times, with the following parameters: -/// -/// 1. `displayString: 'http://', linkString: 'http://google.com/'` -/// 2. `displayString: 'google.com', linkString: 'http://google.com/'` -/// 3. `displayString: '/', linkString: 'http://google.com/'` -/// -/// {@template flutter.painting.LinkBuilder.recognizer} -/// It's necessary for the owning widget to manage the lifecycle of any -/// [GestureRecognizer]s created in this function, such as for handling a tap on -/// the link. See [TextSpan.recognizer] for more. -/// {@endtemplate} -/// -/// {@tool dartpad} -/// This example shows how to use [TextLinker] to link both URLs and Twitter -/// handles in a [TextSpan] tree. It also illustrates the difference between -/// `displayString` and `linkString`. -/// -/// ** See code in examples/api/lib/painting/text_linker/text_linker.1.dart ** -/// {@end-tool} -typedef InlineLinkBuilder = InlineSpan Function( - String displayString, - String linkString, -); - -/// Specifies a way to find and style parts of some text. -/// -/// [TextLinker]s can be applied to some text using the [linkSpans] method. -/// -/// {@tool dartpad} -/// This example shows how to use [TextLinker] to link both URLs and Twitter -/// handles in the same text. -/// -/// ** See code in examples/api/lib/painting/text_linker/text_linker.0.dart ** -/// {@end-tool} -/// -/// {@tool dartpad} -/// This example shows how to use [TextLinker] to link both URLs and Twitter -/// handles in a [TextSpan] tree instead of a flat string. -/// -/// ** See code in examples/api/lib/painting/text_linker/text_linker.1.dart ** -/// {@end-tool} -/// -/// See also: -/// -/// * [LinkedText.textLinkers], which uses [TextLinker]s to allow full control -/// over matching and building different types of links. -/// * [LinkedText.new], which is simpler than using [TextLinker] and -/// automatically manages the lifecycle of any [GestureRecognizer]s. -class TextLinker { - /// Creates an instance of [TextLinker] with a [RegExp] and an [InlineLinkBuilder - /// [InlineLinkBuilder]. - /// - /// Does not manage the lifecycle of any [GestureRecognizer]s created in the - /// [InlineLinkBuilder], so it's the responsibility of the caller to do so. - /// See [TextSpan.recognizer] for more. - TextLinker({ - required this.regExp, - required this.linkBuilder, - }); - - /// Builds an [InlineSpan] to display the text that it's passed. - /// - /// {@macro flutter.painting.LinkBuilder.recognizer} - final InlineLinkBuilder linkBuilder; - - /// Matches text that should be turned into a link with [linkBuilder]. - final RegExp regExp; - - /// Applies the given [TextLinker]s to the given [InlineSpan]s and returns the - /// new resulting spans and any created [GestureRecognizer]s. - static Iterable linkSpans(Iterable spans, Iterable textLinkers) { - final _LinkedSpans linkedSpans = _LinkedSpans( - spans: spans, - textLinkers: textLinkers, - ); - return linkedSpans.linkedSpans; - } - - // Turns all matches from the regExp into a list of TextRanges. - static Iterable _textRangesFromText(String text, RegExp regExp) { - final Iterable matches = regExp.allMatches(text); - return matches.map((RegExpMatch match) { - return TextRange( - start: match.start, - end: match.end, - ); - }); - } - - /// Apply this [TextLinker] to a [String]. - Iterable<_TextLinkerMatch> _link(String text) { - final Iterable textRanges = _textRangesFromText(text, regExp); - return textRanges.map((TextRange textRange) { - return _TextLinkerMatch( - textRange: textRange, - linkBuilder: linkBuilder, - linkString: text.substring(textRange.start, textRange.end), - ); - }); - } - - @override - String toString() => '${objectRuntimeType(this, 'TextLinker')}($regExp)'; -} - -/// A matched replacement on some string. -/// -/// Produced by applying a [TextLinker]'s [RegExp] to a string. -class _TextLinkerMatch { - _TextLinkerMatch({ - required this.textRange, - required this.linkBuilder, - required this.linkString, - }) : assert(textRange.end - textRange.start == linkString.length); - - final InlineLinkBuilder linkBuilder; - final TextRange textRange; - - /// The string that [textRange] matches. - final String linkString; - - /// Get all [_TextLinkerMatch]s obtained from applying the given - /// `textLinker`s with the given `text`. - static List<_TextLinkerMatch> fromTextLinkers(Iterable textLinkers, String text) { - return textLinkers - .fold>( - <_TextLinkerMatch>[], - (List<_TextLinkerMatch> previousValue, TextLinker value) { - return previousValue..addAll(value._link(text)); - }); - } - - @override - String toString() => '${objectRuntimeType(this, '_TextLinkerMatch')}($textRange, $linkBuilder, $linkString)'; -} - -/// Used to cache information about a span's recursive text. -/// -/// Avoids repeatedly calling [TextSpan.toPlainText]. -class _TextCache { - factory _TextCache({ - required InlineSpan span, - }) { - if (span is! TextSpan) { - return _TextCache._( - text: '', - lengths: {span: 0}, - ); - } - - _TextCache childrenTextCache = _TextCache._empty(); - for (final InlineSpan child in span.children ?? []) { - final _TextCache childTextCache = _TextCache( - span: child, - ); - childrenTextCache = childrenTextCache._merge(childTextCache); - } - - final String text = (span.text ?? '') + childrenTextCache.text; - return _TextCache._( - text: text, - lengths: { - span: text.length, - ...childrenTextCache._lengths, - }, - ); - } - - factory _TextCache.fromMany({ - required Iterable spans, - }) { - _TextCache textCache = _TextCache._empty(); - for (final InlineSpan span in spans) { - final _TextCache spanTextCache = _TextCache( - span: span, - ); - textCache = textCache._merge(spanTextCache); - } - return textCache; - } - - _TextCache._empty( - ) : text = '', - _lengths = {}; - - const _TextCache._({ - required this.text, - required Map lengths, - }) : _lengths = lengths; - - /// The flattened text of all spans in the span tree. - final String text; - - /// A [Map] containing the lengths of all spans in the span tree. - /// - /// The length is defined as the length of the flattened text at the point in - /// the tree where the node resides. - /// - /// The length of [text] is the length of the root node in [_lengths]. - final Map _lengths; - - /// Merges the given _TextCache with this one by appending it to the end. - /// - /// Returns a new _TextCache and makes no modifications to either passed in. - _TextCache _merge(_TextCache other) { - return _TextCache._( - text: text + other.text, - lengths: Map.from(_lengths)..addAll(other._lengths), - ); - } - - int? getLength(InlineSpan span) => _lengths[span]; - - @override - String toString() => '${objectRuntimeType(this, '_TextCache')}($text, $_lengths)'; -} - -/// Signature for the output of linking an InlineSpan to some -/// _TextLinkerMatches. -typedef _LinkSpanRecursion = ( - /// The output of linking the input InlineSpan. - InlineSpan linkedSpan, - /// The provided _TextLinkerMatches, but with those completely used during - /// linking removed. - Iterable<_TextLinkerMatch> unusedTextLinkerMatches, -); - -/// Signature for the output of linking a List of InlineSpans to some -/// _TextLinkerMatches. -typedef _LinkSpansRecursion = ( - /// The output of linking the input InlineSpans. - Iterable linkedSpans, - /// The provided _TextLinkerMatches, but with those completely used during - /// linking removed. - Iterable<_TextLinkerMatch> unusedTextLinkerMatches, -); - -/// Applies some [TextLinker]s to some [InlineSpan]s and produces a new list of -/// [linkedSpans] as well as the [recognizers] created for each generated link. -class _LinkedSpans { - factory _LinkedSpans({ - required Iterable spans, - required Iterable textLinkers, - }) { - // Flatten the spans and store all string lengths, so that matches across - // span boundaries can be matched in the flat string. This is calculated - // once in the beginning to avoid recomputing. - final _TextCache textCache = _TextCache.fromMany(spans: spans); - - final Iterable<_TextLinkerMatch> textLinkerMatches = - _cleanTextLinkerMatches( - _TextLinkerMatch.fromTextLinkers(textLinkers, textCache.text), - ); - - final (Iterable linkedSpans, Iterable<_TextLinkerMatch> _) = - _linkSpansRecurse( - spans, - textCache, - textLinkerMatches, - ); - - return _LinkedSpans._( - linkedSpans: linkedSpans, - ); - } - - const _LinkedSpans._({ - required this.linkedSpans, - }); - - final Iterable linkedSpans; - - static List<_TextLinkerMatch> _cleanTextLinkerMatches(Iterable<_TextLinkerMatch> textLinkerMatches) { - final List<_TextLinkerMatch> nextTextLinkerMatches = textLinkerMatches.toList(); - - // Sort by start. - nextTextLinkerMatches.sort((_TextLinkerMatch a, _TextLinkerMatch b) { - return a.textRange.start.compareTo(b.textRange.start); - }); - - // Validate that there are no overlapping matches. - int lastEnd = 0; - for (final _TextLinkerMatch textLinkerMatch in nextTextLinkerMatches) { - if (textLinkerMatch.textRange.start < lastEnd) { - throw ArgumentError('Matches must not overlap. Overlapping text was "${textLinkerMatch.linkString}" located at ${textLinkerMatch.textRange.start}-${textLinkerMatch.textRange.end}.'); - } - lastEnd = textLinkerMatch.textRange.end; - } - - // Remove empty ranges. - nextTextLinkerMatches.removeWhere((_TextLinkerMatch textLinkerMatch) { - return textLinkerMatch.textRange.start == textLinkerMatch.textRange.end; - }); - - return nextTextLinkerMatches; - } - - // `index` is the index of the start of `span` in the overall flattened tree - // string. - static _LinkSpansRecursion _linkSpansRecurse(Iterable spans, _TextCache textCache, Iterable<_TextLinkerMatch> textLinkerMatches, [int index = 0]) { - final List output = []; - Iterable<_TextLinkerMatch> nextTextLinkerMatches = textLinkerMatches; - int nextIndex = index; - for (final InlineSpan span in spans) { - final (InlineSpan childSpan, Iterable<_TextLinkerMatch> childTextLinkerMatches) = _linkSpanRecurse( - span, - textCache, - nextTextLinkerMatches, - nextIndex, - ); - output.add(childSpan); - nextTextLinkerMatches = childTextLinkerMatches; - nextIndex += textCache.getLength(span)!; - } - - return (output, nextTextLinkerMatches); - } - - // `index` is the index of the start of `span` in the overall flattened tree - // string. - static _LinkSpanRecursion _linkSpanRecurse(InlineSpan span, _TextCache textCache, Iterable<_TextLinkerMatch> textLinkerMatches, [int index = 0]) { - if (span is! TextSpan) { - return (span, textLinkerMatches); - } - - final List nextChildren = []; - List<_TextLinkerMatch> nextTextLinkerMatches = <_TextLinkerMatch>[...textLinkerMatches]; - int lastLinkEnd = index; - if (span.text?.isNotEmpty ?? false) { - final int textEnd = index + span.text!.length; - for (final _TextLinkerMatch textLinkerMatch in textLinkerMatches) { - if (textLinkerMatch.textRange.start >= textEnd) { - // Because ranges is ordered, there are no more relevant ranges for this - // text. - break; - } - if (textLinkerMatch.textRange.end <= index) { - // This range ends before this span and is therefore irrelevant to it. - // It should have been removed from ranges. - assert(false, 'Invalid ranges.'); - nextTextLinkerMatches.removeAt(0); - continue; - } - if (textLinkerMatch.textRange.start > index) { - // Add the unlinked text before the range. - nextChildren.add(TextSpan( - text: span.text!.substring( - lastLinkEnd - index, - textLinkerMatch.textRange.start - index, - ), - )); - } - // Add the link itself. - final int linkStart = math.max(textLinkerMatch.textRange.start, index); - lastLinkEnd = math.min(textLinkerMatch.textRange.end, textEnd); - final InlineSpan nextChild = textLinkerMatch.linkBuilder( - span.text!.substring(linkStart - index, lastLinkEnd - index), - textLinkerMatch.linkString, - ); - nextChildren.add(nextChild); - if (textLinkerMatch.textRange.end > textEnd) { - // If we only partially used this range, keep it in nextRanges. Since - // overlapping ranges have been removed, this must be the last relevant - // range for this span. - break; - } - nextTextLinkerMatches.removeAt(0); - } - - // Add any extra text after any ranges. - final String remainingText = span.text!.substring(lastLinkEnd - index); - if (remainingText.isNotEmpty) { - nextChildren.add(TextSpan( - text: remainingText, - )); - } - } - - // Recurse on the children. - if (span.children?.isNotEmpty ?? false) { - final ( - Iterable childrenSpans, - Iterable<_TextLinkerMatch> childrenTextLinkerMatches, - ) = _linkSpansRecurse( - span.children!, - textCache, - nextTextLinkerMatches, - index + (span.text?.length ?? 0), - ); - nextTextLinkerMatches = childrenTextLinkerMatches.toList(); - nextChildren.addAll(childrenSpans); - } - - return ( - TextSpan( - style: span.style, - children: nextChildren, - ), - nextTextLinkerMatches, - ); - } -} diff --git a/packages/flutter/lib/src/widgets/linked_text.dart b/packages/flutter/lib/src/widgets/linked_text.dart deleted file mode 100644 index 9031adc0fc340..0000000000000 --- a/packages/flutter/lib/src/widgets/linked_text.dart +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; - -import 'basic.dart'; -import 'framework.dart'; -import 'text.dart'; - -/// Singature for a function that builds the [Widget] output by [LinkedText]. -/// -/// Typically a [Text.rich] containing a [TextSpan] whose children are the -/// [linkedSpans]. -typedef LinkedTextWidgetBuilder = Widget Function ( - BuildContext context, - Iterable linkedSpans, -); - -/// A widget that displays text with parts of it made interactive. -/// -/// By default, any URLs in the text are made interactive, and clicking one -/// calls the provided callback. -/// -/// Works with either a flat [String] (`text`) or a list of [InlineSpan]s -/// (`spans`). When using `spans`, only [TextSpan]s will be converted to links. -/// -/// {@tool dartpad} -/// This example shows how to create a [LinkedText] that turns URLs into -/// working links. -/// -/// ** See code in examples/api/lib/widgets/linked_text/linked_text.0.dart ** -/// {@end-tool} -/// -/// {@tool dartpad} -/// This example shows how to use [LinkedText] to link Twitter handles by -/// passing in a custom [RegExp]. -/// -/// ** See code in examples/api/lib/widgets/linked_text/linked_text.1.dart ** -/// {@end-tool} -/// -/// {@tool dartpad} -/// This example shows how to use [LinkedText] to link URLs in a TextSpan tree -/// instead of in a flat string. -/// -/// ** See code in examples/api/lib/widgets/linked_text/linked_text.2.dart ** -/// {@end-tool} -class LinkedText extends StatefulWidget { - /// Creates an instance of [LinkedText] from the given [text] or [spans], - /// turning any URLs into interactive links. - /// - /// See also: - /// - /// * [LinkedText.regExp], which matches based on any given [RegExp]. - /// * [LinkedText.textLinkers], which uses [TextLinker]s to allow full - /// control over matching and building different types of links. - LinkedText({ - super.key, - required ValueChanged onTapUri, - this.builder = _defaultBuilder, - List? spans, - String? text, - }) : assert((text == null) != (spans == null), 'Must specify exactly one to link: either text or spans.'), - spans = spans ?? [ - TextSpan( - text: text, - ), - ], - onTap = _getOnTap(onTapUri), - regExp = defaultUriRegExp, - textLinkers = null; - - /// Creates an instance of [LinkedText] from the given [text] or [spans], - /// turning anything matched by [regExp] into interactive links. - /// - /// {@tool dartpad} - /// This example shows how to use [LinkedText] to link Twitter handles by - /// passing in a custom [RegExp]. - /// - /// ** See code in examples/api/lib/widgets/linked_text/linked_text.1.dart ** - /// {@end-tool} - /// - /// See also: - /// - /// * [LinkedText.new], which matches [Uri]s. - /// * [LinkedText.textLinkers], which uses [TextLinker]s to allow full - /// control over matching and building different types of links. - LinkedText.regExp({ - super.key, - required this.onTap, - required this.regExp, - this.builder = _defaultBuilder, - List? spans, - String? text, - }) : assert((text == null) != (spans == null), 'Must specify exactly one to link: either text or spans.'), - spans = spans ?? [ - TextSpan( - text: text, - ), - ], - textLinkers = null; - - /// Creates an instance of [LinkedText] where the given [textLinkers] are - /// applied. - /// - /// Useful for independently matching different types of strings with - /// different behaviors. For example, highlighting both URLs and Twitter - /// handles with different style and/or behavior. - /// - /// {@tool dartpad} - /// This example shows how to use [LinkedText] to link both URLs and Twitter - /// handles in the same text. - /// - /// ** See code in examples/api/lib/widgets/linked_text/linked_text.3.dart ** - /// {@end-tool} - /// - /// See also: - /// - /// * [LinkedText.new], which matches [Uri]s. - /// * [LinkedText.regExp], which matches based on any given [RegExp]. - LinkedText.textLinkers({ - super.key, - this.builder = _defaultBuilder, - String? text, - List? spans, - required List textLinkers, - }) : assert((text == null) != (spans == null), 'Must specify exactly one to link: either text or spans.'), - assert(textLinkers.isNotEmpty), - textLinkers = textLinkers, // ignore: prefer_initializing_formals - spans = spans ?? [ - TextSpan( - text: text, - ), - ], - onTap = null, - regExp = null; - - /// The spans on which to create links. - /// - /// It's also possible to specify a plain string by using the `text` - /// parameter instead. - final List spans; - - /// Builds the [Widget] that is output by [LinkedText]. - /// - /// By default, builds a [Text.rich] with a single [TextSpan] whose children - /// are the linked [TextSpan]s, and whose style is [DefaultTextStyle]. - final LinkedTextWidgetBuilder builder; - - /// Handles tapping on a link. - /// - /// This is irrelevant when using [LinkedText.textLinkers], where this is - /// controlled with an [InlineLinkBuilder] instead. - final ValueChanged? onTap; - - /// Matches the text that should be turned into a link. - /// - /// This is irrelevant when using [LinkedText.textLinkers], where each - /// [TextLinker] specifies its own [TextLinker.regExp]. - /// - /// {@tool dartpad} - /// This example shows how to use [LinkedText] to link Twitter handles by - /// passing in a custom [RegExp]. - /// - /// ** See code in examples/api/lib/widgets/linked_text/linked_text.1.dart ** - /// {@end-tool} - final RegExp? regExp; - - /// Defines what parts of the text to match and how to link them. - /// - /// [TextLinker]s are applied in the order given. Overlapping matches are not - /// supported and will produce an error. - /// - /// {@tool dartpad} - /// This example shows how to use [LinkedText] to link both URLs and Twitter - /// handles in the same text with [TextLinker]s. - /// - /// ** See code in examples/api/lib/widgets/linked_text/linked_text.3.dart ** - /// {@end-tool} - final List? textLinkers; - - /// The default [RegExp], which matches [Uri]s by default. - /// - /// Matches with and without a host, but only "http" or "https". Ignores email - /// addresses. - static final RegExp defaultUriRegExp = RegExp(r'(? given a callback specifically for - /// tapping on a [Uri]. - static ValueChanged _getOnTap(ValueChanged onTapUri) { - return (String linkString) { - Uri uri = Uri.parse(linkString); - if (uri.host.isEmpty) { - // defaultUriRegExp matches Uris without a host, but packages like - // url_launcher require a host to launch a Uri. So add the host. - uri = Uri.parse('https://$linkString'); - } - onTapUri(uri); - }; - } - - /// The default value of [builder]. - /// - /// Builds a [Text.rich] with a single [TextSpan] whose children are the - /// linked [TextSpan]s, and whose style is [DefaultTextStyle]. If there are no - /// linked [TextSpan]s to display, builds a [SizedBox.shrink]. - static Widget _defaultBuilder(BuildContext context, Iterable linkedSpans) { - if (linkedSpans.isEmpty) { - return const SizedBox.shrink(); - } - - return Text.rich( - TextSpan( - style: DefaultTextStyle.of(context).style, - children: linkedSpans.toList(), - ), - ); - } - - /// The style used for the link by default if none is given. - @visibleForTesting - static TextStyle defaultLinkStyle = _InlineLinkSpan.defaultLinkStyle; - - @override - State createState() => _LinkedTextState(); -} - -class _LinkedTextState extends State { - final List _recognizers = []; - late Iterable _linkedSpans; - late final List _textLinkers; - - void _disposeRecognizers() { - for (final GestureRecognizer recognizer in _recognizers) { - recognizer.dispose(); - } - _recognizers.clear(); - } - - void _linkSpans() { - _disposeRecognizers(); - final Iterable linkedSpans = TextLinker.linkSpans( - widget.spans, - _textLinkers, - ); - _linkedSpans = linkedSpans; - } - - @override - void initState() { - super.initState(); - _textLinkers = widget.textLinkers ?? [ - TextLinker( - regExp: widget.regExp ?? LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () => widget.onTap!(linkString); - // Keep track of created recognizers so that they can be disposed. - _recognizers.add(recognizer); - return _InlineLinkSpan( - recognizer: recognizer, - style: LinkedText.defaultLinkStyle, - text: displayString, - ); - }, - ), - ]; - _linkSpans(); - } - - @override - void didUpdateWidget(LinkedText oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget.spans != oldWidget.spans || widget.textLinkers != oldWidget.textLinkers) { - _linkSpans(); - } - } - - @override - void dispose() { - _disposeRecognizers(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return widget.builder(context, _linkedSpans); - } -} - -/// An inline, interactive text link. -/// -/// See also: -/// -/// * [LinkedText], which creates links with this class by default. -class _InlineLinkSpan extends TextSpan { - /// Create an instance of [_InlineLinkSpan]. - _InlineLinkSpan({ - required String text, - TextStyle? style, - super.recognizer, - }) : super( - style: style ?? defaultLinkStyle, - mouseCursor: SystemMouseCursors.click, - text: text, - ); - - static Color get _linkColor { - return switch (defaultTargetPlatform) { - // This value was taken from Safari on an iPhone 14 Pro iOS 16.4 - // simulator. - TargetPlatform.iOS => const Color(0xff1717f0), - // This value was taken from Chrome on macOS 13.4.1. - TargetPlatform.macOS => const Color(0xff0000ee), - // This value was taken from Chrome on Android 14. - TargetPlatform.android || TargetPlatform.fuchsia => const Color(0xff0e0eef), - // This value was taken from the Chrome browser running on GNOME 43.3 on - // Debian. - TargetPlatform.linux => const Color(0xff0026e8), - // This value was taken from the Edge browser running on Windows 10. - TargetPlatform.windows => const Color(0xff1e2b8b), - }; - } - - /// The style used for the link by default if none is given. - @visibleForTesting - static TextStyle defaultLinkStyle = TextStyle( - color: _linkColor, - decorationColor: _linkColor, - decoration: TextDecoration.underline, - ); -} diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index 7c55f76192286..cc188608a8519 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -73,7 +73,6 @@ export 'src/widgets/inherited_theme.dart'; export 'src/widgets/interactive_viewer.dart'; export 'src/widgets/keyboard_listener.dart'; export 'src/widgets/layout_builder.dart'; -export 'src/widgets/linked_text.dart'; export 'src/widgets/list_wheel_scroll_view.dart'; export 'src/widgets/localizations.dart'; export 'src/widgets/lookup_boundary.dart'; diff --git a/packages/flutter/test/painting/text_linker_test.dart b/packages/flutter/test/painting/text_linker_test.dart deleted file mode 100644 index aee0a5fea1659..0000000000000 --- a/packages/flutter/test/painting/text_linker_test.dart +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - final RegExp hashTagRegExp = RegExp(r'#[a-zA-Z0-9]*'); - final RegExp urlRegExp = RegExp(r'(?[ - 'https://www.example.com', - 'www.example123.co.uk', - 'subdomain.example.net', - 'ftp.subdomain.example.net', - 'http://subdomain.example.net', - 'https://subdomain.example.net', - 'http://example.com/', - 'https://www.example.org/', - 'ftp.subdomain.example.net', - 'example.com', - 'subdomain.example.io', - 'www.example123.co.uk', - 'http://example.com:8080/', - 'https://www.example.com/path/to/resource', - 'http://www.example.com/index.php?query=test#fragment', - 'https://subdomain.example.io:8443/resource/file.html?search=query#result', - 'example.com', - 'subsub.www.example.com', - 'https://subsub.www.example.com' - ]) { - test('converts the valid url $text to a link by default', () { - final Iterable linkedSpans = TextLinker.linkSpans( - [ - TextSpan( - text: text, - ), - ], - [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - ); - }, - ), - ], - ); - - expect(linkedSpans, hasLength(1)); - expect(linkedSpans.first, isA()); - - final TextSpan wrapperSpan = linkedSpans.first as TextSpan; - expect(wrapperSpan.text, isNull); - expect(wrapperSpan.children, hasLength(1)); - - final TextSpan span = wrapperSpan.children!.first as TextSpan; - - expect(span.text, text); - expect(span.style, LinkedText.defaultLinkStyle); - expect(span.children, isNull); - }); - } - - for (final String text in [ - 'abcd://subdomain.example.net', - 'ftp://subdomain.example.net', - ]) { - test('does nothing to the invalid url $text', () { - final Iterable linkedSpans = TextLinker.linkSpans( - [ - TextSpan( - text: text, - ), - ], - [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - return TextSpan( - text: displayString, - ); - }, - ), - ], - ); - - expect(linkedSpans, hasLength(1)); - expect(linkedSpans.first, isA()); - - final TextSpan wrapperSpan = linkedSpans.first as TextSpan; - expect(wrapperSpan.text, isNull); - expect(wrapperSpan.children, hasLength(1)); - - final TextSpan span = wrapperSpan.children!.first as TextSpan; - - expect(span.text, text); - expect(span.style, isNull); - expect(span.children, isNull); - }); - } - - for (final String text in [ - '"example.com"', - "'example.com'", - '(example.com)', - ]) { - test('can parse url $text with leading and trailing characters', () { - final Iterable linkedSpans = TextLinker.linkSpans( - [ - TextSpan( - text: text, - ), - ], - [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - ); - }, - ), - ], - ); - - expect(linkedSpans, hasLength(1)); - expect(linkedSpans.first, isA()); - - final TextSpan wrapperSpan = linkedSpans.first as TextSpan; - expect(wrapperSpan.text, isNull); - expect(wrapperSpan.children, hasLength(3)); - - expect(wrapperSpan.children!.first, isA()); - final TextSpan leadingSpan = wrapperSpan.children!.first as TextSpan; - expect(leadingSpan.text, hasLength(1)); - expect(leadingSpan.style, isNull); - expect(leadingSpan.children, isNull); - - expect(wrapperSpan.children![1], isA()); - final TextSpan bodySpan = wrapperSpan.children![1] as TextSpan; - expect(bodySpan.text, 'example.com'); - expect(bodySpan.style, LinkedText.defaultLinkStyle); - expect(bodySpan.children, isNull); - - expect(wrapperSpan.children!.last, isA()); - final TextSpan trailingSpan = wrapperSpan.children!.last as TextSpan; - expect(trailingSpan.text, hasLength(1)); - expect(trailingSpan.style, isNull); - expect(trailingSpan.children, isNull); - }); - } - }); - - test('multiple TextLinkers', () { - final TextLinker urlTextLinker = TextLinker( - regExp: urlRegExp, - linkBuilder: (String displayString, String linkString) { - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - ); - }, - ); - final TextLinker hashTagTextLinker = TextLinker( - regExp: hashTagRegExp, - linkBuilder: (String displayString, String linkString) { - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - ); - }, - ); - final Iterable linkedSpans = TextLinker.linkSpans( - [ - const TextSpan( - text: 'Flutter is great #crossplatform #declarative check out flutter.dev.', - ), - ], - [urlTextLinker, hashTagTextLinker], - ); - - expect(linkedSpans, hasLength(1)); - expect(linkedSpans.first, isA()); - - final TextSpan wrapperSpan = linkedSpans.first as TextSpan; - expect(wrapperSpan.text, isNull); - expect(wrapperSpan.children, hasLength(7)); - - expect(wrapperSpan.children!.first, isA()); - final TextSpan textSpan1 = wrapperSpan.children!.first as TextSpan; - expect(textSpan1.text, 'Flutter is great '); - expect(textSpan1.style, isNull); - expect(textSpan1.children, isNull); - - expect(wrapperSpan.children![1], isA()); - final TextSpan hashTagSpan1 = wrapperSpan.children![1] as TextSpan; - expect(hashTagSpan1.text, '#crossplatform'); - expect(hashTagSpan1.style, LinkedText.defaultLinkStyle); - expect(hashTagSpan1.children, isNull); - - expect(wrapperSpan.children![2], isA()); - final TextSpan textSpan2 = wrapperSpan.children![2] as TextSpan; - expect(textSpan2.text, ' '); - expect(textSpan2.style, isNull); - expect(textSpan2.children, isNull); - - expect(wrapperSpan.children![3], isA()); - final TextSpan hashTagSpan2 = wrapperSpan.children![3] as TextSpan; - expect(hashTagSpan2.text, '#declarative'); - expect(hashTagSpan2.style, LinkedText.defaultLinkStyle); - expect(hashTagSpan2.children, isNull); - - expect(wrapperSpan.children![4], isA()); - final TextSpan textSpan3 = wrapperSpan.children![4] as TextSpan; - expect(textSpan3.text, ' check out '); - expect(textSpan3.style, isNull); - expect(textSpan3.children, isNull); - - expect(wrapperSpan.children![5], isA()); - final TextSpan urlSpan = wrapperSpan.children![5] as TextSpan; - expect(urlSpan.text, 'flutter.dev'); - expect(urlSpan.style, LinkedText.defaultLinkStyle); - expect(urlSpan.children, isNull); - - expect(wrapperSpan.children![6], isA()); - final TextSpan textSpan4 = wrapperSpan.children![6] as TextSpan; - expect(textSpan4.text, '.'); - expect(textSpan4.style, isNull); - expect(textSpan4.children, isNull); - }); - - test('complex span tree', () { - final Iterable linkedSpans = TextLinker.linkSpans( - const [ - TextSpan( - text: 'Check out https://www.', - children: [ - TextSpan( - style: TextStyle( - fontWeight: FontWeight.w800, - ), - text: 'flutter', - ), - ], - ), - TextSpan( - text: '.dev!', - ), - ], - [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - ); - }, - ), - ], - ); - - expect(linkedSpans, hasLength(2)); - - expect(linkedSpans.first, isA()); - final TextSpan span1 = linkedSpans.first as TextSpan; - expect(span1.text, isNull); - expect(span1.style, isNull); - expect(span1.children, hasLength(3)); - - // First span's children ('Check out https://www.flutter'). - expect(span1.children![0], isA()); - final TextSpan span1Child1 = span1.children![0] as TextSpan; - expect(span1Child1.text, 'Check out '); - expect(span1Child1.style, isNull); - expect(span1Child1.children, isNull); - - expect(span1.children![1], isA()); - final TextSpan span1Child2 = span1.children![1] as TextSpan; - expect(span1Child2.text, 'https://www.'); - expect(span1Child2.style, LinkedText.defaultLinkStyle); - expect(span1Child2.children, isNull); - - expect(span1.children![2], isA()); - final TextSpan span1Child3 = span1.children![2] as TextSpan; - expect(span1Child3.text, null); - expect(span1Child3.style, const TextStyle(fontWeight: FontWeight.w800)); - expect(span1Child3.children, hasLength(1)); - - expect(span1Child3.children![0], isA()); - final TextSpan span1Child3Child1 = span1Child3.children![0] as TextSpan; - expect(span1Child3Child1.text, 'flutter'); - expect(span1Child3Child1.style, LinkedText.defaultLinkStyle); - expect(span1Child3Child1.children, isNull); - - // Second span's children ('.dev!'). - expect(linkedSpans.elementAt(1), isA()); - final TextSpan span2 = linkedSpans.elementAt(1) as TextSpan; - expect(span2.text, isNull); - expect(span2.children, hasLength(2)); - expect(span2.style, isNull); - - expect(span2.children![0], isA()); - final TextSpan span2Child1 = span2.children![0] as TextSpan; - expect(span2Child1.text, '.dev'); - expect(span2Child1.style, LinkedText.defaultLinkStyle); - expect(span2Child1.children, isNull); - - expect(span2.children![1], isA()); - final TextSpan span2Child2 = span2.children![1] as TextSpan; - expect(span2Child2.text, '!'); - expect(span2Child2.children, isNull); - }); - }); -} diff --git a/packages/flutter/test/widgets/linked_text_test.dart b/packages/flutter/test/widgets/linked_text_test.dart deleted file mode 100644 index 9a1b2ab09c55d..0000000000000 --- a/packages/flutter/test/widgets/linked_text_test.dart +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - final RegExp hashTagRegExp = RegExp(r'#[a-zA-Z0-9]*'); - final RegExp urlRegExp = RegExp(r'(? recognizers = []; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (BuildContext context) { - return LinkedText.textLinkers( - textLinkers: [ - TextLinker( - regExp: hashTagRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () { - lastTappedLink = linkString; - }; - recognizers.add(recognizer); - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - recognizer: recognizer, - ); - }, - ), - ], - text: 'Flutter is great #crossplatform #declarative', - ); - }, - ), - ), - ), - ); - - expect(find.byType(RichText), findsOneWidget); - expect(lastTappedLink, isNull); - - await tester.tapAt(tester.getCenter(find.byType(RichText))); - expect(lastTappedLink, '#crossplatform'); - - expect(recognizers, hasLength(2)); - for (final TapGestureRecognizer recognizer in recognizers) { - recognizer.dispose(); - } - }); - - testWidgets('can link multiple different types', (WidgetTester tester) async { - String? lastTappedLink; - final List recognizers = []; - final TextLinker urlTextLinker = TextLinker( - regExp: urlRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () { - lastTappedLink = linkString; - }; - recognizers.add(recognizer); - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - recognizer: recognizer, - ); - }, - ); - final TextLinker hashTagTextLinker = TextLinker( - regExp: hashTagRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () { - lastTappedLink = linkString; - }; - recognizers.add(recognizer); - return TextSpan( - style: LinkedText.defaultLinkStyle, - text: displayString, - recognizer: recognizer, - ); - }, - ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (BuildContext context) { - return LinkedText.textLinkers( - textLinkers: [urlTextLinker, hashTagTextLinker], - text: 'flutter.dev is great #crossplatform #declarative', - ); - }, - ), - ), - ), - ); - - expect(find.byType(RichText), findsOneWidget); - expect(lastTappedLink, isNull); - - await tester.tapAt(tester.getTopLeft(find.byType(RichText))); - expect(lastTappedLink, 'flutter.dev'); - - await tester.tapAt(tester.getCenter(find.byType(RichText))); - expect(lastTappedLink, '#crossplatform'); - - expect(recognizers, hasLength(3)); - for (final TapGestureRecognizer recognizer in recognizers) { - recognizer.dispose(); - } - }); - - testWidgets('can customize linkBuilder', (WidgetTester tester) async { - String? lastTappedLink; - final List recognizers = []; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (BuildContext context) { - return LinkedText.textLinkers( - textLinkers: [ - TextLinker( - regExp: LinkedText.defaultUriRegExp, - linkBuilder: (String displayString, String linkString) { - final TapGestureRecognizer recognizer = TapGestureRecognizer() - ..onTap = () { - lastTappedLink = linkString; - }; - recognizers.add(recognizer); - return TextSpan( - recognizer: recognizer, - text: displayString, - mouseCursor: SystemMouseCursors.help, - ); - }, - ), - ], - text: 'Check out flutter.dev.', - ); - }, - ), - ), - ), - ); - - expect(find.byType(RichText), findsOneWidget); - expect(lastTappedLink, isNull); - - final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse, pointer: 1); - await gesture.addPointer(location: tester.getCenter(find.byType(Scaffold))); - await tester.pump(); - expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); - await gesture.moveTo(tester.getCenter(find.byType(RichText))); - expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.help); - - await tester.tapAt(tester.getCenter(find.byType(RichText))); - expect(lastTappedLink, 'flutter.dev'); - - expect(recognizers, hasLength(1)); - for (final TapGestureRecognizer recognizer in recognizers) { - recognizer.dispose(); - } - }); - - testWidgets('can take nested spans', (WidgetTester tester) async { - Uri? lastTappedUri; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (BuildContext context) { - return LinkedText( - onTapUri: (Uri uri) { - lastTappedUri = uri; - }, - spans: [ - TextSpan( - text: 'Check out fl', - style: DefaultTextStyle.of(context).style, - children: const [ - TextSpan( - text: 'u', - children: [ - TextSpan( - style: TextStyle( - fontWeight: FontWeight.w800, - ), - text: 'tt', - ), - TextSpan( - text: 'er', - ), - ], - ), - ], - ), - const TextSpan( - text: '.dev.', - ), - ], - ); - }, - ), - ), - ), - ); - - expect(find.byType(RichText), findsOneWidget); - expect(lastTappedUri, isNull); - - await tester.tapAt(tester.getCenter(find.byType(RichText))); - - // The https:// host is automatically added. - expect(lastTappedUri, Uri.parse('https://flutter.dev')); - }); - - testWidgets('can handle WidgetSpans', (WidgetTester tester) async { - Uri? lastTappedUri; - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (BuildContext context) { - return LinkedText( - onTapUri: (Uri uri) { - lastTappedUri = uri; - }, - spans: [ - TextSpan( - text: 'Check out fl', - style: DefaultTextStyle.of(context).style, - children: const [ - TextSpan( - text: 'u', - children: [ - TextSpan( - style: TextStyle( - fontWeight: FontWeight.w800, - ), - text: 'tt', - ), - WidgetSpan( - child: FlutterLogo(), - ), - TextSpan( - text: 'er', - ), - ], - ), - ], - ), - const TextSpan( - text: '.dev.', - ), - ], - ); - }, - ), - ), - ), - ); - - expect(find.byType(RichText), findsOneWidget); - expect(lastTappedUri, isNull); - - await tester.tapAt(tester.getCenter(find.byType(RichText))); - - // The WidgetSpan is ignored, so a link is still produced even though it has - // a FlutterLogo in the middle of it. - expect(lastTappedUri, Uri.parse('https://flutter.dev')); - }); - - testWidgets('builds the widget specified by builder', (WidgetTester tester) async { - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: Builder( - builder: (BuildContext context) { - return LinkedText( - onTapUri: (Uri uri) {}, - text: 'Check out flutter.dev.', - builder: (BuildContext context, Iterable linkedSpans) { - return RichText( - textAlign: TextAlign.center, - text: TextSpan( - children: linkedSpans.toList(), - ), - ); - }, - ); - }, - ), - ), - ), - ); - - expect(find.byType(RichText), findsOneWidget); - final RichText richText = tester.widget(find.byType(RichText)); - expect(richText.textAlign, TextAlign.center); - }); -} From abf8361ad487828e40ee2bae969a0131c8b43260 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Mon, 18 Sep 2023 14:55:06 -0500 Subject: [PATCH 1323/1547] Don't uninstall before retrying to connect during app launch (#134542) When retrying to connect to the device during app launch, don't uninstall the app first. Latest test flake for https://github.com/flutter/flutter/issues/120808: https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8770202475999850785/+/u/run_hot_mode_dev_cycle_ios__benchmark/test_stdout Shows that it uninstalled and then tried debugging and failed, which would make sense since the app wasn't installed anymore. ``` [2023-09-11 18:02:24.555646] [STDOUT] stdout: [ +6 ms] Lost connection to device. Trying to connect again... [2023-09-11 18:02:24.556949] [STDOUT] stdout: [ +1 ms] executing: /opt/s/w/ir/x/w/recipe_cleanup/tmp53fs1szo/flutter sdk/bin/cache/artifacts/libimobiledevice/idevicesyslog -u 00008030-00144DA10185402E [2023-09-11 18:02:24.557323] [STDOUT] stdout: [ ] executing: script -t 0 /dev/null /opt/s/w/ir/x/w/recipe_cleanup/tmp53fs1szo/flutter sdk/bin/cache/artifacts/ios-deploy/ios-deploy --id 00008030-00144DA10185402E --bundle build/ios/iphoneos/Flutter Gallery.app --app_deltas build/ios/app-delta --uninstall --noinstall --debug --no-wifi --args --enable-dart-profiling --disable-vm-service-publication --enable-checked-mode --verify-entry-points [2023-09-11 18:02:24.578010] [STDOUT] stdout: [ +20 ms] [....] Waiting for iOS device to be connected [2023-09-11 18:02:24.712631] [STDOUT] stdout: [ +134 ms] [....] Using 00008030-00144DA10185402E (N104AP, iPhone 11, iphoneos, arm64e, 16.2, 20C65) a.k.a. 'iPhone 11'. [2023-09-11 18:02:24.712725] [STDOUT] stdout: [ ] ------ Uninstall phase ------ [2023-09-11 18:02:24.818293] [STDOUT] stdout: [ +105 ms] [ OK ] Uninstalled package with bundle id io.flutter.examples.gallery [2023-09-11 18:02:24.906833] [STDOUT] stdout: [ +88 ms] ------ Debug phase ------ [2023-09-11 18:02:24.906924] [STDOUT] stdout: [ ] Starting debug of 00008030-00144DA10185402E (N104AP, iPhone 11, iphoneos, arm64e, 16.2, 20C65) a.k.a. 'iPhone 11' connected through USB... [2023-09-11 18:02:25.285252] [STDOUT] stdout: [ +378 ms] [ 0%] Looking up developer disk image [2023-09-11 18:02:25.529937] [STDOUT] stdout: [ +244 ms] [ 90%] Mounting developer disk image [2023-09-11 18:02:25.545261] [STDOUT] stdout: [ +15 ms] [ 95%] Developer disk image already mounted [2023-09-11 18:02:25.587923] [STDOUT] stdout: [ +42 ms] Detected path to iOS debug symbols: "Symbol Path: /Users/swarming/Library/Developer/Xcode/iOS DeviceSupport/16.2 (20C65) arm64e/Symbols" [2023-09-11 18:02:25.857177] [STDOUT] stdout: [ +269 ms] Script started, output file is /dev/null [2023-09-11 18:02:25.857259] [STDOUT] stdout: [ ] Script done, output file is /dev/null [2023-09-11 18:02:25.857511] [STDOUT] stdout: [ ] ios-deploy exited with code 0 [2023-09-11 18:02:25.858066] [STDOUT] stderr: [ ] Could not run build/ios/iphoneos/Flutter Gallery.app on 00008030-00144DA10185402E. [2023-09-11 18:02:25.858130] [STDOUT] stderr: [ ] Try launching Xcode and selecting "Product > Run" to fix the problem: [2023-09-11 18:02:25.858214] [STDOUT] stderr: [ ] open ios/Runner.xcworkspace [2023-09-11 18:02:25.858537] [STDOUT] stdout: [ ] Installing and launching... (completed in 52.4s) [2023-09-11 18:02:25.858956] [STDOUT] stderr: [ ] Error launching application on iPhone 11. ``` --- packages/flutter_tools/lib/src/ios/devices.dart | 5 ++++- .../general.shard/ios/ios_device_start_prebuilt_test.dart | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index e7133b0ad3228..6be9ed3ca52ab 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -543,6 +543,7 @@ class IOSDevice extends Device { debuggingOptions: debuggingOptions, launchArguments: launchArguments, ipv6: ipv6, + uninstallFirst: debuggingOptions.uninstallFirst, ); } @@ -695,6 +696,7 @@ class IOSDevice extends Device { debuggingOptions: debuggingOptions, launchArguments: launchArguments, ipv6: ipv6, + uninstallFirst: false, skipInstall: true, ); installationResult = await iosDeployDebugger!.launchAndAttach() ? 0 : 1; @@ -737,6 +739,7 @@ class IOSDevice extends Device { required DebuggingOptions debuggingOptions, required List launchArguments, required bool ipv6, + required bool uninstallFirst, bool skipInstall = false, }) { final DeviceLogReader deviceLogReader = getLogReader( @@ -753,7 +756,7 @@ class IOSDevice extends Device { appDeltaDirectory: package.appDeltaDirectory, launchArguments: launchArguments, interfaceType: connectionInterface, - uninstallFirst: debuggingOptions.uninstallFirst, + uninstallFirst: uninstallFirst, skipInstall: skipInstall, ); if (deviceLogReader is IOSDeviceLogReader) { diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index f163f32e2fa77..d0aa1ab6e0ad6 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -75,6 +75,7 @@ FakeCommand attachDebuggerCommand({ String stdout = '(lldb) run\nsuccess', Completer? completer, bool isWirelessDevice = false, + bool uninstallFirst = false, bool skipInstall = false, }) { return FakeCommand( @@ -88,6 +89,8 @@ FakeCommand attachDebuggerCommand({ '123', '--bundle', '/', + if (uninstallFirst) + '--uninstall', if (skipInstall) '--noinstall', '--debug', @@ -349,6 +352,7 @@ void main() { final FakeProcessManager processManager = FakeProcessManager.list([ attachDebuggerCommand( stdout: '(lldb) run\nsuccess\nProcess 525 exited with status = -1 (0xffffffff) lost connection', + uninstallFirst: true, ), attachDebuggerCommand( stdout: '(lldb) run\nsuccess\nThe Dart VM service is listening on http://127.0.0.1:456', @@ -375,6 +379,7 @@ void main() { debuggingOptions: DebuggingOptions.enabled( BuildInfo.debug, usingCISystem: true, + uninstallFirst: true, ), platformArgs: {}, ); From 56cbf3e1d9b373dc70099c96c09e4133f36a332f Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi Date: Mon, 18 Sep 2023 22:44:55 +0200 Subject: [PATCH 1324/1547] Cover more test/widgets tests with leak tracking #5 (#134869) --- .../test/material/filled_button_test.dart | 4 +- .../flutter/test/material/snack_bar_test.dart | 1 - .../flutter/test/widgets/listener_test.dart | 35 ++++-- .../widgets/listview_end_append_test.dart | 5 +- .../test/widgets/localizations_test.dart | 7 +- .../test/widgets/lookup_boundary_test.dart | 85 +++++++------- .../flutter/test/widgets/magnifier_test.dart | 12 +- .../test/widgets/mark_needs_build_test.dart | 3 +- .../test/widgets/media_query_test.dart | 65 +++++------ .../test/widgets/modal_barrier_test.dart | 68 ++++++------ .../test/widgets/mouse_region_test.dart | 104 ++++++++++-------- .../test/widgets/multi_view_binding_test.dart | 5 +- .../widgets/multi_view_tree_updates_test.dart | 7 +- .../flutter/test/widgets/multichild_test.dart | 7 +- .../multichildobject_with_keys_test.dart | 7 +- .../widgets/navigator_and_layers_test.dart | 3 +- .../widgets/navigator_replacement_test.dart | 11 +- .../widgets/navigator_restoration_test.dart | 61 +++++----- 18 files changed, 263 insertions(+), 227 deletions(-) diff --git a/packages/flutter/test/material/filled_button_test.dart b/packages/flutter/test/material/filled_button_test.dart index 5c71f5395f105..58cfd9c7ae129 100644 --- a/packages/flutter/test/material/filled_button_test.dart +++ b/packages/flutter/test/material/filled_button_test.dart @@ -1976,9 +1976,7 @@ void main() { ); expect(controller.value, {MaterialState.disabled}); expect(count, 1); - }, - leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed(), - ); + }); } diff --git a/packages/flutter/test/material/snack_bar_test.dart b/packages/flutter/test/material/snack_bar_test.dart index bf7e4fe7b9fbd..4f32a0790771d 100644 --- a/packages/flutter/test/material/snack_bar_test.dart +++ b/packages/flutter/test/material/snack_bar_test.dart @@ -2544,7 +2544,6 @@ void main() { }); testWidgetsWithLeakTracking('Should have only one SnackBar during back swipe navigation', - leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed(), (WidgetTester tester) async { const String snackBarText = 'hello snackbar'; const Key snackTarget = Key('snack-target'); diff --git a/packages/flutter/test/widgets/listener_test.dart b/packages/flutter/test/widgets/listener_test.dart index f1f8686cc26d4..64daf2e4bb981 100644 --- a/packages/flutter/test/widgets/listener_test.dart +++ b/packages/flutter/test/widgets/listener_test.dart @@ -8,11 +8,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'gesture_utils.dart'; void main() { - testWidgets('Events bubble up the tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Events bubble up the tree', (WidgetTester tester) async { final List log = []; await tester.pumpWidget( @@ -46,7 +47,7 @@ void main() { ])); }); - testWidgets('Detects hover events from touch devices', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Detects hover events from touch devices', (WidgetTester tester) async { final List log = []; await tester.pumpWidget( @@ -74,7 +75,7 @@ void main() { }); group('transformed events', () { - testWidgets('simple offset for touch/signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('simple offset for touch/signal', (WidgetTester tester) async { final List events = []; final Key key = UniqueKey(); @@ -145,7 +146,7 @@ void main() { expect(events.single.transform, expectedTransform); }); - testWidgets('scaled for touch/signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scaled for touch/signal', (WidgetTester tester) async { final List events = []; final Key key = UniqueKey(); @@ -222,7 +223,7 @@ void main() { expect(events.single.transform, expectedTransform); }); - testWidgets('scaled and offset for touch/signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scaled and offset for touch/signal', (WidgetTester tester) async { final List events = []; final Key key = UniqueKey(); @@ -300,7 +301,7 @@ void main() { expect(events.single.transform, expectedTransform); }); - testWidgets('rotated for touch/signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('rotated for touch/signal', (WidgetTester tester) async { final List events = []; final Key key = UniqueKey(); @@ -378,9 +379,12 @@ void main() { }); }); - testWidgets("RenderPointerListener's debugFillProperties when default", (WidgetTester tester) async { + testWidgetsWithLeakTracking("RenderPointerListener's debugFillProperties when default", (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - RenderPointerListener().debugFillProperties(builder); + final RenderPointerListener renderListener = RenderPointerListener(); + addTearDown(renderListener.dispose); + + renderListener.debugFillProperties(builder); final List description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) @@ -396,9 +400,13 @@ void main() { ]); }); - testWidgets("RenderPointerListener's debugFillProperties when full", (WidgetTester tester) async { + testWidgetsWithLeakTracking("RenderPointerListener's debugFillProperties when full", (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - RenderPointerListener( + + final RenderErrorBox renderErrorBox = RenderErrorBox(); + addTearDown(() => renderErrorBox.dispose()); + + final RenderPointerListener renderListener = RenderPointerListener( onPointerDown: (PointerDownEvent event) {}, onPointerUp: (PointerUpEvent event) {}, onPointerMove: (PointerMoveEvent event) {}, @@ -406,8 +414,11 @@ void main() { onPointerCancel: (PointerCancelEvent event) {}, onPointerSignal: (PointerSignalEvent event) {}, behavior: HitTestBehavior.opaque, - child: RenderErrorBox(), - ).debugFillProperties(builder); + child: renderErrorBox, + ); + addTearDown(renderListener.dispose); + + renderListener.debugFillProperties(builder); final List description = builder.properties .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) diff --git a/packages/flutter/test/widgets/listview_end_append_test.dart b/packages/flutter/test/widgets/listview_end_append_test.dart index 6d587828fd9ec..1e1cf76869baf 100644 --- a/packages/flutter/test/widgets/listview_end_append_test.dart +++ b/packages/flutter/test/widgets/listview_end_append_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('ListView.builder() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/9506 Widget buildFrame(int itemCount) { @@ -35,7 +36,7 @@ void main() { expect(find.text('item 3'), findsOneWidget); }); - testWidgets('ListView.builder() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/9506 Widget buildFrame(int itemCount) { diff --git a/packages/flutter/test/widgets/localizations_test.dart b/packages/flutter/test/widgets/localizations_test.dart index ff96e095faf5e..213fe955f5955 100644 --- a/packages/flutter/test/widgets/localizations_test.dart +++ b/packages/flutter/test/widgets/localizations_test.dart @@ -6,11 +6,12 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { final TestAutomatedTestWidgetsFlutterBinding binding = TestAutomatedTestWidgetsFlutterBinding(); - testWidgets('Locale is available when Localizations widget stops deferring frames', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Locale is available when Localizations widget stops deferring frames', (WidgetTester tester) async { final FakeLocalizationsDelegate delegate = FakeLocalizationsDelegate(); await tester.pumpWidget(Localizations( locale: const Locale('fo'), @@ -37,7 +38,7 @@ void main() { expect(find.text('loaded'), findsOneWidget); }); - testWidgets('Localizations.localeOf throws when no localizations exist', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Localizations.localeOf throws when no localizations exist', (WidgetTester tester) async { final GlobalKey contextKey = GlobalKey(debugLabel: 'Test Key'); await tester.pumpWidget(Container(key: contextKey)); @@ -48,7 +49,7 @@ void main() { ))); }); - testWidgets('Localizations.maybeLocaleOf returns null when no localizations exist', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Localizations.maybeLocaleOf returns null when no localizations exist', (WidgetTester tester) async { final GlobalKey contextKey = GlobalKey(debugLabel: 'Test Key'); await tester.pumpWidget(Container(key: contextKey)); diff --git a/packages/flutter/test/widgets/lookup_boundary_test.dart b/packages/flutter/test/widgets/lookup_boundary_test.dart index 36d2d3b310b7c..d1af4fa09a731 100644 --- a/packages/flutter/test/widgets/lookup_boundary_test.dart +++ b/packages/flutter/test/widgets/lookup_boundary_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('LookupBoundary.dependOnInheritedWidgetOfExactType', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { InheritedWidget? containerThroughBoundary; InheritedWidget? containerStoppedAtBoundary; @@ -32,7 +33,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('ignores ancestor boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores ancestor boundary', (WidgetTester tester) async { InheritedWidget? inheritedWidget; final Key inheritedKey = UniqueKey(); @@ -53,7 +54,7 @@ void main() { expect(inheritedWidget, equals(tester.widget(find.byKey(inheritedKey)))); }); - testWidgets('finds widget before boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('finds widget before boundary', (WidgetTester tester) async { InheritedWidget? containerThroughBoundary; InheritedWidget? containerStoppedAtBoundary; @@ -80,7 +81,7 @@ void main() { expect(containerStoppedAtBoundary, equals(tester.widget(find.byKey(inheritedKey)))); }); - testWidgets('creates dependency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('creates dependency', (WidgetTester tester) async { MyInheritedWidget? inheritedWidget; final Widget widgetTree = DidChangeDependencySpy( @@ -108,7 +109,7 @@ void main() { expect(tester.state<_DidChangeDependencySpyState>(find.byType(DidChangeDependencySpy)).didChangeDependenciesCount, 2); }); - testWidgets('causes didChangeDependencies to be called on move even if dependency was not fulfilled due to boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('causes didChangeDependencies to be called on move even if dependency was not fulfilled due to boundary', (WidgetTester tester) async { MyInheritedWidget? inheritedWidget; final Key globalKey = GlobalKey(); @@ -173,7 +174,7 @@ void main() { expect(tester.state<_DidChangeDependencySpyState>(find.byType(DidChangeDependencySpy)).didChangeDependenciesCount, 3); }); - testWidgets('causes didChangeDependencies to be called on move even if dependency was non-existant', (WidgetTester tester) async { + testWidgetsWithLeakTracking('causes didChangeDependencies to be called on move even if dependency was non-existant', (WidgetTester tester) async { MyInheritedWidget? inheritedWidget; final Key globalKey = GlobalKey(); @@ -212,7 +213,7 @@ void main() { }); group('LookupBoundary.getElementForInheritedWidgetOfExactType', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { InheritedElement? containerThroughBoundary; InheritedElement? containerStoppedAtBoundary; @@ -236,7 +237,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('ignores ancestor boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores ancestor boundary', (WidgetTester tester) async { InheritedElement? inheritedWidget; final Key inheritedKey = UniqueKey(); @@ -257,7 +258,7 @@ void main() { expect(inheritedWidget, equals(tester.element(find.byKey(inheritedKey)))); }); - testWidgets('finds widget before boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('finds widget before boundary', (WidgetTester tester) async { InheritedElement? containerThroughBoundary; InheritedElement? containerStoppedAtBoundary; @@ -284,7 +285,7 @@ void main() { expect(containerStoppedAtBoundary, equals(tester.element(find.byKey(inheritedKey)))); }); - testWidgets('does not creates dependency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not creates dependency', (WidgetTester tester) async { final Widget widgetTree = DidChangeDependencySpy( onDidChangeDependencies: (BuildContext context) { @@ -309,7 +310,7 @@ void main() { expect(tester.state<_DidChangeDependencySpyState>(find.byType(DidChangeDependencySpy)).didChangeDependenciesCount, 1); }); - testWidgets('does not cause didChangeDependencies to be called on move when found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not cause didChangeDependencies to be called on move when found', (WidgetTester tester) async { final Key globalKey = GlobalKey(); final Widget widgetTree = DidChangeDependencySpy( @@ -369,7 +370,7 @@ void main() { expect(tester.state<_DidChangeDependencySpyState>(find.byType(DidChangeDependencySpy)).didChangeDependenciesCount, 1); }); - testWidgets('does not cause didChangeDependencies to be called on move when nothing was found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not cause didChangeDependencies to be called on move when nothing was found', (WidgetTester tester) async { final Key globalKey = GlobalKey(); final Widget widgetTree = DidChangeDependencySpy( @@ -404,7 +405,7 @@ void main() { }); group('LookupBoundary.findAncestorWidgetOfExactType', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { Widget? containerThroughBoundary; Widget? containerStoppedAtBoundary; Widget? boundaryThroughBoundary; @@ -435,7 +436,7 @@ void main() { expect(boundaryStoppedAtBoundary, equals(tester.widget(find.byKey(boundaryKey)))); }); - testWidgets('finds right widget before boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('finds right widget before boundary', (WidgetTester tester) async { Widget? containerThroughBoundary; Widget? containerStoppedAtBoundary; @@ -466,7 +467,7 @@ void main() { expect(containerStoppedAtBoundary, equals(tester.widget(find.byKey(innerContainerKey)))); }); - testWidgets('works if nothing is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works if nothing is found', (WidgetTester tester) async { Widget? containerStoppedAtBoundary; await tester.pumpWidget(Builder( @@ -479,7 +480,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('does not establish a dependency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not establish a dependency', (WidgetTester tester) async { Widget? containerThroughBoundary; Widget? containerStoppedAtBoundary; Widget? containerStoppedAtBoundaryUnfulfilled; @@ -520,7 +521,7 @@ void main() { }); group('LookupBoundary.findAncestorStateOfType', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { State? containerThroughBoundary; State? containerStoppedAtBoundary; @@ -543,7 +544,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('finds right widget before boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('finds right widget before boundary', (WidgetTester tester) async { State? containerThroughBoundary; State? containerStoppedAtBoundary; @@ -572,7 +573,7 @@ void main() { expect(containerStoppedAtBoundary, equals(tester.state(find.byKey(innerContainerKey)))); }); - testWidgets('works if nothing is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works if nothing is found', (WidgetTester tester) async { State? containerStoppedAtBoundary; await tester.pumpWidget(Builder( @@ -585,7 +586,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('does not establish a dependency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not establish a dependency', (WidgetTester tester) async { State? containerThroughBoundary; State? containerStoppedAtBoundary; State? containerStoppedAtBoundaryUnfulfilled; @@ -626,7 +627,7 @@ void main() { }); group('LookupBoundary.findRootAncestorStateOfType', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { State? containerThroughBoundary; State? containerStoppedAtBoundary; @@ -649,7 +650,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('finds right widget before boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('finds right widget before boundary', (WidgetTester tester) async { State? containerThroughBoundary; State? containerStoppedAtBoundary; @@ -678,7 +679,7 @@ void main() { expect(containerStoppedAtBoundary, equals(tester.state(find.byKey(innerContainerKey)))); }); - testWidgets('works if nothing is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works if nothing is found', (WidgetTester tester) async { State? containerStoppedAtBoundary; await tester.pumpWidget(Builder( @@ -691,7 +692,7 @@ void main() { expect(containerStoppedAtBoundary, isNull); }); - testWidgets('does not establish a dependency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not establish a dependency', (WidgetTester tester) async { State? containerThroughBoundary; State? containerStoppedAtBoundary; State? containerStoppedAtBoundaryUnfulfilled; @@ -732,7 +733,7 @@ void main() { }); group('LookupBoundary.findAncestorRenderObjectOfType', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { RenderPadding? paddingThroughBoundary; RenderPadding? passingStoppedAtBoundary; @@ -756,7 +757,7 @@ void main() { expect(passingStoppedAtBoundary, isNull); }); - testWidgets('finds right widget before boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('finds right widget before boundary', (WidgetTester tester) async { RenderPadding? paddingThroughBoundary; RenderPadding? paddingStoppedAtBoundary; @@ -788,7 +789,7 @@ void main() { expect(paddingStoppedAtBoundary, equals(tester.renderObject(find.byKey(innerPaddingKey)))); }); - testWidgets('works if nothing is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works if nothing is found', (WidgetTester tester) async { RenderPadding? paddingStoppedAtBoundary; await tester.pumpWidget(Builder( @@ -801,7 +802,7 @@ void main() { expect(paddingStoppedAtBoundary, isNull); }); - testWidgets('does not establish a dependency', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not establish a dependency', (WidgetTester tester) async { RenderPadding? paddingThroughBoundary; RenderPadding? paddingStoppedAtBoundary; RenderWrap? wrapStoppedAtBoundaryUnfulfilled; @@ -843,7 +844,7 @@ void main() { }); group('LookupBoundary.visitAncestorElements', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { final List throughBoundary = []; final List stoppedAtBoundary = []; final List stoppedAtBoundaryTerminatedEarly = []; @@ -909,7 +910,7 @@ void main() { }); group('LookupBoundary.visitChildElements', () { - testWidgets('respects boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('respects boundary', (WidgetTester tester) async { final Key root = UniqueKey(); final Key child1 = UniqueKey(); final Key child2 = UniqueKey(); @@ -961,7 +962,7 @@ void main() { }); group('LookupBoundary.debugIsHidingAncestorWidgetOfExactType', () { - testWidgets('is hiding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is hiding', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Container( padding: const EdgeInsets.all(10), @@ -978,7 +979,7 @@ void main() { expect(isHidden, isTrue); }); - testWidgets('is not hiding entity within boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding entity within boundary', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Container( padding: const EdgeInsets.all(10), @@ -999,7 +1000,7 @@ void main() { expect(isHidden, isFalse); }); - testWidgets('is not hiding if no boundary exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding if no boundary exists', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Container( padding: const EdgeInsets.all(10), @@ -1014,7 +1015,7 @@ void main() { expect(isHidden, isFalse); }); - testWidgets('is not hiding if no boundary and no entity exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding if no boundary and no entity exists', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Builder( builder: (BuildContext context) { @@ -1027,7 +1028,7 @@ void main() { }); group('LookupBoundary.debugIsHidingAncestorStateOfType', () { - testWidgets('is hiding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is hiding', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(MyStatefulContainer( child: LookupBoundary( @@ -1042,7 +1043,7 @@ void main() { expect(isHidden, isTrue); }); - testWidgets('is not hiding entity within boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding entity within boundary', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(MyStatefulContainer( child: LookupBoundary( @@ -1059,7 +1060,7 @@ void main() { expect(isHidden, isFalse); }); - testWidgets('is not hiding if no boundary exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding if no boundary exists', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(MyStatefulContainer( child: Builder( @@ -1072,7 +1073,7 @@ void main() { expect(isHidden, isFalse); }); - testWidgets('is not hiding if no boundary and no entity exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding if no boundary and no entity exists', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Builder( builder: (BuildContext context) { @@ -1085,7 +1086,7 @@ void main() { }); group('LookupBoundary.debugIsHidingAncestorRenderObjectOfType', () { - testWidgets('is hiding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is hiding', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Padding( padding: EdgeInsets.zero, @@ -1101,7 +1102,7 @@ void main() { expect(isHidden, isTrue); }); - testWidgets('is not hiding entity within boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding entity within boundary', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Padding( padding: EdgeInsets.zero, @@ -1120,7 +1121,7 @@ void main() { expect(isHidden, isFalse); }); - testWidgets('is not hiding if no boundary exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding if no boundary exists', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Padding( padding: EdgeInsets.zero, @@ -1134,7 +1135,7 @@ void main() { expect(isHidden, isFalse); }); - testWidgets('is not hiding if no boundary and no entity exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is not hiding if no boundary and no entity exists', (WidgetTester tester) async { bool? isHidden; await tester.pumpWidget(Builder( builder: (BuildContext context) { diff --git a/packages/flutter/test/widgets/magnifier_test.dart b/packages/flutter/test/widgets/magnifier_test.dart index b6dda7a2e6757..2175efaf8e82d 100644 --- a/packages/flutter/test/widgets/magnifier_test.dart +++ b/packages/flutter/test/widgets/magnifier_test.dart @@ -9,6 +9,7 @@ import 'package:fake_async/fake_async.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _MockAnimationController extends AnimationController { _MockAnimationController() @@ -42,7 +43,7 @@ void main() { } group('Raw Magnifier', () { - testWidgets('should render with correct focal point and decoration', + testWidgetsWithLeakTracking('should render with correct focal point and decoration', (WidgetTester tester) async { final Key appKey = UniqueKey(); const Size magnifierSize = Size(100, 100); @@ -116,7 +117,7 @@ void main() { magnifierController.removeFromOverlay(); }); - testWidgets( + testWidgetsWithLeakTracking( 'should immediately remove from overlay on no animation controller', (WidgetTester tester) async { await runFakeAsync((FakeAsync async) async { @@ -149,7 +150,7 @@ void main() { }); }); - testWidgets('should update shown based on animation status', + testWidgetsWithLeakTracking('should update shown based on animation status', (WidgetTester tester) async { await runFakeAsync((FakeAsync async) async { final MagnifierController magnifierController = @@ -214,7 +215,7 @@ void main() { }); group('show', () { - testWidgets('should insert below below widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should insert below below widget', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Text('text'), )); @@ -226,6 +227,7 @@ void main() { final OverlayEntry fakeBeforeOverlayEntry = OverlayEntry(builder: (_) => fakeBefore); + addTearDown(() => fakeBeforeOverlayEntry..remove()..dispose()); Overlay.of(context).insert(fakeBeforeOverlayEntry); magnifierController.show( @@ -247,7 +249,7 @@ void main() { expect(allOverlayChildren.first.widget.key, fakeMagnifier.key); }); - testWidgets('should insert newly built widget without animating out if overlay != null', + testWidgetsWithLeakTracking('should insert newly built widget without animating out if overlay != null', (WidgetTester tester) async { await runFakeAsync((FakeAsync async) async { final _MockAnimationController animationController = diff --git a/packages/flutter/test/widgets/mark_needs_build_test.dart b/packages/flutter/test/widgets/mark_needs_build_test.dart index 9fa2d008b3360..af21964be22f8 100644 --- a/packages/flutter/test/widgets/mark_needs_build_test.dart +++ b/packages/flutter/test/widgets/mark_needs_build_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('setState can be called from build, initState, didChangeDependencies, and didUpdateWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setState can be called from build, initState, didChangeDependencies, and didUpdateWidget', (WidgetTester tester) async { // Initial build. await tester.pumpWidget( const Directionality( diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 38793a39489ff..35b0ba95e0605 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -7,6 +7,7 @@ import 'dart:ui' show Brightness, DisplayFeature, DisplayFeatureState, DisplayFe import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _MediaQueryAspectCase { const _MediaQueryAspectCase(this.method, this.data); @@ -43,7 +44,7 @@ class _MediaQueryAspectVariant extends TestVariant<_MediaQueryAspectCase> { } void main() { - testWidgets('MediaQuery does not have a default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery does not have a default', (WidgetTester tester) async { late final FlutterError error; // Cannot use tester.pumpWidget here because it wraps the widget in a View, // which introduces a MediaQuery ancestor. @@ -87,7 +88,7 @@ void main() { ); }); - testWidgets('MediaQuery.of finds a MediaQueryData when there is one', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.of finds a MediaQueryData when there is one', (WidgetTester tester) async { bool tested = false; await tester.pumpWidget( MediaQuery( @@ -107,7 +108,7 @@ void main() { expect(tested, isTrue); }); - testWidgets('MediaQuery.maybeOf defaults to null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.maybeOf defaults to null', (WidgetTester tester) async { bool tested = false; // Cannot use tester.pumpWidget here because it wraps the widget in a View, // which introduces a MediaQuery ancestor. @@ -128,7 +129,7 @@ void main() { expect(tested, isTrue); }); - testWidgets('MediaQuery.maybeOf finds a MediaQueryData when there is one', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.maybeOf finds a MediaQueryData when there is one', (WidgetTester tester) async { bool tested = false; await tester.pumpWidget( MediaQuery( @@ -146,7 +147,7 @@ void main() { expect(tested, isTrue); }); - testWidgets('MediaQueryData.fromView is sane', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQueryData.fromView is sane', (WidgetTester tester) async { final MediaQueryData data = MediaQueryData.fromView(tester.view); expect(data, hasOneLineDescription); expect(data.hashCode, equals(data.copyWith().hashCode)); @@ -162,7 +163,7 @@ void main() { expect(data.displayFeatures, isEmpty); }); - testWidgets('MediaQueryData.fromView uses platformData if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQueryData.fromView uses platformData if provided', (WidgetTester tester) async { const MediaQueryData platformData = MediaQueryData( textScaleFactor: 1234, platformBrightness: Brightness.dark, @@ -199,7 +200,7 @@ void main() { expect(data.displayFeatures, tester.view.displayFeatures); }); - testWidgets('MediaQueryData.fromView uses data from platformDispatcher if no platformData is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQueryData.fromView uses data from platformDispatcher if no platformData is provided', (WidgetTester tester) async { tester.platformDispatcher ..textScaleFactorTestValue = 123 ..platformBrightnessTestValue = Brightness.dark @@ -229,7 +230,7 @@ void main() { expect(data.displayFeatures, tester.view.displayFeatures); }); - testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view, preserving platform-specific data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.fromView injects a new MediaQuery with data from view, preserving platform-specific data', (WidgetTester tester) async { const MediaQueryData platformData = MediaQueryData( textScaleFactor: 1234, platformBrightness: Brightness.dark, @@ -278,7 +279,7 @@ void main() { expect(data.displayFeatures, tester.view.displayFeatures); }); - testWidgets('MediaQuery.fromView injects a new MediaQuery with data from view when no surrounding MediaQuery exists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.fromView injects a new MediaQuery with data from view when no surrounding MediaQuery exists', (WidgetTester tester) async { tester.platformDispatcher ..textScaleFactorTestValue = 123 ..platformBrightnessTestValue = Brightness.dark @@ -329,7 +330,7 @@ void main() { expect(data.displayFeatures, tester.view.displayFeatures); }); - testWidgets('MediaQuery.fromView updates on notifications (no parent data)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.fromView updates on notifications (no parent data)', (WidgetTester tester) async { addTearDown(() => tester.platformDispatcher.clearAllTestValues()); addTearDown(() => tester.view.reset()); @@ -392,7 +393,7 @@ void main() { expect(rebuildCount, 5); }); - testWidgets('MediaQuery.fromView updates on notifications (with parent data)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.fromView updates on notifications (with parent data)', (WidgetTester tester) async { addTearDown(() => tester.platformDispatcher.clearAllTestValues()); addTearDown(() => tester.view.reset()); @@ -451,7 +452,7 @@ void main() { expect(rebuildCount, 2); }); - testWidgets('MediaQuery.fromView updates when parent data changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.fromView updates when parent data changes', (WidgetTester tester) async { late MediaQueryData data; int rebuildCount = 0; TextScaler textScaler = const TextScaler.linear(55); @@ -488,7 +489,7 @@ void main() { expect(rebuildCount, 2); }); - testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async { final MediaQueryData data = MediaQueryData.fromView(tester.view); final MediaQueryData copied = data.copyWith(); expect(copied.size, data.size); @@ -510,7 +511,7 @@ void main() { expect(copied.displayFeatures, data.displayFeatures); }); - testWidgets('MediaQuery.copyWith copies specified values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.copyWith copies specified values', (WidgetTester tester) async { // Random and unique double values are used to ensure that the correct // values are copied over exactly const Size customSize = Size(3.14, 2.72); @@ -570,7 +571,7 @@ void main() { expect(copied.displayFeatures, customDisplayFeatures); }); - testWidgets('MediaQuery.removePadding removes specified padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removePadding removes specified padding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -642,7 +643,7 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.removePadding only removes specified padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removePadding only removes specified padding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -711,7 +712,7 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.removeViewInsets removes specified viewInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removeViewInsets removes specified viewInsets', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -783,7 +784,7 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.removeViewInsets removes only specified viewInsets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removeViewInsets removes only specified viewInsets', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -852,7 +853,7 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.removeViewPadding removes specified viewPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removeViewPadding removes specified viewPadding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -924,7 +925,7 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.removeViewPadding removes only specified viewPadding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removeViewPadding removes only specified viewPadding', (WidgetTester tester) async { const Size size = Size(2.0, 4.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -993,7 +994,7 @@ void main() { expect(unpadded.displayFeatures, displayFeatures); }); - testWidgets('MediaQuery.textScalerOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.textScalerOf', (WidgetTester tester) async { late TextScaler outsideTextScaler; late TextScaler insideTextScaler; @@ -1020,7 +1021,7 @@ void main() { expect(insideTextScaler, const TextScaler.linear(4.0)); }); - testWidgets('MediaQuery.platformBrightnessOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.platformBrightnessOf', (WidgetTester tester) async { late Brightness outsideBrightness; late Brightness insideBrightness; @@ -1047,7 +1048,7 @@ void main() { expect(insideBrightness, Brightness.dark); }); - testWidgets('MediaQuery.highContrastOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.highContrastOf', (WidgetTester tester) async { late bool outsideHighContrast; late bool insideHighContrast; @@ -1074,7 +1075,7 @@ void main() { expect(insideHighContrast, true); }); - testWidgets('MediaQuery.onOffSwitchLabelsOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.onOffSwitchLabelsOf', (WidgetTester tester) async { late bool outsideOnOffSwitchLabels; late bool insideOnOffSwitchLabels; @@ -1101,7 +1102,7 @@ void main() { expect(insideOnOffSwitchLabels, true); }); - testWidgets('MediaQuery.boldTextOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.boldTextOf', (WidgetTester tester) async { late bool outsideBoldTextOverride; late bool insideBoldTextOverride; @@ -1128,7 +1129,7 @@ void main() { expect(insideBoldTextOverride, true); }); - testWidgets('MediaQuery.fromView creates a MediaQuery', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.fromView creates a MediaQuery', (WidgetTester tester) async { MediaQuery? mediaQueryOutside; MediaQuery? mediaQueryInside; @@ -1153,7 +1154,7 @@ void main() { expect(mediaQueryOutside, isNot(mediaQueryInside)); }); - testWidgets('MediaQueryData.fromWindow is created using window values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQueryData.fromWindow is created using window values', (WidgetTester tester) async { final MediaQueryData windowData = MediaQueryData.fromWindow(tester.view); late MediaQueryData fromWindowData; @@ -1189,7 +1190,7 @@ void main() { expect(settingsA, isNot(settingsB)); }); - testWidgets('MediaQuery.removeDisplayFeatures removes specified display features and padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removeDisplayFeatures removes specified display features and padding', (WidgetTester tester) async { const Size size = Size(82.0, 40.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -1263,7 +1264,7 @@ void main() { expect(subScreenMediaQuery.displayFeatures, isEmpty); }); - testWidgets('MediaQuery.removePadding only removes specified display features and padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.removePadding only removes specified display features and padding', (WidgetTester tester) async { const Size size = Size(82.0, 40.0); const double devicePixelRatio = 2.0; const TextScaler textScaler = TextScaler.linear(1.2); @@ -1347,14 +1348,14 @@ void main() { expect(subScreenMediaQuery.displayFeatures, [cutoutDisplayFeature]); }); - testWidgets('MediaQueryData.gestureSettings is set from view.gestureSettings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQueryData.gestureSettings is set from view.gestureSettings', (WidgetTester tester) async { tester.view.gestureSettings = const GestureSettings(physicalDoubleTapSlop: 100, physicalTouchSlop: 100); addTearDown(() => tester.view.resetGestureSettings()); expect(MediaQueryData.fromView(tester.view).gestureSettings.touchSlop, closeTo(33.33, 0.1)); // Repeating, of course }); - testWidgets('MediaQuery can be partially depended-on', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery can be partially depended-on', (WidgetTester tester) async { MediaQueryData data = const MediaQueryData( size: Size(800, 600), textScaler: TextScaler.linear(1.1), @@ -1430,7 +1431,7 @@ void main() { expect(textScalerBuildCount, 2); }); - testWidgets('MediaQuery partial dependencies', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery partial dependencies', (WidgetTester tester) async { MediaQueryData data = const MediaQueryData(); int buildCount = 0; diff --git a/packages/flutter/test/widgets/modal_barrier_test.dart b/packages/flutter/test/widgets/modal_barrier_test.dart index 3d8ea7cc2777d..d502f9cd3f61a 100644 --- a/packages/flutter/test/widgets/modal_barrier_test.dart +++ b/packages/flutter/test/widgets/modal_barrier_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -46,7 +47,7 @@ void main() { }); group('ModalBarrier', () { - testWidgets('prevents interactions with widgets behind it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prevents interactions with widgets behind it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -61,7 +62,7 @@ void main() { expect(tapped, isFalse, reason: 'because the tap is not prevented by ModalBarrier'); }); - testWidgets('prevents hover interactions with widgets behind it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prevents hover interactions with widgets behind it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -88,7 +89,7 @@ void main() { expect(hovered, isFalse, reason: 'because the hover is not prevented by ModalBarrier'); }); - testWidgets('does not prevent interactions with widgets in front of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not prevent interactions with widgets in front of it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -103,7 +104,7 @@ void main() { expect(tapped, isTrue, reason: 'because the tap is prevented by ModalBarrier'); }); - testWidgets('does not prevent interactions with translucent widgets in front of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not prevent interactions with translucent widgets in front of it', (WidgetTester tester) async { bool dragged = false; final Widget subject = Stack( textDirection: TextDirection.ltr, @@ -130,7 +131,7 @@ void main() { expect(dragged, isTrue, reason: 'because the drag is prevented by ModalBarrier'); }); - testWidgets('does not prevent hover interactions with widgets in front of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not prevent hover interactions with widgets in front of it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -158,7 +159,7 @@ void main() { hovered = false; }); - testWidgets('plays system alert sound when user tries to dismiss it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('plays system alert sound when user tries to dismiss it', (WidgetTester tester) async { final List playedSystemSounds = []; try { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( @@ -187,7 +188,7 @@ void main() { expect(playedSystemSounds[0], SystemSoundType.alert.toString()); }); - testWidgets('pops the Navigator when dismissed by primary tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pops the Navigator when dismissed by primary tap', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => const SecondWidget(), @@ -220,7 +221,7 @@ void main() { ); }); - testWidgets('pops the Navigator when dismissed by non-primary tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pops the Navigator when dismissed by non-primary tap', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => const SecondWidget(), @@ -254,7 +255,7 @@ void main() { ); }); - testWidgets('may pop the Navigator when competing with other gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('may pop the Navigator when competing with other gestures', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => const SecondWidgetWithCompetence(), @@ -282,7 +283,7 @@ void main() { ); }); - testWidgets('does not pop the Navigator with a WillPopScope that returns false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not pop the Navigator with a WillPopScope that returns false', (WidgetTester tester) async { bool willPopCalled = false; final Map routes = { '/': (BuildContext context) => const FirstWidget(), @@ -327,7 +328,7 @@ void main() { expect(willPopCalled, isTrue); }); - testWidgets('pops the Navigator with a WillPopScope that returns true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pops the Navigator with a WillPopScope that returns true', (WidgetTester tester) async { bool willPopCalled = false; final Map routes = { '/': (BuildContext context) => const FirstWidget(), @@ -372,7 +373,7 @@ void main() { expect(willPopCalled, isTrue); }); - testWidgets('will call onDismiss callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will call onDismiss callback', (WidgetTester tester) async { bool dismissCallbackCalled = false; final Map routes = { '/': (BuildContext context) => const FirstWidget(), @@ -400,7 +401,7 @@ void main() { expect(dismissCallbackCalled, true); }); - testWidgets('when onDismiss throws, should have correct context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when onDismiss throws, should have correct context', (WidgetTester tester) async { final FlutterExceptionHandler? handler = FlutterError.onError; FlutterErrorDetails? error; FlutterError.onError = (FlutterErrorDetails details) { @@ -423,7 +424,7 @@ void main() { FlutterError.onError = handler; }); - testWidgets('will not pop when given an onDismiss callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will not pop when given an onDismiss callback', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => SecondWidget(onDismiss: () {}), @@ -450,7 +451,7 @@ void main() { ); }); - testWidgets('Undismissible ModalBarrier hidden in semantic tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Undismissible ModalBarrier hidden in semantic tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const ModalBarrier(dismissible: false)); @@ -460,7 +461,7 @@ void main() { semantics.dispose(); }); - testWidgets('Dismissible ModalBarrier includes button in semantic tree on iOS, macOS and android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible ModalBarrier includes button in semantic tree on iOS, macOS and android', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const Directionality( textDirection: TextDirection.ltr, @@ -486,7 +487,7 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.android})); }); group('AnimatedModalBarrier', () { - testWidgets('prevents interactions with widgets behind it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prevents interactions with widgets behind it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -501,7 +502,7 @@ void main() { expect(tapped, isFalse, reason: 'because the tap is not prevented by ModalBarrier'); }); - testWidgets('prevents hover interactions with widgets behind it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('prevents hover interactions with widgets behind it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -528,7 +529,7 @@ void main() { expect(hovered, isFalse, reason: 'because the hover is not prevented by AnimatedModalBarrier'); }); - testWidgets('does not prevent interactions with widgets in front of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not prevent interactions with widgets in front of it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -543,7 +544,7 @@ void main() { expect(tapped, isTrue, reason: 'because the tap is prevented by AnimatedModalBarrier'); }); - testWidgets('does not prevent interactions with translucent widgets in front of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not prevent interactions with translucent widgets in front of it', (WidgetTester tester) async { bool dragged = false; final Widget subject = Stack( textDirection: TextDirection.ltr, @@ -570,7 +571,7 @@ void main() { expect(dragged, isTrue, reason: 'because the drag is prevented by AnimatedModalBarrier'); }); - testWidgets('does not prevent hover interactions with widgets in front of it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not prevent hover interactions with widgets in front of it', (WidgetTester tester) async { final Widget subject = Stack( textDirection: TextDirection.ltr, children: [ @@ -598,7 +599,7 @@ void main() { hovered = false; }); - testWidgets('plays system alert sound when user tries to dismiss it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('plays system alert sound when user tries to dismiss it', (WidgetTester tester) async { final List playedSystemSounds = []; try { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( @@ -627,7 +628,7 @@ void main() { expect(playedSystemSounds[0], SystemSoundType.alert.toString()); }); - testWidgets('pops the Navigator when dismissed by primary tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pops the Navigator when dismissed by primary tap', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => const AnimatedSecondWidget(), @@ -660,7 +661,7 @@ void main() { ); }); - testWidgets('pops the Navigator when dismissed by non-primary tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pops the Navigator when dismissed by non-primary tap', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => const AnimatedSecondWidget(), @@ -694,7 +695,7 @@ void main() { ); }); - testWidgets('may pop the Navigator when competing with other gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('may pop the Navigator when competing with other gestures', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => const AnimatedSecondWidgetWithCompetence(), @@ -722,7 +723,7 @@ void main() { ); }); - testWidgets('does not pop the Navigator with a WillPopScope that returns false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not pop the Navigator with a WillPopScope that returns false', (WidgetTester tester) async { bool willPopCalled = false; final Map routes = { '/': (BuildContext context) => const FirstWidget(), @@ -767,7 +768,7 @@ void main() { expect(willPopCalled, isTrue); }); - testWidgets('pops the Navigator with a WillPopScope that returns true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pops the Navigator with a WillPopScope that returns true', (WidgetTester tester) async { bool willPopCalled = false; final Map routes = { '/': (BuildContext context) => const FirstWidget(), @@ -812,7 +813,7 @@ void main() { expect(willPopCalled, isTrue); }); - testWidgets('will call onDismiss callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will call onDismiss callback', (WidgetTester tester) async { bool dismissCallbackCalled = false; final Map routes = { '/': (BuildContext context) => const FirstWidget(), @@ -840,7 +841,7 @@ void main() { expect(dismissCallbackCalled, true); }); - testWidgets('will not pop when given an onDismiss callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will not pop when given an onDismiss callback', (WidgetTester tester) async { final Map routes = { '/': (BuildContext context) => const FirstWidget(), '/modal': (BuildContext context) => AnimatedSecondWidget(onDismiss: () {}), @@ -867,7 +868,7 @@ void main() { ); }); - testWidgets('Undismissible AnimatedModalBarrier hidden in semantic tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Undismissible AnimatedModalBarrier hidden in semantic tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(AnimatedModalBarrier(dismissible: false, color: colorAnimation)); @@ -877,7 +878,7 @@ void main() { semantics.dispose(); }); - testWidgets('Dismissible AnimatedModalBarrier includes button in semantic tree on iOS, macOS and android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dismissible AnimatedModalBarrier includes button in semantic tree on iOS, macOS and android', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -904,9 +905,10 @@ void main() { }); group('SemanticsClipper', () { - testWidgets('SemanticsClipper correctly clips Semantics.rect in four directions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsClipper correctly clips Semantics.rect in four directions', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ValueNotifier notifier = ValueNotifier(const EdgeInsets.fromLTRB(10, 20, 30, 40)); + addTearDown(notifier.dispose); const Rect fullScreen = TestSemantics.fullScreen; await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -933,7 +935,7 @@ void main() { }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.android})); }); - testWidgets('uses default mouse cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses default mouse cursor', (WidgetTester tester) async { await tester.pumpWidget(const Stack( textDirection: TextDirection.ltr, children: [ diff --git a/packages/flutter/test/widgets/mouse_region_test.dart b/packages/flutter/test/widgets/mouse_region_test.dart index 91e3b3e6e88a7..a26d7b3d799df 100644 --- a/packages/flutter/test/widgets/mouse_region_test.dart +++ b/packages/flutter/test/widgets/mouse_region_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class HoverClient extends StatefulWidget { const HoverClient({ @@ -77,7 +78,7 @@ class _HoverFeedbackState extends State { void main() { // Regression test for https://github.com/flutter/flutter/issues/73330 - testWidgets('hitTestBehavior test - HitTestBehavior.deferToChild/opaque', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hitTestBehavior test - HitTestBehavior.deferToChild/opaque', (WidgetTester tester) async { bool onEnter = false; await tester.pumpWidget(Center( child: MouseRegion( @@ -103,7 +104,7 @@ void main() { expect(onEnter, true); }); - testWidgets('hitTestBehavior test - HitTestBehavior.deferToChild and non-opaque', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hitTestBehavior test - HitTestBehavior.deferToChild and non-opaque', (WidgetTester tester) async { bool onEnterRegion1 = false; bool onEnterRegion2 = false; await tester.pumpWidget(Directionality( @@ -143,7 +144,7 @@ void main() { expect(onEnterRegion1, true); }); - testWidgets('hitTestBehavior test - HitTestBehavior.translucent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hitTestBehavior test - HitTestBehavior.translucent', (WidgetTester tester) async { bool onEnterRegion1 = false; bool onEnterRegion2 = false; await tester.pumpWidget(Directionality( @@ -177,7 +178,7 @@ void main() { expect(onEnterRegion1, true); }); - testWidgets('onEnter and onExit can be triggered with mouse buttons pressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onEnter and onExit can be triggered with mouse buttons pressed', (WidgetTester tester) async { PointerEnterEvent? enter; PointerExitEvent? exit; await tester.pumpWidget(Center( @@ -212,7 +213,7 @@ void main() { expect(exit!.localPosition, equals(const Offset(-349.0, -249.0))); }); - testWidgets('detects pointer enter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('detects pointer enter', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -244,7 +245,7 @@ void main() { expect(exit, isNull); }); - testWidgets('detects pointer exiting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('detects pointer exiting', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -275,7 +276,7 @@ void main() { expect(exit!.localPosition, equals(const Offset(-349.0, -249.0))); }); - testWidgets('triggers pointer enter when a mouse is connected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('triggers pointer enter when a mouse is connected', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -301,7 +302,7 @@ void main() { expect(exit, isNull); }); - testWidgets('triggers pointer exit when a mouse is disconnected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('triggers pointer exit when a mouse is disconnected', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -339,7 +340,7 @@ void main() { expect(exit, isNull); }); - testWidgets('triggers pointer enter when widget appears', (WidgetTester tester) async { + testWidgetsWithLeakTracking('triggers pointer enter when widget appears', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -375,7 +376,7 @@ void main() { expect(exit, isNull); }); - testWidgets("doesn't trigger pointer exit when widget disappears", (WidgetTester tester) async { + testWidgetsWithLeakTracking("doesn't trigger pointer exit when widget disappears", (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -408,7 +409,7 @@ void main() { expect(exit, isNull); }); - testWidgets('triggers pointer enter when widget moves in', (WidgetTester tester) async { + testWidgetsWithLeakTracking('triggers pointer enter when widget moves in', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -450,7 +451,7 @@ void main() { expect(exit, isNull); }); - testWidgets('triggers pointer exit when widget moves out', (WidgetTester tester) async { + testWidgetsWithLeakTracking('triggers pointer exit when widget moves out', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -492,7 +493,7 @@ void main() { expect(exit!.localPosition, equals(const Offset(50, 50))); }); - testWidgets('detects hover from touch devices', (WidgetTester tester) async { + testWidgetsWithLeakTracking('detects hover from touch devices', (WidgetTester tester) async { PointerEnterEvent? enter; PointerHoverEvent? move; PointerExitEvent? exit; @@ -522,7 +523,7 @@ void main() { expect(exit, isNull); }); - testWidgets('Hover works with nested listeners', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hover works with nested listeners', (WidgetTester tester) async { final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); final List enter1 = []; @@ -597,7 +598,7 @@ void main() { clearLists(); }); - testWidgets('Hover transfers between two listeners', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hover transfers between two listeners', (WidgetTester tester) async { final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); final List enter1 = []; @@ -690,7 +691,7 @@ void main() { expect(exit2, isEmpty); }); - testWidgets('applies mouse cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applies mouse cursor', (WidgetTester tester) async { await tester.pumpWidget(const _Scaffold( topLeft: MouseRegion( cursor: SystemMouseCursors.text, @@ -711,7 +712,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.basic); }); - testWidgets('MouseRegion uses updated callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MouseRegion uses updated callbacks', (WidgetTester tester) async { final List logs = []; Widget hoverableContainer({ PointerEnterEventListener? onEnter, @@ -773,7 +774,7 @@ void main() { expect(logs, ['enter2', 'hover2', 'exit2']); }); - testWidgets('needsCompositing set when parent class needsCompositing is set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('needsCompositing set when parent class needsCompositing is set', (WidgetTester tester) async { await tester.pumpWidget( MouseRegion( onEnter: (PointerEnterEvent _) {}, @@ -795,7 +796,7 @@ void main() { expect(listener.needsCompositing, isFalse); }); - testWidgets('works with transform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works with transform', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/31986. final Key key = UniqueKey(); const double scaleFactor = 2.0; @@ -862,7 +863,7 @@ void main() { events.clear(); }); - testWidgets('needsCompositing is always false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('needsCompositing is always false', (WidgetTester tester) async { // Pretend that we have a mouse connected. final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(); @@ -897,7 +898,7 @@ void main() { expect(tester.layers.whereType(), hasLength(1)); }); - testWidgets("Callbacks aren't called during build", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Callbacks aren't called during build", (WidgetTester tester) async { final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(location: Offset.zero); @@ -939,7 +940,7 @@ void main() { expect(numExits, equals(0)); }); - testWidgets("MouseRegion activate/deactivate don't duplicate annotations", (WidgetTester tester) async { + testWidgetsWithLeakTracking("MouseRegion activate/deactivate don't duplicate annotations", (WidgetTester tester) async { final GlobalKey feedbackKey = GlobalKey(); final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); await gesture.addPointer(); @@ -983,7 +984,7 @@ void main() { expect(numExits, equals(0)); }); - testWidgets('Exit event when unplugging mouse should have a position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Exit event when unplugging mouse should have a position', (WidgetTester tester) async { final List enter = []; final List hover = []; final List exit = []; @@ -1031,7 +1032,7 @@ void main() { expect(exit.single.delta, Offset.zero); }); - testWidgets('detects pointer enter with closure arguments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('detects pointer enter with closure arguments', (WidgetTester tester) async { await tester.pumpWidget(const _HoverClientWithClosures()); expect(find.text('not hovering'), findsOneWidget); @@ -1048,7 +1049,7 @@ void main() { expect(find.text('HOVERING'), findsOneWidget); }); - testWidgets('MouseRegion paints child once and only once when MouseRegion is inactive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MouseRegion paints child once and only once when MouseRegion is inactive', (WidgetTester tester) async { int paintCount = 0; await tester.pumpWidget( Directionality( @@ -1066,7 +1067,7 @@ void main() { expect(paintCount, 1); }); - testWidgets('MouseRegion paints child once and only once when MouseRegion is active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MouseRegion paints child once and only once when MouseRegion is active', (WidgetTester tester) async { int paintCount = 0; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); @@ -1088,7 +1089,7 @@ void main() { expect(paintCount, 1); }); - testWidgets('A MouseRegion mounted under the pointer should take effect in the next postframe', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A MouseRegion mounted under the pointer should take effect in the next postframe', (WidgetTester tester) async { bool hovered = false; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); @@ -1130,7 +1131,7 @@ void main() { expect(tester.binding.hasScheduledFrame, isFalse); }); - testWidgets('A MouseRegion unmounted under the pointer should not trigger state change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A MouseRegion unmounted under the pointer should not trigger state change', (WidgetTester tester) async { bool hovered = true; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); @@ -1173,7 +1174,7 @@ void main() { expect(tester.binding.hasScheduledFrame, isFalse); }); - testWidgets('A MouseRegion moved into the mouse should take effect in the next postframe', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A MouseRegion moved into the mouse should take effect in the next postframe', (WidgetTester tester) async { bool hovered = false; final List logHovered = []; bool moved = false; @@ -1303,7 +1304,7 @@ void main() { ); } - testWidgets('a transparent one should allow MouseRegions behind it to receive pointers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('a transparent one should allow MouseRegions behind it to receive pointers', (WidgetTester tester) async { final List logs = []; await tester.pumpWidget(tripleRegions( opaqueC: false, @@ -1350,7 +1351,7 @@ void main() { expect(logs, ['exitC', 'exitB', 'exitA']); }); - testWidgets('an opaque one should prevent MouseRegions behind it receiving pointers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('an opaque one should prevent MouseRegions behind it receiving pointers', (WidgetTester tester) async { final List logs = []; await tester.pumpWidget(tripleRegions( opaqueC: true, @@ -1397,7 +1398,7 @@ void main() { expect(logs, ['exitC', 'exitA']); }); - testWidgets('opaque should default to true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('opaque should default to true', (WidgetTester tester) async { final List logs = []; await tester.pumpWidget(tripleRegions( addLog: (String log) => logs.add(log), @@ -1420,7 +1421,7 @@ void main() { }); }); - testWidgets('an empty opaque MouseRegion is effective', (WidgetTester tester) async { + testWidgetsWithLeakTracking('an empty opaque MouseRegion is effective', (WidgetTester tester) async { bool bottomRegionIsHovered = false; await tester.pumpWidget( Directionality( @@ -1455,7 +1456,7 @@ void main() { expect(bottomRegionIsHovered, isFalse); }); - testWidgets("Changing MouseRegion's callbacks is effective and doesn't repaint", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Changing MouseRegion's callbacks is effective and doesn't repaint", (WidgetTester tester) async { final List logs = []; const Key key = ValueKey(1); @@ -1519,7 +1520,7 @@ void main() { expect(logs, ['paint']); }); - testWidgets('Changing MouseRegion.opaque is effective and repaints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing MouseRegion.opaque is effective and repaints', (WidgetTester tester) async { final List logs = []; final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); @@ -1563,7 +1564,7 @@ void main() { expect(logs, ['paint', 'hover-enter']); }); - testWidgets('Changing MouseRegion.cursor is effective and repaints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing MouseRegion.cursor is effective and repaints', (WidgetTester tester) async { final List logPaints = []; final List logEnters = []; @@ -1610,7 +1611,7 @@ void main() { logEnters.clear(); }); - testWidgets('Changing whether MouseRegion.cursor is null is effective and repaints', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing whether MouseRegion.cursor is null is effective and repaints', (WidgetTester tester) async { final List logEnters = []; final List logPaints = []; @@ -1682,7 +1683,7 @@ void main() { logEnters.clear(); }); - testWidgets('Does not trigger side effects during a reparent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not trigger side effects during a reparent', (WidgetTester tester) async { final List logEnters = []; final List logExits = []; final List logCursors = []; @@ -1766,9 +1767,13 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.click); }); - testWidgets("RenderMouseRegion's debugFillProperties when default", (WidgetTester tester) async { + testWidgetsWithLeakTracking("RenderMouseRegion's debugFillProperties when default", (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - RenderMouseRegion().debugFillProperties(builder); + + final RenderMouseRegion renderMouseRegion = RenderMouseRegion(); + addTearDown(renderMouseRegion.dispose); + + renderMouseRegion.debugFillProperties(builder); final List description = builder.properties.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)).map((DiagnosticsNode node) => node.toString()).toList(); @@ -1781,16 +1786,23 @@ void main() { ]); }); - testWidgets("RenderMouseRegion's debugFillProperties when full", (WidgetTester tester) async { + testWidgetsWithLeakTracking("RenderMouseRegion's debugFillProperties when full", (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); - RenderMouseRegion( + + final RenderErrorBox renderErrorBox = RenderErrorBox(); + addTearDown(renderErrorBox.dispose); + + final RenderMouseRegion renderMouseRegion = RenderMouseRegion( onEnter: (PointerEnterEvent event) {}, onExit: (PointerExitEvent event) {}, onHover: (PointerHoverEvent event) {}, cursor: SystemMouseCursors.click, validForMouseTracker: false, - child: RenderErrorBox(), - ).debugFillProperties(builder); + child: renderErrorBox, + ); + addTearDown(renderMouseRegion.dispose); + + renderMouseRegion.debugFillProperties(builder); final List description = builder.properties.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)).map((DiagnosticsNode node) => node.toString()).toList(); @@ -1805,7 +1817,7 @@ void main() { ]); }); - testWidgets('No new frames are scheduled when mouse moves without triggering callbacks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No new frames are scheduled when mouse moves without triggering callbacks', (WidgetTester tester) async { await tester.pumpWidget(Center( child: MouseRegion( child: const SizedBox( @@ -1825,7 +1837,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/67044 - testWidgets('Handle mouse events should ignore the detached MouseTrackerAnnotation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Handle mouse events should ignore the detached MouseTrackerAnnotation', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Center( child: Draggable( diff --git a/packages/flutter/test/widgets/multi_view_binding_test.dart b/packages/flutter/test/widgets/multi_view_binding_test.dart index 6c7c1d09de368..d896cfa196f39 100644 --- a/packages/flutter/test/widgets/multi_view_binding_test.dart +++ b/packages/flutter/test/widgets/multi_view_binding_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('runApp uses deprecated pipelineOwner and renderView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('runApp uses deprecated pipelineOwner and renderView', (WidgetTester tester) async { runApp(const SizedBox()); final RenderObject renderObject = tester.renderObject(find.byType(SizedBox)); @@ -21,7 +22,7 @@ void main() { expect(renderObject.owner, equals(tester.binding.pipelineOwner)); }); - testWidgets('can manually attach RootWidget to build owner', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can manually attach RootWidget to build owner', (WidgetTester tester) async { expect(find.byType(ColoredBox), findsNothing); final RootWidget rootWidget = RootWidget( diff --git a/packages/flutter/test/widgets/multi_view_tree_updates_test.dart b/packages/flutter/test/widgets/multi_view_tree_updates_test.dart index 7bc41fe9c519c..c8d6c049b8fa8 100644 --- a/packages/flutter/test/widgets/multi_view_tree_updates_test.dart +++ b/packages/flutter/test/widgets/multi_view_tree_updates_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Widgets in view update as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets in view update as expected', (WidgetTester tester) async { final Widget widget = View( view: tester.view, child: const TestWidget(), @@ -49,7 +50,7 @@ void main() { expect(tester.renderObject(find.byType(Text)).text.toPlainText(), 'FooBar'); }); - testWidgets('Views in ViewCollection update as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Views in ViewCollection update as expected', (WidgetTester tester) async { Iterable renderParagraphTexts() { return tester.renderObjectList(find.byType(Text)).map((RenderParagraph r) => r.text.toPlainText()); } @@ -103,7 +104,7 @@ void main() { expect(renderParagraphTexts(), ['Guten', 'Morgen']); }); - testWidgets('Views in ViewAnchor update as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Views in ViewAnchor update as expected', (WidgetTester tester) async { Iterable renderParagraphTexts() { return tester.renderObjectList(find.byType(Text)).map((RenderParagraph r) => r.text.toPlainText()); } diff --git a/packages/flutter/test/widgets/multichild_test.dart b/packages/flutter/test/widgets/multichild_test.dart index 78dc38fe9d08a..f52afc5ef99cd 100644 --- a/packages/flutter/test/widgets/multichild_test.dart +++ b/packages/flutter/test/widgets/multichild_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; @@ -32,7 +33,7 @@ void checkTree(WidgetTester tester, List expectedDecorations) { } void main() { - testWidgets('MultiChildRenderObjectElement control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MultiChildRenderObjectElement control test', (WidgetTester tester) async { await tester.pumpWidget( const Stack( @@ -117,7 +118,7 @@ void main() { }); - testWidgets('MultiChildRenderObjectElement with stateless widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MultiChildRenderObjectElement with stateless widgets', (WidgetTester tester) async { await tester.pumpWidget( const Stack( @@ -243,7 +244,7 @@ void main() { checkTree(tester, []); }); - testWidgets('MultiChildRenderObjectElement with stateful widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MultiChildRenderObjectElement with stateful widgets', (WidgetTester tester) async { await tester.pumpWidget( const Stack( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/multichildobject_with_keys_test.dart b/packages/flutter/test/widgets/multichildobject_with_keys_test.dart index d00260a7740a3..07d04fa3895a8 100644 --- a/packages/flutter/test/widgets/multichildobject_with_keys_test.dart +++ b/packages/flutter/test/widgets/multichildobject_with_keys_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Render and element tree stay in sync when keyed children move around', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Render and element tree stay in sync when keyed children move around', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/48855. await tester.pumpWidget( @@ -59,7 +60,7 @@ void main() { ); }); - testWidgets('Building a new MultiChildRenderObjectElement with children having duplicated keys throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Building a new MultiChildRenderObjectElement with children having duplicated keys throws', (WidgetTester tester) async { const ValueKey duplicatedKey = ValueKey(1); await tester.pumpWidget(const Column( @@ -79,7 +80,7 @@ void main() { ); }); - testWidgets('Updating a MultiChildRenderObjectElement to have children with duplicated keys throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updating a MultiChildRenderObjectElement to have children with duplicated keys throws', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/81541 const ValueKey key1 = ValueKey(1); diff --git a/packages/flutter/test/widgets/navigator_and_layers_test.dart b/packages/flutter/test/widgets/navigator_and_layers_test.dart index 1283a386438af..496b69fc359f6 100644 --- a/packages/flutter/test/widgets/navigator_and_layers_test.dart +++ b/packages/flutter/test/widgets/navigator_and_layers_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; @@ -26,7 +27,7 @@ class TestCustomPainter extends CustomPainter { } void main() { - testWidgets('Do we paint when coming back from a navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do we paint when coming back from a navigation', (WidgetTester tester) async { final List log = []; log.add('0'); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/navigator_replacement_test.dart b/packages/flutter/test/widgets/navigator_replacement_test.dart index d43df8a88cff7..a1c762c0d6065 100644 --- a/packages/flutter/test/widgets/navigator_replacement_test.dart +++ b/packages/flutter/test/widgets/navigator_replacement_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'observer_tester.dart'; void main() { - testWidgets('Back during pushReplacement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Back during pushReplacement', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: const Material(child: Text('home')), routes: { @@ -42,7 +43,7 @@ void main() { }); group('pushAndRemoveUntil', () { - testWidgets('notifies appropriately', (WidgetTester tester) async { + testWidgetsWithLeakTracking('notifies appropriately', (WidgetTester tester) async { final TestObserver observer = TestObserver(); final Widget myApp = MaterialApp( home: const Material(child: Text('home')), @@ -110,7 +111,7 @@ void main() { ])); }); - testWidgets('triggers page transition animation for pushed route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('triggers page transition animation for pushed route', (WidgetTester tester) async { final Widget myApp = MaterialApp( home: const Material(child: Text('home')), routes: { @@ -139,7 +140,7 @@ void main() { expect(find.text('b'), findsOneWidget); }); - testWidgets('Hero transition triggers when preceding route contains hero, and predicate route does not', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero transition triggers when preceding route contains hero, and predicate route does not', (WidgetTester tester) async { const String kHeroTag = 'hero'; final Widget myApp = MaterialApp( initialRoute: '/', @@ -184,7 +185,7 @@ void main() { expect(find.text('b'), isOnstage); }); - testWidgets('Hero transition does not trigger when preceding route does not contain hero, but predicate route does', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hero transition does not trigger when preceding route does not contain hero, but predicate route does', (WidgetTester tester) async { const String kHeroTag = 'hero'; final Widget myApp = MaterialApp( theme: ThemeData( diff --git a/packages/flutter/test/widgets/navigator_restoration_test.dart b/packages/flutter/test/widgets/navigator_restoration_test.dart index ecbed9bfb7658..e91d41aa1f4b3 100644 --- a/packages/flutter/test/widgets/navigator_restoration_test.dart +++ b/packages/flutter/test/widgets/navigator_restoration_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Restoration Smoke Test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Restoration Smoke Test', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -29,7 +30,7 @@ void main() { expect(findRoute('home', count: 2), findsOneWidget); }); - testWidgets('restorablePushNamed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushNamed', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -66,7 +67,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }); - testWidgets('restorablePushReplacementNamed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushReplacementNamed', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -99,7 +100,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }); - testWidgets('restorablePopAndPushNamed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePopAndPushNamed', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -132,7 +133,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }); - testWidgets('restorablePushNamedAndRemoveUntil', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushNamedAndRemoveUntil', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -165,7 +166,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }); - testWidgets('restorablePush', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePush', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -202,7 +203,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('restorablePush adds route on all platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePush adds route on all platforms', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -212,7 +213,7 @@ void main() { expect(findRoute('Foo'), findsOneWidget); }); - testWidgets('restorablePushReplacement', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushReplacement', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -245,7 +246,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('restorablePushReplacement adds route on all platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushReplacement adds route on all platforms', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -255,7 +256,7 @@ void main() { expect(findRoute('Foo'), findsOneWidget); }); - testWidgets('restorablePushAndRemoveUntil', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushAndRemoveUntil', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -288,7 +289,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('restorablePushAndRemoveUntil adds route on all platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorablePushAndRemoveUntil adds route on all platforms', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -298,7 +299,7 @@ void main() { expect(findRoute('Foo'), findsOneWidget); }); - testWidgets('restorableReplace', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorableReplace', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -334,7 +335,7 @@ void main() { expect(findRoute('Bar'), findsNothing); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('restorableReplace adds route on all platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorableReplace adds route on all platforms', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -346,7 +347,7 @@ void main() { expect(findRoute('Foo'), findsOneWidget); }); - testWidgets('restorableReplaceRouteBelow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorableReplaceRouteBelow', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -392,7 +393,7 @@ void main() { expect(findRoute('Anchor', count: 2), findsOneWidget); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('restorableReplaceRouteBelow adds route on all platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restorableReplaceRouteBelow adds route on all platforms', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home', count: 0), findsOneWidget); @@ -412,7 +413,7 @@ void main() { expect(findRoute('Foo', skipOffstage: false), findsOneWidget); }); - testWidgets('restoring a popped route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restoring a popped route', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -440,7 +441,7 @@ void main() { expect(findRoute('Foo', count: 2), findsOneWidget); }); - testWidgets('popped routes are not restored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('popped routes are not restored', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -465,7 +466,7 @@ void main() { expect(findRoute('home', skipOffstage: false), findsOneWidget); }); - testWidgets('routes that are in the process of push are restored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('routes that are in the process of push are restored', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -494,7 +495,7 @@ void main() { expect(route2.isActive, isTrue); }); - testWidgets('routes that are in the process of pop are not restored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('routes that are in the process of pop are not restored', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -531,7 +532,7 @@ void main() { expect(notifyCount, 1); }); - testWidgets('routes are restored in the right order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('routes are restored in the right order', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); tester.state(find.byType(Navigator)).restorablePushNamed('route1'); @@ -569,7 +570,7 @@ void main() { expect(findRoute('home'), findsOneWidget); }); - testWidgets('all routes up to first unrestorable are restored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('all routes up to first unrestorable are restored', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); tester.state(find.byType(Navigator)).restorablePushNamed('route1'); @@ -599,7 +600,7 @@ void main() { expect(findRoute('home', skipOffstage: false), findsOneWidget); }); - testWidgets('removing unrestorable routes restores all of them', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removing unrestorable routes restores all of them', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); tester.state(find.byType(Navigator)).restorablePushNamed('route1'); @@ -633,7 +634,7 @@ void main() { expect(findRoute('home', skipOffstage: false), findsOneWidget); }); - testWidgets('RestorableRouteFuture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableRouteFuture', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -673,7 +674,7 @@ void main() { expect(restoredRouteFuture.enabled, isFalse); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 - testWidgets('RestorableRouteFuture in unrestorable context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableRouteFuture in unrestorable context', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); expect(findRoute('home'), findsOneWidget); @@ -704,7 +705,7 @@ void main() { expect(findRoute('home'), findsOneWidget); }); - testWidgets('Illegal arguments throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Illegal arguments throw', (WidgetTester tester) async { await tester.pumpWidget(const TestWidget()); tester.state(find.byType(Navigator)).restorablePushNamed('Bar'); await tester.pumpAndSettle(); @@ -787,7 +788,7 @@ void main() { ); }); - testWidgets('Moving scopes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving scopes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root', child: TestWidget( @@ -840,7 +841,7 @@ void main() { expect(findRoute('home', count: 0), findsOneWidget); }); - testWidgets('Restoring pages', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Restoring pages', (WidgetTester tester) async { await tester.pumpWidget(const PagedTestWidget()); expect(findRoute('home', count: 0), findsOneWidget); await tapRouteCounter('home', tester); @@ -882,7 +883,7 @@ void main() { expect(findRoute('bar', count: 0), findsOneWidget); }); - testWidgets('Unrestorable pages', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unrestorable pages', (WidgetTester tester) async { await tester.pumpWidget(const PagedTestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -936,7 +937,7 @@ void main() { expect(findRoute('home', count: 1), findsOneWidget); }); - testWidgets('removed page is not restored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removed page is not restored', (WidgetTester tester) async { await tester.pumpWidget(const PagedTestWidget()); await tapRouteCounter('home', tester); expect(findRoute('home', count: 1), findsOneWidget); @@ -976,7 +977,7 @@ void main() { expect(findRoute('p1', count: 0), findsOneWidget); }); - testWidgets('Helpful assert thrown all routes in onGenerateInitialRoutes are not restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Helpful assert thrown all routes in onGenerateInitialRoutes are not restorable', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( restorationScopeId: 'material_app', From 658710b6f944e9a6f8bba9c4896fb953f1062976 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova Date: Mon, 18 Sep 2023 13:45:38 -0700 Subject: [PATCH 1325/1547] Cover more tests with leak tracking. (#134805) --- .../cupertino/activity_indicator_test.dart | 15 ++-- .../adaptive_text_selection_toolbar_test.dart | 19 +++-- packages/flutter/test/cupertino/app_test.dart | 79 ++++++++++++------ .../test/cupertino/bottom_tab_bar_test.dart | 31 +++---- .../flutter/test/cupertino/button_test.dart | 31 +++---- .../flutter/test/cupertino/checkbox_test.dart | 15 ++-- packages/flutter/test/material/app_test.dart | 46 ++++++++--- .../material/calendar_date_picker_test.dart | 82 +++++++++---------- packages/flutter/test/material/chip_test.dart | 17 +++- .../test/widgets/undo_history_test.dart | 26 +++--- 10 files changed, 215 insertions(+), 146 deletions(-) diff --git a/packages/flutter/test/cupertino/activity_indicator_test.dart b/packages/flutter/test/cupertino/activity_indicator_test.dart index dcb8ac43156d5..1db90ea77ce7b 100644 --- a/packages/flutter/test/cupertino/activity_indicator_test.dart +++ b/packages/flutter/test/cupertino/activity_indicator_test.dart @@ -10,9 +10,10 @@ library; import 'package:flutter/cupertino.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Activity indicator animate property works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activity indicator animate property works', (WidgetTester tester) async { await tester.pumpWidget(buildCupertinoActivityIndicator()); expect(SchedulerBinding.instance.transientCallbackCount, equals(1)); @@ -28,7 +29,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(1)); }); - testWidgets('Activity indicator dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activity indicator dark mode', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Center( @@ -77,7 +78,7 @@ void main() { ); }); - testWidgets('Activity indicator 0% in progress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activity indicator 0% in progress', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Center( @@ -99,7 +100,7 @@ void main() { ); }); - testWidgets('Activity indicator 30% in progress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activity indicator 30% in progress', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Center( @@ -121,7 +122,7 @@ void main() { ); }); - testWidgets('Activity indicator 100% in progress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Activity indicator 100% in progress', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Center( @@ -142,7 +143,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/41345. - testWidgets('has the correct corner radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has the correct corner radius', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoActivityIndicator(animating: false, radius: 100), ); @@ -158,7 +159,7 @@ void main() { ); }); - testWidgets('Can specify color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can specify color', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Center( diff --git a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart index 70f4be6d4518b..fd5b2c93935d8 100644 --- a/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/adaptive_text_selection_toolbar_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/live_text_utils.dart'; @@ -37,7 +38,7 @@ void main() { ); } - testWidgets('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Builds the right toolbar on each platform, including web, and shows buttonItems', (WidgetTester tester) async { const String buttonText = 'Click me'; await tester.pumpWidget( @@ -78,7 +79,7 @@ void main() { skip: isBrowser, // [intended] see https://github.com/flutter/flutter/issues/108382 ); - testWidgets('Can build children directly as well', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can build children directly as well', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -101,17 +102,21 @@ void main() { skip: isBrowser, // [intended] see https://github.com/flutter/flutter/issues/108382 ); - testWidgets('Can build from EditableTextState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can build from EditableTextState', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); await tester.pumpWidget(CupertinoApp( home: Align( alignment: Alignment.topLeft, child: SizedBox( width: 400, child: EditableText( - controller: TextEditingController(), + controller: controller, backgroundCursorColor: const Color(0xff00ffff), - focusNode: FocusNode(), + focusNode: focusNode, style: const TextStyle(), cursorColor: const Color(0xff00ffff), selectionControls: cupertinoTextSelectionHandleControls, @@ -160,7 +165,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('Can build for editable text from raw parameters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can build for editable text from raw parameters', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(CupertinoApp( home: Center( @@ -210,7 +215,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('Builds the correct button per-platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Builds the correct button per-platform', (WidgetTester tester) async { const String buttonText = 'Click me'; await tester.pumpWidget( diff --git a/packages/flutter/test/cupertino/app_test.dart b/packages/flutter/test/cupertino/app_test.dart index 50265a8f66951..ea384af7feba9 100644 --- a/packages/flutter/test/cupertino/app_test.dart +++ b/packages/flutter/test/cupertino/app_test.dart @@ -40,7 +40,7 @@ void main() { expect(find.widgetWithText(Navigator, 'foo'), findsOneWidget); }); - testWidgets('Has default cupertino localizations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Has default cupertino localizations', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Builder( @@ -62,7 +62,7 @@ void main() { expect(find.text('Thu Oct 4 '), findsOneWidget); }); - testWidgets('Can use dynamic color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can use dynamic color', (WidgetTester tester) async { const CupertinoDynamicColor dynamicColor = CupertinoDynamicColor.withBrightness( color: Color(0xFF000000), darkColor: Color(0xFF000001), @@ -84,7 +84,7 @@ void main() { expect(tester.widget(find.byType(Title)).color.value, 0xFF000001); }); - testWidgets('Can customize initial routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can customize initial routes', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget( CupertinoApp( @@ -131,7 +131,7 @@ void main() { expect(find.text('regular page two'), findsNothing); }); - testWidgets('CupertinoApp.navigatorKey can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoApp.navigatorKey can be updated', (WidgetTester tester) async { final GlobalKey<NavigatorState> key1 = GlobalKey<NavigatorState>(); await tester.pumpWidget(CupertinoApp( navigatorKey: key1, @@ -147,12 +147,13 @@ void main() { expect(key1.currentState, isNull); }); - testWidgets('CupertinoApp.router works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoApp.router works', (WidgetTester tester) async { final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( uri: Uri.parse('initial'), ), ); + addTearDown(provider.dispose); final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -164,6 +165,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); await tester.pumpWidget(CupertinoApp.router( routeInformationProvider: provider, routeInformationParser: SimpleRouteInformationParser(), @@ -176,9 +178,14 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('CupertinoApp.router route information parser is optional', (WidgetTester tester) async { + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + )); + + testWidgetsWithLeakTracking('CupertinoApp.router route information parser is optional', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -190,6 +197,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); await tester.pumpWidget(CupertinoApp.router( routerDelegate: delegate, @@ -201,9 +209,14 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('CupertinoApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + )); + + testWidgetsWithLeakTracking('CupertinoApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -215,12 +228,14 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( uri: Uri.parse('initial'), ), ); + addTearDown(provider.dispose); await tester.pumpWidget(CupertinoApp.router( routeInformationProvider: provider, routerDelegate: delegate, @@ -228,7 +243,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('CupertinoApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoApp.router throw if route configuration is provided along with other delegate', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -240,6 +255,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate); await tester.pumpWidget(CupertinoApp.router( @@ -249,15 +265,19 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('CupertinoApp.router router config works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoApp.router router config works', (WidgetTester tester) async { + late SimpleNavigatorRouterDelegate delegate; + addTearDown(() => delegate.dispose()); + final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( + initialRouteInformation: RouteInformation( + uri: Uri.parse('initial'), + ), + ); + addTearDown(provider.dispose); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>( - routeInformationProvider: PlatformRouteInformationProvider( - initialRouteInformation: RouteInformation( - uri: Uri.parse('initial'), - ), - ), + routeInformationProvider: provider, routeInformationParser: SimpleRouteInformationParser(), - routerDelegate: SimpleNavigatorRouterDelegate( + routerDelegate: delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); }, @@ -280,9 +300,14 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('CupertinoApp has correct default ScrollBehavior', (WidgetTester tester) async { + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + )); + + testWidgetsWithLeakTracking('CupertinoApp has correct default ScrollBehavior', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( CupertinoApp( @@ -297,7 +322,7 @@ void main() { expect(ScrollConfiguration.of(capturedContext).runtimeType, CupertinoScrollBehavior); }); - testWidgets('A ScrollBehavior can be set for CupertinoApp', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A ScrollBehavior can be set for CupertinoApp', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( CupertinoApp( @@ -315,7 +340,7 @@ void main() { expect(scrollBehavior.getScrollPhysics(capturedContext).runtimeType, NeverScrollableScrollPhysics); }); - testWidgets('When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('When `useInheritedMediaQuery` is true an existing MediaQuery is used if one is available', (WidgetTester tester) async { late BuildContext capturedContext; final UniqueKey uniqueKey = UniqueKey(); await tester.pumpWidget( @@ -335,7 +360,7 @@ void main() { expect(capturedContext.dependOnInheritedWidgetOfExactType<MediaQuery>()?.key, uniqueKey); }); - testWidgets('Text color is correctly resolved when CupertinoThemeData.brightness is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text color is correctly resolved when CupertinoThemeData.brightness is null', (WidgetTester tester) async { debugBrightnessOverride = Brightness.dark; await tester.pumpWidget( @@ -374,7 +399,7 @@ void main() { debugBrightnessOverride = null; }); - testWidgets('Cursor color is resolved when CupertinoThemeData.brightness is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor color is resolved when CupertinoThemeData.brightness is null', (WidgetTester tester) async { debugBrightnessOverride = Brightness.dark; RenderEditable findRenderEditable(WidgetTester tester) { @@ -431,7 +456,7 @@ void main() { debugBrightnessOverride = null; }); - testWidgets('Assert in buildScrollbar that controller != null when using it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Assert in buildScrollbar that controller != null when using it', (WidgetTester tester) async { const ScrollBehavior defaultBehavior = CupertinoScrollBehavior(); late BuildContext capturedContext; diff --git a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart index 04576a904d604..20c8b054aa976 100644 --- a/packages/flutter/test/cupertino/bottom_tab_bar_test.dart +++ b/packages/flutter/test/cupertino/bottom_tab_bar_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; import '../widgets/semantics_tester.dart'; @@ -29,7 +30,7 @@ Future<void> pumpWidgetWithBoilerplate(WidgetTester tester, Widget widget) async Future<void> main() async { - testWidgets('Need at least 2 tabs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Need at least 2 tabs', (WidgetTester tester) async { await expectLater( () => pumpWidgetWithBoilerplate(tester, CupertinoTabBar( items: <BottomNavigationBarItem>[ @@ -47,7 +48,7 @@ Future<void> main() async { ); }); - testWidgets('Active and inactive colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Active and inactive colors', (WidgetTester tester) async { await pumpWidgetWithBoilerplate(tester, MediaQuery( data: const MediaQueryData(), child: CupertinoTabBar( @@ -81,7 +82,7 @@ Future<void> main() async { }); - testWidgets('BottomNavigationBar.label will create a text widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('BottomNavigationBar.label will create a text widget', (WidgetTester tester) async { await pumpWidgetWithBoilerplate(tester, MediaQuery( data: const MediaQueryData(), child: CupertinoTabBar( @@ -103,7 +104,7 @@ Future<void> main() async { expect(find.text('Tab 2'), findsOneWidget); }); - testWidgets('Active and inactive colors dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Active and inactive colors dark mode', (WidgetTester tester) async { const CupertinoDynamicColor dynamicActiveColor = CupertinoDynamicColor.withBrightness( color: Color(0xFF000000), darkColor: Color(0xFF000001), @@ -191,7 +192,7 @@ Future<void> main() async { expect(decoration2.border!.top.color.value, 0x29000000); }); - testWidgets('Tabs respects themes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tabs respects themes', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoTabBar( @@ -255,7 +256,7 @@ Future<void> main() async { expect(actualActive.text.style!.color, isSameColorAs(CupertinoColors.activeBlue.darkColor)); }); - testWidgets('Use active icon', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Use active icon', (WidgetTester tester) async { final MemoryImage activeIcon = MemoryImage(Uint8List.fromList(kBlueSquarePng)); final MemoryImage inactiveIcon = MemoryImage(Uint8List.fromList(kTransparentImage)); @@ -288,7 +289,7 @@ Future<void> main() async { expect(image.image, activeIcon); }); - testWidgets('Adjusts height to account for bottom padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adjusts height to account for bottom padding', (WidgetTester tester) async { final CupertinoTabBar tabBar = CupertinoTabBar( items: <BottomNavigationBarItem>[ BottomNavigationBarItem( @@ -327,7 +328,7 @@ Future<void> main() async { expect(tester.getSize(find.byType(CupertinoTabBar)).height, 90.0); }); - testWidgets('Set custom height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Set custom height', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/51704 const double tabBarHeight = 56.0; final CupertinoTabBar tabBar = CupertinoTabBar( @@ -370,7 +371,7 @@ Future<void> main() async { expect(tester.getSize(find.byType(CupertinoTabBar)).height, tabBarHeight + bottomPadding); }); - testWidgets('Ensure bar height will not change when toggle keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ensure bar height will not change when toggle keyboard', (WidgetTester tester) async { const double tabBarHeight = 56.0; final CupertinoTabBar tabBar = CupertinoTabBar( height: tabBarHeight, @@ -424,7 +425,7 @@ Future<void> main() async { expect(tester.getSize(find.byType(CupertinoTabBar)).height, tabBarHeight + bottomPadding); }); - testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Opaque background does not add blur effects', (WidgetTester tester) async { await pumpWidgetWithBoilerplate(tester, MediaQuery( data: const MediaQueryData(), child: CupertinoTabBar( @@ -463,7 +464,7 @@ Future<void> main() async { expect(find.byType(BackdropFilter), findsNothing); }); - testWidgets('Tap callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap callback', (WidgetTester tester) async { late int callbackTab; await pumpWidgetWithBoilerplate(tester, MediaQuery( @@ -491,7 +492,7 @@ Future<void> main() async { expect(callbackTab, 1); }); - testWidgets('tabs announce semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tabs announce semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await pumpWidgetWithBoilerplate(tester, MediaQuery( @@ -526,7 +527,7 @@ Future<void> main() async { semantics.dispose(); }); - testWidgets('Label of items should be nullable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Label of items should be nullable', (WidgetTester tester) async { final MemoryImage iconProvider = MemoryImage(Uint8List.fromList(kTransparentImage)); final List<int> itemsTapped = <int>[]; @@ -563,7 +564,7 @@ Future<void> main() async { expect(itemsTapped, <int>[1]); }); - testWidgets('Hide border hides the top border of the tabBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hide border hides the top border of the tabBar', (WidgetTester tester) async { await pumpWidgetWithBoilerplate( tester, MediaQuery( @@ -623,7 +624,7 @@ Future<void> main() async { expect(boxDecorationHiddenBorder.border, isNull); }); - testWidgets('Hovering over tab bar item updates cursor to clickable on Web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovering over tab bar item updates cursor to clickable on Web', (WidgetTester tester) async { await pumpWidgetWithBoilerplate( tester, MediaQuery( diff --git a/packages/flutter/test/cupertino/button_test.dart b/packages/flutter/test/cupertino/button_test.dart index e5e0cae05a4bb..b3587ae7fdd76 100644 --- a/packages/flutter/test/cupertino/button_test.dart +++ b/packages/flutter/test/cupertino/button_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -17,7 +18,7 @@ const TextStyle testStyle = TextStyle( ); void main() { - testWidgets('Default layout minimum size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default layout minimum size', (WidgetTester tester) async { await tester.pumpWidget( boilerplate(child: const CupertinoButton( onPressed: null, @@ -32,7 +33,7 @@ void main() { ); }); - testWidgets('Minimum size parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Minimum size parameter', (WidgetTester tester) async { const double minSize = 60.0; await tester.pumpWidget( boilerplate(child: const CupertinoButton( @@ -49,7 +50,7 @@ void main() { ); }); - testWidgets('Size grows with text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Size grows with text', (WidgetTester tester) async { await tester.pumpWidget( boilerplate(child: const CupertinoButton( onPressed: null, @@ -102,7 +103,7 @@ void main() { }); */ - testWidgets('Button child alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button child alignment', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoButton( @@ -129,7 +130,7 @@ void main() { expect(align.alignment, Alignment.centerLeft); }); - testWidgets('Button with background is wider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button with background is wider', (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: const CupertinoButton( onPressed: null, color: Color(0xFFFFFFFF), @@ -143,7 +144,7 @@ void main() { ); }); - testWidgets('Custom padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom padding', (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: const CupertinoButton( onPressed: null, padding: EdgeInsets.all(100.0), @@ -156,7 +157,7 @@ void main() { ); }); - testWidgets('Button takes taps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button takes taps', (WidgetTester tester) async { bool value = false; await tester.pumpWidget( StatefulBuilder( @@ -195,7 +196,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Enabled button animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Enabled button animates', (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: CupertinoButton( child: const Text('Tap me'), onPressed: () { }, @@ -231,7 +232,7 @@ void main() { expect(transition.opacity.value, moreOrLessEquals(1.0, epsilon: 0.001)); }); - testWidgets('pressedOpacity defaults to 0.1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pressedOpacity defaults to 0.1', (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: CupertinoButton( child: const Text('Tap me'), onPressed: () { }, @@ -250,7 +251,7 @@ void main() { expect(opacity.opacity.value, 0.4); }); - testWidgets('pressedOpacity parameter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pressedOpacity parameter', (WidgetTester tester) async { const double pressedOpacity = 0.5; await tester.pumpWidget(boilerplate(child: CupertinoButton( pressedOpacity: pressedOpacity, @@ -271,7 +272,7 @@ void main() { expect(opacity.opacity.value, pressedOpacity); }); - testWidgets('Cupertino button is semantically a button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cupertino button is semantically a button', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( boilerplate( @@ -302,7 +303,7 @@ void main() { semantics.dispose(); }); - testWidgets('Can specify colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can specify colors', (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: CupertinoButton( color: const Color(0x000000FF), disabledColor: const Color(0x0000FF00), @@ -330,7 +331,7 @@ void main() { expect(boxDecoration.color, const Color(0x0000FF00)); }); - testWidgets('Can specify dynamic colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can specify dynamic colors', (WidgetTester tester) async { const Color bgColor = CupertinoDynamicColor.withBrightness( color: Color(0xFF123456), darkColor: Color(0xFF654321), @@ -379,7 +380,7 @@ void main() { expect(boxDecoration.color!.value, 0xFF111111); }); - testWidgets('Button respects themes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Button respects themes', (WidgetTester tester) async { late TextStyle textStyle; await tester.pumpWidget( @@ -453,7 +454,7 @@ void main() { expect(decoration.color, isSameColorAs(CupertinoColors.systemBlue.darkColor)); }); - testWidgets('Hovering over Cupertino button updates cursor to clickable on Web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovering over Cupertino button updates cursor to clickable on Web', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( diff --git a/packages/flutter/test/cupertino/checkbox_test.dart b/packages/flutter/test/cupertino/checkbox_test.dart index 601aef991d884..7f047e62cf7d3 100644 --- a/packages/flutter/test/cupertino/checkbox_test.dart +++ b/packages/flutter/test/cupertino/checkbox_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -15,7 +16,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('CupertinoCheckbox semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoCheckbox semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( @@ -155,7 +156,7 @@ void main() { handle.dispose(); }); - testWidgets('Can wrap CupertinoCheckbox with Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can wrap CupertinoCheckbox with Semantics', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); await tester.pumpWidget( @@ -183,7 +184,7 @@ void main() { handle.dispose(); }); - testWidgets('CupertinoCheckbox tristate: true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoCheckbox tristate: true', (WidgetTester tester) async { bool? checkBoxValue; await tester.pumpWidget( @@ -227,7 +228,7 @@ void main() { expect(checkBoxValue, null); }); - testWidgets('has semantics for tristate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantics for tristate', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( CupertinoApp( @@ -294,7 +295,7 @@ void main() { semantics.dispose(); }); - testWidgets('has semantic events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has semantic events', (WidgetTester tester) async { dynamic semanticEvent; bool? checkboxValue = false; tester.binding.defaultBinaryMessenger.setMockDecodedMessageHandler<dynamic>(SystemChannels.accessibility, (dynamic message) async { @@ -334,7 +335,7 @@ void main() { semanticsTester.dispose(); }); - testWidgets('Checkbox can be toggled by keyboard shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox can be toggled by keyboard shortcuts', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp({bool enabled = true}) { @@ -371,7 +372,7 @@ void main() { expect(value, isTrue); }); - testWidgets('Checkbox respects shape and side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Checkbox respects shape and side', (WidgetTester tester) async { const RoundedRectangleBorder roundedRectangleBorder = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))); diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 31d86997a8815..06b2cbb00ed06 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -1083,12 +1083,13 @@ void main() { expect(key1.currentState, isNull); }); - testWidgets('MaterialApp.router works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.router works', (WidgetTester tester) async { final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( uri: Uri.parse('initial'), ), ); + addTearDown(provider.dispose); final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -1100,6 +1101,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); await tester.pumpWidget(MaterialApp.router( routeInformationProvider: provider, routeInformationParser: SimpleRouteInformationParser(), @@ -1112,9 +1114,14 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); - - testWidgets('MaterialApp.router route information parser is optional', (WidgetTester tester) async { + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + )); + + testWidgetsWithLeakTracking('MaterialApp.router route information parser is optional', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); @@ -1126,6 +1133,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); await tester.pumpWidget(MaterialApp.router( routerDelegate: delegate, @@ -1137,7 +1145,12 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + )); testWidgetsWithLeakTracking('MaterialApp.router throw if route information provider is provided but no route information parser', (WidgetTester tester) async { final SimpleNavigatorRouterDelegate delegate = SimpleNavigatorRouterDelegate( @@ -1151,6 +1164,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); final PlatformRouteInformationProvider provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( @@ -1177,6 +1191,7 @@ void main() { return route.didPop(result); }, ); + addTearDown(delegate.dispose); delegate.routeInformation = RouteInformation(uri: Uri.parse('initial')); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>(routerDelegate: delegate); await tester.pumpWidget(MaterialApp.router( @@ -1186,15 +1201,19 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('MaterialApp.router router config works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp.router router config works', (WidgetTester tester) async { + late SimpleNavigatorRouterDelegate routerDelegate; + addTearDown(() => routerDelegate.dispose()); + late PlatformRouteInformationProvider provider; + addTearDown(() => provider.dispose()); final RouterConfig<RouteInformation> routerConfig = RouterConfig<RouteInformation>( - routeInformationProvider: PlatformRouteInformationProvider( + routeInformationProvider: provider = PlatformRouteInformationProvider( initialRouteInformation: RouteInformation( uri: Uri.parse('initial'), ), ), routeInformationParser: SimpleRouteInformationParser(), - routerDelegate: SimpleNavigatorRouterDelegate( + routerDelegate: routerDelegate = SimpleNavigatorRouterDelegate( builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); }, @@ -1217,7 +1236,12 @@ void main() { await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) { }); await tester.pumpAndSettle(); expect(find.text('popped'), findsOneWidget); - }); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + leakTrackingTestConfig: const LeakTrackingTestConfig( + allowAllNotDisposed: true, + )); testWidgetsWithLeakTracking('MaterialApp.builder can build app without a Navigator', (WidgetTester tester) async { Widget? builderChild; @@ -1545,7 +1569,9 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit SimpleNavigatorRouterDelegate({ required this.builder, required this.onPopPage, - }); + }) { + maybeDispatchObjectCreation(); + } @override GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); diff --git a/packages/flutter/test/material/calendar_date_picker_test.dart b/packages/flutter/test/material/calendar_date_picker_test.dart index 7dcf81209da9e..7caae93b9a770 100644 --- a/packages/flutter/test/material/calendar_date_picker_test.dart +++ b/packages/flutter/test/material/calendar_date_picker_test.dart @@ -77,7 +77,7 @@ void main() { } group('CalendarDatePicker', () { - testWidgets('Can select a day', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a day', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -87,7 +87,7 @@ void main() { expect(selectedDate, equals(DateTime(2016, DateTime.january, 12))); }); - testWidgets('Can select a day with nothing first selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a day with nothing first selected', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( onDateChanged: (DateTime date) => selectedDate = date, @@ -96,7 +96,7 @@ void main() { expect(selectedDate, equals(DateTime(2016, DateTime.january, 12))); }); - testWidgets('Can select a month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a month', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -121,7 +121,7 @@ void main() { expect(displayedMonth, equals(DateTime(2015, DateTime.december))); }); - testWidgets('Can select a month with nothing first selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a month with nothing first selected', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, @@ -145,7 +145,7 @@ void main() { expect(displayedMonth, equals(DateTime(2015, DateTime.december))); }); - testWidgets('Can select a year', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -160,7 +160,7 @@ void main() { expect(displayedMonth, equals(DateTime(2018))); }); - testWidgets('Can select a year with nothing first selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year with nothing first selected', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( onDisplayedMonthChanged: (DateTime date) => displayedMonth = date, @@ -174,7 +174,7 @@ void main() { expect(displayedMonth, equals(DateTime(2018))); }); - testWidgets('Selecting date does not change displayed month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting date does not change displayed month', (WidgetTester tester) async { DateTime? selectedDate; DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( @@ -197,7 +197,7 @@ void main() { expect(find.text('31'), findsNothing); }); - testWidgets('Changing year does change selected date', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing year does change selected date', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -249,7 +249,7 @@ void main() { expect(displayedMonth, equals(DateTime(2018, DateTime.march))); }); - testWidgets('Can select a year and then a day', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year and then a day', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -263,7 +263,7 @@ void main() { expect(selectedDate, equals(DateTime(2017, DateTime.january, 19))); }); - testWidgets('Cannot select a day outside bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select a day outside bounds', (WidgetTester tester) async { final DateTime validDate = DateTime(2017, DateTime.january, 15); DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( @@ -286,7 +286,7 @@ void main() { expect(selectedDate, validDate); }); - testWidgets('Cannot navigate to a month outside bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot navigate to a month outside bounds', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( firstDate: DateTime(2016, DateTime.december, 15), @@ -310,7 +310,7 @@ void main() { expect(previousMonthIcon, findsNothing); }); - testWidgets('Cannot select disabled year', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select disabled year', (WidgetTester tester) async { DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( firstDate: DateTime(2018, DateTime.june, 9), @@ -331,7 +331,7 @@ void main() { expect(displayedMonth, isNull); }); - testWidgets('Selecting firstDate year respects firstDate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting firstDate year respects firstDate', (WidgetTester tester) async { DateTime? selectedDate; DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( @@ -351,7 +351,7 @@ void main() { expect(selectedDate, DateTime(2016, DateTime.june, 9)); }); - testWidgets('Selecting lastDate year respects lastDate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting lastDate year respects lastDate', (WidgetTester tester) async { DateTime? selectedDate; DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( @@ -373,7 +373,7 @@ void main() { expect(selectedDate, DateTime(2019, DateTime.january, 4)); }); - testWidgets('Selecting lastDate year respects lastDate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting lastDate year respects lastDate', (WidgetTester tester) async { DateTime? selectedDate; DateTime? displayedMonth; await tester.pumpWidget(calendarDatePicker( @@ -396,7 +396,7 @@ void main() { expect(selectedDate, DateTime(2019, DateTime.january, 4)); }); - testWidgets('Only predicate days are selectable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Only predicate days are selectable', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( firstDate: DateTime(2017, DateTime.january, 10), @@ -413,7 +413,7 @@ void main() { expect(selectedDate, DateTime(2017, DateTime.january, 10)); }); - testWidgets('Can select initial calendar picker mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select initial calendar picker mode', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2014, DateTime.january, 15), initialCalendarMode: DatePickerMode.year, @@ -425,7 +425,7 @@ void main() { expect(find.text('January 2018'), findsOneWidget); }); - testWidgets('Material2 - currentDate is highlighted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( useMaterial3: false, initialDate: DateTime(2016, DateTime.january, 15), @@ -443,7 +443,7 @@ void main() { ); }); - testWidgets('Material3 - currentDate is highlighted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - currentDate is highlighted', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( useMaterial3: true, initialDate: DateTime(2016, DateTime.january, 15), @@ -461,7 +461,7 @@ void main() { ); }); - testWidgets('Material2 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( useMaterial3: false, firstDate: DateTime(2016, 1, 3), @@ -482,7 +482,7 @@ void main() { ); }); - testWidgets('Material3 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - currentDate is highlighted even if it is disabled', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( useMaterial3: true, firstDate: DateTime(2016, 1, 3), @@ -503,7 +503,7 @@ void main() { ); }); - testWidgets('Selecting date does not switch picker to year selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting date does not switch picker to year selection', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2020, DateTime.may, 10), initialCalendarMode: DatePickerMode.year, @@ -517,7 +517,7 @@ void main() { expect(find.text('2017'), findsNothing); }); - testWidgets('Selecting disabled date does not change current selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting disabled date does not change current selection', (WidgetTester tester) async { DateTime day(int day) => DateTime(2020, DateTime.may, day); DateTime selection = day(2); @@ -542,7 +542,7 @@ void main() { }); for (final bool useMaterial3 in <bool>[false, true]) { - testWidgets('Updates to initialDate parameter are not reflected in the state (useMaterial3=$useMaterial3)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updates to initialDate parameter are not reflected in the state (useMaterial3=$useMaterial3)', (WidgetTester tester) async { final Key pickerKey = UniqueKey(); final DateTime initialDate = DateTime(2020, 1, 21); final DateTime updatedDate = DateTime(1976, 2, 23); @@ -592,7 +592,7 @@ void main() { }); } - testWidgets('Updates to initialCalendarMode parameter is not reflected in the state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updates to initialCalendarMode parameter is not reflected in the state', (WidgetTester tester) async { final Key pickerKey = UniqueKey(); await tester.pumpWidget(calendarDatePicker( @@ -619,7 +619,7 @@ void main() { expect(find.text('2016'), findsOneWidget); // 2016 in year grid }); - testWidgets('Dragging more than half the width should not cause a jump', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dragging more than half the width should not cause a jump', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), )); @@ -641,7 +641,7 @@ void main() { }); group('Keyboard navigation', () { - testWidgets('Can toggle to year mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can toggle to year mode', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), )); @@ -656,7 +656,7 @@ void main() { expect(find.text('January 2016'), findsOneWidget); }); - testWidgets('Can navigate next/previous months', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can navigate next/previous months', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), )); @@ -685,7 +685,7 @@ void main() { expect(find.text('March 2016'), findsOneWidget); }); - testWidgets('Can navigate date grid with arrow keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can navigate date grid with arrow keys', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -715,7 +715,7 @@ void main() { expect(selectedDate, DateTime(2016, DateTime.january, 18)); }); - testWidgets('Navigating with arrow keys scrolls months', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigating with arrow keys scrolls months', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -756,7 +756,7 @@ void main() { expect(selectedDate, DateTime(2015, DateTime.november, 26)); }); - testWidgets('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RTL text direction reverses the horizontal arrow key navigation', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), @@ -800,7 +800,7 @@ void main() { feedback.dispose(); }); - testWidgets('Selecting date vibrates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting date vibrates', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), )); @@ -815,7 +815,7 @@ void main() { expect(feedback.hapticCount, 3); }); - testWidgets('Tapping unselectable date does not vibrate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping unselectable date does not vibrate', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 10), selectableDayPredicate: (DateTime date) => date.day.isEven, @@ -831,7 +831,7 @@ void main() { expect(feedback.hapticCount, 0); }); - testWidgets('Changing modes and year vibrates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing modes and year vibrates', (WidgetTester tester) async { await tester.pumpWidget(calendarDatePicker( initialDate: DateTime(2016, DateTime.january, 15), )); @@ -845,7 +845,7 @@ void main() { }); group('Semantics', () { - testWidgets('day mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('day mode', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); await tester.pumpWidget(calendarDatePicker( @@ -1061,7 +1061,7 @@ void main() { semantics.dispose(); }); - testWidgets('calendar year mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('calendar year mode', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); await tester.pumpWidget(calendarDatePicker( @@ -1091,12 +1091,12 @@ void main() { }); group('YearPicker', () { - testWidgets('Current year is visible in year picker', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Current year is visible in year picker', (WidgetTester tester) async { await tester.pumpWidget(yearPicker()); expect(find.text('2016'), findsOneWidget); }); - testWidgets('Can select a year', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select a year', (WidgetTester tester) async { DateTime? selectedDate; await tester.pumpWidget(yearPicker( onChanged: (DateTime date) => selectedDate = date, @@ -1107,7 +1107,7 @@ void main() { expect(selectedDate, equals(DateTime(2018))); }); - testWidgets('Cannot select disabled year', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot select disabled year', (WidgetTester tester) async { DateTime? selectedYear; await tester.pumpWidget(yearPicker( firstDate: DateTime(2018, DateTime.june, 9), @@ -1126,7 +1126,7 @@ void main() { expect(selectedYear, equals(DateTime(2018, DateTime.july))); }); - testWidgets('Selecting year with no selected month uses earliest month', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting year with no selected month uses earliest month', (WidgetTester tester) async { DateTime? selectedYear; await tester.pumpWidget(yearPicker( firstDate: DateTime(2018, DateTime.june, 9), @@ -1145,7 +1145,7 @@ void main() { expect(selectedYear, equals(DateTime(2019, DateTime.june))); }); - testWidgets('Selecting year with no selected month uses January', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selecting year with no selected month uses January', (WidgetTester tester) async { DateTime? selectedYear; await tester.pumpWidget(yearPicker( firstDate: DateTime(2018, DateTime.june, 9), diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index 992bd5947b05c..d95f4fbad7a24 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -703,11 +703,13 @@ void main() { expect(calledDelete, isFalse); }); - testWidgets('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Chip elements are ordered horizontally for locale', (WidgetTester tester) async { final UniqueKey iconKey = UniqueKey(); + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); final Widget test = Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Material( child: Chip( @@ -882,11 +884,14 @@ void main() { testWidgets('Chip padding - LTR', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); await tester.pumpWidget( wrapForChip( child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Material( child: Center( @@ -918,12 +923,16 @@ void main() { testWidgets('Chip padding - RTL', (WidgetTester tester) async { final GlobalKey keyA = GlobalKey(); final GlobalKey keyB = GlobalKey(); + + late final OverlayEntry entry; + addTearDown(() => entry..remove()..dispose()); + await tester.pumpWidget( wrapForChip( textDirection: TextDirection.rtl, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + entry = OverlayEntry( builder: (BuildContext context) { return Material( child: Center( diff --git a/packages/flutter/test/widgets/undo_history_test.dart b/packages/flutter/test/widgets/undo_history_test.dart index ce09b652e4d62..dffb059bfc6ef 100644 --- a/packages/flutter/test/widgets/undo_history_test.dart +++ b/packages/flutter/test/widgets/undo_history_test.dart @@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'editable_text_utils.dart'; -final FocusNode focusNode = FocusNode(debugLabel: 'UndoHistory Node'); +final FocusNode _focusNode = FocusNode(debugLabel: 'UndoHistory Node'); void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -41,7 +41,7 @@ void main() { onTriggered: (int newValue) { value.value = newValue; }, - focusNode: focusNode, + focusNode: _focusNode, child: Container(), ), ), @@ -57,7 +57,7 @@ void main() { controller.redo(); expect(value.value, 0); - focusNode.requestFocus(); + _focusNode.requestFocus(); await tester.pump(); expect(controller.value.canUndo, false); expect(controller.value.canRedo, false); @@ -130,9 +130,9 @@ void main() { onTriggered: (int newValue) { value.value = newValue; }, - focusNode: focusNode, + focusNode: _focusNode, child: Focus( - focusNode: focusNode, + focusNode: _focusNode, child: Container(), ), ), @@ -149,7 +149,7 @@ void main() { await sendRedo(tester); expect(value.value, 0); - focusNode.requestFocus(); + _focusNode.requestFocus(); await tester.pump(); expect(controller.value.canUndo, false); expect(controller.value.canRedo, false); @@ -222,13 +222,13 @@ void main() { onTriggered: (int newValue) { value.value = newValue; }, - focusNode: focusNode, + focusNode: _focusNode, child: Container(), ), ), ); - focusNode.requestFocus(); + _focusNode.requestFocus(); // Wait for the throttling. await tester.pump(const Duration(milliseconds: 500)); @@ -275,7 +275,7 @@ void main() { onTriggered: (int newValue) { value.value = valueToUse(newValue); }, - focusNode: focusNode, + focusNode: _focusNode, child: Container(), ), ), @@ -291,7 +291,7 @@ void main() { controller.redo(); expect(value.value, 0); - focusNode.requestFocus(); + _focusNode.requestFocus(); await tester.pump(); expect(controller.value.canUndo, false); expect(controller.value.canRedo, false); @@ -389,9 +389,9 @@ void main() { onTriggered: (int newValue) { value.value = newValue; }, - focusNode: focusNode, + focusNode: _focusNode, child: Focus( - focusNode: focusNode, + focusNode: _focusNode, child: Container(), ), ), @@ -399,7 +399,7 @@ void main() { ); await tester.pump(const Duration(milliseconds: 500)); - focusNode.requestFocus(); + _focusNode.requestFocus(); await tester.pump(); // Undo/redo have no effect if the value has never changed. From 2396a417e32ea0600419099d2402e75224ae194b Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Mon, 18 Sep 2023 22:46:29 +0200 Subject: [PATCH 1326/1547] Cover more test/widgets tests with leak tracking #6 (#134884) --- .../test/widgets/notification_test.dart | 11 +- .../widgets/obscured_animated_image_test.dart | 3 +- .../test/widgets/opacity_repaint_test.dart | 5 +- .../flutter/test/widgets/opacity_test.dart | 14 +- .../test/widgets/overflow_bar_test.dart | 17 +- .../test/widgets/overflow_box_test.dart | 9 +- .../test/widgets/overlay_portal_test.dart | 224 +++++++++++++----- .../widgets/overscroll_indicator_test.dart | 33 +-- .../overscroll_stretch_indicator_test.dart | 69 ++++-- .../page_forward_transitions_test.dart | 5 +- .../test/widgets/page_route_builder_test.dart | 5 +- .../test/widgets/page_storage_test.dart | 5 +- .../test/widgets/page_transitions_test.dart | 11 +- .../flutter/test/widgets/page_view_test.dart | 100 ++++---- .../test/widgets/pageable_list_test.dart | 11 +- .../test/widgets/parent_data_test.dart | 11 +- .../widgets/performance_overlay_test.dart | 7 +- .../test/widgets/physical_model_test.dart | 7 +- .../test/widgets/placeholder_test.dart | 9 +- .../test/widgets/platform_menu_bar_test.dart | 13 +- 20 files changed, 366 insertions(+), 203 deletions(-) diff --git a/packages/flutter/test/widgets/notification_test.dart b/packages/flutter/test/widgets/notification_test.dart index e58d86f2f06e0..ddfa0d23111e8 100644 --- a/packages/flutter/test/widgets/notification_test.dart +++ b/packages/flutter/test/widgets/notification_test.dart @@ -4,15 +4,16 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class MyNotification extends Notification { } void main() { - testWidgets('Notification basics - toString', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Notification basics - toString', (WidgetTester tester) async { expect(MyNotification(), hasOneLineDescription); }); - testWidgets('Notification basics - dispatch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Notification basics - dispatch', (WidgetTester tester) async { final List<dynamic> log = <dynamic>[]; final GlobalKey key = GlobalKey(); await tester.pumpWidget(NotificationListener<MyNotification>( @@ -36,7 +37,7 @@ void main() { expect(log, <dynamic>['b', notification, 'a', notification]); }); - testWidgets('Notification basics - cancel', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Notification basics - cancel', (WidgetTester tester) async { final List<dynamic> log = <dynamic>[]; final GlobalKey key = GlobalKey(); await tester.pumpWidget(NotificationListener<MyNotification>( @@ -60,7 +61,7 @@ void main() { expect(log, <dynamic>['b', notification]); }); - testWidgets('Notification basics - listener null return value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Notification basics - listener null return value', (WidgetTester tester) async { final List<Type> log = <Type>[]; final GlobalKey key = GlobalKey(); await tester.pumpWidget(NotificationListener<MyNotification>( @@ -77,7 +78,7 @@ void main() { expect(log, <Type>[MyNotification]); }); - testWidgets('Notification basics - listener null return value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Notification basics - listener null return value', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); final ScrollMetricsNotification n1 = ScrollMetricsNotification( metrics: FixedScrollMetrics( diff --git a/packages/flutter/test/widgets/obscured_animated_image_test.dart b/packages/flutter/test/widgets/obscured_animated_image_test.dart index 788d8f2d4905f..179df2c1a8e0b 100644 --- a/packages/flutter/test/widgets/obscured_animated_image_test.dart +++ b/packages/flutter/test/widgets/obscured_animated_image_test.dart @@ -8,6 +8,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; import '../painting/fake_codec.dart'; @@ -17,7 +18,7 @@ Future<void> main() async { final FakeCodec fakeCodec = await FakeCodec.fromData(Uint8List.fromList(kAnimatedGif)); final FakeImageProvider fakeImageProvider = FakeImageProvider(fakeCodec); - testWidgets('Obscured image does not animate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Obscured image does not animate', (WidgetTester tester) async { final GlobalKey imageKey = GlobalKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/opacity_repaint_test.dart b/packages/flutter/test/widgets/opacity_repaint_test.dart index b0aff87cd6753..c858380ef5a11 100644 --- a/packages/flutter/test/widgets/opacity_repaint_test.dart +++ b/packages/flutter/test/widgets/opacity_repaint_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('RenderOpacity avoids repainting and does not drop layer at fully opaque', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderOpacity avoids repainting and does not drop layer at fully opaque', (WidgetTester tester) async { RenderTestObject.paintCount = 0; await tester.pumpWidget( const ColoredBox( @@ -46,7 +47,7 @@ void main() { expect(RenderTestObject.paintCount, 1); }); - testWidgets('RenderOpacity allows opacity layer to be dropped at 0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderOpacity allows opacity layer to be dropped at 0 opacity', (WidgetTester tester) async { RenderTestObject.paintCount = 0; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/opacity_test.dart b/packages/flutter/test/widgets/opacity_test.dart index 197720dcc22a1..a638dcfe2029a 100644 --- a/packages/flutter/test/widgets/opacity_test.dart +++ b/packages/flutter/test/widgets/opacity_test.dart @@ -7,14 +7,17 @@ @Tags(<String>['reduced-test-set']) library; +import 'dart:ui' as ui; + import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Opacity', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // Opacity 1.0: Semantics and painting @@ -151,7 +154,7 @@ void main() { semantics.dispose(); }); - testWidgets('offset is correctly handled in Opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('offset is correctly handled in Opacity', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -184,7 +187,7 @@ void main() { ); }); - testWidgets('empty opacity does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('empty opacity does not crash', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary(child: Opacity(opacity: 0.5, child: Container())), ); @@ -192,10 +195,11 @@ void main() { // The following line will send the layer to engine and cause crash if an // empty opacity layer is sent. final OffsetLayer offsetLayer = element.renderObject!.debugLayer! as OffsetLayer; - await offsetLayer.toImage(const Rect.fromLTRB(0.0, 0.0, 1.0, 1.0)); + final ui.Image image = await offsetLayer.toImage(const Rect.fromLTRB(0.0, 0.0, 1.0, 1.0)); + image.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/49857 - testWidgets('Child shows up in the right spot when opacity is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Child shows up in the right spot when opacity is disabled', (WidgetTester tester) async { debugDisableOpacityLayers = true; final GlobalKey key = GlobalKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/overflow_bar_test.dart b/packages/flutter/test/widgets/overflow_bar_test.dart index d8e9520b20cd2..3145df151320a 100644 --- a/packages/flutter/test/widgets/overflow_bar_test.dart +++ b/packages/flutter/test/widgets/overflow_bar_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('OverflowBar documented defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar documented defaults', (WidgetTester tester) async { const OverflowBar bar = OverflowBar(); expect(bar.spacing, 0); expect(bar.alignment, null); @@ -17,7 +18,7 @@ void main() { expect(bar.children, const <Widget>[]); }); - testWidgets('Empty OverflowBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty OverflowBar', (WidgetTester tester) async { const Size size = Size(16, 24); await tester.pumpWidget( @@ -46,7 +47,7 @@ void main() { expect(tester.getSize(find.byType(OverflowBar)), Size.zero); }); - testWidgets('OverflowBar horizontal layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar horizontal layout', (WidgetTester tester) async { final Key child1Key = UniqueKey(); final Key child2Key = UniqueKey(); final Key child3Key = UniqueKey(); @@ -93,7 +94,7 @@ void main() { expect(tester.getRect(find.byKey(child1Key)), const Rect.fromLTRB(10.0 + 96 + 10.0, 8, 10.0 + 10.0 + 144, 56)); }); - testWidgets('OverflowBar vertical layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar vertical layout', (WidgetTester tester) async { final Key child1Key = UniqueKey(); final Key child2Key = UniqueKey(); final Key child3Key = UniqueKey(); @@ -174,7 +175,7 @@ void main() { expect(tester.getRect(find.byKey(child3Key)), const Rect.fromLTRB(100.0/2.0 - 32/2, 112, 100.0/2.0 + 32/2, 144)); }); - testWidgets('OverflowBar intrinsic width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar intrinsic width', (WidgetTester tester) async { Widget buildFrame({ required double width }) { return Directionality( textDirection: TextDirection.ltr, @@ -205,7 +206,7 @@ void main() { expect(tester.getSize(find.byType(OverflowBar)).width, 150); }); - testWidgets('OverflowBar intrinsic height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar intrinsic height', (WidgetTester tester) async { Widget buildFrame({ required double maxWidth }) { return Directionality( textDirection: TextDirection.ltr, @@ -237,7 +238,7 @@ void main() { }); - testWidgets('OverflowBar is wider that its intrinsic width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar is wider that its intrinsic width', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); @@ -273,7 +274,7 @@ void main() { expect(tester.getTopLeft(find.byKey(key2)).dx, 600); }); - testWidgets('OverflowBar with alignment should match Row with mainAxisAlignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBar with alignment should match Row with mainAxisAlignment', (WidgetTester tester) async { final Key key0 = UniqueKey(); final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); diff --git a/packages/flutter/test/widgets/overflow_box_test.dart b/packages/flutter/test/widgets/overflow_box_test.dart index 2cb07611145f4..bc97f50e7f094 100644 --- a/packages/flutter/test/widgets/overflow_box_test.dart +++ b/packages/flutter/test/widgets/overflow_box_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('OverflowBox control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBox control test', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(Align( alignment: Alignment.bottomRight, @@ -30,7 +31,7 @@ void main() { expect(box.size, equals(const Size(100.0, 50.0))); }); - testWidgets('OverflowBox implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('OverflowBox implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const OverflowBox( minWidth: 1.0, @@ -50,7 +51,7 @@ void main() { ]); }); - testWidgets('SizedOverflowBox alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizedOverflowBox alignment', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.rtl, @@ -73,7 +74,7 @@ void main() { ); }); - testWidgets('SizedOverflowBox alignment (direction-sensitive)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizedOverflowBox alignment (direction-sensitive)', (WidgetTester tester) async { final GlobalKey inner = GlobalKey(); await tester.pumpWidget(Directionality( textDirection: TextDirection.rtl, diff --git a/packages/flutter/test/widgets/overlay_portal_test.dart b/packages/flutter/test/widgets/overlay_portal_test.dart index d361f0c5d6b61..22d624b9c0b76 100644 --- a/packages/flutter/test/widgets/overlay_portal_test.dart +++ b/packages/flutter/test/widgets/overlay_portal_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _ManyRelayoutBoundaries extends StatelessWidget { const _ManyRelayoutBoundaries({ @@ -94,18 +95,20 @@ void main() { _PaintOrder.paintOrder.clear(); }); - testWidgets('The overlay child sees the right inherited widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The overlay child sees the right inherited widgets', (WidgetTester tester) async { int buildCount = 0; TextDirection? directionSeenByOverlayChild; TextDirection textDirection = TextDirection.rtl; late StateSetter setState; + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -141,13 +144,16 @@ void main() { expect(directionSeenByOverlayChild, textDirection); }); - testWidgets('Safe to deactivate and re-activate OverlayPortal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe to deactivate and re-activate OverlayPortal', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + final Widget widget = Directionality( key: GlobalKey(debugLabel: 'key'), textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( controller: controller1, @@ -164,14 +170,17 @@ void main() { await tester.pumpWidget(SizedBox(child: widget)); }); - testWidgets('Safe to hide overlay child and remove OverlayPortal in the same frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe to hide overlay child and remove OverlayPortal in the same frame', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/129025. + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + final Widget widget = Directionality( key: GlobalKey(debugLabel: 'key'), textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( controller: controller1, @@ -192,7 +201,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Safe to hide overlay child and reparent OverlayPortal in the same frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe to hide overlay child and reparent OverlayPortal in the same frame', (WidgetTester tester) async { final OverlayPortal overlayPortal = OverlayPortal( key: GlobalKey(debugLabel: 'key'), controller: controller1, @@ -202,12 +211,14 @@ void main() { List<Widget> children = <Widget>[ const SizedBox(), overlayPortal ]; + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); late StateSetter setState; final Widget widget = Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry( + overlayEntry = OverlayStatefulEntry( builder: (BuildContext context, StateSetter setter) { setState = setter; return Column(children: children); @@ -228,13 +239,16 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Safe to hide overlay child and reparent OverlayPortal in the same frame 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe to hide overlay child and reparent OverlayPortal in the same frame 2', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + final Widget widget = Directionality( key: GlobalKey(debugLabel: 'key'), textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( controller: controller1, @@ -255,14 +269,17 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('No relayout boundary between OverlayPortal and Overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No relayout boundary between OverlayPortal and Overlay', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/133545. + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); final GlobalKey key = GlobalKey(debugLabel: 'key'); + final Widget widget = Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { // The Positioned widget prevents a relayout boundary from being // introduced between the Overlay and OverlayPortal. @@ -326,14 +343,17 @@ void main() { ); }); - testWidgets('show/hide works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('show/hide works', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); final OverlayPortalController controller = OverlayPortalController(debugLabel: 'local controller'); + const Widget target = SizedBox(); final Widget widget = Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( controller: controller, @@ -364,13 +384,16 @@ void main() { expect(find.byWidget(target), findsOneWidget); }); - testWidgets('overlayChildBuilder is not evaluated until show is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overlayChildBuilder is not evaluated until show is called', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); final OverlayPortalController controller = OverlayPortalController(debugLabel: 'local controller'); + final Widget widget = Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( controller: controller, @@ -387,16 +410,18 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('overlay child can use Positioned', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overlay child can use Positioned', (WidgetTester tester) async { double dimensions = 30; late StateSetter setState; + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -433,9 +458,11 @@ void main() { expect(tester.getSize(find.byType(Placeholder)), const Size(50, 50)) ; }); - testWidgets('overlay child can be hit tested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overlay child can be hit tested', (WidgetTester tester) async { double offset = 0; late StateSetter setState; + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); bool isHit = false; await tester.pumpWidget( @@ -443,7 +470,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter setter) { @@ -488,13 +515,16 @@ void main() { expect(isHit, true); }); - testWidgets('works in a LayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in a LayoutBuilder', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -515,7 +545,9 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('works in a LayoutBuilder 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in a LayoutBuilder 2', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); late StateSetter setState; bool shouldShowChild = false; @@ -532,7 +564,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter setter) { + overlayEntry = OverlayStatefulEntry(builder: (BuildContext context, StateSetter setter) { setState = setter; return OverlayPortal( controller: controller1, @@ -552,7 +584,9 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('works in a LayoutBuilder 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('works in a LayoutBuilder 3', (WidgetTester tester) async { + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); late StateSetter setState; bool shouldShowChild = false; @@ -571,7 +605,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter setter) { + overlayEntry = OverlayStatefulEntry(builder: (BuildContext context, StateSetter setter) { setState = setter; // The Positioned widget ensures there's no relayout boundary // between the Overlay and the OverlayPortal. @@ -598,7 +632,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('throws when no Overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('throws when no Overlay', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -626,10 +660,12 @@ void main() { ); }); - testWidgets('widget is laid out before overlay child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('widget is laid out before overlay child', (WidgetTester tester) async { final GlobalKey widgetKey = GlobalKey(debugLabel: 'widget'); final RenderBox childBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); final RenderBox overlayChildBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); int layoutCount = 0; await tester.pumpWidget( @@ -637,7 +673,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return _ManyRelayoutBoundaries(levels: 50, child: Builder(builder: (BuildContext context) { return OverlayPortal( @@ -679,12 +715,16 @@ void main() { verifyTreeIsClean(); }); - testWidgets('adding/removing overlay child does not redirty overlay more than once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('adding/removing overlay child does not redirty overlay more than once', (WidgetTester tester) async { final GlobalKey widgetKey = GlobalKey(debugLabel: 'widget'); final GlobalKey overlayKey = GlobalKey(debugLabel: 'overlay'); final RenderBox childBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); final RenderBox overlayChildBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); final _RenderLayoutCounter overlayLayoutCounter = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); int layoutCount = 0; controller1.hide(); @@ -695,8 +735,8 @@ void main() { key: overlayKey, initialEntries: <OverlayEntry>[ // Overlay.performLayout will call layoutCounter.layout. - OverlayEntry(builder: (BuildContext context) => WidgetToRenderBoxAdapter(renderBox: overlayLayoutCounter)), - OverlayEntry( + overlayEntry1 = OverlayEntry(builder: (BuildContext context) => WidgetToRenderBoxAdapter(renderBox: overlayLayoutCounter)), + overlayEntry2 = OverlayEntry( builder: (BuildContext context) { return _ManyRelayoutBoundaries(levels: 50, child: Builder(builder: (BuildContext context) { return OverlayPortal( @@ -737,11 +777,13 @@ void main() { verifyTreeIsClean(); }); - testWidgets('Adding/Removing OverlayPortal in LayoutBuilder during layout', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Adding/Removing OverlayPortal in LayoutBuilder during layout', (WidgetTester tester) async { final GlobalKey widgetKey = GlobalKey(debugLabel: 'widget'); final GlobalKey overlayKey = GlobalKey(debugLabel: 'overlay'); controller1.hide(); late StateSetter setState; + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); Size size = Size.zero; final Widget overlayPortal = OverlayPortal( @@ -757,7 +799,7 @@ void main() { child: Overlay( key: overlayKey, initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry = OverlayEntry( builder: (BuildContext context) { return StatefulBuilder( builder: (BuildContext context, StateSetter stateSetter) { @@ -957,7 +999,7 @@ void main() { }); group('GlobalKey Reparenting', () { - testWidgets('child is laid out before overlay child after OverlayEntry shuffle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child is laid out before overlay child after OverlayEntry shuffle', (WidgetTester tester) async { int layoutCount = 0; final GlobalKey widgetKey = GlobalKey(debugLabel: 'widget'); @@ -982,8 +1024,11 @@ void main() { }), ); }); + addTearDown(() => overlayEntry1..remove()..dispose()); final OverlayEntry overlayEntry2 = OverlayEntry(builder: (BuildContext context) => const Placeholder()); + addTearDown(() => overlayEntry2..remove()..dispose()); final OverlayEntry overlayEntry3 = OverlayEntry(builder: (BuildContext context) => const Placeholder()); + addTearDown(() => overlayEntry3..remove()..dispose()); await tester.pumpWidget( Directionality( @@ -1094,7 +1139,7 @@ void main() { expect(layoutCount2, 1); }); - testWidgets('Swap child and overlayChild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swap child and overlayChild', (WidgetTester tester) async { final RenderBox childBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); final RenderBox overlayChildBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); @@ -1105,12 +1150,15 @@ void main() { final Widget child1 = WidgetToRenderBoxAdapter(renderBox: overlayChildBox); final Widget child2 = WidgetToRenderBoxAdapter(renderBox: childBox); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry(builder: (BuildContext context) { + overlayEntry = OverlayEntry(builder: (BuildContext context) { return _ManyRelayoutBoundaries( levels: 50, child: StatefulBuilder(builder: (BuildContext context, StateSetter stateSetter) { @@ -1133,7 +1181,7 @@ void main() { verifyTreeIsClean(); }); - testWidgets('forgetChild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('forgetChild', (WidgetTester tester) async { final RenderBox childBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); final RenderBox overlayChildBox = RenderConstrainedBox(additionalConstraints: const BoxConstraints()); @@ -1145,6 +1193,11 @@ void main() { final Widget child1 = WidgetToRenderBoxAdapter(renderBox: overlayChildBox); final Widget child2 = WidgetToRenderBoxAdapter(renderBox: childBox); + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); + controller1.hide(); await tester.pumpWidget( @@ -1152,7 +1205,7 @@ void main() { textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry(builder: (BuildContext context) { + overlayEntry1 = OverlayEntry(builder: (BuildContext context) { return StatefulBuilder(builder: (BuildContext context, StateSetter stateSetter) { setState2 = stateSetter; return OverlayPortal( @@ -1162,7 +1215,7 @@ void main() { ); }); }), - OverlayEntry(builder: (BuildContext context) { + overlayEntry2 = OverlayEntry(builder: (BuildContext context) { return _ManyRelayoutBoundaries( levels: 50, child: StatefulBuilder(builder: (BuildContext context, StateSetter stateSetter) { @@ -1243,7 +1296,7 @@ void main() { verifyTreeIsClean(); }); - testWidgets('Paint order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paint order', (WidgetTester tester) async { final GlobalKey outerKey = GlobalKey(debugLabel: 'Original Outer Widget'); final GlobalKey innerKey = GlobalKey(debugLabel: 'Original Inner Widget'); @@ -1284,12 +1337,15 @@ void main() { ], ); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry(builder: (BuildContext context) { + overlayEntry = OverlayEntry(builder: (BuildContext context) { return StatefulBuilder(builder: (BuildContext context, StateSetter stateSetter) { setState = stateSetter; return widget; @@ -1365,21 +1421,26 @@ void main() { setState2 = null; }); - testWidgets('between OverlayEntry & overlayChild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('between OverlayEntry & overlayChild', (WidgetTester tester) async { final _RenderLayoutCounter counter1 = _RenderLayoutCounter(); final _RenderLayoutCounter counter2 = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry1 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState1 = stateSetter; // WidgetToRenderBoxAdapter is keyed by the render box. return WidgetToRenderBoxAdapter(renderBox: swapped ? counter2 : counter1); }), - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry2 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState2 = stateSetter; return OverlayPortal( controller: controller1, @@ -1408,20 +1469,25 @@ void main() { expect(counter2.layoutCount, 3); }); - testWidgets('between OverlayEntry & overlayChild, featuring LayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('between OverlayEntry & overlayChild, featuring LayoutBuilder', (WidgetTester tester) async { final _RenderLayoutCounter counter1 = _RenderLayoutCounter(); final _RenderLayoutCounter counter2 = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry1 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState1 = stateSetter; return WidgetToRenderBoxAdapter(renderBox: swapped ? counter2 : counter1); }), - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry2 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState2 = stateSetter; return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -1454,16 +1520,21 @@ void main() { expect(counter2.layoutCount, 3); }); - testWidgets('between overlayChild & overlayChild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('between overlayChild & overlayChild', (WidgetTester tester) async { final _RenderLayoutCounter counter1 = _RenderLayoutCounter(); final _RenderLayoutCounter counter2 = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry1 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState1 = stateSetter; return OverlayPortal( // WidgetToRenderBoxAdapter is keyed by the render box. @@ -1472,7 +1543,7 @@ void main() { child: const SizedBox(), ); }), - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry2 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState2 = stateSetter; return OverlayPortal( controller: controller2, @@ -1501,16 +1572,21 @@ void main() { expect(counter2.layoutCount, 3); }); - testWidgets('between overlayChild & overlayChild, featuring LayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('between overlayChild & overlayChild, featuring LayoutBuilder', (WidgetTester tester) async { final _RenderLayoutCounter counter1 = _RenderLayoutCounter(); final _RenderLayoutCounter counter2 = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry1 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState1 = stateSetter; return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -1522,7 +1598,7 @@ void main() { } ); }), - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry2 = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState2 = stateSetter; return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -1555,16 +1631,19 @@ void main() { expect(counter2.layoutCount, 3); }); - testWidgets('between child & overlayChild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('between child & overlayChild', (WidgetTester tester) async { final _RenderLayoutCounter counter1 = _RenderLayoutCounter(); final _RenderLayoutCounter counter2 = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState1 = stateSetter; return OverlayPortal( // WidgetToRenderBoxAdapter is keyed by the render box. @@ -1594,16 +1673,19 @@ void main() { expect(counter2.layoutCount, 3); }); - testWidgets('between child & overlayChild, featuring LayoutBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('between child & overlayChild, featuring LayoutBuilder', (WidgetTester tester) async { final _RenderLayoutCounter counter1 = _RenderLayoutCounter(); final _RenderLayoutCounter counter2 = _RenderLayoutCounter(); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { + overlayEntry = OverlayStatefulEntry(builder: (BuildContext context, StateSetter stateSetter) { setState1 = stateSetter; return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -1638,19 +1720,25 @@ void main() { }); }); - testWidgets('Safe to move the overlay child to a different Overlay and remove the old Overlay', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Safe to move the overlay child to a different Overlay and remove the old Overlay', (WidgetTester tester) async { controller1.show(); final GlobalKey key = GlobalKey(debugLabel: 'key'); final GlobalKey oldOverlayKey = GlobalKey(debugLabel: 'old overlay'); final GlobalKey newOverlayKey = GlobalKey(debugLabel: 'new overlay'); final GlobalKey overlayChildKey = GlobalKey(debugLabel: 'overlay child key'); + + late final OverlayEntry overlayEntry1; + addTearDown(() => overlayEntry1..remove()..dispose()); + late final OverlayEntry overlayEntry2; + addTearDown(() => overlayEntry2..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( key: oldOverlayKey, initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry1 = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( key: key, @@ -1675,7 +1763,7 @@ void main() { child: Overlay( key: newOverlayKey, initialEntries: <OverlayEntry>[ - OverlayEntry( + overlayEntry2 = OverlayEntry( builder: (BuildContext context) { return OverlayPortal( key: key, @@ -1698,18 +1786,21 @@ void main() { }); group('Paint order', () { - testWidgets('show bringsToTop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('show bringsToTop', (WidgetTester tester) async { controller1.hide(); const _PaintOrder child1 = _PaintOrder(); const _PaintOrder child2 = _PaintOrder(); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry(builder: (BuildContext context) { + overlayEntry = OverlayEntry(builder: (BuildContext context) { return Column( children: <Widget>[ OverlayPortal(controller: controller1, overlayChildBuilder: (BuildContext context) => child1), @@ -1762,7 +1853,7 @@ void main() { ); }); - testWidgets('Paint order does not change after global key reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paint order does not change after global key reparenting', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); late StateSetter setState; @@ -1787,12 +1878,15 @@ void main() { child: const SizedBox(), ); + late final OverlayEntry overlayEntry; + addTearDown(() => overlayEntry..remove()..dispose()); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Overlay( initialEntries: <OverlayEntry>[ - OverlayEntry(builder: (BuildContext context) { + overlayEntry = OverlayEntry(builder: (BuildContext context) { return Column( children: <Widget>[ StatefulBuilder(builder: (BuildContext context, StateSetter stateSetter) { diff --git a/packages/flutter/test/widgets/overscroll_indicator_test.dart b/packages/flutter/test/widgets/overscroll_indicator_test.dart index 340871db3230b..4caaa3a9714cc 100644 --- a/packages/flutter/test/widgets/overscroll_indicator_test.dart +++ b/packages/flutter/test/widgets/overscroll_indicator_test.dart @@ -6,6 +6,7 @@ import 'dart:math' as math; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; final Matcher doesNotOverscroll = isNot(paints..circle()); @@ -19,7 +20,7 @@ Future<void> slowDrag(WidgetTester tester, Offset start, Offset offset) async { } void main() { - testWidgets('Overscroll indicator color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll indicator color', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -55,7 +56,7 @@ void main() { expect(painter, doesNotOverscroll); }); - testWidgets('Nested scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested scrollable', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -86,7 +87,7 @@ void main() { expect(innerPainter, paints..circle()); }); - testWidgets('Overscroll indicator changes side when you drag on the other side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll indicator changes side when you drag on the other side', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -128,7 +129,7 @@ void main() { expect(painter, doesNotOverscroll); }); - testWidgets('Overscroll indicator changes side when you shift sides', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll indicator changes side when you shift sides', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -166,7 +167,7 @@ void main() { }); group("Flipping direction of scrollable doesn't change overscroll behavior", () { - testWidgets('down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('down', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -186,7 +187,7 @@ void main() { expect(painter, doesNotOverscroll); }); - testWidgets('up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('up', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -208,7 +209,7 @@ void main() { }); }); - testWidgets('Overscroll in both directions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll in both directions', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -231,7 +232,7 @@ void main() { expect(painter, doesNotOverscroll); }); - testWidgets('Overscroll ignored from alternate axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll ignored from alternate axis', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -260,7 +261,7 @@ void main() { expect(painter, doesNotOverscroll); }); - testWidgets('Overscroll horizontally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overscroll horizontally', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -291,7 +292,7 @@ void main() { expect(painter, doesNotOverscroll); }); - testWidgets('Nested overscrolls do not throw exceptions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested overscrolls do not throw exceptions', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: PageView( @@ -313,7 +314,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Changing settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing settings', (WidgetTester tester) async { RenderObject painter; await tester.pumpWidget( @@ -359,7 +360,7 @@ void main() { expect(painter, isNot(paints..circle()..circle())); }); - testWidgets('CustomScrollView overscroll indicator works if there is sliver before center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView overscroll indicator works if there is sliver before center', (WidgetTester tester) async { final Key centerKey = UniqueKey(); await tester.pumpWidget( Directionality( @@ -398,7 +399,7 @@ void main() { expect(painter, paints..save()..translate(y: 0.0)..scale()..circle()); }); - testWidgets('CustomScrollView overscroll indicator works well with [CustomScrollView.center] and [OverscrollIndicatorNotification.paintOffset]', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView overscroll indicator works well with [CustomScrollView.center] and [OverscrollIndicatorNotification.paintOffset]', (WidgetTester tester) async { final Key centerKey = UniqueKey(); await tester.pumpWidget( Directionality( @@ -445,7 +446,7 @@ void main() { expect(painter, paints..save()..translate(y: 50.0)..scale()..circle()); }); - testWidgets('The OverscrollIndicator should not overflow the scrollable view edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The OverscrollIndicator should not overflow the scrollable view edge', (WidgetTester tester) async { // Regressing test for https://github.com/flutter/flutter/issues/64149 await tester.pumpWidget( Directionality( @@ -508,7 +509,7 @@ void main() { }); group('[OverscrollIndicatorNotification.paintOffset] test', () { - testWidgets('Leading', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Leading', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -538,7 +539,7 @@ void main() { expect(painter, paints..save()..translate(y: 50.0 - 30.0)..scale()..circle()); }); - testWidgets('Trailing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Trailing', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart b/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart index d8aa4e12a4e96..3f48544f7e40a 100644 --- a/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart +++ b/packages/flutter/test/widgets/overscroll_stretch_indicator_test.dart @@ -10,6 +10,7 @@ library; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { Widget buildTest( @@ -76,10 +77,12 @@ void main() { ); } - testWidgets('Stretch overscroll will do nothing when axes do not match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll will do nothing when axes do not match', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -135,11 +138,13 @@ void main() { expect(box2.localToGlobal(Offset.zero), const Offset(0.0, 250.0)); }); - testWidgets('Stretch overscroll vertically', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll vertically', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest(box1Key, box2Key, box3Key, controller), ); @@ -212,11 +217,13 @@ void main() { expect(box3.localToGlobal(Offset.zero).dy, 350.0); }); - testWidgets('Stretch overscroll works in reverse - vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll works in reverse - vertical', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest(box1Key, box2Key, box3Key, controller, reverse: true), ); @@ -245,11 +252,13 @@ void main() { ); }); - testWidgets('Stretch overscroll works in reverse - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll works in reverse - horizontal', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest( box1Key, @@ -285,11 +294,13 @@ void main() { ); }); - testWidgets('Stretch overscroll works in reverse - horizontal - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll works in reverse - horizontal - RTL', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest( box1Key, @@ -371,11 +382,13 @@ void main() { expect(box3.localToGlobal(Offset.zero).dx, 500.0); }); - testWidgets('Stretch overscroll horizontally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll horizontally', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest(box1Key, box2Key, box3Key, controller, axis: Axis.horizontal) ); @@ -448,11 +461,13 @@ void main() { expect(box3.localToGlobal(Offset.zero).dx, 500.0); }); - testWidgets('Stretch overscroll horizontally RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll horizontally RTL', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest( box1Key, @@ -488,12 +503,14 @@ void main() { ); }); - testWidgets('Disallow stretching overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disallow stretching overscroll', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); - double indicatorNotification =0; + addTearDown(controller.dispose); + + double indicatorNotification = 0; await tester.pumpWidget( NotificationListener<OverscrollIndicatorNotification>( onNotification: (OverscrollIndicatorNotification notification) { @@ -530,7 +547,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Stretch does not overflow bounds of container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch does not overflow bounds of container', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/90197 await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -587,7 +604,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Clip behavior is updated as needed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Clip behavior is updated as needed', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/97867 await tester.pumpWidget( Directionality( @@ -647,7 +664,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('clipBehavior parameter updates overscroll clipping behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('clipBehavior parameter updates overscroll clipping behavior', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/103491 Widget buildFrame(Clip clipBehavior) { @@ -711,7 +728,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Stretch limit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch limit', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/99264 await tester.pumpWidget( Directionality( @@ -762,7 +779,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Multiple pointers will not exceed stretch limit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiple pointers will not exceed stretch limit', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/99264 await tester.pumpWidget( Directionality( @@ -832,11 +849,13 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Stretch overscroll vertically, change direction mid scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll vertically, change direction mid scroll', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest( box1Key, @@ -901,11 +920,13 @@ void main() { expect(box3.localToGlobal(Offset.zero), const Offset(0.0, 200.0)); }); - testWidgets('Stretch overscroll horizontally, change direction mid scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll horizontally, change direction mid scroll', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest( box1Key, @@ -971,11 +992,13 @@ void main() { expect(box3.localToGlobal(Offset.zero), const Offset(200.0, 0.0)); }); - testWidgets('Fling toward the trailing edge causes stretch toward the leading edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fling toward the trailing edge causes stretch toward the leading edge', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest(box1Key, box2Key, box3Key, controller), ); @@ -1011,11 +1034,13 @@ void main() { expect(box3.localToGlobal(Offset.zero).dy, 350.0); }); - testWidgets('Fling toward the leading edge causes stretch toward the trailing edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fling toward the leading edge causes stretch toward the trailing edge', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest(box1Key, box2Key, box3Key, controller), ); @@ -1063,11 +1088,13 @@ void main() { expect(box3.localToGlobal(Offset.zero).dy, 500.0); }); - testWidgets('changing scroll direction during recede animation will not change the stretch direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('changing scroll direction during recede animation will not change the stretch direction', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest(box1Key, box2Key, box3Key, controller, boxHeight: 205.0), ); @@ -1125,11 +1152,13 @@ void main() { await gesture.up(); }); - testWidgets('Stretch overscroll only uses image filter during stretch effect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stretch overscroll only uses image filter during stretch effect', (WidgetTester tester) async { final GlobalKey box1Key = GlobalKey(); final GlobalKey box2Key = GlobalKey(); final GlobalKey box3Key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( buildTest( box1Key, diff --git a/packages/flutter/test/widgets/page_forward_transitions_test.dart b/packages/flutter/test/widgets/page_forward_transitions_test.dart index 9ffc019cc670b..da523ac96f40a 100644 --- a/packages/flutter/test/widgets/page_forward_transitions_test.dart +++ b/packages/flutter/test/widgets/page_forward_transitions_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestTransition extends AnimatedWidget { const TestTransition({ @@ -57,7 +58,7 @@ void main() { const Duration kTwoTenthsOfTheTransitionDuration = Duration(milliseconds: 30); const Duration kFourTenthsOfTheTransitionDuration = Duration(milliseconds: 60); - testWidgets('Check onstage/offstage handling around transitions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Check onstage/offstage handling around transitions', (WidgetTester tester) async { final GlobalKey insideKey = GlobalKey(); @@ -196,7 +197,7 @@ void main() { }); - testWidgets('Check onstage/offstage handling of barriers around transitions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Check onstage/offstage handling of barriers around transitions', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( onGenerateRoute: (RouteSettings settings) { diff --git a/packages/flutter/test/widgets/page_route_builder_test.dart b/packages/flutter/test/widgets/page_route_builder_test.dart index 3e6090fa80195..7e90c9a4e273e 100644 --- a/packages/flutter/test/widgets/page_route_builder_test.dart +++ b/packages/flutter/test/widgets/page_route_builder_test.dart @@ -9,6 +9,7 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestPage extends StatelessWidget { const TestPage({ super.key, this.useMaterial3 }); @@ -93,7 +94,7 @@ class ModalPage extends StatelessWidget { } void main() { - testWidgets('Material2 - Barriers show when using PageRouteBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material2 - Barriers show when using PageRouteBuilder', (WidgetTester tester) async { await tester.pumpWidget(const TestPage(useMaterial3: false)); await tester.tap(find.byType(FloatingActionButton)); await tester.pumpAndSettle(); @@ -103,7 +104,7 @@ void main() { ); }); - testWidgets('Material3 - Barriers show when using PageRouteBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Material3 - Barriers show when using PageRouteBuilder', (WidgetTester tester) async { await tester.pumpWidget(const TestPage(useMaterial3: true)); await tester.tap(find.byType(FloatingActionButton)); await tester.pumpAndSettle(); diff --git a/packages/flutter/test/widgets/page_storage_test.dart b/packages/flutter/test/widgets/page_storage_test.dart index db74aa58b32d2..ec8d39002de18 100644 --- a/packages/flutter/test/widgets/page_storage_test.dart +++ b/packages/flutter/test/widgets/page_storage_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('PageStorage read and write', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageStorage read and write', (WidgetTester tester) async { const Key builderKey = PageStorageKey<String>('builderKey'); late StateSetter setState; int storedValue = 0; @@ -37,7 +38,7 @@ void main() { expect(PageStorage.of(builderElement).readState(builderElement), equals(storedValue)); }); - testWidgets('PageStorage read and write by identifier', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageStorage read and write by identifier', (WidgetTester tester) async { late StateSetter setState; int storedValue = 0; diff --git a/packages/flutter/test/widgets/page_transitions_test.dart b/packages/flutter/test/widgets/page_transitions_test.dart index 55729ea2395a7..6b1a973ea408b 100644 --- a/packages/flutter/test/widgets/page_transitions_test.dart +++ b/packages/flutter/test/widgets/page_transitions_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestOverlayRoute extends OverlayRoute<void> { TestOverlayRoute({ super.settings }); @@ -47,7 +48,7 @@ class PersistentBottomSheetTestState extends State<PersistentBottomSheetTest> { } void main() { - testWidgets('Check onstage/offstage handling around transitions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Check onstage/offstage handling around transitions', (WidgetTester tester) async { final GlobalKey containerKey1 = GlobalKey(); final GlobalKey containerKey2 = GlobalKey(); final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ @@ -129,7 +130,7 @@ void main() { expect(Navigator.canPop(containerKey1.currentContext!), isFalse); }); - testWidgets('Check back gesture disables Heroes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Check back gesture disables Heroes', (WidgetTester tester) async { final GlobalKey containerKey1 = GlobalKey(); final GlobalKey containerKey2 = GlobalKey(); const String kHeroTag = 'hero'; @@ -198,7 +199,7 @@ void main() { expect(settingsOffset.dy, 100.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets("Check back gesture doesn't start during transitions", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Check back gesture doesn't start during transitions", (WidgetTester tester) async { final GlobalKey containerKey1 = GlobalKey(); final GlobalKey containerKey2 = GlobalKey(); final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ @@ -242,7 +243,7 @@ void main() { }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); // Tests bug https://github.com/flutter/flutter/issues/6451 - testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async { final GlobalKey containerKey1 = GlobalKey(); final GlobalKey containerKey2 = GlobalKey(); final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ @@ -295,7 +296,7 @@ void main() { expect(sheet.setStateCalled, isFalse); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Test completed future', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Test completed future', (WidgetTester tester) async { final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ '/': (_) => const Center(child: Text('home')), '/next': (_) => const Center(child: Text('next')), diff --git a/packages/flutter/test/widgets/page_view_test.dart b/packages/flutter/test/widgets/page_view_test.dart index 9b94146ee55d8..41405b00e229e 100644 --- a/packages/flutter/test/widgets/page_view_test.dart +++ b/packages/flutter/test/widgets/page_view_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; import 'semantics_tester.dart'; @@ -14,7 +15,7 @@ import 'states.dart'; void main() { // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('PageView.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -49,11 +50,10 @@ void main() { expect(finderCalled, true); }); - testWidgets('PageView resize from zero-size viewport should not lose state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView resize from zero-size viewport should not lose state', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/88956 - final PageController controller = PageController( - initialPage: 1, - ); + final PageController controller = PageController(initialPage: 1); + addTearDown(controller.dispose); Widget build(Size size) { return Directionality( @@ -94,11 +94,10 @@ void main() { expect(find.text('Iowa'), findsOneWidget); }); - testWidgets('Change the page through the controller when zero-size viewport', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Change the page through the controller when zero-size viewport', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/88956 - final PageController controller = PageController( - initialPage: 1, - ); + final PageController controller = PageController(initialPage: 1); + addTearDown(controller.dispose); Widget build(Size size) { return Directionality( @@ -134,11 +133,10 @@ void main() { expect(find.text('Illinois'), findsOneWidget); }); - testWidgets('_PagePosition.applyViewportDimension should not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('_PagePosition.applyViewportDimension should not throw', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/101007 - final PageController controller = PageController( - initialPage: 1, - ); + final PageController controller = PageController(initialPage: 1); + addTearDown(controller.dispose); // Set the starting viewportDimension to 0.0 await tester.binding.setSurfaceSize(Size.zero); @@ -173,13 +171,14 @@ void main() { await tester.binding.setSurfaceSize(null); }); - testWidgets('PageController cannot return page while unattached', + testWidgetsWithLeakTracking('PageController cannot return page while unattached', (WidgetTester tester) async { final PageController controller = PageController(); + addTearDown(controller.dispose); expect(() => controller.page, throwsAssertionError); }); - testWidgets('PageView control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView control test', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(Directionality( @@ -246,7 +245,7 @@ void main() { expect(find.text('Arizona'), findsNothing); }); - testWidgets('PageView does not squish when overscrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView does not squish when overscrolled', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: PageView( children: List<Widget>.generate(10, (int i) { @@ -284,8 +283,9 @@ void main() { expect(sizeOf(0), equals(const Size(800.0, 600.0))); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('PageController control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageController control test', (WidgetTester tester) async { final PageController controller = PageController(initialPage: 4); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -330,7 +330,7 @@ void main() { expect(find.text('California'), findsOneWidget); }); - testWidgets('PageController page stability', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageController page stability', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Center( @@ -382,8 +382,10 @@ void main() { expect(find.text('Arizona'), findsOneWidget); }); - testWidgets('PageController nextPage and previousPage return Futures that resolve', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageController nextPage and previousPage return Futures that resolve', (WidgetTester tester) async { final PageController controller = PageController(); + addTearDown(controller.dispose); + await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: PageView( @@ -414,7 +416,7 @@ void main() { expect(previousPageCompleted, true); }); - testWidgets('PageView in zero-size container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView in zero-size container', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Center( @@ -444,7 +446,7 @@ void main() { expect(find.text('Alabama'), findsOneWidget); }); - testWidgets('Page changes at halfway point', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Page changes at halfway point', (WidgetTester tester) async { final List<int> log = <int>[]; await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -494,9 +496,10 @@ void main() { expect(find.text('Alaska'), findsOneWidget); }); - testWidgets('Bouncing scroll physics ballistics does not overshoot', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Bouncing scroll physics ballistics does not overshoot', (WidgetTester tester) async { final List<int> log = <int>[]; final PageController controller = PageController(viewportFraction: 0.9); + addTearDown(controller.dispose); Widget build(PageController controller, { Size? size }) { final Widget pageView = Directionality( @@ -548,8 +551,9 @@ void main() { expect(find.text('Arizona'), findsNothing); }); - testWidgets('PageView viewportFraction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView viewportFraction', (WidgetTester tester) async { PageController controller = PageController(viewportFraction: 7/8); + addTearDown(controller.dispose); Widget build(PageController controller) { return Directionality( @@ -583,6 +587,7 @@ void main() { expect(tester.getTopLeft(find.text('Idaho')), const Offset(750.0, 0.0)); controller = PageController(viewportFraction: 39/40); + addTearDown(controller.dispose); await tester.pumpWidget(build(controller)); @@ -591,7 +596,7 @@ void main() { expect(tester.getTopLeft(find.text('Idaho')), const Offset(790.0, 0.0)); }); - testWidgets('Page snapping disable and reenable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Page snapping disable and reenable', (WidgetTester tester) async { final List<int> log = <int>[]; Widget build({ required bool pageSnapping }) { @@ -654,8 +659,9 @@ void main() { expect(find.text('Arkansas'), findsNothing); }); - testWidgets('PageView small viewportFraction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView small viewportFraction', (WidgetTester tester) async { final PageController controller = PageController(viewportFraction: 1/8); + addTearDown(controller.dispose); Widget build(PageController controller) { return Directionality( @@ -698,8 +704,9 @@ void main() { expect(tester.getTopLeft(find.text('Iowa')), const Offset(750.0, 0.0)); }); - testWidgets('PageView large viewportFraction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView large viewportFraction', (WidgetTester tester) async { final PageController controller = PageController(viewportFraction: 5/4); + addTearDown(controller.dispose); Widget build(PageController controller) { return Directionality( @@ -731,7 +738,7 @@ void main() { expect(tester.getTopLeft(find.text('Hawaii')), const Offset(-100.0, 0.0)); }); - testWidgets( + testWidgetsWithLeakTracking( 'Updating PageView large viewportFraction', (WidgetTester tester) async { Widget build(PageController controller) { @@ -754,12 +761,14 @@ void main() { } final PageController oldController = PageController(viewportFraction: 5/4); + addTearDown(oldController.dispose); await tester.pumpWidget(build(oldController)); expect(tester.getTopLeft(find.text('Alabama')), const Offset(-100, 0)); expect(tester.getBottomRight(find.text('Alabama')), const Offset(900.0, 600.0)); final PageController newController = PageController(viewportFraction: 4); + addTearDown(newController.dispose); await tester.pumpWidget(build(newController)); newController.jumpToPage(10); await tester.pump(); @@ -768,11 +777,12 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'PageView large viewportFraction can scroll to the last page and snap', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/45096. final PageController controller = PageController(viewportFraction: 5/4); + addTearDown(controller.dispose); Widget build(PageController controller) { return Directionality( @@ -805,11 +815,12 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'All visible pages are able to receive touch events', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23873. final PageController controller = PageController(viewportFraction: 1/4); + addTearDown(controller.dispose); late int tappedIndex; Widget build() { @@ -853,12 +864,13 @@ void main() { }, ); - testWidgets('the current item remains centered on constraint change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the current item remains centered on constraint change', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/50505. final PageController controller = PageController( initialPage: kStates.length - 1, viewportFraction: 0.5, ); + addTearDown(controller.dispose); Widget build(Size size) { return Directionality( @@ -895,10 +907,11 @@ void main() { verifyCentered(); }); - testWidgets('PageView does not report page changed on overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView does not report page changed on overscroll', (WidgetTester tester) async { final PageController controller = PageController( initialPage: kStates.length - 1, ); + addTearDown(controller.dispose); int changeIndex = 0; Widget build() { return Directionality( @@ -921,8 +934,9 @@ void main() { expect(changeIndex, 0); }); - testWidgets('PageView can restore page', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView can restore page', (WidgetTester tester) async { final PageController controller = PageController(); + addTearDown(controller.dispose); expect( () => controller.page, throwsA(isAssertionError.having( @@ -983,6 +997,7 @@ void main() { expect(controller.page, 2); final PageController controller2 = PageController(keepPage: false); + addTearDown(controller2.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: PageStorage( @@ -1001,10 +1016,11 @@ void main() { expect(controller2.page, 0); }); - testWidgets('PageView exposes semantics of children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView exposes semantics of children', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final PageController controller = PageController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: PageView( @@ -1040,7 +1056,7 @@ void main() { semantics.dispose(); }); - testWidgets('PageMetrics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageMetrics', (WidgetTester tester) async { final PageMetrics page = PageMetrics( minScrollExtent: 100.0, maxScrollExtent: 200.0, @@ -1057,8 +1073,9 @@ void main() { expect(page2.page, 4.0); }); - testWidgets('Page controller can handle rounding issue', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Page controller can handle rounding issue', (WidgetTester tester) async { final PageController pageController = PageController(); + addTearDown(pageController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -1077,10 +1094,11 @@ void main() { expect(pageController.page, 1); }); - testWidgets('PageView can participate in a11y scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView can participate in a11y scrolling', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final PageController controller = PageController(); + addTearDown(controller.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: PageView( @@ -1155,7 +1173,7 @@ void main() { expect(context.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('PageView.padEnds tests', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView.padEnds tests', (WidgetTester tester) async { Finder viewportFinder() => find.byType(SliverFillViewport, skipOffstage: false); // PageView() defaults to true. @@ -1177,10 +1195,11 @@ void main() { expect(tester.widget<SliverFillViewport>(viewportFinder()).padEnds, false); }); - testWidgets('PageView - precision error inside RenderSliverFixedExtentBoxAdaptor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView - precision error inside RenderSliverFixedExtentBoxAdaptor', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/95101 - final PageController controller = PageController(initialPage: 152); + addTearDown(controller.dispose); + await tester.pumpWidget( Center( child: SizedBox( @@ -1204,9 +1223,10 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('PageView content should not be stretched on precision error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView content should not be stretched on precision error', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/126561. final PageController controller = PageController(); + addTearDown(controller.dispose); const double pixel6EmulatorWidth = 411.42857142857144; diff --git a/packages/flutter/test/widgets/pageable_list_test.dart b/packages/flutter/test/widgets/pageable_list_test.dart index 3cab09a14c5ff..0dd30a18da5eb 100644 --- a/packages/flutter/test/widgets/pageable_list_test.dart +++ b/packages/flutter/test/widgets/pageable_list_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Size pageSize = const Size(600.0, 300.0); const List<int> defaultPages = <int>[0, 1, 2, 3, 4, 5]; @@ -59,7 +60,7 @@ Future<void> pageRight(WidgetTester tester) { } void main() { - testWidgets('PageView default control', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView default control', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -70,7 +71,7 @@ void main() { ); }); - testWidgets('PageView control test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView control test (LTR)', (WidgetTester tester) async { currentPage = null; await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr)); expect(currentPage, isNull); @@ -98,7 +99,7 @@ void main() { expect(currentPage, equals(0)); }); - testWidgets('PageView with reverse (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView with reverse (LTR)', (WidgetTester tester) async { currentPage = null; await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.ltr)); await pageRight(tester); @@ -132,7 +133,7 @@ void main() { expect(find.text('5'), findsNothing); }); - testWidgets('PageView control test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView control test (RTL)', (WidgetTester tester) async { currentPage = null; await tester.pumpWidget(buildFrame(textDirection: TextDirection.rtl)); await pageRight(tester); @@ -166,7 +167,7 @@ void main() { expect(find.text('5'), findsNothing); }); - testWidgets('PageView with reverse (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView with reverse (RTL)', (WidgetTester tester) async { currentPage = null; await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl)); expect(currentPage, isNull); diff --git a/packages/flutter/test/widgets/parent_data_test.dart b/packages/flutter/test/widgets/parent_data_test.dart index d546947c81f9c..525d10816166b 100644 --- a/packages/flutter/test/widgets/parent_data_test.dart +++ b/packages/flutter/test/widgets/parent_data_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; @@ -49,7 +50,7 @@ void checkTree(WidgetTester tester, List<TestParentData> expectedParentData) { final TestParentData kNonPositioned = TestParentData(); void main() { - testWidgets('ParentDataWidget control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ParentDataWidget control test', (WidgetTester tester) async { await tester.pumpWidget( const Stack( textDirection: TextDirection.ltr, @@ -249,7 +250,7 @@ void main() { checkTree(tester, <TestParentData>[]); }); - testWidgets('ParentDataWidget conflicting data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ParentDataWidget conflicting data', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -331,7 +332,7 @@ void main() { checkTree(tester, <TestParentData>[]); }); - testWidgets('ParentDataWidget interacts with global keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ParentDataWidget interacts with global keys', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -389,7 +390,7 @@ void main() { ]); }); - testWidgets('Parent data invalid ancestor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Parent data invalid ancestor', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Row( @@ -424,7 +425,7 @@ void main() { ); }); - testWidgets('ParentDataWidget can be used with different ancestor RenderObjectWidgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ParentDataWidget can be used with different ancestor RenderObjectWidgets', (WidgetTester tester) async { await tester.pumpWidget( OneAncestorWidget( child: Container(), diff --git a/packages/flutter/test/widgets/performance_overlay_test.dart b/packages/flutter/test/widgets/performance_overlay_test.dart index 8c337f1182a8a..9af1f11012fc5 100644 --- a/packages/flutter/test/widgets/performance_overlay_test.dart +++ b/packages/flutter/test/widgets/performance_overlay_test.dart @@ -5,14 +5,15 @@ import 'package:flutter/src/rendering/performance_overlay.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Performance overlay smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Performance overlay smoke test', (WidgetTester tester) async { await tester.pumpWidget(const PerformanceOverlay()); await tester.pumpWidget(PerformanceOverlay.allEnabled()); }); - testWidgets('update widget field checkerboardRasterCacheImages', + testWidgetsWithLeakTracking('update widget field checkerboardRasterCacheImages', (WidgetTester tester) async { await tester.pumpWidget(const PerformanceOverlay()); await tester.pumpWidget( @@ -25,7 +26,7 @@ void main() { true); }); - testWidgets('update widget field checkerboardOffscreenLayers', + testWidgetsWithLeakTracking('update widget field checkerboardOffscreenLayers', (WidgetTester tester) async { await tester.pumpWidget(const PerformanceOverlay()); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/physical_model_test.dart b/packages/flutter/test/widgets/physical_model_test.dart index 7d3146b9c1b76..066d1c7573259 100644 --- a/packages/flutter/test/widgets/physical_model_test.dart +++ b/packages/flutter/test/widgets/physical_model_test.dart @@ -10,9 +10,10 @@ library; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('PhysicalModel updates clipBehavior in updateRenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalModel updates clipBehavior in updateRenderObject', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp(home: PhysicalModel(color: Colors.red)), ); @@ -28,7 +29,7 @@ void main() { expect(renderPhysicalModel.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('PhysicalShape updates clipBehavior in updateRenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalShape updates clipBehavior in updateRenderObject', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp(home: PhysicalShape(color: Colors.red, clipper: ShapeBorderClipper(shape: CircleBorder()))), ); @@ -44,7 +45,7 @@ void main() { expect(renderPhysicalShape.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('PhysicalModel - clips when overflows and elevation is 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PhysicalModel - clips when overflows and elevation is 0', (WidgetTester tester) async { const Key key = Key('test'); await tester.pumpWidget( Theme( diff --git a/packages/flutter/test/widgets/placeholder_test.dart b/packages/flutter/test/widgets/placeholder_test.dart index 980f6473edc77..28aadb0dbf213 100644 --- a/packages/flutter/test/widgets/placeholder_test.dart +++ b/packages/flutter/test/widgets/placeholder_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Placeholder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Placeholder', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); expect(tester.renderObject<RenderBox>(find.byType(Placeholder)).size, const Size(800.0, 600.0)); await tester.pumpWidget(const Center(child: Placeholder())); @@ -19,21 +20,21 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(Placeholder)).size, const Size(200.0, 300.0)); }); - testWidgets('Placeholder color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Placeholder color', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); expect(tester.renderObject(find.byType(Placeholder)), paints..path(color: const Color(0xFF455A64))); await tester.pumpWidget(const Placeholder(color: Color(0xFF00FF00))); expect(tester.renderObject(find.byType(Placeholder)), paints..path(color: const Color(0xFF00FF00))); }); - testWidgets('Placeholder stroke width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Placeholder stroke width', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); expect(tester.renderObject(find.byType(Placeholder)), paints..path(strokeWidth: 2.0)); await tester.pumpWidget(const Placeholder(strokeWidth: 10.0)); expect(tester.renderObject(find.byType(Placeholder)), paints..path(strokeWidth: 10.0)); }); - testWidgets('Placeholder child widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Placeholder child widget', (WidgetTester tester) async { await tester.pumpWidget(const Placeholder()); expect(find.text('Label'), findsNothing); await tester.pumpWidget(const MaterialApp(home: Placeholder(child: Text('Label')))); diff --git a/packages/flutter/test/widgets/platform_menu_bar_test.dart b/packages/flutter/test/widgets/platform_menu_bar_test.dart index 8828115a91c39..c72e85130e4a1 100644 --- a/packages/flutter/test/widgets/platform_menu_bar_test.dart +++ b/packages/flutter/test/widgets/platform_menu_bar_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter/src/foundation/diagnostics.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -47,7 +48,7 @@ void main() { group('PlatformMenuBar', () { group('basic menu structure is transmitted to platform', () { - testWidgets('using onSelected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using onSelected', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -78,7 +79,7 @@ void main() { equals(expectedStructure), ); }); - testWidgets('using onSelectedIntent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using onSelectedIntent', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Material( @@ -126,7 +127,7 @@ void main() { ); expect(tester.takeException(), isA<AssertionError>()); }); - testWidgets('diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('diagnostics', (WidgetTester tester) async { const PlatformMenuItem item = PlatformMenuItem( label: 'label2', shortcut: SingleActivator(LogicalKeyboardKey.keyA), @@ -158,7 +159,7 @@ void main() { }); }); group('MenuBarItem', () { - testWidgets('diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('diagnostics', (WidgetTester tester) async { const PlatformMenuItem childItem = PlatformMenuItem( label: 'label', ); @@ -182,7 +183,7 @@ void main() { }); group('ShortcutSerialization', () { - testWidgets('character constructor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('character constructor', (WidgetTester tester) async { final ShortcutSerialization serialization = ShortcutSerialization.character('?'); expect(serialization.toChannelRepresentation(), equals(<String, Object?>{ 'shortcutCharacter': '?', @@ -195,7 +196,7 @@ void main() { })); }); - testWidgets('modifier constructor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modifier constructor', (WidgetTester tester) async { final ShortcutSerialization serialization = ShortcutSerialization.modifier(LogicalKeyboardKey.home); expect(serialization.toChannelRepresentation(), equals(<String, Object?>{ 'shortcutTrigger': LogicalKeyboardKey.home.keyId, From da0f9a997a60f61aa636cf148103e6569b2746d1 Mon Sep 17 00:00:00 2001 From: Michael Goderbauer <goderbauer@google.com> Date: Mon, 18 Sep 2023 13:51:09 -0700 Subject: [PATCH 1327/1547] Enable private field promotion for framework (#134473) New feature in upcoming Dart 3.2. See https://github.com/dart-lang/language/issues/2020. Feature is enabled by bumping the min SDK version to 3.2. Part of https://github.com/flutter/flutter/issues/134476. --- .../flutter/lib/src/cupertino/colors.dart | 2 +- packages/flutter/lib/src/cupertino/route.dart | 8 +++--- .../lib/src/foundation/diagnostics.dart | 2 +- .../src/foundation/persistent_hash_map.dart | 2 +- .../lib/src/material/button_theme.dart | 8 +++--- .../lib/src/material/ink_highlight.dart | 2 +- .../flutter/lib/src/material/ink_ripple.dart | 2 +- .../flutter/lib/src/material/ink_sparkle.dart | 4 +-- .../lib/src/material/list_tile_theme.dart | 26 +++++++++---------- .../flutter/lib/src/painting/strut_style.dart | 2 +- packages/flutter/lib/src/rendering/error.dart | 6 ++--- .../lib/src/widgets/editable_text.dart | 2 +- .../flutter/lib/src/widgets/framework.dart | 2 +- .../lib/src/widgets/icon_theme_data.dart | 2 +- packages/flutter/lib/src/widgets/router.dart | 4 +-- packages/flutter/lib/src/widgets/routes.dart | 2 +- .../lib/src/widgets/scroll_delegate.dart | 10 +++---- packages/flutter/pubspec.yaml | 2 +- .../flutter/test/widgets/routes_test.dart | 2 +- packages/flutter/test_private/pubspec.yaml | 2 +- .../flutter/test_private/test/pubspec.yaml | 2 +- 21 files changed, 47 insertions(+), 47 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/colors.dart b/packages/flutter/lib/src/cupertino/colors.dart index 7e0dfc1741734..8d57221c64376 100644 --- a/packages/flutter/lib/src/cupertino/colors.dart +++ b/packages/flutter/lib/src/cupertino/colors.dart @@ -1126,7 +1126,7 @@ class CupertinoDynamicColor extends Color with Diagnosticable { void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); if (_debugLabel != null) { - properties.add(MessageProperty('debugLabel', _debugLabel!)); + properties.add(MessageProperty('debugLabel', _debugLabel)); } properties.add(createCupertinoColorProperty('color', color)); if (_isPlatformBrightnessDependent) { diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index a354078c02b97..0c1d5262658dd 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -845,16 +845,16 @@ class _CupertinoEdgeShadowDecoration extends Decoration { return b!._colors == null ? b : _CupertinoEdgeShadowDecoration._(b._colors!.map<Color>((Color color) => Color.lerp(null, color, t)!).toList()); } if (b == null) { - return a._colors == null ? a : _CupertinoEdgeShadowDecoration._(a._colors!.map<Color>((Color color) => Color.lerp(null, color, 1.0 - t)!).toList()); + return a._colors == null ? a : _CupertinoEdgeShadowDecoration._(a._colors.map<Color>((Color color) => Color.lerp(null, color, 1.0 - t)!).toList()); } assert(b._colors != null || a._colors != null); // If it ever becomes necessary, we could allow decorations with different // length' here, similarly to how it is handled in [LinearGradient.lerp]. - assert(b._colors == null || a._colors == null || a._colors!.length == b._colors!.length); + assert(b._colors == null || a._colors == null || a._colors.length == b._colors.length); return _CupertinoEdgeShadowDecoration._( <Color>[ for (int i = 0; i < b._colors!.length; i += 1) - Color.lerp(a._colors?[i], b._colors?[i], t)!, + Color.lerp(a._colors?[i], b._colors[i], t)!, ], ); } @@ -904,7 +904,7 @@ class _CupertinoEdgeShadowPainter extends BoxPainter { _CupertinoEdgeShadowPainter( this._decoration, super.onChanged, - ) : assert(_decoration._colors == null || _decoration._colors!.length > 1); + ) : assert(_decoration._colors == null || _decoration._colors.length > 1); final _CupertinoEdgeShadowDecoration _decoration; diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index b2ecd9a903d28..04317cf19de03 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -2673,7 +2673,7 @@ class DiagnosticsProperty<T> extends DiagnosticsNode { @override String toDescription({ TextTreeConfiguration? parentConfiguration }) { if (_description != null) { - return _addTooltip(_description!); + return _addTooltip(_description); } if (exception != null) { diff --git a/packages/flutter/lib/src/foundation/persistent_hash_map.dart b/packages/flutter/lib/src/foundation/persistent_hash_map.dart index 411dca02b2b60..59bc692beb069 100644 --- a/packages/flutter/lib/src/foundation/persistent_hash_map.dart +++ b/packages/flutter/lib/src/foundation/persistent_hash_map.dart @@ -53,7 +53,7 @@ class PersistentHashMap<K extends Object, V> { // Unfortunately can not use unsafeCast<V?>(...) here because it leads // to worse code generation on VM. - return _root!.get(0, key, key.hashCode) as V?; + return _root.get(0, key, key.hashCode) as V?; } } diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart index 438d8fc6d01ce..a9866a0c18f7b 100644 --- a/packages/flutter/lib/src/material/button_theme.dart +++ b/packages/flutter/lib/src/material/button_theme.dart @@ -249,7 +249,7 @@ class ButtonThemeData with Diagnosticable { /// child (typically the button's label). EdgeInsetsGeometry get padding { if (_padding != null) { - return _padding!; + return _padding; } switch (textTheme) { case ButtonTextTheme.normal: @@ -277,7 +277,7 @@ class ButtonThemeData with Diagnosticable { /// [Material]. ShapeBorder get shape { if (_shape != null) { - return _shape!; + return _shape; } switch (textTheme) { case ButtonTextTheme.normal: @@ -537,7 +537,7 @@ class ButtonThemeData with Diagnosticable { switch (getTextTheme(button)) { case ButtonTextTheme.normal: case ButtonTextTheme.accent: - return _splashColor!; + return _splashColor; case ButtonTextTheme.primary: break; } @@ -642,7 +642,7 @@ class ButtonThemeData with Diagnosticable { } if (_padding != null) { - return _padding!; + return _padding; } switch (getTextTheme(button)) { diff --git a/packages/flutter/lib/src/material/ink_highlight.dart b/packages/flutter/lib/src/material/ink_highlight.dart index e294b30575977..c0d50a7940b64 100644 --- a/packages/flutter/lib/src/material/ink_highlight.dart +++ b/packages/flutter/lib/src/material/ink_highlight.dart @@ -130,7 +130,7 @@ class InkHighlight extends InteractiveInkFeature { void paintFeature(Canvas canvas, Matrix4 transform) { final Paint paint = Paint()..color = color.withAlpha(_alpha.value); final Offset? originOffset = MatrixUtils.getAsTranslation(transform); - final Rect rect = _rectCallback != null ? _rectCallback!() : Offset.zero & referenceBox.size; + final Rect rect = _rectCallback != null ? _rectCallback() : Offset.zero & referenceBox.size; if (originOffset == null) { canvas.save(); canvas.transform(transform.storage); diff --git a/packages/flutter/lib/src/material/ink_ripple.dart b/packages/flutter/lib/src/material/ink_ripple.dart index 7a574153db6cd..8f9dcde76e906 100644 --- a/packages/flutter/lib/src/material/ink_ripple.dart +++ b/packages/flutter/lib/src/material/ink_ripple.dart @@ -228,7 +228,7 @@ class InkRipple extends InteractiveInkFeature { final Paint paint = Paint()..color = color.withAlpha(alpha); Rect? rect; if (_clipCallback != null) { - rect = _clipCallback!(); + rect = _clipCallback(); } // Splash moves to the center of the reference box. final Offset center = Offset.lerp( diff --git a/packages/flutter/lib/src/material/ink_sparkle.dart b/packages/flutter/lib/src/material/ink_sparkle.dart index 9f63819fbe16c..d4d107735bc2d 100644 --- a/packages/flutter/lib/src/material/ink_sparkle.dart +++ b/packages/flutter/lib/src/material/ink_sparkle.dart @@ -285,7 +285,7 @@ class InkSparkle extends InteractiveInkFeature { if (_clipCallback != null) { _clipCanvas( canvas: canvas, - clipCallback: _clipCallback!, + clipCallback: _clipCallback, textDirection: _textDirection, customBorder: customBorder, borderRadius: _borderRadius, @@ -296,7 +296,7 @@ class InkSparkle extends InteractiveInkFeature { final Paint paint = Paint()..shader = _fragmentShader; if (_clipCallback != null) { - canvas.drawRect(_clipCallback!(), paint); + canvas.drawRect(_clipCallback(), paint); } else { canvas.drawPaint(paint); } diff --git a/packages/flutter/lib/src/material/list_tile_theme.dart b/packages/flutter/lib/src/material/list_tile_theme.dart index f3dc20ee979cc..bd06bbd6c5fc5 100644 --- a/packages/flutter/lib/src/material/list_tile_theme.dart +++ b/packages/flutter/lib/src/material/list_tile_theme.dart @@ -378,79 +378,79 @@ class ListTileTheme extends InheritedTheme { /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.dense] property instead. - bool? get dense => _data != null ? _data!.dense : _dense; + bool? get dense => _data != null ? _data.dense : _dense; /// Overrides the default value of [ListTile.shape]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.shape] property instead. - ShapeBorder? get shape => _data != null ? _data!.shape : _shape; + ShapeBorder? get shape => _data != null ? _data.shape : _shape; /// Overrides the default value of [ListTile.style]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.style] property instead. - ListTileStyle? get style => _data != null ? _data!.style : _style; + ListTileStyle? get style => _data != null ? _data.style : _style; /// Overrides the default value of [ListTile.selectedColor]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.selectedColor] property instead. - Color? get selectedColor => _data != null ? _data!.selectedColor : _selectedColor; + Color? get selectedColor => _data != null ? _data.selectedColor : _selectedColor; /// Overrides the default value of [ListTile.iconColor]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.iconColor] property instead. - Color? get iconColor => _data != null ? _data!.iconColor : _iconColor; + Color? get iconColor => _data != null ? _data.iconColor : _iconColor; /// Overrides the default value of [ListTile.textColor]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.textColor] property instead. - Color? get textColor => _data != null ? _data!.textColor : _textColor; + Color? get textColor => _data != null ? _data.textColor : _textColor; /// Overrides the default value of [ListTile.contentPadding]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.contentPadding] property instead. - EdgeInsetsGeometry? get contentPadding => _data != null ? _data!.contentPadding : _contentPadding; + EdgeInsetsGeometry? get contentPadding => _data != null ? _data.contentPadding : _contentPadding; /// Overrides the default value of [ListTile.tileColor]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.tileColor] property instead. - Color? get tileColor => _data != null ? _data!.tileColor : _tileColor; + Color? get tileColor => _data != null ? _data.tileColor : _tileColor; /// Overrides the default value of [ListTile.selectedTileColor]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.selectedTileColor] property instead. - Color? get selectedTileColor => _data != null ? _data!.selectedTileColor : _selectedTileColor; + Color? get selectedTileColor => _data != null ? _data.selectedTileColor : _selectedTileColor; /// Overrides the default value of [ListTile.horizontalTitleGap]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.horizontalTitleGap] property instead. - double? get horizontalTitleGap => _data != null ? _data!.horizontalTitleGap : _horizontalTitleGap; + double? get horizontalTitleGap => _data != null ? _data.horizontalTitleGap : _horizontalTitleGap; /// Overrides the default value of [ListTile.minVerticalPadding]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.minVerticalPadding] property instead. - double? get minVerticalPadding => _data != null ? _data!.minVerticalPadding : _minVerticalPadding; + double? get minVerticalPadding => _data != null ? _data.minVerticalPadding : _minVerticalPadding; /// Overrides the default value of [ListTile.minLeadingWidth]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.minLeadingWidth] property instead. - double? get minLeadingWidth => _data != null ? _data!.minLeadingWidth : _minLeadingWidth; + double? get minLeadingWidth => _data != null ? _data.minLeadingWidth : _minLeadingWidth; /// Overrides the default value of [ListTile.enableFeedback]. /// /// This property is obsolete: please use the [data] /// [ListTileThemeData.enableFeedback] property instead. - bool? get enableFeedback => _data != null ? _data!.enableFeedback : _enableFeedback; + bool? get enableFeedback => _data != null ? _data.enableFeedback : _enableFeedback; /// The [data] property of the closest instance of this class that /// encloses the given context. diff --git a/packages/flutter/lib/src/painting/strut_style.dart b/packages/flutter/lib/src/painting/strut_style.dart index 4899affb03f07..152ec3b8cfd19 100644 --- a/packages/flutter/lib/src/painting/strut_style.dart +++ b/packages/flutter/lib/src/painting/strut_style.dart @@ -405,7 +405,7 @@ class StrutStyle with Diagnosticable { /// constructor. List<String>? get fontFamilyFallback { if (_package != null && _fontFamilyFallback != null) { - return _fontFamilyFallback!.map((String family) => 'packages/$_package/$family').toList(); + return _fontFamilyFallback.map((String family) => 'packages/$_package/$family').toList(); } return _fontFamilyFallback; } diff --git a/packages/flutter/lib/src/rendering/error.dart b/packages/flutter/lib/src/rendering/error.dart index 41fa359da602d..ee7806faee6fa 100644 --- a/packages/flutter/lib/src/rendering/error.dart +++ b/packages/flutter/lib/src/rendering/error.dart @@ -157,11 +157,11 @@ class RenderErrorBox extends RenderBox { width -= padding.left + padding.right; left += padding.left; } - _paragraph!.layout(ui.ParagraphConstraints(width: width)); - if (size.height > padding.top + _paragraph!.height + padding.bottom) { + _paragraph.layout(ui.ParagraphConstraints(width: width)); + if (size.height > padding.top + _paragraph.height + padding.bottom) { top += padding.top; } - context.canvas.drawParagraph(_paragraph!, offset + Offset(left, top)); + context.canvas.drawParagraph(_paragraph, offset + Offset(left, top)); } } catch (error) { // If an error happens here we're in a terrible state, so we really should diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 264ca6665bcf0..225aba07a0e13 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -1002,7 +1002,7 @@ class EditableText extends StatefulWidget { if (_strutStyle == null) { return StrutStyle.fromTextStyle(style, forceStrutHeight: true); } - return _strutStyle!.inheritFromTextStyle(style); + return _strutStyle.inheritFromTextStyle(style); } final StrutStyle? _strutStyle; diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index ebe4e60e849cd..a8724cc3b4a6e 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -5359,7 +5359,7 @@ class ErrorWidget extends LeafRenderObjectWidget { if (_flutterError == null) { properties.add(StringProperty('message', message, quoted: false)); } else { - properties.add(_flutterError!.toDiagnosticsNode(style: DiagnosticsTreeStyle.whitespace)); + properties.add(_flutterError.toDiagnosticsNode(style: DiagnosticsTreeStyle.whitespace)); } } } diff --git a/packages/flutter/lib/src/widgets/icon_theme_data.dart b/packages/flutter/lib/src/widgets/icon_theme_data.dart index 6c27c54bb3bfd..3c890b9554cc6 100644 --- a/packages/flutter/lib/src/widgets/icon_theme_data.dart +++ b/packages/flutter/lib/src/widgets/icon_theme_data.dart @@ -157,7 +157,7 @@ class IconThemeData with Diagnosticable { /// An opacity to apply to both explicit and default icon colors. /// /// Falls back to 1.0. - double? get opacity => _opacity == null ? null : clampDouble(_opacity!, 0.0, 1.0); + double? get opacity => _opacity == null ? null : clampDouble(_opacity, 0.0, 1.0); final double? _opacity; /// The default for [Icon.shadows]. diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index f0ea0861005c8..f9ad34b1be7e9 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -65,7 +65,7 @@ class RouteInformation { ) String get location { if (_location != null) { - return _location!; + return _location; } return Uri.decodeComponent( Uri( @@ -86,7 +86,7 @@ class RouteInformation { /// In web platform, the host and scheme are always empty. Uri get uri { if (_uri != null){ - return _uri!; + return _uri; } return Uri.parse(_location!); } diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index d779df692d587..d36236d5d66f1 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -2155,7 +2155,7 @@ class RawDialogRoute<T> extends PopupRoute<T> { child: child, ); } - return _transitionBuilder!(context, animation, secondaryAnimation, child); + return _transitionBuilder(context, animation, secondaryAnimation, child); } } diff --git a/packages/flutter/lib/src/widgets/scroll_delegate.dart b/packages/flutter/lib/src/widgets/scroll_delegate.dart index 6a816f153bd33..eb2ec00e409d7 100644 --- a/packages/flutter/lib/src/widgets/scroll_delegate.dart +++ b/packages/flutter/lib/src/widgets/scroll_delegate.dart @@ -670,22 +670,22 @@ class SliverChildListDelegate extends SliverChildDelegate { } // Lazily fill the [_keyToIndex]. if (!_keyToIndex!.containsKey(key)) { - int index = _keyToIndex![null]!; + int index = _keyToIndex[null]!; while (index < children.length) { final Widget child = children[index]; if (child.key != null) { - _keyToIndex![child.key] = index; + _keyToIndex[child.key] = index; } if (child.key == key) { // Record current index for next function call. - _keyToIndex![null] = index + 1; + _keyToIndex[null] = index + 1; return index; } index += 1; } - _keyToIndex![null] = index; + _keyToIndex[null] = index; } else { - return _keyToIndex![key]; + return _keyToIndex[key]; } return null; } diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 5f4d0bd30d76c..b5e962b866616 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -3,7 +3,7 @@ description: A framework for writing Flutter applications homepage: https://flutter.dev environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter/test/widgets/routes_test.dart b/packages/flutter/test/widgets/routes_test.dart index 8d802f67e25f6..f695ecdd2404f 100644 --- a/packages/flutter/test/widgets/routes_test.dart +++ b/packages/flutter/test/widgets/routes_test.dart @@ -2078,7 +2078,7 @@ class _TestDialogRouteWithCustomBarrierCurve<T> extends PopupRoute<T> { if (_barrierCurve == null) { return super.barrierCurve; } - return _barrierCurve!; + return _barrierCurve; } final Curve? _barrierCurve; diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index 270187916f3f5..b2d9b52ec1af2 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_test_private description: Tests private interfaces of the flutter environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 72510d5dc9705..17b80ecc7a591 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -1,7 +1,7 @@ name: animated_icons_private_test environment: - sdk: '>=3.0.0-0 <4.0.0' + sdk: '>=3.2.0-0 <4.0.0' dependencies: # To update these, use "flutter update-packages --force-upgrade". From 43407cf155f38188dd7f9fe9698f4bd36bd9529a Mon Sep 17 00:00:00 2001 From: Vasiliy Ditsyak <v.ditsyak@gmail.com> Date: Mon, 18 Sep 2023 23:12:08 +0200 Subject: [PATCH 1328/1547] Access to fragment in router state on page refresh (#131123) This PR fixes the issue #108614 Particularly this behaviour https://github.com/flutter/flutter/issues/108614#issuecomment-1645231915 --- .../lib/src/navigation/url_strategy.dart | 14 +++++++++++++- .../src/navigation_non_web/url_strategy.dart | 2 +- .../test/navigation/url_strategy_test.dart | 19 ++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart index e0f0dbeaa81b8..ff2b08c063538 100644 --- a/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation/url_strategy.dart @@ -46,6 +46,7 @@ class PathUrlStrategy extends ui_web.HashUrlStrategy { /// interactions. PathUrlStrategy([ super.platformLocation, + this.includeHash = false, ]) : _platformLocation = platformLocation, _basePath = stripTrailingSlash(extractPathname(checkBaseHref( platformLocation.getBaseHref(), @@ -54,9 +55,20 @@ class PathUrlStrategy extends ui_web.HashUrlStrategy { final ui_web.PlatformLocation _platformLocation; final String _basePath; + /// There were an issue with url #hash which disappears from URL on first start of the web application + /// This flag allows to preserve that hash and was introduced mainly to preserve backward compatibility + /// with existing applications that rely on a full match on the path. If someone navigates to + /// /profile or /profile#foo, they both will work without this flag otherwise /profile#foo won't match + /// with the /profile route name anymore because the hash became part of the path. + /// + /// This flag solves the edge cases when using auth provider which redirects back to the app with + /// token in redirect URL as /#access_token=bla_bla_bla + final bool includeHash; + @override String getPath() { - final String path = _platformLocation.pathname + _platformLocation.search; + final String? hash = includeHash ? _platformLocation.hash : null; + final String path = _platformLocation.pathname + _platformLocation.search + (hash ?? ''); if (_basePath.isNotEmpty && path.startsWith(_basePath)) { return ensureLeadingSlash(path.substring(_basePath.length)); } diff --git a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart index 0a4703b8120b7..0e7aa1e994759 100644 --- a/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart +++ b/packages/flutter_web_plugins/lib/src/navigation_non_web/url_strategy.dart @@ -129,5 +129,5 @@ class PathUrlStrategy extends HashUrlStrategy { /// /// The [PlatformLocation] parameter is useful for testing to mock out browser /// integrations. - const PathUrlStrategy([PlatformLocation? _]); + const PathUrlStrategy([PlatformLocation? _, bool __ = false,]); } diff --git a/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart b/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart index f5bfa160554bf..d9e0a4d453595 100644 --- a/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart +++ b/packages/flutter_web_plugins/test/navigation/url_strategy_test.dart @@ -80,17 +80,34 @@ void main() { expect(strategy.getPath(), '/bar'); }); - test('gets path correctly in the presence of query params', () { + test('gets path correctly in the presence of query params and omits fragment if no flag specified', () { location.baseHref = 'https://example.com/foo/'; location.pathname = '/foo/bar'; final PathUrlStrategy strategy = PathUrlStrategy(location); + location.search = '?q=1'; + expect(strategy.getPath(), '/bar?q=1'); + + location.search = '?q=1&t=r'; + expect(strategy.getPath(), '/bar?q=1&t=r'); + + location.hash = '#fragment=1'; + expect(strategy.getPath(), '/bar?q=1&t=r'); + }); + + test('gets path correctly in the presence of query params and fragment', () { + location.baseHref = 'https://example.com/foo/'; + location.pathname = '/foo/bar'; + final PathUrlStrategy strategy = PathUrlStrategy(location, true); location.search = '?q=1'; expect(strategy.getPath(), '/bar?q=1'); location.search = '?q=1&t=r'; expect(strategy.getPath(), '/bar?q=1&t=r'); + + location.hash = '#fragment=1'; + expect(strategy.getPath(), '/bar?q=1&t=r#fragment=1'); }); test('empty route name is ok', () { From f2050e8a10cf46a18c47ad11a8494c5af929e153 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Mon, 18 Sep 2023 15:17:52 -0700 Subject: [PATCH 1329/1547] Fixes focus traversal crash if the current node can't request focus (#134954) fixes https://github.com/flutter/flutter/issues/134854 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../lib/src/widgets/focus_traversal.dart | 4 ++- .../test/widgets/focus_traversal_test.dart | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 203e13252958d..1d01055b914ae 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -433,7 +433,9 @@ abstract class FocusTraversalPolicy with Diagnosticable { // finds. assert((){ final Set<FocusNode> difference = sortedDescendants.toSet().difference(scope.traversalDescendants.toSet()); - if (currentNode.skipTraversal) { + if (currentNode.skipTraversal || !currentNode.canRequestFocus) { + // The scope.traversalDescendants will not contain currentNode if it + // skips traversal or not focusable. assert( difference.length == 1 && difference.contains(currentNode), 'Sorted descendants contains different nodes than FocusScopeNode.traversalDescendants would. ' diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index d8ccbbc8389a8..5b2abf4cf25ea 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -596,6 +596,41 @@ void main() { expect(scope.hasFocus, isTrue); }); + testWidgetsWithLeakTracking('Requesting nextFocus on node focuses its descendant', (WidgetTester tester) async { + for (final bool canRequestFocus in <bool>{true, false}) { + final FocusNode node1 = FocusNode(); + final FocusNode node2 = FocusNode(); + addTearDown(() { + node1.dispose(); + node2.dispose(); + }); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FocusTraversalGroup( + policy: ReadingOrderTraversalPolicy(), + child: FocusScope( + child: Focus( + focusNode: node1, + canRequestFocus: canRequestFocus, + child: Focus( + focusNode: node2, + child: Container(), + ), + ), + ), + ), + ), + ); + + final bool didFindNode = node1.nextFocus(); + await tester.pump(); + expect(didFindNode, isTrue); + expect(node1.hasPrimaryFocus, isFalse); + expect(node2.hasPrimaryFocus, isTrue); + } + }); + testWidgetsWithLeakTracking('Move reading focus to previous node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); From 5c6ef59b90aa7dc8f0df8ea6341da7e6ad5e96f6 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Mon, 18 Sep 2023 15:33:06 -0700 Subject: [PATCH 1330/1547] Resolve breaking change of adding a method to ChangeNotifier. (#134953) --- .../lib/src/foundation/change_notifier.dart | 14 +++++++------- packages/flutter/lib/src/rendering/paragraph.dart | 2 +- packages/flutter/lib/src/services/restoration.dart | 2 +- .../src/widgets/draggable_scrollable_sheet.dart | 2 +- .../flutter/lib/src/widgets/focus_manager.dart | 4 ++-- .../flutter/lib/src/widgets/focus_traversal.dart | 2 +- packages/flutter/lib/src/widgets/navigator.dart | 2 +- packages/flutter/lib/src/widgets/restoration.dart | 2 +- packages/flutter/lib/src/widgets/router.dart | 2 +- .../flutter/lib/src/widgets/scroll_controller.dart | 2 +- .../flutter/lib/src/widgets/selectable_region.dart | 2 +- packages/flutter/lib/src/widgets/shortcuts.dart | 4 ++-- .../flutter/lib/src/widgets/snapshot_widget.dart | 4 ---- .../flutter/lib/src/widgets/widget_inspector.dart | 2 +- .../test/foundation/change_notifier_test.dart | 4 ++-- .../test/widgets/automatic_keep_alive_test.dart | 2 +- .../widgets/route_notification_messages_test.dart | 2 +- .../test/widgets/router_restoration_test.dart | 4 ++-- packages/flutter/test/widgets/router_test.dart | 6 +++--- 19 files changed, 30 insertions(+), 34 deletions(-) diff --git a/packages/flutter/lib/src/foundation/change_notifier.dart b/packages/flutter/lib/src/foundation/change_notifier.dart index d8ab7d5720e43..7bfc2fb294a26 100644 --- a/packages/flutter/lib/src/foundation/change_notifier.dart +++ b/packages/flutter/lib/src/foundation/change_notifier.dart @@ -207,7 +207,7 @@ mixin class ChangeNotifier implements Listenable { @protected bool get hasListeners => _count > 0; - /// Dispatches event of object creation to [MemoryAllocations.instance]. + /// Dispatches event of the [object] creation to [MemoryAllocations.instance]. /// /// If the event was already dispatched or [kFlutterMemoryAllocationsEnabled] /// is false, the method is noop. @@ -227,16 +227,16 @@ mixin class ChangeNotifier implements Listenable { /// Make sure to invoke it with condition `if (kFlutterMemoryAllocationsEnabled) ...` /// so that the method is tree-shaken away when the flag is false. @protected - void maybeDispatchObjectCreation() { + static void maybeDispatchObjectCreation(ChangeNotifier object) { // Tree shaker does not include this method and the class MemoryAllocations // if kFlutterMemoryAllocationsEnabled is false. - if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) { + if (kFlutterMemoryAllocationsEnabled && !object._creationDispatched) { MemoryAllocations.instance.dispatchObjectCreated( library: _flutterFoundationLibrary, className: '$ChangeNotifier', - object: this, + object: object, ); - _creationDispatched = true; + object._creationDispatched = true; } } @@ -271,7 +271,7 @@ mixin class ChangeNotifier implements Listenable { assert(ChangeNotifier.debugAssertNotDisposed(this)); if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + maybeDispatchObjectCreation(this); } if (_count == _listeners.length) { @@ -535,7 +535,7 @@ class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> { /// Creates a [ChangeNotifier] that wraps this value. ValueNotifier(this._value) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 79e25371abe7c..111ddb3fc4195 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -1321,7 +1321,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM required this.range, }) : assert(range.isValid && !range.isCollapsed && range.isNormalized) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } _selectionGeometry = _getSelectionGeometry(); } diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index d3046a0e252cd..4bb7811f52764 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -155,7 +155,7 @@ class RestorationManager extends ChangeNotifier { /// with the engine to get restoration messages (by calling [initChannels]). RestorationManager() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } initChannels(); } diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 0cb003af71a02..276b711db400e 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -1074,7 +1074,7 @@ class _DraggableScrollableActuatorState extends State<DraggableScrollableActuato class _ResetNotifier extends ChangeNotifier { _ResetNotifier() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } /// Whether someone called [sendReset] or not. diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 991cb81534b76..54efacf0b11cb 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -439,7 +439,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { this.debugLabel = debugLabel; if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1468,7 +1468,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { /// documentation in that method for caveats to watch out for. FocusManager() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } rootScope._manager = this; } diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 1d01055b914ae..13a22d0dc74e7 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -1788,7 +1788,7 @@ class _FocusTraversalGroupNode extends FocusNode { required this.policy, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 41b570be858f5..4fbf1a6a5aec3 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -3390,7 +3390,7 @@ class _History extends Iterable<_RouteEntry> with ChangeNotifier { /// Creates an instance of [_History]. _History() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/restoration.dart b/packages/flutter/lib/src/widgets/restoration.dart index 367d90e47e80b..f3585417a0e63 100644 --- a/packages/flutter/lib/src/widgets/restoration.dart +++ b/packages/flutter/lib/src/widgets/restoration.dart @@ -457,7 +457,7 @@ abstract class RestorableProperty<T> extends ChangeNotifier { /// Creates a [RestorableProperty]. RestorableProperty(){ if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index f9ad34b1be7e9..c396a949ecf2a 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1467,7 +1467,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid required RouteInformation initialRouteInformation, }) : _value = initialRouteInformation { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/scroll_controller.dart b/packages/flutter/lib/src/widgets/scroll_controller.dart index 1f794b2ee2c9b..de88a41acc4a5 100644 --- a/packages/flutter/lib/src/widgets/scroll_controller.dart +++ b/packages/flutter/lib/src/widgets/scroll_controller.dart @@ -65,7 +65,7 @@ class ScrollController extends ChangeNotifier { this.onDetach, }) : _initialScrollOffset = initialScrollOffset { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index b0a26c11d04ad..371e178e026a3 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -1580,7 +1580,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai /// Creates an instance of [MultiSelectableSelectionContainerDelegate]. MultiSelectableSelectionContainerDelegate() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index c0118e633f608..293d28e979199 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -749,7 +749,7 @@ class ShortcutManager with Diagnosticable, ChangeNotifier { this.modal = false, }) : _shortcuts = shortcuts { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1203,7 +1203,7 @@ class ShortcutRegistry with ChangeNotifier { /// Creates an instance of [ShortcutRegistry]. ShortcutRegistry() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/snapshot_widget.dart b/packages/flutter/lib/src/widgets/snapshot_widget.dart index 7d509ce28ba72..854512f1f4528 100644 --- a/packages/flutter/lib/src/widgets/snapshot_widget.dart +++ b/packages/flutter/lib/src/widgets/snapshot_widget.dart @@ -482,8 +482,4 @@ class _DefaultSnapshotPainter implements SnapshotPainter { @override bool shouldRepaint(covariant _DefaultSnapshotPainter oldPainter) => false; - - @override - @protected - void maybeDispatchObjectCreation() { } } diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 66cc2d5abddb0..888a6c817b9fa 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2898,7 +2898,7 @@ class InspectorSelection with ChangeNotifier { /// Creates an instance of [InspectorSelection]. InspectorSelection() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/foundation/change_notifier_test.dart b/packages/flutter/test/foundation/change_notifier_test.dart index d766c6198dce0..6bb678a957002 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart @@ -29,7 +29,7 @@ class A { class B extends A with ChangeNotifier { B() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -43,7 +43,7 @@ class B extends A with ChangeNotifier { class Counter with ChangeNotifier { Counter() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/automatic_keep_alive_test.dart b/packages/flutter/test/widgets/automatic_keep_alive_test.dart index 60bf9e7cf588d..089a827d02d5b 100644 --- a/packages/flutter/test/widgets/automatic_keep_alive_test.dart +++ b/packages/flutter/test/widgets/automatic_keep_alive_test.dart @@ -638,7 +638,7 @@ class RenderSliverMultiBoxAdaptorAlt extends RenderSliver with class LeakCheckerHandle with ChangeNotifier { LeakCheckerHandle() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index 1d79ee0ed1c7b..1a3d65ae852cd 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -340,7 +340,7 @@ class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeN this.reportConfiguration = false, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/router_restoration_test.dart b/packages/flutter/test/widgets/router_restoration_test.dart index 4892c9c841ffe..4d429c893d1b0 100644 --- a/packages/flutter/test/widgets/router_restoration_test.dart +++ b/packages/flutter/test/widgets/router_restoration_test.dart @@ -92,7 +92,7 @@ class _TestRouteInformationParser extends RouteInformationParser<String> { class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { _TestRouterDelegate() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -136,7 +136,7 @@ class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { class _TestRouteInformationProvider extends RouteInformationProvider with ChangeNotifier { _TestRouteInformationProvider() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index fdb3407467c52..b6e5ec80cc7d9 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1646,7 +1646,7 @@ class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeN this.reportConfiguration = false, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1734,7 +1734,7 @@ class SimpleRouteInformationProvider extends RouteInformationProvider with Chang this.onRouterReport, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1794,7 +1794,7 @@ class SimpleAsyncRouterDelegate extends RouterDelegate<RouteInformation> with Ch required this.builder, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } From a9183f696c8e12617d05a26b0b5e80035e515f2a Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:04:06 -0700 Subject: [PATCH 1331/1547] Revert "Resolve breaking change of adding a method to ChangeNotifier." (#134978) Reverts flutter/flutter#134953 Several failures on CI --- .../lib/src/foundation/change_notifier.dart | 14 +++++++------- packages/flutter/lib/src/rendering/paragraph.dart | 2 +- packages/flutter/lib/src/services/restoration.dart | 2 +- .../src/widgets/draggable_scrollable_sheet.dart | 2 +- .../flutter/lib/src/widgets/focus_manager.dart | 4 ++-- .../flutter/lib/src/widgets/focus_traversal.dart | 2 +- packages/flutter/lib/src/widgets/navigator.dart | 2 +- packages/flutter/lib/src/widgets/restoration.dart | 2 +- packages/flutter/lib/src/widgets/router.dart | 2 +- .../flutter/lib/src/widgets/scroll_controller.dart | 2 +- .../flutter/lib/src/widgets/selectable_region.dart | 2 +- packages/flutter/lib/src/widgets/shortcuts.dart | 4 ++-- .../flutter/lib/src/widgets/snapshot_widget.dart | 4 ++++ .../flutter/lib/src/widgets/widget_inspector.dart | 2 +- .../test/foundation/change_notifier_test.dart | 4 ++-- .../test/widgets/automatic_keep_alive_test.dart | 2 +- .../widgets/route_notification_messages_test.dart | 2 +- .../test/widgets/router_restoration_test.dart | 4 ++-- packages/flutter/test/widgets/router_test.dart | 6 +++--- 19 files changed, 34 insertions(+), 30 deletions(-) diff --git a/packages/flutter/lib/src/foundation/change_notifier.dart b/packages/flutter/lib/src/foundation/change_notifier.dart index 7bfc2fb294a26..d8ab7d5720e43 100644 --- a/packages/flutter/lib/src/foundation/change_notifier.dart +++ b/packages/flutter/lib/src/foundation/change_notifier.dart @@ -207,7 +207,7 @@ mixin class ChangeNotifier implements Listenable { @protected bool get hasListeners => _count > 0; - /// Dispatches event of the [object] creation to [MemoryAllocations.instance]. + /// Dispatches event of object creation to [MemoryAllocations.instance]. /// /// If the event was already dispatched or [kFlutterMemoryAllocationsEnabled] /// is false, the method is noop. @@ -227,16 +227,16 @@ mixin class ChangeNotifier implements Listenable { /// Make sure to invoke it with condition `if (kFlutterMemoryAllocationsEnabled) ...` /// so that the method is tree-shaken away when the flag is false. @protected - static void maybeDispatchObjectCreation(ChangeNotifier object) { + void maybeDispatchObjectCreation() { // Tree shaker does not include this method and the class MemoryAllocations // if kFlutterMemoryAllocationsEnabled is false. - if (kFlutterMemoryAllocationsEnabled && !object._creationDispatched) { + if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) { MemoryAllocations.instance.dispatchObjectCreated( library: _flutterFoundationLibrary, className: '$ChangeNotifier', - object: object, + object: this, ); - object._creationDispatched = true; + _creationDispatched = true; } } @@ -271,7 +271,7 @@ mixin class ChangeNotifier implements Listenable { assert(ChangeNotifier.debugAssertNotDisposed(this)); if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } if (_count == _listeners.length) { @@ -535,7 +535,7 @@ class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> { /// Creates a [ChangeNotifier] that wraps this value. ValueNotifier(this._value) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 111ddb3fc4195..79e25371abe7c 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -1321,7 +1321,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM required this.range, }) : assert(range.isValid && !range.isCollapsed && range.isNormalized) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } _selectionGeometry = _getSelectionGeometry(); } diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index 4bb7811f52764..d3046a0e252cd 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -155,7 +155,7 @@ class RestorationManager extends ChangeNotifier { /// with the engine to get restoration messages (by calling [initChannels]). RestorationManager() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } initChannels(); } diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 276b711db400e..0cb003af71a02 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -1074,7 +1074,7 @@ class _DraggableScrollableActuatorState extends State<DraggableScrollableActuato class _ResetNotifier extends ChangeNotifier { _ResetNotifier() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } /// Whether someone called [sendReset] or not. diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 54efacf0b11cb..991cb81534b76 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -439,7 +439,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { this.debugLabel = debugLabel; if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } @@ -1468,7 +1468,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { /// documentation in that method for caveats to watch out for. FocusManager() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } rootScope._manager = this; } diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 13a22d0dc74e7..1d01055b914ae 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -1788,7 +1788,7 @@ class _FocusTraversalGroupNode extends FocusNode { required this.policy, }) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 4fbf1a6a5aec3..41b570be858f5 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -3390,7 +3390,7 @@ class _History extends Iterable<_RouteEntry> with ChangeNotifier { /// Creates an instance of [_History]. _History() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/restoration.dart b/packages/flutter/lib/src/widgets/restoration.dart index f3585417a0e63..367d90e47e80b 100644 --- a/packages/flutter/lib/src/widgets/restoration.dart +++ b/packages/flutter/lib/src/widgets/restoration.dart @@ -457,7 +457,7 @@ abstract class RestorableProperty<T> extends ChangeNotifier { /// Creates a [RestorableProperty]. RestorableProperty(){ if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index c396a949ecf2a..f9ad34b1be7e9 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1467,7 +1467,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid required RouteInformation initialRouteInformation, }) : _value = initialRouteInformation { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/scroll_controller.dart b/packages/flutter/lib/src/widgets/scroll_controller.dart index de88a41acc4a5..1f794b2ee2c9b 100644 --- a/packages/flutter/lib/src/widgets/scroll_controller.dart +++ b/packages/flutter/lib/src/widgets/scroll_controller.dart @@ -65,7 +65,7 @@ class ScrollController extends ChangeNotifier { this.onDetach, }) : _initialScrollOffset = initialScrollOffset { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 371e178e026a3..b0a26c11d04ad 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -1580,7 +1580,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai /// Creates an instance of [MultiSelectableSelectionContainerDelegate]. MultiSelectableSelectionContainerDelegate() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index 293d28e979199..c0118e633f608 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -749,7 +749,7 @@ class ShortcutManager with Diagnosticable, ChangeNotifier { this.modal = false, }) : _shortcuts = shortcuts { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } @@ -1203,7 +1203,7 @@ class ShortcutRegistry with ChangeNotifier { /// Creates an instance of [ShortcutRegistry]. ShortcutRegistry() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/lib/src/widgets/snapshot_widget.dart b/packages/flutter/lib/src/widgets/snapshot_widget.dart index 854512f1f4528..7d509ce28ba72 100644 --- a/packages/flutter/lib/src/widgets/snapshot_widget.dart +++ b/packages/flutter/lib/src/widgets/snapshot_widget.dart @@ -482,4 +482,8 @@ class _DefaultSnapshotPainter implements SnapshotPainter { @override bool shouldRepaint(covariant _DefaultSnapshotPainter oldPainter) => false; + + @override + @protected + void maybeDispatchObjectCreation() { } } diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 888a6c817b9fa..66cc2d5abddb0 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2898,7 +2898,7 @@ class InspectorSelection with ChangeNotifier { /// Creates an instance of [InspectorSelection]. InspectorSelection() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/test/foundation/change_notifier_test.dart b/packages/flutter/test/foundation/change_notifier_test.dart index 6bb678a957002..d766c6198dce0 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart @@ -29,7 +29,7 @@ class A { class B extends A with ChangeNotifier { B() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } @@ -43,7 +43,7 @@ class B extends A with ChangeNotifier { class Counter with ChangeNotifier { Counter() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/test/widgets/automatic_keep_alive_test.dart b/packages/flutter/test/widgets/automatic_keep_alive_test.dart index 089a827d02d5b..60bf9e7cf588d 100644 --- a/packages/flutter/test/widgets/automatic_keep_alive_test.dart +++ b/packages/flutter/test/widgets/automatic_keep_alive_test.dart @@ -638,7 +638,7 @@ class RenderSliverMultiBoxAdaptorAlt extends RenderSliver with class LeakCheckerHandle with ChangeNotifier { LeakCheckerHandle() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index 1a3d65ae852cd..1d79ee0ed1c7b 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -340,7 +340,7 @@ class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeN this.reportConfiguration = false, }) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/test/widgets/router_restoration_test.dart b/packages/flutter/test/widgets/router_restoration_test.dart index 4d429c893d1b0..4892c9c841ffe 100644 --- a/packages/flutter/test/widgets/router_restoration_test.dart +++ b/packages/flutter/test/widgets/router_restoration_test.dart @@ -92,7 +92,7 @@ class _TestRouteInformationParser extends RouteInformationParser<String> { class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { _TestRouterDelegate() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } @@ -136,7 +136,7 @@ class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { class _TestRouteInformationProvider extends RouteInformationProvider with ChangeNotifier { _TestRouteInformationProvider() { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index b6e5ec80cc7d9..fdb3407467c52 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1646,7 +1646,7 @@ class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeN this.reportConfiguration = false, }) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } @@ -1734,7 +1734,7 @@ class SimpleRouteInformationProvider extends RouteInformationProvider with Chang this.onRouterReport, }) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } @@ -1794,7 +1794,7 @@ class SimpleAsyncRouterDelegate extends RouterDelegate<RouteInformation> with Ch required this.builder, }) { if (kFlutterMemoryAllocationsEnabled) { - ChangeNotifier.maybeDispatchObjectCreation(this); + maybeDispatchObjectCreation(); } } From ab66f55728d90c48fdd93a982d9bb9e2bd83cf62 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Mon, 18 Sep 2023 20:31:54 -0700 Subject: [PATCH 1332/1547] Reland Resolve breaking change of adding a method to ChangeNotifier. (#134983) --- .../lib/src/foundation/change_notifier.dart | 14 +++++++------- packages/flutter/lib/src/rendering/paragraph.dart | 2 +- packages/flutter/lib/src/services/restoration.dart | 2 +- .../src/widgets/draggable_scrollable_sheet.dart | 2 +- .../flutter/lib/src/widgets/focus_manager.dart | 4 ++-- .../flutter/lib/src/widgets/focus_traversal.dart | 2 +- packages/flutter/lib/src/widgets/navigator.dart | 2 +- packages/flutter/lib/src/widgets/restoration.dart | 2 +- packages/flutter/lib/src/widgets/router.dart | 2 +- .../flutter/lib/src/widgets/scroll_controller.dart | 2 +- .../flutter/lib/src/widgets/selectable_region.dart | 2 +- packages/flutter/lib/src/widgets/shortcuts.dart | 4 ++-- .../flutter/lib/src/widgets/snapshot_widget.dart | 4 ---- .../flutter/lib/src/widgets/widget_inspector.dart | 2 +- .../test/foundation/change_notifier_test.dart | 4 ++-- packages/flutter/test/material/app_test.dart | 2 +- .../test/widgets/automatic_keep_alive_test.dart | 2 +- .../widgets/route_notification_messages_test.dart | 2 +- .../test/widgets/router_restoration_test.dart | 4 ++-- packages/flutter/test/widgets/router_test.dart | 6 +++--- 20 files changed, 31 insertions(+), 35 deletions(-) diff --git a/packages/flutter/lib/src/foundation/change_notifier.dart b/packages/flutter/lib/src/foundation/change_notifier.dart index d8ab7d5720e43..7bfc2fb294a26 100644 --- a/packages/flutter/lib/src/foundation/change_notifier.dart +++ b/packages/flutter/lib/src/foundation/change_notifier.dart @@ -207,7 +207,7 @@ mixin class ChangeNotifier implements Listenable { @protected bool get hasListeners => _count > 0; - /// Dispatches event of object creation to [MemoryAllocations.instance]. + /// Dispatches event of the [object] creation to [MemoryAllocations.instance]. /// /// If the event was already dispatched or [kFlutterMemoryAllocationsEnabled] /// is false, the method is noop. @@ -227,16 +227,16 @@ mixin class ChangeNotifier implements Listenable { /// Make sure to invoke it with condition `if (kFlutterMemoryAllocationsEnabled) ...` /// so that the method is tree-shaken away when the flag is false. @protected - void maybeDispatchObjectCreation() { + static void maybeDispatchObjectCreation(ChangeNotifier object) { // Tree shaker does not include this method and the class MemoryAllocations // if kFlutterMemoryAllocationsEnabled is false. - if (kFlutterMemoryAllocationsEnabled && !_creationDispatched) { + if (kFlutterMemoryAllocationsEnabled && !object._creationDispatched) { MemoryAllocations.instance.dispatchObjectCreated( library: _flutterFoundationLibrary, className: '$ChangeNotifier', - object: this, + object: object, ); - _creationDispatched = true; + object._creationDispatched = true; } } @@ -271,7 +271,7 @@ mixin class ChangeNotifier implements Listenable { assert(ChangeNotifier.debugAssertNotDisposed(this)); if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + maybeDispatchObjectCreation(this); } if (_count == _listeners.length) { @@ -535,7 +535,7 @@ class ValueNotifier<T> extends ChangeNotifier implements ValueListenable<T> { /// Creates a [ChangeNotifier] that wraps this value. ValueNotifier(this._value) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 79e25371abe7c..111ddb3fc4195 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -1321,7 +1321,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM required this.range, }) : assert(range.isValid && !range.isCollapsed && range.isNormalized) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } _selectionGeometry = _getSelectionGeometry(); } diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index d3046a0e252cd..4bb7811f52764 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -155,7 +155,7 @@ class RestorationManager extends ChangeNotifier { /// with the engine to get restoration messages (by calling [initChannels]). RestorationManager() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } initChannels(); } diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 0cb003af71a02..276b711db400e 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -1074,7 +1074,7 @@ class _DraggableScrollableActuatorState extends State<DraggableScrollableActuato class _ResetNotifier extends ChangeNotifier { _ResetNotifier() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } /// Whether someone called [sendReset] or not. diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 991cb81534b76..54efacf0b11cb 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -439,7 +439,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { this.debugLabel = debugLabel; if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1468,7 +1468,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier { /// documentation in that method for caveats to watch out for. FocusManager() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } rootScope._manager = this; } diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 1d01055b914ae..13a22d0dc74e7 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -1788,7 +1788,7 @@ class _FocusTraversalGroupNode extends FocusNode { required this.policy, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 41b570be858f5..4fbf1a6a5aec3 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -3390,7 +3390,7 @@ class _History extends Iterable<_RouteEntry> with ChangeNotifier { /// Creates an instance of [_History]. _History() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/restoration.dart b/packages/flutter/lib/src/widgets/restoration.dart index 367d90e47e80b..f3585417a0e63 100644 --- a/packages/flutter/lib/src/widgets/restoration.dart +++ b/packages/flutter/lib/src/widgets/restoration.dart @@ -457,7 +457,7 @@ abstract class RestorableProperty<T> extends ChangeNotifier { /// Creates a [RestorableProperty]. RestorableProperty(){ if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index f9ad34b1be7e9..c396a949ecf2a 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -1467,7 +1467,7 @@ class PlatformRouteInformationProvider extends RouteInformationProvider with Wid required RouteInformation initialRouteInformation, }) : _value = initialRouteInformation { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/scroll_controller.dart b/packages/flutter/lib/src/widgets/scroll_controller.dart index 1f794b2ee2c9b..de88a41acc4a5 100644 --- a/packages/flutter/lib/src/widgets/scroll_controller.dart +++ b/packages/flutter/lib/src/widgets/scroll_controller.dart @@ -65,7 +65,7 @@ class ScrollController extends ChangeNotifier { this.onDetach, }) : _initialScrollOffset = initialScrollOffset { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index b0a26c11d04ad..371e178e026a3 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -1580,7 +1580,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai /// Creates an instance of [MultiSelectableSelectionContainerDelegate]. MultiSelectableSelectionContainerDelegate() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart index c0118e633f608..293d28e979199 100644 --- a/packages/flutter/lib/src/widgets/shortcuts.dart +++ b/packages/flutter/lib/src/widgets/shortcuts.dart @@ -749,7 +749,7 @@ class ShortcutManager with Diagnosticable, ChangeNotifier { this.modal = false, }) : _shortcuts = shortcuts { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1203,7 +1203,7 @@ class ShortcutRegistry with ChangeNotifier { /// Creates an instance of [ShortcutRegistry]. ShortcutRegistry() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/lib/src/widgets/snapshot_widget.dart b/packages/flutter/lib/src/widgets/snapshot_widget.dart index 7d509ce28ba72..854512f1f4528 100644 --- a/packages/flutter/lib/src/widgets/snapshot_widget.dart +++ b/packages/flutter/lib/src/widgets/snapshot_widget.dart @@ -482,8 +482,4 @@ class _DefaultSnapshotPainter implements SnapshotPainter { @override bool shouldRepaint(covariant _DefaultSnapshotPainter oldPainter) => false; - - @override - @protected - void maybeDispatchObjectCreation() { } } diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 66cc2d5abddb0..888a6c817b9fa 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2898,7 +2898,7 @@ class InspectorSelection with ChangeNotifier { /// Creates an instance of [InspectorSelection]. InspectorSelection() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/foundation/change_notifier_test.dart b/packages/flutter/test/foundation/change_notifier_test.dart index d766c6198dce0..6bb678a957002 100644 --- a/packages/flutter/test/foundation/change_notifier_test.dart +++ b/packages/flutter/test/foundation/change_notifier_test.dart @@ -29,7 +29,7 @@ class A { class B extends A with ChangeNotifier { B() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -43,7 +43,7 @@ class B extends A with ChangeNotifier { class Counter with ChangeNotifier { Counter() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/material/app_test.dart b/packages/flutter/test/material/app_test.dart index 06b2cbb00ed06..2a4110f1d0fff 100644 --- a/packages/flutter/test/material/app_test.dart +++ b/packages/flutter/test/material/app_test.dart @@ -1570,7 +1570,7 @@ class SimpleNavigatorRouterDelegate extends RouterDelegate<RouteInformation> wit required this.builder, required this.onPopPage, }) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } @override diff --git a/packages/flutter/test/widgets/automatic_keep_alive_test.dart b/packages/flutter/test/widgets/automatic_keep_alive_test.dart index 60bf9e7cf588d..089a827d02d5b 100644 --- a/packages/flutter/test/widgets/automatic_keep_alive_test.dart +++ b/packages/flutter/test/widgets/automatic_keep_alive_test.dart @@ -638,7 +638,7 @@ class RenderSliverMultiBoxAdaptorAlt extends RenderSliver with class LeakCheckerHandle with ChangeNotifier { LeakCheckerHandle() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index 1d79ee0ed1c7b..1a3d65ae852cd 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -340,7 +340,7 @@ class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeN this.reportConfiguration = false, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/router_restoration_test.dart b/packages/flutter/test/widgets/router_restoration_test.dart index 4892c9c841ffe..4d429c893d1b0 100644 --- a/packages/flutter/test/widgets/router_restoration_test.dart +++ b/packages/flutter/test/widgets/router_restoration_test.dart @@ -92,7 +92,7 @@ class _TestRouteInformationParser extends RouteInformationParser<String> { class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { _TestRouterDelegate() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -136,7 +136,7 @@ class _TestRouterDelegate extends RouterDelegate<String> with ChangeNotifier { class _TestRouteInformationProvider extends RouteInformationProvider with ChangeNotifier { _TestRouteInformationProvider() { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index fdb3407467c52..b6e5ec80cc7d9 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1646,7 +1646,7 @@ class SimpleRouterDelegate extends RouterDelegate<RouteInformation> with ChangeN this.reportConfiguration = false, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1734,7 +1734,7 @@ class SimpleRouteInformationProvider extends RouteInformationProvider with Chang this.onRouterReport, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } @@ -1794,7 +1794,7 @@ class SimpleAsyncRouterDelegate extends RouterDelegate<RouteInformation> with Ch required this.builder, }) { if (kFlutterMemoryAllocationsEnabled) { - maybeDispatchObjectCreation(); + ChangeNotifier.maybeDispatchObjectCreation(this); } } From 893650416352789ec1253f69603589802f2b3f51 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 19 Sep 2023 02:10:24 -0400 Subject: [PATCH 1333/1547] Roll Flutter Engine from e1c784e3f841 to 589bde9a95c9 (16 revisions) (#134998) https://github.com/flutter/engine/compare/e1c784e3f841...589bde9a95c9 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from 4122791099ce to 744807d740c7 (1 revision) (flutter/engine#46019) 2023-09-19 jonahwilliams@google.com [Android] Add support for setting thread affinity based on core speed. (flutter/engine#45673) 2023-09-19 chinmaygarde@google.com [Impeller] Fix STB backend to account for max texture sizes. (flutter/engine#46010) 2023-09-19 matanlurey@users.noreply.github.com [Impeller] Hold the CommandPoolVK at a higher scope. (flutter/engine#46013) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from 0c990ab9e097 to 4122791099ce (19 revisions) (flutter/engine#46016) 2023-09-18 kjlubick@users.noreply.github.com Add missing include of SkPath (flutter/engine#45996) 2023-09-18 chinmaygarde@google.com [Impeller] Respect max supported texture size when allocating glyph atlas texture. (flutter/engine#45992) 2023-09-18 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 3_Lh8otTpmVuf-Zwb... to qy5FU4y6sx1FscCpd... (flutter/engine#45998) 2023-09-18 chris@bracken.jp Revert "[Windows] Update vsync on raster thread (#45310)" (flutter/engine#46000) 2023-09-18 matanlurey@users.noreply.github.com Provide a default `--target-variant` for `clang_tidy`. (flutter/engine#45909) 2023-09-18 ychris@google.com Revert "[ios] use python script to generate extension safe frameworks and code sign them" (flutter/engine#46004) 2023-09-18 john@johnmccutchan.com Disable HardwareBuffer backed Platform Views temporarily (flutter/engine#45986) 2023-09-18 john@johnmccutchan.com Tighten up ImageReaderPlatformViewRenderTarget code (flutter/engine#45889) 2023-09-18 ychris@google.com [ios] use python script to generate extension safe frameworks and code sign them (flutter/engine#45781) 2023-09-18 bdero@google.com Bump impeller-cmake to HEAD. (flutter/engine#45953) 2023-09-18 31859944+LongCatIsLooong@users.noreply.github.com [iOS] Remove selectionDidChange call in UndoManager (flutter/engine#45657) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 3_Lh8otTpmVu to qy5FU4y6sx1F If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 71dcbe8aaf38b..0c152eeb9fa5a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e1c784e3f8415f529a24886568806548f385c1d4 +589bde9a95c9c8c6d2e9cb920b4813d15cbcf99c diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c6ce50c165d4e..ec5dd71320e96 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -3_Lh8otTpmVuf-Zwb5yQy61cqmV-4g7xjO1wsANaeC0C +qy5FU4y6sx1FscCpd_r8vxXwLApv4irBWyfBT9WF374C From f246dc7ae0e6980d7e3bcd201305066f47e6e419 Mon Sep 17 00:00:00 2001 From: Daco Harkes <dacoharkes@google.com> Date: Tue, 19 Sep 2023 17:48:26 +0200 Subject: [PATCH 1334/1547] Bring native_assets ios tests out of staging (#135015) Move test added in https://github.com/flutter/flutter/pull/130494 out of staging. * https://ci.chromium.org/ui/p/flutter/builders/luci.flutter.staging/Mac_ios%20native_assets_ios * https://ci.chromium.org/ui/p/flutter/builders/luci.flutter.staging/Mac_ios%20native_assets_ios_simulator > Monitor the CI results of the new shard on the [Flutter build dashboard](https://flutter-dashboard.appspot.com/#/build). After 50 consecutive passing builds without any flakes, the flake bot will create a PR to remove the bringup: true parameter from .ci.yaml in the Framework tree. This will allow the test to block the tree, preventing breakages. With this change, the new shard will start running in presubmit automatically, unless specify presubmit: false. https://github.com/flutter/flutter/wiki/Adding-a-new-Test-Shard#steps-to-add-a-new-framework-test-shard Umbrella issue: * https://github.com/flutter/flutter/issues/129757 --- .ci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 5b7e2d2e1e5b3..7d0b3212756ee 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4103,7 +4103,6 @@ targets: - name: Mac_ios native_assets_ios_simulator recipe: devicelab/devicelab_drone presubmit: false - bringup: true # TODO(dacoharkes): Set to false in follow up PR and check that test works on CI. timeout: 60 properties: tags: > @@ -4113,7 +4112,6 @@ targets: - name: Mac_ios native_assets_ios recipe: devicelab/devicelab_drone presubmit: false - bringup: true # TODO(dacoharkes): Set to false in follow up PR and check that test works on CI. timeout: 60 properties: tags: > From d3c60569d16c5b11ce1e49ca66fbcd1431f82017 Mon Sep 17 00:00:00 2001 From: Jackson Gardner <jacksongardner@google.com> Date: Tue, 19 Sep 2023 09:26:16 -0700 Subject: [PATCH 1335/1547] Update CI to Chrome 117. (#134761) --- .ci.yaml | 148 +++++++++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 7d0b3212756ee..5b9542aba87b9 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -145,7 +145,7 @@ platform_properties: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] os: Mac-12 @@ -211,7 +211,7 @@ platform_properties: [ {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "certs", "version": "version:9563bb"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] os: Windows-10 @@ -288,7 +288,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, @@ -307,7 +307,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, @@ -326,7 +326,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, @@ -414,7 +414,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -660,7 +660,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -678,7 +678,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -696,7 +696,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -714,7 +714,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -732,7 +732,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -750,7 +750,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -769,7 +769,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"} + {"dependency": "chrome_and_driver", "version": "version:117.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -787,7 +787,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -806,7 +806,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -825,7 +825,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -923,7 +923,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"} + {"dependency": "chrome_and_driver", "version": "version:117.0"} ] tags: > ["devicelab", "hostonly", "linux"] @@ -949,7 +949,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "build_id:8787856497187628321"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, @@ -975,7 +975,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "build_id:8787856497187628321"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, @@ -1001,7 +1001,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "build_id:8787856497187628321"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, @@ -1027,7 +1027,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, {"dependency": "cmake", "version": "build_id:8787856497187628321"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, @@ -1093,7 +1093,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"} + {"dependency": "chrome_and_driver", "version": "version:117.0"} ] tags: > ["devicelab","hostonly", "linux"] @@ -1106,7 +1106,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"} + {"dependency": "chrome_and_driver", "version": "version:117.0"} ] tags: > ["devicelab"] @@ -1124,7 +1124,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"} + {"dependency": "chrome_and_driver", "version": "version:117.0"} ] tags: > ["devicelab"] @@ -1141,7 +1141,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1161,7 +1161,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1181,7 +1181,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1201,7 +1201,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1221,7 +1221,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_long_running_tests @@ -1241,7 +1241,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1261,7 +1261,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1281,7 +1281,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1301,7 +1301,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1321,7 +1321,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1341,7 +1341,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1361,7 +1361,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1381,7 +1381,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_tests @@ -1401,7 +1401,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1421,7 +1421,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1441,7 +1441,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1461,7 +1461,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1481,7 +1481,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1501,7 +1501,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1521,7 +1521,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1541,7 +1541,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: web_canvaskit_tests @@ -1561,7 +1561,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] @@ -2906,7 +2906,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -2924,7 +2924,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -2942,7 +2942,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -2960,7 +2960,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3441,7 +3441,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3465,7 +3465,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3489,7 +3489,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3513,7 +3513,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "gems", "version": "v3.3.14"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} @@ -3595,7 +3595,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] @@ -4424,7 +4424,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4442,7 +4442,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4460,7 +4460,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4478,7 +4478,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4496,7 +4496,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:17"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4603,7 +4603,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4635,7 +4635,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4654,7 +4654,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4674,7 +4674,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4706,7 +4706,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4725,7 +4725,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"} ] tags: > @@ -4798,7 +4798,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4822,7 +4822,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4846,7 +4846,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4870,7 +4870,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4894,7 +4894,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4918,7 +4918,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, {"dependency": "vs_build", "version": "version:vs2019"} @@ -4981,7 +4981,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] @@ -5002,7 +5002,7 @@ targets: dependencies: >- [ {"dependency": "android_sdk", "version": "version:33v6"}, - {"dependency": "chrome_and_driver", "version": "version:115.0"}, + {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "open_jdk", "version": "version:11"}, {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] From 4ce7fdd92b549a07173c5cefc189aeaaa9aa66be Mon Sep 17 00:00:00 2001 From: Greg Spencer <gspencergoog@users.noreply.github.com> Date: Tue, 19 Sep 2023 10:26:07 -0700 Subject: [PATCH 1336/1547] Remove 'must be non-null' and 'must not be null' comments from non-framework libraries (#134994) ## Description This removes all of the comments that are of the form "so-and-so must not be null" or "so-and-so must be non-null" from the cases where those values are defines as non-nullable values. This PR removes them from the library in the repo that don't have anything to do with the framework. This was done by hand, since it really didn't lend itself to scripting, so it needs to be more than just spot-checked, I think. I was careful to leave any comment that referred to parameters that were nullable, but I may have missed some. In addition to being no longer relevant after null safety has been made the default, these comments were largely fragile, in that it was easy for them to get out of date, and not be accurate anymore anyhow. This did create a number of constructor comments which basically say "Creates a [Foo].", but I don't really know how to avoid that in a large scale change, since there's not much you can really say in a lot of cases. I think we might consider some leniency for constructors to the "Comment must be meaningful" style guidance (which we de facto have already, since there are a bunch of these). ## Related PRs - https://github.com/flutter/flutter/pull/134984 - https://github.com/flutter/flutter/pull/134991 - https://github.com/flutter/flutter/pull/134992 - https://github.com/flutter/flutter/pull/134993 ## Tests - Documentation only change. --- .../macrobenchmarks/lib/src/web/recorder.dart | 2 -- .../gen_keycodes/lib/physical_key_data.dart | 2 -- examples/layers/rendering/src/sector_layout.dart | 2 -- packages/flutter_driver/lib/src/common/wait.dart | 16 ---------------- .../lib/src/extension/wait_conditions.dart | 14 -------------- .../flutter_test/lib/src/animation_sheet.dart | 2 -- packages/flutter_test/lib/src/binding.dart | 2 +- packages/flutter_test/lib/src/controller.dart | 4 ++-- .../lib/src/test_default_binary_messenger.dart | 2 -- .../build_system/targets/icon_tree_shaker.dart | 2 -- .../flutter_tools/lib/src/ios/plist_parser.dart | 6 ------ .../lib/src/plugin_event_channel.dart | 13 ++++--------- 12 files changed, 7 insertions(+), 60 deletions(-) diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart index 614f6aa349b6f..89661d6ddac1c 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/recorder.dart @@ -83,8 +83,6 @@ Future<void> _dummyAsyncVoidCallback() async {} @sealed class Runner { /// Creates a runner for the [recorder]. - /// - /// All arguments must not be null. Runner({ required this.recorder, this.setUpAllDidRun = _dummyAsyncVoidCallback, diff --git a/dev/tools/gen_keycodes/lib/physical_key_data.dart b/dev/tools/gen_keycodes/lib/physical_key_data.dart index 8bc7065ea8c08..b71a7cba1510a 100644 --- a/dev/tools/gen_keycodes/lib/physical_key_data.dart +++ b/dev/tools/gen_keycodes/lib/physical_key_data.dart @@ -214,8 +214,6 @@ class PhysicalKeyData { /// written with the [toJson] method. class PhysicalKeyEntry { /// Creates a single key entry from available data. - /// - /// The [usbHidCode] and [chromiumName] parameters must not be null. PhysicalKeyEntry({ required this.usbHidCode, required this.name, diff --git a/examples/layers/rendering/src/sector_layout.dart b/examples/layers/rendering/src/sector_layout.dart index e2716171f7969..a8bfa641f94dc 100644 --- a/examples/layers/rendering/src/sector_layout.dart +++ b/examples/layers/rendering/src/sector_layout.dart @@ -636,8 +636,6 @@ class SectorHitTestResult extends HitTestResult { /// A hit test entry used by [RenderSector]. class SectorHitTestEntry extends HitTestEntry { /// Creates a box hit test entry. - /// - /// The [radius] and [theta] argument must not be null. SectorHitTestEntry(RenderSector super.target, { required this.radius, required this.theta }); @override diff --git a/packages/flutter_driver/lib/src/common/wait.dart b/packages/flutter_driver/lib/src/common/wait.dart index 5d9e86fefbef3..0c19ce48c68c2 100644 --- a/packages/flutter_driver/lib/src/common/wait.dart +++ b/packages/flutter_driver/lib/src/common/wait.dart @@ -9,8 +9,6 @@ import 'message.dart'; /// A Flutter Driver command that waits until a given [condition] is satisfied. class WaitForCondition extends Command { /// Creates a command that waits for the given [condition] is met. - /// - /// The [condition] argument must not be null. const WaitForCondition(this.condition, {super.timeout}); /// Deserializes this command from the value generated by [serialize]. @@ -89,8 +87,6 @@ class NoTransientCallbacks extends SerializableWaitCondition { /// Factory constructor to parse a [NoTransientCallbacks] instance from the /// given JSON map. - /// - /// The [json] argument must not be null. factory NoTransientCallbacks.deserialize(Map<String, String> json) { if (json['conditionName'] != 'NoTransientCallbacksCondition') { throw SerializationException('Error occurred during deserializing the NoTransientCallbacksCondition JSON string: $json'); @@ -109,8 +105,6 @@ class NoPendingFrame extends SerializableWaitCondition { /// Factory constructor to parse a [NoPendingFrame] instance from the given /// JSON map. - /// - /// The [json] argument must not be null. factory NoPendingFrame.deserialize(Map<String, String> json) { if (json['conditionName'] != 'NoPendingFrameCondition') { throw SerializationException('Error occurred during deserializing the NoPendingFrameCondition JSON string: $json'); @@ -129,8 +123,6 @@ class FirstFrameRasterized extends SerializableWaitCondition { /// Factory constructor to parse a [FirstFrameRasterized] instance from the /// given JSON map. - /// - /// The [json] argument must not be null. factory FirstFrameRasterized.deserialize(Map<String, String> json) { if (json['conditionName'] != 'FirstFrameRasterizedCondition') { throw SerializationException('Error occurred during deserializing the FirstFrameRasterizedCondition JSON string: $json'); @@ -152,8 +144,6 @@ class NoPendingPlatformMessages extends SerializableWaitCondition { /// Factory constructor to parse a [NoPendingPlatformMessages] instance from the /// given JSON map. - /// - /// The [json] argument must not be null. factory NoPendingPlatformMessages.deserialize(Map<String, String> json) { if (json['conditionName'] != 'NoPendingPlatformMessagesCondition') { throw SerializationException('Error occurred during deserializing the NoPendingPlatformMessagesCondition JSON string: $json'); @@ -168,14 +158,10 @@ class NoPendingPlatformMessages extends SerializableWaitCondition { /// A combined condition that waits until all the given [conditions] are met. class CombinedCondition extends SerializableWaitCondition { /// Creates a [CombinedCondition] condition. - /// - /// The [conditions] argument must not be null. const CombinedCondition(this.conditions); /// Factory constructor to parse a [CombinedCondition] instance from the /// given JSON map. - /// - /// The [jsonMap] argument must not be null. factory CombinedCondition.deserialize(Map<String, String> jsonMap) { if (jsonMap['conditionName'] != 'CombinedCondition') { throw SerializationException('Error occurred during deserializing the CombinedCondition JSON string: $jsonMap'); @@ -210,8 +196,6 @@ class CombinedCondition extends SerializableWaitCondition { } /// Parses a [SerializableWaitCondition] or its subclass from the given [json] map. -/// -/// The [json] argument must not be null. SerializableWaitCondition _deserialize(Map<String, String> json) { final String conditionName = json['conditionName']!; switch (conditionName) { diff --git a/packages/flutter_driver/lib/src/extension/wait_conditions.dart b/packages/flutter_driver/lib/src/extension/wait_conditions.dart index 1f61bcc1ca0ff..424a0adf9370a 100644 --- a/packages/flutter_driver/lib/src/extension/wait_conditions.dart +++ b/packages/flutter_driver/lib/src/extension/wait_conditions.dart @@ -39,8 +39,6 @@ class _InternalNoTransientCallbacksCondition implements WaitCondition { /// Factory constructor to parse an [InternalNoTransientCallbacksCondition] /// instance from the given [SerializableWaitCondition] instance. - /// - /// The [condition] argument must not be null. factory _InternalNoTransientCallbacksCondition.deserialize(SerializableWaitCondition condition) { if (condition.conditionName != 'NoTransientCallbacksCondition') { throw SerializationException('Error occurred during deserializing from the given condition: ${condition.serialize()}'); @@ -67,8 +65,6 @@ class _InternalNoPendingFrameCondition implements WaitCondition { /// Factory constructor to parse an [InternalNoPendingFrameCondition] instance /// from the given [SerializableWaitCondition] instance. - /// - /// The [condition] argument must not be null. factory _InternalNoPendingFrameCondition.deserialize(SerializableWaitCondition condition) { if (condition.conditionName != 'NoPendingFrameCondition') { throw SerializationException('Error occurred during deserializing from the given condition: ${condition.serialize()}'); @@ -95,8 +91,6 @@ class _InternalFirstFrameRasterizedCondition implements WaitCondition { /// Factory constructor to parse an [InternalNoPendingFrameCondition] instance /// from the given [SerializableWaitCondition] instance. - /// - /// The [condition] argument must not be null. factory _InternalFirstFrameRasterizedCondition.deserialize(SerializableWaitCondition condition) { if (condition.conditionName != 'FirstFrameRasterizedCondition') { throw SerializationException('Error occurred during deserializing from the given condition: ${condition.serialize()}'); @@ -121,8 +115,6 @@ class _InternalNoPendingPlatformMessagesCondition implements WaitCondition { /// Factory constructor to parse an [_InternalNoPendingPlatformMessagesCondition] instance /// from the given [SerializableWaitCondition] instance. - /// - /// The [condition] argument must not be null. factory _InternalNoPendingPlatformMessagesCondition.deserialize(SerializableWaitCondition condition) { if (condition.conditionName != 'NoPendingPlatformMessagesCondition') { throw SerializationException('Error occurred during deserializing from the given condition: ${condition.serialize()}'); @@ -150,14 +142,10 @@ class _InternalNoPendingPlatformMessagesCondition implements WaitCondition { class _InternalCombinedCondition implements WaitCondition { /// Creates an [_InternalCombinedCondition] instance with the given list of /// [conditions]. - /// - /// The [conditions] argument must not be null. const _InternalCombinedCondition(this.conditions); /// Factory constructor to parse an [_InternalCombinedCondition] instance from /// the given [SerializableWaitCondition] instance. - /// - /// The [condition] argument must not be null. factory _InternalCombinedCondition.deserialize(SerializableWaitCondition condition) { if (condition.conditionName != 'CombinedCondition') { throw SerializationException('Error occurred during deserializing from the given condition: ${condition.serialize()}'); @@ -187,8 +175,6 @@ class _InternalCombinedCondition implements WaitCondition { } /// Parses a [WaitCondition] or its subclass from the given serializable [waitCondition]. -/// -/// The [waitCondition] argument must not be null. WaitCondition deserializeCondition(SerializableWaitCondition waitCondition) { final String conditionName = waitCondition.conditionName; switch (conditionName) { diff --git a/packages/flutter_test/lib/src/animation_sheet.dart b/packages/flutter_test/lib/src/animation_sheet.dart index 48b5d269ab5de..3d0d0bf65ed1b 100644 --- a/packages/flutter_test/lib/src/animation_sheet.dart +++ b/packages/flutter_test/lib/src/animation_sheet.dart @@ -175,8 +175,6 @@ class AnimationSheetBuilder { /// [collate]. If neither condition is met, the frames are not recorded, which /// is useful during setup phases. /// - /// The `child` must not be null. - /// /// See also: /// /// * [WidgetTester.pumpFrames], which renders a widget in a series of frames diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index b87105680848a..7be1c7a71bbc0 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -782,7 +782,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase /// /// The `description` is used by the [LiveTestWidgetsFlutterBinding] to /// show a label on the screen during the test. The description comes from - /// the value passed to [testWidgets]. It must not be null. + /// the value passed to [testWidgets]. Future<void> runTest( Future<void> Function() testBody, VoidCallback invariantTester, { diff --git a/packages/flutter_test/lib/src/controller.dart b/packages/flutter_test/lib/src/controller.dart index e1f668de2451a..d5763135a6c84 100644 --- a/packages/flutter_test/lib/src/controller.dart +++ b/packages/flutter_test/lib/src/controller.dart @@ -1426,7 +1426,7 @@ abstract class WidgetController { /// Specify `platform` as one of the platforms allowed in /// [platform.Platform.operatingSystem] to make the event appear to be from /// that type of system. Defaults to "web" on web, and "android" everywhere - /// else. Must not be null. + /// else. /// /// Specify the `physicalKey` for the event to override what is included in /// the simulated event. If not specified, it uses a default from the US @@ -1471,7 +1471,7 @@ abstract class WidgetController { /// Specify `platform` as one of the platforms allowed in /// [platform.Platform.operatingSystem] to make the event appear to be from /// that type of system. Defaults to "web" on web, and "android" everywhere - /// else. Must not be null. + /// else. /// /// Specify the `physicalKey` for the event to override what is included in /// the simulated event. If not specified, it uses a default from the US diff --git a/packages/flutter_test/lib/src/test_default_binary_messenger.dart b/packages/flutter_test/lib/src/test_default_binary_messenger.dart index f5c4e2f529369..25647bc9d90f3 100644 --- a/packages/flutter_test/lib/src/test_default_binary_messenger.dart +++ b/packages/flutter_test/lib/src/test_default_binary_messenger.dart @@ -47,8 +47,6 @@ typedef AllMessagesHandler = Future<ByteData?>? Function( /// Listeners for these messages are configured using [setMessageHandler]. class TestDefaultBinaryMessenger extends BinaryMessenger { /// Creates a [TestDefaultBinaryMessenger] instance. - /// - /// The [delegate] instance must not be null. TestDefaultBinaryMessenger( this.delegate, { Map<String, MessageHandler> outboundHandlers = const <String, MessageHandler>{}, diff --git a/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart b/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart index 7f3b0dee8bd56..916d1b3f59299 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart @@ -28,8 +28,6 @@ List<Map<String, Object?>> _getList(Object? object, String errorMessage) { class IconTreeShaker { /// Creates a wrapper for icon font subsetting. /// - /// The environment parameter must not be null. - /// /// If the `fontManifest` parameter is null, [enabled] will return false since /// there are no fonts to shake. /// diff --git a/packages/flutter_tools/lib/src/ios/plist_parser.dart b/packages/flutter_tools/lib/src/ios/plist_parser.dart index de40cedff8ede..b736f7cd63678 100644 --- a/packages/flutter_tools/lib/src/ios/plist_parser.dart +++ b/packages/flutter_tools/lib/src/ios/plist_parser.dart @@ -44,8 +44,6 @@ class PlistParser { /// /// If [plistFilePath] points to a non-existent file or a file that's not a /// valid property list file, this will return null. - /// - /// The [plistFilePath] argument must not be null. String? plistXmlContent(String plistFilePath) { if (!_fileSystem.isFileSync(_plutilExecutable)) { throw const FileNotFoundException(_plutilExecutable); @@ -101,8 +99,6 @@ class PlistParser { /// /// If [plistFilePath] points to a non-existent file or a file that's not a /// valid property list file, this will return an empty map. - /// - /// The [plistFilePath] argument must not be null. Map<String, Object> parseFile(String plistFilePath) { if (!_fileSystem.isFileSync(plistFilePath)) { return const <String, Object>{}; @@ -176,8 +172,6 @@ class PlistParser { /// valid property list file, this will return null. /// /// If [key] is not found in the property list, this will return null. - /// - /// The [plistFilePath] and [key] arguments must not be null. T? getValueFromFile<T>(String plistFilePath, String key) { final Map<String, dynamic> parsed = parseFile(plistFilePath); return parsed[key] as T?; diff --git a/packages/flutter_web_plugins/lib/src/plugin_event_channel.dart b/packages/flutter_web_plugins/lib/src/plugin_event_channel.dart index 00bd96a672670..d679e24caee0b 100644 --- a/packages/flutter_web_plugins/lib/src/plugin_event_channel.dart +++ b/packages/flutter_web_plugins/lib/src/plugin_event_channel.dart @@ -15,10 +15,9 @@ import 'plugin_registry.dart'; /// channel sends a stream of events to the handler listening on the /// framework-side. /// -/// The channel [name] must not be null. If no [codec] is provided, then -/// [StandardMethodCodec] is used. If no [binaryMessenger] is provided, then -/// [pluginBinaryMessenger], which sends messages to the framework-side, -/// is used. +/// If no [codec] is provided, then [StandardMethodCodec] is used. If no +/// [binaryMessenger] is provided, then [pluginBinaryMessenger], which sends +/// messages to the framework-side, is used. /// /// Channels created using this class implement two methods for /// subscribing to the event stream. The methods use the encoding of @@ -37,8 +36,6 @@ import 'plugin_registry.dart'; /// subscribed are silently discarded. class PluginEventChannel<T> { /// Creates a new plugin event channel. - /// - /// The [name] and [codec] arguments must not be null. const PluginEventChannel( this.name, [ this.codec = const StandardMethodCodec(), @@ -46,13 +43,11 @@ class PluginEventChannel<T> { ]); /// The logical channel on which communication happens. - /// - /// This must not be null. final String name; /// The message codec used by this channel. /// - /// This must not be null. This defaults to [StandardMethodCodec]. + /// Defaults to [StandardMethodCodec]. final MethodCodec codec; /// The messenger used by this channel to send platform messages. From 5b47fef613e2d74ae44e1e22c2a3495294db180e Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 19 Sep 2023 15:49:57 -0400 Subject: [PATCH 1337/1547] Manual roll Flutter Engine from 589bde9a95c9 to 28f14e6eec4f (11 revisions) (#135041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manual roll requested by jonahwilliams@google.com https://github.com/flutter/engine/compare/589bde9a95c9...28f14e6eec4f 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from d54cf63f051b to d756a2f5665d (5 revisions) (flutter/engine#46048) 2023-09-19 jacksongardner@google.com Update CI to Chrome 117 (flutter/engine#45842) 2023-09-19 mdebbar@google.com [web] DOM objects implement JS object (flutter/engine#46047) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from 91adc7d289f7 to d54cf63f051b (3 revisions) (flutter/engine#46043) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from 1e84aa4509cd to 91adc7d289f7 (2 revisions) (flutter/engine#46040) 2023-09-19 skia-flutter-autoroll@skia.org Roll Dart SDK from 8ad823c03f26 to e7cd697bd0e9 (2 revisions) (flutter/engine#46039) 2023-09-19 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from qy5FU4y6sx1FscCpd... to 06g6i7-5u8O-FOTSi... (flutter/engine#46038) 2023-09-19 kjlubick@users.noreply.github.com Add more missing Skia #includes (flutter/engine#46034) 2023-09-19 leroux_bruno@yahoo.fr [macOS,iOS] Expose channel buffers 'resize' and 'overflow' control co… (flutter/engine#44848) 2023-09-19 skia-flutter-autoroll@skia.org Roll Dart SDK from 5b0e7bda1379 to 8ad823c03f26 (3 revisions) (flutter/engine#46028) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from 744807d740c7 to 1e84aa4509cd (4 revisions) (flutter/engine#46026) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from qy5FU4y6sx1F to 06g6i7-5u8O- If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0c152eeb9fa5a..21517c83ede06 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -589bde9a95c9c8c6d2e9cb920b4813d15cbcf99c +28f14e6eec4f4dbe6d678f758ca7ff4654473f54 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index ec5dd71320e96..f7ba18dba0bde 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -qy5FU4y6sx1FscCpd_r8vxXwLApv4irBWyfBT9WF374C +06g6i7-5u8O-FOTSiXV49zPhENc4ZaXzGkSyFuDpJQgC From 65693955343d710a03f52f0ee5c9fceb69bc7ea5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 19 Sep 2023 17:39:52 -0400 Subject: [PATCH 1338/1547] Manual roll Flutter Engine from 28f14e6eec4f to 10c480310926 (6 revisions) (#135066) Manual roll requested by jonahwilliams@google.com Cannot build log URL because revision "10c480310926" is invalid: Luci builds of "Linux Fuchsia" for 10c480310926d7e04a77ba8a04d321f9d225a545 was INFRA_FAILURE 2023-09-19 matanlurey@users.noreply.github.com Add TODO(name) to comply with Clang Tidy. (flutter/engine#46057) 2023-09-19 ychris@google.com [ios]Adjust golden test threshold for TwoPlatformViewsWithOtherBackDropFilterTests based on current macOS version (flutter/engine#45891) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from d756a2f5665d to 559a964f9f1b (9 revisions) (flutter/engine#46059) 2023-09-19 skia-flutter-autoroll@skia.org Roll Dart SDK from e7cd697bd0e9 to b8f006d88c07 (1 revision) (flutter/engine#46055) 2023-09-19 matanlurey@users.noreply.github.com Deprecate `fml::LOG_X` in favor of `kLogX`. (flutter/engine#46052) 2023-09-19 matanlurey@users.noreply.github.com Rename `layoutGoals` to `kLayoutGoals` to enforce lints on headers. (flutter/engine#46054) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 21517c83ede06..c73600fdfd049 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -28f14e6eec4f4dbe6d678f758ca7ff4654473f54 +10c480310926d7e04a77ba8a04d321f9d225a545 From ba2dde48fa135e1d0eeaac45948af3c8d692f2b8 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Tue, 19 Sep 2023 15:33:29 -0700 Subject: [PATCH 1339/1547] Specify suggested format in doc comment. (#134887) --- packages/flutter/lib/src/foundation/memory_allocations.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/flutter/lib/src/foundation/memory_allocations.dart b/packages/flutter/lib/src/foundation/memory_allocations.dart index dd918dd625464..abc6481858c4e 100644 --- a/packages/flutter/lib/src/foundation/memory_allocations.dart +++ b/packages/flutter/lib/src/foundation/memory_allocations.dart @@ -64,6 +64,9 @@ class ObjectCreated extends ObjectEvent { }); /// Name of the instrumented library. + /// + /// The format of this parameter should be a library Uri. + /// For example: `'package:flutter/rendering.dart'`. final String library; /// Name of the instrumented class. From c7c9d8eea6c9fe44bceb6d78be35c5046f46bca8 Mon Sep 17 00:00:00 2001 From: David Iglesias <ditman@gmail.com> Date: Tue, 19 Sep 2023 15:38:51 -0700 Subject: [PATCH 1340/1547] [web] Encode AssetManifest.bin as JSON and use that on the web. (#131382) This PR modifies the web build slightly to create an `AssetManifest.json`, that is a JSON(base64)-encoded version of the `AssetManifest.bin` file. _(This should enable all browsers to download the file without any interference, and all servers to serve it with the correct headers.)_ It also modifies Flutter's `AssetManifest` class so it loads and uses said file `if (kIsWeb)`. ### Issues * Fixes https://github.com/flutter/flutter/issues/124883 ### Tests * Unit tests added. * Some tests that run on the Web needed to be informed of the new filename, but their behavior didn't have to change (binary contents are the same across all platforms). * I've deployed a test app, so users affected by the BIN issue may take a look at the PR in action: * https://dit-tests.web.app --- .../lib/src/services/asset_bundle.dart | 4 +- .../lib/src/services/asset_manifest.dart | 28 +++++- .../test/painting/image_resolution_test.dart | 17 ++++ .../test/services/asset_bundle_test.dart | 16 ++++ .../test/services/asset_manifest_test.dart | 54 +++++++---- packages/flutter_tools/lib/src/asset.dart | 17 +++- .../test/general.shard/asset_bundle_test.dart | 96 +++++++++++++++++++ 7 files changed, 205 insertions(+), 27 deletions(-) diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart index 238467b27db6c..0c65ca323ca74 100644 --- a/packages/flutter/lib/src/services/asset_bundle.dart +++ b/packages/flutter/lib/src/services/asset_bundle.dart @@ -88,8 +88,8 @@ abstract class AssetBundle { Future<String> loadString(String key, { bool cache = true }) async { final ByteData data = await load(key); // 50 KB of data should take 2-3 ms to parse on a Moto G4, and about 400 μs - // on a Pixel 4. - if (data.lengthInBytes < 50 * 1024) { + // on a Pixel 4. On the web we can't bail to isolates, though... + if (data.lengthInBytes < 50 * 1024 || kIsWeb) { return utf8.decode(Uint8List.sublistView(data)); } // For strings larger than 50 KB, run the computation in an isolate to diff --git a/packages/flutter/lib/src/services/asset_manifest.dart b/packages/flutter/lib/src/services/asset_manifest.dart index 3b27490098a8d..c948067e4cb39 100644 --- a/packages/flutter/lib/src/services/asset_manifest.dart +++ b/packages/flutter/lib/src/services/asset_manifest.dart @@ -2,18 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:convert'; + import 'package:flutter/foundation.dart'; import 'asset_bundle.dart'; import 'message_codecs.dart'; // We use .bin as the extension since it is well-known to represent -// data in some arbitrary binary format. Using a well-known extension here -// is important for web, because some web servers will not serve files with -// unrecognized file extensions by default. -// See https://github.com/flutter/flutter/issues/128456. +// data in some arbitrary binary format. const String _kAssetManifestFilename = 'AssetManifest.bin'; +// We use the same bin file for the web, but re-encoded as JSON(base64(bytes)) +// so it can be downloaded by even the dumbest of browsers. +// See https://github.com/flutter/flutter/issues/128456 +const String _kAssetManifestWebFilename = 'AssetManifest.bin.json'; + /// Contains details about available assets and their variants. /// See [Resolution-aware image assets](https://docs.flutter.dev/ui/assets-and-images#resolution-aware) /// to learn about asset variants and how to declare them. @@ -21,6 +25,22 @@ abstract class AssetManifest { /// Loads asset manifest data from an [AssetBundle] object and creates an /// [AssetManifest] object from that data. static Future<AssetManifest> loadFromAssetBundle(AssetBundle bundle) { + // The AssetManifest file contains binary data. + // + // On the web, the build process wraps this binary data in json+base64 so + // it can be transmitted over the network without special configuration + // (see #131382). + if (kIsWeb) { + // On the web, the AssetManifest is downloaded as a String, then + // json+base64-decoded to get to the binary data. + return bundle.loadStructuredData(_kAssetManifestWebFilename, (String jsonData) async { + // Decode the manifest JSON file to the underlying BIN, and convert to ByteData. + final ByteData message = ByteData.sublistView(base64.decode(json.decode(jsonData) as String)); + // Now we can keep operating as usual. + return _AssetManifestBin.fromStandardMessageCodecMessage(message); + }); + } + // On every other platform, the binary file contents are used directly. return bundle.loadStructuredBinaryData(_kAssetManifestFilename, _AssetManifestBin.fromStandardMessageCodecMessage); } diff --git a/packages/flutter/test/painting/image_resolution_test.dart b/packages/flutter/test/painting/image_resolution_test.dart index 2a784de9e0764..e52f1b274b34e 100644 --- a/packages/flutter/test/painting/image_resolution_test.dart +++ b/packages/flutter/test/painting/image_resolution_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:convert'; import 'dart:ui' as ui; import 'package:flutter/foundation.dart'; @@ -22,6 +23,22 @@ class TestAssetBundle extends CachingAssetBundle { return const StandardMessageCodec().encodeMessage(_assetBundleMap)!; } + if (key == 'AssetManifest.bin.json') { + // Encode the manifest data that will be used by the app + final ByteData data = const StandardMessageCodec().encodeMessage(_assetBundleMap)!; + // Simulate the behavior of NetworkAssetBundle.load here, for web tests + return ByteData.sublistView( + utf8.encode( + json.encode( + base64.encode( + // Encode only the actual bytes of the buffer, and no more... + data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes) + ) + ) + ) + ); + } + loadCallCount[key] = loadCallCount[key] ?? 0 + 1; if (key == 'one') { return ByteData(1) diff --git a/packages/flutter/test/services/asset_bundle_test.dart b/packages/flutter/test/services/asset_bundle_test.dart index 2177935357c80..7641adaf1a8a4 100644 --- a/packages/flutter/test/services/asset_bundle_test.dart +++ b/packages/flutter/test/services/asset_bundle_test.dart @@ -25,6 +25,22 @@ class TestAssetBundle extends CachingAssetBundle { .encodeMessage(<String, Object>{'one': <Object>[]})!; } + if (key == 'AssetManifest.bin.json') { + // Encode the manifest data that will be used by the app + final ByteData data = const StandardMessageCodec().encodeMessage(<String, Object> {'one': <Object>[]})!; + // Simulate the behavior of NetworkAssetBundle.load here, for web tests + return ByteData.sublistView( + utf8.encode( + json.encode( + base64.encode( + // Encode only the actual bytes of the buffer, and no more... + data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes) + ) + ) + ) + ); + } + if (key == 'counter') { return ByteData.sublistView(utf8.encode(loadCallCount[key]!.toString())); } diff --git a/packages/flutter/test/services/asset_manifest_test.dart b/packages/flutter/test/services/asset_manifest_test.dart index c06ffd0126b64..108515f4330d0 100644 --- a/packages/flutter/test/services/asset_manifest_test.dart +++ b/packages/flutter/test/services/asset_manifest_test.dart @@ -2,34 +2,52 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:convert'; + import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; class TestAssetBundle extends AssetBundle { + static const Map<String, List<Object>> _binManifestData = <String, List<Object>>{ + 'assets/foo.png': <Object>[ + <String, Object>{ + 'asset': 'assets/foo.png', + }, + <String, Object>{ + 'asset': 'assets/2x/foo.png', + 'dpr': 2.0 + }, + ], + 'assets/bar.png': <Object>[ + <String, Object>{ + 'asset': 'assets/bar.png', + }, + ], + }; + @override Future<ByteData> load(String key) async { if (key == 'AssetManifest.bin') { - final Map<String, List<Object>> binManifestData = <String, List<Object>>{ - 'assets/foo.png': <Object>[ - <String, Object>{ - 'asset': 'assets/foo.png', - }, - <String, Object>{ - 'asset': 'assets/2x/foo.png', - 'dpr': 2.0 - }, - ], - 'assets/bar.png': <Object>[ - <String, Object>{ - 'asset': 'assets/bar.png', - }, - ], - }; - - final ByteData data = const StandardMessageCodec().encodeMessage(binManifestData)!; + final ByteData data = const StandardMessageCodec().encodeMessage(_binManifestData)!; return data; } + if (key == 'AssetManifest.bin.json') { + // Encode the manifest data that will be used by the app + final ByteData data = const StandardMessageCodec().encodeMessage(_binManifestData)!; + // Simulate the behavior of NetworkAssetBundle.load here, for web tests + return ByteData.sublistView( + utf8.encode( + json.encode( + base64.encode( + // Encode only the actual bytes of the buffer, and no more... + data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes) + ) + ) + ) + ); + } + throw ArgumentError('Unexpected key'); } diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index 7c8f054517cdb..7eda50bc1f7de 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart @@ -168,6 +168,7 @@ class ManifestAssetBundle implements AssetBundle { // We assume the main asset is designed for a device pixel ratio of 1.0. static const String _kAssetManifestJsonFilename = 'AssetManifest.json'; static const String _kAssetManifestBinFilename = 'AssetManifest.bin'; + static const String _kAssetManifestBinJsonFilename = 'AssetManifest.bin.json'; static const String _kNoticeFile = 'NOTICES'; // Comically, this can't be name with the more common .gz file extension @@ -233,8 +234,6 @@ class ManifestAssetBundle implements AssetBundle { // device. _lastBuildTimestamp = DateTime.now(); if (flutterManifest.isEmpty) { - entries[_kAssetManifestJsonFilename] = DevFSStringContent('{}'); - entryKinds[_kAssetManifestJsonFilename] = AssetKind.regular; entries[_kAssetManifestJsonFilename] = DevFSStringContent('{}'); entryKinds[_kAssetManifestJsonFilename] = AssetKind.regular; final ByteData emptyAssetManifest = @@ -242,6 +241,11 @@ class ManifestAssetBundle implements AssetBundle { entries[_kAssetManifestBinFilename] = DevFSByteContent(emptyAssetManifest.buffer.asUint8List(0, emptyAssetManifest.lengthInBytes)); entryKinds[_kAssetManifestBinFilename] = AssetKind.regular; + // Create .bin.json on web builds. + if (targetPlatform == TargetPlatform.web_javascript) { + entries[_kAssetManifestBinJsonFilename] = DevFSStringContent('""'); + entryKinds[_kAssetManifestBinJsonFilename] = AssetKind.regular; + } return 0; } @@ -437,8 +441,8 @@ class ManifestAssetBundle implements AssetBundle { final Map<String, List<String>> assetManifest = _createAssetManifest(assetVariants, deferredComponentsAssetVariants); - final DevFSStringContent assetManifestJson = DevFSStringContent(json.encode(assetManifest)); final DevFSByteContent assetManifestBinary = _createAssetManifestBinary(assetManifest); + final DevFSStringContent assetManifestJson = DevFSStringContent(json.encode(assetManifest)); final DevFSStringContent fontManifest = DevFSStringContent(json.encode(fonts)); final LicenseResult licenseResult = _licenseCollector.obtainLicenses(packageConfig, additionalLicenseFiles); if (licenseResult.errorMessages.isNotEmpty) { @@ -464,6 +468,13 @@ class ManifestAssetBundle implements AssetBundle { _setIfChanged(_kAssetManifestJsonFilename, assetManifestJson, AssetKind.regular); _setIfChanged(_kAssetManifestBinFilename, assetManifestBinary, AssetKind.regular); + // Create .bin.json on web builds. + if (targetPlatform == TargetPlatform.web_javascript) { + final DevFSStringContent assetManifestBinaryJson = DevFSStringContent(json.encode( + base64.encode(assetManifestBinary.bytes) + )); + _setIfChanged(_kAssetManifestBinJsonFilename, assetManifestBinaryJson, AssetKind.regular); + } _setIfChanged(kFontManifestJson, fontManifest, AssetKind.regular); _setLicenseIfChanged(licenseResult.combinedLicenses, targetPlatform); return 0; diff --git a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart index 11837c7fb2572..4b798f61ec665 100644 --- a/packages/flutter_tools/test/general.shard/asset_bundle_test.dart +++ b/packages/flutter_tools/test/general.shard/asset_bundle_test.dart @@ -325,6 +325,102 @@ flutter: }); }); + group('AssetBundle.build (web builds)', () { + late FileSystem testFileSystem; + + setUp(() async { + testFileSystem = MemoryFileSystem( + style: globals.platform.isWindows + ? FileSystemStyle.windows + : FileSystemStyle.posix, + ); + testFileSystem.currentDirectory = testFileSystem.systemTempDirectory.createTempSync('flutter_asset_bundle_test.'); + }); + + testUsingContext('empty pubspec', () async { + globals.fs.file('pubspec.yaml') + ..createSync() + ..writeAsStringSync(''); + + final AssetBundle bundle = AssetBundleFactory.instance.createBundle(); + await bundle.build(packagesPath: '.packages', targetPlatform: TargetPlatform.web_javascript); + + expect(bundle.entries.keys, + unorderedEquals(<String>[ + 'AssetManifest.json', + 'AssetManifest.bin', + 'AssetManifest.bin.json', + ]) + ); + expect( + utf8.decode(await bundle.entries['AssetManifest.json']!.contentsAsBytes()), + '{}', + ); + expect( + utf8.decode(await bundle.entries['AssetManifest.bin.json']!.contentsAsBytes()), + '""', + ); + }, overrides: <Type, Generator>{ + FileSystem: () => testFileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('pubspec contains an asset', () async { + globals.fs.file('.packages').createSync(); + globals.fs.file('pubspec.yaml').writeAsStringSync(r''' +name: test +dependencies: + flutter: + sdk: flutter +flutter: + assets: + - assets/bar/lizard.png +'''); + globals.fs.file( + globals.fs.path.joinAll(<String>['assets', 'bar', 'lizard.png']) + ).createSync(recursive: true); + + final AssetBundle bundle = AssetBundleFactory.instance.createBundle(); + await bundle.build(packagesPath: '.packages', targetPlatform: TargetPlatform.web_javascript); + + expect(bundle.entries.keys, + unorderedEquals(<String>[ + 'AssetManifest.json', + 'AssetManifest.bin', + 'AssetManifest.bin.json', + 'FontManifest.json', + 'NOTICES', // not .Z + 'assets/bar/lizard.png', + ]) + ); + final Map<Object?, Object?> manifestJson = json.decode( + utf8.decode( + await bundle.entries['AssetManifest.json']!.contentsAsBytes() + ) + ) as Map<Object?, Object?>; + expect(manifestJson, isNotEmpty); + expect(manifestJson['assets/bar/lizard.png'], isNotNull); + + final Uint8List manifestBinJsonBytes = base64.decode( + json.decode( + utf8.decode( + await bundle.entries['AssetManifest.bin.json']!.contentsAsBytes() + ) + ) as String + ); + + final Uint8List manifestBinBytes = Uint8List.fromList( + await bundle.entries['AssetManifest.bin']!.contentsAsBytes() + ); + + expect(manifestBinJsonBytes, equals(manifestBinBytes), + reason: 'JSON-encoded binary content should be identical to BIN file.'); + }, overrides: <Type, Generator>{ + FileSystem: () => testFileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + }); + testUsingContext('Failed directory delete shows message', () async { final FileExceptionHandler handler = FileExceptionHandler(); final FileSystem fileSystem = MemoryFileSystem.test(opHandle: handler.opHandle); From 5c6b031c109aeb51f75d114639210e2daf541a67 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:17:25 -0700 Subject: [PATCH 1341/1547] Retry Linux web tests 1 time on roll presubmit (#135073) Reland of https://github.com/flutter/flutter/pull/134552 --- .ci.yaml | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 5b9542aba87b9..49334e1c88e9e 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1148,6 +1148,8 @@ targets: subshard: "1_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1168,6 +1170,8 @@ targets: subshard: "2_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1188,6 +1192,8 @@ targets: subshard: "3_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1208,6 +1214,8 @@ targets: subshard: "4_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1228,6 +1236,8 @@ targets: subshard: "5_5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1248,6 +1258,8 @@ targets: subshard: "0" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1268,6 +1280,8 @@ targets: subshard: "1" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1288,6 +1302,8 @@ targets: subshard: "2" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1308,6 +1324,8 @@ targets: subshard: "3" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1328,6 +1346,8 @@ targets: subshard: "4" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1348,6 +1368,8 @@ targets: subshard: "5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1368,6 +1390,8 @@ targets: subshard: "6" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1388,6 +1412,8 @@ targets: subshard: "7_last" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1408,6 +1434,8 @@ targets: subshard: "0" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1428,6 +1456,8 @@ targets: subshard: "1" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1448,6 +1478,8 @@ targets: subshard: "2" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1468,6 +1500,8 @@ targets: subshard: "3" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1488,6 +1522,8 @@ targets: subshard: "4" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1508,6 +1544,8 @@ targets: subshard: "5" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1528,6 +1566,8 @@ targets: subshard: "6" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1548,6 +1588,8 @@ targets: subshard: "7_last" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/** @@ -1569,6 +1611,8 @@ targets: subshard: "1_1" tags: > ["framework", "hostonly", "shard", "linux"] + # Retry for flakes caused by https://github.com/flutter/flutter/issues/132654 + presubmit_max_attempts: "2" runIf: - dev/** - packages/flutter_tools/** From 13e34bd3c2af770d58eafc9cba9f29e2a871ff41 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 19 Sep 2023 20:03:19 -0400 Subject: [PATCH 1342/1547] Manual roll Flutter Engine from 10c480310926 to a7af55c56aa6 (4 revisions) (#135071) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/10c480310926...a7af55c56aa6 2023-09-19 goderbauer@google.com Enable strict-inference (flutter/engine#46062) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from 559a964f9f1b to fe3568162721 (5 revisions) (flutter/engine#46069) 2023-09-19 58529443+srujzs@users.noreply.github.com Implement JSObject instead of extending (flutter/engine#46070) 2023-09-19 matanlurey@users.noreply.github.com `FlutterMouse.*` -> `kFlutterMouse.*`, so we can lint header files. (flutter/engine#46056) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index c73600fdfd049..4441743edb1a2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -10c480310926d7e04a77ba8a04d321f9d225a545 +a7af55c56aa63cc37da4ca334737cc992e041302 From 52ef9d8827e8a53e880b83d59ea030b58a6b47e7 Mon Sep 17 00:00:00 2001 From: Xilai Zhang <xilaizhang@google.com> Date: Tue, 19 Sep 2023 17:06:45 -0700 Subject: [PATCH 1343/1547] [flutter roll] Revert "Native assets support for Linux" (#135069) Reverts flutter/flutter#134031 context: b/301051367 Looked at the error message from the broken TAP target, but seems like the failure might be non trivial to resolve. Would it be okay if we revert this for now while it is being triaged? --- .ci.yaml | 24 +- .../build_system/targets/native_assets.dart | 27 +- .../lib/src/linux/build_linux.dart | 2 - .../lib/src/linux/native_assets.dart | 238 ----------- .../cmake_native_assets_migration.dart | 65 --- .../flutter_tools/lib/src/native_assets.dart | 27 +- .../lib/src/test/test_compiler.dart | 11 +- .../app_shared/linux.tmpl/CMakeLists.txt.tmpl | 6 - .../linux/native_assets_test.dart | 374 ------------------ .../cmake_project_migration_test.dart | 127 ------ .../integration.shard/native_assets_test.dart | 30 +- .../transition_test_utils.dart | 9 +- 12 files changed, 21 insertions(+), 919 deletions(-) delete mode 100644 packages/flutter_tools/lib/src/linux/native_assets.dart delete mode 100644 packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart delete mode 100644 packages/flutter_tools/test/general.shard/linux/native_assets_test.dart diff --git a/.ci.yaml b/.ci.yaml index 49334e1c88e9e..83d6386af773d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -951,10 +951,8 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "cmake", "version": "build_id:8787856497187628321"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, - {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "version:11"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: tool_integration_tests subshard: "1_4" @@ -977,10 +975,8 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "cmake", "version": "build_id:8787856497187628321"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, - {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "version:11"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: tool_integration_tests subshard: "2_4" @@ -1003,10 +999,8 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "cmake", "version": "build_id:8787856497187628321"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, - {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "version:11"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: tool_integration_tests subshard: "3_4" @@ -1029,10 +1023,8 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "cmake", "version": "build_id:8787856497187628321"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, - {"dependency": "ninja", "version": "version:1.9.0"}, - {"dependency": "open_jdk", "version": "version:11"} + {"dependency": "open_jdk", "version": "version:11"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} ] shard: tool_integration_tests subshard: "4_4" diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index c92c1d6949581..6e73882927f99 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -12,7 +12,6 @@ import '../../base/platform.dart'; import '../../build_info.dart'; import '../../dart/package_map.dart'; import '../../ios/native_assets.dart'; -import '../../linux/native_assets.dart'; import '../../macos/native_assets.dart'; import '../../macos/xcode.dart'; import '../../native_assets.dart'; @@ -119,21 +118,6 @@ class NativeAssets extends Target { fileSystem: fileSystem, buildRunner: buildRunner, ); - case TargetPlatform.linux_arm64: - case TargetPlatform.linux_x64: - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); - (_, dependencies) = await buildNativeAssetsLinux( - targetPlatform: targetPlatform, - buildMode: buildMode, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); case TargetPlatform.tester: if (const LocalPlatform().isMacOS) { (_, dependencies) = await buildNativeAssetsMacOS( @@ -145,15 +129,6 @@ class NativeAssets extends Target { buildRunner: buildRunner, flutterTester: true, ); - } else if (const LocalPlatform().isLinux) { - (_, dependencies) = await buildNativeAssetsLinux( - buildMode: BuildMode.debug, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - flutterTester: true, - ); } else { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 // Write the file we claim to have in the [outputs]. @@ -167,6 +142,8 @@ class NativeAssets extends Target { case TargetPlatform.android: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: + case TargetPlatform.linux_arm64: + case TargetPlatform.linux_x64: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 1bcf07361fd65..410416aa63062 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -17,7 +17,6 @@ import '../convert.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; -import '../migrations/cmake_native_assets_migration.dart'; // Matches the following error and warning patterns: // - <file path>:<line>:<column>: (fatal) error: <error...> @@ -46,7 +45,6 @@ Future<void> buildLinux( final List<ProjectMigrator> migrators = <ProjectMigrator>[ CmakeCustomCommandMigration(linuxProject, logger), - CmakeNativeAssetsMigration(linuxProject, 'linux', logger), ]; final ProjectMigration migration = ProjectMigration(migrators); diff --git a/packages/flutter_tools/lib/src/linux/native_assets.dart b/packages/flutter_tools/lib/src/linux/native_assets.dart deleted file mode 100644 index a9dcb334d870f..0000000000000 --- a/packages/flutter_tools/lib/src/linux/native_assets.dart +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult; -import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; -import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; - -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../base/io.dart'; -import '../build_info.dart'; -import '../globals.dart' as globals; -import '../native_assets.dart'; - -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file. -Future<Uri?> dryRunNativeAssetsLinux({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - bool flutterTester = false, - required FileSystem fileSystem, -}) async { - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { - return null; - } - - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.linux); - final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsLinuxInternal( - fileSystem, - projectUri, - flutterTester, - buildRunner, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - nativeAssetPaths, - buildUri_, - fileSystem, - ); - return nativeAssetsUri; -} - -Future<Iterable<Asset>> dryRunNativeAssetsLinuxInternal( - FileSystem fileSystem, - Uri projectUri, - bool flutterTester, - NativeAssetsBuildRunner buildRunner, -) async { - const OS targetOs = OS.linux; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); - - globals.logger.printTrace('Dry running native assets for $targetOs.'); - final List<Asset> nativeAssets = (await buildRunner.dryRun( - linkModePreference: LinkModePreference.dynamic, - targetOs: targetOs, - workingDirectory: projectUri, - includeParentEnvironment: true, - )) - .assets; - ensureNoLinkModeStatic(nativeAssets); - globals.logger.printTrace('Dry running native assets for $targetOs done.'); - final Uri? absolutePath = flutterTester ? buildUri_ : null; - final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); - final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values; - return nativeAssetPaths; -} - -/// Builds native assets. -/// -/// If [targetPlatform] is omitted, the current target architecture is used. -/// -/// If [flutterTester] is true, absolute paths are emitted in the native -/// assets mapping. This can be used for JIT mode without sandbox on the host. -/// This is used in `flutter test` and `flutter run -d flutter-tester`. -Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsLinux({ - required NativeAssetsBuildRunner buildRunner, - TargetPlatform? targetPlatform, - required Uri projectUri, - required BuildMode buildMode, - bool flutterTester = false, - Uri? yamlParentDirectory, - required FileSystem fileSystem, -}) async { - const OS targetOs = OS.linux; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); - final Directory buildDir = fileSystem.directory(buildUri_); - if (!await buildDir.exists()) { - // CMake requires the folder to exist to do copying. - await buildDir.create(recursive: true); - } - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { - final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); - return (nativeAssetsYaml, <Uri>[]); - } - - final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current; - final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); - - globals.logger.printTrace('Building native assets for $target $buildModeCli.'); - final BuildResult result = await buildRunner.build( - linkModePreference: LinkModePreference.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - ); - final List<Asset> nativeAssets = result.assets; - final Set<Uri> dependencies = result.dependencies.toSet(); - ensureNoLinkModeStatic(nativeAssets); - globals.logger.printTrace('Building native assets for $target done.'); - final Uri? absolutePath = flutterTester ? buildUri_ : null; - final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); - await _copyNativeAssetsLinux( - buildUri_, - assetTargetLocations, - buildMode, - fileSystem, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - assetTargetLocations.values, - yamlParentDirectory ?? buildUri_, - fileSystem, - ); - return (nativeAssetsUri, dependencies.toList()); -} - -Map<Asset, Asset> _assetTargetLocations( - List<Asset> nativeAssets, - Uri? absolutePath, -) => - <Asset, Asset>{ - for (final Asset asset in nativeAssets) asset: _targetLocationLinux(asset, absolutePath), - }; - -Asset _targetLocationLinux(Asset asset, Uri? absolutePath) { - final AssetPath path = asset.path; - switch (path) { - case AssetSystemPath _: - case AssetInExecutable _: - case AssetInProcess _: - return asset; - case AssetAbsolutePath _: - final String fileName = path.uri.pathSegments.last; - Uri uri; - if (absolutePath != null) { - // Flutter tester needs full host paths. - uri = absolutePath.resolve(fileName); - } else { - // Flutter Desktop needs "absolute" paths inside the app. - // "relative" in the context of native assets would be relative to the - // kernel or aot snapshot. - uri = Uri(path: fileName); - } - return asset.copyWith(path: AssetAbsolutePath(uri)); - } - throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); -} - -/// Extract the [Target] from a [TargetPlatform]. -Target _getNativeTarget(TargetPlatform targetPlatform) { - switch (targetPlatform) { - case TargetPlatform.linux_x64: - return Target.linuxX64; - case TargetPlatform.linux_arm64: - return Target.linuxArm64; - case TargetPlatform.android: - case TargetPlatform.ios: - case TargetPlatform.darwin: - case TargetPlatform.windows_x64: - case TargetPlatform.fuchsia_arm64: - case TargetPlatform.fuchsia_x64: - case TargetPlatform.tester: - case TargetPlatform.web_javascript: - case TargetPlatform.android_arm: - case TargetPlatform.android_arm64: - case TargetPlatform.android_x64: - case TargetPlatform.android_x86: - throw Exception('Unknown targetPlatform: $targetPlatform.'); - } -} - -Future<void> _copyNativeAssetsLinux( - Uri buildUri, - Map<Asset, Asset> assetTargetLocations, - BuildMode buildMode, - FileSystem fileSystem, -) async { - if (assetTargetLocations.isNotEmpty) { - globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); - final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); - if (!buildDir.existsSync()) { - buildDir.createSync(recursive: true); - } - for (final MapEntry<Asset, Asset> assetMapping in assetTargetLocations.entries) { - final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri; - final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri; - final Uri targetUri = buildUri.resolveUri(target); - final String targetFullPath = targetUri.toFilePath(); - await fileSystem.file(source).copy(targetFullPath); - } - globals.logger.printTrace('Copying native assets done.'); - } -} - -/// Flutter expects `clang++` to be on the path on Linux hosts. -/// -/// Search for the accompanying `clang`, `ar`, and `ld`. -Future<CCompilerConfig> cCompilerConfigLinux() async { - const String kClangPlusPlusBinary = 'clang++'; - const String kClangBinary = 'clang'; - const String kArBinary = 'llvm-ar'; - const String kLdBinary = 'ld.lld'; - - final ProcessResult whichResult = await globals.processManager.run(<String>['which', kClangPlusPlusBinary]); - if (whichResult.exitCode != 0) { - throwToolExit('Failed to find $kClangPlusPlusBinary on PATH.'); - } - File clangPpFile = globals.fs.file((whichResult.stdout as String).trim()); - clangPpFile = globals.fs.file(await clangPpFile.resolveSymbolicLinks()); - - final Directory clangDir = clangPpFile.parent; - final Map<String, Uri> binaryPaths = <String, Uri>{}; - for (final String binary in <String>[kClangBinary, kArBinary, kLdBinary]) { - final File binaryFile = clangDir.childFile(binary); - if (!await binaryFile.exists()) { - throwToolExit("Failed to find $binary relative to $clangPpFile: $binaryFile doesn't exist."); - } - binaryPaths[binary] = binaryFile.uri; - } - return CCompilerConfig( - ar: binaryPaths[kArBinary], - cc: binaryPaths[kClangBinary], - ld: binaryPaths[kLdBinary], - ); -} diff --git a/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart deleted file mode 100644 index fe9ba86a035ac..0000000000000 --- a/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import '../base/file_system.dart'; -import '../base/project_migrator.dart'; -import '../cmake_project.dart'; - -/// Adds the snippet to the CMake file that copies the native assets. -/// -/// ```cmake -/// # Copy the native assets provided by the build.dart from all packages. -/// set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -/// install(DIRECTORY "${NATIVE_ASSETS_DIR}" -/// DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" -/// COMPONENT Runtime) -/// ``` -class CmakeNativeAssetsMigration extends ProjectMigrator { - CmakeNativeAssetsMigration(CmakeBasedProject project, this.os, super.logger) - : _cmakeFile = project.managedCmakeFile; - - final File _cmakeFile; - final String os; - - @override - void migrate() { - if (!_cmakeFile.existsSync()) { - logger.printTrace('CMake project not found, skipping install() NATIVE_ASSETS_DIR migration.'); - return; - } - - final String originalProjectContents = _cmakeFile.readAsStringSync(); - - if (originalProjectContents.contains('set(NATIVE_ASSETS_DIR')) { - // Command is already present. - return; - } - - final String copyNativeAssetsCommand = ''' - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "\${PROJECT_BUILD_DIR}native_assets/$os/") -install(DIRECTORY "\${NATIVE_ASSETS_DIR}" - DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -'''; - - // Insert the new command after the bundled libraries loop. - const String bundleLibrariesCommandEnd = r''' -endforeach(bundled_library) -'''; - - String newProjectContents = originalProjectContents; - - newProjectContents = originalProjectContents.replaceFirst( - bundleLibrariesCommandEnd, - '$bundleLibrariesCommandEnd$copyNativeAssetsCommand', - ); - - if (originalProjectContents != newProjectContents) { - logger.printStatus('CMake missing install() NATIVE_ASSETS_DIR command, updating.'); - _cmakeFile.writeAsStringSync(newProjectContents); - } - } -} diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index b269fd876ed6a..3253d29191581 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -19,7 +19,6 @@ import 'cache.dart'; import 'features.dart'; import 'globals.dart' as globals; import 'ios/native_assets.dart'; -import 'linux/native_assets.dart'; import 'macos/native_assets.dart'; import 'macos/native_assets_host.dart'; import 'resident_runner.dart'; @@ -169,9 +168,6 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { if (globals.platform.isMacOS || globals.platform.isIOS) { return cCompilerConfigMacOS(); } - if (globals.platform.isLinux) { - return cCompilerConfigLinux(); - } throwToolExit( 'Native assets feature not yet implemented for Linux, Windows and Android.', ); @@ -337,13 +333,6 @@ Future<Uri?> dryRunNativeAssets({ fileSystem: fileSystem, buildRunner: buildRunner, ); - } else if (const LocalPlatform().isLinux) { - nativeAssetsYaml = await dryRunNativeAssetsLinux( - projectUri: projectUri, - flutterTester: true, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); } else { await ensureNoNativeAssetsOrOsIsSupported( projectUri, @@ -353,13 +342,6 @@ Future<Uri?> dryRunNativeAssets({ ); nativeAssetsYaml = null; } - case build_info.TargetPlatform.linux_arm64: - case build_info.TargetPlatform.linux_x64: - nativeAssetsYaml = await dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); case build_info.TargetPlatform.android_arm: case build_info.TargetPlatform.android_arm64: case build_info.TargetPlatform.android_x64: @@ -367,6 +349,8 @@ Future<Uri?> dryRunNativeAssets({ case build_info.TargetPlatform.android: case build_info.TargetPlatform.fuchsia_arm64: case build_info.TargetPlatform.fuchsia_x64: + case build_info.TargetPlatform.linux_arm64: + case build_info.TargetPlatform.linux_x64: case build_info.TargetPlatform.web_javascript: case build_info.TargetPlatform.windows_x64: await ensureNoNativeAssetsOrOsIsSupported( @@ -398,12 +382,7 @@ Future<Uri?> dryRunNativeAssetsMultipeOSes({ if (targetPlatforms.contains(build_info.TargetPlatform.darwin) || (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS)) ...await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, false, buildRunner), - if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) || - targetPlatforms.contains(build_info.TargetPlatform.linux_x64) || - (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.linux)) - ...await dryRunNativeAssetsLinuxInternal(fileSystem, projectUri, false, buildRunner), - if (targetPlatforms.contains(build_info.TargetPlatform.ios)) - ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) + if (targetPlatforms.contains(build_info.TargetPlatform.ios)) ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) ]; final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); return nativeAssetsUri; diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 347f3623ff593..8f50eb9268b05 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -16,7 +16,6 @@ import '../bundle.dart'; import '../compile.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; -import '../linux/native_assets.dart'; import '../macos/native_assets.dart'; import '../native_assets.dart'; import '../project.dart'; @@ -182,15 +181,7 @@ class TestCompiler { flutterTester: true, fileSystem: globals.fs, buildRunner: buildRunner, - ); - } else if (globals.platform.isLinux) { - (nativeAssetsYaml, _) = await buildNativeAssetsLinux( - buildMode: BuildMode.debug, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); + ); } else { await ensureNoNativeAssetsOrOsIsSupported( projectUri, diff --git a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl index 580180401d132..a4fc907bec376 100644 --- a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl @@ -127,12 +127,6 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart deleted file mode 100644 index 34d2fc552f820..0000000000000 --- a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:file/file.dart'; -import 'package:file/memory.dart'; -import 'package:file_testing/file_testing.dart'; -import 'package:flutter_tools/src/artifacts.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/base/platform.dart'; -import 'package:flutter_tools/src/build_info.dart'; -import 'package:flutter_tools/src/build_system/build_system.dart'; -import 'package:flutter_tools/src/dart/package_map.dart'; -import 'package:flutter_tools/src/features.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/linux/native_assets.dart'; -import 'package:flutter_tools/src/native_assets.dart'; -import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; -import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; -import 'package:package_config/package_config_types.dart'; - -import '../../src/common.dart'; -import '../../src/context.dart'; -import '../../src/fakes.dart'; -import '../fake_native_assets_build_runner.dart'; - -void main() { - late FakeProcessManager processManager; - late Environment environment; - late Artifacts artifacts; - late FileSystem fileSystem; - late BufferLogger logger; - late Uri projectUri; - - setUp(() { - processManager = FakeProcessManager.empty(); - logger = BufferLogger.test(); - artifacts = Artifacts.test(); - fileSystem = MemoryFileSystem.test(); - environment = Environment.test( - fileSystem.currentDirectory, - inputs: <String, String>{}, - artifacts: artifacts, - processManager: processManager, - fileSystem: fileSystem, - logger: logger, - ); - environment.buildDir.createSync(recursive: true); - projectUri = environment.projectDir.uri; - }); - - testUsingContext('dry run with no package config', overrides: <Type, Generator>{ - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - expect( - await dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - hasPackageConfigResult: false, - ), - ), - null, - ); - expect( - (globals.logger as BufferLogger).traceText, - contains('No package config found. Skipping native assets compilation.'), - ); - }); - - testUsingContext('build with no package config', overrides: <Type, Generator>{ - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await buildNativeAssetsLinux( - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - hasPackageConfigResult: false, - ), - ); - expect( - (globals.logger as BufferLogger).traceText, - contains('No package config found. Skipping native assets compilation.'), - ); - }); - - testUsingContext('dry run for multiple OSes with no package config', overrides: <Type, Generator>{ - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await dryRunNativeAssetsMultipeOSes( - projectUri: projectUri, - fileSystem: fileSystem, - targetPlatforms: <TargetPlatform>[ - TargetPlatform.darwin, - TargetPlatform.ios, - ], - buildRunner: FakeNativeAssetsBuildRunner( - hasPackageConfigResult: false, - ), - ); - expect( - (globals.logger as BufferLogger).traceText, - contains('No package config found. Skipping native assets compilation.'), - ); - }); - - testUsingContext('dry run with assets but not enabled', overrides: <Type, Generator>{ - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: <Package>[ - Package('bar', projectUri), - ], - ), - ), - throwsToolExit( - message: 'Package(s) bar require the native assets feature to be enabled. ' - 'Enable using `flutter config --enable-native-assets`.', - ), - ); - }); - - testUsingContext('dry run with assets', overrides: <Type, Generator>{ - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - final Uri? nativeAssetsYaml = await dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: <Package>[ - Package('bar', projectUri), - ], - dryRunResult: FakeNativeAssetsBuilderResult( - assets: <Asset>[ - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.linuxX64, - path: AssetAbsolutePath(Uri.file('libbar.so')), - ), - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.linuxArm64, - path: AssetAbsolutePath(Uri.file('libbar.so')), - ), - ], - ), - ), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/linux/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - contains('package:bar/bar.dart'), - ); - }); - - testUsingContext('build with assets but not enabled', overrides: <Type, Generator>{ - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => buildNativeAssetsLinux( - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: <Package>[ - Package('bar', projectUri), - ], - ), - ), - throwsToolExit( - message: 'Package(s) bar require the native assets feature to be enabled. ' - 'Enable using `flutter config --enable-native-assets`.', - ), - ); - }); - - testUsingContext('build no assets', overrides: <Type, Generator>{ - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: <Package>[ - Package('bar', projectUri), - ], - ), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/linux/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - isNot(contains('package:bar/bar.dart')), - ); - expect( - environment.projectDir - .childDirectory('build') - .childDirectory('native_assets') - .childDirectory('linux'), - exists, - ); - }); - - for (final bool flutterTester in <bool>[false, true]) { - String testName = ''; - if (flutterTester) { - testName += ' flutter tester'; - } - testUsingContext('build with assets$testName', overrides: <Type, Generator>{ - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - if (const LocalPlatform().isWindows) { - return; // Backslashes in commands, but we will never run these commands on Windows. - } - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - final File dylibAfterCompiling = fileSystem.file('libbar.so'); - // The mock doesn't create the file, so create it here. - await dylibAfterCompiling.create(); - final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - flutterTester: flutterTester, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: <Package>[ - Package('bar', projectUri), - ], - buildResult: FakeNativeAssetsBuilderResult( - assets: <Asset>[ - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.linuxX64, - path: AssetAbsolutePath(dylibAfterCompiling.uri), - ), - ], - ), - ), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/linux/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - stringContainsInOrder(<String>[ - 'package:bar/bar.dart', - if (flutterTester) - // Tests run on host system, so the have the full path on the system. - '- ${projectUri.resolve('/build/native_assets/linux/libbar.so').toFilePath()}' - else - // Apps are a bundle with the dylibs on their dlopen path. - '- libbar.so', - ]), - ); - }); - } - - testUsingContext('static libs not supported', overrides: <Type, Generator>{ - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: <Package>[ - Package('bar', projectUri), - ], - dryRunResult: FakeNativeAssetsBuilderResult( - assets: <Asset>[ - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.static, - target: native_assets_cli.Target.macOSArm64, - path: AssetAbsolutePath(Uri.file('bar.a')), - ), - Asset( - id: 'package:bar/bar.dart', - linkMode: LinkMode.static, - target: native_assets_cli.Target.macOSX64, - path: AssetAbsolutePath(Uri.file('bar.a')), - ), - ], - ), - ), - ), - throwsToolExit( - message: 'Native asset(s) package:bar/bar.dart have their link mode set to ' - 'static, but this is not yet supported. ' - 'For more info see https://github.com/dart-lang/sdk/issues/49418.', - ), - ); - }); - - // This logic is mocked in the other tests to avoid having test order - // randomization causing issues with what processes are invoked. - // Exercise the parsing of the process output in this separate test. - testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', overrides: <Type, Generator>{ - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.list( - <FakeCommand>[ - const FakeCommand( - command: <Pattern>['which', 'clang++'], - stdout: ''' -/some/path/to/clang++ -''', // Newline at the end of the string. - ) - ], - ), - FileSystem: () => fileSystem, - }, () async { - if (!const LocalPlatform().isLinux) { - // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 - return; - } - - await fileSystem.directory('/some/path/to/').create(recursive: true); - await fileSystem.file('/some/path/to/clang++').create(); - await fileSystem.file('/some/path/to/clang').create(); - await fileSystem.file('/some/path/to/llvm-ar').create(); - await fileSystem.file('/some/path/to/ld.lld').create(); - - final File packagesFile = fileSystem - .directory(projectUri) - .childDirectory('.dart_tool') - .childFile('package_config.json'); - await packagesFile.parent.create(); - await packagesFile.create(); - final PackageConfig packageConfig = await loadPackageConfigWithLogging( - packagesFile, - logger: environment.logger, - ); - final NativeAssetsBuildRunner runner = - NativeAssetsBuildRunnerImpl(projectUri, packageConfig, fileSystem, logger); - final CCompilerConfig result = await runner.cCompilerConfig; - expect(result.cc, Uri.file('/some/path/to/clang')); - }); -} diff --git a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart index 8689febb15ae8..36ee8d7824a3a 100644 --- a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart @@ -8,7 +8,6 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cmake_project.dart'; import 'package:flutter_tools/src/migrations/cmake_custom_command_migration.dart'; -import 'package:flutter_tools/src/migrations/cmake_native_assets_migration.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; @@ -156,132 +155,6 @@ add_custom_command( expect(testLogger.statusText, contains('add_custom_command() missing VERBATIM or FLUTTER_TARGET_PLATFORM, updating.')); }); }); - - group('migrate add install() NATIVE_ASSETS_DIR command', () { - late MemoryFileSystem memoryFileSystem; - late BufferLogger testLogger; - late FakeCmakeProject mockCmakeProject; - late File managedCmakeFile; - - setUp(() { - memoryFileSystem = MemoryFileSystem.test(); - managedCmakeFile = memoryFileSystem.file('CMakeLists.txtx'); - - testLogger = BufferLogger( - terminal: Terminal.test(), - outputPreferences: OutputPreferences.test(), - ); - - mockCmakeProject = FakeCmakeProject(managedCmakeFile); - }); - - testWithoutContext('skipped if files are missing', () { - final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( - mockCmakeProject, - 'linux', - testLogger, - ); - cmakeProjectMigration.migrate(); - expect(managedCmakeFile.existsSync(), isFalse); - - expect(testLogger.traceText, contains('CMake project not found, skipping install() NATIVE_ASSETS_DIR migration.')); - expect(testLogger.statusText, isEmpty); - }); - - testWithoutContext('skipped if nothing to migrate', () { - const String contents = 'Nothing to migrate'; - managedCmakeFile.writeAsStringSync(contents); - final DateTime projectLastModified = managedCmakeFile.lastModifiedSync(); - - final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( - mockCmakeProject, - 'linux', - testLogger, - ); - cmakeProjectMigration.migrate(); - - expect(managedCmakeFile.lastModifiedSync(), projectLastModified); - expect(managedCmakeFile.readAsStringSync(), contents); - - expect(testLogger.statusText, isEmpty); - }); - - testWithoutContext('skipped if already migrated', () { - const String contents = r''' -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -'''; - managedCmakeFile.writeAsStringSync(contents); - final DateTime projectLastModified = managedCmakeFile.lastModifiedSync(); - - final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( - mockCmakeProject, - 'linux', - testLogger, - ); - cmakeProjectMigration.migrate(); - - expect(managedCmakeFile.lastModifiedSync(), projectLastModified); - expect(managedCmakeFile.readAsStringSync(), contents); - - expect(testLogger.statusText, isEmpty); - }); - - // TODO(dacoharkes): Add test for Windows when adding Windows support. https://github.com/flutter/flutter/issues/129757 - testWithoutContext('is migrated to copy native assets', () { - managedCmakeFile.writeAsStringSync(r''' -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) -'''); - - final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( - mockCmakeProject, - 'linux', - testLogger, - ); - cmakeProjectMigration.migrate(); - - expect(managedCmakeFile.readAsStringSync(), r''' -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) -'''); - - expect(testLogger.statusText, contains('CMake missing install() NATIVE_ASSETS_DIR command, updating.')); - }); - }); }); } diff --git a/packages/flutter_tools/test/integration.shard/native_assets_test.dart b/packages/flutter_tools/test/integration.shard/native_assets_test.dart index c6824fb35774e..e539e74a27a75 100644 --- a/packages/flutter_tools/test/integration.shard/native_assets_test.dart +++ b/packages/flutter_tools/test/integration.shard/native_assets_test.dart @@ -17,7 +17,6 @@ import 'dart:io'; import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; -import 'package:native_assets_cli/native_assets_cli.dart'; import '../src/common.dart'; import 'test_utils.dart' show fileSystem, platform; @@ -57,8 +56,10 @@ const String packageName = 'package_with_native_assets'; const String exampleAppName = '${packageName}_example'; +const String dylibName = 'lib$packageName.dylib'; + void main() { - if (!platform.isMacOS && !platform.isLinux) { + if (!platform.isMacOS) { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 return; } @@ -147,9 +148,6 @@ void main() { if (device == 'macos') { expectDylibIsBundledMacOS(exampleDirectory, buildMode); } - if (device == 'linux') { - expectDylibIsBundledLinux(exampleDirectory, buildMode); - } if (device == hostOs) { expectCCompilerIsConfigured(exampleDirectory); } @@ -203,8 +201,6 @@ void main() { expectDylibIsBundledMacOS(exampleDirectory, buildMode); } else if (buildSubcommand == 'ios') { expectDylibIsBundledIos(exampleDirectory, buildMode); - } else if (buildSubcommand == 'linux') { - expectDylibIsBundledLinux(exampleDirectory, buildMode); } expectCCompilerIsConfigured(exampleDirectory); }); @@ -282,7 +278,7 @@ void expectDylibIsBundledMacOS(Directory appDirectory, String buildMode) { expect(appBundle, exists); final Directory dylibsFolder = appBundle.childDirectory('Contents/Frameworks'); expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(OS.macOS.dylibFileName(packageName)); + final File dylib = dylibsFolder.childFile(dylibName); expect(dylib, exists); } @@ -291,21 +287,7 @@ void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { expect(appBundle, exists); final Directory dylibsFolder = appBundle.childDirectory('Frameworks'); expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(OS.iOS.dylibFileName(packageName)); - expect(dylib, exists); -} - -/// Checks that dylibs are bundled. -/// -/// Sample path: build/linux/x64/release/bundle/lib/libmy_package.so -void expectDylibIsBundledLinux(Directory appDirectory, String buildMode) { - // Linux does not support cross compilation, so always only check current architecture. - final String architecture = Architecture.current.dartPlatform; - final Directory appBundle = appDirectory.childDirectory('build/$hostOs/$architecture/$buildMode/bundle/'); - expect(appBundle, exists); - final Directory dylibsFolder = appBundle.childDirectory('lib/'); - expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(OS.linux.dylibFileName(packageName)); + final File dylib = dylibsFolder.childFile(dylibName); expect(dylib, exists); } @@ -314,7 +296,7 @@ void expectDylibIsBundledLinux(Directory appDirectory, String buildMode) { void expectDylibIsBundledWithFrameworks(Directory appDirectory, String buildMode, String os) { final Directory frameworksFolder = appDirectory.childDirectory('build/$os/framework/${buildMode.upperCaseFirst()}'); expect(frameworksFolder, exists); - final File dylib = frameworksFolder.childFile(OS.macOS.dylibFileName(packageName)); + final File dylib = frameworksFolder.childFile(dylibName); expect(dylib, exists); } diff --git a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart index fa3a7f3b9e5b8..9c34917600395 100644 --- a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart +++ b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart @@ -6,7 +6,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:flutter_tools/src/base/platform.dart'; import 'package:meta/meta.dart'; import 'package:process/process.dart'; @@ -178,15 +177,9 @@ Future<ProcessTestResult> runFlutter( minutes: 10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml. }) async { - const LocalPlatform platform = LocalPlatform(); final Stopwatch clock = Stopwatch()..start(); final Process process = await processManager.start( - <String>[ - // In a container with no X display, use the virtual framebuffer. - if (platform.isLinux && (platform.environment['DISPLAY'] ?? '').isEmpty) '/usr/bin/xvfb-run', - flutterBin, - ...arguments, - ], + <String>[flutterBin, ...arguments], workingDirectory: workingDirectory, ); final List<LogLine> logs = <LogLine>[]; From 14b832aaf6cb29713670b2c17bdc00e508e64496 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Wed, 20 Sep 2023 02:42:40 +0200 Subject: [PATCH 1344/1547] cover more tests with leak tracking (#134837) --- packages/flutter/test/scheduler/ticker_test.dart | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/flutter/test/scheduler/ticker_test.dart b/packages/flutter/test/scheduler/ticker_test.dart index bbe9b7d9df3c3..d4eab13d6fb94 100644 --- a/packages/flutter/test/scheduler/ticker_test.dart +++ b/packages/flutter/test/scheduler/ticker_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { Future<void> setAppLifeCycleState(AppLifecycleState state) async { @@ -15,7 +16,7 @@ void main() { .handlePlatformMessage('flutter/lifecycle', message, (_) {}); } - testWidgets('Ticker mute control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticker mute control test', (WidgetTester tester) async { int tickCount = 0; void handleTick(Duration duration) { tickCount += 1; @@ -97,7 +98,7 @@ void main() { expect(ticker.isActive, isFalse); }); - testWidgets('Ticker control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticker control test', (WidgetTester tester) async { late Ticker ticker; void testFunction() { @@ -110,7 +111,7 @@ void main() { expect(ticker.toString(debugIncludeStack: true), contains('testFunction')); }); - testWidgets('Ticker can be sped up with time dilation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticker can be sped up with time dilation', (WidgetTester tester) async { timeDilation = 0.5; // Move twice as fast. late Duration lastDuration; void handleTick(Duration duration) { @@ -128,7 +129,7 @@ void main() { timeDilation = 1.0; // restore time dilation, or it will affect other tests }); - testWidgets('Ticker can be slowed down with time dilation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticker can be slowed down with time dilation', (WidgetTester tester) async { timeDilation = 2.0; // Move half as fast. late Duration lastDuration; void handleTick(Duration duration) { @@ -146,7 +147,7 @@ void main() { timeDilation = 1.0; // restore time dilation, or it will affect other tests }); - testWidgets('Ticker stops ticking when application is paused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticker stops ticking when application is paused', (WidgetTester tester) async { int tickCount = 0; void handleTick(Duration duration) { tickCount += 1; @@ -169,7 +170,7 @@ void main() { setAppLifeCycleState(AppLifecycleState.resumed); }); - testWidgets('Ticker can be created before application unpauses', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticker can be created before application unpauses', (WidgetTester tester) async { setAppLifeCycleState(AppLifecycleState.paused); int tickCount = 0; From fe9a2c5477f7ce06447a0e241f6d76569e3be94e Mon Sep 17 00:00:00 2001 From: Greg Spencer <gspencergoog@users.noreply.github.com> Date: Tue, 19 Sep 2023 18:37:22 -0700 Subject: [PATCH 1345/1547] Remove 'must not be null' comments from painting and rendering libraries. (#134993) ## Description This removes all of the comments that are of the form "so-and-so (must not be null|can ?not be null|must be non-null)" from the cases where those values are defines as non-nullable values. This PR removes them from the painting and rendering libraries. This was done by hand, since it really didn't lend itself to scripting, so it needs to be more than just spot-checked, I think. I was careful to leave any comment that referred to parameters that were nullable, but I may have missed some. In addition to being no longer relevant after null safety has been made the default, these comments were largely fragile, in that it was easy for them to get out of date, and not be accurate anymore anyhow. This did create a number of constructor comments which basically say "Creates a [Foo].", but I don't really know how to avoid that in a large scale change, since there's not much you can really say in a lot of cases. I think we might consider some leniency for constructors to the "Comment must be meaningful" style guidance (which we de facto have already, since there are a bunch of these). ## Related PRs - https://github.com/flutter/flutter/pull/134984 - https://github.com/flutter/flutter/pull/134991 - https://github.com/flutter/flutter/pull/134992 - https://github.com/flutter/flutter/pull/134994 ## Tests - Documentation only change. --- .../lib/src/painting/_network_image_io.dart | 2 - .../lib/src/painting/_network_image_web.dart | 2 - .../flutter/lib/src/painting/alignment.dart | 4 -- .../painting/beveled_rectangle_border.dart | 2 - .../flutter/lib/src/painting/borders.dart | 10 --- .../flutter/lib/src/painting/box_border.dart | 12 +--- .../lib/src/painting/box_decoration.dart | 2 - .../lib/src/painting/circle_border.dart | 2 - packages/flutter/lib/src/painting/colors.dart | 10 ++- .../painting/continuous_rectangle_border.dart | 2 +- .../lib/src/painting/decoration_image.dart | 12 +--- .../lib/src/painting/flutter_logo.dart | 2 - .../lib/src/painting/fractional_offset.dart | 2 - .../flutter/lib/src/painting/geometry.dart | 2 - .../flutter/lib/src/painting/gradient.dart | 13 ++-- .../flutter/lib/src/painting/image_cache.dart | 5 +- .../lib/src/painting/image_provider.dart | 18 ++--- .../lib/src/painting/image_resolution.dart | 8 +-- .../lib/src/painting/image_stream.dart | 4 -- .../flutter/lib/src/painting/inline_span.dart | 2 - .../lib/src/painting/matrix_utils.dart | 2 - .../lib/src/painting/notched_shapes.dart | 2 - .../painting/rounded_rectangle_border.dart | 2 - .../lib/src/painting/shape_decoration.dart | 5 +- .../lib/src/painting/stadium_border.dart | 2 - .../flutter/lib/src/painting/strut_style.dart | 2 - .../lib/src/painting/text_painter.dart | 6 +- .../flutter/lib/src/painting/text_style.dart | 8 +-- .../lib/src/rendering/animated_size.dart | 2 +- packages/flutter/lib/src/rendering/box.dart | 2 - .../lib/src/rendering/custom_layout.dart | 2 - .../lib/src/rendering/custom_paint.dart | 2 - .../flutter/lib/src/rendering/editable.dart | 22 ++----- packages/flutter/lib/src/rendering/flex.dart | 2 +- packages/flutter/lib/src/rendering/flow.dart | 2 +- packages/flutter/lib/src/rendering/image.dart | 5 +- packages/flutter/lib/src/rendering/layer.dart | 15 +---- .../src/rendering/list_wheel_viewport.dart | 20 +++--- .../flutter/lib/src/rendering/object.dart | 2 - .../flutter/lib/src/rendering/paragraph.dart | 8 +-- .../src/rendering/performance_overlay.dart | 3 - .../lib/src/rendering/platform_view.dart | 8 +-- .../flutter/lib/src/rendering/proxy_box.dart | 65 ++++--------------- .../lib/src/rendering/proxy_sliver.dart | 15 ++--- .../lib/src/rendering/rotated_box.dart | 2 - .../flutter/lib/src/rendering/selection.dart | 6 -- .../lib/src/rendering/shifted_box.dart | 14 +--- .../flutter/lib/src/rendering/sliver.dart | 6 -- .../lib/src/rendering/sliver_fill.dart | 2 - .../rendering/sliver_fixed_extent_list.dart | 4 -- .../lib/src/rendering/sliver_grid.dart | 8 +-- .../lib/src/rendering/sliver_list.dart | 2 - .../rendering/sliver_multi_box_adaptor.dart | 2 - .../lib/src/rendering/sliver_padding.dart | 2 +- packages/flutter/lib/src/rendering/stack.dart | 4 -- packages/flutter/lib/src/rendering/table.dart | 8 --- .../lib/src/rendering/table_border.dart | 3 - .../flutter/lib/src/rendering/viewport.dart | 3 +- packages/flutter/lib/src/rendering/wrap.dart | 2 +- 59 files changed, 79 insertions(+), 309 deletions(-) diff --git a/packages/flutter/lib/src/painting/_network_image_io.dart b/packages/flutter/lib/src/painting/_network_image_io.dart index 5221279c61d16..a1fbb3f6e7a99 100644 --- a/packages/flutter/lib/src/painting/_network_image_io.dart +++ b/packages/flutter/lib/src/painting/_network_image_io.dart @@ -20,8 +20,6 @@ typedef _SimpleDecoderCallback = Future<ui.Codec> Function(ui.ImmutableBuffer bu @immutable class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage { /// Creates an object that fetches the image at the given URL. - /// - /// The arguments [url] and [scale] must not be null. const NetworkImage(this.url, { this.scale = 1.0, this.headers }); @override diff --git a/packages/flutter/lib/src/painting/_network_image_web.dart b/packages/flutter/lib/src/painting/_network_image_web.dart index 52010c140c93b..c3219046eb267 100644 --- a/packages/flutter/lib/src/painting/_network_image_web.dart +++ b/packages/flutter/lib/src/painting/_network_image_web.dart @@ -40,8 +40,6 @@ class NetworkImage extends image_provider.ImageProvider<image_provider.NetworkImage> implements image_provider.NetworkImage { /// Creates an object that fetches the image at the given URL. - /// - /// The arguments [url] and [scale] must not be null. const NetworkImage(this.url, {this.scale = 1.0, this.headers}); @override diff --git a/packages/flutter/lib/src/painting/alignment.dart b/packages/flutter/lib/src/painting/alignment.dart index b323e9b1acef0..7509321d75b6f 100644 --- a/packages/flutter/lib/src/painting/alignment.dart +++ b/packages/flutter/lib/src/painting/alignment.dart @@ -185,8 +185,6 @@ abstract class AlignmentGeometry { /// whether the horizontal direction depends on the [TextDirection]. class Alignment extends AlignmentGeometry { /// Creates an alignment. - /// - /// The [x] and [y] arguments must not be null. const Alignment(this.x, this.y); /// The distance fraction in the horizontal direction. @@ -401,8 +399,6 @@ class Alignment extends AlignmentGeometry { /// whose horizontal component does not depend on the text direction). class AlignmentDirectional extends AlignmentGeometry { /// Creates a directional alignment. - /// - /// The [start] and [y] arguments must not be null. const AlignmentDirectional(this.start, this.y); /// The distance fraction in the horizontal direction. diff --git a/packages/flutter/lib/src/painting/beveled_rectangle_border.dart b/packages/flutter/lib/src/painting/beveled_rectangle_border.dart index 0f5e4571e804b..3c900e808dd27 100644 --- a/packages/flutter/lib/src/painting/beveled_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/beveled_rectangle_border.dart @@ -20,8 +20,6 @@ import 'borders.dart'; class BeveledRectangleBorder extends OutlinedBorder { /// Creates a border like a [RoundedRectangleBorder] except that the corners /// are joined by straight lines instead of arcs. - /// - /// The arguments must not be null. const BeveledRectangleBorder({ super.side, this.borderRadius = BorderRadius.zero, diff --git a/packages/flutter/lib/src/painting/borders.dart b/packages/flutter/lib/src/painting/borders.dart index 82282a6d8800c..63e7f3bf83748 100644 --- a/packages/flutter/lib/src/painting/borders.dart +++ b/packages/flutter/lib/src/painting/borders.dart @@ -77,8 +77,6 @@ class BorderSide with Diagnosticable { /// If one of the sides is zero-width with [BorderStyle.none], then the other /// side is return as-is. If both of the sides are zero-width with /// [BorderStyle.none], then [BorderSide.none] is returned. - /// - /// The arguments must not be null. static BorderSide merge(BorderSide a, BorderSide b) { assert(canMerge(a, b)); final bool aIsNone = a.style == BorderStyle.none && a.width == 0.0; @@ -243,8 +241,6 @@ class BorderSide with Diagnosticable { /// /// Two sides can be merged if one or both are zero-width with /// [BorderStyle.none], or if they both have the same color and style. - /// - /// The arguments must not be null. static bool canMerge(BorderSide a, BorderSide b) { if ((a.style == BorderStyle.none && a.width == 0.0) || (b.style == BorderStyle.none && b.width == 0.0)) { @@ -256,8 +252,6 @@ class BorderSide with Diagnosticable { /// Linearly interpolate between two border sides. /// - /// The arguments must not be null. - /// /// {@macro dart.ui.shadow.lerp} static BorderSide lerp(BorderSide a, BorderSide b, double t) { if (identical(a, b)) { @@ -665,8 +659,6 @@ abstract class ShapeBorder { abstract class OutlinedBorder extends ShapeBorder { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. - /// - /// The value of [side] must not be null. const OutlinedBorder({ this.side = BorderSide.none }); @override @@ -884,8 +876,6 @@ class _CompoundBorder extends ShapeBorder { /// borders (where all the borders have the same configuration); to render a /// uniform border, consider using [Canvas.drawRect] directly. /// -/// The arguments must not be null. -/// /// See also: /// /// * [paintImage], which paints an image in a rectangle on a canvas. diff --git a/packages/flutter/lib/src/painting/box_border.dart b/packages/flutter/lib/src/painting/box_border.dart index 633be6a114017..7d2e5bab0c34d 100644 --- a/packages/flutter/lib/src/painting/box_border.dart +++ b/packages/flutter/lib/src/painting/box_border.dart @@ -387,8 +387,6 @@ class Border extends BoxBorder { /// Creates a border. /// /// All the sides of the border default to [BorderSide.none]. - /// - /// The arguments must not be null. const Border({ this.top = BorderSide.none, this.right = BorderSide.none, @@ -397,8 +395,6 @@ class Border extends BoxBorder { }); /// Creates a border whose sides are all the same. - /// - /// The `side` argument must not be null. const Border.fromBorderSide(BorderSide side) : top = side, right = side, @@ -410,7 +406,7 @@ class Border extends BoxBorder { /// The `vertical` argument applies to the [left] and [right] sides, and the /// `horizontal` argument applies to the [top] and [bottom] sides. /// - /// All arguments default to [BorderSide.none] and must not be null. + /// All arguments default to [BorderSide.none]. const Border.symmetric({ BorderSide vertical = BorderSide.none, BorderSide horizontal = BorderSide.none, @@ -437,8 +433,6 @@ class Border extends BoxBorder { /// /// It is only valid to call this if [BorderSide.canMerge] returns true for /// the pairwise combination of each side on both [Border]s. - /// - /// The arguments must not be null. static Border merge(Border a, Border b) { assert(BorderSide.canMerge(a.top, b.top)); assert(BorderSide.canMerge(a.right, b.right)); @@ -761,8 +755,6 @@ class BorderDirectional extends BoxBorder { /// the trailing edge. They are resolved during [paint]. /// /// All the sides of the border default to [BorderSide.none]. - /// - /// The arguments must not be null. const BorderDirectional({ this.top = BorderSide.none, this.start = BorderSide.none, @@ -775,8 +767,6 @@ class BorderDirectional extends BoxBorder { /// /// It is only valid to call this if [BorderSide.canMerge] returns true for /// the pairwise combination of each side on both [BorderDirectional]s. - /// - /// The arguments must not be null. static BorderDirectional merge(BorderDirectional a, BorderDirectional b) { assert(BorderSide.canMerge(a.top, b.top)); assert(BorderSide.canMerge(a.start, b.start)); diff --git a/packages/flutter/lib/src/painting/box_decoration.dart b/packages/flutter/lib/src/painting/box_decoration.dart index e076247d99165..26328607ccf3f 100644 --- a/packages/flutter/lib/src/painting/box_decoration.dart +++ b/packages/flutter/lib/src/painting/box_decoration.dart @@ -84,8 +84,6 @@ class BoxDecoration extends Decoration { /// * If [boxShadow] is null, this decoration does not paint a shadow. /// * If [gradient] is null, this decoration does not paint gradients. /// * If [backgroundBlendMode] is null, this decoration paints with [BlendMode.srcOver] - /// - /// The [shape] argument must not be null. const BoxDecoration({ this.color, this.image, diff --git a/packages/flutter/lib/src/painting/circle_border.dart b/packages/flutter/lib/src/painting/circle_border.dart index 69b5aeb63c370..afec6883efbcc 100644 --- a/packages/flutter/lib/src/painting/circle_border.dart +++ b/packages/flutter/lib/src/painting/circle_border.dart @@ -30,8 +30,6 @@ import 'borders.dart'; /// * [Border], which, when used with [BoxDecoration], can also describe a circle. class CircleBorder extends OutlinedBorder { /// Create a circle border. - /// - /// The [side] argument must not be null. const CircleBorder({ super.side, this.eccentricity = 0.0 }) : assert(eccentricity >= 0.0, 'The eccentricity argument $eccentricity is not greater than or equal to zero.'), assert(eccentricity <= 1.0, 'The eccentricity argument $eccentricity is not less than or equal to one.'); diff --git a/packages/flutter/lib/src/painting/colors.dart b/packages/flutter/lib/src/painting/colors.dart index beb614b25b8c6..f5c9e06bd8856 100644 --- a/packages/flutter/lib/src/painting/colors.dart +++ b/packages/flutter/lib/src/painting/colors.dart @@ -86,8 +86,8 @@ Color _colorFromHue( class HSVColor { /// Creates a color. /// - /// All the arguments must not be null and be in their respective ranges. See - /// the fields for each parameter for a description of their ranges. + /// All the arguments must be in their respective ranges. See the fields for + /// each parameter for a description of their ranges. const HSVColor.fromAHSV(this.alpha, this.hue, this.saturation, this.value) : assert(alpha >= 0.0), assert(alpha <= 1.0), @@ -254,8 +254,8 @@ class HSVColor { class HSLColor { /// Creates a color. /// - /// All the arguments must not be null and be in their respective ranges. See - /// the fields for each parameter for a description of their ranges. + /// All the arguments must be in their respective ranges. See the fields for + /// each parameter for a description of their ranges. const HSLColor.fromAHSL(this.alpha, this.hue, this.saturation, this.lightness) : assert(alpha >= 0.0), assert(alpha <= 1.0), @@ -499,8 +499,6 @@ class ColorSwatch<T> extends Color { /// [DiagnosticsProperty] that has an [Color] as value. class ColorProperty extends DiagnosticsProperty<Color> { /// Create a diagnostics property for [Color]. - /// - /// The [showName], [style], and [level] arguments must not be null. ColorProperty( String super.name, super.value, { diff --git a/packages/flutter/lib/src/painting/continuous_rectangle_border.dart b/packages/flutter/lib/src/painting/continuous_rectangle_border.dart index 302203175b4f2..b7612e43cb490 100644 --- a/packages/flutter/lib/src/painting/continuous_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/continuous_rectangle_border.dart @@ -33,7 +33,7 @@ import 'edge_insets.dart'; /// radius in a step function instead of gradually like the /// [ContinuousRectangleBorder]. class ContinuousRectangleBorder extends OutlinedBorder { - /// The arguments must not be null. + /// Creates a [ContinuousRectangleBorder]. const ContinuousRectangleBorder({ super.side, this.borderRadius = BorderRadius.zero, diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index 66c1be27ff33e..62ea98b8cec9c 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart @@ -40,9 +40,6 @@ enum ImageRepeat { @immutable class DecorationImage { /// Creates an image to show in a [BoxDecoration]. - /// - /// The [image], [alignment], [repeat], and [matchTextDirection] arguments - /// must not be null. const DecorationImage({ required this.image, this.onError, @@ -173,9 +170,9 @@ class DecorationImage { /// Creates a [DecorationImagePainter] for this [DecorationImage]. /// - /// The `onChanged` argument must not be null. It will be called whenever the - /// image needs to be repainted, e.g. because it is loading incrementally or - /// because it is animated. + /// The `onChanged` argument will be called whenever the image needs to be + /// repainted, e.g. because it is loading incrementally or because it is + /// animated. DecorationImagePainter createPainter(VoidCallback onChanged) { return _DecorationImagePainter._(this, onChanged); } @@ -502,9 +499,6 @@ void debugFlushLastFrameImageSizeInfo() { /// bilinear interpolation, rather than the default [FilterQuality.none] which corresponds /// to nearest-neighbor. /// -/// The `canvas`, `rect`, `image`, `scale`, `alignment`, `repeat`, `flipHorizontally` and `filterQuality` -/// arguments must not be null. -/// /// See also: /// /// * [paintBorder], which paints a border around a rectangle on a canvas. diff --git a/packages/flutter/lib/src/painting/flutter_logo.dart b/packages/flutter/lib/src/painting/flutter_logo.dart index 8bee6d9e60b91..81f08eeeb034a 100644 --- a/packages/flutter/lib/src/painting/flutter_logo.dart +++ b/packages/flutter/lib/src/painting/flutter_logo.dart @@ -38,8 +38,6 @@ class FlutterLogoDecoration extends Decoration { /// /// The [style] controls whether and where to draw the "Flutter" label. If one /// is shown, the [textColor] controls the color of the label. - /// - /// The [textColor], [style], and [margin] arguments must not be null. const FlutterLogoDecoration({ this.textColor = const Color(0xFF757575), this.style = FlutterLogoStyle.markOnly, diff --git a/packages/flutter/lib/src/painting/fractional_offset.dart b/packages/flutter/lib/src/painting/fractional_offset.dart index fffdcd36b1f20..174e3b522b5f5 100644 --- a/packages/flutter/lib/src/painting/fractional_offset.dart +++ b/packages/flutter/lib/src/painting/fractional_offset.dart @@ -53,8 +53,6 @@ import 'basic_types.dart'; @immutable class FractionalOffset extends Alignment { /// Creates a fractional offset. - /// - /// The [dx] and [dy] arguments must not be null. const FractionalOffset(double dx, double dy) : super(dx * 2.0 - 1.0, dy * 2.0 - 1.0); diff --git a/packages/flutter/lib/src/painting/geometry.dart b/packages/flutter/lib/src/painting/geometry.dart index e57d3cfad2a89..fb12ba1065f7c 100644 --- a/packages/flutter/lib/src/painting/geometry.dart +++ b/packages/flutter/lib/src/painting/geometry.dart @@ -35,8 +35,6 @@ import 'basic_types.dart'; /// container. /// /// Used by [Tooltip] to position a tooltip relative to its parent. -/// -/// The arguments must not be null. Offset positionDependentBox({ required Size size, required Size childSize, diff --git a/packages/flutter/lib/src/painting/gradient.dart b/packages/flutter/lib/src/painting/gradient.dart index 106d694068f0c..e1545edecdc72 100644 --- a/packages/flutter/lib/src/painting/gradient.dart +++ b/packages/flutter/lib/src/painting/gradient.dart @@ -149,8 +149,8 @@ class GradientRotation extends GradientTransform { abstract class Gradient { /// Initialize the gradient's colors and stops. /// - /// The [colors] argument must not be null, and must have at least two colors - /// (the length is not verified until the [createShader] method is called). + /// The [colors] argument must have at least two colors (the length is not + /// verified until the [createShader] method is called). /// /// If specified, the [stops] argument must have the same number of entries as /// [colors] (this is also not verified until the [createShader] method is @@ -374,8 +374,7 @@ abstract class Gradient { class LinearGradient extends Gradient { /// Creates a linear gradient. /// - /// The [colors] argument must not be null. If [stops] is non-null, it must - /// have the same length as [colors]. + /// If [stops] is non-null, it must have the same length as [colors]. const LinearGradient({ this.begin = Alignment.centerLeft, this.end = Alignment.centerRight, @@ -625,8 +624,7 @@ class LinearGradient extends Gradient { class RadialGradient extends Gradient { /// Creates a radial gradient. /// - /// The [colors] argument must not be null. If [stops] is non-null, it must - /// have the same length as [colors]. + /// If [stops] is non-null, it must have the same length as [colors]. const RadialGradient({ this.center = Alignment.center, this.radius = 0.5, @@ -921,8 +919,7 @@ class RadialGradient extends Gradient { class SweepGradient extends Gradient { /// Creates a sweep gradient. /// - /// The [colors] argument must not be null. If [stops] is non-null, it must - /// have the same length as [colors]. + /// If [stops] is non-null, it must have the same length as [colors]. const SweepGradient({ this.center = Alignment.center, this.startAngle = 0.0, diff --git a/packages/flutter/lib/src/painting/image_cache.dart b/packages/flutter/lib/src/painting/image_cache.dart index 7a7c17b46ccac..f8ddad84f465b 100644 --- a/packages/flutter/lib/src/painting/image_cache.dart +++ b/packages/flutter/lib/src/painting/image_cache.dart @@ -231,8 +231,7 @@ class ImageCache { /// completely discarded by the cache. It should be set to false when calls /// to evict are trying to relieve memory pressure, since an image with a /// listener will not actually be evicted from memory, and subsequent attempts - /// to load it will end up allocating more memory for the image again. The - /// argument must not be null. + /// to load it will end up allocating more memory for the image again. /// /// See also: /// @@ -313,8 +312,6 @@ class ImageCache { /// if not, calls the given callback to obtain it first. In either case, the /// key is moved to the 'most recently used' position. /// - /// The arguments must not be null. The `loader` cannot return null. - /// /// In the event that the loader throws an exception, it will be caught only if /// `onError` is also provided. When an exception is caught resolving an image, /// no completers are cached and `null` is returned instead of a new diff --git a/packages/flutter/lib/src/painting/image_provider.dart b/packages/flutter/lib/src/painting/image_provider.dart index b7067c2583dd7..50df1a66e8db1 100644 --- a/packages/flutter/lib/src/painting/image_provider.dart +++ b/packages/flutter/lib/src/painting/image_provider.dart @@ -406,8 +406,7 @@ abstract class ImageProvider<T extends Object> { /// The location may be [ImageCacheStatus.untracked], indicating that this /// image provider's key is not available in the [ImageCache]. /// - /// The `cache` and `configuration` parameters must not be null. If the - /// `handleError` parameter is null, errors will be reported to + /// If the `handleError` parameter is null, errors will be reported to /// [FlutterError.onError], and the method will return null. /// /// A completed return value of null indicates that an error has occurred. @@ -655,8 +654,6 @@ class _AbstractImageStreamCompleter extends ImageStreamCompleter {} @immutable class AssetBundleImageKey { /// Creates the key for an [AssetImage] or [AssetBundleImageProvider]. - /// - /// The arguments must not be null. const AssetBundleImageKey({ required this.bundle, required this.name, @@ -1402,8 +1399,6 @@ class ResizeImage extends ImageProvider<ResizeImageKey> { // our cache if the headers describe the image as having expired at that point. abstract class NetworkImage extends ImageProvider<NetworkImage> { /// Creates an object that fetches the image at the given URL. - /// - /// The arguments [url] and [scale] must not be null. const factory NetworkImage(String url, { double scale, Map<String, String>? headers }) = network_image.NetworkImage; /// The URL from which the image will be fetched. @@ -1436,8 +1431,6 @@ abstract class NetworkImage extends ImageProvider<NetworkImage> { @immutable class FileImage extends ImageProvider<FileImage> { /// Creates an object that decodes a [File] as an image. - /// - /// The arguments must not be null. const FileImage(this.file, { this.scale = 1.0 }); /// The file to decode into an image. @@ -1528,8 +1521,6 @@ class FileImage extends ImageProvider<FileImage> { @immutable class MemoryImage extends ImageProvider<MemoryImage> { /// Creates an object that decodes a [Uint8List] buffer as an image. - /// - /// The arguments must not be null. const MemoryImage(this.bytes, { this.scale = 1.0 }); /// The bytes to decode into an image. @@ -1674,10 +1665,9 @@ class MemoryImage extends ImageProvider<MemoryImage> { class ExactAssetImage extends AssetBundleImageProvider { /// Creates an object that fetches the given image from an asset bundle. /// - /// The [assetName] and [scale] arguments must not be null. The [scale] arguments - /// defaults to 1.0. The [bundle] argument may be null, in which case the - /// bundle provided in the [ImageConfiguration] passed to the [resolve] call - /// will be used instead. + /// The [scale] argument defaults to 1. The [bundle] argument may be null, in + /// which case the bundle provided in the [ImageConfiguration] passed to the + /// [resolve] call will be used instead. /// /// The [package] argument must be non-null when fetching an asset that is /// included in a package. See the documentation for the [ExactAssetImage] class diff --git a/packages/flutter/lib/src/painting/image_resolution.dart b/packages/flutter/lib/src/painting/image_resolution.dart index 2644a05f72583..f3fe4ef975fa8 100644 --- a/packages/flutter/lib/src/painting/image_resolution.dart +++ b/packages/flutter/lib/src/painting/image_resolution.dart @@ -233,10 +233,10 @@ const double _kLowDprLimit = 2.0; class AssetImage extends AssetBundleImageProvider { /// Creates an object that fetches an image from an asset bundle. /// - /// The [assetName] argument must not be null. It should name the main asset - /// from the set of images to choose from. The [package] argument must be - /// non-null when fetching an asset that is included in package. See the - /// documentation for the [AssetImage] class itself for details. + /// The [assetName] argument should name the main asset from the set of images + /// to choose from. The [package] argument must be non-null when fetching an + /// asset that is included in package. See the documentation for the + /// [AssetImage] class itself for details. const AssetImage( this.assetName, { this.bundle, diff --git a/packages/flutter/lib/src/painting/image_stream.dart b/packages/flutter/lib/src/painting/image_stream.dart index ccfa72d15b025..2f5537a353701 100644 --- a/packages/flutter/lib/src/painting/image_stream.dart +++ b/packages/flutter/lib/src/painting/image_stream.dart @@ -20,8 +20,6 @@ import 'package:flutter/scheduler.dart'; class ImageInfo { /// Creates an [ImageInfo] object for the given [image] and [scale]. /// - /// Both the [image] and the [scale] must not be null. - /// /// The [debugLabel] may be used to identify the source of this image. const ImageInfo({ required this.image, this.scale = 1.0, this.debugLabel }); @@ -159,8 +157,6 @@ class ImageInfo { @immutable class ImageStreamListener { /// Creates a new [ImageStreamListener]. - /// - /// The [onImage] parameter must not be null. const ImageStreamListener( this.onImage, { this.onChunk, diff --git a/packages/flutter/lib/src/painting/inline_span.dart b/packages/flutter/lib/src/painting/inline_span.dart index 175ee7d8963cc..97bb83f2c6b2c 100644 --- a/packages/flutter/lib/src/painting/inline_span.dart +++ b/packages/flutter/lib/src/painting/inline_span.dart @@ -51,8 +51,6 @@ class InlineSpanSemanticsInformation { /// Constructs an object that holds the text and semantics label values of an /// [InlineSpan]. /// - /// The text parameter must not be null. - /// /// Use [InlineSpanSemanticsInformation.placeholder] instead of directly setting /// [isPlaceholder]. const InlineSpanSemanticsInformation( diff --git a/packages/flutter/lib/src/painting/matrix_utils.dart b/packages/flutter/lib/src/painting/matrix_utils.dart index 7bc30f076b12d..b2d0018de6207 100644 --- a/packages/flutter/lib/src/painting/matrix_utils.dart +++ b/packages/flutter/lib/src/painting/matrix_utils.dart @@ -541,8 +541,6 @@ List<String> debugDescribeTransform(Matrix4? transform) { /// Property which handles [Matrix4] that represent transforms. class TransformProperty extends DiagnosticsProperty<Matrix4> { /// Create a diagnostics property for [Matrix4] objects. - /// - /// The [showName] and [level] arguments must not be null. TransformProperty( String super.name, super.value, { diff --git a/packages/flutter/lib/src/painting/notched_shapes.dart b/packages/flutter/lib/src/painting/notched_shapes.dart index 8f7a83042d494..2e19b315c6658 100644 --- a/packages/flutter/lib/src/painting/notched_shapes.dart +++ b/packages/flutter/lib/src/painting/notched_shapes.dart @@ -130,8 +130,6 @@ class CircularNotchedRectangle extends NotchedShape { class AutomaticNotchedShape extends NotchedShape { /// Creates a [NotchedShape] that is defined by two [ShapeBorder]s. /// - /// The [host] must not be null. - /// /// The [guest] may be null, in which case no notch is created even /// if a guest rectangle is provided to [getOuterPath]. const AutomaticNotchedShape(this.host, [ this.guest ]); diff --git a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart index c4320ebdf841d..27109396c2a0c 100644 --- a/packages/flutter/lib/src/painting/rounded_rectangle_border.dart +++ b/packages/flutter/lib/src/painting/rounded_rectangle_border.dart @@ -25,8 +25,6 @@ import 'circle_border.dart'; /// describe a rounded rectangle. class RoundedRectangleBorder extends OutlinedBorder { /// Creates a rounded rectangle border. - /// - /// The arguments must not be null. const RoundedRectangleBorder({ super.side, this.borderRadius = BorderRadius.zero, diff --git a/packages/flutter/lib/src/painting/shape_decoration.dart b/packages/flutter/lib/src/painting/shape_decoration.dart index bf7a0e872d132..fbe3c60ad5c3d 100644 --- a/packages/flutter/lib/src/painting/shape_decoration.dart +++ b/packages/flutter/lib/src/painting/shape_decoration.dart @@ -68,8 +68,6 @@ class ShapeDecoration extends Decoration { /// /// The [color] and [gradient] properties are mutually exclusive, one (or /// both) of them must be null. - /// - /// The [shape] must not be null. const ShapeDecoration({ this.color, this.image, @@ -157,8 +155,7 @@ class ShapeDecoration extends Decoration { /// Shapes can be stacked (using the `+` operator). The color, gradient, and /// image are drawn into the inner-most shape specified. /// - /// The [shape] property specifies the outline (border) of the decoration. The - /// shape must not be null. + /// The [shape] property specifies the outline (border) of the decoration. /// /// ## Directionality-dependent shapes /// diff --git a/packages/flutter/lib/src/painting/stadium_border.dart b/packages/flutter/lib/src/painting/stadium_border.dart index 1576e93acaed2..e9e57dfcda24e 100644 --- a/packages/flutter/lib/src/painting/stadium_border.dart +++ b/packages/flutter/lib/src/painting/stadium_border.dart @@ -25,8 +25,6 @@ import 'rounded_rectangle_border.dart'; /// * [BorderSide], which is used to describe the border of the stadium. class StadiumBorder extends OutlinedBorder { /// Create a stadium border. - /// - /// The [side] argument must not be null. const StadiumBorder({ super.side }); @override diff --git a/packages/flutter/lib/src/painting/strut_style.dart b/packages/flutter/lib/src/painting/strut_style.dart index 152ec3b8cfd19..432a835950161 100644 --- a/packages/flutter/lib/src/painting/strut_style.dart +++ b/packages/flutter/lib/src/painting/strut_style.dart @@ -318,8 +318,6 @@ class StrutStyle with Diagnosticable { /// Builds a StrutStyle that contains values of the equivalent properties in /// the provided [textStyle]. /// - /// The [textStyle] parameter must not be null. - /// /// The named parameters override the [textStyle]'s argument's properties. /// Since TextStyle does not contain [leading] or [forceStrutHeight], these /// values will take on default values (null and false) unless otherwise diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 0d1b24c7594b3..955e716ed0f5b 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -56,8 +56,6 @@ enum TextOverflow { /// Placeholders specify an empty space in the text layout, which is used /// to later render arbitrary inline widgets into defined by a [WidgetSpan]. /// -/// The [size] and [alignment] properties are required and cannot be null. -/// /// See also: /// /// * [WidgetSpan], a subclass of [InlineSpan] and [PlaceholderSpan] that @@ -470,8 +468,6 @@ class TextPainter { /// The `text` and `textDirection` arguments are optional but [text] and /// [textDirection] must be non-null before calling [layout]. /// - /// The [textAlign] property must not be null. - /// /// The [maxLines] property, if non-null, must be greater than zero. TextPainter({ InlineSpan? text, @@ -707,7 +703,7 @@ class TextPainter { /// /// After this is set, you must call [layout] before the next call to [paint]. /// - /// The [textAlign] property must not be null. It defaults to [TextAlign.start]. + /// The [textAlign] property defaults to [TextAlign.start]. TextAlign get textAlign => _textAlign; TextAlign _textAlign; set textAlign(TextAlign value) { diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart index d88e5a0262381..3fd51313a7ba7 100644 --- a/packages/flutter/lib/src/painting/text_style.dart +++ b/packages/flutter/lib/src/painting/text_style.dart @@ -929,8 +929,6 @@ class TextStyle with Diagnosticable { /// applied to a `style` whose [fontWeight] is [FontWeight.w500] will return a /// [TextStyle] with a [FontWeight.w300]. /// - /// The numeric arguments must not be null. - /// /// If the underlying values are null, then the corresponding factors and/or /// deltas must not be specified. /// @@ -1321,9 +1319,9 @@ class TextStyle with Diagnosticable { /// The style information for paragraphs, encoded for use by `dart:ui`. /// - /// The `textScaleFactor` argument must not be null. If omitted, it defaults - /// to 1.0. The other arguments may be null. The `maxLines` argument, if - /// specified and non-null, must be greater than zero. + /// If the `textScaleFactor` argument is omitted, it defaults to one. The + /// other arguments may be null. The `maxLines` argument, if specified and + /// non-null, must be greater than zero. /// /// If the font size on this style isn't set, it will default to 14 logical /// pixels. diff --git a/packages/flutter/lib/src/rendering/animated_size.dart b/packages/flutter/lib/src/rendering/animated_size.dart index 5f3aaea161701..cbce56c38c319 100644 --- a/packages/flutter/lib/src/rendering/animated_size.dart +++ b/packages/flutter/lib/src/rendering/animated_size.dart @@ -175,7 +175,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/rendering/box.dart b/packages/flutter/lib/src/rendering/box.dart index 68cb816d26a79..cedd6362b9954 100644 --- a/packages/flutter/lib/src/rendering/box.dart +++ b/packages/flutter/lib/src/rendering/box.dart @@ -899,8 +899,6 @@ class BoxHitTestResult extends HitTestResult { /// A hit test entry used by [RenderBox]. class BoxHitTestEntry extends HitTestEntry<RenderBox> { /// Creates a box hit test entry. - /// - /// The [localPosition] argument must not be null. BoxHitTestEntry(super.target, this.localPosition); /// The position of the hit test in the local coordinates of [target]. diff --git a/packages/flutter/lib/src/rendering/custom_layout.dart b/packages/flutter/lib/src/rendering/custom_layout.dart index e5ddee86281c4..7c28feca822cd 100644 --- a/packages/flutter/lib/src/rendering/custom_layout.dart +++ b/packages/flutter/lib/src/rendering/custom_layout.dart @@ -303,8 +303,6 @@ class RenderCustomMultiChildLayoutBox extends RenderBox with ContainerRenderObjectMixin<RenderBox, MultiChildLayoutParentData>, RenderBoxContainerDefaultsMixin<RenderBox, MultiChildLayoutParentData> { /// Creates a render object that customizes the layout of multiple children. - /// - /// The [delegate] argument must not be null. RenderCustomMultiChildLayoutBox({ List<RenderBox>? children, required MultiChildLayoutDelegate delegate, diff --git a/packages/flutter/lib/src/rendering/custom_paint.dart b/packages/flutter/lib/src/rendering/custom_paint.dart index 320640a9fad86..e9e176ec6dc14 100644 --- a/packages/flutter/lib/src/rendering/custom_paint.dart +++ b/packages/flutter/lib/src/rendering/custom_paint.dart @@ -303,8 +303,6 @@ abstract class CustomPainter extends Listenable { @immutable class CustomPainterSemantics { /// Creates semantics information describing a rectangle on a canvas. - /// - /// Arguments `rect` and `properties` must not be null. const CustomPainterSemantics({ this.key, required this.rect, diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 2dd8671711aa4..721e0aa45cf1f 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -36,8 +36,6 @@ const Radius _kFloatingCursorRadius = Radius.circular(1.0); @immutable class TextSelectionPoint { /// Creates a description of a point in a text selection. - /// - /// The [point] argument must not be null. const TextSelectionPoint(this.point, this.direction); /// Coordinates of the lower left or lower right corner of the selection, @@ -261,9 +259,7 @@ class VerticalCaretMovementRun implements Iterator<TextPosition> { class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, ContainerRenderObjectMixin<RenderBox, TextParentData>, RenderInlineChildrenContainerDefaults implements TextLayoutMetrics { /// Creates a render object that implements the visual aspects of a text field. /// - /// The [textAlign] argument must not be null. It defaults to [TextAlign.start]. - /// - /// The [textDirection] argument must not be null. + /// The [textAlign] argument defaults to [TextAlign.start]. /// /// If [showCursor] is not specified, then it defaults to hiding the cursor. /// @@ -271,8 +267,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// the number of lines. By default, it is 1, meaning this is a single-line /// text field. If it is not null, it must be greater than zero. /// - /// The [offset] is required and must not be null. You can use [ - /// ViewportOffset.zero] if you have no need for scrolling. + /// Use [ViewportOffset.zero] for the [offset] if there is no need for + /// scrolling. RenderEditable({ InlineSpan? text, required TextDirection textDirection, @@ -564,7 +560,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// Character used for obscuring text if [obscureText] is true. /// - /// Cannot be null, and must have a length of exactly one. + /// Must have a length of exactly one. String get obscuringCharacter => _obscuringCharacter; String _obscuringCharacter; set obscuringCharacter(String value) { @@ -607,8 +603,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// The object that controls the text selection, used by this render object /// for implementing cut, copy, and paste keyboard shortcuts. /// - /// It must not be null. It will make cut, copy and paste functionality work - /// with the most recently set [TextSelectionDelegate]. + /// It will make cut, copy and paste functionality work with the most recently + /// set [TextSelectionDelegate]. TextSelectionDelegate textSelectionDelegate; /// Track whether position of the start of the selected text is within the viewport. @@ -802,8 +798,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, } /// How the text should be aligned horizontally. - /// - /// This must not be null. TextAlign get textAlign => _textPainter.textAlign; set textAlign(TextAlign value) { if (_textPainter.textAlign == value) { @@ -824,8 +818,6 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// and the Hebrew phrase to its right, while in a [TextDirection.rtl] /// context, the English phrase will be on the right and the Hebrew phrase on /// its left. - /// - /// This must not be null. // TextPainter.textDirection is nullable, but it is set to a // non-null value in the RenderEditable constructor and we refuse to // set it to null here, so _textPainter.textDirection cannot be null. @@ -1257,7 +1249,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart index 5737ce92a1e56..da12a9cd94437 100644 --- a/packages/flutter/lib/src/rendering/flex.dart +++ b/packages/flutter/lib/src/rendering/flex.dart @@ -472,7 +472,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.none; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/rendering/flow.dart b/packages/flutter/lib/src/rendering/flow.dart index 0a2658d02ddeb..e3ab6357a09dd 100644 --- a/packages/flutter/lib/src/rendering/flow.dart +++ b/packages/flutter/lib/src/rendering/flow.dart @@ -227,7 +227,7 @@ class RenderFlow extends RenderBox /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart index 0180a26ad190c..593bc97c6a552 100644 --- a/packages/flutter/lib/src/rendering/image.dart +++ b/packages/flutter/lib/src/rendering/image.dart @@ -23,9 +23,8 @@ export 'package:flutter/painting.dart' show class RenderImage extends RenderBox { /// Creates a render box that displays an image. /// - /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments - /// must not be null. The [textDirection] argument must not be null if - /// [alignment] will need resolving or if [matchTextDirection] is true. + /// The [textDirection] argument must not be null if [alignment] will need + /// resolving or if [matchTextDirection] is true. RenderImage({ ui.Image? image, this.debugImageLabel, diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart index b8cd83fac5e32..f2bd274fd5212 100644 --- a/packages/flutter/lib/src/rendering/layer.dart +++ b/packages/flutter/lib/src/rendering/layer.dart @@ -974,8 +974,6 @@ class TextureLayer extends Layer { /// on iOS. class PlatformViewLayer extends Layer { /// Creates a platform view layer. - /// - /// The `rect` and `viewId` parameters must not be null. PlatformViewLayer({ required this.rect, required this.viewId, @@ -1411,8 +1409,6 @@ class ContainerLayer extends Layer { /// may explicitly allow null as a value, for example if they know that they /// transform all their children identically. /// - /// The `transform` argument must not be null. - /// /// Used by [FollowerLayer] to transform its child to a [LeaderLayer]'s /// position. void applyTransform(Layer? child, Matrix4 transform) { @@ -1610,7 +1606,7 @@ class ClipRectLayer extends ContainerLayer { /// The [clipRect] argument must not be null before the compositing phase of /// the pipeline. /// - /// The [clipBehavior] argument must not be null, and must not be [Clip.none]. + /// The [clipBehavior] argument must not be [Clip.none]. ClipRectLayer({ Rect? clipRect, Clip clipBehavior = Clip.hardEdge, @@ -2368,9 +2364,8 @@ class LayerLink { class LeaderLayer extends ContainerLayer { /// Creates a leader layer. /// - /// The [link] property must not be null, and must not have been provided to - /// any other [LeaderLayer] layers that are [attached] to the layer tree at - /// the same time. + /// The [link] property must not have been provided to any other [LeaderLayer] + /// layers that are [attached] to the layer tree at the same time. /// /// The [offset] property must be non-null before the compositing phase of the /// pipeline. @@ -2480,8 +2475,6 @@ class LeaderLayer extends ContainerLayer { class FollowerLayer extends ContainerLayer { /// Creates a follower layer. /// - /// The [link] property must not be null. - /// /// The [unlinkedOffset], [linkedOffset], and [showWhenUnlinked] properties /// must be non-null before the compositing phase of the pipeline. FollowerLayer({ @@ -2805,8 +2798,6 @@ class FollowerLayer extends ContainerLayer { /// if [opaque] is true and the layer's annotation is added. class AnnotatedRegionLayer<T extends Object> extends ContainerLayer { /// Creates a new layer that annotates its children with [value]. - /// - /// The [value] provided cannot be null. AnnotatedRegionLayer( this.value, { this.size, diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart index 48bc762367999..bdf62c603b169 100644 --- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart @@ -146,7 +146,7 @@ class RenderListWheelViewport implements RenderAbstractViewport { /// Creates a [RenderListWheelViewport] which renders children on a wheel. /// - /// All arguments must not be null. Optional arguments have reasonable defaults. + /// Optional arguments have reasonable defaults. RenderListWheelViewport({ required this.childManager, required ViewportOffset offset, @@ -220,8 +220,6 @@ class RenderListWheelViewport /// viewport uses to select which part of its content to display. As the user /// scrolls the viewport, this value changes, which changes the content that /// is displayed. - /// - /// Must not be null. ViewportOffset get offset => _offset; ViewportOffset _offset; set offset(ViewportOffset value) { @@ -264,7 +262,7 @@ class RenderListWheelViewport /// /// Defaults to an arbitrary but aesthetically reasonable number of 2.0. /// - /// Must not be null and must be positive. + /// Must be a positive number. /// {@endtemplate} double get diameterRatio => _diameterRatio; double _diameterRatio; @@ -293,7 +291,7 @@ class RenderListWheelViewport /// A larger number brings the vanishing point closer and a smaller number /// pushes the vanishing point further. /// - /// Must not be null and must be positive. + /// Must be a positive number. /// {@endtemplate} double get perspective => _perspective; double _perspective; @@ -402,7 +400,7 @@ class RenderListWheelViewport /// The size of the children along the main axis. Children [RenderBox]es will /// be given the [BoxConstraints] of this exact size. /// - /// Must not be null and must be positive. + /// Must be a positive number. /// {@endtemplate} double get itemExtent => _itemExtent; double _itemExtent; @@ -432,7 +430,7 @@ class RenderListWheelViewport /// Changing this value will change the number of children built and shown /// inside the wheel. /// - /// Must not be null and must be positive. + /// Must be a positive number. /// {@endtemplate} /// /// Defaults to 1. @@ -454,9 +452,9 @@ class RenderListWheelViewport /// If false, every child will be painted. However the [Scrollable] is still /// the size of the viewport and detects gestures inside only. /// - /// Defaults to false. Must not be null. Cannot be true if [clipBehavior] - /// is not [Clip.none] since children outside the viewport will be clipped, and - /// therefore cannot render children outside the viewport. + /// Defaults to false. Cannot be true if [clipBehavior] is not [Clip.none] + /// since children outside the viewport will be clipped, and therefore cannot + /// render children outside the viewport. /// {@endtemplate} bool get renderChildrenOutsideViewport => _renderChildrenOutsideViewport; bool _renderChildrenOutsideViewport; @@ -475,7 +473,7 @@ class RenderListWheelViewport /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart index 2683563f8c6e5..059e0a169c021 100644 --- a/packages/flutter/lib/src/rendering/object.dart +++ b/packages/flutter/lib/src/rendering/object.dart @@ -812,8 +812,6 @@ abstract class Constraints { /// Signature for a function that is called for each [RenderObject]. /// /// Used by [RenderObject.visitChildren] and [RenderObject.visitChildrenForSemantics]. -/// -/// The `child` argument must not be null. typedef RenderObjectVisitor = void Function(RenderObject child); /// Signature for a function that is called during layout. diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 111ddb3fc4195..acdfed2543af8 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -255,9 +255,6 @@ mixin RenderInlineChildrenContainerDefaults on RenderBox, ContainerRenderObjectM class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBox, TextParentData>, RenderInlineChildrenContainerDefaults, RelayoutWhenSystemFontsChangeMixin { /// Creates a paragraph render object. /// - /// The [text], [textAlign], [textDirection], [overflow], [softWrap], and - /// [textScaler] arguments must not be null. - /// /// The [maxLines] property may be null (and indeed defaults to null), but if /// it is not null, it must be greater than zero. RenderParagraph(InlineSpan text, { @@ -463,8 +460,6 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo /// and the Hebrew phrase to its right, while in a [TextDirection.rtl] /// context, the English phrase will be on the right and the Hebrew phrase on /// its left. - /// - /// This must not be null. TextDirection get textDirection => _textPainter.textDirection!; set textDirection(TextDirection value) { if (_textPainter.textDirection == value) { @@ -941,8 +936,7 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo /// /// The [boxHeightStyle] and [boxWidthStyle] arguments may be used to select /// the shape of the [TextBox]es. These properties default to - /// [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively and - /// must not be null. + /// [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively. /// /// A given selection might have more than one rect if the [RenderParagraph] /// contains multiple [InlineSpan]s or bidirectional text, because logically diff --git a/packages/flutter/lib/src/rendering/performance_overlay.dart b/packages/flutter/lib/src/rendering/performance_overlay.dart index d48e21317c788..fbd4de8ada7eb 100644 --- a/packages/flutter/lib/src/rendering/performance_overlay.dart +++ b/packages/flutter/lib/src/rendering/performance_overlay.dart @@ -59,9 +59,6 @@ enum PerformanceOverlayOption { /// to true. class RenderPerformanceOverlay extends RenderBox { /// Creates a performance overlay render object. - /// - /// The [optionsMask], [rasterizerThreshold], [checkerboardRasterCacheImages], - /// and [checkerboardOffscreenLayers] arguments must not be null. RenderPerformanceOverlay({ int optionsMask = 0, int rasterizerThreshold = 0, diff --git a/packages/flutter/lib/src/rendering/platform_view.dart b/packages/flutter/lib/src/rendering/platform_view.dart index e2bfb28177476..a04fbd8c6fccc 100644 --- a/packages/flutter/lib/src/rendering/platform_view.dart +++ b/packages/flutter/lib/src/rendering/platform_view.dart @@ -122,7 +122,7 @@ class RenderAndroidView extends PlatformViewRenderBox { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { @@ -404,8 +404,6 @@ abstract class RenderDarwinPlatformView<T extends DarwinPlatformViewController> /// * [PlatformViewsService], which is a service for controlling platform views. class RenderUiKitView extends RenderDarwinPlatformView<UiKitViewController> { /// Creates a render object for an iOS UIView. - /// - /// The `viewId`, `hitTestBehavior`, and `gestureRecognizers` parameters must not be null. RenderUiKitView({ required super.viewController, required super.hitTestBehavior, @@ -655,8 +653,6 @@ class _PlatformViewGestureRecognizer extends OneSequenceGestureRecognizer { /// integrates it with the gesture arenas system and adds relevant semantic nodes to the semantics tree. class PlatformViewRenderBox extends RenderBox with _PlatformViewGestureMixin { /// Creating a render object for a [PlatformViewSurface]. - /// - /// The `controller` parameter must not be null. PlatformViewRenderBox({ required PlatformViewController controller, required PlatformViewHitTestBehavior hitTestBehavior, @@ -670,7 +666,7 @@ class PlatformViewRenderBox extends RenderBox with _PlatformViewGestureMixin { /// The controller for this render object. PlatformViewController get controller => _controller; PlatformViewController _controller; - /// This value must not be null, and setting it to a new value will result in a repaint. + /// Setting this value to a new value will result in a repaint. set controller(covariant PlatformViewController controller) { assert(controller.viewId > -1); diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 25c32741b7b16..bf80a69330b27 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -200,7 +200,7 @@ abstract class RenderProxyBoxWithHitTestBehavior extends RenderProxyBox { class RenderConstrainedBox extends RenderProxyBox { /// Creates a render box that constrains its child. /// - /// The [additionalConstraints] argument must not be null and must be valid. + /// The [additionalConstraints] argument must be valid. RenderConstrainedBox({ RenderBox? child, required BoxConstraints additionalConstraints, @@ -891,8 +891,6 @@ class RenderOpacity extends RenderProxyBox { /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent /// (i.e., invisible). /// - /// The opacity must not be null. - /// /// Values 1.0 and 0.0 are painted with a fast path. Other values /// require painting the child into an intermediate buffer, which is /// expensive. @@ -1094,8 +1092,6 @@ mixin RenderAnimatedOpacityMixin<T extends RenderObject> on RenderObjectWithChil /// than a [double] to control the opacity. class RenderAnimatedOpacity extends RenderProxyBox with RenderAnimatedOpacityMixin<RenderBox> { /// Creates a partially transparent render object. - /// - /// The [opacity] argument must not be null. RenderAnimatedOpacity({ required Animation<double> opacity, bool alwaysIncludeSemantics = false, @@ -1117,8 +1113,6 @@ typedef ShaderCallback = Shader Function(Rect bounds); /// of a child by using a [ui.Gradient.linear] mask. class RenderShaderMask extends RenderProxyBox { /// Creates a render object that applies a mask generated by a [Shader] to its child. - /// - /// The [shaderCallback] and [blendMode] arguments must not be null. RenderShaderMask({ RenderBox? child, required ShaderCallback shaderCallback, @@ -1192,10 +1186,8 @@ class RenderShaderMask extends RenderProxyBox { /// such as a blur. class RenderBackdropFilter extends RenderProxyBox { /// Creates a backdrop filter. - /// - /// The [filter] argument must not be null. - /// The [blendMode] argument, if provided, must not be null - /// and will default to [BlendMode.srcOver]. + // + /// The [blendMode] argument defaults to [BlendMode.srcOver]. RenderBackdropFilter({ RenderBox? child, required ui.ImageFilter filter, BlendMode blendMode = BlendMode.srcOver }) : _filter = filter, _blendMode = blendMode, @@ -1341,8 +1333,6 @@ abstract class CustomClipper<T> extends Listenable { class ShapeBorderClipper extends CustomClipper<Path> { /// Creates a [ShapeBorder] clipper. /// - /// The [shape] argument must not be null. - /// /// The [textDirection] argument must be provided non-null if [shape] /// has a text direction dependency (for example if it is expressed in terms /// of "start" and "end" instead of "left" and "right"). It may be null if @@ -1512,8 +1502,7 @@ class RenderClipRect extends _RenderCustomClip<Rect> { /// If [clipper] is null, the clip will match the layout size and position of /// the child. /// - /// The [clipBehavior] must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. RenderClipRect({ super.child, super.clipper, @@ -1585,8 +1574,7 @@ class RenderClipRRect extends _RenderCustomClip<RRect> { /// /// If [clipper] is non-null, then [borderRadius] is ignored. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. RenderClipRRect({ super.child, BorderRadiusGeometry borderRadius = BorderRadius.zero, @@ -1687,8 +1675,7 @@ class RenderClipOval extends _RenderCustomClip<Rect> { /// If [clipper] is null, the oval will be inscribed into the layout size and /// position of the child. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. RenderClipOval({ super.child, super.clipper, @@ -1783,8 +1770,7 @@ class RenderClipPath extends _RenderCustomClip<Path> { /// consider using a [RenderClipRect], which can achieve the same effect more /// efficiently. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. RenderClipPath({ super.child, super.clipper, @@ -1849,8 +1835,7 @@ class RenderClipPath extends _RenderCustomClip<Path> { /// The concrete implementations [RenderPhysicalModel] and [RenderPhysicalShape] /// determine the actual shape of the physical model. abstract class _RenderPhysicalModelBase<T> extends _RenderCustomClip<T> { - /// The [shape], [elevation], [color], and [shadowColor] must not be null. - /// Additionally, the [elevation] must be non-negative. + /// The [elevation] parameter must be non-negative. _RenderPhysicalModelBase({ required super.child, required double elevation, @@ -1930,9 +1915,7 @@ class RenderPhysicalModel extends _RenderPhysicalModelBase<RRect> { /// /// The [color] is required. /// - /// The [shape], [elevation], [color], [clipBehavior], and [shadowColor] - /// arguments must not be null. Additionally, the [elevation] must be - /// non-negative. + /// The [elevation] parameter must be non-negative. RenderPhysicalModel({ super.child, BoxShape shape = BoxShape.rectangle, @@ -2090,8 +2073,7 @@ class RenderPhysicalShape extends _RenderPhysicalModelBase<Path> { /// /// The [color] and [clipper] parameters are required. /// - /// The [clipper], [elevation], [color] and [shadowColor] must not be null. - /// Additionally, the [elevation] must be non-negative. + /// The [elevation] parameter must be non-negative. RenderPhysicalShape({ super.child, required CustomClipper<Path> super.clipper, @@ -2330,8 +2312,6 @@ class RenderDecoratedBox extends RenderProxyBox { /// Applies a transformation before painting its child. class RenderTransform extends RenderProxyBox { /// Creates a render object that transforms its child. - /// - /// The [transform] argument must not be null. RenderTransform({ required Matrix4 transform, Offset? origin, @@ -2598,8 +2578,6 @@ class RenderTransform extends RenderProxyBox { /// Scales and positions its child within itself according to [fit]. class RenderFittedBox extends RenderProxyBox { /// Scales and positions its child within itself. - /// - /// The [fit] and [alignment] arguments must not be null. RenderFittedBox({ BoxFit fit = BoxFit.contain, AlignmentGeometry alignment = Alignment.center, @@ -2762,7 +2740,7 @@ class RenderFittedBox extends RenderProxyBox { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.none; set clipBehavior(Clip value) { @@ -2891,8 +2869,6 @@ class RenderFittedBox extends RenderProxyBox { /// they overflow. class RenderFractionalTranslation extends RenderProxyBox { /// Creates a render object that translates its child's painting. - /// - /// The [translation] argument must not be null. RenderFractionalTranslation({ required Offset translation, this.transformHitTests = true, @@ -3154,8 +3130,7 @@ class RenderMouseRegion extends RenderProxyBoxWithHitTestBehavior implements Mou /// Creates a render object that forwards pointer events to callbacks. /// /// All parameters are optional. By default this method creates an opaque - /// mouse region with no callbacks and cursor being [MouseCursor.defer]. The - /// [cursor] must not be null. + /// mouse region with no callbacks and cursor being [MouseCursor.defer]. RenderMouseRegion({ this.onEnter, this.onHover, @@ -3562,8 +3537,6 @@ class RenderRepaintBoundary extends RenderProxyBox { /// nodes in the subtree from seeing them. class RenderIgnorePointer extends RenderProxyBox { /// Creates a render object that is invisible to hit testing. - /// - /// The [ignoring] argument must not be null. RenderIgnorePointer({ RenderBox? child, bool ignoring = true, @@ -3812,8 +3785,6 @@ class RenderOffstage extends RenderProxyBox { /// subtree from considering entirely for the purposes of hit testing. class RenderAbsorbPointer extends RenderProxyBox { /// Creates a render object that absorbs pointers during hit testing. - /// - /// The [absorbing] argument must not be null. RenderAbsorbPointer({ RenderBox? child, bool absorbing = true, @@ -3932,8 +3903,6 @@ class RenderMetaData extends RenderProxyBoxWithHitTestBehavior { /// an accessibility tool). class RenderSemanticsGestureHandler extends RenderProxyBoxWithHitTestBehavior { /// Creates a render object that listens for specific semantic gestures. - /// - /// The [scrollFactor] and [behavior] arguments must not be null. RenderSemanticsGestureHandler({ super.child, GestureTapCallback? onTap, @@ -4125,8 +4094,6 @@ class RenderSemanticsGestureHandler extends RenderProxyBoxWithHitTestBehavior { class RenderSemanticsAnnotations extends RenderProxyBox { /// Creates a render object that attaches a semantic annotation. /// - /// The [container] argument must not be null. - /// /// If the [SemanticsProperties.attributedLabel] is not null, the [textDirection] must also not be null. RenderSemanticsAnnotations({ RenderBox? child, @@ -4719,8 +4686,6 @@ class RenderIndexedSemantics extends RenderProxyBox { /// * [LeaderLayer], the layer that this render object creates. class RenderLeaderLayer extends RenderProxyBox { /// Creates a render object that uses a [LeaderLayer]. - /// - /// The [link] must not be null. RenderLeaderLayer({ required LayerLink link, RenderBox? child, @@ -4730,8 +4695,8 @@ class RenderLeaderLayer extends RenderProxyBox { /// The link object that connects this [RenderLeaderLayer] with one or more /// [RenderFollowerLayer]s. /// - /// This property must not be null. The object must not be associated with - /// another [RenderLeaderLayer] that is also being painted. + /// The object must not be associated with another [RenderLeaderLayer] that is + /// also being painted. LayerLink get link => _link; LayerLink _link; set link(LayerLink value) { @@ -4800,8 +4765,6 @@ class RenderLeaderLayer extends RenderProxyBox { /// * [FollowerLayer], the layer that this render object creates. class RenderFollowerLayer extends RenderProxyBox { /// Creates a render object that uses a [FollowerLayer]. - /// - /// The [link] and [offset] arguments must not be null. RenderFollowerLayer({ required LayerLink link, bool showWhenUnlinked = true, diff --git a/packages/flutter/lib/src/rendering/proxy_sliver.dart b/packages/flutter/lib/src/rendering/proxy_sliver.dart index 2425cb8ebc7e0..a33ee947cb8d7 100644 --- a/packages/flutter/lib/src/rendering/proxy_sliver.dart +++ b/packages/flutter/lib/src/rendering/proxy_sliver.dart @@ -118,14 +118,11 @@ class RenderSliverOpacity extends RenderProxySliver { /// The fraction to scale the child's alpha value. /// - /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent + /// An opacity of one is fully opaque. An opacity of zero is fully transparent /// (i.e. invisible). /// - /// The opacity must not be null. - /// - /// Values 1.0 and 0.0 are painted with a fast path. Other values - /// require painting the child into an intermediate buffer, which is - /// expensive. + /// Values one and zero are painted with a fast path. Other values require + /// painting the child into an intermediate buffer, which is expensive. double get opacity => _opacity; double _opacity; set opacity(double value) { @@ -215,8 +212,6 @@ class RenderSliverOpacity extends RenderProxySliver { /// {@macro flutter.widgets.IgnorePointer.ignoringSemantics} class RenderSliverIgnorePointer extends RenderProxySliver { /// Creates a render object that is invisible to hit testing. - /// - /// The [ignoring] argument must not be null. RenderSliverIgnorePointer({ RenderSliver? sliver, bool ignoring = true, @@ -410,8 +405,6 @@ class RenderSliverOffstage extends RenderProxySliver { /// rather than a [double] to control the opacity. class RenderSliverAnimatedOpacity extends RenderProxySliver with RenderAnimatedOpacityMixin<RenderSliver> { /// Creates a partially transparent render object. - /// - /// The [opacity] argument must not be null. RenderSliverAnimatedOpacity({ required Animation<double> opacity, bool alwaysIncludeSemantics = false, @@ -431,7 +424,7 @@ class RenderSliverAnimatedOpacity extends RenderProxySliver with RenderAnimatedO class RenderSliverConstrainedCrossAxis extends RenderProxySliver { /// Creates a render object that constrains the cross axis extent of its sliver child. /// - /// The [maxExtent] parameter must not be null and must be nonnegative. + /// The [maxExtent] parameter must be nonnegative. RenderSliverConstrainedCrossAxis({ required double maxExtent }) : _maxExtent = maxExtent, diff --git a/packages/flutter/lib/src/rendering/rotated_box.dart b/packages/flutter/lib/src/rendering/rotated_box.dart index 03cb105acfd71..89cf6aafc46ac 100644 --- a/packages/flutter/lib/src/rendering/rotated_box.dart +++ b/packages/flutter/lib/src/rendering/rotated_box.dart @@ -19,8 +19,6 @@ const double _kQuarterTurnsInRadians = math.pi / 2.0; /// rotated box consumes only as much space as required by the rotated child. class RenderRotatedBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> { /// Creates a rotated render box. - /// - /// The [quarterTurns] argument must not be null. RenderRotatedBox({ required int quarterTurns, RenderBox? child, diff --git a/packages/flutter/lib/src/rendering/selection.dart b/packages/flutter/lib/src/rendering/selection.dart index 303a5d71654b1..d5434f26f9d68 100644 --- a/packages/flutter/lib/src/rendering/selection.dart +++ b/packages/flutter/lib/src/rendering/selection.dart @@ -421,8 +421,6 @@ class SelectionEdgeUpdateEvent extends SelectionEvent { /// [isEnd], according to the [granularity]. class GranularlyExtendSelectionEvent extends SelectionEvent { /// Creates a [GranularlyExtendSelectionEvent]. - /// - /// All parameters are required and must not be null. const GranularlyExtendSelectionEvent({ required this.forward, required this.isEnd, @@ -499,8 +497,6 @@ enum SelectionExtendDirection { /// move to when moving to across lines. class DirectionallyExtendSelectionEvent extends SelectionEvent { /// Creates a [DirectionallyExtendSelectionEvent]. - /// - /// All parameters are required and must not be null. const DirectionallyExtendSelectionEvent({ required this.dx, required this.isEnd, @@ -706,8 +702,6 @@ class SelectionGeometry { @immutable class SelectionPoint with Diagnosticable { /// Creates a selection point object. - /// - /// All properties must not be null. const SelectionPoint({ required this.localPosition, required this.lineHeight, diff --git a/packages/flutter/lib/src/rendering/shifted_box.dart b/packages/flutter/lib/src/rendering/shifted_box.dart index c0e21a66d8d08..2afe15c064ad5 100644 --- a/packages/flutter/lib/src/rendering/shifted_box.dart +++ b/packages/flutter/lib/src/rendering/shifted_box.dart @@ -102,7 +102,7 @@ abstract class RenderShiftedBox extends RenderBox with RenderObjectWithChildMixi class RenderPadding extends RenderShiftedBox { /// Creates a render object that insets its child. /// - /// The [padding] argument must not be null and must have non-negative insets. + /// The [padding] argument must have non-negative insets. RenderPadding({ required EdgeInsetsGeometry padding, TextDirection? textDirection, @@ -267,8 +267,6 @@ class RenderPadding extends RenderShiftedBox { abstract class RenderAligningShiftedBox extends RenderShiftedBox { /// Initializes member variables for subclasses. /// - /// The [alignment] argument must not be null. - /// /// The [textDirection] must be non-null if the [alignment] is /// direction-sensitive. RenderAligningShiftedBox({ @@ -308,8 +306,6 @@ abstract class RenderAligningShiftedBox extends RenderShiftedBox { AlignmentGeometry get alignment => _alignment; AlignmentGeometry _alignment; /// Sets the alignment to a new value, and triggers a layout update. - /// - /// The new alignment must not be null. set alignment(AlignmentGeometry value) { if (_alignment == value) { return; @@ -685,8 +681,6 @@ class RenderConstrainedOverflowBox extends RenderAligningShiftedBox { class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugOverflowIndicatorMixin { /// Creates a [RenderBox] that sizes itself to the child and modifies the /// [constraints] before passing it down to that child. - /// - /// The [alignment] and [clipBehavior] must not be null. RenderConstraintsTransformBox({ required super.alignment, required super.textDirection, @@ -877,8 +871,6 @@ class RenderConstraintsTransformBox extends RenderAligningShiftedBox with DebugO class RenderSizedOverflowBox extends RenderAligningShiftedBox { /// Creates a render box of a given size that lets its child overflow. /// - /// The [requestedSize] and [alignment] arguments must not be null. - /// /// The [textDirection] argument must not be null if the [alignment] is /// direction-sensitive. RenderSizedOverflowBox({ @@ -959,8 +951,6 @@ class RenderFractionallySizedOverflowBox extends RenderAligningShiftedBox { /// If non-null, the [widthFactor] and [heightFactor] arguments must be /// non-negative. /// - /// The [alignment] must not be null. - /// /// The [textDirection] must be non-null if the [alignment] is /// direction-sensitive. RenderFractionallySizedOverflowBox({ @@ -1313,8 +1303,6 @@ class RenderCustomSingleChildLayoutBox extends RenderShiftedBox { /// and the bottom of the box. class RenderBaseline extends RenderShiftedBox { /// Creates a [RenderBaseline] object. - /// - /// The [baseline] and [baselineType] arguments must not be null. RenderBaseline({ RenderBox? child, required double baseline, diff --git a/packages/flutter/lib/src/rendering/sliver.dart b/packages/flutter/lib/src/rendering/sliver.dart index 020d8a9abdf6f..8c197447ed21e 100644 --- a/packages/flutter/lib/src/rendering/sliver.dart +++ b/packages/flutter/lib/src/rendering/sliver.dart @@ -183,8 +183,6 @@ ScrollDirection applyGrowthDirectionToScrollDirection(ScrollDirection scrollDire /// offset. class SliverConstraints extends Constraints { /// Creates sliver constraints with the given information. - /// - /// All of the argument must not be null. const SliverConstraints({ required this.axisDirection, required this.growthDirection, @@ -620,8 +618,6 @@ class SliverGeometry with Diagnosticable { /// [paintExtent]. If the [hitTestExtent] argument is null, [hitTestExtent] /// defaults to the [paintExtent]. If [visible] is null, [visible] defaults to /// whether [paintExtent] is greater than zero. - /// - /// The other arguments must not be null. const SliverGeometry({ this.scrollExtent = 0.0, this.paintExtent = 0.0, @@ -997,8 +993,6 @@ class SliverHitTestResult extends HitTestResult { /// [AxisDirection] of the target sliver. class SliverHitTestEntry extends HitTestEntry<RenderSliver> { /// Creates a sliver hit test entry. - /// - /// The [mainAxisPosition] and [crossAxisPosition] arguments must not be null. SliverHitTestEntry( super.target, { required this.mainAxisPosition, diff --git a/packages/flutter/lib/src/rendering/sliver_fill.dart b/packages/flutter/lib/src/rendering/sliver_fill.dart index 29000545a5a11..b5f2763ca0778 100644 --- a/packages/flutter/lib/src/rendering/sliver_fill.dart +++ b/packages/flutter/lib/src/rendering/sliver_fill.dart @@ -27,8 +27,6 @@ import 'sliver_fixed_extent_list.dart'; class RenderSliverFillViewport extends RenderSliverFixedExtentBoxAdaptor { /// Creates a sliver that contains multiple box children that each fill the /// viewport. - /// - /// The [childManager] argument must not be null. RenderSliverFillViewport({ required super.childManager, double viewportFraction = 1.0, diff --git a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart index 28a9c92ba71ec..5b775f779abbe 100644 --- a/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart +++ b/packages/flutter/lib/src/rendering/sliver_fixed_extent_list.dart @@ -38,8 +38,6 @@ import 'sliver_multi_box_adaptor.dart'; abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAdaptor { /// Creates a sliver that contains multiple box children that have the same /// extent in the main axis. - /// - /// The [childManager] argument must not be null. RenderSliverFixedExtentBoxAdaptor({ required super.childManager, }); @@ -411,8 +409,6 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor { /// Creates a sliver that contains multiple box children that have a given /// extent in the main axis. - /// - /// The [childManager] argument must not be null. RenderSliverFixedExtentList({ required super.childManager, required double itemExtent, diff --git a/packages/flutter/lib/src/rendering/sliver_grid.dart b/packages/flutter/lib/src/rendering/sliver_grid.dart index 22fddd2178293..b2141dcd55cc6 100644 --- a/packages/flutter/lib/src/rendering/sliver_grid.dart +++ b/packages/flutter/lib/src/rendering/sliver_grid.dart @@ -165,8 +165,8 @@ abstract class SliverGridLayout { class SliverGridRegularTileLayout extends SliverGridLayout { /// Creates a layout that uses equally sized and spaced tiles. /// - /// All of the arguments must not be null and must not be negative. The - /// `crossAxisCount` argument must be greater than zero. + /// All of the arguments must not be negative. The `crossAxisCount` argument + /// must be greater than zero. const SliverGridRegularTileLayout({ required this.crossAxisCount, required this.mainAxisStride, @@ -336,7 +336,6 @@ class SliverGridDelegateWithFixedCrossAxisCount extends SliverGridDelegate { /// Creates a delegate that makes grid layouts with a fixed number of tiles in /// the cross axis. /// - /// All of the arguments except [mainAxisExtent] must not be null. /// The `mainAxisSpacing`, `mainAxisExtent` and `crossAxisSpacing` arguments /// must not be negative. The `crossAxisCount` and `childAspectRatio` /// arguments must be greater than zero. @@ -435,7 +434,6 @@ class SliverGridDelegateWithMaxCrossAxisExtent extends SliverGridDelegate { /// Creates a delegate that makes grid layouts with tiles that have a maximum /// cross-axis extent. /// - /// All of the arguments except [mainAxisExtent] must not be null. /// The [maxCrossAxisExtent], [mainAxisExtent], [mainAxisSpacing], /// and [crossAxisSpacing] arguments must not be negative. /// The [childAspectRatio] argument must be greater than zero. @@ -549,8 +547,6 @@ class SliverGridParentData extends SliverMultiBoxAdaptorParentData { class RenderSliverGrid extends RenderSliverMultiBoxAdaptor { /// Creates a sliver that contains multiple box children that whose size and /// position are determined by a delegate. - /// - /// The [childManager] and [gridDelegate] arguments must not be null. RenderSliverGrid({ required super.childManager, required SliverGridDelegate gridDelegate, diff --git a/packages/flutter/lib/src/rendering/sliver_list.dart b/packages/flutter/lib/src/rendering/sliver_list.dart index 8c5658e100659..e1fdedad1ca2f 100644 --- a/packages/flutter/lib/src/rendering/sliver_list.dart +++ b/packages/flutter/lib/src/rendering/sliver_list.dart @@ -36,8 +36,6 @@ import 'sliver_multi_box_adaptor.dart'; class RenderSliverList extends RenderSliverMultiBoxAdaptor { /// Creates a sliver that places multiple box children in a linear array along /// the main axis. - /// - /// The [childManager] argument must not be null. RenderSliverList({ required super.childManager, }); diff --git a/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart b/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart index 546087eac6188..76188fcbcaa74 100644 --- a/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart +++ b/packages/flutter/lib/src/rendering/sliver_multi_box_adaptor.dart @@ -184,8 +184,6 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver RenderSliverHelpers, RenderSliverWithKeepAliveMixin { /// Creates a sliver with multiple box children. - /// - /// The [childManager] argument must not be null. RenderSliverMultiBoxAdaptor({ required RenderSliverBoxChildManager childManager, }) : _childManager = childManager { diff --git a/packages/flutter/lib/src/rendering/sliver_padding.dart b/packages/flutter/lib/src/rendering/sliver_padding.dart index a245b79b461e7..c02ee71e81b3f 100644 --- a/packages/flutter/lib/src/rendering/sliver_padding.dart +++ b/packages/flutter/lib/src/rendering/sliver_padding.dart @@ -298,7 +298,7 @@ abstract class RenderSliverEdgeInsetsPadding extends RenderSliver with RenderObj class RenderSliverPadding extends RenderSliverEdgeInsetsPadding { /// Creates a render object that insets its child in a viewport. /// - /// The [padding] argument must not be null and must have non-negative insets. + /// The [padding] argument must have non-negative insets. RenderSliverPadding({ required EdgeInsetsGeometry padding, TextDirection? textDirection, diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart index 83ebbaaf447e1..5fe64c47b7c77 100644 --- a/packages/flutter/lib/src/rendering/stack.dart +++ b/packages/flutter/lib/src/rendering/stack.dart @@ -18,13 +18,9 @@ import 'object.dart'; /// container, this class has no width and height members. To determine the /// width or height of the rectangle, convert it to a [Rect] using [toRect()] /// (passing the container's own Rect), and then examine that object. -/// -/// The fields [left], [right], [bottom], and [top] must not be null. @immutable class RelativeRect { /// Creates a RelativeRect with the given values. - /// - /// The arguments must not be null. const RelativeRect.fromLTRB(this.left, this.top, this.right, this.bottom); /// Creates a RelativeRect from a Rect and a Size. The Rect (first argument) diff --git a/packages/flutter/lib/src/rendering/table.dart b/packages/flutter/lib/src/rendering/table.dart index 2cc86091ce050..2aa4658c3b583 100644 --- a/packages/flutter/lib/src/rendering/table.dart +++ b/packages/flutter/lib/src/rendering/table.dart @@ -132,8 +132,6 @@ class IntrinsicColumnWidth extends TableColumnWidth { /// This is the cheapest way to size a column. class FixedColumnWidth extends TableColumnWidth { /// Creates a column width based on a fixed number of logical pixels. - /// - /// The [value] argument must not be null. const FixedColumnWidth(this.value); /// The width the column should occupy in logical pixels. @@ -159,8 +157,6 @@ class FixedColumnWidth extends TableColumnWidth { class FractionColumnWidth extends TableColumnWidth { /// Creates a column width based on a fraction of the table's constraints' /// maxWidth. - /// - /// The [value] argument must not be null. const FractionColumnWidth(this.value); /// The fraction of the table's constraints' maxWidth that this column should @@ -197,8 +193,6 @@ class FractionColumnWidth extends TableColumnWidth { class FlexColumnWidth extends TableColumnWidth { /// Creates a column width based on a fraction of the remaining space once all /// the other columns have been laid out. - /// - /// The [value] argument must not be null. const FlexColumnWidth([this.value = 1.0]); /// The fraction of the remaining space once all the other columns have @@ -369,8 +363,6 @@ class RenderTable extends RenderBox { /// * `children` must either be null or contain lists of all the same length. /// if `children` is not null, then `rows` must be null. /// * [columnWidths] may be null, in which case it defaults to an empty map. - /// * [defaultColumnWidth] must not be null. - /// * [configuration] must not be null (but has a default value). RenderTable({ int? columns, int? rows, diff --git a/packages/flutter/lib/src/rendering/table_border.dart b/packages/flutter/lib/src/rendering/table_border.dart index 97f2c6b9e47bf..a5fbf5a94e845 100644 --- a/packages/flutter/lib/src/rendering/table_border.dart +++ b/packages/flutter/lib/src/rendering/table_border.dart @@ -204,9 +204,6 @@ class TableBorder { required Iterable<double> rows, required Iterable<double> columns, }) { - // properties can't be null - - // arguments can't be null assert(rows.isEmpty || (rows.first >= 0.0 && rows.last <= rect.height)); assert(columns.isEmpty || (columns.first >= 0.0 && columns.last <= rect.width)); diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index 66560c8521f48..4e04e9b64372b 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -386,7 +386,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { @@ -1138,7 +1138,6 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix /// in the viewport after it has been revealed. See [RevealedOffset.rect] /// for a full definition of this [Rect]. /// - /// The parameters `viewport` and `offset` are required and cannot be null. /// If `descendant` is null, this is a no-op and `rect` is returned. /// /// If both `descendant` and `rect` are null, null is returned because there is diff --git a/packages/flutter/lib/src/rendering/wrap.dart b/packages/flutter/lib/src/rendering/wrap.dart index 6df2519663566..d651add2c5daf 100644 --- a/packages/flutter/lib/src/rendering/wrap.dart +++ b/packages/flutter/lib/src/rendering/wrap.dart @@ -327,7 +327,7 @@ class RenderWrap extends RenderBox /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.none; set clipBehavior(Clip value) { From 07e70a40867ca9abb276c832e362a7e051d45576 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 19 Sep 2023 21:41:26 -0400 Subject: [PATCH 1346/1547] Manual roll Flutter Engine from a7af55c56aa6 to 0d7db40c27fd (7 revisions) (#135079) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/a7af55c56aa6...0d7db40c27fd 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from fe3568162721 to 1a8885b9e03c (6 revisions) (flutter/engine#46075) 2023-09-19 30870216+gaaclarke@users.noreply.github.com [Impeller] adds hardware gate for wide gamut (flutter/engine#46051) 2023-09-19 jacksongardner@google.com Properly transfer objects between the main thread and web worker. (flutter/engine#46061) 2023-09-19 30870216+gaaclarke@users.noreply.github.com Made the warning about downgrading wide gamut happen at the correct time (flutter/engine#46064) 2023-09-19 matanlurey@users.noreply.github.com Conform to clang_tidy in `client_wrapper` headers. (flutter/engine#46058) 2023-09-19 30870216+gaaclarke@users.noreply.github.com [Impeller] Adds unit test to make sure we can encode bgr101010xr to png. (flutter/engine#46007) 2023-09-19 ychris@google.com [ios] scenario test make parent view controller hide status bar (flutter/engine#46065) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4441743edb1a2..130e209009113 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a7af55c56aa63cc37da4ca334737cc992e041302 +0d7db40c27fdb39ec0866dba024904dd767193a0 From 6cf7ca01373bfd836f8a9a1018a848d84a61a973 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 19 Sep 2023 22:31:04 -0400 Subject: [PATCH 1347/1547] Roll Flutter Engine from a7af55c56aa6 to 5a924a9017d7 (10 revisions) (#135085) https://github.com/flutter/engine/compare/a7af55c56aa6...5a924a9017d7 2023-09-19 chinmaygarde@google.com [Impeller] Fix validation error about incorrect aspect on buffer to texture copies. (flutter/engine#46078) 2023-09-19 jonahwilliams@google.com [Impeller] Affinity adjustments for Vulkan backend. (flutter/engine#46063) 2023-09-19 chinmaygarde@google.com [Impeller] Fix validation errors in RendererTest. (flutter/engine#46076) 2023-09-19 skia-flutter-autoroll@skia.org Roll Skia from fe3568162721 to 1a8885b9e03c (6 revisions) (flutter/engine#46075) 2023-09-19 30870216+gaaclarke@users.noreply.github.com [Impeller] adds hardware gate for wide gamut (flutter/engine#46051) 2023-09-19 jacksongardner@google.com Properly transfer objects between the main thread and web worker. (flutter/engine#46061) 2023-09-19 30870216+gaaclarke@users.noreply.github.com Made the warning about downgrading wide gamut happen at the correct time (flutter/engine#46064) 2023-09-19 matanlurey@users.noreply.github.com Conform to clang_tidy in `client_wrapper` headers. (flutter/engine#46058) 2023-09-19 30870216+gaaclarke@users.noreply.github.com [Impeller] Adds unit test to make sure we can encode bgr101010xr to png. (flutter/engine#46007) 2023-09-19 ychris@google.com [ios] scenario test make parent view controller hide status bar (flutter/engine#46065) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 130e209009113..f5643d7a6a205 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0d7db40c27fdb39ec0866dba024904dd767193a0 +5a924a9017d764bc5c08d21a76f6ab52bba3a6f1 From f4b5fc18031e5ee5af89dffb004e66ebf3312a33 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Tue, 19 Sep 2023 22:43:57 -0400 Subject: [PATCH 1348/1547] Unpin url launcher (remake) (#134958) More up to date version of https://github.com/flutter/flutter/pull/133786. Fixes https://github.com/flutter/flutter/issues/111304 --- dev/a11y_assessments/pubspec.yaml | 4 +- dev/automated_tests/pubspec.yaml | 8 +- dev/benchmarks/complex_layout/pubspec.yaml | 6 +- dev/benchmarks/macrobenchmarks/pubspec.yaml | 6 +- dev/benchmarks/microbenchmarks/pubspec.yaml | 6 +- .../multiple_flutters/module/pubspec.yaml | 24 ++-- .../platform_channels_benchmarks/pubspec.yaml | 8 +- .../platform_views_layout/pubspec.yaml | 6 +- .../pubspec.yaml | 6 +- dev/benchmarks/test_apps/stocks/pubspec.yaml | 6 +- dev/bots/pubspec.yaml | 10 +- dev/conductor/core/pubspec.yaml | 8 +- dev/customer_testing/pubspec.yaml | 6 +- dev/devicelab/pubspec.yaml | 10 +- dev/forbidden_from_release_tests/pubspec.yaml | 6 +- .../abstract_method_smoke_test/pubspec.yaml | 4 +- .../pubspec.yaml | 8 +- .../android_semantics_testing/pubspec.yaml | 6 +- .../android_views/pubspec.yaml | 24 ++-- dev/integration_tests/channels/pubspec.yaml | 4 +- .../deferred_components_test/pubspec.yaml | 6 +- .../external_ui/pubspec.yaml | 6 +- dev/integration_tests/flavors/pubspec.yaml | 6 +- .../android/project-app.lockfile | 34 +++-- .../android/project-integration_test.lockfile | 5 + .../project-url_launcher_android.lockfile | 117 ++++++++---------- .../flutter_gallery/pubspec.yaml | 28 ++--- .../gradle_deprecated_settings/pubspec.yaml | 12 +- .../hybrid_android_views/pubspec.yaml | 24 ++-- .../flutterapp/pubspec.yaml | 6 +- .../ios_app_with_extensions/pubspec.yaml | 6 +- .../ios_platform_view_tests/pubspec.yaml | 6 +- .../non_nullable/pubspec.yaml | 6 +- .../platform_interaction/pubspec.yaml | 6 +- .../release_smoke_test/pubspec.yaml | 4 +- .../spell_check/pubspec.yaml | 6 +- dev/integration_tests/ui/pubspec.yaml | 6 +- dev/integration_tests/web/pubspec.yaml | 4 +- .../web_compile_tests/pubspec.yaml | 4 +- .../web_e2e_tests/pubspec.yaml | 8 +- .../wide_gamut_test/pubspec.yaml | 4 +- .../windows_startup_test/pubspec.yaml | 6 +- dev/manual_tests/pubspec.yaml | 4 +- dev/tools/gen_defaults/pubspec.yaml | 6 +- dev/tools/gen_keycodes/pubspec.yaml | 8 +- dev/tools/pubspec.yaml | 8 +- dev/tools/vitool/pubspec.yaml | 4 +- dev/tracing_tests/pubspec.yaml | 4 +- examples/api/pubspec.yaml | 10 +- examples/flutter_view/pubspec.yaml | 4 +- examples/hello_world/pubspec.yaml | 6 +- examples/image_list/pubspec.yaml | 6 +- examples/layers/pubspec.yaml | 4 +- examples/platform_channel/pubspec.yaml | 6 +- examples/platform_channel_swift/pubspec.yaml | 6 +- examples/platform_view/pubspec.yaml | 4 +- examples/splash/pubspec.yaml | 4 +- examples/texture/pubspec.yaml | 6 +- packages/flutter/pubspec.yaml | 8 +- packages/flutter/test_private/pubspec.yaml | 6 +- .../flutter/test_private/test/pubspec.yaml | 6 +- packages/flutter_driver/pubspec.yaml | 8 +- packages/flutter_goldens/pubspec.yaml | 6 +- packages/flutter_goldens_client/pubspec.yaml | 6 +- packages/flutter_localizations/pubspec.yaml | 4 +- packages/flutter_test/pubspec.yaml | 4 +- .../lib/src/commands/update_packages.dart | 2 - packages/flutter_tools/pubspec.yaml | 14 +-- .../general.shard/update_packages_test.dart | 1 - packages/flutter_web_plugins/pubspec.yaml | 4 +- .../pubspec.yaml | 8 +- .../integration_test/example/pubspec.yaml | 8 +- .../integration_test_macos/pubspec.yaml | 4 +- packages/integration_test/pubspec.yaml | 4 +- 74 files changed, 329 insertions(+), 330 deletions(-) diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml index 81dc3007cc185..066d34ee57f7f 100644 --- a/dev/a11y_assessments/pubspec.yaml +++ b/dev/a11y_assessments/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -35,4 +35,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b244 +# PUBSPEC CHECKSUM: 1e6b diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index 7983b4afc9d05..c2344ee156556 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter integration_test: sdk: flutter - platform: 3.1.1 + platform: 3.1.2 test: 1.24.6 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -37,7 +37,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -64,7 +64,7 @@ dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -72,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: e054 +# PUBSPEC CHECKSUM: a37d diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index a694b759c3a3c..04f16921cc9a2 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,7 +74,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -83,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 0c2c +# PUBSPEC CHECKSUM: 4654 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index c01a06ccc1f38..640e44725ab9e 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -75,7 +75,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -210,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 0c2c +# PUBSPEC CHECKSUM: 4654 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index dab505297d934..10ae4b2fcd256 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -5,7 +5,7 @@ environment: sdk: '>=3.2.0-0 <4.0.0' dependencies: - meta: 1.9.1 + meta: 1.10.0 flutter: sdk: flutter flutter_test: @@ -65,7 +65,7 @@ dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -137,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 5ca3 +# PUBSPEC CHECKSUM: 46cb diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 57c87babf7661..9da448d2581e9 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 google_fonts: 4.0.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -21,16 +21,16 @@ dependencies: http: 0.13.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_android: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_linux: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_platform_interface: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_windows: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -38,7 +38,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: cfcb +# PUBSPEC CHECKSUM: 90fc diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index 1be876ebbbceb..f132da5b869c0 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: sdk: flutter microbenchmarks: path: ../microbenchmarks - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,7 +39,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,7 +66,7 @@ dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a38e +# PUBSPEC CHECKSUM: 3cb7 diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 602a685f3fa9d..4cedf138c5976 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,7 +72,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 0c2c +# PUBSPEC CHECKSUM: 4654 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 90323063f92c3..c6919442ba8c4 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -23,7 +23,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,7 +72,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 0c2c +# PUBSPEC CHECKSUM: 4654 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 90f815e22a98f..66b2524056d27 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -70,10 +70,10 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b44e +# PUBSPEC CHECKSUM: 3376 diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 42892499fa465..203c8782fa936 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -12,9 +12,9 @@ dependencies: flutter_devicelab: path: ../devicelab http_parser: 4.0.2 - meta: 1.9.1 + meta: 1.10.0 path: 1.8.3 - platform: 3.1.1 + platform: 3.1.2 process: 4.2.4 test: 1.24.6 @@ -41,7 +41,7 @@ dependencies: json_annotation: 4.8.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - metrics_center: 1.0.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + metrics_center: 1.0.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,11 +67,11 @@ dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xml: 6.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: b1a4 +# PUBSPEC CHECKSUM: d5ce diff --git a/dev/conductor/core/pubspec.yaml b/dev/conductor/core/pubspec.yaml index d5cfab651b770..0822a15a429da 100644 --- a/dev/conductor/core/pubspec.yaml +++ b/dev/conductor/core/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: args: 2.4.2 http: 0.13.6 intl: 0.18.1 - meta: 1.9.1 + meta: 1.10.0 path: 1.8.3 process: 4.2.4 protobuf: 3.1.0 @@ -23,7 +23,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" fixnum: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -62,7 +62,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 9f31 +# PUBSPEC CHECKSUM: 815a diff --git a/dev/customer_testing/pubspec.yaml b/dev/customer_testing/pubspec.yaml index ffafd00e3ab7a..62f474d53c273 100644 --- a/dev/customer_testing/pubspec.yaml +++ b/dev/customer_testing/pubspec.yaml @@ -8,7 +8,7 @@ dependencies: args: 2.4.2 path: 1.8.3 glob: 2.1.2 - meta: 1.9.1 + meta: 1.10.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +52,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 727c +# PUBSPEC CHECKSUM: 80a4 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 63be4031993d3..09083ee59f5fb 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: file: 6.1.4 http: 0.13.6 logging: 1.2.0 - meta: 1.9.1 - metrics_center: 1.0.11 + meta: 1.10.0 + metrics_center: 1.0.12 path: 1.8.3 - platform: 3.1.1 + platform: 3.1.2 process: 4.2.4 pubspec_parse: 1.2.3 shelf: 1.4.1 @@ -22,7 +22,7 @@ dependencies: stack_trace: 1.11.1 vm_service: 11.10.0 web: 0.1.4-beta - webkit_inspection_protocol: 1.2.0 + webkit_inspection_protocol: 1.2.1 xml: 6.4.2 _discoveryapis_commons: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1712 +# PUBSPEC CHECKSUM: 163c diff --git a/dev/forbidden_from_release_tests/pubspec.yaml b/dev/forbidden_from_release_tests/pubspec.yaml index 6244f6b3ce944..cc3e527d1fd21 100644 --- a/dev/forbidden_from_release_tests/pubspec.yaml +++ b/dev/forbidden_from_release_tests/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: vm_snapshot_analysis: 0.7.6 collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: d76b +# PUBSPEC CHECKSUM: 4c93 diff --git a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml index 6105b6e5d1239..243ee9149538c 100644 --- a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml +++ b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml @@ -13,11 +13,11 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 16bf +# PUBSPEC CHECKSUM: 1ce6 diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index 824bef6aa9919..47823636f5174 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -25,14 +25,14 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 battery_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -96,4 +96,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 8917 +# PUBSPEC CHECKSUM: 2240 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index ffaa0525a1873..9f11efaf13a91 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,10 +60,10 @@ dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 8f4c +# PUBSPEC CHECKSUM: ca74 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 5abef88592677..bc5393790f8b8 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - path_provider: 2.1.0 + path_provider: 2.1.1 # This made non-transitive to allow exact pinning # https://github.com/flutter/flutter/issues/116376 - path_provider_android: 2.1.0 + path_provider_android: 2.2.0 collection: 1.18.0 assets_for_android_views: git: @@ -29,14 +29,14 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_linux: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_platform_interface: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_windows: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -49,7 +49,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -86,10 +86,10 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ef80 +# PUBSPEC CHECKSUM: 5bb1 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index fdaca2cd1d168..3541ec8be7c21 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -43,4 +43,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4b5f +# PUBSPEC CHECKSUM: 3886 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 41f8fa7057cbd..9161c6cfa7c53 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,7 +67,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -80,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index fadfda2ad9135..6c61163b1a733 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,10 +59,10 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: c7d4 +# PUBSPEC CHECKSUM: 53fc diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 295014a784bc4..27516a59cf3e8 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,7 +61,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/dev/integration_tests/flutter_gallery/android/project-app.lockfile b/dev/integration_tests/flutter_gallery/android/project-app.lockfile index 01747922649a5..c5040659c70d5 100644 --- a/dev/integration_tests/flutter_gallery/android/project-app.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-app.lockfile @@ -2,19 +2,28 @@ # Manual edits can break the build and are not advised. # This file is expected to be part of source control. androidx.activity:activity:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation-experimental:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation-experimental:1.1.0=debugAndroidTestCompileClasspath +androidx.annotation:annotation-experimental:1.3.0=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation-jvm:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.arch.core:core-common:2.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.arch.core:core-runtime:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.arch.core:core-runtime:2.0.0=debugAndroidTestCompileClasspath +androidx.arch.core:core-runtime:2.1.0=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.browser:browser:1.5.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.collection:collection:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.core:core:1.6.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.concurrent:concurrent-futures:1.0.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.core:core:1.10.1=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.core:core:1.6.0=debugAndroidTestCompileClasspath androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.fragment:fragment:1.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.interpolator:interpolator:1.0.0=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-common-java8:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-common:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.lifecycle:lifecycle-common:2.2.0=debugAndroidTestCompileClasspath +androidx.lifecycle:lifecycle-common:2.3.1=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-livedata-core:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-livedata:2.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath +androidx.lifecycle:lifecycle-runtime:2.3.1=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-viewmodel:2.1.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.multidex:multidex-instrumentation:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath @@ -56,14 +65,17 @@ org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-bom:1.8.22=debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22=debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-analysis:9.1=androidJacocoAnt org.ow2.asm:asm-commons:9.1=androidJacocoAnt org.ow2.asm:asm-tree:9.1=androidJacocoAnt diff --git a/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile b/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile index f45da3d417cf0..1326b8773fd76 100644 --- a/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-integration_test.lockfile @@ -37,6 +37,8 @@ com.google.j2objc:j2objc-annotations:1.3=debugAndroidTestCompileClasspath,debugA com.squareup:javawriter:2.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath javax.inject:javax.inject:1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath junit:junit:4.12=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.12.22=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy:1.12.22=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath net.sf.kxml:kxml2:2.3.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.checkerframework:checker-compat-qual:2.5.5=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.codehaus.mojo:animal-sniffer-annotations:1.18=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -55,6 +57,9 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileCl org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.mockito:mockito-core:5.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.mockito:mockito-inline:5.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.objenesis:objenesis:3.3=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-analysis:9.1=androidJacocoAnt org.ow2.asm:asm-commons:9.1=androidJacocoAnt org.ow2.asm:asm-tree:9.1=androidJacocoAnt diff --git a/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile b/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile index 6831d08f57f4a..796a30231af53 100644 --- a/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile +++ b/dev/integration_tests/flutter_gallery/android/project-url_launcher_android.lockfile @@ -2,104 +2,89 @@ # Manual edits can break the build and are not advised. # This file is expected to be part of source control. androidx.activity:activity:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation-experimental:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.annotation:annotation:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation-experimental:1.3.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation-jvm:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.annotation:annotation:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.arch.core:core-common:2.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.arch.core:core-runtime:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.arch.core:core-runtime:2.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.browser:browser:1.5.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.collection:collection:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.core:core:1.6.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.concurrent:concurrent-futures:1.0.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.core:core:1.10.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.fragment:fragment:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.interpolator:interpolator:1.0.0=debugAndroidTestRuntimeClasspath,debugRuntimeClasspath,debugUnitTestRuntimeClasspath,profileRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseRuntimeClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-common-java8:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.lifecycle:lifecycle-common:2.3.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-livedata-core:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-livedata:2.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.lifecycle:lifecycle-runtime:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.lifecycle:lifecycle-runtime:2.3.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.lifecycle:lifecycle-viewmodel:2.1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.savedstate:savedstate:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test.espresso:espresso-idling-resource:3.5.1=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +androidx.test:annotation:1.0.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.test:core:1.0.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -androidx.test:monitor:1.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +androidx.test:monitor:1.6.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.tracing:tracing:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window-java:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath androidx.window:window:1.0.0-beta04=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -backport-util-concurrent:backport-util-concurrent:3.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -classworlds:classworlds:1.1-alpha-2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.almworks.sqlite4java:sqlite4java:0.282=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.android.apps.common.testing.accessibility.framework:accessibility-test-framework:2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.auto.service:auto-service:1.0-rc4=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.auto:auto-common:0.8=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.almworks.sqlite4java:sqlite4java:1.0.392=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.auto.value:auto-value-annotations:1.10.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.code.findbugs:jsr305:3.0.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.errorprone:error_prone_annotations:2.2.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.18.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath com.google.guava:failureaccess:1.0.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.guava:guava:27.0.1-jre=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:guava:31.1-jre=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.guava:listenablefuture:1.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.j2objc:j2objc-annotations:1.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.google.protobuf:protobuf-java:2.6.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -com.ibm.icu:icu4j:53.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.google.j2objc:j2objc-annotations:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +com.ibm.icu:icu4j:72.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath javax.annotation:javax.annotation-api:1.3.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath javax.inject:javax.inject:1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -junit:junit:4.12=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -nekohtml:nekohtml:1.9.6.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -nekohtml:xercesMinimal:1.9.6.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.ant:ant-launcher:1.8.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.ant:ant:1.8.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-file:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-http-lightweight:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-http-shared:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven.wagon:wagon-provider-api:1.0-beta-6=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-ant-tasks:2.1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-artifact-manager:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-artifact:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-error-diagnostics:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-model:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-plugin-registry:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-profile:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-project:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-repository-metadata:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.apache.maven:maven-settings:2.2.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.bouncycastle:bcprov-jdk15on:1.52=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.checkerframework:checker-qual:2.5.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.17=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.plexus:plexus-container-default:1.0-alpha-9-stable-1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.plexus:plexus-interpolation:1.11=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.codehaus.plexus:plexus-utils:1.5.15=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +junit:junit:4.13.2=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.12.22=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +net.bytebuddy:byte-buddy:1.12.22=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.bouncycastle:bcprov-jdk18on:1.72=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.checkerframework:checker-qual:3.12.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.conscrypt:conscrypt-openjdk-uber:2.5.2=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.hamcrest:hamcrest-core:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.hamcrest:hamcrest-library:1.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.30=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-bom:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.mockito:mockito-core:1.10.19=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.objenesis:objenesis:2.1=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm-analysis:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.mockito:mockito-core:5.1.1=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.objenesis:objenesis:3.3=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-analysis:9.1=androidJacocoAnt -org.ow2.asm:asm-commons:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm-analysis:9.5=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-commons:9.1=androidJacocoAnt -org.ow2.asm:asm-tree:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm-commons:9.5=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm-tree:9.1=androidJacocoAnt -org.ow2.asm:asm-util:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.ow2.asm:asm:7.0=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm-tree:9.5=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm-util:9.5=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.ow2.asm:asm:9.1=androidJacocoAnt -org.robolectric:annotations:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:junit:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:pluginapi:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:plugins-maven-dependency-resolver:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:resources:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:robolectric:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:sandbox:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:shadowapi:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:shadows-framework:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:utils-reflector:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath -org.robolectric:utils:4.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.ow2.asm:asm:9.5=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:annotations:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:junit:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:nativeruntime-dist-compat:1.0.1=debugUnitTestRuntimeClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:nativeruntime:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:pluginapi:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:plugins-maven-dependency-resolver:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:resources:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:robolectric:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:sandbox:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:shadowapi:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:shadows-framework:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:utils-reflector:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath +org.robolectric:utils:4.10.3=debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath empty=androidApis,androidJdkImage,androidTestUtil,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAnnotationProcessorClasspath,debugUnitTestAnnotationProcessorClasspath,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileUnitTestAnnotationProcessorClasspath,releaseAnnotationProcessorClasspath,releaseUnitTestAnnotationProcessorClasspath diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 445a0a32bb614..55bbdf203f514 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -11,10 +11,10 @@ dependencies: intl: 0.18.1 connectivity: 3.0.6 string_scanner: 1.2.0 - url_launcher: 6.1.12 + url_launcher: 6.1.14 # This is listed as direct so it can be manually pinned - url_launcher_android: 6.0.17 - cupertino_icons: 1.0.5 + url_launcher_android: 6.1.0 + cupertino_icons: 1.0.6 video_player: 2.2.11 scoped_model: git: @@ -35,17 +35,17 @@ dependencies: device_info_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" html: 0.15.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_ios: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_linux: 3.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_macos: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_platform_interface: 2.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_web: 2.0.18 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - url_launcher_windows: 3.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_ios: 6.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_linux: 3.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_macos: 3.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_web: 2.0.20 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + url_launcher_windows: 3.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_platform_interface: 5.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_web: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -83,7 +83,7 @@ dev_dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -103,7 +103,7 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 6978 +# PUBSPEC CHECKSUM: 656d diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index f2d670c9424c5..4d490f1bd833b 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -11,20 +11,20 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_web: 0.3.2+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_web: 0.3.2+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" cross_file: 0.3.3+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - flutter_plugin_android_lifecycle: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + flutter_plugin_android_lifecycle: 2.0.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" quiver: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fb0d +# PUBSPEC CHECKSUM: ac38 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index ea6f2bc1f0b84..ba5fc8b5930a6 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: sdk: flutter flutter_driver: sdk: flutter - path_provider: 2.1.0 + path_provider: 2.1.1 collection: 1.18.0 assets_for_android_views: git: @@ -26,15 +26,15 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_android: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_foundation: 2.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_linux: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_platform_interface: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - path_provider_windows: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_android: 2.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_foundation: 2.3.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_linux: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_platform_interface: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + path_provider_windows: 2.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -47,7 +47,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - xdg_directories: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -84,10 +84,10 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ef80 +# PUBSPEC CHECKSUM: 5bb1 diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index cb719011ebb1d..d69d5d2e79676 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -22,12 +22,12 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -99,4 +99,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: c5eb +# PUBSPEC CHECKSUM: 5314 diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index bcffc6b087ece..a822bde851b20 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -26,8 +26,8 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" device_info_platform_interface: 2.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - plugin_platform_interface: 2.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -91,4 +91,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 5a72 +# PUBSPEC CHECKSUM: 969a diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 146809226c998..b4cb2793ac27d 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,7 +67,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -77,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index 74984d2002f3f..be9b6e89abe95 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -10,12 +10,12 @@ environment: dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: c5eb +# PUBSPEC CHECKSUM: 5314 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index a842b975026e6..8c8ccb30b829f 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,10 +59,10 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: c7d4 +# PUBSPEC CHECKSUM: 53fc diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index e250a1ebe52cc..58110c605b538 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1e26 +# PUBSPEC CHECKSUM: 594d diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index cf81a0a1c533b..e7369ca35bbf0 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -32,12 +32,12 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 14cd +# PUBSPEC CHECKSUM: 97f5 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index f5b3d7876e39a..3b5e905a944db 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -60,7 +60,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -76,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index 9b90e3aaa2b42..d386e66d9cf6b 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -17,8 +17,8 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 16bf +# PUBSPEC CHECKSUM: 1ce6 diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index f9e9ed8d4131b..a62e79a88ac0d 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -9,8 +9,8 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 16bf +# PUBSPEC CHECKSUM: 1ce6 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index b48834f447a60..1ccd57d92125d 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -67,7 +67,7 @@ dev_dependencies: mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -81,7 +81,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: fb77 +# PUBSPEC CHECKSUM: 84a0 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index 7177e44a09df8..8ba51de49d7ac 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -41,4 +41,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1e26 +# PUBSPEC CHECKSUM: 594d diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 15424e16b06c5..74fa742aa3c54 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -59,7 +59,7 @@ dependencies: web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c7d4 +# PUBSPEC CHECKSUM: 53fc diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 8d552b3a502fb..25c005d20ccb1 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: b244 +# PUBSPEC CHECKSUM: 1e6b diff --git a/dev/tools/gen_defaults/pubspec.yaml b/dev/tools/gen_defaults/pubspec.yaml index 77c781054e3fe..15656eda02485 100644 --- a/dev/tools/gen_defaults/pubspec.yaml +++ b/dev/tools/gen_defaults/pubspec.yaml @@ -29,7 +29,7 @@ dev_dependencies: js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -52,7 +52,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 727c +# PUBSPEC CHECKSUM: 80a4 diff --git a/dev/tools/gen_keycodes/pubspec.yaml b/dev/tools/gen_keycodes/pubspec.yaml index 049ada19f7815..3e6a67130af6f 100644 --- a/dev/tools/gen_keycodes/pubspec.yaml +++ b/dev/tools/gen_keycodes/pubspec.yaml @@ -7,9 +7,9 @@ environment: dependencies: args: 2.4.2 http: 0.13.6 - meta: 1.9.1 + meta: 1.10.0 path: 1.8.3 - platform: 3.1.1 + platform: 3.1.2 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,7 +54,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 2974 +# PUBSPEC CHECKSUM: 9e9d diff --git a/dev/tools/pubspec.yaml b/dev/tools/pubspec.yaml index 95c68bfe19c74..e3a4cac9649f2 100644 --- a/dev/tools/pubspec.yaml +++ b/dev/tools/pubspec.yaml @@ -9,7 +9,7 @@ dependencies: args: 2.4.2 http: 0.13.6 intl: 0.18.1 - meta: 1.9.1 + meta: 1.10.0 path: 1.8.3 process: 4.2.4 pub_semver: 2.1.4 @@ -20,7 +20,7 @@ dependencies: crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -58,7 +58,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: fc8e +# PUBSPEC CHECKSUM: 64b7 diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 18ffb4f4b611e..7187ed5184deb 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -37,4 +37,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 81ed +# PUBSPEC CHECKSUM: 7915 diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 7ced60bfcfec4..1a5404ab382ee 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1e26 +# PUBSPEC CHECKSUM: 594d diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 630181e7f7a6f..b4a107138b1e1 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -11,14 +11,14 @@ environment: flutter: ">=2.5.0-6.0.pre.30 <3.0.0" dependencies: - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 flutter: sdk: flutter characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,7 +61,7 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,10 +84,10 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: cf7b +# PUBSPEC CHECKSUM: 91a5 diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index 68e8b23a86289..acfd7e7217ae8 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +20,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 16bf +# PUBSPEC CHECKSUM: 1ce6 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 3cf792dae6753..906174575b076 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,7 +65,7 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index e3fab334ea232..d59ff492fc5a9 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -12,12 +12,12 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -54,4 +54,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: c5eb +# PUBSPEC CHECKSUM: 5314 diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index e4c2f9d8740d8..6d678bcaab518 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,4 +36,4 @@ flutter: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: b244 +# PUBSPEC CHECKSUM: 1e6b diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 20e34a60266cc..7d9eb3c0233c2 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,10 +65,10 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 7f70178476f82..6e9b295877fa9 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,10 +65,10 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0291 +# PUBSPEC CHECKSUM: 07b9 diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index 663dc5ae94243..c4df76cc6ac8e 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -20,4 +20,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 16bf +# PUBSPEC CHECKSUM: 1ce6 diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 618f6eed651c3..7679969b28e96 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -31,4 +31,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b244 +# PUBSPEC CHECKSUM: 1e6b diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index d2b513e317af9..474b8aa35806c 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -61,7 +61,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8f4c +# PUBSPEC CHECKSUM: ca74 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index b5e962b866616..f6a7f8b95660b 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: characters: 1.3.0 collection: 1.18.0 material_color_utilities: 0.5.0 - meta: 1.9.1 + meta: 1.10.0 vector_math: 2.1.4 web: 0.1.4-beta sky_engine: @@ -49,7 +49,7 @@ dev_dependencies: node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -71,7 +71,7 @@ dev_dependencies: vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 956b +# PUBSPEC CHECKSUM: 8694 diff --git a/packages/flutter/test_private/pubspec.yaml b/packages/flutter/test_private/pubspec.yaml index b2d9b52ec1af2..96d98b1cda51d 100644 --- a/packages/flutter/test_private/pubspec.yaml +++ b/packages/flutter/test_private/pubspec.yaml @@ -6,7 +6,7 @@ environment: dependencies: # To update these, use "flutter update-packages --force-upgrade". - meta: 1.9.1 + meta: 1.10.0 path: 1.8.3 process: 4.2.4 process_runner: 4.1.2 @@ -15,6 +15,6 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 6090 +# PUBSPEC CHECKSUM: bdb8 diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 17b80ecc7a591..6006fd9f1dc0a 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: sdk: flutter characters: 1.3.0 collection: 1.18.0 - meta: 1.9.1 + meta: 1.10.0 vector_math: 2.1.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,7 +36,7 @@ dev_dependencies: fake_async: 1.3.1 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5840 +# PUBSPEC CHECKSUM: ca68 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index b85d1c4ca4d25..fcca59407fd59 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: fuchsia_remote_debug_protocol: sdk: flutter path: 1.8.3 - meta: 1.9.1 + meta: 1.10.0 vm_service: 11.10.0 webdriver: 3.0.2 @@ -25,7 +25,7 @@ dependencies: collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -69,7 +69,7 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5599 +# PUBSPEC CHECKSUM: 22c2 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index f76185c6d2127..da9f2a0df08de 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -12,8 +12,8 @@ dependencies: flutter_goldens_client: path: ../flutter_goldens_client file: 6.1.4 - meta: 1.9.1 - platform: 3.1.1 + meta: 1.10.0 + platform: 3.1.2 process: 4.2.4 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -36,4 +36,4 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a2a1 +# PUBSPEC CHECKSUM: 4cc9 diff --git a/packages/flutter_goldens_client/pubspec.yaml b/packages/flutter_goldens_client/pubspec.yaml index dea9d647002e6..e1254b0c6796f 100644 --- a/packages/flutter_goldens_client/pubspec.yaml +++ b/packages/flutter_goldens_client/pubspec.yaml @@ -7,11 +7,11 @@ dependencies: # To update these, use "flutter update-packages --force-upgrade". crypto: 3.0.3 file: 6.1.4 - platform: 3.1.1 + platform: 3.1.2 process: 4.2.4 collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -19,4 +19,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 510c +# PUBSPEC CHECKSUM: 1c34 diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index 2c2db43d59b59..c512a2b6b9ebb 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 677e +# PUBSPEC CHECKSUM: 47a5 diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index 0b726abf67c93..b46cec8720fd4 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ dependencies: dev_dependencies: file: 6.1.4 -# PUBSPEC CHECKSUM: 5d38 +# PUBSPEC CHECKSUM: b05f diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index 4a060dc728c96..e482057c56fa7 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -34,8 +34,6 @@ const Map<String, String> kManuallyPinnedDependencies = <String, String>{ 'video_player': '2.2.11', // Keep pinned to latest until 1.0.0. 'material_color_utilities': '0.5.0', - // https://github.com/flutter/flutter/issues/111304 - 'url_launcher_android': '6.0.17', // https://github.com/flutter/flutter/issues/115660 'archive': '3.3.2', }; diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 7993203176de3..7f899d5363c7b 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: args: 2.4.2 browser_launcher: 1.1.1 dds: 2.9.4 - dwds: 20.0.1 + dwds: 21.0.0 completion: 1.0.1 coverage: 1.6.3 crypto: 3.0.3 @@ -20,8 +20,8 @@ dependencies: html: 0.15.4 http: 0.13.6 intl: 0.18.1 - meta: 1.9.1 - multicast_dns: 0.3.2+3 + meta: 1.10.0 + multicast_dns: 0.3.2+4 mustache_template: 2.0.0 package_config: 2.1.0 process: 4.2.4 @@ -29,7 +29,7 @@ dependencies: stack_trace: 1.11.1 usage: 4.1.1 webdriver: 3.0.2 - webkit_inspection_protocol: 1.2.0 + webkit_inspection_protocol: 1.2.1 xml: 6.4.2 yaml: 3.1.2 native_stack_traces: 0.5.6 @@ -63,7 +63,7 @@ dependencies: vm_service: 11.10.0 - standard_message_codec: 0.0.1+3 + standard_message_codec: 0.0.1+4 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -84,7 +84,7 @@ dependencies: json_rpc_2: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" shelf_proxy: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -112,4 +112,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 7f4e +# PUBSPEC CHECKSUM: f179 diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index 9741eb48d11e4..7b2ecd82b064e 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -106,7 +106,6 @@ void main() { 'flutter_template_images', 'video_player', 'material_color_utilities', - 'url_launcher_android', 'archive', ]), ); diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index ef2ebb0e07a35..02babffc73467 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -33,4 +33,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b244 +# PUBSPEC CHECKSUM: 1e6b diff --git a/packages/fuchsia_remote_debug_protocol/pubspec.yaml b/packages/fuchsia_remote_debug_protocol/pubspec.yaml index c73ea6b80c23e..a6e3d721fbce5 100644 --- a/packages/fuchsia_remote_debug_protocol/pubspec.yaml +++ b/packages/fuchsia_remote_debug_protocol/pubspec.yaml @@ -11,9 +11,9 @@ dependencies: vm_service: 11.10.0 file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - platform: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: test: 1.24.6 @@ -56,11 +56,11 @@ dev_dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 4e84 +# PUBSPEC CHECKSUM: a1ad diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index 9245d22fa4656..dfe4569d34ded 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -10,12 +10,12 @@ dependencies: flutter: sdk: flutter - cupertino_icons: 1.0.5 + cupertino_icons: 1.0.6 characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -78,10 +78,10 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2b00 +# PUBSPEC CHECKSUM: 6329 diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index e2a8860af37b7..536748fd1ab43 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -19,11 +19,11 @@ dependencies: characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" collection: 1.18.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: 8f86 +# PUBSPEC CHECKSUM: 7aad diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index 4fe03e19a69b5..ed9f2109b1418 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -24,7 +24,7 @@ dependencies: file: 6.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - meta: 1.9.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" source_span: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stack_trace: 1.11.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 4b5f +# PUBSPEC CHECKSUM: 3886 From a1e49be25b42d8bf217db4744e9ff8c8b6ebe2a5 Mon Sep 17 00:00:00 2001 From: Greg Spencer <gspencergoog@users.noreply.github.com> Date: Tue, 19 Sep 2023 21:20:49 -0700 Subject: [PATCH 1349/1547] Remove 'must be non-null' and 'must not be null' comments from material. (#134991) ## Description This removes all of the comments that are of the form "so-and-so (must not be null|can ?not be null|must be non-null)" from the cases where those values are defines as non-nullable values. This PR removes them from the material library. This was done by hand, since it really didn't lend itself to scripting, so it needs to be more than just spot-checked, I think. I was careful to leave any comment that referred to parameters that were nullable, but I may have missed some. In addition to being no longer relevant after null safety has been made the default, these comments were largely fragile, in that it was easy for them to get out of date, and not be accurate anymore anyhow. This did create a number of constructor comments which basically say "Creates a [Foo].", but I don't really know how to avoid that in a large scale change, since there's not much you can really say in a lot of cases. I think we might consider some leniency for constructors to the "Comment must be meaningful" style guidance (which we de facto have already, since there are a bunch of these). ## Related PRs - https://github.com/flutter/flutter/pull/134984 - https://github.com/flutter/flutter/pull/134992 - https://github.com/flutter/flutter/pull/134993 - https://github.com/flutter/flutter/pull/134994 ## Tests - Documentation only change. --- .../animated_icons/animated_icons.dart | 4 +-- packages/flutter/lib/src/material/app.dart | 2 -- .../flutter/lib/src/material/app_bar.dart | 3 --- .../lib/src/material/app_bar_theme.dart | 2 -- packages/flutter/lib/src/material/banner.dart | 5 ++-- .../lib/src/material/banner_theme.dart | 2 -- .../src/material/bottom_app_bar_theme.dart | 2 -- .../src/material/bottom_navigation_bar.dart | 6 ++--- .../material/bottom_navigation_bar_theme.dart | 4 --- .../lib/src/material/bottom_sheet.dart | 2 -- packages/flutter/lib/src/material/button.dart | 9 +++---- .../lib/src/material/button_bar_theme.dart | 2 -- .../lib/src/material/button_style_button.dart | 2 +- .../lib/src/material/button_theme.dart | 9 +------ .../src/material/calendar_date_picker.dart | 3 +-- packages/flutter/lib/src/material/card.dart | 3 +-- .../flutter/lib/src/material/card_theme.dart | 2 -- .../flutter/lib/src/material/checkbox.dart | 4 +-- .../lib/src/material/checkbox_list_tile.dart | 2 -- packages/flutter/lib/src/material/chip.dart | 13 ++++------ .../flutter/lib/src/material/chip_theme.dart | 4 --- .../flutter/lib/src/material/choice_chip.dart | 3 +-- .../flutter/lib/src/material/data_table.dart | 15 +++-------- .../lib/src/material/data_table_theme.dart | 4 --- .../flutter/lib/src/material/date_picker.dart | 10 +++----- packages/flutter/lib/src/material/dialog.dart | 4 +-- .../lib/src/material/dialog_theme.dart | 2 -- .../lib/src/material/divider_theme.dart | 2 -- packages/flutter/lib/src/material/drawer.dart | 2 +- .../flutter/lib/src/material/dropdown.dart | 13 ++-------- .../lib/src/material/dropdown_menu.dart | 2 -- .../lib/src/material/elevated_button.dart | 4 --- .../src/material/elevated_button_theme.dart | 2 -- .../flutter/lib/src/material/expand_icon.dart | 4 +-- .../lib/src/material/expansion_panel.dart | 14 +++-------- .../src/material/expansion_tile_theme.dart | 2 -- .../lib/src/material/filled_button.dart | 8 ------ .../lib/src/material/filled_button_theme.dart | 2 -- .../lib/src/material/flexible_space_bar.dart | 3 --- .../src/material/floating_action_button.dart | 24 +++++++----------- .../floating_action_button_location.dart | 4 +-- .../flutter/lib/src/material/icon_button.dart | 4 --- .../lib/src/material/icon_button_theme.dart | 2 -- .../lib/src/material/ink_decoration.dart | 5 ++-- .../flutter/lib/src/material/ink_well.dart | 8 ------ .../lib/src/material/input_border.dart | 17 ++++++------- .../flutter/lib/src/material/input_chip.dart | 6 ++--- .../input_date_picker_form_field.dart | 3 --- .../lib/src/material/input_decorator.dart | 7 ------ .../lib/src/material/list_tile_theme.dart | 2 -- .../flutter/lib/src/material/material.dart | 12 +++------ .../lib/src/material/material_button.dart | 8 +++--- .../flutter/lib/src/material/menu_anchor.dart | 4 +-- .../lib/src/material/menu_button_theme.dart | 2 -- .../lib/src/material/mergeable_material.dart | 2 -- .../src/material/navigation_bar_theme.dart | 2 -- .../src/material/navigation_drawer_theme.dart | 2 -- .../lib/src/material/navigation_rail.dart | 10 ++++---- .../src/material/navigation_rail_theme.dart | 2 -- .../lib/src/material/outlined_button.dart | 4 --- .../src/material/outlined_button_theme.dart | 2 -- packages/flutter/lib/src/material/page.dart | 3 --- .../src/material/paginated_data_table.dart | 16 +++++------- .../flutter/lib/src/material/popup_menu.dart | 16 ++++-------- .../lib/src/material/popup_menu_theme.dart | 2 -- .../lib/src/material/range_slider.dart | 25 +++++++++++-------- .../flutter/lib/src/material/scaffold.dart | 8 ++---- .../lib/src/material/scrollbar_theme.dart | 2 -- .../lib/src/material/search_anchor.dart | 4 --- .../lib/src/material/selectable_text.dart | 12 ++++----- .../lib/src/material/slider_theme.dart | 4 --- .../flutter/lib/src/material/snack_bar.dart | 11 +++----- .../lib/src/material/snack_bar_theme.dart | 2 -- .../flutter/lib/src/material/stepper.dart | 4 --- packages/flutter/lib/src/material/switch.dart | 2 -- .../lib/src/material/switch_list_tile.dart | 2 -- .../lib/src/material/tab_bar_theme.dart | 2 -- .../lib/src/material/tab_controller.dart | 12 ++++----- .../lib/src/material/tab_indicator.dart | 2 -- packages/flutter/lib/src/material/tabs.dart | 8 +++--- .../flutter/lib/src/material/text_button.dart | 6 +---- .../lib/src/material/text_button_theme.dart | 2 -- .../flutter/lib/src/material/text_field.dart | 8 +----- .../src/material/text_selection_theme.dart | 2 -- packages/flutter/lib/src/material/theme.dart | 5 +--- .../flutter/lib/src/material/theme_data.dart | 13 ++-------- .../flutter/lib/src/material/time_picker.dart | 2 -- .../lib/src/material/time_picker_theme.dart | 2 -- .../lib/src/material/toggle_buttons.dart | 5 ++-- .../src/material/toggle_buttons_theme.dart | 2 -- .../flutter/lib/src/material/tooltip.dart | 2 -- .../lib/src/material/tooltip_theme.dart | 2 -- .../lib/src/material/tooltip_visibility.dart | 2 -- 93 files changed, 127 insertions(+), 376 deletions(-) diff --git a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart index addcf65d47846..09feb5eced18d 100644 --- a/packages/flutter/lib/src/material/animated_icons/animated_icons.dart +++ b/packages/flutter/lib/src/material/animated_icons/animated_icons.dart @@ -29,8 +29,8 @@ part of material_animated_icons; // ignore: use_string_in_part_of_directives class AnimatedIcon extends StatelessWidget { /// Creates an AnimatedIcon. /// - /// The [progress] and [icon] arguments must not be null. - /// The [size] and [color] default to the value given by the current [IconTheme]. + /// The [size] and [color] default to the value given by the current + /// [IconTheme]. const AnimatedIcon({ super.key, required this.icon, diff --git a/packages/flutter/lib/src/material/app.dart b/packages/flutter/lib/src/material/app.dart index 41c5d9fc7ded6..7d7d42687e5ec 100644 --- a/packages/flutter/lib/src/material/app.dart +++ b/packages/flutter/lib/src/material/app.dart @@ -202,8 +202,6 @@ class MaterialApp extends StatefulWidget { /// unsupported route. /// /// This class creates an instance of [WidgetsApp]. - /// - /// The boolean arguments, [routes], and [navigatorObservers], must not be null. const MaterialApp({ super.key, this.navigatorKey, diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index ab0567e25e163..621acad1463ab 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -1436,9 +1436,6 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { /// * <https://material.io/design/components/app-bars-top.html> class SliverAppBar extends StatefulWidget { /// Creates a Material Design app bar that can be placed in a [CustomScrollView]. - /// - /// The arguments [forceElevated], [primary], [floating], [pinned], [snap] - /// and [automaticallyImplyLeading] must not be null. const SliverAppBar({ super.key, this.leading, diff --git a/packages/flutter/lib/src/material/app_bar_theme.dart b/packages/flutter/lib/src/material/app_bar_theme.dart index adab8d2addf5a..c8528b5d7d99a 100644 --- a/packages/flutter/lib/src/material/app_bar_theme.dart +++ b/packages/flutter/lib/src/material/app_bar_theme.dart @@ -200,8 +200,6 @@ class AppBarTheme with Diagnosticable { /// Linearly interpolate between two AppBar themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static AppBarTheme lerp(AppBarTheme? a, AppBarTheme? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/banner.dart b/packages/flutter/lib/src/material/banner.dart index b3a47a56a793e..de2ef0d08ed1a 100644 --- a/packages/flutter/lib/src/material/banner.dart +++ b/packages/flutter/lib/src/material/banner.dart @@ -93,9 +93,8 @@ enum MaterialBannerClosedReason { class MaterialBanner extends StatefulWidget { /// Creates a [MaterialBanner]. /// - /// The [actions], [content], and [forceActionsBelow] must be non-null. - /// The [actions].length must be greater than 0. The [elevation] must be null or - /// non-negative. + /// The length of the [actions] list must not be empty. The [elevation] must + /// be null or non-negative. const MaterialBanner({ super.key, required this.content, diff --git a/packages/flutter/lib/src/material/banner_theme.dart b/packages/flutter/lib/src/material/banner_theme.dart index e2d973fd5ffef..8792204ef8380 100644 --- a/packages/flutter/lib/src/material/banner_theme.dart +++ b/packages/flutter/lib/src/material/banner_theme.dart @@ -97,8 +97,6 @@ class MaterialBannerThemeData with Diagnosticable { /// Linearly interpolate between two Banner themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static MaterialBannerThemeData lerp(MaterialBannerThemeData? a, MaterialBannerThemeData? b, double t) { return MaterialBannerThemeData( diff --git a/packages/flutter/lib/src/material/bottom_app_bar_theme.dart b/packages/flutter/lib/src/material/bottom_app_bar_theme.dart index c056894899b64..d2516e647a413 100644 --- a/packages/flutter/lib/src/material/bottom_app_bar_theme.dart +++ b/packages/flutter/lib/src/material/bottom_app_bar_theme.dart @@ -94,8 +94,6 @@ class BottomAppBarTheme with Diagnosticable { /// Linearly interpolate between two BAB themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static BottomAppBarTheme lerp(BottomAppBarTheme? a, BottomAppBarTheme? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar.dart b/packages/flutter/lib/src/material/bottom_navigation_bar.dart index 15e63f6a59242..072fccce82d60 100644 --- a/packages/flutter/lib/src/material/bottom_navigation_bar.dart +++ b/packages/flutter/lib/src/material/bottom_navigation_bar.dart @@ -80,8 +80,8 @@ enum BottomNavigationBarLandscapeLayout { /// [BottomNavigationBarType.fixed] when there are less than four items, and /// [BottomNavigationBarType.shifting] otherwise. /// -/// The length of [items] must be at least two and each item's icon and title/label -/// must not be null. +/// The length of [items] must be at least two and each item's icon and +/// label must not be null. /// /// * [BottomNavigationBarType.fixed], the default when there are less than /// four [items]. The selected item is rendered with the @@ -188,7 +188,7 @@ class BottomNavigationBar extends StatefulWidget { /// are two or three [items], [BottomNavigationBarType.shifting] otherwise. /// /// The [iconSize], [selectedFontSize], [unselectedFontSize], and [elevation] - /// arguments must be non-null and non-negative. + /// arguments must be non-negative. /// /// If [selectedLabelStyle].color and [unselectedLabelStyle].color values /// are non-null, they will be used instead of [selectedItemColor] and diff --git a/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart b/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart index b6d3ad6bff4cc..d60fa6b016d8d 100644 --- a/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart +++ b/packages/flutter/lib/src/material/bottom_navigation_bar_theme.dart @@ -170,8 +170,6 @@ class BottomNavigationBarThemeData with Diagnosticable { /// Linearly interpolate between two [BottomNavigationBarThemeData]. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static BottomNavigationBarThemeData lerp(BottomNavigationBarThemeData? a, BottomNavigationBarThemeData? b, double t) { if (identical(a, b) && a != null) { @@ -276,8 +274,6 @@ class BottomNavigationBarThemeData with Diagnosticable { class BottomNavigationBarTheme extends InheritedWidget { /// Constructs a bottom navigation bar theme that configures all descendant /// [BottomNavigationBar] widgets. - /// - /// The [data] must not be null. const BottomNavigationBarTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index df42645275215..aea0f76e09f09 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -1133,8 +1133,6 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> { /// curve specified with the [curve] argument, after the finger is released. In /// such a case, the value of [startingPoint] would be the progress of the /// animation at the time when the finger was released. -/// -/// The [startingPoint] and [curve] arguments must not be null. class _BottomSheetSuspendedCurve extends ParametricCurve<double> { /// Creates a suspended curve. const _BottomSheetSuspendedCurve( diff --git a/packages/flutter/lib/src/material/button.dart b/packages/flutter/lib/src/material/button.dart index 917123558b1cc..bda8513ebffa6 100644 --- a/packages/flutter/lib/src/material/button.dart +++ b/packages/flutter/lib/src/material/button.dart @@ -40,11 +40,8 @@ import 'theme_data.dart'; class RawMaterialButton extends StatefulWidget { /// Create a button based on [Semantics], [Material], and [InkWell] widgets. /// - /// The [shape], [elevation], [focusElevation], [hoverElevation], - /// [highlightElevation], [disabledElevation], [padding], [constraints], - /// [autofocus], and [clipBehavior] arguments must not be null. Additionally, - /// [elevation], [focusElevation], [hoverElevation], [highlightElevation], and - /// [disabledElevation] must be non-negative. + /// The [elevation], [focusElevation], [hoverElevation], [highlightElevation], + /// and [disabledElevation] parameters must be non-negative. const RawMaterialButton({ super.key, required this.onPressed, @@ -288,7 +285,7 @@ class RawMaterialButton extends StatefulWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; /// Whether detected gestures should provide acoustic and/or haptic feedback. diff --git a/packages/flutter/lib/src/material/button_bar_theme.dart b/packages/flutter/lib/src/material/button_bar_theme.dart index 9f3aac0ca8858..2251b940a0c11 100644 --- a/packages/flutter/lib/src/material/button_bar_theme.dart +++ b/packages/flutter/lib/src/material/button_bar_theme.dart @@ -233,8 +233,6 @@ class ButtonBarThemeData with Diagnosticable { class ButtonBarTheme extends InheritedWidget { /// Constructs a button bar theme that configures all descendent [ButtonBar] /// widgets. - /// - /// The [data] must not be null. const ButtonBarTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/button_style_button.dart b/packages/flutter/lib/src/material/button_style_button.dart index c1f75e87c8e06..1568ce0353d17 100644 --- a/packages/flutter/lib/src/material/button_style_button.dart +++ b/packages/flutter/lib/src/material/button_style_button.dart @@ -89,7 +89,7 @@ abstract class ButtonStyleButton extends StatefulWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; /// {@macro flutter.widgets.Focus.focusNode} diff --git a/packages/flutter/lib/src/material/button_theme.dart b/packages/flutter/lib/src/material/button_theme.dart index a9866a0c18f7b..e41ea025e58c0 100644 --- a/packages/flutter/lib/src/material/button_theme.dart +++ b/packages/flutter/lib/src/material/button_theme.dart @@ -66,9 +66,6 @@ enum ButtonBarLayoutBehavior { /// depend on any inherited themes. class ButtonTheme extends InheritedTheme { /// Creates a button theme. - /// - /// The [textTheme], [minWidth], [height], and [colorScheme] arguments - /// must not be null. ButtonTheme({ super.key, ButtonTextTheme textTheme = ButtonTextTheme.normal, @@ -108,8 +105,6 @@ class ButtonTheme extends InheritedTheme { ); /// Creates a button theme from [data]. - /// - /// The [data] argument must not be null. const ButtonTheme.fromButtonThemeData({ super.key, required this.data, @@ -168,9 +163,7 @@ class ButtonThemeData with Diagnosticable { /// Create a button theme object that can be used with [ButtonTheme] /// or [ThemeData]. /// - /// The [textTheme], [minWidth], [height], [alignedDropdown], and - /// [layoutBehavior] parameters must not be null. The [minWidth] and - /// [height] parameters must greater than or equal to zero. + /// The [minWidth] and [height] parameters must greater than or equal to zero. /// /// The ButtonTheme's methods that have a [MaterialButton] parameter and /// have a name with a `get` prefix are used to configure a diff --git a/packages/flutter/lib/src/material/calendar_date_picker.dart b/packages/flutter/lib/src/material/calendar_date_picker.dart index 9bc419eac50dd..e3cefd4775429 100644 --- a/packages/flutter/lib/src/material/calendar_date_picker.dart +++ b/packages/flutter/lib/src/material/calendar_date_picker.dart @@ -1143,8 +1143,7 @@ const _DayPickerGridDelegate _dayPickerGridDelegate = _DayPickerGridDelegate(); class YearPicker extends StatefulWidget { /// Creates a year picker. /// - /// The [firstDate], [lastDate], [selectedDate], and [onChanged] - /// arguments must be non-null. The [lastDate] must be after the [firstDate]. + /// The [lastDate] must be after the [firstDate]. YearPicker({ super.key, DateTime? currentDate, diff --git a/packages/flutter/lib/src/material/card.dart b/packages/flutter/lib/src/material/card.dart index 085d88d9c7afe..dd9ced05fa960 100644 --- a/packages/flutter/lib/src/material/card.dart +++ b/packages/flutter/lib/src/material/card.dart @@ -58,8 +58,7 @@ import 'theme.dart'; class Card extends StatelessWidget { /// Creates a Material Design card. /// - /// The [elevation] must be null or non-negative. The [borderOnForeground] - /// must not be null. + /// The [elevation] must be null or non-negative. const Card({ super.key, this.color, diff --git a/packages/flutter/lib/src/material/card_theme.dart b/packages/flutter/lib/src/material/card_theme.dart index 25855ddbafc64..23391dbe77047 100644 --- a/packages/flutter/lib/src/material/card_theme.dart +++ b/packages/flutter/lib/src/material/card_theme.dart @@ -110,8 +110,6 @@ class CardTheme with Diagnosticable { /// Linearly interpolate between two Card themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static CardTheme lerp(CardTheme? a, CardTheme? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/checkbox.dart b/packages/flutter/lib/src/material/checkbox.dart index 518351ae9cd1f..c6bd10b8a15d1 100644 --- a/packages/flutter/lib/src/material/checkbox.dart +++ b/packages/flutter/lib/src/material/checkbox.dart @@ -74,8 +74,6 @@ class Checkbox extends StatefulWidget { /// can only be null if [tristate] is true. /// * [onChanged], which is called when the value of the checkbox should /// change. It can be set to null to disable the checkbox. - /// - /// The values of [tristate] and [autofocus] must not be null. const Checkbox({ super.key, required this.value, @@ -391,7 +389,7 @@ class Checkbox extends StatefulWidget { /// this is true. This is only used when [ThemeData.useMaterial3] is set to true. /// {@endtemplate} /// - /// Must not be null. Defaults to false. + /// Defaults to false. final bool isError; /// {@template flutter.material.checkbox.semanticLabel} diff --git a/packages/flutter/lib/src/material/checkbox_list_tile.dart b/packages/flutter/lib/src/material/checkbox_list_tile.dart index 87d91827bd354..76dc4265e4c3b 100644 --- a/packages/flutter/lib/src/material/checkbox_list_tile.dart +++ b/packages/flutter/lib/src/material/checkbox_list_tile.dart @@ -159,8 +159,6 @@ class CheckboxListTile extends StatelessWidget { /// can only be null if [tristate] is true. /// * [onChanged], which is called when the value of the checkbox should /// change. It can be set to null to disable the checkbox. - /// - /// The value of [tristate] must not be null. const CheckboxListTile({ super.key, required this.value, diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index a91c94a45f066..7c1132dfd8615 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -137,7 +137,7 @@ abstract interface class ChipAttributes { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. Clip get clipBehavior; /// {@macro flutter.widgets.Focus.focusNode} @@ -333,7 +333,7 @@ abstract interface class SelectableChipAttributes { /// If [onSelected] is not null, this value will be used to determine if the /// select check mark will be shown or not. /// - /// Must not be null. Defaults to false. + /// Defaults to false. bool get selected; /// Called when the chip should change between selected and de-selected @@ -447,7 +447,7 @@ abstract interface class DisabledChipAttributes { /// For classes which don't have this as a constructor argument, [isEnabled] /// returns true if their user action callback is set. /// - /// Defaults to true. Cannot be null. + /// Defaults to true. bool get isEnabled; /// The color used for the chip's background to indicate that it is not @@ -561,7 +561,6 @@ abstract interface class TappableChipAttributes { class Chip extends StatelessWidget implements ChipAttributes, DeletableChipAttributes { /// Creates a Material Design chip. /// - /// The [label], [autofocus], and [clipBehavior] arguments must not be null. /// The [elevation] must be null or non-negative. const Chip({ super.key, @@ -707,10 +706,8 @@ class RawChip extends StatefulWidget /// The [onPressed] and [onSelected] callbacks must not both be specified at /// the same time. /// - /// The [label], [isEnabled], [selected], [autofocus], and [clipBehavior] - /// arguments must not be null. The [pressElevation] and [elevation] must be - /// null or non-negative. Typically, [pressElevation] is greater than - /// [elevation]. + /// The [pressElevation] and [elevation] must be null or non-negative. + /// Typically, [pressElevation] is greater than [elevation]. const RawChip({ super.key, this.defaultProperties, diff --git a/packages/flutter/lib/src/material/chip_theme.dart b/packages/flutter/lib/src/material/chip_theme.dart index 4c9a052d9e039..44aa0b0016bb9 100644 --- a/packages/flutter/lib/src/material/chip_theme.dart +++ b/packages/flutter/lib/src/material/chip_theme.dart @@ -42,8 +42,6 @@ import 'theme.dart'; /// application. class ChipTheme extends InheritedTheme { /// Applies the given theme [data] to [child]. - /// - /// The [data] and [child] arguments must not be null. const ChipTheme({ super.key, required this.data, @@ -490,8 +488,6 @@ class ChipThemeData with Diagnosticable { /// Linearly interpolate between two chip themes. /// - /// The arguments must not be null. - /// /// {@macro dart.ui.shadow.lerp} static ChipThemeData? lerp(ChipThemeData? a, ChipThemeData? b, double t) { if (identical(a, b)) { diff --git a/packages/flutter/lib/src/material/choice_chip.dart b/packages/flutter/lib/src/material/choice_chip.dart index 8eba9b0b7dd4f..873d554199b90 100644 --- a/packages/flutter/lib/src/material/choice_chip.dart +++ b/packages/flutter/lib/src/material/choice_chip.dart @@ -22,8 +22,7 @@ enum _ChipVariant { flat, elevated } /// [ChoiceChip]s represent a single choice from a set. Choice chips contain /// related descriptive text or categories. /// -/// Requires one of its ancestors to be a [Material] widget. The [selected] and -/// [label] arguments must not be null. +/// Requires one of its ancestors to be a [Material] widget. /// /// {@tool dartpad} /// This example shows how to create [ChoiceChip]s with [onSelected]. When the diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index d4d280b6960da..e1add455280dc 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -36,8 +36,6 @@ typedef DataColumnSortCallback = void Function(int columnIndex, bool ascending); @immutable class DataColumn { /// Creates the configuration for a column of a [DataTable]. - /// - /// The [label] argument must not be null. const DataColumn({ required this.label, this.tooltip, @@ -112,8 +110,6 @@ class DataColumn { @immutable class DataRow { /// Creates the configuration for a row of a [DataTable]. - /// - /// The [cells] argument must not be null. const DataRow({ this.key, this.selected = false, @@ -126,8 +122,6 @@ class DataRow { /// Creates the configuration for a row of a [DataTable], deriving /// the key from a row index. - /// - /// The [cells] argument must not be null. DataRow.byIndex({ int? index, this.selected = false, @@ -248,8 +242,7 @@ class DataCell { /// Creates an object to hold the data for a cell in a [DataTable]. /// /// The first argument is the widget to show for the cell, typically - /// a [Text] or [DropdownButton] widget; this becomes the [child] - /// property and must not be null. + /// a [Text] or [DropdownButton] widget. /// /// If the cell has no data, then a [Text] widget with placeholder /// text should be provided instead, and then the [placeholder] @@ -402,7 +395,7 @@ class DataTable extends StatelessWidget { /// The [columns] argument must be a list of as many [DataColumn] /// objects as the table is to have columns, ignoring the leading /// checkbox column if any. The [columns] argument must have a - /// length greater than zero and must not be null. + /// length greater than zero. /// /// The [rows] argument must be a list of as many [DataRow] objects /// as the table is to have rows, ignoring the leading heading row @@ -676,7 +669,7 @@ class DataTable extends StatelessWidget { /// The data to show in each row (excluding the row that contains /// the column headings). /// - /// Must be non-null, but may be empty. + /// The list may be empty. final List<DataRow> rows; /// {@template flutter.material.dataTable.dividerThickness} @@ -712,7 +705,7 @@ class DataTable extends StatelessWidget { /// /// This can be used to clip the content within the border of the [DataTable]. /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; // Set by the constructor to the index of the only Column that is diff --git a/packages/flutter/lib/src/material/data_table_theme.dart b/packages/flutter/lib/src/material/data_table_theme.dart index 79a534e69a92c..fb2bb96b00565 100644 --- a/packages/flutter/lib/src/material/data_table_theme.dart +++ b/packages/flutter/lib/src/material/data_table_theme.dart @@ -162,8 +162,6 @@ class DataTableThemeData with Diagnosticable { /// Linearly interpolate between two [DataTableThemeData]s. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static DataTableThemeData lerp(DataTableThemeData a, DataTableThemeData b, double t) { if (identical(a, b)) { @@ -266,8 +264,6 @@ class DataTableThemeData with Diagnosticable { class DataTableTheme extends InheritedWidget { /// Constructs a data table theme that configures all descendant /// [DataTable] widgets. - /// - /// The [data] must not be null. const DataTableTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/date_picker.dart b/packages/flutter/lib/src/material/date_picker.dart index f1b86a3cf3e08..154529a84e28c 100644 --- a/packages/flutter/lib/src/material/date_picker.dart +++ b/packages/flutter/lib/src/material/date_picker.dart @@ -70,7 +70,7 @@ const double _kMaxTextScaleFactor = 1.3; /// An optional [initialEntryMode] argument can be used to display the date /// picker in the [DatePickerEntryMode.calendar] (a calendar month grid) /// or [DatePickerEntryMode.input] (a text input field) mode. -/// It defaults to [DatePickerEntryMode.calendar] and must be non-null. +/// It defaults to [DatePickerEntryMode.calendar]. /// /// {@template flutter.material.date_picker.switchToInputEntryModeIcon} /// An optional [switchToInputEntryModeIcon] argument can be used to @@ -117,7 +117,6 @@ const double _kMaxTextScaleFactor = 1.3; /// The [context], [barrierDismissible], [barrierColor], [barrierLabel], /// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], /// the documentation for which discusses how it is used. -/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -943,7 +942,7 @@ class _DatePickerHeader extends StatelessWidget { /// before or on `initialDateRange.end`. /// /// The [firstDate] is the earliest allowable date. The [lastDate] is the latest -/// allowable date. Both must be non-null. +/// allowable date. /// /// If an initial date range is provided, `initialDateRange.start` /// and `initialDateRange.end` must both fall between or on [firstDate] and @@ -957,7 +956,7 @@ class _DatePickerHeader extends StatelessWidget { /// An optional [initialEntryMode] argument can be used to display the date /// picker in the [DatePickerEntryMode.calendar] (a scrollable calendar month /// grid) or [DatePickerEntryMode.input] (two text input fields) mode. -/// It defaults to [DatePickerEntryMode.calendar] and must be non-null. +/// It defaults to [DatePickerEntryMode.calendar]. /// /// {@macro flutter.material.date_picker.switchToInputEntryModeIcon} /// @@ -996,7 +995,6 @@ class _DatePickerHeader extends StatelessWidget { /// The [context], [barrierDismissible], [barrierColor], [barrierLabel], /// [useRootNavigator] and [routeSettings] arguments are passed to [showDialog], /// the documentation for which discusses how it is used. -/// [context], [barrierDismissible] and [useRootNavigator] must be non-null. /// /// The [builder] parameter can be used to wrap the dialog widget /// to add inherited widgets like [Theme]. @@ -1237,7 +1235,7 @@ class DateRangePickerDialog extends StatefulWidget { /// scrollable calendar month grid) or [DatePickerEntryMode.input] (two text /// input fields) mode. /// - /// It defaults to [DatePickerEntryMode.calendar] and must be non-null. + /// It defaults to [DatePickerEntryMode.calendar]. final DatePickerEntryMode initialEntryMode; /// The label on the cancel button for the text input mode. diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 16c05049a2eca..a9ca87452c813 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -182,7 +182,7 @@ class Dialog extends StatelessWidget { /// See the enum [Clip] for details of all possible options and their common /// use cases. /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. /// {@endtemplate} final Clip clipBehavior; @@ -1096,8 +1096,6 @@ class SimpleDialog extends StatelessWidget { /// Creates a simple dialog. /// /// Typically used in conjunction with [showDialog]. - /// - /// The [titlePadding] and [contentPadding] arguments must not be null. const SimpleDialog({ super.key, this.title, diff --git a/packages/flutter/lib/src/material/dialog_theme.dart b/packages/flutter/lib/src/material/dialog_theme.dart index 8f318cf8d0622..f27728418b64d 100644 --- a/packages/flutter/lib/src/material/dialog_theme.dart +++ b/packages/flutter/lib/src/material/dialog_theme.dart @@ -107,8 +107,6 @@ class DialogTheme with Diagnosticable { /// Linearly interpolate between two dialog themes. /// - /// The arguments must not be null. - /// /// {@macro dart.ui.shadow.lerp} static DialogTheme lerp(DialogTheme? a, DialogTheme? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/divider_theme.dart b/packages/flutter/lib/src/material/divider_theme.dart index 93975aa34e27c..b9f0a52fccd65 100644 --- a/packages/flutter/lib/src/material/divider_theme.dart +++ b/packages/flutter/lib/src/material/divider_theme.dart @@ -83,8 +83,6 @@ class DividerThemeData with Diagnosticable { /// Linearly interpolate between two Divider themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static DividerThemeData lerp(DividerThemeData? a, DividerThemeData? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index b4bd85a94709c..abb67e32858a5 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -310,7 +310,7 @@ class DrawerController extends StatefulWidget { /// /// Rarely used directly. /// - /// The [child] argument must not be null and is typically a [Drawer]. + /// The [child] argument is typically a [Drawer]. const DrawerController({ GlobalKey? key, required this.child, diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index 91ffca3e302d0..a72eba1b90ad8 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -730,7 +730,7 @@ class _DropdownMenuItemContainer extends StatelessWidget { /// Defines how the item is positioned within the container. /// - /// This property must not be null. It defaults to [AlignmentDirectional.centerStart]. + /// Defaults to [AlignmentDirectional.centerStart]. /// /// See also: /// @@ -912,12 +912,6 @@ class DropdownButton<T> extends StatefulWidget { /// if it is non-null. If [disabledHint] is null, then [hint] will be displayed /// if it is non-null. /// - /// The [elevation] and [iconSize] arguments must not be null (they both have - /// defaults, so do not need to be specified). The boolean [isDense] and - /// [isExpanded] arguments must not be null. - /// - /// The [autofocus] argument must not be null. - /// /// The [dropdownColor] argument specifies the background color of the /// dropdown when it is open. If it is null, the current theme's /// [ThemeData.canvasColor] will be used instead. @@ -1215,7 +1209,7 @@ class DropdownButton<T> extends StatefulWidget { /// Defines how the hint or the selected item is positioned within the button. /// - /// This property must not be null. It defaults to [AlignmentDirectional.centerStart]. + /// Defaults to [AlignmentDirectional.centerStart]. /// /// See also: /// @@ -1589,9 +1583,6 @@ class DropdownButtonFormField<T> extends FormField<T> { /// For a description of the `onSaved`, `validator`, or `autovalidateMode` /// parameters, see [FormField]. For the rest (other than [decoration]), see /// [DropdownButton]. - /// - /// The `items`, `elevation`, `iconSize`, `isDense`, `isExpanded`, - /// `autofocus`, and `decoration` parameters must not be null. DropdownButtonFormField({ super.key, required List<DropdownMenuItem<T>>? items, diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index ca439552ba00e..3b80170fcabbf 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -39,8 +39,6 @@ const double _kDefaultHorizontalPadding = 12.0; /// * [DropdownMenu] class DropdownMenuEntry<T> { /// Creates an entry that is used with [DropdownMenu.dropdownMenuEntries]. - /// - /// [label] must be non-null. const DropdownMenuEntry({ required this.value, required this.label, diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index 5f8b4fe64088f..9fd146dd6c22d 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -62,8 +62,6 @@ import 'theme_data.dart'; /// * <https://m3.material.io/components/buttons> class ElevatedButton extends ButtonStyleButton { /// Create an ElevatedButton. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. const ElevatedButton({ super.key, required super.onPressed, @@ -83,8 +81,6 @@ class ElevatedButton extends ButtonStyleButton { /// /// The icon and label are arranged in a row and padded by 12 logical pixels /// at the start, and 16 at the end, with an 8 pixel gap in between. - /// - /// The [icon] and [label] arguments must not be null. factory ElevatedButton.icon({ Key? key, required VoidCallback? onPressed, diff --git a/packages/flutter/lib/src/material/elevated_button_theme.dart b/packages/flutter/lib/src/material/elevated_button_theme.dart index 09964270103b7..bc2b93a778abf 100644 --- a/packages/flutter/lib/src/material/elevated_button_theme.dart +++ b/packages/flutter/lib/src/material/elevated_button_theme.dart @@ -91,8 +91,6 @@ class ElevatedButtonThemeData with Diagnosticable { /// [ButtonStyle] for [ElevatedButton]s below the overall [Theme]. class ElevatedButtonTheme extends InheritedTheme { /// Create a [ElevatedButtonTheme]. - /// - /// The [data] parameter must not be null. const ElevatedButtonTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/expand_icon.dart b/packages/flutter/lib/src/material/expand_icon.dart index 10733d64e04f6..7672223655d49 100644 --- a/packages/flutter/lib/src/material/expand_icon.dart +++ b/packages/flutter/lib/src/material/expand_icon.dart @@ -49,7 +49,7 @@ class ExpandIcon extends StatefulWidget { /// The size of the icon. /// - /// This property must not be null. It defaults to 24.0. + /// Defaults to 24. final double size; /// The callback triggered when the icon is pressed and the state changes @@ -61,7 +61,7 @@ class ExpandIcon extends StatefulWidget { /// The padding around the icon. The entire padded icon will react to input /// gestures. /// - /// This property must not be null. It defaults to 8.0 padding on all sides. + /// Defaults to a padding of 8 on all sides. final EdgeInsetsGeometry padding; /// {@template flutter.material.ExpandIcon.color} diff --git a/packages/flutter/lib/src/material/expansion_panel.dart b/packages/flutter/lib/src/material/expansion_panel.dart index 409bb1c96c717..95eb2ad7ee801 100644 --- a/packages/flutter/lib/src/material/expansion_panel.dart +++ b/packages/flutter/lib/src/material/expansion_panel.dart @@ -74,8 +74,6 @@ typedef ExpansionPanelHeaderBuilder = Widget Function(BuildContext context, bool class ExpansionPanel { /// Creates an expansion panel to be used as a child for [ExpansionPanelList]. /// See [ExpansionPanelList] for an example on how to use this widget. - /// - /// The [headerBuilder], [body], and [isExpanded] arguments must not be null. ExpansionPanel({ required this.headerBuilder, required this.body, @@ -120,8 +118,7 @@ class ExpansionPanel { class ExpansionPanelRadio extends ExpansionPanel { /// An expansion panel that allows for radio functionality. /// - /// A unique [value] must be passed into the constructor. The - /// [headerBuilder], [body], [value] must not be null. + /// A unique [value] must be passed into the constructor. ExpansionPanelRadio({ required this.value, required super.headerBuilder, @@ -160,8 +157,6 @@ class ExpansionPanelRadio extends ExpansionPanel { class ExpansionPanelList extends StatefulWidget { /// Creates an expansion panel list widget. The [expansionCallback] is /// triggered when an expansion panel expand/collapse button is pushed. - /// - /// The [children] and [animationDuration] arguments must not be null. const ExpansionPanelList({ super.key, this.children = const <ExpansionPanel>[], @@ -177,10 +172,9 @@ class ExpansionPanelList extends StatefulWidget { /// Creates a radio expansion panel list widget. /// - /// This widget allows for at most one panel in the list to be open. - /// The expansion panel callback is triggered when an expansion panel - /// expand/collapse button is pushed. The [children] and [animationDuration] - /// arguments must not be null. The [children] objects must be instances + /// This widget allows for at most one panel in the list to be open. The + /// expansion panel callback is triggered when an expansion panel + /// expand/collapse button is pushed. The [children] objects must be instances /// of [ExpansionPanelRadio]. /// /// {@tool dartpad} diff --git a/packages/flutter/lib/src/material/expansion_tile_theme.dart b/packages/flutter/lib/src/material/expansion_tile_theme.dart index 981c85a80b916..01d045ed692c9 100644 --- a/packages/flutter/lib/src/material/expansion_tile_theme.dart +++ b/packages/flutter/lib/src/material/expansion_tile_theme.dart @@ -210,8 +210,6 @@ class ExpansionTileThemeData with Diagnosticable { /// [ExpansionTileTheme] for [ExpansionTile]s below the overall [Theme]. class ExpansionTileTheme extends InheritedTheme { /// Applies the given theme [data] to [child]. - /// - /// The [data] and [child] arguments must not be null. const ExpansionTileTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/filled_button.dart b/packages/flutter/lib/src/material/filled_button.dart index b348e41c113ae..0943111084e4a 100644 --- a/packages/flutter/lib/src/material/filled_button.dart +++ b/packages/flutter/lib/src/material/filled_button.dart @@ -64,8 +64,6 @@ enum _FilledButtonVariant { filled, tonal } /// * <https://m3.material.io/components/buttons> class FilledButton extends ButtonStyleButton { /// Create a FilledButton. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. const FilledButton({ super.key, required super.onPressed, @@ -84,8 +82,6 @@ class FilledButton extends ButtonStyleButton { /// /// The icon and label are arranged in a row with padding at the start and end /// and a gap between them. - /// - /// The [icon] and [label] arguments must not be null. factory FilledButton.icon({ Key? key, required VoidCallback? onPressed, @@ -107,8 +103,6 @@ class FilledButton extends ButtonStyleButton { /// [FilledButton] and [OutlinedButton]. They’re useful in contexts where /// a lower-priority button requires slightly more emphasis than an /// outline would give, such as "Next" in an onboarding flow. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. const FilledButton.tonal({ super.key, required super.onPressed, @@ -127,8 +121,6 @@ class FilledButton extends ButtonStyleButton { /// /// The icon and label are arranged in a row with padding at the start and end /// and a gap between them. - /// - /// The [icon] and [label] arguments must not be null. factory FilledButton.tonalIcon({ Key? key, required VoidCallback? onPressed, diff --git a/packages/flutter/lib/src/material/filled_button_theme.dart b/packages/flutter/lib/src/material/filled_button_theme.dart index 72d59aae624a0..eebbf98e282d8 100644 --- a/packages/flutter/lib/src/material/filled_button_theme.dart +++ b/packages/flutter/lib/src/material/filled_button_theme.dart @@ -91,8 +91,6 @@ class FilledButtonThemeData with Diagnosticable { /// [ButtonStyle] for [FilledButton]s below the overall [Theme]. class FilledButtonTheme extends InheritedTheme { /// Create a [FilledButtonTheme]. - /// - /// The [data] parameter must not be null. const FilledButtonTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/flexible_space_bar.dart b/packages/flutter/lib/src/material/flexible_space_bar.dart index b3b3bf2355a1b..2869bd56ab377 100644 --- a/packages/flutter/lib/src/material/flexible_space_bar.dart +++ b/packages/flutter/lib/src/material/flexible_space_bar.dart @@ -371,9 +371,6 @@ class FlexibleSpaceBarSettings extends InheritedWidget { /// /// Used by [Scaffold] and [SliverAppBar]. [child] must have a /// [FlexibleSpaceBar] widget in its tree for the settings to take affect. - /// - /// The required [toolbarOpacity], [minExtent], [maxExtent], [currentExtent], - /// and [child] parameters must not be null. const FlexibleSpaceBarSettings({ super.key, required this.toolbarOpacity, diff --git a/packages/flutter/lib/src/material/floating_action_button.dart b/packages/flutter/lib/src/material/floating_action_button.dart index ab37361f383a6..e692e0ab76cfa 100644 --- a/packages/flutter/lib/src/material/floating_action_button.dart +++ b/packages/flutter/lib/src/material/floating_action_button.dart @@ -83,9 +83,8 @@ enum _FloatingActionButtonType { class FloatingActionButton extends StatelessWidget { /// Creates a circular floating action button. /// - /// The [mini] and [clipBehavior] arguments must not be null. Additionally, - /// [elevation], [highlightElevation], and [disabledElevation] (if specified) - /// must be non-negative. + /// The [elevation], [highlightElevation], and [disabledElevation] parameters, + /// if specified, must be non-negative. const FloatingActionButton({ super.key, this.child, @@ -127,10 +126,8 @@ class FloatingActionButton extends StatelessWidget { /// This constructor overrides the default size constraints of the floating /// action button. /// - /// The [clipBehavior] and [autofocus] arguments must not be null. - /// Additionally, [elevation], [focusElevation], [hoverElevation], - /// [highlightElevation], and [disabledElevation] (if specified) must be - /// non-negative. + /// The [elevation], [focusElevation], [hoverElevation], [highlightElevation], + /// and [disabledElevation] parameters, if specified, must be non-negative. const FloatingActionButton.small({ super.key, this.child, @@ -172,10 +169,8 @@ class FloatingActionButton extends StatelessWidget { /// This constructor overrides the default size constraints of the floating /// action button. /// - /// The [clipBehavior] and [autofocus] arguments must not be null. - /// Additionally, [elevation], [focusElevation], [hoverElevation], - /// [highlightElevation], and [disabledElevation] (if specified) must be - /// non-negative. + /// The [elevation], [focusElevation], [hoverElevation], [highlightElevation], + /// and [disabledElevation] parameters, if specified, must be non-negative. const FloatingActionButton.large({ super.key, this.child, @@ -215,9 +210,8 @@ class FloatingActionButton extends StatelessWidget { /// Creates a wider [StadiumBorder]-shaped floating action button with /// an optional [icon] and a [label]. /// - /// The [label], [autofocus], and [clipBehavior] arguments must not be null. - /// Additionally, [elevation], [highlightElevation], and [disabledElevation] - /// (if specified) must be non-negative. + /// The [elevation], [highlightElevation], and [disabledElevation] parameters, + /// if specified, must be non-negative. /// /// See also: /// * <https://m3.material.io/components/extended-fab> @@ -418,7 +412,7 @@ class FloatingActionButton extends StatelessWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; /// True if this is an "extended" floating action button. diff --git a/packages/flutter/lib/src/material/floating_action_button_location.dart b/packages/flutter/lib/src/material/floating_action_button_location.dart index c32fb92f166d2..a23496ce65e09 100644 --- a/packages/flutter/lib/src/material/floating_action_button_location.dart +++ b/packages/flutter/lib/src/material/floating_action_button_location.dart @@ -1004,8 +1004,8 @@ class _ScalingFabMotionAnimator extends FloatingActionButtonAnimator { class _AnimationSwap<T> extends CompoundAnimation<T> { /// Creates an [_AnimationSwap]. /// - /// Both arguments must be non-null. Either can be an [_AnimationSwap] itself - /// to combine multiple animations. + /// Either argument can be an [_AnimationSwap] itself to combine multiple + /// animations. _AnimationSwap(Animation<T> first, Animation<T> next, this.parent, this.swapThreshold) : super(first: first, next: next); final Animation<double> parent; diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index 88a9a36e24032..5beb239ea9d76 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -173,8 +173,6 @@ class IconButton extends StatelessWidget { /// Requires one of its ancestors to be a [Material] widget. This requirement /// no longer exists if [ThemeData.useMaterial3] is set to true. /// - /// [autofocus] argument must not be null (though it has default value). - /// /// The [icon] argument must be specified, and is typically either an [Icon] /// or an [ImageIcon]. const IconButton({ @@ -362,8 +360,6 @@ class IconButton extends StatelessWidget { /// [IconTheme] and therefore should not be explicitly given in the icon /// widget. /// - /// This property must not be null. - /// /// See [Icon], [ImageIcon]. final Widget icon; diff --git a/packages/flutter/lib/src/material/icon_button_theme.dart b/packages/flutter/lib/src/material/icon_button_theme.dart index ee639128131cf..b598dc1075caf 100644 --- a/packages/flutter/lib/src/material/icon_button_theme.dart +++ b/packages/flutter/lib/src/material/icon_button_theme.dart @@ -89,8 +89,6 @@ class IconButtonThemeData with Diagnosticable { /// [ButtonStyle] for [IconButton]s below the overall [Theme]. class IconButtonTheme extends InheritedTheme { /// Create a [IconButtonTheme]. - /// - /// The [data] parameter must not be null. const IconButtonTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/ink_decoration.dart b/packages/flutter/lib/src/material/ink_decoration.dart index 2492caca6959c..05434e7f63e40 100644 --- a/packages/flutter/lib/src/material/ink_decoration.dart +++ b/packages/flutter/lib/src/material/ink_decoration.dart @@ -169,9 +169,8 @@ class Ink extends StatefulWidget { /// properties of the [DecorationImage] of that [BoxDecoration] are set /// according to the arguments passed to this method. /// - /// The `image` argument must not be null. If there is no - /// intention to render anything on this image, consider using a - /// [Container] with a [BoxDecoration.image] instead. The `onImageError` + /// If there is no intention to render anything on this image, consider using + /// a [Container] with a [BoxDecoration.image] instead. The `onImageError` /// argument may be provided to listen for errors when resolving the image. /// /// The `alignment`, `repeat`, and `matchTextDirection` arguments must not diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index fe0fa9aca21fe..8b92f28a9d915 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -36,8 +36,6 @@ import 'theme.dart'; /// class. abstract class InteractiveInkFeature extends InkFeature { /// Creates an InteractiveInkFeature. - /// - /// The [controller] and [referenceBox] arguments must not be null. InteractiveInkFeature({ required super.controller, required super.referenceBox, @@ -296,9 +294,6 @@ class InkResponse extends StatelessWidget { /// Creates an area of a [Material] that responds to touch. /// /// Must have an ancestor [Material] widget in which to cause ink reactions. - /// - /// The [containedInkWell], [highlightShape], [enableFeedback], - /// and [excludeFromSemantics] arguments must not be null. const InkResponse({ super.key, this.child, @@ -1455,9 +1450,6 @@ class InkWell extends InkResponse { /// Creates an ink well. /// /// Must have an ancestor [Material] widget in which to cause ink reactions. - /// - /// The [enableFeedback], and [excludeFromSemantics] arguments - /// must not be null. const InkWell({ super.key, super.child, diff --git a/packages/flutter/lib/src/material/input_border.dart b/packages/flutter/lib/src/material/input_border.dart index 87ae0f6fc98de..1da20f7c5a598 100644 --- a/packages/flutter/lib/src/material/input_border.dart +++ b/packages/flutter/lib/src/material/input_border.dart @@ -31,10 +31,9 @@ import 'package:flutter/widgets.dart'; abstract class InputBorder extends ShapeBorder { /// Creates a border for an [InputDecorator]. /// - /// The [borderSide] parameter must not be null. Applications typically do - /// not specify a [borderSide] parameter because the input decorator - /// substitutes its own, using [copyWith], based on the current theme and - /// [InputDecorator.isFocused]. + /// Applications typically do not specify a [borderSide] parameter because the + /// [InputDecorator] substitutes its own, using [copyWith], based on the + /// current theme and [InputDecorator.isFocused]. const InputBorder({ this.borderSide = BorderSide.none, }); @@ -149,8 +148,7 @@ class UnderlineInputBorder extends InputBorder { /// on the current theme and [InputDecorator.isFocused]. /// /// The [borderRadius] parameter defaults to a value where the top left - /// and right corners have a circular radius of 4.0. The [borderRadius] - /// parameter must not be null. + /// and right corners have a circular radius of 4.0. const UnderlineInputBorder({ super.borderSide = const BorderSide(), this.borderRadius = const BorderRadius.only( @@ -292,10 +290,9 @@ class OutlineInputBorder extends InputBorder { /// value [BorderSide.none], the input decorator substitutes its own, using /// [copyWith], based on the current theme and [InputDecorator.isFocused]. /// - /// The [borderRadius] parameter defaults to a value where all four - /// corners have a circular radius of 4.0. The [borderRadius] parameter - /// must not be null and the corner radii must be circular, i.e. their - /// [Radius.x] and [Radius.y] values must be the same. + /// The [borderRadius] parameter defaults to a value where all four corners + /// have a circular radius of 4.0. The corner radii must be circular, i.e. + /// their [Radius.x] and [Radius.y] values must be the same. /// /// See also: /// diff --git a/packages/flutter/lib/src/material/input_chip.dart b/packages/flutter/lib/src/material/input_chip.dart index 33a4bfd841d53..13c97d4a50f4e 100644 --- a/packages/flutter/lib/src/material/input_chip.dart +++ b/packages/flutter/lib/src/material/input_chip.dart @@ -83,10 +83,8 @@ class InputChip extends StatelessWidget /// The [onPressed] and [onSelected] callbacks must not both be specified at /// the same time. /// - /// The [label], [isEnabled], [selected], [autofocus], and [clipBehavior] - /// arguments must not be null. The [pressElevation] and [elevation] must be - /// null or non-negative. Typically, [pressElevation] is greater than - /// [elevation]. + /// The [pressElevation] and [elevation] must be null or non-negative. + /// Typically, [pressElevation] is greater than [elevation]. const InputChip({ super.key, this.avatar, diff --git a/packages/flutter/lib/src/material/input_date_picker_form_field.dart b/packages/flutter/lib/src/material/input_date_picker_form_field.dart index 4a82273b78248..a7600e4fc970d 100644 --- a/packages/flutter/lib/src/material/input_date_picker_form_field.dart +++ b/packages/flutter/lib/src/material/input_date_picker_form_field.dart @@ -42,9 +42,6 @@ class InputDatePickerFormField extends StatefulWidget { /// for [initialDate]. /// /// [firstDate] must be on or before [lastDate]. - /// - /// [firstDate], [lastDate], and [autofocus] must be non-null. - /// InputDatePickerFormField({ super.key, DateTime? initialDate, diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 9e3a67ee4dff1..abaab18e4e6c5 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -1797,8 +1797,6 @@ class InputDecorator extends StatefulWidget { /// /// Null [InputDecoration] properties are initialized with the corresponding /// values from [ThemeData.inputDecorationTheme]. - /// - /// Must not be null. final InputDecoration decoration; /// The style on which to base the label, hint, counter, and error styles @@ -2556,8 +2554,6 @@ class InputDecoration { /// an instance of [UnderlineInputBorder]. If [border] is [InputBorder.none] /// then no border is drawn. /// - /// The [enabled] argument must not be null. - /// /// Only one of [prefix] and [prefixText] can be specified. /// /// Similarly, only one of [suffix] and [suffixText] can be specified. @@ -3834,9 +3830,6 @@ class InputDecoration { class InputDecorationTheme with Diagnosticable { /// Creates a value for [ThemeData.inputDecorationTheme] that /// defines default values for [InputDecorator]. - /// - /// The values of [isDense], [isCollapsed], [filled], [floatingLabelAlignment], - /// and [border] must not be null. const InputDecorationTheme({ this.labelStyle, this.floatingLabelStyle, diff --git a/packages/flutter/lib/src/material/list_tile_theme.dart b/packages/flutter/lib/src/material/list_tile_theme.dart index bd06bbd6c5fc5..3b77ffd97997e 100644 --- a/packages/flutter/lib/src/material/list_tile_theme.dart +++ b/packages/flutter/lib/src/material/list_tile_theme.dart @@ -470,8 +470,6 @@ class ListTileTheme extends InheritedTheme { /// Creates a list tile theme that controls the color and style parameters for /// [ListTile]s, and merges in the current list tile theme, if any. - /// - /// The [child] argument must not be null. static Widget merge({ Key? key, bool? dense, diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index e7d76a439e072..f5ebf2d7a4a34 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -171,9 +171,7 @@ abstract class MaterialInkController { class Material extends StatefulWidget { /// Creates a piece of material. /// - /// The [type], [elevation], [borderOnForeground], - /// [clipBehavior], and [animationDuration] arguments must not be null. - /// Additionally, [elevation] must be non-negative. + /// The [elevation] must be non-negative. /// /// If a [shape] is specified, then the [borderRadius] property must be /// null and the [type] property must not be [MaterialType.circle]. If the @@ -324,7 +322,7 @@ class Material extends StatefulWidget { /// use cases. /// {@endtemplate} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; /// Defines the duration of animated changes for [shape], [elevation], @@ -841,9 +839,7 @@ class ShapeBorderTween extends Tween<ShapeBorder?> { class _MaterialInterior extends ImplicitlyAnimatedWidget { /// Creates a const instance of [_MaterialInterior]. /// - /// The [child], [shape], [clipBehavior], [color], and [shadowColor] arguments - /// must not be null. The [elevation] must be specified and greater than or - /// equal to zero. + /// The [elevation] must be specified and greater than or equal to zero. const _MaterialInterior({ required this.child, required this.shape, @@ -876,7 +872,7 @@ class _MaterialInterior extends ImplicitlyAnimatedWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; /// The target z-coordinate at which to place this physical object relative diff --git a/packages/flutter/lib/src/material/material_button.dart b/packages/flutter/lib/src/material/material_button.dart index 2f3c5cc96ad7c..4afcc231f9e8e 100644 --- a/packages/flutter/lib/src/material/material_button.dart +++ b/packages/flutter/lib/src/material/material_button.dart @@ -45,10 +45,8 @@ class MaterialButton extends StatelessWidget { /// To create a custom Material button consider using [TextButton], /// [ElevatedButton], or [OutlinedButton]. /// - /// The [autofocus] and [clipBehavior] arguments must not be null. - /// Additionally, [elevation], [hoverElevation], [focusElevation], - /// [highlightElevation], and [disabledElevation] must be non-negative, if - /// specified. + /// The [elevation], [hoverElevation], [focusElevation], [highlightElevation], + /// and [disabledElevation] arguments must be non-negative, if specified. const MaterialButton({ super.key, required this.onPressed, @@ -338,7 +336,7 @@ class MaterialButton extends StatelessWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; /// {@macro flutter.widgets.Focus.focusNode} diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart index 3ad5543407b33..3b231b234028e 100644 --- a/packages/flutter/lib/src/material/menu_anchor.dart +++ b/packages/flutter/lib/src/material/menu_anchor.dart @@ -1189,7 +1189,7 @@ class CheckboxMenuButton extends StatelessWidget { /// The checkbox will have different default container color and check color when /// this is true. This is only used when [ThemeData.useMaterial3] is set to true. /// - /// Must not be null. Defaults to false. + /// Defaults to false. final bool isError; /// Called when the value of the checkbox should change. @@ -3214,7 +3214,7 @@ class _MenuLayout extends SingleChildLayoutDelegate { } else if (offBottom(y)) { final double newY = anchorRect.top - childSize.height; if (!offTop(newY)) { - // Only move the menu up if its parent is horizontal (MenuAchor/MenuBar). + // Only move the menu up if its parent is horizontal (MenuAnchor/MenuBar). if (parentOrientation == Axis.horizontal) { y = newY - alignmentOffset.dy; } else { diff --git a/packages/flutter/lib/src/material/menu_button_theme.dart b/packages/flutter/lib/src/material/menu_button_theme.dart index 987b2c3bb7955..47bf9b4c58f1a 100644 --- a/packages/flutter/lib/src/material/menu_button_theme.dart +++ b/packages/flutter/lib/src/material/menu_button_theme.dart @@ -103,8 +103,6 @@ class MenuButtonThemeData with Diagnosticable { /// [Theme]. class MenuButtonTheme extends InheritedTheme { /// Create a [MenuButtonTheme]. - /// - /// The [data] parameter must not be null. const MenuButtonTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/mergeable_material.dart b/packages/flutter/lib/src/material/mergeable_material.dart index 1ff2982d794e7..d8a95d6747ea1 100644 --- a/packages/flutter/lib/src/material/mergeable_material.dart +++ b/packages/flutter/lib/src/material/mergeable_material.dart @@ -19,8 +19,6 @@ import 'theme.dart'; abstract class MergeableMaterialItem { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. - /// - /// The argument is the [key], which must not be null. const MergeableMaterialItem(this.key); /// The key for this item of the list. diff --git a/packages/flutter/lib/src/material/navigation_bar_theme.dart b/packages/flutter/lib/src/material/navigation_bar_theme.dart index ae4781d17b738..2de555f6395e9 100644 --- a/packages/flutter/lib/src/material/navigation_bar_theme.dart +++ b/packages/flutter/lib/src/material/navigation_bar_theme.dart @@ -206,8 +206,6 @@ class NavigationBarThemeData with Diagnosticable { class NavigationBarTheme extends InheritedTheme { /// Creates a navigation rail theme that controls the /// [NavigationBarThemeData] properties for a [NavigationBar]. - /// - /// The data argument must not be null. const NavigationBarTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/navigation_drawer_theme.dart b/packages/flutter/lib/src/material/navigation_drawer_theme.dart index e16a2a3e3d6fa..7a06587572cc1 100644 --- a/packages/flutter/lib/src/material/navigation_drawer_theme.dart +++ b/packages/flutter/lib/src/material/navigation_drawer_theme.dart @@ -219,8 +219,6 @@ class NavigationDrawerThemeData with Diagnosticable { class NavigationDrawerTheme extends InheritedTheme { /// Creates a navigation rail theme that controls the /// [NavigationDrawerThemeData] properties for a [NavigationDrawer]. - /// - /// The data argument must not be null. const NavigationDrawerTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index 0524542d1ef20..0e47262b2ecaf 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -80,8 +80,8 @@ class NavigationRail extends StatefulWidget { /// [minExtendedWidth] is specified, it must be non-negative and greater than /// [minWidth]. /// - /// The argument [extended] must not be null. [extended] can only be set to - /// true when the [labelType] is null or [NavigationRailLabelType.none]. + /// The [extended] argument can only be set to true when the [labelType] is + /// null or [NavigationRailLabelType.none]. /// /// If [backgroundColor], [elevation], [groupAlignment], [labelType], /// [unselectedLabelTextStyle], [selectedLabelTextStyle], @@ -946,9 +946,9 @@ enum NavigationRailLabelType { class NavigationRailDestination { /// Creates a destination that is used with [NavigationRail.destinations]. /// - /// [icon] and [label] must be non-null. When the [NavigationRail.labelType] - /// is [NavigationRailLabelType.none], the label is still used for semantics, - /// and may still be used if [NavigationRail.extended] is true. + /// When the [NavigationRail.labelType] is [NavigationRailLabelType.none], the + /// label is still used for semantics, and may still be used if + /// [NavigationRail.extended] is true. const NavigationRailDestination({ required this.icon, Widget? selectedIcon, diff --git a/packages/flutter/lib/src/material/navigation_rail_theme.dart b/packages/flutter/lib/src/material/navigation_rail_theme.dart index b8a3f788754b8..664d2cb57fd3f 100644 --- a/packages/flutter/lib/src/material/navigation_rail_theme.dart +++ b/packages/flutter/lib/src/material/navigation_rail_theme.dart @@ -236,8 +236,6 @@ class NavigationRailThemeData with Diagnosticable { class NavigationRailTheme extends InheritedTheme { /// Creates a navigation rail theme that controls the /// [NavigationRailThemeData] properties for a [NavigationRail]. - /// - /// The data argument must not be null. const NavigationRailTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index 60ff7cbe4d933..c8875b2ac2baa 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -67,8 +67,6 @@ import 'theme_data.dart'; /// * <https://m3.material.io/components/buttons> class OutlinedButton extends ButtonStyleButton { /// Create an OutlinedButton. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. const OutlinedButton({ super.key, required super.onPressed, @@ -88,8 +86,6 @@ class OutlinedButton extends ButtonStyleButton { /// /// The icon and label are arranged in a row and padded by 12 logical pixels /// at the start, and 16 at the end, with an 8 pixel gap in between. - /// - /// The [icon] and [label] arguments must not be null. factory OutlinedButton.icon({ Key? key, required VoidCallback? onPressed, diff --git a/packages/flutter/lib/src/material/outlined_button_theme.dart b/packages/flutter/lib/src/material/outlined_button_theme.dart index 5dead513f803d..724f1e7d4f601 100644 --- a/packages/flutter/lib/src/material/outlined_button_theme.dart +++ b/packages/flutter/lib/src/material/outlined_button_theme.dart @@ -91,8 +91,6 @@ class OutlinedButtonThemeData with Diagnosticable { /// [ButtonStyle] for [OutlinedButton]s below the overall [Theme]. class OutlinedButtonTheme extends InheritedTheme { /// Create a [OutlinedButtonTheme]. - /// - /// The [data] parameter must not be null. const OutlinedButtonTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/page.dart b/packages/flutter/lib/src/material/page.dart index 0c1be0c83a2dc..db781f5376473 100644 --- a/packages/flutter/lib/src/material/page.dart +++ b/packages/flutter/lib/src/material/page.dart @@ -34,9 +34,6 @@ import 'theme.dart'; /// * [MaterialPage], which is a [Page] of this class. class MaterialPageRoute<T> extends PageRoute<T> with MaterialRouteTransitionMixin<T> { /// Construct a MaterialPageRoute whose contents are defined by [builder]. - /// - /// The values of [builder], [maintainState], and [PageRoute.fullscreenDialog] - /// must not be null. MaterialPageRoute({ required this.builder, super.settings, diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index eb04e9d00cee0..45eb851d778fe 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -71,15 +71,11 @@ class PaginatedDataTable extends StatefulWidget { /// order is ascending, this should be true (the default), otherwise it should /// be false. /// - /// The [source] must not be null. The [source] should be a long-lived - /// [DataTableSource]. The same source should be provided each time a - /// particular [PaginatedDataTable] widget is created; avoid creating a new - /// [DataTableSource] with each new instance of the [PaginatedDataTable] - /// widget unless the data table really is to now show entirely different - /// data from a new source. - /// - /// The [rowsPerPage] and [availableRowsPerPage] must not be null (they - /// both have defaults, though, so don't have to be specified). + /// The [source] should be a long-lived [DataTableSource]. The same source + /// should be provided each time a particular [PaginatedDataTable] widget is + /// created; avoid creating a new [DataTableSource] with each new instance of + /// the [PaginatedDataTable] widget unless the data table really is to now + /// show entirely different data from a new source. /// /// Themed by [DataTableTheme]. [DataTableThemeData.decoration] is ignored. /// To modify the border or background color of the [PaginatedDataTable], use @@ -264,7 +260,7 @@ class PaginatedDataTable extends StatefulWidget { /// and no affordance will be provided to change the value. final ValueChanged<int?>? onRowsPerPageChanged; - /// The data source which provides data to show in each row. Must be non-null. + /// The data source which provides data to show in each row. /// /// This object should generally have a lifetime longer than the /// [PaginatedDataTable] widget itself; it should be reused each time the diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 4d81e0959daae..520868c42d9d9 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -216,8 +216,6 @@ class PopupMenuItem<T> extends PopupMenuEntry<T> { /// Creates an item for a popup menu. /// /// By default, the item is [enabled]. - /// - /// The `enabled` and `height` arguments must not be null. const PopupMenuItem({ super.key, this.value, @@ -474,8 +472,6 @@ class CheckedPopupMenuItem<T> extends PopupMenuItem<T> { /// /// By default, the menu item is [enabled] but unchecked. To mark the item as /// checked, set [checked] to true. - /// - /// The `checked` and `enabled` arguments must not be null. const CheckedPopupMenuItem({ super.key, super.value, @@ -904,7 +900,7 @@ class _PopupMenuRoute<T> extends PopupRoute<T> { /// Show a popup menu that contains the `items` at `position`. /// -/// `items` should be non-null and not empty. +/// The `items` parameter must not be empty. /// /// If `initialValue` is specified then the first item with a matching value /// will be highlighted and the value of `position` gives the rectangle whose @@ -1101,8 +1097,6 @@ typedef PopupMenuItemBuilder<T> = List<PopupMenuEntry<T>> Function(BuildContext /// * [showMenu], a method to dynamically show a popup menu at a given location. class PopupMenuButton<T> extends StatefulWidget { /// Creates a button that shows a popup menu. - /// - /// The [itemBuilder] argument must not be null. const PopupMenuButton({ super.key, required this.itemBuilder, @@ -1207,11 +1201,11 @@ class PopupMenuButton<T> extends StatefulWidget { /// Whether this popup menu button is interactive. /// - /// Must be non-null, defaults to `true` + /// Defaults to true. /// - /// If `true` the button will respond to presses by displaying the menu. + /// If true, the button will respond to presses by displaying the menu. /// - /// If `false`, the button is styled with the disabled color from the + /// If false, the button is styled with the disabled color from the /// current [Theme] and will not respond to presses or show the popup /// menu and [onSelected], [onCanceled] and [itemBuilder] will not be called. /// @@ -1289,7 +1283,7 @@ class PopupMenuButton<T> extends StatefulWidget { /// /// The [clipBehavior] argument is used the clip shape of the menu. /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; @override diff --git a/packages/flutter/lib/src/material/popup_menu_theme.dart b/packages/flutter/lib/src/material/popup_menu_theme.dart index eeda6177114b2..5d2c675398c5f 100644 --- a/packages/flutter/lib/src/material/popup_menu_theme.dart +++ b/packages/flutter/lib/src/material/popup_menu_theme.dart @@ -225,8 +225,6 @@ class PopupMenuThemeData with Diagnosticable { class PopupMenuTheme extends InheritedTheme { /// Creates a popup menu theme that controls the configurations for /// popup menus in its widget subtree. - /// - /// The data argument must not be null. const PopupMenuTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index c21c6b8ae6921..af73161d2a4d1 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -109,11 +109,12 @@ class RangeSlider extends StatefulWidget { /// Creates a Material Design range slider. /// /// The range slider widget itself does not maintain any state. Instead, when - /// the state of the slider changes, the widget calls the [onChanged] callback. - /// Most widgets that use a range slider will listen for the [onChanged] callback - /// and rebuild the slider with new [values] to update the visual appearance of - /// the slider. To know when the value starts to change, or when it is done - /// changing, set the optional callbacks [onChangeStart] and/or [onChangeEnd]. + /// the state of the slider changes, the widget calls the [onChanged] + /// callback. Most widgets that use a range slider will listen for the + /// [onChanged] callback and rebuild the slider with new [values] to update + /// the visual appearance of the slider. To know when the value starts to + /// change, or when it is done changing, set the optional callbacks + /// [onChangeStart] and/or [onChangeEnd]. /// /// * [values], which determines currently selected values for this range /// slider. @@ -128,11 +129,15 @@ class RangeSlider extends StatefulWidget { /// [inactiveColor] properties, although more fine-grained control of the /// appearance is achieved using a [SliderThemeData]. /// - /// The [values], [min], [max] must not be null. The [min] must be less than - /// or equal to the [max]. [values].start must be less than or equal to - /// [values].end. [values].start and [values].end must be greater than or - /// equal to the [min] and less than or equal to the [max]. The [divisions] - /// must be null or greater than 0. + /// The [min] must be less than or equal to the [max]. + /// + /// The [RangeValues.start] attribute of the [values] parameter must be less + /// than or equal to its [RangeValues.end] attribute. The [RangeValues.start] + /// and [RangeValues.end] attributes of the [values] parameter must be greater + /// than or equal to the [min] parameter and less than or equal to the [max] + /// parameter. + /// + /// The [divisions] parameter must be null or greater than zero. RangeSlider({ super.key, required this.values, diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index f1e820b3bcf40..87fb31857eb8b 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1642,7 +1642,7 @@ class Scaffold extends StatefulWidget { /// This is useful if the app bar's [AppBar.backgroundColor] is not /// completely opaque. /// - /// This property is false by default. It must not be null. + /// This property is false by default. /// /// See also: /// @@ -2516,7 +2516,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto double get _floatingActionButtonVisibilityValue => _floatingActionButtonVisibilityController.value; /// Sets the current value of the visibility animation for the - /// [Scaffold.floatingActionButton]. This value must not be null. + /// [Scaffold.floatingActionButton]. set _floatingActionButtonVisibilityValue(double newValue) { _floatingActionButtonVisibilityController.value = clampDouble(newValue, _floatingActionButtonVisibilityController.lowerBound, @@ -2752,8 +2752,6 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto Color _bodyScrimColor = Colors.black; /// Whether to show a [ModalBarrier] over the body of the scaffold. - /// - /// The `value` parameter must not be null. void showBodyScrim(bool value, double opacity) { if (_showBodyScrim == value && _bodyScrimColor.opacity == opacity) { return; @@ -3080,8 +3078,6 @@ class ScaffoldFeatureController<T extends Widget, U> { /// curve specified with the [curve] argument, after the finger is released. In /// such a case, the value of [startingPoint] would be the progress of the /// animation at the time when the finger was released. -/// -/// The [startingPoint] and [curve] arguments must not be null. class _BottomSheetSuspendedCurve extends ParametricCurve<double> { /// Creates a suspended curve. const _BottomSheetSuspendedCurve( diff --git a/packages/flutter/lib/src/material/scrollbar_theme.dart b/packages/flutter/lib/src/material/scrollbar_theme.dart index ac519a66b7a9e..5cee3bfd45414 100644 --- a/packages/flutter/lib/src/material/scrollbar_theme.dart +++ b/packages/flutter/lib/src/material/scrollbar_theme.dart @@ -172,8 +172,6 @@ class ScrollbarThemeData with Diagnosticable { /// Linearly interpolate between two Scrollbar themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static ScrollbarThemeData lerp(ScrollbarThemeData? a, ScrollbarThemeData? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 4897de7449df8..1c68a4fd8496f 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -142,8 +142,6 @@ class SearchAnchor extends StatefulWidget { /// /// ** See code in examples/api/lib/material/search_anchor/search_anchor.0.dart ** /// {@end-tool} - /// - /// The [suggestionsBuilder] argument must not be null. factory SearchAnchor.bar({ Widget? barLeading, Iterable<Widget>? barTrailing, @@ -295,8 +293,6 @@ class SearchAnchor extends StatefulWidget { /// /// The widget returned by this builder is faded out when it is tapped. /// At the same time a search view route is faded in. - /// - /// This must not be null. final SearchAnchorChildBuilder builder; /// Called to get the suggestion list for the search view. diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index 8616a4f8ba42d..508302bc7ebb3 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -174,9 +174,9 @@ class SelectableText extends StatefulWidget { /// closest enclosing [DefaultTextStyle]. /// - /// The [showCursor], [autofocus], [dragStartBehavior], [selectionHeightStyle], - /// [selectionWidthStyle] and [data] parameters must not be null. If specified, - /// the [maxLines] argument must be greater than zero. + /// If the [showCursor], [autofocus], [dragStartBehavior], + /// [selectionHeightStyle], [selectionWidthStyle] and [data] arguments are + /// specified, the [maxLines] argument must be greater than zero. const SelectableText( String this.data, { super.key, @@ -232,10 +232,8 @@ class SelectableText extends StatefulWidget { /// Creates a selectable text widget with a [TextSpan]. /// - /// The [textSpan] parameter must not be null and only contain [TextSpan] in - /// [textSpan].children. Other type of [InlineSpan] is not allowed. - /// - /// The [autofocus] and [dragStartBehavior] arguments must not be null. + /// The [TextSpan.children] attribute of the [textSpan] parameter must only + /// contain [TextSpan]s. Other types of [InlineSpan] are not allowed. const SelectableText.rich( TextSpan this.textSpan, { super.key, diff --git a/packages/flutter/lib/src/material/slider_theme.dart b/packages/flutter/lib/src/material/slider_theme.dart index 492de070e7288..18648fe459367 100644 --- a/packages/flutter/lib/src/material/slider_theme.dart +++ b/packages/flutter/lib/src/material/slider_theme.dart @@ -49,8 +49,6 @@ import 'theme.dart'; /// the [RangeSlider]'s tick marks. class SliderTheme extends InheritedTheme { /// Applies the given theme [data] to [child]. - /// - /// The [data] and [child] arguments must not be null. const SliderTheme({ super.key, required this.data, @@ -655,8 +653,6 @@ class SliderThemeData with Diagnosticable { /// Linearly interpolate between two slider themes. /// - /// The arguments must not be null. - /// /// {@macro dart.ui.shadow.lerp} static SliderThemeData lerp(SliderThemeData a, SliderThemeData b, double t) { if (identical(a, b)) { diff --git a/packages/flutter/lib/src/material/snack_bar.dart b/packages/flutter/lib/src/material/snack_bar.dart index ce3df05095567..85df795b313cd 100644 --- a/packages/flutter/lib/src/material/snack_bar.dart +++ b/packages/flutter/lib/src/material/snack_bar.dart @@ -83,8 +83,6 @@ enum SnackBarClosedReason { /// * <https://material.io/design/components/snackbars.html> class SnackBarAction extends StatefulWidget { /// Creates an action for a [SnackBar]. - /// - /// The [label] and [onPressed] arguments must be non-null. const SnackBarAction({ super.key, this.textColor, @@ -127,7 +125,7 @@ class SnackBarAction extends StatefulWidget { /// The button label. final String label; - /// The callback to be called when the button is pressed. Must not be null. + /// The callback to be called when the button is pressed. /// /// This callback will be called at most once each time this action is /// displayed in a [SnackBar]. @@ -272,8 +270,7 @@ class _SnackBarActionState extends State<SnackBarAction> { class SnackBar extends StatefulWidget { /// Creates a snack bar. /// - /// The [content] argument must be non-null. The [elevation] must be null or - /// non-negative. + /// The [elevation] must be null or non-negative. const SnackBar({ super.key, required this.content, @@ -466,12 +463,12 @@ class SnackBar extends StatefulWidget { /// The direction in which the SnackBar can be dismissed. /// - /// Cannot be null, defaults to [DismissDirection.down]. + /// Defaults to [DismissDirection.down]. final DismissDirection dismissDirection; /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; // API for ScaffoldMessengerState.showSnackBar(): diff --git a/packages/flutter/lib/src/material/snack_bar_theme.dart b/packages/flutter/lib/src/material/snack_bar_theme.dart index faf8ea72fe2e5..938c0b9e83515 100644 --- a/packages/flutter/lib/src/material/snack_bar_theme.dart +++ b/packages/flutter/lib/src/material/snack_bar_theme.dart @@ -196,8 +196,6 @@ class SnackBarThemeData with Diagnosticable { /// Linearly interpolate between two SnackBar Themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static SnackBarThemeData lerp(SnackBarThemeData? a, SnackBarThemeData? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/stepper.dart b/packages/flutter/lib/src/material/stepper.dart index b6ab24a64a74c..470fe0975f91c 100644 --- a/packages/flutter/lib/src/material/stepper.dart +++ b/packages/flutter/lib/src/material/stepper.dart @@ -134,8 +134,6 @@ const double _kTriangleHeight = _kStepSize * 0.866025; // Triangle height. sqrt( @immutable class Step { /// Creates a step for a [Stepper]. - /// - /// The [title], [content], and [state] arguments must not be null. const Step({ required this.title, this.subtitle, @@ -197,8 +195,6 @@ class Stepper extends StatefulWidget { /// This widget is not meant to be rebuilt with a different list of steps /// unless a key is provided in order to distinguish the old stepper from the /// new one. - /// - /// The [steps], [type], and [currentStep] arguments must not be null. const Stepper({ super.key, required this.steps, diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index e301c8578b8ce..aca371a684aff 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -178,8 +178,6 @@ class Switch extends StatelessWidget { _switchType = _SwitchType.adaptive; /// Whether this switch is on or off. - /// - /// This property must not be null. final bool value; /// Called when the user toggles the switch on or off. diff --git a/packages/flutter/lib/src/material/switch_list_tile.dart b/packages/flutter/lib/src/material/switch_list_tile.dart index be09ce380c799..3ee9a39071c1d 100644 --- a/packages/flutter/lib/src/material/switch_list_tile.dart +++ b/packages/flutter/lib/src/material/switch_list_tile.dart @@ -261,8 +261,6 @@ class SwitchListTile extends StatelessWidget { assert(inactiveThumbImage != null || onInactiveThumbImageError == null); /// Whether this switch is checked. - /// - /// This property must not be null. final bool value; /// Called when the user toggles the switch on or off. diff --git a/packages/flutter/lib/src/material/tab_bar_theme.dart b/packages/flutter/lib/src/material/tab_bar_theme.dart index e65e8b3c4db82..1f45037ad0ea8 100644 --- a/packages/flutter/lib/src/material/tab_bar_theme.dart +++ b/packages/flutter/lib/src/material/tab_bar_theme.dart @@ -141,8 +141,6 @@ class TabBarTheme with Diagnosticable { /// Linearly interpolate between two tab bar themes. /// - /// The arguments must not be null. - /// /// {@macro dart.ui.shadow.lerp} static TabBarTheme lerp(TabBarTheme a, TabBarTheme b, double t) { if (identical(a, b)) { diff --git a/packages/flutter/lib/src/material/tab_controller.dart b/packages/flutter/lib/src/material/tab_controller.dart index 0229fe17c418e..3e1bbe362c4a4 100644 --- a/packages/flutter/lib/src/material/tab_controller.dart +++ b/packages/flutter/lib/src/material/tab_controller.dart @@ -95,12 +95,12 @@ class TabController extends ChangeNotifier { /// Creates an object that manages the state required by [TabBar] and a /// [TabBarView]. /// - /// The [length] must not be null or negative. Typically it's a value greater - /// than one, i.e. typically there are two or more tabs. The [length] must - /// match [TabBar.tabs]'s and [TabBarView.children]'s length. + /// The [length] must not be negative. Typically it's a value greater than + /// one, i.e. typically there are two or more tabs. The [length] must match + /// [TabBar.tabs]'s and [TabBarView.children]'s length. /// - /// The `initialIndex` must be valid given [length] and must not be null. If - /// [length] is zero, then `initialIndex` must be 0 (the default). + /// The `initialIndex` must be valid given [length]. If [length] is zero, then + /// `initialIndex` must be 0 (the default). TabController({ int initialIndex = 0, Duration? animationDuration, @@ -342,8 +342,6 @@ class DefaultTabController extends StatefulWidget { /// /// The [length] argument is typically greater than one. The [length] must /// match [TabBar.tabs]'s and [TabBarView.children]'s length. - /// - /// The [initialIndex] argument must not be null. const DefaultTabController({ super.key, required this.length, diff --git a/packages/flutter/lib/src/material/tab_indicator.dart b/packages/flutter/lib/src/material/tab_indicator.dart index dbe30d136d4a1..1b46a7f06e290 100644 --- a/packages/flutter/lib/src/material/tab_indicator.dart +++ b/packages/flutter/lib/src/material/tab_indicator.dart @@ -17,8 +17,6 @@ import 'colors.dart'; /// or the entire tab with [TabBarIndicatorSize.tab]. class UnderlineTabIndicator extends Decoration { /// Create an underline style selected tab indicator. - /// - /// The [borderSide] and [insets] arguments must not be null. const UnderlineTabIndicator({ this.borderRadius, this.borderSide = const BorderSide(width: 2.0, color: Colors.white), diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 761540d77c91b..9976dd21e30d3 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -736,15 +736,15 @@ class _TabBarScrollController extends ScrollController { class TabBar extends StatefulWidget implements PreferredSizeWidget { /// Creates a Material Design primary tab bar. /// - /// The [tabs] argument must not be null and its length must match the [controller]'s + /// The length of the [tabs] argument must match the [controller]'s /// [TabController.length]. /// /// If a [TabController] is not provided, then there must be a /// [DefaultTabController] ancestor. /// - /// The [indicatorWeight] parameter defaults to 2, and must not be null. + /// The [indicatorWeight] parameter defaults to 2. /// - /// The [indicatorPadding] parameter defaults to [EdgeInsets.zero], and must not be null. + /// The [indicatorPadding] parameter defaults to [EdgeInsets.zero]. /// /// If [indicator] is not null or provided from [TabBarTheme], /// then [indicatorWeight] and [indicatorColor] are ignored. @@ -2046,8 +2046,6 @@ class _TabBarViewState extends State<TabBarView> { /// Used by [TabPageSelector] to indicate the selected page. class TabPageSelectorIndicator extends StatelessWidget { /// Creates an indicator used by [TabPageSelector]. - /// - /// The [backgroundColor], [borderColor], and [size] parameters must not be null. const TabPageSelectorIndicator({ super.key, required this.backgroundColor, diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index 223c7f3b03ecc..e29b5684585cf 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -73,9 +73,7 @@ import 'theme_data.dart'; /// * <https://material.io/design/components/buttons.html> /// * <https://m3.material.io/components/buttons> class TextButton extends ButtonStyleButton { - /// Create a TextButton. - /// - /// The [autofocus] and [clipBehavior] arguments must not be null. + /// Create a [TextButton]. const TextButton({ super.key, required super.onPressed, @@ -96,8 +94,6 @@ class TextButton extends ButtonStyleButton { /// /// The icon and label are arranged in a row and padded by 8 logical pixels /// at the ends, with an 8 pixel gap in between. - /// - /// The [icon] and [label] arguments must not be null. factory TextButton.icon({ Key? key, required VoidCallback? onPressed, diff --git a/packages/flutter/lib/src/material/text_button_theme.dart b/packages/flutter/lib/src/material/text_button_theme.dart index 4b13a922fbf72..79a2f4016385d 100644 --- a/packages/flutter/lib/src/material/text_button_theme.dart +++ b/packages/flutter/lib/src/material/text_button_theme.dart @@ -91,8 +91,6 @@ class TextButtonThemeData with Diagnosticable { /// [ButtonStyle] for [TextButton]s below the overall [Theme]. class TextButtonTheme extends InheritedTheme { /// Create a [TextButtonTheme]. - /// - /// The [data] parameter must not be null. const TextButtonTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 9679f0c47d3d3..e8ea4289967d8 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -238,13 +238,7 @@ class TextField extends StatefulWidget { /// /// The [selectionHeightStyle] and [selectionWidthStyle] properties allow /// changing the shape of the selection highlighting. These properties default - /// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively and - /// must not be null. - /// - /// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect], - /// [scrollPadding], [maxLines], [maxLength], [selectionHeightStyle], - /// [selectionWidthStyle], [enableSuggestions], and - /// [enableIMEPersonalizedLearning] arguments must not be null. + /// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight], respectively. /// /// See also: /// diff --git a/packages/flutter/lib/src/material/text_selection_theme.dart b/packages/flutter/lib/src/material/text_selection_theme.dart index 676cdc38a6462..b7e659ae4d498 100644 --- a/packages/flutter/lib/src/material/text_selection_theme.dart +++ b/packages/flutter/lib/src/material/text_selection_theme.dart @@ -140,8 +140,6 @@ class TextSelectionThemeData with Diagnosticable { class TextSelectionTheme extends InheritedTheme { /// Creates a text selection theme widget that specifies the text /// selection properties for all widgets below it in the widget tree. - /// - /// The data argument must not be null. const TextSelectionTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/theme.dart b/packages/flutter/lib/src/material/theme.dart index 8bbc12cefe7ca..c55efc2aeb291 100644 --- a/packages/flutter/lib/src/material/theme.dart +++ b/packages/flutter/lib/src/material/theme.dart @@ -36,8 +36,6 @@ const Duration kThemeAnimationDuration = Duration(milliseconds: 200); /// the [MaterialApp.theme] argument. class Theme extends StatelessWidget { /// Applies the given theme [data] to [child]. - /// - /// The [data] and [child] arguments must not be null. const Theme({ super.key, required this.data, @@ -201,8 +199,7 @@ class ThemeDataTween extends Tween<ThemeData> { class AnimatedTheme extends ImplicitlyAnimatedWidget { /// Creates an animated theme. /// - /// By default, the theme transition uses a linear curve. The [data] and - /// [child] arguments must not be null. + /// By default, the theme transition uses a linear curve. const AnimatedTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index 6a24b4f30c760..ff00c152dc7b9 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -784,8 +784,6 @@ class ThemeData with Diagnosticable { /// Create a [ThemeData] based on the colors in the given [colorScheme] and /// text styles of the optional [textTheme]. /// - /// The [colorScheme] can not be null. - /// /// If [colorScheme].brightness is [Brightness.dark] then /// [ThemeData.applyElevationOverlayColor] will be set to true to support /// the Material dark theme method for indicating elevation by applying @@ -1795,8 +1793,6 @@ class ThemeData with Diagnosticable { /// Linearly interpolate between two themes. /// - /// The arguments must not be null. - /// /// {@macro dart.ui.shadow.lerp} static ThemeData lerp(ThemeData a, ThemeData b, double t) { if (identical(a, b)) { @@ -2245,8 +2241,6 @@ class ThemeData with Diagnosticable { class MaterialBasedCupertinoThemeData extends CupertinoThemeData { /// Create a [MaterialBasedCupertinoThemeData] based on a Material [ThemeData] /// and its `cupertinoOverrideTheme`. - /// - /// The [materialTheme] parameter must not be null. MaterialBasedCupertinoThemeData({ required ThemeData materialTheme, }) : this._( @@ -2373,8 +2367,6 @@ class _FifoCache<K, V> { /// Returns the previously cached value for the given key, if available; /// if not, calls the given callback to obtain it first. - /// - /// The arguments must not be null. V putIfAbsent(K key, V Function() loader) { assert(key != null); final V? result = _cache[key]; @@ -2427,9 +2419,8 @@ class _FifoCache<K, V> { class VisualDensity with Diagnosticable { /// A const constructor for [VisualDensity]. /// - /// All of the arguments must be non-null, and [horizontal] and [vertical] - /// must be in the interval between [minimumDensity] and [maximumDensity], - /// inclusive. + /// The [horizontal] and [vertical] arguments must be in the interval between + /// [minimumDensity] and [maximumDensity], inclusive. const VisualDensity({ this.horizontal = 0.0, this.vertical = 0.0, diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index d55ab6a077693..52d176fa31358 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2108,8 +2108,6 @@ typedef EntryModeChangeCallback = void Function(TimePickerEntryMode); /// Use [showTimePicker] to show a dialog already containing a [TimePickerDialog]. class TimePickerDialog extends StatefulWidget { /// Creates a Material Design time picker. - /// - /// [initialTime] must not be null. const TimePickerDialog({ super.key, required this.initialTime, diff --git a/packages/flutter/lib/src/material/time_picker_theme.dart b/packages/flutter/lib/src/material/time_picker_theme.dart index 1d0a95776db74..30983f9ec14b4 100644 --- a/packages/flutter/lib/src/material/time_picker_theme.dart +++ b/packages/flutter/lib/src/material/time_picker_theme.dart @@ -301,8 +301,6 @@ class TimePickerThemeData with Diagnosticable { /// Linearly interpolate between two time picker themes. /// - /// The argument `t` must not be null. - /// /// {@macro dart.ui.shadow.lerp} static TimePickerThemeData lerp(TimePickerThemeData? a, TimePickerThemeData? b, double t) { if (identical(a, b) && a != null) { diff --git a/packages/flutter/lib/src/material/toggle_buttons.dart b/packages/flutter/lib/src/material/toggle_buttons.dart index 4b786f3ca96da..731bf9781695e 100644 --- a/packages/flutter/lib/src/material/toggle_buttons.dart +++ b/packages/flutter/lib/src/material/toggle_buttons.dart @@ -205,9 +205,8 @@ class ToggleButtons extends StatelessWidget { /// /// Both [children] and [isSelected] properties arguments are required. /// - /// [isSelected] values must be non-null. [focusNodes] must be null or a - /// list of non-null nodes. [renderBorder] and [direction] must not be null. - /// If [direction] is [Axis.vertical], [verticalDirection] must not be null. + /// The [focusNodes] argument must be null or a list of nodes. If [direction] + /// is [Axis.vertical], [verticalDirection] must not be null. const ToggleButtons({ super.key, required this.children, diff --git a/packages/flutter/lib/src/material/toggle_buttons_theme.dart b/packages/flutter/lib/src/material/toggle_buttons_theme.dart index 199ec362928b7..24dbaa7aa1f53 100644 --- a/packages/flutter/lib/src/material/toggle_buttons_theme.dart +++ b/packages/flutter/lib/src/material/toggle_buttons_theme.dart @@ -246,8 +246,6 @@ class ToggleButtonsThemeData with Diagnosticable { class ToggleButtonsTheme extends InheritedTheme { /// Creates a toggle buttons theme that controls the color and border /// parameters for [ToggleButtons]. - /// - /// The data argument must not be null. const ToggleButtonsTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart index 2be81e1ba51cc..7db630ccb38b1 100644 --- a/packages/flutter/lib/src/material/tooltip.dart +++ b/packages/flutter/lib/src/material/tooltip.dart @@ -820,8 +820,6 @@ class TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin { /// below a target specified in the global coordinate system. class _TooltipPositionDelegate extends SingleChildLayoutDelegate { /// Creates a delegate for computing the layout of a tooltip. - /// - /// The arguments must not be null. _TooltipPositionDelegate({ required this.target, required this.verticalOffset, diff --git a/packages/flutter/lib/src/material/tooltip_theme.dart b/packages/flutter/lib/src/material/tooltip_theme.dart index 3f3c28dc539fd..a2542d6d085ff 100644 --- a/packages/flutter/lib/src/material/tooltip_theme.dart +++ b/packages/flutter/lib/src/material/tooltip_theme.dart @@ -262,8 +262,6 @@ class TooltipThemeData with Diagnosticable { class TooltipTheme extends InheritedTheme { /// Creates a tooltip theme that controls the configurations for /// [Tooltip]. - /// - /// The data argument must not be null. const TooltipTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/material/tooltip_visibility.dart b/packages/flutter/lib/src/material/tooltip_visibility.dart index ff151324348a3..52642317a6007 100644 --- a/packages/flutter/lib/src/material/tooltip_visibility.dart +++ b/packages/flutter/lib/src/material/tooltip_visibility.dart @@ -26,8 +26,6 @@ class _TooltipVisibilityScope extends InheritedWidget { /// continues to provide any semantic information that is provided. class TooltipVisibility extends StatelessWidget { /// Creates a widget that configures the visibility of [Tooltip]. - /// - /// Both arguments must not be null. const TooltipVisibility({ super.key, required this.visible, From e300fda76783362db9cbb3ac51454ce2fe59c667 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 00:51:11 -0400 Subject: [PATCH 1350/1547] Roll Flutter Engine from 5a924a9017d7 to 81b93fc4a2cc (2 revisions) (#135093) https://github.com/flutter/engine/compare/5a924a9017d7...81b93fc4a2cc 2023-09-20 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 06g6i7-5u8O-FOTSi... to kGkqpvcPI1TGmR4Sc... (flutter/engine#46079) 2023-09-20 godofredoc@google.com Use magic envs to pass commit and temp folder. (flutter/engine#46015) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 06g6i7-5u8O- to kGkqpvcPI1TG If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f5643d7a6a205..11666252e435b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5a924a9017d764bc5c08d21a76f6ab52bba3a6f1 +81b93fc4a2cc02f067acfe19574eb2ccc316fed7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index f7ba18dba0bde..d40166ed1086a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -06g6i7-5u8O-FOTSiXV49zPhENc4ZaXzGkSyFuDpJQgC +kGkqpvcPI1TGmR4Scp19EXK5hxyrDBhn2-hp4U8E6skC From a5db10e43ced5df7dfb49f77fd2f75f92c609503 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 02:00:03 -0400 Subject: [PATCH 1351/1547] Roll Flutter Engine from 81b93fc4a2cc to 36379b62bec8 (2 revisions) (#135095) https://github.com/flutter/engine/compare/81b93fc4a2cc...36379b62bec8 2023-09-20 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from ZhY53WD7bFJSA3xoO... to aHtib4LBcLwx7JwK-... (flutter/engine#46082) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 1a8885b9e03c to 5d916c04e9fc (6 revisions) (flutter/engine#46081) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from ZhY53WD7bFJS to aHtib4LBcLwx If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 11666252e435b..1858f9445b52f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -81b93fc4a2cc02f067acfe19574eb2ccc316fed7 +36379b62bec845f1238e02b252ba78bc605b1c42 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index a867f8b1ddce9..144340c0c9743 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ZhY53WD7bFJSA3xoOchmSzb5zambmf3zOGFuK0GVv_YC +aHtib4LBcLwx7JwK-pLiQPleFerXUt7If4yJSTh4tUcC From 1e56af5a2eccbcbe82d7ddeac48ea916dd0a0412 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 02:49:05 -0400 Subject: [PATCH 1352/1547] Roll Flutter Engine from 36379b62bec8 to 24f7ac38dfa2 (2 revisions) (#135096) https://github.com/flutter/engine/compare/36379b62bec8...24f7ac38dfa2 2023-09-20 bdero@google.com [Impeller] Use BlackTransparent clear color when backdrop filters are present. (flutter/engine#46085) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 5d916c04e9fc to d6325ec2f053 (1 revision) (flutter/engine#46083) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1858f9445b52f..1260106322481 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -36379b62bec845f1238e02b252ba78bc605b1c42 +24f7ac38dfa25de991ed67c68abf7d0581b2d2f6 From 3c25a9f2ca5b4ad07225b95735fb1c1d312af300 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 03:31:05 -0400 Subject: [PATCH 1353/1547] Roll Flutter Engine from 24f7ac38dfa2 to 9c6b2500282b (3 revisions) (#135098) https://github.com/flutter/engine/compare/24f7ac38dfa2...9c6b2500282b 2023-09-20 skia-flutter-autoroll@skia.org Roll Dart SDK from b8f006d88c07 to b3fd178ce59f (3 revisions) (flutter/engine#46087) 2023-09-20 bdero@google.com [Impeller] Ensure that reused textures are cleared before getting sampled by backdrop textures (flutter/engine#46084) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from d6325ec2f053 to e9b9e9a4f541 (1 revision) (flutter/engine#46086) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1260106322481..4787d0a69a132 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -24f7ac38dfa25de991ed67c68abf7d0581b2d2f6 +9c6b2500282b6810957bc000e1ca217e7bfd2d4f From aae6c6d7fbdbe042d5a2b8a96e727bd6bd1c0d8b Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 04:36:30 -0400 Subject: [PATCH 1354/1547] Roll Flutter Engine from 9c6b2500282b to df4e6c079682 (1 revision) (#135101) https://github.com/flutter/engine/compare/9c6b2500282b...df4e6c079682 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from e9b9e9a4f541 to e3aa86332255 (1 revision) (flutter/engine#46088) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4787d0a69a132..0392ec56e60c6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9c6b2500282b6810957bc000e1ca217e7bfd2d4f +df4e6c0796829391a1f76c5e3237eda4359cf2c3 From cb4b402ce5535e53aa7c5fa277f8febb70e4df24 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 05:24:31 -0400 Subject: [PATCH 1355/1547] Roll Flutter Engine from df4e6c079682 to 83b4df415bf3 (2 revisions) (#135102) https://github.com/flutter/engine/compare/df4e6c079682...83b4df415bf3 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 14e9b3c91c64 to 7d9d5ac84d8f (1 revision) (flutter/engine#46090) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from e3aa86332255 to 14e9b3c91c64 (1 revision) (flutter/engine#46089) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0392ec56e60c6..2741f0115d5b3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -df4e6c0796829391a1f76c5e3237eda4359cf2c3 +83b4df415bf36a3e15f7a8eeefe94abd6da560d6 From d0004c9513f30f1e99962b3d1884d354fe12d7c3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 07:52:35 -0400 Subject: [PATCH 1356/1547] Roll Flutter Engine from 83b4df415bf3 to 67d4aaef3c7b (1 revision) (#135128) https://github.com/flutter/engine/compare/83b4df415bf3...67d4aaef3c7b 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 7d9d5ac84d8f to d7f2d1083979 (1 revision) (flutter/engine#46091) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2741f0115d5b3..75ef6f0696eb0 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -83b4df415bf36a3e15f7a8eeefe94abd6da560d6 +67d4aaef3c7b82c5bee549f3cd0fbf12259762e2 From c3db02099368f538e5361d812a07709cddaa813d Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Wed, 20 Sep 2023 16:34:23 +0200 Subject: [PATCH 1357/1547] Cover more test/widgets tests with leak tracking #9 (#135054) --- .../widgets/selection_container_test.dart | 28 ++++-- .../test/widgets/semantics_10_test.dart | 3 +- .../test/widgets/semantics_11_test.dart | 3 +- .../test/widgets/semantics_1_test.dart | 3 +- .../test/widgets/semantics_2_test.dart | 3 +- .../test/widgets/semantics_3_test.dart | 3 +- .../test/widgets/semantics_4_test.dart | 3 +- .../test/widgets/semantics_5_test.dart | 3 +- .../test/widgets/semantics_6_test.dart | 3 +- .../test/widgets/semantics_7_test.dart | 3 +- .../test/widgets/semantics_8_test.dart | 3 +- .../test/widgets/semantics_9_test.dart | 7 +- ...semantics_child_configs_delegate_test.dart | 11 ++- .../test/widgets/semantics_clipping_test.dart | 5 +- .../test/widgets/semantics_debugger_test.dart | 27 ++--- .../semantics_keep_alive_offstage_test.dart | 4 +- .../test/widgets/semantics_merge_test.dart | 5 +- .../flutter/test/widgets/semantics_test.dart | 61 ++++++------ ...ssion_for_current_semantics_tree_test.dart | 5 +- .../test/widgets/semantics_tester_test.dart | 3 +- .../widgets/semantics_traversal_test.dart | 3 +- .../semantics_zero_surface_size_test.dart | 3 +- .../test/widgets/set_state_1_test.dart | 3 +- .../test/widgets/set_state_2_test.dart | 3 +- .../test/widgets/set_state_3_test.dart | 3 +- .../test/widgets/set_state_4_test.dart | 3 +- .../test/widgets/set_state_5_test.dart | 3 +- .../test/widgets/shader_mask_test.dart | 7 +- .../flutter/test/widgets/shadow_test.dart | 9 +- .../test/widgets/shape_decoration_test.dart | 11 ++- .../test/widgets/shared_app_data_test.dart | 7 +- .../flutter/test/widgets/shortcuts_test.dart | 92 +++++++++-------- .../test/widgets/simple_semantics_test.dart | 5 +- .../single_child_scroll_view_test.dart | 99 +++++++++++++------ ...size_changed_layout_notification_test.dart | 3 +- .../flutter/test/widgets/sized_box_test.dart | 9 +- .../widgets/sliver_appbar_opacity_test.dart | 31 ++++-- .../sliver_constrained_cross_axis_test.dart | 11 ++- .../test/widgets/sliver_constraints_test.dart | 3 +- .../widgets/sliver_cross_axis_group_test.dart | 57 ++++++----- .../widgets/sliver_fill_remaining_test.dart | 45 +++++---- 41 files changed, 366 insertions(+), 230 deletions(-) diff --git a/packages/flutter/test/widgets/selection_container_test.dart b/packages/flutter/test/widgets/selection_container_test.dart index 3c7648c9209c7..c6ceebf778106 100644 --- a/packages/flutter/test/widgets/selection_container_test.dart +++ b/packages/flutter/test/widgets/selection_container_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { @@ -20,9 +21,11 @@ void main() { ); } - testWidgets('updates its registrar and delegate based on the number of selectables', (WidgetTester tester) async { + testWidgetsWithLeakTracking('updates its registrar and delegate based on the number of selectables', (WidgetTester tester) async { final TestSelectionRegistrar registrar = TestSelectionRegistrar(); final TestContainerDelegate delegate = TestContainerDelegate(); + addTearDown(delegate.dispose); + await pumpContainer( tester, SelectionContainer( @@ -42,9 +45,11 @@ void main() { expect(delegate.selectables.length, 3); }); - testWidgets('disabled container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('disabled container', (WidgetTester tester) async { final TestSelectionRegistrar registrar = TestSelectionRegistrar(); final TestContainerDelegate delegate = TestContainerDelegate(); + addTearDown(delegate.dispose); + await pumpContainer( tester, SelectionContainer( @@ -65,10 +70,13 @@ void main() { expect(delegate.selectables.length, 0); }); - testWidgets('Swapping out container delegate does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swapping out container delegate does not crash', (WidgetTester tester) async { final TestSelectionRegistrar registrar = TestSelectionRegistrar(); final TestContainerDelegate delegate = TestContainerDelegate(); + addTearDown(delegate.dispose); final TestContainerDelegate childDelegate = TestContainerDelegate(); + addTearDown(childDelegate.dispose); + await pumpContainer( tester, SelectionContainer( @@ -90,6 +98,8 @@ void main() { expect(delegate.value.hasContent, isTrue); final TestContainerDelegate newDelegate = TestContainerDelegate(); + addTearDown(newDelegate.dispose); + await pumpContainer( tester, SelectionContainer( @@ -112,10 +122,13 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Can update within one frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can update within one frame', (WidgetTester tester) async { final TestSelectionRegistrar registrar = TestSelectionRegistrar(); final TestContainerDelegate delegate = TestContainerDelegate(); + addTearDown(delegate.dispose); final TestContainerDelegate childDelegate = TestContainerDelegate(); + addTearDown(childDelegate.dispose); + await pumpContainer( tester, SelectionContainer( @@ -139,9 +152,11 @@ void main() { expect(delegate.value.hasContent, isTrue); }); - testWidgets('selection container registers itself if there is a selectable child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection container registers itself if there is a selectable child', (WidgetTester tester) async { final TestSelectionRegistrar registrar = TestSelectionRegistrar(); final TestContainerDelegate delegate = TestContainerDelegate(); + addTearDown(delegate.dispose); + await pumpContainer( tester, SelectionContainer( @@ -181,9 +196,10 @@ void main() { expect(registrar.selectables.length, 0); }); - testWidgets('selection container gets registrar from context if not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection container gets registrar from context if not provided', (WidgetTester tester) async { final TestSelectionRegistrar registrar = TestSelectionRegistrar(); final TestContainerDelegate delegate = TestContainerDelegate(); + addTearDown(delegate.dispose); await pumpContainer( tester, diff --git a/packages/flutter/test/widgets/semantics_10_test.dart b/packages/flutter/test/widgets/semantics_10_test.dart index 0ef416efd64bf..d550253e9bbb9 100644 --- a/packages/flutter/test/widgets/semantics_10_test.dart +++ b/packages/flutter/test/widgets/semantics_10_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('can cease to be semantics boundary after markNeedsSemanticsUpdate() has already been called once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can cease to be semantics boundary after markNeedsSemanticsUpdate() has already been called once', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_11_test.dart b/packages/flutter/test/widgets/semantics_11_test.dart index 7979f319d6075..05b1d572eda8f 100644 --- a/packages/flutter/test/widgets/semantics_11_test.dart +++ b/packages/flutter/test/widgets/semantics_11_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('markNeedsSemanticsUpdate() called on non-boundary with non-boundary parent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('markNeedsSemanticsUpdate() called on non-boundary with non-boundary parent', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_1_test.dart b/packages/flutter/test/widgets/semantics_1_test.dart index 7d475627942f2..3631f73d2b2e3 100644 --- a/packages/flutter/test/widgets/semantics_1_test.dart +++ b/packages/flutter/test/widgets/semantics_1_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 1', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // smoketest diff --git a/packages/flutter/test/widgets/semantics_2_test.dart b/packages/flutter/test/widgets/semantics_2_test.dart index 2a0c69bf357fe..e56248d3d827a 100644 --- a/packages/flutter/test/widgets/semantics_2_test.dart +++ b/packages/flutter/test/widgets/semantics_2_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 2', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // this test is the same as the test in Semantics 1, but diff --git a/packages/flutter/test/widgets/semantics_3_test.dart b/packages/flutter/test/widgets/semantics_3_test.dart index 32c1ac218b13d..11757f5d5fda5 100644 --- a/packages/flutter/test/widgets/semantics_3_test.dart +++ b/packages/flutter/test/widgets/semantics_3_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 3', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // implicit annotators diff --git a/packages/flutter/test/widgets/semantics_4_test.dart b/packages/flutter/test/widgets/semantics_4_test.dart index 084e1d30a20f6..34ee195838e6b 100644 --- a/packages/flutter/test/widgets/semantics_4_test.dart +++ b/packages/flutter/test/widgets/semantics_4_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 4', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 4', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // O diff --git a/packages/flutter/test/widgets/semantics_5_test.dart b/packages/flutter/test/widgets/semantics_5_test.dart index 16859cb921c84..160c54303d334 100644 --- a/packages/flutter/test/widgets/semantics_5_test.dart +++ b/packages/flutter/test/widgets/semantics_5_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 5', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 5', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_6_test.dart b/packages/flutter/test/widgets/semantics_6_test.dart index 30c126126b726..88bd11fc1fb3c 100644 --- a/packages/flutter/test/widgets/semantics_6_test.dart +++ b/packages/flutter/test/widgets/semantics_6_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('can change semantics in a branch blocked by BlockSemantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can change semantics in a branch blocked by BlockSemantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final TestSemantics expectedSemantics = TestSemantics.root( diff --git a/packages/flutter/test/widgets/semantics_7_test.dart b/packages/flutter/test/widgets/semantics_7_test.dart index 2ad88a3c446bf..3f9af1cad843d 100644 --- a/packages/flutter/test/widgets/semantics_7_test.dart +++ b/packages/flutter/test/widgets/semantics_7_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 7 - Merging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 7 - Merging', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); String label; diff --git a/packages/flutter/test/widgets/semantics_8_test.dart b/packages/flutter/test/widgets/semantics_8_test.dart index 4fe5cd885f1b2..ffea309d169df 100644 --- a/packages/flutter/test/widgets/semantics_8_test.dart +++ b/packages/flutter/test/widgets/semantics_8_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics 8 - Merging with reset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics 8 - Merging with reset', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_9_test.dart b/packages/flutter/test/widgets/semantics_9_test.dart index 9152a13fce0e2..9d2ac510ef4ef 100644 --- a/packages/flutter/test/widgets/semantics_9_test.dart +++ b/packages/flutter/test/widgets/semantics_9_test.dart @@ -6,12 +6,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { group('BlockSemantics', () { - testWidgets('hides semantic nodes of siblings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hides semantic nodes of siblings', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Stack( @@ -49,7 +50,7 @@ void main() { semantics.dispose(); }); - testWidgets('does not hides semantic nodes of siblings outside the current semantic boundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not hides semantic nodes of siblings outside the current semantic boundary', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality(textDirection: TextDirection.ltr, child: Stack( @@ -103,7 +104,7 @@ void main() { semantics.dispose(); }); - testWidgets('node is semantic boundary and blocking previously painted nodes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('node is semantic boundary and blocking previously painted nodes', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey stackKey = GlobalKey(); diff --git a/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart b/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart index a562a53891d6f..b2e67726b1cae 100644 --- a/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart +++ b/packages/flutter/test/widgets/semantics_child_configs_delegate_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics can merge sibling group', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics can merge sibling group', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const SemanticsTag first = SemanticsTag('1'); const SemanticsTag second = SemanticsTag('2'); @@ -74,7 +75,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics can drop semantics config', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics can drop semantics config', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const SemanticsTag first = SemanticsTag('1'); const SemanticsTag second = SemanticsTag('2'); @@ -132,7 +133,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics throws when mark the same config twice case 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics throws when mark the same config twice case 1', (WidgetTester tester) async { const SemanticsTag first = SemanticsTag('1'); const SemanticsTag second = SemanticsTag('2'); const SemanticsTag third = SemanticsTag('3'); @@ -178,7 +179,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('Semantics throws when mark the same config twice case 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics throws when mark the same config twice case 2', (WidgetTester tester) async { const SemanticsTag first = SemanticsTag('1'); const SemanticsTag second = SemanticsTag('2'); const SemanticsTag third = SemanticsTag('3'); @@ -224,7 +225,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('RenderObject with semantics child delegate will mark correct boundary dirty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObject with semantics child delegate will mark correct boundary dirty', (WidgetTester tester) async { final UniqueKey inner = UniqueKey(); final UniqueKey boundaryParent = UniqueKey(); final UniqueKey grandBoundaryParent = UniqueKey(); diff --git a/packages/flutter/test/widgets/semantics_clipping_test.dart b/packages/flutter/test/widgets/semantics_clipping_test.dart index 73554422dceaf..8b63e86a08d25 100644 --- a/packages/flutter/test/widgets/semantics_clipping_test.dart +++ b/packages/flutter/test/widgets/semantics_clipping_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('SemanticNode.rect is clipped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticNode.rect is clipped', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const Directionality( @@ -67,7 +68,7 @@ void main() { semantics.dispose(); }); - testWidgets('SemanticsNode is not removed if out of bounds and merged into something within bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNode is not removed if out of bounds and merged into something within bounds', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const Directionality( diff --git a/packages/flutter/test/widgets/semantics_debugger_test.dart b/packages/flutter/test/widgets/semantics_debugger_test.dart index d5985b933d964..4c48e69664591 100644 --- a/packages/flutter/test/widgets/semantics_debugger_test.dart +++ b/packages/flutter/test/widgets/semantics_debugger_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SemanticsDebugger will schedule a frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger will schedule a frame', (WidgetTester tester) async { await tester.pumpWidget( SemanticsDebugger( child: Container(), @@ -17,7 +18,7 @@ void main() { expect(tester.binding.hasScheduledFrame, isTrue); }); - testWidgets('SemanticsDebugger smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger smoke test', (WidgetTester tester) async { // This is a smoketest to verify that adding a debugger doesn't crash. await tester.pumpWidget( @@ -61,7 +62,7 @@ void main() { expect(true, isTrue); // expect that we reach here without crashing }); - testWidgets('SemanticsDebugger reparents subtree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger reparents subtree', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget( @@ -147,7 +148,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('SemanticsDebugger interaction test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger interaction test', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -185,7 +186,7 @@ void main() { log.clear(); }); - testWidgets('SemanticsDebugger interaction test - negative', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger interaction test - negative', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -225,7 +226,7 @@ void main() { log.clear(); }); - testWidgets('SemanticsDebugger scroll test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger scroll test', (WidgetTester tester) async { final Key childKey = UniqueKey(); await tester.pumpWidget( @@ -268,7 +269,7 @@ void main() { expect(tester.getTopLeft(find.byKey(childKey)).dy, equals(0.0)); }); - testWidgets('SemanticsDebugger long press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger long press', (WidgetTester tester) async { bool didLongPress = false; await tester.pumpWidget( @@ -290,7 +291,7 @@ void main() { expect(didLongPress, isTrue); }); - testWidgets('SemanticsDebugger slider', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger slider', (WidgetTester tester) async { double value = 0.75; await tester.pumpWidget( @@ -337,7 +338,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('SemanticsDebugger checkbox', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger checkbox', (WidgetTester tester) async { final Key keyTop = UniqueKey(); final Key keyBottom = UniqueKey(); @@ -378,7 +379,7 @@ void main() { expect(valueTop, isFalse); }); - testWidgets('SemanticsDebugger checkbox message', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger checkbox message', (WidgetTester tester) async { final Key checkbox = UniqueKey(); final Key checkboxUnchecked = UniqueKey(); final Key checkboxDisabled = UniqueKey(); @@ -450,7 +451,7 @@ void main() { ); }); - testWidgets('SemanticsDebugger ignores duplicated label and tooltip for Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger ignores duplicated label and tooltip for Android', (WidgetTester tester) async { final Key child = UniqueKey(); final Key debugger = UniqueKey(); final bool isPlatformAndroid = defaultTargetPlatform == TargetPlatform.android; @@ -477,7 +478,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('SemanticsDebugger textfield', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger textfield', (WidgetTester tester) async { final UniqueKey textField = UniqueKey(); final UniqueKey debugger = UniqueKey(); @@ -504,7 +505,7 @@ void main() { ); }); - testWidgets('SemanticsDebugger label style is used in the painter.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsDebugger label style is used in the painter.', (WidgetTester tester) async { final UniqueKey debugger = UniqueKey(); const TextStyle labelStyle = TextStyle(color: Colors.amber); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_keep_alive_offstage_test.dart b/packages/flutter/test/widgets/semantics_keep_alive_offstage_test.dart index 8cffc4eb5f1d7..915b7fc6c6485 100644 --- a/packages/flutter/test/widgets/semantics_keep_alive_offstage_test.dart +++ b/packages/flutter/test/widgets/semantics_keep_alive_offstage_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Un-layouted RenderObject in keep alive offstage area do not crash semantics compiler', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Un-layouted RenderObject in keep alive offstage area do not crash semantics compiler', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/20313. final SemanticsTester semantics = SemanticsTester(tester); @@ -18,6 +19,7 @@ void main() { const double bottomScrollOffset = 3000.0; final ScrollController controller = ScrollController(initialScrollOffset: bottomScrollOffset); + addTearDown(controller.dispose); await tester.pumpWidget(_buildTestWidget( extraPadding: false, diff --git a/packages/flutter/test/widgets/semantics_merge_test.dart b/packages/flutter/test/widgets/semantics_merge_test.dart index a4a997d37b91e..82d3c8157aa4b 100644 --- a/packages/flutter/test/widgets/semantics_merge_test.dart +++ b/packages/flutter/test/widgets/semantics_merge_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -14,7 +15,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('MergeSemantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeSemantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // not merged @@ -120,7 +121,7 @@ void main() { semantics.dispose(); }); - testWidgets('MergeSemantics works if other nodes are implicitly merged into its node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MergeSemantics works if other nodes are implicitly merged into its node', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart index 8a95217212fcd..8ec5e33799432 100644 --- a/packages/flutter/test/widgets/semantics_test.dart +++ b/packages/flutter/test/widgets/semantics_test.dart @@ -7,6 +7,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -15,7 +16,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('Semantics shutdown and restart', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics shutdown and restart', (WidgetTester tester) async { SemanticsTester? semantics = SemanticsTester(tester); final TestSemantics expectedSemantics = TestSemantics.root( @@ -59,7 +60,7 @@ void main() { semantics.dispose(); }, semanticsEnabled: false); - testWidgets('Semantics tag only applies to immediate child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics tag only applies to immediate child', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -95,7 +96,7 @@ void main() { semantics.dispose(); }, semanticsEnabled: false); - testWidgets('Semantics tooltip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics tooltip', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final TestSemantics expectedSemantics = TestSemantics.root( @@ -123,7 +124,7 @@ void main() { semantics.dispose(); }); - testWidgets('Detach and reattach assert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Detach and reattach assert', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey key = GlobalKey(); @@ -201,7 +202,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics and Directionality - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics and Directionality - RTL', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -218,7 +219,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics and Directionality - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics and Directionality - LTR', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -235,7 +236,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics and Directionality - cannot override RTL with LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics and Directionality - cannot override RTL with LTR', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final TestSemantics expectedSemantics = TestSemantics.root( @@ -262,7 +263,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics and Directionality - cannot override LTR with RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics and Directionality - cannot override LTR with RTL', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final TestSemantics expectedSemantics = TestSemantics.root( @@ -289,7 +290,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics label and hint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics label and hint', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -319,7 +320,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics hints can merge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics hints can merge', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -355,7 +356,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics values do not merge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics values do not merge', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -406,7 +407,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics value and hint can merge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics value and hint can merge', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -442,7 +443,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics tagForChildren works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics tagForChildren works', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -490,7 +491,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widget supports all actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widget supports all actions', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<SemanticsAction> performedActions = <SemanticsAction>[]; @@ -580,7 +581,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widget supports all flags', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widget supports all flags', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // Checked state and toggled state are mutually exclusive. await tester.pumpWidget( @@ -710,7 +711,7 @@ void main() { expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); }); - testWidgets('Actions can be replaced without triggering semantics update', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Actions can be replaced without triggering semantics update', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int semanticsUpdateCount = 0; final SemanticsHandle handle = tester.binding.pipelineOwner.ensureSemantics( @@ -807,7 +808,7 @@ void main() { semantics.dispose(); }); - testWidgets('onTapHint and onLongPressHint create custom actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTapHint and onLongPressHint create custom actions', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); await tester.pumpWidget(Semantics( container: true, @@ -833,7 +834,7 @@ void main() { semantics.dispose(); }); - testWidgets('CustomSemanticsActions can be added to a Semantics widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomSemanticsActions can be added to a Semantics widget', (WidgetTester tester) async { final SemanticsHandle semantics = tester.ensureSemantics(); await tester.pumpWidget(Semantics( container: true, @@ -852,7 +853,7 @@ void main() { semantics.dispose(); }); - testWidgets('Increased/decreased values are annotated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Increased/decreased values are annotated', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -884,7 +885,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widgets built in a widget tree are sorted properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widgets built in a widget tree are sorted properly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int semanticsUpdateCount = 0; final SemanticsHandle handle = tester.binding.pipelineOwner.ensureSemantics( @@ -967,7 +968,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widgets built with explicit sort orders are sorted properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widgets built with explicit sort orders are sorted properly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int semanticsUpdateCount = 0; final SemanticsHandle handle = tester.binding.pipelineOwner.ensureSemantics( @@ -1025,7 +1026,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widgets without sort orders are sorted properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widgets without sort orders are sorted properly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int semanticsUpdateCount = 0; final SemanticsHandle handle = tester.binding.pipelineOwner.ensureSemantics( @@ -1086,7 +1087,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widgets that are transformed are sorted properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widgets that are transformed are sorted properly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int semanticsUpdateCount = 0; final SemanticsHandle handle = tester.binding.pipelineOwner.ensureSemantics( @@ -1150,7 +1151,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics widgets without sort orders are sorted properly when no Directionality is present', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics widgets without sort orders are sorted properly when no Directionality is present', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); int semanticsUpdateCount = 0; final SemanticsHandle handle = tester.binding.pipelineOwner.ensureSemantics(listener: () { @@ -1251,7 +1252,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics excludeSemantics ignores children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics excludeSemantics ignores children', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Semantics( label: 'label', @@ -1279,7 +1280,7 @@ void main() { semantics.dispose(); }); - testWidgets('Can change handlers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can change handlers', (WidgetTester tester) async { await tester.pumpWidget(Semantics( container: true, label: 'foo', @@ -1666,7 +1667,7 @@ void main() { )); }); - testWidgets('Semantics with zero transform gets dropped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics with zero transform gets dropped', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110671. // Construct a widget tree that will end up with a fitted box that applies // a zero transform because it does not actually draw its children. @@ -1693,7 +1694,7 @@ void main() { expect(node.childrenCount, 0); }); - testWidgets('blocking user interaction works on explicit child node.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('blocking user interaction works on explicit child node.', (WidgetTester tester) async { final UniqueKey key1 = UniqueKey(); final UniqueKey key2 = UniqueKey(); await tester.pumpWidget( @@ -1736,7 +1737,7 @@ void main() { ); }); - testWidgets('blocking user interaction on a merged child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('blocking user interaction on a merged child', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( @@ -1771,7 +1772,7 @@ void main() { ); }); - testWidgets('does not merge conflicting actions even if one of them is blocked', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not merge conflicting actions even if one of them is blocked', (WidgetTester tester) async { final UniqueKey key = UniqueKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart b/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart index 1f7aec466cf97..479f20e6319c1 100644 --- a/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart +++ b/packages/flutter/test/widgets/semantics_tester_generate_test_semantics_expression_for_current_semantics_tree_test.dart @@ -10,6 +10,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -52,7 +53,7 @@ void _tests() { // also update this code to reflect the new output. // // This test is flexible w.r.t. leading and trailing whitespace. - testWidgets('generates code', (WidgetTester tester) async { + testWidgetsWithLeakTracking('generates code', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await pumpTestWidget(tester); final String code = semantics @@ -91,7 +92,7 @@ void _tests() { expect('$code,', expectedCode); }); - testWidgets('generated code is correct', (WidgetTester tester) async { + testWidgetsWithLeakTracking('generated code is correct', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await pumpTestWidget(tester); expect( diff --git a/packages/flutter/test/widgets/semantics_tester_test.dart b/packages/flutter/test/widgets/semantics_tester_test.dart index c5a9de1763cb9..e8b8a1ea59493 100644 --- a/packages/flutter/test/widgets/semantics_tester_test.dart +++ b/packages/flutter/test/widgets/semantics_tester_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Semantics tester visits last child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics tester visits last child', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/semantics_traversal_test.dart b/packages/flutter/test/widgets/semantics_traversal_test.dart index a509ab2d2cf4e..23247ad651380 100644 --- a/packages/flutter/test/widgets/semantics_traversal_test.dart +++ b/packages/flutter/test/widgets/semantics_traversal_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -21,7 +22,7 @@ void main() { }); void testTraversal(String description, TraversalTestFunction testFunction) { - testWidgets(description, (WidgetTester tester) async { + testWidgetsWithLeakTracking(description, (WidgetTester tester) async { final TraversalTester traversalTester = TraversalTester(tester); await testFunction(traversalTester); traversalTester.dispose(); diff --git a/packages/flutter/test/widgets/semantics_zero_surface_size_test.dart b/packages/flutter/test/widgets/semantics_zero_surface_size_test.dart index 07c58cdafa4ef..273c437cca453 100644 --- a/packages/flutter/test/widgets/semantics_zero_surface_size_test.dart +++ b/packages/flutter/test/widgets/semantics_zero_surface_size_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('has only root node if surface size is 0x0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has only root node if surface size is 0x0', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Semantics( diff --git a/packages/flutter/test/widgets/set_state_1_test.dart b/packages/flutter/test/widgets/set_state_1_test.dart index ca29a40b26fc6..dc85b46e470c3 100644 --- a/packages/flutter/test/widgets/set_state_1_test.dart +++ b/packages/flutter/test/widgets/set_state_1_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Inside extends StatefulWidget { const Inside({ super.key }); @@ -65,7 +66,7 @@ class OutsideState extends State<Outside> { } void main() { - testWidgets('setState() smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setState() smoke test', (WidgetTester tester) async { await tester.pumpWidget(const Outside()); final Offset location = tester.getCenter(find.text('INSIDE')); final TestGesture gesture = await tester.startGesture(location); diff --git a/packages/flutter/test/widgets/set_state_2_test.dart b/packages/flutter/test/widgets/set_state_2_test.dart index 4df03006cff66..1894cea871bae 100644 --- a/packages/flutter/test/widgets/set_state_2_test.dart +++ b/packages/flutter/test/widgets/set_state_2_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('setState() overbuild test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setState() overbuild test', (WidgetTester tester) async { final List<String> log = <String>[]; final Builder inner = Builder( builder: (BuildContext context) { diff --git a/packages/flutter/test/widgets/set_state_3_test.dart b/packages/flutter/test/widgets/set_state_3_test.dart index 461746e98a122..534d9cb976646 100644 --- a/packages/flutter/test/widgets/set_state_3_test.dart +++ b/packages/flutter/test/widgets/set_state_3_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; late ChangerState changer; @@ -52,7 +53,7 @@ class LeafState extends State<Leaf> { } void main() { - testWidgets('three-way setState() smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('three-way setState() smoke test', (WidgetTester tester) async { await tester.pumpWidget(const Changer(Wrapper(Leaf()))); await tester.pumpWidget(const Changer(Wrapper(Leaf()))); changer.test(); diff --git a/packages/flutter/test/widgets/set_state_4_test.dart b/packages/flutter/test/widgets/set_state_4_test.dart index e0fc2e7ee0693..2349f8151a3eb 100644 --- a/packages/flutter/test/widgets/set_state_4_test.dart +++ b/packages/flutter/test/widgets/set_state_4_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Changer extends StatefulWidget { const Changer({ super.key }); @@ -21,7 +22,7 @@ class ChangerState extends State<Changer> { } void main() { - testWidgets('setState() catches being used with an async callback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setState() catches being used with an async callback', (WidgetTester tester) async { await tester.pumpWidget(const Changer()); final ChangerState s = tester.state(find.byType(Changer)); expect(s.test0, isNot(throwsFlutterError)); diff --git a/packages/flutter/test/widgets/set_state_5_test.dart b/packages/flutter/test/widgets/set_state_5_test.dart index fd7bdaccd73f1..335d427d643c0 100644 --- a/packages/flutter/test/widgets/set_state_5_test.dart +++ b/packages/flutter/test/widgets/set_state_5_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class BadWidget extends StatefulWidget { const BadWidget({ super.key }); @@ -27,7 +28,7 @@ class BadWidgetState extends State<BadWidget> { } void main() { - testWidgets('setState() catches being used inside a constructor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setState() catches being used inside a constructor', (WidgetTester tester) async { await tester.pumpWidget(const BadWidget()); expect(tester.takeException(), isFlutterError); }); diff --git a/packages/flutter/test/widgets/shader_mask_test.dart b/packages/flutter/test/widgets/shader_mask_test.dart index 018950f20bc8b..7b941c06d4903 100644 --- a/packages/flutter/test/widgets/shader_mask_test.dart +++ b/packages/flutter/test/widgets/shader_mask_test.dart @@ -9,6 +9,7 @@ library; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Shader createShader(Rect bounds) { return const LinearGradient( @@ -21,12 +22,12 @@ Shader createShader(Rect bounds) { void main() { - testWidgets('Can be constructed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can be constructed', (WidgetTester tester) async { const Widget child = SizedBox(width: 100.0, height: 100.0); await tester.pumpWidget(const ShaderMask(shaderCallback: createShader, child: child)); }); - testWidgets('Bounds rect includes offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Bounds rect includes offset', (WidgetTester tester) async { late Rect shaderBounds; Shader recordShaderBounds(Rect bounds) { shaderBounds = bounds; @@ -50,7 +51,7 @@ void main() { }); - testWidgets('Bounds rect includes offset visual inspection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Bounds rect includes offset visual inspection', (WidgetTester tester) async { final Widget widgetBottomRight = Container( width: 400, height: 400, diff --git a/packages/flutter/test/widgets/shadow_test.dart b/packages/flutter/test/widgets/shadow_test.dart index eb97b9af2d9ae..f2d5f93b429e5 100644 --- a/packages/flutter/test/widgets/shadow_test.dart +++ b/packages/flutter/test/widgets/shadow_test.dart @@ -9,13 +9,14 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { tearDown(() { debugDisableShadows = true; }); - testWidgets('Shadows on BoxDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shadows on BoxDecoration', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -61,7 +62,7 @@ void main() { ); } for (final int elevation in kElevationToShadow.keys) { - testWidgets('elevation $elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('elevation $elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget(build(elevation)); await expectLater( @@ -73,7 +74,7 @@ void main() { } }); - testWidgets('Shadows with PhysicalLayer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shadows with PhysicalLayer', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -132,7 +133,7 @@ void main() { } for (final int elevation in kElevationToShadow.keys) { - testWidgets('elevation $elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('elevation $elevation', (WidgetTester tester) async { debugDisableShadows = false; await tester.pumpWidget(build(elevation.toDouble())); await expectLater( diff --git a/packages/flutter/test/widgets/shape_decoration_test.dart b/packages/flutter/test/widgets/shape_decoration_test.dart index 1926745869c43..0db118ad09d3c 100644 --- a/packages/flutter/test/widgets/shape_decoration_test.dart +++ b/packages/flutter/test/widgets/shape_decoration_test.dart @@ -7,6 +7,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../image_data.dart'; import '../painting/mocks_for_image_cache.dart'; @@ -16,7 +17,7 @@ Future<void> main() async { AutomatedTestWidgetsFlutterBinding(); final ui.Image rawImage = await decodeImageFromList(Uint8List.fromList(kTransparentImage)); final ImageProvider image = TestImageProvider(0, 0, image: rawImage); - testWidgets('ShapeDecoration.image', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ShapeDecoration.image', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: DecoratedBox( @@ -39,7 +40,7 @@ Future<void> main() async { ); }); - testWidgets('ShapeDecoration.color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ShapeDecoration.color', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: DecoratedBox( @@ -68,7 +69,7 @@ Future<void> main() async { expect(decoration.padding, isA<EdgeInsetsDirectional>()); }); - testWidgets('TestBorder and Directionality - 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TestBorder and Directionality - 1', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( MaterialApp( @@ -89,7 +90,7 @@ Future<void> main() async { ); }); - testWidgets('TestBorder and Directionality - 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TestBorder and Directionality - 2', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( Directionality( @@ -113,7 +114,7 @@ Future<void> main() async { ); }); - testWidgets('Does not crash with directional gradient', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not crash with directional gradient', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/76967. await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/shared_app_data_test.dart b/packages/flutter/test/widgets/shared_app_data_test.dart index 6d57734d4b1b3..db9ec5d3a02f7 100644 --- a/packages/flutter/test/widgets/shared_app_data_test.dart +++ b/packages/flutter/test/widgets/shared_app_data_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SharedAppData basics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SharedAppData basics', (WidgetTester tester) async { int columnBuildCount = 0; int child1BuildCount = 0; int child2BuildCount = 0; @@ -116,7 +117,7 @@ void main() { expect(find.text('null').evaluate().length, 2); }); - testWidgets('WidgetsApp SharedAppData ', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp SharedAppData ', (WidgetTester tester) async { int parentBuildCount = 0; int childBuildCount = 0; @@ -154,7 +155,7 @@ void main() { expect(find.text('child'), findsOneWidget); }); - testWidgets('WidgetsApp SharedAppData Shadowing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetsApp SharedAppData Shadowing', (WidgetTester tester) async { int innerTapCount = 0; int outerTapCount = 0; diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index a73bb38e803fe..ed2d5ad99e919 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -112,7 +112,7 @@ void main() { ); }); - testWidgets('handles two keys', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles two keys', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( LogicalKeySet( @@ -211,7 +211,7 @@ void main() { ); }); - testWidgets('isActivatedBy works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isActivatedBy works as expected', (WidgetTester tester) async { // Collect some key events to use for testing. final List<RawKeyEvent> events = <RawKeyEvent>[]; await tester.pumpWidget( @@ -253,7 +253,7 @@ void main() { }); group(SingleActivator, () { - testWidgets('handles Ctrl-C', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles Ctrl-C', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const SingleActivator( @@ -352,7 +352,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, isEmpty); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('handles repeated events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles repeated events', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const SingleActivator( @@ -378,7 +378,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, isEmpty); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('rejects repeated events if requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('rejects repeated events if requested', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const SingleActivator( @@ -405,7 +405,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, isEmpty); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('handles Shift-Ctrl-C', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles Shift-Ctrl-C', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const SingleActivator( @@ -455,7 +455,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, isEmpty); }); - testWidgets('isActivatedBy works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isActivatedBy works as expected', (WidgetTester tester) async { // Collect some key events to use for testing. final List<RawKeyEvent> events = <RawKeyEvent>[]; await tester.pumpWidget( @@ -534,15 +534,16 @@ void main() { }); group(Shortcuts, () { - testWidgets('Default constructed Shortcuts has empty shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default constructed Shortcuts has empty shortcuts', (WidgetTester tester) async { const Shortcuts shortcuts = Shortcuts(shortcuts: <LogicalKeySet, Intent>{}, child: SizedBox()); await tester.pumpWidget(shortcuts); expect(shortcuts.shortcuts, isNotNull); expect(shortcuts.shortcuts, isEmpty); }); - testWidgets('Default constructed Shortcuts.manager has empty shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default constructed Shortcuts.manager has empty shortcuts', (WidgetTester tester) async { final ShortcutManager manager = ShortcutManager(); + addTearDown(manager.dispose); expect(manager.shortcuts, isNotNull); expect(manager.shortcuts, isEmpty); final Shortcuts shortcuts = Shortcuts.manager(manager: manager, child: const SizedBox()); @@ -551,11 +552,12 @@ void main() { expect(shortcuts.shortcuts, isEmpty); }); - testWidgets('Shortcuts.manager passes on shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts.manager passes on shortcuts', (WidgetTester tester) async { final Map<LogicalKeySet, Intent> testShortcuts = <LogicalKeySet, Intent>{ LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), }; final ShortcutManager manager = ShortcutManager(shortcuts: testShortcuts); + addTearDown(manager.dispose); expect(manager.shortcuts, isNotNull); expect(manager.shortcuts, equals(testShortcuts)); final Shortcuts shortcuts = Shortcuts.manager(manager: manager, child: const SizedBox()); @@ -564,7 +566,7 @@ void main() { expect(shortcuts.shortcuts, equals(testShortcuts)); }); - testWidgets('ShortcutManager handles shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ShortcutManager handles shortcuts', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -573,6 +575,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( Actions( @@ -599,7 +602,7 @@ void main() { expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.shiftLeft])); }); - testWidgets('Shortcuts.manager lets manager handle shortcuts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts.manager lets manager handle shortcuts', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -608,6 +611,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( Actions( @@ -634,7 +638,7 @@ void main() { expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.shiftLeft])); }); - testWidgets('ShortcutManager ignores key presses with no primary focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ShortcutManager ignores key presses with no primary focus', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -643,6 +647,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( Actions( @@ -671,7 +676,7 @@ void main() { expect(()=> ShortcutManager().dispose(), dispatchesMemoryEvents(ShortcutManager)); }); - testWidgets("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -680,6 +685,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( Shortcuts.manager( @@ -711,7 +717,7 @@ void main() { expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.shiftLeft])); }); - testWidgets('Shortcuts can disable a shortcut with Intent.doNothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts can disable a shortcut with Intent.doNothing', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -720,6 +726,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.shift): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( MaterialApp( @@ -753,7 +760,7 @@ void main() { expect(pressedKeys, isEmpty); }); - testWidgets("Shortcuts that aren't bound to an action don't absorb keys meant for text fields", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Shortcuts that aren't bound to an action don't absorb keys meant for text fields", (WidgetTester tester) async { final GlobalKey textFieldKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -762,6 +769,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.keyA): const TestIntent(), }, ); + addTearDown(testManager.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -778,7 +786,7 @@ void main() { expect(pressedKeys, equals(<LogicalKeyboardKey>[LogicalKeyboardKey.keyA])); }); - testWidgets('Shortcuts that are bound to an action do override text fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts that are bound to an action do override text fields', (WidgetTester tester) async { final GlobalKey textFieldKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -787,6 +795,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.keyA): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( MaterialApp( @@ -815,7 +824,7 @@ void main() { expect(invoked, isTrue); }); - testWidgets('Shortcuts can override intents that apply to text fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts can override intents that apply to text fields', (WidgetTester tester) async { final GlobalKey textFieldKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -824,6 +833,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.keyA): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( MaterialApp( @@ -856,7 +866,7 @@ void main() { expect(invoked, isFalse); }); - testWidgets('Shortcuts can override intents that apply to text fields with DoNothingAndStopPropagationIntent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts can override intents that apply to text fields with DoNothingAndStopPropagationIntent', (WidgetTester tester) async { final GlobalKey textFieldKey = GlobalKey(); final List<LogicalKeyboardKey> pressedKeys = <LogicalKeyboardKey>[]; final TestShortcutManager testManager = TestShortcutManager( @@ -865,6 +875,7 @@ void main() { LogicalKeySet(LogicalKeyboardKey.keyA): const TestIntent(), }, ); + addTearDown(testManager.dispose); bool invoked = false; await tester.pumpWidget( MaterialApp( @@ -982,6 +993,7 @@ void main() { ): const ActivateIntent(), }, ); + addTearDown(testManager.dispose); Shortcuts.manager( manager: testManager, @@ -997,7 +1009,7 @@ void main() { expect(description[1], equalsIgnoringHashCodes('shortcuts: {{Key A + Key B}: ActivateIntent#00000}')); }); - testWidgets('Shortcuts support multiple intents', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts support multiple intents', (WidgetTester tester) async { tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; bool? value = true; Widget buildApp() { @@ -1078,7 +1090,7 @@ void main() { expect(controller.position.pixels, 0.0); }); - testWidgets('Shortcuts support activators that returns null in triggers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shortcuts support activators that returns null in triggers', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const DumbLogicalActivator(LogicalKeyboardKey.keyC), @@ -1120,7 +1132,7 @@ void main() { }); group('CharacterActivator', () { - testWidgets('is triggered on events with correct character', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is triggered on events with correct character', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const CharacterActivator('?'), @@ -1138,7 +1150,7 @@ void main() { invoked = 0; }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('handles repeated events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles repeated events', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const CharacterActivator('?'), @@ -1158,7 +1170,7 @@ void main() { invoked = 0; }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('rejects repeated events if requested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('rejects repeated events if requested', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const CharacterActivator('?', includeRepeats: false), @@ -1178,7 +1190,7 @@ void main() { invoked = 0; }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('handles Alt, Ctrl and Meta', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handles Alt, Ctrl and Meta', (WidgetTester tester) async { int invoked = 0; await tester.pumpWidget(activatorTester( const CharacterActivator('?', alt: true, meta: true, control: true), @@ -1224,7 +1236,7 @@ void main() { invoked = 0; }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('isActivatedBy works as expected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isActivatedBy works as expected', (WidgetTester tester) async { // Collect some key events to use for testing. final List<RawKeyEvent> events = <RawKeyEvent>[]; await tester.pumpWidget( @@ -1293,7 +1305,7 @@ void main() { }); group('CallbackShortcuts', () { - testWidgets('trigger on key events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('trigger on key events', (WidgetTester tester) async { int invokedA = 0; int invokedB = 0; await tester.pumpWidget( @@ -1331,7 +1343,7 @@ void main() { expect(invokedB, equals(1)); }); - testWidgets('nested CallbackShortcuts stop propagation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('nested CallbackShortcuts stop propagation', (WidgetTester tester) async { int invokedOuter = 0; int invokedInner = 0; await tester.pumpWidget( @@ -1364,7 +1376,7 @@ void main() { expect(invokedInner, equals(1)); }); - testWidgets('non-overlapping nested CallbackShortcuts fire appropriately', (WidgetTester tester) async { + testWidgetsWithLeakTracking('non-overlapping nested CallbackShortcuts fire appropriately', (WidgetTester tester) async { int invokedOuter = 0; int invokedInner = 0; await tester.pumpWidget( @@ -1401,7 +1413,7 @@ void main() { expect(invokedInner, equals(1)); }); - testWidgets('Works correctly with Shortcuts too', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Works correctly with Shortcuts too', (WidgetTester tester) async { int invokedCallbackA = 0; int invokedCallbackB = 0; int invokedActionA = 0; @@ -1475,7 +1487,7 @@ void main() { }); group('ShortcutRegistrar', () { - testWidgets('trigger ShortcutRegistrar on key events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('trigger ShortcutRegistrar on key events', (WidgetTester tester) async { int invokedA = 0; int invokedB = 0; await tester.pumpWidget( @@ -1520,7 +1532,7 @@ void main() { expect(invokedB, equals(1)); }); - testWidgets('MaterialApp has a ShortcutRegistrar listening', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MaterialApp has a ShortcutRegistrar listening', (WidgetTester tester) async { int invokedA = 0; int invokedB = 0; await tester.pumpWidget( @@ -1565,7 +1577,7 @@ void main() { expect(invokedB, equals(1)); }); - testWidgets("doesn't override text field shortcuts", (WidgetTester tester) async { + testWidgetsWithLeakTracking("doesn't override text field shortcuts", (WidgetTester tester) async { final TextEditingController controller = TextEditingController(); await tester.pumpWidget( MaterialApp( @@ -1597,7 +1609,7 @@ void main() { expect(controller.selection.extentOffset, equals(7)); }); - testWidgets('nested ShortcutRegistrars stop propagation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('nested ShortcutRegistrars stop propagation', (WidgetTester tester) async { int invokedOuter = 0; int invokedInner = 0; await tester.pumpWidget( @@ -1638,7 +1650,7 @@ void main() { expect(invokedInner, equals(1)); }); - testWidgets('non-overlapping nested ShortcutRegistrars fire appropriately', (WidgetTester tester) async { + testWidgetsWithLeakTracking('non-overlapping nested ShortcutRegistrars fire appropriately', (WidgetTester tester) async { int invokedOuter = 0; int invokedInner = 0; await tester.pumpWidget( @@ -1684,7 +1696,7 @@ void main() { expect(invokedInner, equals(1)); }); - testWidgets('Works correctly with Shortcuts too', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Works correctly with Shortcuts too', (WidgetTester tester) async { int invokedCallbackA = 0; int invokedCallbackB = 0; int invokedActionA = 0; @@ -1761,7 +1773,7 @@ void main() { await tester.sendKeyUpEvent(LogicalKeyboardKey.keyB); }); - testWidgets('Updating shortcuts triggers dependency rebuild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updating shortcuts triggers dependency rebuild', (WidgetTester tester) async { final List<Map<ShortcutActivator, Intent>> shortcutsChanged = <Map<ShortcutActivator, Intent>>[]; void dependenciesUpdated(Map<ShortcutActivator, Intent> shortcuts) { shortcutsChanged.add(shortcuts); @@ -1835,8 +1847,9 @@ void main() { })); }); - testWidgets('using a disposed token asserts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('using a disposed token asserts', (WidgetTester tester) async { final ShortcutRegistry registry = ShortcutRegistry(); + addTearDown(registry.dispose); final ShortcutRegistryEntry token = registry.addAll(const <ShortcutActivator, Intent>{ SingleActivator(LogicalKeyboardKey.keyA): DoNothingIntent(), }); @@ -1844,8 +1857,9 @@ void main() { expect(() {token.replaceAll(<ShortcutActivator, Intent>{}); }, throwsFlutterError); }); - testWidgets('setting duplicate bindings asserts', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setting duplicate bindings asserts', (WidgetTester tester) async { final ShortcutRegistry registry = ShortcutRegistry(); + addTearDown(registry.dispose); final ShortcutRegistryEntry token = registry.addAll(const <ShortcutActivator, Intent>{ SingleActivator(LogicalKeyboardKey.keyA): DoNothingIntent(), }); diff --git a/packages/flutter/test/widgets/simple_semantics_test.dart b/packages/flutter/test/widgets/simple_semantics_test.dart index 4b5729ea5d461..34b0733a94855 100644 --- a/packages/flutter/test/widgets/simple_semantics_test.dart +++ b/packages/flutter/test/widgets/simple_semantics_test.dart @@ -6,11 +6,12 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Simple tree is simple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simple tree is simple', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -34,7 +35,7 @@ void main() { semantics.dispose(); }); - testWidgets('Simple tree is simple - material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simple tree is simple - material', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // Not using Text widget because of https://github.com/flutter/flutter/issues/12357. diff --git a/packages/flutter/test/widgets/single_child_scroll_view_test.dart b/packages/flutter/test/widgets/single_child_scroll_view_test.dart index 83b8df226f8ad..2cc8708215436 100644 --- a/packages/flutter/test/widgets/single_child_scroll_view_test.dart +++ b/packages/flutter/test/widgets/single_child_scroll_view_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; import 'semantics_tester.dart'; @@ -144,7 +145,7 @@ void main() { ); }); - testWidgets('SingleChildScrollView control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView control test', (WidgetTester tester) async { await tester.pumpWidget(SingleChildScrollView( child: Container( height: 2000.0, @@ -160,8 +161,9 @@ void main() { expect(box.localToGlobal(Offset.zero), equals(const Offset(0.0, -200.0))); }); - testWidgets('Changing controllers changes scroll position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing controllers changes scroll position', (WidgetTester tester) async { final TestScrollController controller = TestScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(SingleChildScrollView( child: Container( @@ -182,8 +184,9 @@ void main() { expect(scrollable.position, isA<TestScrollPosition>()); }); - testWidgets('Sets PrimaryScrollController when primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sets PrimaryScrollController when primary', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); await tester.pumpWidget(PrimaryScrollController( controller: primaryScrollController, child: SingleChildScrollView( @@ -200,8 +203,9 @@ void main() { }); - testWidgets('Changing scroll controller inside dirty layout builder does not assert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing scroll controller inside dirty layout builder does not assert', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(Center( child: SizedBox( @@ -237,25 +241,28 @@ void main() { )); }); - testWidgets('Vertical SingleChildScrollViews are not primary by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical SingleChildScrollViews are not primary by default', (WidgetTester tester) async { const SingleChildScrollView view = SingleChildScrollView(); expect(view.primary, isNull); }); - testWidgets('Horizontal SingleChildScrollViews are not primary by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal SingleChildScrollViews are not primary by default', (WidgetTester tester) async { const SingleChildScrollView view = SingleChildScrollView(scrollDirection: Axis.horizontal); expect(view.primary, isNull); }); - testWidgets('SingleChildScrollViews with controllers are not primary by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollViews with controllers are not primary by default', (WidgetTester tester) async { + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final SingleChildScrollView view = SingleChildScrollView( - controller: ScrollController(), + controller: controller, ); expect(view.primary, isNull); }); - testWidgets('Vertical SingleChildScrollViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical SingleChildScrollViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: const SingleChildScrollView(), controller: controller, @@ -263,8 +270,9 @@ void main() { expect(controller.hasClients, isTrue); }, variant: TargetPlatformVariant.mobile()); - testWidgets("Vertical SingleChildScrollViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Vertical SingleChildScrollViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: const SingleChildScrollView(), controller: controller, @@ -272,9 +280,10 @@ void main() { expect(controller.hasClients, isFalse); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Nested scrollables have a null PrimaryScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested scrollables have a null PrimaryScrollController', (WidgetTester tester) async { const Key innerKey = Key('inner'); final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -300,9 +309,10 @@ void main() { expect(innerScrollable.controller, isNull); }); - testWidgets('SingleChildScrollView semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -395,8 +405,9 @@ void main() { semantics.dispose(); }); - testWidgets('SingleChildScrollView semantics clips cover entire child vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView semantics clips cover entire child vertical', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final UniqueKey scrollView = UniqueKey(); final UniqueKey childBox = UniqueKey(); const double length = 10000; @@ -434,8 +445,9 @@ void main() { expect(semanticsClip.size.height, length); }); - testWidgets('SingleChildScrollView semantics clips cover entire child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView semantics clips cover entire child', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final UniqueKey scrollView = UniqueKey(); final UniqueKey childBox = UniqueKey(); const double length = 10000; @@ -474,7 +486,9 @@ void main() { expect(semanticsClip.size.width, length); }); - testWidgets('SingleChildScrollView getOffsetToReveal - down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView getOffsetToReveal - down', (WidgetTester tester) async { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); List<Widget> children; await tester.pumpWidget( Directionality( @@ -484,7 +498,7 @@ void main() { height: 200.0, width: 300.0, child: SingleChildScrollView( - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, child: Column( children: children = List<Widget>.generate(20, (int i) { return SizedBox( @@ -520,7 +534,9 @@ void main() { expect(revealed.rect, const Rect.fromLTWH(40.0, 190.0, 10.0, 10.0)); }); - testWidgets('SingleChildScrollView getOffsetToReveal - up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView getOffsetToReveal - up', (WidgetTester tester) async { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); final List<Widget> children = List<Widget>.generate(20, (int i) { return SizedBox( height: 100.0, @@ -536,7 +552,7 @@ void main() { height: 200.0, width: 300.0, child: SingleChildScrollView( - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, reverse: true, child: Column( children: children.reversed.toList(), @@ -567,7 +583,9 @@ void main() { expect(revealed.rect, const Rect.fromLTWH(40.0, 0.0, 10.0, 10.0)); }); - testWidgets('SingleChildScrollView getOffsetToReveal - right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView getOffsetToReveal - right', (WidgetTester tester) async { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); List<Widget> children; await tester.pumpWidget( @@ -579,7 +597,7 @@ void main() { width: 200.0, child: SingleChildScrollView( scrollDirection: Axis.horizontal, - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, child: Row( children: children = List<Widget>.generate(20, (int i) { return SizedBox( @@ -615,7 +633,9 @@ void main() { expect(revealed.rect, const Rect.fromLTWH(190.0, 40.0, 10.0, 10.0)); }); - testWidgets('SingleChildScrollView getOffsetToReveal - left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView getOffsetToReveal - left', (WidgetTester tester) async { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); final List<Widget> children = List<Widget>.generate(20, (int i) { return SizedBox( height: 300.0, @@ -634,7 +654,7 @@ void main() { child: SingleChildScrollView( scrollDirection: Axis.horizontal, reverse: true, - controller: ScrollController(initialScrollOffset: 300.0), + controller: controller, child: Row( children: children.reversed.toList(), ), @@ -664,7 +684,7 @@ void main() { expect(revealed.rect, const Rect.fromLTWH(0.0, 40.0, 10.0, 10.0)); }); - testWidgets('Nested SingleChildScrollView showOnScreen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested SingleChildScrollView showOnScreen', (WidgetTester tester) async { final List<List<Widget>> children = List<List<Widget>>.generate(10, (int x) { return List<Widget>.generate(10, (int y) { return SizedBox( @@ -674,8 +694,10 @@ void main() { ); }); }); - ScrollController controllerX; - ScrollController controllerY; + late ScrollController controllerX; + addTearDown(() => controllerX.dispose()); + late ScrollController controllerY; + addTearDown(() => controllerY.dispose()); /// Builds a gird: /// @@ -874,9 +896,11 @@ void main() { ); } - testWidgets('in view in inner, but not in outer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('in view in inner, but not in outer', (WidgetTester tester) async { final ScrollController inner = ScrollController(); + addTearDown(inner.dispose); final ScrollController outer = ScrollController(); + addTearDown(outer.dispose); await buildNestedScroller( tester: tester, inner: inner, @@ -891,9 +915,11 @@ void main() { expect(outer.offset, 100.0); }); - testWidgets('not in view of neither inner nor outer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('not in view of neither inner nor outer', (WidgetTester tester) async { final ScrollController inner = ScrollController(); + addTearDown(inner.dispose); final ScrollController outer = ScrollController(); + addTearDown(outer.dispose); await buildNestedScroller( tester: tester, inner: inner, @@ -908,9 +934,11 @@ void main() { expect(outer.offset, 200.0); }); - testWidgets('in view in inner and outer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('in view in inner and outer', (WidgetTester tester) async { final ScrollController inner = ScrollController(initialScrollOffset: 200.0); + addTearDown(inner.dispose); final ScrollController outer = ScrollController(initialScrollOffset: 200.0); + addTearDown(outer.dispose); await buildNestedScroller( tester: tester, inner: inner, @@ -925,9 +953,11 @@ void main() { expect(inner.offset, 200.0); }); - testWidgets('inner shown in outer, but item not visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inner shown in outer, but item not visible', (WidgetTester tester) async { final ScrollController inner = ScrollController(initialScrollOffset: 200.0); + addTearDown(inner.dispose); final ScrollController outer = ScrollController(initialScrollOffset: 200.0); + addTearDown(outer.dispose); await buildNestedScroller( tester: tester, inner: inner, @@ -942,9 +972,11 @@ void main() { expect(inner.offset, 400.0); }); - testWidgets('inner half shown in outer, item only visible in inner', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inner half shown in outer, item only visible in inner', (WidgetTester tester) async { final ScrollController inner = ScrollController(); + addTearDown(inner.dispose); final ScrollController outer = ScrollController(initialScrollOffset: 100.0); + addTearDown(outer.dispose); await buildNestedScroller( tester: tester, inner: inner, @@ -960,8 +992,13 @@ void main() { }); }); - testWidgets('keyboardDismissBehavior tests', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboardDismissBehavior tests', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); Future<void> boilerplate(ScrollViewKeyboardDismissBehavior behavior) { return tester.pumpWidget( diff --git a/packages/flutter/test/widgets/size_changed_layout_notification_test.dart b/packages/flutter/test/widgets/size_changed_layout_notification_test.dart index 6f8c8c83c1759..f4b1e8862057a 100644 --- a/packages/flutter/test/widgets/size_changed_layout_notification_test.dart +++ b/packages/flutter/test/widgets/size_changed_layout_notification_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SizeChangedLayoutNotification test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizeChangedLayoutNotification test', (WidgetTester tester) async { bool notified = false; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/sized_box_test.dart b/packages/flutter/test/widgets/sized_box_test.dart index 4d1d5094e1a59..60822a1e31b56 100644 --- a/packages/flutter/test/widgets/sized_box_test.dart +++ b/packages/flutter/test/widgets/sized_box_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SizedBox constructors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizedBox constructors', (WidgetTester tester) async { const SizedBox a = SizedBox(); expect(a.width, isNull); expect(a.height, isNull); @@ -37,7 +38,7 @@ void main() { expect(g.height, 0.0); }); - testWidgets('SizedBox - no child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizedBox - no child', (WidgetTester tester) async { final GlobalKey patient = GlobalKey(); await tester.pumpWidget( @@ -109,7 +110,7 @@ void main() { expect(patient.currentContext!.size, equals(Size.zero)); }); - testWidgets('SizedBox - container child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizedBox - container child', (WidgetTester tester) async { final GlobalKey patient = GlobalKey(); await tester.pumpWidget( @@ -188,7 +189,7 @@ void main() { expect(patient.currentContext!.size, equals(Size.zero)); }); - testWidgets('SizedBox.square tests', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizedBox.square tests', (WidgetTester tester) async { await tester.pumpWidget( const SizedBox.square( dimension: 100, diff --git a/packages/flutter/test/widgets/sliver_appbar_opacity_test.dart b/packages/flutter/test/widgets/sliver_appbar_opacity_test.dart index 474af5272cbe8..41d222c353c1e 100644 --- a/packages/flutter/test/widgets/sliver_appbar_opacity_test.dart +++ b/packages/flutter/test/widgets/sliver_appbar_opacity_test.dart @@ -5,10 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('!pinned && !floating && !bottom ==> fade opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('!pinned && !floating && !bottom ==> fade opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: false, @@ -26,8 +28,9 @@ void main() { expect(render.text.style!.color!.opacity, 0.0); }); - testWidgets('!pinned && !floating && bottom ==> fade opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('!pinned && !floating && bottom ==> fade opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: false, @@ -45,8 +48,9 @@ void main() { expect(render.text.style!.color!.opacity, 0.0); }); - testWidgets('!pinned && floating && !bottom ==> fade opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('!pinned && floating && !bottom ==> fade opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: false, @@ -64,8 +68,9 @@ void main() { expect(render.text.style!.color!.opacity, 0.0); }); - testWidgets('!pinned && floating && bottom ==> fade opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('!pinned && floating && bottom ==> fade opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: false, @@ -83,8 +88,9 @@ void main() { expect(render.text.style!.color!.opacity, 0.0); }); - testWidgets('pinned && !floating && !bottom ==> 1.0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pinned && !floating && !bottom ==> 1.0 opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: true, @@ -102,8 +108,9 @@ void main() { expect(render.text.style!.color!.opacity, 1.0); }); - testWidgets('pinned && !floating && bottom ==> 1.0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pinned && !floating && bottom ==> 1.0 opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: true, @@ -121,10 +128,11 @@ void main() { expect(render.text.style!.color!.opacity, 1.0); }); - testWidgets('pinned && floating && !bottom ==> 1.0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pinned && floating && !bottom ==> 1.0 opacity', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25000. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: true, @@ -142,10 +150,11 @@ void main() { expect(render.text.style!.color!.opacity, 1.0); }); - testWidgets('pinned && floating && bottom && extraToolbarHeight == 0.0 ==> fade opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pinned && floating && bottom && extraToolbarHeight == 0.0 ==> fade opacity', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/25993. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: true, @@ -163,8 +172,9 @@ void main() { expect(render.text.style!.color!.opacity, 0.0); }); - testWidgets('pinned && floating && bottom && extraToolbarHeight != 0.0 ==> 1.0 opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pinned && floating && bottom && extraToolbarHeight != 0.0 ==> 1.0 opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _TestWidget( pinned: true, @@ -183,8 +193,9 @@ void main() { expect(render.text.style!.color!.opacity, 1.0); }); - testWidgets('!pinned && !floating && !bottom && extraToolbarHeight != 0.0 ==> fade opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('!pinned && !floating && !bottom && extraToolbarHeight != 0.0 ==> fade opacity', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); const double collapsedHeight = 100.0; await tester.pumpWidget( _TestWidget( diff --git a/packages/flutter/test/widgets/sliver_constrained_cross_axis_test.dart b/packages/flutter/test/widgets/sliver_constrained_cross_axis_test.dart index 0fa6bf5eff40e..6cf42bd9cb92c 100644 --- a/packages/flutter/test/widgets/sliver_constrained_cross_axis_test.dart +++ b/packages/flutter/test/widgets/sliver_constrained_cross_axis_test.dart @@ -5,12 +5,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const double VIEWPORT_HEIGHT = 500; const double VIEWPORT_WIDTH = 300; void main() { - testWidgets('SliverConstrainedCrossAxis basic test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverConstrainedCrossAxis basic test', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverConstrainedCrossAxis(maxExtent: 50)); final RenderBox box = tester.renderObject(find.byType(Container)); @@ -21,7 +22,7 @@ void main() { expect(sliver.geometry!.paintExtent, equals(100)); }); - testWidgets('SliverConstrainedCrossAxis updates correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverConstrainedCrossAxis updates correctly', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverConstrainedCrossAxis(maxExtent: 50)); final RenderBox box1 = tester.renderObject(find.byType(Container)); @@ -35,7 +36,7 @@ void main() { expect(box2.size.width, 80); }); - testWidgets('SliverConstrainedCrossAxis uses parent extent if maxExtent is greater', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverConstrainedCrossAxis uses parent extent if maxExtent is greater', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverConstrainedCrossAxis(maxExtent: 400)); final RenderBox box = tester.renderObject(find.byType(Container)); @@ -43,7 +44,7 @@ void main() { expect(box.size.width, VIEWPORT_WIDTH); }); - testWidgets('SliverConstrainedCrossAxis constrains the height when direction is horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverConstrainedCrossAxis constrains the height when direction is horizontal', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverConstrainedCrossAxis( maxExtent: 50, scrollDirection: Axis.horizontal, @@ -53,7 +54,7 @@ void main() { expect(box.size.height, 50); }); - testWidgets('SliverConstrainedCrossAxis sets its own flex to 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverConstrainedCrossAxis sets its own flex to 0', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverConstrainedCrossAxis( maxExtent: 50, )); diff --git a/packages/flutter/test/widgets/sliver_constraints_test.dart b/packages/flutter/test/widgets/sliver_constraints_test.dart index 56565b69ebb5d..e2ac47afe7d98 100644 --- a/packages/flutter/test/widgets/sliver_constraints_test.dart +++ b/packages/flutter/test/widgets/sliver_constraints_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('precedingScrollExtent is reported as infinity for Sliver of unknown size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('precedingScrollExtent is reported as infinity for Sliver of unknown size', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: CustomScrollView( diff --git a/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart b/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart index a3d4dc8fd906b..8755d358e8ea4 100644 --- a/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/sliver_utils.dart'; @@ -13,9 +14,10 @@ const double VIEWPORT_HEIGHT = 600; const double VIEWPORT_WIDTH = 300; void main() { - testWidgets('SliverCrossAxisGroup is laid out properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverCrossAxisGroup is laid out properly', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, @@ -60,7 +62,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('SliverExpanded is laid out properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverExpanded is laid out properly', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( slivers: <Widget>[ @@ -98,7 +100,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('SliverConstrainedCrossAxis is laid out properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverConstrainedCrossAxis is laid out properly', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( slivers: <Widget>[ @@ -127,7 +129,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('Mix of slivers is laid out properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mix of slivers is laid out properly', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( slivers: <Widget>[ @@ -160,7 +162,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('Mix of slivers is laid out properly when horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mix of slivers is laid out properly when horizontal', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( scrollDirection: Axis.horizontal, @@ -215,7 +217,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('Mix of slivers is laid out properly when reversed horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mix of slivers is laid out properly when reversed horizontal', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( scrollDirection: Axis.horizontal, @@ -271,7 +273,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('Mix of slivers is laid out properly when reversed vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mix of slivers is laid out properly when reversed vertical', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( reverse: true, @@ -354,9 +356,10 @@ void main() { ); }); - testWidgets('Hit test works properly on various parts of SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hit test works properly on various parts of SliverCrossAxisGroup', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); String? clickedTile; @@ -425,7 +428,7 @@ void main() { expect(clickedTile, equals('Group 1 Tile 2')); }); - testWidgets('Constrained sliver takes up remaining space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Constrained sliver takes up remaining space', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); await tester.pumpWidget(_buildSliverCrossAxisGroup( slivers: <Widget>[ @@ -454,7 +457,7 @@ void main() { expect(renderGroup.geometry!.scrollExtent, equals(300 * 20)); }); - testWidgets('Assertion error when constrained widget runs out of cross axis extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Assertion error when constrained widget runs out of cross axis extent', (WidgetTester tester) async { final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; final Function(FlutterErrorDetails)? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); @@ -476,7 +479,7 @@ void main() { ); }); - testWidgets('Assertion error when expanded widget runs out of cross axis extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Assertion error when expanded widget runs out of cross axis extent', (WidgetTester tester) async { final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; final Function(FlutterErrorDetails)? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); @@ -499,7 +502,7 @@ void main() { ); }); - testWidgets('applyPaintTransform is implemented properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applyPaintTransform is implemented properly', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverCrossAxisGroup( slivers: <Widget>[ const SliverToBoxAdapter(child: Text('first box')), @@ -515,8 +518,9 @@ void main() { expect(second.localToGlobal(Offset.zero), const Offset(VIEWPORT_WIDTH / 2, 0)); }); - testWidgets('SliverPinnedPersistentHeader is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPinnedPersistentHeader is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -540,8 +544,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(-20.0)); }); - testWidgets('SliverFloatingPersistentHeader is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFloatingPersistentHeader is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -569,8 +574,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverPinnedPersistentHeader is painted within bounds of SliverCrossAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPinnedPersistentHeader is painted within bounds of SliverCrossAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -599,8 +605,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverFloatingPersistentHeader is painted within bounds of SliverCrossAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFloatingPersistentHeader is painted within bounds of SliverCrossAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -635,8 +642,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverPinnedFloatingPersistentHeader is painted within bounds of SliverCrossAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPinnedFloatingPersistentHeader is painted within bounds of SliverCrossAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -672,8 +680,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverAppBar with floating: false, pinned: false, snap: false is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with floating: false, pinned: false, snap: false is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -701,8 +710,9 @@ void main() { expect(renderHeader.geometry!.paintExtent, equals(0.0)); }); - testWidgets('SliverAppBar with floating: true, pinned: false, snap: true is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with floating: true, pinned: false, snap: true is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -741,8 +751,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(-50.0)); }); - testWidgets('SliverAppBar with floating: true, pinned: true, snap: true is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with floating: true, pinned: true, snap: true is painted within bounds of SliverCrossAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -781,8 +792,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(-50.0)); }); - testWidgets('SliverFloatingPersistentHeader scroll direction is not affected by controller.jumpTo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFloatingPersistentHeader scroll direction is not affected by controller.jumpTo', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverCrossAxisGroup( controller: controller, slivers: <Widget>[ @@ -810,8 +822,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverCrossAxisGroup skips painting invisible children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverCrossAxisGroup skips painting invisible children', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); int counter = 0; void incrementCounter() { diff --git a/packages/flutter/test/widgets/sliver_fill_remaining_test.dart b/packages/flutter/test/widgets/sliver_fill_remaining_test.dart index f0279e27437fc..a1965c49f76e9 100644 --- a/packages/flutter/test/widgets/sliver_fill_remaining_test.dart +++ b/packages/flutter/test/widgets/sliver_fill_remaining_test.dart @@ -6,6 +6,7 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { @@ -39,8 +40,9 @@ void main() { group('SliverFillRemaining', () { group('hasScrollBody: true, default', () { - testWidgets('no siblings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no siblings', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -79,8 +81,9 @@ void main() { ); }); - testWidgets('one sibling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('one sibling', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -120,8 +123,9 @@ void main() { ); }); - testWidgets('scrolls beyond viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrolls beyond viewportMainAxisExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<Widget> slivers = <Widget>[ sliverBox, SliverFillRemaining( @@ -139,8 +143,9 @@ void main() { }); group('hasScrollBody: false', () { - testWidgets('does not extend past viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not extend past viewportMainAxisExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<Widget> slivers = <Widget>[ sliverBox, SliverFillRemaining( @@ -158,7 +163,7 @@ void main() { expect(find.byType(Container), findsNWidgets(2)); }); - testWidgets('child without size is sized by extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child without size is sized by extent', (WidgetTester tester) async { final List<Widget> slivers = <Widget>[ sliverBox, SliverFillRemaining( @@ -179,7 +184,7 @@ void main() { expect(box.size.width, equals(650)); }); - testWidgets('child with smaller size is sized by extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child with smaller size is sized by extent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<Widget> slivers = <Widget>[ sliverBox, @@ -220,7 +225,7 @@ void main() { ); }); - testWidgets('extent is overridden by child with larger size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extent is overridden by child with larger size', (WidgetTester tester) async { final List<Widget> slivers = <Widget>[ sliverBox, SliverFillRemaining( @@ -244,7 +249,7 @@ void main() { expect(box.size.width, equals(1000)); }); - testWidgets('extent is overridden by child size if precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extent is overridden by child size if precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<Widget> slivers = <Widget>[ SliverFixedExtentList( @@ -285,7 +290,7 @@ void main() { expect(tester.getCenter(button).dx, equals(400.0)); }); - testWidgets('alignment with a flexible works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('alignment with a flexible works', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<Widget> slivers = <Widget>[ sliverBox, @@ -354,7 +359,7 @@ void main() { }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); group('fillOverscroll: true, relevant platforms', () { - testWidgets('child without size is sized by extent and overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child without size is sized by extent and overscroll', (WidgetTester tester) async { final List<Widget> slivers = <Widget>[ sliverBox, SliverFillRemaining( @@ -381,7 +386,7 @@ void main() { expect(box3.size.height, equals(450)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('child with smaller size is overridden and sized by extent and overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child with smaller size is overridden and sized by extent and overscroll', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<Widget> slivers = <Widget>[ sliverBox, @@ -428,9 +433,10 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('extent is overridden by child size and overscroll if precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extent is overridden by child size and overscroll if precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<Widget> slivers = <Widget>[ SliverFixedExtentList( itemExtent: 150, @@ -492,9 +498,10 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('fillOverscroll works when child has no size and precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fillOverscroll works when child has no size and precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<Widget> slivers = <Widget>[ SliverFixedExtentList( itemExtent: 150, @@ -554,7 +561,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('alignment with a flexible works with fillOverscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('alignment with a flexible works with fillOverscroll', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<Widget> slivers = <Widget>[ sliverBox, @@ -648,7 +655,7 @@ void main() { group('fillOverscroll: true, is ignored on irrelevant platforms', () { // Android/Other scroll physics when hasScrollBody: false, ignores fillOverscroll: true - testWidgets('child without size is sized by extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child without size is sized by extent', (WidgetTester tester) async { final List<Widget> slivers = <Widget>[ sliverBox, SliverFillRemaining( @@ -667,7 +674,7 @@ void main() { expect(box2.size.height, equals(450)); }); - testWidgets('child with size is overridden and sized by extent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child with size is overridden and sized by extent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<Widget> slivers = <Widget>[ sliverBox, @@ -706,9 +713,10 @@ void main() { expect(tester.getCenter(button).dx, equals(400.0)); }); - testWidgets('extent is overridden by child size if precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('extent is overridden by child size if precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<Widget> slivers = <Widget>[ SliverFixedExtentList( itemExtent: 150, @@ -763,9 +771,10 @@ void main() { expect(tester.getCenter(button).dx, equals(400.0)); }); - testWidgets('child has no size and precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child has no size and precedingScrollExtent > viewportMainAxisExtent', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<Widget> slivers = <Widget>[ SliverFixedExtentList( itemExtent: 150, From 98ebab58ee862d078204ae2dce9fbd5cdba6abf1 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Wed, 20 Sep 2023 16:34:41 +0200 Subject: [PATCH 1358/1547] Cover more test/widgets tests with leak tracking #8 (#135045) --- .../test/widgets/scroll_interaction_test.dart | 3 +- .../widgets/scroll_notification_test.dart | 11 +- .../test/widgets/scroll_physics_test.dart | 3 +- .../test/widgets/scroll_position_test.dart | 16 +- .../test/widgets/scroll_view_test.dart | 330 ++++++++++----- .../widgets/scrollable_animations_test.dart | 10 +- .../test/widgets/scrollable_dispose_test.dart | 6 +- .../test/widgets/scrollable_fling_test.dart | 7 +- .../test/widgets/scrollable_grid_test.dart | 7 +- .../test/widgets/scrollable_helpers_test.dart | 31 +- .../widgets/scrollable_in_overlay_test.dart | 4 +- .../scrollable_list_hit_testing_test.dart | 11 +- .../test/widgets/scrollable_of_test.dart | 17 +- .../widgets/scrollable_restoration_test.dart | 37 +- .../widgets/scrollable_selection_test.dart | 73 ++-- .../widgets/scrollable_semantics_test.dart | 37 +- ...llable_semantics_traversal_order_test.dart | 38 +- .../flutter/test/widgets/scrollable_test.dart | 105 ++--- .../flutter/test/widgets/scrollbar_test.dart | 147 ++++--- .../selectable_region_context_menu_test.dart | 4 +- .../test/widgets/selectable_region_test.dart | 390 +++++++++++++----- 21 files changed, 868 insertions(+), 419 deletions(-) diff --git a/packages/flutter/test/widgets/scroll_interaction_test.dart b/packages/flutter/test/widgets/scroll_interaction_test.dart index f0dd0c3b0a916..06a1735d06e36 100644 --- a/packages/flutter/test/widgets/scroll_interaction_test.dart +++ b/packages/flutter/test/widgets/scroll_interaction_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Scroll flings twice in a row does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll flings twice in a row does not crash', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/scroll_notification_test.dart b/packages/flutter/test/widgets/scroll_notification_test.dart index 0493f8ab25231..d1b1c7f6d71d8 100644 --- a/packages/flutter/test/widgets/scroll_notification_test.dart +++ b/packages/flutter/test/widgets/scroll_notification_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('ScrollMetricsNotification test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollMetricsNotification test', (WidgetTester tester) async { final List<Notification> events = <Notification>[]; Widget buildFrame(double height) { return NotificationListener<Notification>( @@ -62,7 +63,7 @@ void main() { expect(events.length, 0); }); - testWidgets('Scroll notification basics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll notification basics', (WidgetTester tester) async { late ScrollNotification notification; await tester.pumpWidget(NotificationListener<ScrollNotification>( @@ -103,7 +104,7 @@ void main() { expect(end.dragDetails!.velocity, equals(Velocity.zero)); }); - testWidgets('Scroll notification depth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll notification depth', (WidgetTester tester) async { final List<Type> depth0Types = <Type>[]; final List<Type> depth1Types = <Type>[]; final List<int> depth0Values = <int>[]; @@ -158,7 +159,7 @@ void main() { expect(depth1Values, equals(<int>[1, 1, 1, 1, 1])); }); - testWidgets('ScrollNotifications bubble past Scaffold Material', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollNotifications bubble past Scaffold Material', (WidgetTester tester) async { final List<Type> notificationTypes = <Type>[]; await tester.pumpWidget( @@ -206,7 +207,7 @@ void main() { expect(notificationTypes, equals(types)); }); - testWidgets('ScrollNotificationObserver', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollNotificationObserver', (WidgetTester tester) async { late ScrollNotificationObserverState observer; ScrollNotification? notification; diff --git a/packages/flutter/test/widgets/scroll_physics_test.dart b/packages/flutter/test/widgets/scroll_physics_test.dart index 6f209bc12bf7e..6185ff15e7111 100644 --- a/packages/flutter/test/widgets/scroll_physics_test.dart +++ b/packages/flutter/test/widgets/scroll_physics_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestScrollPhysics extends ScrollPhysics { const TestScrollPhysics({ @@ -339,7 +340,7 @@ FlutterError } }); - testWidgets('PageScrollPhysics work with NestedScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageScrollPhysics work with NestedScrollView', (WidgetTester tester) async { // Regression test for: https://github.com/flutter/flutter/issues/47850 await tester.pumpWidget(Material( child: Directionality( diff --git a/packages/flutter/test/widgets/scroll_position_test.dart b/packages/flutter/test/widgets/scroll_position_test.dart index 4ada8e22f3fee..8d6f0648329dd 100644 --- a/packages/flutter/test/widgets/scroll_position_test.dart +++ b/packages/flutter/test/widgets/scroll_position_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; ScrollController _controller = ScrollController( initialScrollOffset: 110.0, @@ -140,7 +141,7 @@ Future<void> performTest(WidgetTester tester, bool maintainState) async { } void main() { - testWidgets("ScrollPosition jumpTo() doesn't call notifyListeners twice", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ScrollPosition jumpTo() doesn't call notifyListeners twice", (WidgetTester tester) async { int count = 0; await tester.pumpWidget(MaterialApp( home: ListView.builder( @@ -159,15 +160,22 @@ void main() { expect(count, 1); }); - testWidgets('whether we remember our scroll position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('whether we remember our scroll position', (WidgetTester tester) async { await performTest(tester, true); await performTest(tester, false); }); - testWidgets('scroll alignment is honored by ensureVisible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scroll alignment is honored by ensureVisible', (WidgetTester tester) async { final List<int> items = List<int>.generate(11, (int index) => index).toList(); final List<FocusNode> nodes = List<FocusNode>.generate(11, (int index) => FocusNode(debugLabel: 'Item ${index + 1}')).toList(); + addTearDown(() { + for (final FocusNode node in nodes) { + node.dispose(); + } + }); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: ListView( @@ -226,7 +234,7 @@ void main() { expect(controller.position.pixels, equals(0.0)); }); - testWidgets('jumpTo recommends deferred loading', (WidgetTester tester) async { + testWidgetsWithLeakTracking('jumpTo recommends deferred loading', (WidgetTester tester) async { int loadedWithDeferral = 0; int buildCount = 0; const double height = 500; diff --git a/packages/flutter/test/widgets/scroll_view_test.dart b/packages/flutter/test/widgets/scroll_view_test.dart index be22bf40741c6..a957e71560986 100644 --- a/packages/flutter/test/widgets/scroll_view_test.dart +++ b/packages/flutter/test/widgets/scroll_view_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/services.dart' show LogicalKeyboardKey; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'states.dart'; @@ -68,7 +69,7 @@ Widget primaryScrollControllerBoilerplate({ required Widget child, required Scro } void main() { - testWidgets('ListView control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView control test', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -110,8 +111,13 @@ void main() { log.clear(); }); - testWidgets('ListView dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView( @@ -143,7 +149,7 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('GridView.builder supports null items', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder supports null items', (WidgetTester tester) async { await tester.pumpWidget(textFieldBoilerplate( child: GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( @@ -163,7 +169,7 @@ void main() { expect(find.text('item'), findsNWidgets(5)); }); - testWidgets('ListView.builder supports null items', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder supports null items', (WidgetTester tester) async { await tester.pumpWidget(textFieldBoilerplate( child: ListView.builder( itemCount: 42, @@ -180,11 +186,14 @@ void main() { expect(find.text('item'), findsNWidgets(5)); }); - testWidgets('PageView supports null items in itemBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView supports null items in itemBuilder', (WidgetTester tester) async { + final PageController controller = PageController(viewportFraction: 1 / 5); + addTearDown(controller.dispose); + await tester.pumpWidget(textFieldBoilerplate( child: PageView.builder( itemCount: 5, - controller: PageController(viewportFraction: 1/5), + controller: controller, itemBuilder: (BuildContext context, int index) { if (index == 2) { return null; @@ -198,7 +207,7 @@ void main() { expect(find.text('item'), findsNWidgets(2)); }); - testWidgets('ListView.separated supports null items in itemBuilder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated supports null items in itemBuilder', (WidgetTester tester) async { await tester.pumpWidget(textFieldBoilerplate( child: ListView.separated( itemCount: 42, @@ -219,8 +228,13 @@ void main() { expect(find.text('separator'), findsNWidgets(5)); }); - testWidgets('ListView.builder dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView.builder( @@ -253,8 +267,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('ListView.custom dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.custom dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView.custom( @@ -289,8 +308,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('ListView.separated dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView.separated( @@ -324,8 +348,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('GridView dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView( @@ -358,8 +387,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('GridView.builder dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.builder( @@ -393,8 +427,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('GridView.count dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.count dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.count( @@ -427,8 +466,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('GridView.extent dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.extent dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.extent( @@ -461,8 +505,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('GridView.custom dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.custom dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.custom( @@ -498,8 +547,13 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('ListView dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView( @@ -530,8 +584,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('ListView.builder dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView.builder( @@ -563,8 +622,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('ListView.custom dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.custom dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView.custom( @@ -598,8 +662,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('ListView.separated dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: ListView.separated( @@ -632,8 +701,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('GridView dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView( @@ -665,8 +739,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('GridView.builder dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.builder( @@ -699,8 +778,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('GridView.count dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.count dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.count( @@ -732,8 +816,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('GridView.extent dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.extent dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.extent( @@ -765,8 +854,13 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('GridView.custom dismiss keyboard manual test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.custom dismiss keyboard manual test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: GridView.custom( @@ -801,7 +895,7 @@ void main() { expect(textField.focusNode!.hasFocus, isTrue); }); - testWidgets('ListView restart ballistic activity out of range', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView restart ballistic activity out of range', (WidgetTester tester) async { Widget buildListView(int n) { return Directionality( textDirection: TextDirection.ltr, @@ -831,7 +925,7 @@ void main() { expect(viewport.offset.pixels, equals(2400.0)); }); - testWidgets('CustomScrollView control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView control test', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( @@ -879,8 +973,13 @@ void main() { log.clear(); }); - testWidgets('CustomScrollView dismiss keyboard onDrag test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView dismiss keyboard onDrag test', (WidgetTester tester) async { final List<FocusNode> focusNodes = List<FocusNode>.generate(50, (int i) => FocusNode()); + addTearDown(() { + for (final FocusNode node in focusNodes) { + node.dispose(); + } + }); await tester.pumpWidget(textFieldBoilerplate( child: CustomScrollView( @@ -918,9 +1017,10 @@ void main() { expect(textField.focusNode!.hasFocus, isFalse); }); - testWidgets('Can jumpTo during drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can jumpTo during drag', (WidgetTester tester) async { final List<Type> log = <Type>[]; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -977,23 +1077,26 @@ void main() { }); test('PrimaryScrollController.automaticallyInheritOnPlatforms defaults to all mobile platforms', (){ - final PrimaryScrollController primaryScrollController = PrimaryScrollController( - controller: ScrollController(), - child: const SizedBox(), - ); - expect( - primaryScrollController.automaticallyInheritForPlatforms, - TargetPlatformVariant.mobile().values, - ); + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + final PrimaryScrollController primaryScrollController = PrimaryScrollController( + controller: controller, + child: const SizedBox(), + ); + expect( + primaryScrollController.automaticallyInheritForPlatforms, + TargetPlatformVariant.mobile().values, + ); }); - testWidgets('Vertical CustomScrollViews are not primary by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical CustomScrollViews are not primary by default', (WidgetTester tester) async { const CustomScrollView view = CustomScrollView(); expect(view.primary, isNull); }); - testWidgets('Vertical CustomScrollViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical CustomScrollViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: const CustomScrollView(), controller: controller, @@ -1001,8 +1104,9 @@ void main() { expect(controller.hasClients, isTrue); }, variant: TargetPlatformVariant.mobile()); - testWidgets("Vertical CustomScrollViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Vertical CustomScrollViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: const CustomScrollView(), controller: controller, @@ -1010,13 +1114,14 @@ void main() { expect(controller.hasClients, isFalse); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Vertical ListViews are not primary by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical ListViews are not primary by default', (WidgetTester tester) async { final ListView view = ListView(); expect(view.primary, isNull); }); - testWidgets('Vertical ListViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical ListViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: ListView(), controller: controller, @@ -1024,8 +1129,9 @@ void main() { expect(controller.hasClients, isTrue); }, variant: TargetPlatformVariant.mobile()); - testWidgets("Vertical ListViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Vertical ListViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: ListView(), controller: controller, @@ -1033,13 +1139,14 @@ void main() { expect(controller.hasClients, isFalse); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Vertical GridViews are not primary by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical GridViews are not primary by default', (WidgetTester tester) async { final GridView view = GridView.count(crossAxisCount: 1); expect(view.primary, isNull); }); - testWidgets('Vertical GridViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical GridViews use PrimaryScrollController by default on mobile', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: GridView.count(crossAxisCount: 1), controller: controller, @@ -1047,8 +1154,9 @@ void main() { expect(controller.hasClients, isTrue); }, variant: TargetPlatformVariant.mobile()); - testWidgets("Vertical GridViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Vertical GridViews don't use PrimaryScrollController by default on desktop", (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: GridView.count(crossAxisCount: 1), controller: controller, @@ -1056,79 +1164,98 @@ void main() { expect(controller.hasClients, isFalse); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Horizontal CustomScrollViews are non-primary by default', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); + testWidgetsWithLeakTracking('Horizontal CustomScrollViews are non-primary by default', (WidgetTester tester) async { + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: CustomScrollView( scrollDirection: Axis.horizontal, - controller: ScrollController(), + controller: controller2, ), - controller: controller, + controller: controller1, )); - expect(controller.hasClients, isFalse); + expect(controller1.hasClients, isFalse); }); - testWidgets('Horizontal ListViews are non-primary by default', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); + testWidgetsWithLeakTracking('Horizontal ListViews are non-primary by default', (WidgetTester tester) async { + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: ListView( scrollDirection: Axis.horizontal, - controller: ScrollController(), + controller: controller2, ), - controller: controller, + controller: controller1, )); - expect(controller.hasClients, isFalse); + expect(controller1.hasClients, isFalse); }); - testWidgets('Horizontal GridViews are non-primary by default', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); + testWidgetsWithLeakTracking('Horizontal GridViews are non-primary by default', (WidgetTester tester) async { + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: GridView.count( scrollDirection: Axis.horizontal, - controller: ScrollController(), + controller: controller2, crossAxisCount: 1, ), - controller: controller, + controller: controller1, )); - expect(controller.hasClients, isFalse); + expect(controller1.hasClients, isFalse); }); - testWidgets('CustomScrollViews with controllers are non-primary by default', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); + testWidgetsWithLeakTracking('CustomScrollViews with controllers are non-primary by default', (WidgetTester tester) async { + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: CustomScrollView( - controller: ScrollController(), + controller: controller2, ), - controller: controller, + controller: controller1, )); - expect(controller.hasClients, isFalse); + expect(controller1.hasClients, isFalse); }); - testWidgets('ListViews with controllers are non-primary by default', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); + testWidgetsWithLeakTracking('ListViews with controllers are non-primary by default', (WidgetTester tester) async { + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: ListView( - controller: ScrollController(), + controller: controller2, ), - controller: controller, + controller: controller1, )); - expect(controller.hasClients, isFalse); + expect(controller1.hasClients, isFalse); }); - testWidgets('GridViews with controllers are non-primary by default', (WidgetTester tester) async { - final ScrollController controller = ScrollController(); + testWidgetsWithLeakTracking('GridViews with controllers are non-primary by default', (WidgetTester tester) async { + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget(primaryScrollControllerBoilerplate( child: GridView.count( - controller: ScrollController(), + controller: controller2, crossAxisCount: 1, ), - controller: controller, + controller: controller1, )); - expect(controller.hasClients, isFalse); + expect(controller1.hasClients, isFalse); }); - testWidgets('CustomScrollView sets PrimaryScrollController when primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView sets PrimaryScrollController when primary', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1142,8 +1269,9 @@ void main() { expect(scrollable.controller, primaryScrollController); }); - testWidgets('ListView sets PrimaryScrollController when primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView sets PrimaryScrollController when primary', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1157,8 +1285,9 @@ void main() { expect(scrollable.controller, primaryScrollController); }); - testWidgets('GridView sets PrimaryScrollController when primary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView sets PrimaryScrollController when primary', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1172,9 +1301,10 @@ void main() { expect(scrollable.controller, primaryScrollController); }); - testWidgets('Nested scrollables have a null PrimaryScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested scrollables have a null PrimaryScrollController', (WidgetTester tester) async { const Key innerKey = Key('inner'); final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1202,27 +1332,27 @@ void main() { expect(innerScrollable.controller, isNull); }); - testWidgets('Primary ListViews are always scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Primary ListViews are always scrollable', (WidgetTester tester) async { final ListView view = ListView(primary: true); expect(view.physics, isA<AlwaysScrollableScrollPhysics>()); }); - testWidgets('Non-primary ListViews are not always scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Non-primary ListViews are not always scrollable', (WidgetTester tester) async { final ListView view = ListView(primary: false); expect(view.physics, isNot(isA<AlwaysScrollableScrollPhysics>())); }); - testWidgets('Defaulting-to-primary ListViews are always scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Defaulting-to-primary ListViews are always scrollable', (WidgetTester tester) async { final ListView view = ListView(); expect(view.physics, isA<AlwaysScrollableScrollPhysics>()); }); - testWidgets('Defaulting-to-not-primary ListViews are not always scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Defaulting-to-not-primary ListViews are not always scrollable', (WidgetTester tester) async { final ListView view = ListView(scrollDirection: Axis.horizontal); expect(view.physics, isNot(isA<AlwaysScrollableScrollPhysics>())); }); - testWidgets('primary:true leads to scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('primary:true leads to scrolling', (WidgetTester tester) async { bool scrolled = false; await tester.pumpWidget( Directionality( @@ -1242,7 +1372,7 @@ void main() { expect(scrolled, isTrue); }); - testWidgets('primary:false leads to no scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('primary:false leads to no scrolling', (WidgetTester tester) async { bool scrolled = false; await tester.pumpWidget( Directionality( @@ -1262,7 +1392,7 @@ void main() { expect(scrolled, isFalse); }); - testWidgets('physics:AlwaysScrollableScrollPhysics actually overrides primary:false default behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('physics:AlwaysScrollableScrollPhysics actually overrides primary:false default behavior', (WidgetTester tester) async { bool scrolled = false; await tester.pumpWidget( Directionality( @@ -1283,7 +1413,7 @@ void main() { expect(scrolled, isTrue); }); - testWidgets('physics:ScrollPhysics actually overrides primary:true default behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('physics:ScrollPhysics actually overrides primary:true default behavior', (WidgetTester tester) async { bool scrolled = false; await tester.pumpWidget( Directionality( @@ -1304,7 +1434,7 @@ void main() { expect(scrolled, isFalse); }); - testWidgets('separatorBuilder must return something', (WidgetTester tester) async { + testWidgetsWithLeakTracking('separatorBuilder must return something', (WidgetTester tester) async { const List<String> listOfValues = <String>['ALPHA', 'BETA', 'GAMMA', 'DELTA']; Widget buildFrame(Widget firstSeparator) { @@ -1332,7 +1462,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('when itemBuilder throws, creates Error Widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when itemBuilder throws, creates Error Widget', (WidgetTester tester) async { const List<String> listOfValues = <String>['ALPHA', 'BETA', 'GAMMA', 'DELTA']; Widget buildFrame(bool throwOnFirstItem) { @@ -1363,7 +1493,7 @@ void main() { expect(finder, findsOneWidget); }); - testWidgets('when separatorBuilder throws, creates ErrorWidget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when separatorBuilder throws, creates ErrorWidget', (WidgetTester tester) async { const List<String> listOfValues = <String>['ALPHA', 'BETA', 'GAMMA', 'DELTA']; const Key key = Key('list'); @@ -1399,14 +1529,14 @@ void main() { expect(finder, findsOneWidget); }); - testWidgets('ListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { expect(() => ListView( itemExtent: 100, prototypeItem: const SizedBox(), ), throwsAssertionError); }); - testWidgets('ListView.builder asserts on negative childCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder asserts on negative childCount', (WidgetTester tester) async { expect(() => ListView.builder( itemBuilder: (BuildContext context, int index) { return const SizedBox(); @@ -1415,7 +1545,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('ListView.builder asserts on negative semanticChildCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder asserts on negative semanticChildCount', (WidgetTester tester) async { expect(() => ListView.builder( itemBuilder: (BuildContext context, int index) { return const SizedBox(); @@ -1425,7 +1555,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('ListView.builder asserts on nonsensical childCount/semanticChildCount', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder asserts on nonsensical childCount/semanticChildCount', (WidgetTester tester) async { expect(() => ListView.builder( itemBuilder: (BuildContext context, int index) { return const SizedBox(); @@ -1435,7 +1565,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('ListView.builder asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { expect(() => ListView.builder( itemBuilder: (BuildContext context, int index) { return const SizedBox(); @@ -1445,7 +1575,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('ListView.custom asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.custom asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { expect(() => ListView.custom( childrenDelegate: SliverChildBuilderDelegate( (BuildContext context, int index) { @@ -1457,7 +1587,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('PrimaryScrollController provides fallback ScrollActions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PrimaryScrollController provides fallback ScrollActions', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: CustomScrollView( @@ -1501,7 +1631,7 @@ void main() { ); }); - testWidgets('Fallback ScrollActions handle too many positions with error message', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fallback ScrollActions handle too many positions with error message', (WidgetTester tester) async { Widget getScrollView() { return SizedBox( width: 400.0, @@ -1550,7 +1680,7 @@ void main() { ); }); - testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { final List<int> numbers = <int>[0,1,2]; await tester.pumpWidget( @@ -1588,7 +1718,7 @@ void main() { expect(item2Height, 30.0); }); - testWidgets('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { final List<int> numbers = <int>[0,1,2]; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/scrollable_animations_test.dart b/packages/flutter/test/widgets/scrollable_animations_test.dart index b055f6a635fe8..041d2496561e5 100644 --- a/packages/flutter/test/widgets/scrollable_animations_test.dart +++ b/packages/flutter/test/widgets/scrollable_animations_test.dart @@ -5,10 +5,12 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Does not animate if already at target position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not animate if already at target position', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -27,8 +29,9 @@ void main() { expect(controller.position.pixels, currentPosition); }); - testWidgets('Does not animate if already at target position within tolerance', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not animate if already at target position within tolerance', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -50,8 +53,9 @@ void main() { expect(controller.position.pixels, targetPosition); }); - testWidgets('Animates if going to a position outside of tolerance', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animates if going to a position outside of tolerance', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/scrollable_dispose_test.dart b/packages/flutter/test/widgets/scrollable_dispose_test.dart index 79eaf6bc86196..90eec2250c3fa 100644 --- a/packages/flutter/test/widgets/scrollable_dispose_test.dart +++ b/packages/flutter/test/widgets/scrollable_dispose_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; void main() { - testWidgets('simultaneously dispose a widget and end the scroll animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('simultaneously dispose a widget and end the scroll animation', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -26,10 +27,11 @@ void main() { await tester.pump(const Duration(hours: 5)); }); - testWidgets('Disposing a (nested) Scrollable while holding in overscroll does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing a (nested) Scrollable while holding in overscroll does not crash', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/27707. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final Key outerContainer = GlobalKey(); await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/scrollable_fling_test.dart b/packages/flutter/test/widgets/scrollable_fling_test.dart index 3d521377007b1..29dc51b0933bc 100644 --- a/packages/flutter/test/widgets/scrollable_fling_test.dart +++ b/packages/flutter/test/widgets/scrollable_fling_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const TextStyle testFont = TextStyle( color: Color(0xFF00FF00), @@ -31,7 +32,7 @@ Future<void> pumpTest(WidgetTester tester, TargetPlatform platform) async { const double dragOffset = 213.82; void main() { - testWidgets('Flings on different platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flings on different platforms', (WidgetTester tester) async { double getCurrentOffset() { return tester.state<ScrollableState>(find.byType(Scrollable)).position.pixels; } @@ -96,7 +97,7 @@ void main() { expect(linuxResult, equals(androidResult)); }); - testWidgets('fling and tap to stop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling and tap to stop', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( Directionality( @@ -126,7 +127,7 @@ void main() { expect(log, equals(<String>['tap 21', 'tap 35'])); }); - testWidgets('fling and wait and tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling and wait and tap', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/scrollable_grid_test.dart b/packages/flutter/test/widgets/scrollable_grid_test.dart index 86c4dfaeb20a1..0f404f4188b93 100644 --- a/packages/flutter/test/widgets/scrollable_grid_test.dart +++ b/packages/flutter/test/widgets/scrollable_grid_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('GridView default control', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView default control', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -20,7 +21,7 @@ void main() { }); // Tests https://github.com/flutter/flutter/issues/5522 - testWidgets('GridView displays correct children with nonzero padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView displays correct children with nonzero padding', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.fromLTRB(0.0, 100.0, 0.0, 0.0); final Widget testWidget = Directionality( @@ -76,7 +77,7 @@ void main() { expect(find.text('4'), findsNothing); }); - testWidgets('GridView.count() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.count() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/9506 Widget buildFrame(int itemCount) { return Directionality( diff --git a/packages/flutter/test/widgets/scrollable_helpers_test.dart b/packages/flutter/test/widgets/scrollable_helpers_test.dart index 17b623dc09f61..f693442e5f14e 100644 --- a/packages/flutter/test/widgets/scrollable_helpers_test.dart +++ b/packages/flutter/test/widgets/scrollable_helpers_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; final LogicalKeyboardKey modifierKey = defaultTargetPlatform == TargetPlatform.macOS ? LogicalKeyboardKey.metaLeft @@ -13,8 +14,9 @@ final LogicalKeyboardKey modifierKey = defaultTargetPlatform == TargetPlatform.m void main() { group('ScrollableDetails', (){ - final ScrollController controller = ScrollController(); test('copyWith / == / hashCode', () { + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final ScrollableDetails details = ScrollableDetails( direction: AxisDirection.down, controller: controller, @@ -42,6 +44,8 @@ void main() { }); test('toString', (){ + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); const ScrollableDetails bareDetails = ScrollableDetails( direction: AxisDirection.right, ); @@ -86,8 +90,9 @@ void main() { }); }); - testWidgets("Keyboard scrolling doesn't happen if scroll physics are set to NeverScrollableScrollPhysics", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Keyboard scrolling doesn't happen if scroll physics are set to NeverScrollableScrollPhysics", (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.fuchsia), @@ -152,8 +157,9 @@ void main() { ); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Vertical scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.fuchsia), @@ -223,8 +229,9 @@ void main() { ); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Horizontal scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.fuchsia), @@ -283,8 +290,9 @@ void main() { ); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Horizontal scrollables are scrolled the correct direction in RTL locales.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal scrollables are scrolled the correct direction in RTL locales.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.fuchsia), @@ -346,9 +354,11 @@ void main() { ); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Reversed vertical scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reversed vertical scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(debugLabel: 'SizedBox'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.fuchsia), @@ -420,9 +430,11 @@ void main() { ); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Reversed horizontal scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reversed horizontal scrollables are scrolled when activated via keyboard.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(debugLabel: 'SizedBox'); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( theme: ThemeData(platform: TargetPlatform.fuchsia), @@ -479,8 +491,9 @@ void main() { await tester.pumpAndSettle(); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Custom scrollables with a center sliver are scrolled when activated via keyboard.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Custom scrollables with a center sliver are scrolled when activated via keyboard.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final List<String> items = List<String>.generate(20, (int index) => 'Item $index'); await tester.pumpWidget( MaterialApp( @@ -550,7 +563,7 @@ void main() { ); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Can scroll using intents only', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can scroll using intents only', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: ListView( diff --git a/packages/flutter/test/widgets/scrollable_in_overlay_test.dart b/packages/flutter/test/widgets/scrollable_in_overlay_test.dart index c28f535b8625b..2207c762bcf7a 100644 --- a/packages/flutter/test/widgets/scrollable_in_overlay_test.dart +++ b/packages/flutter/test/widgets/scrollable_in_overlay_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { test('Can dispose ScrollPosition when hasPixels is false', () { @@ -18,9 +19,10 @@ void main() { position.dispose(); // Should not throw/assert. }); - testWidgets('scrollable in hidden overlay does not crash when unhidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrollable in hidden overlay does not crash when unhidden', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/44269. final TabController controller = TabController(vsync: const TestVSync(), length: 1); + addTearDown(controller.dispose); final OverlayEntry entry1 = OverlayEntry( maintainState: true, diff --git a/packages/flutter/test/widgets/scrollable_list_hit_testing_test.dart b/packages/flutter/test/widgets/scrollable_list_hit_testing_test.dart index e956f34bd9a09..15bef69c25d0b 100644 --- a/packages/flutter/test/widgets/scrollable_list_hit_testing_test.dart +++ b/packages/flutter/test/widgets/scrollable_list_hit_testing_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const List<int> items = <int>[0, 1, 2, 3, 4, 5]; void main() { - testWidgets('Tap item after scroll - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap item after scroll - horizontal', (WidgetTester tester) async { final List<int> tapped = <int>[]; await tester.pumpWidget( Directionality( @@ -51,7 +52,7 @@ void main() { expect(tapped, equals(<int>[2])); }); - testWidgets('Tap item after scroll - vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap item after scroll - vertical', (WidgetTester tester) async { final List<int> tapped = <int>[]; await tester.pumpWidget( Directionality( @@ -94,7 +95,7 @@ void main() { expect(tapped, equals(<int>[1])); // the center of the third item is off-screen so it shouldn't get hit }); - testWidgets('Padding scroll anchor start', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding scroll anchor start', (WidgetTester tester) async { final List<int> tapped = <int>[]; await tester.pumpWidget( @@ -126,7 +127,7 @@ void main() { expect(tapped, equals(<int>[0, 1, 1])); }); - testWidgets('Padding scroll anchor end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding scroll anchor end', (WidgetTester tester) async { final List<int> tapped = <int>[]; await tester.pumpWidget( @@ -159,7 +160,7 @@ void main() { expect(tapped, equals(<int>[0, 1, 1])); }); - testWidgets('Tap immediately following clamped overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap immediately following clamped overscroll', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/5709 final List<int> tapped = <int>[]; diff --git a/packages/flutter/test/widgets/scrollable_of_test.dart b/packages/flutter/test/widgets/scrollable_of_test.dart index 03ce562419b8c..1aec1979dd200 100644 --- a/packages/flutter/test/widgets/scrollable_of_test.dart +++ b/packages/flutter/test/widgets/scrollable_of_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class ScrollPositionListener extends StatefulWidget { const ScrollPositionListener({ super.key, required this.child, required this.log}); @@ -123,9 +124,10 @@ class TestChildState extends State<TestChild> { } void main() { - testWidgets('Scrollable.of() dependent rebuilds when Scrollable position changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable.of() dependent rebuilds when Scrollable position changes', (WidgetTester tester) async { late String logValue; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); // Changing the SingleChildScrollView's physics causes the // ScrollController's ScrollPosition to be rebuilt. @@ -163,7 +165,7 @@ void main() { expect(logValue, 'listener 400.0'); }); - testWidgets('Scrollable.of() is possible using ScrollNotification context', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable.of() is possible using ScrollNotification context', (WidgetTester tester) async { late ScrollNotification notification; await tester.pumpWidget(NotificationListener<ScrollNotification>( @@ -183,9 +185,11 @@ void main() { expect(Scrollable.of(notification.context!), equals(scrollableElement.state)); }); - testWidgets('Static Scrollable methods can target a specific axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Static Scrollable methods can target a specific axis', (WidgetTester tester) async { final TestScrollController horizontalController = TestScrollController(deferLoading: true); + addTearDown(horizontalController.dispose); final TestScrollController verticalController = TestScrollController(deferLoading: false); + addTearDown(verticalController.dispose); late final AxisDirection foundAxisDirection; late final bool foundRecommendation; @@ -218,7 +222,7 @@ void main() { expect(foundRecommendation, isTrue); }); - testWidgets('Axis targeting scrollables establishes the correct dependencies', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Axis targeting scrollables establishes the correct dependencies', (WidgetTester tester) async { final GlobalKey<TestScrollableState> verticalKey = GlobalKey<TestScrollableState>(); final GlobalKey<TestChildState> childKey = GlobalKey<TestChildState>(); @@ -237,12 +241,15 @@ void main() { expect(verticalKey.currentState!.dependenciesChanged, 1); expect(childKey.currentState!.dependenciesChanged, 1); + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + // Change the horizontal ScrollView, adding a controller await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: SingleChildScrollView( scrollDirection: Axis.horizontal, - controller: ScrollController(), + controller: controller, child: TestScrollable( key: verticalKey, child: TestChild(key: childKey), diff --git a/packages/flutter/test/widgets/scrollable_restoration_test.dart b/packages/flutter/test/widgets/scrollable_restoration_test.dart index fb5e251941d32..2aac5a4148e14 100644 --- a/packages/flutter/test/widgets/scrollable_restoration_test.dart +++ b/packages/flutter/test/widgets/scrollable_restoration_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('CustomScrollView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CustomScrollView restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: CustomScrollView( @@ -33,7 +34,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('ListView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListView( @@ -53,7 +54,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('ListView.builder restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.builder restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListView.builder( @@ -70,7 +71,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('ListView.separated restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.separated restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListView.separated( @@ -89,7 +90,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('ListView.custom restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListView.custom restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListView.custom( @@ -111,7 +112,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('GridView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: GridView( @@ -132,7 +133,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('GridView.builder restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.builder restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: GridView.builder( @@ -150,7 +151,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('GridView.custom restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.custom restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: GridView.custom( @@ -173,7 +174,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('GridView.count restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.count restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: GridView.count( @@ -194,7 +195,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('GridView.extent restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('GridView.extent restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: GridView.extent( @@ -215,7 +216,7 @@ void main() { await restoreScrollAndVerify(tester); }); - testWidgets('SingleChildScrollView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleChildScrollView restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: SingleChildScrollView( @@ -262,7 +263,7 @@ void main() { expect(tester.getTopLeft(find.text('Tile 1')), const Offset(0, -475)); }); - testWidgets('PageView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: PageView( @@ -278,7 +279,7 @@ void main() { await pageViewScrollAndRestore(tester); }); - testWidgets('PageView.builder restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView.builder restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: PageView.builder( @@ -294,7 +295,7 @@ void main() { await pageViewScrollAndRestore(tester); }); - testWidgets('PageView.custom restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PageView.custom restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: PageView.custom( @@ -315,7 +316,7 @@ void main() { await pageViewScrollAndRestore(tester); }); - testWidgets('ListWheelScrollView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListWheelScrollView restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListWheelScrollView( @@ -332,7 +333,7 @@ void main() { await restoreScrollAndVerify(tester, secondOffset: 542); }); - testWidgets('ListWheelScrollView.useDelegate restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListWheelScrollView.useDelegate restoration', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListWheelScrollView.useDelegate( @@ -354,7 +355,7 @@ void main() { await restoreScrollAndVerify(tester, secondOffset: 542); }); - testWidgets('NestedScrollView restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView restoration', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: TestHarness( @@ -422,7 +423,7 @@ void main() { expect(find.text('Tile 10'), findsOneWidget); }); - testWidgets('RestorationData is flushed even if no frame is scheduled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorationData is flushed even if no frame is scheduled', (WidgetTester tester) async { await tester.pumpWidget( TestHarness( child: ListView( diff --git a/packages/flutter/test/widgets/scrollable_selection_test.dart b/packages/flutter/test/widgets/scrollable_selection_test.dart index ea3fa2843a3e0..fbafd52e28215 100644 --- a/packages/flutter/test/widgets/scrollable_selection_test.dart +++ b/packages/flutter/test/widgets/scrollable_selection_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'clipboard_utils.dart'; import 'keyboard_utils.dart'; @@ -36,7 +37,7 @@ void main() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null); }); - testWidgets('mouse can select multiple widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -74,7 +75,7 @@ void main() { await gesture.up(); }); - testWidgets('mouse can select multiple widgets - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets - horizontal', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -107,7 +108,7 @@ void main() { await gesture.up(); }); - testWidgets('mouse can select multiple widgets on double-click drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets on double-click drag', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -151,7 +152,7 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. - testWidgets('mouse can select multiple widgets on double-click drag - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets on double-click drag - horizontal', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -190,8 +191,9 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. - testWidgets('select to scroll forward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll forward', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -239,8 +241,9 @@ void main() { await gesture.up(); }); - testWidgets('select to scroll works for small scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll works for small scrollable', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: SelectionArea( @@ -285,8 +288,9 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('select to scroll backward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll backward', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -333,8 +337,9 @@ void main() { expect(paragraph3.selections[0], const TextSelection(baseOffset: 6, extentOffset: 0)); }); - testWidgets('select to scroll forward - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll forward - horizontal', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -381,8 +386,9 @@ void main() { await gesture.up(); }); - testWidgets('select to scroll backward - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll backward - horizontal', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -430,8 +436,9 @@ void main() { await gesture.up(); }); - testWidgets('preserve selection when out of view.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('preserve selection when out of view.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -477,8 +484,9 @@ void main() { expect(paragraph50.selections[0], const TextSelection(baseOffset: 2, extentOffset: 4)); }); - testWidgets('can select all non-Apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can select all non-Apple', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: node, @@ -503,8 +511,9 @@ void main() { expect(find.text('Item 13'), findsNothing); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.windows, TargetPlatform.linux, TargetPlatform.fuchsia })); - testWidgets('can select all - Apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can select all - Apple', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: node, @@ -529,8 +538,9 @@ void main() { expect(find.text('Item 13'), findsNothing); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('select to scroll by dragging selection handles forward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll by dragging selection handles forward', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -586,8 +596,9 @@ void main() { await gesture.up(); }); - testWidgets('select to scroll by dragging start selection handle stops scroll when released', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll by dragging start selection handle stops scroll when released', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -640,8 +651,9 @@ void main() { expect(controller.offset, previousOffset); }); - testWidgets('select to scroll by dragging end selection handle stops scroll when released', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select to scroll by dragging end selection handle stops scroll when released', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -693,9 +705,11 @@ void main() { expect(controller.offset, previousOffset); }); - testWidgets('keyboard selection should auto scroll - vertical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard selection should auto scroll - vertical', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: node, @@ -756,9 +770,11 @@ void main() { expect(controller.offset, 72.0); }, variant: TargetPlatformVariant.all()); - testWidgets('keyboard selection should auto scroll - vertical reversed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard selection should auto scroll - vertical reversed', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: node, @@ -820,9 +836,11 @@ void main() { expect(controller.offset, 72.0); }, variant: TargetPlatformVariant.all()); - testWidgets('keyboard selection should auto scroll - horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard selection should auto scroll - horizontal', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: node, @@ -866,9 +884,11 @@ void main() { expect(controller.offset, 352.0); }, variant: TargetPlatformVariant.all()); - testWidgets('keyboard selection should auto scroll - horizontal reversed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard selection should auto scroll - horizontal reversed', (WidgetTester tester) async { final FocusNode node = FocusNode(); + addTearDown(node.dispose); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: node, @@ -922,8 +942,9 @@ void main() { }, variant: TargetPlatformVariant.all()); group('Complex cases', () { - testWidgets('selection starts outside of the scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection starts outside of the scrollable', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -966,9 +987,11 @@ void main() { expect(controller.offset, 1000.0); }); - testWidgets('nested scrollables keep selection alive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('nested scrollables keep selection alive', (WidgetTester tester) async { final ScrollController outerController = ScrollController(); + addTearDown(outerController.dispose); final ScrollController innerController = ScrollController(); + addTearDown(innerController.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( selectionControls: materialTextSelectionControls, @@ -1030,9 +1053,11 @@ void main() { expect(innerParagraph24.selections[0], const TextSelection(baseOffset: 0, extentOffset: 2)); }); - testWidgets('can copy off screen selection - Apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can copy off screen selection - Apple', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: focusNode, @@ -1071,9 +1096,11 @@ void main() { expect(clipboardData['text'], 'em 0It'); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('can copy off screen selection - non-Apple', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can copy off screen selection - non-Apple', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget(MaterialApp( home: SelectionArea( focusNode: focusNode, diff --git a/packages/flutter/test/widgets/scrollable_semantics_test.dart b/packages/flutter/test/widgets/scrollable_semantics_test.dart index 5307fc7a6d73e..f9e2d1679e8df 100644 --- a/packages/flutter/test/widgets/scrollable_semantics_test.dart +++ b/packages/flutter/test/widgets/scrollable_semantics_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -16,7 +17,7 @@ void main() { debugResetSemanticsIdCounter(); }); - testWidgets('scrollable exposes the correct semantic actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrollable exposes the correct semantic actions', (WidgetTester tester) async { semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -42,7 +43,7 @@ void main() { semantics.dispose(); }); - testWidgets('showOnScreen works in scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showOnScreen works in scrollable', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation const double kItemHeight = 40.0; @@ -57,6 +58,7 @@ void main() { final ScrollController scrollController = ScrollController( initialScrollOffset: kItemHeight / 2, ); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( @@ -80,7 +82,7 @@ void main() { semantics.dispose(); }); - testWidgets('showOnScreen works with pinned app bar and sliver list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showOnScreen works with pinned app bar and sliver list', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation const double kItemHeight = 100.0; @@ -96,6 +98,7 @@ void main() { final ScrollController scrollController = ScrollController( initialScrollOffset: kItemHeight / 2, ); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -142,7 +145,7 @@ void main() { semantics.dispose(); }); - testWidgets('showOnScreen works with pinned app bar and individual slivers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showOnScreen works with pinned app bar and individual slivers', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation const double kItemHeight = 100.0; @@ -166,6 +169,7 @@ void main() { final ScrollController scrollController = ScrollController( initialScrollOffset: 2.5 * kItemHeight, ); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -210,7 +214,7 @@ void main() { semantics.dispose(); }); - testWidgets('correct scrollProgress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correct scrollProgress', (WidgetTester tester) async { semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( @@ -253,7 +257,7 @@ void main() { semantics.dispose(); }); - testWidgets('correct scrollProgress for unbound', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correct scrollProgress for unbound', (WidgetTester tester) async { semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( @@ -303,7 +307,7 @@ void main() { semantics.dispose(); }); - testWidgets('Semantics tree is populated mid-scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics tree is populated mid-scroll', (WidgetTester tester) async { semantics = SemanticsTester(tester); final List<Widget> children = List<Widget>.generate(80, (int i) => SizedBox( @@ -328,7 +332,7 @@ void main() { semantics.dispose(); }); - testWidgets('Can toggle semantics on, off, on without crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can toggle semantics on, off, on without crash', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -434,7 +438,7 @@ void main() { }); - testWidgets('brings item above leading edge to leading edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('brings item above leading edge to leading edge', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation await tester.pumpWidget(widgetUnderTest); @@ -450,7 +454,7 @@ void main() { semantics.dispose(); }); - testWidgets('brings item below trailing edge to trailing edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('brings item below trailing edge to trailing edge', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation await tester.pumpWidget(widgetUnderTest); @@ -466,7 +470,7 @@ void main() { semantics.dispose(); }); - testWidgets('does not change position of items already fully on-screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not change position of items already fully on-screen', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation await tester.pumpWidget(widgetUnderTest); @@ -536,10 +540,13 @@ void main() { ), ), ); + }); + tearDown(() { + scrollController.dispose(); }); - testWidgets('brings item above leading edge to leading edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('brings item above leading edge to leading edge', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation await tester.pumpWidget(widgetUnderTest); @@ -555,7 +562,7 @@ void main() { semantics.dispose(); }); - testWidgets('brings item below trailing edge to trailing edge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('brings item below trailing edge to trailing edge', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation await tester.pumpWidget(widgetUnderTest); @@ -571,7 +578,7 @@ void main() { semantics.dispose(); }); - testWidgets('does not change position of items already fully on-screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not change position of items already fully on-screen', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation await tester.pumpWidget(widgetUnderTest); @@ -589,7 +596,7 @@ void main() { }); - testWidgets('transform of inner node from useTwoPaneSemantics scrolls correctly with nested scrollables', (WidgetTester tester) async { + testWidgetsWithLeakTracking('transform of inner node from useTwoPaneSemantics scrolls correctly with nested scrollables', (WidgetTester tester) async { semantics = SemanticsTester(tester); // enables semantics tree generation // Context: https://github.com/flutter/flutter/issues/61631 diff --git a/packages/flutter/test/widgets/scrollable_semantics_traversal_order_test.dart b/packages/flutter/test/widgets/scrollable_semantics_traversal_order_test.dart index ff54d1084e71b..8e35b357982e0 100644 --- a/packages/flutter/test/widgets/scrollable_semantics_traversal_order_test.dart +++ b/packages/flutter/test/widgets/scrollable_semantics_traversal_order_test.dart @@ -5,13 +5,17 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Traversal Order of SliverList', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal Order of SliverList', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); + final ScrollController controller = ScrollController(initialScrollOffset: 3000.0); + addTearDown(controller.dispose); + final List<Widget> listChildren = List<Widget>.generate(30, (int i) { return SizedBox( height: 200.0, @@ -38,7 +42,7 @@ void main() { child: MediaQuery( data: const MediaQueryData(), child: CustomScrollView( - controller: ScrollController(initialScrollOffset: 3000.0), + controller: controller, semanticChildCount: 30, slivers: <Widget>[ SliverList( @@ -182,9 +186,12 @@ void main() { semantics.dispose(); }); - testWidgets('Traversal Order of SliverFixedExtentList', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal Order of SliverFixedExtentList', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); + final ScrollController controller = ScrollController(initialScrollOffset: 3000.0); + addTearDown(controller.dispose); + final List<Widget> listChildren = List<Widget>.generate(30, (int i) { return SizedBox( height: 200.0, @@ -211,7 +218,7 @@ void main() { child: MediaQuery( data: const MediaQueryData(), child: CustomScrollView( - controller: ScrollController(initialScrollOffset: 3000.0), + controller: controller, slivers: <Widget>[ SliverFixedExtentList( itemExtent: 200.0, @@ -321,9 +328,12 @@ void main() { semantics.dispose(); }); - testWidgets('Traversal Order of SliverGrid', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal Order of SliverGrid', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); + final ScrollController controller = ScrollController(initialScrollOffset: 1600.0); + addTearDown(controller.dispose); + final List<Widget> listChildren = List<Widget>.generate(30, (int i) { return SizedBox( height: 200.0, @@ -338,7 +348,7 @@ void main() { child: MediaQuery( data: const MediaQueryData(), child: CustomScrollView( - controller: ScrollController(initialScrollOffset: 1600.0), + controller: controller, slivers: <Widget>[ SliverGrid.count( crossAxisCount: 2, @@ -449,9 +459,12 @@ void main() { semantics.dispose(); }); - testWidgets('Traversal Order of List of individual slivers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal Order of List of individual slivers', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); + final ScrollController controller = ScrollController(initialScrollOffset: 3000.0); + addTearDown(controller.dispose); + final List<Widget> listChildren = List<Widget>.generate(30, (int i) { return SliverToBoxAdapter( child: SizedBox( @@ -480,7 +493,7 @@ void main() { child: MediaQuery( data: const MediaQueryData(), child: CustomScrollView( - controller: ScrollController(initialScrollOffset: 3000.0), + controller: controller, slivers: listChildren, ), ), @@ -585,9 +598,12 @@ void main() { semantics.dispose(); }); - testWidgets('Traversal Order of in a SingleChildScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal Order of in a SingleChildScrollView', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); + final ScrollController controller = ScrollController(initialScrollOffset: 3000.0); + addTearDown(controller.dispose); + final List<Widget> listChildren = List<Widget>.generate(30, (int i) { return SizedBox( height: 200.0, @@ -614,7 +630,7 @@ void main() { child: MediaQuery( data: const MediaQueryData(), child: SingleChildScrollView( - controller: ScrollController(initialScrollOffset: 3000.0), + controller: controller, child: Column( children: listChildren, ), @@ -671,7 +687,7 @@ void main() { semantics.dispose(); }); - testWidgets('Traversal Order with center child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal Order with center child', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Semantics( diff --git a/packages/flutter/test/widgets/scrollable_test.dart b/packages/flutter/test/widgets/scrollable_test.dart index c5d5b5fd014df..93efe9ff89853 100644 --- a/packages/flutter/test/widgets/scrollable_test.dart +++ b/packages/flutter/test/widgets/scrollable_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -109,7 +110,7 @@ void resetScrollOffset(WidgetTester tester) { } void main() { - testWidgets('Flings on different platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Flings on different platforms', (WidgetTester tester) async { await pumpTest(tester, TargetPlatform.android); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); expect(getScrollOffset(tester), dragOffset); @@ -145,7 +146,7 @@ void main() { expect(macOSResult, lessThan(iOSResult)); // iOS is slipperier than macOS }); - testWidgets('Holding scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Holding scroll', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); await tester.drag(find.byType(Scrollable), const Offset(0.0, 200.0), touchSlopY: 0.0); expect(getScrollOffset(tester), -200.0); @@ -164,7 +165,7 @@ void main() { expect(getScrollOffset(tester), 0.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Repeated flings builds momentum', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Repeated flings builds momentum', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); await tester.pump(); // trigger fling @@ -177,7 +178,7 @@ void main() { expect(getScrollVelocity(tester), greaterThan(1100.0)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Repeated flings do not build momentum on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Repeated flings do not build momentum on Android', (WidgetTester tester) async { await pumpTest(tester, TargetPlatform.android); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); await tester.pump(); // trigger fling @@ -190,7 +191,7 @@ void main() { expect(getScrollVelocity(tester), moreOrLessEquals(1000.0)); }); - testWidgets('A slower final fling does not apply carried momentum', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A slower final fling does not apply carried momentum', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); await tester.pump(); // trigger fling @@ -207,7 +208,7 @@ void main() { expect(getScrollVelocity(tester), lessThan(200.0)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('No iOS/macOS momentum build with flings in opposite directions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No iOS/macOS momentum build with flings in opposite directions', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); await tester.pump(); // trigger fling @@ -220,7 +221,7 @@ void main() { expect(getScrollVelocity(tester), -1000.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('No iOS/macOS momentum kept on hold gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No iOS/macOS momentum kept on hold gestures', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); await tester.pump(); // trigger fling @@ -233,7 +234,7 @@ void main() { expect(getScrollVelocity(tester), 0.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Drags creeping unaffected on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drags creeping unaffected on Android', (WidgetTester tester) async { await pumpTest(tester, TargetPlatform.android); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true)); await gesture.moveBy(const Offset(0.0, -0.5)); @@ -244,7 +245,7 @@ void main() { expect(getScrollOffset(tester), 1.5); }); - testWidgets('Drags creeping must break threshold on iOS/macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drags creeping must break threshold on iOS/macOS', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true)); await gesture.moveBy(const Offset(0.0, -0.5)); @@ -264,7 +265,7 @@ void main() { expect(getScrollOffset(tester), 0.5); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Big drag over threshold magnitude preserved on iOS/macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Big drag over threshold magnitude preserved on iOS/macOS', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true)); await gesture.moveBy(const Offset(0.0, -30.0)); @@ -272,7 +273,7 @@ void main() { expect(getScrollOffset(tester), 30.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Slow threshold breaks are attenuated on iOS/macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slow threshold breaks are attenuated on iOS/macOS', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true)); // This is a typical 'hesitant' iOS scroll start. @@ -283,7 +284,7 @@ void main() { expect(getScrollOffset(tester), moreOrLessEquals(11.16666666666666673)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Small continuing motion preserved on iOS/macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Small continuing motion preserved on iOS/macOS', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true)); await gesture.moveBy(const Offset(0.0, -30.0)); // Break threshold. @@ -296,7 +297,7 @@ void main() { expect(getScrollOffset(tester), 31.5); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Motion stop resets threshold on iOS/macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Motion stop resets threshold on iOS/macOS', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true)); await gesture.moveBy(const Offset(0.0, -30.0)); // Break threshold. @@ -319,7 +320,7 @@ void main() { expect(getScrollOffset(tester), 32.5); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Scroll pointer signals are handled on Fuchsia', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll pointer signals are handled on Fuchsia', (WidgetTester tester) async { await pumpTest(tester, TargetPlatform.fuchsia); final Offset scrollEventLocation = tester.getCenter(find.byType(Viewport)); final TestPointer testPointer = TestPointer(1, ui.PointerDeviceKind.mouse); @@ -332,7 +333,7 @@ void main() { expect(getScrollOffset(tester), 0.0); }); - testWidgets('Scroll pointer signals are handled when there is competition', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll pointer signals are handled when there is competition', (WidgetTester tester) async { // This is a regression test. When there are multiple scrollables listening // to the same event, for example when scrollables are nested, there used // to be exceptions at scrolling events. @@ -349,7 +350,7 @@ void main() { expect(getScrollOffset(tester), 0.0); }); - testWidgets('Scroll pointer signals are ignored when scrolling is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll pointer signals are ignored when scrolling is disabled', (WidgetTester tester) async { await pumpTest(tester, TargetPlatform.fuchsia, scrollable: false); final Offset scrollEventLocation = tester.getCenter(find.byType(Viewport)); final TestPointer testPointer = TestPointer(1, ui.PointerDeviceKind.mouse); @@ -359,10 +360,12 @@ void main() { expect(getScrollOffset(tester), 0.0); }); - testWidgets('Holding scroll and Scroll pointer signal will update ScrollDirection.forward / ScrollDirection.reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Holding scroll and Scroll pointer signal will update ScrollDirection.forward / ScrollDirection.reverse', (WidgetTester tester) async { ScrollDirection? lastUserScrollingDirection; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await pumpTest(tester, TargetPlatform.fuchsia, controller: controller); controller.addListener(() { @@ -393,7 +396,7 @@ void main() { }); - testWidgets('Scrolls in correct direction when scroll axis is reversed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolls in correct direction when scroll axis is reversed', (WidgetTester tester) async { await pumpTest(tester, TargetPlatform.fuchsia, reverse: true); final Offset scrollEventLocation = tester.getCenter(find.byType(Viewport)); @@ -405,7 +408,7 @@ void main() { expect(getScrollOffset(tester), 20.0); }); - testWidgets('Scrolls horizontally when shift is pressed by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolls horizontally when shift is pressed by default', (WidgetTester tester) async { await pumpTest( tester, debugDefaultTargetPlatformOverride, @@ -432,7 +435,7 @@ void main() { expect(getScrollOffset(tester), 20.0); }, variant: TargetPlatformVariant.all()); - testWidgets('Scroll axis is not flipped for trackpad', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll axis is not flipped for trackpad', (WidgetTester tester) async { await pumpTest( tester, debugDefaultTargetPlatformOverride, @@ -459,7 +462,7 @@ void main() { expect(getScrollOffset(tester), 0.0); }, variant: TargetPlatformVariant.all()); - testWidgets('Scrolls horizontally when custom key is pressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolls horizontally when custom key is pressed', (WidgetTester tester) async { await pumpTest( tester, debugDefaultTargetPlatformOverride, @@ -487,7 +490,7 @@ void main() { expect(getScrollOffset(tester), 20.0); }, variant: TargetPlatformVariant.all()); - testWidgets('Still scrolls horizontally when other keys are pressed at the same time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Still scrolls horizontally when other keys are pressed at the same time', (WidgetTester tester) async { await pumpTest( tester, debugDefaultTargetPlatformOverride, @@ -536,7 +539,7 @@ void main() { ); } - testWidgets('Hold does not disable user interaction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hold does not disable user interaction', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66816. await pumpTestWidget(tester, canDrag: true); final RenderIgnorePointer renderIgnorePointer = tester.renderObject<RenderIgnorePointer>( @@ -555,7 +558,7 @@ void main() { expect(renderIgnorePointer.ignoring, false); }); - testWidgets('Drag disables user interaction when recognized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Drag disables user interaction when recognized', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66816. await pumpTestWidget(tester, canDrag: true); final RenderIgnorePointer renderIgnorePointer = tester.renderObject<RenderIgnorePointer>( @@ -577,7 +580,7 @@ void main() { expect(renderIgnorePointer.ignoring, false); }); - testWidgets('Ballistic disables user interaction until it stops', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ballistic disables user interaction until it stops', (WidgetTester tester) async { await pumpTestWidget(tester, canDrag: true); final RenderIgnorePointer renderIgnorePointer = tester.renderObject<RenderIgnorePointer>( find.descendant(of: find.byType(CustomScrollView), matching: find.byType(IgnorePointer)), @@ -595,11 +598,13 @@ void main() { }); }); - testWidgets('Can recommendDeferredLoadingForContext - animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can recommendDeferredLoadingForContext - animation', (WidgetTester tester) async { final List<String> widgetTracker = <String>[]; int cheapWidgets = 0; int expensiveWidgets = 0; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( @@ -650,7 +655,7 @@ void main() { expect(widgetTracker.skip(17).skip(25).skip(70).every((String type) => type == 'expensive'), true); }); - testWidgets('Can recommendDeferredLoadingForContext - ballistics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can recommendDeferredLoadingForContext - ballistics', (WidgetTester tester) async { int cheapWidgets = 0; int expensiveWidgets = 0; await tester.pumpWidget(Directionality( @@ -687,7 +692,7 @@ void main() { expect(cheapWidgets, 21); }); - testWidgets('Can recommendDeferredLoadingForContext - override heuristic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can recommendDeferredLoadingForContext - override heuristic', (WidgetTester tester) async { int cheapWidgets = 0; int expensiveWidgets = 0; await tester.pumpWidget(Directionality( @@ -731,7 +736,7 @@ void main() { expect(physics.count, 44 + 17); }); - testWidgets('Can recommendDeferredLoadingForContext - override heuristic and always return true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can recommendDeferredLoadingForContext - override heuristic and always return true', (WidgetTester tester) async { int cheapWidgets = 0; int expensiveWidgets = 0; await tester.pumpWidget(Directionality( @@ -772,8 +777,9 @@ void main() { expect(cheapWidgets, 61); }); - testWidgets('ensureVisible does not move PageViews', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ensureVisible does not move PageViews', (WidgetTester tester) async { final PageController controller = PageController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -855,7 +861,7 @@ void main() { expect(targetMidLeftPage1, findsOneWidget); }); - testWidgets('ensureVisible does not move TabViews', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ensureVisible does not move TabViews', (WidgetTester tester) async { final TickerProvider vsync = TestTickerProvider(); final TabController controller = TabController( length: 3, @@ -942,10 +948,13 @@ void main() { expect(targetMidLeftPage1, findsOneWidget); }); - testWidgets('PointerScroll on nested NeverScrollable ListView goes to outer Scrollable.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PointerScroll on nested NeverScrollable ListView goes to outer Scrollable.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/70948 final ScrollController outerController = ScrollController(); + addTearDown(outerController.dispose); final ScrollController innerController = ScrollController(); + addTearDown(innerController.dispose); + await tester.pumpWidget(MaterialApp( theme: ThemeData(useMaterial3: false), home: Scaffold( @@ -999,8 +1008,10 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/71949 - testWidgets('Zero offset pointer scroll should not trigger an assertion.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Zero offset pointer scroll should not trigger an assertion.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + Widget build(double height) { return MaterialApp( home: Scaffold( @@ -1039,7 +1050,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Accepts drag with unknown device kind by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Accepts drag with unknown device kind by default', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/90912. await tester.pumpWidget( const MaterialApp( @@ -1068,7 +1079,7 @@ void main() { await tester.pump(); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.android })); - testWidgets('Does not scroll with mouse pointer drag when behavior is configured to ignore them', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not scroll with mouse pointer drag when behavior is configured to ignore them', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride, enableMouseDrag: false); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse); @@ -1088,7 +1099,7 @@ void main() { await tester.pump(); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.android })); - testWidgets("Support updating 'ScrollBehavior.dragDevices' at runtime", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Support updating 'ScrollBehavior.dragDevices' at runtime", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/111716 Widget buildFrame(Set<ui.PointerDeviceKind>? dragDevices) { return MaterialApp( @@ -1122,7 +1133,7 @@ void main() { expect(getScrollOffset(tester), 200.0); }); - testWidgets('Does scroll with mouse pointer drag when behavior is not configured to ignore them', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does scroll with mouse pointer drag when behavior is not configured to ignore them', (WidgetTester tester) async { await pumpTest(tester, debugDefaultTargetPlatformOverride); final TestGesture gesture = await tester.startGesture(tester.getCenter(find.byType(Scrollable), warnIfMissed: true), kind: ui.PointerDeviceKind.mouse); @@ -1142,7 +1153,7 @@ void main() { await tester.pump(); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.android })); - testWidgets('Updated content dimensions correctly reflect in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Updated content dimensions correctly reflect in semantics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/40419. final SemanticsHandle handle = tester.ensureSemantics(); final UniqueKey listView = UniqueKey(); @@ -1200,7 +1211,7 @@ void main() { handle.dispose(); }); - testWidgets('Two panel semantics is added to the sibling nodes of direct children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Two panel semantics is added to the sibling nodes of direct children', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); final UniqueKey key = UniqueKey(); await tester.pumpWidget(MaterialApp( @@ -1245,7 +1256,7 @@ void main() { handle.dispose(); }); - testWidgets('Scroll inertia cancel event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll inertia cancel event', (WidgetTester tester) async { await pumpTest(tester, null); await tester.fling(find.byType(Scrollable), const Offset(0.0, -dragOffset), 1000.0); expect(getScrollOffset(tester), dragOffset); @@ -1261,7 +1272,7 @@ void main() { expect(getScrollOffset(tester), closeTo(344.0642, 0.0001)); }); - testWidgets('Swapping viewports in a scrollable does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Swapping viewports in a scrollable does not crash', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final GlobalKey key = GlobalKey(); final GlobalKey key1 = GlobalKey(); @@ -1270,11 +1281,13 @@ void main() { key: key, viewportBuilder: (BuildContext context, ViewportOffset position) { if (withViewPort) { + final ViewportOffset offset = ViewportOffset.zero(); + addTearDown(() => offset.dispose()); return Viewport( slivers: <Widget>[ SliverToBoxAdapter(child: Semantics(key: key1, container: true, child: const Text('text1'))) ], - offset: ViewportOffset.zero(), + offset: offset, ); } return Semantics(key: key1, container: true, child: const Text('text1')); @@ -1306,7 +1319,7 @@ void main() { semantics.dispose(); }); - testWidgets('deltaToScrollOrigin getter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('deltaToScrollOrigin getter', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: CustomScrollView( @@ -1327,7 +1340,7 @@ void main() { expect(scrollable.deltaToScrollOrigin, const Offset(0.0, 200)); }); - testWidgets('resolvedPhysics getter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('resolvedPhysics getter', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData.light().copyWith( @@ -1357,7 +1370,7 @@ void main() { ); }); - testWidgets('dragDevices change updates widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dragDevices change updates widget', (WidgetTester tester) async { bool enable = false; await tester.pumpWidget( @@ -1410,7 +1423,7 @@ void main() { expect(getScrollOffset(tester), 200); }); - testWidgets('dragDevices change updates widget when oldWidget scrollBehavior is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dragDevices change updates widget when oldWidget scrollBehavior is null', (WidgetTester tester) async { ScrollBehavior? scrollBehavior; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/scrollbar_test.dart b/packages/flutter/test/widgets/scrollbar_test.dart index 1e2c831a44e09..c518dccc8f677 100644 --- a/packages/flutter/test/widgets/scrollbar_test.dart +++ b/packages/flutter/test/widgets/scrollbar_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/src/physics/utils.dart' show nearEqual; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Color _kScrollbarColor = Color(0xFF123456); const double _kThickness = 2.5; @@ -384,7 +385,7 @@ void main() { scrollMetrics: metrics, ); - testWidgets('down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('down', (WidgetTester tester) async { painter.update( metrics.copyWith( viewportDimension: size.height, @@ -414,7 +415,7 @@ void main() { expect(size.width - rect1.right, padding.right); }); - testWidgets('up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('up', (WidgetTester tester) async { painter.update( metrics.copyWith( viewportDimension: size.height, @@ -446,7 +447,7 @@ void main() { expect(size.width - rect1.right, padding.right); }); - testWidgets('left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('left', (WidgetTester tester) async { painter.update( metrics.copyWith( viewportDimension: size.width, @@ -478,7 +479,7 @@ void main() { expect(rect1.left, padding.left); }); - testWidgets('right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('right', (WidgetTester tester) async { painter.update( metrics.copyWith( viewportDimension: size.width, @@ -511,7 +512,7 @@ void main() { }); }); - testWidgets('thumb resizes gradually on overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('thumb resizes gradually on overscroll', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.fromLTRB(1, 2, 3, 4); const Size size = Size(60, 300); final double scrollExtent = size.height * 10; @@ -664,7 +665,7 @@ void main() { expect(trackRRect.trRadius, const Radius.circular(2.0)); }); - testWidgets('ScrollbarPainter asserts if no TextDirection has been provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarPainter asserts if no TextDirection has been provided', (WidgetTester tester) async { final ScrollbarPainter painter = ScrollbarPainter( color: _kScrollbarColor, fadeoutOpacityAnimation: kAlwaysCompleteAnimation, @@ -683,8 +684,9 @@ void main() { } }); - testWidgets('Tapping the track area pages the Scroll View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tapping the track area pages the Scroll View', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -745,7 +747,7 @@ void main() { ); }); - testWidgets('Scrollbar never goes away until finger lift', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar never goes away until finger lift', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -803,7 +805,7 @@ void main() { ); }); - testWidgets('Scrollbar does not fade away while hovering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar does not fade away while hovering', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -850,7 +852,7 @@ void main() { ); }); - testWidgets('Scrollbar will fade back in when hovering over known track area', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar will fade back in when hovering over known track area', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -911,7 +913,7 @@ void main() { ); }); - testWidgets('Scrollbar will show on hover without needing to scroll first for metrics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar will show on hover without needing to scroll first for metrics', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -946,8 +948,9 @@ void main() { ); }); - testWidgets('Scrollbar thumb can be dragged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb can be dragged', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1001,8 +1004,9 @@ void main() { ); }); - testWidgets('Scrollbar thumb cannot be dragged into overscroll if the physics do not allow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb cannot be dragged into overscroll if the physics do not allow', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1053,8 +1057,9 @@ void main() { ); }); - testWidgets('Scrollbar thumb cannot be dragged into overscroll if the platform does not allow it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb cannot be dragged into overscroll if the platform does not allow it', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1121,8 +1126,9 @@ void main() { TargetPlatform.fuchsia, })); - testWidgets('Scrollbar thumb can be dragged into overscroll if the platform allows it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb can be dragged into overscroll if the platform allows it', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1188,7 +1194,7 @@ void main() { })); // Regression test for https://github.com/flutter/flutter/issues/66444 - testWidgets("RawScrollbar doesn't show when scroll the inner scrollable widget", (WidgetTester tester) async { + testWidgetsWithLeakTracking("RawScrollbar doesn't show when scroll the inner scrollable widget", (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); final GlobalKey outerKey = GlobalKey(); @@ -1250,8 +1256,9 @@ void main() { ); }); - testWidgets('Scrollbar hit test area adjusts for PointerDeviceKind', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar hit test area adjusts for PointerDeviceKind', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1339,9 +1346,10 @@ void main() { ); }); - testWidgets('hit test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hit test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/99324 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); bool onTap = false; await tester.pumpWidget( Directionality( @@ -1388,12 +1396,14 @@ void main() { expect(onTap, true); }); - testWidgets('RawScrollbar.thumbVisibility asserts that a ScrollPosition is attached', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawScrollbar.thumbVisibility asserts that a ScrollPosition is attached', (WidgetTester tester) async { final FlutterExceptionHandler? handler = FlutterError.onError; FlutterErrorDetails? error; FlutterError.onError = (FlutterErrorDetails details) { error = details; }; + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -1402,7 +1412,7 @@ void main() { data: const MediaQueryData(), child: RawScrollbar( thumbVisibility: true, - controller: ScrollController(), + controller: controller, thumbColor: const Color(0x11111111), child: const SingleChildScrollView( child: SizedBox( @@ -1426,12 +1436,14 @@ void main() { FlutterError.onError = handler; }); - testWidgets('RawScrollbar.thumbVisibility asserts that a ScrollPosition is attached', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawScrollbar.thumbVisibility asserts that a ScrollPosition is attached', (WidgetTester tester) async { final FlutterExceptionHandler? handler = FlutterError.onError; FlutterErrorDetails? error; FlutterError.onError = (FlutterErrorDetails details) { error = details; }; + final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -1440,7 +1452,7 @@ void main() { data: const MediaQueryData(), child: RawScrollbar( thumbVisibility: true, - controller: ScrollController(), + controller: controller, thumbColor: const Color(0x11111111), child: const SingleChildScrollView( child: SizedBox( @@ -1464,9 +1476,11 @@ void main() { FlutterError.onError = handler; }); - testWidgets('Interactive scrollbars should have a valid scroll controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Interactive scrollbars should have a valid scroll controller', (WidgetTester tester) async { final ScrollController primaryScrollController = ScrollController(); + addTearDown(primaryScrollController.dispose); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( @@ -1505,9 +1519,10 @@ void main() { ); }); - testWidgets('Simultaneous dragging and pointer scrolling does not cause a crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Simultaneous dragging and pointer scrolling does not cause a crash', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/70105 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1679,8 +1694,9 @@ void main() { ); }); - testWidgets('Scrollbar thumb can be dragged in reverse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb can be dragged in reverse', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1735,7 +1751,7 @@ void main() { ); }); - testWidgets('ScrollbarPainter asserts if scrollbarOrientation is used with wrong axisDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollbarPainter asserts if scrollbarOrientation is used with wrong axisDirection', (WidgetTester tester) async { final ScrollbarPainter painter = ScrollbarPainter( color: _kScrollbarColor, fadeoutOpacityAnimation: kAlwaysCompleteAnimation, @@ -1753,8 +1769,9 @@ void main() { expect(() => painter.paint(testCanvas, size), throwsA(isA<AssertionError>())); }); - testWidgets('RawScrollbar mainAxisMargin property works properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawScrollbar mainAxisMargin property works properly', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1783,8 +1800,9 @@ void main() { ); }); - testWidgets('shape property of RawScrollbar can draw a BeveledRectangleBorder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shape property of RawScrollbar can draw a BeveledRectangleBorder', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1820,8 +1838,9 @@ void main() { ); }); - testWidgets('minThumbLength property of RawScrollbar is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('minThumbLength property of RawScrollbar is respected', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1846,8 +1865,9 @@ void main() { ..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 21.0))); // thumb }); - testWidgets('shape property of RawScrollbar can draw a CircleBorder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shape property of RawScrollbar can draw a CircleBorder', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1882,8 +1902,9 @@ void main() { ); }); - testWidgets('crossAxisMargin property of RawScrollbar is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('crossAxisMargin property of RawScrollbar is respected', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1907,8 +1928,9 @@ void main() { ..rect(rect: const Rect.fromLTRB(764.0, 0.0, 770.0, 360.0))); }); - testWidgets('shape property of RawScrollbar can draw a RoundedRectangleBorder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shape property of RawScrollbar can draw a RoundedRectangleBorder', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1941,8 +1963,9 @@ void main() { ); }); - testWidgets('minOverscrollLength property of RawScrollbar is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('minOverscrollLength property of RawScrollbar is respected', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1973,8 +1996,9 @@ void main() { ..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 8.0))); }); - testWidgets('not passing any shape or radius to RawScrollbar will draw the usual rectangular thumb', (WidgetTester tester) async { + testWidgetsWithLeakTracking('not passing any shape or radius to RawScrollbar will draw the usual rectangular thumb', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1999,8 +2023,9 @@ void main() { ); }); - testWidgets('The bar can show or hide when the viewport size change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The bar can show or hide when the viewport size change', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildFrame(double height) { return Directionality( textDirection: TextDirection.ltr, @@ -2030,10 +2055,11 @@ void main() { expect(find.byType(RawScrollbar), isNot(paints..rect())); // Hide the bar. }); - testWidgets('The bar can show or hide when the view size change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The bar can show or hide when the view size change', (WidgetTester tester) async { addTearDown(tester.view.reset); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildFrame() { return Directionality( textDirection: TextDirection.ltr, @@ -2072,10 +2098,12 @@ void main() { expect(find.byType(RawScrollbar), isNot(paints..rect())); // Not shown. }); - testWidgets('Scrollbar will not flip axes based on notification is there is a scroll controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar will not flip axes based on notification is there is a scroll controller', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/87697 final ScrollController verticalScrollController = ScrollController(); + addTearDown(verticalScrollController.dispose); final ScrollController horizontalScrollController = ScrollController(); + addTearDown(horizontalScrollController.dispose); Widget buildFrame() { return Directionality( textDirection: TextDirection.ltr, @@ -2133,8 +2161,9 @@ void main() { ); }); - testWidgets('notificationPredicate depth test.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('notificationPredicate depth test.', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final List<int> depths = <int>[]; Widget buildFrame() { return Directionality( @@ -2167,8 +2196,9 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/92262 - testWidgets('Do not crash when resize from scrollable to non-scrollable.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when resize from scrollable to non-scrollable.', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildFrame(double height) { return Directionality( textDirection: TextDirection.ltr, @@ -2203,10 +2233,11 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Scrollbar thumb can be dragged when the scrollable widget has a negative minScrollExtent - desktop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb can be dragged when the scrollable widget has a negative minScrollExtent - desktop', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/95840 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final UniqueKey uniqueKey = UniqueKey(); await tester.pumpWidget( Directionality( @@ -2285,10 +2316,11 @@ void main() { ); }, variant: TargetPlatformVariant.desktop()); - testWidgets('Scrollbar thumb can be dragged when the scrollable widget has a negative minScrollExtent - mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar thumb can be dragged when the scrollable widget has a negative minScrollExtent - mobile', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/95840 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final UniqueKey uniqueKey = UniqueKey(); await tester.pumpWidget( Directionality( @@ -2421,8 +2453,9 @@ void main() { expect(painter.shouldRepaint(createPainter(scrollbarOrientation: ScrollbarOrientation.bottom)), true); }); - testWidgets('Scrollbar track can be drawn', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar track can be drawn', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2464,8 +2497,9 @@ void main() { ); }); - testWidgets('RawScrollbar correctly assigns colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawScrollbar correctly assigns colors', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2510,8 +2544,9 @@ void main() { ); }); - testWidgets('trackRadius and radius properties of RawScrollbar can draw RoundedRectangularRect', (WidgetTester tester) async { + testWidgetsWithLeakTracking('trackRadius and radius properties of RawScrollbar can draw RoundedRectangularRect', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2549,8 +2584,9 @@ void main() { ); }); - testWidgets('Scrollbar asserts that a visible track has a visible thumb', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar asserts that a visible track has a visible thumb', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildApp() { return Directionality( textDirection: TextDirection.ltr, @@ -2573,9 +2609,10 @@ void main() { expect(() => tester.pumpWidget(buildApp()), throwsAssertionError); }); - testWidgets('Skip the ScrollPosition check if the bar was unmounted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Skip the ScrollPosition check if the bar was unmounted', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/103939 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildApp(bool buildBar) { return Directionality( textDirection: TextDirection.ltr, @@ -2611,9 +2648,10 @@ void main() { // Go without throw. }); - testWidgets('Track offset respects MediaQuery padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Track offset respects MediaQuery padding', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/106834 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2643,8 +2681,9 @@ void main() { ); // thumb }); - testWidgets('RawScrollbar.padding replaces MediaQueryData.padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawScrollbar.padding replaces MediaQueryData.padding', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2675,8 +2714,9 @@ void main() { ); // thumb }); - testWidgets('Scrollbar respect the NeverScrollableScrollPhysics physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollbar respect the NeverScrollableScrollPhysics physics', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2717,9 +2757,10 @@ void main() { expect(scrollController.offset, 0.0); }); - testWidgets('The thumb should follow the pointer when the scroll metrics changed during dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The thumb should follow the pointer when the scroll metrics changed during dragging', (WidgetTester tester) async { // Regressing test for https://github.com/flutter/flutter/issues/112072 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2787,9 +2828,10 @@ void main() { ); }); - testWidgets('The scrollable should not stutter when the scroll metrics shrink during dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The scrollable should not stutter when the scroll metrics shrink during dragging', (WidgetTester tester) async { // Regressing test for https://github.com/flutter/flutter/issues/121574 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -2851,9 +2893,10 @@ void main() { expect(scrollController.offset, greaterThan(lastPosition)); }); - testWidgets('The bar support mouse wheel event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The bar support mouse wheel event', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/109659 final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); Widget buildFrame() { return Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/selectable_region_context_menu_test.dart b/packages/flutter/test/widgets/selectable_region_context_menu_test.dart index 5ec1891246ce1..a7a43dab80158 100644 --- a/packages/flutter/test/widgets/selectable_region_context_menu_test.dart +++ b/packages/flutter/test/widgets/selectable_region_context_menu_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'package:web/web.dart' as web; extension on web.HTMLCollection { @@ -59,8 +60,9 @@ void main() { expect(foundStyle, isTrue); }); - testWidgets('right click can trigger select word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('right click can trigger select word', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final UniqueKey spy = UniqueKey(); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 1e25ba4e7ff41..e28fb1640370e 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'clipboard_utils.dart'; import 'keyboard_utils.dart'; @@ -37,12 +38,15 @@ void main() { }); group('SelectableRegion', () { - testWidgets('mouse selection single click sends correct events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse selection single click sends correct events', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -75,12 +79,15 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/102410. - testWidgets('mouse double click sends select-word event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse double click sends select-word event', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -103,8 +110,11 @@ void main() { expect(selectionEvent.globalPosition, const Offset(200.0, 200.0)); }); - testWidgets('Does not crash when using Navigator pages', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not crash when using Navigator pages', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/119776 + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: Navigator( @@ -114,7 +124,7 @@ void main() { children: <Widget>[ const Text('How are you?'), SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const SelectAllWidget(child: SizedBox(width: 100, height: 100)), ), @@ -134,15 +144,18 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('can draw handles when they are at rect boundaries', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can draw handles when they are at rect boundaries', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: Column( children: <Widget>[ const Text('How are you?'), SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectAllWidget(key: spy, child: const SizedBox(width: 100, height: 100)), ), @@ -164,12 +177,15 @@ void main() { expect(renderSpy.endHandle, isNotNull); }); - testWidgets('touch does not accept drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('touch does not accept drag', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -187,12 +203,15 @@ void main() { ); }); - testWidgets('does not merge semantics node of the children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not merge semantics node of the children', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: Scaffold( body: Center( @@ -262,12 +281,15 @@ void main() { semantics.dispose(); }); - testWidgets('mouse selection always cancels previous selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse selection always cancels previous selection', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -283,12 +305,15 @@ void main() { expect(renderSelectionSpy.events[0], isA<ClearSelectionEvent>()); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/102410. - testWidgets('touch long press sends select-word event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('touch long press sends select-word event', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -308,12 +333,15 @@ void main() { expect(selectionEvent.globalPosition, const Offset(200.0, 200.0)); }); - testWidgets('touch long press and drag sends correct events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('touch long press and drag sends correct events', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -341,14 +369,17 @@ void main() { expect(edgeEvent.granularity, TextGranularity.word); }); - testWidgets( + testWidgetsWithLeakTracking( 'touch long press cancel does not send ClearSelectionEvent', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -373,11 +404,14 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'scrolling after the selection does not send ClearSelectionEvent', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128765 final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SizedBox( @@ -386,7 +420,7 @@ void main() { child: SizedBox( height: 2000, child: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -417,12 +451,15 @@ void main() { }, ); - testWidgets('mouse long press does not send select-word event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse long press does not send select-word event', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: SelectionSpy(key: spy), ), @@ -443,7 +480,7 @@ void main() { }); }); - testWidgets('dragging handle or selecting word triggers haptic feedback on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dragging handle or selecting word triggers haptic feedback on Android', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { log.add(methodCall); @@ -452,11 +489,13 @@ void main() { addTearDown(() { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall); }); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Text('How are you?'), ), @@ -504,11 +543,14 @@ void main() { }, variant: TargetPlatformVariant.all()); group('SelectionArea integration', () { - testWidgets('mouse can select single text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select single text', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Center( child: Text('How are you'), @@ -548,11 +590,14 @@ void main() { await gesture.up(); }); - testWidgets('mouse can select word-by-word on double click drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select word-by-word on double click drag', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Center( child: Text('How are you'), @@ -617,11 +662,14 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. - testWidgets('mouse can select multiple widgets on double click drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets on double click drag', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -663,11 +711,14 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. - testWidgets('mouse can select multiple widgets on double click drag and return to origin word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets on double click drag and return to origin word', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -721,11 +772,14 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. - testWidgets('mouse can reverse selection across multiple widgets on double click drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can reverse selection across multiple widgets on double click drag', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -766,11 +820,14 @@ void main() { await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. - testWidgets('mouse can select multiple widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select multiple widgets', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -806,11 +863,14 @@ void main() { await gesture.up(); }); - testWidgets('mouse can work with disabled container', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can work with disabled container', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -847,11 +907,14 @@ void main() { await gesture.up(); }); - testWidgets('mouse can reverse selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can reverse selection', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -886,15 +949,18 @@ void main() { await gesture.up(); }); - testWidgets( + testWidgetsWithLeakTracking( 'single tap on the previous selection toggles the toolbar on iOS', (WidgetTester tester) async { Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; final UniqueKey toolbarKey = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -958,15 +1024,18 @@ void main() { skip: kIsWeb, // [intended] Web uses its native context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'right-click mouse can select word at position on Apple platforms', (WidgetTester tester) async { Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; final UniqueKey toolbarKey = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -1032,15 +1101,18 @@ void main() { skip: kIsWeb, // [intended] Web uses its native context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'right-click mouse at the same position as previous right-click toggles the context menu on macOS', (WidgetTester tester) async { Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; final UniqueKey toolbarKey = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -1130,15 +1202,18 @@ void main() { skip: kIsWeb, // [intended] Web uses its native context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'right-click mouse shows the context menu at position on Android, Fucshia, and Windows', (WidgetTester tester) async { Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; final UniqueKey toolbarKey = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -1238,15 +1313,18 @@ void main() { skip: kIsWeb, // [intended] Web uses its native context menu. ); - testWidgets( + testWidgetsWithLeakTracking( 'right-click mouse toggles the context menu on Linux', (WidgetTester tester) async { Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; final UniqueKey toolbarKey = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -1355,11 +1433,14 @@ void main() { skip: kIsWeb, // [intended] Web uses its native context menu. ); - testWidgets('can copy a selection made with the mouse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can copy a selection made with the mouse', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1388,12 +1469,16 @@ void main() { expect(clipboardData['text'], 'w are you?Good, and you?Fine, '); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.windows, TargetPlatform.linux, TargetPlatform.fuchsia })); - testWidgets( + testWidgetsWithLeakTracking( 'does not override TextField keyboard shortcuts if the TextField is focused - non apple', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'I am fine, thank you.'); + addTearDown(controller.dispose); final FocusNode selectableRegionFocus = FocusNode(); + addTearDown(selectableRegionFocus.dispose); final FocusNode textFieldFocus = FocusNode(); + addTearDown(textFieldFocus.dispose); + await tester.pumpWidget( MaterialApp( home: Material( @@ -1441,12 +1526,16 @@ void main() { skip: kIsWeb, // [intended] the web handles this on its own. ); - testWidgets( + testWidgetsWithLeakTracking( 'does not override TextField keyboard shortcuts if the TextField is focused - apple', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: 'I am fine, thank you.'); + addTearDown(controller.dispose); final FocusNode selectableRegionFocus = FocusNode(); + addTearDown(selectableRegionFocus.dispose); final FocusNode textFieldFocus = FocusNode(); + addTearDown(textFieldFocus.dispose); + await tester.pumpWidget( MaterialApp( home: Material( @@ -1494,8 +1583,10 @@ void main() { skip: kIsWeb, // [intended] the web handles this on its own. ); - testWidgets('select all', (WidgetTester tester) async { + testWidgetsWithLeakTracking('select all', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( @@ -1525,13 +1616,16 @@ void main() { expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.windows, TargetPlatform.linux, TargetPlatform.fuchsia })); - testWidgets( + testWidgetsWithLeakTracking( 'mouse selection can handle widget span', (WidgetTester tester) async { final UniqueKey outerText = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: Center( child: Text.rich( @@ -1564,14 +1658,17 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/61020 ); - testWidgets( + testWidgetsWithLeakTracking( 'can select word when a selectables rect is completely inside of another selectables rect', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/127076. final UniqueKey outerText = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: Scaffold( body: Center( @@ -1612,14 +1709,17 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/61020 ); - testWidgets( + testWidgetsWithLeakTracking( 'widget span is ignored if it does not contain text - non Apple', (WidgetTester tester) async { final UniqueKey outerText = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: Center( child: Text.rich( @@ -1652,14 +1752,17 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/61020 ); - testWidgets( + testWidgetsWithLeakTracking( 'widget span is ignored if it does not contain text - Apple', (WidgetTester tester) async { final UniqueKey outerText = UniqueKey(); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: Center( child: Text.rich( @@ -1692,11 +1795,14 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/61020 ); - testWidgets('mouse can select across bidi text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('mouse can select across bidi text', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1733,11 +1839,14 @@ void main() { await gesture.up(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61020 - testWidgets('long press and drag touch moves selection word by word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long press and drag touch moves selection word by word', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1764,15 +1873,18 @@ void main() { await gesture.up(); }); - testWidgets('can drag end handle when not covering entire screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can drag end handle when not covering entire screen', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104620. + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: Column( children: <Widget>[ const Text('How are you?'), SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Text('Good, and you?'), ), @@ -1801,15 +1913,18 @@ void main() { await gesture.up(); }); - testWidgets('can drag start handle when not covering entire screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can drag start handle when not covering entire screen', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/104620. + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: Column( children: <Widget>[ const Text('How are you?'), SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Text('Good, and you?'), ), @@ -1837,11 +1952,14 @@ void main() { await gesture.up(); }); - testWidgets('can drag start selection handle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can drag start selection handle', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1879,11 +1997,14 @@ void main() { await gesture.up(); }); - testWidgets('can drag start selection handle across end selection handle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can drag start selection handle across end selection handle', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1916,11 +2037,14 @@ void main() { await gesture.up(); }); - testWidgets('can drag end selection handle across start selection handle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can drag end selection handle across start selection handle', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1953,11 +2077,14 @@ void main() { await gesture.up(); }); - testWidgets('can select all from toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can select all from toolbar', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -1989,11 +2116,14 @@ void main() { expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); }, skip: kIsWeb); // [intended] Web uses its native context menu. - testWidgets('can copy from toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can copy from toolbar', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -2029,11 +2159,14 @@ void main() { expect(clipboardData['text'], 'thank'); }, skip: kIsWeb); // [intended] Web uses its native context menu. - testWidgets('can use keyboard to granularly extend selection - character', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use keyboard to granularly extend selection - character', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -2089,11 +2222,14 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('can use keyboard to granularly extend selection - word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use keyboard to granularly extend selection - word', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -2197,11 +2333,14 @@ void main() { expect(paragraph2.selections.length, 0); }, variant: TargetPlatformVariant.all()); - testWidgets('can use keyboard to granularly extend selection - line', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use keyboard to granularly extend selection - line', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -2286,11 +2425,14 @@ void main() { expect(paragraph1.selections[0].end, 2); }, variant: TargetPlatformVariant.all()); - testWidgets('can use keyboard to granularly extend selection - document', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use keyboard to granularly extend selection - document', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -2362,11 +2504,14 @@ void main() { expect(paragraph3.selections.length, 0); }, variant: TargetPlatformVariant.all()); - testWidgets('can use keyboard to directionally extend selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can use keyboard to directionally extend selection', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -2459,9 +2604,11 @@ void main() { late ValueNotifier<MagnifierInfo> magnifierInfo; final Widget fakeMagnifier = Container(key: UniqueKey()); - testWidgets('Can drag handles to show, unshow, and update magnifier', + testWidgetsWithLeakTracking('Can drag handles to show, unshow, and update magnifier', (WidgetTester tester) async { const String text = 'Monkeys and rabbits in my soup'; + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( @@ -2475,7 +2622,7 @@ void main() { return fakeMagnifier; }, ), - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Text(text), ), @@ -2525,13 +2672,15 @@ void main() { }); }); - testWidgets('toolbar is hidden on mobile when orientation changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toolbar is hidden on mobile when orientation changes', (WidgetTester tester) async { addTearDown(tester.view.reset); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Text('How are you?'), ), @@ -2567,12 +2716,15 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android }), ); - testWidgets('the selection behavior when clicking `Copy` item in mobile platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the selection behavior when clicking `Copy` item in mobile platforms', (WidgetTester tester) async { List<ContextMenuButtonItem> buttonItems = <ContextMenuButtonItem>[]; + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -2621,12 +2773,15 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('the handles do not disappear when clicking `Select all` item in mobile platforms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('the handles do not disappear when clicking `Select all` item in mobile platforms', (WidgetTester tester) async { List<ContextMenuButtonItem> buttonItems = <ContextMenuButtonItem>[]; + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -2674,12 +2829,15 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android, TargetPlatform.fuchsia }), ); - testWidgets('builds the correct button items', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builds the correct button items', (WidgetTester tester) async { Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionHandleControls, contextMenuBuilder: ( BuildContext context, @@ -2713,14 +2871,16 @@ void main() { skip: kIsWeb, // [intended] ); - testWidgets('onSelectionChange is called when the selection changes through gestures', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes through gestures', (WidgetTester tester) async { SelectedContent? content; + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: SelectableRegion( onSelectionChanged: (SelectedContent? selectedContent) => content = selectedContent, - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Center( child: Text('How are you'), @@ -2845,14 +3005,16 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('onSelectionChange is called when the selection changes through keyboard actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChange is called when the selection changes through keyboard actions', (WidgetTester tester) async { SelectedContent? content; + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: SelectableRegion( onSelectionChanged: (SelectedContent? selectedContent) => content = selectedContent, - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Column( children: <Widget>[ @@ -3003,12 +3165,15 @@ void main() { TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.contextMenu, null); }); - testWidgets('web can show flutter context menu when the browser context menu is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('web can show flutter context menu when the browser context menu is disabled', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( onSelectionChanged: (SelectedContent? selectedContent) {}, - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: const Center( child: Text('How are you'), @@ -3034,14 +3199,17 @@ void main() { ); }); - testWidgets('Multiple selectables on a single line should be in screen order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiple selectables on a single line should be in screen order', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/127942. final UniqueKey outerText = UniqueKey(); const TextStyle textStyle = TextStyle(fontSize: 10); + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + await tester.pumpWidget( MaterialApp( home: SelectableRegion( - focusNode: FocusNode(), + focusNode: focusNode, selectionControls: materialTextSelectionControls, child: Scaffold( body: Center( From 7212a079d9325614544be56903d44a49aad286ab Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 10:38:24 -0400 Subject: [PATCH 1359/1547] Roll Flutter Engine from 67d4aaef3c7b to 6535421b30d3 (1 revision) (#135139) https://github.com/flutter/engine/compare/67d4aaef3c7b...6535421b30d3 2023-09-20 skia-flutter-autoroll@skia.org Roll Dart SDK from b3fd178ce59f to ed05ca364d5e (1 revision) (flutter/engine#46092) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 75ef6f0696eb0..f03dbb8627b9a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -67d4aaef3c7b82c5bee549f3cd0fbf12259762e2 +6535421b30d3dc758f01b899656fc2b325f9580d From a1f8c99f959f59074d96de675aa4e959ba4be940 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 11:29:06 -0400 Subject: [PATCH 1360/1547] Roll Flutter Engine from 6535421b30d3 to 5f82fc2f6f24 (2 revisions) (#135142) https://github.com/flutter/engine/compare/6535421b30d3...5f82fc2f6f24 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from d7f2d1083979 to fd317812bd27 (2 revisions) (flutter/engine#46094) 2023-09-20 skia-flutter-autoroll@skia.org Roll Dart SDK from b3fd178ce59f to ed05ca364d5e (1 revision) (flutter/engine#46093) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index f03dbb8627b9a..b72f57bac4cb9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6535421b30d3dc758f01b899656fc2b325f9580d +5f82fc2f6f241f0beef0baf1d5336192b5c22a9a From 8cda3bea23a5e29236f048ced85416f19945c0cb Mon Sep 17 00:00:00 2001 From: Greg Spencer <gspencergoog@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:44:49 -0700 Subject: [PATCH 1361/1547] Remove 'must not be null' comments from various libraries. (#134984) ## Description This removes all of the comments that are of the form "so-and-so (must not be null|can ?not be null|must be non-null)" from the cases where those values are defines as non-nullable values. This PR removes them from the animation, cupertino, foundation, gestures, semantics, and services libraries. Each of them only had a few, so I lumped them together. This was done by hand, since it really didn't lend itself to scripting, so it needs to be more than just spot-checked, I think. I was careful to leave any comment that referred to parameters that were nullable, but I may have missed some. In addition to being no longer relevant after null safety has been made the default, these comments were largely fragile, in that it was easy for them to get out of date, and not be accurate anymore anyhow. This did create a number of constructor comments which basically say "Creates a [Foo].", but I don't really know how to avoid that in a large scale change, since there's not much you can really say in a lot of cases. I think we might consider some leniency for constructors to the "Comment must be meaningful" style guidance (which we de facto have already, since there are a bunch of these). ## Related PRs - https://github.com/flutter/flutter/pull/134991 - https://github.com/flutter/flutter/pull/134992 - https://github.com/flutter/flutter/pull/134993 - https://github.com/flutter/flutter/pull/134994 ## Tests - Documentation only change. --- .../src/animation/animation_controller.dart | 12 +-- .../flutter/lib/src/animation/animations.dart | 17 ++-- .../flutter/lib/src/animation/curves.dart | 17 +--- packages/flutter/lib/src/animation/tween.dart | 2 - .../lib/src/animation/tween_sequence.dart | 2 +- .../lib/src/cupertino/activity_indicator.dart | 4 +- packages/flutter/lib/src/cupertino/app.dart | 2 - .../lib/src/cupertino/bottom_tab_bar.dart | 11 +-- .../flutter/lib/src/cupertino/button.dart | 2 +- .../flutter/lib/src/cupertino/checkbox.dart | 2 - .../flutter/lib/src/cupertino/colors.dart | 12 +-- .../lib/src/cupertino/context_menu.dart | 10 +-- .../lib/src/cupertino/date_picker.dart | 29 +++--- ...desktop_text_selection_toolbar_button.dart | 4 - .../flutter/lib/src/cupertino/dialog.dart | 10 +-- .../lib/src/cupertino/form_section.dart | 2 +- .../flutter/lib/src/cupertino/nav_bar.dart | 17 ++-- .../lib/src/cupertino/page_scaffold.dart | 2 +- .../flutter/lib/src/cupertino/picker.dart | 18 ++-- .../flutter/lib/src/cupertino/refresh.dart | 12 +-- packages/flutter/lib/src/cupertino/route.dart | 2 - .../lib/src/cupertino/search_field.dart | 34 +++---- .../lib/src/cupertino/segmented_control.dart | 8 +- .../flutter/lib/src/cupertino/slider.dart | 2 - .../cupertino/sliding_segmented_control.dart | 10 +-- .../flutter/lib/src/cupertino/switch.dart | 5 +- .../lib/src/cupertino/tab_scaffold.dart | 16 ++-- .../flutter/lib/src/cupertino/text_field.dart | 17 ++-- .../text_selection_toolbar_button.dart | 4 - .../flutter/lib/src/cupertino/text_theme.dart | 2 +- packages/flutter/lib/src/cupertino/theme.dart | 2 - .../lib/src/cupertino/thumb_painter.dart | 2 - .../lib/src/foundation/assertions.dart | 6 +- .../lib/src/foundation/basic_types.dart | 7 +- .../lib/src/foundation/diagnostics.dart | 35 +------- .../lib/src/foundation/stack_frame.dart | 4 +- .../lib/src/gestures/drag_details.dart | 10 --- packages/flutter/lib/src/gestures/events.dart | 30 ------- .../flutter/lib/src/gestures/force_press.dart | 2 - .../flutter/lib/src/gestures/long_press.dart | 8 -- .../flutter/lib/src/gestures/lsq_solver.dart | 2 - .../flutter/lib/src/gestures/monodrag.dart | 2 - .../flutter/lib/src/gestures/multidrag.dart | 2 - packages/flutter/lib/src/gestures/scale.dart | 9 +- packages/flutter/lib/src/gestures/tap.dart | 4 +- .../lib/src/gestures/tap_and_drag.dart | 18 ---- .../lib/src/gestures/velocity_tracker.dart | 6 +- .../lib/src/rendering/table_border.dart | 3 + .../flutter/lib/src/semantics/semantics.dart | 8 +- .../lib/src/semantics/semantics_event.dart | 4 - .../flutter/lib/src/services/autofill.dart | 6 +- .../lib/src/services/mouse_cursor.dart | 4 +- .../lib/src/services/mouse_tracking.dart | 2 - .../lib/src/services/platform_channel.dart | 11 +-- .../lib/src/services/platform_views.dart | 88 ++++++++++--------- .../src/services/raw_keyboard_android.dart | 3 - .../src/services/raw_keyboard_fuchsia.dart | 2 - .../lib/src/services/raw_keyboard_ios.dart | 3 - .../lib/src/services/raw_keyboard_linux.dart | 3 - .../lib/src/services/raw_keyboard_macos.dart | 3 - .../lib/src/services/raw_keyboard_web.dart | 2 - .../src/services/raw_keyboard_windows.dart | 3 - .../flutter/lib/src/services/restoration.dart | 6 -- .../lib/src/services/text_editing.dart | 4 - .../lib/src/services/text_editing_delta.dart | 12 --- .../lib/src/services/text_formatter.dart | 9 -- .../flutter/lib/src/services/text_input.dart | 15 ++-- .../flutter_driver/lib/src/common/wait.dart | 2 - .../flutter_goldens/lib/flutter_goldens.dart | 6 +- packages/flutter_test/lib/src/goldens.dart | 2 - 70 files changed, 176 insertions(+), 461 deletions(-) diff --git a/packages/flutter/lib/src/animation/animation_controller.dart b/packages/flutter/lib/src/animation/animation_controller.dart index 24df24fb8cbff..2a5f7e9850fb8 100644 --- a/packages/flutter/lib/src/animation/animation_controller.dart +++ b/packages/flutter/lib/src/animation/animation_controller.dart @@ -230,9 +230,9 @@ class AnimationController extends Animation<double> /// value at which this animation is deemed to be completed. It cannot be /// null. /// - /// * `vsync` is the [TickerProvider] for the current context. It can be - /// changed by calling [resync]. It is required and must not be null. See - /// [TickerProvider] for advice on obtaining a ticker provider. + /// * `vsync` is the required [TickerProvider] for the current context. It can + /// be changed by calling [resync]. See [TickerProvider] for advice on + /// obtaining a ticker provider. AnimationController({ double? value, this.duration, @@ -258,9 +258,9 @@ class AnimationController extends Animation<double> /// * [debugLabel] is a string to help identify this animation during /// debugging (used by [toString]). /// - /// * `vsync` is the [TickerProvider] for the current context. It can be - /// changed by calling [resync]. It is required and must not be null. See - /// [TickerProvider] for advice on obtaining a ticker provider. + /// * `vsync` is the required [TickerProvider] for the current context. It can + /// be changed by calling [resync]. See [TickerProvider] for advice on + /// obtaining a ticker provider. /// /// This constructor is most useful for animations that will be driven using a /// physics simulation, especially when the physics simulation has no diff --git a/packages/flutter/lib/src/animation/animations.dart b/packages/flutter/lib/src/animation/animations.dart index de2f7c04fb7de..4fb2d6732fd1d 100644 --- a/packages/flutter/lib/src/animation/animations.dart +++ b/packages/flutter/lib/src/animation/animations.dart @@ -269,8 +269,6 @@ class ReverseAnimation extends Animation<double> with AnimationLazyListenerMixin, AnimationLocalStatusListenersMixin { /// Creates a reverse animation. - /// - /// The parent argument must not be null. ReverseAnimation(this.parent); /// The animation whose value and direction this animation is reversing. @@ -376,8 +374,6 @@ class ReverseAnimation extends Animation<double> /// [Curve]. class CurvedAnimation extends Animation<double> with AnimationWithParentMixin<double> { /// Creates a curved animation. - /// - /// The parent and curve arguments must not be null. CurvedAnimation({ required this.parent, required this.curve, @@ -631,8 +627,9 @@ class TrainHoppingAnimation extends Animation<double> /// animation otherwise. abstract class CompoundAnimation<T> extends Animation<T> with AnimationLazyListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin { - /// Creates a CompoundAnimation. Both arguments must be non-null. Either can - /// be a CompoundAnimation itself to combine multiple animations. + /// Creates a [CompoundAnimation]. + /// + /// Either argument can be a [CompoundAnimation] itself to combine multiple animations. CompoundAnimation({ required this.first, required this.next, @@ -720,8 +717,8 @@ class AnimationMean extends CompoundAnimation<double> { class AnimationMax<T extends num> extends CompoundAnimation<T> { /// Creates an [AnimationMax]. /// - /// Both arguments must be non-null. Either can be an [AnimationMax] itself - /// to combine multiple animations. + /// Either argument can be an [AnimationMax] itself to combine multiple + /// animations. AnimationMax(Animation<T> first, Animation<T> next) : super(first: first, next: next); @override @@ -735,8 +732,8 @@ class AnimationMax<T extends num> extends CompoundAnimation<T> { class AnimationMin<T extends num> extends CompoundAnimation<T> { /// Creates an [AnimationMin]. /// - /// Both arguments must be non-null. Either can be an [AnimationMin] itself - /// to combine multiple animations. + /// Either argument can be an [AnimationMin] itself to combine multiple + /// animations. AnimationMin(Animation<T> first, Animation<T> next) : super(first: first, next: next); @override diff --git a/packages/flutter/lib/src/animation/curves.dart b/packages/flutter/lib/src/animation/curves.dart index 0c54a653f0361..aaa09951ab27a 100644 --- a/packages/flutter/lib/src/animation/curves.dart +++ b/packages/flutter/lib/src/animation/curves.dart @@ -127,8 +127,6 @@ class _Linear extends Curve { /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_sawtooth.mp4} class SawTooth extends Curve { /// Creates a sawtooth curve. - /// - /// The [count] argument must not be null. const SawTooth(this.count); /// The number of repetitions of the sawtooth pattern in the unit interval. @@ -157,8 +155,6 @@ class SawTooth extends Curve { /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_interval.mp4} class Interval extends Curve { /// Creates an interval curve. - /// - /// The arguments must not be null. const Interval(this.begin, this.end, { this.curve = Curves.linear }); /// The largest value for which this interval is 0.0. @@ -202,8 +198,6 @@ class Interval extends Curve { /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_threshold.mp4} class Threshold extends Curve { /// Creates a threshold curve. - /// - /// The [threshold] argument must not be null. const Threshold(this.threshold); /// The value before which the curve is 0.0 and after which the curve is 1.0. @@ -302,8 +296,6 @@ class Cubic extends Curve { /// /// Rather than creating a new instance, consider using one of the common /// cubic curves in [Curves]. - /// - /// The [a] (x1), [b] (y1), [c] (x2) and [d] (y2) arguments must not be null. const Cubic(this.a, this.b, this.c, this.d); /// The x coordinate of the first control point. @@ -599,8 +591,6 @@ abstract class Curve2D extends ParametricCurve<Offset> { /// * [Curve2D], a parametric curve that maps a double parameter to a 2D location. class Curve2DSample { /// Creates an object that holds a sample; used with [Curve2D] subclasses. - /// - /// All arguments must not be null. const Curve2DSample(this.t, this.value); /// The parametric location of this sample point along the curve. @@ -659,8 +649,7 @@ class CatmullRomSpline extends Curve2D { /// control point. The default is chosen so that the slope of the line at the /// ends matches that of the first or last line segment in the control points. /// - /// The `tension` and `controlPoints` arguments must not be null, and the - /// `controlPoints` list must contain at least four control points to + /// The `controlPoints` list must contain at least four control points to /// interpolate. /// /// The internal curve data structures are lazily computed the first time @@ -860,8 +849,6 @@ class CatmullRomCurve extends Curve { /// [transform] is called. If you would rather pre-compute the curve, use /// [CatmullRomCurve.precompute] instead. /// - /// All of the arguments must not be null. - /// /// See also: /// /// * This [paper on using Catmull-Rom splines](http://faculty.cs.tamu.edu/schaefer/research/cr_cad.pdf). @@ -1144,8 +1131,6 @@ class CatmullRomCurve extends Curve { /// * [CurvedAnimation], which can take a separate curve and reverse curve. class FlippedCurve extends Curve { /// Creates a flipped curve. - /// - /// The [curve] argument must not be null. const FlippedCurve(this.curve); /// The curve that is being flipped. diff --git a/packages/flutter/lib/src/animation/tween.dart b/packages/flutter/lib/src/animation/tween.dart index 1f0bb5d387a22..14cb5f0d77bda 100644 --- a/packages/flutter/lib/src/animation/tween.dart +++ b/packages/flutter/lib/src/animation/tween.dart @@ -547,8 +547,6 @@ class ConstantTween<T> extends Tween<T> { /// [AnimationController]. class CurveTween extends Animatable<double> { /// Creates a curve tween. - /// - /// The [curve] argument must not be null. CurveTween({ required this.curve }); /// The curve to use when transforming the value of the animation. diff --git a/packages/flutter/lib/src/animation/tween_sequence.dart b/packages/flutter/lib/src/animation/tween_sequence.dart index a8e3208a5953a..8600ea836dbcb 100644 --- a/packages/flutter/lib/src/animation/tween_sequence.dart +++ b/packages/flutter/lib/src/animation/tween_sequence.dart @@ -122,7 +122,7 @@ class FlippedTweenSequence extends TweenSequence<double> { class TweenSequenceItem<T> { /// Construct a TweenSequenceItem. /// - /// The [tween] must not be null and [weight] must be greater than 0.0. + /// The [weight] must be greater than 0.0. const TweenSequenceItem({ required this.tween, required this.weight, diff --git a/packages/flutter/lib/src/cupertino/activity_indicator.dart b/packages/flutter/lib/src/cupertino/activity_indicator.dart index bd5bacf6b76e1..b1c2e5ce62d45 100644 --- a/packages/flutter/lib/src/cupertino/activity_indicator.dart +++ b/packages/flutter/lib/src/cupertino/activity_indicator.dart @@ -67,7 +67,7 @@ class CupertinoActivityIndicator extends StatefulWidget { /// Radius of the spinner widget. /// - /// Defaults to 10px. Must be positive and cannot be null. + /// Defaults to 10 pixels. Must be positive. final double radius; /// Determines the percentage of spinner ticks that will be shown. Typical usage would @@ -75,7 +75,7 @@ class CupertinoActivityIndicator extends StatefulWidget { /// during pull-to-refresh when the drag-down action shows one tick at a time as /// the user continues to drag down. /// - /// Defaults to 1.0. Must be between 0.0 and 1.0 inclusive, and cannot be null. + /// Defaults to one. Must be between zero and one, inclusive. final double progress; @override diff --git a/packages/flutter/lib/src/cupertino/app.dart b/packages/flutter/lib/src/cupertino/app.dart index b4b0b818fa66f..f68ffc92bcd09 100644 --- a/packages/flutter/lib/src/cupertino/app.dart +++ b/packages/flutter/lib/src/cupertino/app.dart @@ -145,8 +145,6 @@ class CupertinoApp extends StatefulWidget { /// unsupported route. /// /// This class creates an instance of [WidgetsApp]. - /// - /// The boolean arguments, [routes], and [navigatorObservers], must not be null. const CupertinoApp({ super.key, this.navigatorKey, diff --git a/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart b/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart index 6d920abff92bb..6dd1bf3786404 100644 --- a/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart +++ b/packages/flutter/lib/src/cupertino/bottom_tab_bar.dart @@ -79,8 +79,6 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { assert(height >= 0.0); /// The interactive items laid out within the bottom navigation bar. - /// - /// Must not be null. final List<BottomNavigationBarItem> items; /// The callback that is called when a item is tapped. @@ -92,8 +90,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { /// The index into [items] of the current active item. /// - /// Must not be null and must inclusively be between 0 and the number of tabs - /// minus 1. + /// Must be between 0 and the number of tabs minus 1, inclusive. final int currentIndex; /// The background color of the tab bar. If it contains transparency, the @@ -113,7 +110,7 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { /// in the unselected state. /// /// Defaults to a [CupertinoDynamicColor] that matches the disabled foreground - /// color of the native `UITabBar` component. Cannot be null. + /// color of the native `UITabBar` component. final Color inactiveColor; /// The size of all of the [BottomNavigationBarItem] icons. @@ -121,13 +118,11 @@ class CupertinoTabBar extends StatelessWidget implements PreferredSizeWidget { /// This value is used to configure the [IconTheme] for the navigation bar. /// When a [BottomNavigationBarItem.icon] widget is not an [Icon] the widget /// should configure itself to match the icon theme's size and color. - /// - /// Must not be null. final double iconSize; /// The height of the [CupertinoTabBar]. /// - /// Defaults to 50.0. Must not be null. + /// Defaults to 50. final double height; /// The border of the [CupertinoTabBar]. diff --git a/packages/flutter/lib/src/cupertino/button.dart b/packages/flutter/lib/src/cupertino/button.dart index b5f71d54b9b81..73c90d01f1c25 100644 --- a/packages/flutter/lib/src/cupertino/button.dart +++ b/packages/flutter/lib/src/cupertino/button.dart @@ -95,7 +95,7 @@ class CupertinoButton extends StatefulWidget { /// Ignored if the [CupertinoButton] doesn't also have a [color]. /// /// Defaults to [CupertinoColors.quaternarySystemFill] when [color] is - /// specified. Must not be null. + /// specified. final Color disabledColor; /// The callback that is called when the button is tapped or otherwise activated. diff --git a/packages/flutter/lib/src/cupertino/checkbox.dart b/packages/flutter/lib/src/cupertino/checkbox.dart index 9d37c7af9c03c..6df97362b2dfc 100644 --- a/packages/flutter/lib/src/cupertino/checkbox.dart +++ b/packages/flutter/lib/src/cupertino/checkbox.dart @@ -57,8 +57,6 @@ class CupertinoCheckbox extends StatefulWidget { /// can only be null if [tristate] is true. /// * [onChanged], which is called when the value of the checkbox should /// change. It can be set to null to disable the checkbox. - /// - /// The values of [tristate] and [autofocus] must not be null. const CupertinoCheckbox({ super.key, required this.value, diff --git a/packages/flutter/lib/src/cupertino/colors.dart b/packages/flutter/lib/src/cupertino/colors.dart index 8d57221c64376..7db9b9a489977 100644 --- a/packages/flutter/lib/src/cupertino/colors.dart +++ b/packages/flutter/lib/src/cupertino/colors.dart @@ -738,8 +738,6 @@ abstract final class CupertinoColors { class CupertinoDynamicColor extends Color with Diagnosticable { /// Creates an adaptive [Color] that changes its effective color based on the /// [BuildContext] given. The default effective color is [color]. - /// - /// All the colors must not be null. const CupertinoDynamicColor({ String? debugLabel, required Color color, @@ -768,8 +766,6 @@ class CupertinoDynamicColor extends Color with Diagnosticable { /// given [BuildContext]'s brightness (from [MediaQueryData.platformBrightness] /// or [CupertinoThemeData.brightness]) and accessibility contrast setting /// ([MediaQueryData.highContrast]). The default effective color is [color]. - /// - /// All the colors must not be null. const CupertinoDynamicColor.withBrightnessAndContrast({ String? debugLabel, required Color color, @@ -791,8 +787,6 @@ class CupertinoDynamicColor extends Color with Diagnosticable { /// Creates an adaptive [Color] that changes its effective color based on the given /// [BuildContext]'s brightness (from [MediaQueryData.platformBrightness] or /// [CupertinoThemeData.brightness]). The default effective color is [color]. - /// - /// All the colors must not be null. const CupertinoDynamicColor.withBrightness({ String? debugLabel, required Color color, @@ -828,8 +822,8 @@ class CupertinoDynamicColor extends Color with Diagnosticable { /// The current effective color. /// - /// Must not be null. Defaults to [color] if this [CupertinoDynamicColor] has - /// never been resolved. + /// Defaults to [color] if this [CupertinoDynamicColor] has never been + /// resolved. final Color _effectiveColor; @override @@ -1158,8 +1152,6 @@ class CupertinoDynamicColor extends Color with Diagnosticable { } /// Creates a diagnostics property for [CupertinoDynamicColor]. -/// -/// The [showName], [style], and [level] arguments must not be null. DiagnosticsProperty<Color> createCupertinoColorProperty( String name, Color? value, { diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index 113e923ab308f..385bae14fbb32 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -132,9 +132,7 @@ enum _ContextMenuLocation { class CupertinoContextMenu extends StatefulWidget { /// Create a context menu. /// - /// [actions] is required and cannot be null or empty. - /// - /// [child] is required and cannot be null. + /// The [actions] parameter cannot be empty. CupertinoContextMenu({ super.key, required this.actions, @@ -153,9 +151,7 @@ class CupertinoContextMenu extends StatefulWidget { /// Use instead of the default constructor when it is needed to have a more /// custom animation. /// - /// [actions] is required and cannot be null or empty. - /// - /// [builder] is required. + /// The [actions] parameter cannot be empty. CupertinoContextMenu.builder({ super.key, required this.actions, @@ -389,7 +385,7 @@ class CupertinoContextMenu extends StatefulWidget { /// /// These actions are typically [CupertinoContextMenuAction]s. /// - /// This parameter cannot be null or empty. + /// This parameter must not be empty. final List<Widget> actions; /// If true, clicking on the [CupertinoContextMenuAction]s will diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index afc938624e9ad..dc15ea3e35d2b 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -237,17 +237,16 @@ class CupertinoDatePicker extends StatefulWidget { /// to [CupertinoDatePickerMode.dateAndTime]. /// /// [onDateTimeChanged] is the callback called when the selected date or time - /// changes and must not be null. When in [CupertinoDatePickerMode.time] mode, - /// the year, month and day will be the same as [initialDateTime]. When in + /// changes. When in [CupertinoDatePickerMode.time] mode, the year, month and + /// day will be the same as [initialDateTime]. When in /// [CupertinoDatePickerMode.date] mode, this callback will always report the /// start time of the currently selected day. When in /// [CupertinoDatePickerMode.monthYear] mode, the day and time will be the /// start time of the first day of the month. /// /// [initialDateTime] is the initial date time of the picker. Defaults to the - /// present date and time and must not be null. The present must conform to - /// the intervals set in [minimumDate], [maximumDate], [minimumYear], and - /// [maximumYear]. + /// present date and time. The present must conform to the intervals set in + /// [minimumDate], [maximumDate], [minimumYear], and [maximumYear]. /// /// [minimumDate] is the minimum selectable [DateTime] of the picker. When set /// to null, the picker does not limit the minimum [DateTime] the user can pick. @@ -262,7 +261,7 @@ class CupertinoDatePicker extends StatefulWidget { /// maximum time the user can pick if it's set to a date later than that. /// /// [minimumYear] is the minimum year that the picker can be scrolled to in - /// [CupertinoDatePickerMode.date] mode. Defaults to 1 and must not be null. + /// [CupertinoDatePickerMode.date] mode. Defaults to 1. /// /// [maximumYear] is the maximum year that the picker can be scrolled to in /// [CupertinoDatePickerMode.date] mode. Null if there's no limit. @@ -331,14 +330,14 @@ class CupertinoDatePicker extends StatefulWidget { ); } - /// The mode of the date picker as one of [CupertinoDatePickerMode]. - /// Defaults to [CupertinoDatePickerMode.dateAndTime]. Cannot be null and - /// value cannot change after initial build. + /// The mode of the date picker as one of [CupertinoDatePickerMode]. Defaults + /// to [CupertinoDatePickerMode.dateAndTime]. Value cannot change after + /// initial build. final CupertinoDatePickerMode mode; /// The initial date and/or time of the picker. Defaults to the present date - /// and time and must not be null. The present must conform to the intervals - /// set in [minimumDate], [maximumDate], [minimumYear], and [maximumYear]. + /// and time. The present must conform to the intervals set in [minimumDate], + /// [maximumDate], [minimumYear], and [maximumYear]. /// /// Changing this value after the initial build will not affect the currently /// selected date time. @@ -375,7 +374,7 @@ class CupertinoDatePicker extends StatefulWidget { final DateTime? maximumDate; /// Minimum year that the picker can be scrolled to in - /// [CupertinoDatePickerMode.date] mode. Defaults to 1 and must not be null. + /// [CupertinoDatePickerMode.date] mode. Defaults to 1. final int minimumYear; /// Maximum year that the picker can be scrolled to in @@ -399,8 +398,6 @@ class CupertinoDatePicker extends StatefulWidget { /// Callback called when the selected date and/or time changes. If the new /// selected [DateTime] is not valid, or is not in the [minimumDate] through /// [maximumDate] range, this callback will not be called. - /// - /// Must not be null. final ValueChanged<DateTime> onDateTimeChanged; /// Background color of date picker. @@ -1890,7 +1887,7 @@ class CupertinoTimerPicker extends StatefulWidget { /// defaults to [CupertinoTimerPickerMode.hms]. /// /// [onTimerDurationChanged] is the callback called when the selected duration - /// changes and must not be null. + /// changes. /// /// [initialTimerDuration] defaults to 0 second and is limited from 0 second /// to 23 hours 59 minutes 59 seconds. @@ -1940,7 +1937,7 @@ class CupertinoTimerPicker extends StatefulWidget { /// Defines how the timer picker should be positioned within its parent. /// - /// This property must not be null. It defaults to [Alignment.center]. + /// Defaults to [Alignment.center]. final AlignmentGeometry alignment; /// Background color of timer picker. diff --git a/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart b/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart index 20f6d3a8eb23d..07c41c3cea2a9 100644 --- a/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart +++ b/packages/flutter/lib/src/cupertino/desktop_text_selection_toolbar_button.dart @@ -31,8 +31,6 @@ const EdgeInsets _kToolbarButtonPadding = EdgeInsets.fromLTRB( /// A button in the style of the Mac context menu buttons. class CupertinoDesktopTextSelectionToolbarButton extends StatefulWidget { /// Creates an instance of CupertinoDesktopTextSelectionToolbarButton. - /// - /// [child] cannot be null. const CupertinoDesktopTextSelectionToolbarButton({ super.key, required this.onPressed, @@ -51,8 +49,6 @@ class CupertinoDesktopTextSelectionToolbarButton extends StatefulWidget { /// Create an instance of [CupertinoDesktopTextSelectionToolbarButton] from /// the given [ContextMenuButtonItem]. - /// - /// [buttonItem] cannot be null. CupertinoDesktopTextSelectionToolbarButton.buttonItem({ super.key, required ContextMenuButtonItem this.buttonItem, diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 7adfe82eb6a53..a5b586c5ca6d7 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -190,8 +190,6 @@ bool _isInAccessibilityMode(BuildContext context) { /// * <https://developer.apple.com/ios/human-interface-guidelines/views/alerts/> class CupertinoAlertDialog extends StatefulWidget { /// Creates an iOS-style alert dialog. - /// - /// The [actions] must not be null. const CupertinoAlertDialog({ super.key, this.title, @@ -686,8 +684,6 @@ class _CupertinoActionSheetState extends State<CupertinoActionSheet> { /// more choices related to the current context. class CupertinoActionSheetAction extends StatelessWidget { /// Creates an action for an iOS-style action sheet. - /// - /// The [child] and [onPressed] arguments must not be null. const CupertinoActionSheetAction({ super.key, required this.onPressed, @@ -697,8 +693,6 @@ class CupertinoActionSheetAction extends StatelessWidget { }); /// The callback that is called when the button is tapped. - /// - /// This attribute must not be null. final VoidCallback onPressed; /// Whether this action is the default choice in the action sheet. @@ -1632,14 +1626,14 @@ class CupertinoDialogAction extends StatelessWidget { /// but more than one action can have this attribute set to true in the same /// [CupertinoAlertDialog]. /// - /// This parameters defaults to false and cannot be null. + /// This parameters defaults to false. final bool isDefaultAction; /// Whether this action destroys an object. /// /// For example, an action that deletes an email is destructive. /// - /// Defaults to false and cannot be null. + /// Defaults to false. final bool isDestructiveAction; /// [TextStyle] to apply to any text that appears in this button. diff --git a/packages/flutter/lib/src/cupertino/form_section.dart b/packages/flutter/lib/src/cupertino/form_section.dart index 6bd9fd4c10455..a381775ff9b63 100644 --- a/packages/flutter/lib/src/cupertino/form_section.dart +++ b/packages/flutter/lib/src/cupertino/form_section.dart @@ -193,7 +193,7 @@ class CupertinoFormSection extends StatelessWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; @override diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index 9c2d472f15f39..665da8b7257cf 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -293,8 +293,6 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer /// 3. Show a back chevron with the previous route's `title` if the current /// route is a [CupertinoPageRoute] and the previous route is also a /// [CupertinoPageRoute]. - /// - /// This value cannot be null. /// {@endtemplate} final bool automaticallyImplyLeading; @@ -303,8 +301,6 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer /// If true and [middle] is null, automatically fill in a [Text] widget with /// the current route's `title` if the route is a [CupertinoPageRoute]. /// If [middle] widget is not null, this parameter has no effect. - /// - /// This value cannot be null. final bool automaticallyImplyMiddle; /// {@template flutter.cupertino.CupertinoNavigationBar.previousPageTitle} @@ -395,7 +391,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer /// When set to true, only one navigation bar can be present per route unless /// [heroTag] is also set. /// - /// This value defaults to true and cannot be null. + /// This value defaults to true. /// {@endtemplate} final bool transitionBetweenRoutes; @@ -411,8 +407,8 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer /// navigation bars per route or to transition between multiple /// [Navigator]s. /// - /// Cannot be null. To disable Hero transitions for this navigation bar, - /// set [transitionBetweenRoutes] to false. + /// To disable Hero transitions for this navigation bar, set + /// [transitionBetweenRoutes] to false. /// {@endtemplate} final Object heroTag; @@ -577,7 +573,8 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> { class CupertinoSliverNavigationBar extends StatefulWidget { /// Creates a navigation bar for scrolling lists. /// - /// The [largeTitle] argument is required and must not be null. + /// If [automaticallyImplyTitle] is false, then the [largeTitle] argument is + /// required. const CupertinoSliverNavigationBar({ super.key, this.largeTitle, @@ -638,8 +635,6 @@ class CupertinoSliverNavigationBar extends StatefulWidget { /// If true and [largeTitle] is null, automatically fill in a [Text] widget /// with the current route's `title` if the route is a [CupertinoPageRoute]. /// If [largeTitle] widget is not null, this parameter has no effect. - /// - /// This value cannot be null. final bool automaticallyImplyTitle; /// Controls whether [middle] widget should always be visible (even in @@ -1402,8 +1397,6 @@ class _NavigationBarStaticComponents { class CupertinoNavigationBarBackButton extends StatelessWidget { /// Construct a [CupertinoNavigationBarBackButton] that can be used to pop /// the current route. - /// - /// The [color] parameter must not be null. const CupertinoNavigationBarBackButton({ super.key, this.color, diff --git a/packages/flutter/lib/src/cupertino/page_scaffold.dart b/packages/flutter/lib/src/cupertino/page_scaffold.dart index 1789ca624b0e6..ea34f2556550c 100644 --- a/packages/flutter/lib/src/cupertino/page_scaffold.dart +++ b/packages/flutter/lib/src/cupertino/page_scaffold.dart @@ -75,7 +75,7 @@ class CupertinoPageScaffold extends StatefulWidget { /// scaffold, the body can be resized to avoid overlapping the keyboard, which /// prevents widgets inside the body from being obscured by the keyboard. /// - /// Defaults to true and cannot be null. + /// Defaults to true. final bool resizeToAvoidBottomInset; @override diff --git a/packages/flutter/lib/src/cupertino/picker.dart b/packages/flutter/lib/src/cupertino/picker.dart index 11f032b449749..ecbce297b9115 100644 --- a/packages/flutter/lib/src/cupertino/picker.dart +++ b/packages/flutter/lib/src/cupertino/picker.dart @@ -53,8 +53,7 @@ const double _kOverAndUnderCenterOpacity = 0.447; class CupertinoPicker extends StatefulWidget { /// Creates a picker from a concrete list of children. /// - /// The [diameterRatio] and [itemExtent] arguments must not be null. The - /// [itemExtent] must be greater than zero. + /// The [itemExtent] must be greater than zero. /// /// The [backgroundColor] defaults to null, which disables background painting entirely. /// (i.e. the picker is going to have a completely transparent background), to match @@ -99,11 +98,11 @@ class CupertinoPicker extends StatefulWidget { /// normally the builder is only called once for each index (except when /// rebuilding - the cache is cleared). /// - /// The [itemBuilder] argument must not be null. The [childCount] argument - /// reflects the number of children that will be provided by the [itemBuilder]. + /// The [childCount] argument reflects the number of children that will be + /// provided by the [itemBuilder]. /// {@macro flutter.widgets.ListWheelChildBuilderDelegate.childCount} /// - /// The [itemExtent] argument must be non-null and positive. + /// The [itemExtent] argument must be positive. /// /// The [backgroundColor] defaults to null, which disables background painting entirely. /// (i.e. the picker is going to have a completely transparent background), to match @@ -134,7 +133,7 @@ class CupertinoPicker extends StatefulWidget { /// /// For more details, see [ListWheelScrollView.diameterRatio]. /// - /// Must not be null and defaults to `1.1` to visually mimic iOS. + /// Defaults to 1.1 to visually mimic iOS. final double diameterRatio; /// Background color behind the children. @@ -334,13 +333,12 @@ class CupertinoPickerDefaultSelectionOverlay extends StatelessWidget { /// area (or the currently selected item, depending on how you described it /// elsewhere) of a [CupertinoPicker]. /// - /// The [background] argument default value is [CupertinoColors.tertiarySystemFill]. - /// It must be non-null. + /// The [background] argument default value is + /// [CupertinoColors.tertiarySystemFill]. /// /// The [capStartEdge] and [capEndEdge] arguments decide whether to add a /// default margin and use rounded corners on the left and right side of the - /// rectangular overlay. - /// Default to true and must not be null. + /// rectangular overlay, and they both default to true. const CupertinoPickerDefaultSelectionOverlay({ super.key, this.background = CupertinoColors.tertiarySystemFill, diff --git a/packages/flutter/lib/src/cupertino/refresh.dart b/packages/flutter/lib/src/cupertino/refresh.dart index 4d32e61484238..c4e1852e610d1 100644 --- a/packages/flutter/lib/src/cupertino/refresh.dart +++ b/packages/flutter/lib/src/cupertino/refresh.dart @@ -283,7 +283,7 @@ class CupertinoSliverRefreshControl extends StatefulWidget { /// Create a new refresh control for inserting into a list of slivers. /// /// The [refreshTriggerPullDistance] and [refreshIndicatorExtent] arguments - /// must not be null and must be >= 0. + /// must be greater than or equal to 0. /// /// The [builder] argument may be null, in which case no indicator UI will be /// shown but the [onRefresh] will still be invoked. By default, [builder] @@ -307,8 +307,8 @@ class CupertinoSliverRefreshControl extends StatefulWidget { /// The amount of overscroll the scrollable must be dragged to trigger a reload. /// - /// Must not be null, must be larger than 0.0 and larger than - /// [refreshIndicatorExtent]. Defaults to 100px when not specified. + /// Must be larger than zero and larger than [refreshIndicatorExtent]. + /// Defaults to 100 pixels when not specified. /// /// When overscrolled past this distance, [onRefresh] will be called if not /// null and the [builder] will build in the [RefreshIndicatorMode.armed] state. @@ -317,9 +317,9 @@ class CupertinoSliverRefreshControl extends StatefulWidget { /// The amount of space the refresh indicator sliver will keep holding while /// [onRefresh]'s [Future] is still running. /// - /// Must not be null and must be positive, but can be 0.0, in which case the - /// sliver will start retracting back to 0.0 as soon as the refresh is started. - /// Defaults to 60px when not specified. + /// Must be a positive number, but can be zero, in which case the sliver will + /// start retracting back to zero as soon as the refresh is started. Defaults + /// to 60 pixels when not specified. /// /// Must be smaller than [refreshTriggerPullDistance], since the sliver /// shouldn't grow further after triggering the refresh. diff --git a/packages/flutter/lib/src/cupertino/route.dart b/packages/flutter/lib/src/cupertino/route.dart index 0c1d5262658dd..d0c6be160d60a 100644 --- a/packages/flutter/lib/src/cupertino/route.dart +++ b/packages/flutter/lib/src/cupertino/route.dart @@ -713,8 +713,6 @@ class _CupertinoBackGestureDetectorState<T> extends State<_CupertinoBackGestureD /// detector controller is associated. class _CupertinoBackGestureController<T> { /// Creates a controller for an iOS-style back gesture. - /// - /// The [navigator] and [controller] arguments must not be null. _CupertinoBackGestureController({ required this.navigator, required this.controller, diff --git a/packages/flutter/lib/src/cupertino/search_field.dart b/packages/flutter/lib/src/cupertino/search_field.dart index a5ffc2c5c4990..f8ec3713dcc1d 100644 --- a/packages/flutter/lib/src/cupertino/search_field.dart +++ b/packages/flutter/lib/src/cupertino/search_field.dart @@ -197,51 +197,51 @@ class CupertinoSearchTextField extends StatefulWidget { /// Sets the padding insets for the text and placeholder. /// - /// Cannot be null. Defaults to padding that replicates the - /// `UISearchTextField` look. The inset values were determined using the - /// comparison tool in https://github.com/flutter/platform_tests/. + /// Defaults to padding that replicates the `UISearchTextField` look. The + /// inset values were determined using the comparison tool in + /// https://github.com/flutter/platform_tests/. final EdgeInsetsGeometry padding; /// Sets the color for the suffix and prefix icons. /// - /// Cannot be null. Defaults to [CupertinoColors.secondaryLabel]. + /// Defaults to [CupertinoColors.secondaryLabel]. final Color itemColor; /// Sets the base icon size for the suffix and prefix icons. /// - /// Cannot be null. The size of the icon is scaled using the accessibility - /// font scale settings. Defaults to `20.0`. + /// The size of the icon is scaled using the accessibility font scale + /// settings. Defaults to `20.0`. final double itemSize; /// Sets the padding insets for the suffix. /// - /// Cannot be null. Defaults to padding that replicates the - /// `UISearchTextField` suffix look. The inset values were determined using - /// the comparison tool in https://github.com/flutter/platform_tests/. + /// Defaults to padding that replicates the `UISearchTextField` suffix look. + /// The inset values were determined using the comparison tool in + /// https://github.com/flutter/platform_tests/. final EdgeInsetsGeometry prefixInsets; /// Sets a prefix widget. /// - /// Cannot be null. Defaults to an [Icon] widget with the [CupertinoIcons.search] icon. + /// Defaults to an [Icon] widget with the [CupertinoIcons.search] icon. final Widget prefixIcon; /// Sets the padding insets for the prefix. /// - /// Cannot be null. Defaults to padding that replicates the - /// `UISearchTextField` prefix look. The inset values were determined using - /// the comparison tool in https://github.com/flutter/platform_tests/. + /// Defaults to padding that replicates the `UISearchTextField` prefix look. + /// The inset values were determined using the comparison tool in + /// https://github.com/flutter/platform_tests/. final EdgeInsetsGeometry suffixInsets; /// Sets the suffix widget's icon. /// - /// Cannot be null. Defaults to the X-Mark [CupertinoIcons.xmark_circle_fill]. - /// "To change the functionality of the suffix icon, provide a custom - /// onSuffixTap callback and specify an intuitive suffixIcon. + /// Defaults to the X-Mark [CupertinoIcons.xmark_circle_fill]. "To change the + /// functionality of the suffix icon, provide a custom onSuffixTap callback + /// and specify an intuitive suffixIcon. final Icon suffixIcon; /// Dictates when the X-Mark (suffix) should be visible. /// - /// Cannot be null. Defaults to only on when editing. + /// Defaults to only on when editing. final OverlayVisibilityMode suffixMode; /// Sets the X-Mark (suffix) action. diff --git a/packages/flutter/lib/src/cupertino/segmented_control.dart b/packages/flutter/lib/src/cupertino/segmented_control.dart index e1012fa8f54d7..dcb0cde6604a5 100644 --- a/packages/flutter/lib/src/cupertino/segmented_control.dart +++ b/packages/flutter/lib/src/cupertino/segmented_control.dart @@ -76,9 +76,9 @@ const Duration _kFadeDuration = Duration(milliseconds: 165); class CupertinoSegmentedControl<T extends Object> extends StatefulWidget { /// Creates an iOS-style segmented control bar. /// - /// The [children] and [onValueChanged] arguments must not be null. The - /// [children] argument must be an ordered [Map] such as a [LinkedHashMap]. - /// Further, the length of the [children] list must be greater than one. + /// The [children] argument must be an ordered [Map] such as a + /// [LinkedHashMap]. Further, the length of the [children] list must be + /// greater than one. /// /// Each widget value in the map of [children] must have an associated key /// that uniquely identifies this widget. This key is what will be returned @@ -120,8 +120,6 @@ class CupertinoSegmentedControl<T extends Object> extends StatefulWidget { /// The callback that is called when a new option is tapped. /// - /// This attribute must not be null. - /// /// The segmented control passes the newly selected widget's associated key /// to the callback but does not actually change state until the parent /// widget rebuilds the segmented control with the new [groupValue]. diff --git a/packages/flutter/lib/src/cupertino/slider.dart b/packages/flutter/lib/src/cupertino/slider.dart index 006a962514504..50a6d29e4bc8a 100644 --- a/packages/flutter/lib/src/cupertino/slider.dart +++ b/packages/flutter/lib/src/cupertino/slider.dart @@ -202,8 +202,6 @@ class CupertinoSlider extends StatefulWidget { /// The color to use for the thumb of the slider. /// - /// Thumb color must not be null. - /// /// Defaults to [CupertinoColors.white]. final Color thumbColor; diff --git a/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart b/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart index 2a9d12d3a0266..884e86d5ab967 100644 --- a/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart +++ b/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart @@ -299,9 +299,9 @@ class _SegmentSeparatorState extends State<_SegmentSeparator> with TickerProvide class CupertinoSlidingSegmentedControl<T> extends StatefulWidget { /// Creates an iOS-style segmented control bar. /// - /// The [children] and [onValueChanged] arguments must not be null. The - /// [children] argument must be an ordered [Map] such as a [LinkedHashMap]. - /// Further, the length of the [children] list must be greater than one. + /// The [children] argument must be an ordered [Map] such as a + /// [LinkedHashMap]. Further, the length of the [children] list must be + /// greater than one. /// /// Each widget value in the map of [children] must have an associated key /// that uniquely identifies this widget. This key is what will be returned @@ -343,8 +343,6 @@ class CupertinoSlidingSegmentedControl<T> extends StatefulWidget { /// The callback that is called when a new option is tapped. /// - /// This attribute must not be null. - /// /// The segmented control passes the newly selected widget's associated key /// to the callback but does not actually change state until the parent /// widget rebuilds the segmented control with the new [groupValue]. @@ -403,7 +401,7 @@ class CupertinoSlidingSegmentedControl<T> extends StatefulWidget { /// The amount of space by which to inset the [children]. /// - /// Must not be null. Defaults to EdgeInsets.symmetric(vertical: 2, horizontal: 3). + /// Defaults to `EdgeInsets.symmetric(vertical: 2, horizontal: 3)`. final EdgeInsetsGeometry padding; @override diff --git a/packages/flutter/lib/src/cupertino/switch.dart b/packages/flutter/lib/src/cupertino/switch.dart index 75518bcdec84f..7c0a1957f3d73 100644 --- a/packages/flutter/lib/src/cupertino/switch.dart +++ b/packages/flutter/lib/src/cupertino/switch.dart @@ -64,8 +64,7 @@ import 'thumb_painter.dart'; class CupertinoSwitch extends StatefulWidget { /// Creates an iOS-style switch. /// - /// The [value] parameter must not be null. - /// The [dragStartBehavior] parameter defaults to [DragStartBehavior.start] and must not be null. + /// The [dragStartBehavior] parameter defaults to [DragStartBehavior.start]. const CupertinoSwitch({ super.key, required this.value, @@ -84,8 +83,6 @@ class CupertinoSwitch extends StatefulWidget { }); /// Whether this switch is on or off. - /// - /// Must not be null. final bool value; /// Called when the user toggles with switch on or off. diff --git a/packages/flutter/lib/src/cupertino/tab_scaffold.dart b/packages/flutter/lib/src/cupertino/tab_scaffold.dart index 8bd129a7eb7ac..8995abfe5d4d2 100644 --- a/packages/flutter/lib/src/cupertino/tab_scaffold.dart +++ b/packages/flutter/lib/src/cupertino/tab_scaffold.dart @@ -32,8 +32,8 @@ class CupertinoTabController extends ChangeNotifier { /// Creates a [CupertinoTabController] to control the tab index of [CupertinoTabScaffold] /// and [CupertinoTabBar]. /// - /// The [initialIndex] must not be null and defaults to 0. The value must be - /// greater than or equal to 0, and less than the total number of tabs. + /// The [initialIndex] defaults to 0. The value must be greater than or equal + /// to 0, and less than the total number of tabs. CupertinoTabController({ int initialIndex = 0 }) : _index = initialIndex, assert(initialIndex >= 0); @@ -123,8 +123,6 @@ class CupertinoTabController extends ChangeNotifier { /// * [iOS human interface guidelines](https://developer.apple.com/design/human-interface-guidelines/ios/bars/tab-bars/). class CupertinoTabScaffold extends StatefulWidget { /// Creates a layout for applications with a tab bar at the bottom. - /// - /// The [tabBar] and [tabBuilder] arguments must not be null. CupertinoTabScaffold({ super.key, required this.tabBar, @@ -161,8 +159,6 @@ class CupertinoTabScaffold extends StatefulWidget { /// By default [tabBar] disables text scaling to match the native iOS behavior. /// To override this behavior, wrap each of the [tabBar]'s items inside a /// [MediaQuery] with the desired [TextScaler]. - /// - /// Must not be null. final CupertinoTabBar tabBar; /// Controls the currently selected tab index of the [tabBar], as well as the @@ -186,8 +182,6 @@ class CupertinoTabScaffold extends StatefulWidget { /// In that case, the child's [BuildContext]'s [MediaQuery] will have a /// bottom padding indicating the area of obstructing overlap from the /// [tabBar]. - /// - /// Must not be null. final IndexedWidgetBuilder tabBuilder; /// The color of the widget that underlies the entire scaffold. @@ -201,7 +195,7 @@ class CupertinoTabScaffold extends StatefulWidget { /// scaffold, the body can be resized to avoid overlapping the keyboard, which /// prevents widgets inside the body from being obscured by the keyboard. /// - /// Defaults to true and cannot be null. + /// Defaults to true. final bool resizeToAvoidBottomInset; /// Restoration ID to save and restore the state of the [CupertinoTabScaffold]. @@ -514,8 +508,8 @@ class RestorableCupertinoTabController extends RestorableChangeNotifier<Cupertin /// Creates a [RestorableCupertinoTabController] to control the tab index of /// [CupertinoTabScaffold] and [CupertinoTabBar]. /// - /// The `initialIndex` must not be null and defaults to 0. The value must be - /// greater than or equal to 0, and less than the total number of tabs. + /// The `initialIndex` defaults to zero. The value must be greater than or + /// equal to zero, and less than the total number of tabs. RestorableCupertinoTabController({ int initialIndex = 0 }) : assert(initialIndex >= 0), _initialIndex = initialIndex; diff --git a/packages/flutter/lib/src/cupertino/text_field.dart b/packages/flutter/lib/src/cupertino/text_field.dart index bda1ad6aecc55..824f3cb026219 100644 --- a/packages/flutter/lib/src/cupertino/text_field.dart +++ b/packages/flutter/lib/src/cupertino/text_field.dart @@ -194,8 +194,7 @@ class CupertinoTextField extends StatefulWidget { /// /// The [selectionHeightStyle] and [selectionWidthStyle] properties allow /// changing the shape of the selection highlighting. These properties default - /// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively and - /// must not be null. + /// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight], respectively. /// /// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior], /// [expands], [obscureText], [prefixMode], [readOnly], [scrollPadding], @@ -332,13 +331,7 @@ class CupertinoTextField extends StatefulWidget { /// /// The [selectionHeightStyle] and [selectionWidthStyle] properties allow /// changing the shape of the selection highlighting. These properties default - /// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively and - /// must not be null. - /// - /// The [autocorrect], [autofocus], [clearButtonMode], [dragStartBehavior], - /// [expands], [obscureText], [prefixMode], [readOnly], [scrollPadding], - /// [suffixMode], [textAlign], [selectionHeightStyle], [selectionWidthStyle], - /// and [enableSuggestions] properties must not be null. + /// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively. /// /// See also: /// @@ -489,7 +482,7 @@ class CupertinoTextField extends StatefulWidget { /// Controls the visibility of the [prefix] widget based on the state of /// text entry when the [prefix] argument is not null. /// - /// Defaults to [OverlayVisibilityMode.always] and cannot be null. + /// Defaults to [OverlayVisibilityMode.always]. /// /// Has no effect when [prefix] is null. final OverlayVisibilityMode prefixMode; @@ -500,7 +493,7 @@ class CupertinoTextField extends StatefulWidget { /// Controls the visibility of the [suffix] widget based on the state of /// text entry when the [suffix] argument is not null. /// - /// Defaults to [OverlayVisibilityMode.always] and cannot be null. + /// Defaults to [OverlayVisibilityMode.always]. /// /// Has no effect when [suffix] is null. final OverlayVisibilityMode suffixMode; @@ -512,7 +505,7 @@ class CupertinoTextField extends StatefulWidget { /// /// Will only appear if no [suffix] widget is appearing. /// - /// Defaults to never appearing and cannot be null. + /// Defaults to [OverlayVisibilityMode.never]. final OverlayVisibilityMode clearButtonMode; /// {@macro flutter.widgets.editableText.keyboardType} diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart index 140cd216135e1..cc991db20d651 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar_button.dart @@ -34,8 +34,6 @@ const EdgeInsets _kToolbarButtonPadding = EdgeInsets.symmetric(vertical: 18.0, h /// A button in the style of the iOS text selection toolbar buttons. class CupertinoTextSelectionToolbarButton extends StatefulWidget { /// Create an instance of [CupertinoTextSelectionToolbarButton]. - /// - /// [child] cannot be null. const CupertinoTextSelectionToolbarButton({ super.key, this.onPressed, @@ -54,8 +52,6 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget { /// Create an instance of [CupertinoTextSelectionToolbarButton] from the given /// [ContextMenuButtonItem]. - /// - /// [buttonItem] cannot be null. CupertinoTextSelectionToolbarButton.buttonItem({ super.key, required ContextMenuButtonItem this.buttonItem, diff --git a/packages/flutter/lib/src/cupertino/text_theme.dart b/packages/flutter/lib/src/cupertino/text_theme.dart index d6ee4d136eb9f..b8ef784561ff2 100644 --- a/packages/flutter/lib/src/cupertino/text_theme.dart +++ b/packages/flutter/lib/src/cupertino/text_theme.dart @@ -116,7 +116,7 @@ class CupertinoTextThemeData with Diagnosticable { /// Create a [CupertinoTextThemeData]. /// /// The [primaryColor] is used to derive TextStyle defaults of other attributes - /// such as [navActionTextStyle] and [actionTextStyle], it must not be null when + /// such as [navActionTextStyle] and [actionTextStyle]. It must not be null when /// either [navActionTextStyle] or [actionTextStyle] is null. Defaults to /// [CupertinoColors.systemBlue]. /// diff --git a/packages/flutter/lib/src/cupertino/theme.dart b/packages/flutter/lib/src/cupertino/theme.dart index 05a572eb636cb..b4daa961c1383 100644 --- a/packages/flutter/lib/src/cupertino/theme.dart +++ b/packages/flutter/lib/src/cupertino/theme.dart @@ -47,8 +47,6 @@ const _CupertinoThemeDefaults _kDefaultTheme = _CupertinoThemeDefaults( /// with a [CupertinoThemeData] derived from the Material [ThemeData]. class CupertinoTheme extends StatelessWidget { /// Creates a [CupertinoTheme] to change descendant Cupertino widgets' styling. - /// - /// The [data] and [child] parameters must not be null. const CupertinoTheme({ super.key, required this.data, diff --git a/packages/flutter/lib/src/cupertino/thumb_painter.dart b/packages/flutter/lib/src/cupertino/thumb_painter.dart index 319c6a00e967e..08f43f63ba857 100644 --- a/packages/flutter/lib/src/cupertino/thumb_painter.dart +++ b/packages/flutter/lib/src/cupertino/thumb_painter.dart @@ -59,8 +59,6 @@ class CupertinoThumbPainter { final Color color; /// The list of [BoxShadow] to paint below the thumb. - /// - /// Must not be null. final List<BoxShadow> shadows; /// Half the default diameter of the thumb. diff --git a/packages/flutter/lib/src/foundation/assertions.dart b/packages/flutter/lib/src/foundation/assertions.dart index 3cc1c3ba9480e..a914609f89e05 100644 --- a/packages/flutter/lib/src/foundation/assertions.dart +++ b/packages/flutter/lib/src/foundation/assertions.dart @@ -48,8 +48,7 @@ typedef StackTraceDemangler = StackTrace Function(StackTrace details); /// * [RepetitiveStackFrameFilter], which uses this class to compare against [StackFrame]s. @immutable class PartialStackFrame { - /// Creates a new [PartialStackFrame] instance. All arguments are required and - /// must not be null. + /// Creates a new [PartialStackFrame] instance. const PartialStackFrame({ required this.package, required this.className, @@ -397,9 +396,6 @@ class FlutterErrorDetails with Diagnosticable { /// /// The framework calls this constructor when catching an exception that will /// subsequently be reported using [FlutterError.onError]. - /// - /// The [exception] must not be null; other arguments can be left to - /// their default values. const FlutterErrorDetails({ required this.exception, this.stack, diff --git a/packages/flutter/lib/src/foundation/basic_types.dart b/packages/flutter/lib/src/foundation/basic_types.dart index 9bc8c6aa6e77b..27c9bc9222923 100644 --- a/packages/flutter/lib/src/foundation/basic_types.dart +++ b/packages/flutter/lib/src/foundation/basic_types.dart @@ -102,9 +102,8 @@ typedef AsyncValueGetter<T> = Future<T> Function(); /// also applies to any iterables derived from this one, e.g. as /// returned by `where`. class CachingIterable<E> extends IterableBase<E> { - /// Creates a CachingIterable using the given [Iterator] as the - /// source of data. The iterator must be non-null and must not throw - /// exceptions. + /// Creates a [CachingIterable] using the given [Iterator] as the source of + /// data. The iterator must not throw exceptions. /// /// Since the argument is an [Iterator], not an [Iterable], it is /// guaranteed that the underlying data set will only be walked @@ -229,8 +228,6 @@ class _LazyListIterator<E> implements Iterator<E> { /// A factory interface that also reports the type of the created objects. class Factory<T> { /// Creates a new factory. - /// - /// The `constructor` parameter must not be null. const Factory(this.constructor); /// Creates a new object of type T. diff --git a/packages/flutter/lib/src/foundation/diagnostics.dart b/packages/flutter/lib/src/foundation/diagnostics.dart index 04317cf19de03..4f14a3b4da04c 100644 --- a/packages/flutter/lib/src/foundation/diagnostics.dart +++ b/packages/flutter/lib/src/foundation/diagnostics.dart @@ -226,8 +226,6 @@ enum DiagnosticsTreeStyle { /// to render text art for arbitrary trees of [DiagnosticsNode] objects. class TextTreeConfiguration { /// Create a configuration object describing how to render a tree as text. - /// - /// All of the arguments must not be null. TextTreeConfiguration({ required this.prefixLineOne, required this.prefixOtherLines, @@ -1451,8 +1449,6 @@ abstract class DiagnosticsNode { /// Diagnostics containing just a string `message` and not a concrete name or /// value. /// - /// The [style] and [level] arguments must not be null. - /// /// See also: /// /// * [MessageProperty], which is better suited to messages that are to be @@ -1829,8 +1825,6 @@ class MessageProperty extends DiagnosticsProperty<void> { /// /// Messages have no concrete [value] (so [value] will return null). The /// message is stored as the description. - /// - /// The [name], `message`, and [level] arguments must not be null. MessageProperty( String name, String message, { @@ -1847,8 +1841,6 @@ class MessageProperty extends DiagnosticsProperty<void> { /// instead of describing a property with a string value. class StringProperty extends DiagnosticsProperty<String> { /// Create a diagnostics property for strings. - /// - /// The [showName], [quoted], [style], and [level] arguments must not be null. StringProperty( String super.name, super.value, { @@ -1956,8 +1948,6 @@ abstract class _NumProperty<T extends num> extends DiagnosticsProperty<T> { /// Numeric formatting is optimized for debug message readability. class DoubleProperty extends _NumProperty<double> { /// If specified, [unit] describes the unit for the [value] (e.g. px). - /// - /// The [showName], [style], and [level] arguments must not be null. DoubleProperty( super.name, super.value, { @@ -1974,8 +1964,6 @@ class DoubleProperty extends _NumProperty<double> { /// /// Use if computing the property [value] may throw an exception or is /// expensive. - /// - /// The [showName] and [level] arguments must not be null. DoubleProperty.lazy( super.name, super.computeValue, { @@ -1996,8 +1984,6 @@ class DoubleProperty extends _NumProperty<double> { /// Examples of units include 'px' and 'ms'. class IntProperty extends _NumProperty<int> { /// Create a diagnostics property for integers. - /// - /// The [showName], [style], and [level] arguments must not be null. IntProperty( super.name, super.value, { @@ -2022,8 +2008,6 @@ class PercentProperty extends DoubleProperty { /// Setting [showName] to false is often reasonable for [PercentProperty] /// objects, as the fact that the property is shown as a percentage tends to /// be sufficient to disambiguate its meaning. - /// - /// The [showName] and [level] arguments must not be null. PercentProperty( super.name, super.fraction, { @@ -2096,8 +2080,6 @@ class FlagProperty extends DiagnosticsProperty<bool> { /// /// [showName] defaults to false as typically [ifTrue] and [ifFalse] should /// be descriptions that make the property name redundant. - /// - /// The [showName] and [level] arguments must not be null. FlagProperty( String name, { required bool? value, @@ -2196,8 +2178,6 @@ class IterableProperty<T> extends DiagnosticsProperty<Iterable<T>> { /// empty iterable [value] is not interesting to display similar to how /// [defaultValue] is used to indicate that a specific concrete value is not /// interesting to display. - /// - /// The [style], [showName], [showSeparator], and [level] arguments must not be null. IterableProperty( String super.name, super.value, { @@ -2322,8 +2302,7 @@ class ObjectFlagProperty<T> extends DiagnosticsProperty<T> { /// absent (null), but for which the exact value's [Object.toString] /// representation is not very transparent (e.g. a callback). /// - /// The [showName] and [level] arguments must not be null. Additionally, at - /// least one of [ifPresent] and [ifNull] must not be null. + /// At least one of [ifPresent] or [ifNull] must be non-null. ObjectFlagProperty( String super.name, super.value, { @@ -2337,8 +2316,6 @@ class ObjectFlagProperty<T> extends DiagnosticsProperty<T> { /// /// Only use if prefixing the property name with the word 'has' is a good /// flag name. - /// - /// The [name] and [level] arguments must not be null. ObjectFlagProperty.has( String super.name, super.value, { @@ -2515,9 +2492,6 @@ typedef ComputePropertyValueCallback<T> = T? Function(); class DiagnosticsProperty<T> extends DiagnosticsNode { /// Create a diagnostics property. /// - /// The [showName], [showSeparator], [style], [missingIfNull], and [level] - /// arguments must not be null. - /// /// The [level] argument is just a suggestion and can be overridden if /// something else about the property causes it to have a lower or higher /// level. For example, if the property value is null and [missingIfNull] is @@ -2554,9 +2528,6 @@ class DiagnosticsProperty<T> extends DiagnosticsNode { /// Use if computing the property [value] may throw an exception or is /// expensive. /// - /// The [showName], [showSeparator], [style], [missingIfNull], and [level] - /// arguments must not be null. - /// /// The [level] argument is just a suggestion and can be overridden /// if something else about the property causes it to have a lower or higher /// level. For example, if calling `computeValue` throws an exception, [level] @@ -2694,8 +2665,6 @@ class DiagnosticsProperty<T> extends DiagnosticsNode { /// If a [tooltip] is specified, add the tooltip it to the end of `text` /// enclosing it parenthesis to disambiguate the tooltip from the rest of /// the text. - /// - /// `text` must not be null. String _addTooltip(String text) { return tooltip == null ? text : '$text ($tooltip)'; } @@ -2863,8 +2832,6 @@ class DiagnosticsProperty<T> extends DiagnosticsNode { /// to implement [getChildren] and [getProperties]. class DiagnosticableNode<T extends Diagnosticable> extends DiagnosticsNode { /// Create a diagnostics describing a [Diagnosticable] value. - /// - /// The [value] argument must not be null. DiagnosticableNode({ super.name, required this.value, diff --git a/packages/flutter/lib/src/foundation/stack_frame.dart b/packages/flutter/lib/src/foundation/stack_frame.dart index 8a2f0d61945f4..b45c82fb731c3 100644 --- a/packages/flutter/lib/src/foundation/stack_frame.dart +++ b/packages/flutter/lib/src/foundation/stack_frame.dart @@ -22,8 +22,8 @@ import 'object.dart'; class StackFrame { /// Creates a new StackFrame instance. /// - /// All parameters must not be null. The [className] may be the empty string - /// if there is no class (e.g. for a top level library method). + /// The [className] may be the empty string if there is no class (e.g. for a + /// top level library method). const StackFrame({ required this.number, required this.column, diff --git a/packages/flutter/lib/src/gestures/drag_details.dart b/packages/flutter/lib/src/gestures/drag_details.dart index f519c09097155..bcf91c3e884b7 100644 --- a/packages/flutter/lib/src/gestures/drag_details.dart +++ b/packages/flutter/lib/src/gestures/drag_details.dart @@ -20,8 +20,6 @@ export 'velocity_tracker.dart' show Velocity; /// * [DragEndDetails], the details for [GestureDragEndCallback]. class DragDownDetails { /// Creates details for a [GestureDragDownCallback]. - /// - /// The [globalPosition] argument must not be null. DragDownDetails({ this.globalPosition = Offset.zero, Offset? localPosition, @@ -65,8 +63,6 @@ typedef GestureDragDownCallback = void Function(DragDownDetails details); /// * [DragEndDetails], the details for [GestureDragEndCallback]. class DragStartDetails { /// Creates details for a [GestureDragStartCallback]. - /// - /// The [globalPosition] argument must not be null. DragStartDetails({ this.sourceTimeStamp, this.globalPosition = Offset.zero, @@ -128,12 +124,8 @@ typedef GestureDragStartCallback = void Function(DragStartDetails details); class DragUpdateDetails { /// Creates details for a [GestureDragUpdateCallback]. /// - /// The [delta] argument must not be null. - /// /// If [primaryDelta] is non-null, then its value must match one of the /// coordinates of [delta] and the other coordinate must be zero. - /// - /// The [globalPosition] argument must be provided and must not be null. DragUpdateDetails({ this.sourceTimeStamp, this.delta = Offset.zero, @@ -219,8 +211,6 @@ class DragEndDetails { /// If [primaryVelocity] is non-null, its value must match one of the /// coordinates of `velocity.pixelsPerSecond` and the other coordinate /// must be zero. - /// - /// The [velocity] argument must not be null. DragEndDetails({ this.velocity = Velocity.zero, this.primaryVelocity, diff --git a/packages/flutter/lib/src/gestures/events.dart b/packages/flutter/lib/src/gestures/events.dart index be147d6d154cc..c78f324e723c2 100644 --- a/packages/flutter/lib/src/gestures/events.dart +++ b/packages/flutter/lib/src/gestures/events.dart @@ -819,8 +819,6 @@ mixin _CopyPointerAddedEvent on PointerEvent { /// made contact with the surface of the device. class PointerAddedEvent extends PointerEvent with _PointerEventDescription, _CopyPointerAddedEvent { /// Creates a pointer added event. - /// - /// All of the arguments must be non-null. const PointerAddedEvent({ super.viewId, super.timeStamp, @@ -914,8 +912,6 @@ mixin _CopyPointerRemovedEvent on PointerEvent { /// detection range or might have been disconnected from the system entirely. class PointerRemovedEvent extends PointerEvent with _PointerEventDescription, _CopyPointerRemovedEvent { /// Creates a pointer removed event. - /// - /// All of the arguments must be non-null. const PointerRemovedEvent({ super.viewId, super.timeStamp, @@ -1024,8 +1020,6 @@ mixin _CopyPointerHoverEvent on PointerEvent { /// events in a widget tree. class PointerHoverEvent extends PointerEvent with _PointerEventDescription, _CopyPointerHoverEvent { /// Creates a pointer hover event. - /// - /// All of the arguments must be non-null. const PointerHoverEvent({ super.viewId, super.timeStamp, @@ -1143,8 +1137,6 @@ mixin _CopyPointerEnterEvent on PointerEvent { /// events in a widget tree. class PointerEnterEvent extends PointerEvent with _PointerEventDescription, _CopyPointerEnterEvent { /// Creates a pointer enter event. - /// - /// All of the arguments must be non-null. const PointerEnterEvent({ super.viewId, super.timeStamp, @@ -1293,8 +1285,6 @@ mixin _CopyPointerExitEvent on PointerEvent { /// events in a widget tree. class PointerExitEvent extends PointerEvent with _PointerEventDescription, _CopyPointerExitEvent { /// Creates a pointer exit event. - /// - /// All of the arguments must be non-null. const PointerExitEvent({ super.viewId, super.timeStamp, @@ -1435,8 +1425,6 @@ mixin _CopyPointerDownEvent on PointerEvent { /// events in a widget tree. class PointerDownEvent extends PointerEvent with _PointerEventDescription, _CopyPointerDownEvent { /// Creates a pointer down event. - /// - /// All of the arguments must be non-null. const PointerDownEvent({ super.viewId, super.timeStamp, @@ -1551,8 +1539,6 @@ mixin _CopyPointerMoveEvent on PointerEvent { /// events in a widget tree. class PointerMoveEvent extends PointerEvent with _PointerEventDescription, _CopyPointerMoveEvent { /// Creates a pointer move event. - /// - /// All of the arguments must be non-null. const PointerMoveEvent({ super.viewId, super.timeStamp, @@ -1668,8 +1654,6 @@ mixin _CopyPointerUpEvent on PointerEvent { /// events in a widget tree. class PointerUpEvent extends PointerEvent with _PointerEventDescription, _CopyPointerUpEvent { /// Creates a pointer up event. - /// - /// All of the arguments must be non-null. const PointerUpEvent({ super.viewId, super.timeStamp, @@ -1802,8 +1786,6 @@ mixin _CopyPointerScrollEvent on PointerEvent { /// participating agents may disambiguate an event's target. class PointerScrollEvent extends PointerSignalEvent with _PointerEventDescription, _CopyPointerScrollEvent { /// Creates a pointer scroll event. - /// - /// All of the arguments must be non-null. const PointerScrollEvent({ super.viewId, super.timeStamp, @@ -1905,8 +1887,6 @@ mixin _CopyPointerScrollInertiaCancelEvent on PointerEvent { /// participating agents may disambiguate an event's target. class PointerScrollInertiaCancelEvent extends PointerSignalEvent with _PointerEventDescription, _CopyPointerScrollInertiaCancelEvent { /// Creates a pointer scroll-inertia cancel event. - /// - /// All of the arguments must be non-null. const PointerScrollInertiaCancelEvent({ super.viewId, super.timeStamp, @@ -1994,8 +1974,6 @@ mixin _CopyPointerScaleEvent on PointerEvent { /// participating agents may disambiguate an event's target. class PointerScaleEvent extends PointerSignalEvent with _PointerEventDescription, _CopyPointerScaleEvent { /// Creates a pointer scale event. - /// - /// All of the arguments must be non-null. const PointerScaleEvent({ super.viewId, super.timeStamp, @@ -2080,8 +2058,6 @@ mixin _CopyPointerPanZoomStartEvent on PointerEvent { /// events in a widget tree. class PointerPanZoomStartEvent extends PointerEvent with _PointerEventDescription, _CopyPointerPanZoomStartEvent { /// Creates a pointer pan/zoom start event. - /// - /// All of the arguments must be non-null. const PointerPanZoomStartEvent({ super.viewId, super.timeStamp, @@ -2183,8 +2159,6 @@ mixin _CopyPointerPanZoomUpdateEvent on PointerEvent { /// events in a widget tree. class PointerPanZoomUpdateEvent extends PointerEvent with _PointerEventDescription, _CopyPointerPanZoomUpdateEvent { /// Creates a pointer pan/zoom update event. - /// - /// All of the arguments must be non-null. const PointerPanZoomUpdateEvent({ super.viewId, super.timeStamp, @@ -2303,8 +2277,6 @@ mixin _CopyPointerPanZoomEndEvent on PointerEvent { /// events in a widget tree. class PointerPanZoomEndEvent extends PointerEvent with _PointerEventDescription, _CopyPointerPanZoomEndEvent { /// Creates a pointer pan/zoom end event. - /// - /// All of the arguments must be non-null. const PointerPanZoomEndEvent({ super.viewId, super.timeStamp, @@ -2397,8 +2369,6 @@ mixin _CopyPointerCancelEvent on PointerEvent { /// events in a widget tree. class PointerCancelEvent extends PointerEvent with _PointerEventDescription, _CopyPointerCancelEvent { /// Creates a pointer cancel event. - /// - /// All of the arguments must be non-null. const PointerCancelEvent({ super.viewId, super.timeStamp, diff --git a/packages/flutter/lib/src/gestures/force_press.dart b/packages/flutter/lib/src/gestures/force_press.dart index dc0d19ff93331..d17255a8f1988 100644 --- a/packages/flutter/lib/src/gestures/force_press.dart +++ b/packages/flutter/lib/src/gestures/force_press.dart @@ -46,8 +46,6 @@ enum _ForceState { class ForcePressDetails { /// Creates details for a [GestureForcePressStartCallback], /// [GestureForcePressPeakCallback] or [GestureForcePressEndCallback]. - /// - /// The [globalPosition] argument must not be null. ForcePressDetails({ required this.globalPosition, Offset? localPosition, diff --git a/packages/flutter/lib/src/gestures/long_press.dart b/packages/flutter/lib/src/gestures/long_press.dart index 1c759c2161227..f5fef32b42947 100644 --- a/packages/flutter/lib/src/gestures/long_press.dart +++ b/packages/flutter/lib/src/gestures/long_press.dart @@ -107,8 +107,6 @@ typedef GestureLongPressEndCallback = void Function(LongPressEndDetails details) class LongPressDownDetails { /// Creates the details for a [GestureLongPressDownCallback]. /// - /// The `globalPosition` argument must not be null. - /// /// If the `localPosition` argument is not specified, it will default to the /// global position. const LongPressDownDetails({ @@ -136,8 +134,6 @@ class LongPressDownDetails { /// * [LongPressEndDetails], the details for [GestureLongPressEndCallback]. class LongPressStartDetails { /// Creates the details for a [GestureLongPressStartCallback]. - /// - /// The [globalPosition] argument must not be null. const LongPressStartDetails({ this.globalPosition = Offset.zero, Offset? localPosition, @@ -159,8 +155,6 @@ class LongPressStartDetails { /// * [LongPressStartDetails], the details for [GestureLongPressStartCallback]. class LongPressMoveUpdateDetails { /// Creates the details for a [GestureLongPressMoveUpdateCallback]. - /// - /// The [globalPosition] and [offsetFromOrigin] arguments must not be null. const LongPressMoveUpdateDetails({ this.globalPosition = Offset.zero, Offset? localPosition, @@ -195,8 +189,6 @@ class LongPressMoveUpdateDetails { /// * [LongPressStartDetails], the details for [GestureLongPressStartCallback]. class LongPressEndDetails { /// Creates the details for a [GestureLongPressEndCallback]. - /// - /// The [globalPosition] argument must not be null. const LongPressEndDetails({ this.globalPosition = Offset.zero, Offset? localPosition, diff --git a/packages/flutter/lib/src/gestures/lsq_solver.dart b/packages/flutter/lib/src/gestures/lsq_solver.dart index 46a05d7036635..edd2548e9d813 100644 --- a/packages/flutter/lib/src/gestures/lsq_solver.dart +++ b/packages/flutter/lib/src/gestures/lsq_solver.dart @@ -95,8 +95,6 @@ class PolynomialFit { /// Uses the least-squares algorithm to fit a polynomial to a set of data. class LeastSquaresSolver { /// Creates a least-squares solver. - /// - /// The [x], [y], and [w] arguments must not be null. LeastSquaresSolver(this.x, this.y, this.w) : assert(x.length == y.length), assert(y.length == w.length); diff --git a/packages/flutter/lib/src/gestures/monodrag.dart b/packages/flutter/lib/src/gestures/monodrag.dart index 31a2a028486b8..7904ab2be69a2 100644 --- a/packages/flutter/lib/src/gestures/monodrag.dart +++ b/packages/flutter/lib/src/gestures/monodrag.dart @@ -70,8 +70,6 @@ typedef GestureVelocityTrackerBuilder = VelocityTracker Function(PointerEvent ev abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { /// Initialize the object. /// - /// [dragStartBehavior] must not be null. - /// /// {@macro flutter.gestures.GestureRecognizer.supportedDevices} DragGestureRecognizer({ super.debugOwner, diff --git a/packages/flutter/lib/src/gestures/multidrag.dart b/packages/flutter/lib/src/gestures/multidrag.dart index cab4e7948f518..3d850573b5272 100644 --- a/packages/flutter/lib/src/gestures/multidrag.dart +++ b/packages/flutter/lib/src/gestures/multidrag.dart @@ -32,8 +32,6 @@ typedef GestureMultiDragStartCallback = Drag? Function(Offset position); /// each pointer is a subclass of [MultiDragPointerState]. abstract class MultiDragPointerState { /// Creates per-pointer state for a [MultiDragGestureRecognizer]. - /// - /// The [initialPosition] argument must not be null. MultiDragPointerState(this.initialPosition, this.kind, this.gestureSettings) : _velocityTracker = VelocityTracker.withKind(kind); diff --git a/packages/flutter/lib/src/gestures/scale.dart b/packages/flutter/lib/src/gestures/scale.dart index 11b53cf52d48d..b1dbe36708e6a 100644 --- a/packages/flutter/lib/src/gestures/scale.dart +++ b/packages/flutter/lib/src/gestures/scale.dart @@ -96,8 +96,6 @@ class _PointerPanZoomData { /// Details for [GestureScaleStartCallback]. class ScaleStartDetails { /// Creates details for [GestureScaleStartCallback]. - /// - /// The [focalPoint] argument must not be null. ScaleStartDetails({ this.focalPoint = Offset.zero, Offset? localFocalPoint, @@ -139,9 +137,8 @@ class ScaleStartDetails { class ScaleUpdateDetails { /// Creates details for [GestureScaleUpdateCallback]. /// - /// The [focalPoint], [scale], [horizontalScale], [verticalScale], [rotation] - /// arguments must not be null. The [scale], [horizontalScale], and [verticalScale] - /// argument must be greater than or equal to zero. + /// The [scale], [horizontalScale], and [verticalScale] arguments must be + /// greater than or equal to zero. ScaleUpdateDetails({ this.focalPoint = Offset.zero, Offset? localFocalPoint, @@ -243,8 +240,6 @@ class ScaleUpdateDetails { /// Details for [GestureScaleEndCallback]. class ScaleEndDetails { /// Creates details for [GestureScaleEndCallback]. - /// - /// The [velocity] argument must not be null. ScaleEndDetails({ this.velocity = Velocity.zero, this.scaleVelocity = 0, this.pointerCount = 0 }); /// The velocity of the last pointer to be lifted off of the screen. diff --git a/packages/flutter/lib/src/gestures/tap.dart b/packages/flutter/lib/src/gestures/tap.dart index 88ea7808fe545..d522c79911028 100644 --- a/packages/flutter/lib/src/gestures/tap.dart +++ b/packages/flutter/lib/src/gestures/tap.dart @@ -26,8 +26,6 @@ export 'events.dart' show PointerCancelEvent, PointerDownEvent, PointerEvent, Po /// * [TapGestureRecognizer], which passes this information to one of its callbacks. class TapDownDetails { /// Creates details for a [GestureTapDownCallback]. - /// - /// The [globalPosition] argument must not be null. TapDownDetails({ this.globalPosition = Offset.zero, Offset? localPosition, @@ -65,7 +63,7 @@ typedef GestureTapDownCallback = void Function(TapDownDetails details); /// * [GestureDetector.onTapUp], which receives this information. /// * [TapGestureRecognizer], which passes this information to one of its callbacks. class TapUpDetails { - /// The [globalPosition] argument must not be null. + /// Creates a [TapUpDetails] data object. TapUpDetails({ required this.kind, this.globalPosition = Offset.zero, diff --git a/packages/flutter/lib/src/gestures/tap_and_drag.dart b/packages/flutter/lib/src/gestures/tap_and_drag.dart index 31aa233c80434..108beaf024ee6 100644 --- a/packages/flutter/lib/src/gestures/tap_and_drag.dart +++ b/packages/flutter/lib/src/gestures/tap_and_drag.dart @@ -76,9 +76,6 @@ typedef GestureTapDragDownCallback = void Function(TapDragDownDetails details); /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. class TapDragDownDetails with Diagnosticable { /// Creates details for a [GestureTapDragDownCallback]. - /// - /// The [globalPosition], [localPosition], and [consecutiveTapCount] - /// arguments must be provided and must not be null. TapDragDownDetails({ required this.globalPosition, required this.localPosition, @@ -130,9 +127,6 @@ typedef GestureTapDragUpCallback = void Function(TapDragUpDetails details); /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. class TapDragUpDetails with Diagnosticable { /// Creates details for a [GestureTapDragUpCallback]. - /// - /// The [kind], [globalPosition], [localPosition], and [consecutiveTapCount] - /// arguments must be provided and must not be null. TapDragUpDetails({ required this.kind, required this.globalPosition, @@ -184,9 +178,6 @@ typedef GestureTapDragStartCallback = void Function(TapDragStartDetails details) /// * [TapDragEndDetails], the details for [GestureTapDragEndCallback]. class TapDragStartDetails with Diagnosticable { /// Creates details for a [GestureTapDragStartCallback]. - /// - /// The [globalPosition], [localPosition], and [consecutiveTapCount] - /// arguments must be provided and must not be null. TapDragStartDetails({ this.sourceTimeStamp, required this.globalPosition, @@ -253,13 +244,8 @@ typedef GestureTapDragUpdateCallback = void Function(TapDragUpdateDetails detail class TapDragUpdateDetails with Diagnosticable { /// Creates details for a [GestureTapDragUpdateCallback]. /// - /// The [delta] argument must not be null. - /// /// If [primaryDelta] is non-null, then its value must match one of the /// coordinates of [delta] and the other coordinate must be zero. - /// - /// The [globalPosition], [localPosition], [offsetFromOrigin], [localOffsetFromOrigin], - /// and [consecutiveTapCount] arguments must be provided and must not be null. TapDragUpdateDetails({ this.sourceTimeStamp, this.delta = Offset.zero, @@ -378,10 +364,6 @@ typedef GestureTapDragEndCallback = void Function(TapDragEndDetails endDetails); /// * [TapDragUpdateDetails], the details for [GestureTapDragUpdateCallback]. class TapDragEndDetails with Diagnosticable { /// Creates details for a [GestureTapDragEndCallback]. - /// - /// The [velocity] argument must not be null. - /// - /// The [consecutiveTapCount] argument must be provided and must not be null. TapDragEndDetails({ this.velocity = Velocity.zero, this.primaryVelocity, diff --git a/packages/flutter/lib/src/gestures/velocity_tracker.dart b/packages/flutter/lib/src/gestures/velocity_tracker.dart index 414eb6cc17e66..ca7aa468a0198 100644 --- a/packages/flutter/lib/src/gestures/velocity_tracker.dart +++ b/packages/flutter/lib/src/gestures/velocity_tracker.dart @@ -13,9 +13,7 @@ export 'dart:ui' show Offset, PointerDeviceKind; /// A velocity in two dimensions. @immutable class Velocity { - /// Creates a velocity. - /// - /// The [pixelsPerSecond] argument must not be null. + /// Creates a [Velocity]. const Velocity({ required this.pixelsPerSecond, }); @@ -90,8 +88,6 @@ class Velocity { /// useful velocity operations. class VelocityEstimate { /// Creates a dimensional velocity estimate. - /// - /// [pixelsPerSecond], [confidence], [duration], and [offset] must not be null. const VelocityEstimate({ required this.pixelsPerSecond, required this.confidence, diff --git a/packages/flutter/lib/src/rendering/table_border.dart b/packages/flutter/lib/src/rendering/table_border.dart index a5fbf5a94e845..97f2c6b9e47bf 100644 --- a/packages/flutter/lib/src/rendering/table_border.dart +++ b/packages/flutter/lib/src/rendering/table_border.dart @@ -204,6 +204,9 @@ class TableBorder { required Iterable<double> rows, required Iterable<double> columns, }) { + // properties can't be null + + // arguments can't be null assert(rows.isEmpty || (rows.first >= 0.0 && rows.last <= rect.height)); assert(columns.isEmpty || (columns.first >= 0.0 && columns.last <= rect.width)); diff --git a/packages/flutter/lib/src/semantics/semantics.dart b/packages/flutter/lib/src/semantics/semantics.dart index 21e14f3d18892..29f87d6f94369 100644 --- a/packages/flutter/lib/src/semantics/semantics.dart +++ b/packages/flutter/lib/src/semantics/semantics.dart @@ -211,7 +211,7 @@ class ChildSemanticsConfigurationsResultBuilder { class CustomSemanticsAction { /// Creates a new [CustomSemanticsAction]. /// - /// The [label] must not be null or the empty string. + /// The [label] must not be empty. const CustomSemanticsAction({required String this.label}) : assert(label != ''), hint = null, @@ -220,7 +220,7 @@ class CustomSemanticsAction { /// Creates a new [CustomSemanticsAction] that overrides a standard semantics /// action. /// - /// The [hint] must not be null or the empty string. + /// The [hint] must not be empty. const CustomSemanticsAction.overridingAction({required String this.hint, required SemanticsAction this.action}) : assert(hint != ''), label = null; @@ -411,8 +411,6 @@ class AttributedStringProperty extends DiagnosticsProperty<AttributedString> { class SemanticsData with Diagnosticable { /// Creates a semantics data object. /// - /// The [flags], [actions], [label], and [Rect] arguments must not be null. - /// /// If [label] is not empty, then [textDirection] must also not be null. SemanticsData({ required this.flags, @@ -4994,7 +4992,7 @@ abstract class SemanticsSortKey with Diagnosticable implements Comparable<Semant class OrdinalSortKey extends SemanticsSortKey { /// Creates a const semantics sort key that uses a [double] as its key value. /// - /// The [order] must be a finite number, and must not be null. + /// The [order] must be a finite number. const OrdinalSortKey( this.order, { super.name, diff --git a/packages/flutter/lib/src/semantics/semantics_event.dart b/packages/flutter/lib/src/semantics/semantics_event.dart index 6350a9a47f1ee..7ed42d56d3bc7 100644 --- a/packages/flutter/lib/src/semantics/semantics_event.dart +++ b/packages/flutter/lib/src/semantics/semantics_event.dart @@ -90,13 +90,9 @@ class AnnounceSemanticsEvent extends SemanticsEvent { : super('announce'); /// The message to announce. - /// - /// This property must not be null. final String message; /// Text direction for [message]. - /// - /// This property must not be null. final TextDirection textDirection; /// Determines whether the announcement should interrupt any existing announcement, diff --git a/packages/flutter/lib/src/services/autofill.dart b/packages/flutter/lib/src/services/autofill.dart index 8cf825fc5f71d..992d72557b613 100644 --- a/packages/flutter/lib/src/services/autofill.dart +++ b/packages/flutter/lib/src/services/autofill.dart @@ -670,15 +670,11 @@ class AutofillConfiguration { /// /// The identifier needs to be unique within the [AutofillScope] for the /// [AutofillClient] to receive the correct autofill value. - /// - /// Must not be null. final String uniqueIdentifier; /// A list of strings that helps the autofill service identify the type of the /// [AutofillClient]. /// - /// Must not be null. - /// /// {@template flutter.services.AutofillConfiguration.autofillHints} /// For the best results, hint strings need to be understood by the platform's /// autofill service. The common values of hint strings can be found in @@ -753,7 +749,7 @@ class AutofillConfiguration { abstract class AutofillClient { /// The unique identifier of this [AutofillClient]. /// - /// Must not be null and the identifier must not be changed. + /// The identifier must not be changed. String get autofillId; /// The [TextInputConfiguration] that describes this [AutofillClient]. diff --git a/packages/flutter/lib/src/services/mouse_cursor.dart b/packages/flutter/lib/src/services/mouse_cursor.dart index c698aa0b0bc97..a9cd9e94231a7 100644 --- a/packages/flutter/lib/src/services/mouse_cursor.dart +++ b/packages/flutter/lib/src/services/mouse_cursor.dart @@ -102,8 +102,6 @@ class MouseCursorManager { /// will no longer be used in the future. abstract class MouseCursorSession { /// Create a session. - /// - /// All arguments must be non-null. MouseCursorSession(this.cursor, this.device); /// The cursor that created this session. @@ -207,7 +205,7 @@ abstract class MouseCursor with Diagnosticable { /// to make debug information more readable. It is returned as the [toString] /// when the diagnostic level is at or above [DiagnosticLevel.info]. /// - /// The [debugDescription] must not be null or empty string. + /// The [debugDescription] must not be empty. String get debugDescription; @override diff --git a/packages/flutter/lib/src/services/mouse_tracking.dart b/packages/flutter/lib/src/services/mouse_tracking.dart index e0c405b90db38..a6a066e48286c 100644 --- a/packages/flutter/lib/src/services/mouse_tracking.dart +++ b/packages/flutter/lib/src/services/mouse_tracking.dart @@ -44,8 +44,6 @@ typedef PointerHoverEventListener = void Function(PointerHoverEvent event); /// * [MouseTracker], which uses [MouseTrackerAnnotation]. class MouseTrackerAnnotation with Diagnosticable { /// Creates an immutable [MouseTrackerAnnotation]. - /// - /// All arguments are optional. The [cursor] must not be null. const MouseTrackerAnnotation({ this.onEnter, this.onExit, diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index 426893ab3333f..2e1308d2811c4 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart @@ -162,10 +162,11 @@ BinaryMessenger _findBinaryMessenger() { /// /// See: <https://flutter.dev/platform-channels/> class BasicMessageChannel<T> { - /// Creates a [BasicMessageChannel] with the specified [name], [codec] and [binaryMessenger]. + /// Creates a [BasicMessageChannel] with the specified [name], [codec] and + /// [binaryMessenger]. /// - /// The [name] and [codec] arguments cannot be null. The default [ServicesBinding.defaultBinaryMessenger] - /// instance is used if [binaryMessenger] is null. + /// The default [ServicesBinding.defaultBinaryMessenger] instance is used if + /// [binaryMessenger] is null. const BasicMessageChannel(this.name, this.codec, { BinaryMessenger? binaryMessenger }) : _binaryMessenger = binaryMessenger; @@ -253,8 +254,8 @@ class MethodChannel { /// The [codec] used will be [StandardMethodCodec], unless otherwise /// specified. /// - /// The [name] and [codec] arguments cannot be null. The default [ServicesBinding.defaultBinaryMessenger] - /// instance is used if [binaryMessenger] is null. + /// The default [ServicesBinding.defaultBinaryMessenger] instance is used if + /// [binaryMessenger] is null. const MethodChannel(this.name, [this.codec = const StandardMethodCodec(), BinaryMessenger? binaryMessenger ]) : _binaryMessenger = binaryMessenger; diff --git a/packages/flutter/lib/src/services/platform_views.dart b/packages/flutter/lib/src/services/platform_views.dart index c1774998ff6ff..0fb1144838274 100644 --- a/packages/flutter/lib/src/services/platform_views.dart +++ b/packages/flutter/lib/src/services/platform_views.dart @@ -58,7 +58,7 @@ class PlatformViewsRegistry { /// Callback signature for when a platform view was created. /// -/// `id` is the platform view's unique identifier. +/// The `id` parameter is the platform view's unique identifier. typedef PlatformViewCreatedCallback = void Function(int id); /// Provides access to the platform views service. @@ -92,28 +92,33 @@ class PlatformViewsService { /// {@template flutter.services.PlatformViewsService.initAndroidView} /// Creates a controller for a new Android view. /// - /// `id` is an unused unique identifier generated with [platformViewsRegistry]. + /// The `id` argument is an unused unique identifier generated with + /// [platformViewsRegistry]. /// - /// `viewType` is the identifier of the Android view type to be created, a - /// factory for this view type must have been registered on the platform side. - /// Platform view factories are typically registered by plugin code. - /// Plugins can register a platform view factory with + /// The `viewType` argument is the identifier of the Android view type to be + /// created, a factory for this view type must have been registered on the + /// platform side. Platform view factories are typically registered by plugin + /// code. Plugins can register a platform view factory with /// [PlatformViewRegistry#registerViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewRegistry.html#registerViewFactory-java.lang.String-io.flutter.plugin.platform.PlatformViewFactory-). /// - /// `creationParams` will be passed as the args argument of [PlatformViewFactory#create](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#create-android.content.Context-int-java.lang.Object-) + /// The `creationParams` argument will be passed as the args argument of + /// [PlatformViewFactory#create](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#create-android.content.Context-int-java.lang.Object-) /// - /// `creationParamsCodec` is the codec used to encode `creationParams` before sending it to the - /// platform side. It should match the codec passed to the constructor of [PlatformViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#PlatformViewFactory-io.flutter.plugin.common.MessageCodec-). - /// This is typically one of: [StandardMessageCodec], [JSONMessageCodec], [StringCodec], or [BinaryCodec]. + /// The `creationParamsCodec` argument is the codec used to encode + /// `creationParams` before sending it to the platform side. It should match + /// the codec passed to the constructor of + /// [PlatformViewFactory](/javadoc/io/flutter/plugin/platform/PlatformViewFactory.html#PlatformViewFactory-io.flutter.plugin.common.MessageCodec-). + /// This is typically one of: [StandardMessageCodec], [JSONMessageCodec], + /// [StringCodec], or [BinaryCodec]. /// - /// `onFocus` is a callback that will be invoked when the Android View asks to get the - /// input focus. + /// The `onFocus` argument is a callback that will be invoked when the Android + /// View asks to get the input focus. /// - /// The Android view will only be created after [AndroidViewController.setSize] is called for the - /// first time. + /// The Android view will only be created after + /// [AndroidViewController.setSize] is called for the first time. /// - /// The `id, `viewType, and `layoutDirection` parameters must not be null. - /// If `creationParams` is non null then `creationParamsCodec` must not be null. + /// If `creationParams` is non null then `creationParamsCodec` must not be + /// null. /// {@endtemplate} /// /// This attempts to use the newest and most efficient platform view @@ -196,19 +201,23 @@ class PlatformViewsService { return controller; } - // TODO(amirh): reference the iOS plugin API for registering a UIView factory once it lands. - /// This is work in progress, not yet ready to be used, and requires a custom engine build. Creates a controller for a new iOS UIView. + // TODO(amirh): reference the iOS plugin API for registering a UIView factory + // once it lands. + + /// This is work in progress, not yet ready to be used, and requires a custom + /// engine build. Creates a controller for a new iOS UIView. /// - /// `id` is an unused unique identifier generated with [platformViewsRegistry]. + /// The `id` parameter is an unused unique identifier generated with + /// [platformViewsRegistry]. /// - /// `viewType` is the identifier of the iOS view type to be created, a - /// factory for this view type must have been registered on the platform side. - /// Platform view factories are typically registered by plugin code. + /// The `viewType` parameter is the identifier of the iOS view type to be + /// created, a factory for this view type must have been registered on the + /// platform side. Platform view factories are typically registered by plugin + /// code. /// - /// `onFocus` is a callback that will be invoked when the UIKit view asks to - /// get the input focus. - /// The `id, `viewType, and `layoutDirection` parameters must not be null. - /// If `creationParams` is non null then `creationParamsCodec` must not be null. + /// The `onFocus` parameter is a callback that will be invoked when the UIKit + /// view asks to get the input focus. If `creationParams` is non null then + /// `creationParamsCodec` must not be null. static Future<UiKitViewController> initUiKitView({ required int id, required String viewType, @@ -242,16 +251,17 @@ class PlatformViewsService { /// Factory method to create an `AppKitView`. /// - /// `id` is an unused unique identifier generated with [platformViewsRegistry]. + /// The `id` parameter is an unused unique identifier generated with + /// [platformViewsRegistry]. /// - /// `viewType` is the identifier of the iOS view type to be created, a - /// factory for this view type must have been registered on the platform side. - /// Platform view factories are typically registered by plugin code. + /// The `viewType` parameter is the identifier of the iOS view type to be + /// created, a factory for this view type must have been registered on the + /// platform side. Platform view factories are typically registered by plugin + /// code. /// - /// `onFocus` is a callback that will be invoked when the UIKit view asks to - /// get the input focus. - /// The `id, `viewType, and `layoutDirection` parameters must not be null. - /// If `creationParams` is non null then `creationParamsCodec` must not be null. + /// The `onFocus` parameter is a callback that will be invoked when the UIKit + /// view asks to get the input focus. If `creationParams` is non null then + /// `creationParamsCodec` must not be null. static Future<AppKitViewController> initAppKitView({ required int id, required String viewType, @@ -289,8 +299,6 @@ class PlatformViewsService { /// A Dart version of Android's [MotionEvent.PointerProperties](https://developer.android.com/reference/android/view/MotionEvent.PointerProperties). class AndroidPointerProperties { /// Creates an [AndroidPointerProperties] object. - /// - /// All parameters must not be null. const AndroidPointerProperties({ required this.id, required this.toolType, @@ -331,8 +339,6 @@ class AndroidPointerProperties { /// A Dart version of Android's [MotionEvent.PointerCoords](https://developer.android.com/reference/android/view/MotionEvent.PointerCoords). class AndroidPointerCoords { /// Creates an AndroidPointerCoords. - /// - /// All parameters must not be null. const AndroidPointerCoords({ required this.orientation, required this.pressure, @@ -413,8 +419,6 @@ class AndroidPointerCoords { /// * [AndroidViewController.sendMotionEvent], which can be used to send an [AndroidMotionEvent] explicitly. class AndroidMotionEvent { /// Creates an AndroidMotionEvent. - /// - /// All parameters must not be null. AndroidMotionEvent({ required this.downTime, required this.eventTime, @@ -807,8 +811,8 @@ abstract class AndroidViewController extends PlatformViewController { /// Sizes the Android View. /// - /// [size] is the view's new size in logical pixel, it must not be null and must - /// be bigger than zero. + /// [size] is the view's new size in logical pixel. It must be greater than + /// zero. /// /// The first time a size is set triggers the creation of the Android view. /// diff --git a/packages/flutter/lib/src/services/raw_keyboard_android.dart b/packages/flutter/lib/src/services/raw_keyboard_android.dart index 4de79dad9567e..c6f07ed11f3bf 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_android.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_android.dart @@ -27,9 +27,6 @@ const int _kCombiningCharacterMask = 0x7fffffff; /// * [RawKeyboard], which uses this interface to expose key data. class RawKeyEventDataAndroid extends RawKeyEventData { /// Creates a key event data structure specific for Android. - /// - /// The [flags], [codePoint], [keyCode], [scanCode], and [metaState] arguments - /// must not be null. const RawKeyEventDataAndroid({ this.flags = 0, this.codePoint = 0, diff --git a/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart b/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart index 3f74d08400518..3331a78dd70ca 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_fuchsia.dart @@ -22,8 +22,6 @@ export 'raw_keyboard.dart' show KeyboardSide, ModifierKey; /// * [RawKeyboard], which uses this interface to expose key data. class RawKeyEventDataFuchsia extends RawKeyEventData { /// Creates a key event data structure specific for Fuchsia. - /// - /// The [hidUsage], [codePoint], and [modifiers] arguments must not be null. const RawKeyEventDataFuchsia({ this.hidUsage = 0, this.codePoint = 0, diff --git a/packages/flutter/lib/src/services/raw_keyboard_ios.dart b/packages/flutter/lib/src/services/raw_keyboard_ios.dart index 841d8425b6cdf..74cded59a6a9b 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_ios.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_ios.dart @@ -22,9 +22,6 @@ export 'raw_keyboard.dart' show KeyboardSide, ModifierKey; /// * [RawKeyboard], which uses this interface to expose key data. class RawKeyEventDataIos extends RawKeyEventData { /// Creates a key event data structure specific for iOS. - /// - /// The [characters], [charactersIgnoringModifiers], and [modifiers], arguments - /// must not be null. const RawKeyEventDataIos({ this.characters = '', this.charactersIgnoringModifiers = '', diff --git a/packages/flutter/lib/src/services/raw_keyboard_linux.dart b/packages/flutter/lib/src/services/raw_keyboard_linux.dart index 81c128d0a3746..d01a9a8e6d1ab 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_linux.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_linux.dart @@ -22,9 +22,6 @@ export 'raw_keyboard.dart' show KeyboardSide, ModifierKey; /// * [RawKeyboard], which uses this interface to expose key data. class RawKeyEventDataLinux extends RawKeyEventData { /// Creates a key event data structure specific for Linux. - /// - /// The [keyHelper], [scanCode], [unicodeScalarValues], [keyCode], and [modifiers], - /// arguments must not be null. const RawKeyEventDataLinux({ required this.keyHelper, this.unicodeScalarValues = 0, diff --git a/packages/flutter/lib/src/services/raw_keyboard_macos.dart b/packages/flutter/lib/src/services/raw_keyboard_macos.dart index 4f33c8617b842..1d0476d803224 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_macos.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_macos.dart @@ -33,9 +33,6 @@ int runeToLowerCase(int rune) { /// * [RawKeyboard], which uses this interface to expose key data. class RawKeyEventDataMacOs extends RawKeyEventData { /// Creates a key event data structure specific for macOS. - /// - /// The [characters], [charactersIgnoringModifiers], and [modifiers], arguments - /// must not be null. const RawKeyEventDataMacOs({ this.characters = '', this.charactersIgnoringModifiers = '', diff --git a/packages/flutter/lib/src/services/raw_keyboard_web.dart b/packages/flutter/lib/src/services/raw_keyboard_web.dart index 8cc289b79d2ff..c3d114e706d01 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_web.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_web.dart @@ -27,8 +27,6 @@ String? _unicodeChar(String key) { @immutable class RawKeyEventDataWeb extends RawKeyEventData { /// Creates a key event data structure specific for Web. - /// - /// The [code] and [metaState] arguments must not be null. const RawKeyEventDataWeb({ required this.code, required this.key, diff --git a/packages/flutter/lib/src/services/raw_keyboard_windows.dart b/packages/flutter/lib/src/services/raw_keyboard_windows.dart index 2c2376a38ee43..3110b5aebcfe2 100644 --- a/packages/flutter/lib/src/services/raw_keyboard_windows.dart +++ b/packages/flutter/lib/src/services/raw_keyboard_windows.dart @@ -27,9 +27,6 @@ const int _vkProcessKey = 0xe5; /// * [RawKeyboard], which uses this interface to expose key data. class RawKeyEventDataWindows extends RawKeyEventData { /// Creates a key event data structure specific for Windows. - /// - /// The [keyCode], [scanCode], [characterCodePoint], and [modifiers], arguments - /// must not be null. const RawKeyEventDataWindows({ this.keyCode = 0, this.scanCode = 0, diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart index 4bb7811f52764..694f2f63ce5ba 100644 --- a/packages/flutter/lib/src/services/restoration.dart +++ b/packages/flutter/lib/src/services/restoration.dart @@ -495,8 +495,6 @@ class RestorationBucket { /// claiming a child from a parent via [claimChild]. If no parent bucket is /// available, [RestorationManager.rootBucket] may be used as a parent. /// {@endtemplate} - /// - /// The `restorationId` must not be null. RestorationBucket.empty({ required String restorationId, required Object? debugOwner, @@ -529,8 +527,6 @@ class RestorationBucket { /// ``` /// /// {@macro flutter.services.RestorationBucket.empty.bucketCreation} - /// - /// The `manager` argument must not be null. RestorationBucket.root({ required RestorationManager manager, required Map<Object?, Object?>? rawData, @@ -551,8 +547,6 @@ class RestorationBucket { /// [RestorationBucket.empty] and have the parent adopt it via [adoptChild]. /// /// {@macro flutter.services.RestorationBucket.empty.bucketCreation} - /// - /// The `restorationId` and `parent` argument must not be null. RestorationBucket.child({ required String restorationId, required RestorationBucket parent, diff --git a/packages/flutter/lib/src/services/text_editing.dart b/packages/flutter/lib/src/services/text_editing.dart index 6dae30a85f15f..d1d91c20ef289 100644 --- a/packages/flutter/lib/src/services/text_editing.dart +++ b/packages/flutter/lib/src/services/text_editing.dart @@ -12,8 +12,6 @@ export 'dart:ui' show TextAffinity, TextPosition; @immutable class TextSelection extends TextRange { /// Creates a text selection. - /// - /// The [baseOffset] and [extentOffset] arguments must not be null. const TextSelection({ required this.baseOffset, required this.extentOffset, @@ -29,8 +27,6 @@ class TextSelection extends TextRange { /// A collapsed selection starts and ends at the same offset, which means it /// contains zero characters but instead serves as an insertion point in the /// text. - /// - /// The [offset] argument must not be null. const TextSelection.collapsed({ required int offset, this.affinity = TextAffinity.downstream, diff --git a/packages/flutter/lib/src/services/text_editing_delta.dart b/packages/flutter/lib/src/services/text_editing_delta.dart index a93c46ad49780..aff975414674a 100644 --- a/packages/flutter/lib/src/services/text_editing_delta.dart +++ b/packages/flutter/lib/src/services/text_editing_delta.dart @@ -56,10 +56,6 @@ bool _debugTextRangeIsValid(TextRange range, String text) { /// to true. abstract class TextEditingDelta with Diagnosticable { /// Creates a delta for a given change to the editing state. - /// - /// {@template flutter.services.TextEditingDelta} - /// The [oldText], [selection], and [composing] arguments must not be null. - /// {@endtemplate} const TextEditingDelta({ required this.oldText, required this.selection, @@ -251,8 +247,6 @@ abstract class TextEditingDelta with Diagnosticable { class TextEditingDeltaInsertion extends TextEditingDelta { /// Creates an insertion delta for a given change to the editing state. /// - /// {@macro flutter.services.TextEditingDelta} - /// /// {@template flutter.services.TextEditingDelta.optIn} /// See also: /// @@ -304,8 +298,6 @@ class TextEditingDeltaInsertion extends TextEditingDelta { class TextEditingDeltaDeletion extends TextEditingDelta { /// Creates a deletion delta for a given change to the editing state. /// - /// {@macro flutter.services.TextEditingDelta} - /// /// {@macro flutter.services.TextEditingDelta.optIn} const TextEditingDeltaDeletion({ required super.oldText, @@ -356,8 +348,6 @@ class TextEditingDeltaReplacement extends TextEditingDelta { /// A replacement can occur in cases such as auto-correct, suggestions, and /// when a selection is replaced by a single character. /// - /// {@macro flutter.services.TextEditingDelta} - /// /// {@macro flutter.services.TextEditingDelta.optIn} const TextEditingDeltaReplacement({ required super.oldText, @@ -413,8 +403,6 @@ class TextEditingDeltaNonTextUpdate extends TextEditingDelta { /// handles. There are no changes to the text, but there are updates to the selection /// and potentially the composing region as well. /// - /// {@macro flutter.services.TextEditingDelta} - /// /// {@macro flutter.services.TextEditingDelta.optIn} const TextEditingDeltaNonTextUpdate({ required super.oldText, diff --git a/packages/flutter/lib/src/services/text_formatter.dart b/packages/flutter/lib/src/services/text_formatter.dart index d3c205b8489dd..92d9570a13f9a 100644 --- a/packages/flutter/lib/src/services/text_formatter.dart +++ b/packages/flutter/lib/src/services/text_formatter.dart @@ -271,9 +271,6 @@ class FilteringTextInputFormatter extends TextInputFormatter { /// If [allow] is false, then the filter pattern is a deny list, /// and characters that match the pattern are rejected. See also /// the [FilteringTextInputFormatter.deny] constructor. - /// - /// The [filterPattern], [allow], and [replacementString] arguments - /// must not be null. FilteringTextInputFormatter( this.filterPattern, { required this.allow, @@ -281,18 +278,12 @@ class FilteringTextInputFormatter extends TextInputFormatter { }); /// Creates a formatter that only allows characters matching a pattern. - /// - /// The [filterPattern] and [replacementString] arguments - /// must not be null. FilteringTextInputFormatter.allow( Pattern filterPattern, { String replacementString = '', }) : this(filterPattern, allow: true, replacementString: replacementString); /// Creates a formatter that blocks characters matching a pattern. - /// - /// The [filterPattern] and [replacementString] arguments - /// must not be null. FilteringTextInputFormatter.deny( Pattern filterPattern, { String replacementString = '', diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart index 29684ccb8d88a..ae7efa8ff006d 100644 --- a/packages/flutter/lib/src/services/text_input.dart +++ b/packages/flutter/lib/src/services/text_input.dart @@ -566,7 +566,7 @@ class TextInputConfiguration { /// [autocorrect], so that suggestions are only shown when [autocorrect] is /// true. On Android autocorrection and suggestion are controlled separately. /// - /// Defaults to true. Cannot be null. + /// Defaults to true. /// /// See also: /// @@ -580,7 +580,7 @@ class TextInputConfiguration { /// change is sent through semantics actions and is directly disabled from /// the widget side. /// - /// Defaults to true. Cannot be null. + /// Defaults to true. final bool enableInteractiveSelection; /// What text to display in the text input control's action button. @@ -612,7 +612,7 @@ class TextInputConfiguration { /// /// This flag only affects Android. On iOS, there is no equivalent flag. /// - /// Defaults to true. Cannot be null. + /// Defaults to true. /// /// See also: /// @@ -684,7 +684,7 @@ class TextInputConfiguration { /// * If [TextInputClient] is implemented then updates for the editing /// state will come through [TextInputClient.updateEditingValue]. /// - /// Defaults to false. Cannot be null. + /// Defaults to false. final bool enableDeltaModel; /// Returns a representation of this object as a JSON object. @@ -762,9 +762,6 @@ class TextEditingValue { /// The selection and composing range must be within the text. This is not /// checked during construction, and must be guaranteed by the caller. /// - /// The [text], [selection], and [composing] arguments must not be null but - /// each have default values. - /// /// The default value of [selection] is `TextSelection.collapsed(offset: -1)`. /// This indicates that there is no selection at all. const TextEditingValue({ @@ -1398,8 +1395,8 @@ class TextInputConnection { /// Send the smallest rect that covers the text in the client that's currently /// being composed. /// - /// The given `rect` can not be null. If any of the 4 coordinates of the given - /// [Rect] is not finite, a [Rect] of size (-1, -1) will be sent instead. + /// If any of the 4 coordinates of the given [Rect] is not finite, a [Rect] of + /// size (-1, -1) will be sent instead. /// /// This information is used for positioning the IME candidates menu on each /// platform. diff --git a/packages/flutter_driver/lib/src/common/wait.dart b/packages/flutter_driver/lib/src/common/wait.dart index 0c19ce48c68c2..73a3424e13ea6 100644 --- a/packages/flutter_driver/lib/src/common/wait.dart +++ b/packages/flutter_driver/lib/src/common/wait.dart @@ -12,8 +12,6 @@ class WaitForCondition extends Command { const WaitForCondition(this.condition, {super.timeout}); /// Deserializes this command from the value generated by [serialize]. - /// - /// The [json] argument cannot be null. WaitForCondition.deserialize(super.json) : condition = _deserialize(json), super.deserialize(); diff --git a/packages/flutter_goldens/lib/flutter_goldens.dart b/packages/flutter_goldens/lib/flutter_goldens.dart index 2e53f34233c7b..d9b901e267027 100644 --- a/packages/flutter_goldens/lib/flutter_goldens.dart +++ b/packages/flutter_goldens/lib/flutter_goldens.dart @@ -97,11 +97,11 @@ abstract class FlutterGoldenFileComparator extends GoldenFileComparator { }); /// The directory to which golden file URIs will be resolved in [compare] and - /// [update], cannot be null. + /// [update]. final Uri basedir; /// A client for uploading image tests and making baseline requests to the - /// Flutter Gold Dashboard, cannot be null. + /// Flutter Gold Dashboard. final SkiaGoldClient skiaClient; /// The file system used to perform file access. @@ -378,8 +378,6 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator { }); /// Describes the reason for using the [FlutterSkippingFileComparator]. - /// - /// Cannot be null. final String reason; /// Creates a new [FlutterSkippingFileComparator] that mirrors the diff --git a/packages/flutter_test/lib/src/goldens.dart b/packages/flutter_test/lib/src/goldens.dart index 82259c5879eef..edd49d2841b9c 100644 --- a/packages/flutter_test/lib/src/goldens.dart +++ b/packages/flutter_test/lib/src/goldens.dart @@ -331,8 +331,6 @@ class ComparisonResult { }); /// Indicates whether or not a pixel comparison test has failed. - /// - /// This value cannot be null. final bool passed; /// Error message used to describe the cause of the pixel comparison failure. From 3a78e5c5fcd9a83cfae479f6cd7508ad7b421835 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 12:01:02 -0400 Subject: [PATCH 1362/1547] Roll Packages from d4e245421737 to 51e74b97508a (12 revisions) (#135145) https://github.com/flutter/packages/compare/d4e245421737...51e74b97508a 2023-09-19 stuartmorgan@google.com [ios_platform_images] Convert to Pigeon (flutter/packages#4945) 2023-09-19 abdeluached@gmail.com [go_router_builder] Generate initialLocation with StatefulShellBranchConfig (flutter/packages#4880) 2023-09-19 engine-flutter-autoroll@skia.org Roll Flutter from b7d0e8c9ed70 to 893650416352 (15 revisions) (flutter/packages#4947) 2023-09-18 47866232+chunhtai@users.noreply.github.com [go_router] Adds on exit (flutter/packages#4699) 2023-09-18 47866232+chunhtai@users.noreply.github.com [go_router] Fixes RouteInformationParser that does not restore full RouteMatchList if the optionURLReflectsImperativeAPIs is set (flutter/packages#4713) 2023-09-18 stuartmorgan@google.com [file_selector] Fix unknown extensions on macOS (flutter/packages#4946) 2023-09-18 30872003+misos1@users.noreply.github.com [camera_avfoundation] ignore audio samples until first video sample (flutter/packages#4587) 2023-09-18 engine-flutter-autoroll@skia.org Roll Flutter from 1b18b1327a59 to b7d0e8c9ed70 (11 revisions) (flutter/packages#4944) 2023-09-18 tarrinneal@gmail.com [video_player] isCompleted event. (flutter/packages#4923) 2023-09-18 32538273+ValentinVignal@users.noreply.github.com [go_router] Fix an issue in the documentation that used `state.queryParameters` instead of `state.uri.queryParameters` (flutter/packages#4881) 2023-09-18 stuartmorgan@google.com [google_sign_in] Convert iOS to Pigeon (flutter/packages#4941) 2023-09-18 stuartmorgan@google.com Add dashboard link to README (flutter/packages#4902) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index ea3bd83ec2020..728005329905e 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -d4e24542173774e2f9d78de8fd17d34713478bf4 +51e74b97508a3f85af2c45d994be0e0a58b496f8 From 594ff98a654594ba0a91e8c739125f498989a297 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:01:04 +0000 Subject: [PATCH 1363/1547] [Android] Add Java/AGP/Gradle incompatibility warning to `flutter create` (#131444) Adds warning to `flutter create` command that checks if detected Java version is compatible with the template AGP and template Gradle versions. If a developer is building for Android and their Java version is incompatible with either the AGP or Gradle versions that Flutter currently supports by default for new Flutter projects, then - a warning will show noting the incompatibility and - steps will be shown to fix the issue, the recommended option being to configure a new compatible Java version given that Flutter knows we can support the template Gradle/AGP versions and updating them manually may be risky (feedback on this approach would be greatly appreciated!) Given that the template AGP and Gradle versions are compatible, this PR assumes that the detected Java version may only conflict with one of the template AGP or Gradle versions because: - the minimum Java version for a given AGP version is less than the maximum Java version compatible for the minimum Gradle version required for that AGP version (too low a Java version will fail AGP compatibility test, but not Gradle compatibility). - the maximum Java version compatible with minimum Gradle version for a given AGP version is higher than minimum Java version required for that AGP version (too high a Java version will fail Gradle compatibility test, but not AGP compatibility test). Fixes https://github.com/flutter/flutter/issues/130515 in the sense that `flutter create foo`; `cd foo`; `flutter run` should always be successful. --- .../flutter_tools/lib/src/android/README.md | 94 ++++ .../lib/src/android/gradle_utils.dart | 428 +++++++++++++----- .../lib/src/base/version_range.dart | 30 ++ .../lib/src/commands/create.dart | 179 ++++++++ .../lib/src/commands/create_base.dart | 2 +- packages/flutter_tools/lib/src/project.dart | 10 +- .../lib/src/project_validator.dart | 2 +- .../module/android/gradle/build.gradle.tmpl | 2 +- .../hermetic/create_usage_test.dart | 17 +- .../permeable/build_aar_test.dart | 2 + .../permeable/build_apk_test.dart | 9 + .../commands.shard/permeable/create_test.dart | 229 ++++++++++ .../android/gradle_utils_test.dart | 339 +++++++++++++- 13 files changed, 1204 insertions(+), 139 deletions(-) create mode 100644 packages/flutter_tools/lib/src/android/README.md create mode 100644 packages/flutter_tools/lib/src/base/version_range.dart diff --git a/packages/flutter_tools/lib/src/android/README.md b/packages/flutter_tools/lib/src/android/README.md new file mode 100644 index 0000000000000..fbc870bac46ee --- /dev/null +++ b/packages/flutter_tools/lib/src/android/README.md @@ -0,0 +1,94 @@ +# Flutter Tools for Android + +This section of the Flutter repository contains the command line developer tools +for building Flutter applications on Android. What follows are some notes about +updating this part of the tool. + +## Updating Android dependencies +The Android dependencies that Flutter uses to run on Android +include the Android NDK and SDK versions, Gradle, the Kotlin Gradle Plugin, +and the Android Gradle Plugin (AGP). The template versions of these +dependencies can be found in [gradle_utils.dart](gradle_utils.dart). + +Follow the guides below when*... + +### Updating the template version of... + +#### The Android SDK & NDK +All of the Android SDK/NDK versions noted in `gradle_utils.dart` +(`compileSdkVersion`, `minSdkVersion`, `targetSdkVersion`, `ndkVersion`) +versions should match the values in Flutter Gradle Plugin (`FlutterExtension`), +so updating any of these versions also requires an update in +[flutter.groovy](../../../gradle/src/main/groovy/flutter.groovy). + +When updating the Android `compileSdkVersion`, `minSdkVersion`, or +`targetSdkVersion`, make sure that: +- Framework integration & benchmark tests are running with at least that SDK +version. +- Flutter tools tests that perform String checks with the current template +SDK verisons are updated (you should see these fail if you do not fix them +preemptively). + +#### Gradle +When updating the Gradle version used in project templates +(`templateDefaultGradleVersion`), make sure that: +- Framework integration & benchmark tests are running with at least this Gradle +version. +- Flutter tools tests that perform String checks with the current template +Gradle version are updated (you should see these fail if you do not fix them +preemptively). + +#### The Kotlin Gradle Plugin +When updating the Kotlin Gradle Plugin (KGP) version used in project templates +(`templateKotlinGradlePluginVersion`), make sure that the framework integration +& benchmark tests are running with at least this KGP version. + +For information aboout the latest version, check https://kotlinlang.org/docs/releases.html#release-details. + +#### The Android Gradle Plugin (AGP) +When updating the Android Gradle Plugin (AGP) versions used in project templates +(`templateAndroidGradlePluginVersion`, `templateAndroidGradlePluginVersionForModule`), +make sure that: +- Framework integration & benchmark tests are running with at least this AGP +version. +- Flutter tools tests that perform String checks with the current template +AGP verisons are updated (you should see these fail if you do not fix them +preemptively). + +### A new version becomes available for... + +#### Gradle +When new versions of Gradle become available, make sure to: +- Check if the maximum version of Gradle that we support +(`maxKnownAndSupportedGradleVersion`) can be updated, and if so, take the +necessary steps to ensure we are testing this version in CI. +- Check that the Java version that is one higher than we currently support +(`oneMajorVersionHigherJavaVersion`) based on current maximum supported +Gradle version is up-to-date. +- Update the `_javaGradleCompatList` that contains the Java/Gradle +compatibility information known to the tool. +- Update the test cases in [gradle_utils_test.dart](../../..test/general.shard/android/gradle_utils_test.dart) that test compatibility between Java and Gradle versions +(relevant tests should fail if you do not fix them preemptively, but should also +be marked inline). +- Update the test cases in [create_test.dart](../../../test/commands.shard/permeable/create_test.dart) that test for a warning for Java/Gradle incompatibilities as needed +(relevant tests should fail if you do not fix them preemptively). + +For more information about the latest version, check https://gradle.org/releases/. + +#### The Android Gradle Plugin (AGP) +When new versions of the Android Gradle Plugin become available, make sure to: +- Update the maximum version of AGP that we know of (`maxKnownAgpVersion`). +- Check if the maximum version of AGP that we support +(`maxKnownAndSupportedAgpVersion`) can be updated, and if so, take the necessary +steps to ensure that we are testing this version in CI. +- Update the `_javaAgpCompatList` that contains the Java/AGP compatibility +information known to the tool. +- Update the test cases in [gradle_utils_test.dart](../../..test/general.shard/android/gradle_utils_test.dart) that test compatibility between Java and AGP versions +(relevant tests should fail if you do not fix them preemptively, but should also +be marked inline). +- Update the test cases in [create_test.dart](../../../test/commands.shard/permeable/create_test.dart) that test for a warning for Java/AGP incompatibilities as needed +(relevant tests should fail if you do not fix them preemptively). + +For information about the latest version, check https://developer.android.com/studio/releases/gradle-plugin#updating-gradle. + +\* There is an ongoing effort to reduce these steps; see https://github.com/flutter/flutter/issues/134780. diff --git a/packages/flutter_tools/lib/src/android/gradle_utils.dart b/packages/flutter_tools/lib/src/android/gradle_utils.dart index 90b80a385749b..ebf92513ee715 100644 --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart @@ -12,6 +12,7 @@ import '../base/os.dart'; import '../base/platform.dart'; import '../base/utils.dart'; import '../base/version.dart'; +import '../base/version_range.dart'; import '../build_info.dart'; import '../cache.dart'; import '../globals.dart' as globals; @@ -24,33 +25,50 @@ import 'android_sdk.dart'; // In general, Flutter aims to default to the latest version. // However, this currently requires to migrate existing integration tests to the latest supported values. // -// For more information about the latest version, check: -// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle -// https://kotlinlang.org/docs/releases.html#release-details +// Please see the README before changing any of these values. const String templateDefaultGradleVersion = '7.5'; const String templateAndroidGradlePluginVersion = '7.3.0'; -const String templateDefaultGradleVersionForModule = '7.3.0'; +const String templateAndroidGradlePluginVersionForModule = '7.3.0'; const String templateKotlinGradlePluginVersion = '1.7.10'; -// These versions should match the values in Flutter Gradle Plugin (FlutterExtension). -// The Flutter Gradle plugin is only applied to app projects, and modules that are built from source -// using (include_flutter.groovy). -// The remaining projects are: plugins, and modules compiled as AARs. In modules, the ephemeral directory -// `.android` is always regenerated after flutter pub get, so new versions are picked up after a -// Flutter upgrade. +// The Flutter Gradle Plugin is only applied to app projects, and modules that +// are built from source using (`include_flutter.groovy`). The remaining +// projects are: plugins, and modules compiled as AARs. In modules, the +// ephemeral directory `.android` is always regenerated after `flutter pub get`, +// so new versions are picked up after a Flutter upgrade. +// +// Please see the README before changing any of these values. const String compileSdkVersion = '33'; const String minSdkVersion = '19'; const String targetSdkVersion = '33'; const String ndkVersion = '23.1.7779620'; + +// Update these when new major versions of Java are supported by new Gradle +// versions that we support. +// Source of truth: https://docs.gradle.org/current/userguide/compatibility.html +const String oneMajorVersionHigherJavaVersion = '20'; + // Update this when new versions of Gradle come out including minor versions +// and should correspond to the maximum Gradle version we test in CI. // // Supported here means supported by the tooling for // flutter analyze --suggestions and does not imply broader flutter support. -const String _maxKnownAndSupportedGradleVersion = '8.0.2'; +const String maxKnownAndSupportedGradleVersion = '8.0.2'; + // Update this when new versions of AGP come out. +// +// Supported here means tooling is aware of this version's Java <-> AGP +// compatibility. @visibleForTesting -const String maxKnownAgpVersion = '8.1'; +const String maxKnownAndSupportedAgpVersion = '8.1'; + +// Update this when new versions of AGP come out. +const String maxKnownAgpVersion = '8.3'; + +// Oldest documented version of AGP that has a listed minimum +// compatible Java version. +const String oldestDocumentedJavaAgpCompatibilityVersion = '4.2'; // Expected content: // "classpath 'com.android.tools.build:gradle:7.3.0'" @@ -355,13 +373,13 @@ bool validateGradleAndAgp(Logger logger, } // Check highest supported version before checking unknown versions. - if (isWithinVersionRange(agpV, min: '8.0', max: maxKnownAgpVersion)) { + if (isWithinVersionRange(agpV, min: '8.0', max: maxKnownAndSupportedAgpVersion)) { return isWithinVersionRange(gradleV, - min: '8.0', max: _maxKnownAndSupportedGradleVersion); + min: '8.0', max: maxKnownAndSupportedGradleVersion); } // Check if versions are newer than the max known versions. if (isWithinVersionRange(agpV, - min: _maxKnownAndSupportedGradleVersion, max: '100.100')) { + min: maxKnownAndSupportedAgpVersion, max: '100.100')) { // Assume versions we do not know about are valid but log. final bool validGradle = isWithinVersionRange(gradleV, min: '8.0', max: '100.00'); @@ -374,42 +392,42 @@ bool validateGradleAndAgp(Logger logger, // Max agp here is a made up version to contain all 7.4 changes. if (isWithinVersionRange(agpV, min: '7.4', max: '7.5')) { return isWithinVersionRange(gradleV, - min: '7.5', max: _maxKnownAndSupportedGradleVersion); + min: '7.5', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '7.3', max: '7.4', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '7.4', max: _maxKnownAndSupportedGradleVersion); + min: '7.4', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '7.2', max: '7.3', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '7.3.3', max: _maxKnownAndSupportedGradleVersion); + min: '7.3.3', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '7.1', max: '7.2', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '7.2', max: _maxKnownAndSupportedGradleVersion); + min: '7.2', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '7.0', max: '7.1', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '7.0', max: _maxKnownAndSupportedGradleVersion); + min: '7.0', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '4.2.0', max: '7.0', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '6.7.1', max: _maxKnownAndSupportedGradleVersion); + min: '6.7.1', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '4.1.0', max: '4.2.0', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '6.5', max: _maxKnownAndSupportedGradleVersion); + min: '6.5', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange(agpV, min: '4.0.0', max: '4.1.0', inclusiveMax: false)) { return isWithinVersionRange(gradleV, - min: '6.1.1', max: _maxKnownAndSupportedGradleVersion); + min: '6.1.1', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange( agpV, @@ -417,7 +435,7 @@ bool validateGradleAndAgp(Logger logger, max: '3.6.4', )) { return isWithinVersionRange(gradleV, - min: '5.6.4', max: _maxKnownAndSupportedGradleVersion); + min: '5.6.4', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange( agpV, @@ -425,7 +443,7 @@ bool validateGradleAndAgp(Logger logger, max: '3.5.4', )) { return isWithinVersionRange(gradleV, - min: '5.4.1', max: _maxKnownAndSupportedGradleVersion); + min: '5.4.1', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange( agpV, @@ -433,7 +451,7 @@ bool validateGradleAndAgp(Logger logger, max: '3.4.3', )) { return isWithinVersionRange(gradleV, - min: '5.1.1', max: _maxKnownAndSupportedGradleVersion); + min: '5.1.1', max: maxKnownAndSupportedGradleVersion); } if (isWithinVersionRange( agpV, @@ -441,24 +459,20 @@ bool validateGradleAndAgp(Logger logger, max: '3.3.3', )) { return isWithinVersionRange(gradleV, - min: '4.10.1', max: _maxKnownAndSupportedGradleVersion); + min: '4.10.1', max: maxKnownAndSupportedGradleVersion); } logger.printTrace('Unknown Gradle-Agp compatibility, $gradleV, $agpV'); return false; } -// Validate that the [javaVersion] and Gradle version are compatible with -// each other. -// -// Source of truth: -// https://docs.gradle.org/current/userguide/compatibility.html#java -bool validateJavaGradle(Logger logger, +/// Validate that the [javaVersion] and Gradle version are compatible with +/// each other. +/// +/// Source of truth: +/// https://docs.gradle.org/current/userguide/compatibility.html#java +bool validateJavaAndGradle(Logger logger, {required String? javaV, required String? gradleV}) { - // Update these when new major versions of Java are supported by android. - // Supported means Java <-> Gradle support. - const String oneMajorVersionHigherJavaVersion = '20'; - // https://docs.gradle.org/current/userguide/compatibility.html#java const String oldestSupportedJavaVersion = '1.8'; const String oldestDocumentedJavaGradleCompatibility = '2.0'; @@ -492,7 +506,7 @@ bool validateJavaGradle(Logger logger, // Assume versions Java versions newer than [maxSupportedJavaVersion] // required a higher gradle version. final bool validGradle = isWithinVersionRange(gradleV, - min: _maxKnownAndSupportedGradleVersion, max: '100.00'); + min: maxKnownAndSupportedGradleVersion, max: '100.00'); logger.printWarning( 'Newer than known valid Java version ($javaV), gradle ($gradleV).' '\n Treating as valid configuration.'); @@ -500,82 +514,7 @@ bool validateJavaGradle(Logger logger, } // Begin known Java <-> Gradle evaluation. - final List<JavaGradleCompat> compatList = <JavaGradleCompat>[ - JavaGradleCompat( - javaMin: '19', - javaMax: '20', - gradleMin: '7.6', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '18', - javaMax: '19', - gradleMin: '7.5', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '17', - javaMax: '18', - gradleMin: '7.3', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '16', - javaMax: '17', - gradleMin: '7.0', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '15', - javaMax: '16', - gradleMin: '6.7', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '14', - javaMax: '15', - gradleMin: '6.3', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '13', - javaMax: '14', - gradleMin: '6.0', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '12', - javaMax: '13', - gradleMin: '5.4', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '11', - javaMax: '12', - gradleMin: '5.0', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - // 1.11 is a made up java version to cover everything in 1.10.* - JavaGradleCompat( - javaMin: '1.10', - javaMax: '1.11', - gradleMin: '4.7', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '1.9', - javaMax: '1.10', - gradleMin: '4.3', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - JavaGradleCompat( - javaMin: '1.8', - javaMax: '1.9', - gradleMin: '2.0', - gradleMax: _maxKnownAndSupportedGradleVersion, - ), - ]; - for (final JavaGradleCompat data in compatList) { + for (final JavaGradleCompat data in _javaGradleCompatList) { if (isWithinVersionRange(javaV, min: data.javaMin, max: data.javaMax, inclusiveMax: false)) { return isWithinVersionRange(gradleV, min: data.gradleMin, max: data.gradleMax); } @@ -585,6 +524,105 @@ bool validateJavaGradle(Logger logger, return false; } +/// Returns compatibility information for the valid range of Gradle versions for +/// the specified Java version. +/// +/// Returns null when the tooling has not documented the compatibile Gradle +/// versions for the Java version (either the version is too old or too new). If +/// this seems like a mistake, the caller may need to update the +/// [_javaGradleCompatList] detailing Java/Gradle compatibility. +JavaGradleCompat? getValidGradleVersionRangeForJavaVersion( + Logger logger, { + required String javaV, +}) { + for (final JavaGradleCompat data in _javaGradleCompatList) { + if (isWithinVersionRange(javaV, min: data.javaMin, max: data.javaMax, inclusiveMax: false)) { + return data; + } + } + + logger.printTrace('Unable to determine valid Gradle version range for Java version $javaV.'); + return null; +} + +/// Validate that the specified Java and Android Gradle Plugin (AGP) versions are +/// compatible with each other. +/// +/// Returns true when the specified Java and AGP versions are +/// definitely compatible; otherwise, false is assumed by default. In addition, +/// this will return false when either a null Java or AGP version is provided. +/// +/// Source of truth are the AGP release notes: +/// https://developer.android.com/build/releases/gradle-plugin +bool validateJavaAndAgp(Logger logger, + {required String? javaV, required String? agpV}) { + if (javaV == null || agpV == null) { + logger.printTrace( + 'Java version or AGP version unknown ($javaV, $agpV).'); + return false; + } + + // Check if AGP version is too old to perform validation. + if (isWithinVersionRange(agpV, + min: '1.0', max: oldestDocumentedJavaAgpCompatibilityVersion, inclusiveMax: false)) { + logger.printTrace('AGP Version: $agpV is too old to determine Java compatibility.'); + return false; + } + + if (isWithinVersionRange(agpV, + min: maxKnownAndSupportedAgpVersion, max: '100.100', inclusiveMin: false)) { + logger.printTrace('AGP Version: $agpV is too new to determine Java compatibility.'); + return false; + } + + // Begin known Java <-> AGP evaluation. + for (final JavaAgpCompat data in _javaAgpCompatList) { + if (isWithinVersionRange(agpV, min: data.agpMin, max: data.agpMax)) { + return isWithinVersionRange(javaV, min: data.javaMin, max: '100.100'); + } + } + + logger.printTrace('Unknown Java-AGP compatibility $javaV, $agpV'); + return false; + } + + /// Returns compatibility information concerning the minimum AGP + /// version for the specified Java version. + JavaAgpCompat? getMinimumAgpVersionForJavaVersion(Logger logger, + {required String javaV}) { + for (final JavaAgpCompat data in _javaAgpCompatList) { + if (isWithinVersionRange(javaV, min: data.javaMin, max: '100.100')) { + return data; + } + } + + logger.printTrace('Unable to determine minimum AGP version for specified Java version.'); + return null; +} + +/// Returns valid Java range for specified Gradle and AGP verisons. +/// +/// Assumes that gradleV and agpV are compatible versions. +VersionRange getJavaVersionFor({required String gradleV, required String agpV}) { + // Find minimum Java version based on AGP compatibility. + String? minJavaVersion; + for (final JavaAgpCompat data in _javaAgpCompatList) { + if (isWithinVersionRange(agpV, min: data.agpMin, max: data.agpMax)) { + minJavaVersion = data.javaMin; + } + } + + // Find maximum Java version based on Gradle compatibility. + String? maxJavaVersion; + for (final JavaGradleCompat data in _javaGradleCompatList.reversed) { + if (isWithinVersionRange(gradleV, min: data.gradleMin, max: maxKnownAndSupportedGradleVersion)) { + maxJavaVersion = data.javaMax; + } + } + + return VersionRange(minJavaVersion, maxJavaVersion); +} + /// Returns the Gradle version that is required by the given Android Gradle plugin version /// by picking the largest compatible version from /// https://developer.android.com/studio/releases/gradle-plugin#updating-gradle @@ -607,7 +645,7 @@ String getGradleVersionFor(String androidPluginVersion) { GradleForAgp(agpMin: '7.5.0', agpMax: '100.100', minRequiredGradle: '8.0'), // Assume if AGP is newer than this code know about return the highest gradle // version we know about. - GradleForAgp(agpMin: maxKnownAgpVersion, agpMax: maxKnownAgpVersion, minRequiredGradle: _maxKnownAndSupportedGradleVersion), + GradleForAgp(agpMin: maxKnownAgpVersion, agpMax: maxKnownAgpVersion, minRequiredGradle: maxKnownAndSupportedGradleVersion), ]; @@ -617,7 +655,7 @@ String getGradleVersionFor(String androidPluginVersion) { } } if (isWithinVersionRange(androidPluginVersion, min: maxKnownAgpVersion, max: '100.100')) { - return _maxKnownAndSupportedGradleVersion; + return maxKnownAndSupportedGradleVersion; } throwToolExit('Unsupported Android Plugin version: $androidPluginVersion.'); } @@ -708,17 +746,63 @@ void exitWithNoSdkMessage() { } // Data class to hold normal/defined Java <-> Gradle compatability criteria. +// +// The [javaMax] is exclusive in terms of supporting the noted [gradleMin], +// whereas [javaMin] is inclusive. +@immutable class JavaGradleCompat { - JavaGradleCompat({ + const JavaGradleCompat({ required this.javaMin, required this.javaMax, required this.gradleMin, required this.gradleMax, }); + final String javaMin; final String javaMax; final String gradleMin; final String gradleMax; + + @override + bool operator ==(Object other) => + other is JavaGradleCompat && + other.javaMin == javaMin && + other.javaMax == javaMax && + other.gradleMin == gradleMin && + other.gradleMax == gradleMax; + + @override + int get hashCode => Object.hash(javaMin, javaMax, gradleMin, gradleMax); +} + +// Data class to hold defined Java <-> AGP compatibility criteria. +// +// The [agpMin] and [agpMax] are inclusive in terms of having the +// noted [javaMin] and [javaDefault] versions. +@immutable +class JavaAgpCompat { + const JavaAgpCompat({ + required this.javaMin, + required this.javaDefault, + required this.agpMin, + required this.agpMax, + }); + + final String javaMin; + final String javaDefault; + final String agpMin; + final String agpMax; + + @override + bool operator ==(Object other) => + other is JavaAgpCompat && + other.javaMin == javaMin && + other.javaDefault == javaDefault && + other.agpMin == agpMin && + other.agpMax == agpMax; + + @override + int get hashCode => Object.hash(javaMin, javaDefault, agpMin, agpMax); } class GradleForAgp { @@ -727,6 +811,7 @@ class GradleForAgp { required this.agpMax, required this.minRequiredGradle, }); + final String agpMin; final String agpMax; final String minRequiredGradle; @@ -740,3 +825,112 @@ String getGradlewFileName(Platform platform) { return 'gradlew'; } } + +/// List of compatible Java/Gradle versions. +/// +/// Should be updated when a new version of Java is supported by a new version +/// of Gradle, as https://docs.gradle.org/current/userguide/compatibility.html +/// details. +List<JavaGradleCompat> _javaGradleCompatList = const <JavaGradleCompat>[ + JavaGradleCompat( + javaMin: '19', + javaMax: '20', + gradleMin: '7.6', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '18', + javaMax: '19', + gradleMin: '7.5', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '17', + javaMax: '18', + gradleMin: '7.3', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '16', + javaMax: '17', + gradleMin: '7.0', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '15', + javaMax: '16', + gradleMin: '6.7', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '14', + javaMax: '15', + gradleMin: '6.3', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '13', + javaMax: '14', + gradleMin: '6.0', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '12', + javaMax: '13', + gradleMin: '5.4', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '11', + javaMax: '12', + gradleMin: '5.0', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + // 1.11 is a made up java version to cover everything in 1.10.* + JavaGradleCompat( + javaMin: '1.10', + javaMax: '1.11', + gradleMin: '4.7', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '1.9', + javaMax: '1.10', + gradleMin: '4.3', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + JavaGradleCompat( + javaMin: '1.8', + javaMax: '1.9', + gradleMin: '2.0', + gradleMax: maxKnownAndSupportedGradleVersion, + ), + ]; + + // List of compatible Java/AGP versions, where agpMax versions are inclusive. + // + // Should be updated whenever a new version of AGP is released as + // https://developer.android.com/build/releases/gradle-plugin details. + List<JavaAgpCompat> _javaAgpCompatList = const <JavaAgpCompat>[ + JavaAgpCompat( + javaMin: '17', + javaDefault: '17', + agpMin: '8.0', + agpMax: maxKnownAndSupportedAgpVersion, + ), + JavaAgpCompat( + javaMin: '11', + javaDefault: '11', + agpMin: '7.0', + agpMax: '7.4', + ), + JavaAgpCompat( + // You may use JDK 1.7 with AGP 4.2, but we treat 1.8 as the default since + // it is used by default for this AGP version and lower versions of Java + // are deprecated for executing Gradle. + javaMin: '1.8', + javaDefault: '1.8', + agpMin: '4.2', + agpMax: '4.2', + ), + ]; diff --git a/packages/flutter_tools/lib/src/base/version_range.dart b/packages/flutter_tools/lib/src/base/version_range.dart new file mode 100644 index 0000000000000..f5bc6788e24dd --- /dev/null +++ b/packages/flutter_tools/lib/src/base/version_range.dart @@ -0,0 +1,30 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:meta/meta.dart' show immutable; + +/// Data class that represents a range of versions in their String +/// representation. +/// +/// Both the [versionMin] and [versionMax] are inclusive versions, and undefined +/// values represent an unknown minimum/maximum version. +@immutable +class VersionRange{ + const VersionRange( + this.versionMin, + this.versionMax, + ); + + final String? versionMin; + final String? versionMax; + + @override + bool operator ==(Object other) => + other is VersionRange && + other.versionMin == versionMin && + other.versionMax == versionMax; + + @override + int get hashCode => Object.hash(versionMin, versionMax); +} diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 0c6ca3a02cda6..191f92c1c65aa 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:meta/meta.dart'; + import '../android/gradle_utils.dart' as gradle; import '../base/common.dart'; import '../base/context.dart'; @@ -9,6 +11,8 @@ import '../base/file_system.dart'; import '../base/net.dart'; import '../base/terminal.dart'; import '../base/utils.dart'; +import '../base/version.dart'; +import '../base/version_range.dart'; import '../convert.dart'; import '../dart/pub.dart'; import '../features.dart'; @@ -501,6 +505,19 @@ Your $application code is in $relativeAppMain. } } + // Show warning for Java/AGP or Java/Gradle incompatibility if building for + // Android and Java version has been detected. + if (includeAndroid && globals.java?.version != null) { + _printIncompatibleJavaAgpGradleVersionsWarning( + javaVersion: versionToParsableString(globals.java?.version)!, + templateGradleVersion: templateContext['gradleVersion']! as String, + templateAgpVersion: templateContext['agpVersion']! as String, + templateAgpVersionForModule: templateContext['agpVersionForModule']! as String, + projectType: template, + projectDirPath: projectDirPath, + ); + } + return FlutterCommandResult.success(); } @@ -853,3 +870,165 @@ For more details, see: https://flutter.dev/docs/get-started/web '''); } } + +// Prints a warning if the specified Java version conflicts with either the +// template Gradle or AGP version. +// +// Assumes the specified templateGradleVersion and templateAgpVersion are +// compatible, meaning that the Java version may only conflict with one of the +// template Gradle or AGP versions. +void _printIncompatibleJavaAgpGradleVersionsWarning({ + required String javaVersion, + required String templateGradleVersion, + required String templateAgpVersion, + required String templateAgpVersionForModule, + required FlutterProjectType projectType, + required String projectDirPath}) { + // Determine if the Java version specified conflicts with the template Gradle or AGP version. + final bool javaGradleVersionsCompatible = gradle.validateJavaAndGradle(globals.logger, javaV: javaVersion, gradleV: templateGradleVersion); + bool javaAgpVersionsCompatible = gradle.validateJavaAndAgp(globals.logger, javaV: javaVersion, agpV: templateAgpVersion); + String relevantTemplateAgpVersion = templateAgpVersion; + + if (projectType == FlutterProjectType.module && Version.parse(templateAgpVersion)! < Version.parse(templateAgpVersionForModule)!) { + // If a module is being created, make sure to check for Java/AGP compatibility between the highest used version of AGP in the module template. + javaAgpVersionsCompatible = gradle.validateJavaAndAgp(globals.logger, javaV: javaVersion, agpV: templateAgpVersionForModule); + relevantTemplateAgpVersion = templateAgpVersionForModule; + } + + if (javaGradleVersionsCompatible && javaAgpVersionsCompatible) { + return; + } + + // Determine header of warning with recommended fix of re-configuring Java version. + final String incompatibleVersionsAndRecommendedOptionMessage = getIncompatibleJavaGradleAgpMessageHeader(javaGradleVersionsCompatible, templateGradleVersion, relevantTemplateAgpVersion, projectType.cliName); + + if (!javaGradleVersionsCompatible) { + + if (projectType == FlutterProjectType.plugin || projectType == FlutterProjectType.pluginFfi) { + // Only impacted files could be in sample code. + return; + } + + // Gradle template version incompatible with Java version. + final gradle.JavaGradleCompat? validCompatibleGradleVersionRange = gradle.getValidGradleVersionRangeForJavaVersion(globals.logger, javaV: javaVersion); + final String compatibleGradleVersionMessage = validCompatibleGradleVersionRange == null ? '' : ' (compatible Gradle version range: ${validCompatibleGradleVersionRange.gradleMin} - ${validCompatibleGradleVersionRange.gradleMax})'; + + globals.printWarning(''' +$incompatibleVersionsAndRecommendedOptionMessage + +Alternatively, to continue using your configured Java version, update the Gradle +version specified in the following file to a compatible Gradle version$compatibleGradleVersionMessage: +${_getGradleWrapperPropertiesFilePath(projectType, projectDirPath)} + +You may also update the Gradle version used by running +`./gradlew wrapper --gradle-version=<COMPATIBLE_GRADLE_VERSION>`. + +See +https://docs.gradle.org/current/userguide/compatibility.html#java for details +on compatible Java/Gradle versions, and see +https://docs.gradle.org/current/userguide/gradle_wrapper.html#sec:upgrading_wrapper +for more details on using the Gradle Wrapper command to update the Gradle version +used. +''', + emphasis: true + ); + return; + } + + // AGP template version incompatible with Java version. + final gradle.JavaAgpCompat? minimumCompatibleAgpVersion = gradle.getMinimumAgpVersionForJavaVersion(globals.logger, javaV: javaVersion); + final String compatibleAgpVersionMessage = minimumCompatibleAgpVersion == null ? '' : ' (minimum compatible AGP version: ${minimumCompatibleAgpVersion.agpMin})'; + final String gradleBuildFilePaths = ' - ${_getBuildGradleConfigurationFilePaths(projectType, projectDirPath)!.join('\n - ')}'; + + globals.printWarning(''' +$incompatibleVersionsAndRecommendedOptionMessage + +Alternatively, to continue using your configured Java version, update the AGP +version specified in the following files to a compatible AGP +version$compatibleAgpVersionMessage as necessary: +$gradleBuildFilePaths + +See +https://developer.android.com/build/releases/gradle-plugin for details on +compatible Java/AGP versions. +''', + emphasis: true + ); +} + +// Returns incompatible Java/template Gradle/template AGP message header based +// on incompatibility and project type. +@visibleForTesting +String getIncompatibleJavaGradleAgpMessageHeader( + bool javaGradleVersionsCompatible, + String templateGradleVersion, + String templateAgpVersion, + String projectType) { + final String incompatibleDependency = javaGradleVersionsCompatible ? 'Android Gradle Plugin (AGP)' :'Gradle' ; + final String incompatibleDependencyVersion = javaGradleVersionsCompatible ? 'AGP version $templateAgpVersion' : 'Gradle version $templateGradleVersion'; + final VersionRange validJavaRange = gradle.getJavaVersionFor(gradleV: templateGradleVersion, agpV: templateAgpVersion); + // validJavaRange should have non-null verisonMin and versionMax since it based on our template AGP and Gradle versions. + final String validJavaRangeMessage = '(minimum compatible version: ${validJavaRange.versionMin!}, maximum compatible version: ${validJavaRange.versionMax!})'; + + return ''' +The configured version of Java detected may conflict with the $incompatibleDependency version in your new Flutter $projectType. + +[RECOMMENDED] If so, to keep the default $incompatibleDependencyVersion, make +sure to download a compatible Java version +$validJavaRangeMessage. +You may configure this compatible Java version by running: +`flutter config --jdk-dir=<JDK_DIRECTORY>` +Note that this is a global configuration for Flutter. +'''; +} + +// Returns path of the gradle-wrapper.properties file for the specified +// generated project type. +String? _getGradleWrapperPropertiesFilePath(FlutterProjectType projectType, String projectDirPath) { + String gradleWrapperPropertiesFilePath = ''; + switch (projectType) { + case FlutterProjectType.app: + case FlutterProjectType.skeleton: + gradleWrapperPropertiesFilePath = globals.fs.path.join(projectDirPath, 'android/gradle/wrapper/gradle-wrapper.properties'); + case FlutterProjectType.module: + gradleWrapperPropertiesFilePath = globals.fs.path.join(projectDirPath, '.android/gradle/wrapper/gradle-wrapper.properties'); + case FlutterProjectType.plugin: + case FlutterProjectType.pluginFfi: + case FlutterProjectType.package: + case FlutterProjectType.packageFfi: + // TODO(camsim99): Add relevant file path for packageFfi when Android is supported. + // No gradle-wrapper.properties files not part of sample code that + // can be determined. + return null; + } + return gradleWrapperPropertiesFilePath; +} + +// Returns the path(s) of the build.gradle file(s) for the specified generated +// project type. +List<String>? _getBuildGradleConfigurationFilePaths(FlutterProjectType projectType, String projectDirPath) { + final List<String> buildGradleConfigurationFilePaths = <String>[]; + switch (projectType) { + case FlutterProjectType.app: + case FlutterProjectType.skeleton: + case FlutterProjectType.pluginFfi: + buildGradleConfigurationFilePaths.add(globals.fs.path.join(projectDirPath, 'android/build.gradle')); + case FlutterProjectType.module: + const String moduleBuildGradleFilePath = '.android/build.gradle'; + const String moduleAppBuildGradleFlePath = '.android/app/build.gradle'; + const String moduleFlutterBuildGradleFilePath = '.android/Flutter/build.gradle'; + buildGradleConfigurationFilePaths.addAll(<String>[ + globals.fs.path.join(projectDirPath, moduleBuildGradleFilePath), + globals.fs.path.join(projectDirPath, moduleAppBuildGradleFlePath), + globals.fs.path.join(projectDirPath, moduleFlutterBuildGradleFilePath), + ]); + case FlutterProjectType.plugin: + buildGradleConfigurationFilePaths.add(globals.fs.path.join(projectDirPath, 'android/app/build.gradle')); + case FlutterProjectType.package: + case FlutterProjectType.packageFfi: + // TODO(camsim99): Add any relevant file paths for packageFfi when Android is supported. + // No build.gradle file because there is no platform-specific implementation. + return null; + } + return buildGradleConfigurationFilePaths; +} diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index 2ad3f6b7a5d10..293f96bd8d5b9 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -422,9 +422,9 @@ abstract class CreateBase extends FlutterCommand { 'dartSdkVersionBounds': dartSdkVersionBounds, 'implementationTests': implementationTests, 'agpVersion': agpVersion, + 'agpVersionForModule': gradle.templateAndroidGradlePluginVersionForModule, 'kotlinVersion': kotlinVersion, 'gradleVersion': gradleVersion, - 'gradleVersionForModule': gradle.templateDefaultGradleVersionForModule, 'compileSdkVersion': gradle.compileSdkVersion, 'minSdkVersion': gradle.minSdkVersion, 'ndkVersion': gradle.ndkVersion, diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart index 24897e311d357..befd5793e7d52 100644 --- a/packages/flutter_tools/lib/src/project.dart +++ b/packages/flutter_tools/lib/src/project.dart @@ -573,7 +573,7 @@ class AndroidProject extends FlutterProjectPlatform { /// /// This is expected to be called from /// flutter_tools/lib/src/project_validator.dart. - Future<ProjectValidatorResult> validateJavaGradleAgpVersions() async { + Future<ProjectValidatorResult> validateJavaAndGradleAgpVersions() async { // Constructing ProjectValidatorResult happens here and not in // flutter_tools/lib/src/project_validator.dart because of the additional // Complexity of variable status values and error string formatting. @@ -599,7 +599,7 @@ class AndroidProject extends FlutterProjectPlatform { hostAppGradleRoot, globals.logger, globals.processManager); final String? agpVersion = gradle.getAgpVersion(hostAppGradleRoot, globals.logger); - final String? javaVersion = _versionToParsableString(globals.java?.version); + final String? javaVersion = versionToParsableString(globals.java?.version); // Assume valid configuration. String description = validJavaGradleAgpString; @@ -607,7 +607,7 @@ class AndroidProject extends FlutterProjectPlatform { final bool compatibleGradleAgp = gradle.validateGradleAndAgp(globals.logger, gradleV: gradleVersion, agpV: agpVersion); - final bool compatibleJavaGradle = gradle.validateJavaGradle(globals.logger, + final bool compatibleJavaGradle = gradle.validateJavaAndGradle(globals.logger, javaV: javaVersion, gradleV: gradleVersion); // Begin description formatting. @@ -722,9 +722,9 @@ $javaGradleCompatUrl 'androidIdentifier': androidIdentifier, 'androidX': usesAndroidX, 'agpVersion': gradle.templateAndroidGradlePluginVersion, + 'agpVersionForModule': gradle.templateAndroidGradlePluginVersionForModule, 'kotlinVersion': gradle.templateKotlinGradlePluginVersion, 'gradleVersion': gradle.templateDefaultGradleVersion, - 'gradleVersionForModule': gradle.templateDefaultGradleVersionForModule, 'compileSdkVersion': gradle.compileSdkVersion, 'minSdkVersion': gradle.minSdkVersion, 'ndkVersion': gradle.ndkVersion, @@ -923,7 +923,7 @@ class CompatibilityResult { } /// Converts a [Version] to a string that can be parsed by [Version.parse]. -String? _versionToParsableString(Version? version) { +String? versionToParsableString(Version? version) { if (version == null) { return null; } diff --git a/packages/flutter_tools/lib/src/project_validator.dart b/packages/flutter_tools/lib/src/project_validator.dart index 57c3f8dd4fe3a..8e23c8fc52013 100644 --- a/packages/flutter_tools/lib/src/project_validator.dart +++ b/packages/flutter_tools/lib/src/project_validator.dart @@ -227,7 +227,7 @@ class GeneralInfoProjectValidator extends ProjectValidator{ result.add(_materialDesignResult(flutterManifest)); result.add(_pluginValidatorResult(flutterManifest)); } - result.add(await project.android.validateJavaGradleAgpVersions()); + result.add(await project.android.validateJavaAndGradleAgpVersions()); return result; } diff --git a/packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl b/packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl index 616e17728a79e..66fb01795ae11 100644 --- a/packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl +++ b/packages/flutter_tools/templates/module/android/gradle/build.gradle.tmpl @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:{{gradleVersionForModule}}' + classpath 'com.android.tools.build:gradle:{{agpVersionForModule}}' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart index 068bac8a2d0c3..a3230581de189 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:args/command_runner.dart'; +import 'package:flutter_tools/src/android/java.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/create.dart'; @@ -141,7 +142,10 @@ void main() { await runner.run(<String>['create', '--no-pub', '--template=package_ffi', 'testy6']); expect((await command.usageValues).commandCreateProjectType, 'package_ffi'); - })); + }), + overrides: <Type, Generator>{ + Java: () => FakeJava(), + }); testUsingContext('set iOS host language type as usage value', () => testbed.run(() async { final CreateCommand command = CreateCommand(); @@ -160,8 +164,10 @@ void main() { 'testy', ]); expect((await command.usageValues).commandCreateIosLanguage, 'objc'); - - })); + }), + overrides: <Type, Generator>{ + Java: () => FakeJava(), + }); testUsingContext('set Android host language type as usage value', () => testbed.run(() async { final CreateCommand command = CreateCommand(); @@ -178,7 +184,9 @@ void main() { 'testy', ]); expect((await command.usageValues).commandCreateAndroidLanguage, 'java'); - })); + }), overrides: <Type, Generator>{ + Java: () => FakeJava(), + }); testUsingContext('create --offline', () => testbed.run(() async { final CreateCommand command = CreateCommand(); @@ -189,6 +197,7 @@ void main() { expect(command.argParser.options.containsKey('offline'), true); expect(command.shouldUpdateCache, true); }, overrides: <Type, Generator>{ + Java: () => null, Pub: () => fakePub, })); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart index a88a3ad534cf4..8fdbac1efc4e7 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart @@ -6,6 +6,7 @@ import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/android/android_studio.dart'; +import 'package:flutter_tools/src/android/java.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/build_info.dart'; @@ -295,6 +296,7 @@ void main() { }, overrides: <Type, Generator>{ FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), + Java: () => null, ProcessManager: () => processManager, FeatureFlags: () => TestFeatureFlags(isIOSEnabled: false), AndroidStudio: () => FakeAndroidStudio(), diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart index 515c3a7d9f8d9..8e82ff48702fc 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart @@ -6,6 +6,7 @@ import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/android/android_studio.dart'; +import 'package:flutter_tools/src/android/java.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/version.dart'; @@ -143,6 +144,7 @@ void main() { }, overrides: <Type, Generator>{ AndroidSdk: () => null, + Java: () => null, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), ProcessManager: () => processManager, AndroidStudio: () => FakeAndroidStudio(), @@ -174,6 +176,7 @@ void main() { }, overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, + Java: () => null, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), ProcessManager: () => processManager, AndroidStudio: () => FakeAndroidStudio(), @@ -205,6 +208,7 @@ void main() { }, overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, + Java: () => null, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), ProcessManager: () => processManager, AndroidStudio: () => FakeAndroidStudio(), @@ -236,6 +240,7 @@ void main() { }, overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, + Java: () => null, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), ProcessManager: () => processManager, AndroidStudio: () => FakeAndroidStudio(), @@ -269,6 +274,7 @@ void main() { }, overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, + Java: () => null, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), ProcessManager: () => processManager, AndroidStudio: () => FakeAndroidStudio(), @@ -320,6 +326,7 @@ void main() { }, overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, + Java: () => null, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), ProcessManager: () => processManager, Usage: () => testUsage, @@ -374,6 +381,7 @@ void main() { overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), + Java: () => null, ProcessManager: () => processManager, Usage: () => testUsage, AndroidStudio: () => FakeAndroidStudio(), @@ -420,6 +428,7 @@ void main() { overrides: <Type, Generator>{ AndroidSdk: () => mockAndroidSdk, FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir), + Java: () => null, ProcessManager: () => processManager, Usage: () => testUsage, AndroidStudio: () => FakeAndroidStudio(), diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index b9d0ed6d2d6ef..0dee658224120 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -8,18 +8,22 @@ import 'dart:io' as io; import 'package:args/command_runner.dart'; import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/android/gradle_utils.dart' show templateAndroidGradlePluginVersion, templateAndroidGradlePluginVersionForModule, templateDefaultGradleVersion; +import 'package:flutter_tools/src/android/java.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/net.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/version.dart' as software; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/create.dart'; import 'package:flutter_tools/src/commands/create_base.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/flutter_project_metadata.dart' show FlutterProjectType; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/version.dart'; @@ -40,6 +44,8 @@ const String _kNoPlatformsMessage = "You've created a plugin project that doesn' const String frameworkRevision = '12345678'; const String frameworkChannel = 'omega'; const String _kDisabledPlatformRequestedMessage = 'currently not supported on your local environment.'; +const String _kIncompatibleJavaVersionMessage = 'The configured version of Java detected may conflict with the'; +final String _kIncompatibleAgpVersionForModule = Version.parse(templateAndroidGradlePluginVersion) < Version.parse(templateAndroidGradlePluginVersionForModule) ? templateAndroidGradlePluginVersionForModule : templateAndroidGradlePluginVersion; // This needs to be created from the local platform due to re-entrant flutter calls made in this test. FakePlatform _kNoColorTerminalPlatform() => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false; @@ -1417,6 +1423,7 @@ void main() { expect(xcodeProject, contains('DEVELOPMENT_TEAM = 3333CCCC33;')); }, overrides: <Type, Generator>{ FlutterVersion: () => fakeFlutterVersion, + Java: () => null, Platform: _kNoColorTerminalMacOSPlatform, ProcessManager: () => fakeProcessManager, }); @@ -3403,6 +3410,228 @@ void main() { Logger: () => logger, }); + testUsingContext('should not show warning for incompatible Java/template Gradle versions when Java version not found', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + await runner.run(<String>['create', '--no-pub', '--platforms=android', projectDir.path]); + + expect(logger.warningText, isNot(contains(_kIncompatibleJavaVersionMessage))); + }, overrides: <Type, Generator>{ + Java: () => null, + Logger: () => logger, + }); + + testUsingContext('should not show warning for incompatible Java/template Gradle versions when created project type is irrelevant', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + // Test not creating a project for Android. + await runner.run(<String>['create', '--no-pub', '--platforms=ios,windows,macos,linux', projectDir.path]); + tryToDelete(projectDir); + // Test creating a package (Dart-only code). + await runner.run(<String>['create', '--no-pub', '--template=package', projectDir.path]); + tryToDelete(projectDir); + // Test creating project types without configured Gradle versions. + await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]); + tryToDelete(projectDir); + await runner.run(<String>['create', '--no-pub', '--template=plugin_ffi', projectDir.path]); + + expect(logger.warningText, isNot(contains(getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, templateAndroidGradlePluginVersion, 'app')))); + expect(logger.warningText, isNot(contains(getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, templateAndroidGradlePluginVersion, 'package')))); + expect(logger.warningText, isNot(contains(getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, templateAndroidGradlePluginVersion, 'plugin')))); + expect(logger.warningText, isNot(contains(getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, templateAndroidGradlePluginVersion, 'pluginFfi')))); + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(1000, 0, 0, '1000.0.0')), // Too high a version for template Gradle versions. + Logger: () => logger, + }); + + testUsingContext('should not show warning for incompatible Java/template AGP versions when project type unrelated', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + // Test not creating a project for Android. + await runner.run(<String>['create', '--no-pub', '--platforms=ios,windows,macos,linux', projectDir.path]); + tryToDelete(projectDir); + // Test creating a package (Dart-only code). + await runner.run(<String>['create', '--no-pub', '--template=package', projectDir.path]); + + expect(logger.warningText, isNot(contains(getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, templateAndroidGradlePluginVersion, 'app')))); + expect(logger.warningText, isNot(contains(getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, templateAndroidGradlePluginVersion, 'package')))); + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(0, 0, 0, '0.0.0')), // Too low a version for template AGP versions. + Logger: () => logger, + }); + + testUsingContext('should show warning for incompatible Java/template Gradle versions when detected', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<FlutterProjectType> relevantProjectTypes = <FlutterProjectType>[FlutterProjectType.app, FlutterProjectType.skeleton, FlutterProjectType.module]; + + for (final FlutterProjectType projectType in relevantProjectTypes) { + final String relevantAgpVersion = projectType == FlutterProjectType.module ? _kIncompatibleAgpVersionForModule : templateAndroidGradlePluginVersion; + final String expectedMessage = getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + final String unexpectedMessage = getIncompatibleJavaGradleAgpMessageHeader(true, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + + await runner.run(<String>['create', '--no-pub', '--template=${projectType.cliName}', if (projectType != FlutterProjectType.module) '--platforms=android', projectDir.path]); + + // Check components of expected header warning message are printed. + expect(logger.warningText, contains(expectedMessage)); + expect(logger.warningText, isNot(contains(unexpectedMessage))); + expect(logger.warningText, contains('./gradlew wrapper --gradle-version=<COMPATIBLE_GRADLE_VERSION>')); + expect(logger.warningText, contains('https://docs.gradle.org/current/userguide/compatibility.html#java')); + + // Check expected file for updating Gradle version is present. + if (projectType == FlutterProjectType.app || projectType == FlutterProjectType.skeleton) { + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, 'android/gradle/wrapper/gradle-wrapper.properties'))); + } + else { + // Project type is module. + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, '.android/gradle/wrapper/gradle-wrapper.properties'))); + } + + // Cleanup to reuse projectDir and logger checks. + tryToDelete(projectDir); + logger.clear(); + } + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(500, 0, 0, '500.0.0')), // Too high a version for template Gradle versions. + Logger: () => logger, + }); + + testUsingContext('should show warning for incompatible Java/template AGP versions when detected', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<FlutterProjectType> relevantProjectTypes = <FlutterProjectType>[FlutterProjectType.app, FlutterProjectType.skeleton, FlutterProjectType.pluginFfi, FlutterProjectType.module, FlutterProjectType.plugin]; + + for (final FlutterProjectType projectType in relevantProjectTypes) { + final String relevantAgpVersion = projectType == FlutterProjectType.module ? _kIncompatibleAgpVersionForModule : templateAndroidGradlePluginVersion; + final String expectedMessage = getIncompatibleJavaGradleAgpMessageHeader(true, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + final String unexpectedMessage = getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + + await runner.run(<String>['create', '--no-pub', '--template=${projectType.cliName}', if (projectType != FlutterProjectType.module) '--platforms=android', projectDir.path]); + + // Check components of expected header warning message are printed. + expect(logger.warningText, contains(expectedMessage)); + expect(logger.warningText, isNot(contains(unexpectedMessage))); + expect(logger.warningText, contains('https://developer.android.com/build/releases/gradle-plugin')); + + // Check expected file(s) for updating AGP version is/are present. + if (projectType == FlutterProjectType.app || projectType == FlutterProjectType.skeleton || projectType == FlutterProjectType.pluginFfi) { + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, 'android/build.gradle'))); + } + else if (projectType == FlutterProjectType.plugin) { + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, 'android/app/build.gradle'))); + } + else { + // Project type is module. + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, '.android/build.gradle'))); + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, '.android/app/build.gradle'))); + expect(logger.warningText, contains(globals.fs.path.join(projectDir.path, '.android/Flutter/build.gradle'))); + } + + // Cleanup to reuse projectDir and logger checks. + tryToDelete(projectDir); + logger.clear(); + } + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(1, 8, 0, '1.8.0')), // Too low a version for template AGP versions. + Logger: () => logger, + }); + + // The Java versions configured in the following tests will need updates as more Java versions are supported by AGP/Gradle: + + testUsingContext('should not show warning for incompatible Java/template AGP/Gradle versions when not detected', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<FlutterProjectType> relevantProjectTypes = <FlutterProjectType>[FlutterProjectType.app, FlutterProjectType.skeleton, FlutterProjectType.pluginFfi, FlutterProjectType.module, FlutterProjectType.plugin]; + + for (final FlutterProjectType projectType in relevantProjectTypes) { + final String relevantAgpVersion = projectType == FlutterProjectType.module ? _kIncompatibleAgpVersionForModule : templateAndroidGradlePluginVersion; + final String unexpectedIncompatibleAgpMessage = getIncompatibleJavaGradleAgpMessageHeader(true, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + final String unexpectedIncompatibleGradleMessage = getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + + await runner.run(<String>['create', '--no-pub', '--template=${projectType.cliName}', if (projectType != FlutterProjectType.module) '--platforms=android', projectDir.path]); + + // We do not expect warnings for incompatible Java/template AGP versions if they are in fact, compatible. + expect(logger.warningText, isNot(contains(unexpectedIncompatibleAgpMessage))); + expect(logger.warningText, isNot(contains(unexpectedIncompatibleGradleMessage))); + + // Cleanup to reuse projectDir and logger checks. + tryToDelete(projectDir); + logger.clear(); + } + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(14, 0, 0, '14.0.0')), // Middle compatible Java version with current template AGP/Gradle versions. + Logger: () => logger, + }); + + testUsingContext('should not show warning for incompatible Java/template AGP/Gradle versions when not detected -- maximum compatible Java version', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<FlutterProjectType> relevantProjectTypes = <FlutterProjectType>[FlutterProjectType.app, FlutterProjectType.skeleton, FlutterProjectType.pluginFfi, FlutterProjectType.module, FlutterProjectType.plugin]; + + for (final FlutterProjectType projectType in relevantProjectTypes) { + final String relevantAgpVersion = projectType == FlutterProjectType.module ? _kIncompatibleAgpVersionForModule : templateAndroidGradlePluginVersion; + final String unexpectedIncompatibleAgpMessage = getIncompatibleJavaGradleAgpMessageHeader(true, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + final String unexpectedIncompatibleGradleMessage = getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + + await runner.run(<String>['create', '--no-pub', '--template=${projectType.cliName}', if (projectType != FlutterProjectType.module) '--platforms=android', projectDir.path]); + + // We do not expect warnings for incompatible Java/template AGP versions if they are in fact, compatible. + expect(logger.warningText, isNot(contains(unexpectedIncompatibleAgpMessage))); + expect(logger.warningText, isNot(contains(unexpectedIncompatibleGradleMessage))); + + // Cleanup to reuse projectDir and logger checks. + tryToDelete(projectDir); + logger.clear(); + } + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(17, 0, 0, '18.0.0')), // Maximum compatible Java version with current template AGP/Gradle versions. + Logger: () => logger, + }); + + testUsingContext('should not show warning for incompatible Java/template AGP/Gradle versions when not detected -- minimum compatible Java version', () async { + Cache.flutterRoot = '../..'; + + final CreateCommand command = CreateCommand(); + final CommandRunner<void> runner = createTestCommandRunner(command); + final List<FlutterProjectType> relevantProjectTypes = <FlutterProjectType>[FlutterProjectType.app, FlutterProjectType.skeleton, FlutterProjectType.pluginFfi, FlutterProjectType.module, FlutterProjectType.plugin]; + + for (final FlutterProjectType projectType in relevantProjectTypes) { + final String relevantAgpVersion = projectType == FlutterProjectType.module ? _kIncompatibleAgpVersionForModule : templateAndroidGradlePluginVersion; + final String unexpectedIncompatibleAgpMessage = getIncompatibleJavaGradleAgpMessageHeader(true, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + final String unexpectedIncompatibleGradleMessage = getIncompatibleJavaGradleAgpMessageHeader(false, templateDefaultGradleVersion, relevantAgpVersion, projectType.cliName); + + await runner.run(<String>['create', '--no-pub', '--template=${projectType.cliName}', if (projectType != FlutterProjectType.module) '--platforms=android', projectDir.path]); + + // We do not expect warnings for incompatible Java/template AGP versions if they are in fact, compatible. + expect(logger.warningText, isNot(contains(unexpectedIncompatibleAgpMessage))); + expect(logger.warningText, isNot(contains(unexpectedIncompatibleGradleMessage))); + + // Cleanup to reuse projectDir and logger checks. + tryToDelete(projectDir); + logger.clear(); + } + }, overrides: <Type, Generator>{ + Java: () => FakeJava(version: const software.Version.withText(11, 0, 0, '11.0.0')), // Minimum compatible Java version with current template AGP/Gradle versions. + Logger: () => logger, + }); + testUsingContext('Does not double quote description in index.html on web', () async { await _createProject( projectDir, diff --git a/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart index 9aa482e5f3ef5..e789afaa8d02b 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_utils_test.dart @@ -7,6 +7,7 @@ import 'package:flutter_tools/src/android/gradle_utils.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/base/version_range.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/project.dart'; import '../../src/common.dart'; @@ -470,16 +471,20 @@ allprojects { group('validates gradle/agp versions', () { final List<GradleAgpTestData> testData = <GradleAgpTestData>[ - // Values too new *these need to update* when + // Values too new *these need to be updated* when // max known gradle and max known agp versions are updated: // Newer tools version supports max gradle version. GradleAgpTestData(true, agpVersion: '8.2', gradleVersion: '8.0'), - // Newer tools version does not even meet current gradle version requiremnts. + // Newer tools version does not even meet current gradle version requirements. GradleAgpTestData(false, agpVersion: '8.2', gradleVersion: '7.3'), // Newer tools version requires newer gradle version. GradleAgpTestData(true, agpVersion: '8.3', gradleVersion: '8.1'), - // Minimims as defined in + // Template versions of Gradle/AGP. + GradleAgpTestData(true, agpVersion: templateAndroidGradlePluginVersion, gradleVersion: templateDefaultGradleVersion), + GradleAgpTestData(true, agpVersion: templateAndroidGradlePluginVersionForModule, gradleVersion: templateDefaultGradleVersion), + + // Minimums as defined in // https://developer.android.com/studio/releases/gradle-plugin#updating-gradle GradleAgpTestData(true, agpVersion: '8.1', gradleVersion: '8.0'), GradleAgpTestData(true, agpVersion: '8.0', gradleVersion: '8.0'), @@ -577,16 +582,15 @@ allprojects { group('validates java/gradle versions', () { final List<JavaGradleTestData> testData = <JavaGradleTestData>[ - // Values too new *these need to update* when + // Values too new *these need to be updated* when // max supported java and max known gradle versions are updated: // Newer tools version does not even meet current gradle version requiremnts. JavaGradleTestData(false, javaVersion: '20', gradleVersion: '7.5'), // Newer tools version requires newer gradle version. JavaGradleTestData(true, javaVersion: '20', gradleVersion: '8.1'), - // Max known unsupported java version. - JavaGradleTestData(true, javaVersion: '24', gradleVersion: '8.1'), - - // Minimims as defined in + // Max known unsupported Java version. + JavaGradleTestData(true, javaVersion: '24', gradleVersion: maxKnownAndSupportedGradleVersion), + // Minimums as defined in // https://docs.gradle.org/current/userguide/compatibility.html#java JavaGradleTestData(true, javaVersion: '19', gradleVersion: '7.6'), JavaGradleTestData(true, javaVersion: '18', gradleVersion: '7.5'), @@ -600,7 +604,7 @@ allprojects { JavaGradleTestData(true, javaVersion: '1.10', gradleVersion: '4.7'), JavaGradleTestData(true, javaVersion: '1.9', gradleVersion: '4.3'), JavaGradleTestData(true, javaVersion: '1.8', gradleVersion: '2.0'), - // Gradle too old for java version. + // Gradle too old for Java version. JavaGradleTestData(false, javaVersion: '19', gradleVersion: '6.7'), JavaGradleTestData(false, javaVersion: '11', gradleVersion: '4.10.1'), JavaGradleTestData(false, javaVersion: '1.9', gradleVersion: '4.1'), @@ -642,7 +646,7 @@ allprojects { testWithoutContext( '(Java, gradle): (${data.javaVersion}, ${data.gradleVersion})', () { expect( - validateJavaGradle( + validateJavaAndGradle( BufferLogger.test(), javaV: data.javaVersion, gradleV: data.gradleVersion, @@ -653,6 +657,314 @@ allprojects { } }); }); + + group('validates java/AGP versions', () { + final List<JavaAgpTestData> testData = <JavaAgpTestData>[ + // Strictly too old Java versions for known AGP versions. + JavaAgpTestData(false, javaVersion: '1.6', agpVersion: maxKnownAgpVersion), + JavaAgpTestData(false, javaVersion: '1.6', agpVersion: maxKnownAndSupportedAgpVersion), + JavaAgpTestData(false, javaVersion: '1.6', agpVersion: '4.2'), + // Strictly too old AGP versions. + JavaAgpTestData(false, javaVersion: '1.8', agpVersion: '1.0'), + JavaAgpTestData(false, javaVersion: '1.8', agpVersion: '4.1'), + JavaAgpTestData(false, javaVersion: '1.8', agpVersion: '2.3'), + // Strictly too new Java versions for defined AGP versions. + JavaAgpTestData(true, javaVersion: '18', agpVersion: '8.1'), + JavaAgpTestData(true, javaVersion: '18', agpVersion: '7.4'), + JavaAgpTestData(true, javaVersion: '18', agpVersion: '4.2'), + // Strictly too new AGP versions. + // *The tests that follow need to be updated* when max supported AGP versions are updated: + JavaAgpTestData(false, javaVersion: '24', agpVersion: '8.3'), + JavaAgpTestData(false, javaVersion: '20', agpVersion: '8.3'), + JavaAgpTestData(false, javaVersion: '17', agpVersion: '8.3'), + // Java 17 & patch versions compatibility cases + // *The tests that follow need to be updated* when maxKnownAndSupportedAgpVersion is + // updated: + JavaAgpTestData(false, javaVersion: '17', agpVersion: '8.2'), + JavaAgpTestData(true, javaVersion: '17', agpVersion: maxKnownAndSupportedAgpVersion), + JavaAgpTestData(true, javaVersion: '17', agpVersion: '8.1'), + JavaAgpTestData(true, javaVersion: '17', agpVersion: '8.0'), + JavaAgpTestData(true, javaVersion: '17', agpVersion: '7.4'), + JavaAgpTestData(false, javaVersion: '17.0.3', agpVersion: '8.2'), + JavaAgpTestData(true, javaVersion: '17.0.3', agpVersion: maxKnownAndSupportedAgpVersion), + JavaAgpTestData(true, javaVersion: '17.0.3', agpVersion: '8.1'), + JavaAgpTestData(true, javaVersion: '17.0.3', agpVersion: '8.0'), + JavaAgpTestData(true, javaVersion: '17.0.3', agpVersion: '7.4'), + // Java 11 & patch versions compatibility cases + JavaAgpTestData(false, javaVersion: '11', agpVersion: '8.0'), + JavaAgpTestData(true, javaVersion: '11', agpVersion: '7.4'), + JavaAgpTestData(true, javaVersion: '11', agpVersion: '7.2'), + JavaAgpTestData(true, javaVersion: '11', agpVersion: '7.0'), + JavaAgpTestData(true, javaVersion: '11', agpVersion: '4.2'), + JavaAgpTestData(false, javaVersion: '11.0.18', agpVersion: '8.0'), + JavaAgpTestData(true, javaVersion: '11.0.18', agpVersion: '7.4'), + JavaAgpTestData(true, javaVersion: '11.0.18', agpVersion: '7.2'), + JavaAgpTestData(true, javaVersion: '11.0.18', agpVersion: '7.0'), + JavaAgpTestData(true, javaVersion: '11.0.18', agpVersion: '4.2'), + // Java 8 compatibility cases + JavaAgpTestData(false, javaVersion: '1.8', agpVersion: '7.0'), + JavaAgpTestData(true, javaVersion: '1.8', agpVersion: oldestDocumentedJavaAgpCompatibilityVersion), // agpVersion = 4.2 + JavaAgpTestData(false, javaVersion: '1.8', agpVersion: '4.1'), + // Null value cases + // ignore: avoid_redundant_argument_values + JavaAgpTestData(false, javaVersion: null, agpVersion: '4.2'), + // ignore: avoid_redundant_argument_values + JavaAgpTestData(false, javaVersion: '1.8', agpVersion: null), + // ignore: avoid_redundant_argument_values + JavaAgpTestData(false, javaVersion: null, agpVersion: null), + ]; + + for (final JavaAgpTestData data in testData) { + testWithoutContext( + '(Java, agp): (${data.javaVersion}, ${data.agpVersion})', () { + expect( + validateJavaAndAgp( + BufferLogger.test(), + javaV: data.javaVersion, + agpV: data.agpVersion, + ), + data.validPair ? isTrue : isFalse, + reason: 'J: ${data.javaVersion}, G: ${data.agpVersion}'); + }); + } + }); + + group('detecting valid Gradle/AGP versions for given Java version and vice versa', () { + testWithoutContext('getValidGradleVersionRangeForJavaVersion returns valid Gradle version range for Java version', () { + final Logger testLogger = BufferLogger.test(); + // Java version too high. + expect(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: oneMajorVersionHigherJavaVersion), isNull); + // Maximum known Java version. + // *The test case that follows needs to be updated* when higher versions of Java are supported: + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '20'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '20.0.2')), + isNull)); + // Known supported Java versions. + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '19'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '19.0.2')), + equals( + const JavaGradleCompat( + javaMin: '19', + javaMax: '20', + gradleMin: '7.6', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '18'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '18.0.2')), + equals( + const JavaGradleCompat( + javaMin: '18', + javaMax: '19', + gradleMin: '7.5', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '17'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '17.0.2')), + equals( + const JavaGradleCompat( + javaMin: '17', + javaMax: '18', + gradleMin: '7.3', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '16'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '16.0.2')), + equals( + const JavaGradleCompat( + javaMin: '16', + javaMax: '17', + gradleMin: '7.0', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '15'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '15.0.2')), + equals( + const JavaGradleCompat( + javaMin: '15', + javaMax: '16', + gradleMin: '6.7', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '14'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '14.0.2')), + equals( + const JavaGradleCompat( + javaMin: '14', + javaMax: '15', + gradleMin: '6.3', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '13'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '13.0.2')), + equals( + const JavaGradleCompat( + javaMin: '13', + javaMax: '14', + gradleMin: '6.0', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '12'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '12.0.2')), + equals( + const JavaGradleCompat( + javaMin: '12', + javaMax: '13', + gradleMin: '5.4', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '11'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '11.0.2')), + equals( + const JavaGradleCompat( + javaMin: '11', + javaMax: '12', + gradleMin: '5.0', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.10'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.10.2')), + equals( + const JavaGradleCompat( + javaMin: '1.10', + javaMax: '1.11', + gradleMin: '4.7', + gradleMax: maxKnownAndSupportedGradleVersion)))); + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.9'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.9.2')), + equals( + const JavaGradleCompat( + javaMin: '1.9', + javaMax: '1.10', + gradleMin: '4.3', + gradleMax: maxKnownAndSupportedGradleVersion)))); + // Java 1.8 -- return oldest documented compatibility info + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.8'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.8.2')), + equals( + const JavaGradleCompat( + javaMin: '1.8', + javaMax: '1.9', + gradleMin: '2.0', + gradleMax: maxKnownAndSupportedGradleVersion)))); + // Java version too low. + expect( + getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.7'), + allOf( + equals(getValidGradleVersionRangeForJavaVersion(testLogger, javaV: '1.7.2')), + isNull)); + }); + + testWithoutContext('getMinimumAgpVersionForJavaVersion returns minimum AGP version for Java version', () { + final Logger testLogger = BufferLogger.test(); + // Maximum known Java version. + // *The test case that follows needs to be updated* as higher versions of AGP are supported: + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: oneMajorVersionHigherJavaVersion), + equals( + const JavaAgpCompat( + javaMin: '17', + javaDefault: '17', + agpMin: '8.0', + agpMax: '8.1'))); + // Known Java versions. + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: '17'), + allOf( + equals(getMinimumAgpVersionForJavaVersion(testLogger, javaV: '17.0.2')), + equals( + const JavaAgpCompat( + javaMin: '17', + javaDefault: '17', + agpMin: '8.0', + agpMax: '8.1')))); + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: '15'), + allOf( + equals(getMinimumAgpVersionForJavaVersion(testLogger, javaV: '15.0.2')), + equals( + const JavaAgpCompat( + javaMin: '11', + javaDefault: '11', + agpMin: '7.0', + agpMax: '7.4')))); + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: '11'), + allOf( + equals(getMinimumAgpVersionForJavaVersion(testLogger, javaV: '11.0.2')), + equals( + const JavaAgpCompat( + javaMin: '11', + javaDefault: '11', + agpMin: '7.0', + agpMax: '7.4')))); + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: '1.9'), + allOf( + equals(getMinimumAgpVersionForJavaVersion(testLogger, javaV: '1.9.2')), + equals( + const JavaAgpCompat( + javaMin: '1.8', + javaDefault: '1.8', + agpMin: '4.2', + agpMax: '4.2')))); + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: '1.8'), + allOf( + equals(getMinimumAgpVersionForJavaVersion(testLogger, javaV: '1.8.2')), + equals( + const JavaAgpCompat( + javaMin: '1.8', + javaDefault: '1.8', + agpMin: '4.2', + agpMax: '4.2')))); + // Java version too low. + expect( + getMinimumAgpVersionForJavaVersion(testLogger, javaV: '1.7'), + allOf( + equals(getMinimumAgpVersionForJavaVersion(testLogger, javaV: '1.7.2')), + isNull)); + }); + + testWithoutContext('getJavaVersionFor returns expected Java version range', () { + // Strictly too old Gradle and AGP versions. + expect(getJavaVersionFor(gradleV: '1.9', agpV: '4.1'), equals(const VersionRange(null, null))); + // Strictly too old Gradle or AGP version. + expect(getJavaVersionFor(gradleV: '1.9', agpV: '4.2'), equals(const VersionRange('1.8', null))); + expect(getJavaVersionFor(gradleV: '2.0', agpV: '4.1'), equals(const VersionRange(null, '1.9'))); + // Strictly too new Gradle and AGP versions. + expect(getJavaVersionFor(gradleV: '8.1', agpV: '8.2'), equals(const VersionRange(null, null))); + // Strictly too new Gradle version and maximum version of AGP. + //*This test case will need its expected Java range updated when a new version of AGP is supported.* + expect(getJavaVersionFor(gradleV: '8.1', agpV: maxKnownAndSupportedAgpVersion), equals(const VersionRange('17', null))); + // Strictly too new AGP version and maximum version of Gradle. + //*This test case will need its expected Java range updated when a new version of Gradle is supported.* + expect(getJavaVersionFor(gradleV: maxKnownAndSupportedGradleVersion, agpV: '8.2'), equals(const VersionRange(null, '20'))); + // Tests with a known compatible Gradle/AGP version pair. + expect(getJavaVersionFor(gradleV: '7.0', agpV: '7.2'), equals(const VersionRange('11', '17'))); + expect(getJavaVersionFor(gradleV: '7.1', agpV: '7.2'), equals(const VersionRange('11', '17'))); + expect(getJavaVersionFor(gradleV: '7.2.2', agpV: '7.2'), equals(const VersionRange('11', '17'))); + expect(getJavaVersionFor(gradleV: '7.1', agpV: '7.0'), equals(const VersionRange('11', '17'))); + expect(getJavaVersionFor(gradleV: '7.1', agpV: '7.2'), equals(const VersionRange('11', '17'))); + expect(getJavaVersionFor(gradleV: '7.1', agpV: '7.4'), equals(const VersionRange('11', '17'))); + }); + }); } class GradleAgpTestData { @@ -669,6 +981,13 @@ class JavaGradleTestData { final bool validPair; } +class JavaAgpTestData { + JavaAgpTestData(this.validPair, {this.javaVersion, this.agpVersion}); + final String? agpVersion; + final String? javaVersion; + final bool validPair; +} + final Platform windowsPlatform = FakePlatform( operatingSystem: 'windows', environment: <String, String>{ From 52969a0909b06d176f1f24ae561438117b1c5d5a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 12:13:25 -0400 Subject: [PATCH 1364/1547] Roll Flutter Engine from 5f82fc2f6f24 to 6f256257b79f (1 revision) (#135147) https://github.com/flutter/engine/compare/5f82fc2f6f24...6f256257b79f 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from fd317812bd27 to 56ce5bb201c6 (4 revisions) (flutter/engine#46096) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b72f57bac4cb9..9352f6bb6edfa 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5f82fc2f6f241f0beef0baf1d5336192b5c22a9a +6f256257b79fd4a3927a7c429db4c962f1d414b3 From 6e5134b0673eabe85fbd898b876185daf5a1b110 Mon Sep 17 00:00:00 2001 From: Greg Spencer <gspencergoog@users.noreply.github.com> Date: Wed, 20 Sep 2023 09:43:01 -0700 Subject: [PATCH 1365/1547] Remove 'must be non-null' and 'must not be null' comments in widgets library (#134992) ## Description This removes all of the comments that are of the form "so-and-so (must not be null|can ?not be null|must be non-null)" from the cases where those values are defines as non-nullable values. This PR removes them from the widgets library. This was done by hand, since it really didn't lend itself to scripting, so it needs to be more than just spot-checked, I think. I was careful to leave any comment that referred to parameters that were nullable, but I may have missed some. In addition to being no longer relevant after null safety has been made the default, these comments were largely fragile, in that it was easy for them to get out of date, and not be accurate anymore anyhow. This did create a number of constructor comments which basically say "Creates a [Foo].", but I don't really know how to avoid that in a large scale change, since there's not much you can really say in a lot of cases. I think we might consider some leniency for constructors to the "Comment must be meaningful" style guidance (which we de facto have already, since there are a bunch of these). ## Related PRs - https://github.com/flutter/flutter/pull/134984 - https://github.com/flutter/flutter/pull/134991 - https://github.com/flutter/flutter/pull/134993 - https://github.com/flutter/flutter/pull/134994 ## Tests - Documentation only change. --- packages/flutter/lib/src/widgets/actions.dart | 14 -- .../lib/src/widgets/animated_cross_fade.dart | 2 - .../lib/src/widgets/animated_size.dart | 4 +- .../lib/src/widgets/animated_switcher.dart | 3 - packages/flutter/lib/src/widgets/app.dart | 2 - packages/flutter/lib/src/widgets/async.dart | 4 - .../flutter/lib/src/widgets/autofill.dart | 2 - .../lib/src/widgets/automatic_keep_alive.dart | 2 - packages/flutter/lib/src/widgets/banner.dart | 5 - packages/flutter/lib/src/widgets/basic.dart | 149 +++++------------- .../flutter/lib/src/widgets/color_filter.dart | 2 - .../flutter/lib/src/widgets/container.dart | 3 +- .../lib/src/widgets/decorated_sliver.dart | 3 +- .../flutter/lib/src/widgets/dismissible.dart | 12 +- .../src/widgets/disposable_build_context.dart | 2 +- .../flutter/lib/src/widgets/drag_target.dart | 10 +- .../widgets/draggable_scrollable_sheet.dart | 7 - .../src/widgets/dual_transition_builder.dart | 3 - .../lib/src/widgets/editable_text.dart | 24 ++- .../lib/src/widgets/fade_in_image.dart | 8 - .../lib/src/widgets/focus_manager.dart | 3 - .../flutter/lib/src/widgets/focus_scope.dart | 16 +- .../lib/src/widgets/focus_traversal.dart | 19 --- packages/flutter/lib/src/widgets/form.dart | 6 +- .../flutter/lib/src/widgets/framework.dart | 3 - .../lib/src/widgets/gesture_detector.dart | 2 - packages/flutter/lib/src/widgets/heroes.dart | 7 +- .../flutter/lib/src/widgets/icon_data.dart | 2 - .../flutter/lib/src/widgets/icon_theme.dart | 4 - packages/flutter/lib/src/widgets/image.dart | 11 -- .../flutter/lib/src/widgets/image_filter.dart | 2 - .../lib/src/widgets/implicit_animations.dart | 46 +----- .../lib/src/widgets/inherited_notifier.dart | 2 - .../lib/src/widgets/interactive_viewer.dart | 15 +- .../lib/src/widgets/keyboard_listener.dart | 4 - .../lib/src/widgets/layout_builder.dart | 5 - .../src/widgets/list_wheel_scroll_view.dart | 19 ++- .../flutter/lib/src/widgets/media_query.dart | 43 ++--- .../flutter/lib/src/widgets/navigator.dart | 11 +- .../lib/src/widgets/nested_scroll_view.dart | 14 +- .../lib/src/widgets/orientation_builder.dart | 2 - .../flutter/lib/src/widgets/overflow_bar.dart | 7 +- packages/flutter/lib/src/widgets/overlay.dart | 4 +- .../lib/src/widgets/overscroll_indicator.dart | 9 +- .../flutter/lib/src/widgets/page_storage.dart | 2 - .../flutter/lib/src/widgets/page_view.dart | 18 +-- packages/flutter/lib/src/widgets/pages.dart | 3 - .../lib/src/widgets/platform_view.dart | 7 +- .../src/widgets/raw_keyboard_listener.dart | 4 - .../flutter/lib/src/widgets/restoration.dart | 6 - packages/flutter/lib/src/widgets/router.dart | 24 +-- packages/flutter/lib/src/widgets/routes.dart | 3 +- .../flutter/lib/src/widgets/safe_area.dart | 2 - .../lib/src/widgets/scroll_activity.dart | 6 - .../widgets/scroll_aware_image_provider.dart | 3 +- .../lib/src/widgets/scroll_configuration.dart | 2 - .../widgets/scroll_notification_observer.dart | 2 - .../lib/src/widgets/scroll_physics.dart | 10 +- .../flutter/lib/src/widgets/scroll_view.dart | 8 +- .../flutter/lib/src/widgets/scrollable.dart | 2 - .../lib/src/widgets/scrollable_helpers.dart | 9 +- .../flutter/lib/src/widgets/scrollbar.dart | 19 +-- .../lib/src/widgets/selection_container.dart | 4 - .../lib/src/widgets/semantics_debugger.dart | 2 - .../src/widgets/single_child_scroll_view.dart | 2 +- packages/flutter/lib/src/widgets/sliver.dart | 9 +- .../flutter/lib/src/widgets/sliver_fill.dart | 15 +- .../src/widgets/sliver_layout_builder.dart | 2 - .../src/widgets/sliver_persistent_header.dart | 2 - .../widgets/sliver_varied_extent_list.dart | 2 - .../lib/src/widgets/status_transitions.dart | 2 - packages/flutter/lib/src/widgets/table.dart | 6 +- packages/flutter/lib/src/widgets/text.dart | 11 -- .../lib/src/widgets/text_selection.dart | 5 +- .../lib/src/widgets/ticker_provider.dart | 2 - packages/flutter/lib/src/widgets/title.dart | 1 - .../flutter/lib/src/widgets/transitions.dart | 19 +-- .../src/widgets/tween_animation_builder.dart | 3 - .../lib/src/widgets/unique_widget.dart | 4 +- .../src/widgets/value_listenable_builder.dart | 5 - .../flutter/lib/src/widgets/viewport.dart | 4 - .../flutter/lib/src/widgets/visibility.dart | 10 -- .../lib/src/widgets/widget_inspector.dart | 9 -- .../flutter/lib/src/widgets/widget_span.dart | 8 +- .../lib/src/widgets/will_pop_scope.dart | 2 - 85 files changed, 157 insertions(+), 619 deletions(-) diff --git a/packages/flutter/lib/src/widgets/actions.dart b/packages/flutter/lib/src/widgets/actions.dart index 72137c0d6fba8..4e31bbd45c32a 100644 --- a/packages/flutter/lib/src/widgets/actions.dart +++ b/packages/flutter/lib/src/widgets/actions.dart @@ -455,8 +455,6 @@ abstract class Action<T extends Intent> with Diagnosticable { @immutable class ActionListener extends StatefulWidget { /// Create a const [ActionListener]. - /// - /// The [listener], [action], and [child] arguments must not be null. const ActionListener({ super.key, required this.listener, @@ -465,13 +463,9 @@ class ActionListener extends StatefulWidget { }); /// The [ActionListenerCallback] callback to register with the [action]. - /// - /// Must not be null. final ActionListenerCallback listener; /// The [Action] that the callback will be registered with. - /// - /// Must not be null. final Action<Intent> action; /// {@macro flutter.widgets.ProxyWidget.child} @@ -712,8 +706,6 @@ class ActionDispatcher with Diagnosticable { /// * [ActionDispatcher], the object that this widget uses to manage actions. class Actions extends StatefulWidget { /// Creates an [Actions] widget. - /// - /// The [child], [actions], and [dispatcher] arguments must not be null. const Actions({ super.key, this.dispatcher, @@ -950,8 +942,6 @@ class Actions extends StatefulWidget { /// This method returns the result of invoking the action's [Action.invoke] /// method. /// - /// The `context` and `intent` arguments must not be null. - /// /// If the given `intent` doesn't map to an action, then it will look to the /// next ancestor [Actions] widget in the hierarchy until it reaches the root. /// @@ -1003,8 +993,6 @@ class Actions extends StatefulWidget { /// first action found was disabled, or the action itself returns null /// from [Action.invoke], then this method returns null. /// - /// The `context` and `intent` arguments must not be null. - /// /// If the given `intent` doesn't map to an action, then it will look to the /// next ancestor [Actions] widget in the hierarchy until it reaches the root. /// If a suitable [Action] is found but its [Action.isEnabled] returns false, @@ -1153,8 +1141,6 @@ class _ActionsScope extends InheritedWidget { /// It hosts its own [FocusNode] or uses [focusNode], if given. class FocusableActionDetector extends StatefulWidget { /// Create a const [FocusableActionDetector]. - /// - /// The [enabled], [autofocus], [mouseCursor], and [child] arguments must not be null. const FocusableActionDetector({ super.key, this.enabled = true, diff --git a/packages/flutter/lib/src/widgets/animated_cross_fade.dart b/packages/flutter/lib/src/widgets/animated_cross_fade.dart index 6d0e928af11d5..116d61bc3fee1 100644 --- a/packages/flutter/lib/src/widgets/animated_cross_fade.dart +++ b/packages/flutter/lib/src/widgets/animated_cross_fade.dart @@ -115,8 +115,6 @@ class AnimatedCrossFade extends StatefulWidget { /// The [duration] of the animation is the same for all components (fade in, /// fade out, and size), and you can pass [Interval]s instead of [Curve]s in /// order to have finer control, e.g., creating an overlap between the fades. - /// - /// All the arguments other than [key] must be non-null. const AnimatedCrossFade({ super.key, required this.firstChild, diff --git a/packages/flutter/lib/src/widgets/animated_size.dart b/packages/flutter/lib/src/widgets/animated_size.dart index b136fc6aef77f..3deb0d7660288 100644 --- a/packages/flutter/lib/src/widgets/animated_size.dart +++ b/packages/flutter/lib/src/widgets/animated_size.dart @@ -23,8 +23,6 @@ import 'ticker_provider.dart'; /// * [SizeTransition], which changes its size based on an [Animation]. class AnimatedSize extends StatefulWidget { /// Creates a widget that animates its size to match that of its child. - /// - /// The [curve] and [duration] arguments must not be null. const AnimatedSize({ super.key, this.child, @@ -77,7 +75,7 @@ class AnimatedSize extends StatefulWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; @override diff --git a/packages/flutter/lib/src/widgets/animated_switcher.dart b/packages/flutter/lib/src/widgets/animated_switcher.dart index e2d6828a6b376..177ede770629b 100644 --- a/packages/flutter/lib/src/widgets/animated_switcher.dart +++ b/packages/flutter/lib/src/widgets/animated_switcher.dart @@ -103,9 +103,6 @@ typedef AnimatedSwitcherLayoutBuilder = Widget Function(Widget? currentChild, Li /// * [FadeTransition], which [AnimatedSwitcher] uses to perform the transition. class AnimatedSwitcher extends StatefulWidget { /// Creates an [AnimatedSwitcher]. - /// - /// The [duration], [transitionBuilder], [layoutBuilder], [switchInCurve], and - /// [switchOutCurve] parameters must not be null. const AnimatedSwitcher({ super.key, this.child, diff --git a/packages/flutter/lib/src/widgets/app.dart b/packages/flutter/lib/src/widgets/app.dart index d8d649c103a45..b6b4b9647bfcd 100644 --- a/packages/flutter/lib/src/widgets/app.dart +++ b/packages/flutter/lib/src/widgets/app.dart @@ -264,8 +264,6 @@ class WidgetsApp extends StatefulWidget { /// Creates a widget that wraps a number of widgets that are commonly /// required for an application. /// - /// The boolean arguments, [color], and [navigatorObservers] must not be null. - /// /// Most callers will want to use the [home] or [routes] parameters, or both. /// The [home] parameter is a convenience for the following [routes] map: /// diff --git a/packages/flutter/lib/src/widgets/async.dart b/packages/flutter/lib/src/widgets/async.dart index 7e755524c2c2d..36b0f77eb48e0 100644 --- a/packages/flutter/lib/src/widgets/async.dart +++ b/packages/flutter/lib/src/widgets/async.dart @@ -386,8 +386,6 @@ class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> { /// strategy is given by [builder]. /// /// The [initialData] is used to create the initial snapshot. - /// - /// The [builder] must not be null. const StreamBuilder({ super.key, this.initialData, @@ -517,8 +515,6 @@ class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>> { class FutureBuilder<T> extends StatefulWidget { /// Creates a widget that builds itself based on the latest snapshot of /// interaction with a [Future]. - /// - /// The [builder] must not be null. const FutureBuilder({ super.key, required this.future, diff --git a/packages/flutter/lib/src/widgets/autofill.dart b/packages/flutter/lib/src/widgets/autofill.dart index c184081944b1c..0d72987d3490e 100644 --- a/packages/flutter/lib/src/widgets/autofill.dart +++ b/packages/flutter/lib/src/widgets/autofill.dart @@ -64,8 +64,6 @@ enum AutofillContextAction { /// clean up actions to be run when a topmost [AutofillGroup] is disposed. class AutofillGroup extends StatefulWidget { /// Creates a scope for autofillable input fields. - /// - /// The [child] argument must not be null. const AutofillGroup({ super.key, required this.child, diff --git a/packages/flutter/lib/src/widgets/automatic_keep_alive.dart b/packages/flutter/lib/src/widgets/automatic_keep_alive.dart index 4b3b7cb6ccc28..a8292b1487d9e 100644 --- a/packages/flutter/lib/src/widgets/automatic_keep_alive.dart +++ b/packages/flutter/lib/src/widgets/automatic_keep_alive.dart @@ -294,8 +294,6 @@ class _AutomaticKeepAliveState extends State<AutomaticKeepAlive> { /// [KeepAliveNotification] internally. class KeepAliveNotification extends Notification { /// Creates a notification to indicate that a subtree must be kept alive. - /// - /// The [handle] must not be null. const KeepAliveNotification(this.handle); /// A [Listenable] that will inform its clients when the widget that fired the diff --git a/packages/flutter/lib/src/widgets/banner.dart b/packages/flutter/lib/src/widgets/banner.dart index 55e6ed5620958..33a11fd828c46 100644 --- a/packages/flutter/lib/src/widgets/banner.dart +++ b/packages/flutter/lib/src/widgets/banner.dart @@ -54,9 +54,6 @@ enum BannerLocation { /// Paints a [Banner]. class BannerPainter extends CustomPainter { /// Creates a banner painter. - /// - /// The [message], [textDirection], [location], and [layoutDirection] - /// arguments must not be null. BannerPainter({ required this.message, required this.textDirection, @@ -236,8 +233,6 @@ class BannerPainter extends CustomPainter { /// debug mode, to show a banner that says "DEBUG". class Banner extends StatelessWidget { /// Creates a banner. - /// - /// The [message] and [location] arguments must not be null. const Banner({ super.key, this.child, diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index a8820921e7c1d..3e0a8942886a2 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -147,8 +147,6 @@ abstract class _UbiquitousInheritedWidget extends InheritedWidget { class Directionality extends _UbiquitousInheritedWidget { /// Creates a widget that determines the directionality of text and /// text-direction-sensitive render objects. - /// - /// The [textDirection] and [child] arguments must not be null. const Directionality({ super.key, required this.textDirection, @@ -320,8 +318,7 @@ class Directionality extends _UbiquitousInheritedWidget { class Opacity extends SingleChildRenderObjectWidget { /// Creates a widget that makes its child partially transparent. /// - /// The [opacity] argument must not be null and must be between 0.0 and 1.0 - /// (inclusive). + /// The [opacity] argument must be between zero and one, inclusive. const Opacity({ super.key, required this.opacity, @@ -331,14 +328,11 @@ class Opacity extends SingleChildRenderObjectWidget { /// The fraction to scale the child's alpha value. /// - /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent + /// An opacity of one is fully opaque. An opacity of zero is fully transparent /// (i.e., invisible). /// - /// The opacity must not be null. - /// - /// Values 1.0 and 0.0 are painted with a fast path. Other values - /// require painting the child into an intermediate buffer, which is - /// expensive. + /// Values one and zero are painted with a fast path. Other values require + /// painting the child into an intermediate buffer, which is expensive. final double opacity; /// Whether the semantic information of the children is always included. @@ -411,8 +405,6 @@ class Opacity extends SingleChildRenderObjectWidget { /// * [BackdropFilter], which applies an image filter to the background. class ShaderMask extends SingleChildRenderObjectWidget { /// Creates a widget that applies a mask generated by a [Shader] to its child. - /// - /// The [shaderCallback] and [blendMode] arguments must not be null. const ShaderMask({ super.key, required this.shaderCallback, @@ -560,7 +552,6 @@ class ShaderMask extends SingleChildRenderObjectWidget { class BackdropFilter extends SingleChildRenderObjectWidget { /// Creates a backdrop filter. /// - /// The [filter] argument must not be null. /// The [blendMode] argument will default to [BlendMode.srcOver] and must not be /// null if provided. const BackdropFilter({ @@ -776,8 +767,7 @@ class ClipRect extends SingleChildRenderObjectWidget { /// If [clipper] is null, the clip will match the layout size and position of /// the child. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. const ClipRect({ super.key, this.clipper, @@ -860,8 +850,7 @@ class ClipRRect extends SingleChildRenderObjectWidget { /// /// If [clipper] is non-null, then [borderRadius] is ignored. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. const ClipRRect({ super.key, this.borderRadius = BorderRadius.zero, @@ -933,8 +922,7 @@ class ClipOval extends SingleChildRenderObjectWidget { /// If [clipper] is null, the oval will be inscribed into the layout size and /// position of the child. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. const ClipOval({ super.key, this.clipper, @@ -1008,8 +996,7 @@ class ClipPath extends SingleChildRenderObjectWidget { /// consider using a [ClipRect], which can achieve the same effect more /// efficiently. /// - /// The [clipBehavior] argument must not be null. If [clipBehavior] is - /// [Clip.none], no clipping will be applied. + /// If [clipBehavior] is [Clip.none], no clipping will be applied. const ClipPath({ super.key, this.clipper, @@ -1199,8 +1186,7 @@ class PhysicalShape extends SingleChildRenderObjectWidget { /// /// The [color] is required; physical things have a color. /// - /// The [clipper], [elevation], [color], [clipBehavior], and [shadowColor] - /// must not be null. Additionally, the [elevation] must be non-negative. + /// The [elevation] must be non-negative. const PhysicalShape({ super.key, required this.clipper, @@ -1310,8 +1296,6 @@ class PhysicalShape extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class Transform extends SingleChildRenderObjectWidget { /// Creates a widget that transforms its child. - /// - /// The [transform] argument must not be null. const Transform({ super.key, required this.transform, @@ -1325,8 +1309,7 @@ class Transform extends SingleChildRenderObjectWidget { /// Creates a widget that transforms its child using a rotation around the /// center. /// - /// The `angle` argument must not be null. It gives the rotation in clockwise - /// radians. + /// The `angle` argument gives the rotation in clockwise radians. /// /// {@tool snippet} /// @@ -1361,7 +1344,7 @@ class Transform extends SingleChildRenderObjectWidget { /// Creates a widget that transforms its child using a translation. /// - /// The `offset` argument must not be null. It specifies the translation. + /// The `offset` argument specifies the translation. /// /// {@tool snippet} /// @@ -1390,19 +1373,25 @@ class Transform extends SingleChildRenderObjectWidget { /// Creates a widget that scales its child along the 2D plane. /// - /// The `scaleX` argument provides the scalar by which to multiply the `x` axis, and the `scaleY` argument provides the scalar by which to multiply the `y` axis. Either may be omitted, in which case the scaling factor for that axis defaults to 1.0. + /// The `scaleX` argument provides the scalar by which to multiply the `x` + /// axis, and the `scaleY` argument provides the scalar by which to multiply + /// the `y` axis. Either may be omitted, in which case the scaling factor for + /// that axis defaults to 1.0. /// - /// For convenience, to scale the child uniformly, instead of providing `scaleX` and `scaleY`, the `scale` parameter may be used. + /// For convenience, to scale the child uniformly, instead of providing + /// `scaleX` and `scaleY`, the `scale` parameter may be used. /// - /// At least one of `scale`, `scaleX`, and `scaleY` must be non-null. If `scale` is provided, the other two must be null; similarly, if it is not provided, one of the other two must be provided. + /// At least one of `scale`, `scaleX`, and `scaleY` must be non-null. If + /// `scale` is provided, the other two must be null; similarly, if it is not + /// provided, one of the other two must be provided. /// - /// The [alignment] controls the origin of the scale; by default, this is - /// the center of the box. + /// The [alignment] controls the origin of the scale; by default, this is the + /// center of the box. /// /// {@tool snippet} /// - /// This example shrinks an orange box containing text such that each dimension - /// is half the size it would otherwise be. + /// This example shrinks an orange box containing text such that each + /// dimension is half the size it would otherwise be. /// /// ```dart /// Transform.scale( @@ -1418,8 +1407,8 @@ class Transform extends SingleChildRenderObjectWidget { /// /// See also: /// - /// * [ScaleTransition], which animates changes in scale smoothly - /// over a given duration. + /// * [ScaleTransition], which animates changes in scale smoothly over a given + /// duration. Transform.scale({ super.key, double? scale, @@ -1577,8 +1566,8 @@ class Transform extends SingleChildRenderObjectWidget { class CompositedTransformTarget extends SingleChildRenderObjectWidget { /// Creates a composited transform target widget. /// - /// The [link] property must not be null, and must not be currently being used - /// by any other [CompositedTransformTarget] object that is in the tree. + /// The [link] property must not be currently used by any other + /// [CompositedTransformTarget] object that is in the tree. const CompositedTransformTarget({ super.key, required this.link, @@ -1588,8 +1577,8 @@ class CompositedTransformTarget extends SingleChildRenderObjectWidget { /// The link object that connects this [CompositedTransformTarget] with one or /// more [CompositedTransformFollower]s. /// - /// This property must not be null. The object must not be associated with - /// another [CompositedTransformTarget] that is also being painted. + /// The link must not be associated with another [CompositedTransformTarget] + /// that is also being painted. final LayerLink link; @override @@ -1635,9 +1624,8 @@ class CompositedTransformTarget extends SingleChildRenderObjectWidget { class CompositedTransformFollower extends SingleChildRenderObjectWidget { /// Creates a composited transform target widget. /// - /// The [link] property must not be null. If it was also provided to a - /// [CompositedTransformTarget], that widget must come earlier in the paint - /// order. + /// If the [link] property was also provided to a [CompositedTransformTarget], + /// that widget must come earlier in the paint order. /// /// The [showWhenUnlinked] and [offset] properties must also not be null. const CompositedTransformFollower({ @@ -1652,8 +1640,6 @@ class CompositedTransformFollower extends SingleChildRenderObjectWidget { /// The link object that connects this [CompositedTransformFollower] with a /// [CompositedTransformTarget]. - /// - /// This property must not be null. final LayerLink link; /// Whether to show the widget's contents when there is no corresponding @@ -1737,8 +1723,6 @@ class CompositedTransformFollower extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class FittedBox extends SingleChildRenderObjectWidget { /// Creates a widget that scales and positions its child within itself according to [fit]. - /// - /// The [fit] and [alignment] arguments must not be null. const FittedBox({ super.key, this.fit = BoxFit.contain, @@ -1817,8 +1801,6 @@ class FittedBox extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class FractionalTranslation extends SingleChildRenderObjectWidget { /// Creates a widget that translates its child's painting. - /// - /// The [translation] argument must not be null. const FractionalTranslation({ super.key, required this.translation, @@ -1880,8 +1862,6 @@ class FractionalTranslation extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class RotatedBox extends SingleChildRenderObjectWidget { /// A widget that rotates its child. - /// - /// The [quarterTurns] argument must not be null. const RotatedBox({ super.key, required this.quarterTurns, @@ -1955,8 +1935,6 @@ class RotatedBox extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class Padding extends SingleChildRenderObjectWidget { /// Creates a widget that insets its child. - /// - /// The [padding] argument must not be null. const Padding({ super.key, required this.padding, @@ -2233,8 +2211,6 @@ class Center extends Align { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class CustomSingleChildLayout extends SingleChildRenderObjectWidget { /// Creates a custom single child layout. - /// - /// The [delegate] argument must not be null. const CustomSingleChildLayout({ super.key, required this.delegate, @@ -2262,8 +2238,6 @@ class CustomSingleChildLayout extends SingleChildRenderObjectWidget { /// [MultiChildLayoutDelegate.positionChild] methods use these identifiers. class LayoutId extends ParentDataWidget<MultiChildLayoutParentData> { /// Marks a child with a layout identifier. - /// - /// Both the child and the id arguments must not be null. LayoutId({ Key? key, required this.id, @@ -2336,8 +2310,6 @@ class LayoutId extends ParentDataWidget<MultiChildLayoutParentData> { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class CustomMultiChildLayout extends MultiChildRenderObjectWidget { /// Creates a custom multi-child layout. - /// - /// The [delegate] argument must not be null. const CustomMultiChildLayout({ super.key, required this.delegate, @@ -2524,8 +2496,6 @@ class SizedBox extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class ConstrainedBox extends SingleChildRenderObjectWidget { /// Creates a widget that imposes additional constraints on its child. - /// - /// The [constraints] argument must not be null. ConstrainedBox({ super.key, required this.constraints, @@ -3011,8 +2981,7 @@ class FractionallySizedBox extends SingleChildRenderObjectWidget { class LimitedBox extends SingleChildRenderObjectWidget { /// Creates a box that limits its size only when it's unconstrained. /// - /// The [maxWidth] and [maxHeight] arguments must not be null and must not be - /// negative. + /// The [maxWidth] and [maxHeight] arguments must not be negative. const LimitedBox({ super.key, this.maxWidth = double.infinity, @@ -3170,8 +3139,6 @@ class OverflowBox extends SingleChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class SizedOverflowBox extends SingleChildRenderObjectWidget { /// Creates a widget of a given size that lets its child overflow. - /// - /// The [size] argument must not be null. const SizedOverflowBox({ super.key, required this.size, @@ -3648,8 +3615,6 @@ class SliverToBoxAdapter extends SingleChildRenderObjectWidget { /// * [Padding], the box version of this widget. class SliverPadding extends SingleChildRenderObjectWidget { /// Creates a sliver that applies padding on each side of another sliver. - /// - /// The [padding] argument must not be null. const SliverPadding({ super.key, required this.padding, @@ -4027,8 +3992,6 @@ class Stack extends MultiChildRenderObjectWidget { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class IndexedStack extends StatelessWidget { /// Creates a [Stack] widget that paints a single child. - /// - /// The [index] argument must not be null. const IndexedStack({ super.key, this.alignment = AlignmentDirectional.topStart, @@ -4272,8 +4235,6 @@ class Positioned extends ParentDataWidget<StackParentData> { /// then the `start` argument is used for the [left] property and the `end` /// argument is used for the [right] property. /// - /// The `textDirection` argument must not be null. - /// /// See also: /// /// * [PositionedDirectional], which adapts to the ambient [Directionality]. @@ -4612,9 +4573,8 @@ class Flex extends MultiChildRenderObjectWidget { /// /// The [direction] is required. /// - /// The [direction], [mainAxisAlignment], [crossAxisAlignment], and - /// [verticalDirection] arguments must not be null. If [crossAxisAlignment] is - /// [CrossAxisAlignment.baseline], then [textBaseline] must not be null. + /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then + /// [textBaseline] must not be null. /// /// The [textDirection] argument defaults to the ambient [Directionality], if /// any. If there is no ambient directionality, and a text direction is going @@ -4978,8 +4938,6 @@ class Flex extends MultiChildRenderObjectWidget { class Row extends Flex { /// Creates a horizontal array of children. /// - /// The [mainAxisAlignment], [mainAxisSize], [crossAxisAlignment], and - /// [verticalDirection] arguments must not be null. /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then /// [textBaseline] must not be null. /// @@ -5173,8 +5131,6 @@ class Row extends Flex { class Column extends Flex { /// Creates a vertical array of children. /// - /// The [mainAxisAlignment], [mainAxisSize], [crossAxisAlignment], and - /// [verticalDirection] arguments must not be null. /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then /// [textBaseline] must not be null. /// @@ -5653,8 +5609,6 @@ class Flow extends MultiChildRenderObjectWidget { /// /// Wraps each of the given children in a [RepaintBoundary] to avoid /// repainting the children when the flow repaints. - /// - /// The [delegate] argument must not be null. Flow({ super.key, required this.delegate, @@ -5668,8 +5622,6 @@ class Flow extends MultiChildRenderObjectWidget { /// Does not wrap the given children in repaint boundaries, unlike the default /// constructor. Useful when the child is trivial to paint or already contains /// a repaint boundary. - /// - /// The [delegate] argument must not be null. const Flow.unwrapped({ super.key, required this.delegate, @@ -5682,7 +5634,7 @@ class Flow extends MultiChildRenderObjectWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; @override @@ -5779,9 +5731,6 @@ class Flow extends MultiChildRenderObjectWidget { class RichText extends MultiChildRenderObjectWidget { /// Creates a paragraph of rich text. /// - /// The [text], [textAlign], [softWrap], [overflow], and [textScaler] - /// arguments must not be null. - /// /// The [maxLines] property may be null (and indeed defaults to null), but if /// it is not null, it must be greater than zero. /// @@ -6264,8 +6213,6 @@ class RawImage extends LeafRenderObjectWidget { /// * [rootBundle], the default asset bundle. class DefaultAssetBundle extends InheritedWidget { /// Creates a widget that determines the default asset bundle for its descendants. - /// - /// The [bundle] and [child] arguments must not be null. const DefaultAssetBundle({ super.key, required this.bundle, @@ -6307,8 +6254,6 @@ class DefaultAssetBundle extends InheritedWidget { /// [onUnmount] callback. class WidgetToRenderBoxAdapter extends LeafRenderObjectWidget { /// Creates an adapter for placing a specific [RenderBox] in the widget tree. - /// - /// The [renderBox] argument must not be null. WidgetToRenderBoxAdapter({ required this.renderBox, this.onBuild, @@ -6535,7 +6480,7 @@ class MouseRegion extends SingleChildRenderObjectWidget { /// Creates a widget that forwards mouse events to callbacks. /// /// By default, all callbacks are empty, [cursor] is [MouseCursor.defer], and - /// [opaque] is true. The [cursor] must not be null. + /// [opaque] is true. const MouseRegion({ super.key, this.onEnter, @@ -6875,8 +6820,6 @@ class RepaintBoundary extends SingleChildRenderObjectWidget { /// * [SliverIgnorePointer], the sliver version of this widget. class IgnorePointer extends SingleChildRenderObjectWidget { /// Creates a widget that is invisible to hit testing. - /// - /// The [ignoring] argument must not be null. const IgnorePointer({ super.key, this.ignoring = true, @@ -6991,8 +6934,6 @@ class IgnorePointer extends SingleChildRenderObjectWidget { /// events but is itself invisible to hit testing. class AbsorbPointer extends SingleChildRenderObjectWidget { /// Creates a widget that absorbs pointers during hit testing. - /// - /// The [absorbing] argument must not be null. const AbsorbPointer({ super.key, this.absorbing = true, @@ -7127,8 +7068,8 @@ class MetaData extends SingleChildRenderObjectWidget { class Semantics extends SingleChildRenderObjectWidget { /// Creates a semantic annotation. /// - /// The [container] argument must not be null. To create a `const` instance - /// of [Semantics], use the [Semantics.fromProperties] constructor. + /// To create a `const` instance of [Semantics], use the + /// [Semantics.fromProperties] constructor. /// /// See also: /// @@ -7278,8 +7219,6 @@ class Semantics extends SingleChildRenderObjectWidget { ); /// Creates a semantic annotation using [SemanticsProperties]. - /// - /// The [container] and [properties] arguments must not be null. const Semantics.fromProperties({ super.key, super.child, @@ -7570,8 +7509,6 @@ class ExcludeSemantics extends SingleChildRenderObjectWidget { /// * [CustomScrollView], for an explanation of index semantics. class IndexedSemantics extends SingleChildRenderObjectWidget { /// Creates a widget that annotated the first child semantics node with an index. - /// - /// [index] must not be null. const IndexedSemantics({ super.key, required this.index, @@ -7727,8 +7664,6 @@ class KeyedSubtree extends StatelessWidget { /// [builder] callback to create the widget's child. class Builder extends StatelessWidget { /// Creates a widget that delegates its build to a callback. - /// - /// The [builder] argument must not be null. const Builder({ super.key, required this.builder, @@ -7800,8 +7735,6 @@ typedef StatefulWidgetBuilder = Widget Function(BuildContext context, StateSette /// * [Builder], the platonic stateless widget. class StatefulBuilder extends StatefulWidget { /// Creates a widget that both has state and delegates its build to a callback. - /// - /// The [builder] argument must not be null. const StatefulBuilder({ super.key, required this.builder, @@ -7829,8 +7762,6 @@ class _StatefulBuilderState extends State<StatefulBuilder> { /// child on top of that color. class ColoredBox extends SingleChildRenderObjectWidget { /// Creates a widget that paints its area with the specified [Color]. - /// - /// The [color] parameter must not be null. const ColoredBox({ required this.color, super.child, super.key }); /// The color to paint the background area with. @@ -7859,8 +7790,6 @@ class _RenderColoredBox extends RenderProxyBoxWithHitTestBehavior { super(behavior: HitTestBehavior.opaque); /// The fill color for this render object. - /// - /// This parameter must not be null. Color get color => _color; Color _color; set color(Color value) { diff --git a/packages/flutter/lib/src/widgets/color_filter.dart b/packages/flutter/lib/src/widgets/color_filter.dart index ea2ef46ed8a48..bd01095792d54 100644 --- a/packages/flutter/lib/src/widgets/color_filter.dart +++ b/packages/flutter/lib/src/widgets/color_filter.dart @@ -32,8 +32,6 @@ import 'framework.dart'; @immutable class ColorFiltered extends SingleChildRenderObjectWidget { /// Creates a widget that applies a [ColorFilter] to its child. - /// - /// The [colorFilter] must not be null. const ColorFiltered({required this.colorFilter, super.child, super.key}); /// The color filter to apply to the child of this widget. diff --git a/packages/flutter/lib/src/widgets/container.dart b/packages/flutter/lib/src/widgets/container.dart index 486bce79ce7fd..f6967ce1d0745 100644 --- a/packages/flutter/lib/src/widgets/container.dart +++ b/packages/flutter/lib/src/widgets/container.dart @@ -56,8 +56,7 @@ import 'image.dart'; class DecoratedBox extends SingleChildRenderObjectWidget { /// Creates a widget that paints a [Decoration]. /// - /// The [decoration] and [position] arguments must not be null. By default the - /// decoration paints behind the child. + /// By default the decoration paints behind the child. const DecoratedBox({ super.key, required this.decoration, diff --git a/packages/flutter/lib/src/widgets/decorated_sliver.dart b/packages/flutter/lib/src/widgets/decorated_sliver.dart index fffe3b4113bee..3cc1b83e87c67 100644 --- a/packages/flutter/lib/src/widgets/decorated_sliver.dart +++ b/packages/flutter/lib/src/widgets/decorated_sliver.dart @@ -40,8 +40,7 @@ import 'image.dart'; class DecoratedSliver extends SingleChildRenderObjectWidget { /// Creates a widget that paints a [Decoration]. /// - /// The [decoration] and [position] arguments must not be null. By default the - /// decoration paints behind the child. + /// By default the decoration paints behind the child. const DecoratedSliver({ super.key, required this.decoration, diff --git a/packages/flutter/lib/src/widgets/dismissible.dart b/packages/flutter/lib/src/widgets/dismissible.dart index 87f9753511a47..0fe4bdfcd51c7 100644 --- a/packages/flutter/lib/src/widgets/dismissible.dart +++ b/packages/flutter/lib/src/widgets/dismissible.dart @@ -90,12 +90,12 @@ enum DismissDirection { class Dismissible extends StatefulWidget { /// Creates a widget that can be dismissed. /// - /// The [key] argument must not be null because [Dismissible]s are commonly - /// used in lists and removed from the list when dismissed. Without keys, the - /// default behavior is to sync widgets based on their index in the list, - /// which means the item after the dismissed item would be synced with the - /// state of the dismissed item. Using keys causes the widgets to sync - /// according to their keys and avoids this pitfall. + /// The [key] argument is required because [Dismissible]s are commonly used in + /// lists and removed from the list when dismissed. Without keys, the default + /// behavior is to sync widgets based on their index in the list, which means + /// the item after the dismissed item would be synced with the state of the + /// dismissed item. Using keys causes the widgets to sync according to their + /// keys and avoids this pitfall. const Dismissible({ required Key key, required this.child, diff --git a/packages/flutter/lib/src/widgets/disposable_build_context.dart b/packages/flutter/lib/src/widgets/disposable_build_context.dart index 2283acaeec478..f3bcf6abd7f30 100644 --- a/packages/flutter/lib/src/widgets/disposable_build_context.dart +++ b/packages/flutter/lib/src/widgets/disposable_build_context.dart @@ -26,7 +26,7 @@ class DisposableBuildContext<T extends State> { /// /// Creators must call [dispose] when the [State] is disposed. /// - /// The [State] must not be null, and [State.mounted] must be true. + /// [State.mounted] must be true. DisposableBuildContext(T this._state) : assert(_state.mounted, 'A DisposableBuildContext was given a BuildContext for an Element that is not mounted.'); diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index a2ed56a7f3f19..bf323cf6de0ba 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -164,8 +164,7 @@ Offset pointerDragAnchorStrategy(Draggable<Object> draggable, BuildContext conte class Draggable<T extends Object> extends StatefulWidget { /// Creates a widget that can be dragged to a [DragTarget]. /// - /// The [child] and [feedback] arguments must not be null. If - /// [maxSimultaneousDrags] is non-null, it must be non-negative. + /// If [maxSimultaneousDrags] is non-null, it must be non-negative. const Draggable({ super.key, required this.child, @@ -394,8 +393,7 @@ class Draggable<T extends Object> extends StatefulWidget { class LongPressDraggable<T extends Object> extends Draggable<T> { /// Creates a widget that can be dragged starting from long press. /// - /// The [child] and [feedback] arguments must not be null. If - /// [maxSimultaneousDrags] is non-null, it must be non-negative. + /// If [maxSimultaneousDrags] is non-null, it must be non-negative. const LongPressDraggable({ super.key, required super.child, @@ -586,8 +584,6 @@ class DraggableDetails { /// Represents the details when a pointer event occurred on the [DragTarget]. class DragTargetDetails<T> { /// Creates details for a [DragTarget] callback. - /// - /// The [offset] must not be null. DragTargetDetails({required this.data, required this.offset}); /// The data that was dropped onto this [DragTarget]. @@ -612,8 +608,6 @@ class DragTargetDetails<T> { /// * [LongPressDraggable] class DragTarget<T extends Object> extends StatefulWidget { /// Creates a widget that receives drags. - /// - /// The [builder] argument must not be null. const DragTarget({ super.key, required this.builder, diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart index 276b711db400e..e8e56fc47ab34 100644 --- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart +++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart @@ -295,9 +295,6 @@ class DraggableScrollableController extends ChangeNotifier { /// {@end-tool} class DraggableScrollableSheet extends StatefulWidget { /// Creates a widget that can be dragged and scrolled in a single gesture. - /// - /// The [builder], [initialChildSize], [minChildSize], [maxChildSize] and - /// [expand] parameters must not be null. const DraggableScrollableSheet({ super.key, this.initialChildSize = 0.5, @@ -1031,8 +1028,6 @@ class DraggableScrollableActuator extends StatefulWidget { /// This child's [DraggableScrollableSheet] descendant will be reset when the /// [reset] method is applied to a context that includes it. - /// - /// Must not be null. final Widget child; @@ -1098,8 +1093,6 @@ class _ResetNotifier extends ChangeNotifier { class _InheritedResetNotifier extends InheritedNotifier<_ResetNotifier> { /// Creates an [InheritedNotifier] that the [DraggableScrollableSheet] will /// listen to for an indication that it should reset itself back to [DraggableScrollableSheet.initialChildSize]. - /// - /// The [child] and [notifier] properties must not be null. const _InheritedResetNotifier({ required super.child, required _ResetNotifier super.notifier, diff --git a/packages/flutter/lib/src/widgets/dual_transition_builder.dart b/packages/flutter/lib/src/widgets/dual_transition_builder.dart index bc5b5b3a3be29..5f1a1868e4a55 100644 --- a/packages/flutter/lib/src/widgets/dual_transition_builder.dart +++ b/packages/flutter/lib/src/widgets/dual_transition_builder.dart @@ -32,9 +32,6 @@ typedef AnimatedTransitionBuilder = Widget Function( /// any descendant widget is lost when the transition starts or completes. class DualTransitionBuilder extends StatefulWidget { /// Creates a [DualTransitionBuilder]. - /// - /// The [animation], [forwardBuilder], and [reverseBuilder] arguments are - /// required and must not be null. const DualTransitionBuilder({ super.key, required this.animation, diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 225aba07a0e13..339c6405fa47a 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -369,26 +369,26 @@ class ToolbarOptions { /// Whether to show copy option in toolbar. /// - /// Defaults to false. Must not be null. + /// Defaults to false. final bool copy; /// Whether to show cut option in toolbar. /// /// If [EditableText.readOnly] is set to true, cut will be disabled regardless. /// - /// Defaults to false. Must not be null. + /// Defaults to false. final bool cut; /// Whether to show paste option in toolbar. /// /// If [EditableText.readOnly] is set to true, paste will be disabled regardless. /// - /// Defaults to false. Must not be null. + /// Defaults to false. final bool paste; /// Whether to show select all option in toolbar. /// - /// Defaults to false. Must not be null. + /// Defaults to false. final bool selectAll; } @@ -888,7 +888,7 @@ class EditableText extends StatefulWidget { /// copied with copy or cut. If [readOnly] is also true, then the text cannot /// be selected. /// - /// Defaults to false. Cannot be null. + /// Defaults to false. /// {@endtemplate} final bool obscureText; @@ -904,7 +904,7 @@ class EditableText extends StatefulWidget { /// When this is set to true, the text cannot be modified /// by any shortcut or keyboard operation. The text is still selectable. /// - /// Defaults to false. Must not be null. + /// Defaults to false. /// {@endtemplate} final bool readOnly; @@ -913,7 +913,7 @@ class EditableText extends StatefulWidget { /// When this is set to false, the width will be based on text width, which /// will also be affected by [textWidthBasis]. /// - /// Defaults to true. Must not be null. + /// Defaults to true. /// /// See also: /// @@ -953,7 +953,7 @@ class EditableText extends StatefulWidget { /// {@template flutter.widgets.editableText.autocorrect} /// Whether to enable autocorrection. /// - /// Defaults to true. Cannot be null. + /// Defaults to true. /// {@endtemplate} final bool autocorrect; @@ -1009,7 +1009,7 @@ class EditableText extends StatefulWidget { /// {@template flutter.widgets.editableText.textAlign} /// How the text should be aligned horizontally. /// - /// Defaults to [TextAlign.start] and cannot be null. + /// Defaults to [TextAlign.start]. /// {@endtemplate} final TextAlign textAlign; @@ -1037,7 +1037,7 @@ class EditableText extends StatefulWidget { /// Only supports text keyboards, other keyboard types will ignore this /// configuration. Capitalization is locale-aware. /// - /// Defaults to [TextCapitalization.none]. Must not be null. + /// Defaults to [TextCapitalization.none]. /// /// See also: /// @@ -1078,8 +1078,6 @@ class EditableText extends StatefulWidget { final TextScaler? textScaler; /// The color to use when painting the cursor. - /// - /// Cannot be null. final Color cursorColor; /// The color to use when painting the autocorrection Rect. @@ -1233,7 +1231,7 @@ class EditableText extends StatefulWidget { /// If true, the keyboard will open as soon as this text field obtains focus. /// Otherwise, the keyboard is only shown after the user taps the text field. /// - /// Defaults to false. Cannot be null. + /// Defaults to false. /// {@endtemplate} // See https://github.com/flutter/flutter/issues/7035 for the rationale for this // keyboard behavior. diff --git a/packages/flutter/lib/src/widgets/fade_in_image.dart b/packages/flutter/lib/src/widgets/fade_in_image.dart index b489316ef5595..b16f5d3305b0e 100644 --- a/packages/flutter/lib/src/widgets/fade_in_image.dart +++ b/packages/flutter/lib/src/widgets/fade_in_image.dart @@ -71,10 +71,6 @@ class FadeInImage extends StatefulWidget { /// The [placeholder] and [image] may have their own FilterQuality settings via [filterQuality] /// and [placeholderFilterQuality]. /// - /// The [placeholder], [image], [fadeOutDuration], [fadeOutCurve], - /// [fadeInDuration], [fadeInCurve], [alignment], [repeat], and - /// [matchTextDirection] arguments must not be null. - /// /// If [excludeFromSemantics] is true, then [imageSemanticLabel] will be ignored. const FadeInImage({ super.key, @@ -178,10 +174,6 @@ class FadeInImage extends StatefulWidget { /// and [height] regardless of these parameters. These parameters are primarily /// intended to reduce the memory usage of [ImageCache]. /// - /// The [placeholder], [image], [imageScale], [fadeOutDuration], - /// [fadeOutCurve], [fadeInDuration], [fadeInCurve], [alignment], [repeat], - /// and [matchTextDirection] arguments must not be null. - /// /// See also: /// /// * [Image.asset], which has more details about loading images from diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 54efacf0b11cb..69705e477c178 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -417,9 +417,6 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// /// The [debugLabel] is ignored on release builds. /// - /// The [skipTraversal], [descendantsAreFocusable], and [canRequestFocus] - /// arguments must not be null. - /// /// To receive key events that focuses on this node, pass a listener to `onKeyEvent`. /// The `onKey` is a legacy API based on [RawKeyEvent] and will be deprecated /// in the future. diff --git a/packages/flutter/lib/src/widgets/focus_scope.dart b/packages/flutter/lib/src/widgets/focus_scope.dart index 497a9419eed21..766bb0b4afdbc 100644 --- a/packages/flutter/lib/src/widgets/focus_scope.dart +++ b/packages/flutter/lib/src/widgets/focus_scope.dart @@ -111,10 +111,6 @@ import 'inherited_notifier.dart'; /// traversal policy on the [Focus] nodes below it in the widget hierarchy. class Focus extends StatefulWidget { /// Creates a widget that manages a [FocusNode]. - /// - /// The [child] argument is required and must not be null. - /// - /// The [autofocus] argument must not be null. const Focus({ super.key, required this.child, @@ -203,7 +199,7 @@ class Focus extends StatefulWidget { /// If there is more than one widget with autofocus set, then the first one /// added to the tree will get focus. /// - /// Must not be null. Defaults to false. + /// Defaults to false. /// {@endtemplate} final bool autofocus; @@ -350,7 +346,7 @@ class Focus extends StatefulWidget { /// It is not typical to set this to false, as that can affect the semantics /// information available to accessibility systems. /// - /// Must not be null, defaults to true. + /// Defaults to true. /// {@endtemplate} final bool includeSemantics; @@ -746,10 +742,6 @@ class _FocusState extends State<Focus> { /// policy for a widget subtree. class FocusScope extends Focus { /// Creates a widget that manages a [FocusScopeNode]. - /// - /// The [child] argument is required and must not be null. - /// - /// The [autofocus] argument must not be null. const FocusScope({ super.key, FocusScopeNode? node, @@ -870,10 +862,6 @@ class _FocusInheritedScope extends InheritedNotifier<FocusNode> { /// `descendantsAreFocusable` attribute. class ExcludeFocus extends StatelessWidget { /// Const constructor for [ExcludeFocus] widget. - /// - /// The [excluding] argument must not be null. - /// - /// The [child] argument is required, and must not be null. const ExcludeFocus({ super.key, this.excluding = true, diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 13a22d0dc74e7..1212e27c8247a 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -193,8 +193,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { /// traversing forwards (i.e. with [next]), and there is no current focus in /// the nearest [FocusScopeNode] that `currentNode` belongs to. /// - /// The `currentNode` argument must not be null. - /// /// If `ignoreCurrentFocus` is false or not given, this function returns the /// [FocusScopeNode.focusedChild], if set, on the nearest scope of the /// `currentNode`, otherwise, returns the first node from [sortDescendants], @@ -221,8 +219,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { /// traversing backwards (i.e. with [previous]), and there is no current focus /// in the nearest [FocusScopeNode] that `currentNode` belongs to. /// - /// The `currentNode` argument must not be null. - /// /// If `ignoreCurrentFocus` is false or not given, this function returns the /// [FocusScopeNode.focusedChild], if set, on the nearest scope of the /// `currentNode`, otherwise, returns the last node from [sortDescendants], @@ -265,8 +261,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { /// /// This is typically used by [inDirection] to determine which node to focus /// if it is called when no node is currently focused. - /// - /// All arguments must not be null. FocusNode? findFirstFocusInDirection(FocusNode currentNode, TraversalDirection direction); /// Clears the data associated with the given [FocusScopeNode] for this object. @@ -298,8 +292,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { /// the node that has been selected. /// /// Returns true if it successfully found a node and requested focus. - /// - /// The [currentNode] argument must not be null. bool next(FocusNode currentNode) => _moveFocus(currentNode, forward: true); /// Focuses the previous widget in the focus scope that contains the given @@ -310,8 +302,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { /// the node that has been selected. /// /// Returns true if it successfully found a node and requested focus. - /// - /// The [currentNode] argument must not be null. bool previous(FocusNode currentNode) => _moveFocus(currentNode, forward: false); /// Focuses the next widget in the given [direction] in the focus scope that @@ -322,8 +312,6 @@ abstract class FocusTraversalPolicy with Diagnosticable { /// [FocusNode.requestFocus] on the node that has been selected. /// /// Returns true if it successfully found a node and requested focus. - /// - /// All arguments must not be null. bool inDirection(FocusNode currentNode, TraversalDirection direction); /// Sorts the given `descendants` into focus order. @@ -1628,8 +1616,6 @@ class FocusTraversalOrder extends InheritedWidget { /// focus traversal in a direction. class FocusTraversalGroup extends StatefulWidget { /// Creates a [FocusTraversalGroup] object. - /// - /// The [child] and [descendantsAreFocusable] arguments must not be null. FocusTraversalGroup({ super.key, FocusTraversalPolicy? policy, @@ -1839,7 +1825,6 @@ class _FocusTraversalGroupState extends State<FocusTraversalGroup> { class RequestFocusIntent extends Intent { /// Creates an intent used with [RequestFocusAction]. /// - /// The [focusNode] argument must not be null. /// {@macro flutter.widgets.FocusTraversalPolicy.requestFocusCallback} const RequestFocusIntent(this.focusNode, { TraversalRequestFocusCallback? requestFocusCallback @@ -2025,10 +2010,6 @@ class DirectionalFocusAction extends Action<DirectionalFocusIntent> { /// `descendantsAreFocusable` attribute. class ExcludeFocusTraversal extends StatelessWidget { /// Const constructor for [ExcludeFocusTraversal] widget. - /// - /// The [excluding] argument must not be null. - /// - /// The [child] argument is required, and must not be null. const ExcludeFocusTraversal({ super.key, this.excluding = true, diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index ca980ad93304f..3989da3ea429e 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -49,8 +49,6 @@ const Duration _kIOSAnnouncementDelayDuration = Duration(seconds: 1); /// * [TextFormField], a convenience widget that wraps a [TextField] widget in a [FormField]. class Form extends StatefulWidget { /// Creates a container for form fields. - /// - /// The [child] argument must not be null. const Form({ super.key, required this.child, @@ -384,8 +382,6 @@ typedef FormFieldBuilder<T> = Widget Function(FormFieldState<T> field); /// * [TextField], which is a commonly used form field for entering text. class FormField<T> extends StatefulWidget { /// Creates a single form field. - /// - /// The [builder] argument must not be null. const FormField({ super.key, required this.builder, @@ -440,7 +436,7 @@ class FormField<T> extends StatefulWidget { /// will auto-validate even without user interaction. If /// [AutovalidateMode.disabled], auto-validation will be disabled. /// - /// Defaults to [AutovalidateMode.disabled], cannot be null. + /// Defaults to [AutovalidateMode.disabled]. /// {@endtemplate} final AutovalidateMode autovalidateMode; diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index a8724cc3b4a6e..18a2a2e6268c2 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -1976,9 +1976,6 @@ abstract class SingleChildRenderObjectWidget extends RenderObjectWidget { /// its children in named slots. abstract class MultiChildRenderObjectWidget extends RenderObjectWidget { /// Initializes fields for subclasses. - /// - /// The [children] argument must not be null and must not contain any null - /// objects. const MultiChildRenderObjectWidget({ super.key, this.children = const <Widget>[] }); /// The widgets below this widget in the tree. diff --git a/packages/flutter/lib/src/widgets/gesture_detector.dart b/packages/flutter/lib/src/widgets/gesture_detector.dart index eb686b97a552d..43c7caa764683 100644 --- a/packages/flutter/lib/src/widgets/gesture_detector.dart +++ b/packages/flutter/lib/src/widgets/gesture_detector.dart @@ -91,8 +91,6 @@ typedef GestureRecognizerFactoryInitializer<T extends GestureRecognizer> = void /// Used by [RawGestureDetector.gestures]. class GestureRecognizerFactoryWithHandlers<T extends GestureRecognizer> extends GestureRecognizerFactory<T> { /// Creates a gesture recognizer factory with the given callbacks. - /// - /// The arguments must not be null. const GestureRecognizerFactoryWithHandlers(this._constructor, this._initializer); final GestureRecognizerFactoryConstructor<T> _constructor; diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart index f0ff4a7b7f4e6..1edac3cea47c6 100644 --- a/packages/flutter/lib/src/widgets/heroes.dart +++ b/packages/flutter/lib/src/widgets/heroes.dart @@ -170,7 +170,6 @@ enum HeroFlightDirection { class Hero extends StatefulWidget { /// Create a hero. /// - /// The [tag] and [child] parameters must not be null. /// The [child] parameter and all of the its descendants must not be [Hero]es. const Hero({ super.key, @@ -259,7 +258,7 @@ class Hero extends StatefulWidget { /// [PageRoute.maintainState] set to true for a gesture triggered hero /// transition to work. /// - /// Defaults to false and cannot be null. + /// Defaults to false. final bool transitionOnUserGestures; // Returns a map of all of the heroes in `context` indexed by hero tag that @@ -1061,8 +1060,6 @@ class HeroController extends NavigatorObserver { /// hero animations, as usual. class HeroMode extends StatelessWidget { /// Creates a widget that enables or disables [Hero]es. - /// - /// The [child] and [enabled] arguments must not be null. const HeroMode({ super.key, required this.child, @@ -1077,7 +1074,7 @@ class HeroMode extends StatelessWidget { /// If this property is false, the [Hero]es in this subtree will not animate /// on route changes. Otherwise, they will animate as usual. /// - /// Defaults to true and must not be null. + /// Defaults to true. final bool enabled; @override diff --git a/packages/flutter/lib/src/widgets/icon_data.dart b/packages/flutter/lib/src/widgets/icon_data.dart index 214cadcfc5ef2..865d5d10801cd 100644 --- a/packages/flutter/lib/src/widgets/icon_data.dart +++ b/packages/flutter/lib/src/widgets/icon_data.dart @@ -93,8 +93,6 @@ class IconData { /// [DiagnosticsProperty] that has an [IconData] as value. class IconDataProperty extends DiagnosticsProperty<IconData> { /// Create a diagnostics property for [IconData]. - /// - /// The [showName], [style], and [level] arguments must not be null. IconDataProperty( String super.name, super.value, { diff --git a/packages/flutter/lib/src/widgets/icon_theme.dart b/packages/flutter/lib/src/widgets/icon_theme.dart index d27ccf475bb2c..404baaaf0b40d 100644 --- a/packages/flutter/lib/src/widgets/icon_theme.dart +++ b/packages/flutter/lib/src/widgets/icon_theme.dart @@ -17,8 +17,6 @@ import 'inherited_theme.dart'; /// The icon theme is honored by [Icon] and [ImageIcon] widgets. class IconTheme extends InheritedTheme { /// Creates an icon theme that controls properties of descendant widgets. - /// - /// Both [data] and [child] arguments must not be null. const IconTheme({ super.key, required this.data, @@ -27,8 +25,6 @@ class IconTheme extends InheritedTheme { /// Creates an icon theme that controls the properties of /// descendant widgets, and merges in the current icon theme, if any. - /// - /// The [data] and [child] arguments must not be null. static Widget merge({ Key? key, required IconThemeData data, diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 1e0776cd78047..e2871e5e2279f 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart @@ -335,9 +335,6 @@ class Image extends StatefulWidget { /// To show an image from the network or from an asset bundle, consider using /// [Image.network] and [Image.asset] respectively. /// - /// The [image], [alignment], [repeat], and [matchTextDirection] arguments - /// must not be null. - /// /// Either the [width] and [height] arguments should be specified, or the /// widget should be placed in a context that sets tight layout constraints. /// Otherwise, the image dimensions will change as the image is loaded, which @@ -373,8 +370,6 @@ class Image extends StatefulWidget { /// Creates a widget that displays an [ImageStream] obtained from the network. /// - /// The [src], [scale], and [repeat] arguments must not be null. - /// /// Either the [width] and [height] arguments should be specified, or the /// widget should be placed in a context that sets tight layout constraints. /// Otherwise, the image dimensions will change as the image is loaded, which @@ -429,8 +424,6 @@ class Image extends StatefulWidget { /// Creates a widget that displays an [ImageStream] obtained from a [File]. /// - /// The [file], [scale], and [repeat] arguments must not be null. - /// /// Either the [width] and [height] arguments should be specified, or the /// widget should be placed in a context that sets tight layout constraints. /// Otherwise, the image dimensions will change as the image is loaded, which @@ -526,8 +519,6 @@ class Image extends StatefulWidget { /// regardless of these parameters. These parameters are primarily intended /// to reduce the memory usage of [ImageCache]. /// - /// The [name] and [repeat] arguments must not be null. - /// /// Either the [width] and [height] arguments should be specified, or the /// widget should be placed in a context that sets tight layout constraints. /// Otherwise, the image dimensions will change as the image is loaded, which @@ -663,8 +654,6 @@ class Image extends StatefulWidget { /// image at its intended size and applies to both the width and the height. /// {@macro flutter.painting.imageInfo.scale} /// - /// The `bytes`, `scale`, and [repeat] arguments must not be null. - /// /// This only accepts compressed image formats (e.g. PNG). Uncompressed /// formats like rawRgba (the default format of [dart:ui.Image.toByteData]) /// will lead to exceptions. diff --git a/packages/flutter/lib/src/widgets/image_filter.dart b/packages/flutter/lib/src/widgets/image_filter.dart index f7a1785744924..ada948a6ae47c 100644 --- a/packages/flutter/lib/src/widgets/image_filter.dart +++ b/packages/flutter/lib/src/widgets/image_filter.dart @@ -34,8 +34,6 @@ import 'framework.dart'; @immutable class ImageFiltered extends SingleChildRenderObjectWidget { /// Creates a widget that applies an [ImageFilter] to its child. - /// - /// The [imageFilter] must not be null. const ImageFiltered({ super.key, required this.imageFilter, diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index 90ad122c211d0..de234ceab574e 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -274,8 +274,6 @@ class TextStyleTween extends Tween<TextStyle> { /// * [AnimatedSwitcher], which fades from one widget to another. abstract class ImplicitlyAnimatedWidget extends StatefulWidget { /// Initializes fields for subclasses. - /// - /// The [curve] and [duration] arguments must not be null. const ImplicitlyAnimatedWidget({ super.key, this.curve = Curves.linear, @@ -598,8 +596,6 @@ abstract class AnimatedWidgetBaseState<T extends ImplicitlyAnimatedWidget> exten /// * [AnimatedCrossFade], which fades between two children and interpolates their sizes. class AnimatedContainer extends ImplicitlyAnimatedWidget { /// Creates a container that animates its parameters implicitly. - /// - /// The [curve] and [duration] arguments must not be null. AnimatedContainer({ super.key, this.alignment, @@ -805,8 +801,6 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer> class AnimatedPadding extends ImplicitlyAnimatedWidget { /// Creates a widget that insets its child by a value that animates /// implicitly. - /// - /// The [padding], [curve], and [duration] arguments must not be null. AnimatedPadding({ super.key, required this.padding, @@ -893,8 +887,6 @@ class _AnimatedPaddingState extends AnimatedWidgetBaseState<AnimatedPadding> { class AnimatedAlign extends ImplicitlyAnimatedWidget { /// Creates a widget that positions its child by an alignment that animates /// implicitly. - /// - /// The [alignment], [curve], and [duration] arguments must not be null. const AnimatedAlign({ super.key, required this.alignment, @@ -1031,8 +1023,6 @@ class AnimatedPositioned extends ImplicitlyAnimatedWidget { /// [width]), and only two out of the three vertical values ([top], /// [bottom], [height]), can be set. In each case, at least one of /// the three must be null. - /// - /// The [curve] and [duration] arguments must not be null. const AnimatedPositioned({ super.key, required this.child, @@ -1049,8 +1039,6 @@ class AnimatedPositioned extends ImplicitlyAnimatedWidget { assert(top == null || bottom == null || height == null); /// Creates a widget that animates the rectangle it occupies implicitly. - /// - /// The [curve] and [duration] arguments must not be null. AnimatedPositioned.fromRect({ super.key, required this.child, @@ -1182,8 +1170,6 @@ class AnimatedPositionedDirectional extends ImplicitlyAnimatedWidget { /// Only two out of the three horizontal values ([start], [end], [width]), and /// only two out of the three vertical values ([top], [bottom], [height]), can /// be set. In each case, at least one of the three must be null. - /// - /// The [curve] and [duration] arguments must not be null. const AnimatedPositionedDirectional({ super.key, required this.child, @@ -1345,9 +1331,6 @@ class _AnimatedPositionedDirectionalState extends AnimatedWidgetBaseState<Animat /// an [Animation] is provided by the caller instead of being built in. class AnimatedScale extends ImplicitlyAnimatedWidget { /// Creates a widget that animates its scale implicitly. - /// - /// The [scale] argument must not be null. - /// The [curve] and [duration] arguments must not be null. const AnimatedScale({ super.key, this.child, @@ -1365,8 +1348,6 @@ class AnimatedScale extends ImplicitlyAnimatedWidget { final Widget? child; /// The target scale. - /// - /// The scale must not be null. final double scale; /// The alignment of the origin of the coordinate system in which the scale @@ -1472,9 +1453,6 @@ class _AnimatedScaleState extends ImplicitlyAnimatedWidgetState<AnimatedScale> { /// an [Animation] is provided by the caller instead of being built in. class AnimatedRotation extends ImplicitlyAnimatedWidget { /// Creates a widget that animates its rotation implicitly. - /// - /// The [turns] argument must not be null. - /// The [curve] and [duration] arguments must not be null. const AnimatedRotation({ super.key, this.child, @@ -1569,8 +1547,6 @@ class _AnimatedRotationState extends ImplicitlyAnimatedWidgetState<AnimatedRotat /// position over a given duration whenever the given [AnimatedAlign.alignment] changes. class AnimatedSlide extends ImplicitlyAnimatedWidget { /// Creates a widget that animates its offset translation implicitly. - /// - /// The [offset] and [duration] arguments must not be null. const AnimatedSlide({ super.key, this.child, @@ -1587,8 +1563,6 @@ class AnimatedSlide extends ImplicitlyAnimatedWidget { /// The target offset. /// The child will be translated horizontally by `width * dx` and vertically by `height * dy` - /// - /// The offset must not be null. final Offset offset; @override @@ -1703,8 +1677,7 @@ class _AnimatedSlideState extends ImplicitlyAnimatedWidgetState<AnimatedSlide> { class AnimatedOpacity extends ImplicitlyAnimatedWidget { /// Creates a widget that animates its opacity implicitly. /// - /// The [opacity] argument must not be null and must be between 0.0 and 1.0, - /// inclusive. The [curve] and [duration] arguments must not be null. + /// The [opacity] argument must be between zero and one, inclusive. const AnimatedOpacity({ super.key, this.child, @@ -1724,8 +1697,6 @@ class AnimatedOpacity extends ImplicitlyAnimatedWidget { /// /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent /// (i.e., invisible). - /// - /// The opacity must not be null. final double opacity; /// Whether the semantic information of the children is always included. @@ -1817,8 +1788,7 @@ class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState<AnimatedOpacit class SliverAnimatedOpacity extends ImplicitlyAnimatedWidget { /// Creates a widget that animates its opacity implicitly. /// - /// The [opacity] argument must not be null and must be between 0.0 and 1.0, - /// inclusive. The [curve] and [duration] arguments must not be null. + /// The [opacity] argument must be between zero and one, inclusive. const SliverAnimatedOpacity({ super.key, this.sliver, @@ -1836,8 +1806,6 @@ class SliverAnimatedOpacity extends ImplicitlyAnimatedWidget { /// /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent /// (i.e., invisible). - /// - /// The opacity must not be null. final double opacity; /// Whether the semantic information of the children is always included. @@ -1906,9 +1874,6 @@ class _SliverAnimatedOpacityState extends ImplicitlyAnimatedWidgetState<SliverAn /// the lifecycle of the underlying [AnimationController]. class AnimatedDefaultTextStyle extends ImplicitlyAnimatedWidget { /// Creates a widget that animates the default text style implicitly. - /// - /// The [child], [style], [softWrap], [overflow], [curve], and [duration] - /// arguments must not be null. const AnimatedDefaultTextStyle({ super.key, required this.child, @@ -1931,8 +1896,6 @@ class AnimatedDefaultTextStyle extends ImplicitlyAnimatedWidget { /// The target text style. /// - /// The text style must not be null. - /// /// When this property is changed, the style will be animated over [duration] time. final TextStyle style; @@ -2024,9 +1987,7 @@ class _AnimatedDefaultTextStyleState extends AnimatedWidgetBaseState<AnimatedDef class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget { /// Creates a widget that animates the properties of a [PhysicalModel]. /// - /// The [child], [shape], [borderRadius], [elevation], [color], [shadowColor], - /// [curve], [clipBehavior], and [duration] arguments must not be null. - /// Additionally, [elevation] must be non-negative. + /// The [elevation] must be non-negative. /// /// Animating [color] is optional and is controlled by the [animateColor] flag. /// @@ -2159,7 +2120,6 @@ class AnimatedFractionallySizedBox extends ImplicitlyAnimatedWidget { /// space that animates implicitly, and positions its child by an alignment /// that animates implicitly. /// - /// The [curve] and [duration] argument must not be null /// If non-null, the [widthFactor] and [heightFactor] arguments must be /// non-negative. const AnimatedFractionallySizedBox({ diff --git a/packages/flutter/lib/src/widgets/inherited_notifier.dart b/packages/flutter/lib/src/widgets/inherited_notifier.dart index c6ce2ce401926..a3f09cd983255 100644 --- a/packages/flutter/lib/src/widgets/inherited_notifier.dart +++ b/packages/flutter/lib/src/widgets/inherited_notifier.dart @@ -58,8 +58,6 @@ import 'framework.dart'; abstract class InheritedNotifier<T extends Listenable> extends InheritedWidget { /// Create an inherited widget that updates its dependents when [notifier] /// sends notifications. - /// - /// The [child] argument must not be null. const InheritedNotifier({ super.key, this.notifier, diff --git a/packages/flutter/lib/src/widgets/interactive_viewer.dart b/packages/flutter/lib/src/widgets/interactive_viewer.dart index a0ee8fafa6fa7..9ed589af7bb52 100644 --- a/packages/flutter/lib/src/widgets/interactive_viewer.dart +++ b/packages/flutter/lib/src/widgets/interactive_viewer.dart @@ -44,8 +44,6 @@ typedef InteractiveViewerWidgetBuilder = Widget Function(BuildContext context, Q /// don't set [clipBehavior] or be sure that the InteractiveViewer widget is the /// size of the area that should be interactive. /// -/// The [child] must not be null. -/// /// See also: /// * The [Flutter Gallery's transformations demo](https://github.com/flutter/gallery/blob/master/lib/demos/reference/transformations_demo.dart), /// which includes the use of InteractiveViewer. @@ -62,8 +60,6 @@ typedef InteractiveViewerWidgetBuilder = Widget Function(BuildContext context, Q @immutable class InteractiveViewer extends StatefulWidget { /// Create an InteractiveViewer. - /// - /// The [child] parameter must not be null. InteractiveViewer({ super.key, this.clipBehavior = Clip.hardEdge, @@ -111,8 +107,8 @@ class InteractiveViewer extends StatefulWidget { /// Can be used to render a child that changes in response to the current /// transformation. /// - /// The [builder] parameter must not be null. See its docs for an example of - /// using it to optimize a large child. + /// See the [builder] attribute docs for an example of using it to optimize a + /// large child. InteractiveViewer.builder({ super.key, this.clipBehavior = Clip.hardEdge, @@ -307,7 +303,7 @@ class InteractiveViewer extends StatefulWidget { /// /// Defaults to 2.5. /// - /// Cannot be null, and must be greater than zero and greater than minScale. + /// Must be greater than zero and greater than [minScale]. final double maxScale; /// The minimum allowed scale. @@ -321,15 +317,14 @@ class InteractiveViewer extends StatefulWidget { /// /// Defaults to 0.8. /// - /// Cannot be null, and must be a finite number greater than zero and less - /// than maxScale. + /// Must be a finite number greater than zero and less than [maxScale]. final double minScale; /// Changes the deceleration behavior after a gesture. /// /// Defaults to 0.0000135. /// - /// Cannot be null, and must be a finite number greater than zero. + /// Must be a finite number greater than zero. final double interactionEndFrictionCoefficient; /// Called when the user ends a pan or scale gesture on the widget. diff --git a/packages/flutter/lib/src/widgets/keyboard_listener.dart b/packages/flutter/lib/src/widgets/keyboard_listener.dart index 0f43379c49819..e339807076193 100644 --- a/packages/flutter/lib/src/widgets/keyboard_listener.dart +++ b/packages/flutter/lib/src/widgets/keyboard_listener.dart @@ -37,10 +37,6 @@ class KeyboardListener extends StatelessWidget { /// For text entry, consider using a [EditableText], which integrates with /// on-screen keyboards and input method editors (IMEs). /// - /// The [focusNode] and [child] arguments are required and must not be null. - /// - /// The [autofocus] argument must not be null. - /// /// The `key` is an identifier for widgets, and is unrelated to keyboards. /// See [Widget.key]. const KeyboardListener({ diff --git a/packages/flutter/lib/src/widgets/layout_builder.dart b/packages/flutter/lib/src/widgets/layout_builder.dart index b2c8638a197d8..d7e489bc052f4 100644 --- a/packages/flutter/lib/src/widgets/layout_builder.dart +++ b/packages/flutter/lib/src/widgets/layout_builder.dart @@ -34,9 +34,6 @@ typedef LayoutWidgetBuilder = Widget Function(BuildContext context, BoxConstrain /// [RenderConstrainedLayoutBuilder]. abstract class ConstrainedLayoutBuilder<ConstraintType extends Constraints> extends RenderObjectWidget { /// Creates a widget that defers its building until layout. - /// - /// The [builder] argument must not be null, and the returned widget should not - /// be null. const ConstrainedLayoutBuilder({ super.key, required this.builder, @@ -262,8 +259,6 @@ mixin RenderConstrainedLayoutBuilder<ConstraintType extends Constraints, ChildTy /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class LayoutBuilder extends ConstrainedLayoutBuilder<BoxConstraints> { /// Creates a widget that defers its building until layout. - /// - /// The [builder] argument must not be null. const LayoutBuilder({ super.key, required super.builder, diff --git a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart index 96f56b2d026d1..6a20487ebe216 100644 --- a/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/list_wheel_scroll_view.dart @@ -214,14 +214,14 @@ class ListWheelChildBuilderDelegate extends ListWheelChildDelegate { class FixedExtentScrollController extends ScrollController { /// Creates a scroll controller for scrollables whose items have the same size. /// - /// [initialItem] defaults to 0 and must not be null. + /// [initialItem] defaults to zero. FixedExtentScrollController({ this.initialItem = 0, }); /// The page to show when first creating the scroll view. /// - /// Defaults to 0 and must not be null. + /// Defaults to zero. final int initialItem; /// The currently selected item index that's closest to the center of the viewport. @@ -254,8 +254,6 @@ class FixedExtentScrollController extends ScrollController { /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. - /// - /// The `duration` and `curve` arguments must not be null. Future<void> animateToItem( int itemIndex, { required Duration duration, @@ -665,8 +663,9 @@ class ListWheelScrollView extends StatefulWidget { /// {@macro flutter.rendering.RenderListWheelViewport.overAndUnderCenterOpacity} final double overAndUnderCenterOpacity; - /// Size of each child in the main axis. Must not be null and must be - /// positive. + /// Size of each child in the main axis. + /// + /// Must be positive. final double itemExtent; /// {@macro flutter.rendering.RenderListWheelViewport.squeeze} @@ -940,18 +939,18 @@ class ListWheelElement extends RenderObjectElement implements ListWheelChildMana class ListWheelViewport extends RenderObjectWidget { /// Creates a viewport where children are rendered onto a wheel. /// - /// The [diameterRatio] argument defaults to 2.0 and must not be null. + /// The [diameterRatio] argument defaults to 2. /// - /// The [perspective] argument defaults to 0.003 and must not be null. + /// The [perspective] argument defaults to 0.003. /// /// The [itemExtent] argument in pixels must be provided and must be positive. /// - /// The [clipBehavior] argument defaults to [Clip.hardEdge] and must not be null. + /// The [clipBehavior] argument defaults to [Clip.hardEdge]. /// /// The [renderChildrenOutsideViewport] argument defaults to false and must /// not be null. /// - /// The [offset] argument must be provided and must not be null. + /// The [offset] argument must be provided. const ListWheelViewport({ super.key, this.diameterRatio = RenderListWheelViewport.defaultDiameterRatio, diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index 5e4272f497326..f0544de55a18d 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -616,8 +616,8 @@ class MediaQueryData { /// Creates a copy of this media query data but with the given [padding]s /// replaced with zero. /// - /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments - /// must not be null. If all four are false (the default) then this + /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and + /// `removeBottom` arguments are false (the default), then this /// [MediaQueryData] is returned unmodified. /// /// See also: @@ -656,8 +656,8 @@ class MediaQueryData { /// Creates a copy of this media query data but with the given [viewInsets] /// replaced with zero. /// - /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments - /// must not be null. If all four are false (the default) then this + /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and + /// `removeBottom` arguments are false (the default), then this /// [MediaQueryData] is returned unmodified. /// /// See also: @@ -694,8 +694,8 @@ class MediaQueryData { /// Creates a copy of this media query data but with the given [viewPadding] /// replaced with zero. /// - /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments - /// must not be null. If all four are false (the default) then this + /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and + /// `removeBottom` arguments are false (the default), then this /// [MediaQueryData] is returned unmodified. /// /// See also: @@ -884,8 +884,6 @@ class MediaQueryData { /// * [MediaQueryData], the data structure that represents the metrics. class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// Creates a widget that provides [MediaQueryData] to its descendants. - /// - /// The [data] and [child] arguments must not be null. const MediaQuery({ super.key, required this.data, @@ -899,16 +897,13 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// is consumed by a widget in such a way that the padding is no longer /// exposed to the widget's descendants or siblings. /// - /// The [context] argument is required, must not be null, and must have a - /// [MediaQuery] in scope. + /// The [context] argument must have a [MediaQuery] in scope. /// - /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments - /// must not be null. If all four are false (the default) then the returned + /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and + /// `removeBottom` arguments are false (the default), then the returned /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not /// particularly useful. /// - /// The [child] argument is required and must not be null. - /// /// See also: /// /// * [SafeArea], which both removes the padding from the [MediaQuery] and @@ -946,16 +941,13 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// insets are consumed by a widget in such a way that the view insets are no /// longer exposed to the widget's descendants or siblings. /// - /// The [context] argument is required, must not be null, and must have a - /// [MediaQuery] in scope. + /// The [context] argument must have a [MediaQuery] in scope. /// - /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments - /// must not be null. If all four are false (the default) then the returned + /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and + /// `removeBottom` arguments are false (the default), then the returned /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not /// particularly useful. /// - /// The [child] argument is required and must not be null. - /// /// See also: /// /// * [MediaQueryData.viewInsets], the affected property of the @@ -991,16 +983,13 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// padding is consumed by a widget in such a way that the view padding is no /// longer exposed to the widget's descendants or siblings. /// - /// The [context] argument is required, must not be null, and must have a - /// [MediaQuery] in scope. + /// The [context] argument must have a [MediaQuery] in scope. /// - /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments - /// must not be null. If all four are false (the default) then the returned + /// If all four of the `removeLeft`, `removeTop`, `removeRight`, and + /// `removeBottom` arguments are false (the default), then the returned /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not /// particularly useful. /// - /// The [child] argument is required and must not be null. - /// /// See also: /// /// * [MediaQueryData.viewPadding], the affected property of the @@ -1069,8 +1058,6 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { /// /// The injected [MediaQuery] automatically updates when any of the data used /// to construct it changes. - /// - /// The [view] and [child] arguments are required and must not be null. static Widget fromView({ Key? key, required FlutterView view, diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 4fbf1a6a5aec3..efb0fcf2e1b80 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -613,8 +613,6 @@ class RouteSettings { /// history. abstract class Page<T> extends RouteSettings { /// Creates a page and initializes [key] for subclasses. - /// - /// The [arguments] argument must not be null. const Page({ this.key, super.name, @@ -1451,9 +1449,6 @@ const TraversalEdgeBehavior kDefaultRouteTraversalEdgeBehavior = kIsWeb class Navigator extends StatefulWidget { /// Creates a widget that maintains a stack-based history of child widgets. /// - /// The [onGenerateRoute], [pages], [onGenerateInitialRoutes], - /// [transitionDelegate], [observers] arguments must not be null. - /// /// If the [pages] is not empty, the [onPopPage] must not be null. const Navigator({ super.key, @@ -1520,7 +1515,7 @@ class Navigator extends StatefulWidget { /// The delegate used for deciding how routes transition in or off the screen /// during the [pages] updates. /// - /// Defaults to [DefaultTransitionDelegate] if not specified, cannot be null. + /// Defaults to [DefaultTransitionDelegate]. final TransitionDelegate<dynamic> transitionDelegate; /// The name of the first route to show. @@ -1652,7 +1647,7 @@ class Navigator extends StatefulWidget { /// In cases where clipping is not desired, consider setting this property to /// [Clip.none]. /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; /// Whether or not the navigator and it's new topmost route should request focus @@ -5909,8 +5904,6 @@ typedef RouteCompletionCallback<T> = void Function(T result); /// {@end-tool} class RestorableRouteFuture<T> extends RestorableProperty<String?> { /// Creates a [RestorableRouteFuture]. - /// - /// The [onPresent] and [navigatorFinder] arguments must not be null. RestorableRouteFuture({ this.navigatorFinder = _defaultNavigatorFinder, required this.onPresent, diff --git a/packages/flutter/lib/src/widgets/nested_scroll_view.dart b/packages/flutter/lib/src/widgets/nested_scroll_view.dart index 020f3dc195a75..da872cce9cfd7 100644 --- a/packages/flutter/lib/src/widgets/nested_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/nested_scroll_view.dart @@ -289,7 +289,7 @@ class NestedScrollView extends StatefulWidget { /// outer scrollable over the inner when scrolling back. /// /// This is useful for an outer scrollable containing a [SliverAppBar] that - /// is expected to float. This cannot be null. + /// is expected to float. final bool floatHeaderSlivers; /// {@macro flutter.material.Material.clipBehavior} @@ -1698,8 +1698,6 @@ class SliverOverlapAbsorberHandle extends ChangeNotifier { class SliverOverlapAbsorber extends SingleChildRenderObjectWidget { /// Creates a sliver that absorbs overlap and reports it to a /// [SliverOverlapAbsorberHandle]. - /// - /// The [handle] must not be null. const SliverOverlapAbsorber({ super.key, required this.handle, @@ -1742,8 +1740,6 @@ class RenderSliverOverlapAbsorber extends RenderSliver with RenderObjectWithChil /// Create a sliver that absorbs overlap and reports it to a /// [SliverOverlapAbsorberHandle]. /// - /// The [handle] must not be null. - /// /// The [sliver] must be a [RenderSliver]. RenderSliverOverlapAbsorber({ required SliverOverlapAbsorberHandle handle, @@ -1849,8 +1845,6 @@ class RenderSliverOverlapAbsorber extends RenderSliver with RenderObjectWithChil class SliverOverlapInjector extends SingleChildRenderObjectWidget { /// Creates a sliver that is as tall as the value of the given [handle]'s /// layout extent. - /// - /// The [handle] must not be null. const SliverOverlapInjector({ super.key, required this.handle, @@ -1891,8 +1885,6 @@ class SliverOverlapInjector extends SingleChildRenderObjectWidget { /// during a particular frame. class RenderSliverOverlapInjector extends RenderSliver { /// Creates a sliver that is as tall as the value of the given [handle]'s extent. - /// - /// The [handle] must not be null. RenderSliverOverlapInjector({ required SliverOverlapAbsorberHandle handle, }) : _handle = handle; @@ -2013,8 +2005,6 @@ class RenderSliverOverlapInjector extends RenderSliver { /// the viewport needs to recompute its layout (e.g. when it is scrolled). class NestedScrollViewViewport extends Viewport { /// Creates a variant of [Viewport] that has a [SliverOverlapAbsorberHandle]. - /// - /// The [handle] must not be null. NestedScrollViewViewport({ super.key, super.axisDirection, @@ -2073,8 +2063,6 @@ class NestedScrollViewViewport extends Viewport { class RenderNestedScrollViewViewport extends RenderViewport { /// Create a variant of [RenderViewport] that has a /// [SliverOverlapAbsorberHandle]. - /// - /// The [handle] must not be null. RenderNestedScrollViewViewport({ super.axisDirection, required super.crossAxisDirection, diff --git a/packages/flutter/lib/src/widgets/orientation_builder.dart b/packages/flutter/lib/src/widgets/orientation_builder.dart index 6289374af0b49..3ef6face3daf8 100644 --- a/packages/flutter/lib/src/widgets/orientation_builder.dart +++ b/packages/flutter/lib/src/widgets/orientation_builder.dart @@ -26,8 +26,6 @@ typedef OrientationWidgetBuilder = Widget Function(BuildContext context, Orienta /// landscape or portrait mode. class OrientationBuilder extends StatelessWidget { /// Creates an orientation builder. - /// - /// The [builder] argument must not be null. const OrientationBuilder({ super.key, required this.builder, diff --git a/packages/flutter/lib/src/widgets/overflow_bar.dart b/packages/flutter/lib/src/widgets/overflow_bar.dart index b71e1686ca6a5..75291df635af6 100644 --- a/packages/flutter/lib/src/widgets/overflow_bar.dart +++ b/packages/flutter/lib/src/widgets/overflow_bar.dart @@ -54,11 +54,6 @@ enum OverflowBarAlignment { /// {@end-tool} class OverflowBar extends MultiChildRenderObjectWidget { /// Constructs an OverflowBar. - /// - /// The [spacing], [overflowSpacing], [overflowAlignment], - /// [overflowDirection], and [clipBehavior] parameters must not be - /// null. The [children] argument must not be null and must not contain - /// any null objects. const OverflowBar({ super.key, this.spacing = 0.0, @@ -199,7 +194,7 @@ class OverflowBar extends MultiChildRenderObjectWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. final Clip clipBehavior; @override diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart index 4a0d6ef2becfc..d689e10769082 100644 --- a/packages/flutter/lib/src/widgets/overlay.dart +++ b/packages/flutter/lib/src/widgets/overlay.dart @@ -431,7 +431,7 @@ class Overlay extends StatefulWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; /// The [OverlayState] from the closest instance of [Overlay] that encloses @@ -1011,7 +1011,7 @@ class _RenderTheater extends RenderBox with ContainerRenderObjectMixin<RenderBox /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.hardEdge; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/widgets/overscroll_indicator.dart b/packages/flutter/lib/src/widgets/overscroll_indicator.dart index 810cbf6fab694..ef198d769be64 100644 --- a/packages/flutter/lib/src/widgets/overscroll_indicator.dart +++ b/packages/flutter/lib/src/widgets/overscroll_indicator.dart @@ -79,9 +79,6 @@ class GlowingOverscrollIndicator extends StatefulWidget { /// In order for this widget to display an overscroll indication, the [child] /// widget must contain a widget that generates a [ScrollNotification], such /// as a [ListView] or a [GridView]. - /// - /// The [showLeading], [showTrailing], [axisDirection], [color], and - /// [notificationPredicate] arguments must not be null. const GlowingOverscrollIndicator({ super.key, this.showLeading = true, @@ -633,8 +630,6 @@ class StretchingOverscrollIndicator extends StatefulWidget { /// In order for this widget to display an overscroll indication, the [child] /// widget must contain a widget that generates a [ScrollNotification], such /// as a [ListView] or a [GridView]. - /// - /// The [axisDirection] and [notificationPredicate] arguments must not be null. const StretchingOverscrollIndicator({ super.key, required this.axisDirection, @@ -952,8 +947,6 @@ class _StretchController extends ChangeNotifier { class OverscrollIndicatorNotification extends Notification with ViewportNotificationMixin { /// Creates a notification that an [GlowingOverscrollIndicator] or a /// [StretchingOverscrollIndicator] will start showing an overscroll indication. - /// - /// The [leading] argument must not be null. OverscrollIndicatorNotification({ required this.leading, }); @@ -984,7 +977,7 @@ class OverscrollIndicatorNotification extends Notification with ViewportNotifica /// Calling [disallowIndicator] sets this to false, preventing the over scroll /// indicator from showing. /// - /// Defaults to true, cannot be null. + /// Defaults to true. bool accepted = true; /// Call this method if the overscroll indicator should be prevented. diff --git a/packages/flutter/lib/src/widgets/page_storage.dart b/packages/flutter/lib/src/widgets/page_storage.dart index 0a0da4e4103ba..808274172c681 100644 --- a/packages/flutter/lib/src/widgets/page_storage.dart +++ b/packages/flutter/lib/src/widgets/page_storage.dart @@ -159,8 +159,6 @@ class PageStorageBucket { /// * [ModalRoute], which includes this class. class PageStorage extends StatelessWidget { /// Creates a widget that provides a storage bucket for its descendants. - /// - /// The [bucket] argument must not be null. const PageStorage({ super.key, required this.bucket, diff --git a/packages/flutter/lib/src/widgets/page_view.dart b/packages/flutter/lib/src/widgets/page_view.dart index 5d75be724366e..ddd0603edc474 100644 --- a/packages/flutter/lib/src/widgets/page_view.dart +++ b/packages/flutter/lib/src/widgets/page_view.dart @@ -112,8 +112,6 @@ import 'viewport.dart'; /// {@end-tool} class PageController extends ScrollController { /// Creates a page controller. - /// - /// The [initialPage], [keepPage], and [viewportFraction] arguments must not be null. PageController({ this.initialPage = 0, this.keepPage = true, @@ -183,8 +181,6 @@ class PageController extends ScrollController { /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. - /// - /// The `duration` and `curve` arguments must not be null. Future<void> animateToPage( int page, { required Duration duration, @@ -221,8 +217,6 @@ class PageController extends ScrollController { /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. - /// - /// The `duration` and `curve` arguments must not be null. Future<void> nextPage({ required Duration duration, required Curve curve }) { return animateToPage(page!.round() + 1, duration: duration, curve: curve); } @@ -231,8 +225,6 @@ class PageController extends ScrollController { /// /// The animation lasts for the given duration and follows the given curve. /// The returned [Future] resolves when the animation completes. - /// - /// The `duration` and `curve` arguments must not be null. Future<void> previousPage({ required Duration duration, required Curve curve }) { return animateToPage(page!.round() - 1, duration: duration, curve: curve); } @@ -642,10 +634,10 @@ class PageView extends StatefulWidget { /// See the documentation at [SliverChildListDelegate.children] for more details. /// /// {@template flutter.widgets.PageView.allowImplicitScrolling} - /// The [allowImplicitScrolling] parameter must not be null. If true, the - /// [PageView] will participate in accessibility scrolling more like a - /// [ListView], where implicit scroll actions will move to the next page - /// rather than into the contents of the [PageView]. + /// If [allowImplicitScrolling] is true, the [PageView] will participate in + /// accessibility scrolling more like a [ListView], where implicit scroll + /// actions will move to the next page rather than into the contents of the + /// [PageView]. /// {@endtemplate} PageView({ super.key, @@ -917,7 +909,7 @@ class PageView extends StatefulWidget { /// /// If [PageController.viewportFraction] >= 1.0, this property has no effect. /// - /// This property defaults to true and must not be null. + /// This property defaults to true. final bool padEnds; @override diff --git a/packages/flutter/lib/src/widgets/pages.dart b/packages/flutter/lib/src/widgets/pages.dart index 989beb1f4283b..2399efba7388d 100644 --- a/packages/flutter/lib/src/widgets/pages.dart +++ b/packages/flutter/lib/src/widgets/pages.dart @@ -70,9 +70,6 @@ Widget _defaultTransitionsBuilder(BuildContext context, Animation<double> animat /// * [Route], which documents the meaning of the `T` generic type argument. class PageRouteBuilder<T> extends PageRoute<T> { /// Creates a route that delegates to builder callbacks. - /// - /// The [pageBuilder], [transitionsBuilder], [opaque], [barrierDismissible], - /// [maintainState], and [fullscreenDialog] arguments must not be null. PageRouteBuilder({ super.settings, required this.pageBuilder, diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index f8c2144c63693..9916b34782c57 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -66,7 +66,6 @@ class AndroidView extends StatefulWidget { /// Creates a widget that embeds an Android view. /// /// {@template flutter.widgets.AndroidView.constructorArgs} - /// The `viewType` and `hitTestBehavior` parameters must not be null. /// If `creationParams` is not null then `creationParamsCodec` must not be null. /// {@endtemplate} const AndroidView({ @@ -189,7 +188,7 @@ class AndroidView extends StatefulWidget { /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.hardEdge], and must not be null. + /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; @override @@ -939,8 +938,6 @@ typedef CreatePlatformViewCallback = PlatformViewController Function(PlatformVie class PlatformViewLink extends StatefulWidget { /// Construct a [PlatformViewLink] widget. /// - /// The `surfaceFactory` and the `onCreatePlatformView` must not be null. - /// /// See also: /// /// * [PlatformViewSurface] for details on the widget returned by `surfaceFactory`. @@ -1082,8 +1079,6 @@ class _PlatformViewLinkState extends State<PlatformViewLink> { class PlatformViewSurface extends LeafRenderObjectWidget { /// Construct a [PlatformViewSurface]. - /// - /// The [controller] must not be null. const PlatformViewSurface({ super.key, required this.controller, diff --git a/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart b/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart index 832a1f6862bf0..46e611f6d22ff 100644 --- a/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart +++ b/packages/flutter/lib/src/widgets/raw_keyboard_listener.dart @@ -36,10 +36,6 @@ class RawKeyboardListener extends StatefulWidget { /// /// For text entry, consider using a [EditableText], which integrates with /// on-screen keyboards and input method editors (IMEs). - /// - /// The [focusNode] and [child] arguments are required and must not be null. - /// - /// The [autofocus] argument must not be null. const RawKeyboardListener({ super.key, required this.focusNode, diff --git a/packages/flutter/lib/src/widgets/restoration.dart b/packages/flutter/lib/src/widgets/restoration.dart index f3585417a0e63..7f532552c008a 100644 --- a/packages/flutter/lib/src/widgets/restoration.dart +++ b/packages/flutter/lib/src/widgets/restoration.dart @@ -54,8 +54,6 @@ class RestorationScope extends StatefulWidget { /// /// Providing null as the [restorationId] turns off state restoration for /// the [child] and its descendants. - /// - /// The [child] must not be null. const RestorationScope({ super.key, required this.restorationId, @@ -199,8 +197,6 @@ class UnmanagedRestorationScope extends InheritedWidget { /// /// When [bucket] is null state restoration is turned off for the [child] and /// its descendants. - /// - /// The [child] must not be null. const UnmanagedRestorationScope({ super.key, this.bucket, @@ -273,8 +269,6 @@ class RootRestorationScope extends StatefulWidget { /// /// Providing null as the [restorationId] turns off state restoration for /// the [child] and its descendants. - /// - /// The [child] must not be null. const RootRestorationScope({ super.key, required this.restorationId, diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart index c396a949ecf2a..04924fcfd82be 100644 --- a/packages/flutter/lib/src/widgets/router.dart +++ b/packages/flutter/lib/src/widgets/router.dart @@ -42,7 +42,7 @@ import 'restoration_properties.dart'; class RouteInformation { /// Creates a route information object. /// - /// Either location or uri must not be null. + /// Either `location` or `uri` must not be null. const RouteInformation({ @Deprecated( 'Pass Uri.parse(location) to uri parameter instead. ' @@ -120,19 +120,19 @@ class RouteInformation { /// and [BackButtonDispatcher]. This abstract class provides way to bundle these /// delegates into a single object to configure a [Router]. /// -/// The [routerDelegate] must not be null. The [backButtonDispatcher], -/// [routeInformationProvider], and [routeInformationProvider] are optional. +/// The [backButtonDispatcher], [routeInformationProvider], and +/// [routeInformationProvider] are optional. /// /// The [routeInformationProvider] and [routeInformationParser] must -/// both be provided or not provided. +/// both be provided or both not provided. class RouterConfig<T> { /// Creates a [RouterConfig]. /// - /// The [routerDelegate] must not be null. The [backButtonDispatcher], - /// [routeInformationProvider], and [routeInformationParser] are optional. + /// The [backButtonDispatcher], [routeInformationProvider], and + /// [routeInformationParser] are optional. /// - /// The [routeInformationProvider] and [routeInformationParser] must - /// both be provided or not provided. + /// The [routeInformationProvider] and [routeInformationParser] must both be + /// provided or both not provided. const RouterConfig({ this.routeInformationProvider, this.routeInformationParser, @@ -357,8 +357,6 @@ class Router<T> extends StatefulWidget { /// /// The [routeInformationProvider] and [routeInformationParser] must /// both be provided or not provided. - /// - /// The [routerDelegate] must not be null. const Router({ super.key, this.routeInformationProvider, @@ -381,8 +379,6 @@ class Router<T> extends StatefulWidget { /// If the [RouterConfig.routeInformationProvider] is not null, then /// [RouterConfig.routeInformationParser] must also not be /// null. - /// - /// The [RouterConfig.routerDelegate] must not be null. factory Router.withConfig({ Key? key, required RouterConfig<T> config, @@ -1083,8 +1079,6 @@ class RootBackButtonDispatcher extends BackButtonDispatcher with WidgetsBindingO /// [parent] of the [ChildBackButtonDispatcher]. class ChildBackButtonDispatcher extends BackButtonDispatcher { /// Creates a back button dispatcher that acts as the child of another. - /// - /// The [parent] must not be null. ChildBackButtonDispatcher(this.parent); /// The back button dispatcher that this object will attempt to take priority @@ -1139,8 +1133,6 @@ class ChildBackButtonDispatcher extends BackButtonDispatcher { /// screen but don't want to use a new page for that. class BackButtonListener extends StatefulWidget { /// Creates a BackButtonListener widget . - /// - /// The [child] and [onBackButtonPressed] arguments must not be null. const BackButtonListener({ super.key, required this.child, diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index d36236d5d66f1..6edc488d03765 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -2168,8 +2168,7 @@ class RawDialogRoute<T> extends PopupRoute<T> { /// is dimmed with a [ModalBarrier]. The widget returned by the `pageBuilder` /// does not share a context with the location that [showGeneralDialog] is /// originally called from. Use a [StatefulBuilder] or a custom -/// [StatefulWidget] if the dialog needs to update dynamically. The -/// `pageBuilder` argument can not be null. +/// [StatefulWidget] if the dialog needs to update dynamically. /// /// The `context` argument is used to look up the [Navigator] for the /// dialog. It is only used when the method is called. Its corresponding widget diff --git a/packages/flutter/lib/src/widgets/safe_area.dart b/packages/flutter/lib/src/widgets/safe_area.dart index a9208d5f0c54a..93048ea3a7a10 100644 --- a/packages/flutter/lib/src/widgets/safe_area.dart +++ b/packages/flutter/lib/src/widgets/safe_area.dart @@ -146,8 +146,6 @@ class SafeArea extends StatelessWidget { /// system. class SliverSafeArea extends StatelessWidget { /// Creates a sliver that avoids operating system interfaces. - /// - /// The [left], [top], [right], [bottom], and [minimum] arguments must not be null. const SliverSafeArea({ super.key, this.left = true, diff --git a/packages/flutter/lib/src/widgets/scroll_activity.dart b/packages/flutter/lib/src/widgets/scroll_activity.dart index d42d0374e203b..81a1da840e61a 100644 --- a/packages/flutter/lib/src/widgets/scroll_activity.dart +++ b/packages/flutter/lib/src/widgets/scroll_activity.dart @@ -230,8 +230,6 @@ class HoldScrollActivity extends ScrollActivity implements ScrollHoldController class ScrollDragController implements Drag { /// Creates an object that scrolls a scroll view as the user drags their /// finger across the screen. - /// - /// The [delegate] and `details` arguments must not be null. ScrollDragController({ required ScrollActivityDelegate delegate, required DragStartDetails details, @@ -525,8 +523,6 @@ class DragScrollActivity extends ScrollActivity { /// animation parameters. class BallisticScrollActivity extends ScrollActivity { /// Creates an activity that animates a scroll view based on a [simulation]. - /// - /// The [delegate], [simulation], and [vsync] arguments must not be null. BallisticScrollActivity( super.delegate, Simulation simulation, @@ -618,8 +614,6 @@ class BallisticScrollActivity extends ScrollActivity { class DrivenScrollActivity extends ScrollActivity { /// Creates an activity that animates a scroll view based on animation /// parameters. - /// - /// All of the parameters must be non-null. DrivenScrollActivity( super.delegate, { required double from, diff --git a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart index f408d8835be66..11d903e808f83 100644 --- a/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart +++ b/packages/flutter/lib/src/widgets/scroll_aware_image_provider.dart @@ -45,8 +45,7 @@ class ScrollAwareImageProvider<T extends Object> extends ImageProvider<T> { /// Creates a [ScrollAwareImageProvider]. /// /// The [context] object is the [BuildContext] of the [State] using this - /// provider. It is used to determine scrolling velocity during [resolve]. It - /// must not be null. + /// provider. It is used to determine scrolling velocity during [resolve]. /// /// The [imageProvider] is used to create a key and load the image. It must /// not be null, and is assumed to interact with the cache in the normal way diff --git a/packages/flutter/lib/src/widgets/scroll_configuration.dart b/packages/flutter/lib/src/widgets/scroll_configuration.dart index e8c72ab8d90bd..653e839b4d06e 100644 --- a/packages/flutter/lib/src/widgets/scroll_configuration.dart +++ b/packages/flutter/lib/src/widgets/scroll_configuration.dart @@ -337,8 +337,6 @@ class _WrappedScrollBehavior implements ScrollBehavior { /// decorations used by descendants of [child]. class ScrollConfiguration extends InheritedWidget { /// Creates a widget that controls how [Scrollable] widgets behave in a subtree. - /// - /// The [behavior] and [child] arguments must not be null. const ScrollConfiguration({ super.key, required this.behavior, diff --git a/packages/flutter/lib/src/widgets/scroll_notification_observer.dart b/packages/flutter/lib/src/widgets/scroll_notification_observer.dart index 4419269da84ba..f7112ec149437 100644 --- a/packages/flutter/lib/src/widgets/scroll_notification_observer.dart +++ b/packages/flutter/lib/src/widgets/scroll_notification_observer.dart @@ -82,8 +82,6 @@ final class _ListenerEntry extends LinkedListEntry<_ListenerEntry> { /// {@end-tool} class ScrollNotificationObserver extends StatefulWidget { /// Create a [ScrollNotificationObserver]. - /// - /// The [child] parameter must not be null. const ScrollNotificationObserver({ super.key, required this.child, diff --git a/packages/flutter/lib/src/widgets/scroll_physics.dart b/packages/flutter/lib/src/widgets/scroll_physics.dart index 59ee6fcc50aed..ef8ca02b0a143 100644 --- a/packages/flutter/lib/src/widgets/scroll_physics.dart +++ b/packages/flutter/lib/src/widgets/scroll_physics.dart @@ -220,14 +220,10 @@ class ScrollPhysics { /// Provides a heuristic to determine if expensive frame-bound tasks should be /// deferred. /// - /// The velocity parameter must not be null, but may be positive, negative, or - /// zero. + /// The `velocity` parameter may be positive, negative, or zero. /// - /// The metrics parameter must not be null. - /// - /// The context parameter must not be null. It normally refers to the - /// [BuildContext] of the widget making the call, such as an [Image] widget - /// in a [ListView]. + /// The `context` parameter normally refers to the [BuildContext] of the widget + /// making the call, such as an [Image] widget in a [ListView]. /// /// This can be used to determine whether decoding or fetching complex data /// for the currently visible part of the viewport should be delayed diff --git a/packages/flutter/lib/src/widgets/scroll_view.dart b/packages/flutter/lib/src/widgets/scroll_view.dart index 666990cd3ccc2..0e6b4ed248685 100644 --- a/packages/flutter/lib/src/widgets/scroll_view.dart +++ b/packages/flutter/lib/src/widgets/scroll_view.dart @@ -97,9 +97,7 @@ abstract class ScrollView extends StatelessWidget { /// /// If the [shrinkWrap] argument is true, the [center] argument must be null. /// - /// The [scrollDirection], [reverse], and [shrinkWrap] arguments must not be null. - /// - /// The [anchor] argument must be non-null and in the range 0.0 to 1.0. + /// The [anchor] argument must be in the range zero to one, inclusive. const ScrollView({ super.key, this.scrollDirection = Axis.vertical, @@ -1907,8 +1905,6 @@ class GridView extends BoxScrollView { /// Creates a scrollable, 2D array of widgets with a custom /// [SliverGridDelegate]. /// - /// The [gridDelegate] argument must not be null. - /// /// The `addAutomaticKeepAlives` argument corresponds to the /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The /// `addRepaintBoundaries` argument corresponds to the @@ -2007,8 +2003,6 @@ class GridView extends BoxScrollView { /// /// To use an [IndexedWidgetBuilder] callback to build children, either use /// a [SliverChildBuilderDelegate] or use the [GridView.builder] constructor. - /// - /// The [gridDelegate] and [childrenDelegate] arguments must not be null. const GridView.custom({ super.key, super.scrollDirection, diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index 0d7a24a857753..88bd115771451 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -96,8 +96,6 @@ typedef TwoDimensionalViewportBuilder = Widget Function(BuildContext context, Vi /// the scroll position without using a [ScrollController]. class Scrollable extends StatefulWidget { /// Creates a widget that scrolls. - /// - /// The [axisDirection] and [viewportBuilder] arguments must not be null. const Scrollable({ super.key, this.axisDirection = AxisDirection.down, diff --git a/packages/flutter/lib/src/widgets/scrollable_helpers.dart b/packages/flutter/lib/src/widgets/scrollable_helpers.dart index 20466f96ef84c..1854cfc217513 100644 --- a/packages/flutter/lib/src/widgets/scrollable_helpers.dart +++ b/packages/flutter/lib/src/widgets/scrollable_helpers.dart @@ -28,8 +28,7 @@ export 'package:flutter/physics.dart' show Tolerance; /// information about the Scrollable in order to be initialized. @immutable class ScrollableDetails { - /// Creates a set of details describing the [Scrollable]. The [direction] - /// cannot be null. + /// Creates a set of details describing the [Scrollable]. const ScrollableDetails({ required this.direction, this.controller, @@ -338,8 +337,6 @@ enum ScrollIncrementType { /// for the scrollable. class ScrollIncrementDetails { /// A const constructor for a [ScrollIncrementDetails]. - /// - /// All of the arguments must not be null, and are required. const ScrollIncrementDetails({ required this.type, required this.metrics, @@ -405,8 +402,8 @@ class ScrollAction extends ContextAction<ScrollIntent> { /// /// Must not be called when the position is null, or when any of the position /// metrics (pixels, viewportDimension, maxScrollExtent, minScrollExtent) are - /// null. The type and state arguments must not be null, and the widget must - /// have already been laid out so that the position fields are valid. + /// null. The widget must have already been laid out so that the position + /// fields are valid. static double _calculateScrollIncrement(ScrollableState state, { ScrollIncrementType type = ScrollIncrementType.line }) { assert(state.position.hasPixels); assert(state.resolvedPhysics == null || state.resolvedPhysics!.shouldAcceptUserOffset(state.position)); diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart index bfdc0307fcdf9..6b32305ea0dbb 100644 --- a/packages/flutter/lib/src/widgets/scrollbar.dart +++ b/packages/flutter/lib/src/widgets/scrollbar.dart @@ -220,7 +220,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { /// /// The scrollbar track consumes this space. /// - /// Must not be null and defaults to 0. + /// Defaults to zero. double get crossAxisMargin => _crossAxisMargin; double _crossAxisMargin; set crossAxisMargin(double value) { @@ -276,8 +276,8 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { /// partial obstructions such as display notches. If you only want additional /// margins around the scrollbar, see [mainAxisMargin]. /// - /// Defaults to [EdgeInsets.zero]. Must not be null and offsets from all four - /// directions must be greater than or equal to zero. + /// Defaults to [EdgeInsets.zero]. Offsets from all four directions must be + /// greater than or equal to zero. EdgeInsets get padding => _padding; EdgeInsets _padding; set padding(EdgeInsets value) { @@ -655,7 +655,7 @@ class ScrollbarPainter extends ChangeNotifier implements CustomPainter { /// Convert between a thumb track position and the corresponding scroll /// position. /// - /// thumbOffsetLocal is a position in the thumb track. Cannot be null. + /// The `thumbOffsetLocal` argument is a position in the thumb track. double getTrackToScroll(double thumbOffsetLocal) { final double scrollableExtent = _lastMetrics!.maxScrollExtent - _lastMetrics!.minScrollExtent; final double thumbMovableExtent = _traversableTrackExtent - _thumbExtent; @@ -957,9 +957,6 @@ class RawScrollbar extends StatefulWidget { /// /// The [child], or a descendant of the [child], should be a source of /// [ScrollNotification] notifications, typically a [Scrollable] widget. - /// - /// The [child], [fadeDuration], [pressDuration], and [timeToFade] arguments - /// must not be null. const RawScrollbar({ super.key, required this.child, @@ -1245,18 +1242,18 @@ class RawScrollbar extends StatefulWidget { /// The [Duration] of the fade animation. /// - /// Cannot be null, defaults to a [Duration] of 300 milliseconds. + /// Defaults to a [Duration] of 300 milliseconds. final Duration fadeDuration; /// The [Duration] of time until the fade animation begins. /// - /// Cannot be null, defaults to a [Duration] of 600 milliseconds. + /// Defaults to a [Duration] of 600 milliseconds. final Duration timeToFade; /// The [Duration] of time that a LongPress will trigger the drag gesture of /// the scrollbar thumb. /// - /// Cannot be null, defaults to [Duration.zero]. + /// Defaults to [Duration.zero]. final Duration pressDuration; /// {@template flutter.widgets.Scrollbar.notificationPredicate} @@ -1307,7 +1304,7 @@ class RawScrollbar extends StatefulWidget { /// /// The scrollbar track consumes this space. /// - /// Must not be null and defaults to 0. + /// Defaults to zero. final double crossAxisMargin; /// The insets by which the scrollbar thumb and track should be padded. diff --git a/packages/flutter/lib/src/widgets/selection_container.dart b/packages/flutter/lib/src/widgets/selection_container.dart index 3c16d7909b9df..b0e6c743b9999 100644 --- a/packages/flutter/lib/src/widgets/selection_container.dart +++ b/packages/flutter/lib/src/widgets/selection_container.dart @@ -41,8 +41,6 @@ class SelectionContainer extends StatefulWidget { /// /// If [registrar] is not provided, this selection container gets the /// [SelectionRegistrar] from the context instead. - /// - /// The [delegate] and [child] must not be null. const SelectionContainer({ super.key, this.registrar, @@ -59,8 +57,6 @@ class SelectionContainer extends StatefulWidget { /// /// ** See code in examples/api/lib/material/selection_container/selection_container_disabled.0.dart ** /// {@end-tool} - /// - /// The [child] must not be null. const SelectionContainer.disabled({ super.key, required this.child, diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart index 24a12d06e7fe3..892140fdd572f 100644 --- a/packages/flutter/lib/src/widgets/semantics_debugger.dart +++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart @@ -21,8 +21,6 @@ import 'view.dart'; class SemanticsDebugger extends StatefulWidget { /// Creates a widget that visualizes the semantics for the child. /// - /// The [child] argument must not be null. - /// /// [labelStyle] dictates the [TextStyle] used for the semantics labels. const SemanticsDebugger({ super.key, diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index d0cec39ae8909..53cb54846eb76 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -362,7 +362,7 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix /// {@macro flutter.material.Material.clipBehavior} /// - /// Defaults to [Clip.none], and must not be null. + /// Defaults to [Clip.none]. Clip get clipBehavior => _clipBehavior; Clip _clipBehavior = Clip.none; set clipBehavior(Clip value) { diff --git a/packages/flutter/lib/src/widgets/sliver.dart b/packages/flutter/lib/src/widgets/sliver.dart index f4bb14da73cc3..9e76d448753a3 100644 --- a/packages/flutter/lib/src/widgets/sliver.dart +++ b/packages/flutter/lib/src/widgets/sliver.dart @@ -1113,8 +1113,7 @@ class SliverMultiBoxAdaptorElement extends RenderObjectElement implements Render class SliverOpacity extends SingleChildRenderObjectWidget { /// Creates a sliver that makes its sliver child partially transparent. /// - /// The [opacity] argument must not be null and must be between 0.0 and 1.0 - /// (inclusive). + /// The [opacity] argument must be between zero and one, inclusive. const SliverOpacity({ super.key, required this.opacity, @@ -1128,8 +1127,6 @@ class SliverOpacity extends SingleChildRenderObjectWidget { /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent /// (i.e. invisible). /// - /// The opacity must not be null. - /// /// Values 1.0 and 0.0 are painted with a fast path. Other values /// require painting the sliver child into an intermediate buffer, which is /// expensive. @@ -1193,8 +1190,6 @@ class SliverOpacity extends SingleChildRenderObjectWidget { /// * [IgnorePointer], the equivalent widget for boxes. class SliverIgnorePointer extends SingleChildRenderObjectWidget { /// Creates a sliver widget that is invisible to hit testing. - /// - /// The [ignoring] argument must not be null. const SliverIgnorePointer({ super.key, this.ignoring = true, @@ -1333,8 +1328,6 @@ class _SliverOffstageElement extends SingleChildRenderObjectElement { /// for that mixin class for details. class KeepAlive extends ParentDataWidget<KeepAliveParentDataMixin> { /// Marks a child as needing to remain alive. - /// - /// The [child] and [keepAlive] arguments must not be null. const KeepAlive({ super.key, required this.keepAlive, diff --git a/packages/flutter/lib/src/widgets/sliver_fill.dart b/packages/flutter/lib/src/widgets/sliver_fill.dart index 743453620fd85..f39a5f1b1a16f 100644 --- a/packages/flutter/lib/src/widgets/sliver_fill.dart +++ b/packages/flutter/lib/src/widgets/sliver_fill.dart @@ -45,14 +45,14 @@ class SliverFillViewport extends StatelessWidget { /// Whether to add padding to both ends of the list. /// /// If this is set to true and [viewportFraction] < 1.0, padding will be added - /// such that the first and last child slivers will be in the center of - /// the viewport when scrolled all the way to the start or end, respectively. - /// You may want to set this to false if this [SliverFillViewport] is not the only + /// such that the first and last child slivers will be in the center of the + /// viewport when scrolled all the way to the start or end, respectively. You + /// may want to set this to false if this [SliverFillViewport] is not the only /// widget along this main axis, such as in a [CustomScrollView] with multiple /// children. /// - /// This option cannot be null. If [viewportFraction] >= 1.0, this option has no - /// effect. Defaults to true. + /// If [viewportFraction] is greater than one, this option has no effect. + /// Defaults to true. final bool padEnds; /// {@macro flutter.widgets.SliverMultiBoxAdaptorWidget.delegate} @@ -282,10 +282,9 @@ class SliverFillRemaining extends StatelessWidget { /// Indicates whether the child should stretch to fill the overscroll area /// created by certain scroll physics, such as iOS' default scroll physics. - /// This value cannot be null. This flag is only relevant when the - /// [hasScrollBody] value is false. + /// This flag is only relevant when [hasScrollBody] is false. /// - /// Defaults to false, meaning the default behavior is for the child to + /// Defaults to false, meaning that the default behavior is for the child to /// maintain its size and not extend into the overscroll area. final bool fillOverscroll; diff --git a/packages/flutter/lib/src/widgets/sliver_layout_builder.dart b/packages/flutter/lib/src/widgets/sliver_layout_builder.dart index e4f0308cd6a21..43af22187511e 100644 --- a/packages/flutter/lib/src/widgets/sliver_layout_builder.dart +++ b/packages/flutter/lib/src/widgets/sliver_layout_builder.dart @@ -25,8 +25,6 @@ typedef SliverLayoutWidgetBuilder = Widget Function(BuildContext context, Sliver /// * [LayoutBuilder], the non-sliver version of this widget. class SliverLayoutBuilder extends ConstrainedLayoutBuilder<SliverConstraints> { /// Creates a sliver widget that defers its building until layout. - /// - /// The [builder] argument must not be null. const SliverLayoutBuilder({ super.key, required super.builder, diff --git a/packages/flutter/lib/src/widgets/sliver_persistent_header.dart b/packages/flutter/lib/src/widgets/sliver_persistent_header.dart index 23e0e2911a3f4..359badf4da7ec 100644 --- a/packages/flutter/lib/src/widgets/sliver_persistent_header.dart +++ b/packages/flutter/lib/src/widgets/sliver_persistent_header.dart @@ -119,8 +119,6 @@ abstract class SliverPersistentHeaderDelegate { class SliverPersistentHeader extends StatelessWidget { /// Creates a sliver that varies its size when it is scrolled to the start of /// a viewport. - /// - /// The [delegate], [pinned], and [floating] arguments must not be null. const SliverPersistentHeader({ super.key, required this.delegate, diff --git a/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart b/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart index e79b7dfc27f81..b727726b36aa9 100644 --- a/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart +++ b/packages/flutter/lib/src/widgets/sliver_varied_extent_list.dart @@ -114,8 +114,6 @@ class SliverVariedExtentList extends SliverMultiBoxAdaptorWidget { class RenderSliverVariedExtentList extends RenderSliverFixedExtentBoxAdaptor { /// Creates a sliver that contains multiple box children that have a explicit /// extent in the main axis. - /// - /// The [childManager] argument must not be null. RenderSliverVariedExtentList({ required super.childManager, required ItemExtentBuilder itemExtentBuilder, diff --git a/packages/flutter/lib/src/widgets/status_transitions.dart b/packages/flutter/lib/src/widgets/status_transitions.dart index b79bd0df437b7..734cd0f29b0c0 100644 --- a/packages/flutter/lib/src/widgets/status_transitions.dart +++ b/packages/flutter/lib/src/widgets/status_transitions.dart @@ -8,8 +8,6 @@ import 'framework.dart'; /// A widget that rebuilds when the given animation changes status. abstract class StatusTransitionWidget extends StatefulWidget { /// Initializes fields for subclasses. - /// - /// The [animation] argument must not be null. const StatusTransitionWidget({ super.key, required this.animation, diff --git a/packages/flutter/lib/src/widgets/table.dart b/packages/flutter/lib/src/widgets/table.dart index a3aba1c95fe25..316a118efba66 100644 --- a/packages/flutter/lib/src/widgets/table.dart +++ b/packages/flutter/lib/src/widgets/table.dart @@ -112,9 +112,6 @@ class _TableElementRow { /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). class Table extends RenderObjectWidget { /// Creates a table. - /// - /// The [children], [defaultColumnWidth], and [defaultVerticalAlignment] - /// arguments must not be null. Table({ super.key, this.children = const <TableRow>[], @@ -169,8 +166,7 @@ class Table extends RenderObjectWidget { /// The rows of the table. /// - /// Every row in a table must have the same number of children, and all the - /// children must be non-null. + /// Every row in a table must have the same number of children. final List<TableRow> children; /// How the horizontal extents of the columns of this table should be determined. diff --git a/packages/flutter/lib/src/widgets/text.dart b/packages/flutter/lib/src/widgets/text.dart index b1870e1a94b1f..a6054c60acad0 100644 --- a/packages/flutter/lib/src/widgets/text.dart +++ b/packages/flutter/lib/src/widgets/text.dart @@ -40,11 +40,6 @@ class DefaultTextStyle extends InheritedTheme { /// Consider using [DefaultTextStyle.merge] to inherit styling information /// from the current default text style for a given [BuildContext]. /// - /// The [style] and [child] arguments are required and must not be null. - /// - /// The [softWrap] and [overflow] arguments must not be null (though they do - /// have default values). - /// /// The [maxLines] property may be null (and indeed defaults to null), but if /// it is not null, it must be greater than zero. const DefaultTextStyle({ @@ -235,8 +230,6 @@ class _NullWidget extends StatelessWidget { /// [Text] widgets. class DefaultTextHeightBehavior extends InheritedTheme { /// Creates a default text height behavior for the given subtree. - /// - /// The [textHeightBehavior] and [child] arguments are required and must not be null. const DefaultTextHeightBehavior({ super.key, required this.textHeightBehavior, @@ -419,8 +412,6 @@ class Text extends StatelessWidget { /// If the [style] argument is null, the text will use the style from the /// closest enclosing [DefaultTextStyle]. /// - /// The [data] parameter must not be null. - /// /// The [overflow] property's behavior is affected by the [softWrap] argument. /// If the [softWrap] is true or null, the glyph causing overflow, and those /// that follow, will not be rendered. Otherwise, it will be shown with the @@ -460,8 +451,6 @@ class Text extends StatelessWidget { /// * [TextSpan]s define text and children [InlineSpan]s. /// * [WidgetSpan]s define embedded inline widgets. /// - /// The [textSpan] parameter must not be null. - /// /// See [RichText] which provides a lower-level way to draw text. const Text.rich( InlineSpan this.textSpan, { diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart index e805b572793dd..c0d699aae8f15 100644 --- a/packages/flutter/lib/src/widgets/text_selection.dart +++ b/packages/flutter/lib/src/widgets/text_selection.dart @@ -313,7 +313,7 @@ final TextSelectionControls emptyTextSelectionControls = EmptyTextSelectionContr class TextSelectionOverlay { /// Creates an object that manages overlay entries for selection handles. /// - /// The [context] must not be null and must have an [Overlay] as an ancestor. + /// The [context] must have an [Overlay] as an ancestor. TextSelectionOverlay({ required TextEditingValue value, required this.context, @@ -914,7 +914,7 @@ class TextSelectionOverlay { class SelectionOverlay { /// Creates an object that manages overlay entries for selection handles. /// - /// The [context] must not be null and must have an [Overlay] as an ancestor. + /// The [context] must have an [Overlay] as an ancestor. SelectionOverlay({ required this.context, this.debugRequiredFor, @@ -3021,7 +3021,6 @@ class TextSelectionGestureDetector extends StatefulWidget { /// Create a [TextSelectionGestureDetector]. /// /// Multiple callbacks can be called for one sequence of input gesture. - /// The [child] parameter must not be null. const TextSelectionGestureDetector({ super.key, this.onTapTrackStart, diff --git a/packages/flutter/lib/src/widgets/ticker_provider.dart b/packages/flutter/lib/src/widgets/ticker_provider.dart index 09dcc608a8143..270e7b66a7ec8 100644 --- a/packages/flutter/lib/src/widgets/ticker_provider.dart +++ b/packages/flutter/lib/src/widgets/ticker_provider.dart @@ -20,8 +20,6 @@ export 'package:flutter/scheduler.dart' show TickerProvider; /// [TickerProviderStateMixin] or a [SingleTickerProviderStateMixin]. class TickerMode extends StatefulWidget { /// Creates a widget that enables or disables tickers. - /// - /// The [enabled] argument must not be null. const TickerMode({ super.key, required this.enabled, diff --git a/packages/flutter/lib/src/widgets/title.dart b/packages/flutter/lib/src/widgets/title.dart index a97ca974f8bfb..ad20e4db54a35 100644 --- a/packages/flutter/lib/src/widgets/title.dart +++ b/packages/flutter/lib/src/widgets/title.dart @@ -23,7 +23,6 @@ class Title extends StatelessWidget { }) : assert(color.alpha == 0xFF); /// A one-line description of this app for use in the window manager. - /// Must not be null. final String title; /// A color that the window manager should use to identify this app. Must be diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart index f16100b0862b3..24d90161c93f9 100644 --- a/packages/flutter/lib/src/widgets/transitions.dart +++ b/packages/flutter/lib/src/widgets/transitions.dart @@ -168,8 +168,6 @@ class _AnimatedState extends State<AnimatedWidget> { /// position based on the value of a rectangle relative to a bounding box. class SlideTransition extends AnimatedWidget { /// Creates a fractional translation transition. - /// - /// The [position] argument must not be null. const SlideTransition({ super.key, required Animation<Offset> position, @@ -380,8 +378,6 @@ class ScaleTransition extends MatrixTransition { /// aligns its child. class RotationTransition extends MatrixTransition { /// Creates a rotation transition. - /// - /// The [turns] argument must not be null. const RotationTransition({ super.key, required Animation<double> turns, @@ -437,9 +433,8 @@ class RotationTransition extends MatrixTransition { class SizeTransition extends AnimatedWidget { /// Creates a size transition. /// - /// The [axis], [sizeFactor], and [axisAlignment] arguments must not be null. /// The [axis] argument defaults to [Axis.vertical]. The [axisAlignment] - /// defaults to 0.0, which centers the child along the main axis during the + /// defaults to zero, which centers the child along the main axis during the /// transition. const SizeTransition({ super.key, @@ -545,8 +540,6 @@ class SizeTransition extends AnimatedWidget { /// * [SliverFadeTransition], the sliver version of this widget. class FadeTransition extends SingleChildRenderObjectWidget { /// Creates an opacity transition. - /// - /// The [opacity] argument must not be null. const FadeTransition({ super.key, required this.opacity, @@ -637,8 +630,6 @@ class FadeTransition extends SingleChildRenderObjectWidget { /// * [FadeTransition], the box version of this widget. class SliverFadeTransition extends SingleChildRenderObjectWidget { /// Creates an opacity transition. - /// - /// The [opacity] argument must not be null. const SliverFadeTransition({ super.key, required this.opacity, @@ -738,8 +729,6 @@ class RelativeRectTween extends Tween<RelativeRect> { /// aligns its child. class PositionedTransition extends AnimatedWidget { /// Creates a transition for [Positioned]. - /// - /// The [rect] argument must not be null. const PositionedTransition({ super.key, required Animation<RelativeRect> rect, @@ -797,7 +786,7 @@ class RelativePositionedTransition extends AnimatedWidget { /// /// Each frame, the [Positioned] widget will be configured to represent the /// current value of the [rect] argument assuming that the stack has the given - /// [size]. Both [rect] and [size] must not be null. + /// [size]. const RelativePositionedTransition({ super.key, required Animation<Rect?> rect, @@ -860,8 +849,6 @@ class DecoratedBoxTransition extends AnimatedWidget { /// Creates an animated [DecoratedBox] whose [Decoration] animation updates /// the widget. /// - /// The [decoration] and [position] must not be null. - /// /// See also: /// /// * [DecoratedBox.new] @@ -1094,8 +1081,6 @@ class DefaultTextStyleTransition extends AnimatedWidget { /// reports the new value in its builder callback. class ListenableBuilder extends AnimatedWidget { /// Creates a builder that responds to changes in [listenable]. - /// - /// The [listenable] and [builder] arguments must not be null. const ListenableBuilder({ super.key, required super.listenable, diff --git a/packages/flutter/lib/src/widgets/tween_animation_builder.dart b/packages/flutter/lib/src/widgets/tween_animation_builder.dart index edd7b619b51d6..3ef9f63fe4117 100644 --- a/packages/flutter/lib/src/widgets/tween_animation_builder.dart +++ b/packages/flutter/lib/src/widgets/tween_animation_builder.dart @@ -93,9 +93,6 @@ import 'value_listenable_builder.dart'; class TweenAnimationBuilder<T extends Object?> extends ImplicitlyAnimatedWidget { /// Creates a [TweenAnimationBuilder]. /// - /// The properties [tween], [duration], and [builder] are required. The values - /// for [tween], [curve], and [builder] must not be null. - /// /// The [TweenAnimationBuilder] takes full ownership of the provided [tween] /// instance and mutates it. Once a [Tween] has been passed to a /// [TweenAnimationBuilder], its properties should not be accessed or changed diff --git a/packages/flutter/lib/src/widgets/unique_widget.dart b/packages/flutter/lib/src/widgets/unique_widget.dart index fa6c078f5c261..64688e4ac4b21 100644 --- a/packages/flutter/lib/src/widgets/unique_widget.dart +++ b/packages/flutter/lib/src/widgets/unique_widget.dart @@ -20,8 +20,8 @@ import 'framework.dart'; abstract class UniqueWidget<T extends State<StatefulWidget>> extends StatefulWidget { /// Creates a widget that has exactly one inflated instance in the tree. /// - /// The [key] argument must not be null because it identifies the unique - /// inflated instance of this widget. + /// The [key] argument is required because it identifies the unique inflated + /// instance of this widget. const UniqueWidget({ required GlobalKey<T> key, }) : super(key: key); diff --git a/packages/flutter/lib/src/widgets/value_listenable_builder.dart b/packages/flutter/lib/src/widgets/value_listenable_builder.dart index 79a3d8cb6bff4..0673fd2fd0c84 100644 --- a/packages/flutter/lib/src/widgets/value_listenable_builder.dart +++ b/packages/flutter/lib/src/widgets/value_listenable_builder.dart @@ -111,7 +111,6 @@ typedef ValueWidgetBuilder<T> = Widget Function(BuildContext context, T value, W class ValueListenableBuilder<T> extends StatefulWidget { /// Creates a [ValueListenableBuilder]. /// - /// The [valueListenable] and [builder] arguments must not be null. /// The [child] is optional but is good practice to use if part of the widget /// subtree does not depend on the value of the [valueListenable]. const ValueListenableBuilder({ @@ -125,8 +124,6 @@ class ValueListenableBuilder<T> extends StatefulWidget { /// /// This widget does not ensure that the [ValueListenable]'s value is not /// null, therefore your [builder] may need to handle null values. - /// - /// This [ValueListenable] itself must not be null. final ValueListenable<T> valueListenable; /// A [ValueWidgetBuilder] which builds a widget depending on the @@ -134,8 +131,6 @@ class ValueListenableBuilder<T> extends StatefulWidget { /// /// Can incorporate a [valueListenable] value-independent widget subtree /// from the [child] parameter into the returned widget tree. - /// - /// Must not be null. final ValueWidgetBuilder<T> builder; /// A [valueListenable]-independent widget which is passed back to the [builder]. diff --git a/packages/flutter/lib/src/widgets/viewport.dart b/packages/flutter/lib/src/widgets/viewport.dart index ad4a67facc204..36f556510e92e 100644 --- a/packages/flutter/lib/src/widgets/viewport.dart +++ b/packages/flutter/lib/src/widgets/viewport.dart @@ -53,8 +53,6 @@ class Viewport extends MultiChildRenderObjectWidget { /// The viewport listens to the [offset], which means you do not need to /// rebuild this widget when the [offset] changes. /// - /// The [offset] argument must not be null. - /// /// The [cacheExtent] must be specified if the [cacheExtentStyle] is /// not [CacheExtentStyle.pixel]. Viewport({ @@ -327,8 +325,6 @@ class ShrinkWrappingViewport extends MultiChildRenderObjectWidget { /// /// The viewport listens to the [offset], which means you do not need to /// rebuild this widget when the [offset] changes. - /// - /// The [offset] argument must not be null. const ShrinkWrappingViewport({ super.key, this.axisDirection = AxisDirection.down, diff --git a/packages/flutter/lib/src/widgets/visibility.dart b/packages/flutter/lib/src/widgets/visibility.dart index eaf95eb2e3be3..a5e2fca28f919 100644 --- a/packages/flutter/lib/src/widgets/visibility.dart +++ b/packages/flutter/lib/src/widgets/visibility.dart @@ -42,10 +42,6 @@ import 'ticker_provider.dart'; class Visibility extends StatelessWidget { /// Control whether the given [child] is [visible]. /// - /// The [child] and [replacement] arguments must not be null. - /// - /// The boolean arguments must not be null. - /// /// The [maintainSemantics] and [maintainInteractivity] arguments can only be /// set if [maintainSize] is set. /// @@ -332,10 +328,6 @@ class _VisibilityScope extends InheritedWidget { class SliverVisibility extends StatelessWidget { /// Control whether the given [sliver] is [visible]. /// - /// The [sliver] and [replacementSliver] arguments must not be null. - /// - /// The boolean arguments must not be null. - /// /// The [maintainSemantics] and [maintainInteractivity] arguments can only be /// set if [maintainSize] is set. /// @@ -372,8 +364,6 @@ class SliverVisibility extends StatelessWidget { /// Control whether the given [sliver] is [visible]. /// - /// The [sliver] and [replacementSliver] arguments must not be null. - /// /// This is equivalent to the default [SliverVisibility] constructor with all /// "maintain" fields set to true. This constructor should be used in place of /// a [SliverOpacity] widget that only takes on values of `0.0` or `1.0`, as it diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 888a6c817b9fa..bf6324d2ec9b7 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -616,8 +616,6 @@ class _ScreenshotPaintingContext extends PaintingContext { class _DiagnosticsPathNode { /// Creates a full description of a step in a path through a tree of /// [DiagnosticsNode] objects. - /// - /// The [node] and [child] arguments must not be null. _DiagnosticsPathNode({ required this.node, required this.children, @@ -2668,8 +2666,6 @@ class _WidgetForTypeTests extends Widget { /// bottom left corner of the application switches back to select mode. class WidgetInspector extends StatefulWidget { /// Creates a widget that enables inspection for the child. - /// - /// The [child] argument must not be null. const WidgetInspector({ super.key, required this.child, @@ -3004,7 +3000,6 @@ class _InspectorOverlay extends LeafRenderObjectWidget { } class _RenderInspectorOverlay extends RenderBox { - /// The arguments must not be null. _RenderInspectorOverlay({ required InspectorSelection selection }) : _selection = selection; @@ -3546,16 +3541,12 @@ Iterable<DiagnosticsNode> _describeRelevantUserCode( /// /// The [value] for this property is a string representation of the Flutter /// DevTools url. -/// -/// Properties `description` and `url` must not be null. class DevToolsDeepLinkProperty extends DiagnosticsProperty<String> { /// Creates a diagnostics property that displays a deep link to Flutter DevTools. /// /// The [value] of this property will return a map of data for the Flutter /// DevTools deep link, including the full `url`, the Flutter DevTools `screenId`, /// and the `objectId` in Flutter DevTools that this diagnostic references. - /// - /// The `description` and `url` arguments must not be null. DevToolsDeepLinkProperty(String description, String url) : super('', url, description: description, level: DiagnosticLevel.info); } diff --git a/packages/flutter/lib/src/widgets/widget_span.dart b/packages/flutter/lib/src/widgets/widget_span.dart index 242cb3033c4ad..5ec5e99cd2b7f 100644 --- a/packages/flutter/lib/src/widgets/widget_span.dart +++ b/packages/flutter/lib/src/widgets/widget_span.dart @@ -69,10 +69,10 @@ const double _kEngineDefaultFontSize = 14.0; class WidgetSpan extends PlaceholderSpan { /// Creates a [WidgetSpan] with the given values. /// - /// The [child] property must be non-null. [WidgetSpan] is a leaf node in - /// the [InlineSpan] tree. Child widgets are constrained by the width of the - /// paragraph they occupy. Child widget heights are unconstrained, and may - /// cause the text to overflow and be ellipsized/truncated. + /// [WidgetSpan] is a leaf node in the [InlineSpan] tree. Child widgets are + /// constrained by the width of the paragraph they occupy. Child widget + /// heights are unconstrained, and may cause the text to overflow and be + /// ellipsized/truncated. /// /// A [TextStyle] may be provided with the [style] property, but only the /// decoration, foreground, background, and spacing options will be used. diff --git a/packages/flutter/lib/src/widgets/will_pop_scope.dart b/packages/flutter/lib/src/widgets/will_pop_scope.dart index eefe437983375..81b59454861c3 100644 --- a/packages/flutter/lib/src/widgets/will_pop_scope.dart +++ b/packages/flutter/lib/src/widgets/will_pop_scope.dart @@ -22,8 +22,6 @@ import 'routes.dart'; class WillPopScope extends StatefulWidget { /// Creates a widget that registers a callback to veto attempts by the user to /// dismiss the enclosing [ModalRoute]. - /// - /// The [child] argument must not be null. @Deprecated( 'Use PopScope instead. ' 'This feature was deprecated after v3.12.0-1.0.pre.', From 4d8e390c1be6237ab45df9c57b87e50e499056db Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 13:41:24 -0400 Subject: [PATCH 1366/1547] Roll Flutter Engine from 6f256257b79f to 55314d08d792 (2 revisions) (#135151) https://github.com/flutter/engine/compare/6f256257b79f...55314d08d792 2023-09-20 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from kGkqpvcPI1TGmR4Sc... to zuOP7YCHHocXuZJcD... (flutter/engine#46097) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 56ce5bb201c6 to f54c214a739b (4 revisions) (flutter/engine#46098) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from kGkqpvcPI1TG to zuOP7YCHHocX If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9352f6bb6edfa..6bc92f887ad9d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6f256257b79fd4a3927a7c429db4c962f1d414b3 +55314d08d7928efe925d6ba7a8ce781051ffd36f diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index d40166ed1086a..27699de91e60d 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -kGkqpvcPI1TGmR4Scp19EXK5hxyrDBhn2-hp4U8E6skC +zuOP7YCHHocXuZJcDIxnlpB-rNuuZrNvIw4FuTNHV5gC From 22e4088134b80c63faf3abd98bfbae8abe7ea8d6 Mon Sep 17 00:00:00 2001 From: Chris Yang <ychris@google.com> Date: Wed, 20 Sep 2023 11:50:04 -0700 Subject: [PATCH 1367/1547] codeisn extension safe iOS framework (#134966) Update the conductor to code sign extension safe iOS frameworks The new frameworks are added in https://github.com/flutter/engine/pull/45781/files part of https://github.com/flutter/flutter/issues/124291 Also includes an Engine roll includes: https://github.com/flutter/engine/commit/9232e76c30455ee1c0c1584001bdbb01000f8212 https://github.com/flutter/engine/commit/39c0f2ea1f536eb7dc057d9147f23e3fec4a56c9 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- bin/internal/engine.version | 2 +- dev/conductor/core/lib/src/codesign.dart | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6bc92f887ad9d..1da2e14ecc4eb 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -55314d08d7928efe925d6ba7a8ce781051ffd36f +39c0f2ea1f536eb7dc057d9147f23e3fec4a56c9 \ No newline at end of file diff --git a/dev/conductor/core/lib/src/codesign.dart b/dev/conductor/core/lib/src/codesign.dart index 5691aefe07ea7..2e45cd0f6d574 100644 --- a/dev/conductor/core/lib/src/codesign.dart +++ b/dev/conductor/core/lib/src/codesign.dart @@ -201,10 +201,16 @@ class CodesignCommand extends Command<void> { 'artifacts/engine/darwin-x64/libtessellator.dylib', 'artifacts/engine/ios-profile/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', 'artifacts/engine/ios-profile/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', + 'artifacts/engine/ios-profile/extension_safe/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', + 'artifacts/engine/ios-profile/extension_safe/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', 'artifacts/engine/ios-release/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', 'artifacts/engine/ios-release/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', + 'artifacts/engine/ios-release/extension_safe/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', + 'artifacts/engine/ios-release/extension_safe/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', 'artifacts/engine/ios/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', 'artifacts/engine/ios/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', + 'artifacts/engine/ios/extension_safe/Flutter.xcframework/ios-arm64/Flutter.framework/Flutter', + 'artifacts/engine/ios/extension_safe/Flutter.xcframework/ios-arm64_x86_64-simulator/Flutter.framework/Flutter', 'artifacts/ios-deploy/ios-deploy', ] .map((String relativePath) => From 9b767e6c1fc0d52c2761724b1bad160986c6ce67 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:21:10 +0200 Subject: [PATCH 1368/1547] cover more tests with leak tracing (#134833) --- packages/flutter/test/services/system_chrome_test.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/flutter/test/services/system_chrome_test.dart b/packages/flutter/test/services/system_chrome_test.dart index 555d9e219797d..c4aa7fe3373ed 100644 --- a/packages/flutter/test/services/system_chrome_test.dart +++ b/packages/flutter/test/services/system_chrome_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('SystemChrome overlay style test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SystemChrome overlay style test', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { From 96a4ae9dc5244c7d8766a82cf15ebf322a91e77f Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Wed, 20 Sep 2023 21:29:33 +0200 Subject: [PATCH 1369/1547] Cover more test/widgets tests with leak tracking #10 (#135143) --- .../widgets/sliver_fill_viewport_test.dart | 5 +- .../test/widgets/sliver_list_test.dart | 37 ++++--- .../widgets/sliver_main_axis_group_test.dart | 57 +++++++---- .../sliver_persistent_header_test.dart | 7 +- .../sliver_prototype_item_extent_test.dart | 15 +-- .../test/widgets/sliver_semantics_test.dart | 24 +++-- .../test/widgets/sliver_visibility_test.dart | 3 +- .../slivers_appbar_floating_pinned_test.dart | 19 ++-- .../widgets/slivers_appbar_floating_test.dart | 17 ++-- .../widgets/slivers_appbar_pinned_test.dart | 11 ++- .../slivers_appbar_scrolling_test.dart | 9 +- .../widgets/slivers_appbar_stretch_test.dart | 29 +++--- .../slivers_block_global_key_test.dart | 7 +- .../test/widgets/slivers_block_test.dart | 60 +++++++++--- .../test/widgets/slivers_evil_test.dart | 5 +- .../test/widgets/slivers_keepalive_test.dart | 25 ++--- .../test/widgets/slivers_padding_test.dart | 96 ++++++++++++++----- .../test/widgets/slivers_protocol_test.dart | 3 +- .../flutter/test/widgets/slivers_test.dart | 74 +++++++------- .../slotted_render_object_widget_test.dart | 7 +- .../test/widgets/snapshot_widget_test.dart | 67 ++++++++++--- .../flutter/test/widgets/spacer_test.dart | 7 +- .../test/widgets/spell_check_test.dart | 23 ++--- packages/flutter/test/widgets/stack_test.dart | 51 +++++----- .../state_setting_in_scrollables_test.dart | 11 ++- .../test/widgets/stateful_component_test.dart | 5 +- .../widgets/stateful_components_test.dart | 3 +- .../test/widgets/status_transitions_test.dart | 4 +- .../flutter/test/widgets/syncing_test.dart | 7 +- packages/flutter/test/widgets/table_test.dart | 47 ++++----- .../flutter/test/widgets/tap_region_test.dart | 9 +- .../test/widgets/text_golden_test.dart | 43 +++++---- ...xt_scaler_backward_compatibility_test.dart | 13 ++- 33 files changed, 506 insertions(+), 294 deletions(-) diff --git a/packages/flutter/test/widgets/sliver_fill_viewport_test.dart b/packages/flutter/test/widgets/sliver_fill_viewport_test.dart index a08d235a979ef..a17abfb90a7f0 100644 --- a/packages/flutter/test/widgets/sliver_fill_viewport_test.dart +++ b/packages/flutter/test/widgets/sliver_fill_viewport_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SliverFillViewport control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFillViewport control test', (WidgetTester tester) async { final List<Widget> children = List<Widget>.generate(20, (int i) { return ColoredBox(color: Colors.green, child: Text('$i', textDirection: TextDirection.ltr)); }); @@ -158,7 +159,7 @@ void main() { ); }); - testWidgets('SliverFillViewport padding test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFillViewport padding test', (WidgetTester tester) async { final SliverChildListDelegate delegate = SliverChildListDelegate( <Widget>[ const Text('0'), diff --git a/packages/flutter/test/widgets/sliver_list_test.dart b/packages/flutter/test/widgets/sliver_list_test.dart index 1131e4b43b0a4..bad587cdfa691 100644 --- a/packages/flutter/test/widgets/sliver_list_test.dart +++ b/packages/flutter/test/widgets/sliver_list_test.dart @@ -4,15 +4,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SliverList reverse children (with keys)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList reverse children (with keys)', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); const double itemHeight = 300.0; const double viewportHeight = 500.0; const double scrollPosition = 18 * itemHeight; final ScrollController controller = ScrollController(initialScrollOffset: scrollPosition); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverList( items: items, @@ -53,13 +55,14 @@ void main() { expect(find.text('Tile 0'), findsNothing); }); - testWidgets('SliverList replace children (with keys)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList replace children (with keys)', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); const double itemHeight = 300.0; const double viewportHeight = 500.0; const double scrollPosition = 18 * itemHeight; final ScrollController controller = ScrollController(initialScrollOffset: scrollPosition); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverList( items: items, @@ -105,13 +108,14 @@ void main() { expect(find.text('Tile 119'), findsNothing); }); - testWidgets('SliverList replace with shorter children list (with keys)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList replace with shorter children list (with keys)', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); const double itemHeight = 300.0; const double viewportHeight = 500.0; final double scrollPosition = items.length * itemHeight - viewportHeight; final ScrollController controller = ScrollController(initialScrollOffset: scrollPosition); + addTearDown(controller.dispose); await tester.pumpWidget(_buildSliverList( items: items, @@ -145,28 +149,33 @@ void main() { expect(find.text('Tile 19'), findsNothing); }); - testWidgets('SliverList should layout first child in case of child reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList should layout first child in case of child reordering', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/35904. List<String> items = <String>['1', '2']; - - await tester.pumpWidget(_buildSliverListRenderWidgetChild(items)); + final ScrollController controller1 = ScrollController(); + addTearDown(controller1.dispose); + await tester.pumpWidget(_buildSliverListRenderWidgetChild(items, controller1)); await tester.pumpAndSettle(); expect(find.text('Tile 1'), findsOneWidget); expect(find.text('Tile 2'), findsOneWidget); items = items.reversed.toList(); - await tester.pumpWidget(_buildSliverListRenderWidgetChild(items)); + final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); + await tester.pumpWidget(_buildSliverListRenderWidgetChild(items, controller2)); await tester.pumpAndSettle(); expect(find.text('Tile 1'), findsOneWidget); expect(find.text('Tile 2'), findsOneWidget); }); - testWidgets('SliverList should recalculate inaccurate layout offset case 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList should recalculate inaccurate layout offset case 1', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/42142. final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( _buildSliverList( items: List<int>.from(items), @@ -223,10 +232,12 @@ void main() { }); - testWidgets('SliverList should recalculate inaccurate layout offset case 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList should recalculate inaccurate layout offset case 2', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/42142. final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( _buildSliverList( items: List<int>.from(items), @@ -275,10 +286,12 @@ void main() { expect(find.text('Tile 3'), findsOneWidget); }); - testWidgets('SliverList should start to perform layout from the initial child when there is no valid offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList should start to perform layout from the initial child when there is no valid offset', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/66198. bool isShow = true; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + Widget buildSliverList(ScrollController controller) { return Directionality( textDirection: TextDirection.ltr, @@ -335,7 +348,7 @@ void main() { }); } -Widget _buildSliverListRenderWidgetChild(List<String> items) { +Widget _buildSliverListRenderWidgetChild(List<String> items, ScrollController controller) { return MaterialApp( home: Directionality( textDirection: TextDirection.ltr, @@ -343,7 +356,7 @@ Widget _buildSliverListRenderWidgetChild(List<String> items) { child: SizedBox( height: 500, child: CustomScrollView( - controller: ScrollController(), + controller: controller, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate( diff --git a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart index c0f89fa308b68..9ad4699af5910 100644 --- a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/sliver_utils.dart'; @@ -13,9 +14,10 @@ const double VIEWPORT_HEIGHT = 600; const double VIEWPORT_WIDTH = 300; void main() { - testWidgets('SliverMainAxisGroup is laid out properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverMainAxisGroup is laid out properly', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _buildSliverMainAxisGroup( @@ -64,9 +66,10 @@ void main() { expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); - testWidgets('SliverMainAxisGroup is laid out properly when reversed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverMainAxisGroup is laid out properly when reversed', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _buildSliverMainAxisGroup( @@ -116,9 +119,10 @@ void main() { expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); - testWidgets('SliverMainAxisGroup is laid out properly when horizontal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverMainAxisGroup is laid out properly when horizontal', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _buildSliverMainAxisGroup( @@ -173,9 +177,10 @@ void main() { expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); - testWidgets('SliverMainAxisGroup is laid out properly when horizontal, reversed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverMainAxisGroup is laid out properly when horizontal, reversed', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( _buildSliverMainAxisGroup( @@ -231,9 +236,10 @@ void main() { expect(renderGroup.geometry!.hasVisualOverflow, isTrue); }); - testWidgets('Hit test works properly on various parts of SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hit test works properly on various parts of SliverMainAxisGroup', (WidgetTester tester) async { final List<int> items = List<int>.generate(20, (int i) => i); final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); String? clickedTile; @@ -303,7 +309,7 @@ void main() { expect(clickedTile, equals('Group 1 Tile 2')); }); - testWidgets('applyPaintTransform is implemented properly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('applyPaintTransform is implemented properly', (WidgetTester tester) async { await tester.pumpWidget(_buildSliverMainAxisGroup( slivers: <Widget>[ const SliverToBoxAdapter(child: Text('first box')), @@ -319,8 +325,10 @@ void main() { expect(second.localToGlobal(Offset.zero), Offset(0, first.size.height)); }); - testWidgets('visitChildrenForSemantics visits children in the correct order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visitChildrenForSemantics visits children in the correct order', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: const <Widget>[ @@ -344,8 +352,10 @@ void main() { expect(visitedChildren[1].geometry!.scrollExtent, equals(500)); }); - testWidgets('SliverPinnedPersistentHeader is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPinnedPersistentHeader is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -371,8 +381,10 @@ void main() { }); - testWidgets('SliverFloatingPersistentHeader is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFloatingPersistentHeader is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -400,8 +412,10 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverPinnedPersistentHeader is painted within bounds of SliverMainAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPinnedPersistentHeader is painted within bounds of SliverMainAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -429,8 +443,10 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverFloatingPersistentHeader is painted within bounds of SliverMainAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFloatingPersistentHeader is painted within bounds of SliverMainAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -465,8 +481,10 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverPinnedFloatingPersistentHeader is painted within bounds of SliverMainAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPinnedFloatingPersistentHeader is painted within bounds of SliverMainAxisGroup with different minExtent/maxExtent', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -502,8 +520,10 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(0.0)); }); - testWidgets('SliverAppBar with floating: false, pinned: false, snap: false is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with floating: false, pinned: false, snap: false is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -532,8 +552,10 @@ void main() { expect(renderHeader.geometry!.layoutExtent, equals(0.0)); }); - testWidgets('SliverAppBar with floating: true, pinned: false, snap: true is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with floating: true, pinned: false, snap: true is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -572,8 +594,10 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(-50.0)); }); - testWidgets('SliverAppBar with floating: true, pinned: true, snap: true is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar with floating: true, pinned: true, snap: true is painted within bounds of SliverMainAxisGroup', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget(_buildSliverMainAxisGroup( controller: controller, slivers: <Widget>[ @@ -612,8 +636,9 @@ void main() { expect((renderHeader.parentData! as SliverPhysicalParentData).paintOffset.dy, equals(-50.0)); }); - testWidgets('SliverMainAxisGroup skips painting invisible children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverMainAxisGroup skips painting invisible children', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); int counter = 0; void incrementCounter() { diff --git a/packages/flutter/test/widgets/sliver_persistent_header_test.dart b/packages/flutter/test/widgets/sliver_persistent_header_test.dart index 8fb239f7a52d5..26f8cb2f4ec9a 100644 --- a/packages/flutter/test/widgets/sliver_persistent_header_test.dart +++ b/packages/flutter/test/widgets/sliver_persistent_header_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/src/rendering/sliver_persistent_header.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets( + testWidgetsWithLeakTracking( '_SliverScrollingPersistentHeader should update stretchConfiguration', (WidgetTester tester) async { for (final double stretchTriggerOffset in <double>[10.0, 20.0]) { @@ -37,7 +38,7 @@ void main() { expect(render.stretchConfiguration?.stretchTriggerOffset, 20); }); - testWidgets( + testWidgetsWithLeakTracking( '_SliverPinnedPersistentHeader should update stretchConfiguration', (WidgetTester tester) async { for (final double stretchTriggerOffset in <double>[10.0, 20.0]) { @@ -68,7 +69,7 @@ void main() { expect(render.stretchConfiguration?.stretchTriggerOffset, 20); }); - testWidgets( + testWidgetsWithLeakTracking( '_SliverPinnedPersistentHeader should update showOnScreenConfiguration', (WidgetTester tester) async { for (final double maxShowOnScreenExtent in <double>[1000, 2000]) { diff --git a/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart b/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart index 48b000f5eb477..c7e9ff7409f40 100644 --- a/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart +++ b/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestItem extends StatelessWidget { const TestItem({ super.key, required this.item, this.width, this.height }); @@ -40,7 +41,7 @@ Widget buildFrame({ int? count, double? width, double? height, Axis? scrollDirec } void main() { - testWidgets('SliverPrototypeExtentList.builder test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList.builder test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -69,7 +70,7 @@ void main() { } }); - testWidgets('SliverPrototypeExtentList.builder test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList.builder test', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -95,7 +96,7 @@ void main() { expect(find.text('Item 7'), findsNothing); }); - testWidgets('SliverPrototypeExtentList vertical scrolling basics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList vertical scrolling basics', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(count: 20, height: 100.0)); // The viewport is 600 pixels high, lazily created items are 100 pixels high. @@ -121,7 +122,7 @@ void main() { } }); - testWidgets('SliverPrototypeExtentList horizontal scrolling basics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList horizontal scrolling basics', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(count: 20, width: 100.0, scrollDirection: Axis.horizontal)); // The viewport is 800 pixels wide, lazily created items are 100 pixels wide. @@ -147,7 +148,7 @@ void main() { } }); - testWidgets('SliverPrototypeExtentList change the prototype item', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList change the prototype item', (WidgetTester tester) async { await tester.pumpWidget(buildFrame(count: 10, height: 60.0)); // The viewport is 600 pixels high, each of the 10 items is 60 pixels high @@ -173,7 +174,7 @@ void main() { } }); - testWidgets('SliverPrototypeExtentList first item is also the prototype', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList first item is also the prototype', (WidgetTester tester) async { final List<Widget> items = List<Widget>.generate(10, (int index) { return TestItem(key: ValueKey<int>(index), item: index, height: index == 0 ? 60.0 : null); }).toList(); @@ -203,7 +204,7 @@ void main() { } }); - testWidgets('SliverPrototypeExtentList prototypeItem paint transform is zero.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPrototypeExtentList prototypeItem paint transform is zero.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/67117 // This test ensures that the SliverPrototypeExtentList does not cause an // assertion error when calculating the paint transform of its prototypeItem. diff --git a/packages/flutter/test/widgets/sliver_semantics_test.dart b/packages/flutter/test/widgets/sliver_semantics_test.dart index 9ccafcf316fbe..24e599281fd5e 100644 --- a/packages/flutter/test/widgets/sliver_semantics_test.dart +++ b/packages/flutter/test/widgets/sliver_semantics_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -19,12 +20,13 @@ void main() { } void _tests() { - testWidgets('excludeFromScrollable works correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('excludeFromScrollable works correctly', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const double appBarExpandedHeight = 200.0; final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); final List<Widget> listChildren = List<Widget>.generate(30, (int i) { return SizedBox( height: appBarExpandedHeight, @@ -281,7 +283,7 @@ void _tests() { semantics.dispose(); }); - testWidgets('Offscreen sliver are hidden in semantics tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Offscreen sliver are hidden in semantics tree', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const double containerHeight = 200.0; @@ -289,6 +291,7 @@ void _tests() { final ScrollController scrollController = ScrollController( initialScrollOffset: containerHeight * 1.5, ); + addTearDown(scrollController.dispose); final List<Widget> slivers = List<Widget>.generate(30, (int i) { return SliverToBoxAdapter( child: SizedBox( @@ -373,7 +376,7 @@ void _tests() { semantics.dispose(); }); - testWidgets('SemanticsNodes of Slivers are in paint order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNodes of Slivers are in paint order', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<Widget> slivers = List<Widget>.generate(5, (int i) { @@ -453,7 +456,7 @@ void _tests() { semantics.dispose(); }); - testWidgets('SemanticsNodes of a sliver fully covered by another overlapping sliver are excluded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNodes of a sliver fully covered by another overlapping sliver are excluded', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<Widget> listChildren = List<Widget>.generate(10, (int i) { @@ -463,6 +466,7 @@ void _tests() { ); }); final ScrollController controller = ScrollController(initialScrollOffset: 280.0); + addTearDown(controller.dispose); await tester.pumpWidget(Semantics( textDirection: TextDirection.ltr, child: Localizations( @@ -564,10 +568,11 @@ void _tests() { semantics.dispose(); }); - testWidgets('Slivers fully covered by another overlapping sliver are hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slivers fully covered by another overlapping sliver are hidden', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(initialScrollOffset: 280.0); + addTearDown(controller.dispose); final List<Widget> slivers = List<Widget>.generate(10, (int i) { return SliverToBoxAdapter( child: SizedBox( @@ -675,7 +680,7 @@ void _tests() { semantics.dispose(); }); - testWidgets('SemanticsNodes of a sliver fully covered by another overlapping sliver are excluded (reverse)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNodes of a sliver fully covered by another overlapping sliver are excluded (reverse)', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<Widget> listChildren = List<Widget>.generate(10, (int i) { @@ -685,6 +690,7 @@ void _tests() { ); }); final ScrollController controller = ScrollController(initialScrollOffset: 280.0); + addTearDown(controller.dispose); await tester.pumpWidget(Semantics( textDirection: TextDirection.ltr, child: Localizations( @@ -789,10 +795,11 @@ void _tests() { semantics.dispose(); }); - testWidgets('Slivers fully covered by another overlapping sliver are hidden (reverse)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slivers fully covered by another overlapping sliver are hidden (reverse)', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(initialScrollOffset: 280.0); + addTearDown(controller.dispose); final List<Widget> slivers = List<Widget>.generate(10, (int i) { return SliverToBoxAdapter( child: SizedBox( @@ -903,10 +910,11 @@ void _tests() { semantics.dispose(); }); - testWidgets('Slivers fully covered by another overlapping sliver are hidden (with center sliver)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slivers fully covered by another overlapping sliver are hidden (with center sliver)', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final ScrollController controller = ScrollController(initialScrollOffset: 280.0); + addTearDown(controller.dispose); final GlobalKey forwardAppBarKey = GlobalKey(debugLabel: 'forward app bar'); final List<Widget> forwardChildren = List<Widget>.generate(10, (int i) { return SizedBox( diff --git a/packages/flutter/test/widgets/sliver_visibility_test.dart b/packages/flutter/test/widgets/sliver_visibility_test.dart index 841563452f473..af9148d5dca57 100644 --- a/packages/flutter/test/widgets/sliver_visibility_test.dart +++ b/packages/flutter/test/widgets/sliver_visibility_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -29,7 +30,7 @@ class _TestStateState extends State<TestState> { } void main() { - testWidgets('SliverVisibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverVisibility', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> log = <String>[]; const Key anchor = Key('drag'); diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart index ff3ec8c8030ba..45c7922b55ecf 100644 --- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Sliver appBars - floating and pinned - correct elevation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appBars - floating and pinned - correct elevation', (WidgetTester tester) async { await tester.pumpWidget(Localizations( locale: const Locale('en', 'us'), delegates: const <LocalizationsDelegate<dynamic>>[ @@ -46,7 +47,7 @@ void main() { expect(renderObject.elevation, 0.0); }); - testWidgets('Sliver appbars - floating and pinned - correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - floating and pinned - correct semantics', (WidgetTester tester) async { await tester.pumpWidget( Localizations( locale: const Locale('en', 'us'), @@ -241,8 +242,10 @@ void main() { semantics.dispose(); }); - testWidgets('Sliver appbars - floating and pinned - second app bar stacks below', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - floating and pinned - second app bar stacks below', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -292,10 +295,12 @@ void main() { expect(tester.getTopLeft(find.text('E')), Offset(0.0, 200.0 + 56.0 + cSize.height * 2.0 + 500.0 - 600.0)); }); - testWidgets('Does not crash when there is less than minExtent remainingPaintExtent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not crash when there is less than minExtent remainingPaintExtent', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/21887. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); const double availableHeight = 50.0; + await tester.pumpWidget( MaterialApp( home: Center( @@ -337,7 +342,7 @@ void main() { expect(render.geometry!.layoutExtent, 0.0); }); - testWidgets('Pinned and floating SliverAppBar sticks to top the content is scroll down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Pinned and floating SliverAppBar sticks to top the content is scroll down', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -371,7 +376,7 @@ void main() { expect(render.geometry!.paintOrigin, -scrollDistance); }); - testWidgets('Floating SliverAppBar sticks to top the content is scroll down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Floating SliverAppBar sticks to top the content is scroll down', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -404,7 +409,7 @@ void main() { expect(render.geometry!.paintOrigin, -scrollDistance); }); - testWidgets('Pinned SliverAppBar sticks to top the content is scroll down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Pinned SliverAppBar sticks to top the content is scroll down', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_test.dart index 01e32544b3699..de3fb1b2b379b 100644 --- a/packages/flutter/test/widgets/slivers_appbar_floating_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_floating_test.dart @@ -7,6 +7,7 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void verifyPaintPosition(GlobalKey key, Offset ideal, bool visible) { final RenderSliver target = key.currentContext!.findRenderObject()! as RenderSliver; @@ -25,7 +26,7 @@ void verifyActualBoxPosition(WidgetTester tester, Finder finder, int index, Rect } void main() { - testWidgets("Sliver appbars - floating - scroll offset doesn't change", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Sliver appbars - floating - scroll offset doesn't change", (WidgetTester tester) async { const double bigHeight = 1000.0; await tester.pumpWidget( Directionality( @@ -53,7 +54,7 @@ void main() { expect(position.maxScrollExtent, max); }); - testWidgets('Sliver appbars - floating - normal behavior works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - floating - normal behavior works', (WidgetTester tester) async { final TestDelegate delegate = TestDelegate(); const double bigHeight = 1000.0; GlobalKey key1, key2, key3; @@ -125,7 +126,7 @@ void main() { verifyPaintPosition(key3, Offset.zero, true); }); - testWidgets('Sliver appbars - floating - no floating behavior when animating', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - floating - no floating behavior when animating', (WidgetTester tester) async { final TestDelegate delegate = TestDelegate(); const double bigHeight = 1000.0; GlobalKey key1, key2, key3; @@ -160,7 +161,7 @@ void main() { verifyPaintPosition(key3, Offset.zero, true); }); - testWidgets('Sliver appbars - floating - floating behavior when dragging down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - floating - floating behavior when dragging down', (WidgetTester tester) async { final TestDelegate delegate = TestDelegate(); const double bigHeight = 1000.0; GlobalKey key1, key2, key3; @@ -197,7 +198,7 @@ void main() { verifyPaintPosition(key3, Offset.zero, true); }); - testWidgets('Sliver appbars - floating - overscroll gap is below header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - floating - overscroll gap is below header', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -258,7 +259,7 @@ void main() { expect(geometry.paintExtent, paintExtent); } - testWidgets('SliverAppBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildTest(SliverAppBar( key: appBarKey, @@ -312,7 +313,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 56.0, visible: true); }); - testWidgets('SliverPersistentHeader', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPersistentHeader', (WidgetTester tester) async { final GlobalKey headerKey = GlobalKey(); await tester.pumpWidget(buildTest(SliverPersistentHeader( key: headerKey, @@ -354,7 +355,7 @@ void main() { verifyGeometry(key: headerKey, paintExtent: 56.0, visible: true); }); - testWidgets('and snapping SliverAppBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('and snapping SliverAppBar', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildTest(SliverAppBar( key: appBarKey, diff --git a/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart index 2651ec271d3c3..8c57dad28c3e8 100644 --- a/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_pinned_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void verifyPaintPosition(GlobalKey key, Offset ideal, bool visible) { final RenderSliver target = key.currentContext!.findRenderObject()! as RenderSliver; @@ -23,7 +24,7 @@ void verifyActualBoxPosition(WidgetTester tester, Finder finder, int index, Rect } void main() { - testWidgets('Sliver appbars - pinned', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - pinned', (WidgetTester tester) async { const double bigHeight = 550.0; GlobalKey key1, key2, key3, key4, key5; await tester.pumpWidget( @@ -59,7 +60,7 @@ void main() { verifyPaintPosition(key5, const Offset(0.0, 50.0), true); }); - testWidgets('Sliver appbars - toStringDeep of maxExtent that throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - toStringDeep of maxExtent that throws', (WidgetTester tester) async { final TestDelegateThatCanThrow delegateThatCanThrow = TestDelegateThatCanThrow(); GlobalKey key; await tester.pumpWidget( @@ -121,7 +122,7 @@ void main() { ); }); - testWidgets('Sliver appbars - pinned with slow scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - pinned with slow scroll', (WidgetTester tester) async { const double bigHeight = 550.0; GlobalKey key1, key2, key3, key4, key5; await tester.pumpWidget( @@ -214,7 +215,7 @@ void main() { verifyPaintPosition(key5, const Offset(0.0, 550.0), true); }); - testWidgets('Sliver appbars - pinned with less overlap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - pinned with less overlap', (WidgetTester tester) async { const double bigHeight = 650.0; GlobalKey key1, key2, key3, key4, key5; await tester.pumpWidget( @@ -250,7 +251,7 @@ void main() { verifyPaintPosition(key5, Offset.zero, true); }); - testWidgets('Sliver appbars - overscroll gap is below header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - overscroll gap is below header', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart b/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart index 9042575fc9b7b..5b2e7f77af663 100644 --- a/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_scrolling_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void verifyPaintPosition(GlobalKey key, Offset ideal) { final RenderObject target = key.currentContext!.findRenderObject()!; @@ -15,7 +16,7 @@ void verifyPaintPosition(GlobalKey key, Offset ideal) { } void main() { - testWidgets('Sliver appbars - scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - scrolling', (WidgetTester tester) async { GlobalKey key1, key2, key3, key4, key5; await tester.pumpWidget( Directionality( @@ -50,7 +51,7 @@ void main() { verifyPaintPosition(key5, const Offset(0.0, 50.0)); }); - testWidgets('Sliver appbars - scrolling off screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - scrolling off screen', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final TestDelegate delegate = TestDelegate(); await tester.pumpWidget( @@ -74,7 +75,7 @@ void main() { expect(rect, equals(const Rect.fromLTWH(0.0, -195.0, 800.0, 200.0))); }); - testWidgets('Sliver appbars - scrolling - overscroll gap is below header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars - scrolling - overscroll gap is below header', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -106,7 +107,7 @@ void main() { expect(tester.getTopLeft(find.text('X')), const Offset(0.0, 250.0)); }); - testWidgets('Sliver appbars const child delegate - scrolling - overscroll gap is below header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver appbars const child delegate - scrolling - overscroll gap is below header', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/slivers_appbar_stretch_test.dart b/packages/flutter/test/widgets/slivers_appbar_stretch_test.dart index 74137bf010549..6ffccf5e09ead 100644 --- a/packages/flutter/test/widgets/slivers_appbar_stretch_test.dart +++ b/packages/flutter/test/widgets/slivers_appbar_stretch_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('SliverAppBar - Stretch', () { - testWidgets('fills overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fills overscroll', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -43,7 +44,7 @@ void main() { expect(header.child!.size.height, equals(200.0)); }); - testWidgets('fills overscroll after reverse direction input - scrolling header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fills overscroll after reverse direction input - scrolling header', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -92,7 +93,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('fills overscroll after reverse direction input - floating header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fills overscroll after reverse direction input - floating header', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -142,7 +143,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('does not stretch without overscroll physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not stretch without overscroll physics', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -177,7 +178,7 @@ void main() { expect(header.child!.size.height, equals(100.0)); }); - testWidgets('default trigger offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default trigger offset', (WidgetTester tester) async { bool didTrigger = false; const Key anchor = Key('drag'); await tester.pumpWidget( @@ -215,7 +216,7 @@ void main() { expect(didTrigger, isTrue); }); - testWidgets('custom trigger offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('custom trigger offset', (WidgetTester tester) async { bool didTrigger = false; const Key anchor = Key('drag'); await tester.pumpWidget( @@ -254,7 +255,7 @@ void main() { expect(didTrigger, isTrue); }); - testWidgets('stretch callback not triggered without overscroll physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('stretch callback not triggered without overscroll physics', (WidgetTester tester) async { bool didTrigger = false; const Key anchor = Key('drag'); await tester.pumpWidget( @@ -293,7 +294,7 @@ void main() { expect(didTrigger, isFalse); }); - testWidgets('asserts reasonable trigger offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('asserts reasonable trigger offset', (WidgetTester tester) async { expect( () { return MaterialApp( @@ -325,7 +326,7 @@ void main() { }); group('SliverAppBar - Stretch, Pinned', () { - testWidgets('fills overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fills overscroll', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -360,7 +361,7 @@ void main() { expect(header.child!.size.height, equals(200.0)); }); - testWidgets('does not stretch without overscroll physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not stretch without overscroll physics', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -397,7 +398,7 @@ void main() { }); group('SliverAppBar - Stretch, Floating', () { - testWidgets('fills overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fills overscroll', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -432,7 +433,7 @@ void main() { expect(header.child!.size.height, equals(200.0)); }); - testWidgets('does not fill overscroll without proper physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not fill overscroll without proper physics', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -469,7 +470,7 @@ void main() { }); group('SliverAppBar - Stretch, Floating, Pinned', () { - testWidgets('fills overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fills overscroll', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( @@ -505,7 +506,7 @@ void main() { expect(header.child!.size.height, equals(200.0)); }); - testWidgets('does not fill overscroll without proper physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not fill overscroll without proper physics', (WidgetTester tester) async { const Key anchor = Key('drag'); await tester.pumpWidget( MaterialApp( diff --git a/packages/flutter/test/widgets/slivers_block_global_key_test.dart b/packages/flutter/test/widgets/slivers_block_global_key_test.dart index 3b754cb602d6b..495d8c211d770 100644 --- a/packages/flutter/test/widgets/slivers_block_global_key_test.dart +++ b/packages/flutter/test/widgets/slivers_block_global_key_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; int globalGeneration = 0; @@ -25,13 +26,15 @@ class _GenerationTextState extends State<GenerationText> { // Creates a SliverList with `keys.length` children and each child having a key from `keys` and a text of `key:generation`. // The generation is increased with every call to this method. Future<void> test(WidgetTester tester, double offset, List<int> keys) { + final ViewportOffset viewportOffset = ViewportOffset.fixed(offset); + addTearDown(viewportOffset.dispose); globalGeneration += 1; return tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( cacheExtent: 0.0, - offset: ViewportOffset.fixed(offset), + offset: viewportOffset, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(keys.map<Widget>((int key) { @@ -59,7 +62,7 @@ void verify(WidgetTester tester, List<Offset> answerKey, String text) { } void main() { - testWidgets('Viewport+SliverBlock with GlobalKey reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverBlock with GlobalKey reparenting', (WidgetTester tester) async { await test(tester, 0.0, <int>[1,2,3,4,5,6,7,8,9]); verify(tester, <Offset>[ Offset.zero, diff --git a/packages/flutter/test/widgets/slivers_block_test.dart b/packages/flutter/test/widgets/slivers_block_test.dart index 7b76ab452b551..b4b75211cc1ec 100644 --- a/packages/flutter/test/widgets/slivers_block_test.dart +++ b/packages/flutter/test/widgets/slivers_block_test.dart @@ -5,13 +5,16 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Future<void> test(WidgetTester tester, double offset) { + final ViewportOffset viewportOffset = ViewportOffset.fixed(offset); + addTearDown(viewportOffset.dispose); return tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(offset), + offset: viewportOffset, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(const <Widget>[ @@ -29,11 +32,13 @@ Future<void> test(WidgetTester tester, double offset) { } Future<void> testWithConstChildDelegate(WidgetTester tester, double offset) { + final ViewportOffset viewportOffset = ViewportOffset.fixed(offset); + addTearDown(viewportOffset.dispose); return tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(offset), + offset: viewportOffset, slivers: const <Widget>[ SliverList( delegate: SliverChildListDelegate.fixed(<Widget>[ @@ -63,7 +68,7 @@ void verify(WidgetTester tester, List<Offset> answerKey, String text) { } void main() { - testWidgets('Viewport+SliverBlock basic test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverBlock basic test', (WidgetTester tester) async { await test(tester, 0.0); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); verify(tester, <Offset>[ @@ -96,7 +101,7 @@ void main() { ], 'ab'); }); - testWidgets('Viewport+SliverBlock basic test with constant SliverChildListDelegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverBlock basic test with constant SliverChildListDelegate', (WidgetTester tester) async { await testWithConstChildDelegate(tester, 0.0); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); verify(tester, <Offset>[ @@ -129,9 +134,10 @@ void main() { ], 'ab'); }); - testWidgets('Viewport with GlobalKey reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport with GlobalKey reparenting', (WidgetTester tester) async { final Key key1 = GlobalKey(); final ViewportOffset offset = ViewportOffset.zero(); + addTearDown(offset.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -242,12 +248,15 @@ void main() { ], 'acb'); }); - testWidgets('Viewport overflow clipping of SliverToBoxAdapter', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport overflow clipping of SliverToBoxAdapter', (WidgetTester tester) async { + final ViewportOffset offset1 = ViewportOffset.zero(); + addTearDown(offset1.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.zero(), + offset: offset1, slivers: const <Widget>[ SliverToBoxAdapter( child: SizedBox(height: 400.0, child: Text('a')), @@ -259,11 +268,14 @@ void main() { expect(find.byType(Viewport), isNot(paints..clipRect())); + final ViewportOffset offset2 = ViewportOffset.fixed(100.0); + addTearDown(offset2.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(100.0), + offset: offset2, slivers: const <Widget>[ SliverToBoxAdapter( child: SizedBox(height: 400.0, child: Text('a')), @@ -275,11 +287,14 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); + final ViewportOffset offset3 = ViewportOffset.fixed(100.0); + addTearDown(offset3.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(100.0), + offset: offset3, slivers: const <Widget>[ SliverToBoxAdapter( child: SizedBox(height: 4000.0, child: Text('a')), @@ -291,11 +306,14 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); + final ViewportOffset offset4 = ViewportOffset.zero(); + addTearDown(offset4.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.zero(), + offset: offset4, slivers: const <Widget>[ SliverToBoxAdapter( child: SizedBox(height: 4000.0, child: Text('a')), @@ -308,12 +326,15 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); }); - testWidgets('Viewport overflow clipping of SliverBlock', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport overflow clipping of SliverBlock', (WidgetTester tester) async { + final ViewportOffset offset1 = ViewportOffset.zero(); + addTearDown(offset1.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.zero(), + offset: offset1, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(const <Widget>[ @@ -327,11 +348,14 @@ void main() { expect(find.byType(Viewport), isNot(paints..clipRect())); + final ViewportOffset offset2 = ViewportOffset.fixed(100.0); + addTearDown(offset2.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(100.0), + offset: offset2, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(const <Widget>[ @@ -345,11 +369,14 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); + final ViewportOffset offset3 = ViewportOffset.fixed(100.0); + addTearDown(offset3.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(100.0), + offset: offset3, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(const <Widget>[ @@ -363,11 +390,14 @@ void main() { expect(find.byType(Viewport), paints..clipRect()); + final ViewportOffset offset4 = ViewportOffset.zero(); + addTearDown(offset4.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.zero(), + offset: offset4, slivers: <Widget>[ SliverList( delegate: SliverChildListDelegate(const <Widget>[ diff --git a/packages/flutter/test/widgets/slivers_evil_test.dart b/packages/flutter/test/widgets/slivers_evil_test.dart index 2c9aa0ef35366..d821c969ff47d 100644 --- a/packages/flutter/test/widgets/slivers_evil_test.dart +++ b/packages/flutter/test/widgets/slivers_evil_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { TestSliverPersistentHeaderDelegate(this._maxExtent); @@ -57,7 +58,7 @@ class TestScrollPhysics extends ClampingScrollPhysics { } void main() { - testWidgets('Evil test of sliver features - 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Evil test of sliver features - 1', (WidgetTester tester) async { final GlobalKey centerKey = GlobalKey(); await tester.pumpWidget( MediaQuery( @@ -184,7 +185,7 @@ void main() { }); - testWidgets('Removing offscreen items above and rescrolling does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Removing offscreen items above and rescrolling does not crash', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: CustomScrollView( cacheExtent: 0.0, diff --git a/packages/flutter/test/widgets/slivers_keepalive_test.dart b/packages/flutter/test/widgets/slivers_keepalive_test.dart index ae7dc37c4cc46..b75c5c405bc94 100644 --- a/packages/flutter/test/widgets/slivers_keepalive_test.dart +++ b/packages/flutter/test/widgets/slivers_keepalive_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Sliver with keep alive without key - should dispose after reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver with keep alive without key - should dispose after reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ const WidgetTest0(text: 'child 0', keepAlive: true), const WidgetTest1(text: 'child 1', keepAlive: true), @@ -29,7 +30,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('Sliver without keep alive without key - should dispose after reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver without keep alive without key - should dispose after reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ const WidgetTest0(text: 'child 0'), const WidgetTest1(text: 'child 1'), @@ -52,7 +53,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('Sliver without keep alive with key - should dispose after reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver without keep alive with key - should dispose after reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: GlobalKey()), WidgetTest1(text: 'child 1', key: GlobalKey()), @@ -75,7 +76,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('Sliver with keep alive with key - should not dispose after reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver with keep alive with key - should not dispose after reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: GlobalKey(), keepAlive: true), WidgetTest1(text: 'child 1', key: GlobalKey(), keepAlive: true), @@ -97,7 +98,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('Sliver with keep alive with Unique key - should not dispose after reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver with keep alive with Unique key - should not dispose after reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true), WidgetTest1(text: 'child 1', key: UniqueKey(), keepAlive: true), @@ -119,7 +120,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('Sliver with keep alive with Value key - should not dispose after reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver with keep alive with Value key - should not dispose after reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ const WidgetTest0(text: 'child 0', key: ValueKey<int>(0), keepAlive: true), const WidgetTest1(text: 'child 1', key: ValueKey<int>(1), keepAlive: true), @@ -141,7 +142,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('Sliver complex case 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver complex case 1', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: GlobalKey(), keepAlive: true), WidgetTest1(text: 'child 1', key: GlobalKey(), keepAlive: true), @@ -185,7 +186,7 @@ void main() { expect(state2.hasBeenDisposed, true); }); - testWidgets('Sliver complex case 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver complex case 2', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: GlobalKey(), keepAlive: true), WidgetTest1(text: 'child 1', key: UniqueKey()), @@ -228,7 +229,7 @@ void main() { expect(state2.hasBeenDisposed, true); }); - testWidgets('Sliver with SliverChildBuilderDelegate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver with SliverChildBuilderDelegate', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true), WidgetTest1(text: 'child 1', key: GlobalKey()), @@ -271,7 +272,7 @@ void main() { expect(state2.hasBeenDisposed, true); }); - testWidgets('SliverFillViewport should not dispose widget with key during in screen reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFillViewport should not dispose widget with key during in screen reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true), WidgetTest1(text: 'child 1', key: UniqueKey()), @@ -312,7 +313,7 @@ void main() { expect(state2.hasBeenDisposed, true); }); - testWidgets('SliverList should not dispose widget with key during in screen reordering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList should not dispose widget with key during in screen reordering', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true), const WidgetTest1(text: 'child 1', keepAlive: true), @@ -362,7 +363,7 @@ void main() { expect(state2.hasBeenDisposed, false); }); - testWidgets('SliverList remove child from child list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList remove child from child list', (WidgetTester tester) async { List<Widget> childList= <Widget>[ WidgetTest0(text: 'child 0', key: UniqueKey(), keepAlive: true), const WidgetTest1(text: 'child 1', keepAlive: true), diff --git a/packages/flutter/test/widgets/slivers_padding_test.dart b/packages/flutter/test/widgets/slivers_padding_test.dart index 619f024be53fd..8886cca1391a1 100644 --- a/packages/flutter/test/widgets/slivers_padding_test.dart +++ b/packages/flutter/test/widgets/slivers_padding_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _MockRenderSliver extends RenderSliver { @override @@ -19,11 +20,13 @@ class _MockRenderSliver extends RenderSliver { } Future<void> test(WidgetTester tester, double offset, EdgeInsetsGeometry padding, AxisDirection axisDirection, TextDirection textDirection) { + final ViewportOffset viewportOffset = ViewportOffset.fixed(offset); + addTearDown(viewportOffset.dispose); return tester.pumpWidget( Directionality( textDirection: textDirection, child: Viewport( - offset: ViewportOffset.fixed(offset), + offset: viewportOffset, axisDirection: axisDirection, slivers: <Widget>[ const SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('before'))), @@ -50,7 +53,7 @@ void verify(WidgetTester tester, List<Rect> answerKey) { } void main() { - testWidgets('Viewport+SliverPadding basic test (VISUAL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding basic test (VISUAL)', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.fromLTRB(25.0, 20.0, 15.0, 35.0); await test(tester, 0.0, padding, AxisDirection.down, TextDirection.ltr); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -89,7 +92,7 @@ void main() { ]); }); - testWidgets('Viewport+SliverPadding basic test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding basic test (LTR)', (WidgetTester tester) async { const EdgeInsetsDirectional padding = EdgeInsetsDirectional.fromSTEB(25.0, 20.0, 15.0, 35.0); await test(tester, 0.0, padding, AxisDirection.down, TextDirection.ltr); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -128,7 +131,7 @@ void main() { ]); }); - testWidgets('Viewport+SliverPadding basic test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding basic test (RTL)', (WidgetTester tester) async { const EdgeInsetsDirectional padding = EdgeInsetsDirectional.fromSTEB(25.0, 20.0, 15.0, 35.0); await test(tester, 0.0, padding, AxisDirection.down, TextDirection.rtl); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -167,7 +170,7 @@ void main() { ]); }); - testWidgets('Viewport+SliverPadding hit testing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding hit testing', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); await test(tester, 350.0, padding, AxisDirection.down, TextDirection.ltr); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -189,7 +192,7 @@ void main() { expectIsTextSpan(result.path.first.target, 'after'); }); - testWidgets('Viewport+SliverPadding hit testing up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding hit testing up', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); await test(tester, 350.0, padding, AxisDirection.up, TextDirection.ltr); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -211,7 +214,7 @@ void main() { expectIsTextSpan(result.path.first.target, 'after'); }); - testWidgets('Viewport+SliverPadding hit testing left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding hit testing left', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); await test(tester, 350.0, padding, AxisDirection.left, TextDirection.ltr); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -233,7 +236,7 @@ void main() { expectIsTextSpan(result.path.first.target, 'after'); }); - testWidgets('Viewport+SliverPadding hit testing right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding hit testing right', (WidgetTester tester) async { const EdgeInsets padding = EdgeInsets.all(30.0); await test(tester, 350.0, padding, AxisDirection.right, TextDirection.ltr); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); @@ -255,12 +258,15 @@ void main() { expectIsTextSpan(result.path.first.target, 'after'); }); - testWidgets('Viewport+SliverPadding no child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding no child', (WidgetTester tester) async { + final ViewportOffset offset = ViewportOffset.fixed(0.0); + addTearDown(offset.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(0.0), + offset: offset, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.all(100.0)), SliverToBoxAdapter(child: SizedBox(width: 400.0, height: 400.0, child: Text('x'))), @@ -271,9 +277,10 @@ void main() { expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(0.0, 200.0)); }); - testWidgets('SliverPadding with no child reports correct geometry as scroll offset changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPadding with no child reports correct geometry as scroll offset changes', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/64506 final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -299,13 +306,16 @@ void main() { ); }); - testWidgets('Viewport+SliverPadding changing padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding changing padding', (WidgetTester tester) async { + final ViewportOffset offset1 = ViewportOffset.fixed(0.0); + addTearDown(offset1.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( axisDirection: AxisDirection.left, - offset: ViewportOffset.fixed(0.0), + offset: offset1, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(90.0, 1.0, 110.0, 2.0)), SliverToBoxAdapter(child: SizedBox(width: 201.0, child: Text('x'))), @@ -313,13 +323,18 @@ void main() { ), ), ); + expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(399.0, 0.0)); + + final ViewportOffset offset2 = ViewportOffset.fixed(0.0); + addTearDown(offset2.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( axisDirection: AxisDirection.left, - offset: ViewportOffset.fixed(0.0), + offset: offset2, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(110.0, 1.0, 80.0, 2.0)), SliverToBoxAdapter(child: SizedBox(width: 201.0, child: Text('x'))), @@ -327,77 +342,102 @@ void main() { ), ), ); + expect(tester.renderObject<RenderBox>(find.text('x')).localToGlobal(Offset.zero), const Offset(409.0, 0.0)); }); - testWidgets('Viewport+SliverPadding changing direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport+SliverPadding changing direction', (WidgetTester tester) async { + final ViewportOffset offset1 = ViewportOffset.fixed(0.0); + addTearDown(offset1.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( axisDirection: AxisDirection.up, - offset: ViewportOffset.fixed(0.0), + offset: offset1, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)), ], ), ), ); + expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 2.0); + + final ViewportOffset offset2 = ViewportOffset.fixed(0.0); + addTearDown(offset2.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(0.0), + offset: offset2, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)), ], ), ), ); + expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 8.0); + + final ViewportOffset offset3 = ViewportOffset.fixed(0.0); + addTearDown(offset3.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( axisDirection: AxisDirection.right, - offset: ViewportOffset.fixed(0.0), + offset: offset3, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)), ], ), ), ); + expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 4.0); + + final ViewportOffset offset4 = ViewportOffset.fixed(0.0); + addTearDown(offset4.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( axisDirection: AxisDirection.left, - offset: ViewportOffset.fixed(0.0), + offset: offset4, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)), ], ), ), ); + expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 1.0); + + final ViewportOffset offset5 = ViewportOffset.fixed(99999.9); + addTearDown(offset5.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( axisDirection: AxisDirection.left, - offset: ViewportOffset.fixed(99999.9), + offset: offset5, slivers: const <Widget>[ SliverPadding(padding: EdgeInsets.fromLTRB(1.0, 2.0, 4.0, 8.0)), ], ), ), ); + expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding, skipOffstage: false)).afterPadding, 1.0); }); - testWidgets('SliverPadding propagates geometry offset corrections', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPadding propagates geometry offset corrections', (WidgetTester tester) async { Widget listBuilder(IndexedWidgetBuilder sliverChildBuilder) { return Directionality( textDirection: TextDirection.ltr, @@ -463,7 +503,7 @@ void main() { ); }); - testWidgets('SliverPadding includes preceding padding in the precedingScrollExtent provided to child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPadding includes preceding padding in the precedingScrollExtent provided to child', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/49195 final UniqueKey key = UniqueKey(); await tester.pumpWidget(Directionality( @@ -496,11 +536,13 @@ void main() { ); }); - testWidgets("SliverPadding consumes only its padding from the overlap of its parent's constraints", (WidgetTester tester) async { + testWidgetsWithLeakTracking("SliverPadding consumes only its padding from the overlap of its parent's constraints", (WidgetTester tester) async { final _MockRenderSliver mock = _MockRenderSliver(); + addTearDown(mock.dispose); final RenderSliverPadding renderObject = RenderSliverPadding( padding: const EdgeInsets.only(top: 20), ); + addTearDown(renderObject.dispose); renderObject.child = mock; renderObject.layout(const SliverConstraints( viewportMainAxisExtent: 100.0, @@ -521,11 +563,13 @@ void main() { expect(mock.constraints.overlap, 80.0); }); - testWidgets("SliverPadding passes the overlap to the child if it's negative", (WidgetTester tester) async { + testWidgetsWithLeakTracking("SliverPadding passes the overlap to the child if it's negative", (WidgetTester tester) async { final _MockRenderSliver mock = _MockRenderSliver(); + addTearDown(mock.dispose); final RenderSliverPadding renderObject = RenderSliverPadding( padding: const EdgeInsets.only(top: 20), ); + addTearDown(renderObject.dispose); renderObject.child = mock; renderObject.layout(const SliverConstraints( viewportMainAxisExtent: 100.0, @@ -546,11 +590,13 @@ void main() { expect(mock.constraints.overlap, -100.0); }); - testWidgets('SliverPadding passes the paintOrigin of the child on', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverPadding passes the paintOrigin of the child on', (WidgetTester tester) async { final _MockRenderSliver mock = _MockRenderSliver(); + addTearDown(mock.dispose); final RenderSliverPadding renderObject = RenderSliverPadding( padding: const EdgeInsets.only(top: 20), ); + addTearDown(renderObject.dispose); renderObject.child = mock; renderObject.layout(const SliverConstraints( viewportMainAxisExtent: 100.0, diff --git a/packages/flutter/test/widgets/slivers_protocol_test.dart b/packages/flutter/test/widgets/slivers_protocol_test.dart index 6758b7dd0e48a..c93c93daacd22 100644 --- a/packages/flutter/test/widgets/slivers_protocol_test.dart +++ b/packages/flutter/test/widgets/slivers_protocol_test.dart @@ -7,6 +7,7 @@ import 'dart:math' as math; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void verifyPaintPosition(GlobalKey key, Offset ideal) { final RenderObject target = key.currentContext!.findRenderObject()!; @@ -17,7 +18,7 @@ void verifyPaintPosition(GlobalKey key, Offset ideal) { } void main() { - testWidgets('Sliver protocol', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sliver protocol', (WidgetTester tester) async { GlobalKey key1, key2, key3, key4, key5; await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/slivers_test.dart b/packages/flutter/test/widgets/slivers_test.dart index 0685d126a21f5..71769d00d6dad 100644 --- a/packages/flutter/test/widgets/slivers_test.dart +++ b/packages/flutter/test/widgets/slivers_test.dart @@ -6,16 +6,19 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; Future<void> test(WidgetTester tester, double offset, { double anchor = 0.0 }) { + final ViewportOffset viewportOffset = ViewportOffset.fixed(offset); + addTearDown(viewportOffset.dispose); return tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: Viewport( anchor: anchor / 600.0, - offset: ViewportOffset.fixed(offset), + offset: viewportOffset, slivers: const <Widget>[ SliverToBoxAdapter(child: SizedBox(height: 400.0)), SliverToBoxAdapter(child: SizedBox(height: 400.0)), @@ -70,7 +73,7 @@ void verify(WidgetTester tester, List<Offset> idealPositions, List<bool> idealVi } void main() { - testWidgets('Viewport basic test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport basic test', (WidgetTester tester) async { await test(tester, 0.0); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); verify(tester, <Offset>[ @@ -109,7 +112,7 @@ void main() { ], <bool>[false, false, true, true, false]); }); - testWidgets('Viewport anchor test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Viewport anchor test', (WidgetTester tester) async { await test(tester, 0.0, anchor: 100.0); expect(tester.renderObject<RenderBox>(find.byType(Viewport)).size, equals(const Size(800.0, 600.0))); verify(tester, <Offset>[ @@ -148,7 +151,7 @@ void main() { ], <bool>[false, false, true, true, false]); }); - testWidgets('Multiple grids and lists', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiple grids and lists', (WidgetTester tester) async { await tester.pumpWidget( Center( child: SizedBox( @@ -229,7 +232,7 @@ void main() { expect(find.text('BOTTOM'), findsOneWidget); }); - testWidgets('SliverFixedExtentList correctly clears garbage', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFixedExtentList correctly clears garbage', (WidgetTester tester) async { final List<String> items = <String>['1', '2', '3', '4', '5', '6']; await testSliverFixedExtentList(tester, items); // Keep alive widgets require 1 frame to notify their parents. Pumps in between @@ -270,7 +273,7 @@ void main() { expect(find.text('4'), findsOneWidget); }); - testWidgets('SliverFixedExtentList handles underflow when its children changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFixedExtentList handles underflow when its children changes', (WidgetTester tester) async { final List<String> items = <String>['1', '2', '3', '4', '5', '6']; final List<String> initializedChild = <String>[]; List<Widget> children = <Widget>[]; @@ -282,6 +285,8 @@ void main() { ); } final ScrollController controller = ScrollController(initialScrollOffset: 5400); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -335,7 +340,7 @@ void main() { expect(listEquals<String>(initializedChild, <String>['6']), isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'SliverGrid Correctly layout children after rearranging', (WidgetTester tester) async { await tester.pumpWidget(const TestSliverGrid( @@ -368,7 +373,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'SliverGrid negative usableCrossAxisExtent', (WidgetTester tester) async { await tester.pumpWidget( @@ -406,7 +411,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'SliverList can handle inaccurate scroll offset due to changes in children list', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/pull/59888. @@ -510,7 +515,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'SliverFixedExtentList Correctly layout children after rearranging', (WidgetTester tester) async { await tester.pumpWidget(const TestSliverFixedExtentList( @@ -548,7 +553,7 @@ void main() { }, ); - testWidgets('Can override ErrorWidget.build', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can override ErrorWidget.build', (WidgetTester tester) async { const Text errorText = Text('error'); final ErrorWidgetBuilder oldBuilder = ErrorWidget.builder; ErrorWidget.builder = (FlutterErrorDetails details) => errorText; @@ -564,8 +569,10 @@ void main() { ErrorWidget.builder = oldBuilder; }); - testWidgets('SliverFixedExtentList with SliverChildBuilderDelegate auto-correct scroll offset - super fast', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFixedExtentList with SliverChildBuilderDelegate auto-correct scroll offset - super fast', (WidgetTester tester) async { final ScrollController controller = ScrollController(initialScrollOffset: 600); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -611,8 +618,10 @@ void main() { expect(controller.offset, 800.0); }); - testWidgets('SliverFixedExtentList with SliverChildBuilderDelegate auto-correct scroll offset - reasonable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFixedExtentList with SliverChildBuilderDelegate auto-correct scroll offset - reasonable', (WidgetTester tester) async { final ScrollController controller = ScrollController(initialScrollOffset: 600); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -661,7 +670,7 @@ void main() { } group('SliverOffstage - ', () { - testWidgets('offstage true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('offstage true', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(boilerPlate( const SliverOffstage( @@ -680,7 +689,7 @@ void main() { semantics.dispose(); }); - testWidgets('offstage false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('offstage false', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(boilerPlate( const SliverOffstage( @@ -702,7 +711,7 @@ void main() { }); group('SliverOpacity - ', () { - testWidgets('painting & semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('painting & semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // Opacity 1.0: Semantics and painting @@ -824,7 +833,7 @@ void main() { }); group('SliverIgnorePointer - ', () { - testWidgets('ignores pointer events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores pointer events', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> events = <String>[]; await tester.pumpWidget(boilerPlate( @@ -846,7 +855,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignores semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> events = <String>[]; await tester.pumpWidget(boilerPlate( @@ -869,7 +878,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignoring only block semantics actions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignoring only block semantics actions', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(boilerPlate( SliverIgnorePointer( @@ -885,7 +894,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignores pointer events & semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores pointer events & semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> events = <String>[]; await tester.pumpWidget(boilerPlate( @@ -907,7 +916,7 @@ void main() { semantics.dispose(); }); - testWidgets('ignores nothing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores nothing', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> events = <String>[]; await tester.pumpWidget(boilerPlate( @@ -931,7 +940,7 @@ void main() { }); }); - testWidgets('SliverList handles 0 scrollOffsetCorrection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList handles 0 scrollOffsetCorrection', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/62198 await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -956,7 +965,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('SliverGrid children can be arbitrarily placed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGrid children can be arbitrarily placed', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/64006 int firstTapped = 0; int secondTapped = 0; @@ -1014,7 +1023,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverList.builder can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList.builder can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1052,7 +1061,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverList.builder can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList.builder can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1090,7 +1099,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverList.separated can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList.separated can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1129,7 +1138,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverList.separated has correct number of children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList.separated has correct number of children', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -1149,7 +1158,7 @@ void main() { expect(find.text('separator'), findsNWidgets(1)); }); - testWidgets('SliverList.list can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList.list can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1191,7 +1200,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverFixedExtentList.builder can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverFixedExtentList.builder can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1229,7 +1238,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverList.list can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverList.list can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1272,7 +1281,7 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverGrid.builder can build children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGrid.builder can build children', (WidgetTester tester) async { int firstTapped = 0; int secondTapped = 0; final Key key = UniqueKey(); @@ -1311,9 +1320,10 @@ void main() { expect(secondTapped, 1); }); - testWidgets('SliverGridRegularTileLayout.computeMaxScrollOffset handles 0 children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverGridRegularTileLayout.computeMaxScrollOffset handles 0 children', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59663 final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); // SliverGridDelegateWithFixedCrossAxisCount await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart index 55b222b24fb80..925684b5f24db 100644 --- a/packages/flutter/test/widgets/slotted_render_object_widget_test.dart +++ b/packages/flutter/test/widgets/slotted_render_object_widget_test.dart @@ -7,12 +7,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Color green = Color(0xFF00FF00); const Color yellow = Color(0xFFFFFF00); void main() { - testWidgets('SlottedRenderObjectWidget test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SlottedRenderObjectWidget test', (WidgetTester tester) async { await tester.pumpWidget(buildWidget( topLeft: Container( height: 100, @@ -137,7 +138,7 @@ void main() { expect(_RenderTest().publicNameForSlot(slot), slot.toString()); }); - testWidgets('key reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('key reparenting', (WidgetTester tester) async { const Widget widget1 = SizedBox(key: ValueKey<String>('smol'), height: 10, width: 10); const Widget widget2 = SizedBox(key: ValueKey<String>('big'), height: 100, width: 100); const Widget nullWidget = SizedBox(key: ValueKey<String>('null'), height: 50, width: 50); @@ -203,7 +204,7 @@ void main() { )); }); - testWidgets('debugDescribeChildren', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugDescribeChildren', (WidgetTester tester) async { await tester.pumpWidget(buildWidget( topLeft: const SizedBox( height: 100, diff --git a/packages/flutter/test/widgets/snapshot_widget_test.dart b/packages/flutter/test/widgets/snapshot_widget_test.dart index 05512bae827d7..e6faaa97a055e 100644 --- a/packages/flutter/test/widgets/snapshot_widget_test.dart +++ b/packages/flutter/test/widgets/snapshot_widget_test.dart @@ -13,11 +13,14 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('SnapshotWidget can rasterize child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnapshotWidget can rasterize child', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); final Key key = UniqueKey(); + await tester.pumpWidget(RepaintBoundary( key: key, child: TestDependencies( @@ -56,9 +59,11 @@ void main() { await expectLater(find.byKey(key), matchesGoldenFile('raster_widget.red.png')); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('Changing devicePixelRatio does not repaint if snapshotting is not enabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing devicePixelRatio does not repaint if snapshotting is not enabled', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(); + addTearDown(controller.dispose); final TestPainter painter = TestPainter(); + addTearDown(painter.dispose); double devicePixelRatio = 1.0; late StateSetter localSetState; @@ -89,9 +94,11 @@ void main() { expect(painter.count, 1); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('Changing devicePixelRatio forces raster regeneration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing devicePixelRatio forces raster regeneration', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); final TestPainter painter = TestPainter(); + addTearDown(painter.dispose); double devicePixelRatio = 1.0; late StateSetter localSetState; @@ -126,8 +133,10 @@ void main() { expect(raster, isNot(newRaster)); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('SnapshotWidget paints its child as a single picture layer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnapshotWidget paints its child as a single picture layer', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); + await tester.pumpWidget(RepaintBoundary( child: Center( child: TestDependencies( @@ -153,14 +162,21 @@ void main() { expect(tester.layers.last, isA<PictureLayer>()); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('SnapshotWidget can update the painter type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SnapshotWidget can update the painter type', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); + final TestPainter painter1 = TestPainter(); + addTearDown(painter1.dispose); + final TestPainter2 painter2 = TestPainter2(); + addTearDown(painter2.dispose); + + await tester.pumpWidget( Center( child: TestDependencies( child: SnapshotWidget( controller: controller, - painter: TestPainter(), + painter: painter1, child: const SizedBox(), ), ), @@ -172,7 +188,7 @@ void main() { child: TestDependencies( child: SnapshotWidget( controller: controller, - painter: TestPainter2(), + painter: painter2, child: const SizedBox(), ), ), @@ -182,8 +198,10 @@ void main() { expect(tester.takeException(), isNull); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('RenderSnapshotWidget does not error on rasterization of child with empty size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderSnapshotWidget does not error on rasterization of child with empty size', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); + await tester.pumpWidget( Center( child: TestDependencies( @@ -201,6 +219,8 @@ void main() { testWidgets('RenderSnapshotWidget throws assertion if platform view is encountered', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); + await tester.pumpWidget( Center( child: TestDependencies( @@ -220,8 +240,10 @@ void main() { .having((FlutterError error) => error.message, 'message', contains('SnapshotWidget used with a child that contains a PlatformView'))); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('RenderSnapshotWidget does not assert if SnapshotMode.forced', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderSnapshotWidget does not assert if SnapshotMode.forced', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); + await tester.pumpWidget( Center( child: TestDependencies( @@ -241,8 +263,10 @@ void main() { expect(tester.takeException(), isNull); }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - testWidgets('RenderSnapshotWidget does not take a snapshot if a platform view is encountered with SnapshotMode.permissive', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderSnapshotWidget does not take a snapshot if a platform view is encountered with SnapshotMode.permissive', (WidgetTester tester) async { final SnapshotController controller = SnapshotController(allowSnapshotting: true); + addTearDown(controller.dispose); + await tester.pumpWidget( Center( child: TestDependencies( @@ -261,9 +285,15 @@ void main() { expect(tester.takeException(), isNull); expect(tester.layers.last, isA<PlatformViewLayer>()); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 - - testWidgets('SnapshotWidget should have same result when enabled', (WidgetTester tester) async { + }, + skip: kIsWeb, // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/135141 + allowAllNotDisposed: true, + )); + + testWidgetsWithLeakTracking('SnapshotWidget should have same result when enabled', (WidgetTester tester) async { addTearDown(tester.view.reset); tester.view @@ -272,6 +302,8 @@ void main() { const ValueKey<String> repaintBoundaryKey = ValueKey<String>('boundary'); final SnapshotController controller = SnapshotController(); + addTearDown(controller.dispose); + await tester.pumpWidget(RepaintBoundary( key: repaintBoundaryKey, child: MaterialApp( @@ -291,12 +323,19 @@ void main() { )); final ui.Image imageWhenDisabled = (tester.renderObject(find.byKey(repaintBoundaryKey)) as RenderRepaintBoundary).toImageSync(); + addTearDown(imageWhenDisabled.dispose); controller.allowSnapshotting = true; await tester.pump(); await expectLater(find.byKey(repaintBoundaryKey), matchesReferenceImage(imageWhenDisabled)); - }, skip: kIsWeb); // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + }, + skip: kIsWeb, // TODO(jonahwilliams): https://github.com/flutter/flutter/issues/106689 + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/135137 + notDisposedAllowList: <String, int> {'Image': 1}, + )); } class TestPlatformView extends SingleChildRenderObjectWidget { diff --git a/packages/flutter/test/widgets/spacer_test.dart b/packages/flutter/test/widgets/spacer_test.dart index 06fbda26d2451..47ee53b3c06ac 100644 --- a/packages/flutter/test/widgets/spacer_test.dart +++ b/packages/flutter/test/widgets/spacer_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Spacer takes up space.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Spacer takes up space.', (WidgetTester tester) async { await tester.pumpWidget(const Column( children: <Widget>[ SizedBox(width: 10.0, height: 10.0), @@ -19,7 +20,7 @@ void main() { expect(spacerRect.topLeft, const Offset(400.0, 10.0)); }); - testWidgets('Spacer takes up space proportional to flex.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Spacer takes up space proportional to flex.', (WidgetTester tester) async { const Spacer spacer1 = Spacer(); const Spacer spacer2 = Spacer(); const Spacer spacer3 = Spacer(flex: 2); @@ -53,7 +54,7 @@ void main() { expect(spacer4Rect.left, moreOrLessEquals(10.0, epsilon: 0.1)); }); - testWidgets('Spacer takes up space.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Spacer takes up space.', (WidgetTester tester) async { await tester.pumpWidget(const UnconstrainedBox( constrainedAxis: Axis.vertical, child: Column( diff --git a/packages/flutter/test/widgets/spell_check_test.dart b/packages/flutter/test/widgets/spell_check_test.dart index f9b89dcde36b8..131f5e9b044e5 100644 --- a/packages/flutter/test/widgets/spell_check_test.dart +++ b/packages/flutter/test/widgets/spell_check_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; late TextStyle composingStyle; late TextStyle misspelledTextStyle; @@ -17,7 +18,7 @@ void main() { misspelledTextStyle = TextField.materialMisspelledTextStyle; }); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions ignores composing region when composing region out of range', (WidgetTester tester) async { const String text = 'Hello, wrold! Hey'; @@ -46,7 +47,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions, isolated misspelled word with separate composing region example', (WidgetTester tester) async { const String text = 'Hello, wrold! Hey'; @@ -77,7 +78,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions, composing region and misspelled words overlap example', (WidgetTester tester) async { const String text = 'Right worng worng right'; @@ -111,7 +112,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions, consecutive misspelled words example', (WidgetTester tester) async { const String text = 'Right worng worng right'; @@ -144,7 +145,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions corrects results when they lag, results text shorter than actual text example', (WidgetTester tester) async { const String text = 'Hello, wrold! Hey'; @@ -174,7 +175,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions corrects results when they lag, results text longer with more misspelled words than actual text example', (WidgetTester tester) async { const String text = 'Hello, wrold! Hey'; @@ -206,7 +207,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions corrects results when they lag, results text mismatched example', (WidgetTester tester) async { const String text = 'Hello, wrold! Hey'; @@ -233,7 +234,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions corrects results when they lag, results shifted forward example', (WidgetTester tester) async { const String text = 'Hello, there wrold! Hey'; @@ -263,7 +264,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions corrects results when they lag, results shifted backwards example', (WidgetTester tester) async { const String text = 'Hello, wrold! Hey'; @@ -293,7 +294,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions corrects results when they lag, results shifted backwards and forwards example', (WidgetTester tester) async { const String text = 'Hello, wrold! And Hye!'; @@ -326,7 +327,7 @@ void main() { expect(textSpanTree, equals(expectedTextSpanTree)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS })); - testWidgets( + testWidgetsWithLeakTracking( 'buildTextSpanWithSpellCheckSuggestions discards result when additions are made to misspelled word example', (WidgetTester tester) async { const String text = 'Hello, wroldd!'; diff --git a/packages/flutter/test/widgets/stack_test.dart b/packages/flutter/test/widgets/stack_test.dart index cd3174f5037ef..039b8c2567985 100644 --- a/packages/flutter/test/widgets/stack_test.dart +++ b/packages/flutter/test/widgets/stack_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestCallbackPainter; @@ -18,7 +19,7 @@ class TestPaintingContext implements PaintingContext { } void main() { - testWidgets('Can construct an empty Stack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can construct an empty Stack', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -27,7 +28,7 @@ void main() { ); }); - testWidgets('Can construct an empty Centered Stack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can construct an empty Centered Stack', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -36,7 +37,7 @@ void main() { ); }); - testWidgets('Can change position data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can change position data', (WidgetTester tester) async { const Key key = Key('container'); await tester.pumpWidget( @@ -93,7 +94,7 @@ void main() { expect(parentData.height, isNull); }); - testWidgets('Can remove parent data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can remove parent data', (WidgetTester tester) async { const Key key = Key('container'); const SizedBox sizedBox = SizedBox(key: key, width: 10.0, height: 10.0); @@ -131,7 +132,7 @@ void main() { expect(parentData.height, isNull); }); - testWidgets('Can align non-positioned children (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can align non-positioned children (LTR)', (WidgetTester tester) async { const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -177,7 +178,7 @@ void main() { expect(child1RenderObjectParentData.offset, equals(const Offset(10.0, 10.0))); }); - testWidgets('Can align non-positioned children (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can align non-positioned children (RTL)', (WidgetTester tester) async { const Key child0Key = Key('child0'); const Key child1Key = Key('child1'); @@ -223,7 +224,7 @@ void main() { expect(child1RenderObjectParentData.offset, equals(const Offset(0.0, 10.0))); }); - testWidgets('Can construct an empty IndexedStack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can construct an empty IndexedStack', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -232,7 +233,7 @@ void main() { ); }); - testWidgets('Can construct an empty Centered IndexedStack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can construct an empty Centered IndexedStack', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -241,7 +242,7 @@ void main() { ); }); - testWidgets('Can construct an IndexedStack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can construct an IndexedStack', (WidgetTester tester) async { const int itemCount = 3; late List<int> itemsPainted; @@ -289,7 +290,7 @@ void main() { expect(itemsPainted, equals(<int>[2])); }); - testWidgets('Can hit test an IndexedStack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can hit test an IndexedStack', (WidgetTester tester) async { const Key key = Key('indexedStack'); const int itemCount = 3; late List<int> itemsTapped; @@ -320,7 +321,7 @@ void main() { expect(itemsTapped, <int>[2]); }); - testWidgets('IndexedStack sets non-selected indexes to visible=false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IndexedStack sets non-selected indexes to visible=false', (WidgetTester tester) async { Widget buildStack({required int itemCount, required int? selectedIndex}) { final List<Widget> children = List<Widget>.generate(itemCount, (int i) { return _ShowVisibility(index: i); @@ -355,7 +356,7 @@ void main() { expect(find.text('index 2 is visible ? true', skipOffstage: false), findsOneWidget); }); - testWidgets('Can set width and height', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set width and height', (WidgetTester tester) async { const Key key = Key('container'); const BoxDecoration kBoxDecoration = BoxDecoration( @@ -423,7 +424,7 @@ void main() { expect(renderBox.size.height, equals(12.0)); }); - testWidgets('Can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(const Stack(textDirection: TextDirection.ltr)); final RenderStack renderObject = tester.allRenderObjects.whereType<RenderStack>().first; expect(renderObject.clipBehavior, equals(Clip.hardEdge)); @@ -432,7 +433,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.hardEdge)); }); - testWidgets('Clip.none is respected by describeApproximateClip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Clip.none is respected by describeApproximateClip', (WidgetTester tester) async { await tester.pumpWidget(const Stack( textDirection: TextDirection.ltr, children: <Widget>[Positioned(left: 1000, right: 2000, child: SizedBox(width: 2000, height: 2000))], @@ -455,7 +456,7 @@ void main() { expect(visited, true); }); - testWidgets('IndexedStack with null index', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IndexedStack with null index', (WidgetTester tester) async { bool? tapped; await tester.pumpWidget( @@ -485,7 +486,7 @@ void main() { expect(tapped, isNull); }); - testWidgets('IndexedStack reports hidden children as offstage', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IndexedStack reports hidden children as offstage', (WidgetTester tester) async { final List<Widget> children = <Widget>[ for (int i = 0; i < 5; i++) Text('child $i'), ]; @@ -519,7 +520,7 @@ void main() { } }); - testWidgets('Stack clip test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stack clip test', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -580,7 +581,7 @@ void main() { expect(context.invocations.first.memberName, equals(#paintChild)); }); - testWidgets('Stack sizing: default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stack sizing: default', (WidgetTester tester) async { final List<String> logs = <String>[]; await tester.pumpWidget( Directionality( @@ -610,7 +611,7 @@ void main() { expect(logs, <String>['BoxConstraints(0.0<=w<=3.0, 0.0<=h<=7.0)']); }); - testWidgets('Stack sizing: explicit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stack sizing: explicit', (WidgetTester tester) async { final List<String> logs = <String>[]; Widget buildStack(StackFit sizing) { return Directionality( @@ -652,7 +653,7 @@ void main() { ]); }); - testWidgets('Positioned.directional control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Positioned.directional control test', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Directionality( @@ -689,7 +690,7 @@ void main() { expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0)); }); - testWidgets('PositionedDirectional control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PositionedDirectional control test', (WidgetTester tester) async { final Key key = UniqueKey(); await tester.pumpWidget( Directionality( @@ -724,7 +725,7 @@ void main() { expect(tester.getTopLeft(find.byKey(key)), const Offset(50.0, 0.0)); }); - testWidgets('Can change the text direction of a Stack', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can change the text direction of a Stack', (WidgetTester tester) async { await tester.pumpWidget( const Stack( alignment: Alignment.center, @@ -742,7 +743,7 @@ void main() { ); }); - testWidgets('Alignment with partially-positioned children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Alignment with partially-positioned children', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.rtl, @@ -887,7 +888,7 @@ void main() { )); }); - testWidgets('Can update clipBehavior of IndexedStack', + testWidgetsWithLeakTracking('Can update clipBehavior of IndexedStack', (WidgetTester tester) async { await tester.pumpWidget(const IndexedStack(textDirection: TextDirection.ltr)); final RenderIndexedStack renderObject = @@ -905,7 +906,7 @@ void main() { expect(renderIndexedObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('IndexedStack sizing: explicit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IndexedStack sizing: explicit', (WidgetTester tester) async { final List<String> logs = <String>[]; Widget buildIndexedStack(StackFit sizing) { return Directionality( diff --git a/packages/flutter/test/widgets/state_setting_in_scrollables_test.dart b/packages/flutter/test/widgets/state_setting_in_scrollables_test.dart index 0f1ca8c15a535..c9ddff09179a1 100644 --- a/packages/flutter/test/widgets/state_setting_in_scrollables_test.dart +++ b/packages/flutter/test/widgets/state_setting_in_scrollables_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class Foo extends StatefulWidget { const Foo({ super.key }); @@ -12,7 +13,13 @@ class Foo extends StatefulWidget { } class FooState extends State<Foo> { - ScrollController scrollController = ScrollController(); + final ScrollController scrollController = ScrollController(); + + @override + void dispose() { + scrollController.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { @@ -81,7 +88,7 @@ class FooScrollBehavior extends ScrollBehavior { } void main() { - testWidgets('Can animate scroll after setState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can animate scroll after setState', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/stateful_component_test.dart b/packages/flutter/test/widgets/stateful_component_test.dart index 078e30f0cd6fd..3db736a133195 100644 --- a/packages/flutter/test/widgets/stateful_component_test.dart +++ b/packages/flutter/test/widgets/stateful_component_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'test_widgets.dart'; void main() { - testWidgets('Stateful widget smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stateful widget smoke test', (WidgetTester tester) async { void checkTree(BoxDecoration expectedDecoration) { final SingleChildRenderObjectElement element = tester.element( find.byElementPredicate((Element element) => element is SingleChildRenderObjectElement && element.renderObject is! RenderView), @@ -54,7 +55,7 @@ void main() { checkTree(kBoxDecorationB); }); - testWidgets("Don't rebuild subwidgets", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Don't rebuild subwidgets", (WidgetTester tester) async { await tester.pumpWidget( const FlipWidget( key: Key('rebuild test'), diff --git a/packages/flutter/test/widgets/stateful_components_test.dart b/packages/flutter/test/widgets/stateful_components_test.dart index 13f5a6ac7fd61..168d7424a8d59 100644 --- a/packages/flutter/test/widgets/stateful_components_test.dart +++ b/packages/flutter/test/widgets/stateful_components_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class InnerWidget extends StatefulWidget { const InnerWidget({ super.key }); @@ -44,7 +45,7 @@ class OuterContainerState extends State<OuterContainer> { } void main() { - testWidgets('resync stateful widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('resync stateful widget', (WidgetTester tester) async { const Key innerKey = Key('inner'); const Key outerKey = Key('outer'); diff --git a/packages/flutter/test/widgets/status_transitions_test.dart b/packages/flutter/test/widgets/status_transitions_test.dart index 42b91b1e938a4..0667398c26ca8 100644 --- a/packages/flutter/test/widgets/status_transitions_test.dart +++ b/packages/flutter/test/widgets/status_transitions_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestStatusTransitionWidget extends StatusTransitionWidget { const TestStatusTransitionWidget({ @@ -19,12 +20,13 @@ class TestStatusTransitionWidget extends StatusTransitionWidget { } void main() { - testWidgets('Status transition control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Status transition control test', (WidgetTester tester) async { bool didBuild = false; final AnimationController controller = AnimationController( duration: const Duration(seconds: 1), vsync: const TestVSync(), ); + addTearDown(controller.dispose); await tester.pumpWidget(TestStatusTransitionWidget( animation: controller, diff --git a/packages/flutter/test/widgets/syncing_test.dart b/packages/flutter/test/widgets/syncing_test.dart index 84745ca07cd30..ff514d6ae3168 100644 --- a/packages/flutter/test/widgets/syncing_test.dart +++ b/packages/flutter/test/widgets/syncing_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestWidget extends StatefulWidget { const TestWidget({ @@ -48,7 +49,7 @@ class TestWidgetState extends State<TestWidget> { void main() { - testWidgets('no change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no change', (WidgetTester tester) async { await tester.pumpWidget( ColoredBox( color: Colors.blue, @@ -88,7 +89,7 @@ void main() { await tester.pumpWidget(Container()); }); - testWidgets('remove one', (WidgetTester tester) async { + testWidgetsWithLeakTracking('remove one', (WidgetTester tester) async { await tester.pumpWidget( ColoredBox( color: Colors.blue, @@ -127,7 +128,7 @@ void main() { await tester.pumpWidget(Container()); }); - testWidgets('swap instances around', (WidgetTester tester) async { + testWidgetsWithLeakTracking('swap instances around', (WidgetTester tester) async { const Widget a = TestWidget(persistentState: 0x61, syncedState: 0x41, child: Text('apple', textDirection: TextDirection.ltr)); const Widget b = TestWidget(persistentState: 0x62, syncedState: 0x42, child: Text('banana', textDirection: TextDirection.ltr)); await tester.pumpWidget(const Column()); diff --git a/packages/flutter/test/widgets/table_test.dart b/packages/flutter/test/widgets/table_test.dart index 727fd1040d621..b5531277d3ee8 100644 --- a/packages/flutter/test/widgets/table_test.dart +++ b/packages/flutter/test/widgets/table_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestStatefulWidget extends StatefulWidget { const TestStatefulWidget({ super.key }); @@ -37,7 +38,7 @@ class TestChildState extends State<TestChildWidget> { } void main() { - testWidgets('Table widget - empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - empty', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -46,7 +47,7 @@ void main() { ); }); - testWidgets('Table widget - control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - control test', (WidgetTester tester) async { Future<void> run(TextDirection textDirection) async { await tester.pumpWidget( Directionality( @@ -86,7 +87,7 @@ void main() { await run(TextDirection.rtl); }); - testWidgets('Table widget can be detached and re-attached', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget can be detached and re-attached', (WidgetTester tester) async { final Widget table = Table( key: GlobalKey(), children: const <TableRow>[ @@ -121,7 +122,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Table widget - column offset (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - column offset (LTR)', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -191,7 +192,7 @@ void main() { expect(c3.left, equals(c1.left)); }); - testWidgets('Table widget - column offset (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - column offset (RTL)', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -261,7 +262,7 @@ void main() { expect(c3.right, equals(c1.right)); }); - testWidgets('Table border - smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table border - smoke test', (WidgetTester tester) async { Future<void> run(TextDirection textDirection) async { await tester.pumpWidget( Directionality( @@ -295,7 +296,7 @@ void main() { await run(TextDirection.rtl); }); - testWidgets('Table widget - changing table dimensions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - changing table dimensions', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -351,7 +352,7 @@ void main() { expect(boxG1, isNot(equals(boxG2))); }); - testWidgets('Really small deficit double precision error', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Really small deficit double precision error', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/27083 const SizedBox cell = SizedBox(width: 16, height: 16); await tester.pumpWidget( @@ -376,7 +377,7 @@ void main() { // If the above bug is present this test will never terminate. }); - testWidgets('Calculating flex columns with small width deficit', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Calculating flex columns with small width deficit', (WidgetTester tester) async { const SizedBox cell = SizedBox(width: 1, height: 1); // If the error is present, pumpWidget() will fail due to an unsatisfied // assertion during the layout phase. @@ -406,7 +407,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('Table widget - repump test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - repump test', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -464,7 +465,7 @@ void main() { expect(boxA.size, equals(boxB.size)); }); - testWidgets('Table widget - intrinsic sizing test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - intrinsic sizing test', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -500,7 +501,7 @@ void main() { expect(boxA.size.height, equals(boxB.size.height)); }); - testWidgets('Table widget - intrinsic sizing test, resizing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - intrinsic sizing test, resizing', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -561,7 +562,7 @@ void main() { expect(boxA.size.height, equals(boxB.size.height)); }); - testWidgets('Table widget - intrinsic sizing test, changing column widths', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - intrinsic sizing test, changing column widths', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -621,7 +622,7 @@ void main() { expect(boxA.size.height, equals(boxB.size.height)); }); - testWidgets('Table widget - moving test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - moving test', (WidgetTester tester) async { final List<BuildContext> contexts = <BuildContext>[]; await tester.pumpWidget( Directionality( @@ -677,7 +678,7 @@ void main() { expect(contexts[0], equals(contexts[1])); }); - testWidgets('Table widget - keyed rows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - keyed rows', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -735,7 +736,7 @@ void main() { expect(state22.mounted, isTrue); }); - testWidgets('Table widget - global key reparenting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - global key reparenting', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final Key tableKey = UniqueKey(); @@ -848,7 +849,7 @@ void main() { expect(table.row(0).length, 2); }); - testWidgets('Table widget diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget diagnostics', (WidgetTester tester) async { GlobalKey key0; final Widget table = Directionality( textDirection: TextDirection.ltr, @@ -904,7 +905,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/31473. - testWidgets( + testWidgetsWithLeakTracking( 'Does not crash if a child RenderObject is replaced by another RenderObject of a different type', (WidgetTester tester) async { await tester.pumpWidget( @@ -930,7 +931,7 @@ void main() { }, ); - testWidgets('Table widget - Default textBaseline is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Table widget - Default textBaseline is null', (WidgetTester tester) async { expect( () => Table(defaultVerticalAlignment: TableCellVerticalAlignment.baseline), throwsA( @@ -940,7 +941,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'Table widget requires all TableRows to have same number of children', (WidgetTester tester) async { FlutterError? error; @@ -965,7 +966,7 @@ void main() { }, ); - testWidgets('Can replace child with a different RenderObject type', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can replace child with a different RenderObject type', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/69395. await tester.pumpWidget( Directionality( @@ -1001,7 +1002,7 @@ void main() { expect(table.column(2).last.runtimeType, isNot(toBeReplaced)); }); - testWidgets('Do not crash if a child that has not been layed out in a previous build is removed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash if a child that has not been layed out in a previous build is removed', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/60488. Widget buildTable(Key key) { return Directionality( @@ -1034,7 +1035,7 @@ void main() { expect(find.text('Hello'), findsOneWidget); }); - testWidgets('TableRow with no children throws an error message', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TableRow with no children throws an error message', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/119541. String result = 'no exception'; diff --git a/packages/flutter/test/widgets/tap_region_test.dart b/packages/flutter/test/widgets/tap_region_test.dart index 56625c666c6a3..a244518417d1f 100644 --- a/packages/flutter/test/widgets/tap_region_test.dart +++ b/packages/flutter/test/widgets/tap_region_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('TapRegionSurface detects outside taps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TapRegionSurface detects outside taps', (WidgetTester tester) async { final Set<String> tappedOutside = <String>{}; await tester.pumpWidget( Directionality( @@ -101,7 +102,7 @@ void main() { expect(tappedOutside, isEmpty); }); - testWidgets('TapRegionSurface detects inside taps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TapRegionSurface detects inside taps', (WidgetTester tester) async { final Set<String> tappedInside = <String>{}; await tester.pumpWidget( Directionality( @@ -188,7 +189,7 @@ void main() { expect(tappedInside, isEmpty); }); - testWidgets('TapRegionSurface detects inside taps correctly with behavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TapRegionSurface detects inside taps correctly with behavior', (WidgetTester tester) async { final Set<String> tappedInside = <String>{}; const ValueKey<String> noGroupKey = ValueKey<String>('No Group'); const ValueKey<String> group1AKey = ValueKey<String>('Group 1 A'); @@ -275,7 +276,7 @@ void main() { tappedInside.clear(); }); - testWidgets('Setting the group updates the registration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting the group updates the registration', (WidgetTester tester) async { final Set<String> tappedOutside = <String>{}; await tester.pumpWidget( Directionality( diff --git a/packages/flutter/test/widgets/text_golden_test.dart b/packages/flutter/test/widgets/text_golden_test.dart index 4267da2d79a18..35a2afc0a2fba 100644 --- a/packages/flutter/test/widgets/text_golden_test.dart +++ b/packages/flutter/test/widgets/text_golden_test.dart @@ -10,9 +10,10 @@ library; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Centered text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Centered text', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -63,7 +64,7 @@ void main() { }); - testWidgets('Text Foreground', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Foreground', (WidgetTester tester) async { const Color black = Color(0xFF000000); const Color red = Color(0xFFFF0000); const Color blue = Color(0xFF0000FF); @@ -141,7 +142,7 @@ void main() { // TODO(garyq): This test requires an update when the background // drawing from the beginning of the line bug is fixed. The current // tested version is not completely correct. - testWidgets('Text Background', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Background', (WidgetTester tester) async { const Color red = Colors.red; const Color blue = Colors.blue; const Color translucentGreen = Color(0x5000F000); @@ -188,7 +189,7 @@ void main() { ); }); - testWidgets('Text Fade', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Fade', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -225,7 +226,7 @@ void main() { ); }); - testWidgets('Default Strut text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default Strut text', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -250,7 +251,7 @@ void main() { ); }); - testWidgets('Strut text 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Strut text 1', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -277,7 +278,7 @@ void main() { ); }); - testWidgets('Strut text 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Strut text 2', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -305,7 +306,7 @@ void main() { ); }); - testWidgets('Strut text rich', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Strut text rich', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -356,7 +357,7 @@ void main() { ); }); - testWidgets('Strut text font fallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Strut text font fallback', (WidgetTester tester) async { // Font Fallback await tester.pumpWidget( Center( @@ -391,7 +392,7 @@ void main() { ); }); - testWidgets('Strut text rich forceStrutHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Strut text rich forceStrutHeight', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( @@ -442,7 +443,7 @@ void main() { ); }); - testWidgets('Decoration thickness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Decoration thickness', (WidgetTester tester) async { final TextDecoration allDecorations = TextDecoration.combine( <TextDecoration>[ TextDecoration.underline, @@ -480,7 +481,7 @@ void main() { ); }); - testWidgets('Decoration thickness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Decoration thickness', (WidgetTester tester) async { final TextDecoration allDecorations = TextDecoration.combine( <TextDecoration>[ TextDecoration.underline, @@ -519,7 +520,7 @@ void main() { ); }); - testWidgets('Text Inline widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget', (WidgetTester tester) async { await tester.pumpWidget( Theme(data: ThemeData(useMaterial3: false), child: Center( child: RepaintBoundary( @@ -613,7 +614,7 @@ void main() { ); }); - testWidgets('Text Inline widget textfield', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget textfield', (WidgetTester tester) async { await tester.pumpWidget( Center( child: MaterialApp( @@ -660,7 +661,7 @@ void main() { }); // This tests if multiple Text.rich widgets are able to inline nest within each other. - testWidgets('Text Inline widget nesting', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget nesting', (WidgetTester tester) async { await tester.pumpWidget( Center( child: MaterialApp( @@ -789,7 +790,7 @@ void main() { ); }); - testWidgets('Text Inline widget baseline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget baseline', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -899,7 +900,7 @@ void main() { ); }); - testWidgets('Text Inline widget aboveBaseline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget aboveBaseline', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -1009,7 +1010,7 @@ void main() { ); }); - testWidgets('Text Inline widget belowBaseline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget belowBaseline', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -1119,7 +1120,7 @@ void main() { ); }); - testWidgets('Text Inline widget top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget top', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -1229,7 +1230,7 @@ void main() { ); }); - testWidgets('Text Inline widget middle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text Inline widget middle', (WidgetTester tester) async { await tester.pumpWidget( Theme( data: ThemeData(useMaterial3: false), @@ -1339,7 +1340,7 @@ void main() { ); }); - testWidgets('Text TextHeightBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text TextHeightBehavior', (WidgetTester tester) async { await tester.pumpWidget( Center( child: RepaintBoundary( diff --git a/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart b/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart index c38c3f617fd38..724fcbdb7f2c4 100644 --- a/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart +++ b/packages/flutter/test/widgets/text_scaler_backward_compatibility_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('TextStyle', () { @@ -64,7 +65,7 @@ void main() { ); }); - testWidgets('MediaQuery.textScaleFactorOf overriding compatibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MediaQuery.textScaleFactorOf overriding compatibility', (WidgetTester tester) async { late final double outsideTextScaleFactor; late final TextScaler outsideTextScaler; late final double insideTextScaleFactor; @@ -103,7 +104,7 @@ void main() { expect(insideTextScaler, const TextScaler.linear(4.0)); }); - testWidgets('textScaleFactor overriding backward compatibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textScaleFactor overriding backward compatibility', (WidgetTester tester) async { late final double outsideTextScaleFactor; late final TextScaler outsideTextScaler; late final double insideTextScaleFactor; @@ -183,7 +184,7 @@ void main() { }); group('Widgets backward compatibility', () { - testWidgets('RichText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RichText', (WidgetTester tester) async { await tester.pumpWidget( RichText( textDirection: TextDirection.ltr, @@ -199,7 +200,7 @@ void main() { expect(tester.renderObject<RenderParagraph>(find.byType(RichText)).textScaleFactor, 2.0); }); - testWidgets('Text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text', (WidgetTester tester) async { await tester.pumpWidget( const Text( 'text', @@ -214,9 +215,11 @@ void main() { ); }); - testWidgets('EditableText', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EditableText', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Node'); + addTearDown(focusNode.dispose); const TextStyle textStyle = TextStyle(); const Color cursorColor = Color.fromARGB(0xFF, 0xFF, 0x00, 0x00); await tester.pumpWidget( From b0a90aee17e9554d50f19983948b8e802a8a067e Mon Sep 17 00:00:00 2001 From: Michael Goderbauer <goderbauer@google.com> Date: Wed, 20 Sep 2023 12:59:08 -0700 Subject: [PATCH 1370/1547] Enable strict-inference (#135043) Avoids that dynamic accidentally sneaks in, see https://dart.dev/tools/analysis#enabling-additional-type-checks --- analysis_options.yaml | 1 + .../analyze-snippet-code-test-dart-ui/ui.dart | 2 +- .../custom_imports_broken.dart | 2 +- .../known_broken_documentation.dart | 7 ++++--- dev/bots/test/analyze_snippet_code_test.dart | 15 +++++++++------ .../core/test/packages_autoroller_test.dart | 6 +++--- .../tasks/flutter_engine_group_performance.dart | 2 +- dev/devicelab/lib/framework/runner.dart | 2 +- .../ios_platform_view_tests/lib/main.dart | 2 +- .../bottom_navigation_bar.2.dart | 2 +- .../material/navigation_bar/navigation_bar.2.dart | 8 ++++---- .../api/lib/widgets/scroll_view/list_view.0.dart | 4 ++-- .../flutter/lib/src/cupertino/toggleable.dart | 2 +- .../flutter/lib/src/material/bottom_sheet.dart | 2 +- packages/flutter/lib/src/material/switch.dart | 2 +- packages/flutter/lib/src/material/toggleable.dart | 2 +- packages/flutter/lib/src/widgets/navigator.dart | 4 ++-- .../flutter/test/material/popup_menu_test.dart | 2 +- packages/flutter/test/painting/colors_test.dart | 2 +- .../flutter/test/rendering/proxy_box_test.dart | 12 +++++++----- .../flutter/test/widgets/media_query_test.dart | 2 +- .../widgets/sliver_cross_axis_group_test.dart | 7 ++++--- packages/flutter_test/lib/src/_binding_io.dart | 2 +- .../test/utils/fake_and_mock_utils.dart | 6 +++--- .../test/general.shard/ios/ios_deploy_test.dart | 14 +++++++------- .../debug_adapter/test_server.dart | 4 ++-- .../flutter_tools/test/src/fake_http_client.dart | 2 +- 27 files changed, 63 insertions(+), 55 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 4da1e9f1fb3a8..6bf95b55f404d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -17,6 +17,7 @@ analyzer: language: strict-casts: true + strict-inference: true strict-raw-types: true errors: # allow self-reference to deprecated members (we do this because otherwise we have diff --git a/dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart b/dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart index 85c41d9deb375..30458dd8871a7 100644 --- a/dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart +++ b/dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart @@ -11,7 +11,7 @@ library dart.ui; /// /// ```dart /// class MyStringBuffer { -/// error; // error (missing_const_final_var_or_type, always_specify_types) +/// error; // error (prefer_typing_uninitialized_variables, inference_failure_on_uninitialized_variable, missing_const_final_var_or_type) /// /// StringBuffer _buffer = StringBuffer(); // error (prefer_final_fields, unused_field) /// } diff --git a/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart b/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart index cdf466efe2631..46dc91139bff2 100644 --- a/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart +++ b/dev/bots/test/analyze-snippet-code-test-input/custom_imports_broken.dart @@ -16,6 +16,6 @@ String? bar; /// error: widgets library was not imported (not even implicitly). /// ```dart -/// print(Widget); +/// print(Widget); // error (undefined_identifier) /// ``` String? foo; diff --git a/dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart b/dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart index a822e88ec0a30..2704029efcb5f 100644 --- a/dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart +++ b/dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart @@ -131,7 +131,7 @@ /// Widget build(BuildContext context) { /// final String title; /// return Opacity( -/// key: globalKey, // error (undefined_identifier, argument_type_not_assignable) +/// key: globalKey, // error (undefined_identifier) /// opacity: _visible ? 1.0 : 0.0, /// child: Text(title), // error (read_potentially_unassigned_final) /// ); @@ -144,13 +144,14 @@ /// ``` /// /// ```dart -/// import 'dart:io'; // error (unused_import)/// final Widget p = Placeholder(); // error (undefined_class, undefined_function) +/// import 'dart:io'; // error (unused_import) +/// final Widget p = Placeholder(); // error (undefined_class, undefined_function) /// ``` /// /// ```dart /// // (e.g. in a stateful widget) /// void initState() { // error (must_call_super, annotate_overrides) -/// widget.toString(); // error (undefined_identifier, return_of_invalid_type) +/// widget.toString(); /// } /// ``` /// diff --git a/dev/bots/test/analyze_snippet_code_test.dart b/dev/bots/test/analyze_snippet_code_test.dart index 90b6366cb93ab..45ff34d405e2b 100644 --- a/dev/bots/test/analyze_snippet_code_test.dart +++ b/dev/bots/test/analyze_snippet_code_test.dart @@ -21,16 +21,19 @@ const List<String> expectedMainErrors = <String>[ 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:134:14: (top-level declaration) (undefined_identifier)', 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:136:21: (top-level declaration) (read_potentially_unassigned_final)', 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:147:12: (self-contained program) (unused_import)', - 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:152:10: (stateful widget) (annotate_overrides)', - 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:152:10: (stateful widget) (must_call_super)', - 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:160:7: (top-level declaration) (undefined_identifier)', - 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:164: Found "```" in code but it did not match RegExp: pattern=^ */// *```dart\$ flags= so something is wrong. Line was: "/// ```"', + 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:148:11: (self-contained program) (undefined_class)', + 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:148:22: (self-contained program) (undefined_function)', + 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:153:10: (stateful widget) (annotate_overrides)', + 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:153:10: (stateful widget) (must_call_super)', + 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:161:7: (top-level declaration) (undefined_identifier)', + 'dev/bots/test/analyze-snippet-code-test-input/known_broken_documentation.dart:165: Found "```" in code but it did not match RegExp: pattern=^ */// *```dart\$ flags= so something is wrong. Line was: "/// ```"', 'dev/bots/test/analyze-snippet-code-test-input/short_but_still_broken.dart:9:12: (statement) (invalid_assignment)', 'dev/bots/test/analyze-snippet-code-test-input/short_but_still_broken.dart:18:4: Empty ```dart block in snippet code.', ]; const List<String> expectedUiErrors = <String>[ 'dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart:14:7: (top-level declaration) (prefer_typing_uninitialized_variables)', + 'dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart:14:7: (top-level declaration) (inference_failure_on_uninitialized_variable)', 'dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart:14:7: (top-level declaration) (missing_const_final_var_or_type)', 'dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart:16:20: (top-level declaration) (prefer_final_fields)', 'dev/bots/test/analyze-snippet-code-test-dart-ui/ui.dart:16:20: (top-level declaration) (unused_field)', @@ -69,7 +72,7 @@ void main() { final List<String> stderrNoDescriptions = stderrLines.map(removeLintDescriptions).toList(); expect(stderrNoDescriptions, <String>[ ...expectedMainErrors, - 'Found 16 snippet code errors.', + 'Found 18 snippet code errors.', 'See the documentation at the top of dev/bots/analyze_snippet_code.dart for details.', '', // because we end with a newline, split gives us an extra blank line ]); @@ -93,7 +96,7 @@ void main() { expect(stderrNoDescriptions, <String>[ ...expectedUiErrors, ...expectedMainErrors, - 'Found 20 snippet code errors.', + 'Found 23 snippet code errors.', 'See the documentation at the top of dev/bots/analyze_snippet_code.dart for details.', '', // because we end with a newline, split gives us an extra blank line ]); diff --git a/dev/conductor/core/test/packages_autoroller_test.dart b/dev/conductor/core/test/packages_autoroller_test.dart index 3861759b9229b..d320f731a491d 100644 --- a/dev/conductor/core/test/packages_autoroller_test.dart +++ b/dev/conductor/core/test/packages_autoroller_test.dart @@ -170,7 +170,7 @@ void main() { await expectLater( () async { final Future<void> rollFuture = autoroller.roll(); - await controller.stream.drain(); + await controller.stream.drain<Object?>(); await rollFuture; }, throwsA(isA<Exception>().having( @@ -214,7 +214,7 @@ void main() { ], stdout: '[{"number": 123}]'), ]); final Future<void> rollFuture = autoroller.roll(); - await controller.stream.drain(); + await controller.stream.drain<Object?>(); await rollFuture; expect(processManager, hasNoRemainingExpectations); expect(stdio.stdout, contains('flutter-pub-roller-bot already has open tool PRs')); @@ -312,7 +312,7 @@ void main() { ]), ]); final Future<void> rollFuture = autoroller.roll(); - await controller.stream.drain(); + await controller.stream.drain<Object?>(); await rollFuture; expect(processManager, hasNoRemainingExpectations); }); diff --git a/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart b/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart index 995b38918e66c..5ba8eb091b6ac 100644 --- a/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart +++ b/dev/devicelab/bin/tasks/flutter_engine_group_performance.dart @@ -16,7 +16,7 @@ const String _activityName = 'MainActivity'; const int _numberOfIterations = 10; Future<void> _withApkInstall( - String apkPath, String bundleName, Function(AndroidDevice) body) async { + String apkPath, String bundleName, Future<void> Function(AndroidDevice) body) async { final DeviceDiscovery devices = DeviceDiscovery(); final AndroidDevice device = await devices.workingDevice as AndroidDevice; await device.unlock(); diff --git a/dev/devicelab/lib/framework/runner.dart b/dev/devicelab/lib/framework/runner.dart index 39d0015db5e29..3696a9ce86c08 100644 --- a/dev/devicelab/lib/framework/runner.dart +++ b/dev/devicelab/lib/framework/runner.dart @@ -42,7 +42,7 @@ Future<void> runTasks( List<String>? taskArgs, bool useEmulator = false, @visibleForTesting Map<String, String>? isolateParams, - @visibleForTesting Function(String) print = print, + @visibleForTesting void Function(String) print = print, @visibleForTesting List<String>? logs, }) async { for (final String taskName in taskNames) { diff --git a/dev/integration_tests/ios_platform_view_tests/lib/main.dart b/dev/integration_tests/ios_platform_view_tests/lib/main.dart index 661e32d458514..22025f261e863 100644 --- a/dev/integration_tests/ios_platform_view_tests/lib/main.dart +++ b/dev/integration_tests/ios_platform_view_tests/lib/main.dart @@ -201,7 +201,7 @@ class _ZOrderTestPageState extends State<ZOrderTestPage> { )), TextButton( onPressed: () { - showDialog( + showDialog<void>( context: context, builder: (BuildContext context) { return const SizedBox( diff --git a/examples/api/lib/material/bottom_navigation_bar/bottom_navigation_bar.2.dart b/examples/api/lib/material/bottom_navigation_bar/bottom_navigation_bar.2.dart index 560406e34cbd9..49e42910fa5ea 100644 --- a/examples/api/lib/material/bottom_navigation_bar/bottom_navigation_bar.2.dart +++ b/examples/api/lib/material/bottom_navigation_bar/bottom_navigation_bar.2.dart @@ -91,7 +91,7 @@ class _BottomNavigationBarExampleState extends State<BottomNavigationBarExample> } void showModal(BuildContext context) { - showDialog( + showDialog<void>( context: context, builder: (BuildContext context) => AlertDialog( content: const Text('Example Dialog'), diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart index 981eb5d81216a..b0056c37bc916 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.2.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.2.dart @@ -174,7 +174,7 @@ class RootPage extends StatelessWidget { ElevatedButton( style: buttonStyle, onPressed: () { - showDialog( + showDialog<void>( context: context, useRootNavigator: false, builder: _buildDialog, @@ -186,9 +186,9 @@ class RootPage extends StatelessWidget { ElevatedButton( style: buttonStyle, onPressed: () { - showDialog( + showDialog<void>( context: context, - useRootNavigator: true, + useRootNavigator: true, // ignore: avoid_redundant_argument_values builder: _buildDialog, ); }, @@ -200,7 +200,7 @@ class RootPage extends StatelessWidget { return ElevatedButton( style: buttonStyle, onPressed: () { - showBottomSheet( + showBottomSheet<void>( context: context, builder: (BuildContext context) { return Container( diff --git a/examples/api/lib/widgets/scroll_view/list_view.0.dart b/examples/api/lib/widgets/scroll_view/list_view.0.dart index 954995f4b9d00..870420fdfd8f1 100644 --- a/examples/api/lib/widgets/scroll_view/list_view.0.dart +++ b/examples/api/lib/widgets/scroll_view/list_view.0.dart @@ -136,7 +136,7 @@ class GridBuilder extends StatefulWidget { }); final bool isSelectionMode; - final Function(bool)? onSelectionChange; + final ValueChanged<bool>? onSelectionChange; final List<bool> selectedList; @override @@ -189,7 +189,7 @@ class ListBuilder extends StatefulWidget { final bool isSelectionMode; final List<bool> selectedList; - final Function(bool)? onSelectionChange; + final ValueChanged<bool>? onSelectionChange; @override State<ListBuilder> createState() => _ListBuilderState(); diff --git a/packages/flutter/lib/src/cupertino/toggleable.dart b/packages/flutter/lib/src/cupertino/toggleable.dart index dacdab762b50c..a5fb38d9a6d84 100644 --- a/packages/flutter/lib/src/cupertino/toggleable.dart +++ b/packages/flutter/lib/src/cupertino/toggleable.dart @@ -111,7 +111,7 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin /// build method - potentially after wrapping it in other widgets. Widget buildToggleable({ FocusNode? focusNode, - Function(bool)? onFocusChange, + ValueChanged<bool>? onFocusChange, bool autofocus = false, required Size size, required CustomPainter painter, diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart index aea0f76e09f09..75f8b3e7796e2 100644 --- a/packages/flutter/lib/src/material/bottom_sheet.dart +++ b/packages/flutter/lib/src/material/bottom_sheet.dart @@ -440,7 +440,7 @@ class _DragHandle extends StatelessWidget { }); final VoidCallback? onSemanticsTap; - final Function(bool) handleHover; + final ValueChanged<bool> handleHover; final Set<MaterialState> materialState; final Color? dragHandleColor; final Size? dragHandleSize; diff --git a/packages/flutter/lib/src/material/switch.dart b/packages/flutter/lib/src/material/switch.dart index aca371a684aff..975bbb54c820f 100644 --- a/packages/flutter/lib/src/material/switch.dart +++ b/packages/flutter/lib/src/material/switch.dart @@ -710,7 +710,7 @@ class _MaterialSwitch extends StatefulWidget { final MaterialStateProperty<Color?>? overlayColor; final double? splashRadius; final FocusNode? focusNode; - final Function(bool)? onFocusChange; + final ValueChanged<bool>? onFocusChange; final bool autofocus; final Size size; diff --git a/packages/flutter/lib/src/material/toggleable.dart b/packages/flutter/lib/src/material/toggleable.dart index daa9bdb7f3654..ecf19d37e4576 100644 --- a/packages/flutter/lib/src/material/toggleable.dart +++ b/packages/flutter/lib/src/material/toggleable.dart @@ -302,7 +302,7 @@ mixin ToggleableStateMixin<S extends StatefulWidget> on TickerProviderStateMixin /// build method - potentially after wrapping it in other widgets. Widget buildToggleable({ FocusNode? focusNode, - Function(bool)? onFocusChange, + ValueChanged<bool>? onFocusChange, bool autofocus = false, required MaterialStateProperty<MouseCursor> mouseCursor, required Size size, diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index efb0fcf2e1b80..3b78bd7387d7b 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -5470,7 +5470,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res } /// Gets first route entry satisfying the predicate, or null if not found. - _RouteEntry? _firstRouteEntryWhereOrNull<T>(_RouteEntryPredicate test) { + _RouteEntry? _firstRouteEntryWhereOrNull(_RouteEntryPredicate test) { for (final _RouteEntry element in _history) { if (test(element)) { return element; @@ -5480,7 +5480,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res } /// Gets last route entry satisfying the predicate, or null if not found. - _RouteEntry? _lastRouteEntryWhereOrNull<T>(_RouteEntryPredicate test) { + _RouteEntry? _lastRouteEntryWhereOrNull(_RouteEntryPredicate test) { _RouteEntry? result; for (final _RouteEntry element in _history) { if (test(element)) { diff --git a/packages/flutter/test/material/popup_menu_test.dart b/packages/flutter/test/material/popup_menu_test.dart index e2fa281b6387d..5dec66dd1d442 100644 --- a/packages/flutter/test/material/popup_menu_test.dart +++ b/packages/flutter/test/material/popup_menu_test.dart @@ -3352,7 +3352,7 @@ void main() { itemBuilder: (BuildContext context) => <PopupMenuItem<int>>[ PopupMenuItem<int>( onTap: () { - showModalBottomSheet( + showModalBottomSheet<void>( context: context, builder: (BuildContext context) { return const SizedBox( diff --git a/packages/flutter/test/painting/colors_test.dart b/packages/flutter/test/painting/colors_test.dart index cee4ffaa30e88..4671d29db9254 100644 --- a/packages/flutter/test/painting/colors_test.dart +++ b/packages/flutter/test/painting/colors_test.dart @@ -464,7 +464,7 @@ void main() { }); test('ColorSwatch.lerp identical a,b', () { - expect(ColorSwatch.lerp(null, null, 0), null); + expect(ColorSwatch.lerp<Object?>(null, null, 0), null); const ColorSwatch<int> color = ColorSwatch<int>(0x00000000, <int, Color>{1: Color(0x00000000)}); expect(identical(ColorSwatch.lerp(color, color, 0.5), color), true); }); diff --git a/packages/flutter/test/rendering/proxy_box_test.dart b/packages/flutter/test/rendering/proxy_box_test.dart index 45b34a1235e71..4dfa6c2b9ba4f 100644 --- a/packages/flutter/test/rendering/proxy_box_test.dart +++ b/packages/flutter/test/rendering/proxy_box_test.dart @@ -881,7 +881,7 @@ void main() { }); // Simulate painting a RenderBox as if 'debugPaintSizeEnabled == true' - Function(PaintingContext, Offset) debugPaint(RenderBox renderBox) { + DebugPaintCallback debugPaint(RenderBox renderBox) { layout(renderBox); pumpFrame(phase: EnginePhase.compositingBits); return (PaintingContext context, Offset offset) { @@ -891,7 +891,7 @@ void main() { } test('RenderClipPath.debugPaintSize draws a path and a debug text when clipBehavior is not Clip.none', () { - Function(PaintingContext, Offset) debugPaintClipRect(Clip clip) { + DebugPaintCallback debugPaintClipRect(Clip clip) { final RenderBox child = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 200, height: 200)); final RenderClipPath renderClipPath = RenderClipPath(clipBehavior: clip, child: child); return debugPaint(renderClipPath); @@ -908,7 +908,7 @@ void main() { }); test('RenderClipRect.debugPaintSize draws a rect and a debug text when clipBehavior is not Clip.none', () { - Function(PaintingContext, Offset) debugPaintClipRect(Clip clip) { + DebugPaintCallback debugPaintClipRect(Clip clip) { final RenderBox child = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 200, height: 200)); final RenderClipRect renderClipRect = RenderClipRect(clipBehavior: clip, child: child); return debugPaint(renderClipRect); @@ -924,7 +924,7 @@ void main() { }); test('RenderClipRRect.debugPaintSize draws a rounded rect and a debug text when clipBehavior is not Clip.none', () { - Function(PaintingContext, Offset) debugPaintClipRRect(Clip clip) { + DebugPaintCallback debugPaintClipRRect(Clip clip) { final RenderBox child = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 200, height: 200)); final RenderClipRRect renderClipRRect = RenderClipRRect(clipBehavior: clip, child: child); return debugPaint(renderClipRRect); @@ -940,7 +940,7 @@ void main() { }); test('RenderClipOval.debugPaintSize draws a path and a debug text when clipBehavior is not Clip.none', () { - Function(PaintingContext, Offset) debugPaintClipOval(Clip clip) { + DebugPaintCallback debugPaintClipOval(Clip clip) { final RenderBox child = RenderConstrainedBox(additionalConstraints: const BoxConstraints.tightFor(width: 200, height: 200)); final RenderClipOval renderClipOval = RenderClipOval(clipBehavior: clip, child: child); return debugPaint(renderClipOval); @@ -1085,3 +1085,5 @@ void expectAssertionError() { FlutterError.reportError(errorDetails); } } + +typedef DebugPaintCallback = void Function(PaintingContext context, Offset offset); diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index 35b0ba95e0605..f2608a214057b 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -11,7 +11,7 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _MediaQueryAspectCase { const _MediaQueryAspectCase(this.method, this.data); - final Function(BuildContext) method; + final void Function(BuildContext) method; final MediaQueryData data; } diff --git a/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart b/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart index 8755d358e8ea4..139077213f317 100644 --- a/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_cross_axis_group_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -327,7 +328,7 @@ void main() { testWidgets('Assertion error when SliverExpanded is used outside of SliverCrossAxisGroup', (WidgetTester tester) async { final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; - final Function(FlutterErrorDetails)? oldHandler = FlutterError.onError; + final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); await tester.pumpWidget( @@ -459,7 +460,7 @@ void main() { testWidgetsWithLeakTracking('Assertion error when constrained widget runs out of cross axis extent', (WidgetTester tester) async { final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; - final Function(FlutterErrorDetails)? oldHandler = FlutterError.onError; + final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); final List<int> items = List<int>.generate(20, (int i) => i); @@ -481,7 +482,7 @@ void main() { testWidgetsWithLeakTracking('Assertion error when expanded widget runs out of cross axis extent', (WidgetTester tester) async { final List<FlutterErrorDetails> errors = <FlutterErrorDetails>[]; - final Function(FlutterErrorDetails)? oldHandler = FlutterError.onError; + final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails error) => errors.add(error); final List<int> items = List<int>.generate(20, (int i) => i); diff --git a/packages/flutter_test/lib/src/_binding_io.dart b/packages/flutter_test/lib/src/_binding_io.dart index 2123956cef468..a789b9aabe97c 100644 --- a/packages/flutter_test/lib/src/_binding_io.dart +++ b/packages/flutter_test/lib/src/_binding_io.dart @@ -128,7 +128,7 @@ class _MockHttpClient implements HttpClient { bool Function(X509Certificate cert, String host, int port)? badCertificateCallback; @override - Function(String line)? keyLog; + void Function(String line)? keyLog; @override void close({ bool force = false }) { } diff --git a/packages/flutter_test/test/utils/fake_and_mock_utils.dart b/packages/flutter_test/test/utils/fake_and_mock_utils.dart index db2b7ba438503..8f5fcf1720ad8 100644 --- a/packages/flutter_test/test/utils/fake_and_mock_utils.dart +++ b/packages/flutter_test/test/utils/fake_and_mock_utils.dart @@ -19,7 +19,7 @@ void verifyPropertyFaked<TProperty>({ required TProperty realValue, required TProperty fakeValue, required TProperty Function() propertyRetriever, - required Function(TestWidgetsFlutterBinding, TProperty fakeValue) propertyFaker, + required void Function(TestWidgetsFlutterBinding, TProperty fakeValue) propertyFaker, Matcher Function(TProperty) matcher = equals, }) { TProperty propertyBeforeFaking; @@ -45,8 +45,8 @@ void verifyPropertyReset<TProperty>({ required WidgetTester tester, required TProperty fakeValue, required TProperty Function() propertyRetriever, - required Function() propertyResetter, - required Function(TProperty fakeValue) propertyFaker, + required VoidCallback propertyResetter, + required ValueSetter<TProperty> propertyFaker, Matcher Function(TProperty) matcher = equals, }) { TProperty propertyBeforeFaking; diff --git a/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart index e5bce99b638a2..7862b4d919158 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_deploy_test.dart @@ -80,7 +80,7 @@ void main () { expect(iosDeployDebugger.logLines, emits('Did finish launching.')); expect(await iosDeployDebugger.launchAndAttach(), isTrue); - await iosDeployDebugger.logLines.drain(); + await iosDeployDebugger.logLines.drain<Object?>(); expect(processManager, hasNoRemainingExpectations); expect(appDeltaDirectory, exists); }); @@ -141,7 +141,7 @@ void main () { 'process detach', ])); expect(await iosDeployDebugger.launchAndAttach(), isTrue); - await logLines.drain(); + await logLines.drain<Object?>(); expect(logger.traceText, contains('PROCESS_STOPPED')); expect(logger.traceText, contains('thread backtrace all')); @@ -189,7 +189,7 @@ void main () { expect(iosDeployDebugger.logLines, emitsDone); expect(await iosDeployDebugger.launchAndAttach(), isFalse); - await iosDeployDebugger.logLines.drain(); + await iosDeployDebugger.logLines.drain<Object?>(); }); testWithoutContext('app exit', () async { @@ -209,7 +209,7 @@ void main () { ])); expect(await iosDeployDebugger.launchAndAttach(), isTrue); - await iosDeployDebugger.logLines.drain(); + await iosDeployDebugger.logLines.drain<Object?>(); }); testWithoutContext('app crash', () async { @@ -239,7 +239,7 @@ void main () { ])); expect(await iosDeployDebugger.launchAndAttach(), isTrue); - await iosDeployDebugger.logLines.drain(); + await iosDeployDebugger.logLines.drain<Object?>(); expect(logger.traceText, contains('Process 6156 stopped')); expect(logger.traceText, contains('thread backtrace all')); @@ -263,7 +263,7 @@ void main () { expect(iosDeployDebugger.logLines, emitsDone); expect(await iosDeployDebugger.launchAndAttach(), isFalse); - await iosDeployDebugger.logLines.drain(); + await iosDeployDebugger.logLines.drain<Object?>(); }); testWithoutContext('no provisioning profile 1, stdout', () async { @@ -364,7 +364,7 @@ void main () { 'Log on attach2', ])); expect(await iosDeployDebugger.launchAndAttach(), isTrue); - await logLines.drain(); + await logLines.drain<Object?>(); expect(LineSplitter.split(logger.traceText), containsOnce('Received logs from ios-deploy.')); }); diff --git a/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart b/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart index f92da208d4100..49ca2cebf3f13 100644 --- a/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart +++ b/packages/flutter_tools/test/integration.shard/debug_adapter/test_server.dart @@ -19,7 +19,7 @@ abstract class DapTestServer { Future<void> stop(); StreamSink<List<int>> get sink; Stream<List<int>> get stream; - Function(String message)? onStderrOutput; + void Function(String message)? onStderrOutput; } /// An instance of a DAP server running in-process (to aid debugging). @@ -83,7 +83,7 @@ class OutOfProcessDapTestServer extends DapTestServer { .listen((String error) { logger?.call(error); if (!_isShuttingDown) { - final Function(String message)? stderrHandler = onStderrOutput; + final void Function(String message)? stderrHandler = onStderrOutput; if (stderrHandler != null) { stderrHandler(error); } else { diff --git a/packages/flutter_tools/test/src/fake_http_client.dart b/packages/flutter_tools/test/src/fake_http_client.dart index b30074274b411..e21db1cd399c9 100644 --- a/packages/flutter_tools/test/src/fake_http_client.dart +++ b/packages/flutter_tools/test/src/fake_http_client.dart @@ -147,7 +147,7 @@ class FakeHttpClient implements HttpClient { bool Function(X509Certificate cert, String host, int port)? badCertificateCallback; @override - Function(String line)? keyLog; + void Function(String line)? keyLog; @override void close({bool force = false}) { } From e6d160a5c71c3816ae634b664804a31c5474d4c6 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Wed, 20 Sep 2023 22:27:29 +0200 Subject: [PATCH 1371/1547] Cover more test/widgets tests with leak tracking #7 (#134943) --- .../flutter/test/widgets/pop_scope_test.dart | 9 +- .../flutter/test/widgets/positioned_test.dart | 5 +- ...range_maintaining_scroll_physics_test.dart | 13 +- .../widgets/raw_keyboard_listener_test.dart | 16 +-- .../flutter/test/widgets/reassemble_test.dart | 3 +- .../widgets/render_object_element_test.dart | 3 +- .../widgets/render_object_widget_test.dart | 11 +- .../test/widgets/reorderable_list_test.dart | 56 ++++----- .../widgets/reparent_state_harder_test.dart | 3 +- .../test/widgets/reparent_state_test.dart | 15 +-- ...parent_state_with_layout_builder_test.dart | 5 +- .../widgets/restorable_property_test.dart | 111 +++++++++++++----- .../test/widgets/restoration_mixin_test.dart | 41 ++++--- .../test/widgets/restoration_scope_test.dart | 30 +++-- .../restoration_scopes_moving_test.dart | 5 +- .../flutter/test/widgets/rich_text_test.dart | 11 +- .../widgets/root_restoration_scope_test.dart | 23 ++-- .../test/widgets/rotated_box_test.dart | 3 +- .../route_notification_messages_test.dart | 20 +++- .../flutter/test/widgets/routes_test.dart | 80 +++++++------ packages/flutter/test/widgets/row_test.dart | 55 ++++----- packages/flutter/test/widgets/rtl_test.dart | 9 +- .../flutter/test/widgets/run_app_test.dart | 3 +- .../flutter/test/widgets/safe_area_test.dart | 34 +++--- .../test/widgets/scroll_activity_test.dart | 12 +- .../scroll_aware_image_provider_test.dart | 24 ++-- .../test/widgets/scroll_behavior_test.dart | 19 +-- .../test/widgets/scroll_controller_test.dart | 36 ++++-- .../test/widgets/scroll_events_test.dart | 17 +-- 29 files changed, 409 insertions(+), 263 deletions(-) diff --git a/packages/flutter/test/widgets/pop_scope_test.dart b/packages/flutter/test/widgets/pop_scope_test.dart index 116951ce78778..23f7569ee98f4 100644 --- a/packages/flutter/test/widgets/pop_scope_test.dart +++ b/packages/flutter/test/widgets/pop_scope_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'navigator_utils.dart'; @@ -34,7 +35,7 @@ void main() { .setMockMethodCallHandler(SystemChannels.platform, null); }); - testWidgets('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toggling canPop on root route allows/prevents backs', (WidgetTester tester) async { bool canPop = false; late StateSetter setState; late BuildContext context; @@ -79,7 +80,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toggling canPop on secondary route allows/prevents backs', (WidgetTester tester) async { final GlobalKey<NavigatorState> nav = GlobalKey<NavigatorState>(); bool canPop = true; late StateSetter setState; @@ -247,7 +248,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('removing PopScope from the tree removes its effect on navigation', (WidgetTester tester) async { bool usePopScope = true; late StateSetter setState; late BuildContext context; @@ -299,7 +300,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets('identical PopScopes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('identical PopScopes', (WidgetTester tester) async { bool usePopScope1 = true; bool usePopScope2 = true; late StateSetter setState; diff --git a/packages/flutter/test/widgets/positioned_test.dart b/packages/flutter/test/widgets/positioned_test.dart index 834bd845f0af3..33a8331bda32d 100644 --- a/packages/flutter/test/widgets/positioned_test.dart +++ b/packages/flutter/test/widgets/positioned_test.dart @@ -7,9 +7,10 @@ import 'dart:async'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Positioned constructors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Positioned constructors', (WidgetTester tester) async { final Widget child = Container(); final Positioned a = Positioned( left: 101.0, @@ -56,7 +57,7 @@ void main() { expect(c.height, null); }); - testWidgets('Can animate position data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can animate position data', (WidgetTester tester) async { final RelativeRectTween rect = RelativeRectTween( begin: RelativeRect.fromRect( const Rect.fromLTRB(10.0, 20.0, 20.0, 30.0), diff --git a/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart b/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart index cc55aecf4729e..4b3eea78f7666 100644 --- a/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart +++ b/packages/flutter/test/widgets/range_maintaining_scroll_physics_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class ExpandingBox extends StatefulWidget { const ExpandingBox({ super.key, required this.collapsedSize, required this.expandedSize }); @@ -53,7 +54,7 @@ class _ExpandingBoxState extends State<ExpandingBox> with AutomaticKeepAliveClie } void main() { - testWidgets('shrink listview', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shrink listview', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: ListView.builder( itemBuilder: (BuildContext context, int index) => index == 0 @@ -98,7 +99,7 @@ void main() { expect(position.pixels, 100.0); }); - testWidgets('shrink listview while dragging', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shrink listview while dragging', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: ListView.builder( itemBuilder: (BuildContext context, int index) => index == 0 @@ -157,7 +158,7 @@ void main() { expect(position.pixels, 50.0); }); - testWidgets('shrink listview while ballistic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shrink listview while ballistic', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: GestureDetector( onTap: () { assert(false); }, @@ -220,7 +221,7 @@ void main() { expect(position.pixels, 0.0); }); - testWidgets('expanding page views', (WidgetTester tester) async { + testWidgetsWithLeakTracking('expanding page views', (WidgetTester tester) async { await tester.pumpWidget(const Padding(padding: EdgeInsets.only(right: 200.0), child: TabBarDemo())); await tester.tap(find.text('bike')); await tester.pump(); @@ -231,7 +232,7 @@ void main() { expect(bike2.center, bike1.shift(const Offset(100.0, 0.0)).center); }); - testWidgets('changing the size of the viewport when overscrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('changing the size of the viewport when overscrolled', (WidgetTester tester) async { Widget build(double height) { return Directionality( textDirection: TextDirection.rtl, @@ -265,7 +266,7 @@ void main() { expect(oldPosition, newPosition); }); - testWidgets('inserting and removing an item when overscrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inserting and removing an item when overscrolled', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/62890 const double itemExtent = 100.0; diff --git a/packages/flutter/test/widgets/raw_keyboard_listener_test.dart b/packages/flutter/test/widgets/raw_keyboard_listener_test.dart index 64f927b5f95c9..4bb44325bd967 100644 --- a/packages/flutter/test/widgets/raw_keyboard_listener_test.dart +++ b/packages/flutter/test/widgets/raw_keyboard_listener_test.dart @@ -5,19 +5,22 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Can dispose without keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can dispose without keyboard', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget(RawKeyboardListener(focusNode: focusNode, child: Container())); await tester.pumpWidget(RawKeyboardListener(focusNode: focusNode, child: Container())); await tester.pumpWidget(Container()); }); - testWidgets('Fuchsia key event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fuchsia key event', (WidgetTester tester) async { final List<RawKeyEvent> events = <RawKeyEvent>[]; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( RawKeyboardListener( @@ -43,13 +46,13 @@ void main() { expect(typedData.isModifierPressed(ModifierKey.metaModifier, side: KeyboardSide.left), isTrue); await tester.pumpWidget(Container()); - focusNode.dispose(); }, skip: isBrowser); // [intended] This is a Fuchsia-specific test. - testWidgets('Web key event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Web key event', (WidgetTester tester) async { final List<RawKeyEvent> events = <RawKeyEvent>[]; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( RawKeyboardListener( @@ -74,13 +77,13 @@ void main() { expect(typedData.isModifierPressed(ModifierKey.metaModifier, side: KeyboardSide.left), isTrue); await tester.pumpWidget(Container()); - focusNode.dispose(); }); - testWidgets('Defunct listeners do not receive events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Defunct listeners do not receive events', (WidgetTester tester) async { final List<RawKeyEvent> events = <RawKeyEvent>[]; final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( RawKeyboardListener( @@ -108,6 +111,5 @@ void main() { expect(events.length, 0); await tester.pumpWidget(Container()); - focusNode.dispose(); }); } diff --git a/packages/flutter/test/widgets/reassemble_test.dart b/packages/flutter/test/widgets/reassemble_test.dart index 32eff20023226..2145a34cbe6f1 100644 --- a/packages/flutter/test/widgets/reassemble_test.dart +++ b/packages/flutter/test/widgets/reassemble_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('reassemble does not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reassemble does not crash', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: Text('Hello World'), )); diff --git a/packages/flutter/test/widgets/render_object_element_test.dart b/packages/flutter/test/widgets/render_object_element_test.dart index a485d3fed6950..95189e03bba9d 100644 --- a/packages/flutter/test/widgets/render_object_element_test.dart +++ b/packages/flutter/test/widgets/render_object_element_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; @immutable class Pair<T> { @@ -239,7 +240,7 @@ class RenderSwapper extends RenderBox { BoxParentData parentDataFor(RenderObject renderObject) => renderObject.parentData! as BoxParentData; void main() { - testWidgets('RenderObjectElement *RenderObjectChild methods get called with correct arguments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjectElement *RenderObjectChild methods get called with correct arguments', (WidgetTester tester) async { const Key redKey = ValueKey<String>('red'); const Key blueKey = ValueKey<String>('blue'); Widget widget() { diff --git a/packages/flutter/test/widgets/render_object_widget_test.dart b/packages/flutter/test/widgets/render_object_widget_test.dart index e6ba52fd82307..7aac4ea187672 100644 --- a/packages/flutter/test/widgets/render_object_widget_test.dart +++ b/packages/flutter/test/widgets/render_object_widget_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; final BoxDecoration kBoxDecorationA = BoxDecoration(border: nonconst(null)); final BoxDecoration kBoxDecorationB = BoxDecoration(border: nonconst(null)); @@ -75,7 +76,7 @@ class TestNonVisitingRenderObject extends RenderBox with RenderObjectWithChildMi } void main() { - testWidgets('RenderObjectWidget smoke test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjectWidget smoke test', (WidgetTester tester) async { await tester.pumpWidget(DecoratedBox(decoration: kBoxDecorationA)); SingleChildRenderObjectElement element = tester.element(find.byElementType(SingleChildRenderObjectElement)); @@ -94,7 +95,7 @@ void main() { expect(renderObject.position, equals(DecorationPosition.background)); }); - testWidgets('RenderObjectWidget can add and remove children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjectWidget can add and remove children', (WidgetTester tester) async { void checkFullTree() { final SingleChildRenderObjectElement element = @@ -178,7 +179,7 @@ void main() { childBareTree(); }); - testWidgets('Detached render tree is intact', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Detached render tree is intact', (WidgetTester tester) async { await tester.pumpWidget(DecoratedBox( decoration: kBoxDecorationA, @@ -220,7 +221,7 @@ void main() { expect(grandChild.child, isNull); }); - testWidgets('Can watch inherited widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can watch inherited widgets', (WidgetTester tester) async { final Key boxKey = UniqueKey(); final TestOrientedBox box = TestOrientedBox(key: boxKey); @@ -242,7 +243,7 @@ void main() { expect(decoration.color, equals(const Color(0xFF0000FF))); }); - testWidgets('RenderObject not visiting children provides helpful error message', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObject not visiting children provides helpful error message', (WidgetTester tester) async { await tester.pumpWidget( TestNonVisitingWidget( child: Container(color: const Color(0xFFED1D7F)), diff --git a/packages/flutter/test/widgets/reorderable_list_test.dart b/packages/flutter/test/widgets/reorderable_list_test.dart index 496d2242b1b33..f50b0380eed23 100644 --- a/packages/flutter/test/widgets/reorderable_list_test.dart +++ b/packages/flutter/test/widgets/reorderable_list_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('SliverReorderableList works well when having gestureSettings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList works well when having gestureSettings', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/103404 const int itemCount = 5; int onReorderCallCount = 0; @@ -67,7 +68,7 @@ void main() { expect(items, orderedEquals(<int>[1, 0, 2, 3, 4])); }); - testWidgets('SliverReorderableList item has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList item has correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const int itemCount = 5; int onReorderCallCount = 0; @@ -127,7 +128,7 @@ void main() { semantics.dispose(); }); - testWidgets('SliverReorderableList custom semantics action has correct label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList custom semantics action has correct label', (WidgetTester tester) async { const int itemCount = 5; final List<int> items = List<int>.generate(itemCount, (int index) => index); // The list has five elements of height 100 @@ -166,7 +167,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/100451 - testWidgets('SliverReorderableList.builder respects findChildIndexCallback', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList.builder respects findChildIndexCallback', (WidgetTester tester) async { bool finderCalled = false; int itemCount = 7; late StateSetter stateSetter; @@ -206,7 +207,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/88191 - testWidgets('Do not crash when dragging with two fingers simultaneously', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when dragging with two fingers simultaneously', (WidgetTester tester) async { final List<int> items = List<int>.generate(3, (int index) => index); void handleReorder(int fromIndex, int toIndex) { if (toIndex > fromIndex) { @@ -252,7 +253,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('negative itemCount should assert', (WidgetTester tester) async { + testWidgetsWithLeakTracking('negative itemCount should assert', (WidgetTester tester) async { final List<int> items = <int>[1, 2, 3]; await tester.pumpWidget(MaterialApp( home: StatefulBuilder( @@ -284,7 +285,7 @@ void main() { expect(tester.takeException(), isA<AssertionError>()); }); - testWidgets('zero itemCount should not build widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('zero itemCount should not build widget', (WidgetTester tester) async { final List<int> items = <int>[1, 2, 3]; await tester.pumpWidget(MaterialApp( home: StatefulBuilder( @@ -331,7 +332,7 @@ void main() { expect(find.text('after'), findsOneWidget); }); - testWidgets('SliverReorderableList, drag and drop, fixed height items', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList, drag and drop, fixed height items', (WidgetTester tester) async { final List<int> items = List<int>.generate(8, (int index) => index); Future<void> pressDragRelease(Offset start, Offset delta) async { @@ -397,7 +398,7 @@ void main() { expect(items, orderedEquals(<int>[0, 1, 2, 3, 4, 5, 6, 7])); }); - testWidgets('SliverReorderableList, items inherit DefaultTextStyle, IconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList, items inherit DefaultTextStyle, IconTheme', (WidgetTester tester) async { const Color textColor = Color(0xffffffff); const Color iconColor = Color(0xff0000ff); @@ -450,7 +451,7 @@ void main() { expect(getTextStyle().color, textColor); }); - testWidgets('SliverReorderableList - custom proxyDecorator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList - custom proxyDecorator', (WidgetTester tester) async { const ValueKey<String> fadeTransitionKey = ValueKey<String>('reordered-fade'); await tester.pumpWidget( @@ -513,7 +514,7 @@ void main() { expect(getItemFadeTransition(), findsNothing); }); - testWidgets('ReorderableList supports items with nested list views without throwing layout exception.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableList supports items with nested list views without throwing layout exception.', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -567,7 +568,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('ReorderableList supports items with nested list views without throwing layout exception.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableList supports items with nested list views without throwing layout exception.', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/83224. await tester.pumpWidget( MaterialApp( @@ -622,7 +623,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('SliverReorderableList - properly animates the drop in a reversed list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList - properly animates the drop in a reversed list', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110949 final List<int> items = List<int>.generate(8, (int index) => index); @@ -673,7 +674,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')), const Offset(0, 400)); }); - testWidgets('SliverReorderableList - properly animates the drop at starting position in a reversed list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList - properly animates the drop at starting position in a reversed list', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/84625 final List<int> items = List<int>.generate(8, (int index) => index); @@ -716,7 +717,7 @@ void main() { expect(tester.getTopLeft(find.text('item 0')), const Offset(0, 500)); }); - testWidgets('SliverReorderableList calls onReorderStart and onReorderEnd correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList calls onReorderStart and onReorderEnd correctly', (WidgetTester tester) async { final List<int> items = List<int>.generate(8, (int index) => index); int? startIndex, endIndex; final Finder item0 = find.textContaining('item 0'); @@ -767,7 +768,7 @@ void main() { expect(endIndex, equals(0)); }); - testWidgets('ReorderableList calls onReorderStart and onReorderEnd correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableList calls onReorderStart and onReorderEnd correctly', (WidgetTester tester) async { final List<int> items = List<int>.generate(8, (int index) => index); int? startIndex, endIndex; final Finder item0 = find.textContaining('item 0'); @@ -840,7 +841,7 @@ void main() { - testWidgets('ReorderableList asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ReorderableList asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { final List<int> numbers = <int>[0,1,2]; expect(() => ReorderableList( itemBuilder: (BuildContext context, int index) { @@ -860,7 +861,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('SliverReorderableList asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList asserts on both non-null itemExtent and prototypeItem', (WidgetTester tester) async { final List<int> numbers = <int>[0,1,2]; expect(() => SliverReorderableList( itemBuilder: (BuildContext context, int index) { @@ -880,7 +881,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('if itemExtent is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { final List<int> numbers = <int>[0,1,2]; await tester.pumpWidget( @@ -925,7 +926,7 @@ void main() { expect(item2Height, 30.0); }); - testWidgets('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { + testWidgetsWithLeakTracking('if prototypeItem is non-null, children have same extent in the scroll direction', (WidgetTester tester) async { final List<int> numbers = <int>[0,1,2]; await tester.pumpWidget( @@ -968,7 +969,7 @@ void main() { }); group('ReorderableDragStartListener', () { - testWidgets('It should allow the item to be dragged when enabled is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('It should allow the item to be dragged when enabled is true', (WidgetTester tester) async { const int itemCount = 5; int onReorderCallCount = 0; final List<int> items = List<int>.generate(itemCount, (int index) => index); @@ -1014,7 +1015,7 @@ void main() { expect(items, orderedEquals(<int>[1, 0, 2, 3, 4])); }); - testWidgets('It should not allow the item to be dragged when enabled is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('It should not allow the item to be dragged when enabled is false', (WidgetTester tester) async { const int itemCount = 5; int onReorderCallCount = 0; final List<int> items = List<int>.generate(itemCount, (int index) => index); @@ -1063,7 +1064,7 @@ void main() { }); group('ReorderableDelayedDragStartListener', () { - testWidgets('It should allow the item to be dragged when enabled is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('It should allow the item to be dragged when enabled is true', (WidgetTester tester) async { const int itemCount = 5; int onReorderCallCount = 0; final List<int> items = List<int>.generate(itemCount, (int index) => index); @@ -1110,7 +1111,7 @@ void main() { expect(items, orderedEquals(<int>[1, 0, 2, 3, 4])); }); - testWidgets('It should not allow the item to be dragged when enabled is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('It should not allow the item to be dragged when enabled is false', (WidgetTester tester) async { const int itemCount = 5; int onReorderCallCount = 0; final List<int> items = List<int>.generate(itemCount, (int index) => index); @@ -1158,7 +1159,7 @@ void main() { }); }); - testWidgets('SliverReorderableList properly disposes items', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList properly disposes items', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/105010 const int itemCount = 5; final List<int> items = List<int>.generate(itemCount, (int index) => index); @@ -1225,7 +1226,7 @@ void main() { expect(item0, findsNothing); }); - testWidgets('SliverReorderableList auto scrolls speed is configurable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverReorderableList auto scrolls speed is configurable', (WidgetTester tester) async { Future<void> pumpFor({ required Duration duration, Duration interval = const Duration(milliseconds: 50), @@ -1243,6 +1244,7 @@ void main() { Future<double> pumpListAndDrag({required double autoScrollerVelocityScalar}) async { final List<int> items = List<int>.generate(10, (int index) => index); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget( MaterialApp( @@ -1310,7 +1312,7 @@ void main() { expect(offsetForFastScroller / offsetForSlowScroller, fastVelocityScalar / slowVelocityScalar); }); - testWidgets('Null check error when dragging and dropping last element into last index with reverse:true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Null check error when dragging and dropping last element into last index with reverse:true', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/132077 const int itemCount = 5; final List<String> items = List<String>.generate(itemCount, (int index) => 'Item ${index+1}'); diff --git a/packages/flutter/test/widgets/reparent_state_harder_test.dart b/packages/flutter/test/widgets/reparent_state_harder_test.dart index d7029bb888192..3deb76318e008 100644 --- a/packages/flutter/test/widgets/reparent_state_harder_test.dart +++ b/packages/flutter/test/widgets/reparent_state_harder_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // This is a regression test for https://github.com/flutter/flutter/issues/5588. @@ -92,7 +93,7 @@ class RekeyableDummyStatefulWidgetWrapperState extends State<RekeyableDummyState } void main() { - testWidgets('Handle GlobalKey reparenting in weird orders', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Handle GlobalKey reparenting in weird orders', (WidgetTester tester) async { // This is a bit of a weird test so let's try to explain it a bit. // diff --git a/packages/flutter/test/widgets/reparent_state_test.dart b/packages/flutter/test/widgets/reparent_state_test.dart index a14505a877b81..ce7ab6bb7f7f7 100644 --- a/packages/flutter/test/widgets/reparent_state_test.dart +++ b/packages/flutter/test/widgets/reparent_state_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class StateMarker extends StatefulWidget { const StateMarker({ super.key, this.child }); @@ -50,7 +51,7 @@ class DeactivateLoggerState extends State<DeactivateLogger> { } void main() { - testWidgets('can reparent state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can reparent state', (WidgetTester tester) async { final GlobalKey left = GlobalKey(); final GlobalKey right = GlobalKey(); @@ -130,7 +131,7 @@ void main() { expect(right.currentState, isNull); }); - testWidgets('can reparent state with multichild widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can reparent state with multichild widgets', (WidgetTester tester) async { final GlobalKey left = GlobalKey(); final GlobalKey right = GlobalKey(); @@ -198,7 +199,7 @@ void main() { expect(right.currentState, isNull); }); - testWidgets('can with scrollable list', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can with scrollable list', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(StateMarker(key: key)); @@ -231,7 +232,7 @@ void main() { expect(keyState.marker, equals('marked')); }); - testWidgets('Reparent during update children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reparent during update children', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(Stack( @@ -268,7 +269,7 @@ void main() { expect(keyState.marker, equals('marked')); }); - testWidgets('Reparent to child during update children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reparent to child during update children', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); await tester.pumpWidget(Stack( @@ -330,7 +331,7 @@ void main() { expect(keyState.marker, equals('marked')); }); - testWidgets('Deactivate implies build', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Deactivate implies build', (WidgetTester tester) async { final GlobalKey key = GlobalKey(); final List<String> log = <String>[]; final DeactivateLogger logger = DeactivateLogger(key: key, log: log); @@ -352,7 +353,7 @@ void main() { expect(log, isEmpty); }); - testWidgets('Reparenting with multiple moves', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Reparenting with multiple moves', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(); final GlobalKey key2 = GlobalKey(); final GlobalKey key3 = GlobalKey(); diff --git a/packages/flutter/test/widgets/reparent_state_with_layout_builder_test.dart b/packages/flutter/test/widgets/reparent_state_with_layout_builder_test.dart index 9578888c30fdd..567f344e823e6 100644 --- a/packages/flutter/test/widgets/reparent_state_with_layout_builder_test.dart +++ b/packages/flutter/test/widgets/reparent_state_with_layout_builder_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; // This is a regression test for https://github.com/flutter/flutter/issues/5840. @@ -65,7 +66,7 @@ class StatefulCreationCounterState extends State<StatefulCreationCounter> { } void main() { - testWidgets('reparent state with layout builder', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reparent state with layout builder', (WidgetTester tester) async { expect(StatefulCreationCounterState.creationCount, 0); await tester.pumpWidget(const Bar()); expect(StatefulCreationCounterState.creationCount, 1); @@ -75,7 +76,7 @@ void main() { expect(StatefulCreationCounterState.creationCount, 1); }); - testWidgets('Clean then reparent with dependencies', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Clean then reparent with dependencies', (WidgetTester tester) async { int layoutBuilderBuildCount = 0; late StateSetter keyedSetState; diff --git a/packages/flutter/test/widgets/restorable_property_test.dart b/packages/flutter/test/widgets/restorable_property_test.dart index bb985cd130806..f6725601507ac 100644 --- a/packages/flutter/test/widgets/restorable_property_test.dart +++ b/packages/flutter/test/widgets/restorable_property_test.dart @@ -7,30 +7,62 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('value is not accessible when not registered', (WidgetTester tester) async { - expect(() => RestorableNum<num>(0).value, throwsAssertionError); - expect(() => RestorableDouble(1.0).value, throwsAssertionError); - expect(() => RestorableInt(1).value, throwsAssertionError); - expect(() => RestorableString('hello').value, throwsAssertionError); - expect(() => RestorableBool(true).value, throwsAssertionError); - expect(() => RestorableNumN<num?>(0).value, throwsAssertionError); - expect(() => RestorableDoubleN(1.0).value, throwsAssertionError); - expect(() => RestorableIntN(1).value, throwsAssertionError); - expect(() => RestorableStringN('hello').value, throwsAssertionError); - expect(() => RestorableBoolN(true).value, throwsAssertionError); - expect(() => RestorableTextEditingController().value, throwsAssertionError); - expect(() => RestorableDateTime(DateTime(2020, 4, 3)).value, throwsAssertionError); - expect(() => RestorableDateTimeN(DateTime(2020, 4, 3)).value, throwsAssertionError); - expect(() => RestorableEnumN<TestEnum>(TestEnum.one, values: TestEnum.values).value, throwsAssertionError); - expect(() => RestorableEnum<TestEnum>(TestEnum.one, values: TestEnum.values).value, throwsAssertionError); - expect(() => _TestRestorableValue().value, throwsAssertionError); + testWidgetsWithLeakTracking('value is not accessible when not registered', (WidgetTester tester) async { + final RestorableNum<num> numValue = RestorableNum<num>(0); + addTearDown(numValue.dispose); + expect(() => numValue.value, throwsAssertionError); + final RestorableDouble doubleValue = RestorableDouble(1.0); + addTearDown(doubleValue.dispose); + expect(() => doubleValue.value, throwsAssertionError); + final RestorableInt intValue = RestorableInt(1); + addTearDown(intValue.dispose); + expect(() => intValue.value, throwsAssertionError); + final RestorableString stringValue = RestorableString('hello'); + addTearDown(stringValue.dispose); + expect(() => stringValue.value, throwsAssertionError); + final RestorableBool boolValue = RestorableBool(true); + addTearDown(boolValue.dispose); + expect(() => boolValue.value, throwsAssertionError); + final RestorableNumN<num?> nullableNumValue = RestorableNumN<num?>(0); + addTearDown(nullableNumValue.dispose); + expect(() => nullableNumValue.value, throwsAssertionError); + final RestorableDoubleN nullableDoubleValue = RestorableDoubleN(1.0); + addTearDown(nullableDoubleValue.dispose); + expect(() => nullableDoubleValue.value, throwsAssertionError); + final RestorableIntN nullableIntValue = RestorableIntN(1); + addTearDown(nullableIntValue.dispose); + expect(() => nullableIntValue.value, throwsAssertionError); + final RestorableStringN nullableStringValue = RestorableStringN('hello'); + addTearDown(nullableStringValue.dispose); + expect(() => nullableStringValue.value, throwsAssertionError); + final RestorableBoolN nullableBoolValue = RestorableBoolN(true); + addTearDown(nullableBoolValue.dispose); + expect(() => nullableBoolValue.value, throwsAssertionError); + final RestorableTextEditingController controllerValue = RestorableTextEditingController(); + addTearDown(controllerValue.dispose); + expect(() => controllerValue.value, throwsAssertionError); + final RestorableDateTime dateTimeValue = RestorableDateTime(DateTime(2020, 4, 3)); + addTearDown(dateTimeValue.dispose); + expect(() => dateTimeValue.value, throwsAssertionError); + final RestorableDateTimeN nullableDateTimeValue = RestorableDateTimeN(DateTime(2020, 4, 3)); + addTearDown(nullableDateTimeValue.dispose); + expect(() => nullableDateTimeValue.value, throwsAssertionError); + final RestorableEnumN<TestEnum> nullableEnumValue = RestorableEnumN<TestEnum>(TestEnum.one, values: TestEnum.values); + addTearDown(nullableEnumValue.dispose); + expect(() => nullableEnumValue.value, throwsAssertionError); + final RestorableEnum<TestEnum> enumValue = RestorableEnum<TestEnum>(TestEnum.one, values: TestEnum.values); + addTearDown(enumValue.dispose); + expect(() => enumValue.value, throwsAssertionError); + final _TestRestorableValue objectValue = _TestRestorableValue(); + addTearDown(objectValue.dispose); + expect(() => objectValue.value, throwsAssertionError); }); testWidgetsWithLeakTracking('$RestorableProperty dispatches creation in constructor', (WidgetTester widgetTester) async { - expect(()=> RestorableDateTimeN(null).dispose(), dispatchesMemoryEvents(RestorableDateTimeN)); + expect(() => RestorableDateTimeN(null).dispose(), dispatchesMemoryEvents(RestorableDateTimeN)); }); - testWidgets('work when not in restoration scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { await tester.pumpWidget(const _RestorableWidget()); expect(find.text('hello world'), findsOneWidget); @@ -94,7 +126,7 @@ void main() { expect(find.text('guten tag'), findsOneWidget); }); - testWidgets('restart and restore', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restart and restore', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -185,7 +217,7 @@ void main() { expect(find.text('guten tag'), findsOneWidget); }); - testWidgets('restore to older state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restore to older state', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -283,7 +315,7 @@ void main() { expect(find.text('hello world'), findsOneWidget); }); - testWidgets('call notifiers when value changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('call notifiers when value changes', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -465,7 +497,7 @@ void main() { expect(notifyLog, isEmpty); }); - testWidgets('RestorableValue calls didUpdateValue', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableValue calls didUpdateValue', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -489,7 +521,7 @@ void main() { expect(state.objectValue.didUpdateValueCallCount, 1); }); - testWidgets('RestorableEnum and RestorableEnumN assert if default value is not in enum', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableEnum and RestorableEnumN assert if default value is not in enum', (WidgetTester tester) async { expect(() => RestorableEnum<TestEnum>( TestEnum.four, values: TestEnum.values.toSet().difference(<TestEnum>{TestEnum.four})), throwsAssertionError); @@ -498,33 +530,37 @@ void main() { values: TestEnum.values.toSet().difference(<TestEnum>{TestEnum.four})), throwsAssertionError); }); - testWidgets('RestorableEnum and RestorableEnumN assert if unknown values are set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableEnum and RestorableEnumN assert if unknown values are set', (WidgetTester tester) async { final RestorableEnum<TestEnum> enumMissingValue = RestorableEnum<TestEnum>( TestEnum.one, values: TestEnum.values.toSet().difference(<TestEnum>{TestEnum.four}), ); + addTearDown(enumMissingValue.dispose); expect(() => enumMissingValue.value = TestEnum.four, throwsAssertionError); final RestorableEnumN<TestEnum> nullableEnumMissingValue = RestorableEnumN<TestEnum>( null, values: TestEnum.values.toSet().difference(<TestEnum>{TestEnum.four}), ); + addTearDown(nullableEnumMissingValue.dispose); expect(() => nullableEnumMissingValue.value = TestEnum.four, throwsAssertionError); }); - testWidgets('RestorableEnum and RestorableEnumN assert if unknown values are restored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableEnum and RestorableEnumN assert if unknown values are restored', (WidgetTester tester) async { final RestorableEnum<TestEnum> enumMissingValue = RestorableEnum<TestEnum>( TestEnum.one, values: TestEnum.values.toSet().difference(<TestEnum>{TestEnum.four}), ); + addTearDown(enumMissingValue.dispose); expect(() => enumMissingValue.fromPrimitives('four'), throwsAssertionError); final RestorableEnumN<TestEnum> nullableEnumMissingValue = RestorableEnumN<TestEnum>( null, values: TestEnum.values.toSet().difference(<TestEnum>{TestEnum.four}), ); + addTearDown(nullableEnumMissingValue.dispose); expect(() => nullableEnumMissingValue.fromPrimitives('four'), throwsAssertionError); }); - testWidgets('RestorableN types are properly defined', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RestorableN types are properly defined', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', child: _RestorableWidget(), @@ -631,6 +667,27 @@ class _RestorableWidgetState extends State<_RestorableWidget> with RestorationMi registerForRestoration(objectValue, 'object'); } + @override + void dispose() { + numValue.dispose(); + doubleValue.dispose(); + intValue.dispose(); + stringValue.dispose(); + boolValue.dispose(); + dateTimeValue.dispose(); + enumValue.dispose(); + nullableNumValue.dispose(); + nullableDoubleValue.dispose(); + nullableIntValue.dispose(); + nullableStringValue.dispose(); + nullableBoolValue.dispose(); + nullableDateTimeValue.dispose(); + nullableEnumValue.dispose(); + controllerValue.dispose(); + objectValue.dispose(); + super.dispose(); + } + void setProperties(VoidCallback callback) { setState(callback); } diff --git a/packages/flutter/test/widgets/restoration_mixin_test.dart b/packages/flutter/test/widgets/restoration_mixin_test.dart index 8eefb90df0fbf..7fb55feb461aa 100644 --- a/packages/flutter/test/widgets/restoration_mixin_test.dart +++ b/packages/flutter/test/widgets/restoration_mixin_test.dart @@ -4,13 +4,15 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'restoration.dart'; void main() { - testWidgets('claims bucket', (WidgetTester tester) async { + testWidgetsWithLeakTracking('claims bucket', (WidgetTester tester) async { const String id = 'hello world 1234'; final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = <String, dynamic>{}; final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); expect(rawData, isEmpty); @@ -35,8 +37,9 @@ void main() { expect(state.restoreStateLog.single, isNull); }); - testWidgets('claimed bucket with data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('claimed bucket with data', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); await tester.pumpWidget( @@ -57,8 +60,9 @@ void main() { expect(state.restoreStateLog.single, isNull); }); - testWidgets('renames existing bucket when new ID is provided via widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('renames existing bucket when new ID is provided via widget', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); await tester.pumpWidget( @@ -99,8 +103,9 @@ void main() { expect(state.toggleBucketLog, isEmpty); }); - testWidgets('renames existing bucket when didUpdateRestorationId is called', (WidgetTester tester) async { + testWidgetsWithLeakTracking('renames existing bucket when didUpdateRestorationId is called', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); await tester.pumpWidget( @@ -134,8 +139,9 @@ void main() { expect(state.toggleBucketLog, isEmpty); }); - testWidgets('Disposing widget removes its data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing widget removes its data', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = _createRawDataSet(); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); @@ -162,8 +168,9 @@ void main() { expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); }); - testWidgets('toggling id between null and non-null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toggling id between null and non-null', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = _createRawDataSet(); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); @@ -222,9 +229,10 @@ void main() { expect(state.toggleBucketLog.single, same(bucket)); }); - testWidgets('move in and out of scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('move in and out of scope', (WidgetTester tester) async { final Key key = GlobalKey(); final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = _createRawDataSet(); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); @@ -284,8 +292,9 @@ void main() { expect(state.toggleBucketLog.single, same(bucket)); }); - testWidgets('moving scope moves its data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('moving scope moves its data', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = <String, dynamic>{}; final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final Key key = GlobalKey(); @@ -349,7 +358,7 @@ void main() { expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('moving-child'), isTrue); }); - testWidgets('restartAndRestore', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restartAndRestore', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -388,7 +397,7 @@ void main() { expect(state.toggleBucketLog, isEmpty); }); - testWidgets('restore while running', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restore while running', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -427,7 +436,7 @@ void main() { expect(state.toggleBucketLog, isEmpty); }); - testWidgets('can register additional property outside of restoreState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can register additional property outside of restoreState', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -464,7 +473,7 @@ void main() { expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); }); - testWidgets('cannot register same property twice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cannot register same property twice', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -494,7 +503,7 @@ void main() { expect(() => state.registerPropertyUnderSameId(), throwsAssertionError); }); - testWidgets('data of disabled property is not stored', (WidgetTester tester) async { + testWidgetsWithLeakTracking('data of disabled property is not stored', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -534,7 +543,7 @@ void main() { expect(state.property.value, 10); // Initialized to default value. }); - testWidgets('Enabling property stores its data again', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Enabling property stores its data again', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -572,7 +581,7 @@ void main() { expect(state.property.value, 40); }); - testWidgets('Unregistering a property removes its data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unregistering a property removes its data', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', @@ -598,7 +607,7 @@ void main() { expect(state.bucket!.read<int>('additional'), 11); }); - testWidgets('Disposing a property unregisters it, but keeps data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing a property unregisters it, but keeps data', (WidgetTester tester) async { await tester.pumpWidget( const RootRestorationScope( restorationId: 'root-child', diff --git a/packages/flutter/test/widgets/restoration_scope_test.dart b/packages/flutter/test/widgets/restoration_scope_test.dart index 74ab521fc544f..aaabc66f6de0c 100644 --- a/packages/flutter/test/widgets/restoration_scope_test.dart +++ b/packages/flutter/test/widgets/restoration_scope_test.dart @@ -4,12 +4,13 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'restoration.dart'; void main() { group('UnmanagedRestorationScope', () { - testWidgets('makes bucket available to descendants', (WidgetTester tester) async { + testWidgetsWithLeakTracking('makes bucket available to descendants', (WidgetTester tester) async { final RestorationBucket bucket1 = RestorationBucket.empty( restorationId: 'foo', debugOwner: 'owner', @@ -39,7 +40,7 @@ void main() { expect(state.bucket, bucket2); }); - testWidgets('null bucket disables restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('null bucket disables restoration', (WidgetTester tester) async { await tester.pumpWidget( const UnmanagedRestorationScope( child: BucketSpy(), @@ -51,7 +52,7 @@ void main() { }); group('RestorationScope', () { - testWidgets('asserts when none is found', (WidgetTester tester) async { + testWidgetsWithLeakTracking('asserts when none is found', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget(WidgetsApp( color: const Color(0xD0FF0000), @@ -97,9 +98,10 @@ void main() { expect(RestorationScope.of(capturedContext), scope.bucket); }); - testWidgets('makes bucket available to descendants', (WidgetTester tester) async { + testWidgetsWithLeakTracking('makes bucket available to descendants', (WidgetTester tester) async { const String id = 'hello world 1234'; final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = <String, dynamic>{}; final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); expect(rawData, isEmpty); @@ -120,8 +122,9 @@ void main() { expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey(id), isTrue); }); - testWidgets('bucket for descendants contains data claimed from parent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('bucket for descendants contains data claimed from parent', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); await tester.pumpWidget( @@ -140,8 +143,9 @@ void main() { expect(state.bucket!.read<int>('foo'), 22); }); - testWidgets('renames existing bucket when new ID is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('renames existing bucket when new ID is provided', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); await tester.pumpWidget( @@ -178,8 +182,9 @@ void main() { expect(state.bucket, same(bucket)); }); - testWidgets('Disposing a scope removes its data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Disposing a scope removes its data', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = _createRawDataSet(); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); @@ -207,8 +212,9 @@ void main() { expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); }); - testWidgets('no bucket for descendants when id is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no bucket for descendants when id is null', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{}); await tester.pumpWidget( @@ -251,7 +257,7 @@ void main() { expect(state.bucket, isNull); }); - testWidgets('no bucket for descendants when scope is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no bucket for descendants when scope is null', (WidgetTester tester) async { final Key scopeKey = GlobalKey(); await tester.pumpWidget( @@ -266,6 +272,7 @@ void main() { // Move it under a valid scope. final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{}); await tester.pumpWidget( UnmanagedRestorationScope( @@ -293,7 +300,7 @@ void main() { expect(state.bucket, isNull); }); - testWidgets('no bucket for descendants when scope and id are null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no bucket for descendants when scope and id are null', (WidgetTester tester) async { await tester.pumpWidget( const RestorationScope( restorationId: null, @@ -304,8 +311,9 @@ void main() { expect(state.bucket, isNull); }); - testWidgets('moving scope moves its data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('moving scope moves its data', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = <String, dynamic>{}; final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final Key scopeKey = GlobalKey(); diff --git a/packages/flutter/test/widgets/restoration_scopes_moving_test.dart b/packages/flutter/test/widgets/restoration_scopes_moving_test.dart index 1edea3feb8a32..0b91adc024a47 100644 --- a/packages/flutter/test/widgets/restoration_scopes_moving_test.dart +++ b/packages/flutter/test/widgets/restoration_scopes_moving_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('widget moves scopes during restore', (WidgetTester tester) async { + testWidgetsWithLeakTracking('widget moves scopes during restore', (WidgetTester tester) async { await tester.pumpWidget(const RootRestorationScope( restorationId: 'root', child: Directionality( @@ -68,7 +69,7 @@ void main() { expect(tester.state<TestWidgetWithCounterChildState>(find.byType(TestWidgetWithCounterChild)).toggleCount, 0); }); - testWidgets('restoration is turned on later', (WidgetTester tester) async { + testWidgetsWithLeakTracking('restoration is turned on later', (WidgetTester tester) async { tester.binding.restorationManager.disableRestoration(); await tester.pumpWidget(const RootRestorationScope( restorationId: 'root-child', diff --git a/packages/flutter/test/widgets/rich_text_test.dart b/packages/flutter/test/widgets/rich_text_test.dart index 474854c22e960..abea136e5ca86 100644 --- a/packages/flutter/test/widgets/rich_text_test.dart +++ b/packages/flutter/test/widgets/rich_text_test.dart @@ -6,9 +6,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('RichText with recognizers without handlers does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RichText with recognizers without handlers does not throw', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -40,7 +41,7 @@ void main() { )); }); - testWidgets('TextSpan Locale works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextSpan Locale works', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -89,7 +90,7 @@ void main() { )); }); - testWidgets('TextSpan spellOut works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TextSpan spellOut works', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -138,7 +139,7 @@ void main() { )); }); - testWidgets('WidgetSpan calculate correct intrinsic heights', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpan calculate correct intrinsic heights', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -170,7 +171,7 @@ void main() { expect(tester.getSize(find.byType(IntrinsicHeight)).height, 3 * 16); }); - testWidgets('RichText implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RichText implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); RichText( text: const TextSpan(text: 'rich text'), diff --git a/packages/flutter/test/widgets/root_restoration_scope_test.dart b/packages/flutter/test/widgets/root_restoration_scope_test.dart index 56333dd55665c..26db826c53ade 100644 --- a/packages/flutter/test/widgets/root_restoration_scope_test.dart +++ b/packages/flutter/test/widgets/root_restoration_scope_test.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'restoration.dart'; @@ -17,8 +18,13 @@ void main() { binding._restorationManager = MockRestorationManager(); }); - testWidgets('does not inject root bucket if inside scope', (WidgetTester tester) async { + tearDown(() { + binding._restorationManager.dispose(); + }); + + testWidgetsWithLeakTracking('does not inject root bucket if inside scope', (WidgetTester tester) async { final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> rawData = <String, dynamic>{}; final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); expect(rawData, isEmpty); @@ -47,7 +53,7 @@ void main() { expect(find.text('Hello'), findsOneWidget); }); - testWidgets('waits for root bucket', (WidgetTester tester) async { + testWidgetsWithLeakTracking('waits for root bucket', (WidgetTester tester) async { final Completer<RestorationBucket> bucketCompleter = Completer<RestorationBucket>(); binding.restorationManager.rootBucket = bucketCompleter.future; @@ -83,7 +89,7 @@ void main() { expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue); }); - testWidgets('no delay when root is available synchronously', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no delay when root is available synchronously', (WidgetTester tester) async { final Map<String, dynamic> rawData = <String, dynamic>{}; final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); @@ -109,7 +115,7 @@ void main() { expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue); }); - testWidgets('does not insert root when restoration id is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not insert root when restoration id is null', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -175,9 +181,10 @@ void main() { expect(state.bucket, isNull); }); - testWidgets('injects root bucket when moved out of scope', (WidgetTester tester) async { + testWidgetsWithLeakTracking('injects root bucket when moved out of scope', (WidgetTester tester) async { final Key rootScopeKey = GlobalKey(); final MockRestorationManager manager = MockRestorationManager(); + addTearDown(manager.dispose); final Map<String, dynamic> inScopeRawData = <String, dynamic>{}; final RestorationBucket inScopeRootBucket = RestorationBucket.root(manager: manager, rawData: inScopeRawData); @@ -257,7 +264,7 @@ void main() { expect((inScopeRawData[childrenMapKey] as Map<Object?, Object?>).containsKey('root-child'), isTrue); }); - testWidgets('injects new root when old one is decommissioned', (WidgetTester tester) async { + testWidgetsWithLeakTracking('injects new root when old one is decommissioned', (WidgetTester tester) async { final Map<String, dynamic> firstRawData = <String, dynamic>{}; final RestorationBucket firstRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: firstRawData); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(firstRoot); @@ -300,7 +307,7 @@ void main() { expect(state.bucket!.read<int>('foo'), 22); }); - testWidgets('injects null when rootBucket is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('injects null when rootBucket is null', (WidgetTester tester) async { final Completer<RestorationBucket?> completer = Completer<RestorationBucket?>(); binding.restorationManager.rootBucket = completer.future; @@ -337,7 +344,7 @@ void main() { expect(state.bucket, isNotNull); }); - testWidgets('can switch to null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can switch to null', (WidgetTester tester) async { final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); diff --git a/packages/flutter/test/widgets/rotated_box_test.dart b/packages/flutter/test/widgets/rotated_box_test.dart index c47bfd09d5d68..9e93264aaea73 100644 --- a/packages/flutter/test/widgets/rotated_box_test.dart +++ b/packages/flutter/test/widgets/rotated_box_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Rotated box control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rotated box control test', (WidgetTester tester) async { final List<String> log = <String>[]; final Key rotatedBoxKey = UniqueKey(); diff --git a/packages/flutter/test/widgets/route_notification_messages_test.dart b/packages/flutter/test/widgets/route_notification_messages_test.dart index 1a3d65ae852cd..c1913d7db5605 100644 --- a/packages/flutter/test/widgets/route_notification_messages_test.dart +++ b/packages/flutter/test/widgets/route_notification_messages_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class OnTapPage extends StatelessWidget { const OnTapPage({super.key, required this.id, required this.onTap}); @@ -32,7 +33,7 @@ class OnTapPage extends StatelessWidget { } void main() { - testWidgets('Push and Pop should send platform messages', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Push and Pop should send platform messages', (WidgetTester tester) async { final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ '/': (BuildContext context) => OnTapPage( id: '/', @@ -107,7 +108,7 @@ void main() { ); }); - testWidgets('Navigator does not report route name by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigator does not report route name by default', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); @@ -141,7 +142,7 @@ void main() { expect(log, hasLength(0)); }); - testWidgets('Replace should send platform messages', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Replace should send platform messages', (WidgetTester tester) async { final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ '/': (BuildContext context) => OnTapPage( id: '/', @@ -217,7 +218,7 @@ void main() { ); }); - testWidgets('Nameless routes should send platform messages', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nameless routes should send platform messages', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); @@ -261,7 +262,7 @@ void main() { expect(log, isEmpty); }); - testWidgets('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('PlatformRouteInformationProvider reports URL', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.navigation, (MethodCall methodCall) async { log.add(methodCall); @@ -273,12 +274,14 @@ void main() { uri: Uri.parse('initial'), ), ); + addTearDown(provider.dispose); final SimpleRouterDelegate delegate = SimpleRouterDelegate( reportConfiguration: true, builder: (BuildContext context, RouteInformation information) { return Text(information.uri.toString()); }, ); + addTearDown(delegate.dispose); await tester.pumpWidget(MaterialApp.router( routeInformationProvider: provider, @@ -313,7 +316,12 @@ void main() { 'replace': false, }), ]); - }); + }, + leakTrackingTestConfig: const LeakTrackingTestConfig( + // TODO(ksokolovskyi): remove after fixing + // https://github.com/flutter/flutter/issues/134205 + notDisposedAllowList: <String, int?> {'_RestorableRouteInformation': 1}, + )); } typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation); diff --git a/packages/flutter/test/widgets/routes_test.dart b/packages/flutter/test/widgets/routes_test.dart index f695ecdd2404f..ebc47b1fc57af 100644 --- a/packages/flutter/test/widgets/routes_test.dart +++ b/packages/flutter/test/widgets/routes_test.dart @@ -8,6 +8,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -89,6 +90,9 @@ class TestRoute extends Route<String?> with LocalHistoryRoute<String?> { @override void dispose() { log('dispose'); + for (final OverlayEntry e in _entries) { + e.dispose(); + } _entries.clear(); routes.remove(this); super.dispose(); @@ -113,12 +117,12 @@ Future<void> runNavigatorTest( } void main() { - testWidgets('Route settings', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route settings', (WidgetTester tester) async { const RouteSettings settings = RouteSettings(name: 'A'); expect(settings, hasOneLineDescription); }); - testWidgets('Route settings arguments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route settings arguments', (WidgetTester tester) async { const RouteSettings settings = RouteSettings(name: 'A'); expect(settings.arguments, isNull); @@ -127,7 +131,7 @@ void main() { expect(settings2.arguments, same(arguments)); }); - testWidgets('Route management - push, replace, pop sequence', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route management - push, replace, pop sequence', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget( Directionality( @@ -214,7 +218,7 @@ void main() { results.clear(); }); - testWidgets('Route management - push, remove, pop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route management - push, remove, pop', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget( Directionality( @@ -329,7 +333,7 @@ void main() { results.clear(); }); - testWidgets('Route management - push, replace, popUntil', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route management - push, replace, popUntil', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget( Directionality( @@ -406,7 +410,7 @@ void main() { results.clear(); }); - testWidgets('Route localHistory - popUntil', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Route localHistory - popUntil', (WidgetTester tester) async { final TestRoute routeA = TestRoute('A'); routeA.addLocalHistoryEntry(LocalHistoryEntry( onRemove: () { routeA.log('onRemove 0'); }, @@ -543,7 +547,7 @@ void main() { }); }); - testWidgets('Can autofocus a TextField nested in a Focus in a route.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can autofocus a TextField nested in a Focus in a route.', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(); final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); @@ -573,7 +577,7 @@ void main() { }); group('PageRouteBuilder', () { - testWidgets('reverseTransitionDuration defaults to 300ms', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reverseTransitionDuration defaults to 300ms', (WidgetTester tester) async { // Default PageRouteBuilder reverse transition duration should be 300ms. await tester.pumpWidget( MaterialApp( @@ -624,7 +628,7 @@ void main() { expect(find.text('Open page'), findsOneWidget); }); - testWidgets('reverseTransitionDuration can be customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reverseTransitionDuration can be customized', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( onGenerateRoute: (RouteSettings settings) { return MaterialPageRoute<dynamic>( @@ -676,7 +680,7 @@ void main() { }); group('TransitionRoute', () { - testWidgets('secondary animation is kDismissed when next route finishes pop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('secondary animation is kDismissed when next route finishes pop', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); await tester.pumpWidget( MaterialApp( @@ -734,7 +738,7 @@ void main() { expect(secondaryAnimationPageOne.parent, kAlwaysDismissedAnimation); }); - testWidgets('secondary animation is kDismissed when next route is removed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('secondary animation is kDismissed when next route is removed', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); await tester.pumpWidget( MaterialApp( @@ -789,7 +793,7 @@ void main() { expect(secondaryAnimationPageOne.parent, kAlwaysDismissedAnimation); }); - testWidgets('secondary animation is kDismissed after train hopping finishes and pop', (WidgetTester tester) async { + testWidgetsWithLeakTracking('secondary animation is kDismissed after train hopping finishes and pop', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); await tester.pumpWidget( MaterialApp( @@ -861,7 +865,7 @@ void main() { expect(secondaryAnimationPageOne.parent, kAlwaysDismissedAnimation); }); - testWidgets('secondary animation is kDismissed when train hopping is interrupted', (WidgetTester tester) async { + testWidgetsWithLeakTracking('secondary animation is kDismissed when train hopping is interrupted', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); await tester.pumpWidget( MaterialApp( @@ -930,7 +934,7 @@ void main() { expect(trainHopper2.currentTrain, isNull); // Has been disposed. }); - testWidgets('secondary animation is triggered when pop initial route', (WidgetTester tester) async { + testWidgetsWithLeakTracking('secondary animation is triggered when pop initial route', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); late Animation<double> secondaryAnimationOfRouteOne; late Animation<double> primaryAnimationOfRouteTwo; @@ -968,7 +972,7 @@ void main() { expect(secondaryAnimationOfRouteOne.value, primaryAnimationOfRouteTwo.value); }); - testWidgets('showGeneralDialog handles transparent barrier color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showGeneralDialog handles transparent barrier color', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Builder( builder: (BuildContext context) { @@ -1002,7 +1006,7 @@ void main() { expect(find.byType(ModalBarrier), findsNWidgets(1)); }); - testWidgets('showGeneralDialog adds non-dismissible barrier when barrierDismissible is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showGeneralDialog adds non-dismissible barrier when barrierDismissible is false', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Builder( builder: (BuildContext context) { @@ -1037,7 +1041,7 @@ void main() { expect(find.byType(ModalBarrier), findsNWidgets(1)); }); - testWidgets('showGeneralDialog uses null as a barrierLabel by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showGeneralDialog uses null as a barrierLabel by default', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Builder( builder: (BuildContext context) { @@ -1072,7 +1076,7 @@ void main() { expect(find.byType(ModalBarrier), findsNWidgets(1)); }); - testWidgets('showGeneralDialog uses root navigator by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showGeneralDialog uses root navigator by default', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); final DialogObserver nestedObserver = DialogObserver(); @@ -1108,7 +1112,7 @@ void main() { expect(nestedObserver.dialogCount, 0); }); - testWidgets('showGeneralDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showGeneralDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); final DialogObserver nestedObserver = DialogObserver(); @@ -1145,7 +1149,7 @@ void main() { expect(nestedObserver.dialogCount, 1); }); - testWidgets('showGeneralDialog default argument values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showGeneralDialog default argument values', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); await tester.pumpWidget(MaterialApp( @@ -1181,7 +1185,7 @@ void main() { }); group('showGeneralDialog avoids overlapping display features', () { - testWidgets('positioning with anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with anchorPoint', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1219,7 +1223,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('positioning with Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with Directionality', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1259,7 +1263,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('positioning by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning by default', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( builder: (BuildContext context, Widget? child) { @@ -1297,7 +1301,7 @@ void main() { }); }); - testWidgets('reverseTransitionDuration defaults to transitionDuration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reverseTransitionDuration defaults to transitionDuration', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); // Default MaterialPageRoute transition duration should be 300ms. @@ -1349,7 +1353,7 @@ void main() { expect(find.byKey(containerKey), findsNothing); }); - testWidgets('reverseTransitionDuration can be customized', (WidgetTester tester) async { + testWidgetsWithLeakTracking('reverseTransitionDuration can be customized', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); await tester.pumpWidget(MaterialApp( onGenerateRoute: (RouteSettings settings) { @@ -1401,7 +1405,7 @@ void main() { expect(find.byKey(containerKey), findsNothing); }); - testWidgets('custom reverseTransitionDuration does not result in interrupted animations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('custom reverseTransitionDuration does not result in interrupted animations', (WidgetTester tester) async { final GlobalKey containerKey = GlobalKey(); await tester.pumpWidget(MaterialApp( theme: ThemeData( @@ -1469,7 +1473,7 @@ void main() { }); group('ModalRoute', () { - testWidgets('default barrierCurve', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default barrierCurve', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Builder( @@ -1531,7 +1535,7 @@ void main() { expect(modalBarrierAnimation.value, Colors.black); }); - testWidgets('custom barrierCurve', (WidgetTester tester) async { + testWidgetsWithLeakTracking('custom barrierCurve', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Builder( @@ -1594,7 +1598,7 @@ void main() { expect(modalBarrierAnimation.value, Colors.black); }); - testWidgets('white barrierColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('white barrierColor', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: Material( child: Builder( @@ -1657,7 +1661,7 @@ void main() { expect(modalBarrierAnimation.value, Colors.white); }); - testWidgets('modal route semantics order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('modal route semantics order', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46625. final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -1730,7 +1734,7 @@ void main() { semantics.dispose(); }, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.iOS})); - testWidgets('focus traverse correct when pop multiple page simultaneously', (WidgetTester tester) async { + testWidgetsWithLeakTracking('focus traverse correct when pop multiple page simultaneously', (WidgetTester tester) async { // Regression test: https://github.com/flutter/flutter/issues/48903 final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget(MaterialApp( @@ -1776,7 +1780,7 @@ void main() { expect(focusNodeOnPageOne.hasFocus, isTrue); }); - testWidgets('focus traversal is correct when popping multiple pages simultaneously - with focused children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('focus traversal is correct when popping multiple pages simultaneously - with focused children', (WidgetTester tester) async { // Regression test: https://github.com/flutter/flutter/issues/48903 final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget(MaterialApp( @@ -1828,7 +1832,7 @@ void main() { expect(focusNodeOnPageOne.hasFocus, isTrue); }); - testWidgets('child with local history can be disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child with local history can be disposed', (WidgetTester tester) async { // Regression test: https://github.com/flutter/flutter/issues/52478 await tester.pumpWidget(const MaterialApp( home: WidgetWithLocalHistory(), @@ -1849,7 +1853,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('child with no local history can be disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child with no local history can be disposed', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: WidgetWithNoLocalHistory(), )); @@ -1869,7 +1873,7 @@ void main() { }); }); - testWidgets('can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can be dismissed with escape keyboard shortcut', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget(MaterialApp( navigatorKey: navigatorKey, @@ -1891,7 +1895,7 @@ void main() { expect(find.text('dialog1'), findsNothing); }); - testWidgets('can not be dismissed with escape keyboard shortcut if barrier not dismissible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can not be dismissed with escape keyboard shortcut if barrier not dismissible', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget(MaterialApp( navigatorKey: navigatorKey, @@ -1914,7 +1918,7 @@ void main() { expect(find.text('dialog1'), findsOneWidget); }); - testWidgets('ModalRoute.of works for void routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ModalRoute.of works for void routes', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); await tester.pumpWidget(MaterialApp( navigatorKey: navigatorKey, @@ -1936,7 +1940,7 @@ void main() { expect(parentRoute, isA<MaterialPageRoute<void>>()); }); - testWidgets('RawDialogRoute is state restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawDialogRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( restorationScopeId: 'app', diff --git a/packages/flutter/test/widgets/row_test.dart b/packages/flutter/test/widgets/row_test.dart index 884dfbf288b37..da7ee24981e8b 100644 --- a/packages/flutter/test/widgets/row_test.dart +++ b/packages/flutter/test/widgets/row_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class OrderPainter extends CustomPainter { const OrderPainter(this.index); @@ -28,7 +29,7 @@ Widget log(int index) => CustomPaint(painter: OrderPainter(index)); void main() { // NO DIRECTION - testWidgets('Row with one Flexible child - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with one Flexible child - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -59,7 +60,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row with default main axis parameters - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with default main axis parameters - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -90,7 +91,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row with MainAxisAlignment.center - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.center - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -120,7 +121,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row with MainAxisAlignment.end - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.end - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -152,7 +153,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row with MainAxisAlignment.spaceBetween - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceBetween - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -184,7 +185,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row with MainAxisAlignment.spaceAround - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceAround - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -218,7 +219,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row with MainAxisAlignment.spaceEvenly - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceEvenly - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -250,7 +251,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row and MainAxisSize.min - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row and MainAxisSize.min - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('rowKey'); const Key child0Key = Key('child0'); @@ -280,7 +281,7 @@ void main() { expect(OrderPainter.log, <int>[]); }); - testWidgets('Row MainAxisSize.min layout at zero size - no textDirection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row MainAxisSize.min layout at zero size - no textDirection', (WidgetTester tester) async { OrderPainter.log.clear(); const Key childKey = Key('childKey'); @@ -308,7 +309,7 @@ void main() { // LTR - testWidgets('Row with one Flexible child - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with one Flexible child - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -358,7 +359,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with default main axis parameters - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with default main axis parameters - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -408,7 +409,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with MainAxisAlignment.center - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.center - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -450,7 +451,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2]); }); - testWidgets('Row with MainAxisAlignment.end - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.end - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -500,7 +501,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with MainAxisAlignment.spaceBetween - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceBetween - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -550,7 +551,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with MainAxisAlignment.spaceAround - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceAround - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -608,7 +609,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3, 4]); }); - testWidgets('Row with MainAxisAlignment.spaceEvenly - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceEvenly - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -658,7 +659,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row and MainAxisSize.min - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row and MainAxisSize.min - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('rowKey'); const Key child0Key = Key('child0'); @@ -700,7 +701,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2]); }); - testWidgets('Row MainAxisSize.min layout at zero size - LTR', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row MainAxisSize.min layout at zero size - LTR', (WidgetTester tester) async { OrderPainter.log.clear(); const Key childKey = Key('childKey'); @@ -729,7 +730,7 @@ void main() { // RTL - testWidgets('Row with one Flexible child - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with one Flexible child - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -779,7 +780,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with default main axis parameters - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with default main axis parameters - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -829,7 +830,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with MainAxisAlignment.center - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.center - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -871,7 +872,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2]); }); - testWidgets('Row with MainAxisAlignment.end - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.end - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -921,7 +922,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with MainAxisAlignment.spaceBetween - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceBetween - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -971,7 +972,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row with MainAxisAlignment.spaceAround - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceAround - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -1029,7 +1030,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3, 4]); }); - testWidgets('Row with MainAxisAlignment.spaceEvenly - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row with MainAxisAlignment.spaceEvenly - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('row'); const Key child0Key = Key('child0'); @@ -1079,7 +1080,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2, 3]); }); - testWidgets('Row and MainAxisSize.min - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row and MainAxisSize.min - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key rowKey = Key('rowKey'); const Key child0Key = Key('child0'); @@ -1121,7 +1122,7 @@ void main() { expect(OrderPainter.log, <int>[1, 2]); }); - testWidgets('Row MainAxisSize.min layout at zero size - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Row MainAxisSize.min layout at zero size - RTL', (WidgetTester tester) async { OrderPainter.log.clear(); const Key childKey = Key('childKey'); diff --git a/packages/flutter/test/widgets/rtl_test.dart b/packages/flutter/test/widgets/rtl_test.dart index 077be41cc2644..810adc2d2ba59 100644 --- a/packages/flutter/test/widgets/rtl_test.dart +++ b/packages/flutter/test/widgets/rtl_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Padding RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding RTL', (WidgetTester tester) async { const Widget child = Padding( padding: EdgeInsetsDirectional.only(start: 10.0), child: Placeholder(), @@ -43,7 +44,7 @@ void main() { ); }); - testWidgets('Container padding/margin RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Container padding/margin RTL', (WidgetTester tester) async { final Widget child = Container( padding: const EdgeInsetsDirectional.only(start: 6.0), margin: const EdgeInsetsDirectional.only(end: 20.0, start: 4.0), @@ -63,7 +64,7 @@ void main() { expect(tester.getTopRight(find.byType(Placeholder)), const Offset(790.0, 0.0)); }); - testWidgets('Container padding/margin mixed RTL/absolute', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Container padding/margin mixed RTL/absolute', (WidgetTester tester) async { final Widget child = Container( padding: const EdgeInsets.only(left: 6.0), margin: const EdgeInsetsDirectional.only(end: 20.0, start: 4.0), @@ -83,7 +84,7 @@ void main() { expect(tester.getTopRight(find.byType(Placeholder)), const Offset(796.0, 0.0)); }); - testWidgets('EdgeInsetsDirectional without Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('EdgeInsetsDirectional without Directionality', (WidgetTester tester) async { await tester.pumpWidget(const Padding(padding: EdgeInsetsDirectional.zero)); expect(tester.takeException(), isAssertionError); }); diff --git a/packages/flutter/test/widgets/run_app_test.dart b/packages/flutter/test/widgets/run_app_test.dart index 49c035999a1e4..d48a75f7991c9 100644 --- a/packages/flutter/test/widgets/run_app_test.dart +++ b/packages/flutter/test/widgets/run_app_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('runApp inside onPressed does not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('runApp inside onPressed does not throw', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/safe_area_test.dart b/packages/flutter/test/widgets/safe_area_test.dart index 2960351456eb0..afe4c41b29001 100644 --- a/packages/flutter/test/widgets/safe_area_test.dart +++ b/packages/flutter/test/widgets/safe_area_test.dart @@ -5,10 +5,11 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { group('SafeArea', () { - testWidgets('SafeArea - basic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea - basic', (WidgetTester tester) async { await tester.pumpWidget( const MediaQuery( data: MediaQueryData(padding: EdgeInsets.all(20.0)), @@ -22,7 +23,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0)); }); - testWidgets('SafeArea - with minimums', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea - with minimums', (WidgetTester tester) async { await tester.pumpWidget( const MediaQuery( data: MediaQueryData(padding: EdgeInsets.all(20.0)), @@ -37,7 +38,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 570.0)); }); - testWidgets('SafeArea - nested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea - nested', (WidgetTester tester) async { await tester.pumpWidget( const MediaQuery( data: MediaQueryData(padding: EdgeInsets.all(20.0)), @@ -54,7 +55,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0)); }); - testWidgets('SafeArea - changing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea - changing', (WidgetTester tester) async { const Widget child = SafeArea( bottom: false, child: SafeArea( @@ -85,7 +86,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('SafeArea - properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea - properties', (WidgetTester tester) async { final SafeArea child = SafeArea( right: false, bottom: false, @@ -112,7 +113,7 @@ void main() { ); } - testWidgets('SafeArea alone.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea alone.', (WidgetTester tester) async { final Widget child = boilerplate(const SafeArea( maintainBottomViewPadding: true, child: Column( @@ -147,7 +148,7 @@ void main() { expect(initialPoint, finalPoint); }); - testWidgets('SafeArea alone - partial ViewInsets consume Padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea alone - partial ViewInsets consume Padding', (WidgetTester tester) async { final Widget child = boilerplate(const SafeArea( maintainBottomViewPadding: true, child: Column( @@ -180,7 +181,7 @@ void main() { expect(initialPoint, finalPoint); }); - testWidgets('SafeArea with nested Scaffold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea with nested Scaffold', (WidgetTester tester) async { final Widget child = boilerplate(const SafeArea( maintainBottomViewPadding: true, child: Scaffold( @@ -218,7 +219,7 @@ void main() { expect(initialPoint, finalPoint); }); - testWidgets('SafeArea with nested Scaffold - partial ViewInsets consume Padding', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SafeArea with nested Scaffold - partial ViewInsets consume Padding', (WidgetTester tester) async { final Widget child = boilerplate(const SafeArea( maintainBottomViewPadding: true, child: Scaffold( @@ -258,12 +259,15 @@ void main() { group('SliverSafeArea', () { Widget buildWidget(EdgeInsets mediaPadding, Widget sliver) { + late final ViewportOffset offset; + addTearDown(() => offset.dispose()); + return MediaQuery( data: MediaQueryData(padding: mediaPadding), child: Directionality( textDirection: TextDirection.ltr, child: Viewport( - offset: ViewportOffset.fixed(0.0), + offset: offset = ViewportOffset.fixed(0.0), slivers: <Widget>[ const SliverToBoxAdapter(child: SizedBox(width: 800.0, height: 100.0, child: Text('before'))), sliver, @@ -285,7 +289,7 @@ void main() { expect(testAnswers, equals(expectedRects)); } - testWidgets('SliverSafeArea - basic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverSafeArea - basic', (WidgetTester tester) async { await tester.pumpWidget( buildWidget( const EdgeInsets.all(20.0), @@ -302,7 +306,7 @@ void main() { ]); }); - testWidgets('SliverSafeArea - basic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverSafeArea - basic', (WidgetTester tester) async { await tester.pumpWidget( buildWidget( const EdgeInsets.all(20.0), @@ -320,7 +324,7 @@ void main() { ]); }); - testWidgets('SliverSafeArea - nested', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverSafeArea - nested', (WidgetTester tester) async { await tester.pumpWidget( buildWidget( const EdgeInsets.all(20.0), @@ -340,7 +344,7 @@ void main() { ]); }); - testWidgets('SliverSafeArea - changing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverSafeArea - changing', (WidgetTester tester) async { const Widget sliver = SliverSafeArea( bottom: false, sliver: SliverSafeArea( @@ -379,7 +383,7 @@ void main() { }); }); - testWidgets('SliverSafeArea - properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverSafeArea - properties', (WidgetTester tester) async { const SliverSafeArea child = SliverSafeArea( right: false, bottom: false, diff --git a/packages/flutter/test/widgets/scroll_activity_test.dart b/packages/flutter/test/widgets/scroll_activity_test.dart index f6dd3235d0f9e..824c12105c809 100644 --- a/packages/flutter/test/widgets/scroll_activity_test.dart +++ b/packages/flutter/test/widgets/scroll_activity_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; List<Widget> children(int n) { return List<Widget>.generate(n, (int i) { @@ -14,8 +15,9 @@ List<Widget> children(int n) { } void main() { - testWidgets('Scrolling with list view changes, leaving the overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolling with list view changes, leaving the overscroll', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30)))); final double thirty = controller.position.maxScrollExtent; controller.jumpTo(thirty); @@ -28,8 +30,9 @@ void main() { expect(controller.position.pixels, thirty + 100.0); // and ends up at the end }); - testWidgets('Scrolling with list view changes, remaining overscrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolling with list view changes, remaining overscrolled', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(MaterialApp(home: ListView(controller: controller, children: children(30)))); final double thirty = controller.position.maxScrollExtent; controller.jumpTo(thirty); @@ -42,7 +45,7 @@ void main() { expect(controller.position.pixels, thirty + 100.0); // and ends up at the end }); - testWidgets('Ability to keep a PageView at the end manually (issue 62209)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ability to keep a PageView at the end manually (issue 62209)', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp(home: PageView62209())); expect(find.text('Page 1'), findsOneWidget); expect(find.text('Page 100'), findsNothing); @@ -129,8 +132,9 @@ void main() { expect(find.text('Page 9'), findsOneWidget); }); - testWidgets('Pointer is not ignored during trackpad scrolling.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Pointer is not ignored during trackpad scrolling.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); int? lastTapped; int? lastHovered; await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart b/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart index 51fa9d85ef70e..8dcba52ef928e 100644 --- a/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart +++ b/packages/flutter/test/widgets/scroll_aware_image_provider_test.dart @@ -6,6 +6,7 @@ import 'dart:ui' as ui show Image; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../painting/image_test_utils.dart'; @@ -17,6 +18,10 @@ void main() { testImage = await createTestImage(width: 10, height: 10); }); + tearDownAll(() { + testImage.dispose(); + }); + tearDown(() { imageCache.clear(); }); @@ -29,7 +34,7 @@ void main() { return Scrollable.of(find.byType(TestWidget).evaluate().first).position; } - testWidgets('ScrollAwareImageProvider does not delay if widget is not in scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider does not delay if widget is not in scrollable', (WidgetTester tester) async { final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); await tester.pumpWidget(TestWidget(key)); @@ -56,7 +61,7 @@ void main() { expect(imageCache.currentSize, 1); }); - testWidgets('ScrollAwareImageProvider does not delay if in scrollable that is not scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider does not delay if in scrollable that is not scrolling', (WidgetTester tester) async { final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -92,9 +97,10 @@ void main() { expect(findPhysics<RecordingPhysics>(tester).velocities, <double>[0]); }); - testWidgets('ScrollAwareImageProvider does not delay if in scrollable that is scrolling slowly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider does not delay if in scrollable that is scrolling slowly', (WidgetTester tester) async { final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[]; final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( @@ -149,9 +155,10 @@ void main() { expect(imageCache.currentSize, 1); }); - testWidgets('ScrollAwareImageProvider delays if in scrollable that is scrolling fast', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider delays if in scrollable that is scrolling fast', (WidgetTester tester) async { final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[]; final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( @@ -216,9 +223,10 @@ void main() { expect(imageCache.currentSize, 1); }); - testWidgets('ScrollAwareImageProvider delays if in scrollable that is scrolling fast and fizzles if disposed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider delays if in scrollable that is scrolling fast and fizzles if disposed', (WidgetTester tester) async { final List<GlobalKey<TestWidgetState>> keys = <GlobalKey<TestWidgetState>>[]; final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: ListView.builder( @@ -285,9 +293,10 @@ void main() { expect(imageCache.currentSize, 0); }); - testWidgets('ScrollAwareImageProvider resolves from ImageCache and does not set completer twice', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider resolves from ImageCache and does not set completer twice', (WidgetTester tester) async { final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: SingleChildScrollView( @@ -333,12 +342,13 @@ void main() { expect(stream.completer, null); }); - testWidgets('ScrollAwareImageProvider does not block LRU updates to image cache', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollAwareImageProvider does not block LRU updates to image cache', (WidgetTester tester) async { final int oldSize = imageCache.maximumSize; imageCache.maximumSize = 1; final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: SingleChildScrollView( diff --git a/packages/flutter/test/widgets/scroll_behavior_test.dart b/packages/flutter/test/widgets/scroll_behavior_test.dart index 1d075e05ede62..087f80012ac5a 100644 --- a/packages/flutter/test/widgets/scroll_behavior_test.dart +++ b/packages/flutter/test/widgets/scroll_behavior_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; late GestureVelocityTrackerBuilder lastCreatedBuilder; class TestScrollBehavior extends ScrollBehavior { @@ -33,7 +34,7 @@ class TestScrollBehavior extends ScrollBehavior { } void main() { - testWidgets('Assert in buildScrollbar that controller != null when using it', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Assert in buildScrollbar that controller != null when using it', (WidgetTester tester) async { const ScrollBehavior defaultBehavior = ScrollBehavior(); late BuildContext capturedContext; @@ -75,14 +76,14 @@ void main() { }, variant: TargetPlatformVariant.all()); // Regression test for https://github.com/flutter/flutter/issues/89681 - testWidgets('_WrappedScrollBehavior shouldNotify test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('_WrappedScrollBehavior shouldNotify test', (WidgetTester tester) async { final ScrollBehavior behavior1 = const ScrollBehavior().copyWith(); final ScrollBehavior behavior2 = const ScrollBehavior().copyWith(); expect(behavior1.shouldNotify(behavior2), false); }); - testWidgets('Inherited ScrollConfiguration changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inherited ScrollConfiguration changed', (WidgetTester tester) async { final GlobalKey key = GlobalKey(debugLabel: 'scrollable'); TestScrollBehavior? behavior; late ScrollPositionWithSingleContext position; @@ -131,7 +132,7 @@ void main() { expect(metrics.viewportDimension, equals(600.0)); }); - testWidgets('ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollBehavior default android overscroll indicator', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -155,7 +156,7 @@ void main() { }, variant: TargetPlatformVariant.only(TargetPlatform.android)); group('ScrollBehavior configuration is maintained over multiple copies', () { - testWidgets('dragDevices', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dragDevices', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 const ScrollBehavior defaultBehavior = ScrollBehavior(); expect(defaultBehavior.dragDevices, <PointerDeviceKind>{ @@ -177,7 +178,7 @@ void main() { expect(twiceCopiedBehavior.dragDevices, PointerDeviceKind.values.toSet()); }); - testWidgets('physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('physics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 late ScrollPhysics defaultPhysics; late ScrollPhysics onceCopiedPhysics; @@ -219,7 +220,7 @@ void main() { expect(twiceCopiedPhysics, const BouncingScrollPhysics()); }); - testWidgets('platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('platform', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 late TargetPlatform defaultPlatform; late TargetPlatform onceCopiedPlatform; @@ -276,7 +277,7 @@ void main() { ); } - testWidgets('scrollbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrollbar', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 const ScrollBehavior defaultBehavior = ScrollBehavior(); await tester.pumpWidget(wrap(defaultBehavior)); @@ -296,7 +297,7 @@ void main() { // For default scrollbars }, variant: TargetPlatformVariant.desktop()); - testWidgets('overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overscroll', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/91673 const ScrollBehavior defaultBehavior = ScrollBehavior(); await tester.pumpWidget(wrap(defaultBehavior)); diff --git a/packages/flutter/test/widgets/scroll_controller_test.dart b/packages/flutter/test/widgets/scroll_controller_test.dart index 76a9820470c26..32b8a19f5c7db 100644 --- a/packages/flutter/test/widgets/scroll_controller_test.dart +++ b/packages/flutter/test/widgets/scroll_controller_test.dart @@ -11,8 +11,9 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'states.dart'; void main() { - testWidgets('ScrollController control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollController control test', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -77,6 +78,7 @@ void main() { expect(realOffset(), equals(controller.offset)); final ScrollController controller2 = ScrollController(); + addTearDown(controller2.dispose); await tester.pumpWidget( Directionality( @@ -132,10 +134,11 @@ void main() { expect(realOffset(), equals(controller2.offset)); }); - testWidgets('ScrollController control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollController control test', (WidgetTester tester) async { final ScrollController controller = ScrollController( initialScrollOffset: 209.0, ); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -177,8 +180,9 @@ void main() { expect(realOffset(), equals(controller.offset)); }); - testWidgets('DrivenScrollActivity ending after dispose', (WidgetTester tester) async { + testWidgetsWithLeakTracking('DrivenScrollActivity ending after dispose', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( Directionality( @@ -198,14 +202,17 @@ void main() { await tester.pumpWidget(Container(), const Duration(seconds: 2)); }); - testWidgets('Read operations on ScrollControllers with no positions fail', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Read operations on ScrollControllers with no positions fail', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); expect(() => controller.offset, throwsAssertionError); expect(() => controller.position, throwsAssertionError); }); - testWidgets('Read operations on ScrollControllers with more than one position fail', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Read operations on ScrollControllers with more than one position fail', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -238,14 +245,17 @@ void main() { expect(() => controller.position, throwsAssertionError); }); - testWidgets('Write operations on ScrollControllers with no positions fail', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Write operations on ScrollControllers with no positions fail', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); expect(() => controller.animateTo(1.0, duration: const Duration(seconds: 1), curve: Curves.linear), throwsAssertionError); expect(() => controller.jumpTo(1.0), throwsAssertionError); }); - testWidgets('Write operations on ScrollControllers with more than one position do not throw', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Write operations on ScrollControllers with more than one position do not throw', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -279,7 +289,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('Scroll controllers notify when the position changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll controllers notify when the position changes', (WidgetTester tester) async { final ScrollController controller = ScrollController(); final List<double> log = <double>[]; @@ -313,7 +323,7 @@ void main() { expect(log, isEmpty); }); - testWidgets('keepScrollOffset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keepScrollOffset', (WidgetTester tester) async { final PageStorageBucket bucket = PageStorageBucket(); Widget buildFrame(ScrollController controller) { @@ -341,6 +351,7 @@ void main() { // The initialScrollOffset is used in this case, because there's no saved // scroll offset. ScrollController controller = ScrollController(initialScrollOffset: 200.0); + addTearDown(controller.dispose); await tester.pumpWidget(buildFrame(controller)); expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 2')), Offset.zero); @@ -351,6 +362,7 @@ void main() { // The initialScrollOffset isn't used in this case, because the scrolloffset // can be restored. controller = ScrollController(initialScrollOffset: 25.0); + addTearDown(controller.dispose); await tester.pumpWidget(buildFrame(controller)); expect(controller.offset, 2000.0); expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 20')), Offset.zero); @@ -360,13 +372,14 @@ void main() { // the initialScrollOffset is used. controller = ScrollController(keepScrollOffset: false, initialScrollOffset: 100.0); + addTearDown(controller.dispose); await tester.pumpWidget(buildFrame(controller)); expect(controller.offset, 100.0); expect(tester.getTopLeft(find.widgetWithText(SizedBox, 'Item 1')), Offset.zero); }); - testWidgets('isScrollingNotifier works with pointer scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isScrollingNotifier works with pointer scroll', (WidgetTester tester) async { Widget buildFrame(ScrollController controller) { return Directionality( textDirection: TextDirection.ltr, @@ -381,6 +394,7 @@ void main() { bool isScrolling = false; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); controller.addListener((){ isScrolling = controller.position.isScrollingNotifier.value; }); @@ -396,6 +410,6 @@ void main() { }); test('$ScrollController dispatches object creation in constructor', () { - expect(()=> ScrollController().dispose(), dispatchesMemoryEvents(ScrollController)); + expect(() => ScrollController().dispose(), dispatchesMemoryEvents(ScrollController)); }); } diff --git a/packages/flutter/test/widgets/scroll_events_test.dart b/packages/flutter/test/widgets/scroll_events_test.dart index 397eb5b9524a8..f7087418f63bc 100644 --- a/packages/flutter/test/widgets/scroll_events_test.dart +++ b/packages/flutter/test/widgets/scroll_events_test.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; Widget _buildScroller({ required List<String> log }) { return NotificationListener<ScrollNotification>( @@ -38,7 +39,7 @@ void main() { scrollable.position.jumpTo(newScrollOffset); } - testWidgets('Scroll event drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll event drag', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -57,7 +58,7 @@ void main() { expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end'])); }); - testWidgets('Scroll animateTo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll animateTo', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -74,7 +75,7 @@ void main() { expect(completer.isCompleted, isTrue); }); - testWidgets('Scroll jumpTo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll jumpTo', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -85,7 +86,7 @@ void main() { expect(log, equals(<String>['scroll-start', 'scroll-update', 'scroll-end'])); }); - testWidgets('Scroll jumpTo during animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll jumpTo during animation', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -110,7 +111,7 @@ void main() { expect(completer.isCompleted, isTrue); }); - testWidgets('Scroll scrollTo during animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll scrollTo during animation', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -134,7 +135,7 @@ void main() { expect(completer.isCompleted, isTrue); }); - testWidgets('fling, fling generates two start/end pairs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling, fling generates two start/end pairs', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -157,7 +158,7 @@ void main() { expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end'])); }); - testWidgets('fling, pause, fling generates two start/end pairs', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling, pause, fling generates two start/end pairs', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); @@ -176,7 +177,7 @@ void main() { expect(log, equals(<String>['scroll-start', 'scroll-end', 'scroll-start', 'scroll-end'])); }); - testWidgets('fling up ends', (WidgetTester tester) async { + testWidgetsWithLeakTracking('fling up ends', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(_buildScroller(log: log)); From a96bf714cb46bacf07c1a9cf15242edc117d5cf5 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Wed, 20 Sep 2023 22:29:41 +0200 Subject: [PATCH 1372/1547] Cover cupertino/form_section_test with leak tracing (#135158) --- .../src/cupertino/text_form_field_row.dart | 1 + .../test/cupertino/form_section_test.dart | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_form_field_row.dart b/packages/flutter/lib/src/cupertino/text_form_field_row.dart index ed20b583a5fc0..674c62237ed5d 100644 --- a/packages/flutter/lib/src/cupertino/text_form_field_row.dart +++ b/packages/flutter/lib/src/cupertino/text_form_field_row.dart @@ -313,6 +313,7 @@ class _CupertinoTextFormFieldRowState extends FormFieldState<String> { @override void dispose() { _cupertinoTextFormFieldRow.controller?.removeListener(_handleControllerChanged); + _controller?.dispose(); super.dispose(); } diff --git a/packages/flutter/test/cupertino/form_section_test.dart b/packages/flutter/test/cupertino/form_section_test.dart index 7a9e4f0539b35..da86fb9e898c9 100644 --- a/packages/flutter/test/cupertino/form_section_test.dart +++ b/packages/flutter/test/cupertino/form_section_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Shows header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows header', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -22,7 +23,7 @@ void main() { expect(find.text('Header'), findsOneWidget); }); - testWidgets('Shows footer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows footer', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -37,7 +38,7 @@ void main() { expect(find.text('Footer'), findsOneWidget); }); - testWidgets('Shows long dividers in edge-to-edge section part 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows long dividers in edge-to-edge section part 1', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -54,7 +55,7 @@ void main() { expect(childrenColumn.children.length, 3); }); - testWidgets('Shows long dividers in edge-to-edge section part 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows long dividers in edge-to-edge section part 2', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -75,7 +76,7 @@ void main() { expect(childrenColumn.children.length, 5); }); - testWidgets('Does not show long dividers in insetGrouped section part 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not show long dividers in insetGrouped section part 1', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -93,7 +94,7 @@ void main() { expect(childrenColumn.children.length, 1); }); - testWidgets('Does not show long dividers in insetGrouped section part 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not show long dividers in insetGrouped section part 2', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( restorationScopeId: 'App', @@ -115,7 +116,7 @@ void main() { expect(childrenColumn.children.length, 3); }); - testWidgets('Sets background color for section', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Sets background color for section', (WidgetTester tester) async { const Color backgroundColor = CupertinoColors.systemBlue; await tester.pumpWidget( @@ -138,7 +139,7 @@ void main() { expect(boxDecoration.color, backgroundColor); }); - testWidgets('Setting clipBehavior clips children section', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting clipBehavior clips children section', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -153,7 +154,7 @@ void main() { expect(find.byType(ClipRRect), findsOneWidget); }); - testWidgets('Not setting clipBehavior does not produce a RenderClipRRect object', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Not setting clipBehavior does not produce a RenderClipRRect object', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( From b433b175393af0442754107d5300ff4f35cf2260 Mon Sep 17 00:00:00 2001 From: Gray Mackall <34871572+gmackall@users.noreply.github.com> Date: Wed, 20 Sep 2023 16:56:25 -0400 Subject: [PATCH 1373/1547] Upgrade AGP version in tracing_tests (#134671) Related to https://github.com/flutter/flutter/issues/134419 --- .ci.yaml | 3 ++- dev/tracing_tests/android/build.gradle | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 83d6386af773d..b685889056f5d 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -569,7 +569,8 @@ targets: properties: dependencies: >- [ - {"dependency": "android_sdk", "version": "version:33v6"} + {"dependency": "android_sdk", "version": "version:33v6"}, + {"dependency": "open_jdk", "version": "version:17"} ] shard: framework_tests subshard: slow diff --git a/dev/tracing_tests/android/build.gradle b/dev/tracing_tests/android/build.gradle index 830c81ab1a6fa..68ee66d66c4c1 100644 --- a/dev/tracing_tests/android/build.gradle +++ b/dev/tracing_tests/android/build.gradle @@ -10,7 +10,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } From d6d2e89fc897a9054310fc0372d862c28659787c Mon Sep 17 00:00:00 2001 From: Yegor <yjbanov@google.com> Date: Wed, 20 Sep 2023 15:20:16 -0700 Subject: [PATCH 1374/1547] finer grained logging of Chromium launch sequence (#135078) Log the details of how Chromium is about to be launched prior to running the Chromium command, as well as the path to the Chromium executable. This should improve our understanding of what's happening here: https://github.com/flutter/flutter/issues/132654#issuecomment-1726630123 --- .../flutter_tools/lib/src/web/chrome.dart | 17 +++- .../test/web.shard/chrome_test.dart | 88 ++++++++++++++----- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 22068d5e3ebde..3d2ed0be9b50b 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -171,14 +171,23 @@ class ChromiumLauncher { throwToolExit('Only one instance of chrome can be started.'); } + if (_logger.isVerbose) { + _logger.printTrace('Launching Chromium (url = $url, headless = $headless, skipCheck = $skipCheck, debugPort = $debugPort)'); + } + final String chromeExecutable = _browserFinder(_platform, _fileSystem); - if (_logger.isVerbose && !_platform.isWindows) { - // The "--version" argument is not supported on Windows. - final ProcessResult versionResult = await _processManager.run(<String>[chromeExecutable, '--version']); - _logger.printTrace('Using ${versionResult.stdout}'); + if (_logger.isVerbose) { + _logger.printTrace('Will use Chromium executable at $chromeExecutable'); + + if (!_platform.isWindows) { + // The "--version" argument is not supported on Windows. + final ProcessResult versionResult = await _processManager.run(<String>[chromeExecutable, '--version']); + _logger.printTrace('Using ${versionResult.stdout}'); + } } + final Directory userDataDir = _fileSystem.systemTempDirectory .createTempSync('flutter_tools_chrome_device.'); diff --git a/packages/flutter_tools/test/web.shard/chrome_test.dart b/packages/flutter_tools/test/web.shard/chrome_test.dart index dacc69eceddc5..0c6c1ea4f0b2a 100644 --- a/packages/flutter_tools/test/web.shard/chrome_test.dart +++ b/packages/flutter_tools/test/web.shard/chrome_test.dart @@ -44,6 +44,7 @@ void main() { late Platform platform; late FakeProcessManager processManager; late OperatingSystemUtils operatingSystemUtils; + late BufferLogger testLogger; setUp(() { exceptionHandler = FileExceptionHandler(); @@ -59,13 +60,41 @@ void main() { processManager: processManager, operatingSystemUtils: operatingSystemUtils, browserFinder: findChromeExecutable, - logger: BufferLogger.test(), + logger: testLogger = BufferLogger.test(), ); }); + Future<Chromium> testLaunchChrome(String userDataDir, FakeProcessManager processManager, ChromiumLauncher chromeLauncher) { + if (testLogger.isVerbose) { + processManager.addCommand(const FakeCommand( + command: <String>[ + 'example_chrome', + '--version', + ], + stdout: 'Chromium 115', + )); + } + + processManager.addCommand(FakeCommand( + command: <String>[ + 'example_chrome', + '--user-data-dir=$userDataDir', + '--remote-debugging-port=12345', + ...kChromeArgs, + 'example_url', + ], + stderr: kDevtoolsStderr, + )); + + return chromeLauncher.launch( + 'example_url', + skipCheck: true, + ); + } + testWithoutContext('can launch chrome and connect to the devtools', () async { await expectReturnsNormallyLater( - _testLaunchChrome( + testLaunchChrome( '/.tmp_rand0/flutter_tools_chrome_device.rand0', processManager, chromeLauncher, @@ -73,15 +102,44 @@ void main() { ); }); + testWithoutContext('can launch chrome in verbose mode', () async { + chromeLauncher = ChromiumLauncher( + fileSystem: fileSystem, + platform: platform, + processManager: processManager, + operatingSystemUtils: operatingSystemUtils, + browserFinder: findChromeExecutable, + logger: testLogger = BufferLogger.test(verbose: true), + ); + + await expectReturnsNormallyLater( + testLaunchChrome( + '/.tmp_rand0/flutter_tools_chrome_device.rand0', + processManager, + chromeLauncher, + ) + ); + + expect( + testLogger.traceText.trim(), + 'Launching Chromium (url = example_url, headless = false, skipCheck = true, debugPort = null)\n' + 'Will use Chromium executable at example_chrome\n' + 'Using Chromium 115\n' + '[CHROME]: \n' + '[CHROME]: \n' + '[CHROME]: DevTools listening', + ); + }); + testWithoutContext('cannot have two concurrent instances of chrome', () async { - await _testLaunchChrome( + await testLaunchChrome( '/.tmp_rand0/flutter_tools_chrome_device.rand0', processManager, chromeLauncher, ); await expectToolExitLater( - _testLaunchChrome( + testLaunchChrome( '/.tmp_rand0/flutter_tools_chrome_device.rand1', processManager, chromeLauncher, @@ -91,7 +149,7 @@ void main() { }); testWithoutContext('can launch new chrome after stopping a previous chrome', () async { - final Chromium chrome = await _testLaunchChrome( + final Chromium chrome = await testLaunchChrome( '/.tmp_rand0/flutter_tools_chrome_device.rand0', processManager, chromeLauncher, @@ -99,7 +157,7 @@ void main() { await chrome.close(); await expectReturnsNormallyLater( - _testLaunchChrome( + testLaunchChrome( '/.tmp_rand0/flutter_tools_chrome_device.rand1', processManager, chromeLauncher, @@ -630,24 +688,6 @@ void main() { }); } -Future<Chromium> _testLaunchChrome(String userDataDir, FakeProcessManager processManager, ChromiumLauncher chromeLauncher) { - processManager.addCommand(FakeCommand( - command: <String>[ - 'example_chrome', - '--user-data-dir=$userDataDir', - '--remote-debugging-port=12345', - ...kChromeArgs, - 'example_url', - ], - stderr: kDevtoolsStderr, - )); - - return chromeLauncher.launch( - 'example_url', - skipCheck: true, - ); -} - /// Fake chrome connection that fails to get tabs a few times. class FakeChromeConnection extends Fake implements ChromeConnection { From a4bc89461695317e6463ce146d10f06b92621a27 Mon Sep 17 00:00:00 2001 From: David Iglesias <ditman@gmail.com> Date: Wed, 20 Sep 2023 15:55:52 -0700 Subject: [PATCH 1375/1547] [deps] Update package:web dependency. (#135174) This PR is the result of running: ```console $ flutter upgrade-packages --force-upgrade ``` ### Issues * Fixes https://github.com/flutter/flutter/issues/135075 * Supersedes #135081 --- dev/a11y_assessments/pubspec.yaml | 4 ++-- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/complex_layout/pubspec.yaml | 4 ++-- dev/benchmarks/macrobenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/microbenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 6 +++--- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_views_layout/pubspec.yaml | 4 ++-- .../platform_views_layout_hybrid_composition/pubspec.yaml | 4 ++-- dev/benchmarks/test_apps/stocks/pubspec.yaml | 4 ++-- dev/bots/pubspec.yaml | 4 ++-- dev/devicelab/pubspec.yaml | 4 ++-- .../abstract_method_smoke_test/pubspec.yaml | 4 ++-- .../android_embedding_v2_smoke_test/pubspec.yaml | 4 ++-- .../android_semantics_testing/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 6 +++--- dev/integration_tests/channels/pubspec.yaml | 4 ++-- dev/integration_tests/deferred_components_test/pubspec.yaml | 4 ++-- dev/integration_tests/external_ui/pubspec.yaml | 4 ++-- dev/integration_tests/flavors/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- .../gradle_deprecated_settings/pubspec.yaml | 6 +++--- dev/integration_tests/hybrid_android_views/pubspec.yaml | 6 +++--- .../ios_add2app_life_cycle/flutterapp/pubspec.yaml | 4 ++-- dev/integration_tests/ios_app_with_extensions/pubspec.yaml | 4 ++-- dev/integration_tests/ios_platform_view_tests/pubspec.yaml | 4 ++-- dev/integration_tests/non_nullable/pubspec.yaml | 4 ++-- dev/integration_tests/platform_interaction/pubspec.yaml | 4 ++-- dev/integration_tests/release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 4 ++-- dev/integration_tests/web/pubspec.yaml | 4 ++-- dev/integration_tests/web_compile_tests/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- dev/integration_tests/windows_startup_test/pubspec.yaml | 4 ++-- dev/manual_tests/pubspec.yaml | 4 ++-- dev/tools/vitool/pubspec.yaml | 4 ++-- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 4 ++-- examples/flutter_view/pubspec.yaml | 4 ++-- examples/hello_world/pubspec.yaml | 4 ++-- examples/image_list/pubspec.yaml | 4 ++-- examples/layers/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 4 ++-- examples/platform_channel_swift/pubspec.yaml | 4 ++-- examples/platform_view/pubspec.yaml | 4 ++-- examples/splash/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 4 ++-- packages/flutter/pubspec.yaml | 4 ++-- packages/flutter/test_private/test/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_goldens/pubspec.yaml | 4 ++-- packages/flutter_localizations/pubspec.yaml | 4 ++-- packages/flutter_test/pubspec.yaml | 4 ++-- packages/flutter_tools/pubspec.yaml | 4 ++-- packages/flutter_web_plugins/pubspec.yaml | 4 ++-- packages/integration_test/example/pubspec.yaml | 4 ++-- .../integration_test/integration_test_macos/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 60 files changed, 124 insertions(+), 124 deletions(-) diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml index 066d34ee57f7f..f87fd7b36e892 100644 --- a/dev/a11y_assessments/pubspec.yaml +++ b/dev/a11y_assessments/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -35,4 +35,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1e6b +# PUBSPEC CHECKSUM: 0c69 diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index c2344ee156556..e9cac0aa1de43 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: a37d +# PUBSPEC CHECKSUM: 7c7b diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 04f16921cc9a2..9c768c180f9d0 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -83,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 4654 +# PUBSPEC CHECKSUM: de52 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 640e44725ab9e..6d17bc023a845 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # flutter update-packages --force-upgrade flutter_gallery_assets: 1.0.2 - web: 0.1.4-beta + web: 0.2.1-beta async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -210,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: 4654 +# PUBSPEC CHECKSUM: de52 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 10ae4b2fcd256..75dee25045c26 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -137,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 46cb +# PUBSPEC CHECKSUM: 1fc9 diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index 9da448d2581e9..afb1401267411 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -36,8 +36,8 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 90fc +# PUBSPEC CHECKSUM: 23fb diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index f132da5b869c0..e795850a56429 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3cb7 +# PUBSPEC CHECKSUM: 15b5 diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index 4cedf138c5976..b2fed493c9570 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 4654 +# PUBSPEC CHECKSUM: de52 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index c6919442ba8c4..7da9277564103 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: 4654 +# PUBSPEC CHECKSUM: de52 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index 66b2524056d27..ac0731a83c091 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3376 +# PUBSPEC CHECKSUM: cb74 diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index 203c8782fa936..a81f4bd8512fd 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -65,7 +65,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xml: 6.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: d5ce +# PUBSPEC CHECKSUM: 86cc diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index 09083ee59f5fb..a3ca142e8fd5e 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: shelf_static: 1.1.2 stack_trace: 1.11.1 vm_service: 11.10.0 - web: 0.1.4-beta + web: 0.2.1-beta webkit_inspection_protocol: 1.2.1 xml: 6.4.2 @@ -72,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 163c +# PUBSPEC CHECKSUM: c63a diff --git a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml index 243ee9149538c..3dd766b495c37 100644 --- a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml +++ b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml @@ -15,9 +15,9 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1ce6 +# PUBSPEC CHECKSUM: 0ae4 diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index 47823636f5174..db54176660212 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -96,4 +96,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 2240 +# PUBSPEC CHECKSUM: 103e diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 9f11efaf13a91..672ac5a2c26ea 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -58,7 +58,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ca74 +# PUBSPEC CHECKSUM: a372 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index bc5393790f8b8..16e4bb7ac4f7d 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -46,9 +46,9 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -92,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 5bb1 +# PUBSPEC CHECKSUM: aeb0 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index 3541ec8be7c21..cc9c8a637bc84 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -43,4 +43,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 3886 +# PUBSPEC CHECKSUM: e584 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index 9161c6cfa7c53..d6eb5693b0e49 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -80,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index 6c61163b1a733..a6a5107e46531 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 53fc +# PUBSPEC CHECKSUM: ebfa diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index 27516a59cf3e8..c67b1791e4d41 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -58,7 +58,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 55bbdf203f514..1fc8421f36c5a 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -49,7 +49,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_platform_interface: 5.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_web: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: 656d +# PUBSPEC CHECKSUM: fd6b diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 4d490f1bd833b..ffabcfd441507 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_android: 0.10.8+9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_avfoundation: 0.9.13+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_avfoundation: 0.9.13+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.2+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" characters: 1.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -34,9 +34,9 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ac38 +# PUBSPEC CHECKSUM: 0937 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index ba5fc8b5930a6..c471c69ebcb92 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -44,9 +44,9 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - win32: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + win32: 5.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 5bb1 +# PUBSPEC CHECKSUM: aeb0 diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index d69d5d2e79676..f1fbc13f76144 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -99,4 +99,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: 5314 +# PUBSPEC CHECKSUM: 4112 diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index a822bde851b20..94a23a2b992a7 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -91,4 +91,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 969a +# PUBSPEC CHECKSUM: 8498 diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index b4cb2793ac27d..19fd1544729ca 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -77,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index be9b6e89abe95..9d9ff91c3c002 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -39,4 +39,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 5314 +# PUBSPEC CHECKSUM: 4112 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 8c8ccb30b829f..303ccd4b08b5e 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 53fc +# PUBSPEC CHECKSUM: ebfa diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 58110c605b538..5e7915978095f 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 594d +# PUBSPEC CHECKSUM: 474b diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index e7369ca35bbf0..e12b8bb8255eb 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 97f5 +# PUBSPEC CHECKSUM: 85f3 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 3b5e905a944db..27ceab81fa333 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -57,7 +57,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index d386e66d9cf6b..55d8197a797e1 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -19,6 +19,6 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1ce6 +# PUBSPEC CHECKSUM: 0ae4 diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index a62e79a88ac0d..10c74337b573f 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -11,6 +11,6 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1ce6 +# PUBSPEC CHECKSUM: 0ae4 diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index 1ccd57d92125d..a8fdd163c0366 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -84,4 +84,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 84a0 +# PUBSPEC CHECKSUM: 1d9e diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index 8ba51de49d7ac..b86f9c131a842 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -41,4 +41,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 594d +# PUBSPEC CHECKSUM: 474b diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 74fa742aa3c54..2cfd559220870 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -56,10 +56,10 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 53fc +# PUBSPEC CHECKSUM: ebfa diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 25c005d20ccb1..8c3a81f6230e8 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 1e6b +# PUBSPEC CHECKSUM: 0c69 diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 7187ed5184deb..2c3b726e05933 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -37,4 +37,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 7915 +# PUBSPEC CHECKSUM: 3f13 diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 1a5404ab382ee..9fa6a4e0af07d 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 594d +# PUBSPEC CHECKSUM: 474b diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index b4a107138b1e1..42a25c17013b8 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 91a5 +# PUBSPEC CHECKSUM: 2aa3 diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index acfd7e7217ae8..ce118d5f8fd8b 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -13,11 +13,11 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 1ce6 +# PUBSPEC CHECKSUM: 0ae4 diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 906174575b076..1c4bdbd16f182 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: @@ -68,4 +68,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index d59ff492fc5a9..9e5f4dab6d65a 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -54,4 +54,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: 5314 +# PUBSPEC CHECKSUM: 4112 diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index 6d678bcaab518..d82f2d649cd5e 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -36,4 +36,4 @@ flutter: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: 1e6b +# PUBSPEC CHECKSUM: 0c69 diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 7d9eb3c0233c2..8081c270ef527 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 6e9b295877fa9..34a5a2bbc5200 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 07b9 +# PUBSPEC CHECKSUM: 9fb7 diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index c4df76cc6ac8e..1f512b1561296 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -20,4 +20,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 1ce6 +# PUBSPEC CHECKSUM: 0ae4 diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index 7679969b28e96..f87573007a315 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -31,4 +31,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1e6b +# PUBSPEC CHECKSUM: 0c69 diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 474b8aa35806c..726bfb44501dd 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -64,4 +64,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ca74 +# PUBSPEC CHECKSUM: a372 diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index f6a7f8b95660b..9ec08024811ce 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 meta: 1.10.0 vector_math: 2.1.4 - web: 0.1.4-beta + web: 0.2.1-beta sky_engine: sdk: flutter @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 8694 +# PUBSPEC CHECKSUM: 5f92 diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 6006fd9f1dc0a..19b76362958a8 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_goldens: @@ -39,4 +39,4 @@ dev_dependencies: platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ca68 +# PUBSPEC CHECKSUM: b866 diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index fcca59407fd59..77abc24a0659b 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: fake_async: 1.3.1 @@ -72,4 +72,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 22c2 +# PUBSPEC CHECKSUM: bac0 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index da9f2a0df08de..ad7f98079dc1c 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -34,6 +34,6 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 4cc9 +# PUBSPEC CHECKSUM: 3ac7 diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index c512a2b6b9ebb..50fb8f06bbc48 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 47a5 +# PUBSPEC CHECKSUM: 35a3 diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index b46cec8720fd4..3eac57c97eb47 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -40,9 +40,9 @@ dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: file: 6.1.4 -# PUBSPEC CHECKSUM: b05f +# PUBSPEC CHECKSUM: 9e5d diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 7f899d5363c7b..a69a7465fd877 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -48,7 +48,7 @@ dependencies: http_multi_server: 3.2.1 convert: 3.1.1 async: 2.11.0 - unified_analytics: 3.0.0 + unified_analytics: 4.0.0 cli_config: 0.1.1 graphs: 2.3.1 @@ -112,4 +112,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: f179 +# PUBSPEC CHECKSUM: 807a diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index 02babffc73467..84cb9643140f0 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -33,4 +33,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1e6b +# PUBSPEC CHECKSUM: 0c69 diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index dfe4569d34ded..d4de3e98957b2 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -84,4 +84,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 6329 +# PUBSPEC CHECKSUM: fb27 diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index 536748fd1ab43..d9501f40dd625 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -21,9 +21,9 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: 7aad +# PUBSPEC CHECKSUM: 68ab diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index ed9f2109b1418..f9dbd36e2a7db 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.1.4-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: 3886 +# PUBSPEC CHECKSUM: e584 From 1bfd6a1f3cd8ff57b7ad7d91f934c9b1e707d379 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 18:59:18 -0400 Subject: [PATCH 1376/1547] Roll Flutter Engine from 39c0f2ea1f53 to 89d864552acd (4 revisions) (#135169) https://github.com/flutter/engine/compare/39c0f2ea1f53...89d864552acd 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 565d95f72f2e to f4238844089f (3 revisions) (flutter/engine#46105) 2023-09-20 skia-flutter-autoroll@skia.org Roll Dart SDK from ed05ca364d5e to d5d05146868a (1 revision) (flutter/engine#46104) 2023-09-20 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from aHtib4LBcLwx7JwK-... to QcxgV9KlY7j3o3b4j... (flutter/engine#46102) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from 9bc5eeb93a1e to 565d95f72f2e (1 revision) (flutter/engine#46100) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from aHtib4LBcLwx to QcxgV9KlY7j3 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1da2e14ecc4eb..5e4c0c3c918d3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -39c0f2ea1f536eb7dc057d9147f23e3fec4a56c9 \ No newline at end of file +89d864552acdd55c4fa175a9e2c1c809135a7174 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 144340c0c9743..4ef97df9126d1 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -aHtib4LBcLwx7JwK-pLiQPleFerXUt7If4yJSTh4tUcC +QcxgV9KlY7j3o3b4jzhzTH7yw1xDUfdSnU0UXLuoQEYC From 04854e8aff88669c03c0d28b17d48ed73c329f46 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Thu, 21 Sep 2023 01:43:44 +0200 Subject: [PATCH 1377/1547] Fix memory leak in _SelectableTextState (#135049) --- .../lib/src/material/selectable_text.dart | 1 + .../test/widgets/selectable_text_test.dart | 260 +++++++++--------- 2 files changed, 137 insertions(+), 124 deletions(-) diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index 508302bc7ebb3..e97441e7a80a9 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -536,6 +536,7 @@ class _SelectableTextState extends State<SelectableText> implements TextSelectio super.didUpdateWidget(oldWidget); if (widget.data != oldWidget.data || widget.textSpan != oldWidget.textSpan) { _controller.removeListener(_onControllerChanged); + _controller.dispose(); _controller = _TextSpanEditingController( textSpan: widget.textSpan ?? TextSpan(text: widget.data), ); diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 9591f09db5e17..1de30a19e45c6 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -18,6 +18,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/clipboard_utils.dart'; import '../widgets/editable_text_utils.dart' show textOffsetToPosition; @@ -55,6 +56,7 @@ Widget overlay({ Widget? child }) { ); }, ); + addTearDown(() => entry..remove()..dispose()); return overlayWithEntry(entry); } @@ -215,7 +217,7 @@ void main() { expect(tester.takeException(), isNotNull); // side effect exception }); - testWidgets('Do not crash when remove SelectableText during handle drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Do not crash when remove SelectableText during handle drag', (WidgetTester tester) async { // Regression test https://github.com/flutter/flutter/issues/108242 bool isShow = true; late StateSetter setter; @@ -283,7 +285,7 @@ void main() { await tester.pump(); }); - testWidgets('has expected defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has expected defaults', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: const SelectableText('selectable text'), @@ -299,7 +301,7 @@ void main() { expect(selectableText.enableInteractiveSelection, true); }); - testWidgets('Rich selectable text has expected defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rich selectable text has expected defaults', (WidgetTester tester) async { await tester.pumpWidget( const MediaQuery( data: MediaQueryData(), @@ -344,7 +346,7 @@ void main() { expect(selectableText.enableInteractiveSelection, true); }); - testWidgets('Rich selectable text supports WidgetSpan', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rich selectable text supports WidgetSpan', (WidgetTester tester) async { await tester.pumpWidget( const MediaQuery( data: MediaQueryData(), @@ -385,7 +387,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('no text keyboard when widget is focused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('no text keyboard when widget is focused', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText('selectable text'), @@ -396,7 +398,7 @@ void main() { expect(tester.testTextInput.hasAnyClients, false); }); - testWidgets('uses DefaultSelectionStyle for selection and cursor colors if provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses DefaultSelectionStyle for selection and cursor colors if provided', (WidgetTester tester) async { const Color selectionColor = Colors.orange; const Color cursorColor = Colors.red; @@ -417,7 +419,7 @@ void main() { expect(state.widget.cursorColor, cursorColor); }); - testWidgets('Selectable Text has adaptive size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable Text has adaptive size', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: const SelectableText('s'), @@ -439,7 +441,7 @@ void main() { expect(longtextBox.size, const Size(199.0, 14.0)); }); - testWidgets('can scale with textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can scale with textScaleFactor', (WidgetTester tester) async { await tester.pumpWidget( boilerplate( child: const SelectableText('selectable text'), @@ -462,7 +464,7 @@ void main() { expect(scaledBox.size.height, 27.0); }); - testWidgets('can switch between textWidthBasis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can switch between textWidthBasis', (WidgetTester tester) async { RenderBox findTextBox() => tester.renderObject(find.byType(SelectableText)); const String text = 'I can face roll keyboardkeyboardaszzaaaaszzaaaaszzaaaaszzaaaa'; await tester.pumpWidget( @@ -488,7 +490,7 @@ void main() { expect(textBox.size, const Size(633.0, 28.0)); }); - testWidgets('can switch between textHeightBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can switch between textHeightBehavior', (WidgetTester tester) async { const String text = 'selectable text'; const TextHeightBehavior textHeightBehavior = TextHeightBehavior( applyHeightToFirstAscent: false, @@ -512,7 +514,7 @@ void main() { expect(findRenderEditable(tester).textHeightBehavior, textHeightBehavior); }); - testWidgets('Cursor blinks when showCursor is true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cursor blinks when showCursor is true', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText( @@ -540,7 +542,7 @@ void main() { expect(editableText.cursorCurrentlyVisible, equals(initialShowCursor)); }); - testWidgets('selectable text selection toolbar renders correctly inside opacity', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectable text selection toolbar renders correctly inside opacity', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -571,7 +573,7 @@ void main() { expect(find.text('Select all'), findsOneWidget); }); - testWidgets('Caret position is updated on tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret position is updated on tap', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText('abc def ghi'), @@ -591,7 +593,7 @@ void main() { expect(editableText.controller.selection.extentOffset, tapIndex); }); - testWidgets('enableInteractiveSelection = false, tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('enableInteractiveSelection = false, tap', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText( @@ -614,7 +616,7 @@ void main() { expect(editableText.controller.selection.extentOffset, -1); }); - testWidgets('enableInteractiveSelection = false, long-press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('enableInteractiveSelection = false, long-press', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText( @@ -639,7 +641,7 @@ void main() { expect(editableText.controller.selection.extentOffset, -1); }); - testWidgets('Can long press to select', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can long press to select', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText('abc def ghi'), @@ -668,7 +670,7 @@ void main() { expect(editableText.controller.selection.baseOffset, 9); }); - testWidgets("Slight movements in longpress don't hide/show handles", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Slight movements in longpress don't hide/show handles", (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText('abc def ghi'), @@ -695,7 +697,7 @@ void main() { expect(handle.opacity.value, equals(1.0)); }); - testWidgets('Mouse long press is just like a tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse long press is just like a tap', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText('abc def ghi'), @@ -717,7 +719,7 @@ void main() { expect(editableText.controller.selection.extentOffset, eIndex); }); - testWidgets('selectable text basic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectable text basic', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText('selectable'), @@ -749,7 +751,7 @@ void main() { expect(find.text('Cut'), findsNothing); }); - testWidgets('selectable text can disable toolbar options', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selectable text can disable toolbar options', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText( @@ -769,7 +771,7 @@ void main() { expect(find.text('Select all'), findsOneWidget); }); - testWidgets('Can select text by dragging with a mouse', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can select text by dragging with a mouse', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -797,7 +799,7 @@ void main() { expect(controller.selection.extentOffset, 8); }); - testWidgets('Continuous dragging does not cause flickering', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Continuous dragging does not cause flickering', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -849,7 +851,7 @@ void main() { expect(controller.selection.extentOffset, 9); }); - testWidgets('Dragging in opposite direction also works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dragging in opposite direction also works', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -877,7 +879,7 @@ void main() { expect(controller.selection.extentOffset, 5); }); - testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slow mouse dragging also selects text', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -904,7 +906,7 @@ void main() { expect(controller.selection.extentOffset,8); }); - testWidgets('Can drag handles to change selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can drag handles to change selection', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -966,7 +968,7 @@ void main() { expect(controller.selection.extentOffset, 11); }); - testWidgets('Dragging handles calls onSelectionChanged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dragging handles calls onSelectionChanged', (WidgetTester tester) async { TextSelection? newSelection; await tester.pumpWidget( MaterialApp( @@ -1018,7 +1020,7 @@ void main() { expect(newSelection!.extentOffset, 9); }); - testWidgets('Cannot drag one handle past the other', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Cannot drag one handle past the other', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -1076,7 +1078,7 @@ void main() { expect(controller.selection.extentOffset, 5); }); - testWidgets('Can use selection toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can use selection toolbar', (WidgetTester tester) async { const String testValue = 'abc def ghi'; await tester.pumpWidget( const MaterialApp( @@ -1118,7 +1120,7 @@ void main() { expect(controller.selection.isCollapsed, true); }); - testWidgets('Selectable height with maxLine', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable height with maxLine', (WidgetTester tester) async { await tester.pumpWidget(selectableTextBuilder()); RenderBox findTextBox() => tester.renderObject(find.byType(SelectableText)); @@ -1170,7 +1172,7 @@ void main() { expect(textBox.size.height, greaterThan(fourLineInputSize.height)); }); - testWidgets('Can drag handles to change selection in multiline', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can drag handles to change selection in multiline', (WidgetTester tester) async { const String testValue = kThreeLines; await tester.pumpWidget( overlay( @@ -1258,7 +1260,7 @@ void main() { expect(controller.selection.isCollapsed, true); }); - testWidgets('Can scroll multiline input', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can scroll multiline input', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText( @@ -1352,7 +1354,7 @@ void main() { expect(inputBox.hitTest(BoxHitTestResult(), position: inputBox.globalToLocal(newFourthPos)), isFalse); }); - testWidgets('minLines cannot be greater than maxLines', (WidgetTester tester) async { + testWidgetsWithLeakTracking('minLines cannot be greater than maxLines', (WidgetTester tester) async { expect( () async { await tester.pumpWidget( @@ -1376,7 +1378,7 @@ void main() { ); }); - testWidgets('Selectable height with minLine', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable height with minLine', (WidgetTester tester) async { await tester.pumpWidget(selectableTextBuilder()); RenderBox findTextBox() => tester.renderObject(find.byType(SelectableText)); @@ -1390,7 +1392,7 @@ void main() { expect(textBox.size.height, emptyInputSize.height * 2); }); - testWidgets('Can align to center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can align to center', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SizedBox( @@ -1412,7 +1414,7 @@ void main() { expect(topLeft.dx, equals(399.0)); }); - testWidgets('Can align to center within center', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can align to center within center', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SizedBox( @@ -1436,9 +1438,11 @@ void main() { expect(topLeft.dx, equals(399.0)); }); - testWidgets('Selectable text is skipped during focus traversal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable text is skipped during focus traversal', (WidgetTester tester) async { final FocusNode firstFieldFocus = FocusNode(); + addTearDown(firstFieldFocus.dispose); final FocusNode lastFieldFocus = FocusNode(); + addTearDown(lastFieldFocus.dispose); await tester.pumpWidget( MaterialApp( @@ -1474,7 +1478,7 @@ void main() { expect(lastFieldFocus.hasFocus, isTrue); }); - testWidgets('Selectable text identifies as text field in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable text identifies as text field in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1501,7 +1505,7 @@ void main() { semantics.dispose(); }); - testWidgets('Selectable text rich text with spell out in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable text rich text with spell out in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1534,7 +1538,7 @@ void main() { semantics.dispose(); }); - testWidgets('Selectable text rich text with locale in semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable text rich text with locale in semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -1567,7 +1571,7 @@ void main() { semantics.dispose(); }); - testWidgets('Selectable rich text with gesture recognizer has correct semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Selectable rich text with gesture recognizer has correct semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( overlay( @@ -1623,6 +1627,7 @@ void main() { Future<void> setupWidget(WidgetTester tester, String text) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); await tester.pumpWidget( MaterialApp( home: Material( @@ -1642,7 +1647,7 @@ void main() { controller = editableTextWidget.controller; } - testWidgets('Shift test 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shift test 1', (WidgetTester tester) async { await setupWidget(tester, 'a big house'); await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); @@ -1650,7 +1655,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, -1); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Shift test 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shift test 2', (WidgetTester tester) async { await setupWidget(tester, 'abcdefghi'); controller.selection = const TextSelection.collapsed(offset: 3); @@ -1662,7 +1667,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, 1); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Control Shift test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Control Shift test', (WidgetTester tester) async { await setupWidget(tester, 'their big house'); await tester.sendKeyDownEvent(LogicalKeyboardKey.control); @@ -1674,7 +1679,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, -5); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Down and up test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Down and up test', (WidgetTester tester) async { await setupWidget(tester, 'a big house'); await tester.sendKeyDownEvent(LogicalKeyboardKey.shift); @@ -1692,7 +1697,7 @@ void main() { expect(controller.selection.extentOffset - controller.selection.baseOffset, 0); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Down and up test 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Down and up test 2', (WidgetTester tester) async { await setupWidget(tester, 'a big house\njumped over a mouse\nOne more line yay'); controller.selection = const TextSelection.collapsed(offset: 0); @@ -1744,8 +1749,9 @@ void main() { }, variant: KeySimulatorTransitModeVariant.all()); }); - testWidgets('Copy test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Copy test', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); String clipboardContent = ''; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -1802,8 +1808,9 @@ void main() { await tester.pumpAndSettle(); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Select all test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Select all test', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); const String testValue = 'a big house\njumped over a mouse'; await tester.pumpWidget( MaterialApp( @@ -1836,8 +1843,9 @@ void main() { expect(controller.selection.extentOffset, 31); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('keyboard selection should call onSelectionChanged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keyboard selection should call onSelectionChanged', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); TextSelection? newSelection; const String testValue = 'a big house\njumped over a mouse'; await tester.pumpWidget( @@ -1882,8 +1890,9 @@ void main() { } }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Changing positions of selectable text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing positions of selectable text', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final List<RawKeyEvent> events = <RawKeyEvent>[]; final Key key1 = UniqueKey(); @@ -1972,8 +1981,9 @@ void main() { expect(c1.selection.extentOffset - c1.selection.baseOffset, -10); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Changing focus test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing focus test', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final List<RawKeyEvent> events = <RawKeyEvent>[]; final Key key1 = UniqueKey(); @@ -2041,7 +2051,7 @@ void main() { expect(c2.selection.extentOffset - c2.selection.baseOffset, -5); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Caret works when maxLines is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret works when maxLines is null', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SelectableText( @@ -2064,7 +2074,7 @@ void main() { expect(controller.selection.baseOffset, 0); }); - testWidgets('SelectableText baseline alignment no-strut', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText baseline alignment no-strut', (WidgetTester tester) async { final Key keyA = UniqueKey(); final Key keyB = UniqueKey(); @@ -2113,7 +2123,7 @@ void main() { expect(tester.getBottomLeft(find.byKey(keyB)).dy, rowBottomY); }); - testWidgets('SelectableText baseline alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText baseline alignment', (WidgetTester tester) async { final Key keyA = UniqueKey(); final Key keyB = UniqueKey(); @@ -2160,7 +2170,7 @@ void main() { expect(tester.getBottomLeft(find.byKey(keyB)).dy, rowBottomY); }); - testWidgets('SelectableText semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Key key = UniqueKey(); @@ -2280,7 +2290,7 @@ void main() { semantics.dispose(); }); - testWidgets('SelectableText semantics, with semanticsLabel', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText semantics, with semanticsLabel', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Key key = UniqueKey(); @@ -2307,7 +2317,7 @@ void main() { semantics.dispose(); }); - testWidgets('SelectableText semantics, enableInteractiveSelection = false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText semantics, enableInteractiveSelection = false', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Key key = UniqueKey(); @@ -2353,7 +2363,7 @@ void main() { semantics.dispose(); }); - testWidgets('SelectableText semantics for selections', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText semantics for selections', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Key key = UniqueKey(); @@ -2449,13 +2459,15 @@ void main() { semantics.dispose(); }); - testWidgets('semantic nodes of offscreen recognizers are marked hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantic nodes of offscreen recognizers are marked hidden', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/100395. final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(fontSize: 200); const String onScreenText = 'onscreen\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'; const String offScreenText = 'off screen'; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: SingleChildScrollView( @@ -2542,7 +2554,7 @@ void main() { semantics.dispose(); }); - testWidgets('SelectableText change selection with semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText change selection with semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner!; final Key key = UniqueKey(); @@ -2641,7 +2653,7 @@ void main() { semantics.dispose(); }); - testWidgets('Can activate SelectableText with explicit controller via semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can activate SelectableText with explicit controller via semantics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/17801 const String testValue = 'Hello'; @@ -2715,7 +2727,7 @@ void main() { semantics.dispose(); }); - testWidgets('onTap is called upon tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap is called upon tap', (WidgetTester tester) async { int tapCount = 0; await tester.pumpWidget( overlay( @@ -2739,7 +2751,7 @@ void main() { expect(tapCount, 3); }); - testWidgets('SelectableText style is merged with default text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText style is merged with default text style', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/23994 final TextStyle defaultStyle = TextStyle( color: Colors.blue[500], @@ -2786,7 +2798,7 @@ void main() { expect(editableText.style.color, isNull); }); - testWidgets('style enforces required fields', (WidgetTester tester) async { + testWidgetsWithLeakTracking('style enforces required fields', (WidgetTester tester) async { Widget buildFrame(TextStyle style) { return MaterialApp( home: Material( @@ -2818,7 +2830,7 @@ void main() { expect(tester.takeException(), isNotNull); }); - testWidgets( + testWidgetsWithLeakTracking( 'tap moves cursor to the edge of the word it tapped', (WidgetTester tester) async { await tester.pumpWidget( @@ -2850,7 +2862,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'tap moves cursor to the position tapped (Android)', (WidgetTester tester) async { await tester.pumpWidget( @@ -2882,7 +2894,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'two slow taps do not trigger a word selection', (WidgetTester tester) async { await tester.pumpWidget( @@ -2917,7 +2929,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap selects word and first tap of double tap moves cursor', (WidgetTester tester) async { await tester.pumpWidget( @@ -2964,7 +2976,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap selects word and first tap of double tap moves cursor and shows toolbar (Android)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3009,7 +3021,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap on top of cursor also selects word (Android)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3058,7 +3070,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap hold selects word', (WidgetTester tester) async { await tester.pumpWidget( @@ -3106,7 +3118,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap selects word with semantics label', (WidgetTester tester) async { await tester.pumpWidget( @@ -3139,7 +3151,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'tap after a double tap select is not affected (iOS)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3186,7 +3198,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press selects word and shows toolbar (iOS)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3223,7 +3235,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press selects word and shows toolbar (Android)', (WidgetTester tester) async { @@ -3255,7 +3267,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'long press selects word and shows custom toolbar (Android)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3293,7 +3305,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press selects word and shows custom toolbar (iOS)', (WidgetTester tester) async { @@ -3328,7 +3340,7 @@ void main() { variant: TargetPlatformVariant.all(), ); - testWidgets( + testWidgetsWithLeakTracking( 'textSelectionControls is passed to EditableText', (WidgetTester tester) async { await tester.pumpWidget( @@ -3348,7 +3360,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'long press tap cannot initiate a double tap', (WidgetTester tester) async { await tester.pumpWidget( @@ -3390,7 +3402,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press drag extends the selection to the word under the drag and shows toolbar on lift on non-Apple platforms', (WidgetTester tester) async { await tester.pumpWidget( @@ -3466,7 +3478,7 @@ void main() { variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press drag extends the selection to the word under the drag and shows toolbar on lift (iOS)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3559,7 +3571,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long press drag moves the cursor under the drag and shows toolbar on lift (macOS)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3637,7 +3649,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }), ); - testWidgets('long press drag can edge scroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('long press drag can edge scroll', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -3741,7 +3753,7 @@ void main() { skip: true, // https://github.com/flutter/flutter/issues/64059 ); - testWidgets( + testWidgetsWithLeakTracking( 'long tap still selects after a double tap select (iOS)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3787,7 +3799,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'long tap still selects after a double tap select (macOS)', (WidgetTester tester) async { await tester.pumpWidget( @@ -3831,7 +3843,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS }), ); //convert - testWidgets( + testWidgetsWithLeakTracking( 'double tap after a long tap is not affected', (WidgetTester tester) async { await tester.pumpWidget( @@ -3880,7 +3892,7 @@ void main() { }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'double tap chains work', (WidgetTester tester) async { await tester.pumpWidget( @@ -3955,7 +3967,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('force press does not select a word on (android)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('force press does not select a word on (android)', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -3991,7 +4003,7 @@ void main() { expect(find.byType(TextButton), findsNothing); }); - testWidgets('force press selects word', (WidgetTester tester) async { + testWidgetsWithLeakTracking('force press selects word', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4032,7 +4044,7 @@ void main() { expect(find.byType(CupertinoButton), findsNWidgets(4)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('tap on non-force-press-supported devices work', (WidgetTester tester) async { + testWidgetsWithLeakTracking('tap on non-force-press-supported devices work', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4080,7 +4092,7 @@ void main() { // https://github.com/flutter/flutter/issues/43445 }, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); - testWidgets('default SelectableText debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default SelectableText debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const SelectableText('something').debugFillProperties(builder); @@ -4092,7 +4104,7 @@ void main() { expect(description, <String>['data: something']); }); - testWidgets('SelectableText implements debugFillProperties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); // Not checking controller, inputFormatters, focusNode @@ -4139,7 +4151,7 @@ void main() { ]); }); - testWidgets( + testWidgetsWithLeakTracking( 'strut basic single line', (WidgetTester tester) async { await tester.pumpWidget( @@ -4162,7 +4174,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut TextStyle increases height', (WidgetTester tester) async { await tester.pumpWidget( @@ -4209,7 +4221,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut basic multi line', (WidgetTester tester) async { await tester.pumpWidget( @@ -4233,7 +4245,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut no force small strut', (WidgetTester tester) async { await tester.pumpWidget( @@ -4265,7 +4277,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut no force large strut', (WidgetTester tester) async { await tester.pumpWidget( @@ -4294,7 +4306,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut height override', (WidgetTester tester) async { await tester.pumpWidget( @@ -4323,7 +4335,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'strut forces field taller', (WidgetTester tester) async { await tester.pumpWidget( @@ -4354,7 +4366,7 @@ void main() { }, ); - testWidgets('Caret center position', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret center position', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SizedBox( @@ -4390,7 +4402,7 @@ void main() { expect(topLeft.dx, equals(385)); }); - testWidgets('Caret indexes into trailing whitespace center align', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Caret indexes into trailing whitespace center align', (WidgetTester tester) async { await tester.pumpWidget( overlay( child: const SizedBox( @@ -4436,7 +4448,7 @@ void main() { expect(topLeft.dx, equals(385)); }); - testWidgets('selection handles are rendered and not faded away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection handles are rendered and not faded away', (WidgetTester tester) async { const String testText = 'lorem ipsum'; await tester.pumpWidget( const MaterialApp( @@ -4466,7 +4478,7 @@ void main() { expect(right.opacity.value, equals(1.0)); }); - testWidgets('selection handles are rendered and not faded away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selection handles are rendered and not faded away', (WidgetTester tester) async { const String testText = 'lorem ipsum'; await tester.pumpWidget( @@ -4494,7 +4506,7 @@ void main() { expect(right.opacity.value, equals(1.0)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Long press shows handles and toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Long press shows handles and toolbar', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4513,7 +4525,7 @@ void main() { expect(editableText.selectionOverlay!.toolbarIsVisible, isTrue); }); - testWidgets('Double tap shows handles and toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Double tap shows handles and toolbar', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4534,7 +4546,7 @@ void main() { expect(editableText.selectionOverlay!.toolbarIsVisible, isTrue); }); - testWidgets( + testWidgetsWithLeakTracking( 'Mouse tap does not show handles nor toolbar', (WidgetTester tester) async { await tester.pumpWidget( @@ -4562,7 +4574,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Mouse long press does not show handles nor toolbar', (WidgetTester tester) async { await tester.pumpWidget( @@ -4590,7 +4602,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Mouse double tap does not show handles nor toolbar', (WidgetTester tester) async { await tester.pumpWidget( @@ -4622,7 +4634,7 @@ void main() { }, ); - testWidgets('text span with tap gesture recognizer works in selectable rich text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text span with tap gesture recognizer works in selectable rich text', (WidgetTester tester) async { int spyTaps = 0; final TapGestureRecognizer spyRecognizer = TapGestureRecognizer() ..onTap = () { @@ -4672,7 +4684,7 @@ void main() { expect(spyTaps, 1); }); - testWidgets('text span with long press gesture recognizer works in selectable rich text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text span with long press gesture recognizer works in selectable rich text', (WidgetTester tester) async { int spyLongPress = 0; final LongPressGestureRecognizer spyRecognizer = LongPressGestureRecognizer() ..onLongPress = () { @@ -4723,7 +4735,7 @@ void main() { expect(spyLongPress, 1); }); - testWidgets('SelectableText changes mouse cursor when hovered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText changes mouse cursor when hovered', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4742,7 +4754,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('The handles show after pressing Select All', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The handles show after pressing Select All', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4779,7 +4791,7 @@ void main() { }), ); - testWidgets('The Select All calls on selection changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The Select All calls on selection changed', (WidgetTester tester) async { TextSelection? newSelection; await tester.pumpWidget( MaterialApp( @@ -4815,7 +4827,7 @@ void main() { }), ); - testWidgets('The Select All calls on selection changed with a mouse on windows and linux', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The Select All calls on selection changed with a mouse on windows and linux', (WidgetTester tester) async { const String string = 'abc def ghi'; TextSelection? newSelection; await tester.pumpWidget( @@ -4857,7 +4869,7 @@ void main() { }), ); - testWidgets('Does not show handles when updated from the web engine', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not show handles when updated from the web engine', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Material( @@ -4897,7 +4909,7 @@ void main() { } }); - testWidgets('onSelectionChanged is called when selection changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onSelectionChanged is called when selection changes', (WidgetTester tester) async { int onSelectionChangedCallCount = 0; await tester.pumpWidget( @@ -4927,7 +4939,7 @@ void main() { expect(onSelectionChangedCallCount, equals(3)); }); - testWidgets('selecting a space selects the previous word on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('selecting a space selects the previous word on mobile', (WidgetTester tester) async { TextSelection? selection; await tester.pumpWidget( @@ -5028,7 +5040,7 @@ void main() { expect(selection!.extentOffset, 1); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux, TargetPlatform.fuchsia })); - testWidgets('double tapping a space selects the previous word on mobile', (WidgetTester tester) async { + testWidgetsWithLeakTracking('double tapping a space selects the previous word on mobile', (WidgetTester tester) async { TextSelection? selection; await tester.pumpWidget( @@ -5093,7 +5105,7 @@ void main() { expect(selection!.extentOffset, 14); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android })); - testWidgets('text selection style 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text selection style 1', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -5146,7 +5158,7 @@ void main() { ); }); - testWidgets('text selection style 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('text selection style 2', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -5198,7 +5210,7 @@ void main() { ); }); - testWidgets('keeps alive when has focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keeps alive when has focus', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( theme: ThemeData(useMaterial3: false), @@ -5290,7 +5302,7 @@ void main() { late ValueNotifier<MagnifierInfo> magnifierInfo; final Widget fakeMagnifier = Container(key: UniqueKey()); - testWidgets( + testWidgetsWithLeakTracking( 'Can drag handles to show, unshow, and update magnifier', (WidgetTester tester) async { const String testValue = 'abc def ghi'; @@ -5359,7 +5371,7 @@ void main() { }); }); - testWidgets('SelectableText text span style is merged with default text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText text span style is merged with default text style', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/71389 const TextStyle textStyle = TextStyle(color: Color(0xff00ff00), fontSize: 12.0); @@ -5380,7 +5392,7 @@ void main() { expect(editableText.style.fontSize, textStyle.fontSize); }); - testWidgets('SelectableText text span style is merged with default text style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SelectableText text span style is merged with default text style', (WidgetTester tester) async { TextSelection? selection; int count = 0; @@ -5420,7 +5432,7 @@ void main() { expect(count, 1); // The `onSelectionChanged` will not be triggered. }); - testWidgets("Off-screen selected text doesn't throw exception", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Off-screen selected text doesn't throw exception", (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/123527 TextSelection? selection; From 2868bc1351c8dabbd336ced4df797a2535c9d3c1 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:45:15 +0200 Subject: [PATCH 1378/1547] Fix leak in hardware_keyboard_test.dart (#134380) --- .../test/services/hardware_keyboard_test.dart | 33 ++++++---- .../test/services/raw_keyboard_test.dart | 64 ++++++++++--------- 2 files changed, 54 insertions(+), 43 deletions(-) diff --git a/packages/flutter/test/services/hardware_keyboard_test.dart b/packages/flutter/test/services/hardware_keyboard_test.dart index b9522292a7563..c2c48412263fc 100644 --- a/packages/flutter/test/services/hardware_keyboard_test.dart +++ b/packages/flutter/test/services/hardware_keyboard_test.dart @@ -8,9 +8,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('HardwareKeyboard records pressed keys and enabled locks', (WidgetTester tester) async { + testWidgetsWithLeakTracking('HardwareKeyboard records pressed keys and enabled locks', (WidgetTester tester) async { await simulateKeyDownEvent(LogicalKeyboardKey.numLock, platform: 'windows'); expect(HardwareKeyboard.instance.physicalKeysPressed, equals(<PhysicalKeyboardKey>{PhysicalKeyboardKey.numLock})); @@ -68,7 +69,7 @@ void main() { equals(<KeyboardLockMode>{})); }, variant: KeySimulatorTransitModeVariant.keyDataThenRawKeyData()); - testWidgets('KeyboardManager synthesizes modifier keys in rawKeyData mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('KeyboardManager synthesizes modifier keys in rawKeyData mode', (WidgetTester tester) async { final List<KeyEvent> events = <KeyEvent>[]; HardwareKeyboard.instance.addHandler((KeyEvent event) { events.add(event); @@ -96,8 +97,9 @@ void main() { expect(events[1].synthesized, false); }); - testWidgets('Dispatch events to all handlers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dispatch events to all handlers', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final List<int> logs = <int>[]; await tester.pumpWidget( @@ -201,8 +203,9 @@ void main() { // _CastError on _hardwareKeyboard.lookUpLayout(key). The original scenario // that this is triggered on Android is unknown. Here we make up a scenario // where a ShiftLeft key down is dispatched but the modifier bit is not set. - testWidgets('Correctly convert down events that are synthesized released', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Correctly convert down events that are synthesized released', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final List<KeyEvent> events = <KeyEvent>[]; await tester.pumpWidget( @@ -244,8 +247,9 @@ void main() { KeyDataTransitMode.rawKeyData, })); - testWidgets('Instantly dispatch synthesized key events when the queue is empty', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Instantly dispatch synthesized key events when the queue is empty', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final List<int> logs = <int>[]; await tester.pumpWidget( @@ -276,19 +280,22 @@ void main() { logs.clear(); }, variant: KeySimulatorTransitModeVariant.keyDataThenRawKeyData()); - testWidgets('Postpone synthesized key events when the queue is not empty', (WidgetTester tester) async { - final FocusNode focusNode = FocusNode(); + testWidgetsWithLeakTracking('Postpone synthesized key events when the queue is not empty', (WidgetTester tester) async { + final FocusNode keyboardListenerFocusNode = FocusNode(); + addTearDown(keyboardListenerFocusNode.dispose); + final FocusNode rawKeyboardListenerFocusNode = FocusNode(); + addTearDown(rawKeyboardListenerFocusNode.dispose); final List<String> logs = <String>[]; await tester.pumpWidget( RawKeyboardListener( - focusNode: FocusNode(), + focusNode: rawKeyboardListenerFocusNode, onKey: (RawKeyEvent event) { logs.add('${event.runtimeType}'); }, child: KeyboardListener( autofocus: true, - focusNode: focusNode, + focusNode: keyboardListenerFocusNode, child: Container(), onKeyEvent: (KeyEvent event) { logs.add('${event.runtimeType}'); @@ -331,7 +338,7 @@ void main() { // In that case, the key data should not be converted to any [KeyEvent]s, // but is only used so that *a* key data comes before the raw key message // and makes [KeyEventManager] infer [KeyDataTransitMode.keyDataThenRawKeyData]. - testWidgets('Empty keyData yields no event but triggers inference', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty keyData yields no event but triggers inference', (WidgetTester tester) async { final List<KeyEvent> events = <KeyEvent>[]; final List<RawKeyEvent> rawEvents = <RawKeyEvent>[]; tester.binding.keyboard.addHandler((KeyEvent event) { @@ -383,7 +390,7 @@ void main() { expect(rawEvents.length, 2); }); - testWidgets('Exceptions from keyMessageHandler are caught and reported', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Exceptions from keyMessageHandler are caught and reported', (WidgetTester tester) async { final KeyMessageHandler? oldKeyMessageHandler = tester.binding.keyEventManager.keyMessageHandler; addTearDown(() { tester.binding.keyEventManager.keyMessageHandler = oldKeyMessageHandler; @@ -426,7 +433,7 @@ void main() { expect(record, isNull); }); - testWidgets('Exceptions from HardwareKeyboard handlers are caught and reported', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Exceptions from HardwareKeyboard handlers are caught and reported', (WidgetTester tester) async { bool throwingCallback(KeyEvent event) { throw 1; } @@ -466,7 +473,7 @@ void main() { expect(record, isNull); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('debugPrintKeyboardEvents causes logging of key events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugPrintKeyboardEvents causes logging of key events', (WidgetTester tester) async { final bool oldDebugPrintKeyboardEvents = debugPrintKeyboardEvents; final DebugPrintCallback oldDebugPrint = debugPrint; final StringBuffer messages = StringBuffer(); diff --git a/packages/flutter/test/services/raw_keyboard_test.dart b/packages/flutter/test/services/raw_keyboard_test.dart index ed52400bdeb51..f5c4b38b4acf5 100644 --- a/packages/flutter/test/services/raw_keyboard_test.dart +++ b/packages/flutter/test/services/raw_keyboard_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class _ModifierCheck { const _ModifierCheck(this.key, this.side); @@ -17,7 +18,7 @@ class _ModifierCheck { void main() { group('RawKeyboard', () { - testWidgets('The correct character is produced', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The correct character is produced', (WidgetTester tester) async { for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows']) { String character = ''; void handleKey(RawKeyEvent event) { @@ -32,7 +33,7 @@ void main() { } }); - testWidgets('No character is produced for non-printables', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No character is produced for non-printables', (WidgetTester tester) async { for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'web']) { void handleKey(RawKeyEvent event) { expect(event.character, isNull, reason: 'on $platform'); @@ -43,7 +44,7 @@ void main() { } }); - testWidgets('keysPressed is maintained', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed is maintained', (WidgetTester tester) async { for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) { RawKeyboard.instance.clearKeysPressed(); expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform'); @@ -149,7 +150,7 @@ void main() { } }, skip: isBrowser); // https://github.com/flutter/flutter/issues/61021 - testWidgets('keysPressed is correct when modifier is released before key', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed is correct when modifier is released before key', (WidgetTester tester) async { for (final String platform in <String>['linux', 'android', 'macos', 'fuchsia', 'windows', 'ios']) { RawKeyboard.instance.clearKeysPressed(); expect(RawKeyboard.instance.keysPressed, isEmpty, reason: 'on $platform'); @@ -200,7 +201,7 @@ void main() { } }, skip: isBrowser); // https://github.com/flutter/flutter/issues/76741 - testWidgets('keysPressed modifiers are synchronized with key events on macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on macOS', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -224,7 +225,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is a macOS-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on iOS', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -248,7 +249,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is an iOS-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on Windows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on Windows', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -272,7 +273,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is a Windows-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on android', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -296,7 +297,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is an Android-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on fuchsia', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on fuchsia', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -320,7 +321,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is a Fuchsia-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on Linux GLFW', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on Linux GLFW', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -382,7 +383,7 @@ void main() { // // GTK has some weird behavior where the tested key event sequence will // result in a AltRight down event without Alt bitmask. - testWidgets('keysPressed modifiers are synchronized with key events on Linux GTK (down events)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on Linux GTK (down events)', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); await simulateGTKKeyEvent(true, 0x6c/*AltRight*/, 0xffea/*AltRight*/, 0x2000000); @@ -402,7 +403,7 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/114591 . // // On Linux, CapsLock can be remapped to a non-modifier key. - testWidgets('CapsLock should not be release when remapped on Linux', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CapsLock should not be release when remapped on Linux', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); await simulateGTKKeyEvent(true, 0x42/*CapsLock*/, 0xff08/*Backspace*/, 0x2000000); @@ -419,7 +420,7 @@ void main() { // Regression test for https://github.com/flutter/flutter/issues/114591 . // // On Web, CapsLock can be remapped to a non-modifier key. - testWidgets('CapsLock should not be release when remapped on Web', (WidgetTester _) async { + testWidgetsWithLeakTracking('CapsLock should not be release when remapped on Web', (WidgetTester _) async { final List<RawKeyEvent> events = <RawKeyEvent>[]; RawKeyboard.instance.addListener(events.add); addTearDown(() { @@ -449,7 +450,7 @@ void main() { ); }, skip: !isBrowser); // [intended] This is a Browser-specific test. - testWidgets('keysPressed modifiers are synchronized with key events on web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('keysPressed modifiers are synchronized with key events on web', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. Change the modifiers so // that they show the shift key as already down when this event is @@ -537,7 +538,7 @@ void main() { ); }); - testWidgets('sided modifiers without a side set return all sides on Android', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sided modifiers without a side set return all sides on Android', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -574,7 +575,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is an Android-specific test. - testWidgets('sided modifiers without a side set return all sides on macOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sided modifiers without a side set return all sides on macOS', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -611,7 +612,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is a macOS-specific test. - testWidgets('sided modifiers without a side set return all sides on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sided modifiers without a side set return all sides on iOS', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -648,7 +649,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is an iOS-specific test. - testWidgets('repeat events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('repeat events', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); late RawKeyEvent receivedEvent; RawKeyboard.instance.keyEventHandler = (RawKeyEvent event) { @@ -691,7 +692,7 @@ void main() { RawKeyboard.instance.keyEventHandler = null; }, skip: isBrowser); // [intended] This is a Windows-specific test. - testWidgets('sided modifiers without a side set return all sides on Windows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sided modifiers without a side set return all sides on Windows', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -726,7 +727,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is a Windows-specific test. - testWidgets('sided modifiers without a side set return all sides on Linux GLFW', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sided modifiers without a side set return all sides on Linux GLFW', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -764,7 +765,7 @@ void main() { ); }, skip: isBrowser); // [intended] This is a GLFW-specific test. - testWidgets('sided modifiers without a side set return left sides on web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sided modifiers without a side set return left sides on web', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -797,7 +798,7 @@ void main() { ); }); - testWidgets('RawKeyboard asserts if no keys are in keysPressed after receiving a key down event', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RawKeyboard asserts if no keys are in keysPressed after receiving a key down event', (WidgetTester tester) async { final Map<String, dynamic> keyEventMessage; if (kIsWeb) { keyEventMessage = const <String, dynamic>{ @@ -833,7 +834,7 @@ void main() { ); }); - testWidgets('Allows inconsistent modifier for iOS', (WidgetTester _) async { + testWidgetsWithLeakTracking('Allows inconsistent modifier for iOS', (WidgetTester _) async { // Use `testWidgets` for clean-ups. final List<RawKeyEvent> events = <RawKeyEvent>[]; RawKeyboard.instance.addListener(events.add); @@ -861,7 +862,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, contains(LogicalKeyboardKey.capsLock)); }, skip: isBrowser); // [intended] This is an iOS-specific group. - testWidgets('Allows inconsistent modifier for Android', (WidgetTester _) async { + testWidgetsWithLeakTracking('Allows inconsistent modifier for Android', (WidgetTester _) async { // Use `testWidgets` for clean-ups. final List<RawKeyEvent> events = <RawKeyEvent>[]; RawKeyboard.instance.addListener(events.add); @@ -892,7 +893,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, contains(LogicalKeyboardKey.capsLock)); }, skip: isBrowser); // [intended] This is an Android-specific group. - testWidgets('Allows inconsistent modifier for Web - Alt graph', (WidgetTester _) async { + testWidgetsWithLeakTracking('Allows inconsistent modifier for Web - Alt graph', (WidgetTester _) async { // Regression test for https://github.com/flutter/flutter/issues/113836 final List<RawKeyEvent> events = <RawKeyEvent>[]; RawKeyboard.instance.addListener(events.add); @@ -921,7 +922,7 @@ void main() { expect(RawKeyboard.instance.keysPressed, contains(LogicalKeyboardKey.altGraph)); }, skip: !isBrowser); // [intended] This is a Browser-specific test. - testWidgets('Allows inconsistent modifier for Web - Alt right', (WidgetTester _) async { + testWidgetsWithLeakTracking('Allows inconsistent modifier for Web - Alt right', (WidgetTester _) async { // Regression test for https://github.com/flutter/flutter/issues/113836 final List<RawKeyEvent> events = <RawKeyEvent>[]; RawKeyboard.instance.addListener(events.add); @@ -950,8 +951,9 @@ void main() { expect(RawKeyboard.instance.keysPressed, contains(LogicalKeyboardKey.altRight)); }, skip: !isBrowser); // [intended] This is a Browser-specific test. - testWidgets('Dispatch events to all handlers', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dispatch events to all handlers', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final List<int> logs = <int>[]; await tester.pumpWidget( @@ -1014,7 +1016,7 @@ void main() { logs.clear(); }, variant: KeySimulatorTransitModeVariant.all()); - testWidgets('Exceptions from RawKeyboard listeners are caught and reported', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Exceptions from RawKeyboard listeners are caught and reported', (WidgetTester tester) async { void throwingListener(RawKeyEvent event) { throw 1; } @@ -1288,7 +1290,7 @@ void main() { expect(data.repeatCount, equals(42)); }); - testWidgets('Key events are responded to correctly.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Key events are responded to correctly.', (WidgetTester tester) async { expect(RawKeyboard.instance.keysPressed, isEmpty); // Generate the data for a regular key down event. final Map<String, dynamic> data = KeyEventSimulator.getKeyData( @@ -1308,6 +1310,7 @@ void main() { // Set up a widget that will receive focused text events. final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); await tester.pumpWidget( Focus( focusNode: focusNode, @@ -2098,7 +2101,7 @@ void main() { expect(data.logicalKey, equals(LogicalKeyboardKey.arrowLeft)); }); - testWidgets('Win32 VK_PROCESSKEY events are skipped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Win32 VK_PROCESSKEY events are skipped', (WidgetTester tester) async { const String platform = 'windows'; bool lastHandled = true; final List<RawKeyEvent> events = <RawKeyEvent>[]; @@ -2111,6 +2114,7 @@ void main() { return KeyEventResult.ignored; }, ); + addTearDown(node.dispose); await tester.pumpWidget(RawKeyboardListener( focusNode: node, child: Container(), From 237db2bb2aa70ec4e710c3587b53f47517c62c05 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:45:44 +0200 Subject: [PATCH 1379/1547] cover more tests with leak tracing (#134834) --- .../test/semantics/semantics_binding_test.dart | 7 ++++--- .../test/semantics/semantics_elevation_test.dart | 11 ++++++----- .../flutter/test/semantics/semantics_owner_test.dart | 3 ++- .../flutter/test/semantics/semantics_update_test.dart | 5 +++-- .../flutter/test/semantics/traversal_order_test.dart | 3 ++- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/flutter/test/semantics/semantics_binding_test.dart b/packages/flutter/test/semantics/semantics_binding_test.dart index 29f256ef53f77..380713692c283 100644 --- a/packages/flutter/test/semantics/semantics_binding_test.dart +++ b/packages/flutter/test/semantics/semantics_binding_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/semantics.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Listeners are called when semantics are turned on with ensureSemantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Listeners are called when semantics are turned on with ensureSemantics', (WidgetTester tester) async { expect(SemanticsBinding.instance.semanticsEnabled, isFalse); final List<bool> status = <bool>[]; @@ -43,7 +44,7 @@ void main() { expect(SemanticsBinding.instance.semanticsEnabled, isFalse); }, semanticsEnabled: false); - testWidgets('Listeners are called when semantics are turned on by platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Listeners are called when semantics are turned on by platform', (WidgetTester tester) async { expect(SemanticsBinding.instance.semanticsEnabled, isFalse); final List<bool> status = <bool>[]; @@ -69,7 +70,7 @@ void main() { expect(SemanticsBinding.instance.semanticsEnabled, isFalse); }, semanticsEnabled: false); - testWidgets('SemanticsBinding.ensureSemantics triggers creation of semantics owner.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsBinding.ensureSemantics triggers creation of semantics owner.', (WidgetTester tester) async { expect(SemanticsBinding.instance.semanticsEnabled, isFalse); expect(tester.binding.pipelineOwner.semanticsOwner, isNull); diff --git a/packages/flutter/test/semantics/semantics_elevation_test.dart b/packages/flutter/test/semantics/semantics_elevation_test.dart index 24c6918af2bdb..149101db2a837 100644 --- a/packages/flutter/test/semantics/semantics_elevation_test.dart +++ b/packages/flutter/test/semantics/semantics_elevation_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('SemanticsNodes overlapping in z', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNodes overlapping in z', (WidgetTester tester) async { // Cards are semantic boundaries that always own their own SemanticNode, // PhysicalModels merge their semantics information into parent. // @@ -97,7 +98,7 @@ void main() { semantics.dispose(); }); - testWidgets('SemanticsNodes overlapping in z with switched children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNodes overlapping in z with switched children', (WidgetTester tester) async { // Same as 'SemanticsNodes overlapping in z', but the order of children // is reversed @@ -173,7 +174,7 @@ void main() { semantics.dispose(); }); - testWidgets('single node thickness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('single node thickness', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(const MaterialApp( @@ -193,7 +194,7 @@ void main() { semantics.dispose(); }); - testWidgets('force-merge', (WidgetTester tester) async { + testWidgetsWithLeakTracking('force-merge', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( @@ -247,7 +248,7 @@ void main() { semantics.dispose(); }); - testWidgets('force-merge with inversed children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('force-merge with inversed children', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(MaterialApp( diff --git a/packages/flutter/test/semantics/semantics_owner_test.dart b/packages/flutter/test/semantics/semantics_owner_test.dart index 18c93f5eb62ed..c8f59f19df493 100644 --- a/packages/flutter/test/semantics/semantics_owner_test.dart +++ b/packages/flutter/test/semantics/semantics_owner_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('Performing SemanticsAction.showOnScreen does not crash if node no longer exist', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Performing SemanticsAction.showOnScreen does not crash if node no longer exist', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/100358. final SemanticsTester semantics = SemanticsTester(tester); diff --git a/packages/flutter/test/semantics/semantics_update_test.dart b/packages/flutter/test/semantics/semantics_update_test.dart index e5a41228b13ed..42708c877974c 100644 --- a/packages/flutter/test/semantics/semantics_update_test.dart +++ b/packages/flutter/test/semantics/semantics_update_test.dart @@ -8,11 +8,12 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/semantics.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { SemanticsUpdateTestBinding(); - testWidgets('Semantics update does not send update for merged nodes.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics update does not send update for merged nodes.', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); // Pumps a placeholder to trigger the warm up frame. await tester.pumpWidget( @@ -85,7 +86,7 @@ void main() { handle.dispose(); }); - testWidgets('Semantics update receives attributed text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Semantics update receives attributed text', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); // Pumps a placeholder to trigger the warm up frame. await tester.pumpWidget( diff --git a/packages/flutter/test/semantics/traversal_order_test.dart b/packages/flutter/test/semantics/traversal_order_test.dart index 2b469bb1139a4..5bc8981463ad2 100644 --- a/packages/flutter/test/semantics/traversal_order_test.dart +++ b/packages/flutter/test/semantics/traversal_order_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; void main() { - testWidgets('Traversal order handles touching elements', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Traversal order handles touching elements', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( MaterialApp( From a0406cccb1a8425b6939c2058170e96712caee51 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:46:14 +0200 Subject: [PATCH 1380/1547] Mark ReastaurationManager not disposed (#134832) --- packages/flutter/test/services/restoration_test.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/flutter/test/services/restoration_test.dart b/packages/flutter/test/services/restoration_test.dart index 7e872c5e215d0..c82224ac59a98 100644 --- a/packages/flutter/test/services/restoration_test.dart +++ b/packages/flutter/test/services/restoration_test.dart @@ -18,7 +18,7 @@ void main() { }); group('RestorationManager', () { - testWidgets('root bucket retrieval', (WidgetTester tester) async { + testWidgetsWithLeakTracking('root bucket retrieval', (WidgetTester tester) async { final List<MethodCall> callsToEngine = <MethodCall>[]; final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>(); tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) { @@ -62,7 +62,11 @@ void main() { }); expect(synchronousBucket, isNotNull); expect(synchronousBucket, same(rootBucket)); - }); + }, + // TODO(NobodyForNothing): Remove after fixing and cover remaining file + // with leak tests https://github.com/flutter/flutter/issues/134831 + leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: + <String, int?>{'RestorationManager': 1})); testWidgets('root bucket received from engine before retrieval', (WidgetTester tester) async { SystemChannels.restoration.setMethodCallHandler(null); From f92884c7b846d0fde13a8c332ac648977fc9b631 Mon Sep 17 00:00:00 2001 From: Jia Hao <jiahaog@users.noreply.github.com> Date: Thu, 21 Sep 2023 00:20:09 +0000 Subject: [PATCH 1381/1547] Rename `debugProfilePlatformChannels` to a constant that works in release mode (#134922) When it comes to startup profiling, it is very helpful to look at platform channels. `debugProfilePlatformChannels` today only works in debug and profile mode. Unfortunately, using profile mode is less accurate for startup profiling, because of the service isolate introducing additional overhead. This PR allows this toggle to work in release mode. Note that there are two parts to `debugProfilePlatformChannels`: - Adding timeline events - Logging statistics about platform channels I also considered adding a separate toggle to limit the scope of this change to the former, but that seems like complexity that we might not need at this time. Towards #102189 --- packages/flutter/lib/src/services/debug.dart | 14 +---- .../lib/src/services/platform_channel.dart | 56 ++++++++++--------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/packages/flutter/lib/src/services/debug.dart b/packages/flutter/lib/src/services/debug.dart index 518c29c5359bf..ce63157aaf760 100644 --- a/packages/flutter/lib/src/services/debug.dart +++ b/packages/flutter/lib/src/services/debug.dart @@ -15,18 +15,6 @@ export 'hardware_keyboard.dart' show KeyDataTransitMode; /// of their extent of support for keyboard API. KeyDataTransitMode? debugKeyEventSimulatorTransitModeOverride; -/// Profile and print statistics on Platform Channel usage. -/// -/// When this is true statistics about the usage of Platform Channels will be -/// printed out periodically to the console and Timeline events will show the -/// time between sending and receiving a message (encoding and decoding time -/// excluded). -/// -/// The statistics include the total bytes transmitted and the average number of -/// bytes per invocation in the last quantum. "Up" means in the direction of -/// Flutter to the host platform, "down" is the host platform to flutter. -bool debugProfilePlatformChannels = false; - /// Setting to true will cause extensive logging to occur when key events are /// received. /// @@ -46,7 +34,7 @@ bool debugAssertAllServicesVarsUnset(String reason) { if (debugKeyEventSimulatorTransitModeOverride != null) { throw FlutterError(reason); } - if (debugProfilePlatformChannels || debugPrintKeyboardEvents) { + if (debugPrintKeyboardEvents) { throw FlutterError(reason); } return true; diff --git a/packages/flutter/lib/src/services/platform_channel.dart b/packages/flutter/lib/src/services/platform_channel.dart index 2e1308d2811c4..cba9e1654d4a0 100644 --- a/packages/flutter/lib/src/services/platform_channel.dart +++ b/packages/flutter/lib/src/services/platform_channel.dart @@ -12,7 +12,6 @@ import '_background_isolate_binary_messenger_io.dart' import 'binary_messenger.dart'; import 'binding.dart'; -import 'debug.dart' show debugProfilePlatformChannels; import 'message_codec.dart'; import 'message_codecs.dart'; @@ -23,9 +22,21 @@ export 'binary_messenger.dart' show BinaryMessenger; export 'binding.dart' show RootIsolateToken; export 'message_codec.dart' show MessageCodec, MethodCall, MethodCodec; -bool _debugProfilePlatformChannelsIsRunning = false; -const Duration _debugProfilePlatformChannelsRate = Duration(seconds: 1); -final Expando<BinaryMessenger> _debugBinaryMessengers = Expando<BinaryMessenger>(); +/// Profile and print statistics on Platform Channel usage. +/// +/// When this is true statistics about the usage of Platform Channels will be +/// printed out periodically to the console and Timeline events will show the +/// time between sending and receiving a message (encoding and decoding time +/// excluded). +/// +/// The statistics include the total bytes transmitted and the average number of +/// bytes per invocation in the last quantum. "Up" means in the direction of +/// Flutter to the host platform, "down" is the host platform to flutter. +const bool kProfilePlatformChannels = false; + +bool _profilePlatformChannelsIsRunning = false; +const Duration _profilePlatformChannelsRate = Duration(seconds: 1); +final Expando<BinaryMessenger> _profiledBinaryMessengers = Expando<BinaryMessenger>(); class _ProfiledBinaryMessenger implements BinaryMessenger { const _ProfiledBinaryMessenger(this.proxy, this.channelTypeName, this.codecTypeName); @@ -40,17 +51,12 @@ class _ProfiledBinaryMessenger implements BinaryMessenger { Future<ByteData?>? sendWithPostfix(String channel, String postfix, ByteData? message) async { _debugRecordUpStream(channelTypeName, '$channel$postfix', codecTypeName, message); - TimelineTask? debugTimelineTask; - if (!kReleaseMode) { - debugTimelineTask = TimelineTask()..start('Platform Channel send $channel$postfix'); - } + final TimelineTask timelineTask = TimelineTask()..start('Platform Channel send $channel$postfix'); final ByteData? result; try { result = await proxy.send(channel, message); } finally { - if (!kReleaseMode) { - debugTimelineTask!.finish(); - } + timelineTask.finish(); } _debugRecordDownStream(channelTypeName, '$channel$postfix', codecTypeName, result); return result; @@ -93,17 +99,17 @@ class _PlatformChannelStats { double get averageDownPayload => _downBytes / _downCount; } -final Map<String, _PlatformChannelStats> _debugProfilePlatformChannelsStats = <String, _PlatformChannelStats>{}; +final Map<String, _PlatformChannelStats> _profilePlatformChannelsStats = <String, _PlatformChannelStats>{}; Future<void> _debugLaunchProfilePlatformChannels() async { - if (!_debugProfilePlatformChannelsIsRunning) { - _debugProfilePlatformChannelsIsRunning = true; - await Future<dynamic>.delayed(_debugProfilePlatformChannelsRate); - _debugProfilePlatformChannelsIsRunning = false; + if (!_profilePlatformChannelsIsRunning) { + _profilePlatformChannelsIsRunning = true; + await Future<dynamic>.delayed(_profilePlatformChannelsRate); + _profilePlatformChannelsIsRunning = false; final StringBuffer log = StringBuffer(); log.writeln('Platform Channel Stats:'); final List<_PlatformChannelStats> allStats = - _debugProfilePlatformChannelsStats.values.toList(); + _profilePlatformChannelsStats.values.toList(); // Sort highest combined bandwidth first. allStats.sort((_PlatformChannelStats x, _PlatformChannelStats y) => (y.upBytes + y.downBytes) - (x.upBytes + x.downBytes)); @@ -112,14 +118,14 @@ Future<void> _debugLaunchProfilePlatformChannels() async { ' (name:"${stats.channel}" type:"${stats.type}" codec:"${stats.codec}" upBytes:${stats.upBytes} upBytes_avg:${stats.averageUpPayload.toStringAsFixed(1)} downBytes:${stats.downBytes} downBytes_avg:${stats.averageDownPayload.toStringAsFixed(1)})'); } debugPrint(log.toString()); - _debugProfilePlatformChannelsStats.clear(); + _profilePlatformChannelsStats.clear(); } } void _debugRecordUpStream(String channelTypeName, String name, String codecTypeName, ByteData? bytes) { final _PlatformChannelStats stats = - _debugProfilePlatformChannelsStats[name] ??= + _profilePlatformChannelsStats[name] ??= _PlatformChannelStats(name, codecTypeName, channelTypeName); stats.addUpStream(bytes?.lengthInBytes ?? 0); _debugLaunchProfilePlatformChannels(); @@ -128,7 +134,7 @@ void _debugRecordUpStream(String channelTypeName, String name, void _debugRecordDownStream(String channelTypeName, String name, String codecTypeName, ByteData? bytes) { final _PlatformChannelStats stats = - _debugProfilePlatformChannelsStats[name] ??= + _profilePlatformChannelsStats[name] ??= _PlatformChannelStats(name, codecTypeName, channelTypeName); stats.addDownStream(bytes?.lengthInBytes ?? 0); _debugLaunchProfilePlatformChannels(); @@ -184,8 +190,8 @@ class BasicMessageChannel<T> { /// [BackgroundIsolateBinaryMessenger.ensureInitialized]. BinaryMessenger get binaryMessenger { final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger(); - return !kReleaseMode && debugProfilePlatformChannels - ? _debugBinaryMessengers[this] ??= _ProfiledBinaryMessenger( + return kProfilePlatformChannels + ? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger( // ignore: no_runtimetype_tostring result, runtimeType.toString(), codec.runtimeType.toString()) : result; @@ -273,8 +279,8 @@ class MethodChannel { /// [BackgroundIsolateBinaryMessenger.ensureInitialized]. BinaryMessenger get binaryMessenger { final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger(); - return !kReleaseMode && debugProfilePlatformChannels - ? _debugBinaryMessengers[this] ??= _ProfiledBinaryMessenger( + return kProfilePlatformChannels + ? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger( // ignore: no_runtimetype_tostring result, runtimeType.toString(), codec.runtimeType.toString()) : result; @@ -304,7 +310,7 @@ class MethodChannel { Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async { final ByteData input = codec.encodeMethodCall(MethodCall(method, arguments)); final ByteData? result = - !kReleaseMode && debugProfilePlatformChannels ? + kProfilePlatformChannels ? await (binaryMessenger as _ProfiledBinaryMessenger).sendWithPostfix(name, '#$method', input) : await binaryMessenger.send(name, input); if (result == null) { From c416aa4735069ab91b3991f3b45919b329177462 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 20 Sep 2023 23:09:24 -0400 Subject: [PATCH 1382/1547] Roll Flutter Engine from 89d864552acd to 76e5e35ab395 (21 revisions) (#135192) https://github.com/flutter/engine/compare/89d864552acd...76e5e35ab395 2023-09-21 matanlurey@users.noreply.github.com Tidy up `DlPaint` and friends. (flutter/engine#46120) 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from 86f48da2c812 to a7bcbb9a39f3 (1 revision) (flutter/engine#46128) 2023-09-21 30870216+gaaclarke@users.noreply.github.com [Impeller] removed global mutable variable for tessellation allocation function pointers (flutter/engine#46127) 2023-09-20 jonahwilliams@google.com [Impeller] Remove removal of save layer from clip. (flutter/engine#46113) 2023-09-20 jason-simmons@users.noreply.github.com [Impeller] Apply the entity transformation when rendering FramebufferBlendContents (flutter/engine#46106) 2023-09-20 matanlurey@users.noreply.github.com Clang tidy-ify `DlColor` and friends. (flutter/engine#46122) 2023-09-20 godofredoc@google.com Apply the right tag for linux fuchsia cipd packages. (flutter/engine#46123) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from b78c91996051 to 86f48da2c812 (4 revisions) (flutter/engine#46121) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from d923bab3d5fa to b78c91996051 (4 revisions) (flutter/engine#46119) 2023-09-20 matanlurey@users.noreply.github.com Make `dl_color_(filter|source)` tidy. (flutter/engine#46111) 2023-09-20 matanlurey@users.noreply.github.com Make `dl_(image|mask|path)_(filter|effect).h` tidy! (flutter/engine#46110) 2023-09-20 matanlurey@users.noreply.github.com Migrate from `LOG_X` to `kLogX`. (flutter/engine#46107) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from b3c1f49821d8 to d923bab3d5fa (2 revisions) (flutter/engine#46118) 2023-09-20 matanlurey@users.noreply.github.com Make a variety of low-impact Clang tidy fixes in Impeller. (flutter/engine#46116) 2023-09-20 ychris@google.com [ios] fix asset url not found when loading app extension (flutter/engine#46073) 2023-09-20 matanlurey@users.noreply.github.com Make a variety of low-impact Clang tidy fixes. (flutter/engine#46114) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from c19115e8f712 to b3c1f49821d8 (3 revisions) (flutter/engine#46112) 2023-09-20 skia-flutter-autoroll@skia.org Roll Skia from f4238844089f to c19115e8f712 (5 revisions) (flutter/engine#46108) 2023-09-20 mdebbar@google.com [web] Move context menu handling to its own class (flutter/engine#46042) 2023-09-20 matanlurey@users.noreply.github.com Delete `ci/lint.sh`, which is no longer used. (flutter/engine#46049) 2023-09-20 mdebbar@google.com [web] Make `PlatformViewManager` a clear singleton (flutter/engine#46044) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5e4c0c3c918d3..178fce31c5ee4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -89d864552acdd55c4fa175a9e2c1c809135a7174 +76e5e35ab3954c2b4f07e374b9d89a28f1442f8c From b90a13f3a1383229daf7a3f9e696e966391dba59 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 00:44:25 -0400 Subject: [PATCH 1383/1547] Roll Flutter Engine from 76e5e35ab395 to 88aad1056781 (1 revision) (#135198) https://github.com/flutter/engine/compare/76e5e35ab395...88aad1056781 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from a7bcbb9a39f3 to 81b9c7fd19b2 (1 revision) (flutter/engine#46129) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 178fce31c5ee4..1c196fd3492a5 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -76e5e35ab3954c2b4f07e374b9d89a28f1442f8c +88aad105678119ff2a8b6c2267f11af36480c75f From 518b77519187a7cb93eab3b113b13c7406a05e00 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 01:48:26 -0400 Subject: [PATCH 1384/1547] Roll Flutter Engine from 88aad1056781 to 3e66ffa6aae6 (2 revisions) (#135200) https://github.com/flutter/engine/compare/88aad1056781...3e66ffa6aae6 2023-09-21 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from zuOP7YCHHocXuZJcD... to 3DKf4d8UFviYKRI28... (flutter/engine#46133) 2023-09-21 jonahwilliams@google.com [Impeller] temp work around for cmd pool validation issues. (flutter/engine#46131) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from zuOP7YCHHocX to 3DKf4d8UFviY If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1c196fd3492a5..79a9587d2b294 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -88aad105678119ff2a8b6c2267f11af36480c75f +3e66ffa6aae64384a6f4b0fac7da4ff565c00c17 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 27699de91e60d..4569c4540f718 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -zuOP7YCHHocXuZJcDIxnlpB-rNuuZrNvIw4FuTNHV5gC +3DKf4d8UFviYKRI289TgMqMOusKtYENjbSeT4i3xySIC From 07cc3f7a617e435b0718c7b4ad1206816d780e53 Mon Sep 17 00:00:00 2001 From: Bruno Leroux <leroux_bruno@yahoo.fr> Date: Thu, 21 Sep 2023 07:54:19 +0200 Subject: [PATCH 1385/1547] Form fields onChange callback should be called on reset (#134295) ## Description This PR fixes form fields in order to call the `onChange` callback when the form is reset. This change is based on the work done in https://github.com/flutter/flutter/pull/123108. I considered adding the `onChange` callback to the `FormField` superclass but it would break existing code because two of the three subclasses defines the `onChange` callback with `ValueChanged<String>?` type and the third one defines it with `ValueChanged<String?>?`. ## Related Issue Fixes https://github.com/flutter/flutter/issues/123009. ## Tests Adds 3 tests. --- .../src/cupertino/text_form_field_row.dart | 19 +++--- .../flutter/lib/src/material/dropdown.dart | 11 +++- .../lib/src/material/text_form_field.dart | 17 +++-- .../cupertino/text_form_field_row_test.dart | 39 ++++++++++++ .../material/dropdown_form_field_test.dart | 48 ++++++++++++++ .../test/material/text_form_field_test.dart | 62 +++++++++++++++++++ 6 files changed, 177 insertions(+), 19 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_form_field_row.dart b/packages/flutter/lib/src/cupertino/text_form_field_row.dart index 674c62237ed5d..5f9c951ebd4dc 100644 --- a/packages/flutter/lib/src/cupertino/text_form_field_row.dart +++ b/packages/flutter/lib/src/cupertino/text_form_field_row.dart @@ -133,7 +133,7 @@ class CupertinoTextFormFieldRow extends FormField<String> { int? minLines, bool expands = false, int? maxLength, - ValueChanged<String>? onChanged, + this.onChanged, GestureTapCallback? onTap, VoidCallback? onEditingComplete, ValueChanged<String>? onFieldSubmitted, @@ -179,9 +179,7 @@ class CupertinoTextFormFieldRow extends FormField<String> { void onChangedHandler(String value) { field.didChange(value); - if (onChanged != null) { - onChanged(value); - } + onChanged?.call(value); } return CupertinoFormRow( @@ -260,6 +258,9 @@ class CupertinoTextFormFieldRow extends FormField<String> { /// initialize its [TextEditingController.text] with [initialValue]. final TextEditingController? controller; + /// {@macro flutter.material.TextFormField.onChanged} + final ValueChanged<String>? onChanged; + static Widget _defaultContextMenuBuilder(BuildContext context, EditableTextState editableTextState) { return CupertinoAdaptiveTextSelectionToolbar.editableText( editableTextState: editableTextState, @@ -328,13 +329,11 @@ class _CupertinoTextFormFieldRowState extends FormFieldState<String> { @override void reset() { + // Set the controller value before calling super.reset() to let + // _handleControllerChanged suppress the change. + _effectiveController!.text = widget.initialValue!; super.reset(); - - if (widget.initialValue != null) { - setState(() { - _effectiveController!.text = widget.initialValue!; - }); - } + _cupertinoTextFormFieldRow.onChanged?.call(_effectiveController!.text); } void _handleControllerChanged() { diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart index a72eba1b90ad8..719488109270d 100644 --- a/packages/flutter/lib/src/material/dropdown.dart +++ b/packages/flutter/lib/src/material/dropdown.dart @@ -1736,13 +1736,12 @@ class DropdownButtonFormField<T> extends FormField<T> { } class _DropdownButtonFormFieldState<T> extends FormFieldState<T> { + DropdownButtonFormField<T> get _dropdownButtonFormField => widget as DropdownButtonFormField<T>; @override void didChange(T? value) { super.didChange(value); - final DropdownButtonFormField<T> dropdownButtonFormField = widget as DropdownButtonFormField<T>; - assert(dropdownButtonFormField.onChanged != null); - dropdownButtonFormField.onChanged!(value); + _dropdownButtonFormField.onChanged!(value); } @override @@ -1752,4 +1751,10 @@ class _DropdownButtonFormFieldState<T> extends FormFieldState<T> { setValue(widget.initialValue); } } + + @override + void reset() { + super.reset(); + _dropdownButtonFormField.onChanged!(value); + } } diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart index b388d932aa8e2..a283b96915167 100644 --- a/packages/flutter/lib/src/material/text_form_field.dart +++ b/packages/flutter/lib/src/material/text_form_field.dart @@ -131,7 +131,7 @@ class TextFormField extends FormField<String> { int? minLines, bool expands = false, int? maxLength, - ValueChanged<String>? onChanged, + this.onChanged, GestureTapCallback? onTap, TapRegionCallback? onTapOutside, VoidCallback? onEditingComplete, @@ -193,9 +193,7 @@ class TextFormField extends FormField<String> { .applyDefaults(Theme.of(field.context).inputDecorationTheme); void onChangedHandler(String value) { field.didChange(value); - if (onChanged != null) { - onChanged(value); - } + onChanged?.call(value); } return UnmanagedRestorationScope( bucket: field.bucket, @@ -272,6 +270,12 @@ class TextFormField extends FormField<String> { /// initialize its [TextEditingController.text] with [initialValue]. final TextEditingController? controller; + /// {@template flutter.material.TextFormField.onChanged} + /// Called when the user initiates a change to the TextField's + /// value: when they have inserted or deleted text or reset the form. + /// {@endtemplate} + final ValueChanged<String>? onChanged; + static Widget _defaultContextMenuBuilder(BuildContext context, EditableTextState editableTextState) { return AdaptiveTextSelectionToolbar.editableText( editableTextState: editableTextState, @@ -365,10 +369,11 @@ class _TextFormFieldState extends FormFieldState<String> { @override void reset() { - // setState will be called in the superclass, so even though state is being - // manipulated, no setState call is needed here. + // Set the controller value before calling super.reset() to let + // _handleControllerChanged suppress the change. _effectiveController.text = widget.initialValue ?? ''; super.reset(); + _textFormField.onChanged?.call(_effectiveController.text); } void _handleControllerChanged() { diff --git a/packages/flutter/test/cupertino/text_form_field_row_test.dart b/packages/flutter/test/cupertino/text_form_field_row_test.dart index ff48a0e2a8462..9ddff783b6cbd 100644 --- a/packages/flutter/test/cupertino/text_form_field_row_test.dart +++ b/packages/flutter/test/cupertino/text_form_field_row_test.dart @@ -490,4 +490,43 @@ void main() { final CupertinoTextField rtlTextFieldWidget = tester.widget(rtlTextFieldFinder); expect(rtlTextFieldWidget.textDirection, TextDirection.rtl); }); + + testWidgets('CupertinoTextFormFieldRow onChanged is called when the form is reset', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/123009. + final GlobalKey<FormFieldState<String>> stateKey = GlobalKey<FormFieldState<String>>(); + final GlobalKey<FormState> formKey = GlobalKey<FormState>(); + String value = 'initialValue'; + + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: Form( + key: formKey, + child: CupertinoTextFormFieldRow( + key: stateKey, + initialValue: value, + onChanged: (String newValue) { + value = newValue; + }, + ), + ), + ), + ), + ); + + // Initial value is 'initialValue'. + expect(stateKey.currentState!.value, 'initialValue'); + expect(value, 'initialValue'); + + // Change value to 'changedValue'. + await tester.enterText(find.byType(CupertinoTextField), 'changedValue'); + expect(stateKey.currentState!.value,'changedValue'); + expect(value, 'changedValue'); + + // Should be back to 'initialValue' when the form is reset. + formKey.currentState!.reset(); + await tester.pump(); + expect(stateKey.currentState!.value,'initialValue'); + expect(value, 'initialValue'); + }); } diff --git a/packages/flutter/test/material/dropdown_form_field_test.dart b/packages/flutter/test/material/dropdown_form_field_test.dart index 094c8cb30e735..6d8faf8b24a0a 100644 --- a/packages/flutter/test/material/dropdown_form_field_test.dart +++ b/packages/flutter/test/material/dropdown_form_field_test.dart @@ -1231,4 +1231,52 @@ void main() { inkWell = tester.widget<InkWell>(find.byType(InkWell)); expect(inkWell.borderRadius, errorBorderRadius); }); + + testWidgets('DropdownButtonFormField onChanged is called when the form is reset', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/123009. + final GlobalKey<FormFieldState<String>> stateKey = GlobalKey<FormFieldState<String>>(); + final GlobalKey<FormState> formKey = GlobalKey<FormState>(); + String? value; + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Form( + key: formKey, + child: DropdownButtonFormField<String>( + key: stateKey, + value: 'One', + items: <String>['One', 'Two', 'Free', 'Four'] + .map<DropdownMenuItem<String>>((String value) { + return DropdownMenuItem<String>( + value: value, + child: Text(value), + ); + }).toList(), + onChanged: (String? newValue) { + value = newValue; + }, + ), + ), + ), + ), + ); + + // Initial value is 'One'. + expect(value, isNull); + expect(stateKey.currentState!.value, equals('One')); + + // Select 'Two'. + await tester.tap(find.text('One')); + await tester.pumpAndSettle(); + await tester.tap(find.text('Two').last); + await tester.pumpAndSettle(); + expect(value, equals('Two')); + expect(stateKey.currentState!.value, equals('Two')); + + // Should be back to 'One' when the form is reset. + formKey.currentState!.reset(); + expect(value, equals('One')); + expect(stateKey.currentState!.value, equals('One')); + }); } diff --git a/packages/flutter/test/material/text_form_field_test.dart b/packages/flutter/test/material/text_form_field_test.dart index 9d52c9c0de45d..b3bdc07fc76b8 100644 --- a/packages/flutter/test/material/text_form_field_test.dart +++ b/packages/flutter/test/material/text_form_field_test.dart @@ -816,6 +816,31 @@ void main() { expect(find.text('initialValue'), findsOneWidget); }); + testWidgetsWithLeakTracking('reset resets the text fields value to the controller initial value', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(text: 'initialValue'); + addTearDown(controller.dispose); + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: TextFormField( + controller: controller, + ), + ), + ), + ), + ); + + await tester.enterText(find.byType(TextFormField), 'changedValue'); + + final FormFieldState<String> state = tester.state<FormFieldState<String>>(find.byType(TextFormField)); + state.reset(); + + expect(find.text('changedValue'), findsNothing); + expect(find.text('initialValue'), findsOneWidget); + }); + // Regression test for https://github.com/flutter/flutter/issues/34847. testWidgetsWithLeakTracking("didChange resets the text field's value to empty when passed null", (WidgetTester tester) async { await tester.pumpWidget( @@ -1478,4 +1503,41 @@ void main() { await tester.pump(); expect(textField.cursorColor, errorColor); }); + + testWidgetsWithLeakTracking('TextFormField onChanged is called when the form is reset', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/123009. + final GlobalKey<FormFieldState<String>> stateKey = GlobalKey<FormFieldState<String>>(); + final GlobalKey<FormState> formKey = GlobalKey<FormState>(); + String value = 'initialValue'; + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + body: Form( + key: formKey, + child: TextFormField( + key: stateKey, + initialValue: value, + onChanged: (String newValue) { + value = newValue; + }, + ), + ), + ), + )); + + // Initial value is 'initialValue'. + expect(stateKey.currentState!.value, 'initialValue'); + expect(value, 'initialValue'); + + // Change value to 'changedValue'. + await tester.enterText(find.byType(TextField), 'changedValue'); + expect(stateKey.currentState!.value,'changedValue'); + expect(value, 'changedValue'); + + // Should be back to 'initialValue' when the form is reset. + formKey.currentState!.reset(); + await tester.pump(); + expect(stateKey.currentState!.value,'initialValue'); + expect(value, 'initialValue'); + }); } From 089e93a15c4529e8ef87eaf056a07e634c91f1da Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 03:38:23 -0400 Subject: [PATCH 1386/1547] Roll Flutter Engine from 3e66ffa6aae6 to a4b1ef79596a (1 revision) (#135206) https://github.com/flutter/engine/compare/3e66ffa6aae6...a4b1ef79596a 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from 81b9c7fd19b2 to c20aeee90da9 (3 revisions) (flutter/engine#46134) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 79a9587d2b294..8d62266d24be4 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3e66ffa6aae64384a6f4b0fac7da4ff565c00c17 +a4b1ef79596acf36fb707e9a9029237e47074bb8 From 687f9c867f04c9c7a5bfb7edc92e25cd52a24c80 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 06:53:27 -0400 Subject: [PATCH 1387/1547] Roll Flutter Engine from a4b1ef79596a to 584861202198 (2 revisions) (#135214) https://github.com/flutter/engine/compare/a4b1ef79596a...584861202198 2023-09-21 skia-flutter-autoroll@skia.org Roll Dart SDK from d5d05146868a to eaeca487c944 (2 revisions) (flutter/engine#46138) 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from c20aeee90da9 to 322abacca561 (1 revision) (flutter/engine#46137) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8d62266d24be4..8138065b11498 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -a4b1ef79596acf36fb707e9a9029237e47074bb8 +5848612021985e760187de3c13146295ac80ba4a From beeb3ce9233337d5b728dbf7a761e1a7372ffb39 Mon Sep 17 00:00:00 2001 From: derdilla <82763757+NobodyForNothing@users.noreply.github.com> Date: Thu, 21 Sep 2023 15:30:21 +0200 Subject: [PATCH 1388/1547] Cover some cupertino tests with leak tracing (#135149) --- .../flutter/test/cupertino/button_test.dart | 4 +- .../flutter/test/cupertino/colors_test.dart | 17 ++-- .../cupertino/context_menu_action_test.dart | 13 +-- .../test/cupertino/context_menu_test.dart | 37 ++++---- .../flutter/test/cupertino/debug_test.dart | 3 +- ...op_text_selection_toolbar_button_test.dart | 9 +- .../desktop_text_selection_toolbar_test.dart | 9 +- .../flutter/test/cupertino/form_row_test.dart | 19 ++-- .../test/cupertino/icon_theme_data_test.dart | 3 +- .../test/cupertino/list_section_test.dart | 23 ++--- .../test/cupertino/list_tile_test.dart | 45 ++++----- .../test/cupertino/localizations_test.dart | 5 +- .../cupertino/material/tab_scaffold_test.dart | 29 ++++-- .../flutter/test/cupertino/refresh_test.dart | 57 +++++------ .../flutter/test/cupertino/route_test.dart | 95 ++++++++++--------- .../test/cupertino/scrollbar_paint_test.dart | 7 +- .../cupertino/segmented_control_test.dart | 75 +++++++-------- .../flutter/test/cupertino/slider_test.dart | 29 +++--- packages/flutter/test/cupertino/tab_test.dart | 21 ++-- .../text_field_restoration_test.dart | 5 +- .../text_selection_toolbar_button_test.dart | 7 +- .../text_selection_toolbar_test.dart | 15 +-- .../flutter/test/cupertino/theme_test.dart | 25 ++--- 23 files changed, 291 insertions(+), 261 deletions(-) diff --git a/packages/flutter/test/cupertino/button_test.dart b/packages/flutter/test/cupertino/button_test.dart index b3587ae7fdd76..23640455febff 100644 --- a/packages/flutter/test/cupertino/button_test.dart +++ b/packages/flutter/test/cupertino/button_test.dart @@ -68,7 +68,7 @@ void main() { // TODO(LongCatIsLoong): Uncomment once https://github.com/flutter/flutter/issues/44115 // is fixed. /* - testWidgets( + testWidgetsWithLeakTracking( 'CupertinoButton.filled default color contrast meets guideline', (WidgetTester tester) async { // The native color combination systemBlue text over white background fails @@ -185,7 +185,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(1)); }); - testWidgets("Disabled button doesn't animate", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Disabled button doesn't animate", (WidgetTester tester) async { await tester.pumpWidget(boilerplate(child: const CupertinoButton( onPressed: null, child: Text('Tap me'), diff --git a/packages/flutter/test/cupertino/colors_test.dart b/packages/flutter/test/cupertino/colors_test.dart index f334426d29b78..a98a856a24d0d 100644 --- a/packages/flutter/test/cupertino/colors_test.dart +++ b/packages/flutter/test/cupertino/colors_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class DependentWidget extends StatelessWidget { const DependentWidget({ @@ -200,7 +201,7 @@ void main() { ); }); - testWidgets( + testWidgetsWithLeakTracking( 'Dynamic colors that are not actually dynamic should not claim dependencies', (WidgetTester tester) async { await tester.pumpWidget(const DependentWidget(color: notSoDynamicColor1)); @@ -210,7 +211,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Dynamic colors that are only dependent on vibrancy should not claim unnecessary dependencies, ' 'and its resolved color should change when its dependency changes', (WidgetTester tester) async { @@ -254,7 +255,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Dynamic colors that are only dependent on accessibility contrast should not claim unnecessary dependencies, ' 'and its resolved color should change when its dependency changes', (WidgetTester tester) async { @@ -283,7 +284,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Dynamic colors that are only dependent on elevation level should not claim unnecessary dependencies, ' 'and its resolved color should change when its dependency changes', (WidgetTester tester) async { @@ -312,7 +313,7 @@ void main() { }, ); - testWidgets('Dynamic color with all 3 dependencies works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dynamic color with all 3 dependencies works', (WidgetTester tester) async { const Color dynamicRainbowColor1 = CupertinoDynamicColor( color: color0, darkColor: color1, @@ -413,7 +414,7 @@ void main() { expect(find.byType(DependentWidget), paints..rect(color: color7)); }); - testWidgets('CupertinoDynamicColor used in a CupertinoTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoDynamicColor used in a CupertinoTheme', (WidgetTester tester) async { late CupertinoDynamicColor color; await tester.pumpWidget( CupertinoApp( @@ -498,7 +499,7 @@ void main() { Color? color; setUp(() { color = null; }); - testWidgets('dynamic color works in cupertino override theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dynamic color works in cupertino override theme', (WidgetTester tester) async { CupertinoDynamicColor typedColor() => color! as CupertinoDynamicColor; await tester.pumpWidget( @@ -555,7 +556,7 @@ void main() { expect(typedColor().value, dynamicColor.darkHighContrastElevatedColor.value); }); - testWidgets('dynamic color does not work in a material theme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dynamic color does not work in a material theme', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( // This will create a MaterialBasedCupertinoThemeData with primaryColor set to `dynamicColor`. diff --git a/packages/flutter/test/cupertino/context_menu_action_test.dart b/packages/flutter/test/cupertino/context_menu_action_test.dart index ad6a52b9c313e..535d502a69a94 100644 --- a/packages/flutter/test/cupertino/context_menu_action_test.dart +++ b/packages/flutter/test/cupertino/context_menu_action_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { // Constants taken from _ContextMenuActionState. @@ -71,7 +72,7 @@ void main() { return icon; } - testWidgets('responds to taps', (WidgetTester tester) async { + testWidgetsWithLeakTracking('responds to taps', (WidgetTester tester) async { bool wasPressed = false; await tester.pumpWidget(getApp(onPressed: () { wasPressed = true; @@ -82,7 +83,7 @@ void main() { expect(wasPressed, true); }); - testWidgets('turns grey when pressed and held', (WidgetTester tester) async { + testWidgetsWithLeakTracking('turns grey when pressed and held', (WidgetTester tester) async { await tester.pumpWidget(getApp()); expect(find.byType(CupertinoContextMenuAction), paints..rect(color: kBackgroundColor.color)); @@ -117,27 +118,27 @@ void main() { paints..rect(color: kBackgroundColor.darkColor)); }); - testWidgets('icon and textStyle colors are correct out of the box', + testWidgetsWithLeakTracking('icon and textStyle colors are correct out of the box', (WidgetTester tester) async { await tester.pumpWidget(getApp()); expect(getTextStyle(tester).color, CupertinoColors.label); expect(getIcon(tester).color, CupertinoColors.label); }); - testWidgets('icon and textStyle colors are correct for destructive actions', + testWidgetsWithLeakTracking('icon and textStyle colors are correct for destructive actions', (WidgetTester tester) async { await tester.pumpWidget(getApp(isDestructiveAction: true)); expect(getTextStyle(tester).color, kDestructiveActionColor); expect(getIcon(tester).color, kDestructiveActionColor); }); - testWidgets('textStyle is correct for defaultAction', + testWidgetsWithLeakTracking('textStyle is correct for defaultAction', (WidgetTester tester) async { await tester.pumpWidget(getApp(isDefaultAction: true)); expect(getTextStyle(tester).fontWeight, kDefaultActionWeight); }); - testWidgets( + testWidgetsWithLeakTracking( 'Hovering over Cupertino context menu action updates cursor to clickable on Web', (WidgetTester tester) async { /// Cupertino context menu action without "onPressed" callback. diff --git a/packages/flutter/test/cupertino/context_menu_test.dart b/packages/flutter/test/cupertino/context_menu_test.dart index 06817cbb3b67b..c6874be188f83 100644 --- a/packages/flutter/test/cupertino/context_menu_test.dart +++ b/packages/flutter/test/cupertino/context_menu_test.dart @@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized(); @@ -120,7 +121,7 @@ void main() { } group('CupertinoContextMenu before and during opening', () { - testWidgets('An unopened CupertinoContextMenu renders child in the same place as without', (WidgetTester tester) async { + testWidgetsWithLeakTracking('An unopened CupertinoContextMenu renders child in the same place as without', (WidgetTester tester) async { // Measure the child in the scene with no CupertinoContextMenu. final Widget child = getChild(); await tester.pumpWidget( @@ -140,7 +141,7 @@ void main() { expect(tester.getRect(find.byWidget(child)), childRect); }); - testWidgets('Can open CupertinoContextMenu by tap and hold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can open CupertinoContextMenu by tap and hold', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); expect(find.byWidget(child), findsOneWidget); @@ -176,7 +177,7 @@ void main() { expect(findStatic(), findsOneWidget); }); - testWidgets('CupertinoContextMenu is in the correct position when within a nested navigator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoContextMenu is in the correct position when within a nested navigator', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(CupertinoApp( home: CupertinoPageScaffold( @@ -241,7 +242,7 @@ void main() { expect(findStatic(), findsOneWidget); }); - testWidgets('CupertinoContextMenu with a basic builder opens and closes the same as when providing a child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoContextMenu with a basic builder opens and closes the same as when providing a child', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getBuilderContextMenu(builder: (BuildContext context, Animation<double> animation) { return child; @@ -279,7 +280,7 @@ void main() { expect(findStatic(), findsOneWidget); }); - testWidgets('CupertinoContextMenu with a builder can change the animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoContextMenu with a builder can change the animation', (WidgetTester tester) async { await tester.pumpWidget(getBuilderContextMenu(builder: (BuildContext context, Animation<double> animation) { return Container( width: 300.0, @@ -319,7 +320,7 @@ void main() { expect(decoyLaterDecoration?.borderRadius, isNot(equals(BorderRadius.circular(0)))); }); - testWidgets('Hovering over Cupertino context menu updates cursor to clickable on Web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovering over Cupertino context menu updates cursor to clickable on Web', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(CupertinoApp( home: CupertinoPageScaffold( @@ -350,7 +351,7 @@ void main() { ); }); - testWidgets('CupertinoContextMenu is in the correct position when within a Transform.scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoContextMenu is in the correct position when within a Transform.scale', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(CupertinoApp( home: CupertinoPageScaffold( @@ -408,7 +409,7 @@ void main() { }); group('CupertinoContextMenu when open', () { - testWidgets('Last action does not have border', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Last action does not have border', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(CupertinoApp( home: CupertinoPageScaffold( @@ -467,7 +468,7 @@ void main() { expect(findStaticChildDecoration(tester), findsNWidgets(3)); }); - testWidgets('Can close CupertinoContextMenu by background tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can close CupertinoContextMenu by background tap', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); @@ -485,7 +486,7 @@ void main() { expect(findStatic(), findsNothing); }); - testWidgets('Can close CupertinoContextMenu by dragging down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can close CupertinoContextMenu by dragging down', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); @@ -527,7 +528,7 @@ void main() { expect(findStatic(), findsNothing); }); - testWidgets('Can close CupertinoContextMenu by flinging down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can close CupertinoContextMenu by flinging down', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); @@ -552,7 +553,7 @@ void main() { expect(findStatic(), findsNothing); }); - testWidgets("Backdrop is added using ModalRoute's filter parameter", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Backdrop is added using ModalRoute's filter parameter", (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); expect(find.byType(BackdropFilter), findsNothing); @@ -567,7 +568,7 @@ void main() { expect(find.byType(BackdropFilter), findsOneWidget); }); - testWidgets('Preview widget should have the correct border radius', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Preview widget should have the correct border radius', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); @@ -585,7 +586,7 @@ void main() { expect(previewWidget.borderRadius, equals(BorderRadius.circular(12.0))); }); - testWidgets('CupertinoContextMenu width is correct', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoContextMenu width is correct', (WidgetTester tester) async { final Widget child = getChild(); await tester.pumpWidget(getContextMenu(child: child)); expect(find.byWidget(child), findsOneWidget); @@ -628,7 +629,7 @@ void main() { } }); - testWidgets("ContextMenu route animation doesn't throw exception on dismiss", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ContextMenu route animation doesn't throw exception on dismiss", (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/124597. final List<int> items = List<int>.generate(2, (int index) => index).toList(); @@ -675,7 +676,7 @@ void main() { }); group("Open layout differs depending on child's position on screen", () { - testWidgets('Portrait', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Portrait', (WidgetTester tester) async { const Size portraitScreenSize = Size(600.0, 800.0); await binding.setSurfaceSize(portraitScreenSize); @@ -747,7 +748,7 @@ void main() { await binding.setSurfaceSize(const Size(800.0, 600.0)); }); - testWidgets('Landscape', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Landscape', (WidgetTester tester) async { // Pump a CupertinoContextMenu in the center of the screen and open it. final Widget child = getChild(); await tester.pumpWidget(getContextMenu( @@ -812,7 +813,7 @@ void main() { }); }); - testWidgets('Conflicting gesture detectors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Conflicting gesture detectors', (WidgetTester tester) async { int? onPointerDownTime; int? onPointerUpTime; bool insideTapTriggered = false; diff --git a/packages/flutter/test/cupertino/debug_test.dart b/packages/flutter/test/cupertino/debug_test.dart index 85dca9e404539..f392a5a59ffb5 100644 --- a/packages/flutter/test/cupertino/debug_test.dart +++ b/packages/flutter/test/cupertino/debug_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('debugCheckHasCupertinoLocalizations throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugCheckHasCupertinoLocalizations throws', (WidgetTester tester) async { final GlobalKey noLocalizationsAvailable = GlobalKey(); final GlobalKey localizationsAvailable = GlobalKey(); diff --git a/packages/flutter/test/cupertino/desktop_text_selection_toolbar_button_test.dart b/packages/flutter/test/cupertino/desktop_text_selection_toolbar_button_test.dart index 4ca0433e3cf1e..107caba6f0e2f 100644 --- a/packages/flutter/test/cupertino/desktop_text_selection_toolbar_button_test.dart +++ b/packages/flutter/test/cupertino/desktop_text_selection_toolbar_button_test.dart @@ -5,11 +5,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('can press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can press', (WidgetTester tester) async { bool pressed = false; await tester.pumpWidget( CupertinoApp( @@ -30,7 +31,7 @@ void main() { expect(pressed, true); }); - testWidgets('keeps contrast with background on hover', + testWidgetsWithLeakTracking('keeps contrast with background on hover', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( @@ -70,7 +71,7 @@ void main() { ); }); - testWidgets('pressedOpacity defaults to 0.1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('pressedOpacity defaults to 0.1', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -114,7 +115,7 @@ void main() { expect(opacity.opacity.value, 1.0); }); - testWidgets('passing null to onPressed disables the button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing null to onPressed disables the button', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Center( diff --git a/packages/flutter/test/cupertino/desktop_text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/desktop_text_selection_toolbar_test.dart index c3519e6a8addf..3536d68de5863 100644 --- a/packages/flutter/test/cupertino/desktop_text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/desktop_text_selection_toolbar_test.dart @@ -7,11 +7,12 @@ import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('has correct backdrop filters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has correct backdrop filters', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -53,7 +54,7 @@ void main() { ); }); - testWidgets('has shadow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('has shadow', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -83,7 +84,7 @@ void main() { ); }); - testWidgets('is translucent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('is translucent', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -116,7 +117,7 @@ void main() { ); }); - testWidgets('positions itself at the anchor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positions itself at the anchor', (WidgetTester tester) async { // An arbitrary point on the screen to position at. const Offset anchor = Offset(30.0, 40.0); diff --git a/packages/flutter/test/cupertino/form_row_test.dart b/packages/flutter/test/cupertino/form_row_test.dart index 9cb079905a6dc..926f0002f9195 100644 --- a/packages/flutter/test/cupertino/form_row_test.dart +++ b/packages/flutter/test/cupertino/form_row_test.dart @@ -6,9 +6,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Shows prefix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows prefix', (WidgetTester tester) async { const Widget prefix = Text('Enter Value'); await tester.pumpWidget( @@ -25,7 +26,7 @@ void main() { expect(prefix, tester.widget(find.byType(Text))); }); - testWidgets('Shows child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows child', (WidgetTester tester) async { const Widget child = CupertinoTextField(); await tester.pumpWidget( @@ -41,7 +42,7 @@ void main() { expect(child, tester.widget(find.byType(CupertinoTextField))); }); - testWidgets('RTL puts prefix after child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RTL puts prefix after child', (WidgetTester tester) async { const Widget prefix = Text('Enter Value'); const Widget child = CupertinoTextField(); @@ -62,7 +63,7 @@ void main() { expect(tester.getTopLeft(find.byType(Text)).dx > tester.getTopLeft(find.byType(CupertinoTextField)).dx, true); }); - testWidgets('LTR puts child after prefix', (WidgetTester tester) async { + testWidgetsWithLeakTracking('LTR puts child after prefix', (WidgetTester tester) async { const Widget prefix = Text('Enter Value'); const Widget child = CupertinoTextField(); @@ -83,7 +84,7 @@ void main() { expect(tester.getTopLeft(find.byType(Text)).dx > tester.getTopLeft(find.byType(CupertinoTextField)).dx, false); }); - testWidgets('Shows error widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows error widget', (WidgetTester tester) async { const Widget error = Text('Error'); await tester.pumpWidget( @@ -100,7 +101,7 @@ void main() { expect(error, tester.widget(find.byType(Text))); }); - testWidgets('Shows helper widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows helper widget', (WidgetTester tester) async { const Widget helper = Text('Helper'); await tester.pumpWidget( @@ -117,7 +118,7 @@ void main() { expect(helper, tester.widget(find.byType(Text))); }); - testWidgets('Shows helper text above error text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows helper text above error text', (WidgetTester tester) async { const Widget helper = Text('Helper'); const Widget error = CupertinoActivityIndicator(); @@ -139,7 +140,7 @@ void main() { ); }); - testWidgets('Shows helper in label color and error text in red color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shows helper in label color and error text in red color', (WidgetTester tester) async { const Widget helper = Text('Helper'); const Widget error = Text('Error'); @@ -166,7 +167,7 @@ void main() { expect(errorTextStyle.style.color, CupertinoColors.destructiveRed); }); - testWidgets('CupertinoFormRow adapts to MaterialApp dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoFormRow adapts to MaterialApp dark mode', (WidgetTester tester) async { const Widget prefix = Text('Prefix'); const Widget helper = Text('Helper'); diff --git a/packages/flutter/test/cupertino/icon_theme_data_test.dart b/packages/flutter/test/cupertino/icon_theme_data_test.dart index dda4b4b5c11ba..75fff4b62ea0a 100644 --- a/packages/flutter/test/cupertino/icon_theme_data_test.dart +++ b/packages/flutter/test/cupertino/icon_theme_data_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('IconTheme.of works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme.of works', (WidgetTester tester) async { const IconThemeData data = IconThemeData( size: 16.0, fill: 0.0, diff --git a/packages/flutter/test/cupertino/list_section_test.dart b/packages/flutter/test/cupertino/list_section_test.dart index 735c9614ca9e7..0119947b5b668 100644 --- a/packages/flutter/test/cupertino/list_section_test.dart +++ b/packages/flutter/test/cupertino/list_section_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('shows header', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows header', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -23,7 +24,7 @@ void main() { expect(find.text('Header'), findsOneWidget); }); - testWidgets('shows footer', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows footer', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -40,7 +41,7 @@ void main() { expect(find.text('Footer'), findsOneWidget); }); - testWidgets('shows long dividers in edge-to-edge section part 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows long dividers in edge-to-edge section part 1', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -59,7 +60,7 @@ void main() { expect(childrenColumn.children.length, 3); }); - testWidgets('shows long dividers in edge-to-edge section part 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows long dividers in edge-to-edge section part 2', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -80,7 +81,7 @@ void main() { expect(childrenColumn.children.length, 5); }); - testWidgets('does not show long dividers in insetGrouped section part 1', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not show long dividers in insetGrouped section part 1', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -100,7 +101,7 @@ void main() { expect(childrenColumn.children.length, 1); }); - testWidgets('does not show long dividers in insetGrouped section part 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not show long dividers in insetGrouped section part 2', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -121,7 +122,7 @@ void main() { expect(childrenColumn.children.length, 3); }); - testWidgets('sets background color for section', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sets background color for section', (WidgetTester tester) async { const Color backgroundColor = CupertinoColors.systemBlue; await tester.pumpWidget( @@ -144,7 +145,7 @@ void main() { expect(boxDecoration.color, backgroundColor); }); - testWidgets('setting clipBehavior clips children section', (WidgetTester tester) async { + testWidgetsWithLeakTracking('setting clipBehavior clips children section', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -161,7 +162,7 @@ void main() { expect(find.byType(ClipRRect), findsOneWidget); }); - testWidgets('not setting clipBehavior does not clip children section', (WidgetTester tester) async { + testWidgetsWithLeakTracking('not setting clipBehavior does not clip children section', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -177,7 +178,7 @@ void main() { expect(find.byType(ClipRRect), findsNothing); }); - testWidgets('CupertinoListSection respects separatorColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoListSection respects separatorColor', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -200,7 +201,7 @@ void main() { } }); - testWidgets('CupertinoListSection.separatorColor defaults CupertinoColors.separator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoListSection.separatorColor defaults CupertinoColors.separator', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( diff --git a/packages/flutter/test/cupertino/list_tile_test.dart b/packages/flutter/test/cupertino/list_tile_test.dart index 9ff90e82faadf..0501613bbde49 100644 --- a/packages/flutter/test/cupertino/list_tile_test.dart +++ b/packages/flutter/test/cupertino/list_tile_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('shows title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows title', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); await tester.pumpWidget( @@ -23,7 +24,7 @@ void main() { expect(find.text('CupertinoListTile'), findsOneWidget); }); - testWidgets('shows subtitle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows subtitle', (WidgetTester tester) async { const Widget subtitle = Text('CupertinoListTile subtitle'); await tester.pumpWidget( @@ -41,7 +42,7 @@ void main() { expect(find.text('CupertinoListTile subtitle'), findsOneWidget); }); - testWidgets('shows additionalInfo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows additionalInfo', (WidgetTester tester) async { const Widget additionalInfo = Text('Not Connected'); await tester.pumpWidget( @@ -59,7 +60,7 @@ void main() { expect(find.text('Not Connected'), findsOneWidget); }); - testWidgets('shows trailing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows trailing', (WidgetTester tester) async { const Widget trailing = CupertinoListTileChevron(); await tester.pumpWidget( @@ -76,7 +77,7 @@ void main() { expect(tester.widget<CupertinoListTileChevron>(find.byType(CupertinoListTileChevron)), trailing); }); - testWidgets('shows leading', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shows leading', (WidgetTester tester) async { const Widget leading = Icon(CupertinoIcons.add); await tester.pumpWidget( @@ -93,7 +94,7 @@ void main() { expect(tester.widget<Icon>(find.byType(Icon)), leading); }); - testWidgets('sets backgroundColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sets backgroundColor', (WidgetTester tester) async { const Color backgroundColor = CupertinoColors.systemRed; await tester.pumpWidget( @@ -118,7 +119,7 @@ void main() { expect(container.color, backgroundColor); }); - testWidgets('does not change backgroundColor when tapped if onTap is not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not change backgroundColor when tapped if onTap is not provided', (WidgetTester tester) async { const Color backgroundColor = CupertinoColors.systemBlue; const Color backgroundColorActivated = CupertinoColors.systemRed; @@ -148,7 +149,7 @@ void main() { expect(container.color, backgroundColor); }); - testWidgets('changes backgroundColor when tapped if onTap is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('changes backgroundColor when tapped if onTap is provided', (WidgetTester tester) async { const Color backgroundColor = CupertinoColors.systemBlue; const Color backgroundColorActivated = CupertinoColors.systemRed; @@ -187,7 +188,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('does not contain GestureDetector if onTap is not provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not contain GestureDetector if onTap is not provided', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -208,7 +209,7 @@ void main() { expect(find.byType(GestureDetector), findsNothing); }); - testWidgets('contains GestureDetector if onTap is provided', (WidgetTester tester) async { + testWidgetsWithLeakTracking('contains GestureDetector if onTap is provided', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -230,7 +231,7 @@ void main() { expect(find.byType(GestureDetector), findsOneWidget); }); - testWidgets('resets the background color when navigated back', (WidgetTester tester) async { + testWidgetsWithLeakTracking('resets the background color when navigated back', (WidgetTester tester) async { const Color backgroundColor = CupertinoColors.systemBlue; const Color backgroundColorActivated = CupertinoColors.systemRed; @@ -279,7 +280,7 @@ void main() { }); group('alignment of widgets for left-to-right', () { - testWidgets('leading is on the left of title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('leading is on the left of title', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); const Widget leading = Icon(CupertinoIcons.add); @@ -303,7 +304,7 @@ void main() { expect(foundTitle.dx > foundLeading.dx, true); }); - testWidgets('subtitle is placed below title and aligned on left', (WidgetTester tester) async { + testWidgetsWithLeakTracking('subtitle is placed below title and aligned on left', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile title'); const Widget subtitle = Text('CupertinoListTile subtitle'); @@ -328,7 +329,7 @@ void main() { expect(foundTitle.dy < foundSubtitle.dy, isTrue); }); - testWidgets('additionalInfo is on the right of title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('additionalInfo is on the right of title', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); const Widget additionalInfo = Text('Not Connected'); @@ -352,7 +353,7 @@ void main() { expect(foundTitle.dx < foundInfo.dx, isTrue); }); - testWidgets('trailing is on the right of additionalInfo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('trailing is on the right of additionalInfo', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); const Widget additionalInfo = Text('Not Connected'); const Widget trailing = CupertinoListTileChevron(); @@ -380,7 +381,7 @@ void main() { }); group('alignment of widgets for right-to-left', () { - testWidgets('leading is on the right of title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('leading is on the right of title', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); const Widget leading = Icon(CupertinoIcons.add); @@ -404,7 +405,7 @@ void main() { expect(foundTitle.dx < foundLeading.dx, true); }); - testWidgets('subtitle is placed below title and aligned on right', (WidgetTester tester) async { + testWidgetsWithLeakTracking('subtitle is placed below title and aligned on right', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile title'); const Widget subtitle = Text('CupertinoListTile subtitle'); @@ -429,7 +430,7 @@ void main() { expect(foundTitle.dy < foundSubtitle.dy, isTrue); }); - testWidgets('additionalInfo is on the left of title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('additionalInfo is on the left of title', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); const Widget additionalInfo = Text('Not Connected'); @@ -453,7 +454,7 @@ void main() { expect(foundTitle.dx > foundInfo.dx, isTrue); }); - testWidgets('trailing is on the left of additionalInfo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('trailing is on the left of additionalInfo', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); const Widget additionalInfo = Text('Not Connected'); const Widget trailing = CupertinoListTileChevron(); @@ -480,7 +481,7 @@ void main() { }); }); - testWidgets('onTap with delay does not throw an exception', (WidgetTester tester) async { + testWidgetsWithLeakTracking('onTap with delay does not throw an exception', (WidgetTester tester) async { const Widget title = Text('CupertinoListTile'); bool showTile = true; @@ -520,7 +521,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('title does not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('title does not overflow', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoPageScaffold( @@ -534,7 +535,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('subtitle does not overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('subtitle does not overflow', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoPageScaffold( diff --git a/packages/flutter/test/cupertino/localizations_test.dart b/packages/flutter/test/cupertino/localizations_test.dart index 86b6e4fe00b19..fd1f94a63ff31 100644 --- a/packages/flutter/test/cupertino/localizations_test.dart +++ b/packages/flutter/test/cupertino/localizations_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('English translations exist for all CupertinoLocalization properties', (WidgetTester tester) async { + testWidgetsWithLeakTracking('English translations exist for all CupertinoLocalization properties', (WidgetTester tester) async { const CupertinoLocalizations localizations = DefaultCupertinoLocalizations(); expect(localizations.datePickerYear(2018), isNotNull); @@ -36,7 +37,7 @@ void main() { expect(localizations.noSpellCheckReplacementsLabel, isNotNull); }); - testWidgets('CupertinoLocalizations.of throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoLocalizations.of throws', (WidgetTester tester) async { final GlobalKey noLocalizationsAvailable = GlobalKey(); final GlobalKey localizationsAvailable = GlobalKey(); diff --git a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart index 1014b4137e80b..7f15919b3ef65 100644 --- a/packages/flutter/test/cupertino/material/tab_scaffold_test.dart +++ b/packages/flutter/test/cupertino/material/tab_scaffold_test.dart @@ -7,6 +7,7 @@ import 'dart:typed_data'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../../image_data.dart'; @@ -17,9 +18,14 @@ void main() { selectedTabs = <int>[]; }); - testWidgets('Last tab gets focus', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Last tab gets focus', (WidgetTester tester) async { // 2 nodes for 2 tabs - final List<FocusNode> focusNodes = <FocusNode>[FocusNode(), FocusNode()]; + final List<FocusNode> focusNodes = <FocusNode>[]; + for (int i = 0; i < 2; i++) { + final FocusNode focusNode = FocusNode(); + focusNodes.add(focusNode); + addTearDown(focusNode.dispose); + } await tester.pumpWidget( MaterialApp( @@ -52,10 +58,13 @@ void main() { expect(focusNodes[1].hasFocus, isFalse); }); - testWidgets('Do not affect focus order in the route', (WidgetTester tester) async { - final List<FocusNode> focusNodes = <FocusNode>[ - FocusNode(), FocusNode(), FocusNode(), FocusNode(), - ]; + testWidgetsWithLeakTracking('Do not affect focus order in the route', (WidgetTester tester) async { + final List<FocusNode> focusNodes = <FocusNode>[]; + for (int i = 0; i < 4; i++) { + final FocusNode focusNode = FocusNode(); + focusNodes.add(focusNode); + addTearDown(focusNode.dispose); + } await tester.pumpWidget( MaterialApp( @@ -118,7 +127,7 @@ void main() { ); }); - testWidgets('Tab bar respects themes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tab bar respects themes', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoTabScaffold( @@ -176,7 +185,7 @@ void main() { expect(tab2.text.style!.color!.value, CupertinoColors.systemRed.darkColor.value); }); - testWidgets('dark mode background color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('dark mode background color', (WidgetTester tester) async { const CupertinoDynamicColor backgroundColor = CupertinoDynamicColor.withBrightness( color: Color(0xFF123456), darkColor: Color(0xFF654321), @@ -229,7 +238,7 @@ void main() { expect(tabDecoration.color!.value, backgroundColor.darkColor.value); }); - testWidgets('Does not lose state when focusing on text input', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Does not lose state when focusing on text input', (WidgetTester tester) async { // Regression testing for https://github.com/flutter/flutter/issues/28457. await tester.pumpWidget( @@ -275,7 +284,7 @@ void main() { expect(find.text("don't lose me"), findsOneWidget); }); - testWidgets('textScaleFactor is set to 1.0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textScaleFactor is set to 1.0', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp( home: Builder(builder: (BuildContext context) { diff --git a/packages/flutter/test/cupertino/refresh_test.dart b/packages/flutter/test/cupertino/refresh_test.dart index 5601753a4710f..cc4b757ee396c 100644 --- a/packages/flutter/test/cupertino/refresh_test.dart +++ b/packages/flutter/test/cupertino/refresh_test.dart @@ -10,6 +10,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { late FakeBuilder mockHelper; @@ -34,7 +35,7 @@ void main() { } void uiTestGroup() { - testWidgets("doesn't invoke anything without user interaction", (WidgetTester tester) async { + testWidgetsWithLeakTracking("doesn't invoke anything without user interaction", (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -56,7 +57,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('calls the indicator builder when starting to overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('calls the indicator builder when starting to overscroll', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -90,7 +91,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets( + testWidgetsWithLeakTracking( "don't call the builder if overscroll doesn't move slivers like on Android", (WidgetTester tester) async { await tester.pumpWidget( @@ -124,7 +125,7 @@ void main() { variant: TargetPlatformVariant.only(TargetPlatform.android), ); - testWidgets('let the builder update as canceled drag scrolls away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('let the builder update as canceled drag scrolls away', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -186,7 +187,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('drag past threshold triggers refresh task', (WidgetTester tester) async { + testWidgetsWithLeakTracking('drag past threshold triggers refresh task', (WidgetTester tester) async { final List<MethodCall> platformCallLog = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { @@ -268,7 +269,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets( + testWidgetsWithLeakTracking( 'refreshing task keeps the sliver expanded forever until done', (WidgetTester tester) async { await tester.pumpWidget( @@ -343,7 +344,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'refreshing task keeps the sliver expanded forever until completes with error', (WidgetTester tester) async { final FlutterError error = FlutterError('Oops'); @@ -431,7 +432,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('expanded refreshing sliver scrolls normally', (WidgetTester tester) async { + testWidgetsWithLeakTracking('expanded refreshing sliver scrolls normally', (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); await tester.pumpWidget( @@ -520,7 +521,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('expanded refreshing sliver goes away when done', (WidgetTester tester) async { + testWidgetsWithLeakTracking('expanded refreshing sliver goes away when done', (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); await tester.pumpWidget( @@ -588,7 +589,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('builder still called when sliver snapped back more than 90%', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builder still called when sliver snapped back more than 90%', (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); await tester.pumpWidget( @@ -686,7 +687,7 @@ void main() { expect(find.text('-1'), findsOneWidget); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets( + testWidgetsWithLeakTracking( 'retracting sliver during done cannot be pulled to refresh again until fully retracted', (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); @@ -791,7 +792,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'sliver held in overscroll when task finishes completes normally', (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); @@ -843,7 +844,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'sliver scrolled away when task completes properly removes itself', (WidgetTester tester) async { if (testListLength < 4) { @@ -929,7 +930,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( "don't do anything unless it can be overscrolled at the start of the list", (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); @@ -957,7 +958,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'without an onRefresh, builder is called with arm for one frame then sliver goes away', (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); @@ -1014,7 +1015,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('Should not crash when dragged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Should not crash when dragged', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -1039,7 +1040,7 @@ void main() { // Test to make sure the refresh sliver's overscroll isn't eaten by the // nav bar sliver https://github.com/flutter/flutter/issues/74516. - testWidgets( + testWidgetsWithLeakTracking( 'properly displays when the refresh sliver is behind the large title nav bar sliver', (WidgetTester tester) async { await tester.pumpWidget( @@ -1082,7 +1083,7 @@ void main() { } void stateMachineTestGroup() { - testWidgets('starts in inactive state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('starts in inactive state', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -1102,7 +1103,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('goes to drag and returns to inactive in a small drag', (WidgetTester tester) async { + testWidgetsWithLeakTracking('goes to drag and returns to inactive in a small drag', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -1132,7 +1133,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('goes to armed the frame it passes the threshold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('goes to armed the frame it passes the threshold', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CustomScrollView( @@ -1167,7 +1168,7 @@ void main() { ); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets( + testWidgetsWithLeakTracking( 'goes to refresh the frame it crossed back the refresh threshold', (WidgetTester tester) async { await tester.pumpWidget( @@ -1216,7 +1217,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'goes to done internally as soon as the task finishes', (WidgetTester tester) async { await tester.pumpWidget( @@ -1264,7 +1265,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'goes back to inactive when retracting back past 10% of arming distance', (WidgetTester tester) async { await tester.pumpWidget( @@ -1349,7 +1350,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( 'goes back to inactive if already scrolled away when task completes', (WidgetTester tester) async { await tester.pumpWidget( @@ -1413,7 +1414,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets( + testWidgetsWithLeakTracking( "don't have to build any indicators or occupy space during refresh", (WidgetTester tester) async { mockHelper.refreshIndicator = const Center(child: Text('-1')); @@ -1463,7 +1464,7 @@ void main() { variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), ); - testWidgets('buildRefreshIndicator progress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('buildRefreshIndicator progress', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Builder( @@ -1510,7 +1511,7 @@ void main() { expect(tester.widget<CupertinoActivityIndicator>(find.byType(CupertinoActivityIndicator)).progress, 100.0 / 100.0); }); - testWidgets('indicator should not become larger when overscrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('indicator should not become larger when overscrolled', (WidgetTester tester) async { // test for https://github.com/flutter/flutter/issues/79841 await tester.pumpWidget( Directionality( @@ -1546,7 +1547,7 @@ void main() { // correct by coincidence. group('state machine test short list', stateMachineTestGroup); - testWidgets( + testWidgetsWithLeakTracking( 'Does not crash when paintExtent > remainingPaintExtent', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/46871. diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index 92a0d96951c93..e19a390229dbd 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -12,6 +12,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -22,7 +23,7 @@ void main() { navigatorObserver = MockNavigatorObserver(); }); - testWidgets('Middle auto-populates with title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Middle auto-populates with title', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Placeholder(), @@ -52,7 +53,7 @@ void main() { expect(tester.getCenter(find.text('An iPod')).dx, 400.0); }); - testWidgets('Large title auto-populates with title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Large title auto-populates with title', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Placeholder(), @@ -117,7 +118,7 @@ void main() { expect(tester.getCenter(find.byWidget(titles[0].widget)).dx, 400.0); }); - testWidgets('Leading auto-populates with back button with previous title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Leading auto-populates with back button with previous title', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Placeholder(), @@ -164,7 +165,7 @@ void main() { expect(tester.getTopLeft(find.text('An iPod')).dx, moreOrLessEquals(8.0 + 4.0 + 34.0 + 6.0, epsilon: 0.5)); }); - testWidgets('Previous title is correct on first transition frame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Previous title is correct on first transition frame', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Placeholder(), @@ -207,7 +208,7 @@ void main() { expect(find.widgetWithText(CupertinoButton, 'An iPod'), findsOneWidget); }); - testWidgets('Previous title stays up to date with changing routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Previous title stays up to date with changing routes', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Placeholder(), @@ -271,7 +272,7 @@ void main() { expect(tester.getTopLeft(find.text('Back')).dx, moreOrLessEquals(8.0 + 4.0 + 34.0 + 6.0, epsilon: 0.5)); }); - testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Back swipe dismiss interrupted by route push', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/28728 final GlobalKey scaffoldKey = GlobalKey(); @@ -377,7 +378,7 @@ void main() { ); }); - testWidgets('Fullscreen route animates correct transform values over time', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Fullscreen route animates correct transform values over time', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Builder( @@ -562,11 +563,11 @@ void main() { expect(tester.getTopLeft(find.byType(Placeholder)).dx, moreOrLessEquals(-0.0, epsilon: 1.0)); } - testWidgets('CupertinoPageRoute has parallax when non fullscreenDialog route is pushed on top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoPageRoute has parallax when non fullscreenDialog route is pushed on top', (WidgetTester tester) async { await testParallax(tester, fromFullscreenDialog: false); }); - testWidgets('FullscreenDialog CupertinoPageRoute has parallax when non fullscreenDialog route is pushed on top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FullscreenDialog CupertinoPageRoute has parallax when non fullscreenDialog route is pushed on top', (WidgetTester tester) async { await testParallax(tester, fromFullscreenDialog: true); }); @@ -651,15 +652,15 @@ void main() { expect(tester.getTopLeft(find.byType(Placeholder)).dx, 0.0); } - testWidgets('CupertinoPageRoute has no parallax when fullscreenDialog route is pushed on top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoPageRoute has no parallax when fullscreenDialog route is pushed on top', (WidgetTester tester) async { await testNoParallax(tester, fromFullscreenDialog: false); }); - testWidgets('FullscreenDialog CupertinoPageRoute has no parallax when fullscreenDialog route is pushed on top', (WidgetTester tester) async { + testWidgetsWithLeakTracking('FullscreenDialog CupertinoPageRoute has no parallax when fullscreenDialog route is pushed on top', (WidgetTester tester) async { await testNoParallax(tester, fromFullscreenDialog: true); }); - testWidgets('Animated push/pop is not linear', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animated push/pop is not linear', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Text('1'), @@ -711,7 +712,7 @@ void main() { expect(tester.getTopLeft(find.text('2')).dx, moreOrLessEquals(607, epsilon: 1)); }); - testWidgets('Dragged pop gesture is linear', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dragged pop gesture is linear', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Text('1'), @@ -757,7 +758,7 @@ void main() { expect(tester.getTopLeft(find.text('2')).dx, moreOrLessEquals(300)); }); - testWidgets('Pop gesture snapping is not linear', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Pop gesture snapping is not linear', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Text('1'), @@ -804,7 +805,7 @@ void main() { ); }); - testWidgets('Snapped drags forwards and backwards should signal didStart/StopUserGesture', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Snapped drags forwards and backwards should signal didStart/StopUserGesture', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigatorKey = GlobalKey(); await tester.pumpWidget( CupertinoApp( @@ -858,7 +859,7 @@ void main() { }); /// Regression test for https://github.com/flutter/flutter/issues/29596. - testWidgets('test edge swipe then drop back at ending point works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test edge swipe then drop back at ending point works', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( navigatorObservers: <NavigatorObserver>[navigatorObserver], @@ -895,7 +896,7 @@ void main() { expect(navigatorObserver.invocations.removeLast(), NavigatorInvocation.didPop); }); - testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('test edge swipe then drop back at starting point works', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( navigatorObservers: <NavigatorObserver>[navigatorObserver], @@ -952,7 +953,7 @@ void main() { ); } - testWidgets('when route is not fullscreenDialog, it has a barrierColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when route is not fullscreenDialog, it has a barrierColor', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: SizedBox.expand(), @@ -967,7 +968,7 @@ void main() { expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, const Color(0x18000000)); }); - testWidgets('when route is a fullscreenDialog, it has no barrierColor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when route is a fullscreenDialog, it has no barrierColor', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: SizedBox.expand(), @@ -982,7 +983,7 @@ void main() { expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, isNull); }); - testWidgets('when route is not fullscreenDialog, it has a _CupertinoEdgeShadowDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when route is not fullscreenDialog, it has a _CupertinoEdgeShadowDecoration', (WidgetTester tester) async { PaintPattern paintsShadowRect({required double dx, required Color color}) { return paints..everything((Symbol methodName, List<dynamic> arguments) { if (methodName != #drawRect) { @@ -1072,7 +1073,7 @@ void main() { expect(box, paintsShadowRect(dx: 754, color: const Color(0x00000000))); }); - testWidgets('when route is fullscreenDialog, it has no visible _CupertinoEdgeShadowDecoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when route is fullscreenDialog, it has no visible _CupertinoEdgeShadowDecoration', (WidgetTester tester) async { PaintPattern paintsNoShadows() { return paints..everything((Symbol methodName, List<dynamic> arguments) { if (methodName != #drawRect) { @@ -1114,7 +1115,7 @@ void main() { }); }); - testWidgets('ModalPopup overlay dark mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ModalPopup overlay dark mode', (WidgetTester tester) async { late StateSetter stateSetter; Brightness brightness = Brightness.light; @@ -1187,7 +1188,7 @@ void main() { ); }); - testWidgets('During back swipe the route ignores input', (WidgetTester tester) async { + testWidgetsWithLeakTracking('During back swipe the route ignores input', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/39989 final GlobalKey homeScaffoldKey = GlobalKey(); @@ -1250,7 +1251,7 @@ void main() { expect(pageTapCount, 1); }); - testWidgets('showCupertinoModalPopup uses root navigator by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup uses root navigator by default', (WidgetTester tester) async { final PopupObserver rootObserver = PopupObserver(); final PopupObserver nestedObserver = PopupObserver(); @@ -1283,7 +1284,7 @@ void main() { expect(nestedObserver.popupCount, 0); }); - testWidgets('back swipe to screen edges does not dismiss the hero animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('back swipe to screen edges does not dismiss the hero animation', (WidgetTester tester) async { final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>(); final UniqueKey container = UniqueKey(); await tester.pumpWidget(CupertinoApp( @@ -1353,7 +1354,7 @@ void main() { expect(firstPosition, greaterThan(thirdPosition)); }); - testWidgets('showCupertinoModalPopup uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final PopupObserver rootObserver = PopupObserver(); final PopupObserver nestedObserver = PopupObserver(); @@ -1387,7 +1388,7 @@ void main() { expect(nestedObserver.popupCount, 1); }); - testWidgets('showCupertinoDialog uses root navigator by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoDialog uses root navigator by default', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); final DialogObserver nestedObserver = DialogObserver(); @@ -1420,7 +1421,7 @@ void main() { expect(nestedObserver.dialogCount, 0); }); - testWidgets('showCupertinoDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoDialog uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final DialogObserver rootObserver = DialogObserver(); final DialogObserver nestedObserver = DialogObserver(); @@ -1454,7 +1455,7 @@ void main() { expect(nestedObserver.dialogCount, 1); }); - testWidgets('showCupertinoModalPopup does not allow for semantics dismiss by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup does not allow for semantics dismiss by default', (WidgetTester tester) async { debugDefaultTargetPlatformOverride = TargetPlatform.iOS; final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(CupertinoApp( @@ -1489,7 +1490,7 @@ void main() { semantics.dispose(); }); - testWidgets('showCupertinoModalPopup allows for semantics dismiss when set', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup allows for semantics dismiss when set', (WidgetTester tester) async { debugDefaultTargetPlatformOverride = TargetPlatform.iOS; final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(CupertinoApp( @@ -1525,7 +1526,7 @@ void main() { semantics.dispose(); }); - testWidgets('showCupertinoModalPopup passes RouteSettings to PopupRoute', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup passes RouteSettings to PopupRoute', (WidgetTester tester) async { final RouteSettingsObserver routeSettingsObserver = RouteSettingsObserver(); await tester.pumpWidget(CupertinoApp( @@ -1556,7 +1557,7 @@ void main() { expect(routeSettingsObserver.routeName, '/modal'); }); - testWidgets('showCupertinoModalPopup transparent barrier color is transparent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup transparent barrier color is transparent', (WidgetTester tester) async { const Color kTransparentColor = Color(0x00000000); await tester.pumpWidget(CupertinoApp( @@ -1582,7 +1583,7 @@ void main() { expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, null); }); - testWidgets('showCupertinoModalPopup null barrier color must be default gray barrier color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup null barrier color must be default gray barrier color', (WidgetTester tester) async { // Barrier color for a Cupertino modal barrier. // Extracted from https://developer.apple.com/design/resources/. const Color kModalBarrierColor = CupertinoDynamicColor.withBrightness( @@ -1612,7 +1613,7 @@ void main() { expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, kModalBarrierColor); }); - testWidgets('showCupertinoModalPopup custom barrier color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup custom barrier color', (WidgetTester tester) async { const Color customColor = Color(0x11223344); await tester.pumpWidget(CupertinoApp( @@ -1638,7 +1639,7 @@ void main() { expect(tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color, customColor); }); - testWidgets('showCupertinoModalPopup barrier dismissible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup barrier dismissible', (WidgetTester tester) async { await tester.pumpWidget(CupertinoApp( home: CupertinoPageScaffold( child: Builder(builder: (BuildContext context) { @@ -1663,7 +1664,7 @@ void main() { expect(find.text('Visible'), findsNothing); }); - testWidgets('showCupertinoModalPopup barrier not dismissible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('showCupertinoModalPopup barrier not dismissible', (WidgetTester tester) async { await tester.pumpWidget(CupertinoApp( home: CupertinoPageScaffold( child: Builder(builder: (BuildContext context) { @@ -1689,7 +1690,7 @@ void main() { expect(find.text('Visible'), findsOneWidget); }); - testWidgets('CupertinoPage works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoPage works', (WidgetTester tester) async { final LocalKey pageKey = UniqueKey(); final TransitionDetector detector = TransitionDetector(); List<Page<void>> myPages = <Page<void>>[ @@ -1750,7 +1751,7 @@ void main() { expect(find.widgetWithText(CupertinoNavigationBar, 'title two'), findsOneWidget); }); - testWidgets('CupertinoPage can toggle MaintainState', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoPage can toggle MaintainState', (WidgetTester tester) async { final LocalKey pageKeyOne = UniqueKey(); final LocalKey pageKeyTwo = UniqueKey(); final TransitionDetector detector = TransitionDetector(); @@ -1799,7 +1800,7 @@ void main() { expect(find.text('second'), findsOneWidget); }); - testWidgets('Popping routes should cancel down events', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popping routes should cancel down events', (WidgetTester tester) async { await tester.pumpWidget(const _TestPostRouteCancel()); final TestGesture gesture = await tester.createGesture(); @@ -1818,7 +1819,7 @@ void main() { expect(find.text('PointerCancelEvents: 1'), findsOneWidget); }); - testWidgets('Popping routes during back swipe should not crash', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Popping routes during back swipe should not crash', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/63984#issuecomment-675679939 final CupertinoPageRoute<void> r = CupertinoPageRoute<void>(builder: (BuildContext context) { @@ -1868,7 +1869,7 @@ void main() { await tester.pump(); }); - testWidgets('CupertinoModalPopupRoute is state restorable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoModalPopupRoute is state restorable', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( restorationScopeId: 'app', @@ -1899,7 +1900,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/33615 group('showCupertinoDialog avoids overlapping display features', () { - testWidgets('positioning with anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with anchorPoint', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? child) { @@ -1937,7 +1938,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('positioning with Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning with Directionality', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? child) { @@ -1977,7 +1978,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(800.0, 600.0)); }); - testWidgets('positioning by default', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning by default', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? child) { @@ -2016,7 +2017,7 @@ void main() { }); group('showCupertinoModalPopup avoids overlapping display features', () { - testWidgets('positioning using anchorPoint', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning using anchorPoint', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? child) { @@ -2054,7 +2055,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)).dx, 800); }); - testWidgets('positioning using Directionality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positioning using Directionality', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? child) { @@ -2094,7 +2095,7 @@ void main() { expect(tester.getBottomRight(find.byType(Placeholder)).dx, 800); }); - testWidgets('default positioning', (WidgetTester tester) async { + testWidgetsWithLeakTracking('default positioning', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? child) { diff --git a/packages/flutter/test/cupertino/scrollbar_paint_test.dart b/packages/flutter/test/cupertino/scrollbar_paint_test.dart index a19a3ca8567f1..f9bc1822ac1e7 100644 --- a/packages/flutter/test/cupertino/scrollbar_paint_test.dart +++ b/packages/flutter/test/cupertino/scrollbar_paint_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const Color _kScrollbarColor = Color(0x59000000); @@ -13,7 +14,7 @@ const Offset _kGestureOffset = Offset(0, -25); const Radius _kScrollbarRadius = Radius.circular(1.5); void main() { - testWidgets('Paints iOS spec', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paints iOS spec', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -51,7 +52,7 @@ void main() { )); }); - testWidgets('Paints iOS spec with nav bar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paints iOS spec with nav bar', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: MediaQuery( @@ -96,7 +97,7 @@ void main() { )); }); - testWidgets("should not paint when there isn't enough space", (WidgetTester tester) async { + testWidgetsWithLeakTracking("should not paint when there isn't enough space", (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: MediaQuery( diff --git a/packages/flutter/test/cupertino/segmented_control_test.dart b/packages/flutter/test/cupertino/segmented_control_test.dart index 42775489f9d38..84fd8c2493672 100644 --- a/packages/flutter/test/cupertino/segmented_control_test.dart +++ b/packages/flutter/test/cupertino/segmented_control_test.dart @@ -14,6 +14,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -93,7 +94,7 @@ Color getBackgroundColor(WidgetTester tester, int childIndex) { } void main() { - testWidgets('Tap changes toggle state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap changes toggle state', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -127,7 +128,7 @@ void main() { expect(sharedValue, 1); }); - testWidgets('Need at least 2 children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Need at least 2 children', (WidgetTester tester) async { await expectLater( () => tester.pumpWidget( boilerplate( @@ -161,7 +162,7 @@ void main() { ); }); - testWidgets('Padding works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Padding works', (WidgetTester tester) async { const Key key = Key('Container'); final Map<int, Widget> children = <int, Widget>{}; @@ -248,7 +249,7 @@ void main() { await verifyPadding(padding: const EdgeInsets.fromLTRB(1, 3, 5, 7)); }); - testWidgets('Value attribute must be the key of one of the children widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Value attribute must be the key of one of the children widgets', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -271,7 +272,7 @@ void main() { ); }); - testWidgets('Widgets have correct default text/icon styles, change correctly on selection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets have correct default text/icon styles, change correctly on selection', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Icon(IconData(1)); @@ -314,7 +315,7 @@ void main() { expect(iconTheme.data.color, isSameColorAs(CupertinoColors.white)); }); - testWidgets( + testWidgetsWithLeakTracking( 'Segmented controls respects themes', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; @@ -360,7 +361,7 @@ void main() { }, ); - testWidgets('SegmentedControl is correct when user provides custom colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SegmentedControl is correct when user provides custom colors', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Icon(IconData(1)); @@ -417,7 +418,7 @@ void main() { expect(getBackgroundColor(tester, 1), CupertinoColors.activeGreen.color); }); - testWidgets('Widgets are centered within segments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets are centered within segments', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -444,7 +445,7 @@ void main() { expect(tester.getCenter(find.text('Child 2')), const Offset(142.0, 100.0)); }); - testWidgets('Tap calls onValueChanged', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Tap calls onValueChanged', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -473,7 +474,7 @@ void main() { expect(value, isTrue); }); - testWidgets('State does not change if onValueChanged does not call setState()', (WidgetTester tester) async { + testWidgetsWithLeakTracking('State does not change if onValueChanged does not call setState()', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -504,7 +505,7 @@ void main() { expect(getBackgroundColor(tester, 1), isSameColorAs(CupertinoColors.white)); }); - testWidgets( + testWidgetsWithLeakTracking( 'Background color of child should change on selection, ' 'and should not change when tapped again', (WidgetTester tester) async { @@ -524,7 +525,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'Children can be non-Text or Icon widgets (in this case, ' 'a Container or Placeholder widget)', (WidgetTester tester) async { @@ -557,7 +558,7 @@ void main() { }, ); - testWidgets('Passed in value is child initially selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Passed in value is child initially selected', (WidgetTester tester) async { await tester.pumpWidget(setupSimpleSegmentedControl()); expect(getSelectedIndex(tester), 0); @@ -566,7 +567,7 @@ void main() { expect(getBackgroundColor(tester, 1), isSameColorAs(CupertinoColors.white)); }); - testWidgets('Null input for value results in no child initially selected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Null input for value results in no child initially selected', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -597,7 +598,7 @@ void main() { expect(getBackgroundColor(tester, 1), isSameColorAs(CupertinoColors.white)); }); - testWidgets('Long press changes background color of not-selected child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Long press changes background color of not-selected child', (WidgetTester tester) async { await tester.pumpWidget(setupSimpleSegmentedControl()); expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue); @@ -611,7 +612,7 @@ void main() { expect(getBackgroundColor(tester, 1), const Color(0x33007aff)); }); - testWidgets('Long press does not change background color of currently-selected child', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Long press does not change background color of currently-selected child', (WidgetTester tester) async { await tester.pumpWidget(setupSimpleSegmentedControl()); expect(getBackgroundColor(tester, 0), CupertinoColors.activeBlue); @@ -625,7 +626,7 @@ void main() { expect(getBackgroundColor(tester, 1), isSameColorAs(CupertinoColors.white)); }); - testWidgets('Height of segmented control is determined by tallest widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Height of segmented control is determined by tallest widget', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = Container( constraints: const BoxConstraints.tightFor(height: 100.0), @@ -656,7 +657,7 @@ void main() { expect(buttonBox.size.height, 400.0); }); - testWidgets('Width of each segmented control segment is determined by widest widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Width of each segmented control segment is determined by widest widget', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = Container( constraints: const BoxConstraints.tightFor(width: 50.0), @@ -695,7 +696,7 @@ void main() { expect(childWidth, getSurroundingRect(tester, child: 2).width); }); - testWidgets('Width is finite in unbounded space', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Width is finite in unbounded space', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -723,7 +724,7 @@ void main() { expect(segmentedControl.size.width.isFinite, isTrue); }); - testWidgets('Directionality test - RTL should reverse order of widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Directionality test - RTL should reverse order of widgets', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -743,7 +744,7 @@ void main() { expect(tester.getTopRight(find.text('Child 1')).dx > tester.getTopRight(find.text('Child 2')).dx, isTrue); }); - testWidgets('Correct initial selection and toggling behavior - RTL', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Correct initial selection and toggling behavior - RTL', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -786,7 +787,7 @@ void main() { expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue); }); - testWidgets('Segmented control semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Segmented control semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final Map<int, Widget> children = <int, Widget>{}; @@ -889,7 +890,7 @@ void main() { semantics.dispose(); }); - testWidgets('Non-centered taps work on smaller widgets', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Non-centered taps work on smaller widgets', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -931,7 +932,7 @@ void main() { expect(sharedValue, 0); }); - testWidgets('Hit-tests report accurate local position in segments', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hit-tests report accurate local position in segments', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; late TapDownDetails tapDownDetails; children[0] = GestureDetector( @@ -971,7 +972,7 @@ void main() { expect(tapDownDetails.globalPosition, segment0GlobalOffset + const Offset(7, 11)); }); - testWidgets( + testWidgetsWithLeakTracking( 'Segment still hittable with a child that has no hitbox', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/57326. @@ -1010,7 +1011,7 @@ void main() { }, ); - testWidgets('Animation is correct when the selected segment changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animation is correct when the selected segment changes', (WidgetTester tester) async { await tester.pumpWidget(setupSimpleSegmentedControl()); await tester.tap(find.text('Child 2')); @@ -1040,7 +1041,7 @@ void main() { expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue); }); - testWidgets('Animation is correct when widget is rebuilt', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animation is correct when widget is rebuilt', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('Child 1'); children[1] = const Text('Child 2'); @@ -1192,7 +1193,7 @@ void main() { expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue); }); - testWidgets('Multiple segments are pressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Multiple segments are pressed', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); @@ -1234,7 +1235,7 @@ void main() { expect(getBackgroundColor(tester, 2), isSameColorAs(CupertinoColors.white)); }); - testWidgets('Transition is triggered while a transition is already occurring', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Transition is triggered while a transition is already occurring', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); @@ -1296,7 +1297,7 @@ void main() { expect(getBackgroundColor(tester, 2), CupertinoColors.activeBlue); }); - testWidgets('Segment is selected while it is transitioning to unselected state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Segment is selected while it is transitioning to unselected state', (WidgetTester tester) async { await tester.pumpWidget(setupSimpleSegmentedControl()); await tester.tap(find.text('Child 2')); @@ -1324,7 +1325,7 @@ void main() { expect(getBackgroundColor(tester, 1), isSameColorAs(CupertinoColors.white)); }); - testWidgets('Add segment while animation is running', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Add segment while animation is running', (WidgetTester tester) async { Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); @@ -1372,7 +1373,7 @@ void main() { expect(getBackgroundColor(tester, 3), isSameColorAs(CupertinoColors.white)); }); - testWidgets('Remove segment while animation is running', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Remove segment while animation is running', (WidgetTester tester) async { Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); @@ -1417,7 +1418,7 @@ void main() { expect(getBackgroundColor(tester, 1), CupertinoColors.activeBlue); }); - testWidgets('Remove currently animating segment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Remove currently animating segment', (WidgetTester tester) async { Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); @@ -1469,7 +1470,7 @@ void main() { }); // Regression test: https://github.com/flutter/flutter/issues/43414. - testWidgets("Quick double tap doesn't break the internal state", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Quick double tap doesn't break the internal state", (WidgetTester tester) async { const Map<int, Widget> children = <int, Widget>{ 0: Text('A'), 1: Text('B'), @@ -1509,7 +1510,7 @@ void main() { expect(sharedValue, 2); }); - testWidgets('Golden Test Placeholder Widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Golden Test Placeholder Widget', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = Container(); children[1] = const Placeholder(); @@ -1543,7 +1544,7 @@ void main() { ); }); - testWidgets('Golden Test Pressed State', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Golden Test Pressed State', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); @@ -1581,7 +1582,7 @@ void main() { ); }); - testWidgets('Hovering over Cupertino segmented control updates cursor to clickable on Web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovering over Cupertino segmented control updates cursor to clickable on Web', (WidgetTester tester) async { final Map<int, Widget> children = <int, Widget>{}; children[0] = const Text('A'); children[1] = const Text('B'); diff --git a/packages/flutter/test/cupertino/slider_test.dart b/packages/flutter/test/cupertino/slider_test.dart index a205276e0e7ba..38fd62e11c6d2 100644 --- a/packages/flutter/test/cupertino/slider_test.dart +++ b/packages/flutter/test/cupertino/slider_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/semantics_tester.dart'; @@ -32,7 +33,7 @@ void main() { return tester.dragFrom(topLeft + const Offset(unit, unit), const Offset(delta, 0.0)); } - testWidgets('Slider does not move when tapped (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider does not move when tapped (LTR)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; @@ -68,7 +69,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider does not move when tapped (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider does not move when tapped (RTL)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; @@ -104,7 +105,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider calls onChangeStart once when interaction begins', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider calls onChangeStart once when interaction begins', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; int numberOfTimesOnChangeStartIsCalled = 0; @@ -145,7 +146,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider calls onChangeEnd once after interaction has ended', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider calls onChangeEnd once after interaction has ended', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; int numberOfTimesOnChangeEndIsCalled = 0; @@ -186,7 +187,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider moves when dragged (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider moves when dragged (LTR)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; late double startValue; @@ -240,7 +241,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider moves when dragged (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider moves when dragged (RTL)', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; late double startValue; @@ -294,7 +295,7 @@ void main() { expect(SchedulerBinding.instance.transientCallbackCount, equals(0)); }); - testWidgets('Slider Semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider Semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( @@ -358,7 +359,7 @@ void main() { semantics.dispose(); }); - testWidgets('Slider Semantics can be updated', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider Semantics can be updated', (WidgetTester tester) async { final SemanticsHandle handle = tester.ensureSemantics(); double value = 0.5; await tester.pumpWidget( @@ -409,7 +410,7 @@ void main() { handle.dispose(); }); - testWidgets('Slider respects themes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Slider respects themes', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -444,7 +445,7 @@ void main() { ); }); - testWidgets('Themes can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Themes can be overridden', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( theme: const CupertinoThemeData(brightness: Brightness.dark), @@ -463,7 +464,7 @@ void main() { ); }); - testWidgets('Themes can be overridden by dynamic colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Themes can be overridden by dynamic colors', (WidgetTester tester) async { const CupertinoDynamicColor activeColor = CupertinoDynamicColor( color: Color(0x00000001), darkColor: Color(0x00000002), @@ -519,7 +520,7 @@ void main() { expect(find.byType(CupertinoSlider), paints..rrect(color: activeColor.highContrastElevatedColor)); }); - testWidgets('track color is dynamic', (WidgetTester tester) async { + testWidgetsWithLeakTracking('track color is dynamic', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( theme: const CupertinoThemeData(brightness: Brightness.light), @@ -567,7 +568,7 @@ void main() { ); }); - testWidgets('Thumb color can be overridden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Thumb color can be overridden', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -615,7 +616,7 @@ void main() { ); }); - testWidgets('Hovering over Cupertino slider thumb updates cursor to clickable on Web', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hovering over Cupertino slider thumb updates cursor to clickable on Web', (WidgetTester tester) async { final Key sliderKey = UniqueKey(); double value = 0.0; diff --git a/packages/flutter/test/cupertino/tab_test.dart b/packages/flutter/test/cupertino/tab_test.dart index 63001a64f3ffc..c2f6ede7ada93 100644 --- a/packages/flutter/test/cupertino/tab_test.dart +++ b/packages/flutter/test/cupertino/tab_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Use home', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Use home', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoTabView( @@ -18,7 +19,7 @@ void main() { expect(find.text('home'), findsOneWidget); }); - testWidgets('Use routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Use routes', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoTabView( @@ -32,7 +33,7 @@ void main() { expect(find.text('first route'), findsOneWidget); }); - testWidgets('Use home and named routes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Use home and named routes', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoTabView( @@ -58,7 +59,7 @@ void main() { expect(find.text('second named route'), findsOneWidget); }); - testWidgets('Use onGenerateRoute', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Use onGenerateRoute', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: CupertinoTabView( @@ -80,7 +81,7 @@ void main() { expect(find.text('generated home'), findsOneWidget); }); - testWidgets('Use onUnknownRoute', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Use onUnknownRoute', (WidgetTester tester) async { late String unknownForRouteCalled; await tester.pumpWidget( CupertinoApp( @@ -101,7 +102,7 @@ void main() { expect(tester.takeException(), isAssertionError); }); - testWidgets('Can use navigatorKey to navigate', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can use navigatorKey to navigate', (WidgetTester tester) async { final GlobalKey<NavigatorState> key = GlobalKey(); await tester.pumpWidget( CupertinoApp( @@ -122,7 +123,7 @@ void main() { expect(find.text('second route'), findsOneWidget); }); - testWidgets('Changing the key resets the navigator', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing the key resets the navigator', (WidgetTester tester) async { final GlobalKey<NavigatorState> key = GlobalKey(); await tester.pumpWidget( CupertinoApp( @@ -172,7 +173,7 @@ void main() { expect(find.text('second route'), findsNothing); }); - testWidgets('Throws FlutterError when onUnknownRoute is null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws FlutterError when onUnknownRoute is null', (WidgetTester tester) async { final GlobalKey<NavigatorState> key = GlobalKey(); await tester.pumpWidget( CupertinoApp( @@ -209,7 +210,7 @@ void main() { ); }); - testWidgets('Throws FlutterError when onUnknownRoute returns null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Throws FlutterError when onUnknownRoute returns null', (WidgetTester tester) async { final GlobalKey<NavigatorState> key = GlobalKey<NavigatorState>(); await tester.pumpWidget( CupertinoApp( @@ -239,7 +240,7 @@ void main() { ); }); - testWidgets('Navigator of CupertinoTabView restores state', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigator of CupertinoTabView restores state', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( restorationScopeId: 'app', diff --git a/packages/flutter/test/cupertino/text_field_restoration_test.dart b/packages/flutter/test/cupertino/text_field_restoration_test.dart index ad6c8e12f896b..b892984d0d195 100644 --- a/packages/flutter/test/cupertino/text_field_restoration_test.dart +++ b/packages/flutter/test/cupertino/text_field_restoration_test.dart @@ -5,12 +5,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; const String text = 'Hello World! How are you? Life is good!'; const String alternativeText = 'Everything is awesome!!'; void main() { - testWidgets('CupertinoTextField restoration', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoTextField restoration', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( restorationScopeId: 'app', @@ -21,7 +22,7 @@ void main() { await restoreAndVerify(tester); }); - testWidgets('CupertinoTextField restoration with external controller', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoTextField restoration with external controller', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( restorationScopeId: 'app', diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_button_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_button_test.dart index 76eee86317a7f..575b284abdbca 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_button_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_button_test.dart @@ -4,11 +4,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('can press', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can press', (WidgetTester tester) async { bool pressed = false; await tester.pumpWidget( CupertinoApp( @@ -29,7 +30,7 @@ void main() { expect(pressed, true); }); - testWidgets('background darkens when pressed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('background darkens when pressed', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( home: Center( @@ -75,7 +76,7 @@ void main() { expect(boxDecoration.color, const Color(0x00000000)); }); - testWidgets('passing null to onPressed disables the button', (WidgetTester tester) async { + testWidgetsWithLeakTracking('passing null to onPressed disables the button', (WidgetTester tester) async { await tester.pumpWidget( const CupertinoApp( home: Center( diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart index f1cf29c4ab8b5..5a7e4fff35faa 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../widgets/editable_text_utils.dart' show textOffsetToPosition; @@ -106,7 +107,7 @@ void main() { ); } - testWidgets('chevrons point to the correct side', (WidgetTester tester) async { + testWidgetsWithLeakTracking('chevrons point to the correct side', (WidgetTester tester) async { // Add enough TestBoxes to need 3 pages. final List<Widget> children = List<Widget>.generate(15, (int i) => const TestBox()); await tester.pumpWidget( @@ -146,7 +147,7 @@ void main() { expect(findOverflowBackButton(), overflowBackPaintPattern()); }, skip: kIsWeb); // Path.combine is not implemented in the HTML backend https://github.com/flutter/flutter/issues/44572 - testWidgets('paginates children if they overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('paginates children if they overflow', (WidgetTester tester) async { late StateSetter setState; final List<Widget> children = List<Widget>.generate(7, (int i) => const TestBox()); await tester.pumpWidget( @@ -241,7 +242,7 @@ void main() { expect(findOverflowBackButton(), findsNothing); }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgets('does not paginate if children fit with zero margin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not paginate if children fit with zero margin', (WidgetTester tester) async { final List<Widget> children = List<Widget>.generate(7, (int i) => const TestBox()); final double spacerWidth = 1.0 / tester.view.devicePixelRatio; final double dividerWidth = 1.0 / tester.view.devicePixelRatio; @@ -268,7 +269,7 @@ void main() { expect(findOverflowBackButton(), findsNothing); }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgets('positions itself at anchorAbove if it fits', (WidgetTester tester) async { + testWidgetsWithLeakTracking('positions itself at anchorAbove if it fits', (WidgetTester tester) async { late StateSetter setState; const double height = _kToolbarHeight; const double anchorBelowY = 500.0; @@ -334,7 +335,7 @@ void main() { expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. - testWidgets('can create and use a custom toolbar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { final TextEditingController controller = TextEditingController( text: 'Select me custom menu', ); @@ -369,7 +370,7 @@ void main() { for (final Brightness? themeBrightness in <Brightness?>[...Brightness.values, null]) { for (final Brightness? mediaBrightness in <Brightness?>[...Brightness.values, null]) { - testWidgets('draws dark buttons in dark mode and light button in light mode when theme is $themeBrightness and MediaQuery is $mediaBrightness', (WidgetTester tester) async { + testWidgetsWithLeakTracking('draws dark buttons in dark mode and light button in light mode when theme is $themeBrightness and MediaQuery is $mediaBrightness', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( theme: CupertinoThemeData( @@ -426,7 +427,7 @@ void main() { } } - testWidgets('draws a shadow below the toolbar in light mode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('draws a shadow below the toolbar in light mode', (WidgetTester tester) async { late StateSetter setState; const double height = _kToolbarHeight; double anchorAboveY = 0.0; diff --git a/packages/flutter/test/cupertino/theme_test.dart b/packages/flutter/test/cupertino/theme_test.dart index 5f8b9a372f111..8ee7c9deb1de7 100644 --- a/packages/flutter/test/cupertino/theme_test.dart +++ b/packages/flutter/test/cupertino/theme_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; int buildCount = 0; CupertinoThemeData? actualTheme; @@ -46,7 +47,7 @@ void main() { actualIconTheme = null; }); - testWidgets('Default theme has defaults', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Default theme has defaults', (WidgetTester tester) async { final CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData()); expect(theme.brightness, isNull); @@ -55,7 +56,7 @@ void main() { expect(theme.applyThemeToAll, false); }); - testWidgets('Theme attributes cascade', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Theme attributes cascade', (WidgetTester tester) async { final CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData( primaryColor: CupertinoColors.systemRed, )); @@ -63,7 +64,7 @@ void main() { expect(theme.textTheme.actionTextStyle.color, isSameColorAs(CupertinoColors.systemRed.color)); }); - testWidgets('Dependent attribute can be overridden from cascaded value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Dependent attribute can be overridden from cascaded value', (WidgetTester tester) async { final CupertinoThemeData theme = await testTheme(tester, const CupertinoThemeData( brightness: Brightness.dark, textTheme: CupertinoTextThemeData( @@ -77,7 +78,7 @@ void main() { expect(theme.textTheme.textStyle.color, isSameColorAs(CupertinoColors.black)); }); - testWidgets( + testWidgetsWithLeakTracking( 'Reading themes creates dependencies', (WidgetTester tester) async { // Reading the theme creates a dependency. @@ -118,7 +119,7 @@ void main() { }, ); - testWidgets( + testWidgetsWithLeakTracking( 'copyWith works', (WidgetTester tester) async { const CupertinoThemeData originalTheme = CupertinoThemeData( @@ -141,7 +142,7 @@ void main() { }, ); - testWidgets("Theme has default IconThemeData, which is derived from the theme's primary color", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Theme has default IconThemeData, which is derived from the theme's primary color", (WidgetTester tester) async { const CupertinoDynamicColor primaryColor = CupertinoColors.systemRed; const CupertinoThemeData themeData = CupertinoThemeData(primaryColor: primaryColor); @@ -158,7 +159,7 @@ void main() { expect(darkColor, isSameColorAs(primaryColor.darkColor)); }); - testWidgets('IconTheme.of creates a dependency on iconTheme', (WidgetTester tester) async { + testWidgetsWithLeakTracking('IconTheme.of creates a dependency on iconTheme', (WidgetTester tester) async { IconThemeData iconTheme = await testIconTheme(tester, const CupertinoThemeData(primaryColor: CupertinoColors.destructiveRed)); expect(buildCount, 1); @@ -169,7 +170,7 @@ void main() { expect(iconTheme.color, CupertinoColors.activeOrange); }); - testWidgets('CupertinoTheme diagnostics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoTheme diagnostics', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); const CupertinoThemeData().debugFillProperties(builder); @@ -201,7 +202,7 @@ void main() { ); }); - testWidgets('CupertinoTheme.toStringDeep uses single-line style', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoTheme.toStringDeep uses single-line style', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/47651. expect( const CupertinoTheme( @@ -212,7 +213,7 @@ void main() { ); }); - testWidgets('CupertinoThemeData equality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoThemeData equality', (WidgetTester tester) async { const CupertinoThemeData a = CupertinoThemeData(brightness: Brightness.dark); final CupertinoThemeData b = a.copyWith(); final CupertinoThemeData c = a.copyWith(brightness: Brightness.light); @@ -235,7 +236,7 @@ void main() { } void dynamicColorsTestGroup() { - testWidgets('CupertinoTheme.of resolves colors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoTheme.of resolves colors', (WidgetTester tester) async { final CupertinoThemeData data = CupertinoThemeData(brightness: currentBrightness, primaryColor: CupertinoColors.systemRed); final CupertinoThemeData theme = await testTheme(tester, data); @@ -243,7 +244,7 @@ void main() { colorMatches(theme.primaryColor, CupertinoColors.systemRed); }); - testWidgets('CupertinoTheme.of resolves default values', (WidgetTester tester) async { + testWidgetsWithLeakTracking('CupertinoTheme.of resolves default values', (WidgetTester tester) async { const CupertinoDynamicColor primaryColor = CupertinoColors.systemRed; final CupertinoThemeData data = CupertinoThemeData(brightness: currentBrightness, primaryColor: primaryColor); From 22748e3a3a38f2d4f55a3654edacba2ff11fdd93 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 09:33:29 -0400 Subject: [PATCH 1389/1547] Roll Flutter Engine from 584861202198 to 6c1e58c86e8c (1 revision) (#135216) https://github.com/flutter/engine/compare/584861202198...6c1e58c86e8c 2023-09-21 sigurdm@google.com Add package:tar to DEPS (flutter/engine#46140) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8138065b11498..590649a4deb09 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -5848612021985e760187de3c13146295ac80ba4a +6c1e58c86e8c39717b40d007490239174ce0fccd From 8f04f0c2f889471c895a7ffbe51c3d2704091d00 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 11:45:19 -0400 Subject: [PATCH 1390/1547] Roll Packages from 51e74b97508a to d0411e450a8d (1 revision) (#135224) https://github.com/flutter/packages/compare/51e74b97508a...d0411e450a8d 2023-09-20 stuartmorgan@google.com [various] Update invalid NSURL tests (flutter/packages#4959) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 728005329905e..44829152e052d 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -51e74b97508a3f85af2c45d994be0e0a58b496f8 +d0411e450a8d94fcb221e8d8eacd3b1f8ca0e2fc From 5708b76ef06d8b21930a20b3482beaf9ec7e06b1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 12:30:00 -0400 Subject: [PATCH 1391/1547] Roll Flutter Engine from 6c1e58c86e8c to fa032d52a118 (1 revision) (#135227) https://github.com/flutter/engine/compare/6c1e58c86e8c...fa032d52a118 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from 322abacca561 to 0cf83a86c56d (1 revision) (flutter/engine#46143) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 590649a4deb09..8a039f6dd379a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6c1e58c86e8c39717b40d007490239174ce0fccd +fa032d52a1185c761dc67c00ee17ffeb9b6a53c1 From 77718845dd686effbf48b30c85a077f33d033b7c Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 21 Sep 2023 10:06:21 -0700 Subject: [PATCH 1392/1547] Handle breaking changes in leak_tracker. (#135185) --- packages/flutter/pubspec.yaml | 8 ++++---- .../material/material_states_controller_test.dart | 7 +++++-- .../flutter/test/services/restoration_test.dart | 5 ++++- .../flutter/test/widgets/focus_manager_test.dart | 14 ++++++++++---- .../test/widgets/restorable_property_test.dart | 5 ++++- packages/flutter/test/widgets/router_test.dart | 10 ++++++---- .../test/widgets/scroll_controller_test.dart | 7 +++++-- packages/flutter/test/widgets/shortcuts_test.dart | 14 ++++++++++---- 8 files changed, 48 insertions(+), 22 deletions(-) diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index 9ec08024811ce..f0c56c262b5bd 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -22,8 +22,8 @@ dev_dependencies: flutter_goldens: sdk: flutter fake_async: 1.3.1 - leak_tracker: 9.0.6 - leak_tracker_flutter_testing: 1.0.3 + leak_tracker: 9.0.7 + leak_tracker_flutter_testing: 1.0.5 _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -42,7 +42,7 @@ dev_dependencies: intl: 0.18.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" io: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - leak_tracker_testing: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + leak_tracker_testing: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" matcher: 0.12.16 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 5f92 +# PUBSPEC CHECKSUM: a796 diff --git a/packages/flutter/test/material/material_states_controller_test.dart b/packages/flutter/test/material/material_states_controller_test.dart index f797d34e34bb1..275c1034117e8 100644 --- a/packages/flutter/test/material/material_states_controller_test.dart +++ b/packages/flutter/test/material/material_states_controller_test.dart @@ -13,8 +13,11 @@ void main() { expect(MaterialStatesController(<MaterialState>{MaterialState.selected}).value, <MaterialState>{MaterialState.selected}); }); - test('MaterialStatesController dispatches memory events', () { - expect(()=> MaterialStatesController().dispose(), dispatchesMemoryEvents(MaterialStatesController)); + test('MaterialStatesController dispatches memory events', () async { + await expectLater( + await memoryEvents(() => MaterialStatesController().dispose(), MaterialStatesController), + areCreateAndDispose, + ); }); test('MaterialStatesController update, listener', () { diff --git a/packages/flutter/test/services/restoration_test.dart b/packages/flutter/test/services/restoration_test.dart index c82224ac59a98..dc3472dcde029 100644 --- a/packages/flutter/test/services/restoration_test.dart +++ b/packages/flutter/test/services/restoration_test.dart @@ -14,7 +14,10 @@ import 'restoration.dart'; void main() { testWidgetsWithLeakTracking('$RestorationManager dispatches memory events', (WidgetTester tester) async { - expect(() => RestorationManager().dispose(), dispatchesMemoryEvents(RestorationManager)); + await expectLater( + await memoryEvents(() => RestorationManager().dispose(), RestorationManager), + areCreateAndDispose, + ); }); group('RestorationManager', () { diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index fea504a93e826..8e3cfb9974bbb 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -1770,12 +1770,18 @@ void main() { tester.binding.focusManager.removeListener(handleFocusChange); }); - test('$FocusManager dispatches object creation in constructor', () { - expect(()=> FocusManager().dispose(), dispatchesMemoryEvents(FocusManager)); + test('$FocusManager dispatches object creation in constructor', () async { + await expectLater( + await memoryEvents(() => FocusManager().dispose(), FocusManager), + areCreateAndDispose, + ); }); - test('$FocusNode dispatches object creation in constructor', () { - expect(()=> FocusNode().dispose(), dispatchesMemoryEvents(FocusNode)); + test('$FocusNode dispatches object creation in constructor', () async { + await expectLater( + await memoryEvents(() => FocusNode().dispose(), FocusNode), + areCreateAndDispose, + ); }); testWidgetsWithLeakTracking('FocusManager notifies listeners when a widget loses focus because it was removed.', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/restorable_property_test.dart b/packages/flutter/test/widgets/restorable_property_test.dart index f6725601507ac..835380a7ba0e3 100644 --- a/packages/flutter/test/widgets/restorable_property_test.dart +++ b/packages/flutter/test/widgets/restorable_property_test.dart @@ -59,7 +59,10 @@ void main() { }); testWidgetsWithLeakTracking('$RestorableProperty dispatches creation in constructor', (WidgetTester widgetTester) async { - expect(() => RestorableDateTimeN(null).dispose(), dispatchesMemoryEvents(RestorableDateTimeN)); + await expectLater( + await memoryEvents(() => RestorableDateTimeN(null).dispose(), RestorableDateTimeN), + areCreateAndDispose, + ); }); testWidgetsWithLeakTracking('work when not in restoration scope', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/router_test.dart b/packages/flutter/test/widgets/router_test.dart index b6e5ec80cc7d9..2f739778d5279 100644 --- a/packages/flutter/test/widgets/router_test.dart +++ b/packages/flutter/test/widgets/router_test.dart @@ -1584,14 +1584,16 @@ testWidgets('ChildBackButtonDispatcher take priority recursively', (WidgetTester }); }); - test('$PlatformRouteInformationProvider dispatches object creation in constructor', () { - void createAndDispose() { + test('$PlatformRouteInformationProvider dispatches object creation in constructor', () async { + Future<void> createAndDispose() async { PlatformRouteInformationProvider( initialRouteInformation: RouteInformation(uri: Uri.parse('http://google.com')), ).dispose(); } - - expect(createAndDispose, dispatchesMemoryEvents(PlatformRouteInformationProvider)); + await expectLater( + await memoryEvents(createAndDispose, PlatformRouteInformationProvider), + areCreateAndDispose, + ); }); } diff --git a/packages/flutter/test/widgets/scroll_controller_test.dart b/packages/flutter/test/widgets/scroll_controller_test.dart index 32b8a19f5c7db..3b1682ac524b7 100644 --- a/packages/flutter/test/widgets/scroll_controller_test.dart +++ b/packages/flutter/test/widgets/scroll_controller_test.dart @@ -409,7 +409,10 @@ void main() { expect(isScrolling, isTrue); }); - test('$ScrollController dispatches object creation in constructor', () { - expect(() => ScrollController().dispose(), dispatchesMemoryEvents(ScrollController)); + test('$ScrollController dispatches object creation in constructor', () async { + await expectLater( + await memoryEvents(() => ScrollController().dispose(), ScrollController), + areCreateAndDispose, + ); }); } diff --git a/packages/flutter/test/widgets/shortcuts_test.dart b/packages/flutter/test/widgets/shortcuts_test.dart index ed2d5ad99e919..047f727a466c9 100644 --- a/packages/flutter/test/widgets/shortcuts_test.dart +++ b/packages/flutter/test/widgets/shortcuts_test.dart @@ -672,8 +672,11 @@ void main() { expect(pressedKeys, isEmpty); }); - test('$ShortcutManager dispatches object creation in constructor', () { - expect(()=> ShortcutManager().dispose(), dispatchesMemoryEvents(ShortcutManager)); + test('$ShortcutManager dispatches object creation in constructor', () async { + await expectLater( + await memoryEvents(() => ShortcutManager().dispose(), ShortcutManager), + areCreateAndDispose, + ); }); testWidgetsWithLeakTracking("Shortcuts passes to the next Shortcuts widget if it doesn't map the key", (WidgetTester tester) async { @@ -1872,8 +1875,11 @@ void main() { token.dispose(); }); - test('dispatches object creation in constructor', () { - expect(()=> ShortcutRegistry().dispose(), dispatchesMemoryEvents(ShortcutRegistry)); + test('dispatches object creation in constructor', () async { + await expectLater( + await memoryEvents(() => ShortcutRegistry().dispose(), ShortcutRegistry), + areCreateAndDispose, + ); }); }); } From 4204f07d76ec39985268bbbc2de3f6b6c491eac7 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Thu, 21 Sep 2023 19:24:52 +0200 Subject: [PATCH 1393/1547] Add RestorationManager disposals in test/services/restoration_test.dart. (#135218) --- .../test/services/restoration_test.dart | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/flutter/test/services/restoration_test.dart b/packages/flutter/test/services/restoration_test.dart index dc3472dcde029..ce52f5f342bcb 100644 --- a/packages/flutter/test/services/restoration_test.dart +++ b/packages/flutter/test/services/restoration_test.dart @@ -30,6 +30,7 @@ void main() { }); final RestorationManager manager = RestorationManager(); + addTearDown(manager.dispose); final Future<RestorationBucket?> rootBucketFuture = manager.rootBucket; RestorationBucket? rootBucket; rootBucketFuture.then((RestorationBucket? bucket) { @@ -65,13 +66,9 @@ void main() { }); expect(synchronousBucket, isNotNull); expect(synchronousBucket, same(rootBucket)); - }, - // TODO(NobodyForNothing): Remove after fixing and cover remaining file - // with leak tests https://github.com/flutter/flutter/issues/134831 - leakTrackingTestConfig: const LeakTrackingTestConfig(notDisposedAllowList: - <String, int?>{'RestorationManager': 1})); + }); - testWidgets('root bucket received from engine before retrieval', (WidgetTester tester) async { + testWidgetsWithLeakTracking('root bucket received from engine before retrieval', (WidgetTester tester) async { SystemChannels.restoration.setMethodCallHandler(null); final List<MethodCall> callsToEngine = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async { @@ -79,6 +76,7 @@ void main() { return null; }); final RestorationManager manager = RestorationManager(); + addTearDown(manager.dispose); await _pushDataFromEngine(_createEncodedRestorationData1()); @@ -90,7 +88,7 @@ void main() { expect(callsToEngine, isEmpty); }); - testWidgets('root bucket received while engine retrieval is pending', (WidgetTester tester) async { + testWidgetsWithLeakTracking('root bucket received while engine retrieval is pending', (WidgetTester tester) async { SystemChannels.restoration.setMethodCallHandler(null); final List<MethodCall> callsToEngine = <MethodCall>[]; final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>(); @@ -99,6 +97,7 @@ void main() { return result.future; }); final RestorationManager manager = RestorationManager(); + addTearDown(manager.dispose); RestorationBucket? rootBucket; manager.rootBucket.then((RestorationBucket? bucket) => rootBucket = bucket); @@ -120,11 +119,12 @@ void main() { expect(rootBucket2!.contains('foo'), isFalse); }); - testWidgets('root bucket is properly replaced when new data is available', (WidgetTester tester) async { + testWidgetsWithLeakTracking('root bucket is properly replaced when new data is available', (WidgetTester tester) async { tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) async { return _createEncodedRestorationData1(); }); final RestorationManager manager = RestorationManager(); + addTearDown(manager.dispose); RestorationBucket? rootBucket; manager.rootBucket.then((RestorationBucket? bucket) { rootBucket = bucket; @@ -160,7 +160,7 @@ void main() { expect(newChild.read<String>('bar'), 'Hello'); }); - testWidgets('returns null as root bucket when restoration is disabled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('returns null as root bucket when restoration is disabled', (WidgetTester tester) async { final List<MethodCall> callsToEngine = <MethodCall>[]; final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>(); tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) { @@ -171,6 +171,7 @@ void main() { final RestorationManager manager = RestorationManager()..addListener(() { listenerCount++; }); + addTearDown(manager.dispose); RestorationBucket? rootBucket; bool rootBucketResolved = false; manager.rootBucket.then((RestorationBucket? bucket) { @@ -203,7 +204,7 @@ void main() { expect(rootBucket, isNull); }); - testWidgets('flushData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('flushData', (WidgetTester tester) async { final List<MethodCall> callsToEngine = <MethodCall>[]; final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>(); tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) { @@ -212,6 +213,7 @@ void main() { }); final RestorationManager manager = RestorationManager(); + addTearDown(manager.dispose); final Future<RestorationBucket?> rootBucketFuture = manager.rootBucket; RestorationBucket? rootBucket; rootBucketFuture.then((RestorationBucket? bucket) { @@ -239,13 +241,14 @@ void main() { expect(callsToEngine, hasLength(1)); }); - testWidgets('isReplacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('isReplacing', (WidgetTester tester) async { final Completer<Map<dynamic, dynamic>> result = Completer<Map<dynamic, dynamic>>(); tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.restoration, (MethodCall call) { return result.future; }); final TestRestorationManager manager = TestRestorationManager(); + addTearDown(manager.dispose); expect(manager.isReplacing, isFalse); RestorationBucket? rootBucket; From de44daf1f86834ec63727fa115f1b4fd30fa5c0b Mon Sep 17 00:00:00 2001 From: Bruno Leroux <leroux_bruno@yahoo.fr> Date: Thu, 21 Sep 2023 19:37:07 +0200 Subject: [PATCH 1394/1547] Add a parameter to configure InputDecorator hint fade animations duration (#135211) ## Description This PR adds a parameter to configure the input decorator hint fade transition duration. This animation is not part of the Material specification. Removing it was considered but it breaks internal tests (see https://github.com/flutter/flutter/pull/107406). I also considered several ways to avoid the fade animation (setting duration to 0, removing the hint text, etc) but it breaks many existing tests that assumes the hint text to be visible. To mitigate the issue in a non disruptive way, I set the default duration to 20ms (an arbitrary short value). ## Related Issue Fixes https://github.com/flutter/flutter/issues/20283. ## Tests Adds 3 tests, updates 3 tests. --- .../lib/src/material/input_decorator.dart | 33 +- .../test/material/input_decorator_test.dart | 297 +++++++++++++++--- 2 files changed, 287 insertions(+), 43 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index abaab18e4e6c5..e429eb8e7740c 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -30,6 +30,13 @@ const Duration _kTransitionDuration = Duration(milliseconds: 167); const Curve _kTransitionCurve = Curves.fastOutSlowIn; const double _kFinalLabelScale = 0.75; +// The default duration for hint fade in/out transitions. +// +// Animating hint is not mentioned in the Material specification. +// The animation is kept for backard compatibility and a short duration +// is used to mitigate the UX impact. +const Duration _kHintFadeTransitionDuration = Duration(milliseconds: 20); + // Defines the gap in the InputDecorator's outline border where the // floating label will appear. class _InputBorderGap extends ChangeNotifier { @@ -2192,7 +2199,7 @@ class _InputDecoratorState extends State<InputDecorator> with TickerProviderStat final String? hintText = decoration.hintText; final Widget? hint = hintText == null ? null : AnimatedOpacity( opacity: (isEmpty && !_hasInlineLabel) ? 1.0 : 0.0, - duration: _kTransitionDuration, + duration: decoration.hintFadeDuration ?? _kHintFadeTransitionDuration, curve: _kTransitionCurve, child: Text( hintText, @@ -2571,6 +2578,7 @@ class InputDecoration { this.hintStyle, this.hintTextDirection, this.hintMaxLines, + this.hintFadeDuration, this.error, this.errorText, this.errorStyle, @@ -2641,6 +2649,7 @@ class InputDecoration { helperStyle = null, helperMaxLines = null, hintMaxLines = null, + hintFadeDuration = null, error = null, errorText = null, errorStyle = null, @@ -2854,6 +2863,12 @@ class InputDecoration { /// used to handle the overflow when it is limited to single line. final int? hintMaxLines; + /// The duration of the [hintText] fade in and fade out animations. + /// + /// If null, defaults to [InputDecorationTheme.hintFadeDuration]. + /// If [InputDecorationTheme.hintFadeDuration] is null defaults to 20ms. + final Duration? hintFadeDuration; + /// Optional widget that appears below the [InputDecorator.child] and the border. /// /// If non-null, the border's color animates to red and the [helperText] is not shown. @@ -3507,6 +3522,7 @@ class InputDecoration { String? hintText, TextStyle? hintStyle, TextDirection? hintTextDirection, + Duration? hintFadeDuration, int? hintMaxLines, Widget? error, String? errorText, @@ -3561,6 +3577,7 @@ class InputDecoration { hintStyle: hintStyle ?? this.hintStyle, hintTextDirection: hintTextDirection ?? this.hintTextDirection, hintMaxLines: hintMaxLines ?? this.hintMaxLines, + hintFadeDuration: hintFadeDuration ?? this.hintFadeDuration, error: error ?? this.error, errorText: errorText ?? this.errorText, errorStyle: errorStyle ?? this.errorStyle, @@ -3614,6 +3631,7 @@ class InputDecoration { helperStyle: helperStyle ?? theme.helperStyle, helperMaxLines : helperMaxLines ?? theme.helperMaxLines, hintStyle: hintStyle ?? theme.hintStyle, + hintFadeDuration: hintFadeDuration ?? theme.hintFadeDuration, errorStyle: errorStyle ?? theme.errorStyle, errorMaxLines: errorMaxLines ?? theme.errorMaxLines, floatingLabelBehavior: floatingLabelBehavior ?? theme.floatingLabelBehavior, @@ -3664,6 +3682,7 @@ class InputDecoration { && other.hintStyle == hintStyle && other.hintTextDirection == hintTextDirection && other.hintMaxLines == hintMaxLines + && other.hintFadeDuration == hintFadeDuration && other.error == error && other.errorText == errorText && other.errorStyle == errorStyle @@ -3720,6 +3739,7 @@ class InputDecoration { hintStyle, hintTextDirection, hintMaxLines, + hintFadeDuration, error, errorText, errorStyle, @@ -3774,6 +3794,7 @@ class InputDecoration { if (helperMaxLines != null) 'helperMaxLines: "$helperMaxLines"', if (hintText != null) 'hintText: "$hintText"', if (hintMaxLines != null) 'hintMaxLines: "$hintMaxLines"', + if (hintFadeDuration != null) 'hintFadeDuration: "$hintFadeDuration"', if (error != null) 'error: "$error"', if (errorText != null) 'errorText: "$errorText"', if (errorStyle != null) 'errorStyle: "$errorStyle"', @@ -3836,6 +3857,7 @@ class InputDecorationTheme with Diagnosticable { this.helperStyle, this.helperMaxLines, this.hintStyle, + this.hintFadeDuration, this.errorStyle, this.errorMaxLines, this.floatingLabelBehavior = FloatingLabelBehavior.auto, @@ -3906,6 +3928,9 @@ class InputDecorationTheme with Diagnosticable { /// input field and the current [Theme]. final TextStyle? hintStyle; + /// The duration of the [InputDecoration.hintText] fade in and fade out animations. + final Duration? hintFadeDuration; + /// {@macro flutter.material.inputDecoration.errorStyle} final TextStyle? errorStyle; @@ -4243,6 +4268,7 @@ class InputDecorationTheme with Diagnosticable { TextStyle? helperStyle, int? helperMaxLines, TextStyle? hintStyle, + Duration? hintFadeDuration, TextStyle? errorStyle, int? errorMaxLines, FloatingLabelBehavior? floatingLabelBehavior, @@ -4277,6 +4303,7 @@ class InputDecorationTheme with Diagnosticable { helperStyle: helperStyle ?? this.helperStyle, helperMaxLines: helperMaxLines ?? this.helperMaxLines, hintStyle: hintStyle ?? this.hintStyle, + hintFadeDuration: hintFadeDuration ?? this.hintFadeDuration, errorStyle: errorStyle ?? this.errorStyle, errorMaxLines: errorMaxLines ?? this.errorMaxLines, floatingLabelBehavior: floatingLabelBehavior ?? this.floatingLabelBehavior, @@ -4326,6 +4353,7 @@ class InputDecorationTheme with Diagnosticable { helperStyle: helperStyle ?? inputDecorationTheme.helperStyle, helperMaxLines: helperMaxLines ?? inputDecorationTheme.helperMaxLines, hintStyle: hintStyle ?? inputDecorationTheme.hintStyle, + hintFadeDuration: hintFadeDuration ?? inputDecorationTheme.hintFadeDuration, errorStyle: errorStyle ?? inputDecorationTheme.errorStyle, errorMaxLines: errorMaxLines ?? inputDecorationTheme.errorMaxLines, contentPadding: contentPadding ?? inputDecorationTheme.contentPadding, @@ -4385,6 +4413,7 @@ class InputDecorationTheme with Diagnosticable { border, alignLabelWithHint, constraints, + hintFadeDuration, ), ); @@ -4402,6 +4431,7 @@ class InputDecorationTheme with Diagnosticable { && other.helperStyle == helperStyle && other.helperMaxLines == helperMaxLines && other.hintStyle == hintStyle + && other.hintFadeDuration == hintFadeDuration && other.errorStyle == errorStyle && other.errorMaxLines == errorMaxLines && other.isDense == isDense @@ -4441,6 +4471,7 @@ class InputDecorationTheme with Diagnosticable { properties.add(DiagnosticsProperty<TextStyle>('helperStyle', helperStyle, defaultValue: defaultTheme.helperStyle)); properties.add(IntProperty('helperMaxLines', helperMaxLines, defaultValue: defaultTheme.helperMaxLines)); properties.add(DiagnosticsProperty<TextStyle>('hintStyle', hintStyle, defaultValue: defaultTheme.hintStyle)); + properties.add(DiagnosticsProperty<Duration>('hintFadeDuration', hintFadeDuration, defaultValue: defaultTheme.hintFadeDuration)); properties.add(DiagnosticsProperty<TextStyle>('errorStyle', errorStyle, defaultValue: defaultTheme.errorStyle)); properties.add(IntProperty('errorMaxLines', errorMaxLines, defaultValue: defaultTheme.errorMaxLines)); properties.add(DiagnosticsProperty<FloatingLabelBehavior>('floatingLabelBehavior', floatingLabelBehavior, defaultValue: defaultTheme.floatingLabelBehavior)); diff --git a/packages/flutter/test/material/input_decorator_test.dart b/packages/flutter/test/material/input_decorator_test.dart index edf9bec88c351..eed10b5bc06d4 100644 --- a/packages/flutter/test/material/input_decorator_test.dart +++ b/packages/flutter/test/material/input_decorator_test.dart @@ -1089,14 +1089,14 @@ void runAllTests({ required bool useMaterial3 }) { ); // The hint's opacity animates from 0.0 to 1.0. - // The animation's duration is 167ms. + // The animation's default duration is 20ms. { - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity50ms = getOpacity(tester, 'hint'); - expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity100ms = getOpacity(tester, 'hint'); - expect(hintOpacity100ms, inExclusiveRange(hintOpacity50ms, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(hintOpacity9ms, 1.0)); } await tester.pumpAndSettle(); @@ -1123,14 +1123,14 @@ void runAllTests({ required bool useMaterial3 }) { ); // The hint's opacity animates from 1.0 to 0.0. - // The animation's duration is 167ms. + // The animation's default duration is 20ms. { - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity50ms = getOpacity(tester, 'hint'); - expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity100ms = getOpacity(tester, 'hint'); - expect(hintOpacity100ms, inExclusiveRange(0.0, hintOpacity50ms)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(0.0, hintOpacity9ms)); } await tester.pumpAndSettle(); @@ -1210,6 +1210,219 @@ void runAllTests({ required bool useMaterial3 }) { expect(getBorderWeight(tester), 2.0); }); + testWidgetsWithLeakTracking('InputDecorator default hint animation duration', (WidgetTester tester) async { + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isEmpty: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + ), + ), + ); + + // The hint is not visible (opacity 0.0). + expect(getOpacity(tester, 'hint'), 0.0); + + // Focus to show the hint. + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isEmpty: true, + isFocused: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + ), + ), + ); + + // The hint's opacity animates from 0.0 to 1.0. + // The animation's default duration is 20ms. + { + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(hintOpacity9ms, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + expect(getOpacity(tester, 'hint'), 1.0); + } + + // Unfocus to hide the hint. + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isEmpty: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + ), + ), + ); + + // The hint's opacity animates from 1.0 to 0.0. + // The animation's default duration is 20ms. + { + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(0.0, hintOpacity9ms)); + await tester.pump(const Duration(milliseconds: 9)); + expect(getOpacity(tester, 'hint'), 0.0); + } + }); + + testWidgetsWithLeakTracking('InputDecorator custom hint animation duration', (WidgetTester tester) async { + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isEmpty: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + hintFadeDuration: Duration(milliseconds: 120), + ), + ), + ); + + // The hint is not visible (opacity 0.0). + expect(getOpacity(tester, 'hint'), 0.0); + + // Focus to show the hint. + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isEmpty: true, + isFocused: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + hintFadeDuration: Duration(milliseconds: 120), + ), + ), + ); + + // The hint's opacity animates from 0.0 to 1.0. + // The animation's duration is set to 120ms. + { + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity50ms = getOpacity(tester, 'hint'); + expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity100ms = getOpacity(tester, 'hint'); + expect(hintOpacity100ms, inExclusiveRange(hintOpacity50ms, 1.0)); + await tester.pump(const Duration(milliseconds: 50)); + expect(getOpacity(tester, 'hint'), 1.0); + } + + // Unfocus to hide the hint. + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + isEmpty: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + hintFadeDuration: Duration(milliseconds: 120), + ), + ), + ); + + // The hint's opacity animates from 1.0 to 0.0. + // The animation's default duration is 20ms. + { + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity50ms = getOpacity(tester, 'hint'); + expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity100ms = getOpacity(tester, 'hint'); + expect(hintOpacity100ms, inExclusiveRange(0.0, hintOpacity50ms)); + await tester.pump(const Duration(milliseconds: 50)); + expect(getOpacity(tester, 'hint'), 0.0); + } + }); + + testWidgetsWithLeakTracking('InputDecorator custom hint animation duration from theme', (WidgetTester tester) async { + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + inputDecorationTheme: const InputDecorationTheme( + hintFadeDuration: Duration(milliseconds: 120), + ), + isEmpty: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + ), + ), + ); + + // The hint is not visible (opacity 0.0). + expect(getOpacity(tester, 'hint'), 0.0); + + // Focus to show the hint. + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + inputDecorationTheme: const InputDecorationTheme( + hintFadeDuration: Duration(milliseconds: 120), + ), + isEmpty: true, + isFocused: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + ), + ), + ); + + // The hint's opacity animates from 0.0 to 1.0. + // The animation's duration is set to 120ms. + { + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity50ms = getOpacity(tester, 'hint'); + expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity100ms = getOpacity(tester, 'hint'); + expect(hintOpacity100ms, inExclusiveRange(hintOpacity50ms, 1.0)); + await tester.pump(const Duration(milliseconds: 50)); + expect(getOpacity(tester, 'hint'), 1.0); + } + + // Unfocus to hide the hint. + await tester.pumpWidget( + buildInputDecorator( + useMaterial3: useMaterial3, + inputDecorationTheme: const InputDecorationTheme( + hintFadeDuration: Duration(milliseconds: 120), + ), + isEmpty: true, + decoration: const InputDecoration( + labelText: 'label', + hintText: 'hint', + ), + ), + ); + + // The hint's opacity animates from 1.0 to 0.0. + // The animation's duration is set to 160ms. + { + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity50ms = getOpacity(tester, 'hint'); + expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 50)); + final double hintOpacity100ms = getOpacity(tester, 'hint'); + expect(hintOpacity100ms, inExclusiveRange(0.0, hintOpacity50ms)); + await tester.pump(const Duration(milliseconds: 50)); + expect(getOpacity(tester, 'hint'), 0.0); + } + }); + testWidgetsWithLeakTracking('InputDecorator with no input border', (WidgetTester tester) async { // Label is visible, hint is not (opacity 0.0). await tester.pumpWidget( @@ -2246,14 +2459,14 @@ void runAllTests({ required bool useMaterial3 }) { ); // The hint's opacity animates from 0.0 to 1.0. - // The animation's duration is 167ms. + // The animation's default duration is 20ms. { - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity50ms = getOpacity(tester, 'hint'); - expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity100ms = getOpacity(tester, 'hint'); - expect(hintOpacity100ms, inExclusiveRange(hintOpacity50ms, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(hintOpacity9ms, 1.0)); } await tester.pumpAndSettle(); @@ -2281,14 +2494,14 @@ void runAllTests({ required bool useMaterial3 }) { ); // The hint's opacity animates from 1.0 to 0.0. - // The animation's duration is 167ms. + // The animation's default duration is 20ms. { - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity50ms = getOpacity(tester, 'hint'); - expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity100ms = getOpacity(tester, 'hint'); - expect(hintOpacity100ms, inExclusiveRange(0.0, hintOpacity50ms)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(0.0, hintOpacity9ms)); } await tester.pumpAndSettle(); @@ -2343,14 +2556,14 @@ void runAllTests({ required bool useMaterial3 }) { ); // The hint's opacity animates from 0.0 to 1.0. - // The animation's duration is 167ms. + // The animation's default duration is 20ms. { - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity50ms = getOpacity(tester, 'hint'); - expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity100ms = getOpacity(tester, 'hint'); - expect(hintOpacity100ms, inExclusiveRange(hintOpacity50ms, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(hintOpacity9ms, 1.0)); } await tester.pumpAndSettle(); @@ -2378,14 +2591,14 @@ void runAllTests({ required bool useMaterial3 }) { ); // The hint's opacity animates from 1.0 to 0.0. - // The animation's duration is 167ms. + // The animation's default duration is 20ms. { - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity50ms = getOpacity(tester, 'hint'); - expect(hintOpacity50ms, inExclusiveRange(0.0, 1.0)); - await tester.pump(const Duration(milliseconds: 50)); - final double hintOpacity100ms = getOpacity(tester, 'hint'); - expect(hintOpacity100ms, inExclusiveRange(0.0, hintOpacity50ms)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity9ms = getOpacity(tester, 'hint'); + expect(hintOpacity9ms, inExclusiveRange(0.0, 1.0)); + await tester.pump(const Duration(milliseconds: 9)); + final double hintOpacity18ms = getOpacity(tester, 'hint'); + expect(hintOpacity18ms, inExclusiveRange(0.0, hintOpacity9ms)); } await tester.pumpAndSettle(); From 203ec67c6596d28081577a92eee0a5160f60ba7c Mon Sep 17 00:00:00 2001 From: Tong Mu <dkwingsmt@users.noreply.github.com> Date: Thu, 21 Sep 2023 10:43:07 -0700 Subject: [PATCH 1395/1547] Fix violation of the render rule in Windows Startup Test (#134245) This PR fixes yet another case in the windows startup test that violates the render rule, which caused https://github.com/flutter/engine/pull/45300 to be reverted. Although the `FlutterView.render` call is within `onBeginFrame`, there is an `await` before the call, causing the call to fall out of the synchronous scope. I've added this problem to the documentation of `FlutterView.render` in https://github.com/flutter/engine/pull/45555. --- .../windows_startup_test/lib/main.dart | 65 ++++++++++++++----- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/dev/integration_tests/windows_startup_test/lib/main.dart b/dev/integration_tests/windows_startup_test/lib/main.dart index 6917653db72e9..f79473238a15b 100644 --- a/dev/integration_tests/windows_startup_test/lib/main.dart +++ b/dev/integration_tests/windows_startup_test/lib/main.dart @@ -31,6 +31,25 @@ void drawHelloWorld(ui.FlutterView view) { view.render(sceneBuilder.build()); } +Future<void> _waitUntilWindowVisible() async { + while (!await isWindowVisible()) { + await Future<void>.delayed(const Duration(milliseconds: 100)); + } +} + +void _expectVisible(bool current, bool expect, Completer<String> completer, int frameCount) { + if (current != expect) { + try { + throw 'Window should be ${expect ? 'visible' : 'hidden'} on frame $frameCount'; + } catch (e) { + if (!completer.isCompleted) { + completer.completeError(e); + } + rethrow; + } + } +} + void main() async { // TODO(goderbauer): Create a window if embedder doesn't provide an implicit view to draw into. assert(ui.PlatformDispatcher.instance.implicitView != null); @@ -70,27 +89,39 @@ void main() async { throw 'Window should be hidden at startup'; } - bool firstFrame = true; - ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) async { - if (await isWindowVisible()) { - if (firstFrame) { - throw 'Window should be hidden on first frame'; - } - - if (!visibilityCompleter.isCompleted) { - visibilityCompleter.complete('success'); - } + int frameCount = 0; + ui.PlatformDispatcher.instance.onBeginFrame = (Duration duration) { + // Our goal is to verify that it's `drawHelloWorld` that makes the window + // appear, not anything else. This requires checking the visibility right + // before drawing, but since `isWindowVisible` has to be async, and + // `FlutterView.render` (in `drawHelloWorld`) forbids async before it, + // this can not be done during a single onBeginFrame. However, we can + // verify in separate frames to indirectly prove it, by ensuring that + // no other mechanism can affect isWindowVisible in the first frame at all. + frameCount += 1; + switch (frameCount) { + // The 1st frame: render nothing, just verify that the window is hidden. + case 1: + isWindowVisible().then((bool visible) { + _expectVisible(visible, false, visibilityCompleter, frameCount); + ui.PlatformDispatcher.instance.scheduleFrame(); + }); + // The 2nd frame: render, which makes the window appear. + case 2: + drawHelloWorld(view); + _waitUntilWindowVisible().then((_) { + if (!visibilityCompleter.isCompleted) { + visibilityCompleter.complete('success'); + } + }); + // Others, in case requested to render. + default: + drawHelloWorld(view); } - - // Draw something to trigger the first frame callback that displays the - // window. - drawHelloWorld(view); - firstFrame = false; }; - - ui.PlatformDispatcher.instance.scheduleFrame(); } catch (e) { visibilityCompleter.completeError(e); rethrow; } + ui.PlatformDispatcher.instance.scheduleFrame(); } From da1f801fd5b971ff95e78e6c2757217b611320d1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 14:16:40 -0400 Subject: [PATCH 1396/1547] Roll Flutter Engine from fa032d52a118 to 78c1ad249b57 (1 revision) (#135238) https://github.com/flutter/engine/compare/fa032d52a118...78c1ad249b57 2023-09-21 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 3DKf4d8UFviYKRI28... to PXDDhlPyd9sgrWWun... (flutter/engine#46148) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 3DKf4d8UFviY to PXDDhlPyd9sg If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8a039f6dd379a..153324e92fc42 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -fa032d52a1185c761dc67c00ee17ffeb9b6a53c1 +78c1ad249b57164c85468c39491c4f618724ce5d diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 4569c4540f718..d6fff414b4b54 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -3DKf4d8UFviYKRI289TgMqMOusKtYENjbSeT4i3xySIC +PXDDhlPyd9sgrWWunaLin7Q_HAx2RMYRbJ6NXLlIrJUC From c627dbfbc6400a0ac53d175fe368b178b7acb506 Mon Sep 17 00:00:00 2001 From: Derek Xu <derekx@google.com> Date: Thu, 21 Sep 2023 14:32:35 -0400 Subject: [PATCH 1397/1547] Add `--frontend-server-starter-path` option to `flutter run` and `flutter test` (#135038) --- packages/flutter_tools/bin/macos_assemble.sh | 1 + packages/flutter_tools/bin/tool_backend.dart | 3 ++ packages/flutter_tools/bin/xcode_backend.dart | 1 + .../gradle/src/main/groovy/flutter.groovy | 10 ++++ .../flutter_tools/lib/src/build_info.dart | 14 ++++++ .../lib/src/build_system/targets/common.dart | 2 + .../flutter_tools/lib/src/commands/run.dart | 1 + .../flutter_tools/lib/src/commands/test.dart | 1 + packages/flutter_tools/lib/src/compile.dart | 24 ++++++---- .../lib/src/resident_runner.dart | 3 ++ .../lib/src/runner/flutter_command.dart | 17 +++++++ .../lib/src/test/test_compiler.dart | 1 + .../test/general.shard/build_info_test.dart | 6 +++ .../build_system/targets/common_test.dart | 47 +++++++++++++++++++ .../build_system/targets/web_test.dart | 32 +++++++++++++ .../general.shard/bundle_builder_test.dart | 2 + .../general.shard/resident_runner_test.dart | 22 +++++++++ .../general.shard/xcode_backend_test.dart | 5 ++ 18 files changed, 184 insertions(+), 8 deletions(-) diff --git a/packages/flutter_tools/bin/macos_assemble.sh b/packages/flutter_tools/bin/macos_assemble.sh index 3f21624e7c964..3963a80839532 100755 --- a/packages/flutter_tools/bin/macos_assemble.sh +++ b/packages/flutter_tools/bin/macos_assemble.sh @@ -123,6 +123,7 @@ BuildApp() { "-dSplitDebugInfo=${SPLIT_DEBUG_INFO}" "-dTrackWidgetCreation=${TRACK_WIDGET_CREATION}" "-dAction=${ACTION}" + "-dFrontendServerStarterPath=${FRONTEND_SERVER_STARTER_PATH}" "--DartDefines=${DART_DEFINES}" "--ExtraGenSnapshotOptions=${EXTRA_GEN_SNAPSHOT_OPTIONS}" "--ExtraFrontEndOptions=${EXTRA_FRONT_END_OPTIONS}" diff --git a/packages/flutter_tools/bin/tool_backend.dart b/packages/flutter_tools/bin/tool_backend.dart index 7b67f56757638..d98c7055477db 100644 --- a/packages/flutter_tools/bin/tool_backend.dart +++ b/packages/flutter_tools/bin/tool_backend.dart @@ -13,6 +13,7 @@ Future<void> main(List<String> arguments) async { final String? dartDefines = Platform.environment['DART_DEFINES']; final bool dartObfuscation = Platform.environment['DART_OBFUSCATION'] == 'true'; + final String? frontendServerStarterPath = Platform.environment['FRONTEND_SERVER_STARTER_PATH']; final String? extraFrontEndOptions = Platform.environment['EXTRA_FRONT_END_OPTIONS']; final String? extraGenSnapshotOptions = Platform.environment['EXTRA_GEN_SNAPSHOT_OPTIONS']; final String? flutterEngine = Platform.environment['FLUTTER_ENGINE']; @@ -106,6 +107,8 @@ or '--DartDefines=$dartDefines', if (extraGenSnapshotOptions != null) '--ExtraGenSnapshotOptions=$extraGenSnapshotOptions', + if (frontendServerStarterPath != null) + '-dFrontendServerStarterPath=$frontendServerStarterPath', if (extraFrontEndOptions != null) '--ExtraFrontEndOptions=$extraFrontEndOptions', target, diff --git a/packages/flutter_tools/bin/xcode_backend.dart b/packages/flutter_tools/bin/xcode_backend.dart index 87d1c22313a5f..6e3fb7174a015 100644 --- a/packages/flutter_tools/bin/xcode_backend.dart +++ b/packages/flutter_tools/bin/xcode_backend.dart @@ -402,6 +402,7 @@ class Context { '-dTrackWidgetCreation=${environment['TRACK_WIDGET_CREATION'] ?? ''}', '-dDartObfuscation=${environment['DART_OBFUSCATION'] ?? ''}', '-dAction=${environment['ACTION'] ?? ''}', + '-dFrontendServerStarterPath=${environment['FRONTEND_SERVER_STARTER_PATH'] ?? ''}', '--ExtraGenSnapshotOptions=${environment['EXTRA_GEN_SNAPSHOT_OPTIONS'] ?? ''}', '--DartDefines=${environment['DART_DEFINES'] ?? ''}', '--ExtraFrontEndOptions=${environment['EXTRA_FRONT_END_OPTIONS'] ?? ''}', diff --git a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy index f3c1a4145cf24..53808cfe48ccc 100644 --- a/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy +++ b/packages/flutter_tools/gradle/src/main/groovy/flutter.groovy @@ -964,6 +964,10 @@ class FlutterPlugin implements Plugin<Project> { if (project.hasProperty('track-widget-creation')) { trackWidgetCreationValue = project.property('track-widget-creation').toBoolean() } + String frontendServerStarterPathValue = null + if (project.hasProperty('frontend-server-starter-path')) { + frontendServerStarterPathValue = project.property('frontend-server-starter-path') + } String extraFrontEndOptionsValue = null if (project.hasProperty('extra-front-end-options')) { extraFrontEndOptionsValue = project.property('extra-front-end-options') @@ -1052,6 +1056,7 @@ class FlutterPlugin implements Plugin<Project> { targetPlatformValues = targetPlatforms sourceDir getFlutterSourceDirectory() intermediateDir project.file("${project.buildDir}/$INTERMEDIATES_DIR/flutter/${variant.name}/") + frontendServerStarterPath frontendServerStarterPathValue extraFrontEndOptions extraFrontEndOptionsValue extraGenSnapshotOptions extraGenSnapshotOptionsValue splitDebugInfo splitDebugInfoValue @@ -1290,6 +1295,8 @@ abstract class BaseFlutterTask extends DefaultTask { @Internal File intermediateDir @Optional @Input + String frontendServerStarterPath + @Optional @Input String extraFrontEndOptions @Optional @Input String extraGenSnapshotOptions @@ -1394,6 +1401,9 @@ abstract class BaseFlutterTask extends DefaultTask { if (extraGenSnapshotOptions != null) { args "--ExtraGenSnapshotOptions=${extraGenSnapshotOptions}" } + if (frontendServerStarterPath != null) { + args "-dFrontendServerStarterPath=${frontendServerStarterPath}" + } if (extraFrontEndOptions != null) { args "--ExtraFrontEndOptions=${extraFrontEndOptions}" } diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index fea9da5c415fc..b084efeddf185 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -23,6 +23,7 @@ class BuildInfo { this.mode, this.flavor, { this.trackWidgetCreation = false, + this.frontendServerStarterPath, List<String>? extraFrontEndOptions, List<String>? extraGenSnapshotOptions, List<String>? fileSystemRoots, @@ -82,6 +83,10 @@ class BuildInfo { /// Whether the build should track widget creation locations. final bool trackWidgetCreation; + /// If provided, the frontend server will be started in JIT mode from this + /// file. + final String? frontendServerStarterPath; + /// Extra command-line options for front-end. final List<String> extraFrontEndOptions; @@ -237,6 +242,8 @@ class BuildInfo { if (dartDefines.isNotEmpty) kDartDefines: encodeDartDefines(dartDefines), kDartObfuscation: dartObfuscation.toString(), + if (frontendServerStarterPath != null) + kFrontendServerStarterPath: frontendServerStarterPath!, if (extraFrontEndOptions.isNotEmpty) kExtraFrontEndOptions: extraFrontEndOptions.join(','), if (extraGenSnapshotOptions.isNotEmpty) @@ -274,6 +281,8 @@ class BuildInfo { if (dartDefines.isNotEmpty) 'DART_DEFINES': encodeDartDefines(dartDefines), 'DART_OBFUSCATION': dartObfuscation.toString(), + if (frontendServerStarterPath != null) + 'FRONTEND_SERVER_STARTER_PATH': frontendServerStarterPath!, if (extraFrontEndOptions.isNotEmpty) 'EXTRA_FRONT_END_OPTIONS': extraFrontEndOptions.join(','), if (extraGenSnapshotOptions.isNotEmpty) @@ -310,6 +319,8 @@ class BuildInfo { if (dartDefines.isNotEmpty) '-Pdart-defines=${encodeDartDefines(dartDefines)}', '-Pdart-obfuscation=$dartObfuscation', + if (frontendServerStarterPath != null) + '-Pfrontend-server-starter-path=$frontendServerStarterPath', if (extraFrontEndOptions.isNotEmpty) '-Pextra-front-end-options=${extraFrontEndOptions.join(',')}', if (extraGenSnapshotOptions.isNotEmpty) @@ -901,6 +912,9 @@ const String kTargetFile = 'TargetFile'; /// Whether to enable or disable track widget creation. const String kTrackWidgetCreation = 'TrackWidgetCreation'; +/// If provided, the frontend server will be started in JIT mode from this file. +const String kFrontendServerStarterPath = 'FrontendServerStarterPath'; + /// Additional configuration passed to the dart front end. /// /// This is expected to be a comma separated list of strings. diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 951febd5b477c..d5febecf4251a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -178,6 +178,7 @@ class KernelSnapshot extends Target { final TargetPlatform targetPlatform = getTargetPlatformForName(targetPlatformEnvironment); // This configuration is all optional. + final String? frontendServerStarterPath = environment.defines[kFrontendServerStarterPath]; final List<String> extraFrontEndOptions = decodeCommaSeparated(environment.defines, kExtraFrontEndOptions); final List<String>? fileSystemRoots = environment.defines[kFileSystemRoots]?.split(','); final String? fileSystemScheme = environment.defines[kFileSystemScheme]; @@ -254,6 +255,7 @@ class KernelSnapshot extends Target { linkPlatformKernelIn: forceLinkPlatform || buildMode.isPrecompiled, mainPath: targetFileAbsolute, depFilePath: environment.buildDir.childFile('kernel_snapshot.d').path, + frontendServerStarterPath: frontendServerStarterPath, extraFrontEndOptions: extraFrontEndOptions, fileSystemRoots: fileSystemRoots, fileSystemScheme: fileSystemScheme, diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 67b5c0aece89e..bb6538fcf379f 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -315,6 +315,7 @@ class RunCommand extends RunCommandBase { requiresPubspecYaml(); usesFilesystemOptions(hide: !verboseHelp); usesExtraDartFlagOptions(verboseHelp: verboseHelp); + usesFrontendServerStarterPathOption(verboseHelp: verboseHelp); addEnableExperimentation(hide: !verboseHelp); usesInitializeFromDillOption(hide: !verboseHelp); diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index 16864daee6bef..a7279c5916d19 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -67,6 +67,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { requiresPubspecYaml(); usesPubOption(); addNullSafetyModeOptions(hide: !verboseHelp); + usesFrontendServerStarterPathOption(verboseHelp: verboseHelp); usesTrackWidgetCreation(verboseHelp: verboseHelp); addEnableExperimentation(hide: !verboseHelp); usesDartDefineOption(); diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index 8ba7d1e89f39c..e7571a69eac32 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -227,6 +227,7 @@ class KernelCompiler { TargetModel targetModel = TargetModel.flutter, bool linkPlatformKernelIn = false, bool aot = false, + String? frontendServerStarterPath, List<String>? extraFrontEndOptions, List<String>? fileSystemRoots, String? fileSystemScheme, @@ -243,10 +244,12 @@ class KernelCompiler { String? nativeAssets, }) async { final TargetPlatform? platform = targetModel == TargetModel.dartdevc ? TargetPlatform.web_javascript : null; - final String frontendServer = _artifacts.getArtifactPath( - Artifact.frontendServerSnapshotForEngineDartSdk, - platform: platform, - ); + final String frontendServer = (frontendServerStarterPath == null || frontendServerStarterPath.isEmpty) + ? _artifacts.getArtifactPath( + Artifact.frontendServerSnapshotForEngineDartSdk, + platform: platform, + ) + : frontendServerStarterPath; // This is a URI, not a file path, so the forward slash is correct even on Windows. if (!sdkRoot.endsWith('/')) { sdkRoot = '$sdkRoot/'; @@ -490,6 +493,7 @@ abstract class ResidentCompiler { bool assumeInitializeFromDillUpToDate, TargetModel targetModel, bool unsafePackageSerialization, + String? frontendServerStarterPath, List<String> extraFrontEndOptions, String platformDill, List<String>? dartDefines, @@ -605,6 +609,7 @@ class DefaultResidentCompiler implements ResidentCompiler { this.assumeInitializeFromDillUpToDate = false, this.targetModel = TargetModel.flutter, this.unsafePackageSerialization = false, + this.frontendServerStarterPath, this.extraFrontEndOptions, this.platformDill, List<String>? dartDefines, @@ -635,6 +640,7 @@ class DefaultResidentCompiler implements ResidentCompiler { final String? initializeFromDill; final bool assumeInitializeFromDillUpToDate; final bool unsafePackageSerialization; + final String? frontendServerStarterPath; final List<String>? extraFrontEndOptions; final List<String> dartDefines; final String? librariesSpec; @@ -771,10 +777,12 @@ class DefaultResidentCompiler implements ResidentCompiler { String? nativeAssetsUri, }) async { final TargetPlatform? platform = (targetModel == TargetModel.dartdevc) ? TargetPlatform.web_javascript : null; - final String frontendServer = artifacts.getArtifactPath( - Artifact.frontendServerSnapshotForEngineDartSdk, - platform: platform, - ); + final String frontendServer = (frontendServerStarterPath == null || frontendServerStarterPath!.isEmpty) + ? artifacts.getArtifactPath( + Artifact.frontendServerSnapshotForEngineDartSdk, + platform: platform, + ) + : frontendServerStarterPath!; final List<String> command = <String>[ artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), '--disable-dart-dev', diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 00ae359d634b6..742132b908c80 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -67,6 +67,7 @@ class FlutterDevice { targetModel: targetModel, dartDefines: buildInfo.dartDefines, packagesPath: buildInfo.packagesPath, + frontendServerStarterPath: buildInfo.frontendServerStarterPath, extraFrontEndOptions: buildInfo.extraFrontEndOptions, artifacts: globals.artifacts!, processManager: globals.processManager, @@ -155,6 +156,7 @@ class FlutterDevice { ), assumeInitializeFromDillUpToDate: buildInfo.assumeInitializeFromDillUpToDate, targetModel: TargetModel.dartdevc, + frontendServerStarterPath: buildInfo.frontendServerStarterPath, extraFrontEndOptions: extraFrontEndOptions, platformDill: globals.fs.file(platformDillPath).absolute.uri.toString(), dartDefines: buildInfo.dartDefines, @@ -185,6 +187,7 @@ class FlutterDevice { fileSystemScheme: buildInfo.fileSystemScheme, targetModel: targetModel, dartDefines: buildInfo.dartDefines, + frontendServerStarterPath: buildInfo.frontendServerStarterPath, extraFrontEndOptions: extraFrontEndOptions, initializeFromDill: buildInfo.initializeFromDill ?? getDefaultCachedKernelPath( trackWidgetCreation: buildInfo.trackWidgetCreation, diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index d062cc60640fc..36cf0c575f4f2 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -112,6 +112,7 @@ class FlutterCommandResult { /// Common flutter command line options. abstract final class FlutterOptions { + static const String kFrontendServerStarterPath = 'frontend-server-starter-path'; static const String kExtraFrontEndOptions = 'extra-front-end-options'; static const String kExtraGenSnapshotOptions = 'extra-gen-snapshot-options'; static const String kEnableExperiment = 'enable-experiment'; @@ -849,6 +850,18 @@ abstract class FlutterCommand extends Command<void> { ); } + void usesFrontendServerStarterPathOption({required bool verboseHelp}) { + argParser.addOption( + FlutterOptions.kFrontendServerStarterPath, + help: 'When this value is provided, the frontend server will be started ' + 'in JIT mode from the specified file, instead of from the AOT ' + 'snapshot shipped with the Dart SDK. The specified file can either ' + 'be a Dart source file, or an AppJIT snapshot. This option does ' + 'not affect web builds.', + hide: !verboseHelp, + ); + } + /// Enables support for the hidden options --extra-front-end-options and /// --extra-gen-snapshot-options. void usesExtraDartFlagOptions({ required bool verboseHelp }) { @@ -1239,6 +1252,10 @@ abstract class FlutterCommand extends Command<void> { ? stringArg('flavor') : null, trackWidgetCreation: trackWidgetCreation, + frontendServerStarterPath: argParser.options + .containsKey(FlutterOptions.kFrontendServerStarterPath) + ? stringArg(FlutterOptions.kFrontendServerStarterPath) + : null, extraFrontEndOptions: extraFrontEndOptions.isNotEmpty ? extraFrontEndOptions : null, diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 8f50eb9268b05..387795e521cd5 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -121,6 +121,7 @@ class TestCompiler { initializeFromDill: testFilePath, dartDefines: buildInfo.dartDefines, packagesPath: buildInfo.packagesPath, + frontendServerStarterPath: buildInfo.frontendServerStarterPath, extraFrontEndOptions: buildInfo.extraFrontEndOptions, platform: globals.platform, testCompilation: true, diff --git a/packages/flutter_tools/test/general.shard/build_info_test.dart b/packages/flutter_tools/test/general.shard/build_info_test.dart index 929ce64cd41c8..131a8530a81b8 100644 --- a/packages/flutter_tools/test/general.shard/build_info_test.dart +++ b/packages/flutter_tools/test/general.shard/build_info_test.dart @@ -175,6 +175,7 @@ void main() { dartDefines: <String>['foo=2', 'bar=2'], dartObfuscation: true, splitDebugInfoPath: 'foo/', + frontendServerStarterPath: 'foo/bar/frontend_server_starter.dart', extraFrontEndOptions: <String>['--enable-experiment=non-nullable', 'bar'], extraGenSnapshotOptions: <String>['--enable-experiment=non-nullable', 'fizz'], bundleSkSLPath: 'foo/bar/baz.sksl.json', @@ -190,6 +191,7 @@ void main() { 'BuildMode': 'debug', 'DartDefines': 'Zm9vPTI=,YmFyPTI=', 'DartObfuscation': 'true', + 'FrontendServerStarterPath': 'foo/bar/frontend_server_starter.dart', 'ExtraFrontEndOptions': '--enable-experiment=non-nullable,bar', 'ExtraGenSnapshotOptions': '--enable-experiment=non-nullable,fizz', 'SplitDebugInfo': 'foo/', @@ -211,6 +213,7 @@ void main() { dartDefines: <String>['foo=2', 'bar=2'], dartObfuscation: true, splitDebugInfoPath: 'foo/', + frontendServerStarterPath: 'foo/bar/frontend_server_starter.dart', extraFrontEndOptions: <String>['--enable-experiment=non-nullable', 'bar'], extraGenSnapshotOptions: <String>['--enable-experiment=non-nullable', 'fizz'], bundleSkSLPath: 'foo/bar/baz.sksl.json', @@ -226,6 +229,7 @@ void main() { 'DART_DEFINES': 'Zm9vPTI=,YmFyPTI=', 'DART_OBFUSCATION': 'true', 'SPLIT_DEBUG_INFO': 'foo/', + 'FRONTEND_SERVER_STARTER_PATH': 'foo/bar/frontend_server_starter.dart', 'EXTRA_FRONT_END_OPTIONS': '--enable-experiment=non-nullable,bar', 'EXTRA_GEN_SNAPSHOT_OPTIONS': '--enable-experiment=non-nullable,fizz', 'BUNDLE_SKSL_PATH': 'foo/bar/baz.sksl.json', @@ -242,6 +246,7 @@ void main() { dartDefineConfigJsonMap: <String, Object>{'baz': '2'}, dartObfuscation: true, splitDebugInfoPath: 'foo/', + frontendServerStarterPath: 'foo/bar/frontend_server_starter.dart', extraFrontEndOptions: <String>['--enable-experiment=non-nullable', 'bar'], extraGenSnapshotOptions: <String>['--enable-experiment=non-nullable', 'fizz'], bundleSkSLPath: 'foo/bar/baz.sksl.json', @@ -253,6 +258,7 @@ void main() { expect(buildInfo.toGradleConfig(), <String>[ '-Pdart-defines=Zm9vPTI=,YmFyPTI=', '-Pdart-obfuscation=true', + '-Pfrontend-server-starter-path=foo/bar/frontend_server_starter.dart', '-Pextra-front-end-options=--enable-experiment=non-nullable,bar', '-Pextra-gen-snapshot-options=--enable-experiment=non-nullable,fizz', '-Psplit-debug-info=foo/', diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 31d9d86ac2d2e..a287f1b0d0923 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -217,6 +217,53 @@ native-assets: {} expect(processManager, hasNoRemainingExpectations); }); + testWithoutContext('KernelSnapshot correctly forwards FrontendServerStarterPath', () async { + fileSystem.file('.dart_tool/package_config.json') + ..createSync(recursive: true) + ..writeAsStringSync('{"configVersion": 2, "packages":[]}'); + androidEnvironment.buildDir.childFile('native_assets.yaml') + ..createSync(recursive: true) + ..writeAsStringSync(emptyNativeAssets); + final String build = androidEnvironment.buildDir.path; + final String flutterPatchedSdkPath = artifacts.getArtifactPath( + Artifact.flutterPatchedSdkPath, + platform: TargetPlatform.android_arm, + mode: BuildMode.profile, + ); + processManager.addCommands(<FakeCommand>[ + FakeCommand(command: <String>[ + artifacts.getArtifactPath(Artifact.engineDartBinary), + '--disable-dart-dev', + 'path/to/frontend_server_starter.dart', + '--sdk-root', + '$flutterPatchedSdkPath/', + '--target=flutter', + '--no-print-incremental-dependencies', + ...buildModeOptions(BuildMode.profile, <String>[]), + '--track-widget-creation', + '--aot', + '--tfa', + '--target-os', + 'android', + '--packages', + '/.dart_tool/package_config.json', + '--output-dill', + '$build/app.dill', + '--depfile', + '$build/kernel_snapshot.d', + '--native-assets', + '$build/native_assets.yaml', + '--verbosity=error', + 'file:///lib/main.dart', + ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'), + ]); + + await const KernelSnapshot() + .build(androidEnvironment..defines[kFrontendServerStarterPath] = 'path/to/frontend_server_starter.dart'); + + expect(processManager, hasNoRemainingExpectations); + }); + testWithoutContext('KernelSnapshot correctly forwards ExtraFrontEndOptions', () async { fileSystem.file('.dart_tool/package_config.json') ..createSync(recursive: true) diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart index 8e47324eda371..a736b2b3b9a71 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/web_test.dart @@ -391,6 +391,38 @@ void main() { ProcessManager: () => processManager, })); + test('Dart2JSTarget ignores frontend server starter path option when calling dart2js', () => testbed.run(() async { + environment.defines[kBuildMode] = 'profile'; + environment.defines[kFrontendServerStarterPath] = 'path/to/frontend_server_starter.dart'; + processManager.addCommand(FakeCommand( + command: <String>[ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + '--no-source-maps', + '-o', + environment.buildDir.childFile('app.dill').absolute.path, + '--packages=.dart_tool/package_config.json', + '--cfe-only', + environment.buildDir.childFile('main.dart').absolute.path, + ] + )); + processManager.addCommand(FakeCommand( + command: <String>[ + ..._kDart2jsLinuxArgs, + '-Ddart.vm.profile=true', + '--no-minify', + '--no-source-maps', + '-O4', + '-o', + environment.buildDir.childFile('main.dart.js').absolute.path, + environment.buildDir.childFile('app.dill').absolute.path, + ] + )); + + await Dart2JSTarget(WebRendererMode.auto).build(environment); + }, overrides: <Type, Generator>{ + ProcessManager: () => processManager, + })); test('Dart2JSTarget calls dart2js with expected args with enabled experiment', () => testbed.run(() async { environment.defines[kBuildMode] = 'profile'; diff --git a/packages/flutter_tools/test/general.shard/bundle_builder_test.dart b/packages/flutter_tools/test/general.shard/bundle_builder_test.dart index 335354026fb27..fb854f24c71ef 100644 --- a/packages/flutter_tools/test/general.shard/bundle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/bundle_builder_test.dart @@ -87,6 +87,7 @@ void main() { BuildMode.debug, null, trackWidgetCreation: true, + frontendServerStarterPath: 'path/to/frontend_server_starter.dart', extraFrontEndOptions: <String>['test1', 'test2'], extraGenSnapshotOptions: <String>['test3', 'test4'], fileSystemRoots: <String>['test5', 'test6'], @@ -106,6 +107,7 @@ void main() { expect(env!.defines[kTargetPlatform], 'ios'); expect(env!.defines[kTargetFile], mainPath); expect(env!.defines[kTrackWidgetCreation], 'true'); + expect(env!.defines[kFrontendServerStarterPath], 'path/to/frontend_server_starter.dart'); expect(env!.defines[kExtraFrontEndOptions], 'test1,test2'); expect(env!.defines[kExtraGenSnapshotOptions], 'test3,test4'); expect(env!.defines[kFileSystemRoots], 'test5,test6'); diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 42b8dafb90d04..e24262fff8246 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -1963,6 +1963,28 @@ flutter: ProcessManager: () => FakeProcessManager.any(), }); + testUsingContext('FlutterDevice passes frontendServerStarterPath parameter if specified', () async { + fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]); + final FakeDevice device = FakeDevice(); + + final DefaultResidentCompiler? residentCompiler = (await FlutterDevice.create( + device, + buildInfo: const BuildInfo( + BuildMode.debug, + '', + treeShakeIcons: false, + frontendServerStarterPath: '/foo/bar/frontend_server_starter.dart', + ), + target: null, platform: FakePlatform(), + )).generator as DefaultResidentCompiler?; + + expect(residentCompiler!.frontendServerStarterPath, '/foo/bar/frontend_server_starter.dart'); + }, overrides: <Type, Generator>{ + Artifacts: () => Artifacts.test(), + FileSystem: () => MemoryFileSystem.test(), + ProcessManager: () => FakeProcessManager.any(), + }); + testUsingContext('Handle existing VM service clients DDS error', () => testbed.run(() async { fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[]); final FakeDevice device = FakeDevice() diff --git a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart index dd36810f897b5..5215644437607 100644 --- a/packages/flutter_tools/test/general.shard/xcode_backend_test.dart +++ b/packages/flutter_tools/test/general.shard/xcode_backend_test.dart @@ -51,6 +51,7 @@ void main() { '-dTrackWidgetCreation=', '-dDartObfuscation=', '-dAction=build', + '-dFrontendServerStarterPath=', '--ExtraGenSnapshotOptions=', '--DartDefines=', '--ExtraFrontEndOptions=', @@ -103,6 +104,7 @@ void main() { '-dTrackWidgetCreation=', '-dDartObfuscation=', '-dAction=', + '-dFrontendServerStarterPath=', '--ExtraGenSnapshotOptions=', '--DartDefines=', '--ExtraFrontEndOptions=', @@ -136,6 +138,7 @@ void main() { const String expandedCodeSignIdentity = 'F1326572E0B71C3C8442805230CB4B33B708A2E2'; const String extraFrontEndOptions = '--some-option'; const String extraGenSnapshotOptions = '--obfuscate'; + const String frontendServerStarterPath = '/path/to/frontend_server_starter.dart'; const String sdkRoot = '/path/to/sdk'; const String splitDebugInfo = '/path/to/split/debug/info'; const String trackWidgetCreation = 'true'; @@ -154,6 +157,7 @@ void main() { 'EXTRA_FRONT_END_OPTIONS': extraFrontEndOptions, 'EXTRA_GEN_SNAPSHOT_OPTIONS': extraGenSnapshotOptions, 'FLUTTER_ROOT': flutterRoot.path, + 'FRONTEND_SERVER_STARTER_PATH': frontendServerStarterPath, 'INFOPLIST_PATH': 'Info.plist', 'SDKROOT': sdkRoot, 'SPLIT_DEBUG_INFO': splitDebugInfo, @@ -177,6 +181,7 @@ void main() { '-dTrackWidgetCreation=$trackWidgetCreation', '-dDartObfuscation=$dartObfuscation', '-dAction=install', + '-dFrontendServerStarterPath=$frontendServerStarterPath', '--ExtraGenSnapshotOptions=$extraGenSnapshotOptions', '--DartDefines=$dartDefines', '--ExtraFrontEndOptions=$extraFrontEndOptions', From 30a9f99bc80bba85dc8f34a5a0dfb00c9ca654a7 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Thu, 21 Sep 2023 11:49:29 -0700 Subject: [PATCH 1398/1547] Send analytics on 'build ios' and 'build ipa' for plist impeller value (#135193) This analytics event only records the value of the plist entry on `build` commands. This will give an idea of the proportion of users who are disabling Impeller when shipping apps. --- .../lib/src/commands/build_ios.dart | 16 +++ .../lib/src/ios/plist_parser.dart | 1 + .../hermetic/build_ios_test.dart | 129 ++++++++++++++++++ .../hermetic/build_ipa_test.dart | 3 +- 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 211bf2f16c7c8..117414e89f85c 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -20,6 +20,7 @@ import '../globals.dart' as globals; import '../ios/application_package.dart'; import '../ios/mac.dart'; import '../ios/plist_parser.dart'; +import '../reporting/reporting.dart'; import '../runner/flutter_command.dart'; import 'build.dart'; @@ -724,6 +725,21 @@ abstract class _BuildIOSSubCommand extends BuildSubCommand { if (result.output != null) { globals.printStatus('Built ${result.output}.'); + // When an app is successfully built, record to analytics whether Impeller + // is enabled or disabled. + final BuildableIOSApp app = await buildableIOSApp; + final String plistPath = app.project.infoPlist.path; + final bool? impellerEnabled = globals.plistParser.getValueFromFile<bool>( + plistPath, PlistParser.kFLTEnableImpellerKey, + ); + BuildEvent( + impellerEnabled == false + ? 'plist-impeller-disabled' + : 'plist-impeller-enabled', + type: 'ios', + flutterUsage: globals.flutterUsage, + ).send(); + return FlutterCommandResult.success(); } diff --git a/packages/flutter_tools/lib/src/ios/plist_parser.dart b/packages/flutter_tools/lib/src/ios/plist_parser.dart index b736f7cd63678..a482957455294 100644 --- a/packages/flutter_tools/lib/src/ios/plist_parser.dart +++ b/packages/flutter_tools/lib/src/ios/plist_parser.dart @@ -31,6 +31,7 @@ class PlistParser { static const String kCFBundleVersionKey = 'CFBundleVersion'; static const String kCFBundleDisplayNameKey = 'CFBundleDisplayName'; static const String kCFBundleNameKey = 'CFBundleName'; + static const String kFLTEnableImpellerKey = 'FLTEnableImpeller'; static const String kMinimumOSVersionKey = 'MinimumOSVersion'; static const String kNSPrincipalClassKey = 'NSPrincipalClass'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index a36960457498b..8f0ae0d5b3257 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -17,7 +17,9 @@ import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build_ios.dart'; import 'package:flutter_tools/src/ios/code_signing.dart'; import 'package:flutter_tools/src/ios/mac.dart'; +import 'package:flutter_tools/src/ios/plist_parser.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart'; +import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:test/fake.dart'; @@ -438,6 +440,133 @@ void main() { Usage: () => usage, XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); + + group('Analytics for impeller plist setting', () { + const String plistContents = ''' +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>FLTEnableImpeller</key> + <false/> +</dict> +</plist> +'''; + const FakeCommand plutilCommand = FakeCommand( + command: <String>[ + '/usr/bin/plutil', '-convert', 'xml1', '-o', '-', '/ios/Runner/Info.plist', + ], + stdout: plistContents, + ); + + testUsingContext('Sends an analytics event when Impeller is enabled', () async { + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: MemoryFileSystem.test(), + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + createMinimalMockProjectFiles(); + + await createTestCommandRunner(command).run( + const <String>['build', 'ios', '--no-pub'] + ); + + expect(usage.events, contains( + const TestUsageEvent( + 'build', 'ios', + label:'plist-impeller-enabled', + parameters:CustomDimensions(), + ), + )); + }, overrides: <Type, Generator>{ + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ + xattrCommand, + setUpFakeXcodeBuildHandler(onRun: () { + fileSystem.directory('build/ios/Release-iphoneos/Runner.app') + .createSync(recursive: true); + }), + setUpRsyncCommand(onRun: () => + fileSystem.file('build/ios/iphoneos/Runner.app/Frameworks/App.framework/App') + ..createSync(recursive: true) + ..writeAsBytesSync(List<int>.generate(10000, (int index) => 0))), + ]), + Platform: () => macosPlatform, + FileSystemUtils: () => FileSystemUtils( + fileSystem: fileSystem, + platform: macosPlatform, + ), + Usage: () => usage, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + }); + + testUsingContext('Sends an analytics event when Impeller is disabled', () async { + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + fileSystem: fileSystem, + logger: BufferLogger.test(), + osUtils: FakeOperatingSystemUtils(), + ); + createMinimalMockProjectFiles(); + + fileSystem.file( + fileSystem.path.join('usr', 'bin', 'plutil'), + ).createSync(recursive: true); + + final File infoPlist = fileSystem.file(fileSystem.path.join( + 'ios', 'Runner', 'Info.plist', + ))..createSync(recursive: true); + + infoPlist.writeAsStringSync(plistContents); + + await createTestCommandRunner(command).run( + const <String>['build', 'ios', '--no-pub'] + ); + + expect(usage.events, contains( + const TestUsageEvent( + 'build', 'ios', + label:'plist-impeller-disabled', + parameters:CustomDimensions(), + ), + )); + }, overrides: <Type, Generator>{ + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.list(<FakeCommand>[ + xattrCommand, + setUpFakeXcodeBuildHandler(onRun: () { + fileSystem.directory('build/ios/Release-iphoneos/Runner.app') + .createSync(recursive: true); + }), + setUpRsyncCommand(onRun: () => + fileSystem.file('build/ios/iphoneos/Runner.app/Frameworks/App.framework/App') + ..createSync(recursive: true) + ..writeAsBytesSync(List<int>.generate(10000, (int index) => 0))), + ]), + Platform: () => macosPlatform, + FileSystemUtils: () => FileSystemUtils( + fileSystem: fileSystem, + platform: macosPlatform, + ), + Usage: () => usage, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + FlutterProjectFactory: () => FlutterProjectFactory( + fileSystem: fileSystem, + logger: BufferLogger.test(), + ), + PlistParser: () => PlistParser( + fileSystem: fileSystem, + logger: BufferLogger.test(), + processManager: FakeProcessManager.list(<FakeCommand>[ + plutilCommand, plutilCommand, plutilCommand, + ]), + ), + }); + }); + group('xcresults device', () { testUsingContext('Trace error if xcresult is empty.', () async { final BuildCommand command = BuildCommand( diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index 11f65819e1c06..e925821917847 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -63,7 +63,8 @@ class FakePlistUtils extends Fake implements PlistParser { @override T? getValueFromFile<T>(String plistFilePath, String key) { - return fileContents[plistFilePath]![key] as T?; + final Map<String, Object>? plistFile = fileContents[plistFilePath]; + return plistFile == null ? null : plistFile[key] as T?; } } From d0664bcd7903e98e54f84b08c6e00c4401a53ec1 Mon Sep 17 00:00:00 2001 From: Yegor <yjbanov@google.com> Date: Thu, 21 Sep 2023 12:38:20 -0700 Subject: [PATCH 1399/1547] a few web tweaks for a11y assessment app (#134479) Mostly tweaks for better focus management, namely: * Use `autofocus` throughout so the a11y focus is transferred to a logical place when overlaid content pops up (screen transitions, dialogs). * Consolidate "enabled" and "disabled" widgets into the same screen. Otherwise, when only a disabled widget is shown, there's nothing to focus on and the screen reader is lost. --- dev/a11y_assessments/lib/main.dart | 19 +++++++- .../lib/use_cases/check_box_list_tile.dart | 33 +++++++++---- .../check_box_list_tile_disabled.dart | 47 ------------------- .../lib/use_cases/date_picker.dart | 1 + .../lib/use_cases/dialog.dart | 2 + .../lib/use_cases/slider.dart | 1 + .../lib/use_cases/text_field.dart | 28 ++++++++--- .../lib/use_cases/text_field_disabled.dart | 44 ----------------- .../lib/use_cases/text_field_password.dart | 27 ++++++++--- .../lib/use_cases/use_cases.dart | 4 -- dev/a11y_assessments/pubspec.yaml | 2 +- .../test/text_field_disabled_test.dart | 23 --------- .../test/text_field_password_test.dart | 23 ++++++--- .../test/text_field_test.dart | 23 ++++++--- dev/a11y_assessments/web/manifest.json | 2 +- 15 files changed, 121 insertions(+), 158 deletions(-) delete mode 100644 dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart delete mode 100644 dev/a11y_assessments/lib/use_cases/text_field_disabled.dart delete mode 100644 dev/a11y_assessments/test/text_field_disabled_test.dart diff --git a/dev/a11y_assessments/lib/main.dart b/dev/a11y_assessments/lib/main.dart index 9bf39a96c8455..5b7a14d767a28 100644 --- a/dev/a11y_assessments/lib/main.dart +++ b/dev/a11y_assessments/lib/main.dart @@ -2,12 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'use_cases/use_cases.dart'; +// TODO(yjbanov): https://github.com/flutter/flutter/issues/83809 +// Currently this app (as most Flutter Web apps) relies on the +// `autofocus` property to guide the a11y focus when navigating +// across routes (screen transitions, dialogs, etc). We may want +// to revisit this after we figure out a long-term story for a11y +// focus. See also https://github.com/flutter/flutter/issues/97747 void main() { runApp(const App()); + if (kIsWeb) { + SemanticsBinding.instance.ensureSemantics(); + } } class App extends StatelessWidget { @@ -36,12 +47,13 @@ class App extends StatelessWidget { class HomePage extends StatelessWidget { const HomePage({super.key}); - Widget _buildUseCaseItem(UseCase useCase) { + Widget _buildUseCaseItem(int index, UseCase useCase) { return Padding( padding: const EdgeInsets.all(10), child: Builder( builder: (BuildContext context) { return TextButton( + autofocus: index == 0, key: Key(useCase.name), onPressed: () => Navigator.of(context).pushNamed(useCase.route), child: Text(useCase.name), @@ -57,7 +69,10 @@ class HomePage extends StatelessWidget { appBar: AppBar(title: const Text('Accessibility Assessments')), body: Center( child: ListView( - children: useCases.map<Widget>(_buildUseCaseItem).toList(), + children: List<Widget>.generate( + useCases.length, + (int index) => _buildUseCaseItem(index, useCases[index]), + ), ), ), ); diff --git a/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart b/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart index ecdf03427a5fa..b21f5d0c95f03 100644 --- a/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart +++ b/dev/a11y_assessments/lib/use_cases/check_box_list_tile.dart @@ -30,16 +30,29 @@ class _MainWidgetState extends State<_MainWidget> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('CheckBoxListTile')), - body: Center( - child: CheckboxListTile( - value: _checked, - onChanged: (bool? value) { - setState(() { - _checked = value!; - }); - }, - title: const Text('a check box list title'), - ), + body: ListView( + children: <Widget>[ + CheckboxListTile( + autofocus: true, + value: _checked, + onChanged: (bool? value) { + setState(() { + _checked = value!; + }); + }, + title: const Text('a check box list title'), + ), + CheckboxListTile( + value: _checked, + onChanged: (bool? value) { + setState(() { + _checked = value!; + }); + }, + title: const Text('a disabled check box list title'), + enabled: false, + ), + ], ), ); } diff --git a/dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart b/dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart deleted file mode 100644 index fe4d7e2be0f3a..0000000000000 --- a/dev/a11y_assessments/lib/use_cases/check_box_list_tile_disabled.dart +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -import 'use_cases.dart'; - -class CheckBoxListTileDisabled extends UseCase { - - @override - String get name => 'CheckBoxListTile Disabled'; - - @override - String get route => '/check-box-list-tile-disabled'; - - @override - Widget build(BuildContext context) => _MainWidget(); -} - -class _MainWidget extends StatefulWidget { - @override - State<_MainWidget> createState() => _MainWidgetState(); -} - -class _MainWidgetState extends State<_MainWidget> { - bool _checked = false; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('CheckBoxListTile Disabled')), - body: Center( - child: CheckboxListTile( - value: _checked, - onChanged: (bool? value) { - setState(() { - _checked = value!; - }); - }, - title: const Text('a disabled check box list title'), - enabled: false, - ), - ), - ); - } -} diff --git a/dev/a11y_assessments/lib/use_cases/date_picker.dart b/dev/a11y_assessments/lib/use_cases/date_picker.dart index 0a6b1e85563df..a7192abc475c4 100644 --- a/dev/a11y_assessments/lib/use_cases/date_picker.dart +++ b/dev/a11y_assessments/lib/use_cases/date_picker.dart @@ -36,6 +36,7 @@ class _MainWidgetState extends State<_MainWidget> { ), body: Center( child: TextButton( + autofocus: true, onPressed: () => showDatePicker( context: context, initialEntryMode: DatePickerEntryMode.calendarOnly, diff --git a/dev/a11y_assessments/lib/use_cases/dialog.dart b/dev/a11y_assessments/lib/use_cases/dialog.dart index 73ebddc5a97dd..e110259f5c633 100644 --- a/dev/a11y_assessments/lib/use_cases/dialog.dart +++ b/dev/a11y_assessments/lib/use_cases/dialog.dart @@ -29,6 +29,7 @@ class _MainWidget extends StatelessWidget { ), body: Center( child: TextButton( + autofocus: true, onPressed: () => showDialog<String>( context: context, builder: (BuildContext context) => Dialog( @@ -41,6 +42,7 @@ class _MainWidget extends StatelessWidget { const Text('This is a typical dialog.'), const SizedBox(height: 15), TextButton( + autofocus: true, onPressed: () { Navigator.pop(context); }, diff --git a/dev/a11y_assessments/lib/use_cases/slider.dart b/dev/a11y_assessments/lib/use_cases/slider.dart index a83261dbea3c5..8dbd398bf4e3b 100644 --- a/dev/a11y_assessments/lib/use_cases/slider.dart +++ b/dev/a11y_assessments/lib/use_cases/slider.dart @@ -37,6 +37,7 @@ class MainWidgetState extends State<MainWidget> { ), body: Center( child: Slider( + autofocus: true, value: currentSliderValue, max: 100, divisions: 5, diff --git a/dev/a11y_assessments/lib/use_cases/text_field.dart b/dev/a11y_assessments/lib/use_cases/text_field.dart index 3dd7e6eb16d8e..0038cb52f25cc 100644 --- a/dev/a11y_assessments/lib/use_cases/text_field.dart +++ b/dev/a11y_assessments/lib/use_cases/text_field.dart @@ -28,14 +28,28 @@ class _MainWidget extends StatelessWidget { backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('TextField'), ), - body: const Center( - child: TextField( - decoration: InputDecoration( - labelText: 'Email', - suffixText: '@gmail.com', - hintText: 'Enter your email', + body: ListView( + children: <Widget>[ + const TextField( + key: Key('enabled text field'), + autofocus: true, + decoration: InputDecoration( + labelText: 'Email', + suffixText: '@gmail.com', + hintText: 'Enter your email', + ), ), - ) + TextField( + key: const Key('disabled text field'), + decoration: const InputDecoration( + labelText: 'Email', + suffixText: '@gmail.com', + hintText: 'Enter your email', + ), + enabled: false, + controller: TextEditingController(text: 'xyz'), + ), + ], ), ); } diff --git a/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart b/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart deleted file mode 100644 index dcd20818001b3..0000000000000 --- a/dev/a11y_assessments/lib/use_cases/text_field_disabled.dart +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/material.dart'; - -import 'use_cases.dart'; - -class TextFieldDisabledUseCase extends UseCase { - - @override - String get name => 'TextField disabled'; - - @override - String get route => '/text-field-disabled'; - - @override - Widget build(BuildContext context) => const _MainWidget(); -} - -class _MainWidget extends StatelessWidget { - const _MainWidget(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: const Text('TextField disabled'), - ), - body: Center( - child: TextField( - decoration: const InputDecoration( - labelText: 'Email', - suffixText: '@gmail.com', - hintText: 'Enter your email', - enabled: false, - ), - controller: TextEditingController(text: 'abc'), - ) - ), - ); - } -} diff --git a/dev/a11y_assessments/lib/use_cases/text_field_password.dart b/dev/a11y_assessments/lib/use_cases/text_field_password.dart index 5da9337cb6dfb..3c6152dd34885 100644 --- a/dev/a11y_assessments/lib/use_cases/text_field_password.dart +++ b/dev/a11y_assessments/lib/use_cases/text_field_password.dart @@ -28,14 +28,27 @@ class _MainWidget extends StatelessWidget { backgroundColor: Theme.of(context).colorScheme.inversePrimary, title: const Text('TextField password'), ), - body: const Center( - child: TextField( - decoration: InputDecoration( - labelText: 'Password', - hintText: 'Enter your password', + body: ListView( + children: const <Widget>[ + TextField( + key: Key('enabled password'), + autofocus: true, + decoration: InputDecoration( + labelText: 'Password', + hintText: 'Enter your password', + ), + obscureText: true, ), - obscureText: true, - ) + TextField( + key: Key('disabled password'), + decoration: InputDecoration( + labelText: 'Password', + hintText: 'Enter your password', + ), + enabled: false, + obscureText: true, + ), + ], ), ); } diff --git a/dev/a11y_assessments/lib/use_cases/use_cases.dart b/dev/a11y_assessments/lib/use_cases/use_cases.dart index 6099b87bc4931..056f9e2b11a4b 100644 --- a/dev/a11y_assessments/lib/use_cases/use_cases.dart +++ b/dev/a11y_assessments/lib/use_cases/use_cases.dart @@ -5,12 +5,10 @@ import 'package:flutter/widgets.dart'; import 'check_box_list_tile.dart'; -import 'check_box_list_tile_disabled.dart'; import 'date_picker.dart'; import 'dialog.dart'; import 'slider.dart'; import 'text_field.dart'; -import 'text_field_disabled.dart'; import 'text_field_password.dart'; abstract class UseCase { @@ -21,11 +19,9 @@ abstract class UseCase { final List<UseCase> useCases = <UseCase>[ CheckBoxListTile(), - CheckBoxListTileDisabled(), DialogUseCase(), SliderUseCase(), TextFieldUseCase(), - TextFieldDisabledUseCase(), TextFieldPasswordUseCase(), DatePickerUseCase(), ]; diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml index f87fd7b36e892..6d71cbeb20859 100644 --- a/dev/a11y_assessments/pubspec.yaml +++ b/dev/a11y_assessments/pubspec.yaml @@ -1,5 +1,5 @@ name: a11y_assessments -description: "A new Flutter project." +description: A new Flutter project environment: sdk: '>=3.2.0-22.0.dev <4.0.0' diff --git a/dev/a11y_assessments/test/text_field_disabled_test.dart b/dev/a11y_assessments/test/text_field_disabled_test.dart deleted file mode 100644 index 0a304b9ef5fec..0000000000000 --- a/dev/a11y_assessments/test/text_field_disabled_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:a11y_assessments/use_cases/text_field_disabled.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'test_utils.dart'; - -void main() { - testWidgets('text field disabled can run', (WidgetTester tester) async { - await pumpsUseCase(tester, TextFieldDisabledUseCase()); - expect(find.byType(TextField), findsOneWidget); - expect(find.text('abc'), findsOneWidget); - - await tester.tap(find.byType(TextField)); - await tester.pumpAndSettle(); - await tester.enterText(find.byType(TextField), 'bde'); - await tester.pumpAndSettle(); - expect(find.text('abc'), findsOneWidget); - }); -} diff --git a/dev/a11y_assessments/test/text_field_password_test.dart b/dev/a11y_assessments/test/text_field_password_test.dart index 44a65a4e0023f..90e4fd6a6a078 100644 --- a/dev/a11y_assessments/test/text_field_password_test.dart +++ b/dev/a11y_assessments/test/text_field_password_test.dart @@ -11,12 +11,23 @@ import 'test_utils.dart'; void main() { testWidgets('text field password can run', (WidgetTester tester) async { await pumpsUseCase(tester, TextFieldPasswordUseCase()); - expect(find.byType(TextField), findsOneWidget); + expect(find.byType(TextField), findsExactly(2)); - await tester.tap(find.byType(TextField)); - await tester.pumpAndSettle(); - await tester.enterText(find.byType(TextField), 'abc'); - await tester.pumpAndSettle(); - expect(find.text('abc'), findsOneWidget); + // Test the enabled password + { + final Finder finder = find.byKey(const Key('enabled password')); + await tester.tap(finder); + await tester.pumpAndSettle(); + await tester.enterText(finder, 'abc'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + } + + // Test the disabled password + { + final Finder finder = find.byKey(const Key('disabled password')); + final TextField passwordField = tester.widget<TextField>(finder); + expect(passwordField.enabled, isFalse); + } }); } diff --git a/dev/a11y_assessments/test/text_field_test.dart b/dev/a11y_assessments/test/text_field_test.dart index 7623876edd6d5..0b2ea4ad7a8c2 100644 --- a/dev/a11y_assessments/test/text_field_test.dart +++ b/dev/a11y_assessments/test/text_field_test.dart @@ -11,12 +11,23 @@ import 'test_utils.dart'; void main() { testWidgets('text field can run', (WidgetTester tester) async { await pumpsUseCase(tester, TextFieldUseCase()); - expect(find.byType(TextField), findsOneWidget); + expect(find.byType(TextField), findsExactly(2)); - await tester.tap(find.byType(TextField)); - await tester.pumpAndSettle(); - await tester.enterText(find.byType(TextField), 'abc'); - await tester.pumpAndSettle(); - expect(find.text('abc'), findsOneWidget); + // Test the enabled text field + { + final Finder finder = find.byKey(const Key('enabled text field')); + await tester.tap(finder); + await tester.pumpAndSettle(); + await tester.enterText(finder, 'abc'); + await tester.pumpAndSettle(); + expect(find.text('abc'), findsOneWidget); + } + + // Test the disabled text field + { + final Finder finder = find.byKey(const Key('disabled text field')); + final TextField textField = tester.widget<TextField>(finder); + expect(textField.enabled, isFalse); + } }); } diff --git a/dev/a11y_assessments/web/manifest.json b/dev/a11y_assessments/web/manifest.json index 9a2a11fa46b37..b2bfc8ba99bf1 100644 --- a/dev/a11y_assessments/web/manifest.json +++ b/dev/a11y_assessments/web/manifest.json @@ -5,7 +5,7 @@ "display": "standalone", "background_color": "#0175C2", "theme_color": "#0175C2", - "description": ""A new Flutter project."", + "description": "A new Flutter project.", "orientation": "portrait-primary", "prefer_related_applications": false, "icons": [ From 45e4a0e5250c8ed21aa2d13fc2ce668aba11f186 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Thu, 21 Sep 2023 12:41:58 -0700 Subject: [PATCH 1400/1547] Fix a TextSpan test (#135187) `TextSpan.toStringDeep()` returns a string that contains a lengthy diagnostic message instead of the plain string. --- packages/flutter/test/rendering/paragraph_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/flutter/test/rendering/paragraph_test.dart b/packages/flutter/test/rendering/paragraph_test.dart index f7d8eba8c2e4b..a85d83ae39489 100644 --- a/packages/flutter/test/rendering/paragraph_test.dart +++ b/packages/flutter/test/rendering/paragraph_test.dart @@ -436,15 +436,15 @@ void main() { expect(paragraph.size.width, 78.0); expect(paragraph.size.height, 26.0); + final int length = testSpan.toPlainText().length; // Test the sizes of nested spans. - final String text = testSpan.toStringDeep(); final List<ui.TextBox> boxes = <ui.TextBox>[ - for (int i = 0; i < text.length; ++i) + for (int i = 0; i < length; ++i) ...paragraph.getBoxesForSelection( TextSelection(baseOffset: i, extentOffset: i + 1), ), ]; - expect(boxes.length, equals(4)); + expect(boxes, hasLength(4)); expect(boxes[0].toRect().width, 13.0); expect(boxes[0].toRect().height, 13.0); From 528a281a5c89c9bb91e6c6d1f90ebc1376a3809b Mon Sep 17 00:00:00 2001 From: hangyu <jhy03261997@gmail.com> Date: Thu, 21 Sep 2023 14:53:22 -0700 Subject: [PATCH 1401/1547] Update alwaysNeedsCompositing in RenderParagraph (#135076) fix #111370 According to https://github.com/flutter/flutter/blob/5b47fef613e2d74ae44e1e22c2a3495294db180e/packages/flutter/lib/src/rendering/box.dart#L1259 : A [RenderBox] that uses methods on [PaintingContext] that introduce new /// layers should override the [alwaysNeedsCompositing] getter and set it to /// true. set [alwaysNeedsCompositing] to true when RenderParagraph introduces LeaderLayer for selection handles. ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../flutter/lib/src/rendering/paragraph.dart | 6 ++ .../test/material/selection_area_test.dart | 57 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index acdfed2543af8..13b17af303388 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -388,6 +388,9 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo } _lastSelectableFragments ??= _getSelectableFragments(); _lastSelectableFragments!.forEach(_registrar!.add); + if (_lastSelectableFragments!.isNotEmpty) { + markNeedsCompositingBitsUpdate(); + } } void _removeSelectionRegistrarSubscription() { @@ -425,6 +428,9 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo _lastSelectableFragments = null; } + @override + bool get alwaysNeedsCompositing => _lastSelectableFragments?.isNotEmpty ?? false; + @override void markNeedsLayout() { _lastSelectableFragments?.forEach((_SelectableFragment element) => element.didChangeParagraphLayout()); diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index 8e786831dc026..1a61612b6492d 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -70,6 +70,63 @@ void main() { expect(tester.takeException(), isNull); }); + // Regression test for https://github.com/flutter/flutter/issues/111370 + testWidgetsWithLeakTracking('Handle is correctly transformed when the text is inside of a FittedBox ',(WidgetTester tester) async { + final Key textKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + color: const Color(0xFF2196F3), + home: Scaffold( + body: SelectionArea( + child: SizedBox( + height: 100, + child: FittedBox( + fit: BoxFit.fill, + child: Text('test', key: textKey), + ), + ), + ), + ), + ), + ); + + final TestGesture longpress = await tester.startGesture(const Offset(10, 10)); + addTearDown(longpress.removePointer); + await tester.pump(const Duration(milliseconds: 500)); + await longpress.up(); + + // Text box is scaled by 5. + final RenderBox textBox = tester.firstRenderObject(find.byKey(textKey)); + expect(textBox.size.height, 20.0); + final Offset textPoint = textBox.localToGlobal(const Offset(0, 20)); + expect(textPoint, equals(const Offset(0, 100))); + + // Find handles and verify their sizes. + expect(find.byType(Overlay), findsOneWidget); + expect(find.descendant(of: find.byType(Overlay),matching: find.byType(CustomPaint),),findsNWidgets(2)); + final Iterable<RenderBox> handles = tester.renderObjectList(find.descendant( + of: find.byType(Overlay), + matching: find.byType(CustomPaint), + )); + + // The handle height is determined by the formula: + // textLineHeight + _kSelectionHandleRadius * 2 - _kSelectionHandleOverlap . + // The text line height will be the value of the fontSize. + // The constant _kSelectionHandleRadius has the value of 6. + // The constant _kSelectionHandleOverlap has the value of 1.5. + // The handle height before scaling is 20.0 + 6 * 2 - 1.5 = 30.5. + + final double handleHeightBeforeScaling = handles.first.size.height; + expect(handleHeightBeforeScaling, 30.5); + + final Offset handleHeightAfterScaling = handles.first.localToGlobal(const Offset(0, 30.5)) - handles.first.localToGlobal(Offset.zero); + + // The handle height after scaling is 30.5 * 5 = 152.5 + expect(handleHeightAfterScaling, equals(const Offset(0.0, 152.5))); + }, + skip: isBrowser, // [intended] + variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.iOS}), + ); testWidgetsWithLeakTracking('builds the default context menu by default', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); From daea6e00bfc0452cbd3b1c46f3dd2d41a05da0a7 Mon Sep 17 00:00:00 2001 From: Jacob MacDonald <jakemac@google.com> Date: Thu, 21 Sep 2023 15:02:12 -0700 Subject: [PATCH 1402/1547] remove field override, assign to super field instead (#135165) Removes an ignore about overriding fields. Instead we just assign the value to the original field in the super class. Related to https://github.com/dart-lang/language/issues/3332 (discovered during investigations into the violation of that lint). --- .../test/commands.shard/hermetic/run_test.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index ca7564e59e9b6..2a5a644a85c07 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -1335,13 +1335,10 @@ class FakeIOSDevice extends Fake implements IOSDevice { class TestRunCommandForUsageValues extends RunCommand { TestRunCommandForUsageValues({ - this.devices, - }); - - @override - // devices is not set within usageValues, so we override the field - // ignore: overridden_fields - List<Device>? devices; + List<Device>? devices, + }) { + this.devices = devices; + } @override Future<BuildInfo> getBuildInfo({ BuildMode? forcedBuildMode, File? forcedTargetFile }) async { From ffecedbca49076119ed8071c88a6bd4c07c79b86 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Fri, 22 Sep 2023 01:30:32 +0200 Subject: [PATCH 1403/1547] Cover more test/widgets tests with leak tracking #11 (#135231) --- .../test/cupertino/action_sheet_test.dart | 2 +- .../test/widgets/text_semantics_test.dart | 3 +- packages/flutter/test/widgets/text_test.dart | 90 +++++------ .../flutter/test/widgets/texture_test.dart | 13 +- .../test/widgets/ticker_mode_test.dart | 13 +- .../test/widgets/ticker_provider_test.dart | 17 ++- packages/flutter/test/widgets/title_test.dart | 9 +- .../tracking_scroll_controller_test.dart | 4 +- .../widgets/transformed_scrollable_test.dart | 17 ++- .../test/widgets/transitions_test.dart | 51 ++++--- .../flutter/test/widgets/tree_shape_test.dart | 57 +++---- .../widgets/tween_animation_builder_test.dart | 29 ++-- .../two_dimensional_scroll_view_test.dart | 56 +++++-- .../two_dimensional_viewport_test.dart | 141 +++++++++++++----- .../test/widgets/undo_history_test.dart | 41 +++-- .../test/widgets/unique_widget_test.dart | 3 +- .../value_listenable_builder_test.dart | 28 ++-- packages/flutter/test/widgets/view_test.dart | 31 ++-- .../flutter/test/widgets/visibility_test.dart | 11 +- packages/flutter/test/widgets/wrap_test.dart | 41 ++--- 20 files changed, 410 insertions(+), 247 deletions(-) diff --git a/packages/flutter/test/cupertino/action_sheet_test.dart b/packages/flutter/test/cupertino/action_sheet_test.dart index f5f3dde5892de..0dffe2d74bc0d 100644 --- a/packages/flutter/test/cupertino/action_sheet_test.dart +++ b/packages/flutter/test/cupertino/action_sheet_test.dart @@ -31,7 +31,7 @@ void main() { await tester.tapAt(const Offset(20.0, 20.0)); await tester.pump(); expect(find.text('Action Sheet'), findsNothing); - }, leakTrackingTestConfig: LeakTrackingTestConfig.debugNotDisposed()); + }); testWidgetsWithLeakTracking('Verify that a tap on title section (not buttons) does not dismiss an action sheet', (WidgetTester tester) async { await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/text_semantics_test.dart b/packages/flutter/test/widgets/text_semantics_test.dart index 190d2630d1725..9bc76eeea8335 100644 --- a/packages/flutter/test/widgets/text_semantics_test.dart +++ b/packages/flutter/test/widgets/text_semantics_test.dart @@ -6,11 +6,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('SemanticsNode ids are stable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SemanticsNode ids are stable', (WidgetTester tester) async { // Regression test for b/151732341. final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index fa09e584c5e25..c29ebdc7341fe 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -9,11 +9,12 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; void main() { - testWidgets('Text respects media query', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text respects media query', (WidgetTester tester) async { await tester.pumpWidget(const MediaQuery( data: MediaQueryData(textScaleFactor: 1.3), child: Center( @@ -34,7 +35,7 @@ void main() { expect(text.textScaler, TextScaler.noScaling); }); - testWidgets('Text respects textScaleFactor with default font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text respects textScaleFactor with default font size', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Text('Hello', textDirection: TextDirection.ltr)), ); @@ -62,7 +63,7 @@ void main() { expect(largeSize.height, equals(21.0)); }); - testWidgets('Text respects textScaleFactor with explicit font size', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text respects textScaleFactor with explicit font size', (WidgetTester tester) async { await tester.pumpWidget(const Center( child: Text( 'Hello', @@ -102,7 +103,7 @@ void main() { expect(message, contains(' Text ')); }); - testWidgets('Text can be created from TextSpans and uses defaultTextStyle', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text can be created from TextSpans and uses defaultTextStyle', (WidgetTester tester) async { await tester.pumpWidget( const DefaultTextStyle( style: TextStyle( @@ -132,7 +133,7 @@ void main() { expect(text.text.style!.fontSize, 20.0); }); - testWidgets('inline widgets works with ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets works with ellipsis', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/35869 const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -165,7 +166,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('inline widgets hitTest works with ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets hitTest works with ellipsis', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/68559 const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -201,7 +202,7 @@ void main() { expect(tester.takeException(), null); }); - testWidgets('inline widgets works with textScaleFactor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets works with textScaleFactor', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59316 final UniqueKey key = UniqueKey(); double textScaleFactor = 1.0; @@ -265,7 +266,7 @@ void main() { expect(renderText.size.height, singleLineHeight * textScaleFactor * 3); }); - testWidgets("Inline widgets' scaled sizes are constrained", (WidgetTester tester) async { + testWidgetsWithLeakTracking("Inline widgets' scaled sizes are constrained", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/130588 await tester.pumpWidget( const Directionality( @@ -282,7 +283,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('semanticsLabel can override text label', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semanticsLabel can override text label', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( const Text( @@ -328,7 +329,7 @@ void main() { semantics.dispose(); }); - testWidgets('semantics label is in order when uses widget span', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics label is in order when uses widget span', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -363,7 +364,7 @@ void main() { ); }); - testWidgets('semantics can handle some widget spans without semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics can handle some widget spans without semantics', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -405,7 +406,7 @@ void main() { matchesSemantics(label: 'before \n mid\nfoo\n after')); }); - testWidgets('semantics can handle all widget spans without semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics can handle all widget spans without semantics', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -447,7 +448,7 @@ void main() { matchesSemantics(label: 'before \n mid\n after')); }); - testWidgets('semantics can handle widget spans with explicit semantics node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantics can handle widget spans with explicit semantics node', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -482,7 +483,7 @@ void main() { ); }); - testWidgets('semanticsLabel can be shorter than text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semanticsLabel can be shorter than text', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -530,7 +531,7 @@ void main() { semantics.dispose(); }); - testWidgets('recognizers split semantic node', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic node', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -584,13 +585,14 @@ void main() { semantics.dispose(); }); - testWidgets('semantic nodes of offscreen recognizers are marked hidden', (WidgetTester tester) async { + testWidgetsWithLeakTracking('semantic nodes of offscreen recognizers are marked hidden', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/100395. final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(fontSize: 200); const String onScreenText = 'onscreen\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'; const String offScreenText = 'off screen'; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget( SingleChildScrollView( controller: controller, @@ -653,7 +655,7 @@ void main() { semantics.dispose(); }); - testWidgets('recognizers split semantic node when TextSpan overflows', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic node when TextSpan overflows', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -704,7 +706,7 @@ void main() { semantics.dispose(); }); - testWidgets('recognizers split semantic nodes with text span labels', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic nodes with text span labels', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -762,7 +764,7 @@ void main() { }); - testWidgets('recognizers split semantic node - bidi', (WidgetTester tester) async { + testWidgetsWithLeakTracking('recognizers split semantic node - bidi', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -843,7 +845,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/62945 - testWidgets('TapGesture recognizers contribute link semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TapGesture recognizers contribute link semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -883,7 +885,7 @@ void main() { semantics.dispose(); }); - testWidgets('inline widgets generate semantic nodes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets generate semantic nodes', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -957,7 +959,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/62945 - testWidgets('inline widgets semantic nodes scale', (WidgetTester tester) async { + testWidgetsWithLeakTracking('inline widgets semantic nodes scale', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); const TextStyle textStyle = TextStyle(); await tester.pumpWidget( @@ -1037,7 +1039,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/62945 - testWidgets('receives fontFamilyFallback and package from root ThemeData', (WidgetTester tester) async { + testWidgetsWithLeakTracking('receives fontFamilyFallback and package from root ThemeData', (WidgetTester tester) async { const String fontFamily = 'fontFamily'; const String package = 'package_name'; final List<String> fontFamilyFallback = <String>['font', 'family', 'fallback']; @@ -1070,7 +1072,7 @@ void main() { } }); - testWidgets('Overflow is clipping correctly - short text with overflow: clip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: clip', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.clip, @@ -1080,7 +1082,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - long text with overflow: ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - long text with overflow: ellipsis', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.ellipsis, @@ -1093,7 +1095,7 @@ void main() { ); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87878 - testWidgets('Overflow is clipping correctly - short text with overflow: ellipsis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: ellipsis', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.ellipsis, @@ -1103,7 +1105,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - long text with overflow: fade', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - long text with overflow: fade', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.fade, @@ -1116,7 +1118,7 @@ void main() { ); }); - testWidgets('Overflow is clipping correctly - short text with overflow: fade', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: fade', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.fade, @@ -1126,7 +1128,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - long text with overflow: visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - long text with overflow: visible', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.visible, @@ -1136,7 +1138,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('Overflow is clipping correctly - short text with overflow: visible', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Overflow is clipping correctly - short text with overflow: visible', (WidgetTester tester) async { await _pumpTextWidget( tester: tester, overflow: TextOverflow.visible, @@ -1146,7 +1148,7 @@ void main() { expect(find.byType(Text), isNot(paints..clipRect())); }); - testWidgets('textWidthBasis affects the width of a Text widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textWidthBasis affects the width of a Text widget', (WidgetTester tester) async { Future<void> createText(TextWidthBasis textWidthBasis) { return tester.pumpWidget( MaterialApp( @@ -1183,7 +1185,7 @@ void main() { expect(textSizeLongestLine.height, equals(fontHeight * 2)); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44020 - testWidgets('textWidthBasis with textAlign still obeys parent alignment', (WidgetTester tester) async { + testWidgetsWithLeakTracking('textWidthBasis with textAlign still obeys parent alignment', (WidgetTester tester) async { await tester.pumpWidget( const MaterialApp( home: Scaffold( @@ -1233,7 +1235,7 @@ void main() { expect(tester.getSize(find.text('RIGHT ALIGNED, LONGEST LINE')).width, equals(width)); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/44020 - testWidgets( + testWidgetsWithLeakTracking( 'textWidthBasis.longestLine confines the width of the paragraph ' 'when given loose constraints', (WidgetTester tester) async { @@ -1273,7 +1275,7 @@ void main() { skip: isBrowser, // https://github.com/flutter/flutter/issues/44020 ); - testWidgets('Paragraph.getBoxesForRange returns nothing when selection range is zero length', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Paragraph.getBoxesForRange returns nothing when selection range is zero length', (WidgetTester tester) async { final ui.ParagraphBuilder builder = ui.ParagraphBuilder(ui.ParagraphStyle()); builder.addText('hello'); final ui.Paragraph paragraph = builder.build(); @@ -1283,7 +1285,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/65818 - testWidgets('WidgetSpans with no semantic information are elided from semantics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); // Without the fix for this bug the pump widget will throw a RangeError. await tester.pumpWidget( @@ -1331,7 +1333,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 // Regression test for https://github.com/flutter/flutter/issues/69787 - testWidgets('WidgetSpans with no semantic information are elided from semantics - case 2', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics - case 2', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -1382,7 +1384,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 // Regression test for https://github.com/flutter/flutter/issues/69787 - testWidgets('WidgetSpans with no semantic information are elided from semantics - case 3', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics - case 3', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -1445,7 +1447,7 @@ void main() { }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 // Regression test for https://github.com/flutter/flutter/issues/69787 - testWidgets('WidgetSpans with no semantic information are elided from semantics - case 4', (WidgetTester tester) async { + testWidgetsWithLeakTracking('WidgetSpans with no semantic information are elided from semantics - case 4', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); await tester.pumpWidget( Directionality( @@ -1515,7 +1517,7 @@ void main() { semantics.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/87877 - testWidgets('RenderParagraph intrinsic width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderParagraph intrinsic width', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -1556,7 +1558,7 @@ void main() { expect(paragraph.getMinIntrinsicWidth(0.0), 200); }); - testWidgets('can compute intrinsic width and height for widget span with text scaling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('can compute intrinsic width and height for widget span with text scaling', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/59316 const Key textKey = Key('RichText'); Widget textWithNestedInlineSpans({ required double textScaleFactor, required double screenWidth }) { @@ -1609,7 +1611,7 @@ void main() { ); }); - testWidgets('Text uses TextStyle.overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Text uses TextStyle.overflow', (WidgetTester tester) async { const TextOverflow overflow = TextOverflow.fade; await tester.pumpWidget(const Text( @@ -1624,7 +1626,7 @@ void main() { expect(richText.text.style!.overflow, overflow); }); - testWidgets( + testWidgetsWithLeakTracking( 'Text can be hit-tested without layout or paint being called in a frame', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/85108. @@ -1660,7 +1662,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Mouse hovering over selectable Text uses SystemMouseCursor.text', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse hovering over selectable Text uses SystemMouseCursor.text', (WidgetTester tester) async { await tester.pumpWidget(const MaterialApp( home: SelectionArea( child: Text('Flutter'), @@ -1675,7 +1677,7 @@ void main() { expect(RendererBinding.instance.mouseTracker.debugDeviceActiveCursor(1), SystemMouseCursors.text); }); - testWidgets('Mouse hovering over selectable Text uses default selection style mouse cursor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Mouse hovering over selectable Text uses default selection style mouse cursor', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: SelectionArea( child: DefaultSelectionStyle.merge( diff --git a/packages/flutter/test/widgets/texture_test.dart b/packages/flutter/test/widgets/texture_test.dart index 4a5b1b774aa42..e0bf2dc09e930 100644 --- a/packages/flutter/test/widgets/texture_test.dart +++ b/packages/flutter/test/widgets/texture_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Texture with freeze set to true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with freeze set to true', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1, freeze: true)), ); @@ -25,6 +26,7 @@ void main() { expect(textureBox.freeze, true); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; @@ -35,7 +37,7 @@ void main() { expect(textureLayer.freeze, true); }); - testWidgets('Texture with default FilterQuality', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with default FilterQuality', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1)), ); @@ -53,6 +55,7 @@ void main() { expect(textureBox.filterQuality, FilterQuality.low); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; @@ -64,7 +67,7 @@ void main() { }); - testWidgets('Texture with FilterQuality.none', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with FilterQuality.none', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1, filterQuality: FilterQuality.none)), ); @@ -82,6 +85,7 @@ void main() { expect(textureBox.filterQuality, FilterQuality.none); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; @@ -92,7 +96,7 @@ void main() { expect(textureLayer.filterQuality, FilterQuality.none); }); - testWidgets('Texture with FilterQuality.low', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Texture with FilterQuality.low', (WidgetTester tester) async { await tester.pumpWidget( const Center(child: Texture(textureId: 1)), ); @@ -110,6 +114,7 @@ void main() { expect(textureBox.filterQuality, FilterQuality.low); final ContainerLayer containerLayer = ContainerLayer(); + addTearDown(containerLayer.dispose); final PaintingContext paintingContext = PaintingContext(containerLayer, Rect.zero); textureBox.paint(paintingContext, Offset.zero); final Layer layer = containerLayer.lastChild!; diff --git a/packages/flutter/test/widgets/ticker_mode_test.dart b/packages/flutter/test/widgets/ticker_mode_test.dart index aa09b8c9c2e6c..75ac25e8db430 100644 --- a/packages/flutter/test/widgets/ticker_mode_test.dart +++ b/packages/flutter/test/widgets/ticker_mode_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Nested TickerMode cannot turn tickers back on', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Nested TickerMode cannot turn tickers back on', (WidgetTester tester) async { int outerTickCount = 0; int innerTickCount = 0; @@ -99,7 +100,7 @@ void main() { expect(innerTickCount, 0); }); - testWidgets('Changing TickerMode does not rebuild widgets with SingleTickerProviderStateMixin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing TickerMode does not rebuild widgets with SingleTickerProviderStateMixin', (WidgetTester tester) async { Widget widgetUnderTest({required bool tickerEnabled}) { return TickerMode( enabled: tickerEnabled, @@ -121,7 +122,7 @@ void main() { expect(state().buildCount, 1); }); - testWidgets('Changing TickerMode does not rebuild widgets with TickerProviderStateMixin', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing TickerMode does not rebuild widgets with TickerProviderStateMixin', (WidgetTester tester) async { Widget widgetUnderTest({required bool tickerEnabled}) { return TickerMode( enabled: tickerEnabled, @@ -143,7 +144,7 @@ void main() { expect(state().buildCount, 1); }); - testWidgets('Moving widgets with SingleTickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving widgets with SingleTickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { final GlobalKey tickingWidgetKey = GlobalKey(); Widget widgetUnderTest({required LocalKey tickerModeKey, required bool tickerEnabled}) { return TickerMode( @@ -164,7 +165,7 @@ void main() { expect(tickingState.ticker.isTicking, isFalse); }); - testWidgets('Moving widgets with TickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving widgets with TickerProviderStateMixin to a new TickerMode ancestor works', (WidgetTester tester) async { final GlobalKey tickingWidgetKey = GlobalKey(); Widget widgetUnderTest({required LocalKey tickerModeKey, required bool tickerEnabled}) { return TickerMode( @@ -185,7 +186,7 @@ void main() { expect(tickingState.ticker.isTicking, isFalse); }); - testWidgets('Ticking widgets in old route do not rebuild when new route is pushed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Ticking widgets in old route do not rebuild when new route is pushed', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( routes: <String, WidgetBuilder>{ '/foo' : (BuildContext context) => const Text('New route'), diff --git a/packages/flutter/test/widgets/ticker_provider_test.dart b/packages/flutter/test/widgets/ticker_provider_test.dart index 2f342dae0bab4..1c65f075d7ef2 100644 --- a/packages/flutter/test/widgets/ticker_provider_test.dart +++ b/packages/flutter/test/widgets/ticker_provider_test.dart @@ -6,9 +6,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('TickerMode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TickerMode', (WidgetTester tester) async { const Widget widget = TickerMode( enabled: false, child: CircularProgressIndicator(), @@ -34,7 +35,7 @@ void main() { expect(tester.binding.transientCallbackCount, 0); }); - testWidgets('Navigation with TickerMode', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Navigation with TickerMode', (WidgetTester tester) async { await tester.pumpWidget(MaterialApp( home: const LinearProgressIndicator(), routes: <String, WidgetBuilder>{ @@ -56,7 +57,7 @@ void main() { expect(tester.binding.transientCallbackCount, 1); }); - testWidgets('SingleTickerProviderStateMixin can handle not being used', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin can handle not being used', (WidgetTester tester) async { const Widget widget = BoringTickerTest(); expect(widget.toString, isNot(throwsException)); @@ -96,7 +97,7 @@ void main() { )); }); - testWidgets('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { final GlobalKey<_SingleTickerTestState> key = GlobalKey<_SingleTickerTestState>(); final Widget widget = _SingleTickerTest(key: key); await tester.pumpWidget(widget); @@ -136,7 +137,7 @@ void main() { } }); - testWidgets('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin dispose while active', (WidgetTester tester) async { final GlobalKey<_SingleTickerTestState> key = GlobalKey<_SingleTickerTestState>(); final Widget widget = _SingleTickerTest(key: key); await tester.pumpWidget(widget); @@ -176,7 +177,7 @@ void main() { } }); - testWidgets('TickerProviderStateMixin dispose while any ticker is active', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TickerProviderStateMixin dispose while any ticker is active', (WidgetTester tester) async { final GlobalKey<_MultipleTickerTestState> key = GlobalKey<_MultipleTickerTestState>(); final Widget widget = _MultipleTickerTest(key: key); await tester.pumpWidget(widget); @@ -216,12 +217,12 @@ void main() { }); }); - testWidgets('SingleTickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SingleTickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { await tester.pumpWidget(const _SingleTickerTest()); expect(tester.state<_SingleTickerTestState>(find.byType(_SingleTickerTest)).toStringCount, 0); }); - testWidgets('TickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TickerProviderStateMixin does not call State.toString', (WidgetTester tester) async { await tester.pumpWidget(const _MultipleTickerTest()); expect(tester.state<_MultipleTickerTestState>(find.byType(_MultipleTickerTest)).toStringCount, 0); }); diff --git a/packages/flutter/test/widgets/title_test.dart b/packages/flutter/test/widgets/title_test.dart index 71dbf6f9e1c79..e61a2a86ec324 100644 --- a/packages/flutter/test/widgets/title_test.dart +++ b/packages/flutter/test/widgets/title_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toString control test', (WidgetTester tester) async { final Widget widget = Title( color: const Color(0xFF00FF00), title: 'Awesome app', @@ -16,7 +17,7 @@ void main() { expect(widget.toString, isNot(throwsException)); }); - testWidgets('should handle having no title', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should handle having no title', (WidgetTester tester) async { final Title widget = Title( color: const Color(0xFF00FF00), child: Container(), @@ -26,14 +27,14 @@ void main() { expect(widget.color, equals(const Color(0xFF00FF00))); }); - testWidgets('should not allow non-opaque color', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should not allow non-opaque color', (WidgetTester tester) async { expect(() => Title( color: const Color(0x00000000), child: Container(), ), throwsAssertionError); }); - testWidgets('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async { + testWidgetsWithLeakTracking('should not pass "null" to setApplicationSwitcherDescription', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async { diff --git a/packages/flutter/test/widgets/tracking_scroll_controller_test.dart b/packages/flutter/test/widgets/tracking_scroll_controller_test.dart index 11a19f5362a0a..fd76a6d0c4daf 100644 --- a/packages/flutter/test/widgets/tracking_scroll_controller_test.dart +++ b/packages/flutter/test/widgets/tracking_scroll_controller_test.dart @@ -4,10 +4,12 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('TrackingScrollController saves offset', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TrackingScrollController saves offset', (WidgetTester tester) async { final TrackingScrollController controller = TrackingScrollController(); + addTearDown(controller.dispose); const double listItemHeight = 100.0; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/transformed_scrollable_test.dart b/packages/flutter/test/widgets/transformed_scrollable_test.dart index 5a57556d78dd8..a11485de5d286 100644 --- a/packages/flutter/test/widgets/transformed_scrollable_test.dart +++ b/packages/flutter/test/widgets/transformed_scrollable_test.dart @@ -6,10 +6,13 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Scrollable scaled up', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable scaled up', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform.scale( @@ -52,8 +55,10 @@ void main() { expect(controller.offset, 42.5); // 85.0 - (85.0 / 2) }); - testWidgets('Scrollable scaled down', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable scaled down', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform.scale( @@ -96,8 +101,10 @@ void main() { expect(controller.offset, 0.0); // 340.0 - (170.0 * 2) }); - testWidgets('Scrollable rotated 90 degrees', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrollable rotated 90 degrees', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform.rotate( @@ -136,8 +143,10 @@ void main() { expect(controller.offset, 30.0); // 100.0 - 70.0 }); - testWidgets('Perspective transform on scrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Perspective transform on scrollable', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: Transform( diff --git a/packages/flutter/test/widgets/transitions_test.dart b/packages/flutter/test/widgets/transitions_test.dart index 9af19cf513d75..92f74baf604af 100644 --- a/packages/flutter/test/widgets/transitions_test.dart +++ b/packages/flutter/test/widgets/transitions_test.dart @@ -5,9 +5,10 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('toString control test', (WidgetTester tester) async { const Widget widget = FadeTransition( opacity: kAlwaysCompleteAnimation, child: Text('Ready', textDirection: TextDirection.ltr), @@ -47,7 +48,7 @@ void main() { controller = AnimationController(vsync: const TestVSync()); }); - testWidgets('decoration test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('decoration test', (WidgetTester tester) async { final DecoratedBoxTransition transitionUnderTest = DecoratedBoxTransition( decoration: decorationTween.animate(controller), @@ -95,7 +96,7 @@ void main() { expect(actualDecoration.boxShadow, null); }); - testWidgets('animations work with curves test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animations work with curves test', (WidgetTester tester) async { final Animation<Decoration> curvedDecorationAnimation = decorationTween.animate(CurvedAnimation( parent: controller, @@ -144,7 +145,7 @@ void main() { }); }); - testWidgets('AlignTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlignTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<Alignment> alignmentTween = AlignmentTween( begin: Alignment.centerLeft, @@ -168,7 +169,7 @@ void main() { expect(actualAlignment, const Alignment(0.0, 0.5)); }); - testWidgets('RelativePositionedTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RelativePositionedTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<Rect?> rectTween = RectTween( begin: const Rect.fromLTWH(0, 0, 30, 40), @@ -214,7 +215,7 @@ void main() { expect(renderBox.size, equals(const Size(665, 420))); }); - testWidgets('AlignTransition keeps width and height factors', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AlignTransition keeps width and height factors', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<Alignment> alignmentTween = AlignmentTween( begin: Alignment.centerLeft, @@ -235,7 +236,7 @@ void main() { expect(actualAlign.heightFactor, 0.4); }); - testWidgets('SizeTransition clamps negative size factors - vertical axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizeTransition clamps negative size factors - vertical axis', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: -1.0, end: 1.0).animate(controller); @@ -265,7 +266,7 @@ void main() { expect(actualPositionedBox.heightFactor, 1.0); }); - testWidgets('SizeTransition clamps negative size factors - horizontal axis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SizeTransition clamps negative size factors - horizontal axis', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: -1.0, end: 1.0).animate(controller); @@ -296,7 +297,7 @@ void main() { expect(actualPositionedBox.widthFactor, 1.0); }); - testWidgets('MatrixTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MatrixTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = MatrixTransition( alignment: Alignment.topRight, @@ -336,7 +337,7 @@ void main() { ])..transpose()); }); - testWidgets('MatrixTransition maintains chosen alignment during animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('MatrixTransition maintains chosen alignment during animation', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = MatrixTransition( alignment: Alignment.topRight, @@ -357,7 +358,7 @@ void main() { expect(actualAlignment, Alignment.topRight); }); - testWidgets('RotationTransition animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RotationTransition animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = RotationTransition( alignment: Alignment.topRight, @@ -396,7 +397,7 @@ void main() { ])..transpose())); }); - testWidgets('RotationTransition maintains chosen alignment during animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RotationTransition maintains chosen alignment during animation', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Widget widget = RotationTransition( alignment: Alignment.topRight, @@ -426,7 +427,7 @@ void main() { ); return opacityWidget.opacity.value; } - testWidgets('animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -469,7 +470,7 @@ void main() { ); return opacityWidget.opacity.value; } - testWidgets('animates', (WidgetTester tester) async { + testWidgetsWithLeakTracking('animates', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Localizations( @@ -519,7 +520,7 @@ void main() { }); group('MatrixTransition', () { - testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -582,7 +583,7 @@ void main() { }); group('ScaleTransition', () { - testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -635,7 +636,7 @@ void main() { }); group('RotationTransition', () { - testWidgets('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { + testWidgetsWithLeakTracking('uses ImageFilter when provided with FilterQuality argument', (WidgetTester tester) async { final AnimationController controller = AnimationController(vsync: const TestVSync()); final Animation<double> animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); final Widget widget = Directionality( @@ -688,9 +689,11 @@ void main() { }); group('Builders', () { - testWidgets('AnimatedBuilder rebuilds when changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('AnimatedBuilder rebuilds when changed', (WidgetTester tester) async { final GlobalKey<RedrawCounterState> redrawKey = GlobalKey<RedrawCounterState>(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -716,10 +719,12 @@ void main() { expect(redrawKey.currentState!.redraws, equals(2)); }); - testWidgets("AnimatedBuilder doesn't rebuild the child", (WidgetTester tester) async { + testWidgetsWithLeakTracking("AnimatedBuilder doesn't rebuild the child", (WidgetTester tester) async { final GlobalKey<RedrawCounterState> redrawKey = GlobalKey<RedrawCounterState>(); final GlobalKey<RedrawCounterState> redrawKeyChild = GlobalKey<RedrawCounterState>(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -750,9 +755,11 @@ void main() { expect(redrawKeyChild.currentState!.redraws, equals(1)); }); - testWidgets('ListenableBuilder rebuilds when changed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ListenableBuilder rebuilds when changed', (WidgetTester tester) async { final GlobalKey<RedrawCounterState> redrawKey = GlobalKey<RedrawCounterState>(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -778,10 +785,12 @@ void main() { expect(redrawKey.currentState!.redraws, equals(2)); }); - testWidgets("ListenableBuilder doesn't rebuild the child", (WidgetTester tester) async { + testWidgetsWithLeakTracking("ListenableBuilder doesn't rebuild the child", (WidgetTester tester) async { final GlobalKey<RedrawCounterState> redrawKey = GlobalKey<RedrawCounterState>(); final GlobalKey<RedrawCounterState> redrawKeyChild = GlobalKey<RedrawCounterState>(); final ChangeNotifier notifier = ChangeNotifier(); + addTearDown(notifier.dispose); + await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, diff --git a/packages/flutter/test/widgets/tree_shape_test.dart b/packages/flutter/test/widgets/tree_shape_test.dart index 306bacfb18cb0..ab1c97ff922bd 100644 --- a/packages/flutter/test/widgets/tree_shape_test.dart +++ b/packages/flutter/test/widgets/tree_shape_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Providing a RenderObjectWidget directly to the RootWidget fails', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Providing a RenderObjectWidget directly to the RootWidget fails', (WidgetTester tester) async { // No render tree exists to attach the RenderObjectWidget to. await pumpWidgetWithoutViewWrapper( tester: tester, @@ -23,7 +24,7 @@ void main() { )); }); - testWidgets('Moving a RenderObjectWidget to the RootWidget via GlobalKey fails', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a RenderObjectWidget to the RootWidget via GlobalKey fails', (WidgetTester tester) async { final Widget globalKeyedWidget = ColoredBox( key: GlobalKey(), color: Colors.red, @@ -50,7 +51,7 @@ void main() { )); }); - testWidgets('A View cannot be a child of a render object widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A View cannot be a child of a render object widget', (WidgetTester tester) async { await tester.pumpWidget(Center( child: View( view: FakeView(tester.view), @@ -65,7 +66,7 @@ void main() { )); }); - testWidgets('The child of a ViewAnchor cannot be a View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The child of a ViewAnchor cannot be a View', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( child: View( @@ -82,7 +83,7 @@ void main() { )); }); - testWidgets('A View can not be moved via GlobalKey to be a child of a RenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A View can not be moved via GlobalKey to be a child of a RenderObject', (WidgetTester tester) async { final Widget globalKeyedView = View( key: GlobalKey(), view: FakeView(tester.view), @@ -110,7 +111,7 @@ void main() { )); }); - testWidgets('The view property of a ViewAnchor cannot be a render object widget', (WidgetTester tester) async { + testWidgetsWithLeakTracking('The view property of a ViewAnchor cannot be a render object widget', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( view: const ColoredBox(color: Colors.red), @@ -125,7 +126,7 @@ void main() { )); }); - testWidgets('A RenderObject cannot be moved into the view property of a ViewAnchor via GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('A RenderObject cannot be moved into the view property of a ViewAnchor via GlobalKey', (WidgetTester tester) async { final Widget globalKeyedWidget = ColoredBox( key: GlobalKey(), color: Colors.red, @@ -152,7 +153,7 @@ void main() { )); }); - testWidgets('ViewAnchor cannot be used at the top of the widget tree (outside of View)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor cannot be used at the top of the widget tree (outside of View)', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: const ViewAnchor( @@ -167,7 +168,7 @@ void main() { )); }); - testWidgets('ViewAnchor cannot be moved to the top of the widget tree (outside of View) via GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor cannot be moved to the top of the widget tree (outside of View) via GlobalKey', (WidgetTester tester) async { final Widget globalKeyedViewAnchor = ViewAnchor( key: GlobalKey(), child: const SizedBox(), @@ -194,7 +195,7 @@ void main() { )); }); - testWidgets('View can be used at the top of the widget tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('View can be used at the top of the widget tree', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: View( @@ -206,7 +207,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('View can be moved to the top of the widget tree view GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('View can be moved to the top of the widget tree view GlobalKey', (WidgetTester tester) async { final Widget globalKeyView = View( view: FakeView(tester.view), child: const ColoredBox(color: Colors.red), @@ -235,7 +236,7 @@ void main() { expect(find.byType(ColoredBox), findsOneWidget); }); - testWidgets('ViewCollection can be used at the top of the widget tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection can be used at the top of the widget tree', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -251,7 +252,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('ViewCollection cannot be used inside a View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection cannot be used inside a View', (WidgetTester tester) async { await tester.pumpWidget( ViewCollection( views: <Widget>[ @@ -270,7 +271,7 @@ void main() { )); }); - testWidgets('ViewCollection can be used as ViewAnchor.view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection can be used as ViewAnchor.view', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( view: ViewCollection( @@ -288,7 +289,7 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('ViewCollection cannot have render object widgets as children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection cannot have render object widgets as children', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -305,7 +306,7 @@ void main() { )); }); - testWidgets('Views can be moved in and out of ViewCollections via GlobalKey', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Views can be moved in and out of ViewCollections via GlobalKey', (WidgetTester tester) async { final Widget greenView = View( key: GlobalKey(debugLabel: 'green'), view: tester.view, @@ -350,7 +351,7 @@ void main() { expect(find.byType(ColoredBox), findsNWidgets(2)); }); - testWidgets('Can move stuff between views via global key: viewA -> viewB', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff between views via global key: viewA -> viewB', (WidgetTester tester) async { final FlutterView greenView = tester.view; final FlutterView redView = FakeView(tester.view); final Widget globalKeyChild = SizedBox( @@ -455,7 +456,7 @@ void main() { expect(leafRenderObject[redView.viewId], isA<RenderConstrainedBox>()); }); - testWidgets('Can move stuff between views via global key: viewB -> viewA', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff between views via global key: viewB -> viewA', (WidgetTester tester) async { final FlutterView greenView = tester.view; final FlutterView redView = FakeView(tester.view); final Widget globalKeyChild = SizedBox( @@ -560,7 +561,7 @@ void main() { expect(leafRenderObject[greenView.viewId], isA<RenderConstrainedBox>()); }); - testWidgets('Can move stuff out of a view that is going away, viewA -> ViewB', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is going away, viewA -> ViewB', (WidgetTester tester) async { final FlutterView greenView = tester.view; final Key greenKey = UniqueKey(); final FlutterView redView = FakeView(tester.view); @@ -641,7 +642,7 @@ void main() { ); }); - testWidgets('Can move stuff out of a view that is going away, viewB -> ViewA', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is going away, viewB -> ViewA', (WidgetTester tester) async { final FlutterView greenView = tester.view; final Key greenKey = UniqueKey(); final FlutterView redView = FakeView(tester.view); @@ -722,7 +723,7 @@ void main() { ); }); - testWidgets('Can move stuff out of a view that is moving itself, stuff ends up before view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is moving itself, stuff ends up before view', (WidgetTester tester) async { final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); final Key key3 = UniqueKey(); @@ -808,7 +809,7 @@ void main() { )); }); - testWidgets('Can move stuff out of a view that is moving itself, stuff ends up after view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can move stuff out of a view that is moving itself, stuff ends up after view', (WidgetTester tester) async { final Key key1 = UniqueKey(); final Key key2 = UniqueKey(); final Key key3 = UniqueKey(); @@ -896,7 +897,7 @@ void main() { )); }); - testWidgets('Can globalkey move down the tree from a view that is going away', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can globalkey move down the tree from a view that is going away', (WidgetTester tester) async { final FlutterView anchorView = FakeView(tester.view); final Widget globalKeyChild = SizedBox( key: GlobalKey(), @@ -973,7 +974,7 @@ void main() { ); }); - testWidgets('RenderObjects are disposed when a view goes away from a ViewAnchor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjects are disposed when a view goes away from a ViewAnchor', (WidgetTester tester) async { final FlutterView anchorView = FakeView(tester.view); await tester.pumpWidget( @@ -1003,7 +1004,7 @@ void main() { expect(box.debugDisposed, isTrue); }); - testWidgets('RenderObjects are disposed when a view goes away from a ViewCollection', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderObjects are disposed when a view goes away from a ViewCollection', (WidgetTester tester) async { final FlutterView redView = tester.view; final FlutterView greenView = FakeView(tester.view); @@ -1044,7 +1045,7 @@ void main() { expect(box.debugDisposed, isTrue); }); - testWidgets('View can be wrapped and unwrapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('View can be wrapped and unwrapped', (WidgetTester tester) async { final Widget view = View( view: tester.view, child: const SizedBox(), @@ -1077,7 +1078,7 @@ void main() { expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); }); - testWidgets('ViewAnchor with View can be wrapped and unwrapped', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor with View can be wrapped and unwrapped', (WidgetTester tester) async { final Widget viewAnchor = ViewAnchor( view: View( view: FakeView(tester.view), @@ -1102,7 +1103,7 @@ void main() { expect(tester.renderObject(find.byType(SizedBox)), same(renderSizedBox)); }); - testWidgets('Moving a View keeps its semantics tree stable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Moving a View keeps its semantics tree stable', (WidgetTester tester) async { final Widget view = View( // No explicit key, we rely on the implicit key of the underlying RawView. view: tester.view, diff --git a/packages/flutter/test/widgets/tween_animation_builder_test.dart b/packages/flutter/test/widgets/tween_animation_builder_test.dart index afad96ecfe1d5..4c19cda2dfcdf 100644 --- a/packages/flutter/test/widgets/tween_animation_builder_test.dart +++ b/packages/flutter/test/widgets/tween_animation_builder_test.dart @@ -4,9 +4,10 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Animates forward when built', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Animates forward when built', (WidgetTester tester) async { final List<int> values = <int>[]; int endCount = 0; await tester.pumpWidget( @@ -37,7 +38,7 @@ void main() { expect(values, <int>[10, 60, 110]); }); - testWidgets('No initial animation when begin=null', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No initial animation when begin=null', (WidgetTester tester) async { final List<int> values = <int>[]; int endCount = 0; await tester.pumpWidget( @@ -61,7 +62,7 @@ void main() { }); - testWidgets('No initial animation when begin=end', (WidgetTester tester) async { + testWidgetsWithLeakTracking('No initial animation when begin=end', (WidgetTester tester) async { final List<int> values = <int>[]; int endCount = 0; await tester.pumpWidget( @@ -84,7 +85,7 @@ void main() { expect(values, <int>[100]); }); - testWidgets('Replace tween animates new tween', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Replace tween animates new tween', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder<int>( @@ -112,7 +113,7 @@ void main() { expect(values, <int>[0, 100, 100, 150, 200]); }); - testWidgets('Curve is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Curve is respected', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween, required Curve curve}) { return TweenAnimationBuilder<int>( @@ -142,7 +143,7 @@ void main() { expect(values, <int>[100, 150]); }); - testWidgets('Duration is respected', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Duration is respected', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween, required Duration duration}) { return TweenAnimationBuilder<int>( @@ -170,7 +171,7 @@ void main() { expect(values, <int>[100, 125]); }); - testWidgets('Child is integrated into tree', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Child is integrated into tree', (WidgetTester tester) async { await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, @@ -189,7 +190,7 @@ void main() { }); group('Change tween gapless while', () { - testWidgets('running forward', (WidgetTester tester) async { + testWidgetsWithLeakTracking('running forward', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder<int>( @@ -224,7 +225,7 @@ void main() { values.clear(); }); - testWidgets('running forward and then reverse with same tween instance', (WidgetTester tester) async { + testWidgetsWithLeakTracking('running forward and then reverse with same tween instance', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder<int>( @@ -254,7 +255,7 @@ void main() { }); }); - testWidgets('Changing tween while gapless tween change is in progress', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing tween while gapless tween change is in progress', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder<int>( @@ -294,7 +295,7 @@ void main() { expect(values, <int>[175, 338, 501]); }); - testWidgets('Changing curve while no animation is running does not trigger animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Changing curve while no animation is running does not trigger animation', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required Curve curve}) { return TweenAnimationBuilder<int>( @@ -323,7 +324,7 @@ void main() { expect(values, <int>[100]); }); - testWidgets('Setting same tween and direction does not trigger animation', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting same tween and direction does not trigger animation', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder<int>( @@ -352,7 +353,7 @@ void main() { expect(values, everyElement(100)); }); - testWidgets('Setting same tween and direction while gapless animation is in progress works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Setting same tween and direction while gapless animation is in progress works', (WidgetTester tester) async { final List<int> values = <int>[]; Widget buildWidget({required IntTween tween}) { return TweenAnimationBuilder<int>( @@ -388,7 +389,7 @@ void main() { expect(values, everyElement(300)); }); - testWidgets('Works with nullable tweens', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Works with nullable tweens', (WidgetTester tester) async { final List<Size?> values = <Size?>[]; await tester.pumpWidget( TweenAnimationBuilder<Size?>( diff --git a/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart b/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart index 9da89311ceb4b..f1cb8d5c30131 100644 --- a/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_scroll_view_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/src/gestures/monodrag.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'two_dimensional_utils.dart'; @@ -19,34 +20,40 @@ Widget? _testChildBuilder(BuildContext context, ChildVicinity vicinity) { void main() { group('TwoDimensionalScrollView',() { - testWidgets('asserts the axis directions do not conflict with one another', (WidgetTester tester) async { + testWidgetsWithLeakTracking('asserts the axis directions do not conflict with one another', (WidgetTester tester) async { final List<Object> exceptions = <Object>[]; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { exceptions.add(details.exception); }; // Horizontal wrong + late final TwoDimensionalChildBuilderDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), + delegate: delegate1 = TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), horizontalDetails: const ScrollableDetails.vertical(), // Horizontal has default const ScrollableDetails.horizontal() ), )); // Vertical wrong + late final TwoDimensionalChildBuilderDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), + delegate: delegate2 = TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), verticalDetails: const ScrollableDetails.horizontal(), // Horizontal has default const ScrollableDetails.horizontal() ), )); // Both wrong + late final TwoDimensionalChildBuilderDelegate delegate3; + addTearDown(() => delegate3.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), + delegate: delegate3 = TwoDimensionalChildBuilderDelegate(builder: (_, __) => null), verticalDetails: const ScrollableDetails.horizontal(), horizontalDetails: const ScrollableDetails.vertical(), ), @@ -60,15 +67,19 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('ScrollableDetails.controller can set initial scroll positions, modify within bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollableDetails.controller can set initial scroll positions, modify within bounds', (WidgetTester tester) async { final ScrollController verticalController = ScrollController(initialScrollOffset: 100); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(initialScrollOffset: 50); + addTearDown(horizontalController.dispose); + late final TwoDimensionalChildBuilderDelegate delegate; + addTearDown(() => delegate.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( verticalDetails: ScrollableDetails.vertical(controller: verticalController), horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController), - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate = TwoDimensionalChildBuilderDelegate( builder: _testChildBuilder, maxXIndex: 99, maxYIndex: 99, @@ -99,13 +110,20 @@ void main() { expect(horizontalController.position.pixels, 19200); }, variant: TargetPlatformVariant.all()); - testWidgets('Properly assigns the PrimaryScrollController to the main axis on the correct platform', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Properly assigns the PrimaryScrollController to the main axis on the correct platform', (WidgetTester tester) async { late ScrollController controller; Widget buildForPrimaryScrollController({ bool? explicitPrimary, Axis mainAxis = Axis.vertical, bool addControllerConflict = false, }) { + final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); + final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); + late final TwoDimensionalChildBuilderDelegate delegate; + addTearDown(() => delegate.dispose()); + return MaterialApp( home: PrimaryScrollController( controller: controller, @@ -114,15 +132,15 @@ void main() { primary: explicitPrimary, verticalDetails: ScrollableDetails.vertical( controller: addControllerConflict && mainAxis == Axis.vertical - ? ScrollController() + ? verticalController : null ), horizontalDetails: ScrollableDetails.horizontal( controller: addControllerConflict && mainAxis == Axis.horizontal - ? ScrollController() + ? horizontalController : null ), - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate = TwoDimensionalChildBuilderDelegate( builder: _testChildBuilder, maxXIndex: 99, maxYIndex: 99, @@ -134,6 +152,7 @@ void main() { // Horizontal default - horizontal never automatically adopts PSC controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, )); @@ -151,6 +170,7 @@ void main() { // Horizontal explicitly true controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, explicitPrimary: true, @@ -171,6 +191,7 @@ void main() { // Horizontal explicitly false controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, explicitPrimary: false, @@ -190,6 +211,7 @@ void main() { // Vertical default controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController()); await tester.pumpAndSettle(); @@ -209,6 +231,7 @@ void main() { // Vertical explicitly true controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( explicitPrimary: true, )); @@ -228,6 +251,7 @@ void main() { // Vertical explicitly false controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( explicitPrimary: false, )); @@ -253,6 +277,7 @@ void main() { // Vertical asserts ScrollableDetails.controller has not been provided if // primary is explicitly set controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( explicitPrimary: true, addControllerConflict: true, @@ -268,6 +293,7 @@ void main() { // Horizontal asserts ScrollableDetails.controller has not been provided // if primary is explicitly set true controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildForPrimaryScrollController( mainAxis: Axis.horizontal, explicitPrimary: true, @@ -282,12 +308,14 @@ void main() { FlutterError.onError = oldHandler; }, variant: TargetPlatformVariant.all()); - testWidgets('TwoDimensionalScrollable receives the correct details from TwoDimensionalScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TwoDimensionalScrollable receives the correct details from TwoDimensionalScrollView', (WidgetTester tester) async { late BuildContext capturedContext; // Default + late final TwoDimensionalChildBuilderDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate1 = TwoDimensionalChildBuilderDelegate( builder: (BuildContext context, ChildVicinity vicinity) { capturedContext = context; return Text(vicinity.toString()); @@ -305,13 +333,15 @@ void main() { expect(scrollable.widget.dragStartBehavior, DragStartBehavior.start); // Customized + late final TwoDimensionalChildBuilderDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(MaterialApp( home: SimpleBuilderTableView( verticalDetails: const ScrollableDetails.vertical(reverse: true), horizontalDetails: const ScrollableDetails.horizontal(reverse: true), diagonalDragBehavior: DiagonalDragBehavior.weightedContinuous, dragStartBehavior: DragStartBehavior.down, - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate2 = TwoDimensionalChildBuilderDelegate( builder: _testChildBuilder, ), ), diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index e65f5319ba3aa..903dfe8c0038f 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -7,16 +7,19 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'two_dimensional_utils.dart'; void main() { group('TwoDimensionalChildDelegate', () { group('TwoDimensionalChildBuilderDelegate', () { - testWidgets('repaintBoundaries', (WidgetTester tester) async { + testWidgetsWithLeakTracking('repaintBoundaries', (WidgetTester tester) async { // Default - adds repaint boundaries + late final TwoDimensionalChildBuilderDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(simpleBuilderTest( - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate1 = TwoDimensionalChildBuilderDelegate( // Only build 1 child maxXIndex: 0, maxYIndex: 0, @@ -43,8 +46,10 @@ void main() { } // None + late final TwoDimensionalChildBuilderDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(simpleBuilderTest( - delegate: TwoDimensionalChildBuilderDelegate( + delegate: delegate2 = TwoDimensionalChildBuilderDelegate( // Only build 1 child maxXIndex: 0, maxYIndex: 0, @@ -72,7 +77,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('will return null from build for exceeding maxXIndex and maxYIndex', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will return null from build for exceeding maxXIndex and maxYIndex', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( // Only build 1 child @@ -88,6 +93,8 @@ void main() { ); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -185,7 +192,7 @@ void main() { ); }); - testWidgets('throws an error when builder throws', (WidgetTester tester) async { + testWidgetsWithLeakTracking('throws an error when builder throws', (WidgetTester tester) async { final List<Object> exceptions = <Object>[]; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { @@ -200,6 +207,8 @@ void main() { throw 'Builder error!'; } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -211,13 +220,14 @@ void main() { expect(exceptions[0] as String, contains('Builder error!')); }, variant: TargetPlatformVariant.all()); - testWidgets('shouldRebuild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shouldRebuild', (WidgetTester tester) async { expect(builderDelegate.shouldRebuild(builderDelegate), isTrue); }, variant: TargetPlatformVariant.all()); - testWidgets('builder delegate supports automatic keep alive - default true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builder delegate supports automatic keep alive - default true', (WidgetTester tester) async { const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final UniqueKey checkBoxKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -232,6 +242,7 @@ void main() { ); } ); + addTearDown(builderDelegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: builderDelegate, @@ -301,9 +312,10 @@ void main() { ); }); - testWidgets('builder delegate will not add automatic keep alives', (WidgetTester tester) async { + testWidgetsWithLeakTracking('builder delegate will not add automatic keep alives', (WidgetTester tester) async { const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final UniqueKey checkBoxKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -319,6 +331,7 @@ void main() { ); } ); + addTearDown(builderDelegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: builderDelegate, @@ -383,7 +396,7 @@ void main() { }); group('TwoDimensionalChildListDelegate', () { - testWidgets('repaintBoundaries', (WidgetTester tester) async { + testWidgetsWithLeakTracking('repaintBoundaries', (WidgetTester tester) async { final List<List<Widget>> children = <List<Widget>>[]; children.add(<Widget>[ const SizedBox( @@ -393,8 +406,10 @@ void main() { ) ]); // Default - adds repaint boundaries + late final TwoDimensionalChildListDelegate delegate1; + addTearDown(() => delegate1.dispose()); await tester.pumpWidget(simpleListTest( - delegate: TwoDimensionalChildListDelegate( + delegate: delegate1 = TwoDimensionalChildListDelegate( // Only builds 1 child children: children, ) @@ -426,8 +441,10 @@ void main() { } // None + late final TwoDimensionalChildListDelegate delegate2; + addTearDown(() => delegate2.dispose()); await tester.pumpWidget(simpleListTest( - delegate: TwoDimensionalChildListDelegate( + delegate: delegate2 = TwoDimensionalChildListDelegate( // Different children triggers rebuild children: <List<Widget>>[<Widget>[Container()]], addRepaintBoundaries: false, @@ -451,7 +468,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('will return null for a ChildVicinity outside of list bounds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will return null for a ChildVicinity outside of list bounds', (WidgetTester tester) async { final List<List<Widget>> children = <List<Widget>>[]; children.add(<Widget>[ const SizedBox( @@ -464,6 +481,7 @@ void main() { // Only builds 1 child children: children, ); + addTearDown(delegate.dispose); // X index expect( @@ -483,7 +501,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('shouldRebuild', (WidgetTester tester) async { + testWidgetsWithLeakTracking('shouldRebuild', (WidgetTester tester) async { final List<List<Widget>> children = <List<Widget>>[]; children.add(<Widget>[ const SizedBox( @@ -496,18 +514,20 @@ void main() { // Only builds 1 child children: children, ); + addTearDown(delegate.dispose); expect(delegate.shouldRebuild(delegate), isFalse); final List<List<Widget>> newChildren = <List<Widget>>[]; final TwoDimensionalChildListDelegate oldDelegate = TwoDimensionalChildListDelegate( children: newChildren, ); + addTearDown(oldDelegate.dispose); expect(delegate.shouldRebuild(oldDelegate), isTrue); }, variant: TargetPlatformVariant.all()); }); - testWidgets('list delegate supports automatic keep alive - default true', (WidgetTester tester) async { + testWidgetsWithLeakTracking('list delegate supports automatic keep alive - default true', (WidgetTester tester) async { final UniqueKey checkBoxKey = UniqueKey(); final Widget originCell = SizedBox.square( dimension: 200, @@ -516,6 +536,7 @@ void main() { ); const Widget otherCell = SizedBox.square(dimension: 200); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate( children: <List<Widget>>[ <Widget>[originCell, otherCell, otherCell, otherCell, otherCell], @@ -525,6 +546,7 @@ void main() { <Widget>[otherCell, otherCell, otherCell, otherCell, otherCell], ], ); + addTearDown(listDelegate.dispose); await tester.pumpWidget(simpleListTest( delegate: listDelegate, @@ -594,7 +616,7 @@ void main() { ); }); - testWidgets('list delegate will not add automatic keep alives', (WidgetTester tester) async { + testWidgetsWithLeakTracking('list delegate will not add automatic keep alives', (WidgetTester tester) async { final UniqueKey checkBoxKey = UniqueKey(); final Widget originCell = SizedBox.square( dimension: 200, @@ -603,6 +625,7 @@ void main() { ); const Widget otherCell = SizedBox.square(dimension: 200); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final TwoDimensionalChildListDelegate listDelegate = TwoDimensionalChildListDelegate( addAutomaticKeepAlives: false, children: <List<Widget>>[ @@ -613,6 +636,7 @@ void main() { <Widget>[otherCell, otherCell, otherCell, otherCell, otherCell], ], ); + addTearDown(listDelegate.dispose); await tester.pumpWidget(simpleListTest( delegate: listDelegate, @@ -677,7 +701,7 @@ void main() { }); group('TwoDimensionalScrollable', () { - testWidgets('.of, .maybeOf', (WidgetTester tester) async { + testWidgetsWithLeakTracking('.of, .maybeOf', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -687,6 +711,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -714,7 +740,7 @@ void main() { expect(TwoDimensionalScrollable.maybeOf(capturedContext), isNull); }, variant: TargetPlatformVariant.all()); - testWidgets('horizontal and vertical getters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('horizontal and vertical getters', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -724,6 +750,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -734,7 +762,7 @@ void main() { expect(scrollable.horizontalScrollable.position.pixels, 0.0); }, variant: TargetPlatformVariant.all()); - testWidgets('creates fallback ScrollControllers if not provided by ScrollableDetails', (WidgetTester tester) async { + testWidgetsWithLeakTracking('creates fallback ScrollControllers if not provided by ScrollableDetails', (WidgetTester tester) async { late BuildContext capturedContext; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -744,6 +772,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -798,7 +828,7 @@ void main() { FlutterError.onError = oldHandler; }, variant: TargetPlatformVariant.all()); - testWidgets('correctly sets restorationIds', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly sets restorationIds', (WidgetTester tester) async { late BuildContext capturedContext; // with restorationID set await tester.pumpWidget(WidgetsApp( @@ -868,7 +898,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('Restoration works', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Restoration works', (WidgetTester tester) async { await tester.pumpWidget(WidgetsApp( color: const Color(0xFFFFFFFF), restorationScopeId: 'Test ID', @@ -893,7 +923,7 @@ void main() { await restoreScrollAndVerify(tester); }, variant: TargetPlatformVariant.all()); - testWidgets('Inner Scrollables receive the correct details from TwoDimensionalScrollable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inner Scrollables receive the correct details from TwoDimensionalScrollable', (WidgetTester tester) async { // Default late BuildContext capturedContext; await tester.pumpWidget(TwoDimensionalScrollable( @@ -939,7 +969,9 @@ void main() { // Customized final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); double calculator(_) => 0.0; await tester.pumpWidget(TwoDimensionalScrollable( incrementCalculator: calculator, @@ -1009,10 +1041,12 @@ void main() { }, variant: TargetPlatformVariant.all()); group('DiagonalDragBehavior', () { - testWidgets('none (default)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('none (default)', (WidgetTester tester) async { // Vertical and horizontal axes are locked. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1059,11 +1093,13 @@ void main() { expect(horizontalController.position.pixels, 140.0); }, variant: TargetPlatformVariant.all()); - testWidgets('weightedEvent', (WidgetTester tester) async { + testWidgetsWithLeakTracking('weightedEvent', (WidgetTester tester) async { // For weighted event, the winning axis is locked for the duration of // the gesture. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1181,13 +1217,15 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.all()); - testWidgets('weightedContinuous', (WidgetTester tester) async { + testWidgetsWithLeakTracking('weightedContinuous', (WidgetTester tester) async { // For weighted continuous, the winning axis can change if the axis // differential for the gesture exceeds kTouchSlop. So it can lock, and // remain locked, if the user maintains a generally straight gesture, // otherwise it will unlock and re-evaluate. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1238,10 +1276,12 @@ void main() { await tester.pumpAndSettle(); }, variant: TargetPlatformVariant.all()); - testWidgets('free', (WidgetTester tester) async { + testWidgetsWithLeakTracking('free', (WidgetTester tester) async { // For free, anything goes. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: simpleBuilderTest( @@ -1283,7 +1323,7 @@ void main() { }); }); - testWidgets('TwoDimensionalViewport asserts against axes mismatch', (WidgetTester tester) async { + testWidgetsWithLeakTracking('TwoDimensionalViewport asserts against axes mismatch', (WidgetTester tester) async { // Horizontal mismatch expect( () { @@ -1458,7 +1498,7 @@ void main() { ); }); - testWidgets('getters', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getters', (WidgetTester tester) async { final UniqueKey childKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1467,6 +1507,7 @@ void main() { return SizedBox.square(key: childKey, dimension: 200); } ); + addTearDown(delegate.dispose); final RenderSimpleBuilderTableViewport renderViewport = RenderSimpleBuilderTableViewport( verticalOffset: ViewportOffset.fixed(10.0), verticalAxisDirection: AxisDirection.down, @@ -1476,6 +1517,7 @@ void main() { mainAxis: Axis.vertical, childManager: _NullBuildContext(), ); + addTearDown(renderViewport.dispose); expect(renderViewport.clipBehavior, Clip.hardEdge); expect(renderViewport.cacheExtent, RenderAbstractViewport.defaultCacheExtent); @@ -1510,7 +1552,7 @@ void main() { expect(viewport.viewportDimension, const Size(800.0, 600.0)); }, variant: TargetPlatformVariant.all()); - testWidgets('Children are organized according to mainAxis', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Children are organized according to mainAxis', (WidgetTester tester) async { final Map<ChildVicinity, UniqueKey> childKeys = <ChildVicinity, UniqueKey>{}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -1520,6 +1562,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); TwoDimensionalViewportParentData parentDataOf(RenderBox child) { return child.parentData! as TwoDimensionalViewportParentData; } @@ -1596,7 +1639,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('sets up parent data', (WidgetTester tester) async { + testWidgetsWithLeakTracking('sets up parent data', (WidgetTester tester) async { // Also tests computeAbsolutePaintOffsetFor & computeChildPaintExtent // Regression test for https://github.com/flutter/flutter/issues/128723 final Map<ChildVicinity, UniqueKey> childKeys = <ChildVicinity, UniqueKey>{}; @@ -1608,6 +1651,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); // parent data is TwoDimensionalViewportParentData TwoDimensionalViewportParentData parentDataOf(RenderBox child) { @@ -1707,7 +1751,9 @@ void main() { // Change the scroll positions to test partially visible. final ScrollController verticalController = ScrollController(); + addTearDown(verticalController.dispose); final ScrollController horizontalController = ScrollController(); + addTearDown(horizontalController.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, horizontalDetails: ScrollableDetails.horizontal(controller: horizontalController), @@ -1727,7 +1773,7 @@ void main() { expect(childParentData.layoutOffset, const Offset(-50.0, -50.0)); }, variant: TargetPlatformVariant.all()); - testWidgets('debugDescribeChildren', (WidgetTester tester) async { + testWidgetsWithLeakTracking('debugDescribeChildren', (WidgetTester tester) async { final Map<ChildVicinity, UniqueKey> childKeys = <ChildVicinity, UniqueKey>{}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -1737,6 +1783,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -1798,7 +1845,7 @@ void main() { expect((exceptions[0] as FlutterError).message, contains('unbounded')); }, variant: TargetPlatformVariant.all()); - testWidgets('computeDryLayout asserts axes are bounded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('computeDryLayout asserts axes are bounded', (WidgetTester tester) async { final UniqueKey childKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1807,6 +1854,8 @@ void main() { return SizedBox.square(key: childKey, dimension: 200); } ); + addTearDown(delegate.dispose); + // Call computeDryLayout with unbounded constraints await tester.pumpWidget(simpleBuilderTest(delegate: delegate)); final RenderTwoDimensionalViewport viewport = getViewport( @@ -1827,7 +1876,7 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - testWidgets('correctly resizes dimensions', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly resizes dimensions', (WidgetTester tester) async { final UniqueKey childKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1836,6 +1885,8 @@ void main() { return SizedBox.square(key: childKey, dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -1857,7 +1908,7 @@ void main() { tester.view.resetDevicePixelRatio(); }, variant: TargetPlatformVariant.all()); - testWidgets('Rebuilds when delegate changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Rebuilds when delegate changes', (WidgetTester tester) async { final UniqueKey firstChildKey = UniqueKey(); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 0, @@ -1867,6 +1918,8 @@ void main() { return SizedBox.square(key: firstChildKey, dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, )); @@ -1882,6 +1935,8 @@ void main() { return Container(key: newChildKey, height: 300, width: 300, color: const Color(0xFFFFFFFF)); } ); + addTearDown(() => newDelegate.dispose()); + await tester.pumpWidget(simpleBuilderTest( delegate: newDelegate, )); @@ -1892,7 +1947,7 @@ void main() { expect(viewport.firstChild, tester.renderObject<RenderBox>(find.byKey(newChildKey))); }, variant: TargetPlatformVariant.all()); - testWidgets('hitTestChildren', (WidgetTester tester) async { + testWidgetsWithLeakTracking('hitTestChildren', (WidgetTester tester) async { final List<ChildVicinity> taps = <ChildVicinity>[]; final Map<ChildVicinity, UniqueKey> childKeys = <ChildVicinity, UniqueKey>{}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( @@ -1913,6 +1968,7 @@ void main() { ); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -1961,7 +2017,7 @@ void main() { expect(taps.contains(const ChildVicinity(xIndex: 5, yIndex: 5)), isFalse); }, variant: TargetPlatformVariant.all()); - testWidgets('getChildFor', (WidgetTester tester) async { + testWidgetsWithLeakTracking('getChildFor', (WidgetTester tester) async { final Map<ChildVicinity, UniqueKey> childKeys = <ChildVicinity, UniqueKey>{}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -1971,6 +2027,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -2007,6 +2064,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -2039,6 +2097,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, // Will cause the test implementation to not set dimensions @@ -2048,9 +2108,10 @@ void main() { expect(error.message, contains('was not given content dimensions')); }, variant: TargetPlatformVariant.all()); - testWidgets('will not rebuild a child if it can be reused', (WidgetTester tester) async { + testWidgetsWithLeakTracking('will not rebuild a child if it can be reused', (WidgetTester tester) async { final List<ChildVicinity> builtChildren = <ChildVicinity>[]; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, maxYIndex: 5, @@ -2059,6 +2120,7 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, @@ -2087,6 +2149,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, // Will cause the test implementation to not set the layoutOffset of @@ -2105,6 +2169,8 @@ void main() { return const SizedBox.square(dimension: 200); } ); + addTearDown(delegate.dispose); + await tester.pumpWidget(simpleBuilderTest( delegate: delegate, // Will cause the test implementation to not actually layout the @@ -2115,7 +2181,7 @@ void main() { expect(error.toString(), contains('child.hasSize')); }, variant: TargetPlatformVariant.all()); - testWidgets('does not support intrinsics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('does not support intrinsics', (WidgetTester tester) async { final Map<ChildVicinity, UniqueKey> childKeys = <ChildVicinity, UniqueKey>{}; final TwoDimensionalChildBuilderDelegate delegate = TwoDimensionalChildBuilderDelegate( maxXIndex: 5, @@ -2125,6 +2191,7 @@ void main() { return SizedBox.square(key: childKeys[vicinity], dimension: 200); } ); + addTearDown(delegate.dispose); await tester.pumpWidget(simpleBuilderTest( delegate: delegate, diff --git a/packages/flutter/test/widgets/undo_history_test.dart b/packages/flutter/test/widgets/undo_history_test.dart index dffb059bfc6ef..b5a80d09b4fed 100644 --- a/packages/flutter/test/widgets/undo_history_test.dart +++ b/packages/flutter/test/widgets/undo_history_test.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'editable_text_utils.dart'; @@ -30,9 +31,12 @@ void main() { Future<void> sendUndo(WidgetTester tester) => sendUndoRedo(tester); Future<void> sendRedo(WidgetTester tester) => sendUndoRedo(tester, true); - testWidgets('allows undo and redo to be called programmatically from the UndoHistoryController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows undo and redo to be called programmatically from the UndoHistoryController', (WidgetTester tester) async { final ValueNotifier<int> value = ValueNotifier<int>(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory<int>( @@ -119,9 +123,12 @@ void main() { expect(controller.value.canRedo, false); }, variant: TargetPlatformVariant.all()); - testWidgets('allows undo and redo to be called using the keyboard', (WidgetTester tester) async { + testWidgetsWithLeakTracking('allows undo and redo to be called using the keyboard', (WidgetTester tester) async { final ValueNotifier<int> value = ValueNotifier<int>(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory<int>( @@ -211,9 +218,12 @@ void main() { expect(controller.value.canRedo, false); }, variant: TargetPlatformVariant.all(), skip: kIsWeb); // [intended] - testWidgets('duplicate changes do not affect the undo history', (WidgetTester tester) async { + testWidgetsWithLeakTracking('duplicate changes do not affect the undo history', (WidgetTester tester) async { final ValueNotifier<int> value = ValueNotifier<int>(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory<int>( @@ -261,11 +271,14 @@ void main() { expect(controller.value.canRedo, true); }, variant: TargetPlatformVariant.all()); - testWidgets('ignores value changes pushed during onTriggered', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ignores value changes pushed during onTriggered', (WidgetTester tester) async { final ValueNotifier<int> value = ValueNotifier<int>(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); int Function(int newValue) valueToUse = (int value) => value; final GlobalKey<UndoHistoryState<int>> key = GlobalKey<UndoHistoryState<int>>(); + await tester.pumpWidget( MaterialApp( home: UndoHistory<int>( @@ -309,16 +322,20 @@ void main() { expect(() => key.currentState!.undo(), throwsAssertionError); }, variant: TargetPlatformVariant.all()); - testWidgets('changes should send setUndoState to the UndoManagerConnection on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('changes should send setUndoState to the UndoManagerConnection on iOS', (WidgetTester tester) async { final List<MethodCall> log = <MethodCall>[]; tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.undoManager, (MethodCall methodCall) async { log.add(methodCall); return null; }); final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); final ValueNotifier<int> value = ValueNotifier<int>(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory<int>( @@ -378,9 +395,12 @@ void main() { expect(methodCall.arguments as Map<String, dynamic>, <String, bool>{'canUndo': false, 'canRedo': true}); }, variant: const TargetPlatformVariant(<TargetPlatform>{TargetPlatform.iOS}), skip: kIsWeb); // [intended] - testWidgets('handlePlatformUndo should undo or redo appropriately on iOS', (WidgetTester tester) async { + testWidgetsWithLeakTracking('handlePlatformUndo should undo or redo appropriately on iOS', (WidgetTester tester) async { final ValueNotifier<int> value = ValueNotifier<int>(0); + addTearDown(value.dispose); final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); + await tester.pumpWidget( MaterialApp( home: UndoHistory<int>( @@ -465,9 +485,10 @@ void main() { }); group('UndoHistoryController', () { - testWidgets('UndoHistoryController notifies onUndo listeners onUndo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UndoHistoryController notifies onUndo listeners onUndo', (WidgetTester tester) async { int calls = 0; final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); controller.onUndo.addListener(() { calls++; }); @@ -482,9 +503,10 @@ void main() { expect(calls, 1); }); - testWidgets('UndoHistoryController notifies onRedo listeners onRedo', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UndoHistoryController notifies onRedo listeners onRedo', (WidgetTester tester) async { int calls = 0; final UndoHistoryController controller = UndoHistoryController(); + addTearDown(controller.dispose); controller.onRedo.addListener(() { calls++; }); @@ -499,9 +521,10 @@ void main() { expect(calls, 1); }); - testWidgets('UndoHistoryController notifies listeners on value change', (WidgetTester tester) async { + testWidgetsWithLeakTracking('UndoHistoryController notifies listeners on value change', (WidgetTester tester) async { int calls = 0; final UndoHistoryController controller = UndoHistoryController(value: const UndoHistoryValue(canUndo: true)); + addTearDown(controller.dispose); controller.addListener(() { calls++; }); diff --git a/packages/flutter/test/widgets/unique_widget_test.dart b/packages/flutter/test/widgets/unique_widget_test.dart index be060bc0ee1bb..8fa7b3f174dea 100644 --- a/packages/flutter/test/widgets/unique_widget_test.dart +++ b/packages/flutter/test/widgets/unique_widget_test.dart @@ -4,6 +4,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; class TestUniqueWidget extends UniqueWidget<TestUniqueWidgetState> { const TestUniqueWidget({ required super.key }); @@ -18,7 +19,7 @@ class TestUniqueWidgetState extends State<TestUniqueWidget> { } void main() { - testWidgets('Unique widget control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Unique widget control test', (WidgetTester tester) async { final TestUniqueWidget widget = TestUniqueWidget(key: GlobalKey<TestUniqueWidgetState>()); await tester.pumpWidget(widget); diff --git a/packages/flutter/test/widgets/value_listenable_builder_test.dart b/packages/flutter/test/widgets/value_listenable_builder_test.dart index 4384ed408efaa..4354f0636e0c7 100644 --- a/packages/flutter/test/widgets/value_listenable_builder_test.dart +++ b/packages/flutter/test/widgets/value_listenable_builder_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { late SpyStringValueNotifier valueListenable; @@ -32,21 +33,26 @@ void main() { textBuilderUnderTest = builderForValueListenable(valueListenable); }); - testWidgets('Null value is ok', (WidgetTester tester) async { + tearDown(() { + valueListenable.dispose(); + }); + + testWidgetsWithLeakTracking('Null value is ok', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); expect(find.byType(Placeholder), findsOneWidget); }); - testWidgets('Widget builds with initial value', (WidgetTester tester) async { - valueListenable = SpyStringValueNotifier('Bachman'); + testWidgetsWithLeakTracking('Widget builds with initial value', (WidgetTester tester) async { + final SpyStringValueNotifier valueListenable = SpyStringValueNotifier('Bachman'); + addTearDown(valueListenable.dispose); await tester.pumpWidget(builderForValueListenable(valueListenable)); expect(find.text('Bachman'), findsOneWidget); }); - testWidgets('Widget updates when value changes', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widget updates when value changes', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; @@ -59,15 +65,15 @@ void main() { expect(find.text('Dinesh'), findsOneWidget); }); - testWidgets('Can change listenable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Can change listenable', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; await tester.pump(); expect(find.text('Gilfoyle'), findsOneWidget); - final ValueListenable<String?> differentListenable = - SpyStringValueNotifier('Hendricks'); + final SpyStringValueNotifier differentListenable = SpyStringValueNotifier('Hendricks'); + addTearDown(differentListenable.dispose); await tester.pumpWidget(builderForValueListenable(differentListenable)); @@ -75,15 +81,15 @@ void main() { expect(find.text('Hendricks'), findsOneWidget); }); - testWidgets('Stops listening to old listenable after changing listenable', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Stops listening to old listenable after changing listenable', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; await tester.pump(); expect(find.text('Gilfoyle'), findsOneWidget); - final ValueListenable<String?> differentListenable = - SpyStringValueNotifier('Hendricks'); + final SpyStringValueNotifier differentListenable = SpyStringValueNotifier('Hendricks'); + addTearDown(differentListenable.dispose); await tester.pumpWidget(builderForValueListenable(differentListenable)); @@ -98,7 +104,7 @@ void main() { expect(find.text('Hendricks'), findsOneWidget); }); - testWidgets('Self-cleans when removed', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Self-cleans when removed', (WidgetTester tester) async { await tester.pumpWidget(textBuilderUnderTest); valueListenable.value = 'Gilfoyle'; diff --git a/packages/flutter/test/widgets/view_test.dart b/packages/flutter/test/widgets/view_test.dart index b0a87c09ffb8e..2fe695f0ae4c0 100644 --- a/packages/flutter/test/widgets/view_test.dart +++ b/packages/flutter/test/widgets/view_test.dart @@ -7,9 +7,10 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void main() { - testWidgets('Widgets running with runApp can find View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets running with runApp can find View', (WidgetTester tester) async { FlutterView? viewOf; FlutterView? viewMaybeOf; @@ -29,7 +30,7 @@ void main() { expect(viewMaybeOf, isA<FlutterView>()); }); - testWidgets('Widgets running with pumpWidget can find View', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Widgets running with pumpWidget can find View', (WidgetTester tester) async { FlutterView? view; FlutterView? viewMaybeOf; @@ -49,7 +50,7 @@ void main() { expect(viewMaybeOf, isA<FlutterView>()); }); - testWidgets('cannot find View behind a LookupBoundary', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cannot find View behind a LookupBoundary', (WidgetTester tester) async { await tester.pumpWidget( LookupBoundary( child: Container(), @@ -69,7 +70,7 @@ void main() { ); }); - testWidgets('child of view finds view, parentPipelineOwner, mediaQuery', (WidgetTester tester) async { + testWidgetsWithLeakTracking('child of view finds view, parentPipelineOwner, mediaQuery', (WidgetTester tester) async { FlutterView? outsideView; FlutterView? insideView; PipelineOwner? outsideParent; @@ -111,7 +112,7 @@ void main() { expect(pipelineOwners.single, equals(insideParent)); }); - testWidgets('cannot have multiple views with same FlutterView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('cannot have multiple views with same FlutterView', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -138,11 +139,11 @@ void main() { ); }); - testWidgets('ViewCollection must have one view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewCollection must have one view', (WidgetTester tester) async { expect(() => ViewCollection(views: const <Widget>[]), throwsAssertionError); }); - testWidgets('ViewAnchor.child does not see surrounding view', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor.child does not see surrounding view', (WidgetTester tester) async { FlutterView? inside; FlutterView? outside; await tester.pumpWidget( @@ -165,7 +166,7 @@ void main() { expect(outside, isNotNull); }); - testWidgets('ViewAnchor layout order', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ViewAnchor layout order', (WidgetTester tester) async { Finder findSpyWidget(int label) { return find.byWidgetPredicate((Widget w) => w is SpyRenderWidget && w.label == label); } @@ -192,7 +193,7 @@ void main() { expect(log, <String>['layout 1', 'layout 3', 'layout 2']); }); - testWidgets('visitChildren of ViewAnchor visits both children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visitChildren of ViewAnchor visits both children', (WidgetTester tester) async { await tester.pumpWidget( ViewAnchor( view: View( @@ -221,7 +222,7 @@ void main() { expect(children, hasLength(1)); }); - testWidgets('visitChildren of ViewCollection visits all children', (WidgetTester tester) async { + testWidgetsWithLeakTracking('visitChildren of ViewCollection visits all children', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: ViewCollection( @@ -267,7 +268,7 @@ void main() { }); group('renderObject getter', () { - testWidgets('ancestors of view see RenderView as renderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors of view see RenderView as renderObject', (WidgetTester tester) async { late BuildContext builderContext; await pumpWidgetWithoutViewWrapper( tester: tester, @@ -289,7 +290,7 @@ void main() { expect(tester.element(find.byType(Builder)).renderObject, renderObject); }); - testWidgets('ancestors of ViewCollection get null for renderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors of ViewCollection get null for renderObject', (WidgetTester tester) async { late BuildContext builderContext; await pumpWidgetWithoutViewWrapper( tester: tester, @@ -317,7 +318,7 @@ void main() { expect(tester.element(find.byType(Builder)).renderObject, isNull); }); - testWidgets('ancestors of a ViewAnchor see the right RenderObject', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ancestors of a ViewAnchor see the right RenderObject', (WidgetTester tester) async { late BuildContext builderContext; await tester.pumpWidget( Builder( @@ -342,7 +343,7 @@ void main() { }); }); - testWidgets('correctly switches between view configurations', (WidgetTester tester) async { + testWidgetsWithLeakTracking('correctly switches between view configurations', (WidgetTester tester) async { await pumpWidgetWithoutViewWrapper( tester: tester, widget: View( @@ -401,7 +402,7 @@ void main() { ), throwsAssertionError); }); - testWidgets('attaches itself correctly', (WidgetTester tester) async { + testWidgetsWithLeakTracking('attaches itself correctly', (WidgetTester tester) async { final Key viewKey = UniqueKey(); late final PipelineOwner parentPipelineOwner; await tester.pumpWidget( diff --git a/packages/flutter/test/widgets/visibility_test.dart b/packages/flutter/test/widgets/visibility_test.dart index cd11376111d50..0b2b6330f30b0 100644 --- a/packages/flutter/test/widgets/visibility_test.dart +++ b/packages/flutter/test/widgets/visibility_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import 'semantics_tester.dart'; @@ -29,7 +30,7 @@ class _TestStateState extends State<TestState> { } void main() { - testWidgets('Visibility', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); final List<String> log = <String>[]; @@ -439,7 +440,7 @@ void main() { semantics.dispose(); }); - testWidgets('Visibility does not force compositing when visible and maintain*', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility does not force compositing when visible and maintain*', (WidgetTester tester) async { await tester.pumpWidget( const Visibility( maintainSize: true, @@ -455,7 +456,7 @@ void main() { expect(tester.layers.last, isA<PictureLayer>()); }); - testWidgets('SliverVisibility does not force compositing when visible and maintain*', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverVisibility does not force compositing when visible and maintain*', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -485,7 +486,7 @@ void main() { expect(tester.layers.last, isA<PictureLayer>()); }); - testWidgets('Visibility.of returns correct value', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility.of returns correct value', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, @@ -518,7 +519,7 @@ void main() { expect(find.text('is visible ? false', skipOffstage: false), findsOneWidget); }); - testWidgets('Visibility.of works when multiple Visibility widgets are in hierarchy', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visibility.of works when multiple Visibility widgets are in hierarchy', (WidgetTester tester) async { bool didChangeDependencies = false; void handleDidChangeDependencies() { didChangeDependencies = true; diff --git a/packages/flutter/test/widgets/wrap_test.dart b/packages/flutter/test/widgets/wrap_test.dart index 1a132ef0255f2..41165288f9bad 100644 --- a/packages/flutter/test/widgets/wrap_test.dart +++ b/packages/flutter/test/widgets/wrap_test.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; void verify(WidgetTester tester, List<Offset> answerKey) { final List<Offset> testAnswers = tester.renderObjectList<RenderBox>(find.byType(SizedBox)).map<Offset>( @@ -14,7 +15,7 @@ void verify(WidgetTester tester, List<Offset> answerKey) { } void main() { - testWidgets('Basic Wrap test (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Basic Wrap test (LTR)', (WidgetTester tester) async { await tester.pumpWidget( const Wrap( textDirection: TextDirection.ltr, @@ -129,7 +130,7 @@ void main() { }); - testWidgets('Basic Wrap test (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Basic Wrap test (RTL)', (WidgetTester tester) async { await tester.pumpWidget( const Wrap( textDirection: TextDirection.rtl, @@ -247,12 +248,12 @@ void main() { }); - testWidgets('Empty wrap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Empty wrap', (WidgetTester tester) async { await tester.pumpWidget(const Center(child: Wrap(alignment: WrapAlignment.center))); expect(tester.renderObject<RenderBox>(find.byType(Wrap)).size, equals(Size.zero)); }); - testWidgets('Wrap alignment (LTR)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap alignment (LTR)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( alignment: WrapAlignment.center, spacing: 5.0, @@ -322,7 +323,7 @@ void main() { ]); }); - testWidgets('Wrap alignment (RTL)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap alignment (RTL)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( alignment: WrapAlignment.center, spacing: 5.0, @@ -392,7 +393,7 @@ void main() { ]); }); - testWidgets('Wrap runAlignment (DOWN)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap runAlignment (DOWN)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( runAlignment: WrapAlignment.center, runSpacing: 5.0, @@ -479,7 +480,7 @@ void main() { }); - testWidgets('Wrap runAlignment (UP)', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap runAlignment (UP)', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( runAlignment: WrapAlignment.center, runSpacing: 5.0, @@ -570,7 +571,7 @@ void main() { }); - testWidgets('Shrink-wrapping Wrap test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Shrink-wrapping Wrap test', (WidgetTester tester) async { await tester.pumpWidget( const Align( alignment: Alignment.topLeft, @@ -620,7 +621,7 @@ void main() { ]); }); - testWidgets('Wrap spacing test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap spacing test', (WidgetTester tester) async { await tester.pumpWidget( const Align( alignment: Alignment.topLeft, @@ -645,7 +646,7 @@ void main() { ]); }); - testWidgets('Vertical Wrap test with spacing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical Wrap test with spacing', (WidgetTester tester) async { await tester.pumpWidget( const Align( alignment: Alignment.topLeft, @@ -704,7 +705,7 @@ void main() { ]); }); - testWidgets('Visual overflow generates a clip', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Visual overflow generates a clip', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( textDirection: TextDirection.ltr, children: <Widget>[ @@ -726,7 +727,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(Wrap)), paints..clipRect()); }); - testWidgets('Hit test children in wrap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Hit test children in wrap', (WidgetTester tester) async { final List<String> log = <String>[]; await tester.pumpWidget(Wrap( @@ -762,14 +763,14 @@ void main() { expect(log, equals(<String>['hit'])); }); - testWidgets('RenderWrap toStringShallow control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderWrap toStringShallow control test', (WidgetTester tester) async { await tester.pumpWidget(const Wrap(alignment: WrapAlignment.center)); final RenderBox wrap = tester.renderObject(find.byType(Wrap)); expect(wrap.toStringShallow(), hasOneLineDescription); }); - testWidgets('RenderWrap toString control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RenderWrap toString control test', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( direction: Axis.vertical, runSpacing: 7.0, @@ -787,7 +788,7 @@ void main() { expect(width, equals(2021)); }); - testWidgets('Wrap baseline control test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap baseline control test', (WidgetTester tester) async { await tester.pumpWidget( const Center( child: Baseline( @@ -815,7 +816,7 @@ void main() { ); }); - testWidgets('Spacing with slight overflow', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Spacing with slight overflow', (WidgetTester tester) async { await tester.pumpWidget(const Wrap( textDirection: TextDirection.ltr, spacing: 10.0, @@ -837,7 +838,7 @@ void main() { ]); }); - testWidgets('Object exactly matches container width', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Object exactly matches container width', (WidgetTester tester) async { await tester.pumpWidget( const Column( children: <Widget>[ @@ -879,7 +880,7 @@ void main() { ]); }); - testWidgets('Wrap can set and update clipBehavior', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Wrap can set and update clipBehavior', (WidgetTester tester) async { await tester.pumpWidget(const Wrap(textDirection: TextDirection.ltr)); final RenderWrap renderObject = tester.allRenderObjects.whereType<RenderWrap>().first; expect(renderObject.clipBehavior, equals(Clip.none)); @@ -888,7 +889,7 @@ void main() { expect(renderObject.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('Horizontal wrap - IntrinsicsHeight', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Horizontal wrap - IntrinsicsHeight', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/48679. await tester.pumpWidget( const Directionality( @@ -920,7 +921,7 @@ void main() { expect(tester.getSize(find.byType(IntrinsicHeight)).height, 2 * 16 + 40); }); - testWidgets('Vertical wrap - IntrinsicsWidth', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Vertical wrap - IntrinsicsWidth', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/48679. await tester.pumpWidget( const Directionality( From 5def6f2bab65ab05f772a8e55ec2fff71822090d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 20:00:09 -0400 Subject: [PATCH 1404/1547] Roll Flutter Engine from 78c1ad249b57 to 7a9409e12fab (8 revisions) (#135266) https://github.com/flutter/engine/compare/78c1ad249b57...7a9409e12fab 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from 0cf83a86c56d to a0928a46b9c8 (19 revisions) (flutter/engine#46164) 2023-09-21 john@johnmccutchan.com Re-enable HardwareBuffer backed Platform Views on Android >= 29 (flutter/engine#46071) 2023-09-21 jonahwilliams@google.com [Impeller] Use final cmd buffer to present drawable. (flutter/engine#46023) 2023-09-21 matanlurey@users.noreply.github.com More Clang Tidy --fix[es] to header files (flutter/engine#46151) 2023-09-21 dkwingsmt@users.noreply.github.com Reland: Enforce the rule of calling FlutterView.Render (#45300) (flutter/engine#45555) 2023-09-21 yjbanov@google.com Revert "[web] fix clicks on merged semantic nodes (#43620)" (flutter/engine#46067) 2023-09-21 matanlurey@users.noreply.github.com Move `git_repo_tools` and `process_fakes` outside of `clang_tidy`. (flutter/engine#46017) 2023-09-21 godofredoc@google.com Remove linux fuchsia from recipes cq. (flutter/engine#46153) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 153324e92fc42..01d0ac34b5307 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -78c1ad249b57164c85468c39491c4f618724ce5d +7a9409e12fab770a86e115ade95ec38d083e63f2 From 9d42ad84ee096eb67deca42ac2962f54d442cbf1 Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Fri, 22 Sep 2023 03:20:23 +0200 Subject: [PATCH 1405/1547] Fix memory leak in NestedScrollViewState. (#135248) --- .../lib/src/widgets/nested_scroll_view.dart | 8 ++ .../test/widgets/nested_scroll_view_test.dart | 121 ++++++++++-------- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/packages/flutter/lib/src/widgets/nested_scroll_view.dart b/packages/flutter/lib/src/widgets/nested_scroll_view.dart index da872cce9cfd7..30ee29f9bfa10 100644 --- a/packages/flutter/lib/src/widgets/nested_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/nested_scroll_view.dart @@ -441,6 +441,7 @@ class NestedScrollViewState extends State<NestedScrollView> { void dispose() { _coordinator!.dispose(); _coordinator = null; + _absorberHandle.dispose(); super.dispose(); } @@ -1620,6 +1621,13 @@ class _NestedOuterBallisticScrollActivity extends BallisticScrollActivity { /// [SliverOverlapAbsorber] to align its children, and which shows sample /// usage for this class. class SliverOverlapAbsorberHandle extends ChangeNotifier { + /// Creates a [SliverOverlapAbsorberHandle]. + SliverOverlapAbsorberHandle() { + if (kFlutterMemoryAllocationsEnabled) { + ChangeNotifier.maybeDispatchObjectCreation(this); + } + } + // Incremented when a RenderSliverOverlapAbsorber takes ownership of this // object, decremented when it releases it. This allows us to find cases where // the same handle is being passed to two render objects. diff --git a/packages/flutter/test/widgets/nested_scroll_view_test.dart b/packages/flutter/test/widgets/nested_scroll_view_test.dart index c4b6e271aa8b5..6527110b86e86 100644 --- a/packages/flutter/test/widgets/nested_scroll_view_test.dart +++ b/packages/flutter/test/widgets/nested_scroll_view_test.dart @@ -9,6 +9,7 @@ import 'package:flutter/gestures.dart' show DragStartBehavior; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; import '../rendering/rendering_tester.dart' show TestClipPaintingContext; @@ -109,7 +110,7 @@ Widget buildTest({ } void main() { - testWidgets('ScrollDirection test', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollDirection test', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/107101 final List<ScrollDirection> receivedResult = <ScrollDirection>[]; const List<ScrollDirection> expectedReverseResult = <ScrollDirection>[ScrollDirection.reverse, ScrollDirection.idle]; @@ -211,7 +212,7 @@ void main() { expect(context.clipBehavior, equals(Clip.antiAlias)); }); - testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView overscroll and release and hold', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(find.text('aaa2'), findsOneWidget); await tester.pump(const Duration(milliseconds: 250)); @@ -234,7 +235,7 @@ void main() { expect(tester.renderObject<RenderBox>(find.byType(AppBar)).size.height, 200.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('NestedScrollView overscroll and release and hold', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView overscroll and release and hold', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(find.text('aaa2'), findsOneWidget); await tester.pump(const Duration(milliseconds: 250)); @@ -259,7 +260,7 @@ void main() { await tester.pump(const Duration(milliseconds: 1000)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('NestedScrollView overscroll and release', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView overscroll and release', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(find.text('aaa2'), findsOneWidget); await tester.pump(const Duration(milliseconds: 500)); @@ -275,7 +276,7 @@ void main() { expect(find.text('aaa2'), findsOneWidget); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('NestedScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView', (WidgetTester tester) async { await tester.pumpWidget(buildTest()); expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa3'), findsNothing); @@ -342,10 +343,11 @@ void main() { ); }); - testWidgets('NestedScrollView with a ScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView with a ScrollController', (WidgetTester tester) async { final ScrollController controller = ScrollController( initialScrollOffset: 50.0, ); + addTearDown(controller.dispose); late double scrollOffset; controller.addListener(() { @@ -419,8 +421,9 @@ void main() { expect(find.text('ddd1'), findsOneWidget); }); - testWidgets('Three NestedScrollViews with one ScrollController', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Three NestedScrollViews with one ScrollController', (WidgetTester tester) async { final TrackingScrollController controller = TrackingScrollController(); + addTearDown(controller.dispose); expect(controller.mostRecentlyUpdatedPosition, isNull); expect(controller.initialScrollOffset, 0.0); @@ -482,7 +485,7 @@ void main() { ); }); - testWidgets('NestedScrollViews with custom physics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollViews with custom physics', (WidgetTester tester) async { await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, child: Localizations( @@ -520,7 +523,7 @@ void main() { expect(point1.dy, greaterThan(point2.dy)); }); - testWidgets('NestedScrollViews respect NeverScrollableScrollPhysics', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollViews respect NeverScrollableScrollPhysics', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/113753 await tester.pumpWidget(Directionality( textDirection: TextDirection.ltr, @@ -561,7 +564,7 @@ void main() { expect(point1, point2); }); - testWidgets('NestedScrollView and internal scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView and internal scrolling', (WidgetTester tester) async { debugDisableShadows = false; const List<String> tabs = <String>['Hello', 'World']; int buildCount = 0; @@ -843,7 +846,7 @@ void main() { debugDisableShadows = true; }); - testWidgets('NestedScrollView and bouncing', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView and bouncing', (WidgetTester tester) async { // This verifies that overscroll bouncing works correctly on iOS. For // example, this checks that if you pull to overscroll, friction is applied; // it also makes sure that if you scroll back the other way, the scroll @@ -946,7 +949,7 @@ void main() { }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); group('NestedScrollViewState exposes inner and outer controllers', () { - testWidgets('Scrolling by less than the outer extent does not scroll the inner body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolling by less than the outer extent does not scroll the inner body', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey, @@ -978,7 +981,7 @@ void main() { expect(globalKey.currentState!.innerController.offset, 0.0); }); - testWidgets('Scrolling by exactly the outer extent does not scroll the inner body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolling by exactly the outer extent does not scroll the inner body', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey, @@ -1010,7 +1013,7 @@ void main() { expect(globalKey.currentState!.innerController.offset, 0.0); }); - testWidgets('Scrolling by greater than the outer extent scrolls the inner body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scrolling by greater than the outer extent scrolls the inner body', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey, @@ -1046,7 +1049,7 @@ void main() { ); }); - testWidgets('Inertia-cancel event does not modify either position.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inertia-cancel event does not modify either position.', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey, @@ -1094,7 +1097,7 @@ void main() { ); }); - testWidgets('scrolling by less than the expanded outer extent does not scroll the inner body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrolling by less than the expanded outer extent does not scroll the inner body', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest(key: globalKey)); @@ -1123,7 +1126,7 @@ void main() { expect(globalKey.currentState!.innerController.offset, 0.0); }); - testWidgets('scrolling by exactly the expanded outer extent does not scroll the inner body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrolling by exactly the expanded outer extent does not scroll the inner body', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest(key: globalKey)); @@ -1152,7 +1155,7 @@ void main() { expect(globalKey.currentState!.innerController.offset, 0.0); }); - testWidgets('scrolling by greater than the expanded outer extent scrolls the inner body', (WidgetTester tester) async { + testWidgetsWithLeakTracking('scrolling by greater than the expanded outer extent scrolls the inner body', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); await tester.pumpWidget(buildTest(key: globalKey)); @@ -1182,11 +1185,12 @@ void main() { expect(globalKey.currentState!.innerController.offset, 50.0); }); - testWidgets( + testWidgetsWithLeakTracking( 'NestedScrollViewState.outerController should correspond to NestedScrollView.controller', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey = GlobalKey(); final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); await tester.pumpWidget(buildTest( controller: scrollController, @@ -1213,7 +1217,7 @@ void main() { ); group('manipulating controllers when', () { - testWidgets('outer: not scrolled, inner: not scrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('outer: not scrolled, inner: not scrolled', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey1 = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey1, @@ -1255,7 +1259,7 @@ void main() { expect(globalKey2.currentState!.outerController.position.pixels, 0.0); }); - testWidgets('outer: not scrolled, inner: scrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('outer: not scrolled, inner: scrolled', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey1 = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey1, @@ -1299,7 +1303,7 @@ void main() { expect(globalKey2.currentState!.outerController.position.pixels, 0.0); }); - testWidgets('outer: scrolled, inner: not scrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('outer: scrolled, inner: not scrolled', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey1 = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey1, @@ -1343,7 +1347,7 @@ void main() { expect(globalKey2.currentState!.outerController.position.pixels, 0.0); }); - testWidgets('outer: scrolled, inner: scrolled', (WidgetTester tester) async { + testWidgetsWithLeakTracking('outer: scrolled, inner: scrolled', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> globalKey1 = GlobalKey(); await tester.pumpWidget(buildTest( key: globalKey1, @@ -1392,7 +1396,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/39963. - testWidgets('NestedScrollView with SliverOverlapAbsorber in or out of the first screen', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView with SliverOverlapAbsorber in or out of the first screen', (WidgetTester tester) async { await tester.pumpWidget(const _TestLayoutExtentIsNegative(1)); await tester.pumpWidget(const _TestLayoutExtentIsNegative(10)); }); @@ -1471,7 +1475,7 @@ void main() { return geometry.paintExtent; } - testWidgets('float', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( floating: true, @@ -1523,7 +1527,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 56.0, visible: true); }); - testWidgets('float expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float expanded', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( floating: true, @@ -1578,7 +1582,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 200.0, visible: true); }); - testWidgets('float with pointer signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float with pointer signal', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( floating: true, @@ -1635,7 +1639,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 56.0, visible: true); }); - testWidgets('snap with pointer signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('snap with pointer signal', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( floating: true, @@ -1689,7 +1693,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 0.0, visible: false); }); - testWidgets('float expanded with pointer signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float expanded with pointer signal', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( floating: true, @@ -1749,7 +1753,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 200.0, visible: true); }); - testWidgets('only snap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('only snap', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); final GlobalKey<NestedScrollViewState> nestedKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( @@ -1884,7 +1888,7 @@ void main() { expect(nestedKey.currentState!.outerController.offset, 56.0); }); - testWidgets('only snap expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('only snap expanded', (WidgetTester tester) async { final GlobalKey appBarKey = GlobalKey(); final GlobalKey<NestedScrollViewState> nestedKey = GlobalKey(); await tester.pumpWidget(buildFloatTest( @@ -2020,7 +2024,7 @@ void main() { expect(nestedKey.currentState!.outerController.offset, 200.0); }); - testWidgets('float pinned', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float pinned', (WidgetTester tester) async { // This configuration should have the same behavior of a pinned app bar. // No floating should happen, and the app bar should persist. final GlobalKey appBarKey = GlobalKey(); @@ -2075,7 +2079,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 56.0, visible: true); }); - testWidgets('float pinned expanded', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float pinned expanded', (WidgetTester tester) async { // Only the expanded portion (flexible space) of the app bar should float // in and out. final GlobalKey appBarKey = GlobalKey(); @@ -2134,7 +2138,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 200.0, visible: true); }); - testWidgets('float pinned with pointer signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float pinned with pointer signal', (WidgetTester tester) async { // This configuration should have the same behavior of a pinned app bar. // No floating should happen, and the app bar should persist. final GlobalKey appBarKey = GlobalKey(); @@ -2194,7 +2198,7 @@ void main() { verifyGeometry(key: appBarKey, paintExtent: 56.0, visible: true); }); - testWidgets('float pinned expanded with pointer signal', (WidgetTester tester) async { + testWidgetsWithLeakTracking('float pinned expanded with pointer signal', (WidgetTester tester) async { // Only the expanded portion (flexible space) of the app bar should float // in and out. final GlobalKey appBarKey = GlobalKey(); @@ -2289,10 +2293,11 @@ void main() { ); } - testWidgets('overscroll, hold for 0 velocity, and release', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overscroll, hold for 0 velocity, and release', (WidgetTester tester) async { // Dragging into an overscroll and holding so that when released, the // ballistic scroll activity has a 0 velocity. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildBallisticTest(controller)); // Last item of the inner scroll view. expect(find.text('Item 49'), findsNothing); @@ -2316,10 +2321,11 @@ void main() { expect(tester.getCenter(find.text('Item 49')).dy, equals(585.0)); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS })); - testWidgets('overscroll, release, and tap', (WidgetTester tester) async { + testWidgetsWithLeakTracking('overscroll, release, and tap', (WidgetTester tester) async { // Tapping while an inner ballistic scroll activity is in progress will // trigger a secondary ballistic scroll activity with a 0 velocity. final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildBallisticTest(controller)); // Last item of the inner scroll view. expect(find.text('Item 49'), findsNothing); @@ -2350,7 +2356,7 @@ void main() { }); // Regression test for https://github.com/flutter/flutter/issues/63978 - testWidgets('Inner _NestedScrollPosition.applyClampedDragUpdate correctly calculates range when in overscroll', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Inner _NestedScrollPosition.applyClampedDragUpdate correctly calculates range when in overscroll', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> nestedScrollView = GlobalKey(); await tester.pumpWidget(MaterialApp( home: Scaffold( @@ -2404,8 +2410,9 @@ void main() { expect(nestedScrollView.currentState!.innerController.position.pixels, 295.0); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS })); - testWidgets('Scroll pointer signal should not cause overscroll.', (WidgetTester tester) async { + testWidgetsWithLeakTracking('Scroll pointer signal should not cause overscroll.', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildTest(controller: controller)); final Offset scrollEventLocation = tester.getCenter(find.byType(NestedScrollView)); @@ -2426,7 +2433,7 @@ void main() { expect(find.text('ddd1'), findsOneWidget); }); - testWidgets('NestedScrollView basic scroll with pointer signal', (WidgetTester tester) async{ + testWidgetsWithLeakTracking('NestedScrollView basic scroll with pointer signal', (WidgetTester tester) async{ await tester.pumpWidget(buildTest()); expect(find.text('aaa2'), findsOneWidget); expect(find.text('aaa3'), findsNothing); @@ -2466,12 +2473,13 @@ void main() { }); // Related to https://github.com/flutter/flutter/issues/64266 - testWidgets( + testWidgetsWithLeakTracking( 'Holding scroll and Scroll pointer signal will update ScrollDirection.forward / ScrollDirection.reverse', (WidgetTester tester) async { ScrollDirection? lastUserScrollingDirection; final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); await tester.pumpWidget(buildTest(controller: controller)); controller.addListener(() { @@ -2503,7 +2511,7 @@ void main() { ); // Regression test for https://github.com/flutter/flutter/issues/72257 - testWidgets('NestedScrollView works well when rebuilding during scheduleWarmUpFrame', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView works well when rebuilding during scheduleWarmUpFrame', (WidgetTester tester) async { bool? isScrolled; final Widget myApp = MaterialApp( home: Scaffold( @@ -2546,8 +2554,9 @@ void main() { }); // Regression test of https://github.com/flutter/flutter/issues/74372 - testWidgets('ScrollPosition can be accessed during `_updatePosition()`', (WidgetTester tester) async { + testWidgetsWithLeakTracking('ScrollPosition can be accessed during `_updatePosition()`', (WidgetTester tester) async { final ScrollController controller = ScrollController(); + addTearDown(controller.dispose); late ScrollPosition position; Widget buildFrame({ScrollPhysics? physics}) { @@ -2592,7 +2601,7 @@ void main() { expect(position.pixels, 0.0); }); - testWidgets("NestedScrollView doesn't crash due to precision error", (WidgetTester tester) async { + testWidgetsWithLeakTracking("NestedScrollView doesn't crash due to precision error", (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/63825 await tester.pumpWidget(MaterialApp( @@ -2639,7 +2648,7 @@ void main() { await tester.pumpAndSettle(); }); - testWidgets('NestedScrollViewCoordinator.pointerScroll dispatches correct scroll notifications', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollViewCoordinator.pointerScroll dispatches correct scroll notifications', (WidgetTester tester) async { int scrollEnded = 0; int scrollStarted = 0; bool isScrolled = false; @@ -2701,7 +2710,7 @@ void main() { expect(scrollEnded, 2); }); - testWidgets('SliverAppBar.medium collapses in NestedScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.medium collapses in NestedScrollView', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> nestedScrollView = GlobalKey(); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 112; @@ -2783,7 +2792,7 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('SliverAppBar.large collapses in NestedScrollView', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverAppBar.large collapses in NestedScrollView', (WidgetTester tester) async { final GlobalKey<NestedScrollViewState> nestedScrollView = GlobalKey(); const double collapsedAppBarHeight = 64; const double expandedAppBarHeight = 152; @@ -2866,7 +2875,7 @@ void main() { expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight); }); - testWidgets('NestedScrollView does not crash when inner scrollable changes while scrolling', (WidgetTester tester) async { + testWidgetsWithLeakTracking('NestedScrollView does not crash when inner scrollable changes while scrolling', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/126454. Widget buildApp({required bool nested}) { final Widget innerScrollable = ListView( @@ -2903,7 +2912,7 @@ void main() { await tester.pumpWidget(buildApp(nested: true)); }); - testWidgets('SliverOverlapInjector asserts when there is no SliverOverlapAbsorber', (WidgetTester tester) async { + testWidgetsWithLeakTracking('SliverOverlapInjector asserts when there is no SliverOverlapAbsorber', (WidgetTester tester) async { Widget buildApp() { return MaterialApp( home: Scaffold( @@ -2997,7 +3006,8 @@ void main() { ) ); } - testWidgets('when headerSliverBuilder is empty', (WidgetTester tester) async { + + testWidgetsWithLeakTracking('when headerSliverBuilder is empty', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/117316 // Regression test for https://github.com/flutter/flutter/issues/46089 // Short body / long body @@ -3015,7 +3025,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('when headerSliverBuilder extent is 0', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when headerSliverBuilder extent is 0', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/79077 // Short body / long body for (final _BodyLength bodyLength in _BodyLength.values) { @@ -3169,7 +3179,7 @@ void main() { } }, variant: TargetPlatformVariant.all()); - testWidgets('With a pinned SliverAppBar', (WidgetTester tester) async { + testWidgetsWithLeakTracking('With a pinned SliverAppBar', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/110956 // Regression test for https://github.com/flutter/flutter/issues/127282 // Regression test for https://github.com/flutter/flutter/issues/32563 @@ -3200,6 +3210,13 @@ void main() { } }); }); + + testWidgetsWithLeakTracking('$SliverOverlapAbsorberHandle dispatches creation in constructor', (WidgetTester widgetTester) async { + await expectLater( + await memoryEvents(() => SliverOverlapAbsorberHandle().dispose(), SliverOverlapAbsorberHandle), + areCreateAndDispose, + ); + }); } double appBarHeight(WidgetTester tester) => tester.getSize(find.byType(AppBar, skipOffstage: false)).height; From 5163d814891a4e87f366e116b0e2c62b4e2d316d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 21:20:25 -0400 Subject: [PATCH 1406/1547] Roll Flutter Engine from 7a9409e12fab to 2a33fdc4be48 (3 revisions) (#135270) https://github.com/flutter/engine/compare/7a9409e12fab...2a33fdc4be48 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from 611f08987be3 to 5b2dae1a9b54 (2 revisions) (flutter/engine#46168) 2023-09-21 matanlurey@users.noreply.github.com Revert #46131, don't store `vkImage`, reset `vkComandPool` synchronously (flutter/engine#46166) 2023-09-21 skia-flutter-autoroll@skia.org Roll Skia from a0928a46b9c8 to 611f08987be3 (2 revisions) (flutter/engine#46165) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 01d0ac34b5307..63d5d9525fd77 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7a9409e12fab770a86e115ade95ec38d083e63f2 +2a33fdc4be488610f9ed40a3999f2a43acef681f From 68d5c1760b32a5835537abc2cfbfd2cafe082781 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 22:14:19 -0400 Subject: [PATCH 1407/1547] Roll Flutter Engine from 2a33fdc4be48 to e726798410af (1 revision) (#135271) https://github.com/flutter/engine/compare/2a33fdc4be48...e726798410af 2023-09-22 dnfield@google.com [Impeller] fail if software backend is chosen and Impeller is enabled on iOS (flutter/engine#46124) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 63d5d9525fd77..1b9485b06d805 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2a33fdc4be488610f9ed40a3999f2a43acef681f +e726798410af24497308f925802c5f4dbeb227b0 From 85e52d4363f8d4d4d0ade48a744e9436f90eb1d8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 21 Sep 2023 23:34:27 -0400 Subject: [PATCH 1408/1547] Roll Flutter Engine from e726798410af to e0fb071ead2f (2 revisions) (#135276) https://github.com/flutter/engine/compare/e726798410af...e0fb071ead2f 2023-09-22 skia-flutter-autoroll@skia.org Roll Dart SDK from eaeca487c944 to 5d33f4c85b82 (1 revision) (flutter/engine#46176) 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 5b2dae1a9b54 to 86454ab4f3de (1 revision) (flutter/engine#46175) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1b9485b06d805..afe018ad32e20 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e726798410af24497308f925802c5f4dbeb227b0 +e0fb071ead2f9dcd266d662a4898ffb39e224aa7 From 0377e80de8ab4283bf0dd90bcf790e335c585098 Mon Sep 17 00:00:00 2001 From: Tomasz Gucio <72562119+tgucio@users.noreply.github.com> Date: Fri, 22 Sep 2023 07:49:06 +0200 Subject: [PATCH 1409/1547] Size CupertinoTextSelectionToolbar to children (#133386) --- .../src/cupertino/text_selection_toolbar.dart | 402 ++++++++++-------- .../test/cupertino/text_field_test.dart | 18 +- .../test/cupertino/text_selection_test.dart | 4 +- .../text_selection_toolbar_test.dart | 44 +- 4 files changed, 253 insertions(+), 215 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart b/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart index ff1bd07c7a3a0..6e89fc6dd5d5e 100644 --- a/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart +++ b/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart @@ -14,20 +14,25 @@ import 'colors.dart'; import 'text_selection_toolbar_button.dart'; import 'theme.dart'; -// Values extracted from https://developer.apple.com/design/resources/. -// The height of the toolbar, including the arrow. -const double _kToolbarHeight = 45.0; +// The radius of the toolbar RRect shape. +// Value extracted from https://developer.apple.com/design/resources/. +const Radius _kToolbarBorderRadius = Radius.circular(8.0); + // Vertical distance between the tip of the arrow and the line of text the arrow // is pointing to. The value used here is eyeballed. const double _kToolbarContentDistance = 8.0; + +// The size of the arrow pointing to the anchor. Eyeballed value. const Size _kToolbarArrowSize = Size(14.0, 7.0); // Minimal padding from tip of the selection toolbar arrow to horizontal edges of the // screen. Eyeballed value. const double _kArrowScreenPadding = 26.0; -// Values extracted from https://developer.apple.com/design/resources/. -const Radius _kToolbarBorderRadius = Radius.circular(8); +// The size and thickness of the chevron icon used for navigating between toolbar pages. +// Eyeballed values. +const double _kToolbarChevronSize = 10.0; +const double _kToolbarChevronThickness = 2.0; // Color was measured from a screenshot of iOS 16.0.2 // TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/41507. @@ -36,9 +41,6 @@ const CupertinoDynamicColor _kToolbarBackgroundColor = CupertinoDynamicColor.wit darkColor: Color(0xFF222222), ); -const double _kToolbarChevronSize = 10; -const double _kToolbarChevronThickness = 2; - // Color was measured from a screenshot of iOS 16.0.2. const CupertinoDynamicColor _kToolbarDividerColor = CupertinoDynamicColor.withBrightness( color: Color(0xFFD6D6D6), @@ -64,8 +66,8 @@ const Duration _kToolbarTransitionDuration = Duration(milliseconds: 125); /// Material-style toolbar. typedef CupertinoToolbarBuilder = Widget Function( BuildContext context, - Offset anchor, - bool isAbove, + Offset anchorAbove, + Offset anchorBelow, Widget child, ); @@ -127,37 +129,23 @@ class CupertinoTextSelectionToolbar extends StatelessWidget { // Builds a toolbar just like the default iOS toolbar, with the right color // background and a rounded cutout with an arrow. - static Widget _defaultToolbarBuilder(BuildContext context, Offset anchor, bool isAbove, Widget child) { - final Widget outputChild = _CupertinoTextSelectionToolbarShape( - anchor: anchor, - isAbove: isAbove, + static Widget _defaultToolbarBuilder( + BuildContext context, + Offset anchorAbove, + Offset anchorBelow, + Widget child, + ) { + return _CupertinoTextSelectionToolbarShape( + anchorAbove: anchorAbove, + anchorBelow: anchorBelow, + shadowColor: CupertinoTheme.brightnessOf(context) == Brightness.light + ? CupertinoColors.black.withOpacity(0.2) + : null, child: ColoredBox( color: _kToolbarBackgroundColor.resolveFrom(context), child: child, ), ); - if (CupertinoTheme.brightnessOf(context) == Brightness.dark) { - return outputChild; - } - return DecoratedBox( - // These shadow values were eyeballed from a screenshot of iOS 16.3.1, as - // light mode didn't appear in the Apple design resources assets linked at - // the top of this file. - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(_kToolbarBorderRadius), - boxShadow: <BoxShadow>[ - BoxShadow( - color: CupertinoColors.black.withOpacity(0.2), - blurRadius: 15.0, - offset: Offset( - 0.0, - isAbove ? 0.0 : _kToolbarArrowSize.height, - ), - ), - ], - ), - child: outputChild, - ); } @override @@ -166,10 +154,6 @@ class CupertinoTextSelectionToolbar extends StatelessWidget { final EdgeInsets mediaQueryPadding = MediaQuery.paddingOf(context); final double paddingAbove = mediaQueryPadding.top + kToolbarScreenPadding; - final double toolbarHeightNeeded = paddingAbove - + _kToolbarContentDistance - + _kToolbarHeight; - final bool fitsAbove = anchorAbove.dy >= toolbarHeightNeeded; // The arrow, which points to the anchor, has some margin so it can't get // too close to the horizontal edges of the screen. @@ -196,11 +180,10 @@ class CupertinoTextSelectionToolbar extends StatelessWidget { delegate: TextSelectionToolbarLayoutDelegate( anchorAbove: anchorAboveAdjusted, anchorBelow: anchorBelowAdjusted, - fitsAbove: fitsAbove, ), child: _CupertinoTextSelectionToolbarContent( - anchor: fitsAbove ? anchorAboveAdjusted : anchorBelowAdjusted, - isAbove: fitsAbove, + anchorAbove: anchorAboveAdjusted, + anchorBelow: anchorBelowAdjusted, toolbarBuilder: toolbarBuilder, children: children, ), @@ -215,30 +198,32 @@ class CupertinoTextSelectionToolbar extends StatelessWidget { // The anchor should be in global coordinates. class _CupertinoTextSelectionToolbarShape extends SingleChildRenderObjectWidget { const _CupertinoTextSelectionToolbarShape({ - required Offset anchor, - required bool isAbove, + required Offset anchorAbove, + required Offset anchorBelow, + Color? shadowColor, super.child, - }) : _anchor = anchor, - _isAbove = isAbove; + }) : _anchorAbove = anchorAbove, + _anchorBelow = anchorBelow, + _shadowColor = shadowColor; - final Offset _anchor; - - // Whether the arrow should point down and be attached to the bottom - // of the toolbar, or point up and be attached to the top of the toolbar. - final bool _isAbove; + final Offset _anchorAbove; + final Offset _anchorBelow; + final Color? _shadowColor; @override _RenderCupertinoTextSelectionToolbarShape createRenderObject(BuildContext context) => _RenderCupertinoTextSelectionToolbarShape( - _anchor, - _isAbove, + _anchorAbove, + _anchorBelow, + _shadowColor, null, ); @override void updateRenderObject(BuildContext context, _RenderCupertinoTextSelectionToolbarShape renderObject) { renderObject - ..anchor = _anchor - ..isAbove = _isAbove; + ..anchorAbove = _anchorAbove + ..anchorBelow = _anchorBelow + ..shadowColor = _shadowColor; } } @@ -252,34 +237,47 @@ class _CupertinoTextSelectionToolbarShape extends SingleChildRenderObjectWidget // on the necessary side. class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { _RenderCupertinoTextSelectionToolbarShape( - this._anchor, - this._isAbove, + this._anchorAbove, + this._anchorBelow, + this._shadowColor, super.child, ); @override bool get isRepaintBoundary => true; - Offset get anchor => _anchor; - Offset _anchor; - set anchor(Offset value) { - if (value == _anchor) { + Offset get anchorAbove => _anchorAbove; + Offset _anchorAbove; + set anchorAbove(Offset value) { + if (value == _anchorAbove) { return; } - _anchor = value; + _anchorAbove = value; markNeedsLayout(); } - bool get isAbove => _isAbove; - bool _isAbove; - set isAbove(bool value) { - if (_isAbove == value) { + Offset get anchorBelow => _anchorBelow; + Offset _anchorBelow; + set anchorBelow(Offset value) { + if (value == _anchorBelow) { return; } - _isAbove = value; + _anchorBelow = value; markNeedsLayout(); } + Color? get shadowColor => _shadowColor; + Color? _shadowColor; + set shadowColor(Color? value) { + if (value == _shadowColor) { + return; + } + _shadowColor = value; + markNeedsPaint(); + } + + bool get isAbove => anchorAbove.dy >= (child?.size.height ?? 0.0) - _kToolbarArrowSize.height * 2; + @override void performLayout() { final RenderBox? child = this.child; @@ -287,26 +285,21 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { return; } - // The child is tall enough to have the arrow clipped out of it on both sides - // top and bottom. Since _kToolbarHeight includes the height of one arrow, the - // total height that the child is given is that plus one more arrow height. - // The extra height on the opposite side of the arrow will be clipped out. By - // using this approach, the buttons don't need any special padding that - // depends on isAbove. - final BoxConstraints heightConstraint = BoxConstraints( - minHeight: _kToolbarHeight + _kToolbarArrowSize.height, - maxHeight: _kToolbarHeight + _kToolbarArrowSize.height, + final BoxConstraints enforcedConstraint = BoxConstraints( minWidth: _kToolbarArrowSize.width + _kToolbarBorderRadius.x * 2, ).enforce(constraints.loosen()); + child.layout(enforcedConstraint, parentUsesSize: true); - child.layout(heightConstraint, parentUsesSize: true); - + // The buttons are padded on both top and bottom sufficiently to have + // the arrow clipped out of it on either side. By + // using this approach, the buttons don't need any special padding that + // depends on isAbove. // The height of one arrow will be clipped off of the child, so adjust the // size and position to remove that piece from the layout. final BoxParentData childParentData = child.parentData! as BoxParentData; childParentData.offset = Offset( 0.0, - _isAbove ? -_kToolbarArrowSize.height : 0.0, + isAbove ? -_kToolbarArrowSize.height : 0.0, ); size = Size( child.size.width, @@ -314,6 +307,13 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { ); } + // Returns the RRect inside which the child is painted. + RRect _shapeRRect(RenderBox child) { + final Rect rect = Offset(0.0, _kToolbarArrowSize.height) + & Size(child.size.width, child.size.height - _kToolbarArrowSize.height * 2); + return RRect.fromRectAndRadius(rect, _kToolbarBorderRadius).scaleRadii(); + } + // Adds the given `rrect` to the current `path`, starting from the last point // in `path` and ends after the last corner of the rrect (closest corner to // `startAngle` in the counterclockwise direction), without closing the path. @@ -328,7 +328,7 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { // added, then this method returns the mutated path without closing it. static Path _addRRectToPath(Path path, RRect rrect, { required double startAngle }) { const double halfPI = math.pi / 2; - assert(startAngle % halfPI == 0); + assert(startAngle % halfPI == 0.0); final Rect rect = rrect.outerRect; final List<(Offset, Radius)> rrectCorners = <(Offset, Radius)>[ @@ -351,12 +351,8 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { return path; } - // The path is described in the toolbar's coordinate system. - Path _clipPath(RenderBox child) { - final Rect rect = Offset(0.0, _isAbove ? 0 : _kToolbarArrowSize.height) - & Size(size.width, size.height - _kToolbarArrowSize.height); - final RRect rrect = RRect.fromRectAndRadius(rect, _kToolbarBorderRadius).scaleRadii(); - + // The path is described in the toolbar child's coordinate system. + Path _clipPath(RenderBox child, RRect rrect) { final Path path = Path(); // If there isn't enough width for the arrow + radii, ignore the arrow. // Because of the constraints we gave children in performLayout, this should @@ -366,7 +362,7 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { return path..addRRect(rrect); } - final Offset localAnchor = globalToLocal(_anchor); + final Offset localAnchor = globalToLocal(isAbove ? _anchorAbove : _anchorBelow); final double arrowTipX = clampDouble( localAnchor.dx, _kToolbarBorderRadius.x + _kToolbarArrowSize.width / 2, @@ -374,18 +370,22 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { ); // Draw the path clockwise, starting from the beginning side of the arrow. - if (_isAbove) { + if (isAbove) { + final double arrowBaseY = child.size.height - _kToolbarArrowSize.height; + final double arrowTipY = child.size.height; path - ..moveTo(arrowTipX + _kToolbarArrowSize.width / 2, rect.bottom) // right side of the arrow triangle - ..lineTo(arrowTipX, rect.bottom + _kToolbarArrowSize.height) // The tip of the arrow - ..lineTo(arrowTipX - _kToolbarArrowSize.width / 2, rect.bottom); // left side of the arrow triangle + ..moveTo(arrowTipX + _kToolbarArrowSize.width / 2, arrowBaseY) // right side of the arrow triangle + ..lineTo(arrowTipX, arrowTipY) // The tip of the arrow + ..lineTo(arrowTipX - _kToolbarArrowSize.width / 2, arrowBaseY); // left side of the arrow triangle } else { + final double arrowBaseY = _kToolbarArrowSize.height; + const double arrowTipY = 0.0; path - ..moveTo(arrowTipX - _kToolbarArrowSize.width / 2, rect.top) // right side of the arrow triangle - ..lineTo(arrowTipX, rect.top) // The tip of the arrow - ..lineTo(arrowTipX + _kToolbarArrowSize.width / 2, rect.top); // left side of the arrow triangle + ..moveTo(arrowTipX - _kToolbarArrowSize.width / 2, arrowBaseY) // right side of the arrow triangle + ..lineTo(arrowTipX, arrowTipY) // The tip of the arrow + ..lineTo(arrowTipX + _kToolbarArrowSize.width / 2, arrowBaseY); // left side of the arrow triangle } - final double startAngle = _isAbove ? math.pi / 2 : -math.pi / 2; + final double startAngle = isAbove ? math.pi / 2 : -math.pi / 2; return _addRRectToPath(path, rrect, startAngle: startAngle)..close(); } @@ -395,12 +395,34 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { if (child == null) { return; } + + final BoxParentData childParentData = child.parentData! as BoxParentData; + + final RRect rrect = _shapeRRect(child); + final Path clipPath = _clipPath(child, rrect); + + // If configured, paint the shadow beneath the shape. + if (_shadowColor != null) { + final BoxShadow boxShadow = BoxShadow( + color: _shadowColor!, + blurRadius: 15.0, + ); + final RRect shadowRRect = RRect.fromLTRBR( + rrect.left, + rrect.top, + rrect.right, + rrect.bottom + _kToolbarArrowSize.height, + _kToolbarBorderRadius, + ).shift(offset + childParentData.offset + boxShadow.offset); + context.canvas.drawRRect(shadowRRect, boxShadow.toPaint()); + } + _clipPathLayer.layer = context.pushClipPath( needsCompositing, - offset, - Offset.zero & size, - _clipPath(child), - super.paint, + offset + childParentData.offset, + Offset.zero & child.size, + clipPath, + (PaintingContext innerContext, Offset innerOffset) => innerContext.paintChild(child, innerOffset), oldLayer: _clipPathLayer.layer, ); } @@ -434,21 +456,27 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { ..style = PaintingStyle.stroke; final BoxParentData childParentData = child.parentData! as BoxParentData; - context.canvas.drawPath(_clipPath(child).shift(offset + childParentData.offset), debugPaint); + final Path clipPath = _clipPath(child, _shapeRRect(child)); + context.canvas.drawPath(clipPath.shift(offset + childParentData.offset), debugPaint); return true; }()); } @override bool hitTestChildren(BoxHitTestResult result, { required Offset position }) { + final RenderBox? child = this.child; + if (child == null) { + return false; + } + // Positions outside of the clipped area of the child are not counted as // hits. - final BoxParentData childParentData = child!.parentData! as BoxParentData; + final BoxParentData childParentData = child.parentData! as BoxParentData; final Rect hitBox = Rect.fromLTWH( childParentData.offset.dx, childParentData.offset.dy + _kToolbarArrowSize.height, - child!.size.width, - child!.size.height - _kToolbarArrowSize.height * 2, + child.size.width, + child.size.height - _kToolbarArrowSize.height * 2, ); if (!hitBox.contains(position)) { return false; @@ -465,15 +493,15 @@ class _RenderCupertinoTextSelectionToolbarShape extends RenderShiftedBox { // The anchor should be in global coordinates. class _CupertinoTextSelectionToolbarContent extends StatefulWidget { const _CupertinoTextSelectionToolbarContent({ - required this.anchor, - required this.isAbove, + required this.anchorAbove, + required this.anchorBelow, required this.toolbarBuilder, required this.children, }) : assert(children.length > 0); - final Offset anchor; + final Offset anchorAbove; + final Offset anchorBelow; final List<Widget> children; - final bool isAbove; final CupertinoToolbarBuilder toolbarBuilder; @override @@ -564,26 +592,48 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel super.dispose(); } - Widget _createChevron({required bool isLeft}) { - final Color color = _kToolbarTextColor.resolveFrom(context); - - return IgnorePointer( - child: Center( - // If widthFactor is not set to 0, the button is given unbounded width. - widthFactor: 0, - child: CustomPaint( - painter: isLeft - ? _LeftCupertinoChevronPainter(color: color) - : _RightCupertinoChevronPainter(color: color), - size: const Size.square(_kToolbarChevronSize), + @override + Widget build(BuildContext context) { + final Color chevronColor = _kToolbarTextColor.resolveFrom(context); + + // Wrap the children and the chevron painters in Center with widthFactor + // and heightFactor of 1.0 so _CupertinoTextSelectionToolbarItems can get + // the natural size of the buttons and then expand vertically as needed. + final Widget backButton = Center( + widthFactor: 1.0, + heightFactor: 1.0, + child: CupertinoTextSelectionToolbarButton( + onPressed: _handlePreviousPage, + child: IgnorePointer( + child: CustomPaint( + painter: _LeftCupertinoChevronPainter(color: chevronColor), + size: const Size.square(_kToolbarChevronSize), + ), ), ), ); - } + final Widget nextButton = Center( + widthFactor: 1.0, + heightFactor: 1.0, + child: CupertinoTextSelectionToolbarButton( + onPressed: _handleNextPage, + child: IgnorePointer( + child: CustomPaint( + painter: _RightCupertinoChevronPainter(color: chevronColor), + size: const Size.square(_kToolbarChevronSize), + ), + ), + ), + ); + final List<Widget> children = widget.children.map((Widget child) { + return Center( + widthFactor: 1.0, + heightFactor: 1.0, + child: child, + ); + }).toList(); - @override - Widget build(BuildContext context) { - return widget.toolbarBuilder(context, widget.anchor, widget.isAbove, FadeTransition( + return widget.toolbarBuilder(context, widget.anchorAbove, widget.anchorBelow, FadeTransition( opacity: _controller, child: AnimatedSize( duration: _kToolbarTransitionDuration, @@ -593,17 +643,11 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel child: _CupertinoTextSelectionToolbarItems( key: _toolbarItemsKey, page: _page, - backButton: CupertinoTextSelectionToolbarButton( - onPressed: _handlePreviousPage, - child: _createChevron(isLeft: true), - ), + backButton: backButton, dividerColor: _kToolbarDividerColor.resolveFrom(context), dividerWidth: 1.0 / MediaQuery.devicePixelRatioOf(context), - nextButton: CupertinoTextSelectionToolbarButton( - onPressed: _handleNextPage, - child: _createChevron(isLeft: false), - ), - children: widget.children, + nextButton: nextButton, + children: children, ), ), ), @@ -633,7 +677,7 @@ abstract class _CupertinoChevronPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { - assert(size.height == size.width, 'size must have the same height and width'); + assert(size.height == size.width, 'size must have the same height and width: $size'); final double iconSize = size.height; @@ -893,10 +937,6 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container return newChild; } - bool _isSlottedChild(RenderBox child) { - return child == _backButton || child == _nextButton; - } - int _page; int get page => _page; set page(int value) { @@ -946,66 +986,71 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container return; } + // First pass: determine the height of the tallest child. + double greatestHeight = 0.0; + visitChildren((RenderObject renderObjectChild) { + final RenderBox child = renderObjectChild as RenderBox; + final double childHeight = child.getMaxIntrinsicHeight(constraints.maxWidth); + if (childHeight > greatestHeight) { + greatestHeight = childHeight; + } + }); + // Layout slotted children. - _backButton!.layout(constraints.loosen(), parentUsesSize: true); - _nextButton!.layout(constraints.loosen(), parentUsesSize: true); + final BoxConstraints slottedConstraints = BoxConstraints( + maxWidth: constraints.maxWidth, + minHeight: greatestHeight, + maxHeight: greatestHeight, + ); + _backButton!.layout(slottedConstraints, parentUsesSize: true); + _nextButton!.layout(slottedConstraints, parentUsesSize: true); - final double subsequentPageButtonsWidth = - _backButton!.size.width + _nextButton!.size.width; + final double subsequentPageButtonsWidth = _backButton!.size.width + _nextButton!.size.width; double currentButtonPosition = 0.0; late double toolbarWidth; // The width of the whole widget. - late double greatestHeight = 0.0; late double firstPageWidth; int currentPage = 0; int i = -1; visitChildren((RenderObject renderObjectChild) { i++; final RenderBox child = renderObjectChild as RenderBox; - final ToolbarItemsParentData childParentData = - child.parentData! as ToolbarItemsParentData; + final ToolbarItemsParentData childParentData = child.parentData! as ToolbarItemsParentData; childParentData.shouldPaint = false; // Skip slotted children and children on pages after the visible page. - if (_isSlottedChild(child) || currentPage > _page) { + if (child == _backButton || child == _nextButton || currentPage > _page) { return; } - double paginationButtonsWidth = 0.0; - if (currentPage == 0) { - // If this is the last child, it's ok to fit without a forward button. - // Note childCount doesn't include slotted children which come before the list ones. - paginationButtonsWidth = - i == childCount + 1 ? 0.0 : _nextButton!.size.width; - } else { - paginationButtonsWidth = subsequentPageButtonsWidth; - } + // If this is the last child on the first page, it's ok to fit without a forward button. + // Note childCount doesn't include slotted children which come before the list ones. + double paginationButtonsWidth = currentPage == 0 + ? i == childCount + 1 ? 0.0 : _nextButton!.size.width + : subsequentPageButtonsWidth; // The width of the menu is set by the first page. child.layout( - BoxConstraints.loose(Size( - (currentPage == 0 ? constraints.maxWidth : firstPageWidth) - paginationButtonsWidth, - constraints.maxHeight, - )), + BoxConstraints( + maxWidth: (currentPage == 0 ? constraints.maxWidth : firstPageWidth) - paginationButtonsWidth, + minHeight: greatestHeight, + maxHeight: greatestHeight, + ), parentUsesSize: true, ); - greatestHeight = child.size.height > greatestHeight - ? child.size.height - : greatestHeight; - // If this child causes the current page to overflow, move to the next // page and relayout the child. - final double currentWidth = - currentButtonPosition + paginationButtonsWidth + child.size.width; + final double currentWidth = currentButtonPosition + paginationButtonsWidth + child.size.width; if (currentWidth > constraints.maxWidth) { currentPage++; currentButtonPosition = _backButton!.size.width + dividerWidth; paginationButtonsWidth = _backButton!.size.width + _nextButton!.size.width; child.layout( - BoxConstraints.loose(Size( - firstPageWidth - paginationButtonsWidth, - constraints.maxHeight, - )), + BoxConstraints( + maxWidth: firstPageWidth - paginationButtonsWidth, + minHeight: greatestHeight, + maxHeight: greatestHeight, + ), parentUsesSize: true, ); } @@ -1026,10 +1071,8 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container // Position page nav buttons. if (currentPage > 0) { - final ToolbarItemsParentData nextButtonParentData = - _nextButton!.parentData! as ToolbarItemsParentData; - final ToolbarItemsParentData backButtonParentData = - _backButton!.parentData! as ToolbarItemsParentData; + final ToolbarItemsParentData nextButtonParentData = _nextButton!.parentData! as ToolbarItemsParentData; + final ToolbarItemsParentData backButtonParentData = _backButton!.parentData! as ToolbarItemsParentData; // The forward button only shows when there's a page after this one. if (page != currentPage) { nextButtonParentData.offset = Offset(toolbarWidth, 0.0); @@ -1043,16 +1086,16 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container // already been taken care of when laying out the children to // accommodate the back button. } - - // Update previous/next page values so that we can check in the horizontal - // drag gesture callback if it's possible to navigate. - hasNextPage = page != currentPage; - hasPreviousPage = page > 0; } else { // No divider for the next button when there's only one page. toolbarWidth -= dividerWidth; } + // Update previous/next page values so that we can check in the horizontal + // drag gesture callback if it's possible to navigate. + hasNextPage = page != currentPage; + hasPreviousPage = page > 0; + size = constraints.constrain(Size(toolbarWidth, greatestHeight)); } @@ -1093,8 +1136,7 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container if (child == null) { return false; } - final ToolbarItemsParentData childParentData = - child.parentData! as ToolbarItemsParentData; + final ToolbarItemsParentData childParentData = child.parentData! as ToolbarItemsParentData; if (!childParentData.shouldPaint) { return false; } diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index df3001ce6ce60..fe4a90fc084ba 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -6837,7 +6837,7 @@ void main() { includes: <Offset> [ // Expected center of the arrow. The arrow should stay clear of // the edges of the selection toolbar. - Offset(26.0, bottomLeftSelectionPosition.dy + 7.0 + 8.0 + 0.1), + Offset(26.0, bottomLeftSelectionPosition.dy + 8.0 + 0.1), ], ), ), @@ -6847,10 +6847,10 @@ void main() { find.byType(CupertinoTextSelectionToolbar), paints..clipPath( pathMatcher: PathBoundsMatcher( - topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 7 + 8, epsilon: 0.01), + topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8, epsilon: 0.01), leftMatcher: moreOrLessEquals(8), rightMatcher: lessThanOrEqualTo(400 - 8), - bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8 + 45, epsilon: 0.01), + bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8 + 44, epsilon: 0.01), ), ), ); @@ -6898,7 +6898,7 @@ void main() { ], includes: <Offset> [ // Expected center of the arrow. - Offset(400 - 26.0, bottomLeftSelectionPosition.dy + 7 + 8 + 0.1), + Offset(400 - 26.0, bottomLeftSelectionPosition.dy + 8 + 0.1), ], ), ), @@ -6908,9 +6908,9 @@ void main() { find.byType(CupertinoTextSelectionToolbar), paints..clipPath( pathMatcher: PathBoundsMatcher( - topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 7 + 8, epsilon: 0.01), + topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8, epsilon: 0.01), rightMatcher: moreOrLessEquals(400.0 - 8), - bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8 + 45, epsilon: 0.01), + bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy + 8 + 44, epsilon: 0.01), leftMatcher: greaterThanOrEqualTo(8), ), ), @@ -6963,7 +6963,7 @@ void main() { paints..clipPath( pathMatcher: PathBoundsMatcher( bottomMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy - 8 - lineHeight, epsilon: 0.01), - topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy - 8 - lineHeight - 45, epsilon: 0.01), + topMatcher: moreOrLessEquals(bottomLeftSelectionPosition.dy - 8 - lineHeight - 44, epsilon: 0.01), rightMatcher: lessThanOrEqualTo(400 - 8), leftMatcher: greaterThanOrEqualTo(8), ), @@ -7032,7 +7032,7 @@ void main() { paints..clipPath( pathMatcher: PathBoundsMatcher( bottomMatcher: moreOrLessEquals(selectionPosition.dy - 8 - lineHeight, epsilon: 0.01), - topMatcher: moreOrLessEquals(selectionPosition.dy - 8 - lineHeight - 45, epsilon: 0.01), + topMatcher: moreOrLessEquals(selectionPosition.dy - 8 - lineHeight - 44, epsilon: 0.01), rightMatcher: lessThanOrEqualTo(400 - 8), leftMatcher: greaterThanOrEqualTo(8), ), @@ -7105,7 +7105,7 @@ void main() { paints..clipPath( pathMatcher: PathBoundsMatcher( bottomMatcher: moreOrLessEquals(selectionPosition.dy - 8 - lineHeight, epsilon: 0.01), - topMatcher: moreOrLessEquals(selectionPosition.dy - 8 - lineHeight - 45, epsilon: 0.01), + topMatcher: moreOrLessEquals(selectionPosition.dy - 8 - lineHeight - 44, epsilon: 0.01), rightMatcher: lessThanOrEqualTo(400 - 8), leftMatcher: greaterThanOrEqualTo(8), ), diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart index 53be97f0d2486..31843d7e5f42b 100644 --- a/packages/flutter/test/cupertino/text_selection_test.dart +++ b/packages/flutter/test/cupertino/text_selection_test.dart @@ -671,8 +671,8 @@ void main() { final Offset textFieldOffset = tester.getTopLeft(find.byType(CupertinoTextField)); - // 7.0 + 45.0 + 8.0 - 8.0 = _kToolbarArrowSize + _kToolbarHeight + _kToolbarContentDistance - padding - expect(selectionOffset.dy + 7.0 + 45.0 + 8.0 - 8.0, equals(textFieldOffset.dy)); + // 7.0 + 44.0 + 8.0 - 8.0 = _kToolbarArrowSize + text_button_height + _kToolbarContentDistance - padding + expect(selectionOffset.dy + 7.0 + 44.0 + 8.0 - 8.0, equals(textFieldOffset.dy)); }, skip: isBrowser, // [intended] the selection menu isn't required by web variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }), diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart index 5a7e4fff35faa..2de48850c03a8 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart @@ -12,7 +12,7 @@ import '../widgets/editable_text_utils.dart' show textOffsetToPosition; // These constants are copied from cupertino/text_selection_toolbar.dart. const double _kArrowScreenPadding = 26.0; const double _kToolbarContentDistance = 8.0; -const double _kToolbarHeight = 45.0; +const Size _kToolbarArrowSize = Size(14.0, 7.0); // A custom text selection menu that just displays a single custom button. class _CustomCupertinoTextSelectionControls extends CupertinoTextSelectionControls { @@ -271,7 +271,7 @@ void main() { testWidgetsWithLeakTracking('positions itself at anchorAbove if it fits', (WidgetTester tester) async { late StateSetter setState; - const double height = _kToolbarHeight; + const double height = 50.0; const double anchorBelowY = 500.0; double anchorAboveY = 0.0; const double paddingAbove = 12.0; @@ -332,7 +332,7 @@ void main() { }); await tester.pump(); toolbarY = tester.getTopLeft(findToolbar()).dy; - expect(toolbarY, equals(anchorAboveY - height - _kToolbarContentDistance)); + expect(toolbarY, equals(anchorAboveY - height + _kToolbarArrowSize.height - _kToolbarContentDistance)); }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. testWidgetsWithLeakTracking('can create and use a custom toolbar', (WidgetTester tester) async { @@ -429,7 +429,7 @@ void main() { testWidgetsWithLeakTracking('draws a shadow below the toolbar in light mode', (WidgetTester tester) async { late StateSetter setState; - const double height = _kToolbarHeight; + const double height = 50.0; double anchorAboveY = 0.0; await tester.pumpWidget( @@ -468,20 +468,15 @@ void main() { ), ); - // When the toolbar is below the content, the shadow hangs below the entire - // toolbar. - final Finder finder = find.descendant( - of: find.byType(CupertinoTextSelectionToolbar), - matching: find.byType(DecoratedBox), + final double dividerWidth = 1.0 / tester.view.devicePixelRatio; + + expect( + find.byType(CupertinoTextSelectionToolbar), + paints..rrect( + rrect: RRect.fromLTRBR(8.0, 515.0, 158.0 + 2 * dividerWidth, 558.0, const Radius.circular(8.0)), + color: const Color(0x33000000), + ), ); - expect(finder, findsOneWidget); - DecoratedBox decoratedBox = tester.widget(finder.first); - BoxDecoration boxDecoration = decoratedBox.decoration as BoxDecoration; - List<BoxShadow>? shadows = boxDecoration.boxShadow; - expect(shadows, isNotNull); - expect(shadows, hasLength(1)); - BoxShadow shadow = boxDecoration.boxShadow!.first; - expect(shadow.offset.dy, equals(7.0)); // When the toolbar is above the content, the shadow sits around the arrow // with no offset. @@ -489,12 +484,13 @@ void main() { anchorAboveY = 80.0; }); await tester.pump(); - decoratedBox = tester.widget(finder.first); - boxDecoration = decoratedBox.decoration as BoxDecoration; - shadows = boxDecoration.boxShadow; - expect(shadows, isNotNull); - expect(shadows, hasLength(1)); - shadow = boxDecoration.boxShadow!.first; - expect(shadow.offset.dy, equals(0.0)); + + expect( + find.byType(CupertinoTextSelectionToolbar), + paints..rrect( + rrect: RRect.fromLTRBR(8.0, 29.0, 158.0 + 2 * dividerWidth, 72.0, const Radius.circular(8.0)), + color: const Color(0x33000000), + ), + ); }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. } From 2def951924f7a74fd0fa9ad2ba21804321a7a737 Mon Sep 17 00:00:00 2001 From: Daco Harkes <dacoharkes@google.com> Date: Fri, 22 Sep 2023 08:07:06 +0200 Subject: [PATCH 1410/1547] Reland "Native assets support for Linux" (#135097) Reland of #134031. (Reverted in #135069.) Contains the fix for b/301051367 together with cl/567233346. Support for FFI calls with `@Native external` functions through Native assets on Linux. This enables bundling native code without any build-system boilerplate code. For more info see: * https://github.com/flutter/flutter/issues/129757 ### Implementation details for Linux. Mainly follows the design of https://github.com/flutter/flutter/pull/130494. Some differences are: * Linux does not support cross compiling or compiling for multiple architectures, so this has not been implemented. * Linux has no add2app. The assets copying is done in the install-phase of the CMake build of a flutter app. CMake requires the native assets folder to exist, so we create it also when the feature is disabled or there are no assets. ### Tests This PR adds new tests to cover the various use cases. * packages/flutter_tools/test/general.shard/linux/native_assets_test.dart * Unit tests the Linux-specific part of building native assets. It also extends various existing tests: * packages/flutter_tools/test/integration.shard/native_assets_test.dart * Runs (incl hot reload/hot restart), builds, builds frameworks for Linux and flutter-tester. --- .ci.yaml | 24 +- .../flutter_tools/lib/src/build_info.dart | 4 + .../build_system/targets/native_assets.dart | 27 +- .../lib/src/linux/build_linux.dart | 2 + .../lib/src/linux/native_assets.dart | 238 +++++++++++ .../cmake_native_assets_migration.dart | 65 +++ .../flutter_tools/lib/src/native_assets.dart | 27 +- .../lib/src/test/test_compiler.dart | 49 ++- .../app_shared/linux.tmpl/CMakeLists.txt.tmpl | 6 + .../linux/native_assets_test.dart | 374 ++++++++++++++++++ .../cmake_project_migration_test.dart | 127 ++++++ .../integration.shard/native_assets_test.dart | 30 +- .../transition_test_utils.dart | 9 +- 13 files changed, 944 insertions(+), 38 deletions(-) create mode 100644 packages/flutter_tools/lib/src/linux/native_assets.dart create mode 100644 packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart create mode 100644 packages/flutter_tools/test/general.shard/linux/native_assets_test.dart diff --git a/.ci.yaml b/.ci.yaml index b685889056f5d..7c00866d0cd6c 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -952,8 +952,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "1_4" @@ -976,8 +978,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "2_4" @@ -1000,8 +1004,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "3_4" @@ -1024,8 +1030,10 @@ targets: {"dependency": "android_sdk", "version": "version:33v6"}, {"dependency": "chrome_and_driver", "version": "version:117.0"}, {"dependency": "clang", "version": "git_revision:5d5aba78dbbee75508f01bcaa69aedb2ab79065a"}, - {"dependency": "open_jdk", "version": "version:11"}, - {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"} + {"dependency": "cmake", "version": "build_id:8787856497187628321"}, + {"dependency": "goldctl", "version": "git_revision:f808dcff91b221ae313e540c09d79696cd08b8de"}, + {"dependency": "ninja", "version": "version:1.9.0"}, + {"dependency": "open_jdk", "version": "version:11"} ] shard: tool_integration_tests subshard: "4_4" diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index b084efeddf185..b99d5f6effa45 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -47,6 +47,7 @@ class BuildInfo { this.packageConfig = PackageConfig.empty, this.initializeFromDill, this.assumeInitializeFromDillUpToDate = false, + this.buildNativeAssets = true, }) : extraFrontEndOptions = extraFrontEndOptions ?? const <String>[], extraGenSnapshotOptions = extraGenSnapshotOptions ?? const <String>[], fileSystemRoots = fileSystemRoots ?? const <String>[], @@ -188,6 +189,9 @@ class BuildInfo { /// and skips the check and potential invalidation of files. final bool assumeInitializeFromDillUpToDate; + /// If set, builds native assets with `build.dart` from all packages. + final bool buildNativeAssets; + static const BuildInfo debug = BuildInfo(BuildMode.debug, null, trackWidgetCreation: true, treeShakeIcons: false); static const BuildInfo profile = BuildInfo(BuildMode.profile, null, treeShakeIcons: kIconTreeShakerEnabledDefault); static const BuildInfo jitRelease = BuildInfo(BuildMode.jitRelease, null, treeShakeIcons: kIconTreeShakerEnabledDefault); diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index 6e73882927f99..c92c1d6949581 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -12,6 +12,7 @@ import '../../base/platform.dart'; import '../../build_info.dart'; import '../../dart/package_map.dart'; import '../../ios/native_assets.dart'; +import '../../linux/native_assets.dart'; import '../../macos/native_assets.dart'; import '../../macos/xcode.dart'; import '../../native_assets.dart'; @@ -118,6 +119,21 @@ class NativeAssets extends Target { fileSystem: fileSystem, buildRunner: buildRunner, ); + case TargetPlatform.linux_arm64: + case TargetPlatform.linux_x64: + final String? environmentBuildMode = environment.defines[kBuildMode]; + if (environmentBuildMode == null) { + throw MissingDefineException(kBuildMode, name); + } + final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); + (_, dependencies) = await buildNativeAssetsLinux( + targetPlatform: targetPlatform, + buildMode: buildMode, + projectUri: projectUri, + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); case TargetPlatform.tester: if (const LocalPlatform().isMacOS) { (_, dependencies) = await buildNativeAssetsMacOS( @@ -129,6 +145,15 @@ class NativeAssets extends Target { buildRunner: buildRunner, flutterTester: true, ); + } else if (const LocalPlatform().isLinux) { + (_, dependencies) = await buildNativeAssetsLinux( + buildMode: BuildMode.debug, + projectUri: projectUri, + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + flutterTester: true, + ); } else { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 // Write the file we claim to have in the [outputs]. @@ -142,8 +167,6 @@ class NativeAssets extends Target { case TargetPlatform.android: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: - case TargetPlatform.linux_arm64: - case TargetPlatform.linux_x64: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 diff --git a/packages/flutter_tools/lib/src/linux/build_linux.dart b/packages/flutter_tools/lib/src/linux/build_linux.dart index 410416aa63062..1bcf07361fd65 100644 --- a/packages/flutter_tools/lib/src/linux/build_linux.dart +++ b/packages/flutter_tools/lib/src/linux/build_linux.dart @@ -17,6 +17,7 @@ import '../convert.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; +import '../migrations/cmake_native_assets_migration.dart'; // Matches the following error and warning patterns: // - <file path>:<line>:<column>: (fatal) error: <error...> @@ -45,6 +46,7 @@ Future<void> buildLinux( final List<ProjectMigrator> migrators = <ProjectMigrator>[ CmakeCustomCommandMigration(linuxProject, logger), + CmakeNativeAssetsMigration(linuxProject, 'linux', logger), ]; final ProjectMigration migration = ProjectMigration(migrators); diff --git a/packages/flutter_tools/lib/src/linux/native_assets.dart b/packages/flutter_tools/lib/src/linux/native_assets.dart new file mode 100644 index 0000000000000..a9dcb334d870f --- /dev/null +++ b/packages/flutter_tools/lib/src/linux/native_assets.dart @@ -0,0 +1,238 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; + +import '../base/common.dart'; +import '../base/file_system.dart'; +import '../base/io.dart'; +import '../build_info.dart'; +import '../globals.dart' as globals; +import '../native_assets.dart'; + +/// Dry run the native builds. +/// +/// This does not build native assets, it only simulates what the final paths +/// of all assets will be so that this can be embedded in the kernel file. +Future<Uri?> dryRunNativeAssetsLinux({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + bool flutterTester = false, + required FileSystem fileSystem, +}) async { + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + return null; + } + + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.linux); + final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsLinuxInternal( + fileSystem, + projectUri, + flutterTester, + buildRunner, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + nativeAssetPaths, + buildUri_, + fileSystem, + ); + return nativeAssetsUri; +} + +Future<Iterable<Asset>> dryRunNativeAssetsLinuxInternal( + FileSystem fileSystem, + Uri projectUri, + bool flutterTester, + NativeAssetsBuildRunner buildRunner, +) async { + const OS targetOs = OS.linux; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + + globals.logger.printTrace('Dry running native assets for $targetOs.'); + final List<Asset> nativeAssets = (await buildRunner.dryRun( + linkModePreference: LinkModePreference.dynamic, + targetOs: targetOs, + workingDirectory: projectUri, + includeParentEnvironment: true, + )) + .assets; + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Dry running native assets for $targetOs done.'); + final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); + final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values; + return nativeAssetPaths; +} + +/// Builds native assets. +/// +/// If [targetPlatform] is omitted, the current target architecture is used. +/// +/// If [flutterTester] is true, absolute paths are emitted in the native +/// assets mapping. This can be used for JIT mode without sandbox on the host. +/// This is used in `flutter test` and `flutter run -d flutter-tester`. +Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsLinux({ + required NativeAssetsBuildRunner buildRunner, + TargetPlatform? targetPlatform, + required Uri projectUri, + required BuildMode buildMode, + bool flutterTester = false, + Uri? yamlParentDirectory, + required FileSystem fileSystem, +}) async { + const OS targetOs = OS.linux; + final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + final Directory buildDir = fileSystem.directory(buildUri_); + if (!await buildDir.exists()) { + // CMake requires the folder to exist to do copying. + await buildDir.create(recursive: true); + } + if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); + return (nativeAssetsYaml, <Uri>[]); + } + + final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current; + final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); + + globals.logger.printTrace('Building native assets for $target $buildModeCli.'); + final BuildResult result = await buildRunner.build( + linkModePreference: LinkModePreference.dynamic, + target: target, + buildMode: buildModeCli, + workingDirectory: projectUri, + includeParentEnvironment: true, + cCompilerConfig: await buildRunner.cCompilerConfig, + ); + final List<Asset> nativeAssets = result.assets; + final Set<Uri> dependencies = result.dependencies.toSet(); + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Building native assets for $target done.'); + final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); + await _copyNativeAssetsLinux( + buildUri_, + assetTargetLocations, + buildMode, + fileSystem, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + assetTargetLocations.values, + yamlParentDirectory ?? buildUri_, + fileSystem, + ); + return (nativeAssetsUri, dependencies.toList()); +} + +Map<Asset, Asset> _assetTargetLocations( + List<Asset> nativeAssets, + Uri? absolutePath, +) => + <Asset, Asset>{ + for (final Asset asset in nativeAssets) asset: _targetLocationLinux(asset, absolutePath), + }; + +Asset _targetLocationLinux(Asset asset, Uri? absolutePath) { + final AssetPath path = asset.path; + switch (path) { + case AssetSystemPath _: + case AssetInExecutable _: + case AssetInProcess _: + return asset; + case AssetAbsolutePath _: + final String fileName = path.uri.pathSegments.last; + Uri uri; + if (absolutePath != null) { + // Flutter tester needs full host paths. + uri = absolutePath.resolve(fileName); + } else { + // Flutter Desktop needs "absolute" paths inside the app. + // "relative" in the context of native assets would be relative to the + // kernel or aot snapshot. + uri = Uri(path: fileName); + } + return asset.copyWith(path: AssetAbsolutePath(uri)); + } + throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); +} + +/// Extract the [Target] from a [TargetPlatform]. +Target _getNativeTarget(TargetPlatform targetPlatform) { + switch (targetPlatform) { + case TargetPlatform.linux_x64: + return Target.linuxX64; + case TargetPlatform.linux_arm64: + return Target.linuxArm64; + case TargetPlatform.android: + case TargetPlatform.ios: + case TargetPlatform.darwin: + case TargetPlatform.windows_x64: + case TargetPlatform.fuchsia_arm64: + case TargetPlatform.fuchsia_x64: + case TargetPlatform.tester: + case TargetPlatform.web_javascript: + case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: + case TargetPlatform.android_x64: + case TargetPlatform.android_x86: + throw Exception('Unknown targetPlatform: $targetPlatform.'); + } +} + +Future<void> _copyNativeAssetsLinux( + Uri buildUri, + Map<Asset, Asset> assetTargetLocations, + BuildMode buildMode, + FileSystem fileSystem, +) async { + if (assetTargetLocations.isNotEmpty) { + globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); + final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); + if (!buildDir.existsSync()) { + buildDir.createSync(recursive: true); + } + for (final MapEntry<Asset, Asset> assetMapping in assetTargetLocations.entries) { + final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri; + final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri; + final Uri targetUri = buildUri.resolveUri(target); + final String targetFullPath = targetUri.toFilePath(); + await fileSystem.file(source).copy(targetFullPath); + } + globals.logger.printTrace('Copying native assets done.'); + } +} + +/// Flutter expects `clang++` to be on the path on Linux hosts. +/// +/// Search for the accompanying `clang`, `ar`, and `ld`. +Future<CCompilerConfig> cCompilerConfigLinux() async { + const String kClangPlusPlusBinary = 'clang++'; + const String kClangBinary = 'clang'; + const String kArBinary = 'llvm-ar'; + const String kLdBinary = 'ld.lld'; + + final ProcessResult whichResult = await globals.processManager.run(<String>['which', kClangPlusPlusBinary]); + if (whichResult.exitCode != 0) { + throwToolExit('Failed to find $kClangPlusPlusBinary on PATH.'); + } + File clangPpFile = globals.fs.file((whichResult.stdout as String).trim()); + clangPpFile = globals.fs.file(await clangPpFile.resolveSymbolicLinks()); + + final Directory clangDir = clangPpFile.parent; + final Map<String, Uri> binaryPaths = <String, Uri>{}; + for (final String binary in <String>[kClangBinary, kArBinary, kLdBinary]) { + final File binaryFile = clangDir.childFile(binary); + if (!await binaryFile.exists()) { + throwToolExit("Failed to find $binary relative to $clangPpFile: $binaryFile doesn't exist."); + } + binaryPaths[binary] = binaryFile.uri; + } + return CCompilerConfig( + ar: binaryPaths[kArBinary], + cc: binaryPaths[kClangBinary], + ld: binaryPaths[kLdBinary], + ); +} diff --git a/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart new file mode 100644 index 0000000000000..fe9ba86a035ac --- /dev/null +++ b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart @@ -0,0 +1,65 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import '../base/file_system.dart'; +import '../base/project_migrator.dart'; +import '../cmake_project.dart'; + +/// Adds the snippet to the CMake file that copies the native assets. +/// +/// ```cmake +/// # Copy the native assets provided by the build.dart from all packages. +/// set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +/// install(DIRECTORY "${NATIVE_ASSETS_DIR}" +/// DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" +/// COMPONENT Runtime) +/// ``` +class CmakeNativeAssetsMigration extends ProjectMigrator { + CmakeNativeAssetsMigration(CmakeBasedProject project, this.os, super.logger) + : _cmakeFile = project.managedCmakeFile; + + final File _cmakeFile; + final String os; + + @override + void migrate() { + if (!_cmakeFile.existsSync()) { + logger.printTrace('CMake project not found, skipping install() NATIVE_ASSETS_DIR migration.'); + return; + } + + final String originalProjectContents = _cmakeFile.readAsStringSync(); + + if (originalProjectContents.contains('set(NATIVE_ASSETS_DIR')) { + // Command is already present. + return; + } + + final String copyNativeAssetsCommand = ''' + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "\${PROJECT_BUILD_DIR}native_assets/$os/") +install(DIRECTORY "\${NATIVE_ASSETS_DIR}" + DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +'''; + + // Insert the new command after the bundled libraries loop. + const String bundleLibrariesCommandEnd = r''' +endforeach(bundled_library) +'''; + + String newProjectContents = originalProjectContents; + + newProjectContents = originalProjectContents.replaceFirst( + bundleLibrariesCommandEnd, + '$bundleLibrariesCommandEnd$copyNativeAssetsCommand', + ); + + if (originalProjectContents != newProjectContents) { + logger.printStatus('CMake missing install() NATIVE_ASSETS_DIR command, updating.'); + _cmakeFile.writeAsStringSync(newProjectContents); + } + } +} diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index 3253d29191581..b269fd876ed6a 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -19,6 +19,7 @@ import 'cache.dart'; import 'features.dart'; import 'globals.dart' as globals; import 'ios/native_assets.dart'; +import 'linux/native_assets.dart'; import 'macos/native_assets.dart'; import 'macos/native_assets_host.dart'; import 'resident_runner.dart'; @@ -168,6 +169,9 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { if (globals.platform.isMacOS || globals.platform.isIOS) { return cCompilerConfigMacOS(); } + if (globals.platform.isLinux) { + return cCompilerConfigLinux(); + } throwToolExit( 'Native assets feature not yet implemented for Linux, Windows and Android.', ); @@ -333,6 +337,13 @@ Future<Uri?> dryRunNativeAssets({ fileSystem: fileSystem, buildRunner: buildRunner, ); + } else if (const LocalPlatform().isLinux) { + nativeAssetsYaml = await dryRunNativeAssetsLinux( + projectUri: projectUri, + flutterTester: true, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); } else { await ensureNoNativeAssetsOrOsIsSupported( projectUri, @@ -342,6 +353,13 @@ Future<Uri?> dryRunNativeAssets({ ); nativeAssetsYaml = null; } + case build_info.TargetPlatform.linux_arm64: + case build_info.TargetPlatform.linux_x64: + nativeAssetsYaml = await dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); case build_info.TargetPlatform.android_arm: case build_info.TargetPlatform.android_arm64: case build_info.TargetPlatform.android_x64: @@ -349,8 +367,6 @@ Future<Uri?> dryRunNativeAssets({ case build_info.TargetPlatform.android: case build_info.TargetPlatform.fuchsia_arm64: case build_info.TargetPlatform.fuchsia_x64: - case build_info.TargetPlatform.linux_arm64: - case build_info.TargetPlatform.linux_x64: case build_info.TargetPlatform.web_javascript: case build_info.TargetPlatform.windows_x64: await ensureNoNativeAssetsOrOsIsSupported( @@ -382,7 +398,12 @@ Future<Uri?> dryRunNativeAssetsMultipeOSes({ if (targetPlatforms.contains(build_info.TargetPlatform.darwin) || (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS)) ...await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, false, buildRunner), - if (targetPlatforms.contains(build_info.TargetPlatform.ios)) ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) + if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) || + targetPlatforms.contains(build_info.TargetPlatform.linux_x64) || + (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.linux)) + ...await dryRunNativeAssetsLinuxInternal(fileSystem, projectUri, false, buildRunner), + if (targetPlatforms.contains(build_info.TargetPlatform.ios)) + ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) ]; final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); return nativeAssetsUri; diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 387795e521cd5..600478faa3e23 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -16,6 +16,7 @@ import '../bundle.dart'; import '../compile.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; +import '../linux/native_assets.dart'; import '../macos/native_assets.dart'; import '../native_assets.dart'; import '../project.dart'; @@ -168,28 +169,40 @@ class TestCompiler { } Uri? nativeAssetsYaml; - final Uri projectUri = FlutterProject.current().directory.uri; - final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( - projectUri, - buildInfo.packageConfig, - globals.fs, - globals.logger, - ); - if (globals.platform.isMacOS) { - (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( - buildMode: BuildMode.debug, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); + if (!buildInfo.buildNativeAssets) { + nativeAssetsYaml = null; } else { - await ensureNoNativeAssetsOrOsIsSupported( + final Uri projectUri = FlutterProject.current().directory.uri; + final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( projectUri, - const LocalPlatform().operatingSystem, + buildInfo.packageConfig, globals.fs, - buildRunner, + globals.logger, ); + if (globals.platform.isMacOS) { + (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( + buildMode: buildInfo.mode, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); + } else if (globals.platform.isLinux) { + (nativeAssetsYaml, _) = await buildNativeAssetsLinux( + buildMode: buildInfo.mode, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); + } else { + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + const LocalPlatform().operatingSystem, + globals.fs, + buildRunner, + ); + } } final CompilerOutput? compilerOutput = await compiler!.recompile( diff --git a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl index a4fc907bec376..580180401d132 100644 --- a/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/linux.tmpl/CMakeLists.txt.tmpl @@ -127,6 +127,12 @@ foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) COMPONENT Runtime) endforeach(bundled_library) +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart new file mode 100644 index 0000000000000..34d2fc552f820 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart @@ -0,0 +1,374 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/dart/package_map.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/linux/native_assets.dart'; +import 'package:flutter_tools/src/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; +import 'package:package_config/package_config_types.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fakes.dart'; +import '../fake_native_assets_build_runner.dart'; + +void main() { + late FakeProcessManager processManager; + late Environment environment; + late Artifacts artifacts; + late FileSystem fileSystem; + late BufferLogger logger; + late Uri projectUri; + + setUp(() { + processManager = FakeProcessManager.empty(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + fileSystem = MemoryFileSystem.test(); + environment = Environment.test( + fileSystem.currentDirectory, + inputs: <String, String>{}, + artifacts: artifacts, + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + environment.buildDir.createSync(recursive: true); + projectUri = environment.projectDir.uri; + }); + + testUsingContext('dry run with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + expect( + await dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ), + null, + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('build with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run for multiple OSes with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await dryRunNativeAssetsMultipeOSes( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: <TargetPlatform>[ + TargetPlatform.darwin, + TargetPlatform.ios, + ], + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('dry run with assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final Uri? nativeAssetsYaml = await dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.linuxX64, + path: AssetAbsolutePath(Uri.file('libbar.so')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.linuxArm64, + path: AssetAbsolutePath(Uri.file('libbar.so')), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/linux/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + contains('package:bar/bar.dart'), + ); + }); + + testUsingContext('build with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('build no assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/linux/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + isNot(contains('package:bar/bar.dart')), + ); + expect( + environment.projectDir + .childDirectory('build') + .childDirectory('native_assets') + .childDirectory('linux'), + exists, + ); + }); + + for (final bool flutterTester in <bool>[false, true]) { + String testName = ''; + if (flutterTester) { + testName += ' flutter tester'; + } + testUsingContext('build with assets$testName', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + if (const LocalPlatform().isWindows) { + return; // Backslashes in commands, but we will never run these commands on Windows. + } + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final File dylibAfterCompiling = fileSystem.file('libbar.so'); + // The mock doesn't create the file, so create it here. + await dylibAfterCompiling.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + flutterTester: flutterTester, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + buildResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.linuxX64, + path: AssetAbsolutePath(dylibAfterCompiling.uri), + ), + ], + ), + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/linux/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + stringContainsInOrder(<String>[ + 'package:bar/bar.dart', + if (flutterTester) + // Tests run on host system, so the have the full path on the system. + '- ${projectUri.resolve('/build/native_assets/linux/libbar.so').toFilePath()}' + else + // Apps are a bundle with the dylibs on their dlopen path. + '- libbar.so', + ]), + ); + }); + } + + testUsingContext('static libs not supported', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsLinux( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.macOSArm64, + path: AssetAbsolutePath(Uri.file('bar.a')), + ), + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.macOSX64, + path: AssetAbsolutePath(Uri.file('bar.a')), + ), + ], + ), + ), + ), + throwsToolExit( + message: 'Native asset(s) package:bar/bar.dart have their link mode set to ' + 'static, but this is not yet supported. ' + 'For more info see https://github.com/dart-lang/sdk/issues/49418.', + ), + ); + }); + + // This logic is mocked in the other tests to avoid having test order + // randomization causing issues with what processes are invoked. + // Exercise the parsing of the process output in this separate test. + testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + <FakeCommand>[ + const FakeCommand( + command: <Pattern>['which', 'clang++'], + stdout: ''' +/some/path/to/clang++ +''', // Newline at the end of the string. + ) + ], + ), + FileSystem: () => fileSystem, + }, () async { + if (!const LocalPlatform().isLinux) { + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + return; + } + + await fileSystem.directory('/some/path/to/').create(recursive: true); + await fileSystem.file('/some/path/to/clang++').create(); + await fileSystem.file('/some/path/to/clang').create(); + await fileSystem.file('/some/path/to/llvm-ar').create(); + await fileSystem.file('/some/path/to/ld.lld').create(); + + final File packagesFile = fileSystem + .directory(projectUri) + .childDirectory('.dart_tool') + .childFile('package_config.json'); + await packagesFile.parent.create(); + await packagesFile.create(); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + packagesFile, + logger: environment.logger, + ); + final NativeAssetsBuildRunner runner = + NativeAssetsBuildRunnerImpl(projectUri, packageConfig, fileSystem, logger); + final CCompilerConfig result = await runner.cCompilerConfig; + expect(result.cc, Uri.file('/some/path/to/clang')); + }); +} diff --git a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart index 36ee8d7824a3a..8689febb15ae8 100644 --- a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart @@ -8,6 +8,7 @@ import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cmake_project.dart'; import 'package:flutter_tools/src/migrations/cmake_custom_command_migration.dart'; +import 'package:flutter_tools/src/migrations/cmake_native_assets_migration.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; @@ -155,6 +156,132 @@ add_custom_command( expect(testLogger.statusText, contains('add_custom_command() missing VERBATIM or FLUTTER_TARGET_PLATFORM, updating.')); }); }); + + group('migrate add install() NATIVE_ASSETS_DIR command', () { + late MemoryFileSystem memoryFileSystem; + late BufferLogger testLogger; + late FakeCmakeProject mockCmakeProject; + late File managedCmakeFile; + + setUp(() { + memoryFileSystem = MemoryFileSystem.test(); + managedCmakeFile = memoryFileSystem.file('CMakeLists.txtx'); + + testLogger = BufferLogger( + terminal: Terminal.test(), + outputPreferences: OutputPreferences.test(), + ); + + mockCmakeProject = FakeCmakeProject(managedCmakeFile); + }); + + testWithoutContext('skipped if files are missing', () { + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + expect(managedCmakeFile.existsSync(), isFalse); + + expect(testLogger.traceText, contains('CMake project not found, skipping install() NATIVE_ASSETS_DIR migration.')); + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if nothing to migrate', () { + const String contents = 'Nothing to migrate'; + managedCmakeFile.writeAsStringSync(contents); + final DateTime projectLastModified = managedCmakeFile.lastModifiedSync(); + + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.lastModifiedSync(), projectLastModified); + expect(managedCmakeFile.readAsStringSync(), contents); + + expect(testLogger.statusText, isEmpty); + }); + + testWithoutContext('skipped if already migrated', () { + const String contents = r''' +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +'''; + managedCmakeFile.writeAsStringSync(contents); + final DateTime projectLastModified = managedCmakeFile.lastModifiedSync(); + + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.lastModifiedSync(), projectLastModified); + expect(managedCmakeFile.readAsStringSync(), contents); + + expect(testLogger.statusText, isEmpty); + }); + + // TODO(dacoharkes): Add test for Windows when adding Windows support. https://github.com/flutter/flutter/issues/129757 + testWithoutContext('is migrated to copy native assets', () { + managedCmakeFile.writeAsStringSync(r''' +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) +'''); + + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + 'linux', + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.readAsStringSync(), r''' +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) +'''); + + expect(testLogger.statusText, contains('CMake missing install() NATIVE_ASSETS_DIR command, updating.')); + }); + }); }); } diff --git a/packages/flutter_tools/test/integration.shard/native_assets_test.dart b/packages/flutter_tools/test/integration.shard/native_assets_test.dart index e539e74a27a75..c6824fb35774e 100644 --- a/packages/flutter_tools/test/integration.shard/native_assets_test.dart +++ b/packages/flutter_tools/test/integration.shard/native_assets_test.dart @@ -17,6 +17,7 @@ import 'dart:io'; import 'package:file/file.dart'; import 'package:file_testing/file_testing.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; import '../src/common.dart'; import 'test_utils.dart' show fileSystem, platform; @@ -56,10 +57,8 @@ const String packageName = 'package_with_native_assets'; const String exampleAppName = '${packageName}_example'; -const String dylibName = 'lib$packageName.dylib'; - void main() { - if (!platform.isMacOS) { + if (!platform.isMacOS && !platform.isLinux) { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 return; } @@ -148,6 +147,9 @@ void main() { if (device == 'macos') { expectDylibIsBundledMacOS(exampleDirectory, buildMode); } + if (device == 'linux') { + expectDylibIsBundledLinux(exampleDirectory, buildMode); + } if (device == hostOs) { expectCCompilerIsConfigured(exampleDirectory); } @@ -201,6 +203,8 @@ void main() { expectDylibIsBundledMacOS(exampleDirectory, buildMode); } else if (buildSubcommand == 'ios') { expectDylibIsBundledIos(exampleDirectory, buildMode); + } else if (buildSubcommand == 'linux') { + expectDylibIsBundledLinux(exampleDirectory, buildMode); } expectCCompilerIsConfigured(exampleDirectory); }); @@ -278,7 +282,7 @@ void expectDylibIsBundledMacOS(Directory appDirectory, String buildMode) { expect(appBundle, exists); final Directory dylibsFolder = appBundle.childDirectory('Contents/Frameworks'); expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(dylibName); + final File dylib = dylibsFolder.childFile(OS.macOS.dylibFileName(packageName)); expect(dylib, exists); } @@ -287,7 +291,21 @@ void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { expect(appBundle, exists); final Directory dylibsFolder = appBundle.childDirectory('Frameworks'); expect(dylibsFolder, exists); - final File dylib = dylibsFolder.childFile(dylibName); + final File dylib = dylibsFolder.childFile(OS.iOS.dylibFileName(packageName)); + expect(dylib, exists); +} + +/// Checks that dylibs are bundled. +/// +/// Sample path: build/linux/x64/release/bundle/lib/libmy_package.so +void expectDylibIsBundledLinux(Directory appDirectory, String buildMode) { + // Linux does not support cross compilation, so always only check current architecture. + final String architecture = Architecture.current.dartPlatform; + final Directory appBundle = appDirectory.childDirectory('build/$hostOs/$architecture/$buildMode/bundle/'); + expect(appBundle, exists); + final Directory dylibsFolder = appBundle.childDirectory('lib/'); + expect(dylibsFolder, exists); + final File dylib = dylibsFolder.childFile(OS.linux.dylibFileName(packageName)); expect(dylib, exists); } @@ -296,7 +314,7 @@ void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { void expectDylibIsBundledWithFrameworks(Directory appDirectory, String buildMode, String os) { final Directory frameworksFolder = appDirectory.childDirectory('build/$os/framework/${buildMode.upperCaseFirst()}'); expect(frameworksFolder, exists); - final File dylib = frameworksFolder.childFile(dylibName); + final File dylib = frameworksFolder.childFile(OS.macOS.dylibFileName(packageName)); expect(dylib, exists); } diff --git a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart index 9c34917600395..fa3a7f3b9e5b8 100644 --- a/packages/flutter_tools/test/integration.shard/transition_test_utils.dart +++ b/packages/flutter_tools/test/integration.shard/transition_test_utils.dart @@ -6,6 +6,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter_tools/src/base/platform.dart'; import 'package:meta/meta.dart'; import 'package:process/process.dart'; @@ -177,9 +178,15 @@ Future<ProcessTestResult> runFlutter( minutes: 10), // must be less than test timeout of 15 minutes! See ../../dart_test.yaml. }) async { + const LocalPlatform platform = LocalPlatform(); final Stopwatch clock = Stopwatch()..start(); final Process process = await processManager.start( - <String>[flutterBin, ...arguments], + <String>[ + // In a container with no X display, use the virtual framebuffer. + if (platform.isLinux && (platform.environment['DISPLAY'] ?? '').isEmpty) '/usr/bin/xvfb-run', + flutterBin, + ...arguments, + ], workingDirectory: workingDirectory, ); final List<LogLine> logs = <LogLine>[]; From f388559bdcf0c7fb8147e16477bf8f4931fc4ef4 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 02:40:50 -0400 Subject: [PATCH 1411/1547] Roll Flutter Engine from e0fb071ead2f to f8e909b88f3f (1 revision) (#135281) https://github.com/flutter/engine/compare/e0fb071ead2f...f8e909b88f3f 2023-09-22 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from PXDDhlPyd9sgrWWun... to ZyajVWocCHVIuJkzM... (flutter/engine#46179) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from PXDDhlPyd9sg to ZyajVWocCHVI If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index afe018ad32e20..2239a41f90def 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e0fb071ead2f9dcd266d662a4898ffb39e224aa7 +f8e909b88f3fba00b647f7a2ae5f3cb9a4839d75 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index d6fff414b4b54..20a51c3538ef9 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -PXDDhlPyd9sgrWWunaLin7Q_HAx2RMYRbJ6NXLlIrJUC +ZyajVWocCHVIuJkzM88O4Ss5WHqZcTNDl7K2YwixdMwC From 09f7d7c56043037895470fbe879fdfc0baf2ded9 Mon Sep 17 00:00:00 2001 From: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:34:06 +0800 Subject: [PATCH 1412/1547] Remove extra padding if a dropdown menu entry also has a leading icon (#135004) Fixes #131350 This PR is to remove the extra padding in `DropdownMenuEntry` if both the text field and the dropdown menu entry have leading icons. **After** fix: <img width="300" alt="Screenshot 2023-09-19 at 4 35 24 PM" src="https://github.com/flutter/flutter/assets/36861262/ed7d92a5-3f96-4106-a03e-09258ea3709f"> **Before** fix: <img width="300" alt="Screenshot 2023-09-19 at 4 37 58 PM" src="https://github.com/flutter/flutter/assets/36861262/fdbfef54-6c93-48fb-bd64-41fa31dde531"> --- .../lib/src/material/dropdown_menu.dart | 33 +++++++++++------- .../test/material/dropdown_menu_test.dart | 34 +++++++++++++++++++ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 3b80170fcabbf..51b17e5b2cb1a 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -432,21 +432,28 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> { { int? focusedIndex, bool enableScrollToHighlight = true} ) { final List<Widget> result = <Widget>[]; - final double padding = leadingPadding ?? _kDefaultHorizontalPadding; - final ButtonStyle defaultStyle; - switch (textDirection) { - case TextDirection.rtl: - defaultStyle = MenuItemButton.styleFrom( - padding: EdgeInsets.only(left: _kDefaultHorizontalPadding, right: padding), - ); - case TextDirection.ltr: - defaultStyle = MenuItemButton.styleFrom( - padding: EdgeInsets.only(left: padding, right: _kDefaultHorizontalPadding), - ); - } - for (int i = 0; i < filteredEntries.length; i++) { final DropdownMenuEntry<T> entry = filteredEntries[i]; + + // By default, when the text field has a leading icon but a menu entry doesn't + // have one, the label of the entry should have extra padding to be aligned + // with the text in the text input field. When both the text field and the + // menu entry have leading icons, the menu entry should remove the extra + // paddings so its leading icon will be aligned with the leading icon of + // the text field. + final double padding = entry.leadingIcon == null ? (leadingPadding ?? _kDefaultHorizontalPadding) : _kDefaultHorizontalPadding; + final ButtonStyle defaultStyle; + switch (textDirection) { + case TextDirection.rtl: + defaultStyle = MenuItemButton.styleFrom( + padding: EdgeInsets.only(left: _kDefaultHorizontalPadding, right: padding), + ); + case TextDirection.ltr: + defaultStyle = MenuItemButton.styleFrom( + padding: EdgeInsets.only(left: padding, right: _kDefaultHorizontalPadding), + ); + } + ButtonStyle effectiveStyle = entry.style ?? defaultStyle; final Color focusedBackgroundColor = effectiveStyle.foregroundColor?.resolve(<MaterialState>{MaterialState.focused}) ?? Theme.of(context).colorScheme.onSurface; diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index a499bcd262e5e..6b142e5c9099f 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -1680,6 +1680,40 @@ void main() { await tester.pumpAndSettle(); expect(controller.text, ''); // nothing selected }); + + // Regression test for https://github.com/flutter/flutter/issues/131350. + testWidgets('DropdownMenuEntry.leadingIcon default layout', (WidgetTester tester) async { + // The DropdownMenu should not get extra padding in DropdownMenuEntry items + // when both text field and DropdownMenuEntry have leading icons. + await tester.pumpWidget(const MaterialApp( + home: Scaffold( + body: DropdownMenu<int>( + leadingIcon: Icon(Icons.search), + hintText: 'Hint', + dropdownMenuEntries: <DropdownMenuEntry<int>>[ + DropdownMenuEntry<int>( + value: 0, + label: 'Item 0', + leadingIcon: Icon(Icons.alarm) + ), + DropdownMenuEntry<int>(value: 1, label: 'Item 1'), + ], + ), + ) + )); + await tester.tap(find.byType(DropdownMenu<int>)); + await tester.pumpAndSettle(); + + // Check text location in text field. + expect(tester.getTopLeft(find.text('Hint')).dx, 48.0); + + // By default, the text of item 0 should be aligned with the text of the text field. + expect(tester.getTopLeft(find.text('Item 0').last).dx, 48.0); + + // By default, the text of item 1 should be aligned with the text of the text field, + // so there are some extra padding before "Item 1". + expect(tester.getTopLeft(find.text('Item 1').last).dx, 48.0); + }); } enum TestMenu { From 12d761a82866361be27dd41dc07fa4ddc05156a2 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 03:36:08 -0400 Subject: [PATCH 1413/1547] Roll Flutter Engine from f8e909b88f3f to 3a2346ade2f2 (4 revisions) (#135283) https://github.com/flutter/engine/compare/f8e909b88f3f...3a2346ade2f2 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 97ec4dbabd05 to 3ae3bb0d40df (1 revision) (flutter/engine#46182) 2023-09-22 leroux_bruno@yahoo.fr [iOS] Disable spelling corrections when auto correction is disabled (flutter/engine#46144) 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 86454ab4f3de to 97ec4dbabd05 (1 revision) (flutter/engine#46181) 2023-09-22 skia-flutter-autoroll@skia.org Roll Dart SDK from 5d33f4c85b82 to 6bde93a6e56f (1 revision) (flutter/engine#46180) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2239a41f90def..fffe64a71938e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f8e909b88f3fba00b647f7a2ae5f3cb9a4839d75 +3a2346ade2f28e6dff4ea7dfbc3b41cfb6ecfd78 From 801a1c9304f8f430e36e4efea6981d071dd5f7ef Mon Sep 17 00:00:00 2001 From: Matheus Kirchesch <matheus@btor.com.br> Date: Fri, 22 Sep 2023 05:03:02 -0300 Subject: [PATCH 1414/1547] Added option to disable [NavigationDrawerDestination]s (#132349) This PR adds a new option in the NavigationDrawerDestination api allowing it to be disabled, this is very useful for role based access control, especially in the navigation drawer which is used to lay out all the app destinations * https://github.com/flutter/flutter/issues/132348 --- .../lib/src/material/navigation_drawer.dart | 61 +++++++++++++------ .../test/material/navigation_drawer_test.dart | 51 ++++++++++++++++ 2 files changed, 93 insertions(+), 19 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_drawer.dart b/packages/flutter/lib/src/material/navigation_drawer.dart index 611a2d51d7644..3c4edbe172ed8 100644 --- a/packages/flutter/lib/src/material/navigation_drawer.dart +++ b/packages/flutter/lib/src/material/navigation_drawer.dart @@ -193,6 +193,7 @@ class NavigationDrawerDestination extends StatelessWidget { required this.icon, this.selectedIcon, required this.label, + this.enabled = true, }); /// Sets the color of the [Material] that holds all of the [Drawer]'s @@ -229,12 +230,20 @@ class NavigationDrawerDestination extends StatelessWidget { /// text style would use [TextTheme.labelLarge] with [ColorScheme.onSurfaceVariant]. final Widget label; + /// Indicates that this destination is selectable. + /// + /// Defaults to true. + final bool enabled; + @override Widget build(BuildContext context) { const Set<MaterialState> selectedState = <MaterialState>{ MaterialState.selected }; const Set<MaterialState> unselectedState = <MaterialState>{}; + const Set<MaterialState> disabledState = <MaterialState>{ + MaterialState.disabled + }; final NavigationDrawerThemeData navigationDrawerTheme = NavigationDrawerTheme.of(context); @@ -247,13 +256,13 @@ class NavigationDrawerDestination extends StatelessWidget { return _NavigationDestinationBuilder( buildIcon: (BuildContext context) { final Widget selectedIconWidget = IconTheme.merge( - data: navigationDrawerTheme.iconTheme?.resolve(selectedState) ?? - defaults.iconTheme!.resolve(selectedState)!, + data: navigationDrawerTheme.iconTheme?.resolve(enabled ? selectedState : disabledState) ?? + defaults.iconTheme!.resolve(enabled ? selectedState : disabledState)!, child: selectedIcon ?? icon, ); final Widget unselectedIconWidget = IconTheme.merge( - data: navigationDrawerTheme.iconTheme?.resolve(unselectedState) ?? - defaults.iconTheme!.resolve(unselectedState)!, + data: navigationDrawerTheme.iconTheme?.resolve(enabled ? unselectedState : disabledState) ?? + defaults.iconTheme!.resolve(enabled ? unselectedState : disabledState)!, child: icon, ); @@ -263,11 +272,12 @@ class NavigationDrawerDestination extends StatelessWidget { }, buildLabel: (BuildContext context) { final TextStyle? effectiveSelectedLabelTextStyle = - navigationDrawerTheme.labelTextStyle?.resolve(selectedState) ?? - defaults.labelTextStyle!.resolve(selectedState); + navigationDrawerTheme.labelTextStyle?.resolve(enabled ? selectedState : disabledState) ?? + defaults.labelTextStyle!.resolve(enabled ? selectedState : disabledState); final TextStyle? effectiveUnselectedLabelTextStyle = - navigationDrawerTheme.labelTextStyle?.resolve(unselectedState) ?? - defaults.labelTextStyle!.resolve(unselectedState); + navigationDrawerTheme.labelTextStyle?.resolve(enabled ? unselectedState : disabledState) ?? + defaults.labelTextStyle!.resolve(enabled ? unselectedState : disabledState); + return DefaultTextStyle( style: _isForwardOrCompleted(animation) ? effectiveSelectedLabelTextStyle! @@ -275,6 +285,7 @@ class NavigationDrawerDestination extends StatelessWidget { child: label, ); }, + enabled: enabled, ); } } @@ -296,6 +307,7 @@ class _NavigationDestinationBuilder extends StatelessWidget { const _NavigationDestinationBuilder({ required this.buildIcon, required this.buildLabel, + this.enabled = true, }); /// Builds the icon for a destination in a [NavigationDrawer]. @@ -322,12 +334,26 @@ class _NavigationDestinationBuilder extends StatelessWidget { /// animation is decreasing or dismissed. final WidgetBuilder buildLabel; + /// Indicates that this destination is selectable. + /// + /// Defaults to true. + final bool enabled; + @override Widget build(BuildContext context) { final _NavigationDrawerDestinationInfo info = _NavigationDrawerDestinationInfo.of(context); final NavigationDrawerThemeData navigationDrawerTheme = NavigationDrawerTheme.of(context); final NavigationDrawerThemeData defaults = _NavigationDrawerDefaultsM3(context); + final Row destinationBody = Row( + children: <Widget>[ + const SizedBox(width: 16), + buildIcon(context), + const SizedBox(width: 12), + buildLabel(context), + ], + ); + return Padding( padding: info.tilePadding, child: _NavigationDestinationSemantics( @@ -335,7 +361,7 @@ class _NavigationDestinationBuilder extends StatelessWidget { height: navigationDrawerTheme.tileHeight ?? defaults.tileHeight, child: InkWell( highlightColor: Colors.transparent, - onTap: info.onTap, + onTap: enabled ? info.onTap : null, customBorder: info.indicatorShape ?? navigationDrawerTheme.indicatorShape ?? defaults.indicatorShape!, child: Stack( alignment: Alignment.center, @@ -347,14 +373,7 @@ class _NavigationDestinationBuilder extends StatelessWidget { width: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).width, height: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).height, ), - Row( - children: <Widget>[ - const SizedBox(width: 16), - buildIcon(context), - const SizedBox(width: 12), - buildLabel(context), - ], - ), + destinationBody ], ), ), @@ -702,7 +721,9 @@ class _NavigationDrawerDefaultsM3 extends NavigationDrawerThemeData { return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return IconThemeData( size: 24.0, - color: states.contains(MaterialState.selected) + color: states.contains(MaterialState.disabled) + ? _colors.onSurfaceVariant.withOpacity(0.38) + : states.contains(MaterialState.selected) ? _colors.onSecondaryContainer : _colors.onSurfaceVariant, ); @@ -714,7 +735,9 @@ class _NavigationDrawerDefaultsM3 extends NavigationDrawerThemeData { return MaterialStateProperty.resolveWith((Set<MaterialState> states) { final TextStyle style = _textTheme.labelLarge!; return style.apply( - color: states.contains(MaterialState.selected) + color: states.contains(MaterialState.disabled) + ? _colors.onSurfaceVariant.withOpacity(0.38) + : states.contains(MaterialState.selected) ? _colors.onSecondaryContainer : _colors.onSurfaceVariant, ); diff --git a/packages/flutter/test/material/navigation_drawer_test.dart b/packages/flutter/test/material/navigation_drawer_test.dart index 8a6b6d0aafed0..6df86c5a29cb3 100644 --- a/packages/flutter/test/material/navigation_drawer_test.dart +++ b/packages/flutter/test/material/navigation_drawer_test.dart @@ -395,6 +395,57 @@ void main() { final NavigationDrawer drawer = tester.widget(find.byType(NavigationDrawer)); expect(drawer.tilePadding, const EdgeInsets.symmetric(horizontal: 12.0)); }); + + testWidgetsWithLeakTracking('Destinations respect their disabled state', (WidgetTester tester) async { + final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); + int selectedIndex = 0; + + widgetSetup(tester, 800); + + final Widget widget = _buildWidget( + scaffoldKey, + NavigationDrawer( + children: const <Widget>[ + NavigationDrawerDestination( + icon: Icon(Icons.ac_unit), + label: Text('AC'), + ), + NavigationDrawerDestination( + icon: Icon(Icons.access_alarm), + label: Text('Alarm'), + ), + NavigationDrawerDestination( + icon: Icon(Icons.accessible), + label: Text('Accessible'), + enabled: false, + ), + ], + onDestinationSelected: (int i) { + selectedIndex = i; + }, + ), + ); + + await tester.pumpWidget(widget); + scaffoldKey.currentState!.openDrawer(); + await tester.pump(); + + expect(find.text('AC'), findsOneWidget); + expect(find.text('Alarm'), findsOneWidget); + expect(find.text('Accessible'), findsOneWidget); + + await tester.pump(const Duration(seconds: 1)); + + expect(selectedIndex, 0); + + await tester.tap(find.text('Alarm')); + expect(selectedIndex, 1); + + await tester.tap(find.text('Accessible')); + expect(selectedIndex, 1); + + tester.pumpAndSettle(); + }); } Widget _buildWidget(GlobalKey<ScaffoldState> scaffoldKey, Widget child, { bool? useMaterial3 }) { From 8de97ca1bbebc2c549a0c160fe6a4f51d267d96c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 05:14:11 -0400 Subject: [PATCH 1415/1547] Roll Flutter Engine from 3a2346ade2f2 to 3d54e44d0654 (2 revisions) (#135288) https://github.com/flutter/engine/compare/3a2346ade2f2...3d54e44d0654 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from a3480a62e438 to 8d9e2cd32ec7 (1 revision) (flutter/engine#46184) 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 3ae3bb0d40df to a3480a62e438 (1 revision) (flutter/engine#46183) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fffe64a71938e..0d31d0a214b90 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3a2346ade2f28e6dff4ea7dfbc3b41cfb6ecfd78 +3d54e44d0654d9abd67a1979a157a13cfca2d581 From 723ba03a440ace692dd9c13f1c8baba544a8e1b6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 06:25:26 -0400 Subject: [PATCH 1416/1547] Roll Flutter Engine from 3d54e44d0654 to 2fa8dec336d0 (1 revision) (#135289) https://github.com/flutter/engine/compare/3d54e44d0654...2fa8dec336d0 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 8d9e2cd32ec7 to 8752f3ac6e99 (1 revision) (flutter/engine#46186) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 0d31d0a214b90..fd302e8c1783c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3d54e44d0654d9abd67a1979a157a13cfca2d581 +2fa8dec336d01e7559a9db627e0b9dac43d92fac From 99192f83a7180bde08476572f3abe82dfe5c3eaf Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 08:06:02 -0400 Subject: [PATCH 1417/1547] Roll Flutter Engine from 2fa8dec336d0 to b642e4f4dffa (1 revision) (#135295) https://github.com/flutter/engine/compare/2fa8dec336d0...b642e4f4dffa 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 8752f3ac6e99 to d0f04adbec5c (1 revision) (flutter/engine#46191) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index fd302e8c1783c..42767660fa663 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2fa8dec336d01e7559a9db627e0b9dac43d92fac +b642e4f4dffa6154c8198f80cf01cb1c08ef51a7 From 6502883a967383944214478108a4ab803adce8ac Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 09:48:37 -0400 Subject: [PATCH 1418/1547] Roll Flutter Engine from b642e4f4dffa to 9d06c176cf98 (2 revisions) (#135304) https://github.com/flutter/engine/compare/b642e4f4dffa...9d06c176cf98 2023-09-22 skia-flutter-autoroll@skia.org Roll Dart SDK from 6bde93a6e56f to 4ddff752a6b0 (1 revision) (flutter/engine#46193) 2023-09-22 whesse@google.com Re-add package tar to DEPS (flutter/engine#46190) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 42767660fa663..ba53d4b4c695f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -b642e4f4dffa6154c8198f80cf01cb1c08ef51a7 +9d06c176cf981771f9d56b04c3f4a979d82a0025 From f58163447f3b593073161b2e447d9e4f9d5ec6d7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 10:39:31 -0400 Subject: [PATCH 1419/1547] Roll Flutter Engine from 9d06c176cf98 to e97155428ad4 (1 revision) (#135306) https://github.com/flutter/engine/compare/9d06c176cf98...e97155428ad4 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from d0f04adbec5c to a911bc1352f2 (1 revision) (flutter/engine#46194) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ba53d4b4c695f..8c2aa4795a013 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9d06c176cf981771f9d56b04c3f4a979d82a0025 +e97155428ad46b59c1b3aa9d8cbe182f65401182 From 06780cb1d0698f0fd9376eb43ef6789714c6d465 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 11:25:37 -0400 Subject: [PATCH 1420/1547] Roll Flutter Engine from e97155428ad4 to ef9ceed1af08 (1 revision) (#135308) https://github.com/flutter/engine/compare/e97155428ad4...ef9ceed1af08 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from a911bc1352f2 to f346a813ffd4 (1 revision) (flutter/engine#46195) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8c2aa4795a013..5f09714afdae7 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e97155428ad46b59c1b3aa9d8cbe182f65401182 +ef9ceed1af0866c5e194ae52da6e5f82ce6a83b3 From 74c6693170e184807428683ebcb893b1717d2ecf Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 12:02:02 -0400 Subject: [PATCH 1421/1547] Roll Packages from d0411e450a8d to 98ebcd3d9c05 (3 revisions) (#135310) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/flutter/packages/compare/d0411e450a8d...98ebcd3d9c05 2023-09-22 engine-flutter-autoroll@skia.org Manual roll Flutter (stable) from 367f9ea16bfa to 12fccda59847 (2 revisions) (flutter/packages#4976) 2023-09-21 47866232+chunhtai@users.noreply.github.com [go_router] Fixes the GoRouter.goBranch so that it doesn't reset extr… (flutter/packages#4723) 2023-09-21 maurits@vnbskm.nl [webview_flutter_wkwebview] Adds WKWebView implementation to override console log (flutter/packages#4703) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 44829152e052d..c779848cdf372 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -d0411e450a8d94fcb221e8d8eacd3b1f8ca0e2fc +98ebcd3d9c05c95801b0137b9bfd0cf898a18b56 From dbe0ccd8853dabdcb0f94ce2cdef892a1b10e48a Mon Sep 17 00:00:00 2001 From: Bartek Pacia <barpac02@gmail.com> Date: Fri, 22 Sep 2023 18:31:48 +0200 Subject: [PATCH 1422/1547] Refactor "app plugin loader" Gradle Plugin so it can be applied using the declarative `plugins {}` block (#127897) This PR fixes #125009. --- examples/hello_world/android/build.gradle | 3 +- .../android/buildscript-gradle.lockfile | 182 +++--------------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../hello_world/android/project-app.lockfile | 16 +- examples/hello_world/android/settings.gradle | 13 +- .../gradle/app_plugin_loader.gradle | 35 +--- .../flutter_tools/gradle/build.gradle.kts | 12 +- .../flutter_tools/gradle/settings.gradle.kts | 7 + .../src/main/groovy/app_plugin_loader.groovy | 42 ++++ .../android-java.tmpl/build.gradle.tmpl | 1 - .../android-kotlin.tmpl/build.gradle.tmpl | 1 - .../{settings.gradle => settings.gradle.tmpl} | 13 +- .../templates/template_manifest.json | 1 + 13 files changed, 116 insertions(+), 212 deletions(-) create mode 100644 packages/flutter_tools/gradle/settings.gradle.kts create mode 100644 packages/flutter_tools/gradle/src/main/groovy/app_plugin_loader.groovy rename packages/flutter_tools/templates/app_shared/android.tmpl/{settings.gradle => settings.gradle.tmpl} (71%) diff --git a/examples/hello_world/android/build.gradle b/examples/hello_world/android/build.gradle index 2de20623576a8..a38857e025b8d 100644 --- a/examples/hello_world/android/build.gradle +++ b/examples/hello_world/android/build.gradle @@ -7,14 +7,13 @@ // See dev/tools/bin/generate_gradle_lockfiles.dart. buildscript { - ext.kotlin_version = '1.5.31' + ext.kotlin_version = '1.9.0' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/examples/hello_world/android/buildscript-gradle.lockfile b/examples/hello_world/android/buildscript-gradle.lockfile index efe13277310ee..14350adbcb457 100644 --- a/examples/hello_world/android/buildscript-gradle.lockfile +++ b/examples/hello_world/android/buildscript-gradle.lockfile @@ -1,163 +1,29 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -androidx.databinding:databinding-common:7.2.0=classpath -androidx.databinding:databinding-compiler-common:7.2.0=classpath -com.android.databinding:baseLibrary:7.2.0=classpath -com.android.tools.analytics-library:crash:30.2.0=classpath -com.android.tools.analytics-library:protos:30.2.0=classpath -com.android.tools.analytics-library:shared:30.2.0=classpath -com.android.tools.analytics-library:tracker:30.2.0=classpath -com.android.tools.build.jetifier:jetifier-core:1.0.0-beta09=classpath -com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09=classpath -com.android.tools.build:aapt2-proto:7.2.0-7984345=classpath -com.android.tools.build:aaptcompiler:7.2.0=classpath -com.android.tools.build:apksig:7.2.0=classpath -com.android.tools.build:apkzlib:7.2.0=classpath -com.android.tools.build:builder-model:7.2.0=classpath -com.android.tools.build:builder-test-api:7.2.0=classpath -com.android.tools.build:builder:7.2.0=classpath -com.android.tools.build:bundletool:1.8.2=classpath -com.android.tools.build:gradle-api:7.2.0=classpath -com.android.tools.build:gradle:7.2.0=classpath -com.android.tools.build:manifest-merger:30.2.0=classpath -com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api=classpath -com.android.tools.ddms:ddmlib:30.2.0=classpath -com.android.tools.layoutlib:layoutlib-api:30.2.0=classpath -com.android.tools.lint:lint-model:30.2.0=classpath -com.android.tools.lint:lint-typedef-remover:30.2.0=classpath -com.android.tools.utp:android-device-provider-ddmlib-proto:30.2.0=classpath -com.android.tools.utp:android-device-provider-gradle-proto:30.2.0=classpath -com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:30.2.0=classpath -com.android.tools.utp:android-test-plugin-host-coverage-proto:30.2.0=classpath -com.android.tools.utp:android-test-plugin-host-retention-proto:30.2.0=classpath -com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:30.2.0=classpath -com.android.tools:annotations:30.2.0=classpath -com.android.tools:common:30.2.0=classpath -com.android.tools:dvlib:30.2.0=classpath -com.android.tools:repository:30.2.0=classpath -com.android.tools:sdk-common:30.2.0=classpath -com.android.tools:sdklib:30.2.0=classpath -com.android:signflinger:7.2.0=classpath -com.android:zipflinger:7.2.0=classpath -com.fasterxml.jackson.core:jackson-annotations:2.11.1=classpath -com.fasterxml.jackson.core:jackson-core:2.11.1=classpath -com.fasterxml.jackson.core:jackson-databind:2.11.1=classpath -com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.1=classpath -com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.11.1=classpath -com.fasterxml.jackson.module:jackson-module-kotlin:2.11.1=classpath -com.fasterxml.woodstox:woodstox-core:6.2.1=classpath -com.github.gundy:semver4j:0.16.4=classpath -com.google.android:annotations:4.1.1.4=classpath -com.google.api.grpc:proto-google-common-protos:1.12.0=classpath -com.google.auto.value:auto-value-annotations:1.6.2=classpath -com.google.code.findbugs:jsr305:3.0.2=classpath -com.google.code.gson:gson:2.8.6=classpath -com.google.crypto.tink:tink:1.3.0-rc2=classpath -com.google.dagger:dagger:2.28.3=classpath -com.google.errorprone:error_prone_annotations:2.3.4=classpath -com.google.flatbuffers:flatbuffers-java:1.12.0=classpath -com.google.guava:failureaccess:1.0.1=classpath -com.google.guava:guava:30.1-jre=classpath -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=classpath -com.google.j2objc:j2objc-annotations:1.3=classpath -com.google.jimfs:jimfs:1.1=classpath -com.google.protobuf:protobuf-java-util:3.10.0=classpath -com.google.protobuf:protobuf-java:3.10.0=classpath -com.google.testing.platform:core-proto:0.0.8-alpha07=classpath -com.googlecode.json-simple:json-simple:1.1=classpath -com.googlecode.juniversalchardet:juniversalchardet:1.0.3=classpath -com.squareup:javapoet:1.10.0=classpath -com.squareup:javawriter:2.5.0=classpath -com.sun.activation:javax.activation:1.2.0=classpath -com.sun.istack:istack-commons-runtime:3.0.8=classpath -com.sun.xml.fastinfoset:FastInfoset:1.2.16=classpath -commons-codec:commons-codec:1.11=classpath -commons-io:commons-io:2.4=classpath -commons-logging:commons-logging:1.2=classpath -de.undercouch:gradle-download-task:4.1.1=classpath -io.grpc:grpc-api:1.21.1=classpath -io.grpc:grpc-context:1.21.1=classpath -io.grpc:grpc-core:1.21.1=classpath -io.grpc:grpc-netty:1.21.1=classpath -io.grpc:grpc-protobuf-lite:1.21.1=classpath -io.grpc:grpc-protobuf:1.21.1=classpath -io.grpc:grpc-stub:1.21.1=classpath -io.netty:netty-buffer:4.1.34.Final=classpath -io.netty:netty-codec-http2:4.1.34.Final=classpath -io.netty:netty-codec-http:4.1.34.Final=classpath -io.netty:netty-codec-socks:4.1.34.Final=classpath -io.netty:netty-codec:4.1.34.Final=classpath -io.netty:netty-common:4.1.34.Final=classpath -io.netty:netty-handler-proxy:4.1.34.Final=classpath -io.netty:netty-handler:4.1.34.Final=classpath -io.netty:netty-resolver:4.1.34.Final=classpath -io.netty:netty-transport:4.1.34.Final=classpath -io.opencensus:opencensus-api:0.21.0=classpath -io.opencensus:opencensus-contrib-grpc-metrics:0.21.0=classpath -it.unimi.dsi:fastutil:8.4.0=classpath -jakarta.activation:jakarta.activation-api:1.2.1=classpath -jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=classpath -javax.inject:javax.inject:1=classpath -net.java.dev.jna:jna-platform:5.6.0=classpath -net.java.dev.jna:jna:5.6.0=classpath -net.sf.jopt-simple:jopt-simple:4.9=classpath -net.sf.kxml:kxml2:2.3.0=classpath -org.apache.commons:commons-compress:1.20=classpath -org.apache.httpcomponents:httpclient:4.5.9=classpath -org.apache.httpcomponents:httpcore:4.4.11=classpath -org.apache.httpcomponents:httpmime:4.5.6=classpath -org.bitbucket.b_c:jose4j:0.7.0=classpath -org.bouncycastle:bcpkix-jdk15on:1.56=classpath -org.bouncycastle:bcprov-jdk15on:1.56=classpath -org.checkerframework:checker-qual:3.5.0=classpath -org.codehaus.mojo:animal-sniffer-annotations:1.17=classpath -org.codehaus.woodstox:stax2-api:4.2.1=classpath -org.glassfish.jaxb:jaxb-runtime:2.3.2=classpath -org.glassfish.jaxb:txw2:2.3.2=classpath -org.jdom:jdom2:2.0.6=classpath -org.jetbrains.dokka:dokka-core:1.4.32=classpath -org.jetbrains.intellij.deps:trove4j:1.0.20181211=classpath -org.jetbrains.kotlin:kotlin-android-extensions:1.5.31=classpath -org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.5.31=classpath -org.jetbrains.kotlin:kotlin-build-common:1.5.31=classpath -org.jetbrains.kotlin:kotlin-compiler-embeddable:1.5.31=classpath -org.jetbrains.kotlin:kotlin-compiler-runner:1.5.31=classpath -org.jetbrains.kotlin:kotlin-daemon-client:1.5.31=classpath -org.jetbrains.kotlin:kotlin-daemon-embeddable:1.5.31=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.5.31=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.5.31=classpath -org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31=classpath -org.jetbrains.kotlin:kotlin-klib-commonizer-api:1.5.31=classpath -org.jetbrains.kotlin:kotlin-native-utils:1.5.31=classpath -org.jetbrains.kotlin:kotlin-project-model:1.5.31=classpath -org.jetbrains.kotlin:kotlin-reflect:1.5.31=classpath -org.jetbrains.kotlin:kotlin-scripting-common:1.5.31=classpath -org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.5.31=classpath -org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.5.31=classpath -org.jetbrains.kotlin:kotlin-scripting-jvm:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.31=classpath -org.jetbrains.kotlin:kotlin-stdlib:1.5.31=classpath -org.jetbrains.kotlin:kotlin-tooling-metadata:1.5.31=classpath -org.jetbrains.kotlin:kotlin-util-io:1.5.31=classpath -org.jetbrains.kotlin:kotlin-util-klib:1.5.31=classpath +org.jetbrains.intellij.deps:trove4j:1.0.20200330=classpath +org.jetbrains.kotlin:kotlin-android-extensions:1.9.0=classpath +org.jetbrains.kotlin:kotlin-build-tools-api:1.9.0=classpath +org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0=classpath +org.jetbrains.kotlin:kotlin-compiler-runner:1.9.0=classpath +org.jetbrains.kotlin:kotlin-daemon-client:1.9.0=classpath +org.jetbrains.kotlin:kotlin-daemon-embeddable:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-idea:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0=classpath +org.jetbrains.kotlin:kotlin-gradle-plugins-bom:1.9.0=classpath +org.jetbrains.kotlin:kotlin-klib-commonizer-api:1.9.0=classpath +org.jetbrains.kotlin:kotlin-native-utils:1.9.0=classpath +org.jetbrains.kotlin:kotlin-project-model:1.9.0=classpath +org.jetbrains.kotlin:kotlin-scripting-common:1.9.0=classpath +org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.9.0=classpath +org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.9.0=classpath +org.jetbrains.kotlin:kotlin-scripting-jvm:1.9.0=classpath +org.jetbrains.kotlin:kotlin-tooling-core:1.9.0=classpath +org.jetbrains.kotlin:kotlin-util-io:1.9.0=classpath +org.jetbrains.kotlin:kotlin-util-klib:1.9.0=classpath org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.0=classpath -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0=classpath -org.jetbrains:annotations:13.0=classpath -org.jetbrains:markdown-jvm:0.2.1=classpath -org.jetbrains:markdown:0.2.1=classpath -org.json:json:20180813=classpath -org.jsoup:jsoup:1.13.1=classpath -org.jvnet.staxex:stax-ex:1.8.1=classpath -org.ow2.asm:asm-analysis:9.1=classpath -org.ow2.asm:asm-commons:9.1=classpath -org.ow2.asm:asm-tree:9.1=classpath -org.ow2.asm:asm-util:9.1=classpath -org.ow2.asm:asm:9.1=classpath -org.slf4j:slf4j-api:1.7.30=classpath -org.tensorflow:tensorflow-lite-metadata:0.1.0-rc2=classpath -xerces:xercesImpl:2.12.0=classpath -xml-apis:xml-apis:1.4.01=classpath empty= diff --git a/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties b/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties index 3c472b99c6f35..ec915a81eb454 100644 --- a/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties +++ b/examples/hello_world/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-all.zip diff --git a/examples/hello_world/android/project-app.lockfile b/examples/hello_world/android/project-app.lockfile index e160a81ffd42a..0d87887fa38ec 100644 --- a/examples/hello_world/android/project-app.lockfile +++ b/examples/hello_world/android/project-app.lockfile @@ -87,10 +87,10 @@ org.codehaus.groovy:groovy-all:2.4.15=lintClassPath org.codehaus.mojo:animal-sniffer-annotations:1.18=lintClassPath org.glassfish.jaxb:jaxb-runtime:2.3.1=lintClassPath org.glassfish.jaxb:txw2:2.3.1=lintClassPath -org.jacoco:org.jacoco.agent:0.8.7=androidJacocoAnt -org.jacoco:org.jacoco.ant:0.8.7=androidJacocoAnt -org.jacoco:org.jacoco.core:0.8.7=androidJacocoAnt -org.jacoco:org.jacoco.report:0.8.7=androidJacocoAnt +org.jacoco:org.jacoco.agent:0.8.8=androidJacocoAnt +org.jacoco:org.jacoco.ant:0.8.8=androidJacocoAnt +org.jacoco:org.jacoco.core:0.8.8=androidJacocoAnt +org.jacoco:org.jacoco.report:0.8.8=androidJacocoAnt org.jetbrains.kotlin:kotlin-reflect:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72=lintClassPath org.jetbrains.kotlin:kotlin-stdlib-common:1.5.31=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath @@ -107,12 +107,12 @@ org.jetbrains.trove4j:trove4j:20160824=lintClassPath org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugCompileClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestRuntimeClasspath,lintClassPath,profileCompileClasspath,profileRuntimeClasspath,profileUnitTestCompileClasspath,profileUnitTestRuntimeClasspath,releaseCompileClasspath,releaseRuntimeClasspath,releaseUnitTestCompileClasspath,releaseUnitTestRuntimeClasspath org.jvnet.staxex:stax-ex:1.8=lintClassPath org.ow2.asm:asm-analysis:7.0=lintClassPath -org.ow2.asm:asm-analysis:9.1=androidJacocoAnt +org.ow2.asm:asm-analysis:9.2=androidJacocoAnt org.ow2.asm:asm-commons:7.0=lintClassPath -org.ow2.asm:asm-commons:9.1=androidJacocoAnt +org.ow2.asm:asm-commons:9.2=androidJacocoAnt org.ow2.asm:asm-tree:7.0=lintClassPath -org.ow2.asm:asm-tree:9.1=androidJacocoAnt +org.ow2.asm:asm-tree:9.2=androidJacocoAnt org.ow2.asm:asm-util:7.0=lintClassPath org.ow2.asm:asm:7.0=lintClassPath -org.ow2.asm:asm:9.1=androidJacocoAnt +org.ow2.asm:asm:9.2=androidJacocoAnt empty=androidApis,androidJdkImage,androidTestUtil,compile,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAndroidTestRuntimeClasspath,debugAnnotationProcessorClasspath,debugReverseMetadataValues,debugUnitTestAnnotationProcessorClasspath,debugWearBundling,lintChecks,lintPublish,profileAnnotationProcessorClasspath,profileReverseMetadataValues,profileUnitTestAnnotationProcessorClasspath,profileWearBundling,releaseAnnotationProcessorClasspath,releaseReverseMetadataValues,releaseUnitTestAnnotationProcessorClasspath,releaseWearBundling,testCompile diff --git a/examples/hello_world/android/settings.gradle b/examples/hello_world/android/settings.gradle index 4b92919bbe50f..47426ccdb58f8 100644 --- a/examples/hello_world/android/settings.gradle +++ b/examples/hello_world/android/settings.gradle @@ -19,6 +19,12 @@ pluginManagement { // Flutter Gradle Plugin ships together with the Flutter SDK includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + plugins { // Flutter Gradle Plugin's ID is defined in /packages/flutter_tools/gradle/build.gradle.kts. // We set `apply false`, because we don't want to apply the plugin to @@ -27,6 +33,9 @@ pluginManagement { } } -include ':app' +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.4.2" apply false +} -apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle" +include ':app' diff --git a/packages/flutter_tools/gradle/app_plugin_loader.gradle b/packages/flutter_tools/gradle/app_plugin_loader.gradle index e5cfe9ca55db4..fd450e6b1b4d9 100644 --- a/packages/flutter_tools/gradle/app_plugin_loader.gradle +++ b/packages/flutter_tools/gradle/app_plugin_loader.gradle @@ -2,35 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// This file is included from `<app>/android/settings.gradle`, -// so it can be versioned with the Flutter SDK. +// This file exists solely for the compatibility with projects that have +// not migrated to the declarative apply of the Flutter App Plugin Loader Gradle Plugin. -import groovy.json.JsonSlurper - -def flutterProjectRoot = rootProject.projectDir.parentFile - -// If this logic is changed, also change the logic in module_plugin_loader.gradle. -def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins-dependencies') -if (!pluginsFile.exists()) { - return -} - -def object = new JsonSlurper().parseText(pluginsFile.text) -assert object instanceof Map -assert object.plugins instanceof Map -assert object.plugins.android instanceof List -// Includes the Flutter plugins that support the Android platform. -object.plugins.android.each { androidPlugin -> - assert androidPlugin.name instanceof String - assert androidPlugin.path instanceof String - // Skip plugins that have no native build (such as a Dart-only implementation - // of a federated plugin). - def needsBuild = androidPlugin.containsKey('native_build') ? androidPlugin['native_build'] : true - if (!needsBuild) { - return - } - def pluginDirectory = new File(androidPlugin.path, 'android') - assert pluginDirectory.exists() - include ":${androidPlugin.name}" - project(":${androidPlugin.name}").projectDir = pluginDirectory -} +def pathToThisDirectory = buildscript.sourceFile.parentFile +apply from: "$pathToThisDirectory/src/main/groovy/app_plugin_loader.groovy" diff --git a/packages/flutter_tools/gradle/build.gradle.kts b/packages/flutter_tools/gradle/build.gradle.kts index 289693f9a478b..9c6cfdd98e8a5 100644 --- a/packages/flutter_tools/gradle/build.gradle.kts +++ b/packages/flutter_tools/gradle/build.gradle.kts @@ -3,12 +3,8 @@ // found in the LICENSE file. plugins { - `groovy-gradle-plugin` -} - -repositories { - google() - mavenCentral() + `java-gradle-plugin` + `groovy` } @@ -22,6 +18,10 @@ gradlePlugin { id = "dev.flutter.flutter-gradle-plugin" implementationClass = "FlutterPlugin" } + create("flutterAppPluginLoaderPlugin") { + id = "dev.flutter.flutter-plugin-loader" + implementationClass = "FlutterAppPluginLoaderPlugin" + } } } diff --git a/packages/flutter_tools/gradle/settings.gradle.kts b/packages/flutter_tools/gradle/settings.gradle.kts new file mode 100644 index 0000000000000..f8d3e87ffa2d7 --- /dev/null +++ b/packages/flutter_tools/gradle/settings.gradle.kts @@ -0,0 +1,7 @@ +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} diff --git a/packages/flutter_tools/gradle/src/main/groovy/app_plugin_loader.groovy b/packages/flutter_tools/gradle/src/main/groovy/app_plugin_loader.groovy new file mode 100644 index 0000000000000..402ab64e62271 --- /dev/null +++ b/packages/flutter_tools/gradle/src/main/groovy/app_plugin_loader.groovy @@ -0,0 +1,42 @@ +import groovy.json.JsonSlurper +import org.gradle.api.Plugin +import org.gradle.api.initialization.Settings + +apply plugin: FlutterAppPluginLoaderPlugin + +class FlutterAppPluginLoaderPlugin implements Plugin<Settings> { + // This string must match _kFlutterPluginsHasNativeBuildKey defined in + // packages/flutter_tools/lib/src/flutter_plugins.dart. + private final String nativeBuildKey = 'native_build' + + @Override + void apply(Settings settings) { + def flutterProjectRoot = settings.settingsDir.parentFile + + // If this logic is changed, also change the logic in module_plugin_loader.gradle. + def pluginsFile = new File(flutterProjectRoot, '.flutter-plugins-dependencies') + if (!pluginsFile.exists()) { + return + } + + def object = new JsonSlurper().parseText(pluginsFile.text) + assert object instanceof Map + assert object.plugins instanceof Map + assert object.plugins.android instanceof List + // Includes the Flutter plugins that support the Android platform. + object.plugins.android.each { androidPlugin -> + assert androidPlugin.name instanceof String + assert androidPlugin.path instanceof String + // Skip plugins that have no native build (such as a Dart-only implementation + // of a federated plugin). + def needsBuild = androidPlugin.containsKey(nativeBuildKey) ? androidPlugin[nativeBuildKey] : true + if (!needsBuild) { + return + } + def pluginDirectory = new File(androidPlugin.path, 'android') + assert pluginDirectory.exists() + settings.include(":${androidPlugin.name}") + settings.project(":${androidPlugin.name}").projectDir = pluginDirectory + } + } +} diff --git a/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl index 1411541a8d260..40c56e3454e02 100644 --- a/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-java.tmpl/build.gradle.tmpl @@ -6,7 +6,6 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:{{agpVersion}}' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl b/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl index 1411541a8d260..40c56e3454e02 100644 --- a/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl +++ b/packages/flutter_tools/templates/app_shared/android-kotlin.tmpl/build.gradle.tmpl @@ -6,7 +6,6 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:{{agpVersion}}' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/packages/flutter_tools/templates/app_shared/android.tmpl/settings.gradle b/packages/flutter_tools/templates/app_shared/android.tmpl/settings.gradle.tmpl similarity index 71% rename from packages/flutter_tools/templates/app_shared/android.tmpl/settings.gradle rename to packages/flutter_tools/templates/app_shared/android.tmpl/settings.gradle.tmpl index 55c4ca8b109a4..56f8773a953e3 100644 --- a/packages/flutter_tools/templates/app_shared/android.tmpl/settings.gradle +++ b/packages/flutter_tools/templates/app_shared/android.tmpl/settings.gradle.tmpl @@ -10,11 +10,20 @@ pluginManagement { includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + plugins { id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false } } -include ":app" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "{{agpVersion}}" apply false +} -apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle" +include ":app" diff --git a/packages/flutter_tools/templates/template_manifest.json b/packages/flutter_tools/templates/template_manifest.json index f7cc14a3b9573..b43e75d4228e6 100644 --- a/packages/flutter_tools/templates/template_manifest.json +++ b/packages/flutter_tools/templates/template_manifest.json @@ -36,6 +36,7 @@ "templates/app_shared/android.tmpl/app/src/main/res/values/styles.xml", "templates/app_shared/android.tmpl/app/src/profile/AndroidManifest.xml.tmpl", "templates/app_shared/android.tmpl/gradle.properties.tmpl", + "templates/app_shared/android.tmpl/settings.gradle.tmpl", "templates/app_shared/android.tmpl/gradle/wrapper/gradle-wrapper.properties.tmpl", "templates/app_shared/android.tmpl/settings.gradle", "templates/app_shared/ios-objc.tmpl/Runner.xcodeproj/project.pbxproj.tmpl", From 76a938bfa6d140529c35b4b4657d1984d15b9baa Mon Sep 17 00:00:00 2001 From: Ricardo Amador <32242716+ricardoamador@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:23:14 -0700 Subject: [PATCH 1423/1547] Reenable 'Linux packages_autoroller' in prod with kms key update (#135316) The Github token was recreated and uploaded to GCS. I have verified a passing run with the new key here: https://luci-milo.appspot.com/raw/build/logs.chromium.org/flutter/led/ricardoamador_google.com/bc5d1e66627ad6b9f58d2dc85b7524692520e83858132b9e92ff8d3166b1b7e5/+/build.proto And the bot is now generating pull requests: https://github.com/flutter/flutter/pull/135315 *List which issues are fixed by this PR. You must list at least one issue.* Fixes https://github.com/flutter/flutter/issues/131968 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 7c00866d0cd6c..05695660b3172 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -256,7 +256,6 @@ targets: presubmit: false recipe: pub_autoroller/pub_autoroller timeout: 30 - bringup: true # https://github.com/flutter/flutter/issues/131968 enabled_branches: # Don't run this on release branches - master From a09b1e43b14349627b63ddba571a8cf42c60c714 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 15:25:24 -0400 Subject: [PATCH 1424/1547] Roll Flutter Engine from ef9ceed1af08 to 92be04f73d5d (3 revisions) (#135319) https://github.com/flutter/engine/compare/ef9ceed1af08...92be04f73d5d 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 8beae2053939 to fe73688dc40f (1 revision) (flutter/engine#46202) 2023-09-22 matanlurey@users.noreply.github.com Enable checking headers with Clang Tidy. (flutter/engine#46009) 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from f346a813ffd4 to 8beae2053939 (5 revisions) (flutter/engine#46200) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5f09714afdae7..76d9f332e436a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ef9ceed1af0866c5e194ae52da6e5f82ce6a83b3 +92be04f73d5db4788e04b3b51a88b8edd9fc2079 From 9fe6ed15f7b3f443305a7e271ad76bb6684c3f5d Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Fri, 22 Sep 2023 12:28:54 -0700 Subject: [PATCH 1425/1547] Roll pub packages (#135315) This PR was generated by `flutter update-packages --force-upgrade`. --- packages/flutter_tools/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index a69a7465fd877..4a2e14dd4dfa8 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -69,7 +69,7 @@ dependencies: analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" built_collection: 5.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - built_value: 8.6.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + built_value: 8.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" clock: 1.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" csslib: 1.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dap: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -112,4 +112,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 807a +# PUBSPEC CHECKSUM: 887b From 99ac6b8164fd9197a1e25a4e28400c1deb22c3fb Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Fri, 22 Sep 2023 13:44:04 -0700 Subject: [PATCH 1426/1547] _RenderChip should not create OpacityLayer without disposing. (#134708) --- packages/flutter/lib/src/material/chip.dart | 12 +++++++++++- packages/flutter/test/material/chip_test.dart | 7 +------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index 7c1132dfd8615..cbccb25ea2066 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -2034,6 +2034,8 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } } + final LayerHandle<OpacityLayer> _avatarOpacityLayerHandler = LayerHandle<OpacityLayer>(); + void _paintAvatar(PaintingContext context, Offset offset) { void paintWithOverlay(PaintingContext context, Offset offset) { context.paintChild(avatar!, _boxParentData(avatar!).offset + offset); @@ -2041,13 +2043,15 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } if (!theme.showAvatar && avatarDrawerAnimation.isDismissed) { + _avatarOpacityLayerHandler.layer = null; return; } final Color disabledColor = _disabledColor; final int disabledColorAlpha = disabledColor.alpha; if (needsCompositing) { - context.pushLayer(OpacityLayer(alpha: disabledColorAlpha), paintWithOverlay, offset); + _avatarOpacityLayerHandler.layer = context.pushOpacity(offset, disabledColorAlpha, paintWithOverlay, oldLayer: _avatarOpacityLayerHandler.layer); } else { + _avatarOpacityLayerHandler.layer = null; if (disabledColorAlpha != 0xff) { context.canvas.saveLayer( _boxRect(avatar).shift(offset).inflate(20.0), @@ -2086,6 +2090,12 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } } + @override + void dispose() { + _avatarOpacityLayerHandler.layer = null; + super.dispose(); + } + @override void paint(PaintingContext context, Offset offset) { _paintAvatar(context, offset); diff --git a/packages/flutter/test/material/chip_test.dart b/packages/flutter/test/material/chip_test.dart index d95f4fbad7a24..8b9b923a1cbc0 100644 --- a/packages/flutter/test/material/chip_test.dart +++ b/packages/flutter/test/material/chip_test.dart @@ -290,12 +290,7 @@ void main() { expect(labelStyle.overflow, textTheme.bodyLarge?.overflow); expect(labelStyle.textBaseline, textTheme.bodyLarge?.textBaseline); expect(labelStyle.wordSpacing, textTheme.bodyLarge?.wordSpacing); - }, - // TODO(polina-c): remove after fixing - // https://github.com/flutter/flutter/issues/134394 - leakTrackingTestConfig: const LeakTrackingTestConfig( - notDisposedAllowList: <String, int?>{'OpacityLayer': 2}, - )); + }); testWidgetsWithLeakTracking('M3 Chip defaults', (WidgetTester tester) async { late TextTheme textTheme; From feb6d6ed3dee3f7658724c566a616f6ccf26a2da Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 17:17:50 -0400 Subject: [PATCH 1427/1547] Roll Flutter Engine from 92be04f73d5d to 954ea95be336 (2 revisions) (#135325) https://github.com/flutter/engine/compare/92be04f73d5d...954ea95be336 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from fe73688dc40f to 8a1e6e5844d7 (1 revision) (flutter/engine#46205) 2023-09-22 jonahwilliams@google.com [Impeller] Reland: construct text frames on UI thread. (flutter/engine#46115) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 76d9f332e436a..7435040ffc2ef 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -92be04f73d5db4788e04b3b51a88b8edd9fc2079 +954ea95be3361e4749904f11284cc9b80e793b5b From 579e196073e97815f77f4cc1fd7778499e648136 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Fri, 22 Sep 2023 14:55:28 -0700 Subject: [PATCH 1428/1547] Stop reporting new_gen_gc_count to SkiaPerf (#135324) Movement in this metric is mostly noise, creates many false alerts, and is neither the cause nor effect of changes in other metrics. --- dev/devicelab/lib/tasks/perf_tests.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 9018dfda43819..1dc73382bfab7 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -1357,7 +1357,6 @@ const List<String> _kCommonScoreKeys = <String>[ '90th_percentile_picture_cache_memory', '99th_percentile_picture_cache_memory', 'worst_picture_cache_memory', - 'new_gen_gc_count', 'old_gen_gc_count', ]; From a4e3f93367a13c12e3e1d5f048c66b7cb3bdba6d Mon Sep 17 00:00:00 2001 From: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Date: Sat, 23 Sep 2023 00:26:25 +0200 Subject: [PATCH 1429/1547] Fix memory leak in _MatchesReferenceImage (#135150) --- packages/flutter_test/lib/src/matchers.dart | 44 ++++--- packages/flutter_test/pubspec.yaml | 40 ++++++- .../test/reference_image_test.dart | 112 +++++++++++++++--- 3 files changed, 161 insertions(+), 35 deletions(-) diff --git a/packages/flutter_test/lib/src/matchers.dart b/packages/flutter_test/lib/src/matchers.dart index 9742411bee12e..85087dc5e636b 100644 --- a/packages/flutter_test/lib/src/matchers.dart +++ b/packages/flutter_test/lib/src/matchers.dart @@ -576,7 +576,9 @@ AsyncMatcher matchesGoldenFile(Object key, {int? version}) { /// final ui.Canvas pictureCanvas = ui.Canvas(recorder); /// pictureCanvas.drawCircle(Offset.zero, 20.0, paint); /// final ui.Picture picture = recorder.endRecording(); +/// addTearDown(picture.dispose); /// ui.Image referenceImage = await picture.toImage(50, 50); +/// addTearDown(referenceImage.dispose); /// /// await expectLater(find.text('Save'), matchesReferenceImage(referenceImage)); /// await expectLater(image, matchesReferenceImage(referenceImage)); @@ -2139,10 +2141,13 @@ class _MatchesReferenceImage extends AsyncMatcher { @override Future<String?> matchAsync(dynamic item) async { Future<ui.Image> imageFuture; + final bool disposeImage; // set to true if the matcher created and owns the image and must therefore dispose it. if (item is Future<ui.Image>) { imageFuture = item; + disposeImage = false; } else if (item is ui.Image) { imageFuture = Future<ui.Image>.value(item); + disposeImage = false; } else { final Finder finder = item as Finder; final Iterable<Element> elements = finder.evaluate(); @@ -2152,30 +2157,37 @@ class _MatchesReferenceImage extends AsyncMatcher { return 'matched too many widgets'; } imageFuture = captureImage(elements.single); + disposeImage = true; } final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance; return binding.runAsync<String?>(() async { final ui.Image image = await imageFuture; - final ByteData? bytes = await image.toByteData(); - if (bytes == null) { - return 'could not be encoded.'; - } + try { + final ByteData? bytes = await image.toByteData(); + if (bytes == null) { + return 'could not be encoded.'; + } - final ByteData? referenceBytes = await referenceImage.toByteData(); - if (referenceBytes == null) { - return 'could not have its reference image encoded.'; - } + final ByteData? referenceBytes = await referenceImage.toByteData(); + if (referenceBytes == null) { + return 'could not have its reference image encoded.'; + } - if (referenceImage.height != image.height || referenceImage.width != image.width) { - return 'does not match as width or height do not match. $image != $referenceImage'; - } + if (referenceImage.height != image.height || referenceImage.width != image.width) { + return 'does not match as width or height do not match. $image != $referenceImage'; + } - final int countDifferentPixels = _countDifferentPixels( - Uint8List.view(bytes.buffer), - Uint8List.view(referenceBytes.buffer), - ); - return countDifferentPixels == 0 ? null : 'does not match on $countDifferentPixels pixels'; + final int countDifferentPixels = _countDifferentPixels( + Uint8List.view(bytes.buffer), + Uint8List.view(referenceBytes.buffer), + ); + return countDifferentPixels == 0 ? null : 'does not match on $countDifferentPixels pixels'; + } finally { + if (disposeImage) { + image.dispose(); + } + } }); } diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index 3eac57c97eb47..f71a48991d1cd 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -44,5 +44,43 @@ dependencies: dev_dependencies: file: 6.1.4 + # Used to detect memory leaks. + leak_tracker_flutter_testing: 1.0.5 -# PUBSPEC CHECKSUM: 9e5d + _fe_analyzer_shared: 64.0.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + analyzer: 6.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + args: 2.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + convert: 3.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + coverage: 1.6.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + crypto: 3.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + frontend_server_client: 3.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + glob: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_multi_server: 3.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + http_parser: 4.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + intl: 0.18.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + io: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + js: 0.6.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + leak_tracker: 9.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + leak_tracker_testing: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + logging: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + mime: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + node_preamble: 2.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + package_config: 2.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pool: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + pub_semver: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf: 1.4.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_packages_handler: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_static: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + shelf_web_socket: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_map_stack_trace: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + source_maps: 0.10.12 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test: 1.24.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + test_core: 0.5.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + +# PUBSPEC CHECKSUM: aa8d diff --git a/packages/flutter_test/test/reference_image_test.dart b/packages/flutter_test/test/reference_image_test.dart index add664c4bbd65..8be052337cdc3 100644 --- a/packages/flutter_test/test/reference_image_test.dart +++ b/packages/flutter_test/test/reference_image_test.dart @@ -4,9 +4,12 @@ import 'dart:ui' as ui; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; -Future<ui.Image> createTestImage(int width, int height, ui.Color color) { +Future<ui.Image> createTestImage(int width, int height, ui.Color color) async { final ui.Paint paint = ui.Paint() ..style = ui.PaintingStyle.stroke ..strokeWidth = 1.0 @@ -15,7 +18,9 @@ Future<ui.Image> createTestImage(int width, int height, ui.Color color) { final ui.Canvas pictureCanvas = ui.Canvas(recorder); pictureCanvas.drawCircle(Offset.zero, 20.0, paint); final ui.Picture picture = recorder.endRecording(); - return picture.toImage(width, height); + final ui.Image image = await picture.toImage(width, height); + picture.dispose(); + return image; } void main() { @@ -24,50 +29,121 @@ void main() { const ui.Color transparentRed = ui.Color.fromARGB(128, 255, 0, 0); group('succeeds', () { - testWidgets('when images have the same content', (WidgetTester tester) async { - await expectLater( - await createTestImage(100, 100, red), - matchesReferenceImage(await createTestImage(100, 100, red)), - ); - await expectLater( - await createTestImage(100, 100, green), - matchesReferenceImage(await createTestImage(100, 100, green)), - ); + testWidgetsWithLeakTracking('when images have the same content', (WidgetTester tester) async { + final ui.Image image1 = await createTestImage(100, 100, red); + addTearDown(image1.dispose); + final ui.Image referenceImage1 = await createTestImage(100, 100, red); + addTearDown(referenceImage1.dispose); - await expectLater( - await createTestImage(100, 100, transparentRed), - matchesReferenceImage(await createTestImage(100, 100, transparentRed)), - ); + await expectLater(image1, matchesReferenceImage(referenceImage1)); + + final ui.Image image2 = await createTestImage(100, 100, green); + addTearDown(image2.dispose); + final ui.Image referenceImage2 = await createTestImage(100, 100, green); + addTearDown(referenceImage2.dispose); + + await expectLater(image2, matchesReferenceImage(referenceImage2)); + + final ui.Image image3 = await createTestImage(100, 100, transparentRed); + addTearDown(image3.dispose); + final ui.Image referenceImage3 = await createTestImage(100, 100, transparentRed); + addTearDown(referenceImage3.dispose); + + await expectLater(image3, matchesReferenceImage(referenceImage3)); }); - testWidgets('when images are identical', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when images are identical', (WidgetTester tester) async { final ui.Image image = await createTestImage(100, 100, red); + addTearDown(image.dispose); await expectLater(image, matchesReferenceImage(image)); }); + + testWidgetsWithLeakTracking('when widget looks the same', (WidgetTester tester) async { + addTearDown(tester.view.reset); + tester.view + ..physicalSize = const Size(10, 10) + ..devicePixelRatio = 1; + + const ValueKey<String> repaintBoundaryKey = ValueKey<String>('boundary'); + + await tester.pumpWidget( + const RepaintBoundary( + key: repaintBoundaryKey, + child: ColoredBox(color: red), + ), + ); + + final ui.Image referenceImage = (tester.renderObject(find.byKey(repaintBoundaryKey)) as RenderRepaintBoundary).toImageSync(); + addTearDown(referenceImage.dispose); + + await expectLater(find.byKey(repaintBoundaryKey), matchesReferenceImage(referenceImage)); + }); }); group('fails', () { - testWidgets('when image sizes do not match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when image sizes do not match', (WidgetTester tester) async { final ui.Image red50 = await createTestImage(50, 50, red); + addTearDown(red50.dispose); final ui.Image red100 = await createTestImage(100, 100, red); + addTearDown(red100.dispose); + expect( await matchesReferenceImage(red50).matchAsync(red100), equals('does not match as width or height do not match. [100×100] != [50×50]'), ); }); - testWidgets('when image pixels do not match', (WidgetTester tester) async { + testWidgetsWithLeakTracking('when image pixels do not match', (WidgetTester tester) async { final ui.Image red100 = await createTestImage(100, 100, red); + addTearDown(red100.dispose); final ui.Image transparentRed100 = await createTestImage(100, 100, transparentRed); + addTearDown(transparentRed100.dispose); + expect( await matchesReferenceImage(red100).matchAsync(transparentRed100), equals('does not match on 57 pixels'), ); + final ui.Image green100 = await createTestImage(100, 100, green); + addTearDown(green100.dispose); + expect( await matchesReferenceImage(red100).matchAsync(green100), equals('does not match on 57 pixels'), ); }); + + testWidgetsWithLeakTracking('when widget does not look the same', (WidgetTester tester) async { + addTearDown(tester.view.reset); + tester.view + ..physicalSize = const Size(10, 10) + ..devicePixelRatio = 1; + + const ValueKey<String> repaintBoundaryKey = ValueKey<String>('boundary'); + + await tester.pumpWidget( + const RepaintBoundary( + key: repaintBoundaryKey, + child: ColoredBox(color: red), + ), + ); + + final ui.Image referenceImage = (tester.renderObject(find.byKey(repaintBoundaryKey)) as RenderRepaintBoundary).toImageSync(); + addTearDown(referenceImage.dispose); + + await tester.pumpWidget( + const RepaintBoundary( + key: repaintBoundaryKey, + child: ColoredBox(color: green), + ), + ); + + expect( + await matchesReferenceImage(referenceImage).matchAsync( + find.byKey(repaintBoundaryKey), + ), + equals('does not match on 100 pixels'), + ); + }); }); } From c00e9798ff8a25ff48f9459979df2c479d6eaa06 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Fri, 22 Sep 2023 15:26:52 -0700 Subject: [PATCH 1430/1547] Fix _paintAvatar in chip.dart to dispose layer. (#135228) --- packages/flutter/lib/src/material/chip.dart | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/chip.dart b/packages/flutter/lib/src/material/chip.dart index cbccb25ea2066..757c64269e489 100644 --- a/packages/flutter/lib/src/material/chip.dart +++ b/packages/flutter/lib/src/material/chip.dart @@ -2065,21 +2065,26 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip } } + final LayerHandle<OpacityLayer> _childOpacityLayerHandler = LayerHandle<OpacityLayer>(); + void _paintChild(PaintingContext context, Offset offset, RenderBox? child, bool? isEnabled) { if (child == null) { + _childOpacityLayerHandler.layer = null; return; } final int disabledColorAlpha = _disabledColor.alpha; if (!enableAnimation.isCompleted) { if (needsCompositing) { - context.pushLayer( - OpacityLayer(alpha: disabledColorAlpha), + _childOpacityLayerHandler.layer = context.pushOpacity( + offset, + disabledColorAlpha, (PaintingContext context, Offset offset) { context.paintChild(child, _boxParentData(child).offset + offset); }, - offset, + oldLayer: _childOpacityLayerHandler.layer, ); } else { + _childOpacityLayerHandler.layer = null; final Rect childRect = _boxRect(child).shift(offset); context.canvas.saveLayer(childRect.inflate(20.0), Paint()..color = _disabledColor); context.paintChild(child, _boxParentData(child).offset + offset); @@ -2092,6 +2097,7 @@ class _RenderChip extends RenderBox with SlottedContainerRenderObjectMixin<_Chip @override void dispose() { + _childOpacityLayerHandler.layer = null; _avatarOpacityLayerHandler.layer = null; super.dispose(); } From 49e16867a327ff2e94c3ffbd7d345cad8e07e9a8 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Fri, 22 Sep 2023 15:27:05 -0700 Subject: [PATCH 1431/1547] TabController should dispatch creation in constructor. (#133952) --- .../flutter/lib/src/material/tab_controller.dart | 7 ++++++- packages/flutter/lib/src/material/tabs.dart | 1 + .../test/material/page_selector_test.dart | 6 ++++++ .../test/material/tab_controller_test.dart | 16 ++++++++++++++++ .../flutter/test/widgets/framework_test.dart | 2 +- .../flutter/test/widgets/scrollable_test.dart | 2 +- 6 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 packages/flutter/test/material/tab_controller_test.dart diff --git a/packages/flutter/lib/src/material/tab_controller.dart b/packages/flutter/lib/src/material/tab_controller.dart index 3e1bbe362c4a4..ea740eac50c5d 100644 --- a/packages/flutter/lib/src/material/tab_controller.dart +++ b/packages/flutter/lib/src/material/tab_controller.dart @@ -6,6 +6,7 @@ import 'dart:math' as math; import 'package:flutter/widgets.dart'; +import '../foundation/memory_allocations.dart'; import 'constants.dart'; // Examples can assume: @@ -114,7 +115,11 @@ class TabController extends ChangeNotifier { _animationController = AnimationController.unbounded( value: initialIndex.toDouble(), vsync: vsync, - ); + ) { + if (kFlutterMemoryAllocationsEnabled) { + ChangeNotifier.maybeDispatchObjectCreation(this); + } + } // Private constructor used by `_copyWith`. This allows a new TabController to // be created without having to create a new animationController. diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 9976dd21e30d3..5ee5e6116778e 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -1380,6 +1380,7 @@ class _TabBarState extends State<TabBar> { _controller!.removeListener(_handleTabControllerTick); } _controller = null; + _scrollController?.dispose(); // We don't own the _controller Animation, so it's not disposed here. super.dispose(); } diff --git a/packages/flutter/test/material/page_selector_test.dart b/packages/flutter/test/material/page_selector_test.dart index b1bf60008c4d1..27da67f09402f 100644 --- a/packages/flutter/test/material/page_selector_test.dart +++ b/packages/flutter/test/material/page_selector_test.dart @@ -70,6 +70,7 @@ void main() { vsync: const TestVSync(), length: 3, ); + addTearDown(tabController.dispose); await tester.pumpWidget(buildFrame(tabController)); expect(tabController.index, 0); @@ -91,6 +92,7 @@ void main() { vsync: const TestVSync(), length: 3, ); + addTearDown(tabController.dispose); await tester.pumpWidget(buildFrame(tabController)); expect(tabController.index, 0); @@ -135,6 +137,7 @@ void main() { initialIndex: 1, length: 3, ); + addTearDown(tabController.dispose); await tester.pumpWidget(buildFrame(tabController)); expect(tabController.index, 1); @@ -196,6 +199,7 @@ void main() { initialIndex: 1, length: 3, ); + addTearDown(tabController.dispose); await tester.pumpWidget(buildFrame(tabController, color: kRed, selectedColor: kBlue)); expect(tabController.index, 1); @@ -212,6 +216,7 @@ void main() { initialIndex: 1, length: 3, ); + addTearDown(tabController.dispose); await tester.pumpWidget(buildFrame(tabController, indicatorSize: 16.0)); final Iterable<Element> indicatorElements = find.descendant( @@ -233,6 +238,7 @@ void main() { initialIndex: 1, length: 3, ); + addTearDown(tabController.dispose); Iterable<TabPageSelectorIndicator> indicators; diff --git a/packages/flutter/test/material/tab_controller_test.dart b/packages/flutter/test/material/tab_controller_test.dart new file mode 100644 index 0000000000000..50d266e812005 --- /dev/null +++ b/packages/flutter/test/material/tab_controller_test.dart @@ -0,0 +1,16 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; + +void main() { + testWidgetsWithLeakTracking('$TabController dispatches creation in constructor.', (WidgetTester widgetTester) async { + await expectLater( + await memoryEvents(() async => TabController(length: 1, vsync: const TestVSync()).dispose(), TabController), + areCreateAndDispose, + ); + }); +} diff --git a/packages/flutter/test/widgets/framework_test.dart b/packages/flutter/test/widgets/framework_test.dart index bfa44287a29fd..d66f3466911b6 100644 --- a/packages/flutter/test/widgets/framework_test.dart +++ b/packages/flutter/test/widgets/framework_test.dart @@ -1062,7 +1062,7 @@ void main() { element.createChild(0, after: null); }); - testWidgetsWithLeakTracking('GlobalKey - re-attach child to new parents, and the old parent is deactivated(unmounted)', (WidgetTester tester) async { + testWidgets('GlobalKey - re-attach child to new parents, and the old parent is deactivated(unmounted)', (WidgetTester tester) async { // This is a regression test for https://github.com/flutter/flutter/issues/62055 const Key key1 = GlobalObjectKey('key1'); const Key key2 = GlobalObjectKey('key2'); diff --git a/packages/flutter/test/widgets/scrollable_test.dart b/packages/flutter/test/widgets/scrollable_test.dart index 93efe9ff89853..e7576552f6b24 100644 --- a/packages/flutter/test/widgets/scrollable_test.dart +++ b/packages/flutter/test/widgets/scrollable_test.dart @@ -861,7 +861,7 @@ void main() { expect(targetMidLeftPage1, findsOneWidget); }); - testWidgetsWithLeakTracking('ensureVisible does not move TabViews', (WidgetTester tester) async { + testWidgets('ensureVisible does not move TabViews', (WidgetTester tester) async { final TickerProvider vsync = TestTickerProvider(); final TabController controller = TabController( length: 3, From 57ccf3a594d629b6d3dd3e4c8137f0e78a1cb92c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Fri, 22 Sep 2023 18:30:22 -0400 Subject: [PATCH 1432/1547] Roll Flutter Engine from 954ea95be336 to e4bfdc1a67de (1 revision) (#135332) https://github.com/flutter/engine/compare/954ea95be336...e4bfdc1a67de 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 8a1e6e5844d7 to 78fced84372d (4 revisions) (flutter/engine#46207) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7435040ffc2ef..6a3d719e5d3d1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -954ea95be3361e4749904f11284cc9b80e793b5b +e4bfdc1a67de2ee07ab8f192e41c5f6d02f578cc From 1d769955b0dff4b6fd6adf7ee526ec46cb2b9b50 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Fri, 22 Sep 2023 17:30:02 -0700 Subject: [PATCH 1433/1547] Convert relative to absolute import. (#135337) Requested here: https://github.com/flutter/flutter/pull/133952#discussion_r1334860858 --- packages/flutter/lib/src/material/tab_controller.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/material/tab_controller.dart b/packages/flutter/lib/src/material/tab_controller.dart index ea740eac50c5d..507b74288e86b 100644 --- a/packages/flutter/lib/src/material/tab_controller.dart +++ b/packages/flutter/lib/src/material/tab_controller.dart @@ -4,9 +4,9 @@ import 'dart:math' as math; +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import '../foundation/memory_allocations.dart'; import 'constants.dart'; // Examples can assume: From 70fd3350414355df05e9a9fb75faa161b90f1665 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:32:16 -0700 Subject: [PATCH 1434/1547] Move some tests from staging to prod (#135333) This PR moves tests running on Pixel 7 Pro that use Skia from staging to prod. --- .ci.yaml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 05695660b3172..9d63daff79f16 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1722,17 +1722,16 @@ targets: - name: Linux_pixel_7pro backdrop_filter_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > ["devicelab", "android", "linux", "pixel", "7pro"] task_name: backdrop_filter_perf__timeline_summary - - name: Linux_pixel_7pro draw_atlas_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -1744,6 +1743,7 @@ targets: - name: Linux_pixel_7pro draw_atlas_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -1755,6 +1755,7 @@ targets: - name: Linux_pixel_7pro dynamic_path_tessellation_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -1766,6 +1767,7 @@ targets: - name: Linux_pixel_7pro static_path_tessellation_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -1777,6 +1779,7 @@ targets: - name: Linux_pixel_7pro hello_world_impeller recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -1959,7 +1962,6 @@ targets: - name: Linux_pixel_7pro cubic_bezier_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > @@ -1978,7 +1980,6 @@ targets: - name: Linux_pixel_7pro cull_opacity_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > @@ -2250,7 +2251,6 @@ targets: - name: Linux_pixel_7pro imagefiltered_transform_animation_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > @@ -2556,7 +2556,6 @@ targets: - name: Linux_pixel_7pro platform_views_scroll_perf__timeline_summary recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 60 properties: @@ -2625,7 +2624,6 @@ targets: - name: Linux_pixel_7pro textfield_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > @@ -2767,6 +2765,7 @@ targets: - name: Linux_pixel_7pro animated_blur_backdrop_filter_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -2778,6 +2777,7 @@ targets: - name: Linux_pixel_7pro animated_advanced_blend_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -2789,6 +2789,7 @@ targets: - name: Linux_pixel_7pro animated_advanced_blend_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -2810,6 +2811,7 @@ targets: - name: Linux_pixel_7pro animated_blur_backdrop_filter_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: @@ -2821,6 +2823,7 @@ targets: - name: Linux_pixel_7pro draw_vertices_perf_opengles__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller bringup: true timeout: 60 properties: @@ -2832,6 +2835,7 @@ targets: - name: Linux_pixel_7pro draw_vertices_perf__timeline_summary recipe: devicelab/devicelab_drone presubmit: false + # Uses Impeller. bringup: true timeout: 60 properties: From 6379648b7241631a665b7660e1b1e7421af8ad93 Mon Sep 17 00:00:00 2001 From: Chris Bracken <chris@bracken.jp> Date: Sat, 23 Sep 2023 01:57:21 +0100 Subject: [PATCH 1435/1547] [iOS,macOS] Clean up obsolete PlatformView warning (#135040) PlatformViews have been supported without a custom engine build on iOS for quite some time now, and are nearing support for macOS. Adds a link to the website documentation covering creation of PlatformViews for iOS and adds a TODO to do the same once the macOS PlatformView documentation is ready. Related: https://github.com/flutter/website/issues/9424 --- packages/flutter/lib/src/services/platform_views.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/services/platform_views.dart b/packages/flutter/lib/src/services/platform_views.dart index 0fb1144838274..bb3c19f756231 100644 --- a/packages/flutter/lib/src/services/platform_views.dart +++ b/packages/flutter/lib/src/services/platform_views.dart @@ -201,11 +201,7 @@ class PlatformViewsService { return controller; } - // TODO(amirh): reference the iOS plugin API for registering a UIView factory - // once it lands. - - /// This is work in progress, not yet ready to be used, and requires a custom - /// engine build. Creates a controller for a new iOS UIView. + /// Factory method to create a `UiKitView`. /// /// The `id` parameter is an unused unique identifier generated with /// [platformViewsRegistry]. @@ -218,6 +214,8 @@ class PlatformViewsService { /// The `onFocus` parameter is a callback that will be invoked when the UIKit /// view asks to get the input focus. If `creationParams` is non null then /// `creationParamsCodec` must not be null. + /// + /// See: https://docs.flutter.dev/platform-integration/ios/platform-views static Future<UiKitViewController> initUiKitView({ required int id, required String viewType, @@ -249,6 +247,8 @@ class PlatformViewsService { return UiKitViewController._(id, layoutDirection); } + // TODO(cbracken): Write and link website docs. https://github.com/flutter/website/issues/9424. + // /// Factory method to create an `AppKitView`. /// /// The `id` parameter is an unused unique identifier generated with From f5d91854bbd31311d455ba5efa6d72e4639e3caa Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 23 Sep 2023 13:15:28 -0400 Subject: [PATCH 1436/1547] Roll Flutter Engine from e4bfdc1a67de to 564480337eae (4 revisions) (#135341) https://github.com/flutter/engine/compare/e4bfdc1a67de...564480337eae 2023-09-22 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from ZyajVWocCHVIuJkzM... to M9rDyhmn7VY4iTxzQ... (flutter/engine#46215) 2023-09-22 skia-flutter-autoroll@skia.org Roll Dart SDK from 4ddff752a6b0 to 692273b46610 (1 revision) (flutter/engine#46212) 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from 78fced84372d to e9358f92110c (4 revisions) (flutter/engine#46211) 2023-09-22 bdero@google.com [Impeller] Incorporate backdrop filters in subpass coverage. (flutter/engine#46130) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from ZyajVWocCHVI to M9rDyhmn7VY4 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 6a3d719e5d3d1..d3e0360fdcc9b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e4bfdc1a67de2ee07ab8f192e41c5f6d02f578cc +564480337eaef9762089c85c89f1ebf877de5539 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 20a51c3538ef9..7fd9c9abe9f77 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -ZyajVWocCHVIuJkzM88O4Ss5WHqZcTNDl7K2YwixdMwC +M9rDyhmn7VY4iTxzQo1aLY0ssV6IYwx61YrXw9IOomAC From 7671627207a13cd2350a6806080a8a4a69fa172d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 23 Sep 2023 14:55:34 -0400 Subject: [PATCH 1437/1547] Roll Flutter Engine from 564480337eae to 614859053262 (7 revisions) (#135362) https://github.com/flutter/engine/compare/564480337eae...614859053262 2023-09-23 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from M9rDyhmn7VY4iTxzQ... to de4D1aoqF6LBk18Rd... (flutter/engine#46229) 2023-09-23 ychris@google.com [ios] Fix default assets url (flutter/engine#46214) 2023-09-23 skia-flutter-autoroll@skia.org Roll Skia from 15ccdeaba011 to 983f42f4c76b (1 revision) (flutter/engine#46223) 2023-09-23 chillers@google.com Revert "[Impeller] fail if software backend is chosen and Impeller is enabled on iOS" (flutter/engine#46217) 2023-09-23 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from QcxgV9KlY7j3o3b4j... to PCEkaltiQ-iEKlmEj... (flutter/engine#46221) 2023-09-22 jonahwilliams@google.com [Impeller] dont treat non-rects as rects. (flutter/engine#46218) 2023-09-22 skia-flutter-autoroll@skia.org Roll Skia from e9358f92110c to 15ccdeaba011 (1 revision) (flutter/engine#46216) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from QcxgV9KlY7j3 to PCEkaltiQ-iE fuchsia/sdk/core/mac-amd64 from M9rDyhmn7VY4 to de4D1aoqF6LB If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d3e0360fdcc9b..2df4c483b5cbe 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -564480337eaef9762089c85c89f1ebf877de5539 +61485905326222ba1cfe26af74533c71eced5aac diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 4ef97df9126d1..b40dd33665c4c 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -QcxgV9KlY7j3o3b4jzhzTH7yw1xDUfdSnU0UXLuoQEYC +PCEkaltiQ-iEKlmEj87_RYerXAUaDmwE-bHTqz-I8jMC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 7fd9c9abe9f77..6fab34ae4b516 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -M9rDyhmn7VY4iTxzQo1aLY0ssV6IYwx61YrXw9IOomAC +de4D1aoqF6LBk18Rdjpzg5wqU3L3U2RCowLPHUUmnVMC From 69004a896c24d1b7381f833ad7239558e227ccc3 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sat, 23 Sep 2023 15:39:27 -0400 Subject: [PATCH 1438/1547] Roll Flutter Engine from 614859053262 to ee27600dfbe2 (1 revision) (#135364) https://github.com/flutter/engine/compare/614859053262...ee27600dfbe2 2023-09-23 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from PCEkaltiQ-iEKlmEj... to M-fNM9YP2Lpc8Y_Dj... (flutter/engine#46231) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from PCEkaltiQ-iE to M-fNM9YP2Lpc If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 2df4c483b5cbe..ef816f1c4baf1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -61485905326222ba1cfe26af74533c71eced5aac +ee27600dfbe2919fa048cba5a197d423c8b073d6 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index b40dd33665c4c..f2a99d7e669d8 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -PCEkaltiQ-iEKlmEj87_RYerXAUaDmwE-bHTqz-I8jMC +M-fNM9YP2Lpc8Y_Dj7W2nZ4xcbMR2TFzh0DY-bGs0MEC From 6d88ade70af6a7d0b961b14058a9f9283999337a Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 16:03:13 -0700 Subject: [PATCH 1439/1547] Marks Linux_android opacity_peephole_grid_of_alpha_savelayers_perf__e2e_summary to be flaky (#135119) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_android opacity_peephole_grid_of_alpha_savelayers_perf__e2e_summary" } --> Issue link: https://github.com/flutter/flutter/issues/135118 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 9d63daff79f16..354e3ef4490ed 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2698,6 +2698,7 @@ targets: task_name: opacity_peephole_fade_transition_text_perf__e2e_summary - name: Linux_android opacity_peephole_grid_of_alpha_savelayers_perf__e2e_summary + bringup: true # Flaky https://github.com/flutter/flutter/issues/135118 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 From 6d4a5e3d31a25cc87e4dda185271793c6f8cd10b Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 16:07:06 -0700 Subject: [PATCH 1440/1547] Marks Linux_android flutter_gallery__start_up_delayed to be flaky (#134632) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_android flutter_gallery__start_up_delayed" } --> Issue link: https://github.com/flutter/flutter/issues/134631 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 354e3ef4490ed..d6314e4fdda82 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2104,6 +2104,7 @@ targets: task_name: flutter_gallery__start_up - name: Linux_android flutter_gallery__start_up_delayed + bringup: true # Flaky https://github.com/flutter/flutter/issues/134631 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 From 4f5c8155597a813980654e15d8c47a191243d426 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 16:07:08 -0700 Subject: [PATCH 1441/1547] Marks Linux_android platform_channels_benchmarks to be flaky (#135106) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_android platform_channels_benchmarks" } --> Issue link: https://github.com/flutter/flutter/issues/135105 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index d6314e4fdda82..ad06b266a325f 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2520,6 +2520,7 @@ targets: task_name: slider_perf_android - name: Linux_android platform_channels_benchmarks + bringup: true # Flaky https://github.com/flutter/flutter/issues/135105 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 From 3ba8472a154fe4f9bfd82098af413ab371d5f257 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 19:49:35 -0700 Subject: [PATCH 1442/1547] Marks Mac_ios static_path_tessellation_perf_ios__timeline_summary to be unflaky (#133127) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios static_path_tessellation_perf_ios__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20static_path_tessellation_perf_ios__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index ad06b266a325f..aa6d6fc1c2a33 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2871,7 +2871,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false timeout: 60 - bringup: true properties: tags: > ["devicelab", "ios", "mac"] From 389d482aacb9051823ba37ed46dbbc65af5989e6 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 19:49:37 -0700 Subject: [PATCH 1443/1547] Marks Mac_ios animated_advanced_blend_perf_ios__timeline_summary to be unflaky (#132630) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios animated_advanced_blend_perf_ios__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20animated_advanced_blend_perf_ios__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index aa6d6fc1c2a33..e36b915f848c3 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2805,7 +2805,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false timeout: 60 - bringup: true properties: tags: > ["devicelab", "ios", "mac"] From 82a972bf1a9ec3886157661ab543359ec987f231 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 20:52:33 -0700 Subject: [PATCH 1444/1547] Marks Mac_ios very_long_picture_scrolling_perf_ios__e2e_summary to be unflaky (#134629) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios very_long_picture_scrolling_perf_ios__e2e_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20very_long_picture_scrolling_perf_ios__e2e_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index e36b915f848c3..c5ea354c430b7 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4313,7 +4313,6 @@ targets: - name: Mac_ios very_long_picture_scrolling_perf_ios__e2e_summary recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 120 properties: From 713272eb61ff0cce32d01420ffca9154a1a8b3bd Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Sun, 24 Sep 2023 00:03:41 -0400 Subject: [PATCH 1445/1547] Roll Flutter Engine from ee27600dfbe2 to 2daf5e7bb249 (1 revision) (#135371) https://github.com/flutter/engine/compare/ee27600dfbe2...2daf5e7bb249 2023-09-24 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from de4D1aoqF6LBk18Rd... to W1uZC0_FbXyoCmwJ1... (flutter/engine#46238) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from de4D1aoqF6LB to W1uZC0_FbXyo If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ef816f1c4baf1..139b1c363773b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ee27600dfbe2919fa048cba5a197d423c8b073d6 +2daf5e7bb2494302b6f26dbf1e57f185678eef07 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 6fab34ae4b516..6ac9676c877d4 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -de4D1aoqF6LBk18Rdjpzg5wqU3L3U2RCowLPHUUmnVMC +W1uZC0_FbXyoCmwJ17DM5CSvCQ-f3VF-Y3QuN_WB2eoC From 260c16cfb87ad73240fdc75e6eff4ac10eb75700 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 21:04:54 -0700 Subject: [PATCH 1446/1547] Marks Linux_pixel_7pro picture_cache_perf__timeline_summary to be unflaky (#134118) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_pixel_7pro picture_cache_perf__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux_pixel_7pro%20picture_cache_perf__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index c5ea354c430b7..fb251da3a0ee8 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2493,7 +2493,6 @@ targets: - name: Linux_pixel_7pro picture_cache_perf__timeline_summary recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 60 properties: From 6240c899b93c46d87916b025cb844231722b162f Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 21:07:20 -0700 Subject: [PATCH 1447/1547] Marks Mac_ios draw_points_perf_ios__timeline_summary to be unflaky (#127933) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios draw_points_perf_ios__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20draw_points_perf_ios__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index fb251da3a0ee8..ed668120247de 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4351,7 +4351,6 @@ targets: - name: Mac_ios draw_points_perf_ios__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > From c0bde99e0f777258868b8e68d9bd7a9b6cc041f8 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 21:11:19 -0700 Subject: [PATCH 1448/1547] Marks Mac_ios dynamic_path_tessellation_perf_ios__timeline_summary to be unflaky (#133128) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios dynamic_path_tessellation_perf_ios__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20dynamic_path_tessellation_perf_ios__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index ed668120247de..283dc480e0bf1 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2878,7 +2878,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false timeout: 60 - bringup: true properties: tags: > ["devicelab", "ios", "mac"] From 417aaf5b2b70f4a48324fa581bf0635f9be28a05 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 21:12:53 -0700 Subject: [PATCH 1449/1547] Marks Windows module_test to be unflaky (#134121) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows module_test" } --> The issue https://github.com/flutter/flutter/issues/133639 has been closed, and the test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Windows%20module_test%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 283dc480e0bf1..671eea0a1403e 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4712,7 +4712,6 @@ targets: - .ci.yaml - name: Windows module_test - bringup: true # Flaky https://github.com/flutter/flutter/issues/133639 recipe: devicelab/devicelab_drone timeout: 60 properties: From 2c1f517d10f274a8a0c27867cf9b7831de2aa0f3 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 22:06:26 -0700 Subject: [PATCH 1450/1547] Marks Mac_ios draw_vertices_perf_ios__timeline_summary to be unflaky (#134625) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios draw_vertices_perf_ios__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20draw_vertices_perf_ios__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 671eea0a1403e..ce449e1cd13a4 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2849,7 +2849,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false timeout: 60 - bringup: true properties: tags: > ["devicelab", "ios", "mac"] From 8bc223e3e5cc919bada837ecc0afdc546969a79e Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sat, 23 Sep 2023 22:14:20 -0700 Subject: [PATCH 1451/1547] Marks Mac_ios draw_atlas_perf_ios__timeline_summary to be unflaky (#134626) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Mac_ios draw_atlas_perf_ios__timeline_summary" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Mac_ios%20draw_atlas_perf_ios__timeline_summary%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index ce449e1cd13a4..6ed1dcbab51e3 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2858,7 +2858,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false timeout: 60 - bringup: true properties: tags: > ["devicelab", "ios", "mac"] From a6e98d3006479f4e11f8de9b61037fd6b103f00e Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sun, 24 Sep 2023 09:40:07 -0700 Subject: [PATCH 1452/1547] Marks Windows_android channels_integration_test_win to be unflaky (#135374) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows_android channels_integration_test_win" } --> The issue https://github.com/flutter/flutter/issues/134636 has been closed, and the test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Windows_android%20channels_integration_test_win%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 6ed1dcbab51e3..efc30c7ad7578 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -5173,7 +5173,6 @@ targets: task_name: basic_material_app_win__compile - name: Windows_android channels_integration_test_win - bringup: true # Flaky https://github.com/flutter/flutter/issues/134636 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 From 797d34e5af10ced9fdb6ce08a70a7553c9accdce Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sun, 24 Sep 2023 09:40:10 -0700 Subject: [PATCH 1453/1547] Marks Linux_pixel_7pro hello_world_impeller to be unflaky (#135372) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_pixel_7pro hello_world_impeller" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux_pixel_7pro%20hello_world_impeller%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index efc30c7ad7578..0d49c021c7fb6 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1780,7 +1780,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false # Uses Impeller. - bringup: true timeout: 60 properties: tags: > From 49f1a6bb96fa9cab35446c3c76abea3f4aae6f68 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Sun, 24 Sep 2023 18:20:02 -0700 Subject: [PATCH 1454/1547] Fix failing test at master. (#135394) --- packages/flutter/test/widgets/routes_test.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/flutter/test/widgets/routes_test.dart b/packages/flutter/test/widgets/routes_test.dart index ebc47b1fc57af..a309a51368e49 100644 --- a/packages/flutter/test/widgets/routes_test.dart +++ b/packages/flutter/test/widgets/routes_test.dart @@ -549,8 +549,11 @@ void main() { testWidgetsWithLeakTracking('Can autofocus a TextField nested in a Focus in a route.', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); final FocusNode focusNode = FocusNode(debugLabel: 'Test Node'); + addTearDown(focusNode.dispose); + await tester.pumpWidget( Material( child: MaterialApp( From 2f56288a4e6ec5af0bf62e806881608ac6d7e68d Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Sun, 24 Sep 2023 18:49:07 -0700 Subject: [PATCH 1455/1547] Marks Linux_samsung_a02 new_gallery__transition_perf to be unflaky (#135373) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_samsung_a02 new_gallery__transition_perf" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux_samsung_a02%20new_gallery__transition_perf%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 0d49c021c7fb6..2d58fc9120226 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2426,7 +2426,6 @@ targets: # Samsung A02, Skia - name: Linux_samsung_a02 new_gallery__transition_perf recipe: devicelab/devicelab_drone - bringup: true presubmit: false timeout: 60 properties: From 07ce6a76a0d99b3354e110742cd6e9b35321887d Mon Sep 17 00:00:00 2001 From: godofredoc <godofredoc@google.com> Date: Sun, 24 Sep 2023 21:29:39 -0700 Subject: [PATCH 1456/1547] Revert "Marks Linux_samsung_a02 new_gallery__transition_perf to be unflaky" (#135399) Reverts flutter/flutter#135373 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 2d58fc9120226..0d49c021c7fb6 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2426,6 +2426,7 @@ targets: # Samsung A02, Skia - name: Linux_samsung_a02 new_gallery__transition_perf recipe: devicelab/devicelab_drone + bringup: true presubmit: false timeout: 60 properties: From 6a9df55d9f4d76bf2652dc7762be4d31fd84d2a1 Mon Sep 17 00:00:00 2001 From: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:37:02 -0700 Subject: [PATCH 1457/1547] Add a basic golden test for `CupertinoTextSelectionToolbar` (#135267) Goden tests are easier to understand than `paints..` since the toolbar has a relatively complex path, and this should make PRs that make visual changes easier to review. The current goldens don't look correct since I messed up the y offset of the tip of the arrow when the arrow is pointing up. Should be fixed in https://github.com/flutter/flutter/pull/133386 --- .../text_selection_toolbar_test.dart | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart index 2de48850c03a8..dd87a1eb7fc55 100644 --- a/packages/flutter/test/cupertino/text_selection_toolbar_test.dart +++ b/packages/flutter/test/cupertino/text_selection_toolbar_test.dart @@ -2,6 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// This file is run as part of a reduced test set in CI on Mac and Windows +// machines. +@Tags(<String>['reduced-test-set']) +library; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -493,4 +498,51 @@ void main() { ), ); }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. + + testWidgetsWithLeakTracking('Basic golden tests', (WidgetTester tester) async { + final Key key = UniqueKey(); + Widget buildToolbar(Brightness brightness, Offset offset) { + final Widget toolbar = CupertinoTextSelectionToolbar( + anchorAbove: offset, + anchorBelow: offset, + children: <Widget>[ + CupertinoTextSelectionToolbarButton.text(onPressed: () {}, text: 'Lorem ipsum'), + CupertinoTextSelectionToolbarButton.text(onPressed: () {}, text: 'dolor sit amet'), + CupertinoTextSelectionToolbarButton.text(onPressed: () {}, text: 'Lorem ipsum \ndolor sit amet'), + CupertinoTextSelectionToolbarButton.buttonItem(buttonItem: ContextMenuButtonItem(onPressed: () {}, type: ContextMenuButtonType.copy)), + ], + ); + return CupertinoApp( + theme: CupertinoThemeData(brightness: brightness), + home: Center( + child: SizedBox( + height: 200, + child: RepaintBoundary(key: key, child: toolbar), + ), + ), + ); + } + + // The String describes the location of the toolbar in relation to the + // content the arrow points to. + const List<(String, Offset)> toolbarLocation = <(String, Offset)>[ + ('BottomRight', Offset.zero), + ('BottomLeft', Offset(100000, 0)), + ('TopRight', Offset(0, 100)), + ('TopLeft', Offset(100000, 100)), + ]; + + debugDisableShadows = false; + addTearDown(() => debugDisableShadows = true); + for (final Brightness brightness in Brightness.values) { + for (final (String location, Offset offset) in toolbarLocation) { + await tester.pumpWidget(buildToolbar(brightness, offset)); + await expectLater( + find.byKey(key), + matchesGoldenFile('cupertino_selection_toolbar.$location.$brightness.png'), + ); + } + } + debugDisableShadows = true; + }, skip: kIsWeb); // [intended] We do not use Flutter-rendered context menu on the Web. } From be085a92293d14d716ca52263cb5f9c854d867b7 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 00:37:04 -0400 Subject: [PATCH 1458/1547] Roll Flutter Engine from 2daf5e7bb249 to 3ea1174ecfaa (4 revisions) (#135396) https://github.com/flutter/engine/compare/2daf5e7bb249...3ea1174ecfaa 2023-09-25 zanderso@users.noreply.github.com In run_tests.py, separate Dart package unit tests from other tests (flutter/engine#46232) 2023-09-24 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from SqWjDvrDsMfiisUoA... to VKAiabs4VzJ1Py-oA... (flutter/engine#46241) 2023-09-24 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from W1uZC0_FbXyoCmwJ1... to 0Jl20zAW45rRsTNEu... (flutter/engine#46240) 2023-09-24 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from M-fNM9YP2Lpc8Y_Dj... to SqWjDvrDsMfiisUoA... (flutter/engine#46239) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from M-fNM9YP2Lpc to VKAiabs4VzJ1 fuchsia/sdk/core/mac-amd64 from W1uZC0_FbXyo to 0Jl20zAW45rR If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 139b1c363773b..daf3c87c58b6b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2daf5e7bb2494302b6f26dbf1e57f185678eef07 +3ea1174ecfaa425cf0315921f39fba0cbc2e4668 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index f2a99d7e669d8..fa4bbae7bf221 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -M-fNM9YP2Lpc8Y_Dj7W2nZ4xcbMR2TFzh0DY-bGs0MEC +VKAiabs4VzJ1Py-oAN6-gffPf6vdWYlXuxYr8qboThQC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 6ac9676c877d4..59194bdb5d560 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -W1uZC0_FbXyoCmwJ17DM5CSvCQ-f3VF-Y3QuN_WB2eoC +0Jl20zAW45rRsTNEuuX3QIp835kbZeZevlzjb6BT7PYC From d5a8cd3840c00f68308b433f132eb9d5d59182d8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 03:12:22 -0400 Subject: [PATCH 1459/1547] Roll Flutter Engine from 3ea1174ecfaa to e1c1022c2d6d (2 revisions) (#135403) https://github.com/flutter/engine/compare/3ea1174ecfaa...e1c1022c2d6d 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from 983f42f4c76b to b8bc0c080aa8 (1 revision) (flutter/engine#46247) 2023-09-25 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from 0Jl20zAW45rRsTNEu... to SNqQGAfjWL3PbUABh... (flutter/engine#46246) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from 0Jl20zAW45rR to SNqQGAfjWL3P If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index daf3c87c58b6b..da9a455d5cb87 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3ea1174ecfaa425cf0315921f39fba0cbc2e4668 +e1c1022c2d6d2c4840b262c96b4cd10c81b59858 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 59194bdb5d560..f162cd6d6608a 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -0Jl20zAW45rRsTNEuuX3QIp835kbZeZevlzjb6BT7PYC +SNqQGAfjWL3PbUABhZ7BwODv1wB0MaCNsJHkhne4okMC From 3c4b81daebb7625ca5ff2935fa0872fa88cee301 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 06:31:30 -0400 Subject: [PATCH 1460/1547] Roll Flutter Engine from e1c1022c2d6d to e6d3bac5c723 (2 revisions) (#135410) https://github.com/flutter/engine/compare/e1c1022c2d6d...e6d3bac5c723 2023-09-25 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from VKAiabs4VzJ1Py-oA... to uY9WEf2tJxa1Hpp4v... (flutter/engine#46252) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from b8bc0c080aa8 to 31ceb1669d1c (1 revision) (flutter/engine#46249) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from VKAiabs4VzJ1 to uY9WEf2tJxa1 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index da9a455d5cb87..d1322090f43d3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e1c1022c2d6d2c4840b262c96b4cd10c81b59858 +e6d3bac5c723760a0f641802ffa3f2b2ae924732 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index fa4bbae7bf221..acb24bf12143a 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -VKAiabs4VzJ1Py-oAN6-gffPf6vdWYlXuxYr8qboThQC +uY9WEf2tJxa1Hpp4v7RXvPN25swStFm4US-PlU6Xe8wC From 16ae8c0109181b29b9b9c4a1ab6db13c6eb8fcf6 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Mon, 25 Sep 2023 07:13:30 -0700 Subject: [PATCH 1461/1547] Revert "Marks Linux_pixel_7pro hello_world_impeller to be unflaky" (#135388) Reverts flutter/flutter#135372 --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index 0d49c021c7fb6..efc30c7ad7578 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1780,6 +1780,7 @@ targets: recipe: devicelab/devicelab_drone presubmit: false # Uses Impeller. + bringup: true timeout: 60 properties: tags: > From 9c7ab9014edf83b061796f5ab7e10610430be129 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 10:35:26 -0400 Subject: [PATCH 1462/1547] Roll Flutter Engine from e6d3bac5c723 to 2c4c1108aa87 (1 revision) (#135424) https://github.com/flutter/engine/compare/e6d3bac5c723...2c4c1108aa87 2023-09-25 49699333+dependabot[bot]@users.noreply.github.com Bump archive from 3.3.9 to 3.4.2 in /lib/web_ui (flutter/engine#46253) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d1322090f43d3..8cc1cbeb41f88 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -e6d3bac5c723760a0f641802ffa3f2b2ae924732 +2c4c1108aa87d51b3ad998314864b6883cee12ac From 4ae2e91c643908373a311b0612faf56c651aded1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 12:00:01 -0400 Subject: [PATCH 1463/1547] Roll Packages from 98ebcd3d9c05 to e548ae1d2045 (5 revisions) (#135431) https://github.com/flutter/packages/compare/98ebcd3d9c05...e548ae1d2045 2023-09-23 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 2.21.7 to 2.21.8 (flutter/packages#4952) 2023-09-23 engine-flutter-autoroll@skia.org Manual roll Flutter from 893650416352 to f92884c7b846 (48 revisions) (flutter/packages#4985) 2023-09-22 geral.sbi2@gmail.com [image_picker_android] check if data from result is empty when picking a single img or video (flutter/packages#4836) 2023-09-22 me@nils.re [camera_android] Removes usage of `_ambiguate` method in tests (flutter/packages#4948) 2023-09-22 49699333+dependabot[bot]@users.noreply.github.com [sign_in]: Bump com.google.android.gms:play-services-auth from 20.6.0 to 20.7.0 in /packages/google_sign_in/google_sign_in_android/android (flutter/packages#4841) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index c779848cdf372..272a7525f0c58 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -98ebcd3d9c05c95801b0137b9bfd0cf898a18b56 +e548ae1d2045974a6be0b9c9e3517cf23b78240e From def17532706f212e329a543da1da195cc46402be Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 13:34:55 -0400 Subject: [PATCH 1464/1547] Roll Flutter Engine from 2c4c1108aa87 to 1ae3d20332f0 (4 revisions) (#135438) https://github.com/flutter/engine/compare/2c4c1108aa87...1ae3d20332f0 2023-09-25 54558023+keyonghan@users.noreply.github.com Switch goma to reclient for Linux host engine targets (flutter/engine#45884) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from 7a49397a02b4 to e16a9b5b2c48 (1 revision) (flutter/engine#46258) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from 569a30fbdbdf to 7a49397a02b4 (2 revisions) (flutter/engine#46257) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from 31ceb1669d1c to 569a30fbdbdf (1 revision) (flutter/engine#46256) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8cc1cbeb41f88..34accb3c9ba45 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -2c4c1108aa87d51b3ad998314864b6883cee12ac +1ae3d20332f03c6fa5ea7fa4ee421ebdf2d5b2ef From 52914c7628f53ea2eff1ede5d13413b844627f26 Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Mon, 25 Sep 2023 10:40:06 -0700 Subject: [PATCH 1465/1547] simulatedAccessibilityTraversal account for force merging (#135178) fixes https://github.com/flutter/flutter/issues/135144 --- packages/flutter_test/lib/src/controller.dart | 14 +++++--- .../flutter_test/test/controller_test.dart | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/packages/flutter_test/lib/src/controller.dart b/packages/flutter_test/lib/src/controller.dart index d5763135a6c84..9ab37a45edc71 100644 --- a/packages/flutter_test/lib/src/controller.dart +++ b/packages/flutter_test/lib/src/controller.dart @@ -242,23 +242,29 @@ class SemanticsController { /// * [flutter/engine/AccessibilityBridge.java#SemanticsNode.isFocusable()](https://github.com/flutter/engine/blob/main/shell/platform/android/io/flutter/view/AccessibilityBridge.java#L2641) /// * [flutter/engine/SemanticsObject.mm#SemanticsObject.isAccessibilityElement](https://github.com/flutter/engine/blob/main/shell/platform/darwin/ios/framework/Source/SemanticsObject.mm#L449) bool _isImportantForAccessibility(SemanticsNode node) { + if (node.isMergedIntoParent) { + // If this node is merged, all its information are present on an ancestor + // node. + return false; + } + final SemanticsData data = node.getSemanticsData(); // If the node scopes a route, it doesn't matter what other flags/actions it // has, it is _not_ important for accessibility, so we short circuit. - if (node.hasFlag(SemanticsFlag.scopesRoute)) { + if (data.hasFlag(SemanticsFlag.scopesRoute)) { return false; } - final bool hasNonScrollingAction = node.getSemanticsData().actions & ~_scrollingActions != 0; + final bool hasNonScrollingAction = data.actions & ~_scrollingActions != 0; if (hasNonScrollingAction) { return true; } - final bool hasImportantFlag = node.getSemanticsData().flags & _importantFlagsForAccessibility != 0; + final bool hasImportantFlag = data.flags & _importantFlagsForAccessibility != 0; if (hasImportantFlag) { return true; } - final bool hasContent = node.label.isNotEmpty || node.value.isNotEmpty || node.hint.isNotEmpty; + final bool hasContent = data.label.isNotEmpty || data.value.isNotEmpty || data.hint.isNotEmpty; if (hasContent) { return true; } diff --git a/packages/flutter_test/test/controller_test.dart b/packages/flutter_test/test/controller_test.dart index 0337264f36521..c2ca9c93242eb 100644 --- a/packages/flutter_test/test/controller_test.dart +++ b/packages/flutter_test/test/controller_test.dart @@ -982,6 +982,38 @@ void main() { tester.semantics.simulatedAccessibilityTraversal(), containsAllInOrder(expectedMatchers)); }); + + testWidgets('merging node should not be visited', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: MergeSemantics( + child: Column( + children: <Widget>[ + Semantics( + container: true, + child: const Text('1'), + ), + Semantics( + container: true, + child: const Text('2'), + ), + Semantics( + container: true, + child: const Text('3'), + ), + ], + ), + ), + ), + ); + + expect( + tester.semantics.simulatedAccessibilityTraversal(), + orderedEquals( + <Matcher>[containsSemantics(label: '1\n2\n3')], + ), + ); + }); }); }); } From fffbbf279edd44c0e6ee297d4bb3b4d4dec22199 Mon Sep 17 00:00:00 2001 From: Chip Weinberger <weinberger.c@gmail.com> Date: Mon, 25 Sep 2023 12:09:51 -0700 Subject: [PATCH 1466/1547] [Velocity Tracker] Fix: Issue 97761: Flutter Scrolling does not match iOS; inadvertent scrolling when user lifts up finger (#132291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Issue **Issue:** https://github.com/flutter/flutter/issues/97761 https://github.com/flutter/flutter/assets/1863934/53c5e0df-b85a-483c-a17d-bddd18db3aa9 ## The Cause: The bug is very simple to understand - `velocity_tracker.dart` **only adds new samples while your finger is moving**. **Therefore**, if you move your finger quickly & (important) stop suddenly with no extra movement, the last 3 samples will all be > 0 dy. Regardless of how long you wait, you will get movement when you lift up your finger. **Logs from velocity_tracker.dart:** Notice: all 3 `_previousVelocityAt` are `dy > 0` despite a 2 second delay since the last scroll ``` // start moving finger flutter: addPosition dy:-464.0 flutter: addPosition dy:-465.0 flutter: addPosition dy:-466.0 flutter: addPosition dy:-467.0 flutter: addPosition dy:-468.0 flutter: addPosition dy:-469.0 flutter: addPosition dy:-470.0 // stop moving finger here, keep it still for 2 seconds & lift it up flutter: _previousVelocityAt(-2) samples(-467.0, -468.0)) dy:-176.772140710624 flutter: _previousVelocityAt(-1) samples(-468.0, -469.0)) dy:-375.0937734433609 flutter: _previousVelocityAt(0) samples(-469.0, -470.0)) dy:-175.71604287471447 flutter: primaryVelocity DragEndDetails(Velocity(0.0, -305.5)).primaryVelocity flutter: createBallisticSimulation pixels 464.16666666666663 velocity 305.4699824197211 ``` ## The Fix **There are 3 options to fix it:** A. sample uniformly *per unit time* (a larger more risky change, hurts battery life) B. consider elapsed time since the last sample. If greater than X, assume no more velocity. (easy & just as valid) C. similar to B, but instead add "ghost samples" of velocity zero, and run calculations as normal (a bit tricker, of dubious benefit imo) **For Option B I considered two approaches:** 1. _get the current timestamp and compare to event timestamp._ This is tricky because events are documented to use an arbitrary timescale & I wasn't able to find the code that generates the timestamps. This approach could be considered more. 2. _get a new timestamp using Stopwatch and compare now vs when the last sample was added._ This is the solution implemented here. There is a limitation in that we don't know when addSamples is called relative to the event. But, this estimation is already on a very low latency path & still it gives us a *minimum* time bound which is sufficient for comparison. **This PR chooses the simplest of the all solutions. Please try it our yourself, it completely solves the problem 😀** Option _B.1_ would be a nice alternative as well, if we can define and access the same timesource as the pointer tracker in a maintainable simple way. ## After Fix https://github.com/flutter/flutter/assets/1863934/be50d8e7-d5da-495a-a4af-c71bc541cbe3 --- .../lib/src/gestures/velocity_tracker.dart | 39 ++++++++++++++++++- .../test/gestures/velocity_tracker_test.dart | 18 +++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/gestures/velocity_tracker.dart b/packages/flutter/lib/src/gestures/velocity_tracker.dart index ca7aa468a0198..f761a1be23f8d 100644 --- a/packages/flutter/lib/src/gestures/velocity_tracker.dart +++ b/packages/flutter/lib/src/gestures/velocity_tracker.dart @@ -149,12 +149,17 @@ class VelocityTracker { /// The kind of pointer this tracker is for. final PointerDeviceKind kind; + // Time difference since the last sample was added + final Stopwatch _sinceLastSample = Stopwatch(); + // Circular buffer; current sample at _index. final List<_PointAtTime?> _samples = List<_PointAtTime?>.filled(_historySize, null); int _index = 0; /// Adds a position as the given time to the tracker. void addPosition(Duration time, Offset position) { + _sinceLastSample.start(); + _sinceLastSample.reset(); _index += 1; if (_index == _historySize) { _index = 0; @@ -169,6 +174,16 @@ class VelocityTracker { /// /// Returns null if there is no data on which to base an estimate. VelocityEstimate? getVelocityEstimate() { + // no recent user movement? + if (_sinceLastSample.elapsedMilliseconds > VelocityTracker._assumePointerMoveStoppedMilliseconds) { + return const VelocityEstimate( + pixelsPerSecond: Offset.zero, + confidence: 1.0, + duration: Duration.zero, + offset: Offset.zero, + ); + } + final List<double> x = <double>[]; final List<double> y = <double>[]; final List<double> w = <double>[]; @@ -195,7 +210,7 @@ class VelocityTracker { final double age = (newestSample.time - sample.time).inMicroseconds.toDouble() / 1000; final double delta = (sample.time - previousSample.time).inMicroseconds.abs().toDouble() / 1000; previousSample = sample; - if (age > _horizonMilliseconds || delta > _assumePointerMoveStoppedMilliseconds) { + if (age > _horizonMilliseconds || delta > VelocityTracker._assumePointerMoveStoppedMilliseconds) { break; } @@ -288,6 +303,8 @@ class IOSScrollViewFlingVelocityTracker extends VelocityTracker { @override void addPosition(Duration time, Offset position) { + _sinceLastSample.start(); + _sinceLastSample.reset(); assert(() { final _PointAtTime? previousPoint = _touchSamples[_index]; if (previousPoint == null || previousPoint.time <= time) { @@ -326,6 +343,16 @@ class IOSScrollViewFlingVelocityTracker extends VelocityTracker { @override VelocityEstimate getVelocityEstimate() { + // no recent user movement? + if (_sinceLastSample.elapsedMilliseconds > VelocityTracker._assumePointerMoveStoppedMilliseconds) { + return const VelocityEstimate( + pixelsPerSecond: Offset.zero, + confidence: 1.0, + duration: Duration.zero, + offset: Offset.zero, + ); + } + // The velocity estimated using this expression is an approximation of the // scroll velocity of an iOS scroll view at the moment the user touch was // released, not the final velocity of the iOS pan gesture recognizer @@ -387,6 +414,16 @@ class MacOSScrollViewFlingVelocityTracker extends IOSScrollViewFlingVelocityTrac @override VelocityEstimate getVelocityEstimate() { + // no recent user movement? + if (_sinceLastSample.elapsedMilliseconds > VelocityTracker._assumePointerMoveStoppedMilliseconds) { + return const VelocityEstimate( + pixelsPerSecond: Offset.zero, + confidence: 1.0, + duration: Duration.zero, + offset: Offset.zero, + ); + } + // The velocity estimated using this expression is an approximation of the // scroll velocity of a macOS scroll view at the moment the user touch was // released. diff --git a/packages/flutter/test/gestures/velocity_tracker_test.dart b/packages/flutter/test/gestures/velocity_tracker_test.dart index 3e6b94534bbbb..61eebc13fe186 100644 --- a/packages/flutter/test/gestures/velocity_tracker_test.dart +++ b/packages/flutter/test/gestures/velocity_tracker_test.dart @@ -144,4 +144,22 @@ void main() { } } }); + + test('Assume zero velocity when there are no recent samples', () async { + final IOSScrollViewFlingVelocityTracker tracker = IOSScrollViewFlingVelocityTracker(PointerDeviceKind.touch); + Offset position = Offset.zero; + Duration time = Duration.zero; + const Offset positionDelta = Offset(0, -1); + const Duration durationDelta = Duration(seconds: 1); + + for (int i = 0; i < 10; i+=1) { + position += positionDelta; + time += durationDelta; + tracker.addPosition(time, position); + } + + await Future<void>.delayed(const Duration(milliseconds: 50)); + + expect(tracker.getVelocity().pixelsPerSecond, Offset.zero); + }); } From 79caa8373c42383b7ee3f2bd1b2b6d2070ffafc2 Mon Sep 17 00:00:00 2001 From: Edgar Jan <EdgarJan@users.noreply.github.com> Date: Mon, 25 Sep 2023 22:17:07 +0300 Subject: [PATCH 1467/1547] Fix and Test Conditional Validator Behavior in FormField (#132714) In the FormField widget, if a validator is initially set (and validation fails), then subsequently the validator is set to null, the form incorrectly retains its error state. This is not expected behavior as removing the validator should clear any validation errors. --- packages/flutter/lib/src/widgets/form.dart | 2 + packages/flutter/test/widgets/form_test.dart | 67 ++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 3989da3ea429e..cb8b5d9c6e8b0 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -524,6 +524,8 @@ class FormFieldState<T> extends State<FormField<T>> with RestorationMixin { void _validate() { if (widget.validator != null) { _errorText.value = widget.validator!(_value); + } else { + _errorText.value = null; } } diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart index 90f5fe727bf33..6d2996c723640 100644 --- a/packages/flutter/test/widgets/form_test.dart +++ b/packages/flutter/test/widgets/form_test.dart @@ -945,4 +945,71 @@ void main() { fieldKey.currentState!.reset(); expect(fieldKey.currentState!.hasInteractedByUser, isFalse); }); + + testWidgets('Validator is nullified and error text behaves accordingly', + (WidgetTester tester) async { + final GlobalKey<FormState> formKey = GlobalKey<FormState>(); + bool useValidator = false; + late StateSetter setState; + + String? validator(String? value) { + if (value == null || value.isEmpty) { + return 'test_error'; + } + return null; + } + + Widget builder() { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + setState = setter; + return MaterialApp( + home: MediaQuery( + data: const MediaQueryData(), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Material( + child: Form( + key: formKey, + child: TextFormField( + validator: useValidator ? validator : null, + ), + ), + ), + ), + ), + ), + ); + }, + ); + } + + await tester.pumpWidget(builder()); + + // Start with no validator. + await tester.enterText(find.byType(TextFormField), ''); + await tester.pump(); + formKey.currentState!.validate(); + await tester.pump(); + expect(find.text('test_error'), findsNothing); + + // Now use the validator. + setState(() { + useValidator = true; + }); + await tester.pump(); + formKey.currentState!.validate(); + await tester.pump(); + expect(find.text('test_error'), findsOneWidget); + + // Remove the validator again and expect the error to disappear. + setState(() { + useValidator = false; + }); + await tester.pump(); + formKey.currentState!.validate(); + await tester.pump(); + expect(find.text('test_error'), findsNothing); + }); } From cb4b4d4ac93981d9f22aa17ce5e10b22346b4700 Mon Sep 17 00:00:00 2001 From: Chris Bracken <chris@bracken.jp> Date: Mon, 25 Sep 2023 20:27:31 +0100 Subject: [PATCH 1468/1547] [macOS,iOS] Improve CocoaPods upgrade instructions (#135453) In our CocoaPods doctor check, if the version of CocoaPods is found to be too low, rather than emitting a link to the install instructions, emit a link to the upgrade instructions. Since this check operates on CocoaPodsStatus, an enum, swtich to using a case statement and cover all cases. ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [ ] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I added new tests to check the change I am making, or this PR is [test-exempt]. - [X] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../lib/src/macos/cocoapods.dart | 2 ++ .../lib/src/macos/cocoapods_validator.dart | 21 ++++++++----------- .../macos/cocoapods_validator_test.dart | 1 + 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/flutter_tools/lib/src/macos/cocoapods.dart b/packages/flutter_tools/lib/src/macos/cocoapods.dart index e675b50c5efa8..c4e9b86e41ade 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods.dart @@ -48,6 +48,8 @@ const String outOfDatePluginsPodfileConsequence = ''' const String cocoaPodsInstallInstructions = 'see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.'; +const String cocoaPodsUpdateInstructions = 'see https://guides.cocoapods.org/using/getting-started.html#updating-cocoapods for instructions.'; + const String podfileIosMigrationInstructions = ''' rm ios/Podfile'''; diff --git a/packages/flutter_tools/lib/src/macos/cocoapods_validator.dart b/packages/flutter_tools/lib/src/macos/cocoapods_validator.dart index 56b16dbfd5b19..93fccd62e5abb 100644 --- a/packages/flutter_tools/lib/src/macos/cocoapods_validator.dart +++ b/packages/flutter_tools/lib/src/macos/cocoapods_validator.dart @@ -29,31 +29,28 @@ class CocoaPodsValidator extends DoctorValidator { .evaluateCocoaPodsInstallation; ValidationType status = ValidationType.success; - if (cocoaPodsStatus == CocoaPodsStatus.recommended) { - messages.add(ValidationMessage(_userMessages.cocoaPodsVersion((await _cocoaPods.cocoaPodsVersionText).toString()))); - } else { - if (cocoaPodsStatus == CocoaPodsStatus.notInstalled) { + switch (cocoaPodsStatus) { + case CocoaPodsStatus.recommended: + messages.add(ValidationMessage(_userMessages.cocoaPodsVersion((await _cocoaPods.cocoaPodsVersionText).toString()))); + case CocoaPodsStatus.notInstalled: status = ValidationType.missing; messages.add(ValidationMessage.error( _userMessages.cocoaPodsMissing(noCocoaPodsConsequence, cocoaPodsInstallInstructions))); - - } else if (cocoaPodsStatus == CocoaPodsStatus.brokenInstall) { + case CocoaPodsStatus.brokenInstall: status = ValidationType.missing; messages.add(ValidationMessage.error( _userMessages.cocoaPodsBrokenInstall(brokenCocoaPodsConsequence, cocoaPodsInstallInstructions))); - - } else if (cocoaPodsStatus == CocoaPodsStatus.unknownVersion) { + case CocoaPodsStatus.unknownVersion: status = ValidationType.partial; messages.add(ValidationMessage.hint( _userMessages.cocoaPodsUnknownVersion(unknownCocoaPodsConsequence, cocoaPodsInstallInstructions))); - } else { + case CocoaPodsStatus.belowMinimumVersion: + case CocoaPodsStatus.belowRecommendedVersion: status = ValidationType.partial; final String currentVersionText = (await _cocoaPods.cocoaPodsVersionText).toString(); messages.add(ValidationMessage.hint( - _userMessages.cocoaPodsOutdated(currentVersionText, cocoaPodsRecommendedVersion.toString(), noCocoaPodsConsequence, cocoaPodsInstallInstructions))); - } + _userMessages.cocoaPodsOutdated(currentVersionText, cocoaPodsRecommendedVersion.toString(), noCocoaPodsConsequence, cocoaPodsUpdateInstructions))); } - return ValidationResult(status, messages); } } diff --git a/packages/flutter_tools/test/general.shard/macos/cocoapods_validator_test.dart b/packages/flutter_tools/test/general.shard/macos/cocoapods_validator_test.dart index 1a5c24068366a..22216ba9f8adc 100644 --- a/packages/flutter_tools/test/general.shard/macos/cocoapods_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/cocoapods_validator_test.dart @@ -41,6 +41,7 @@ void main() { expect(message.type, ValidationMessageType.hint); expect(message.message, contains('CocoaPods $currentVersion out of date')); expect(message.message, contains('(1.11.0 is recommended)')); + expect(message.message, contains('getting-started.html#updating-cocoapods')); }); }); } From 965337be6abf38cfd8bfc9367386736aeee64b7a Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 17:14:51 -0400 Subject: [PATCH 1469/1547] Roll Flutter Engine from 1ae3d20332f0 to 3f606570ac7c (6 revisions) (#135457) https://github.com/flutter/engine/compare/1ae3d20332f0...3f606570ac7c 2023-09-25 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Switch goma to reclient for Linux clang_tidy targets" (flutter/engine#46267) 2023-09-25 43759233+kenzieschmoll@users.noreply.github.com Add description to assert in `history.dart` (flutter/engine#46072) 2023-09-25 54558023+keyonghan@users.noreply.github.com Switch goma to reclient for Linux clang_tidy targets (flutter/engine#45898) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from e16a9b5b2c48 to a19a325cd670 (6 revisions) (flutter/engine#46261) 2023-09-25 skia-flutter-autoroll@skia.org Roll Dart SDK from 692273b46610 to 216b25f9ea6f (6 revisions) (flutter/engine#46260) 2023-09-25 54558023+keyonghan@users.noreply.github.com Switch goma to reclient for Linux fuchsia/unopt/android_aot (flutter/engine#45899) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 34accb3c9ba45..9eb954060f481 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -1ae3d20332f03c6fa5ea7fa4ee421ebdf2d5b2ef +3f606570ac7cdbdd5bdac38e788ac8b3480752c9 From d28c10ceb2b1b762284182475710c2ab7d5b4bee Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 20:15:40 -0400 Subject: [PATCH 1470/1547] Roll Flutter Engine from 3f606570ac7c to 6bf8067392cf (8 revisions) (#135472) https://github.com/flutter/engine/compare/3f606570ac7c...6bf8067392cf 2023-09-25 54558023+keyonghan@users.noreply.github.com Restore goma from rbe before 3.16 branching (flutter/engine#46272) 2023-09-25 bkonyi@google.com Add package:tar to DEPS to fix broken 3H configurations (flutter/engine#46273) 2023-09-25 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from SNqQGAfjWL3PbUABh... to we5owZaebdO_3kyjz... (flutter/engine#46270) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from a19a325cd670 to 00e4d00021a7 (6 revisions) (flutter/engine#46269) 2023-09-25 jonahwilliams@google.com [Impeller] fallback to position data if texture coordinates are undefined. (flutter/engine#46264) 2023-09-25 ian@mckellar.org fuchsia: Update FIDL for unknown interactions (flutter/engine#45773) 2023-09-25 jonahwilliams@google.com [Engine] use QoS classes in iOS engine. (flutter/engine#46265) 2023-09-25 jonahwilliams@google.com Revert "Switch goma to reclient for Linux clang_tidy targets (#45898)" (flutter/engine#46266) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from SNqQGAfjWL3P to we5owZaebdO_ If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 9eb954060f481..be4d08365abd1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -3f606570ac7cdbdd5bdac38e788ac8b3480752c9 +6bf8067392cfb61a492d811065ffeb4d1feb35ac diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index f162cd6d6608a..24084301c34c4 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -SNqQGAfjWL3PbUABhZ7BwODv1wB0MaCNsJHkhne4okMC +we5owZaebdO_3kyjzbmpyh37YiP2bGjPyaGIUnxXruUC From b097d2402222a7687eb4a3b9a6db6dc0fafcc288 Mon Sep 17 00:00:00 2001 From: Callum Moffat <smartercallum@gmail.com> Date: Mon, 25 Sep 2023 20:35:57 -0400 Subject: [PATCH 1471/1547] Add "Frame Request Pending" lag to collected metrics (#135279) This measures the wall clock time between a new frame being scheduled in dart code to the Vsync callback in the engine It's an important source of lag which isn't shown in the top-level UI / Build time graphs, and can correlate with "invisible" missed/non-scheduled frames I had to change a few unrelated timings in the test, it was only passing based on luck of sort order, and broke when I added more entries to the timeline. Part of #129150 --- ...me_request_pending_latency_summarizer.dart | 64 +++++++++++++++++++ .../lib/src/driver/timeline_summary.dart | 15 +++++ .../src/real_tests/timeline_summary_test.dart | 44 +++++++++++-- 3 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 packages/flutter_driver/lib/src/driver/frame_request_pending_latency_summarizer.dart diff --git a/packages/flutter_driver/lib/src/driver/frame_request_pending_latency_summarizer.dart b/packages/flutter_driver/lib/src/driver/frame_request_pending_latency_summarizer.dart new file mode 100644 index 0000000000000..2554611103d99 --- /dev/null +++ b/packages/flutter_driver/lib/src/driver/frame_request_pending_latency_summarizer.dart @@ -0,0 +1,64 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'percentile_utils.dart'; +import 'timeline.dart'; + +/// Event name for frame request pending timeline events. +const String kFrameRequestPendingEvent = 'Frame Request Pending'; + +/// Summarizes [TimelineEvents]s corresponding to [kFrameRequestPendingEvent] events. +/// +/// `FrameRequestPendingLatency` is the time between `Animator::RequestFrame` +/// and `Animator::BeginFrame` for each frame built by the Flutter engine. +class FrameRequestPendingLatencySummarizer { + /// Creates a FrameRequestPendingLatencySummarizer given the timeline events. + FrameRequestPendingLatencySummarizer(this.frameRequestPendingEvents); + + /// Timeline events with names in [kFrameRequestPendingTimelineEventNames]. + final List<TimelineEvent> frameRequestPendingEvents; + + /// Computes the average `FrameRequestPendingLatency` over the period of the timeline. + double computeAverageFrameRequestPendingLatency() { + final List<double> frameRequestPendingLatencies = + _computeFrameRequestPendingLatencies(); + if (frameRequestPendingLatencies.isEmpty) { + return 0; + } + + final double total = frameRequestPendingLatencies.reduce((double a, double b) => a + b); + return total / frameRequestPendingLatencies.length; + } + + /// Computes the [percentile]-th percentile `FrameRequestPendingLatency` over the + /// period of the timeline. + double computePercentileFrameRequestPendingLatency(double percentile) { + final List<double> frameRequestPendingLatencies = + _computeFrameRequestPendingLatencies(); + if (frameRequestPendingLatencies.isEmpty) { + return 0; + } + return findPercentile(frameRequestPendingLatencies, percentile); + } + + List<double> _computeFrameRequestPendingLatencies() { + final List<double> result = <double>[]; + final Map<String, int> starts = <String, int>{}; + for (int i = 0; i < frameRequestPendingEvents.length; i++) { + final TimelineEvent event = frameRequestPendingEvents[i]; + if (event.phase == 'b') { + final String? id = event.json['id'] as String?; + if (id != null) { + starts[id] = event.timestampMicros!; + } + } else if (event.phase == 'e') { + final int? start = starts[event.json['id']]; + if (start != null) { + result.add((event.timestampMicros! - start).toDouble()); + } + } + } + return result; + } +} diff --git a/packages/flutter_driver/lib/src/driver/timeline_summary.dart b/packages/flutter_driver/lib/src/driver/timeline_summary.dart index 6d580bd551b96..d79caeffd06a7 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -9,6 +9,7 @@ import 'package:file/file.dart'; import 'package:path/path.dart' as path; import 'common.dart'; +import 'frame_request_pending_latency_summarizer.dart'; import 'gc_summarizer.dart'; import 'percentile_utils.dart'; import 'profiling_summarizer.dart'; @@ -258,6 +259,14 @@ class TimelineSummary { /// * "worst_picture_cache_memory": The worst (highest) value seen for the /// memory used for the engine picture cache entries. /// See [RasterCacheSummarizer.computeWorstPictureMemory]. + /// * "average_frame_request_pending_latency": Computes the average of the delay + /// between `Animator::RequestFrame` and `Animator::BeginFrame` in the engine. + /// See [FrameRequestPendingLatencySummarizer.computeAverageFrameRequestPendingLatency]. + /// * "90th_percentile_frame_request_pending_latency" and + /// "99th_percentile_frame_request_pending_latency": The 90/99-th percentile + /// delay between `Animator::RequestFrame` and `Animator::BeginFrame` in the + /// engine. + /// See [FrameRequestPendingLatencySummarizer.computePercentileFrameRequestPendingLatency]. Map<String, dynamic> get summaryJson { final SceneDisplayLagSummarizer sceneDisplayLagSummarizer = _sceneDisplayLagSummarizer(); final VsyncFrameLagSummarizer vsyncFrameLagSummarizer = _vsyncFrameLagSummarizer(); @@ -265,6 +274,7 @@ class TimelineSummary { final RasterCacheSummarizer rasterCacheSummarizer = _rasterCacheSummarizer(); final GCSummarizer gcSummarizer = _gcSummarizer(); final RefreshRateSummary refreshRateSummary = RefreshRateSummary(vsyncEvents: _extractNamedEvents(kUIThreadVsyncProcessEvent)); + final FrameRequestPendingLatencySummarizer frameRequestPendingLatencySummarizer = _frameRequestPendingLatencySummarizer(); final Map<String, dynamic> timelineSummary = <String, dynamic>{ 'average_frame_build_time_millis': computeAverageFrameBuildTimeMillis(), @@ -303,6 +313,9 @@ class TimelineSummary { 'average_layer_cache_count': rasterCacheSummarizer.computeAverageLayerCount(), '90th_percentile_layer_cache_count': rasterCacheSummarizer.computePercentileLayerCount(90.0), '99th_percentile_layer_cache_count': rasterCacheSummarizer.computePercentileLayerCount(99.0), + 'average_frame_request_pending_latency': frameRequestPendingLatencySummarizer.computeAverageFrameRequestPendingLatency(), + '90th_percentile_frame_request_pending_latency': frameRequestPendingLatencySummarizer.computePercentileFrameRequestPendingLatency(90.0), + '99th_percentile_frame_request_pending_latency': frameRequestPendingLatencySummarizer.computePercentileFrameRequestPendingLatency(99.0), 'worst_layer_cache_count': rasterCacheSummarizer.computeWorstLayerCount(), 'average_layer_cache_memory': rasterCacheSummarizer.computeAverageLayerMemory(), '90th_percentile_layer_cache_memory': rasterCacheSummarizer.computePercentileLayerMemory(90.0), @@ -491,5 +504,7 @@ class TimelineSummary { RasterCacheSummarizer _rasterCacheSummarizer() => RasterCacheSummarizer(_extractNamedEvents(kRasterCacheEvent)); + FrameRequestPendingLatencySummarizer _frameRequestPendingLatencySummarizer() => FrameRequestPendingLatencySummarizer(_extractNamedEvents(kFrameRequestPendingEvent)); + GCSummarizer _gcSummarizer() => GCSummarizer.fromEvents(_extractEventsWithNames(kGCRootEvents)); } diff --git a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart index 430df503df9c9..2e6c70a064f03 100644 --- a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart +++ b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart @@ -143,6 +143,20 @@ void main() { return result; } + Map<String, dynamic> frameRequestPendingStart(String id, int timeStamp) => <String, dynamic>{ + 'name': 'Frame Request Pending', + 'ph': 'b', + 'id': id, + 'ts': timeStamp, + }; + + Map<String, dynamic> frameRequestPendingEnd(String id, int timeStamp) => <String, dynamic>{ + 'name': 'Frame Request Pending', + 'ph': 'e', + 'id': id, + 'ts': timeStamp, + }; + group('frame_count', () { test('counts frames', () { expect( @@ -448,13 +462,19 @@ void main() { expect( summarize(<Map<String, dynamic>>[ begin(1000), end(19000), - begin(19000), end(29000), - begin(29000), end(49000), + begin(19001), end(29001), + begin(29002), end(49002), ...newGenGC(4, 10, 100), ...oldGenGC(5, 10000, 100), frameBegin(1000), frameEnd(18000), frameBegin(19000), frameEnd(28000), frameBegin(29000), frameEnd(48000), + frameRequestPendingStart('1', 1000), + frameRequestPendingEnd('1', 2000), + frameRequestPendingStart('2', 3000), + frameRequestPendingEnd('2', 5000), + frameRequestPendingStart('3', 6000), + frameRequestPendingEnd('3', 9000), ]).summaryJson, <String, dynamic>{ 'average_frame_build_time_millis': 15.0, @@ -475,7 +495,7 @@ void main() { 'frame_build_times': <int>[17000, 9000, 19000], 'frame_rasterizer_times': <int>[18000, 10000, 20000], 'frame_begin_times': <int>[0, 18000, 28000], - 'frame_rasterizer_begin_times': <int>[0, 18000, 28000], + 'frame_rasterizer_begin_times': <int>[0, 18001, 28002], 'average_vsync_transitions_missed': 0.0, '90th_percentile_vsync_transitions_missed': 0.0, '99th_percentile_vsync_transitions_missed': 0.0, @@ -505,6 +525,9 @@ void main() { '90hz_frame_percentage': 0, '120hz_frame_percentage': 0, 'illegal_refresh_rate_frame_count': 0, + 'average_frame_request_pending_latency': 2000.0, + '90th_percentile_frame_request_pending_latency': 3000.0, + '99th_percentile_frame_request_pending_latency': 3000.0, }, ); }); @@ -556,8 +579,8 @@ void main() { test('writes summary to JSON file', () async { await summarize(<Map<String, dynamic>>[ begin(1000), end(19000), - begin(19000), end(29000), - begin(29000), end(49000), + begin(19001), end(29001), + begin(29002), end(49002), frameBegin(1000), frameEnd(18000), frameBegin(19000), frameEnd(28000), frameBegin(29000), frameEnd(48000), @@ -569,6 +592,12 @@ void main() { cpuUsage(5000, 20), cpuUsage(5010, 60), memoryUsage(6000, 20, 40), memoryUsage(6100, 30, 45), platformVsync(7000), vsyncCallback(7500), + frameRequestPendingStart('1', 1000), + frameRequestPendingEnd('1', 2000), + frameRequestPendingStart('2', 3000), + frameRequestPendingEnd('2', 5000), + frameRequestPendingStart('3', 6000), + frameRequestPendingEnd('3', 9000), ]).writeTimelineToFile('test', destinationDirectory: tempDir.path); final String written = await fs.file(path.join(tempDir.path, 'test.timeline_summary.json')).readAsString(); @@ -591,7 +620,7 @@ void main() { 'frame_build_times': <int>[17000, 9000, 19000], 'frame_rasterizer_times': <int>[18000, 10000, 20000], 'frame_begin_times': <int>[0, 18000, 28000], - 'frame_rasterizer_begin_times': <int>[0, 18000, 28000], + 'frame_rasterizer_begin_times': <int>[0, 18001, 28002], 'average_vsync_transitions_missed': 8.0, '90th_percentile_vsync_transitions_missed': 12.0, '99th_percentile_vsync_transitions_missed': 12.0, @@ -627,6 +656,9 @@ void main() { '90hz_frame_percentage': 0, '120hz_frame_percentage': 0, 'illegal_refresh_rate_frame_count': 0, + 'average_frame_request_pending_latency': 2000.0, + '90th_percentile_frame_request_pending_latency': 3000.0, + '99th_percentile_frame_request_pending_latency': 3000.0, }); }); }); From f6f18d06889e26a4201d640c5d2440e2032df053 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Mon, 25 Sep 2023 23:09:32 -0400 Subject: [PATCH 1472/1547] Roll Flutter Engine from 6bf8067392cf to 75950dc280d5 (4 revisions) (#135480) https://github.com/flutter/engine/compare/6bf8067392cf...75950dc280d5 2023-09-26 skia-flutter-autoroll@skia.org Roll Dart SDK from 216b25f9ea6f to 7c749713c688 (1 revision) (flutter/engine#46284) 2023-09-25 bdero@google.com [Impeller] Support applying color filters on the CPU for the RRect fast path. (flutter/engine#46281) 2023-09-25 skia-flutter-autoroll@skia.org Roll Skia from 00e4d00021a7 to b961fc353715 (6 revisions) (flutter/engine#46280) 2023-09-25 jonahwilliams@google.com [Impeller] Dont blow away coverage hint on advanced blends. (flutter/engine#46219) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jonahwilliams@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index be4d08365abd1..87454b9a0acbd 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -6bf8067392cfb61a492d811065ffeb4d1feb35ac +75950dc280d55c9aa1ac33ac30f280a290fe0e4c From f11fb9a36b8e468a88a86bf040d8bccfa24cd51d Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 26 Sep 2023 04:39:23 -0400 Subject: [PATCH 1473/1547] Roll Flutter Engine from 75950dc280d5 to 230dfeed79ed (3 revisions) (#135489) https://github.com/flutter/engine/compare/75950dc280d5...230dfeed79ed 2023-09-26 skia-flutter-autoroll@skia.org Roll Dart SDK from 7c749713c688 to 7c3588c05f87 (1 revision) (flutter/engine#46288) 2023-09-26 godofredoc@google.com Prepare fuchsia script to coexist with v1 and v2 of fuchsia builders. (flutter/engine#46126) 2023-09-26 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from uY9WEf2tJxa1Hpp4v... to a56c8yPp4DDlj_Qbl... (flutter/engine#46285) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from uY9WEf2tJxa1 to a56c8yPp4DDl If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 87454b9a0acbd..5637766c6503c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -75950dc280d55c9aa1ac33ac30f280a290fe0e4c +230dfeed79ed7180ab1b9e600043731ecb746a2f diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index acb24bf12143a..2e0684338d2af 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -uY9WEf2tJxa1Hpp4v7RXvPN25swStFm4US-PlU6Xe8wC +a56c8yPp4DDlj_QblIlLum8BoJiVSDsDsJtweyEsZ7sC From feb5eee4ecb923b10d9c6305b755be193c79dace Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 26 Sep 2023 09:42:37 -0400 Subject: [PATCH 1474/1547] Roll Flutter Engine from 230dfeed79ed to 7b989a28514e (2 revisions) (#135494) https://github.com/flutter/engine/compare/230dfeed79ed...7b989a28514e 2023-09-26 skia-flutter-autoroll@skia.org Roll Skia from b961fc353715 to 8264a73430de (1 revision) (flutter/engine#46289) 2023-09-26 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 4.0.0 to 4.1.0 (flutter/engine#46290) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5637766c6503c..cb47ddf01c3ee 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -230dfeed79ed7180ab1b9e600043731ecb746a2f +7b989a28514edbfa3191a91031c1ebc5d86e0e89 From 936763f58963ef3dd103986fc232310c43360344 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 26 Sep 2023 12:03:00 -0400 Subject: [PATCH 1475/1547] Roll Packages from e548ae1d2045 to 619af75f7966 (4 revisions) (#135505) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/flutter/packages/compare/e548ae1d2045...619af75f7966 2023-09-25 47866232+chunhtai@users.noreply.github.com [go_router] Fixes the Android back button ignores top level route's o… (flutter/packages#4984) 2023-09-25 49699333+dependabot[bot]@users.noreply.github.com Bump actions/checkout from 4.0.0 to 4.1.0 (flutter/packages#4988) 2023-09-25 34871572+gmackall@users.noreply.github.com [camera_android] Set buildconfig to true for compatibility with AGP 8.0+ (flutter/packages#4951) 2023-09-25 stuartmorgan@google.com [various] Remove obsolete symlinks (flutter/packages#4993) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 272a7525f0c58..3fb150d36ffd8 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -e548ae1d2045974a6be0b9c9e3517cf23b78240e +619af75f7966f90498dfce3a754d37422b972c6d From 3cfe3720d61ccfc4f092f15e67637425fc908015 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:48:19 -0500 Subject: [PATCH 1476/1547] Wait for CONFIGURATION_BUILD_DIR to update when debugging with Xcode (#135444) So there appears to be a race situation between the flutter CLI and Xcode. In the CLI, we update the `CONFIGURATION_BUILD_DIR` in the Xcode build settings and then tell Xcode to install, launch, and debug the app. When Xcode installs the app, it should use the `CONFIGURATION_BUILD_DIR` to find the bundle. However, it appears that sometimes Xcode hasn't processed the change to the build settings before the install happens, which causes it to not be able to find the bundle. Fixes https://github.com/flutter/flutter/issues/135442 --- Since it's a timing issue, there's not really a consistent way to test it. I was able to confirm that it works, though, by using the following steps: 1. Create a flutter project 2. Open the project in Xcode 3. `flutter clean` 4. `flutter run --profile -v` If I saw a print line `stderr: CONFIGURATION_BUILD_DIR: build/Debug-iphoneos`, that means it first found the old and incorrect `CONFIGURATION_BUILD_DIR` before updating to the the new, so I was able to confirm that it would wait until it updated. --- packages/flutter_tools/bin/xcode_debug.js | 171 ++++++++++++++++-- .../flutter_tools/lib/src/ios/devices.dart | 26 +-- .../lib/src/ios/xcode_debug.dart | 13 ++ .../ios_device_start_nonprebuilt_test.dart | 3 + .../ios/ios_device_start_prebuilt_test.dart | 4 + .../general.shard/ios/xcode_debug_test.dart | 31 +++- 6 files changed, 215 insertions(+), 33 deletions(-) diff --git a/packages/flutter_tools/bin/xcode_debug.js b/packages/flutter_tools/bin/xcode_debug.js index 20b8f2337b386..35c39b88b5ae7 100644 --- a/packages/flutter_tools/bin/xcode_debug.js +++ b/packages/flutter_tools/bin/xcode_debug.js @@ -61,6 +61,11 @@ class CommandArguments { this.xcodePath = this.validatedStringArgument('--xcode-path', parsedArguments['--xcode-path']); this.projectPath = this.validatedStringArgument('--project-path', parsedArguments['--project-path']); + this.projectName = this.validatedStringArgument('--project-name', parsedArguments['--project-name']); + this.expectedConfigurationBuildDir = this.validatedStringArgument( + '--expected-configuration-build-dir', + parsedArguments['--expected-configuration-build-dir'], + ); this.workspacePath = this.validatedStringArgument('--workspace-path', parsedArguments['--workspace-path']); this.targetDestinationId = this.validatedStringArgument('--device-id', parsedArguments['--device-id']); this.targetSchemeName = this.validatedStringArgument('--scheme', parsedArguments['--scheme']); @@ -92,42 +97,76 @@ class CommandArguments { } /** - * Validates the flag is allowed for the current command. + * Returns map of commands to map of allowed arguments. For each command, if + * an argument flag is a key, than that flag is allowed for that command. If + * the value for the key is true, then it is required for the command. * - * @param {!string} flag - * @param {?string} value - * @returns {!bool} - * @throws Will throw an error if the flag is not allowed for the current - * command and the value is not null, undefined, or empty. + * @returns {!string} Map of commands to allowed and optionally required + * arguments. */ - isArgumentAllowed(flag, value) { - const allowedArguments = { - 'common': { + argumentSettings() { + return { + 'check-workspace-opened': { '--xcode-path': true, '--project-path': true, '--workspace-path': true, - '--verbose': true, + '--verbose': false, }, - 'check-workspace-opened': {}, 'debug': { + '--xcode-path': true, + '--project-path': true, + '--workspace-path': true, + '--project-name': true, + '--expected-configuration-build-dir': false, '--device-id': true, '--scheme': true, '--skip-building': true, '--launch-args': true, + '--verbose': false, }, 'stop': { + '--xcode-path': true, + '--project-path': true, + '--workspace-path': true, '--close-window': true, '--prompt-to-save': true, + '--verbose': false, }, - } + }; + } - const isAllowed = allowedArguments['common'][flag] === true || allowedArguments[this.command][flag] === true; + /** + * Validates the flag is allowed for the current command. + * + * @param {!string} flag + * @param {?string} value + * @returns {!bool} + * @throws Will throw an error if the flag is not allowed for the current + * command and the value is not null, undefined, or empty. + */ + isArgumentAllowed(flag, value) { + const isAllowed = this.argumentSettings()[this.command].hasOwnProperty(flag); if (isAllowed === false && (value != null && value !== '')) { throw `The flag ${flag} is not allowed for the command ${this.command}.`; } return isAllowed; } + /** + * Validates required flag has a value. + * + * @param {!string} flag + * @param {?string} value + * @throws Will throw an error if the flag is required for the current + * command and the value is not null, undefined, or empty. + */ + validateRequiredArgument(flag, value) { + const isRequired = this.argumentSettings()[this.command][flag] === true; + if (isRequired === true && (value == null || value === '')) { + throw `Missing value for ${flag}`; + } + } + /** * Parses the command line arguments into an object. * @@ -182,9 +221,7 @@ class CommandArguments { if (this.isArgumentAllowed(flag, value) === false) { return null; } - if (value == null || value === '') { - throw `Missing value for ${flag}`; - } + this.validateRequiredArgument(flag, value); return value; } @@ -227,9 +264,7 @@ class CommandArguments { if (this.isArgumentAllowed(flag, value) === false) { return null; } - if (value == null || value === '') { - throw `Missing value for ${flag}`; - } + this.validateRequiredArgument(flag, value); try { return JSON.parse(value); } catch (e) { @@ -348,6 +383,15 @@ function debugApp(xcode, args) { return new FunctionResult(null, destinationResult.error) } + // If expectedConfigurationBuildDir is available, ensure that it matches the + // build settings. + if (args.expectedConfigurationBuildDir != null && args.expectedConfigurationBuildDir !== '') { + const updateResult = waitForConfigurationBuildDirToUpdate(targetWorkspace, args); + if (updateResult.error != null) { + return new FunctionResult(null, updateResult.error); + } + } + try { // Documentation from the Xcode Script Editor dictionary indicates that the // `debug` function has a parameter called `runDestinationSpecifier` which @@ -529,3 +573,92 @@ function stopApp(xcode, args) { } return new FunctionResult(null, null); } + +/** + * Gets resolved build setting for CONFIGURATION_BUILD_DIR and waits until its + * value matches the `--expected-configuration-build-dir` argument. Waits up to + * 2 minutes. + * + * @param {!WorkspaceDocument} targetWorkspace A `WorkspaceDocument` (Xcode Mac + * Scripting class). + * @param {!CommandArguments} args + * @returns {!FunctionResult} Always returns null as the `result`. + */ +function waitForConfigurationBuildDirToUpdate(targetWorkspace, args) { + // Get the project + let project; + try { + project = targetWorkspace.projects().find(x => x.name() == args.projectName); + } catch (e) { + return new FunctionResult(null, `Failed to find project ${args.projectName}: ${e}`); + } + if (project == null) { + return new FunctionResult(null, `Failed to find project ${args.projectName}.`); + } + + // Get the target + let target; + try { + // The target is probably named the same as the project, but if not, just use the first. + const targets = project.targets(); + target = targets.find(x => x.name() == args.projectName); + if (target == null && targets.length > 0) { + target = targets[0]; + if (args.verbose) { + console.log(`Failed to find target named ${args.projectName}, picking first target: ${target.name()}.`); + } + } + } catch (e) { + return new FunctionResult(null, `Failed to find target: ${e}`); + } + if (target == null) { + return new FunctionResult(null, `Failed to find target.`); + } + + try { + // Use the first build configuration (Debug). Any should do since they all + // include Generated.xcconfig. + const buildConfig = target.buildConfigurations()[0]; + const buildSettings = buildConfig.resolvedBuildSettings().reverse(); + + // CONFIGURATION_BUILD_DIR is often at (reverse) index 225 for Xcode + // projects, so check there first. If it's not there, search the build + // settings (which can be a little slow). + const defaultIndex = 225; + let configurationBuildDirSettings; + if (buildSettings[defaultIndex] != null && buildSettings[defaultIndex].name() === 'CONFIGURATION_BUILD_DIR') { + configurationBuildDirSettings = buildSettings[defaultIndex]; + } else { + configurationBuildDirSettings = buildSettings.find(x => x.name() === 'CONFIGURATION_BUILD_DIR'); + } + + if (configurationBuildDirSettings == null) { + // This should not happen, even if it's not set by Flutter, there should + // always be a resolved build setting for CONFIGURATION_BUILD_DIR. + return new FunctionResult(null, `Unable to find CONFIGURATION_BUILD_DIR.`); + } + + // Wait up to 2 minutes for the CONFIGURATION_BUILD_DIR to update to the + // expected value. + const checkFrequencyInSeconds = 0.5; + const maxWaitInSeconds = 2 * 60; // 2 minutes + const verboseLogInterval = 10 * (1 / checkFrequencyInSeconds); + const iterations = maxWaitInSeconds * (1 / checkFrequencyInSeconds); + for (let i = 0; i < iterations; i++) { + const verbose = args.verbose && i % verboseLogInterval === 0; + + const configurationBuildDir = configurationBuildDirSettings.value(); + if (configurationBuildDir === args.expectedConfigurationBuildDir) { + console.log(`CONFIGURATION_BUILD_DIR: ${configurationBuildDir}`); + return new FunctionResult(null, null); + } + if (verbose) { + console.log(`Current CONFIGURATION_BUILD_DIR: ${configurationBuildDir} while expecting ${args.expectedConfigurationBuildDir}`); + } + delay(checkFrequencyInSeconds); + } + return new FunctionResult(null, 'Timed out waiting for CONFIGURATION_BUILD_DIR to update.'); + } catch (e) { + return new FunctionResult(null, `Failed to get CONFIGURATION_BUILD_DIR: ${e}`); + } +} diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart index 6be9ed3ca52ab..d07542d436591 100644 --- a/packages/flutter_tools/lib/src/ios/devices.dart +++ b/packages/flutter_tools/lib/src/ios/devices.dart @@ -723,6 +723,18 @@ class IOSDevice extends Device { return LaunchResult.failed(); } finally { startAppStatus.stop(); + + if ((isCoreDevice || forceXcodeDebugWorkflow) && debuggingOptions.debuggingEnabled && package is BuildableIOSApp) { + // When debugging via Xcode, after the app launches, reset the Generated + // settings to not include the custom configuration build directory. + // This is to prevent confusion if the project is later ran via Xcode + // rather than the Flutter CLI. + await updateGeneratedXcodeProperties( + project: FlutterProject.current(), + buildInfo: debuggingOptions.buildInfo, + targetOverride: mainPath, + ); + } } } @@ -868,6 +880,8 @@ class IOSDevice extends Device { scheme: scheme, xcodeProject: project.xcodeProject, xcodeWorkspace: project.xcodeWorkspace!, + hostAppProjectName: project.hostAppProjectName, + expectedConfigurationBuildDir: bundle.parent.absolute.path, verboseLogging: _logger.isVerbose, ); } else { @@ -889,18 +903,6 @@ class IOSDevice extends Device { shutdownHooks.addShutdownHook(() => _xcodeDebug.exit(force: true)); } - if (package is BuildableIOSApp) { - // After automating Xcode, reset the Generated settings to not include - // the custom configuration build directory. This is to prevent - // confusion if the project is later ran via Xcode rather than the - // Flutter CLI. - await updateGeneratedXcodeProperties( - project: flutterProject, - buildInfo: debuggingOptions.buildInfo, - targetOverride: mainPath, - ); - } - return debugSuccess; } } diff --git a/packages/flutter_tools/lib/src/ios/xcode_debug.dart b/packages/flutter_tools/lib/src/ios/xcode_debug.dart index e1b503643573c..563ec9d8e3444 100644 --- a/packages/flutter_tools/lib/src/ios/xcode_debug.dart +++ b/packages/flutter_tools/lib/src/ios/xcode_debug.dart @@ -85,6 +85,13 @@ class XcodeDebug { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, + if (project.expectedConfigurationBuildDir != null) + ...<String>[ + '--expected-configuration-build-dir', + project.expectedConfigurationBuildDir!, + ], '--device-id', deviceId, '--scheme', @@ -310,6 +317,7 @@ class XcodeDebug { _xcode.xcodeAppPath, '-g', // Do not bring the application to the foreground. '-j', // Launches the app hidden. + '-F', // Open "fresh", without restoring windows. xcodeWorkspace.path ], throwOnError: true, @@ -396,6 +404,7 @@ class XcodeDebug { return XcodeDebugProject( scheme: 'Runner', + hostAppProjectName: 'Runner', xcodeProject: tempXcodeProject.childDirectory('Runner.xcodeproj'), xcodeWorkspace: tempXcodeProject.childDirectory('Runner.xcworkspace'), isTemporaryProject: true, @@ -470,6 +479,8 @@ class XcodeDebugProject { required this.scheme, required this.xcodeWorkspace, required this.xcodeProject, + required this.hostAppProjectName, + this.expectedConfigurationBuildDir, this.isTemporaryProject = false, this.verboseLogging = false, }); @@ -477,6 +488,8 @@ class XcodeDebugProject { final String scheme; final Directory xcodeWorkspace; final Directory xcodeProject; + final String hostAppProjectName; + final String? expectedConfigurationBuildDir; final bool isTemporaryProject; /// When [verboseLogging] is true, the xcode_debug.js script will log diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart index 00d19d1edeab3..68d78e5f9b346 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_nonprebuilt_test.dart @@ -472,6 +472,7 @@ void main() { scheme: 'Runner', xcodeWorkspace: fileSystem.directory('/ios/Runner.xcworkspace'), xcodeProject: fileSystem.directory('/ios/Runner.xcodeproj'), + hostAppProjectName: 'Runner', ), expectedDeviceId: '123', expectedLaunchArguments: <String>['--enable-dart-profiling'], @@ -534,6 +535,8 @@ void main() { scheme: 'Runner', xcodeWorkspace: fileSystem.directory('/ios/Runner.xcworkspace'), xcodeProject: fileSystem.directory('/ios/Runner.xcodeproj'), + hostAppProjectName: 'Runner', + expectedConfigurationBuildDir: '/build/ios/iphoneos', ), expectedDeviceId: '123', expectedLaunchArguments: <String>['--enable-dart-profiling'], diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index d0aa1ab6e0ad6..37edf3ebe38ff 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -713,6 +713,7 @@ void main() { scheme: 'Runner', xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + hostAppProjectName: 'Runner', ), expectedDeviceId: '123', expectedLaunchArguments: <String>['--enable-dart-profiling'], @@ -757,6 +758,7 @@ void main() { scheme: 'Runner', xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + hostAppProjectName: 'Runner', ), expectedDeviceId: '123', expectedLaunchArguments: <String>['--enable-dart-profiling'], @@ -817,6 +819,7 @@ void main() { scheme: 'Runner', xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + hostAppProjectName: 'Runner', ), expectedDeviceId: '123', expectedLaunchArguments: <String>['--enable-dart-profiling'], @@ -869,6 +872,7 @@ void main() { scheme: 'Runner', xcodeWorkspace: temporaryXcodeProjectDirectory.childDirectory('Runner.xcworkspace'), xcodeProject: temporaryXcodeProjectDirectory.childDirectory('Runner.xcodeproj'), + hostAppProjectName: 'Runner', ), expectedDeviceId: '123', expectedLaunchArguments: <String>['--enable-dart-profiling'], diff --git a/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart b/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart index cbd2416c2d9c2..0fe3a8aa9bdae 100644 --- a/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/xcode_debug_test.dart @@ -56,10 +56,11 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', ); }); - testWithoutContext('succeeds in opening and debugging with launch options and verbose logging', () async { + testWithoutContext('succeeds in opening and debugging with launch options, expectedConfigurationBuildDir, and verbose logging', () async { fakeProcessManager.addCommands(<FakeCommand>[ FakeCommand( command: <String>[ @@ -88,6 +89,7 @@ void main() { pathToXcodeApp, '-g', '-j', + '-F', xcworkspace.path ], ), @@ -105,6 +107,10 @@ void main() { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, + '--expected-configuration-build-dir', + '/build/ios/iphoneos', '--device-id', deviceId, '--scheme', @@ -131,6 +137,8 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', + expectedConfigurationBuildDir: '/build/ios/iphoneos', verboseLogging: true, ); @@ -150,7 +158,7 @@ void main() { expect(status, true); }); - testWithoutContext('succeeds in opening and debugging without launch options and verbose logging', () async { + testWithoutContext('succeeds in opening and debugging without launch options, expectedConfigurationBuildDir, and verbose logging', () async { fakeProcessManager.addCommands(<FakeCommand>[ FakeCommand( command: <String>[ @@ -178,6 +186,7 @@ void main() { pathToXcodeApp, '-g', '-j', + '-F', xcworkspace.path ], ), @@ -195,6 +204,8 @@ void main() { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, '--device-id', deviceId, '--scheme', @@ -257,6 +268,7 @@ void main() { pathToXcodeApp, '-g', '-j', + '-F', xcworkspace.path ], exception: ProcessException( @@ -266,6 +278,7 @@ void main() { '/non_existant_path', '-g', '-j', + '-F', xcworkspace.path, ], 'The application /non_existant_path cannot be opened for an unexpected reason', @@ -332,6 +345,8 @@ void main() { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, '--device-id', deviceId, '--scheme', @@ -401,6 +416,8 @@ void main() { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, '--device-id', deviceId, '--scheme', @@ -474,6 +491,8 @@ void main() { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, '--device-id', deviceId, '--scheme', @@ -547,6 +566,8 @@ void main() { project.xcodeProject.path, '--workspace-path', project.xcodeWorkspace.path, + '--project-name', + project.hostAppProjectName, '--device-id', deviceId, '--scheme', @@ -674,6 +695,7 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', ); final XcodeDebug xcodeDebug = XcodeDebug( logger: logger, @@ -731,6 +753,7 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', isTemporaryProject: true, ); @@ -794,6 +817,7 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', isTemporaryProject: true, ); final XcodeDebug xcodeDebug = XcodeDebug( @@ -857,6 +881,7 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', ); final XcodeDebug xcodeDebug = XcodeDebug( logger: logger, @@ -899,6 +924,7 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', isTemporaryProject: true, ); final XcodeDebug xcodeDebug = XcodeDebug( @@ -950,6 +976,7 @@ void main() { scheme: 'Runner', xcodeProject: xcodeproj, xcodeWorkspace: xcworkspace, + hostAppProjectName: 'Runner', ); }); From 7143284102ee6c7e341e52c5c88697ca537dbd47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:27:00 -0700 Subject: [PATCH 1477/1547] [Windows] Add more Arm64 compile and run tests (#135475) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of: https://github.com/flutter/flutter/issues/129806 Test runs kicked off using `led`: * Compile tests * ✅ [flutter_gallery_win_desktop__compile](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/a23b73ca25cc56309a725c77be0107aaa1f2d09b1f41f1cc04276b85fac34366/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR2Yv8iS9YbTxMZKS2i5zmAz9E8FCNjW6waLq4e8HwtaFtMlapl66UHf73w) * Start up tests * ✅ [windows_startup_test](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/e615b28993c8b4fcb90e2d52226f9e4d9478850bee67f1f19a88d37e767dcfc2/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR1YtPTpAr6FRq71fy392orp6PO8t9jN8n-mpWvlDF0xRnnOsq3zsAPabWg) * ✅ [flutter_gallery_win_desktop__start_up](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/a0148122f81f3eee512ba8e59adcfcff86195eac10dc9a95969b36ae63e0d3e0/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR29O3jW-LyaVAwD54jUmnhfZ2mswqtaZascRoGvteT5gaHihxKI4IastgM) * ✅ [flutter_view_win_desktop__start_up](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/6dac552365a2d5502aeda81563f4e62f7bdb73f383d98ed8d8ae52c62e00edea/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR2_irHDuoZ0V-PSjYDW082yx8ZeDVhOIk0yjQBAZNVa5iKVIGAWZs8v4lo) * ✅ [platform_view_win_desktop__start_up](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/e6522c77bcbecabdd1f6d38f3b4e1ea41055d8ae7d61f92b741cc953b94d2e15/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR2X7KJDGjQUWJtpq7KY-nUFK-LA6LvmrAinzj0QuF8pEbpwfsAz6Kv3OkM) * ✅ [complex_layout_win_desktop__start_up](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/a811334185bc077a5cb69e46fc109ee3e679df6a924ee28d3c73f8b18717fa31/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR0gIiXFMnB_MSaqUxVyTpgpJqc37xSKqOzEsf2oD_oU-AhKPqrGQ-ZD7IY) * `flutter run` console output tests * ✅ [run_debug_test_windows](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/1b275a8b161c965c44c09565a5a9784e322cded973b52dc24645496f43aead5a/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR1IlBr0824cq9UKi46j_11eto6HTEQ9KVXF5Is1ZxcSIO7G6IlN-slsyI8) * ✅ [run_release_test_windows](https://ci.chromium.org/raw/build/logs.chromium.org/flutter/led/loicsharma_google.com/5b259bb5e2c07666fa12f053c3f5bd782bf074563a9afeeea231fa48bd33daa2/+/build.proto?server=chromium-swarm.appspot.com&fbclid=IwAR3DSHzCGL-KN26E-7hQL58qxV2p0Dtb9hE4AZ0HvEY4hp8mCMzX9jznsFQ) /cc @pbo-linaro --- .ci.yaml | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index efc30c7ad7578..4fcfc6696cc3b 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4814,6 +4814,25 @@ targets: - bin/** - .ci.yaml + - name: Windows_arm64 run_debug_test_windows + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + task_name: run_debug_test_windows + runIf: + - dev/** + - packages/flutter_tools/** + - bin/** + - .ci.yaml + - name: Windows run_release_test_windows recipe: devicelab/devicelab_drone presubmit: false @@ -4832,6 +4851,25 @@ targets: - bin/** - .ci.yaml + - name: Windows_arm64 run_release_test_windows + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + task_name: run_release_test_windows + runIf: + - dev/** + - packages/flutter_tools/** + - bin/** + - .ci.yaml + - name: Windows tool_integration_tests_1_6 recipe: flutter/flutter_drone timeout: 60 @@ -5111,6 +5149,20 @@ targets: ] task_name: flutter_gallery_win_desktop__compile + - name: Windows_arm64 flutter_gallery_win_desktop__compile + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + task_name: flutter_gallery_win_desktop__compile + - name: Windows flutter_gallery_win_desktop__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -5124,6 +5176,20 @@ targets: ] task_name: flutter_gallery_win_desktop__start_up + - name: Windows_arm64 flutter_gallery_win_desktop__start_up + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + task_name: flutter_gallery_win_desktop__start_up + - name: Windows complex_layout_win_desktop__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -5137,6 +5203,20 @@ targets: ] task_name: complex_layout_win_desktop__start_up + - name: Windows_arm64 complex_layout_win_desktop__start_up + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + task_name: complex_layout_win_desktop__start_up + - name: Windows flutter_view_win_desktop__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -5150,6 +5230,20 @@ targets: ] task_name: flutter_view_win_desktop__start_up + - name: Windows_arm64 flutter_view_win_desktop__start_up + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + task_name: flutter_view_win_desktop__start_up + - name: Windows platform_view_win_desktop__start_up recipe: devicelab/devicelab_drone presubmit: false @@ -5163,6 +5257,20 @@ targets: ] task_name: platform_view_win_desktop__start_up + - name: Windows_arm64 platform_view_win_desktop__start_up + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + task_name: platform_view_win_desktop__start_up + - name: Windows_android basic_material_app_win__compile recipe: devicelab/devicelab_drone presubmit: false @@ -5242,6 +5350,20 @@ targets: ["devicelab", "hostonly", "windows"] task_name: windows_startup_test + - name: Windows_arm64 windows_startup_test + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + dependencies: >- + [ + {"dependency": "vs_build", "version": "version:vs2019"} + ] + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + task_name: windows_startup_test + - name: Windows flutter_tool_startup__windows recipe: devicelab/devicelab_drone presubmit: false @@ -5251,6 +5373,16 @@ targets: ["devicelab", "hostonly", "windows"] task_name: flutter_tool_startup + - name: Windows_arm64 flutter_tool_startup__windows + recipe: devicelab/devicelab_drone + bringup: true # https://github.com/flutter/flutter/issues/134083 + presubmit: false + timeout: 60 + properties: + tags: > + ["devicelab", "hostonly", "windows", "arm64"] + task_name: flutter_tool_startup + - name: Linux flutter_tool_startup__linux recipe: devicelab/devicelab_drone presubmit: false From 54678fdb6004b5564b47f4689d473af5d4e64278 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 26 Sep 2023 15:41:19 -0400 Subject: [PATCH 1478/1547] Roll Flutter Engine from 7b989a28514e to acdb364a42d5 (2 revisions) (#135516) https://github.com/flutter/engine/compare/7b989a28514e...acdb364a42d5 2023-09-26 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from we5owZaebdO_3kyjz... to OMrTgAfDg9PKXTzq0... (flutter/engine#46294) 2023-09-26 skia-flutter-autoroll@skia.org Roll Skia from 8264a73430de to dd6a4e3655fc (2 revisions) (flutter/engine#46291) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from we5owZaebdO_ to OMrTgAfDg9PK If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index cb47ddf01c3ee..077b1fe766138 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7b989a28514edbfa3191a91031c1ebc5d86e0e89 +acdb364a42d51a3db93b5ee3da4ddb1de258cc54 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 24084301c34c4..a188d4efa073c 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -we5owZaebdO_3kyjzbmpyh37YiP2bGjPyaGIUnxXruUC +OMrTgAfDg9PKXTzq02S-SPbjInFqsBoiPrFMP-k3TNYC From c21bf45b20e4723ecf9b4a57e90116b533e5d56f Mon Sep 17 00:00:00 2001 From: Derek Xu <derekx@google.com> Date: Tue, 26 Sep 2023 17:20:37 -0400 Subject: [PATCH 1479/1547] Switch flutter_tools to run frontend server from AOT snapshot (#135255) Co-authored-by: Christopher Fujino <fujino@google.com> --- packages/flutter_tools/lib/src/artifacts.dart | 2 +- .../lib/src/build_system/targets/common.dart | 1 + packages/flutter_tools/lib/src/compile.dart | 70 ++++++++++++------- .../test/general.shard/artifacts_test.dart | 7 +- .../build_system/targets/common_test.dart | 14 ++-- .../general.shard/compile_batch_test.dart | 18 ++--- .../compile_incremental_test.dart | 2 +- .../test/web_test_compiler_test.dart | 2 +- 8 files changed, 70 insertions(+), 46 deletions(-) diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 8775db6fec1f1..161e8b6ae7daa 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -190,7 +190,7 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod case Artifact.wasmOptBinary: return 'wasm-opt$exe'; case Artifact.frontendServerSnapshotForEngineDartSdk: - return 'frontend_server.dart.snapshot'; + return 'frontend_server_aot.dart.snapshot'; case Artifact.linuxDesktopPath: return ''; case Artifact.linuxHeaders: diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index d5febecf4251a..c3507abb349aa 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -132,6 +132,7 @@ class KernelSnapshot extends Target { Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), Source.artifact(Artifact.platformKernelDill), Source.artifact(Artifact.engineDartBinary), + Source.artifact(Artifact.engineDartAotRuntime), Source.artifact(Artifact.frontendServerSnapshotForEngineDartSdk), ]; diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index e7571a69eac32..15d209367f156 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -244,20 +244,10 @@ class KernelCompiler { String? nativeAssets, }) async { final TargetPlatform? platform = targetModel == TargetModel.dartdevc ? TargetPlatform.web_javascript : null; - final String frontendServer = (frontendServerStarterPath == null || frontendServerStarterPath.isEmpty) - ? _artifacts.getArtifactPath( - Artifact.frontendServerSnapshotForEngineDartSdk, - platform: platform, - ) - : frontendServerStarterPath; // This is a URI, not a file path, so the forward slash is correct even on Windows. if (!sdkRoot.endsWith('/')) { sdkRoot = '$sdkRoot/'; } - final String engineDartPath = _artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform); - if (!_processManager.canRun(engineDartPath)) { - throwToolExit('Unable to find Dart binary at $engineDartPath'); - } String? mainUri; final File mainFile = _fileSystem.file(mainPath); final Uri mainFileUri = mainFile.uri; @@ -282,10 +272,33 @@ class KernelCompiler { toMultiRootPath(dartPluginRegistrantFileUri, _fileSystemScheme, _fileSystemRoots, _fileSystem.path.separator == r'\'); } - final List<String> command = <String>[ - engineDartPath, - '--disable-dart-dev', - frontendServer, + final List<String> commandToStartFrontendServer; + if (frontendServerStarterPath != null && frontendServerStarterPath.isNotEmpty) { + final String engineDartPath = _artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform); + if (!_processManager.canRun(engineDartPath)) { + throwToolExit('Unable to find Dart binary at $engineDartPath'); + } + commandToStartFrontendServer = <String>[ + engineDartPath, + '--disable-dart-dev', + frontendServerStarterPath, + ]; + } else { + final String engineDartAotRuntimePath = _artifacts.getArtifactPath(Artifact.engineDartAotRuntime, platform: platform); + if (!_processManager.canRun(engineDartAotRuntimePath)) { + throwToolExit('Unable to find dartaotruntime binary at $engineDartAotRuntimePath'); + } + commandToStartFrontendServer = <String>[ + engineDartAotRuntimePath, + '--disable-dart-dev', + _artifacts.getArtifactPath( + Artifact.frontendServerSnapshotForEngineDartSdk, + platform: platform, + ), + ]; + } + + final List<String> command = commandToStartFrontendServer + <String>[ '--sdk-root', sdkRoot, '--target=$targetModel', @@ -777,16 +790,25 @@ class DefaultResidentCompiler implements ResidentCompiler { String? nativeAssetsUri, }) async { final TargetPlatform? platform = (targetModel == TargetModel.dartdevc) ? TargetPlatform.web_javascript : null; - final String frontendServer = (frontendServerStarterPath == null || frontendServerStarterPath!.isEmpty) - ? artifacts.getArtifactPath( - Artifact.frontendServerSnapshotForEngineDartSdk, - platform: platform, - ) - : frontendServerStarterPath!; - final List<String> command = <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), - '--disable-dart-dev', - frontendServer, + late final List<String> commandToStartFrontendServer; + if (frontendServerStarterPath != null && frontendServerStarterPath!.isNotEmpty) { + commandToStartFrontendServer = <String>[ + artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), + '--disable-dart-dev', + frontendServerStarterPath!, + ]; + } else { + commandToStartFrontendServer = <String>[ + artifacts.getArtifactPath(Artifact.engineDartAotRuntime, platform: platform), + '--disable-dart-dev', + artifacts.getArtifactPath( + Artifact.frontendServerSnapshotForEngineDartSdk, + platform: platform, + ), + ]; + } + + final List<String> command = commandToStartFrontendServer + <String>[ '--sdk-root', sdkRoot, '--incremental', diff --git a/packages/flutter_tools/test/general.shard/artifacts_test.dart b/packages/flutter_tools/test/general.shard/artifacts_test.dart index 920980a23ba2f..dc39ffe002c8c 100644 --- a/packages/flutter_tools/test/general.shard/artifacts_test.dart +++ b/packages/flutter_tools/test/general.shard/artifacts_test.dart @@ -143,7 +143,8 @@ void main() { ); expect( artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), - fileSystem.path.join('root', 'bin', 'cache', 'dart-sdk', 'bin', 'snapshots', 'frontend_server.dart.snapshot') + fileSystem.path.join('root', 'bin', 'cache', 'dart-sdk', 'bin', + 'snapshots', 'frontend_server_aot.dart.snapshot') ); }); @@ -325,7 +326,7 @@ void main() { expect( artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), fileSystem.path.join('/out', 'host_debug_unopt', 'dart-sdk', 'bin', - 'snapshots', 'frontend_server.dart.snapshot') + 'snapshots', 'frontend_server_aot.dart.snapshot') ); @@ -397,7 +398,7 @@ void main() { Artifact.frontendServerSnapshotForEngineDartSdk, platform: TargetPlatform.web_javascript), fileSystem.path.join('/flutter', 'prebuilts', 'linux-x64', 'dart-sdk', 'bin', - 'snapshots', 'frontend_server.dart.snapshot'), + 'snapshots', 'frontend_server_aot.dart.snapshot'), ); expect( artifacts.getArtifactPath( diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index a287f1b0d0923..0b05203de2520 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -94,7 +94,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -139,7 +139,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -185,7 +185,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -279,7 +279,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -328,7 +328,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -375,7 +375,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -434,7 +434,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary), + artifacts.getArtifactPath(Artifact.engineDartAotRuntime), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', diff --git a/packages/flutter_tools/test/general.shard/compile_batch_test.dart b/packages/flutter_tools/test/general.shard/compile_batch_test.dart index e82fb93fe600e..9d2ad2a8868fc 100644 --- a/packages/flutter_tools/test/general.shard/compile_batch_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_batch_test.dart @@ -53,7 +53,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -99,7 +99,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -145,7 +145,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -191,7 +191,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -239,7 +239,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -287,7 +287,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -339,7 +339,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -389,7 +389,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -449,7 +449,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', diff --git a/packages/flutter_tools/test/general.shard/compile_incremental_test.dart b/packages/flutter_tools/test/general.shard/compile_incremental_test.dart index adaa4c2a6b973..14749ae1d458e 100644 --- a/packages/flutter_tools/test/general.shard/compile_incremental_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_incremental_test.dart @@ -30,7 +30,7 @@ void main() { late FakeProcessManager fakeProcessManager; const List<String> frontendServerCommand = <String>[ - 'Artifact.engineDartBinary', + 'Artifact.engineDartAotRuntime', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', diff --git a/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart b/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart index 54f8be20c9310..26ed691651c53 100644 --- a/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart +++ b/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart @@ -36,7 +36,7 @@ void main() { ); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <Pattern>[ - 'Artifact.engineDartBinary.TargetPlatform.web_javascript', + 'Artifact.engineDartAotRuntime.TargetPlatform.web_javascript', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk.TargetPlatform.web_javascript', '--sdk-root', From d81c8aa88b8b84a75313a32cb26468540d50fee4 Mon Sep 17 00:00:00 2001 From: Renzo Olivares <rmolivares@renzo-olivares.dev> Date: Tue, 26 Sep 2023 15:06:15 -0700 Subject: [PATCH 1480/1547] SelectionArea long press selection overlay behavior should match native (#133967) During a long press, on native iOS the context menu does not show until the long press has ended. The handles are shown immediately when the long press begins. This is true for static and editable text. For static text on Android, the context menu appears when the long press is initiated, but the handles do not appear until the long press has ended. For editable text on Android, the context menu does not appear until the long press ended, and the handles also do not appear until the end. For both platforms in editable/static contexts the context menu does not show while doing a long press drag. I think the behavior where the context menu is not shown until the long press ends makes the most sense even though Android varies in this depending on the context. The user is not able to react to the context menu until the long press has ended. Other details: On a windows touch screen device the context menu does not show up until the long press ends in editable/static text contexts. On a long press hold it selects the word on drag start as well as popping up the selection handles (static text). --- .../lib/src/widgets/selectable_region.dart | 12 ++- .../test/material/selection_area_test.dart | 5 + .../widgets/scrollable_selection_test.dart | 3 + .../test/widgets/selectable_region_test.dart | 99 +++++++++++++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 371e178e026a3..4b972c081e311 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -539,8 +539,12 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe HapticFeedback.selectionClick(); widget.focusNode.requestFocus(); _selectWordAt(offset: details.globalPosition); - _showToolbar(); - _showHandles(); + // Platforms besides Android will show the text selection handles when + // the long press is initiated. Android shows the text selection handles when + // the long press has ended, usually after a pointer up event is received. + if (defaultTargetPlatform != TargetPlatform.android) { + _showHandles(); + } _updateSelectedContentIfNeeded(); } @@ -552,6 +556,10 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe void _handleTouchLongPressEnd(LongPressEndDetails details) { _finalizeSelection(); _updateSelectedContentIfNeeded(); + _showToolbar(); + if (defaultTargetPlatform == TargetPlatform.android) { + _showHandles(); + } } bool _positionIsOnActiveSelection({required Offset globalPosition}) { diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index 1a61612b6492d..8edb4b68d4bac 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -151,6 +151,8 @@ void main() { await tester.pump(const Duration(milliseconds: 500)); // `are` is selected. expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); + + await gesture.up(); await tester.pumpAndSettle(); expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); @@ -189,6 +191,8 @@ void main() { await tester.pump(const Duration(milliseconds: 500)); // `are` is selected. expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); + + await gesture.up(); await tester.pumpAndSettle(); expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); @@ -262,6 +266,7 @@ void main() { await gesture.up(); final List<TextBox> boxes = paragraph2.getBoxesForSelection(paragraph2.selections[0]); expect(boxes.length, 1); + await tester.pumpAndSettle(); // There is a selection now. // We check the presence of the copy button to make sure the selection toolbar // is showing. diff --git a/packages/flutter/test/widgets/scrollable_selection_test.dart b/packages/flutter/test/widgets/scrollable_selection_test.dart index fbafd52e28215..043b484bff97d 100644 --- a/packages/flutter/test/widgets/scrollable_selection_test.dart +++ b/packages/flutter/test/widgets/scrollable_selection_test.dart @@ -561,6 +561,7 @@ void main() { addTearDown(gesture.removePointer); await tester.pump(const Duration(milliseconds: 500)); await gesture.up(); + await tester.pumpAndSettle(); expect(paragraph0.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); final List<TextBox> boxes = paragraph0.getBoxesForSelection(paragraph0.selections[0]); @@ -619,6 +620,7 @@ void main() { addTearDown(gesture.removePointer); await tester.pump(const Duration(milliseconds: 500)); await gesture.up(); + await tester.pumpAndSettle(); expect(paragraph0.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); final List<TextBox> boxes = paragraph0.getBoxesForSelection(paragraph0.selections[0]); @@ -674,6 +676,7 @@ void main() { addTearDown(gesture.removePointer); await tester.pump(const Duration(milliseconds: 500)); await gesture.up(); + await tester.pumpAndSettle(); expect(paragraph0.selections[0], const TextSelection(baseOffset: 0, extentOffset: 4)); final List<TextBox> boxes = paragraph0.getBoxesForSelection(paragraph0.selections[0]); diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index e28fb1640370e..717ba3d5f1825 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -949,6 +949,100 @@ void main() { await gesture.up(); }); + testWidgets( + 'long press selection overlay behavior on iOS and Android', + (WidgetTester tester) async { + // This test verifies that all platforms wait until long press end to + // show the context menu, and only Android waits until long press end to + // show the selection handles. + final bool isPlatformAndroid = defaultTargetPlatform == TargetPlatform.android; + Set<ContextMenuButtonType> buttonTypes = <ContextMenuButtonType>{}; + final UniqueKey toolbarKey = UniqueKey(); + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: FocusNode(), + selectionControls: materialTextSelectionHandleControls, + contextMenuBuilder: ( + BuildContext context, + SelectableRegionState selectableRegionState, + ) { + buttonTypes = selectableRegionState.contextMenuButtonItems + .map((ContextMenuButtonItem buttonItem) => buttonItem.type) + .toSet(); + return SizedBox.shrink(key: toolbarKey); + }, + child: const Text('How are you?'), + ), + ), + ); + + expect(buttonTypes.isEmpty, true); + expect(find.byKey(toolbarKey), findsNothing); + + final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2)); + addTearDown(gesture.removePointer); + await tester.pump(const Duration(milliseconds: 500)); + await tester.pumpAndSettle(); + + // All platform except Android should show the selection handles when the + // long press starts. + List<FadeTransition> transitions = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_SelectionHandleOverlay'), + matching: find.byType(FadeTransition), + ).evaluate().map((Element e) => e.widget).cast<FadeTransition>().toList(); + expect(transitions.length, isPlatformAndroid ? 0 : 2); + FadeTransition? left; + FadeTransition? right; + if (!isPlatformAndroid) { + left = transitions[0]; + right = transitions[1]; + expect(left.opacity.value, equals(1.0)); + expect(right.opacity.value, equals(1.0)); + } + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); + expect(find.byKey(toolbarKey), findsNothing); + + await gesture.moveTo(textOffsetToPosition(paragraph, 8)); + await tester.pumpAndSettle(); + transitions = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_SelectionHandleOverlay'), + matching: find.byType(FadeTransition), + ).evaluate().map((Element e) => e.widget).cast<FadeTransition>().toList(); + // All platform except Android should show the selection handles while doing + // a long press drag. + expect(transitions.length, isPlatformAndroid ? 0 : 2); + if (!isPlatformAndroid) { + left = transitions[0]; + right = transitions[1]; + expect(left.opacity.value, equals(1.0)); + expect(right.opacity.value, equals(1.0)); + } + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 11)); + expect(find.byKey(toolbarKey), findsNothing); + + await gesture.up(); + await tester.pumpAndSettle(); + transitions = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_SelectionHandleOverlay'), + matching: find.byType(FadeTransition), + ).evaluate().map((Element e) => e.widget).cast<FadeTransition>().toList(); + expect(transitions.length, 2); + left = transitions[0]; + right = transitions[1]; + + // All platforms should show the selection handles and context menu when + // the long press ends. + expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 11)); + expect(left.opacity.value, equals(1.0)); + expect(right.opacity.value, equals(1.0)); + expect(find.byKey(toolbarKey), findsOneWidget); + }, + variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.iOS }), + skip: kIsWeb, // [intended] Web uses its native context menu. + ); + testWidgetsWithLeakTracking( 'single tap on the previous selection toggles the toolbar on iOS', (WidgetTester tester) async { @@ -2695,6 +2789,9 @@ void main() { // `are` is selected. expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); await tester.pumpAndSettle(); + + await gesture.up(); + await tester.pumpAndSettle(); // Text selection toolbar has appeared. expect(find.text('Copy'), findsOneWidget); @@ -2862,6 +2959,8 @@ void main() { await tester.pump(const Duration(milliseconds: 500)); // `are` is selected. expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); + + await gesture.up(); await tester.pumpAndSettle(); expect(buttonTypes, contains(ContextMenuButtonType.copy)); From 67d4a831165d828fcf8afb6ff4a93ef67e8228d6 Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Tue, 26 Sep 2023 17:38:18 -0500 Subject: [PATCH 1481/1547] Allow multiple ParentDataWidgets to write to ParentData (#133581) Fixes https://github.com/flutter/flutter/issues/133089 This allows more than one ParentDataWidget to write to the ParentData of a child render object. Previously only one was allowed. There are some rules though: 1. Only one of a given type of `ParentDataWidget` can write to the `ParentData` of a given child. a. For example, 2 `Positioned` widgets wrapping a child of a `Stack` would not be allowed, as only one of type `Positioned` can contribute data. 2. The type of `ParentData` **must** be compatible with all of the `ParentDataWidget`s that want to contribute data. a. For example, `TwoDimensionalViewportParentData` mixes in the `KeepAliveParentDataMixin`. So the `ParentData` of a given child would be compatible with the `KeepAlive` `ParentDataWidget`, as well as another `ParentDataWidget` that writes `TwoDimensionalViewportParentData` (or a subclass of `TwoDimensionalViewportParentData` - This was the motivation for this change, where a `ParentDataWidget` is being used in `TableView` with the parent data type being a subclass of `TwoDimensionalViewportParentData`.) --- .../flutter/lib/src/widgets/framework.dart | 160 ++++++++++++++---- .../test/widgets/parent_data_test.dart | 152 ++++++++++++++++- .../test/widgets/two_dimensional_utils.dart | 41 +++++ .../two_dimensional_viewport_test.dart | 116 ++++++++++++- 4 files changed, 424 insertions(+), 45 deletions(-) diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index 18a2a2e6268c2..0d5fd908cde31 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -5824,12 +5824,28 @@ class ParentDataElement<T extends ParentData> extends ProxyElement { /// Creates an element that uses the given widget as its configuration. ParentDataElement(ParentDataWidget<T> super.widget); + /// Returns the [Type] of [ParentData] that this element has been configured + /// for. + /// + /// This is only available in debug mode. It will throw in profile and + /// release modes. + Type get debugParentDataType { + Type? type; + assert(() { + type = T; + return true; + }()); + if (type != null) { + return type!; + } + throw UnsupportedError('debugParentDataType is only supported in debug builds'); + } + void _applyParentData(ParentDataWidget<T> widget) { void applyParentDataToChild(Element child) { if (child is RenderObjectElement) { child._updateParentData(widget); } else { - assert(child is! ParentDataElement<ParentData>); child.visitChildren(applyParentDataToChild); } } @@ -6278,50 +6294,124 @@ abstract class RenderObjectElement extends Element { return ancestor as RenderObjectElement?; } - ParentDataElement<ParentData>? _findAncestorParentDataElement() { - Element? ancestor = _parent; - ParentDataElement<ParentData>? result; - while (ancestor != null && ancestor is! RenderObjectElement) { - if (ancestor is ParentDataElement<ParentData>) { - result = ancestor; - break; - } - ancestor = ancestor._parent; - } + void _debugCheckCompetingAncestors( + List<ParentDataElement<ParentData>> result, + Set<Type> debugAncestorTypes, + Set<Type> debugParentDataTypes, + List<Type> debugAncestorCulprits, + ) { assert(() { - if (result == null || ancestor == null) { - return true; - } - // Check that no other ParentDataWidgets want to provide parent data. - final List<ParentDataElement<ParentData>> badAncestors = <ParentDataElement<ParentData>>[]; - ancestor = ancestor!._parent; - while (ancestor != null && ancestor is! RenderObjectElement) { - if (ancestor is ParentDataElement<ParentData>) { - badAncestors.add(ancestor! as ParentDataElement<ParentData>); - } - ancestor = ancestor!._parent; - } - if (badAncestors.isNotEmpty) { - badAncestors.insert(0, result); + // Check that no other ParentDataWidgets of the same + // type want to provide parent data. + if (debugAncestorTypes.length != result.length || debugParentDataTypes.length != result.length) { + // This can only occur if the Sets of ancestors and parent data types was + // provided a dupe and did not add it. + assert(debugAncestorTypes.length < result.length || debugParentDataTypes.length < result.length); try { // We explicitly throw here (even though we immediately redirect the // exception elsewhere) so that debuggers will notice it when they // have "break on exception" enabled. throw FlutterError.fromParts(<DiagnosticsNode>[ ErrorSummary('Incorrect use of ParentDataWidget.'), - ErrorDescription('The following ParentDataWidgets are providing parent data to the same RenderObject:'), - for (final ParentDataElement<ParentData> ancestor in badAncestors) - ErrorDescription('- ${ancestor.widget} (typically placed directly inside a ${(ancestor.widget as ParentDataWidget<ParentData>).debugTypicalAncestorWidgetDescription} widget)'), - ErrorDescription('However, a RenderObject can only receive parent data from at most one ParentDataWidget.'), - ErrorHint('Usually, this indicates that at least one of the offending ParentDataWidgets listed above is not placed directly inside a compatible ancestor widget.'), - ErrorDescription('The ownership chain for the RenderObject that received the parent data was:\n ${debugGetCreatorChain(10)}'), + ErrorDescription( + 'Competing ParentDataWidgets are providing parent data to the ' + 'same RenderObject:' + ), + for (final ParentDataElement<ParentData> ancestor in result.where((ParentDataElement<ParentData> ancestor) { + return debugAncestorCulprits.contains(ancestor.runtimeType); + })) + ErrorDescription( + '- ${ancestor.widget}, which writes ParentData of type ' + '${ancestor.debugParentDataType}, (typically placed directly ' + 'inside a ' + '${(ancestor.widget as ParentDataWidget<ParentData>).debugTypicalAncestorWidgetClass} ' + 'widget)' + ), + ErrorDescription( + 'A RenderObject can receive parent data from multiple ' + 'ParentDataWidgets, but the Type of ParentData must be unique to ' + 'prevent one overwriting another.' + ), + ErrorHint( + 'Usually, this indicates that one or more of the offending ' + "ParentDataWidgets listed above isn't placed inside a dedicated " + "compatible ancestor widget that it isn't sharing with another " + 'ParentDataWidget of the same type.' + ), + ErrorHint( + 'Otherwise, separating aspects of ParentData to prevent ' + 'conflicts can be done using mixins, mixing them all in on the ' + 'full ParentData Object, such as KeepAlive does with ' + 'KeepAliveParentDataMixin.' + ), + ErrorDescription( + 'The ownership chain for the RenderObject that received the ' + 'parent data was:\n ${debugGetCreatorChain(10)}' + ), ]); - } on FlutterError catch (e) { - _reportException(ErrorSummary('while looking for parent data.'), e, e.stackTrace); + } on FlutterError catch (error) { + _reportException( + ErrorSummary('while looking for parent data.'), + error, + error.stackTrace, + ); } } return true; }()); + } + + List<ParentDataElement<ParentData>> _findAncestorParentDataElements() { + Element? ancestor = _parent; + final List<ParentDataElement<ParentData>> result = <ParentDataElement<ParentData>>[]; + final Set<Type> debugAncestorTypes = <Type>{}; + final Set<Type> debugParentDataTypes = <Type>{}; + final List<Type> debugAncestorCulprits = <Type>[]; + + // More than one ParentDataWidget can contribute ParentData, but there are + // some constraints. + // 1. ParentData can only be written by unique ParentDataWidget types. + // For example, two KeepAlive ParentDataWidgets trying to write to the + // same child is not allowed. + // 2. Each contributing ParentDataWidget must contribute to a unique + // ParentData type, less ParentData be overwritten. + // For example, there cannot be two ParentDataWidgets that both write + // ParentData of type KeepAliveParentDataMixin, if the first check was + // subverted by a subclassing of the KeepAlive ParentDataWidget. + // 3. The ParentData itself must be compatible with all ParentDataWidgets + // writing to it. + // For example, TwoDimensionalViewportParentData uses the + // KeepAliveParentDataMixin, so it could be compatible with both + // KeepAlive, and another ParentDataWidget with ParentData type + // TwoDimensionalViewportParentData or a subclass thereof. + // The first and second cases are verified here. The third is verified in + // debugIsValidRenderObject. + + while (ancestor != null && ancestor is! RenderObjectElement) { + if (ancestor is ParentDataElement<ParentData>) { + assert((ParentDataElement<ParentData> ancestor) { + if (!debugAncestorTypes.add(ancestor.runtimeType) || !debugParentDataTypes.add(ancestor.debugParentDataType)) { + debugAncestorCulprits.add(ancestor.runtimeType); + } + return true; + }(ancestor)); + result.add(ancestor); + } + ancestor = ancestor._parent; + } + assert(() { + if (result.isEmpty || ancestor == null) { + return true; + } + // Validate points 1 and 2 from above. + _debugCheckCompetingAncestors( + result, + debugAncestorTypes, + debugParentDataTypes, + debugAncestorCulprits, + ); + return true; + }()); return result; } @@ -6477,8 +6567,8 @@ abstract class RenderObjectElement extends Element { return true; }()); _ancestorRenderObjectElement?.insertRenderObjectChild(renderObject, newSlot); - final ParentDataElement<ParentData>? parentDataElement = _findAncestorParentDataElement(); - if (parentDataElement != null) { + final List<ParentDataElement<ParentData>> parentDataElements = _findAncestorParentDataElements(); + for (final ParentDataElement<ParentData> parentDataElement in parentDataElements) { _updateParentData(parentDataElement.widget as ParentDataWidget<ParentData>); } } diff --git a/packages/flutter/test/widgets/parent_data_test.dart b/packages/flutter/test/widgets/parent_data_test.dart index 525d10816166b..d8934ba572a96 100644 --- a/packages/flutter/test/widgets/parent_data_test.dart +++ b/packages/flutter/test/widgets/parent_data_test.dart @@ -250,12 +250,99 @@ void main() { checkTree(tester, <TestParentData>[]); }); + testWidgetsWithLeakTracking('ParentData overwrite with custom ParentDataWidget subclasses', (WidgetTester tester) async { + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: <Widget>[ + CustomPositionedWidget( + bottom: 8.0, + child: Positioned( + top: 6.0, + left: 7.0, + child: DecoratedBox(decoration: kBoxDecorationB), + ), + ), + ], + ), + ), + ); + + dynamic exception = tester.takeException(); + expect(exception, isFlutterError); + expect( + exception.toString(), + startsWith( + 'Incorrect use of ParentDataWidget.\n' + 'Competing ParentDataWidgets are providing parent data to the same RenderObject:\n' + '- Positioned(left: 7.0, top: 6.0), which writes ParentData of type ' + 'StackParentData, (typically placed directly inside a Stack widget)\n' + '- CustomPositionedWidget, which writes ParentData of type ' + 'StackParentData, (typically placed directly inside a Stack widget)\n' + 'A RenderObject can receive parent data from multiple ' + 'ParentDataWidgets, but the Type of ParentData must be unique to ' + 'prevent one overwriting another.\n' + 'Usually, this indicates that one or more of the offending ParentDataWidgets listed ' + "above isn't placed inside a dedicated compatible ancestor widget that it isn't " + 'sharing with another ParentDataWidget of the same type.\n' + 'Otherwise, separating aspects of ParentData to prevent conflicts can ' + 'be done using mixins, mixing them all in on the full ParentData ' + 'Object, such as KeepAlive does with KeepAliveParentDataMixin.\n' + 'The ownership chain for the RenderObject that received the parent data was:\n' + ' DecoratedBox ← Positioned ← CustomPositionedWidget ← Stack ← Directionality ← ', // End of chain omitted, not relevant for test. + ), + ); + + await tester.pumpWidget( + const Directionality( + textDirection: TextDirection.ltr, + child: Stack( + children: <Widget>[ + SubclassPositioned( + bottom: 8.0, + child: Positioned( + top: 6.0, + left: 7.0, + child: DecoratedBox(decoration: kBoxDecorationB), + ), + ), + ], + ), + ), + ); + + exception = tester.takeException(); + expect(exception, isFlutterError); + expect( + exception.toString(), + startsWith( + 'Incorrect use of ParentDataWidget.\n' + 'Competing ParentDataWidgets are providing parent data to the same RenderObject:\n' + '- Positioned(left: 7.0, top: 6.0), which writes ParentData of type ' + 'StackParentData, (typically placed directly inside a Stack widget)\n' + '- SubclassPositioned(bottom: 8.0), which writes ParentData of type ' + 'StackParentData, (typically placed directly inside a Stack widget)\n' + 'A RenderObject can receive parent data from multiple ' + 'ParentDataWidgets, but the Type of ParentData must be unique to ' + 'prevent one overwriting another.\n' + 'Usually, this indicates that one or more of the offending ParentDataWidgets listed ' + "above isn't placed inside a dedicated compatible ancestor widget that it isn't " + 'sharing with another ParentDataWidget of the same type.\n' + 'Otherwise, separating aspects of ParentData to prevent conflicts can ' + 'be done using mixins, mixing them all in on the full ParentData ' + 'Object, such as KeepAlive does with KeepAliveParentDataMixin.\n' + 'The ownership chain for the RenderObject that received the parent data was:\n' + ' DecoratedBox ← Positioned ← SubclassPositioned ← Stack ← Directionality ← ', // End of chain omitted, not relevant for test. + ), + ); + }); + testWidgetsWithLeakTracking('ParentDataWidget conflicting data', (WidgetTester tester) async { await tester.pumpWidget( const Directionality( textDirection: TextDirection.ltr, child: Stack( - textDirection: TextDirection.ltr, children: <Widget>[ Positioned( top: 5.0, @@ -277,19 +364,26 @@ void main() { exception.toString(), startsWith( 'Incorrect use of ParentDataWidget.\n' - 'The following ParentDataWidgets are providing parent data to the same RenderObject:\n' - '- Positioned(left: 7.0, top: 6.0) (typically placed directly inside a Stack widget)\n' - '- Positioned(top: 5.0, bottom: 8.0) (typically placed directly inside a Stack widget)\n' - 'However, a RenderObject can only receive parent data from at most one ParentDataWidget.\n' - 'Usually, this indicates that at least one of the offending ParentDataWidgets listed ' - 'above is not placed directly inside a compatible ancestor widget.\n' + 'Competing ParentDataWidgets are providing parent data to the same RenderObject:\n' + '- Positioned(left: 7.0, top: 6.0), which writes ParentData of type ' + 'StackParentData, (typically placed directly inside a Stack widget)\n' + '- Positioned(top: 5.0, bottom: 8.0), which writes ParentData of type ' + 'StackParentData, (typically placed directly inside a Stack widget)\n' + 'A RenderObject can receive parent data from multiple ' + 'ParentDataWidgets, but the Type of ParentData must be unique to ' + 'prevent one overwriting another.\n' + 'Usually, this indicates that one or more of the offending ParentDataWidgets listed ' + "above isn't placed inside a dedicated compatible ancestor widget that it isn't " + 'sharing with another ParentDataWidget of the same type.\n' + 'Otherwise, separating aspects of ParentData to prevent conflicts can ' + 'be done using mixins, mixing them all in on the full ParentData ' + 'Object, such as KeepAlive does with KeepAliveParentDataMixin.\n' 'The ownership chain for the RenderObject that received the parent data was:\n' ' DecoratedBox ← Positioned ← Positioned ← Stack ← Directionality ← ', // End of chain omitted, not relevant for test. ), ); await tester.pumpWidget(const Stack(textDirection: TextDirection.ltr)); - checkTree(tester, <TestParentData>[]); await tester.pumpWidget( @@ -308,6 +402,7 @@ void main() { ), ), ); + exception = tester.takeException(); expect(exception, isFlutterError); expect( @@ -328,7 +423,6 @@ void main() { await tester.pumpWidget( const Stack(textDirection: TextDirection.ltr), ); - checkTree(tester, <TestParentData>[]); }); @@ -458,6 +552,46 @@ void main() { }); } +class SubclassPositioned extends Positioned { + const SubclassPositioned({ + super.key, + super.left, + super.top, + super.right, + super.bottom, + super.width, + super.height, + required super.child, + }); + + @override + void applyParentData(RenderObject renderObject) { + assert(renderObject.parentData is StackParentData); + final StackParentData parentData = renderObject.parentData! as StackParentData; + parentData.bottom = bottom; + } +} + +class CustomPositionedWidget extends ParentDataWidget<StackParentData> { + const CustomPositionedWidget({ + super.key, + required this.bottom, + required super.child, + }); + + final double bottom; + + @override + void applyParentData(RenderObject renderObject) { + assert(renderObject.parentData is StackParentData); + final StackParentData parentData = renderObject.parentData! as StackParentData; + parentData.bottom = bottom; + } + + @override + Type get debugTypicalAncestorWidgetClass => Stack; +} + class TestParentDataWidget extends ParentDataWidget<DummyParentData> { const TestParentDataWidget({ super.key, diff --git a/packages/flutter/test/widgets/two_dimensional_utils.dart b/packages/flutter/test/widgets/two_dimensional_utils.dart index 017897bcae56b..d2cbf3b8883a7 100644 --- a/packages/flutter/test/widgets/two_dimensional_utils.dart +++ b/packages/flutter/test/widgets/two_dimensional_utils.dart @@ -192,6 +192,18 @@ class RenderSimpleBuilderTableViewport extends RenderTwoDimensionalViewport { RenderBox? testGetChildFor(ChildVicinity vicinity) => getChildFor(vicinity); + @override + TestExtendedParentData parentDataOf(RenderBox child) { + return child.parentData! as TestExtendedParentData; + } + + @override + void setupParentData(RenderBox child) { + if (child.parentData is! TestExtendedParentData) { + child.parentData = TestExtendedParentData(); + } + } + @override void layoutChildSequence() { // Really simple table implementation for testing. @@ -468,3 +480,32 @@ class KeepAliveCheckBoxState extends State<KeepAliveCheckBox> with AutomaticKeep ); } } + +// TwoDimensionalViewportParentData already mixes in KeepAliveParentDataMixin, +// and so should be compatible with both the KeepAlive and +// TestParentDataWidget ParentDataWidgets. +// This ParentData is set up above as part of the +// RenderSimpleBuilderTableViewport for testing. +class TestExtendedParentData extends TwoDimensionalViewportParentData { + int? testValue; +} + +class TestParentDataWidget extends ParentDataWidget<TestExtendedParentData> { + const TestParentDataWidget({ + super.key, + required super.child, + this.testValue, + }); + + final int? testValue; + + @override + void applyParentData(RenderObject renderObject) { + assert(renderObject.parentData is TestExtendedParentData); + final TestExtendedParentData parentData = renderObject.parentData! as TestExtendedParentData; + parentData.testValue = testValue; + } + + @override + Type get debugTypicalAncestorWidgetClass => SimpleBuilderTableViewport; +} diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index 903dfe8c0038f..8063ea0d1a690 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -312,6 +312,120 @@ void main() { ); }); + testWidgets('Keep alive works with additional parent data widgets', (WidgetTester tester) async { + const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); + final ScrollController verticalController = ScrollController(); + final UniqueKey checkBoxKey = UniqueKey(); + final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBuilderDelegate( + maxXIndex: 5, + maxYIndex: 5, + addRepaintBoundaries: false, + builder: (BuildContext context, ChildVicinity vicinity) { + // The delegate will add a KeepAlive ParentDataWidget, this add an + // additional ParentDataWidget. + return TestParentDataWidget( + testValue: 20, + child: SizedBox.square( + dimension: 200, + child: Center(child: vicinity == firstCell + ? KeepAliveCheckBox(key: checkBoxKey) + : Text('R${vicinity.xIndex}:C${vicinity.yIndex}') + ), + ), + ); + } + ); + + await tester.pumpWidget(simpleBuilderTest( + delegate: builderDelegate, + verticalDetails: ScrollableDetails.vertical(controller: verticalController), + )); + await tester.pumpAndSettle(); + + expect(verticalController.hasClients, isTrue); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).checkValue, + isFalse, + ); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).wantKeepAlive, + isFalse, + ); + RenderSimpleBuilderTableViewport viewport = getViewport(tester, checkBoxKey) as RenderSimpleBuilderTableViewport; + TestExtendedParentData parentData = viewport.parentDataOf(viewport.testGetChildFor(firstCell)!); + // Check parent data from both ParentDataWidgets + expect(parentData.testValue, 20); + expect(parentData.keepAlive, isFalse); + + // Scroll away, disposing of the checkbox. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 600.0); + expect(find.byKey(checkBoxKey), findsNothing); + + // Bring back into view, still unchecked, not kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + // Check the box to set keep alive to true. + await tester.tap(find.byKey(checkBoxKey)); + await tester.pumpAndSettle(); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + viewport = getViewport(tester, checkBoxKey) as RenderSimpleBuilderTableViewport; + parentData = viewport.parentDataOf(viewport.testGetChildFor(firstCell)!); + // Check parent data from both ParentDataWidgets + expect(parentData.testValue, 20); + expect(parentData.keepAlive, isTrue); + + // Scroll away again, checkbox should be kept alive now. + verticalController.jumpTo(verticalController.position.maxScrollExtent); + await tester.pump(); + expect(verticalController.position.pixels, 600.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + viewport = getViewport(tester, checkBoxKey) as RenderSimpleBuilderTableViewport; + parentData = viewport.parentDataOf(viewport.testGetChildFor(firstCell)!); + // Check parent data from both ParentDataWidgets + expect(parentData.testValue, 20); + expect(parentData.keepAlive, isTrue); + + // Bring back into view, still checked, after being kept alive. + verticalController.jumpTo(0.0); + await tester.pump(); + expect(verticalController.position.pixels, 0.0); + expect(find.byKey(checkBoxKey), findsOneWidget); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).checkValue, + isTrue, + ); + expect( + tester.state<KeepAliveCheckBoxState>(find.byKey(checkBoxKey)).wantKeepAlive, + isTrue, + ); + viewport = getViewport(tester, checkBoxKey) as RenderSimpleBuilderTableViewport; + parentData = viewport.parentDataOf(viewport.testGetChildFor(firstCell)!); + // Check parent data from both ParentDataWidgets + expect(parentData.testValue, 20); + expect(parentData.keepAlive, isTrue); + }); + testWidgetsWithLeakTracking('builder delegate will not add automatic keep alives', (WidgetTester tester) async { const ChildVicinity firstCell = ChildVicinity(xIndex: 0, yIndex: 0); final ScrollController verticalController = ScrollController(); @@ -787,7 +901,7 @@ void main() { expect(horizontal.widget.controller, isNotNull); }, variant: TargetPlatformVariant.all()); - testWidgets('asserts the axis directions do not conflict with one another', (WidgetTester tester) async { + testWidgetsWithLeakTracking('asserts the axis directions do not conflict with one another', (WidgetTester tester) async { final List<Object> exceptions = <Object>[]; final FlutterExceptionHandler? oldHandler = FlutterError.onError; FlutterError.onError = (FlutterErrorDetails details) { From 851497ffc97b02e28bf94ce7eb46987334720ee6 Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Tue, 26 Sep 2023 16:05:11 -0700 Subject: [PATCH 1482/1547] [flutter_tools] fix tests with no native assets running native asset build (#135474) Fixes https://github.com/flutter/flutter/issues/135461 --- .../lib/src/ios/native_assets.dart | 4 +- .../lib/src/linux/native_assets.dart | 4 +- .../lib/src/macos/native_assets.dart | 4 +- .../flutter_tools/lib/src/native_assets.dart | 38 ++++++++----------- .../targets/native_assets_test.dart | 2 + .../linux/native_assets_test.dart | 24 ++++++++++++ .../general.shard/resident_runner_test.dart | 2 +- 7 files changed, 49 insertions(+), 29 deletions(-) diff --git a/packages/flutter_tools/lib/src/ios/native_assets.dart b/packages/flutter_tools/lib/src/ios/native_assets.dart index 3e2d595fba494..21ddb2c5e5177 100644 --- a/packages/flutter_tools/lib/src/ios/native_assets.dart +++ b/packages/flutter_tools/lib/src/ios/native_assets.dart @@ -23,7 +23,7 @@ Future<Uri?> dryRunNativeAssetsIOS({ required Uri projectUri, required FileSystem fileSystem, }) async { - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (!await nativeBuildRequired(buildRunner)) { return null; } @@ -72,7 +72,7 @@ Future<List<Uri>> buildNativeAssetsIOS({ required Uri yamlParentDirectory, required FileSystem fileSystem, }) async { - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (!await nativeBuildRequired(buildRunner)) { await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory, fileSystem); return <Uri>[]; } diff --git a/packages/flutter_tools/lib/src/linux/native_assets.dart b/packages/flutter_tools/lib/src/linux/native_assets.dart index a9dcb334d870f..6c52a33707c3f 100644 --- a/packages/flutter_tools/lib/src/linux/native_assets.dart +++ b/packages/flutter_tools/lib/src/linux/native_assets.dart @@ -23,7 +23,7 @@ Future<Uri?> dryRunNativeAssetsLinux({ bool flutterTester = false, required FileSystem fileSystem, }) async { - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (!await nativeBuildRequired(buildRunner)) { return null; } @@ -90,7 +90,7 @@ Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsLinux({ // CMake requires the folder to exist to do copying. await buildDir.create(recursive: true); } - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (!await nativeBuildRequired(buildRunner)) { final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); return (nativeAssetsYaml, <Uri>[]); } diff --git a/packages/flutter_tools/lib/src/macos/native_assets.dart b/packages/flutter_tools/lib/src/macos/native_assets.dart index c62c28fc111f2..1bdf27d76ffab 100644 --- a/packages/flutter_tools/lib/src/macos/native_assets.dart +++ b/packages/flutter_tools/lib/src/macos/native_assets.dart @@ -23,7 +23,7 @@ Future<Uri?> dryRunNativeAssetsMacOS({ bool flutterTester = false, required FileSystem fileSystem, }) async { - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (!await nativeBuildRequired(buildRunner)) { return null; } @@ -77,7 +77,7 @@ Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsMacOS({ }) async { const OS targetOs = OS.macOS; final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (!await nativeBuildRequired(buildRunner)) { final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); return (nativeAssetsYaml, <Uri>[]); } diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index b269fd876ed6a..caeffa356333e 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -214,7 +214,7 @@ BuildMode nativeAssetsBuildMode(build_info.BuildMode buildMode) { /// /// Native asset builds cannot be run without a package config. If there is /// no package config, leave a logging trace about that. -Future<bool> hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async { +Future<bool> _hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async { final bool packageConfigExists = await buildRunner.hasPackageConfig(); if (!packageConfigExists) { globals.logger.printTrace('No package config found. Skipping native assets compilation.'); @@ -222,24 +222,23 @@ Future<bool> hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async { return !packageConfigExists; } -/// Checks that if native assets is disabled, none of the dependencies declare -/// native assets. -/// -/// If any of the dependencies have native assets, but native assets are -/// disabled, exits the tool. -Future<bool> isDisabledAndNoNativeAssets(NativeAssetsBuildRunner buildRunner) async { - if (featureFlags.isNativeAssetsEnabled) { +Future<bool> nativeBuildRequired(NativeAssetsBuildRunner buildRunner) async { + if (await _hasNoPackageConfig(buildRunner)) { return false; } final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets(); if (packagesWithNativeAssets.isEmpty) { - return true; + return false; } - final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' '); - throwToolExit( - 'Package(s) $packageNames require the native assets feature to be enabled. ' - 'Enable using `flutter config --enable-native-assets`.', - ); + + if (!featureFlags.isNativeAssetsEnabled) { + final String packageNames = packagesWithNativeAssets.map((Package p) => p.name).join(' '); + throwToolExit( + 'Package(s) $packageNames require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ); + } + return true; } /// Ensures that either this project has no native assets, or that native assets @@ -252,7 +251,7 @@ Future<void> ensureNoNativeAssetsOrOsIsSupported( FileSystem fileSystem, NativeAssetsBuildRunner buildRunner, ) async { - if (await hasNoPackageConfig(buildRunner)) { + if (await _hasNoPackageConfig(buildRunner)) { return; } final List<Package> packagesWithNativeAssets = await buildRunner.packagesWithNativeAssets(); @@ -345,12 +344,7 @@ Future<Uri?> dryRunNativeAssets({ buildRunner: buildRunner, ); } else { - await ensureNoNativeAssetsOrOsIsSupported( - projectUri, - const LocalPlatform().operatingSystem, - fileSystem, - buildRunner, - ); + await nativeBuildRequired(buildRunner); nativeAssetsYaml = null; } case build_info.TargetPlatform.linux_arm64: @@ -389,7 +383,7 @@ Future<Uri?> dryRunNativeAssetsMultipeOSes({ required FileSystem fileSystem, required Iterable<build_info.TargetPlatform> targetPlatforms, }) async { - if (await hasNoPackageConfig(buildRunner) || await isDisabledAndNoNativeAssets(buildRunner)) { + if (await nativeBuildRequired(buildRunner)) { return null; } diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart index 09fe96148d81f..36d4628ad9eeb 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/native_assets_test.dart @@ -14,6 +14,7 @@ import 'package:flutter_tools/src/build_system/targets/native_assets.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; +import 'package:package_config/package_config.dart' show Package; import '../../../src/common.dart'; import '../../../src/context.dart'; @@ -104,6 +105,7 @@ void main() { await createPackageConfig(iosEnvironment); final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[Package('foo', iosEnvironment.buildDir.uri)], buildResult: FakeNativeAssetsBuilderResult(assets: <native_assets_cli.Asset>[ native_assets_cli.Asset( id: 'package:foo/foo.dart', diff --git a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart index 34d2fc552f820..89797079fd276 100644 --- a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart @@ -6,6 +6,7 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -86,6 +87,24 @@ void main() { ); }); + testUsingContext('does not throw if clang not present but no native assets present', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.create(recursive: true); + await buildNativeAssetsLinux( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: _BuildRunnerWithoutClang(), + ); + expect( + (globals.logger as BufferLogger).traceText, + isNot(contains('Building native assets for ')), + ); + }); + testUsingContext('dry run for multiple OSes with no package config', overrides: <Type, Generator>{ ProcessManager: () => FakeProcessManager.empty(), }, () async { @@ -372,3 +391,8 @@ void main() { expect(result.cc, Uri.file('/some/path/to/clang')); }); } + +class _BuildRunnerWithoutClang extends FakeNativeAssetsBuildRunner { + @override + Future<CCompilerConfig> get cCompilerConfig async => throwToolExit('Failed to find clang++ on the PATH.'); +} diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index e24262fff8246..2af0b715306db 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -2420,7 +2420,7 @@ flutter: expect(buildRunner.buildInvocations, 0); expect(buildRunner.dryRunInvocations, 1); expect(buildRunner.hasPackageConfigInvocations, 1); - expect(buildRunner.packagesWithNativeAssetsInvocations, 0); + expect(buildRunner.packagesWithNativeAssetsInvocations, 1); }), overrides: <Type, Generator>{ ProcessManager: () => FakeProcessManager.any(), From eae421e4333f08edfe16bf1f770fe5e6d22eac8d Mon Sep 17 00:00:00 2001 From: "Mateus Felipe C. C. Pinto" <mateusfccp@gmail.com> Date: Tue, 26 Sep 2023 21:17:21 -0300 Subject: [PATCH 1483/1547] [documentation] remove repeated "For example," in RenderSliverEdgeInsetsPadding documentation (#135297) There was a repeated "For example," in the documentation of `RenderSliverEdgeInsetsPadding`. This PR fix this. --- packages/flutter/lib/src/rendering/sliver_padding.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter/lib/src/rendering/sliver_padding.dart b/packages/flutter/lib/src/rendering/sliver_padding.dart index c02ee71e81b3f..62540d9655716 100644 --- a/packages/flutter/lib/src/rendering/sliver_padding.dart +++ b/packages/flutter/lib/src/rendering/sliver_padding.dart @@ -18,7 +18,7 @@ import 'sliver.dart'; /// /// {@template flutter.rendering.RenderSliverEdgeInsetsPadding} /// Applying padding in the main extent of the viewport to slivers that have scroll effects is likely to have -/// undesired effects. For example, For example, wrapping a [SliverPersistentHeader] with +/// undesired effects. For example, wrapping a [SliverPersistentHeader] with /// `pinned:true` will cause only the appbar to stay pinned while the padding will scroll away. /// {@endtemplate} abstract class RenderSliverEdgeInsetsPadding extends RenderSliver with RenderObjectWithChildMixin<RenderSliver> { From a1639be4a01255fe11ab4b0a5d521f73f5ed43ba Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Tue, 26 Sep 2023 17:19:42 -0700 Subject: [PATCH 1484/1547] Revert "Switch flutter_tools to run frontend server from AOT snapshot" (#135537) Reverts flutter/flutter#135255 This broke Google Testing, and requires an internal patch before relanding. --- packages/flutter_tools/lib/src/artifacts.dart | 2 +- .../lib/src/build_system/targets/common.dart | 1 - packages/flutter_tools/lib/src/compile.dart | 70 +++++++------------ .../test/general.shard/artifacts_test.dart | 7 +- .../build_system/targets/common_test.dart | 14 ++-- .../general.shard/compile_batch_test.dart | 18 ++--- .../compile_incremental_test.dart | 2 +- .../test/web_test_compiler_test.dart | 2 +- 8 files changed, 46 insertions(+), 70 deletions(-) diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 161e8b6ae7daa..8775db6fec1f1 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -190,7 +190,7 @@ String? _artifactToFileName(Artifact artifact, Platform hostPlatform, [ BuildMod case Artifact.wasmOptBinary: return 'wasm-opt$exe'; case Artifact.frontendServerSnapshotForEngineDartSdk: - return 'frontend_server_aot.dart.snapshot'; + return 'frontend_server.dart.snapshot'; case Artifact.linuxDesktopPath: return ''; case Artifact.linuxHeaders: diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index c3507abb349aa..d5febecf4251a 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -132,7 +132,6 @@ class KernelSnapshot extends Target { Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/common.dart'), Source.artifact(Artifact.platformKernelDill), Source.artifact(Artifact.engineDartBinary), - Source.artifact(Artifact.engineDartAotRuntime), Source.artifact(Artifact.frontendServerSnapshotForEngineDartSdk), ]; diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart index 15d209367f156..e7571a69eac32 100644 --- a/packages/flutter_tools/lib/src/compile.dart +++ b/packages/flutter_tools/lib/src/compile.dart @@ -244,10 +244,20 @@ class KernelCompiler { String? nativeAssets, }) async { final TargetPlatform? platform = targetModel == TargetModel.dartdevc ? TargetPlatform.web_javascript : null; + final String frontendServer = (frontendServerStarterPath == null || frontendServerStarterPath.isEmpty) + ? _artifacts.getArtifactPath( + Artifact.frontendServerSnapshotForEngineDartSdk, + platform: platform, + ) + : frontendServerStarterPath; // This is a URI, not a file path, so the forward slash is correct even on Windows. if (!sdkRoot.endsWith('/')) { sdkRoot = '$sdkRoot/'; } + final String engineDartPath = _artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform); + if (!_processManager.canRun(engineDartPath)) { + throwToolExit('Unable to find Dart binary at $engineDartPath'); + } String? mainUri; final File mainFile = _fileSystem.file(mainPath); final Uri mainFileUri = mainFile.uri; @@ -272,33 +282,10 @@ class KernelCompiler { toMultiRootPath(dartPluginRegistrantFileUri, _fileSystemScheme, _fileSystemRoots, _fileSystem.path.separator == r'\'); } - final List<String> commandToStartFrontendServer; - if (frontendServerStarterPath != null && frontendServerStarterPath.isNotEmpty) { - final String engineDartPath = _artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform); - if (!_processManager.canRun(engineDartPath)) { - throwToolExit('Unable to find Dart binary at $engineDartPath'); - } - commandToStartFrontendServer = <String>[ - engineDartPath, - '--disable-dart-dev', - frontendServerStarterPath, - ]; - } else { - final String engineDartAotRuntimePath = _artifacts.getArtifactPath(Artifact.engineDartAotRuntime, platform: platform); - if (!_processManager.canRun(engineDartAotRuntimePath)) { - throwToolExit('Unable to find dartaotruntime binary at $engineDartAotRuntimePath'); - } - commandToStartFrontendServer = <String>[ - engineDartAotRuntimePath, - '--disable-dart-dev', - _artifacts.getArtifactPath( - Artifact.frontendServerSnapshotForEngineDartSdk, - platform: platform, - ), - ]; - } - - final List<String> command = commandToStartFrontendServer + <String>[ + final List<String> command = <String>[ + engineDartPath, + '--disable-dart-dev', + frontendServer, '--sdk-root', sdkRoot, '--target=$targetModel', @@ -790,25 +777,16 @@ class DefaultResidentCompiler implements ResidentCompiler { String? nativeAssetsUri, }) async { final TargetPlatform? platform = (targetModel == TargetModel.dartdevc) ? TargetPlatform.web_javascript : null; - late final List<String> commandToStartFrontendServer; - if (frontendServerStarterPath != null && frontendServerStarterPath!.isNotEmpty) { - commandToStartFrontendServer = <String>[ - artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), - '--disable-dart-dev', - frontendServerStarterPath!, - ]; - } else { - commandToStartFrontendServer = <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime, platform: platform), - '--disable-dart-dev', - artifacts.getArtifactPath( - Artifact.frontendServerSnapshotForEngineDartSdk, - platform: platform, - ), - ]; - } - - final List<String> command = commandToStartFrontendServer + <String>[ + final String frontendServer = (frontendServerStarterPath == null || frontendServerStarterPath!.isEmpty) + ? artifacts.getArtifactPath( + Artifact.frontendServerSnapshotForEngineDartSdk, + platform: platform, + ) + : frontendServerStarterPath!; + final List<String> command = <String>[ + artifacts.getArtifactPath(Artifact.engineDartBinary, platform: platform), + '--disable-dart-dev', + frontendServer, '--sdk-root', sdkRoot, '--incremental', diff --git a/packages/flutter_tools/test/general.shard/artifacts_test.dart b/packages/flutter_tools/test/general.shard/artifacts_test.dart index dc39ffe002c8c..920980a23ba2f 100644 --- a/packages/flutter_tools/test/general.shard/artifacts_test.dart +++ b/packages/flutter_tools/test/general.shard/artifacts_test.dart @@ -143,8 +143,7 @@ void main() { ); expect( artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), - fileSystem.path.join('root', 'bin', 'cache', 'dart-sdk', 'bin', - 'snapshots', 'frontend_server_aot.dart.snapshot') + fileSystem.path.join('root', 'bin', 'cache', 'dart-sdk', 'bin', 'snapshots', 'frontend_server.dart.snapshot') ); }); @@ -326,7 +325,7 @@ void main() { expect( artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), fileSystem.path.join('/out', 'host_debug_unopt', 'dart-sdk', 'bin', - 'snapshots', 'frontend_server_aot.dart.snapshot') + 'snapshots', 'frontend_server.dart.snapshot') ); @@ -398,7 +397,7 @@ void main() { Artifact.frontendServerSnapshotForEngineDartSdk, platform: TargetPlatform.web_javascript), fileSystem.path.join('/flutter', 'prebuilts', 'linux-x64', 'dart-sdk', 'bin', - 'snapshots', 'frontend_server_aot.dart.snapshot'), + 'snapshots', 'frontend_server.dart.snapshot'), ); expect( artifacts.getArtifactPath( diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart index 0b05203de2520..a287f1b0d0923 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/common_test.dart @@ -94,7 +94,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -139,7 +139,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -185,7 +185,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -279,7 +279,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -328,7 +328,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -375,7 +375,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', @@ -434,7 +434,7 @@ native-assets: {} ); processManager.addCommands(<FakeCommand>[ FakeCommand(command: <String>[ - artifacts.getArtifactPath(Artifact.engineDartAotRuntime), + artifacts.getArtifactPath(Artifact.engineDartBinary), '--disable-dart-dev', artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk), '--sdk-root', diff --git a/packages/flutter_tools/test/general.shard/compile_batch_test.dart b/packages/flutter_tools/test/general.shard/compile_batch_test.dart index 9d2ad2a8868fc..e82fb93fe600e 100644 --- a/packages/flutter_tools/test/general.shard/compile_batch_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_batch_test.dart @@ -53,7 +53,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -99,7 +99,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -145,7 +145,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -191,7 +191,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -239,7 +239,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -287,7 +287,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -339,7 +339,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -389,7 +389,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', @@ -449,7 +449,7 @@ void main() { logger: logger, processManager: FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: const <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', diff --git a/packages/flutter_tools/test/general.shard/compile_incremental_test.dart b/packages/flutter_tools/test/general.shard/compile_incremental_test.dart index 14749ae1d458e..adaa4c2a6b973 100644 --- a/packages/flutter_tools/test/general.shard/compile_incremental_test.dart +++ b/packages/flutter_tools/test/general.shard/compile_incremental_test.dart @@ -30,7 +30,7 @@ void main() { late FakeProcessManager fakeProcessManager; const List<String> frontendServerCommand = <String>[ - 'Artifact.engineDartAotRuntime', + 'Artifact.engineDartBinary', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk', '--sdk-root', diff --git a/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart b/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart index 26ed691651c53..54f8be20c9310 100644 --- a/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart +++ b/packages/flutter_tools/test/general.shard/test/web_test_compiler_test.dart @@ -36,7 +36,7 @@ void main() { ); final FakeProcessManager processManager = FakeProcessManager.list(<FakeCommand>[ FakeCommand(command: <Pattern>[ - 'Artifact.engineDartAotRuntime.TargetPlatform.web_javascript', + 'Artifact.engineDartBinary.TargetPlatform.web_javascript', '--disable-dart-dev', 'Artifact.frontendServerSnapshotForEngineDartSdk.TargetPlatform.web_javascript', '--sdk-root', From bea63d7c81760b6bff5fabfb954834a037180d60 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Tue, 26 Sep 2023 20:46:25 -0400 Subject: [PATCH 1485/1547] Roll Flutter Engine from acdb364a42d5 to 0a8ad236e4af (5 revisions) (#135527) https://github.com/flutter/engine/compare/acdb364a42d5...0a8ad236e4af 2023-09-26 1961493+harryterkelsen@users.noreply.github.com [canvaskit] Use DirectionalLight_Shadow flag for drawing shadows (flutter/engine#46292) 2023-09-26 30870216+gaaclarke@users.noreply.github.com [Impeller] fixes behavior for blurred rounded rect clear (flutter/engine#46167) 2023-09-26 skia-flutter-autoroll@skia.org Roll Skia from dd6a4e3655fc to bc4f22353590 (6 revisions) (flutter/engine#46299) 2023-09-26 30870216+gaaclarke@users.noreply.github.com Clean up the docstring for ColorFilter.matrix (flutter/engine#46298) 2023-09-26 49699333+dependabot[bot]@users.noreply.github.com Bump uuid from 4.0.0 to 4.1.0 in /lib/web_ui (flutter/engine#46293) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 077b1fe766138..e82ba3fb3e14d 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -acdb364a42d51a3db93b5ee3da4ddb1de258cc54 +0a8ad236e4afba9659831227bd4a5f8ed18d83aa From 3ad9998cf07098d58429aeac242e47a0156ae29c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 27 Sep 2023 02:59:59 -0400 Subject: [PATCH 1486/1547] Roll Flutter Engine from 0a8ad236e4af to f70f65f7a622 (5 revisions) (#135549) https://github.com/flutter/engine/compare/0a8ad236e4af...f70f65f7a622 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from d1215b38667c to 76aecbaea259 (1 revision) (flutter/engine#46309) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from bc4f22353590 to d1215b38667c (4 revisions) (flutter/engine#46306) 2023-09-26 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from a56c8yPp4DDlj_Qbl... to Lg6FR6iDnZeV6y-E8... (flutter/engine#46302) 2023-09-26 ychris@google.com [ios] Fix app extension not able to find assets from unloaded bundle (flutter/engine#46283) 2023-09-26 leroux_bruno@yahoo.fr [Android] Fix enableSuggestions set to false not honored (flutter/engine#46037) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from a56c8yPp4DDl to Lg6FR6iDnZeV If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index e82ba3fb3e14d..66b1cea933a9a 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -0a8ad236e4afba9659831227bd4a5f8ed18d83aa +f70f65f7a6229793b2c6e2e32d23cbe9b90108d8 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 2e0684338d2af..06243cfed48d8 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -a56c8yPp4DDlj_QblIlLum8BoJiVSDsDsJtweyEsZ7sC +Lg6FR6iDnZeV6y-E8iVqEsPfDyNRkT_ZnJSGtO2OH2UC From 3e7c388e9136a0e811562e1f2cb488942482b6a6 Mon Sep 17 00:00:00 2001 From: Alex Li <github@alexv525.com> Date: Wed, 27 Sep 2023 15:02:13 +0800 Subject: [PATCH 1487/1547] =?UTF-8?q?=E2=9C=A8=20`flutter=20config=20--lis?= =?UTF-8?q?t`=20(#135401)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #81831. The PR improves the `config` command in below ways: - Does not print the settings in usages or other options. - Adds the `--list` flag to print the full settings list. - Separates usages for settings and analytics. - Prints the restart tip when clearing features. --- .../lib/src/commands/config.dart | 91 ++++++++++++------- .../commands.shard/hermetic/config_test.dart | 36 ++++++-- .../command_output_test.dart | 3 +- 3 files changed, 89 insertions(+), 41 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/config.dart b/packages/flutter_tools/lib/src/commands/config.dart index 9d0d3d6abfabb..0b22f065c9654 100644 --- a/packages/flutter_tools/lib/src/commands/config.dart +++ b/packages/flutter_tools/lib/src/commands/config.dart @@ -15,6 +15,11 @@ import '../runner/flutter_command_runner.dart'; class ConfigCommand extends FlutterCommand { ConfigCommand({ bool verboseHelp = false }) { + argParser.addFlag( + 'list', + help: 'List all settings and their current values.', + negatable: false, + ); argParser.addFlag('analytics', hide: !verboseHelp, help: 'Enable or disable reporting anonymously tool usage statistics and crash reports.\n' @@ -73,37 +78,7 @@ class ConfigCommand extends FlutterCommand { bool get shouldUpdateCache => false; @override - String get usageFooter { - // List all config settings. for feature flags, include whether they - // are available. - final Map<String, Feature> featuresByName = <String, Feature>{}; - final String channel = globals.flutterVersion.channel; - for (final Feature feature in allFeatures) { - final String? configSetting = feature.configSetting; - if (configSetting != null) { - featuresByName[configSetting] = feature; - } - } - String values = globals.config.keys - .map<String>((String key) { - String configFooter = ''; - if (featuresByName.containsKey(key)) { - final FeatureChannelSetting setting = featuresByName[key]!.getSettingForChannel(channel); - if (!setting.available) { - configFooter = '(Unavailable)'; - } - } - return ' $key: ${globals.config.getValue(key)} $configFooter'; - }).join('\n'); - if (values.isEmpty) { - values = ' No settings have been configured.'; - } - final bool analyticsEnabled = globals.flutterUsage.enabled && - !globals.flutterUsage.suppressAnalytics; - return - '\nSettings:\n$values\n\n' - 'Analytics reporting is currently ${analyticsEnabled ? 'enabled' : 'disabled'}.'; - } + String get usageFooter => '\n$analyticsUsage'; /// Return null to disable analytics recording of the `config` command. @override @@ -121,6 +96,11 @@ class ConfigCommand extends FlutterCommand { ' flutter config --android-studio-dir "/opt/Android Studio"'); } + if (boolArg('list')) { + globals.printStatus(settingsText); + return FlutterCommandResult.success(); + } + if (boolArg('machine')) { await handleMachine(); return FlutterCommandResult.success(); @@ -133,6 +113,7 @@ class ConfigCommand extends FlutterCommand { globals.config.removeValue(configSetting); } } + globals.printStatus(requireReloadTipText); return FlutterCommandResult.success(); } @@ -195,7 +176,7 @@ class ConfigCommand extends FlutterCommand { if (argResults == null || argResults!.arguments.isEmpty) { globals.printStatus(usage); } else { - globals.printStatus('\nYou may need to restart any open editors for them to read new settings.'); + globals.printStatus('\n$requireReloadTipText'); } return FlutterCommandResult.success(); @@ -234,4 +215,50 @@ class ConfigCommand extends FlutterCommand { globals.printStatus('Setting "$keyName" value to "$keyValue".'); } } + + /// List all config settings. for feature flags, include whether they are available. + String get settingsText { + final Map<String, Feature> featuresByName = <String, Feature>{}; + final String channel = globals.flutterVersion.channel; + for (final Feature feature in allFeatures) { + final String? configSetting = feature.configSetting; + if (configSetting != null) { + featuresByName[configSetting] = feature; + } + } + final Set<String> keys = <String>{ + ...allFeatures.map((Feature e) => e.configSetting).whereType<String>(), + ...globals.config.keys, + }; + final Iterable<String> settings = keys.map<String>((String key) { + Object? value = globals.config.getValue(key); + value ??= '(Not set)'; + final StringBuffer buffer = StringBuffer(' $key: $value'); + if (featuresByName.containsKey(key)) { + final FeatureChannelSetting setting = featuresByName[key]!.getSettingForChannel(channel); + if (!setting.available) { + buffer.write(' (Unavailable)'); + } + } + return buffer.toString(); + }); + final StringBuffer buffer = StringBuffer(); + buffer.writeln('All Settings:'); + if (settings.isEmpty) { + buffer.writeln(' No configs have been configured.'); + } else { + buffer.writeln(settings.join('\n')); + } + return buffer.toString(); + } + + /// List the status of the analytics reporting. + String get analyticsUsage { + final bool analyticsEnabled = + globals.flutterUsage.enabled && !globals.flutterUsage.suppressAnalytics; + return 'Analytics reporting is currently ${analyticsEnabled ? 'enabled' : 'disabled'}.'; + } + + /// Raising the reload tip for setting changes. + final String requireReloadTipText = 'You may need to restart any open editors for them to read new settings.'; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart index d3e86de9695e1..4f98a5b37020e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/config_test.dart @@ -12,6 +12,7 @@ import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/config.dart'; +import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/version.dart'; @@ -48,6 +49,23 @@ void main() { } group('config', () { + testUsingContext('prints all settings with --list', () async { + final ConfigCommand configCommand = ConfigCommand(); + final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand); + await commandRunner.run(<String>['config', '--list']); + expect( + testLogger.statusText, + 'All Settings:\n' + '${allFeatures + .where((Feature e) => e.configSetting != null) + .map((Feature e) => ' ${e.configSetting}: (Not set)') + .join('\n')}' + '\n\n', + ); + }, overrides: <Type, Generator>{ + Usage: () => testUsage, + }); + testUsingContext('throws error on excess arguments', () { final ConfigCommand configCommand = ConfigCommand(); final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand); @@ -196,6 +214,7 @@ void main() { await commandRunner.run(<String>[ 'config', + '--list' ]); expect( @@ -270,20 +289,21 @@ void main() { Usage: () => testUsage, }); - testUsingContext('analytics reported disabled when suppressed', () async { + testUsingContext('analytics reported with help usages', () async { final ConfigCommand configCommand = ConfigCommand(); - final CommandRunner<void> commandRunner = createTestCommandRunner(configCommand); + createTestCommandRunner(configCommand); testUsage.suppressAnalytics = true; - - await commandRunner.run(<String>[ - 'config', - ]); - expect( - testLogger.statusText, + configCommand.usage, containsIgnoringWhitespace('Analytics reporting is currently disabled'), ); + + testUsage.suppressAnalytics = false; + expect( + configCommand.usage, + containsIgnoringWhitespace('Analytics reporting is currently enabled'), + ); }, overrides: <Type, Generator>{ Usage: () => testUsage, }); diff --git a/packages/flutter_tools/test/integration.shard/command_output_test.dart b/packages/flutter_tools/test/integration.shard/command_output_test.dart index 7b72ef67643b6..60c34113dec4f 100644 --- a/packages/flutter_tools/test/integration.shard/command_output_test.dart +++ b/packages/flutter_tools/test/integration.shard/command_output_test.dart @@ -71,11 +71,12 @@ void main() { expect(result.stdout, contains('Shutdown hooks complete')); }); - testWithoutContext('flutter config contains all features', () async { + testWithoutContext('flutter config --list contains all features', () async { final String flutterBin = fileSystem.path.join(getFlutterRoot(), 'bin', 'flutter'); final ProcessResult result = await processManager.run(<String>[ flutterBin, 'config', + '--list' ]); // contains all of the experiments in features.dart From ff4a0f676f4194b19c3c298e1842e6b263e0a64c Mon Sep 17 00:00:00 2001 From: Daco Harkes <dacoharkes@google.com> Date: Wed, 27 Sep 2023 14:22:58 +0200 Subject: [PATCH 1488/1547] Native assets support for Windows (#134203) Support for FFI calls with `@Native external` functions through Native assets on Windows. This enables bundling native code without any build-system boilerplate code. For more info see: * https://github.com/flutter/flutter/issues/129757 ### Implementation details for Windows. Mainly follows the design of https://github.com/flutter/flutter/pull/134031. Specifically for Windows in this PR is the logic for finding the compiler `cl.exe` and environment variables that contain the paths to the Windows headers `vcvars.bat` based on `vswhere.exe`. --- .../build_system/targets/native_assets.dart | 25 +- .../lib/src/ios/native_assets.dart | 18 +- .../lib/src/linux/native_assets.dart | 188 +------- .../lib/src/macos/native_assets.dart | 28 +- .../cmake_native_assets_migration.dart | 4 +- .../flutter_tools/lib/src/native_assets.dart | 274 ++++++++++- .../lib/src/test/test_compiler.dart | 9 + .../lib/src/windows/build_windows.dart | 2 + .../lib/src/windows/native_assets.dart | 91 ++++ .../lib/src/windows/visual_studio.dart | 92 +++- .../windows.tmpl/CMakeLists.txt.tmpl | 6 + .../templates/package_ffi/pubspec.yaml.tmpl | 2 +- .../fake_native_assets_build_runner.dart | 2 +- .../general.shard/ios/native_assets_test.dart | 16 +- .../linux/native_assets_test.dart | 24 +- .../macos/native_assets_test.dart | 17 +- .../cmake_project_migration_test.dart | 48 +- .../windows/native_assets_test.dart | 439 ++++++++++++++++++ .../windows/visual_studio_test.dart | 223 +++++---- .../integration.shard/native_assets_test.dart | 43 +- 20 files changed, 1208 insertions(+), 343 deletions(-) create mode 100644 packages/flutter_tools/lib/src/windows/native_assets.dart create mode 100644 packages/flutter_tools/test/general.shard/windows/native_assets_test.dart diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index c92c1d6949581..7a5ee21788003 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -16,6 +16,7 @@ import '../../linux/native_assets.dart'; import '../../macos/native_assets.dart'; import '../../macos/xcode.dart'; import '../../native_assets.dart'; +import '../../windows/native_assets.dart'; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; @@ -134,6 +135,20 @@ class NativeAssets extends Target { fileSystem: fileSystem, buildRunner: buildRunner, ); + case TargetPlatform.windows_x64: + final String? environmentBuildMode = environment.defines[kBuildMode]; + if (environmentBuildMode == null) { + throw MissingDefineException(kBuildMode, name); + } + final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); + (_, dependencies) = await buildNativeAssetsWindows( + targetPlatform: targetPlatform, + buildMode: buildMode, + projectUri: projectUri, + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); case TargetPlatform.tester: if (const LocalPlatform().isMacOS) { (_, dependencies) = await buildNativeAssetsMacOS( @@ -154,6 +169,15 @@ class NativeAssets extends Target { buildRunner: buildRunner, flutterTester: true, ); + } else if (const LocalPlatform().isWindows) { + (_, dependencies) = await buildNativeAssetsWindows( + buildMode: BuildMode.debug, + projectUri: projectUri, + yamlParentDirectory: environment.buildDir.uri, + fileSystem: fileSystem, + buildRunner: buildRunner, + flutterTester: true, + ); } else { // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 // Write the file we claim to have in the [outputs]. @@ -168,7 +192,6 @@ class NativeAssets extends Target { case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.web_javascript: - case TargetPlatform.windows_x64: // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 // Write the file we claim to have in the [outputs]. await writeNativeAssetsYaml(<Asset>[], environment.buildDir.uri, fileSystem); diff --git a/packages/flutter_tools/lib/src/ios/native_assets.dart b/packages/flutter_tools/lib/src/ios/native_assets.dart index 21ddb2c5e5177..8a18b9eb14765 100644 --- a/packages/flutter_tools/lib/src/ios/native_assets.dart +++ b/packages/flutter_tools/lib/src/ios/native_assets.dart @@ -27,7 +27,7 @@ Future<Uri?> dryRunNativeAssetsIOS({ return null; } - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.iOS); + final Uri buildUri = nativeAssetsBuildUri(projectUri, OS.iOS); final Iterable<Asset> assetTargetLocations = await dryRunNativeAssetsIOSInternal( fileSystem, projectUri, @@ -35,7 +35,7 @@ Future<Uri?> dryRunNativeAssetsIOS({ ); final Uri nativeAssetsUri = await writeNativeAssetsYaml( assetTargetLocations, - buildUri_, + buildUri, fileSystem, ); return nativeAssetsUri; @@ -46,17 +46,17 @@ Future<Iterable<Asset>> dryRunNativeAssetsIOSInternal( Uri projectUri, NativeAssetsBuildRunner buildRunner, ) async { - const OS targetOs = OS.iOS; - globals.logger.printTrace('Dry running native assets for $targetOs.'); + const OS targetOS = OS.iOS; + globals.logger.printTrace('Dry running native assets for $targetOS.'); final List<Asset> nativeAssets = (await buildRunner.dryRun( linkModePreference: LinkModePreference.dynamic, - targetOs: targetOs, + targetOS: targetOS, workingDirectory: projectUri, includeParentEnvironment: true, )) .assets; ensureNoLinkModeStatic(nativeAssets); - globals.logger.printTrace('Dry running native assets for $targetOs done.'); + globals.logger.printTrace('Dry running native assets for $targetOS done.'); final Iterable<Asset> assetTargetLocations = _assetTargetLocations(nativeAssets).values; return assetTargetLocations; } @@ -80,8 +80,8 @@ Future<List<Uri>> buildNativeAssetsIOS({ final List<Target> targets = darwinArchs.map(_getNativeTarget).toList(); final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); - const OS targetOs = OS.iOS; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + const OS targetOS = OS.iOS; + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); final IOSSdk iosSdk = _getIOSSdk(environmentType); globals.logger.printTrace('Building native assets for $targets $buildModeCli.'); @@ -104,7 +104,7 @@ Future<List<Uri>> buildNativeAssetsIOS({ globals.logger.printTrace('Building native assets for $targets done.'); final Map<AssetPath, List<Asset>> fatAssetTargetLocations = _fatAssetTargetLocations(nativeAssets); await copyNativeAssetsMacOSHost( - buildUri_, + buildUri, fatAssetTargetLocations, codesignIdentity, buildMode, diff --git a/packages/flutter_tools/lib/src/linux/native_assets.dart b/packages/flutter_tools/lib/src/linux/native_assets.dart index 6c52a33707c3f..692c4126ac830 100644 --- a/packages/flutter_tools/lib/src/linux/native_assets.dart +++ b/packages/flutter_tools/lib/src/linux/native_assets.dart @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:native_assets_builder/native_assets_builder.dart' show BuildResult; import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; -import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; import '../base/common.dart'; import '../base/file_system.dart'; @@ -22,24 +20,14 @@ Future<Uri?> dryRunNativeAssetsLinux({ required Uri projectUri, bool flutterTester = false, required FileSystem fileSystem, -}) async { - if (!await nativeBuildRequired(buildRunner)) { - return null; - } - - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.linux); - final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsLinuxInternal( - fileSystem, - projectUri, - flutterTester, - buildRunner, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - nativeAssetPaths, - buildUri_, - fileSystem, +}) { + return dryRunNativeAssetsSingleArchitecture( + buildRunner: buildRunner, + projectUri: projectUri, + flutterTester: flutterTester, + fileSystem: fileSystem, + os: OS.linux, ); - return nativeAssetsUri; } Future<Iterable<Asset>> dryRunNativeAssetsLinuxInternal( @@ -47,33 +35,16 @@ Future<Iterable<Asset>> dryRunNativeAssetsLinuxInternal( Uri projectUri, bool flutterTester, NativeAssetsBuildRunner buildRunner, -) async { - const OS targetOs = OS.linux; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); - - globals.logger.printTrace('Dry running native assets for $targetOs.'); - final List<Asset> nativeAssets = (await buildRunner.dryRun( - linkModePreference: LinkModePreference.dynamic, - targetOs: targetOs, - workingDirectory: projectUri, - includeParentEnvironment: true, - )) - .assets; - ensureNoLinkModeStatic(nativeAssets); - globals.logger.printTrace('Dry running native assets for $targetOs done.'); - final Uri? absolutePath = flutterTester ? buildUri_ : null; - final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); - final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values; - return nativeAssetPaths; +) { + return dryRunNativeAssetsSingleArchitectureInternal( + fileSystem, + projectUri, + flutterTester, + buildRunner, + OS.linux, + ); } -/// Builds native assets. -/// -/// If [targetPlatform] is omitted, the current target architecture is used. -/// -/// If [flutterTester] is true, absolute paths are emitted in the native -/// assets mapping. This can be used for JIT mode without sandbox on the host. -/// This is used in `flutter test` and `flutter run -d flutter-tester`. Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsLinux({ required NativeAssetsBuildRunner buildRunner, TargetPlatform? targetPlatform, @@ -82,127 +53,16 @@ Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsLinux({ bool flutterTester = false, Uri? yamlParentDirectory, required FileSystem fileSystem, -}) async { - const OS targetOs = OS.linux; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); - final Directory buildDir = fileSystem.directory(buildUri_); - if (!await buildDir.exists()) { - // CMake requires the folder to exist to do copying. - await buildDir.create(recursive: true); - } - if (!await nativeBuildRequired(buildRunner)) { - final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); - return (nativeAssetsYaml, <Uri>[]); - } - - final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current; - final native_assets_cli.BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); - - globals.logger.printTrace('Building native assets for $target $buildModeCli.'); - final BuildResult result = await buildRunner.build( - linkModePreference: LinkModePreference.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - ); - final List<Asset> nativeAssets = result.assets; - final Set<Uri> dependencies = result.dependencies.toSet(); - ensureNoLinkModeStatic(nativeAssets); - globals.logger.printTrace('Building native assets for $target done.'); - final Uri? absolutePath = flutterTester ? buildUri_ : null; - final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); - await _copyNativeAssetsLinux( - buildUri_, - assetTargetLocations, - buildMode, - fileSystem, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - assetTargetLocations.values, - yamlParentDirectory ?? buildUri_, - fileSystem, +}) { + return buildNativeAssetsSingleArchitecture( + buildRunner: buildRunner, + targetPlatform: targetPlatform, + projectUri: projectUri, + buildMode: buildMode, + flutterTester: flutterTester, + yamlParentDirectory: yamlParentDirectory, + fileSystem: fileSystem, ); - return (nativeAssetsUri, dependencies.toList()); -} - -Map<Asset, Asset> _assetTargetLocations( - List<Asset> nativeAssets, - Uri? absolutePath, -) => - <Asset, Asset>{ - for (final Asset asset in nativeAssets) asset: _targetLocationLinux(asset, absolutePath), - }; - -Asset _targetLocationLinux(Asset asset, Uri? absolutePath) { - final AssetPath path = asset.path; - switch (path) { - case AssetSystemPath _: - case AssetInExecutable _: - case AssetInProcess _: - return asset; - case AssetAbsolutePath _: - final String fileName = path.uri.pathSegments.last; - Uri uri; - if (absolutePath != null) { - // Flutter tester needs full host paths. - uri = absolutePath.resolve(fileName); - } else { - // Flutter Desktop needs "absolute" paths inside the app. - // "relative" in the context of native assets would be relative to the - // kernel or aot snapshot. - uri = Uri(path: fileName); - } - return asset.copyWith(path: AssetAbsolutePath(uri)); - } - throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); -} - -/// Extract the [Target] from a [TargetPlatform]. -Target _getNativeTarget(TargetPlatform targetPlatform) { - switch (targetPlatform) { - case TargetPlatform.linux_x64: - return Target.linuxX64; - case TargetPlatform.linux_arm64: - return Target.linuxArm64; - case TargetPlatform.android: - case TargetPlatform.ios: - case TargetPlatform.darwin: - case TargetPlatform.windows_x64: - case TargetPlatform.fuchsia_arm64: - case TargetPlatform.fuchsia_x64: - case TargetPlatform.tester: - case TargetPlatform.web_javascript: - case TargetPlatform.android_arm: - case TargetPlatform.android_arm64: - case TargetPlatform.android_x64: - case TargetPlatform.android_x86: - throw Exception('Unknown targetPlatform: $targetPlatform.'); - } -} - -Future<void> _copyNativeAssetsLinux( - Uri buildUri, - Map<Asset, Asset> assetTargetLocations, - BuildMode buildMode, - FileSystem fileSystem, -) async { - if (assetTargetLocations.isNotEmpty) { - globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); - final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); - if (!buildDir.existsSync()) { - buildDir.createSync(recursive: true); - } - for (final MapEntry<Asset, Asset> assetMapping in assetTargetLocations.entries) { - final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri; - final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri; - final Uri targetUri = buildUri.resolveUri(target); - final String targetFullPath = targetUri.toFilePath(); - await fileSystem.file(source).copy(targetFullPath); - } - globals.logger.printTrace('Copying native assets done.'); - } } /// Flutter expects `clang++` to be on the path on Linux hosts. diff --git a/packages/flutter_tools/lib/src/macos/native_assets.dart b/packages/flutter_tools/lib/src/macos/native_assets.dart index 1bdf27d76ffab..5e79097f2ca03 100644 --- a/packages/flutter_tools/lib/src/macos/native_assets.dart +++ b/packages/flutter_tools/lib/src/macos/native_assets.dart @@ -27,9 +27,9 @@ Future<Uri?> dryRunNativeAssetsMacOS({ return null; } - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OS.macOS); + final Uri buildUri = nativeAssetsBuildUri(projectUri, OS.macOS); final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, flutterTester, buildRunner); - final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); + final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri, fileSystem); return nativeAssetsUri; } @@ -39,20 +39,20 @@ Future<Iterable<Asset>> dryRunNativeAssetsMacOSInternal( bool flutterTester, NativeAssetsBuildRunner buildRunner, ) async { - const OS targetOs = OS.macOS; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + const OS targetOS = OS.macOS; + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); - globals.logger.printTrace('Dry running native assets for $targetOs.'); + globals.logger.printTrace('Dry running native assets for $targetOS.'); final List<Asset> nativeAssets = (await buildRunner.dryRun( linkModePreference: LinkModePreference.dynamic, - targetOs: targetOs, + targetOS: targetOS, workingDirectory: projectUri, includeParentEnvironment: true, )) .assets; ensureNoLinkModeStatic(nativeAssets); - globals.logger.printTrace('Dry running native assets for $targetOs done.'); - final Uri? absolutePath = flutterTester ? buildUri_ : null; + globals.logger.printTrace('Dry running native assets for $targetOS done.'); + final Uri? absolutePath = flutterTester ? buildUri : null; final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values; return nativeAssetPaths; @@ -75,10 +75,10 @@ Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsMacOS({ Uri? yamlParentDirectory, required FileSystem fileSystem, }) async { - const OS targetOs = OS.macOS; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOs); + const OS targetOS = OS.macOS; + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); if (!await nativeBuildRequired(buildRunner)) { - final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri_, fileSystem); + final Uri nativeAssetsYaml = await writeNativeAssetsYaml(<Asset>[], yamlParentDirectory ?? buildUri, fileSystem); return (nativeAssetsYaml, <Uri>[]); } @@ -102,11 +102,11 @@ Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsMacOS({ } ensureNoLinkModeStatic(nativeAssets); globals.logger.printTrace('Building native assets for $targets done.'); - final Uri? absolutePath = flutterTester ? buildUri_ : null; + final Uri? absolutePath = flutterTester ? buildUri : null; final Map<Asset, Asset> assetTargetLocations = _assetTargetLocations(nativeAssets, absolutePath); final Map<AssetPath, List<Asset>> fatAssetTargetLocations = _fatAssetTargetLocations(nativeAssets, absolutePath); - await copyNativeAssetsMacOSHost(buildUri_, fatAssetTargetLocations, codesignIdentity, buildMode, fileSystem); - final Uri nativeAssetsUri = await writeNativeAssetsYaml(assetTargetLocations.values, yamlParentDirectory ?? buildUri_, fileSystem); + await copyNativeAssetsMacOSHost(buildUri, fatAssetTargetLocations, codesignIdentity, buildMode, fileSystem); + final Uri nativeAssetsUri = await writeNativeAssetsYaml(assetTargetLocations.values, yamlParentDirectory ?? buildUri, fileSystem); return (nativeAssetsUri, dependencies.toList()); } diff --git a/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart index fe9ba86a035ac..c7f21351afbbd 100644 --- a/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart +++ b/packages/flutter_tools/lib/src/migrations/cmake_native_assets_migration.dart @@ -41,8 +41,8 @@ class CmakeNativeAssetsMigration extends ProjectMigrator { # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "\${PROJECT_BUILD_DIR}native_assets/$os/") install(DIRECTORY "\${NATIVE_ASSETS_DIR}" - DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) + DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) '''; // Insert the new command after the bundled libraries loop. diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index caeffa356333e..38afb4e6e60d8 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -23,6 +23,7 @@ import 'linux/native_assets.dart'; import 'macos/native_assets.dart'; import 'macos/native_assets_host.dart'; import 'resident_runner.dart'; +import 'windows/native_assets.dart'; /// Programmatic API to be used by Dart launchers to invoke native builds. /// @@ -42,7 +43,7 @@ abstract class NativeAssetsBuildRunner { Future<DryRunResult> dryRun({ required bool includeParentEnvironment, required LinkModePreference linkModePreference, - required OS targetOs, + required OS targetOS, required Uri workingDirectory, }); @@ -100,10 +101,8 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { @override Future<bool> hasPackageConfig() { - final File packageConfigJson = fileSystem - .directory(projectUri.toFilePath()) - .childDirectory('.dart_tool') - .childFile('package_config.json'); + final File packageConfigJson = + fileSystem.directory(projectUri.toFilePath()).childDirectory('.dart_tool').childFile('package_config.json'); return packageConfigJson.exists(); } @@ -120,7 +119,7 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { Future<DryRunResult> dryRun({ required bool includeParentEnvironment, required LinkModePreference linkModePreference, - required OS targetOs, + required OS targetOS, required Uri workingDirectory, }) { final PackageLayout packageLayout = PackageLayout.fromPackageConfig( @@ -130,7 +129,7 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { return _buildRunner.dryRun( includeParentEnvironment: includeParentEnvironment, linkModePreference: linkModePreference, - targetOs: targetOs, + targetOs: targetOS, workingDirectory: workingDirectory, packageLayout: packageLayout, ); @@ -172,8 +171,11 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { if (globals.platform.isLinux) { return cCompilerConfigLinux(); } + if (globals.platform.isWindows) { + return cCompilerConfigWindows(); + } throwToolExit( - 'Native assets feature not yet implemented for Linux, Windows and Android.', + 'Native assets feature not yet implemented for Android.', ); }(); } @@ -343,6 +345,13 @@ Future<Uri?> dryRunNativeAssets({ fileSystem: fileSystem, buildRunner: buildRunner, ); + } else if (const LocalPlatform().isWindows) { + nativeAssetsYaml = await dryRunNativeAssetsWindows( + projectUri: projectUri, + flutterTester: true, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); } else { await nativeBuildRequired(buildRunner); nativeAssetsYaml = null; @@ -354,6 +363,12 @@ Future<Uri?> dryRunNativeAssets({ fileSystem: fileSystem, buildRunner: buildRunner, ); + case build_info.TargetPlatform.windows_x64: + nativeAssetsYaml = await dryRunNativeAssetsWindows( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: buildRunner, + ); case build_info.TargetPlatform.android_arm: case build_info.TargetPlatform.android_arm64: case build_info.TargetPlatform.android_x64: @@ -362,7 +377,6 @@ Future<Uri?> dryRunNativeAssets({ case build_info.TargetPlatform.fuchsia_arm64: case build_info.TargetPlatform.fuchsia_x64: case build_info.TargetPlatform.web_javascript: - case build_info.TargetPlatform.windows_x64: await ensureNoNativeAssetsOrOsIsSupported( projectUri, targetPlatform.toString(), @@ -387,19 +401,41 @@ Future<Uri?> dryRunNativeAssetsMultipeOSes({ return null; } - final Uri buildUri_ = buildUriMultiple(projectUri); + final Uri buildUri = buildUriMultiple(projectUri); final Iterable<Asset> nativeAssetPaths = <Asset>[ if (targetPlatforms.contains(build_info.TargetPlatform.darwin) || (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.macOS)) - ...await dryRunNativeAssetsMacOSInternal(fileSystem, projectUri, false, buildRunner), + ...await dryRunNativeAssetsMacOSInternal( + fileSystem, + projectUri, + false, + buildRunner, + ), if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) || targetPlatforms.contains(build_info.TargetPlatform.linux_x64) || (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.linux)) - ...await dryRunNativeAssetsLinuxInternal(fileSystem, projectUri, false, buildRunner), + ...await dryRunNativeAssetsLinuxInternal( + fileSystem, + projectUri, + false, + buildRunner, + ), + if (targetPlatforms.contains(build_info.TargetPlatform.windows_x64) || + (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.windows)) + ...await dryRunNativeAssetsWindowsInternal( + fileSystem, + projectUri, + false, + buildRunner, + ), if (targetPlatforms.contains(build_info.TargetPlatform.ios)) - ...await dryRunNativeAssetsIOSInternal(fileSystem, projectUri, buildRunner) + ...await dryRunNativeAssetsIOSInternal( + fileSystem, + projectUri, + buildRunner, + ) ]; - final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri_, fileSystem); + final Uri nativeAssetsUri = await writeNativeAssetsYaml(nativeAssetPaths, buildUri, fileSystem); return nativeAssetsUri; } @@ -409,3 +445,213 @@ Uri buildUriMultiple(Uri projectUri) { final String buildDir = build_info.getBuildDirectory(); return projectUri.resolve('$buildDir/native_assets/multiple/'); } + +/// Dry run the native builds. +/// +/// This does not build native assets, it only simulates what the final paths +/// of all assets will be so that this can be embedded in the kernel file. +Future<Uri?> dryRunNativeAssetsSingleArchitecture({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + bool flutterTester = false, + required FileSystem fileSystem, + required OS os, +}) async { + if (!await nativeBuildRequired(buildRunner)) { + return null; + } + + final Uri buildUri = nativeAssetsBuildUri(projectUri, os); + final Iterable<Asset> nativeAssetPaths = await dryRunNativeAssetsSingleArchitectureInternal( + fileSystem, + projectUri, + flutterTester, + buildRunner, + os, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + nativeAssetPaths, + buildUri, + fileSystem, + ); + return nativeAssetsUri; +} + +Future<Iterable<Asset>> dryRunNativeAssetsSingleArchitectureInternal( + FileSystem fileSystem, + Uri projectUri, + bool flutterTester, + NativeAssetsBuildRunner buildRunner, + OS targetOS, +) async { + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); + + globals.logger.printTrace('Dry running native assets for $targetOS.'); + final List<Asset> nativeAssets = (await buildRunner.dryRun( + linkModePreference: LinkModePreference.dynamic, + targetOS: targetOS, + workingDirectory: projectUri, + includeParentEnvironment: true, + )) + .assets; + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Dry running native assets for $targetOS done.'); + final Uri? absolutePath = flutterTester ? buildUri : null; + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocationsSingleArchitecture( + nativeAssets, + absolutePath, + ); + final Iterable<Asset> nativeAssetPaths = assetTargetLocations.values; + return nativeAssetPaths; +} + +/// Builds native assets. +/// +/// If [targetPlatform] is omitted, the current target architecture is used. +/// +/// If [flutterTester] is true, absolute paths are emitted in the native +/// assets mapping. This can be used for JIT mode without sandbox on the host. +/// This is used in `flutter test` and `flutter run -d flutter-tester`. +Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> buildNativeAssetsSingleArchitecture({ + required NativeAssetsBuildRunner buildRunner, + build_info.TargetPlatform? targetPlatform, + required Uri projectUri, + required build_info.BuildMode buildMode, + bool flutterTester = false, + Uri? yamlParentDirectory, + required FileSystem fileSystem, +}) async { + final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current; + final OS targetOS = target.os; + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); + final Directory buildDir = fileSystem.directory(buildUri); + if (!await buildDir.exists()) { + // CMake requires the folder to exist to do copying. + await buildDir.create(recursive: true); + } + if (!await nativeBuildRequired(buildRunner)) { + final Uri nativeAssetsYaml = await writeNativeAssetsYaml( + <Asset>[], + yamlParentDirectory ?? buildUri, + fileSystem, + ); + return (nativeAssetsYaml, <Uri>[]); + } + + final BuildMode buildModeCli = nativeAssetsBuildMode(buildMode); + + globals.logger.printTrace('Building native assets for $target $buildModeCli.'); + final BuildResult result = await buildRunner.build( + linkModePreference: LinkModePreference.dynamic, + target: target, + buildMode: buildModeCli, + workingDirectory: projectUri, + includeParentEnvironment: true, + cCompilerConfig: await buildRunner.cCompilerConfig, + ); + final List<Asset> nativeAssets = result.assets; + final Set<Uri> dependencies = result.dependencies.toSet(); + ensureNoLinkModeStatic(nativeAssets); + globals.logger.printTrace('Building native assets for $target done.'); + final Uri? absolutePath = flutterTester ? buildUri : null; + final Map<Asset, Asset> assetTargetLocations = _assetTargetLocationsSingleArchitecture(nativeAssets, absolutePath); + await _copyNativeAssetsSingleArchitecture( + buildUri, + assetTargetLocations, + buildMode, + fileSystem, + ); + final Uri nativeAssetsUri = await writeNativeAssetsYaml( + assetTargetLocations.values, + yamlParentDirectory ?? buildUri, + fileSystem, + ); + return (nativeAssetsUri, dependencies.toList()); +} + +Map<Asset, Asset> _assetTargetLocationsSingleArchitecture( + List<Asset> nativeAssets, + Uri? absolutePath, +) { + return <Asset, Asset>{ + for (final Asset asset in nativeAssets) + asset: _targetLocationSingleArchitecture( + asset, + absolutePath, + ), + }; +} + +Asset _targetLocationSingleArchitecture(Asset asset, Uri? absolutePath) { + final AssetPath path = asset.path; + switch (path) { + case AssetSystemPath _: + case AssetInExecutable _: + case AssetInProcess _: + return asset; + case AssetAbsolutePath _: + final String fileName = path.uri.pathSegments.last; + Uri uri; + if (absolutePath != null) { + // Flutter tester needs full host paths. + uri = absolutePath.resolve(fileName); + } else { + // Flutter Desktop needs "absolute" paths inside the app. + // "relative" in the context of native assets would be relative to the + // kernel or aot snapshot. + uri = Uri(path: fileName); + } + return asset.copyWith(path: AssetAbsolutePath(uri)); + } + throw Exception('Unsupported asset path type ${path.runtimeType} in asset $asset'); +} + +/// Extract the [Target] from a [TargetPlatform]. +/// +/// Does not cover MacOS, iOS, and Android as these pass the architecture +/// in other enums. +Target _getNativeTarget(build_info.TargetPlatform targetPlatform) { + switch (targetPlatform) { + case build_info.TargetPlatform.linux_x64: + return Target.linuxX64; + case build_info.TargetPlatform.linux_arm64: + return Target.linuxArm64; + case build_info.TargetPlatform.windows_x64: + return Target.windowsX64; + case build_info.TargetPlatform.android: + case build_info.TargetPlatform.ios: + case build_info.TargetPlatform.darwin: + case build_info.TargetPlatform.fuchsia_arm64: + case build_info.TargetPlatform.fuchsia_x64: + case build_info.TargetPlatform.tester: + case build_info.TargetPlatform.web_javascript: + case build_info.TargetPlatform.android_arm: + case build_info.TargetPlatform.android_arm64: + case build_info.TargetPlatform.android_x64: + case build_info.TargetPlatform.android_x86: + throw Exception('Unknown targetPlatform: $targetPlatform.'); + } +} + +Future<void> _copyNativeAssetsSingleArchitecture( + Uri buildUri, + Map<Asset, Asset> assetTargetLocations, + build_info.BuildMode buildMode, + FileSystem fileSystem, +) async { + if (assetTargetLocations.isNotEmpty) { + globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); + final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); + if (!buildDir.existsSync()) { + buildDir.createSync(recursive: true); + } + for (final MapEntry<Asset, Asset> assetMapping in assetTargetLocations.entries) { + final Uri source = (assetMapping.key.path as AssetAbsolutePath).uri; + final Uri target = (assetMapping.value.path as AssetAbsolutePath).uri; + final Uri targetUri = buildUri.resolveUri(target); + final String targetFullPath = targetUri.toFilePath(); + await fileSystem.file(source).copy(targetFullPath); + } + globals.logger.printTrace('Copying native assets done.'); + } +} diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 600478faa3e23..1433a7150c260 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -20,6 +20,7 @@ import '../linux/native_assets.dart'; import '../macos/native_assets.dart'; import '../native_assets.dart'; import '../project.dart'; +import '../windows/native_assets.dart'; import 'test_time_recorder.dart'; /// A request to the [TestCompiler] for recompilation. @@ -195,6 +196,14 @@ class TestCompiler { fileSystem: globals.fs, buildRunner: buildRunner, ); + } else if (globals.platform.isWindows) { + (nativeAssetsYaml, _) = await buildNativeAssetsWindows( + buildMode: buildInfo.mode, + projectUri: projectUri, + flutterTester: true, + fileSystem: globals.fs, + buildRunner: buildRunner, + ); } else { await ensureNoNativeAssetsOrOsIsSupported( projectUri, diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index 5d88dddef5fed..dddc0d424d2bf 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -18,6 +18,7 @@ import '../convert.dart'; import '../flutter_plugins.dart'; import '../globals.dart' as globals; import '../migrations/cmake_custom_command_migration.dart'; +import '../migrations/cmake_native_assets_migration.dart'; import 'migrations/build_architecture_migration.dart'; import 'migrations/show_window_migration.dart'; import 'migrations/version_migration.dart'; @@ -61,6 +62,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { final List<ProjectMigrator> migrators = <ProjectMigrator>[ CmakeCustomCommandMigration(windowsProject, globals.logger), + CmakeNativeAssetsMigration(windowsProject, 'windows', globals.logger), VersionMigration(windowsProject, globals.logger), ShowWindowMigration(windowsProject, globals.logger), BuildArchitectureMigration(windowsProject, buildDirectory, globals.logger), diff --git a/packages/flutter_tools/lib/src/windows/native_assets.dart b/packages/flutter_tools/lib/src/windows/native_assets.dart new file mode 100644 index 0000000000000..c5f5835d0084f --- /dev/null +++ b/packages/flutter_tools/lib/src/windows/native_assets.dart @@ -0,0 +1,91 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode; + +import '../base/file_system.dart'; +import '../build_info.dart'; +import '../globals.dart' as globals; +import '../native_assets.dart'; +import 'visual_studio.dart'; + +/// Dry run the native builds. +/// +/// This does not build native assets, it only simulates what the final paths +/// of all assets will be so that this can be embedded in the kernel file. +Future<Uri?> dryRunNativeAssetsWindows({ + required NativeAssetsBuildRunner buildRunner, + required Uri projectUri, + bool flutterTester = false, + required FileSystem fileSystem, +}) { + return dryRunNativeAssetsSingleArchitecture( + buildRunner: buildRunner, + projectUri: projectUri, + flutterTester: flutterTester, + fileSystem: fileSystem, + os: OS.windows, + ); +} + +Future<Iterable<Asset>> dryRunNativeAssetsWindowsInternal( + FileSystem fileSystem, + Uri projectUri, + bool flutterTester, + NativeAssetsBuildRunner buildRunner, +) { + return dryRunNativeAssetsSingleArchitectureInternal( + fileSystem, + projectUri, + flutterTester, + buildRunner, + OS.windows, + ); +} + +Future<(Uri? nativeAssetsYaml, List<Uri> dependencies)> + buildNativeAssetsWindows({ + required NativeAssetsBuildRunner buildRunner, + TargetPlatform? targetPlatform, + required Uri projectUri, + required BuildMode buildMode, + bool flutterTester = false, + Uri? yamlParentDirectory, + required FileSystem fileSystem, +}) { + return buildNativeAssetsSingleArchitecture( + buildRunner: buildRunner, + targetPlatform: targetPlatform, + projectUri: projectUri, + buildMode: buildMode, + flutterTester: flutterTester, + yamlParentDirectory: yamlParentDirectory, + fileSystem: fileSystem, + ); +} + + +Future<CCompilerConfig> cCompilerConfigWindows() async { + final VisualStudio visualStudio = VisualStudio( + fileSystem: globals.fs, + platform: globals.platform, + logger: globals.logger, + processManager: globals.processManager, + ); + + return CCompilerConfig( + cc: _toOptionalFileUri(visualStudio.clPath), + ld: _toOptionalFileUri(visualStudio.linkPath), + ar: _toOptionalFileUri(visualStudio.libPath), + envScript: _toOptionalFileUri(visualStudio.vcvarsPath), + envScriptArgs: <String>[], + ); +} + +Uri? _toOptionalFileUri(String? string) { + if (string == null) { + return null; + } + return Uri.file(string); +} diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart index e9c39aa2fa4db..5251450a81b4e 100644 --- a/packages/flutter_tools/lib/src/windows/visual_studio.dart +++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart @@ -184,6 +184,60 @@ class VisualStudio { } } + /// The path to cl.exe, or null if no Visual Studio installation has + /// the components necessary to build. + String? get clPath { + return _getMsvcBinPath('cl.exe'); + } + + /// The path to lib.exe, or null if no Visual Studio installation has + /// the components necessary to build. + String? get libPath { + return _getMsvcBinPath('lib.exe'); + } + + /// The path to link.exe, or null if no Visual Studio installation has + /// the components necessary to build. + String? get linkPath { + return _getMsvcBinPath('link.exe'); + } + + String? _getMsvcBinPath(String executable) { + final VswhereDetails? details = _bestVisualStudioDetails; + if (details == null || !details.isUsable || details.installationPath == null || details.msvcVersion == null) { + return null; + } + + return _fileSystem.path.joinAll(<String>[ + details.installationPath!, + 'VC', + 'Tools', + 'MSVC', + details.msvcVersion!, + 'bin', + 'Hostx64', + 'x64', + executable, + ]); + } + + /// The path to vcvars64.exe, or null if no Visual Studio installation has + /// the components necessary to build. + String? get vcvarsPath { + final VswhereDetails? details = _bestVisualStudioDetails; + if (details == null || !details.isUsable || details.installationPath == null) { + return null; + } + + return _fileSystem.path.joinAll(<String>[ + details.installationPath!, + 'VC', + 'Auxiliary', + 'Build', + 'vcvars64.bat', + ]); + } + /// The major version of the Visual Studio install, as an integer. int? get _majorVersion => fullVersion != null ? int.tryParse(fullVersion!.split('.')[0]) : null; @@ -301,7 +355,12 @@ class VisualStudio { if (whereResult.exitCode == 0) { final List<Map<String, dynamic>>? installations = _tryDecodeVswhereJson(whereResult.stdout); if (installations != null && installations.isNotEmpty) { - return VswhereDetails.fromJson(validateRequirements, installations[0]); + final String? msvcVersion = _findMsvcVersion(installations); + return VswhereDetails.fromJson( + validateRequirements, + installations[0], + msvcVersion, + ); } } } on ArgumentError { @@ -312,6 +371,28 @@ class VisualStudio { return null; } + String? _findMsvcVersion(List<Map<String, dynamic>> installations) { + final String? installationPath = installations[0]['installationPath'] as String?; + String? msvcVersion; + if (installationPath != null) { + final Directory installationDir = _fileSystem.directory(installationPath); + final Directory msvcDir = installationDir + .childDirectory('VC') + .childDirectory('Tools') + .childDirectory('MSVC'); + if (msvcDir.existsSync()) { + final Iterable<Directory> msvcVersionDirs = msvcDir.listSync().whereType<Directory>(); + if (msvcVersionDirs.isEmpty) { + return null; + } + msvcVersion = msvcVersionDirs.last.uri.pathSegments + .where((String e) => e.isNotEmpty) + .last; + } + } + return msvcVersion; + } + List<Map<String, dynamic>>? _tryDecodeVswhereJson(String vswhereJson) { List<dynamic>? result; FormatException? originalError; @@ -443,12 +524,14 @@ class VswhereDetails { required this.isRebootRequired, required this.isPrerelease, required this.catalogDisplayVersion, + required this.msvcVersion, }); /// Create a `VswhereDetails` from the JSON output of vswhere.exe. factory VswhereDetails.fromJson( bool meetsRequirements, - Map<String, dynamic> details + Map<String, dynamic> details, + String? msvcVersion, ) { final Map<String, dynamic>? catalog = details['catalog'] as Map<String, dynamic>?; @@ -467,6 +550,8 @@ class VswhereDetails { // contain replacement characters. displayName: details['displayName'] as String?, catalogDisplayVersion: catalog == null ? null : catalog['productDisplayVersion'] as String?, + + msvcVersion: msvcVersion, ); } @@ -511,6 +596,9 @@ class VswhereDetails { /// The user-friendly version. final String? catalogDisplayVersion; + /// The MSVC versions. + final String? msvcVersion; + /// Checks if the Visual Studio installation can be used by Flutter. /// /// Returns false if the installation has issues the user must resolve. diff --git a/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl b/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl index 78f98b83d572f..0c89cfcd82feb 100644 --- a/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl +++ b/packages/flutter_tools/templates/app_shared/windows.tmpl/CMakeLists.txt.tmpl @@ -91,6 +91,12 @@ if(PLUGIN_BUNDLED_LIBRARIES) COMPONENT Runtime) endif() +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl b/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl index 8fa5f3ac67ad0..9237f30b97191 100644 --- a/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl +++ b/packages/flutter_tools/templates/package_ffi/pubspec.yaml.tmpl @@ -10,7 +10,7 @@ dependencies: cli_config: ^0.1.1 logging: ^1.1.1 native_assets_cli: ^0.2.0 - native_toolchain_c: ^0.2.0 + native_toolchain_c: ^0.2.3 dev_dependencies: ffi: ^2.0.2 diff --git a/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart b/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart index bcdd74c2d8b52..bd4f99042effd 100644 --- a/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart +++ b/packages/flutter_tools/test/general.shard/fake_native_assets_build_runner.dart @@ -49,7 +49,7 @@ class FakeNativeAssetsBuildRunner implements NativeAssetsBuildRunner { Future<native_assets_builder.DryRunResult> dryRun({ required bool includeParentEnvironment, required LinkModePreference linkModePreference, - required OS targetOs, + required OS targetOS, required Uri workingDirectory, }) async { dryRunInvocations++; diff --git a/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart b/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart index 0a6b7805785b6..baac43c2aa35a 100644 --- a/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/native_assets_test.dart @@ -142,6 +142,13 @@ void main() { ), ), ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Dry running native assets for ios.', + 'Dry running native assets for ios done.', + ]), + ); expect( nativeAssetsYaml, projectUri.resolve('build/native_assets/ios/native_assets.yaml'), @@ -259,13 +266,20 @@ void main() { Asset( id: 'package:bar/bar.dart', linkMode: LinkMode.dynamic, - target: native_assets_cli.Target.macOSArm64, + target: native_assets_cli.Target.iOSArm64, path: AssetAbsolutePath(Uri.file('bar.dylib')), ), ], ), ), ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Building native assets for [ios_arm64] debug.', + 'Building native assets for [ios_arm64] done.', + ]), + ); expect( environment.buildDir.childFile('native_assets.yaml'), exists, diff --git a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart index 89797079fd276..19b5ae7016fd0 100644 --- a/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/linux/native_assets_test.dart @@ -180,6 +180,13 @@ void main() { ), ), ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Dry running native assets for linux.', + 'Dry running native assets for linux done.', + ]), + ); expect( nativeAssetsYaml, projectUri.resolve('build/native_assets/linux/native_assets.yaml'), @@ -222,6 +229,7 @@ void main() { await packageConfig.parent.create(); await packageConfig.create(); final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( + targetPlatform: TargetPlatform.linux_x64, projectUri: projectUri, buildMode: BuildMode.debug, fileSystem: fileSystem, @@ -257,16 +265,14 @@ void main() { FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), ProcessManager: () => FakeProcessManager.empty(), }, () async { - if (const LocalPlatform().isWindows) { - return; // Backslashes in commands, but we will never run these commands on Windows. - } - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final File packageConfig = environment.projectDir.childDirectory('.dart_tool').childFile('package_config.json'); await packageConfig.parent.create(); await packageConfig.create(); final File dylibAfterCompiling = fileSystem.file('libbar.so'); // The mock doesn't create the file, so create it here. await dylibAfterCompiling.create(); final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( + targetPlatform: TargetPlatform.linux_x64, projectUri: projectUri, buildMode: BuildMode.debug, fileSystem: fileSystem, @@ -287,6 +293,13 @@ void main() { ), ), ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Building native assets for linux_x64 debug.', + 'Building native assets for linux_x64 done.', + ]), + ); expect( nativeAssetsYaml, projectUri.resolve('build/native_assets/linux/native_assets.yaml'), @@ -297,7 +310,7 @@ void main() { 'package:bar/bar.dart', if (flutterTester) // Tests run on host system, so the have the full path on the system. - '- ${projectUri.resolve('/build/native_assets/linux/libbar.so').toFilePath()}' + '- ${projectUri.resolve('build/native_assets/linux/libbar.so').toFilePath()}' else // Apps are a bundle with the dylibs on their dlopen path. '- libbar.so', @@ -365,7 +378,6 @@ void main() { FileSystem: () => fileSystem, }, () async { if (!const LocalPlatform().isLinux) { - // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 return; } diff --git a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart index 07cdd2bbd3742..877521bc1077b 100644 --- a/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/native_assets_test.dart @@ -161,6 +161,13 @@ void main() { ), ), ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Dry running native assets for macos.', + 'Dry running native assets for macos done.', + ]), + ); expect( nativeAssetsYaml, projectUri.resolve('build/native_assets/macos/native_assets.yaml'), @@ -291,6 +298,13 @@ void main() { ), ), ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Building native assets for [macos_arm64] debug.', + 'Building native assets for [macos_arm64] done.', + ]), + ); expect( nativeAssetsYaml, projectUri.resolve('build/native_assets/macos/native_assets.yaml'), @@ -301,7 +315,7 @@ void main() { 'package:bar/bar.dart', if (flutterTester) // Tests run on host system, so the have the full path on the system. - '- ${projectUri.resolve('/build/native_assets/macos/bar.dylib').toFilePath()}' + '- ${projectUri.resolve('build/native_assets/macos/bar.dylib').toFilePath()}' else // Apps are a bundle with the dylibs on their dlopen path. '- bar.dylib', @@ -370,7 +384,6 @@ InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault ), }, () async { if (!const LocalPlatform().isMacOS) { - // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 return; } diff --git a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart index 8689febb15ae8..6ebbfa9bc2705 100644 --- a/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart +++ b/packages/flutter_tools/test/general.shard/migrations/cmake_project_migration_test.dart @@ -230,9 +230,9 @@ install(DIRECTORY "${NATIVE_ASSETS_DIR}" expect(testLogger.statusText, isEmpty); }); - // TODO(dacoharkes): Add test for Windows when adding Windows support. https://github.com/flutter/flutter/issues/129757 - testWithoutContext('is migrated to copy native assets', () { - managedCmakeFile.writeAsStringSync(r''' + for (final String os in <String>['linux', 'windows']) { + testWithoutContext('is migrated to copy native assets', () { + managedCmakeFile.writeAsStringSync(r''' foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" @@ -249,38 +249,40 @@ install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) '''); - final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( - mockCmakeProject, - 'linux', - testLogger, - ); - cmakeProjectMigration.migrate(); - - expect(managedCmakeFile.readAsStringSync(), r''' -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + final CmakeNativeAssetsMigration cmakeProjectMigration = CmakeNativeAssetsMigration( + mockCmakeProject, + os, + testLogger, + ); + cmakeProjectMigration.migrate(); + + expect(managedCmakeFile.readAsStringSync(), ''' +foreach(bundled_library \${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "\${bundled_library}" + DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) # Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) +set(NATIVE_ASSETS_DIR "\${PROJECT_BUILD_DIR}native_assets/$os/") +install(DIRECTORY "\${NATIVE_ASSETS_DIR}" + DESTINATION "\${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + file(REMOVE_RECURSE \\"\${INSTALL_BUNDLE_DATA_DIR}/\${FLUTTER_ASSET_DIR_NAME}\\") " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) +install(DIRECTORY "\${PROJECT_BUILD_DIR}/\${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "\${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) '''); - expect(testLogger.statusText, contains('CMake missing install() NATIVE_ASSETS_DIR command, updating.')); - }); + expect(testLogger.statusText, + contains('CMake missing install() NATIVE_ASSETS_DIR command, updating.')); + }); + } }); }); } diff --git a/packages/flutter_tools/test/general.shard/windows/native_assets_test.dart b/packages/flutter_tools/test/general.shard/windows/native_assets_test.dart new file mode 100644 index 0000000000000..71a52fed23559 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/windows/native_assets_test.dart @@ -0,0 +1,439 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/dart/package_map.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/native_assets.dart'; +import 'package:flutter_tools/src/windows/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target; +import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli; +import 'package:package_config/package_config_types.dart'; + +import '../../src/common.dart'; +import '../../src/context.dart'; +import '../../src/fakes.dart'; +import '../fake_native_assets_build_runner.dart'; + +void main() { + late FakeProcessManager processManager; + late Environment environment; + late Artifacts artifacts; + late FileSystem fileSystem; + late BufferLogger logger; + late Uri projectUri; + + setUp(() { + processManager = FakeProcessManager.empty(); + logger = BufferLogger.test(); + artifacts = Artifacts.test(); + fileSystem = MemoryFileSystem.test(style: FileSystemStyle.windows); + environment = Environment.test( + fileSystem.currentDirectory, + inputs: <String, String>{}, + artifacts: artifacts, + processManager: processManager, + fileSystem: fileSystem, + logger: logger, + ); + environment.buildDir.createSync(recursive: true); + projectUri = environment.projectDir.uri; + }); + + testUsingContext('dry run with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + expect( + await dryRunNativeAssetsWindows( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ), + null, + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('build with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await buildNativeAssetsWindows( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run for multiple OSes with no package config', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await dryRunNativeAssetsMultipeOSes( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: <TargetPlatform>[ + TargetPlatform.windows_x64, + ], + buildRunner: FakeNativeAssetsBuildRunner( + hasPackageConfigResult: false, + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + contains('No package config found. Skipping native assets compilation.'), + ); + }); + + testUsingContext('dry run with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsWindows( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('dry run with assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final Uri? nativeAssetsYaml = await dryRunNativeAssetsWindows( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.windowsX64, + path: AssetAbsolutePath(Uri.file('bar.dll')), + ), + ], + ), + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Dry running native assets for windows.', + 'Dry running native assets for windows done.', + ]), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/windows/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + contains('package:bar/bar.dart'), + ); + }); + + testUsingContext('build with assets but not enabled', overrides: <Type, Generator>{ + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => buildNativeAssetsWindows( + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ), + throwsToolExit( + message: 'Package(s) bar require the native assets feature to be enabled. ' + 'Enable using `flutter config --enable-native-assets`.', + ), + ); + }); + + testUsingContext('build no assets', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsWindows( + targetPlatform: TargetPlatform.windows_x64, + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + ), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/windows/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + isNot(contains('package:bar/bar.dart')), + ); + expect( + environment.projectDir.childDirectory('build').childDirectory('native_assets').childDirectory('windows'), + exists, + ); + }); + + for (final bool flutterTester in <bool>[false, true]) { + String testName = ''; + if (flutterTester) { + testName += ' flutter tester'; + } + testUsingContext('build with assets$testName', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childDirectory('.dart_tool').childFile('package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + final File dylibAfterCompiling = fileSystem.file('bar.dll'); + // The mock doesn't create the file, so create it here. + await dylibAfterCompiling.create(); + final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsWindows( + targetPlatform: TargetPlatform.windows_x64, + projectUri: projectUri, + buildMode: BuildMode.debug, + fileSystem: fileSystem, + flutterTester: flutterTester, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + buildResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.dynamic, + target: native_assets_cli.Target.windowsX64, + path: AssetAbsolutePath(dylibAfterCompiling.uri), + ), + ], + ), + ), + ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder(<String>[ + 'Building native assets for windows_x64 debug.', + 'Building native assets for windows_x64 done.', + ]), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/windows/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + stringContainsInOrder(<String>[ + 'package:bar/bar.dart', + if (flutterTester) + // Tests run on host system, so the have the full path on the system. + '- ${projectUri.resolve('build/native_assets/windows/bar.dll').toFilePath()}' + else + // Apps are a bundle with the dylibs on their dlopen path. + '- bar.dll', + ]), + ); + }); + } + + testUsingContext('static libs not supported', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => dryRunNativeAssetsWindows( + projectUri: projectUri, + fileSystem: fileSystem, + buildRunner: FakeNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: <Package>[ + Package('bar', projectUri), + ], + dryRunResult: FakeNativeAssetsBuilderResult( + assets: <Asset>[ + Asset( + id: 'package:bar/bar.dart', + linkMode: LinkMode.static, + target: native_assets_cli.Target.windowsX64, + path: AssetAbsolutePath(Uri.file(OS.windows.staticlibFileName('bar'))), + ), + ], + ), + ), + ), + throwsToolExit( + message: 'Native asset(s) package:bar/bar.dart have their link mode set to ' + 'static, but this is not yet supported. ' + 'For more info see https://github.com/dart-lang/sdk/issues/49418.', + ), + ); + }); + + // This logic is mocked in the other tests to avoid having test order + // randomization causing issues with what processes are invoked. + // Exercise the parsing of the process output in this separate test. + testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', overrides: <Type, Generator>{ + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + <FakeCommand>[ + FakeCommand( + command: <Pattern>[ + RegExp(r'(.*)vswhere.exe'), + '-format', + 'json', + '-products', + '*', + '-utf8', + '-latest', + '-version', + '16', + '-requires', + 'Microsoft.VisualStudio.Workload.NativeDesktop', + 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', + 'Microsoft.VisualStudio.Component.VC.CMake.Project', + ], + stdout: r''' +[ + { + "instanceId": "491ec752", + "installDate": "2023-04-21T08:17:11Z", + "installationName": "VisualStudio/17.5.4+33530.505", + "installationPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community", + "installationVersion": "17.5.33530.505", + "productId": "Microsoft.VisualStudio.Product.Community", + "productPath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\IDE\\devenv.exe", + "state": 4294967295, + "isComplete": true, + "isLaunchable": true, + "isPrerelease": false, + "isRebootRequired": false, + "displayName": "Visual Studio Community 2022", + "description": "Powerful IDE, free for students, open-source contributors, and individuals", + "channelId": "VisualStudio.17.Release", + "channelUri": "https://aka.ms/vs/17/release/channel", + "enginePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\resources\\app\\ServiceHub\\Services\\Microsoft.VisualStudio.Setup.Service", + "installedChannelId": "VisualStudio.17.Release", + "installedChannelUri": "https://aka.ms/vs/17/release/channel", + "releaseNotes": "https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-v17.5#17.5.4", + "thirdPartyNotices": "https://go.microsoft.com/fwlink/?LinkId=661288", + "updateDate": "2023-04-21T08:17:11.2249473Z", + "catalog": { + "buildBranch": "d17.5", + "buildVersion": "17.5.33530.505", + "id": "VisualStudio/17.5.4+33530.505", + "localBuild": "build-lab", + "manifestName": "VisualStudio", + "manifestType": "installer", + "productDisplayVersion": "17.5.4", + "productLine": "Dev17", + "productLineVersion": "2022", + "productMilestone": "RTW", + "productMilestoneIsPreRelease": "False", + "productName": "Visual Studio", + "productPatchVersion": "4", + "productPreReleaseMilestoneSuffix": "1.0", + "productSemanticVersion": "17.5.4+33530.505", + "requiredEngineVersion": "3.5.2150.18781" + }, + "properties": { + "campaignId": "2060:abb99c5d1ecc4013acf2e1814b10b690", + "channelManifestId": "VisualStudio.17.Release/17.5.4+33530.505", + "nickname": "", + "setupEngineFilePath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\setup.exe" + } + } +] +''', // Newline at the end of the string. + ) + ], + ), + FileSystem: () => fileSystem, + }, () async { + if (!const LocalPlatform().isWindows) { + return; + } + + final Directory msvcBinDir = + fileSystem.directory(r'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64'); + await msvcBinDir.create(recursive: true); + + final File packagesFile = fileSystem + .directory(projectUri) + .childDirectory('.dart_tool') + .childFile('package_config.json'); + await packagesFile.parent.create(); + await packagesFile.create(); + final PackageConfig packageConfig = await loadPackageConfigWithLogging( + packagesFile, + logger: environment.logger, + ); + final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl( + projectUri, + packageConfig, + fileSystem, + logger, + ); + final CCompilerConfig result = await runner.cCompilerConfig; + expect(result.cc?.toFilePath(), msvcBinDir.childFile('cl.exe').uri.toFilePath()); + expect(result.ar?.toFilePath(), msvcBinDir.childFile('lib.exe').uri.toFilePath()); + expect(result.ld?.toFilePath(), msvcBinDir.childFile('link.exe').uri.toFilePath()); + expect(result.envScript, isNotNull); + expect(result.envScriptArgs, isNotNull); + }); +} diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart index 6f2aa45411a32..57b07e929e280 100644 --- a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart @@ -11,12 +11,16 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/windows/visual_studio.dart'; import '../../src/common.dart'; -import '../../src/fake_process_manager.dart'; +import '../../src/context.dart'; const String programFilesPath = r'C:\Program Files (x86)'; const String visualStudioPath = programFilesPath + r'\Microsoft Visual Studio\2017\Community'; const String cmakePath = visualStudioPath + r'\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe'; const String vswherePath = programFilesPath + r'\Microsoft Visual Studio\Installer\vswhere.exe'; +const String clPath = visualStudioPath + r'\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64\cl.exe'; +const String libPath = visualStudioPath + r'\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64\lib.exe'; +const String linkPath = visualStudioPath + r'\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64\link.exe'; +const String vcvarsPath = visualStudioPath + r'\VC\Auxiliary\Build\vcvars64.bat'; final Platform windowsPlatform = FakePlatform( operatingSystem: 'windows', @@ -140,6 +144,7 @@ void setMockVswhereResponse( ]) { fileSystem.file(vswherePath).createSync(recursive: true); fileSystem.file(cmakePath).createSync(recursive: true); + fileSystem.file(clPath).createSync(recursive: true); final String finalResponse = responseOverride ?? (response != null ? json.encode(<Map<String, dynamic>>[response]) : '[]'); final List<String> requirementArguments = requiredComponents == null @@ -300,11 +305,11 @@ void setMockSdkRegResponse( const String registryKey = r'InstallationFolder'; const String installationPath = r'C:\Program Files (x86)\Windows Kits\10\'; final String stdout = registryPresent - ? ''' + ? ''' $registryPath $registryKey REG_SZ $installationPath ''' - : ''' + : ''' ERROR: The system was unable to find the specified registry key or value. '''; @@ -776,6 +781,10 @@ void main() { expect(visualStudio.hasNecessaryComponents, true); expect(visualStudio.cmakePath, equals(cmakePath)); expect(visualStudio.cmakeGenerator, equals('Visual Studio 16 2019')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); }); testWithoutContext('Everything returns good values when Build Tools is present with all components', () { @@ -814,6 +823,10 @@ void main() { expect(visualStudio.hasNecessaryComponents, true); expect(visualStudio.cmakePath, equals(cmakePath)); expect(visualStudio.cmakeGenerator, equals('Visual Studio 17 2022')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); }); testWithoutContext('Metadata is for compatible version when latest is missing components', () { @@ -905,8 +918,7 @@ void main() { }); testWithoutContext('Ignores unicode replacement char in unused properties', () { - final Map<String, dynamic> response = Map<String, dynamic>.of(_defaultResponse) - ..['unused'] = 'Bad UTF8 \u{FFFD}'; + final Map<String, dynamic> response = Map<String, dynamic>.of(_defaultResponse)..['unused'] = 'Bad UTF8 \u{FFFD}'; setMockCompatibleVisualStudioInstallation( response, @@ -919,6 +931,10 @@ void main() { expect(visualStudio.hasNecessaryComponents, true); expect(visualStudio.cmakePath, equals(cmakePath)); expect(visualStudio.cmakeGenerator, equals('Visual Studio 16 2019')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); }); testWithoutContext('Throws ToolExit on bad UTF-8 in installationPath', () { @@ -953,13 +969,16 @@ void main() { expect(visualStudio.cmakePath, equals(cmakePath)); expect(visualStudio.cmakeGenerator, equals('Visual Studio 16 2019')); expect(visualStudio.displayName, equals('\u{FFFD}')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); }); testWithoutContext("Ignores bad UTF-8 in catalog's productDisplayVersion", () { final Map<String, dynamic> catalog = Map<String, dynamic>.of(_defaultResponse['catalog'] as Map<String, dynamic>) ..['productDisplayVersion'] = '\u{FFFD}'; - final Map<String, dynamic> response = Map<String, dynamic>.of(_defaultResponse) - ..['catalog'] = catalog; + final Map<String, dynamic> response = Map<String, dynamic>.of(_defaultResponse)..['catalog'] = catalog; setMockCompatibleVisualStudioInstallation(response, fixture.fileSystem, fixture.processManager); @@ -969,6 +988,10 @@ void main() { expect(visualStudio.cmakePath, equals(cmakePath)); expect(visualStudio.cmakeGenerator, equals('Visual Studio 16 2019')); expect(visualStudio.displayVersion, equals('\u{FFFD}')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); }); testWithoutContext('Ignores malformed JSON in description property', () { @@ -987,101 +1010,109 @@ void main() { expect(visualStudio.cmakePath, equals(cmakePath)); expect(visualStudio.cmakeGenerator, equals('Visual Studio 16 2019')); expect(visualStudio.displayVersion, equals('16.2.5')); + expect(visualStudio.clPath, equals(clPath)); + expect(visualStudio.libPath, equals(libPath)); + expect(visualStudio.linkPath, equals(linkPath)); + expect(visualStudio.vcvarsPath, equals(vcvarsPath)); expect(fixture.logger.warningText, isEmpty); }); }); group(VswhereDetails, () { - test('Accepts empty JSON', () { - const bool meetsRequirements = true; - final Map<String, dynamic> json = <String, dynamic>{}; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json); - - expect(result.installationPath, null); - expect(result.displayName, null); - expect(result.fullVersion, null); - expect(result.isComplete, null); - expect(result.isLaunchable, null); - expect(result.isRebootRequired, null); - expect(result.isPrerelease, null); - expect(result.catalogDisplayVersion, null); - expect(result.isUsable, isTrue); - }); - - test('Ignores unknown JSON properties', () { - const bool meetsRequirements = true; - final Map<String, dynamic> json = <String, dynamic>{ - 'hello': 'world', - }; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json); - - expect(result.installationPath, null); - expect(result.displayName, null); - expect(result.fullVersion, null); - expect(result.isComplete, null); - expect(result.isLaunchable, null); - expect(result.isRebootRequired, null); - expect(result.isPrerelease, null); - expect(result.catalogDisplayVersion, null); - expect(result.isUsable, isTrue); - }); - - test('Accepts JSON', () { - const bool meetsRequirements = true; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, _defaultResponse); - - expect(result.installationPath, visualStudioPath); - expect(result.displayName, 'Visual Studio Community 2019'); - expect(result.fullVersion, '16.2.29306.81'); - expect(result.isComplete, true); - expect(result.isLaunchable, true); - expect(result.isRebootRequired, false); - expect(result.isPrerelease, false); - expect(result.catalogDisplayVersion, '16.2.5'); - expect(result.isUsable, isTrue); - }); - - test('Installation that does not satisfy requirements is not usable', () { - const bool meetsRequirements = false; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, _defaultResponse); - - expect(result.isUsable, isFalse); - }); - - test('Incomplete installation is not usable', () { - const bool meetsRequirements = true; - final Map<String, dynamic> json = Map<String, dynamic>.of(_defaultResponse) - ..['isComplete'] = false; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json); - - expect(result.isUsable, isFalse); - }); - - test('Unlaunchable installation is not usable', () { - const bool meetsRequirements = true; - final Map<String, dynamic> json = Map<String, dynamic>.of(_defaultResponse) - ..['isLaunchable'] = false; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json); - - expect(result.isUsable, isFalse); - }); - - test('Installation that requires reboot is not usable', () { - const bool meetsRequirements = true; - final Map<String, dynamic> json = Map<String, dynamic>.of(_defaultResponse) - ..['isRebootRequired'] = true; - - final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json); - - expect(result.isUsable, isFalse); - }); + test('Accepts empty JSON', () { + const bool meetsRequirements = true; + final Map<String, dynamic> json = <String, dynamic>{}; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json, msvcVersion); + + expect(result.installationPath, null); + expect(result.displayName, null); + expect(result.fullVersion, null); + expect(result.isComplete, null); + expect(result.isLaunchable, null); + expect(result.isRebootRequired, null); + expect(result.isPrerelease, null); + expect(result.catalogDisplayVersion, null); + expect(result.isUsable, isTrue); + }); + + test('Ignores unknown JSON properties', () { + const bool meetsRequirements = true; + final Map<String, dynamic> json = <String, dynamic>{ + 'hello': 'world', + }; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json, msvcVersion); + + expect(result.installationPath, null); + expect(result.displayName, null); + expect(result.fullVersion, null); + expect(result.isComplete, null); + expect(result.isLaunchable, null); + expect(result.isRebootRequired, null); + expect(result.isPrerelease, null); + expect(result.catalogDisplayVersion, null); + expect(result.isUsable, isTrue); + }); + + test('Accepts JSON', () { + const bool meetsRequirements = true; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, _defaultResponse, msvcVersion); + + expect(result.installationPath, visualStudioPath); + expect(result.displayName, 'Visual Studio Community 2019'); + expect(result.fullVersion, '16.2.29306.81'); + expect(result.isComplete, true); + expect(result.isLaunchable, true); + expect(result.isRebootRequired, false); + expect(result.isPrerelease, false); + expect(result.catalogDisplayVersion, '16.2.5'); + expect(result.isUsable, isTrue); + }); + + test('Installation that does not satisfy requirements is not usable', () { + const bool meetsRequirements = false; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, _defaultResponse, msvcVersion); + + expect(result.isUsable, isFalse); + }); + + test('Incomplete installation is not usable', () { + const bool meetsRequirements = true; + final Map<String, dynamic> json = Map<String, dynamic>.of(_defaultResponse)..['isComplete'] = false; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json, msvcVersion); + + expect(result.isUsable, isFalse); + }); + + test('Unlaunchable installation is not usable', () { + const bool meetsRequirements = true; + final Map<String, dynamic> json = Map<String, dynamic>.of(_defaultResponse)..['isLaunchable'] = false; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json, msvcVersion); + + expect(result.isUsable, isFalse); + }); + + test('Installation that requires reboot is not usable', () { + const bool meetsRequirements = true; + final Map<String, dynamic> json = Map<String, dynamic>.of(_defaultResponse)..['isRebootRequired'] = true; + const String msvcVersion = ''; + + final VswhereDetails result = VswhereDetails.fromJson(meetsRequirements, json, msvcVersion); + + expect(result.isUsable, isFalse); + }); }); } diff --git a/packages/flutter_tools/test/integration.shard/native_assets_test.dart b/packages/flutter_tools/test/integration.shard/native_assets_test.dart index c6824fb35774e..3456c6a224b6f 100644 --- a/packages/flutter_tools/test/integration.shard/native_assets_test.dart +++ b/packages/flutter_tools/test/integration.shard/native_assets_test.dart @@ -58,8 +58,8 @@ const String packageName = 'package_with_native_assets'; const String exampleAppName = '${packageName}_example'; void main() { - if (!platform.isMacOS && !platform.isLinux) { - // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + if (!platform.isMacOS && !platform.isLinux && !platform.isWindows) { + // TODO(dacoharkes): Implement Fuchsia. https://github.com/flutter/flutter/issues/129757 return; } @@ -146,9 +146,10 @@ void main() { if (device == 'macos') { expectDylibIsBundledMacOS(exampleDirectory, buildMode); - } - if (device == 'linux') { + } else if (device == 'linux') { expectDylibIsBundledLinux(exampleDirectory, buildMode); + } else if (device == 'windows') { + expectDylibIsBundledWindows(exampleDirectory, buildMode); } if (device == hostOs) { expectCCompilerIsConfigured(exampleDirectory); @@ -205,6 +206,8 @@ void main() { expectDylibIsBundledIos(exampleDirectory, buildMode); } else if (buildSubcommand == 'linux') { expectDylibIsBundledLinux(exampleDirectory, buildMode); + } else if (buildSubcommand == 'windows') { + expectDylibIsBundledWindows(exampleDirectory, buildMode); } expectCCompilerIsConfigured(exampleDirectory); }); @@ -239,11 +242,15 @@ void main() { 'build', buildSubcommand, if (buildSubcommand == 'ios') '--no-codesign', + if (buildSubcommand == 'windows') '-v' // Requires verbose mode for error. ], workingDirectory: exampleDirectory.path, ); expect(result.exitCode, isNot(0)); - expect(result.stderr, contains('link mode set to static, but this is not yet supported')); + expect( + (result.stdout as String) + (result.stderr as String), + contains('link mode set to static, but this is not yet supported'), + ); }); }); } @@ -301,14 +308,36 @@ void expectDylibIsBundledIos(Directory appDirectory, String buildMode) { void expectDylibIsBundledLinux(Directory appDirectory, String buildMode) { // Linux does not support cross compilation, so always only check current architecture. final String architecture = Architecture.current.dartPlatform; - final Directory appBundle = appDirectory.childDirectory('build/$hostOs/$architecture/$buildMode/bundle/'); + final Directory appBundle = appDirectory + .childDirectory('build') + .childDirectory(hostOs) + .childDirectory(architecture) + .childDirectory(buildMode) + .childDirectory('bundle'); expect(appBundle, exists); - final Directory dylibsFolder = appBundle.childDirectory('lib/'); + final Directory dylibsFolder = appBundle.childDirectory('lib'); expect(dylibsFolder, exists); final File dylib = dylibsFolder.childFile(OS.linux.dylibFileName(packageName)); expect(dylib, exists); } +/// Checks that dylibs are bundled. +/// +/// Sample path: build\windows\x64\runner\Debug\my_package_example.exe +void expectDylibIsBundledWindows(Directory appDirectory, String buildMode) { + // Linux does not support cross compilation, so always only check current architecture. + final String architecture = Architecture.current.dartPlatform; + final Directory appBundle = appDirectory + .childDirectory('build') + .childDirectory(hostOs) + .childDirectory(architecture) + .childDirectory('runner') + .childDirectory(buildMode.upperCaseFirst()); + expect(appBundle, exists); + final File dylib = appBundle.childFile(OS.windows.dylibFileName(packageName)); + expect(dylib, exists); +} + /// For `flutter build` we can't easily test whether running the app works. /// Check that we have the dylibs in the app. void expectDylibIsBundledWithFrameworks(Directory appDirectory, String buildMode, String os) { From 9fedb1a6ce03f58f47db01f9cefc5226dd086926 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Wed, 27 Sep 2023 08:35:32 -0700 Subject: [PATCH 1489/1547] Marks Linux_pixel_7pro hello_world_impeller to be unflaky (#135564) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_pixel_7pro hello_world_impeller" } --> The test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux_pixel_7pro%20hello_world_impeller%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index 4fcfc6696cc3b..e443943fcddad 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1780,7 +1780,6 @@ targets: recipe: devicelab/devicelab_drone presubmit: false # Uses Impeller. - bringup: true timeout: 60 properties: tags: > From 2a19b71a8281ad86aadf74bfb55674017bb7b060 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Wed, 27 Sep 2023 12:06:49 -0400 Subject: [PATCH 1490/1547] Roll Packages from 619af75f7966 to 21c2ebb39c07 (6 revisions) (#135602) https://github.com/flutter/packages/compare/619af75f7966...21c2ebb39c07 2023-09-26 43054281+camsim99@users.noreply.github.com [Android] Add new tasks for subset of tests to run API 33 (flutter/packages#4974) 2023-09-26 stuartmorgan@google.com [video_player] Update iOS prefixes (flutter/packages#4994) 2023-09-26 srawlins@google.com [go_router] Fix @tool directive with missing @end-tool (flutter/packages#4998) 2023-09-26 84124091+opxdelwin@users.noreply.github.com [GoRouter] option to override initial route set by platform (flutter/packages#4717) 2023-09-26 ditman@gmail.com [video_player] Ensures autoplay is false on the web. (flutter/packages#4961) 2023-09-26 34871572+gmackall@users.noreply.github.com [camera_android] Downgrade to AGP 7.3.0 to fix build_alll_packages test failures (flutter/packages#4997) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 3fb150d36ffd8..817cebedcd599 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -619af75f7966f90498dfce3a754d37422b972c6d +21c2ebb39c0732b8c4ae2d68f25b96a895be915f From d3c45f1499ae9fedc24bd0e47f7d5eddd1a608e8 Mon Sep 17 00:00:00 2001 From: godofredoc <godofredoc@google.com> Date: Wed, 27 Sep 2023 09:42:54 -0700 Subject: [PATCH 1491/1547] Config changes for linux coverage. (#135604) This build runs for over and hour and it does not need to run on presubmit or release candidate branches. --- .ci.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index e443943fcddad..ae6015b314bce 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -245,9 +245,12 @@ targets: task_name: analyzer_benchmark - name: Linux coverage - bringup: true + presubmit: false recipe: flutter/coverage timeout: 120 + enabled_branches: + # Don't run this on release branches + - master properties: tags: > ["framework", "hostonly", "shard", "linux"] From 433bca5edb0bb9646174a4f23d3710b7145626f5 Mon Sep 17 00:00:00 2001 From: Taha Tesser <tessertaha@gmail.com> Date: Wed, 27 Sep 2023 20:02:17 +0300 Subject: [PATCH 1492/1547] Fix `SearchAnchor`'s search view isn't updated when the theme changes & widgets inside the search view do not inherit local themes (#132749) fixes [SearchAnchor (search view) UI glitch on platform brightness changes](https://github.com/flutter/flutter/issues/131835) fixes [Search view widgets cannot inherit local themes](https://github.com/flutter/flutter/issues/132741) ### Description - This fixes an issue where the `SearchAnchor`'s search view isn't updated when the platform brightness changes. - Fixes an issue where widgets inside the search view cannot use local themes ### Actual Results `SearchAnchor` currently passed both global and local themes on the search view popup pushing and it uses anchor. button's context to look up the theme. ![search_view drawio (1)](https://github.com/flutter/flutter/assets/48603081/b5317fb1-ee73-461c-a119-f2a1e29f5909) As a result, when the platform changes and the search view is rebuilt, it cannot use the updated theme. https://github.com/flutter/flutter/assets/48603081/2f1ebe74-e7d5-4ef3-b97c-a741c3d68964 ### Expected Results Similar to `PopupMenuButton`, the theme should be located in the search view so that when the platform brightness is updated and the search view is rebuilt it can use the updated theme. ![search_view drawio](https://github.com/flutter/flutter/assets/48603081/4e48c0cb-a558-4de6-9865-5f51981a343f) https://github.com/flutter/flutter/assets/48603081/d8d85982-c661-4cac-83e8-0488b1d93daf However, the search view's context cannot access local themes so I added support for `InheritedTheme`, which fixes the local. theme issue for both the search view and widgets inside the search view. ### When using local themes for the `SearchAnchor`'s search view and widgets inside the view. ### Before ![Screenshot 2023-08-17 at 15 54 02](https://github.com/flutter/flutter/assets/48603081/dec18ba3-9f01-4706-987a-eb2fd4afb180) ### After ![Screenshot 2023-08-17 at 15 55 15](https://github.com/flutter/flutter/assets/48603081/13f2797a-7f70-43b5-bc56-7971cf76a61d) --- .../lib/src/material/search_anchor.dart | 103 ++++++++-------- .../lib/src/material/search_view_theme.dart | 7 +- .../test/material/search_anchor_test.dart | 111 ++++++++++++++++++ 3 files changed, 168 insertions(+), 53 deletions(-) diff --git a/packages/flutter/lib/src/material/search_anchor.dart b/packages/flutter/lib/src/material/search_anchor.dart index 1c68a4fd8496f..32fcad2862a76 100644 --- a/packages/flutter/lib/src/material/search_anchor.dart +++ b/packages/flutter/lib/src/material/search_anchor.dart @@ -342,7 +342,8 @@ class _SearchAnchorState extends State<SearchAnchor> { } void _openView() { - Navigator.of(context).push(_SearchViewRoute( + final NavigatorState navigator = Navigator.of(context); + navigator.push(_SearchViewRoute( viewLeading: widget.viewLeading, viewTrailing: widget.viewTrailing, viewHintText: widget.viewHintText, @@ -363,6 +364,7 @@ class _SearchAnchorState extends State<SearchAnchor> { searchController: _searchController, suggestionsBuilder: widget.suggestionsBuilder, textCapitalization: widget.textCapitalization, + capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), )); } @@ -433,6 +435,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { required this.anchorKey, required this.searchController, required this.suggestionsBuilder, + required this.capturedThemes, }); final ValueGetter<bool>? toggleVisibility; @@ -455,6 +458,7 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { final GlobalKey anchorKey; final SearchController searchController; final SuggestionsBuilder suggestionsBuilder; + final CapturedThemes capturedThemes; @override Color? get barrierColor => Colors.transparent; @@ -467,7 +471,6 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { late final SearchViewThemeData viewDefaults; late final SearchViewThemeData viewTheme; - late final DividerThemeData dividerTheme; final RectTween _rectTween = RectTween(); Rect? getRect() { @@ -502,7 +505,6 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { void updateViewConfig(BuildContext context) { viewDefaults = _SearchViewDefaultsM3(context, isFullScreen: showFullScreenView); viewTheme = SearchViewTheme.of(context); - dividerTheme = DividerTheme.of(context); } void updateTweens(BuildContext context) { @@ -576,30 +578,29 @@ class _SearchViewRoute extends PopupRoute<_SearchViewRoute> { curve: _kViewFadeOnInterval, reverseCurve: _kViewFadeOnInterval.flipped, ), - child: _ViewContent( - viewLeading: viewLeading, - viewTrailing: viewTrailing, - viewHintText: viewHintText, - viewBackgroundColor: viewBackgroundColor, - viewElevation: viewElevation, - viewSurfaceTintColor: viewSurfaceTintColor, - viewSide: viewSide, - viewShape: viewShape, - viewHeaderTextStyle: viewHeaderTextStyle, - viewHeaderHintStyle: viewHeaderHintStyle, - dividerColor: dividerColor, - showFullScreenView: showFullScreenView, - animation: curvedAnimation, - topPadding: topPadding, - viewMaxWidth: _rectTween.end!.width, - viewRect: viewRect, - viewDefaults: viewDefaults, - viewTheme: viewTheme, - dividerTheme: dividerTheme, - viewBuilder: viewBuilder, - searchController: searchController, - suggestionsBuilder: suggestionsBuilder, - textCapitalization: textCapitalization, + child: capturedThemes.wrap( + _ViewContent( + viewLeading: viewLeading, + viewTrailing: viewTrailing, + viewHintText: viewHintText, + viewBackgroundColor: viewBackgroundColor, + viewElevation: viewElevation, + viewSurfaceTintColor: viewSurfaceTintColor, + viewSide: viewSide, + viewShape: viewShape, + viewHeaderTextStyle: viewHeaderTextStyle, + viewHeaderHintStyle: viewHeaderHintStyle, + dividerColor: dividerColor, + showFullScreenView: showFullScreenView, + animation: curvedAnimation, + topPadding: topPadding, + viewMaxWidth: _rectTween.end!.width, + viewRect: viewRect, + viewBuilder: viewBuilder, + searchController: searchController, + suggestionsBuilder: suggestionsBuilder, + textCapitalization: textCapitalization, + ), ), ); } @@ -631,9 +632,6 @@ class _ViewContent extends StatefulWidget { required this.animation, required this.viewMaxWidth, required this.viewRect, - required this.viewDefaults, - required this.viewTheme, - required this.dividerTheme, required this.searchController, required this.suggestionsBuilder, }); @@ -656,9 +654,6 @@ class _ViewContent extends StatefulWidget { final Animation<double> animation; final double viewMaxWidth; final Rect viewRect; - final SearchViewThemeData viewDefaults; - final SearchViewThemeData viewTheme; - final DividerThemeData dividerTheme; final SearchController searchController; final SuggestionsBuilder suggestionsBuilder; @@ -747,39 +742,43 @@ class _ViewContentState extends State<_ViewContent> { ), ]; + final SearchViewThemeData viewDefaults = _SearchViewDefaultsM3(context, isFullScreen: widget.showFullScreenView); + final SearchViewThemeData viewTheme = SearchViewTheme.of(context); + final DividerThemeData dividerTheme = DividerTheme.of(context); + final Color effectiveBackgroundColor = widget.viewBackgroundColor - ?? widget.viewTheme.backgroundColor - ?? widget.viewDefaults.backgroundColor!; + ?? viewTheme.backgroundColor + ?? viewDefaults.backgroundColor!; final Color effectiveSurfaceTint = widget.viewSurfaceTintColor - ?? widget.viewTheme.surfaceTintColor - ?? widget.viewDefaults.surfaceTintColor!; + ?? viewTheme.surfaceTintColor + ?? viewDefaults.surfaceTintColor!; final double effectiveElevation = widget.viewElevation - ?? widget.viewTheme.elevation - ?? widget.viewDefaults.elevation!; + ?? viewTheme.elevation + ?? viewDefaults.elevation!; final BorderSide? effectiveSide = widget.viewSide - ?? widget.viewTheme.side - ?? widget.viewDefaults.side; + ?? viewTheme.side + ?? viewDefaults.side; OutlinedBorder effectiveShape = widget.viewShape - ?? widget.viewTheme.shape - ?? widget.viewDefaults.shape!; + ?? viewTheme.shape + ?? viewDefaults.shape!; if (effectiveSide != null) { effectiveShape = effectiveShape.copyWith(side: effectiveSide); } final Color effectiveDividerColor = widget.dividerColor - ?? widget.viewTheme.dividerColor - ?? widget.dividerTheme.color - ?? widget.viewDefaults.dividerColor!; + ?? viewTheme.dividerColor + ?? dividerTheme.color + ?? viewDefaults.dividerColor!; final TextStyle? effectiveTextStyle = widget.viewHeaderTextStyle - ?? widget.viewTheme.headerTextStyle - ?? widget.viewDefaults.headerTextStyle; + ?? viewTheme.headerTextStyle + ?? viewDefaults.headerTextStyle; final TextStyle? effectiveHintStyle = widget.viewHeaderHintStyle - ?? widget.viewTheme.headerHintStyle + ?? viewTheme.headerHintStyle ?? widget.viewHeaderTextStyle - ?? widget.viewTheme.headerTextStyle - ?? widget.viewDefaults.headerHintStyle; + ?? viewTheme.headerTextStyle + ?? viewDefaults.headerHintStyle; final Widget viewDivider = DividerTheme( - data: widget.dividerTheme.copyWith(color: effectiveDividerColor), + data: dividerTheme.copyWith(color: effectiveDividerColor), child: const Divider(height: 1), ); diff --git a/packages/flutter/lib/src/material/search_view_theme.dart b/packages/flutter/lib/src/material/search_view_theme.dart index ec893000c2e83..db583be66c5d3 100644 --- a/packages/flutter/lib/src/material/search_view_theme.dart +++ b/packages/flutter/lib/src/material/search_view_theme.dart @@ -187,7 +187,7 @@ class SearchViewThemeData with Diagnosticable { /// /// * [SearchViewThemeData], which describes the actual configuration of a search view /// theme. -class SearchViewTheme extends InheritedWidget { +class SearchViewTheme extends InheritedTheme { /// Creates a const theme that controls the configurations for the search view /// created by the [SearchAnchor] widget. const SearchViewTheme({ @@ -212,6 +212,11 @@ class SearchViewTheme extends InheritedWidget { return searchViewTheme?.data ?? Theme.of(context).searchViewTheme; } + @override + Widget wrap(BuildContext context, Widget child) { + return SearchViewTheme(data: data, child: child); + } + @override bool updateShouldNotify(SearchViewTheme oldWidget) => data != oldWidget.data; } diff --git a/packages/flutter/test/material/search_anchor_test.dart b/packages/flutter/test/material/search_anchor_test.dart index c2af15aad9ac1..3398560998b7a 100644 --- a/packages/flutter/test/material/search_anchor_test.dart +++ b/packages/flutter/test/material/search_anchor_test.dart @@ -2055,6 +2055,117 @@ void main() { expect(inputText.style.color, theme.colorScheme.onSurface); }); }); + + testWidgets('SearchAnchor view respects theme brightness', (WidgetTester tester) async { + Widget buildSearchAnchor(ThemeData theme) { + return MaterialApp( + theme: theme, + home: Center( + child: Material( + child: SearchAnchor( + builder: (BuildContext context, SearchController controller) { + return IconButton( + icon: const Icon(Icons.ac_unit), + onPressed: () { + controller.openView(); + }, + ); + }, + suggestionsBuilder: (BuildContext context, SearchController controller) { + return <Widget>[]; + }, + ), + ), + ), + ); + } + + ThemeData theme = ThemeData(brightness: Brightness.light); + await tester.pumpWidget(buildSearchAnchor(theme)); + + // Open the search view. + await tester.tap(find.widgetWithIcon(IconButton, Icons.ac_unit)); + await tester.pumpAndSettle(); + + // Test the search view background color. + Material material = getSearchViewMaterial(tester); + expect(material.color, theme.colorScheme.surface); + + // Change the theme brightness. + theme = ThemeData(brightness: Brightness.dark); + await tester.pumpWidget(buildSearchAnchor(theme)); + await tester.pumpAndSettle(); + + // Test the search view background color. + material = getSearchViewMaterial(tester); + expect(material.color, theme.colorScheme.surface); + }); + + testWidgets('Search view widgets can inherit local themes', (WidgetTester tester) async { + final ThemeData globalTheme = ThemeData(colorSchemeSeed: Colors.red); + final ThemeData localTheme = ThemeData( + colorSchemeSeed: Colors.green, + iconButtonTheme: IconButtonThemeData( + style: IconButton.styleFrom( + backgroundColor: const Color(0xffffff00) + ), + ), + cardTheme: const CardTheme(color: Color(0xff00ffff)), + ); + Widget buildSearchAnchor() { + return MaterialApp( + theme: globalTheme, + home: Center( + child: Builder( + builder: (BuildContext context) { + return Theme( + data: localTheme, + child: Material( + child: SearchAnchor.bar( + suggestionsBuilder: (BuildContext context, SearchController controller) { + return <Widget>[ + Card( + child: ListTile( + onTap: () {}, + title: const Text('Item 1'), + ), + ), + ]; + }, + ), + ), + ); + } + ), + ), + ); + } + + await tester.pumpWidget(buildSearchAnchor()); + + // Open the search view. + await tester.tap(find.byType(SearchBar)); + await tester.pumpAndSettle(); + + // Test the search view background color. + final Material searchViewMaterial = getSearchViewMaterial(tester); + expect(searchViewMaterial.color, localTheme.colorScheme.surface); + + // Test the search view icons background color. + final Material iconButtonMaterial = tester.widget<Material>(find.descendant( + of: find.byType(IconButton), + matching: find.byType(Material), + ).first); + expect(find.byWidget(iconButtonMaterial), findsOneWidget); + expect(iconButtonMaterial.color, localTheme.iconButtonTheme.style?.backgroundColor?.resolve(<MaterialState>{})); + + // Test the suggestion card color. + final Material suggestionMaterial = tester.widget<Material>(find.descendant( + of: find.byType(Card), + matching: find.byType(Material), + ).first); + expect(suggestionMaterial.color, localTheme.cardTheme.color); + }); } Future<void> checkSearchBarDefaults(WidgetTester tester, ColorScheme colorScheme, Material material) async { From 47f12cae1f3f96a37951c1ace0e4998fe304bec3 Mon Sep 17 00:00:00 2001 From: Casey Rogers <caseycrogers@berkeley.edu> Date: Wed, 27 Sep 2023 14:29:13 -0700 Subject: [PATCH 1493/1547] made top level if checks gaurd clauses (#135070) This is a tiny tweak to replace some top level if clauses with guard clauses in `FutureBuilder`. I find the resultant code much more readable, but this is a matter of taste and I didn't see any info one way or another on it in the style guide so let me know if this is not to your all's preference. --- packages/flutter/lib/src/widgets/async.dart | 67 +++++++++++---------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/packages/flutter/lib/src/widgets/async.dart b/packages/flutter/lib/src/widgets/async.dart index 36b0f77eb48e0..b8aed1f94fc8d 100644 --- a/packages/flutter/lib/src/widgets/async.dart +++ b/packages/flutter/lib/src/widgets/async.dart @@ -595,13 +595,14 @@ class _FutureBuilderState<T> extends State<FutureBuilder<T>> { @override void didUpdateWidget(FutureBuilder<T> oldWidget) { super.didUpdateWidget(oldWidget); - if (oldWidget.future != widget.future) { - if (_activeCallbackIdentity != null) { - _unsubscribe(); - _snapshot = _snapshot.inState(ConnectionState.none); - } - _subscribe(); + if (oldWidget.future == widget.future) { + return; + } + if (_activeCallbackIdentity != null) { + _unsubscribe(); + _snapshot = _snapshot.inState(ConnectionState.none); } + _subscribe(); } @override @@ -614,33 +615,35 @@ class _FutureBuilderState<T> extends State<FutureBuilder<T>> { } void _subscribe() { - if (widget.future != null) { - final Object callbackIdentity = Object(); - _activeCallbackIdentity = callbackIdentity; - widget.future!.then<void>((T data) { - if (_activeCallbackIdentity == callbackIdentity) { - setState(() { - _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data); - }); - } - }, onError: (Object error, StackTrace stackTrace) { - if (_activeCallbackIdentity == callbackIdentity) { - setState(() { - _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error, stackTrace); - }); - } - assert(() { - if (FutureBuilder.debugRethrowError) { - Future<Object>.error(error, stackTrace); - } - return true; - }()); - }); - // An implementation like `SynchronousFuture` may have already called the - // .then closure. Do not overwrite it in that case. - if (_snapshot.connectionState != ConnectionState.done) { - _snapshot = _snapshot.inState(ConnectionState.waiting); + if (widget.future == null) { + // There is no future to subscribe to, do nothing. + return; + } + final Object callbackIdentity = Object(); + _activeCallbackIdentity = callbackIdentity; + widget.future!.then<void>((T data) { + if (_activeCallbackIdentity == callbackIdentity) { + setState(() { + _snapshot = AsyncSnapshot<T>.withData(ConnectionState.done, data); + }); } + }, onError: (Object error, StackTrace stackTrace) { + if (_activeCallbackIdentity == callbackIdentity) { + setState(() { + _snapshot = AsyncSnapshot<T>.withError(ConnectionState.done, error, stackTrace); + }); + } + assert(() { + if (FutureBuilder.debugRethrowError) { + Future<Object>.error(error, stackTrace); + } + return true; + }()); + }); + // An implementation like `SynchronousFuture` may have already called the + // .then closure. Do not overwrite it in that case. + if (_snapshot.connectionState != ConnectionState.done) { + _snapshot = _snapshot.inState(ConnectionState.waiting); } } From 80fb7bd2060132af51b7191d808b9fbbd6e3ab7c Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Wed, 27 Sep 2023 16:57:24 -0500 Subject: [PATCH 1494/1547] Support ensureVisible/showOnScreen/showInViewport for 2D Scrolling (#135182) --- .../src/rendering/list_wheel_viewport.dart | 11 +- .../flutter/lib/src/rendering/viewport.dart | 121 +++++--- .../lib/src/widgets/scroll_position.dart | 24 +- .../flutter/lib/src/widgets/scrollable.dart | 91 +++++- .../src/widgets/single_child_scroll_view.dart | 12 +- .../src/widgets/two_dimensional_viewport.dart | 278 +++++++++++++++++- .../test/widgets/ensure_visible_test.dart | 277 +++++++++++++++++ .../test/widgets/two_dimensional_utils.dart | 1 + .../two_dimensional_viewport_test.dart | 269 +++++++++++++++++ 9 files changed, 1026 insertions(+), 58 deletions(-) diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart index bdf62c603b169..611d3e55e6408 100644 --- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart @@ -1121,11 +1121,18 @@ class RenderListWheelViewport } @override - RevealedOffset getOffsetToReveal(RenderObject target, double alignment, { Rect? rect }) { + RevealedOffset getOffsetToReveal( + RenderObject target, + double alignment, { + Rect? rect, + Axis? axis, + }) { + // One dimensional viewport has only one axis, it should match if it has + // been provided. + assert(axis == null || axis == Axis.vertical); // `target` is only fully revealed when in the selected/center position. Therefore, // this method always returns the offset that shows `target` in the center position, // which is the same offset for all `alignment` values. - rect ??= target.paintBounds; // `child` will be the last RenderObject before the viewport when walking up from `target`. diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index 4e04e9b64372b..aa2dd97b9c5cf 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -108,10 +108,22 @@ abstract interface class RenderAbstractViewport extends RenderObject { /// when the offset of the viewport is changed by x then `target` also moves /// by x within the viewport. /// + /// The optional [Axis] is used by + /// [RenderTwoDimensionalViewport.getOffsetToReveal] to + /// determine which of the two axes to compute an offset for. One dimensional + /// subclasses like [RenderViewportBase] and [RenderListWheelViewport] will + /// assert in debug builds if the `axis` value is provided and does not match + /// the single [Axis] that viewport is configured for. + /// /// See also: /// /// * [RevealedOffset], which describes the return value of this method. - RevealedOffset getOffsetToReveal(RenderObject target, double alignment, { Rect? rect }); + RevealedOffset getOffsetToReveal( + RenderObject target, + double alignment, { + Rect? rect, + Axis? axis, + }); /// The default value for the cache extent of the viewport. /// @@ -169,6 +181,56 @@ class RevealedOffset { /// value for a specific element. final Rect rect; + /// Determines which provided leading or trailing edge of the viewport, as + /// [RevealedOffset]s, will be used for [RenderViewportBase.showInViewport] + /// accounting for the size and already visible portion of the [RenderObject] + /// that is being revealed. + /// + /// Also used by [RenderTwoDimensionalViewport.showInViewport] for each + /// horizontal and vertical [Axis]. + /// + /// If the target [RenderObject] is already fully visible, this will return + /// null. + static RevealedOffset? clampOffset({ + required RevealedOffset leadingEdgeOffset, + required RevealedOffset trailingEdgeOffset, + required double currentOffset, + }) { + // scrollOffset + // 0 +---------+ + // | | + // _ | | + // viewport position | | | + // with `descendant` at | | | _ + // trailing edge |_ | xxxxxxx | | viewport position + // | | | with `descendant` at + // | | _| leading edge + // | | + // 800 +---------+ + // + // `trailingEdgeOffset`: Distance from scrollOffset 0 to the start of the + // viewport on the left in image above. + // `leadingEdgeOffset`: Distance from scrollOffset 0 to the start of the + // viewport on the right in image above. + // + // The viewport position on the left is achieved by setting `offset.pixels` + // to `trailingEdgeOffset`, the one on the right by setting it to + // `leadingEdgeOffset`. + final bool inverted = leadingEdgeOffset.offset < trailingEdgeOffset.offset; + final RevealedOffset smaller; + final RevealedOffset larger; + (smaller, larger) = inverted + ? (leadingEdgeOffset, trailingEdgeOffset) + : (trailingEdgeOffset, leadingEdgeOffset); + if (currentOffset > larger.offset) { + return larger; + } else if (currentOffset < smaller.offset) { + return smaller; + } else { + return null; + } + } + @override String toString() { return '${objectRuntimeType(this, 'RevealedOffset')}(offset: $offset, rect: $rect)'; @@ -753,7 +815,17 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix } @override - RevealedOffset getOffsetToReveal(RenderObject target, double alignment, { Rect? rect }) { + RevealedOffset getOffsetToReveal( + RenderObject target, + double alignment, { + Rect? rect, + Axis? axis, + }) { + // One dimensional viewport has only one axis, it should match if it has + // been provided. + axis ??= this.axis; + assert(axis == this.axis); + // Steps to convert `rect` (from a RenderBox coordinate system) to its // scroll offset within this viewport (not in the exact order): // @@ -1164,44 +1236,12 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix final RevealedOffset leadingEdgeOffset = viewport.getOffsetToReveal(descendant, 0.0, rect: rect); final RevealedOffset trailingEdgeOffset = viewport.getOffsetToReveal(descendant, 1.0, rect: rect); final double currentOffset = offset.pixels; - - // scrollOffset - // 0 +---------+ - // | | - // _ | | - // viewport position | | | - // with `descendant` at | | | _ - // trailing edge |_ | xxxxxxx | | viewport position - // | | | with `descendant` at - // | | _| leading edge - // | | - // 800 +---------+ - // - // `trailingEdgeOffset`: Distance from scrollOffset 0 to the start of the - // viewport on the left in image above. - // `leadingEdgeOffset`: Distance from scrollOffset 0 to the start of the - // viewport on the right in image above. - // - // The viewport position on the left is achieved by setting `offset.pixels` - // to `trailingEdgeOffset`, the one on the right by setting it to - // `leadingEdgeOffset`. - - final RevealedOffset targetOffset; - if (leadingEdgeOffset.offset < trailingEdgeOffset.offset) { - // `descendant` is too big to be visible on screen in its entirety. Let's - // align it with the edge that requires the least amount of scrolling. - final double leadingEdgeDiff = (offset.pixels - leadingEdgeOffset.offset).abs(); - final double trailingEdgeDiff = (offset.pixels - trailingEdgeOffset.offset).abs(); - targetOffset = leadingEdgeDiff < trailingEdgeDiff ? leadingEdgeOffset : trailingEdgeOffset; - } else if (currentOffset > leadingEdgeOffset.offset) { - // `descendant` currently starts above the leading edge and can be shown - // fully on screen by scrolling down (which means: moving viewport up). - targetOffset = leadingEdgeOffset; - } else if (currentOffset < trailingEdgeOffset.offset) { - // `descendant currently ends below the trailing edge and can be shown - // fully on screen by scrolling up (which means: moving viewport down) - targetOffset = trailingEdgeOffset; - } else { + final RevealedOffset? targetOffset = RevealedOffset.clampOffset( + leadingEdgeOffset: leadingEdgeOffset, + trailingEdgeOffset: trailingEdgeOffset, + currentOffset: currentOffset, + ); + if (targetOffset == null) { // `descendant` is between leading and trailing edge and hence already // fully shown on screen. No action necessary. assert(viewport.parent != null); @@ -1209,7 +1249,6 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix return MatrixUtils.transformRect(transform, rect ?? descendant.paintBounds); } - offset.moveTo(targetOffset.offset, duration: duration, curve: curve); return targetOffset.rect; } diff --git a/packages/flutter/lib/src/widgets/scroll_position.dart b/packages/flutter/lib/src/widgets/scroll_position.dart index 6311b1aae493c..e1ec77eae2b78 100644 --- a/packages/flutter/lib/src/widgets/scroll_position.dart +++ b/packages/flutter/lib/src/widgets/scroll_position.dart @@ -810,14 +810,32 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { double target; switch (_applyAxisDirectionToAlignmentPolicy(alignmentPolicy)) { case ScrollPositionAlignmentPolicy.explicit: - target = clampDouble(viewport.getOffsetToReveal(object, alignment, rect: targetRect).offset, minScrollExtent, maxScrollExtent); + target = viewport.getOffsetToReveal( + object, + alignment, + rect: targetRect, + axis: axis, + ).offset; + target = clampDouble(target, minScrollExtent, maxScrollExtent); case ScrollPositionAlignmentPolicy.keepVisibleAtEnd: - target = clampDouble(viewport.getOffsetToReveal(object, 1.0, rect: targetRect).offset, minScrollExtent, maxScrollExtent); + target = viewport.getOffsetToReveal( + object, + 1.0, // Aligns to end + rect: targetRect, + axis: axis, + ).offset; + target = clampDouble(target, minScrollExtent, maxScrollExtent); if (target < pixels) { target = pixels; } case ScrollPositionAlignmentPolicy.keepVisibleAtStart: - target = clampDouble(viewport.getOffsetToReveal(object, 0.0, rect: targetRect).offset, minScrollExtent, maxScrollExtent); + target = viewport.getOffsetToReveal( + object, + 0.0, // Aligns to start + rect: targetRect, + axis: axis, + ).offset; + target = clampDouble(target, minScrollExtent, maxScrollExtent); if (target > pixels) { target = pixels; } diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index 88bd115771451..e017d77aa44b1 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -44,6 +44,13 @@ typedef ViewportBuilder = Widget Function(BuildContext context, ViewportOffset p /// which the scrollable content is displayed. typedef TwoDimensionalViewportBuilder = Widget Function(BuildContext context, ViewportOffset verticalPosition, ViewportOffset horizontalPosition); +// The return type of _performEnsureVisible. +// +// The list of futures represents each pending ScrollPosition call to +// ensureVisible. The returned ScrollableState's context is used to find the +// next potential ancestor Scrollable. +typedef _EnsureVisibleResults = (List<Future<void>>, ScrollableState); + /// A widget that manages scrolling in one dimension and informs the [Viewport] /// through which the content is viewed. /// @@ -441,6 +448,10 @@ class Scrollable extends StatefulWidget { /// Scrolls the scrollables that enclose the given context so as to make the /// given context visible. + /// + /// If the [Scrollable] of the provided [BuildContext] is a + /// [TwoDimensionalScrollable], both vertical and horizontal axes will ensure + /// the target is made visible. static Future<void> ensureVisible( BuildContext context, { double alignment = 0.0, @@ -459,14 +470,16 @@ class Scrollable extends StatefulWidget { RenderObject? targetRenderObject; ScrollableState? scrollable = Scrollable.maybeOf(context); while (scrollable != null) { - futures.add(scrollable.position.ensureVisible( + final List<Future<void>> newFutures; + (newFutures, scrollable) = scrollable._performEnsureVisible( context.findRenderObject()!, alignment: alignment, duration: duration, curve: curve, alignmentPolicy: alignmentPolicy, targetRenderObject: targetRenderObject, - )); + ); + futures.addAll(newFutures); targetRenderObject = targetRenderObject ?? context.findRenderObject(); context = scrollable.context; @@ -1011,6 +1024,28 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R return result; } + // Returns the Future from calling ensureVisible for the ScrollPosition, as + // as well as this ScrollableState instance so its context can be used to + // check for other ancestor Scrollables in executing ensureVisible. + _EnsureVisibleResults _performEnsureVisible( + RenderObject object, { + double alignment = 0.0, + Duration duration = Duration.zero, + Curve curve = Curves.ease, + ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, + RenderObject? targetRenderObject, + }) { + final Future<void> ensureVisibleFuture = position.ensureVisible( + object, + alignment: alignment, + duration: duration, + curve: curve, + alignmentPolicy: alignmentPolicy, + targetRenderObject: targetRenderObject, + ); + return (<Future<void>>[ ensureVisibleFuture ], this); + } + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); @@ -2040,6 +2075,25 @@ class _VerticalOuterDimension extends Scrollable { class _VerticalOuterDimensionState extends ScrollableState { DiagonalDragBehavior get diagonalDragBehavior => (widget as _VerticalOuterDimension).diagonalDragBehavior; + // Implemented in the _HorizontalInnerDimension instead. + @override + _EnsureVisibleResults _performEnsureVisible( + RenderObject object, { + double alignment = 0.0, + Duration duration = Duration.zero, + Curve curve = Curves.ease, + ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, + RenderObject? targetRenderObject, + }) { + assert( + false, + 'The _performEnsureVisible method was called for the vertical scrollable ' + 'of a TwoDimensionalScrollable. This should not happen as the horizontal ' + 'scrollable handles both axes.' + ); + return (<Future<void>>[], this); + } + @override void setCanDrag(bool value) { switch (diagonalDragBehavior) { @@ -2119,6 +2173,39 @@ class _HorizontalInnerDimensionState extends ScrollableState { super.didChangeDependencies(); } + // Returns the Future from calling ensureVisible for the ScrollPosition, as + // as well as the vertical ScrollableState instance so its context can be + // used to check for other ancestor Scrollables in executing ensureVisible. + @override + _EnsureVisibleResults _performEnsureVisible( + RenderObject object, { + double alignment = 0.0, + Duration duration = Duration.zero, + Curve curve = Curves.ease, + ScrollPositionAlignmentPolicy alignmentPolicy = ScrollPositionAlignmentPolicy.explicit, + RenderObject? targetRenderObject, + }) { + final List<Future<void>> newFutures = <Future<void>>[]; + + newFutures.add(position.ensureVisible( + object, + alignment: alignment, + duration: duration, + curve: curve, + alignmentPolicy: alignmentPolicy, + )); + + newFutures.add(verticalScrollable.position.ensureVisible( + object, + alignment: alignment, + duration: duration, + curve: curve, + alignmentPolicy: alignmentPolicy, + )); + + return (newFutures, verticalScrollable); + } + void _evaluateLockedAxis(Offset offset) { assert(lastDragOffset != null); final Offset offsetDelta = lastDragOffset! - offset; diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index 53cb54846eb76..d4af0def621b7 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -592,7 +592,17 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix } @override - RevealedOffset getOffsetToReveal(RenderObject target, double alignment, { Rect? rect }) { + RevealedOffset getOffsetToReveal( + RenderObject target, + double alignment, { + Rect? rect, + Axis? axis, + }) { + // One dimensional viewport has only one axis, it should match if it has + // been provided. + axis ??= this.axis; + assert(axis == this.axis); + rect ??= target.paintBounds; if (target is! RenderBox) { return RevealedOffset(offset: offset.pixels, rect: rect); diff --git a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart index 282ef44490874..3b3baf1061eb7 100644 --- a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart +++ b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; +import 'package:flutter/animation.dart'; import 'package:flutter/rendering.dart'; import 'framework.dart'; @@ -497,7 +498,6 @@ class TwoDimensionalViewportParentData extends ParentData with KeepAliveParentD /// /// Subclasses should not override [performLayout], as it handles housekeeping /// on either side of the call to [layoutChildSequence]. -// TODO(Piinks): ensureVisible https://github.com/flutter/flutter/issues/126299 abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderAbstractViewport { /// Initializes fields for subclasses. /// @@ -848,11 +848,7 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA RenderBox? child = _firstChild; while (child != null) { final TwoDimensionalViewportParentData childParentData = parentDataOf(child); - // TODO(Piinks): When ensure visible is supported, remove this isVisible - // condition. - if (childParentData.isVisible) { - visitor(child); - } + visitor(child); child = childParentData._nextSibling; } // Do not visit children in [_keepAliveBucket]. @@ -920,10 +916,274 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA } } + @protected + @override + RevealedOffset getOffsetToReveal( + RenderObject target, + double alignment, { + Rect? rect, + Axis? axis, + }) { + // We must know which axis we are revealing for, since RevealedOffset + // refers to only one of two scroll positions. + assert(axis != null); + + final (double offset, AxisDirection axisDirection) = switch (axis!) { + Axis.vertical => (verticalOffset.pixels, verticalAxisDirection), + Axis.horizontal => (horizontalOffset.pixels, horizontalAxisDirection), + }; + + rect ??= target.paintBounds; + // `child` will be the last RenderObject before the viewport when walking + // up from `target`. + RenderObject child = target; + while (child.parent != this) { + child = child.parent!; + } + + assert(child.parent == this); + final RenderBox box = child as RenderBox; + final Rect rectLocal = MatrixUtils.transformRect(target.getTransformTo(child), rect); + + final double targetMainAxisExtent; + double leadingScrollOffset = offset; + // The scroll offset of `rect` within `child`. + switch (axisDirection) { + case AxisDirection.up: + leadingScrollOffset += child.size.height - rectLocal.bottom; + targetMainAxisExtent = rectLocal.height; + case AxisDirection.right: + leadingScrollOffset += rectLocal.left; + targetMainAxisExtent = rectLocal.width; + case AxisDirection.down: + leadingScrollOffset += rectLocal.top; + targetMainAxisExtent = rectLocal.height; + case AxisDirection.left: + leadingScrollOffset += child.size.width - rectLocal.right; + targetMainAxisExtent = rectLocal.width; + } + + // The scroll offset in the viewport to `rect`. + final TwoDimensionalViewportParentData childParentData = parentDataOf(box); + leadingScrollOffset += switch (axisDirection) { + AxisDirection.down => childParentData.paintOffset!.dy, + AxisDirection.up => viewportDimension.height - childParentData.paintOffset!.dy - box.size.height, + AxisDirection.right => childParentData.paintOffset!.dx, + AxisDirection.left => viewportDimension.width - childParentData.paintOffset!.dx - box.size.width, + }; + + // This step assumes the viewport's layout is up-to-date, i.e., if + // the position is changed after the last performLayout, the new scroll + // position will not be accounted for. + final Matrix4 transform = target.getTransformTo(this); + Rect targetRect = MatrixUtils.transformRect(transform, rect); + + final double mainAxisExtent = switch (axisDirectionToAxis(axisDirection)) { + Axis.horizontal => viewportDimension.width, + Axis.vertical => viewportDimension.height, + }; + + final double targetOffset = leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment; + + final double offsetDifference = switch (axisDirectionToAxis(axisDirection)){ + Axis.vertical => verticalOffset.pixels - targetOffset, + Axis.horizontal => horizontalOffset.pixels - targetOffset, + }; + switch (axisDirection) { + case AxisDirection.down: + targetRect = targetRect.translate(0.0, offsetDifference); + case AxisDirection.right: + targetRect = targetRect.translate(offsetDifference, 0.0); + case AxisDirection.up: + targetRect = targetRect.translate(0.0, -offsetDifference); + case AxisDirection.left: + targetRect = targetRect.translate(-offsetDifference, 0.0); + } + + final RevealedOffset revealedOffset = RevealedOffset( + offset: targetOffset, + rect: targetRect, + ); + return revealedOffset; + } + @override - RevealedOffset getOffsetToReveal(RenderObject target, double alignment, { Rect? rect }) { - // TODO(Piinks): Add this back in follow up change (ensureVisible), https://github.com/flutter/flutter/issues/126299 - return const RevealedOffset(offset: 0.0, rect: Rect.zero); + void showOnScreen({ + RenderObject? descendant, + Rect? rect, + Duration duration = Duration.zero, + Curve curve = Curves.ease, + }) { + // It is possible for one and not both axes to allow for implicit scrolling, + // so handling is split between the options for allowed implicit scrolling. + final bool allowHorizontal = horizontalOffset.allowImplicitScrolling; + final bool allowVertical = verticalOffset.allowImplicitScrolling; + AxisDirection? axisDirection; + switch ((allowHorizontal, allowVertical)) { + case (true, true): + // Both allow implicit scrolling. + break; + case (false, true): + // Only the vertical Axis allows implicit scrolling. + axisDirection = verticalAxisDirection; + case (true, false): + // Only the horizontal Axis allows implicit scrolling. + axisDirection = horizontalAxisDirection; + case (false, false): + // Neither axis allows for implicit scrolling. + return super.showOnScreen( + descendant: descendant, + rect: rect, + duration: duration, + curve: curve, + ); + } + + final Rect? newRect = RenderTwoDimensionalViewport.showInViewport( + descendant: descendant, + viewport: this, + axisDirection: axisDirection, + rect: rect, + duration: duration, + curve: curve, + ); + + super.showOnScreen( + rect: newRect, + duration: duration, + curve: curve, + ); + } + + /// Make (a portion of) the given `descendant` of the given `viewport` fully + /// visible in one or both dimensions of the `viewport` by manipulating the + /// [ViewportOffset]s. + /// + /// The `axisDirection` determines from which axes the `descendant` will be + /// revealed. When the `axisDirection` is null, both axes will be updated to + /// reveal the descendant. + /// + /// The optional `rect` parameter describes which area of the `descendant` + /// should be shown in the viewport. If `rect` is null, the entire + /// `descendant` will be revealed. The `rect` parameter is interpreted + /// relative to the coordinate system of `descendant`. + /// + /// The returned [Rect] describes the new location of `descendant` or `rect` + /// in the viewport after it has been revealed. See [RevealedOffset.rect] + /// for a full definition of this [Rect]. + /// + /// The parameter `viewport` is required and cannot be null. If `descendant` + /// is null, this is a no-op and `rect` is returned. + /// + /// If both `descendant` and `rect` are null, null is returned because there + /// is nothing to be shown in the viewport. + /// + /// The `duration` parameter can be set to a non-zero value to animate the + /// target object into the viewport with an animation defined by `curve`. + /// + /// See also: + /// + /// * [RenderObject.showOnScreen], overridden by + /// [RenderTwoDimensionalViewport] to delegate to this method. + static Rect? showInViewport({ + RenderObject? descendant, + Rect? rect, + required RenderTwoDimensionalViewport viewport, + Duration duration = Duration.zero, + Curve curve = Curves.ease, + AxisDirection? axisDirection, + }) { + if (descendant == null) { + return rect; + } + + Rect? showVertical(Rect? rect) { + return RenderTwoDimensionalViewport._showInViewportForAxisDirection( + descendant: descendant, + viewport: viewport, + axis: Axis.vertical, + rect: rect, + duration: duration, + curve: curve, + ); + } + + Rect? showHorizontal(Rect? rect) { + return RenderTwoDimensionalViewport._showInViewportForAxisDirection( + descendant: descendant, + viewport: viewport, + axis: Axis.horizontal, + rect: rect, + duration: duration, + curve: curve, + ); + } + + switch (axisDirection) { + case AxisDirection.left: + case AxisDirection.right: + return showHorizontal(rect); + case AxisDirection.up: + case AxisDirection.down: + return showVertical(rect); + case null: + // Update rect after revealing in one axis before revealing in the next. + rect = showHorizontal(rect) ?? rect; + // We only return the final rect after both have been revealed. + rect = showVertical(rect); + if (rect == null) { + // `descendant` is between leading and trailing edge and hence already + // fully shown on screen. + assert(viewport.parent != null); + final Matrix4 transform = descendant.getTransformTo(viewport.parent); + return MatrixUtils.transformRect( + transform, + rect ?? descendant.paintBounds, + ); + } + return rect; + } + } + + static Rect? _showInViewportForAxisDirection({ + required RenderObject descendant, + Rect? rect, + required RenderTwoDimensionalViewport viewport, + required Axis axis, + Duration duration = Duration.zero, + Curve curve = Curves.ease, + }) { + final ViewportOffset offset = switch (axis) { + Axis.vertical => viewport.verticalOffset, + Axis.horizontal => viewport.horizontalOffset, + }; + + final RevealedOffset leadingEdgeOffset = viewport.getOffsetToReveal( + descendant, + 0.0, + rect: rect, + axis: axis, + ); + final RevealedOffset trailingEdgeOffset = viewport.getOffsetToReveal( + descendant, + 1.0, + rect: rect, + axis: axis, + ); + final double currentOffset = offset.pixels; + + final RevealedOffset? targetOffset = RevealedOffset.clampOffset( + leadingEdgeOffset: leadingEdgeOffset, + trailingEdgeOffset: trailingEdgeOffset, + currentOffset: currentOffset, + ); + if (targetOffset == null) { + // Already visible in this axis. + return null; + } + + offset.moveTo(targetOffset.offset, duration: duration, curve: curve); + return targetOffset.rect; } /// Should be used by subclasses to invalidate any cached metrics for the diff --git a/packages/flutter/test/widgets/ensure_visible_test.dart b/packages/flutter/test/widgets/ensure_visible_test.dart index 329388ee11a88..97898ca632f71 100644 --- a/packages/flutter/test/widgets/ensure_visible_test.dart +++ b/packages/flutter/test/widgets/ensure_visible_test.dart @@ -9,6 +9,8 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; +import 'two_dimensional_utils.dart'; + Finder findKey(int i) => find.byKey(ValueKey<int>(i), skipOffstage: false); Widget buildSingleChildScrollView(Axis scrollDirection, { bool reverse = false }) { @@ -1051,4 +1053,279 @@ void main() { expect(tester.getTopLeft(findKey(-3)).dy, equals(100.0)); }); }); + + group('TwoDimensionalViewport ensureVisible', () { + Finder findKey(ChildVicinity vicinity) { + return find.byKey(ValueKey<ChildVicinity>(vicinity)); + } + + BuildContext findContext(WidgetTester tester, ChildVicinity vicinity) { + return tester.element(findKey(vicinity)); + } + + testWidgets('Axis.vertical', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 0)), + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(0.0), + ); + // (0, 3) is in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(600.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 3)), + ); + await tester.pump(); + // Now in view at top edge of viewport + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(0.0), + ); + + // If already visible, no change + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 3)), + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(0.0), + ); + }); + + testWidgets('Axis.horizontal', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 1, yIndex: 0)), + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 1, yIndex: 0))).dx, + equals(0.0), + ); + // (5, 0) is now in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 5, yIndex: 0))).dx, + equals(800.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 5, yIndex: 0)), + alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd, + ); + await tester.pump(); + // Now in view at trailing edge of viewport + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 5, yIndex: 0))).dx, + equals(600.0), + ); + + // If already in position, no change + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 5, yIndex: 0)), + alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd, + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 5, yIndex: 0))).dx, + equals(600.0), + ); + }); + + testWidgets('both axes', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 1, yIndex: 1)), + ); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 1, yIndex: 1))), + const Rect.fromLTRB(0.0, 0.0, 200.0, 200.0), + ); + // (5, 4) is in the cache extent, and will be brought into view next + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(800.0, 600.0, 1000.0, 800.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 5, yIndex: 4)), + alignment: 1.0, // Same as ScrollAlignmentPolicy.keepVisibleAtEnd + ); + await tester.pump(); + // Now in view at bottom trailing corner of viewport + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(600.0, 400.0, 800.0, 600.0), + ); + + // If already visible, no change + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 5, yIndex: 4)), + alignment: 1.0, + ); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(600.0, 400.0, 800.0, 600.0), + ); + }); + + testWidgets('Axis.vertical reverse', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest( + verticalDetails: const ScrollableDetails.vertical(reverse: true), + useCacheExtent: true, + )); + + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(400.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 0)), + ); + await tester.pump(); + // Already visible so no change. + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(400.0), + ); + // (0, 3) is in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(-200.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 3)), + ); + await tester.pump(); + // Now in view at bottom edge of viewport since we are reversed + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(400.0), + ); + + // If already visible, no change + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 3)), + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(400.0), + ); + }); + + testWidgets('Axis.horizontal reverse', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest( + horizontalDetails: const ScrollableDetails.horizontal(reverse: true), + useCacheExtent: true, + )); + + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dx, + equals(600.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 0, yIndex: 0)), + ); + await tester.pump(); + // Already visible so no change. + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dx, + equals(600.0), + ); + // (4, 0) is in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 4, yIndex: 0))).dx, + equals(-200.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 4, yIndex: 0)), + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 4, yIndex: 0))).dx, + equals(200.0), + ); + + // If already visible, no change + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 4, yIndex: 0)), + ); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 4, yIndex: 0))).dx, + equals(200.0), + ); + }); + + testWidgets('both axes reverse', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest( + verticalDetails: const ScrollableDetails.vertical(reverse: true), + horizontalDetails: const ScrollableDetails.horizontal(reverse: true), + useCacheExtent: true, + )); + + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 1, yIndex: 1)), + ); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 1, yIndex: 1))), + const Rect.fromLTRB(600.0, 400.0, 800.0, 600.0), + ); + // (5, 4) is in the cache extent, and will be brought into view next + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(-200.0, -200.0, 0.0, 0.0), + ); + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 5, yIndex: 4)), + alignment: 1.0, // Same as ScrollAlignmentPolicy.keepVisibleAtEnd + ); + await tester.pump(); + // Now in view at trailing corner of viewport + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(0.0, 0.0, 200.0, 200.0), + ); + + // If already visible, no change + Scrollable.ensureVisible(findContext( + tester, + const ChildVicinity(xIndex: 5, yIndex: 4)), + alignment: 1.0, + ); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(0.0, 0.0, 200.0, 200.0), + ); + }); + }); } diff --git a/packages/flutter/test/widgets/two_dimensional_utils.dart b/packages/flutter/test/widgets/two_dimensional_utils.dart index d2cbf3b8883a7..a518f52170a13 100644 --- a/packages/flutter/test/widgets/two_dimensional_utils.dart +++ b/packages/flutter/test/widgets/two_dimensional_utils.dart @@ -17,6 +17,7 @@ final TwoDimensionalChildBuilderDelegate builderDelegate = TwoDimensionalChildBu maxYIndex: 5, builder: (BuildContext context, ChildVicinity vicinity) { return Container( + key: ValueKey<ChildVicinity>(vicinity), color: vicinity.xIndex.isEven && vicinity.yIndex.isEven ? Colors.amber[100] : (vicinity.xIndex.isOdd && vicinity.yIndex.isOdd diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index 8063ea0d1a690..1d10521d91395 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -2365,6 +2365,275 @@ void main() { ), ); }, variant: TargetPlatformVariant.all()); + + group('TwoDimensionalViewport showOnScreen & showInViewport', () { + Finder findKey(ChildVicinity vicinity) { + return find.byKey(ValueKey<ChildVicinity>(vicinity)); + } + + testWidgets('Axis.vertical', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + // Child visible at origin + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(0.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(0.0), + ); + // (0, 3) is in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(600.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 3)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Now in view + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(400.0), + ); + + // If already visible, no change + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 3)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(400.0), + ); + }); + + testWidgets('Axis.horizontal', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 1, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 1, yIndex: 0))).dx, + equals(200.0), // No change since already fully visible + ); + // (5, 0) is now in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 5, yIndex: 0))).dx, + equals(1000.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 5, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Now in view + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 5, yIndex: 0))).dx, + equals(600.0), + ); + + // If already in position, no change + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 5, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 5, yIndex: 0))).dx, + equals(600.0), + ); + }); + + testWidgets('both axes', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 1, yIndex: 1)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 1, yIndex: 1))), + const Rect.fromLTRB(200.0, 200.0, 400.0, 400.0), + ); + // (5, 4) is in the cache extent, and will be brought into view next + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(1000.0, 800.0, 1200.0, 1000.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 5, yIndex: 4)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Now in view + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(600.0, 200.0, 800.0, 400.0), + ); + + // If already visible, no change + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 5, yIndex: 4)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(600.0, 200.0, 800.0, 400.0), + ); + }); + + testWidgets('Axis.vertical reverse', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest( + verticalDetails: const ScrollableDetails.vertical(reverse: true), + useCacheExtent: true, + )); + + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(400.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Already visible so no change. + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dy, + equals(400.0), + ); + // (0, 3) is in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(-200.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 3)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Now in view + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(0.0), + ); + + // If already visible, no change + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 3)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 3))).dy, + equals(0.0), + ); + }); + + testWidgets('Axis.horizontal reverse', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest( + horizontalDetails: const ScrollableDetails.horizontal(reverse: true), + useCacheExtent: true, + )); + + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dx, + equals(600.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 0, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Already visible so no change. + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 0, yIndex: 0))).dx, + equals(600.0), + ); + // (4, 0) is in the cache extent, and will be brought into view next + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 4, yIndex: 0))).dx, + equals(-200.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 4, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 4, yIndex: 0))).dx, + equals(0.0), + ); + + // If already visible, no change + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 4, yIndex: 0)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getTopLeft(findKey(const ChildVicinity(xIndex: 4, yIndex: 0))).dx, + equals(0.0), + ); + }); + + testWidgets('both axes reverse', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest( + verticalDetails: const ScrollableDetails.vertical(reverse: true), + horizontalDetails: const ScrollableDetails.horizontal(reverse: true), + useCacheExtent: true, + )); + + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 1, yIndex: 1)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 1, yIndex: 1))), + const Rect.fromLTRB(400.0, 200.0, 600.0, 400.0), + ); + // (5, 4) is in the cache extent, and will be brought into view next + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(-400.0, -400.0, -200.0, -200.0), + ); + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 5, yIndex: 4)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + // Now in view + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(0.0, 200.0, 200.0, 400.0), + ); + + // If already visible, no change + tester.renderObject(find.byKey( + const ValueKey<ChildVicinity>(ChildVicinity(xIndex: 5, yIndex: 4)), + skipOffstage: false, + )).showOnScreen(); + await tester.pump(); + expect( + tester.getRect(findKey(const ChildVicinity(xIndex: 5, yIndex: 4))), + const Rect.fromLTRB(0.0, 200.0, 200.0, 400.0), + ); + }); + }); }); } From 21ad7122a18174d44fe3da879b225ddbafbc9dce Mon Sep 17 00:00:00 2001 From: Renzo Olivares <rmolivares@renzo-olivares.dev> Date: Wed, 27 Sep 2023 18:42:16 -0700 Subject: [PATCH 1495/1547] Implement SelectionArea single click/tap gestures (#132682) This change collapses the selection at the clicked/tapped location on single click down for desktop platforms, and on single click/tap up for mobile platforms to match native. This is a change from how `SelectionArea` previously worked. Before this change a single click down would clear the selection. From observing a native browser it looks like when tapping on static text the selection is not cleared but collapsed. A user can still attain the selection from static text using the `window.getSelection` API. https://jsfiddle.net/juepasn3/11/ You can try this demo out here to observe this behavior yourself. When clicking on static text the selection will change. This change also allows `Paragraph.selections` to return selections that are collapsed. This for testing purposes to confirm where the selection has been collapsed. Partially fixes: #129583 --- ...ectable_region_toolbar_builder.0_test.dart | 7 +- .../flutter/lib/src/rendering/paragraph.dart | 11 +- .../flutter/lib/src/widgets/scrollable.dart | 4 +- .../lib/src/widgets/selectable_region.dart | 139 ++++++-- .../test/material/selection_area_test.dart | 10 +- .../test/rendering/paragraph_test.dart | 3 +- .../test/widgets/selectable_region_test.dart | 300 ++++++++++++++---- 7 files changed, 375 insertions(+), 99 deletions(-) diff --git a/examples/api/test/material/context_menu/selectable_region_toolbar_builder.0_test.dart b/examples/api/test/material/context_menu/selectable_region_toolbar_builder.0_test.dart index 31b89ee89dd03..a7147873fbe4a 100644 --- a/examples/api/test/material/context_menu/selectable_region_toolbar_builder.0_test.dart +++ b/examples/api/test/material/context_menu/selectable_region_toolbar_builder.0_test.dart @@ -24,6 +24,9 @@ void main() { // Right clicking the Text in the SelectionArea shows the custom context // menu. + final TestGesture primaryMouseButtonGesture = await tester.createGesture( + kind: PointerDeviceKind.mouse, + ); final TestGesture gesture = await tester.startGesture( tester.getCenter(find.text(example.text)), kind: PointerDeviceKind.mouse, @@ -37,7 +40,9 @@ void main() { expect(find.text('Print'), findsOneWidget); // Tap to dismiss. - await tester.tapAt(tester.getCenter(find.byType(Scaffold))); + await primaryMouseButtonGesture.down(tester.getCenter(find.byType(Scaffold))); + await tester.pump(); + await primaryMouseButtonGesture.up(); await tester.pumpAndSettle(); expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 13b17af303388..9ac2d9a499b51 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -132,7 +132,7 @@ mixin RenderInlineChildrenContainerDefaults on RenderBox, ContainerRenderObjectM ui.PlaceholderAlignment.belowBaseline || ui.PlaceholderAlignment.bottom || ui.PlaceholderAlignment.middle || - ui.PlaceholderAlignment.top => null, + ui.PlaceholderAlignment.top => null, ui.PlaceholderAlignment.baseline => child.getDistanceToBaseline(span.baseline!), }, ); @@ -351,8 +351,7 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo final List<TextSelection> results = <TextSelection>[]; for (final _SelectableFragment fragment in _lastSelectableFragments!) { if (fragment._textSelectionStart != null && - fragment._textSelectionEnd != null && - fragment._textSelectionStart!.offset != fragment._textSelectionEnd!.offset) { + fragment._textSelectionEnd != null) { results.add( TextSelection( baseOffset: fragment._textSelectionStart!.offset, @@ -1309,9 +1308,9 @@ class RenderParagraph extends RenderBox with ContainerRenderObjectMixin<RenderBo /// A continuous, selectable piece of paragraph. /// -/// Since the selections in [PlaceHolderSpan] are handled independently in its +/// Since the selections in [PlaceholderSpan] are handled independently in its /// subtree, a selection in [RenderParagraph] can't continue across a -/// [PlaceHolderSpan]. The [RenderParagraph] splits itself on [PlaceHolderSpan] +/// [PlaceholderSpan]. The [RenderParagraph] splits itself on [PlaceholderSpan] /// to create multiple `_SelectableFragment`s so that they can be selected /// separately. class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutMetrics { @@ -1720,7 +1719,7 @@ class _SelectableFragment with Selectable, ChangeNotifier implements TextLayoutM _selectableContainsOriginWord = true; final TextPosition position = paragraph.getPositionForOffset(paragraph.globalToLocal(globalPosition)); - if (_positionIsWithinCurrentSelection(position)) { + if (_positionIsWithinCurrentSelection(position) && _textSelectionStart != _textSelectionEnd) { return SelectionResult.end; } final _WordBoundaryRecord wordBoundary = _getWordBoundaryAtPosition(position); diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index e017d77aa44b1..86c350401d4b6 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -670,7 +670,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R if (oldWidget.controller == null) { // The old controller was null, meaning the fallback cannot be null. // Dispose of the fallback. - assert(_fallbackScrollController != null); + assert(_fallbackScrollController != null); assert(widget.controller != null); _fallbackScrollController!.detach(position); _fallbackScrollController!.dispose(); @@ -1954,7 +1954,7 @@ class TwoDimensionalScrollableState extends State<TwoDimensionalScrollable> { if (oldWidget.horizontalDetails.controller == null) { // The old controller was null, meaning the fallback cannot be null. // Dispose of the fallback. - assert(_horizontalFallbackController != null); + assert(_horizontalFallbackController != null); assert(widget.horizontalDetails.controller != null); _horizontalFallbackController!.dispose(); _horizontalFallbackController = null; diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 4b972c081e311..70369b8b3a08e 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -352,7 +352,8 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe _showToolbar(location: details.globalPosition); } } else { - _clearSelection(); + hideToolbar(); + _collapseSelectionAt(offset: details.globalPosition); } }; instance.onSecondaryTapDown = _handleRightClickDown; @@ -472,6 +473,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe (TapAndPanGestureRecognizer instance) { instance ..onTapDown = _startNewMouseSelectionGesture + ..onTapUp = _handleMouseTapUp ..onDragStart = _handleMouseDragStart ..onDragUpdate = _handleMouseDragUpdate ..onDragEnd = _handleMouseDragEnd @@ -498,7 +500,17 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe case 1: widget.focusNode.requestFocus(); hideToolbar(); - _clearSelection(); + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.iOS: + // On mobile platforms the selection is set on tap up. + break; + case TargetPlatform.macOS: + case TargetPlatform.linux: + case TargetPlatform.windows: + _collapseSelectionAt(offset: details.globalPosition); + } case 2: _selectWordAt(offset: details.globalPosition); } @@ -528,6 +540,24 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe _updateSelectedContentIfNeeded(); } + void _handleMouseTapUp(TapDragUpDetails details) { + switch (_getEffectiveConsecutiveTapCount(details.consecutiveTapCount)) { + case 1: + switch (defaultTargetPlatform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.iOS: + _collapseSelectionAt(offset: details.globalPosition); + case TargetPlatform.macOS: + case TargetPlatform.linux: + case TargetPlatform.windows: + // On desktop platforms the selection is set on tap down. + break; + } + } + _updateSelectedContentIfNeeded(); + } + void _updateSelectedContentIfNeeded() { if (_lastSelectedContent?.plainText != _selectable?.getSelectedContent()?.plainText) { _lastSelectedContent = _selectable?.getSelectedContent(); @@ -586,8 +616,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe // keep the current selection, if not then collapse it. final bool lastSecondaryTapDownPositionWasOnActiveSelection = _positionIsOnActiveSelection(globalPosition: details.globalPosition); if (!lastSecondaryTapDownPositionWasOnActiveSelection) { - _selectStartTo(offset: lastSecondaryTapDownPosition!); - _selectEndTo(offset: lastSecondaryTapDownPosition!); + _collapseSelectionAt(offset: lastSecondaryTapDownPosition!); } _showHandles(); _showToolbar(location: lastSecondaryTapDownPosition); @@ -612,8 +641,7 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe // keep the current selection, if not then collapse it. final bool lastSecondaryTapDownPositionWasOnActiveSelection = _positionIsOnActiveSelection(globalPosition: details.globalPosition); if (!lastSecondaryTapDownPositionWasOnActiveSelection) { - _selectStartTo(offset: lastSecondaryTapDownPosition!); - _selectEndTo(offset: lastSecondaryTapDownPosition!); + _collapseSelectionAt(offset: lastSecondaryTapDownPosition!); } _showHandles(); _showToolbar(location: lastSecondaryTapDownPosition); @@ -925,8 +953,9 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe /// See also: /// * [_selectStartTo], which sets or updates selection start edge. /// * [_finalizeSelection], which stops the `continuous` updates. - /// * [_clearSelection], which clear the ongoing selection. + /// * [_clearSelection], which clears the ongoing selection. /// * [_selectWordAt], which selects a whole word at the location. + /// * [_collapseSelectionAt], which collapses the selection at the location. /// * [selectAll], which selects the entire content. void _selectEndTo({required Offset offset, bool continuous = false, TextGranularity? textGranularity}) { if (!continuous) { @@ -964,8 +993,9 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe /// See also: /// * [_selectEndTo], which sets or updates selection end edge. /// * [_finalizeSelection], which stops the `continuous` updates. - /// * [_clearSelection], which clear the ongoing selection. + /// * [_clearSelection], which clears the ongoing selection. /// * [_selectWordAt], which selects a whole word at the location. + /// * [_collapseSelectionAt], which collapses the selection at the location. /// * [selectAll], which selects the entire content. void _selectStartTo({required Offset offset, bool continuous = false, TextGranularity? textGranularity}) { if (!continuous) { @@ -978,6 +1008,20 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe } } + /// Collapses the selection at the given `offset` location. + /// + /// See also: + /// * [_selectStartTo], which sets or updates selection start edge. + /// * [_selectEndTo], which sets or updates selection end edge. + /// * [_finalizeSelection], which stops the `continuous` updates. + /// * [_clearSelection], which clears the ongoing selection. + /// * [_selectWordAt], which selects a whole word at the location. + /// * [selectAll], which selects the entire content. + void _collapseSelectionAt({required Offset offset}) { + _selectStartTo(offset: offset); + _selectEndTo(offset: offset); + } + /// Selects a whole word at the `offset` location. /// /// If the whole word is already in the current selection, selection won't @@ -991,7 +1035,8 @@ class SelectableRegionState extends State<SelectableRegion> with TextSelectionDe /// * [_selectStartTo], which sets or updates selection start edge. /// * [_selectEndTo], which sets or updates selection end edge. /// * [_finalizeSelection], which stops the `continuous` updates. - /// * [_clearSelection], which clear the ongoing selection. + /// * [_clearSelection], which clears the ongoing selection. + /// * [_collapseSelectionAt], which collapses the selection at the location. /// * [selectAll], which selects the entire content. void _selectWordAt({required Offset offset}) { // There may be other selection ongoing. @@ -1881,7 +1926,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai SelectionPoint? startPoint; if (startGeometry.startSelectionPoint != null) { - final Matrix4 startTransform = getTransformFrom(selectables[startIndexWalker]); + final Matrix4 startTransform = getTransformFrom(selectables[startIndexWalker]); final Offset start = MatrixUtils.transformPoint(startTransform, startGeometry.startSelectionPoint!.localPosition); // It can be NaN if it is detached or off-screen. if (start.isFinite) { @@ -1902,7 +1947,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai } SelectionPoint? endPoint; if (endGeometry.endSelectionPoint != null) { - final Matrix4 endTransform = getTransformFrom(selectables[endIndexWalker]); + final Matrix4 endTransform = getTransformFrom(selectables[endIndexWalker]); final Offset end = MatrixUtils.transformPoint(endTransform, endGeometry.endSelectionPoint!.localPosition); // It can be NaN if it is detached or off-screen. if (end.isFinite) { @@ -1986,8 +2031,8 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai final Rect? drawableArea = hasSize ? Rect .fromLTWH(0, 0, containerSize.width, containerSize.height) .inflate(_kSelectionHandleDrawableAreaPadding) : null; - final bool hideStartHandle = value.startSelectionPoint == null || drawableArea == null || !drawableArea.contains(value.startSelectionPoint!.localPosition); - final bool hideEndHandle = value.endSelectionPoint == null || drawableArea == null|| !drawableArea.contains(value.endSelectionPoint!.localPosition); + final bool hideStartHandle = value.startSelectionPoint == null || drawableArea == null || !drawableArea.contains(value.startSelectionPoint!.localPosition); + final bool hideEndHandle = value.endSelectionPoint == null || drawableArea == null|| !drawableArea.contains(value.endSelectionPoint!.localPosition); effectiveStartHandle = hideStartHandle ? null : _startHandleLayer; effectiveEndHandle = hideEndHandle ? null : _endHandleLayer; } @@ -2047,6 +2092,34 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai ); } + // Clears the selection on all selectables not in the range of + // currentSelectionStartIndex..currentSelectionEndIndex. + // + // If one of the edges does not exist, then this method will clear the selection + // in all selectables except the existing edge. + // + // If neither of the edges exist this method immediately returns. + void _flushInactiveSelections() { + if (currentSelectionStartIndex == -1 && currentSelectionEndIndex == -1) { + return; + } + if (currentSelectionStartIndex == -1 || currentSelectionEndIndex == -1) { + final int skipIndex = currentSelectionStartIndex == -1 ? currentSelectionEndIndex : currentSelectionStartIndex; + selectables + .where((Selectable target) => target != selectables[skipIndex]) + .forEach((Selectable target) => dispatchSelectionEventToChild(target, const ClearSelectionEvent())); + return; + } + final int skipStart = min(currentSelectionStartIndex, currentSelectionEndIndex); + final int skipEnd = max(currentSelectionStartIndex, currentSelectionEndIndex); + for (int index = 0; index < selectables.length; index += 1) { + if (index >= skipStart && index <= skipEnd) { + continue; + } + dispatchSelectionEventToChild(selectables[index], const ClearSelectionEvent()); + } + } + /// Selects all contents of all selectables. @protected SelectionResult handleSelectAll(SelectAllSelectionEvent event) { @@ -2290,7 +2363,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai bool hasFoundEdgeIndex = false; SelectionResult? result; for (int index = 0; index < selectables.length && !hasFoundEdgeIndex; index += 1) { - final Selectable child = selectables[index]; + final Selectable child = selectables[index]; final SelectionResult childResult = dispatchSelectionEventToChild(child, event); switch (childResult) { case SelectionResult.next: @@ -2323,6 +2396,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai } else { currentSelectionStartIndex = newIndex; } + _flushInactiveSelections(); // The result can only be null if the loop went through the entire list // without any of the selection returned end or previous. In this case, the // caller of this method needs to find the next selectable in their list. @@ -2345,13 +2419,39 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai return true; }()); SelectionResult? finalResult; - int newIndex = isEnd ? currentSelectionEndIndex : currentSelectionStartIndex; + // Determines if the edge being adjusted is within the current viewport. + // - If so, we begin the search for the new selection edge position at the + // currentSelectionEndIndex/currentSelectionStartIndex. + // - If not, we attempt to locate the new selection edge starting from + // the opposite end. + // - If neither edge is in the current viewport, the search for the new + // selection edge position begins at 0. + // + // This can happen when there is a scrollable child and the edge being adjusted + // has been scrolled out of view. + final bool isCurrentEdgeWithinViewport = isEnd ? _selectionGeometry.endSelectionPoint != null : _selectionGeometry.startSelectionPoint != null; + final bool isOppositeEdgeWithinViewport = isEnd ? _selectionGeometry.startSelectionPoint != null : _selectionGeometry.endSelectionPoint != null; + int newIndex = switch ((isEnd, isCurrentEdgeWithinViewport, isOppositeEdgeWithinViewport)) { + (true, true, true) => currentSelectionEndIndex, + (true, true, false) => currentSelectionEndIndex, + (true, false, true) => currentSelectionStartIndex, + (true, false, false) => 0, + (false, true, true) => currentSelectionStartIndex, + (false, true, false) => currentSelectionStartIndex, + (false, false, true) => currentSelectionEndIndex, + (false, false, false) => 0, + }; bool? forward; late SelectionResult currentSelectableResult; - // This loop sends the selection event to the - // currentSelectionEndIndex/currentSelectionStartIndex to determine the - // direction of the search. If the result is `SelectionResult.next`, this - // loop look backward. Otherwise, it looks forward. + // This loop sends the selection event to one of the following to determine + // the direction of the search. + // - currentSelectionEndIndex/currentSelectionStartIndex if the current edge + // is in the current viewport. + // - The opposite edge index if the current edge is not in the current viewport. + // - Index 0 if neither edge is in the current viewport. + // + // If the result is `SelectionResult.next`, this loop look backward. + // Otherwise, it looks forward. // // The terminate condition are: // 1. the selectable returns end, pending, none. @@ -2391,6 +2491,7 @@ abstract class MultiSelectableSelectionContainerDelegate extends SelectionContai } else { currentSelectionStartIndex = newIndex; } + _flushInactiveSelections(); return finalResult!; } } diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index 8edb4b68d4bac..521a3ff66eca0 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -224,8 +224,14 @@ void main() { // Backwards selection. await gesture.down(textOffsetToPosition(paragraph, 3)); - await tester.pumpAndSettle(); - expect(content, isNull); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(kDoubleTapTimeout); + expect(content, isNotNull); + expect(content!.plainText, ''); + + await gesture.down(textOffsetToPosition(paragraph, 3)); + await tester.pump(); await gesture.moveTo(textOffsetToPosition(paragraph, 0)); await gesture.up(); await tester.pump(); diff --git a/packages/flutter/test/rendering/paragraph_test.dart b/packages/flutter/test/rendering/paragraph_test.dart index a85d83ae39489..06aa6a151a3d9 100644 --- a/packages/flutter/test/rendering/paragraph_test.dart +++ b/packages/flutter/test/rendering/paragraph_test.dart @@ -978,7 +978,8 @@ void main() { granularity: TextGranularity.word, ), ); - expect(paragraph.selections.length, 0); // how []are you + expect(paragraph.selections.length, 1); // how []are you + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 4)); // Equivalent to sending shift + alt + arrow-left. registrar.selectables[0].dispatchSelectionEvent( diff --git a/packages/flutter/test/widgets/selectable_region_test.dart b/packages/flutter/test/widgets/selectable_region_test.dart index 717ba3d5f1825..4be55348f5d2d 100644 --- a/packages/flutter/test/widgets/selectable_region_test.dart +++ b/packages/flutter/test/widgets/selectable_region_test.dart @@ -281,7 +281,7 @@ void main() { semantics.dispose(); }); - testWidgetsWithLeakTracking('mouse selection always cancels previous selection', (WidgetTester tester) async { + testWidgets('mouse single-click selection collapses the selection', (WidgetTester tester) async { final UniqueKey spy = UniqueKey(); final FocusNode focusNode = FocusNode(); addTearDown(focusNode.dispose); @@ -300,9 +300,14 @@ void main() { final RenderSelectionSpy renderSelectionSpy = tester.renderObject<RenderSelectionSpy>(find.byKey(spy)); final TestGesture gesture = await tester.startGesture(const Offset(200.0, 200.0), kind: PointerDeviceKind.mouse); addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); await tester.pumpAndSettle(); - expect(renderSelectionSpy.events.length, 1); - expect(renderSelectionSpy.events[0], isA<ClearSelectionEvent>()); + expect(renderSelectionSpy.events.length, 2); + expect(renderSelectionSpy.events[0], isA<SelectionEdgeUpdateEvent>()); + expect((renderSelectionSpy.events[0] as SelectionEdgeUpdateEvent).type, SelectionEventType.startEdgeUpdate); + expect(renderSelectionSpy.events[1], isA<SelectionEdgeUpdateEvent>()); + expect((renderSelectionSpy.events[1] as SelectionEdgeUpdateEvent).type, SelectionEventType.endEdgeUpdate); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/102410. testWidgetsWithLeakTracking('touch long press sends select-word event', (WidgetTester tester) async { @@ -474,7 +479,7 @@ void main() { await tester.pump(const Duration(milliseconds: 500)); await gesture.up(); expect( - renderSelectionSpy.events.every((SelectionEvent element) => element is ClearSelectionEvent), + renderSelectionSpy.events.every((SelectionEvent element) => element is SelectionEdgeUpdateEvent), isTrue, ); }); @@ -543,7 +548,7 @@ void main() { }, variant: TargetPlatformVariant.all()); group('SelectionArea integration', () { - testWidgetsWithLeakTracking('mouse can select single text', (WidgetTester tester) async { + testWidgets('mouse can select single text on desktop platforms', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); addTearDown(focusNode.dispose); @@ -574,13 +579,17 @@ void main() { // Check backward selection. await gesture.moveTo(textOffsetToPosition(paragraph, 1)); await tester.pump(); + expect(paragraph.selections.isEmpty, isFalse); expect(paragraph.selections[0], const TextSelection(baseOffset: 2, extentOffset: 1)); // Start a new drag. await gesture.up(); + await tester.pumpAndSettle(); + await gesture.down(textOffsetToPosition(paragraph, 5)); await tester.pumpAndSettle(); - expect(paragraph.selections.isEmpty, isTrue); + expect(paragraph.selections.isEmpty, isFalse); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 5)); // Selecting across line should select to the end. await gesture.moveTo(textOffsetToPosition(paragraph, 5) + const Offset(0.0, 200.0)); @@ -588,7 +597,60 @@ void main() { expect(paragraph.selections[0], const TextSelection(baseOffset: 5, extentOffset: 11)); await gesture.up(); - }); + }, variant: TargetPlatformVariant.desktop()); + + testWidgetsWithLeakTracking('mouse can select single text on mobile platforms', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: focusNode, + selectionControls: materialTextSelectionControls, + child: const Center( + child: Text('How are you'), + ), + ), + ), + ); + final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + + await gesture.moveTo(textOffsetToPosition(paragraph, 4)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 2, extentOffset: 4)); + + await gesture.moveTo(textOffsetToPosition(paragraph, 6)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 2, extentOffset: 6)); + + // Check backward selection. + await gesture.moveTo(textOffsetToPosition(paragraph, 1)); + await tester.pump(); + expect(paragraph.selections.isEmpty, isFalse); + expect(paragraph.selections[0], const TextSelection(baseOffset: 2, extentOffset: 1)); + + // Start a new drag. + await gesture.up(); + await tester.pumpAndSettle(); + + await gesture.down(textOffsetToPosition(paragraph, 5)); + await tester.pumpAndSettle(); + await gesture.moveTo(textOffsetToPosition(paragraph, 6)); + await tester.pump(); + expect(paragraph.selections.isEmpty, isFalse); + expect(paragraph.selections[0], const TextSelection(baseOffset: 5, extentOffset: 6)); + + // Selecting across line should select to the end. + await gesture.moveTo(textOffsetToPosition(paragraph, 5) + const Offset(0.0, 200.0)); + await tester.pump(); + expect(paragraph.selections[0], const TextSelection(baseOffset: 5, extentOffset: 11)); + + await gesture.up(); + }, variant: TargetPlatformVariant.mobile()); testWidgetsWithLeakTracking('mouse can select word-by-word on double click drag', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); @@ -643,7 +705,8 @@ void main() { await gesture.down(textOffsetToPosition(paragraph, 5)); await tester.pump(); await gesture.up(); - expect(paragraph.selections.isEmpty, isTrue); + expect(paragraph.selections.isEmpty, isFalse); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 5)); await tester.pump(kDoubleTapTimeout); // Double-click. @@ -761,13 +824,13 @@ void main() { // Should clear the selection on paragraph 3. expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 12)); expect(paragraph2.selections[0], const TextSelection(baseOffset: 0, extentOffset: 6)); - expect(paragraph3.selections.isEmpty, true); + expect(paragraph3.selections.isEmpty, isTrue); await gesture.moveTo(textOffsetToPosition(paragraph1, 4)); // Should clear the selection on paragraph 2. expect(paragraph1.selections[0], const TextSelection(baseOffset: 0, extentOffset: 7)); - expect(paragraph2.selections.isEmpty, true); - expect(paragraph3.selections.isEmpty, true); + expect(paragraph2.selections.isEmpty, isTrue); + expect(paragraph3.selections.isEmpty, isTrue); await gesture.up(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/125582. @@ -863,6 +926,52 @@ void main() { await gesture.up(); }); + testWidgetsWithLeakTracking('collapsing selection should clear selection of all other selectables', (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + focusNode: focusNode, + selectionControls: materialTextSelectionControls, + child: const Column( + children: <Widget>[ + Text('How are you?'), + Text('Good, and you?'), + Text('Fine, thank you.'), + ], + ), + ), + ), + ); + final RenderParagraph paragraph1 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you?'), matching: find.byType(RichText))); + final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph1, 2), kind: PointerDeviceKind.mouse); + addTearDown(gesture.removePointer); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph1.selections[0], const TextSelection.collapsed(offset: 2)); + + final RenderParagraph paragraph2 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('Good, and you?'), matching: find.byType(RichText))); + await gesture.down(textOffsetToPosition(paragraph2, 5)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + expect(paragraph1.selections.isEmpty, isTrue); + expect(paragraph2.selections[0], const TextSelection.collapsed(offset: 5)); + + final RenderParagraph paragraph3 = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('Fine, thank you.'), matching: find.byType(RichText))); + await gesture.down(textOffsetToPosition(paragraph3, 13)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + + expect(paragraph1.selections.isEmpty, isTrue); + expect(paragraph2.selections.isEmpty, isTrue); + expect(paragraph3.selections[0], const TextSelection.collapsed(offset: 13)); + }); + testWidgetsWithLeakTracking('mouse can work with disabled container', (WidgetTester tester) async { final FocusNode focusNode = FocusNode(); addTearDown(focusNode.dispose); @@ -1108,10 +1217,11 @@ void main() { expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. + // Collapse selection. await tester.tapAt(textOffsetToPosition(paragraph, 9)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + expect(paragraph.selections.isEmpty, isFalse); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 9)); expect(find.byKey(toolbarKey), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), @@ -1151,7 +1261,9 @@ void main() { expect(find.byKey(toolbarKey), findsNothing); final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); + final TestGesture primaryMouseButtonGesture = await tester.createGesture(kind: PointerDeviceKind.mouse); final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2), kind: PointerDeviceKind.mouse, buttons: kSecondaryMouseButton); + addTearDown(primaryMouseButtonGesture.removePointer); addTearDown(gesture.removePointer); await tester.pump(); expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); @@ -1185,10 +1297,14 @@ void main() { expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. - await tester.tapAt(textOffsetToPosition(paragraph, 1)); + // Collapse selection. + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 1)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + await primaryMouseButtonGesture.up(); + await tester.pumpAndSettle(); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 1)); expect(find.byKey(toolbarKey), findsNothing); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }), @@ -1229,6 +1345,8 @@ void main() { final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2), kind: PointerDeviceKind.mouse, buttons: kSecondaryMouseButton); + final TestGesture primaryMouseButtonGesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(primaryMouseButtonGesture.removePointer); addTearDown(gesture.removePointer); await tester.pump(); expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 3)); @@ -1286,10 +1404,14 @@ void main() { expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. - await tester.tapAt(textOffsetToPosition(paragraph, 1)); + // Collapse selection. + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 1)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + await primaryMouseButtonGesture.up(); + await tester.pumpAndSettle(); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 1)); expect(find.byKey(toolbarKey), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.macOS), @@ -1330,21 +1452,24 @@ void main() { final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2), kind: PointerDeviceKind.mouse, buttons: kSecondaryMouseButton); + final TestGesture primaryMouseButtonGesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(primaryMouseButtonGesture.removePointer); addTearDown(gesture.removePointer); await tester.pump(); - // Selection is collapsed so none is reported. - expect(paragraph.selections.isEmpty, true); - await gesture.up(); await tester.pump(); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 2)); expect(buttonTypes.length, 1); expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); expect(find.byKey(toolbarKey), findsOneWidget); await gesture.down(textOffsetToPosition(paragraph, 6)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 6)); await gesture.up(); await tester.pump(); @@ -1355,7 +1480,8 @@ void main() { await gesture.down(textOffsetToPosition(paragraph, 9)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 9)); await gesture.up(); await tester.pump(); @@ -1364,20 +1490,23 @@ void main() { expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. - await tester.tapAt(textOffsetToPosition(paragraph, 1)); + // Collapse selection. + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 1)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + await primaryMouseButtonGesture.up(); + await tester.pumpAndSettle(kDoubleTapTimeout); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 1)); expect(find.byKey(toolbarKey), findsNothing); // Create an uncollapsed selection by dragging. - final TestGesture dragGesture = await tester.startGesture(textOffsetToPosition(paragraph, 0), kind: PointerDeviceKind.mouse); - addTearDown(dragGesture.removePointer); + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 0)); await tester.pump(); - await dragGesture.moveTo(textOffsetToPosition(paragraph, 5)); + await primaryMouseButtonGesture.moveTo(textOffsetToPosition(paragraph, 5)); await tester.pump(); expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 5)); - await dragGesture.up(); + await primaryMouseButtonGesture.up(); await tester.pump(); // Right click on previous selection should not collapse the selection. @@ -1394,13 +1523,18 @@ void main() { await tester.pump(); await gesture.up(); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 7)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. - await tester.tapAt(textOffsetToPosition(paragraph, 1)); + // Collapse selection. + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 1)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + await primaryMouseButtonGesture.up(); + await tester.pumpAndSettle(); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 1)); expect(find.byKey(toolbarKey), findsNothing); }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.windows }), @@ -1441,13 +1575,15 @@ void main() { final RenderParagraph paragraph = tester.renderObject<RenderParagraph>(find.descendant(of: find.text('How are you'), matching: find.byType(RichText))); final TestGesture gesture = await tester.startGesture(textOffsetToPosition(paragraph, 2), kind: PointerDeviceKind.mouse, buttons: kSecondaryMouseButton); + final TestGesture primaryMouseButtonGesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(primaryMouseButtonGesture.removePointer); addTearDown(gesture.removePointer); await tester.pump(); - // Selection is collapsed so none is reported. - expect(paragraph.selections.isEmpty, true); - await gesture.up(); await tester.pump(); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 2)); // Context menu toggled on. expect(buttonTypes.length, 1); @@ -1456,17 +1592,18 @@ void main() { await gesture.down(textOffsetToPosition(paragraph, 6)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); - await gesture.up(); await tester.pump(); + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 2)); - // Context menu toggled off. + // Context menu toggled off. Selection remains the same. expect(find.byKey(toolbarKey), findsNothing); await gesture.down(textOffsetToPosition(paragraph, 9)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 9)); await gesture.up(); await tester.pump(); @@ -1476,19 +1613,22 @@ void main() { expect(buttonTypes, contains(ContextMenuButtonType.selectAll)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. - await tester.tapAt(textOffsetToPosition(paragraph, 1)); + // Collapse selection. + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 1)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + await primaryMouseButtonGesture.up(); + await tester.pumpAndSettle(kDoubleTapTimeout); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 1)); expect(find.byKey(toolbarKey), findsNothing); - final TestGesture dragGesture = await tester.startGesture(textOffsetToPosition(paragraph, 0), kind: PointerDeviceKind.mouse); - addTearDown(dragGesture.removePointer); + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 0)); await tester.pump(); - await dragGesture.moveTo(textOffsetToPosition(paragraph, 5)); + await primaryMouseButtonGesture.moveTo(textOffsetToPosition(paragraph, 5)); await tester.pump(); expect(paragraph.selections[0], const TextSelection(baseOffset: 0, extentOffset: 5)); - await dragGesture.up(); + await primaryMouseButtonGesture.up(); await tester.pump(); // Right click on previous selection should not collapse the selection. @@ -1514,13 +1654,18 @@ void main() { await tester.pump(); await gesture.up(); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 7)); expect(find.byKey(toolbarKey), findsOneWidget); - // Clear selection. - await tester.tapAt(textOffsetToPosition(paragraph, 1)); + // Collapse selection. + await primaryMouseButtonGesture.down(textOffsetToPosition(paragraph, 1)); await tester.pump(); - expect(paragraph.selections.isEmpty, true); + await primaryMouseButtonGesture.up(); + await tester.pumpAndSettle(); + // Selection is collapsed. + expect(paragraph.selections.isEmpty, false); + expect(paragraph.selections[0], const TextSelection.collapsed(offset: 1)); expect(find.byKey(toolbarKey), findsNothing); }, variant: TargetPlatformVariant.only(TargetPlatform.linux), @@ -2414,7 +2559,9 @@ void main() { expect(paragraph1.selections.length, 1); expect(paragraph1.selections[0].start, 2); expect(paragraph1.selections[0].end, 12); - expect(paragraph2.selections.length, 0); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 0); await sendKeyCombination(tester, SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: alt, control: control)); await tester.pump(); @@ -2424,7 +2571,9 @@ void main() { expect(paragraph1.selections.length, 1); expect(paragraph1.selections[0].start, 2); expect(paragraph1.selections[0].end, 8); - expect(paragraph2.selections.length, 0); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 0); }, variant: TargetPlatformVariant.all()); testWidgetsWithLeakTracking('can use keyboard to granularly extend selection - line', (WidgetTester tester) async { @@ -2507,7 +2656,9 @@ void main() { expect(paragraph1.selections.length, 1); expect(paragraph1.selections[0].start, 2); expect(paragraph1.selections[0].end, 12); - expect(paragraph2.selections.length, 0); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 0); await sendKeyCombination(tester, SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, alt: alt, meta: meta)); await tester.pump(); @@ -2594,8 +2745,12 @@ void main() { expect(paragraph1.selections.length, 1); expect(paragraph1.selections[0].start, 0); expect(paragraph1.selections[0].end, 2); - expect(paragraph2.selections.length, 0); - expect(paragraph3.selections.length, 0); + expect(paragraph2.selections.length, 1); + expect(paragraph2.selections[0].start, 0); + expect(paragraph2.selections[0].end, 0); + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 0); + expect(paragraph3.selections[0].end, 0); }, variant: TargetPlatformVariant.all()); testWidgetsWithLeakTracking('can use keyboard to directionally extend selection', (WidgetTester tester) async { @@ -2666,7 +2821,9 @@ void main() { expect(paragraph2.selections.length, 1); expect(paragraph2.selections[0].start, 2); expect(paragraph2.selections[0].end, 6); - expect(paragraph3.selections.length, 0); + expect(paragraph3.selections.length, 1); + expect(paragraph3.selections[0].start, 0); + expect(paragraph3.selections[0].end, 0); await sendKeyCombination(tester, const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true)); await tester.pump(); @@ -3017,8 +3174,14 @@ void main() { // Backwards selection. await mouseGesture.down(textOffsetToPosition(paragraph, 3)); - await tester.pumpAndSettle(); - expect(content, isNull); + await tester.pump(); + await mouseGesture.up(); + await tester.pumpAndSettle(kDoubleTapTimeout); + expect(content, isNotNull); + expect(content!.plainText, ''); + + await mouseGesture.down(textOffsetToPosition(paragraph, 3)); + await tester.pump(); await mouseGesture.moveTo(textOffsetToPosition(paragraph, 0)); await tester.pumpAndSettle(); @@ -3045,9 +3208,10 @@ void main() { // Called on tap. await mouseGesture.down(textOffsetToPosition(paragraph, 0)); await tester.pumpAndSettle(); - expect(content, isNull); await mouseGesture.up(); - await tester.pumpAndSettle(); + await tester.pumpAndSettle(kDoubleTapTimeout); + expect(content, isNotNull); + expect(content!.plainText, ''); // With touch gestures. @@ -3224,7 +3388,7 @@ void main() { expect(paragraph2.selections.length, 1); expect(paragraph2.selections[0].start, 0); expect(paragraph2.selections[0].end, 8); - expect(paragraph3.selections.length, 0); + expect(paragraph3.selections.length, 1); expect(content, isNotNull); expect(content!.plainText, 'w are you?Good, an'); @@ -3233,8 +3397,8 @@ void main() { expect(paragraph1.selections.length, 1); expect(paragraph1.selections[0].start, 2); expect(paragraph1.selections[0].end, 7); - expect(paragraph2.selections.length, 0); - expect(paragraph3.selections.length, 0); + expect(paragraph2.selections.length, 1); + expect(paragraph3.selections.length, 1); expect(content, isNotNull); expect(content!.plainText, 'w are'); @@ -3243,8 +3407,8 @@ void main() { expect(paragraph1.selections.length, 1); expect(paragraph1.selections[0].start, 0); expect(paragraph1.selections[0].end, 2); - expect(paragraph2.selections.length, 0); - expect(paragraph3.selections.length, 0); + expect(paragraph2.selections.length, 1); + expect(paragraph3.selections.length, 1); expect(content, isNotNull); expect(content!.plainText, 'Ho'); }); From f2cf0cc0853f2230ddb4b3e4a55d2deea9cb5dce Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 00:00:46 -0400 Subject: [PATCH 1496/1547] Manual roll Flutter Engine from f70f65f7a622 to be32dcc9117a (31 revisions) (#135637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Manual roll Flutter Engine from f70f65f7a622 to be32dcc9117a (31 revisions) Manual roll requested by jacksongardner@google.com Cannot build log URL because revision "be32dcc9117a" is invalid: Luci builds of "Linux linux_unopt" for be32dcc9117a462760cb52c18d0d050f067f2463 was STARTED 2023-09-28 jacksongardner@google.com Rollback Dart SDK to 3.2.0-119. (flutter/engine#46339) 2023-09-28 1961493+harryterkelsen@users.noreply.github.com [canvaskit] Do not double-apply ImageFilter transform to children (flutter/engine#46336) 2023-09-28 ychris@google.com Reland "Reverts "[ios] Fix app extension not able to find assets from… (flutter/engine#46329) 2023-09-27 47866232+chunhtai@users.noreply.github.com Revert "[Impeller] Fixes stroke path geometry that can draw outside o… (flutter/engine#46334) 2023-09-27 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from jQHACBU4Fi2wMElkm... to U334SygIkffMJVmdu... (flutter/engine#46333) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from 952e8dd66560 to b048b468d641 (1 revision) (flutter/engine#46332) 2023-09-27 jason-simmons@users.noreply.github.com [Impeller] Destroy all per-thread command pools tied to a context before deleting the context (flutter/engine#46286) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from d78aba2524b3 to 952e8dd66560 (1 revision) (flutter/engine#46331) 2023-09-27 jonahwilliams@google.com [Impeller] Match Skia gradient clamping behavior (and document). (flutter/engine#44825) 2023-09-27 skia-flutter-autoroll@skia.org Roll Dart SDK from 97647bb1666b to 80a965ee48ab (1 revision) (flutter/engine#46330) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from ff5474eed6b4 to d78aba2524b3 (3 revisions) (flutter/engine#46327) 2023-09-27 98614782+auto-submit[bot]@users.noreply.github.com Reverts "[ios] Fix app extension not able to find assets from unloaded bundle" (flutter/engine#46328) 2023-09-27 737941+loic-sharma@users.noreply.github.com [Windows] Improve logic to update swap intervals (flutter/engine#46172) 2023-09-27 jonahwilliams@google.com [Impeller] Fallback to no index buffer when tesselation count is large, split up nonZero contours. (flutter/engine#46282) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from 4731ccd6342c to ff5474eed6b4 (1 revision) (flutter/engine#46325) 2023-09-27 jason-simmons@users.noreply.github.com Declare native wrapper classes in Fuchsia packages as base classes (flutter/engine#46305) 2023-09-27 godofredoc@google.com Remove fuchsia from recipes cq. (flutter/engine#46324) 2023-09-27 skia-flutter-autoroll@skia.org Roll Dart SDK from c2a455113e39 to 97647bb1666b (1 revision) (flutter/engine#46323) 2023-09-27 matej.knopp@gmail.com [macOS] Synchronise modifiers from mouse events for RawKeyboard (flutter/engine#46230) 2023-09-27 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from Lg6FR6iDnZeV6y-E8... to 6Y22MutFhgL7ua18F... (flutter/engine#46322) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from 2991bb799d3f to 4731ccd6342c (1 revision) (flutter/engine#46321) 2023-09-27 jason-simmons@users.noreply.github.com Declare native wrapper classes in the GPU package as base classes (flutter/engine#46304) 2023-09-27 jason-simmons@users.noreply.github.com Do not call DrawTextBlob for performance overlay text when using Impeller (flutter/engine#46307) 2023-09-27 kjlubick@users.noreply.github.com Update to use GrDirectContexts::MakeGL (flutter/engine#46308) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from 0f4f31127ac5 to 2991bb799d3f (1 revision) (flutter/engine#46319) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from fc629215398f to 0f4f31127ac5 (1 revision) (flutter/engine#46318) 2023-09-27 skia-flutter-autoroll@skia.org Roll Dart SDK from 6c4eb86ecd25 to c2a455113e39 (1 revision) (flutter/engine#46317) 2023-09-27 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from OMrTgAfDg9PKXTzq0... to jQHACBU4Fi2wMElkm... (flutter/engine#46314) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from 960325c13009 to fc629215398f (1 revision) (flutter/engine#46313) 2023-09-27 skia-flutter-autoroll@skia.org Roll Skia from 76aecbaea259 to 960325c13009 (2 revisions) (flutter/engine#46311) 2023-09-27 skia-flutter-autoroll@skia.org Roll Dart SDK from 7c3588c05f87 to 6c4eb86ecd25 (3 revisions) (flutter/engine#46310) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from Lg6FR6iDnZeV to 6Y22MutFhgL7 fuchsia/sdk/core/mac-amd64 from OMrTgAfDg9PK to U334SygIkffM If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose ... --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 66b1cea933a9a..d342d1483dcba 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -f70f65f7a6229793b2c6e2e32d23cbe9b90108d8 +be32dcc9117a462760cb52c18d0d050f067f2463 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 06243cfed48d8..cd1d12929f239 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -Lg6FR6iDnZeV6y-E8iVqEsPfDyNRkT_ZnJSGtO2OH2UC +6Y22MutFhgL7ua18FzWslqS1baVCAG7l6MuPhp1vEs0C diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index a188d4efa073c..989fb74d7aaa0 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -OMrTgAfDg9PKXTzq02S-SPbjInFqsBoiPrFMP-k3TNYC +U334SygIkffMJVmduVhvR7c4L4qnQHz_9dPjcYKDwEsC From f644e4f4db8d78c401f13afca8de181c0b7547d1 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 01:44:07 -0400 Subject: [PATCH 1497/1547] Manual roll Flutter Engine from be32dcc9117a to 44aef2e61718 (4 revisions) (#135646) Manual roll requested by zra@google.com https://github.com/flutter/engine/compare/be32dcc9117a...44aef2e61718 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from 4441cde55a79 to 704217de51e1 (1 revision) (flutter/engine#46346) 2023-09-28 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Roll Dart SDK from 7c3588c05f87 to 86c577329bf7 (8 revisions)" (flutter/engine#46345) 2023-09-28 skia-flutter-autoroll@skia.org Roll Dart SDK from 7c3588c05f87 to 86c577329bf7 (8 revisions) (flutter/engine#46342) 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from b048b468d641 to 4441cde55a79 (1 revision) (flutter/engine#46341) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d342d1483dcba..bb53e07b73195 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -be32dcc9117a462760cb52c18d0d050f067f2463 +44aef2e61718aef1076ca1bd2080197c2188ff3c From 2cd0b6078de2a4e2c2eb6a857da8fe5958bc7e00 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 02:57:59 -0400 Subject: [PATCH 1498/1547] Roll Flutter Engine from 44aef2e61718 to c47faed53afe (1 revision) (#135647) https://github.com/flutter/engine/compare/44aef2e61718...c47faed53afe 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from 704217de51e1 to f3e5eddda2fa (1 revision) (flutter/engine#46350) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index bb53e07b73195..4972810701ebf 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -44aef2e61718aef1076ca1bd2080197c2188ff3c +c47faed53afe75d827e7782c448030bb1c748200 From 4600b12a7e1c5fa17de32b92e91e8512bc1ce168 Mon Sep 17 00:00:00 2001 From: Taha Tesser <tessertaha@gmail.com> Date: Thu, 28 Sep 2023 11:50:06 +0300 Subject: [PATCH 1499/1547] Update `TextField.style` documentation for Material 3 (#135556) fixes [TextField uses bodyLarge instead of titleMedium as the documentation says ](https://github.com/flutter/flutter/issues/135411) --- packages/flutter/lib/src/material/input_decorator.dart | 1 - packages/flutter/lib/src/material/text_field.dart | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index e429eb8e7740c..80091f426444f 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -2903,7 +2903,6 @@ class InputDecoration { /// {@endtemplate} final TextStyle? errorStyle; - /// The maximum number of lines the [errorText] can occupy. /// /// Defaults to null, which means that the [errorText] will be limited diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index e8ea4289967d8..181be1a631849 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -423,7 +423,12 @@ class TextField extends StatefulWidget { /// /// This text style is also used as the base style for the [decoration]. /// - /// If null, defaults to the `titleMedium` text style from the current [Theme]. + /// If null, [TextTheme.bodyLarge] will be used. When the text field is disabled, + /// [TextTheme.bodyLarge] with an opacity of 0.38 will be used instead. + /// + /// If null and [ThemeData.useMaterial3] is false, [TextTheme.titleMedium] will + /// be used. When the text field is disabled, [TextTheme.titleMedium] with + /// [ThemeData.disabledColor] will be used instead. final TextStyle? style; /// {@macro flutter.widgets.editableText.strutStyle} From 9b335d9f7fca3897fe513c7b953f6920474db218 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 05:26:37 -0400 Subject: [PATCH 1500/1547] Roll Flutter Engine from c47faed53afe to d2540d87fd96 (2 revisions) (#135652) https://github.com/flutter/engine/compare/c47faed53afe...d2540d87fd96 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from 1f4e5c374172 to d410e03a6b9b (1 revision) (flutter/engine#46353) 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from f3e5eddda2fa to 1f4e5c374172 (2 revisions) (flutter/engine#46351) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 4972810701ebf..8d9f0fbc1663e 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -c47faed53afe75d827e7782c448030bb1c748200 +d2540d87fd962627ceccb84f22cc33e461577764 From 09b89f41340041e92b711b4aadcc1d97cc998198 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 06:35:36 -0400 Subject: [PATCH 1501/1547] Roll Flutter Engine from d2540d87fd96 to 937bf0432214 (1 revision) (#135660) https://github.com/flutter/engine/compare/d2540d87fd96...937bf0432214 2023-09-28 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from 6Y22MutFhgL7ua18F... to cu6apvEZ2P6zhishc... (flutter/engine#46355) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from 6Y22MutFhgL7 to cu6apvEZ2P6z If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 8d9f0fbc1663e..1ffd9f57dc6ed 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d2540d87fd962627ceccb84f22cc33e461577764 +937bf0432214091119043cdabb6b9e8a0b94c388 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index cd1d12929f239..96ce318ec1905 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -6Y22MutFhgL7ua18FzWslqS1baVCAG7l6MuPhp1vEs0C +cu6apvEZ2P6zhishcExZHv7qWi62MO8R3JOnclnglFAC From 666d8f80e4236ef35848c9311b619ec5cf529a26 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 08:00:15 -0400 Subject: [PATCH 1502/1547] Roll Flutter Engine from 937bf0432214 to 495955a3b5de (1 revision) (#135665) https://github.com/flutter/engine/compare/937bf0432214...495955a3b5de 2023-09-28 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from U334SygIkffMJVmdu... to 4WW3KRrAbuY7VeGT0... (flutter/engine#46357) Also rolling transitive DEPS: fuchsia/sdk/core/mac-amd64 from U334SygIkffM to 4WW3KRrAbuY7 If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-mac.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 1ffd9f57dc6ed..57f8caa9bcd8f 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -937bf0432214091119043cdabb6b9e8a0b94c388 +495955a3b5de2c2e1b4bf056ea8f8a39bb7f59e7 diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index 989fb74d7aaa0..87ee95f0b4107 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -U334SygIkffMJVmduVhvR7c4L4qnQHz_9dPjcYKDwEsC +4WW3KRrAbuY7VeGT0pBFAQktetsyx-3C0mKMNxCd0uYC From dd341d4295416f559b971fa58583a8efacfd376c Mon Sep 17 00:00:00 2001 From: Callum Moffat <smartercallum@gmail.com> Date: Thu, 28 Sep 2023 09:05:10 -0400 Subject: [PATCH 1503/1547] Upload generated frame-request-pending stats (#135645) These values are generated since https://github.com/flutter/flutter/pull/135279, but I didn't know to add the new keys to this list to get them to upload. Part of https://github.com/flutter/flutter/issues/129150 --- dev/devicelab/lib/tasks/perf_tests.dart | 3 +++ dev/devicelab/test/perf_tests_test.dart | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 1dc73382bfab7..416b43cd37a55 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -1358,6 +1358,9 @@ const List<String> _kCommonScoreKeys = <String>[ '99th_percentile_picture_cache_memory', 'worst_picture_cache_memory', 'old_gen_gc_count', + 'average_frame_request_pending_latency', + '90th_percentile_frame_request_pending_latency', + '99th_percentile_frame_request_pending_latency' ]; /// Measures how long it takes to compile a Flutter app to JavaScript and how diff --git a/dev/devicelab/test/perf_tests_test.dart b/dev/devicelab/test/perf_tests_test.dart index 237cffb1c8013..57a214cc8b770 100644 --- a/dev/devicelab/test/perf_tests_test.dart +++ b/dev/devicelab/test/perf_tests_test.dart @@ -58,6 +58,9 @@ void main() { 'average_vsync_transitions_missed': 1, '90th_percentile_vsync_transitions_missed': 1, '99th_percentile_vsync_transitions_missed': 1, + 'average_frame_request_pending_latency': 0.1, + '90th_percentile_frame_request_pending_latency': 0.1, + '99th_percentile_frame_request_pending_latency': 0.1, }; const String resultFileName = 'fake_result'; void driveCallback(List<String> arguments) { @@ -108,6 +111,9 @@ void main() { '90hz_frame_percentage': 0.4, '120hz_frame_percentage': 0.6, 'illegal_refresh_rate_frame_count': 10, + 'average_frame_request_pending_latency': 0.1, + '90th_percentile_frame_request_pending_latency': 0.1, + '99th_percentile_frame_request_pending_latency': 0.1, }; const String resultFileName = 'fake_result'; void driveCallback(List<String> arguments) { From 63b98d55b0144f7d7bda575856b4494405832286 Mon Sep 17 00:00:00 2001 From: Zachary Anderson <zanderso@users.noreply.github.com> Date: Thu, 28 Sep 2023 07:23:25 -0700 Subject: [PATCH 1504/1547] Revert "Upload generated frame-request-pending stats" (#135672) Reverts flutter/flutter#135645 --- dev/devicelab/lib/tasks/perf_tests.dart | 3 --- dev/devicelab/test/perf_tests_test.dart | 6 ------ 2 files changed, 9 deletions(-) diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 416b43cd37a55..1dc73382bfab7 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -1358,9 +1358,6 @@ const List<String> _kCommonScoreKeys = <String>[ '99th_percentile_picture_cache_memory', 'worst_picture_cache_memory', 'old_gen_gc_count', - 'average_frame_request_pending_latency', - '90th_percentile_frame_request_pending_latency', - '99th_percentile_frame_request_pending_latency' ]; /// Measures how long it takes to compile a Flutter app to JavaScript and how diff --git a/dev/devicelab/test/perf_tests_test.dart b/dev/devicelab/test/perf_tests_test.dart index 57a214cc8b770..237cffb1c8013 100644 --- a/dev/devicelab/test/perf_tests_test.dart +++ b/dev/devicelab/test/perf_tests_test.dart @@ -58,9 +58,6 @@ void main() { 'average_vsync_transitions_missed': 1, '90th_percentile_vsync_transitions_missed': 1, '99th_percentile_vsync_transitions_missed': 1, - 'average_frame_request_pending_latency': 0.1, - '90th_percentile_frame_request_pending_latency': 0.1, - '99th_percentile_frame_request_pending_latency': 0.1, }; const String resultFileName = 'fake_result'; void driveCallback(List<String> arguments) { @@ -111,9 +108,6 @@ void main() { '90hz_frame_percentage': 0.4, '120hz_frame_percentage': 0.6, 'illegal_refresh_rate_frame_count': 10, - 'average_frame_request_pending_latency': 0.1, - '90th_percentile_frame_request_pending_latency': 0.1, - '99th_percentile_frame_request_pending_latency': 0.1, }; const String resultFileName = 'fake_result'; void driveCallback(List<String> arguments) { From 8d01d55bf0649fe570f39e6d8ed911288563f6b8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 10:55:05 -0400 Subject: [PATCH 1505/1547] Roll Flutter Engine from 495955a3b5de to d09c2dbe2292 (1 revision) (#135669) https://github.com/flutter/engine/compare/495955a3b5de...d09c2dbe2292 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from d410e03a6b9b to cfac8410d773 (1 revision) (flutter/engine#46362) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 57f8caa9bcd8f..312d5f308b770 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -495955a3b5de2c2e1b4bf056ea8f8a39bb7f59e7 +d09c2dbe229279da31c82ffa96c19d05e9c9d08c From 449c9279e762ae1e18d608a60c25e1909d9f00d0 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 11:57:52 -0400 Subject: [PATCH 1506/1547] Roll Flutter Engine from d09c2dbe2292 to 82b69dadc07a (2 revisions) (#135675) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/flutter/engine/compare/d09c2dbe2292...82b69dadc07a 2023-09-28 leroux_bruno@yahoo.fr [Android] Rename `allowChannelBufferOverflow` to `setWarnsOnChannelOv… (flutter/engine#46361) 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from cfac8410d773 to 267bb43e822d (1 revision) (flutter/engine#46363) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 312d5f308b770..641be9943b276 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d09c2dbe229279da31c82ffa96c19d05e9c9d08c +82b69dadc07aa12252831e7c3bceb9f6a54fcec7 From d134345f8c465d26e0d2011d023706dac7a5d6ff Mon Sep 17 00:00:00 2001 From: Taha Tesser <tessertaha@gmail.com> Date: Thu, 28 Sep 2023 19:06:53 +0300 Subject: [PATCH 1507/1547] Fix `RangeSlider` throws an exception in a `ListView` (#135667) fixes [[RangeSlider] [Flutter 3.10] LateInitializationError: Field '_startThumbCenter@280317193' has not been initialized.](https://github.com/flutter/flutter/issues/126648) ### Code sample (Run it on iOS) <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: ListView( children: <Widget>[ const SizedBox( height: 1000, child: Placeholder(), ), RangeSlider( values: const RangeValues(0.25, 0.75), onChanged: (value) {}, ), ], ), ); } } ``` </details> --- .../lib/src/material/range_slider.dart | 4 +-- .../test/material/range_slider_test.dart | 32 ++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index af73161d2a4d1..d8bb4961f1148 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -900,8 +900,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix late TapGestureRecognizer _tap; bool _active = false; late RangeValues _newValues; - late Offset _startThumbCenter; - late Offset _endThumbCenter; + Offset _startThumbCenter = Offset.zero; + Offset _endThumbCenter = Offset.zero; Rect? overlayStartRect; Rect? overlayEndRect; diff --git a/packages/flutter/test/material/range_slider_test.dart b/packages/flutter/test/material/range_slider_test.dart index 5bedc0cad01af..bd1c528065239 100644 --- a/packages/flutter/test/material/range_slider_test.dart +++ b/packages/flutter/test/material/range_slider_test.dart @@ -2541,7 +2541,7 @@ void main() { ); }); - testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { + testWidgetsWithLeakTracking('RangeSlider onChangeStart and onChangeEnd fire once', (WidgetTester tester) async { // Regression test for https://github.com/flutter/flutter/issues/128433 int startFired = 0; @@ -2581,4 +2581,34 @@ void main() { expect(startFired, equals(1)); expect(endFired, equals(1)); }); + + testWidgetsWithLeakTracking('RangeSlider in a ListView does not throw an exception', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/126648 + + await tester.pumpWidget( + MaterialApp( + home: Directionality( + textDirection: TextDirection.ltr, + child: Material( + child: ListView( + children: <Widget>[ + const SizedBox( + height: 600, + child: Placeholder(), + ), + RangeSlider( + values: const RangeValues(40, 80), + max: 100, + onChanged: (RangeValues newValue) { }, + ), + ], + ), + ), + ), + ), + ); + + // No exception should be thrown. + expect(tester.takeException(), null); + }); } From 880a0a1903aec1d0bb4d89c4f11ab7e2a9fdb115 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 12:18:38 -0400 Subject: [PATCH 1508/1547] Roll Packages from 21c2ebb39c07 to c070b0a7a80a (3 revisions) (#135676) https://github.com/flutter/packages/compare/21c2ebb39c07...c070b0a7a80a 2023-09-28 stuartmorgan@google.com [video_player] Add macOS support (flutter/packages#4982) 2023-09-28 32538273+ValentinVignal@users.noreply.github.com [go_router] Avoid logging when `debugLogDiagnostics` is `false` (flutter/packages#4875) 2023-09-28 stuartmorgan@google.com [tool] Don't lint Flutter shim podspecs (flutter/packages#5007) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/flutter_packages.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/flutter_packages.version b/bin/internal/flutter_packages.version index 817cebedcd599..cf81bee4c12fb 100644 --- a/bin/internal/flutter_packages.version +++ b/bin/internal/flutter_packages.version @@ -1 +1 @@ -21c2ebb39c0732b8c4ae2d68f25b96a895be915f +c070b0a7a80a54d5fad254fecdfd98ffe764bd4e From 3b19c2e5d83aac48d0629d7ff1f007076b17c32b Mon Sep 17 00:00:00 2001 From: tauu <tauu@h2overclock.de> Date: Thu, 28 Sep 2023 18:43:04 +0200 Subject: [PATCH 1509/1547] [web] fix: do not call onSubmitted of TextField when switching browser tabs on mobile web (#134870) This PR fixes #134846. As discussed in the issue, the onSubmitted callback of a TextField is called when the browser switches tabs or is sent to the background if the flutter app is running in any mobile browser (desktop browsers are not affected). Furthermore there is no straight forward way to distinguish between onSubmitted being called because the user pressed the enter key and it being called because the user switched tabs. For example in a chat app this would cause a message to be sent when the user submits the text by pressing "send" on the virtual keyboard as well as when the user switches to another tab. The later action is likely not so much intended. The next section explains what causes the bug and explains the proposed fix. ## Bug Analysis The root cause for this behaviour is line 3494 in editable_text.dart: https://github.com/flutter/flutter/blob/0b540a87f1be9a5bb7e550c777dfe5221c53a112/packages/flutter/lib/src/widgets/editable_text.dart#L3487-L3499 Only if the app is running on the web `_finalizeEditing` is called and this will then trigger the onSubmitted callback. If flutter is running on the web, there are only exactly 3 cases, in which the function is called. The following call trace analysis will describe why. - `connectionClosed()` is only called by in one location, `_handleTextInputInvocation` of the TextInput service. https://github.com/flutter/flutter/blob/367203b3011fc1752cfa1f51adf9751d090c94e6/packages/flutter/lib/src/services/text_input.dart#L1896C12-L1899 - In particular it is only called if the TextInput service receives a 'TextInputClient.onConnectionClosed' message from the engine. - The only location where the web part of the engine send this message is the `onConnectionClosed` function of the TextEditingChannel. https://github.com/flutter/engine/blob/cbda68a720904137ee9dfdf840db323afcf52705/lib/web_ui/lib/src/engine/text_editing/text_editing.dart#L2242-L2254 - `onConnectionClosed` in turn is only called by the `sendTextConnectionClosedToFrameworkIfAny` function of `HybridTextEditing`. https://github.com/flutter/engine/blob/cbda68a720904137ee9dfdf840db323afcf52705/lib/web_ui/lib/src/engine/text_editing/text_editing.dart#L2340-L2345 The function `sendTextConnectionClosedToFrameworkIfAny` is only called at 3 distinct locations of the web engine. ### 1. IOSTextEditingStrategy As described in the comment `sendTextConnectionClosedToFrameworkIfAny` is called if the browser is sent to the background or the tab is changed. https://github.com/flutter/engine/blob/cbda68a720904137ee9dfdf840db323afcf52705/lib/web_ui/lib/src/engine/text_editing/text_editing.dart#L1632-L1656 ### 2. AndroidTextEditingStrategy Same situation as for iOS. `sendTextConnectionClosedToFrameworkIfAny` is also called if `windowHasFocus` is false, which is the case if the browser is sent to background or the tab is changed. https://github.com/flutter/engine/blob/cbda68a720904137ee9dfdf840db323afcf52705/lib/web_ui/lib/src/engine/text_editing/text_editing.dart#L1773-L1785 ### 3. TextInputFinishAutofillContext This call seems to always happen when `finishAutofillContext` is triggered by the framework. https://github.com/flutter/engine/blob/cbda68a720904137ee9dfdf840db323afcf52705/lib/web_ui/lib/src/engine/text_editing/text_editing.dart#L2075-L2083 ## Proposed Fix The fixed proposed and implemented by this PR is to simply delete the call to`_finalizeEditing` in the `connectionClosed` function of editable_text.dart. https://github.com/flutter/flutter/blob/0b540a87f1be9a5bb7e550c777dfe5221c53a112/packages/flutter/lib/src/widgets/editable_text.dart#L3487-L3499 The reasoning for this being: * `_finalizeEditing` is only called in `connectionClosed` for the web engine. * As explained by the trace analysis above, the web engine only triggers this `_finalizeEditing` call in 3 cases. * In the 2 cases for IOSTextEditingStrategy and AndroidTextEditingStrategy the web engine triggering the call only causes the undesired behaviour reported in the issue. * In the third case for TextInputFinishAutofillContext, I can't see a good reason why this would require calling `_finalizeEditing` as it only instructs the platform to save the current values. Other platforms also don't have anything that would trigger onSubmitted being called, so it seems safe to remove it. * For other platforms the onConnectionClosed function was recently incorporated to only unfocus the TextField. So removing the call `_finalizeEditing` unifies the platform behaviour. See also https://github.com/flutter/flutter/pull/123929 https://github.com/flutter/engine/pull/41500 *List which issues are fixed by this PR. You must list at least one issue.* #134846 To simplify the evaluation, here are two versions of the minimal example given in the issue, build with the current master and with this PR applied: current master: https://tauu.github.io/flutter-onsubmit-test/build/web-master/ current master + PR applied: https://tauu.github.io/flutter-onsubmit-test/build/web/ --- .../flutter/lib/src/widgets/editable_text.dart | 6 +----- .../test/widgets/editable_text_test.dart | 18 ++++++------------ 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index 339c6405fa47a..c4c376565aae1 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -3488,11 +3488,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien _textInputConnection!.connectionClosedReceived(); _textInputConnection = null; _lastKnownRemoteTextEditingValue = null; - if (kIsWeb) { - _finalizeEditing(TextInputAction.done, shouldUnfocus: true); - } else { - widget.focusNode.unfocus(); - } + widget.focusNode.unfocus(); } } diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index dc5b7fb797ad4..e3dfc46c78e6d 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -1559,7 +1559,9 @@ void main() { expect(tester.testTextInput.setClientArgs!['inputAction'], equals('TextInputAction.done')); }); - // Test case for https://github.com/flutter/flutter/issues/123523. + // Test case for + // https://github.com/flutter/flutter/issues/123523 + // https://github.com/flutter/flutter/issues/134846 . testWidgetsWithLeakTracking( 'The focus and callback behavior are correct when TextInputClient.onConnectionClosed message received', (WidgetTester tester) async { @@ -1597,17 +1599,9 @@ void main() { editableText.connectionClosed(); await tester.pump(); - if (kIsWeb) { - expect(onSubmittedInvoked, isTrue); - expect(onEditingCompleteInvoked, isTrue); - // Because we add the onEditingComplete and we didn't unfocus there, so focus still exists. - expect(focusNode.hasFocus, isTrue); - } else { - // For mobile and other platforms, calling connectionClosed will only unfocus. - expect(focusNode.hasFocus, isFalse); - expect(onEditingCompleteInvoked, isFalse); - expect(onSubmittedInvoked, isFalse); - } + expect(focusNode.hasFocus, isFalse); + expect(onEditingCompleteInvoked, isFalse); + expect(onSubmittedInvoked, isFalse); }); testWidgetsWithLeakTracking('connection is closed when TextInputClient.onConnectionClosed message received', (WidgetTester tester) async { From c35515a0790bd093f3aca3d6d03bd93cc7aeb911 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Thu, 28 Sep 2023 10:38:51 -0700 Subject: [PATCH 1510/1547] Marks Windows module_custom_host_app_name_test to be unflaky (#135567) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows module_custom_host_app_name_test" } --> The issue https://github.com/flutter/flutter/issues/134644 has been closed, and the test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Windows%20module_custom_host_app_name_test%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index ae6015b314bce..debf9a566a8f8 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4673,7 +4673,6 @@ targets: task_name: hot_mode_dev_cycle_win_target__benchmark - name: Windows module_custom_host_app_name_test - bringup: true # Flaky https://github.com/flutter/flutter/issues/134644 recipe: devicelab/devicelab_drone timeout: 60 properties: From aa498cd51adf23c904e8b288f178168088a5d091 Mon Sep 17 00:00:00 2001 From: Andrew Kolos <andrewrkolos@gmail.com> Date: Thu, 28 Sep 2023 10:38:54 -0700 Subject: [PATCH 1511/1547] Add API to read flavor from framework at run time (#134179) Resolves #128046. Adds a services API that allows flutter app developers to write app code that determines `--flavor` the app was built with. This is implemented by having the tool adding the value of `--flavor` to its list of dart environment declarations, which will be available to the app at run time. Specifically,`FLUTTER_APP_FLAVOR` is set. I chose this implementation for its simplicity. There is some precedent for this, but only for web ([example](https://github.com/flutter/flutter/blob/cd2f3f5e78409027d3c9014172708e4dec7f2185/packages/flutter_tools/lib/src/runner/flutter_command.dart#L1231)). --- .../integration_test/integration_test.dart | 2 + packages/flutter/lib/services.dart | 1 + packages/flutter/lib/src/services/flavor.dart | 10 +++ .../lib/src/runner/flutter_command.dart | 16 +++- .../runner/flutter_command_test.dart | 83 +++++++++++++++++++ 5 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 packages/flutter/lib/src/services/flavor.dart diff --git a/dev/integration_tests/flavors/integration_test/integration_test.dart b/dev/integration_tests/flavors/integration_test/integration_test.dart index d2cdd10dd4ec9..4fda3ce79bb4c 100644 --- a/dev/integration_tests/flavors/integration_test/integration_test.dart +++ b/dev/integration_tests/flavors/integration_test/integration_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'package:flavors/main.dart' as app; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; @@ -16,6 +17,7 @@ void main() { await tester.pumpAndSettle(); expect(find.text('paid'), findsOneWidget); + expect(appFlavor, 'paid'); }); }); } diff --git a/packages/flutter/lib/services.dart b/packages/flutter/lib/services.dart index 9cfde5e909806..cdd209fd1f8bb 100644 --- a/packages/flutter/lib/services.dart +++ b/packages/flutter/lib/services.dart @@ -19,6 +19,7 @@ export 'src/services/browser_context_menu.dart'; export 'src/services/clipboard.dart'; export 'src/services/debug.dart'; export 'src/services/deferred_component.dart'; +export 'src/services/flavor.dart'; export 'src/services/font_loader.dart'; export 'src/services/haptic_feedback.dart'; export 'src/services/hardware_keyboard.dart'; diff --git a/packages/flutter/lib/src/services/flavor.dart b/packages/flutter/lib/src/services/flavor.dart new file mode 100644 index 0000000000000..292c3b37c43e8 --- /dev/null +++ b/packages/flutter/lib/src/services/flavor.dart @@ -0,0 +1,10 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// The flavor this app was built with. +/// +/// This is equivalent to the value argued to the `--flavor` option at build time. +/// This will be `null` if the `--flavor` option was not provided. +const String? appFlavor = String.fromEnvironment('FLUTTER_APP_FLAVOR') != '' ? + String.fromEnvironment('FLUTTER_APP_FLAVOR') : null; diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 36cf0c575f4f2..1d99c9a29e450 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1247,10 +1247,20 @@ abstract class FlutterCommand extends Command<void> { } } + final String? flavor = argParser.options.containsKey('flavor') ? stringArg('flavor') : null; + if (flavor != null) { + if (globals.platform.environment['FLUTTER_APP_FLAVOR'] != null) { + throwToolExit('FLUTTER_APP_FLAVOR is used by the framework and cannot be set in the environment.'); + } + if (dartDefines.any((String define) => define.startsWith('FLUTTER_APP_FLAVOR'))) { + throwToolExit('FLUTTER_APP_FLAVOR is used by the framework and cannot be ' + 'set using --${FlutterOptions.kDartDefinesOption} or --${FlutterOptions.kDartDefineFromFileOption}'); + } + dartDefines.add('FLUTTER_APP_FLAVOR=$flavor'); + } + return BuildInfo(buildMode, - argParser.options.containsKey('flavor') - ? stringArg('flavor') - : null, + flavor, trackWidgetCreation: trackWidgetCreation, frontendServerStarterPath: argParser.options .containsKey(FlutterOptions.kFrontendServerStarterPath) diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 810c8ef3379a6..9f6d9c5e2c17e 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -11,11 +11,14 @@ import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/error_handling_io.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/signals.dart'; import 'package:flutter_tools/src/base/time.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; +import 'package:flutter_tools/src/commands/run.dart'; import 'package:flutter_tools/src/dart/pub.dart'; import 'package:flutter_tools/src/device.dart'; import 'package:flutter_tools/src/globals.dart' as globals; @@ -700,6 +703,67 @@ void main() { expect(testLogger.statusText, contains(UserMessages().flutterSpecifyDevice)); }); }); + + group('--flavor', () { + late _TestDeviceManager testDeviceManager; + late Logger logger; + late FileSystem fileSystem; + + setUp(() { + logger = BufferLogger.test(); + testDeviceManager = _TestDeviceManager(logger: logger); + fileSystem = MemoryFileSystem.test(); + }); + + testUsingContext("tool exits when FLUTTER_APP_FLAVOR is already set in user's environment", () async { + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + fileSystem.file('.packages').createSync(); + + final FakeDevice device = FakeDevice('name', 'id'); + testDeviceManager.devices = <Device>[device]; + final _TestRunCommandThatOnlyValidates command = _TestRunCommandThatOnlyValidates(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + expect(runner.run(<String>['run', '--no-pub', '--no-hot', '--flavor=strawberry']), + throwsToolExit(message: 'FLUTTER_APP_FLAVOR is used by the framework and cannot be set in the environment.')); + + }, overrides: <Type, Generator>{ + DeviceManager: () => testDeviceManager, + Platform: () => FakePlatform( + environment: <String, String>{ + 'FLUTTER_APP_FLAVOR': 'I was already set' + } + ), + Cache: () => Cache.test(processManager: FakeProcessManager.any()), + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + + testUsingContext('tool exits when FLUTTER_APP_FLAVOR is set in --dart-define or --dart-define-from-file', () async { + fileSystem.file('lib/main.dart').createSync(recursive: true); + fileSystem.file('pubspec.yaml').createSync(); + fileSystem.file('.packages').createSync(); + fileSystem.file('config.json')..createSync()..writeAsStringSync('{"FLUTTER_APP_FLAVOR": "strawberry"}'); + + final FakeDevice device = FakeDevice('name', 'id'); + testDeviceManager.devices = <Device>[device]; + final _TestRunCommandThatOnlyValidates command = _TestRunCommandThatOnlyValidates(); + final CommandRunner<void> runner = createTestCommandRunner(command); + + expect(runner.run(<String>['run', '--dart-define=FLUTTER_APP_FLAVOR=strawberry', '--no-pub', '--no-hot', '--flavor=strawberry']), + throwsToolExit(message: 'FLUTTER_APP_FLAVOR is used by the framework and cannot be set using --dart-define or --dart-define-from-file')); + + expect(runner.run(<String>['run', '--dart-define-from-file=config.json', '--no-pub', '--no-hot', '--flavor=strawberry']), + throwsToolExit(message: 'FLUTTER_APP_FLAVOR is used by the framework and cannot be set using --dart-define or --dart-define-from-file')); + }, overrides: <Type, Generator>{ + DeviceManager: () => testDeviceManager, + Platform: () => FakePlatform(), + Cache: () => Cache.test(processManager: FakeProcessManager.any()), + FileSystem: () => fileSystem, + ProcessManager: () => FakeProcessManager.any(), + }); + }); }); } @@ -853,3 +917,22 @@ class FakePub extends Fake implements Pub { PubOutputMode outputMode = PubOutputMode.all, }) async { } } + +class _TestDeviceManager extends DeviceManager { + _TestDeviceManager({required super.logger}); + List<Device> devices = <Device>[]; + + @override + List<DeviceDiscovery> get deviceDiscoverers { + final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); + devices.forEach(discoverer.addDevice); + return <DeviceDiscovery>[discoverer]; + } +} + +class _TestRunCommandThatOnlyValidates extends RunCommand { + @override + Future<FlutterCommandResult> runCommand() async { + return FlutterCommandResult.success(); + } +} From 6cde5da5ea33a8affde9eb1c724b1ff7b7892e5f Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 13:44:46 -0400 Subject: [PATCH 1512/1547] Roll Flutter Engine from 82b69dadc07a to d9eaebd05851 (1 revision) (#135679) https://github.com/flutter/engine/compare/82b69dadc07a...d9eaebd05851 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from 267bb43e822d to bcbcb109bad6 (1 revision) (flutter/engine#46365) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 641be9943b276..5fcbbff9f7957 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -82b69dadc07aa12252831e7c3bceb9f6a54fcec7 +d9eaebd05851076b49732df05a4b1ad8f64a9b70 From 4ed9ab8b238489594aba240a20560c72d3328eb9 Mon Sep 17 00:00:00 2001 From: Alex Li <github@alexv525.com> Date: Fri, 29 Sep 2023 02:21:58 +0800 Subject: [PATCH 1513/1547] =?UTF-8?q?=F0=9F=9A=80=20Add=20more=20fields=20?= =?UTF-8?q?to=20`RefreshProgressIndicator`=20(#135207)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #134494 --- .../lib/src/material/progress_indicator.dart | 23 ++++++- .../material/progress_indicator_test.dart | 69 +++++++++++++++++++ 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/progress_indicator.dart b/packages/flutter/lib/src/material/progress_indicator.dart index 8dc13967c147b..2a1cfa80e8f53 100644 --- a/packages/flutter/lib/src/material/progress_indicator.dart +++ b/packages/flutter/lib/src/material/progress_indicator.dart @@ -865,8 +865,21 @@ class RefreshProgressIndicator extends CircularProgressIndicator { super.semanticsLabel, super.semanticsValue, super.strokeCap, + this.elevation = 2.0, + this.indicatorMargin = const EdgeInsets.all(4.0), + this.indicatorPadding = const EdgeInsets.all(12.0), }); + /// {@macro flutter.material.material.elevation} + final double elevation; + + /// The amount of space by which to inset the whole indicator. + /// It accommodates the [elevation] of the indicator. + final EdgeInsetsGeometry indicatorMargin; + + /// The amount of space by which to inset the inner refresh indicator. + final EdgeInsetsGeometry indicatorPadding; + /// Default stroke width. static const double defaultStrokeWidth = 2.5; @@ -913,6 +926,10 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState { // Last value received from the widget before null. double? _lastValue; + /// Force casting the widget as [RefreshProgressIndicator]. + @override + RefreshProgressIndicator get widget => super.widget as RefreshProgressIndicator; + // Always show the indeterminate version of the circular progress indicator. // // When value is non-null the sweep of the progress indicator arrow's arc @@ -973,13 +990,13 @@ class _RefreshProgressIndicatorState extends _CircularProgressIndicatorState { child: Container( width: _indicatorSize, height: _indicatorSize, - margin: const EdgeInsets.all(4.0), // accommodate the shadow + margin: widget.indicatorMargin, child: Material( type: MaterialType.circle, color: backgroundColor, - elevation: 2.0, + elevation: widget.elevation, child: Padding( - padding: const EdgeInsets.all(12.0), + padding: widget.indicatorPadding, child: Opacity( opacity: opacity, child: Transform.rotate( diff --git a/packages/flutter/test/material/progress_indicator_test.dart b/packages/flutter/test/material/progress_indicator_test.dart index 12ec99d24994c..7537bf97871e1 100644 --- a/packages/flutter/test/material/progress_indicator_test.dart +++ b/packages/flutter/test/material/progress_indicator_test.dart @@ -1183,6 +1183,75 @@ void main() { expect(tester.getSize(find.byType(CircularProgressIndicator)), const Size(36, 36)); }); + + testWidgetsWithLeakTracking('RefreshProgressIndicator using fields correctly', (WidgetTester tester) async { + Future<void> pumpIndicator(RefreshProgressIndicator indicator) { + return tester.pumpWidget(Theme(data: theme, child: indicator)); + } + + // With default values. + await pumpIndicator(const RefreshProgressIndicator()); + Material material = tester.widget( + find.descendant( + of: find.byType(RefreshProgressIndicator), + matching: find.byType(Material), + ), + ); + Container container = tester.widget( + find.descendant( + of: find.byType(RefreshProgressIndicator), + matching: find.byType(Container), + ), + ); + Padding padding = tester.widget( + find.descendant( + of: find.descendant( + of: find.byType(RefreshProgressIndicator), + matching: find.byType(Material), + ), + matching: find.byType(Padding), + ), + ); + expect(material.elevation, 2.0); + expect(container.margin, const EdgeInsets.all(4.0)); + expect(padding.padding, const EdgeInsets.all(12.0)); + + // With values provided. + const double testElevation = 1.0; + const EdgeInsetsGeometry testIndicatorMargin = EdgeInsets.all(6.0); + const EdgeInsetsGeometry testIndicatorPadding = EdgeInsets.all(10.0); + await pumpIndicator( + const RefreshProgressIndicator( + elevation: testElevation, + indicatorMargin: testIndicatorMargin, + indicatorPadding: testIndicatorPadding, + ), + ); + material = tester.widget( + find.descendant( + of: find.byType(RefreshProgressIndicator), + matching: find.byType(Material), + ), + ); + container = tester.widget( + find.descendant( + of: find.byType(RefreshProgressIndicator), + matching: find.byType(Container), + ), + ); + padding = tester.widget( + find.descendant( + of: find.descendant( + of: find.byType(RefreshProgressIndicator), + matching: find.byType(Material), + ), + matching: find.byType(Padding), + ), + ); + expect(material.elevation, testElevation); + expect(container.margin, testIndicatorMargin); + expect(padding.padding, testIndicatorPadding); + }); } class _RefreshProgressIndicatorGolden extends StatefulWidget { From f76c150cc8b64fc59d14d0d79ab10ac033db73e2 Mon Sep 17 00:00:00 2001 From: "auto-submit[bot]" <98614782+auto-submit[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 18:36:26 +0000 Subject: [PATCH 1514/1547] Reverts "Marks Windows module_custom_host_app_name_test to be unflaky" (#135692) Reverts flutter/flutter#135567 Initiated by: ricardoamador This change reverts the following previous change: Original Description: <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Windows module_custom_host_app_name_test" } --> The issue https://github.com/flutter/flutter/issues/134644 has been closed, and the test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Windows%20module_custom_host_app_name_test%22). This test can be marked as unflaky. --- .ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci.yaml b/.ci.yaml index debf9a566a8f8..ae6015b314bce 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -4673,6 +4673,7 @@ targets: task_name: hot_mode_dev_cycle_win_target__benchmark - name: Windows module_custom_host_app_name_test + bringup: true # Flaky https://github.com/flutter/flutter/issues/134644 recipe: devicelab/devicelab_drone timeout: 60 properties: From 9fdb167183f285103f75419537a7c61ca67c6ad6 Mon Sep 17 00:00:00 2001 From: Matheus Kirchesch <matheus@btor.com.br> Date: Thu, 28 Sep 2023 15:41:18 -0300 Subject: [PATCH 1515/1547] Added option to disable [NavigationDestination]s ([NavigationBar] destination widget) (#132361) This PR adds a new option in the NavigationDestination api (the destination widget for the NavigationBar) allowing it to be disabled. As the issue states this PR is the NavigationBar's version of these two PRs (https://github.com/flutter/flutter/pull/132349 and https://github.com/flutter/flutter/pull/127113) * https://github.com/flutter/flutter/issues/132359 --- .../lib/src/material/navigation_bar.dart | 58 +++++++++++++++---- .../test/material/navigation_bar_test.dart | 37 ++++++++++++ 2 files changed, 83 insertions(+), 12 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index c6c99e40d8348..b209ffb21ec04 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -295,6 +295,7 @@ class NavigationDestination extends StatelessWidget { this.selectedIcon, required this.label, this.tooltip, + this.enabled = true, }); /// The [Widget] (usually an [Icon]) that's displayed for this @@ -333,11 +334,17 @@ class NavigationDestination extends StatelessWidget { /// Defaults to null, in which case the [label] text will be used. final String? tooltip; + /// Indicates that this destination is selectable. + /// + /// Defaults to true. + final bool enabled; + @override Widget build(BuildContext context) { final _NavigationDestinationInfo info = _NavigationDestinationInfo.of(context); const Set<MaterialState> selectedState = <MaterialState>{MaterialState.selected}; const Set<MaterialState> unselectedState = <MaterialState>{}; + const Set<MaterialState> disabledState = <MaterialState>{MaterialState.disabled}; final NavigationBarThemeData navigationBarTheme = NavigationBarTheme.of(context); final NavigationBarThemeData defaults = _defaultsFor(context); @@ -346,15 +353,24 @@ class NavigationDestination extends StatelessWidget { return _NavigationDestinationBuilder( label: label, tooltip: tooltip, + enabled: enabled, buildIcon: (BuildContext context) { + final IconThemeData selectedIconTheme = + navigationBarTheme.iconTheme?.resolve(selectedState) + ?? defaults.iconTheme!.resolve(selectedState)!; + final IconThemeData unselectedIconTheme = + navigationBarTheme.iconTheme?.resolve(unselectedState) + ?? defaults.iconTheme!.resolve(unselectedState)!; + final IconThemeData disabledIconTheme = + navigationBarTheme.iconTheme?.resolve(disabledState) + ?? defaults.iconTheme!.resolve(disabledState)!; + final Widget selectedIconWidget = IconTheme.merge( - data: navigationBarTheme.iconTheme?.resolve(selectedState) - ?? defaults.iconTheme!.resolve(selectedState)!, + data: enabled ? selectedIconTheme : disabledIconTheme, child: selectedIcon ?? icon, ); final Widget unselectedIconWidget = IconTheme.merge( - data: navigationBarTheme.iconTheme?.resolve(unselectedState) - ?? defaults.iconTheme!.resolve(unselectedState)!, + data: enabled ? unselectedIconTheme : disabledIconTheme, child: icon, ); @@ -382,7 +398,15 @@ class NavigationDestination extends StatelessWidget { ?? defaults.labelTextStyle!.resolve(selectedState); final TextStyle? effectiveUnselectedLabelTextStyle = navigationBarTheme.labelTextStyle?.resolve(unselectedState) ?? defaults.labelTextStyle!.resolve(unselectedState); - final TextStyle? textStyle = _isForwardOrCompleted(animation) ? effectiveSelectedLabelTextStyle : effectiveUnselectedLabelTextStyle; + final TextStyle? effectiveDisabledLabelTextStyle = navigationBarTheme.labelTextStyle?.resolve(disabledState) + ?? defaults.labelTextStyle!.resolve(disabledState); + + final TextStyle? textStyle = enabled + ? _isForwardOrCompleted(animation) + ? effectiveSelectedLabelTextStyle + : effectiveUnselectedLabelTextStyle + : effectiveDisabledLabelTextStyle; + return Padding( padding: const EdgeInsets.only(top: 4), child: MediaQuery.withClampedTextScaling( @@ -416,6 +440,7 @@ class _NavigationDestinationBuilder extends StatefulWidget { required this.buildLabel, required this.label, this.tooltip, + this.enabled = true, }); /// Builds the icon for a destination in a [NavigationBar]. @@ -454,6 +479,11 @@ class _NavigationDestinationBuilder extends StatefulWidget { /// Defaults to null, in which case the [label] text will be used. final String? tooltip; + /// Indicates that this destination is selectable. + /// + /// Defaults to true. + final bool enabled; + @override State<_NavigationDestinationBuilder> createState() => _NavigationDestinationBuilderState(); } @@ -474,7 +504,7 @@ class _NavigationDestinationBuilderState extends State<_NavigationDestinationBui iconKey: iconKey, labelBehavior: info.labelBehavior, customBorder: navigationBarTheme.indicatorShape ?? defaults.indicatorShape, - onTap: info.onTap, + onTap: widget.enabled ? info.onTap : null, child: Row( children: <Widget>[ Expanded( @@ -1319,9 +1349,11 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData { return MaterialStateProperty.resolveWith((Set<MaterialState> states) { return IconThemeData( size: 24.0, - color: states.contains(MaterialState.selected) - ? _colors.onSecondaryContainer - : _colors.onSurfaceVariant, + color: states.contains(MaterialState.disabled) + ? _colors.onSurfaceVariant.withOpacity(0.38) + : states.contains(MaterialState.selected) + ? _colors.onSecondaryContainer + : _colors.onSurfaceVariant, ); }); } @@ -1332,9 +1364,11 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData { @override MaterialStateProperty<TextStyle?>? get labelTextStyle { return MaterialStateProperty.resolveWith((Set<MaterialState> states) { final TextStyle style = _textTheme.labelMedium!; - return style.apply(color: states.contains(MaterialState.selected) - ? _colors.onSurface - : _colors.onSurfaceVariant + return style.apply(color: states.contains(MaterialState.disabled) + ? _colors.onSurfaceVariant.withOpacity(0.38) + : states.contains(MaterialState.selected) + ? _colors.onSurface + : _colors.onSurfaceVariant ); }); } diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index f38a4830f6617..598b9a3664ece 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -977,6 +977,43 @@ void main() { expect(_getIndicatorDecoration(tester)?.shape, shape); }); + testWidgetsWithLeakTracking('Destinations respect their disabled state', (WidgetTester tester) async { + int selectedIndex = 0; + + await tester.pumpWidget( + _buildWidget( + NavigationBar( + destinations: const <Widget>[ + NavigationDestination( + icon: Icon(Icons.ac_unit), + label: 'AC', + ), + NavigationDestination( + icon: Icon(Icons.access_alarm), + label: 'Alarm', + ), + NavigationDestination( + icon: Icon(Icons.bookmark), + label: 'Bookmark', + enabled: false, + ), + ], + onDestinationSelected: (int i) => selectedIndex = i, + selectedIndex: selectedIndex, + ), + ) + ); + + await tester.tap(find.text('AC')); + expect(selectedIndex, 0); + + await tester.tap(find.text('Alarm')); + expect(selectedIndex, 1); + + await tester.tap(find.text('Bookmark')); + expect(selectedIndex, 1); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests From 8860dd21d8e91deba17ca3349e57e572e1567b75 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 15:01:12 -0400 Subject: [PATCH 1516/1547] Roll Flutter Engine from d9eaebd05851 to 9789dbc2ec3f (2 revisions) (#135688) https://github.com/flutter/engine/compare/d9eaebd05851...9789dbc2ec3f 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from bcbcb109bad6 to d8a71d549262 (1 revision) (flutter/engine#46367) 2023-09-28 skia-flutter-autoroll@skia.org Manual roll Dart SDK from 7c3588c05f87 to 077d768accfa (11 revisions) (flutter/engine#46366) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5fcbbff9f7957..ea0af0a73b371 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -d9eaebd05851076b49732df05a4b1ad8f64a9b70 +9789dbc2ec3f06ee56837bf86f9dcf451be8599a From e61f9e0ce5e9dc3f3e1aab070cdc25a4010ec7de Mon Sep 17 00:00:00 2001 From: Bruno Leroux <leroux_bruno@yahoo.fr> Date: Thu, 28 Sep 2023 21:56:15 +0200 Subject: [PATCH 1517/1547] Fix TabBarView.viewportFraction change is ignored (#135590) ## Description This PR updates `_TabBarViewState.didUpdateWidget` in order to react to `TabBarView.viewportFraction`change. ## Related Issue Fixes https://github.com/flutter/flutter/issues/135557. ## Tests Adds 1 test. --- packages/flutter/lib/src/material/tabs.dart | 7 +++ packages/flutter/test/material/tabs_test.dart | 48 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart index 5ee5e6116778e..235e611eddf1c 100644 --- a/packages/flutter/lib/src/material/tabs.dart +++ b/packages/flutter/lib/src/material/tabs.dart @@ -1867,6 +1867,13 @@ class _TabBarViewState extends State<TabBarView> { _currentIndex = _controller!.index; _jumpToPage(_currentIndex!); } + if (widget.viewportFraction != oldWidget.viewportFraction) { + _pageController?.dispose(); + _pageController = PageController( + initialPage: _currentIndex!, + viewportFraction: widget.viewportFraction, + ); + } // While a warp is under way, we stop updating the tab page contents. // This is tracked in https://github.com/flutter/flutter/issues/31269. if (widget.children != oldWidget.children && _warpUnderwayCount == 0) { diff --git a/packages/flutter/test/material/tabs_test.dart b/packages/flutter/test/material/tabs_test.dart index 098ad754c954c..bc26ae7ff1a55 100644 --- a/packages/flutter/test/material/tabs_test.dart +++ b/packages/flutter/test/material/tabs_test.dart @@ -1643,6 +1643,54 @@ void main() { expect(pageController.viewportFraction, 1); }); + testWidgets('TabBarView viewportFraction can be updated', (WidgetTester tester) async { + // This is a regression test for https://github.com/flutter/flutter/issues/135557. + final List<String> tabs = <String>['A', 'B', 'C']; + TabController? controller; + + Widget buildFrame(double viewportFraction) { + controller = _tabController( + vsync: const TestVSync(), + length: tabs.length, + initialIndex: 1, + ); + return boilerplate( + child: Column( + children: <Widget>[ + TabBar( + tabs: tabs.map<Widget>((String tab) => Tab(text: tab)).toList(), + controller: controller, + ), + SizedBox( + width: 400.0, + height: 400.0, + child: TabBarView( + viewportFraction: viewportFraction, + controller: controller, + children: const <Widget>[ + Center(child: Text('0')), + Center(child: Text('1')), + Center(child: Text('2')), + ], + ), + ), + ], + ), + ); + } + + await tester.pumpWidget(buildFrame(0.8)); + PageView pageView = tester.widget(find.byType(PageView)); + PageController pageController = pageView.controller; + expect(pageController.viewportFraction, 0.8); + + // Rebuild with a different viewport fraction. + await tester.pumpWidget(buildFrame(0.5)); + pageView = tester.widget(find.byType(PageView)); + pageController = pageView.controller; + expect(pageController.viewportFraction, 0.5); + }); + testWidgets('TabBarView has clipBehavior Clip.hardEdge by default', (WidgetTester tester) async { final List<Widget> tabs = <Widget>[const Text('First'), const Text('Second')]; From 97847e099a727f6318c7f3d1003709ded11d18c5 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 16:10:11 -0400 Subject: [PATCH 1518/1547] Roll Flutter Engine from 9789dbc2ec3f to dbb60932a6ab (2 revisions) (#135694) https://github.com/flutter/engine/compare/9789dbc2ec3f...dbb60932a6ab 2023-09-28 chris@bracken.jp Revert "[macOS] performKeyEquivalent cleanup (#45946)" (flutter/engine#46374) 2023-09-28 matej.knopp@gmail.com [macOS] performKeyEquivalent cleanup (flutter/engine#45946) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index ea0af0a73b371..d26be2ae79552 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -9789dbc2ec3f06ee56837bf86f9dcf451be8599a +dbb60932a6ab039de4e799f918b835d837fd5a10 From b5c8fd11e4906d900039584b4f67c9753327060c Mon Sep 17 00:00:00 2001 From: flutter-pub-roller-bot <137456488+flutter-pub-roller-bot@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:00:28 -0700 Subject: [PATCH 1519/1547] Roll pub packages (#135455) This PR was generated by `flutter update-packages --force-upgrade`. --- dev/integration_tests/gradle_deprecated_settings/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index ffabcfd441507..7ec1495bdcdc1 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - camera_android: 0.10.8+9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + camera_android: 0.10.8+10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_avfoundation: 0.9.13+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_platform_interface: 2.5.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" camera_web: 0.3.2+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -39,4 +39,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0937 +# PUBSPEC CHECKSUM: 265f From 371aadd822a258100f7481be84ddd6969ffba82c Mon Sep 17 00:00:00 2001 From: Yegor <yjbanov@google.com> Date: Thu, 28 Sep 2023 15:28:31 -0700 Subject: [PATCH 1520/1547] [tool] fallback to sigkill when closing Chromium (#135521) This implements https://github.com/flutter/flutter/issues/132654#issuecomment-1738221257, namely: Make `Chromium.close` more robust: * Send `SIGTERM` and wait up to 5 seconds, if the process exited, great! Return from the function. * If the process has not exited, then send a `SIGKILL`, which is a much firmer way to exit a process. Same as before, wait up to 5 seconds, if the process exited, great! Return from the function. * If it still hasn't exited then give up trying to exit Chromium, just print a warning to the console and return from the function. Bonus: a few nullability fixes and extra `-v` logging. Fixes https://github.com/flutter/flutter/issues/132654 --- packages/flutter_tools/lib/src/base/io.dart | 18 ++- .../lib/src/test/flutter_web_platform.dart | 20 ++- .../flutter_tools/lib/src/web/chrome.dart | 52 ++++++-- .../ios/ios_device_start_prebuilt_test.dart | 8 +- .../resident_web_runner_test.dart | 10 +- .../test/src/fake_process_manager.dart | 10 +- .../test/web.shard/chrome_test.dart | 120 +++++++++++++++++- 7 files changed, 212 insertions(+), 26 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/io.dart b/packages/flutter_tools/lib/src/base/io.dart index 2a6352737b1fa..83473499a9125 100644 --- a/packages/flutter_tools/lib/src/base/io.dart +++ b/packages/flutter_tools/lib/src/base/io.dart @@ -191,15 +191,27 @@ class ProcessSignal { /// /// Returns true if the signal was delivered, false otherwise. /// - /// On Windows, this can only be used with [ProcessSignal.sigterm], which - /// terminates the process. + /// On Windows, this can only be used with [sigterm], which terminates the + /// process. /// - /// This is implemented by sending the signal using [Process.killPid]. + /// This is implemented by sending the signal using [io.Process.killPid] and + /// therefore cannot be faked in tests. To fake sending signals in tests, use + /// [kill] instead. bool send(int pid) { assert(!_platform.isWindows || this == ProcessSignal.sigterm); return io.Process.killPid(pid, _delegate); } + /// A more testable variant of [send]. + /// + /// Sends this signal to the given `process` by invoking [io.Process.kill]. + /// + /// In tests this method can be faked by passing a fake implementation of the + /// [io.Process] interface. + bool kill(io.Process process) { + return process.kill(_delegate); + } + @override String toString() => _delegate.toString(); } diff --git a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart index ec99e517b066a..6400b7a059304 100644 --- a/packages/flutter_tools/lib/src/test/flutter_web_platform.dart +++ b/packages/flutter_tools/lib/src/test/flutter_web_platform.dart @@ -441,6 +441,14 @@ class FlutterWebPlatform extends PlatformPlugin { if (_closed) { throw StateError('Load called on a closed FlutterWebPlatform'); } + + final String pathFromTest = _fileSystem.path.relative(path, from: _fileSystem.path.join(_root, 'test')); + final Uri suiteUrl = url.resolveUri(_fileSystem.path.toUri('${_fileSystem.path.withoutExtension(pathFromTest)}.html')); + final String relativePath = _fileSystem.path.relative(_fileSystem.path.normalize(path), from: _fileSystem.currentDirectory.path); + if (_logger.isVerbose) { + _logger.printTrace('Loading test suite $relativePath.'); + } + final PoolResource lockResource = await _suiteLock.request(); final Runtime browser = platform.runtime; @@ -455,17 +463,23 @@ class FlutterWebPlatform extends PlatformPlugin { throw StateError('Load called on a closed FlutterWebPlatform'); } - final String pathFromTest = _fileSystem.path.relative(path, from: _fileSystem.path.join(_root, 'test')); - final Uri suiteUrl = url.resolveUri(_fileSystem.path.toUri('${_fileSystem.path.withoutExtension(pathFromTest)}.html')); - final String relativePath = _fileSystem.path.relative(_fileSystem.path.normalize(path), from: _fileSystem.currentDirectory.path); + if (_logger.isVerbose) { + _logger.printTrace('Running test suite $relativePath.'); + } + final RunnerSuite suite = await _browserManager!.load(relativePath, suiteUrl, suiteConfig, message, onDone: () async { await _browserManager!.close(); _browserManager = null; lockResource.release(); + if (_logger.isVerbose) { + _logger.printTrace('Test suite $relativePath finished.'); + } }); + if (_closed) { throw StateError('Load called on a closed FlutterWebPlatform'); } + return suite; } diff --git a/packages/flutter_tools/lib/src/web/chrome.dart b/packages/flutter_tools/lib/src/web/chrome.dart index 3d2ed0be9b50b..f35a6634a2d6f 100644 --- a/packages/flutter_tools/lib/src/web/chrome.dart +++ b/packages/flutter_tools/lib/src/web/chrome.dart @@ -225,10 +225,10 @@ class ChromiumLauncher { url, ]; - final Process? process = await _spawnChromiumProcess(args, chromeExecutable); + final Process process = await _spawnChromiumProcess(args, chromeExecutable); // When the process exits, copy the user settings back to the provided data-dir. - if (process != null && cacheDir != null) { + if (cacheDir != null) { unawaited(process.exitCode.whenComplete(() { _cacheUserSessionInformation(userDataDir, cacheDir); // cleanup temp dir @@ -245,10 +245,11 @@ class ChromiumLauncher { url: url, process: process, chromiumLauncher: this, + logger: _logger, ), skipCheck); } - Future<Process?> _spawnChromiumProcess(List<String> args, String chromeExecutable) async { + Future<Process> _spawnChromiumProcess(List<String> args, String chromeExecutable) async { if (_operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64) { final ProcessResult result = _processManager.runSync(<String>['file', chromeExecutable]); // Check if ARM Chrome is installed. @@ -469,25 +470,58 @@ class Chromium { this.debugPort, this.chromeConnection, { this.url, - Process? process, + required Process process, required ChromiumLauncher chromiumLauncher, + required Logger logger, }) : _process = process, - _chromiumLauncher = chromiumLauncher; + _chromiumLauncher = chromiumLauncher, + _logger = logger; final String? url; final int debugPort; - final Process? _process; + final Process _process; final ChromeConnection chromeConnection; final ChromiumLauncher _chromiumLauncher; + final Logger _logger; - Future<int?> get onExit async => _process?.exitCode; + /// Resolves to browser's main process' exit code, when the browser exits. + Future<int> get onExit async => _process.exitCode; + + /// The main Chromium process that represents this instance of Chromium. + /// + /// Killing this process should result in the browser exiting. + @visibleForTesting + Process get process => _process; + /// Closes all connections to the browser and asks the browser to exit. Future<void> close() async { + if (_logger.isVerbose) { + _logger.printTrace('Shutting down Chromium.'); + } if (_chromiumLauncher.hasChromeInstance) { _chromiumLauncher.currentCompleter = Completer<Chromium>(); } chromeConnection.close(); - _process?.kill(); - await _process?.exitCode; + + // Try to exit Chromium nicely using SIGTERM, before exiting it rudely using + // SIGKILL. Wait no longer than 5 seconds for Chromium to exit before + // falling back to SIGKILL, and then to a warning message. + ProcessSignal.sigterm.kill(_process); + await _process.exitCode.timeout(const Duration(seconds: 5), onTimeout: () { + _logger.printWarning( + 'Failed to exit Chromium (pid: ${_process.pid}) using SIGTERM. Will try ' + 'sending SIGKILL instead.' + ); + ProcessSignal.sigkill.kill(_process); + return _process.exitCode.timeout(const Duration(seconds: 5), onTimeout: () async { + _logger.printWarning( + 'Failed to exit Chromium (pid: ${_process.pid}) using SIGKILL. Giving ' + 'up. Will continue, assuming Chromium has exited successfully, but ' + 'it is possible that this left a dangling Chromium process running ' + 'on the system.' + ); + return 0; + }); + }); } } diff --git a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart index 37edf3ebe38ff..90f834081b269 100644 --- a/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/ios_device_start_prebuilt_test.dart @@ -213,7 +213,7 @@ void main() { completer.complete(); expect(secondLaunchResult.started, true); expect(secondLaunchResult.hasVmService, true); - expect(await device.stopApp(iosApp), false); + expect(await device.stopApp(iosApp), true); }); testWithoutContext('IOSDevice.startApp launches in debug mode via log reading on <iOS 13', () async { @@ -291,7 +291,7 @@ void main() { expect(launchResult.started, true); expect(launchResult.hasVmService, true); - expect(await device.stopApp(iosApp), false); + expect(await device.stopApp(iosApp), true); expect(logger.errorText, contains('The Dart VM Service was not discovered after 30 seconds. This is taking much longer than expected...')); expect(utf8.decoder.convert(stdin.writes.first), contains('process interrupt')); completer.complete(); @@ -336,7 +336,7 @@ void main() { expect(launchResult.started, true); expect(launchResult.hasVmService, true); - expect(await device.stopApp(iosApp), false); + expect(await device.stopApp(iosApp), true); expect(logger.errorText, contains('The Dart VM Service was not discovered after 45 seconds. This is taking much longer than expected...')); expect(logger.errorText, contains('Click "Allow" to the prompt asking if you would like to find and connect devices on your local network.')); completer.complete(); @@ -388,7 +388,7 @@ void main() { expect(processManager, hasNoRemainingExpectations); expect(launchResult.started, true); expect(launchResult.hasVmService, true); - expect(await device.stopApp(iosApp), false); + expect(await device.stopApp(iosApp), true); }); testWithoutContext('IOSDevice.startApp does not retry when ios-deploy loses connection if not in CI', () async { diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 4fc88ae771b6a..f7b63a0f9364d 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -39,6 +39,7 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import '../src/common.dart'; import '../src/context.dart'; +import '../src/fake_process_manager.dart'; import '../src/fake_vm_services.dart'; const List<VmServiceExpectation> kAttachLogExpectations = @@ -620,8 +621,9 @@ void main() { ]); setupMocks(); final TestChromiumLauncher chromiumLauncher = TestChromiumLauncher(); + final FakeProcess process = FakeProcess(); final Chromium chrome = - Chromium(1, chromeConnection, chromiumLauncher: chromiumLauncher); + Chromium(1, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); chromiumLauncher.setInstance(chrome); flutterDevice.device = GoogleChromeDevice( @@ -687,8 +689,9 @@ void main() { ]); setupMocks(); final TestChromiumLauncher chromiumLauncher = TestChromiumLauncher(); + final FakeProcess process = FakeProcess(); final Chromium chrome = - Chromium(1, chromeConnection, chromiumLauncher: chromiumLauncher); + Chromium(1, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); chromiumLauncher.setInstance(chrome); flutterDevice.device = GoogleChromeDevice( @@ -1025,8 +1028,9 @@ void main() { setupMocks(); final FakeChromeConnection chromeConnection = FakeChromeConnection(); final TestChromiumLauncher chromiumLauncher = TestChromiumLauncher(); + final FakeProcess process = FakeProcess(); final Chromium chrome = - Chromium(1, chromeConnection, chromiumLauncher: chromiumLauncher); + Chromium(1, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); chromiumLauncher.setInstance(chrome); flutterDevice.device = GoogleChromeDevice( diff --git a/packages/flutter_tools/test/src/fake_process_manager.dart b/packages/flutter_tools/test/src/fake_process_manager.dart index 427f19a5233ac..305a37cbf968f 100644 --- a/packages/flutter_tools/test/src/fake_process_manager.dart +++ b/packages/flutter_tools/test/src/fake_process_manager.dart @@ -213,10 +213,17 @@ class FakeProcess implements io.Process { /// The raw byte content of stdout. final List<int> _stdout; + /// The list of [kill] signals this process received so far. + @visibleForTesting + List<io.ProcessSignal> get signals => _signals; + final List<io.ProcessSignal> _signals = <io.ProcessSignal>[]; + @override bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) { + _signals.add(signal); + // Killing a fake process has no effect. - return false; + return true; } } @@ -400,6 +407,7 @@ abstract class FakeProcessManager implements ProcessManager { if (fakeProcess == null) { return false; } + fakeProcess.kill(signal); if (fakeProcess._completer != null) { fakeProcess._completer.complete(); } diff --git a/packages/flutter_tools/test/web.shard/chrome_test.dart b/packages/flutter_tools/test/web.shard/chrome_test.dart index 0c6c1ea4f0b2a..f9611f4e7ee0c 100644 --- a/packages/flutter_tools/test/web.shard/chrome_test.dart +++ b/packages/flutter_tools/test/web.shard/chrome_test.dart @@ -3,7 +3,9 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:io' as io; +import 'package:fake_async/fake_async.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -16,7 +18,7 @@ import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'; import '../src/common.dart'; import '../src/fake_process_manager.dart'; -import '../src/fakes.dart'; +import '../src/fakes.dart' hide FakeProcess; const List<String> kChromeArgs = <String>[ '--disable-background-timer-throttling', @@ -165,6 +167,116 @@ void main() { ); }); + testWithoutContext('exits normally using SIGTERM', () async { + final BufferLogger logger = BufferLogger.test(); + final FakeAsync fakeAsync = FakeAsync(); + + fakeAsync.run((_) { + () async { + final FakeChromeConnection chromeConnection = FakeChromeConnection(maxRetries: 4); + final ChromiumLauncher chromiumLauncher = ChromiumLauncher( + fileSystem: fileSystem, + platform: platform, + processManager: processManager, + operatingSystemUtils: operatingSystemUtils, + browserFinder: findChromeExecutable, + logger: logger, + ); + + final FakeProcess process = FakeProcess( + duration: const Duration(seconds: 3), + ); + + final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); + + final Future<void> closeFuture = chrome.close(); + fakeAsync.elapse(const Duration(seconds: 4)); + await closeFuture; + + expect(process.signals, <io.ProcessSignal>[io.ProcessSignal.sigterm]); + }(); + }); + + fakeAsync.flushTimers(); + expect(logger.warningText, isEmpty); + }); + + testWithoutContext('falls back to SIGKILL if SIGTERM did not work', () async { + final BufferLogger logger = BufferLogger.test(); + final FakeAsync fakeAsync = FakeAsync(); + + fakeAsync.run((_) { + () async { + final FakeChromeConnection chromeConnection = FakeChromeConnection(maxRetries: 4); + final ChromiumLauncher chromiumLauncher = ChromiumLauncher( + fileSystem: fileSystem, + platform: platform, + processManager: processManager, + operatingSystemUtils: operatingSystemUtils, + browserFinder: findChromeExecutable, + logger: logger, + ); + + final FakeProcess process = FakeProcess( + duration: const Duration(seconds: 6), + ); + + final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); + + final Future<void> closeFuture = chrome.close(); + fakeAsync.elapse(const Duration(seconds: 7)); + await closeFuture; + + expect(process.signals, <io.ProcessSignal>[io.ProcessSignal.sigterm, io.ProcessSignal.sigkill]); + }(); + }); + + fakeAsync.flushTimers(); + expect( + logger.warningText, + 'Failed to exit Chromium (pid: 1234) using SIGTERM. Will try sending SIGKILL instead.\n', + ); + }); + + testWithoutContext('falls back to a warning if SIGKILL did not work', () async { + final BufferLogger logger = BufferLogger.test(); + final FakeAsync fakeAsync = FakeAsync(); + + fakeAsync.run((_) { + () async { + final FakeChromeConnection chromeConnection = FakeChromeConnection(maxRetries: 4); + final ChromiumLauncher chromiumLauncher = ChromiumLauncher( + fileSystem: fileSystem, + platform: platform, + processManager: processManager, + operatingSystemUtils: operatingSystemUtils, + browserFinder: findChromeExecutable, + logger: logger, + ); + + final FakeProcess process = FakeProcess( + duration: const Duration(seconds: 20), + ); + + final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); + + final Future<void> closeFuture = chrome.close(); + fakeAsync.elapse(const Duration(seconds: 30)); + await closeFuture; + expect(process.signals, <io.ProcessSignal>[io.ProcessSignal.sigterm, io.ProcessSignal.sigkill]); + }(); + }); + + fakeAsync.flushTimers(); + expect( + logger.warningText, + 'Failed to exit Chromium (pid: 1234) using SIGTERM. Will try sending SIGKILL instead.\n' + 'Failed to exit Chromium (pid: 1234) using SIGKILL. Giving up. Will continue, assuming ' + 'Chromium has exited successfully, but it is possible that this left a dangling Chromium ' + 'process running on the system.\n', + ); + }); + testWithoutContext('does not crash if saving profile information fails due to a file system exception.', () async { final BufferLogger logger = BufferLogger.test(); chromeLauncher = ChromiumLauncher( @@ -656,7 +768,8 @@ void main() { browserFinder: findChromeExecutable, logger: logger, ); - final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher); + final FakeProcess process = FakeProcess(); + final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); expect(await chromiumLauncher.connect(chrome, false), equals(chrome)); expect(logger.errorText, isEmpty); }); @@ -672,7 +785,8 @@ void main() { browserFinder: findChromeExecutable, logger: logger, ); - final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher); + final FakeProcess process = FakeProcess(); + final Chromium chrome = Chromium(0, chromeConnection, chromiumLauncher: chromiumLauncher, process: process, logger: logger); await expectToolExitLater( chromiumLauncher.connect(chrome, false), allOf( From 49689632903a00da21db270457db16dd4990600c Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 18:37:17 -0400 Subject: [PATCH 1521/1547] Roll Flutter Engine from dbb60932a6ab to cc7c3c1f0f41 (2 revisions) (#135701) https://github.com/flutter/engine/compare/dbb60932a6ab...cc7c3c1f0f41 2023-09-28 matej.knopp@gmail.com [macOS] FlutterTextInputPlugin should clip to bounds (flutter/engine#46142) 2023-09-28 skia-flutter-autoroll@skia.org Roll Skia from d8a71d549262 to 33502f9b0c7d (2 revisions) (flutter/engine#46375) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d26be2ae79552..83f8c8d306fa9 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -dbb60932a6ab039de4e799f918b835d837fd5a10 +cc7c3c1f0f4115b9f7cb3470183f1965c45cc8f7 From 55c7a2efc4e300ebfdf601867073a9e8fd4c6560 Mon Sep 17 00:00:00 2001 From: Flutter GitHub Bot <fluttergithubbot@gmail.com> Date: Thu, 28 Sep 2023 15:44:52 -0700 Subject: [PATCH 1522/1547] Marks Linux_android flutter_gallery__start_up_delayed to be unflaky (#135565) <!-- meta-tags: To be used by the automation script only, DO NOT MODIFY. { "name": "Linux_android flutter_gallery__start_up_delayed" } --> The issue https://github.com/flutter/flutter/issues/134631 has been closed, and the test has been passing for [50 consecutive runs](https://data.corp.google.com/sites/flutter_infra_metrics_datasite/flutter_check_test_flakiness_status_dashboard/?p=BUILDER_NAME:%22Linux_android%20flutter_gallery__start_up_delayed%22). This test can be marked as unflaky. --- .ci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci.yaml b/.ci.yaml index ae6015b314bce..8892860eae755 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -2106,7 +2106,6 @@ targets: task_name: flutter_gallery__start_up - name: Linux_android flutter_gallery__start_up_delayed - bringup: true # Flaky https://github.com/flutter/flutter/issues/134631 recipe: devicelab/devicelab_drone presubmit: false timeout: 60 From 3509a1dfb7864f903d897a34fadc1546c9134749 Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Thu, 28 Sep 2023 18:01:46 -0500 Subject: [PATCH 1523/1547] Remove assertions on getOffsetToReveal (#135634) --- .../src/rendering/list_wheel_viewport.dart | 5 +-- .../flutter/lib/src/rendering/viewport.dart | 18 +++++--- .../src/widgets/single_child_scroll_view.dart | 7 ++- .../src/widgets/two_dimensional_viewport.dart | 7 ++- .../flutter/test/rendering/viewport_test.dart | 8 ++++ .../widgets/list_wheel_scroll_view_test.dart | 31 +++++++++++++ .../single_child_scroll_view_test.dart | 34 ++++++++++++++ .../two_dimensional_viewport_test.dart | 44 ++++++++++++++++++- 8 files changed, 134 insertions(+), 20 deletions(-) diff --git a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart index 611d3e55e6408..c66e97e3e55a4 100644 --- a/packages/flutter/lib/src/rendering/list_wheel_viewport.dart +++ b/packages/flutter/lib/src/rendering/list_wheel_viewport.dart @@ -1125,11 +1125,8 @@ class RenderListWheelViewport RenderObject target, double alignment, { Rect? rect, - Axis? axis, + Axis? axis, // Unused, only Axis.vertical supported by this viewport. }) { - // One dimensional viewport has only one axis, it should match if it has - // been provided. - assert(axis == null || axis == Axis.vertical); // `target` is only fully revealed when in the selected/center position. Therefore, // this method always returns the offset that shows `target` in the center position, // which is the same offset for all `alignment` values. diff --git a/packages/flutter/lib/src/rendering/viewport.dart b/packages/flutter/lib/src/rendering/viewport.dart index aa2dd97b9c5cf..8756c8fe63f85 100644 --- a/packages/flutter/lib/src/rendering/viewport.dart +++ b/packages/flutter/lib/src/rendering/viewport.dart @@ -111,9 +111,14 @@ abstract interface class RenderAbstractViewport extends RenderObject { /// The optional [Axis] is used by /// [RenderTwoDimensionalViewport.getOffsetToReveal] to /// determine which of the two axes to compute an offset for. One dimensional - /// subclasses like [RenderViewportBase] and [RenderListWheelViewport] will - /// assert in debug builds if the `axis` value is provided and does not match - /// the single [Axis] that viewport is configured for. + /// subclasses like [RenderViewportBase] and [RenderListWheelViewport] + /// will ignore the `axis` value if provided, since there is only one [Axis]. + /// + /// If the `axis` is omitted when called on [RenderTwoDimensionalViewport], + /// the [RenderTwoDimensionalViewport.mainAxis] is used. To reveal an object + /// properly in both axes, this method should be called for each [Axis] as the + /// returned [RevealedOffset.offset] only represents the offset of one of the + /// the two [ScrollPosition]s. /// /// See also: /// @@ -821,10 +826,9 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix Rect? rect, Axis? axis, }) { - // One dimensional viewport has only one axis, it should match if it has - // been provided. - axis ??= this.axis; - assert(axis == this.axis); + // One dimensional viewport has only one axis, override if it was + // provided/may be mismatched. + axis = this.axis; // Steps to convert `rect` (from a RenderBox coordinate system) to its // scroll offset within this viewport (not in the exact order): diff --git a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart index d4af0def621b7..59b4956f5f7dc 100644 --- a/packages/flutter/lib/src/widgets/single_child_scroll_view.dart +++ b/packages/flutter/lib/src/widgets/single_child_scroll_view.dart @@ -598,10 +598,9 @@ class _RenderSingleChildViewport extends RenderBox with RenderObjectWithChildMix Rect? rect, Axis? axis, }) { - // One dimensional viewport has only one axis, it should match if it has - // been provided. - axis ??= this.axis; - assert(axis == this.axis); + // One dimensional viewport has only one axis, override if it was + // provided/may be mismatched. + axis = this.axis; rect ??= target.paintBounds; if (target is! RenderBox) { diff --git a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart index 3b3baf1061eb7..5759df9c90e9a 100644 --- a/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart +++ b/packages/flutter/lib/src/widgets/two_dimensional_viewport.dart @@ -924,11 +924,10 @@ abstract class RenderTwoDimensionalViewport extends RenderBox implements RenderA Rect? rect, Axis? axis, }) { - // We must know which axis we are revealing for, since RevealedOffset - // refers to only one of two scroll positions. - assert(axis != null); + // If an axis has not been specified, use the mainAxis. + axis ??= mainAxis; - final (double offset, AxisDirection axisDirection) = switch (axis!) { + final (double offset, AxisDirection axisDirection) = switch (axis) { Axis.vertical => (verticalOffset.pixels, verticalAxisDirection), Axis.horizontal => (horizontalOffset.pixels, horizontalAxisDirection), }; diff --git a/packages/flutter/test/rendering/viewport_test.dart b/packages/flutter/test/rendering/viewport_test.dart index e2e00012721c6..b4cf6ae489c94 100644 --- a/packages/flutter/test/rendering/viewport_test.dart +++ b/packages/flutter/test/rendering/viewport_test.dart @@ -1586,6 +1586,14 @@ void main() { final double revealOffset = viewport.getOffsetToReveal(target, 0.0).offset; expect(revealOffset, -(300.0 + padding.horizontal) * 5 + 34.0 * 2); }); + + testWidgets('will not assert on mismatched axis', (WidgetTester tester) async { + await tester.pumpWidget(buildList(axis: Axis.vertical, reverse: true, reverseGrowth: true)); + final RenderAbstractViewport viewport = tester.allRenderObjects.whereType<RenderAbstractViewport>().first; + + final RenderObject target = tester.renderObject(find.text('Tile 0', skipOffstage: false)); + viewport.getOffsetToReveal(target, 0.0, axis: Axis.horizontal); + }); }); testWidgets('RenderViewportBase.showOnScreen reports the correct targetRect', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart index ef2361d50039c..e58bd6909d2fc 100644 --- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart +++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart @@ -1598,6 +1598,37 @@ void main() { expect(revealed.rect, const Rect.fromLTWH(165.0, 265.0, 10.0, 10.0)); }); + testWidgets('will not assert on getOffsetToReveal Axis', (WidgetTester tester) async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + height: 500.0, + width: 300.0, + child: ListWheelScrollView( + controller: ScrollController(initialScrollOffset: 300.0), + itemExtent: 100.0, + children: List<Widget>.generate(10, (int i) { + return Center( + child: SizedBox( + height: 50.0, + width: 50.0, + child: Text('Item $i'), + ), + ); + }), + ), + ), + ), + ), + ); + + final RenderListWheelViewport viewport = tester.allRenderObjects.whereType<RenderListWheelViewport>().first; + final RenderObject target = tester.renderObject(find.text('Item 5')); + viewport.getOffsetToReveal(target, 0.0, axis: Axis.horizontal); + }); + testWidgets('ListWheelScrollView showOnScreen', (WidgetTester tester) async { List<Widget> outerChildren; final List<Widget> innerChildren = List<Widget>.generate(10, (int index) => Container()); diff --git a/packages/flutter/test/widgets/single_child_scroll_view_test.dart b/packages/flutter/test/widgets/single_child_scroll_view_test.dart index 2cc8708215436..dfe67d39ff20a 100644 --- a/packages/flutter/test/widgets/single_child_scroll_view_test.dart +++ b/packages/flutter/test/widgets/single_child_scroll_view_test.dart @@ -486,6 +486,40 @@ void main() { expect(semanticsClip.size.width, length); }); + testWidgetsWithLeakTracking('SingleChildScrollView getOffsetToReveal - will not assert on axis mismatch', (WidgetTester tester) async { + final ScrollController controller = ScrollController(initialScrollOffset: 300.0); + addTearDown(controller.dispose); + List<Widget> children; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: SizedBox( + height: 200.0, + width: 300.0, + child: SingleChildScrollView( + controller: controller, + child: Column( + children: children = List<Widget>.generate(20, (int i) { + return SizedBox( + height: 100.0, + width: 300.0, + child: Text('Tile $i'), + ); + }), + ), + ), + ), + ), + ), + ); + + final RenderAbstractViewport viewport = tester.allRenderObjects.whereType<RenderAbstractViewport>().first; + + final RenderObject target = tester.renderObject(find.byWidget(children[5])); + viewport.getOffsetToReveal(target, 0.0, axis: Axis.horizontal); + }); + testWidgetsWithLeakTracking('SingleChildScrollView getOffsetToReveal - down', (WidgetTester tester) async { final ScrollController controller = ScrollController(initialScrollOffset: 300.0); addTearDown(controller.dispose); diff --git a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart index 1d10521d91395..b7432de826f3e 100644 --- a/packages/flutter/test/widgets/two_dimensional_viewport_test.dart +++ b/packages/flutter/test/widgets/two_dimensional_viewport_test.dart @@ -2366,11 +2366,53 @@ void main() { ); }, variant: TargetPlatformVariant.all()); - group('TwoDimensionalViewport showOnScreen & showInViewport', () { + group('showOnScreen & showInViewport', () { Finder findKey(ChildVicinity vicinity) { return find.byKey(ValueKey<ChildVicinity>(vicinity)); } + testWidgets('getOffsetToReveal', (WidgetTester tester) async { + await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); + + RenderAbstractViewport viewport = tester.allRenderObjects.whereType<RenderAbstractViewport>().first; + final RevealedOffset verticalOffset = viewport.getOffsetToReveal( + tester.renderObject(findKey(const ChildVicinity(xIndex: 5, yIndex: 5))), + 1.0, + axis: Axis.vertical, + ); + final RevealedOffset horizontalOffset = viewport.getOffsetToReveal( + tester.renderObject(findKey(const ChildVicinity(xIndex: 5, yIndex: 5))), + 1.0, + axis: Axis.horizontal, + ); + expect(verticalOffset.offset, 600.0); + expect(verticalOffset.rect, const Rect.fromLTRB(1000.0, 400.0, 1200.0, 600.0)); + expect(horizontalOffset.offset, 400.0); + expect(horizontalOffset.rect, const Rect.fromLTRB(600.0, 1000.0, 800.0, 1200.0)); + + // default is to use mainAxis when axis is not provided, mainAxis + // defaults to Axis.vertical. + RevealedOffset defaultOffset = viewport.getOffsetToReveal( + tester.renderObject(findKey(const ChildVicinity(xIndex: 5, yIndex: 5))), + 1.0, + ); + expect(defaultOffset.offset, verticalOffset.offset); + expect(defaultOffset.rect, verticalOffset.rect); + + // mainAxis as Axis.horizontal + await tester.pumpWidget(simpleBuilderTest( + useCacheExtent: true, + mainAxis: Axis.horizontal, + )); + viewport = tester.allRenderObjects.whereType<RenderAbstractViewport>().first; + defaultOffset = viewport.getOffsetToReveal( + tester.renderObject(findKey(const ChildVicinity(xIndex: 5, yIndex: 5))), + 1.0, + ); + expect(defaultOffset.offset, horizontalOffset.offset); + expect(defaultOffset.rect, horizontalOffset.rect); + }); + testWidgets('Axis.vertical', (WidgetTester tester) async { await tester.pumpWidget(simpleBuilderTest(useCacheExtent: true)); // Child visible at origin From de20e74a9af5798e912938423f9a7ce0354d4daf Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Date: Thu, 28 Sep 2023 19:42:11 -0400 Subject: [PATCH 1524/1547] Roll Flutter Engine from cc7c3c1f0f41 to 485543c6765a (8 revisions) (#135717) https://github.com/flutter/engine/compare/cc7c3c1f0f41...485543c6765a 2023-09-28 skia-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from cu6apvEZ2P6zhishc... to l2RxJKPfYn7QzGOoL... (flutter/engine#46382) 2023-09-28 30870216+gaaclarke@users.noreply.github.com Remove opacity layer dcheck. (flutter/engine#46160) 2023-09-28 matanlurey@users.noreply.github.com Add initial support for 4x MSAA in OpenGLES backend. (flutter/engine#46381) 2023-09-28 matej.knopp@gmail.com Reland: [macOS] performKeyEquivalent cleanup (flutter/engine#46377) 2023-09-28 matej.knopp@gmail.com [macOS] TextInputPlugin should mark navigation events in IME popover as handled (flutter/engine#46141) 2023-09-28 30870216+gaaclarke@users.noreply.github.com Removed unnecessary dynamic dispatch (flutter/engine#46369) 2023-09-28 joel.winarske@gmail.com [Impeller] Fix OpenGLES EGL_BAD_ACCESS due to context being current on multiple threads. (flutter/engine#46287) 2023-09-28 ajihyf@gmail.com Fix damage calculation when not providing populate_existing_damage for gl embedder (flutter/engine#45611) Also rolling transitive DEPS: fuchsia/sdk/core/linux-amd64 from cu6apvEZ2P6z to l2RxJKPfYn7Q If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC jacksongardner@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- bin/internal/engine.version | 2 +- bin/internal/fuchsia-linux.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 83f8c8d306fa9..66dcfe6601fd1 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cc7c3c1f0f4115b9f7cb3470183f1965c45cc8f7 +485543c6765ab38e9effc37b1c12c293ba5f9ab6 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 96ce318ec1905..6331e09a5f423 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -cu6apvEZ2P6zhishcExZHv7qWi62MO8R3JOnclnglFAC +l2RxJKPfYn7QzGOoLPUPk0FyRZxbYTRv1JiQJgUbm9sC From e5d3b704da4001f7d8f2b8db28f27b1c08a99035 Mon Sep 17 00:00:00 2001 From: Polina Cherkasova <polinach@google.com> Date: Thu, 28 Sep 2023 17:03:23 -0700 Subject: [PATCH 1525/1547] Pin leak_tracker before publishing breaking change. (#135720) --- packages/flutter_tools/lib/src/commands/update_packages.dart | 4 ++++ .../test/general.shard/update_packages_test.dart | 2 ++ 2 files changed, 6 insertions(+) diff --git a/packages/flutter_tools/lib/src/commands/update_packages.dart b/packages/flutter_tools/lib/src/commands/update_packages.dart index e482057c56fa7..bf3bc59a90d72 100644 --- a/packages/flutter_tools/lib/src/commands/update_packages.dart +++ b/packages/flutter_tools/lib/src/commands/update_packages.dart @@ -36,6 +36,10 @@ const Map<String, String> kManuallyPinnedDependencies = <String, String>{ 'material_color_utilities': '0.5.0', // https://github.com/flutter/flutter/issues/115660 'archive': '3.3.2', + // https://github.com/flutter/flutter/issues/135716 + 'leak_tracker': '9.0.7', + // https://github.com/flutter/flutter/issues/135716 + 'leak_tracker_flutter_testing': '1.0.5', }; class UpdatePackagesCommand extends FlutterCommand { diff --git a/packages/flutter_tools/test/general.shard/update_packages_test.dart b/packages/flutter_tools/test/general.shard/update_packages_test.dart index 7b2ecd82b064e..1bfe39ada9538 100644 --- a/packages/flutter_tools/test/general.shard/update_packages_test.dart +++ b/packages/flutter_tools/test/general.shard/update_packages_test.dart @@ -107,6 +107,8 @@ void main() { 'video_player', 'material_color_utilities', 'archive', + 'leak_tracker', + 'leak_tracker_flutter_testing', ]), ); }); From d13cd8846e5ea7446a1120581b5091234c9a9eca Mon Sep 17 00:00:00 2001 From: Jonah Williams <jonahwilliams@google.com> Date: Thu, 28 Sep 2023 17:21:14 -0700 Subject: [PATCH 1526/1547] [flutter_tools] remove VmService screenshot for native devices. (#135462) * This is completely broken on the Impeller renderer, see: https://github.com/flutter/flutter/issues/135052 * Even on the Skia renderer, this gives a software rasterized screenshot which will absolutely look different from a native rendering screenshot. I plan to remove this functionality from the engine. --- .../lib/src/commands/screenshot.dart | 32 +------ .../lib/src/resident_runner.dart | 10 +-- packages/flutter_tools/lib/src/vmservice.dart | 5 -- .../hermetic/screenshot_command_test.dart | 10 --- .../general.shard/terminal_handler_test.dart | 90 +------------------ .../test/general.shard/vmservice_test.dart | 7 -- 6 files changed, 10 insertions(+), 144 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/screenshot.dart b/packages/flutter_tools/lib/src/commands/screenshot.dart index 21b531ecf597b..db3686e49f6b1 100644 --- a/packages/flutter_tools/lib/src/commands/screenshot.dart +++ b/packages/flutter_tools/lib/src/commands/screenshot.dart @@ -18,7 +18,6 @@ const String _kType = 'type'; const String _kVmServiceUrl = 'vm-service-url'; const String _kDeviceType = 'device'; const String _kSkiaType = 'skia'; -const String _kRasterizerType = 'rasterizer'; class ScreenshotCommand extends FlutterCommand { ScreenshotCommand({required this.fs}) { @@ -33,7 +32,7 @@ class ScreenshotCommand extends FlutterCommand { aliases: <String>[ 'observatory-url' ], // for historical reasons valueHelp: 'URI', help: 'The VM Service URL to which to connect.\n' - 'This is required when "--$_kType" is "$_kSkiaType" or "$_kRasterizerType".\n' + 'This is required when "--$_kType" is "$_kSkiaType".\n' 'To find the VM service URL, use "flutter run" and look for ' '"A Dart VM Service ... is available at" in the output.', ); @@ -41,13 +40,12 @@ class ScreenshotCommand extends FlutterCommand { _kType, valueHelp: 'type', help: 'The type of screenshot to retrieve.', - allowed: const <String>[_kDeviceType, _kSkiaType, _kRasterizerType], + allowed: const <String>[_kDeviceType, _kSkiaType], allowedHelp: const <String, String>{ _kDeviceType: "Delegate to the device's native screenshot capabilities. This " 'screenshots the entire screen currently being displayed (including content ' 'not rendered by Flutter, like the device status bar).', _kSkiaType: 'Render the Flutter app as a Skia picture. Requires "--$_kVmServiceUrl".', - _kRasterizerType: 'Render the Flutter app using the rasterizer. Requires "--$_kVmServiceUrl."', }, defaultsTo: _kDeviceType, ); @@ -116,8 +114,6 @@ class ScreenshotCommand extends FlutterCommand { await runScreenshot(outputFile); case _kSkiaType: success = await runSkia(outputFile); - case _kRasterizerType: - success = await runRasterizer(outputFile); } return success ? FlutterCommandResult.success() @@ -173,30 +169,6 @@ class ScreenshotCommand extends FlutterCommand { return true; } - Future<bool> runRasterizer(File? outputFile) async { - final Uri vmServiceUrl = Uri.parse(stringArg(_kVmServiceUrl)!); - final FlutterVmService vmService = await connectToVmService(vmServiceUrl, logger: globals.logger); - final vm_service.Response? response = await vmService.screenshot(); - if (response == null) { - globals.printError( - 'The screenshot request failed, probably because the device was ' - 'disconnected', - ); - return false; - } - outputFile ??= globals.fsUtils.getUniqueFile( - fs.currentDirectory, - 'flutter', - 'png', - ); - final IOSink sink = outputFile.openWrite(); - sink.add(base64.decode(response.json?['screenshot'] as String)); - await sink.close(); - _showOutputFileInfo(outputFile); - ensureOutputIsNotJsonRpcError(outputFile); - return true; - } - static void checkOutput(File outputFile, FileSystem fs) { if (!fs.file(outputFile.path).existsSync()) { throwToolExit( diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 742132b908c80..1b63932ce60c7 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -1017,17 +1017,17 @@ abstract class ResidentHandlers { } Future<bool> _takeVmServiceScreenshot(FlutterDevice device, File outputFile) async { - final bool isWebDevice = device.targetPlatform == TargetPlatform.web_javascript; + if (device.targetPlatform != TargetPlatform.web_javascript) { + return false; + } assert(supportsServiceProtocol); return _toggleDebugBanner(device, () async { - final vm_service.Response? response = isWebDevice - ? await device.vmService!.callMethodWrapper('ext.dwds.screenshot') - : await device.vmService!.screenshot(); + final vm_service.Response? response = await device.vmService!.callMethodWrapper('ext.dwds.screenshot'); if (response == null) { throw Exception('Failed to take screenshot'); } - final String data = response.json![isWebDevice ? 'data' : 'screenshot'] as String; + final String data = response.json!['data'] as String; outputFile.writeAsBytesSync(base64.decode(data)); }); } diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 78a5b92bd7787..60874eccd4d78 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart @@ -28,7 +28,6 @@ const String kFlushUIThreadTasksMethod = '_flutter.flushUIThreadTasks'; const String kRunInViewMethod = '_flutter.runInView'; const String kListViewsMethod = '_flutter.listViews'; const String kScreenshotSkpMethod = '_flutter.screenshotSkp'; -const String kScreenshotMethod = '_flutter.screenshot'; const String kRenderFrameWithRasterStatsMethod = '_flutter.renderFrameWithRasterStats'; const String kReloadAssetFonts = '_flutter.reloadAssetFonts'; @@ -1054,10 +1053,6 @@ class FlutterVmService { ); } - Future<vm_service.Response?> screenshot() { - return _checkedCallServiceExtension(kScreenshotMethod); - } - Future<vm_service.Response?> screenshotSkp() { return _checkedCallServiceExtension(kScreenshotSkpMethod); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart index 42954dc440a40..01725cc991394 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart @@ -31,11 +31,6 @@ void main() { .run(<String>['screenshot', '--type=skia', '--vm-service-url=http://localhost:8181']), throwsA(isException.having((Exception exception) => exception.toString(), 'message', contains('dummy'))), ); - - await expectLater(() => createTestCommandRunner(ScreenshotCommand(fs: MemoryFileSystem.test())) - .run(<String>['screenshot', '--type=rasterizer', '--vm-service-url=http://localhost:8181']), - throwsA(isException.having((Exception exception) => exception.toString(), 'message', contains('dummy'))), - ); }); @@ -44,11 +39,6 @@ void main() { .run(<String>['screenshot', '--type=skia']), throwsToolExit(message: 'VM Service URI must be specified for screenshot type skia') ); - - await expectLater(() => createTestCommandRunner(ScreenshotCommand(fs: MemoryFileSystem.test())) - .run(<String>['screenshot', '--type=rasterizer',]), - throwsToolExit(message: 'VM Service URI must be specified for screenshot type rasterizer'), - ); }); testUsingContext('device screenshots require device', () async { diff --git a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart index e6a38e5d39ae3..33f615c85ad75 100644 --- a/packages/flutter_tools/test/general.shard/terminal_handler_test.dart +++ b/packages/flutter_tools/test/general.shard/terminal_handler_test.dart @@ -1015,38 +1015,14 @@ void main() { expect(logger.statusText, contains('Screenshot written to flutter_01.png (0kB)')); }); - testWithoutContext('s, can take screenshot on debug device that does not support screenshot', () async { + testWithoutContext('s, will not take screenshot on non-web device without screenshot tooling support', () async { final BufferLogger logger = BufferLogger.test(); final FileSystem fileSystem = MemoryFileSystem.test(); - final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[ - listViews, - FakeVmServiceRequest( - method: 'ext.flutter.debugAllowBanner', - args: <String, Object?>{ - 'isolateId': fakeUnpausedIsolate.id, - 'enabled': 'false', - }, - ), - FakeVmServiceRequest( - method: '_flutter.screenshot', - args: <String, Object>{}, - jsonResponse: <String, Object>{ - 'screenshot': base64.encode(<int>[1, 2, 3, 4]), - }, - ), - FakeVmServiceRequest( - method: 'ext.flutter.debugAllowBanner', - args: <String, Object?>{ - 'isolateId': fakeUnpausedIsolate.id, - 'enabled': 'true', - }, - ), - ], logger: logger, fileSystem: fileSystem); + final TerminalHandler terminalHandler = setUpTerminalHandler(<FakeVmServiceRequest>[], logger: logger, fileSystem: fileSystem); await terminalHandler.processTerminalInput('s'); - expect(logger.statusText, contains('Screenshot written to flutter_01.png (0kB)')); - expect(fileSystem.currentDirectory.childFile('flutter_01.png').readAsBytesSync(), <int>[1, 2, 3, 4]); + expect(logger.statusText, isNot(contains('Screenshot written to'))); }); testWithoutContext('s, can take screenshot on debug web device that does not support screenshot', () async { @@ -1133,66 +1109,6 @@ void main() { expect(fileSystem.currentDirectory.childFile('flutter_01.png'), isNot(exists)); }); - testWithoutContext('s, bails taking screenshot on debug device if debugAllowBanner throws RpcError', () async { - final BufferLogger logger = BufferLogger.test(); - final FileSystem fileSystem = MemoryFileSystem.test(); - final TerminalHandler terminalHandler = setUpTerminalHandler( - <FakeVmServiceRequest>[ - listViews, - FakeVmServiceRequest( - method: 'ext.flutter.debugAllowBanner', - args: <String, Object?>{ - 'isolateId': fakeUnpausedIsolate.id, - 'enabled': 'false', - }, - // Failed response, - errorCode: RPCErrorCodes.kInternalError, - ), - ], - logger: logger, - fileSystem: fileSystem, - ); - - await terminalHandler.processTerminalInput('s'); - - expect(logger.errorText, contains('Error')); - }); - - testWithoutContext('s, bails taking screenshot on debug device if flutter.screenshot throws RpcError, restoring banner', () async { - final BufferLogger logger = BufferLogger.test(); - final FileSystem fileSystem = MemoryFileSystem.test(); - final TerminalHandler terminalHandler = setUpTerminalHandler( - <FakeVmServiceRequest>[ - listViews, - FakeVmServiceRequest( - method: 'ext.flutter.debugAllowBanner', - args: <String, Object?>{ - 'isolateId': fakeUnpausedIsolate.id, - 'enabled': 'false', - }, - ), - const FakeVmServiceRequest( - method: '_flutter.screenshot', - // Failed response, - errorCode: RPCErrorCodes.kInternalError, - ), - FakeVmServiceRequest( - method: 'ext.flutter.debugAllowBanner', - args: <String, Object?>{ - 'isolateId': fakeUnpausedIsolate.id, - 'enabled': 'true', - }, - ), - ], - logger: logger, - fileSystem: fileSystem, - ); - - await terminalHandler.processTerminalInput('s'); - - expect(logger.errorText, contains('Error')); - }); - testWithoutContext('s, bails taking screenshot on debug device if dwds.screenshot throws RpcError, restoring banner', () async { final BufferLogger logger = BufferLogger.test(); final FileSystem fileSystem = MemoryFileSystem.test(); diff --git a/packages/flutter_tools/test/general.shard/vmservice_test.dart b/packages/flutter_tools/test/general.shard/vmservice_test.dart index 73e710c6567af..2557b3a289758 100644 --- a/packages/flutter_tools/test/general.shard/vmservice_test.dart +++ b/packages/flutter_tools/test/general.shard/vmservice_test.dart @@ -442,10 +442,6 @@ void main() { method: kListViewsMethod, errorCode: RPCErrorCodes.kServiceDisappeared, ), - const FakeVmServiceRequest( - method: kScreenshotMethod, - errorCode: RPCErrorCodes.kServiceDisappeared, - ), const FakeVmServiceRequest( method: kScreenshotSkpMethod, errorCode: RPCErrorCodes.kServiceDisappeared, @@ -480,9 +476,6 @@ void main() { final List<FlutterView> views = await fakeVmServiceHost.vmService.getFlutterViews(); expect(views, isEmpty); - final vm_service.Response? screenshot = await fakeVmServiceHost.vmService.screenshot(); - expect(screenshot, isNull); - final vm_service.Response? screenshotSkp = await fakeVmServiceHost.vmService.screenshotSkp(); expect(screenshotSkp, isNull); From 951653a1c06b3207448f7bc66ba91b52e6a06521 Mon Sep 17 00:00:00 2001 From: keyonghan <54558023+keyonghan@users.noreply.github.com> Date: Thu, 28 Sep 2023 17:57:06 -0700 Subject: [PATCH 1527/1547] Add arch property for windows_arm64 platform (#135725) Window arm64 bots are using x64 built python, which gave incorrect arch info. This PR adds the arch info explicitly so that recipes can get this value and populate to benchmark tags. Part of https://github.com/flutter/flutter/issues/135722 --- .ci.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.ci.yaml b/.ci.yaml index 8892860eae755..1c4d16970f4fc 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -199,6 +199,8 @@ platform_properties: device_type: none windows_arm64: properties: + # The arch can be removed after https://github.com/flutter/flutter/issues/135722. + arch: arm dependencies: >- [ {"dependency": "certs", "version": "version:9563bb"} From f0abad66b249244cbdbb291cf6edfbba9937ffa0 Mon Sep 17 00:00:00 2001 From: Xilai Zhang <xilaizhang@google.com> Date: Tue, 10 Oct 2023 19:29:41 -0700 Subject: [PATCH 1528/1547] [flutter_releases] Flutter beta 3.16.0-0.1.pre Framework Cherrypicks (#136303) # Flutter beta 3.16.0-0.1.pre Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- bin/internal/release-candidate-branch.version | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 bin/internal/release-candidate-branch.version diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 66dcfe6601fd1..a33d59193df0c 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -485543c6765ab38e9effc37b1c12c293ba5f9ab6 +7ccdde78a7d174dc0bf0be77102b205e844c7998 diff --git a/bin/internal/release-candidate-branch.version b/bin/internal/release-candidate-branch.version new file mode 100644 index 0000000000000..0ca38b3c50500 --- /dev/null +++ b/bin/internal/release-candidate-branch.version @@ -0,0 +1 @@ +flutter-3.16-candidate.0 From fe6553b689e4d2151b0f760ca06927fc284cc0a9 Mon Sep 17 00:00:00 2001 From: godofredoc <godofredoc@google.com> Date: Wed, 11 Oct 2023 19:07:11 -0700 Subject: [PATCH 1529/1547] Roll engine to 249cc9b8. (#136428) Rolls engine to 249cc9b86c45acb7e32b4097bc8a5059b91c888e. --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index a33d59193df0c..b0c5f21647be2 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -7ccdde78a7d174dc0bf0be77102b205e844c7998 +249cc9b86c45acb7e32b4097bc8a5059b91c888e From cd285a9aa829267d25435d6579d066af7fcee596 Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Tue, 17 Oct 2023 05:28:30 -0700 Subject: [PATCH 1530/1547] [flutter_tools] handle ERROR_INVALID_FUNCTION when trying to symlink across drives (#136681) CP of https://github.com/flutter/flutter/commit/9751fe64494d4d986d5196bda028e65544e644a0 Original issue: https://github.com/flutter/flutter/issues/66224 CP Request: https://github.com/flutter/flutter/issues/136680 --- .../flutter_tools/lib/src/flutter_plugins.dart | 8 ++++++++ .../test/general.shard/plugins_test.dart | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/packages/flutter_tools/lib/src/flutter_plugins.dart b/packages/flutter_tools/lib/src/flutter_plugins.dart index 87880d7583b83..fd38dd79be11c 100644 --- a/packages/flutter_tools/lib/src/flutter_plugins.dart +++ b/packages/flutter_tools/lib/src/flutter_plugins.dart @@ -1035,6 +1035,14 @@ void handleSymlinkException(FileSystemException e, { : 'You must build from a terminal run as administrator.'; throwToolExit('Building with plugins requires symlink support.\n\n$instructions'); } + // ERROR_INVALID_FUNCTION, trying to link across drives, which is not supported + if (e.osError?.errorCode == 1) { + throwToolExit( + 'Creating symlink from $source to $destination failed with ' + 'ERROR_INVALID_FUNCTION. Try moving your Flutter project to the same ' + 'drive as your Flutter SDK.', + ); + } } } diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart index 811b3fd84f2ce..8efcbefca3456 100644 --- a/packages/flutter_tools/test/general.shard/plugins_test.dart +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart @@ -1690,6 +1690,24 @@ flutter: ); }); + testWithoutContext('Symlink failures instruct developers to have their project on the same drive as their SDK', () async { + final Platform platform = FakePlatform(operatingSystem: 'windows'); + final FakeOperatingSystemUtils os = FakeOperatingSystemUtils('Microsoft Windows [Version 10.0.14972]'); + + const FileSystemException e = FileSystemException('', '', OSError('', 1)); + + expect( + () => handleSymlinkException( + e, + platform: platform, + os: os, + source: pubCachePath, + destination: ephemeralPackagePath, + ), + throwsToolExit(message: 'Try moving your Flutter project to the same drive as your Flutter SDK'), + ); + }); + testWithoutContext('Symlink failures only give instructions for specific errors', () async { final Platform platform = FakePlatform(operatingSystem: 'windows'); final FakeOperatingSystemUtils os = FakeOperatingSystemUtils('Microsoft Windows [Version 10.0.14393]'); From 180a8582e4d1bc11aabdf5e18c397edae4edae05 Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Tue, 17 Oct 2023 18:02:16 -0700 Subject: [PATCH 1531/1547] update analytics in generate api docs site to use new UA4 (#136497) (#136742) Original tracking issue: https://github.com/flutter/flutter/issues/136741 CP request: https://github.com/flutter/flutter/issues/136743 Change the analytics instance that the generated api.flutter.dev and master-api.flutter.dev use. --- dev/docs/analytics-footer.html | 4 + dev/docs/analytics-header.html | 7 + dev/docs/analytics.html | 9 - dev/tools/create_api_docs.dart | 25 ++- dev/tools/dartdoc_checker.dart | 47 +++-- dev/tools/test/create_api_docs_test.dart | 230 +++++++++++++++++++++++ 6 files changed, 287 insertions(+), 35 deletions(-) create mode 100644 dev/docs/analytics-footer.html create mode 100644 dev/docs/analytics-header.html delete mode 100644 dev/docs/analytics.html diff --git a/dev/docs/analytics-footer.html b/dev/docs/analytics-footer.html new file mode 100644 index 0000000000000..133ecf3bd3e73 --- /dev/null +++ b/dev/docs/analytics-footer.html @@ -0,0 +1,4 @@ +<!-- Google Tag Manager (noscript) --> +<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-ND4LWWZ" +height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> +<!-- End Google Tag Manager (noscript) --> diff --git a/dev/docs/analytics-header.html b/dev/docs/analytics-header.html new file mode 100644 index 0000000000000..bed0852361406 --- /dev/null +++ b/dev/docs/analytics-header.html @@ -0,0 +1,7 @@ +<!-- Google Tag Manager --> +<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': +new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], +j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= +'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f) +})(window,document,'script','dataLayer','GTM-ND4LWWZ');</script> +<!-- End Google Tag Manager --> diff --git a/dev/docs/analytics.html b/dev/docs/analytics.html deleted file mode 100644 index ee11d34b06003..0000000000000 --- a/dev/docs/analytics.html +++ /dev/null @@ -1,9 +0,0 @@ -<script> - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-67589403-1', 'auto'); - ga('send', 'pageview'); -</script> diff --git a/dev/tools/create_api_docs.dart b/dev/tools/create_api_docs.dart index 87c556e98a612..56f6c32695a23 100644 --- a/dev/tools/create_api_docs.dart +++ b/dev/tools/create_api_docs.dart @@ -518,9 +518,9 @@ class DartdocGenerator { final Version version = FlutterInformation.instance.getFlutterVersion(); // Verify which version of snippets and dartdoc we're using. - final ProcessResult snippetsResult = Process.runSync( - FlutterInformation.instance.getFlutterBinaryPath().path, + final ProcessResult snippetsResult = processManager.runSync( <String>[ + FlutterInformation.instance.getFlutterBinaryPath().path, 'pub', 'global', 'list', @@ -574,13 +574,15 @@ class DartdocGenerator { '--header', docsRoot.childFile('styles.html').path, '--header', - docsRoot.childFile('analytics.html').path, + docsRoot.childFile('analytics-header.html').path, '--header', docsRoot.childFile('survey.html').path, '--header', docsRoot.childFile('snippets.html').path, '--header', docsRoot.childFile('opensearch.html').path, + '--footer', + docsRoot.childFile('analytics-footer.html').path, '--footer-text', packageRoot.childFile('footer.html').path, '--allow-warnings-in-packages', @@ -643,6 +645,7 @@ class DartdocGenerator { arguments: dartdocArgs, workingDirectory: packageRoot, environment: pubEnvironment, + processManager: processManager, )); printStream( process.stdout, @@ -669,7 +672,7 @@ class DartdocGenerator { } _sanityCheckDocs(); - checkForUnresolvedDirectives(publishRoot.childDirectory('flutter').path); + checkForUnresolvedDirectives(publishRoot.childDirectory('flutter')); _createIndexAndCleanup(); @@ -690,12 +693,13 @@ class DartdocGenerator { } } - /// Runs a sanity check by running a test. - void _sanityCheckDocs([Platform platform = const LocalPlatform()]) { + /// A subset of all generated doc files for [_sanityCheckDocs]. + @visibleForTesting + List<File> get canaries { final Directory flutterDirectory = publishRoot.childDirectory('flutter'); final Directory widgetsDirectory = flutterDirectory.childDirectory('widgets'); - final List<File> canaries = <File>[ + return <File>[ publishRoot.childDirectory('assets').childFile('overrides.css'), flutterDirectory.childDirectory('dart-io').childFile('File-class.html'), flutterDirectory.childDirectory('dart-ui').childFile('Canvas-class.html'), @@ -710,12 +714,19 @@ class DartdocGenerator { widgetsDirectory.childFile('Widget-class.html'), widgetsDirectory.childFile('Listener-class.html'), ]; + } + + /// Runs a sanity check by running a test. + void _sanityCheckDocs([Platform platform = const LocalPlatform()]) { for (final File canary in canaries) { if (!canary.existsSync()) { throw Exception('Missing "${canary.path}", which probably means the documentation failed to build correctly.'); } } // Make sure at least one example of each kind includes source code. + final Directory widgetsDirectory = publishRoot + .childDirectory('flutter') + .childDirectory('widgets'); // Check a "sample" example, any one will do. _sanityCheckExample( diff --git a/dev/tools/dartdoc_checker.dart b/dev/tools/dartdoc_checker.dart index 75fbd2be38761..cbc47f8540e10 100644 --- a/dev/tools/dartdoc_checker.dart +++ b/dev/tools/dartdoc_checker.dart @@ -4,9 +4,31 @@ import 'dart:io'; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -/// Scans the dartdoc HTML output in the provided `htmlOutputPath` for +/// Makes sure that the path we were given contains some of the expected +/// libraries. +@visibleForTesting +const List<String> dartdocDirectiveCanaryLibraries = <String>[ + 'animation', + 'cupertino', + 'material', + 'widgets', + 'rendering', + 'flutter_driver', +]; + +/// Makes sure that the path we were given contains some of the expected +/// HTML files. +@visibleForTesting +const List<String> dartdocDirectiveCanaryFiles = <String>[ + 'Widget-class.html', + 'Material-class.html', + 'Canvas-class.html', +]; + +/// Scans the dartdoc HTML output in the provided `dartDocDir` for /// unresolved dartdoc directives (`{@foo x y}`). /// /// Dartdoc usually replaces those directives with other content. However, @@ -22,27 +44,14 @@ import 'package:path/path.dart' as path; /// ``` /// void foo({@required int bar}); /// ``` -void checkForUnresolvedDirectives(String htmlOutputPath) { - final Directory dartDocDir = Directory(htmlOutputPath); +void checkForUnresolvedDirectives(Directory dartDocDir) { if (!dartDocDir.existsSync()) { throw Exception('Directory with dartdoc output (${dartDocDir.path}) does not exist.'); } - // Makes sure that the path we were given contains some of the expected - // libraries and HTML files. - final List<String> canaryLibraries = <String>[ - 'animation', - 'cupertino', - 'material', - 'widgets', - 'rendering', - 'flutter_driver', - ]; - final List<String> canaryFiles = <String>[ - 'Widget-class.html', - 'Material-class.html', - 'Canvas-class.html', - ]; + // Make a copy since this will be mutated + final List<String> canaryLibraries = dartdocDirectiveCanaryLibraries.toList(); + final List<String> canaryFiles = dartdocDirectiveCanaryFiles.toList(); print('Scanning for unresolved dartdoc directives...'); @@ -112,5 +121,5 @@ void main(List<String> args) { if (!Directory(args.single).existsSync()) { throw Exception('The dartdoc HTML output directory ${args.single} does not exist.'); } - checkForUnresolvedDirectives(args.single); + checkForUnresolvedDirectives(Directory(args.single)); } diff --git a/dev/tools/test/create_api_docs_test.dart b/dev/tools/test/create_api_docs_test.dart index 6f98d1fae746e..bc557b157a6a0 100644 --- a/dev/tools/test/create_api_docs_test.dart +++ b/dev/tools/test/create_api_docs_test.dart @@ -10,6 +10,7 @@ import 'package:test/test.dart'; import '../../../packages/flutter_tools/test/src/fake_process_manager.dart'; import '../create_api_docs.dart' as apidocs; +import '../dartdoc_checker.dart'; void main() { group('FlutterInformation', () { @@ -195,6 +196,235 @@ void main() { expect(info['engineRealm'], equals('realm')); }); }); + + group('DartDocGenerator', () { + late apidocs.DartdocGenerator generator; + late MemoryFileSystem fs; + late FakeProcessManager processManager; + late Directory publishRoot; + + setUp(() { + fs = MemoryFileSystem.test(); + publishRoot = fs.directory('/path/to/publish'); + processManager = FakeProcessManager.empty(); + generator = apidocs.DartdocGenerator( + packageRoot: fs.directory('/path/to/package'), + publishRoot: publishRoot, + docsRoot: fs.directory('/path/to/docs'), + filesystem: fs, + processManager: processManager, + ); + final Directory repoRoot = fs.directory('/flutter'); + repoRoot.childDirectory('packages').createSync(recursive: true); + apidocs.FlutterInformation.instance = apidocs.FlutterInformation( + filesystem: fs, + processManager: processManager, + platform: FakePlatform(environment: <String, String>{ + 'FLUTTER_ROOT': repoRoot.path, + }), + ); + }); + + test('.generateDartDoc() invokes dartdoc with the correct command line arguments', () async { + processManager.addCommands(<FakeCommand>[ + const FakeCommand(command: <String>['/flutter/bin/flutter', 'pub', 'get']), + const FakeCommand( + command: <String>['/flutter/bin/flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + const FakeCommand( + command: <Pattern>['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + const FakeCommand( + command: <String>['git', 'rev-parse', 'HEAD'], + ), + const FakeCommand( + command: <String>['/flutter/bin/flutter', 'pub', 'global', 'list'], + ), + FakeCommand( + command: <Pattern>[ + '/flutter/bin/flutter', + 'pub', + 'global', + 'run', + '--enable-asserts', + 'dartdoc', + '--output', + '/path/to/publish/flutter', + '--allow-tools', + '--json', + '--validate-links', + '--link-to-source-excludes', + '/flutter/bin/cache', + '--link-to-source-root', + '/flutter', + '--link-to-source-uri-template', + 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', + '--inject-html', + '--use-base-href', + '--header', + '/path/to/docs/styles.html', + '--header', + '/path/to/docs/analytics-header.html', + '--header', + '/path/to/docs/survey.html', + '--header', + '/path/to/docs/snippets.html', + '--header', + '/path/to/docs/opensearch.html', + '--footer', + '/path/to/docs/analytics-footer.html', + '--footer-text', + '/path/to/package/footer.html', + '--allow-warnings-in-packages', + // match package names + RegExp(r'^(\w+,)+(\w+)$'), + '--exclude-packages', + RegExp(r'^(\w+,)+(\w+)$'), + '--exclude', + // match dart package URIs + RegExp(r'^([\w\/:.]+,)+([\w\/:.]+)$'), + '--favicon', + '/path/to/docs/favicon.ico', + '--package-order', + 'flutter,Dart,${apidocs.kPlatformIntegrationPackageName},flutter_test,flutter_driver', + '--auto-include-dependencies', + ], + ), + ]); + + // This will throw while sanity checking generated files, which is tested independently + await expectLater( + () => generator.generateDartdoc(), + throwsA( + isA<Exception>().having( + (Exception e) => e.toString(), + 'message', + contains(RegExp(r'Missing .* which probably means the documentation failed to build correctly.')), + ), + ), + ); + + expect(processManager, hasNoRemainingExpectations); + }); + + test('sanity checks spot check generated files', () async { + processManager.addCommands(<FakeCommand>[ + const FakeCommand(command: <String>['/flutter/bin/flutter', 'pub', 'get']), + const FakeCommand( + command: <String>['/flutter/bin/flutter', '--version', '--machine'], + stdout: testVersionInfo, + ), + const FakeCommand( + command: <Pattern>['git', 'status', '-b', '--porcelain'], + stdout: '## $branchName', + ), + const FakeCommand( + command: <String>['git', 'rev-parse', 'HEAD'], + ), + const FakeCommand( + command: <String>['/flutter/bin/flutter', 'pub', 'global', 'list'], + ), + FakeCommand( + command: <Pattern>[ + '/flutter/bin/flutter', + 'pub', + 'global', + 'run', + '--enable-asserts', + 'dartdoc', + '--output', + '/path/to/publish/flutter', + '--allow-tools', + '--json', + '--validate-links', + '--link-to-source-excludes', + '/flutter/bin/cache', + '--link-to-source-root', + '/flutter', + '--link-to-source-uri-template', + 'https://github.com/flutter/flutter/blob/master/%f%#L%l%', + '--inject-html', + '--use-base-href', + '--header', + '/path/to/docs/styles.html', + '--header', + '/path/to/docs/analytics-header.html', + '--header', + '/path/to/docs/survey.html', + '--header', + '/path/to/docs/snippets.html', + '--header', + '/path/to/docs/opensearch.html', + '--footer', + '/path/to/docs/analytics-footer.html', + '--footer-text', + '/path/to/package/footer.html', + '--allow-warnings-in-packages', + // match package names + RegExp(r'^(\w+,)+(\w+)$'), + '--exclude-packages', + RegExp(r'^(\w+,)+(\w+)$'), + '--exclude', + // match dart package URIs + RegExp(r'^([\w\/:.]+,)+([\w\/:.]+)$'), + '--favicon', + '/path/to/docs/favicon.ico', + '--package-order', + 'flutter,Dart,${apidocs.kPlatformIntegrationPackageName},flutter_test,flutter_driver', + '--auto-include-dependencies', + ], + onRun: () { + for (final File canary in generator.canaries) { + canary.createSync(recursive: true); + } + for (final String path in dartdocDirectiveCanaryFiles) { + publishRoot.childDirectory('flutter').childFile(path).createSync(recursive: true); + } + for (final String path in dartdocDirectiveCanaryLibraries) { + publishRoot.childDirectory('flutter').childDirectory(path).createSync(recursive: true); + } + publishRoot.childDirectory('flutter').childFile('index.html').createSync(); + + final Directory widgetsDir = publishRoot + .childDirectory('flutter') + .childDirectory('widgets') + ..createSync(recursive: true); + widgetsDir.childFile('showGeneralDialog.html').writeAsStringSync(''' +<pre id="longSnippet1"> + <code class="language-dart"> + import 'package:flutter/material.dart'; + </code> +</pre> +''', + ); + expect(publishRoot.childDirectory('flutter').existsSync(), isTrue); + (widgetsDir + .childDirectory('ModalRoute') + ..createSync(recursive: true)) + .childFile('barrierColor.html') + .writeAsStringSync(''' +<pre id="sample-code"> + <code class="language-dart"> + class FooClass { + Color get barrierColor => FooColor(); + } + </code> +</pre> +'''); + const String queryParams = 'split=1&run=true&sample_id=widgets.Listener.123&sample_channel=master&channel=master'; + widgetsDir.childFile('Listener-class.html').writeAsStringSync(''' +<iframe class="snippet-dartpad" src="https://dartpad.dev/embed-flutter.html?$queryParams"> +</iframe> +'''); + } + ), + ]); + + await generator.generateDartdoc(); + }); + }); } const String branchName = 'stable'; From f00b8f510095945944cc55b91495a00ec310d1a4 Mon Sep 17 00:00:00 2001 From: Camille Simon <43054281+camsim99@users.noreply.github.com> Date: Wed, 18 Oct 2023 05:14:19 +0000 Subject: [PATCH 1532/1547] [CP][Android] Update Java/AGP/Gradle warning compatible Java range (#136766) Cherry-pick for https://github.com/flutter/flutter/issues/136388. --- packages/flutter_tools/lib/src/commands/create.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 191f92c1c65aa..97d70b067288a 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -968,7 +968,7 @@ String getIncompatibleJavaGradleAgpMessageHeader( final String incompatibleDependencyVersion = javaGradleVersionsCompatible ? 'AGP version $templateAgpVersion' : 'Gradle version $templateGradleVersion'; final VersionRange validJavaRange = gradle.getJavaVersionFor(gradleV: templateGradleVersion, agpV: templateAgpVersion); // validJavaRange should have non-null verisonMin and versionMax since it based on our template AGP and Gradle versions. - final String validJavaRangeMessage = '(minimum compatible version: ${validJavaRange.versionMin!}, maximum compatible version: ${validJavaRange.versionMax!})'; + final String validJavaRangeMessage = '(Java ${validJavaRange.versionMin!} <= compatible Java version < Java ${validJavaRange.versionMax!})'; return ''' The configured version of Java detected may conflict with the $incompatibleDependency version in your new Flutter $projectType. From 476aa717cd342d11e16439b71f4f4c9209c50712 Mon Sep 17 00:00:00 2001 From: Kevin Chisholm <kevinjchisholm@google.com> Date: Thu, 19 Oct 2023 20:10:52 -0500 Subject: [PATCH 1533/1547] [flutter_releases] Flutter beta 3.16.0-0.3.pre Framework Cherrypicks (#136932) # Flutter beta 3.16.0-0.3.pre Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index b0c5f21647be2..7d6a0b7836dea 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -249cc9b86c45acb7e32b4097bc8a5059b91c888e +91cde06da08323f25bd4bcc4a1832862f2b58c08 From 4e5e12e93327ad9f38d267e789b6c996f8a95852 Mon Sep 17 00:00:00 2001 From: Srujan Gaddam <58529443+srujzs@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:15:07 -0700 Subject: [PATCH 1534/1547] Cherry-pick package:web update to version 0.3.0 from 0.2.1-beta (#137195) This cherry-picks only the package:web version changes from #132445, and any changes needed to work with the new version. Helps enable https://github.com/flutter/flutter/issues/136405. --- dev/a11y_assessments/pubspec.yaml | 4 ++-- dev/automated_tests/pubspec.yaml | 4 ++-- dev/benchmarks/complex_layout/pubspec.yaml | 4 ++-- dev/benchmarks/macrobenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/microbenchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/multiple_flutters/module/pubspec.yaml | 4 ++-- dev/benchmarks/platform_channels_benchmarks/pubspec.yaml | 4 ++-- dev/benchmarks/platform_views_layout/pubspec.yaml | 4 ++-- .../platform_views_layout_hybrid_composition/pubspec.yaml | 4 ++-- dev/benchmarks/test_apps/stocks/pubspec.yaml | 4 ++-- dev/bots/pubspec.yaml | 4 ++-- dev/devicelab/pubspec.yaml | 4 ++-- dev/integration_tests/abstract_method_smoke_test/pubspec.yaml | 4 ++-- .../android_embedding_v2_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/android_semantics_testing/pubspec.yaml | 4 ++-- dev/integration_tests/android_views/pubspec.yaml | 4 ++-- dev/integration_tests/channels/pubspec.yaml | 4 ++-- dev/integration_tests/deferred_components_test/pubspec.yaml | 4 ++-- dev/integration_tests/external_ui/pubspec.yaml | 4 ++-- dev/integration_tests/flavors/pubspec.yaml | 4 ++-- dev/integration_tests/flutter_gallery/pubspec.yaml | 4 ++-- dev/integration_tests/gradle_deprecated_settings/pubspec.yaml | 4 ++-- dev/integration_tests/hybrid_android_views/pubspec.yaml | 4 ++-- .../ios_add2app_life_cycle/flutterapp/pubspec.yaml | 4 ++-- dev/integration_tests/ios_app_with_extensions/pubspec.yaml | 4 ++-- dev/integration_tests/ios_platform_view_tests/pubspec.yaml | 4 ++-- dev/integration_tests/non_nullable/pubspec.yaml | 4 ++-- dev/integration_tests/platform_interaction/pubspec.yaml | 4 ++-- dev/integration_tests/release_smoke_test/pubspec.yaml | 4 ++-- dev/integration_tests/spell_check/pubspec.yaml | 4 ++-- dev/integration_tests/ui/pubspec.yaml | 4 ++-- dev/integration_tests/web/pubspec.yaml | 4 ++-- dev/integration_tests/web_compile_tests/pubspec.yaml | 4 ++-- dev/integration_tests/web_e2e_tests/pubspec.yaml | 4 ++-- dev/integration_tests/wide_gamut_test/pubspec.yaml | 4 ++-- dev/integration_tests/windows_startup_test/pubspec.yaml | 4 ++-- dev/manual_tests/pubspec.yaml | 4 ++-- dev/tools/vitool/pubspec.yaml | 4 ++-- dev/tracing_tests/pubspec.yaml | 4 ++-- examples/api/pubspec.yaml | 4 ++-- examples/flutter_view/pubspec.yaml | 4 ++-- examples/hello_world/pubspec.yaml | 4 ++-- examples/image_list/pubspec.yaml | 4 ++-- examples/layers/pubspec.yaml | 4 ++-- examples/platform_channel/pubspec.yaml | 4 ++-- examples/platform_channel_swift/pubspec.yaml | 4 ++-- examples/platform_view/pubspec.yaml | 4 ++-- examples/splash/pubspec.yaml | 4 ++-- examples/texture/pubspec.yaml | 4 ++-- .../widgets/_platform_selectable_region_context_menu_web.dart | 2 +- packages/flutter/pubspec.yaml | 4 ++-- packages/flutter/test_private/test/pubspec.yaml | 4 ++-- packages/flutter_driver/pubspec.yaml | 4 ++-- packages/flutter_goldens/pubspec.yaml | 4 ++-- packages/flutter_localizations/pubspec.yaml | 4 ++-- packages/flutter_test/pubspec.yaml | 4 ++-- packages/flutter_web_plugins/pubspec.yaml | 4 ++-- packages/integration_test/example/pubspec.yaml | 4 ++-- packages/integration_test/integration_test_macos/pubspec.yaml | 4 ++-- packages/integration_test/pubspec.yaml | 4 ++-- 60 files changed, 119 insertions(+), 119 deletions(-) diff --git a/dev/a11y_assessments/pubspec.yaml b/dev/a11y_assessments/pubspec.yaml index 6d71cbeb20859..c5670ebb97cc1 100644 --- a/dev/a11y_assessments/pubspec.yaml +++ b/dev/a11y_assessments/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -35,4 +35,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0c69 +# PUBSPEC CHECKSUM: dc9e diff --git a/dev/automated_tests/pubspec.yaml b/dev/automated_tests/pubspec.yaml index e9cac0aa1de43..cbb1f6f65f8a8 100644 --- a/dev/automated_tests/pubspec.yaml +++ b/dev/automated_tests/pubspec.yaml @@ -62,7 +62,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -72,4 +72,4 @@ flutter: assets: - icon/test.png -# PUBSPEC CHECKSUM: 7c7b +# PUBSPEC CHECKSUM: 29b0 diff --git a/dev/benchmarks/complex_layout/pubspec.yaml b/dev/benchmarks/complex_layout/pubspec.yaml index 9c768c180f9d0..89380badb866a 100644 --- a/dev/benchmarks/complex_layout/pubspec.yaml +++ b/dev/benchmarks/complex_layout/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -83,4 +83,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: de52 +# PUBSPEC CHECKSUM: d287 diff --git a/dev/benchmarks/macrobenchmarks/pubspec.yaml b/dev/benchmarks/macrobenchmarks/pubspec.yaml index 6d17bc023a845..8956855932a47 100644 --- a/dev/benchmarks/macrobenchmarks/pubspec.yaml +++ b/dev/benchmarks/macrobenchmarks/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # flutter update-packages --force-upgrade flutter_gallery_assets: 1.0.2 - web: 0.2.1-beta + web: 0.3.0 async: 2.11.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" boolean_selector: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -210,4 +210,4 @@ flutter: fonts: - asset: packages/flutter_gallery_assets/fonts/GalleryIcons.ttf -# PUBSPEC CHECKSUM: de52 +# PUBSPEC CHECKSUM: d287 diff --git a/dev/benchmarks/microbenchmarks/pubspec.yaml b/dev/benchmarks/microbenchmarks/pubspec.yaml index 75dee25045c26..0c91c7ef6683a 100644 --- a/dev/benchmarks/microbenchmarks/pubspec.yaml +++ b/dev/benchmarks/microbenchmarks/pubspec.yaml @@ -63,7 +63,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -137,4 +137,4 @@ flutter: - packages/flutter_gallery_assets/people/square/stella.png - packages/flutter_gallery_assets/people/square/trevor.png -# PUBSPEC CHECKSUM: 1fc9 +# PUBSPEC CHECKSUM: bcfe diff --git a/dev/benchmarks/multiple_flutters/module/pubspec.yaml b/dev/benchmarks/multiple_flutters/module/pubspec.yaml index afb1401267411..eacd619a209a9 100644 --- a/dev/benchmarks/multiple_flutters/module/pubspec.yaml +++ b/dev/benchmarks/multiple_flutters/module/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -48,4 +48,4 @@ flutter: androidPackage: com.example.multiple_flutters_module iosBundleIdentifier: com.example.multipleFluttersModule -# PUBSPEC CHECKSUM: 23fb +# PUBSPEC CHECKSUM: 5c31 diff --git a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml index e795850a56429..97c7fe140ce69 100644 --- a/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml +++ b/dev/benchmarks/platform_channels_benchmarks/pubspec.yaml @@ -64,7 +64,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 15b5 +# PUBSPEC CHECKSUM: 7bea diff --git a/dev/benchmarks/platform_views_layout/pubspec.yaml b/dev/benchmarks/platform_views_layout/pubspec.yaml index b2fed493c9570..cd9dc6f60c4ee 100644 --- a/dev/benchmarks/platform_views_layout/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: de52 +# PUBSPEC CHECKSUM: d287 diff --git a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml index 7da9277564103..446a0b58dcec3 100644 --- a/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml +++ b/dev/benchmarks/platform_views_layout_hybrid_composition/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -81,4 +81,4 @@ flutter: - packages/flutter_gallery_assets/people/square/ali.png - packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png -# PUBSPEC CHECKSUM: de52 +# PUBSPEC CHECKSUM: d287 diff --git a/dev/benchmarks/test_apps/stocks/pubspec.yaml b/dev/benchmarks/test_apps/stocks/pubspec.yaml index ac0731a83c091..526153083cc05 100644 --- a/dev/benchmarks/test_apps/stocks/pubspec.yaml +++ b/dev/benchmarks/test_apps/stocks/pubspec.yaml @@ -25,7 +25,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -76,4 +76,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: cb74 +# PUBSPEC CHECKSUM: 6aa9 diff --git a/dev/bots/pubspec.yaml b/dev/bots/pubspec.yaml index a81f4bd8512fd..6585d67631c46 100644 --- a/dev/bots/pubspec.yaml +++ b/dev/bots/pubspec.yaml @@ -65,7 +65,7 @@ dependencies: typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xml: 6.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dependencies: dev_dependencies: test_api: 0.6.1 -# PUBSPEC CHECKSUM: 86cc +# PUBSPEC CHECKSUM: a602 diff --git a/dev/devicelab/pubspec.yaml b/dev/devicelab/pubspec.yaml index a3ca142e8fd5e..90b762ac6afbf 100644 --- a/dev/devicelab/pubspec.yaml +++ b/dev/devicelab/pubspec.yaml @@ -21,7 +21,7 @@ dependencies: shelf_static: 1.1.2 stack_trace: 1.11.1 vm_service: 11.10.0 - web: 0.2.1-beta + web: 0.3.0 webkit_inspection_protocol: 1.2.1 xml: 6.4.2 @@ -72,4 +72,4 @@ dev_dependencies: watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: c63a +# PUBSPEC CHECKSUM: a06f diff --git a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml index 3dd766b495c37..60ef22f5567c6 100644 --- a/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml +++ b/dev/integration_tests/abstract_method_smoke_test/pubspec.yaml @@ -15,9 +15,9 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0ae4 +# PUBSPEC CHECKSUM: 081a diff --git a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml index db54176660212..ef0bf621f8f40 100644 --- a/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml +++ b/dev/integration_tests/android_embedding_v2_smoke_test/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -96,4 +96,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 103e +# PUBSPEC CHECKSUM: 9073 diff --git a/dev/integration_tests/android_semantics_testing/pubspec.yaml b/dev/integration_tests/android_semantics_testing/pubspec.yaml index 672ac5a2c26ea..193980c8007cb 100644 --- a/dev/integration_tests/android_semantics_testing/pubspec.yaml +++ b/dev/integration_tests/android_semantics_testing/pubspec.yaml @@ -58,7 +58,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -66,4 +66,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: a372 +# PUBSPEC CHECKSUM: aaa7 diff --git a/dev/integration_tests/android_views/pubspec.yaml b/dev/integration_tests/android_views/pubspec.yaml index 16e4bb7ac4f7d..891258bf5eae1 100644 --- a/dev/integration_tests/android_views/pubspec.yaml +++ b/dev/integration_tests/android_views/pubspec.yaml @@ -46,7 +46,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -92,4 +92,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: aeb0 +# PUBSPEC CHECKSUM: 15e5 diff --git a/dev/integration_tests/channels/pubspec.yaml b/dev/integration_tests/channels/pubspec.yaml index cc9c8a637bc84..0b4e90a193f94 100644 --- a/dev/integration_tests/channels/pubspec.yaml +++ b/dev/integration_tests/channels/pubspec.yaml @@ -13,7 +13,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -43,4 +43,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: e584 +# PUBSPEC CHECKSUM: 53b9 diff --git a/dev/integration_tests/deferred_components_test/pubspec.yaml b/dev/integration_tests/deferred_components_test/pubspec.yaml index d6eb5693b0e49..37a3d05d33e02 100644 --- a/dev/integration_tests/deferred_components_test/pubspec.yaml +++ b/dev/integration_tests/deferred_components_test/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -80,4 +80,4 @@ flutter: assets: - customassets/flutter_logo.png -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/dev/integration_tests/external_ui/pubspec.yaml b/dev/integration_tests/external_ui/pubspec.yaml index a6a5107e46531..19f981355470b 100644 --- a/dev/integration_tests/external_ui/pubspec.yaml +++ b/dev/integration_tests/external_ui/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ebfa +# PUBSPEC CHECKSUM: 4930 diff --git a/dev/integration_tests/flavors/pubspec.yaml b/dev/integration_tests/flavors/pubspec.yaml index c67b1791e4d41..dcb4d71a0bb52 100644 --- a/dev/integration_tests/flavors/pubspec.yaml +++ b/dev/integration_tests/flavors/pubspec.yaml @@ -58,7 +58,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -74,4 +74,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/dev/integration_tests/flutter_gallery/pubspec.yaml b/dev/integration_tests/flutter_gallery/pubspec.yaml index 1fc8421f36c5a..e853f48a7d43e 100644 --- a/dev/integration_tests/flutter_gallery/pubspec.yaml +++ b/dev/integration_tests/flutter_gallery/pubspec.yaml @@ -49,7 +49,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_platform_interface: 5.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" video_player_web: 2.0.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -276,4 +276,4 @@ flutter: - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Regular.ttf - asset: packages/flutter_gallery_assets/fonts/merriweather/Merriweather-Light.ttf -# PUBSPEC CHECKSUM: fd6b +# PUBSPEC CHECKSUM: f6a0 diff --git a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml index 7ec1495bdcdc1..3abbe1967f77d 100644 --- a/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml +++ b/dev/integration_tests/gradle_deprecated_settings/pubspec.yaml @@ -34,9 +34,9 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 265f +# PUBSPEC CHECKSUM: 5b94 diff --git a/dev/integration_tests/hybrid_android_views/pubspec.yaml b/dev/integration_tests/hybrid_android_views/pubspec.yaml index c471c69ebcb92..2b26016fbe905 100644 --- a/dev/integration_tests/hybrid_android_views/pubspec.yaml +++ b/dev/integration_tests/hybrid_android_views/pubspec.yaml @@ -44,7 +44,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" win32: 5.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" xdg_directories: 1.0.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: aeb0 +# PUBSPEC CHECKSUM: 15e5 diff --git a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml index f1fbc13f76144..2f9a8e9595246 100644 --- a/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml +++ b/dev/integration_tests/ios_add2app_life_cycle/flutterapp/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -99,4 +99,4 @@ flutter: androidPackage: com.example.iosadd2appflutter iosBundleIdentifier: com.example.iosAdd2appFlutter -# PUBSPEC CHECKSUM: 4112 +# PUBSPEC CHECKSUM: 7b47 diff --git a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml index 94a23a2b992a7..3d614796d5eee 100644 --- a/dev/integration_tests/ios_app_with_extensions/pubspec.yaml +++ b/dev/integration_tests/ios_app_with_extensions/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" plugin_platform_interface: 2.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -91,4 +91,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 8498 +# PUBSPEC CHECKSUM: 7dcd diff --git a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml index 19fd1544729ca..b415fb1ec3315 100644 --- a/dev/integration_tests/ios_platform_view_tests/pubspec.yaml +++ b/dev/integration_tests/ios_platform_view_tests/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -77,4 +77,4 @@ flutter: # the material Icons class. uses-material-design: true -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/dev/integration_tests/non_nullable/pubspec.yaml b/dev/integration_tests/non_nullable/pubspec.yaml index 9d9ff91c3c002..58dcb97e808b6 100644 --- a/dev/integration_tests/non_nullable/pubspec.yaml +++ b/dev/integration_tests/non_nullable/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -39,4 +39,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 4112 +# PUBSPEC CHECKSUM: 7b47 diff --git a/dev/integration_tests/platform_interaction/pubspec.yaml b/dev/integration_tests/platform_interaction/pubspec.yaml index 303ccd4b08b5e..2112c89e5a39b 100644 --- a/dev/integration_tests/platform_interaction/pubspec.yaml +++ b/dev/integration_tests/platform_interaction/pubspec.yaml @@ -56,7 +56,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -65,4 +65,4 @@ dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: ebfa +# PUBSPEC CHECKSUM: 4930 diff --git a/dev/integration_tests/release_smoke_test/pubspec.yaml b/dev/integration_tests/release_smoke_test/pubspec.yaml index 5e7915978095f..f2b1ffea44aa7 100644 --- a/dev/integration_tests/release_smoke_test/pubspec.yaml +++ b/dev/integration_tests/release_smoke_test/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 474b +# PUBSPEC CHECKSUM: 4580 diff --git a/dev/integration_tests/spell_check/pubspec.yaml b/dev/integration_tests/spell_check/pubspec.yaml index e12b8bb8255eb..ca226f3063a04 100644 --- a/dev/integration_tests/spell_check/pubspec.yaml +++ b/dev/integration_tests/spell_check/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -106,4 +106,4 @@ flutter: # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages -# PUBSPEC CHECKSUM: 85f3 +# PUBSPEC CHECKSUM: ec29 diff --git a/dev/integration_tests/ui/pubspec.yaml b/dev/integration_tests/ui/pubspec.yaml index 27ceab81fa333..53d503489830f 100644 --- a/dev/integration_tests/ui/pubspec.yaml +++ b/dev/integration_tests/ui/pubspec.yaml @@ -57,7 +57,7 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" @@ -76,4 +76,4 @@ flutter: assets: - assets/foo.png -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/dev/integration_tests/web/pubspec.yaml b/dev/integration_tests/web/pubspec.yaml index 55d8197a797e1..82206b225ab8a 100644 --- a/dev/integration_tests/web/pubspec.yaml +++ b/dev/integration_tests/web/pubspec.yaml @@ -19,6 +19,6 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0ae4 +# PUBSPEC CHECKSUM: 081a diff --git a/dev/integration_tests/web_compile_tests/pubspec.yaml b/dev/integration_tests/web_compile_tests/pubspec.yaml index 10c74337b573f..c8212be4e4691 100644 --- a/dev/integration_tests/web_compile_tests/pubspec.yaml +++ b/dev/integration_tests/web_compile_tests/pubspec.yaml @@ -11,6 +11,6 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0ae4 +# PUBSPEC CHECKSUM: 081a diff --git a/dev/integration_tests/web_e2e_tests/pubspec.yaml b/dev/integration_tests/web_e2e_tests/pubspec.yaml index a8fdd163c0366..da6afe4a57125 100644 --- a/dev/integration_tests/web_e2e_tests/pubspec.yaml +++ b/dev/integration_tests/web_e2e_tests/pubspec.yaml @@ -42,7 +42,7 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: @@ -84,4 +84,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 1d9e +# PUBSPEC CHECKSUM: 16d3 diff --git a/dev/integration_tests/wide_gamut_test/pubspec.yaml b/dev/integration_tests/wide_gamut_test/pubspec.yaml index b86f9c131a842..2ff9b6fb8376e 100644 --- a/dev/integration_tests/wide_gamut_test/pubspec.yaml +++ b/dev/integration_tests/wide_gamut_test/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -41,4 +41,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 474b +# PUBSPEC CHECKSUM: 4580 diff --git a/dev/integration_tests/windows_startup_test/pubspec.yaml b/dev/integration_tests/windows_startup_test/pubspec.yaml index 2cfd559220870..aadd2358a713d 100644 --- a/dev/integration_tests/windows_startup_test/pubspec.yaml +++ b/dev/integration_tests/windows_startup_test/pubspec.yaml @@ -56,10 +56,10 @@ dependencies: vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vm_service: 11.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" watcher: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" web_socket_channel: 2.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: ebfa +# PUBSPEC CHECKSUM: 4930 diff --git a/dev/manual_tests/pubspec.yaml b/dev/manual_tests/pubspec.yaml index 8c3a81f6230e8..66566439b726a 100644 --- a/dev/manual_tests/pubspec.yaml +++ b/dev/manual_tests/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 0c69 +# PUBSPEC CHECKSUM: dc9e diff --git a/dev/tools/vitool/pubspec.yaml b/dev/tools/vitool/pubspec.yaml index 2c3b726e05933..35e57e16f4242 100644 --- a/dev/tools/vitool/pubspec.yaml +++ b/dev/tools/vitool/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" petitparser: 6.0.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -37,4 +37,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3f13 +# PUBSPEC CHECKSUM: 1048 diff --git a/dev/tracing_tests/pubspec.yaml b/dev/tracing_tests/pubspec.yaml index 9fa6a4e0af07d..32813482959eb 100644 --- a/dev/tracing_tests/pubspec.yaml +++ b/dev/tracing_tests/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 474b +# PUBSPEC CHECKSUM: 4580 diff --git a/examples/api/pubspec.yaml b/examples/api/pubspec.yaml index 42a25c17013b8..4322738a0196a 100644 --- a/examples/api/pubspec.yaml +++ b/examples/api/pubspec.yaml @@ -20,7 +20,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: integration_test: @@ -90,4 +90,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 2aa3 +# PUBSPEC CHECKSUM: f0d8 diff --git a/examples/flutter_view/pubspec.yaml b/examples/flutter_view/pubspec.yaml index ce118d5f8fd8b..407113ff8d39e 100644 --- a/examples/flutter_view/pubspec.yaml +++ b/examples/flutter_view/pubspec.yaml @@ -13,11 +13,11 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: uses-material-design: true assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 0ae4 +# PUBSPEC CHECKSUM: 081a diff --git a/examples/hello_world/pubspec.yaml b/examples/hello_world/pubspec.yaml index 1c4bdbd16f182..2befaff6d42e9 100644 --- a/examples/hello_world/pubspec.yaml +++ b/examples/hello_world/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_driver: @@ -68,4 +68,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/examples/image_list/pubspec.yaml b/examples/image_list/pubspec.yaml index 9e5f4dab6d65a..05e2efeec22ae 100644 --- a/examples/image_list/pubspec.yaml +++ b/examples/image_list/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -54,4 +54,4 @@ flutter: assets: - images/coast.jpg -# PUBSPEC CHECKSUM: 4112 +# PUBSPEC CHECKSUM: 7b47 diff --git a/examples/layers/pubspec.yaml b/examples/layers/pubspec.yaml index d82f2d649cd5e..f9e606d8df83e 100644 --- a/examples/layers/pubspec.yaml +++ b/examples/layers/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -36,4 +36,4 @@ flutter: - services/data.json uses-material-design: true -# PUBSPEC CHECKSUM: 0c69 +# PUBSPEC CHECKSUM: dc9e diff --git a/examples/platform_channel/pubspec.yaml b/examples/platform_channel/pubspec.yaml index 8081c270ef527..5d7a463419ffb 100644 --- a/examples/platform_channel/pubspec.yaml +++ b/examples/platform_channel/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/examples/platform_channel_swift/pubspec.yaml b/examples/platform_channel_swift/pubspec.yaml index 34a5a2bbc5200..103ab89a822f3 100644 --- a/examples/platform_channel_swift/pubspec.yaml +++ b/examples/platform_channel_swift/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -71,4 +71,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: 9fb7 +# PUBSPEC CHECKSUM: 9dec diff --git a/examples/platform_view/pubspec.yaml b/examples/platform_view/pubspec.yaml index 1f512b1561296..6ccd26d43788c 100644 --- a/examples/platform_view/pubspec.yaml +++ b/examples/platform_view/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -20,4 +20,4 @@ flutter: assets: - assets/flutter-mark-square-64.png -# PUBSPEC CHECKSUM: 0ae4 +# PUBSPEC CHECKSUM: 081a diff --git a/examples/splash/pubspec.yaml b/examples/splash/pubspec.yaml index f87573007a315..4f3ec9a334fc0 100644 --- a/examples/splash/pubspec.yaml +++ b/examples/splash/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -31,4 +31,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0c69 +# PUBSPEC CHECKSUM: dc9e diff --git a/examples/texture/pubspec.yaml b/examples/texture/pubspec.yaml index 726bfb44501dd..04b34856895e1 100644 --- a/examples/texture/pubspec.yaml +++ b/examples/texture/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -64,4 +64,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a372 +# PUBSPEC CHECKSUM: aaa7 diff --git a/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart b/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart index 9e29598855d08..4f06bfc8c60dc 100644 --- a/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart +++ b/packages/flutter/lib/src/widgets/_platform_selectable_region_context_menu_web.dart @@ -85,7 +85,7 @@ class PlatformSelectableRegionContextMenu extends StatelessWidget { final SelectionContainerDelegate? client = _activeClient; if (client != null) { // Converts the html right click event to flutter coordinate. - final Offset localOffset = Offset(event.offsetX, event.offsetY); + final Offset localOffset = Offset(event.offsetX.toDouble(), event.offsetY.toDouble()); final Matrix4 transform = client.getTransformTo(null); final Offset globalOffset = MatrixUtils.transformPoint(transform, localOffset); client.dispatchSelectionEvent(SelectWordSelectionEvent(globalPosition: globalOffset)); diff --git a/packages/flutter/pubspec.yaml b/packages/flutter/pubspec.yaml index f0c56c262b5bd..1431dd7eaf0dd 100644 --- a/packages/flutter/pubspec.yaml +++ b/packages/flutter/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: material_color_utilities: 0.5.0 meta: 1.10.0 vector_math: 2.1.4 - web: 0.2.1-beta + web: 0.3.0 sky_engine: sdk: flutter @@ -74,4 +74,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: a796 +# PUBSPEC CHECKSUM: 45cb diff --git a/packages/flutter/test_private/test/pubspec.yaml b/packages/flutter/test_private/test/pubspec.yaml index 19b76362958a8..48699793fd6eb 100644 --- a/packages/flutter/test_private/test/pubspec.yaml +++ b/packages/flutter/test_private/test/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_goldens: @@ -39,4 +39,4 @@ dev_dependencies: platform: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" process: 4.2.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: b866 +# PUBSPEC CHECKSUM: a79b diff --git a/packages/flutter_driver/pubspec.yaml b/packages/flutter_driver/pubspec.yaml index 77abc24a0659b..005b23ad71f20 100644 --- a/packages/flutter_driver/pubspec.yaml +++ b/packages/flutter_driver/pubspec.yaml @@ -35,7 +35,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: fake_async: 1.3.1 @@ -72,4 +72,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: bac0 +# PUBSPEC CHECKSUM: 5ef5 diff --git a/packages/flutter_goldens/pubspec.yaml b/packages/flutter_goldens/pubspec.yaml index ad7f98079dc1c..ad0b4d260529f 100644 --- a/packages/flutter_goldens/pubspec.yaml +++ b/packages/flutter_goldens/pubspec.yaml @@ -34,6 +34,6 @@ dependencies: test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" typed_data: 1.3.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 3ac7 +# PUBSPEC CHECKSUM: 5bfc diff --git a/packages/flutter_localizations/pubspec.yaml b/packages/flutter_localizations/pubspec.yaml index 50fb8f06bbc48..dc9623e9718fe 100644 --- a/packages/flutter_localizations/pubspec.yaml +++ b/packages/flutter_localizations/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" path: 1.8.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -34,4 +34,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 35a3 +# PUBSPEC CHECKSUM: bfd8 diff --git a/packages/flutter_test/pubspec.yaml b/packages/flutter_test/pubspec.yaml index f71a48991d1cd..c2e39420f6e2b 100644 --- a/packages/flutter_test/pubspec.yaml +++ b/packages/flutter_test/pubspec.yaml @@ -40,7 +40,7 @@ dependencies: stream_channel: 2.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" string_scanner: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: file: 6.1.4 @@ -83,4 +83,4 @@ dev_dependencies: webkit_inspection_protocol: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: aa8d +# PUBSPEC CHECKSUM: a2c2 diff --git a/packages/flutter_web_plugins/pubspec.yaml b/packages/flutter_web_plugins/pubspec.yaml index 84cb9643140f0..51e8f22aac920 100644 --- a/packages/flutter_web_plugins/pubspec.yaml +++ b/packages/flutter_web_plugins/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -33,4 +33,4 @@ dev_dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" -# PUBSPEC CHECKSUM: 0c69 +# PUBSPEC CHECKSUM: dc9e diff --git a/packages/integration_test/example/pubspec.yaml b/packages/integration_test/example/pubspec.yaml index d4de3e98957b2..a69981d37190a 100644 --- a/packages/integration_test/example/pubspec.yaml +++ b/packages/integration_test/example/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: flutter_test: @@ -84,4 +84,4 @@ dev_dependencies: flutter: uses-material-design: true -# PUBSPEC CHECKSUM: fb27 +# PUBSPEC CHECKSUM: 9f5c diff --git a/packages/integration_test/integration_test_macos/pubspec.yaml b/packages/integration_test/integration_test_macos/pubspec.yaml index d9501f40dd625..535783476eb49 100644 --- a/packages/integration_test/integration_test_macos/pubspec.yaml +++ b/packages/integration_test/integration_test_macos/pubspec.yaml @@ -21,9 +21,9 @@ dependencies: material_color_utilities: 0.5.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" meta: 1.10.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" dev_dependencies: pedantic: 1.11.1 -# PUBSPEC CHECKSUM: 68ab +# PUBSPEC CHECKSUM: a2e0 diff --git a/packages/integration_test/pubspec.yaml b/packages/integration_test/pubspec.yaml index f9dbd36e2a7db..7e352bd877f94 100644 --- a/packages/integration_test/pubspec.yaml +++ b/packages/integration_test/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: term_glyph: 1.2.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" test_api: 0.6.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" vector_math: 2.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" - web: 0.2.1-beta # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" + web: 0.3.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" webdriver: 3.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade" flutter: @@ -45,4 +45,4 @@ flutter: ios: pluginClass: IntegrationTestPlugin -# PUBSPEC CHECKSUM: e584 +# PUBSPEC CHECKSUM: 53b9 From 379c3f4d37fb5870330e78a0863b2ed7cd643d7d Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Wed, 1 Nov 2023 11:34:49 -0700 Subject: [PATCH 1535/1547] [flutter_releases] Flutter beta 3.16.0-0.4.pre Framework Cherrypicks (#137709) # Flutter beta 3.16.0-0.4.pre Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 7d6a0b7836dea..02eb2d5d508f3 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -91cde06da08323f25bd4bcc4a1832862f2b58c08 +abdaabc6dc88e20dd0fe290a2d3dfcac03b2706f From 4822f901d16eb899e34709d3f6e37830d4e66670 Mon Sep 17 00:00:00 2001 From: Xilai Zhang <xilaizhang@google.com> Date: Tue, 7 Nov 2023 11:24:03 -0800 Subject: [PATCH 1536/1547] =?UTF-8?q?[flutter=20release=20cp]=20Reland=20"?= =?UTF-8?q?Fixes=20ability=20to=20call=20nextFocus()=20on=20a=20node=20to?= =?UTF-8?q?=20focus=20its=20desc=E2=80=A6=20(#138014)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …… (#136898) …endant" (#136894)" This reverts commit c2bd2c1175f5b81e9543955760aec5b876b4e57e. fixes https://github.com/flutter/flutter/issues/134854 Context: https://github.com/flutter/flutter/issues/137071. Updated from [commit in chunhtai/flutter](https://github.com/chunhtai/flutter/commit/adacf2227ef59591b5d2dbdada621c8d5a7ee467) --- .../lib/src/widgets/focus_traversal.dart | 25 +++- .../test/widgets/focus_traversal_test.dart | 116 +++++++++++++++++- 2 files changed, 134 insertions(+), 7 deletions(-) diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart index 1212e27c8247a..3f4707c28fe44 100644 --- a/packages/flutter/lib/src/widgets/focus_traversal.dart +++ b/packages/flutter/lib/src/widgets/focus_traversal.dart @@ -241,7 +241,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { final FocusScopeNode scope = currentNode.nearestScope!; FocusNode? candidate = scope.focusedChild; if (ignoreCurrentFocus || candidate == null && scope.descendants.isNotEmpty) { - final Iterable<FocusNode> sorted = _sortAllDescendants(scope, currentNode); + final Iterable<FocusNode> sorted = _sortAllDescendants(scope, currentNode).where((FocusNode node) => _canRequestTraversalFocus(node)); if (sorted.isEmpty) { candidate = null; } else { @@ -340,10 +340,25 @@ abstract class FocusTraversalPolicy with Diagnosticable { @protected Iterable<FocusNode> sortDescendants(Iterable<FocusNode> descendants, FocusNode currentNode); - Map<FocusNode?, _FocusTraversalGroupInfo> _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { + static bool _canRequestTraversalFocus(FocusNode node) { + return node.canRequestFocus && !node.skipTraversal; + } + + static Iterable<FocusNode> _getDescendantsWithoutExpandingScope(FocusNode node) { + final List<FocusNode> result = <FocusNode>[]; + for (final FocusNode child in node.children) { + result.add(child); + if (child is! FocusScopeNode) { + result.addAll(_getDescendantsWithoutExpandingScope(child)); + } + } + return result; + } + + static Map<FocusNode?, _FocusTraversalGroupInfo> _findGroups(FocusScopeNode scope, _FocusTraversalGroupNode? scopeGroupNode, FocusNode currentNode) { final FocusTraversalPolicy defaultPolicy = scopeGroupNode?.policy ?? ReadingOrderTraversalPolicy(); final Map<FocusNode?, _FocusTraversalGroupInfo> groups = <FocusNode?, _FocusTraversalGroupInfo>{}; - for (final FocusNode node in scope.descendants) { + for (final FocusNode node in _getDescendantsWithoutExpandingScope(scope)) { final _FocusTraversalGroupNode? groupNode = FocusTraversalGroup._getGroupNode(node); // Group nodes need to be added to their parent's node, or to the "null" // node if no parent is found. This creates the hierarchy of group nodes @@ -413,7 +428,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { // They were left in above because they were needed to find their members // during sorting. sortedDescendants.removeWhere((FocusNode node) { - return node != currentNode && (!node.canRequestFocus || node.skipTraversal); + return node != currentNode && !_canRequestTraversalFocus(node); }); // Sanity check to make sure that the algorithm above doesn't diverge from @@ -421,7 +436,7 @@ abstract class FocusTraversalPolicy with Diagnosticable { // finds. assert((){ final Set<FocusNode> difference = sortedDescendants.toSet().difference(scope.traversalDescendants.toSet()); - if (currentNode.skipTraversal || !currentNode.canRequestFocus) { + if (!_canRequestTraversalFocus(currentNode)) { // The scope.traversalDescendants will not contain currentNode if it // skips traversal or not focusable. assert( diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart index 5b2abf4cf25ea..bf447bb661ad0 100644 --- a/packages/flutter/test/widgets/focus_traversal_test.dart +++ b/packages/flutter/test/widgets/focus_traversal_test.dart @@ -96,6 +96,113 @@ void main() { expect(scope.hasFocus, isTrue); }); + testWidgetsWithLeakTracking('focus traversal should work case 1', (WidgetTester tester) async { + final FocusNode outer1 = FocusNode(debugLabel: 'outer1', skipTraversal: true); + final FocusNode outer2 = FocusNode(debugLabel: 'outer2', skipTraversal: true); + final FocusNode inner1 = FocusNode(debugLabel: 'inner1', ); + final FocusNode inner2 = FocusNode(debugLabel: 'inner2', ); + addTearDown(() { + outer1.dispose(); + outer2.dispose(); + inner1.dispose(); + inner2.dispose(); + }); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FocusTraversalGroup( + child: Row( + children: <Widget>[ + FocusScope( + child: Focus( + focusNode: outer1, + child: Focus( + focusNode: inner1, + child: const SizedBox(width: 10, height: 10), + ), + ), + ), + FocusScope( + child: Focus( + focusNode: outer2, + // Add a padding to ensure both Focus widgets have different + // sizes. + child: Padding( + padding: const EdgeInsets.all(5), + child: Focus( + focusNode: inner2, + child: const SizedBox(width: 10, height: 10), + ), + ), + ), + ), + ], + ), + ), + ), + ); + + expect(FocusManager.instance.primaryFocus, isNull); + inner1.requestFocus(); + await tester.pump(); + expect(FocusManager.instance.primaryFocus, inner1); + outer2.nextFocus(); + await tester.pump(); + expect(FocusManager.instance.primaryFocus, inner2); + }); + + testWidgetsWithLeakTracking('focus traversal should work case 2', (WidgetTester tester) async { + final FocusNode outer1 = FocusNode(debugLabel: 'outer1', skipTraversal: true); + final FocusNode outer2 = FocusNode(debugLabel: 'outer2', skipTraversal: true); + final FocusNode inner1 = FocusNode(debugLabel: 'inner1', ); + final FocusNode inner2 = FocusNode(debugLabel: 'inner2', ); + addTearDown(() { + outer1.dispose(); + outer2.dispose(); + inner1.dispose(); + inner2.dispose(); + }); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: FocusTraversalGroup( + child: Row( + children: <Widget>[ + FocusScope( + child: Focus( + focusNode: outer1, + child: Focus( + focusNode: inner1, + child: const SizedBox(width: 10, height: 10), + ), + ), + ), + FocusScope( + child: Focus( + focusNode: outer2, + child: Focus( + focusNode: inner2, + child: const SizedBox(width: 10, height: 10), + ), + ), + ), + ], + ), + ), + ), + ); + + expect(FocusManager.instance.primaryFocus, isNull); + inner1.requestFocus(); + await tester.pump(); + expect(FocusManager.instance.primaryFocus, inner1); + outer2.nextFocus(); + await tester.pump(); + expect(FocusManager.instance.primaryFocus, inner2); + }); + testWidgetsWithLeakTracking('Move focus to next node.', (WidgetTester tester) async { final GlobalKey key1 = GlobalKey(debugLabel: '1'); final GlobalKey key2 = GlobalKey(debugLabel: '2'); @@ -626,8 +733,13 @@ void main() { final bool didFindNode = node1.nextFocus(); await tester.pump(); expect(didFindNode, isTrue); - expect(node1.hasPrimaryFocus, isFalse); - expect(node2.hasPrimaryFocus, isTrue); + if (canRequestFocus) { + expect(node1.hasPrimaryFocus, isTrue); + expect(node2.hasPrimaryFocus, isFalse); + } else { + expect(node1.hasPrimaryFocus, isFalse); + expect(node2.hasPrimaryFocus, isTrue); + } } }); From 092a710c6471ea2a18794b5580e27aa21c284cf7 Mon Sep 17 00:00:00 2001 From: yusuf-goog <91688203+yusuf-goog@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:33:14 -0800 Subject: [PATCH 1537/1547] Bumping version tag of provisioning profile cipd package. (#137710) (#137782) Bug:https://github.com/flutter/flutter/issues/137166 *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .ci.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.ci.yaml b/.ci.yaml index 1c4d16970f4fc..48874999b2155 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -77,7 +77,7 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "apple_signing", "version": "version:2022_to_2023"} + {"dependency": "apple_signing", "version": "version:to_2024"} ] os: Mac-12 device_type: none @@ -89,7 +89,7 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "apple_signing", "version": "version:2022_to_2023"} + {"dependency": "apple_signing", "version": "version:to_2024"} ] os: Mac-12 device_type: none @@ -102,7 +102,7 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "apple_signing", "version": "version:2022_to_2023"} + {"dependency": "apple_signing", "version": "version:to_2024"} ] device_type: none mac_model: "Macmini8,1" @@ -117,7 +117,7 @@ platform_properties: properties: dependencies: >- [ - {"dependency": "apple_signing", "version": "version:2022_to_2023"} + {"dependency": "apple_signing", "version": "version:to_2024"} ] os: Mac-12 device_type: none @@ -131,7 +131,7 @@ platform_properties: dependencies: >- [ {"dependency": "gems", "version": "v3.3.14"}, - {"dependency": "apple_signing", "version": "version:2022_to_2023"} + {"dependency": "apple_signing", "version": "version:to_2024"} ] os: Mac-12 device_type: none @@ -166,7 +166,7 @@ platform_properties: dependencies: >- [ {"dependency": "gems", "version": "v3.3.14"}, - {"dependency": "apple_signing", "version": "version:2022_to_2023"} + {"dependency": "apple_signing", "version": "version:to_2024"} ] os: Mac-12 cpu: x86 From adc7dfe87ebc5ff6cb6ceb786efaa83058fdc1a1 Mon Sep 17 00:00:00 2001 From: Xilai Zhang <xilaizhang@google.com> Date: Tue, 7 Nov 2023 18:30:33 -0800 Subject: [PATCH 1538/1547] [flutter release] update engine version of Flutter 3.16 candidate.0 (#138045) Roll engine version on branch Flutter 3.16 candidate.0 --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 02eb2d5d508f3..41383f07e04e6 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -abdaabc6dc88e20dd0fe290a2d3dfcac03b2706f +ab14aba1d5564df418f0e87f6772916c80a9a00a From db7ef5bf9f59442b0e200a90587e8fa5e0c6336a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20S=20Guerrero?= <jesus_sguerrero@hotmail.com> Date: Wed, 15 Nov 2023 11:25:44 -0800 Subject: [PATCH 1539/1547] [flutter_releases] Flutter stable 3.16.0 Framework Cherrypicks (#138506) # Flutter stable 3.16.0 Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 41383f07e04e6..5c7a2cb13d341 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ab14aba1d5564df418f0e87f6772916c80a9a00a +74d16627b940bb15e50891f82cad6c3e3465bd6d From 20467ba0cd05284b058cf513c19bcac6d374f0bc Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Mon, 20 Nov 2023 10:04:13 -0800 Subject: [PATCH 1540/1547] CP catch StdinException when setting terminal to SingleCharMode (#138032) Original tracking issue: https://github.com/flutter/flutter/issues/129198 Original PR: https://github.com/flutter/flutter/pull/136283 CP Request: https://github.com/flutter/flutter/issues/138040 --- .../flutter_tools/lib/src/base/terminal.dart | 20 +++++++---- .../general.shard/base/terminal_test.dart | 35 ++++++++++++++++++- packages/flutter_tools/test/src/fakes.dart | 14 +++++++- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/packages/flutter_tools/lib/src/base/terminal.dart b/packages/flutter_tools/lib/src/base/terminal.dart index b782441b5996c..73c20f9fe6774 100644 --- a/packages/flutter_tools/lib/src/base/terminal.dart +++ b/packages/flutter_tools/lib/src/base/terminal.dart @@ -314,13 +314,19 @@ class AnsiTerminal implements Terminal { return; } final io.Stdin stdin = _stdio.stdin as io.Stdin; - // The order of setting lineMode and echoMode is important on Windows. - if (value) { - stdin.echoMode = false; - stdin.lineMode = false; - } else { - stdin.lineMode = true; - stdin.echoMode = true; + + try { + // The order of setting lineMode and echoMode is important on Windows. + if (value) { + stdin.echoMode = false; + stdin.lineMode = false; + } else { + stdin.lineMode = true; + stdin.echoMode = true; + } + } on io.StdinException { + // If the pipe to STDIN has been closed it's probably because the + // terminal has been closed, and there is nothing actionable to do here. } } diff --git a/packages/flutter_tools/test/general.shard/base/terminal_test.dart b/packages/flutter_tools/test/general.shard/base/terminal_test.dart index 3d335bbe254ab..5810a58290775 100644 --- a/packages/flutter_tools/test/general.shard/base/terminal_test.dart +++ b/packages/flutter_tools/test/general.shard/base/terminal_test.dart @@ -9,6 +9,7 @@ import 'package:flutter_tools/src/base/terminal.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; +import '../../src/fakes.dart'; void main() { group('output preferences', () { @@ -253,6 +254,16 @@ void main() { expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 10, 23)).preferredStyle, 2); expect(AnsiTerminal(stdio: stdio, platform: const LocalPlatform(), now: DateTime(2018, 1, 11, 23)).preferredStyle, 3); }); + + testWithoutContext('set singleCharMode resilient to StdinException', () async { + final FakeStdio stdio = FakeStdio(); + final AnsiTerminal terminal = AnsiTerminal(stdio: stdio, platform: const LocalPlatform()); + stdio.stdinHasTerminal = true; + stdio._stdin = FakeStdin()..echoModeCallback = (bool _) => throw const StdinException( + 'Error setting terminal echo mode, OS Error: The handle is invalid.', + ); + terminal.singleCharMode = true; + }); } late Stream<String> mockStdInStream; @@ -269,14 +280,36 @@ class TestTerminal extends AnsiTerminal { return mockStdInStream; } + bool _singleCharMode = false; + @override - bool singleCharMode = false; + bool get singleCharMode => _singleCharMode; + + void Function(bool newMode)? _singleCharModeCallback; + + @override + set singleCharMode(bool newMode) { + _singleCharMode = newMode; + if (_singleCharModeCallback != null) { + _singleCharModeCallback!(newMode); + } + } @override int get preferredStyle => 0; } class FakeStdio extends Fake implements Stdio { + Stream<List<int>>? _stdin; + + @override + Stream<List<int>> get stdin { + if (_stdin != null) { + return _stdin!; + } + throw UnimplementedError('stdin'); + } + @override bool stdinHasTerminal = false; } diff --git a/packages/flutter_tools/test/src/fakes.dart b/packages/flutter_tools/test/src/fakes.dart index 4cc4ab1c227e8..9f3bb754271db 100644 --- a/packages/flutter_tools/test/src/fakes.dart +++ b/packages/flutter_tools/test/src/fakes.dart @@ -253,8 +253,20 @@ class FakeStdio extends Stdio { class FakeStdin extends Fake implements Stdin { final StreamController<List<int>> controller = StreamController<List<int>>(); + void Function(bool mode)? echoModeCallback; + + bool _echoMode = true; + + @override + bool get echoMode => _echoMode; + @override - bool echoMode = true; + set echoMode(bool mode) { + _echoMode = mode; + if (echoModeCallback != null) { + echoModeCallback!(mode); + } + } @override bool lineMode = true; From d17e4184ecb2d84dd594025de141be7ad1f3e327 Mon Sep 17 00:00:00 2001 From: Andrew Kolos <andrewrkolos@gmail.com> Date: Mon, 20 Nov 2023 10:07:30 -0800 Subject: [PATCH 1541/1547] [CP] prevent tool crash when `IntelliJValidatorOnMac` encounters an installation with a missing `CFBundleIdentifier` (#138176) Cherry-picks #138095 onto beta --- packages/flutter_tools/lib/src/doctor.dart | 8 +++- .../lib/src/intellij/intellij_validator.dart | 14 +++++- .../intellij/intellij_validator_test.dart | 48 +++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 255e938ef8caa..9e3e1b7f0060e 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -51,17 +51,20 @@ abstract class DoctorValidatorsProvider { // [FeatureFlags]. factory DoctorValidatorsProvider.test({ Platform? platform, + Logger? logger, required FeatureFlags featureFlags, }) { return _DefaultDoctorValidatorsProvider( featureFlags: featureFlags, platform: platform ?? FakePlatform(), + logger: logger ?? BufferLogger.test(), ); } /// The singleton instance, pulled from the [AppContext]. static DoctorValidatorsProvider get _instance => context.get<DoctorValidatorsProvider>()!; static final DoctorValidatorsProvider defaultInstance = _DefaultDoctorValidatorsProvider( + logger: globals.logger, platform: globals.platform, featureFlags: featureFlags, ); @@ -74,12 +77,14 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { _DefaultDoctorValidatorsProvider({ required this.platform, required this.featureFlags, - }); + required Logger logger, + }) : _logger = logger; List<DoctorValidator>? _validators; List<Workflow>? _workflows; final Platform platform; final FeatureFlags featureFlags; + final Logger _logger; late final LinuxWorkflow linuxWorkflow = LinuxWorkflow( platform: platform, @@ -115,6 +120,7 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider { userMessages: userMessages, plistParser: globals.plistParser, processManager: globals.processManager, + logger: _logger, ), ...VsCodeValidator.installedValidators(globals.fs, platform, globals.processManager), ]; diff --git a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart index 4b2b436a3b298..c6d5e695afea7 100644 --- a/packages/flutter_tools/lib/src/intellij/intellij_validator.dart +++ b/packages/flutter_tools/lib/src/intellij/intellij_validator.dart @@ -7,6 +7,7 @@ import 'package:process/process.dart'; import '../base/file_system.dart'; import '../base/io.dart'; +import '../base/logger.dart'; import '../base/platform.dart'; import '../base/user_messages.dart' hide userMessages; import '../base/version.dart'; @@ -50,6 +51,7 @@ abstract class IntelliJValidator extends DoctorValidator { static Iterable<DoctorValidator> installedValidators({ required FileSystem fileSystem, required Platform platform, + required Logger logger, required UserMessages userMessages, required PlistParser plistParser, required ProcessManager processManager, @@ -77,6 +79,7 @@ abstract class IntelliJValidator extends DoctorValidator { userMessages: userMessages, plistParser: plistParser, processManager: processManager, + logger: logger, ); } return <DoctorValidator>[]; @@ -382,6 +385,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator { static Iterable<DoctorValidator> installed({ required FileSystem fileSystem, required FileSystemUtils fileSystemUtils, + required Logger logger, required UserMessages userMessages, required PlistParser plistParser, required ProcessManager processManager, @@ -490,10 +494,16 @@ class IntelliJValidatorOnMac extends IntelliJValidator { if (validator is! IntelliJValidatorOnMac) { return false; } - final String identifierKey = plistParser.getValueFromFile( + final String? identifierKey = plistParser.getValueFromFile<String>( validator.plistFile, PlistParser.kCFBundleIdentifierKey, - ) as String; + ); + if (identifierKey == null) { + logger.printTrace('Android Studio/IntelliJ installation at ' + '${validator.installPath} has a null CFBundleIdentifierKey, ' + 'which is a required field.'); + return false; + } return identifierKey.contains('com.jetbrains.toolbox.linkapp'); }); diff --git a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart index f2bc787c7615f..152fc5f333380 100644 --- a/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart +++ b/packages/flutter_tools/test/general.shard/intellij/intellij_validator_test.dart @@ -5,6 +5,7 @@ import 'package:archive/archive.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; +import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/convert.dart'; @@ -308,6 +309,7 @@ void main() { PlistParser.kCFBundleShortVersionStringKey: '2020.10', PlistParser.kCFBundleIdentifierKey: 'com.jetbrains.intellij', }), + logger: BufferLogger.test(), ).whereType<IntelliJValidatorOnMac>(); expect(validators.length, 2); @@ -389,6 +391,7 @@ void main() { 'CFBundleIdentifier': 'com.jetbrains.toolbox.linkapp', }), processManager: processManager, + logger: BufferLogger.test(), ); expect(validators.length, 1); @@ -431,11 +434,56 @@ void main() { 'CFBundleIdentifier': 'com.jetbrains.toolbox.linkapp', }), processManager: processManager, + logger: BufferLogger.test(), ); expect(installed.length, 0); expect(processManager, hasNoRemainingExpectations); }); + + testWithoutContext('Does not crash when installation is missing its CFBundleIdentifier property', () async { + final BufferLogger logger = BufferLogger.test(); + final FileSystem fileSystem = MemoryFileSystem.test(); + final String ultimatePath = fileSystem.path.join('/', 'foo', 'bar', 'Applications', + 'JetBrains Toolbox', 'IntelliJ IDEA Ultimate.app'); + final String communityEditionPath = fileSystem.path.join('/', 'foo', 'bar', 'Applications', + 'JetBrains Toolbox', 'IntelliJ IDEA Community Edition.app'); + final List<String> installPaths = <String>[ + ultimatePath, + communityEditionPath + ]; + + for (final String installPath in installPaths) { + fileSystem.directory(installPath).createSync(recursive: true); + } + + final FakeProcessManager processManager = + FakeProcessManager.list(<FakeCommand>[ + FakeCommand(command: const <String>[ + 'mdfind', + 'kMDItemCFBundleIdentifier="com.jetbrains.intellij.ce"', + ], stdout: communityEditionPath), + FakeCommand(command: const <String>[ + 'mdfind', + 'kMDItemCFBundleIdentifier="com.jetbrains.intellij*"', + ], stdout: ultimatePath) + ]); + + final Iterable<DoctorValidator> installed = IntelliJValidatorOnMac.installed( + fileSystem: fileSystem, + fileSystemUtils: FileSystemUtils(fileSystem: fileSystem, platform: macPlatform), + userMessages: UserMessages(), + plistParser: FakePlistParser(<String, String>{ + 'JetBrainsToolboxApp': '/path/to/JetBrainsToolboxApp', + }), + processManager: processManager, + logger: logger, + ); + + expect(installed.length, 2); + expect(logger.traceText, contains('installation at $ultimatePath has a null CFBundleIdentifierKey')); + expect(processManager, hasNoRemainingExpectations); + }); } class IntelliJValidatorTestTarget extends IntelliJValidator { From 6f753f71b28f8586211d8e4760c5bf3e437d5730 Mon Sep 17 00:00:00 2001 From: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:11:04 -0600 Subject: [PATCH 1542/1547] [CP] Fix file deletion crash in BuildIOSArchiveCommand.runCommand (#138752) Original PR: https://github.com/flutter/flutter/pull/138734 --- .../lib/src/commands/build_ios.dart | 5 ++- .../hermetic/build_ipa_test.dart | 35 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/packages/flutter_tools/lib/src/commands/build_ios.dart b/packages/flutter_tools/lib/src/commands/build_ios.dart index 117414e89f85c..fba0c14e95a41 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios.dart @@ -10,6 +10,7 @@ import 'package:meta/meta.dart'; import '../base/analyze_size.dart'; import '../base/common.dart'; +import '../base/error_handling_io.dart'; import '../base/logger.dart'; import '../base/process.dart'; import '../base/utils.dart'; @@ -487,7 +488,9 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand { ], ); } finally { - generatedExportPlist?.deleteSync(); + if (generatedExportPlist != null) { + ErrorHandlingFileSystem.deleteIfExists(generatedExportPlist); + } status?.stop(); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index e925821917847..e4a9d6ecae00b 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -169,6 +169,7 @@ void main() { FakeCommand exportArchiveCommand({ String exportOptionsPlist = '/ExportOptions.plist', File? cachePlist, + bool deleteExportOptionsPlist = false, }) { return FakeCommand( command: <String>[ @@ -190,6 +191,9 @@ void main() { if (cachePlist != null) { cachePlist.writeAsStringSync(fileSystem.file(_exportOptionsPlist).readAsStringSync()); } + if (deleteExportOptionsPlist) { + fileSystem.file(_exportOptionsPlist).deleteSync(); + } } ); } @@ -391,6 +395,37 @@ void main() { XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), }); + testUsingContext('ipa build ignores deletion failure if generatedExportPlist does not exist', () async { + final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist'); + final BuildCommand command = BuildCommand( + androidSdk: FakeAndroidSdk(), + buildSystem: TestBuildSystem.all(BuildResult(success: true)), + logger: BufferLogger.test(), + fileSystem: fileSystem, + osUtils: FakeOperatingSystemUtils(), + ); + fakeProcessManager.addCommands(<FakeCommand>[ + xattrCommand, + setUpFakeXcodeBuildHandler(), + exportArchiveCommand( + exportOptionsPlist: _exportOptionsPlist, + cachePlist: cachedExportOptionsPlist, + deleteExportOptionsPlist: true, + ), + ]); + createMinimalMockProjectFiles(); + + await createTestCommandRunner(command).run( + const <String>['build', 'ipa', '--no-pub'] + ); + expect(fakeProcessManager, hasNoRemainingExpectations); + }, overrides: <Type, Generator>{ + FileSystem: () => fileSystem, + ProcessManager: () => fakeProcessManager, + Platform: () => macosPlatform, + XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(), + }); + testUsingContext('ipa build invokes xcodebuild and archives for app store', () async { final File cachedExportOptionsPlist = fileSystem.file('/CachedExportOptions.plist'); final BuildCommand command = BuildCommand( From 7f20e5d18ce4cb80c621533090a7c5113f5bdc52 Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Mon, 27 Nov 2023 09:47:30 -0800 Subject: [PATCH 1543/1547] [flutter_releases] Flutter stable 3.16.1 Framework Cherrypicks (#139075) # Flutter stable 3.16.1 Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 5c7a2cb13d341..92404d6c53fff 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -74d16627b940bb15e50891f82cad6c3e3465bd6d +22b600f240548c1cf6f5d3f9ae65a5c9e51bc443 From 9e1c857886f07d342cf106f2cd588bcd5e031bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20S=20Guerrero?= <jesus_sguerrero@hotmail.com> Date: Thu, 30 Nov 2023 11:51:18 -0600 Subject: [PATCH 1544/1547] [flutter_releases] Flutter stable 3.16.2 Framework Cherrypicks (#139273) # Flutter stable 3.16.2 Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 92404d6c53fff..d006f2c7ae319 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -22b600f240548c1cf6f5d3f9ae65a5c9e51bc443 +cf7a9d0800f2a5da166dbe0eb9fb2476018269b1 From 784a44f6f638ad67ad66624e57043c56aeb4a9e7 Mon Sep 17 00:00:00 2001 From: Christopher Fujino <christopherfujino@gmail.com> Date: Tue, 5 Dec 2023 09:04:51 -0800 Subject: [PATCH 1545/1547] CP bump DDS to fix DAP threadID integer parsing bug (#139158) CP request: https://github.com/flutter/flutter/issues/139177 Upstream tracking issue: https://github.com/dart-lang/sdk/issues/53086 --- packages/flutter_tools/pubspec.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml index 4a2e14dd4dfa8..e77573b019693 100644 --- a/packages/flutter_tools/pubspec.yaml +++ b/packages/flutter_tools/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: archive: 3.3.2 args: 2.4.2 browser_launcher: 1.1.1 - dds: 2.9.4 + dds: 2.9.5 dwds: 21.0.0 completion: 1.0.1 coverage: 1.6.3 @@ -112,4 +112,4 @@ dartdoc: # Exclude this package from the hosted API docs. nodoc: true -# PUBSPEC CHECKSUM: 887b +# PUBSPEC CHECKSUM: 537c From 6d998fe6c0db0ac9eb37318542fb57bacc1bbc88 Mon Sep 17 00:00:00 2001 From: Kate Lovett <katelovett@google.com> Date: Tue, 5 Dec 2023 12:22:07 -0600 Subject: [PATCH 1546/1547] =?UTF-8?q?[CP]=20Add=20ability=20to=20customize?= =?UTF-8?q?=20`NavigationBar`=20indicator=20overlay=20and=20fix=20in?= =?UTF-8?q?=E2=80=A6=20(#139162)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …dicator shape for the overlay (#138901) fixes [Provide ability to override `NavigationBar` indicator ink response overlay](https://github.com/flutter/flutter/issues/138850) fixes [`NavigationBar.indicatorShape` is ignored, `NavigationBarThemeData.indicatorShape` is applied to the indicator inkwell](https://github.com/flutter/flutter/issues/138900) --- Cherry pick fixes https://github.com/flutter/flutter/issues/139159 --- ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( bottomNavigationBar: NavigationBarExample(), ), ); } } class NavigationBarExample extends StatefulWidget { const NavigationBarExample({super.key}); @override State<NavigationBarExample> createState() => _NavigationBarExampleState(); } class _NavigationBarExampleState extends State<NavigationBarExample> { int index = 0; @override Widget build(BuildContext context) { return NavigationBar( elevation: 0, overlayColor: const MaterialStatePropertyAll<Color>(Colors.transparent), // indicatorShape: RoundedRectangleBorder( // borderRadius: BorderRadius.circular(4.0), // ), indicatorColor: Colors.transparent, selectedIndex: index, onDestinationSelected: (int index) { setState(() { this.index = index; }); }, destinations: const <Widget>[ NavigationDestination( selectedIcon: Icon(Icons.home_filled), icon: Icon(Icons.home_outlined), label: 'Home', ), NavigationDestination( selectedIcon: Icon(Icons.favorite), icon: Icon(Icons.favorite_outline), label: 'Favorites', ), ], ); } } ``` </details> ### Before #### Cannot override `NavigationBar` Indicator ink well overlay ![Screenshot 2023-11-22 at 18 22 48](https://github.com/flutter/flutter/assets/48603081/06f54335-71ee-4882-afb0-53b614933c38) #### Indicator shape is ignored for the indicator overlay ![Screenshot 2023-11-22 at 15 29 52](https://github.com/flutter/flutter/assets/48603081/913e0f77-48f4-4c6e-87f3-52c81b78f3d9) ### After #### Can use `NavigationBar.overlayColor` or `NavigationBarThemeData.NavigationBar` to override default indicator overlay `overlayColor: MaterialStatePropertyAll<Color>(Colors.red.withOpacity(0.33)),` ![Screenshot 2023-11-22 at 18 22 08](https://github.com/flutter/flutter/assets/48603081/28badae4-a7c7-4bf0-8bcc-278a1f84729d) `overlayColor: MaterialStatePropertyAll<Color>(Colors.transparent),` ![Screenshot 2023-11-22 at 18 22 25](https://github.com/flutter/flutter/assets/48603081/674b48b1-f66a-4d91-9f10-ad307416ac32) #### Indicator shape is respected for the indicator overlay ![Screenshot 2023-11-22 at 15 30 36](https://github.com/flutter/flutter/assets/48603081/ae9a3627-787e-45ac-9319-2ea8ea1e6ae6) *Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.* *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/material/navigation_bar.dart | 17 ++- .../src/material/navigation_bar_theme.dart | 30 +++-- .../test/material/navigation_bar_test.dart | 124 +++++++++++++++--- .../material/navigation_bar_theme_test.dart | 86 +++++++++++- 4 files changed, 229 insertions(+), 28 deletions(-) diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index b209ffb21ec04..e40c6247d16f8 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -98,6 +98,7 @@ class NavigationBar extends StatelessWidget { this.indicatorShape, this.height, this.labelBehavior, + this.overlayColor, }) : assert(destinations.length >= 2), assert(0 <= selectedIndex && selectedIndex < destinations.length); @@ -201,6 +202,10 @@ class NavigationBar extends StatelessWidget { /// [NavigationDestinationLabelBehavior.alwaysShow]. final NavigationDestinationLabelBehavior? labelBehavior; + /// The highlight color that's typically used to indicate that + /// the [NavigationDestination] is focused, hovered, or pressed. + final MaterialStateProperty<Color?>? overlayColor; + VoidCallback _handleTap(int index) { return onDestinationSelected != null ? () => onDestinationSelected!(index) @@ -243,6 +248,7 @@ class NavigationBar extends StatelessWidget { labelBehavior: effectiveLabelBehavior, indicatorColor: indicatorColor, indicatorShape: indicatorShape, + overlayColor: overlayColor, onTap: _handleTap(i), child: destinations[i], ); @@ -503,7 +509,8 @@ class _NavigationDestinationBuilderState extends State<_NavigationDestinationBui child: _IndicatorInkWell( iconKey: iconKey, labelBehavior: info.labelBehavior, - customBorder: navigationBarTheme.indicatorShape ?? defaults.indicatorShape, + customBorder: info.indicatorShape ?? navigationBarTheme.indicatorShape ?? defaults.indicatorShape, + overlayColor: info.overlayColor ?? navigationBarTheme.overlayColor, onTap: widget.enabled ? info.onTap : null, child: Row( children: <Widget>[ @@ -526,6 +533,7 @@ class _IndicatorInkWell extends InkResponse { const _IndicatorInkWell({ required this.iconKey, required this.labelBehavior, + super.overlayColor, super.customBorder, super.onTap, super.child, @@ -563,6 +571,7 @@ class _NavigationDestinationInfo extends InheritedWidget { required this.labelBehavior, required this.indicatorColor, required this.indicatorShape, + required this.overlayColor, required this.onTap, required super.child, }); @@ -629,6 +638,12 @@ class _NavigationDestinationInfo extends InheritedWidget { /// This is used by destinations to override the indicator shape. final ShapeBorder? indicatorShape; + /// The highlight color that's typically used to indicate that + /// the [NavigationDestination] is focused, hovered, or pressed. + /// + /// This is used by destinations to override the overlay color. + final MaterialStateProperty<Color?>? overlayColor; + /// The callback that should be called when this destination is tapped. /// /// This is computed by calling [NavigationBar.onDestinationSelected] diff --git a/packages/flutter/lib/src/material/navigation_bar_theme.dart b/packages/flutter/lib/src/material/navigation_bar_theme.dart index 2de555f6395e9..adb9e3985cec1 100644 --- a/packages/flutter/lib/src/material/navigation_bar_theme.dart +++ b/packages/flutter/lib/src/material/navigation_bar_theme.dart @@ -52,6 +52,7 @@ class NavigationBarThemeData with Diagnosticable { this.labelTextStyle, this.iconTheme, this.labelBehavior, + this.overlayColor, }); /// Overrides the default value of [NavigationBar.height]. @@ -91,6 +92,9 @@ class NavigationBarThemeData with Diagnosticable { /// Overrides the default value of [NavigationBar.labelBehavior]. final NavigationDestinationLabelBehavior? labelBehavior; + /// Overrides the default value of [NavigationBar.overlayColor]. + final MaterialStateProperty<Color?>? overlayColor; + /// Creates a copy of this object with the given fields replaced with the /// new values. NavigationBarThemeData copyWith({ @@ -104,6 +108,7 @@ class NavigationBarThemeData with Diagnosticable { MaterialStateProperty<TextStyle?>? labelTextStyle, MaterialStateProperty<IconThemeData?>? iconTheme, NavigationDestinationLabelBehavior? labelBehavior, + MaterialStateProperty<Color?>? overlayColor, }) { return NavigationBarThemeData( height: height ?? this.height, @@ -116,6 +121,7 @@ class NavigationBarThemeData with Diagnosticable { labelTextStyle: labelTextStyle ?? this.labelTextStyle, iconTheme: iconTheme ?? this.iconTheme, labelBehavior: labelBehavior ?? this.labelBehavior, + overlayColor: overlayColor ?? this.overlayColor, ); } @@ -139,6 +145,7 @@ class NavigationBarThemeData with Diagnosticable { labelTextStyle: MaterialStateProperty.lerp<TextStyle?>(a?.labelTextStyle, b?.labelTextStyle, t, TextStyle.lerp), iconTheme: MaterialStateProperty.lerp<IconThemeData?>(a?.iconTheme, b?.iconTheme, t, IconThemeData.lerp), labelBehavior: t < 0.5 ? a?.labelBehavior : b?.labelBehavior, + overlayColor: MaterialStateProperty.lerp<Color?>(a?.overlayColor, b?.overlayColor, t, Color.lerp), ); } @@ -154,6 +161,7 @@ class NavigationBarThemeData with Diagnosticable { labelTextStyle, iconTheme, labelBehavior, + overlayColor, ); @override @@ -165,16 +173,17 @@ class NavigationBarThemeData with Diagnosticable { return false; } return other is NavigationBarThemeData - && other.height == height - && other.backgroundColor == backgroundColor - && other.elevation == elevation - && other.shadowColor == shadowColor - && other.surfaceTintColor == surfaceTintColor - && other.indicatorColor == indicatorColor - && other.indicatorShape == indicatorShape - && other.labelTextStyle == labelTextStyle - && other.iconTheme == iconTheme - && other.labelBehavior == labelBehavior; + && other.height == height + && other.backgroundColor == backgroundColor + && other.elevation == elevation + && other.shadowColor == shadowColor + && other.surfaceTintColor == surfaceTintColor + && other.indicatorColor == indicatorColor + && other.indicatorShape == indicatorShape + && other.labelTextStyle == labelTextStyle + && other.iconTheme == iconTheme + && other.labelBehavior == labelBehavior + && other.overlayColor == overlayColor; } @override @@ -190,6 +199,7 @@ class NavigationBarThemeData with Diagnosticable { properties.add(DiagnosticsProperty<MaterialStateProperty<TextStyle?>>('labelTextStyle', labelTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<IconThemeData?>>('iconTheme', iconTheme, defaultValue: null)); properties.add(DiagnosticsProperty<NavigationDestinationLabelBehavior>('labelBehavior', labelBehavior, defaultValue: null)); + properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('overlayColor', overlayColor, defaultValue: null)); } } diff --git a/packages/flutter/test/material/navigation_bar_test.dart b/packages/flutter/test/material/navigation_bar_test.dart index 598b9a3664ece..9e01060611f42 100644 --- a/packages/flutter/test/material/navigation_bar_test.dart +++ b/packages/flutter/test/material/navigation_bar_test.dart @@ -12,6 +12,7 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; @@ -937,7 +938,7 @@ void main() { }); testWidgetsWithLeakTracking('Material3 - Navigation destination updates indicator color and shape', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); + final ThemeData theme = ThemeData(); const Color color = Color(0xff0000ff); const ShapeBorder shape = RoundedRectangleBorder(); @@ -945,20 +946,22 @@ void main() { return MaterialApp( theme: theme, home: Scaffold( - bottomNavigationBar: NavigationBar( - indicatorColor: indicatorColor, - indicatorShape: indicatorShape, - destinations: const <Widget>[ - NavigationDestination( - icon: Icon(Icons.ac_unit), - label: 'AC', - ), - NavigationDestination( - icon: Icon(Icons.access_alarm), - label: 'Alarm', - ), - ], - onDestinationSelected: (int i) { }, + bottomNavigationBar: RepaintBoundary( + child: NavigationBar( + indicatorColor: indicatorColor, + indicatorShape: indicatorShape, + destinations: const <Widget>[ + NavigationDestination( + icon: Icon(Icons.ac_unit), + label: 'AC', + ), + NavigationDestination( + icon: Icon(Icons.access_alarm), + label: 'Alarm', + ), + ], + onDestinationSelected: (int i) { }, + ), ), ), ); @@ -970,11 +973,22 @@ void main() { expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer); expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder()); + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(NavigationIndicator).last)); + await tester.pumpAndSettle(); + + // Test default indicator color and shape with ripple. + await expectLater(find.byType(NavigationBar), matchesGoldenFile('m3.navigation_bar.default.indicator.inkwell.shape.png')); + await tester.pumpWidget(buildNavigationBar(indicatorColor: color, indicatorShape: shape)); // Test custom indicator color and shape. expect(_getIndicatorDecoration(tester)?.color, color); expect(_getIndicatorDecoration(tester)?.shape, shape); + + // Test custom indicator color and shape with ripple. + await expectLater(find.byType(NavigationBar), matchesGoldenFile('m3.navigation_bar.custom.indicator.inkwell.shape.png')); }); testWidgetsWithLeakTracking('Destinations respect their disabled state', (WidgetTester tester) async { @@ -1014,6 +1028,86 @@ void main() { expect(selectedIndex, 1); }); + testWidgetsWithLeakTracking('NavigationBar respects overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + const Color hoverColor = Color(0xff0000ff); + const Color focusColor = Color(0xff00ffff); + const Color pressedColor = Color(0xffff00ff); + final MaterialStateProperty<Color?> overlayColor = MaterialStateProperty.resolveWith<Color>( + (Set<MaterialState> states) { + if (states.contains(MaterialState.hovered)) { + return hoverColor; + } + if (states.contains(MaterialState.focused)) { + return focusColor; + } + if (states.contains(MaterialState.pressed)) { + return pressedColor; + } + return Colors.transparent; + }); + + await tester.pumpWidget(MaterialApp( + home: Scaffold( + bottomNavigationBar: RepaintBoundary( + child: NavigationBar( + overlayColor: overlayColor, + destinations: const <Widget>[ + NavigationDestination( + icon: Icon(Icons.ac_unit), + label: 'AC', + ), + NavigationDestination( + icon: Icon(Icons.access_alarm), + label: 'Alarm', + ), + ], + onDestinationSelected: (int i) { }, + ), + ), + ), + )); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(NavigationIndicator).last)); + await tester.pumpAndSettle(); + + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + + // Test hovered state. + expect( + inkFeatures, + kIsWeb + ? (paints..rrect()..rrect()..circle(color: hoverColor)) + : (paints..circle(color: hoverColor)), + ); + + await gesture.down(tester.getCenter(find.byType(NavigationIndicator).last)); + await tester.pumpAndSettle(); + + // Test pressed state. + expect( + inkFeatures, + kIsWeb + ? (paints..circle()..circle()..circle(color: pressedColor)) + : (paints..circle()..circle(color: pressedColor)), + ); + + await gesture.up(); + await tester.pumpAndSettle(); + + // Press tab to focus the navigation bar. + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pumpAndSettle(); + + // Test focused state. + expect( + inkFeatures, + kIsWeb ? (paints..circle()..circle(color: focusColor)) : (paints..circle()..circle(color: focusColor)), + ); + }); + group('Material 2', () { // These tests are only relevant for Material 2. Once Material 2 // support is deprecated and the APIs are removed, these tests diff --git a/packages/flutter/test/material/navigation_bar_theme_test.dart b/packages/flutter/test/material/navigation_bar_theme_test.dart index 71d27bafc23d1..028c0ffbdeb4b 100644 --- a/packages/flutter/test/material/navigation_bar_theme_test.dart +++ b/packages/flutter/test/material/navigation_bar_theme_test.dart @@ -7,9 +7,11 @@ @Tags(<String>['reduced-test-set']) library; +import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; @@ -48,6 +50,7 @@ void main() { labelTextStyle: MaterialStatePropertyAll<TextStyle>(TextStyle(fontSize: 7.0)), iconTheme: MaterialStatePropertyAll<IconThemeData>(IconThemeData(color: Color(0x00000097))), labelBehavior: NavigationDestinationLabelBehavior.alwaysHide, + overlayColor: MaterialStatePropertyAll<Color>(Color(0x00000096)), ).debugFillProperties(builder); final List<String> description = builder.properties @@ -61,12 +64,11 @@ void main() { expect(description[3], 'indicatorColor: Color(0x00000098)'); expect(description[4], 'indicatorShape: CircleBorder(BorderSide(width: 0.0, style: none))'); expect(description[5], 'labelTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, size: 7.0))'); - // Ignore instance address for IconThemeData. expect(description[6].contains('iconTheme: MaterialStatePropertyAll(IconThemeData'), isTrue); expect(description[6].contains('(color: Color(0x00000097))'), isTrue); - expect(description[7], 'labelBehavior: NavigationDestinationLabelBehavior.alwaysHide'); + expect(description[8], 'overlayColor: MaterialStatePropertyAll(Color(0x00000096))'); }); testWidgetsWithLeakTracking('NavigationBarThemeData values are used when no NavigationBar properties are specified', (WidgetTester tester) async { @@ -216,6 +218,86 @@ void main() { await expectLater(find.byType(NavigationBar), matchesGoldenFile('indicator_custom_label_style.png')); }); + + testWidgetsWithLeakTracking('NavigationBar respects NavigationBarTheme.overlayColor in active/pressed/hovered states', (WidgetTester tester) async { + tester.binding.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; + const Color hoverColor = Color(0xff0000ff); + const Color focusColor = Color(0xff00ffff); + const Color pressedColor = Color(0xffff00ff); + final MaterialStateProperty<Color?> overlayColor = MaterialStateProperty.resolveWith<Color>( + (Set<MaterialState> states) { + if (states.contains(MaterialState.hovered)) { + return hoverColor; + } + if (states.contains(MaterialState.focused)) { + return focusColor; + } + if (states.contains(MaterialState.pressed)) { + return pressedColor; + } + return Colors.transparent; + }); + + await tester.pumpWidget(MaterialApp( + theme: ThemeData(navigationBarTheme: NavigationBarThemeData(overlayColor: overlayColor)), + home: Scaffold( + bottomNavigationBar: RepaintBoundary( + child: NavigationBar( + destinations: const <Widget>[ + NavigationDestination( + icon: Icon(Icons.ac_unit), + label: 'AC', + ), + NavigationDestination( + icon: Icon(Icons.access_alarm), + label: 'Alarm', + ), + ], + onDestinationSelected: (int i) { }, + ), + ), + ), + )); + + final TestGesture gesture = await tester.createGesture(kind: PointerDeviceKind.mouse); + await gesture.addPointer(); + await gesture.moveTo(tester.getCenter(find.byType(NavigationIndicator).last)); + await tester.pumpAndSettle(); + + final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); + + // Test hovered state. + expect( + inkFeatures, + kIsWeb + ? (paints..rrect()..rrect()..circle(color: hoverColor)) + : (paints..circle(color: hoverColor)), + ); + + await gesture.down(tester.getCenter(find.byType(NavigationIndicator).last)); + await tester.pumpAndSettle(); + + // Test pressed state. + expect( + inkFeatures, + kIsWeb + ? (paints..circle()..circle()..circle(color: pressedColor)) + : (paints..circle()..circle(color: pressedColor)), + ); + + await gesture.up(); + await tester.pumpAndSettle(); + + // Press tab to focus the navigation bar. + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pumpAndSettle(); + + // Test focused state. + expect( + inkFeatures, + kIsWeb ? (paints..circle()..circle(color: focusColor)) : (paints..circle()..circle(color: focusColor)), + ); + }); } List<NavigationDestination> _destinations() { From b0366e0a3f089e15fd89c97604ab402fe26b724c Mon Sep 17 00:00:00 2001 From: Casey Hillers <chillers@google.com> Date: Tue, 5 Dec 2023 19:46:39 -0800 Subject: [PATCH 1547/1547] [flutter_releases] Flutter stable 3.16.3 Framework Cherrypicks (#139618) # Flutter stable 3.16.3 Framework ## Scheduled Cherrypicks --- bin/internal/engine.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/internal/engine.version b/bin/internal/engine.version index d006f2c7ae319..05add3e5e8948 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -cf7a9d0800f2a5da166dbe0eb9fb2476018269b1 +54a7145303f0dd9d0f93424a2e124eb4abef5091